diff --git a/.agents/skills b/.agents/skills new file mode 120000 index 0000000000..454b8427cd --- /dev/null +++ b/.agents/skills @@ -0,0 +1 @@ +../.claude/skills \ No newline at end of file diff --git a/.claude/skills/update-go-version/SKILL.md b/.claude/skills/update-go-version/SKILL.md new file mode 100644 index 0000000000..4f5f9f2bb0 --- /dev/null +++ b/.claude/skills/update-go-version/SKILL.md @@ -0,0 +1,169 @@ +--- +name: update-go-version +description: Update Go version across the Pyroscope codebase (go.mod, go.work, CI workflows, Dockerfiles, goreleaser, examples). Use when bumping Go to a new patch or minor version. +argument-hint: +disable-model-invocation: true +allowed-tools: Bash, Read, Write, Edit, Grep, Glob, WebFetch +--- + +# Update Go Version + +Updates the Go version across all relevant files in the Pyroscope codebase. + +## Usage + +``` +/update-go-version 1.25.7 +``` + +## Prerequisites + +If no version argument is provided, do NOT guess. Instead: +1. Fetch the latest Go releases: `curl -s 'https://go.dev/dl/?mode=json' | jq -r '.[].version'` +2. Show the user the available versions and the current state (from go.mod) +3. Ask which version they want to target +4. Only proceed once they confirm + +**Version validation:** The target version MUST be a full patch version (e.g. `1.25.7`), not just a minor version (e.g. `1.25` or `1.25.0`). If the user provides `X.Y.0` or `X.Y`, warn them that they should use the latest patch release for that minor (check go.dev for the latest). Using `.0` means missing security patches and will cause the `toolchain` directive to be dropped from go.mod files (Go removes it when it equals the `go` directive). + +## Steps + +### 0. Create a feature branch + +Always create a new branch from the latest main before making any changes. Never commit directly to main. + +```bash +git checkout main +git fetch origin +git pull origin main +git checkout -b update-go-X.Y.Z +``` + +Use the naming convention `update-go-X.Y.Z` where `X.Y.Z` is the target version. + +### 1. Read current state + +Extract the current versions from the codebase: +- `go` directive from `go.mod` (line 3, e.g. `go 1.24.6`) +- `toolchain` directive from `go.mod` (line 5, e.g. `toolchain go1.24.9`) +- `go-version` from `.github/workflows/ci.yml` (e.g. `1.24.13`) + +Report these to the user before making changes. + +### 2. Determine bump type + +Compare the target version against the current `toolchain` directive in `go.mod`: + +- **Same minor** (e.g. current `toolchain go1.25.3`, target `1.25.7`): **patch bump**. Only the `toolchain` directive and build/CI files need updating. +- **Different minor** (e.g. current `toolchain go1.24.9`, target `1.25.7`): **minor bump**. The `toolchain` directive and build/CI files need updating. Ask the user whether to also update the `go` directive (see step 4). + +Tell the user which type was detected before proceeding. + +### 3. Run the upgrade script + +The `tools/upgrade-go-version.sh` script handles CI, Dockerfile, and release config updates. It also creates a git commit with those changes: + +```bash +bash tools/upgrade-go-version.sh X.Y.Z +``` + +This updates and commits: +- `.github/workflows/*.yml` — `go-version:` values +- `.goreleaser.yaml` — version check hook +- `.pyroscope.yaml` — `ref:` for Go stdlib source linking and `GO_VERSION` +- `tools/update_examples.Dockerfile` — `GO_VERSION` ARG +- All Go Dockerfiles — `FROM golang:` base image tag (excluding ebpf testdata) + +### 4. Update `toolchain` directive in go.mod files + +Update the `toolchain` directive to `goX.Y.Z` in all go.mod files using `go mod edit`: + +```bash +go mod edit -toolchain=goX.Y.Z +``` + +**go.mod files:** +- `go.mod` +- `api/go.mod` +- `lidia/go.mod` +- `examples/golang-pgo/go.mod` +- `examples/tracing/golang-push/go.mod` +- `examples/language-sdk-instrumentation/golang-push/rideshare/go.mod` +- `examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.mod` +- `examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.mod` +- `examples/language-sdk-instrumentation/golang-push/simple/go.mod` + +#### Optional: update `go` directive (minor bump only) + +The `go` directive sets the **minimum compatible Go version**. Only update it when: +- A dependency requires a newer Go version +- The codebase uses a Go language feature from the newer minor version +- The user explicitly requests it + +If updating the `go` directive, the `go` and `toolchain` values MUST differ to prevent Go from dropping the `toolchain` line. Use two separate calls: + +```bash +# For go.mod files: +go mod edit -go=X.Y.0 +go mod edit -toolchain=goX.Y.Z + +# For go.work files (go mod edit does NOT work on .work files): +go work edit -go=X.Y.0 +go work edit -toolchain=goX.Y.Z +``` + +Also update the `go` directive in the examples' go.work files (use `go work edit`; the root repo has no go.work — modules are wired with replace directives): +- `examples/golang-pgo/go.work` +- `examples/tracing/golang-push/go.work` +- `examples/language-sdk-instrumentation/golang-push/rideshare/go.work` +- `examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.work` +- `examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.work` +- `examples/language-sdk-instrumentation/golang-push/simple/go.work` + +### 5. Synchronize Go modules + +```bash +make go/mod +``` + +This runs `go mod tidy` across all modules. Required because CI runs `check/go/mod`. + +Review the diff. Expected: `go.sum` changes, small indirect dependency bumps. Investigate anything unexpected. + +### 6. Verify the build + +```bash +make go/bin +``` + +If the build fails, investigate and fix before proceeding. + +### 7. Commit remaining changes + +The script already committed CI/Dockerfile/release changes. Now commit the go.mod/go.work/go.sum changes: + +```bash +git add -u *.mod *.sum *.work api/ lidia/ examples/ +``` + +Use a commit message that reflects what changed: +- Toolchain only: `"Update Go toolchain to goX.Y.Z"` +- Toolchain + go directive: `"Update Go to X.Y.Z (go directive + toolchain)"` + +### 8. Summary + +Show the user: +- Number of files modified +- Old -> New version for each category (go directive, toolchain, CI, Dockerfiles) +- Whether it was a minor or patch bump +- Build verification result +- Remind user to review commits and push when ready + +## Version semantics reference + +| Directive | Meaning | When to update | +|-----------|---------|---------------| +| `go X.Y.Z` | Minimum Go version for compatibility | Only when a dependency or language feature requires it | +| `toolchain goX.Y.Z` | Exact build version (bug fixes, security) | Every bump (patch and minor) | +| CI `go-version` | Exact version CI uses to build/test | Every bump (via script) | +| Dockerfile `golang:X.Y.Z` | Exact version for container builds | Every bump (via script) | diff --git a/.cursor/rules/development-workflow.mdc b/.cursor/rules/development-workflow.mdc new file mode 100644 index 0000000000..5999d5d8b2 --- /dev/null +++ b/.cursor/rules/development-workflow.mdc @@ -0,0 +1,92 @@ +--- +description: Development workflow, commands, and commit guidelines for Pyroscope +globs: +alwaysApply: false +--- + +# Development Workflow + +## Prerequisites + +- Go 1.25 (see `go.mod`) +- Docker +- Node.js (recent LTS) + Yarn 4 (Berry) — only needed for frontend work in `ui/` +- All other tools auto-download to `.tmp/bin/` + +## Build Commands + +```bash +# Build backend +make go/bin + +# Run Go tests +make go/test + +# Frontend dev (run from ui/): Vite dev server on :5173, proxies API to :4040 +cd ui && yarn install && yarn dev +# Production frontend build (Docker -> ui/dist; required before `make build`) +make frontend/build + +# Docker image +make GOOS=linux GOARCH=amd64 docker-image/pyroscope/build +``` + +## Running Locally + +```bash +# Run all components in monolithic mode with embedded Grafana +go run ./cmd/pyroscope --target all,embedded-grafana +# Pyroscope: http://localhost:4040 +# Grafana: http://localhost:4041 +``` + +## Code Generation + +**CRITICAL**: After changing protobuf, configs, or flags: + +```bash +make generate +``` + +Commit the generated files with your changes. + +## Useful Make Targets + +```bash +make help # Show all available targets +make lint # Run linters +make go/test # Run Go unit tests +make go/bin # Build binaries +make go/mod # Tidy go modules +make generate # Generate code (protobuf, mocks, etc.) +make docker-image/pyroscope/build # Build Docker image +``` + +## Commit Guidelines + +1. **Atomic Commits**: Each commit should be a logical unit +2. **Commit Messages**: Focus on "why" not just "what" +3. **Generated Code**: Include generated files in the same commit as source changes +4. **Format**: Follow existing commit message style (see `git log --oneline -20`) + +## When Working on Features + +1. **Read Component Docs**: Check `docs/sources/reference-pyroscope-architecture/components/` for the component you're modifying +2. **Understand the Ring**: If working on write/read path, understand consistent hashing +3. **Multi-tenancy First**: Always consider multi-tenant implications +4. **Check for Similar Code**: Pyroscope is inspired by Cortex/Mimir - similar patterns apply +5. **Test Multi-tenancy**: Test with multiple tenants to catch isolation issues +6. **Profile Your Changes**: Use `go test -bench` and verify performance impact +7. **Update Documentation**: If changing user-facing behavior, update docs + +## Documentation Locations + +- **User Docs**: `docs/sources/` - Published to grafana.com +- **Contributing**: `docs/internal/contributing/README.md` +- **Component Docs**: `docs/sources/reference-pyroscope-architecture/components/` + +## Getting Help + +- **Contributing Guide**: `docs/internal/contributing/README.md` +- **Code Comments**: The codebase has extensive comments - read them +- **Git History**: Use `git blame` and `git log` to understand design decisions diff --git a/.cursor/rules/go-backend.mdc b/.cursor/rules/go-backend.mdc new file mode 100644 index 0000000000..e88806ce9b --- /dev/null +++ b/.cursor/rules/go-backend.mdc @@ -0,0 +1,154 @@ +--- +description: Go backend coding standards and patterns for Pyroscope +globs: + - "**/*.go" + - "!**/*_test.go" +--- + +# Go Backend Development + +## Import Organization + +Always organize imports into three groups separated by blank lines: + +```go +import ( + // Standard library + "context" + "fmt" + + // Third-party packages + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/atomic" + + // Internal packages + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" +) +``` + +**Don't** add imports within the three import groups (keep them separate). + +## Formatting & Linting + +- Use `golangci-lint` (run via `make lint`) +- gofmt for formatting +- goimports with `-local github.com/grafana/pyroscope` +- Enabled linters: depguard, goconst, misspell, revive, unconvert, unparam + +## Logging + +- **Use**: `github.com/go-kit/log` +- **Don't**: `github.com/go-kit/kit/log` (deprecated import path) +- **Don't**: `fmt.Println` for logging + +Use structured logging: + +```go +import "github.com/go-kit/log/level" + +level.Error(logger).Log("msg", "failed to process", "err", err) +level.Info(logger).Log("msg", "processing complete", "count", count) +``` + +## Error Handling + +- Always check errors explicitly +- Wrap errors with context: + +```go +if err != nil { + return fmt.Errorf("failed to query: %w", err) +} +``` + +## Context Usage + +- Always pass `context.Context` as the first parameter +- Respect context cancellation in loops and long operations: + +```go +func process(ctx context.Context, items []Item) error { + for _, item := range items { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + // process item + } + return nil +} +``` + +## Multi-tenancy Pattern + +All requests must include a tenant ID. Extract from context: + +```go +import "github.com/grafana/pyroscope/v2/pkg/tenant" + +tenantID, err := tenant.ExtractTenantIDFromContext(ctx) +if err != nil { + return err +} +``` + +**Never** hardcode tenant IDs. + +## Object Storage Pattern + +Use the abstract Bucket interface: + +```go +import "github.com/grafana/pyroscope/v2/pkg/objstore" + +bucket := objstore.NewBucket(cfg) +reader, err := bucket.Get(ctx, "path/to/object") +``` + +## Configuration Pattern + +Use `github.com/grafana/dskit` for configuration: + +```go +type Config struct { + ListenPort int `yaml:"listen_port"` +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + f.IntVar(&cfg.ListenPort, "server.http-listen-port", 4040, "HTTP listen port") +} +``` + +## Performance Considerations + +1. **Minimize Allocations in Hot Paths**: + - Reuse buffers with `sync.Pool` + - Avoid string concatenation in loops + - Use `strings.Builder` for string building + +2. **Concurrency**: + - Use worker pools for bounded concurrency + - Prefer channels for coordination over mutexes when possible + - Don't create unbounded goroutines - use worker pools or semaphores + +3. **Profile Your Changes**: + ```bash + go test -cpuprofile=cpu.prof -memprofile=mem.prof -bench=. + go tool pprof cpu.prof + ``` + +## Code Generation + +**IMPORTANT**: After changing protobuf, configs, or flags: +```bash +make generate +``` +Commit the generated files with your changes. + +## Security + +1. **Input Validation**: Always validate and sanitize user input +2. **Path Traversal**: Validate object keys before storage operations +3. **Rate Limiting**: Distributor implements per-tenant rate limiting diff --git a/.cursor/rules/go-testing.mdc b/.cursor/rules/go-testing.mdc new file mode 100644 index 0000000000..ab732d9357 --- /dev/null +++ b/.cursor/rules/go-testing.mdc @@ -0,0 +1,140 @@ +--- +description: Go testing standards and patterns for Pyroscope +globs: + - "**/*_test.go" +--- + +# Go Testing Standards + +## Test File Naming + +- Test files: `*_test.go` +- Test function naming: `TestFunctionName` or `TestComponentName_Method` + +## Test Structure + +Use table-driven tests for multiple cases: + +```go +func TestDistributor_Push(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input *pushv1.PushRequest + wantErr bool + }{ + {name: "valid request", input: validRequest(), wantErr: false}, + {name: "invalid tenant", input: invalidRequest(), wantErr: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := setupDistributor(t) + err := d.Push(context.Background(), tt.input) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} +``` + +## Assertions + +- Use `require` for fatal assertions (test stops on failure) +- Use `assert` for non-fatal assertions (test continues) + +```go +import ( + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Fatal - stops test immediately +require.NoError(t, err) +require.NotNil(t, result) + +// Non-fatal - continues test +assert.Equal(t, expected, actual) +``` + +## Test Organization + +1. **Subtests**: Use `t.Run()` for grouping related cases +2. **Parallel Tests**: Use `t.Parallel()` when tests are independent +3. **Cleanup**: Always use `t.Cleanup()` for resource cleanup + +```go +func TestComponent(t *testing.T) { + t.Parallel() + + resource := createResource(t) + t.Cleanup(func() { + resource.Close() + }) + + t.Run("subtest", func(t *testing.T) { + // test logic + }) +} +``` + +## Test Data + +- Store test data in `testdata/` directories +- Use relative paths from the test file + +## Integration Tests + +Use build tags for integration tests: + +```go +//go:build integration + +package mypackage_test + +func TestIntegration(t *testing.T) { + // ... +} +``` + +## Mocking + +- Use `mockery` for generating mocks from interfaces +- Place mocks in appropriate locations based on scope + +## Multi-tenancy Testing + +**Always test with multiple tenants** to catch isolation issues: + +```go +func TestMultiTenant(t *testing.T) { + tenants := []string{"tenant-a", "tenant-b"} + + for _, tenant := range tenants { + t.Run(tenant, func(t *testing.T) { + ctx := tenant.InjectTenantID(context.Background(), tenant) + // verify tenant isolation + }) + } +} +``` + +## Running Tests + +```bash +# Run all tests +make go/test + +# Run specific package tests +go test ./pkg/distributor/... + +# Run with race detector +go test -race ./... + +# Run benchmarks +go test -bench=. ./pkg/... +``` diff --git a/.cursor/rules/pyroscope-general.mdc b/.cursor/rules/pyroscope-general.mdc new file mode 100644 index 0000000000..2d78c57faf --- /dev/null +++ b/.cursor/rules/pyroscope-general.mdc @@ -0,0 +1,103 @@ +--- +description: General Pyroscope project context and architecture overview +globs: +alwaysApply: true +--- + +# Pyroscope - Project Overview + +Pyroscope is a horizontally scalable, highly available, multi-tenant continuous profiling aggregation system. +It stores and queries profiling data at scale, similar to how Prometheus works for metrics and Loki for logs. + +## Key Characteristics +- Written in **Go** +- Microservices-based architecture inspired by Cortex/Mimir/Loki +- Stores profiling data in object storage (S3, GCS, Azure, etc.) +- Multi-tenant by design + +## Architecture + +Pyroscope uses a **microservices architecture** where a single binary can run different components based on the `-target` parameter. + +### V1 Components + +**Write Path:** +- **Distributor**: Receives profile ingestion requests, validates, and forwards to ingesters +- **Ingester**: Stores profiles in memory, periodically flushes to disk as blocks, periodically uploads blocks to long-term object storage +- **Compactor**: Merges blocks and removes duplicates + +**Read Path:** +- **Query Frontend**: Entry point for queries, handles query splitting and caching +- **Query Scheduler**: Manages query queue and ensures fair execution across tenants +- **Querier**: Executes queries by fetching data from ingesters and store-gateways +- **Store Gateway**: Indexes and serves blocks from long-term object storage + +### V2 Components + +**Write Path:** +- **Distributor**: Receives profile ingestion requests, validates, and forwards to segment writers +- **Segment Writer**: Writes block segments to long-term object storage and their metadata to metastore +- **Metastore**: Maintains the block metadata index and coordinates the block compaction process +- **Compaction Worker**: Merges small segments into larger blocks + +**Read Path:** +- **Query Frontend**: Entry point for queries, creates the query plan and executes it against query backends +- **Query Backend**: Executes queries and merges query responses + +### Storage +- **Block Format**: Profiles stored in Parquet tables, series data in a TSDB index, symbols in a custom format +- **Multi-tenant**: Each tenant has isolated storage +- **Object Storage**: Primary storage backend (S3, GCS, Azure, local filesystem) + +## Repository Structure + +``` +. +├── cmd/ +│ ├── pyroscope/ # Main server binary +│ └── profilecli/ # CLI tool for profile operations +├── pkg/ # Core Go packages +│ ├── distributor/ # Distributor component +│ ├── ingester/ # Ingester component +│ ├── querier/ # Querier component +│ ├── frontend/ # Query frontend component +│ ├── compactor/ # Compactor component +│ ├── metastore/ # Metadata component +│ ├── phlaredb/ # V1 database storage engine +│ ├── model/ # Data models and types +│ ├── objstore/ # Object storage abstraction +│ ├── api/ # API definitions and handlers +│ └── og/ # Legacy code (original Pyroscope) - DO NOT USE +├── ui/ # React/TypeScript frontend (Vite) - has its own ui/CLAUDE.md +├── api/ # API definitions (protobuf, OpenAPI) +├── docs/ # Documentation +├── operations/ # Deployment configs (jsonnet, helm) +├── examples/ # Example applications and SDKs +└── tools/ # Development and build tools +``` + +## Key Dependencies + +- **dskit**: Grafana's distributed systems toolkit (ring, services, middleware) +- **connect**: RPC framework (gRPC-compatible) +- **parquet-go**: Parquet file format implementation +- **go-kit/log**: Structured logging +- **prometheus/client_golang**: Metrics instrumentation +- **opentelemetry**: Distributed tracing + +## Critical Rules + +1. **Multi-tenancy is Critical**: Tenant isolation bugs are severe - test thoroughly +2. **Performance Matters**: This system handles high-throughput profiling data +3. **Favor Simplicity**: Pyroscope values simple, maintainable code over clever abstractions +4. **Consistency with Grafana Labs Style**: Follow patterns from dskit, Mimir, Loki +5. **Ask Before Large Refactors**: Propose significant architectural changes before implementing + +## Things to Avoid + +1. **Don't** introduce dependencies on `pkg/og/` - this is legacy code being phased out +2. **Don't** hardcode tenant IDs - always extract from context +3. **Don't** create unbounded goroutines - use worker pools or semaphores +4. **Don't** log PII or sensitive data +5. **Don't** commit changes to `node_modules/` or generated code without source changes +6. **Don't** modify frontend code (`ui/`) - the frontend is not actively developed and changes are discouraged; if you do need to change it, read `ui/CLAUDE.md` first diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000000..729eefc686 --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,14 @@ +{ + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:3.1.0": { + "version": "3.1.0", + "resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:62e04ec83d944da4fd2830f68a677d1f5466c0654aea1e4baa30232d16029ac1", + "integrity": "sha256:62e04ec83d944da4fd2830f68a677d1f5466c0654aea1e4baa30232d16029ac1" + }, + "ghcr.io/devcontainers/features/node:2.1.0": { + "version": "2.1.0", + "resolved": "ghcr.io/devcontainers/features/node@sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857", + "integrity": "sha256:586c9a6f7dd40bd3ba2cd41e7f2f88dcc31fbe5d1442afcbf07ffbc66b686857" + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..e24a54958b --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,22 @@ +{ + "name": "Go", + "image": "mcr.microsoft.com/devcontainers/go:1.25-bookworm", + "features": { + "ghcr.io/devcontainers/features/node:2.1.0": {}, + "ghcr.io/devcontainers/features/docker-in-docker:3.1.0": { + "version": "latest", + "moby": true + } + }, + "customizations": { + "vscode": { + "extensions": [ + "golang.go", + "esbenp.prettier-vscode" + ] + } + }, + "appPort": [ + "4040:4040" + ] +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 0020fc03ac..0000000000 --- a/.editorconfig +++ /dev/null @@ -1,5 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 85173d15df..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,21 +0,0 @@ -public/build/** -scripts/** -pkg/api/static/** -**/dist -.eslintrc.js -jest.config.js -cypress/** -cypress.config.ts -testSetupFile.js -og/** -examples/** -public/app/util/** -public/app/stories/** -**.spec.ts* -svg-transform.js -setupAfterEnv.ts -globalSetup.js -globalTeardown.js -jest-css-modules-transform-config.js -cmd/profilecli/** -tools/k6/** diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 6cc3798824..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,72 +0,0 @@ -module.exports = { - plugins: ['@typescript-eslint', 'css-modules'], - extends: [ - '@grafana/eslint-config', - 'plugin:import/recommended', - 'plugin:import/typescript', - ], - plugins: ['unused-imports'], - rules: { - 'react/react-in-jsx-scope': 'error', - 'react-hooks/exhaustive-deps': 'error', - 'no-duplicate-imports': 'off', - '@typescript-eslint/naming-convention': [ - 'warn', - { selector: 'function', format: ['PascalCase', 'camelCase'] }, - ], - '@typescript-eslint/no-duplicate-imports': 'error', - '@typescript-eslint/no-unused-vars': 'off', - 'unused-imports/no-unused-imports': 'error', - 'unused-imports/no-unused-vars': [ - 'error', - { - vars: 'all', - varsIgnorePattern: '^_', - args: 'after-used', - argsIgnorePattern: '^_', - }, - ], - 'import/no-relative-packages': 'error', - 'no-restricted-imports': [ - 'error', - { - patterns: [ - // Dialing back this restriction for now - // { - // group: ['../*', './*'], - // message: - // 'Usage of relative parent imports is not allowed. Please use absolute(use alias) imports instead.', - // }, - ], - }, - ], - 'react/prop-types': ['off'], - }, - env: { - browser: true, - jquery: true, - }, - settings: { - 'import/internal-regex': '^@webapp', - 'import/resolver': { - node: { - extensions: ['.ts', '.tsx', '.es6', '.js', '.json', '.svg'], - }, - typescript: { - project: 'tsconfig.json', - }, - }, - }, - parserOptions: { - project: ['tsconfig.json'], - }, - overrides: [ - { - // For tests it's fine to import with ./myfile, since tests won't be overriden downstream - files: ['*.spec.tsx', '*.spec.ts'], - rules: { - 'no-restricted-imports': 'off', - }, - }, - ], -}; diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index b0d7bc4aeb..0eba0e55f3 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -1,26 +1,52 @@ -name: Backport PR creator +name: Backport PR Creator +run-name: "Backport for ${{ github.event.pull_request.title }} (#${{ github.event.pull_request.number }})" + on: - pull_request_target: + pull_request: types: - closed - labeled +permissions: + contents: read + id-token: write + jobs: main: - if: github.repository == 'grafana/pyroscope' - runs-on: ubuntu-latest + # We don't run the backporting for PRs from forks because those can't access "pyroscope-development-app" secrets in vault. + # We don't use GitHub actions app (secrets.GITHUB_TOKEN) because PRs created by the bot don't trigger CI. + # Also only run if the PR is merged, as an extra safe-guard. + # On 'labeled' events, require that the label just added is itself a backport label, otherwise + # adding an unrelated label to an already-backported PR would re-trigger the job with the wrong label. + if: | + !github.event.pull_request.head.repo.fork && + github.event.pull_request.merged == true && + ( + (github.event.action == 'labeled' && startsWith(github.event.label.name, 'backport ')) || + (github.event.action == 'closed' && contains(join(github.event.pull_request.labels.*.name, ','), 'backport ')) + ) + + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-small' || 'ubuntu-latest' }} steps: - - name: Checkout Actions - uses: actions/checkout@v4 + - id: get-github-app-token + uses: grafana/shared-workflows/actions/create-github-app-token@580590a644e82e79bb2598bdaba0be245a14dda0 # create-github-app-token/v0.2.2 with: - repository: grafana/grafana-github-actions - path: ./actions - ref: main - - name: Install Actions - run: npm install --production --prefix ./actions + github_app: pyroscope-development-app + + - name: Checkout Pyroscope + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + ref: ${{ github.event.repository.default_branch }} + fetch-depth: 2 + persist-credentials: false + - name: Run backport - uses: ./actions/backport + uses: grafana/grafana-github-actions-go/backport@f49c00e5c4585f724717bdbb003c3560a3c1d849 with: - token: ${{ secrets.GITHUB_TOKEN }} - labelsToAdd: backport - title: "[{{base}}] {{originalTitle}}" + token: ${{ steps.get-github-app-token.outputs.token }} + # If triggered by being labelled, only backport that label. + # Otherwise, the action will backport all labels. + pr_label: ${{ github.event.action == 'labeled' && github.event.label.name || '' }} + pr_number: ${{ github.event.pull_request.number }} + repo_owner: ${{ github.repository_owner }} + repo_name: ${{ github.event.repository.name }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..85c7345c79 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,214 @@ +name: ci +on: + push: + branches: + - main + + pull_request: + +permissions: + contents: read + +concurrency: + # Cancel any running workflow for the same branch when new commits are pushed. + # We group both by ref_name (available when CI is triggered by a push to a branch/tag) + # and head_ref (available when CI is triggered by a PR). + group: "${{ github.ref_name }}-${{ github.head_ref }}" + cancel-in-progress: true + +jobs: + format: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-large' || 'ubuntu-latest' }} + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Install Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Format + run: make fmt check/unstaged-changes + check-generated: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-large' || 'ubuntu-latest' }} + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Install Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Check generated files + run: make generate check/unstaged-changes + check-example-templates: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-large' || 'ubuntu-latest' }} + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Install Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Check example templates + run: make examples/check-templates + test: + strategy: + fail-fast: false + matrix: + arch: [amd64, arm64] + go_test_flags: + - "-race -cover" + - "" + # Compute runner OS dynamically based on arch and repo ownership + runs-on: >- + ${{ + github.repository_owner == 'grafana' + && format('ubuntu-{0}-large', matrix.arch) + || (matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04') + }} + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Install Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Go Mod + run: make check/go/mod + - name: Test + run: make go/test GO_TEST_FLAGS="${{ matrix.go_test_flags }}" + test-integration: + strategy: + fail-fast: false + matrix: + arch: [amd64, arm64] + go_test_flags: ["-race -cover", ""] + # Compute runner OS dynamically based on arch and repo ownership + runs-on: >- + ${{ + github.repository_owner == 'grafana' + && format('ubuntu-{0}-large', matrix.arch) + || (matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04') + }} + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Install Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Integration Test + run: make go/test-integration GO_TEST_FLAGS="${{ matrix.go_test_flags }}" + lint: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-large' || 'ubuntu-latest' }} + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Install Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Run linter + run: make lint + - name: Check helm manifests + run: make helm/check check/unstaged-changes + + test-docs: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-small' || 'ubuntu-latest' }} + steps: + - name: "Check out code" + uses: "actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5" # v4 + with: + persist-credentials: false + - name: "Test docs" + run: make docs/test + + build-image: + if: github.event_name != 'push' + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} + steps: + - name: Checkout Repo + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Set up QEMU + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + - name: Set up go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Build image Pyroscope + run: make docker-image/pyroscope/build-multiarch "BUILDX_ARGS=--cache-from=type=gha --cache-to=type=gha" + + build-push: + if: github.event_name == 'push' && github.repository == 'grafana/pyroscope' + permissions: + contents: read + id-token: write + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-large' || 'ubuntu-latest' }} + outputs: + image: ${{ steps.push-metadata.outputs.image }} + image-digest: ${{ steps.push-metadata.outputs.image-digest }} + image-tag: ${{ steps.push-metadata.outputs.image-tag }} + steps: + - name: Checkout Repo + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Set up QEMU + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + - name: Set up go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Log into GAR + uses: grafana/shared-workflows/actions/login-to-gar@c7ad5f57693ac858c698d95783685a9cbfd91223 # login-to-gar/v1.0.1 + with: + registry: us-docker.pkg.dev + - name: Pyroscope Build & push multi-arch image + id: build-push + run: | + make docker-image/pyroscope/push-multiarch "BUILDX_ARGS=--cache-from=type=gha --cache-to=type=gha" + - name: Get image, image tag and image digest + id: push-metadata + run: | + image=$(cat ./.docker-image-name-pyroscope) + echo "image=${image}" >> "$GITHUB_OUTPUT" + echo "image-tag=${image#*:}" >> "$GITHUB_OUTPUT" + echo "image-digest=$(cat ./.docker-image-digest-pyroscope)" >> "$GITHUB_OUTPUT" + + deploy-dev: + permissions: + contents: read + id-token: write + if: github.event_name == 'push' && github.repository == 'grafana/pyroscope' && github.ref == 'refs/heads/main' + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-small' || 'ubuntu-latest' }} + needs: [build-push] + steps: + - id: "submit-argowfs-deployment" + name: "Submit Argo Workflows deployment" + uses: grafana/shared-workflows/actions/trigger-argo-workflow@c2f1df59dba624b3fd509e5181aa8da5217120c0 + with: + namespace: "phlare-cd" + workflow_template: "deploy-pyroscope-dev" + parameters: | + dockertag=${{ needs.build-push.outputs.image-tag }} + commit=${{ github.sha }} + - name: Print URI + run: | + echo "URI: ${{ steps.submit-argowfs-deployment.outputs.uri }}" diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml deleted file mode 100644 index 6bf4c735c2..0000000000 --- a/.github/workflows/e2e.yaml +++ /dev/null @@ -1,77 +0,0 @@ -name: e2e -on: - push: - branches: - - main - pull_request: - -concurrency: - # Cancel any running workflow for the same branch when new commits are pushed. - # We group both by ref_name (available when CI is triggered by a push to a branch/tag) - # and head_ref (available when CI is triggered by a PR). - group: "e2e-${{ github.ref_name }}-${{ github.head_ref }}" - cancel-in-progress: true - -jobs: - regular-path: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: lts/hydrogen - cache: yarn - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: "1.21.10" - cache: true - - run: yarn --frozen-lockfile - - run: make build - - name: Cypress run - uses: cypress-io/github-action@v5 - with: - wait-on: http://localhost:4040/ready - start: make run - config-file: cypress/ci.ts - env: - ELECTRON_ENABLE_LOGGING: 1 - - uses: actions/upload-artifact@v2 - if: always() - with: - name: regular-path-cypress-screenshots - path: cypress/screenshots - - base-path: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: lts/hydrogen - cache: yarn - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: "1.21.10" - cache: true - - run: yarn --frozen-lockfile - - run: make build - - name: run nginx with /foobar/ - run: docker-compose -f scripts/base-url/docker-compose.yaml up -d - - name: Cypress run - uses: cypress-io/github-action@v5 - with: - wait-on: http://localhost:8080/foobar/ready - start: | - make run PARAMS=-api.base-url=/foobar/ - config-file: cypress/ci-base-path.ts - env: - ELECTRON_ENABLE_LOGGING: 1 - - uses: actions/upload-artifact@v2 - if: always() - with: - name: base-path-cypress-screenshots - path: cypress/screenshots diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index f78699fe29..503a2b23cd 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -4,72 +4,147 @@ on: branches: - main pull_request: - concurrency: # Cancel any running workflow for the same branch when new commits are pushed. # We group both by ref_name (available when CI is triggered by a push to a branch/tag) # and head_ref (available when CI is triggered by a PR). group: "frontend-${{ github.ref_name }}-${{ github.head_ref }}" cancel-in-progress: true - +permissions: + contents: read jobs: + install: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} + defaults: + run: + working-directory: ui + steps: + - name: Checkout code + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + node-version: 24 + - run: corepack enable + - name: Get yarn cache dir + id: yarn-cache + run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT + - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: yarn-${{ hashFiles('ui/yarn.lock') }} + restore-keys: yarn- + - run: yarn install --immutable + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: node_modules + include-hidden-files: true + path: | + ui/node_modules + ui/.yarn/install-state.gz type-check: - runs-on: ubuntu-latest + needs: install + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} + defaults: + run: + working-directory: ui steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: - node-version: lts/hydrogen - cache: yarn - - run: yarn --frozen-lockfile + node-version: 24 + - run: corepack enable + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: node_modules + path: ui - name: Run type-check run: yarn type-check format: - runs-on: ubuntu-latest + needs: install + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} + defaults: + run: + working-directory: ui steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: - node-version: lts/hydrogen - cache: yarn - - run: yarn --frozen-lockfile + node-version: 24 + - run: corepack enable + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: node_modules + path: ui - name: Run format run: yarn run format lint: - runs-on: ubuntu-latest + needs: install + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} + defaults: + run: + working-directory: ui steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: - node-version: lts/hydrogen - cache: yarn - - run: yarn --frozen-lockfile + node-version: 24 + - run: corepack enable + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: node_modules + path: ui - name: Run lint run: yarn lint - build: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: lts/hydrogen - cache: yarn - - run: yarn --frozen-lockfile - - name: Run build - run: yarn build test: - runs-on: ubuntu-latest + needs: install + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} + defaults: + run: + working-directory: ui steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: - node-version: lts/hydrogen - cache: yarn - - run: yarn --frozen-lockfile + persist-credentials: 'false' + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + node-version: 24 + - run: corepack enable + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: node_modules + path: ui - name: Run tests run: yarn test + build: + needs: install + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} + defaults: + run: + working-directory: ui + steps: + - name: Checkout code + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + node-version: 24 + - run: corepack enable + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: node_modules + path: ui + - name: Run build + run: yarn build diff --git a/.github/workflows/fuzzer.yml b/.github/workflows/fuzzer.yml index d55bd69fd0..d070db11dc 100644 --- a/.github/workflows/fuzzer.yml +++ b/.github/workflows/fuzzer.yml @@ -3,16 +3,19 @@ on: workflow_dispatch: {} schedule: - cron: '0 0 * * 1-5' # Run every weekday at midnight - +permissions: + contents: read jobs: go-fuzz-merge-single: - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64' || 'ubuntu-latest' }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: - go-version: 1.21.10 + go-version: 1.25.12 - name: Run Fuzz_Merge_Single run: go test -fuzz=Fuzz_Merge_Single --fuzztime 1h -run '^$' -v ./pkg/pprof/ diff --git a/.github/workflows/helm-ci.yml b/.github/workflows/helm-ci.yml index eb2dc81a99..1b2b09b36b 100644 --- a/.github/workflows/helm-ci.yml +++ b/.github/workflows/helm-ci.yml @@ -1,17 +1,33 @@ name: helm-ci - on: pull_request - +permissions: + contents: read jobs: - call-lint: - uses: grafana/helm-charts/.github/workflows/linter.yml@main - with: - filter_regex_include: .*operations/pyroscope/helm/.* + # We used to import this from grafana/helm-charts/.github/workflows/linter.yml@main, but we want to update to later version of helm-docs. + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Check Docs + run: | + make helm/docs + if ! git diff --exit-code -- operations/pyroscope/helm/pyroscope/; then + echo 'Documentation not up to date. Please run "make helm/docs" and commit changes!' >&2 + exit 1 + fi - call-lint-test: - uses: grafana/helm-charts/.github/workflows/lint-test.yaml@main + call-lint-test-pyroscope: + uses: grafana/helm-charts/.github/workflows/lint-test.yaml@9ddb81243bfc8aea3bf3d0a9954451d407cee1c6 with: ct_configfile: operations/pyroscope/helm/ct.yaml ct_check_version_increment: false helm_version: v3.14.3 - kubeVersion: "1.23" + call-lint-test-pyroscope-monitoring: + uses: grafana/helm-charts/.github/workflows/lint-test.yaml@9ddb81243bfc8aea3bf3d0a9954451d407cee1c6 + with: + ct_configfile: operations/monitoring/helm/ct.yaml + ct_check_version_increment: false + helm_version: v3.14.3 diff --git a/.github/workflows/helm-integration-httproute.yml b/.github/workflows/helm-integration-httproute.yml new file mode 100644 index 0000000000..66f28b4c92 --- /dev/null +++ b/.github/workflows/helm-integration-httproute.yml @@ -0,0 +1,45 @@ +name: helm-integration-httproute + +on: + pull_request: + paths: + - 'operations/pyroscope/helm/**' + - '.github/workflows/helm-integration-httproute.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + integration-test-httproute: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + + - name: Set up Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version-file: go.mod + cache: true + + # kind, kubectl, and helm must be on PATH; the test binary orchestrates + # everything else (cluster creation, gateway setup, chart install). + - name: Install kind + uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0 + with: + install_only: true + + - name: Install Helm + uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 + with: + version: v3.14.3 + + # kubectl is pre-installed on ubuntu-latest; this just verifies it. + - name: Check kubectl + run: kubectl version --client + + - name: Run HTTPRoute integration tests + run: go test -tags=helm_integration ./operations/pyroscope/helm/pyroscope/e2e/... -v -timeout 60m diff --git a/.github/workflows/helm-release.yml b/.github/workflows/helm-release.yml index 6ca3b5a686..52a7002b04 100644 --- a/.github/workflows/helm-release.yml +++ b/.github/workflows/helm-release.yml @@ -7,11 +7,25 @@ on: - "release-[0-9]+.[0-9]+" jobs: - call-update-helm-repo: - uses: grafana/helm-charts/.github/workflows/update-helm-repo.yaml@main + call-update-helm-repo-pyroscope: + uses: grafana/helm-charts/.github/workflows/update-helm-repo.yaml@8ac07d41b2fa02ca16dc0fc084d8f145cb690988 + permissions: + contents: "write" + id-token: "write" + packages: "write" with: charts_dir: operations/pyroscope/helm/ cr_configfile: operations/pyroscope/helm/cr.yaml ct_configfile: operations/pyroscope/helm/ct.yaml - secrets: - helm_repo_token: ${{ secrets.GH_BOT_ACCESS_TOKEN }} + github_app: grafana-pyroscope-releases + call-update-helm-repo-pyroscope-monitoring: + uses: grafana/helm-charts/.github/workflows/update-helm-repo.yaml@8ac07d41b2fa02ca16dc0fc084d8f145cb690988 + permissions: + contents: "write" + id-token: "write" + packages: "write" + with: + charts_dir: operations/pyroscope/helm/ + cr_configfile: operations/monitoring/helm/cr.yaml + ct_configfile: operations/monitoring/helm/ct.yaml + github_app: grafana-pyroscope-releases diff --git a/.github/workflows/publish-technical-documentation-next.yml b/.github/workflows/publish-technical-documentation-next.yml deleted file mode 100644 index a6f853c049..0000000000 --- a/.github/workflows/publish-technical-documentation-next.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: "publish-technical-documentation-next" - -on: - push: - branches: - - main - paths: - - "docs/sources/**" - workflow_dispatch: -jobs: - test: - runs-on: "ubuntu-latest" - steps: - - name: "Check out code" - uses: "actions/checkout@v3" - - name: "Build website" - run: | - docker run -v ${PWD}/docs/sources:/hugo/content/docs/phlare/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'make hugo' - - sync: - runs-on: "ubuntu-latest" - needs: "test" - steps: - - name: "Check out code" - uses: "actions/checkout@v3" - - - name: "Clone website-sync Action" - # WEBSITE_SYNC_TOKEN is a fine-grained GitHub Personal Access Token that expires. - # It must be regenerated in the grafanabot GitHub account and requires a Grafana organization - # GitHub administrator to update the organization secret. - # The IT helpdesk can update the organization secret. - run: "git clone --single-branch --no-tags --depth 1 -b master https://grafanabot:${{ secrets.WEBSITE_SYNC_TOKEN }}@github.com/grafana/website-sync ./.github/actions/website-sync" - - - name: "Publish to website repository (next)" - uses: "./.github/actions/website-sync" - id: "publish-next" - with: - repository: "grafana/website" - branch: "master" - host: "github.com" - # PUBLISH_TO_WEBSITE_TOKEN is a fine-grained GitHub Personal Access Token that expires. - # It must be regenerated in the grafanabot GitHub account and requires a Grafana organization - # GitHub administrator to update the organization secret. - # The IT helpdesk can update the organization secret. - github_pat: "grafanabot:${{ secrets.PUBLISH_TO_WEBSITE_TOKEN }}" - source_folder: "docs/sources" - target_folder: "content/docs/pyroscope/next" diff --git a/.github/workflows/publish-technical-documentation-release.yml b/.github/workflows/publish-technical-documentation-release.yml deleted file mode 100644 index e0587cceb6..0000000000 --- a/.github/workflows/publish-technical-documentation-release.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: "publish-technical-documentation-release" - -on: - push: - branches: - - "release/v[0-9]+.[0-9]+" - tags: - - "v[0-9]+.[0-9]+.[0-9]+" - paths: - - "docs/sources/**" - workflow_dispatch: -jobs: - test: - runs-on: "ubuntu-latest" - steps: - - name: "Check out code" - uses: "actions/checkout@v3" - - name: "Build website" - run: | - docker run -v ${PWD}/docs/sources:/hugo/content/docs/phlare/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'make hugo' - - sync: - runs-on: "ubuntu-latest" - needs: "test" - steps: - - - name: "Checkout Pyroscope repo" - uses: "actions/checkout@v3" - with: - fetch-depth: 0 - - - name: "Checkout Actions library" - uses: "actions/checkout@v3" - with: - repository: "grafana/grafana-github-actions" - path: "./actions" - - - name: "Install Actions from library" - run: "npm install --production --prefix ./actions" - - - name: "Determine if there is a matching release tag" - id: "has-matching-release-tag" - uses: "./actions/has-matching-release-tag" - with: - ref_name: "${{ github.ref_name }}" - release_tag_regexp: "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$" - release_branch_regexp: "^release/v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$" - release_branch_with_patch_regexp: "^release/v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$" - - - name: "Determine technical documentation version" - if: "steps.has-matching-release-tag.outputs.bool == 'true'" - uses: "./actions/docs-target" - id: "target" - with: - ref_name: "${{ github.ref_name }}" - - - name: "Clone website-sync Action" - if: "steps.has-matching-release-tag.outputs.bool == 'true'" - # WEBSITE_SYNC_TOKEN is a fine-grained GitHub Personal Access Token that expires. - # It must be regenerated in the grafanabot GitHub account and requires a Grafana organization - # GitHub administrator to update the organization secret. - # The IT helpdesk can update the organization secret. - run: "git clone --single-branch --no-tags --depth 1 -b master https://grafanabot:${{ secrets.WEBSITE_SYNC_TOKEN }}@github.com/grafana/website-sync ./.github/actions/website-sync" - - - name: "Publish to website repository (release)" - if: "steps.has-matching-release-tag.outputs.bool == 'true'" - uses: "./.github/actions/website-sync" - id: "publish-release" - with: - repository: "grafana/website" - branch: "master" - host: "github.com" - # PUBLISH_TO_WEBSITE_TOKEN is a fine-grained GitHub Personal Access Token that expires. - # It must be regenerated in the grafanabot GitHub account and requires a Grafana organization - # GitHub administrator to update the organization secret. - # The IT helpdesk can update the organization secret. - github_pat: "grafanabot:${{ secrets.PUBLISH_TO_WEBSITE_TOKEN }}" - source_folder: "docs/sources" - # Append ".x" to target to produce a v..x directory. - target_folder: "content/docs/pyroscope/${{ steps.target.outputs.target }}.x" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4566ae30b1..e591076038 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,83 +5,66 @@ on: # run only against tags tags: - "v*" - # do not run for weekly release tags - - "!v0.0.0-weekly*" permissions: contents: write packages: write + id-token: write + # for dispatching the update-homebrew-formulas workflow + actions: write # issues: write jobs: goreleaser: - runs-on: ubuntu-latest + runs-on: ubuntu-x64-large steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 + persist-credentials: 'false' - name: Set GIT_LAST_COMMIT_DATE run: echo "GIT_LAST_COMMIT_DATE=$(git log -1 --date=iso-strict --format=%cd)" >> $GITHUB_ENV + - name: Set IMAGE_TAG from git tag + run: echo "IMAGE_TAG=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV + - name: Set IMAGE_PUBLISH_LATEST=true, so we overwrite the latest docker image tag and update Homebrew + run: echo "IMAGE_PUBLISH_LATEST=true" >> $GITHUB_ENV # Forces goreleaser to use the correct previous tag for the changelog - name: Set GORELEASER_PREVIOUS_TAG run: echo "GORELEASER_PREVIOUS_TAG=$(git tag -l --sort=-version:refname | grep -E '^v.*' | head -n 2 | tail -1)" >> $GITHUB_ENV - run: git fetch --force --tags - - uses: actions/setup-go@v3 + - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: - go-version: "1.21.10" - cache: true - - uses: actions/setup-node@v3 + go-version: "1.25.12" + cache: false + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: - node-version: lts/hydrogen - cache: yarn + node-version: 20 + package-manager-cache: false # setup docker buildx - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - # login to docker hub - - uses: docker/login-action@v2 - name: Login to Docker Hub + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + - name: Log into GAR + uses: grafana/shared-workflows/actions/login-to-gar@c7ad5f57693ac858c698d95783685a9cbfd91223 # login-to-gar/v1.0.1 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + registry: us-docker.pkg.dev - run: make frontend/build - - name: Get github app token (valid for an hour) - id: app-goreleaser - uses: tibdex/github-app-token@v1 + - uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 with: - app_id: ${{ secrets.APP_ID }} - private_key: ${{ secrets.APP_PRIVATE_KEY }} - - uses: goreleaser/goreleaser-action@v4 - with: - # either 'goreleaser' (default) or 'goreleaser-pro': - distribution: goreleaser - version: latest - args: release --rm-dist --timeout 60m + # ensure this aligns with the version specified in the /Makefile + version: v2.13.2 + args: release --clean --timeout 60m env: - GITHUB_TOKEN: ${{ steps.app-goreleaser.outputs.token }} - # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' - # distribution: - # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} - - # make generate-formulas expects PYROSCOPE_TAG to be set - - name: Set PYROSCOPE_TAG - run: echo "PYROSCOPE_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - name: Get github app token (valid for an hour) - id: brew-token - uses: tibdex/github-app-token@v1 - with: - app_id: ${{ secrets.APP_ID }} - private_key: ${{ secrets.APP_PRIVATE_KEY }} - repository: pyroscope-io/homebrew-brew - - name: Update homebrew formulas - run: | - git config --global url."https://x-access-token:$(echo "${HOMEBREW_GITHUB_TOKEN}" | xargs)@github.com/pyroscope-io/homebrew-brew".insteadOf "https://github.com/pyroscope-io/homebrew-brew" - git config --global user.email "dmitry+bot@pyroscope.io" - git config --global user.name "Pyroscope Bot " - git clone https://github.com/pyroscope-io/homebrew-brew ../homebrew-brew - cd ../homebrew-brew - make generate-formulas && git add Formula && git commit -m "chore: update formulas" && git push origin main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GORELEASER_CURRENT_TAG: ${{ github.ref_name }} + # Our Homebrew publishing currently assumes latest releases only. The + # formula update runs as a separately dispatched workflow (always from + # main, so fixes to it don't need backporting to release branches): it + # creates the tap commit through the GitHub API so it is signed — the + # tap's ruleset requires verified signatures and rejects plain git pushes. + - if: env.IMAGE_PUBLISH_LATEST == 'true' + name: Update homebrew formulas + run: gh workflow run update-homebrew-formulas.yml --repo "${GITHUB_REPOSITORY}" --ref main -f tag="${GITHUB_REF#refs/*/}" env: - HOMEBREW_GITHUB_TOKEN: ${{ steps.brew-token.outputs.token }} - GITHUB_TOKEN: ${{ steps.app-goreleaser.outputs.token }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/renovate-config-validator.yml b/.github/workflows/renovate-config-validator.yml new file mode 100644 index 0000000000..e016803a10 --- /dev/null +++ b/.github/workflows/renovate-config-validator.yml @@ -0,0 +1,32 @@ +name: Validate Renovate config + +on: + push: + branches: + - main + paths: + - 'renovate.json' + - '.github/workflows/renovate-config-validator.yml' + + pull_request: + paths: + - 'renovate.json' + - '.github/workflows/renovate-config-validator.yml' + +permissions: + contents: read + +jobs: + validate: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-small' || 'ubuntu-latest' }} + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + + - name: Validate renovate.json syntax + run: jq -e . renovate.json > /dev/null + + - name: Validate Renovate Config + uses: grafana/shared-workflows/actions/validate-renovate-config@051f0a1cef0e1ef9f92fbe57c65b1eec029c3904 # validate-renovate-config/v0.1.1 diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml new file mode 100644 index 0000000000..50180cbc0f --- /dev/null +++ b/.github/workflows/test-examples.yml @@ -0,0 +1,94 @@ +name: Test Examples + +# Builds and runs the examples and verifies that profiling data (and, for tracing +# examples, span-linked profiling data) can be queried back from Pyroscope. +# +# Runs nightly, on manual dispatch, and on any same-repository PR that touches +# examples/. Fork PRs are excluded: they cannot be trusted to run arbitrary +# docker-compose workloads on CI runners. +# These checks are intentionally NOT part of the required status checks and +# should not block merging. +on: + schedule: + - cron: '13 1 * * *' + workflow_dispatch: + inputs: + target: + description: 'Example dir or path prefix to test (e.g. examples/tracing/java or examples/language-sdk-instrumentation/java). Empty = all examples.' + required: false + default: '' + pull_request: + paths: + - 'examples/**' + +concurrency: + # Cancel any running workflow for the same branch when new commits are pushed. + group: "test-examples-${{ github.ref_name }}-${{ github.head_ref }}" + cancel-in-progress: true + +permissions: + contents: read + +jobs: + # Determine which examples to test: the ones changed by the PR, the ones under + # the manually dispatched target prefix, or all of them (scheduled runs). + detect: + # On PRs, only run for same-repository PRs (not forks): running arbitrary + # docker-compose workloads from untrusted forks on CI runners is unsafe. + if: >- + github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + outputs: + examples: ${{ steps.select.outputs.examples }} + any: ${{ steps.select.outputs.any }} + steps: + - name: Checkout code + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + fetch-depth: 0 + - name: Select examples + id: select + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha }} + TARGET_INPUT: ${{ github.event.inputs.target }} + run: | + set -euo pipefail + if [ "$EVENT_NAME" = "pull_request" ]; then + export BASE_REF="$BASE_SHA" + else + export TARGET="$TARGET_INPUT" + fi + selected="$(bash tools/examples/select-examples.sh)" + + echo "Selected examples:" + printf '%s\n' "$selected" + + { + echo "examples=$(printf '%s\n' "$selected" | paste -sd, -)" + echo "any=$([ -n "$selected" ] && echo true || echo false)" + } >> "$GITHUB_OUTPUT" + + # Bring each selected example up once and verify it: profiles are queried for + # every example (Series + SelectSeries); tracing examples additionally get the + # trace-to-profile link checked (SelectMergeSpanProfile). The profiles and + # trace-link results show up as subtests in this job's output. + test: + needs: detect + if: needs.detect.outputs.any == 'true' + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-large' || 'ubuntu-latest' }} + steps: + - name: Checkout code + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + - name: Install Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: 1.25.12 + - name: Query profiles (and span profiles) for selected examples + env: + PYROSCOPE_TEST_EXAMPLES: ${{ needs.detect.outputs.examples }} + run: make examples/test diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index ad0961c1d3..0000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,156 +0,0 @@ -name: ci -on: - push: - branches: - - main - - r[0-9]+ # Trigger builds after a push to weekly branches - pull_request: - -concurrency: - # Cancel any running workflow for the same branch when new commits are pushed. - # We group both by ref_name (available when CI is triggered by a push to a branch/tag) - # and head_ref (available when CI is triggered by a PR). - group: "${{ github.ref_name }}-${{ github.head_ref }}" - cancel-in-progress: true - -jobs: - format: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.10 - - name: Format - run: make fmt check/unstaged-changes - test: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.10 - - name: Go Mod - run: make check/go/mod - - name: Test - run: make go/test - lint: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.10 - - name: Run linter - run: make lint - - name: Check helm manifests - run: make helm/check check/unstaged-changes - - test-docs: - runs-on: ubuntu-latest - steps: - - name: "Check out code" - uses: "actions/checkout@v3" - - name: "Test docs" - run: make docs/test - - doc-validator: - runs-on: "ubuntu-latest" - container: - image: "grafana/doc-validator:v4.1.1" - steps: - - name: "Checkout code" - uses: "actions/checkout@v3" - - name: "Run doc-validator tool" - run: > - doc-validator - '--skip-checks=^image.+$' - docs/sources - /docs/writers-toolkit - | reviewdog - -f=rdjsonl - --fail-on-error - --filter-mode=nofilter - --name=doc-validator - --reporter=github-pr-review - env: - REVIEWDOG_GITHUB_API_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - build-image: - if: github.event_name != 'push' - runs-on: ubuntu-latest - steps: - - name: Checkout Repo - uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v1 - - name: Set up go - uses: actions/setup-go@v2 - with: - go-version: 1.21.10 - - uses: actions/setup-node@v3 - with: - node-version: lts/hydrogen - cache: yarn - - name: Build image Pyroscope - run: make docker-image/pyroscope/build "BUILDX_ARGS=--cache-from=type=gha --cache-to=type=gha" - - build-push: - if: github.event_name == 'push' && github.repository == 'grafana/pyroscope' - runs-on: ubuntu-latest - steps: - - name: Checkout Repo - uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v1 - - name: Set up go - uses: actions/setup-go@v2 - with: - go-version: 1.21.10 - - uses: actions/setup-node@v3 - with: - node-version: lts/hydrogen - cache: yarn - - name: Login to GCR - uses: docker/login-action@v2 - with: - registry: us.gcr.io - username: _json_key - password: ${{ secrets.GCR_JSON_KEY }} - - name: Pyroscope Build & push multi-arch image - id: build-push - run: | - make docker-image/pyroscope/push "BUILDX_ARGS=--cache-from=type=gha --cache-to=type=gha" - - deploy-dev-001: - if: github.event_name == 'push' && github.repository == 'grafana/pyroscope' - runs-on: ubuntu-latest - needs: [build-push] - steps: - - name: Checkout Repo - uses: actions/checkout@v3 - - name: Get github app token (valid for an hour) - id: app-release - uses: tibdex/github-app-token@v1 - with: - app_id: ${{ secrets.APP_ID }} - private_key: ${{ secrets.APP_PRIVATE_KEY }} - repository: grafana/deployment_tools - - name: Deploy to fire-dev-001 - run: | - git config --global url."https://x-access-token:$(echo "${GITHUB_TOKEN}" | xargs)@github.com/grafana/deployment_tools".insteadOf "https://github.com/grafana/deployment_tools" - make docker-image/pyroscope/deploy-dev-001 - env: - GITHUB_TOKEN: ${{ steps.app-release.outputs.token }} diff --git a/.github/workflows/test_ebpf.yml b/.github/workflows/test_ebpf.yml deleted file mode 100644 index 41f2d53ff1..0000000000 --- a/.github/workflows/test_ebpf.yml +++ /dev/null @@ -1,103 +0,0 @@ -name: Test eBPF -on: - push: - branches: - - main - - r[0-9]+ # Trigger builds after a push to weekly branches - paths: - - ebpf/** - pull_request: - paths: - - ebpf/** - -concurrency: - # Cancel any running workflow for the same branch when new commits are pushed. - # We group both by ref_name (available when CI is triggered by a push to a branch/tag) - # and head_ref (available when CI is triggered by a PR). - group: "ci-ebpf-${{ github.ref_name }}-${{ github.head_ref }}" - cancel-in-progress: true - -jobs: - test_ebpf_amd64: - name: on Bare-metal amd64 - runs-on: ubuntu-latest-16-cores - steps: - - name: Checkout code - uses: actions/checkout@v3 - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.10 - - name: Test - run: sudo make -C ./ebpf go/test/amd64 - test_ebpf_qemu: - name: on QEMU - runs-on: ubuntu-latest-16-cores - strategy: - matrix: - include: -# - arch: amd64 # https://github.com/grafana/pyroscope/issues/3033 -# kernel: amd64/boot/vmlinuz-4.19.0-26-amd64 -# initrd: amd64/boot/initrd.img-4.19.0-26-amd64 - - arch: amd64 - kernel: amd64/boot/vmlinuz-5.10.0-28-amd64 - initrd: amd64/boot/initrd.img-5.10.0-28-amd64 - - arch: amd64 - kernel: amd64/boot/vmlinuz-5.15.0-94-generic - initrd: amd64/boot/initrd.img-5.15.0-94-generic - - arch: amd64 - kernel: amd64/boot/vmlinuz-5.4.0-150-generic - initrd: amd64/boot/initrd.img-5.4.0-150-generic - - arch: amd64 - kernel: amd64/boot/vmlinuz-6.1.0-18-amd64 - initrd: amd64/boot/initrd.img-6.1.0-18-amd64 - - arch: amd64 - kernel: amd64/boot_extra/vmlinuz-5.10.205-195.807.amzn2.x86_64 - initrd: amd64/boot_extra/initramfs-5.10.205-195.807.amzn2.x86_64.img - -# - arch: arm64 # https://github.com/grafana/pyroscope/issues/3033 -# kernel: arm64/boot/vmlinuz-4.19.0-26-arm64 -# initrd: arm64/boot/initrd.img-4.19.0-26-arm64 - - arch: arm64 - kernel: arm64/boot/vmlinuz-5.10.0-28-arm64 - initrd: arm64/boot/initrd.img-5.10.0-28-arm64 - - arch: arm64 - kernel: arm64/boot/vmlinuz-5.15.0-94-generic - initrd: arm64/boot/initrd.img-5.15.0-94-generic - - arch: arm64 - kernel: arm64/boot/vmlinuz-5.4.0-150-generic - initrd: arm64/boot/initrd.img-5.4.0-150-generic - - arch: arm64 - kernel: arm64/boot/vmlinuz-6.1.0-18-arm64 - initrd: arm64/boot/initrd.img-6.1.0-18-arm64 - - arch: arm64 - kernel: arm64/boot_extra/vmlinuz-5.10.205-195.807.amzn2.aarch64 - initrd: arm64/boot_extra/initramfs-5.10.205-195.807.amzn2.aarch64.img - - steps: - - name: Checkout code with submodule - uses: actions/checkout@v3 - with: - submodules: recursive - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.10 - - name: Install qemu - run: sudo apt-get update && sudo apt-get -y install qemu-system-x86 qemu-system-aarch64 - - name: Build tests - run: make -C ./ebpf ebpf.${{ matrix.arch }}.test - - name: Pull VM image - run: make -C ./ebpf/testdata/qemu_img dist/pull - - name: Start VM - run: > - KVM_ARGS="" ARCH=${{ matrix.arch }} KERNEL=${{ matrix.kernel }} INITRD=${{ matrix.initrd }} make -C ./ebpf/testdata/qemu_img qemu/start_and_wait - - name: Copy test binary - run: > - F=$(realpath ./ebpf/ebpf.${{ matrix.arch }}.test) make -C ./ebpf/testdata/qemu_img qemu/scp - - name: Uname - run: > - CMD="uname -a" make -C ./ebpf/testdata/qemu_img qemu/exec - - name: Run tests - run: > - CMD=./ebpf.${{ matrix.arch }}.test make -C ./ebpf/testdata/qemu_img qemu/exec diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml new file mode 100644 index 0000000000..955d1a4b86 --- /dev/null +++ b/.github/workflows/update-contributors.yml @@ -0,0 +1,65 @@ +name: Update Contributors in README + +on: + schedule: + - cron: '0 0 1 * *' + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + update-contributors: + if: github.repository == 'grafana/pyroscope' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + ref: main + - id: get-github-app-token + uses: grafana/shared-workflows/actions/create-github-app-token@580590a644e82e79bb2598bdaba0be245a14dda0 # create-github-app-token/v0.2.2 + with: + github_app: pyroscope-development-app + - name: Get GitHub App User ID + id: get-user-id + env: + GITHUB_TOKEN: ${{ steps.get-github-app-token.outputs.token }} + run: | + APP_BOT="pyroscope-development-app[bot]" + echo "user-id=$(gh api "/users/${APP_BOT}" --jq .id)" >> "$GITHUB_OUTPUT" + - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6 + with: + go-version: 1.25.12 + - name: Update contributors + run: make update-contributors + + - name: Commit and push changes + env: + GITHUB_TOKEN: ${{ steps.get-github-app-token.outputs.token }} + run: | + APP_BOT="pyroscope-development-app[bot]" + git config --local user.name "${APP_BOT}" + git config --local user.email "${{ steps.get-user-id.outputs.user-id }}+${APP_BOT}@users.noreply.github.com" + + if ! git diff --exit-code README.md; then + BRANCH_NAME="update-contributors-$(date +%Y%m%d)" + git checkout -b "${BRANCH_NAME}" + git add README.md + git commit -m 'docs: updates the list of contributors in README' + git push https://x-access-token:${{ steps.get-github-app-token.outputs.token }}@github.com/${{ github.repository }}.git HEAD:${BRANCH_NAME} + + # Check if PR already exists for this branch + EXISTING_PR=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[0].number' || echo "") + if [ -z "$EXISTING_PR" ]; then + gh pr create \ + --title "docs: updates the list of contributors in README" \ + --body "This PR automatically updates the list of contributors in the README." \ + --base main \ + --head "${BRANCH_NAME}" + else + echo "PR #${EXISTING_PR} already exists for this branch" + fi + fi \ No newline at end of file diff --git a/.github/workflows/update-examples-cron.yml b/.github/workflows/update-examples-cron.yml new file mode 100644 index 0000000000..f92f9e2112 --- /dev/null +++ b/.github/workflows/update-examples-cron.yml @@ -0,0 +1,33 @@ +name: Update Examples Cron + +on: + schedule: + - cron: '0 */8 * * *' + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + update-examples-cron: + if: github.repository == 'grafana/pyroscope' + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-small' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: 'false' + - id: get-github-app-token + uses: grafana/shared-workflows/actions/create-github-app-token@580590a644e82e79bb2598bdaba0be245a14dda0 # create-github-app-token/v0.2.2 + with: + github_app: pyroscope-development-app + + - run: | + make tools/update_examples + if ! git diff --exit-code; + then + make tools/update_examples_pr + fi + env: + GITHUB_TOKEN: ${{ steps.get-github-app-token.outputs.token }} + GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/.github/workflows/update-homebrew-formulas.yml b/.github/workflows/update-homebrew-formulas.yml new file mode 100644 index 0000000000..924e71dde8 --- /dev/null +++ b/.github/workflows/update-homebrew-formulas.yml @@ -0,0 +1,93 @@ +name: update-homebrew-formulas + +# Regenerates the Homebrew formulas in grafana/homebrew-pyroscope for a given +# Pyroscope release tag and opens a PR against the tap. The commit is created +# through the GitHub API (planetscale/ghcommit-action, as used across Grafana +# repos), which signs it on behalf of the app — the tap's ruleset requires +# verified signatures on all branches, so commits pushed with plain git are +# rejected. +# +# Dispatched by the release workflow for `latest` releases, or manually for +# re-runs (e.g. when a release run failed after publishing). + +on: + workflow_dispatch: + inputs: + tag: + description: 'Pyroscope release tag to generate formulas for (e.g. v2.1.1)' + required: true + type: string + +permissions: + contents: read + # for minting the app token via OIDC + id-token: write + +jobs: + update-formulas: + runs-on: ${{ github.repository_owner == 'grafana' && 'ubuntu-x64-small' || 'ubuntu-latest' }} + env: + TAP_REPO: grafana/homebrew-pyroscope + BRANCH: update-formulas-${{ inputs.tag }} + steps: + - id: get-github-app-token + uses: grafana/shared-workflows/actions/create-github-app-token@580590a644e82e79bb2598bdaba0be245a14dda0 # create-github-app-token/v0.2.2 + with: + github_app: grafana-pyroscope-bot + - name: Checkout grafana/homebrew-pyroscope + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + repository: grafana/homebrew-pyroscope + token: ${{ steps.get-github-app-token.outputs.token }} + persist-credentials: 'false' + - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version: stable + cache: false + - name: Generate formulas + env: + GITHUB_TOKEN: ${{ steps.get-github-app-token.outputs.token }} + PYROSCOPE_TAG: ${{ inputs.tag }} + run: make generate-formulas + - name: Detect formula changes + id: changes + run: echo "any=$(git status --porcelain -- Formula | grep -q . && echo true || echo false)" >> "$GITHUB_OUTPUT" + - name: Create branch + if: steps.changes.outputs.any == 'true' + env: + GH_TOKEN: ${{ steps.get-github-app-token.outputs.token }} + run: | + # (Re)create the branch at the current main head; reset it if a + # previous run left it behind. + head_oid="$(git rev-parse HEAD)" + gh api "repos/${TAP_REPO}/git/refs" --method POST \ + -f "ref=refs/heads/${BRANCH}" -f "sha=${head_oid}" \ + || gh api "repos/${TAP_REPO}/git/refs/heads/${BRANCH}" --method PATCH \ + -f "sha=${head_oid}" -F force=true + - name: Commit formula changes + if: steps.changes.outputs.any == 'true' + uses: planetscale/ghcommit-action@a6b150b81dca5dd027baa898604418eec9e11465 # v0.2.22 + with: + commit_message: "chore: update formulas to ${{ inputs.tag }}" + repo: grafana/homebrew-pyroscope + branch: update-formulas-${{ inputs.tag }} + file_pattern: "Formula/*.rb" + env: + GITHUB_TOKEN: ${{ steps.get-github-app-token.outputs.token }} + - name: Open PR + if: steps.changes.outputs.any == 'true' + env: + GH_TOKEN: ${{ steps.get-github-app-token.outputs.token }} + PYROSCOPE_TAG: ${{ inputs.tag }} + run: | + # The tap's default branch requires reviewed PRs (org ruleset), so we + # open a PR for a maintainer to merge instead of pushing to main. + existing="$(gh pr list --repo "${TAP_REPO}" --head "${BRANCH}" --state open --json number --jq length)" + if [ "${existing}" != "0" ]; then + echo "PR for ${BRANCH} already open" + exit 0 + fi + gh pr create --repo "${TAP_REPO}" \ + --base main --head "${BRANCH}" \ + --title "chore: update formulas to ${PYROSCOPE_TAG}" \ + --body "Automated formula update for Pyroscope ${PYROSCOPE_TAG}. Review and merge to publish the new version via Homebrew." diff --git a/.github/workflows/update-make-docs.yml b/.github/workflows/update-make-docs.yml deleted file mode 100644 index 27576b4abb..0000000000 --- a/.github/workflows/update-make-docs.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Update `make docs` procedure -on: - schedule: - - cron: '0 7 * * 1-5' - workflow_dispatch: -jobs: - main: - if: github.repository == 'grafana/pyroscope' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: grafana/writers-toolkit/update-make-docs@update-make-docs/v1 - with: - pr_options: > - --label type/docs - trace: true diff --git a/.github/workflows/weekly-release.yml b/.github/workflows/weekly-release.yml index ed9ad108ed..946f8faf11 100644 --- a/.github/workflows/weekly-release.yml +++ b/.github/workflows/weekly-release.yml @@ -4,17 +4,31 @@ on: push: branches: - 'weekly/f*' + +permissions: + contents: write + id-token: write + jobs: goreleaser-weekly: - runs-on: ubuntu-latest + runs-on: ubuntu-x64-large steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 + persist-credentials: false - name: Set GORELEASER_CURRENT_TAG run: echo "GORELEASER_CURRENT_TAG=v0.0.0-$(./tools/image-tag)" >> $GITHUB_ENV - - name: Set WEEKLY_IMAGE_TAG - run: echo "WEEKLY_IMAGE_TAG=$(./tools/image-tag)" >> $GITHUB_ENV + - name: Set IMAGE_TAG + run: echo "IMAGE_TAG=$(./tools/image-tag)" >> $GITHUB_ENV + - name: Set IMAGE_PUBLISH_LATEST=false, so we don't overwrite the latest docker image tag and Homebrew version + run: echo "IMAGE_PUBLISH_LATEST=false" >> $GITHUB_ENV + - name: Set GITHUB_RELEASE_DISABLE=true, so github releases are skipped + run: echo "GITHUB_RELEASE_DISABLE=true" >> $GITHUB_ENV + - name: Set GORELEASER_STRIP_DEBUG_INFO=false, so binaries are not stripped of debug info + run: echo "GORELEASER_STRIP_DEBUG_INFO=false" >> $GITHUB_ENV + - name: Set GORELEASER_LINUX_ONLY=true, so we only build linux binaries + run: echo "GORELEASER_LINUX_ONLY=true" >> $GITHUB_ENV # Forces goreleaser to use the correct previous tag for the changelog - name: Set GORELEASER_PREVIOUS_TAG run: echo "GORELEASER_PREVIOUS_TAG=$(git tag -l --sort=-version:refname | grep -E '^weekly-.*' | head -n 2 | tail -1)" >> $GITHUB_ENV @@ -22,65 +36,31 @@ jobs: - name: Create tags for this weekly release run: | git tag "$GORELEASER_CURRENT_TAG" - git tag "$WEEKLY_IMAGE_TAG" - - uses: actions/setup-go@v3 + git tag "$IMAGE_TAG" + - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: - go-version: "1.21.10" - cache: true + go-version: "1.25.12" + cache: false # setup docker buildx - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - # login to docker hub - - uses: docker/login-action@v2 - name: Login to Docker Hub + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + - name: Log into GAR + uses: grafana/shared-workflows/actions/login-to-gar@c7ad5f57693ac858c698d95783685a9cbfd91223 # login-to-gar/v1.0.1 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - uses: actions/setup-node@v3 + registry: us-docker.pkg.dev + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: - node-version: lts/hydrogen - cache: yarn + node-version: 20 + package-manager-cache: false - run: make frontend/build - - name: Get github app token (valid for an hour) - id: app-goreleaser - uses: tibdex/github-app-token@v1 + - uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 with: - app_id: ${{ secrets.APP_ID }} - private_key: ${{ secrets.APP_PRIVATE_KEY }} - - uses: goreleaser/goreleaser-action@v4 - with: - # either 'goreleaser' (default) or 'goreleaser-pro': - distribution: goreleaser - version: latest - args: release --clean --skip=publish --timeout 60m + # ensure this aligns with the version specified in the /Makefile + version: v2.13.2 + args: release --clean --skip=nfpm --timeout 60m env: - GITHUB_TOKEN: ${{ steps.app-releaser.outputs.token }} - # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' - # distribution: - # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} - # - - name: Push per architecture images and create multi-arch manifest - run: | - set +x - IMAGE_AMMENDS=() - - # the grep needs to remove an extra v, which is in the git tag, but not in the image tag - for image in $(docker images --format '{{.Repository}}:{{.Tag}}' | grep "grafana/pyroscope:${GORELEASER_CURRENT_TAG:1}-"); do - new_image="${image/0.0.0-/}" - docker tag "${image}" "${new_image}" - docker push "${new_image}" - IMAGE_AMMENDS+=( "--amend" "${new_image}" ) - done - - docker manifest create "grafana/pyroscope:${WEEKLY_IMAGE_TAG}" "${IMAGE_AMMENDS[@]}" - docker manifest push "grafana/pyroscope:${WEEKLY_IMAGE_TAG}" - - name: Get github app token (valid for an hour) - id: app-git-tag - uses: tibdex/github-app-token@v1 - with: - app_id: ${{ secrets.APP_ID }} - private_key: ${{ secrets.APP_PRIVATE_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Push git tag for weekly release - run: git push https://x-access-token:${{ steps.app-git-tag.output.token }}@github.com/grafana/pyroscope.git "${WEEKLY_IMAGE_TAG}" + run: git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/grafana/pyroscope.git" "${IMAGE_TAG}" 2> /dev/null diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 0000000000..222e175926 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,11 @@ +# This is also used as the default configuration for the Zizmor reusable workflow. +# We need this file because we allow PRs from forks, and PRs from forks +# can't access config files from shared-workflows repo. +# This file is copied from: https://github.com/grafana/shared-workflows/blob/main/.github/zizmor.yml + +rules: + unpinned-uses: + config: + policies: + actions/*: any # trust GitHub + grafana/*: any # trust Grafana diff --git a/.gitignore b/.gitignore index e04fd0a185..89e014ceb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # Binaries for programs and plugins -bin /phlare /pyroscope /profilecli @@ -8,6 +7,8 @@ bin *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out +# Debug binaries +__debug_bin* /cmd/phlare/data /cmd/pyroscope/data @@ -15,31 +16,32 @@ pyroscope-sync/ data/ data-shared/ data-compactor/ +data-metastore/ .DS_Store -**/dist # IDE .idea .vscode +.zed +pyroscope.sln +.cursor/* +!.cursor/rules/ -# Frontend -public/build -cypress/screenshots -.eslintcache -node_modules -/grafana/flamegraph/coverage/ -# Yarn -**/.yarn/* -!**/.yarn/patches -!**/.yarn/releases -!**/.yarn/plugins -!**/.yarn/sdks -!**/.yarn/versions -.pnp.* -yarn-error.log - -# Contains the docker image id for pyroscope -/.docker-image-id-pyroscope +# Contains the docker image digest for pyroscope +/.docker-image-digest-pyroscope +# Contains the docker image digest for frontend +/.docker-image-digest-frontend +# Contains the docker image name for pyroscope +/.docker-image-name-pyroscope /.tmp tools/k6/.env +.claude/worktrees/ + +# grafana/shared-workflows composite action dockerhub-login check itself out +# into the working tree, which trips goreleaser's dirty-state check. +/_shared-workflows-dockerhub-login/ + +# Local Go workspace files — the repo builds in plain module mode +/go.work +/go.work.sum diff --git a/.gitmodules b/.gitmodules index 64b1ce51ab..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "ebpf/testdata"] - path = ebpf/testdata - url = https://github.com/pyroscope-io/pyroscope-ebpf-testdata.git diff --git a/.golangci.yml b/.golangci.yml index 7c43a84bbf..c2cecb6755 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,92 +1,79 @@ -# This file contains all available configuration options -# with their default values. - -# options for analysis running +version: "2" run: - go: "1.21" - # default concurrency is a available CPU number concurrency: 16 - - # timeout for analysis, e.g. 30s, 5m, default is 1m - timeout: 10m - - # exit code when at least one issue was found, default is 1 + go: "1.21" + modules-download-mode: readonly issues-exit-code: 1 - - # include test files or not, default is true tests: true - - # list of build tags, all linters use it. Default is empty list. - build-tags: [] - - modules-download-mode: readonly - -# output configuration options output: - # colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number" formats: - - format: colored-line-number - - # print lines of code with issue, default is true - print-issued-lines: true - - # print linter name in the end of issue text, default is true - print-linter-name: true - -linters-settings: - goimports: - local-prefixes: github.com/grafana/pyroscope/,github.com/grafana/pyroscope/api,github.com/grafana/pyroscope/tools,github.com/grafana/pyroscope/ebpf - - depguard: - rules: - main: - deny: - - pkg: "github.com/go-kit/kit/log" - desc: "Use github.com/go-kit/log instead of github.com/go-kit/kit/log" - - revive: - rules: - # This particular check seems to have problems with generic types and their receiver naming - - name: receiver-naming - disabled: true - + text: + path: stdout + print-linter-name: true + print-issued-lines: true linters: enable: - - errcheck + - depguard - goconst - - gofmt - - goimports - - revive - - ineffassign - - staticcheck - misspell + - revive - unconvert - unparam - - govet - - typecheck - - depguard - - exportloopref - -issues: - exclude: - - Error return value of .*log\.Logger\)\.Log\x60 is not checked - - Error return value of .*.Log.* is not checked - - Error return value of `` is not checked - - # which dirs to skip: they won't be analyzed; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but next dirs are always skipped independently - # from this option's value: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - exclude-dirs: - - win_eventlog$ - - pkg/og - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - exclude-files: - - .*.pb.go - - .*.y.go - - .*.rl.go - + settings: + depguard: + rules: + main: + deny: + - pkg: github.com/go-kit/kit/log + desc: Use github.com/go-kit/log instead of github.com/go-kit/kit/log + revive: + rules: + - name: receiver-naming + disabled: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - path: (.+)\.go$ + text: Error return value of .*log\.Logger\)\.Log\x60 is not checked + - path: (.+)\.go$ + text: Error return value of .*.Log.* is not checked + - path: (.+)\.go$ + text: Error return value of `` is not checked + - path: (.+)\.go$ + text: grpc.Dial(.*) is deprecated + paths: + - .*.pb.go + - .*.y.go + - .*.rl.go + - win_eventlog$ + - pkg/og + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + settings: + goimports: + local-prefixes: + - github.com/grafana/pyroscope/ + - github.com/grafana/pyroscope/api + - github.com/grafana/pyroscope/tools + - github.com/grafana/pyroscope/ebpf + exclusions: + generated: lax + paths: + - .*.pb.go + - .*.y.go + - .*.rl.go + - win_eventlog$ + - pkg/og + - third_party$ + - builtin$ + - examples$ diff --git a/.goreleaser.yaml b/.goreleaser.yaml index b114a3d8cc..f34da84430 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -3,20 +3,31 @@ version: 2 before: hooks: # This hook ensures that goreleaser uses the correct go version for a Pyroscope release - - sh -euc "go version | grep "go version go1.21.10 " || { echo "Unexpected go version"; exit 1; }" + - sh -euc 'go version | grep "go version go1.25.12 " || { echo "Unexpected go version"; exit 1; }' +env: + # Strip debug information from the binary by default, weekly builds will have debug information + - GORELEASER_DEBUG_INFO_FLAGS={{ if and (index .Env "GORELEASER_STRIP_DEBUG_INFO") (eq .Env.GORELEASER_STRIP_DEBUG_INFO "false") }}{{ else }}-s -w{{ end }} + # Use a custom image prefix (registry) or fallback to the GAR mirror staging repo. + # The gar-image-mirror service copies images from there to docker.io/grafana/pyroscope. + - IMAGE_PREFIX={{ or (index .Env "IMAGE_PREFIX") "us-docker.pkg.dev/grafanalabs-global/dockerhub-pyroscope-prod-mirror/" }} + # Allow a custom image tag to be used (must be set by workflow) + - IMAGE_TAG={{ .Env.IMAGE_TAG }} + # Publish latest image tag + - IMAGE_PUBLISH_LATEST={{ or (index .Env "IMAGE_PUBLISH_LATEST") "false" }} + # Skip GitHub release upload + - GITHUB_RELEASE_DISABLE={{ or (index .Env "GITHUB_RELEASE_DISABLE") "false" }} + # Skip builds of non linux oses + - GORELEASER_LINUX_ONLY={{ or (index .Env "GORELEASER_LINUX_ONLY") "false" }} builds: - env: - CGO_ENABLED=0 goos: - linux - - darwin goarch: - amd64 - arm64 - - arm - goarm: - - "6" - - "7" + goamd64: + - v2 main: ./cmd/pyroscope mod_timestamp: "{{ .CommitTimestamp }}" flags: @@ -26,34 +37,83 @@ builds: - embedassets ldflags: - > - -extldflags "-static" -s -w - -X "github.com/grafana/pyroscope/pkg/util/build.Branch={{ .Branch }}" - -X "github.com/grafana/pyroscope/pkg/util/build.Version={{ .Version }}" - -X "github.com/grafana/pyroscope/pkg/util/build.Revision={{ .ShortCommit }}" - -X "github.com/grafana/pyroscope/pkg/util/build.BuildDate={{ .CommitDate }}" + -extldflags "-static" {{ .Env.GORELEASER_DEBUG_INFO_FLAGS }} + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Branch={{ .Branch }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Version={{ .Version }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Revision={{ .ShortCommit }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.BuildDate={{ .CommitDate }}" id: pyroscope + - env: + - CGO_ENABLED=0 + goos: + - darwin + goarch: + - amd64 + - arm64 + goamd64: + - v2 + main: ./cmd/pyroscope + mod_timestamp: "{{ .CommitTimestamp }}" + flags: + - -trimpath + tags: + - netgo + - embedassets + ldflags: + - > + -extldflags "-static" {{ .Env.GORELEASER_DEBUG_INFO_FLAGS }} + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Branch={{ .Branch }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Version={{ .Version }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Revision={{ .ShortCommit }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.BuildDate={{ .CommitDate }}" + id: pyroscope_non_linux + skip: '{{ if eq .Env.GORELEASER_LINUX_ONLY "true" }}true{{ else }}false{{ end }}' - env: - CGO_ENABLED=0 tags: - netgo ldflags: - > - -extldflags "-static" -s -w - -X "github.com/grafana/pyroscope/pkg/util/build.Branch={{ .Branch }}" - -X "github.com/grafana/pyroscope/pkg/util/build.Version={{ .Version }}" - -X "github.com/grafana/pyroscope/pkg/util/build.Revision={{ .ShortCommit }}" - -X "github.com/grafana/pyroscope/pkg/util/build.BuildDate={{ .CommitDate }}" + -extldflags "-static" {{ .Env.GORELEASER_DEBUG_INFO_FLAGS }} + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Branch={{ .Branch }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Version={{ .Version }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Revision={{ .ShortCommit }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.BuildDate={{ .CommitDate }}" goos: - linux + goarch: + - amd64 + - arm64 + goamd64: + - v2 + ignore: + - goos: windows + goarch: arm + main: ./cmd/profilecli + mod_timestamp: "{{ .CommitTimestamp }}" + flags: + - -trimpath + binary: profilecli + id: profilecli + - env: + - CGO_ENABLED=0 + tags: + - netgo + ldflags: + - > + -extldflags "-static" {{ .Env.GORELEASER_DEBUG_INFO_FLAGS }} + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Branch={{ .Branch }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Version={{ .Version }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.Revision={{ .ShortCommit }}" + -X "github.com/grafana/pyroscope/v2/pkg/util/build.BuildDate={{ .CommitDate }}" + goos: - windows - darwin goarch: - amd64 - arm64 - - arm - goarm: - - "6" - - "7" + goamd64: + - v2 ignore: - goos: windows goarch: arm @@ -62,11 +122,13 @@ builds: flags: - -trimpath binary: profilecli - id: profilecli + id: profilecli_non_linux + skip: '{{ if eq .Env.GORELEASER_LINUX_ONLY "true" }}true{{ else }}false{{ end }}' dockers: - use: buildx goos: linux goarch: amd64 + goamd64: v2 dockerfile: ./cmd/pyroscope/Dockerfile ids: - pyroscope @@ -74,8 +136,7 @@ dockers: extra_files: - cmd/pyroscope/pyroscope.yaml image_templates: - - "grafana/{{ .ProjectName }}:{{ .Version }}-amd64" - - "grafana/{{ .ProjectName }}:latest-amd64" + - "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:{{ .Env.IMAGE_TAG }}-amd64" build_flag_templates: - "--platform=linux/amd64" - "--label=org.opencontainers.image.created={{.Date}}" @@ -85,64 +146,31 @@ dockers: - use: buildx goos: linux goarch: arm64 - extra_files: - - cmd/pyroscope/pyroscope.yaml - dockerfile: ./cmd/pyroscope/Dockerfile - image_templates: - - "grafana/{{ .ProjectName }}:{{ .Version }}-arm64v8" - - "grafana/{{ .ProjectName }}:latest-arm64v8" - build_flag_templates: - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - use: buildx - goos: linux - goarch: arm - goarm: "6" - extra_files: - - cmd/pyroscope/pyroscope.yaml - dockerfile: ./cmd/pyroscope/Dockerfile - image_templates: - - "grafana/{{ .ProjectName }}:{{ .Version }}-armv6" - - "grafana/{{ .ProjectName }}:latest-armv6" - build_flag_templates: - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - use: buildx - goos: linux - goarch: arm - goarm: "7" dockerfile: ./cmd/pyroscope/Dockerfile + ids: + - pyroscope + - profilecli extra_files: - cmd/pyroscope/pyroscope.yaml image_templates: - - "grafana/{{ .ProjectName }}:{{ .Version }}-armv7" - - "grafana/{{ .ProjectName }}:latest-armv7" + - "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:{{ .Env.IMAGE_TAG }}-arm64v8" build_flag_templates: - - "--platform=linux/arm/v7" + - "--platform=linux/arm64/v8" - "--label=org.opencontainers.image.created={{.Date}}" - "--label=org.opencontainers.image.title={{.ProjectName}}" - "--label=org.opencontainers.image.revision={{.FullCommit}}" - "--label=org.opencontainers.image.version={{.Version}}" docker_manifests: # https://goreleaser.com/customization/docker_manifest/ - - name_template: grafana/{{ .ProjectName }}:{{ .Version }} + - name_template: "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:{{ .Env.IMAGE_TAG }}" image_templates: - - grafana/{{ .ProjectName }}:{{ .Version }}-amd64 - - grafana/{{ .ProjectName }}:{{ .Version }}-arm64v8 - - grafana/{{ .ProjectName }}:{{ .Version }}-armv6 - - grafana/{{ .ProjectName }}:{{ .Version }}-armv7 - - name_template: grafana/{{ .ProjectName }}:latest + - "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:{{ .Env.IMAGE_TAG }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:{{ .Env.IMAGE_TAG }}-arm64v8" + - name_template: "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:latest" image_templates: - - grafana/{{ .ProjectName }}:latest-amd64 - - grafana/{{ .ProjectName }}:latest-arm64v8 - - grafana/{{ .ProjectName }}:latest-armv6 - - grafana/{{ .ProjectName }}:latest-armv7 + - "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:{{ .Env.IMAGE_TAG }}-amd64" + - "{{ .Env.IMAGE_PREFIX }}{{ .ProjectName }}:{{ .Env.IMAGE_TAG }}-arm64v8" + skip_push: '{{ if eq .Env.IMAGE_PUBLISH_LATEST "true" }}false{{ else }}true{{ end }}' nfpms: - id: pyroscope formats: @@ -153,6 +181,7 @@ nfpms: vendor: Grafana Labs Inc homepage: https://grafana.com/pyroscope license: AGPL-3.0 + file_name_template: '{{ .PackageName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v2") }}{{ .Amd64 }}{{ end }}' contents: - src: ./tools/packaging/pyroscope.service dst: /etc/systemd/system/pyroscope.service @@ -164,31 +193,37 @@ nfpms: archives: - id: pyroscope - builds: + name_template: '{{.ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v2") }}{{ .Amd64 }}{{ end }}' + ids: - pyroscope + - pyroscope_non_linux - id: profilecli - name_template: 'profilecli_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}' - builds: + name_template: 'profilecli_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v2") }}{{ .Amd64 }}{{ end }}' + ids: - profilecli + - profilecli_non_linux format_overrides: - goos: windows - format: zip + formats: [zip] checksum: name_template: "checksums.txt" snapshot: - name_template: "{{ incpatch .Version }}-next" + version_template: "{{ incpatch .Version }}-next" changelog: sort: asc filters: exclude: - "^test:" release: - draft: true + # Draft releases break our Homebrew release which + # depends on asset urls created on release "publish" + draft: false + make_latest: '{{ .Env.IMAGE_PUBLISH_LATEST }}' footer: | - As always, feedbacks are more than welcome, feel free to open issues/discussions. + As always, feedback is more than welcome, feel free to open issues/discussions. You can reach out to the team using: - - [Slack](https://grafana.slack.com/archives/C047CCW6YM8) + - [Slack](https://grafana.slack.com/archives/C049PLMV8TB) - [Github Discussions](https://github.com/grafana/pyroscope/discussions) - [Github Issues](https://github.com/grafana/pyroscope/issues) - [Mailing List](https://groups.google.com/g/pyroscope-team) @@ -198,12 +233,13 @@ release: - [grafana/pyroscope](https://hub.docker.com/r/grafana/pyroscope/tags) ```bash - docker pull docker.io/grafana/pyroscope:{{ trimprefix .Tag "v" }} + docker pull grafana/{{ .ProjectName }}:{{ .Env.IMAGE_TAG }} ``` ids: - pyroscope - profilecli + disable: '{{ .Env.GITHUB_RELEASE_DISABLE }}' # milestones: # - close: true diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index d24fdfc601..0000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npx lint-staged diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000..0f850fb8de --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/pyroscope.iml b/.idea/pyroscope.iml new file mode 100644 index 0000000000..0fba13d24b --- /dev/null +++ b/.idea/pyroscope.iml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/help.xml b/.idea/runConfigurations/help.xml new file mode 100644 index 0000000000..795fb03274 --- /dev/null +++ b/.idea/runConfigurations/help.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/v1.xml b/.idea/runConfigurations/v1.xml new file mode 100644 index 0000000000..40cc671d2c --- /dev/null +++ b/.idea/runConfigurations/v1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/v2.xml b/.idea/runConfigurations/v2.xml new file mode 100644 index 0000000000..9aae6237b3 --- /dev/null +++ b/.idea/runConfigurations/v2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.mockery.yaml b/.mockery.yaml new file mode 100644 index 0000000000..02c5a77b01 --- /dev/null +++ b/.mockery.yaml @@ -0,0 +1,77 @@ +with-expecter: true +disable-version-string: True +outpkg: "mock{{.PackageName}}" +mockname: "Mock{{.InterfaceName}}" +filename: "mock_{{.InterfaceName | snakecase}}.go" +dir: "pkg/test/mocks/mock{{.PackageName}}" +packages: + github.com/grafana/pyroscope/v2/pkg/objstore: + interfaces: + Bucket: + github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1: + interfaces: + IndexServiceClient: + IndexServiceServer: + CompactionServiceClient: + CompactionServiceServer: + MetadataQueryServiceClient: + MetadataQueryServiceServer: + TenantServiceClient: + TenantServiceServer: + github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect: + interfaces: + QuerierServiceClient: + github.com/grafana/pyroscope/v2/pkg/frontend: + interfaces: + Limits: + github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend: + interfaces: + QueryBackend: + Symbolizer: + github.com/grafana/pyroscope/v2/pkg/ingester/otlp: + interfaces: + PushService: + github.com/grafana/pyroscope/v2/pkg/ingester/pyroscope: + interfaces: + PushService: + github.com/grafana/pyroscope/v2/pkg/metastore/compaction/compactor: + interfaces: + BlockQueueStore: + Tombstones: + github.com/grafana/pyroscope/v2/pkg/metastore/compaction/scheduler: + interfaces: + JobStore: + github.com/grafana/pyroscope/v2/pkg/metastore/discovery: + interfaces: + Discovery: + github.com/grafana/pyroscope/v2/pkg/metastore/index: + interfaces: + Store: + github.com/grafana/pyroscope/v2/pkg/metastore/index/dlq: + interfaces: + Metastore: + github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement: + interfaces: + Placement: + github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement: + interfaces: + Store: + github.com/grafana/pyroscope/v2/pkg/distributor/writepath: + interfaces: + SegmentWriterClient: + IngesterClient: + github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb: + interfaces: + RaftNodeServiceClient: + RaftNodeServiceServer: + github.com/grafana/pyroscope/v2/pkg/metrics: + interfaces: + Exporter: + Ruler: + github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client: + interfaces: + repositoryService: + github.com/grafana/pyroscope/v2/pkg/symbolizer: + interfaces: + DebuginfodClient: + DebugInfoStore: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..5a08a19403 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +# Pre-commit hooks that delegate to Makefile targets +# This ensures CI and local development use the same formatting/linting logic +repos: + - repo: local + hooks: + - id: fmt + name: Format code (Go, protobuf, jsonnet) + entry: make fmt + language: system + pass_filenames: false + # Run on any file change - make fmt handles file filtering internally + always_run: true + + - id: generate + name: Check generated protobuf files + entry: make generate check/unstaged-changes + language: system + pass_filenames: false + # Only run when protobuf-related files in api/ or pkg/ are staged + # This matches: api/**/*.proto, pkg/**/*.proto, api/buf*.yaml, pkg/buf*.yaml + # Root-level YAML files (renovate.json, .golangci.yml, etc.) are excluded + files: '^(api|pkg)/.*\.(proto|yaml)$' + +default_install_hook_types: [pre-push] diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index b46bf2cb16..0000000000 --- a/.prettierignore +++ /dev/null @@ -1,17 +0,0 @@ -public/build/** -pkg/api/static/** -vendor/** -tools/** -operations/** -api/** -data/** -**/dist -**/testdata -*.md -*.yaml -*.yml -*.html -og/** -cmd/** -pkg/test/** -examples/** diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 637787883f..0000000000 --- a/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -{ "singleQuote": true } diff --git a/.pyroscope.yaml b/.pyroscope.yaml new file mode 100644 index 0000000000..c26a764e22 --- /dev/null +++ b/.pyroscope.yaml @@ -0,0 +1,12 @@ +version: v1 +source_code: + mappings: + - path: + - prefix: $GOROOT/src + language: go + source: + github: + owner: golang + repo: go + ref: go1.25.12 + path: src diff --git a/.swcrc b/.swcrc deleted file mode 100644 index 823405229d..0000000000 --- a/.swcrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "jsc": { - "parser": { - "syntax": "typescript", - "decorators": true - }, - "transform": { - "legacyDecorator": true, - "decoratorMetadata": true - } - } -} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..cca210bf8f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "pyroscope", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/pyroscope", + }, + { + "name": "canary-exporter", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/profilecli", + "args": [ + "canary-exporter" + ] + } + ], + "compounds": [ + { + "name": "canary+pyroscope", + "configurations": [ + "pyroscope", + "canary-exporter" + ], + "stopAll": true + } + ] +} \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..04b2920988 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,388 @@ +# Pyroscope - AI Agent Development Guide + +This document provides context and guidance for AI coding assistants (Claude, Cursor, GitHub Copilot, etc.) working on the Pyroscope codebase. + +## What is Pyroscope? + +Pyroscope is a horizontally scalable, highly available, multi-tenant continuous profiling aggregation system. +It's designed to store and query profiling data at scale, similar to how Prometheus works for metrics and Loki for logs. + +**Key Characteristics:** +- Written in **Go** +- Microservices-based architecture inspired by Cortex/Mimir/Loki +- Stores profiling data in object storage (S3, GCS, Azure, etc.) +- Multi-tenant by design + +## Architecture Overview + +Pyroscope uses a **microservices architecture** where a single binary can run different components based on the `-target` parameter. + +### V1 Components + +**Write Path:** +- **Distributor**: Receives profile ingestion requests, validates, and forwards to ingesters +- **Ingester**: Stores profiles in memory, periodically flushes to disk as blocks, periodically uploads blocks to long-term object storage +- **Compactor**: Merges blocks and removes duplicates + +**Read Path:** +- **Query Frontend**: Entry point for queries, handles query splitting and caching +- **Query Scheduler**: Manages query queue and ensures fair execution across tenants +- **Querier**: Executes queries by fetching data from ingesters and store-gateways +- **Store Gateway**: Indexes and serves blocks from long-term object storage + +### V2 Components + +**Write Path:** +- **Distributor**: Receives profile ingestion requests, validates, and forwards to segment writers +- **Segment Writer**: Writes block segments to long-term object storage and the block metadata to metastore +- **Metastore**: Maintains an index for the block metadata and coordinates the block compaction process +- **Compaction Worker**: Merges small segments into larger blocks + +**Read Path:** +- **Query Frontend**: Entry point for queries, creates the query plan and executes it against query backends +- **Query Backend**: Executes queries and merges query responses + +### Storage + +- **Block Format**: Profiles stored in Parquet tables, series data in a TSDB index, symbols in a custom format +- **Multi-tenant**: Each tenant has isolated storage +- **Object Storage**: Primary storage backend (S3, GCS, Azure, local filesystem) + +## Repository Structure + +``` +. +├── cmd/ +│ ├── pyroscope/ # Main server binary +│ └── profilecli/ # CLI tool for profile operations +├── pkg/ # Core Go packages +│ ├── distributor/ # Distributor component +│ ├── ingester/ # Ingester component +│ ├── querier/ # Querier component +│ ├── frontend/ # Query frontend component +│ ├── compactor/ # Compactor component +│ ├── metastore/ # Metadata component +│ ├── phlaredb/ # V1 database storage engine +│ ├── model/ # Data models and types +│ ├── objstore/ # Object storage abstraction +│ ├── api/ # API definitions and handlers +│ └── og/ # Legacy code (original Pyroscope) +├── ui/ # React/TypeScript frontend (Vite) - has its own ui/CLAUDE.md +├── api/ # API definitions (protobuf, OpenAPI) +├── docs/ # Documentation +├── operations/ # Deployment configs (jsonnet, helm) +├── examples/ # Example applications and SDKs +└── tools/ # Development and build tools +``` + +## Tech Stack + +### Backend +- **Language**: Go 1.25 (see `go.mod`) +- **RPC**: gRPC with Connect protocol +- **Storage**: Parquet, TSDB +- **Hash Ring**: Consistent hashing with memberlist (gossip protocol) +- **Observability**: Prometheus metrics, Structured logs, Distributed traces, pprof profiles + +### Frontend +The frontend lives in `ui/` and is a dependency-minimal rewrite of the old `public/app` UI. +**`ui/CLAUDE.md` and `ui/DESIGN.md` are the authoritative guides — read them before touching the UI.** Summary: +- **Stack**: React 19 + Vite 8 + TypeScript 5.9, package-managed with **Yarn 4 (Berry)** — use `yarn`, not `npm` +- **No UI library**: styling via CSS custom properties / semantic tokens in `src/theme.css` (no Emotion, no Grafana UI) +- **Resist new dependencies** — prefer a small local implementation; minimizing the dependency surface is the whole point of the rewrite + +### Testing +- **Go**: Standard `testing` package, testify for assertions +- **Frontend**: Vitest (`yarn test` from `ui/`) + +## Development Workflow + +### Setup & Build + +```bash +# Prerequisites: Go 1.25, Docker, Node, Yarn 4 (Berry). +# All other build tools auto-download to .tmp/bin/ + +# Build backend +make go/bin + +# Run tests +make go/test + +# Frontend dev (run from ui/): Vite dev server on :5173, proxies API to :4040 +cd ui && yarn install && yarn dev +# Production frontend build (Docker -> ui/dist; required before `make build`): +make frontend/build + +# Docker image +make GOOS=linux GOARCH=amd64 docker-image/pyroscope/build +``` + +### Code Generation + +**IMPORTANT**: After changing protobuf, configs, or flags: +```bash +make generate +``` +Commit the generated files with your changes. + +### Running Locally + +```bash +# Run all components in monolithic mode with embedded Grafana +go run ./cmd/pyroscope --target all,embedded-grafana +# Pyroscope: http://localhost:4040 +# Grafana: http://localhost:4041 + +# Run with V2 architecture (segment writers, query backend, symbolizer) +# -symbolizer.enabled=true opts into symbolization (off by default). +go run ./cmd/pyroscope -symbolizer.enabled=true +``` + +## Code Style & Conventions + +### Go Code + +1. **Imports**: Three groups separated by blank lines: + ```go + import ( + // Standard library + "context" + "fmt" + + // Third-party packages + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/atomic" + + // Internal packages + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + ) + ``` + +2. **Formatting**: Use `golangci-lint` (run via `make lint`) + - gofmt for formatting + - goimports with `-local github.com/grafana/pyroscope` + +3. **Linting**: + - Enabled: depguard, goconst, misspell, revive, unconvert, unparam + - Use `github.com/go-kit/log` (NOT `github.com/go-kit/kit/log`) + +4. **Error Handling**: + - Always check errors explicitly + - Wrap errors with context: `fmt.Errorf("failed to query: %w", err)` + - Use structured logging: `level.Error(logger).Log("msg", "failed to process", "err", err)` + +5. **Context**: + - Always pass `context.Context` as the first parameter + - Respect context cancellation in loops and long operations + +6. **Testing**: + - File naming: `*_test.go` + - Test function naming: `TestFunctionName` or `TestComponentName_Method` + - Use table-driven tests for multiple cases + - Prefer `t.Run()` for subtests + - Use `require` for fatal assertions, `assert` for non-fatal + +### TypeScript/React Code + +The `ui/` frontend has its own authoritative guides — **follow `ui/CLAUDE.md` and `ui/DESIGN.md`**. In brief: + +1. **File Extensions**: `.tsx` for components, `.ts` for utilities +2. **Components**: Functional components with hooks; keep state management simple (the rewrite deliberately dropped Redux) +3. **Styling**: Use semantic CSS custom properties from `src/theme.css`; never reference primitive tokens directly, and don't add Emotion or Grafana UI +4. **Props**: Define explicit TypeScript interfaces for all component props +5. **Formatting**: Prettier + ESLint — `yarn format` / `yarn lint` from `ui/` + +## Common Patterns + +### Multi-tenancy + +All requests must include a tenant ID in the `X-Scope-OrgID` header: + +```go +import "github.com/grafana/pyroscope/v2/pkg/tenant" + +// Extract tenant ID from context +tenantID, err := tenant.ExtractTenantIDFromContext(ctx) +if err != nil { + return err +} +``` + +### Consistent Hashing + +Components use a hash ring for sharding: + +```go +// Get ingester for a given label set +replicationSet, err := ring.Get(key, op, bufDescs, bufHosts, bufZones) +``` + +### Object Storage + +Abstract object storage operations: + +```go +import "github.com/grafana/pyroscope/v2/pkg/objstore" + +// Use the Bucket interface +bucket := objstore.NewBucket(cfg) +reader, err := bucket.Get(ctx, "path/to/object") +``` + +### Configuration + +Use `github.com/grafana/dskit` for configuration: + +```go +type Config struct { + ListenPort int `yaml:"listen_port"` + // Use RegisterFlags pattern +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + f.IntVar(&cfg.ListenPort, "server.http-listen-port", 4040, "HTTP listen port") +} +``` + +Run `make generate` after changing config definitions, to regenerate docs. + +## Testing Best Practices + +1. **Unit Tests**: Test individual functions/methods in isolation +2. **Integration Tests**: Use build tags: `//go:build integration` +3. **Mocking**: Use `mockery` for generating mocks from interfaces +4. **Fixtures**: Store test data in `testdata/` directories +5. **Parallel Tests**: Use `t.Parallel()` when tests are independent +6. **Cleanup**: Always use `t.Cleanup()` for resource cleanup + +Example test: +```go +func TestDistributor_Push(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input *pushv1.PushRequest + wantErr bool + }{ + {name: "valid request", input: validRequest(), wantErr: false}, + {name: "invalid tenant", input: invalidRequest(), wantErr: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := setupDistributor(t) + err := d.Push(context.Background(), tt.input) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} +``` + +## Common Pitfalls & Things to Avoid + +1. **Don't** introduce dependencies on `pkg/og/` - this is legacy code being phased out +2. **Don't** use `github.com/go-kit/kit/log` - use `github.com/go-kit/log` +3. **Don't** forget to run `make generate` after changing protobuf/config definitions +4. **Don't** hardcode tenant IDs – always extract from context +5. **Don't** create unbounded goroutines – use worker pools or semaphores +6. **Don't** ignore context cancellation in loops +7. **Don't** log PII or sensitive data +8. **Don't** use `fmt.Println` for logging - use structured logging +9. **Don't** add imports within the three import groups (keep them separate) +10. **Don't** commit changes to `node_modules/` or generated code without source changes + +## Security Considerations + +1. **Input Validation**: Always validate and sanitize user input +2. **Path Traversal**: Validate object keys before storage operations +3. **Rate Limiting**: Distributor implements per-tenant rate limiting +4. **Authentication**: Multi-tenancy via `X-Scope-OrgID` header (authentication delegated to gateway) + +## Performance Considerations + +1. **Profiling**: This is a profiling system – profile your own changes! + ```bash + go test -cpuprofile=cpu.prof -memprofile=mem.prof -bench=. + go tool pprof cpu.prof + ``` + +2. **Allocations**: Minimize allocations in hot paths + - Reuse buffers with `sync.Pool` + - Avoid string concatenation in loops + - Use `strings.Builder` for string building + +3. **Concurrency**: + - Use worker pools for bounded concurrency + - Prefer channels for coordination over mutexes when possible + - Always consider the scalability implications + +## Documentation + +- **User Docs**: `docs/sources/` - Published to grafana.com +- **Contributing**: `docs/internal/contributing/README.md` +- **Component Docs**: In `docs/sources/reference-pyroscope-architecture/components/` + +## Useful Make Targets + +```bash +make help # Show all available targets +make lint # Run linters +make go/test # Run Go unit tests +make go/bin # Build binaries +make go/mod # Tidy go modules +make generate # Generate code (protobuf, mocks, etc.) +make docker-image/pyroscope/build # Build Docker image +``` + +## Key Dependencies + +- **dskit**: Grafana's distributed systems toolkit (ring, services, middleware) +- **connect**: RPC framework (gRPC-compatible) +- **parquet-go**: Parquet file format implementation +- **go-kit/log**: Structured logging +- **prometheus/client_golang**: Metrics instrumentation +- **opentelemetry**: Distributed tracing + +## When Working on Features + +1. **Read Component Docs**: Check `docs/sources/reference-pyroscope-architecture/components/` for the component you're modifying +2. **Understand the Ring**: If working on write/read path, understand consistent hashing +3. **Multi-tenancy First**: Always consider multi-tenant implications +4. **Check for Similar Code**: Pyroscope is inspired by Cortex/Mimir - similar patterns apply +5. **Test Multi-tenancy**: Test with multiple tenants to catch isolation issues +6. **Profile Your Changes**: Use `go test -bench` and verify performance impact +7. **Update Documentation**: If changing user-facing behavior, update docs + +## Getting Help + +- **Contributing Guide**: `docs/internal/contributing/README.md` +- **Code Comments**: The codebase has extensive comments – read them +- **Git History**: Use `git blame` and `git log` to understand design decisions + +## Commit Guidelines + +- **Atomic Commits**: Each commit should be a logical unit +- **Commit Messages**: Focus on "why" not just "what" +- **Generated Code**: Include generated files in the same commit as source changes +- **Format**: Follow existing commit message style (see `git log --oneline -20`) + +## Additional Notes for AI Agents + +- **Favor Simplicity**: Pyroscope values simple, maintainable code over clever abstractions +- **Performance Matters**: This system handles high-throughput profiling data +- **Multi-tenancy is Critical**: Tenant isolation bugs are severe – test thoroughly +- **Consistency with Grafana Labs Style**: Follow patterns from dskit, Mimir, Loki +- **Ask Before Large Refactors**: Propose significant architectural changes before implementing + +--- + +For detailed setup and contributing instructions, see: +- `docs/internal/contributing/README.md` - Development setup and workflow +- `docs/sources/reference-pyroscope-architecture/` - System architecture deep dive diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index aaab6688ea..bc4baa1276 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -11,4 +11,53 @@ /docs/variables.mk @jdbaldry # eBPF collector -/ebpf/ @korniltsev +/ebpf/ @korniltsev-grafanista + +# LIDIA debug symbols format +/lidia/ @korniltsev-grafanista @marcsanmi + +# area/read-path +/pkg/querybackend/ @marcsanmi @aleks-p +/pkg/symbolizer/ @marcsanmi @korniltsev-grafanista +/pkg/storegateway/ @aleks-p +/pkg/scheduler/ @korniltsev-grafanista @bryanhuhta +/pkg/phlaredb/symdb/ @simonswine @korniltsev-grafanista +/pkg/phlaredb/tsdb/ @simonswine @korniltsev-grafanista +/pkg/querier/ @marcsanmi +/pkg/frontend/ @marcsanmi @bryanhuhta +/pkg/block/ @simonswine @marcsanmi @alsoba13 +/pkg/phlaredb/block @simonswine + +# area/write-path +/pkg/distributor/ @aleks-p @alsoba13 +/pkg/segmentwriter/ @alsoba13 @korniltsev-grafanista +/pkg/og/convert/ @korniltsev-grafanista @bryanhuhta +/pkg/pprof/ @korniltsev-grafanista @bryanhuhta +/pkg/model/relabel/ @korniltsev-grafanista @bryanhuhta +/pkg/model/ @korniltsev-grafanista @bryanhuhta +/pkg/model/pprofsplit/ @korniltsev-grafanista @bryanhuhta +/pkg/validation/ @marcsanmi @aleks-p +/pkg/ingester/otlp @marcsanmi @korniltsev-grafanista +/pkg/ingester/ @alsoba13 @korniltsev-grafanista +/pkg/phlaredb/shipper/ @korniltsev-grafanista @bryanhuhta + +# area/compactor +/pkg/compactor/ @alsoba13 +/pkg/compactionworker/ @alsoba13 +/pkg/phlaredb/bucketindex/ @aleks-p +/pkg/phlaredb/downsample/ @aleks-p + +# area/metastore +/pkg/metastore/ @aleks-p + +# parquet +/pkg/objstore/parquet/ @simonswine +/pkg/phlaredb/query/ @simonswine +/pkg/phlaredb/schemas/v1/ @simonswine @aleks-p +/pkg/parquet/ @simonswine + +# api +/api/ @simonswine @marcsanmi @aleks-p + +# objstore +/pkg/objstore/ @simonswine diff --git a/LICENSING.md b/LICENSING.md index 5cc5287860..47fbfb0c37 100644 --- a/LICENSING.md +++ b/LICENSING.md @@ -8,6 +8,7 @@ The default license for this project is [AGPL-3.0-only](LICENSE). The following directories and their subdirectories are licensed under Apache-2.0: ``` +lidia og/pkg/agent/profiler og/pkg/agent/ebpfspy og/packages/pyroscope-flamegraph diff --git a/Makefile b/Makefile index 4d12d055ba..d28363ac2c 100644 --- a/Makefile +++ b/Makefile @@ -9,17 +9,17 @@ MAKEFLAGS += --no-print-directory BIN := $(CURDIR)/.tmp/bin COPYRIGHT_YEARS := 2021-2022 LICENSE_IGNORE := -e /testdata/ -GO_TEST_FLAGS ?= -v -race -cover +GO_TEST_FLAGS ?= -race -cover GOOS ?= $(shell go env GOOS) GOARCH ?= $(shell go env GOARCH) -IMAGE_PLATFORM = linux/amd64 +IMAGE_PLATFORM = linux/$(GOARCH) BUILDX_ARGS = GOPRIVATE=github.com/grafana/frostdb # Boiler plate for building Docker containers. # All this must go at top of file I'm afraid. -IMAGE_PREFIX ?= us.gcr.io/kubernetes-dev/ +IMAGE_PREFIX ?= us-docker.pkg.dev/grafanalabs-global/dockerhub-pyroscope-prod-mirror/ IMAGE_TAG ?= $(shell ./tools/image-tag) GIT_REVISION := $(shell git rev-parse --short HEAD) @@ -27,16 +27,35 @@ GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) GIT_LAST_COMMIT_DATE := $(shell git log -1 --date=iso-strict --format=%cd) EMBEDASSETS ?= embedassets +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + NPROC := $(shell sysctl -n hw.physicalcpu) +else + NPROC := $(shell nproc) +endif + # Build flags -VPREFIX := github.com/grafana/pyroscope/pkg/util/build +VPREFIX := github.com/grafana/pyroscope/v2/pkg/util/build GO_LDFLAGS := -X $(VPREFIX).Branch=$(GIT_BRANCH) -X $(VPREFIX).Version=$(IMAGE_TAG) -X $(VPREFIX).Revision=$(GIT_REVISION) -X $(VPREFIX).BuildDate=$(GIT_LAST_COMMIT_DATE) +GO_GCFLAGS_DEBUG := all="-N -l" # Folders with go.mod file -GO_MOD_PATHS := api/ ebpf/ examples/language-sdk-instrumentation/golang-push/rideshare examples/language-sdk-instrumentation/golang-push/simple/ +GO_MOD_PATHS := api/ lidia/ examples/language-sdk-instrumentation/golang-push/rideshare examples/language-sdk-instrumentation/golang-push/rideshare-alloy examples/language-sdk-instrumentation/golang-push/rideshare-k6 examples/language-sdk-instrumentation/golang-push/simple/ examples/tracing/golang-push/ examples/golang-pgo/ # Add extra arguments to helm commands HELM_ARGS = +HELM_FLAGS_V1 := --set architecture.storage.v1=true --set architecture.storage.v2=false +HELM_FLAGS_V1_MICROSERVICES := --set architecture.microservices.enabled=true --set minio.enabled=true $(HELM_FLAGS_V1) +HELM_FLAGS_V1_DEPLOY := $(HELM_FLAGS_V1) --set pyroscope.extraArgs."pyroscopedb\.max-block-duration"=5m +HELM_FLAGS_V1_MICROSERVICES_DEPLOY := $(HELM_FLAGS_V1_MICROSERVICES) --set pyroscope.extraArgs."pyroscopedb\.max-block-duration"=5m +HELM_FLAGS_V2 := +HELM_FLAGS_V2_MICROSERVICES := --set architecture.microservices.enabled=true --set minio.enabled=true + + +# Local deployment params +KIND_CLUSTER = pyroscope-dev + .PHONY: help help: ## Describe useful make targets @grep -E '^[a-zA-Z_/-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ": .*?## "}; {printf "%-50s %s\n", $$1, $$2}' @@ -51,24 +70,50 @@ lint: go/lint helm/lint buf/lint goreleaser/lint ## Lint Go, Helm and protobuf test: go/test ## Run unit tests .PHONY: generate -generate: $(BIN)/buf $(BIN)/protoc-gen-go $(BIN)/protoc-gen-go-vtproto $(BIN)/protoc-gen-openapiv2 $(BIN)/protoc-gen-grpc-gateway $(BIN)/protoc-gen-connect-go $(BIN)/protoc-gen-connect-go-mux $(BIN)/gomodifytags ## Regenerate protobuf +generate: $(BIN)/buf $(BIN)/protoc-gen-go $(BIN)/protoc-gen-go-vtproto $(BIN)/protoc-gen-openapiv2 $(BIN)/protoc-gen-grpc-gateway $(BIN)/protoc-gen-connect-go $(BIN)/protoc-gen-connect-go-mux $(BIN)/gomodifytags $(BIN)/protoc-gen-connect-openapi ## Regenerate protobuf rm -Rf api/openapiv2/gen/ api/gen find pkg/ \( -name \*.pb.go -o -name \*.connect\*.go \) -delete cd api/ && PATH=$(BIN) $(BIN)/buf generate cd pkg && PATH=$(BIN) $(BIN)/buf generate PATH="$(BIN):$(PATH)" ./tools/add-parquet-tags.sh go run ./tools/doc-generator/ ./docs/sources/configure-server/reference-configuration-parameters/index.template > docs/sources/configure-server/reference-configuration-parameters/index.md + go run ./tools/doc-generator/ -format yaml-example -skip-blocks ingester,querier,query_scheduler,compactor,store_gateway > cmd/pyroscope/pyroscope.yaml + go run ./tools/api-docs-generator/ .PHONY: buf/lint buf/lint: $(BIN)/buf cd api/ && $(BIN)/buf lint || true # TODO: Fix linting problems and remove the always true cd pkg && $(BIN)/buf lint || true # TODO: Fix linting problems and remove the always true -EBPF_TESTS='^TestEBPF.*' - +# api and lidia are separate modules: `./...` does not cross module +# boundaries, so each needs its own invocation. .PHONY: go/test go/test: $(BIN)/gotestsum - $(BIN)/gotestsum -- $(GO_TEST_FLAGS) -skip $(EBPF_TESTS) ./... ./ebpf/... + $(BIN)/gotestsum --rerun-fails=2 --packages "$$(go list ./... | grep -v /test/integration)" -- $(GO_TEST_FLAGS) + cd api && $(BIN)/gotestsum --rerun-fails=2 --packages ./... -- $(GO_TEST_FLAGS) + cd lidia && $(BIN)/gotestsum --rerun-fails=2 --packages ./... -- $(GO_TEST_FLAGS) + +.PHONY: go/test-integration +go/test-integration: $(BIN)/gotestsum + $(BIN)/gotestsum --rerun-fails=2 --packages './pkg/test/integration/...' -- $(GO_TEST_FLAGS) + +# Run tests on examples. These build and run each example via docker-compose, +# verify the containers stay up, and query the ingested profiling data back +# (profiles for every example; the trace-to-profile link for tracing examples). +# +# Scope to specific examples with PYROSCOPE_TEST_EXAMPLES (comma-separated, +# repository-relative dirs), and/or to specific tests with RUN. For example: +# $ make examples/test PYROSCOPE_TEST_EXAMPLES=examples/tracing/java +# $ make examples/test RUN=TestExamples/examples/language-sdk-instrumentation/rust/basic +# +# The default verbose format surfaces what each check verified (discovered +# services, profile types, point/sample counts). Override with +# GOTESTSUM_FORMAT=testname for terse one-line-per-test output. +GOTESTSUM_FORMAT ?= standard-verbose +.PHONY: examples/test +examples/test: RUN := .* +examples/test: $(BIN)/gotestsum + $(BIN)/gotestsum --format $(GOTESTSUM_FORMAT) --packages ./examples -- --count 1 --parallel 2 --timeout 1h --tags examples -run "$(RUN)" .PHONY: build build: frontend/build go/bin ## Do a production build (requiring the frontend build to be present) @@ -78,58 +123,92 @@ build-dev: ## Do a dev build (without requiring the frontend) $(MAKE) EMBEDASSETS="" go/bin .PHONY: frontend/build -frontend/build: frontend/deps ## Do a production build for the frontend - yarn build +frontend/build: + docker build -f cmd/pyroscope/frontend.Dockerfile --output=ui/dist . -.PHONY: frontend/deps -frontend/deps: - yarn --frozen-lockfile +.PHONY: frontend/shell +frontend/shell: + docker build -f cmd/pyroscope/frontend.Dockerfile --iidfile .docker-image-digest-frontend --target builder . + docker run -t -i $$(cat .docker-image-digest-frontend) /bin/bash + +.PHONY: profilecli/build +profilecli/build: go/bin-profilecli ## Build the profilecli binary + +.PHONY: pyroscope/build +pyroscope/build: go/bin-pyroscope ## Build just the pyroscope binary .PHONY: release release/prereq: $(BIN)/goreleaser ## Ensure release pre requesites are met # remove local git tags coming from helm chart release - git tag -d $(shell git tag -l "phlare-*" "api/*" "ebpf/*" "@pyroscope*") + git tag -d $(shell git tag -l "phlare-*" "api/*" "@pyroscope*") # ensure there is a docker cli command @which docker || { apt-get update && apt-get install -y docker.io; } @docker info > /dev/null .PHONY: release release: release/prereq ## Create a release - $(BIN)/goreleaser release -p=$(shell nproc) --rm-dist + $(BIN)/goreleaser release -p=$(NPROC) --clean .PHONY: release/prepare release/prepare: release/prereq ## Prepare a release - $(BIN)/goreleaser release -p=$(shell nproc) --rm-dist --snapshot + $(BIN)/goreleaser release -p=$(NPROC) --clean --snapshot .PHONY: release/build/all release/build/all: release/prereq ## Build all release binaries - $(BIN)/goreleaser build -p=$(shell nproc) --rm-dist --snapshot + $(BIN)/goreleaser build -p=$(NPROC) --clean --snapshot .PHONY: release/build release/build: release/prereq ## Build current platform release binaries - $(BIN)/goreleaser build -p=$(shell nproc) --rm-dist --snapshot --single-target + $(BIN)/goreleaser build -p=$(NPROC) --clean --snapshot --single-target .PHONY: go/deps go/deps: $(GO) mod tidy -define go_build - GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 $(GO) build -tags "netgo $(EMBEDASSETS)" -ldflags "-extldflags \"-static\" $(1)" ./cmd/pyroscope - GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 $(GO) build -ldflags "-extldflags \"-static\" $(1)" ./cmd/profilecli +define go_build_pyroscope + GOOS=$(GOOS) GOARCH=$(GOARCH) GOAMD64=v2 CGO_ENABLED=0 $(GO) build -tags "netgo $(EMBEDASSETS)" -ldflags "-extldflags \"-static\" $(1)" -gcflags=$(2) ./cmd/pyroscope +endef + +define go_build_profilecli + GOOS=$(GOOS) GOARCH=$(GOARCH) GOAMD64=v2 CGO_ENABLED=0 $(GO) build -ldflags "-extldflags \"-static\" $(1)" -gcflags=$(2) ./cmd/profilecli endef .PHONY: go/bin-debug go/bin-debug: - $(call go_build,$(GO_LDFLAGS)) + $(call go_build_pyroscope,$(GO_LDFLAGS),$(GO_GCFLAGS_DEBUG)) + $(call go_build_profilecli,$(GO_LDFLAGS),$(GO_GCFLAGS_DEBUG)) .PHONY: go/bin go/bin: - $(call go_build,-s -w $(GO_LDFLAGS)) + $(call go_build_pyroscope,-s -w $(GO_LDFLAGS),) + $(call go_build_profilecli,-s -w $(GO_LDFLAGS),) + +.PHONY: go/bin-pyroscope-debug +go/bin-pyroscope-debug: + $(call go_build_pyroscope,$(GO_LDFLAGS),$(GO_GCFLAGS_DEBUG)) + +.PHONY: go/bin-profilecli-debug +go/bin-profilecli-debug: + $(call go_build_profilecli,$(GO_LDFLAGS),$(GO_GCFLAGS_DEBUG)) + +.PHONY: go/bin-pyroscope +go/bin-pyroscope: + $(call go_build_pyroscope,-s -w $(GO_LDFLAGS),) + +.PHONY: go/bin-profilecli +go/bin-profilecli: + $(call go_build_profilecli,-s -w $(GO_LDFLAGS),) .PHONY: go/lint go/lint: $(BIN)/golangci-lint - $(BIN)/golangci-lint run + $(BIN)/golangci-lint run ./... $(GO) vet ./... + cd api && $(BIN)/golangci-lint run ./... && $(GO) vet ./... + cd lidia && $(BIN)/golangci-lint run ./... && $(GO) vet ./... + +.PHONY: update-contributors +update-contributors: ## Update the contributors in README.md + go run ./tools/update-contributors .PHONY: go/mod go/mod: $(foreach P,$(GO_MOD_PATHS),go/mod_tidy/$P) @@ -137,9 +216,7 @@ go/mod: $(foreach P,$(GO_MOD_PATHS),go/mod_tidy/$P) .PHONY: go/mod_tidy_root go/mod_tidy_root: GO111MODULE=on go mod download - # doesn't work for go workspace - # GO111MODULE=on go mod verify - go work sync + GO111MODULE=on go mod verify GO111MODULE=on go mod tidy .PHONY: go/mod_tidy/% @@ -153,7 +230,7 @@ fmt: $(BIN)/golangci-lint $(BIN)/buf $(BIN)/tk ## Automatically fix some lint er $(BIN)/golangci-lint run --fix cd api/ && $(BIN)/buf format -w . cd pkg && $(BIN)/buf format -w . - $(BIN)/tk fmt ./operations/pyroscope/jsonnet/ tools/monitoring/ + $(BIN)/tk fmt ./operations/pyroscope/jsonnet/ .PHONY: check/unstaged-changes check/unstaged-changes: @@ -165,7 +242,7 @@ check/go/mod: go/mod define docker_buildx - docker buildx build $(1) --platform $(IMAGE_PLATFORM) $(BUILDX_ARGS) --build-arg=revision=$(GIT_REVISION) -t $(IMAGE_PREFIX)$(shell basename $(@D)) -t $(IMAGE_PREFIX)$(shell basename $(@D)):$(IMAGE_TAG) -f cmd/$(shell basename $(@D))/$(2)Dockerfile . + docker buildx build $(1) --platform $(IMAGE_PLATFORM) $(BUILDX_ARGS) --build-arg=revision=$(GIT_REVISION) -t $(IMAGE_PREFIX)$(shell basename $(@D)):$(2)$(IMAGE_TAG) -f cmd/$(shell basename $(@D))/$(2)Dockerfile . endef define deploy @@ -173,75 +250,84 @@ define deploy # Load image into nodes $(BIN)/kind load docker-image --name $(KIND_CLUSTER) $(IMAGE_PREFIX)pyroscope:$(IMAGE_TAG) kubectl get pods - $(BIN)/helm upgrade --install $(1) ./operations/pyroscope/helm/pyroscope $(2) $(HELM_ARGS) \ + $(BIN)/helm upgrade --install pyroscope ./operations/pyroscope/helm/pyroscope $(2) $(HELM_ARGS) \ + --set architecture.deployUnifiedServices=true \ + --set architecture.overwriteResources.requests.cpu=10m \ --set pyroscope.image.tag=$(IMAGE_TAG) \ --set pyroscope.image.repository=$(IMAGE_PREFIX)pyroscope \ - --set pyroscope.podAnnotations.image-id=$(shell cat .docker-image-id-pyroscope) \ + --set pyroscope.podAnnotations.image-digest=$(shell cat .docker-image-digest-pyroscope) \ --set pyroscope.service.port_name=http-metrics \ - --set pyroscope.podAnnotations."profiles\.grafana\.com\/memory\.port_name"=http-metrics \ - --set pyroscope.podAnnotations."profiles\.grafana\.com\/cpu\.port_name"=http-metrics \ - --set pyroscope.podAnnotations."profiles\.grafana\.com\/goroutine\.port_name"=http-metrics \ - --set pyroscope.extraEnvVars.JAEGER_AGENT_HOST=jaeger.monitoring.svc.cluster.local. \ - --set pyroscope.extraArgs."pyroscopedb\.max-block-duration"=5m - endef + --set-string pyroscope.podAnnotations."profiles\.grafana\.com/memory\.port_name"=http-metrics \ + --set-string pyroscope.podAnnotations."profiles\.grafana\.com/cpu\.port_name"=http-metrics \ + --set-string pyroscope.podAnnotations."profiles\.grafana\.com/goroutine\.port_name"=http-metrics \ + --set-string pyroscope.podAnnotations."k8s\.grafana\.com/scrape"=true \ + --set-string pyroscope.podAnnotations."k8s\.grafana\.com/metrics\.portName"=http-metrics \ + --set-string pyroscope.podAnnotations."k8s\.grafana\.com/metrics\.scrapeInterval"=15s \ + --set-string pyroscope.extraEnvVars.JAEGER_AGENT_HOST=pyroscope-monitoring-alloy-receiver \ + --set pyroscope.extraEnvVars.JAEGER_SAMPLER_TYPE=const \ + --set pyroscope.extraEnvVars.JAEGER_SAMPLER_PARAM=1 +endef + +# Function to handle multiarch image build. Depending on the +# debug_build and push_image args, we run one of: +# - docker-image/pyroscope/build +# - docker-image/pyroscope/build-debug +# - docker-image/pyroscope/push +# - docker-image/pyroscope/push-debug +define multiarch_build + $(eval push_image=$(1)) + $(eval debug_build=$(2)) + $(eval build_cmd=docker-image/pyroscope/$(if $(push_image),push,build)$(if $(debug_build),-debug)) + $(eval image_name=$(IMAGE_PREFIX)$(shell basename $(@D)):$(if $(debug_build),debug.)$(IMAGE_TAG)) + + GOOS=linux GOARCH=arm64 IMAGE_TAG="$(IMAGE_TAG)-arm64" $(MAKE) $(build_cmd) IMAGE_PLATFORM=linux/arm64 + GOOS=linux GOARCH=amd64 IMAGE_TAG="$(IMAGE_TAG)-amd64" $(MAKE) $(build_cmd) IMAGE_PLATFORM=linux/amd64 + + $(if $(push_image), docker buildx imagetools create --tag "$(image_name)" "$(image_name)-amd64" "$(image_name)-arm64") + $(if $(push_image), docker buildx imagetools inspect "$(image_name)" --format "{{json .Manifest.Digest}}" | tr -d '"' > .docker-image-digest-pyroscope) + $(if $(push_image), echo "$(image_name)" > .docker-image-name-pyroscope) +endef + +.PHONY: docker-image/pyroscope/build-multiarch +docker-image/pyroscope/build-multiarch: + $(call multiarch_build,,) + +.PHONY: docker-image/pyroscope/build-multiarch-debug +docker-image/pyroscope/build-multiarch-debug: + $(call multiarch_build,,debug) + +.PHONY: docker-image/pyroscope/push-multiarch +docker-image/pyroscope/push-multiarch: + $(call multiarch_build,push,) + +.PHONY: docker-image/pyroscope/push-multiarch-debug +docker-image/pyroscope/push-multiarch-debug: + $(call multiarch_build,push,debug) .PHONY: docker-image/pyroscope/build-debug -docker-image/pyroscope/build-debug: GOOS=linux -docker-image/pyroscope/build-debug: GOARCH=amd64 -docker-image/pyroscope/build-debug: frontend/build go/bin-debug $(BIN)/linux_amd64/dlv +docker-image/pyroscope/build-debug: frontend/build go/bin-debug docker-image/pyroscope/dlv $(call docker_buildx,--load,debug.) +.PHONY: docker-image/pyroscope/push-debug +docker-image/pyroscope/push-debug: frontend/build go/bin-debug docker-image/pyroscope/dlv + $(call docker_buildx,--push,debug.) + .PHONY: docker-image/pyroscope/build -docker-image/pyroscope/build: GOOS=linux -docker-image/pyroscope/build: GOARCH=amd64 -docker-image/pyroscope/build: frontend/build go/bin - $(call docker_buildx,--load --iidfile .docker-image-id-pyroscope,) +docker-image/pyroscope/build: frontend/build + GOOS=linux $(MAKE) go/bin + $(call docker_buildx,--load --iidfile .docker-image-digest-pyroscope,) .PHONY: docker-image/pyroscope/push -docker-image/pyroscope/push: GOOS=linux -docker-image/pyroscope/push: GOARCH=amd64 docker-image/pyroscope/push: frontend/build go/bin $(call docker_buildx,--push,) -define UPDATER_CONFIG_JSON -{ - "git_author_name": "grafana-pyroscope-bot[bot]", - "git_author_email": "140177480+grafana-pyroscope-bot[bot]@users.noreply.github.com", - "git_committer_name": "grafana-pyroscope-bot[bot]", - "git_committer_email": "140177480+grafana-pyroscope-bot[bot]@users.noreply.github.com", - "pull_request_enabled": true, - "pull_request_branch_prefix": "auto-merge/grafana-pyroscope-bot", - "repo_name": "deployment_tools", - "destination_branch": "master", - "update_jsonnet_attribute_configs": [ - { - "file_path": "ksonnet/lib/pyroscope/releases/dev/images.libsonnet", - "jsonnet_key": "pyroscope", - "jsonnet_value": "$(IMAGE_PREFIX)pyroscope:$(IMAGE_TAG)" - } - ], - "update_jsonnet_lib_configs": [ - { - "jsonnet_dir": "ksonnet/lib/pyroscope/releases/dev", - "dependencies": [ - { - "owner": "grafana", - "name": "pyroscope", - "version": "$(GIT_REVISION)", - "sub_dirs": [ - "operations/pyroscope" - ] - } - ] - } - ] -} -endef - -.PHONY: docker-image/pyroscope/deploy-dev-001 -docker-image/pyroscope/deploy-dev-001: export CONFIG_JSON:=$(call UPDATER_CONFIG_JSON) -docker-image/pyroscope/deploy-dev-001: $(BIN)/updater $(BIN)/jb - PATH=$(BIN):$(PATH) $(BIN)/updater +.PHONY: docker-image/pyroscope/dlv +docker-image/pyroscope/dlv: + # dlv is not intended for local use and is to be installed in the + # platform-specific docker image together with the main Pyroscope binary. + @mkdir -p $(@D) + GOPATH=$(CURDIR)/.tmp GOAMD64=v2 CGO_ENABLED=0 $(GO) install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@v1.25.2 + mv $(CURDIR)/.tmp/bin/$(GOOS)_$(GOARCH)/dlv $(CURDIR)/.tmp/bin/dlv .PHONY: clean clean: ## Delete intermediate build artifacts @@ -250,7 +336,7 @@ clean: ## Delete intermediate build artifacts .PHONY: reference-help reference-help: ## Generates the reference help documentation. -reference-help: go/bin +reference-help: frontend/build go/bin @(./pyroscope -h || true) > cmd/pyroscope/help.txt.tmpl @(./pyroscope -help-all || true) > cmd/pyroscope/help-all.txt.tmpl @@ -260,15 +346,15 @@ $(BIN)/buf: Makefile $(BIN)/golangci-lint: Makefile @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.58.2 + GOBIN=$(abspath $(@D)) $(GO) install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.2.2 $(BIN)/protoc-gen-go: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1 + GOBIN=$(abspath $(@D)) $(GO) install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11 $(BIN)/protoc-gen-connect-go: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install connectrpc.com/connect/cmd/protoc-gen-connect-go@v1.16.2 + GOBIN=$(abspath $(@D)) $(GO) install connectrpc.com/connect/cmd/protoc-gen-connect-go@v1.19.1 $(BIN)/protoc-gen-connect-go-mux: Makefile go.mod @mkdir -p $(@D) @@ -280,11 +366,15 @@ $(BIN)/protoc-gen-go-vtproto: Makefile go.mod $(BIN)/protoc-gen-openapiv2: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.16.0 + GOBIN=$(abspath $(@D)) $(GO) install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.27.5 $(BIN)/protoc-gen-grpc-gateway: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.16.0 + GOBIN=$(abspath $(@D)) $(GO) install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.27.5 + +$(BIN)/protoc-gen-connect-openapi: Makefile go.mod + @mkdir -p $(@D) + GOBIN=$(abspath $(@D)) $(GO) install github.com/sudorandom/protoc-gen-connect-openapi@v0.21.2 $(BIN)/gomodifytags: Makefile go.mod @mkdir -p $(@D) @@ -292,7 +382,7 @@ $(BIN)/gomodifytags: Makefile go.mod $(BIN)/kind: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install sigs.k8s.io/kind@v0.17.0 + GOBIN=$(abspath $(@D)) $(GO) install sigs.k8s.io/kind@v0.25.0 $(BIN)/tk: Makefile go.mod $(BIN)/jb @mkdir -p $(@D) @@ -304,7 +394,7 @@ $(BIN)/jb: Makefile go.mod $(BIN)/helm: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install helm.sh/helm/v3/cmd/helm@v3.14.3 + CGO_ENABLED=0 GOBIN=$(abspath $(@D)) $(GO) install helm.sh/helm/v3/cmd/helm@v3.19.2 $(BIN)/kubeconform: Makefile go.mod @mkdir -p $(@D) @@ -314,77 +404,67 @@ $(BIN)/mage: Makefile go.mod @mkdir -p $(@D) GOBIN=$(abspath $(@D)) $(GO) install github.com/magefile/mage@v1.13.0 -$(BIN)/updater: Makefile +$(BIN)/mockery: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) GOPRIVATE=github.com/grafana/deployment_tools $(GO) install github.com/grafana/deployment_tools/drone/plugins/cmd/updater@d64d509 + GOBIN=$(abspath $(@D)) $(GO) install github.com/vektra/mockery/v2@v2.53.4 +# Note: When updating the goreleaser version also update .github/workflow/release.yml and .git/workflow/weekly-release.yaml $(BIN)/goreleaser: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install github.com/goreleaser/goreleaser/v2@v2.0.0 + GOTOOLCHAIN=go1.25.5 GOBIN=$(abspath $(@D)) $(GO) install github.com/goreleaser/goreleaser/v2@v2.13.2 $(BIN)/gotestsum: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) $(GO) install gotest.tools/gotestsum@v1.9.0 - -DLV_VERSION=v1.21.0 + GOBIN=$(abspath $(@D)) $(GO) install gotest.tools/gotestsum@v1.12.3 -$(BIN)/dlv: Makefile go.mod +$(BIN)/helm-docs: Makefile go.mod @mkdir -p $(@D) - GOBIN=$(abspath $(@D)) CGO_ENABLED=0 $(GO) install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@$(DLV_VERSION) - -$(BIN)/linux_amd64/dlv: Makefile go.mod - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GOPATH=$(CURDIR)/.tmp $(GO) install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@$(DLV_VERSION); - # Create a hardlink if you are on linux_amd64, so we are able to use the same dockerfile - if [[ "$(shell $(GO) env GOOS)" == "linux" && "$(shell $(GO) env GOARCH)" == "amd64" ]]; then \ - mkdir -p "$(@D)"; \ - ln -f $(BIN)/dlv "$@"; \ - fi - -$(BIN)/trunk: Makefile - @mkdir -p $(@D) - curl -L https://trunk.io/releases/trunk -o $(@D)/trunk - chmod +x $(@D)/trunk + GOBIN=$(abspath $(@D)) $(GO) install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2 .PHONY: cve/check cve/check: - docker run -t -i --rm --volume "$(CURDIR)/:/repo" -u "$(shell id -u)" aquasec/trivy:0.45.1 filesystem --cache-dir /repo/.cache/trivy --scanners vuln --skip-dirs .tmp/ --skip-dirs node_modules/ --skip-dirs tools/monitoring/vendor/ /repo - -KIND_CLUSTER = pyroscope-dev + docker run -t -i --rm --volume "$(CURDIR)/:/repo" -u "$(shell id -u)" aquasec/trivy:0.45.1 filesystem --cache-dir /repo/.cache/trivy --scanners vuln --skip-dirs .tmp/ --skip-dirs node_modules/ /repo .PHONY: helm/lint helm/lint: $(BIN)/helm - $(BIN)/helm lint ./operations/pyroscope/helm/pyroscope/ + $(BIN)/helm lint ./operations/pyroscope/helm/pyroscope + $(BIN)/helm lint ./operations/monitoring/helm/pyroscope-monitoring -helm/docs: $(BIN)/helm - docker run --rm --volume "$(CURDIR)/operations/pyroscope/helm:/helm-docs" -u "$(shell id -u)" jnorwood/helm-docs:v1.13.1 +.PHONY: helm/docs +helm/docs: $(BIN)/helm-docs + $(BIN)/helm-docs -c operations/pyroscope/helm/pyroscope + $(BIN)/helm-docs -c operations/monitoring/helm/pyroscope-monitoring .PHONY: goreleaser/lint goreleaser/lint: $(BIN)/goreleaser $(BIN)/goreleaser check -.PHONY: trunk/lint -trunk/lint: $(BIN)/trunk - $(BIN)/trunk check - -.PHONY: trunk/fmt -trunk/fmt: $(BIN)/trunk - $(BIN)/trunk fmt - .PHONY: helm/check helm/check: $(BIN)/kubeconform $(BIN)/helm $(BIN)/helm repo add --force-update minio https://charts.min.io/ $(BIN)/helm repo add --force-update grafana https://grafana.github.io/helm-charts $(BIN)/helm dependency update ./operations/pyroscope/helm/pyroscope/ $(BIN)/helm dependency build ./operations/pyroscope/helm/pyroscope/ + $(BIN)/helm dependency update ./operations/monitoring/helm/pyroscope-monitoring/ + $(BIN)/helm dependency build ./operations/monitoring/helm/pyroscope-monitoring/ mkdir -p ./operations/pyroscope/helm/pyroscope/rendered/ - $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ \ + $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ $(HELM_FLAGS_V1) \ | tee ./operations/pyroscope/helm/pyroscope/rendered/single-binary.yaml \ | $(BIN)/kubeconform --summary --strict --kubernetes-version 1.23.0 - $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ --values operations/pyroscope/helm/pyroscope/values-micro-services.yaml \ + $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ $(HELM_FLAGS_V2) \ + | tee ./operations/pyroscope/helm/pyroscope/rendered/single-binary-v2.yaml \ + | $(BIN)/kubeconform --summary --strict --kubernetes-version 1.23.0 + $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ $(HELM_FLAGS_V1_MICROSERVICES) \ | tee ./operations/pyroscope/helm/pyroscope/rendered/micro-services.yaml \ | $(BIN)/kubeconform --summary --strict --kubernetes-version 1.23.0 + $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ $(HELM_FLAGS_V2_MICROSERVICES) \ + | tee ./operations/pyroscope/helm/pyroscope/rendered/micro-services-v2.yaml \ + | $(BIN)/kubeconform --summary --strict --kubernetes-version 1.23.0 + $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ --values operations/pyroscope/helm/pyroscope/values-micro-services.yaml \ + | tee ./operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services.yaml \ + | $(BIN)/kubeconform --summary --strict --kubernetes-version 1.23.0 $(BIN)/helm template -n default --kube-version "1.23.0" pyroscope-dev ./operations/pyroscope/helm/pyroscope/ --values operations/pyroscope/helm/pyroscope/values-micro-services-hpa.yaml \ - | tee ./operations/pyroscope/helm/pyroscope/rendered/micro-services-hpa.yaml \ + | tee ./operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services-hpa.yaml \ | $(BIN)/kubeconform --summary --strict --kubernetes-version 1.23.0 cat operations/pyroscope/helm/pyroscope/values-micro-services.yaml \ | go run ./tools/yaml-to-json \ @@ -395,30 +475,33 @@ helm/check: $(BIN)/kubeconform $(BIN)/helm cat operations/pyroscope/helm/pyroscope/values.yaml \ | go run ./tools/yaml-to-json \ > ./operations/pyroscope/jsonnet/values.json + # Generate dashboards and rules (native histograms, default) + $(BIN)/helm template pyroscope-monitoring --show-only templates/dashboards.yaml --show-only templates/rules.yaml operations/monitoring/helm/pyroscope-monitoring \ + | go run ./tools/monitoring-chart-extractor + # Generate dashboards for classic histograms (--set dashboards.nativeHistograms=false) + $(BIN)/helm template pyroscope-monitoring --show-only templates/dashboards.yaml operations/monitoring/helm/pyroscope-monitoring --set dashboards.nativeHistograms=false \ + | go run ./tools/monitoring-chart-extractor --output.dashboards.path ./operations/monitoring/dashboards-classic-histogram/ .PHONY: deploy deploy: $(BIN)/kind $(BIN)/helm docker-image/pyroscope/build - $(call deploy,pyroscope-dev,) - # Create a service to provide the same endpoint as micro-services - echo '{"kind":"Service","apiVersion":"v1","metadata":{"name":"pyroscope-micro-services-query-frontend"},"spec":{"ports":[{"name":"pyroscope","port":4040,"targetPort":4040}],"selector":{"app.kubernetes.io/component":"all","app.kubernetes.io/instance":"pyroscope-dev"},"type":"ClusterIP"}}' | kubectl apply -f - + $(call deploy,pyroscope-dev,$(HELM_FLAGS_V2)) + +.PHONY: deploy-v1 +deploy-v1: $(BIN)/kind $(BIN)/helm docker-image/pyroscope/build + $(call deploy,pyroscope-dev,$(HELM_FLAGS_V1_DEPLOY)) .PHONY: deploy-micro-services deploy-micro-services: $(BIN)/kind $(BIN)/helm docker-image/pyroscope/build - # Ensure to delete existing service, that has been created manually by the deploy target - kubectl delete svc --field-selector metadata.name=pyroscope-micro-services-query-frontend -l app.kubernetes.io/managed-by!=Helm - $(call deploy,pyroscope-micro-services,--values=operations/pyroscope/helm/pyroscope/values-micro-services.yaml --set pyroscope.components.querier.resources=null --set pyroscope.components.distributor.resources=null --set pyroscope.components.ingester.resources=null --set pyroscope.components.store-gateway.resources=null --set pyroscope.components.compactor.resources=null) + $(call deploy,pyroscope-micro-services,$(HELM_FLAGS_V2_MICROSERVICES)) -.PHONY: deploy-monitoring -deploy-monitoring: $(BIN)/tk $(BIN)/kind tools/monitoring/environments/default/spec.json - kubectl --context="kind-$(KIND_CLUSTER)" create namespace monitoring --dry-run=client -o yaml | kubectl --context="kind-$(KIND_CLUSTER)" apply -f - - $(BIN)/tk apply tools/monitoring/environments/default/main.jsonnet +.PHONY: deploy-micro-services-v1 +deploy-micro-services-v1: $(BIN)/kind $(BIN)/helm docker-image/pyroscope/build + $(call deploy,pyroscope-micro-services,$(HELM_FLAGS_V1_MICROSERVICES_DEPLOY)) -.PHONY: tools/monitoring/environments/default/spec.json # This is a phony target for now as the cluster might be not already created. -tools/monitoring/environments/default/spec.json: $(BIN)/tk $(BIN)/kind +.PHONY: deploy-monitoring +deploy-monitoring: $(BIN)/kind $(BIN)/helm $(BIN)/kind export kubeconfig --name $(KIND_CLUSTER) || $(BIN)/kind create cluster --name $(KIND_CLUSTER) - pushd tools/monitoring/ && rm -Rf vendor/ lib/ environments/default/spec.json && PATH=$(BIN):$(PATH) $(BIN)/tk init -f - echo "import 'monitoring.libsonnet'" > tools/monitoring/environments/default/main.jsonnet - $(BIN)/tk env set tools/monitoring/environments/default --server=$(shell $(BIN)/kind get kubeconfig --name pyroscope-dev | grep server: | sed 's/server://g' | xargs) --namespace=monitoring + $(BIN)/helm upgrade --install pyroscope-monitoring ./operations/monitoring/helm/pyroscope-monitoring include Makefile.examples @@ -429,3 +512,7 @@ docs/%: .PHONY: run run: ## Run the pyroscope binary (pass parameters with 'make run PARAMS=-myparam') ./pyroscope $(PARAMS) + +.PHONY: mockery +mockery: $(BIN)/mockery + $(BIN)/mockery diff --git a/Makefile.examples b/Makefile.examples index 855a003530..5196bd2937 100644 --- a/Makefile.examples +++ b/Makefile.examples @@ -1,10 +1,36 @@ +GITHUB_REPOSITORY ?= grafana/pyroscope + +# Sync all example files from templates. +.PHONY: examples/sync-templates +examples/sync-templates: + EXAMPLE_CHECK_MODE=update go test ./examples/_templates/ -count 1 -v + +# Verify that every example's files match their templates. +.PHONY: examples/check-templates +examples/check-templates: + EXAMPLE_CHECK_MODE=check go test ./examples/_templates/ -count 1 -v .PHONY: tools/update_examples tools/update_examples: - go run tools/update_examples.go + docker buildx build --platform linux/amd64 -t update_pyroscope_examples -f tools/update_examples.Dockerfile tools + docker run --rm --platform=linux/amd64 -e GITHUB_TOKEN=$(GITHUB_TOKEN) -v$(shell pwd):/pyroscope -w /pyroscope update_pyroscope_examples bash -l -c "go run tools/update_examples.go" + +.PHONY: tools/update_examples_pr +tools/update_examples_pr: + git config --local user.name 'Pyroscope Bot' + git config --local user.email 'dmitry+bot@pyroscope.io' + git checkout -b gh_bot_examples_update + git add . + git commit -m "chore(examples): update examples" + git push -f https://x-access-token:$(GITHUB_TOKEN)@github.com/$(GITHUB_REPOSITORY).git gh_bot_examples_update 2> /dev/null + gh pr create --head gh_bot_examples_update --title "chore(examples): update examples" --body "make tools/update_examples" --repo $(GITHUB_REPOSITORY) || \ + gh pr edit gh_bot_examples_update --title "chore(examples): update examples" --body "make tools/update_examples" --repo $(GITHUB_REPOSITORY) + .PHONY: rideshare/docker/push -rideshare/docker/push: rideshare/docker/push-golang rideshare/docker/push-loadgen rideshare/docker/push-python rideshare/docker/push-ruby rideshare/docker/push-dotnet rideshare/docker/push-java rideshare/docker/push-rust +rideshare/docker/push: IMAGE_PLATFORM := linux/amd64 +rideshare/docker/push: IMAGE_PREFIX := us-docker.pkg.dev/grafanalabs-dev/docker-pyroscope-dev/ +rideshare/docker/push: rideshare/docker/push-golang rideshare/docker/push-loadgen rideshare/docker/push-python rideshare/docker/push-ruby rideshare/docker/push-dotnet rideshare/docker/push-java rideshare/docker/push-rust rideshare/docker/push-nodejs .PHONY: rideshare/docker/push-golang rideshare/docker/push-golang: @@ -16,20 +42,24 @@ rideshare/docker/push-loadgen: .PHONY: rideshare/docker/push-python rideshare/docker/push-python: - docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-python -t $(IMAGE_PREFIX)pyroscope-rideshare-python:$(IMAGE_TAG) examples/python/rideshare/flask + docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-python -t $(IMAGE_PREFIX)pyroscope-rideshare-python:$(IMAGE_TAG) examples/language-sdk-instrumentation/python/rideshare/flask .PHONY: rideshare/docker/push-ruby rideshare/docker/push-ruby: - docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-ruby -t $(IMAGE_PREFIX)pyroscope-rideshare-ruby:$(IMAGE_TAG) examples/ruby/rideshare_rails + docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-ruby -t $(IMAGE_PREFIX)pyroscope-rideshare-ruby:$(IMAGE_TAG) examples/language-sdk-instrumentation/ruby/rideshare_rails .PHONY: rideshare/docker/push-dotnet rideshare/docker/push-dotnet: - docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-dotnet -t $(IMAGE_PREFIX)pyroscope-rideshare-dotnet:$(IMAGE_TAG) examples/dotnet/rideshare/ + docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-dotnet -t $(IMAGE_PREFIX)pyroscope-rideshare-dotnet:$(IMAGE_TAG) examples/language-sdk-instrumentation/dotnet/rideshare/ .PHONY: rideshare/docker/push-java rideshare/docker/push-java: - docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-java -t $(IMAGE_PREFIX)pyroscope-rideshare-java:$(IMAGE_TAG) examples/java/rideshare + docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-java -t $(IMAGE_PREFIX)pyroscope-rideshare-java:$(IMAGE_TAG) examples/language-sdk-instrumentation/java/rideshare .PHONY: rideshare/docker/push-rust rideshare/docker/push-rust: - docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-rust -t $(IMAGE_PREFIX)pyroscope-rideshare-rust:$(IMAGE_TAG) examples/rust/rideshare + docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-rust -t $(IMAGE_PREFIX)pyroscope-rideshare-rust:$(IMAGE_TAG) examples/language-sdk-instrumentation/rust/rideshare + +.PHONY: rideshare/docker/push-nodejs +rideshare/docker/push-nodejs: + docker buildx build --push --platform $(IMAGE_PLATFORM) -t $(IMAGE_PREFIX)pyroscope-rideshare-nodejs -t $(IMAGE_PREFIX)pyroscope-rideshare-nodejs:$(IMAGE_TAG) examples/language-sdk-instrumentation/nodejs/express diff --git a/README.md b/README.md index dbf4e458dc..b803aa0c26 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,109 @@

Pyroscope

-[![ci](https://github.com/grafana/pyroscope/actions/workflows/test.yml/badge.svg)](https://github.com/grafana/pyroscope/actions/workflows/test.yml) -[![JS Tests Status](https://github.com/grafana/pyroscope/workflows/JS%20Tests/badge.svg)](https://github.com/grafana/pyroscope/actions?query=workflow%3AJS%20Tests) +[![ci](https://github.com/grafana/pyroscope/actions/workflows/ci.yml/badge.svg)](https://github.com/grafana/pyroscope/actions/workflows/ci.yml) [![Go Report](https://goreportcard.com/badge/github.com/grafana/pyroscope)](https://goreportcard.com/report/github.com/grafana/pyroscope) [![License: AGPLv3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](LICENSE) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgrafana%2Fpyroscope.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgrafana%2Fpyroscope?ref=badge_shield) [![Latest release](https://img.shields.io/github/release/grafana/pyroscope.svg)](https://github.com/grafana/pyroscope/releases) [![DockerHub](https://img.shields.io/docker/pulls/grafana/pyroscope.svg)](https://hub.docker.com/r/grafana/pyroscope) -[![GoDoc](https://godoc.org/github.com/grafana/pyroscope?status.svg)](https://godoc.org/github.com/grafana/pyroscope) +[![Go Reference](https://pkg.go.dev/badge/github.com/grafana/pyroscope/v2.svg)](https://pkg.go.dev/github.com/grafana/pyroscope/v2) -### 🌟 What is Grafana Pyroscope? +## 🎉 **Announcement: Pyroscope 2.0 is here!** -Grafana Pyroscope is an open source continuous profiling platform. It will help you: -* Find performance issues and bottlenecks in your code -* Use high-cardinality tags/labels to analyze your application -* Resolve issues with high CPU utilization -* Track down memory leaks -* Understand the call tree of your application -* Auto-instrument your code to link profiling data to traces +Pyroscope 2.0 makes the new **v2 architecture** the default. Profiles are written directly to object storage, removing the need for in-memory ingesters and local disks - simplifying operations and lowering resource usage at scale. Existing v1 deployments can opt in via a flag and migrate without data loss. -## 🔥 [Pyroscope Live Demo](https://demo.pyroscope.io/) 🔥 +Read the [2.0 release notes](https://grafana.com/docs/pyroscope/latest/release-notes/v2-0/) and the [v2 architecture overview](https://grafana.com/docs/pyroscope/latest/reference-pyroscope-v2-architecture/). Upgrading from v1? See the [migration guide](https://grafana.com/docs/pyroscope/latest/reference-pyroscope-v2-architecture/migrate-from-v1/). -[![Pyroscope GIF Demo](https://user-images.githubusercontent.com/23323466/143324845-16ff72df-231e-412d-bd0a-38ef2e09cba8.gif)](https://demo.pyroscope.io/) +Want the full story? Watch the GrafanaCON 2026 talk [_Pyroscope 2.0: Continuous Profiling Architecture Deep Dive_](https://www.youtube.com/watch?v=vseSm-pzgmc). -## 🎉 Features +## What is Grafana Pyroscope? -* Minimal CPU overhead -* Horizontally scalable -* Efficient compression, low disk space requirements -* Can handle high-cardinality tags/labels -* Calculate the performance "diff" between various tags/labels and time periods -* Advanced analysis UI +Grafana Pyroscope is a continuous profiling platform designed to surface performance insights from your applications, helping you optimize resource usage such as CPU, memory, and I/O operations. With Pyroscope, you can both **proactively** and **reactively** address performance bottlenecks across your system. -## 💻 Quick Start: Run Pyroscope Locally +The typical use cases are: -### Homebrew +- **Proactive:** Reducing resource consumption, improving application performance, or preventing latency issues. +- **Reactive:** Quickly resolving incidents with line-level detail and debugging active CPU, memory, or I/O bottlenecks. + +Pyroscope provides powerful tools to give you a comprehensive view of your application's behavior while allowing you to drill down into specific services for more targeted root cause analysis. + +## How Does Pyroscope Work? + +![deployment_diagram](https://grafana.com/media/docs/pyroscope/pyroscope_client_server_diagram_11_18_2024.png) + +Pyroscope consists of three main components: +- **Pyroscope Server:** Stores and processes profiling data and serves queries. +- **Clients and instrumentation:** Profiling data reaches the server in several ways: the [Pyroscope SDKs](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/) (push), [Grafana Alloy](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/) (pull or push), or OTLP from OpenTelemetry-compatible sources such as the [OpenTelemetry eBPF profiler](https://grafana.com/docs/pyroscope/latest/configure-client/opentelemetry/ebpf-profiler/). +- **Grafana Profiles Drilldown:** A queryless, intuitive UI for visualizing and analyzing profiling data (formerly Explore Profiles). + +Under the hood, Pyroscope v2 writes profiles straight to object storage—no ingesters, no local disk. The animations below trace the three parts of the architecture. For the details behind each component, see the [v2 architecture documentation](https://grafana.com/docs/pyroscope/latest/reference-pyroscope-v2-architecture/). + +**Write path** — profiles are routed by service and written straight to object storage: + +![Pyroscope v2 write path](images/pyroscope-v2-write-path.gif) + +**Compaction** — compaction-workers merge small segments into larger blocks in the background: + +![Pyroscope v2 compaction](images/pyroscope-v2-compaction.gif) + +**Read path** — queries fan out across object storage to build flame graphs in Grafana Profiles Drilldown: + +![Pyroscope v2 read path](images/pyroscope-v2-read-path.gif) + +--- + +## [Pyroscope Live Demo](https://play.grafana.org/a/grafana-pyroscope-app/explore) + +[![Pyroscope GIF Demo](https://github.com/user-attachments/assets/2faeb985-f2b6-4311-ad29-e318e850c025)](https://play.grafana.org/a/grafana-pyroscope-app/explore) + + +--- + +## **Quick Start: Run the Pyroscope server locally** + +### Docker +```sh +docker run -it -p 4040:4040 grafana/pyroscope +``` + +### Homebrew (macOS / Linux) ```sh brew install pyroscope-io/brew/pyroscope brew services start pyroscope ``` -### Docker +### Binary +Download the archive for your operating system and architecture from the [latest release](https://github.com/grafana/pyroscope/releases/latest), unpack it, and run the binary: ```sh -docker run -it -p 4040:4040 grafana/pyroscope +tar xvf pyroscope_*.tar.gz +./pyroscope ``` -For more documentation on how to configure Pyroscope server, see [our server documentation](https://grafana.com/docs/pyroscope/latest/configure-server/). +Pyroscope listens on port `4040`. For Kubernetes/Helm, Linux packages, building from source, and full configuration options, see the [Get started guide](https://grafana.com/docs/pyroscope/latest/get-started/) and the [server documentation](https://grafana.com/docs/pyroscope/latest/configure-server/). + +## **Quick Start: Visualize profiles with Grafana Profiles Drilldown** + +image + +[Grafana Profiles Drilldown](https://grafana.com/docs/grafana/latest/visualizations/simplified-exploration/profiles/) (formerly Explore Profiles) is the primary, queryless way to visualize and analyze your profiling data. + +### Grafana Cloud / OSS +Profiles Drilldown is pre-installed and is the default way to explore your profiles – all you need to do is start sending data. + +## Documentation + +For more information on how to use Pyroscope with other programming languages, install it on Linux, or use it in a production environment, check out our documentation: + +* [Getting Started](https://grafana.com/docs/pyroscope/latest/get-started/) +* [Deployment Guide](https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/) +* [Pyroscope v2 Architecture](https://grafana.com/docs/pyroscope/latest/reference-pyroscope-v2-architecture/) +## Send data to the server -## Send data to server via Pyroscope agent (language specific) +You can send profiles to Pyroscope with the language SDKs, with [Grafana Alloy](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/), or over OTLP from OpenTelemetry-compatible sources such as the [OpenTelemetry eBPF profiler](https://grafana.com/docs/pyroscope/latest/configure-client/opentelemetry/ebpf-profiler/). -For more documentation on how to add the Pyroscope agent to your code, see the [agent documentation](https://grafana.com/docs/pyroscope/latest/configure-client/) on our website or find language specific examples and documentation below: +For more documentation on how to add the Pyroscope SDK to your code, see the [client documentation](https://grafana.com/docs/pyroscope/latest/configure-client/) on our website or find language-specific examples and documentation below: -

@@ -82,14 +134,14 @@ For more documentation on how to add the Pyroscope agent to your code, see the [
Examples

- Dotnet

+ .NET
Documentation
Examples

+

eBPF

- Documentation
- Examples + Documentation
+ Examples

Rust

@@ -99,37 +151,15 @@ For more documentation on how to add the Pyroscope agent to your code, see the [
-## Deployment Diagram +## [Supported Languages][supported languages] -![deployment_diagram](https://grafana.com/media/docs/pyroscope/pyroscope_client_server_diagram.png) - -## Documentation - -For more information on how to use Pyroscope with other programming languages, install it on Linux, or use it in production environment, check out our documentation: - -* [Getting Started](https://grafana.com/docs/pyroscope/latest/get-started/) -* [Deployment Guide](https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/) -* [Pyroscope Architecture](https://grafana.com/docs/pyroscope/latest/reference-pyroscope-architecture/) - - -## Downloads - -You can download the latest version of pyroscope for macOS, linux and Docker from our [Releases page](https://github.com/grafana/pyroscope/releases). - -## Supported Languages - -* [x] Go (via `pprof`) -* [x] Python (via `py-spy`) -* [x] Ruby (via `rbspy`) -* [x] Linux eBPF -* [x] Java (via `async-profiler`) -* [x] Rust (via `pprof-rs`) -* [x] .NET -* [x] PHP (via `phpspy`) -* [x] Node +Our documentation contains the most recent list of [supported languages] and also an overview over what [profiling types are supported per language][profile-types-languages]. Let us know what other integrations you want to see in [our issues](https://github.com/grafana/pyroscope/issues?q=is%3Aissue+is%3Aopen+label%3Anew-profilers) or in [our slack](https://slack.grafana.com). +[supported languages]: https://grafana.com/docs/pyroscope/latest/configure-client/ +[profile-types-languages]: https://grafana.com/docs/pyroscope/latest/configure-client/profile-types/ + ## Credits Pyroscope is possible thanks to the excellent work of many people, including but not limited to: @@ -139,7 +169,7 @@ Pyroscope is possible thanks to the excellent work of many people, including but * Vladimir Agafonkin — creator of flamebearer — fast flame graph renderer * Ben Frederickson — creator of py-spy — sampling profiler for Python * Adam Saponara — creator of phpspy — sampling profiler for PHP -* Alexei Starovoitov, Brendan Gregg, and many others who made BPF based profiling in Linux kernel possible +* Alexei Starovoitov, Daniel Borkmann, and many others who made BPF based profiling in Linux kernel possible * Jamie Wong — creator of speedscope — interactive flame graph visualizer ## Contributing @@ -150,104 +180,70 @@ To start contributing, check out our [Contributing Guide](docs/internal/contribu ### Thanks to the contributors of Pyroscope! [//]: contributor-faces - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

[//]: contributor-faces diff --git a/api/adhocprofiles/v1/adhocprofiles.proto b/api/adhocprofiles/v1/adhocprofiles.proto index 5f5591575b..c1b53bb348 100644 --- a/api/adhocprofiles/v1/adhocprofiles.proto +++ b/api/adhocprofiles/v1/adhocprofiles.proto @@ -15,6 +15,9 @@ service AdHocProfileService { // Retrieves a list of profiles found in the underlying store. rpc List(AdHocProfilesListRequest) returns (AdHocProfilesListResponse) {} + + // Computes a diff flamegraph from two previously uploaded profiles. + rpc Diff(AdHocProfilesDiffRequest) returns (AdHocProfilesDiffResponse) {} } message AdHocProfilesUploadRequest { @@ -59,3 +62,15 @@ message AdHocProfilesProfileMetadata { // timestamp in milliseconds int64 uploaded_at = 3; } + +message AdHocProfilesDiffRequest { + string left_id = 1; + string right_id = 2; + optional string profile_type = 3; + optional int64 max_nodes = 4; +} + +message AdHocProfilesDiffResponse { + repeated string profile_types = 1; + string flamebearer_profile = 2; +} diff --git a/api/buf.gen.yaml b/api/buf.gen.yaml index 26a3d11cc2..55f9b1bc68 100644 --- a/api/buf.gen.yaml +++ b/api/buf.gen.yaml @@ -5,6 +5,7 @@ managed: default: github.com/grafana/pyroscope/api/gen/proto/go except: - buf.build/googleapis/googleapis + - buf.build/gnostic/gnostic plugins: - name: go @@ -34,3 +35,11 @@ plugins: out: openapiv2/gen/ strategy: all opt: allow_merge=true,merge_file_name=phlare + + - name: connect-openapi + out: connect-openapi/gen/ + opt: + #- debug + - content-types=json + - trim-unused-types + - base=connect-openapi/base.yaml diff --git a/api/buf.lock b/api/buf.lock index f2c6b32b76..c0a18450c7 100644 --- a/api/buf.lock +++ b/api/buf.lock @@ -1,11 +1,18 @@ # Generated by buf. DO NOT EDIT. version: v1 deps: + - remote: buf.build + owner: gnostic + repository: gnostic + commit: 087bc8072ce44e339f213209e4d57bf0 + digest: shake256:4689c26f0460fea84c4c277c1b9c7e7d657388c5b4116d1065f907a92100ffbea87de05bbd138a0166411361e1f6ce063b4c0c6002358d39710f3c4a8de788d5 - remote: buf.build owner: googleapis repository: googleapis - commit: 8d7204855ec14631a499bd7393ce1970 + commit: 61b203b9a9164be9a834f58c37be6f62 + digest: shake256:e619113001d6e284ee8a92b1561e5d4ea89a47b28bf0410815cb2fa23914df8be9f1a6a98dcf069f5bc2d829a2cfb1ac614863be45cd4f8a5ad8606c5f200224 - remote: buf.build owner: grpc-ecosystem repository: grpc-gateway - commit: bc28b723cd774c32b6fbc77621518765 + commit: 4c5ba75caaf84e928b7137ae5c18c26a + digest: shake256:e174ad9408f3e608f6157907153ffec8d310783ee354f821f57178ffbeeb8faa6bb70b41b61099c1783c82fe16210ebd1279bc9c9ee6da5cffba9f0e675b8b99 diff --git a/api/buf.yaml b/api/buf.yaml index 8221480214..b09ea1c748 100644 --- a/api/buf.yaml +++ b/api/buf.yaml @@ -1,4 +1,5 @@ version: v1 +name: buf.build/pyroscope/api lint: use: - DEFAULT @@ -8,3 +9,4 @@ breaking: deps: - buf.build/googleapis/googleapis - buf.build/grpc-ecosystem/grpc-gateway + - buf.build/gnostic/gnostic diff --git a/api/capabilities/v1/feature_flags.proto b/api/capabilities/v1/feature_flags.proto new file mode 100644 index 0000000000..13912ccb6f --- /dev/null +++ b/api/capabilities/v1/feature_flags.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package capabilities.v1; + +service FeatureFlagsService { + // Retrieve feature flags that are enabled for a particular tenant + rpc GetFeatureFlags(GetFeatureFlagsRequest) returns (GetFeatureFlagsResponse) {} +} + +message GetFeatureFlagsRequest {} + +message GetFeatureFlagsResponse { + // Map containing all features, also disable features are returned + repeated FeatureFlag feature_flags = 1; +} + +// FeatureParameters contains the per feature flag parameters. +message FeatureFlag { + // Name of the feature, please use lower camel case. + string name = 1; + // Wether the feature flag is enabled or disabled. + bool enabled = 2; + // Optional description of the feature flag. + optional string description = 3; + // Optional URL to the documentation page of the feature flag. + optional string documentation_url = 4; +} diff --git a/api/connect-openapi/base.yaml b/api/connect-openapi/base.yaml new file mode 100644 index 0000000000..a7a0ff724b --- /dev/null +++ b/api/connect-openapi/base.yaml @@ -0,0 +1,10 @@ +openapi: 3.1.0 +info: + title: Pyroscope API + description: "Pyroscope API definitions" + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. diff --git a/api/connect-openapi/gen/adhocprofiles/v1/adhocprofiles.openapi.yaml b/api/connect-openapi/gen/adhocprofiles/v1/adhocprofiles.openapi.yaml new file mode 100644 index 0000000000..90cf38445c --- /dev/null +++ b/api/connect-openapi/gen/adhocprofiles/v1/adhocprofiles.openapi.yaml @@ -0,0 +1,373 @@ +openapi: 3.1.0 +info: + title: adhocprofiles.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: adhocprofiles.v1.AdHocProfileService +paths: + /adhocprofiles.v1.AdHocProfileService/Diff: + post: + tags: + - adhocprofiles.v1.AdHocProfileService + summary: Computes a diff flamegraph from two previously uploaded profiles. + description: Computes a diff flamegraph from two previously uploaded profiles. + operationId: adhocprofiles.v1.AdHocProfileService.Diff + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesDiffRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesDiffResponse' + /adhocprofiles.v1.AdHocProfileService/Get: + post: + tags: + - adhocprofiles.v1.AdHocProfileService + summary: Retrieves a profile from the underlying store by id and an optional sample type. The response is similar to the one for the upload method. + description: |- + Retrieves a profile from the underlying store by id and an optional sample type. The response is similar to the one + for the upload method. + operationId: adhocprofiles.v1.AdHocProfileService.Get + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesGetRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesGetResponse' + /adhocprofiles.v1.AdHocProfileService/List: + post: + tags: + - adhocprofiles.v1.AdHocProfileService + summary: Retrieves a list of profiles found in the underlying store. + description: Retrieves a list of profiles found in the underlying store. + operationId: adhocprofiles.v1.AdHocProfileService.List + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesListRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesListResponse' + /adhocprofiles.v1.AdHocProfileService/Upload: + post: + tags: + - adhocprofiles.v1.AdHocProfileService + summary: Upload a profile to the underlying store. The request contains a name and a base64 encoded pprof file. The response contains a generated unique identifier, a flamegraph and a list of found sample types within the profile. + description: |- + Upload a profile to the underlying store. The request contains a name and a base64 encoded pprof file. The response + contains a generated unique identifier, a flamegraph and a list of found sample types within the profile. + operationId: adhocprofiles.v1.AdHocProfileService.Upload + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesUploadRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesGetResponse' +components: + schemas: + adhocprofiles.v1.AdHocProfilesDiffRequest: + type: object + properties: + leftId: + type: string + title: left_id + rightId: + type: string + title: right_id + profileType: + type: string + title: profile_type + nullable: true + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + nullable: true + title: AdHocProfilesDiffRequest + additionalProperties: false + adhocprofiles.v1.AdHocProfilesDiffResponse: + type: object + properties: + profileTypes: + type: array + items: + type: string + title: profile_types + flamebearerProfile: + type: string + title: flamebearer_profile + title: AdHocProfilesDiffResponse + additionalProperties: false + adhocprofiles.v1.AdHocProfilesGetRequest: + type: object + properties: + id: + type: string + title: id + description: The unique identifier of the profile. + profileType: + type: string + title: profile_type + description: The desired profile type (e.g., cpu, samples) for the returned flame graph. If omitted the first profile is returned. + nullable: true + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes can be used to truncate the response. + nullable: true + title: AdHocProfilesGetRequest + additionalProperties: false + adhocprofiles.v1.AdHocProfilesGetResponse: + type: object + properties: + id: + type: string + title: id + name: + type: string + title: name + uploadedAt: + type: + - integer + - string + title: uploaded_at + format: int64 + description: timestamp in milliseconds + profileType: + type: string + title: profile_type + profileTypes: + type: array + items: + type: string + title: profile_types + description: |- + Some profiles formats (like pprof) can contain multiple profile (sample) types inside. One of these can be passed + in the Get request using the profile_type field. + flamebearerProfile: + type: string + title: flamebearer_profile + title: AdHocProfilesGetResponse + additionalProperties: false + adhocprofiles.v1.AdHocProfilesListRequest: + type: object + title: AdHocProfilesListRequest + additionalProperties: false + adhocprofiles.v1.AdHocProfilesListResponse: + type: object + properties: + profiles: + type: array + items: + $ref: '#/components/schemas/adhocprofiles.v1.AdHocProfilesProfileMetadata' + title: profiles + title: AdHocProfilesListResponse + additionalProperties: false + adhocprofiles.v1.AdHocProfilesProfileMetadata: + type: object + properties: + id: + type: string + title: id + name: + type: string + title: name + uploadedAt: + type: + - integer + - string + title: uploaded_at + format: int64 + description: timestamp in milliseconds + title: AdHocProfilesProfileMetadata + additionalProperties: false + adhocprofiles.v1.AdHocProfilesUploadRequest: + type: object + properties: + name: + type: string + title: name + description: This is typically the file name and it serves as a human readable name for the profile. + profile: + type: string + title: profile + description: This is the profile encoded in base64. The supported formats are pprof, json, collapsed and perf-script. + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes can be used to truncate the response. + nullable: true + title: AdHocProfilesUploadRequest + additionalProperties: false + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. +security: [] diff --git a/api/connect-openapi/gen/capabilities/v1/feature_flags.openapi.yaml b/api/connect-openapi/gen/capabilities/v1/feature_flags.openapi.yaml new file mode 100644 index 0000000000..512720bff8 --- /dev/null +++ b/api/connect-openapi/gen/capabilities/v1/feature_flags.openapi.yaml @@ -0,0 +1,158 @@ +openapi: 3.1.0 +info: + title: capabilities.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: capabilities.v1.FeatureFlagsService +paths: + /capabilities.v1.FeatureFlagsService/GetFeatureFlags: + post: + tags: + - capabilities.v1.FeatureFlagsService + summary: Retrieve feature flags that are enabled for a particular tenant + description: Retrieve feature flags that are enabled for a particular tenant + operationId: capabilities.v1.FeatureFlagsService.GetFeatureFlags + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/capabilities.v1.GetFeatureFlagsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/capabilities.v1.GetFeatureFlagsResponse' +components: + schemas: + capabilities.v1.FeatureFlag: + type: object + properties: + name: + type: string + title: name + description: Name of the feature, please use lower camel case. + enabled: + type: boolean + title: enabled + description: Wether the feature flag is enabled or disabled. + description: + type: string + title: description + description: Optional description of the feature flag. + nullable: true + documentationUrl: + type: string + title: documentation_url + description: Optional URL to the documentation page of the feature flag. + nullable: true + title: FeatureFlag + additionalProperties: false + description: FeatureParameters contains the per feature flag parameters. + capabilities.v1.GetFeatureFlagsRequest: + type: object + title: GetFeatureFlagsRequest + additionalProperties: false + capabilities.v1.GetFeatureFlagsResponse: + type: object + properties: + featureFlags: + type: array + items: + $ref: '#/components/schemas/capabilities.v1.FeatureFlag' + title: feature_flags + description: Map containing all features, also disable features are returned + title: GetFeatureFlagsResponse + additionalProperties: false + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. +security: [] diff --git a/api/connect-openapi/gen/debuginfo/v1/debuginfo.openapi.yaml b/api/connect-openapi/gen/debuginfo/v1/debuginfo.openapi.yaml new file mode 100644 index 0000000000..f2f1b84d6c --- /dev/null +++ b/api/connect-openapi/gen/debuginfo/v1/debuginfo.openapi.yaml @@ -0,0 +1,175 @@ +openapi: 3.1.0 +info: + title: debuginfo.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: debuginfo.v1.DebuginfoService + description: |- + This service is inspired by parca debug info upload rpc + It is however different, specifically original ShouldInitiateUpload,InitiateUpload,InitiateUpload are merged into Upload + Some structs were renamed. Some features removed (signed upload, force upload) +paths: + /debuginfo.v1.DebuginfoService/Upload: {} +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + debuginfo.v1.FileMetadata: + type: object + properties: + GNU: + type: string + title: GNU + Golang: + type: string + title: Golang + OpenTelemetry: + type: string + title: OpenTelemetry + description: optional libpf.FileID rom the otel profiler + Name: + type: string + title: Name + type: + title: type + $ref: '#/components/schemas/debuginfo.v1.FileMetadata.DebuginfoType' + title: FileMetadata + additionalProperties: false + debuginfo.v1.FileMetadata.DebuginfoType: + type: string + title: DebuginfoType + enum: + - DEBUGINFO_TYPE_EXECUTABLE_FULL + - DEBUGINFO_TYPE_EXECUTABLE_NO_TEXT + debuginfo.v1.ShouldInitiateUploadRequest: + type: object + properties: + file: + title: file + description: bool force = ; + $ref: '#/components/schemas/debuginfo.v1.FileMetadata' + title: ShouldInitiateUploadRequest + additionalProperties: false + debuginfo.v1.ShouldInitiateUploadResponse: + type: object + properties: + shouldInitiateUpload: + type: boolean + title: should_initiate_upload + reason: + type: string + title: reason + title: ShouldInitiateUploadResponse + additionalProperties: false + debuginfo.v1.UploadChunk: + type: object + properties: + chunk: + type: string + title: chunk + format: byte + title: UploadChunk + additionalProperties: false + debuginfo.v1.UploadRequest: + type: object + oneOf: + - properties: + chunk: + title: chunk + $ref: '#/components/schemas/debuginfo.v1.UploadChunk' + title: chunk + required: + - chunk + - properties: + init: + title: init + $ref: '#/components/schemas/debuginfo.v1.ShouldInitiateUploadRequest' + title: init + required: + - init + title: UploadRequest + additionalProperties: false + debuginfo.v1.UploadResponse: + type: object + oneOf: + - properties: + init: + title: init + $ref: '#/components/schemas/debuginfo.v1.ShouldInitiateUploadResponse' + title: init + required: + - init + title: UploadResponse + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/debuginfo/v1alpha1/debuginfo.openapi.yaml b/api/connect-openapi/gen/debuginfo/v1alpha1/debuginfo.openapi.yaml new file mode 100644 index 0000000000..6eccbdb705 --- /dev/null +++ b/api/connect-openapi/gen/debuginfo/v1alpha1/debuginfo.openapi.yaml @@ -0,0 +1,441 @@ +openapi: 3.1.0 +info: + title: debuginfo.v1alpha1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: debuginfo.v1alpha1.DebuginfoService +paths: + /debuginfo.v1alpha1.DebuginfoService/DeleteDebuginfo: + post: + tags: + - debuginfo.v1alpha1.DebuginfoService + summary: DeleteDebuginfo + operationId: debuginfo.v1alpha1.DebuginfoService.DeleteDebuginfo + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.DeleteDebuginfoRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.DeleteDebuginfoResponse' + /debuginfo.v1alpha1.DebuginfoService/ListDebuginfo: + post: + tags: + - debuginfo.v1alpha1.DebuginfoService + summary: ListDebuginfo + operationId: debuginfo.v1alpha1.DebuginfoService.ListDebuginfo + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.ListDebuginfoRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.ListDebuginfoResponse' + /debuginfo.v1alpha1.DebuginfoService/ShouldInitiateUpload: + post: + tags: + - debuginfo.v1alpha1.DebuginfoService + summary: ShouldInitiateUpload + operationId: debuginfo.v1alpha1.DebuginfoService.ShouldInitiateUpload + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.ShouldInitiateUploadRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.ShouldInitiateUploadResponse' + /debuginfo.v1alpha1.DebuginfoService/UploadFinished: + post: + tags: + - debuginfo.v1alpha1.DebuginfoService + summary: UploadFinished + operationId: debuginfo.v1alpha1.DebuginfoService.UploadFinished + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.UploadFinishedRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/debuginfo.v1alpha1.UploadFinishedResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + debuginfo.v1alpha1.DeleteDebuginfoRequest: + type: object + properties: + gnuBuildId: + type: string + title: gnu_build_id + title: DeleteDebuginfoRequest + additionalProperties: false + debuginfo.v1alpha1.DeleteDebuginfoResponse: + type: object + title: DeleteDebuginfoResponse + additionalProperties: false + debuginfo.v1alpha1.FileMetadata: + type: object + properties: + gnuBuildId: + type: string + title: gnu_build_id + description: GNU build ID of the executable. + goBuildId: + type: string + title: go_build_id + description: Go build ID of the executable. + otelFileId: + type: string + title: otel_file_id + description: Optional libpf.FileID from the otel profiler. + name: + type: string + title: name + description: Original file name of the executable. + type: + title: type + description: Type of the debug info. + $ref: '#/components/schemas/debuginfo.v1alpha1.FileMetadata.Type' + title: FileMetadata + additionalProperties: false + debuginfo.v1alpha1.FileMetadata.Type: + type: string + title: Type + enum: + - TYPE_UNSPECIFIED + - TYPE_EXECUTABLE_FULL + - TYPE_EXECUTABLE_NO_TEXT + debuginfo.v1alpha1.ListDebuginfoRequest: + type: object + title: ListDebuginfoRequest + additionalProperties: false + debuginfo.v1alpha1.ListDebuginfoResponse: + type: object + properties: + object: + type: array + items: + $ref: '#/components/schemas/debuginfo.v1alpha1.ObjectMetadata' + title: object + title: ListDebuginfoResponse + additionalProperties: false + debuginfo.v1alpha1.ObjectMetadata: + type: object + properties: + file: + title: file + $ref: '#/components/schemas/debuginfo.v1alpha1.FileMetadata' + state: + title: state + $ref: '#/components/schemas/debuginfo.v1alpha1.ObjectMetadata.State' + startedAt: + title: started_at + $ref: '#/components/schemas/google.protobuf.Timestamp' + finishedAt: + title: finished_at + $ref: '#/components/schemas/google.protobuf.Timestamp' + sizeBytes: + type: + - integer + - string + title: size_bytes + format: int64 + description: Size of the uploaded ELF file in bytes. + title: ObjectMetadata + additionalProperties: false + description: |- + This is stored in buckets at "debug-info/$tenant/$gnu_build_id/metadata" + Along with the actual uploaded file at "debug-info/$tenant/$gnu_build_id/exe" + debuginfo.v1alpha1.ObjectMetadata.State: + type: string + title: State + enum: + - STATE_UPLOADING + - STATE_UPLOADED + debuginfo.v1alpha1.ShouldInitiateUploadRequest: + type: object + properties: + file: + title: file + $ref: '#/components/schemas/debuginfo.v1alpha1.FileMetadata' + title: ShouldInitiateUploadRequest + additionalProperties: false + debuginfo.v1alpha1.ShouldInitiateUploadResponse: + type: object + properties: + shouldInitiateUpload: + type: boolean + title: should_initiate_upload + reason: + type: string + title: reason + title: ShouldInitiateUploadResponse + additionalProperties: false + debuginfo.v1alpha1.UploadFinishedRequest: + type: object + properties: + gnuBuildId: + type: string + title: gnu_build_id + title: UploadFinishedRequest + additionalProperties: false + debuginfo.v1alpha1.UploadFinishedResponse: + type: object + title: UploadFinishedResponse + additionalProperties: false + google.protobuf.Timestamp: + type: string + examples: + - "2023-01-15T01:30:15.01Z" + - "2024-12-25T12:00:00Z" + format: date-time + description: |- + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at + nanosecond resolution. The count is relative to an epoch at UTC midnight on + January 1, 1970, in the proleptic Gregorian calendar which extends the + Gregorian calendar backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a [24-hour linear + smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from [RFC + 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from Java `Instant.now()`. + + Instant now = Instant.now(); + + Timestamp timestamp = + Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + .setNanos(now.getNano()).build(); + + Example 6: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the + format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" + where {year} is always expressed using four digits while {month}, {day}, + {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional + seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), + are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone + is required. A proto3 JSON serializer should always use UTC (as indicated by + "Z") when printing the Timestamp type and a proto3 JSON parser should be + able to accept both UTC and other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past + 01:30 UTC on January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the + standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted + to this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with + the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use + the Joda Time's [`ISODateTimeFormat.dateTime()`]( + http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() + ) to obtain a formatter capable of generating timestamps in this format. +security: [] diff --git a/api/connect-openapi/gen/google/v1/profile.openapi.yaml b/api/connect-openapi/gen/google/v1/profile.openapi.yaml new file mode 100644 index 0000000000..df75e26b3e --- /dev/null +++ b/api/connect-openapi/gen/google/v1/profile.openapi.yaml @@ -0,0 +1,12 @@ +openapi: 3.1.0 +info: + title: google.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. +paths: {} +components: {} +security: [] diff --git a/api/connect-openapi/gen/ingester/v1/ingester.openapi.yaml b/api/connect-openapi/gen/ingester/v1/ingester.openapi.yaml new file mode 100644 index 0000000000..7dee6042cb --- /dev/null +++ b/api/connect-openapi/gen/ingester/v1/ingester.openapi.yaml @@ -0,0 +1,1380 @@ +openapi: 3.1.0 +info: + title: ingester.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: ingester.v1.IngesterService +paths: + /ingester.v1.IngesterService/BlockMetadata: + post: + tags: + - ingester.v1.IngesterService + summary: BlockMetadata + operationId: ingester.v1.IngesterService.BlockMetadata + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.BlockMetadataRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.BlockMetadataResponse' + /ingester.v1.IngesterService/Flush: + post: + tags: + - ingester.v1.IngesterService + summary: Flush + operationId: ingester.v1.IngesterService.Flush + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.FlushRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.FlushResponse' + /ingester.v1.IngesterService/GetBlockStats: + post: + tags: + - ingester.v1.IngesterService + summary: GetBlockStats + operationId: ingester.v1.IngesterService.GetBlockStats + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.GetBlockStatsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.GetBlockStatsResponse' + /ingester.v1.IngesterService/GetProfileStats: + post: + tags: + - ingester.v1.IngesterService + summary: GetProfileStats returns profile stats for the current tenant. + description: GetProfileStats returns profile stats for the current tenant. + operationId: ingester.v1.IngesterService.GetProfileStats + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.GetProfileStatsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.GetProfileStatsResponse' + /ingester.v1.IngesterService/LabelNames: + post: + tags: + - ingester.v1.IngesterService + summary: LabelNames + operationId: ingester.v1.IngesterService.LabelNames + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelNamesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelNamesResponse' + /ingester.v1.IngesterService/LabelValues: + post: + tags: + - ingester.v1.IngesterService + summary: LabelValues + operationId: ingester.v1.IngesterService.LabelValues + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelValuesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelValuesResponse' + /ingester.v1.IngesterService/MergeProfilesLabels: {} + /ingester.v1.IngesterService/MergeProfilesPprof: {} + /ingester.v1.IngesterService/MergeProfilesStacktraces: {} + /ingester.v1.IngesterService/MergeSpanProfile: {} + /ingester.v1.IngesterService/ProfileTypes: + post: + tags: + - ingester.v1.IngesterService + summary: 'Deprecated: ProfileType call is deprecated in the store components TODO: Remove this call in release v1.4' + description: |- + Deprecated: ProfileType call is deprecated in the store components + TODO: Remove this call in release v1.4 + operationId: ingester.v1.IngesterService.ProfileTypes + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.ProfileTypesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.ProfileTypesResponse' + /ingester.v1.IngesterService/Push: + post: + tags: + - ingester.v1.IngesterService + summary: Push + operationId: ingester.v1.IngesterService.Push + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/push.v1.PushRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/push.v1.PushResponse' + /ingester.v1.IngesterService/Series: + post: + tags: + - ingester.v1.IngesterService + summary: Series + operationId: ingester.v1.IngesterService.Series + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.SeriesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.SeriesResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + ingester.v1.BlockHints: + type: object + properties: + ulids: + type: array + items: + type: string + title: ulids + description: The ULID of blocks to query + deduplication: + type: boolean + title: deduplication + description: When all blocks are compacted, there is no effect of the replication factor, hence we do not need to run deduplication. + title: BlockHints + additionalProperties: false + ingester.v1.BlockMetadataRequest: + type: object + properties: + start: + type: + - integer + - string + title: start + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + end: + type: + - integer + - string + title: end + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + title: BlockMetadataRequest + additionalProperties: false + ingester.v1.BlockMetadataResponse: + type: object + properties: + blocks: + type: array + items: + $ref: '#/components/schemas/types.v1.BlockInfo' + title: blocks + description: Blocks that are present on the instance for the start to end period + title: BlockMetadataResponse + additionalProperties: false + ingester.v1.BlockStats: + type: object + properties: + seriesCount: + type: + - integer + - string + title: series_count + format: int64 + profileCount: + type: + - integer + - string + title: profile_count + format: int64 + sampleCount: + type: + - integer + - string + title: sample_count + format: int64 + indexBytes: + type: + - integer + - string + title: index_bytes + format: int64 + profileBytes: + type: + - integer + - string + title: profile_bytes + format: int64 + symbolBytes: + type: + - integer + - string + title: symbol_bytes + format: int64 + title: BlockStats + additionalProperties: false + ingester.v1.FlushRequest: + type: object + title: FlushRequest + additionalProperties: false + ingester.v1.FlushResponse: + type: object + title: FlushResponse + additionalProperties: false + ingester.v1.GetBlockStatsRequest: + type: object + properties: + ulids: + type: array + items: + type: string + title: ulids + title: GetBlockStatsRequest + additionalProperties: false + ingester.v1.GetBlockStatsResponse: + type: object + properties: + blockStats: + type: array + items: + $ref: '#/components/schemas/ingester.v1.BlockStats' + title: block_stats + title: GetBlockStatsResponse + additionalProperties: false + ingester.v1.Hints: + type: object + properties: + block: + title: block + $ref: '#/components/schemas/ingester.v1.BlockHints' + title: Hints + additionalProperties: false + description: Hints are used to propagate information about querying + ingester.v1.MergeProfilesLabelsRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectProfilesRequest' + by: + type: array + items: + type: string + title: by + description: The labels to merge by + stackTraceSelector: + title: stack_trace_selector + description: Select stack traces that match the provided selector. + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeProfilesLabelsRequest + additionalProperties: false + ingester.v1.MergeProfilesLabelsResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + series: + type: array + items: + $ref: '#/components/schemas/types.v1.Series' + title: series + description: The list of series for the profile with their respective value + title: MergeProfilesLabelsResponse + additionalProperties: false + ingester.v1.MergeProfilesPprofRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectProfilesRequest' + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes in the resulting profile. + nullable: true + stackTraceSelector: + title: stack_trace_selector + description: Select stack traces that match the provided selector. + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeProfilesPprofRequest + additionalProperties: false + ingester.v1.MergeProfilesPprofResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + result: + type: string + title: result + format: byte + description: The merge result in the pprof format. + title: MergeProfilesPprofResponse + additionalProperties: false + ingester.v1.MergeProfilesStacktracesRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectProfilesRequest' + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes in the resulting tree. + nullable: true + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeProfilesStacktracesRequest + additionalProperties: false + ingester.v1.MergeProfilesStacktracesResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + result: + title: result + description: The list of stracktraces for the profile with their respective value + $ref: '#/components/schemas/ingester.v1.MergeProfilesStacktracesResult' + title: MergeProfilesStacktracesResponse + additionalProperties: false + ingester.v1.MergeProfilesStacktracesResult: + type: object + properties: + format: + title: format + $ref: '#/components/schemas/ingester.v1.StacktracesMergeFormat' + stacktraces: + type: array + items: + $ref: '#/components/schemas/ingester.v1.StacktraceSample' + title: stacktraces + description: The list of stracktraces with their respective value + functionNames: + type: array + items: + type: string + title: function_names + treeBytes: + type: string + title: tree_bytes + format: byte + description: Merge result marshaled to pyroscope tree bytes. + title: MergeProfilesStacktracesResult + additionalProperties: false + ingester.v1.MergeSpanProfileRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectSpanProfileRequest' + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes in the resulting tree. + nullable: true + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeSpanProfileRequest + additionalProperties: false + ingester.v1.MergeSpanProfileResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + result: + title: result + description: The list of stracktraces for the profile with their respective value + $ref: '#/components/schemas/ingester.v1.MergeSpanProfileResult' + title: MergeSpanProfileResponse + additionalProperties: false + ingester.v1.MergeSpanProfileResult: + type: object + properties: + treeBytes: + type: string + title: tree_bytes + format: byte + title: MergeSpanProfileResult + additionalProperties: false + ingester.v1.ProfileSets: + type: object + properties: + labelsSets: + type: array + items: + $ref: '#/components/schemas/types.v1.Labels' + title: labelsSets + description: 'DEPRECATED: Use fingerprints instead.' + profiles: + type: array + items: + $ref: '#/components/schemas/ingester.v1.SeriesProfile' + title: profiles + fingerprints: + type: array + items: + type: + - integer + - string + format: int64 + title: fingerprints + title: ProfileSets + additionalProperties: false + ingester.v1.ProfileTypesRequest: + type: object + properties: + start: + type: + - integer + - string + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + title: end + format: int64 + description: Milliseconds since epoch. + title: ProfileTypesRequest + additionalProperties: false + ingester.v1.ProfileTypesResponse: + type: object + properties: + profileTypes: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileType' + title: profile_types + title: ProfileTypesResponse + additionalProperties: false + ingester.v1.SelectProfilesRequest: + type: object + properties: + labelSelector: + type: string + title: label_selector + type: + title: type + $ref: '#/components/schemas/types.v1.ProfileType' + start: + type: + - integer + - string + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + title: end + format: int64 + description: Milliseconds since epoch. + hints: + title: hints + description: 'Optional: Hints for querying' + nullable: true + $ref: '#/components/schemas/ingester.v1.Hints' + aggregation: + title: aggregation + description: 'Optional: Aggregation' + nullable: true + $ref: '#/components/schemas/types.v1.TimeSeriesAggregationType' + title: SelectProfilesRequest + additionalProperties: false + ingester.v1.SelectSpanProfileRequest: + type: object + properties: + labelSelector: + type: string + title: label_selector + type: + title: type + $ref: '#/components/schemas/types.v1.ProfileType' + start: + type: + - integer + - string + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + title: end + format: int64 + description: Milliseconds since epoch. + spanSelector: + type: array + items: + type: string + title: span_selector + description: List of span identifiers. + hints: + title: hints + description: 'Optional: Hints for querying' + nullable: true + $ref: '#/components/schemas/ingester.v1.Hints' + title: SelectSpanProfileRequest + additionalProperties: false + ingester.v1.SeriesProfile: + type: object + properties: + labelIndex: + type: integer + title: labelIndex + format: int32 + description: The labels index of the series + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: timestamp in milliseconds + title: SeriesProfile + additionalProperties: false + ingester.v1.SeriesRequest: + type: object + properties: + matchers: + type: array + items: + type: string + title: matchers + labelNames: + type: array + items: + type: string + title: label_names + start: + type: + - integer + - string + title: start + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + end: + type: + - integer + - string + title: end + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + title: SeriesRequest + additionalProperties: false + ingester.v1.SeriesResponse: + type: object + properties: + labelsSet: + type: array + items: + $ref: '#/components/schemas/types.v1.Labels' + title: labels_set + title: SeriesResponse + additionalProperties: false + ingester.v1.StacktraceSample: + type: object + properties: + functionIds: + type: array + items: + type: integer + format: int32 + title: function_ids + value: + type: + - integer + - string + title: value + format: int64 + title: StacktraceSample + additionalProperties: false + ingester.v1.StacktracesMergeFormat: + type: string + title: StacktracesMergeFormat + enum: + - MERGE_FORMAT_UNSPECIFIED + - MERGE_FORMAT_STACKTRACES + - MERGE_FORMAT_TREE + push.v1.PushRequest: + type: object + properties: + series: + type: array + items: + $ref: '#/components/schemas/push.v1.RawProfileSeries' + title: series + description: series is a set raw pprof profiles and accompanying labels + title: PushRequest + additionalProperties: false + description: WriteRawRequest writes a pprof profile + push.v1.PushResponse: + type: object + title: PushResponse + additionalProperties: false + push.v1.RawProfileSeries: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: LabelPair is the key value pairs to identify the corresponding profile + samples: + type: array + items: + $ref: '#/components/schemas/push.v1.RawSample' + title: samples + description: samples are the set of profile bytes + annotations: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileAnnotation' + title: annotations + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. + title: RawProfileSeries + additionalProperties: false + description: RawProfileSeries represents the pprof profile and its associated labels + push.v1.RawSample: + type: object + properties: + rawProfile: + type: string + examples: + - PROFILE_BASE64 + title: raw_profile + format: byte + description: raw_profile is the set of bytes of the pprof profile + ID: + type: string + examples: + - 734FD599-6865-419E-9475-932762D8F469 + title: ID + description: UUID of the profile + title: RawSample + additionalProperties: false + description: RawSample is the set of bytes that correspond to a pprof profile + types.v1.BlockCompaction: + type: object + properties: + level: + type: integer + title: level + format: int32 + sources: + type: array + items: + type: string + title: sources + parents: + type: array + items: + type: string + title: parents + title: BlockCompaction + additionalProperties: false + types.v1.BlockInfo: + type: object + properties: + ulid: + type: string + title: ulid + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + compaction: + title: compaction + $ref: '#/components/schemas/types.v1.BlockCompaction' + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + title: BlockInfo + additionalProperties: false + types.v1.Exemplar: + type: object + properties: + timestamp: + type: + - integer + - string + examples: + - "1730000023000" + title: timestamp + format: int64 + description: Milliseconds since epoch when the profile was captured. + profileId: + type: string + examples: + - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + title: profile_id + description: Unique identifier for the profile (UUID). + spanId: + type: string + examples: + - 00f067aa0ba902b7 + title: span_id + description: Span ID if this profile was split by span during ingestion. + value: + type: + - integer + - string + examples: + - "2450000000" + title: value + format: int64 + description: Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: |- + Labels specific to this exemplar (e.g., pod name, node name). When an exemplar + label overlaps with the series label, it is not included here. + traceId: + type: string + examples: + - 4bf92f3577b34da6a3ce929d0e0e4736 + title: trace_id + description: Trace ID associated with the span, encoded as 32 lowercase hexadecimal characters. + title: Exemplar + additionalProperties: false + description: |- + Exemplar represents metadata for an individual profile sample. + Exemplars allow users to drill down from aggregated timeline views + to specific profile instances. + types.v1.GetProfileStatsRequest: + type: object + title: GetProfileStatsRequest + additionalProperties: false + types.v1.GetProfileStatsResponse: + type: object + properties: + dataIngested: + type: boolean + title: data_ingested + description: Whether we received any data at any time in the past. + oldestProfileTime: + type: + - integer + - string + title: oldest_profile_time + format: int64 + description: Milliseconds since epoch. + newestProfileTime: + type: + - integer + - string + title: newest_profile_time + format: int64 + description: Milliseconds since epoch. + title: GetProfileStatsResponse + additionalProperties: false + types.v1.GoPGO: + type: object + properties: + keepLocations: + type: integer + title: keep_locations + description: Specifies the number of leaf locations to keep. + aggregateCallees: + type: boolean + title: aggregate_callees + description: |- + Aggregate callees causes the leaf location line number to be ignored, + thus aggregating all callee samples (but not callers). + title: GoPGO + additionalProperties: false + types.v1.LabelNamesRequest: + type: object + properties: + matchers: + type: array + items: + type: string + title: matchers + description: List of Label selectors + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Query from this point in time, given in Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Query to this point in time, given in Milliseconds since epoch. + title: LabelNamesRequest + additionalProperties: false + types.v1.LabelNamesResponse: + type: object + properties: + names: + type: array + items: + type: string + title: names + title: LabelNamesResponse + additionalProperties: false + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false + types.v1.LabelValuesRequest: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Name of the label + matchers: + type: array + items: + type: string + title: matchers + description: List of Label selectors + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Query from this point in time, given in Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Query to this point in time, given in Milliseconds since epoch. + title: LabelValuesRequest + additionalProperties: false + types.v1.LabelValuesResponse: + type: object + properties: + names: + type: array + items: + type: string + title: names + title: LabelValuesResponse + additionalProperties: false + types.v1.Labels: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: LabelPair is the key value pairs to identify the corresponding profile + title: Labels + additionalProperties: false + types.v1.Location: + type: object + properties: + name: + type: string + title: name + title: Location + additionalProperties: false + types.v1.Point: + type: object + properties: + value: + type: number + title: value + format: double + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Milliseconds unix timestamp + annotations: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileAnnotation' + title: annotations + exemplars: + type: array + items: + $ref: '#/components/schemas/types.v1.Exemplar' + title: exemplars + description: Exemplars are samples of individual profiles that contributed to this aggregated point + title: Point + additionalProperties: false + types.v1.ProfileAnnotation: + type: object + properties: + key: + type: string + title: key + description: Annotation key [hidden] + value: + type: string + title: value + description: Annotation value [hidden] + title: ProfileAnnotation + additionalProperties: false + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. + types.v1.ProfileType: + type: object + properties: + ID: + type: string + title: ID + name: + type: string + title: name + sampleType: + type: string + title: sample_type + sampleUnit: + type: string + title: sample_unit + periodType: + type: string + title: period_type + periodUnit: + type: string + title: period_unit + title: ProfileType + additionalProperties: false + types.v1.Series: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + points: + type: array + items: + $ref: '#/components/schemas/types.v1.Point' + title: points + title: Series + additionalProperties: false + types.v1.StackTraceSelector: + type: object + properties: + callSite: + type: array + items: + $ref: '#/components/schemas/types.v1.Location' + title: call_site + description: |- + Stack trace of the call site. Root at call_site[0]. + Only stack traces having the prefix provided will be selected. + If empty, the filter is ignored. + goPgo: + title: go_pgo + description: |- + Stack trace selector for profiles purposed for Go PGO. + If set, call_site is ignored. + $ref: '#/components/schemas/types.v1.GoPGO' + title: StackTraceSelector + additionalProperties: false + description: StackTraceSelector is used for filtering stack traces by locations. + types.v1.TimeSeriesAggregationType: + type: string + title: TimeSeriesAggregationType + enum: + - TIME_SERIES_AGGREGATION_TYPE_SUM + - TIME_SERIES_AGGREGATION_TYPE_AVERAGE +security: [] diff --git a/api/connect-openapi/gen/metastore/v1/compactor.openapi.yaml b/api/connect-openapi/gen/metastore/v1/compactor.openapi.yaml new file mode 100644 index 0000000000..0fe0399f4a --- /dev/null +++ b/api/connect-openapi/gen/metastore/v1/compactor.openapi.yaml @@ -0,0 +1,504 @@ +openapi: 3.1.0 +info: + title: metastore.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: metastore.v1.CompactionService +paths: + /metastore.v1.CompactionService/PollCompactionJobs: + post: + tags: + - metastore.v1.CompactionService + summary: Used to both retrieve jobs and update the jobs status at the same time. + description: Used to both retrieve jobs and update the jobs status at the same time. + operationId: metastore.v1.CompactionService.PollCompactionJobs + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.PollCompactionJobsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.PollCompactionJobsResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + metastore.v1.BlockList: + type: object + properties: + tenant: + type: string + title: tenant + shard: + type: integer + title: shard + blocks: + type: array + items: + type: string + title: blocks + title: BlockList + additionalProperties: false + metastore.v1.BlockMeta: + type: object + properties: + formatVersion: + type: integer + title: format_version + id: + type: string + title: id + description: |- + Block ID is a unique identifier for the block. + This is the only field that is not included into + the string table. + tenant: + type: integer + title: tenant + format: int32 + description: If empty, datasets belong to distinct tenants. + shard: + type: integer + title: shard + compactionLevel: + type: integer + title: compaction_level + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + createdBy: + type: integer + title: created_by + format: int32 + metadataOffset: + type: + - integer + - string + title: metadata_offset + format: int64 + size: + type: + - integer + - string + title: size + format: int64 + datasets: + type: array + items: + $ref: '#/components/schemas/metastore.v1.Dataset' + title: datasets + stringTable: + type: array + items: + type: string + title: string_table + description: |- + String table contains strings of the block. + By convention, the first string is always an empty string. + title: BlockMeta + additionalProperties: false + description: |- + BlockMeta is a metadata entry that describes the block's contents. A block + is a collection of datasets that share certain properties, such as shard ID, + compaction level, tenant ID, time range, creation time, and more. + + The block content's format denotes the binary format of the datasets and the + metadata entry (to address logical dependencies). Each dataset has its own + table of contents that lists the sections within the dataset. Each dataset + has its own set of attributes (labels) that describe its specific contents. + metastore.v1.BlockTombstones: + type: object + properties: + name: + type: string + title: name + shard: + type: integer + title: shard + tenant: + type: string + title: tenant + compactionLevel: + type: integer + title: compaction_level + blocks: + type: array + items: + type: string + title: blocks + title: BlockTombstones + additionalProperties: false + metastore.v1.CompactedBlocks: + type: object + properties: + sourceBlocks: + title: source_blocks + $ref: '#/components/schemas/metastore.v1.BlockList' + newBlocks: + type: array + items: + $ref: '#/components/schemas/metastore.v1.BlockMeta' + title: new_blocks + title: CompactedBlocks + additionalProperties: false + metastore.v1.CompactionJob: + type: object + properties: + name: + type: string + title: name + shard: + type: integer + title: shard + tenant: + type: string + title: tenant + compactionLevel: + type: integer + title: compaction_level + sourceBlocks: + type: array + items: + type: string + title: source_blocks + tombstones: + type: array + items: + $ref: '#/components/schemas/metastore.v1.Tombstones' + title: tombstones + title: CompactionJob + additionalProperties: false + metastore.v1.CompactionJobAssignment: + type: object + properties: + name: + type: string + title: name + token: + type: + - integer + - string + title: token + format: int64 + leaseExpiresAt: + type: + - integer + - string + title: lease_expires_at + format: int64 + title: CompactionJobAssignment + additionalProperties: false + metastore.v1.CompactionJobStatus: + type: string + title: CompactionJobStatus + enum: + - COMPACTION_STATUS_UNSPECIFIED + - COMPACTION_STATUS_IN_PROGRESS + - COMPACTION_STATUS_SUCCESS + metastore.v1.CompactionJobStatusUpdate: + type: object + properties: + name: + type: string + title: name + token: + type: + - integer + - string + title: token + format: int64 + status: + title: status + $ref: '#/components/schemas/metastore.v1.CompactionJobStatus' + compactedBlocks: + title: compacted_blocks + description: Only present if the job completed successfully. + $ref: '#/components/schemas/metastore.v1.CompactedBlocks' + title: CompactionJobStatusUpdate + additionalProperties: false + metastore.v1.Dataset: + type: object + properties: + format: + type: integer + title: format + tenant: + type: integer + title: tenant + format: int32 + name: + type: integer + title: name + format: int32 + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + tableOfContents: + type: array + items: + type: + - integer + - string + format: int64 + title: table_of_contents + description: |- + Table of contents lists data sections within the tenant + service region. The offsets are absolute. + + The interpretation of the table of contents is specific + to the format. + + By default (format 0), the sections are: + - 0: profiles.parquet + - 1: index.tsdb + - 2: symbols.symdb + + Format 1 corresponds to the tenant-wide index: + - 0: index.tsdb (dataset index) + size: + type: + - integer + - string + title: size + format: int64 + description: Size of the dataset in bytes. + labels: + type: array + items: + type: integer + format: int32 + title: labels + description: |- + Length prefixed label key-value pairs. + + Multiple label sets can be associated with a dataset to denote relationships + across multiple dimensions. For example, each dataset currently stores data + for multiple profile types: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + + Labels are primarily used to filter datasets based on their attributes. + For instance, labels can be used to select datasets containing a specific + service. + + The set of attributes is extensible and can grow over time. For example, a + namespace attribute could be added to datasets: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + - service_name=B, namespace=N, profile_type=cpu + - service_name=B, namespace=N, profile_type=memory + - service_name=C, namespace=N, profile_type=cpu + - service_name=C, namespace=N, profile_type=memory + + This organization enables querying datasets by namespace without accessing + the block contents, which significantly improves performance. + + Metadata labels are not required to be included in the block's TSDB index + and may be orthogonal to the data dimensions. Generally, attributes serve + two primary purposes: + - To create data scopes that span multiple service, reducing the need to + scan the entire set of block satisfying the query expression, i.e., + the time range and tenant ID. + - To provide additional information about datasets without altering the + storage schema or access methods. + + For example, this approach can support cost attribution or similar breakdown + analyses. It can also handle data dependencies (e.g., links to external data) + using labels. + + The cardinality of the labels is expected to remain relatively low (fewer + than a million unique combinations globally). However, this depends on the + metadata storage system. + + Metadata labels are represented as a slice of `int32` values that refer to + strings in the metadata entry's string table. The slice is a sequence of + length-prefixed key-value (KV) pairs: + + len(2) | k1 | v1 | k2 | v2 | len(3) | k1 | v3 | k2 | v4 | k3 | v5 + + The order of KV pairs is not defined. The format is optimized for indexing + rather than querying, and it is not intended to be the most space-efficient + representation. Since entries are supposed to be indexed, the redundancy of + denormalized relationships is not a concern. + title: Dataset + additionalProperties: false + metastore.v1.PollCompactionJobsRequest: + type: object + properties: + statusUpdates: + type: array + items: + $ref: '#/components/schemas/metastore.v1.CompactionJobStatusUpdate' + title: status_updates + jobCapacity: + type: integer + title: job_capacity + description: How many new jobs a worker can be assigned to. + title: PollCompactionJobsRequest + additionalProperties: false + metastore.v1.PollCompactionJobsResponse: + type: object + properties: + compactionJobs: + type: array + items: + $ref: '#/components/schemas/metastore.v1.CompactionJob' + title: compaction_jobs + assignments: + type: array + items: + $ref: '#/components/schemas/metastore.v1.CompactionJobAssignment' + title: assignments + title: PollCompactionJobsResponse + additionalProperties: false + metastore.v1.ShardTombstone: + type: object + properties: + name: + type: string + title: name + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Lower time boundary. Unix epoch in nanoseconds. + duration: + type: + - integer + - string + title: duration + format: int64 + shard: + type: integer + title: shard + tenant: + type: string + title: tenant + title: ShardTombstone + additionalProperties: false + metastore.v1.Tombstones: + type: object + properties: + blocks: + title: blocks + $ref: '#/components/schemas/metastore.v1.BlockTombstones' + shard: + title: shard + $ref: '#/components/schemas/metastore.v1.ShardTombstone' + title: Tombstones + additionalProperties: false + description: Tombstones represent objects removed from the index but still stored. +security: [] diff --git a/api/connect-openapi/gen/metastore/v1/index.openapi.yaml b/api/connect-openapi/gen/metastore/v1/index.openapi.yaml new file mode 100644 index 0000000000..87402dca5d --- /dev/null +++ b/api/connect-openapi/gen/metastore/v1/index.openapi.yaml @@ -0,0 +1,390 @@ +openapi: 3.1.0 +info: + title: metastore.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: metastore.v1.IndexService +paths: + /metastore.v1.IndexService/AddBlock: + post: + tags: + - metastore.v1.IndexService + summary: AddBlock + operationId: metastore.v1.IndexService.AddBlock + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.AddBlockRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.AddBlockResponse' + /metastore.v1.IndexService/GetBlockMetadata: + post: + tags: + - metastore.v1.IndexService + summary: GetBlockMetadata + operationId: metastore.v1.IndexService.GetBlockMetadata + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.GetBlockMetadataRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.GetBlockMetadataResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + metastore.v1.AddBlockRequest: + type: object + properties: + block: + title: block + $ref: '#/components/schemas/metastore.v1.BlockMeta' + title: AddBlockRequest + additionalProperties: false + metastore.v1.AddBlockResponse: + type: object + title: AddBlockResponse + additionalProperties: false + metastore.v1.BlockList: + type: object + properties: + tenant: + type: string + title: tenant + shard: + type: integer + title: shard + blocks: + type: array + items: + type: string + title: blocks + title: BlockList + additionalProperties: false + metastore.v1.BlockMeta: + type: object + properties: + formatVersion: + type: integer + title: format_version + id: + type: string + title: id + description: |- + Block ID is a unique identifier for the block. + This is the only field that is not included into + the string table. + tenant: + type: integer + title: tenant + format: int32 + description: If empty, datasets belong to distinct tenants. + shard: + type: integer + title: shard + compactionLevel: + type: integer + title: compaction_level + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + createdBy: + type: integer + title: created_by + format: int32 + metadataOffset: + type: + - integer + - string + title: metadata_offset + format: int64 + size: + type: + - integer + - string + title: size + format: int64 + datasets: + type: array + items: + $ref: '#/components/schemas/metastore.v1.Dataset' + title: datasets + stringTable: + type: array + items: + type: string + title: string_table + description: |- + String table contains strings of the block. + By convention, the first string is always an empty string. + title: BlockMeta + additionalProperties: false + description: |- + BlockMeta is a metadata entry that describes the block's contents. A block + is a collection of datasets that share certain properties, such as shard ID, + compaction level, tenant ID, time range, creation time, and more. + + The block content's format denotes the binary format of the datasets and the + metadata entry (to address logical dependencies). Each dataset has its own + table of contents that lists the sections within the dataset. Each dataset + has its own set of attributes (labels) that describe its specific contents. + metastore.v1.Dataset: + type: object + properties: + format: + type: integer + title: format + tenant: + type: integer + title: tenant + format: int32 + name: + type: integer + title: name + format: int32 + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + tableOfContents: + type: array + items: + type: + - integer + - string + format: int64 + title: table_of_contents + description: |- + Table of contents lists data sections within the tenant + service region. The offsets are absolute. + + The interpretation of the table of contents is specific + to the format. + + By default (format 0), the sections are: + - 0: profiles.parquet + - 1: index.tsdb + - 2: symbols.symdb + + Format 1 corresponds to the tenant-wide index: + - 0: index.tsdb (dataset index) + size: + type: + - integer + - string + title: size + format: int64 + description: Size of the dataset in bytes. + labels: + type: array + items: + type: integer + format: int32 + title: labels + description: |- + Length prefixed label key-value pairs. + + Multiple label sets can be associated with a dataset to denote relationships + across multiple dimensions. For example, each dataset currently stores data + for multiple profile types: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + + Labels are primarily used to filter datasets based on their attributes. + For instance, labels can be used to select datasets containing a specific + service. + + The set of attributes is extensible and can grow over time. For example, a + namespace attribute could be added to datasets: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + - service_name=B, namespace=N, profile_type=cpu + - service_name=B, namespace=N, profile_type=memory + - service_name=C, namespace=N, profile_type=cpu + - service_name=C, namespace=N, profile_type=memory + + This organization enables querying datasets by namespace without accessing + the block contents, which significantly improves performance. + + Metadata labels are not required to be included in the block's TSDB index + and may be orthogonal to the data dimensions. Generally, attributes serve + two primary purposes: + - To create data scopes that span multiple service, reducing the need to + scan the entire set of block satisfying the query expression, i.e., + the time range and tenant ID. + - To provide additional information about datasets without altering the + storage schema or access methods. + + For example, this approach can support cost attribution or similar breakdown + analyses. It can also handle data dependencies (e.g., links to external data) + using labels. + + The cardinality of the labels is expected to remain relatively low (fewer + than a million unique combinations globally). However, this depends on the + metadata storage system. + + Metadata labels are represented as a slice of `int32` values that refer to + strings in the metadata entry's string table. The slice is a sequence of + length-prefixed key-value (KV) pairs: + + len(2) | k1 | v1 | k2 | v2 | len(3) | k1 | v3 | k2 | v4 | k3 | v5 + + The order of KV pairs is not defined. The format is optimized for indexing + rather than querying, and it is not intended to be the most space-efficient + representation. Since entries are supposed to be indexed, the redundancy of + denormalized relationships is not a concern. + title: Dataset + additionalProperties: false + metastore.v1.GetBlockMetadataRequest: + type: object + properties: + blocks: + title: blocks + $ref: '#/components/schemas/metastore.v1.BlockList' + title: GetBlockMetadataRequest + additionalProperties: false + metastore.v1.GetBlockMetadataResponse: + type: object + properties: + blocks: + type: array + items: + $ref: '#/components/schemas/metastore.v1.BlockMeta' + title: blocks + title: GetBlockMetadataResponse + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/metastore/v1/query.openapi.yaml b/api/connect-openapi/gen/metastore/v1/query.openapi.yaml new file mode 100644 index 0000000000..b7b64b79a9 --- /dev/null +++ b/api/connect-openapi/gen/metastore/v1/query.openapi.yaml @@ -0,0 +1,452 @@ +openapi: 3.1.0 +info: + title: metastore.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: metastore.v1.MetadataQueryService +paths: + /metastore.v1.MetadataQueryService/QueryMetadata: + post: + tags: + - metastore.v1.MetadataQueryService + summary: QueryMetadata + operationId: metastore.v1.MetadataQueryService.QueryMetadata + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.QueryMetadataRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.QueryMetadataResponse' + /metastore.v1.MetadataQueryService/QueryMetadataLabels: + post: + tags: + - metastore.v1.MetadataQueryService + summary: QueryMetadataLabels + operationId: metastore.v1.MetadataQueryService.QueryMetadataLabels + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.QueryMetadataLabelsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.QueryMetadataLabelsResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + metastore.v1.BlockMeta: + type: object + properties: + formatVersion: + type: integer + title: format_version + id: + type: string + title: id + description: |- + Block ID is a unique identifier for the block. + This is the only field that is not included into + the string table. + tenant: + type: integer + title: tenant + format: int32 + description: If empty, datasets belong to distinct tenants. + shard: + type: integer + title: shard + compactionLevel: + type: integer + title: compaction_level + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + createdBy: + type: integer + title: created_by + format: int32 + metadataOffset: + type: + - integer + - string + title: metadata_offset + format: int64 + size: + type: + - integer + - string + title: size + format: int64 + datasets: + type: array + items: + $ref: '#/components/schemas/metastore.v1.Dataset' + title: datasets + stringTable: + type: array + items: + type: string + title: string_table + description: |- + String table contains strings of the block. + By convention, the first string is always an empty string. + title: BlockMeta + additionalProperties: false + description: |- + BlockMeta is a metadata entry that describes the block's contents. A block + is a collection of datasets that share certain properties, such as shard ID, + compaction level, tenant ID, time range, creation time, and more. + + The block content's format denotes the binary format of the datasets and the + metadata entry (to address logical dependencies). Each dataset has its own + table of contents that lists the sections within the dataset. Each dataset + has its own set of attributes (labels) that describe its specific contents. + metastore.v1.Dataset: + type: object + properties: + format: + type: integer + title: format + tenant: + type: integer + title: tenant + format: int32 + name: + type: integer + title: name + format: int32 + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + tableOfContents: + type: array + items: + type: + - integer + - string + format: int64 + title: table_of_contents + description: |- + Table of contents lists data sections within the tenant + service region. The offsets are absolute. + + The interpretation of the table of contents is specific + to the format. + + By default (format 0), the sections are: + - 0: profiles.parquet + - 1: index.tsdb + - 2: symbols.symdb + + Format 1 corresponds to the tenant-wide index: + - 0: index.tsdb (dataset index) + size: + type: + - integer + - string + title: size + format: int64 + description: Size of the dataset in bytes. + labels: + type: array + items: + type: integer + format: int32 + title: labels + description: |- + Length prefixed label key-value pairs. + + Multiple label sets can be associated with a dataset to denote relationships + across multiple dimensions. For example, each dataset currently stores data + for multiple profile types: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + + Labels are primarily used to filter datasets based on their attributes. + For instance, labels can be used to select datasets containing a specific + service. + + The set of attributes is extensible and can grow over time. For example, a + namespace attribute could be added to datasets: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + - service_name=B, namespace=N, profile_type=cpu + - service_name=B, namespace=N, profile_type=memory + - service_name=C, namespace=N, profile_type=cpu + - service_name=C, namespace=N, profile_type=memory + + This organization enables querying datasets by namespace without accessing + the block contents, which significantly improves performance. + + Metadata labels are not required to be included in the block's TSDB index + and may be orthogonal to the data dimensions. Generally, attributes serve + two primary purposes: + - To create data scopes that span multiple service, reducing the need to + scan the entire set of block satisfying the query expression, i.e., + the time range and tenant ID. + - To provide additional information about datasets without altering the + storage schema or access methods. + + For example, this approach can support cost attribution or similar breakdown + analyses. It can also handle data dependencies (e.g., links to external data) + using labels. + + The cardinality of the labels is expected to remain relatively low (fewer + than a million unique combinations globally). However, this depends on the + metadata storage system. + + Metadata labels are represented as a slice of `int32` values that refer to + strings in the metadata entry's string table. The slice is a sequence of + length-prefixed key-value (KV) pairs: + + len(2) | k1 | v1 | k2 | v2 | len(3) | k1 | v3 | k2 | v4 | k3 | v5 + + The order of KV pairs is not defined. The format is optimized for indexing + rather than querying, and it is not intended to be the most space-efficient + representation. Since entries are supposed to be indexed, the redundancy of + denormalized relationships is not a concern. + title: Dataset + additionalProperties: false + metastore.v1.QueryMetadataLabelsRequest: + type: object + properties: + tenantId: + type: array + items: + type: string + title: tenant_id + startTime: + type: + - integer + - string + title: start_time + format: int64 + endTime: + type: + - integer + - string + title: end_time + format: int64 + query: + type: string + title: query + labels: + type: array + items: + type: string + title: labels + title: QueryMetadataLabelsRequest + additionalProperties: false + metastore.v1.QueryMetadataLabelsResponse: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.Labels' + title: labels + title: QueryMetadataLabelsResponse + additionalProperties: false + metastore.v1.QueryMetadataRequest: + type: object + properties: + tenantId: + type: array + items: + type: string + title: tenant_id + startTime: + type: + - integer + - string + title: start_time + format: int64 + endTime: + type: + - integer + - string + title: end_time + format: int64 + query: + type: string + title: query + labels: + type: array + items: + type: string + title: labels + title: QueryMetadataRequest + additionalProperties: false + metastore.v1.QueryMetadataResponse: + type: object + properties: + blocks: + type: array + items: + $ref: '#/components/schemas/metastore.v1.BlockMeta' + title: blocks + title: QueryMetadataResponse + additionalProperties: false + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false + types.v1.Labels: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: LabelPair is the key value pairs to identify the corresponding profile + title: Labels + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/metastore/v1/raft_log/raft_log.openapi.yaml b/api/connect-openapi/gen/metastore/v1/raft_log/raft_log.openapi.yaml new file mode 100644 index 0000000000..9086b31727 --- /dev/null +++ b/api/connect-openapi/gen/metastore/v1/raft_log/raft_log.openapi.yaml @@ -0,0 +1,12 @@ +openapi: 3.1.0 +info: + title: raft_log + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. +paths: {} +components: {} +security: [] diff --git a/api/connect-openapi/gen/metastore/v1/tenant.openapi.yaml b/api/connect-openapi/gen/metastore/v1/tenant.openapi.yaml new file mode 100644 index 0000000000..8ca1edf735 --- /dev/null +++ b/api/connect-openapi/gen/metastore/v1/tenant.openapi.yaml @@ -0,0 +1,253 @@ +openapi: 3.1.0 +info: + title: metastore.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: metastore.v1.TenantService +paths: + /metastore.v1.TenantService/DeleteTenant: + post: + tags: + - metastore.v1.TenantService + summary: DeleteTenant + operationId: metastore.v1.TenantService.DeleteTenant + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.DeleteTenantRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.DeleteTenantResponse' + /metastore.v1.TenantService/GetTenant: + post: + tags: + - metastore.v1.TenantService + summary: GetTenant + operationId: metastore.v1.TenantService.GetTenant + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.GetTenantRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.GetTenantResponse' + /metastore.v1.TenantService/GetTenants: + post: + tags: + - metastore.v1.TenantService + summary: GetTenants + operationId: metastore.v1.TenantService.GetTenants + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.GetTenantsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/metastore.v1.GetTenantsResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + metastore.v1.DeleteTenantRequest: + type: object + properties: + tenantId: + type: string + title: tenant_id + title: DeleteTenantRequest + additionalProperties: false + metastore.v1.DeleteTenantResponse: + type: object + title: DeleteTenantResponse + additionalProperties: false + metastore.v1.GetTenantRequest: + type: object + properties: + tenantId: + type: string + title: tenant_id + title: GetTenantRequest + additionalProperties: false + metastore.v1.GetTenantResponse: + type: object + properties: + stats: + title: stats + $ref: '#/components/schemas/metastore.v1.TenantStats' + title: GetTenantResponse + additionalProperties: false + metastore.v1.GetTenantsRequest: + type: object + title: GetTenantsRequest + additionalProperties: false + metastore.v1.GetTenantsResponse: + type: object + properties: + tenantIds: + type: array + items: + type: string + title: tenant_ids + title: GetTenantsResponse + additionalProperties: false + metastore.v1.TenantStats: + type: object + properties: + dataIngested: + type: boolean + title: data_ingested + description: Whether we received any data at any time in the past. + oldestProfileTime: + type: + - integer + - string + title: oldest_profile_time + format: int64 + description: Milliseconds since epoch. + newestProfileTime: + type: + - integer + - string + title: newest_profile_time + format: int64 + description: Milliseconds since epoch. + title: TenantStats + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/metastore/v1/types.openapi.yaml b/api/connect-openapi/gen/metastore/v1/types.openapi.yaml new file mode 100644 index 0000000000..91829b2899 --- /dev/null +++ b/api/connect-openapi/gen/metastore/v1/types.openapi.yaml @@ -0,0 +1,12 @@ +openapi: 3.1.0 +info: + title: metastore.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. +paths: {} +components: {} +security: [] diff --git a/api/connect-openapi/gen/push/v1/push.openapi.yaml b/api/connect-openapi/gen/push/v1/push.openapi.yaml new file mode 100644 index 0000000000..7a8904ec76 --- /dev/null +++ b/api/connect-openapi/gen/push/v1/push.openapi.yaml @@ -0,0 +1,225 @@ +openapi: 3.1.0 +info: + title: push.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: push.v1.PusherService +paths: + /push.v1.PusherService/Push: + post: + tags: + - scope/public + - push.v1.PusherService + summary: Push + operationId: push.v1.PusherService.Push + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/push.v1.PushRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/push.v1.PushResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + push.v1.PushRequest: + type: object + properties: + series: + type: array + items: + $ref: '#/components/schemas/push.v1.RawProfileSeries' + title: series + description: series is a set raw pprof profiles and accompanying labels + title: PushRequest + additionalProperties: false + description: WriteRawRequest writes a pprof profile + push.v1.PushResponse: + type: object + title: PushResponse + additionalProperties: false + push.v1.RawProfileSeries: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: LabelPair is the key value pairs to identify the corresponding profile + samples: + type: array + items: + $ref: '#/components/schemas/push.v1.RawSample' + title: samples + description: samples are the set of profile bytes + annotations: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileAnnotation' + title: annotations + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. + title: RawProfileSeries + additionalProperties: false + description: RawProfileSeries represents the pprof profile and its associated labels + push.v1.RawSample: + type: object + properties: + rawProfile: + type: string + examples: + - PROFILE_BASE64 + title: raw_profile + format: byte + description: raw_profile is the set of bytes of the pprof profile + ID: + type: string + examples: + - 734FD599-6865-419E-9475-932762D8F469 + title: ID + description: UUID of the profile + title: RawSample + additionalProperties: false + description: RawSample is the set of bytes that correspond to a pprof profile + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false + types.v1.ProfileAnnotation: + type: object + properties: + key: + type: string + title: key + description: Annotation key [hidden] + value: + type: string + title: value + description: Annotation value [hidden] + title: ProfileAnnotation + additionalProperties: false + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. +security: [] diff --git a/api/connect-openapi/gen/querier/v1/querier.openapi.yaml b/api/connect-openapi/gen/querier/v1/querier.openapi.yaml new file mode 100644 index 0000000000..ce7e97669d --- /dev/null +++ b/api/connect-openapi/gen/querier/v1/querier.openapi.yaml @@ -0,0 +1,2144 @@ +openapi: 3.1.0 +info: + title: querier.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: querier.v1.QuerierService +paths: + /querier.v1.QuerierService/AnalyzeQuery: + post: + tags: + - scope/internal + - querier.v1.QuerierService + summary: AnalyzeQuery + operationId: querier.v1.QuerierService.AnalyzeQuery + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.AnalyzeQueryRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.AnalyzeQueryResponse' + /querier.v1.QuerierService/Diff: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: Diff returns a diff of two profiles + description: Diff returns a diff of two profiles + operationId: querier.v1.QuerierService.Diff + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.DiffRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.DiffResponse' + /querier.v1.QuerierService/GetProfileStats: + post: + tags: + - scope/internal + - querier.v1.QuerierService + summary: GetProfileStats returns profile stats for the current tenant. + description: GetProfileStats returns profile stats for the current tenant. + operationId: querier.v1.QuerierService.GetProfileStats + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.GetProfileStatsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.GetProfileStatsResponse' + /querier.v1.QuerierService/LabelNames: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: LabelNames returns a list of the existing label names. + description: LabelNames returns a list of the existing label names. + operationId: querier.v1.QuerierService.LabelNames + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelNamesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelNamesResponse' + /querier.v1.QuerierService/LabelValues: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: LabelValues returns the existing label values for the provided label names. + description: LabelValues returns the existing label values for the provided label names. + operationId: querier.v1.QuerierService.LabelValues + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelValuesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelValuesResponse' + /querier.v1.QuerierService/ProfileTypes: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: ProfileType returns a list of the existing profile types. + description: ProfileType returns a list of the existing profile types. + operationId: querier.v1.QuerierService.ProfileTypes + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.ProfileTypesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.ProfileTypesResponse' + /querier.v1.QuerierService/SelectHeatmap: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: 'SelectHeatmap returns a heatmap visualization for the requested profiles. Note: This endpoint is only available in the v2 storage layer' + description: |- + SelectHeatmap returns a heatmap visualization for the requested profiles. + Note: This endpoint is only available in the v2 storage layer + operationId: querier.v1.QuerierService.SelectHeatmap + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectHeatmapRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectHeatmapResponse' + /querier.v1.QuerierService/SelectMergeProfile: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: 'Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. This RPC will remain supported in querier.v1 for backward compatibility; future breaking API changes may be introduced in querier.v2. SelectMergeProfile returns matching profiles aggregated in pprof format. It will contain all information stored (so including filenames and line number, if ingested).' + description: |- + Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. + This RPC will remain supported in querier.v1 for backward compatibility; + future breaking API changes may be introduced in querier.v2. + SelectMergeProfile returns matching profiles aggregated in pprof format. It + will contain all information stored (so including filenames and line + number, if ingested). + operationId: querier.v1.QuerierService.SelectMergeProfile + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectMergeProfileRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/google.v1.Profile' + /querier.v1.QuerierService/SelectMergeSpanProfile: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: 'Deprecated: Use SelectMergeStacktraces with span_selector instead. This RPC will remain supported in querier.v1 for backward compatibility; future breaking API changes may be introduced in querier.v2. SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name.' + description: |- + Deprecated: Use SelectMergeStacktraces with span_selector instead. + This RPC will remain supported in querier.v1 for backward compatibility; + future breaking API changes may be introduced in querier.v2. + SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph + format. It will combine samples from within the same callstack, with each + element being grouped by its function name. + operationId: querier.v1.QuerierService.SelectMergeSpanProfile + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectMergeSpanProfileRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectMergeSpanProfileResponse' + /querier.v1.QuerierService/SelectMergeStacktraces: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: SelectMergeStacktraces returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + description: |- + SelectMergeStacktraces returns matching profiles aggregated in a flamegraph + format. It will combine samples from within the same callstack, with each + element being grouped by its function name. + operationId: querier.v1.QuerierService.SelectMergeStacktraces + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectMergeStacktracesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectMergeStacktracesResponse' + /querier.v1.QuerierService/SelectSeries: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: SelectSeries returns a time series for the total sum of the requested profiles. + description: |- + SelectSeries returns a time series for the total sum of the requested + profiles. + operationId: querier.v1.QuerierService.SelectSeries + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectSeriesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SelectSeriesResponse' + /querier.v1.QuerierService/Series: + post: + tags: + - scope/public + - querier.v1.QuerierService + summary: Series returns profiles series matching the request. A series is a unique label set. + description: |- + Series returns profiles series matching the request. A series is a unique + label set. + operationId: querier.v1.QuerierService.Series + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SeriesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/querier.v1.SeriesResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + google.v1.Function: + type: object + properties: + id: + type: + - integer + - string + title: id + format: int64 + description: Unique nonzero id for the function. + name: + type: + - integer + - string + title: name + format: int64 + description: Name of the function, in human-readable form if available. Index into string table + systemName: + type: + - integer + - string + title: system_name + format: int64 + description: |- + Name of the function, as identified by the system. + For instance, it can be a C++ mangled name. Index into string table + filename: + type: + - integer + - string + title: filename + format: int64 + description: Source file containing the function. Index into string table + startLine: + type: + - integer + - string + title: start_line + format: int64 + description: Line number in source file. + title: Function + additionalProperties: false + google.v1.Label: + type: object + properties: + key: + type: + - integer + - string + title: key + format: int64 + description: Index into string table + str: + type: + - integer + - string + title: str + format: int64 + description: At most one of the following must be present Index into string table + num: + type: + - integer + - string + title: num + format: int64 + numUnit: + type: + - integer + - string + title: num_unit + format: int64 + description: |- + Should only be present when num is present. + Specifies the units of num. + Use arbitrary string (for example, "requests") as a custom count unit. + If no unit is specified, consumer may apply heuristic to deduce the unit. + Consumers may also interpret units like "bytes" and "kilobytes" as memory + units and units like "seconds" and "nanoseconds" as time units, + and apply appropriate unit conversions to these. Index into string table + title: Label + additionalProperties: false + google.v1.Line: + type: object + properties: + functionId: + type: + - integer + - string + title: function_id + format: int64 + description: The id of the corresponding profile.Function for this line. + line: + type: + - integer + - string + title: line + format: int64 + description: Line number in source code. + title: Line + additionalProperties: false + google.v1.Location: + type: object + properties: + id: + type: + - integer + - string + title: id + format: int64 + description: |- + Unique nonzero id for the location. A profile could use + instruction addresses or any integer sequence as ids. + mappingId: + type: + - integer + - string + title: mapping_id + format: int64 + description: |- + The id of the corresponding profile.Mapping for this location. + It can be unset if the mapping is unknown or not applicable for + this profile type. + address: + type: + - integer + - string + title: address + format: int64 + description: |- + The instruction address for this location, if available. It + should be within [Mapping.memory_start...Mapping.memory_limit] + for the corresponding mapping. A non-leaf address may be in the + middle of a call instruction. It is up to display tools to find + the beginning of the instruction if necessary. + line: + type: array + items: + $ref: '#/components/schemas/google.v1.Line' + title: line + description: |- + Multiple line indicates this location has inlined functions, + where the last entry represents the caller into which the + preceding entries were inlined. + + E.g., if memcpy() is inlined into printf: + line[0].function_name == "memcpy" + line[1].function_name == "printf" + isFolded: + type: boolean + title: is_folded + description: |- + Provides an indication that multiple symbols map to this location's + address, for example due to identical code folding by the linker. In that + case the line information above represents one of the multiple + symbols. This field must be recomputed when the symbolization state of the + profile changes. + title: Location + additionalProperties: false + description: Describes function and line table debug information. + google.v1.Mapping: + type: object + properties: + id: + type: + - integer + - string + title: id + format: int64 + description: Unique nonzero id for the mapping. + memoryStart: + type: + - integer + - string + title: memory_start + format: int64 + description: Address at which the binary (or DLL) is loaded into memory. + memoryLimit: + type: + - integer + - string + title: memory_limit + format: int64 + description: The limit of the address range occupied by this mapping. + fileOffset: + type: + - integer + - string + title: file_offset + format: int64 + description: Offset in the binary that corresponds to the first mapped address. + filename: + type: + - integer + - string + title: filename + format: int64 + description: |- + The object this entry is loaded from. This can be a filename on + disk for the main binary and shared libraries, or virtual + abstractions like "[vdso]". Index into string table + buildId: + type: + - integer + - string + title: build_id + format: int64 + description: |- + A string that uniquely identifies a particular program version + with high probability. E.g., for binaries generated by GNU tools, + it could be the contents of the .note.gnu.build-id field. Index into string table + hasFunctions: + type: boolean + title: has_functions + description: The following fields indicate the resolution of symbolic info. + hasFilenames: + type: boolean + title: has_filenames + hasLineNumbers: + type: boolean + title: has_line_numbers + hasInlineFrames: + type: boolean + title: has_inline_frames + title: Mapping + additionalProperties: false + google.v1.Profile: + type: object + properties: + sampleType: + type: array + items: + $ref: '#/components/schemas/google.v1.ValueType' + title: sample_type + description: |- + A description of the samples associated with each Sample.value. + For a cpu profile this might be: + [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]] + For a heap profile, this might be: + [["allocations","count"], ["space","bytes"]], + If one of the values represents the number of events represented + by the sample, by convention it should be at index 0 and use + sample_type.unit == "count". + sample: + type: array + items: + $ref: '#/components/schemas/google.v1.Sample' + title: sample + description: The set of samples recorded in this profile. + mapping: + type: array + items: + $ref: '#/components/schemas/google.v1.Mapping' + title: mapping + description: |- + Mapping from address ranges to the image/binary/library mapped + into that address range. mapping[0] will be the main binary. + location: + type: array + items: + $ref: '#/components/schemas/google.v1.Location' + title: location + description: Useful program location + function: + type: array + items: + $ref: '#/components/schemas/google.v1.Function' + title: function + description: Functions referenced by locations + stringTable: + type: array + items: + type: string + title: string_table + description: |- + A common table for strings referenced by various messages. + string_table[0] must always be "". + dropFrames: + type: + - integer + - string + title: drop_frames + format: int64 + description: |- + frames with Function.function_name fully matching the following + regexp will be dropped from the samples, along with their successors. Index into string table. + keepFrames: + type: + - integer + - string + title: keep_frames + format: int64 + description: |- + frames with Function.function_name fully matching the following + regexp will be kept, even if it matches drop_frames. Index into string table. + timeNanos: + type: + - integer + - string + title: time_nanos + format: int64 + description: Time of collection (UTC) represented as nanoseconds past the epoch. + durationNanos: + type: + - integer + - string + title: duration_nanos + format: int64 + description: Duration of the profile, if a duration makes sense. + periodType: + title: period_type + description: |- + The kind of events between sampled ocurrences. + e.g [ "cpu","cycles" ] or [ "heap","bytes" ] + $ref: '#/components/schemas/google.v1.ValueType' + period: + type: + - integer + - string + title: period + format: int64 + description: The number of events between sampled occurrences. + comment: + type: array + items: + type: + - integer + - string + format: int64 + title: comment + description: Freeform text associated to the profile. Indices into string table. + defaultSampleType: + type: + - integer + - string + title: default_sample_type + format: int64 + description: |- + Index into the string table of the type of the preferred sample + value. If unset, clients should default to the last sample value. + title: Profile + additionalProperties: false + google.v1.Sample: + type: object + properties: + locationId: + type: array + items: + type: + - integer + - string + format: int64 + title: location_id + description: |- + The ids recorded here correspond to a Profile.location.id. + The leaf is at location_id[0]. + value: + type: array + items: + type: + - integer + - string + format: int64 + title: value + description: |- + The type and unit of each value is defined by the corresponding + entry in Profile.sample_type. All samples must have the same + number of values, the same as the length of Profile.sample_type. + When aggregating multiple samples into a single sample, the + result has a list of values that is the element-wise sum of the + lists of the originals. + label: + type: array + items: + $ref: '#/components/schemas/google.v1.Label' + title: label + description: |- + label includes additional context for this sample. It can include + things like a thread id, allocation size, etc + title: Sample + additionalProperties: false + description: |- + Each Sample records values encountered in some program + context. The program context is typically a stack trace, perhaps + augmented with auxiliary information like the thread-id, some + indicator of a higher level request being handled etc. + google.v1.ValueType: + type: object + properties: + type: + type: + - integer + - string + title: type + format: int64 + description: Index into string table. + unit: + type: + - integer + - string + title: unit + format: int64 + description: Index into string table. + title: ValueType + additionalProperties: false + description: ValueType describes the semantics and measurement units of a value. + querier.v1.AnalyzeQueryRequest: + type: object + properties: + start: + type: + - integer + - string + title: start + format: int64 + end: + type: + - integer + - string + title: end + format: int64 + query: + type: string + title: query + title: AnalyzeQueryRequest + additionalProperties: false + querier.v1.AnalyzeQueryResponse: + type: object + properties: + queryScopes: + type: array + items: + $ref: '#/components/schemas/querier.v1.QueryScope' + title: query_scopes + description: detailed view of what the query will require + queryImpact: + title: query_impact + description: summary of the query impact / performance + $ref: '#/components/schemas/querier.v1.QueryImpact' + title: AnalyzeQueryResponse + additionalProperties: false + querier.v1.AsyncQueryRequest: + type: object + properties: + requestId: + type: string + title: request_id + description: If set, this is a polling request. + type: + title: type + description: Sets the kind of async query. + $ref: '#/components/schemas/querier.v1.AsyncQueryType' + title: AsyncQueryRequest + additionalProperties: false + querier.v1.AsyncQueryResponse: + type: object + properties: + requestId: + type: string + title: request_id + description: Id of the async query. + status: + title: status + description: 'Status of the query: unknown, in_progress, success, failed' + $ref: '#/components/schemas/querier.v1.AsyncQueryStatus' + errorMessage: + type: string + title: error_message + description: Populated on FAILURE. + title: AsyncQueryResponse + additionalProperties: false + querier.v1.AsyncQueryStatus: + type: string + title: AsyncQueryStatus + enum: + - ASYNC_QUERY_STATUS_UNKNOWN + - ASYNC_QUERY_STATUS_IN_PROGRESS + - ASYNC_QUERY_STATUS_SUCCESS + - ASYNC_QUERY_STATUS_FAILURE + querier.v1.AsyncQueryType: + type: string + title: AsyncQueryType + enum: + - ASYNC_QUERY_TYPE_DISABLED + - ASYNC_QUERY_TYPE_FORCE + querier.v1.DiffRequest: + type: object + properties: + left: + title: left + description: The format of each request is ignored; diff queries always compare trees. + $ref: '#/components/schemas/querier.v1.SelectMergeStacktracesRequest' + right: + title: right + $ref: '#/components/schemas/querier.v1.SelectMergeStacktracesRequest' + title: DiffRequest + additionalProperties: false + querier.v1.DiffResponse: + type: object + properties: + flamegraph: + title: flamegraph + $ref: '#/components/schemas/querier.v1.FlameGraphDiff' + title: DiffResponse + additionalProperties: false + querier.v1.FlameGraph: + type: object + properties: + names: + type: array + items: + type: string + title: names + levels: + type: array + items: + $ref: '#/components/schemas/querier.v1.Level' + title: levels + total: + type: + - integer + - string + title: total + format: int64 + maxSelf: + type: + - integer + - string + title: max_self + format: int64 + title: FlameGraph + additionalProperties: false + querier.v1.FlameGraphDiff: + type: object + properties: + names: + type: array + items: + type: string + title: names + levels: + type: array + items: + $ref: '#/components/schemas/querier.v1.Level' + title: levels + total: + type: + - integer + - string + title: total + format: int64 + maxSelf: + type: + - integer + - string + title: max_self + format: int64 + leftTicks: + type: + - integer + - string + title: leftTicks + format: int64 + rightTicks: + type: + - integer + - string + title: rightTicks + format: int64 + title: FlameGraphDiff + additionalProperties: false + querier.v1.HeatmapQueryType: + type: string + title: HeatmapQueryType + enum: + - HEATMAP_QUERY_TYPE_UNSPECIFIED + - HEATMAP_QUERY_TYPE_INDIVIDUAL + - HEATMAP_QUERY_TYPE_SPAN + querier.v1.Level: + type: object + properties: + values: + type: array + items: + type: + - integer + - string + format: int64 + title: values + title: Level + additionalProperties: false + querier.v1.PprofProfile: + type: object + properties: + profile: + title: profile + $ref: '#/components/schemas/google.v1.Profile' + title: PprofProfile + additionalProperties: false + description: PprofProfile contains pprof output and related response metadata. + querier.v1.ProfileFormat: + type: string + title: ProfileFormat + enum: + - PROFILE_FORMAT_UNSPECIFIED + - PROFILE_FORMAT_FLAMEGRAPH + - PROFILE_FORMAT_TREE + - PROFILE_FORMAT_DOT + - PROFILE_FORMAT_PPROF + querier.v1.ProfileTypesRequest: + type: object + properties: + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + title: ProfileTypesRequest + additionalProperties: false + querier.v1.ProfileTypesResponse: + type: object + properties: + profileTypes: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileType' + title: profile_types + title: ProfileTypesResponse + additionalProperties: false + querier.v1.QueryImpact: + type: object + properties: + totalBytesInTimeRange: + type: + - integer + - string + title: total_bytes_in_time_range + format: int64 + totalQueriedSeries: + type: + - integer + - string + title: total_queried_series + format: int64 + deduplicationNeeded: + type: boolean + title: deduplication_needed + title: QueryImpact + additionalProperties: false + querier.v1.QueryScope: + type: object + properties: + componentType: + type: string + title: component_type + description: a descriptive high level name of the component processing one part + componentCount: + type: + - integer + - string + title: component_count + format: int64 + description: of the query (e.g., "short term storage") how many components of this type will process + blockCount: + type: + - integer + - string + title: block_count + format: int64 + seriesCount: + type: + - integer + - string + title: series_count + format: int64 + profileCount: + type: + - integer + - string + title: profile_count + format: int64 + sampleCount: + type: + - integer + - string + title: sample_count + format: int64 + indexBytes: + type: + - integer + - string + title: index_bytes + format: int64 + profileBytes: + type: + - integer + - string + title: profile_bytes + format: int64 + symbolBytes: + type: + - integer + - string + title: symbol_bytes + format: int64 + title: QueryScope + additionalProperties: false + querier.v1.SelectHeatmapRequest: + type: object + properties: + profileTypeID: + type: string + examples: + - process_cpu:cpu:nanoseconds:cpu:nanoseconds + title: profile_typeID + description: |- + Profile Type ID string in the form + ::::. + labelSelector: + type: string + examples: + - '{namespace="my-namespace"}' + title: label_selector + description: Label selector string + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Milliseconds since epoch. + step: + type: number + title: step + format: double + description: Query resolution step width in seconds + groupBy: + type: array + examples: + - - pod + items: + type: string + examples: + - - pod + title: group_by + description: Group by labels + queryType: + examples: + - HEATMAP_QUERY_TYPE_SPAN + title: query_type + description: 'Query type: individual profiles or span profiles' + $ref: '#/components/schemas/querier.v1.HeatmapQueryType' + exemplarType: + examples: + - EXEMPLAR_TYPE_SPAN + title: exemplar_type + description: Type of exemplars to include in the response. Needs to matching query_type or be NONE + $ref: '#/components/schemas/types.v1.ExemplarType' + limit: + type: + - integer + - string + title: limit + format: int64 + description: Select the top N series by total value. + nullable: true + title: SelectHeatmapRequest + additionalProperties: false + querier.v1.SelectHeatmapResponse: + type: object + properties: + series: + type: array + items: + $ref: '#/components/schemas/types.v1.HeatmapSeries' + title: series + title: SelectHeatmapResponse + additionalProperties: false + querier.v1.SelectMergeProfileRequest: + type: object + properties: + profileTypeID: + type: string + examples: + - process_cpu:cpu:nanoseconds:cpu:nanoseconds + title: profile_typeID + description: |- + Profile Type ID string in the form + ::::. + labelSelector: + type: string + examples: + - '{namespace="my-namespace"}' + title: label_selector + description: Label selector string + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Milliseconds since epoch. + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: |- + Limit the nodes returned to only show the node with the max_node's biggest + total + nullable: true + stackTraceSelector: + title: stack_trace_selector + description: Select stack traces that match the provided selector. + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profileIdSelector: + type: array + examples: + - - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + items: + type: string + examples: + - - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + title: profile_id_selector + description: List of Profile UUIDs to query + traceIdSelector: + type: array + examples: + - - 7c9e66797425440de944be07fc1f90ae + items: + type: string + examples: + - - 7c9e66797425440de944be07fc1f90ae + title: trace_id_selector + description: List of trace IDs (32 hex characters, 128-bit) to filter samples by. + title: SelectMergeProfileRequest + additionalProperties: false + querier.v1.SelectMergeSpanProfileRequest: + type: object + properties: + profileTypeID: + type: string + examples: + - process_cpu:cpu:nanoseconds:cpu:nanoseconds + title: profile_typeID + description: |- + Profile Type ID string in the form + ::::. + labelSelector: + type: string + examples: + - '{namespace="my-namespace"}' + title: label_selector + description: Label selector string + spanSelector: + type: array + examples: + - - 9a517183f26a089d + - 5a4fe264a9c987fe + items: + type: string + examples: + - - 9a517183f26a089d + - 5a4fe264a9c987fe + title: span_selector + description: List of Span IDs to query + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Milliseconds since epoch. + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: |- + Limit the nodes returned to only show the node with the max_node's biggest + total + nullable: true + format: + title: format + description: |- + Profile format specifies the format of profile to be returned. + If not specified, the profile will be returned in flame graph format. + $ref: '#/components/schemas/querier.v1.ProfileFormat' + title: SelectMergeSpanProfileRequest + additionalProperties: false + querier.v1.SelectMergeSpanProfileResponse: + type: object + properties: + flamegraph: + title: flamegraph + $ref: '#/components/schemas/querier.v1.FlameGraph' + tree: + type: string + title: tree + format: byte + description: Pyroscope tree bytes. + title: SelectMergeSpanProfileResponse + additionalProperties: false + querier.v1.SelectMergeStacktracesRequest: + type: object + properties: + profileTypeID: + type: string + examples: + - process_cpu:cpu:nanoseconds:cpu:nanoseconds + title: profile_typeID + description: |- + Profile Type ID string in the form + ::::. + labelSelector: + type: string + examples: + - '{namespace="my-namespace"}' + title: label_selector + description: Label selector string + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Milliseconds since epoch. + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: |- + Limit the nodes returned to only show the node with the max_node's biggest + total + nullable: true + format: + title: format + description: |- + Profile format specifies the format of profile to be returned. + If not specified, the profile will be returned in flame graph format. + $ref: '#/components/schemas/querier.v1.ProfileFormat' + stackTraceSelector: + title: stack_trace_selector + description: Select stack traces that match the provided selector. + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profileIdSelector: + type: array + examples: + - - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + items: + type: string + examples: + - - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + title: profile_id_selector + description: List of Profile UUIDs to query + async: + title: async + description: (experimental) Used for making and polling async queries. + nullable: true + $ref: '#/components/schemas/querier.v1.AsyncQueryRequest' + traceIdSelector: + type: array + examples: + - - 7c9e66797425440de944be07fc1f90ae + items: + type: string + examples: + - - 7c9e66797425440de944be07fc1f90ae + title: trace_id_selector + description: List of trace IDs (32 hex characters, 128-bit) to filter samples by. + spanSelector: + type: array + examples: + - - 9a517183f26a089d + - 5a4fe264a9c987fe + items: + type: string + examples: + - - 9a517183f26a089d + - 5a4fe264a9c987fe + title: span_selector + description: List of span IDs (16 hex characters, 64-bit) to filter samples by. + title: SelectMergeStacktracesRequest + additionalProperties: false + querier.v1.SelectMergeStacktracesResponse: + type: object + properties: + flamegraph: + title: flamegraph + $ref: '#/components/schemas/querier.v1.FlameGraph' + tree: + type: string + title: tree + format: byte + description: Pyroscope tree bytes. + dot: + type: string + title: dot + description: DOT graph representation. + async: + title: async + description: (experimental) Used for responding to async queries. + nullable: true + $ref: '#/components/schemas/querier.v1.AsyncQueryResponse' + pprof: + title: pprof + description: Profile in pprof format. + $ref: '#/components/schemas/querier.v1.PprofProfile' + title: SelectMergeStacktracesResponse + additionalProperties: false + querier.v1.SelectSeriesRequest: + type: object + properties: + profileTypeID: + type: string + examples: + - process_cpu:cpu:nanoseconds:cpu:nanoseconds + title: profile_typeID + description: |- + Profile Type ID string in the form + ::::. + labelSelector: + type: string + examples: + - '{namespace="my-namespace"}' + title: label_selector + description: Label selector string + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Milliseconds since epoch. + groupBy: + type: array + examples: + - - pod + items: + type: string + examples: + - - pod + title: group_by + step: + type: number + title: step + format: double + aggregation: + title: aggregation + description: Query resolution step width in seconds + nullable: true + $ref: '#/components/schemas/types.v1.TimeSeriesAggregationType' + stackTraceSelector: + title: stack_trace_selector + description: Select stack traces that match the provided selector. + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + limit: + type: + - integer + - string + title: limit + format: int64 + description: Select the top N series by total value. + nullable: true + exemplarType: + title: exemplar_type + description: Type of exemplars to include in the response. + $ref: '#/components/schemas/types.v1.ExemplarType' + title: SelectSeriesRequest + additionalProperties: false + querier.v1.SelectSeriesResponse: + type: object + properties: + series: + type: array + items: + $ref: '#/components/schemas/types.v1.Series' + title: series + title: SelectSeriesResponse + additionalProperties: false + querier.v1.SeriesRequest: + type: object + properties: + matchers: + type: array + examples: + - - '{namespace="my-namespace"}' + items: + type: string + examples: + - - '{namespace="my-namespace"}' + title: matchers + description: List of label selector to apply to the result. + labelNames: + type: array + items: + type: string + title: label_names + description: |- + List of label_names to request. If empty will return all label names in the + result. + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: queried. + title: SeriesRequest + additionalProperties: false + querier.v1.SeriesResponse: + type: object + properties: + labelsSet: + type: array + items: + $ref: '#/components/schemas/types.v1.Labels' + title: labels_set + title: SeriesResponse + additionalProperties: false + types.v1.Exemplar: + type: object + properties: + timestamp: + type: + - integer + - string + examples: + - "1730000023000" + title: timestamp + format: int64 + description: Milliseconds since epoch when the profile was captured. + profileId: + type: string + examples: + - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + title: profile_id + description: Unique identifier for the profile (UUID). + spanId: + type: string + examples: + - 00f067aa0ba902b7 + title: span_id + description: Span ID if this profile was split by span during ingestion. + value: + type: + - integer + - string + examples: + - "2450000000" + title: value + format: int64 + description: Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: |- + Labels specific to this exemplar (e.g., pod name, node name). When an exemplar + label overlaps with the series label, it is not included here. + traceId: + type: string + examples: + - 4bf92f3577b34da6a3ce929d0e0e4736 + title: trace_id + description: Trace ID associated with the span, encoded as 32 lowercase hexadecimal characters. + title: Exemplar + additionalProperties: false + description: |- + Exemplar represents metadata for an individual profile sample. + Exemplars allow users to drill down from aggregated timeline views + to specific profile instances. + types.v1.ExemplarType: + type: string + title: ExemplarType + enum: + - EXEMPLAR_TYPE_UNSPECIFIED + - EXEMPLAR_TYPE_NONE + - EXEMPLAR_TYPE_INDIVIDUAL + - EXEMPLAR_TYPE_SPAN + types.v1.GetProfileStatsRequest: + type: object + title: GetProfileStatsRequest + additionalProperties: false + types.v1.GetProfileStatsResponse: + type: object + properties: + dataIngested: + type: boolean + title: data_ingested + description: Whether we received any data at any time in the past. + oldestProfileTime: + type: + - integer + - string + title: oldest_profile_time + format: int64 + description: Milliseconds since epoch. + newestProfileTime: + type: + - integer + - string + title: newest_profile_time + format: int64 + description: Milliseconds since epoch. + title: GetProfileStatsResponse + additionalProperties: false + types.v1.GoPGO: + type: object + properties: + keepLocations: + type: integer + title: keep_locations + description: Specifies the number of leaf locations to keep. + aggregateCallees: + type: boolean + title: aggregate_callees + description: |- + Aggregate callees causes the leaf location line number to be ignored, + thus aggregating all callee samples (but not callers). + title: GoPGO + additionalProperties: false + types.v1.HeatmapSeries: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + slots: + type: array + items: + $ref: '#/components/schemas/types.v1.HeatmapSlot' + title: slots + title: HeatmapSeries + additionalProperties: false + types.v1.HeatmapSlot: + type: object + properties: + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: |- + Milliseconds unix timestamp of the right edge (x_max) of this slot. + The slot covers the half-open interval (timestamp - step, timestamp]. + yMin: + type: array + items: + type: number + format: double + title: y_min + description: Minimum y value + counts: + type: array + items: + type: integer + format: int32 + title: counts + description: How many matches + exemplars: + type: array + items: + $ref: '#/components/schemas/types.v1.Exemplar' + title: exemplars + description: Provide exemplars + title: HeatmapSlot + additionalProperties: false + types.v1.LabelNamesRequest: + type: object + properties: + matchers: + type: array + items: + type: string + title: matchers + description: List of Label selectors + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Query from this point in time, given in Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Query to this point in time, given in Milliseconds since epoch. + title: LabelNamesRequest + additionalProperties: false + types.v1.LabelNamesResponse: + type: object + properties: + names: + type: array + items: + type: string + title: names + title: LabelNamesResponse + additionalProperties: false + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false + types.v1.LabelValuesRequest: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Name of the label + matchers: + type: array + items: + type: string + title: matchers + description: List of Label selectors + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Query from this point in time, given in Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Query to this point in time, given in Milliseconds since epoch. + title: LabelValuesRequest + additionalProperties: false + types.v1.LabelValuesResponse: + type: object + properties: + names: + type: array + items: + type: string + title: names + title: LabelValuesResponse + additionalProperties: false + types.v1.Labels: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: LabelPair is the key value pairs to identify the corresponding profile + title: Labels + additionalProperties: false + types.v1.Location: + type: object + properties: + name: + type: string + title: name + title: Location + additionalProperties: false + types.v1.Point: + type: object + properties: + value: + type: number + title: value + format: double + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Milliseconds unix timestamp + annotations: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileAnnotation' + title: annotations + exemplars: + type: array + items: + $ref: '#/components/schemas/types.v1.Exemplar' + title: exemplars + description: Exemplars are samples of individual profiles that contributed to this aggregated point + title: Point + additionalProperties: false + types.v1.ProfileAnnotation: + type: object + properties: + key: + type: string + title: key + description: Annotation key [hidden] + value: + type: string + title: value + description: Annotation value [hidden] + title: ProfileAnnotation + additionalProperties: false + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. + types.v1.ProfileType: + type: object + properties: + ID: + type: string + title: ID + name: + type: string + title: name + sampleType: + type: string + title: sample_type + sampleUnit: + type: string + title: sample_unit + periodType: + type: string + title: period_type + periodUnit: + type: string + title: period_unit + title: ProfileType + additionalProperties: false + types.v1.Series: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + points: + type: array + items: + $ref: '#/components/schemas/types.v1.Point' + title: points + title: Series + additionalProperties: false + types.v1.StackTraceSelector: + type: object + properties: + callSite: + type: array + items: + $ref: '#/components/schemas/types.v1.Location' + title: call_site + description: |- + Stack trace of the call site. Root at call_site[0]. + Only stack traces having the prefix provided will be selected. + If empty, the filter is ignored. + goPgo: + title: go_pgo + description: |- + Stack trace selector for profiles purposed for Go PGO. + If set, call_site is ignored. + $ref: '#/components/schemas/types.v1.GoPGO' + title: StackTraceSelector + additionalProperties: false + description: StackTraceSelector is used for filtering stack traces by locations. + types.v1.TimeSeriesAggregationType: + type: string + title: TimeSeriesAggregationType + enum: + - TIME_SERIES_AGGREGATION_TYPE_SUM + - TIME_SERIES_AGGREGATION_TYPE_AVERAGE +security: [] diff --git a/api/connect-openapi/gen/query/v1/query.openapi.yaml b/api/connect-openapi/gen/query/v1/query.openapi.yaml new file mode 100644 index 0000000000..eca107580e --- /dev/null +++ b/api/connect-openapi/gen/query/v1/query.openapi.yaml @@ -0,0 +1,1645 @@ +openapi: 3.1.0 +info: + title: query.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: query.v1.QueryFrontendService + - name: query.v1.QueryBackendService +paths: + /query.v1.QueryBackendService/Invoke: + post: + tags: + - query.v1.QueryBackendService + summary: Invoke + operationId: query.v1.QueryBackendService.Invoke + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/query.v1.InvokeRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/query.v1.InvokeResponse' + /query.v1.QueryFrontendService/Query: + post: + tags: + - query.v1.QueryFrontendService + summary: Query + operationId: query.v1.QueryFrontendService.Query + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/query.v1.QueryRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/query.v1.QueryResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + google.v1.Function: + type: object + properties: + id: + type: + - integer + - string + title: id + format: int64 + description: Unique nonzero id for the function. + name: + type: + - integer + - string + title: name + format: int64 + description: Name of the function, in human-readable form if available. Index into string table + systemName: + type: + - integer + - string + title: system_name + format: int64 + description: |- + Name of the function, as identified by the system. + For instance, it can be a C++ mangled name. Index into string table + filename: + type: + - integer + - string + title: filename + format: int64 + description: Source file containing the function. Index into string table + startLine: + type: + - integer + - string + title: start_line + format: int64 + description: Line number in source file. + title: Function + additionalProperties: false + google.v1.Line: + type: object + properties: + functionId: + type: + - integer + - string + title: function_id + format: int64 + description: The id of the corresponding profile.Function for this line. + line: + type: + - integer + - string + title: line + format: int64 + description: Line number in source code. + title: Line + additionalProperties: false + google.v1.Location: + type: object + properties: + id: + type: + - integer + - string + title: id + format: int64 + description: |- + Unique nonzero id for the location. A profile could use + instruction addresses or any integer sequence as ids. + mappingId: + type: + - integer + - string + title: mapping_id + format: int64 + description: |- + The id of the corresponding profile.Mapping for this location. + It can be unset if the mapping is unknown or not applicable for + this profile type. + address: + type: + - integer + - string + title: address + format: int64 + description: |- + The instruction address for this location, if available. It + should be within [Mapping.memory_start...Mapping.memory_limit] + for the corresponding mapping. A non-leaf address may be in the + middle of a call instruction. It is up to display tools to find + the beginning of the instruction if necessary. + line: + type: array + items: + $ref: '#/components/schemas/google.v1.Line' + title: line + description: |- + Multiple line indicates this location has inlined functions, + where the last entry represents the caller into which the + preceding entries were inlined. + + E.g., if memcpy() is inlined into printf: + line[0].function_name == "memcpy" + line[1].function_name == "printf" + isFolded: + type: boolean + title: is_folded + description: |- + Provides an indication that multiple symbols map to this location's + address, for example due to identical code folding by the linker. In that + case the line information above represents one of the multiple + symbols. This field must be recomputed when the symbolization state of the + profile changes. + title: Location + additionalProperties: false + description: Describes function and line table debug information. + google.v1.Mapping: + type: object + properties: + id: + type: + - integer + - string + title: id + format: int64 + description: Unique nonzero id for the mapping. + memoryStart: + type: + - integer + - string + title: memory_start + format: int64 + description: Address at which the binary (or DLL) is loaded into memory. + memoryLimit: + type: + - integer + - string + title: memory_limit + format: int64 + description: The limit of the address range occupied by this mapping. + fileOffset: + type: + - integer + - string + title: file_offset + format: int64 + description: Offset in the binary that corresponds to the first mapped address. + filename: + type: + - integer + - string + title: filename + format: int64 + description: |- + The object this entry is loaded from. This can be a filename on + disk for the main binary and shared libraries, or virtual + abstractions like "[vdso]". Index into string table + buildId: + type: + - integer + - string + title: build_id + format: int64 + description: |- + A string that uniquely identifies a particular program version + with high probability. E.g., for binaries generated by GNU tools, + it could be the contents of the .note.gnu.build-id field. Index into string table + hasFunctions: + type: boolean + title: has_functions + description: The following fields indicate the resolution of symbolic info. + hasFilenames: + type: boolean + title: has_filenames + hasLineNumbers: + type: boolean + title: has_line_numbers + hasInlineFrames: + type: boolean + title: has_inline_frames + title: Mapping + additionalProperties: false + metastore.v1.BlockMeta: + type: object + properties: + formatVersion: + type: integer + title: format_version + id: + type: string + title: id + description: |- + Block ID is a unique identifier for the block. + This is the only field that is not included into + the string table. + tenant: + type: integer + title: tenant + format: int32 + description: If empty, datasets belong to distinct tenants. + shard: + type: integer + title: shard + compactionLevel: + type: integer + title: compaction_level + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + createdBy: + type: integer + title: created_by + format: int32 + metadataOffset: + type: + - integer + - string + title: metadata_offset + format: int64 + size: + type: + - integer + - string + title: size + format: int64 + datasets: + type: array + items: + $ref: '#/components/schemas/metastore.v1.Dataset' + title: datasets + stringTable: + type: array + items: + type: string + title: string_table + description: |- + String table contains strings of the block. + By convention, the first string is always an empty string. + title: BlockMeta + additionalProperties: false + description: |- + BlockMeta is a metadata entry that describes the block's contents. A block + is a collection of datasets that share certain properties, such as shard ID, + compaction level, tenant ID, time range, creation time, and more. + + The block content's format denotes the binary format of the datasets and the + metadata entry (to address logical dependencies). Each dataset has its own + table of contents that lists the sections within the dataset. Each dataset + has its own set of attributes (labels) that describe its specific contents. + metastore.v1.Dataset: + type: object + properties: + format: + type: integer + title: format + tenant: + type: integer + title: tenant + format: int32 + name: + type: integer + title: name + format: int32 + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + tableOfContents: + type: array + items: + type: + - integer + - string + format: int64 + title: table_of_contents + description: |- + Table of contents lists data sections within the tenant + service region. The offsets are absolute. + + The interpretation of the table of contents is specific + to the format. + + By default (format 0), the sections are: + - 0: profiles.parquet + - 1: index.tsdb + - 2: symbols.symdb + + Format 1 corresponds to the tenant-wide index: + - 0: index.tsdb (dataset index) + size: + type: + - integer + - string + title: size + format: int64 + description: Size of the dataset in bytes. + labels: + type: array + items: + type: integer + format: int32 + title: labels + description: |- + Length prefixed label key-value pairs. + + Multiple label sets can be associated with a dataset to denote relationships + across multiple dimensions. For example, each dataset currently stores data + for multiple profile types: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + + Labels are primarily used to filter datasets based on their attributes. + For instance, labels can be used to select datasets containing a specific + service. + + The set of attributes is extensible and can grow over time. For example, a + namespace attribute could be added to datasets: + - service_name=A, profile_type=cpu + - service_name=A, profile_type=memory + - service_name=B, namespace=N, profile_type=cpu + - service_name=B, namespace=N, profile_type=memory + - service_name=C, namespace=N, profile_type=cpu + - service_name=C, namespace=N, profile_type=memory + + This organization enables querying datasets by namespace without accessing + the block contents, which significantly improves performance. + + Metadata labels are not required to be included in the block's TSDB index + and may be orthogonal to the data dimensions. Generally, attributes serve + two primary purposes: + - To create data scopes that span multiple service, reducing the need to + scan the entire set of block satisfying the query expression, i.e., + the time range and tenant ID. + - To provide additional information about datasets without altering the + storage schema or access methods. + + For example, this approach can support cost attribution or similar breakdown + analyses. It can also handle data dependencies (e.g., links to external data) + using labels. + + The cardinality of the labels is expected to remain relatively low (fewer + than a million unique combinations globally). However, this depends on the + metadata storage system. + + Metadata labels are represented as a slice of `int32` values that refer to + strings in the metadata entry's string table. The slice is a sequence of + length-prefixed key-value (KV) pairs: + + len(2) | k1 | v1 | k2 | v2 | len(3) | k1 | v3 | k2 | v4 | k3 | v5 + + The order of KV pairs is not defined. The format is optimized for indexing + rather than querying, and it is not intended to be the most space-efficient + representation. Since entries are supposed to be indexed, the redundancy of + denormalized relationships is not a concern. + title: Dataset + additionalProperties: false + querier.v1.HeatmapQueryType: + type: string + title: HeatmapQueryType + enum: + - HEATMAP_QUERY_TYPE_UNSPECIFIED + - HEATMAP_QUERY_TYPE_INDIVIDUAL + - HEATMAP_QUERY_TYPE_SPAN + query.v1.AttributeTable: + type: object + properties: + keys: + type: array + items: + type: string + title: keys + values: + type: array + items: + type: string + title: values + title: AttributeTable + additionalProperties: false + query.v1.BlockExecution: + type: object + properties: + blockId: + type: string + title: block_id + startTimeNs: + type: + - integer + - string + title: start_time_ns + format: int64 + endTimeNs: + type: + - integer + - string + title: end_time_ns + format: int64 + datasetsProcessed: + type: + - integer + - string + title: datasets_processed + format: int64 + size: + type: + - integer + - string + title: size + format: int64 + shard: + type: integer + title: shard + compactionLevel: + type: integer + title: compaction_level + title: BlockExecution + additionalProperties: false + description: BlockExecution captures execution details for a single block. + query.v1.Diagnostics: + type: object + properties: + queryPlan: + title: query_plan + $ref: '#/components/schemas/query.v1.QueryPlan' + executionNode: + title: execution_node + $ref: '#/components/schemas/query.v1.ExecutionNode' + title: Diagnostics + additionalProperties: false + description: Diagnostic messages, events, statistics, analytics, etc. + query.v1.ExecutionNode: + type: object + properties: + type: + title: type + $ref: '#/components/schemas/query.v1.QueryNode.Type' + executor: + type: string + title: executor + startTimeNs: + type: + - integer + - string + title: start_time_ns + format: int64 + endTimeNs: + type: + - integer + - string + title: end_time_ns + format: int64 + children: + type: array + items: + $ref: '#/components/schemas/query.v1.ExecutionNode' + title: children + stats: + title: stats + $ref: '#/components/schemas/query.v1.ExecutionStats' + error: + type: string + title: error + title: ExecutionNode + additionalProperties: false + description: ExecutionNode captures how a query plan node was actually executed. + query.v1.ExecutionStats: + type: object + properties: + blocksRead: + type: + - integer + - string + title: blocks_read + format: int64 + datasetsProcessed: + type: + - integer + - string + title: datasets_processed + format: int64 + blockExecutions: + type: array + items: + $ref: '#/components/schemas/query.v1.BlockExecution' + title: block_executions + bytesFetched: + type: + - integer + - string + title: bytes_fetched + format: int64 + description: |- + bytes_fetched is the total number of bytes requested from object storage + during this invocation. It counts only the bytes from this single, + successful Invoke call: retried or hedged calls that did not produce a + response are not included, so the value is deterministic across retries. + title: ExecutionStats + additionalProperties: false + description: ExecutionStats captures statistics for READ node execution. + query.v1.Exemplar: + type: object + properties: + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Milliseconds unix timestamp + profileId: + type: string + title: profile_id + spanId: + type: string + title: span_id + value: + type: + - integer + - string + title: value + format: int64 + attributeRefs: + type: array + items: + type: + - integer + - string + format: int64 + title: attribute_refs + title: Exemplar + additionalProperties: false + query.v1.HeatmapPoint: + type: object + properties: + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Milliseconds since epoch when the profile was captured. + profileId: + type: + - integer + - string + title: profile_id + format: int64 + description: Unique identifier for the profile (UUID), reference into AttributeTable with only value set + spanId: + type: + - integer + - string + title: span_id + format: int64 + description: Span ID if this profile was split by span during ingestion + value: + type: + - integer + - string + title: value + format: int64 + description: Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + attributeRefs: + type: array + items: + type: + - integer + - string + format: int64 + title: attribute_refs + description: labels as references into AttributeTable + traceId: + type: string + title: trace_id + format: byte + description: Trace ID associated with the span, if present. + title: HeatmapPoint + additionalProperties: false + query.v1.HeatmapQuery: + type: object + properties: + step: + type: number + title: step + format: double + groupBy: + type: array + items: + type: string + title: group_by + queryType: + title: query_type + $ref: '#/components/schemas/querier.v1.HeatmapQueryType' + limit: + type: + - integer + - string + title: limit + format: int64 + exemplarType: + title: exemplar_type + $ref: '#/components/schemas/types.v1.ExemplarType' + title: HeatmapQuery + additionalProperties: false + query.v1.HeatmapReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.HeatmapQuery' + heatmapSeries: + type: array + items: + $ref: '#/components/schemas/query.v1.HeatmapSeries' + title: heatmap_series + attributeTable: + title: attribute_table + $ref: '#/components/schemas/query.v1.AttributeTable' + title: HeatmapReport + additionalProperties: false + query.v1.HeatmapSeries: + type: object + properties: + attributeRefs: + type: array + items: + type: + - integer + - string + format: int64 + title: attribute_refs + points: + type: array + items: + $ref: '#/components/schemas/query.v1.HeatmapPoint' + title: points + description: Points are timestamp, then span_id, then porfile_id ordered + title: HeatmapSeries + additionalProperties: false + query.v1.InvokeOptions: + type: object + properties: + sanitizeOnMerge: + type: boolean + title: sanitize_on_merge + description: |- + Query workers might not have access to the tenant + overrides, therefore all the necessary options should + be listed in the request explicitly. + collectDiagnostics: + type: boolean + title: collect_diagnostics + title: InvokeOptions + additionalProperties: false + query.v1.InvokeRequest: + type: object + properties: + tenant: + type: array + items: + type: string + title: tenant + startTime: + type: + - integer + - string + title: start_time + format: int64 + endTime: + type: + - integer + - string + title: end_time + format: int64 + labelSelector: + type: string + title: label_selector + query: + type: array + items: + $ref: '#/components/schemas/query.v1.Query' + title: query + queryPlan: + title: query_plan + $ref: '#/components/schemas/query.v1.QueryPlan' + options: + title: options + $ref: '#/components/schemas/query.v1.InvokeOptions' + title: InvokeRequest + additionalProperties: false + query.v1.InvokeResponse: + type: object + properties: + reports: + type: array + items: + $ref: '#/components/schemas/query.v1.Report' + title: reports + diagnostics: + title: diagnostics + $ref: '#/components/schemas/query.v1.Diagnostics' + title: InvokeResponse + additionalProperties: false + query.v1.LabelNamesQuery: + type: object + title: LabelNamesQuery + additionalProperties: false + query.v1.LabelNamesReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.LabelNamesQuery' + labelNames: + type: array + items: + type: string + title: label_names + title: LabelNamesReport + additionalProperties: false + query.v1.LabelValuesQuery: + type: object + properties: + labelName: + type: string + title: label_name + title: LabelValuesQuery + additionalProperties: false + query.v1.LabelValuesReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.LabelValuesQuery' + labelValues: + type: array + items: + type: string + title: label_values + title: LabelValuesReport + additionalProperties: false + query.v1.Point: + type: object + properties: + value: + type: number + title: value + format: double + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Milliseconds unix timestamp + annotationRefs: + type: array + items: + type: + - integer + - string + format: int64 + title: annotation_refs + description: Annotations as references into AttributeTable + exemplars: + type: array + items: + $ref: '#/components/schemas/query.v1.Exemplar' + title: exemplars + description: Exemplars are samples of individual profiles that contributed to this aggregated point + title: Point + additionalProperties: false + query.v1.PprofQuery: + type: object + properties: + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + stackTraceSelector: + title: stack_trace_selector + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profileIdSelector: + type: array + items: + type: string + title: profile_id_selector + spanSelector: + type: array + items: + type: string + title: span_selector + traceIdSelector: + type: array + items: + type: string + title: trace_id_selector + description: 'TODO(kolesnikovae): Go PGO options.' + title: PprofQuery + additionalProperties: false + query.v1.PprofReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.PprofQuery' + pprof: + type: string + title: pprof + format: byte + title: PprofReport + additionalProperties: false + query.v1.Query: + type: object + properties: + queryType: + title: query_type + $ref: '#/components/schemas/query.v1.QueryType' + labelNames: + title: label_names + description: |- + Exactly one of the following fields should be set, + depending on the query type. + $ref: '#/components/schemas/query.v1.LabelNamesQuery' + labelValues: + title: label_values + $ref: '#/components/schemas/query.v1.LabelValuesQuery' + seriesLabels: + title: series_labels + $ref: '#/components/schemas/query.v1.SeriesLabelsQuery' + timeSeries: + title: time_series + $ref: '#/components/schemas/query.v1.TimeSeriesQuery' + tree: + title: tree + $ref: '#/components/schemas/query.v1.TreeQuery' + pprof: + title: pprof + $ref: '#/components/schemas/query.v1.PprofQuery' + heatmap: + title: heatmap + $ref: '#/components/schemas/query.v1.HeatmapQuery' + timeSeriesCompact: + title: time_series_compact + description: |- + function_details + call_graph + top_table + ... + $ref: '#/components/schemas/query.v1.TimeSeriesQuery' + title: Query + additionalProperties: false + query.v1.QueryNode: + type: object + properties: + type: + title: type + $ref: '#/components/schemas/query.v1.QueryNode.Type' + children: + type: array + items: + $ref: '#/components/schemas/query.v1.QueryNode' + title: children + blocks: + type: array + items: + $ref: '#/components/schemas/metastore.v1.BlockMeta' + title: blocks + title: QueryNode + additionalProperties: false + query.v1.QueryNode.Type: + type: string + title: Type + enum: + - UNKNOWN + - MERGE + - READ + query.v1.QueryPlan: + type: object + properties: + root: + title: root + $ref: '#/components/schemas/query.v1.QueryNode' + title: QueryPlan + additionalProperties: false + description: |- + A query plan is represented by a directed acyclic graph (DAG), + where each node is either a "merge" node or a "read" node. + + Merge nodes reference other nodes in the plan as their "children". + Read nodes reference the blocks which contain the actual data to be processed. + query.v1.QueryRequest: + type: object + properties: + startTime: + type: + - integer + - string + title: start_time + format: int64 + endTime: + type: + - integer + - string + title: end_time + format: int64 + labelSelector: + type: string + title: label_selector + query: + type: array + items: + $ref: '#/components/schemas/query.v1.Query' + title: query + title: QueryRequest + additionalProperties: false + query.v1.QueryResponse: + type: object + properties: + reports: + type: array + items: + $ref: '#/components/schemas/query.v1.Report' + title: reports + title: QueryResponse + additionalProperties: false + query.v1.QueryType: + type: string + title: QueryType + enum: + - QUERY_UNSPECIFIED + - QUERY_LABEL_NAMES + - QUERY_LABEL_VALUES + - QUERY_SERIES_LABELS + - QUERY_TIME_SERIES + - QUERY_TREE + - QUERY_PPROF + - QUERY_HEATMAP + - QUERY_TIME_SERIES_COMPACT + query.v1.Report: + type: object + properties: + reportType: + title: report_type + $ref: '#/components/schemas/query.v1.ReportType' + labelNames: + title: label_names + description: |- + Exactly one of the following fields should be set, + depending on the report type. + $ref: '#/components/schemas/query.v1.LabelNamesReport' + labelValues: + title: label_values + $ref: '#/components/schemas/query.v1.LabelValuesReport' + seriesLabels: + title: series_labels + $ref: '#/components/schemas/query.v1.SeriesLabelsReport' + timeSeries: + title: time_series + $ref: '#/components/schemas/query.v1.TimeSeriesReport' + tree: + title: tree + $ref: '#/components/schemas/query.v1.TreeReport' + pprof: + title: pprof + $ref: '#/components/schemas/query.v1.PprofReport' + heatmap: + title: heatmap + $ref: '#/components/schemas/query.v1.HeatmapReport' + timeSeriesCompact: + title: time_series_compact + $ref: '#/components/schemas/query.v1.TimeSeriesCompactReport' + title: Report + additionalProperties: false + query.v1.ReportType: + type: string + title: ReportType + enum: + - REPORT_UNSPECIFIED + - REPORT_LABEL_NAMES + - REPORT_LABEL_VALUES + - REPORT_SERIES_LABELS + - REPORT_TIME_SERIES + - REPORT_TREE + - REPORT_PPROF + - REPORT_HEATMAP + - REPORT_TIME_SERIES_COMPACT + query.v1.Series: + type: object + properties: + attributeRefs: + type: array + items: + type: + - integer + - string + format: int64 + title: attribute_refs + description: References to label key-value pairs in the AttributeTable that identify this series. + points: + type: array + items: + $ref: '#/components/schemas/query.v1.Point' + title: points + description: Time series data points. Each point may contain exemplars with their own attribute_refs. + title: Series + additionalProperties: false + description: Series represents a time series with optimized label storage using attribute references. + query.v1.SeriesLabelsQuery: + type: object + properties: + labelNames: + type: array + items: + type: string + title: label_names + title: SeriesLabelsQuery + additionalProperties: false + query.v1.SeriesLabelsReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.SeriesLabelsQuery' + seriesLabels: + type: array + items: + $ref: '#/components/schemas/types.v1.Labels' + title: series_labels + title: SeriesLabelsReport + additionalProperties: false + query.v1.SymbolMode: + type: string + title: SymbolMode + enum: + - SYMBOL_MODE_UNSPECIFIED + - SYMBOL_MODE_NAME + - SYMBOL_MODE_FULL + - SYMBOL_MODE_REFS + description: SymbolMode selects how a TreeQuery reports frame symbols. + query.v1.SymbolRefTable: + type: object + properties: + names: + type: array + items: + type: string + title: names + buildIds: + type: array + items: + type: string + title: build_ids + binaryNames: + type: array + items: + type: string + title: binary_names + unresolvedBuildId: + type: array + items: + type: integer + title: unresolved_build_id + unresolvedAddress: + type: array + items: + type: + - integer + - string + format: int64 + title: unresolved_address + title: SymbolRefTable + additionalProperties: false + description: |- + SymbolRefTable resolves the integer frame references in a symbol-ref tree. + Each tree node stores one frame reference r; whether r is resolved depends on + whether it falls inside the names slice: + + r < len(names): resolved -> names[r] is the frame name. + r >= len(names): unresolved -> u = r - len(names) indexes the parallel + unresolved_* arrays: + build_ids[unresolved_build_id[u]] build ID of the binary + unresolved_address[u] address within it + + build_ids and binary_names are parallel and 1:1 (binary_names[k] is the + "binary!0xaddr" fallback display for build_ids[k]); each (build ID, + binary name) pair appears once — the same build ID may repeat under + different binary names, each retained exactly as stored. + unresolved_build_id and unresolved_address are parallel, one entry per + unresolved location, sorted by (build ID, binary name, address). + query.v1.TimeSeriesCompactReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.TimeSeriesQuery' + timeSeries: + type: array + items: + $ref: '#/components/schemas/query.v1.Series' + title: time_series + attributeTable: + title: attribute_table + $ref: '#/components/schemas/query.v1.AttributeTable' + title: TimeSeriesCompactReport + additionalProperties: false + query.v1.TimeSeriesQuery: + type: object + properties: + step: + type: number + title: step + format: double + groupBy: + type: array + items: + type: string + title: group_by + limit: + type: + - integer + - string + title: limit + format: int64 + exemplarType: + title: exemplar_type + $ref: '#/components/schemas/types.v1.ExemplarType' + title: TimeSeriesQuery + additionalProperties: false + query.v1.TimeSeriesReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.TimeSeriesQuery' + timeSeries: + type: array + items: + $ref: '#/components/schemas/types.v1.Series' + title: time_series + title: TimeSeriesReport + additionalProperties: false + query.v1.TreeQuery: + type: object + properties: + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + spanSelector: + type: array + items: + type: string + title: span_selector + stackTraceSelector: + title: stack_trace_selector + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profileIdSelector: + type: array + items: + type: string + title: profile_id_selector + fullSymbols: + type: boolean + title: full_symbols + description: |- + Deprecated: use symbol_mode = SYMBOL_MODE_FULL. Retained for wire + compatibility; will be removed in a couple of releases. + traceIdSelector: + type: array + items: + type: string + title: trace_id_selector + symbolMode: + title: symbol_mode + description: |- + symbol_mode selects the symbol output. When unset, full_symbols is honored + for back-compat. + $ref: '#/components/schemas/query.v1.SymbolMode' + maxUnresolvedLocations: + type: + - integer + - string + title: max_unresolved_locations + format: int64 + description: |- + max_unresolved_locations bounds the distinct unresolved locations a + symbol-ref tree result may carry; the query fails past it. Zero means + unlimited. Effective only with SYMBOL_MODE_REFS. + title: TreeQuery + additionalProperties: false + query.v1.TreeReport: + type: object + properties: + query: + title: query + $ref: '#/components/schemas/query.v1.TreeQuery' + tree: + type: string + title: tree + format: byte + symbols: + title: symbols + nullable: true + $ref: '#/components/schemas/query.v1.TreeSymbols' + symbolRefs: + title: symbol_refs + nullable: true + $ref: '#/components/schemas/query.v1.SymbolRefTable' + title: TreeReport + additionalProperties: false + query.v1.TreeSymbols: + type: object + properties: + mappings: + type: array + items: + $ref: '#/components/schemas/google.v1.Mapping' + title: mappings + locations: + type: array + items: + $ref: '#/components/schemas/google.v1.Location' + title: locations + functions: + type: array + items: + $ref: '#/components/schemas/google.v1.Function' + title: functions + strings: + type: array + items: + type: string + title: strings + mappingHashes: + type: array + items: + type: + - integer + - string + format: int64 + title: mapping_hashes + locationHashes: + type: array + items: + type: + - integer + - string + format: int64 + title: location_hashes + functionHashes: + type: array + items: + type: + - integer + - string + format: int64 + title: function_hashes + stringHashes: + type: array + items: + type: + - integer + - string + format: int64 + title: string_hashes + title: TreeSymbols + additionalProperties: false + types.v1.Exemplar: + type: object + properties: + timestamp: + type: + - integer + - string + examples: + - "1730000023000" + title: timestamp + format: int64 + description: Milliseconds since epoch when the profile was captured. + profileId: + type: string + examples: + - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + title: profile_id + description: Unique identifier for the profile (UUID). + spanId: + type: string + examples: + - 00f067aa0ba902b7 + title: span_id + description: Span ID if this profile was split by span during ingestion. + value: + type: + - integer + - string + examples: + - "2450000000" + title: value + format: int64 + description: Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: |- + Labels specific to this exemplar (e.g., pod name, node name). When an exemplar + label overlaps with the series label, it is not included here. + traceId: + type: string + examples: + - 4bf92f3577b34da6a3ce929d0e0e4736 + title: trace_id + description: Trace ID associated with the span, encoded as 32 lowercase hexadecimal characters. + title: Exemplar + additionalProperties: false + description: |- + Exemplar represents metadata for an individual profile sample. + Exemplars allow users to drill down from aggregated timeline views + to specific profile instances. + types.v1.ExemplarType: + type: string + title: ExemplarType + enum: + - EXEMPLAR_TYPE_UNSPECIFIED + - EXEMPLAR_TYPE_NONE + - EXEMPLAR_TYPE_INDIVIDUAL + - EXEMPLAR_TYPE_SPAN + types.v1.GoPGO: + type: object + properties: + keepLocations: + type: integer + title: keep_locations + description: Specifies the number of leaf locations to keep. + aggregateCallees: + type: boolean + title: aggregate_callees + description: |- + Aggregate callees causes the leaf location line number to be ignored, + thus aggregating all callee samples (but not callers). + title: GoPGO + additionalProperties: false + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false + types.v1.Labels: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: LabelPair is the key value pairs to identify the corresponding profile + title: Labels + additionalProperties: false + types.v1.Location: + type: object + properties: + name: + type: string + title: name + title: Location + additionalProperties: false + types.v1.Point: + type: object + properties: + value: + type: number + title: value + format: double + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Milliseconds unix timestamp + annotations: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileAnnotation' + title: annotations + exemplars: + type: array + items: + $ref: '#/components/schemas/types.v1.Exemplar' + title: exemplars + description: Exemplars are samples of individual profiles that contributed to this aggregated point + title: Point + additionalProperties: false + types.v1.ProfileAnnotation: + type: object + properties: + key: + type: string + title: key + description: Annotation key [hidden] + value: + type: string + title: value + description: Annotation value [hidden] + title: ProfileAnnotation + additionalProperties: false + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. + types.v1.Series: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + points: + type: array + items: + $ref: '#/components/schemas/types.v1.Point' + title: points + title: Series + additionalProperties: false + types.v1.StackTraceSelector: + type: object + properties: + callSite: + type: array + items: + $ref: '#/components/schemas/types.v1.Location' + title: call_site + description: |- + Stack trace of the call site. Root at call_site[0]. + Only stack traces having the prefix provided will be selected. + If empty, the filter is ignored. + goPgo: + title: go_pgo + description: |- + Stack trace selector for profiles purposed for Go PGO. + If set, call_site is ignored. + $ref: '#/components/schemas/types.v1.GoPGO' + title: StackTraceSelector + additionalProperties: false + description: StackTraceSelector is used for filtering stack traces by locations. +security: [] diff --git a/api/connect-openapi/gen/segmentwriter/v1/push.openapi.yaml b/api/connect-openapi/gen/segmentwriter/v1/push.openapi.yaml new file mode 100644 index 0000000000..2c4fe53325 --- /dev/null +++ b/api/connect-openapi/gen/segmentwriter/v1/push.openapi.yaml @@ -0,0 +1,196 @@ +openapi: 3.1.0 +info: + title: segmentwriter.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: segmentwriter.v1.SegmentWriterService +paths: + /segmentwriter.v1.SegmentWriterService/Push: + post: + tags: + - segmentwriter.v1.SegmentWriterService + summary: Push + operationId: segmentwriter.v1.SegmentWriterService.Push + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/segmentwriter.v1.PushRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/segmentwriter.v1.PushResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + segmentwriter.v1.PushRequest: + type: object + properties: + tenantId: + type: string + title: tenant_id + description: Unique identifier for the tenant submitting the request. + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: Label KV pairs of the series the profile belongs to. + profile: + type: string + title: profile + format: byte + description: Profile data in binary format. Default format is pprof. + profileId: + type: string + title: profile_id + format: byte + description: Unique identifier of the profile. + shard: + type: integer + title: shard + description: Shard identifier the profile belongs to. + annotations: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileAnnotation' + title: annotations + description: Profile annotations with additional metadata. + title: PushRequest + additionalProperties: false + segmentwriter.v1.PushResponse: + type: object + title: PushResponse + additionalProperties: false + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false + types.v1.ProfileAnnotation: + type: object + properties: + key: + type: string + title: key + description: Annotation key [hidden] + value: + type: string + title: value + description: Annotation value [hidden] + title: ProfileAnnotation + additionalProperties: false + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. +security: [] diff --git a/api/connect-openapi/gen/settings/v1/recording_rules.openapi.yaml b/api/connect-openapi/gen/settings/v1/recording_rules.openapi.yaml new file mode 100644 index 0000000000..aaf17ecdb0 --- /dev/null +++ b/api/connect-openapi/gen/settings/v1/recording_rules.openapi.yaml @@ -0,0 +1,424 @@ +openapi: 3.1.0 +info: + title: settings.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: settings.v1.RecordingRulesService +paths: + /settings.v1.RecordingRulesService/DeleteRecordingRule: + post: + tags: + - settings.v1.RecordingRulesService + summary: DeleteRecordingRule + operationId: settings.v1.RecordingRulesService.DeleteRecordingRule + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.DeleteRecordingRuleRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.DeleteRecordingRuleResponse' + /settings.v1.RecordingRulesService/GetRecordingRule: + post: + tags: + - settings.v1.RecordingRulesService + summary: GetRecordingRule + operationId: settings.v1.RecordingRulesService.GetRecordingRule + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.GetRecordingRuleRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.GetRecordingRuleResponse' + /settings.v1.RecordingRulesService/ListRecordingRules: + post: + tags: + - settings.v1.RecordingRulesService + summary: ListRecordingRules + operationId: settings.v1.RecordingRulesService.ListRecordingRules + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.ListRecordingRulesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.ListRecordingRulesResponse' + /settings.v1.RecordingRulesService/UpsertRecordingRule: + post: + tags: + - settings.v1.RecordingRulesService + summary: UpsertRecordingRule + operationId: settings.v1.RecordingRulesService.UpsertRecordingRule + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.UpsertRecordingRuleRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.UpsertRecordingRuleResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + settings.v1.DeleteRecordingRuleRequest: + type: object + properties: + id: + type: string + title: id + title: DeleteRecordingRuleRequest + additionalProperties: false + settings.v1.DeleteRecordingRuleResponse: + type: object + title: DeleteRecordingRuleResponse + additionalProperties: false + settings.v1.GetRecordingRuleRequest: + type: object + properties: + id: + type: string + title: id + title: GetRecordingRuleRequest + additionalProperties: false + settings.v1.GetRecordingRuleResponse: + type: object + properties: + rule: + title: rule + $ref: '#/components/schemas/settings.v1.RecordingRule' + title: GetRecordingRuleResponse + additionalProperties: false + settings.v1.ListRecordingRulesRequest: + type: object + title: ListRecordingRulesRequest + additionalProperties: false + settings.v1.ListRecordingRulesResponse: + type: object + properties: + rules: + type: array + items: + $ref: '#/components/schemas/settings.v1.RecordingRule' + title: rules + title: ListRecordingRulesResponse + additionalProperties: false + settings.v1.MetricType: + type: string + title: MetricType + enum: + - TOTAL + settings.v1.RecordingRule: + type: object + properties: + id: + type: string + title: id + description: The unique id of the recording rule. + metricName: + type: string + title: metric_name + description: |- + The name of the recording rule, this does not necessarily need to be + unique. + profileType: + type: string + title: profile_type + description: |- + Used in the UI to display what type of profile type this recording rule is + generated from. + + This should be the standard format of: + + :::: + + For example: + + process_cpu:cpu:nanoseconds:cpu:nanoseconds + matchers: + type: array + items: + type: string + title: matchers + groupBy: + type: array + items: + type: string + title: group_by + externalLabels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: external_labels + generation: + type: + - integer + - string + title: generation + format: int64 + description: |- + The observed generation of this recording rule. This value should be + provided when making updates to this record, to avoid conflicting + concurrent updates. + stacktraceFilter: + title: stacktrace_filter + description: |- + The stacktrace filter allows filtering on particular function names in the stacktrace. + This allows recording rules to focus on specific functions and calculate their "total" + resource usage. + nullable: true + $ref: '#/components/schemas/settings.v1.StacktraceFilter' + provisioned: + type: boolean + title: provisioned + description: Provisioned rules are added by config and can't be Upsert or Deleted + title: RecordingRule + additionalProperties: false + settings.v1.StacktraceFilter: + type: object + properties: + functionName: + title: function_name + nullable: true + $ref: '#/components/schemas/settings.v1.StacktraceFilterFunctionName' + title: StacktraceFilter + additionalProperties: false + settings.v1.StacktraceFilterFunctionName: + type: object + properties: + functionName: + type: string + title: function_name + metricType: + title: metric_type + $ref: '#/components/schemas/settings.v1.MetricType' + title: StacktraceFilterFunctionName + additionalProperties: false + settings.v1.UpsertRecordingRuleRequest: + type: object + properties: + id: + type: string + title: id + description: |- + The unique id of the recording rule. If an id is not provided, this will + create a new recording rule. If an id is provided, it will replace the + existing recording rule. + metricName: + type: string + title: metric_name + matchers: + type: array + items: + type: string + title: matchers + groupBy: + type: array + items: + type: string + title: group_by + externalLabels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: external_labels + generation: + type: + - integer + - string + title: generation + format: int64 + description: |- + The observed generation of this recording rule. If this value does not + match the generation stored in the database, this upsert will be rejected. + stacktraceFilter: + title: stacktrace_filter + nullable: true + $ref: '#/components/schemas/settings.v1.StacktraceFilter' + title: UpsertRecordingRuleRequest + additionalProperties: false + settings.v1.UpsertRecordingRuleResponse: + type: object + properties: + rule: + title: rule + $ref: '#/components/schemas/settings.v1.RecordingRule' + title: UpsertRecordingRuleResponse + additionalProperties: false + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/settings/v1/setting.openapi.yaml b/api/connect-openapi/gen/settings/v1/setting.openapi.yaml new file mode 100644 index 0000000000..9fe0efa8d2 --- /dev/null +++ b/api/connect-openapi/gen/settings/v1/setting.openapi.yaml @@ -0,0 +1,247 @@ +openapi: 3.1.0 +info: + title: settings.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: settings.v1.SettingsService +paths: + /settings.v1.SettingsService/Delete: + post: + tags: + - settings.v1.SettingsService + summary: Delete + operationId: settings.v1.SettingsService.Delete + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.DeleteSettingsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.DeleteSettingsResponse' + /settings.v1.SettingsService/Get: + post: + tags: + - settings.v1.SettingsService + summary: Get + operationId: settings.v1.SettingsService.Get + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.GetSettingsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.GetSettingsResponse' + /settings.v1.SettingsService/Set: + post: + tags: + - settings.v1.SettingsService + summary: Set + operationId: settings.v1.SettingsService.Set + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.SetSettingsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/settings.v1.SetSettingsResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + settings.v1.DeleteSettingsRequest: + type: object + properties: + name: + type: string + title: name + title: DeleteSettingsRequest + additionalProperties: false + settings.v1.DeleteSettingsResponse: + type: object + title: DeleteSettingsResponse + additionalProperties: false + settings.v1.GetSettingsRequest: + type: object + title: GetSettingsRequest + additionalProperties: false + settings.v1.GetSettingsResponse: + type: object + properties: + settings: + type: array + items: + $ref: '#/components/schemas/settings.v1.Setting' + title: settings + title: GetSettingsResponse + additionalProperties: false + settings.v1.SetSettingsRequest: + type: object + properties: + setting: + title: setting + $ref: '#/components/schemas/settings.v1.Setting' + title: SetSettingsRequest + additionalProperties: false + settings.v1.SetSettingsResponse: + type: object + properties: + setting: + title: setting + $ref: '#/components/schemas/settings.v1.Setting' + title: SetSettingsResponse + additionalProperties: false + settings.v1.Setting: + type: object + properties: + name: + type: string + title: name + value: + type: string + title: value + modifiedAt: + type: + - integer + - string + title: modifiedAt + format: int64 + title: Setting + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/status/v1/status.openapi.yaml b/api/connect-openapi/gen/status/v1/status.openapi.yaml new file mode 100644 index 0000000000..3985a82f9e --- /dev/null +++ b/api/connect-openapi/gen/status/v1/status.openapi.yaml @@ -0,0 +1,187 @@ +openapi: 3.1.0 +info: + title: status.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: status.v1.StatusService +paths: + /api/v1/status/buildinfo: + get: + tags: + - status.v1.StatusService + summary: GetBuildInfo + description: Retrieve build information about the binary + operationId: status.v1.StatusService.GetBuildInfo + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/status.v1.GetBuildInfoResponse' + /api/v1/status/config: + get: + tags: + - status.v1.StatusService + summary: GetConfig + description: Retrieve the running config + operationId: status.v1.StatusService.GetConfig + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/google.api.HttpBody' + /api/v1/status/config/default: + get: + tags: + - status.v1.StatusService + summary: GetDefaultConfig + operationId: status.v1.StatusService.GetDefaultConfig + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/google.api.HttpBody' + /api/v1/status/config/diff: + get: + tags: + - status.v1.StatusService + summary: GetDiffConfig + description: Retrieve the diff config to the defaults + operationId: status.v1.StatusService.GetDiffConfig + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/google.api.HttpBody' +components: + schemas: + google.api.HttpBody: + type: object + properties: + contentType: + type: string + title: content_type + description: The HTTP Content-Type header value specifying the content type of the body. + data: + type: string + title: data + format: byte + description: The HTTP request/response body as raw binary. + extensions: + type: array + items: + $ref: '#/components/schemas/google.protobuf.Any' + title: extensions + description: |- + Application specific response metadata. Must be set in the first response + for streaming APIs. + title: HttpBody + additionalProperties: false + description: |- + Message that represents an arbitrary HTTP body. It should only be used for + payload formats that can't be represented as JSON, such as raw binary or + an HTML page. + + + This message can be used both in streaming and non-streaming API methods in + the request as well as the response. + + It can be used as a top-level request field, which is convenient if one + wants to extract parameters from either the URL or HTTP template into the + request fields and also want access to the raw HTTP body. + + Example: + + message GetResourceRequest { + // A unique request id. + string request_id = 1; + + // The raw HTTP body is bound to this field. + google.api.HttpBody http_body = 2; + + } + + service ResourceService { + rpc GetResource(GetResourceRequest) + returns (google.api.HttpBody); + rpc UpdateResource(google.api.HttpBody) + returns (google.protobuf.Empty); + + } + + Example with streaming methods: + + service CaldavService { + rpc GetCalendar(stream google.api.HttpBody) + returns (stream google.api.HttpBody); + rpc UpdateCalendar(stream google.api.HttpBody) + returns (stream google.api.HttpBody); + + } + + Use of this type only changes how the request and response bodies are + handled, all other features will continue to work unchanged. + google.protobuf.Any: + type: object + properties: + type: + type: string + value: + type: string + format: binary + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message. + status.v1.GetBuildInfoData: + type: object + properties: + version: + type: string + title: version + revision: + type: string + title: revision + branch: + type: string + title: branch + buildUser: + type: string + title: build_user + buildDate: + type: string + title: build_date + goVersion: + type: string + title: go_version + title: GetBuildInfoData + additionalProperties: false + status.v1.GetBuildInfoRequest: + type: object + title: GetBuildInfoRequest + additionalProperties: false + status.v1.GetBuildInfoResponse: + type: object + properties: + status: + type: string + title: status + data: + title: data + $ref: '#/components/schemas/status.v1.GetBuildInfoData' + title: GetBuildInfoResponse + additionalProperties: false + status.v1.GetConfigRequest: + type: object + title: GetConfigRequest + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/storegateway/v1/storegateway.openapi.yaml b/api/connect-openapi/gen/storegateway/v1/storegateway.openapi.yaml new file mode 100644 index 0000000000..3db7acdbb2 --- /dev/null +++ b/api/connect-openapi/gen/storegateway/v1/storegateway.openapi.yaml @@ -0,0 +1,1172 @@ +openapi: 3.1.0 +info: + title: storegateway.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: storegateway.v1.StoreGatewayService +paths: + /storegateway.v1.StoreGatewayService/BlockMetadata: + post: + tags: + - storegateway.v1.StoreGatewayService + summary: BlockMetadata + operationId: storegateway.v1.StoreGatewayService.BlockMetadata + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.BlockMetadataRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.BlockMetadataResponse' + /storegateway.v1.StoreGatewayService/GetBlockStats: + post: + tags: + - storegateway.v1.StoreGatewayService + summary: GetBlockStats + operationId: storegateway.v1.StoreGatewayService.GetBlockStats + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.GetBlockStatsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.GetBlockStatsResponse' + /storegateway.v1.StoreGatewayService/LabelNames: + post: + tags: + - storegateway.v1.StoreGatewayService + summary: LabelNames + operationId: storegateway.v1.StoreGatewayService.LabelNames + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelNamesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelNamesResponse' + /storegateway.v1.StoreGatewayService/LabelValues: + post: + tags: + - storegateway.v1.StoreGatewayService + summary: LabelValues + operationId: storegateway.v1.StoreGatewayService.LabelValues + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelValuesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/types.v1.LabelValuesResponse' + /storegateway.v1.StoreGatewayService/MergeProfilesLabels: {} + /storegateway.v1.StoreGatewayService/MergeProfilesPprof: {} + /storegateway.v1.StoreGatewayService/MergeProfilesStacktraces: {} + /storegateway.v1.StoreGatewayService/MergeSpanProfile: {} + /storegateway.v1.StoreGatewayService/ProfileTypes: + post: + tags: + - storegateway.v1.StoreGatewayService + summary: 'Deprecated: ProfileType call is deprecated in the store components TODO: Remove this call in release v1.4' + description: |- + Deprecated: ProfileType call is deprecated in the store components + TODO: Remove this call in release v1.4 + operationId: storegateway.v1.StoreGatewayService.ProfileTypes + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.ProfileTypesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.ProfileTypesResponse' + /storegateway.v1.StoreGatewayService/Series: + post: + tags: + - storegateway.v1.StoreGatewayService + summary: Series + operationId: storegateway.v1.StoreGatewayService.Series + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.SeriesRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/ingester.v1.SeriesResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + ingester.v1.BlockHints: + type: object + properties: + ulids: + type: array + items: + type: string + title: ulids + description: The ULID of blocks to query + deduplication: + type: boolean + title: deduplication + description: When all blocks are compacted, there is no effect of the replication factor, hence we do not need to run deduplication. + title: BlockHints + additionalProperties: false + ingester.v1.BlockMetadataRequest: + type: object + properties: + start: + type: + - integer + - string + title: start + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + end: + type: + - integer + - string + title: end + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + title: BlockMetadataRequest + additionalProperties: false + ingester.v1.BlockMetadataResponse: + type: object + properties: + blocks: + type: array + items: + $ref: '#/components/schemas/types.v1.BlockInfo' + title: blocks + description: Blocks that are present on the instance for the start to end period + title: BlockMetadataResponse + additionalProperties: false + ingester.v1.BlockStats: + type: object + properties: + seriesCount: + type: + - integer + - string + title: series_count + format: int64 + profileCount: + type: + - integer + - string + title: profile_count + format: int64 + sampleCount: + type: + - integer + - string + title: sample_count + format: int64 + indexBytes: + type: + - integer + - string + title: index_bytes + format: int64 + profileBytes: + type: + - integer + - string + title: profile_bytes + format: int64 + symbolBytes: + type: + - integer + - string + title: symbol_bytes + format: int64 + title: BlockStats + additionalProperties: false + ingester.v1.GetBlockStatsRequest: + type: object + properties: + ulids: + type: array + items: + type: string + title: ulids + title: GetBlockStatsRequest + additionalProperties: false + ingester.v1.GetBlockStatsResponse: + type: object + properties: + blockStats: + type: array + items: + $ref: '#/components/schemas/ingester.v1.BlockStats' + title: block_stats + title: GetBlockStatsResponse + additionalProperties: false + ingester.v1.Hints: + type: object + properties: + block: + title: block + $ref: '#/components/schemas/ingester.v1.BlockHints' + title: Hints + additionalProperties: false + description: Hints are used to propagate information about querying + ingester.v1.MergeProfilesLabelsRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectProfilesRequest' + by: + type: array + items: + type: string + title: by + description: The labels to merge by + stackTraceSelector: + title: stack_trace_selector + description: Select stack traces that match the provided selector. + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeProfilesLabelsRequest + additionalProperties: false + ingester.v1.MergeProfilesLabelsResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + series: + type: array + items: + $ref: '#/components/schemas/types.v1.Series' + title: series + description: The list of series for the profile with their respective value + title: MergeProfilesLabelsResponse + additionalProperties: false + ingester.v1.MergeProfilesPprofRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectProfilesRequest' + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes in the resulting profile. + nullable: true + stackTraceSelector: + title: stack_trace_selector + description: Select stack traces that match the provided selector. + nullable: true + $ref: '#/components/schemas/types.v1.StackTraceSelector' + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeProfilesPprofRequest + additionalProperties: false + ingester.v1.MergeProfilesPprofResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + result: + type: string + title: result + format: byte + description: The merge result in the pprof format. + title: MergeProfilesPprofResponse + additionalProperties: false + ingester.v1.MergeProfilesStacktracesRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectProfilesRequest' + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes in the resulting tree. + nullable: true + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeProfilesStacktracesRequest + additionalProperties: false + ingester.v1.MergeProfilesStacktracesResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + result: + title: result + description: The list of stracktraces for the profile with their respective value + $ref: '#/components/schemas/ingester.v1.MergeProfilesStacktracesResult' + title: MergeProfilesStacktracesResponse + additionalProperties: false + ingester.v1.MergeProfilesStacktracesResult: + type: object + properties: + format: + title: format + $ref: '#/components/schemas/ingester.v1.StacktracesMergeFormat' + stacktraces: + type: array + items: + $ref: '#/components/schemas/ingester.v1.StacktraceSample' + title: stacktraces + description: The list of stracktraces with their respective value + functionNames: + type: array + items: + type: string + title: function_names + treeBytes: + type: string + title: tree_bytes + format: byte + description: Merge result marshaled to pyroscope tree bytes. + title: MergeProfilesStacktracesResult + additionalProperties: false + ingester.v1.MergeSpanProfileRequest: + type: object + properties: + request: + title: request + description: The client starts the stream with a request containing the profile type and the labels. + $ref: '#/components/schemas/ingester.v1.SelectSpanProfileRequest' + maxNodes: + type: + - integer + - string + title: max_nodes + format: int64 + description: Max nodes in the resulting tree. + nullable: true + profiles: + type: array + items: + type: boolean + title: profiles + description: On a batch of profiles, the client sends the profiles to keep for merging. + title: MergeSpanProfileRequest + additionalProperties: false + ingester.v1.MergeSpanProfileResponse: + type: object + properties: + selectedProfiles: + title: selectedProfiles + description: |- + The server replies batch of profiles. + A last message without profiles signals the next message will be the result of the merge. + $ref: '#/components/schemas/ingester.v1.ProfileSets' + result: + title: result + description: The list of stracktraces for the profile with their respective value + $ref: '#/components/schemas/ingester.v1.MergeSpanProfileResult' + title: MergeSpanProfileResponse + additionalProperties: false + ingester.v1.MergeSpanProfileResult: + type: object + properties: + treeBytes: + type: string + title: tree_bytes + format: byte + title: MergeSpanProfileResult + additionalProperties: false + ingester.v1.ProfileSets: + type: object + properties: + labelsSets: + type: array + items: + $ref: '#/components/schemas/types.v1.Labels' + title: labelsSets + description: 'DEPRECATED: Use fingerprints instead.' + profiles: + type: array + items: + $ref: '#/components/schemas/ingester.v1.SeriesProfile' + title: profiles + fingerprints: + type: array + items: + type: + - integer + - string + format: int64 + title: fingerprints + title: ProfileSets + additionalProperties: false + ingester.v1.ProfileTypesRequest: + type: object + properties: + start: + type: + - integer + - string + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + title: end + format: int64 + description: Milliseconds since epoch. + title: ProfileTypesRequest + additionalProperties: false + ingester.v1.ProfileTypesResponse: + type: object + properties: + profileTypes: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileType' + title: profile_types + title: ProfileTypesResponse + additionalProperties: false + ingester.v1.SelectProfilesRequest: + type: object + properties: + labelSelector: + type: string + title: label_selector + type: + title: type + $ref: '#/components/schemas/types.v1.ProfileType' + start: + type: + - integer + - string + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + title: end + format: int64 + description: Milliseconds since epoch. + hints: + title: hints + description: 'Optional: Hints for querying' + nullable: true + $ref: '#/components/schemas/ingester.v1.Hints' + aggregation: + title: aggregation + description: 'Optional: Aggregation' + nullable: true + $ref: '#/components/schemas/types.v1.TimeSeriesAggregationType' + title: SelectProfilesRequest + additionalProperties: false + ingester.v1.SelectSpanProfileRequest: + type: object + properties: + labelSelector: + type: string + title: label_selector + type: + title: type + $ref: '#/components/schemas/types.v1.ProfileType' + start: + type: + - integer + - string + title: start + format: int64 + description: Milliseconds since epoch. + end: + type: + - integer + - string + title: end + format: int64 + description: Milliseconds since epoch. + spanSelector: + type: array + items: + type: string + title: span_selector + description: List of span identifiers. + hints: + title: hints + description: 'Optional: Hints for querying' + nullable: true + $ref: '#/components/schemas/ingester.v1.Hints' + title: SelectSpanProfileRequest + additionalProperties: false + ingester.v1.SeriesProfile: + type: object + properties: + labelIndex: + type: integer + title: labelIndex + format: int32 + description: The labels index of the series + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: timestamp in milliseconds + title: SeriesProfile + additionalProperties: false + ingester.v1.SeriesRequest: + type: object + properties: + matchers: + type: array + items: + type: string + title: matchers + labelNames: + type: array + items: + type: string + title: label_names + start: + type: + - integer + - string + title: start + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + end: + type: + - integer + - string + title: end + format: int64 + description: |- + Milliseconds since epoch. If missing or zero, only the ingesters will be + queried. + title: SeriesRequest + additionalProperties: false + ingester.v1.SeriesResponse: + type: object + properties: + labelsSet: + type: array + items: + $ref: '#/components/schemas/types.v1.Labels' + title: labels_set + title: SeriesResponse + additionalProperties: false + ingester.v1.StacktraceSample: + type: object + properties: + functionIds: + type: array + items: + type: integer + format: int32 + title: function_ids + value: + type: + - integer + - string + title: value + format: int64 + title: StacktraceSample + additionalProperties: false + ingester.v1.StacktracesMergeFormat: + type: string + title: StacktracesMergeFormat + enum: + - MERGE_FORMAT_UNSPECIFIED + - MERGE_FORMAT_STACKTRACES + - MERGE_FORMAT_TREE + types.v1.BlockCompaction: + type: object + properties: + level: + type: integer + title: level + format: int32 + sources: + type: array + items: + type: string + title: sources + parents: + type: array + items: + type: string + title: parents + title: BlockCompaction + additionalProperties: false + types.v1.BlockInfo: + type: object + properties: + ulid: + type: string + title: ulid + minTime: + type: + - integer + - string + title: min_time + format: int64 + maxTime: + type: + - integer + - string + title: max_time + format: int64 + compaction: + title: compaction + $ref: '#/components/schemas/types.v1.BlockCompaction' + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + title: BlockInfo + additionalProperties: false + types.v1.Exemplar: + type: object + properties: + timestamp: + type: + - integer + - string + examples: + - "1730000023000" + title: timestamp + format: int64 + description: Milliseconds since epoch when the profile was captured. + profileId: + type: string + examples: + - 7c9e6679-7425-40de-944b-e07fc1f90ae7 + title: profile_id + description: Unique identifier for the profile (UUID). + spanId: + type: string + examples: + - 00f067aa0ba902b7 + title: span_id + description: Span ID if this profile was split by span during ingestion. + value: + type: + - integer + - string + examples: + - "2450000000" + title: value + format: int64 + description: Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: |- + Labels specific to this exemplar (e.g., pod name, node name). When an exemplar + label overlaps with the series label, it is not included here. + traceId: + type: string + examples: + - 4bf92f3577b34da6a3ce929d0e0e4736 + title: trace_id + description: Trace ID associated with the span, encoded as 32 lowercase hexadecimal characters. + title: Exemplar + additionalProperties: false + description: |- + Exemplar represents metadata for an individual profile sample. + Exemplars allow users to drill down from aggregated timeline views + to specific profile instances. + types.v1.GoPGO: + type: object + properties: + keepLocations: + type: integer + title: keep_locations + description: Specifies the number of leaf locations to keep. + aggregateCallees: + type: boolean + title: aggregate_callees + description: |- + Aggregate callees causes the leaf location line number to be ignored, + thus aggregating all callee samples (but not callers). + title: GoPGO + additionalProperties: false + types.v1.LabelNamesRequest: + type: object + properties: + matchers: + type: array + items: + type: string + title: matchers + description: List of Label selectors + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Query from this point in time, given in Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Query to this point in time, given in Milliseconds since epoch. + title: LabelNamesRequest + additionalProperties: false + types.v1.LabelNamesResponse: + type: object + properties: + names: + type: array + items: + type: string + title: names + title: LabelNamesResponse + additionalProperties: false + types.v1.LabelPair: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Label name + value: + type: string + examples: + - my_service + title: value + description: Label value + title: LabelPair + additionalProperties: false + types.v1.LabelValuesRequest: + type: object + properties: + name: + type: string + examples: + - service_name + title: name + description: Name of the label + matchers: + type: array + items: + type: string + title: matchers + description: List of Label selectors + start: + type: + - integer + - string + examples: + - "1676282400000" + title: start + format: int64 + description: Query from this point in time, given in Milliseconds since epoch. + end: + type: + - integer + - string + examples: + - "1676289600000" + title: end + format: int64 + description: Query to this point in time, given in Milliseconds since epoch. + title: LabelValuesRequest + additionalProperties: false + types.v1.LabelValuesResponse: + type: object + properties: + names: + type: array + items: + type: string + title: names + title: LabelValuesResponse + additionalProperties: false + types.v1.Labels: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + description: LabelPair is the key value pairs to identify the corresponding profile + title: Labels + additionalProperties: false + types.v1.Location: + type: object + properties: + name: + type: string + title: name + title: Location + additionalProperties: false + types.v1.Point: + type: object + properties: + value: + type: number + title: value + format: double + timestamp: + type: + - integer + - string + title: timestamp + format: int64 + description: Milliseconds unix timestamp + annotations: + type: array + items: + $ref: '#/components/schemas/types.v1.ProfileAnnotation' + title: annotations + exemplars: + type: array + items: + $ref: '#/components/schemas/types.v1.Exemplar' + title: exemplars + description: Exemplars are samples of individual profiles that contributed to this aggregated point + title: Point + additionalProperties: false + types.v1.ProfileAnnotation: + type: object + properties: + key: + type: string + title: key + description: Annotation key [hidden] + value: + type: string + title: value + description: Annotation value [hidden] + title: ProfileAnnotation + additionalProperties: false + description: |- + Annotations provide additional metadata for a profile. + + The main differences between labels and annotations are: + - annotations cannot be used in query selectors + - annotation keys don't have to be unique + + Currently annotations are applied internally by distributors, + any annotation passed via the push API will be dropped. + types.v1.ProfileType: + type: object + properties: + ID: + type: string + title: ID + name: + type: string + title: name + sampleType: + type: string + title: sample_type + sampleUnit: + type: string + title: sample_unit + periodType: + type: string + title: period_type + periodUnit: + type: string + title: period_unit + title: ProfileType + additionalProperties: false + types.v1.Series: + type: object + properties: + labels: + type: array + items: + $ref: '#/components/schemas/types.v1.LabelPair' + title: labels + points: + type: array + items: + $ref: '#/components/schemas/types.v1.Point' + title: points + title: Series + additionalProperties: false + types.v1.StackTraceSelector: + type: object + properties: + callSite: + type: array + items: + $ref: '#/components/schemas/types.v1.Location' + title: call_site + description: |- + Stack trace of the call site. Root at call_site[0]. + Only stack traces having the prefix provided will be selected. + If empty, the filter is ignored. + goPgo: + title: go_pgo + description: |- + Stack trace selector for profiles purposed for Go PGO. + If set, call_site is ignored. + $ref: '#/components/schemas/types.v1.GoPGO' + title: StackTraceSelector + additionalProperties: false + description: StackTraceSelector is used for filtering stack traces by locations. + types.v1.TimeSeriesAggregationType: + type: string + title: TimeSeriesAggregationType + enum: + - TIME_SERIES_AGGREGATION_TYPE_SUM + - TIME_SERIES_AGGREGATION_TYPE_AVERAGE +security: [] diff --git a/api/connect-openapi/gen/types/v1/types.openapi.yaml b/api/connect-openapi/gen/types/v1/types.openapi.yaml new file mode 100644 index 0000000000..ddcad0bb31 --- /dev/null +++ b/api/connect-openapi/gen/types/v1/types.openapi.yaml @@ -0,0 +1,12 @@ +openapi: 3.1.0 +info: + title: types.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. +paths: {} +components: {} +security: [] diff --git a/api/connect-openapi/gen/vcs/v1/vcs.openapi.yaml b/api/connect-openapi/gen/vcs/v1/vcs.openapi.yaml new file mode 100644 index 0000000000..0b045e2e10 --- /dev/null +++ b/api/connect-openapi/gen/vcs/v1/vcs.openapi.yaml @@ -0,0 +1,531 @@ +openapi: 3.1.0 +info: + title: vcs.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: vcs.v1.VCSService +paths: + /vcs.v1.VCSService/GetCommit: + post: + tags: + - vcs.v1.VCSService + summary: GetCommit + operationId: vcs.v1.VCSService.GetCommit + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GetCommitRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GetCommitResponse' + /vcs.v1.VCSService/GetCommits: + post: + tags: + - vcs.v1.VCSService + summary: GetCommits + operationId: vcs.v1.VCSService.GetCommits + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GetCommitsRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GetCommitsResponse' + /vcs.v1.VCSService/GetFile: + post: + tags: + - vcs.v1.VCSService + summary: GetFile + operationId: vcs.v1.VCSService.GetFile + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GetFileRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GetFileResponse' + /vcs.v1.VCSService/GithubApp: + post: + tags: + - vcs.v1.VCSService + summary: GithubApp + operationId: vcs.v1.VCSService.GithubApp + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GithubAppRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GithubAppResponse' + /vcs.v1.VCSService/GithubLogin: + post: + tags: + - vcs.v1.VCSService + summary: GithubLogin + operationId: vcs.v1.VCSService.GithubLogin + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GithubLoginRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GithubLoginResponse' + /vcs.v1.VCSService/GithubRefresh: + post: + tags: + - vcs.v1.VCSService + summary: GithubRefresh + operationId: vcs.v1.VCSService.GithubRefresh + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GithubRefreshRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/vcs.v1.GithubRefreshResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + vcs.v1.CommitAuthor: + type: object + properties: + login: + type: string + title: login + description: the author login + avatarURL: + type: string + title: avatarURL + description: the author avatar URL + title: CommitAuthor + additionalProperties: false + vcs.v1.CommitInfo: + type: object + properties: + message: + type: string + title: message + description: the commit message + author: + title: author + description: the commit author login + $ref: '#/components/schemas/vcs.v1.CommitAuthor' + date: + type: string + title: date + description: the commit date + sha: + type: string + title: sha + description: the commit sha + URL: + type: string + title: URL + description: the full URL to the commit + title: CommitInfo + additionalProperties: false + vcs.v1.GetCommitRequest: + type: object + properties: + repositoryURL: + type: string + title: repositoryURL + description: the full path to the repository + ref: + type: string + title: ref + description: the vcs ref to get the file from + title: GetCommitRequest + additionalProperties: false + vcs.v1.GetCommitResponse: + type: object + properties: + message: + type: string + title: message + description: the commit message + author: + title: author + description: the commit author login + $ref: '#/components/schemas/vcs.v1.CommitAuthor' + date: + type: string + title: date + description: the commit date + sha: + type: string + title: sha + description: the commit sha + URL: + type: string + title: URL + description: the full URL to the commit + title: GetCommitResponse + additionalProperties: false + vcs.v1.GetCommitsRequest: + type: object + properties: + repositoryUrl: + type: string + title: repository_url + refs: + type: array + items: + type: string + title: refs + title: GetCommitsRequest + additionalProperties: false + description: New messages for the GetCommits method + vcs.v1.GetCommitsResponse: + type: object + properties: + commits: + type: array + items: + $ref: '#/components/schemas/vcs.v1.CommitInfo' + title: commits + title: GetCommitsResponse + additionalProperties: false + vcs.v1.GetFileRequest: + type: object + properties: + repositoryURL: + type: string + title: repositoryURL + description: the full path to the repository + ref: + type: string + title: ref + description: the vcs ref to get the file from + localPath: + type: string + title: localPath + description: the path to the file as provided by the symbols + rootPath: + type: string + title: rootPath + description: the root path where the project lives inside the repository + functionName: + type: string + title: functionName + description: the function name as provided by the symbols + title: GetFileRequest + additionalProperties: false + vcs.v1.GetFileResponse: + type: object + properties: + content: + type: string + title: content + description: base64 content of the file + URL: + type: string + title: URL + description: the full URL to the file + title: GetFileResponse + additionalProperties: false + vcs.v1.GithubAppRequest: + type: object + title: GithubAppRequest + additionalProperties: false + vcs.v1.GithubAppResponse: + type: object + properties: + clientID: + type: string + title: clientID + description: |- + clientID must be propagated when calling + https://github.com/login/oauth/authorize in the client_id query parameter. + callbackURL: + type: string + title: callbackURL + description: |- + If callbackURL is not empty, the URL should be propagated when + calling https://github.com/login/oauth/authorize in the + redirect_uri query parameter. + title: GithubAppResponse + additionalProperties: false + vcs.v1.GithubLoginRequest: + type: object + properties: + authorizationCode: + type: string + title: authorizationCode + title: GithubLoginRequest + additionalProperties: false + vcs.v1.GithubLoginResponse: + type: object + properties: + cookie: + type: string + title: cookie + description: |- + Deprecated + In future version, this cookie won't be sent. Now, old cookie is sent + alongside the new expected data (token, token_expires_at and + refresh_token_expires_at). Frontend will be responsible of computing its + own cookie from the new data. Remove after completing + https://github.com/grafana/explore-profiles/issues/187 + token: + type: string + title: token + description: base64 encoded encrypted token + tokenExpiresAt: + type: + - integer + - string + title: token_expires_at + format: int64 + description: Unix ms timestamp of when the token expires. + refreshTokenExpiresAt: + type: + - integer + - string + title: refresh_token_expires_at + format: int64 + description: Unix ms timestamp of when the refresh token expires. + title: GithubLoginResponse + additionalProperties: false + vcs.v1.GithubRefreshRequest: + type: object + title: GithubRefreshRequest + additionalProperties: false + vcs.v1.GithubRefreshResponse: + type: object + properties: + cookie: + type: string + title: cookie + description: |- + Deprecated + In future version, this cookie won't be sent. Now, old cookie is sent + alongside the new expected data (token, token_expires_at and + refresh_token_expires_at). Frontend will be responsible of computing its + own cookie from the new data. Remove after completing + https://github.com/grafana/explore-profiles/issues/187 + token: + type: string + title: token + description: base64 encoded encrypted token + tokenExpiresAt: + type: + - integer + - string + title: token_expires_at + format: int64 + description: Unix ms timestamp of when the token expires. + refreshTokenExpiresAt: + type: + - integer + - string + title: refresh_token_expires_at + format: int64 + description: Unix ms timestamp of when the refresh token expires. + title: GithubRefreshResponse + additionalProperties: false +security: [] diff --git a/api/connect-openapi/gen/version/v1/version.openapi.yaml b/api/connect-openapi/gen/version/v1/version.openapi.yaml new file mode 100644 index 0000000000..0ed4fa4dc1 --- /dev/null +++ b/api/connect-openapi/gen/version/v1/version.openapi.yaml @@ -0,0 +1,133 @@ +openapi: 3.1.0 +info: + title: version.v1 + version: v1.0.0 +tags: + - name: scope/public + description: This operation is considered part of the public API scope + - name: scope/internal + description: This operation is considered part of the interal API scope. There are no stability guaraentees when using those APIs. + - name: version.v1.Version +paths: + /version.v1.Version/Version: + post: + tags: + - version.v1.Version + summary: Version + operationId: version.v1.Version.Version + parameters: + - name: Connect-Protocol-Version + in: header + required: true + schema: + $ref: '#/components/schemas/connect-protocol-version' + - name: Connect-Timeout-Ms + in: header + schema: + $ref: '#/components/schemas/connect-timeout-header' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/version.v1.VersionRequest' + required: true + responses: + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/connect.error' + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/version.v1.VersionResponse' +components: + schemas: + connect-protocol-version: + type: number + title: Connect-Protocol-Version + enum: + - 1 + description: Define the version of the Connect protocol + const: 1 + connect-timeout-header: + type: number + title: Connect-Timeout-Ms + description: Define the timeout, in ms + connect.error: + type: object + properties: + code: + type: string + examples: + - not_found + enum: + - canceled + - unknown + - invalid_argument + - deadline_exceeded + - not_found + - already_exists + - permission_denied + - resource_exhausted + - failed_precondition + - aborted + - out_of_range + - unimplemented + - internal + - unavailable + - data_loss + - unauthenticated + description: The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + message: + type: string + description: A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + details: + type: array + items: + $ref: '#/components/schemas/connect.error_details.Any' + description: A list of messages that carry the error details. There is no limit on the number of messages. + title: Connect Error + additionalProperties: true + description: 'Error type returned by Connect: https://connectrpc.com/docs/go/errors/#http-representation' + connect.error_details.Any: + type: object + properties: + type: + type: string + description: 'A URL that acts as a globally unique identifier for the type of the serialized message. For example: `type.googleapis.com/google.rpc.ErrorInfo`. This is used to determine the schema of the data in the `value` field and is the discriminator for the `debug` field.' + value: + type: string + format: binary + description: The Protobuf message, serialized as bytes and base64-encoded. The specific message type is identified by the `type` field. + debug: + oneOf: + - type: object + title: Any + additionalProperties: true + description: Detailed error information. + discriminator: + propertyName: type + title: Debug + description: Deserialized error detail payload. The 'type' field indicates the schema. This field is for easier debugging and should not be relied upon for application logic. + additionalProperties: true + description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message, with an additional debug field for ConnectRPC error details. + version.v1.VersionRequest: + type: object + title: VersionRequest + additionalProperties: false + version.v1.VersionResponse: + type: object + properties: + QuerierAPI: + type: + - integer + - string + title: QuerierAPI + format: int64 + title: VersionResponse + additionalProperties: false +security: [] diff --git a/api/debuginfo/v1alpha1/debuginfo.proto b/api/debuginfo/v1alpha1/debuginfo.proto new file mode 100644 index 0000000000..6d9976b51e --- /dev/null +++ b/api/debuginfo/v1alpha1/debuginfo.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; + +package debuginfo.v1alpha1; + +import "google/protobuf/timestamp.proto"; +import "types/v1/types.proto"; + +service DebuginfoService { + rpc ShouldInitiateUpload(ShouldInitiateUploadRequest) returns (ShouldInitiateUploadResponse) {} + rpc UploadFinished(UploadFinishedRequest) returns (UploadFinishedResponse) {} + rpc ListDebuginfo(ListDebuginfoRequest) returns (ListDebuginfoResponse) {} + rpc DeleteDebuginfo(DeleteDebuginfoRequest) returns (DeleteDebuginfoResponse) {} +} + +message FileMetadata { + enum Type { + TYPE_UNSPECIFIED = 0; + TYPE_EXECUTABLE_FULL = 1; + TYPE_EXECUTABLE_NO_TEXT = 2; + } + + // GNU build ID of the executable. + string gnu_build_id = 1; + // Go build ID of the executable. + string go_build_id = 2; + // Optional libpf.FileID from the otel profiler. + string otel_file_id = 3; + // Original file name of the executable. + string name = 4; + // Type of the debug info. + Type type = 5; +} + +message ShouldInitiateUploadRequest { + FileMetadata file = 1; +} + +message ShouldInitiateUploadResponse { + bool should_initiate_upload = 1; + string reason = 2; +} + +message UploadFinishedRequest { + string gnu_build_id = 1; +} + +message UploadFinishedResponse {} + +message ListDebuginfoRequest {} + +message ListDebuginfoResponse { + repeated ObjectMetadata object = 1; +} + +message DeleteDebuginfoRequest { + string gnu_build_id = 1; +} + +message DeleteDebuginfoResponse {} + +// This is stored in buckets at "debug-info/$tenant/$gnu_build_id/metadata" +// Along with the actual uploaded file at "debug-info/$tenant/$gnu_build_id/exe" +message ObjectMetadata { + FileMetadata file = 1; + + enum State { + STATE_UPLOADING = 0; + STATE_UPLOADED = 1; + } + + State state = 2; + google.protobuf.Timestamp started_at = 3; + google.protobuf.Timestamp finished_at = 4; + // Size of the uploaded ELF file in bytes. + int64 size_bytes = 5; +} diff --git a/api/gen/proto/go/adhocprofiles/v1/adhocprofiles.pb.go b/api/gen/proto/go/adhocprofiles/v1/adhocprofiles.pb.go index 3a581b3aee..f7973ae4cb 100644 --- a/api/gen/proto/go/adhocprofiles/v1/adhocprofiles.pb.go +++ b/api/gen/proto/go/adhocprofiles/v1/adhocprofiles.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: adhocprofiles/v1/adhocprofiles.proto @@ -12,6 +12,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,25 +23,22 @@ const ( ) type AdHocProfilesUploadRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // This is typically the file name and it serves as a human readable name for the profile. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // This is the profile encoded in base64. The supported formats are pprof, json, collapsed and perf-script. Profile string `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"` // Max nodes can be used to truncate the response. - MaxNodes *int64 `protobuf:"varint,3,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` + MaxNodes *int64 `protobuf:"varint,3,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AdHocProfilesUploadRequest) Reset() { *x = AdHocProfilesUploadRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AdHocProfilesUploadRequest) String() string { @@ -51,7 +49,7 @@ func (*AdHocProfilesUploadRequest) ProtoMessage() {} func (x *AdHocProfilesUploadRequest) ProtoReflect() protoreflect.Message { mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -88,25 +86,22 @@ func (x *AdHocProfilesUploadRequest) GetMaxNodes() int64 { } type AdHocProfilesGetRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The unique identifier of the profile. Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // The desired profile type (e.g., cpu, samples) for the returned flame graph. If omitted the first profile is returned. ProfileType *string `protobuf:"bytes,2,opt,name=profile_type,json=profileType,proto3,oneof" json:"profile_type,omitempty"` // Max nodes can be used to truncate the response. - MaxNodes *int64 `protobuf:"varint,3,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` + MaxNodes *int64 `protobuf:"varint,3,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AdHocProfilesGetRequest) Reset() { *x = AdHocProfilesGetRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AdHocProfilesGetRequest) String() string { @@ -117,7 +112,7 @@ func (*AdHocProfilesGetRequest) ProtoMessage() {} func (x *AdHocProfilesGetRequest) ProtoReflect() protoreflect.Message { mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -154,12 +149,9 @@ func (x *AdHocProfilesGetRequest) GetMaxNodes() int64 { } type AdHocProfilesGetResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // timestamp in milliseconds UploadedAt int64 `protobuf:"varint,3,opt,name=uploaded_at,json=uploadedAt,proto3" json:"uploaded_at,omitempty"` ProfileType string `protobuf:"bytes,4,opt,name=profile_type,json=profileType,proto3" json:"profile_type,omitempty"` @@ -167,15 +159,15 @@ type AdHocProfilesGetResponse struct { // in the Get request using the profile_type field. ProfileTypes []string `protobuf:"bytes,5,rep,name=profile_types,json=profileTypes,proto3" json:"profile_types,omitempty"` FlamebearerProfile string `protobuf:"bytes,6,opt,name=flamebearer_profile,json=flamebearerProfile,proto3" json:"flamebearer_profile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AdHocProfilesGetResponse) Reset() { *x = AdHocProfilesGetResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AdHocProfilesGetResponse) String() string { @@ -186,7 +178,7 @@ func (*AdHocProfilesGetResponse) ProtoMessage() {} func (x *AdHocProfilesGetResponse) ProtoReflect() protoreflect.Message { mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -244,18 +236,16 @@ func (x *AdHocProfilesGetResponse) GetFlamebearerProfile() string { } type AdHocProfilesListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AdHocProfilesListRequest) Reset() { *x = AdHocProfilesListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AdHocProfilesListRequest) String() string { @@ -266,7 +256,7 @@ func (*AdHocProfilesListRequest) ProtoMessage() {} func (x *AdHocProfilesListRequest) ProtoReflect() protoreflect.Message { mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -282,20 +272,17 @@ func (*AdHocProfilesListRequest) Descriptor() ([]byte, []int) { } type AdHocProfilesListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Profiles []*AdHocProfilesProfileMetadata `protobuf:"bytes,1,rep,name=profiles,proto3" json:"profiles,omitempty"` unknownFields protoimpl.UnknownFields - - Profiles []*AdHocProfilesProfileMetadata `protobuf:"bytes,1,rep,name=profiles,proto3" json:"profiles,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AdHocProfilesListResponse) Reset() { *x = AdHocProfilesListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AdHocProfilesListResponse) String() string { @@ -306,7 +293,7 @@ func (*AdHocProfilesListResponse) ProtoMessage() {} func (x *AdHocProfilesListResponse) ProtoReflect() protoreflect.Message { mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -329,23 +316,20 @@ func (x *AdHocProfilesListResponse) GetProfiles() []*AdHocProfilesProfileMetadat } type AdHocProfilesProfileMetadata struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // timestamp in milliseconds - UploadedAt int64 `protobuf:"varint,3,opt,name=uploaded_at,json=uploadedAt,proto3" json:"uploaded_at,omitempty"` + UploadedAt int64 `protobuf:"varint,3,opt,name=uploaded_at,json=uploadedAt,proto3" json:"uploaded_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AdHocProfilesProfileMetadata) Reset() { *x = AdHocProfilesProfileMetadata{} - if protoimpl.UnsafeEnabled { - mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AdHocProfilesProfileMetadata) String() string { @@ -356,7 +340,7 @@ func (*AdHocProfilesProfileMetadata) ProtoMessage() {} func (x *AdHocProfilesProfileMetadata) ProtoReflect() protoreflect.Message { mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -392,127 +376,213 @@ func (x *AdHocProfilesProfileMetadata) GetUploadedAt() int64 { return 0 } -var File_adhocprofiles_v1_adhocprofiles_proto protoreflect.FileDescriptor +type AdHocProfilesDiffRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + LeftId string `protobuf:"bytes,1,opt,name=left_id,json=leftId,proto3" json:"left_id,omitempty"` + RightId string `protobuf:"bytes,2,opt,name=right_id,json=rightId,proto3" json:"right_id,omitempty"` + ProfileType *string `protobuf:"bytes,3,opt,name=profile_type,json=profileType,proto3,oneof" json:"profile_type,omitempty"` + MaxNodes *int64 `protobuf:"varint,4,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AdHocProfilesDiffRequest) Reset() { + *x = AdHocProfilesDiffRequest{} + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AdHocProfilesDiffRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} -var file_adhocprofiles_v1_adhocprofiles_proto_rawDesc = []byte{ - 0x0a, 0x24, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, - 0x76, 0x31, 0x2f, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x14, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, - 0x76, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7a, - 0x0a, 0x1a, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x55, - 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x6d, 0x61, - 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, - 0x08, 0x6d, 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, - 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x17, 0x41, - 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x47, 0x65, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, - 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x48, 0x01, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, - 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, - 0xd8, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x41, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x66, 0x6c, 0x61, - 0x6d, 0x65, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x62, 0x65, 0x61, - 0x72, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x41, 0x64, - 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x67, 0x0a, 0x19, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, - 0x63, 0x0a, 0x1c, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, - 0x65, 0x64, 0x41, 0x74, 0x32, 0xbe, 0x02, 0x0a, 0x13, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x64, 0x0a, 0x06, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x2c, 0x2e, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x29, 0x2e, 0x61, 0x64, 0x68, 0x6f, - 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x48, - 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x61, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2a, 0x2e, 0x61, 0x64, 0x68, - 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, - 0x48, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x48, 0x6f, 0x63, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xdb, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, - 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x12, - 0x41, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, - 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x67, 0x6f, 0x2f, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02, 0x10, 0x41, 0x64, 0x68, - 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, - 0x41, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5c, 0x56, 0x31, - 0xe2, 0x02, 0x1c, 0x41, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x11, 0x41, 0x64, 0x68, 0x6f, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +func (*AdHocProfilesDiffRequest) ProtoMessage() {} + +func (x *AdHocProfilesDiffRequest) ProtoReflect() protoreflect.Message { + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } +// Deprecated: Use AdHocProfilesDiffRequest.ProtoReflect.Descriptor instead. +func (*AdHocProfilesDiffRequest) Descriptor() ([]byte, []int) { + return file_adhocprofiles_v1_adhocprofiles_proto_rawDescGZIP(), []int{6} +} + +func (x *AdHocProfilesDiffRequest) GetLeftId() string { + if x != nil { + return x.LeftId + } + return "" +} + +func (x *AdHocProfilesDiffRequest) GetRightId() string { + if x != nil { + return x.RightId + } + return "" +} + +func (x *AdHocProfilesDiffRequest) GetProfileType() string { + if x != nil && x.ProfileType != nil { + return *x.ProfileType + } + return "" +} + +func (x *AdHocProfilesDiffRequest) GetMaxNodes() int64 { + if x != nil && x.MaxNodes != nil { + return *x.MaxNodes + } + return 0 +} + +type AdHocProfilesDiffResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + ProfileTypes []string `protobuf:"bytes,1,rep,name=profile_types,json=profileTypes,proto3" json:"profile_types,omitempty"` + FlamebearerProfile string `protobuf:"bytes,2,opt,name=flamebearer_profile,json=flamebearerProfile,proto3" json:"flamebearer_profile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AdHocProfilesDiffResponse) Reset() { + *x = AdHocProfilesDiffResponse{} + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AdHocProfilesDiffResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdHocProfilesDiffResponse) ProtoMessage() {} + +func (x *AdHocProfilesDiffResponse) ProtoReflect() protoreflect.Message { + mi := &file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdHocProfilesDiffResponse.ProtoReflect.Descriptor instead. +func (*AdHocProfilesDiffResponse) Descriptor() ([]byte, []int) { + return file_adhocprofiles_v1_adhocprofiles_proto_rawDescGZIP(), []int{7} +} + +func (x *AdHocProfilesDiffResponse) GetProfileTypes() []string { + if x != nil { + return x.ProfileTypes + } + return nil +} + +func (x *AdHocProfilesDiffResponse) GetFlamebearerProfile() string { + if x != nil { + return x.FlamebearerProfile + } + return "" +} + +var File_adhocprofiles_v1_adhocprofiles_proto protoreflect.FileDescriptor + +const file_adhocprofiles_v1_adhocprofiles_proto_rawDesc = "" + + "\n" + + "$adhocprofiles/v1/adhocprofiles.proto\x12\x10adhocprofiles.v1\x1a\x14types/v1/types.proto\"z\n" + + "\x1aAdHocProfilesUploadRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + + "\aprofile\x18\x02 \x01(\tR\aprofile\x12 \n" + + "\tmax_nodes\x18\x03 \x01(\x03H\x00R\bmaxNodes\x88\x01\x01B\f\n" + + "\n" + + "_max_nodes\"\x92\x01\n" + + "\x17AdHocProfilesGetRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12&\n" + + "\fprofile_type\x18\x02 \x01(\tH\x00R\vprofileType\x88\x01\x01\x12 \n" + + "\tmax_nodes\x18\x03 \x01(\x03H\x01R\bmaxNodes\x88\x01\x01B\x0f\n" + + "\r_profile_typeB\f\n" + + "\n" + + "_max_nodes\"\xd8\x01\n" + + "\x18AdHocProfilesGetResponse\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1f\n" + + "\vuploaded_at\x18\x03 \x01(\x03R\n" + + "uploadedAt\x12!\n" + + "\fprofile_type\x18\x04 \x01(\tR\vprofileType\x12#\n" + + "\rprofile_types\x18\x05 \x03(\tR\fprofileTypes\x12/\n" + + "\x13flamebearer_profile\x18\x06 \x01(\tR\x12flamebearerProfile\"\x1a\n" + + "\x18AdHocProfilesListRequest\"g\n" + + "\x19AdHocProfilesListResponse\x12J\n" + + "\bprofiles\x18\x01 \x03(\v2..adhocprofiles.v1.AdHocProfilesProfileMetadataR\bprofiles\"c\n" + + "\x1cAdHocProfilesProfileMetadata\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1f\n" + + "\vuploaded_at\x18\x03 \x01(\x03R\n" + + "uploadedAt\"\xb7\x01\n" + + "\x18AdHocProfilesDiffRequest\x12\x17\n" + + "\aleft_id\x18\x01 \x01(\tR\x06leftId\x12\x19\n" + + "\bright_id\x18\x02 \x01(\tR\arightId\x12&\n" + + "\fprofile_type\x18\x03 \x01(\tH\x00R\vprofileType\x88\x01\x01\x12 \n" + + "\tmax_nodes\x18\x04 \x01(\x03H\x01R\bmaxNodes\x88\x01\x01B\x0f\n" + + "\r_profile_typeB\f\n" + + "\n" + + "_max_nodes\"q\n" + + "\x19AdHocProfilesDiffResponse\x12#\n" + + "\rprofile_types\x18\x01 \x03(\tR\fprofileTypes\x12/\n" + + "\x13flamebearer_profile\x18\x02 \x01(\tR\x12flamebearerProfile2\xa1\x03\n" + + "\x13AdHocProfileService\x12d\n" + + "\x06Upload\x12,.adhocprofiles.v1.AdHocProfilesUploadRequest\x1a*.adhocprofiles.v1.AdHocProfilesGetResponse\"\x00\x12^\n" + + "\x03Get\x12).adhocprofiles.v1.AdHocProfilesGetRequest\x1a*.adhocprofiles.v1.AdHocProfilesGetResponse\"\x00\x12a\n" + + "\x04List\x12*.adhocprofiles.v1.AdHocProfilesListRequest\x1a+.adhocprofiles.v1.AdHocProfilesListResponse\"\x00\x12a\n" + + "\x04Diff\x12*.adhocprofiles.v1.AdHocProfilesDiffRequest\x1a+.adhocprofiles.v1.AdHocProfilesDiffResponse\"\x00B\xdb\x01\n" + + "\x14com.adhocprofiles.v1B\x12AdhocprofilesProtoP\x01ZNgithub.com/grafana/pyroscope/api/gen/proto/go/adhocprofiles/v1;adhocprofilesv1\xa2\x02\x03AXX\xaa\x02\x10Adhocprofiles.V1\xca\x02\x10Adhocprofiles\\V1\xe2\x02\x1cAdhocprofiles\\V1\\GPBMetadata\xea\x02\x11Adhocprofiles::V1b\x06proto3" + var ( file_adhocprofiles_v1_adhocprofiles_proto_rawDescOnce sync.Once - file_adhocprofiles_v1_adhocprofiles_proto_rawDescData = file_adhocprofiles_v1_adhocprofiles_proto_rawDesc + file_adhocprofiles_v1_adhocprofiles_proto_rawDescData []byte ) func file_adhocprofiles_v1_adhocprofiles_proto_rawDescGZIP() []byte { file_adhocprofiles_v1_adhocprofiles_proto_rawDescOnce.Do(func() { - file_adhocprofiles_v1_adhocprofiles_proto_rawDescData = protoimpl.X.CompressGZIP(file_adhocprofiles_v1_adhocprofiles_proto_rawDescData) + file_adhocprofiles_v1_adhocprofiles_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_adhocprofiles_v1_adhocprofiles_proto_rawDesc), len(file_adhocprofiles_v1_adhocprofiles_proto_rawDesc))) }) return file_adhocprofiles_v1_adhocprofiles_proto_rawDescData } -var file_adhocprofiles_v1_adhocprofiles_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_adhocprofiles_v1_adhocprofiles_proto_goTypes = []interface{}{ +var file_adhocprofiles_v1_adhocprofiles_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_adhocprofiles_v1_adhocprofiles_proto_goTypes = []any{ (*AdHocProfilesUploadRequest)(nil), // 0: adhocprofiles.v1.AdHocProfilesUploadRequest (*AdHocProfilesGetRequest)(nil), // 1: adhocprofiles.v1.AdHocProfilesGetRequest (*AdHocProfilesGetResponse)(nil), // 2: adhocprofiles.v1.AdHocProfilesGetResponse (*AdHocProfilesListRequest)(nil), // 3: adhocprofiles.v1.AdHocProfilesListRequest (*AdHocProfilesListResponse)(nil), // 4: adhocprofiles.v1.AdHocProfilesListResponse (*AdHocProfilesProfileMetadata)(nil), // 5: adhocprofiles.v1.AdHocProfilesProfileMetadata + (*AdHocProfilesDiffRequest)(nil), // 6: adhocprofiles.v1.AdHocProfilesDiffRequest + (*AdHocProfilesDiffResponse)(nil), // 7: adhocprofiles.v1.AdHocProfilesDiffResponse } var file_adhocprofiles_v1_adhocprofiles_proto_depIdxs = []int32{ 5, // 0: adhocprofiles.v1.AdHocProfilesListResponse.profiles:type_name -> adhocprofiles.v1.AdHocProfilesProfileMetadata 0, // 1: adhocprofiles.v1.AdHocProfileService.Upload:input_type -> adhocprofiles.v1.AdHocProfilesUploadRequest 1, // 2: adhocprofiles.v1.AdHocProfileService.Get:input_type -> adhocprofiles.v1.AdHocProfilesGetRequest 3, // 3: adhocprofiles.v1.AdHocProfileService.List:input_type -> adhocprofiles.v1.AdHocProfilesListRequest - 2, // 4: adhocprofiles.v1.AdHocProfileService.Upload:output_type -> adhocprofiles.v1.AdHocProfilesGetResponse - 2, // 5: adhocprofiles.v1.AdHocProfileService.Get:output_type -> adhocprofiles.v1.AdHocProfilesGetResponse - 4, // 6: adhocprofiles.v1.AdHocProfileService.List:output_type -> adhocprofiles.v1.AdHocProfilesListResponse - 4, // [4:7] is the sub-list for method output_type - 1, // [1:4] is the sub-list for method input_type + 6, // 4: adhocprofiles.v1.AdHocProfileService.Diff:input_type -> adhocprofiles.v1.AdHocProfilesDiffRequest + 2, // 5: adhocprofiles.v1.AdHocProfileService.Upload:output_type -> adhocprofiles.v1.AdHocProfilesGetResponse + 2, // 6: adhocprofiles.v1.AdHocProfileService.Get:output_type -> adhocprofiles.v1.AdHocProfilesGetResponse + 4, // 7: adhocprofiles.v1.AdHocProfileService.List:output_type -> adhocprofiles.v1.AdHocProfilesListResponse + 7, // 8: adhocprofiles.v1.AdHocProfileService.Diff:output_type -> adhocprofiles.v1.AdHocProfilesDiffResponse + 5, // [5:9] is the sub-list for method output_type + 1, // [1:5] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name @@ -523,89 +593,16 @@ func file_adhocprofiles_v1_adhocprofiles_proto_init() { if File_adhocprofiles_v1_adhocprofiles_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AdHocProfilesUploadRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AdHocProfilesGetRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AdHocProfilesGetResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AdHocProfilesListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AdHocProfilesListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AdHocProfilesProfileMetadata); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[0].OneofWrappers = []interface{}{} - file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[1].OneofWrappers = []interface{}{} + file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[0].OneofWrappers = []any{} + file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[1].OneofWrappers = []any{} + file_adhocprofiles_v1_adhocprofiles_proto_msgTypes[6].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_adhocprofiles_v1_adhocprofiles_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_adhocprofiles_v1_adhocprofiles_proto_rawDesc), len(file_adhocprofiles_v1_adhocprofiles_proto_rawDesc)), NumEnums: 0, - NumMessages: 6, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, @@ -614,7 +611,6 @@ func file_adhocprofiles_v1_adhocprofiles_proto_init() { MessageInfos: file_adhocprofiles_v1_adhocprofiles_proto_msgTypes, }.Build() File_adhocprofiles_v1_adhocprofiles_proto = out.File - file_adhocprofiles_v1_adhocprofiles_proto_rawDesc = nil file_adhocprofiles_v1_adhocprofiles_proto_goTypes = nil file_adhocprofiles_v1_adhocprofiles_proto_depIdxs = nil } diff --git a/api/gen/proto/go/adhocprofiles/v1/adhocprofiles_vtproto.pb.go b/api/gen/proto/go/adhocprofiles/v1/adhocprofiles_vtproto.pb.go index 051bad1e5a..8d80d10fe2 100644 --- a/api/gen/proto/go/adhocprofiles/v1/adhocprofiles_vtproto.pb.go +++ b/api/gen/proto/go/adhocprofiles/v1/adhocprofiles_vtproto.pb.go @@ -154,6 +154,54 @@ func (m *AdHocProfilesProfileMetadata) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *AdHocProfilesDiffRequest) CloneVT() *AdHocProfilesDiffRequest { + if m == nil { + return (*AdHocProfilesDiffRequest)(nil) + } + r := new(AdHocProfilesDiffRequest) + r.LeftId = m.LeftId + r.RightId = m.RightId + if rhs := m.ProfileType; rhs != nil { + tmpVal := *rhs + r.ProfileType = &tmpVal + } + if rhs := m.MaxNodes; rhs != nil { + tmpVal := *rhs + r.MaxNodes = &tmpVal + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AdHocProfilesDiffRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *AdHocProfilesDiffResponse) CloneVT() *AdHocProfilesDiffResponse { + if m == nil { + return (*AdHocProfilesDiffResponse)(nil) + } + r := new(AdHocProfilesDiffResponse) + r.FlamebearerProfile = m.FlamebearerProfile + if rhs := m.ProfileTypes; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.ProfileTypes = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AdHocProfilesDiffResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (this *AdHocProfilesUploadRequest) EqualVT(that *AdHocProfilesUploadRequest) bool { if this == that { return true @@ -318,6 +366,62 @@ func (this *AdHocProfilesProfileMetadata) EqualMessageVT(thatMsg proto.Message) } return this.EqualVT(that) } +func (this *AdHocProfilesDiffRequest) EqualVT(that *AdHocProfilesDiffRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.LeftId != that.LeftId { + return false + } + if this.RightId != that.RightId { + return false + } + if p, q := this.ProfileType, that.ProfileType; (p == nil && q != nil) || (p != nil && (q == nil || *p != *q)) { + return false + } + if p, q := this.MaxNodes, that.MaxNodes; (p == nil && q != nil) || (p != nil && (q == nil || *p != *q)) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AdHocProfilesDiffRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AdHocProfilesDiffRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AdHocProfilesDiffResponse) EqualVT(that *AdHocProfilesDiffResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.ProfileTypes) != len(that.ProfileTypes) { + return false + } + for i, vx := range this.ProfileTypes { + vy := that.ProfileTypes[i] + if vx != vy { + return false + } + } + if this.FlamebearerProfile != that.FlamebearerProfile { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AdHocProfilesDiffResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AdHocProfilesDiffResponse) + if !ok { + return false + } + return this.EqualVT(that) +} // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. @@ -336,6 +440,8 @@ type AdHocProfileServiceClient interface { Get(ctx context.Context, in *AdHocProfilesGetRequest, opts ...grpc.CallOption) (*AdHocProfilesGetResponse, error) // Retrieves a list of profiles found in the underlying store. List(ctx context.Context, in *AdHocProfilesListRequest, opts ...grpc.CallOption) (*AdHocProfilesListResponse, error) + // Computes a diff flamegraph from two previously uploaded profiles. + Diff(ctx context.Context, in *AdHocProfilesDiffRequest, opts ...grpc.CallOption) (*AdHocProfilesDiffResponse, error) } type adHocProfileServiceClient struct { @@ -373,6 +479,15 @@ func (c *adHocProfileServiceClient) List(ctx context.Context, in *AdHocProfilesL return out, nil } +func (c *adHocProfileServiceClient) Diff(ctx context.Context, in *AdHocProfilesDiffRequest, opts ...grpc.CallOption) (*AdHocProfilesDiffResponse, error) { + out := new(AdHocProfilesDiffResponse) + err := c.cc.Invoke(ctx, "/adhocprofiles.v1.AdHocProfileService/Diff", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AdHocProfileServiceServer is the server API for AdHocProfileService service. // All implementations must embed UnimplementedAdHocProfileServiceServer // for forward compatibility @@ -385,6 +500,8 @@ type AdHocProfileServiceServer interface { Get(context.Context, *AdHocProfilesGetRequest) (*AdHocProfilesGetResponse, error) // Retrieves a list of profiles found in the underlying store. List(context.Context, *AdHocProfilesListRequest) (*AdHocProfilesListResponse, error) + // Computes a diff flamegraph from two previously uploaded profiles. + Diff(context.Context, *AdHocProfilesDiffRequest) (*AdHocProfilesDiffResponse, error) mustEmbedUnimplementedAdHocProfileServiceServer() } @@ -401,6 +518,9 @@ func (UnimplementedAdHocProfileServiceServer) Get(context.Context, *AdHocProfile func (UnimplementedAdHocProfileServiceServer) List(context.Context, *AdHocProfilesListRequest) (*AdHocProfilesListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method List not implemented") } +func (UnimplementedAdHocProfileServiceServer) Diff(context.Context, *AdHocProfilesDiffRequest) (*AdHocProfilesDiffResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Diff not implemented") +} func (UnimplementedAdHocProfileServiceServer) mustEmbedUnimplementedAdHocProfileServiceServer() {} // UnsafeAdHocProfileServiceServer may be embedded to opt out of forward compatibility for this service. @@ -468,6 +588,24 @@ func _AdHocProfileService_List_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _AdHocProfileService_Diff_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AdHocProfilesDiffRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdHocProfileServiceServer).Diff(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/adhocprofiles.v1.AdHocProfileService/Diff", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdHocProfileServiceServer).Diff(ctx, req.(*AdHocProfilesDiffRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AdHocProfileService_ServiceDesc is the grpc.ServiceDesc for AdHocProfileService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -487,6 +625,10 @@ var AdHocProfileService_ServiceDesc = grpc.ServiceDesc{ MethodName: "List", Handler: _AdHocProfileService_List_Handler, }, + { + MethodName: "Diff", + Handler: _AdHocProfileService_Diff_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "adhocprofiles/v1/adhocprofiles.proto", @@ -801,6 +943,114 @@ func (m *AdHocProfilesProfileMetadata) MarshalToSizedBufferVT(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *AdHocProfilesDiffRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdHocProfilesDiffRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AdHocProfilesDiffRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.MaxNodes != nil { + i = protohelpers.EncodeVarint(dAtA, i, uint64(*m.MaxNodes)) + i-- + dAtA[i] = 0x20 + } + if m.ProfileType != nil { + i -= len(*m.ProfileType) + copy(dAtA[i:], *m.ProfileType) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(*m.ProfileType))) + i-- + dAtA[i] = 0x1a + } + if len(m.RightId) > 0 { + i -= len(m.RightId) + copy(dAtA[i:], m.RightId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RightId))) + i-- + dAtA[i] = 0x12 + } + if len(m.LeftId) > 0 { + i -= len(m.LeftId) + copy(dAtA[i:], m.LeftId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LeftId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AdHocProfilesDiffResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AdHocProfilesDiffResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AdHocProfilesDiffResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.FlamebearerProfile) > 0 { + i -= len(m.FlamebearerProfile) + copy(dAtA[i:], m.FlamebearerProfile) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FlamebearerProfile))) + i-- + dAtA[i] = 0x12 + } + if len(m.ProfileTypes) > 0 { + for iNdEx := len(m.ProfileTypes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProfileTypes[iNdEx]) + copy(dAtA[i:], m.ProfileTypes[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileTypes[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *AdHocProfilesUploadRequest) SizeVT() (n int) { if m == nil { return 0 @@ -925,6 +1175,51 @@ func (m *AdHocProfilesProfileMetadata) SizeVT() (n int) { return n } +func (m *AdHocProfilesDiffRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.LeftId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.RightId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.ProfileType != nil { + l = len(*m.ProfileType) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.MaxNodes != nil { + n += 1 + protohelpers.SizeOfVarint(uint64(*m.MaxNodes)) + } + n += len(m.unknownFields) + return n +} + +func (m *AdHocProfilesDiffResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ProfileTypes) > 0 { + for _, s := range m.ProfileTypes { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + l = len(m.FlamebearerProfile) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + func (m *AdHocProfilesUploadRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1696,3 +1991,286 @@ func (m *AdHocProfilesProfileMetadata) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *AdHocProfilesDiffRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdHocProfilesDiffRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdHocProfilesDiffRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LeftId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LeftId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RightId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RightId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.ProfileType = &s + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxNodes", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MaxNodes = &v + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AdHocProfilesDiffResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AdHocProfilesDiffResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AdHocProfilesDiffResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileTypes", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileTypes = append(m.ProfileTypes, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FlamebearerProfile", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FlamebearerProfile = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.go b/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.go index b93f7ff74e..0eae3d49c4 100644 --- a/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.go +++ b/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.go @@ -41,14 +41,9 @@ const ( // AdHocProfileServiceListProcedure is the fully-qualified name of the AdHocProfileService's List // RPC. AdHocProfileServiceListProcedure = "/adhocprofiles.v1.AdHocProfileService/List" -) - -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - adHocProfileServiceServiceDescriptor = v1.File_adhocprofiles_v1_adhocprofiles_proto.Services().ByName("AdHocProfileService") - adHocProfileServiceUploadMethodDescriptor = adHocProfileServiceServiceDescriptor.Methods().ByName("Upload") - adHocProfileServiceGetMethodDescriptor = adHocProfileServiceServiceDescriptor.Methods().ByName("Get") - adHocProfileServiceListMethodDescriptor = adHocProfileServiceServiceDescriptor.Methods().ByName("List") + // AdHocProfileServiceDiffProcedure is the fully-qualified name of the AdHocProfileService's Diff + // RPC. + AdHocProfileServiceDiffProcedure = "/adhocprofiles.v1.AdHocProfileService/Diff" ) // AdHocProfileServiceClient is a client for the adhocprofiles.v1.AdHocProfileService service. @@ -61,6 +56,8 @@ type AdHocProfileServiceClient interface { Get(context.Context, *connect.Request[v1.AdHocProfilesGetRequest]) (*connect.Response[v1.AdHocProfilesGetResponse], error) // Retrieves a list of profiles found in the underlying store. List(context.Context, *connect.Request[v1.AdHocProfilesListRequest]) (*connect.Response[v1.AdHocProfilesListResponse], error) + // Computes a diff flamegraph from two previously uploaded profiles. + Diff(context.Context, *connect.Request[v1.AdHocProfilesDiffRequest]) (*connect.Response[v1.AdHocProfilesDiffResponse], error) } // NewAdHocProfileServiceClient constructs a client for the adhocprofiles.v1.AdHocProfileService @@ -72,23 +69,30 @@ type AdHocProfileServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewAdHocProfileServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) AdHocProfileServiceClient { baseURL = strings.TrimRight(baseURL, "/") + adHocProfileServiceMethods := v1.File_adhocprofiles_v1_adhocprofiles_proto.Services().ByName("AdHocProfileService").Methods() return &adHocProfileServiceClient{ upload: connect.NewClient[v1.AdHocProfilesUploadRequest, v1.AdHocProfilesGetResponse]( httpClient, baseURL+AdHocProfileServiceUploadProcedure, - connect.WithSchema(adHocProfileServiceUploadMethodDescriptor), + connect.WithSchema(adHocProfileServiceMethods.ByName("Upload")), connect.WithClientOptions(opts...), ), get: connect.NewClient[v1.AdHocProfilesGetRequest, v1.AdHocProfilesGetResponse]( httpClient, baseURL+AdHocProfileServiceGetProcedure, - connect.WithSchema(adHocProfileServiceGetMethodDescriptor), + connect.WithSchema(adHocProfileServiceMethods.ByName("Get")), connect.WithClientOptions(opts...), ), list: connect.NewClient[v1.AdHocProfilesListRequest, v1.AdHocProfilesListResponse]( httpClient, baseURL+AdHocProfileServiceListProcedure, - connect.WithSchema(adHocProfileServiceListMethodDescriptor), + connect.WithSchema(adHocProfileServiceMethods.ByName("List")), + connect.WithClientOptions(opts...), + ), + diff: connect.NewClient[v1.AdHocProfilesDiffRequest, v1.AdHocProfilesDiffResponse]( + httpClient, + baseURL+AdHocProfileServiceDiffProcedure, + connect.WithSchema(adHocProfileServiceMethods.ByName("Diff")), connect.WithClientOptions(opts...), ), } @@ -99,6 +103,7 @@ type adHocProfileServiceClient struct { upload *connect.Client[v1.AdHocProfilesUploadRequest, v1.AdHocProfilesGetResponse] get *connect.Client[v1.AdHocProfilesGetRequest, v1.AdHocProfilesGetResponse] list *connect.Client[v1.AdHocProfilesListRequest, v1.AdHocProfilesListResponse] + diff *connect.Client[v1.AdHocProfilesDiffRequest, v1.AdHocProfilesDiffResponse] } // Upload calls adhocprofiles.v1.AdHocProfileService.Upload. @@ -116,6 +121,11 @@ func (c *adHocProfileServiceClient) List(ctx context.Context, req *connect.Reque return c.list.CallUnary(ctx, req) } +// Diff calls adhocprofiles.v1.AdHocProfileService.Diff. +func (c *adHocProfileServiceClient) Diff(ctx context.Context, req *connect.Request[v1.AdHocProfilesDiffRequest]) (*connect.Response[v1.AdHocProfilesDiffResponse], error) { + return c.diff.CallUnary(ctx, req) +} + // AdHocProfileServiceHandler is an implementation of the adhocprofiles.v1.AdHocProfileService // service. type AdHocProfileServiceHandler interface { @@ -127,6 +137,8 @@ type AdHocProfileServiceHandler interface { Get(context.Context, *connect.Request[v1.AdHocProfilesGetRequest]) (*connect.Response[v1.AdHocProfilesGetResponse], error) // Retrieves a list of profiles found in the underlying store. List(context.Context, *connect.Request[v1.AdHocProfilesListRequest]) (*connect.Response[v1.AdHocProfilesListResponse], error) + // Computes a diff flamegraph from two previously uploaded profiles. + Diff(context.Context, *connect.Request[v1.AdHocProfilesDiffRequest]) (*connect.Response[v1.AdHocProfilesDiffResponse], error) } // NewAdHocProfileServiceHandler builds an HTTP handler from the service implementation. It returns @@ -135,22 +147,29 @@ type AdHocProfileServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewAdHocProfileServiceHandler(svc AdHocProfileServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + adHocProfileServiceMethods := v1.File_adhocprofiles_v1_adhocprofiles_proto.Services().ByName("AdHocProfileService").Methods() adHocProfileServiceUploadHandler := connect.NewUnaryHandler( AdHocProfileServiceUploadProcedure, svc.Upload, - connect.WithSchema(adHocProfileServiceUploadMethodDescriptor), + connect.WithSchema(adHocProfileServiceMethods.ByName("Upload")), connect.WithHandlerOptions(opts...), ) adHocProfileServiceGetHandler := connect.NewUnaryHandler( AdHocProfileServiceGetProcedure, svc.Get, - connect.WithSchema(adHocProfileServiceGetMethodDescriptor), + connect.WithSchema(adHocProfileServiceMethods.ByName("Get")), connect.WithHandlerOptions(opts...), ) adHocProfileServiceListHandler := connect.NewUnaryHandler( AdHocProfileServiceListProcedure, svc.List, - connect.WithSchema(adHocProfileServiceListMethodDescriptor), + connect.WithSchema(adHocProfileServiceMethods.ByName("List")), + connect.WithHandlerOptions(opts...), + ) + adHocProfileServiceDiffHandler := connect.NewUnaryHandler( + AdHocProfileServiceDiffProcedure, + svc.Diff, + connect.WithSchema(adHocProfileServiceMethods.ByName("Diff")), connect.WithHandlerOptions(opts...), ) return "/adhocprofiles.v1.AdHocProfileService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -161,6 +180,8 @@ func NewAdHocProfileServiceHandler(svc AdHocProfileServiceHandler, opts ...conne adHocProfileServiceGetHandler.ServeHTTP(w, r) case AdHocProfileServiceListProcedure: adHocProfileServiceListHandler.ServeHTTP(w, r) + case AdHocProfileServiceDiffProcedure: + adHocProfileServiceDiffHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -181,3 +202,7 @@ func (UnimplementedAdHocProfileServiceHandler) Get(context.Context, *connect.Req func (UnimplementedAdHocProfileServiceHandler) List(context.Context, *connect.Request[v1.AdHocProfilesListRequest]) (*connect.Response[v1.AdHocProfilesListResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("adhocprofiles.v1.AdHocProfileService.List is not implemented")) } + +func (UnimplementedAdHocProfileServiceHandler) Diff(context.Context, *connect.Request[v1.AdHocProfilesDiffRequest]) (*connect.Response[v1.AdHocProfilesDiffResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("adhocprofiles.v1.AdHocProfileService.Diff is not implemented")) +} diff --git a/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.mux.go b/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.mux.go index 6984eb7543..3b621b429b 100644 --- a/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.mux.go +++ b/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect/adhocprofiles.connect.mux.go @@ -34,4 +34,9 @@ func RegisterAdHocProfileServiceHandler(mux *mux.Router, svc AdHocProfileService svc.List, opts..., )) + mux.Handle("/adhocprofiles.v1.AdHocProfileService/Diff", connect.NewUnaryHandler( + "/adhocprofiles.v1.AdHocProfileService/Diff", + svc.Diff, + opts..., + )) } diff --git a/api/gen/proto/go/capabilities/v1/capabilitiesv1connect/feature_flags.connect.go b/api/gen/proto/go/capabilities/v1/capabilitiesv1connect/feature_flags.connect.go new file mode 100644 index 0000000000..4eb3aa0fc1 --- /dev/null +++ b/api/gen/proto/go/capabilities/v1/capabilitiesv1connect/feature_flags.connect.go @@ -0,0 +1,112 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: capabilities/v1/feature_flags.proto + +package capabilitiesv1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/capabilities/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // FeatureFlagsServiceName is the fully-qualified name of the FeatureFlagsService service. + FeatureFlagsServiceName = "capabilities.v1.FeatureFlagsService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // FeatureFlagsServiceGetFeatureFlagsProcedure is the fully-qualified name of the + // FeatureFlagsService's GetFeatureFlags RPC. + FeatureFlagsServiceGetFeatureFlagsProcedure = "/capabilities.v1.FeatureFlagsService/GetFeatureFlags" +) + +// FeatureFlagsServiceClient is a client for the capabilities.v1.FeatureFlagsService service. +type FeatureFlagsServiceClient interface { + // Retrieve feature flags that are enabled for a particular tenant + GetFeatureFlags(context.Context, *connect.Request[v1.GetFeatureFlagsRequest]) (*connect.Response[v1.GetFeatureFlagsResponse], error) +} + +// NewFeatureFlagsServiceClient constructs a client for the capabilities.v1.FeatureFlagsService +// service. By default, it uses the Connect protocol with the binary Protobuf Codec, asks for +// gzipped responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply +// the connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewFeatureFlagsServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) FeatureFlagsServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + featureFlagsServiceMethods := v1.File_capabilities_v1_feature_flags_proto.Services().ByName("FeatureFlagsService").Methods() + return &featureFlagsServiceClient{ + getFeatureFlags: connect.NewClient[v1.GetFeatureFlagsRequest, v1.GetFeatureFlagsResponse]( + httpClient, + baseURL+FeatureFlagsServiceGetFeatureFlagsProcedure, + connect.WithSchema(featureFlagsServiceMethods.ByName("GetFeatureFlags")), + connect.WithClientOptions(opts...), + ), + } +} + +// featureFlagsServiceClient implements FeatureFlagsServiceClient. +type featureFlagsServiceClient struct { + getFeatureFlags *connect.Client[v1.GetFeatureFlagsRequest, v1.GetFeatureFlagsResponse] +} + +// GetFeatureFlags calls capabilities.v1.FeatureFlagsService.GetFeatureFlags. +func (c *featureFlagsServiceClient) GetFeatureFlags(ctx context.Context, req *connect.Request[v1.GetFeatureFlagsRequest]) (*connect.Response[v1.GetFeatureFlagsResponse], error) { + return c.getFeatureFlags.CallUnary(ctx, req) +} + +// FeatureFlagsServiceHandler is an implementation of the capabilities.v1.FeatureFlagsService +// service. +type FeatureFlagsServiceHandler interface { + // Retrieve feature flags that are enabled for a particular tenant + GetFeatureFlags(context.Context, *connect.Request[v1.GetFeatureFlagsRequest]) (*connect.Response[v1.GetFeatureFlagsResponse], error) +} + +// NewFeatureFlagsServiceHandler builds an HTTP handler from the service implementation. It returns +// the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewFeatureFlagsServiceHandler(svc FeatureFlagsServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + featureFlagsServiceMethods := v1.File_capabilities_v1_feature_flags_proto.Services().ByName("FeatureFlagsService").Methods() + featureFlagsServiceGetFeatureFlagsHandler := connect.NewUnaryHandler( + FeatureFlagsServiceGetFeatureFlagsProcedure, + svc.GetFeatureFlags, + connect.WithSchema(featureFlagsServiceMethods.ByName("GetFeatureFlags")), + connect.WithHandlerOptions(opts...), + ) + return "/capabilities.v1.FeatureFlagsService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case FeatureFlagsServiceGetFeatureFlagsProcedure: + featureFlagsServiceGetFeatureFlagsHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedFeatureFlagsServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedFeatureFlagsServiceHandler struct{} + +func (UnimplementedFeatureFlagsServiceHandler) GetFeatureFlags(context.Context, *connect.Request[v1.GetFeatureFlagsRequest]) (*connect.Response[v1.GetFeatureFlagsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("capabilities.v1.FeatureFlagsService.GetFeatureFlags is not implemented")) +} diff --git a/api/gen/proto/go/capabilities/v1/capabilitiesv1connect/feature_flags.connect.mux.go b/api/gen/proto/go/capabilities/v1/capabilitiesv1connect/feature_flags.connect.mux.go new file mode 100644 index 0000000000..af001978d0 --- /dev/null +++ b/api/gen/proto/go/capabilities/v1/capabilitiesv1connect/feature_flags.connect.mux.go @@ -0,0 +1,27 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: capabilities/v1/feature_flags.proto + +package capabilitiesv1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterFeatureFlagsServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterFeatureFlagsServiceHandler(mux *mux.Router, svc FeatureFlagsServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/capabilities.v1.FeatureFlagsService/GetFeatureFlags", connect.NewUnaryHandler( + "/capabilities.v1.FeatureFlagsService/GetFeatureFlags", + svc.GetFeatureFlags, + opts..., + )) +} diff --git a/api/gen/proto/go/capabilities/v1/feature_flags.pb.go b/api/gen/proto/go/capabilities/v1/feature_flags.pb.go new file mode 100644 index 0000000000..9f81bba338 --- /dev/null +++ b/api/gen/proto/go/capabilities/v1/feature_flags.pb.go @@ -0,0 +1,249 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: capabilities/v1/feature_flags.proto + +package capabilitiesv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetFeatureFlagsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFeatureFlagsRequest) Reset() { + *x = GetFeatureFlagsRequest{} + mi := &file_capabilities_v1_feature_flags_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFeatureFlagsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeatureFlagsRequest) ProtoMessage() {} + +func (x *GetFeatureFlagsRequest) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_v1_feature_flags_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeatureFlagsRequest.ProtoReflect.Descriptor instead. +func (*GetFeatureFlagsRequest) Descriptor() ([]byte, []int) { + return file_capabilities_v1_feature_flags_proto_rawDescGZIP(), []int{0} +} + +type GetFeatureFlagsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Map containing all features, also disable features are returned + FeatureFlags []*FeatureFlag `protobuf:"bytes,1,rep,name=feature_flags,json=featureFlags,proto3" json:"feature_flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFeatureFlagsResponse) Reset() { + *x = GetFeatureFlagsResponse{} + mi := &file_capabilities_v1_feature_flags_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFeatureFlagsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeatureFlagsResponse) ProtoMessage() {} + +func (x *GetFeatureFlagsResponse) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_v1_feature_flags_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeatureFlagsResponse.ProtoReflect.Descriptor instead. +func (*GetFeatureFlagsResponse) Descriptor() ([]byte, []int) { + return file_capabilities_v1_feature_flags_proto_rawDescGZIP(), []int{1} +} + +func (x *GetFeatureFlagsResponse) GetFeatureFlags() []*FeatureFlag { + if x != nil { + return x.FeatureFlags + } + return nil +} + +// FeatureParameters contains the per feature flag parameters. +type FeatureFlag struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Name of the feature, please use lower camel case. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Wether the feature flag is enabled or disabled. + Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled,omitempty"` + // Optional description of the feature flag. + Description *string `protobuf:"bytes,3,opt,name=description,proto3,oneof" json:"description,omitempty"` + // Optional URL to the documentation page of the feature flag. + DocumentationUrl *string `protobuf:"bytes,4,opt,name=documentation_url,json=documentationUrl,proto3,oneof" json:"documentation_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FeatureFlag) Reset() { + *x = FeatureFlag{} + mi := &file_capabilities_v1_feature_flags_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FeatureFlag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FeatureFlag) ProtoMessage() {} + +func (x *FeatureFlag) ProtoReflect() protoreflect.Message { + mi := &file_capabilities_v1_feature_flags_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FeatureFlag.ProtoReflect.Descriptor instead. +func (*FeatureFlag) Descriptor() ([]byte, []int) { + return file_capabilities_v1_feature_flags_proto_rawDescGZIP(), []int{2} +} + +func (x *FeatureFlag) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *FeatureFlag) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *FeatureFlag) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +func (x *FeatureFlag) GetDocumentationUrl() string { + if x != nil && x.DocumentationUrl != nil { + return *x.DocumentationUrl + } + return "" +} + +var File_capabilities_v1_feature_flags_proto protoreflect.FileDescriptor + +const file_capabilities_v1_feature_flags_proto_rawDesc = "" + + "\n" + + "#capabilities/v1/feature_flags.proto\x12\x0fcapabilities.v1\"\x18\n" + + "\x16GetFeatureFlagsRequest\"\\\n" + + "\x17GetFeatureFlagsResponse\x12A\n" + + "\rfeature_flags\x18\x01 \x03(\v2\x1c.capabilities.v1.FeatureFlagR\ffeatureFlags\"\xba\x01\n" + + "\vFeatureFlag\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + + "\aenabled\x18\x02 \x01(\bR\aenabled\x12%\n" + + "\vdescription\x18\x03 \x01(\tH\x00R\vdescription\x88\x01\x01\x120\n" + + "\x11documentation_url\x18\x04 \x01(\tH\x01R\x10documentationUrl\x88\x01\x01B\x0e\n" + + "\f_descriptionB\x14\n" + + "\x12_documentation_url2}\n" + + "\x13FeatureFlagsService\x12f\n" + + "\x0fGetFeatureFlags\x12'.capabilities.v1.GetFeatureFlagsRequest\x1a(.capabilities.v1.GetFeatureFlagsResponse\"\x00B\xd3\x01\n" + + "\x13com.capabilities.v1B\x11FeatureFlagsProtoP\x01ZLgithub.com/grafana/pyroscope/api/gen/proto/go/capabilities/v1;capabilitiesv1\xa2\x02\x03CXX\xaa\x02\x0fCapabilities.V1\xca\x02\x0fCapabilities\\V1\xe2\x02\x1bCapabilities\\V1\\GPBMetadata\xea\x02\x10Capabilities::V1b\x06proto3" + +var ( + file_capabilities_v1_feature_flags_proto_rawDescOnce sync.Once + file_capabilities_v1_feature_flags_proto_rawDescData []byte +) + +func file_capabilities_v1_feature_flags_proto_rawDescGZIP() []byte { + file_capabilities_v1_feature_flags_proto_rawDescOnce.Do(func() { + file_capabilities_v1_feature_flags_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_capabilities_v1_feature_flags_proto_rawDesc), len(file_capabilities_v1_feature_flags_proto_rawDesc))) + }) + return file_capabilities_v1_feature_flags_proto_rawDescData +} + +var file_capabilities_v1_feature_flags_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_capabilities_v1_feature_flags_proto_goTypes = []any{ + (*GetFeatureFlagsRequest)(nil), // 0: capabilities.v1.GetFeatureFlagsRequest + (*GetFeatureFlagsResponse)(nil), // 1: capabilities.v1.GetFeatureFlagsResponse + (*FeatureFlag)(nil), // 2: capabilities.v1.FeatureFlag +} +var file_capabilities_v1_feature_flags_proto_depIdxs = []int32{ + 2, // 0: capabilities.v1.GetFeatureFlagsResponse.feature_flags:type_name -> capabilities.v1.FeatureFlag + 0, // 1: capabilities.v1.FeatureFlagsService.GetFeatureFlags:input_type -> capabilities.v1.GetFeatureFlagsRequest + 1, // 2: capabilities.v1.FeatureFlagsService.GetFeatureFlags:output_type -> capabilities.v1.GetFeatureFlagsResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_capabilities_v1_feature_flags_proto_init() } +func file_capabilities_v1_feature_flags_proto_init() { + if File_capabilities_v1_feature_flags_proto != nil { + return + } + file_capabilities_v1_feature_flags_proto_msgTypes[2].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_capabilities_v1_feature_flags_proto_rawDesc), len(file_capabilities_v1_feature_flags_proto_rawDesc)), + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_capabilities_v1_feature_flags_proto_goTypes, + DependencyIndexes: file_capabilities_v1_feature_flags_proto_depIdxs, + MessageInfos: file_capabilities_v1_feature_flags_proto_msgTypes, + }.Build() + File_capabilities_v1_feature_flags_proto = out.File + file_capabilities_v1_feature_flags_proto_goTypes = nil + file_capabilities_v1_feature_flags_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/capabilities/v1/feature_flags_vtproto.pb.go b/api/gen/proto/go/capabilities/v1/feature_flags_vtproto.pb.go new file mode 100644 index 0000000000..4093ae08ba --- /dev/null +++ b/api/gen/proto/go/capabilities/v1/feature_flags_vtproto.pb.go @@ -0,0 +1,759 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: capabilities/v1/feature_flags.proto + +package capabilitiesv1 + +import ( + context "context" + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *GetFeatureFlagsRequest) CloneVT() *GetFeatureFlagsRequest { + if m == nil { + return (*GetFeatureFlagsRequest)(nil) + } + r := new(GetFeatureFlagsRequest) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetFeatureFlagsRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetFeatureFlagsResponse) CloneVT() *GetFeatureFlagsResponse { + if m == nil { + return (*GetFeatureFlagsResponse)(nil) + } + r := new(GetFeatureFlagsResponse) + if rhs := m.FeatureFlags; rhs != nil { + tmpContainer := make([]*FeatureFlag, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.FeatureFlags = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetFeatureFlagsResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *FeatureFlag) CloneVT() *FeatureFlag { + if m == nil { + return (*FeatureFlag)(nil) + } + r := new(FeatureFlag) + r.Name = m.Name + r.Enabled = m.Enabled + if rhs := m.Description; rhs != nil { + tmpVal := *rhs + r.Description = &tmpVal + } + if rhs := m.DocumentationUrl; rhs != nil { + tmpVal := *rhs + r.DocumentationUrl = &tmpVal + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *FeatureFlag) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *GetFeatureFlagsRequest) EqualVT(that *GetFeatureFlagsRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetFeatureFlagsRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetFeatureFlagsRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetFeatureFlagsResponse) EqualVT(that *GetFeatureFlagsResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.FeatureFlags) != len(that.FeatureFlags) { + return false + } + for i, vx := range this.FeatureFlags { + vy := that.FeatureFlags[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &FeatureFlag{} + } + if q == nil { + q = &FeatureFlag{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetFeatureFlagsResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetFeatureFlagsResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *FeatureFlag) EqualVT(that *FeatureFlag) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Enabled != that.Enabled { + return false + } + if p, q := this.Description, that.Description; (p == nil && q != nil) || (p != nil && (q == nil || *p != *q)) { + return false + } + if p, q := this.DocumentationUrl, that.DocumentationUrl; (p == nil && q != nil) || (p != nil && (q == nil || *p != *q)) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *FeatureFlag) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*FeatureFlag) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// FeatureFlagsServiceClient is the client API for FeatureFlagsService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type FeatureFlagsServiceClient interface { + // Retrieve feature flags that are enabled for a particular tenant + GetFeatureFlags(ctx context.Context, in *GetFeatureFlagsRequest, opts ...grpc.CallOption) (*GetFeatureFlagsResponse, error) +} + +type featureFlagsServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewFeatureFlagsServiceClient(cc grpc.ClientConnInterface) FeatureFlagsServiceClient { + return &featureFlagsServiceClient{cc} +} + +func (c *featureFlagsServiceClient) GetFeatureFlags(ctx context.Context, in *GetFeatureFlagsRequest, opts ...grpc.CallOption) (*GetFeatureFlagsResponse, error) { + out := new(GetFeatureFlagsResponse) + err := c.cc.Invoke(ctx, "/capabilities.v1.FeatureFlagsService/GetFeatureFlags", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FeatureFlagsServiceServer is the server API for FeatureFlagsService service. +// All implementations must embed UnimplementedFeatureFlagsServiceServer +// for forward compatibility +type FeatureFlagsServiceServer interface { + // Retrieve feature flags that are enabled for a particular tenant + GetFeatureFlags(context.Context, *GetFeatureFlagsRequest) (*GetFeatureFlagsResponse, error) + mustEmbedUnimplementedFeatureFlagsServiceServer() +} + +// UnimplementedFeatureFlagsServiceServer must be embedded to have forward compatible implementations. +type UnimplementedFeatureFlagsServiceServer struct { +} + +func (UnimplementedFeatureFlagsServiceServer) GetFeatureFlags(context.Context, *GetFeatureFlagsRequest) (*GetFeatureFlagsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFeatureFlags not implemented") +} +func (UnimplementedFeatureFlagsServiceServer) mustEmbedUnimplementedFeatureFlagsServiceServer() {} + +// UnsafeFeatureFlagsServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to FeatureFlagsServiceServer will +// result in compilation errors. +type UnsafeFeatureFlagsServiceServer interface { + mustEmbedUnimplementedFeatureFlagsServiceServer() +} + +func RegisterFeatureFlagsServiceServer(s grpc.ServiceRegistrar, srv FeatureFlagsServiceServer) { + s.RegisterService(&FeatureFlagsService_ServiceDesc, srv) +} + +func _FeatureFlagsService_GetFeatureFlags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFeatureFlagsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FeatureFlagsServiceServer).GetFeatureFlags(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/capabilities.v1.FeatureFlagsService/GetFeatureFlags", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FeatureFlagsServiceServer).GetFeatureFlags(ctx, req.(*GetFeatureFlagsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// FeatureFlagsService_ServiceDesc is the grpc.ServiceDesc for FeatureFlagsService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var FeatureFlagsService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "capabilities.v1.FeatureFlagsService", + HandlerType: (*FeatureFlagsServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetFeatureFlags", + Handler: _FeatureFlagsService_GetFeatureFlags_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "capabilities/v1/feature_flags.proto", +} + +func (m *GetFeatureFlagsRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetFeatureFlagsRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetFeatureFlagsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *GetFeatureFlagsResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetFeatureFlagsResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetFeatureFlagsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.FeatureFlags) > 0 { + for iNdEx := len(m.FeatureFlags) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.FeatureFlags[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *FeatureFlag) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FeatureFlag) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *FeatureFlag) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.DocumentationUrl != nil { + i -= len(*m.DocumentationUrl) + copy(dAtA[i:], *m.DocumentationUrl) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(*m.DocumentationUrl))) + i-- + dAtA[i] = 0x22 + } + if m.Description != nil { + i -= len(*m.Description) + copy(dAtA[i:], *m.Description) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(*m.Description))) + i-- + dAtA[i] = 0x1a + } + if m.Enabled { + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetFeatureFlagsRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *GetFeatureFlagsResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.FeatureFlags) > 0 { + for _, e := range m.FeatureFlags { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *FeatureFlag) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Enabled { + n += 2 + } + if m.Description != nil { + l = len(*m.Description) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.DocumentationUrl != nil { + l = len(*m.DocumentationUrl) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *GetFeatureFlagsRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetFeatureFlagsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetFeatureFlagsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetFeatureFlagsResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetFeatureFlagsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetFeatureFlagsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeatureFlags", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeatureFlags = append(m.FeatureFlags, &FeatureFlag{}) + if err := m.FeatureFlags[len(m.FeatureFlags)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FeatureFlag) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FeatureFlag: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FeatureFlag: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Enabled = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Description = &s + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DocumentationUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.DocumentationUrl = &s + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/debuginfo/v1alpha1/debuginfo.pb.go b/api/gen/proto/go/debuginfo/v1alpha1/debuginfo.pb.go new file mode 100644 index 0000000000..cb72ba6ea0 --- /dev/null +++ b/api/gen/proto/go/debuginfo/v1alpha1/debuginfo.pb.go @@ -0,0 +1,744 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: debuginfo/v1alpha1/debuginfo.proto + +package debuginfov1alpha1 + +import ( + _ "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type FileMetadata_Type int32 + +const ( + FileMetadata_TYPE_UNSPECIFIED FileMetadata_Type = 0 + FileMetadata_TYPE_EXECUTABLE_FULL FileMetadata_Type = 1 + FileMetadata_TYPE_EXECUTABLE_NO_TEXT FileMetadata_Type = 2 +) + +// Enum value maps for FileMetadata_Type. +var ( + FileMetadata_Type_name = map[int32]string{ + 0: "TYPE_UNSPECIFIED", + 1: "TYPE_EXECUTABLE_FULL", + 2: "TYPE_EXECUTABLE_NO_TEXT", + } + FileMetadata_Type_value = map[string]int32{ + "TYPE_UNSPECIFIED": 0, + "TYPE_EXECUTABLE_FULL": 1, + "TYPE_EXECUTABLE_NO_TEXT": 2, + } +) + +func (x FileMetadata_Type) Enum() *FileMetadata_Type { + p := new(FileMetadata_Type) + *p = x + return p +} + +func (x FileMetadata_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (FileMetadata_Type) Descriptor() protoreflect.EnumDescriptor { + return file_debuginfo_v1alpha1_debuginfo_proto_enumTypes[0].Descriptor() +} + +func (FileMetadata_Type) Type() protoreflect.EnumType { + return &file_debuginfo_v1alpha1_debuginfo_proto_enumTypes[0] +} + +func (x FileMetadata_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use FileMetadata_Type.Descriptor instead. +func (FileMetadata_Type) EnumDescriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{0, 0} +} + +type ObjectMetadata_State int32 + +const ( + ObjectMetadata_STATE_UPLOADING ObjectMetadata_State = 0 + ObjectMetadata_STATE_UPLOADED ObjectMetadata_State = 1 +) + +// Enum value maps for ObjectMetadata_State. +var ( + ObjectMetadata_State_name = map[int32]string{ + 0: "STATE_UPLOADING", + 1: "STATE_UPLOADED", + } + ObjectMetadata_State_value = map[string]int32{ + "STATE_UPLOADING": 0, + "STATE_UPLOADED": 1, + } +) + +func (x ObjectMetadata_State) Enum() *ObjectMetadata_State { + p := new(ObjectMetadata_State) + *p = x + return p +} + +func (x ObjectMetadata_State) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ObjectMetadata_State) Descriptor() protoreflect.EnumDescriptor { + return file_debuginfo_v1alpha1_debuginfo_proto_enumTypes[1].Descriptor() +} + +func (ObjectMetadata_State) Type() protoreflect.EnumType { + return &file_debuginfo_v1alpha1_debuginfo_proto_enumTypes[1] +} + +func (x ObjectMetadata_State) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ObjectMetadata_State.Descriptor instead. +func (ObjectMetadata_State) EnumDescriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{9, 0} +} + +type FileMetadata struct { + state protoimpl.MessageState `protogen:"open.v1"` + // GNU build ID of the executable. + GnuBuildId string `protobuf:"bytes,1,opt,name=gnu_build_id,json=gnuBuildId,proto3" json:"gnu_build_id,omitempty"` + // Go build ID of the executable. + GoBuildId string `protobuf:"bytes,2,opt,name=go_build_id,json=goBuildId,proto3" json:"go_build_id,omitempty"` + // Optional libpf.FileID from the otel profiler. + OtelFileId string `protobuf:"bytes,3,opt,name=otel_file_id,json=otelFileId,proto3" json:"otel_file_id,omitempty"` + // Original file name of the executable. + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + // Type of the debug info. + Type FileMetadata_Type `protobuf:"varint,5,opt,name=type,proto3,enum=debuginfo.v1alpha1.FileMetadata_Type" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FileMetadata) Reset() { + *x = FileMetadata{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FileMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FileMetadata) ProtoMessage() {} + +func (x *FileMetadata) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FileMetadata.ProtoReflect.Descriptor instead. +func (*FileMetadata) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{0} +} + +func (x *FileMetadata) GetGnuBuildId() string { + if x != nil { + return x.GnuBuildId + } + return "" +} + +func (x *FileMetadata) GetGoBuildId() string { + if x != nil { + return x.GoBuildId + } + return "" +} + +func (x *FileMetadata) GetOtelFileId() string { + if x != nil { + return x.OtelFileId + } + return "" +} + +func (x *FileMetadata) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *FileMetadata) GetType() FileMetadata_Type { + if x != nil { + return x.Type + } + return FileMetadata_TYPE_UNSPECIFIED +} + +type ShouldInitiateUploadRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + File *FileMetadata `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ShouldInitiateUploadRequest) Reset() { + *x = ShouldInitiateUploadRequest{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ShouldInitiateUploadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShouldInitiateUploadRequest) ProtoMessage() {} + +func (x *ShouldInitiateUploadRequest) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShouldInitiateUploadRequest.ProtoReflect.Descriptor instead. +func (*ShouldInitiateUploadRequest) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{1} +} + +func (x *ShouldInitiateUploadRequest) GetFile() *FileMetadata { + if x != nil { + return x.File + } + return nil +} + +type ShouldInitiateUploadResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + ShouldInitiateUpload bool `protobuf:"varint,1,opt,name=should_initiate_upload,json=shouldInitiateUpload,proto3" json:"should_initiate_upload,omitempty"` + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ShouldInitiateUploadResponse) Reset() { + *x = ShouldInitiateUploadResponse{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ShouldInitiateUploadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShouldInitiateUploadResponse) ProtoMessage() {} + +func (x *ShouldInitiateUploadResponse) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShouldInitiateUploadResponse.ProtoReflect.Descriptor instead. +func (*ShouldInitiateUploadResponse) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{2} +} + +func (x *ShouldInitiateUploadResponse) GetShouldInitiateUpload() bool { + if x != nil { + return x.ShouldInitiateUpload + } + return false +} + +func (x *ShouldInitiateUploadResponse) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +type UploadFinishedRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + GnuBuildId string `protobuf:"bytes,1,opt,name=gnu_build_id,json=gnuBuildId,proto3" json:"gnu_build_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadFinishedRequest) Reset() { + *x = UploadFinishedRequest{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadFinishedRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadFinishedRequest) ProtoMessage() {} + +func (x *UploadFinishedRequest) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadFinishedRequest.ProtoReflect.Descriptor instead. +func (*UploadFinishedRequest) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{3} +} + +func (x *UploadFinishedRequest) GetGnuBuildId() string { + if x != nil { + return x.GnuBuildId + } + return "" +} + +type UploadFinishedResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadFinishedResponse) Reset() { + *x = UploadFinishedResponse{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadFinishedResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadFinishedResponse) ProtoMessage() {} + +func (x *UploadFinishedResponse) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadFinishedResponse.ProtoReflect.Descriptor instead. +func (*UploadFinishedResponse) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{4} +} + +type ListDebuginfoRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListDebuginfoRequest) Reset() { + *x = ListDebuginfoRequest{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListDebuginfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListDebuginfoRequest) ProtoMessage() {} + +func (x *ListDebuginfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListDebuginfoRequest.ProtoReflect.Descriptor instead. +func (*ListDebuginfoRequest) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{5} +} + +type ListDebuginfoResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Object []*ObjectMetadata `protobuf:"bytes,1,rep,name=object,proto3" json:"object,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListDebuginfoResponse) Reset() { + *x = ListDebuginfoResponse{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListDebuginfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListDebuginfoResponse) ProtoMessage() {} + +func (x *ListDebuginfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListDebuginfoResponse.ProtoReflect.Descriptor instead. +func (*ListDebuginfoResponse) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{6} +} + +func (x *ListDebuginfoResponse) GetObject() []*ObjectMetadata { + if x != nil { + return x.Object + } + return nil +} + +type DeleteDebuginfoRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + GnuBuildId string `protobuf:"bytes,1,opt,name=gnu_build_id,json=gnuBuildId,proto3" json:"gnu_build_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteDebuginfoRequest) Reset() { + *x = DeleteDebuginfoRequest{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteDebuginfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteDebuginfoRequest) ProtoMessage() {} + +func (x *DeleteDebuginfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteDebuginfoRequest.ProtoReflect.Descriptor instead. +func (*DeleteDebuginfoRequest) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{7} +} + +func (x *DeleteDebuginfoRequest) GetGnuBuildId() string { + if x != nil { + return x.GnuBuildId + } + return "" +} + +type DeleteDebuginfoResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteDebuginfoResponse) Reset() { + *x = DeleteDebuginfoResponse{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteDebuginfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteDebuginfoResponse) ProtoMessage() {} + +func (x *DeleteDebuginfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteDebuginfoResponse.ProtoReflect.Descriptor instead. +func (*DeleteDebuginfoResponse) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{8} +} + +// This is stored in buckets at "debug-info/$tenant/$gnu_build_id/metadata" +// Along with the actual uploaded file at "debug-info/$tenant/$gnu_build_id/exe" +type ObjectMetadata struct { + state protoimpl.MessageState `protogen:"open.v1"` + File *FileMetadata `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` + State ObjectMetadata_State `protobuf:"varint,2,opt,name=state,proto3,enum=debuginfo.v1alpha1.ObjectMetadata_State" json:"state,omitempty"` + StartedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"` + FinishedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=finished_at,json=finishedAt,proto3" json:"finished_at,omitempty"` + // Size of the uploaded ELF file in bytes. + SizeBytes int64 `protobuf:"varint,5,opt,name=size_bytes,json=sizeBytes,proto3" json:"size_bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ObjectMetadata) Reset() { + *x = ObjectMetadata{} + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ObjectMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectMetadata) ProtoMessage() {} + +func (x *ObjectMetadata) ProtoReflect() protoreflect.Message { + mi := &file_debuginfo_v1alpha1_debuginfo_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectMetadata.ProtoReflect.Descriptor instead. +func (*ObjectMetadata) Descriptor() ([]byte, []int) { + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP(), []int{9} +} + +func (x *ObjectMetadata) GetFile() *FileMetadata { + if x != nil { + return x.File + } + return nil +} + +func (x *ObjectMetadata) GetState() ObjectMetadata_State { + if x != nil { + return x.State + } + return ObjectMetadata_STATE_UPLOADING +} + +func (x *ObjectMetadata) GetStartedAt() *timestamppb.Timestamp { + if x != nil { + return x.StartedAt + } + return nil +} + +func (x *ObjectMetadata) GetFinishedAt() *timestamppb.Timestamp { + if x != nil { + return x.FinishedAt + } + return nil +} + +func (x *ObjectMetadata) GetSizeBytes() int64 { + if x != nil { + return x.SizeBytes + } + return 0 +} + +var File_debuginfo_v1alpha1_debuginfo_proto protoreflect.FileDescriptor + +const file_debuginfo_v1alpha1_debuginfo_proto_rawDesc = "" + + "\n" + + "\"debuginfo/v1alpha1/debuginfo.proto\x12\x12debuginfo.v1alpha1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14types/v1/types.proto\"\x96\x02\n" + + "\fFileMetadata\x12 \n" + + "\fgnu_build_id\x18\x01 \x01(\tR\n" + + "gnuBuildId\x12\x1e\n" + + "\vgo_build_id\x18\x02 \x01(\tR\tgoBuildId\x12 \n" + + "\fotel_file_id\x18\x03 \x01(\tR\n" + + "otelFileId\x12\x12\n" + + "\x04name\x18\x04 \x01(\tR\x04name\x129\n" + + "\x04type\x18\x05 \x01(\x0e2%.debuginfo.v1alpha1.FileMetadata.TypeR\x04type\"S\n" + + "\x04Type\x12\x14\n" + + "\x10TYPE_UNSPECIFIED\x10\x00\x12\x18\n" + + "\x14TYPE_EXECUTABLE_FULL\x10\x01\x12\x1b\n" + + "\x17TYPE_EXECUTABLE_NO_TEXT\x10\x02\"S\n" + + "\x1bShouldInitiateUploadRequest\x124\n" + + "\x04file\x18\x01 \x01(\v2 .debuginfo.v1alpha1.FileMetadataR\x04file\"l\n" + + "\x1cShouldInitiateUploadResponse\x124\n" + + "\x16should_initiate_upload\x18\x01 \x01(\bR\x14shouldInitiateUpload\x12\x16\n" + + "\x06reason\x18\x02 \x01(\tR\x06reason\"9\n" + + "\x15UploadFinishedRequest\x12 \n" + + "\fgnu_build_id\x18\x01 \x01(\tR\n" + + "gnuBuildId\"\x18\n" + + "\x16UploadFinishedResponse\"\x16\n" + + "\x14ListDebuginfoRequest\"S\n" + + "\x15ListDebuginfoResponse\x12:\n" + + "\x06object\x18\x01 \x03(\v2\".debuginfo.v1alpha1.ObjectMetadataR\x06object\":\n" + + "\x16DeleteDebuginfoRequest\x12 \n" + + "\fgnu_build_id\x18\x01 \x01(\tR\n" + + "gnuBuildId\"\x19\n" + + "\x17DeleteDebuginfoResponse\"\xcf\x02\n" + + "\x0eObjectMetadata\x124\n" + + "\x04file\x18\x01 \x01(\v2 .debuginfo.v1alpha1.FileMetadataR\x04file\x12>\n" + + "\x05state\x18\x02 \x01(\x0e2(.debuginfo.v1alpha1.ObjectMetadata.StateR\x05state\x129\n" + + "\n" + + "started_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12;\n" + + "\vfinished_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "finishedAt\x12\x1d\n" + + "\n" + + "size_bytes\x18\x05 \x01(\x03R\tsizeBytes\"0\n" + + "\x05State\x12\x13\n" + + "\x0fSTATE_UPLOADING\x10\x00\x12\x12\n" + + "\x0eSTATE_UPLOADED\x10\x012\xd0\x03\n" + + "\x10DebuginfoService\x12{\n" + + "\x14ShouldInitiateUpload\x12/.debuginfo.v1alpha1.ShouldInitiateUploadRequest\x1a0.debuginfo.v1alpha1.ShouldInitiateUploadResponse\"\x00\x12i\n" + + "\x0eUploadFinished\x12).debuginfo.v1alpha1.UploadFinishedRequest\x1a*.debuginfo.v1alpha1.UploadFinishedResponse\"\x00\x12f\n" + + "\rListDebuginfo\x12(.debuginfo.v1alpha1.ListDebuginfoRequest\x1a).debuginfo.v1alpha1.ListDebuginfoResponse\"\x00\x12l\n" + + "\x0fDeleteDebuginfo\x12*.debuginfo.v1alpha1.DeleteDebuginfoRequest\x1a+.debuginfo.v1alpha1.DeleteDebuginfoResponse\"\x00B\xe5\x01\n" + + "\x16com.debuginfo.v1alpha1B\x0eDebuginfoProtoP\x01ZRgithub.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1;debuginfov1alpha1\xa2\x02\x03DXX\xaa\x02\x12Debuginfo.V1alpha1\xca\x02\x12Debuginfo\\V1alpha1\xe2\x02\x1eDebuginfo\\V1alpha1\\GPBMetadata\xea\x02\x13Debuginfo::V1alpha1b\x06proto3" + +var ( + file_debuginfo_v1alpha1_debuginfo_proto_rawDescOnce sync.Once + file_debuginfo_v1alpha1_debuginfo_proto_rawDescData []byte +) + +func file_debuginfo_v1alpha1_debuginfo_proto_rawDescGZIP() []byte { + file_debuginfo_v1alpha1_debuginfo_proto_rawDescOnce.Do(func() { + file_debuginfo_v1alpha1_debuginfo_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_debuginfo_v1alpha1_debuginfo_proto_rawDesc), len(file_debuginfo_v1alpha1_debuginfo_proto_rawDesc))) + }) + return file_debuginfo_v1alpha1_debuginfo_proto_rawDescData +} + +var file_debuginfo_v1alpha1_debuginfo_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_debuginfo_v1alpha1_debuginfo_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_debuginfo_v1alpha1_debuginfo_proto_goTypes = []any{ + (FileMetadata_Type)(0), // 0: debuginfo.v1alpha1.FileMetadata.Type + (ObjectMetadata_State)(0), // 1: debuginfo.v1alpha1.ObjectMetadata.State + (*FileMetadata)(nil), // 2: debuginfo.v1alpha1.FileMetadata + (*ShouldInitiateUploadRequest)(nil), // 3: debuginfo.v1alpha1.ShouldInitiateUploadRequest + (*ShouldInitiateUploadResponse)(nil), // 4: debuginfo.v1alpha1.ShouldInitiateUploadResponse + (*UploadFinishedRequest)(nil), // 5: debuginfo.v1alpha1.UploadFinishedRequest + (*UploadFinishedResponse)(nil), // 6: debuginfo.v1alpha1.UploadFinishedResponse + (*ListDebuginfoRequest)(nil), // 7: debuginfo.v1alpha1.ListDebuginfoRequest + (*ListDebuginfoResponse)(nil), // 8: debuginfo.v1alpha1.ListDebuginfoResponse + (*DeleteDebuginfoRequest)(nil), // 9: debuginfo.v1alpha1.DeleteDebuginfoRequest + (*DeleteDebuginfoResponse)(nil), // 10: debuginfo.v1alpha1.DeleteDebuginfoResponse + (*ObjectMetadata)(nil), // 11: debuginfo.v1alpha1.ObjectMetadata + (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp +} +var file_debuginfo_v1alpha1_debuginfo_proto_depIdxs = []int32{ + 0, // 0: debuginfo.v1alpha1.FileMetadata.type:type_name -> debuginfo.v1alpha1.FileMetadata.Type + 2, // 1: debuginfo.v1alpha1.ShouldInitiateUploadRequest.file:type_name -> debuginfo.v1alpha1.FileMetadata + 11, // 2: debuginfo.v1alpha1.ListDebuginfoResponse.object:type_name -> debuginfo.v1alpha1.ObjectMetadata + 2, // 3: debuginfo.v1alpha1.ObjectMetadata.file:type_name -> debuginfo.v1alpha1.FileMetadata + 1, // 4: debuginfo.v1alpha1.ObjectMetadata.state:type_name -> debuginfo.v1alpha1.ObjectMetadata.State + 12, // 5: debuginfo.v1alpha1.ObjectMetadata.started_at:type_name -> google.protobuf.Timestamp + 12, // 6: debuginfo.v1alpha1.ObjectMetadata.finished_at:type_name -> google.protobuf.Timestamp + 3, // 7: debuginfo.v1alpha1.DebuginfoService.ShouldInitiateUpload:input_type -> debuginfo.v1alpha1.ShouldInitiateUploadRequest + 5, // 8: debuginfo.v1alpha1.DebuginfoService.UploadFinished:input_type -> debuginfo.v1alpha1.UploadFinishedRequest + 7, // 9: debuginfo.v1alpha1.DebuginfoService.ListDebuginfo:input_type -> debuginfo.v1alpha1.ListDebuginfoRequest + 9, // 10: debuginfo.v1alpha1.DebuginfoService.DeleteDebuginfo:input_type -> debuginfo.v1alpha1.DeleteDebuginfoRequest + 4, // 11: debuginfo.v1alpha1.DebuginfoService.ShouldInitiateUpload:output_type -> debuginfo.v1alpha1.ShouldInitiateUploadResponse + 6, // 12: debuginfo.v1alpha1.DebuginfoService.UploadFinished:output_type -> debuginfo.v1alpha1.UploadFinishedResponse + 8, // 13: debuginfo.v1alpha1.DebuginfoService.ListDebuginfo:output_type -> debuginfo.v1alpha1.ListDebuginfoResponse + 10, // 14: debuginfo.v1alpha1.DebuginfoService.DeleteDebuginfo:output_type -> debuginfo.v1alpha1.DeleteDebuginfoResponse + 11, // [11:15] is the sub-list for method output_type + 7, // [7:11] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_debuginfo_v1alpha1_debuginfo_proto_init() } +func file_debuginfo_v1alpha1_debuginfo_proto_init() { + if File_debuginfo_v1alpha1_debuginfo_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_debuginfo_v1alpha1_debuginfo_proto_rawDesc), len(file_debuginfo_v1alpha1_debuginfo_proto_rawDesc)), + NumEnums: 2, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_debuginfo_v1alpha1_debuginfo_proto_goTypes, + DependencyIndexes: file_debuginfo_v1alpha1_debuginfo_proto_depIdxs, + EnumInfos: file_debuginfo_v1alpha1_debuginfo_proto_enumTypes, + MessageInfos: file_debuginfo_v1alpha1_debuginfo_proto_msgTypes, + }.Build() + File_debuginfo_v1alpha1_debuginfo_proto = out.File + file_debuginfo_v1alpha1_debuginfo_proto_goTypes = nil + file_debuginfo_v1alpha1_debuginfo_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/debuginfo/v1alpha1/debuginfo_vtproto.pb.go b/api/gen/proto/go/debuginfo/v1alpha1/debuginfo_vtproto.pb.go new file mode 100644 index 0000000000..c0f6440bfd --- /dev/null +++ b/api/gen/proto/go/debuginfo/v1alpha1/debuginfo_vtproto.pb.go @@ -0,0 +1,2238 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: debuginfo/v1alpha1/debuginfo.proto + +package debuginfov1alpha1 + +import ( + context "context" + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + timestamppb1 "github.com/planetscale/vtprotobuf/types/known/timestamppb" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *FileMetadata) CloneVT() *FileMetadata { + if m == nil { + return (*FileMetadata)(nil) + } + r := new(FileMetadata) + r.GnuBuildId = m.GnuBuildId + r.GoBuildId = m.GoBuildId + r.OtelFileId = m.OtelFileId + r.Name = m.Name + r.Type = m.Type + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *FileMetadata) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ShouldInitiateUploadRequest) CloneVT() *ShouldInitiateUploadRequest { + if m == nil { + return (*ShouldInitiateUploadRequest)(nil) + } + r := new(ShouldInitiateUploadRequest) + r.File = m.File.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ShouldInitiateUploadRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ShouldInitiateUploadResponse) CloneVT() *ShouldInitiateUploadResponse { + if m == nil { + return (*ShouldInitiateUploadResponse)(nil) + } + r := new(ShouldInitiateUploadResponse) + r.ShouldInitiateUpload = m.ShouldInitiateUpload + r.Reason = m.Reason + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ShouldInitiateUploadResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *UploadFinishedRequest) CloneVT() *UploadFinishedRequest { + if m == nil { + return (*UploadFinishedRequest)(nil) + } + r := new(UploadFinishedRequest) + r.GnuBuildId = m.GnuBuildId + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *UploadFinishedRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *UploadFinishedResponse) CloneVT() *UploadFinishedResponse { + if m == nil { + return (*UploadFinishedResponse)(nil) + } + r := new(UploadFinishedResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *UploadFinishedResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ListDebuginfoRequest) CloneVT() *ListDebuginfoRequest { + if m == nil { + return (*ListDebuginfoRequest)(nil) + } + r := new(ListDebuginfoRequest) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ListDebuginfoRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ListDebuginfoResponse) CloneVT() *ListDebuginfoResponse { + if m == nil { + return (*ListDebuginfoResponse)(nil) + } + r := new(ListDebuginfoResponse) + if rhs := m.Object; rhs != nil { + tmpContainer := make([]*ObjectMetadata, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Object = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ListDebuginfoResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *DeleteDebuginfoRequest) CloneVT() *DeleteDebuginfoRequest { + if m == nil { + return (*DeleteDebuginfoRequest)(nil) + } + r := new(DeleteDebuginfoRequest) + r.GnuBuildId = m.GnuBuildId + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteDebuginfoRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *DeleteDebuginfoResponse) CloneVT() *DeleteDebuginfoResponse { + if m == nil { + return (*DeleteDebuginfoResponse)(nil) + } + r := new(DeleteDebuginfoResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteDebuginfoResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ObjectMetadata) CloneVT() *ObjectMetadata { + if m == nil { + return (*ObjectMetadata)(nil) + } + r := new(ObjectMetadata) + r.File = m.File.CloneVT() + r.State = m.State + r.StartedAt = (*timestamppb.Timestamp)((*timestamppb1.Timestamp)(m.StartedAt).CloneVT()) + r.FinishedAt = (*timestamppb.Timestamp)((*timestamppb1.Timestamp)(m.FinishedAt).CloneVT()) + r.SizeBytes = m.SizeBytes + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ObjectMetadata) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *FileMetadata) EqualVT(that *FileMetadata) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.GnuBuildId != that.GnuBuildId { + return false + } + if this.GoBuildId != that.GoBuildId { + return false + } + if this.OtelFileId != that.OtelFileId { + return false + } + if this.Name != that.Name { + return false + } + if this.Type != that.Type { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *FileMetadata) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*FileMetadata) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ShouldInitiateUploadRequest) EqualVT(that *ShouldInitiateUploadRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.File.EqualVT(that.File) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ShouldInitiateUploadRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ShouldInitiateUploadRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ShouldInitiateUploadResponse) EqualVT(that *ShouldInitiateUploadResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.ShouldInitiateUpload != that.ShouldInitiateUpload { + return false + } + if this.Reason != that.Reason { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ShouldInitiateUploadResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ShouldInitiateUploadResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *UploadFinishedRequest) EqualVT(that *UploadFinishedRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.GnuBuildId != that.GnuBuildId { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *UploadFinishedRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*UploadFinishedRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *UploadFinishedResponse) EqualVT(that *UploadFinishedResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *UploadFinishedResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*UploadFinishedResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ListDebuginfoRequest) EqualVT(that *ListDebuginfoRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ListDebuginfoRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ListDebuginfoRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ListDebuginfoResponse) EqualVT(that *ListDebuginfoResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Object) != len(that.Object) { + return false + } + for i, vx := range this.Object { + vy := that.Object[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &ObjectMetadata{} + } + if q == nil { + q = &ObjectMetadata{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ListDebuginfoResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ListDebuginfoResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *DeleteDebuginfoRequest) EqualVT(that *DeleteDebuginfoRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.GnuBuildId != that.GnuBuildId { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteDebuginfoRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteDebuginfoRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *DeleteDebuginfoResponse) EqualVT(that *DeleteDebuginfoResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteDebuginfoResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteDebuginfoResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ObjectMetadata) EqualVT(that *ObjectMetadata) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.File.EqualVT(that.File) { + return false + } + if this.State != that.State { + return false + } + if !(*timestamppb1.Timestamp)(this.StartedAt).EqualVT((*timestamppb1.Timestamp)(that.StartedAt)) { + return false + } + if !(*timestamppb1.Timestamp)(this.FinishedAt).EqualVT((*timestamppb1.Timestamp)(that.FinishedAt)) { + return false + } + if this.SizeBytes != that.SizeBytes { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ObjectMetadata) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ObjectMetadata) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// DebuginfoServiceClient is the client API for DebuginfoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type DebuginfoServiceClient interface { + ShouldInitiateUpload(ctx context.Context, in *ShouldInitiateUploadRequest, opts ...grpc.CallOption) (*ShouldInitiateUploadResponse, error) + UploadFinished(ctx context.Context, in *UploadFinishedRequest, opts ...grpc.CallOption) (*UploadFinishedResponse, error) + ListDebuginfo(ctx context.Context, in *ListDebuginfoRequest, opts ...grpc.CallOption) (*ListDebuginfoResponse, error) + DeleteDebuginfo(ctx context.Context, in *DeleteDebuginfoRequest, opts ...grpc.CallOption) (*DeleteDebuginfoResponse, error) +} + +type debuginfoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDebuginfoServiceClient(cc grpc.ClientConnInterface) DebuginfoServiceClient { + return &debuginfoServiceClient{cc} +} + +func (c *debuginfoServiceClient) ShouldInitiateUpload(ctx context.Context, in *ShouldInitiateUploadRequest, opts ...grpc.CallOption) (*ShouldInitiateUploadResponse, error) { + out := new(ShouldInitiateUploadResponse) + err := c.cc.Invoke(ctx, "/debuginfo.v1alpha1.DebuginfoService/ShouldInitiateUpload", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debuginfoServiceClient) UploadFinished(ctx context.Context, in *UploadFinishedRequest, opts ...grpc.CallOption) (*UploadFinishedResponse, error) { + out := new(UploadFinishedResponse) + err := c.cc.Invoke(ctx, "/debuginfo.v1alpha1.DebuginfoService/UploadFinished", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debuginfoServiceClient) ListDebuginfo(ctx context.Context, in *ListDebuginfoRequest, opts ...grpc.CallOption) (*ListDebuginfoResponse, error) { + out := new(ListDebuginfoResponse) + err := c.cc.Invoke(ctx, "/debuginfo.v1alpha1.DebuginfoService/ListDebuginfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debuginfoServiceClient) DeleteDebuginfo(ctx context.Context, in *DeleteDebuginfoRequest, opts ...grpc.CallOption) (*DeleteDebuginfoResponse, error) { + out := new(DeleteDebuginfoResponse) + err := c.cc.Invoke(ctx, "/debuginfo.v1alpha1.DebuginfoService/DeleteDebuginfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DebuginfoServiceServer is the server API for DebuginfoService service. +// All implementations must embed UnimplementedDebuginfoServiceServer +// for forward compatibility +type DebuginfoServiceServer interface { + ShouldInitiateUpload(context.Context, *ShouldInitiateUploadRequest) (*ShouldInitiateUploadResponse, error) + UploadFinished(context.Context, *UploadFinishedRequest) (*UploadFinishedResponse, error) + ListDebuginfo(context.Context, *ListDebuginfoRequest) (*ListDebuginfoResponse, error) + DeleteDebuginfo(context.Context, *DeleteDebuginfoRequest) (*DeleteDebuginfoResponse, error) + mustEmbedUnimplementedDebuginfoServiceServer() +} + +// UnimplementedDebuginfoServiceServer must be embedded to have forward compatible implementations. +type UnimplementedDebuginfoServiceServer struct { +} + +func (UnimplementedDebuginfoServiceServer) ShouldInitiateUpload(context.Context, *ShouldInitiateUploadRequest) (*ShouldInitiateUploadResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ShouldInitiateUpload not implemented") +} +func (UnimplementedDebuginfoServiceServer) UploadFinished(context.Context, *UploadFinishedRequest) (*UploadFinishedResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UploadFinished not implemented") +} +func (UnimplementedDebuginfoServiceServer) ListDebuginfo(context.Context, *ListDebuginfoRequest) (*ListDebuginfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListDebuginfo not implemented") +} +func (UnimplementedDebuginfoServiceServer) DeleteDebuginfo(context.Context, *DeleteDebuginfoRequest) (*DeleteDebuginfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteDebuginfo not implemented") +} +func (UnimplementedDebuginfoServiceServer) mustEmbedUnimplementedDebuginfoServiceServer() {} + +// UnsafeDebuginfoServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to DebuginfoServiceServer will +// result in compilation errors. +type UnsafeDebuginfoServiceServer interface { + mustEmbedUnimplementedDebuginfoServiceServer() +} + +func RegisterDebuginfoServiceServer(s grpc.ServiceRegistrar, srv DebuginfoServiceServer) { + s.RegisterService(&DebuginfoService_ServiceDesc, srv) +} + +func _DebuginfoService_ShouldInitiateUpload_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ShouldInitiateUploadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebuginfoServiceServer).ShouldInitiateUpload(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/debuginfo.v1alpha1.DebuginfoService/ShouldInitiateUpload", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebuginfoServiceServer).ShouldInitiateUpload(ctx, req.(*ShouldInitiateUploadRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DebuginfoService_UploadFinished_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadFinishedRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebuginfoServiceServer).UploadFinished(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/debuginfo.v1alpha1.DebuginfoService/UploadFinished", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebuginfoServiceServer).UploadFinished(ctx, req.(*UploadFinishedRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DebuginfoService_ListDebuginfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListDebuginfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebuginfoServiceServer).ListDebuginfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/debuginfo.v1alpha1.DebuginfoService/ListDebuginfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebuginfoServiceServer).ListDebuginfo(ctx, req.(*ListDebuginfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DebuginfoService_DeleteDebuginfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteDebuginfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebuginfoServiceServer).DeleteDebuginfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/debuginfo.v1alpha1.DebuginfoService/DeleteDebuginfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebuginfoServiceServer).DeleteDebuginfo(ctx, req.(*DeleteDebuginfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// DebuginfoService_ServiceDesc is the grpc.ServiceDesc for DebuginfoService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var DebuginfoService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "debuginfo.v1alpha1.DebuginfoService", + HandlerType: (*DebuginfoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ShouldInitiateUpload", + Handler: _DebuginfoService_ShouldInitiateUpload_Handler, + }, + { + MethodName: "UploadFinished", + Handler: _DebuginfoService_UploadFinished_Handler, + }, + { + MethodName: "ListDebuginfo", + Handler: _DebuginfoService_ListDebuginfo_Handler, + }, + { + MethodName: "DeleteDebuginfo", + Handler: _DebuginfoService_DeleteDebuginfo_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "debuginfo/v1alpha1/debuginfo.proto", +} + +func (m *FileMetadata) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FileMetadata) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *FileMetadata) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Type != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x28 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x22 + } + if len(m.OtelFileId) > 0 { + i -= len(m.OtelFileId) + copy(dAtA[i:], m.OtelFileId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OtelFileId))) + i-- + dAtA[i] = 0x1a + } + if len(m.GoBuildId) > 0 { + i -= len(m.GoBuildId) + copy(dAtA[i:], m.GoBuildId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GoBuildId))) + i-- + dAtA[i] = 0x12 + } + if len(m.GnuBuildId) > 0 { + i -= len(m.GnuBuildId) + copy(dAtA[i:], m.GnuBuildId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GnuBuildId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ShouldInitiateUploadRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ShouldInitiateUploadRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ShouldInitiateUploadRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.File != nil { + size, err := m.File.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ShouldInitiateUploadResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ShouldInitiateUploadResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ShouldInitiateUploadResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Reason) > 0 { + i -= len(m.Reason) + copy(dAtA[i:], m.Reason) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Reason))) + i-- + dAtA[i] = 0x12 + } + if m.ShouldInitiateUpload { + i-- + if m.ShouldInitiateUpload { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *UploadFinishedRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UploadFinishedRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *UploadFinishedRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.GnuBuildId) > 0 { + i -= len(m.GnuBuildId) + copy(dAtA[i:], m.GnuBuildId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GnuBuildId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UploadFinishedResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UploadFinishedResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *UploadFinishedResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *ListDebuginfoRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListDebuginfoRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ListDebuginfoRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *ListDebuginfoResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListDebuginfoResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ListDebuginfoResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Object) > 0 { + for iNdEx := len(m.Object) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Object[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *DeleteDebuginfoRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteDebuginfoRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteDebuginfoRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.GnuBuildId) > 0 { + i -= len(m.GnuBuildId) + copy(dAtA[i:], m.GnuBuildId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GnuBuildId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DeleteDebuginfoResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteDebuginfoResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteDebuginfoResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *ObjectMetadata) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ObjectMetadata) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ObjectMetadata) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.SizeBytes != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.SizeBytes)) + i-- + dAtA[i] = 0x28 + } + if m.FinishedAt != nil { + size, err := (*timestamppb1.Timestamp)(m.FinishedAt).MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + if m.StartedAt != nil { + size, err := (*timestamppb1.Timestamp)(m.StartedAt).MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if m.State != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.State)) + i-- + dAtA[i] = 0x10 + } + if m.File != nil { + size, err := m.File.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *FileMetadata) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.GnuBuildId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.GoBuildId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.OtelFileId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Type != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Type)) + } + n += len(m.unknownFields) + return n +} + +func (m *ShouldInitiateUploadRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.File != nil { + l = m.File.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *ShouldInitiateUploadResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ShouldInitiateUpload { + n += 2 + } + l = len(m.Reason) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *UploadFinishedRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.GnuBuildId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *UploadFinishedResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *ListDebuginfoRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *ListDebuginfoResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Object) > 0 { + for _, e := range m.Object { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *DeleteDebuginfoRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.GnuBuildId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DeleteDebuginfoResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *ObjectMetadata) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.File != nil { + l = m.File.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.State != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.State)) + } + if m.StartedAt != nil { + l = (*timestamppb1.Timestamp)(m.StartedAt).SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.FinishedAt != nil { + l = (*timestamppb1.Timestamp)(m.FinishedAt).SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.SizeBytes != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.SizeBytes)) + } + n += len(m.unknownFields) + return n +} + +func (m *FileMetadata) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FileMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FileMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GnuBuildId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GnuBuildId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GoBuildId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GoBuildId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OtelFileId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OtelFileId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= FileMetadata_Type(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ShouldInitiateUploadRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ShouldInitiateUploadRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ShouldInitiateUploadRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field File", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.File == nil { + m.File = &FileMetadata{} + } + if err := m.File.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ShouldInitiateUploadResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ShouldInitiateUploadResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ShouldInitiateUploadResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ShouldInitiateUpload", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ShouldInitiateUpload = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reason", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reason = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UploadFinishedRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UploadFinishedRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UploadFinishedRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GnuBuildId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GnuBuildId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UploadFinishedResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UploadFinishedResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UploadFinishedResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListDebuginfoRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListDebuginfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListDebuginfoRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListDebuginfoResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListDebuginfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListDebuginfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Object = append(m.Object, &ObjectMetadata{}) + if err := m.Object[len(m.Object)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteDebuginfoRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteDebuginfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteDebuginfoRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GnuBuildId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GnuBuildId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteDebuginfoResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteDebuginfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteDebuginfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ObjectMetadata) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ObjectMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ObjectMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field File", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.File == nil { + m.File = &FileMetadata{} + } + if err := m.File.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + m.State = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.State |= ObjectMetadata_State(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StartedAt == nil { + m.StartedAt = ×tamppb.Timestamp{} + } + if err := (*timestamppb1.Timestamp)(m.StartedAt).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FinishedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FinishedAt == nil { + m.FinishedAt = ×tamppb.Timestamp{} + } + if err := (*timestamppb1.Timestamp)(m.FinishedAt).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SizeBytes", wireType) + } + m.SizeBytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SizeBytes |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect/debuginfo.connect.go b/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect/debuginfo.connect.go new file mode 100644 index 0000000000..303dc7704f --- /dev/null +++ b/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect/debuginfo.connect.go @@ -0,0 +1,196 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: debuginfo/v1alpha1/debuginfo.proto + +package debuginfov1alpha1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1alpha1 "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // DebuginfoServiceName is the fully-qualified name of the DebuginfoService service. + DebuginfoServiceName = "debuginfo.v1alpha1.DebuginfoService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // DebuginfoServiceShouldInitiateUploadProcedure is the fully-qualified name of the + // DebuginfoService's ShouldInitiateUpload RPC. + DebuginfoServiceShouldInitiateUploadProcedure = "/debuginfo.v1alpha1.DebuginfoService/ShouldInitiateUpload" + // DebuginfoServiceUploadFinishedProcedure is the fully-qualified name of the DebuginfoService's + // UploadFinished RPC. + DebuginfoServiceUploadFinishedProcedure = "/debuginfo.v1alpha1.DebuginfoService/UploadFinished" + // DebuginfoServiceListDebuginfoProcedure is the fully-qualified name of the DebuginfoService's + // ListDebuginfo RPC. + DebuginfoServiceListDebuginfoProcedure = "/debuginfo.v1alpha1.DebuginfoService/ListDebuginfo" + // DebuginfoServiceDeleteDebuginfoProcedure is the fully-qualified name of the DebuginfoService's + // DeleteDebuginfo RPC. + DebuginfoServiceDeleteDebuginfoProcedure = "/debuginfo.v1alpha1.DebuginfoService/DeleteDebuginfo" +) + +// DebuginfoServiceClient is a client for the debuginfo.v1alpha1.DebuginfoService service. +type DebuginfoServiceClient interface { + ShouldInitiateUpload(context.Context, *connect.Request[v1alpha1.ShouldInitiateUploadRequest]) (*connect.Response[v1alpha1.ShouldInitiateUploadResponse], error) + UploadFinished(context.Context, *connect.Request[v1alpha1.UploadFinishedRequest]) (*connect.Response[v1alpha1.UploadFinishedResponse], error) + ListDebuginfo(context.Context, *connect.Request[v1alpha1.ListDebuginfoRequest]) (*connect.Response[v1alpha1.ListDebuginfoResponse], error) + DeleteDebuginfo(context.Context, *connect.Request[v1alpha1.DeleteDebuginfoRequest]) (*connect.Response[v1alpha1.DeleteDebuginfoResponse], error) +} + +// NewDebuginfoServiceClient constructs a client for the debuginfo.v1alpha1.DebuginfoService +// service. By default, it uses the Connect protocol with the binary Protobuf Codec, asks for +// gzipped responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply +// the connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewDebuginfoServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) DebuginfoServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + debuginfoServiceMethods := v1alpha1.File_debuginfo_v1alpha1_debuginfo_proto.Services().ByName("DebuginfoService").Methods() + return &debuginfoServiceClient{ + shouldInitiateUpload: connect.NewClient[v1alpha1.ShouldInitiateUploadRequest, v1alpha1.ShouldInitiateUploadResponse]( + httpClient, + baseURL+DebuginfoServiceShouldInitiateUploadProcedure, + connect.WithSchema(debuginfoServiceMethods.ByName("ShouldInitiateUpload")), + connect.WithClientOptions(opts...), + ), + uploadFinished: connect.NewClient[v1alpha1.UploadFinishedRequest, v1alpha1.UploadFinishedResponse]( + httpClient, + baseURL+DebuginfoServiceUploadFinishedProcedure, + connect.WithSchema(debuginfoServiceMethods.ByName("UploadFinished")), + connect.WithClientOptions(opts...), + ), + listDebuginfo: connect.NewClient[v1alpha1.ListDebuginfoRequest, v1alpha1.ListDebuginfoResponse]( + httpClient, + baseURL+DebuginfoServiceListDebuginfoProcedure, + connect.WithSchema(debuginfoServiceMethods.ByName("ListDebuginfo")), + connect.WithClientOptions(opts...), + ), + deleteDebuginfo: connect.NewClient[v1alpha1.DeleteDebuginfoRequest, v1alpha1.DeleteDebuginfoResponse]( + httpClient, + baseURL+DebuginfoServiceDeleteDebuginfoProcedure, + connect.WithSchema(debuginfoServiceMethods.ByName("DeleteDebuginfo")), + connect.WithClientOptions(opts...), + ), + } +} + +// debuginfoServiceClient implements DebuginfoServiceClient. +type debuginfoServiceClient struct { + shouldInitiateUpload *connect.Client[v1alpha1.ShouldInitiateUploadRequest, v1alpha1.ShouldInitiateUploadResponse] + uploadFinished *connect.Client[v1alpha1.UploadFinishedRequest, v1alpha1.UploadFinishedResponse] + listDebuginfo *connect.Client[v1alpha1.ListDebuginfoRequest, v1alpha1.ListDebuginfoResponse] + deleteDebuginfo *connect.Client[v1alpha1.DeleteDebuginfoRequest, v1alpha1.DeleteDebuginfoResponse] +} + +// ShouldInitiateUpload calls debuginfo.v1alpha1.DebuginfoService.ShouldInitiateUpload. +func (c *debuginfoServiceClient) ShouldInitiateUpload(ctx context.Context, req *connect.Request[v1alpha1.ShouldInitiateUploadRequest]) (*connect.Response[v1alpha1.ShouldInitiateUploadResponse], error) { + return c.shouldInitiateUpload.CallUnary(ctx, req) +} + +// UploadFinished calls debuginfo.v1alpha1.DebuginfoService.UploadFinished. +func (c *debuginfoServiceClient) UploadFinished(ctx context.Context, req *connect.Request[v1alpha1.UploadFinishedRequest]) (*connect.Response[v1alpha1.UploadFinishedResponse], error) { + return c.uploadFinished.CallUnary(ctx, req) +} + +// ListDebuginfo calls debuginfo.v1alpha1.DebuginfoService.ListDebuginfo. +func (c *debuginfoServiceClient) ListDebuginfo(ctx context.Context, req *connect.Request[v1alpha1.ListDebuginfoRequest]) (*connect.Response[v1alpha1.ListDebuginfoResponse], error) { + return c.listDebuginfo.CallUnary(ctx, req) +} + +// DeleteDebuginfo calls debuginfo.v1alpha1.DebuginfoService.DeleteDebuginfo. +func (c *debuginfoServiceClient) DeleteDebuginfo(ctx context.Context, req *connect.Request[v1alpha1.DeleteDebuginfoRequest]) (*connect.Response[v1alpha1.DeleteDebuginfoResponse], error) { + return c.deleteDebuginfo.CallUnary(ctx, req) +} + +// DebuginfoServiceHandler is an implementation of the debuginfo.v1alpha1.DebuginfoService service. +type DebuginfoServiceHandler interface { + ShouldInitiateUpload(context.Context, *connect.Request[v1alpha1.ShouldInitiateUploadRequest]) (*connect.Response[v1alpha1.ShouldInitiateUploadResponse], error) + UploadFinished(context.Context, *connect.Request[v1alpha1.UploadFinishedRequest]) (*connect.Response[v1alpha1.UploadFinishedResponse], error) + ListDebuginfo(context.Context, *connect.Request[v1alpha1.ListDebuginfoRequest]) (*connect.Response[v1alpha1.ListDebuginfoResponse], error) + DeleteDebuginfo(context.Context, *connect.Request[v1alpha1.DeleteDebuginfoRequest]) (*connect.Response[v1alpha1.DeleteDebuginfoResponse], error) +} + +// NewDebuginfoServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewDebuginfoServiceHandler(svc DebuginfoServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + debuginfoServiceMethods := v1alpha1.File_debuginfo_v1alpha1_debuginfo_proto.Services().ByName("DebuginfoService").Methods() + debuginfoServiceShouldInitiateUploadHandler := connect.NewUnaryHandler( + DebuginfoServiceShouldInitiateUploadProcedure, + svc.ShouldInitiateUpload, + connect.WithSchema(debuginfoServiceMethods.ByName("ShouldInitiateUpload")), + connect.WithHandlerOptions(opts...), + ) + debuginfoServiceUploadFinishedHandler := connect.NewUnaryHandler( + DebuginfoServiceUploadFinishedProcedure, + svc.UploadFinished, + connect.WithSchema(debuginfoServiceMethods.ByName("UploadFinished")), + connect.WithHandlerOptions(opts...), + ) + debuginfoServiceListDebuginfoHandler := connect.NewUnaryHandler( + DebuginfoServiceListDebuginfoProcedure, + svc.ListDebuginfo, + connect.WithSchema(debuginfoServiceMethods.ByName("ListDebuginfo")), + connect.WithHandlerOptions(opts...), + ) + debuginfoServiceDeleteDebuginfoHandler := connect.NewUnaryHandler( + DebuginfoServiceDeleteDebuginfoProcedure, + svc.DeleteDebuginfo, + connect.WithSchema(debuginfoServiceMethods.ByName("DeleteDebuginfo")), + connect.WithHandlerOptions(opts...), + ) + return "/debuginfo.v1alpha1.DebuginfoService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case DebuginfoServiceShouldInitiateUploadProcedure: + debuginfoServiceShouldInitiateUploadHandler.ServeHTTP(w, r) + case DebuginfoServiceUploadFinishedProcedure: + debuginfoServiceUploadFinishedHandler.ServeHTTP(w, r) + case DebuginfoServiceListDebuginfoProcedure: + debuginfoServiceListDebuginfoHandler.ServeHTTP(w, r) + case DebuginfoServiceDeleteDebuginfoProcedure: + debuginfoServiceDeleteDebuginfoHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedDebuginfoServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedDebuginfoServiceHandler struct{} + +func (UnimplementedDebuginfoServiceHandler) ShouldInitiateUpload(context.Context, *connect.Request[v1alpha1.ShouldInitiateUploadRequest]) (*connect.Response[v1alpha1.ShouldInitiateUploadResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("debuginfo.v1alpha1.DebuginfoService.ShouldInitiateUpload is not implemented")) +} + +func (UnimplementedDebuginfoServiceHandler) UploadFinished(context.Context, *connect.Request[v1alpha1.UploadFinishedRequest]) (*connect.Response[v1alpha1.UploadFinishedResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("debuginfo.v1alpha1.DebuginfoService.UploadFinished is not implemented")) +} + +func (UnimplementedDebuginfoServiceHandler) ListDebuginfo(context.Context, *connect.Request[v1alpha1.ListDebuginfoRequest]) (*connect.Response[v1alpha1.ListDebuginfoResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("debuginfo.v1alpha1.DebuginfoService.ListDebuginfo is not implemented")) +} + +func (UnimplementedDebuginfoServiceHandler) DeleteDebuginfo(context.Context, *connect.Request[v1alpha1.DeleteDebuginfoRequest]) (*connect.Response[v1alpha1.DeleteDebuginfoResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("debuginfo.v1alpha1.DebuginfoService.DeleteDebuginfo is not implemented")) +} diff --git a/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect/debuginfo.connect.mux.go b/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect/debuginfo.connect.mux.go new file mode 100644 index 0000000000..1899a89d95 --- /dev/null +++ b/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect/debuginfo.connect.mux.go @@ -0,0 +1,42 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: debuginfo/v1alpha1/debuginfo.proto + +package debuginfov1alpha1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterDebuginfoServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterDebuginfoServiceHandler(mux *mux.Router, svc DebuginfoServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/debuginfo.v1alpha1.DebuginfoService/ShouldInitiateUpload", connect.NewUnaryHandler( + "/debuginfo.v1alpha1.DebuginfoService/ShouldInitiateUpload", + svc.ShouldInitiateUpload, + opts..., + )) + mux.Handle("/debuginfo.v1alpha1.DebuginfoService/UploadFinished", connect.NewUnaryHandler( + "/debuginfo.v1alpha1.DebuginfoService/UploadFinished", + svc.UploadFinished, + opts..., + )) + mux.Handle("/debuginfo.v1alpha1.DebuginfoService/ListDebuginfo", connect.NewUnaryHandler( + "/debuginfo.v1alpha1.DebuginfoService/ListDebuginfo", + svc.ListDebuginfo, + opts..., + )) + mux.Handle("/debuginfo.v1alpha1.DebuginfoService/DeleteDebuginfo", connect.NewUnaryHandler( + "/debuginfo.v1alpha1.DebuginfoService/DeleteDebuginfo", + svc.DeleteDebuginfo, + opts..., + )) +} diff --git a/api/gen/proto/go/google/v1/profile.pb.go b/api/gen/proto/go/google/v1/profile.pb.go index 4df2323579..9580c72c7b 100644 --- a/api/gen/proto/go/google/v1/profile.pb.go +++ b/api/gen/proto/go/google/v1/profile.pb.go @@ -38,7 +38,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: google/v1/profile.proto @@ -49,6 +49,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -59,10 +60,7 @@ const ( ) type Profile struct { - state protoimpl.MessageState `parquet:"-"` - sizeCache protoimpl.SizeCache `parquet:"-"` - unknownFields protoimpl.UnknownFields `parquet:"-"` - + state protoimpl.MessageState `protogen:"open.v1" parquet:"-"` // A description of the samples associated with each Sample.value. // For a cpu profile this might be: // @@ -107,16 +105,16 @@ type Profile struct { Comment []int64 `protobuf:"varint,13,rep,packed,name=comment,proto3" json:"comment,omitempty" parquet:"-"` // Indices into string table. // Index into the string table of the type of the preferred sample // value. If unset, clients should default to the last sample value. - DefaultSampleType int64 `protobuf:"varint,14,opt,name=default_sample_type,json=defaultSampleType,proto3" json:"default_sample_type,omitempty" parquet:"-"` + DefaultSampleType int64 `protobuf:"varint,14,opt,name=default_sample_type,json=defaultSampleType,proto3" json:"default_sample_type,omitempty" parquet:"-"` + unknownFields protoimpl.UnknownFields `parquet:"-"` + sizeCache protoimpl.SizeCache `parquet:"-"` } func (x *Profile) Reset() { *x = Profile{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Profile) String() string { @@ -127,7 +125,7 @@ func (*Profile) ProtoMessage() {} func (x *Profile) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -242,21 +240,18 @@ func (x *Profile) GetDefaultSampleType() int64 { // ValueType describes the semantics and measurement units of a value. type ValueType struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type int64 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty" parquet:","` // Index into string table. + Unit int64 `protobuf:"varint,2,opt,name=unit,proto3" json:"unit,omitempty" parquet:","` // Index into string table. unknownFields protoimpl.UnknownFields - - Type int64 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty" parquet:","` // Index into string table. - Unit int64 `protobuf:"varint,2,opt,name=unit,proto3" json:"unit,omitempty" parquet:","` // Index into string table. + sizeCache protoimpl.SizeCache } func (x *ValueType) Reset() { *x = ValueType{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ValueType) String() string { @@ -267,7 +262,7 @@ func (*ValueType) ProtoMessage() {} func (x *ValueType) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -301,10 +296,7 @@ func (x *ValueType) GetUnit() int64 { // augmented with auxiliary information like the thread-id, some // indicator of a higher level request being handled etc. type Sample struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The ids recorded here correspond to a Profile.location.id. // The leaf is at location_id[0]. LocationId []uint64 `protobuf:"varint,1,rep,packed,name=location_id,json=locationId,proto3" json:"location_id,omitempty" parquet:","` @@ -317,16 +309,16 @@ type Sample struct { Value []int64 `protobuf:"varint,2,rep,packed,name=value,proto3" json:"value,omitempty" parquet:","` // label includes additional context for this sample. It can include // things like a thread id, allocation size, etc - Label []*Label `protobuf:"bytes,3,rep,name=label,proto3" json:"label,omitempty"` + Label []*Label `protobuf:"bytes,3,rep,name=label,proto3" json:"label,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Sample) Reset() { *x = Sample{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Sample) String() string { @@ -337,7 +329,7 @@ func (*Sample) ProtoMessage() {} func (x *Sample) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -374,11 +366,8 @@ func (x *Sample) GetLabel() []*Label { } type Label struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Key int64 `protobuf:"varint,1,opt,name=key,proto3" json:"key,omitempty"` // Index into string table + state protoimpl.MessageState `protogen:"open.v1"` + Key int64 `protobuf:"varint,1,opt,name=key,proto3" json:"key,omitempty"` // Index into string table // At most one of the following must be present Str int64 `protobuf:"varint,2,opt,name=str,proto3" json:"str,omitempty" parquet:",optional"` // Index into string table Num int64 `protobuf:"varint,3,opt,name=num,proto3" json:"num,omitempty" parquet:",optional"` @@ -389,16 +378,16 @@ type Label struct { // Consumers may also interpret units like "bytes" and "kilobytes" as memory // units and units like "seconds" and "nanoseconds" as time units, // and apply appropriate unit conversions to these. - NumUnit int64 `protobuf:"varint,4,opt,name=num_unit,json=numUnit,proto3" json:"num_unit,omitempty" parquet:",optional"` // Index into string table + NumUnit int64 `protobuf:"varint,4,opt,name=num_unit,json=numUnit,proto3" json:"num_unit,omitempty" parquet:",optional"` // Index into string table + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Label) Reset() { *x = Label{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Label) String() string { @@ -409,7 +398,7 @@ func (*Label) ProtoMessage() {} func (x *Label) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -453,10 +442,7 @@ func (x *Label) GetNumUnit() int64 { } type Mapping struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Unique nonzero id for the mapping. Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // Address at which the binary (or DLL) is loaded into memory. @@ -478,15 +464,15 @@ type Mapping struct { HasFilenames bool `protobuf:"varint,8,opt,name=has_filenames,json=hasFilenames,proto3" json:"has_filenames,omitempty"` HasLineNumbers bool `protobuf:"varint,9,opt,name=has_line_numbers,json=hasLineNumbers,proto3" json:"has_line_numbers,omitempty"` HasInlineFrames bool `protobuf:"varint,10,opt,name=has_inline_frames,json=hasInlineFrames,proto3" json:"has_inline_frames,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Mapping) Reset() { *x = Mapping{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Mapping) String() string { @@ -497,7 +483,7 @@ func (*Mapping) ProtoMessage() {} func (x *Mapping) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -584,10 +570,7 @@ func (x *Mapping) GetHasInlineFrames() bool { // Describes function and line table debug information. type Location struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Unique nonzero id for the location. A profile could use // instruction addresses or any integer sequence as ids. Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` @@ -615,16 +598,16 @@ type Location struct { // case the line information above represents one of the multiple // symbols. This field must be recomputed when the symbolization state of the // profile changes. - IsFolded bool `protobuf:"varint,5,opt,name=is_folded,json=isFolded,proto3" json:"is_folded,omitempty"` + IsFolded bool `protobuf:"varint,5,opt,name=is_folded,json=isFolded,proto3" json:"is_folded,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Location) Reset() { *x = Location{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Location) String() string { @@ -635,7 +618,7 @@ func (*Location) ProtoMessage() {} func (x *Location) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -686,23 +669,20 @@ func (x *Location) GetIsFolded() bool { } type Line struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The id of the corresponding profile.Function for this line. FunctionId uint64 `protobuf:"varint,1,opt,name=function_id,json=functionId,proto3" json:"function_id,omitempty"` // Line number in source code. - Line int64 `protobuf:"varint,2,opt,name=line,proto3" json:"line,omitempty"` + Line int64 `protobuf:"varint,2,opt,name=line,proto3" json:"line,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Line) Reset() { *x = Line{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Line) String() string { @@ -713,7 +693,7 @@ func (*Line) ProtoMessage() {} func (x *Line) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -743,10 +723,7 @@ func (x *Line) GetLine() int64 { } type Function struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Unique nonzero id for the function. Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // Name of the function, in human-readable form if available. @@ -757,16 +734,16 @@ type Function struct { // Source file containing the function. Filename int64 `protobuf:"varint,4,opt,name=filename,proto3" json:"filename,omitempty"` // Index into string table // Line number in source file. - StartLine int64 `protobuf:"varint,5,opt,name=start_line,json=startLine,proto3" json:"start_line,omitempty"` + StartLine int64 `protobuf:"varint,5,opt,name=start_line,json=startLine,proto3" json:"start_line,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Function) Reset() { *x = Function{} - if protoimpl.UnsafeEnabled { - mi := &file_google_v1_profile_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_google_v1_profile_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Function) String() string { @@ -777,7 +754,7 @@ func (*Function) ProtoMessage() {} func (x *Function) ProtoReflect() protoreflect.Message { mi := &file_google_v1_profile_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -829,132 +806,92 @@ func (x *Function) GetStartLine() int64 { var File_google_v1_profile_proto protoreflect.FileDescriptor -var file_google_v1_profile_proto_rawDesc = []byte{ - 0x0a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x76, 0x31, 0x22, 0xbf, 0x04, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x12, 0x35, 0x0a, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x73, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x06, 0x73, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x12, 0x2f, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x2f, 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x66, 0x72, - 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x72, 0x6f, 0x70, - 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x66, - 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6b, 0x65, 0x65, - 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, - 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x35, 0x0a, - 0x0b, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x33, 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x67, 0x0a, 0x06, 0x53, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x26, 0x0a, 0x05, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x05, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x22, 0x58, 0x0a, 0x05, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x73, 0x74, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x73, 0x74, - 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, - 0x6e, 0x75, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x55, 0x6e, 0x69, 0x74, 0x22, 0xd7, - 0x02, 0x0a, 0x07, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, - 0x0c, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, - 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x68, 0x61, 0x73, 0x5f, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x68, 0x61, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, - 0x0d, 0x68, 0x61, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x68, 0x61, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x68, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x68, 0x61, - 0x73, 0x4c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x11, - 0x68, 0x61, 0x73, 0x5f, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, - 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x68, 0x61, 0x73, 0x49, 0x6e, 0x6c, 0x69, - 0x6e, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x70, 0x69, - 0x6e, 0x67, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, - 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x04, 0x6c, - 0x69, 0x6e, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x64, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x64, - 0x22, 0x3b, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75, 0x6e, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, - 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x8a, 0x01, - 0x0a, 0x08, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x42, 0xa4, 0x01, 0x0a, 0x0d, 0x63, - 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x40, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, - 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, - 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x47, 0x58, 0x58, 0xaa, 0x02, 0x09, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x56, 0x31, - 0xca, 0x02, 0x09, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x47, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_google_v1_profile_proto_rawDesc = "" + + "\n" + + "\x17google/v1/profile.proto\x12\tgoogle.v1\"\xbf\x04\n" + + "\aProfile\x125\n" + + "\vsample_type\x18\x01 \x03(\v2\x14.google.v1.ValueTypeR\n" + + "sampleType\x12)\n" + + "\x06sample\x18\x02 \x03(\v2\x11.google.v1.SampleR\x06sample\x12,\n" + + "\amapping\x18\x03 \x03(\v2\x12.google.v1.MappingR\amapping\x12/\n" + + "\blocation\x18\x04 \x03(\v2\x13.google.v1.LocationR\blocation\x12/\n" + + "\bfunction\x18\x05 \x03(\v2\x13.google.v1.FunctionR\bfunction\x12!\n" + + "\fstring_table\x18\x06 \x03(\tR\vstringTable\x12\x1f\n" + + "\vdrop_frames\x18\a \x01(\x03R\n" + + "dropFrames\x12\x1f\n" + + "\vkeep_frames\x18\b \x01(\x03R\n" + + "keepFrames\x12\x1d\n" + + "\n" + + "time_nanos\x18\t \x01(\x03R\ttimeNanos\x12%\n" + + "\x0eduration_nanos\x18\n" + + " \x01(\x03R\rdurationNanos\x125\n" + + "\vperiod_type\x18\v \x01(\v2\x14.google.v1.ValueTypeR\n" + + "periodType\x12\x16\n" + + "\x06period\x18\f \x01(\x03R\x06period\x12\x18\n" + + "\acomment\x18\r \x03(\x03R\acomment\x12.\n" + + "\x13default_sample_type\x18\x0e \x01(\x03R\x11defaultSampleType\"3\n" + + "\tValueType\x12\x12\n" + + "\x04type\x18\x01 \x01(\x03R\x04type\x12\x12\n" + + "\x04unit\x18\x02 \x01(\x03R\x04unit\"g\n" + + "\x06Sample\x12\x1f\n" + + "\vlocation_id\x18\x01 \x03(\x04R\n" + + "locationId\x12\x14\n" + + "\x05value\x18\x02 \x03(\x03R\x05value\x12&\n" + + "\x05label\x18\x03 \x03(\v2\x10.google.v1.LabelR\x05label\"X\n" + + "\x05Label\x12\x10\n" + + "\x03key\x18\x01 \x01(\x03R\x03key\x12\x10\n" + + "\x03str\x18\x02 \x01(\x03R\x03str\x12\x10\n" + + "\x03num\x18\x03 \x01(\x03R\x03num\x12\x19\n" + + "\bnum_unit\x18\x04 \x01(\x03R\anumUnit\"\xd7\x02\n" + + "\aMapping\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12!\n" + + "\fmemory_start\x18\x02 \x01(\x04R\vmemoryStart\x12!\n" + + "\fmemory_limit\x18\x03 \x01(\x04R\vmemoryLimit\x12\x1f\n" + + "\vfile_offset\x18\x04 \x01(\x04R\n" + + "fileOffset\x12\x1a\n" + + "\bfilename\x18\x05 \x01(\x03R\bfilename\x12\x19\n" + + "\bbuild_id\x18\x06 \x01(\x03R\abuildId\x12#\n" + + "\rhas_functions\x18\a \x01(\bR\fhasFunctions\x12#\n" + + "\rhas_filenames\x18\b \x01(\bR\fhasFilenames\x12(\n" + + "\x10has_line_numbers\x18\t \x01(\bR\x0ehasLineNumbers\x12*\n" + + "\x11has_inline_frames\x18\n" + + " \x01(\bR\x0fhasInlineFrames\"\x95\x01\n" + + "\bLocation\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x1d\n" + + "\n" + + "mapping_id\x18\x02 \x01(\x04R\tmappingId\x12\x18\n" + + "\aaddress\x18\x03 \x01(\x04R\aaddress\x12#\n" + + "\x04line\x18\x04 \x03(\v2\x0f.google.v1.LineR\x04line\x12\x1b\n" + + "\tis_folded\x18\x05 \x01(\bR\bisFolded\";\n" + + "\x04Line\x12\x1f\n" + + "\vfunction_id\x18\x01 \x01(\x04R\n" + + "functionId\x12\x12\n" + + "\x04line\x18\x02 \x01(\x03R\x04line\"\x8a\x01\n" + + "\bFunction\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\x03R\x04name\x12\x1f\n" + + "\vsystem_name\x18\x03 \x01(\x03R\n" + + "systemName\x12\x1a\n" + + "\bfilename\x18\x04 \x01(\x03R\bfilename\x12\x1d\n" + + "\n" + + "start_line\x18\x05 \x01(\x03R\tstartLineB\xa4\x01\n" + + "\rcom.google.v1B\fProfileProtoP\x01Z@github.com/grafana/pyroscope/api/gen/proto/go/google/v1;googlev1\xa2\x02\x03GXX\xaa\x02\tGoogle.V1\xca\x02\tGoogle\\V1\xe2\x02\x15Google\\V1\\GPBMetadata\xea\x02\n" + + "Google::V1b\x06proto3" var ( file_google_v1_profile_proto_rawDescOnce sync.Once - file_google_v1_profile_proto_rawDescData = file_google_v1_profile_proto_rawDesc + file_google_v1_profile_proto_rawDescData []byte ) func file_google_v1_profile_proto_rawDescGZIP() []byte { file_google_v1_profile_proto_rawDescOnce.Do(func() { - file_google_v1_profile_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_v1_profile_proto_rawDescData) + file_google_v1_profile_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_google_v1_profile_proto_rawDesc), len(file_google_v1_profile_proto_rawDesc))) }) return file_google_v1_profile_proto_rawDescData } var file_google_v1_profile_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_google_v1_profile_proto_goTypes = []interface{}{ +var file_google_v1_profile_proto_goTypes = []any{ (*Profile)(nil), // 0: google.v1.Profile (*ValueType)(nil), // 1: google.v1.ValueType (*Sample)(nil), // 2: google.v1.Sample @@ -985,109 +922,11 @@ func file_google_v1_profile_proto_init() { if File_google_v1_profile_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_google_v1_profile_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Profile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_v1_profile_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValueType); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_v1_profile_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Sample); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_v1_profile_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Label); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_v1_profile_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Mapping); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_v1_profile_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Location); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_v1_profile_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Line); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_v1_profile_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Function); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_google_v1_profile_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_google_v1_profile_proto_rawDesc), len(file_google_v1_profile_proto_rawDesc)), NumEnums: 0, NumMessages: 8, NumExtensions: 0, @@ -1098,7 +937,6 @@ func file_google_v1_profile_proto_init() { MessageInfos: file_google_v1_profile_proto_msgTypes, }.Build() File_google_v1_profile_proto = out.File - file_google_v1_profile_proto_rawDesc = nil file_google_v1_profile_proto_goTypes = nil file_google_v1_profile_proto_depIdxs = nil } diff --git a/api/gen/proto/go/ingester/v1/ingester.pb.go b/api/gen/proto/go/ingester/v1/ingester.pb.go index 3b679ca791..fb7509e8e7 100644 --- a/api/gen/proto/go/ingester/v1/ingester.pb.go +++ b/api/gen/proto/go/ingester/v1/ingester.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: ingester/v1/ingester.proto @@ -14,6 +14,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -73,23 +74,20 @@ func (StacktracesMergeFormat) EnumDescriptor() ([]byte, []int) { } type ProfileTypesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Milliseconds since epoch. Start int64 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. - End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ProfileTypesRequest) Reset() { *x = ProfileTypesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProfileTypesRequest) String() string { @@ -100,7 +98,7 @@ func (*ProfileTypesRequest) ProtoMessage() {} func (x *ProfileTypesRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -130,20 +128,17 @@ func (x *ProfileTypesRequest) GetEnd() int64 { } type ProfileTypesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ProfileTypes []*v1.ProfileType `protobuf:"bytes,1,rep,name=profile_types,json=profileTypes,proto3" json:"profile_types,omitempty"` unknownFields protoimpl.UnknownFields - - ProfileTypes []*v1.ProfileType `protobuf:"bytes,1,rep,name=profile_types,json=profileTypes,proto3" json:"profile_types,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ProfileTypesResponse) Reset() { *x = ProfileTypesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProfileTypesResponse) String() string { @@ -154,7 +149,7 @@ func (*ProfileTypesResponse) ProtoMessage() {} func (x *ProfileTypesResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -177,27 +172,24 @@ func (x *ProfileTypesResponse) GetProfileTypes() []*v1.ProfileType { } type SeriesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Matchers []string `protobuf:"bytes,1,rep,name=matchers,proto3" json:"matchers,omitempty"` - LabelNames []string `protobuf:"bytes,2,rep,name=label_names,json=labelNames,proto3" json:"label_names,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Matchers []string `protobuf:"bytes,1,rep,name=matchers,proto3" json:"matchers,omitempty"` + LabelNames []string `protobuf:"bytes,2,rep,name=label_names,json=labelNames,proto3" json:"label_names,omitempty"` // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. - End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SeriesRequest) Reset() { *x = SeriesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SeriesRequest) String() string { @@ -208,7 +200,7 @@ func (*SeriesRequest) ProtoMessage() {} func (x *SeriesRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -252,20 +244,17 @@ func (x *SeriesRequest) GetEnd() int64 { } type SeriesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + LabelsSet []*v1.Labels `protobuf:"bytes,2,rep,name=labels_set,json=labelsSet,proto3" json:"labels_set,omitempty"` unknownFields protoimpl.UnknownFields - - LabelsSet []*v1.Labels `protobuf:"bytes,2,rep,name=labels_set,json=labelsSet,proto3" json:"labels_set,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SeriesResponse) Reset() { *x = SeriesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SeriesResponse) String() string { @@ -276,7 +265,7 @@ func (*SeriesResponse) ProtoMessage() {} func (x *SeriesResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -299,18 +288,16 @@ func (x *SeriesResponse) GetLabelsSet() []*v1.Labels { } type FlushRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlushRequest) Reset() { *x = FlushRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlushRequest) String() string { @@ -321,7 +308,7 @@ func (*FlushRequest) ProtoMessage() {} func (x *FlushRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -337,18 +324,16 @@ func (*FlushRequest) Descriptor() ([]byte, []int) { } type FlushResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlushResponse) Reset() { *x = FlushResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlushResponse) String() string { @@ -359,7 +344,7 @@ func (*FlushResponse) ProtoMessage() {} func (x *FlushResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -375,12 +360,9 @@ func (*FlushResponse) Descriptor() ([]byte, []int) { } type SelectProfilesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LabelSelector string `protobuf:"bytes,1,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` - Type *v1.ProfileType `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + LabelSelector string `protobuf:"bytes,1,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` + Type *v1.ProfileType `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` // Milliseconds since epoch. Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. @@ -388,16 +370,16 @@ type SelectProfilesRequest struct { // Optional: Hints for querying Hints *Hints `protobuf:"bytes,5,opt,name=hints,proto3,oneof" json:"hints,omitempty"` // Optional: Aggregation - Aggregation *v1.TimeSeriesAggregationType `protobuf:"varint,6,opt,name=aggregation,proto3,enum=types.v1.TimeSeriesAggregationType,oneof" json:"aggregation,omitempty"` + Aggregation *v1.TimeSeriesAggregationType `protobuf:"varint,6,opt,name=aggregation,proto3,enum=types.v1.TimeSeriesAggregationType,oneof" json:"aggregation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectProfilesRequest) Reset() { *x = SelectProfilesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectProfilesRequest) String() string { @@ -408,7 +390,7 @@ func (*SelectProfilesRequest) ProtoMessage() {} func (x *SelectProfilesRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -466,25 +448,22 @@ func (x *SelectProfilesRequest) GetAggregation() v1.TimeSeriesAggregationType { } type MergeProfilesStacktracesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The client starts the stream with a request containing the profile type and the labels. Request *SelectProfilesRequest `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` // Max nodes in the resulting tree. MaxNodes *int64 `protobuf:"varint,3,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` // On a batch of profiles, the client sends the profiles to keep for merging. - Profiles []bool `protobuf:"varint,2,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + Profiles []bool `protobuf:"varint,2,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeProfilesStacktracesRequest) Reset() { *x = MergeProfilesStacktracesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeProfilesStacktracesRequest) String() string { @@ -495,7 +474,7 @@ func (*MergeProfilesStacktracesRequest) ProtoMessage() {} func (x *MergeProfilesStacktracesRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -532,25 +511,22 @@ func (x *MergeProfilesStacktracesRequest) GetProfiles() []bool { } type MergeProfilesStacktracesResult struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Format StacktracesMergeFormat `protobuf:"varint,3,opt,name=format,proto3,enum=ingester.v1.StacktracesMergeFormat" json:"format,omitempty"` // The list of stracktraces with their respective value Stacktraces []*StacktraceSample `protobuf:"bytes,1,rep,name=stacktraces,proto3" json:"stacktraces,omitempty"` FunctionNames []string `protobuf:"bytes,2,rep,name=function_names,json=functionNames,proto3" json:"function_names,omitempty"` // Merge result marshaled to pyroscope tree bytes. - TreeBytes []byte `protobuf:"bytes,4,opt,name=tree_bytes,json=treeBytes,proto3" json:"tree_bytes,omitempty"` + TreeBytes []byte `protobuf:"bytes,4,opt,name=tree_bytes,json=treeBytes,proto3" json:"tree_bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeProfilesStacktracesResult) Reset() { *x = MergeProfilesStacktracesResult{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeProfilesStacktracesResult) String() string { @@ -561,7 +537,7 @@ func (*MergeProfilesStacktracesResult) ProtoMessage() {} func (x *MergeProfilesStacktracesResult) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -605,24 +581,21 @@ func (x *MergeProfilesStacktracesResult) GetTreeBytes() []byte { } type MergeProfilesStacktracesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The server replies batch of profiles. // A last message without profiles signals the next message will be the result of the merge. SelectedProfiles *ProfileSets `protobuf:"bytes,1,opt,name=selectedProfiles,proto3" json:"selectedProfiles,omitempty"` // The list of stracktraces for the profile with their respective value - Result *MergeProfilesStacktracesResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` + Result *MergeProfilesStacktracesResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeProfilesStacktracesResponse) Reset() { *x = MergeProfilesStacktracesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeProfilesStacktracesResponse) String() string { @@ -633,7 +606,7 @@ func (*MergeProfilesStacktracesResponse) ProtoMessage() {} func (x *MergeProfilesStacktracesResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -663,12 +636,9 @@ func (x *MergeProfilesStacktracesResponse) GetResult() *MergeProfilesStacktraces } type SelectSpanProfileRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LabelSelector string `protobuf:"bytes,1,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` - Type *v1.ProfileType `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + LabelSelector string `protobuf:"bytes,1,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` + Type *v1.ProfileType `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` // Milliseconds since epoch. Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. @@ -676,16 +646,16 @@ type SelectSpanProfileRequest struct { // List of span identifiers. SpanSelector []string `protobuf:"bytes,5,rep,name=span_selector,json=spanSelector,proto3" json:"span_selector,omitempty"` // Optional: Hints for querying - Hints *Hints `protobuf:"bytes,6,opt,name=hints,proto3,oneof" json:"hints,omitempty"` + Hints *Hints `protobuf:"bytes,6,opt,name=hints,proto3,oneof" json:"hints,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectSpanProfileRequest) Reset() { *x = SelectSpanProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectSpanProfileRequest) String() string { @@ -696,7 +666,7 @@ func (*SelectSpanProfileRequest) ProtoMessage() {} func (x *SelectSpanProfileRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -754,25 +724,22 @@ func (x *SelectSpanProfileRequest) GetHints() *Hints { } type MergeSpanProfileRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The client starts the stream with a request containing the profile type and the labels. Request *SelectSpanProfileRequest `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` // Max nodes in the resulting tree. MaxNodes *int64 `protobuf:"varint,2,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` // On a batch of profiles, the client sends the profiles to keep for merging. - Profiles []bool `protobuf:"varint,3,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + Profiles []bool `protobuf:"varint,3,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeSpanProfileRequest) Reset() { *x = MergeSpanProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeSpanProfileRequest) String() string { @@ -783,7 +750,7 @@ func (*MergeSpanProfileRequest) ProtoMessage() {} func (x *MergeSpanProfileRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -820,24 +787,21 @@ func (x *MergeSpanProfileRequest) GetProfiles() []bool { } type MergeSpanProfileResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The server replies batch of profiles. // A last message without profiles signals the next message will be the result of the merge. SelectedProfiles *ProfileSets `protobuf:"bytes,1,opt,name=selectedProfiles,proto3" json:"selectedProfiles,omitempty"` // The list of stracktraces for the profile with their respective value - Result *MergeSpanProfileResult `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"` + Result *MergeSpanProfileResult `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeSpanProfileResponse) Reset() { *x = MergeSpanProfileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeSpanProfileResponse) String() string { @@ -848,7 +812,7 @@ func (*MergeSpanProfileResponse) ProtoMessage() {} func (x *MergeSpanProfileResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -878,20 +842,17 @@ func (x *MergeSpanProfileResponse) GetResult() *MergeSpanProfileResult { } type MergeSpanProfileResult struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + TreeBytes []byte `protobuf:"bytes,1,opt,name=tree_bytes,json=treeBytes,proto3" json:"tree_bytes,omitempty"` unknownFields protoimpl.UnknownFields - - TreeBytes []byte `protobuf:"bytes,1,opt,name=tree_bytes,json=treeBytes,proto3" json:"tree_bytes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *MergeSpanProfileResult) Reset() { *x = MergeSpanProfileResult{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeSpanProfileResult) String() string { @@ -902,7 +863,7 @@ func (*MergeSpanProfileResult) ProtoMessage() {} func (x *MergeSpanProfileResult) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -925,23 +886,20 @@ func (x *MergeSpanProfileResult) GetTreeBytes() []byte { } type ProfileSets struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // DEPRECATED: Use fingerprints instead. - LabelsSets []*v1.Labels `protobuf:"bytes,1,rep,name=labelsSets,proto3" json:"labelsSets,omitempty"` - Profiles []*SeriesProfile `protobuf:"bytes,2,rep,name=profiles,proto3" json:"profiles,omitempty"` - Fingerprints []uint64 `protobuf:"varint,3,rep,packed,name=fingerprints,proto3" json:"fingerprints,omitempty"` + LabelsSets []*v1.Labels `protobuf:"bytes,1,rep,name=labelsSets,proto3" json:"labelsSets,omitempty"` + Profiles []*SeriesProfile `protobuf:"bytes,2,rep,name=profiles,proto3" json:"profiles,omitempty"` + Fingerprints []uint64 `protobuf:"varint,3,rep,packed,name=fingerprints,proto3" json:"fingerprints,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ProfileSets) Reset() { *x = ProfileSets{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProfileSets) String() string { @@ -952,7 +910,7 @@ func (*ProfileSets) ProtoMessage() {} func (x *ProfileSets) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -989,23 +947,20 @@ func (x *ProfileSets) GetFingerprints() []uint64 { } type SeriesProfile struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The labels index of the series LabelIndex int32 `protobuf:"varint,1,opt,name=labelIndex,proto3" json:"labelIndex,omitempty"` // timestamp in milliseconds - Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SeriesProfile) Reset() { *x = SeriesProfile{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SeriesProfile) String() string { @@ -1016,7 +971,7 @@ func (*SeriesProfile) ProtoMessage() {} func (x *SeriesProfile) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1047,10 +1002,7 @@ func (x *SeriesProfile) GetTimestamp() int64 { // Profile represents a point in time profile. type Profile struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The ID of the profile. ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` // The name and type of the profile. @@ -1060,16 +1012,16 @@ type Profile struct { // Timestamp is when that profile was created Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // The list of stracktraces for the profile with their respective value - Stacktraces []*StacktraceSample `protobuf:"bytes,5,rep,name=stacktraces,proto3" json:"stacktraces,omitempty"` + Stacktraces []*StacktraceSample `protobuf:"bytes,5,rep,name=stacktraces,proto3" json:"stacktraces,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Profile) Reset() { *x = Profile{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Profile) String() string { @@ -1080,7 +1032,7 @@ func (*Profile) ProtoMessage() {} func (x *Profile) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1131,21 +1083,18 @@ func (x *Profile) GetStacktraces() []*StacktraceSample { } type StacktraceSample struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + FunctionIds []int32 `protobuf:"varint,1,rep,packed,name=function_ids,json=functionIds,proto3" json:"function_ids,omitempty"` + Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` unknownFields protoimpl.UnknownFields - - FunctionIds []int32 `protobuf:"varint,1,rep,packed,name=function_ids,json=functionIds,proto3" json:"function_ids,omitempty"` - Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StacktraceSample) Reset() { *x = StacktraceSample{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StacktraceSample) String() string { @@ -1156,7 +1105,7 @@ func (*StacktraceSample) ProtoMessage() {} func (x *StacktraceSample) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1186,10 +1135,7 @@ func (x *StacktraceSample) GetValue() int64 { } type MergeProfilesLabelsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The client starts the stream with a request containing the profile type and the labels. Request *SelectProfilesRequest `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` // The labels to merge by @@ -1197,16 +1143,16 @@ type MergeProfilesLabelsRequest struct { // Select stack traces that match the provided selector. StackTraceSelector *v1.StackTraceSelector `protobuf:"bytes,4,opt,name=stack_trace_selector,json=stackTraceSelector,proto3,oneof" json:"stack_trace_selector,omitempty"` // On a batch of profiles, the client sends the profiles to keep for merging. - Profiles []bool `protobuf:"varint,3,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + Profiles []bool `protobuf:"varint,3,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeProfilesLabelsRequest) Reset() { *x = MergeProfilesLabelsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeProfilesLabelsRequest) String() string { @@ -1217,7 +1163,7 @@ func (*MergeProfilesLabelsRequest) ProtoMessage() {} func (x *MergeProfilesLabelsRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1261,24 +1207,21 @@ func (x *MergeProfilesLabelsRequest) GetProfiles() []bool { } type MergeProfilesLabelsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The server replies batch of profiles. // A last message without profiles signals the next message will be the result of the merge. SelectedProfiles *ProfileSets `protobuf:"bytes,1,opt,name=selectedProfiles,proto3" json:"selectedProfiles,omitempty"` // The list of series for the profile with their respective value - Series []*v1.Series `protobuf:"bytes,2,rep,name=series,proto3" json:"series,omitempty"` + Series []*v1.Series `protobuf:"bytes,2,rep,name=series,proto3" json:"series,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeProfilesLabelsResponse) Reset() { *x = MergeProfilesLabelsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeProfilesLabelsResponse) String() string { @@ -1289,7 +1232,7 @@ func (*MergeProfilesLabelsResponse) ProtoMessage() {} func (x *MergeProfilesLabelsResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1319,10 +1262,7 @@ func (x *MergeProfilesLabelsResponse) GetSeries() []*v1.Series { } type MergeProfilesPprofRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The client starts the stream with a request containing the profile type and the labels. Request *SelectProfilesRequest `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` // Max nodes in the resulting profile. @@ -1330,16 +1270,16 @@ type MergeProfilesPprofRequest struct { // Select stack traces that match the provided selector. StackTraceSelector *v1.StackTraceSelector `protobuf:"bytes,4,opt,name=stack_trace_selector,json=stackTraceSelector,proto3,oneof" json:"stack_trace_selector,omitempty"` // On a batch of profiles, the client sends the profiles to keep for merging. - Profiles []bool `protobuf:"varint,2,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + Profiles []bool `protobuf:"varint,2,rep,packed,name=profiles,proto3" json:"profiles,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeProfilesPprofRequest) Reset() { *x = MergeProfilesPprofRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeProfilesPprofRequest) String() string { @@ -1350,7 +1290,7 @@ func (*MergeProfilesPprofRequest) ProtoMessage() {} func (x *MergeProfilesPprofRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1394,24 +1334,21 @@ func (x *MergeProfilesPprofRequest) GetProfiles() []bool { } type MergeProfilesPprofResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The server replies batch of profiles. // A last message without profiles signals the next message will be the result of the merge. SelectedProfiles *ProfileSets `protobuf:"bytes,1,opt,name=selectedProfiles,proto3" json:"selectedProfiles,omitempty"` // The merge result in the pprof format. - Result []byte `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"` + Result []byte `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MergeProfilesPprofResponse) Reset() { *x = MergeProfilesPprofResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *MergeProfilesPprofResponse) String() string { @@ -1422,7 +1359,7 @@ func (*MergeProfilesPprofResponse) ProtoMessage() {} func (x *MergeProfilesPprofResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1452,25 +1389,22 @@ func (x *MergeProfilesPprofResponse) GetResult() []byte { } type BlockMetadataRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. Start int64 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. - End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *BlockMetadataRequest) Reset() { *x = BlockMetadataRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BlockMetadataRequest) String() string { @@ -1481,7 +1415,7 @@ func (*BlockMetadataRequest) ProtoMessage() {} func (x *BlockMetadataRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1511,21 +1445,18 @@ func (x *BlockMetadataRequest) GetEnd() int64 { } type BlockMetadataResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Blocks that are present on the instance for the start to end period - Blocks []*v1.BlockInfo `protobuf:"bytes,1,rep,name=blocks,proto3" json:"blocks,omitempty"` + Blocks []*v1.BlockInfo `protobuf:"bytes,1,rep,name=blocks,proto3" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *BlockMetadataResponse) Reset() { *x = BlockMetadataResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BlockMetadataResponse) String() string { @@ -1536,7 +1467,7 @@ func (*BlockMetadataResponse) ProtoMessage() {} func (x *BlockMetadataResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1560,20 +1491,17 @@ func (x *BlockMetadataResponse) GetBlocks() []*v1.BlockInfo { // Hints are used to propagate information about querying type Hints struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Block *BlockHints `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` unknownFields protoimpl.UnknownFields - - Block *BlockHints `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Hints) Reset() { *x = Hints{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Hints) String() string { @@ -1584,7 +1512,7 @@ func (*Hints) ProtoMessage() {} func (x *Hints) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1607,23 +1535,20 @@ func (x *Hints) GetBlock() *BlockHints { } type BlockHints struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The ULID of blocks to query Ulids []string `protobuf:"bytes,1,rep,name=ulids,proto3" json:"ulids,omitempty"` // When all blocks are compacted, there is no effect of the replication factor, hence we do not need to run deduplication. Deduplication bool `protobuf:"varint,2,opt,name=deduplication,proto3" json:"deduplication,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *BlockHints) Reset() { *x = BlockHints{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BlockHints) String() string { @@ -1634,7 +1559,7 @@ func (*BlockHints) ProtoMessage() {} func (x *BlockHints) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1664,20 +1589,17 @@ func (x *BlockHints) GetDeduplication() bool { } type GetBlockStatsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Ulids []string `protobuf:"bytes,1,rep,name=ulids,proto3" json:"ulids,omitempty"` unknownFields protoimpl.UnknownFields - - Ulids []string `protobuf:"bytes,1,rep,name=ulids,proto3" json:"ulids,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetBlockStatsRequest) Reset() { *x = GetBlockStatsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetBlockStatsRequest) String() string { @@ -1688,7 +1610,7 @@ func (*GetBlockStatsRequest) ProtoMessage() {} func (x *GetBlockStatsRequest) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1711,20 +1633,17 @@ func (x *GetBlockStatsRequest) GetUlids() []string { } type GetBlockStatsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + BlockStats []*BlockStats `protobuf:"bytes,1,rep,name=block_stats,json=blockStats,proto3" json:"block_stats,omitempty"` unknownFields protoimpl.UnknownFields - - BlockStats []*BlockStats `protobuf:"bytes,1,rep,name=block_stats,json=blockStats,proto3" json:"block_stats,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetBlockStatsResponse) Reset() { *x = GetBlockStatsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetBlockStatsResponse) String() string { @@ -1735,7 +1654,7 @@ func (*GetBlockStatsResponse) ProtoMessage() {} func (x *GetBlockStatsResponse) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1758,25 +1677,22 @@ func (x *GetBlockStatsResponse) GetBlockStats() []*BlockStats { } type BlockStats struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SeriesCount uint64 `protobuf:"varint,2,opt,name=series_count,json=seriesCount,proto3" json:"series_count,omitempty"` + ProfileCount uint64 `protobuf:"varint,3,opt,name=profile_count,json=profileCount,proto3" json:"profile_count,omitempty"` + SampleCount uint64 `protobuf:"varint,4,opt,name=sample_count,json=sampleCount,proto3" json:"sample_count,omitempty"` + IndexBytes uint64 `protobuf:"varint,5,opt,name=index_bytes,json=indexBytes,proto3" json:"index_bytes,omitempty"` + ProfileBytes uint64 `protobuf:"varint,6,opt,name=profile_bytes,json=profileBytes,proto3" json:"profile_bytes,omitempty"` + SymbolBytes uint64 `protobuf:"varint,7,opt,name=symbol_bytes,json=symbolBytes,proto3" json:"symbol_bytes,omitempty"` unknownFields protoimpl.UnknownFields - - SeriesCount uint64 `protobuf:"varint,2,opt,name=series_count,json=seriesCount,proto3" json:"series_count,omitempty"` - ProfileCount uint64 `protobuf:"varint,3,opt,name=profile_count,json=profileCount,proto3" json:"profile_count,omitempty"` - SampleCount uint64 `protobuf:"varint,4,opt,name=sample_count,json=sampleCount,proto3" json:"sample_count,omitempty"` - IndexBytes uint64 `protobuf:"varint,5,opt,name=index_bytes,json=indexBytes,proto3" json:"index_bytes,omitempty"` - ProfileBytes uint64 `protobuf:"varint,6,opt,name=profile_bytes,json=profileBytes,proto3" json:"profile_bytes,omitempty"` - SymbolBytes uint64 `protobuf:"varint,7,opt,name=symbol_bytes,json=symbolBytes,proto3" json:"symbol_bytes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BlockStats) Reset() { *x = BlockStats{} - if protoimpl.UnsafeEnabled { - mi := &file_ingester_v1_ingester_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ingester_v1_ingester_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BlockStats) String() string { @@ -1787,7 +1703,7 @@ func (*BlockStats) ProtoMessage() {} func (x *BlockStats) ProtoReflect() protoreflect.Message { mi := &file_ingester_v1_ingester_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1846,361 +1762,170 @@ func (x *BlockStats) GetSymbolBytes() uint64 { var File_ingester_v1_ingester_proto protoreflect.FileDescriptor -var file_ingester_v1_ingester_proto_rawDesc = []byte{ - 0x0a, 0x1a, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x69, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x12, 0x70, 0x75, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x75, 0x73, 0x68, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, - 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3d, 0x0a, 0x13, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x52, 0x0a, 0x14, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, - 0x74, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x12, 0x1f, 0x0a, 0x0b, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x41, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x09, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x53, 0x65, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x46, 0x6c, 0x75, 0x73, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x46, 0x6c, 0x75, 0x73, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa6, 0x02, 0x0a, 0x15, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, - 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x2d, 0x0a, - 0x05, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x69, - 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x6e, 0x74, 0x73, - 0x48, 0x00, 0x52, 0x05, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x4a, 0x0a, 0x0b, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x48, 0x01, 0x52, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x68, 0x69, 0x6e, - 0x74, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0xab, 0x01, 0x0a, 0x1f, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x4e, 0x6f, - 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x08, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, - 0x22, 0xe4, 0x01, 0x0a, 0x1e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x4d, 0x65, 0x72, - 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, - 0x12, 0x3f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x53, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x72, 0x65, 0x65, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x72, - 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x20, 0x4d, 0x65, 0x72, 0x67, - 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, - 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x10, - 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x73, - 0x52, 0x10, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x12, 0x43, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x74, - 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xf2, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x73, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x23, - 0x0a, 0x0d, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x05, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x48, 0x00, 0x52, 0x05, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x88, - 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xa6, 0x01, 0x0a, - 0x17, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x69, 0x6e, 0x67, 0x65, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x70, - 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x6d, 0x61, 0x78, - 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, - 0x6d, 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x08, 0x52, 0x08, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x61, 0x78, 0x5f, - 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x9d, 0x01, 0x0a, 0x18, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, - 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, - 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x53, 0x65, 0x74, 0x73, 0x52, 0x10, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, - 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x37, 0x0a, 0x16, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, - 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x72, 0x65, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x9b, - 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x73, 0x12, 0x30, - 0x0a, 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x53, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x52, 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x53, 0x65, 0x74, 0x73, - 0x12, 0x36, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x08, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x66, 0x69, 0x6e, 0x67, - 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0c, - 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x4d, 0x0a, 0x0d, - 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1e, 0x0a, - 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1c, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xd0, 0x01, 0x0a, 0x07, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3f, 0x0a, - 0x0b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x53, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x22, 0x4b, - 0x0a, 0x10, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x53, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xf4, 0x01, 0x0a, 0x1a, - 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x07, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x69, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, - 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x62, 0x79, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x62, 0x79, 0x12, 0x53, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x63, - 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x12, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, - 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x08, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x74, - 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x22, 0x8d, 0x01, 0x0a, 0x1b, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, - 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x53, 0x65, 0x74, 0x73, 0x52, 0x10, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x22, 0x93, 0x02, 0x0a, 0x19, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x3c, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, - 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x48, 0x00, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, - 0x12, 0x53, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, - 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x54, - 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x48, 0x01, 0x52, 0x12, - 0x73, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x08, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x42, - 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, - 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x7a, 0x0a, 0x1a, 0x4d, 0x65, 0x72, 0x67, - 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x74, 0x73, 0x52, 0x10, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3e, 0x0a, 0x14, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x03, 0x65, 0x6e, 0x64, 0x22, 0x44, 0x0a, 0x15, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, - 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x36, 0x0a, 0x05, 0x48, 0x69, - 0x6e, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x52, 0x05, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x69, 0x6e, 0x74, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x75, 0x6c, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x05, 0x75, 0x6c, 0x69, 0x64, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x64, - 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x0a, 0x14, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x6c, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6c, 0x69, 0x64, 0x73, 0x22, 0x51, 0x0a, 0x15, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, - 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, - 0x73, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x22, 0xe0, 0x01, - 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, - 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x2a, 0x6b, 0x0a, 0x16, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x45, - 0x52, 0x47, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x45, 0x52, 0x47, - 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x43, 0x4b, 0x54, 0x52, - 0x41, 0x43, 0x45, 0x53, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x5f, - 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x54, 0x52, 0x45, 0x45, 0x10, 0x02, 0x32, 0x90, 0x09, - 0x0a, 0x0f, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x35, 0x0a, 0x04, 0x50, 0x75, 0x73, 0x68, 0x12, 0x14, 0x2e, 0x70, 0x75, 0x73, 0x68, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x15, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x55, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x73, 0x12, 0x20, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, - 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, - 0x05, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x12, 0x19, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1a, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x46, 0x6c, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x7d, 0x0a, 0x18, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x69, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x69, 0x6e, 0x67, 0x65, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x6e, - 0x0a, 0x13, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x27, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, - 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, - 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x6b, - 0x0a, 0x12, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, - 0x70, 0x72, 0x6f, 0x66, 0x12, 0x26, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x69, - 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x65, 0x0a, 0x10, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, - 0x24, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, - 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, - 0x30, 0x01, 0x12, 0x58, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x21, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, - 0x20, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, - 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x69, 0x6e, 0x67, - 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x42, 0xb3, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, - 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x76, 0x31, - 0x3b, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x49, 0x58, - 0x58, 0xaa, 0x02, 0x0b, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x56, 0x31, 0xca, - 0x02, 0x0b, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, - 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, - 0x65, 0x72, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_ingester_v1_ingester_proto_rawDesc = "" + + "\n" + + "\x1aingester/v1/ingester.proto\x12\vingester.v1\x1a\x17google/v1/profile.proto\x1a\x12push/v1/push.proto\x1a\x14types/v1/types.proto\"=\n" + + "\x13ProfileTypesRequest\x12\x14\n" + + "\x05start\x18\x01 \x01(\x03R\x05start\x12\x10\n" + + "\x03end\x18\x02 \x01(\x03R\x03end\"R\n" + + "\x14ProfileTypesResponse\x12:\n" + + "\rprofile_types\x18\x01 \x03(\v2\x15.types.v1.ProfileTypeR\fprofileTypes\"t\n" + + "\rSeriesRequest\x12\x1a\n" + + "\bmatchers\x18\x01 \x03(\tR\bmatchers\x12\x1f\n" + + "\vlabel_names\x18\x02 \x03(\tR\n" + + "labelNames\x12\x14\n" + + "\x05start\x18\x03 \x01(\x03R\x05start\x12\x10\n" + + "\x03end\x18\x04 \x01(\x03R\x03end\"A\n" + + "\x0eSeriesResponse\x12/\n" + + "\n" + + "labels_set\x18\x02 \x03(\v2\x10.types.v1.LabelsR\tlabelsSet\"\x0e\n" + + "\fFlushRequest\"\x0f\n" + + "\rFlushResponse\"\xa6\x02\n" + + "\x15SelectProfilesRequest\x12%\n" + + "\x0elabel_selector\x18\x01 \x01(\tR\rlabelSelector\x12)\n" + + "\x04type\x18\x02 \x01(\v2\x15.types.v1.ProfileTypeR\x04type\x12\x14\n" + + "\x05start\x18\x03 \x01(\x03R\x05start\x12\x10\n" + + "\x03end\x18\x04 \x01(\x03R\x03end\x12-\n" + + "\x05hints\x18\x05 \x01(\v2\x12.ingester.v1.HintsH\x00R\x05hints\x88\x01\x01\x12J\n" + + "\vaggregation\x18\x06 \x01(\x0e2#.types.v1.TimeSeriesAggregationTypeH\x01R\vaggregation\x88\x01\x01B\b\n" + + "\x06_hintsB\x0e\n" + + "\f_aggregation\"\xab\x01\n" + + "\x1fMergeProfilesStacktracesRequest\x12<\n" + + "\arequest\x18\x01 \x01(\v2\".ingester.v1.SelectProfilesRequestR\arequest\x12 \n" + + "\tmax_nodes\x18\x03 \x01(\x03H\x00R\bmaxNodes\x88\x01\x01\x12\x1a\n" + + "\bprofiles\x18\x02 \x03(\bR\bprofilesB\f\n" + + "\n" + + "_max_nodes\"\xe4\x01\n" + + "\x1eMergeProfilesStacktracesResult\x12;\n" + + "\x06format\x18\x03 \x01(\x0e2#.ingester.v1.StacktracesMergeFormatR\x06format\x12?\n" + + "\vstacktraces\x18\x01 \x03(\v2\x1d.ingester.v1.StacktraceSampleR\vstacktraces\x12%\n" + + "\x0efunction_names\x18\x02 \x03(\tR\rfunctionNames\x12\x1d\n" + + "\n" + + "tree_bytes\x18\x04 \x01(\fR\ttreeBytes\"\xad\x01\n" + + " MergeProfilesStacktracesResponse\x12D\n" + + "\x10selectedProfiles\x18\x01 \x01(\v2\x18.ingester.v1.ProfileSetsR\x10selectedProfiles\x12C\n" + + "\x06result\x18\x03 \x01(\v2+.ingester.v1.MergeProfilesStacktracesResultR\x06result\"\xf2\x01\n" + + "\x18SelectSpanProfileRequest\x12%\n" + + "\x0elabel_selector\x18\x01 \x01(\tR\rlabelSelector\x12)\n" + + "\x04type\x18\x02 \x01(\v2\x15.types.v1.ProfileTypeR\x04type\x12\x14\n" + + "\x05start\x18\x03 \x01(\x03R\x05start\x12\x10\n" + + "\x03end\x18\x04 \x01(\x03R\x03end\x12#\n" + + "\rspan_selector\x18\x05 \x03(\tR\fspanSelector\x12-\n" + + "\x05hints\x18\x06 \x01(\v2\x12.ingester.v1.HintsH\x00R\x05hints\x88\x01\x01B\b\n" + + "\x06_hints\"\xa6\x01\n" + + "\x17MergeSpanProfileRequest\x12?\n" + + "\arequest\x18\x01 \x01(\v2%.ingester.v1.SelectSpanProfileRequestR\arequest\x12 \n" + + "\tmax_nodes\x18\x02 \x01(\x03H\x00R\bmaxNodes\x88\x01\x01\x12\x1a\n" + + "\bprofiles\x18\x03 \x03(\bR\bprofilesB\f\n" + + "\n" + + "_max_nodes\"\x9d\x01\n" + + "\x18MergeSpanProfileResponse\x12D\n" + + "\x10selectedProfiles\x18\x01 \x01(\v2\x18.ingester.v1.ProfileSetsR\x10selectedProfiles\x12;\n" + + "\x06result\x18\x02 \x01(\v2#.ingester.v1.MergeSpanProfileResultR\x06result\"7\n" + + "\x16MergeSpanProfileResult\x12\x1d\n" + + "\n" + + "tree_bytes\x18\x01 \x01(\fR\ttreeBytes\"\x9b\x01\n" + + "\vProfileSets\x120\n" + + "\n" + + "labelsSets\x18\x01 \x03(\v2\x10.types.v1.LabelsR\n" + + "labelsSets\x126\n" + + "\bprofiles\x18\x02 \x03(\v2\x1a.ingester.v1.SeriesProfileR\bprofiles\x12\"\n" + + "\ffingerprints\x18\x03 \x03(\x04R\ffingerprints\"M\n" + + "\rSeriesProfile\x12\x1e\n" + + "\n" + + "labelIndex\x18\x01 \x01(\x05R\n" + + "labelIndex\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\"\xd0\x01\n" + + "\aProfile\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\tR\x02ID\x12)\n" + + "\x04type\x18\x02 \x01(\v2\x15.types.v1.ProfileTypeR\x04type\x12+\n" + + "\x06labels\x18\x03 \x03(\v2\x13.types.v1.LabelPairR\x06labels\x12\x1c\n" + + "\ttimestamp\x18\x04 \x01(\x03R\ttimestamp\x12?\n" + + "\vstacktraces\x18\x05 \x03(\v2\x1d.ingester.v1.StacktraceSampleR\vstacktraces\"K\n" + + "\x10StacktraceSample\x12!\n" + + "\ffunction_ids\x18\x01 \x03(\x05R\vfunctionIds\x12\x14\n" + + "\x05value\x18\x02 \x01(\x03R\x05value\"\xf4\x01\n" + + "\x1aMergeProfilesLabelsRequest\x12<\n" + + "\arequest\x18\x01 \x01(\v2\".ingester.v1.SelectProfilesRequestR\arequest\x12\x0e\n" + + "\x02by\x18\x02 \x03(\tR\x02by\x12S\n" + + "\x14stack_trace_selector\x18\x04 \x01(\v2\x1c.types.v1.StackTraceSelectorH\x00R\x12stackTraceSelector\x88\x01\x01\x12\x1a\n" + + "\bprofiles\x18\x03 \x03(\bR\bprofilesB\x17\n" + + "\x15_stack_trace_selector\"\x8d\x01\n" + + "\x1bMergeProfilesLabelsResponse\x12D\n" + + "\x10selectedProfiles\x18\x01 \x01(\v2\x18.ingester.v1.ProfileSetsR\x10selectedProfiles\x12(\n" + + "\x06series\x18\x02 \x03(\v2\x10.types.v1.SeriesR\x06series\"\x93\x02\n" + + "\x19MergeProfilesPprofRequest\x12<\n" + + "\arequest\x18\x01 \x01(\v2\".ingester.v1.SelectProfilesRequestR\arequest\x12 \n" + + "\tmax_nodes\x18\x03 \x01(\x03H\x00R\bmaxNodes\x88\x01\x01\x12S\n" + + "\x14stack_trace_selector\x18\x04 \x01(\v2\x1c.types.v1.StackTraceSelectorH\x01R\x12stackTraceSelector\x88\x01\x01\x12\x1a\n" + + "\bprofiles\x18\x02 \x03(\bR\bprofilesB\f\n" + + "\n" + + "_max_nodesB\x17\n" + + "\x15_stack_trace_selector\"z\n" + + "\x1aMergeProfilesPprofResponse\x12D\n" + + "\x10selectedProfiles\x18\x01 \x01(\v2\x18.ingester.v1.ProfileSetsR\x10selectedProfiles\x12\x16\n" + + "\x06result\x18\x02 \x01(\fR\x06result\">\n" + + "\x14BlockMetadataRequest\x12\x14\n" + + "\x05start\x18\x01 \x01(\x03R\x05start\x12\x10\n" + + "\x03end\x18\x02 \x01(\x03R\x03end\"D\n" + + "\x15BlockMetadataResponse\x12+\n" + + "\x06blocks\x18\x01 \x03(\v2\x13.types.v1.BlockInfoR\x06blocks\"6\n" + + "\x05Hints\x12-\n" + + "\x05block\x18\x01 \x01(\v2\x17.ingester.v1.BlockHintsR\x05block\"H\n" + + "\n" + + "BlockHints\x12\x14\n" + + "\x05ulids\x18\x01 \x03(\tR\x05ulids\x12$\n" + + "\rdeduplication\x18\x02 \x01(\bR\rdeduplication\",\n" + + "\x14GetBlockStatsRequest\x12\x14\n" + + "\x05ulids\x18\x01 \x03(\tR\x05ulids\"Q\n" + + "\x15GetBlockStatsResponse\x128\n" + + "\vblock_stats\x18\x01 \x03(\v2\x17.ingester.v1.BlockStatsR\n" + + "blockStats\"\xe0\x01\n" + + "\n" + + "BlockStats\x12!\n" + + "\fseries_count\x18\x02 \x01(\x04R\vseriesCount\x12#\n" + + "\rprofile_count\x18\x03 \x01(\x04R\fprofileCount\x12!\n" + + "\fsample_count\x18\x04 \x01(\x04R\vsampleCount\x12\x1f\n" + + "\vindex_bytes\x18\x05 \x01(\x04R\n" + + "indexBytes\x12#\n" + + "\rprofile_bytes\x18\x06 \x01(\x04R\fprofileBytes\x12!\n" + + "\fsymbol_bytes\x18\a \x01(\x04R\vsymbolBytes*k\n" + + "\x16StacktracesMergeFormat\x12\x1c\n" + + "\x18MERGE_FORMAT_UNSPECIFIED\x10\x00\x12\x1c\n" + + "\x18MERGE_FORMAT_STACKTRACES\x10\x01\x12\x15\n" + + "\x11MERGE_FORMAT_TREE\x10\x022\x90\t\n" + + "\x0fIngesterService\x125\n" + + "\x04Push\x12\x14.push.v1.PushRequest\x1a\x15.push.v1.PushResponse\"\x00\x12L\n" + + "\vLabelValues\x12\x1c.types.v1.LabelValuesRequest\x1a\x1d.types.v1.LabelValuesResponse\"\x00\x12I\n" + + "\n" + + "LabelNames\x12\x1b.types.v1.LabelNamesRequest\x1a\x1c.types.v1.LabelNamesResponse\"\x00\x12U\n" + + "\fProfileTypes\x12 .ingester.v1.ProfileTypesRequest\x1a!.ingester.v1.ProfileTypesResponse\"\x00\x12C\n" + + "\x06Series\x12\x1a.ingester.v1.SeriesRequest\x1a\x1b.ingester.v1.SeriesResponse\"\x00\x12@\n" + + "\x05Flush\x12\x19.ingester.v1.FlushRequest\x1a\x1a.ingester.v1.FlushResponse\"\x00\x12}\n" + + "\x18MergeProfilesStacktraces\x12,.ingester.v1.MergeProfilesStacktracesRequest\x1a-.ingester.v1.MergeProfilesStacktracesResponse\"\x00(\x010\x01\x12n\n" + + "\x13MergeProfilesLabels\x12'.ingester.v1.MergeProfilesLabelsRequest\x1a(.ingester.v1.MergeProfilesLabelsResponse\"\x00(\x010\x01\x12k\n" + + "\x12MergeProfilesPprof\x12&.ingester.v1.MergeProfilesPprofRequest\x1a'.ingester.v1.MergeProfilesPprofResponse\"\x00(\x010\x01\x12e\n" + + "\x10MergeSpanProfile\x12$.ingester.v1.MergeSpanProfileRequest\x1a%.ingester.v1.MergeSpanProfileResponse\"\x00(\x010\x01\x12X\n" + + "\rBlockMetadata\x12!.ingester.v1.BlockMetadataRequest\x1a\".ingester.v1.BlockMetadataResponse\"\x00\x12X\n" + + "\x0fGetProfileStats\x12 .types.v1.GetProfileStatsRequest\x1a!.types.v1.GetProfileStatsResponse\"\x00\x12X\n" + + "\rGetBlockStats\x12!.ingester.v1.GetBlockStatsRequest\x1a\".ingester.v1.GetBlockStatsResponse\"\x00B\xb3\x01\n" + + "\x0fcom.ingester.v1B\rIngesterProtoP\x01ZDgithub.com/grafana/pyroscope/api/gen/proto/go/ingester/v1;ingesterv1\xa2\x02\x03IXX\xaa\x02\vIngester.V1\xca\x02\vIngester\\V1\xe2\x02\x17Ingester\\V1\\GPBMetadata\xea\x02\fIngester::V1b\x06proto3" var ( file_ingester_v1_ingester_proto_rawDescOnce sync.Once - file_ingester_v1_ingester_proto_rawDescData = file_ingester_v1_ingester_proto_rawDesc + file_ingester_v1_ingester_proto_rawDescData []byte ) func file_ingester_v1_ingester_proto_rawDescGZIP() []byte { file_ingester_v1_ingester_proto_rawDescOnce.Do(func() { - file_ingester_v1_ingester_proto_rawDescData = protoimpl.X.CompressGZIP(file_ingester_v1_ingester_proto_rawDescData) + file_ingester_v1_ingester_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ingester_v1_ingester_proto_rawDesc), len(file_ingester_v1_ingester_proto_rawDesc))) }) return file_ingester_v1_ingester_proto_rawDescData } var file_ingester_v1_ingester_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_ingester_v1_ingester_proto_msgTypes = make([]protoimpl.MessageInfo, 29) -var file_ingester_v1_ingester_proto_goTypes = []interface{}{ +var file_ingester_v1_ingester_proto_goTypes = []any{ (StacktracesMergeFormat)(0), // 0: ingester.v1.StacktracesMergeFormat (*ProfileTypesRequest)(nil), // 1: ingester.v1.ProfileTypesRequest (*ProfileTypesResponse)(nil), // 2: ingester.v1.ProfileTypesResponse @@ -2316,367 +2041,17 @@ func file_ingester_v1_ingester_proto_init() { if File_ingester_v1_ingester_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_ingester_v1_ingester_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProfileTypesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProfileTypesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SeriesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SeriesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlushRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlushResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectProfilesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeProfilesStacktracesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeProfilesStacktracesResult); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeProfilesStacktracesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectSpanProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeSpanProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeSpanProfileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeSpanProfileResult); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProfileSets); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SeriesProfile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Profile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StacktraceSample); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeProfilesLabelsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeProfilesLabelsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeProfilesPprofRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MergeProfilesPprofResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockMetadataRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockMetadataResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hints); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockHints); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockStatsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockStatsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ingester_v1_ingester_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockStats); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_ingester_v1_ingester_proto_msgTypes[6].OneofWrappers = []interface{}{} - file_ingester_v1_ingester_proto_msgTypes[7].OneofWrappers = []interface{}{} - file_ingester_v1_ingester_proto_msgTypes[10].OneofWrappers = []interface{}{} - file_ingester_v1_ingester_proto_msgTypes[11].OneofWrappers = []interface{}{} - file_ingester_v1_ingester_proto_msgTypes[18].OneofWrappers = []interface{}{} - file_ingester_v1_ingester_proto_msgTypes[20].OneofWrappers = []interface{}{} + file_ingester_v1_ingester_proto_msgTypes[6].OneofWrappers = []any{} + file_ingester_v1_ingester_proto_msgTypes[7].OneofWrappers = []any{} + file_ingester_v1_ingester_proto_msgTypes[10].OneofWrappers = []any{} + file_ingester_v1_ingester_proto_msgTypes[11].OneofWrappers = []any{} + file_ingester_v1_ingester_proto_msgTypes[18].OneofWrappers = []any{} + file_ingester_v1_ingester_proto_msgTypes[20].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_ingester_v1_ingester_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_ingester_v1_ingester_proto_rawDesc), len(file_ingester_v1_ingester_proto_rawDesc)), NumEnums: 1, NumMessages: 29, NumExtensions: 0, @@ -2688,7 +2063,6 @@ func file_ingester_v1_ingester_proto_init() { MessageInfos: file_ingester_v1_ingester_proto_msgTypes, }.Build() File_ingester_v1_ingester_proto = out.File - file_ingester_v1_ingester_proto_rawDesc = nil file_ingester_v1_ingester_proto_goTypes = nil file_ingester_v1_ingester_proto_depIdxs = nil } diff --git a/api/gen/proto/go/ingester/v1/ingesterv1connect/ingester.connect.go b/api/gen/proto/go/ingester/v1/ingesterv1connect/ingester.connect.go index 9f629348a5..f23154bd08 100644 --- a/api/gen/proto/go/ingester/v1/ingesterv1connect/ingester.connect.go +++ b/api/gen/proto/go/ingester/v1/ingesterv1connect/ingester.connect.go @@ -8,9 +8,9 @@ import ( connect "connectrpc.com/connect" context "context" errors "errors" - v1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - v11 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" - v12 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + v12 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + v11 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" http "net/http" strings "strings" ) @@ -73,42 +73,24 @@ const ( IngesterServiceGetBlockStatsProcedure = "/ingester.v1.IngesterService/GetBlockStats" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - ingesterServiceServiceDescriptor = v1.File_ingester_v1_ingester_proto.Services().ByName("IngesterService") - ingesterServicePushMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("Push") - ingesterServiceLabelValuesMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("LabelValues") - ingesterServiceLabelNamesMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("LabelNames") - ingesterServiceProfileTypesMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("ProfileTypes") - ingesterServiceSeriesMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("Series") - ingesterServiceFlushMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("Flush") - ingesterServiceMergeProfilesStacktracesMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("MergeProfilesStacktraces") - ingesterServiceMergeProfilesLabelsMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("MergeProfilesLabels") - ingesterServiceMergeProfilesPprofMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("MergeProfilesPprof") - ingesterServiceMergeSpanProfileMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("MergeSpanProfile") - ingesterServiceBlockMetadataMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("BlockMetadata") - ingesterServiceGetProfileStatsMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("GetProfileStats") - ingesterServiceGetBlockStatsMethodDescriptor = ingesterServiceServiceDescriptor.Methods().ByName("GetBlockStats") -) - // IngesterServiceClient is a client for the ingester.v1.IngesterService service. type IngesterServiceClient interface { - Push(context.Context, *connect.Request[v11.PushRequest]) (*connect.Response[v11.PushResponse], error) - LabelValues(context.Context, *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) - LabelNames(context.Context, *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) + Push(context.Context, *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) + LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) + LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) // Deprecated: ProfileType call is deprecated in the store components // TODO: Remove this call in release v1.4 - ProfileTypes(context.Context, *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) - Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) - Flush(context.Context, *connect.Request[v1.FlushRequest]) (*connect.Response[v1.FlushResponse], error) - MergeProfilesStacktraces(context.Context) *connect.BidiStreamForClient[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse] - MergeProfilesLabels(context.Context) *connect.BidiStreamForClient[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse] - MergeProfilesPprof(context.Context) *connect.BidiStreamForClient[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse] - MergeSpanProfile(context.Context) *connect.BidiStreamForClient[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse] - BlockMetadata(context.Context, *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) + ProfileTypes(context.Context, *connect.Request[v12.ProfileTypesRequest]) (*connect.Response[v12.ProfileTypesResponse], error) + Series(context.Context, *connect.Request[v12.SeriesRequest]) (*connect.Response[v12.SeriesResponse], error) + Flush(context.Context, *connect.Request[v12.FlushRequest]) (*connect.Response[v12.FlushResponse], error) + MergeProfilesStacktraces(context.Context) *connect.BidiStreamForClient[v12.MergeProfilesStacktracesRequest, v12.MergeProfilesStacktracesResponse] + MergeProfilesLabels(context.Context) *connect.BidiStreamForClient[v12.MergeProfilesLabelsRequest, v12.MergeProfilesLabelsResponse] + MergeProfilesPprof(context.Context) *connect.BidiStreamForClient[v12.MergeProfilesPprofRequest, v12.MergeProfilesPprofResponse] + MergeSpanProfile(context.Context) *connect.BidiStreamForClient[v12.MergeSpanProfileRequest, v12.MergeSpanProfileResponse] + BlockMetadata(context.Context, *connect.Request[v12.BlockMetadataRequest]) (*connect.Response[v12.BlockMetadataResponse], error) // GetProfileStats returns profile stats for the current tenant. - GetProfileStats(context.Context, *connect.Request[v12.GetProfileStatsRequest]) (*connect.Response[v12.GetProfileStatsResponse], error) - GetBlockStats(context.Context, *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) + GetProfileStats(context.Context, *connect.Request[v11.GetProfileStatsRequest]) (*connect.Response[v11.GetProfileStatsResponse], error) + GetBlockStats(context.Context, *connect.Request[v12.GetBlockStatsRequest]) (*connect.Response[v12.GetBlockStatsResponse], error) } // NewIngesterServiceClient constructs a client for the ingester.v1.IngesterService service. By @@ -120,83 +102,84 @@ type IngesterServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewIngesterServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) IngesterServiceClient { baseURL = strings.TrimRight(baseURL, "/") + ingesterServiceMethods := v12.File_ingester_v1_ingester_proto.Services().ByName("IngesterService").Methods() return &ingesterServiceClient{ - push: connect.NewClient[v11.PushRequest, v11.PushResponse]( + push: connect.NewClient[v1.PushRequest, v1.PushResponse]( httpClient, baseURL+IngesterServicePushProcedure, - connect.WithSchema(ingesterServicePushMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("Push")), connect.WithClientOptions(opts...), ), - labelValues: connect.NewClient[v12.LabelValuesRequest, v12.LabelValuesResponse]( + labelValues: connect.NewClient[v11.LabelValuesRequest, v11.LabelValuesResponse]( httpClient, baseURL+IngesterServiceLabelValuesProcedure, - connect.WithSchema(ingesterServiceLabelValuesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("LabelValues")), connect.WithClientOptions(opts...), ), - labelNames: connect.NewClient[v12.LabelNamesRequest, v12.LabelNamesResponse]( + labelNames: connect.NewClient[v11.LabelNamesRequest, v11.LabelNamesResponse]( httpClient, baseURL+IngesterServiceLabelNamesProcedure, - connect.WithSchema(ingesterServiceLabelNamesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("LabelNames")), connect.WithClientOptions(opts...), ), - profileTypes: connect.NewClient[v1.ProfileTypesRequest, v1.ProfileTypesResponse]( + profileTypes: connect.NewClient[v12.ProfileTypesRequest, v12.ProfileTypesResponse]( httpClient, baseURL+IngesterServiceProfileTypesProcedure, - connect.WithSchema(ingesterServiceProfileTypesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("ProfileTypes")), connect.WithClientOptions(opts...), ), - series: connect.NewClient[v1.SeriesRequest, v1.SeriesResponse]( + series: connect.NewClient[v12.SeriesRequest, v12.SeriesResponse]( httpClient, baseURL+IngesterServiceSeriesProcedure, - connect.WithSchema(ingesterServiceSeriesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("Series")), connect.WithClientOptions(opts...), ), - flush: connect.NewClient[v1.FlushRequest, v1.FlushResponse]( + flush: connect.NewClient[v12.FlushRequest, v12.FlushResponse]( httpClient, baseURL+IngesterServiceFlushProcedure, - connect.WithSchema(ingesterServiceFlushMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("Flush")), connect.WithClientOptions(opts...), ), - mergeProfilesStacktraces: connect.NewClient[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse]( + mergeProfilesStacktraces: connect.NewClient[v12.MergeProfilesStacktracesRequest, v12.MergeProfilesStacktracesResponse]( httpClient, baseURL+IngesterServiceMergeProfilesStacktracesProcedure, - connect.WithSchema(ingesterServiceMergeProfilesStacktracesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeProfilesStacktraces")), connect.WithClientOptions(opts...), ), - mergeProfilesLabels: connect.NewClient[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse]( + mergeProfilesLabels: connect.NewClient[v12.MergeProfilesLabelsRequest, v12.MergeProfilesLabelsResponse]( httpClient, baseURL+IngesterServiceMergeProfilesLabelsProcedure, - connect.WithSchema(ingesterServiceMergeProfilesLabelsMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeProfilesLabels")), connect.WithClientOptions(opts...), ), - mergeProfilesPprof: connect.NewClient[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse]( + mergeProfilesPprof: connect.NewClient[v12.MergeProfilesPprofRequest, v12.MergeProfilesPprofResponse]( httpClient, baseURL+IngesterServiceMergeProfilesPprofProcedure, - connect.WithSchema(ingesterServiceMergeProfilesPprofMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeProfilesPprof")), connect.WithClientOptions(opts...), ), - mergeSpanProfile: connect.NewClient[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse]( + mergeSpanProfile: connect.NewClient[v12.MergeSpanProfileRequest, v12.MergeSpanProfileResponse]( httpClient, baseURL+IngesterServiceMergeSpanProfileProcedure, - connect.WithSchema(ingesterServiceMergeSpanProfileMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeSpanProfile")), connect.WithClientOptions(opts...), ), - blockMetadata: connect.NewClient[v1.BlockMetadataRequest, v1.BlockMetadataResponse]( + blockMetadata: connect.NewClient[v12.BlockMetadataRequest, v12.BlockMetadataResponse]( httpClient, baseURL+IngesterServiceBlockMetadataProcedure, - connect.WithSchema(ingesterServiceBlockMetadataMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("BlockMetadata")), connect.WithClientOptions(opts...), ), - getProfileStats: connect.NewClient[v12.GetProfileStatsRequest, v12.GetProfileStatsResponse]( + getProfileStats: connect.NewClient[v11.GetProfileStatsRequest, v11.GetProfileStatsResponse]( httpClient, baseURL+IngesterServiceGetProfileStatsProcedure, - connect.WithSchema(ingesterServiceGetProfileStatsMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("GetProfileStats")), connect.WithClientOptions(opts...), ), - getBlockStats: connect.NewClient[v1.GetBlockStatsRequest, v1.GetBlockStatsResponse]( + getBlockStats: connect.NewClient[v12.GetBlockStatsRequest, v12.GetBlockStatsResponse]( httpClient, baseURL+IngesterServiceGetBlockStatsProcedure, - connect.WithSchema(ingesterServiceGetBlockStatsMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("GetBlockStats")), connect.WithClientOptions(opts...), ), } @@ -204,104 +187,104 @@ func NewIngesterServiceClient(httpClient connect.HTTPClient, baseURL string, opt // ingesterServiceClient implements IngesterServiceClient. type ingesterServiceClient struct { - push *connect.Client[v11.PushRequest, v11.PushResponse] - labelValues *connect.Client[v12.LabelValuesRequest, v12.LabelValuesResponse] - labelNames *connect.Client[v12.LabelNamesRequest, v12.LabelNamesResponse] - profileTypes *connect.Client[v1.ProfileTypesRequest, v1.ProfileTypesResponse] - series *connect.Client[v1.SeriesRequest, v1.SeriesResponse] - flush *connect.Client[v1.FlushRequest, v1.FlushResponse] - mergeProfilesStacktraces *connect.Client[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse] - mergeProfilesLabels *connect.Client[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse] - mergeProfilesPprof *connect.Client[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse] - mergeSpanProfile *connect.Client[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse] - blockMetadata *connect.Client[v1.BlockMetadataRequest, v1.BlockMetadataResponse] - getProfileStats *connect.Client[v12.GetProfileStatsRequest, v12.GetProfileStatsResponse] - getBlockStats *connect.Client[v1.GetBlockStatsRequest, v1.GetBlockStatsResponse] + push *connect.Client[v1.PushRequest, v1.PushResponse] + labelValues *connect.Client[v11.LabelValuesRequest, v11.LabelValuesResponse] + labelNames *connect.Client[v11.LabelNamesRequest, v11.LabelNamesResponse] + profileTypes *connect.Client[v12.ProfileTypesRequest, v12.ProfileTypesResponse] + series *connect.Client[v12.SeriesRequest, v12.SeriesResponse] + flush *connect.Client[v12.FlushRequest, v12.FlushResponse] + mergeProfilesStacktraces *connect.Client[v12.MergeProfilesStacktracesRequest, v12.MergeProfilesStacktracesResponse] + mergeProfilesLabels *connect.Client[v12.MergeProfilesLabelsRequest, v12.MergeProfilesLabelsResponse] + mergeProfilesPprof *connect.Client[v12.MergeProfilesPprofRequest, v12.MergeProfilesPprofResponse] + mergeSpanProfile *connect.Client[v12.MergeSpanProfileRequest, v12.MergeSpanProfileResponse] + blockMetadata *connect.Client[v12.BlockMetadataRequest, v12.BlockMetadataResponse] + getProfileStats *connect.Client[v11.GetProfileStatsRequest, v11.GetProfileStatsResponse] + getBlockStats *connect.Client[v12.GetBlockStatsRequest, v12.GetBlockStatsResponse] } // Push calls ingester.v1.IngesterService.Push. -func (c *ingesterServiceClient) Push(ctx context.Context, req *connect.Request[v11.PushRequest]) (*connect.Response[v11.PushResponse], error) { +func (c *ingesterServiceClient) Push(ctx context.Context, req *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) { return c.push.CallUnary(ctx, req) } // LabelValues calls ingester.v1.IngesterService.LabelValues. -func (c *ingesterServiceClient) LabelValues(ctx context.Context, req *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) { +func (c *ingesterServiceClient) LabelValues(ctx context.Context, req *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) { return c.labelValues.CallUnary(ctx, req) } // LabelNames calls ingester.v1.IngesterService.LabelNames. -func (c *ingesterServiceClient) LabelNames(ctx context.Context, req *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) { +func (c *ingesterServiceClient) LabelNames(ctx context.Context, req *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) { return c.labelNames.CallUnary(ctx, req) } // ProfileTypes calls ingester.v1.IngesterService.ProfileTypes. -func (c *ingesterServiceClient) ProfileTypes(ctx context.Context, req *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) { +func (c *ingesterServiceClient) ProfileTypes(ctx context.Context, req *connect.Request[v12.ProfileTypesRequest]) (*connect.Response[v12.ProfileTypesResponse], error) { return c.profileTypes.CallUnary(ctx, req) } // Series calls ingester.v1.IngesterService.Series. -func (c *ingesterServiceClient) Series(ctx context.Context, req *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) { +func (c *ingesterServiceClient) Series(ctx context.Context, req *connect.Request[v12.SeriesRequest]) (*connect.Response[v12.SeriesResponse], error) { return c.series.CallUnary(ctx, req) } // Flush calls ingester.v1.IngesterService.Flush. -func (c *ingesterServiceClient) Flush(ctx context.Context, req *connect.Request[v1.FlushRequest]) (*connect.Response[v1.FlushResponse], error) { +func (c *ingesterServiceClient) Flush(ctx context.Context, req *connect.Request[v12.FlushRequest]) (*connect.Response[v12.FlushResponse], error) { return c.flush.CallUnary(ctx, req) } // MergeProfilesStacktraces calls ingester.v1.IngesterService.MergeProfilesStacktraces. -func (c *ingesterServiceClient) MergeProfilesStacktraces(ctx context.Context) *connect.BidiStreamForClient[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse] { +func (c *ingesterServiceClient) MergeProfilesStacktraces(ctx context.Context) *connect.BidiStreamForClient[v12.MergeProfilesStacktracesRequest, v12.MergeProfilesStacktracesResponse] { return c.mergeProfilesStacktraces.CallBidiStream(ctx) } // MergeProfilesLabels calls ingester.v1.IngesterService.MergeProfilesLabels. -func (c *ingesterServiceClient) MergeProfilesLabels(ctx context.Context) *connect.BidiStreamForClient[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse] { +func (c *ingesterServiceClient) MergeProfilesLabels(ctx context.Context) *connect.BidiStreamForClient[v12.MergeProfilesLabelsRequest, v12.MergeProfilesLabelsResponse] { return c.mergeProfilesLabels.CallBidiStream(ctx) } // MergeProfilesPprof calls ingester.v1.IngesterService.MergeProfilesPprof. -func (c *ingesterServiceClient) MergeProfilesPprof(ctx context.Context) *connect.BidiStreamForClient[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse] { +func (c *ingesterServiceClient) MergeProfilesPprof(ctx context.Context) *connect.BidiStreamForClient[v12.MergeProfilesPprofRequest, v12.MergeProfilesPprofResponse] { return c.mergeProfilesPprof.CallBidiStream(ctx) } // MergeSpanProfile calls ingester.v1.IngesterService.MergeSpanProfile. -func (c *ingesterServiceClient) MergeSpanProfile(ctx context.Context) *connect.BidiStreamForClient[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse] { +func (c *ingesterServiceClient) MergeSpanProfile(ctx context.Context) *connect.BidiStreamForClient[v12.MergeSpanProfileRequest, v12.MergeSpanProfileResponse] { return c.mergeSpanProfile.CallBidiStream(ctx) } // BlockMetadata calls ingester.v1.IngesterService.BlockMetadata. -func (c *ingesterServiceClient) BlockMetadata(ctx context.Context, req *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) { +func (c *ingesterServiceClient) BlockMetadata(ctx context.Context, req *connect.Request[v12.BlockMetadataRequest]) (*connect.Response[v12.BlockMetadataResponse], error) { return c.blockMetadata.CallUnary(ctx, req) } // GetProfileStats calls ingester.v1.IngesterService.GetProfileStats. -func (c *ingesterServiceClient) GetProfileStats(ctx context.Context, req *connect.Request[v12.GetProfileStatsRequest]) (*connect.Response[v12.GetProfileStatsResponse], error) { +func (c *ingesterServiceClient) GetProfileStats(ctx context.Context, req *connect.Request[v11.GetProfileStatsRequest]) (*connect.Response[v11.GetProfileStatsResponse], error) { return c.getProfileStats.CallUnary(ctx, req) } // GetBlockStats calls ingester.v1.IngesterService.GetBlockStats. -func (c *ingesterServiceClient) GetBlockStats(ctx context.Context, req *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) { +func (c *ingesterServiceClient) GetBlockStats(ctx context.Context, req *connect.Request[v12.GetBlockStatsRequest]) (*connect.Response[v12.GetBlockStatsResponse], error) { return c.getBlockStats.CallUnary(ctx, req) } // IngesterServiceHandler is an implementation of the ingester.v1.IngesterService service. type IngesterServiceHandler interface { - Push(context.Context, *connect.Request[v11.PushRequest]) (*connect.Response[v11.PushResponse], error) - LabelValues(context.Context, *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) - LabelNames(context.Context, *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) + Push(context.Context, *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) + LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) + LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) // Deprecated: ProfileType call is deprecated in the store components // TODO: Remove this call in release v1.4 - ProfileTypes(context.Context, *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) - Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) - Flush(context.Context, *connect.Request[v1.FlushRequest]) (*connect.Response[v1.FlushResponse], error) - MergeProfilesStacktraces(context.Context, *connect.BidiStream[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse]) error - MergeProfilesLabels(context.Context, *connect.BidiStream[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse]) error - MergeProfilesPprof(context.Context, *connect.BidiStream[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse]) error - MergeSpanProfile(context.Context, *connect.BidiStream[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse]) error - BlockMetadata(context.Context, *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) + ProfileTypes(context.Context, *connect.Request[v12.ProfileTypesRequest]) (*connect.Response[v12.ProfileTypesResponse], error) + Series(context.Context, *connect.Request[v12.SeriesRequest]) (*connect.Response[v12.SeriesResponse], error) + Flush(context.Context, *connect.Request[v12.FlushRequest]) (*connect.Response[v12.FlushResponse], error) + MergeProfilesStacktraces(context.Context, *connect.BidiStream[v12.MergeProfilesStacktracesRequest, v12.MergeProfilesStacktracesResponse]) error + MergeProfilesLabels(context.Context, *connect.BidiStream[v12.MergeProfilesLabelsRequest, v12.MergeProfilesLabelsResponse]) error + MergeProfilesPprof(context.Context, *connect.BidiStream[v12.MergeProfilesPprofRequest, v12.MergeProfilesPprofResponse]) error + MergeSpanProfile(context.Context, *connect.BidiStream[v12.MergeSpanProfileRequest, v12.MergeSpanProfileResponse]) error + BlockMetadata(context.Context, *connect.Request[v12.BlockMetadataRequest]) (*connect.Response[v12.BlockMetadataResponse], error) // GetProfileStats returns profile stats for the current tenant. - GetProfileStats(context.Context, *connect.Request[v12.GetProfileStatsRequest]) (*connect.Response[v12.GetProfileStatsResponse], error) - GetBlockStats(context.Context, *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) + GetProfileStats(context.Context, *connect.Request[v11.GetProfileStatsRequest]) (*connect.Response[v11.GetProfileStatsResponse], error) + GetBlockStats(context.Context, *connect.Request[v12.GetBlockStatsRequest]) (*connect.Response[v12.GetBlockStatsResponse], error) } // NewIngesterServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -310,82 +293,83 @@ type IngesterServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewIngesterServiceHandler(svc IngesterServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + ingesterServiceMethods := v12.File_ingester_v1_ingester_proto.Services().ByName("IngesterService").Methods() ingesterServicePushHandler := connect.NewUnaryHandler( IngesterServicePushProcedure, svc.Push, - connect.WithSchema(ingesterServicePushMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("Push")), connect.WithHandlerOptions(opts...), ) ingesterServiceLabelValuesHandler := connect.NewUnaryHandler( IngesterServiceLabelValuesProcedure, svc.LabelValues, - connect.WithSchema(ingesterServiceLabelValuesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("LabelValues")), connect.WithHandlerOptions(opts...), ) ingesterServiceLabelNamesHandler := connect.NewUnaryHandler( IngesterServiceLabelNamesProcedure, svc.LabelNames, - connect.WithSchema(ingesterServiceLabelNamesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("LabelNames")), connect.WithHandlerOptions(opts...), ) ingesterServiceProfileTypesHandler := connect.NewUnaryHandler( IngesterServiceProfileTypesProcedure, svc.ProfileTypes, - connect.WithSchema(ingesterServiceProfileTypesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("ProfileTypes")), connect.WithHandlerOptions(opts...), ) ingesterServiceSeriesHandler := connect.NewUnaryHandler( IngesterServiceSeriesProcedure, svc.Series, - connect.WithSchema(ingesterServiceSeriesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("Series")), connect.WithHandlerOptions(opts...), ) ingesterServiceFlushHandler := connect.NewUnaryHandler( IngesterServiceFlushProcedure, svc.Flush, - connect.WithSchema(ingesterServiceFlushMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("Flush")), connect.WithHandlerOptions(opts...), ) ingesterServiceMergeProfilesStacktracesHandler := connect.NewBidiStreamHandler( IngesterServiceMergeProfilesStacktracesProcedure, svc.MergeProfilesStacktraces, - connect.WithSchema(ingesterServiceMergeProfilesStacktracesMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeProfilesStacktraces")), connect.WithHandlerOptions(opts...), ) ingesterServiceMergeProfilesLabelsHandler := connect.NewBidiStreamHandler( IngesterServiceMergeProfilesLabelsProcedure, svc.MergeProfilesLabels, - connect.WithSchema(ingesterServiceMergeProfilesLabelsMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeProfilesLabels")), connect.WithHandlerOptions(opts...), ) ingesterServiceMergeProfilesPprofHandler := connect.NewBidiStreamHandler( IngesterServiceMergeProfilesPprofProcedure, svc.MergeProfilesPprof, - connect.WithSchema(ingesterServiceMergeProfilesPprofMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeProfilesPprof")), connect.WithHandlerOptions(opts...), ) ingesterServiceMergeSpanProfileHandler := connect.NewBidiStreamHandler( IngesterServiceMergeSpanProfileProcedure, svc.MergeSpanProfile, - connect.WithSchema(ingesterServiceMergeSpanProfileMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("MergeSpanProfile")), connect.WithHandlerOptions(opts...), ) ingesterServiceBlockMetadataHandler := connect.NewUnaryHandler( IngesterServiceBlockMetadataProcedure, svc.BlockMetadata, - connect.WithSchema(ingesterServiceBlockMetadataMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("BlockMetadata")), connect.WithHandlerOptions(opts...), ) ingesterServiceGetProfileStatsHandler := connect.NewUnaryHandler( IngesterServiceGetProfileStatsProcedure, svc.GetProfileStats, - connect.WithSchema(ingesterServiceGetProfileStatsMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("GetProfileStats")), connect.WithHandlerOptions(opts...), ) ingesterServiceGetBlockStatsHandler := connect.NewUnaryHandler( IngesterServiceGetBlockStatsProcedure, svc.GetBlockStats, - connect.WithSchema(ingesterServiceGetBlockStatsMethodDescriptor), + connect.WithSchema(ingesterServiceMethods.ByName("GetBlockStats")), connect.WithHandlerOptions(opts...), ) return "/ingester.v1.IngesterService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -425,54 +409,54 @@ func NewIngesterServiceHandler(svc IngesterServiceHandler, opts ...connect.Handl // UnimplementedIngesterServiceHandler returns CodeUnimplemented from all methods. type UnimplementedIngesterServiceHandler struct{} -func (UnimplementedIngesterServiceHandler) Push(context.Context, *connect.Request[v11.PushRequest]) (*connect.Response[v11.PushResponse], error) { +func (UnimplementedIngesterServiceHandler) Push(context.Context, *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.Push is not implemented")) } -func (UnimplementedIngesterServiceHandler) LabelValues(context.Context, *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) { +func (UnimplementedIngesterServiceHandler) LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.LabelValues is not implemented")) } -func (UnimplementedIngesterServiceHandler) LabelNames(context.Context, *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) { +func (UnimplementedIngesterServiceHandler) LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.LabelNames is not implemented")) } -func (UnimplementedIngesterServiceHandler) ProfileTypes(context.Context, *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) { +func (UnimplementedIngesterServiceHandler) ProfileTypes(context.Context, *connect.Request[v12.ProfileTypesRequest]) (*connect.Response[v12.ProfileTypesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.ProfileTypes is not implemented")) } -func (UnimplementedIngesterServiceHandler) Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) { +func (UnimplementedIngesterServiceHandler) Series(context.Context, *connect.Request[v12.SeriesRequest]) (*connect.Response[v12.SeriesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.Series is not implemented")) } -func (UnimplementedIngesterServiceHandler) Flush(context.Context, *connect.Request[v1.FlushRequest]) (*connect.Response[v1.FlushResponse], error) { +func (UnimplementedIngesterServiceHandler) Flush(context.Context, *connect.Request[v12.FlushRequest]) (*connect.Response[v12.FlushResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.Flush is not implemented")) } -func (UnimplementedIngesterServiceHandler) MergeProfilesStacktraces(context.Context, *connect.BidiStream[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse]) error { +func (UnimplementedIngesterServiceHandler) MergeProfilesStacktraces(context.Context, *connect.BidiStream[v12.MergeProfilesStacktracesRequest, v12.MergeProfilesStacktracesResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.MergeProfilesStacktraces is not implemented")) } -func (UnimplementedIngesterServiceHandler) MergeProfilesLabels(context.Context, *connect.BidiStream[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse]) error { +func (UnimplementedIngesterServiceHandler) MergeProfilesLabels(context.Context, *connect.BidiStream[v12.MergeProfilesLabelsRequest, v12.MergeProfilesLabelsResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.MergeProfilesLabels is not implemented")) } -func (UnimplementedIngesterServiceHandler) MergeProfilesPprof(context.Context, *connect.BidiStream[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse]) error { +func (UnimplementedIngesterServiceHandler) MergeProfilesPprof(context.Context, *connect.BidiStream[v12.MergeProfilesPprofRequest, v12.MergeProfilesPprofResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.MergeProfilesPprof is not implemented")) } -func (UnimplementedIngesterServiceHandler) MergeSpanProfile(context.Context, *connect.BidiStream[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse]) error { +func (UnimplementedIngesterServiceHandler) MergeSpanProfile(context.Context, *connect.BidiStream[v12.MergeSpanProfileRequest, v12.MergeSpanProfileResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.MergeSpanProfile is not implemented")) } -func (UnimplementedIngesterServiceHandler) BlockMetadata(context.Context, *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) { +func (UnimplementedIngesterServiceHandler) BlockMetadata(context.Context, *connect.Request[v12.BlockMetadataRequest]) (*connect.Response[v12.BlockMetadataResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.BlockMetadata is not implemented")) } -func (UnimplementedIngesterServiceHandler) GetProfileStats(context.Context, *connect.Request[v12.GetProfileStatsRequest]) (*connect.Response[v12.GetProfileStatsResponse], error) { +func (UnimplementedIngesterServiceHandler) GetProfileStats(context.Context, *connect.Request[v11.GetProfileStatsRequest]) (*connect.Response[v11.GetProfileStatsResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.GetProfileStats is not implemented")) } -func (UnimplementedIngesterServiceHandler) GetBlockStats(context.Context, *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) { +func (UnimplementedIngesterServiceHandler) GetBlockStats(context.Context, *connect.Request[v12.GetBlockStatsRequest]) (*connect.Response[v12.GetBlockStatsResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ingester.v1.IngesterService.GetBlockStats is not implemented")) } diff --git a/api/gen/proto/go/metastore/v1/compactor.pb.go b/api/gen/proto/go/metastore/v1/compactor.pb.go new file mode 100644 index 0000000000..0aa0c83294 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/compactor.pb.go @@ -0,0 +1,778 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: metastore/v1/compactor.proto + +package metastorev1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CompactionJobStatus int32 + +const ( + CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED CompactionJobStatus = 0 + CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS CompactionJobStatus = 1 + CompactionJobStatus_COMPACTION_STATUS_SUCCESS CompactionJobStatus = 2 +) + +// Enum value maps for CompactionJobStatus. +var ( + CompactionJobStatus_name = map[int32]string{ + 0: "COMPACTION_STATUS_UNSPECIFIED", + 1: "COMPACTION_STATUS_IN_PROGRESS", + 2: "COMPACTION_STATUS_SUCCESS", + } + CompactionJobStatus_value = map[string]int32{ + "COMPACTION_STATUS_UNSPECIFIED": 0, + "COMPACTION_STATUS_IN_PROGRESS": 1, + "COMPACTION_STATUS_SUCCESS": 2, + } +) + +func (x CompactionJobStatus) Enum() *CompactionJobStatus { + p := new(CompactionJobStatus) + *p = x + return p +} + +func (x CompactionJobStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CompactionJobStatus) Descriptor() protoreflect.EnumDescriptor { + return file_metastore_v1_compactor_proto_enumTypes[0].Descriptor() +} + +func (CompactionJobStatus) Type() protoreflect.EnumType { + return &file_metastore_v1_compactor_proto_enumTypes[0] +} + +func (x CompactionJobStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CompactionJobStatus.Descriptor instead. +func (CompactionJobStatus) EnumDescriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{0} +} + +type PollCompactionJobsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + StatusUpdates []*CompactionJobStatusUpdate `protobuf:"bytes,1,rep,name=status_updates,json=statusUpdates,proto3" json:"status_updates,omitempty"` + // How many new jobs a worker can be assigned to. + JobCapacity uint32 `protobuf:"varint,2,opt,name=job_capacity,json=jobCapacity,proto3" json:"job_capacity,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PollCompactionJobsRequest) Reset() { + *x = PollCompactionJobsRequest{} + mi := &file_metastore_v1_compactor_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PollCompactionJobsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PollCompactionJobsRequest) ProtoMessage() {} + +func (x *PollCompactionJobsRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PollCompactionJobsRequest.ProtoReflect.Descriptor instead. +func (*PollCompactionJobsRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{0} +} + +func (x *PollCompactionJobsRequest) GetStatusUpdates() []*CompactionJobStatusUpdate { + if x != nil { + return x.StatusUpdates + } + return nil +} + +func (x *PollCompactionJobsRequest) GetJobCapacity() uint32 { + if x != nil { + return x.JobCapacity + } + return 0 +} + +type PollCompactionJobsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + CompactionJobs []*CompactionJob `protobuf:"bytes,1,rep,name=compaction_jobs,json=compactionJobs,proto3" json:"compaction_jobs,omitempty"` + Assignments []*CompactionJobAssignment `protobuf:"bytes,2,rep,name=assignments,proto3" json:"assignments,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PollCompactionJobsResponse) Reset() { + *x = PollCompactionJobsResponse{} + mi := &file_metastore_v1_compactor_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PollCompactionJobsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PollCompactionJobsResponse) ProtoMessage() {} + +func (x *PollCompactionJobsResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PollCompactionJobsResponse.ProtoReflect.Descriptor instead. +func (*PollCompactionJobsResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{1} +} + +func (x *PollCompactionJobsResponse) GetCompactionJobs() []*CompactionJob { + if x != nil { + return x.CompactionJobs + } + return nil +} + +func (x *PollCompactionJobsResponse) GetAssignments() []*CompactionJobAssignment { + if x != nil { + return x.Assignments + } + return nil +} + +type CompactionJob struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Shard uint32 `protobuf:"varint,2,opt,name=shard,proto3" json:"shard,omitempty"` + Tenant string `protobuf:"bytes,3,opt,name=tenant,proto3" json:"tenant,omitempty"` + CompactionLevel uint32 `protobuf:"varint,4,opt,name=compaction_level,json=compactionLevel,proto3" json:"compaction_level,omitempty"` + SourceBlocks []string `protobuf:"bytes,5,rep,name=source_blocks,json=sourceBlocks,proto3" json:"source_blocks,omitempty"` + Tombstones []*Tombstones `protobuf:"bytes,6,rep,name=tombstones,proto3" json:"tombstones,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactionJob) Reset() { + *x = CompactionJob{} + mi := &file_metastore_v1_compactor_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactionJob) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactionJob) ProtoMessage() {} + +func (x *CompactionJob) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactionJob.ProtoReflect.Descriptor instead. +func (*CompactionJob) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{2} +} + +func (x *CompactionJob) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CompactionJob) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *CompactionJob) GetTenant() string { + if x != nil { + return x.Tenant + } + return "" +} + +func (x *CompactionJob) GetCompactionLevel() uint32 { + if x != nil { + return x.CompactionLevel + } + return 0 +} + +func (x *CompactionJob) GetSourceBlocks() []string { + if x != nil { + return x.SourceBlocks + } + return nil +} + +func (x *CompactionJob) GetTombstones() []*Tombstones { + if x != nil { + return x.Tombstones + } + return nil +} + +// Tombstones represent objects removed from the index but still stored. +type Tombstones struct { + state protoimpl.MessageState `protogen:"open.v1"` + Blocks *BlockTombstones `protobuf:"bytes,1,opt,name=blocks,proto3" json:"blocks,omitempty"` + Shard *ShardTombstone `protobuf:"bytes,2,opt,name=shard,proto3" json:"shard,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Tombstones) Reset() { + *x = Tombstones{} + mi := &file_metastore_v1_compactor_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Tombstones) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Tombstones) ProtoMessage() {} + +func (x *Tombstones) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Tombstones.ProtoReflect.Descriptor instead. +func (*Tombstones) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{3} +} + +func (x *Tombstones) GetBlocks() *BlockTombstones { + if x != nil { + return x.Blocks + } + return nil +} + +func (x *Tombstones) GetShard() *ShardTombstone { + if x != nil { + return x.Shard + } + return nil +} + +type BlockTombstones struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Shard uint32 `protobuf:"varint,2,opt,name=shard,proto3" json:"shard,omitempty"` + Tenant string `protobuf:"bytes,3,opt,name=tenant,proto3" json:"tenant,omitempty"` + CompactionLevel uint32 `protobuf:"varint,4,opt,name=compaction_level,json=compactionLevel,proto3" json:"compaction_level,omitempty"` + Blocks []string `protobuf:"bytes,5,rep,name=blocks,proto3" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BlockTombstones) Reset() { + *x = BlockTombstones{} + mi := &file_metastore_v1_compactor_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BlockTombstones) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockTombstones) ProtoMessage() {} + +func (x *BlockTombstones) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockTombstones.ProtoReflect.Descriptor instead. +func (*BlockTombstones) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{4} +} + +func (x *BlockTombstones) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *BlockTombstones) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *BlockTombstones) GetTenant() string { + if x != nil { + return x.Tenant + } + return "" +} + +func (x *BlockTombstones) GetCompactionLevel() uint32 { + if x != nil { + return x.CompactionLevel + } + return 0 +} + +func (x *BlockTombstones) GetBlocks() []string { + if x != nil { + return x.Blocks + } + return nil +} + +type ShardTombstone struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Lower time boundary. Unix epoch in nanoseconds. + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Duration int64 `protobuf:"varint,3,opt,name=duration,proto3" json:"duration,omitempty"` + Shard uint32 `protobuf:"varint,4,opt,name=shard,proto3" json:"shard,omitempty"` + Tenant string `protobuf:"bytes,5,opt,name=tenant,proto3" json:"tenant,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ShardTombstone) Reset() { + *x = ShardTombstone{} + mi := &file_metastore_v1_compactor_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ShardTombstone) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShardTombstone) ProtoMessage() {} + +func (x *ShardTombstone) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShardTombstone.ProtoReflect.Descriptor instead. +func (*ShardTombstone) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{5} +} + +func (x *ShardTombstone) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ShardTombstone) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *ShardTombstone) GetDuration() int64 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *ShardTombstone) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *ShardTombstone) GetTenant() string { + if x != nil { + return x.Tenant + } + return "" +} + +type CompactionJobAssignment struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Token uint64 `protobuf:"varint,2,opt,name=token,proto3" json:"token,omitempty"` + LeaseExpiresAt int64 `protobuf:"varint,3,opt,name=lease_expires_at,json=leaseExpiresAt,proto3" json:"lease_expires_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactionJobAssignment) Reset() { + *x = CompactionJobAssignment{} + mi := &file_metastore_v1_compactor_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactionJobAssignment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactionJobAssignment) ProtoMessage() {} + +func (x *CompactionJobAssignment) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactionJobAssignment.ProtoReflect.Descriptor instead. +func (*CompactionJobAssignment) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{6} +} + +func (x *CompactionJobAssignment) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CompactionJobAssignment) GetToken() uint64 { + if x != nil { + return x.Token + } + return 0 +} + +func (x *CompactionJobAssignment) GetLeaseExpiresAt() int64 { + if x != nil { + return x.LeaseExpiresAt + } + return 0 +} + +type CompactionJobStatusUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Token uint64 `protobuf:"varint,2,opt,name=token,proto3" json:"token,omitempty"` + Status CompactionJobStatus `protobuf:"varint,3,opt,name=status,proto3,enum=metastore.v1.CompactionJobStatus" json:"status,omitempty"` + // Only present if the job completed successfully. + CompactedBlocks *CompactedBlocks `protobuf:"bytes,4,opt,name=compacted_blocks,json=compactedBlocks,proto3" json:"compacted_blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactionJobStatusUpdate) Reset() { + *x = CompactionJobStatusUpdate{} + mi := &file_metastore_v1_compactor_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactionJobStatusUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactionJobStatusUpdate) ProtoMessage() {} + +func (x *CompactionJobStatusUpdate) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactionJobStatusUpdate.ProtoReflect.Descriptor instead. +func (*CompactionJobStatusUpdate) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{7} +} + +func (x *CompactionJobStatusUpdate) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CompactionJobStatusUpdate) GetToken() uint64 { + if x != nil { + return x.Token + } + return 0 +} + +func (x *CompactionJobStatusUpdate) GetStatus() CompactionJobStatus { + if x != nil { + return x.Status + } + return CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED +} + +func (x *CompactionJobStatusUpdate) GetCompactedBlocks() *CompactedBlocks { + if x != nil { + return x.CompactedBlocks + } + return nil +} + +type CompactedBlocks struct { + state protoimpl.MessageState `protogen:"open.v1"` + SourceBlocks *BlockList `protobuf:"bytes,1,opt,name=source_blocks,json=sourceBlocks,proto3" json:"source_blocks,omitempty"` + NewBlocks []*BlockMeta `protobuf:"bytes,2,rep,name=new_blocks,json=newBlocks,proto3" json:"new_blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactedBlocks) Reset() { + *x = CompactedBlocks{} + mi := &file_metastore_v1_compactor_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactedBlocks) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactedBlocks) ProtoMessage() {} + +func (x *CompactedBlocks) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_compactor_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactedBlocks.ProtoReflect.Descriptor instead. +func (*CompactedBlocks) Descriptor() ([]byte, []int) { + return file_metastore_v1_compactor_proto_rawDescGZIP(), []int{8} +} + +func (x *CompactedBlocks) GetSourceBlocks() *BlockList { + if x != nil { + return x.SourceBlocks + } + return nil +} + +func (x *CompactedBlocks) GetNewBlocks() []*BlockMeta { + if x != nil { + return x.NewBlocks + } + return nil +} + +var File_metastore_v1_compactor_proto protoreflect.FileDescriptor + +const file_metastore_v1_compactor_proto_rawDesc = "" + + "\n" + + "\x1cmetastore/v1/compactor.proto\x12\fmetastore.v1\x1a\x18metastore/v1/types.proto\"\x8e\x01\n" + + "\x19PollCompactionJobsRequest\x12N\n" + + "\x0estatus_updates\x18\x01 \x03(\v2'.metastore.v1.CompactionJobStatusUpdateR\rstatusUpdates\x12!\n" + + "\fjob_capacity\x18\x02 \x01(\rR\vjobCapacity\"\xab\x01\n" + + "\x1aPollCompactionJobsResponse\x12D\n" + + "\x0fcompaction_jobs\x18\x01 \x03(\v2\x1b.metastore.v1.CompactionJobR\x0ecompactionJobs\x12G\n" + + "\vassignments\x18\x02 \x03(\v2%.metastore.v1.CompactionJobAssignmentR\vassignments\"\xdb\x01\n" + + "\rCompactionJob\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05shard\x18\x02 \x01(\rR\x05shard\x12\x16\n" + + "\x06tenant\x18\x03 \x01(\tR\x06tenant\x12)\n" + + "\x10compaction_level\x18\x04 \x01(\rR\x0fcompactionLevel\x12#\n" + + "\rsource_blocks\x18\x05 \x03(\tR\fsourceBlocks\x128\n" + + "\n" + + "tombstones\x18\x06 \x03(\v2\x18.metastore.v1.TombstonesR\n" + + "tombstones\"w\n" + + "\n" + + "Tombstones\x125\n" + + "\x06blocks\x18\x01 \x01(\v2\x1d.metastore.v1.BlockTombstonesR\x06blocks\x122\n" + + "\x05shard\x18\x02 \x01(\v2\x1c.metastore.v1.ShardTombstoneR\x05shard\"\x96\x01\n" + + "\x0fBlockTombstones\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05shard\x18\x02 \x01(\rR\x05shard\x12\x16\n" + + "\x06tenant\x18\x03 \x01(\tR\x06tenant\x12)\n" + + "\x10compaction_level\x18\x04 \x01(\rR\x0fcompactionLevel\x12\x16\n" + + "\x06blocks\x18\x05 \x03(\tR\x06blocks\"\x8c\x01\n" + + "\x0eShardTombstone\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\x12\x1a\n" + + "\bduration\x18\x03 \x01(\x03R\bduration\x12\x14\n" + + "\x05shard\x18\x04 \x01(\rR\x05shard\x12\x16\n" + + "\x06tenant\x18\x05 \x01(\tR\x06tenant\"m\n" + + "\x17CompactionJobAssignment\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05token\x18\x02 \x01(\x04R\x05token\x12(\n" + + "\x10lease_expires_at\x18\x03 \x01(\x03R\x0eleaseExpiresAt\"\xca\x01\n" + + "\x19CompactionJobStatusUpdate\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05token\x18\x02 \x01(\x04R\x05token\x129\n" + + "\x06status\x18\x03 \x01(\x0e2!.metastore.v1.CompactionJobStatusR\x06status\x12H\n" + + "\x10compacted_blocks\x18\x04 \x01(\v2\x1d.metastore.v1.CompactedBlocksR\x0fcompactedBlocks\"\x87\x01\n" + + "\x0fCompactedBlocks\x12<\n" + + "\rsource_blocks\x18\x01 \x01(\v2\x17.metastore.v1.BlockListR\fsourceBlocks\x126\n" + + "\n" + + "new_blocks\x18\x02 \x03(\v2\x17.metastore.v1.BlockMetaR\tnewBlocks*z\n" + + "\x13CompactionJobStatus\x12!\n" + + "\x1dCOMPACTION_STATUS_UNSPECIFIED\x10\x00\x12!\n" + + "\x1dCOMPACTION_STATUS_IN_PROGRESS\x10\x01\x12\x1d\n" + + "\x19COMPACTION_STATUS_SUCCESS\x10\x022~\n" + + "\x11CompactionService\x12i\n" + + "\x12PollCompactionJobs\x12'.metastore.v1.PollCompactionJobsRequest\x1a(.metastore.v1.PollCompactionJobsResponse\"\x00B\xbb\x01\n" + + "\x10com.metastore.v1B\x0eCompactorProtoP\x01ZFgithub.com/grafana/pyroscope/api/gen/proto/go/metastore/v1;metastorev1\xa2\x02\x03MXX\xaa\x02\fMetastore.V1\xca\x02\fMetastore\\V1\xe2\x02\x18Metastore\\V1\\GPBMetadata\xea\x02\rMetastore::V1b\x06proto3" + +var ( + file_metastore_v1_compactor_proto_rawDescOnce sync.Once + file_metastore_v1_compactor_proto_rawDescData []byte +) + +func file_metastore_v1_compactor_proto_rawDescGZIP() []byte { + file_metastore_v1_compactor_proto_rawDescOnce.Do(func() { + file_metastore_v1_compactor_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_metastore_v1_compactor_proto_rawDesc), len(file_metastore_v1_compactor_proto_rawDesc))) + }) + return file_metastore_v1_compactor_proto_rawDescData +} + +var file_metastore_v1_compactor_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_metastore_v1_compactor_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_metastore_v1_compactor_proto_goTypes = []any{ + (CompactionJobStatus)(0), // 0: metastore.v1.CompactionJobStatus + (*PollCompactionJobsRequest)(nil), // 1: metastore.v1.PollCompactionJobsRequest + (*PollCompactionJobsResponse)(nil), // 2: metastore.v1.PollCompactionJobsResponse + (*CompactionJob)(nil), // 3: metastore.v1.CompactionJob + (*Tombstones)(nil), // 4: metastore.v1.Tombstones + (*BlockTombstones)(nil), // 5: metastore.v1.BlockTombstones + (*ShardTombstone)(nil), // 6: metastore.v1.ShardTombstone + (*CompactionJobAssignment)(nil), // 7: metastore.v1.CompactionJobAssignment + (*CompactionJobStatusUpdate)(nil), // 8: metastore.v1.CompactionJobStatusUpdate + (*CompactedBlocks)(nil), // 9: metastore.v1.CompactedBlocks + (*BlockList)(nil), // 10: metastore.v1.BlockList + (*BlockMeta)(nil), // 11: metastore.v1.BlockMeta +} +var file_metastore_v1_compactor_proto_depIdxs = []int32{ + 8, // 0: metastore.v1.PollCompactionJobsRequest.status_updates:type_name -> metastore.v1.CompactionJobStatusUpdate + 3, // 1: metastore.v1.PollCompactionJobsResponse.compaction_jobs:type_name -> metastore.v1.CompactionJob + 7, // 2: metastore.v1.PollCompactionJobsResponse.assignments:type_name -> metastore.v1.CompactionJobAssignment + 4, // 3: metastore.v1.CompactionJob.tombstones:type_name -> metastore.v1.Tombstones + 5, // 4: metastore.v1.Tombstones.blocks:type_name -> metastore.v1.BlockTombstones + 6, // 5: metastore.v1.Tombstones.shard:type_name -> metastore.v1.ShardTombstone + 0, // 6: metastore.v1.CompactionJobStatusUpdate.status:type_name -> metastore.v1.CompactionJobStatus + 9, // 7: metastore.v1.CompactionJobStatusUpdate.compacted_blocks:type_name -> metastore.v1.CompactedBlocks + 10, // 8: metastore.v1.CompactedBlocks.source_blocks:type_name -> metastore.v1.BlockList + 11, // 9: metastore.v1.CompactedBlocks.new_blocks:type_name -> metastore.v1.BlockMeta + 1, // 10: metastore.v1.CompactionService.PollCompactionJobs:input_type -> metastore.v1.PollCompactionJobsRequest + 2, // 11: metastore.v1.CompactionService.PollCompactionJobs:output_type -> metastore.v1.PollCompactionJobsResponse + 11, // [11:12] is the sub-list for method output_type + 10, // [10:11] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_metastore_v1_compactor_proto_init() } +func file_metastore_v1_compactor_proto_init() { + if File_metastore_v1_compactor_proto != nil { + return + } + file_metastore_v1_types_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_metastore_v1_compactor_proto_rawDesc), len(file_metastore_v1_compactor_proto_rawDesc)), + NumEnums: 1, + NumMessages: 9, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_metastore_v1_compactor_proto_goTypes, + DependencyIndexes: file_metastore_v1_compactor_proto_depIdxs, + EnumInfos: file_metastore_v1_compactor_proto_enumTypes, + MessageInfos: file_metastore_v1_compactor_proto_msgTypes, + }.Build() + File_metastore_v1_compactor_proto = out.File + file_metastore_v1_compactor_proto_goTypes = nil + file_metastore_v1_compactor_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/metastore/v1/compactor_vtproto.pb.go b/api/gen/proto/go/metastore/v1/compactor_vtproto.pb.go new file mode 100644 index 0000000000..f03ecee9b4 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/compactor_vtproto.pb.go @@ -0,0 +1,2719 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: metastore/v1/compactor.proto + +package metastorev1 + +import ( + context "context" + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *PollCompactionJobsRequest) CloneVT() *PollCompactionJobsRequest { + if m == nil { + return (*PollCompactionJobsRequest)(nil) + } + r := new(PollCompactionJobsRequest) + r.JobCapacity = m.JobCapacity + if rhs := m.StatusUpdates; rhs != nil { + tmpContainer := make([]*CompactionJobStatusUpdate, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.StatusUpdates = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *PollCompactionJobsRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *PollCompactionJobsResponse) CloneVT() *PollCompactionJobsResponse { + if m == nil { + return (*PollCompactionJobsResponse)(nil) + } + r := new(PollCompactionJobsResponse) + if rhs := m.CompactionJobs; rhs != nil { + tmpContainer := make([]*CompactionJob, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.CompactionJobs = tmpContainer + } + if rhs := m.Assignments; rhs != nil { + tmpContainer := make([]*CompactionJobAssignment, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Assignments = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *PollCompactionJobsResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactionJob) CloneVT() *CompactionJob { + if m == nil { + return (*CompactionJob)(nil) + } + r := new(CompactionJob) + r.Name = m.Name + r.Shard = m.Shard + r.Tenant = m.Tenant + r.CompactionLevel = m.CompactionLevel + if rhs := m.SourceBlocks; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.SourceBlocks = tmpContainer + } + if rhs := m.Tombstones; rhs != nil { + tmpContainer := make([]*Tombstones, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Tombstones = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactionJob) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Tombstones) CloneVT() *Tombstones { + if m == nil { + return (*Tombstones)(nil) + } + r := new(Tombstones) + r.Blocks = m.Blocks.CloneVT() + r.Shard = m.Shard.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Tombstones) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *BlockTombstones) CloneVT() *BlockTombstones { + if m == nil { + return (*BlockTombstones)(nil) + } + r := new(BlockTombstones) + r.Name = m.Name + r.Shard = m.Shard + r.Tenant = m.Tenant + r.CompactionLevel = m.CompactionLevel + if rhs := m.Blocks; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Blocks = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *BlockTombstones) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ShardTombstone) CloneVT() *ShardTombstone { + if m == nil { + return (*ShardTombstone)(nil) + } + r := new(ShardTombstone) + r.Name = m.Name + r.Timestamp = m.Timestamp + r.Duration = m.Duration + r.Shard = m.Shard + r.Tenant = m.Tenant + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ShardTombstone) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactionJobAssignment) CloneVT() *CompactionJobAssignment { + if m == nil { + return (*CompactionJobAssignment)(nil) + } + r := new(CompactionJobAssignment) + r.Name = m.Name + r.Token = m.Token + r.LeaseExpiresAt = m.LeaseExpiresAt + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactionJobAssignment) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactionJobStatusUpdate) CloneVT() *CompactionJobStatusUpdate { + if m == nil { + return (*CompactionJobStatusUpdate)(nil) + } + r := new(CompactionJobStatusUpdate) + r.Name = m.Name + r.Token = m.Token + r.Status = m.Status + r.CompactedBlocks = m.CompactedBlocks.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactionJobStatusUpdate) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactedBlocks) CloneVT() *CompactedBlocks { + if m == nil { + return (*CompactedBlocks)(nil) + } + r := new(CompactedBlocks) + r.SourceBlocks = m.SourceBlocks.CloneVT() + if rhs := m.NewBlocks; rhs != nil { + tmpContainer := make([]*BlockMeta, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.NewBlocks = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactedBlocks) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *PollCompactionJobsRequest) EqualVT(that *PollCompactionJobsRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.StatusUpdates) != len(that.StatusUpdates) { + return false + } + for i, vx := range this.StatusUpdates { + vy := that.StatusUpdates[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &CompactionJobStatusUpdate{} + } + if q == nil { + q = &CompactionJobStatusUpdate{} + } + if !p.EqualVT(q) { + return false + } + } + } + if this.JobCapacity != that.JobCapacity { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *PollCompactionJobsRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*PollCompactionJobsRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *PollCompactionJobsResponse) EqualVT(that *PollCompactionJobsResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.CompactionJobs) != len(that.CompactionJobs) { + return false + } + for i, vx := range this.CompactionJobs { + vy := that.CompactionJobs[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &CompactionJob{} + } + if q == nil { + q = &CompactionJob{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.Assignments) != len(that.Assignments) { + return false + } + for i, vx := range this.Assignments { + vy := that.Assignments[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &CompactionJobAssignment{} + } + if q == nil { + q = &CompactionJobAssignment{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *PollCompactionJobsResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*PollCompactionJobsResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactionJob) EqualVT(that *CompactionJob) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Shard != that.Shard { + return false + } + if this.Tenant != that.Tenant { + return false + } + if this.CompactionLevel != that.CompactionLevel { + return false + } + if len(this.SourceBlocks) != len(that.SourceBlocks) { + return false + } + for i, vx := range this.SourceBlocks { + vy := that.SourceBlocks[i] + if vx != vy { + return false + } + } + if len(this.Tombstones) != len(that.Tombstones) { + return false + } + for i, vx := range this.Tombstones { + vy := that.Tombstones[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Tombstones{} + } + if q == nil { + q = &Tombstones{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactionJob) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactionJob) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Tombstones) EqualVT(that *Tombstones) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Blocks.EqualVT(that.Blocks) { + return false + } + if !this.Shard.EqualVT(that.Shard) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Tombstones) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Tombstones) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *BlockTombstones) EqualVT(that *BlockTombstones) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Shard != that.Shard { + return false + } + if this.Tenant != that.Tenant { + return false + } + if this.CompactionLevel != that.CompactionLevel { + return false + } + if len(this.Blocks) != len(that.Blocks) { + return false + } + for i, vx := range this.Blocks { + vy := that.Blocks[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *BlockTombstones) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*BlockTombstones) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ShardTombstone) EqualVT(that *ShardTombstone) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Timestamp != that.Timestamp { + return false + } + if this.Duration != that.Duration { + return false + } + if this.Shard != that.Shard { + return false + } + if this.Tenant != that.Tenant { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ShardTombstone) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ShardTombstone) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactionJobAssignment) EqualVT(that *CompactionJobAssignment) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Token != that.Token { + return false + } + if this.LeaseExpiresAt != that.LeaseExpiresAt { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactionJobAssignment) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactionJobAssignment) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactionJobStatusUpdate) EqualVT(that *CompactionJobStatusUpdate) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Token != that.Token { + return false + } + if this.Status != that.Status { + return false + } + if !this.CompactedBlocks.EqualVT(that.CompactedBlocks) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactionJobStatusUpdate) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactionJobStatusUpdate) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactedBlocks) EqualVT(that *CompactedBlocks) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.SourceBlocks.EqualVT(that.SourceBlocks) { + return false + } + if len(this.NewBlocks) != len(that.NewBlocks) { + return false + } + for i, vx := range this.NewBlocks { + vy := that.NewBlocks[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &BlockMeta{} + } + if q == nil { + q = &BlockMeta{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactedBlocks) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactedBlocks) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// CompactionServiceClient is the client API for CompactionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type CompactionServiceClient interface { + // Used to both retrieve jobs and update the jobs status at the same time. + PollCompactionJobs(ctx context.Context, in *PollCompactionJobsRequest, opts ...grpc.CallOption) (*PollCompactionJobsResponse, error) +} + +type compactionServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewCompactionServiceClient(cc grpc.ClientConnInterface) CompactionServiceClient { + return &compactionServiceClient{cc} +} + +func (c *compactionServiceClient) PollCompactionJobs(ctx context.Context, in *PollCompactionJobsRequest, opts ...grpc.CallOption) (*PollCompactionJobsResponse, error) { + out := new(PollCompactionJobsResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.CompactionService/PollCompactionJobs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CompactionServiceServer is the server API for CompactionService service. +// All implementations must embed UnimplementedCompactionServiceServer +// for forward compatibility +type CompactionServiceServer interface { + // Used to both retrieve jobs and update the jobs status at the same time. + PollCompactionJobs(context.Context, *PollCompactionJobsRequest) (*PollCompactionJobsResponse, error) + mustEmbedUnimplementedCompactionServiceServer() +} + +// UnimplementedCompactionServiceServer must be embedded to have forward compatible implementations. +type UnimplementedCompactionServiceServer struct { +} + +func (UnimplementedCompactionServiceServer) PollCompactionJobs(context.Context, *PollCompactionJobsRequest) (*PollCompactionJobsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PollCompactionJobs not implemented") +} +func (UnimplementedCompactionServiceServer) mustEmbedUnimplementedCompactionServiceServer() {} + +// UnsafeCompactionServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CompactionServiceServer will +// result in compilation errors. +type UnsafeCompactionServiceServer interface { + mustEmbedUnimplementedCompactionServiceServer() +} + +func RegisterCompactionServiceServer(s grpc.ServiceRegistrar, srv CompactionServiceServer) { + s.RegisterService(&CompactionService_ServiceDesc, srv) +} + +func _CompactionService_PollCompactionJobs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PollCompactionJobsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CompactionServiceServer).PollCompactionJobs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.CompactionService/PollCompactionJobs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CompactionServiceServer).PollCompactionJobs(ctx, req.(*PollCompactionJobsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// CompactionService_ServiceDesc is the grpc.ServiceDesc for CompactionService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var CompactionService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "metastore.v1.CompactionService", + HandlerType: (*CompactionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "PollCompactionJobs", + Handler: _CompactionService_PollCompactionJobs_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "metastore/v1/compactor.proto", +} + +func (m *PollCompactionJobsRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PollCompactionJobsRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PollCompactionJobsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.JobCapacity != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.JobCapacity)) + i-- + dAtA[i] = 0x10 + } + if len(m.StatusUpdates) > 0 { + for iNdEx := len(m.StatusUpdates) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.StatusUpdates[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *PollCompactionJobsResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PollCompactionJobsResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PollCompactionJobsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Assignments) > 0 { + for iNdEx := len(m.Assignments) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Assignments[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.CompactionJobs) > 0 { + for iNdEx := len(m.CompactionJobs) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.CompactionJobs[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *CompactionJob) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactionJob) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactionJob) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Tombstones) > 0 { + for iNdEx := len(m.Tombstones) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Tombstones[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + } + if len(m.SourceBlocks) > 0 { + for iNdEx := len(m.SourceBlocks) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SourceBlocks[iNdEx]) + copy(dAtA[i:], m.SourceBlocks[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SourceBlocks[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if m.CompactionLevel != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x20 + } + if len(m.Tenant) > 0 { + i -= len(m.Tenant) + copy(dAtA[i:], m.Tenant) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tenant))) + i-- + dAtA[i] = 0x1a + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Tombstones) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Tombstones) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Tombstones) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Shard != nil { + size, err := m.Shard.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.Blocks != nil { + size, err := m.Blocks.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *BlockTombstones) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockTombstones) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *BlockTombstones) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Blocks) > 0 { + for iNdEx := len(m.Blocks) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Blocks[iNdEx]) + copy(dAtA[i:], m.Blocks[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Blocks[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if m.CompactionLevel != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x20 + } + if len(m.Tenant) > 0 { + i -= len(m.Tenant) + copy(dAtA[i:], m.Tenant) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tenant))) + i-- + dAtA[i] = 0x1a + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ShardTombstone) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ShardTombstone) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ShardTombstone) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Tenant) > 0 { + i -= len(m.Tenant) + copy(dAtA[i:], m.Tenant) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tenant))) + i-- + dAtA[i] = 0x2a + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x20 + } + if m.Duration != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Duration)) + i-- + dAtA[i] = 0x18 + } + if m.Timestamp != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompactionJobAssignment) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactionJobAssignment) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactionJobAssignment) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.LeaseExpiresAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.LeaseExpiresAt)) + i-- + dAtA[i] = 0x18 + } + if m.Token != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Token)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompactionJobStatusUpdate) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactionJobStatusUpdate) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactionJobStatusUpdate) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CompactedBlocks != nil { + size, err := m.CompactedBlocks.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + if m.Status != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x18 + } + if m.Token != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Token)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompactedBlocks) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactedBlocks) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactedBlocks) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.NewBlocks) > 0 { + for iNdEx := len(m.NewBlocks) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.NewBlocks[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if m.SourceBlocks != nil { + size, err := m.SourceBlocks.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PollCompactionJobsRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.StatusUpdates) > 0 { + for _, e := range m.StatusUpdates { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.JobCapacity != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.JobCapacity)) + } + n += len(m.unknownFields) + return n +} + +func (m *PollCompactionJobsResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CompactionJobs) > 0 { + for _, e := range m.CompactionJobs { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Assignments) > 0 { + for _, e := range m.Assignments { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *CompactionJob) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + l = len(m.Tenant) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CompactionLevel != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CompactionLevel)) + } + if len(m.SourceBlocks) > 0 { + for _, s := range m.SourceBlocks { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Tombstones) > 0 { + for _, e := range m.Tombstones { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *Tombstones) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Blocks != nil { + l = m.Blocks.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Shard != nil { + l = m.Shard.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *BlockTombstones) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + l = len(m.Tenant) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CompactionLevel != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CompactionLevel)) + } + if len(m.Blocks) > 0 { + for _, s := range m.Blocks { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *ShardTombstone) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Timestamp != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Timestamp)) + } + if m.Duration != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Duration)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + l = len(m.Tenant) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompactionJobAssignment) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Token != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Token)) + } + if m.LeaseExpiresAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.LeaseExpiresAt)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompactionJobStatusUpdate) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Token != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Token)) + } + if m.Status != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Status)) + } + if m.CompactedBlocks != nil { + l = m.CompactedBlocks.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompactedBlocks) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SourceBlocks != nil { + l = m.SourceBlocks.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.NewBlocks) > 0 { + for _, e := range m.NewBlocks { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *PollCompactionJobsRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PollCompactionJobsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PollCompactionJobsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StatusUpdates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StatusUpdates = append(m.StatusUpdates, &CompactionJobStatusUpdate{}) + if err := m.StatusUpdates[len(m.StatusUpdates)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field JobCapacity", wireType) + } + m.JobCapacity = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.JobCapacity |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PollCompactionJobsResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PollCompactionJobsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PollCompactionJobsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionJobs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CompactionJobs = append(m.CompactionJobs, &CompactionJob{}) + if err := m.CompactionJobs[len(m.CompactionJobs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Assignments", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Assignments = append(m.Assignments, &CompactionJobAssignment{}) + if err := m.Assignments[len(m.Assignments)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactionJob) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactionJob: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactionJob: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenant = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourceBlocks", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourceBlocks = append(m.SourceBlocks, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tombstones", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tombstones = append(m.Tombstones, &Tombstones{}) + if err := m.Tombstones[len(m.Tombstones)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Tombstones) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Tombstones: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Tombstones: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Blocks == nil { + m.Blocks = &BlockTombstones{} + } + if err := m.Blocks.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Shard == nil { + m.Shard = &ShardTombstone{} + } + if err := m.Shard.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlockTombstones) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockTombstones: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockTombstones: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenant = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Blocks = append(m.Blocks, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ShardTombstone) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ShardTombstone: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ShardTombstone: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Duration", wireType) + } + m.Duration = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Duration |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenant = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactionJobAssignment) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactionJobAssignment: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactionJobAssignment: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + m.Token = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Token |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LeaseExpiresAt", wireType) + } + m.LeaseExpiresAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LeaseExpiresAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactionJobStatusUpdate) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactionJobStatusUpdate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactionJobStatusUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + m.Token = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Token |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= CompactionJobStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactedBlocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CompactedBlocks == nil { + m.CompactedBlocks = &CompactedBlocks{} + } + if err := m.CompactedBlocks.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactedBlocks) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactedBlocks: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactedBlocks: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourceBlocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SourceBlocks == nil { + m.SourceBlocks = &BlockList{} + } + if err := m.SourceBlocks.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewBlocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewBlocks = append(m.NewBlocks, &BlockMeta{}) + if err := m.NewBlocks[len(m.NewBlocks)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/metastore/v1/index.pb.go b/api/gen/proto/go/metastore/v1/index.pb.go new file mode 100644 index 0000000000..254e1a4ad5 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/index.pb.go @@ -0,0 +1,269 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: metastore/v1/index.proto + +package metastorev1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type AddBlockRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Block *BlockMeta `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddBlockRequest) Reset() { + *x = AddBlockRequest{} + mi := &file_metastore_v1_index_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddBlockRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddBlockRequest) ProtoMessage() {} + +func (x *AddBlockRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_index_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddBlockRequest.ProtoReflect.Descriptor instead. +func (*AddBlockRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_index_proto_rawDescGZIP(), []int{0} +} + +func (x *AddBlockRequest) GetBlock() *BlockMeta { + if x != nil { + return x.Block + } + return nil +} + +type AddBlockResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddBlockResponse) Reset() { + *x = AddBlockResponse{} + mi := &file_metastore_v1_index_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddBlockResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddBlockResponse) ProtoMessage() {} + +func (x *AddBlockResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_index_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddBlockResponse.ProtoReflect.Descriptor instead. +func (*AddBlockResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_index_proto_rawDescGZIP(), []int{1} +} + +type GetBlockMetadataRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Blocks *BlockList `protobuf:"bytes,1,opt,name=blocks,proto3" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetBlockMetadataRequest) Reset() { + *x = GetBlockMetadataRequest{} + mi := &file_metastore_v1_index_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetBlockMetadataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockMetadataRequest) ProtoMessage() {} + +func (x *GetBlockMetadataRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_index_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockMetadataRequest.ProtoReflect.Descriptor instead. +func (*GetBlockMetadataRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_index_proto_rawDescGZIP(), []int{2} +} + +func (x *GetBlockMetadataRequest) GetBlocks() *BlockList { + if x != nil { + return x.Blocks + } + return nil +} + +type GetBlockMetadataResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Blocks []*BlockMeta `protobuf:"bytes,1,rep,name=blocks,proto3" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetBlockMetadataResponse) Reset() { + *x = GetBlockMetadataResponse{} + mi := &file_metastore_v1_index_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetBlockMetadataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockMetadataResponse) ProtoMessage() {} + +func (x *GetBlockMetadataResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_index_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockMetadataResponse.ProtoReflect.Descriptor instead. +func (*GetBlockMetadataResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_index_proto_rawDescGZIP(), []int{3} +} + +func (x *GetBlockMetadataResponse) GetBlocks() []*BlockMeta { + if x != nil { + return x.Blocks + } + return nil +} + +var File_metastore_v1_index_proto protoreflect.FileDescriptor + +const file_metastore_v1_index_proto_rawDesc = "" + + "\n" + + "\x18metastore/v1/index.proto\x12\fmetastore.v1\x1a\x18metastore/v1/types.proto\"@\n" + + "\x0fAddBlockRequest\x12-\n" + + "\x05block\x18\x01 \x01(\v2\x17.metastore.v1.BlockMetaR\x05block\"\x12\n" + + "\x10AddBlockResponse\"J\n" + + "\x17GetBlockMetadataRequest\x12/\n" + + "\x06blocks\x18\x01 \x01(\v2\x17.metastore.v1.BlockListR\x06blocks\"K\n" + + "\x18GetBlockMetadataResponse\x12/\n" + + "\x06blocks\x18\x01 \x03(\v2\x17.metastore.v1.BlockMetaR\x06blocks2\xc0\x01\n" + + "\fIndexService\x12K\n" + + "\bAddBlock\x12\x1d.metastore.v1.AddBlockRequest\x1a\x1e.metastore.v1.AddBlockResponse\"\x00\x12c\n" + + "\x10GetBlockMetadata\x12%.metastore.v1.GetBlockMetadataRequest\x1a&.metastore.v1.GetBlockMetadataResponse\"\x00B\xb7\x01\n" + + "\x10com.metastore.v1B\n" + + "IndexProtoP\x01ZFgithub.com/grafana/pyroscope/api/gen/proto/go/metastore/v1;metastorev1\xa2\x02\x03MXX\xaa\x02\fMetastore.V1\xca\x02\fMetastore\\V1\xe2\x02\x18Metastore\\V1\\GPBMetadata\xea\x02\rMetastore::V1b\x06proto3" + +var ( + file_metastore_v1_index_proto_rawDescOnce sync.Once + file_metastore_v1_index_proto_rawDescData []byte +) + +func file_metastore_v1_index_proto_rawDescGZIP() []byte { + file_metastore_v1_index_proto_rawDescOnce.Do(func() { + file_metastore_v1_index_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_metastore_v1_index_proto_rawDesc), len(file_metastore_v1_index_proto_rawDesc))) + }) + return file_metastore_v1_index_proto_rawDescData +} + +var file_metastore_v1_index_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_metastore_v1_index_proto_goTypes = []any{ + (*AddBlockRequest)(nil), // 0: metastore.v1.AddBlockRequest + (*AddBlockResponse)(nil), // 1: metastore.v1.AddBlockResponse + (*GetBlockMetadataRequest)(nil), // 2: metastore.v1.GetBlockMetadataRequest + (*GetBlockMetadataResponse)(nil), // 3: metastore.v1.GetBlockMetadataResponse + (*BlockMeta)(nil), // 4: metastore.v1.BlockMeta + (*BlockList)(nil), // 5: metastore.v1.BlockList +} +var file_metastore_v1_index_proto_depIdxs = []int32{ + 4, // 0: metastore.v1.AddBlockRequest.block:type_name -> metastore.v1.BlockMeta + 5, // 1: metastore.v1.GetBlockMetadataRequest.blocks:type_name -> metastore.v1.BlockList + 4, // 2: metastore.v1.GetBlockMetadataResponse.blocks:type_name -> metastore.v1.BlockMeta + 0, // 3: metastore.v1.IndexService.AddBlock:input_type -> metastore.v1.AddBlockRequest + 2, // 4: metastore.v1.IndexService.GetBlockMetadata:input_type -> metastore.v1.GetBlockMetadataRequest + 1, // 5: metastore.v1.IndexService.AddBlock:output_type -> metastore.v1.AddBlockResponse + 3, // 6: metastore.v1.IndexService.GetBlockMetadata:output_type -> metastore.v1.GetBlockMetadataResponse + 5, // [5:7] is the sub-list for method output_type + 3, // [3:5] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_metastore_v1_index_proto_init() } +func file_metastore_v1_index_proto_init() { + if File_metastore_v1_index_proto != nil { + return + } + file_metastore_v1_types_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_metastore_v1_index_proto_rawDesc), len(file_metastore_v1_index_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_metastore_v1_index_proto_goTypes, + DependencyIndexes: file_metastore_v1_index_proto_depIdxs, + MessageInfos: file_metastore_v1_index_proto_msgTypes, + }.Build() + File_metastore_v1_index_proto = out.File + file_metastore_v1_index_proto_goTypes = nil + file_metastore_v1_index_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/metastore/v1/index_vtproto.pb.go b/api/gen/proto/go/metastore/v1/index_vtproto.pb.go new file mode 100644 index 0000000000..bb513b4f13 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/index_vtproto.pb.go @@ -0,0 +1,841 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: metastore/v1/index.proto + +package metastorev1 + +import ( + context "context" + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *AddBlockRequest) CloneVT() *AddBlockRequest { + if m == nil { + return (*AddBlockRequest)(nil) + } + r := new(AddBlockRequest) + r.Block = m.Block.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AddBlockRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *AddBlockResponse) CloneVT() *AddBlockResponse { + if m == nil { + return (*AddBlockResponse)(nil) + } + r := new(AddBlockResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AddBlockResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetBlockMetadataRequest) CloneVT() *GetBlockMetadataRequest { + if m == nil { + return (*GetBlockMetadataRequest)(nil) + } + r := new(GetBlockMetadataRequest) + r.Blocks = m.Blocks.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetBlockMetadataRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetBlockMetadataResponse) CloneVT() *GetBlockMetadataResponse { + if m == nil { + return (*GetBlockMetadataResponse)(nil) + } + r := new(GetBlockMetadataResponse) + if rhs := m.Blocks; rhs != nil { + tmpContainer := make([]*BlockMeta, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Blocks = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetBlockMetadataResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *AddBlockRequest) EqualVT(that *AddBlockRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Block.EqualVT(that.Block) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AddBlockRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AddBlockRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AddBlockResponse) EqualVT(that *AddBlockResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AddBlockResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AddBlockResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetBlockMetadataRequest) EqualVT(that *GetBlockMetadataRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Blocks.EqualVT(that.Blocks) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetBlockMetadataRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetBlockMetadataRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetBlockMetadataResponse) EqualVT(that *GetBlockMetadataResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Blocks) != len(that.Blocks) { + return false + } + for i, vx := range this.Blocks { + vy := that.Blocks[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &BlockMeta{} + } + if q == nil { + q = &BlockMeta{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetBlockMetadataResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetBlockMetadataResponse) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// IndexServiceClient is the client API for IndexService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type IndexServiceClient interface { + AddBlock(ctx context.Context, in *AddBlockRequest, opts ...grpc.CallOption) (*AddBlockResponse, error) + GetBlockMetadata(ctx context.Context, in *GetBlockMetadataRequest, opts ...grpc.CallOption) (*GetBlockMetadataResponse, error) +} + +type indexServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewIndexServiceClient(cc grpc.ClientConnInterface) IndexServiceClient { + return &indexServiceClient{cc} +} + +func (c *indexServiceClient) AddBlock(ctx context.Context, in *AddBlockRequest, opts ...grpc.CallOption) (*AddBlockResponse, error) { + out := new(AddBlockResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.IndexService/AddBlock", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *indexServiceClient) GetBlockMetadata(ctx context.Context, in *GetBlockMetadataRequest, opts ...grpc.CallOption) (*GetBlockMetadataResponse, error) { + out := new(GetBlockMetadataResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.IndexService/GetBlockMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// IndexServiceServer is the server API for IndexService service. +// All implementations must embed UnimplementedIndexServiceServer +// for forward compatibility +type IndexServiceServer interface { + AddBlock(context.Context, *AddBlockRequest) (*AddBlockResponse, error) + GetBlockMetadata(context.Context, *GetBlockMetadataRequest) (*GetBlockMetadataResponse, error) + mustEmbedUnimplementedIndexServiceServer() +} + +// UnimplementedIndexServiceServer must be embedded to have forward compatible implementations. +type UnimplementedIndexServiceServer struct { +} + +func (UnimplementedIndexServiceServer) AddBlock(context.Context, *AddBlockRequest) (*AddBlockResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddBlock not implemented") +} +func (UnimplementedIndexServiceServer) GetBlockMetadata(context.Context, *GetBlockMetadataRequest) (*GetBlockMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetBlockMetadata not implemented") +} +func (UnimplementedIndexServiceServer) mustEmbedUnimplementedIndexServiceServer() {} + +// UnsafeIndexServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to IndexServiceServer will +// result in compilation errors. +type UnsafeIndexServiceServer interface { + mustEmbedUnimplementedIndexServiceServer() +} + +func RegisterIndexServiceServer(s grpc.ServiceRegistrar, srv IndexServiceServer) { + s.RegisterService(&IndexService_ServiceDesc, srv) +} + +func _IndexService_AddBlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddBlockRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IndexServiceServer).AddBlock(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.IndexService/AddBlock", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IndexServiceServer).AddBlock(ctx, req.(*AddBlockRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _IndexService_GetBlockMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBlockMetadataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IndexServiceServer).GetBlockMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.IndexService/GetBlockMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IndexServiceServer).GetBlockMetadata(ctx, req.(*GetBlockMetadataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// IndexService_ServiceDesc is the grpc.ServiceDesc for IndexService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var IndexService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "metastore.v1.IndexService", + HandlerType: (*IndexServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddBlock", + Handler: _IndexService_AddBlock_Handler, + }, + { + MethodName: "GetBlockMetadata", + Handler: _IndexService_GetBlockMetadata_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "metastore/v1/index.proto", +} + +func (m *AddBlockRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddBlockRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AddBlockRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Block != nil { + size, err := m.Block.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddBlockResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddBlockResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AddBlockResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *GetBlockMetadataRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetBlockMetadataRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetBlockMetadataRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Blocks != nil { + size, err := m.Blocks.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetBlockMetadataResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetBlockMetadataResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetBlockMetadataResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Blocks) > 0 { + for iNdEx := len(m.Blocks) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Blocks[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *AddBlockRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Block != nil { + l = m.Block.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *AddBlockResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *GetBlockMetadataRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Blocks != nil { + l = m.Blocks.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *GetBlockMetadataResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Blocks) > 0 { + for _, e := range m.Blocks { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *AddBlockRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddBlockRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddBlockRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Block", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Block == nil { + m.Block = &BlockMeta{} + } + if err := m.Block.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddBlockResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddBlockResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddBlockResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetBlockMetadataRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetBlockMetadataRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetBlockMetadataRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Blocks == nil { + m.Blocks = &BlockList{} + } + if err := m.Blocks.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetBlockMetadataResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetBlockMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetBlockMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Blocks = append(m.Blocks, &BlockMeta{}) + if err := m.Blocks[len(m.Blocks)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/compactor.connect.go b/api/gen/proto/go/metastore/v1/metastorev1connect/compactor.connect.go new file mode 100644 index 0000000000..18d72c6ffa --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/compactor.connect.go @@ -0,0 +1,111 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: metastore/v1/compactor.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // CompactionServiceName is the fully-qualified name of the CompactionService service. + CompactionServiceName = "metastore.v1.CompactionService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // CompactionServicePollCompactionJobsProcedure is the fully-qualified name of the + // CompactionService's PollCompactionJobs RPC. + CompactionServicePollCompactionJobsProcedure = "/metastore.v1.CompactionService/PollCompactionJobs" +) + +// CompactionServiceClient is a client for the metastore.v1.CompactionService service. +type CompactionServiceClient interface { + // Used to both retrieve jobs and update the jobs status at the same time. + PollCompactionJobs(context.Context, *connect.Request[v1.PollCompactionJobsRequest]) (*connect.Response[v1.PollCompactionJobsResponse], error) +} + +// NewCompactionServiceClient constructs a client for the metastore.v1.CompactionService service. By +// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, +// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewCompactionServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) CompactionServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + compactionServiceMethods := v1.File_metastore_v1_compactor_proto.Services().ByName("CompactionService").Methods() + return &compactionServiceClient{ + pollCompactionJobs: connect.NewClient[v1.PollCompactionJobsRequest, v1.PollCompactionJobsResponse]( + httpClient, + baseURL+CompactionServicePollCompactionJobsProcedure, + connect.WithSchema(compactionServiceMethods.ByName("PollCompactionJobs")), + connect.WithClientOptions(opts...), + ), + } +} + +// compactionServiceClient implements CompactionServiceClient. +type compactionServiceClient struct { + pollCompactionJobs *connect.Client[v1.PollCompactionJobsRequest, v1.PollCompactionJobsResponse] +} + +// PollCompactionJobs calls metastore.v1.CompactionService.PollCompactionJobs. +func (c *compactionServiceClient) PollCompactionJobs(ctx context.Context, req *connect.Request[v1.PollCompactionJobsRequest]) (*connect.Response[v1.PollCompactionJobsResponse], error) { + return c.pollCompactionJobs.CallUnary(ctx, req) +} + +// CompactionServiceHandler is an implementation of the metastore.v1.CompactionService service. +type CompactionServiceHandler interface { + // Used to both retrieve jobs and update the jobs status at the same time. + PollCompactionJobs(context.Context, *connect.Request[v1.PollCompactionJobsRequest]) (*connect.Response[v1.PollCompactionJobsResponse], error) +} + +// NewCompactionServiceHandler builds an HTTP handler from the service implementation. It returns +// the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewCompactionServiceHandler(svc CompactionServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + compactionServiceMethods := v1.File_metastore_v1_compactor_proto.Services().ByName("CompactionService").Methods() + compactionServicePollCompactionJobsHandler := connect.NewUnaryHandler( + CompactionServicePollCompactionJobsProcedure, + svc.PollCompactionJobs, + connect.WithSchema(compactionServiceMethods.ByName("PollCompactionJobs")), + connect.WithHandlerOptions(opts...), + ) + return "/metastore.v1.CompactionService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case CompactionServicePollCompactionJobsProcedure: + compactionServicePollCompactionJobsHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedCompactionServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedCompactionServiceHandler struct{} + +func (UnimplementedCompactionServiceHandler) PollCompactionJobs(context.Context, *connect.Request[v1.PollCompactionJobsRequest]) (*connect.Response[v1.PollCompactionJobsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.CompactionService.PollCompactionJobs is not implemented")) +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/compactor.connect.mux.go b/api/gen/proto/go/metastore/v1/metastorev1connect/compactor.connect.mux.go new file mode 100644 index 0000000000..90b7d7a582 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/compactor.connect.mux.go @@ -0,0 +1,27 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: metastore/v1/compactor.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterCompactionServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterCompactionServiceHandler(mux *mux.Router, svc CompactionServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/metastore.v1.CompactionService/PollCompactionJobs", connect.NewUnaryHandler( + "/metastore.v1.CompactionService/PollCompactionJobs", + svc.PollCompactionJobs, + opts..., + )) +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/index.connect.go b/api/gen/proto/go/metastore/v1/metastorev1connect/index.connect.go new file mode 100644 index 0000000000..8302b8df96 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/index.connect.go @@ -0,0 +1,137 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: metastore/v1/index.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // IndexServiceName is the fully-qualified name of the IndexService service. + IndexServiceName = "metastore.v1.IndexService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // IndexServiceAddBlockProcedure is the fully-qualified name of the IndexService's AddBlock RPC. + IndexServiceAddBlockProcedure = "/metastore.v1.IndexService/AddBlock" + // IndexServiceGetBlockMetadataProcedure is the fully-qualified name of the IndexService's + // GetBlockMetadata RPC. + IndexServiceGetBlockMetadataProcedure = "/metastore.v1.IndexService/GetBlockMetadata" +) + +// IndexServiceClient is a client for the metastore.v1.IndexService service. +type IndexServiceClient interface { + AddBlock(context.Context, *connect.Request[v1.AddBlockRequest]) (*connect.Response[v1.AddBlockResponse], error) + GetBlockMetadata(context.Context, *connect.Request[v1.GetBlockMetadataRequest]) (*connect.Response[v1.GetBlockMetadataResponse], error) +} + +// NewIndexServiceClient constructs a client for the metastore.v1.IndexService service. By default, +// it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and +// sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() +// or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewIndexServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) IndexServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + indexServiceMethods := v1.File_metastore_v1_index_proto.Services().ByName("IndexService").Methods() + return &indexServiceClient{ + addBlock: connect.NewClient[v1.AddBlockRequest, v1.AddBlockResponse]( + httpClient, + baseURL+IndexServiceAddBlockProcedure, + connect.WithSchema(indexServiceMethods.ByName("AddBlock")), + connect.WithClientOptions(opts...), + ), + getBlockMetadata: connect.NewClient[v1.GetBlockMetadataRequest, v1.GetBlockMetadataResponse]( + httpClient, + baseURL+IndexServiceGetBlockMetadataProcedure, + connect.WithSchema(indexServiceMethods.ByName("GetBlockMetadata")), + connect.WithClientOptions(opts...), + ), + } +} + +// indexServiceClient implements IndexServiceClient. +type indexServiceClient struct { + addBlock *connect.Client[v1.AddBlockRequest, v1.AddBlockResponse] + getBlockMetadata *connect.Client[v1.GetBlockMetadataRequest, v1.GetBlockMetadataResponse] +} + +// AddBlock calls metastore.v1.IndexService.AddBlock. +func (c *indexServiceClient) AddBlock(ctx context.Context, req *connect.Request[v1.AddBlockRequest]) (*connect.Response[v1.AddBlockResponse], error) { + return c.addBlock.CallUnary(ctx, req) +} + +// GetBlockMetadata calls metastore.v1.IndexService.GetBlockMetadata. +func (c *indexServiceClient) GetBlockMetadata(ctx context.Context, req *connect.Request[v1.GetBlockMetadataRequest]) (*connect.Response[v1.GetBlockMetadataResponse], error) { + return c.getBlockMetadata.CallUnary(ctx, req) +} + +// IndexServiceHandler is an implementation of the metastore.v1.IndexService service. +type IndexServiceHandler interface { + AddBlock(context.Context, *connect.Request[v1.AddBlockRequest]) (*connect.Response[v1.AddBlockResponse], error) + GetBlockMetadata(context.Context, *connect.Request[v1.GetBlockMetadataRequest]) (*connect.Response[v1.GetBlockMetadataResponse], error) +} + +// NewIndexServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewIndexServiceHandler(svc IndexServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + indexServiceMethods := v1.File_metastore_v1_index_proto.Services().ByName("IndexService").Methods() + indexServiceAddBlockHandler := connect.NewUnaryHandler( + IndexServiceAddBlockProcedure, + svc.AddBlock, + connect.WithSchema(indexServiceMethods.ByName("AddBlock")), + connect.WithHandlerOptions(opts...), + ) + indexServiceGetBlockMetadataHandler := connect.NewUnaryHandler( + IndexServiceGetBlockMetadataProcedure, + svc.GetBlockMetadata, + connect.WithSchema(indexServiceMethods.ByName("GetBlockMetadata")), + connect.WithHandlerOptions(opts...), + ) + return "/metastore.v1.IndexService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case IndexServiceAddBlockProcedure: + indexServiceAddBlockHandler.ServeHTTP(w, r) + case IndexServiceGetBlockMetadataProcedure: + indexServiceGetBlockMetadataHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedIndexServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedIndexServiceHandler struct{} + +func (UnimplementedIndexServiceHandler) AddBlock(context.Context, *connect.Request[v1.AddBlockRequest]) (*connect.Response[v1.AddBlockResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.IndexService.AddBlock is not implemented")) +} + +func (UnimplementedIndexServiceHandler) GetBlockMetadata(context.Context, *connect.Request[v1.GetBlockMetadataRequest]) (*connect.Response[v1.GetBlockMetadataResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.IndexService.GetBlockMetadata is not implemented")) +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/index.connect.mux.go b/api/gen/proto/go/metastore/v1/metastorev1connect/index.connect.mux.go new file mode 100644 index 0000000000..d8274fcda9 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/index.connect.mux.go @@ -0,0 +1,32 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: metastore/v1/index.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterIndexServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterIndexServiceHandler(mux *mux.Router, svc IndexServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/metastore.v1.IndexService/AddBlock", connect.NewUnaryHandler( + "/metastore.v1.IndexService/AddBlock", + svc.AddBlock, + opts..., + )) + mux.Handle("/metastore.v1.IndexService/GetBlockMetadata", connect.NewUnaryHandler( + "/metastore.v1.IndexService/GetBlockMetadata", + svc.GetBlockMetadata, + opts..., + )) +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/query.connect.go b/api/gen/proto/go/metastore/v1/metastorev1connect/query.connect.go new file mode 100644 index 0000000000..c89ce0afc2 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/query.connect.go @@ -0,0 +1,139 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: metastore/v1/query.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // MetadataQueryServiceName is the fully-qualified name of the MetadataQueryService service. + MetadataQueryServiceName = "metastore.v1.MetadataQueryService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // MetadataQueryServiceQueryMetadataProcedure is the fully-qualified name of the + // MetadataQueryService's QueryMetadata RPC. + MetadataQueryServiceQueryMetadataProcedure = "/metastore.v1.MetadataQueryService/QueryMetadata" + // MetadataQueryServiceQueryMetadataLabelsProcedure is the fully-qualified name of the + // MetadataQueryService's QueryMetadataLabels RPC. + MetadataQueryServiceQueryMetadataLabelsProcedure = "/metastore.v1.MetadataQueryService/QueryMetadataLabels" +) + +// MetadataQueryServiceClient is a client for the metastore.v1.MetadataQueryService service. +type MetadataQueryServiceClient interface { + QueryMetadata(context.Context, *connect.Request[v1.QueryMetadataRequest]) (*connect.Response[v1.QueryMetadataResponse], error) + QueryMetadataLabels(context.Context, *connect.Request[v1.QueryMetadataLabelsRequest]) (*connect.Response[v1.QueryMetadataLabelsResponse], error) +} + +// NewMetadataQueryServiceClient constructs a client for the metastore.v1.MetadataQueryService +// service. By default, it uses the Connect protocol with the binary Protobuf Codec, asks for +// gzipped responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply +// the connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewMetadataQueryServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) MetadataQueryServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + metadataQueryServiceMethods := v1.File_metastore_v1_query_proto.Services().ByName("MetadataQueryService").Methods() + return &metadataQueryServiceClient{ + queryMetadata: connect.NewClient[v1.QueryMetadataRequest, v1.QueryMetadataResponse]( + httpClient, + baseURL+MetadataQueryServiceQueryMetadataProcedure, + connect.WithSchema(metadataQueryServiceMethods.ByName("QueryMetadata")), + connect.WithClientOptions(opts...), + ), + queryMetadataLabels: connect.NewClient[v1.QueryMetadataLabelsRequest, v1.QueryMetadataLabelsResponse]( + httpClient, + baseURL+MetadataQueryServiceQueryMetadataLabelsProcedure, + connect.WithSchema(metadataQueryServiceMethods.ByName("QueryMetadataLabels")), + connect.WithClientOptions(opts...), + ), + } +} + +// metadataQueryServiceClient implements MetadataQueryServiceClient. +type metadataQueryServiceClient struct { + queryMetadata *connect.Client[v1.QueryMetadataRequest, v1.QueryMetadataResponse] + queryMetadataLabels *connect.Client[v1.QueryMetadataLabelsRequest, v1.QueryMetadataLabelsResponse] +} + +// QueryMetadata calls metastore.v1.MetadataQueryService.QueryMetadata. +func (c *metadataQueryServiceClient) QueryMetadata(ctx context.Context, req *connect.Request[v1.QueryMetadataRequest]) (*connect.Response[v1.QueryMetadataResponse], error) { + return c.queryMetadata.CallUnary(ctx, req) +} + +// QueryMetadataLabels calls metastore.v1.MetadataQueryService.QueryMetadataLabels. +func (c *metadataQueryServiceClient) QueryMetadataLabels(ctx context.Context, req *connect.Request[v1.QueryMetadataLabelsRequest]) (*connect.Response[v1.QueryMetadataLabelsResponse], error) { + return c.queryMetadataLabels.CallUnary(ctx, req) +} + +// MetadataQueryServiceHandler is an implementation of the metastore.v1.MetadataQueryService +// service. +type MetadataQueryServiceHandler interface { + QueryMetadata(context.Context, *connect.Request[v1.QueryMetadataRequest]) (*connect.Response[v1.QueryMetadataResponse], error) + QueryMetadataLabels(context.Context, *connect.Request[v1.QueryMetadataLabelsRequest]) (*connect.Response[v1.QueryMetadataLabelsResponse], error) +} + +// NewMetadataQueryServiceHandler builds an HTTP handler from the service implementation. It returns +// the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewMetadataQueryServiceHandler(svc MetadataQueryServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + metadataQueryServiceMethods := v1.File_metastore_v1_query_proto.Services().ByName("MetadataQueryService").Methods() + metadataQueryServiceQueryMetadataHandler := connect.NewUnaryHandler( + MetadataQueryServiceQueryMetadataProcedure, + svc.QueryMetadata, + connect.WithSchema(metadataQueryServiceMethods.ByName("QueryMetadata")), + connect.WithHandlerOptions(opts...), + ) + metadataQueryServiceQueryMetadataLabelsHandler := connect.NewUnaryHandler( + MetadataQueryServiceQueryMetadataLabelsProcedure, + svc.QueryMetadataLabels, + connect.WithSchema(metadataQueryServiceMethods.ByName("QueryMetadataLabels")), + connect.WithHandlerOptions(opts...), + ) + return "/metastore.v1.MetadataQueryService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case MetadataQueryServiceQueryMetadataProcedure: + metadataQueryServiceQueryMetadataHandler.ServeHTTP(w, r) + case MetadataQueryServiceQueryMetadataLabelsProcedure: + metadataQueryServiceQueryMetadataLabelsHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedMetadataQueryServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedMetadataQueryServiceHandler struct{} + +func (UnimplementedMetadataQueryServiceHandler) QueryMetadata(context.Context, *connect.Request[v1.QueryMetadataRequest]) (*connect.Response[v1.QueryMetadataResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.MetadataQueryService.QueryMetadata is not implemented")) +} + +func (UnimplementedMetadataQueryServiceHandler) QueryMetadataLabels(context.Context, *connect.Request[v1.QueryMetadataLabelsRequest]) (*connect.Response[v1.QueryMetadataLabelsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.MetadataQueryService.QueryMetadataLabels is not implemented")) +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/query.connect.mux.go b/api/gen/proto/go/metastore/v1/metastorev1connect/query.connect.mux.go new file mode 100644 index 0000000000..9e7d230a1d --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/query.connect.mux.go @@ -0,0 +1,32 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: metastore/v1/query.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterMetadataQueryServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterMetadataQueryServiceHandler(mux *mux.Router, svc MetadataQueryServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/metastore.v1.MetadataQueryService/QueryMetadata", connect.NewUnaryHandler( + "/metastore.v1.MetadataQueryService/QueryMetadata", + svc.QueryMetadata, + opts..., + )) + mux.Handle("/metastore.v1.MetadataQueryService/QueryMetadataLabels", connect.NewUnaryHandler( + "/metastore.v1.MetadataQueryService/QueryMetadataLabels", + svc.QueryMetadataLabels, + opts..., + )) +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/tenant.connect.go b/api/gen/proto/go/metastore/v1/metastorev1connect/tenant.connect.go new file mode 100644 index 0000000000..c3b6d45f15 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/tenant.connect.go @@ -0,0 +1,166 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: metastore/v1/tenant.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // TenantServiceName is the fully-qualified name of the TenantService service. + TenantServiceName = "metastore.v1.TenantService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // TenantServiceGetTenantsProcedure is the fully-qualified name of the TenantService's GetTenants + // RPC. + TenantServiceGetTenantsProcedure = "/metastore.v1.TenantService/GetTenants" + // TenantServiceGetTenantProcedure is the fully-qualified name of the TenantService's GetTenant RPC. + TenantServiceGetTenantProcedure = "/metastore.v1.TenantService/GetTenant" + // TenantServiceDeleteTenantProcedure is the fully-qualified name of the TenantService's + // DeleteTenant RPC. + TenantServiceDeleteTenantProcedure = "/metastore.v1.TenantService/DeleteTenant" +) + +// TenantServiceClient is a client for the metastore.v1.TenantService service. +type TenantServiceClient interface { + GetTenants(context.Context, *connect.Request[v1.GetTenantsRequest]) (*connect.Response[v1.GetTenantsResponse], error) + GetTenant(context.Context, *connect.Request[v1.GetTenantRequest]) (*connect.Response[v1.GetTenantResponse], error) + DeleteTenant(context.Context, *connect.Request[v1.DeleteTenantRequest]) (*connect.Response[v1.DeleteTenantResponse], error) +} + +// NewTenantServiceClient constructs a client for the metastore.v1.TenantService service. By +// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, +// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewTenantServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) TenantServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + tenantServiceMethods := v1.File_metastore_v1_tenant_proto.Services().ByName("TenantService").Methods() + return &tenantServiceClient{ + getTenants: connect.NewClient[v1.GetTenantsRequest, v1.GetTenantsResponse]( + httpClient, + baseURL+TenantServiceGetTenantsProcedure, + connect.WithSchema(tenantServiceMethods.ByName("GetTenants")), + connect.WithClientOptions(opts...), + ), + getTenant: connect.NewClient[v1.GetTenantRequest, v1.GetTenantResponse]( + httpClient, + baseURL+TenantServiceGetTenantProcedure, + connect.WithSchema(tenantServiceMethods.ByName("GetTenant")), + connect.WithClientOptions(opts...), + ), + deleteTenant: connect.NewClient[v1.DeleteTenantRequest, v1.DeleteTenantResponse]( + httpClient, + baseURL+TenantServiceDeleteTenantProcedure, + connect.WithSchema(tenantServiceMethods.ByName("DeleteTenant")), + connect.WithClientOptions(opts...), + ), + } +} + +// tenantServiceClient implements TenantServiceClient. +type tenantServiceClient struct { + getTenants *connect.Client[v1.GetTenantsRequest, v1.GetTenantsResponse] + getTenant *connect.Client[v1.GetTenantRequest, v1.GetTenantResponse] + deleteTenant *connect.Client[v1.DeleteTenantRequest, v1.DeleteTenantResponse] +} + +// GetTenants calls metastore.v1.TenantService.GetTenants. +func (c *tenantServiceClient) GetTenants(ctx context.Context, req *connect.Request[v1.GetTenantsRequest]) (*connect.Response[v1.GetTenantsResponse], error) { + return c.getTenants.CallUnary(ctx, req) +} + +// GetTenant calls metastore.v1.TenantService.GetTenant. +func (c *tenantServiceClient) GetTenant(ctx context.Context, req *connect.Request[v1.GetTenantRequest]) (*connect.Response[v1.GetTenantResponse], error) { + return c.getTenant.CallUnary(ctx, req) +} + +// DeleteTenant calls metastore.v1.TenantService.DeleteTenant. +func (c *tenantServiceClient) DeleteTenant(ctx context.Context, req *connect.Request[v1.DeleteTenantRequest]) (*connect.Response[v1.DeleteTenantResponse], error) { + return c.deleteTenant.CallUnary(ctx, req) +} + +// TenantServiceHandler is an implementation of the metastore.v1.TenantService service. +type TenantServiceHandler interface { + GetTenants(context.Context, *connect.Request[v1.GetTenantsRequest]) (*connect.Response[v1.GetTenantsResponse], error) + GetTenant(context.Context, *connect.Request[v1.GetTenantRequest]) (*connect.Response[v1.GetTenantResponse], error) + DeleteTenant(context.Context, *connect.Request[v1.DeleteTenantRequest]) (*connect.Response[v1.DeleteTenantResponse], error) +} + +// NewTenantServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewTenantServiceHandler(svc TenantServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + tenantServiceMethods := v1.File_metastore_v1_tenant_proto.Services().ByName("TenantService").Methods() + tenantServiceGetTenantsHandler := connect.NewUnaryHandler( + TenantServiceGetTenantsProcedure, + svc.GetTenants, + connect.WithSchema(tenantServiceMethods.ByName("GetTenants")), + connect.WithHandlerOptions(opts...), + ) + tenantServiceGetTenantHandler := connect.NewUnaryHandler( + TenantServiceGetTenantProcedure, + svc.GetTenant, + connect.WithSchema(tenantServiceMethods.ByName("GetTenant")), + connect.WithHandlerOptions(opts...), + ) + tenantServiceDeleteTenantHandler := connect.NewUnaryHandler( + TenantServiceDeleteTenantProcedure, + svc.DeleteTenant, + connect.WithSchema(tenantServiceMethods.ByName("DeleteTenant")), + connect.WithHandlerOptions(opts...), + ) + return "/metastore.v1.TenantService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case TenantServiceGetTenantsProcedure: + tenantServiceGetTenantsHandler.ServeHTTP(w, r) + case TenantServiceGetTenantProcedure: + tenantServiceGetTenantHandler.ServeHTTP(w, r) + case TenantServiceDeleteTenantProcedure: + tenantServiceDeleteTenantHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedTenantServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedTenantServiceHandler struct{} + +func (UnimplementedTenantServiceHandler) GetTenants(context.Context, *connect.Request[v1.GetTenantsRequest]) (*connect.Response[v1.GetTenantsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.TenantService.GetTenants is not implemented")) +} + +func (UnimplementedTenantServiceHandler) GetTenant(context.Context, *connect.Request[v1.GetTenantRequest]) (*connect.Response[v1.GetTenantResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.TenantService.GetTenant is not implemented")) +} + +func (UnimplementedTenantServiceHandler) DeleteTenant(context.Context, *connect.Request[v1.DeleteTenantRequest]) (*connect.Response[v1.DeleteTenantResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metastore.v1.TenantService.DeleteTenant is not implemented")) +} diff --git a/api/gen/proto/go/metastore/v1/metastorev1connect/tenant.connect.mux.go b/api/gen/proto/go/metastore/v1/metastorev1connect/tenant.connect.mux.go new file mode 100644 index 0000000000..7d364dc72b --- /dev/null +++ b/api/gen/proto/go/metastore/v1/metastorev1connect/tenant.connect.mux.go @@ -0,0 +1,37 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: metastore/v1/tenant.proto + +package metastorev1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterTenantServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterTenantServiceHandler(mux *mux.Router, svc TenantServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/metastore.v1.TenantService/GetTenants", connect.NewUnaryHandler( + "/metastore.v1.TenantService/GetTenants", + svc.GetTenants, + opts..., + )) + mux.Handle("/metastore.v1.TenantService/GetTenant", connect.NewUnaryHandler( + "/metastore.v1.TenantService/GetTenant", + svc.GetTenant, + opts..., + )) + mux.Handle("/metastore.v1.TenantService/DeleteTenant", connect.NewUnaryHandler( + "/metastore.v1.TenantService/DeleteTenant", + svc.DeleteTenant, + opts..., + )) +} diff --git a/api/gen/proto/go/metastore/v1/query.pb.go b/api/gen/proto/go/metastore/v1/query.pb.go new file mode 100644 index 0000000000..20de4f99cf --- /dev/null +++ b/api/gen/proto/go/metastore/v1/query.pb.go @@ -0,0 +1,352 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: metastore/v1/query.proto + +package metastorev1 + +import ( + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type QueryMetadataRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + TenantId []string `protobuf:"bytes,1,rep,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + EndTime int64 `protobuf:"varint,3,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + Query string `protobuf:"bytes,4,opt,name=query,proto3" json:"query,omitempty"` + Labels []string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryMetadataRequest) Reset() { + *x = QueryMetadataRequest{} + mi := &file_metastore_v1_query_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryMetadataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryMetadataRequest) ProtoMessage() {} + +func (x *QueryMetadataRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_query_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryMetadataRequest.ProtoReflect.Descriptor instead. +func (*QueryMetadataRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_query_proto_rawDescGZIP(), []int{0} +} + +func (x *QueryMetadataRequest) GetTenantId() []string { + if x != nil { + return x.TenantId + } + return nil +} + +func (x *QueryMetadataRequest) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *QueryMetadataRequest) GetEndTime() int64 { + if x != nil { + return x.EndTime + } + return 0 +} + +func (x *QueryMetadataRequest) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *QueryMetadataRequest) GetLabels() []string { + if x != nil { + return x.Labels + } + return nil +} + +type QueryMetadataResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Blocks []*BlockMeta `protobuf:"bytes,1,rep,name=blocks,proto3" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryMetadataResponse) Reset() { + *x = QueryMetadataResponse{} + mi := &file_metastore_v1_query_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryMetadataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryMetadataResponse) ProtoMessage() {} + +func (x *QueryMetadataResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_query_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryMetadataResponse.ProtoReflect.Descriptor instead. +func (*QueryMetadataResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_query_proto_rawDescGZIP(), []int{1} +} + +func (x *QueryMetadataResponse) GetBlocks() []*BlockMeta { + if x != nil { + return x.Blocks + } + return nil +} + +type QueryMetadataLabelsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + TenantId []string `protobuf:"bytes,1,rep,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + EndTime int64 `protobuf:"varint,3,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + Query string `protobuf:"bytes,4,opt,name=query,proto3" json:"query,omitempty"` + Labels []string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryMetadataLabelsRequest) Reset() { + *x = QueryMetadataLabelsRequest{} + mi := &file_metastore_v1_query_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryMetadataLabelsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryMetadataLabelsRequest) ProtoMessage() {} + +func (x *QueryMetadataLabelsRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_query_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryMetadataLabelsRequest.ProtoReflect.Descriptor instead. +func (*QueryMetadataLabelsRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_query_proto_rawDescGZIP(), []int{2} +} + +func (x *QueryMetadataLabelsRequest) GetTenantId() []string { + if x != nil { + return x.TenantId + } + return nil +} + +func (x *QueryMetadataLabelsRequest) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *QueryMetadataLabelsRequest) GetEndTime() int64 { + if x != nil { + return x.EndTime + } + return 0 +} + +func (x *QueryMetadataLabelsRequest) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *QueryMetadataLabelsRequest) GetLabels() []string { + if x != nil { + return x.Labels + } + return nil +} + +type QueryMetadataLabelsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Labels []*v1.Labels `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryMetadataLabelsResponse) Reset() { + *x = QueryMetadataLabelsResponse{} + mi := &file_metastore_v1_query_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryMetadataLabelsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryMetadataLabelsResponse) ProtoMessage() {} + +func (x *QueryMetadataLabelsResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_query_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryMetadataLabelsResponse.ProtoReflect.Descriptor instead. +func (*QueryMetadataLabelsResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_query_proto_rawDescGZIP(), []int{3} +} + +func (x *QueryMetadataLabelsResponse) GetLabels() []*v1.Labels { + if x != nil { + return x.Labels + } + return nil +} + +var File_metastore_v1_query_proto protoreflect.FileDescriptor + +const file_metastore_v1_query_proto_rawDesc = "" + + "\n" + + "\x18metastore/v1/query.proto\x12\fmetastore.v1\x1a\x18metastore/v1/types.proto\x1a\x14types/v1/types.proto\"\x9b\x01\n" + + "\x14QueryMetadataRequest\x12\x1b\n" + + "\ttenant_id\x18\x01 \x03(\tR\btenantId\x12\x1d\n" + + "\n" + + "start_time\x18\x02 \x01(\x03R\tstartTime\x12\x19\n" + + "\bend_time\x18\x03 \x01(\x03R\aendTime\x12\x14\n" + + "\x05query\x18\x04 \x01(\tR\x05query\x12\x16\n" + + "\x06labels\x18\x05 \x03(\tR\x06labels\"H\n" + + "\x15QueryMetadataResponse\x12/\n" + + "\x06blocks\x18\x01 \x03(\v2\x17.metastore.v1.BlockMetaR\x06blocks\"\xa1\x01\n" + + "\x1aQueryMetadataLabelsRequest\x12\x1b\n" + + "\ttenant_id\x18\x01 \x03(\tR\btenantId\x12\x1d\n" + + "\n" + + "start_time\x18\x02 \x01(\x03R\tstartTime\x12\x19\n" + + "\bend_time\x18\x03 \x01(\x03R\aendTime\x12\x14\n" + + "\x05query\x18\x04 \x01(\tR\x05query\x12\x16\n" + + "\x06labels\x18\x05 \x03(\tR\x06labels\"G\n" + + "\x1bQueryMetadataLabelsResponse\x12(\n" + + "\x06labels\x18\x01 \x03(\v2\x10.types.v1.LabelsR\x06labels2\xe0\x01\n" + + "\x14MetadataQueryService\x12Z\n" + + "\rQueryMetadata\x12\".metastore.v1.QueryMetadataRequest\x1a#.metastore.v1.QueryMetadataResponse\"\x00\x12l\n" + + "\x13QueryMetadataLabels\x12(.metastore.v1.QueryMetadataLabelsRequest\x1a).metastore.v1.QueryMetadataLabelsResponse\"\x00B\xb7\x01\n" + + "\x10com.metastore.v1B\n" + + "QueryProtoP\x01ZFgithub.com/grafana/pyroscope/api/gen/proto/go/metastore/v1;metastorev1\xa2\x02\x03MXX\xaa\x02\fMetastore.V1\xca\x02\fMetastore\\V1\xe2\x02\x18Metastore\\V1\\GPBMetadata\xea\x02\rMetastore::V1b\x06proto3" + +var ( + file_metastore_v1_query_proto_rawDescOnce sync.Once + file_metastore_v1_query_proto_rawDescData []byte +) + +func file_metastore_v1_query_proto_rawDescGZIP() []byte { + file_metastore_v1_query_proto_rawDescOnce.Do(func() { + file_metastore_v1_query_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_metastore_v1_query_proto_rawDesc), len(file_metastore_v1_query_proto_rawDesc))) + }) + return file_metastore_v1_query_proto_rawDescData +} + +var file_metastore_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_metastore_v1_query_proto_goTypes = []any{ + (*QueryMetadataRequest)(nil), // 0: metastore.v1.QueryMetadataRequest + (*QueryMetadataResponse)(nil), // 1: metastore.v1.QueryMetadataResponse + (*QueryMetadataLabelsRequest)(nil), // 2: metastore.v1.QueryMetadataLabelsRequest + (*QueryMetadataLabelsResponse)(nil), // 3: metastore.v1.QueryMetadataLabelsResponse + (*BlockMeta)(nil), // 4: metastore.v1.BlockMeta + (*v1.Labels)(nil), // 5: types.v1.Labels +} +var file_metastore_v1_query_proto_depIdxs = []int32{ + 4, // 0: metastore.v1.QueryMetadataResponse.blocks:type_name -> metastore.v1.BlockMeta + 5, // 1: metastore.v1.QueryMetadataLabelsResponse.labels:type_name -> types.v1.Labels + 0, // 2: metastore.v1.MetadataQueryService.QueryMetadata:input_type -> metastore.v1.QueryMetadataRequest + 2, // 3: metastore.v1.MetadataQueryService.QueryMetadataLabels:input_type -> metastore.v1.QueryMetadataLabelsRequest + 1, // 4: metastore.v1.MetadataQueryService.QueryMetadata:output_type -> metastore.v1.QueryMetadataResponse + 3, // 5: metastore.v1.MetadataQueryService.QueryMetadataLabels:output_type -> metastore.v1.QueryMetadataLabelsResponse + 4, // [4:6] is the sub-list for method output_type + 2, // [2:4] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_metastore_v1_query_proto_init() } +func file_metastore_v1_query_proto_init() { + if File_metastore_v1_query_proto != nil { + return + } + file_metastore_v1_types_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_metastore_v1_query_proto_rawDesc), len(file_metastore_v1_query_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_metastore_v1_query_proto_goTypes, + DependencyIndexes: file_metastore_v1_query_proto_depIdxs, + MessageInfos: file_metastore_v1_query_proto_msgTypes, + }.Build() + File_metastore_v1_query_proto = out.File + file_metastore_v1_query_proto_goTypes = nil + file_metastore_v1_query_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/metastore/v1/query_vtproto.pb.go b/api/gen/proto/go/metastore/v1/query_vtproto.pb.go new file mode 100644 index 0000000000..2e32ad306e --- /dev/null +++ b/api/gen/proto/go/metastore/v1/query_vtproto.pb.go @@ -0,0 +1,1306 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: metastore/v1/query.proto + +package metastorev1 + +import ( + context "context" + fmt "fmt" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *QueryMetadataRequest) CloneVT() *QueryMetadataRequest { + if m == nil { + return (*QueryMetadataRequest)(nil) + } + r := new(QueryMetadataRequest) + r.StartTime = m.StartTime + r.EndTime = m.EndTime + r.Query = m.Query + if rhs := m.TenantId; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.TenantId = tmpContainer + } + if rhs := m.Labels; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Labels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryMetadataRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *QueryMetadataResponse) CloneVT() *QueryMetadataResponse { + if m == nil { + return (*QueryMetadataResponse)(nil) + } + r := new(QueryMetadataResponse) + if rhs := m.Blocks; rhs != nil { + tmpContainer := make([]*BlockMeta, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Blocks = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryMetadataResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *QueryMetadataLabelsRequest) CloneVT() *QueryMetadataLabelsRequest { + if m == nil { + return (*QueryMetadataLabelsRequest)(nil) + } + r := new(QueryMetadataLabelsRequest) + r.StartTime = m.StartTime + r.EndTime = m.EndTime + r.Query = m.Query + if rhs := m.TenantId; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.TenantId = tmpContainer + } + if rhs := m.Labels; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Labels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryMetadataLabelsRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *QueryMetadataLabelsResponse) CloneVT() *QueryMetadataLabelsResponse { + if m == nil { + return (*QueryMetadataLabelsResponse)(nil) + } + r := new(QueryMetadataLabelsResponse) + if rhs := m.Labels; rhs != nil { + tmpContainer := make([]*v1.Labels, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.Labels }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.Labels) + } + } + r.Labels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryMetadataLabelsResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *QueryMetadataRequest) EqualVT(that *QueryMetadataRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.TenantId) != len(that.TenantId) { + return false + } + for i, vx := range this.TenantId { + vy := that.TenantId[i] + if vx != vy { + return false + } + } + if this.StartTime != that.StartTime { + return false + } + if this.EndTime != that.EndTime { + return false + } + if this.Query != that.Query { + return false + } + if len(this.Labels) != len(that.Labels) { + return false + } + for i, vx := range this.Labels { + vy := that.Labels[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryMetadataRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryMetadataRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *QueryMetadataResponse) EqualVT(that *QueryMetadataResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Blocks) != len(that.Blocks) { + return false + } + for i, vx := range this.Blocks { + vy := that.Blocks[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &BlockMeta{} + } + if q == nil { + q = &BlockMeta{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryMetadataResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryMetadataResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *QueryMetadataLabelsRequest) EqualVT(that *QueryMetadataLabelsRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.TenantId) != len(that.TenantId) { + return false + } + for i, vx := range this.TenantId { + vy := that.TenantId[i] + if vx != vy { + return false + } + } + if this.StartTime != that.StartTime { + return false + } + if this.EndTime != that.EndTime { + return false + } + if this.Query != that.Query { + return false + } + if len(this.Labels) != len(that.Labels) { + return false + } + for i, vx := range this.Labels { + vy := that.Labels[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryMetadataLabelsRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryMetadataLabelsRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *QueryMetadataLabelsResponse) EqualVT(that *QueryMetadataLabelsResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Labels) != len(that.Labels) { + return false + } + for i, vx := range this.Labels { + vy := that.Labels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.Labels{} + } + if q == nil { + q = &v1.Labels{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.Labels) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryMetadataLabelsResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryMetadataLabelsResponse) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// MetadataQueryServiceClient is the client API for MetadataQueryService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type MetadataQueryServiceClient interface { + QueryMetadata(ctx context.Context, in *QueryMetadataRequest, opts ...grpc.CallOption) (*QueryMetadataResponse, error) + QueryMetadataLabels(ctx context.Context, in *QueryMetadataLabelsRequest, opts ...grpc.CallOption) (*QueryMetadataLabelsResponse, error) +} + +type metadataQueryServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewMetadataQueryServiceClient(cc grpc.ClientConnInterface) MetadataQueryServiceClient { + return &metadataQueryServiceClient{cc} +} + +func (c *metadataQueryServiceClient) QueryMetadata(ctx context.Context, in *QueryMetadataRequest, opts ...grpc.CallOption) (*QueryMetadataResponse, error) { + out := new(QueryMetadataResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.MetadataQueryService/QueryMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *metadataQueryServiceClient) QueryMetadataLabels(ctx context.Context, in *QueryMetadataLabelsRequest, opts ...grpc.CallOption) (*QueryMetadataLabelsResponse, error) { + out := new(QueryMetadataLabelsResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.MetadataQueryService/QueryMetadataLabels", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MetadataQueryServiceServer is the server API for MetadataQueryService service. +// All implementations must embed UnimplementedMetadataQueryServiceServer +// for forward compatibility +type MetadataQueryServiceServer interface { + QueryMetadata(context.Context, *QueryMetadataRequest) (*QueryMetadataResponse, error) + QueryMetadataLabels(context.Context, *QueryMetadataLabelsRequest) (*QueryMetadataLabelsResponse, error) + mustEmbedUnimplementedMetadataQueryServiceServer() +} + +// UnimplementedMetadataQueryServiceServer must be embedded to have forward compatible implementations. +type UnimplementedMetadataQueryServiceServer struct { +} + +func (UnimplementedMetadataQueryServiceServer) QueryMetadata(context.Context, *QueryMetadataRequest) (*QueryMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryMetadata not implemented") +} +func (UnimplementedMetadataQueryServiceServer) QueryMetadataLabels(context.Context, *QueryMetadataLabelsRequest) (*QueryMetadataLabelsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryMetadataLabels not implemented") +} +func (UnimplementedMetadataQueryServiceServer) mustEmbedUnimplementedMetadataQueryServiceServer() {} + +// UnsafeMetadataQueryServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MetadataQueryServiceServer will +// result in compilation errors. +type UnsafeMetadataQueryServiceServer interface { + mustEmbedUnimplementedMetadataQueryServiceServer() +} + +func RegisterMetadataQueryServiceServer(s grpc.ServiceRegistrar, srv MetadataQueryServiceServer) { + s.RegisterService(&MetadataQueryService_ServiceDesc, srv) +} + +func _MetadataQueryService_QueryMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryMetadataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MetadataQueryServiceServer).QueryMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.MetadataQueryService/QueryMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MetadataQueryServiceServer).QueryMetadata(ctx, req.(*QueryMetadataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MetadataQueryService_QueryMetadataLabels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryMetadataLabelsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MetadataQueryServiceServer).QueryMetadataLabels(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.MetadataQueryService/QueryMetadataLabels", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MetadataQueryServiceServer).QueryMetadataLabels(ctx, req.(*QueryMetadataLabelsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// MetadataQueryService_ServiceDesc is the grpc.ServiceDesc for MetadataQueryService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var MetadataQueryService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "metastore.v1.MetadataQueryService", + HandlerType: (*MetadataQueryServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "QueryMetadata", + Handler: _MetadataQueryService_QueryMetadata_Handler, + }, + { + MethodName: "QueryMetadataLabels", + Handler: _MetadataQueryService_QueryMetadataLabels_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "metastore/v1/query.proto", +} + +func (m *QueryMetadataRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryMetadataRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryMetadataRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Labels[iNdEx]) + copy(dAtA[i:], m.Labels[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Labels[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.Query) > 0 { + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0x22 + } + if m.EndTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.EndTime)) + i-- + dAtA[i] = 0x18 + } + if m.StartTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x10 + } + if len(m.TenantId) > 0 { + for iNdEx := len(m.TenantId) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TenantId[iNdEx]) + copy(dAtA[i:], m.TenantId[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantId[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryMetadataResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryMetadataResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryMetadataResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Blocks) > 0 { + for iNdEx := len(m.Blocks) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Blocks[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryMetadataLabelsRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryMetadataLabelsRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryMetadataLabelsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Labels[iNdEx]) + copy(dAtA[i:], m.Labels[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Labels[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.Query) > 0 { + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0x22 + } + if m.EndTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.EndTime)) + i-- + dAtA[i] = 0x18 + } + if m.StartTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x10 + } + if len(m.TenantId) > 0 { + for iNdEx := len(m.TenantId) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TenantId[iNdEx]) + copy(dAtA[i:], m.TenantId[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantId[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryMetadataLabelsResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryMetadataLabelsResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryMetadataLabelsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Labels[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Labels[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryMetadataRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TenantId) > 0 { + for _, s := range m.TenantId { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.StartTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.StartTime)) + } + if m.EndTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.EndTime)) + } + l = len(m.Query) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Labels) > 0 { + for _, s := range m.Labels { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *QueryMetadataResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Blocks) > 0 { + for _, e := range m.Blocks { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *QueryMetadataLabelsRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TenantId) > 0 { + for _, s := range m.TenantId { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.StartTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.StartTime)) + } + if m.EndTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.EndTime)) + } + l = len(m.Query) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Labels) > 0 { + for _, s := range m.Labels { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *QueryMetadataLabelsResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Labels) > 0 { + for _, e := range m.Labels { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *QueryMetadataRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryMetadataRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryMetadataRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = append(m.TenantId, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + m.EndTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Labels = append(m.Labels, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryMetadataResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Blocks = append(m.Blocks, &BlockMeta{}) + if err := m.Blocks[len(m.Blocks)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryMetadataLabelsRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryMetadataLabelsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryMetadataLabelsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = append(m.TenantId, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + m.EndTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Labels = append(m.Labels, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryMetadataLabelsResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryMetadataLabelsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryMetadataLabelsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Labels = append(m.Labels, &v1.Labels{}) + if unmarshal, ok := interface{}(m.Labels[len(m.Labels)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Labels[len(m.Labels)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/metastore/v1/raft_log/raft_log.pb.go b/api/gen/proto/go/metastore/v1/raft_log/raft_log.pb.go new file mode 100644 index 0000000000..30b66ff851 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/raft_log/raft_log.pb.go @@ -0,0 +1,1187 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: metastore/v1/raft_log/raft_log.proto + +package raft_log + +import ( + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type RaftCommand int32 + +const ( + RaftCommand_RAFT_COMMAND_UNKNOWN RaftCommand = 0 + RaftCommand_RAFT_COMMAND_ADD_BLOCK_METADATA RaftCommand = 1 + RaftCommand_RAFT_COMMAND_GET_COMPACTION_PLAN_UPDATE RaftCommand = 2 + RaftCommand_RAFT_COMMAND_UPDATE_COMPACTION_PLAN RaftCommand = 3 + RaftCommand_RAFT_COMMAND_TRUNCATE_INDEX RaftCommand = 4 +) + +// Enum value maps for RaftCommand. +var ( + RaftCommand_name = map[int32]string{ + 0: "RAFT_COMMAND_UNKNOWN", + 1: "RAFT_COMMAND_ADD_BLOCK_METADATA", + 2: "RAFT_COMMAND_GET_COMPACTION_PLAN_UPDATE", + 3: "RAFT_COMMAND_UPDATE_COMPACTION_PLAN", + 4: "RAFT_COMMAND_TRUNCATE_INDEX", + } + RaftCommand_value = map[string]int32{ + "RAFT_COMMAND_UNKNOWN": 0, + "RAFT_COMMAND_ADD_BLOCK_METADATA": 1, + "RAFT_COMMAND_GET_COMPACTION_PLAN_UPDATE": 2, + "RAFT_COMMAND_UPDATE_COMPACTION_PLAN": 3, + "RAFT_COMMAND_TRUNCATE_INDEX": 4, + } +) + +func (x RaftCommand) Enum() *RaftCommand { + p := new(RaftCommand) + *p = x + return p +} + +func (x RaftCommand) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RaftCommand) Descriptor() protoreflect.EnumDescriptor { + return file_metastore_v1_raft_log_raft_log_proto_enumTypes[0].Descriptor() +} + +func (RaftCommand) Type() protoreflect.EnumType { + return &file_metastore_v1_raft_log_raft_log_proto_enumTypes[0] +} + +func (x RaftCommand) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RaftCommand.Descriptor instead. +func (RaftCommand) EnumDescriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{0} +} + +type AddBlockMetadataRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Metadata *v1.BlockMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddBlockMetadataRequest) Reset() { + *x = AddBlockMetadataRequest{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddBlockMetadataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddBlockMetadataRequest) ProtoMessage() {} + +func (x *AddBlockMetadataRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddBlockMetadataRequest.ProtoReflect.Descriptor instead. +func (*AddBlockMetadataRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{0} +} + +func (x *AddBlockMetadataRequest) GetMetadata() *v1.BlockMeta { + if x != nil { + return x.Metadata + } + return nil +} + +type AddBlockMetadataResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddBlockMetadataResponse) Reset() { + *x = AddBlockMetadataResponse{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddBlockMetadataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddBlockMetadataResponse) ProtoMessage() {} + +func (x *AddBlockMetadataResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddBlockMetadataResponse.ProtoReflect.Descriptor instead. +func (*AddBlockMetadataResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{1} +} + +// GetCompactionPlanUpdateRequest requests CompactionPlanUpdate. +// The resulting plan should be proposed to the raft members. +// This is a read-only operation: it MUST NOT alter the state. +type GetCompactionPlanUpdateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // CompactionJobStatusUpdate is a change + // requested by the compaction worker. + StatusUpdates []*CompactionJobStatusUpdate `protobuf:"bytes,1,rep,name=status_updates,json=statusUpdates,proto3" json:"status_updates,omitempty"` + AssignJobsMax uint32 `protobuf:"varint,2,opt,name=assign_jobs_max,json=assignJobsMax,proto3" json:"assign_jobs_max,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetCompactionPlanUpdateRequest) Reset() { + *x = GetCompactionPlanUpdateRequest{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCompactionPlanUpdateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCompactionPlanUpdateRequest) ProtoMessage() {} + +func (x *GetCompactionPlanUpdateRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCompactionPlanUpdateRequest.ProtoReflect.Descriptor instead. +func (*GetCompactionPlanUpdateRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{2} +} + +func (x *GetCompactionPlanUpdateRequest) GetStatusUpdates() []*CompactionJobStatusUpdate { + if x != nil { + return x.StatusUpdates + } + return nil +} + +func (x *GetCompactionPlanUpdateRequest) GetAssignJobsMax() uint32 { + if x != nil { + return x.AssignJobsMax + } + return 0 +} + +type CompactionJobStatusUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Token uint64 `protobuf:"varint,2,opt,name=token,proto3" json:"token,omitempty"` + Status v1.CompactionJobStatus `protobuf:"varint,3,opt,name=status,proto3,enum=metastore.v1.CompactionJobStatus" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactionJobStatusUpdate) Reset() { + *x = CompactionJobStatusUpdate{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactionJobStatusUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactionJobStatusUpdate) ProtoMessage() {} + +func (x *CompactionJobStatusUpdate) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactionJobStatusUpdate.ProtoReflect.Descriptor instead. +func (*CompactionJobStatusUpdate) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{3} +} + +func (x *CompactionJobStatusUpdate) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CompactionJobStatusUpdate) GetToken() uint64 { + if x != nil { + return x.Token + } + return 0 +} + +func (x *CompactionJobStatusUpdate) GetStatus() v1.CompactionJobStatus { + if x != nil { + return x.Status + } + return v1.CompactionJobStatus(0) +} + +// GetCompactionPlanUpdateResponse includes the planned change. +// The plan should be proposed to the raft members. +type GetCompactionPlanUpdateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Term uint64 `protobuf:"varint,1,opt,name=term,proto3" json:"term,omitempty"` + PlanUpdate *CompactionPlanUpdate `protobuf:"bytes,2,opt,name=plan_update,json=planUpdate,proto3" json:"plan_update,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetCompactionPlanUpdateResponse) Reset() { + *x = GetCompactionPlanUpdateResponse{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCompactionPlanUpdateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCompactionPlanUpdateResponse) ProtoMessage() {} + +func (x *GetCompactionPlanUpdateResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCompactionPlanUpdateResponse.ProtoReflect.Descriptor instead. +func (*GetCompactionPlanUpdateResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{4} +} + +func (x *GetCompactionPlanUpdateResponse) GetTerm() uint64 { + if x != nil { + return x.Term + } + return 0 +} + +func (x *GetCompactionPlanUpdateResponse) GetPlanUpdate() *CompactionPlanUpdate { + if x != nil { + return x.PlanUpdate + } + return nil +} + +type CompactionPlanUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + NewJobs []*NewCompactionJob `protobuf:"bytes,1,rep,name=new_jobs,json=newJobs,proto3" json:"new_jobs,omitempty"` + AssignedJobs []*AssignedCompactionJob `protobuf:"bytes,2,rep,name=assigned_jobs,json=assignedJobs,proto3" json:"assigned_jobs,omitempty"` + UpdatedJobs []*UpdatedCompactionJob `protobuf:"bytes,3,rep,name=updated_jobs,json=updatedJobs,proto3" json:"updated_jobs,omitempty"` + CompletedJobs []*CompletedCompactionJob `protobuf:"bytes,4,rep,name=completed_jobs,json=completedJobs,proto3" json:"completed_jobs,omitempty"` + EvictedJobs []*EvictedCompactionJob `protobuf:"bytes,5,rep,name=evicted_jobs,json=evictedJobs,proto3" json:"evicted_jobs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactionPlanUpdate) Reset() { + *x = CompactionPlanUpdate{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactionPlanUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactionPlanUpdate) ProtoMessage() {} + +func (x *CompactionPlanUpdate) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactionPlanUpdate.ProtoReflect.Descriptor instead. +func (*CompactionPlanUpdate) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{5} +} + +func (x *CompactionPlanUpdate) GetNewJobs() []*NewCompactionJob { + if x != nil { + return x.NewJobs + } + return nil +} + +func (x *CompactionPlanUpdate) GetAssignedJobs() []*AssignedCompactionJob { + if x != nil { + return x.AssignedJobs + } + return nil +} + +func (x *CompactionPlanUpdate) GetUpdatedJobs() []*UpdatedCompactionJob { + if x != nil { + return x.UpdatedJobs + } + return nil +} + +func (x *CompactionPlanUpdate) GetCompletedJobs() []*CompletedCompactionJob { + if x != nil { + return x.CompletedJobs + } + return nil +} + +func (x *CompactionPlanUpdate) GetEvictedJobs() []*EvictedCompactionJob { + if x != nil { + return x.EvictedJobs + } + return nil +} + +type NewCompactionJob struct { + state protoimpl.MessageState `protogen:"open.v1"` + State *CompactionJobState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + Plan *CompactionJobPlan `protobuf:"bytes,2,opt,name=plan,proto3" json:"plan,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NewCompactionJob) Reset() { + *x = NewCompactionJob{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NewCompactionJob) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NewCompactionJob) ProtoMessage() {} + +func (x *NewCompactionJob) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NewCompactionJob.ProtoReflect.Descriptor instead. +func (*NewCompactionJob) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{6} +} + +func (x *NewCompactionJob) GetState() *CompactionJobState { + if x != nil { + return x.State + } + return nil +} + +func (x *NewCompactionJob) GetPlan() *CompactionJobPlan { + if x != nil { + return x.Plan + } + return nil +} + +type AssignedCompactionJob struct { + state protoimpl.MessageState `protogen:"open.v1"` + State *CompactionJobState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + Plan *CompactionJobPlan `protobuf:"bytes,2,opt,name=plan,proto3" json:"plan,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AssignedCompactionJob) Reset() { + *x = AssignedCompactionJob{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AssignedCompactionJob) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignedCompactionJob) ProtoMessage() {} + +func (x *AssignedCompactionJob) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignedCompactionJob.ProtoReflect.Descriptor instead. +func (*AssignedCompactionJob) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{7} +} + +func (x *AssignedCompactionJob) GetState() *CompactionJobState { + if x != nil { + return x.State + } + return nil +} + +func (x *AssignedCompactionJob) GetPlan() *CompactionJobPlan { + if x != nil { + return x.Plan + } + return nil +} + +type UpdatedCompactionJob struct { + state protoimpl.MessageState `protogen:"open.v1"` + State *CompactionJobState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdatedCompactionJob) Reset() { + *x = UpdatedCompactionJob{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdatedCompactionJob) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatedCompactionJob) ProtoMessage() {} + +func (x *UpdatedCompactionJob) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatedCompactionJob.ProtoReflect.Descriptor instead. +func (*UpdatedCompactionJob) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{8} +} + +func (x *UpdatedCompactionJob) GetState() *CompactionJobState { + if x != nil { + return x.State + } + return nil +} + +type CompletedCompactionJob struct { + state protoimpl.MessageState `protogen:"open.v1"` + State *CompactionJobState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + CompactedBlocks *v1.CompactedBlocks `protobuf:"bytes,2,opt,name=compacted_blocks,json=compactedBlocks,proto3" json:"compacted_blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompletedCompactionJob) Reset() { + *x = CompletedCompactionJob{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompletedCompactionJob) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompletedCompactionJob) ProtoMessage() {} + +func (x *CompletedCompactionJob) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompletedCompactionJob.ProtoReflect.Descriptor instead. +func (*CompletedCompactionJob) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{9} +} + +func (x *CompletedCompactionJob) GetState() *CompactionJobState { + if x != nil { + return x.State + } + return nil +} + +func (x *CompletedCompactionJob) GetCompactedBlocks() *v1.CompactedBlocks { + if x != nil { + return x.CompactedBlocks + } + return nil +} + +type EvictedCompactionJob struct { + state protoimpl.MessageState `protogen:"open.v1"` + State *CompactionJobState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EvictedCompactionJob) Reset() { + *x = EvictedCompactionJob{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EvictedCompactionJob) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EvictedCompactionJob) ProtoMessage() {} + +func (x *EvictedCompactionJob) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EvictedCompactionJob.ProtoReflect.Descriptor instead. +func (*EvictedCompactionJob) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{10} +} + +func (x *EvictedCompactionJob) GetState() *CompactionJobState { + if x != nil { + return x.State + } + return nil +} + +// CompactionJobState is produced in response to +// the compaction worker status update request. +// +// Compaction level and other attributes that +// affect the scheduling order or status update +// handling should be included into the message. +type CompactionJobState struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + CompactionLevel uint32 `protobuf:"varint,2,opt,name=compaction_level,json=compactionLevel,proto3" json:"compaction_level,omitempty"` + Status v1.CompactionJobStatus `protobuf:"varint,3,opt,name=status,proto3,enum=metastore.v1.CompactionJobStatus" json:"status,omitempty"` + Token uint64 `protobuf:"varint,4,opt,name=token,proto3" json:"token,omitempty"` + LeaseExpiresAt int64 `protobuf:"varint,5,opt,name=lease_expires_at,json=leaseExpiresAt,proto3" json:"lease_expires_at,omitempty"` + AddedAt int64 `protobuf:"varint,6,opt,name=added_at,json=addedAt,proto3" json:"added_at,omitempty"` + Failures uint32 `protobuf:"varint,7,opt,name=failures,proto3" json:"failures,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactionJobState) Reset() { + *x = CompactionJobState{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactionJobState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactionJobState) ProtoMessage() {} + +func (x *CompactionJobState) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactionJobState.ProtoReflect.Descriptor instead. +func (*CompactionJobState) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{11} +} + +func (x *CompactionJobState) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CompactionJobState) GetCompactionLevel() uint32 { + if x != nil { + return x.CompactionLevel + } + return 0 +} + +func (x *CompactionJobState) GetStatus() v1.CompactionJobStatus { + if x != nil { + return x.Status + } + return v1.CompactionJobStatus(0) +} + +func (x *CompactionJobState) GetToken() uint64 { + if x != nil { + return x.Token + } + return 0 +} + +func (x *CompactionJobState) GetLeaseExpiresAt() int64 { + if x != nil { + return x.LeaseExpiresAt + } + return 0 +} + +func (x *CompactionJobState) GetAddedAt() int64 { + if x != nil { + return x.AddedAt + } + return 0 +} + +func (x *CompactionJobState) GetFailures() uint32 { + if x != nil { + return x.Failures + } + return 0 +} + +type CompactionJobPlan struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Blocks to be compacted. + Tenant string `protobuf:"bytes,2,opt,name=tenant,proto3" json:"tenant,omitempty"` + Shard uint32 `protobuf:"varint,3,opt,name=shard,proto3" json:"shard,omitempty"` + CompactionLevel uint32 `protobuf:"varint,4,opt,name=compaction_level,json=compactionLevel,proto3" json:"compaction_level,omitempty"` + SourceBlocks []string `protobuf:"bytes,5,rep,name=source_blocks,json=sourceBlocks,proto3" json:"source_blocks,omitempty"` + // Objects to be deleted. + Tombstones []*v1.Tombstones `protobuf:"bytes,6,rep,name=tombstones,proto3" json:"tombstones,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactionJobPlan) Reset() { + *x = CompactionJobPlan{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactionJobPlan) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactionJobPlan) ProtoMessage() {} + +func (x *CompactionJobPlan) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactionJobPlan.ProtoReflect.Descriptor instead. +func (*CompactionJobPlan) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{12} +} + +func (x *CompactionJobPlan) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CompactionJobPlan) GetTenant() string { + if x != nil { + return x.Tenant + } + return "" +} + +func (x *CompactionJobPlan) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *CompactionJobPlan) GetCompactionLevel() uint32 { + if x != nil { + return x.CompactionLevel + } + return 0 +} + +func (x *CompactionJobPlan) GetSourceBlocks() []string { + if x != nil { + return x.SourceBlocks + } + return nil +} + +func (x *CompactionJobPlan) GetTombstones() []*v1.Tombstones { + if x != nil { + return x.Tombstones + } + return nil +} + +// UpdateCompactionPlanRequest proposes compaction plan changes. +type UpdateCompactionPlanRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Term uint64 `protobuf:"varint,1,opt,name=term,proto3" json:"term,omitempty"` + PlanUpdate *CompactionPlanUpdate `protobuf:"bytes,2,opt,name=plan_update,json=planUpdate,proto3" json:"plan_update,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateCompactionPlanRequest) Reset() { + *x = UpdateCompactionPlanRequest{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateCompactionPlanRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateCompactionPlanRequest) ProtoMessage() {} + +func (x *UpdateCompactionPlanRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateCompactionPlanRequest.ProtoReflect.Descriptor instead. +func (*UpdateCompactionPlanRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{13} +} + +func (x *UpdateCompactionPlanRequest) GetTerm() uint64 { + if x != nil { + return x.Term + } + return 0 +} + +func (x *UpdateCompactionPlanRequest) GetPlanUpdate() *CompactionPlanUpdate { + if x != nil { + return x.PlanUpdate + } + return nil +} + +type UpdateCompactionPlanResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + PlanUpdate *CompactionPlanUpdate `protobuf:"bytes,1,opt,name=plan_update,json=planUpdate,proto3" json:"plan_update,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateCompactionPlanResponse) Reset() { + *x = UpdateCompactionPlanResponse{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateCompactionPlanResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateCompactionPlanResponse) ProtoMessage() {} + +func (x *UpdateCompactionPlanResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateCompactionPlanResponse.ProtoReflect.Descriptor instead. +func (*UpdateCompactionPlanResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{14} +} + +func (x *UpdateCompactionPlanResponse) GetPlanUpdate() *CompactionPlanUpdate { + if x != nil { + return x.PlanUpdate + } + return nil +} + +type TruncateIndexRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Term uint64 `protobuf:"varint,1,opt,name=term,proto3" json:"term,omitempty"` + Tombstones []*v1.Tombstones `protobuf:"bytes,2,rep,name=tombstones,proto3" json:"tombstones,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TruncateIndexRequest) Reset() { + *x = TruncateIndexRequest{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TruncateIndexRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TruncateIndexRequest) ProtoMessage() {} + +func (x *TruncateIndexRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TruncateIndexRequest.ProtoReflect.Descriptor instead. +func (*TruncateIndexRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{15} +} + +func (x *TruncateIndexRequest) GetTerm() uint64 { + if x != nil { + return x.Term + } + return 0 +} + +func (x *TruncateIndexRequest) GetTombstones() []*v1.Tombstones { + if x != nil { + return x.Tombstones + } + return nil +} + +type TruncateIndexResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TruncateIndexResponse) Reset() { + *x = TruncateIndexResponse{} + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TruncateIndexResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TruncateIndexResponse) ProtoMessage() {} + +func (x *TruncateIndexResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_raft_log_raft_log_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TruncateIndexResponse.ProtoReflect.Descriptor instead. +func (*TruncateIndexResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP(), []int{16} +} + +var File_metastore_v1_raft_log_raft_log_proto protoreflect.FileDescriptor + +const file_metastore_v1_raft_log_raft_log_proto_rawDesc = "" + + "\n" + + "$metastore/v1/raft_log/raft_log.proto\x12\braft_log\x1a\x1cmetastore/v1/compactor.proto\x1a\x18metastore/v1/types.proto\"N\n" + + "\x17AddBlockMetadataRequest\x123\n" + + "\bmetadata\x18\x01 \x01(\v2\x17.metastore.v1.BlockMetaR\bmetadata\"\x1a\n" + + "\x18AddBlockMetadataResponse\"\x94\x01\n" + + "\x1eGetCompactionPlanUpdateRequest\x12J\n" + + "\x0estatus_updates\x18\x01 \x03(\v2#.raft_log.CompactionJobStatusUpdateR\rstatusUpdates\x12&\n" + + "\x0fassign_jobs_max\x18\x02 \x01(\rR\rassignJobsMax\"\x80\x01\n" + + "\x19CompactionJobStatusUpdate\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05token\x18\x02 \x01(\x04R\x05token\x129\n" + + "\x06status\x18\x03 \x01(\x0e2!.metastore.v1.CompactionJobStatusR\x06status\"v\n" + + "\x1fGetCompactionPlanUpdateResponse\x12\x12\n" + + "\x04term\x18\x01 \x01(\x04R\x04term\x12?\n" + + "\vplan_update\x18\x02 \x01(\v2\x1e.raft_log.CompactionPlanUpdateR\n" + + "planUpdate\"\xe2\x02\n" + + "\x14CompactionPlanUpdate\x125\n" + + "\bnew_jobs\x18\x01 \x03(\v2\x1a.raft_log.NewCompactionJobR\anewJobs\x12D\n" + + "\rassigned_jobs\x18\x02 \x03(\v2\x1f.raft_log.AssignedCompactionJobR\fassignedJobs\x12A\n" + + "\fupdated_jobs\x18\x03 \x03(\v2\x1e.raft_log.UpdatedCompactionJobR\vupdatedJobs\x12G\n" + + "\x0ecompleted_jobs\x18\x04 \x03(\v2 .raft_log.CompletedCompactionJobR\rcompletedJobs\x12A\n" + + "\fevicted_jobs\x18\x05 \x03(\v2\x1e.raft_log.EvictedCompactionJobR\vevictedJobs\"w\n" + + "\x10NewCompactionJob\x122\n" + + "\x05state\x18\x01 \x01(\v2\x1c.raft_log.CompactionJobStateR\x05state\x12/\n" + + "\x04plan\x18\x02 \x01(\v2\x1b.raft_log.CompactionJobPlanR\x04plan\"|\n" + + "\x15AssignedCompactionJob\x122\n" + + "\x05state\x18\x01 \x01(\v2\x1c.raft_log.CompactionJobStateR\x05state\x12/\n" + + "\x04plan\x18\x02 \x01(\v2\x1b.raft_log.CompactionJobPlanR\x04plan\"J\n" + + "\x14UpdatedCompactionJob\x122\n" + + "\x05state\x18\x01 \x01(\v2\x1c.raft_log.CompactionJobStateR\x05state\"\x96\x01\n" + + "\x16CompletedCompactionJob\x122\n" + + "\x05state\x18\x01 \x01(\v2\x1c.raft_log.CompactionJobStateR\x05state\x12H\n" + + "\x10compacted_blocks\x18\x02 \x01(\v2\x1d.metastore.v1.CompactedBlocksR\x0fcompactedBlocks\"J\n" + + "\x14EvictedCompactionJob\x122\n" + + "\x05state\x18\x01 \x01(\v2\x1c.raft_log.CompactionJobStateR\x05state\"\x85\x02\n" + + "\x12CompactionJobState\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12)\n" + + "\x10compaction_level\x18\x02 \x01(\rR\x0fcompactionLevel\x129\n" + + "\x06status\x18\x03 \x01(\x0e2!.metastore.v1.CompactionJobStatusR\x06status\x12\x14\n" + + "\x05token\x18\x04 \x01(\x04R\x05token\x12(\n" + + "\x10lease_expires_at\x18\x05 \x01(\x03R\x0eleaseExpiresAt\x12\x19\n" + + "\badded_at\x18\x06 \x01(\x03R\aaddedAt\x12\x1a\n" + + "\bfailures\x18\a \x01(\rR\bfailures\"\xdf\x01\n" + + "\x11CompactionJobPlan\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" + + "\x06tenant\x18\x02 \x01(\tR\x06tenant\x12\x14\n" + + "\x05shard\x18\x03 \x01(\rR\x05shard\x12)\n" + + "\x10compaction_level\x18\x04 \x01(\rR\x0fcompactionLevel\x12#\n" + + "\rsource_blocks\x18\x05 \x03(\tR\fsourceBlocks\x128\n" + + "\n" + + "tombstones\x18\x06 \x03(\v2\x18.metastore.v1.TombstonesR\n" + + "tombstones\"r\n" + + "\x1bUpdateCompactionPlanRequest\x12\x12\n" + + "\x04term\x18\x01 \x01(\x04R\x04term\x12?\n" + + "\vplan_update\x18\x02 \x01(\v2\x1e.raft_log.CompactionPlanUpdateR\n" + + "planUpdate\"_\n" + + "\x1cUpdateCompactionPlanResponse\x12?\n" + + "\vplan_update\x18\x01 \x01(\v2\x1e.raft_log.CompactionPlanUpdateR\n" + + "planUpdate\"d\n" + + "\x14TruncateIndexRequest\x12\x12\n" + + "\x04term\x18\x01 \x01(\x04R\x04term\x128\n" + + "\n" + + "tombstones\x18\x02 \x03(\v2\x18.metastore.v1.TombstonesR\n" + + "tombstones\"\x17\n" + + "\x15TruncateIndexResponse*\xc3\x01\n" + + "\vRaftCommand\x12\x18\n" + + "\x14RAFT_COMMAND_UNKNOWN\x10\x00\x12#\n" + + "\x1fRAFT_COMMAND_ADD_BLOCK_METADATA\x10\x01\x12+\n" + + "'RAFT_COMMAND_GET_COMPACTION_PLAN_UPDATE\x10\x02\x12'\n" + + "#RAFT_COMMAND_UPDATE_COMPACTION_PLAN\x10\x03\x12\x1f\n" + + "\x1bRAFT_COMMAND_TRUNCATE_INDEX\x10\x04B\x9d\x01\n" + + "\fcom.raft_logB\fRaftLogProtoP\x01ZCgithub.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log\xa2\x02\x03RXX\xaa\x02\aRaftLog\xca\x02\aRaftLog\xe2\x02\x13RaftLog\\GPBMetadata\xea\x02\aRaftLogb\x06proto3" + +var ( + file_metastore_v1_raft_log_raft_log_proto_rawDescOnce sync.Once + file_metastore_v1_raft_log_raft_log_proto_rawDescData []byte +) + +func file_metastore_v1_raft_log_raft_log_proto_rawDescGZIP() []byte { + file_metastore_v1_raft_log_raft_log_proto_rawDescOnce.Do(func() { + file_metastore_v1_raft_log_raft_log_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_metastore_v1_raft_log_raft_log_proto_rawDesc), len(file_metastore_v1_raft_log_raft_log_proto_rawDesc))) + }) + return file_metastore_v1_raft_log_raft_log_proto_rawDescData +} + +var file_metastore_v1_raft_log_raft_log_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_metastore_v1_raft_log_raft_log_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_metastore_v1_raft_log_raft_log_proto_goTypes = []any{ + (RaftCommand)(0), // 0: raft_log.RaftCommand + (*AddBlockMetadataRequest)(nil), // 1: raft_log.AddBlockMetadataRequest + (*AddBlockMetadataResponse)(nil), // 2: raft_log.AddBlockMetadataResponse + (*GetCompactionPlanUpdateRequest)(nil), // 3: raft_log.GetCompactionPlanUpdateRequest + (*CompactionJobStatusUpdate)(nil), // 4: raft_log.CompactionJobStatusUpdate + (*GetCompactionPlanUpdateResponse)(nil), // 5: raft_log.GetCompactionPlanUpdateResponse + (*CompactionPlanUpdate)(nil), // 6: raft_log.CompactionPlanUpdate + (*NewCompactionJob)(nil), // 7: raft_log.NewCompactionJob + (*AssignedCompactionJob)(nil), // 8: raft_log.AssignedCompactionJob + (*UpdatedCompactionJob)(nil), // 9: raft_log.UpdatedCompactionJob + (*CompletedCompactionJob)(nil), // 10: raft_log.CompletedCompactionJob + (*EvictedCompactionJob)(nil), // 11: raft_log.EvictedCompactionJob + (*CompactionJobState)(nil), // 12: raft_log.CompactionJobState + (*CompactionJobPlan)(nil), // 13: raft_log.CompactionJobPlan + (*UpdateCompactionPlanRequest)(nil), // 14: raft_log.UpdateCompactionPlanRequest + (*UpdateCompactionPlanResponse)(nil), // 15: raft_log.UpdateCompactionPlanResponse + (*TruncateIndexRequest)(nil), // 16: raft_log.TruncateIndexRequest + (*TruncateIndexResponse)(nil), // 17: raft_log.TruncateIndexResponse + (*v1.BlockMeta)(nil), // 18: metastore.v1.BlockMeta + (v1.CompactionJobStatus)(0), // 19: metastore.v1.CompactionJobStatus + (*v1.CompactedBlocks)(nil), // 20: metastore.v1.CompactedBlocks + (*v1.Tombstones)(nil), // 21: metastore.v1.Tombstones +} +var file_metastore_v1_raft_log_raft_log_proto_depIdxs = []int32{ + 18, // 0: raft_log.AddBlockMetadataRequest.metadata:type_name -> metastore.v1.BlockMeta + 4, // 1: raft_log.GetCompactionPlanUpdateRequest.status_updates:type_name -> raft_log.CompactionJobStatusUpdate + 19, // 2: raft_log.CompactionJobStatusUpdate.status:type_name -> metastore.v1.CompactionJobStatus + 6, // 3: raft_log.GetCompactionPlanUpdateResponse.plan_update:type_name -> raft_log.CompactionPlanUpdate + 7, // 4: raft_log.CompactionPlanUpdate.new_jobs:type_name -> raft_log.NewCompactionJob + 8, // 5: raft_log.CompactionPlanUpdate.assigned_jobs:type_name -> raft_log.AssignedCompactionJob + 9, // 6: raft_log.CompactionPlanUpdate.updated_jobs:type_name -> raft_log.UpdatedCompactionJob + 10, // 7: raft_log.CompactionPlanUpdate.completed_jobs:type_name -> raft_log.CompletedCompactionJob + 11, // 8: raft_log.CompactionPlanUpdate.evicted_jobs:type_name -> raft_log.EvictedCompactionJob + 12, // 9: raft_log.NewCompactionJob.state:type_name -> raft_log.CompactionJobState + 13, // 10: raft_log.NewCompactionJob.plan:type_name -> raft_log.CompactionJobPlan + 12, // 11: raft_log.AssignedCompactionJob.state:type_name -> raft_log.CompactionJobState + 13, // 12: raft_log.AssignedCompactionJob.plan:type_name -> raft_log.CompactionJobPlan + 12, // 13: raft_log.UpdatedCompactionJob.state:type_name -> raft_log.CompactionJobState + 12, // 14: raft_log.CompletedCompactionJob.state:type_name -> raft_log.CompactionJobState + 20, // 15: raft_log.CompletedCompactionJob.compacted_blocks:type_name -> metastore.v1.CompactedBlocks + 12, // 16: raft_log.EvictedCompactionJob.state:type_name -> raft_log.CompactionJobState + 19, // 17: raft_log.CompactionJobState.status:type_name -> metastore.v1.CompactionJobStatus + 21, // 18: raft_log.CompactionJobPlan.tombstones:type_name -> metastore.v1.Tombstones + 6, // 19: raft_log.UpdateCompactionPlanRequest.plan_update:type_name -> raft_log.CompactionPlanUpdate + 6, // 20: raft_log.UpdateCompactionPlanResponse.plan_update:type_name -> raft_log.CompactionPlanUpdate + 21, // 21: raft_log.TruncateIndexRequest.tombstones:type_name -> metastore.v1.Tombstones + 22, // [22:22] is the sub-list for method output_type + 22, // [22:22] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name +} + +func init() { file_metastore_v1_raft_log_raft_log_proto_init() } +func file_metastore_v1_raft_log_raft_log_proto_init() { + if File_metastore_v1_raft_log_raft_log_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_metastore_v1_raft_log_raft_log_proto_rawDesc), len(file_metastore_v1_raft_log_raft_log_proto_rawDesc)), + NumEnums: 1, + NumMessages: 17, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_metastore_v1_raft_log_raft_log_proto_goTypes, + DependencyIndexes: file_metastore_v1_raft_log_raft_log_proto_depIdxs, + EnumInfos: file_metastore_v1_raft_log_raft_log_proto_enumTypes, + MessageInfos: file_metastore_v1_raft_log_raft_log_proto_msgTypes, + }.Build() + File_metastore_v1_raft_log_raft_log_proto = out.File + file_metastore_v1_raft_log_raft_log_proto_goTypes = nil + file_metastore_v1_raft_log_raft_log_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/metastore/v1/raft_log/raft_log_vtproto.pb.go b/api/gen/proto/go/metastore/v1/raft_log/raft_log_vtproto.pb.go new file mode 100644 index 0000000000..c7780beaee --- /dev/null +++ b/api/gen/proto/go/metastore/v1/raft_log/raft_log_vtproto.pb.go @@ -0,0 +1,4245 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: metastore/v1/raft_log/raft_log.proto + +package raft_log + +import ( + fmt "fmt" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *AddBlockMetadataRequest) CloneVT() *AddBlockMetadataRequest { + if m == nil { + return (*AddBlockMetadataRequest)(nil) + } + r := new(AddBlockMetadataRequest) + if rhs := m.Metadata; rhs != nil { + if vtpb, ok := interface{}(rhs).(interface{ CloneVT() *v1.BlockMeta }); ok { + r.Metadata = vtpb.CloneVT() + } else { + r.Metadata = proto.Clone(rhs).(*v1.BlockMeta) + } + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AddBlockMetadataRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *AddBlockMetadataResponse) CloneVT() *AddBlockMetadataResponse { + if m == nil { + return (*AddBlockMetadataResponse)(nil) + } + r := new(AddBlockMetadataResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AddBlockMetadataResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetCompactionPlanUpdateRequest) CloneVT() *GetCompactionPlanUpdateRequest { + if m == nil { + return (*GetCompactionPlanUpdateRequest)(nil) + } + r := new(GetCompactionPlanUpdateRequest) + r.AssignJobsMax = m.AssignJobsMax + if rhs := m.StatusUpdates; rhs != nil { + tmpContainer := make([]*CompactionJobStatusUpdate, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.StatusUpdates = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetCompactionPlanUpdateRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactionJobStatusUpdate) CloneVT() *CompactionJobStatusUpdate { + if m == nil { + return (*CompactionJobStatusUpdate)(nil) + } + r := new(CompactionJobStatusUpdate) + r.Name = m.Name + r.Token = m.Token + r.Status = m.Status + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactionJobStatusUpdate) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetCompactionPlanUpdateResponse) CloneVT() *GetCompactionPlanUpdateResponse { + if m == nil { + return (*GetCompactionPlanUpdateResponse)(nil) + } + r := new(GetCompactionPlanUpdateResponse) + r.Term = m.Term + r.PlanUpdate = m.PlanUpdate.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetCompactionPlanUpdateResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactionPlanUpdate) CloneVT() *CompactionPlanUpdate { + if m == nil { + return (*CompactionPlanUpdate)(nil) + } + r := new(CompactionPlanUpdate) + if rhs := m.NewJobs; rhs != nil { + tmpContainer := make([]*NewCompactionJob, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.NewJobs = tmpContainer + } + if rhs := m.AssignedJobs; rhs != nil { + tmpContainer := make([]*AssignedCompactionJob, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.AssignedJobs = tmpContainer + } + if rhs := m.UpdatedJobs; rhs != nil { + tmpContainer := make([]*UpdatedCompactionJob, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.UpdatedJobs = tmpContainer + } + if rhs := m.CompletedJobs; rhs != nil { + tmpContainer := make([]*CompletedCompactionJob, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.CompletedJobs = tmpContainer + } + if rhs := m.EvictedJobs; rhs != nil { + tmpContainer := make([]*EvictedCompactionJob, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.EvictedJobs = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactionPlanUpdate) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *NewCompactionJob) CloneVT() *NewCompactionJob { + if m == nil { + return (*NewCompactionJob)(nil) + } + r := new(NewCompactionJob) + r.State = m.State.CloneVT() + r.Plan = m.Plan.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *NewCompactionJob) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *AssignedCompactionJob) CloneVT() *AssignedCompactionJob { + if m == nil { + return (*AssignedCompactionJob)(nil) + } + r := new(AssignedCompactionJob) + r.State = m.State.CloneVT() + r.Plan = m.Plan.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AssignedCompactionJob) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *UpdatedCompactionJob) CloneVT() *UpdatedCompactionJob { + if m == nil { + return (*UpdatedCompactionJob)(nil) + } + r := new(UpdatedCompactionJob) + r.State = m.State.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *UpdatedCompactionJob) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompletedCompactionJob) CloneVT() *CompletedCompactionJob { + if m == nil { + return (*CompletedCompactionJob)(nil) + } + r := new(CompletedCompactionJob) + r.State = m.State.CloneVT() + if rhs := m.CompactedBlocks; rhs != nil { + if vtpb, ok := interface{}(rhs).(interface{ CloneVT() *v1.CompactedBlocks }); ok { + r.CompactedBlocks = vtpb.CloneVT() + } else { + r.CompactedBlocks = proto.Clone(rhs).(*v1.CompactedBlocks) + } + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompletedCompactionJob) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *EvictedCompactionJob) CloneVT() *EvictedCompactionJob { + if m == nil { + return (*EvictedCompactionJob)(nil) + } + r := new(EvictedCompactionJob) + r.State = m.State.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *EvictedCompactionJob) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactionJobState) CloneVT() *CompactionJobState { + if m == nil { + return (*CompactionJobState)(nil) + } + r := new(CompactionJobState) + r.Name = m.Name + r.CompactionLevel = m.CompactionLevel + r.Status = m.Status + r.Token = m.Token + r.LeaseExpiresAt = m.LeaseExpiresAt + r.AddedAt = m.AddedAt + r.Failures = m.Failures + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactionJobState) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *CompactionJobPlan) CloneVT() *CompactionJobPlan { + if m == nil { + return (*CompactionJobPlan)(nil) + } + r := new(CompactionJobPlan) + r.Name = m.Name + r.Tenant = m.Tenant + r.Shard = m.Shard + r.CompactionLevel = m.CompactionLevel + if rhs := m.SourceBlocks; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.SourceBlocks = tmpContainer + } + if rhs := m.Tombstones; rhs != nil { + tmpContainer := make([]*v1.Tombstones, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.Tombstones }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.Tombstones) + } + } + r.Tombstones = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CompactionJobPlan) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *UpdateCompactionPlanRequest) CloneVT() *UpdateCompactionPlanRequest { + if m == nil { + return (*UpdateCompactionPlanRequest)(nil) + } + r := new(UpdateCompactionPlanRequest) + r.Term = m.Term + r.PlanUpdate = m.PlanUpdate.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *UpdateCompactionPlanRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *UpdateCompactionPlanResponse) CloneVT() *UpdateCompactionPlanResponse { + if m == nil { + return (*UpdateCompactionPlanResponse)(nil) + } + r := new(UpdateCompactionPlanResponse) + r.PlanUpdate = m.PlanUpdate.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *UpdateCompactionPlanResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TruncateIndexRequest) CloneVT() *TruncateIndexRequest { + if m == nil { + return (*TruncateIndexRequest)(nil) + } + r := new(TruncateIndexRequest) + r.Term = m.Term + if rhs := m.Tombstones; rhs != nil { + tmpContainer := make([]*v1.Tombstones, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.Tombstones }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.Tombstones) + } + } + r.Tombstones = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TruncateIndexRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TruncateIndexResponse) CloneVT() *TruncateIndexResponse { + if m == nil { + return (*TruncateIndexResponse)(nil) + } + r := new(TruncateIndexResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TruncateIndexResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *AddBlockMetadataRequest) EqualVT(that *AddBlockMetadataRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if equal, ok := interface{}(this.Metadata).(interface{ EqualVT(*v1.BlockMeta) bool }); ok { + if !equal.EqualVT(that.Metadata) { + return false + } + } else if !proto.Equal(this.Metadata, that.Metadata) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AddBlockMetadataRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AddBlockMetadataRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AddBlockMetadataResponse) EqualVT(that *AddBlockMetadataResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AddBlockMetadataResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AddBlockMetadataResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetCompactionPlanUpdateRequest) EqualVT(that *GetCompactionPlanUpdateRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.StatusUpdates) != len(that.StatusUpdates) { + return false + } + for i, vx := range this.StatusUpdates { + vy := that.StatusUpdates[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &CompactionJobStatusUpdate{} + } + if q == nil { + q = &CompactionJobStatusUpdate{} + } + if !p.EqualVT(q) { + return false + } + } + } + if this.AssignJobsMax != that.AssignJobsMax { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetCompactionPlanUpdateRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetCompactionPlanUpdateRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactionJobStatusUpdate) EqualVT(that *CompactionJobStatusUpdate) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Token != that.Token { + return false + } + if this.Status != that.Status { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactionJobStatusUpdate) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactionJobStatusUpdate) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetCompactionPlanUpdateResponse) EqualVT(that *GetCompactionPlanUpdateResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Term != that.Term { + return false + } + if !this.PlanUpdate.EqualVT(that.PlanUpdate) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetCompactionPlanUpdateResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetCompactionPlanUpdateResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactionPlanUpdate) EqualVT(that *CompactionPlanUpdate) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.NewJobs) != len(that.NewJobs) { + return false + } + for i, vx := range this.NewJobs { + vy := that.NewJobs[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &NewCompactionJob{} + } + if q == nil { + q = &NewCompactionJob{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.AssignedJobs) != len(that.AssignedJobs) { + return false + } + for i, vx := range this.AssignedJobs { + vy := that.AssignedJobs[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &AssignedCompactionJob{} + } + if q == nil { + q = &AssignedCompactionJob{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.UpdatedJobs) != len(that.UpdatedJobs) { + return false + } + for i, vx := range this.UpdatedJobs { + vy := that.UpdatedJobs[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &UpdatedCompactionJob{} + } + if q == nil { + q = &UpdatedCompactionJob{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.CompletedJobs) != len(that.CompletedJobs) { + return false + } + for i, vx := range this.CompletedJobs { + vy := that.CompletedJobs[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &CompletedCompactionJob{} + } + if q == nil { + q = &CompletedCompactionJob{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.EvictedJobs) != len(that.EvictedJobs) { + return false + } + for i, vx := range this.EvictedJobs { + vy := that.EvictedJobs[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &EvictedCompactionJob{} + } + if q == nil { + q = &EvictedCompactionJob{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactionPlanUpdate) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactionPlanUpdate) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *NewCompactionJob) EqualVT(that *NewCompactionJob) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.State.EqualVT(that.State) { + return false + } + if !this.Plan.EqualVT(that.Plan) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *NewCompactionJob) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*NewCompactionJob) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AssignedCompactionJob) EqualVT(that *AssignedCompactionJob) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.State.EqualVT(that.State) { + return false + } + if !this.Plan.EqualVT(that.Plan) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AssignedCompactionJob) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AssignedCompactionJob) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *UpdatedCompactionJob) EqualVT(that *UpdatedCompactionJob) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.State.EqualVT(that.State) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *UpdatedCompactionJob) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*UpdatedCompactionJob) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompletedCompactionJob) EqualVT(that *CompletedCompactionJob) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.State.EqualVT(that.State) { + return false + } + if equal, ok := interface{}(this.CompactedBlocks).(interface { + EqualVT(*v1.CompactedBlocks) bool + }); ok { + if !equal.EqualVT(that.CompactedBlocks) { + return false + } + } else if !proto.Equal(this.CompactedBlocks, that.CompactedBlocks) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompletedCompactionJob) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompletedCompactionJob) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *EvictedCompactionJob) EqualVT(that *EvictedCompactionJob) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.State.EqualVT(that.State) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *EvictedCompactionJob) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*EvictedCompactionJob) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactionJobState) EqualVT(that *CompactionJobState) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.CompactionLevel != that.CompactionLevel { + return false + } + if this.Status != that.Status { + return false + } + if this.Token != that.Token { + return false + } + if this.LeaseExpiresAt != that.LeaseExpiresAt { + return false + } + if this.AddedAt != that.AddedAt { + return false + } + if this.Failures != that.Failures { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactionJobState) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactionJobState) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *CompactionJobPlan) EqualVT(that *CompactionJobPlan) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + if this.Tenant != that.Tenant { + return false + } + if this.Shard != that.Shard { + return false + } + if this.CompactionLevel != that.CompactionLevel { + return false + } + if len(this.SourceBlocks) != len(that.SourceBlocks) { + return false + } + for i, vx := range this.SourceBlocks { + vy := that.SourceBlocks[i] + if vx != vy { + return false + } + } + if len(this.Tombstones) != len(that.Tombstones) { + return false + } + for i, vx := range this.Tombstones { + vy := that.Tombstones[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.Tombstones{} + } + if q == nil { + q = &v1.Tombstones{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.Tombstones) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CompactionJobPlan) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CompactionJobPlan) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *UpdateCompactionPlanRequest) EqualVT(that *UpdateCompactionPlanRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Term != that.Term { + return false + } + if !this.PlanUpdate.EqualVT(that.PlanUpdate) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *UpdateCompactionPlanRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*UpdateCompactionPlanRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *UpdateCompactionPlanResponse) EqualVT(that *UpdateCompactionPlanResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.PlanUpdate.EqualVT(that.PlanUpdate) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *UpdateCompactionPlanResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*UpdateCompactionPlanResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TruncateIndexRequest) EqualVT(that *TruncateIndexRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Term != that.Term { + return false + } + if len(this.Tombstones) != len(that.Tombstones) { + return false + } + for i, vx := range this.Tombstones { + vy := that.Tombstones[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.Tombstones{} + } + if q == nil { + q = &v1.Tombstones{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.Tombstones) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TruncateIndexRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TruncateIndexRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TruncateIndexResponse) EqualVT(that *TruncateIndexResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TruncateIndexResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TruncateIndexResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (m *AddBlockMetadataRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddBlockMetadataRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AddBlockMetadataRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Metadata != nil { + if vtmsg, ok := interface{}(m.Metadata).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Metadata) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddBlockMetadataResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddBlockMetadataResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AddBlockMetadataResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *GetCompactionPlanUpdateRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetCompactionPlanUpdateRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetCompactionPlanUpdateRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.AssignJobsMax != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.AssignJobsMax)) + i-- + dAtA[i] = 0x10 + } + if len(m.StatusUpdates) > 0 { + for iNdEx := len(m.StatusUpdates) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.StatusUpdates[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *CompactionJobStatusUpdate) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactionJobStatusUpdate) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactionJobStatusUpdate) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Status != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x18 + } + if m.Token != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Token)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetCompactionPlanUpdateResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetCompactionPlanUpdateResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetCompactionPlanUpdateResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.PlanUpdate != nil { + size, err := m.PlanUpdate.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.Term != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Term)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *CompactionPlanUpdate) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactionPlanUpdate) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactionPlanUpdate) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.EvictedJobs) > 0 { + for iNdEx := len(m.EvictedJobs) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.EvictedJobs[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + } + if len(m.CompletedJobs) > 0 { + for iNdEx := len(m.CompletedJobs) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.CompletedJobs[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + } + if len(m.UpdatedJobs) > 0 { + for iNdEx := len(m.UpdatedJobs) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.UpdatedJobs[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + } + if len(m.AssignedJobs) > 0 { + for iNdEx := len(m.AssignedJobs) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.AssignedJobs[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.NewJobs) > 0 { + for iNdEx := len(m.NewJobs) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.NewJobs[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *NewCompactionJob) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NewCompactionJob) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *NewCompactionJob) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Plan != nil { + size, err := m.Plan.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.State != nil { + size, err := m.State.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AssignedCompactionJob) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AssignedCompactionJob) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AssignedCompactionJob) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Plan != nil { + size, err := m.Plan.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.State != nil { + size, err := m.State.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UpdatedCompactionJob) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpdatedCompactionJob) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *UpdatedCompactionJob) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.State != nil { + size, err := m.State.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompletedCompactionJob) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompletedCompactionJob) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompletedCompactionJob) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CompactedBlocks != nil { + if vtmsg, ok := interface{}(m.CompactedBlocks).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.CompactedBlocks) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + if m.State != nil { + size, err := m.State.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EvictedCompactionJob) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EvictedCompactionJob) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *EvictedCompactionJob) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.State != nil { + size, err := m.State.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompactionJobState) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactionJobState) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactionJobState) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Failures != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Failures)) + i-- + dAtA[i] = 0x38 + } + if m.AddedAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.AddedAt)) + i-- + dAtA[i] = 0x30 + } + if m.LeaseExpiresAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.LeaseExpiresAt)) + i-- + dAtA[i] = 0x28 + } + if m.Token != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Token)) + i-- + dAtA[i] = 0x20 + } + if m.Status != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x18 + } + if m.CompactionLevel != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CompactionJobPlan) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CompactionJobPlan) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CompactionJobPlan) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Tombstones) > 0 { + for iNdEx := len(m.Tombstones) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Tombstones[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Tombstones[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.SourceBlocks) > 0 { + for iNdEx := len(m.SourceBlocks) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SourceBlocks[iNdEx]) + copy(dAtA[i:], m.SourceBlocks[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SourceBlocks[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if m.CompactionLevel != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x20 + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x18 + } + if len(m.Tenant) > 0 { + i -= len(m.Tenant) + copy(dAtA[i:], m.Tenant) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tenant))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UpdateCompactionPlanRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpdateCompactionPlanRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *UpdateCompactionPlanRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.PlanUpdate != nil { + size, err := m.PlanUpdate.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.Term != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Term)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *UpdateCompactionPlanResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpdateCompactionPlanResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *UpdateCompactionPlanResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.PlanUpdate != nil { + size, err := m.PlanUpdate.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TruncateIndexRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TruncateIndexRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TruncateIndexRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Tombstones) > 0 { + for iNdEx := len(m.Tombstones) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Tombstones[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Tombstones[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Term != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Term)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TruncateIndexResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TruncateIndexResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TruncateIndexResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *AddBlockMetadataRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Metadata != nil { + if size, ok := interface{}(m.Metadata).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.Metadata) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *AddBlockMetadataResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *GetCompactionPlanUpdateRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.StatusUpdates) > 0 { + for _, e := range m.StatusUpdates { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.AssignJobsMax != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.AssignJobsMax)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompactionJobStatusUpdate) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Token != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Token)) + } + if m.Status != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Status)) + } + n += len(m.unknownFields) + return n +} + +func (m *GetCompactionPlanUpdateResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Term != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Term)) + } + if m.PlanUpdate != nil { + l = m.PlanUpdate.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompactionPlanUpdate) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.NewJobs) > 0 { + for _, e := range m.NewJobs { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.AssignedJobs) > 0 { + for _, e := range m.AssignedJobs { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.UpdatedJobs) > 0 { + for _, e := range m.UpdatedJobs { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.CompletedJobs) > 0 { + for _, e := range m.CompletedJobs { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.EvictedJobs) > 0 { + for _, e := range m.EvictedJobs { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *NewCompactionJob) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.State != nil { + l = m.State.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Plan != nil { + l = m.Plan.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *AssignedCompactionJob) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.State != nil { + l = m.State.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Plan != nil { + l = m.Plan.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *UpdatedCompactionJob) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.State != nil { + l = m.State.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompletedCompactionJob) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.State != nil { + l = m.State.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CompactedBlocks != nil { + if size, ok := interface{}(m.CompactedBlocks).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.CompactedBlocks) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *EvictedCompactionJob) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.State != nil { + l = m.State.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompactionJobState) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CompactionLevel != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CompactionLevel)) + } + if m.Status != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Status)) + } + if m.Token != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Token)) + } + if m.LeaseExpiresAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.LeaseExpiresAt)) + } + if m.AddedAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.AddedAt)) + } + if m.Failures != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Failures)) + } + n += len(m.unknownFields) + return n +} + +func (m *CompactionJobPlan) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Tenant) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + if m.CompactionLevel != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CompactionLevel)) + } + if len(m.SourceBlocks) > 0 { + for _, s := range m.SourceBlocks { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Tombstones) > 0 { + for _, e := range m.Tombstones { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *UpdateCompactionPlanRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Term != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Term)) + } + if m.PlanUpdate != nil { + l = m.PlanUpdate.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *UpdateCompactionPlanResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PlanUpdate != nil { + l = m.PlanUpdate.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *TruncateIndexRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Term != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Term)) + } + if len(m.Tombstones) > 0 { + for _, e := range m.Tombstones { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *TruncateIndexResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *AddBlockMetadataRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddBlockMetadataRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddBlockMetadataRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Metadata == nil { + m.Metadata = &v1.BlockMeta{} + } + if unmarshal, ok := interface{}(m.Metadata).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddBlockMetadataResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddBlockMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddBlockMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetCompactionPlanUpdateRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetCompactionPlanUpdateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetCompactionPlanUpdateRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StatusUpdates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StatusUpdates = append(m.StatusUpdates, &CompactionJobStatusUpdate{}) + if err := m.StatusUpdates[len(m.StatusUpdates)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AssignJobsMax", wireType) + } + m.AssignJobsMax = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AssignJobsMax |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactionJobStatusUpdate) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactionJobStatusUpdate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactionJobStatusUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + m.Token = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Token |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= v1.CompactionJobStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetCompactionPlanUpdateResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetCompactionPlanUpdateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetCompactionPlanUpdateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType) + } + m.Term = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Term |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanUpdate", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PlanUpdate == nil { + m.PlanUpdate = &CompactionPlanUpdate{} + } + if err := m.PlanUpdate.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactionPlanUpdate) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactionPlanUpdate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactionPlanUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewJobs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewJobs = append(m.NewJobs, &NewCompactionJob{}) + if err := m.NewJobs[len(m.NewJobs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AssignedJobs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AssignedJobs = append(m.AssignedJobs, &AssignedCompactionJob{}) + if err := m.AssignedJobs[len(m.AssignedJobs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdatedJobs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UpdatedJobs = append(m.UpdatedJobs, &UpdatedCompactionJob{}) + if err := m.UpdatedJobs[len(m.UpdatedJobs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompletedJobs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CompletedJobs = append(m.CompletedJobs, &CompletedCompactionJob{}) + if err := m.CompletedJobs[len(m.CompletedJobs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EvictedJobs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EvictedJobs = append(m.EvictedJobs, &EvictedCompactionJob{}) + if err := m.EvictedJobs[len(m.EvictedJobs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NewCompactionJob) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NewCompactionJob: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NewCompactionJob: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.State == nil { + m.State = &CompactionJobState{} + } + if err := m.State.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plan", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Plan == nil { + m.Plan = &CompactionJobPlan{} + } + if err := m.Plan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AssignedCompactionJob) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AssignedCompactionJob: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AssignedCompactionJob: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.State == nil { + m.State = &CompactionJobState{} + } + if err := m.State.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plan", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Plan == nil { + m.Plan = &CompactionJobPlan{} + } + if err := m.Plan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdatedCompactionJob) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdatedCompactionJob: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdatedCompactionJob: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.State == nil { + m.State = &CompactionJobState{} + } + if err := m.State.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompletedCompactionJob) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompletedCompactionJob: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompletedCompactionJob: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.State == nil { + m.State = &CompactionJobState{} + } + if err := m.State.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactedBlocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CompactedBlocks == nil { + m.CompactedBlocks = &v1.CompactedBlocks{} + } + if unmarshal, ok := interface{}(m.CompactedBlocks).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.CompactedBlocks); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EvictedCompactionJob) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EvictedCompactionJob: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EvictedCompactionJob: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.State == nil { + m.State = &CompactionJobState{} + } + if err := m.State.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactionJobState) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactionJobState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactionJobState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= v1.CompactionJobStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + m.Token = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Token |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LeaseExpiresAt", wireType) + } + m.LeaseExpiresAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LeaseExpiresAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AddedAt", wireType) + } + m.AddedAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AddedAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Failures", wireType) + } + m.Failures = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Failures |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CompactionJobPlan) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CompactionJobPlan: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CompactionJobPlan: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenant = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourceBlocks", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourceBlocks = append(m.SourceBlocks, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tombstones", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tombstones = append(m.Tombstones, &v1.Tombstones{}) + if unmarshal, ok := interface{}(m.Tombstones[len(m.Tombstones)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Tombstones[len(m.Tombstones)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdateCompactionPlanRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateCompactionPlanRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateCompactionPlanRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType) + } + m.Term = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Term |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanUpdate", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PlanUpdate == nil { + m.PlanUpdate = &CompactionPlanUpdate{} + } + if err := m.PlanUpdate.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdateCompactionPlanResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateCompactionPlanResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateCompactionPlanResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanUpdate", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PlanUpdate == nil { + m.PlanUpdate = &CompactionPlanUpdate{} + } + if err := m.PlanUpdate.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TruncateIndexRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TruncateIndexRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TruncateIndexRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType) + } + m.Term = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Term |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tombstones", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tombstones = append(m.Tombstones, &v1.Tombstones{}) + if unmarshal, ok := interface{}(m.Tombstones[len(m.Tombstones)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Tombstones[len(m.Tombstones)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TruncateIndexResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TruncateIndexResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TruncateIndexResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/metastore/v1/tenant.pb.go b/api/gen/proto/go/metastore/v1/tenant.pb.go new file mode 100644 index 0000000000..2b799a079c --- /dev/null +++ b/api/gen/proto/go/metastore/v1/tenant.pb.go @@ -0,0 +1,421 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: metastore/v1/tenant.proto + +package metastorev1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetTenantsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTenantsRequest) Reset() { + *x = GetTenantsRequest{} + mi := &file_metastore_v1_tenant_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTenantsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTenantsRequest) ProtoMessage() {} + +func (x *GetTenantsRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_tenant_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTenantsRequest.ProtoReflect.Descriptor instead. +func (*GetTenantsRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_tenant_proto_rawDescGZIP(), []int{0} +} + +type GetTenantsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + TenantIds []string `protobuf:"bytes,1,rep,name=tenant_ids,json=tenantIds,proto3" json:"tenant_ids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTenantsResponse) Reset() { + *x = GetTenantsResponse{} + mi := &file_metastore_v1_tenant_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTenantsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTenantsResponse) ProtoMessage() {} + +func (x *GetTenantsResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_tenant_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTenantsResponse.ProtoReflect.Descriptor instead. +func (*GetTenantsResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_tenant_proto_rawDescGZIP(), []int{1} +} + +func (x *GetTenantsResponse) GetTenantIds() []string { + if x != nil { + return x.TenantIds + } + return nil +} + +type GetTenantRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTenantRequest) Reset() { + *x = GetTenantRequest{} + mi := &file_metastore_v1_tenant_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTenantRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTenantRequest) ProtoMessage() {} + +func (x *GetTenantRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_tenant_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTenantRequest.ProtoReflect.Descriptor instead. +func (*GetTenantRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_tenant_proto_rawDescGZIP(), []int{2} +} + +func (x *GetTenantRequest) GetTenantId() string { + if x != nil { + return x.TenantId + } + return "" +} + +type GetTenantResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Stats *TenantStats `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTenantResponse) Reset() { + *x = GetTenantResponse{} + mi := &file_metastore_v1_tenant_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTenantResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTenantResponse) ProtoMessage() {} + +func (x *GetTenantResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_tenant_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTenantResponse.ProtoReflect.Descriptor instead. +func (*GetTenantResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_tenant_proto_rawDescGZIP(), []int{3} +} + +func (x *GetTenantResponse) GetStats() *TenantStats { + if x != nil { + return x.Stats + } + return nil +} + +type TenantStats struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Whether we received any data at any time in the past. + DataIngested bool `protobuf:"varint,1,opt,name=data_ingested,json=dataIngested,proto3" json:"data_ingested,omitempty"` + // Milliseconds since epoch. + OldestProfileTime int64 `protobuf:"varint,2,opt,name=oldest_profile_time,json=oldestProfileTime,proto3" json:"oldest_profile_time,omitempty"` + // Milliseconds since epoch. + NewestProfileTime int64 `protobuf:"varint,3,opt,name=newest_profile_time,json=newestProfileTime,proto3" json:"newest_profile_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TenantStats) Reset() { + *x = TenantStats{} + mi := &file_metastore_v1_tenant_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TenantStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TenantStats) ProtoMessage() {} + +func (x *TenantStats) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_tenant_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TenantStats.ProtoReflect.Descriptor instead. +func (*TenantStats) Descriptor() ([]byte, []int) { + return file_metastore_v1_tenant_proto_rawDescGZIP(), []int{4} +} + +func (x *TenantStats) GetDataIngested() bool { + if x != nil { + return x.DataIngested + } + return false +} + +func (x *TenantStats) GetOldestProfileTime() int64 { + if x != nil { + return x.OldestProfileTime + } + return 0 +} + +func (x *TenantStats) GetNewestProfileTime() int64 { + if x != nil { + return x.NewestProfileTime + } + return 0 +} + +type DeleteTenantRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteTenantRequest) Reset() { + *x = DeleteTenantRequest{} + mi := &file_metastore_v1_tenant_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteTenantRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteTenantRequest) ProtoMessage() {} + +func (x *DeleteTenantRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_tenant_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteTenantRequest.ProtoReflect.Descriptor instead. +func (*DeleteTenantRequest) Descriptor() ([]byte, []int) { + return file_metastore_v1_tenant_proto_rawDescGZIP(), []int{5} +} + +func (x *DeleteTenantRequest) GetTenantId() string { + if x != nil { + return x.TenantId + } + return "" +} + +type DeleteTenantResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteTenantResponse) Reset() { + *x = DeleteTenantResponse{} + mi := &file_metastore_v1_tenant_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteTenantResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteTenantResponse) ProtoMessage() {} + +func (x *DeleteTenantResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_tenant_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteTenantResponse.ProtoReflect.Descriptor instead. +func (*DeleteTenantResponse) Descriptor() ([]byte, []int) { + return file_metastore_v1_tenant_proto_rawDescGZIP(), []int{6} +} + +var File_metastore_v1_tenant_proto protoreflect.FileDescriptor + +const file_metastore_v1_tenant_proto_rawDesc = "" + + "\n" + + "\x19metastore/v1/tenant.proto\x12\fmetastore.v1\"\x13\n" + + "\x11GetTenantsRequest\"3\n" + + "\x12GetTenantsResponse\x12\x1d\n" + + "\n" + + "tenant_ids\x18\x01 \x03(\tR\ttenantIds\"/\n" + + "\x10GetTenantRequest\x12\x1b\n" + + "\ttenant_id\x18\x01 \x01(\tR\btenantId\"D\n" + + "\x11GetTenantResponse\x12/\n" + + "\x05stats\x18\x01 \x01(\v2\x19.metastore.v1.TenantStatsR\x05stats\"\x92\x01\n" + + "\vTenantStats\x12#\n" + + "\rdata_ingested\x18\x01 \x01(\bR\fdataIngested\x12.\n" + + "\x13oldest_profile_time\x18\x02 \x01(\x03R\x11oldestProfileTime\x12.\n" + + "\x13newest_profile_time\x18\x03 \x01(\x03R\x11newestProfileTime\"2\n" + + "\x13DeleteTenantRequest\x12\x1b\n" + + "\ttenant_id\x18\x01 \x01(\tR\btenantId\"\x16\n" + + "\x14DeleteTenantResponse2\x8b\x02\n" + + "\rTenantService\x12Q\n" + + "\n" + + "GetTenants\x12\x1f.metastore.v1.GetTenantsRequest\x1a .metastore.v1.GetTenantsResponse\"\x00\x12N\n" + + "\tGetTenant\x12\x1e.metastore.v1.GetTenantRequest\x1a\x1f.metastore.v1.GetTenantResponse\"\x00\x12W\n" + + "\fDeleteTenant\x12!.metastore.v1.DeleteTenantRequest\x1a\".metastore.v1.DeleteTenantResponse\"\x00B\xb8\x01\n" + + "\x10com.metastore.v1B\vTenantProtoP\x01ZFgithub.com/grafana/pyroscope/api/gen/proto/go/metastore/v1;metastorev1\xa2\x02\x03MXX\xaa\x02\fMetastore.V1\xca\x02\fMetastore\\V1\xe2\x02\x18Metastore\\V1\\GPBMetadata\xea\x02\rMetastore::V1b\x06proto3" + +var ( + file_metastore_v1_tenant_proto_rawDescOnce sync.Once + file_metastore_v1_tenant_proto_rawDescData []byte +) + +func file_metastore_v1_tenant_proto_rawDescGZIP() []byte { + file_metastore_v1_tenant_proto_rawDescOnce.Do(func() { + file_metastore_v1_tenant_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_metastore_v1_tenant_proto_rawDesc), len(file_metastore_v1_tenant_proto_rawDesc))) + }) + return file_metastore_v1_tenant_proto_rawDescData +} + +var file_metastore_v1_tenant_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_metastore_v1_tenant_proto_goTypes = []any{ + (*GetTenantsRequest)(nil), // 0: metastore.v1.GetTenantsRequest + (*GetTenantsResponse)(nil), // 1: metastore.v1.GetTenantsResponse + (*GetTenantRequest)(nil), // 2: metastore.v1.GetTenantRequest + (*GetTenantResponse)(nil), // 3: metastore.v1.GetTenantResponse + (*TenantStats)(nil), // 4: metastore.v1.TenantStats + (*DeleteTenantRequest)(nil), // 5: metastore.v1.DeleteTenantRequest + (*DeleteTenantResponse)(nil), // 6: metastore.v1.DeleteTenantResponse +} +var file_metastore_v1_tenant_proto_depIdxs = []int32{ + 4, // 0: metastore.v1.GetTenantResponse.stats:type_name -> metastore.v1.TenantStats + 0, // 1: metastore.v1.TenantService.GetTenants:input_type -> metastore.v1.GetTenantsRequest + 2, // 2: metastore.v1.TenantService.GetTenant:input_type -> metastore.v1.GetTenantRequest + 5, // 3: metastore.v1.TenantService.DeleteTenant:input_type -> metastore.v1.DeleteTenantRequest + 1, // 4: metastore.v1.TenantService.GetTenants:output_type -> metastore.v1.GetTenantsResponse + 3, // 5: metastore.v1.TenantService.GetTenant:output_type -> metastore.v1.GetTenantResponse + 6, // 6: metastore.v1.TenantService.DeleteTenant:output_type -> metastore.v1.DeleteTenantResponse + 4, // [4:7] is the sub-list for method output_type + 1, // [1:4] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_metastore_v1_tenant_proto_init() } +func file_metastore_v1_tenant_proto_init() { + if File_metastore_v1_tenant_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_metastore_v1_tenant_proto_rawDesc), len(file_metastore_v1_tenant_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_metastore_v1_tenant_proto_goTypes, + DependencyIndexes: file_metastore_v1_tenant_proto_depIdxs, + MessageInfos: file_metastore_v1_tenant_proto_msgTypes, + }.Build() + File_metastore_v1_tenant_proto = out.File + file_metastore_v1_tenant_proto_goTypes = nil + file_metastore_v1_tenant_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/metastore/v1/tenant_vtproto.pb.go b/api/gen/proto/go/metastore/v1/tenant_vtproto.pb.go new file mode 100644 index 0000000000..5e1c7d0abe --- /dev/null +++ b/api/gen/proto/go/metastore/v1/tenant_vtproto.pb.go @@ -0,0 +1,1379 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: metastore/v1/tenant.proto + +package metastorev1 + +import ( + context "context" + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *GetTenantsRequest) CloneVT() *GetTenantsRequest { + if m == nil { + return (*GetTenantsRequest)(nil) + } + r := new(GetTenantsRequest) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetTenantsRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetTenantsResponse) CloneVT() *GetTenantsResponse { + if m == nil { + return (*GetTenantsResponse)(nil) + } + r := new(GetTenantsResponse) + if rhs := m.TenantIds; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.TenantIds = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetTenantsResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetTenantRequest) CloneVT() *GetTenantRequest { + if m == nil { + return (*GetTenantRequest)(nil) + } + r := new(GetTenantRequest) + r.TenantId = m.TenantId + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetTenantRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetTenantResponse) CloneVT() *GetTenantResponse { + if m == nil { + return (*GetTenantResponse)(nil) + } + r := new(GetTenantResponse) + r.Stats = m.Stats.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetTenantResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TenantStats) CloneVT() *TenantStats { + if m == nil { + return (*TenantStats)(nil) + } + r := new(TenantStats) + r.DataIngested = m.DataIngested + r.OldestProfileTime = m.OldestProfileTime + r.NewestProfileTime = m.NewestProfileTime + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TenantStats) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *DeleteTenantRequest) CloneVT() *DeleteTenantRequest { + if m == nil { + return (*DeleteTenantRequest)(nil) + } + r := new(DeleteTenantRequest) + r.TenantId = m.TenantId + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteTenantRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *DeleteTenantResponse) CloneVT() *DeleteTenantResponse { + if m == nil { + return (*DeleteTenantResponse)(nil) + } + r := new(DeleteTenantResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteTenantResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *GetTenantsRequest) EqualVT(that *GetTenantsRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetTenantsRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetTenantsRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetTenantsResponse) EqualVT(that *GetTenantsResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.TenantIds) != len(that.TenantIds) { + return false + } + for i, vx := range this.TenantIds { + vy := that.TenantIds[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetTenantsResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetTenantsResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetTenantRequest) EqualVT(that *GetTenantRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.TenantId != that.TenantId { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetTenantRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetTenantRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetTenantResponse) EqualVT(that *GetTenantResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Stats.EqualVT(that.Stats) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetTenantResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetTenantResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TenantStats) EqualVT(that *TenantStats) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.DataIngested != that.DataIngested { + return false + } + if this.OldestProfileTime != that.OldestProfileTime { + return false + } + if this.NewestProfileTime != that.NewestProfileTime { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TenantStats) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TenantStats) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *DeleteTenantRequest) EqualVT(that *DeleteTenantRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.TenantId != that.TenantId { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteTenantRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteTenantRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *DeleteTenantResponse) EqualVT(that *DeleteTenantResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteTenantResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteTenantResponse) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// TenantServiceClient is the client API for TenantService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type TenantServiceClient interface { + GetTenants(ctx context.Context, in *GetTenantsRequest, opts ...grpc.CallOption) (*GetTenantsResponse, error) + GetTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*GetTenantResponse, error) + DeleteTenant(ctx context.Context, in *DeleteTenantRequest, opts ...grpc.CallOption) (*DeleteTenantResponse, error) +} + +type tenantServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewTenantServiceClient(cc grpc.ClientConnInterface) TenantServiceClient { + return &tenantServiceClient{cc} +} + +func (c *tenantServiceClient) GetTenants(ctx context.Context, in *GetTenantsRequest, opts ...grpc.CallOption) (*GetTenantsResponse, error) { + out := new(GetTenantsResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.TenantService/GetTenants", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tenantServiceClient) GetTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*GetTenantResponse, error) { + out := new(GetTenantResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.TenantService/GetTenant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tenantServiceClient) DeleteTenant(ctx context.Context, in *DeleteTenantRequest, opts ...grpc.CallOption) (*DeleteTenantResponse, error) { + out := new(DeleteTenantResponse) + err := c.cc.Invoke(ctx, "/metastore.v1.TenantService/DeleteTenant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// TenantServiceServer is the server API for TenantService service. +// All implementations must embed UnimplementedTenantServiceServer +// for forward compatibility +type TenantServiceServer interface { + GetTenants(context.Context, *GetTenantsRequest) (*GetTenantsResponse, error) + GetTenant(context.Context, *GetTenantRequest) (*GetTenantResponse, error) + DeleteTenant(context.Context, *DeleteTenantRequest) (*DeleteTenantResponse, error) + mustEmbedUnimplementedTenantServiceServer() +} + +// UnimplementedTenantServiceServer must be embedded to have forward compatible implementations. +type UnimplementedTenantServiceServer struct { +} + +func (UnimplementedTenantServiceServer) GetTenants(context.Context, *GetTenantsRequest) (*GetTenantsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTenants not implemented") +} +func (UnimplementedTenantServiceServer) GetTenant(context.Context, *GetTenantRequest) (*GetTenantResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTenant not implemented") +} +func (UnimplementedTenantServiceServer) DeleteTenant(context.Context, *DeleteTenantRequest) (*DeleteTenantResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteTenant not implemented") +} +func (UnimplementedTenantServiceServer) mustEmbedUnimplementedTenantServiceServer() {} + +// UnsafeTenantServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to TenantServiceServer will +// result in compilation errors. +type UnsafeTenantServiceServer interface { + mustEmbedUnimplementedTenantServiceServer() +} + +func RegisterTenantServiceServer(s grpc.ServiceRegistrar, srv TenantServiceServer) { + s.RegisterService(&TenantService_ServiceDesc, srv) +} + +func _TenantService_GetTenants_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTenantsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TenantServiceServer).GetTenants(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.TenantService/GetTenants", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TenantServiceServer).GetTenants(ctx, req.(*GetTenantsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TenantService_GetTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTenantRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TenantServiceServer).GetTenant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.TenantService/GetTenant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TenantServiceServer).GetTenant(ctx, req.(*GetTenantRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TenantService_DeleteTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteTenantRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TenantServiceServer).DeleteTenant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/metastore.v1.TenantService/DeleteTenant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TenantServiceServer).DeleteTenant(ctx, req.(*DeleteTenantRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// TenantService_ServiceDesc is the grpc.ServiceDesc for TenantService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var TenantService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "metastore.v1.TenantService", + HandlerType: (*TenantServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetTenants", + Handler: _TenantService_GetTenants_Handler, + }, + { + MethodName: "GetTenant", + Handler: _TenantService_GetTenant_Handler, + }, + { + MethodName: "DeleteTenant", + Handler: _TenantService_DeleteTenant_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "metastore/v1/tenant.proto", +} + +func (m *GetTenantsRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetTenantsRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetTenantsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *GetTenantsResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetTenantsResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetTenantsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TenantIds) > 0 { + for iNdEx := len(m.TenantIds) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TenantIds[iNdEx]) + copy(dAtA[i:], m.TenantIds[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantIds[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *GetTenantRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetTenantRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetTenantRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TenantId) > 0 { + i -= len(m.TenantId) + copy(dAtA[i:], m.TenantId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetTenantResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetTenantResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetTenantResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Stats != nil { + size, err := m.Stats.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TenantStats) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TenantStats) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TenantStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.NewestProfileTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.NewestProfileTime)) + i-- + dAtA[i] = 0x18 + } + if m.OldestProfileTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.OldestProfileTime)) + i-- + dAtA[i] = 0x10 + } + if m.DataIngested { + i-- + if m.DataIngested { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *DeleteTenantRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteTenantRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteTenantRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TenantId) > 0 { + i -= len(m.TenantId) + copy(dAtA[i:], m.TenantId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DeleteTenantResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteTenantResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteTenantResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *GetTenantsRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *GetTenantsResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TenantIds) > 0 { + for _, s := range m.TenantIds { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *GetTenantRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TenantId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *GetTenantResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Stats != nil { + l = m.Stats.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *TenantStats) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DataIngested { + n += 2 + } + if m.OldestProfileTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.OldestProfileTime)) + } + if m.NewestProfileTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.NewestProfileTime)) + } + n += len(m.unknownFields) + return n +} + +func (m *DeleteTenantRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TenantId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DeleteTenantResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *GetTenantsRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetTenantsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetTenantsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetTenantsResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetTenantsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetTenantsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantIds", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantIds = append(m.TenantIds, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetTenantRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetTenantRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetTenantRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetTenantResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetTenantResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetTenantResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Stats", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Stats == nil { + m.Stats = &TenantStats{} + } + if err := m.Stats.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TenantStats) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TenantStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TenantStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DataIngested", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.DataIngested = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OldestProfileTime", wireType) + } + m.OldestProfileTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OldestProfileTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NewestProfileTime", wireType) + } + m.NewestProfileTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NewestProfileTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteTenantRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteTenantRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteTenantRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteTenantResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteTenantResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteTenantResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/metastore/v1/types.pb.go b/api/gen/proto/go/metastore/v1/types.pb.go new file mode 100644 index 0000000000..841c1c4bd9 --- /dev/null +++ b/api/gen/proto/go/metastore/v1/types.pb.go @@ -0,0 +1,480 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: metastore/v1/types.proto + +package metastorev1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// BlockMeta is a metadata entry that describes the block's contents. A block +// is a collection of datasets that share certain properties, such as shard ID, +// compaction level, tenant ID, time range, creation time, and more. +// +// The block content's format denotes the binary format of the datasets and the +// metadata entry (to address logical dependencies). Each dataset has its own +// table of contents that lists the sections within the dataset. Each dataset +// has its own set of attributes (labels) that describe its specific contents. +type BlockMeta struct { + state protoimpl.MessageState `protogen:"open.v1"` + FormatVersion uint32 `protobuf:"varint,1,opt,name=format_version,json=formatVersion,proto3" json:"format_version,omitempty"` + // Block ID is a unique identifier for the block. + // This is the only field that is not included into + // the string table. + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // If empty, datasets belong to distinct tenants. + Tenant int32 `protobuf:"varint,3,opt,name=tenant,proto3" json:"tenant,omitempty"` + Shard uint32 `protobuf:"varint,4,opt,name=shard,proto3" json:"shard,omitempty"` + CompactionLevel uint32 `protobuf:"varint,5,opt,name=compaction_level,json=compactionLevel,proto3" json:"compaction_level,omitempty"` + MinTime int64 `protobuf:"varint,6,opt,name=min_time,json=minTime,proto3" json:"min_time,omitempty"` + MaxTime int64 `protobuf:"varint,7,opt,name=max_time,json=maxTime,proto3" json:"max_time,omitempty"` + CreatedBy int32 `protobuf:"varint,8,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` + MetadataOffset uint64 `protobuf:"varint,12,opt,name=metadata_offset,json=metadataOffset,proto3" json:"metadata_offset,omitempty"` + Size uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` + Datasets []*Dataset `protobuf:"bytes,10,rep,name=datasets,proto3" json:"datasets,omitempty"` + // String table contains strings of the block. + // By convention, the first string is always an empty string. + StringTable []string `protobuf:"bytes,11,rep,name=string_table,json=stringTable,proto3" json:"string_table,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BlockMeta) Reset() { + *x = BlockMeta{} + mi := &file_metastore_v1_types_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BlockMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockMeta) ProtoMessage() {} + +func (x *BlockMeta) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_types_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockMeta.ProtoReflect.Descriptor instead. +func (*BlockMeta) Descriptor() ([]byte, []int) { + return file_metastore_v1_types_proto_rawDescGZIP(), []int{0} +} + +func (x *BlockMeta) GetFormatVersion() uint32 { + if x != nil { + return x.FormatVersion + } + return 0 +} + +func (x *BlockMeta) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *BlockMeta) GetTenant() int32 { + if x != nil { + return x.Tenant + } + return 0 +} + +func (x *BlockMeta) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *BlockMeta) GetCompactionLevel() uint32 { + if x != nil { + return x.CompactionLevel + } + return 0 +} + +func (x *BlockMeta) GetMinTime() int64 { + if x != nil { + return x.MinTime + } + return 0 +} + +func (x *BlockMeta) GetMaxTime() int64 { + if x != nil { + return x.MaxTime + } + return 0 +} + +func (x *BlockMeta) GetCreatedBy() int32 { + if x != nil { + return x.CreatedBy + } + return 0 +} + +func (x *BlockMeta) GetMetadataOffset() uint64 { + if x != nil { + return x.MetadataOffset + } + return 0 +} + +func (x *BlockMeta) GetSize() uint64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *BlockMeta) GetDatasets() []*Dataset { + if x != nil { + return x.Datasets + } + return nil +} + +func (x *BlockMeta) GetStringTable() []string { + if x != nil { + return x.StringTable + } + return nil +} + +type Dataset struct { + state protoimpl.MessageState `protogen:"open.v1"` + Format uint32 `protobuf:"varint,9,opt,name=format,proto3" json:"format,omitempty"` + Tenant int32 `protobuf:"varint,1,opt,name=tenant,proto3" json:"tenant,omitempty"` + Name int32 `protobuf:"varint,2,opt,name=name,proto3" json:"name,omitempty"` + MinTime int64 `protobuf:"varint,3,opt,name=min_time,json=minTime,proto3" json:"min_time,omitempty"` + MaxTime int64 `protobuf:"varint,4,opt,name=max_time,json=maxTime,proto3" json:"max_time,omitempty"` + // Table of contents lists data sections within the tenant + // service region. The offsets are absolute. + // + // The interpretation of the table of contents is specific + // to the format. + // + // By default (format 0), the sections are: + // - 0: profiles.parquet + // - 1: index.tsdb + // - 2: symbols.symdb + // + // Format 1 corresponds to the tenant-wide index: + // - 0: index.tsdb (dataset index) + TableOfContents []uint64 `protobuf:"varint,5,rep,packed,name=table_of_contents,json=tableOfContents,proto3" json:"table_of_contents,omitempty"` + // Size of the dataset in bytes. + Size uint64 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"` + // Length prefixed label key-value pairs. + // + // Multiple label sets can be associated with a dataset to denote relationships + // across multiple dimensions. For example, each dataset currently stores data + // for multiple profile types: + // - service_name=A, profile_type=cpu + // - service_name=A, profile_type=memory + // + // Labels are primarily used to filter datasets based on their attributes. + // For instance, labels can be used to select datasets containing a specific + // service. + // + // The set of attributes is extensible and can grow over time. For example, a + // namespace attribute could be added to datasets: + // - service_name=A, profile_type=cpu + // - service_name=A, profile_type=memory + // - service_name=B, namespace=N, profile_type=cpu + // - service_name=B, namespace=N, profile_type=memory + // - service_name=C, namespace=N, profile_type=cpu + // - service_name=C, namespace=N, profile_type=memory + // + // This organization enables querying datasets by namespace without accessing + // the block contents, which significantly improves performance. + // + // Metadata labels are not required to be included in the block's TSDB index + // and may be orthogonal to the data dimensions. Generally, attributes serve + // two primary purposes: + // - To create data scopes that span multiple service, reducing the need to + // scan the entire set of block satisfying the query expression, i.e., + // the time range and tenant ID. + // - To provide additional information about datasets without altering the + // storage schema or access methods. + // + // For example, this approach can support cost attribution or similar breakdown + // analyses. It can also handle data dependencies (e.g., links to external data) + // using labels. + // + // The cardinality of the labels is expected to remain relatively low (fewer + // than a million unique combinations globally). However, this depends on the + // metadata storage system. + // + // Metadata labels are represented as a slice of `int32` values that refer to + // strings in the metadata entry's string table. The slice is a sequence of + // length-prefixed key-value (KV) pairs: + // + // len(2) | k1 | v1 | k2 | v2 | len(3) | k1 | v3 | k2 | v4 | k3 | v5 + // + // The order of KV pairs is not defined. The format is optimized for indexing + // rather than querying, and it is not intended to be the most space-efficient + // representation. Since entries are supposed to be indexed, the redundancy of + // denormalized relationships is not a concern. + Labels []int32 `protobuf:"varint,8,rep,packed,name=labels,proto3" json:"labels,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Dataset) Reset() { + *x = Dataset{} + mi := &file_metastore_v1_types_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Dataset) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Dataset) ProtoMessage() {} + +func (x *Dataset) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_types_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Dataset.ProtoReflect.Descriptor instead. +func (*Dataset) Descriptor() ([]byte, []int) { + return file_metastore_v1_types_proto_rawDescGZIP(), []int{1} +} + +func (x *Dataset) GetFormat() uint32 { + if x != nil { + return x.Format + } + return 0 +} + +func (x *Dataset) GetTenant() int32 { + if x != nil { + return x.Tenant + } + return 0 +} + +func (x *Dataset) GetName() int32 { + if x != nil { + return x.Name + } + return 0 +} + +func (x *Dataset) GetMinTime() int64 { + if x != nil { + return x.MinTime + } + return 0 +} + +func (x *Dataset) GetMaxTime() int64 { + if x != nil { + return x.MaxTime + } + return 0 +} + +func (x *Dataset) GetTableOfContents() []uint64 { + if x != nil { + return x.TableOfContents + } + return nil +} + +func (x *Dataset) GetSize() uint64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *Dataset) GetLabels() []int32 { + if x != nil { + return x.Labels + } + return nil +} + +type BlockList struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tenant string `protobuf:"bytes,1,opt,name=tenant,proto3" json:"tenant,omitempty"` + Shard uint32 `protobuf:"varint,2,opt,name=shard,proto3" json:"shard,omitempty"` + Blocks []string `protobuf:"bytes,3,rep,name=blocks,proto3" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BlockList) Reset() { + *x = BlockList{} + mi := &file_metastore_v1_types_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BlockList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockList) ProtoMessage() {} + +func (x *BlockList) ProtoReflect() protoreflect.Message { + mi := &file_metastore_v1_types_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockList.ProtoReflect.Descriptor instead. +func (*BlockList) Descriptor() ([]byte, []int) { + return file_metastore_v1_types_proto_rawDescGZIP(), []int{2} +} + +func (x *BlockList) GetTenant() string { + if x != nil { + return x.Tenant + } + return "" +} + +func (x *BlockList) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *BlockList) GetBlocks() []string { + if x != nil { + return x.Blocks + } + return nil +} + +var File_metastore_v1_types_proto protoreflect.FileDescriptor + +const file_metastore_v1_types_proto_rawDesc = "" + + "\n" + + "\x18metastore/v1/types.proto\x12\fmetastore.v1\"\x83\x03\n" + + "\tBlockMeta\x12%\n" + + "\x0eformat_version\x18\x01 \x01(\rR\rformatVersion\x12\x0e\n" + + "\x02id\x18\x02 \x01(\tR\x02id\x12\x16\n" + + "\x06tenant\x18\x03 \x01(\x05R\x06tenant\x12\x14\n" + + "\x05shard\x18\x04 \x01(\rR\x05shard\x12)\n" + + "\x10compaction_level\x18\x05 \x01(\rR\x0fcompactionLevel\x12\x19\n" + + "\bmin_time\x18\x06 \x01(\x03R\aminTime\x12\x19\n" + + "\bmax_time\x18\a \x01(\x03R\amaxTime\x12\x1d\n" + + "\n" + + "created_by\x18\b \x01(\x05R\tcreatedBy\x12'\n" + + "\x0fmetadata_offset\x18\f \x01(\x04R\x0emetadataOffset\x12\x12\n" + + "\x04size\x18\t \x01(\x04R\x04size\x121\n" + + "\bdatasets\x18\n" + + " \x03(\v2\x15.metastore.v1.DatasetR\bdatasets\x12!\n" + + "\fstring_table\x18\v \x03(\tR\vstringTable\"\xe1\x01\n" + + "\aDataset\x12\x16\n" + + "\x06format\x18\t \x01(\rR\x06format\x12\x16\n" + + "\x06tenant\x18\x01 \x01(\x05R\x06tenant\x12\x12\n" + + "\x04name\x18\x02 \x01(\x05R\x04name\x12\x19\n" + + "\bmin_time\x18\x03 \x01(\x03R\aminTime\x12\x19\n" + + "\bmax_time\x18\x04 \x01(\x03R\amaxTime\x12*\n" + + "\x11table_of_contents\x18\x05 \x03(\x04R\x0ftableOfContents\x12\x12\n" + + "\x04size\x18\x06 \x01(\x04R\x04size\x12\x16\n" + + "\x06labels\x18\b \x03(\x05R\x06labelsJ\x04\b\a\x10\b\"Q\n" + + "\tBlockList\x12\x16\n" + + "\x06tenant\x18\x01 \x01(\tR\x06tenant\x12\x14\n" + + "\x05shard\x18\x02 \x01(\rR\x05shard\x12\x16\n" + + "\x06blocks\x18\x03 \x03(\tR\x06blocksB\xb7\x01\n" + + "\x10com.metastore.v1B\n" + + "TypesProtoP\x01ZFgithub.com/grafana/pyroscope/api/gen/proto/go/metastore/v1;metastorev1\xa2\x02\x03MXX\xaa\x02\fMetastore.V1\xca\x02\fMetastore\\V1\xe2\x02\x18Metastore\\V1\\GPBMetadata\xea\x02\rMetastore::V1b\x06proto3" + +var ( + file_metastore_v1_types_proto_rawDescOnce sync.Once + file_metastore_v1_types_proto_rawDescData []byte +) + +func file_metastore_v1_types_proto_rawDescGZIP() []byte { + file_metastore_v1_types_proto_rawDescOnce.Do(func() { + file_metastore_v1_types_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_metastore_v1_types_proto_rawDesc), len(file_metastore_v1_types_proto_rawDesc))) + }) + return file_metastore_v1_types_proto_rawDescData +} + +var file_metastore_v1_types_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_metastore_v1_types_proto_goTypes = []any{ + (*BlockMeta)(nil), // 0: metastore.v1.BlockMeta + (*Dataset)(nil), // 1: metastore.v1.Dataset + (*BlockList)(nil), // 2: metastore.v1.BlockList +} +var file_metastore_v1_types_proto_depIdxs = []int32{ + 1, // 0: metastore.v1.BlockMeta.datasets:type_name -> metastore.v1.Dataset + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_metastore_v1_types_proto_init() } +func file_metastore_v1_types_proto_init() { + if File_metastore_v1_types_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_metastore_v1_types_proto_rawDesc), len(file_metastore_v1_types_proto_rawDesc)), + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_metastore_v1_types_proto_goTypes, + DependencyIndexes: file_metastore_v1_types_proto_depIdxs, + MessageInfos: file_metastore_v1_types_proto_msgTypes, + }.Build() + File_metastore_v1_types_proto = out.File + file_metastore_v1_types_proto_goTypes = nil + file_metastore_v1_types_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/metastore/v1/types_vtproto.pb.go b/api/gen/proto/go/metastore/v1/types_vtproto.pb.go new file mode 100644 index 0000000000..8527ed28ae --- /dev/null +++ b/api/gen/proto/go/metastore/v1/types_vtproto.pb.go @@ -0,0 +1,1422 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: metastore/v1/types.proto + +package metastorev1 + +import ( + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *BlockMeta) CloneVT() *BlockMeta { + if m == nil { + return (*BlockMeta)(nil) + } + r := new(BlockMeta) + r.FormatVersion = m.FormatVersion + r.Id = m.Id + r.Tenant = m.Tenant + r.Shard = m.Shard + r.CompactionLevel = m.CompactionLevel + r.MinTime = m.MinTime + r.MaxTime = m.MaxTime + r.CreatedBy = m.CreatedBy + r.MetadataOffset = m.MetadataOffset + r.Size = m.Size + if rhs := m.Datasets; rhs != nil { + tmpContainer := make([]*Dataset, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Datasets = tmpContainer + } + if rhs := m.StringTable; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.StringTable = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *BlockMeta) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Dataset) CloneVT() *Dataset { + if m == nil { + return (*Dataset)(nil) + } + r := new(Dataset) + r.Format = m.Format + r.Tenant = m.Tenant + r.Name = m.Name + r.MinTime = m.MinTime + r.MaxTime = m.MaxTime + r.Size = m.Size + if rhs := m.TableOfContents; rhs != nil { + tmpContainer := make([]uint64, len(rhs)) + copy(tmpContainer, rhs) + r.TableOfContents = tmpContainer + } + if rhs := m.Labels; rhs != nil { + tmpContainer := make([]int32, len(rhs)) + copy(tmpContainer, rhs) + r.Labels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Dataset) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *BlockList) CloneVT() *BlockList { + if m == nil { + return (*BlockList)(nil) + } + r := new(BlockList) + r.Tenant = m.Tenant + r.Shard = m.Shard + if rhs := m.Blocks; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Blocks = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *BlockList) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *BlockMeta) EqualVT(that *BlockMeta) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.FormatVersion != that.FormatVersion { + return false + } + if this.Id != that.Id { + return false + } + if this.Tenant != that.Tenant { + return false + } + if this.Shard != that.Shard { + return false + } + if this.CompactionLevel != that.CompactionLevel { + return false + } + if this.MinTime != that.MinTime { + return false + } + if this.MaxTime != that.MaxTime { + return false + } + if this.CreatedBy != that.CreatedBy { + return false + } + if this.Size != that.Size { + return false + } + if len(this.Datasets) != len(that.Datasets) { + return false + } + for i, vx := range this.Datasets { + vy := that.Datasets[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Dataset{} + } + if q == nil { + q = &Dataset{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.StringTable) != len(that.StringTable) { + return false + } + for i, vx := range this.StringTable { + vy := that.StringTable[i] + if vx != vy { + return false + } + } + if this.MetadataOffset != that.MetadataOffset { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *BlockMeta) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*BlockMeta) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Dataset) EqualVT(that *Dataset) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Tenant != that.Tenant { + return false + } + if this.Name != that.Name { + return false + } + if this.MinTime != that.MinTime { + return false + } + if this.MaxTime != that.MaxTime { + return false + } + if len(this.TableOfContents) != len(that.TableOfContents) { + return false + } + for i, vx := range this.TableOfContents { + vy := that.TableOfContents[i] + if vx != vy { + return false + } + } + if this.Size != that.Size { + return false + } + if len(this.Labels) != len(that.Labels) { + return false + } + for i, vx := range this.Labels { + vy := that.Labels[i] + if vx != vy { + return false + } + } + if this.Format != that.Format { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Dataset) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Dataset) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *BlockList) EqualVT(that *BlockList) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Tenant != that.Tenant { + return false + } + if this.Shard != that.Shard { + return false + } + if len(this.Blocks) != len(that.Blocks) { + return false + } + for i, vx := range this.Blocks { + vy := that.Blocks[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *BlockList) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*BlockList) + if !ok { + return false + } + return this.EqualVT(that) +} +func (m *BlockMeta) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockMeta) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *BlockMeta) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.MetadataOffset != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MetadataOffset)) + i-- + dAtA[i] = 0x60 + } + if len(m.StringTable) > 0 { + for iNdEx := len(m.StringTable) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.StringTable[iNdEx]) + copy(dAtA[i:], m.StringTable[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StringTable[iNdEx]))) + i-- + dAtA[i] = 0x5a + } + } + if len(m.Datasets) > 0 { + for iNdEx := len(m.Datasets) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Datasets[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x52 + } + } + if m.Size != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size)) + i-- + dAtA[i] = 0x48 + } + if m.CreatedBy != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CreatedBy)) + i-- + dAtA[i] = 0x40 + } + if m.MaxTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxTime)) + i-- + dAtA[i] = 0x38 + } + if m.MinTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MinTime)) + i-- + dAtA[i] = 0x30 + } + if m.CompactionLevel != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x28 + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x20 + } + if m.Tenant != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tenant)) + i-- + dAtA[i] = 0x18 + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0x12 + } + if m.FormatVersion != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.FormatVersion)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Dataset) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Dataset) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Dataset) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Format != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Format)) + i-- + dAtA[i] = 0x48 + } + if len(m.Labels) > 0 { + var pksize2 int + for _, num := range m.Labels { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.Labels { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x42 + } + if m.Size != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size)) + i-- + dAtA[i] = 0x30 + } + if len(m.TableOfContents) > 0 { + var pksize4 int + for _, num := range m.TableOfContents { + pksize4 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize4 + j3 := i + for _, num := range m.TableOfContents { + for num >= 1<<7 { + dAtA[j3] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j3++ + } + dAtA[j3] = uint8(num) + j3++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize4)) + i-- + dAtA[i] = 0x2a + } + if m.MaxTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxTime)) + i-- + dAtA[i] = 0x20 + } + if m.MinTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MinTime)) + i-- + dAtA[i] = 0x18 + } + if m.Name != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Name)) + i-- + dAtA[i] = 0x10 + } + if m.Tenant != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tenant)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *BlockList) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockList) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *BlockList) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Blocks) > 0 { + for iNdEx := len(m.Blocks) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Blocks[iNdEx]) + copy(dAtA[i:], m.Blocks[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Blocks[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x10 + } + if len(m.Tenant) > 0 { + i -= len(m.Tenant) + copy(dAtA[i:], m.Tenant) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tenant))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *BlockMeta) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.FormatVersion != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.FormatVersion)) + } + l = len(m.Id) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Tenant != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Tenant)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + if m.CompactionLevel != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CompactionLevel)) + } + if m.MinTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MinTime)) + } + if m.MaxTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MaxTime)) + } + if m.CreatedBy != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CreatedBy)) + } + if m.Size != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Size)) + } + if len(m.Datasets) > 0 { + for _, e := range m.Datasets { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.StringTable) > 0 { + for _, s := range m.StringTable { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.MetadataOffset != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MetadataOffset)) + } + n += len(m.unknownFields) + return n +} + +func (m *Dataset) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Tenant != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Tenant)) + } + if m.Name != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Name)) + } + if m.MinTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MinTime)) + } + if m.MaxTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MaxTime)) + } + if len(m.TableOfContents) > 0 { + l = 0 + for _, e := range m.TableOfContents { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if m.Size != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Size)) + } + if len(m.Labels) > 0 { + l = 0 + for _, e := range m.Labels { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if m.Format != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Format)) + } + n += len(m.unknownFields) + return n +} + +func (m *BlockList) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Tenant) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + if len(m.Blocks) > 0 { + for _, s := range m.Blocks { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *BlockMeta) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockMeta: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockMeta: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FormatVersion", wireType) + } + m.FormatVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FormatVersion |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + m.Tenant = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Tenant |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinTime", wireType) + } + m.MinTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTime", wireType) + } + m.MaxTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedBy", wireType) + } + m.CreatedBy = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreatedBy |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) + } + m.Size = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Datasets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Datasets = append(m.Datasets, &Dataset{}) + if err := m.Datasets[len(m.Datasets)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StringTable", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StringTable = append(m.StringTable, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MetadataOffset", wireType) + } + m.MetadataOffset = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MetadataOffset |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Dataset) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Dataset: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Dataset: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + m.Tenant = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Tenant |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + m.Name = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Name |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinTime", wireType) + } + m.MinTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTime", wireType) + } + m.MaxTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.TableOfContents = append(m.TableOfContents, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.TableOfContents) == 0 { + m.TableOfContents = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.TableOfContents = append(m.TableOfContents, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field TableOfContents", wireType) + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) + } + m.Size = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType == 0 { + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Labels = append(m.Labels, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Labels) == 0 { + m.Labels = make([]int32, 0, elementCount) + } + for iNdEx < postIndex { + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Labels = append(m.Labels, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Format", wireType) + } + m.Format = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Format |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlockList) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenant = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Blocks = append(m.Blocks, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/push/v1/push.pb.go b/api/gen/proto/go/push/v1/push.pb.go index 997e17464a..f5f1aef100 100644 --- a/api/gen/proto/go/push/v1/push.pb.go +++ b/api/gen/proto/go/push/v1/push.pb.go @@ -1,17 +1,21 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: push/v1/push.proto +// This is the API to send profiles to Pyroscope + package pushv1 import ( + _ "github.com/google/gnostic/openapiv3" v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,18 +26,16 @@ const ( ) type PushResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PushResponse) Reset() { *x = PushResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_push_v1_push_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_push_v1_push_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PushResponse) String() string { @@ -44,7 +46,7 @@ func (*PushResponse) ProtoMessage() {} func (x *PushResponse) ProtoReflect() protoreflect.Message { mi := &file_push_v1_push_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -61,21 +63,18 @@ func (*PushResponse) Descriptor() ([]byte, []int) { // WriteRawRequest writes a pprof profile type PushRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // series is a set raw pprof profiles and accompanying labels - Series []*RawProfileSeries `protobuf:"bytes,1,rep,name=series,proto3" json:"series,omitempty"` + Series []*RawProfileSeries `protobuf:"bytes,1,rep,name=series,proto3" json:"series,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PushRequest) Reset() { *x = PushRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_push_v1_push_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_push_v1_push_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PushRequest) String() string { @@ -86,7 +85,7 @@ func (*PushRequest) ProtoMessage() {} func (x *PushRequest) ProtoReflect() protoreflect.Message { mi := &file_push_v1_push_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -110,23 +109,29 @@ func (x *PushRequest) GetSeries() []*RawProfileSeries { // RawProfileSeries represents the pprof profile and its associated labels type RawProfileSeries struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // LabelPair is the key value pairs to identify the corresponding profile Labels []*v1.LabelPair `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"` // samples are the set of profile bytes Samples []*RawSample `protobuf:"bytes,2,rep,name=samples,proto3" json:"samples,omitempty"` + // Annotations provide additional metadata for a profile. + // + // The main differences between labels and annotations are: + // - annotations cannot be used in query selectors + // - annotation keys don't have to be unique + // + // Currently annotations are applied internally by distributors, + // any annotation passed via the push API will be dropped. + Annotations []*v1.ProfileAnnotation `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RawProfileSeries) Reset() { *x = RawProfileSeries{} - if protoimpl.UnsafeEnabled { - mi := &file_push_v1_push_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_push_v1_push_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RawProfileSeries) String() string { @@ -137,7 +142,7 @@ func (*RawProfileSeries) ProtoMessage() {} func (x *RawProfileSeries) ProtoReflect() protoreflect.Message { mi := &file_push_v1_push_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -166,25 +171,29 @@ func (x *RawProfileSeries) GetSamples() []*RawSample { return nil } +func (x *RawProfileSeries) GetAnnotations() []*v1.ProfileAnnotation { + if x != nil { + return x.Annotations + } + return nil +} + // RawSample is the set of bytes that correspond to a pprof profile type RawSample struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // raw_profile is the set of bytes of the pprof profile RawProfile []byte `protobuf:"bytes,1,opt,name=raw_profile,json=rawProfile,proto3" json:"raw_profile,omitempty"` - // unique ID of the profile - ID string `protobuf:"bytes,2,opt,name=ID,proto3" json:"ID,omitempty"` + // UUID of the profile + ID string `protobuf:"bytes,2,opt,name=ID,proto3" json:"ID,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RawSample) Reset() { *x = RawSample{} - if protoimpl.UnsafeEnabled { - mi := &file_push_v1_push_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_push_v1_push_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RawSample) String() string { @@ -195,7 +204,7 @@ func (*RawSample) ProtoMessage() {} func (x *RawSample) ProtoReflect() protoreflect.Message { mi := &file_push_v1_push_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -226,74 +235,58 @@ func (x *RawSample) GetID() string { var File_push_v1_push_proto protoreflect.FileDescriptor -var file_push_v1_push_proto_rawDesc = []byte{ - 0x0a, 0x12, 0x70, 0x75, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x1a, 0x14, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x40, 0x0a, 0x0b, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, 0x77, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x06, 0x73, - 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x6d, 0x0a, 0x10, 0x52, 0x61, 0x77, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x06, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x06, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x2c, 0x0a, 0x07, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x07, 0x73, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x09, 0x52, 0x61, 0x77, 0x53, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x77, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x49, 0x44, 0x32, 0x46, 0x0a, 0x0d, 0x50, 0x75, 0x73, 0x68, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x50, 0x75, 0x73, 0x68, 0x12, 0x14, 0x2e, 0x70, 0x75, - 0x73, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x73, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x93, 0x01, 0x0a, 0x0b, 0x63, - 0x6f, 0x6d, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x76, 0x31, 0x42, 0x09, 0x50, 0x75, 0x73, 0x68, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, - 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2f, 0x76, 0x31, 0x3b, 0x70, - 0x75, 0x73, 0x68, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x50, 0x75, - 0x73, 0x68, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x07, 0x50, 0x75, 0x73, 0x68, 0x5c, 0x56, 0x31, 0xe2, - 0x02, 0x13, 0x50, 0x75, 0x73, 0x68, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x08, 0x50, 0x75, 0x73, 0x68, 0x3a, 0x3a, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_push_v1_push_proto_rawDesc = "" + + "\n" + + "\x12push/v1/push.proto\x12\apush.v1\x1a$gnostic/openapi/v3/annotations.proto\x1a\x14types/v1/types.proto\"\x0e\n" + + "\fPushResponse\"@\n" + + "\vPushRequest\x121\n" + + "\x06series\x18\x01 \x03(\v2\x19.push.v1.RawProfileSeriesR\x06series\"\xac\x01\n" + + "\x10RawProfileSeries\x12+\n" + + "\x06labels\x18\x01 \x03(\v2\x13.types.v1.LabelPairR\x06labels\x12,\n" + + "\asamples\x18\x02 \x03(\v2\x12.push.v1.RawSampleR\asamples\x12=\n" + + "\vannotations\x18\x03 \x03(\v2\x1b.types.v1.ProfileAnnotationR\vannotations\"\x80\x01\n" + + "\tRawSample\x126\n" + + "\vraw_profile\x18\x01 \x01(\fB\x15\xbaG\x12:\x10\x12\x0ePROFILE_BASE64R\n" + + "rawProfile\x12;\n" + + "\x02ID\x18\x02 \x01(\tB+\xbaG(:&\x12$734FD599-6865-419E-9475-932762D8F469R\x02ID2W\n" + + "\rPusherService\x12F\n" + + "\x04Push\x12\x14.push.v1.PushRequest\x1a\x15.push.v1.PushResponse\"\x11\xbaG\x0e\n" + + "\fscope/publicB\x93\x01\n" + + "\vcom.push.v1B\tPushProtoP\x01Z push.v1.RawProfileSeries 4, // 1: push.v1.RawProfileSeries.labels:type_name -> types.v1.LabelPair 3, // 2: push.v1.RawProfileSeries.samples:type_name -> push.v1.RawSample - 1, // 3: push.v1.PusherService.Push:input_type -> push.v1.PushRequest - 0, // 4: push.v1.PusherService.Push:output_type -> push.v1.PushResponse - 4, // [4:5] is the sub-list for method output_type - 3, // [3:4] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 5, // 3: push.v1.RawProfileSeries.annotations:type_name -> types.v1.ProfileAnnotation + 1, // 4: push.v1.PusherService.Push:input_type -> push.v1.PushRequest + 0, // 5: push.v1.PusherService.Push:output_type -> push.v1.PushResponse + 5, // [5:6] is the sub-list for method output_type + 4, // [4:5] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_push_v1_push_proto_init() } @@ -301,61 +294,11 @@ func file_push_v1_push_proto_init() { if File_push_v1_push_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_push_v1_push_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PushResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_push_v1_push_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PushRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_push_v1_push_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RawProfileSeries); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_push_v1_push_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RawSample); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_push_v1_push_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_push_v1_push_proto_rawDesc), len(file_push_v1_push_proto_rawDesc)), NumEnums: 0, NumMessages: 4, NumExtensions: 0, @@ -366,7 +309,6 @@ func file_push_v1_push_proto_init() { MessageInfos: file_push_v1_push_proto_msgTypes, }.Build() File_push_v1_push_proto = out.File - file_push_v1_push_proto_rawDesc = nil file_push_v1_push_proto_goTypes = nil file_push_v1_push_proto_depIdxs = nil } diff --git a/api/gen/proto/go/push/v1/push_vtproto.pb.go b/api/gen/proto/go/push/v1/push_vtproto.pb.go index 0d19001281..295eeaacf9 100644 --- a/api/gen/proto/go/push/v1/push_vtproto.pb.go +++ b/api/gen/proto/go/push/v1/push_vtproto.pb.go @@ -86,6 +86,17 @@ func (m *RawProfileSeries) CloneVT() *RawProfileSeries { } r.Samples = tmpContainer } + if rhs := m.Annotations; rhs != nil { + tmpContainer := make([]*v1.ProfileAnnotation, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.ProfileAnnotation }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.ProfileAnnotation) + } + } + r.Annotations = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -212,6 +223,29 @@ func (this *RawProfileSeries) EqualVT(that *RawProfileSeries) bool { } } } + if len(this.Annotations) != len(that.Annotations) { + return false + } + for i, vx := range this.Annotations { + vy := that.Annotations[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.ProfileAnnotation{} + } + if q == nil { + q = &v1.ProfileAnnotation{} + } + if equal, ok := interface{}(p).(interface { + EqualVT(*v1.ProfileAnnotation) bool + }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -444,6 +478,30 @@ func (m *RawProfileSeries) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.Annotations) > 0 { + for iNdEx := len(m.Annotations) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Annotations[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Annotations[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x1a + } + } if len(m.Samples) > 0 { for iNdEx := len(m.Samples) - 1; iNdEx >= 0; iNdEx-- { size, err := m.Samples[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) @@ -580,6 +638,18 @@ func (m *RawProfileSeries) SizeVT() (n int) { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } } + if len(m.Annotations) > 0 { + for _, e := range m.Annotations { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } n += len(m.unknownFields) return n } @@ -843,6 +913,48 @@ func (m *RawProfileSeries) UnmarshalVT(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Annotations = append(m.Annotations, &v1.ProfileAnnotation{}) + if unmarshal, ok := interface{}(m.Annotations[len(m.Annotations)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Annotations[len(m.Annotations)-1]); err != nil { + return err + } + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/api/gen/proto/go/push/v1/pushv1connect/push.connect.go b/api/gen/proto/go/push/v1/pushv1connect/push.connect.go index 0c455483e4..bd50cec58c 100644 --- a/api/gen/proto/go/push/v1/pushv1connect/push.connect.go +++ b/api/gen/proto/go/push/v1/pushv1connect/push.connect.go @@ -2,6 +2,7 @@ // // Source: push/v1/push.proto +// This is the API to send profiles to Pyroscope package pushv1connect import ( @@ -37,12 +38,6 @@ const ( PusherServicePushProcedure = "/push.v1.PusherService/Push" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - pusherServiceServiceDescriptor = v1.File_push_v1_push_proto.Services().ByName("PusherService") - pusherServicePushMethodDescriptor = pusherServiceServiceDescriptor.Methods().ByName("Push") -) - // PusherServiceClient is a client for the push.v1.PusherService service. type PusherServiceClient interface { Push(context.Context, *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) @@ -57,11 +52,12 @@ type PusherServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewPusherServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) PusherServiceClient { baseURL = strings.TrimRight(baseURL, "/") + pusherServiceMethods := v1.File_push_v1_push_proto.Services().ByName("PusherService").Methods() return &pusherServiceClient{ push: connect.NewClient[v1.PushRequest, v1.PushResponse]( httpClient, baseURL+PusherServicePushProcedure, - connect.WithSchema(pusherServicePushMethodDescriptor), + connect.WithSchema(pusherServiceMethods.ByName("Push")), connect.WithClientOptions(opts...), ), } @@ -88,10 +84,11 @@ type PusherServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewPusherServiceHandler(svc PusherServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + pusherServiceMethods := v1.File_push_v1_push_proto.Services().ByName("PusherService").Methods() pusherServicePushHandler := connect.NewUnaryHandler( PusherServicePushProcedure, svc.Push, - connect.WithSchema(pusherServicePushMethodDescriptor), + connect.WithSchema(pusherServiceMethods.ByName("Push")), connect.WithHandlerOptions(opts...), ) return "/push.v1.PusherService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/api/gen/proto/go/querier/v1/querier.pb.go b/api/gen/proto/go/querier/v1/querier.pb.go index 3cfa0a2ec6..5f50aa6d54 100644 --- a/api/gen/proto/go/querier/v1/querier.pb.go +++ b/api/gen/proto/go/querier/v1/querier.pb.go @@ -1,18 +1,23 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: querier/v1/querier.proto +// Provides the ability to query the Pyroscope database. Most of the calls in +// this group are considered public. + package querierv1 import ( + _ "github.com/google/gnostic/openapiv3" v11 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -25,9 +30,24 @@ const ( type ProfileFormat int32 const ( + // Equivalent to PROFILE_FORMAT_FLAMEGRAPH. Preserved for backward + // compatibility. ProfileFormat_PROFILE_FORMAT_UNSPECIFIED ProfileFormat = 0 - ProfileFormat_PROFILE_FORMAT_FLAMEGRAPH ProfileFormat = 1 - ProfileFormat_PROFILE_FORMAT_TREE ProfileFormat = 2 + // Return a Flamebearer-compatible, single-profile flame graph. Samples + // sharing the same function-name call stack are aggregated into the names + // and levels representation used by the Pyroscope flame graph renderer. + // Format: https://github.com/grafana/pyroscope/blob/main/pkg/og/structs/flamebearer/flamebearer.go + ProfileFormat_PROFILE_FORMAT_FLAMEGRAPH ProfileFormat = 1 + // Return a compact, function-name-only Pyroscope tree serialization in + // SelectMergeStacktracesResponse.tree. + ProfileFormat_PROFILE_FORMAT_TREE ProfileFormat = 2 + // Return a Graphviz DOT directed graph. Nodes represent functions and edges + // represent caller-callee relationships, annotated with aggregated sample + // values. The resulting text can be rendered by Graphviz-compatible tools. + ProfileFormat_PROFILE_FORMAT_DOT ProfileFormat = 3 + // Return a pprof profile, including available mappings, locations, filenames, + // and line numbers, in SelectMergeStacktracesResponse.pprof. + ProfileFormat_PROFILE_FORMAT_PPROF ProfileFormat = 4 ) // Enum value maps for ProfileFormat. @@ -36,11 +56,15 @@ var ( 0: "PROFILE_FORMAT_UNSPECIFIED", 1: "PROFILE_FORMAT_FLAMEGRAPH", 2: "PROFILE_FORMAT_TREE", + 3: "PROFILE_FORMAT_DOT", + 4: "PROFILE_FORMAT_PPROF", } ProfileFormat_value = map[string]int32{ "PROFILE_FORMAT_UNSPECIFIED": 0, "PROFILE_FORMAT_FLAMEGRAPH": 1, "PROFILE_FORMAT_TREE": 2, + "PROFILE_FORMAT_DOT": 3, + "PROFILE_FORMAT_PPROF": 4, } ) @@ -71,26 +95,172 @@ func (ProfileFormat) EnumDescriptor() ([]byte, []int) { return file_querier_v1_querier_proto_rawDescGZIP(), []int{0} } -type ProfileTypesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +type AsyncQueryType int32 + +const ( + // The query should not be async. + AsyncQueryType_ASYNC_QUERY_TYPE_DISABLED AsyncQueryType = 0 + // The query must be async. + AsyncQueryType_ASYNC_QUERY_TYPE_FORCE AsyncQueryType = 1 +) + +// Enum value maps for AsyncQueryType. +var ( + AsyncQueryType_name = map[int32]string{ + 0: "ASYNC_QUERY_TYPE_DISABLED", + 1: "ASYNC_QUERY_TYPE_FORCE", + } + AsyncQueryType_value = map[string]int32{ + "ASYNC_QUERY_TYPE_DISABLED": 0, + "ASYNC_QUERY_TYPE_FORCE": 1, + } +) + +func (x AsyncQueryType) Enum() *AsyncQueryType { + p := new(AsyncQueryType) + *p = x + return p +} + +func (x AsyncQueryType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AsyncQueryType) Descriptor() protoreflect.EnumDescriptor { + return file_querier_v1_querier_proto_enumTypes[1].Descriptor() +} + +func (AsyncQueryType) Type() protoreflect.EnumType { + return &file_querier_v1_querier_proto_enumTypes[1] +} + +func (x AsyncQueryType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AsyncQueryType.Descriptor instead. +func (AsyncQueryType) EnumDescriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{1} +} + +type AsyncQueryStatus int32 +const ( + AsyncQueryStatus_ASYNC_QUERY_STATUS_UNKNOWN AsyncQueryStatus = 0 + AsyncQueryStatus_ASYNC_QUERY_STATUS_IN_PROGRESS AsyncQueryStatus = 1 + AsyncQueryStatus_ASYNC_QUERY_STATUS_SUCCESS AsyncQueryStatus = 2 + AsyncQueryStatus_ASYNC_QUERY_STATUS_FAILURE AsyncQueryStatus = 3 +) + +// Enum value maps for AsyncQueryStatus. +var ( + AsyncQueryStatus_name = map[int32]string{ + 0: "ASYNC_QUERY_STATUS_UNKNOWN", + 1: "ASYNC_QUERY_STATUS_IN_PROGRESS", + 2: "ASYNC_QUERY_STATUS_SUCCESS", + 3: "ASYNC_QUERY_STATUS_FAILURE", + } + AsyncQueryStatus_value = map[string]int32{ + "ASYNC_QUERY_STATUS_UNKNOWN": 0, + "ASYNC_QUERY_STATUS_IN_PROGRESS": 1, + "ASYNC_QUERY_STATUS_SUCCESS": 2, + "ASYNC_QUERY_STATUS_FAILURE": 3, + } +) + +func (x AsyncQueryStatus) Enum() *AsyncQueryStatus { + p := new(AsyncQueryStatus) + *p = x + return p +} + +func (x AsyncQueryStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AsyncQueryStatus) Descriptor() protoreflect.EnumDescriptor { + return file_querier_v1_querier_proto_enumTypes[2].Descriptor() +} + +func (AsyncQueryStatus) Type() protoreflect.EnumType { + return &file_querier_v1_querier_proto_enumTypes[2] +} + +func (x AsyncQueryStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AsyncQueryStatus.Descriptor instead. +func (AsyncQueryStatus) EnumDescriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{2} +} + +type HeatmapQueryType int32 + +const ( + HeatmapQueryType_HEATMAP_QUERY_TYPE_UNSPECIFIED HeatmapQueryType = 0 + HeatmapQueryType_HEATMAP_QUERY_TYPE_INDIVIDUAL HeatmapQueryType = 1 + HeatmapQueryType_HEATMAP_QUERY_TYPE_SPAN HeatmapQueryType = 2 +) + +// Enum value maps for HeatmapQueryType. +var ( + HeatmapQueryType_name = map[int32]string{ + 0: "HEATMAP_QUERY_TYPE_UNSPECIFIED", + 1: "HEATMAP_QUERY_TYPE_INDIVIDUAL", + 2: "HEATMAP_QUERY_TYPE_SPAN", + } + HeatmapQueryType_value = map[string]int32{ + "HEATMAP_QUERY_TYPE_UNSPECIFIED": 0, + "HEATMAP_QUERY_TYPE_INDIVIDUAL": 1, + "HEATMAP_QUERY_TYPE_SPAN": 2, + } +) + +func (x HeatmapQueryType) Enum() *HeatmapQueryType { + p := new(HeatmapQueryType) + *p = x + return p +} + +func (x HeatmapQueryType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (HeatmapQueryType) Descriptor() protoreflect.EnumDescriptor { + return file_querier_v1_querier_proto_enumTypes[3].Descriptor() +} + +func (HeatmapQueryType) Type() protoreflect.EnumType { + return &file_querier_v1_querier_proto_enumTypes[3] +} + +func (x HeatmapQueryType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use HeatmapQueryType.Descriptor instead. +func (HeatmapQueryType) EnumDescriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{3} +} + +type ProfileTypesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. Start int64 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. - End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ProfileTypesRequest) Reset() { *x = ProfileTypesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProfileTypesRequest) String() string { @@ -101,7 +271,7 @@ func (*ProfileTypesRequest) ProtoMessage() {} func (x *ProfileTypesRequest) ProtoReflect() protoreflect.Message { mi := &file_querier_v1_querier_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -131,20 +301,17 @@ func (x *ProfileTypesRequest) GetEnd() int64 { } type ProfileTypesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ProfileTypes []*v1.ProfileType `protobuf:"bytes,1,rep,name=profile_types,json=profileTypes,proto3" json:"profile_types,omitempty"` unknownFields protoimpl.UnknownFields - - ProfileTypes []*v1.ProfileType `protobuf:"bytes,1,rep,name=profile_types,json=profileTypes,proto3" json:"profile_types,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ProfileTypesResponse) Reset() { *x = ProfileTypesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProfileTypesResponse) String() string { @@ -155,7 +322,7 @@ func (*ProfileTypesResponse) ProtoMessage() {} func (x *ProfileTypesResponse) ProtoReflect() protoreflect.Message { mi := &file_querier_v1_querier_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -178,27 +345,26 @@ func (x *ProfileTypesResponse) GetProfileTypes() []*v1.ProfileType { } type SeriesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Matchers []string `protobuf:"bytes,1,rep,name=matchers,proto3" json:"matchers,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + // List of label selector to apply to the result. + Matchers []string `protobuf:"bytes,1,rep,name=matchers,proto3" json:"matchers,omitempty"` + // List of label_names to request. If empty will return all label names in the + // result. LabelNames []string `protobuf:"bytes,2,rep,name=label_names,json=labelNames,proto3" json:"label_names,omitempty"` // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` - // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. - End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SeriesRequest) Reset() { *x = SeriesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SeriesRequest) String() string { @@ -209,7 +375,7 @@ func (*SeriesRequest) ProtoMessage() {} func (x *SeriesRequest) ProtoReflect() protoreflect.Message { mi := &file_querier_v1_querier_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -253,20 +419,17 @@ func (x *SeriesRequest) GetEnd() int64 { } type SeriesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + LabelsSet []*v1.Labels `protobuf:"bytes,2,rep,name=labels_set,json=labelsSet,proto3" json:"labels_set,omitempty"` unknownFields protoimpl.UnknownFields - - LabelsSet []*v1.Labels `protobuf:"bytes,2,rep,name=labels_set,json=labelsSet,proto3" json:"labels_set,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SeriesResponse) Reset() { *x = SeriesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SeriesResponse) String() string { @@ -277,7 +440,7 @@ func (*SeriesResponse) ProtoMessage() {} func (x *SeriesResponse) ProtoReflect() protoreflect.Message { mi := &file_querier_v1_querier_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -300,30 +463,41 @@ func (x *SeriesResponse) GetLabelsSet() []*v1.Labels { } type SelectMergeStacktracesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` + // Profile Type ID string in the form + // ::::. ProfileTypeID string `protobuf:"bytes,1,opt,name=profile_typeID,json=profileTypeID,proto3" json:"profile_typeID,omitempty"` + // Label selector string LabelSelector string `protobuf:"bytes,2,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` // Milliseconds since epoch. Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` - // Limit the nodes returned to only show the node with the max_node's biggest total + // Limit the nodes returned to only show the node with the max_node's biggest + // total MaxNodes *int64 `protobuf:"varint,5,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` // Profile format specifies the format of profile to be returned. // If not specified, the profile will be returned in flame graph format. Format ProfileFormat `protobuf:"varint,6,opt,name=format,proto3,enum=querier.v1.ProfileFormat" json:"format,omitempty"` + // Select stack traces that match the provided selector. + StackTraceSelector *v1.StackTraceSelector `protobuf:"bytes,7,opt,name=stack_trace_selector,json=stackTraceSelector,proto3,oneof" json:"stack_trace_selector,omitempty"` + // List of Profile UUIDs to query + ProfileIdSelector []string `protobuf:"bytes,8,rep,name=profile_id_selector,json=profileIdSelector,proto3" json:"profile_id_selector,omitempty"` + // (experimental) Used for making and polling async queries. + Async *AsyncQueryRequest `protobuf:"bytes,9,opt,name=async,proto3,oneof" json:"async,omitempty"` + // List of trace IDs (32 hex characters, 128-bit) to filter samples by. + TraceIdSelector []string `protobuf:"bytes,10,rep,name=trace_id_selector,json=traceIdSelector,proto3" json:"trace_id_selector,omitempty"` + // List of span IDs (16 hex characters, 64-bit) to filter samples by. + SpanSelector []string `protobuf:"bytes,11,rep,name=span_selector,json=spanSelector,proto3" json:"span_selector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectMergeStacktracesRequest) Reset() { *x = SelectMergeStacktracesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectMergeStacktracesRequest) String() string { @@ -334,7 +508,7 @@ func (*SelectMergeStacktracesRequest) ProtoMessage() {} func (x *SelectMergeStacktracesRequest) ProtoReflect() protoreflect.Message { mi := &file_querier_v1_querier_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -391,23 +565,61 @@ func (x *SelectMergeStacktracesRequest) GetFormat() ProfileFormat { return ProfileFormat_PROFILE_FORMAT_UNSPECIFIED } -type SelectMergeStacktracesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *SelectMergeStacktracesRequest) GetStackTraceSelector() *v1.StackTraceSelector { + if x != nil { + return x.StackTraceSelector + } + return nil +} + +func (x *SelectMergeStacktracesRequest) GetProfileIdSelector() []string { + if x != nil { + return x.ProfileIdSelector + } + return nil +} - Flamegraph *FlameGraph `protobuf:"bytes,1,opt,name=flamegraph,proto3" json:"flamegraph,omitempty"` +func (x *SelectMergeStacktracesRequest) GetAsync() *AsyncQueryRequest { + if x != nil { + return x.Async + } + return nil +} + +func (x *SelectMergeStacktracesRequest) GetTraceIdSelector() []string { + if x != nil { + return x.TraceIdSelector + } + return nil +} + +func (x *SelectMergeStacktracesRequest) GetSpanSelector() []string { + if x != nil { + return x.SpanSelector + } + return nil +} + +type SelectMergeStacktracesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Flamegraph *FlameGraph `protobuf:"bytes,1,opt,name=flamegraph,proto3" json:"flamegraph,omitempty"` // Pyroscope tree bytes. Tree []byte `protobuf:"bytes,2,opt,name=tree,proto3" json:"tree,omitempty"` + // DOT graph representation. + Dot string `protobuf:"bytes,3,opt,name=dot,proto3" json:"dot,omitempty"` + // (experimental) Used for responding to async queries. + Async *AsyncQueryResponse `protobuf:"bytes,4,opt,name=async,proto3,oneof" json:"async,omitempty"` + // Profile in pprof format. + Pprof *PprofProfile `protobuf:"bytes,5,opt,name=pprof,proto3" json:"pprof,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectMergeStacktracesResponse) Reset() { *x = SelectMergeStacktracesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectMergeStacktracesResponse) String() string { @@ -418,7 +630,7 @@ func (*SelectMergeStacktracesResponse) ProtoMessage() {} func (x *SelectMergeStacktracesResponse) ProtoReflect() protoreflect.Message { mi := &file_querier_v1_querier_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -447,32 +659,217 @@ func (x *SelectMergeStacktracesResponse) GetTree() []byte { return nil } -type SelectMergeSpanProfileRequest struct { - state protoimpl.MessageState +func (x *SelectMergeStacktracesResponse) GetDot() string { + if x != nil { + return x.Dot + } + return "" +} + +func (x *SelectMergeStacktracesResponse) GetAsync() *AsyncQueryResponse { + if x != nil { + return x.Async + } + return nil +} + +func (x *SelectMergeStacktracesResponse) GetPprof() *PprofProfile { + if x != nil { + return x.Pprof + } + return nil +} + +// PprofProfile contains pprof output and related response metadata. +type PprofProfile struct { + state protoimpl.MessageState `protogen:"open.v1"` + Profile *v11.Profile `protobuf:"bytes,1,opt,name=profile,proto3" json:"profile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PprofProfile) Reset() { + *x = PprofProfile{} + mi := &file_querier_v1_querier_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PprofProfile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PprofProfile) ProtoMessage() {} + +func (x *PprofProfile) ProtoReflect() protoreflect.Message { + mi := &file_querier_v1_querier_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PprofProfile.ProtoReflect.Descriptor instead. +func (*PprofProfile) Descriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{6} +} + +func (x *PprofProfile) GetProfile() *v11.Profile { + if x != nil { + return x.Profile + } + return nil +} + +type AsyncQueryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // If set, this is a polling request. + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // Sets the kind of async query. + Type AsyncQueryType `protobuf:"varint,2,opt,name=type,proto3,enum=querier.v1.AsyncQueryType" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache +} + +func (x *AsyncQueryRequest) Reset() { + *x = AsyncQueryRequest{} + mi := &file_querier_v1_querier_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AsyncQueryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AsyncQueryRequest) ProtoMessage() {} + +func (x *AsyncQueryRequest) ProtoReflect() protoreflect.Message { + mi := &file_querier_v1_querier_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AsyncQueryRequest.ProtoReflect.Descriptor instead. +func (*AsyncQueryRequest) Descriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{7} +} + +func (x *AsyncQueryRequest) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *AsyncQueryRequest) GetType() AsyncQueryType { + if x != nil { + return x.Type + } + return AsyncQueryType_ASYNC_QUERY_TYPE_DISABLED +} + +type AsyncQueryResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Id of the async query. + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // Status of the query: unknown, in_progress, success, failed + Status AsyncQueryStatus `protobuf:"varint,2,opt,name=status,proto3,enum=querier.v1.AsyncQueryStatus" json:"status,omitempty"` + // Populated on FAILURE. + ErrorMessage string `protobuf:"bytes,3,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AsyncQueryResponse) Reset() { + *x = AsyncQueryResponse{} + mi := &file_querier_v1_querier_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AsyncQueryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AsyncQueryResponse) ProtoMessage() {} + +func (x *AsyncQueryResponse) ProtoReflect() protoreflect.Message { + mi := &file_querier_v1_querier_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AsyncQueryResponse.ProtoReflect.Descriptor instead. +func (*AsyncQueryResponse) Descriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{8} +} + +func (x *AsyncQueryResponse) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *AsyncQueryResponse) GetStatus() AsyncQueryStatus { + if x != nil { + return x.Status + } + return AsyncQueryStatus_ASYNC_QUERY_STATUS_UNKNOWN +} + +func (x *AsyncQueryResponse) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} - ProfileTypeID string `protobuf:"bytes,1,opt,name=profile_typeID,json=profileTypeID,proto3" json:"profile_typeID,omitempty"` - LabelSelector string `protobuf:"bytes,2,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` - SpanSelector []string `protobuf:"bytes,3,rep,name=span_selector,json=spanSelector,proto3" json:"span_selector,omitempty"` +type SelectMergeSpanProfileRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Profile Type ID string in the form + // ::::. + ProfileTypeID string `protobuf:"bytes,1,opt,name=profile_typeID,json=profileTypeID,proto3" json:"profile_typeID,omitempty"` + // Label selector string + LabelSelector string `protobuf:"bytes,2,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` + // List of Span IDs to query + SpanSelector []string `protobuf:"bytes,3,rep,name=span_selector,json=spanSelector,proto3" json:"span_selector,omitempty"` // Milliseconds since epoch. Start int64 `protobuf:"varint,4,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. End int64 `protobuf:"varint,5,opt,name=end,proto3" json:"end,omitempty"` - // Limit the nodes returned to only show the node with the max_node's biggest total + // Limit the nodes returned to only show the node with the max_node's biggest + // total MaxNodes *int64 `protobuf:"varint,6,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` // Profile format specifies the format of profile to be returned. // If not specified, the profile will be returned in flame graph format. - Format ProfileFormat `protobuf:"varint,7,opt,name=format,proto3,enum=querier.v1.ProfileFormat" json:"format,omitempty"` + Format ProfileFormat `protobuf:"varint,7,opt,name=format,proto3,enum=querier.v1.ProfileFormat" json:"format,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectMergeSpanProfileRequest) Reset() { *x = SelectMergeSpanProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectMergeSpanProfileRequest) String() string { @@ -482,8 +879,8 @@ func (x *SelectMergeSpanProfileRequest) String() string { func (*SelectMergeSpanProfileRequest) ProtoMessage() {} func (x *SelectMergeSpanProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[9] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -495,7 +892,7 @@ func (x *SelectMergeSpanProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectMergeSpanProfileRequest.ProtoReflect.Descriptor instead. func (*SelectMergeSpanProfileRequest) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{6} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{9} } func (x *SelectMergeSpanProfileRequest) GetProfileTypeID() string { @@ -548,22 +945,19 @@ func (x *SelectMergeSpanProfileRequest) GetFormat() ProfileFormat { } type SelectMergeSpanProfileResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Flamegraph *FlameGraph `protobuf:"bytes,1,opt,name=flamegraph,proto3" json:"flamegraph,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Flamegraph *FlameGraph `protobuf:"bytes,1,opt,name=flamegraph,proto3" json:"flamegraph,omitempty"` // Pyroscope tree bytes. - Tree []byte `protobuf:"bytes,2,opt,name=tree,proto3" json:"tree,omitempty"` + Tree []byte `protobuf:"bytes,2,opt,name=tree,proto3" json:"tree,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectMergeSpanProfileResponse) Reset() { *x = SelectMergeSpanProfileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectMergeSpanProfileResponse) String() string { @@ -573,8 +967,8 @@ func (x *SelectMergeSpanProfileResponse) String() string { func (*SelectMergeSpanProfileResponse) ProtoMessage() {} func (x *SelectMergeSpanProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[10] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -586,7 +980,7 @@ func (x *SelectMergeSpanProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectMergeSpanProfileResponse.ProtoReflect.Descriptor instead. func (*SelectMergeSpanProfileResponse) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{7} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{10} } func (x *SelectMergeSpanProfileResponse) GetFlamegraph() *FlameGraph { @@ -604,21 +998,19 @@ func (x *SelectMergeSpanProfileResponse) GetTree() []byte { } type DiffRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + // The format of each request is ignored; diff queries always compare trees. + Left *SelectMergeStacktracesRequest `protobuf:"bytes,1,opt,name=left,proto3" json:"left,omitempty"` + Right *SelectMergeStacktracesRequest `protobuf:"bytes,2,opt,name=right,proto3" json:"right,omitempty"` unknownFields protoimpl.UnknownFields - - Left *SelectMergeStacktracesRequest `protobuf:"bytes,1,opt,name=left,proto3" json:"left,omitempty"` - Right *SelectMergeStacktracesRequest `protobuf:"bytes,2,opt,name=right,proto3" json:"right,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DiffRequest) Reset() { *x = DiffRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DiffRequest) String() string { @@ -628,8 +1020,8 @@ func (x *DiffRequest) String() string { func (*DiffRequest) ProtoMessage() {} func (x *DiffRequest) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[11] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -641,7 +1033,7 @@ func (x *DiffRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DiffRequest.ProtoReflect.Descriptor instead. func (*DiffRequest) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{8} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{11} } func (x *DiffRequest) GetLeft() *SelectMergeStacktracesRequest { @@ -659,20 +1051,17 @@ func (x *DiffRequest) GetRight() *SelectMergeStacktracesRequest { } type DiffResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Flamegraph *FlameGraphDiff `protobuf:"bytes,1,opt,name=flamegraph,proto3" json:"flamegraph,omitempty"` unknownFields protoimpl.UnknownFields - - Flamegraph *FlameGraphDiff `protobuf:"bytes,1,opt,name=flamegraph,proto3" json:"flamegraph,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DiffResponse) Reset() { *x = DiffResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DiffResponse) String() string { @@ -682,8 +1071,8 @@ func (x *DiffResponse) String() string { func (*DiffResponse) ProtoMessage() {} func (x *DiffResponse) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[12] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -695,7 +1084,7 @@ func (x *DiffResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DiffResponse.ProtoReflect.Descriptor instead. func (*DiffResponse) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{9} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{12} } func (x *DiffResponse) GetFlamegraph() *FlameGraphDiff { @@ -706,23 +1095,20 @@ func (x *DiffResponse) GetFlamegraph() *FlameGraphDiff { } type FlameGraph struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` + Levels []*Level `protobuf:"bytes,2,rep,name=levels,proto3" json:"levels,omitempty"` + Total int64 `protobuf:"varint,3,opt,name=total,proto3" json:"total,omitempty"` + MaxSelf int64 `protobuf:"varint,4,opt,name=max_self,json=maxSelf,proto3" json:"max_self,omitempty"` unknownFields protoimpl.UnknownFields - - Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` - Levels []*Level `protobuf:"bytes,2,rep,name=levels,proto3" json:"levels,omitempty"` - Total int64 `protobuf:"varint,3,opt,name=total,proto3" json:"total,omitempty"` - MaxSelf int64 `protobuf:"varint,4,opt,name=max_self,json=maxSelf,proto3" json:"max_self,omitempty"` + sizeCache protoimpl.SizeCache } func (x *FlameGraph) Reset() { *x = FlameGraph{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlameGraph) String() string { @@ -732,8 +1118,8 @@ func (x *FlameGraph) String() string { func (*FlameGraph) ProtoMessage() {} func (x *FlameGraph) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[13] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -745,7 +1131,7 @@ func (x *FlameGraph) ProtoReflect() protoreflect.Message { // Deprecated: Use FlameGraph.ProtoReflect.Descriptor instead. func (*FlameGraph) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{10} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{13} } func (x *FlameGraph) GetNames() []string { @@ -777,25 +1163,22 @@ func (x *FlameGraph) GetMaxSelf() int64 { } type FlameGraphDiff struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` + Levels []*Level `protobuf:"bytes,2,rep,name=levels,proto3" json:"levels,omitempty"` + Total int64 `protobuf:"varint,3,opt,name=total,proto3" json:"total,omitempty"` + MaxSelf int64 `protobuf:"varint,4,opt,name=max_self,json=maxSelf,proto3" json:"max_self,omitempty"` + LeftTicks int64 `protobuf:"varint,5,opt,name=leftTicks,proto3" json:"leftTicks,omitempty"` + RightTicks int64 `protobuf:"varint,6,opt,name=rightTicks,proto3" json:"rightTicks,omitempty"` unknownFields protoimpl.UnknownFields - - Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` - Levels []*Level `protobuf:"bytes,2,rep,name=levels,proto3" json:"levels,omitempty"` - Total int64 `protobuf:"varint,3,opt,name=total,proto3" json:"total,omitempty"` - MaxSelf int64 `protobuf:"varint,4,opt,name=max_self,json=maxSelf,proto3" json:"max_self,omitempty"` - LeftTicks int64 `protobuf:"varint,5,opt,name=leftTicks,proto3" json:"leftTicks,omitempty"` - RightTicks int64 `protobuf:"varint,6,opt,name=rightTicks,proto3" json:"rightTicks,omitempty"` + sizeCache protoimpl.SizeCache } func (x *FlameGraphDiff) Reset() { *x = FlameGraphDiff{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlameGraphDiff) String() string { @@ -805,8 +1188,8 @@ func (x *FlameGraphDiff) String() string { func (*FlameGraphDiff) ProtoMessage() {} func (x *FlameGraphDiff) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[14] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -818,7 +1201,7 @@ func (x *FlameGraphDiff) ProtoReflect() protoreflect.Message { // Deprecated: Use FlameGraphDiff.ProtoReflect.Descriptor instead. func (*FlameGraphDiff) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{11} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{14} } func (x *FlameGraphDiff) GetNames() []string { @@ -864,20 +1247,17 @@ func (x *FlameGraphDiff) GetRightTicks() int64 { } type Level struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Values []int64 `protobuf:"varint,1,rep,packed,name=values,proto3" json:"values,omitempty"` unknownFields protoimpl.UnknownFields - - Values []int64 `protobuf:"varint,1,rep,packed,name=values,proto3" json:"values,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Level) Reset() { *x = Level{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Level) String() string { @@ -887,8 +1267,8 @@ func (x *Level) String() string { func (*Level) ProtoMessage() {} func (x *Level) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[15] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -900,7 +1280,7 @@ func (x *Level) ProtoReflect() protoreflect.Message { // Deprecated: Use Level.ProtoReflect.Descriptor instead. func (*Level) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{12} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{15} } func (x *Level) GetValues() []int64 { @@ -911,29 +1291,34 @@ func (x *Level) GetValues() []int64 { } type SelectMergeProfileRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` + // Profile Type ID string in the form + // ::::. ProfileTypeID string `protobuf:"bytes,1,opt,name=profile_typeID,json=profileTypeID,proto3" json:"profile_typeID,omitempty"` + // Label selector string LabelSelector string `protobuf:"bytes,2,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` // Milliseconds since epoch. Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` // Milliseconds since epoch. End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` - // Limit the nodes returned to only show the node with the max_node's biggest total + // Limit the nodes returned to only show the node with the max_node's biggest + // total MaxNodes *int64 `protobuf:"varint,5,opt,name=max_nodes,json=maxNodes,proto3,oneof" json:"max_nodes,omitempty"` // Select stack traces that match the provided selector. StackTraceSelector *v1.StackTraceSelector `protobuf:"bytes,6,opt,name=stack_trace_selector,json=stackTraceSelector,proto3,oneof" json:"stack_trace_selector,omitempty"` + // List of Profile UUIDs to query + ProfileIdSelector []string `protobuf:"bytes,7,rep,name=profile_id_selector,json=profileIdSelector,proto3" json:"profile_id_selector,omitempty"` + // List of trace IDs (32 hex characters, 128-bit) to filter samples by. + TraceIdSelector []string `protobuf:"bytes,8,rep,name=trace_id_selector,json=traceIdSelector,proto3" json:"trace_id_selector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectMergeProfileRequest) Reset() { *x = SelectMergeProfileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectMergeProfileRequest) String() string { @@ -943,8 +1328,8 @@ func (x *SelectMergeProfileRequest) String() string { func (*SelectMergeProfileRequest) ProtoMessage() {} func (x *SelectMergeProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[16] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -956,7 +1341,7 @@ func (x *SelectMergeProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectMergeProfileRequest.ProtoReflect.Descriptor instead. func (*SelectMergeProfileRequest) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{13} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{16} } func (x *SelectMergeProfileRequest) GetProfileTypeID() string { @@ -1001,12 +1386,26 @@ func (x *SelectMergeProfileRequest) GetStackTraceSelector() *v1.StackTraceSelect return nil } -type SelectSeriesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *SelectMergeProfileRequest) GetProfileIdSelector() []string { + if x != nil { + return x.ProfileIdSelector + } + return nil +} + +func (x *SelectMergeProfileRequest) GetTraceIdSelector() []string { + if x != nil { + return x.TraceIdSelector + } + return nil +} +type SelectSeriesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Profile Type ID string in the form + // ::::. ProfileTypeID string `protobuf:"bytes,1,opt,name=profile_typeID,json=profileTypeID,proto3" json:"profile_typeID,omitempty"` + // Label selector string LabelSelector string `protobuf:"bytes,2,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` // Milliseconds since epoch. Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` @@ -1018,15 +1417,19 @@ type SelectSeriesRequest struct { Aggregation *v1.TimeSeriesAggregationType `protobuf:"varint,7,opt,name=aggregation,proto3,enum=types.v1.TimeSeriesAggregationType,oneof" json:"aggregation,omitempty"` // Select stack traces that match the provided selector. StackTraceSelector *v1.StackTraceSelector `protobuf:"bytes,8,opt,name=stack_trace_selector,json=stackTraceSelector,proto3,oneof" json:"stack_trace_selector,omitempty"` + // Select the top N series by total value. + Limit *int64 `protobuf:"varint,9,opt,name=limit,proto3,oneof" json:"limit,omitempty"` + // Type of exemplars to include in the response. + ExemplarType v1.ExemplarType `protobuf:"varint,10,opt,name=exemplar_type,json=exemplarType,proto3,enum=types.v1.ExemplarType" json:"exemplar_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SelectSeriesRequest) Reset() { *x = SelectSeriesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectSeriesRequest) String() string { @@ -1036,8 +1439,8 @@ func (x *SelectSeriesRequest) String() string { func (*SelectSeriesRequest) ProtoMessage() {} func (x *SelectSeriesRequest) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[17] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1049,7 +1452,7 @@ func (x *SelectSeriesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectSeriesRequest.ProtoReflect.Descriptor instead. func (*SelectSeriesRequest) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{14} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{17} } func (x *SelectSeriesRequest) GetProfileTypeID() string { @@ -1108,21 +1511,32 @@ func (x *SelectSeriesRequest) GetStackTraceSelector() *v1.StackTraceSelector { return nil } +func (x *SelectSeriesRequest) GetLimit() int64 { + if x != nil && x.Limit != nil { + return *x.Limit + } + return 0 +} + +func (x *SelectSeriesRequest) GetExemplarType() v1.ExemplarType { + if x != nil { + return x.ExemplarType + } + return v1.ExemplarType(0) +} + type SelectSeriesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Series []*v1.Series `protobuf:"bytes,1,rep,name=series,proto3" json:"series,omitempty"` unknownFields protoimpl.UnknownFields - - Series []*v1.Series `protobuf:"bytes,1,rep,name=series,proto3" json:"series,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SelectSeriesResponse) Reset() { *x = SelectSeriesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SelectSeriesResponse) String() string { @@ -1132,8 +1546,8 @@ func (x *SelectSeriesResponse) String() string { func (*SelectSeriesResponse) ProtoMessage() {} func (x *SelectSeriesResponse) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[18] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1145,7 +1559,7 @@ func (x *SelectSeriesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectSeriesResponse.ProtoReflect.Descriptor instead. func (*SelectSeriesResponse) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{15} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{18} } func (x *SelectSeriesResponse) GetSeries() []*v1.Series { @@ -1155,23 +1569,182 @@ func (x *SelectSeriesResponse) GetSeries() []*v1.Series { return nil } -type AnalyzeQueryRequest struct { - state protoimpl.MessageState +type SelectHeatmapRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Profile Type ID string in the form + // ::::. + ProfileTypeID string `protobuf:"bytes,1,opt,name=profile_typeID,json=profileTypeID,proto3" json:"profile_typeID,omitempty"` + // Label selector string + LabelSelector string `protobuf:"bytes,2,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` + // Milliseconds since epoch. + Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` + // Milliseconds since epoch. + End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + // Query resolution step width in seconds + Step float64 `protobuf:"fixed64,5,opt,name=step,proto3" json:"step,omitempty"` + // Group by labels + GroupBy []string `protobuf:"bytes,6,rep,name=group_by,json=groupBy,proto3" json:"group_by,omitempty"` + // Query type: individual profiles or span profiles + QueryType HeatmapQueryType `protobuf:"varint,7,opt,name=query_type,json=queryType,proto3,enum=querier.v1.HeatmapQueryType" json:"query_type,omitempty"` + // Type of exemplars to include in the response. Needs to matching query_type or be NONE + ExemplarType v1.ExemplarType `protobuf:"varint,8,opt,name=exemplar_type,json=exemplarType,proto3,enum=types.v1.ExemplarType" json:"exemplar_type,omitempty"` + // Select the top N series by total value. + Limit *int64 `protobuf:"varint,9,opt,name=limit,proto3,oneof" json:"limit,omitempty"` + unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache +} + +func (x *SelectHeatmapRequest) Reset() { + *x = SelectHeatmapRequest{} + mi := &file_querier_v1_querier_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SelectHeatmapRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SelectHeatmapRequest) ProtoMessage() {} + +func (x *SelectHeatmapRequest) ProtoReflect() protoreflect.Message { + mi := &file_querier_v1_querier_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SelectHeatmapRequest.ProtoReflect.Descriptor instead. +func (*SelectHeatmapRequest) Descriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{19} +} + +func (x *SelectHeatmapRequest) GetProfileTypeID() string { + if x != nil { + return x.ProfileTypeID + } + return "" +} + +func (x *SelectHeatmapRequest) GetLabelSelector() string { + if x != nil { + return x.LabelSelector + } + return "" +} + +func (x *SelectHeatmapRequest) GetStart() int64 { + if x != nil { + return x.Start + } + return 0 +} + +func (x *SelectHeatmapRequest) GetEnd() int64 { + if x != nil { + return x.End + } + return 0 +} + +func (x *SelectHeatmapRequest) GetStep() float64 { + if x != nil { + return x.Step + } + return 0 +} + +func (x *SelectHeatmapRequest) GetGroupBy() []string { + if x != nil { + return x.GroupBy + } + return nil +} + +func (x *SelectHeatmapRequest) GetQueryType() HeatmapQueryType { + if x != nil { + return x.QueryType + } + return HeatmapQueryType_HEATMAP_QUERY_TYPE_UNSPECIFIED +} + +func (x *SelectHeatmapRequest) GetExemplarType() v1.ExemplarType { + if x != nil { + return x.ExemplarType + } + return v1.ExemplarType(0) +} + +func (x *SelectHeatmapRequest) GetLimit() int64 { + if x != nil && x.Limit != nil { + return *x.Limit + } + return 0 +} + +type SelectHeatmapResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Series []*v1.HeatmapSeries `protobuf:"bytes,1,rep,name=series,proto3" json:"series,omitempty"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} - Start int64 `protobuf:"varint,2,opt,name=start,proto3" json:"start,omitempty"` - End int64 `protobuf:"varint,3,opt,name=end,proto3" json:"end,omitempty"` - Query string `protobuf:"bytes,4,opt,name=query,proto3" json:"query,omitempty"` +func (x *SelectHeatmapResponse) Reset() { + *x = SelectHeatmapResponse{} + mi := &file_querier_v1_querier_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *AnalyzeQueryRequest) Reset() { - *x = AnalyzeQueryRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[16] +func (x *SelectHeatmapResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SelectHeatmapResponse) ProtoMessage() {} + +func (x *SelectHeatmapResponse) ProtoReflect() protoreflect.Message { + mi := &file_querier_v1_querier_proto_msgTypes[20] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SelectHeatmapResponse.ProtoReflect.Descriptor instead. +func (*SelectHeatmapResponse) Descriptor() ([]byte, []int) { + return file_querier_v1_querier_proto_rawDescGZIP(), []int{20} +} + +func (x *SelectHeatmapResponse) GetSeries() []*v1.HeatmapSeries { + if x != nil { + return x.Series } + return nil +} + +type AnalyzeQueryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Start int64 `protobuf:"varint,2,opt,name=start,proto3" json:"start,omitempty"` + End int64 `protobuf:"varint,3,opt,name=end,proto3" json:"end,omitempty"` + Query string `protobuf:"bytes,4,opt,name=query,proto3" json:"query,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AnalyzeQueryRequest) Reset() { + *x = AnalyzeQueryRequest{} + mi := &file_querier_v1_querier_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AnalyzeQueryRequest) String() string { @@ -1181,8 +1754,8 @@ func (x *AnalyzeQueryRequest) String() string { func (*AnalyzeQueryRequest) ProtoMessage() {} func (x *AnalyzeQueryRequest) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[21] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1194,7 +1767,7 @@ func (x *AnalyzeQueryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeQueryRequest.ProtoReflect.Descriptor instead. func (*AnalyzeQueryRequest) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{16} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{21} } func (x *AnalyzeQueryRequest) GetStart() int64 { @@ -1219,21 +1792,18 @@ func (x *AnalyzeQueryRequest) GetQuery() string { } type AnalyzeQueryResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + QueryScopes []*QueryScope `protobuf:"bytes,1,rep,name=query_scopes,json=queryScopes,proto3" json:"query_scopes,omitempty"` // detailed view of what the query will require + QueryImpact *QueryImpact `protobuf:"bytes,2,opt,name=query_impact,json=queryImpact,proto3" json:"query_impact,omitempty"` // summary of the query impact / performance unknownFields protoimpl.UnknownFields - - QueryScopes []*QueryScope `protobuf:"bytes,1,rep,name=query_scopes,json=queryScopes,proto3" json:"query_scopes,omitempty"` // detailed view of what the query will require - QueryImpact *QueryImpact `protobuf:"bytes,2,opt,name=query_impact,json=queryImpact,proto3" json:"query_impact,omitempty"` // summary of the query impact / performance + sizeCache protoimpl.SizeCache } func (x *AnalyzeQueryResponse) Reset() { *x = AnalyzeQueryResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AnalyzeQueryResponse) String() string { @@ -1243,8 +1813,8 @@ func (x *AnalyzeQueryResponse) String() string { func (*AnalyzeQueryResponse) ProtoMessage() {} func (x *AnalyzeQueryResponse) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[22] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1256,7 +1826,7 @@ func (x *AnalyzeQueryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeQueryResponse.ProtoReflect.Descriptor instead. func (*AnalyzeQueryResponse) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{17} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{22} } func (x *AnalyzeQueryResponse) GetQueryScopes() []*QueryScope { @@ -1274,12 +1844,10 @@ func (x *AnalyzeQueryResponse) GetQueryImpact() *QueryImpact { } type QueryScope struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ComponentType string `protobuf:"bytes,1,opt,name=component_type,json=componentType,proto3" json:"component_type,omitempty"` // a descriptive high level name of the component processing one part of the query (e.g., "short term storage") - ComponentCount uint64 `protobuf:"varint,2,opt,name=component_count,json=componentCount,proto3" json:"component_count,omitempty"` // how many components of this type will process the query (indicator of read-path replication) + state protoimpl.MessageState `protogen:"open.v1"` + ComponentType string `protobuf:"bytes,1,opt,name=component_type,json=componentType,proto3" json:"component_type,omitempty"` // a descriptive high level name of the component processing one part + // of the query (e.g., "short term storage") + ComponentCount uint64 `protobuf:"varint,2,opt,name=component_count,json=componentCount,proto3" json:"component_count,omitempty"` // how many components of this type will process BlockCount uint64 `protobuf:"varint,3,opt,name=block_count,json=blockCount,proto3" json:"block_count,omitempty"` SeriesCount uint64 `protobuf:"varint,4,opt,name=series_count,json=seriesCount,proto3" json:"series_count,omitempty"` ProfileCount uint64 `protobuf:"varint,5,opt,name=profile_count,json=profileCount,proto3" json:"profile_count,omitempty"` @@ -1287,15 +1855,15 @@ type QueryScope struct { IndexBytes uint64 `protobuf:"varint,7,opt,name=index_bytes,json=indexBytes,proto3" json:"index_bytes,omitempty"` ProfileBytes uint64 `protobuf:"varint,8,opt,name=profile_bytes,json=profileBytes,proto3" json:"profile_bytes,omitempty"` SymbolBytes uint64 `protobuf:"varint,9,opt,name=symbol_bytes,json=symbolBytes,proto3" json:"symbol_bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *QueryScope) Reset() { *x = QueryScope{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *QueryScope) String() string { @@ -1305,8 +1873,8 @@ func (x *QueryScope) String() string { func (*QueryScope) ProtoMessage() {} func (x *QueryScope) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[23] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1318,7 +1886,7 @@ func (x *QueryScope) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryScope.ProtoReflect.Descriptor instead. func (*QueryScope) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{18} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{23} } func (x *QueryScope) GetComponentType() string { @@ -1385,22 +1953,19 @@ func (x *QueryScope) GetSymbolBytes() uint64 { } type QueryImpact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TotalBytesInTimeRange uint64 `protobuf:"varint,2,opt,name=total_bytes_in_time_range,json=totalBytesInTimeRange,proto3" json:"total_bytes_in_time_range,omitempty"` - TotalQueriedSeries uint64 `protobuf:"varint,3,opt,name=total_queried_series,json=totalQueriedSeries,proto3" json:"total_queried_series,omitempty"` - DeduplicationNeeded bool `protobuf:"varint,4,opt,name=deduplication_needed,json=deduplicationNeeded,proto3" json:"deduplication_needed,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + TotalBytesInTimeRange uint64 `protobuf:"varint,2,opt,name=total_bytes_in_time_range,json=totalBytesInTimeRange,proto3" json:"total_bytes_in_time_range,omitempty"` + TotalQueriedSeries uint64 `protobuf:"varint,3,opt,name=total_queried_series,json=totalQueriedSeries,proto3" json:"total_queried_series,omitempty"` + DeduplicationNeeded bool `protobuf:"varint,4,opt,name=deduplication_needed,json=deduplicationNeeded,proto3" json:"deduplication_needed,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *QueryImpact) Reset() { *x = QueryImpact{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_v1_querier_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_v1_querier_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *QueryImpact) String() string { @@ -1410,8 +1975,8 @@ func (x *QueryImpact) String() string { func (*QueryImpact) ProtoMessage() {} func (x *QueryImpact) ProtoReflect() protoreflect.Message { - mi := &file_querier_v1_querier_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_querier_v1_querier_proto_msgTypes[24] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1423,7 +1988,7 @@ func (x *QueryImpact) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryImpact.ProtoReflect.Descriptor instead. func (*QueryImpact) Descriptor() ([]byte, []int) { - return file_querier_v1_querier_proto_rawDescGZIP(), []int{19} + return file_querier_v1_querier_proto_rawDescGZIP(), []int{24} } func (x *QueryImpact) GetTotalBytesInTimeRange() uint64 { @@ -1449,385 +2014,332 @@ func (x *QueryImpact) GetDeduplicationNeeded() bool { var File_querier_v1_querier_proto protoreflect.FileDescriptor -var file_querier_v1_querier_proto_rawDesc = []byte{ - 0x0a, 0x18, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x76, - 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x14, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3d, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x03, 0x65, 0x6e, 0x64, 0x22, 0x52, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0d, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x74, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x74, - 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x74, - 0x63, 0x68, 0x65, 0x72, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x41, - 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2f, 0x0a, 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x09, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x53, 0x65, - 0x74, 0x22, 0xf8, 0x01, 0x0a, 0x1d, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, - 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x09, 0x6d, 0x61, 0x78, - 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, - 0x6d, 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x06, 0x66, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x71, 0x75, - 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x42, 0x0c, - 0x0a, 0x0a, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x6c, 0x0a, 0x1e, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, - 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x0a, 0x66, 0x6c, 0x61, 0x6d, - 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x72, 0x65, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x72, 0x65, 0x65, 0x22, 0x9d, 0x02, 0x0a, 0x1d, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x49, 0x44, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x49, 0x44, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x70, - 0x61, 0x6e, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, - 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x6e, - 0x6f, 0x64, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x6d, 0x61, - 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x06, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x46, 0x6f, - 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x42, 0x0c, 0x0a, 0x0a, - 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x6c, 0x0a, 0x1e, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, - 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6c, - 0x61, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x0a, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x74, 0x72, 0x65, 0x65, 0x22, 0x8d, 0x01, 0x0a, 0x0b, 0x44, 0x69, 0x66, - 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x6c, 0x65, 0x66, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x04, 0x6c, 0x65, 0x66, 0x74, 0x12, 0x3f, 0x0a, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x4a, 0x0a, 0x0c, 0x44, 0x69, 0x66, 0x66, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x6d, - 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x71, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x47, - 0x72, 0x61, 0x70, 0x68, 0x44, 0x69, 0x66, 0x66, 0x52, 0x0a, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x22, 0x7e, 0x0a, 0x0a, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x47, 0x72, 0x61, - 0x70, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x06, 0x6c, 0x65, 0x76, 0x65, - 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x06, 0x6c, 0x65, 0x76, - 0x65, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, - 0x5f, 0x73, 0x65, 0x6c, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x61, 0x78, - 0x53, 0x65, 0x6c, 0x66, 0x22, 0xc0, 0x01, 0x0a, 0x0e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x44, 0x69, 0x66, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x29, 0x0a, - 0x06, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, - 0x52, 0x06, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x19, - 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x6c, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x07, 0x6d, 0x61, 0x78, 0x53, 0x65, 0x6c, 0x66, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x65, 0x66, - 0x74, 0x54, 0x69, 0x63, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x65, - 0x66, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x69, 0x67, 0x68, 0x74, - 0x54, 0x69, 0x63, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x69, 0x67, - 0x68, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x73, 0x22, 0x1f, 0x0a, 0x05, 0x4c, 0x65, 0x76, 0x65, 0x6c, - 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, - 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xaf, 0x02, 0x0a, 0x19, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, 0x12, 0x25, 0x0a, - 0x0e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, - 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x09, - 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x48, - 0x00, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x53, - 0x0a, 0x14, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x73, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, - 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x48, 0x01, 0x52, 0x12, 0x73, 0x74, - 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, 0x65, - 0x73, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, - 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x84, 0x03, 0x0a, 0x13, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x44, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x5f, 0x62, 0x79, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x42, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x74, 0x65, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x04, 0x73, 0x74, 0x65, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, - 0x65, 0x48, 0x00, 0x52, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x88, 0x01, 0x01, 0x12, 0x53, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, - 0x63, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, - 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x48, - 0x01, 0x52, 0x12, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x74, 0x61, - 0x63, 0x6b, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x22, 0x40, 0x0a, 0x14, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x73, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x06, 0x73, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x22, 0x53, 0x0a, 0x13, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, - 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x8d, 0x01, 0x0a, 0x14, 0x41, 0x6e, 0x61, - 0x6c, 0x79, 0x7a, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x39, 0x0a, 0x0c, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, - 0x0b, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0c, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x69, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x52, 0x0b, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x49, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x22, 0xd1, 0x02, 0x0a, 0x0a, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x27, - 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, - 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x79, 0x6d, - 0x62, 0x6f, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0b, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0xac, 0x01, 0x0a, - 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x12, 0x38, 0x0a, 0x19, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x69, 0x6e, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x49, 0x6e, 0x54, 0x69, 0x6d, - 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x64, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x64, 0x75, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x65, 0x65, 0x64, 0x65, 0x64, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x64, 0x65, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x65, 0x65, 0x64, 0x65, 0x64, 0x2a, 0x67, 0x0a, 0x0d, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1e, 0x0a, 0x1a, - 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, - 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x46, - 0x4c, 0x41, 0x4d, 0x45, 0x47, 0x52, 0x41, 0x50, 0x48, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x50, - 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x54, 0x52, - 0x45, 0x45, 0x10, 0x02, 0x32, 0xbb, 0x07, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x53, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0b, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, - 0x19, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x71, 0x0a, 0x16, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, - 0x65, 0x73, 0x12, 0x29, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, - 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x71, 0x0a, 0x16, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x29, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, - 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, - 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x12, 0x25, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, - 0x00, 0x12, 0x53, 0x0a, 0x0c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x12, 0x1f, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x17, - 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x53, 0x0a, - 0x0c, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1f, 0x2e, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, - 0x7a, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, - 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6e, 0x61, 0x6c, - 0x79, 0x7a, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x42, 0xab, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, - 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x51, 0x58, 0x58, 0xaa, - 0x02, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0a, 0x51, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x16, 0x51, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x72, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x3a, 0x3a, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_querier_v1_querier_proto_rawDesc = "" + + "\n" + + "\x18querier/v1/querier.proto\x12\n" + + "querier.v1\x1a$gnostic/openapi/v3/annotations.proto\x1a\x17google/v1/profile.proto\x1a\x14types/v1/types.proto\"i\n" + + "\x13ProfileTypesRequest\x12*\n" + + "\x05start\x18\x01 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x02 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\"R\n" + + "\x14ProfileTypesResponse\x12:\n" + + "\rprofile_types\x18\x01 \x03(\v2\x15.types.v1.ProfileTypeR\fprofileTypes\"\xc7\x01\n" + + "\rSeriesRequest\x12A\n" + + "\bmatchers\x18\x01 \x03(\tB%\xbaG\": \x12\x1e['{namespace=\"my-namespace\"}']R\bmatchers\x12\x1f\n" + + "\vlabel_names\x18\x02 \x03(\tR\n" + + "labelNames\x12*\n" + + "\x05start\x18\x03 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x04 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\"A\n" + + "\x0eSeriesResponse\x12/\n" + + "\n" + + "labels_set\x18\x02 \x03(\v2\x10.types.v1.LabelsR\tlabelsSet\"\xbe\x06\n" + + "\x1dSelectMergeStacktracesRequest\x12Y\n" + + "\x0eprofile_typeID\x18\x01 \x01(\tB2\xbaG/:-\x12+process_cpu:cpu:nanoseconds:cpu:nanosecondsR\rprofileTypeID\x12J\n" + + "\x0elabel_selector\x18\x02 \x01(\tB#\xbaG :\x1e\x12\x1c'{namespace=\"my-namespace\"}'R\rlabelSelector\x12*\n" + + "\x05start\x18\x03 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x04 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\x12 \n" + + "\tmax_nodes\x18\x05 \x01(\x03H\x00R\bmaxNodes\x88\x01\x01\x121\n" + + "\x06format\x18\x06 \x01(\x0e2\x19.querier.v1.ProfileFormatR\x06format\x12S\n" + + "\x14stack_trace_selector\x18\a \x01(\v2\x1c.types.v1.StackTraceSelectorH\x01R\x12stackTraceSelector\x88\x01\x01\x12_\n" + + "\x13profile_id_selector\x18\b \x03(\tB/\xbaG,:*\x12(['7c9e6679-7425-40de-944b-e07fc1f90ae7']R\x11profileIdSelector\x128\n" + + "\x05async\x18\t \x01(\v2\x1d.querier.v1.AsyncQueryRequestH\x02R\x05async\x88\x01\x01\x12W\n" + + "\x11trace_id_selector\x18\n" + + " \x03(\tB+\xbaG(:&\x12$['7c9e66797425440de944be07fc1f90ae']R\x0ftraceIdSelector\x12S\n" + + "\rspan_selector\x18\v \x03(\tB.\xbaG+:)\x12'['9a517183f26a089d','5a4fe264a9c987fe']R\fspanSelectorB\f\n" + + "\n" + + "_max_nodesB\x17\n" + + "\x15_stack_trace_selectorB\b\n" + + "\x06_async\"\xf3\x01\n" + + "\x1eSelectMergeStacktracesResponse\x126\n" + + "\n" + + "flamegraph\x18\x01 \x01(\v2\x16.querier.v1.FlameGraphR\n" + + "flamegraph\x12\x12\n" + + "\x04tree\x18\x02 \x01(\fR\x04tree\x12\x10\n" + + "\x03dot\x18\x03 \x01(\tR\x03dot\x129\n" + + "\x05async\x18\x04 \x01(\v2\x1e.querier.v1.AsyncQueryResponseH\x00R\x05async\x88\x01\x01\x12.\n" + + "\x05pprof\x18\x05 \x01(\v2\x18.querier.v1.PprofProfileR\x05pprofB\b\n" + + "\x06_async\"<\n" + + "\fPprofProfile\x12,\n" + + "\aprofile\x18\x01 \x01(\v2\x12.google.v1.ProfileR\aprofile\"b\n" + + "\x11AsyncQueryRequest\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\tR\trequestId\x12.\n" + + "\x04type\x18\x02 \x01(\x0e2\x1a.querier.v1.AsyncQueryTypeR\x04type\"\x8e\x01\n" + + "\x12AsyncQueryResponse\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\tR\trequestId\x124\n" + + "\x06status\x18\x02 \x01(\x0e2\x1c.querier.v1.AsyncQueryStatusR\x06status\x12#\n" + + "\rerror_message\x18\x03 \x01(\tR\ferrorMessage\"\xd2\x03\n" + + "\x1dSelectMergeSpanProfileRequest\x12Y\n" + + "\x0eprofile_typeID\x18\x01 \x01(\tB2\xbaG/:-\x12+process_cpu:cpu:nanoseconds:cpu:nanosecondsR\rprofileTypeID\x12J\n" + + "\x0elabel_selector\x18\x02 \x01(\tB#\xbaG :\x1e\x12\x1c'{namespace=\"my-namespace\"}'R\rlabelSelector\x12S\n" + + "\rspan_selector\x18\x03 \x03(\tB.\xbaG+:)\x12'['9a517183f26a089d','5a4fe264a9c987fe']R\fspanSelector\x12*\n" + + "\x05start\x18\x04 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x05 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\x12 \n" + + "\tmax_nodes\x18\x06 \x01(\x03H\x00R\bmaxNodes\x88\x01\x01\x121\n" + + "\x06format\x18\a \x01(\x0e2\x19.querier.v1.ProfileFormatR\x06formatB\f\n" + + "\n" + + "_max_nodes\"l\n" + + "\x1eSelectMergeSpanProfileResponse\x126\n" + + "\n" + + "flamegraph\x18\x01 \x01(\v2\x16.querier.v1.FlameGraphR\n" + + "flamegraph\x12\x12\n" + + "\x04tree\x18\x02 \x01(\fR\x04tree\"\x8d\x01\n" + + "\vDiffRequest\x12=\n" + + "\x04left\x18\x01 \x01(\v2).querier.v1.SelectMergeStacktracesRequestR\x04left\x12?\n" + + "\x05right\x18\x02 \x01(\v2).querier.v1.SelectMergeStacktracesRequestR\x05right\"J\n" + + "\fDiffResponse\x12:\n" + + "\n" + + "flamegraph\x18\x01 \x01(\v2\x1a.querier.v1.FlameGraphDiffR\n" + + "flamegraph\"~\n" + + "\n" + + "FlameGraph\x12\x14\n" + + "\x05names\x18\x01 \x03(\tR\x05names\x12)\n" + + "\x06levels\x18\x02 \x03(\v2\x11.querier.v1.LevelR\x06levels\x12\x14\n" + + "\x05total\x18\x03 \x01(\x03R\x05total\x12\x19\n" + + "\bmax_self\x18\x04 \x01(\x03R\amaxSelf\"\xc0\x01\n" + + "\x0eFlameGraphDiff\x12\x14\n" + + "\x05names\x18\x01 \x03(\tR\x05names\x12)\n" + + "\x06levels\x18\x02 \x03(\v2\x11.querier.v1.LevelR\x06levels\x12\x14\n" + + "\x05total\x18\x03 \x01(\x03R\x05total\x12\x19\n" + + "\bmax_self\x18\x04 \x01(\x03R\amaxSelf\x12\x1c\n" + + "\tleftTicks\x18\x05 \x01(\x03R\tleftTicks\x12\x1e\n" + + "\n" + + "rightTicks\x18\x06 \x01(\x03R\n" + + "rightTicks\"\x1f\n" + + "\x05Level\x12\x16\n" + + "\x06values\x18\x01 \x03(\x03R\x06values\"\xee\x04\n" + + "\x19SelectMergeProfileRequest\x12Y\n" + + "\x0eprofile_typeID\x18\x01 \x01(\tB2\xbaG/:-\x12+process_cpu:cpu:nanoseconds:cpu:nanosecondsR\rprofileTypeID\x12J\n" + + "\x0elabel_selector\x18\x02 \x01(\tB#\xbaG :\x1e\x12\x1c'{namespace=\"my-namespace\"}'R\rlabelSelector\x12*\n" + + "\x05start\x18\x03 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x04 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\x12 \n" + + "\tmax_nodes\x18\x05 \x01(\x03H\x00R\bmaxNodes\x88\x01\x01\x12S\n" + + "\x14stack_trace_selector\x18\x06 \x01(\v2\x1c.types.v1.StackTraceSelectorH\x01R\x12stackTraceSelector\x88\x01\x01\x12_\n" + + "\x13profile_id_selector\x18\a \x03(\tB/\xbaG,:*\x12(['7c9e6679-7425-40de-944b-e07fc1f90ae7']R\x11profileIdSelector\x12W\n" + + "\x11trace_id_selector\x18\b \x03(\tB+\xbaG(:&\x12$['7c9e66797425440de944be07fc1f90ae']R\x0ftraceIdSelectorB\f\n" + + "\n" + + "_max_nodesB\x17\n" + + "\x15_stack_trace_selector\"\xfb\x04\n" + + "\x13SelectSeriesRequest\x12Y\n" + + "\x0eprofile_typeID\x18\x01 \x01(\tB2\xbaG/:-\x12+process_cpu:cpu:nanoseconds:cpu:nanosecondsR\rprofileTypeID\x12J\n" + + "\x0elabel_selector\x18\x02 \x01(\tB#\xbaG :\x1e\x12\x1c'{namespace=\"my-namespace\"}'R\rlabelSelector\x12*\n" + + "\x05start\x18\x03 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x04 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\x12)\n" + + "\bgroup_by\x18\x05 \x03(\tB\x0e\xbaG\v:\t\x12\a['pod']R\agroupBy\x12\x12\n" + + "\x04step\x18\x06 \x01(\x01R\x04step\x12J\n" + + "\vaggregation\x18\a \x01(\x0e2#.types.v1.TimeSeriesAggregationTypeH\x00R\vaggregation\x88\x01\x01\x12S\n" + + "\x14stack_trace_selector\x18\b \x01(\v2\x1c.types.v1.StackTraceSelectorH\x01R\x12stackTraceSelector\x88\x01\x01\x12\x19\n" + + "\x05limit\x18\t \x01(\x03H\x02R\x05limit\x88\x01\x01\x12;\n" + + "\rexemplar_type\x18\n" + + " \x01(\x0e2\x16.types.v1.ExemplarTypeR\fexemplarTypeB\x0e\n" + + "\f_aggregationB\x17\n" + + "\x15_stack_trace_selectorB\b\n" + + "\x06_limit\"@\n" + + "\x14SelectSeriesResponse\x12(\n" + + "\x06series\x18\x01 \x03(\v2\x10.types.v1.SeriesR\x06series\"\xae\x04\n" + + "\x14SelectHeatmapRequest\x12Y\n" + + "\x0eprofile_typeID\x18\x01 \x01(\tB2\xbaG/:-\x12+process_cpu:cpu:nanoseconds:cpu:nanosecondsR\rprofileTypeID\x12J\n" + + "\x0elabel_selector\x18\x02 \x01(\tB#\xbaG :\x1e\x12\x1c'{namespace=\"my-namespace\"}'R\rlabelSelector\x12*\n" + + "\x05start\x18\x03 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x04 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\x12\x12\n" + + "\x04step\x18\x05 \x01(\x01R\x04step\x12)\n" + + "\bgroup_by\x18\x06 \x03(\tB\x0e\xbaG\v:\t\x12\a['pod']R\agroupBy\x12]\n" + + "\n" + + "query_type\x18\a \x01(\x0e2\x1c.querier.v1.HeatmapQueryTypeB \xbaG\x1d:\x1b\x12\x19'HEATMAP_QUERY_TYPE_SPAN'R\tqueryType\x12X\n" + + "\rexemplar_type\x18\b \x01(\x0e2\x16.types.v1.ExemplarTypeB\x1b\xbaG\x18:\x16\x12\x14'EXEMPLAR_TYPE_SPAN'R\fexemplarType\x12\x19\n" + + "\x05limit\x18\t \x01(\x03H\x00R\x05limit\x88\x01\x01B\b\n" + + "\x06_limit\"H\n" + + "\x15SelectHeatmapResponse\x12/\n" + + "\x06series\x18\x01 \x03(\v2\x17.types.v1.HeatmapSeriesR\x06series\"S\n" + + "\x13AnalyzeQueryRequest\x12\x14\n" + + "\x05start\x18\x02 \x01(\x03R\x05start\x12\x10\n" + + "\x03end\x18\x03 \x01(\x03R\x03end\x12\x14\n" + + "\x05query\x18\x04 \x01(\tR\x05query\"\x8d\x01\n" + + "\x14AnalyzeQueryResponse\x129\n" + + "\fquery_scopes\x18\x01 \x03(\v2\x16.querier.v1.QueryScopeR\vqueryScopes\x12:\n" + + "\fquery_impact\x18\x02 \x01(\v2\x17.querier.v1.QueryImpactR\vqueryImpact\"\xd1\x02\n" + + "\n" + + "QueryScope\x12%\n" + + "\x0ecomponent_type\x18\x01 \x01(\tR\rcomponentType\x12'\n" + + "\x0fcomponent_count\x18\x02 \x01(\x04R\x0ecomponentCount\x12\x1f\n" + + "\vblock_count\x18\x03 \x01(\x04R\n" + + "blockCount\x12!\n" + + "\fseries_count\x18\x04 \x01(\x04R\vseriesCount\x12#\n" + + "\rprofile_count\x18\x05 \x01(\x04R\fprofileCount\x12!\n" + + "\fsample_count\x18\x06 \x01(\x04R\vsampleCount\x12\x1f\n" + + "\vindex_bytes\x18\a \x01(\x04R\n" + + "indexBytes\x12#\n" + + "\rprofile_bytes\x18\b \x01(\x04R\fprofileBytes\x12!\n" + + "\fsymbol_bytes\x18\t \x01(\x04R\vsymbolBytes\"\xac\x01\n" + + "\vQueryImpact\x128\n" + + "\x19total_bytes_in_time_range\x18\x02 \x01(\x04R\x15totalBytesInTimeRange\x120\n" + + "\x14total_queried_series\x18\x03 \x01(\x04R\x12totalQueriedSeries\x121\n" + + "\x14deduplication_needed\x18\x04 \x01(\bR\x13deduplicationNeeded*\x99\x01\n" + + "\rProfileFormat\x12\x1e\n" + + "\x1aPROFILE_FORMAT_UNSPECIFIED\x10\x00\x12\x1d\n" + + "\x19PROFILE_FORMAT_FLAMEGRAPH\x10\x01\x12\x17\n" + + "\x13PROFILE_FORMAT_TREE\x10\x02\x12\x16\n" + + "\x12PROFILE_FORMAT_DOT\x10\x03\x12\x18\n" + + "\x14PROFILE_FORMAT_PPROF\x10\x04*K\n" + + "\x0eAsyncQueryType\x12\x1d\n" + + "\x19ASYNC_QUERY_TYPE_DISABLED\x10\x00\x12\x1a\n" + + "\x16ASYNC_QUERY_TYPE_FORCE\x10\x01*\x96\x01\n" + + "\x10AsyncQueryStatus\x12\x1e\n" + + "\x1aASYNC_QUERY_STATUS_UNKNOWN\x10\x00\x12\"\n" + + "\x1eASYNC_QUERY_STATUS_IN_PROGRESS\x10\x01\x12\x1e\n" + + "\x1aASYNC_QUERY_STATUS_SUCCESS\x10\x02\x12\x1e\n" + + "\x1aASYNC_QUERY_STATUS_FAILURE\x10\x03*v\n" + + "\x10HeatmapQueryType\x12\"\n" + + "\x1eHEATMAP_QUERY_TYPE_UNSPECIFIED\x10\x00\x12!\n" + + "\x1dHEATMAP_QUERY_TYPE_INDIVIDUAL\x10\x01\x12\x1b\n" + + "\x17HEATMAP_QUERY_TYPE_SPAN\x10\x022\xe5\t\n" + + "\x0eQuerierService\x12d\n" + + "\fProfileTypes\x12\x1f.querier.v1.ProfileTypesRequest\x1a .querier.v1.ProfileTypesResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12]\n" + + "\vLabelValues\x12\x1c.types.v1.LabelValuesRequest\x1a\x1d.types.v1.LabelValuesResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12Z\n" + + "\n" + + "LabelNames\x12\x1b.types.v1.LabelNamesRequest\x1a\x1c.types.v1.LabelNamesResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12R\n" + + "\x06Series\x12\x19.querier.v1.SeriesRequest\x1a\x1a.querier.v1.SeriesResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12\x82\x01\n" + + "\x16SelectMergeStacktraces\x12).querier.v1.SelectMergeStacktracesRequest\x1a*.querier.v1.SelectMergeStacktracesResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12\x82\x01\n" + + "\x16SelectMergeSpanProfile\x12).querier.v1.SelectMergeSpanProfileRequest\x1a*.querier.v1.SelectMergeSpanProfileResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12b\n" + + "\x12SelectMergeProfile\x12%.querier.v1.SelectMergeProfileRequest\x1a\x12.google.v1.Profile\"\x11\xbaG\x0e\n" + + "\fscope/public\x12d\n" + + "\fSelectSeries\x12\x1f.querier.v1.SelectSeriesRequest\x1a .querier.v1.SelectSeriesResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12g\n" + + "\rSelectHeatmap\x12 .querier.v1.SelectHeatmapRequest\x1a!.querier.v1.SelectHeatmapResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12L\n" + + "\x04Diff\x12\x17.querier.v1.DiffRequest\x1a\x18.querier.v1.DiffResponse\"\x11\xbaG\x0e\n" + + "\fscope/public\x12k\n" + + "\x0fGetProfileStats\x12 .types.v1.GetProfileStatsRequest\x1a!.types.v1.GetProfileStatsResponse\"\x13\xbaG\x10\n" + + "\x0escope/internal\x12f\n" + + "\fAnalyzeQuery\x12\x1f.querier.v1.AnalyzeQueryRequest\x1a .querier.v1.AnalyzeQueryResponse\"\x13\xbaG\x10\n" + + "\x0escope/internalB\xab\x01\n" + + "\x0ecom.querier.v1B\fQuerierProtoP\x01ZBgithub.com/grafana/pyroscope/api/gen/proto/go/querier/v1;querierv1\xa2\x02\x03QXX\xaa\x02\n" + + "Querier.V1\xca\x02\n" + + "Querier\\V1\xe2\x02\x16Querier\\V1\\GPBMetadata\xea\x02\vQuerier::V1b\x06proto3" var ( file_querier_v1_querier_proto_rawDescOnce sync.Once - file_querier_v1_querier_proto_rawDescData = file_querier_v1_querier_proto_rawDesc + file_querier_v1_querier_proto_rawDescData []byte ) func file_querier_v1_querier_proto_rawDescGZIP() []byte { file_querier_v1_querier_proto_rawDescOnce.Do(func() { - file_querier_v1_querier_proto_rawDescData = protoimpl.X.CompressGZIP(file_querier_v1_querier_proto_rawDescData) + file_querier_v1_querier_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_querier_v1_querier_proto_rawDesc), len(file_querier_v1_querier_proto_rawDesc))) }) return file_querier_v1_querier_proto_rawDescData } -var file_querier_v1_querier_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_querier_v1_querier_proto_msgTypes = make([]protoimpl.MessageInfo, 20) -var file_querier_v1_querier_proto_goTypes = []interface{}{ +var file_querier_v1_querier_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_querier_v1_querier_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_querier_v1_querier_proto_goTypes = []any{ (ProfileFormat)(0), // 0: querier.v1.ProfileFormat - (*ProfileTypesRequest)(nil), // 1: querier.v1.ProfileTypesRequest - (*ProfileTypesResponse)(nil), // 2: querier.v1.ProfileTypesResponse - (*SeriesRequest)(nil), // 3: querier.v1.SeriesRequest - (*SeriesResponse)(nil), // 4: querier.v1.SeriesResponse - (*SelectMergeStacktracesRequest)(nil), // 5: querier.v1.SelectMergeStacktracesRequest - (*SelectMergeStacktracesResponse)(nil), // 6: querier.v1.SelectMergeStacktracesResponse - (*SelectMergeSpanProfileRequest)(nil), // 7: querier.v1.SelectMergeSpanProfileRequest - (*SelectMergeSpanProfileResponse)(nil), // 8: querier.v1.SelectMergeSpanProfileResponse - (*DiffRequest)(nil), // 9: querier.v1.DiffRequest - (*DiffResponse)(nil), // 10: querier.v1.DiffResponse - (*FlameGraph)(nil), // 11: querier.v1.FlameGraph - (*FlameGraphDiff)(nil), // 12: querier.v1.FlameGraphDiff - (*Level)(nil), // 13: querier.v1.Level - (*SelectMergeProfileRequest)(nil), // 14: querier.v1.SelectMergeProfileRequest - (*SelectSeriesRequest)(nil), // 15: querier.v1.SelectSeriesRequest - (*SelectSeriesResponse)(nil), // 16: querier.v1.SelectSeriesResponse - (*AnalyzeQueryRequest)(nil), // 17: querier.v1.AnalyzeQueryRequest - (*AnalyzeQueryResponse)(nil), // 18: querier.v1.AnalyzeQueryResponse - (*QueryScope)(nil), // 19: querier.v1.QueryScope - (*QueryImpact)(nil), // 20: querier.v1.QueryImpact - (*v1.ProfileType)(nil), // 21: types.v1.ProfileType - (*v1.Labels)(nil), // 22: types.v1.Labels - (*v1.StackTraceSelector)(nil), // 23: types.v1.StackTraceSelector - (v1.TimeSeriesAggregationType)(0), // 24: types.v1.TimeSeriesAggregationType - (*v1.Series)(nil), // 25: types.v1.Series - (*v1.LabelValuesRequest)(nil), // 26: types.v1.LabelValuesRequest - (*v1.LabelNamesRequest)(nil), // 27: types.v1.LabelNamesRequest - (*v1.GetProfileStatsRequest)(nil), // 28: types.v1.GetProfileStatsRequest - (*v1.LabelValuesResponse)(nil), // 29: types.v1.LabelValuesResponse - (*v1.LabelNamesResponse)(nil), // 30: types.v1.LabelNamesResponse - (*v11.Profile)(nil), // 31: google.v1.Profile - (*v1.GetProfileStatsResponse)(nil), // 32: types.v1.GetProfileStatsResponse + (AsyncQueryType)(0), // 1: querier.v1.AsyncQueryType + (AsyncQueryStatus)(0), // 2: querier.v1.AsyncQueryStatus + (HeatmapQueryType)(0), // 3: querier.v1.HeatmapQueryType + (*ProfileTypesRequest)(nil), // 4: querier.v1.ProfileTypesRequest + (*ProfileTypesResponse)(nil), // 5: querier.v1.ProfileTypesResponse + (*SeriesRequest)(nil), // 6: querier.v1.SeriesRequest + (*SeriesResponse)(nil), // 7: querier.v1.SeriesResponse + (*SelectMergeStacktracesRequest)(nil), // 8: querier.v1.SelectMergeStacktracesRequest + (*SelectMergeStacktracesResponse)(nil), // 9: querier.v1.SelectMergeStacktracesResponse + (*PprofProfile)(nil), // 10: querier.v1.PprofProfile + (*AsyncQueryRequest)(nil), // 11: querier.v1.AsyncQueryRequest + (*AsyncQueryResponse)(nil), // 12: querier.v1.AsyncQueryResponse + (*SelectMergeSpanProfileRequest)(nil), // 13: querier.v1.SelectMergeSpanProfileRequest + (*SelectMergeSpanProfileResponse)(nil), // 14: querier.v1.SelectMergeSpanProfileResponse + (*DiffRequest)(nil), // 15: querier.v1.DiffRequest + (*DiffResponse)(nil), // 16: querier.v1.DiffResponse + (*FlameGraph)(nil), // 17: querier.v1.FlameGraph + (*FlameGraphDiff)(nil), // 18: querier.v1.FlameGraphDiff + (*Level)(nil), // 19: querier.v1.Level + (*SelectMergeProfileRequest)(nil), // 20: querier.v1.SelectMergeProfileRequest + (*SelectSeriesRequest)(nil), // 21: querier.v1.SelectSeriesRequest + (*SelectSeriesResponse)(nil), // 22: querier.v1.SelectSeriesResponse + (*SelectHeatmapRequest)(nil), // 23: querier.v1.SelectHeatmapRequest + (*SelectHeatmapResponse)(nil), // 24: querier.v1.SelectHeatmapResponse + (*AnalyzeQueryRequest)(nil), // 25: querier.v1.AnalyzeQueryRequest + (*AnalyzeQueryResponse)(nil), // 26: querier.v1.AnalyzeQueryResponse + (*QueryScope)(nil), // 27: querier.v1.QueryScope + (*QueryImpact)(nil), // 28: querier.v1.QueryImpact + (*v1.ProfileType)(nil), // 29: types.v1.ProfileType + (*v1.Labels)(nil), // 30: types.v1.Labels + (*v1.StackTraceSelector)(nil), // 31: types.v1.StackTraceSelector + (*v11.Profile)(nil), // 32: google.v1.Profile + (v1.TimeSeriesAggregationType)(0), // 33: types.v1.TimeSeriesAggregationType + (v1.ExemplarType)(0), // 34: types.v1.ExemplarType + (*v1.Series)(nil), // 35: types.v1.Series + (*v1.HeatmapSeries)(nil), // 36: types.v1.HeatmapSeries + (*v1.LabelValuesRequest)(nil), // 37: types.v1.LabelValuesRequest + (*v1.LabelNamesRequest)(nil), // 38: types.v1.LabelNamesRequest + (*v1.GetProfileStatsRequest)(nil), // 39: types.v1.GetProfileStatsRequest + (*v1.LabelValuesResponse)(nil), // 40: types.v1.LabelValuesResponse + (*v1.LabelNamesResponse)(nil), // 41: types.v1.LabelNamesResponse + (*v1.GetProfileStatsResponse)(nil), // 42: types.v1.GetProfileStatsResponse } var file_querier_v1_querier_proto_depIdxs = []int32{ - 21, // 0: querier.v1.ProfileTypesResponse.profile_types:type_name -> types.v1.ProfileType - 22, // 1: querier.v1.SeriesResponse.labels_set:type_name -> types.v1.Labels + 29, // 0: querier.v1.ProfileTypesResponse.profile_types:type_name -> types.v1.ProfileType + 30, // 1: querier.v1.SeriesResponse.labels_set:type_name -> types.v1.Labels 0, // 2: querier.v1.SelectMergeStacktracesRequest.format:type_name -> querier.v1.ProfileFormat - 11, // 3: querier.v1.SelectMergeStacktracesResponse.flamegraph:type_name -> querier.v1.FlameGraph - 0, // 4: querier.v1.SelectMergeSpanProfileRequest.format:type_name -> querier.v1.ProfileFormat - 11, // 5: querier.v1.SelectMergeSpanProfileResponse.flamegraph:type_name -> querier.v1.FlameGraph - 5, // 6: querier.v1.DiffRequest.left:type_name -> querier.v1.SelectMergeStacktracesRequest - 5, // 7: querier.v1.DiffRequest.right:type_name -> querier.v1.SelectMergeStacktracesRequest - 12, // 8: querier.v1.DiffResponse.flamegraph:type_name -> querier.v1.FlameGraphDiff - 13, // 9: querier.v1.FlameGraph.levels:type_name -> querier.v1.Level - 13, // 10: querier.v1.FlameGraphDiff.levels:type_name -> querier.v1.Level - 23, // 11: querier.v1.SelectMergeProfileRequest.stack_trace_selector:type_name -> types.v1.StackTraceSelector - 24, // 12: querier.v1.SelectSeriesRequest.aggregation:type_name -> types.v1.TimeSeriesAggregationType - 23, // 13: querier.v1.SelectSeriesRequest.stack_trace_selector:type_name -> types.v1.StackTraceSelector - 25, // 14: querier.v1.SelectSeriesResponse.series:type_name -> types.v1.Series - 19, // 15: querier.v1.AnalyzeQueryResponse.query_scopes:type_name -> querier.v1.QueryScope - 20, // 16: querier.v1.AnalyzeQueryResponse.query_impact:type_name -> querier.v1.QueryImpact - 1, // 17: querier.v1.QuerierService.ProfileTypes:input_type -> querier.v1.ProfileTypesRequest - 26, // 18: querier.v1.QuerierService.LabelValues:input_type -> types.v1.LabelValuesRequest - 27, // 19: querier.v1.QuerierService.LabelNames:input_type -> types.v1.LabelNamesRequest - 3, // 20: querier.v1.QuerierService.Series:input_type -> querier.v1.SeriesRequest - 5, // 21: querier.v1.QuerierService.SelectMergeStacktraces:input_type -> querier.v1.SelectMergeStacktracesRequest - 7, // 22: querier.v1.QuerierService.SelectMergeSpanProfile:input_type -> querier.v1.SelectMergeSpanProfileRequest - 14, // 23: querier.v1.QuerierService.SelectMergeProfile:input_type -> querier.v1.SelectMergeProfileRequest - 15, // 24: querier.v1.QuerierService.SelectSeries:input_type -> querier.v1.SelectSeriesRequest - 9, // 25: querier.v1.QuerierService.Diff:input_type -> querier.v1.DiffRequest - 28, // 26: querier.v1.QuerierService.GetProfileStats:input_type -> types.v1.GetProfileStatsRequest - 17, // 27: querier.v1.QuerierService.AnalyzeQuery:input_type -> querier.v1.AnalyzeQueryRequest - 2, // 28: querier.v1.QuerierService.ProfileTypes:output_type -> querier.v1.ProfileTypesResponse - 29, // 29: querier.v1.QuerierService.LabelValues:output_type -> types.v1.LabelValuesResponse - 30, // 30: querier.v1.QuerierService.LabelNames:output_type -> types.v1.LabelNamesResponse - 4, // 31: querier.v1.QuerierService.Series:output_type -> querier.v1.SeriesResponse - 6, // 32: querier.v1.QuerierService.SelectMergeStacktraces:output_type -> querier.v1.SelectMergeStacktracesResponse - 8, // 33: querier.v1.QuerierService.SelectMergeSpanProfile:output_type -> querier.v1.SelectMergeSpanProfileResponse - 31, // 34: querier.v1.QuerierService.SelectMergeProfile:output_type -> google.v1.Profile - 16, // 35: querier.v1.QuerierService.SelectSeries:output_type -> querier.v1.SelectSeriesResponse - 10, // 36: querier.v1.QuerierService.Diff:output_type -> querier.v1.DiffResponse - 32, // 37: querier.v1.QuerierService.GetProfileStats:output_type -> types.v1.GetProfileStatsResponse - 18, // 38: querier.v1.QuerierService.AnalyzeQuery:output_type -> querier.v1.AnalyzeQueryResponse - 28, // [28:39] is the sub-list for method output_type - 17, // [17:28] is the sub-list for method input_type - 17, // [17:17] is the sub-list for extension type_name - 17, // [17:17] is the sub-list for extension extendee - 0, // [0:17] is the sub-list for field type_name + 31, // 3: querier.v1.SelectMergeStacktracesRequest.stack_trace_selector:type_name -> types.v1.StackTraceSelector + 11, // 4: querier.v1.SelectMergeStacktracesRequest.async:type_name -> querier.v1.AsyncQueryRequest + 17, // 5: querier.v1.SelectMergeStacktracesResponse.flamegraph:type_name -> querier.v1.FlameGraph + 12, // 6: querier.v1.SelectMergeStacktracesResponse.async:type_name -> querier.v1.AsyncQueryResponse + 10, // 7: querier.v1.SelectMergeStacktracesResponse.pprof:type_name -> querier.v1.PprofProfile + 32, // 8: querier.v1.PprofProfile.profile:type_name -> google.v1.Profile + 1, // 9: querier.v1.AsyncQueryRequest.type:type_name -> querier.v1.AsyncQueryType + 2, // 10: querier.v1.AsyncQueryResponse.status:type_name -> querier.v1.AsyncQueryStatus + 0, // 11: querier.v1.SelectMergeSpanProfileRequest.format:type_name -> querier.v1.ProfileFormat + 17, // 12: querier.v1.SelectMergeSpanProfileResponse.flamegraph:type_name -> querier.v1.FlameGraph + 8, // 13: querier.v1.DiffRequest.left:type_name -> querier.v1.SelectMergeStacktracesRequest + 8, // 14: querier.v1.DiffRequest.right:type_name -> querier.v1.SelectMergeStacktracesRequest + 18, // 15: querier.v1.DiffResponse.flamegraph:type_name -> querier.v1.FlameGraphDiff + 19, // 16: querier.v1.FlameGraph.levels:type_name -> querier.v1.Level + 19, // 17: querier.v1.FlameGraphDiff.levels:type_name -> querier.v1.Level + 31, // 18: querier.v1.SelectMergeProfileRequest.stack_trace_selector:type_name -> types.v1.StackTraceSelector + 33, // 19: querier.v1.SelectSeriesRequest.aggregation:type_name -> types.v1.TimeSeriesAggregationType + 31, // 20: querier.v1.SelectSeriesRequest.stack_trace_selector:type_name -> types.v1.StackTraceSelector + 34, // 21: querier.v1.SelectSeriesRequest.exemplar_type:type_name -> types.v1.ExemplarType + 35, // 22: querier.v1.SelectSeriesResponse.series:type_name -> types.v1.Series + 3, // 23: querier.v1.SelectHeatmapRequest.query_type:type_name -> querier.v1.HeatmapQueryType + 34, // 24: querier.v1.SelectHeatmapRequest.exemplar_type:type_name -> types.v1.ExemplarType + 36, // 25: querier.v1.SelectHeatmapResponse.series:type_name -> types.v1.HeatmapSeries + 27, // 26: querier.v1.AnalyzeQueryResponse.query_scopes:type_name -> querier.v1.QueryScope + 28, // 27: querier.v1.AnalyzeQueryResponse.query_impact:type_name -> querier.v1.QueryImpact + 4, // 28: querier.v1.QuerierService.ProfileTypes:input_type -> querier.v1.ProfileTypesRequest + 37, // 29: querier.v1.QuerierService.LabelValues:input_type -> types.v1.LabelValuesRequest + 38, // 30: querier.v1.QuerierService.LabelNames:input_type -> types.v1.LabelNamesRequest + 6, // 31: querier.v1.QuerierService.Series:input_type -> querier.v1.SeriesRequest + 8, // 32: querier.v1.QuerierService.SelectMergeStacktraces:input_type -> querier.v1.SelectMergeStacktracesRequest + 13, // 33: querier.v1.QuerierService.SelectMergeSpanProfile:input_type -> querier.v1.SelectMergeSpanProfileRequest + 20, // 34: querier.v1.QuerierService.SelectMergeProfile:input_type -> querier.v1.SelectMergeProfileRequest + 21, // 35: querier.v1.QuerierService.SelectSeries:input_type -> querier.v1.SelectSeriesRequest + 23, // 36: querier.v1.QuerierService.SelectHeatmap:input_type -> querier.v1.SelectHeatmapRequest + 15, // 37: querier.v1.QuerierService.Diff:input_type -> querier.v1.DiffRequest + 39, // 38: querier.v1.QuerierService.GetProfileStats:input_type -> types.v1.GetProfileStatsRequest + 25, // 39: querier.v1.QuerierService.AnalyzeQuery:input_type -> querier.v1.AnalyzeQueryRequest + 5, // 40: querier.v1.QuerierService.ProfileTypes:output_type -> querier.v1.ProfileTypesResponse + 40, // 41: querier.v1.QuerierService.LabelValues:output_type -> types.v1.LabelValuesResponse + 41, // 42: querier.v1.QuerierService.LabelNames:output_type -> types.v1.LabelNamesResponse + 7, // 43: querier.v1.QuerierService.Series:output_type -> querier.v1.SeriesResponse + 9, // 44: querier.v1.QuerierService.SelectMergeStacktraces:output_type -> querier.v1.SelectMergeStacktracesResponse + 14, // 45: querier.v1.QuerierService.SelectMergeSpanProfile:output_type -> querier.v1.SelectMergeSpanProfileResponse + 32, // 46: querier.v1.QuerierService.SelectMergeProfile:output_type -> google.v1.Profile + 22, // 47: querier.v1.QuerierService.SelectSeries:output_type -> querier.v1.SelectSeriesResponse + 24, // 48: querier.v1.QuerierService.SelectHeatmap:output_type -> querier.v1.SelectHeatmapResponse + 16, // 49: querier.v1.QuerierService.Diff:output_type -> querier.v1.DiffResponse + 42, // 50: querier.v1.QuerierService.GetProfileStats:output_type -> types.v1.GetProfileStatsResponse + 26, // 51: querier.v1.QuerierService.AnalyzeQuery:output_type -> querier.v1.AnalyzeQueryResponse + 40, // [40:52] is the sub-list for method output_type + 28, // [28:40] is the sub-list for method input_type + 28, // [28:28] is the sub-list for extension type_name + 28, // [28:28] is the sub-list for extension extendee + 0, // [0:28] is the sub-list for field type_name } func init() { file_querier_v1_querier_proto_init() } @@ -1835,259 +2347,19 @@ func file_querier_v1_querier_proto_init() { if File_querier_v1_querier_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_querier_v1_querier_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProfileTypesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProfileTypesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SeriesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SeriesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectMergeStacktracesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectMergeStacktracesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectMergeSpanProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectMergeSpanProfileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DiffRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DiffResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlameGraph); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlameGraphDiff); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Level); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectMergeProfileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectSeriesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectSeriesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AnalyzeQueryRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AnalyzeQueryResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryScope); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_querier_v1_querier_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryImpact); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_querier_v1_querier_proto_msgTypes[4].OneofWrappers = []interface{}{} - file_querier_v1_querier_proto_msgTypes[6].OneofWrappers = []interface{}{} - file_querier_v1_querier_proto_msgTypes[13].OneofWrappers = []interface{}{} - file_querier_v1_querier_proto_msgTypes[14].OneofWrappers = []interface{}{} + file_querier_v1_querier_proto_msgTypes[4].OneofWrappers = []any{} + file_querier_v1_querier_proto_msgTypes[5].OneofWrappers = []any{} + file_querier_v1_querier_proto_msgTypes[9].OneofWrappers = []any{} + file_querier_v1_querier_proto_msgTypes[16].OneofWrappers = []any{} + file_querier_v1_querier_proto_msgTypes[17].OneofWrappers = []any{} + file_querier_v1_querier_proto_msgTypes[19].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_querier_v1_querier_proto_rawDesc, - NumEnums: 1, - NumMessages: 20, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_querier_v1_querier_proto_rawDesc), len(file_querier_v1_querier_proto_rawDesc)), + NumEnums: 4, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, @@ -2097,7 +2369,6 @@ func file_querier_v1_querier_proto_init() { MessageInfos: file_querier_v1_querier_proto_msgTypes, }.Build() File_querier_v1_querier_proto = out.File - file_querier_v1_querier_proto_rawDesc = nil file_querier_v1_querier_proto_goTypes = nil file_querier_v1_querier_proto_depIdxs = nil } diff --git a/api/gen/proto/go/querier/v1/querier_vtproto.pb.go b/api/gen/proto/go/querier/v1/querier_vtproto.pb.go index fd94196998..31880634c4 100644 --- a/api/gen/proto/go/querier/v1/querier_vtproto.pb.go +++ b/api/gen/proto/go/querier/v1/querier_vtproto.pb.go @@ -137,10 +137,33 @@ func (m *SelectMergeStacktracesRequest) CloneVT() *SelectMergeStacktracesRequest r.Start = m.Start r.End = m.End r.Format = m.Format + r.Async = m.Async.CloneVT() if rhs := m.MaxNodes; rhs != nil { tmpVal := *rhs r.MaxNodes = &tmpVal } + if rhs := m.StackTraceSelector; rhs != nil { + if vtpb, ok := interface{}(rhs).(interface{ CloneVT() *v1.StackTraceSelector }); ok { + r.StackTraceSelector = vtpb.CloneVT() + } else { + r.StackTraceSelector = proto.Clone(rhs).(*v1.StackTraceSelector) + } + } + if rhs := m.ProfileIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.ProfileIdSelector = tmpContainer + } + if rhs := m.TraceIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.TraceIdSelector = tmpContainer + } + if rhs := m.SpanSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.SpanSelector = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -158,6 +181,9 @@ func (m *SelectMergeStacktracesResponse) CloneVT() *SelectMergeStacktracesRespon } r := new(SelectMergeStacktracesResponse) r.Flamegraph = m.Flamegraph.CloneVT() + r.Dot = m.Dot + r.Async = m.Async.CloneVT() + r.Pprof = m.Pprof.CloneVT() if rhs := m.Tree; rhs != nil { tmpBytes := make([]byte, len(rhs)) copy(tmpBytes, rhs) @@ -174,6 +200,66 @@ func (m *SelectMergeStacktracesResponse) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *PprofProfile) CloneVT() *PprofProfile { + if m == nil { + return (*PprofProfile)(nil) + } + r := new(PprofProfile) + if rhs := m.Profile; rhs != nil { + if vtpb, ok := interface{}(rhs).(interface{ CloneVT() *v11.Profile }); ok { + r.Profile = vtpb.CloneVT() + } else { + r.Profile = proto.Clone(rhs).(*v11.Profile) + } + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *PprofProfile) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *AsyncQueryRequest) CloneVT() *AsyncQueryRequest { + if m == nil { + return (*AsyncQueryRequest)(nil) + } + r := new(AsyncQueryRequest) + r.RequestId = m.RequestId + r.Type = m.Type + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AsyncQueryRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *AsyncQueryResponse) CloneVT() *AsyncQueryResponse { + if m == nil { + return (*AsyncQueryResponse)(nil) + } + r := new(AsyncQueryResponse) + r.RequestId = m.RequestId + r.Status = m.Status + r.ErrorMessage = m.ErrorMessage + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AsyncQueryResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *SelectMergeSpanProfileRequest) CloneVT() *SelectMergeSpanProfileRequest { if m == nil { return (*SelectMergeSpanProfileRequest)(nil) @@ -364,6 +450,16 @@ func (m *SelectMergeProfileRequest) CloneVT() *SelectMergeProfileRequest { r.StackTraceSelector = proto.Clone(rhs).(*v1.StackTraceSelector) } } + if rhs := m.ProfileIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.ProfileIdSelector = tmpContainer + } + if rhs := m.TraceIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.TraceIdSelector = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -385,6 +481,7 @@ func (m *SelectSeriesRequest) CloneVT() *SelectSeriesRequest { r.Start = m.Start r.End = m.End r.Step = m.Step + r.ExemplarType = m.ExemplarType if rhs := m.GroupBy; rhs != nil { tmpContainer := make([]string, len(rhs)) copy(tmpContainer, rhs) @@ -401,6 +498,10 @@ func (m *SelectSeriesRequest) CloneVT() *SelectSeriesRequest { r.StackTraceSelector = proto.Clone(rhs).(*v1.StackTraceSelector) } } + if rhs := m.Limit; rhs != nil { + tmpVal := *rhs + r.Limit = &tmpVal + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -439,6 +540,65 @@ func (m *SelectSeriesResponse) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *SelectHeatmapRequest) CloneVT() *SelectHeatmapRequest { + if m == nil { + return (*SelectHeatmapRequest)(nil) + } + r := new(SelectHeatmapRequest) + r.ProfileTypeID = m.ProfileTypeID + r.LabelSelector = m.LabelSelector + r.Start = m.Start + r.End = m.End + r.Step = m.Step + r.QueryType = m.QueryType + r.ExemplarType = m.ExemplarType + if rhs := m.GroupBy; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.GroupBy = tmpContainer + } + if rhs := m.Limit; rhs != nil { + tmpVal := *rhs + r.Limit = &tmpVal + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *SelectHeatmapRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *SelectHeatmapResponse) CloneVT() *SelectHeatmapResponse { + if m == nil { + return (*SelectHeatmapResponse)(nil) + } + r := new(SelectHeatmapResponse) + if rhs := m.Series; rhs != nil { + tmpContainer := make([]*v1.HeatmapSeries, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.HeatmapSeries }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.HeatmapSeries) + } + } + r.Series = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *SelectHeatmapResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *AnalyzeQueryRequest) CloneVT() *AnalyzeQueryRequest { if m == nil { return (*AnalyzeQueryRequest)(nil) @@ -686,6 +846,45 @@ func (this *SelectMergeStacktracesRequest) EqualVT(that *SelectMergeStacktracesR if this.Format != that.Format { return false } + if equal, ok := interface{}(this.StackTraceSelector).(interface { + EqualVT(*v1.StackTraceSelector) bool + }); ok { + if !equal.EqualVT(that.StackTraceSelector) { + return false + } + } else if !proto.Equal(this.StackTraceSelector, that.StackTraceSelector) { + return false + } + if len(this.ProfileIdSelector) != len(that.ProfileIdSelector) { + return false + } + for i, vx := range this.ProfileIdSelector { + vy := that.ProfileIdSelector[i] + if vx != vy { + return false + } + } + if !this.Async.EqualVT(that.Async) { + return false + } + if len(this.TraceIdSelector) != len(that.TraceIdSelector) { + return false + } + for i, vx := range this.TraceIdSelector { + vy := that.TraceIdSelector[i] + if vx != vy { + return false + } + } + if len(this.SpanSelector) != len(that.SpanSelector) { + return false + } + for i, vx := range this.SpanSelector { + vy := that.SpanSelector[i] + if vx != vy { + return false + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -708,6 +907,15 @@ func (this *SelectMergeStacktracesResponse) EqualVT(that *SelectMergeStacktraces if string(this.Tree) != string(that.Tree) { return false } + if this.Dot != that.Dot { + return false + } + if !this.Async.EqualVT(that.Async) { + return false + } + if !this.Pprof.EqualVT(that.Pprof) { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -718,6 +926,76 @@ func (this *SelectMergeStacktracesResponse) EqualMessageVT(thatMsg proto.Message } return this.EqualVT(that) } +func (this *PprofProfile) EqualVT(that *PprofProfile) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if equal, ok := interface{}(this.Profile).(interface{ EqualVT(*v11.Profile) bool }); ok { + if !equal.EqualVT(that.Profile) { + return false + } + } else if !proto.Equal(this.Profile, that.Profile) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *PprofProfile) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*PprofProfile) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AsyncQueryRequest) EqualVT(that *AsyncQueryRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.RequestId != that.RequestId { + return false + } + if this.Type != that.Type { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AsyncQueryRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AsyncQueryRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AsyncQueryResponse) EqualVT(that *AsyncQueryResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.RequestId != that.RequestId { + return false + } + if this.Status != that.Status { + return false + } + if this.ErrorMessage != that.ErrorMessage { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AsyncQueryResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AsyncQueryResponse) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *SelectMergeSpanProfileRequest) EqualVT(that *SelectMergeSpanProfileRequest) bool { if this == that { return true @@ -981,6 +1259,24 @@ func (this *SelectMergeProfileRequest) EqualVT(that *SelectMergeProfileRequest) } else if !proto.Equal(this.StackTraceSelector, that.StackTraceSelector) { return false } + if len(this.ProfileIdSelector) != len(that.ProfileIdSelector) { + return false + } + for i, vx := range this.ProfileIdSelector { + vy := that.ProfileIdSelector[i] + if vx != vy { + return false + } + } + if len(this.TraceIdSelector) != len(that.TraceIdSelector) { + return false + } + for i, vx := range this.TraceIdSelector { + vy := that.TraceIdSelector[i] + if vx != vy { + return false + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -1033,6 +1329,12 @@ func (this *SelectSeriesRequest) EqualVT(that *SelectSeriesRequest) bool { } else if !proto.Equal(this.StackTraceSelector, that.StackTraceSelector) { return false } + if p, q := this.Limit, that.Limit; (p == nil && q != nil) || (p != nil && (q == nil || *p != *q)) { + return false + } + if this.ExemplarType != that.ExemplarType { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -1080,50 +1382,136 @@ func (this *SelectSeriesResponse) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } -func (this *AnalyzeQueryRequest) EqualVT(that *AnalyzeQueryRequest) bool { +func (this *SelectHeatmapRequest) EqualVT(that *SelectHeatmapRequest) bool { if this == that { return true } else if this == nil || that == nil { return false } + if this.ProfileTypeID != that.ProfileTypeID { + return false + } + if this.LabelSelector != that.LabelSelector { + return false + } if this.Start != that.Start { return false } if this.End != that.End { return false } - if this.Query != that.Query { + if this.Step != that.Step { + return false + } + if len(this.GroupBy) != len(that.GroupBy) { + return false + } + for i, vx := range this.GroupBy { + vy := that.GroupBy[i] + if vx != vy { + return false + } + } + if this.QueryType != that.QueryType { + return false + } + if this.ExemplarType != that.ExemplarType { + return false + } + if p, q := this.Limit, that.Limit; (p == nil && q != nil) || (p != nil && (q == nil || *p != *q)) { return false } return string(this.unknownFields) == string(that.unknownFields) } -func (this *AnalyzeQueryRequest) EqualMessageVT(thatMsg proto.Message) bool { - that, ok := thatMsg.(*AnalyzeQueryRequest) +func (this *SelectHeatmapRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*SelectHeatmapRequest) if !ok { return false } return this.EqualVT(that) } -func (this *AnalyzeQueryResponse) EqualVT(that *AnalyzeQueryResponse) bool { +func (this *SelectHeatmapResponse) EqualVT(that *SelectHeatmapResponse) bool { if this == that { return true } else if this == nil || that == nil { return false } - if len(this.QueryScopes) != len(that.QueryScopes) { + if len(this.Series) != len(that.Series) { return false } - for i, vx := range this.QueryScopes { - vy := that.QueryScopes[i] + for i, vx := range this.Series { + vy := that.Series[i] if p, q := vx, vy; p != q { if p == nil { - p = &QueryScope{} + p = &v1.HeatmapSeries{} } if q == nil { - q = &QueryScope{} + q = &v1.HeatmapSeries{} } - if !p.EqualVT(q) { + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.HeatmapSeries) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *SelectHeatmapResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*SelectHeatmapResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AnalyzeQueryRequest) EqualVT(that *AnalyzeQueryRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Start != that.Start { + return false + } + if this.End != that.End { + return false + } + if this.Query != that.Query { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AnalyzeQueryRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AnalyzeQueryRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AnalyzeQueryResponse) EqualVT(that *AnalyzeQueryResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.QueryScopes) != len(that.QueryScopes) { + return false + } + for i, vx := range this.QueryScopes { + vy := that.QueryScopes[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &QueryScope{} + } + if q == nil { + q = &QueryScope{} + } + if !p.EqualVT(q) { return false } } @@ -1225,16 +1613,33 @@ type QuerierServiceClient interface { LabelValues(ctx context.Context, in *v1.LabelValuesRequest, opts ...grpc.CallOption) (*v1.LabelValuesResponse, error) // LabelNames returns a list of the existing label names. LabelNames(ctx context.Context, in *v1.LabelNamesRequest, opts ...grpc.CallOption) (*v1.LabelNamesResponse, error) - // Series returns profiles series matching the request. A series is a unique label set. + // Series returns profiles series matching the request. A series is a unique + // label set. Series(ctx context.Context, in *SeriesRequest, opts ...grpc.CallOption) (*SeriesResponse, error) - // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeStacktraces(ctx context.Context, in *SelectMergeStacktracesRequest, opts ...grpc.CallOption) (*SelectMergeStacktracesResponse, error) - // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // Deprecated: Use SelectMergeStacktraces with span_selector instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeSpanProfile(ctx context.Context, in *SelectMergeSpanProfileRequest, opts ...grpc.CallOption) (*SelectMergeSpanProfileResponse, error) - // SelectMergeProfile returns matching profiles aggregated in pprof format. It will contain all information stored (so including filenames and line number, if ingested). + // Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeProfile returns matching profiles aggregated in pprof format. It + // will contain all information stored (so including filenames and line + // number, if ingested). SelectMergeProfile(ctx context.Context, in *SelectMergeProfileRequest, opts ...grpc.CallOption) (*v11.Profile, error) - // SelectSeries returns a time series for the total sum of the requested profiles. + // SelectSeries returns a time series for the total sum of the requested + // profiles. SelectSeries(ctx context.Context, in *SelectSeriesRequest, opts ...grpc.CallOption) (*SelectSeriesResponse, error) + // SelectHeatmap returns a heatmap visualization for the requested profiles. + // Note: This endpoint is only available in the v2 storage layer + SelectHeatmap(ctx context.Context, in *SelectHeatmapRequest, opts ...grpc.CallOption) (*SelectHeatmapResponse, error) // Diff returns a diff of two profiles Diff(ctx context.Context, in *DiffRequest, opts ...grpc.CallOption) (*DiffResponse, error) // GetProfileStats returns profile stats for the current tenant. @@ -1322,6 +1727,15 @@ func (c *querierServiceClient) SelectSeries(ctx context.Context, in *SelectSerie return out, nil } +func (c *querierServiceClient) SelectHeatmap(ctx context.Context, in *SelectHeatmapRequest, opts ...grpc.CallOption) (*SelectHeatmapResponse, error) { + out := new(SelectHeatmapResponse) + err := c.cc.Invoke(ctx, "/querier.v1.QuerierService/SelectHeatmap", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *querierServiceClient) Diff(ctx context.Context, in *DiffRequest, opts ...grpc.CallOption) (*DiffResponse, error) { out := new(DiffResponse) err := c.cc.Invoke(ctx, "/querier.v1.QuerierService/Diff", in, out, opts...) @@ -1359,16 +1773,33 @@ type QuerierServiceServer interface { LabelValues(context.Context, *v1.LabelValuesRequest) (*v1.LabelValuesResponse, error) // LabelNames returns a list of the existing label names. LabelNames(context.Context, *v1.LabelNamesRequest) (*v1.LabelNamesResponse, error) - // Series returns profiles series matching the request. A series is a unique label set. + // Series returns profiles series matching the request. A series is a unique + // label set. Series(context.Context, *SeriesRequest) (*SeriesResponse, error) - // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeStacktraces(context.Context, *SelectMergeStacktracesRequest) (*SelectMergeStacktracesResponse, error) - // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // Deprecated: Use SelectMergeStacktraces with span_selector instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeSpanProfile(context.Context, *SelectMergeSpanProfileRequest) (*SelectMergeSpanProfileResponse, error) - // SelectMergeProfile returns matching profiles aggregated in pprof format. It will contain all information stored (so including filenames and line number, if ingested). + // Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeProfile returns matching profiles aggregated in pprof format. It + // will contain all information stored (so including filenames and line + // number, if ingested). SelectMergeProfile(context.Context, *SelectMergeProfileRequest) (*v11.Profile, error) - // SelectSeries returns a time series for the total sum of the requested profiles. + // SelectSeries returns a time series for the total sum of the requested + // profiles. SelectSeries(context.Context, *SelectSeriesRequest) (*SelectSeriesResponse, error) + // SelectHeatmap returns a heatmap visualization for the requested profiles. + // Note: This endpoint is only available in the v2 storage layer + SelectHeatmap(context.Context, *SelectHeatmapRequest) (*SelectHeatmapResponse, error) // Diff returns a diff of two profiles Diff(context.Context, *DiffRequest) (*DiffResponse, error) // GetProfileStats returns profile stats for the current tenant. @@ -1405,6 +1836,9 @@ func (UnimplementedQuerierServiceServer) SelectMergeProfile(context.Context, *Se func (UnimplementedQuerierServiceServer) SelectSeries(context.Context, *SelectSeriesRequest) (*SelectSeriesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SelectSeries not implemented") } +func (UnimplementedQuerierServiceServer) SelectHeatmap(context.Context, *SelectHeatmapRequest) (*SelectHeatmapResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SelectHeatmap not implemented") +} func (UnimplementedQuerierServiceServer) Diff(context.Context, *DiffRequest) (*DiffResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Diff not implemented") } @@ -1571,6 +2005,24 @@ func _QuerierService_SelectSeries_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _QuerierService_SelectHeatmap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SelectHeatmapRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuerierServiceServer).SelectHeatmap(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/querier.v1.QuerierService/SelectHeatmap", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuerierServiceServer).SelectHeatmap(ctx, req.(*SelectHeatmapRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _QuerierService_Diff_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(DiffRequest) if err := dec(in); err != nil { @@ -1664,6 +2116,10 @@ var QuerierService_ServiceDesc = grpc.ServiceDesc{ MethodName: "SelectSeries", Handler: _QuerierService_SelectSeries_Handler, }, + { + MethodName: "SelectHeatmap", + Handler: _QuerierService_SelectHeatmap_Handler, + }, { MethodName: "Diff", Handler: _QuerierService_Diff_Handler, @@ -1929,6 +2385,65 @@ func (m *SelectMergeStacktracesRequest) MarshalToSizedBufferVT(dAtA []byte) (int i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.SpanSelector) > 0 { + for iNdEx := len(m.SpanSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SpanSelector[iNdEx]) + copy(dAtA[i:], m.SpanSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpanSelector[iNdEx]))) + i-- + dAtA[i] = 0x5a + } + } + if len(m.TraceIdSelector) > 0 { + for iNdEx := len(m.TraceIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TraceIdSelector[iNdEx]) + copy(dAtA[i:], m.TraceIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TraceIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x52 + } + } + if m.Async != nil { + size, err := m.Async.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x4a + } + if len(m.ProfileIdSelector) > 0 { + for iNdEx := len(m.ProfileIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProfileIdSelector[iNdEx]) + copy(dAtA[i:], m.ProfileIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x42 + } + } + if m.StackTraceSelector != nil { + if vtmsg, ok := interface{}(m.StackTraceSelector).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.StackTraceSelector) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x3a + } if m.Format != 0 { i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Format)) i-- @@ -1996,6 +2511,33 @@ func (m *SelectMergeStacktracesResponse) MarshalToSizedBufferVT(dAtA []byte) (in i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.Pprof != nil { + size, err := m.Pprof.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + if m.Async != nil { + size, err := m.Async.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + if len(m.Dot) > 0 { + i -= len(m.Dot) + copy(dAtA[i:], m.Dot) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Dot))) + i-- + dAtA[i] = 0x1a + } if len(m.Tree) > 0 { i -= len(m.Tree) copy(dAtA[i:], m.Tree) @@ -2016,7 +2558,7 @@ func (m *SelectMergeStacktracesResponse) MarshalToSizedBufferVT(dAtA []byte) (in return len(dAtA) - i, nil } -func (m *SelectMergeSpanProfileRequest) MarshalVT() (dAtA []byte, err error) { +func (m *PprofProfile) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -2029,12 +2571,12 @@ func (m *SelectMergeSpanProfileRequest) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *SelectMergeSpanProfileRequest) MarshalToVT(dAtA []byte) (int, error) { +func (m *PprofProfile) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *SelectMergeSpanProfileRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *PprofProfile) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -2046,53 +2588,32 @@ func (m *SelectMergeSpanProfileRequest) MarshalToSizedBufferVT(dAtA []byte) (int i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if m.Format != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Format)) - i-- - dAtA[i] = 0x38 - } - if m.MaxNodes != nil { - i = protohelpers.EncodeVarint(dAtA, i, uint64(*m.MaxNodes)) - i-- - dAtA[i] = 0x30 - } - if m.End != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.End)) - i-- - dAtA[i] = 0x28 - } - if m.Start != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Start)) - i-- - dAtA[i] = 0x20 - } - if len(m.SpanSelector) > 0 { - for iNdEx := len(m.SpanSelector) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.SpanSelector[iNdEx]) - copy(dAtA[i:], m.SpanSelector[iNdEx]) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpanSelector[iNdEx]))) - i-- - dAtA[i] = 0x1a + if m.Profile != nil { + if vtmsg, ok := interface{}(m.Profile).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Profile) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) } - } - if len(m.LabelSelector) > 0 { - i -= len(m.LabelSelector) - copy(dAtA[i:], m.LabelSelector) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelSelector))) - i-- - dAtA[i] = 0x12 - } - if len(m.ProfileTypeID) > 0 { - i -= len(m.ProfileTypeID) - copy(dAtA[i:], m.ProfileTypeID) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileTypeID))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *SelectMergeSpanProfileResponse) MarshalVT() (dAtA []byte, err error) { +func (m *AsyncQueryRequest) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -2105,12 +2626,12 @@ func (m *SelectMergeSpanProfileResponse) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *SelectMergeSpanProfileResponse) MarshalToVT(dAtA []byte) (int, error) { +func (m *AsyncQueryRequest) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *SelectMergeSpanProfileResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *AsyncQueryRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -2122,27 +2643,22 @@ func (m *SelectMergeSpanProfileResponse) MarshalToSizedBufferVT(dAtA []byte) (in i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if len(m.Tree) > 0 { - i -= len(m.Tree) - copy(dAtA[i:], m.Tree) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tree))) + if m.Type != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type)) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x10 } - if m.Flamegraph != nil { - size, err := m.Flamegraph.MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + if len(m.RequestId) > 0 { + i -= len(m.RequestId) + copy(dAtA[i:], m.RequestId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RequestId))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *DiffRequest) MarshalVT() (dAtA []byte, err error) { +func (m *AsyncQueryResponse) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -2155,12 +2671,12 @@ func (m *DiffRequest) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *DiffRequest) MarshalToVT(dAtA []byte) (int, error) { +func (m *AsyncQueryResponse) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *DiffRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *AsyncQueryResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -2172,30 +2688,29 @@ func (m *DiffRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if m.Right != nil { - size, err := m.Right.MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + if len(m.ErrorMessage) > 0 { + i -= len(m.ErrorMessage) + copy(dAtA[i:], m.ErrorMessage) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ErrorMessage))) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a } - if m.Left != nil { - size, err := m.Left.MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + if m.Status != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x10 + } + if len(m.RequestId) > 0 { + i -= len(m.RequestId) + copy(dAtA[i:], m.RequestId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RequestId))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *DiffResponse) MarshalVT() (dAtA []byte, err error) { +func (m *SelectMergeSpanProfileRequest) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -2208,12 +2723,12 @@ func (m *DiffResponse) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *DiffResponse) MarshalToVT(dAtA []byte) (int, error) { +func (m *SelectMergeSpanProfileRequest) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *DiffResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *SelectMergeSpanProfileRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -2225,24 +2740,203 @@ func (m *DiffResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if m.Flamegraph != nil { - size, err := m.Flamegraph.MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + if m.Format != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Format)) i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *FlameGraph) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil + dAtA[i] = 0x38 } - size := m.SizeVT() + if m.MaxNodes != nil { + i = protohelpers.EncodeVarint(dAtA, i, uint64(*m.MaxNodes)) + i-- + dAtA[i] = 0x30 + } + if m.End != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.End)) + i-- + dAtA[i] = 0x28 + } + if m.Start != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Start)) + i-- + dAtA[i] = 0x20 + } + if len(m.SpanSelector) > 0 { + for iNdEx := len(m.SpanSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SpanSelector[iNdEx]) + copy(dAtA[i:], m.SpanSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpanSelector[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.LabelSelector) > 0 { + i -= len(m.LabelSelector) + copy(dAtA[i:], m.LabelSelector) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelSelector))) + i-- + dAtA[i] = 0x12 + } + if len(m.ProfileTypeID) > 0 { + i -= len(m.ProfileTypeID) + copy(dAtA[i:], m.ProfileTypeID) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileTypeID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SelectMergeSpanProfileResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SelectMergeSpanProfileResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *SelectMergeSpanProfileResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Tree) > 0 { + i -= len(m.Tree) + copy(dAtA[i:], m.Tree) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tree))) + i-- + dAtA[i] = 0x12 + } + if m.Flamegraph != nil { + size, err := m.Flamegraph.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DiffRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DiffRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DiffRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Right != nil { + size, err := m.Right.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.Left != nil { + size, err := m.Left.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DiffResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DiffResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DiffResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Flamegraph != nil { + size, err := m.Flamegraph.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *FlameGraph) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() dAtA = make([]byte, size) n, err := m.MarshalToSizedBufferVT(dAtA[:size]) if err != nil { @@ -2460,6 +3154,24 @@ func (m *SelectMergeProfileRequest) MarshalToSizedBufferVT(dAtA []byte) (int, er i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.TraceIdSelector) > 0 { + for iNdEx := len(m.TraceIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TraceIdSelector[iNdEx]) + copy(dAtA[i:], m.TraceIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TraceIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x42 + } + } + if len(m.ProfileIdSelector) > 0 { + for iNdEx := len(m.ProfileIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProfileIdSelector[iNdEx]) + copy(dAtA[i:], m.ProfileIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x3a + } + } if m.StackTraceSelector != nil { if vtmsg, ok := interface{}(m.StackTraceSelector).(interface { MarshalToSizedBufferVT([]byte) (int, error) @@ -2544,6 +3256,16 @@ func (m *SelectSeriesRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.ExemplarType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ExemplarType)) + i-- + dAtA[i] = 0x50 + } + if m.Limit != nil { + i = protohelpers.EncodeVarint(dAtA, i, uint64(*m.Limit)) + i-- + dAtA[i] = 0x48 + } if m.StackTraceSelector != nil { if vtmsg, ok := interface{}(m.StackTraceSelector).(interface { MarshalToSizedBufferVT([]byte) (int, error) @@ -2670,7 +3392,7 @@ func (m *SelectSeriesResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *AnalyzeQueryRequest) MarshalVT() (dAtA []byte, err error) { +func (m *SelectHeatmapRequest) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -2683,12 +3405,12 @@ func (m *AnalyzeQueryRequest) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *AnalyzeQueryRequest) MarshalToVT(dAtA []byte) (int, error) { +func (m *SelectHeatmapRequest) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *AnalyzeQueryRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *SelectHeatmapRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -2700,27 +3422,64 @@ func (m *AnalyzeQueryRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if len(m.Query) > 0 { - i -= len(m.Query) - copy(dAtA[i:], m.Query) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Query))) + if m.Limit != nil { + i = protohelpers.EncodeVarint(dAtA, i, uint64(*m.Limit)) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x48 + } + if m.ExemplarType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ExemplarType)) + i-- + dAtA[i] = 0x40 + } + if m.QueryType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.QueryType)) + i-- + dAtA[i] = 0x38 + } + if len(m.GroupBy) > 0 { + for iNdEx := len(m.GroupBy) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.GroupBy[iNdEx]) + copy(dAtA[i:], m.GroupBy[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GroupBy[iNdEx]))) + i-- + dAtA[i] = 0x32 + } + } + if m.Step != 0 { + i -= 8 + binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Step)))) + i-- + dAtA[i] = 0x29 } if m.End != 0 { i = protohelpers.EncodeVarint(dAtA, i, uint64(m.End)) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x20 } if m.Start != 0 { i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Start)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x18 + } + if len(m.LabelSelector) > 0 { + i -= len(m.LabelSelector) + copy(dAtA[i:], m.LabelSelector) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelSelector))) + i-- + dAtA[i] = 0x12 + } + if len(m.ProfileTypeID) > 0 { + i -= len(m.ProfileTypeID) + copy(dAtA[i:], m.ProfileTypeID) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileTypeID))) + i-- + dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *AnalyzeQueryResponse) MarshalVT() (dAtA []byte, err error) { +func (m *SelectHeatmapResponse) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -2733,12 +3492,12 @@ func (m *AnalyzeQueryResponse) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *AnalyzeQueryResponse) MarshalToVT(dAtA []byte) (int, error) { +func (m *SelectHeatmapResponse) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *AnalyzeQueryResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *SelectHeatmapResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -2750,10 +3509,117 @@ func (m *AnalyzeQueryResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if m.QueryImpact != nil { - size, err := m.QueryImpact.MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err + if len(m.Series) > 0 { + for iNdEx := len(m.Series) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Series[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Series[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *AnalyzeQueryRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AnalyzeQueryRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AnalyzeQueryRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Query) > 0 { + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0x22 + } + if m.End != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.End)) + i-- + dAtA[i] = 0x18 + } + if m.Start != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Start)) + i-- + dAtA[i] = 0x10 + } + return len(dAtA) - i, nil +} + +func (m *AnalyzeQueryResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AnalyzeQueryResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AnalyzeQueryResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.QueryImpact != nil { + size, err := m.QueryImpact.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err } i -= size i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) @@ -3022,6 +3888,38 @@ func (m *SelectMergeStacktracesRequest) SizeVT() (n int) { if m.Format != 0 { n += 1 + protohelpers.SizeOfVarint(uint64(m.Format)) } + if m.StackTraceSelector != nil { + if size, ok := interface{}(m.StackTraceSelector).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.StackTraceSelector) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.ProfileIdSelector) > 0 { + for _, s := range m.ProfileIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Async != nil { + l = m.Async.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.TraceIdSelector) > 0 { + for _, s := range m.TraceIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.SpanSelector) > 0 { + for _, s := range m.SpanSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } n += len(m.unknownFields) return n } @@ -3040,6 +3938,76 @@ func (m *SelectMergeStacktracesResponse) SizeVT() (n int) { if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + l = len(m.Dot) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Async != nil { + l = m.Async.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Pprof != nil { + l = m.Pprof.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *PprofProfile) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Profile != nil { + if size, ok := interface{}(m.Profile).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.Profile) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *AsyncQueryRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RequestId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Type != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Type)) + } + n += len(m.unknownFields) + return n +} + +func (m *AsyncQueryResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RequestId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Status != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Status)) + } + l = len(m.ErrorMessage) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -3242,6 +4210,18 @@ func (m *SelectMergeProfileRequest) SizeVT() (n int) { } n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if len(m.ProfileIdSelector) > 0 { + for _, s := range m.ProfileIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.TraceIdSelector) > 0 { + for _, s := range m.TraceIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } n += len(m.unknownFields) return n } @@ -3288,6 +4268,12 @@ func (m *SelectSeriesRequest) SizeVT() (n int) { } n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.Limit != nil { + n += 1 + protohelpers.SizeOfVarint(uint64(*m.Limit)) + } + if m.ExemplarType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ExemplarType)) + } n += len(m.unknownFields) return n } @@ -3314,6 +4300,70 @@ func (m *SelectSeriesResponse) SizeVT() (n int) { return n } +func (m *SelectHeatmapRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ProfileTypeID) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.LabelSelector) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Start != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Start)) + } + if m.End != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.End)) + } + if m.Step != 0 { + n += 9 + } + if len(m.GroupBy) > 0 { + for _, s := range m.GroupBy { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.QueryType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.QueryType)) + } + if m.ExemplarType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ExemplarType)) + } + if m.Limit != nil { + n += 1 + protohelpers.SizeOfVarint(uint64(*m.Limit)) + } + n += len(m.unknownFields) + return n +} + +func (m *SelectHeatmapResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Series) > 0 { + for _, e := range m.Series { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + func (m *AnalyzeQueryRequest) SizeVT() (n int) { if m == nil { return 0 @@ -4009,60 +5059,9 @@ func (m *SelectMergeStacktracesRequest) UnmarshalVT(dAtA []byte) error { break } } - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *SelectMergeStacktracesResponse) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: SelectMergeStacktracesResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: SelectMergeStacktracesResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Flamegraph", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field StackTraceSelector", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -4089,18 +5088,26 @@ func (m *SelectMergeStacktracesResponse) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Flamegraph == nil { - m.Flamegraph = &FlameGraph{} + if m.StackTraceSelector == nil { + m.StackTraceSelector = &v1.StackTraceSelector{} } - if err := m.Flamegraph.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err + if unmarshal, ok := interface{}(m.StackTraceSelector).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.StackTraceSelector); err != nil { + return err + } } iNdEx = postIndex - case 2: + case 8: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Tree", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProfileIdSelector", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4110,82 +5117,29 @@ func (m *SelectMergeStacktracesResponse) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Tree = append(m.Tree[:0], dAtA[iNdEx:postIndex]...) - if m.Tree == nil { - m.Tree = []byte{} - } + m.ProfileIdSelector = append(m.ProfileIdSelector, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *SelectMergeSpanProfileRequest) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: SelectMergeSpanProfileRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: SelectMergeSpanProfileRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 9: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProfileTypeID", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Async", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4195,27 +5149,31 @@ func (m *SelectMergeSpanProfileRequest) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.ProfileTypeID = string(dAtA[iNdEx:postIndex]) + if m.Async == nil { + m.Async = &AsyncQueryRequest{} + } + if err := m.Async.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + case 10: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LabelSelector", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TraceIdSelector", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4243,9 +5201,9 @@ func (m *SelectMergeSpanProfileRequest) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.LabelSelector = string(dAtA[iNdEx:postIndex]) + m.TraceIdSelector = append(m.TraceIdSelector, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 3: + case 11: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field SpanSelector", wireType) } @@ -4277,83 +5235,6 @@ func (m *SelectMergeSpanProfileRequest) UnmarshalVT(dAtA []byte) error { } m.SpanSelector = append(m.SpanSelector, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) - } - m.Start = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Start |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) - } - m.End = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.End |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxNodes", wireType) - } - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.MaxNodes = &v - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Format", wireType) - } - m.Format = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Format |= ProfileFormat(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -4376,7 +5257,7 @@ func (m *SelectMergeSpanProfileRequest) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *SelectMergeSpanProfileResponse) UnmarshalVT(dAtA []byte) error { +func (m *SelectMergeStacktracesResponse) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4399,10 +5280,10 @@ func (m *SelectMergeSpanProfileResponse) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SelectMergeSpanProfileResponse: wiretype end group for non-group") + return fmt.Errorf("proto: SelectMergeStacktracesResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SelectMergeSpanProfileResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SelectMergeStacktracesResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4475,60 +5356,41 @@ func (m *SelectMergeSpanProfileResponse) UnmarshalVT(dAtA []byte) error { m.Tree = []byte{} } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Dot", wireType) } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *DiffRequest) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - if iNdEx >= l { - return io.ErrUnexpectedEOF + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: DiffRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: DiffRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Dot = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Left", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Async", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -4555,16 +5417,16 @@ func (m *DiffRequest) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Left == nil { - m.Left = &SelectMergeStacktracesRequest{} + if m.Async == nil { + m.Async = &AsyncQueryResponse{} } - if err := m.Left.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Async.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Right", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Pprof", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -4591,10 +5453,10 @@ func (m *DiffRequest) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Right == nil { - m.Right = &SelectMergeStacktracesRequest{} + if m.Pprof == nil { + m.Pprof = &PprofProfile{} } - if err := m.Right.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Pprof.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -4620,7 +5482,7 @@ func (m *DiffRequest) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *DiffResponse) UnmarshalVT(dAtA []byte) error { +func (m *PprofProfile) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4643,15 +5505,15 @@ func (m *DiffResponse) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: DiffResponse: wiretype end group for non-group") + return fmt.Errorf("proto: PprofProfile: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: DiffResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: PprofProfile: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Flamegraph", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Profile", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -4678,11 +5540,19 @@ func (m *DiffResponse) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Flamegraph == nil { - m.Flamegraph = &FlameGraphDiff{} + if m.Profile == nil { + m.Profile = &v11.Profile{} } - if err := m.Flamegraph.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err + if unmarshal, ok := interface{}(m.Profile).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Profile); err != nil { + return err + } } iNdEx = postIndex default: @@ -4707,7 +5577,7 @@ func (m *DiffResponse) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { +func (m *AsyncQueryRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4730,15 +5600,15 @@ func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: FlameGraph: wiretype end group for non-group") + return fmt.Errorf("proto: AsyncQueryRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: FlameGraph: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AsyncQueryRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Names", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4766,13 +5636,83 @@ func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Names = append(m.Names, string(dAtA[iNdEx:postIndex])) + m.RequestId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= AsyncQueryType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AsyncQueryResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AsyncQueryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AsyncQueryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Levels", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RequestId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4782,31 +5722,29 @@ func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Levels = append(m.Levels, &Level{}) - if err := m.Levels[len(m.Levels)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.RequestId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) } - m.Total = 0 + m.Status = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4816,16 +5754,16 @@ func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Total |= int64(b&0x7F) << shift + m.Status |= AsyncQueryStatus(b&0x7F) << shift if b < 0x80 { break } } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxSelf", wireType) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) } - m.MaxSelf = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4835,11 +5773,24 @@ func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.MaxSelf |= int64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ErrorMessage = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -4862,7 +5813,7 @@ func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { +func (m *SelectMergeSpanProfileRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4885,15 +5836,15 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: FlameGraphDiff: wiretype end group for non-group") + return fmt.Errorf("proto: SelectMergeSpanProfileRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: FlameGraphDiff: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SelectMergeSpanProfileRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Names", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProfileTypeID", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4921,13 +5872,13 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Names = append(m.Names, string(dAtA[iNdEx:postIndex])) + m.ProfileTypeID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Levels", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LabelSelector", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4937,31 +5888,29 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Levels = append(m.Levels, &Level{}) - if err := m.Levels[len(m.Levels)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.LabelSelector = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanSelector", wireType) } - m.Total = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4971,16 +5920,29 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Total |= int64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpanSelector = append(m.SpanSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex case 4: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxSelf", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) } - m.MaxSelf = 0 + m.Start = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -4990,16 +5952,16 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.MaxSelf |= int64(b&0x7F) << shift + m.Start |= int64(b&0x7F) << shift if b < 0x80 { break } } case 5: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LeftTicks", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) } - m.LeftTicks = 0 + m.End = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -5009,16 +5971,16 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.LeftTicks |= int64(b&0x7F) << shift + m.End |= int64(b&0x7F) << shift if b < 0x80 { break } } case 6: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RightTicks", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxNodes", wireType) } - m.RightTicks = 0 + var v int64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -5028,7 +5990,27 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.RightTicks |= int64(b&0x7F) << shift + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MaxNodes = &v + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Format", wireType) + } + m.Format = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Format |= ProfileFormat(b&0x7F) << shift if b < 0x80 { break } @@ -5055,7 +6037,7 @@ func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *Level) UnmarshalVT(dAtA []byte) error { +func (m *SelectMergeSpanProfileResponse) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5078,88 +6060,82 @@ func (m *Level) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Level: wiretype end group for non-group") + return fmt.Errorf("proto: SelectMergeSpanProfileResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Level: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SelectMergeSpanProfileResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType == 0 { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Flamegraph", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow } - m.Values = append(m.Values, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } + if iNdEx >= l { + return io.ErrUnexpectedEOF } - if packedLen < 0 { - return protohelpers.ErrInvalidLength + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Flamegraph == nil { + m.Flamegraph = &FlameGraph{} + } + if err := m.Flamegraph.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tree", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow } - if postIndex > l { + if iNdEx >= l { return io.ErrUnexpectedEOF } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.Values) == 0 { - m.Values = make([]int64, 0, elementCount) - } - for iNdEx < postIndex { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Values = append(m.Values, v) + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tree = append(m.Tree[:0], dAtA[iNdEx:postIndex]...) + if m.Tree == nil { + m.Tree = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -5182,7 +6158,973 @@ func (m *Level) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *SelectMergeProfileRequest) UnmarshalVT(dAtA []byte) error { +func (m *DiffRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiffRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiffRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Left", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Left == nil { + m.Left = &SelectMergeStacktracesRequest{} + } + if err := m.Left.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Right", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Right == nil { + m.Right = &SelectMergeStacktracesRequest{} + } + if err := m.Right.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DiffResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiffResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiffResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Flamegraph", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Flamegraph == nil { + m.Flamegraph = &FlameGraphDiff{} + } + if err := m.Flamegraph.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FlameGraph) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FlameGraph: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FlameGraph: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Names", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Names = append(m.Names, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Levels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Levels = append(m.Levels, &Level{}) + if err := m.Levels[len(m.Levels)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + } + m.Total = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Total |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxSelf", wireType) + } + m.MaxSelf = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxSelf |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FlameGraphDiff) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FlameGraphDiff: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FlameGraphDiff: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Names", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Names = append(m.Names, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Levels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Levels = append(m.Levels, &Level{}) + if err := m.Levels[len(m.Levels)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + } + m.Total = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Total |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxSelf", wireType) + } + m.MaxSelf = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxSelf |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LeftTicks", wireType) + } + m.LeftTicks = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LeftTicks |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RightTicks", wireType) + } + m.RightTicks = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RightTicks |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Level) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Level: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Level: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Values = append(m.Values, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Values) == 0 { + m.Values = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Values = append(m.Values, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SelectMergeProfileRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SelectMergeProfileRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SelectMergeProfileRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileTypeID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileTypeID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelSelector = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) + } + m.Start = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Start |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) + } + m.End = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.End |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxNodes", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MaxNodes = &v + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StackTraceSelector", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StackTraceSelector == nil { + m.StackTraceSelector = &v1.StackTraceSelector{} + } + if unmarshal, ok := interface{}(m.StackTraceSelector).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.StackTraceSelector); err != nil { + return err + } + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileIdSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileIdSelector = append(m.ProfileIdSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TraceIdSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TraceIdSelector = append(m.TraceIdSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5205,10 +7147,10 @@ func (m *SelectMergeProfileRequest) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SelectMergeProfileRequest: wiretype end group for non-group") + return fmt.Errorf("proto: SelectSeriesRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SelectMergeProfileRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SelectSeriesRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -5314,10 +7256,10 @@ func (m *SelectMergeProfileRequest) UnmarshalVT(dAtA []byte) error { } } case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxNodes", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupBy", wireType) } - var v int64 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -5327,13 +7269,56 @@ func (m *SelectMergeProfileRequest) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - m.MaxNodes = &v + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GroupBy = append(m.GroupBy, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex case 6: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Step", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Step = float64(math.Float64frombits(v)) + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Aggregation", wireType) + } + var v v1.TimeSeriesAggregationType + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= v1.TimeSeriesAggregationType(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Aggregation = &v + case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field StackTraceSelector", wireType) } @@ -5377,6 +7362,45 @@ func (m *SelectMergeProfileRequest) UnmarshalVT(dAtA []byte) error { } } iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Limit = &v + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExemplarType", wireType) + } + m.ExemplarType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExemplarType |= v1.ExemplarType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -5399,7 +7423,7 @@ func (m *SelectMergeProfileRequest) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { +func (m *SelectSeriesResponse) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5422,10 +7446,103 @@ func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SelectSeriesRequest: wiretype end group for non-group") + return fmt.Errorf("proto: SelectSeriesResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SelectSeriesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SelectSeriesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Series", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Series = append(m.Series, &v1.Series{}) + if unmarshal, ok := interface{}(m.Series[len(m.Series)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Series[len(m.Series)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SelectHeatmapRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SelectHeatmapRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SelectHeatmapRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -5531,6 +7648,17 @@ func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { } } case 5: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Step", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Step = float64(math.Float64frombits(v)) + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field GroupBy", wireType) } @@ -5562,22 +7690,11 @@ func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { } m.GroupBy = append(m.GroupBy, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 6: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field Step", wireType) - } - var v uint64 - if (iNdEx + 8) > l { - return io.ErrUnexpectedEOF - } - v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - m.Step = float64(math.Float64frombits(v)) case 7: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Aggregation", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field QueryType", wireType) } - var v v1.TimeSeriesAggregationType + m.QueryType = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -5587,17 +7704,16 @@ func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= v1.TimeSeriesAggregationType(b&0x7F) << shift + m.QueryType |= HeatmapQueryType(b&0x7F) << shift if b < 0x80 { break } } - m.Aggregation = &v case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StackTraceSelector", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExemplarType", wireType) } - var msglen int + m.ExemplarType = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -5607,36 +7723,31 @@ func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + m.ExemplarType |= v1.ExemplarType(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.StackTraceSelector == nil { - m.StackTraceSelector = &v1.StackTraceSelector{} + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) } - if unmarshal, ok := interface{}(m.StackTraceSelector).(interface { - UnmarshalVT([]byte) error - }); ok { - if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow } - } else { - if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.StackTraceSelector); err != nil { - return err + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break } } - iNdEx = postIndex + m.Limit = &v default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -5659,7 +7770,7 @@ func (m *SelectSeriesRequest) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *SelectSeriesResponse) UnmarshalVT(dAtA []byte) error { +func (m *SelectHeatmapResponse) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5682,10 +7793,10 @@ func (m *SelectSeriesResponse) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SelectSeriesResponse: wiretype end group for non-group") + return fmt.Errorf("proto: SelectHeatmapResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SelectSeriesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SelectHeatmapResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -5717,7 +7828,7 @@ func (m *SelectSeriesResponse) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Series = append(m.Series, &v1.Series{}) + m.Series = append(m.Series, &v1.HeatmapSeries{}) if unmarshal, ok := interface{}(m.Series[len(m.Series)-1]).(interface { UnmarshalVT([]byte) error }); ok { diff --git a/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.go b/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.go index fcf4bd79c3..c8a3cfbfbc 100644 --- a/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.go +++ b/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.go @@ -2,6 +2,8 @@ // // Source: querier/v1/querier.proto +// Provides the ability to query the Pyroscope database. Most of the calls in +// this group are considered public. package querierv1connect import ( @@ -58,6 +60,9 @@ const ( // QuerierServiceSelectSeriesProcedure is the fully-qualified name of the QuerierService's // SelectSeries RPC. QuerierServiceSelectSeriesProcedure = "/querier.v1.QuerierService/SelectSeries" + // QuerierServiceSelectHeatmapProcedure is the fully-qualified name of the QuerierService's + // SelectHeatmap RPC. + QuerierServiceSelectHeatmapProcedure = "/querier.v1.QuerierService/SelectHeatmap" // QuerierServiceDiffProcedure is the fully-qualified name of the QuerierService's Diff RPC. QuerierServiceDiffProcedure = "/querier.v1.QuerierService/Diff" // QuerierServiceGetProfileStatsProcedure is the fully-qualified name of the QuerierService's @@ -68,22 +73,6 @@ const ( QuerierServiceAnalyzeQueryProcedure = "/querier.v1.QuerierService/AnalyzeQuery" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - querierServiceServiceDescriptor = v1.File_querier_v1_querier_proto.Services().ByName("QuerierService") - querierServiceProfileTypesMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("ProfileTypes") - querierServiceLabelValuesMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("LabelValues") - querierServiceLabelNamesMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("LabelNames") - querierServiceSeriesMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("Series") - querierServiceSelectMergeStacktracesMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("SelectMergeStacktraces") - querierServiceSelectMergeSpanProfileMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("SelectMergeSpanProfile") - querierServiceSelectMergeProfileMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("SelectMergeProfile") - querierServiceSelectSeriesMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("SelectSeries") - querierServiceDiffMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("Diff") - querierServiceGetProfileStatsMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("GetProfileStats") - querierServiceAnalyzeQueryMethodDescriptor = querierServiceServiceDescriptor.Methods().ByName("AnalyzeQuery") -) - // QuerierServiceClient is a client for the querier.v1.QuerierService service. type QuerierServiceClient interface { // ProfileType returns a list of the existing profile types. @@ -92,16 +81,33 @@ type QuerierServiceClient interface { LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) // LabelNames returns a list of the existing label names. LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) - // Series returns profiles series matching the request. A series is a unique label set. + // Series returns profiles series matching the request. A series is a unique + // label set. Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) - // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeStacktraces(context.Context, *connect.Request[v1.SelectMergeStacktracesRequest]) (*connect.Response[v1.SelectMergeStacktracesResponse], error) - // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // Deprecated: Use SelectMergeStacktraces with span_selector instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeSpanProfile(context.Context, *connect.Request[v1.SelectMergeSpanProfileRequest]) (*connect.Response[v1.SelectMergeSpanProfileResponse], error) - // SelectMergeProfile returns matching profiles aggregated in pprof format. It will contain all information stored (so including filenames and line number, if ingested). + // Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeProfile returns matching profiles aggregated in pprof format. It + // will contain all information stored (so including filenames and line + // number, if ingested). SelectMergeProfile(context.Context, *connect.Request[v1.SelectMergeProfileRequest]) (*connect.Response[v12.Profile], error) - // SelectSeries returns a time series for the total sum of the requested profiles. + // SelectSeries returns a time series for the total sum of the requested + // profiles. SelectSeries(context.Context, *connect.Request[v1.SelectSeriesRequest]) (*connect.Response[v1.SelectSeriesResponse], error) + // SelectHeatmap returns a heatmap visualization for the requested profiles. + // Note: This endpoint is only available in the v2 storage layer + SelectHeatmap(context.Context, *connect.Request[v1.SelectHeatmapRequest]) (*connect.Response[v1.SelectHeatmapResponse], error) // Diff returns a diff of two profiles Diff(context.Context, *connect.Request[v1.DiffRequest]) (*connect.Response[v1.DiffResponse], error) // GetProfileStats returns profile stats for the current tenant. @@ -118,71 +124,78 @@ type QuerierServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewQuerierServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) QuerierServiceClient { baseURL = strings.TrimRight(baseURL, "/") + querierServiceMethods := v1.File_querier_v1_querier_proto.Services().ByName("QuerierService").Methods() return &querierServiceClient{ profileTypes: connect.NewClient[v1.ProfileTypesRequest, v1.ProfileTypesResponse]( httpClient, baseURL+QuerierServiceProfileTypesProcedure, - connect.WithSchema(querierServiceProfileTypesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("ProfileTypes")), connect.WithClientOptions(opts...), ), labelValues: connect.NewClient[v11.LabelValuesRequest, v11.LabelValuesResponse]( httpClient, baseURL+QuerierServiceLabelValuesProcedure, - connect.WithSchema(querierServiceLabelValuesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("LabelValues")), connect.WithClientOptions(opts...), ), labelNames: connect.NewClient[v11.LabelNamesRequest, v11.LabelNamesResponse]( httpClient, baseURL+QuerierServiceLabelNamesProcedure, - connect.WithSchema(querierServiceLabelNamesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("LabelNames")), connect.WithClientOptions(opts...), ), series: connect.NewClient[v1.SeriesRequest, v1.SeriesResponse]( httpClient, baseURL+QuerierServiceSeriesProcedure, - connect.WithSchema(querierServiceSeriesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("Series")), connect.WithClientOptions(opts...), ), selectMergeStacktraces: connect.NewClient[v1.SelectMergeStacktracesRequest, v1.SelectMergeStacktracesResponse]( httpClient, baseURL+QuerierServiceSelectMergeStacktracesProcedure, - connect.WithSchema(querierServiceSelectMergeStacktracesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectMergeStacktraces")), connect.WithClientOptions(opts...), ), selectMergeSpanProfile: connect.NewClient[v1.SelectMergeSpanProfileRequest, v1.SelectMergeSpanProfileResponse]( httpClient, baseURL+QuerierServiceSelectMergeSpanProfileProcedure, - connect.WithSchema(querierServiceSelectMergeSpanProfileMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectMergeSpanProfile")), connect.WithClientOptions(opts...), ), selectMergeProfile: connect.NewClient[v1.SelectMergeProfileRequest, v12.Profile]( httpClient, baseURL+QuerierServiceSelectMergeProfileProcedure, - connect.WithSchema(querierServiceSelectMergeProfileMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectMergeProfile")), connect.WithClientOptions(opts...), ), selectSeries: connect.NewClient[v1.SelectSeriesRequest, v1.SelectSeriesResponse]( httpClient, baseURL+QuerierServiceSelectSeriesProcedure, - connect.WithSchema(querierServiceSelectSeriesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectSeries")), + connect.WithClientOptions(opts...), + ), + selectHeatmap: connect.NewClient[v1.SelectHeatmapRequest, v1.SelectHeatmapResponse]( + httpClient, + baseURL+QuerierServiceSelectHeatmapProcedure, + connect.WithSchema(querierServiceMethods.ByName("SelectHeatmap")), connect.WithClientOptions(opts...), ), diff: connect.NewClient[v1.DiffRequest, v1.DiffResponse]( httpClient, baseURL+QuerierServiceDiffProcedure, - connect.WithSchema(querierServiceDiffMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("Diff")), connect.WithClientOptions(opts...), ), getProfileStats: connect.NewClient[v11.GetProfileStatsRequest, v11.GetProfileStatsResponse]( httpClient, baseURL+QuerierServiceGetProfileStatsProcedure, - connect.WithSchema(querierServiceGetProfileStatsMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("GetProfileStats")), connect.WithClientOptions(opts...), ), analyzeQuery: connect.NewClient[v1.AnalyzeQueryRequest, v1.AnalyzeQueryResponse]( httpClient, baseURL+QuerierServiceAnalyzeQueryProcedure, - connect.WithSchema(querierServiceAnalyzeQueryMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("AnalyzeQuery")), connect.WithClientOptions(opts...), ), } @@ -198,6 +211,7 @@ type querierServiceClient struct { selectMergeSpanProfile *connect.Client[v1.SelectMergeSpanProfileRequest, v1.SelectMergeSpanProfileResponse] selectMergeProfile *connect.Client[v1.SelectMergeProfileRequest, v12.Profile] selectSeries *connect.Client[v1.SelectSeriesRequest, v1.SelectSeriesResponse] + selectHeatmap *connect.Client[v1.SelectHeatmapRequest, v1.SelectHeatmapResponse] diff *connect.Client[v1.DiffRequest, v1.DiffResponse] getProfileStats *connect.Client[v11.GetProfileStatsRequest, v11.GetProfileStatsResponse] analyzeQuery *connect.Client[v1.AnalyzeQueryRequest, v1.AnalyzeQueryResponse] @@ -243,6 +257,11 @@ func (c *querierServiceClient) SelectSeries(ctx context.Context, req *connect.Re return c.selectSeries.CallUnary(ctx, req) } +// SelectHeatmap calls querier.v1.QuerierService.SelectHeatmap. +func (c *querierServiceClient) SelectHeatmap(ctx context.Context, req *connect.Request[v1.SelectHeatmapRequest]) (*connect.Response[v1.SelectHeatmapResponse], error) { + return c.selectHeatmap.CallUnary(ctx, req) +} + // Diff calls querier.v1.QuerierService.Diff. func (c *querierServiceClient) Diff(ctx context.Context, req *connect.Request[v1.DiffRequest]) (*connect.Response[v1.DiffResponse], error) { return c.diff.CallUnary(ctx, req) @@ -266,16 +285,33 @@ type QuerierServiceHandler interface { LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) // LabelNames returns a list of the existing label names. LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) - // Series returns profiles series matching the request. A series is a unique label set. + // Series returns profiles series matching the request. A series is a unique + // label set. Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) - // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeStacktraces(context.Context, *connect.Request[v1.SelectMergeStacktracesRequest]) (*connect.Response[v1.SelectMergeStacktracesResponse], error) - // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. + // Deprecated: Use SelectMergeStacktraces with span_selector instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. SelectMergeSpanProfile(context.Context, *connect.Request[v1.SelectMergeSpanProfileRequest]) (*connect.Response[v1.SelectMergeSpanProfileResponse], error) - // SelectMergeProfile returns matching profiles aggregated in pprof format. It will contain all information stored (so including filenames and line number, if ingested). + // Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeProfile returns matching profiles aggregated in pprof format. It + // will contain all information stored (so including filenames and line + // number, if ingested). SelectMergeProfile(context.Context, *connect.Request[v1.SelectMergeProfileRequest]) (*connect.Response[v12.Profile], error) - // SelectSeries returns a time series for the total sum of the requested profiles. + // SelectSeries returns a time series for the total sum of the requested + // profiles. SelectSeries(context.Context, *connect.Request[v1.SelectSeriesRequest]) (*connect.Response[v1.SelectSeriesResponse], error) + // SelectHeatmap returns a heatmap visualization for the requested profiles. + // Note: This endpoint is only available in the v2 storage layer + SelectHeatmap(context.Context, *connect.Request[v1.SelectHeatmapRequest]) (*connect.Response[v1.SelectHeatmapResponse], error) // Diff returns a diff of two profiles Diff(context.Context, *connect.Request[v1.DiffRequest]) (*connect.Response[v1.DiffResponse], error) // GetProfileStats returns profile stats for the current tenant. @@ -289,70 +325,77 @@ type QuerierServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewQuerierServiceHandler(svc QuerierServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + querierServiceMethods := v1.File_querier_v1_querier_proto.Services().ByName("QuerierService").Methods() querierServiceProfileTypesHandler := connect.NewUnaryHandler( QuerierServiceProfileTypesProcedure, svc.ProfileTypes, - connect.WithSchema(querierServiceProfileTypesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("ProfileTypes")), connect.WithHandlerOptions(opts...), ) querierServiceLabelValuesHandler := connect.NewUnaryHandler( QuerierServiceLabelValuesProcedure, svc.LabelValues, - connect.WithSchema(querierServiceLabelValuesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("LabelValues")), connect.WithHandlerOptions(opts...), ) querierServiceLabelNamesHandler := connect.NewUnaryHandler( QuerierServiceLabelNamesProcedure, svc.LabelNames, - connect.WithSchema(querierServiceLabelNamesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("LabelNames")), connect.WithHandlerOptions(opts...), ) querierServiceSeriesHandler := connect.NewUnaryHandler( QuerierServiceSeriesProcedure, svc.Series, - connect.WithSchema(querierServiceSeriesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("Series")), connect.WithHandlerOptions(opts...), ) querierServiceSelectMergeStacktracesHandler := connect.NewUnaryHandler( QuerierServiceSelectMergeStacktracesProcedure, svc.SelectMergeStacktraces, - connect.WithSchema(querierServiceSelectMergeStacktracesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectMergeStacktraces")), connect.WithHandlerOptions(opts...), ) querierServiceSelectMergeSpanProfileHandler := connect.NewUnaryHandler( QuerierServiceSelectMergeSpanProfileProcedure, svc.SelectMergeSpanProfile, - connect.WithSchema(querierServiceSelectMergeSpanProfileMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectMergeSpanProfile")), connect.WithHandlerOptions(opts...), ) querierServiceSelectMergeProfileHandler := connect.NewUnaryHandler( QuerierServiceSelectMergeProfileProcedure, svc.SelectMergeProfile, - connect.WithSchema(querierServiceSelectMergeProfileMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectMergeProfile")), connect.WithHandlerOptions(opts...), ) querierServiceSelectSeriesHandler := connect.NewUnaryHandler( QuerierServiceSelectSeriesProcedure, svc.SelectSeries, - connect.WithSchema(querierServiceSelectSeriesMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("SelectSeries")), + connect.WithHandlerOptions(opts...), + ) + querierServiceSelectHeatmapHandler := connect.NewUnaryHandler( + QuerierServiceSelectHeatmapProcedure, + svc.SelectHeatmap, + connect.WithSchema(querierServiceMethods.ByName("SelectHeatmap")), connect.WithHandlerOptions(opts...), ) querierServiceDiffHandler := connect.NewUnaryHandler( QuerierServiceDiffProcedure, svc.Diff, - connect.WithSchema(querierServiceDiffMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("Diff")), connect.WithHandlerOptions(opts...), ) querierServiceGetProfileStatsHandler := connect.NewUnaryHandler( QuerierServiceGetProfileStatsProcedure, svc.GetProfileStats, - connect.WithSchema(querierServiceGetProfileStatsMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("GetProfileStats")), connect.WithHandlerOptions(opts...), ) querierServiceAnalyzeQueryHandler := connect.NewUnaryHandler( QuerierServiceAnalyzeQueryProcedure, svc.AnalyzeQuery, - connect.WithSchema(querierServiceAnalyzeQueryMethodDescriptor), + connect.WithSchema(querierServiceMethods.ByName("AnalyzeQuery")), connect.WithHandlerOptions(opts...), ) return "/querier.v1.QuerierService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -373,6 +416,8 @@ func NewQuerierServiceHandler(svc QuerierServiceHandler, opts ...connect.Handler querierServiceSelectMergeProfileHandler.ServeHTTP(w, r) case QuerierServiceSelectSeriesProcedure: querierServiceSelectSeriesHandler.ServeHTTP(w, r) + case QuerierServiceSelectHeatmapProcedure: + querierServiceSelectHeatmapHandler.ServeHTTP(w, r) case QuerierServiceDiffProcedure: querierServiceDiffHandler.ServeHTTP(w, r) case QuerierServiceGetProfileStatsProcedure: @@ -420,6 +465,10 @@ func (UnimplementedQuerierServiceHandler) SelectSeries(context.Context, *connect return nil, connect.NewError(connect.CodeUnimplemented, errors.New("querier.v1.QuerierService.SelectSeries is not implemented")) } +func (UnimplementedQuerierServiceHandler) SelectHeatmap(context.Context, *connect.Request[v1.SelectHeatmapRequest]) (*connect.Response[v1.SelectHeatmapResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("querier.v1.QuerierService.SelectHeatmap is not implemented")) +} + func (UnimplementedQuerierServiceHandler) Diff(context.Context, *connect.Request[v1.DiffRequest]) (*connect.Response[v1.DiffResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("querier.v1.QuerierService.Diff is not implemented")) } diff --git a/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.mux.go b/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.mux.go index 9a82702031..9b75bebb8b 100644 --- a/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.mux.go +++ b/api/gen/proto/go/querier/v1/querierv1connect/querier.connect.mux.go @@ -59,6 +59,11 @@ func RegisterQuerierServiceHandler(mux *mux.Router, svc QuerierServiceHandler, o svc.SelectSeries, opts..., )) + mux.Handle("/querier.v1.QuerierService/SelectHeatmap", connect.NewUnaryHandler( + "/querier.v1.QuerierService/SelectHeatmap", + svc.SelectHeatmap, + opts..., + )) mux.Handle("/querier.v1.QuerierService/Diff", connect.NewUnaryHandler( "/querier.v1.QuerierService/Diff", svc.Diff, diff --git a/api/gen/proto/go/query/v1/query.pb.go b/api/gen/proto/go/query/v1/query.pb.go new file mode 100644 index 0000000000..3a9aff079b --- /dev/null +++ b/api/gen/proto/go/query/v1/query.pb.go @@ -0,0 +1,3108 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: query/v1/query.proto + +package queryv1 + +import ( + v12 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + v13 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + v11 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type QueryType int32 + +const ( + QueryType_QUERY_UNSPECIFIED QueryType = 0 + QueryType_QUERY_LABEL_NAMES QueryType = 1 + QueryType_QUERY_LABEL_VALUES QueryType = 2 + QueryType_QUERY_SERIES_LABELS QueryType = 3 + QueryType_QUERY_TIME_SERIES QueryType = 4 + QueryType_QUERY_TREE QueryType = 5 + QueryType_QUERY_PPROF QueryType = 6 + QueryType_QUERY_HEATMAP QueryType = 7 + QueryType_QUERY_TIME_SERIES_COMPACT QueryType = 8 +) + +// Enum value maps for QueryType. +var ( + QueryType_name = map[int32]string{ + 0: "QUERY_UNSPECIFIED", + 1: "QUERY_LABEL_NAMES", + 2: "QUERY_LABEL_VALUES", + 3: "QUERY_SERIES_LABELS", + 4: "QUERY_TIME_SERIES", + 5: "QUERY_TREE", + 6: "QUERY_PPROF", + 7: "QUERY_HEATMAP", + 8: "QUERY_TIME_SERIES_COMPACT", + } + QueryType_value = map[string]int32{ + "QUERY_UNSPECIFIED": 0, + "QUERY_LABEL_NAMES": 1, + "QUERY_LABEL_VALUES": 2, + "QUERY_SERIES_LABELS": 3, + "QUERY_TIME_SERIES": 4, + "QUERY_TREE": 5, + "QUERY_PPROF": 6, + "QUERY_HEATMAP": 7, + "QUERY_TIME_SERIES_COMPACT": 8, + } +) + +func (x QueryType) Enum() *QueryType { + p := new(QueryType) + *p = x + return p +} + +func (x QueryType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (QueryType) Descriptor() protoreflect.EnumDescriptor { + return file_query_v1_query_proto_enumTypes[0].Descriptor() +} + +func (QueryType) Type() protoreflect.EnumType { + return &file_query_v1_query_proto_enumTypes[0] +} + +func (x QueryType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use QueryType.Descriptor instead. +func (QueryType) EnumDescriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{0} +} + +type ReportType int32 + +const ( + ReportType_REPORT_UNSPECIFIED ReportType = 0 + ReportType_REPORT_LABEL_NAMES ReportType = 1 + ReportType_REPORT_LABEL_VALUES ReportType = 2 + ReportType_REPORT_SERIES_LABELS ReportType = 3 + ReportType_REPORT_TIME_SERIES ReportType = 4 + ReportType_REPORT_TREE ReportType = 5 + ReportType_REPORT_PPROF ReportType = 6 + ReportType_REPORT_HEATMAP ReportType = 7 + ReportType_REPORT_TIME_SERIES_COMPACT ReportType = 8 +) + +// Enum value maps for ReportType. +var ( + ReportType_name = map[int32]string{ + 0: "REPORT_UNSPECIFIED", + 1: "REPORT_LABEL_NAMES", + 2: "REPORT_LABEL_VALUES", + 3: "REPORT_SERIES_LABELS", + 4: "REPORT_TIME_SERIES", + 5: "REPORT_TREE", + 6: "REPORT_PPROF", + 7: "REPORT_HEATMAP", + 8: "REPORT_TIME_SERIES_COMPACT", + } + ReportType_value = map[string]int32{ + "REPORT_UNSPECIFIED": 0, + "REPORT_LABEL_NAMES": 1, + "REPORT_LABEL_VALUES": 2, + "REPORT_SERIES_LABELS": 3, + "REPORT_TIME_SERIES": 4, + "REPORT_TREE": 5, + "REPORT_PPROF": 6, + "REPORT_HEATMAP": 7, + "REPORT_TIME_SERIES_COMPACT": 8, + } +) + +func (x ReportType) Enum() *ReportType { + p := new(ReportType) + *p = x + return p +} + +func (x ReportType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ReportType) Descriptor() protoreflect.EnumDescriptor { + return file_query_v1_query_proto_enumTypes[1].Descriptor() +} + +func (ReportType) Type() protoreflect.EnumType { + return &file_query_v1_query_proto_enumTypes[1] +} + +func (x ReportType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ReportType.Descriptor instead. +func (ReportType) EnumDescriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{1} +} + +// SymbolMode selects how a TreeQuery reports frame symbols. +type SymbolMode int32 + +const ( + SymbolMode_SYMBOL_MODE_UNSPECIFIED SymbolMode = 0 + SymbolMode_SYMBOL_MODE_NAME SymbolMode = 1 // frame names only + SymbolMode_SYMBOL_MODE_FULL SymbolMode = 2 // full pprof symbol tables alongside the tree + SymbolMode_SYMBOL_MODE_REFS SymbolMode = 3 // compact symbol-ref side table for deferred resolution +) + +// Enum value maps for SymbolMode. +var ( + SymbolMode_name = map[int32]string{ + 0: "SYMBOL_MODE_UNSPECIFIED", + 1: "SYMBOL_MODE_NAME", + 2: "SYMBOL_MODE_FULL", + 3: "SYMBOL_MODE_REFS", + } + SymbolMode_value = map[string]int32{ + "SYMBOL_MODE_UNSPECIFIED": 0, + "SYMBOL_MODE_NAME": 1, + "SYMBOL_MODE_FULL": 2, + "SYMBOL_MODE_REFS": 3, + } +) + +func (x SymbolMode) Enum() *SymbolMode { + p := new(SymbolMode) + *p = x + return p +} + +func (x SymbolMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SymbolMode) Descriptor() protoreflect.EnumDescriptor { + return file_query_v1_query_proto_enumTypes[2].Descriptor() +} + +func (SymbolMode) Type() protoreflect.EnumType { + return &file_query_v1_query_proto_enumTypes[2] +} + +func (x SymbolMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SymbolMode.Descriptor instead. +func (SymbolMode) EnumDescriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{2} +} + +type QueryNode_Type int32 + +const ( + QueryNode_UNKNOWN QueryNode_Type = 0 + QueryNode_MERGE QueryNode_Type = 1 + QueryNode_READ QueryNode_Type = 2 +) + +// Enum value maps for QueryNode_Type. +var ( + QueryNode_Type_name = map[int32]string{ + 0: "UNKNOWN", + 1: "MERGE", + 2: "READ", + } + QueryNode_Type_value = map[string]int32{ + "UNKNOWN": 0, + "MERGE": 1, + "READ": 2, + } +) + +func (x QueryNode_Type) Enum() *QueryNode_Type { + p := new(QueryNode_Type) + *p = x + return p +} + +func (x QueryNode_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (QueryNode_Type) Descriptor() protoreflect.EnumDescriptor { + return file_query_v1_query_proto_enumTypes[3].Descriptor() +} + +func (QueryNode_Type) Type() protoreflect.EnumType { + return &file_query_v1_query_proto_enumTypes[3] +} + +func (x QueryNode_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use QueryNode_Type.Descriptor instead. +func (QueryNode_Type) EnumDescriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{5, 0} +} + +type QueryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + StartTime int64 `protobuf:"varint,1,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + EndTime int64 `protobuf:"varint,2,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + LabelSelector string `protobuf:"bytes,3,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` + Query []*Query `protobuf:"bytes,4,rep,name=query,proto3" json:"query,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryRequest) Reset() { + *x = QueryRequest{} + mi := &file_query_v1_query_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryRequest) ProtoMessage() {} + +func (x *QueryRequest) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryRequest.ProtoReflect.Descriptor instead. +func (*QueryRequest) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{0} +} + +func (x *QueryRequest) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *QueryRequest) GetEndTime() int64 { + if x != nil { + return x.EndTime + } + return 0 +} + +func (x *QueryRequest) GetLabelSelector() string { + if x != nil { + return x.LabelSelector + } + return "" +} + +func (x *QueryRequest) GetQuery() []*Query { + if x != nil { + return x.Query + } + return nil +} + +type QueryResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reports []*Report `protobuf:"bytes,1,rep,name=reports,proto3" json:"reports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryResponse) Reset() { + *x = QueryResponse{} + mi := &file_query_v1_query_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryResponse) ProtoMessage() {} + +func (x *QueryResponse) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryResponse.ProtoReflect.Descriptor instead. +func (*QueryResponse) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{1} +} + +func (x *QueryResponse) GetReports() []*Report { + if x != nil { + return x.Reports + } + return nil +} + +type InvokeOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Query workers might not have access to the tenant + // overrides, therefore all the necessary options should + // be listed in the request explicitly. + SanitizeOnMerge bool `protobuf:"varint,1,opt,name=sanitize_on_merge,json=sanitizeOnMerge,proto3" json:"sanitize_on_merge,omitempty"` + CollectDiagnostics bool `protobuf:"varint,2,opt,name=collect_diagnostics,json=collectDiagnostics,proto3" json:"collect_diagnostics,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InvokeOptions) Reset() { + *x = InvokeOptions{} + mi := &file_query_v1_query_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InvokeOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvokeOptions) ProtoMessage() {} + +func (x *InvokeOptions) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvokeOptions.ProtoReflect.Descriptor instead. +func (*InvokeOptions) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{2} +} + +func (x *InvokeOptions) GetSanitizeOnMerge() bool { + if x != nil { + return x.SanitizeOnMerge + } + return false +} + +func (x *InvokeOptions) GetCollectDiagnostics() bool { + if x != nil { + return x.CollectDiagnostics + } + return false +} + +type InvokeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tenant []string `protobuf:"bytes,1,rep,name=tenant,proto3" json:"tenant,omitempty"` + StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + EndTime int64 `protobuf:"varint,3,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + LabelSelector string `protobuf:"bytes,4,opt,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty"` + Query []*Query `protobuf:"bytes,5,rep,name=query,proto3" json:"query,omitempty"` + QueryPlan *QueryPlan `protobuf:"bytes,6,opt,name=query_plan,json=queryPlan,proto3" json:"query_plan,omitempty"` + Options *InvokeOptions `protobuf:"bytes,7,opt,name=options,proto3" json:"options,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InvokeRequest) Reset() { + *x = InvokeRequest{} + mi := &file_query_v1_query_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InvokeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvokeRequest) ProtoMessage() {} + +func (x *InvokeRequest) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvokeRequest.ProtoReflect.Descriptor instead. +func (*InvokeRequest) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{3} +} + +func (x *InvokeRequest) GetTenant() []string { + if x != nil { + return x.Tenant + } + return nil +} + +func (x *InvokeRequest) GetStartTime() int64 { + if x != nil { + return x.StartTime + } + return 0 +} + +func (x *InvokeRequest) GetEndTime() int64 { + if x != nil { + return x.EndTime + } + return 0 +} + +func (x *InvokeRequest) GetLabelSelector() string { + if x != nil { + return x.LabelSelector + } + return "" +} + +func (x *InvokeRequest) GetQuery() []*Query { + if x != nil { + return x.Query + } + return nil +} + +func (x *InvokeRequest) GetQueryPlan() *QueryPlan { + if x != nil { + return x.QueryPlan + } + return nil +} + +func (x *InvokeRequest) GetOptions() *InvokeOptions { + if x != nil { + return x.Options + } + return nil +} + +// A query plan is represented by a directed acyclic graph (DAG), +// where each node is either a "merge" node or a "read" node. +// +// Merge nodes reference other nodes in the plan as their "children". +// Read nodes reference the blocks which contain the actual data to be processed. +type QueryPlan struct { + state protoimpl.MessageState `protogen:"open.v1"` + Root *QueryNode `protobuf:"bytes,1,opt,name=root,proto3" json:"root,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryPlan) Reset() { + *x = QueryPlan{} + mi := &file_query_v1_query_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryPlan) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryPlan) ProtoMessage() {} + +func (x *QueryPlan) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryPlan.ProtoReflect.Descriptor instead. +func (*QueryPlan) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{4} +} + +func (x *QueryPlan) GetRoot() *QueryNode { + if x != nil { + return x.Root + } + return nil +} + +type QueryNode struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type QueryNode_Type `protobuf:"varint,1,opt,name=type,proto3,enum=query.v1.QueryNode_Type" json:"type,omitempty"` + Children []*QueryNode `protobuf:"bytes,2,rep,name=children,proto3" json:"children,omitempty"` + Blocks []*v1.BlockMeta `protobuf:"bytes,3,rep,name=blocks,proto3" json:"blocks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *QueryNode) Reset() { + *x = QueryNode{} + mi := &file_query_v1_query_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QueryNode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryNode) ProtoMessage() {} + +func (x *QueryNode) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryNode.ProtoReflect.Descriptor instead. +func (*QueryNode) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{5} +} + +func (x *QueryNode) GetType() QueryNode_Type { + if x != nil { + return x.Type + } + return QueryNode_UNKNOWN +} + +func (x *QueryNode) GetChildren() []*QueryNode { + if x != nil { + return x.Children + } + return nil +} + +func (x *QueryNode) GetBlocks() []*v1.BlockMeta { + if x != nil { + return x.Blocks + } + return nil +} + +type Query struct { + state protoimpl.MessageState `protogen:"open.v1"` + QueryType QueryType `protobuf:"varint,1,opt,name=query_type,json=queryType,proto3,enum=query.v1.QueryType" json:"query_type,omitempty"` + // Exactly one of the following fields should be set, + // depending on the query type. + LabelNames *LabelNamesQuery `protobuf:"bytes,2,opt,name=label_names,json=labelNames,proto3" json:"label_names,omitempty"` + LabelValues *LabelValuesQuery `protobuf:"bytes,3,opt,name=label_values,json=labelValues,proto3" json:"label_values,omitempty"` + SeriesLabels *SeriesLabelsQuery `protobuf:"bytes,4,opt,name=series_labels,json=seriesLabels,proto3" json:"series_labels,omitempty"` + TimeSeries *TimeSeriesQuery `protobuf:"bytes,5,opt,name=time_series,json=timeSeries,proto3" json:"time_series,omitempty"` + Tree *TreeQuery `protobuf:"bytes,6,opt,name=tree,proto3" json:"tree,omitempty"` + Pprof *PprofQuery `protobuf:"bytes,7,opt,name=pprof,proto3" json:"pprof,omitempty"` + Heatmap *HeatmapQuery `protobuf:"bytes,8,opt,name=heatmap,proto3" json:"heatmap,omitempty"` + TimeSeriesCompact *TimeSeriesQuery `protobuf:"bytes,9,opt,name=time_series_compact,json=timeSeriesCompact,proto3" json:"time_series_compact,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Query) Reset() { + *x = Query{} + mi := &file_query_v1_query_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Query) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Query) ProtoMessage() {} + +func (x *Query) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Query.ProtoReflect.Descriptor instead. +func (*Query) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{6} +} + +func (x *Query) GetQueryType() QueryType { + if x != nil { + return x.QueryType + } + return QueryType_QUERY_UNSPECIFIED +} + +func (x *Query) GetLabelNames() *LabelNamesQuery { + if x != nil { + return x.LabelNames + } + return nil +} + +func (x *Query) GetLabelValues() *LabelValuesQuery { + if x != nil { + return x.LabelValues + } + return nil +} + +func (x *Query) GetSeriesLabels() *SeriesLabelsQuery { + if x != nil { + return x.SeriesLabels + } + return nil +} + +func (x *Query) GetTimeSeries() *TimeSeriesQuery { + if x != nil { + return x.TimeSeries + } + return nil +} + +func (x *Query) GetTree() *TreeQuery { + if x != nil { + return x.Tree + } + return nil +} + +func (x *Query) GetPprof() *PprofQuery { + if x != nil { + return x.Pprof + } + return nil +} + +func (x *Query) GetHeatmap() *HeatmapQuery { + if x != nil { + return x.Heatmap + } + return nil +} + +func (x *Query) GetTimeSeriesCompact() *TimeSeriesQuery { + if x != nil { + return x.TimeSeriesCompact + } + return nil +} + +type InvokeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reports []*Report `protobuf:"bytes,1,rep,name=reports,proto3" json:"reports,omitempty"` + Diagnostics *Diagnostics `protobuf:"bytes,2,opt,name=diagnostics,proto3" json:"diagnostics,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InvokeResponse) Reset() { + *x = InvokeResponse{} + mi := &file_query_v1_query_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InvokeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvokeResponse) ProtoMessage() {} + +func (x *InvokeResponse) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvokeResponse.ProtoReflect.Descriptor instead. +func (*InvokeResponse) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{7} +} + +func (x *InvokeResponse) GetReports() []*Report { + if x != nil { + return x.Reports + } + return nil +} + +func (x *InvokeResponse) GetDiagnostics() *Diagnostics { + if x != nil { + return x.Diagnostics + } + return nil +} + +// Diagnostic messages, events, statistics, analytics, etc. +type Diagnostics struct { + state protoimpl.MessageState `protogen:"open.v1"` + QueryPlan *QueryPlan `protobuf:"bytes,1,opt,name=query_plan,json=queryPlan,proto3" json:"query_plan,omitempty"` + ExecutionNode *ExecutionNode `protobuf:"bytes,2,opt,name=execution_node,json=executionNode,proto3" json:"execution_node,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Diagnostics) Reset() { + *x = Diagnostics{} + mi := &file_query_v1_query_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Diagnostics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Diagnostics) ProtoMessage() {} + +func (x *Diagnostics) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Diagnostics.ProtoReflect.Descriptor instead. +func (*Diagnostics) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{8} +} + +func (x *Diagnostics) GetQueryPlan() *QueryPlan { + if x != nil { + return x.QueryPlan + } + return nil +} + +func (x *Diagnostics) GetExecutionNode() *ExecutionNode { + if x != nil { + return x.ExecutionNode + } + return nil +} + +// ExecutionNode captures how a query plan node was actually executed. +type ExecutionNode struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type QueryNode_Type `protobuf:"varint,1,opt,name=type,proto3,enum=query.v1.QueryNode_Type" json:"type,omitempty"` + Executor string `protobuf:"bytes,2,opt,name=executor,proto3" json:"executor,omitempty"` + StartTimeNs int64 `protobuf:"varint,3,opt,name=start_time_ns,json=startTimeNs,proto3" json:"start_time_ns,omitempty"` + EndTimeNs int64 `protobuf:"varint,4,opt,name=end_time_ns,json=endTimeNs,proto3" json:"end_time_ns,omitempty"` + Children []*ExecutionNode `protobuf:"bytes,5,rep,name=children,proto3" json:"children,omitempty"` + Stats *ExecutionStats `protobuf:"bytes,6,opt,name=stats,proto3" json:"stats,omitempty"` + Error string `protobuf:"bytes,7,opt,name=error,proto3" json:"error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecutionNode) Reset() { + *x = ExecutionNode{} + mi := &file_query_v1_query_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecutionNode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecutionNode) ProtoMessage() {} + +func (x *ExecutionNode) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecutionNode.ProtoReflect.Descriptor instead. +func (*ExecutionNode) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{9} +} + +func (x *ExecutionNode) GetType() QueryNode_Type { + if x != nil { + return x.Type + } + return QueryNode_UNKNOWN +} + +func (x *ExecutionNode) GetExecutor() string { + if x != nil { + return x.Executor + } + return "" +} + +func (x *ExecutionNode) GetStartTimeNs() int64 { + if x != nil { + return x.StartTimeNs + } + return 0 +} + +func (x *ExecutionNode) GetEndTimeNs() int64 { + if x != nil { + return x.EndTimeNs + } + return 0 +} + +func (x *ExecutionNode) GetChildren() []*ExecutionNode { + if x != nil { + return x.Children + } + return nil +} + +func (x *ExecutionNode) GetStats() *ExecutionStats { + if x != nil { + return x.Stats + } + return nil +} + +func (x *ExecutionNode) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +// ExecutionStats captures statistics for READ node execution. +type ExecutionStats struct { + state protoimpl.MessageState `protogen:"open.v1"` + BlocksRead int64 `protobuf:"varint,1,opt,name=blocks_read,json=blocksRead,proto3" json:"blocks_read,omitempty"` + DatasetsProcessed int64 `protobuf:"varint,2,opt,name=datasets_processed,json=datasetsProcessed,proto3" json:"datasets_processed,omitempty"` + BlockExecutions []*BlockExecution `protobuf:"bytes,3,rep,name=block_executions,json=blockExecutions,proto3" json:"block_executions,omitempty"` + // bytes_fetched is the total number of bytes requested from object storage + // during this invocation. It counts only the bytes from this single, + // successful Invoke call: retried or hedged calls that did not produce a + // response are not included, so the value is deterministic across retries. + BytesFetched uint64 `protobuf:"varint,4,opt,name=bytes_fetched,json=bytesFetched,proto3" json:"bytes_fetched,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecutionStats) Reset() { + *x = ExecutionStats{} + mi := &file_query_v1_query_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecutionStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecutionStats) ProtoMessage() {} + +func (x *ExecutionStats) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecutionStats.ProtoReflect.Descriptor instead. +func (*ExecutionStats) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{10} +} + +func (x *ExecutionStats) GetBlocksRead() int64 { + if x != nil { + return x.BlocksRead + } + return 0 +} + +func (x *ExecutionStats) GetDatasetsProcessed() int64 { + if x != nil { + return x.DatasetsProcessed + } + return 0 +} + +func (x *ExecutionStats) GetBlockExecutions() []*BlockExecution { + if x != nil { + return x.BlockExecutions + } + return nil +} + +func (x *ExecutionStats) GetBytesFetched() uint64 { + if x != nil { + return x.BytesFetched + } + return 0 +} + +// BlockExecution captures execution details for a single block. +type BlockExecution struct { + state protoimpl.MessageState `protogen:"open.v1"` + BlockId string `protobuf:"bytes,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"` + StartTimeNs int64 `protobuf:"varint,2,opt,name=start_time_ns,json=startTimeNs,proto3" json:"start_time_ns,omitempty"` + EndTimeNs int64 `protobuf:"varint,3,opt,name=end_time_ns,json=endTimeNs,proto3" json:"end_time_ns,omitempty"` + DatasetsProcessed int64 `protobuf:"varint,4,opt,name=datasets_processed,json=datasetsProcessed,proto3" json:"datasets_processed,omitempty"` + Size uint64 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` + Shard uint32 `protobuf:"varint,6,opt,name=shard,proto3" json:"shard,omitempty"` + CompactionLevel uint32 `protobuf:"varint,7,opt,name=compaction_level,json=compactionLevel,proto3" json:"compaction_level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BlockExecution) Reset() { + *x = BlockExecution{} + mi := &file_query_v1_query_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BlockExecution) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockExecution) ProtoMessage() {} + +func (x *BlockExecution) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockExecution.ProtoReflect.Descriptor instead. +func (*BlockExecution) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{11} +} + +func (x *BlockExecution) GetBlockId() string { + if x != nil { + return x.BlockId + } + return "" +} + +func (x *BlockExecution) GetStartTimeNs() int64 { + if x != nil { + return x.StartTimeNs + } + return 0 +} + +func (x *BlockExecution) GetEndTimeNs() int64 { + if x != nil { + return x.EndTimeNs + } + return 0 +} + +func (x *BlockExecution) GetDatasetsProcessed() int64 { + if x != nil { + return x.DatasetsProcessed + } + return 0 +} + +func (x *BlockExecution) GetSize() uint64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *BlockExecution) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *BlockExecution) GetCompactionLevel() uint32 { + if x != nil { + return x.CompactionLevel + } + return 0 +} + +type Report struct { + state protoimpl.MessageState `protogen:"open.v1"` + ReportType ReportType `protobuf:"varint,1,opt,name=report_type,json=reportType,proto3,enum=query.v1.ReportType" json:"report_type,omitempty"` + // Exactly one of the following fields should be set, + // depending on the report type. + LabelNames *LabelNamesReport `protobuf:"bytes,2,opt,name=label_names,json=labelNames,proto3" json:"label_names,omitempty"` + LabelValues *LabelValuesReport `protobuf:"bytes,3,opt,name=label_values,json=labelValues,proto3" json:"label_values,omitempty"` + SeriesLabels *SeriesLabelsReport `protobuf:"bytes,4,opt,name=series_labels,json=seriesLabels,proto3" json:"series_labels,omitempty"` + TimeSeries *TimeSeriesReport `protobuf:"bytes,5,opt,name=time_series,json=timeSeries,proto3" json:"time_series,omitempty"` + Tree *TreeReport `protobuf:"bytes,6,opt,name=tree,proto3" json:"tree,omitempty"` + Pprof *PprofReport `protobuf:"bytes,7,opt,name=pprof,proto3" json:"pprof,omitempty"` + Heatmap *HeatmapReport `protobuf:"bytes,8,opt,name=heatmap,proto3" json:"heatmap,omitempty"` + TimeSeriesCompact *TimeSeriesCompactReport `protobuf:"bytes,9,opt,name=time_series_compact,json=timeSeriesCompact,proto3" json:"time_series_compact,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Report) Reset() { + *x = Report{} + mi := &file_query_v1_query_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Report) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Report) ProtoMessage() {} + +func (x *Report) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Report.ProtoReflect.Descriptor instead. +func (*Report) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{12} +} + +func (x *Report) GetReportType() ReportType { + if x != nil { + return x.ReportType + } + return ReportType_REPORT_UNSPECIFIED +} + +func (x *Report) GetLabelNames() *LabelNamesReport { + if x != nil { + return x.LabelNames + } + return nil +} + +func (x *Report) GetLabelValues() *LabelValuesReport { + if x != nil { + return x.LabelValues + } + return nil +} + +func (x *Report) GetSeriesLabels() *SeriesLabelsReport { + if x != nil { + return x.SeriesLabels + } + return nil +} + +func (x *Report) GetTimeSeries() *TimeSeriesReport { + if x != nil { + return x.TimeSeries + } + return nil +} + +func (x *Report) GetTree() *TreeReport { + if x != nil { + return x.Tree + } + return nil +} + +func (x *Report) GetPprof() *PprofReport { + if x != nil { + return x.Pprof + } + return nil +} + +func (x *Report) GetHeatmap() *HeatmapReport { + if x != nil { + return x.Heatmap + } + return nil +} + +func (x *Report) GetTimeSeriesCompact() *TimeSeriesCompactReport { + if x != nil { + return x.TimeSeriesCompact + } + return nil +} + +type LabelNamesQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LabelNamesQuery) Reset() { + *x = LabelNamesQuery{} + mi := &file_query_v1_query_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LabelNamesQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LabelNamesQuery) ProtoMessage() {} + +func (x *LabelNamesQuery) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LabelNamesQuery.ProtoReflect.Descriptor instead. +func (*LabelNamesQuery) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{13} +} + +type LabelNamesReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *LabelNamesQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + LabelNames []string `protobuf:"bytes,2,rep,name=label_names,json=labelNames,proto3" json:"label_names,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LabelNamesReport) Reset() { + *x = LabelNamesReport{} + mi := &file_query_v1_query_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LabelNamesReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LabelNamesReport) ProtoMessage() {} + +func (x *LabelNamesReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LabelNamesReport.ProtoReflect.Descriptor instead. +func (*LabelNamesReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{14} +} + +func (x *LabelNamesReport) GetQuery() *LabelNamesQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *LabelNamesReport) GetLabelNames() []string { + if x != nil { + return x.LabelNames + } + return nil +} + +type LabelValuesQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + LabelName string `protobuf:"bytes,1,opt,name=label_name,json=labelName,proto3" json:"label_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LabelValuesQuery) Reset() { + *x = LabelValuesQuery{} + mi := &file_query_v1_query_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LabelValuesQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LabelValuesQuery) ProtoMessage() {} + +func (x *LabelValuesQuery) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LabelValuesQuery.ProtoReflect.Descriptor instead. +func (*LabelValuesQuery) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{15} +} + +func (x *LabelValuesQuery) GetLabelName() string { + if x != nil { + return x.LabelName + } + return "" +} + +type LabelValuesReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *LabelValuesQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + LabelValues []string `protobuf:"bytes,2,rep,name=label_values,json=labelValues,proto3" json:"label_values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LabelValuesReport) Reset() { + *x = LabelValuesReport{} + mi := &file_query_v1_query_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LabelValuesReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LabelValuesReport) ProtoMessage() {} + +func (x *LabelValuesReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LabelValuesReport.ProtoReflect.Descriptor instead. +func (*LabelValuesReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{16} +} + +func (x *LabelValuesReport) GetQuery() *LabelValuesQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *LabelValuesReport) GetLabelValues() []string { + if x != nil { + return x.LabelValues + } + return nil +} + +type SeriesLabelsQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + LabelNames []string `protobuf:"bytes,1,rep,name=label_names,json=labelNames,proto3" json:"label_names,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SeriesLabelsQuery) Reset() { + *x = SeriesLabelsQuery{} + mi := &file_query_v1_query_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SeriesLabelsQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SeriesLabelsQuery) ProtoMessage() {} + +func (x *SeriesLabelsQuery) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SeriesLabelsQuery.ProtoReflect.Descriptor instead. +func (*SeriesLabelsQuery) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{17} +} + +func (x *SeriesLabelsQuery) GetLabelNames() []string { + if x != nil { + return x.LabelNames + } + return nil +} + +type SeriesLabelsReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *SeriesLabelsQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + SeriesLabels []*v11.Labels `protobuf:"bytes,2,rep,name=series_labels,json=seriesLabels,proto3" json:"series_labels,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SeriesLabelsReport) Reset() { + *x = SeriesLabelsReport{} + mi := &file_query_v1_query_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SeriesLabelsReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SeriesLabelsReport) ProtoMessage() {} + +func (x *SeriesLabelsReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SeriesLabelsReport.ProtoReflect.Descriptor instead. +func (*SeriesLabelsReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{18} +} + +func (x *SeriesLabelsReport) GetQuery() *SeriesLabelsQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *SeriesLabelsReport) GetSeriesLabels() []*v11.Labels { + if x != nil { + return x.SeriesLabels + } + return nil +} + +type TimeSeriesQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + Step float64 `protobuf:"fixed64,1,opt,name=step,proto3" json:"step,omitempty"` + GroupBy []string `protobuf:"bytes,2,rep,name=group_by,json=groupBy,proto3" json:"group_by,omitempty"` + Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + ExemplarType v11.ExemplarType `protobuf:"varint,4,opt,name=exemplar_type,json=exemplarType,proto3,enum=types.v1.ExemplarType" json:"exemplar_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TimeSeriesQuery) Reset() { + *x = TimeSeriesQuery{} + mi := &file_query_v1_query_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TimeSeriesQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TimeSeriesQuery) ProtoMessage() {} + +func (x *TimeSeriesQuery) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TimeSeriesQuery.ProtoReflect.Descriptor instead. +func (*TimeSeriesQuery) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{19} +} + +func (x *TimeSeriesQuery) GetStep() float64 { + if x != nil { + return x.Step + } + return 0 +} + +func (x *TimeSeriesQuery) GetGroupBy() []string { + if x != nil { + return x.GroupBy + } + return nil +} + +func (x *TimeSeriesQuery) GetLimit() int64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *TimeSeriesQuery) GetExemplarType() v11.ExemplarType { + if x != nil { + return x.ExemplarType + } + return v11.ExemplarType(0) +} + +type TimeSeriesReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *TimeSeriesQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + TimeSeries []*v11.Series `protobuf:"bytes,2,rep,name=time_series,json=timeSeries,proto3" json:"time_series,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TimeSeriesReport) Reset() { + *x = TimeSeriesReport{} + mi := &file_query_v1_query_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TimeSeriesReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TimeSeriesReport) ProtoMessage() {} + +func (x *TimeSeriesReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TimeSeriesReport.ProtoReflect.Descriptor instead. +func (*TimeSeriesReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{20} +} + +func (x *TimeSeriesReport) GetQuery() *TimeSeriesQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *TimeSeriesReport) GetTimeSeries() []*v11.Series { + if x != nil { + return x.TimeSeries + } + return nil +} + +type TreeQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + MaxNodes int64 `protobuf:"varint,1,opt,name=max_nodes,json=maxNodes,proto3" json:"max_nodes,omitempty"` + SpanSelector []string `protobuf:"bytes,2,rep,name=span_selector,json=spanSelector,proto3" json:"span_selector,omitempty"` + StackTraceSelector *v11.StackTraceSelector `protobuf:"bytes,3,opt,name=stack_trace_selector,json=stackTraceSelector,proto3,oneof" json:"stack_trace_selector,omitempty"` + ProfileIdSelector []string `protobuf:"bytes,4,rep,name=profile_id_selector,json=profileIdSelector,proto3" json:"profile_id_selector,omitempty"` + // Deprecated: use symbol_mode = SYMBOL_MODE_FULL. Retained for wire + // compatibility; will be removed in a couple of releases. + FullSymbols bool `protobuf:"varint,5,opt,name=full_symbols,json=fullSymbols,proto3" json:"full_symbols,omitempty"` + TraceIdSelector []string `protobuf:"bytes,6,rep,name=trace_id_selector,json=traceIdSelector,proto3" json:"trace_id_selector,omitempty"` + // symbol_mode selects the symbol output. When unset, full_symbols is honored + // for back-compat. + SymbolMode SymbolMode `protobuf:"varint,7,opt,name=symbol_mode,json=symbolMode,proto3,enum=query.v1.SymbolMode" json:"symbol_mode,omitempty"` + // max_unresolved_locations bounds the distinct unresolved locations a + // symbol-ref tree result may carry; the query fails past it. Zero means + // unlimited. Effective only with SYMBOL_MODE_REFS. + MaxUnresolvedLocations int64 `protobuf:"varint,8,opt,name=max_unresolved_locations,json=maxUnresolvedLocations,proto3" json:"max_unresolved_locations,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TreeQuery) Reset() { + *x = TreeQuery{} + mi := &file_query_v1_query_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TreeQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TreeQuery) ProtoMessage() {} + +func (x *TreeQuery) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TreeQuery.ProtoReflect.Descriptor instead. +func (*TreeQuery) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{21} +} + +func (x *TreeQuery) GetMaxNodes() int64 { + if x != nil { + return x.MaxNodes + } + return 0 +} + +func (x *TreeQuery) GetSpanSelector() []string { + if x != nil { + return x.SpanSelector + } + return nil +} + +func (x *TreeQuery) GetStackTraceSelector() *v11.StackTraceSelector { + if x != nil { + return x.StackTraceSelector + } + return nil +} + +func (x *TreeQuery) GetProfileIdSelector() []string { + if x != nil { + return x.ProfileIdSelector + } + return nil +} + +func (x *TreeQuery) GetFullSymbols() bool { + if x != nil { + return x.FullSymbols + } + return false +} + +func (x *TreeQuery) GetTraceIdSelector() []string { + if x != nil { + return x.TraceIdSelector + } + return nil +} + +func (x *TreeQuery) GetSymbolMode() SymbolMode { + if x != nil { + return x.SymbolMode + } + return SymbolMode_SYMBOL_MODE_UNSPECIFIED +} + +func (x *TreeQuery) GetMaxUnresolvedLocations() int64 { + if x != nil { + return x.MaxUnresolvedLocations + } + return 0 +} + +type TreeSymbols struct { + state protoimpl.MessageState `protogen:"open.v1"` + Mappings []*v12.Mapping `protobuf:"bytes,1,rep,name=mappings,proto3" json:"mappings,omitempty"` + Locations []*v12.Location `protobuf:"bytes,2,rep,name=locations,proto3" json:"locations,omitempty"` + Functions []*v12.Function `protobuf:"bytes,3,rep,name=functions,proto3" json:"functions,omitempty"` + Strings []string `protobuf:"bytes,4,rep,name=strings,proto3" json:"strings,omitempty"` + MappingHashes []uint64 `protobuf:"varint,5,rep,packed,name=mapping_hashes,json=mappingHashes,proto3" json:"mapping_hashes,omitempty"` + LocationHashes []uint64 `protobuf:"varint,6,rep,packed,name=location_hashes,json=locationHashes,proto3" json:"location_hashes,omitempty"` + FunctionHashes []uint64 `protobuf:"varint,7,rep,packed,name=function_hashes,json=functionHashes,proto3" json:"function_hashes,omitempty"` + StringHashes []uint64 `protobuf:"varint,8,rep,packed,name=string_hashes,json=stringHashes,proto3" json:"string_hashes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TreeSymbols) Reset() { + *x = TreeSymbols{} + mi := &file_query_v1_query_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TreeSymbols) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TreeSymbols) ProtoMessage() {} + +func (x *TreeSymbols) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TreeSymbols.ProtoReflect.Descriptor instead. +func (*TreeSymbols) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{22} +} + +func (x *TreeSymbols) GetMappings() []*v12.Mapping { + if x != nil { + return x.Mappings + } + return nil +} + +func (x *TreeSymbols) GetLocations() []*v12.Location { + if x != nil { + return x.Locations + } + return nil +} + +func (x *TreeSymbols) GetFunctions() []*v12.Function { + if x != nil { + return x.Functions + } + return nil +} + +func (x *TreeSymbols) GetStrings() []string { + if x != nil { + return x.Strings + } + return nil +} + +func (x *TreeSymbols) GetMappingHashes() []uint64 { + if x != nil { + return x.MappingHashes + } + return nil +} + +func (x *TreeSymbols) GetLocationHashes() []uint64 { + if x != nil { + return x.LocationHashes + } + return nil +} + +func (x *TreeSymbols) GetFunctionHashes() []uint64 { + if x != nil { + return x.FunctionHashes + } + return nil +} + +func (x *TreeSymbols) GetStringHashes() []uint64 { + if x != nil { + return x.StringHashes + } + return nil +} + +// SymbolRefTable resolves the integer frame references in a symbol-ref tree. +// Each tree node stores one frame reference r; whether r is resolved depends on +// whether it falls inside the names slice: +// +// r < len(names): resolved -> names[r] is the frame name. +// r >= len(names): unresolved -> u = r - len(names) indexes the parallel +// unresolved_* arrays: +// build_ids[unresolved_build_id[u]] build ID of the binary +// unresolved_address[u] address within it +// +// build_ids and binary_names are parallel and 1:1 (binary_names[k] is the +// "binary!0xaddr" fallback display for build_ids[k]); each (build ID, +// binary name) pair appears once — the same build ID may repeat under +// different binary names, each retained exactly as stored. +// unresolved_build_id and unresolved_address are parallel, one entry per +// unresolved location, sorted by (build ID, binary name, address). +type SymbolRefTable struct { + state protoimpl.MessageState `protogen:"open.v1"` + Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` + BuildIds []string `protobuf:"bytes,2,rep,name=build_ids,json=buildIds,proto3" json:"build_ids,omitempty"` + BinaryNames []string `protobuf:"bytes,3,rep,name=binary_names,json=binaryNames,proto3" json:"binary_names,omitempty"` + UnresolvedBuildId []uint32 `protobuf:"varint,4,rep,packed,name=unresolved_build_id,json=unresolvedBuildId,proto3" json:"unresolved_build_id,omitempty"` + UnresolvedAddress []uint64 `protobuf:"varint,5,rep,packed,name=unresolved_address,json=unresolvedAddress,proto3" json:"unresolved_address,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SymbolRefTable) Reset() { + *x = SymbolRefTable{} + mi := &file_query_v1_query_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SymbolRefTable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SymbolRefTable) ProtoMessage() {} + +func (x *SymbolRefTable) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SymbolRefTable.ProtoReflect.Descriptor instead. +func (*SymbolRefTable) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{23} +} + +func (x *SymbolRefTable) GetNames() []string { + if x != nil { + return x.Names + } + return nil +} + +func (x *SymbolRefTable) GetBuildIds() []string { + if x != nil { + return x.BuildIds + } + return nil +} + +func (x *SymbolRefTable) GetBinaryNames() []string { + if x != nil { + return x.BinaryNames + } + return nil +} + +func (x *SymbolRefTable) GetUnresolvedBuildId() []uint32 { + if x != nil { + return x.UnresolvedBuildId + } + return nil +} + +func (x *SymbolRefTable) GetUnresolvedAddress() []uint64 { + if x != nil { + return x.UnresolvedAddress + } + return nil +} + +type TreeReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *TreeQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + Tree []byte `protobuf:"bytes,2,opt,name=tree,proto3" json:"tree,omitempty"` + Symbols *TreeSymbols `protobuf:"bytes,3,opt,name=symbols,proto3,oneof" json:"symbols,omitempty"` + SymbolRefs *SymbolRefTable `protobuf:"bytes,4,opt,name=symbol_refs,json=symbolRefs,proto3,oneof" json:"symbol_refs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TreeReport) Reset() { + *x = TreeReport{} + mi := &file_query_v1_query_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TreeReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TreeReport) ProtoMessage() {} + +func (x *TreeReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TreeReport.ProtoReflect.Descriptor instead. +func (*TreeReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{24} +} + +func (x *TreeReport) GetQuery() *TreeQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *TreeReport) GetTree() []byte { + if x != nil { + return x.Tree + } + return nil +} + +func (x *TreeReport) GetSymbols() *TreeSymbols { + if x != nil { + return x.Symbols + } + return nil +} + +func (x *TreeReport) GetSymbolRefs() *SymbolRefTable { + if x != nil { + return x.SymbolRefs + } + return nil +} + +type PprofQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + MaxNodes int64 `protobuf:"varint,1,opt,name=max_nodes,json=maxNodes,proto3" json:"max_nodes,omitempty"` + StackTraceSelector *v11.StackTraceSelector `protobuf:"bytes,2,opt,name=stack_trace_selector,json=stackTraceSelector,proto3,oneof" json:"stack_trace_selector,omitempty"` + ProfileIdSelector []string `protobuf:"bytes,3,rep,name=profile_id_selector,json=profileIdSelector,proto3" json:"profile_id_selector,omitempty"` + SpanSelector []string `protobuf:"bytes,4,rep,name=span_selector,json=spanSelector,proto3" json:"span_selector,omitempty"` + TraceIdSelector []string `protobuf:"bytes,5,rep,name=trace_id_selector,json=traceIdSelector,proto3" json:"trace_id_selector,omitempty"` // TODO(kolesnikovae): Go PGO options. + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PprofQuery) Reset() { + *x = PprofQuery{} + mi := &file_query_v1_query_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PprofQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PprofQuery) ProtoMessage() {} + +func (x *PprofQuery) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PprofQuery.ProtoReflect.Descriptor instead. +func (*PprofQuery) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{25} +} + +func (x *PprofQuery) GetMaxNodes() int64 { + if x != nil { + return x.MaxNodes + } + return 0 +} + +func (x *PprofQuery) GetStackTraceSelector() *v11.StackTraceSelector { + if x != nil { + return x.StackTraceSelector + } + return nil +} + +func (x *PprofQuery) GetProfileIdSelector() []string { + if x != nil { + return x.ProfileIdSelector + } + return nil +} + +func (x *PprofQuery) GetSpanSelector() []string { + if x != nil { + return x.SpanSelector + } + return nil +} + +func (x *PprofQuery) GetTraceIdSelector() []string { + if x != nil { + return x.TraceIdSelector + } + return nil +} + +type PprofReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *PprofQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + Pprof []byte `protobuf:"bytes,2,opt,name=pprof,proto3" json:"pprof,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PprofReport) Reset() { + *x = PprofReport{} + mi := &file_query_v1_query_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PprofReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PprofReport) ProtoMessage() {} + +func (x *PprofReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PprofReport.ProtoReflect.Descriptor instead. +func (*PprofReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{26} +} + +func (x *PprofReport) GetQuery() *PprofQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *PprofReport) GetPprof() []byte { + if x != nil { + return x.Pprof + } + return nil +} + +type HeatmapQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + Step float64 `protobuf:"fixed64,1,opt,name=step,proto3" json:"step,omitempty"` + GroupBy []string `protobuf:"bytes,2,rep,name=group_by,json=groupBy,proto3" json:"group_by,omitempty"` + QueryType v13.HeatmapQueryType `protobuf:"varint,3,opt,name=query_type,json=queryType,proto3,enum=querier.v1.HeatmapQueryType" json:"query_type,omitempty"` + Limit int64 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"` + ExemplarType v11.ExemplarType `protobuf:"varint,5,opt,name=exemplar_type,json=exemplarType,proto3,enum=types.v1.ExemplarType" json:"exemplar_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HeatmapQuery) Reset() { + *x = HeatmapQuery{} + mi := &file_query_v1_query_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HeatmapQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeatmapQuery) ProtoMessage() {} + +func (x *HeatmapQuery) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeatmapQuery.ProtoReflect.Descriptor instead. +func (*HeatmapQuery) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{27} +} + +func (x *HeatmapQuery) GetStep() float64 { + if x != nil { + return x.Step + } + return 0 +} + +func (x *HeatmapQuery) GetGroupBy() []string { + if x != nil { + return x.GroupBy + } + return nil +} + +func (x *HeatmapQuery) GetQueryType() v13.HeatmapQueryType { + if x != nil { + return x.QueryType + } + return v13.HeatmapQueryType(0) +} + +func (x *HeatmapQuery) GetLimit() int64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *HeatmapQuery) GetExemplarType() v11.ExemplarType { + if x != nil { + return x.ExemplarType + } + return v11.ExemplarType(0) +} + +type AttributeTable struct { + state protoimpl.MessageState `protogen:"open.v1"` + Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` + Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AttributeTable) Reset() { + *x = AttributeTable{} + mi := &file_query_v1_query_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AttributeTable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttributeTable) ProtoMessage() {} + +func (x *AttributeTable) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttributeTable.ProtoReflect.Descriptor instead. +func (*AttributeTable) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{28} +} + +func (x *AttributeTable) GetKeys() []string { + if x != nil { + return x.Keys + } + return nil +} + +func (x *AttributeTable) GetValues() []string { + if x != nil { + return x.Values + } + return nil +} + +type HeatmapPoint struct { + state protoimpl.MessageState `protogen:"open.v1"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Milliseconds since epoch when the profile was captured. + ProfileId int64 `protobuf:"varint,2,opt,name=profile_id,json=profileId,proto3" json:"profile_id,omitempty"` // Unique identifier for the profile (UUID), reference into AttributeTable with only value set + SpanId uint64 `protobuf:"varint,3,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"` // Span ID if this profile was split by span during ingestion + Value int64 `protobuf:"varint,4,opt,name=value,proto3" json:"value,omitempty"` // Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + AttributeRefs []int64 `protobuf:"varint,5,rep,packed,name=attribute_refs,json=attributeRefs,proto3" json:"attribute_refs,omitempty"` // labels as references into AttributeTable + TraceId []byte `protobuf:"bytes,6,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` // Trace ID associated with the span, if present. + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HeatmapPoint) Reset() { + *x = HeatmapPoint{} + mi := &file_query_v1_query_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HeatmapPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeatmapPoint) ProtoMessage() {} + +func (x *HeatmapPoint) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeatmapPoint.ProtoReflect.Descriptor instead. +func (*HeatmapPoint) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{29} +} + +func (x *HeatmapPoint) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *HeatmapPoint) GetProfileId() int64 { + if x != nil { + return x.ProfileId + } + return 0 +} + +func (x *HeatmapPoint) GetSpanId() uint64 { + if x != nil { + return x.SpanId + } + return 0 +} + +func (x *HeatmapPoint) GetValue() int64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *HeatmapPoint) GetAttributeRefs() []int64 { + if x != nil { + return x.AttributeRefs + } + return nil +} + +func (x *HeatmapPoint) GetTraceId() []byte { + if x != nil { + return x.TraceId + } + return nil +} + +type HeatmapSeries struct { + state protoimpl.MessageState `protogen:"open.v1"` + AttributeRefs []int64 `protobuf:"varint,1,rep,packed,name=attribute_refs,json=attributeRefs,proto3" json:"attribute_refs,omitempty"` + Points []*HeatmapPoint `protobuf:"bytes,2,rep,name=points,proto3" json:"points,omitempty"` // Points are timestamp, then span_id, then porfile_id ordered + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HeatmapSeries) Reset() { + *x = HeatmapSeries{} + mi := &file_query_v1_query_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HeatmapSeries) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeatmapSeries) ProtoMessage() {} + +func (x *HeatmapSeries) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeatmapSeries.ProtoReflect.Descriptor instead. +func (*HeatmapSeries) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{30} +} + +func (x *HeatmapSeries) GetAttributeRefs() []int64 { + if x != nil { + return x.AttributeRefs + } + return nil +} + +func (x *HeatmapSeries) GetPoints() []*HeatmapPoint { + if x != nil { + return x.Points + } + return nil +} + +type HeatmapReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *HeatmapQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + HeatmapSeries []*HeatmapSeries `protobuf:"bytes,2,rep,name=heatmap_series,json=heatmapSeries,proto3" json:"heatmap_series,omitempty"` + AttributeTable *AttributeTable `protobuf:"bytes,3,opt,name=attribute_table,json=attributeTable,proto3" json:"attribute_table,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HeatmapReport) Reset() { + *x = HeatmapReport{} + mi := &file_query_v1_query_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HeatmapReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeatmapReport) ProtoMessage() {} + +func (x *HeatmapReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[31] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeatmapReport.ProtoReflect.Descriptor instead. +func (*HeatmapReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{31} +} + +func (x *HeatmapReport) GetQuery() *HeatmapQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *HeatmapReport) GetHeatmapSeries() []*HeatmapSeries { + if x != nil { + return x.HeatmapSeries + } + return nil +} + +func (x *HeatmapReport) GetAttributeTable() *AttributeTable { + if x != nil { + return x.AttributeTable + } + return nil +} + +type Exemplar struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Milliseconds unix timestamp + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + ProfileId string `protobuf:"bytes,2,opt,name=profile_id,json=profileId,proto3" json:"profile_id,omitempty"` + SpanId string `protobuf:"bytes,3,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"` + Value int64 `protobuf:"varint,4,opt,name=value,proto3" json:"value,omitempty"` + AttributeRefs []int64 `protobuf:"varint,5,rep,packed,name=attribute_refs,json=attributeRefs,proto3" json:"attribute_refs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Exemplar) Reset() { + *x = Exemplar{} + mi := &file_query_v1_query_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Exemplar) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Exemplar) ProtoMessage() {} + +func (x *Exemplar) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[32] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Exemplar.ProtoReflect.Descriptor instead. +func (*Exemplar) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{32} +} + +func (x *Exemplar) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *Exemplar) GetProfileId() string { + if x != nil { + return x.ProfileId + } + return "" +} + +func (x *Exemplar) GetSpanId() string { + if x != nil { + return x.SpanId + } + return "" +} + +func (x *Exemplar) GetValue() int64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *Exemplar) GetAttributeRefs() []int64 { + if x != nil { + return x.AttributeRefs + } + return nil +} + +type Point struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"` + // Milliseconds unix timestamp + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // Annotations as references into AttributeTable + AnnotationRefs []int64 `protobuf:"varint,5,rep,packed,name=annotation_refs,json=annotationRefs,proto3" json:"annotation_refs,omitempty"` + // Exemplars are samples of individual profiles that contributed to this aggregated point + Exemplars []*Exemplar `protobuf:"bytes,4,rep,name=exemplars,proto3" json:"exemplars,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Point) Reset() { + *x = Point{} + mi := &file_query_v1_query_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Point) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Point) ProtoMessage() {} + +func (x *Point) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[33] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Point.ProtoReflect.Descriptor instead. +func (*Point) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{33} +} + +func (x *Point) GetValue() float64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *Point) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *Point) GetAnnotationRefs() []int64 { + if x != nil { + return x.AnnotationRefs + } + return nil +} + +func (x *Point) GetExemplars() []*Exemplar { + if x != nil { + return x.Exemplars + } + return nil +} + +// Series represents a time series with optimized label storage using attribute references. +type Series struct { + state protoimpl.MessageState `protogen:"open.v1"` + // References to label key-value pairs in the AttributeTable that identify this series. + AttributeRefs []int64 `protobuf:"varint,1,rep,packed,name=attribute_refs,json=attributeRefs,proto3" json:"attribute_refs,omitempty"` + // Time series data points. Each point may contain exemplars with their own attribute_refs. + Points []*Point `protobuf:"bytes,2,rep,name=points,proto3" json:"points,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Series) Reset() { + *x = Series{} + mi := &file_query_v1_query_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Series) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Series) ProtoMessage() {} + +func (x *Series) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[34] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Series.ProtoReflect.Descriptor instead. +func (*Series) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{34} +} + +func (x *Series) GetAttributeRefs() []int64 { + if x != nil { + return x.AttributeRefs + } + return nil +} + +func (x *Series) GetPoints() []*Point { + if x != nil { + return x.Points + } + return nil +} + +type TimeSeriesCompactReport struct { + state protoimpl.MessageState `protogen:"open.v1"` + Query *TimeSeriesQuery `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + TimeSeries []*Series `protobuf:"bytes,2,rep,name=time_series,json=timeSeries,proto3" json:"time_series,omitempty"` + AttributeTable *AttributeTable `protobuf:"bytes,3,opt,name=attribute_table,json=attributeTable,proto3" json:"attribute_table,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TimeSeriesCompactReport) Reset() { + *x = TimeSeriesCompactReport{} + mi := &file_query_v1_query_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TimeSeriesCompactReport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TimeSeriesCompactReport) ProtoMessage() {} + +func (x *TimeSeriesCompactReport) ProtoReflect() protoreflect.Message { + mi := &file_query_v1_query_proto_msgTypes[35] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TimeSeriesCompactReport.ProtoReflect.Descriptor instead. +func (*TimeSeriesCompactReport) Descriptor() ([]byte, []int) { + return file_query_v1_query_proto_rawDescGZIP(), []int{35} +} + +func (x *TimeSeriesCompactReport) GetQuery() *TimeSeriesQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *TimeSeriesCompactReport) GetTimeSeries() []*Series { + if x != nil { + return x.TimeSeries + } + return nil +} + +func (x *TimeSeriesCompactReport) GetAttributeTable() *AttributeTable { + if x != nil { + return x.AttributeTable + } + return nil +} + +var File_query_v1_query_proto protoreflect.FileDescriptor + +const file_query_v1_query_proto_rawDesc = "" + + "\n" + + "\x14query/v1/query.proto\x12\bquery.v1\x1a\x17google/v1/profile.proto\x1a\x18metastore/v1/types.proto\x1a\x18querier/v1/querier.proto\x1a\x14types/v1/types.proto\"\x96\x01\n" + + "\fQueryRequest\x12\x1d\n" + + "\n" + + "start_time\x18\x01 \x01(\x03R\tstartTime\x12\x19\n" + + "\bend_time\x18\x02 \x01(\x03R\aendTime\x12%\n" + + "\x0elabel_selector\x18\x03 \x01(\tR\rlabelSelector\x12%\n" + + "\x05query\x18\x04 \x03(\v2\x0f.query.v1.QueryR\x05query\";\n" + + "\rQueryResponse\x12*\n" + + "\areports\x18\x01 \x03(\v2\x10.query.v1.ReportR\areports\"l\n" + + "\rInvokeOptions\x12*\n" + + "\x11sanitize_on_merge\x18\x01 \x01(\bR\x0fsanitizeOnMerge\x12/\n" + + "\x13collect_diagnostics\x18\x02 \x01(\bR\x12collectDiagnostics\"\x96\x02\n" + + "\rInvokeRequest\x12\x16\n" + + "\x06tenant\x18\x01 \x03(\tR\x06tenant\x12\x1d\n" + + "\n" + + "start_time\x18\x02 \x01(\x03R\tstartTime\x12\x19\n" + + "\bend_time\x18\x03 \x01(\x03R\aendTime\x12%\n" + + "\x0elabel_selector\x18\x04 \x01(\tR\rlabelSelector\x12%\n" + + "\x05query\x18\x05 \x03(\v2\x0f.query.v1.QueryR\x05query\x122\n" + + "\n" + + "query_plan\x18\x06 \x01(\v2\x13.query.v1.QueryPlanR\tqueryPlan\x121\n" + + "\aoptions\x18\a \x01(\v2\x17.query.v1.InvokeOptionsR\aoptions\"4\n" + + "\tQueryPlan\x12'\n" + + "\x04root\x18\x01 \x01(\v2\x13.query.v1.QueryNodeR\x04root\"\xc5\x01\n" + + "\tQueryNode\x12,\n" + + "\x04type\x18\x01 \x01(\x0e2\x18.query.v1.QueryNode.TypeR\x04type\x12/\n" + + "\bchildren\x18\x02 \x03(\v2\x13.query.v1.QueryNodeR\bchildren\x12/\n" + + "\x06blocks\x18\x03 \x03(\v2\x17.metastore.v1.BlockMetaR\x06blocks\"(\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\t\n" + + "\x05MERGE\x10\x01\x12\b\n" + + "\x04READ\x10\x02\"\x86\x04\n" + + "\x05Query\x122\n" + + "\n" + + "query_type\x18\x01 \x01(\x0e2\x13.query.v1.QueryTypeR\tqueryType\x12:\n" + + "\vlabel_names\x18\x02 \x01(\v2\x19.query.v1.LabelNamesQueryR\n" + + "labelNames\x12=\n" + + "\flabel_values\x18\x03 \x01(\v2\x1a.query.v1.LabelValuesQueryR\vlabelValues\x12@\n" + + "\rseries_labels\x18\x04 \x01(\v2\x1b.query.v1.SeriesLabelsQueryR\fseriesLabels\x12:\n" + + "\vtime_series\x18\x05 \x01(\v2\x19.query.v1.TimeSeriesQueryR\n" + + "timeSeries\x12'\n" + + "\x04tree\x18\x06 \x01(\v2\x13.query.v1.TreeQueryR\x04tree\x12*\n" + + "\x05pprof\x18\a \x01(\v2\x14.query.v1.PprofQueryR\x05pprof\x120\n" + + "\aheatmap\x18\b \x01(\v2\x16.query.v1.HeatmapQueryR\aheatmap\x12I\n" + + "\x13time_series_compact\x18\t \x01(\v2\x19.query.v1.TimeSeriesQueryR\x11timeSeriesCompact\"u\n" + + "\x0eInvokeResponse\x12*\n" + + "\areports\x18\x01 \x03(\v2\x10.query.v1.ReportR\areports\x127\n" + + "\vdiagnostics\x18\x02 \x01(\v2\x15.query.v1.DiagnosticsR\vdiagnostics\"\x81\x01\n" + + "\vDiagnostics\x122\n" + + "\n" + + "query_plan\x18\x01 \x01(\v2\x13.query.v1.QueryPlanR\tqueryPlan\x12>\n" + + "\x0eexecution_node\x18\x02 \x01(\v2\x17.query.v1.ExecutionNodeR\rexecutionNode\"\x98\x02\n" + + "\rExecutionNode\x12,\n" + + "\x04type\x18\x01 \x01(\x0e2\x18.query.v1.QueryNode.TypeR\x04type\x12\x1a\n" + + "\bexecutor\x18\x02 \x01(\tR\bexecutor\x12\"\n" + + "\rstart_time_ns\x18\x03 \x01(\x03R\vstartTimeNs\x12\x1e\n" + + "\vend_time_ns\x18\x04 \x01(\x03R\tendTimeNs\x123\n" + + "\bchildren\x18\x05 \x03(\v2\x17.query.v1.ExecutionNodeR\bchildren\x12.\n" + + "\x05stats\x18\x06 \x01(\v2\x18.query.v1.ExecutionStatsR\x05stats\x12\x14\n" + + "\x05error\x18\a \x01(\tR\x05error\"\xca\x01\n" + + "\x0eExecutionStats\x12\x1f\n" + + "\vblocks_read\x18\x01 \x01(\x03R\n" + + "blocksRead\x12-\n" + + "\x12datasets_processed\x18\x02 \x01(\x03R\x11datasetsProcessed\x12C\n" + + "\x10block_executions\x18\x03 \x03(\v2\x18.query.v1.BlockExecutionR\x0fblockExecutions\x12#\n" + + "\rbytes_fetched\x18\x04 \x01(\x04R\fbytesFetched\"\xf3\x01\n" + + "\x0eBlockExecution\x12\x19\n" + + "\bblock_id\x18\x01 \x01(\tR\ablockId\x12\"\n" + + "\rstart_time_ns\x18\x02 \x01(\x03R\vstartTimeNs\x12\x1e\n" + + "\vend_time_ns\x18\x03 \x01(\x03R\tendTimeNs\x12-\n" + + "\x12datasets_processed\x18\x04 \x01(\x03R\x11datasetsProcessed\x12\x12\n" + + "\x04size\x18\x05 \x01(\x04R\x04size\x12\x14\n" + + "\x05shard\x18\x06 \x01(\rR\x05shard\x12)\n" + + "\x10compaction_level\x18\a \x01(\rR\x0fcompactionLevel\"\x99\x04\n" + + "\x06Report\x125\n" + + "\vreport_type\x18\x01 \x01(\x0e2\x14.query.v1.ReportTypeR\n" + + "reportType\x12;\n" + + "\vlabel_names\x18\x02 \x01(\v2\x1a.query.v1.LabelNamesReportR\n" + + "labelNames\x12>\n" + + "\flabel_values\x18\x03 \x01(\v2\x1b.query.v1.LabelValuesReportR\vlabelValues\x12A\n" + + "\rseries_labels\x18\x04 \x01(\v2\x1c.query.v1.SeriesLabelsReportR\fseriesLabels\x12;\n" + + "\vtime_series\x18\x05 \x01(\v2\x1a.query.v1.TimeSeriesReportR\n" + + "timeSeries\x12(\n" + + "\x04tree\x18\x06 \x01(\v2\x14.query.v1.TreeReportR\x04tree\x12+\n" + + "\x05pprof\x18\a \x01(\v2\x15.query.v1.PprofReportR\x05pprof\x121\n" + + "\aheatmap\x18\b \x01(\v2\x17.query.v1.HeatmapReportR\aheatmap\x12Q\n" + + "\x13time_series_compact\x18\t \x01(\v2!.query.v1.TimeSeriesCompactReportR\x11timeSeriesCompact\"\x11\n" + + "\x0fLabelNamesQuery\"d\n" + + "\x10LabelNamesReport\x12/\n" + + "\x05query\x18\x01 \x01(\v2\x19.query.v1.LabelNamesQueryR\x05query\x12\x1f\n" + + "\vlabel_names\x18\x02 \x03(\tR\n" + + "labelNames\"1\n" + + "\x10LabelValuesQuery\x12\x1d\n" + + "\n" + + "label_name\x18\x01 \x01(\tR\tlabelName\"h\n" + + "\x11LabelValuesReport\x120\n" + + "\x05query\x18\x01 \x01(\v2\x1a.query.v1.LabelValuesQueryR\x05query\x12!\n" + + "\flabel_values\x18\x02 \x03(\tR\vlabelValues\"4\n" + + "\x11SeriesLabelsQuery\x12\x1f\n" + + "\vlabel_names\x18\x01 \x03(\tR\n" + + "labelNames\"~\n" + + "\x12SeriesLabelsReport\x121\n" + + "\x05query\x18\x01 \x01(\v2\x1b.query.v1.SeriesLabelsQueryR\x05query\x125\n" + + "\rseries_labels\x18\x02 \x03(\v2\x10.types.v1.LabelsR\fseriesLabels\"\x93\x01\n" + + "\x0fTimeSeriesQuery\x12\x12\n" + + "\x04step\x18\x01 \x01(\x01R\x04step\x12\x19\n" + + "\bgroup_by\x18\x02 \x03(\tR\agroupBy\x12\x14\n" + + "\x05limit\x18\x03 \x01(\x03R\x05limit\x12;\n" + + "\rexemplar_type\x18\x04 \x01(\x0e2\x16.types.v1.ExemplarTypeR\fexemplarType\"v\n" + + "\x10TimeSeriesReport\x12/\n" + + "\x05query\x18\x01 \x01(\v2\x19.query.v1.TimeSeriesQueryR\x05query\x121\n" + + "\vtime_series\x18\x02 \x03(\v2\x10.types.v1.SeriesR\n" + + "timeSeries\"\xab\x03\n" + + "\tTreeQuery\x12\x1b\n" + + "\tmax_nodes\x18\x01 \x01(\x03R\bmaxNodes\x12#\n" + + "\rspan_selector\x18\x02 \x03(\tR\fspanSelector\x12S\n" + + "\x14stack_trace_selector\x18\x03 \x01(\v2\x1c.types.v1.StackTraceSelectorH\x00R\x12stackTraceSelector\x88\x01\x01\x12.\n" + + "\x13profile_id_selector\x18\x04 \x03(\tR\x11profileIdSelector\x12!\n" + + "\ffull_symbols\x18\x05 \x01(\bR\vfullSymbols\x12*\n" + + "\x11trace_id_selector\x18\x06 \x03(\tR\x0ftraceIdSelector\x125\n" + + "\vsymbol_mode\x18\a \x01(\x0e2\x14.query.v1.SymbolModeR\n" + + "symbolMode\x128\n" + + "\x18max_unresolved_locations\x18\b \x01(\x03R\x16maxUnresolvedLocationsB\x17\n" + + "\x15_stack_trace_selector\"\xdb\x02\n" + + "\vTreeSymbols\x12.\n" + + "\bmappings\x18\x01 \x03(\v2\x12.google.v1.MappingR\bmappings\x121\n" + + "\tlocations\x18\x02 \x03(\v2\x13.google.v1.LocationR\tlocations\x121\n" + + "\tfunctions\x18\x03 \x03(\v2\x13.google.v1.FunctionR\tfunctions\x12\x18\n" + + "\astrings\x18\x04 \x03(\tR\astrings\x12%\n" + + "\x0emapping_hashes\x18\x05 \x03(\x04R\rmappingHashes\x12'\n" + + "\x0flocation_hashes\x18\x06 \x03(\x04R\x0elocationHashes\x12'\n" + + "\x0ffunction_hashes\x18\a \x03(\x04R\x0efunctionHashes\x12#\n" + + "\rstring_hashes\x18\b \x03(\x04R\fstringHashes\"\xc5\x01\n" + + "\x0eSymbolRefTable\x12\x14\n" + + "\x05names\x18\x01 \x03(\tR\x05names\x12\x1b\n" + + "\tbuild_ids\x18\x02 \x03(\tR\bbuildIds\x12!\n" + + "\fbinary_names\x18\x03 \x03(\tR\vbinaryNames\x12.\n" + + "\x13unresolved_build_id\x18\x04 \x03(\rR\x11unresolvedBuildId\x12-\n" + + "\x12unresolved_address\x18\x05 \x03(\x04R\x11unresolvedAddress\"\xdd\x01\n" + + "\n" + + "TreeReport\x12)\n" + + "\x05query\x18\x01 \x01(\v2\x13.query.v1.TreeQueryR\x05query\x12\x12\n" + + "\x04tree\x18\x02 \x01(\fR\x04tree\x124\n" + + "\asymbols\x18\x03 \x01(\v2\x15.query.v1.TreeSymbolsH\x00R\asymbols\x88\x01\x01\x12>\n" + + "\vsymbol_refs\x18\x04 \x01(\v2\x18.query.v1.SymbolRefTableH\x01R\n" + + "symbolRefs\x88\x01\x01B\n" + + "\n" + + "\b_symbolsB\x0e\n" + + "\f_symbol_refs\"\x98\x02\n" + + "\n" + + "PprofQuery\x12\x1b\n" + + "\tmax_nodes\x18\x01 \x01(\x03R\bmaxNodes\x12S\n" + + "\x14stack_trace_selector\x18\x02 \x01(\v2\x1c.types.v1.StackTraceSelectorH\x00R\x12stackTraceSelector\x88\x01\x01\x12.\n" + + "\x13profile_id_selector\x18\x03 \x03(\tR\x11profileIdSelector\x12#\n" + + "\rspan_selector\x18\x04 \x03(\tR\fspanSelector\x12*\n" + + "\x11trace_id_selector\x18\x05 \x03(\tR\x0ftraceIdSelectorB\x17\n" + + "\x15_stack_trace_selector\"O\n" + + "\vPprofReport\x12*\n" + + "\x05query\x18\x01 \x01(\v2\x14.query.v1.PprofQueryR\x05query\x12\x14\n" + + "\x05pprof\x18\x02 \x01(\fR\x05pprof\"\xcd\x01\n" + + "\fHeatmapQuery\x12\x12\n" + + "\x04step\x18\x01 \x01(\x01R\x04step\x12\x19\n" + + "\bgroup_by\x18\x02 \x03(\tR\agroupBy\x12;\n" + + "\n" + + "query_type\x18\x03 \x01(\x0e2\x1c.querier.v1.HeatmapQueryTypeR\tqueryType\x12\x14\n" + + "\x05limit\x18\x04 \x01(\x03R\x05limit\x12;\n" + + "\rexemplar_type\x18\x05 \x01(\x0e2\x16.types.v1.ExemplarTypeR\fexemplarType\"<\n" + + "\x0eAttributeTable\x12\x12\n" + + "\x04keys\x18\x01 \x03(\tR\x04keys\x12\x16\n" + + "\x06values\x18\x02 \x03(\tR\x06values\"\xbc\x01\n" + + "\fHeatmapPoint\x12\x1c\n" + + "\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12\x1d\n" + + "\n" + + "profile_id\x18\x02 \x01(\x03R\tprofileId\x12\x17\n" + + "\aspan_id\x18\x03 \x01(\x04R\x06spanId\x12\x14\n" + + "\x05value\x18\x04 \x01(\x03R\x05value\x12%\n" + + "\x0eattribute_refs\x18\x05 \x03(\x03R\rattributeRefs\x12\x19\n" + + "\btrace_id\x18\x06 \x01(\fR\atraceId\"f\n" + + "\rHeatmapSeries\x12%\n" + + "\x0eattribute_refs\x18\x01 \x03(\x03R\rattributeRefs\x12.\n" + + "\x06points\x18\x02 \x03(\v2\x16.query.v1.HeatmapPointR\x06points\"\xc0\x01\n" + + "\rHeatmapReport\x12,\n" + + "\x05query\x18\x01 \x01(\v2\x16.query.v1.HeatmapQueryR\x05query\x12>\n" + + "\x0eheatmap_series\x18\x02 \x03(\v2\x17.query.v1.HeatmapSeriesR\rheatmapSeries\x12A\n" + + "\x0fattribute_table\x18\x03 \x01(\v2\x18.query.v1.AttributeTableR\x0eattributeTable\"\x9d\x01\n" + + "\bExemplar\x12\x1c\n" + + "\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12\x1d\n" + + "\n" + + "profile_id\x18\x02 \x01(\tR\tprofileId\x12\x17\n" + + "\aspan_id\x18\x03 \x01(\tR\x06spanId\x12\x14\n" + + "\x05value\x18\x04 \x01(\x03R\x05value\x12%\n" + + "\x0eattribute_refs\x18\x05 \x03(\x03R\rattributeRefs\"\x96\x01\n" + + "\x05Point\x12\x14\n" + + "\x05value\x18\x01 \x01(\x01R\x05value\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\x12'\n" + + "\x0fannotation_refs\x18\x05 \x03(\x03R\x0eannotationRefs\x120\n" + + "\texemplars\x18\x04 \x03(\v2\x12.query.v1.ExemplarR\texemplars\"X\n" + + "\x06Series\x12%\n" + + "\x0eattribute_refs\x18\x01 \x03(\x03R\rattributeRefs\x12'\n" + + "\x06points\x18\x02 \x03(\v2\x0f.query.v1.PointR\x06points\"\xc0\x01\n" + + "\x17TimeSeriesCompactReport\x12/\n" + + "\x05query\x18\x01 \x01(\v2\x19.query.v1.TimeSeriesQueryR\x05query\x121\n" + + "\vtime_series\x18\x02 \x03(\v2\x10.query.v1.SeriesR\n" + + "timeSeries\x12A\n" + + "\x0fattribute_table\x18\x03 \x01(\v2\x18.query.v1.AttributeTableR\x0eattributeTable*\xd4\x01\n" + + "\tQueryType\x12\x15\n" + + "\x11QUERY_UNSPECIFIED\x10\x00\x12\x15\n" + + "\x11QUERY_LABEL_NAMES\x10\x01\x12\x16\n" + + "\x12QUERY_LABEL_VALUES\x10\x02\x12\x17\n" + + "\x13QUERY_SERIES_LABELS\x10\x03\x12\x15\n" + + "\x11QUERY_TIME_SERIES\x10\x04\x12\x0e\n" + + "\n" + + "QUERY_TREE\x10\x05\x12\x0f\n" + + "\vQUERY_PPROF\x10\x06\x12\x11\n" + + "\rQUERY_HEATMAP\x10\a\x12\x1d\n" + + "\x19QUERY_TIME_SERIES_COMPACT\x10\b*\xde\x01\n" + + "\n" + + "ReportType\x12\x16\n" + + "\x12REPORT_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12REPORT_LABEL_NAMES\x10\x01\x12\x17\n" + + "\x13REPORT_LABEL_VALUES\x10\x02\x12\x18\n" + + "\x14REPORT_SERIES_LABELS\x10\x03\x12\x16\n" + + "\x12REPORT_TIME_SERIES\x10\x04\x12\x0f\n" + + "\vREPORT_TREE\x10\x05\x12\x10\n" + + "\fREPORT_PPROF\x10\x06\x12\x12\n" + + "\x0eREPORT_HEATMAP\x10\a\x12\x1e\n" + + "\x1aREPORT_TIME_SERIES_COMPACT\x10\b*k\n" + + "\n" + + "SymbolMode\x12\x1b\n" + + "\x17SYMBOL_MODE_UNSPECIFIED\x10\x00\x12\x14\n" + + "\x10SYMBOL_MODE_NAME\x10\x01\x12\x14\n" + + "\x10SYMBOL_MODE_FULL\x10\x02\x12\x14\n" + + "\x10SYMBOL_MODE_REFS\x10\x032R\n" + + "\x14QueryFrontendService\x12:\n" + + "\x05Query\x12\x16.query.v1.QueryRequest\x1a\x17.query.v1.QueryResponse\"\x002T\n" + + "\x13QueryBackendService\x12=\n" + + "\x06Invoke\x12\x17.query.v1.InvokeRequest\x1a\x18.query.v1.InvokeResponse\"\x00B\x9b\x01\n" + + "\fcom.query.v1B\n" + + "QueryProtoP\x01Z>github.com/grafana/pyroscope/api/gen/proto/go/query/v1;queryv1\xa2\x02\x03QXX\xaa\x02\bQuery.V1\xca\x02\bQuery\\V1\xe2\x02\x14Query\\V1\\GPBMetadata\xea\x02\tQuery::V1b\x06proto3" + +var ( + file_query_v1_query_proto_rawDescOnce sync.Once + file_query_v1_query_proto_rawDescData []byte +) + +func file_query_v1_query_proto_rawDescGZIP() []byte { + file_query_v1_query_proto_rawDescOnce.Do(func() { + file_query_v1_query_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_query_v1_query_proto_rawDesc), len(file_query_v1_query_proto_rawDesc))) + }) + return file_query_v1_query_proto_rawDescData +} + +var file_query_v1_query_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_query_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 36) +var file_query_v1_query_proto_goTypes = []any{ + (QueryType)(0), // 0: query.v1.QueryType + (ReportType)(0), // 1: query.v1.ReportType + (SymbolMode)(0), // 2: query.v1.SymbolMode + (QueryNode_Type)(0), // 3: query.v1.QueryNode.Type + (*QueryRequest)(nil), // 4: query.v1.QueryRequest + (*QueryResponse)(nil), // 5: query.v1.QueryResponse + (*InvokeOptions)(nil), // 6: query.v1.InvokeOptions + (*InvokeRequest)(nil), // 7: query.v1.InvokeRequest + (*QueryPlan)(nil), // 8: query.v1.QueryPlan + (*QueryNode)(nil), // 9: query.v1.QueryNode + (*Query)(nil), // 10: query.v1.Query + (*InvokeResponse)(nil), // 11: query.v1.InvokeResponse + (*Diagnostics)(nil), // 12: query.v1.Diagnostics + (*ExecutionNode)(nil), // 13: query.v1.ExecutionNode + (*ExecutionStats)(nil), // 14: query.v1.ExecutionStats + (*BlockExecution)(nil), // 15: query.v1.BlockExecution + (*Report)(nil), // 16: query.v1.Report + (*LabelNamesQuery)(nil), // 17: query.v1.LabelNamesQuery + (*LabelNamesReport)(nil), // 18: query.v1.LabelNamesReport + (*LabelValuesQuery)(nil), // 19: query.v1.LabelValuesQuery + (*LabelValuesReport)(nil), // 20: query.v1.LabelValuesReport + (*SeriesLabelsQuery)(nil), // 21: query.v1.SeriesLabelsQuery + (*SeriesLabelsReport)(nil), // 22: query.v1.SeriesLabelsReport + (*TimeSeriesQuery)(nil), // 23: query.v1.TimeSeriesQuery + (*TimeSeriesReport)(nil), // 24: query.v1.TimeSeriesReport + (*TreeQuery)(nil), // 25: query.v1.TreeQuery + (*TreeSymbols)(nil), // 26: query.v1.TreeSymbols + (*SymbolRefTable)(nil), // 27: query.v1.SymbolRefTable + (*TreeReport)(nil), // 28: query.v1.TreeReport + (*PprofQuery)(nil), // 29: query.v1.PprofQuery + (*PprofReport)(nil), // 30: query.v1.PprofReport + (*HeatmapQuery)(nil), // 31: query.v1.HeatmapQuery + (*AttributeTable)(nil), // 32: query.v1.AttributeTable + (*HeatmapPoint)(nil), // 33: query.v1.HeatmapPoint + (*HeatmapSeries)(nil), // 34: query.v1.HeatmapSeries + (*HeatmapReport)(nil), // 35: query.v1.HeatmapReport + (*Exemplar)(nil), // 36: query.v1.Exemplar + (*Point)(nil), // 37: query.v1.Point + (*Series)(nil), // 38: query.v1.Series + (*TimeSeriesCompactReport)(nil), // 39: query.v1.TimeSeriesCompactReport + (*v1.BlockMeta)(nil), // 40: metastore.v1.BlockMeta + (*v11.Labels)(nil), // 41: types.v1.Labels + (v11.ExemplarType)(0), // 42: types.v1.ExemplarType + (*v11.Series)(nil), // 43: types.v1.Series + (*v11.StackTraceSelector)(nil), // 44: types.v1.StackTraceSelector + (*v12.Mapping)(nil), // 45: google.v1.Mapping + (*v12.Location)(nil), // 46: google.v1.Location + (*v12.Function)(nil), // 47: google.v1.Function + (v13.HeatmapQueryType)(0), // 48: querier.v1.HeatmapQueryType +} +var file_query_v1_query_proto_depIdxs = []int32{ + 10, // 0: query.v1.QueryRequest.query:type_name -> query.v1.Query + 16, // 1: query.v1.QueryResponse.reports:type_name -> query.v1.Report + 10, // 2: query.v1.InvokeRequest.query:type_name -> query.v1.Query + 8, // 3: query.v1.InvokeRequest.query_plan:type_name -> query.v1.QueryPlan + 6, // 4: query.v1.InvokeRequest.options:type_name -> query.v1.InvokeOptions + 9, // 5: query.v1.QueryPlan.root:type_name -> query.v1.QueryNode + 3, // 6: query.v1.QueryNode.type:type_name -> query.v1.QueryNode.Type + 9, // 7: query.v1.QueryNode.children:type_name -> query.v1.QueryNode + 40, // 8: query.v1.QueryNode.blocks:type_name -> metastore.v1.BlockMeta + 0, // 9: query.v1.Query.query_type:type_name -> query.v1.QueryType + 17, // 10: query.v1.Query.label_names:type_name -> query.v1.LabelNamesQuery + 19, // 11: query.v1.Query.label_values:type_name -> query.v1.LabelValuesQuery + 21, // 12: query.v1.Query.series_labels:type_name -> query.v1.SeriesLabelsQuery + 23, // 13: query.v1.Query.time_series:type_name -> query.v1.TimeSeriesQuery + 25, // 14: query.v1.Query.tree:type_name -> query.v1.TreeQuery + 29, // 15: query.v1.Query.pprof:type_name -> query.v1.PprofQuery + 31, // 16: query.v1.Query.heatmap:type_name -> query.v1.HeatmapQuery + 23, // 17: query.v1.Query.time_series_compact:type_name -> query.v1.TimeSeriesQuery + 16, // 18: query.v1.InvokeResponse.reports:type_name -> query.v1.Report + 12, // 19: query.v1.InvokeResponse.diagnostics:type_name -> query.v1.Diagnostics + 8, // 20: query.v1.Diagnostics.query_plan:type_name -> query.v1.QueryPlan + 13, // 21: query.v1.Diagnostics.execution_node:type_name -> query.v1.ExecutionNode + 3, // 22: query.v1.ExecutionNode.type:type_name -> query.v1.QueryNode.Type + 13, // 23: query.v1.ExecutionNode.children:type_name -> query.v1.ExecutionNode + 14, // 24: query.v1.ExecutionNode.stats:type_name -> query.v1.ExecutionStats + 15, // 25: query.v1.ExecutionStats.block_executions:type_name -> query.v1.BlockExecution + 1, // 26: query.v1.Report.report_type:type_name -> query.v1.ReportType + 18, // 27: query.v1.Report.label_names:type_name -> query.v1.LabelNamesReport + 20, // 28: query.v1.Report.label_values:type_name -> query.v1.LabelValuesReport + 22, // 29: query.v1.Report.series_labels:type_name -> query.v1.SeriesLabelsReport + 24, // 30: query.v1.Report.time_series:type_name -> query.v1.TimeSeriesReport + 28, // 31: query.v1.Report.tree:type_name -> query.v1.TreeReport + 30, // 32: query.v1.Report.pprof:type_name -> query.v1.PprofReport + 35, // 33: query.v1.Report.heatmap:type_name -> query.v1.HeatmapReport + 39, // 34: query.v1.Report.time_series_compact:type_name -> query.v1.TimeSeriesCompactReport + 17, // 35: query.v1.LabelNamesReport.query:type_name -> query.v1.LabelNamesQuery + 19, // 36: query.v1.LabelValuesReport.query:type_name -> query.v1.LabelValuesQuery + 21, // 37: query.v1.SeriesLabelsReport.query:type_name -> query.v1.SeriesLabelsQuery + 41, // 38: query.v1.SeriesLabelsReport.series_labels:type_name -> types.v1.Labels + 42, // 39: query.v1.TimeSeriesQuery.exemplar_type:type_name -> types.v1.ExemplarType + 23, // 40: query.v1.TimeSeriesReport.query:type_name -> query.v1.TimeSeriesQuery + 43, // 41: query.v1.TimeSeriesReport.time_series:type_name -> types.v1.Series + 44, // 42: query.v1.TreeQuery.stack_trace_selector:type_name -> types.v1.StackTraceSelector + 2, // 43: query.v1.TreeQuery.symbol_mode:type_name -> query.v1.SymbolMode + 45, // 44: query.v1.TreeSymbols.mappings:type_name -> google.v1.Mapping + 46, // 45: query.v1.TreeSymbols.locations:type_name -> google.v1.Location + 47, // 46: query.v1.TreeSymbols.functions:type_name -> google.v1.Function + 25, // 47: query.v1.TreeReport.query:type_name -> query.v1.TreeQuery + 26, // 48: query.v1.TreeReport.symbols:type_name -> query.v1.TreeSymbols + 27, // 49: query.v1.TreeReport.symbol_refs:type_name -> query.v1.SymbolRefTable + 44, // 50: query.v1.PprofQuery.stack_trace_selector:type_name -> types.v1.StackTraceSelector + 29, // 51: query.v1.PprofReport.query:type_name -> query.v1.PprofQuery + 48, // 52: query.v1.HeatmapQuery.query_type:type_name -> querier.v1.HeatmapQueryType + 42, // 53: query.v1.HeatmapQuery.exemplar_type:type_name -> types.v1.ExemplarType + 33, // 54: query.v1.HeatmapSeries.points:type_name -> query.v1.HeatmapPoint + 31, // 55: query.v1.HeatmapReport.query:type_name -> query.v1.HeatmapQuery + 34, // 56: query.v1.HeatmapReport.heatmap_series:type_name -> query.v1.HeatmapSeries + 32, // 57: query.v1.HeatmapReport.attribute_table:type_name -> query.v1.AttributeTable + 36, // 58: query.v1.Point.exemplars:type_name -> query.v1.Exemplar + 37, // 59: query.v1.Series.points:type_name -> query.v1.Point + 23, // 60: query.v1.TimeSeriesCompactReport.query:type_name -> query.v1.TimeSeriesQuery + 38, // 61: query.v1.TimeSeriesCompactReport.time_series:type_name -> query.v1.Series + 32, // 62: query.v1.TimeSeriesCompactReport.attribute_table:type_name -> query.v1.AttributeTable + 4, // 63: query.v1.QueryFrontendService.Query:input_type -> query.v1.QueryRequest + 7, // 64: query.v1.QueryBackendService.Invoke:input_type -> query.v1.InvokeRequest + 5, // 65: query.v1.QueryFrontendService.Query:output_type -> query.v1.QueryResponse + 11, // 66: query.v1.QueryBackendService.Invoke:output_type -> query.v1.InvokeResponse + 65, // [65:67] is the sub-list for method output_type + 63, // [63:65] is the sub-list for method input_type + 63, // [63:63] is the sub-list for extension type_name + 63, // [63:63] is the sub-list for extension extendee + 0, // [0:63] is the sub-list for field type_name +} + +func init() { file_query_v1_query_proto_init() } +func file_query_v1_query_proto_init() { + if File_query_v1_query_proto != nil { + return + } + file_query_v1_query_proto_msgTypes[21].OneofWrappers = []any{} + file_query_v1_query_proto_msgTypes[24].OneofWrappers = []any{} + file_query_v1_query_proto_msgTypes[25].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_query_v1_query_proto_rawDesc), len(file_query_v1_query_proto_rawDesc)), + NumEnums: 4, + NumMessages: 36, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_query_v1_query_proto_goTypes, + DependencyIndexes: file_query_v1_query_proto_depIdxs, + EnumInfos: file_query_v1_query_proto_enumTypes, + MessageInfos: file_query_v1_query_proto_msgTypes, + }.Build() + File_query_v1_query_proto = out.File + file_query_v1_query_proto_goTypes = nil + file_query_v1_query_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/query/v1/query_vtproto.pb.go b/api/gen/proto/go/query/v1/query_vtproto.pb.go new file mode 100644 index 0000000000..9a5287dc2f --- /dev/null +++ b/api/gen/proto/go/query/v1/query_vtproto.pb.go @@ -0,0 +1,12588 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: query/v1/query.proto + +package queryv1 + +import ( + context "context" + binary "encoding/binary" + fmt "fmt" + v12 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + v13 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + v11 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + math "math" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *QueryRequest) CloneVT() *QueryRequest { + if m == nil { + return (*QueryRequest)(nil) + } + r := new(QueryRequest) + r.StartTime = m.StartTime + r.EndTime = m.EndTime + r.LabelSelector = m.LabelSelector + if rhs := m.Query; rhs != nil { + tmpContainer := make([]*Query, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Query = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *QueryResponse) CloneVT() *QueryResponse { + if m == nil { + return (*QueryResponse)(nil) + } + r := new(QueryResponse) + if rhs := m.Reports; rhs != nil { + tmpContainer := make([]*Report, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Reports = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *InvokeOptions) CloneVT() *InvokeOptions { + if m == nil { + return (*InvokeOptions)(nil) + } + r := new(InvokeOptions) + r.SanitizeOnMerge = m.SanitizeOnMerge + r.CollectDiagnostics = m.CollectDiagnostics + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *InvokeOptions) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *InvokeRequest) CloneVT() *InvokeRequest { + if m == nil { + return (*InvokeRequest)(nil) + } + r := new(InvokeRequest) + r.StartTime = m.StartTime + r.EndTime = m.EndTime + r.LabelSelector = m.LabelSelector + r.QueryPlan = m.QueryPlan.CloneVT() + r.Options = m.Options.CloneVT() + if rhs := m.Tenant; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Tenant = tmpContainer + } + if rhs := m.Query; rhs != nil { + tmpContainer := make([]*Query, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Query = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *InvokeRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *QueryPlan) CloneVT() *QueryPlan { + if m == nil { + return (*QueryPlan)(nil) + } + r := new(QueryPlan) + r.Root = m.Root.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryPlan) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *QueryNode) CloneVT() *QueryNode { + if m == nil { + return (*QueryNode)(nil) + } + r := new(QueryNode) + r.Type = m.Type + if rhs := m.Children; rhs != nil { + tmpContainer := make([]*QueryNode, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Children = tmpContainer + } + if rhs := m.Blocks; rhs != nil { + tmpContainer := make([]*v1.BlockMeta, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.BlockMeta }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.BlockMeta) + } + } + r.Blocks = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *QueryNode) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Query) CloneVT() *Query { + if m == nil { + return (*Query)(nil) + } + r := new(Query) + r.QueryType = m.QueryType + r.LabelNames = m.LabelNames.CloneVT() + r.LabelValues = m.LabelValues.CloneVT() + r.SeriesLabels = m.SeriesLabels.CloneVT() + r.TimeSeries = m.TimeSeries.CloneVT() + r.Tree = m.Tree.CloneVT() + r.Pprof = m.Pprof.CloneVT() + r.Heatmap = m.Heatmap.CloneVT() + r.TimeSeriesCompact = m.TimeSeriesCompact.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Query) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *InvokeResponse) CloneVT() *InvokeResponse { + if m == nil { + return (*InvokeResponse)(nil) + } + r := new(InvokeResponse) + r.Diagnostics = m.Diagnostics.CloneVT() + if rhs := m.Reports; rhs != nil { + tmpContainer := make([]*Report, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Reports = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *InvokeResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Diagnostics) CloneVT() *Diagnostics { + if m == nil { + return (*Diagnostics)(nil) + } + r := new(Diagnostics) + r.QueryPlan = m.QueryPlan.CloneVT() + r.ExecutionNode = m.ExecutionNode.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Diagnostics) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ExecutionNode) CloneVT() *ExecutionNode { + if m == nil { + return (*ExecutionNode)(nil) + } + r := new(ExecutionNode) + r.Type = m.Type + r.Executor = m.Executor + r.StartTimeNs = m.StartTimeNs + r.EndTimeNs = m.EndTimeNs + r.Stats = m.Stats.CloneVT() + r.Error = m.Error + if rhs := m.Children; rhs != nil { + tmpContainer := make([]*ExecutionNode, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Children = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ExecutionNode) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ExecutionStats) CloneVT() *ExecutionStats { + if m == nil { + return (*ExecutionStats)(nil) + } + r := new(ExecutionStats) + r.BlocksRead = m.BlocksRead + r.DatasetsProcessed = m.DatasetsProcessed + r.BytesFetched = m.BytesFetched + if rhs := m.BlockExecutions; rhs != nil { + tmpContainer := make([]*BlockExecution, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.BlockExecutions = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ExecutionStats) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *BlockExecution) CloneVT() *BlockExecution { + if m == nil { + return (*BlockExecution)(nil) + } + r := new(BlockExecution) + r.BlockId = m.BlockId + r.StartTimeNs = m.StartTimeNs + r.EndTimeNs = m.EndTimeNs + r.DatasetsProcessed = m.DatasetsProcessed + r.Size = m.Size + r.Shard = m.Shard + r.CompactionLevel = m.CompactionLevel + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *BlockExecution) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Report) CloneVT() *Report { + if m == nil { + return (*Report)(nil) + } + r := new(Report) + r.ReportType = m.ReportType + r.LabelNames = m.LabelNames.CloneVT() + r.LabelValues = m.LabelValues.CloneVT() + r.SeriesLabels = m.SeriesLabels.CloneVT() + r.TimeSeries = m.TimeSeries.CloneVT() + r.Tree = m.Tree.CloneVT() + r.Pprof = m.Pprof.CloneVT() + r.Heatmap = m.Heatmap.CloneVT() + r.TimeSeriesCompact = m.TimeSeriesCompact.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Report) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *LabelNamesQuery) CloneVT() *LabelNamesQuery { + if m == nil { + return (*LabelNamesQuery)(nil) + } + r := new(LabelNamesQuery) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *LabelNamesQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *LabelNamesReport) CloneVT() *LabelNamesReport { + if m == nil { + return (*LabelNamesReport)(nil) + } + r := new(LabelNamesReport) + r.Query = m.Query.CloneVT() + if rhs := m.LabelNames; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.LabelNames = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *LabelNamesReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *LabelValuesQuery) CloneVT() *LabelValuesQuery { + if m == nil { + return (*LabelValuesQuery)(nil) + } + r := new(LabelValuesQuery) + r.LabelName = m.LabelName + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *LabelValuesQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *LabelValuesReport) CloneVT() *LabelValuesReport { + if m == nil { + return (*LabelValuesReport)(nil) + } + r := new(LabelValuesReport) + r.Query = m.Query.CloneVT() + if rhs := m.LabelValues; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.LabelValues = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *LabelValuesReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *SeriesLabelsQuery) CloneVT() *SeriesLabelsQuery { + if m == nil { + return (*SeriesLabelsQuery)(nil) + } + r := new(SeriesLabelsQuery) + if rhs := m.LabelNames; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.LabelNames = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *SeriesLabelsQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *SeriesLabelsReport) CloneVT() *SeriesLabelsReport { + if m == nil { + return (*SeriesLabelsReport)(nil) + } + r := new(SeriesLabelsReport) + r.Query = m.Query.CloneVT() + if rhs := m.SeriesLabels; rhs != nil { + tmpContainer := make([]*v11.Labels, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v11.Labels }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v11.Labels) + } + } + r.SeriesLabels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *SeriesLabelsReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TimeSeriesQuery) CloneVT() *TimeSeriesQuery { + if m == nil { + return (*TimeSeriesQuery)(nil) + } + r := new(TimeSeriesQuery) + r.Step = m.Step + r.Limit = m.Limit + r.ExemplarType = m.ExemplarType + if rhs := m.GroupBy; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.GroupBy = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TimeSeriesQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TimeSeriesReport) CloneVT() *TimeSeriesReport { + if m == nil { + return (*TimeSeriesReport)(nil) + } + r := new(TimeSeriesReport) + r.Query = m.Query.CloneVT() + if rhs := m.TimeSeries; rhs != nil { + tmpContainer := make([]*v11.Series, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v11.Series }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v11.Series) + } + } + r.TimeSeries = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TimeSeriesReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TreeQuery) CloneVT() *TreeQuery { + if m == nil { + return (*TreeQuery)(nil) + } + r := new(TreeQuery) + r.MaxNodes = m.MaxNodes + r.FullSymbols = m.FullSymbols + r.SymbolMode = m.SymbolMode + r.MaxUnresolvedLocations = m.MaxUnresolvedLocations + if rhs := m.SpanSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.SpanSelector = tmpContainer + } + if rhs := m.StackTraceSelector; rhs != nil { + if vtpb, ok := interface{}(rhs).(interface { + CloneVT() *v11.StackTraceSelector + }); ok { + r.StackTraceSelector = vtpb.CloneVT() + } else { + r.StackTraceSelector = proto.Clone(rhs).(*v11.StackTraceSelector) + } + } + if rhs := m.ProfileIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.ProfileIdSelector = tmpContainer + } + if rhs := m.TraceIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.TraceIdSelector = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TreeQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TreeSymbols) CloneVT() *TreeSymbols { + if m == nil { + return (*TreeSymbols)(nil) + } + r := new(TreeSymbols) + if rhs := m.Mappings; rhs != nil { + tmpContainer := make([]*v12.Mapping, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v12.Mapping }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v12.Mapping) + } + } + r.Mappings = tmpContainer + } + if rhs := m.Locations; rhs != nil { + tmpContainer := make([]*v12.Location, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v12.Location }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v12.Location) + } + } + r.Locations = tmpContainer + } + if rhs := m.Functions; rhs != nil { + tmpContainer := make([]*v12.Function, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v12.Function }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v12.Function) + } + } + r.Functions = tmpContainer + } + if rhs := m.Strings; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Strings = tmpContainer + } + if rhs := m.MappingHashes; rhs != nil { + tmpContainer := make([]uint64, len(rhs)) + copy(tmpContainer, rhs) + r.MappingHashes = tmpContainer + } + if rhs := m.LocationHashes; rhs != nil { + tmpContainer := make([]uint64, len(rhs)) + copy(tmpContainer, rhs) + r.LocationHashes = tmpContainer + } + if rhs := m.FunctionHashes; rhs != nil { + tmpContainer := make([]uint64, len(rhs)) + copy(tmpContainer, rhs) + r.FunctionHashes = tmpContainer + } + if rhs := m.StringHashes; rhs != nil { + tmpContainer := make([]uint64, len(rhs)) + copy(tmpContainer, rhs) + r.StringHashes = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TreeSymbols) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *SymbolRefTable) CloneVT() *SymbolRefTable { + if m == nil { + return (*SymbolRefTable)(nil) + } + r := new(SymbolRefTable) + if rhs := m.Names; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Names = tmpContainer + } + if rhs := m.BuildIds; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.BuildIds = tmpContainer + } + if rhs := m.BinaryNames; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.BinaryNames = tmpContainer + } + if rhs := m.UnresolvedBuildId; rhs != nil { + tmpContainer := make([]uint32, len(rhs)) + copy(tmpContainer, rhs) + r.UnresolvedBuildId = tmpContainer + } + if rhs := m.UnresolvedAddress; rhs != nil { + tmpContainer := make([]uint64, len(rhs)) + copy(tmpContainer, rhs) + r.UnresolvedAddress = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *SymbolRefTable) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TreeReport) CloneVT() *TreeReport { + if m == nil { + return (*TreeReport)(nil) + } + r := new(TreeReport) + r.Query = m.Query.CloneVT() + r.Symbols = m.Symbols.CloneVT() + r.SymbolRefs = m.SymbolRefs.CloneVT() + if rhs := m.Tree; rhs != nil { + tmpBytes := make([]byte, len(rhs)) + copy(tmpBytes, rhs) + r.Tree = tmpBytes + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TreeReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *PprofQuery) CloneVT() *PprofQuery { + if m == nil { + return (*PprofQuery)(nil) + } + r := new(PprofQuery) + r.MaxNodes = m.MaxNodes + if rhs := m.StackTraceSelector; rhs != nil { + if vtpb, ok := interface{}(rhs).(interface { + CloneVT() *v11.StackTraceSelector + }); ok { + r.StackTraceSelector = vtpb.CloneVT() + } else { + r.StackTraceSelector = proto.Clone(rhs).(*v11.StackTraceSelector) + } + } + if rhs := m.ProfileIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.ProfileIdSelector = tmpContainer + } + if rhs := m.SpanSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.SpanSelector = tmpContainer + } + if rhs := m.TraceIdSelector; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.TraceIdSelector = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *PprofQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *PprofReport) CloneVT() *PprofReport { + if m == nil { + return (*PprofReport)(nil) + } + r := new(PprofReport) + r.Query = m.Query.CloneVT() + if rhs := m.Pprof; rhs != nil { + tmpBytes := make([]byte, len(rhs)) + copy(tmpBytes, rhs) + r.Pprof = tmpBytes + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *PprofReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *HeatmapQuery) CloneVT() *HeatmapQuery { + if m == nil { + return (*HeatmapQuery)(nil) + } + r := new(HeatmapQuery) + r.Step = m.Step + r.QueryType = m.QueryType + r.Limit = m.Limit + r.ExemplarType = m.ExemplarType + if rhs := m.GroupBy; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.GroupBy = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *HeatmapQuery) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *AttributeTable) CloneVT() *AttributeTable { + if m == nil { + return (*AttributeTable)(nil) + } + r := new(AttributeTable) + if rhs := m.Keys; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Keys = tmpContainer + } + if rhs := m.Values; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Values = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *AttributeTable) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *HeatmapPoint) CloneVT() *HeatmapPoint { + if m == nil { + return (*HeatmapPoint)(nil) + } + r := new(HeatmapPoint) + r.Timestamp = m.Timestamp + r.ProfileId = m.ProfileId + r.SpanId = m.SpanId + r.Value = m.Value + if rhs := m.AttributeRefs; rhs != nil { + tmpContainer := make([]int64, len(rhs)) + copy(tmpContainer, rhs) + r.AttributeRefs = tmpContainer + } + if rhs := m.TraceId; rhs != nil { + tmpBytes := make([]byte, len(rhs)) + copy(tmpBytes, rhs) + r.TraceId = tmpBytes + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *HeatmapPoint) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *HeatmapSeries) CloneVT() *HeatmapSeries { + if m == nil { + return (*HeatmapSeries)(nil) + } + r := new(HeatmapSeries) + if rhs := m.AttributeRefs; rhs != nil { + tmpContainer := make([]int64, len(rhs)) + copy(tmpContainer, rhs) + r.AttributeRefs = tmpContainer + } + if rhs := m.Points; rhs != nil { + tmpContainer := make([]*HeatmapPoint, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Points = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *HeatmapSeries) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *HeatmapReport) CloneVT() *HeatmapReport { + if m == nil { + return (*HeatmapReport)(nil) + } + r := new(HeatmapReport) + r.Query = m.Query.CloneVT() + r.AttributeTable = m.AttributeTable.CloneVT() + if rhs := m.HeatmapSeries; rhs != nil { + tmpContainer := make([]*HeatmapSeries, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.HeatmapSeries = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *HeatmapReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Exemplar) CloneVT() *Exemplar { + if m == nil { + return (*Exemplar)(nil) + } + r := new(Exemplar) + r.Timestamp = m.Timestamp + r.ProfileId = m.ProfileId + r.SpanId = m.SpanId + r.Value = m.Value + if rhs := m.AttributeRefs; rhs != nil { + tmpContainer := make([]int64, len(rhs)) + copy(tmpContainer, rhs) + r.AttributeRefs = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Exemplar) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Point) CloneVT() *Point { + if m == nil { + return (*Point)(nil) + } + r := new(Point) + r.Value = m.Value + r.Timestamp = m.Timestamp + if rhs := m.AnnotationRefs; rhs != nil { + tmpContainer := make([]int64, len(rhs)) + copy(tmpContainer, rhs) + r.AnnotationRefs = tmpContainer + } + if rhs := m.Exemplars; rhs != nil { + tmpContainer := make([]*Exemplar, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Exemplars = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Point) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *Series) CloneVT() *Series { + if m == nil { + return (*Series)(nil) + } + r := new(Series) + if rhs := m.AttributeRefs; rhs != nil { + tmpContainer := make([]int64, len(rhs)) + copy(tmpContainer, rhs) + r.AttributeRefs = tmpContainer + } + if rhs := m.Points; rhs != nil { + tmpContainer := make([]*Point, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Points = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Series) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *TimeSeriesCompactReport) CloneVT() *TimeSeriesCompactReport { + if m == nil { + return (*TimeSeriesCompactReport)(nil) + } + r := new(TimeSeriesCompactReport) + r.Query = m.Query.CloneVT() + r.AttributeTable = m.AttributeTable.CloneVT() + if rhs := m.TimeSeries; rhs != nil { + tmpContainer := make([]*Series, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.TimeSeries = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *TimeSeriesCompactReport) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *QueryRequest) EqualVT(that *QueryRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.StartTime != that.StartTime { + return false + } + if this.EndTime != that.EndTime { + return false + } + if this.LabelSelector != that.LabelSelector { + return false + } + if len(this.Query) != len(that.Query) { + return false + } + for i, vx := range this.Query { + vy := that.Query[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Query{} + } + if q == nil { + q = &Query{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *QueryResponse) EqualVT(that *QueryResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Reports) != len(that.Reports) { + return false + } + for i, vx := range this.Reports { + vy := that.Reports[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Report{} + } + if q == nil { + q = &Report{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *InvokeOptions) EqualVT(that *InvokeOptions) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.SanitizeOnMerge != that.SanitizeOnMerge { + return false + } + if this.CollectDiagnostics != that.CollectDiagnostics { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *InvokeOptions) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*InvokeOptions) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *InvokeRequest) EqualVT(that *InvokeRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Tenant) != len(that.Tenant) { + return false + } + for i, vx := range this.Tenant { + vy := that.Tenant[i] + if vx != vy { + return false + } + } + if this.StartTime != that.StartTime { + return false + } + if this.EndTime != that.EndTime { + return false + } + if this.LabelSelector != that.LabelSelector { + return false + } + if len(this.Query) != len(that.Query) { + return false + } + for i, vx := range this.Query { + vy := that.Query[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Query{} + } + if q == nil { + q = &Query{} + } + if !p.EqualVT(q) { + return false + } + } + } + if !this.QueryPlan.EqualVT(that.QueryPlan) { + return false + } + if !this.Options.EqualVT(that.Options) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *InvokeRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*InvokeRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *QueryPlan) EqualVT(that *QueryPlan) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Root.EqualVT(that.Root) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryPlan) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryPlan) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *QueryNode) EqualVT(that *QueryNode) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Type != that.Type { + return false + } + if len(this.Children) != len(that.Children) { + return false + } + for i, vx := range this.Children { + vy := that.Children[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &QueryNode{} + } + if q == nil { + q = &QueryNode{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.Blocks) != len(that.Blocks) { + return false + } + for i, vx := range this.Blocks { + vy := that.Blocks[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.BlockMeta{} + } + if q == nil { + q = &v1.BlockMeta{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.BlockMeta) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *QueryNode) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*QueryNode) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Query) EqualVT(that *Query) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.QueryType != that.QueryType { + return false + } + if !this.LabelNames.EqualVT(that.LabelNames) { + return false + } + if !this.LabelValues.EqualVT(that.LabelValues) { + return false + } + if !this.SeriesLabels.EqualVT(that.SeriesLabels) { + return false + } + if !this.TimeSeries.EqualVT(that.TimeSeries) { + return false + } + if !this.Tree.EqualVT(that.Tree) { + return false + } + if !this.Pprof.EqualVT(that.Pprof) { + return false + } + if !this.Heatmap.EqualVT(that.Heatmap) { + return false + } + if !this.TimeSeriesCompact.EqualVT(that.TimeSeriesCompact) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Query) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Query) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *InvokeResponse) EqualVT(that *InvokeResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Reports) != len(that.Reports) { + return false + } + for i, vx := range this.Reports { + vy := that.Reports[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Report{} + } + if q == nil { + q = &Report{} + } + if !p.EqualVT(q) { + return false + } + } + } + if !this.Diagnostics.EqualVT(that.Diagnostics) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *InvokeResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*InvokeResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Diagnostics) EqualVT(that *Diagnostics) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.QueryPlan.EqualVT(that.QueryPlan) { + return false + } + if !this.ExecutionNode.EqualVT(that.ExecutionNode) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Diagnostics) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Diagnostics) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ExecutionNode) EqualVT(that *ExecutionNode) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Type != that.Type { + return false + } + if this.Executor != that.Executor { + return false + } + if this.StartTimeNs != that.StartTimeNs { + return false + } + if this.EndTimeNs != that.EndTimeNs { + return false + } + if len(this.Children) != len(that.Children) { + return false + } + for i, vx := range this.Children { + vy := that.Children[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &ExecutionNode{} + } + if q == nil { + q = &ExecutionNode{} + } + if !p.EqualVT(q) { + return false + } + } + } + if !this.Stats.EqualVT(that.Stats) { + return false + } + if this.Error != that.Error { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ExecutionNode) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ExecutionNode) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ExecutionStats) EqualVT(that *ExecutionStats) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.BlocksRead != that.BlocksRead { + return false + } + if this.DatasetsProcessed != that.DatasetsProcessed { + return false + } + if len(this.BlockExecutions) != len(that.BlockExecutions) { + return false + } + for i, vx := range this.BlockExecutions { + vy := that.BlockExecutions[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &BlockExecution{} + } + if q == nil { + q = &BlockExecution{} + } + if !p.EqualVT(q) { + return false + } + } + } + if this.BytesFetched != that.BytesFetched { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ExecutionStats) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ExecutionStats) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *BlockExecution) EqualVT(that *BlockExecution) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.BlockId != that.BlockId { + return false + } + if this.StartTimeNs != that.StartTimeNs { + return false + } + if this.EndTimeNs != that.EndTimeNs { + return false + } + if this.DatasetsProcessed != that.DatasetsProcessed { + return false + } + if this.Size != that.Size { + return false + } + if this.Shard != that.Shard { + return false + } + if this.CompactionLevel != that.CompactionLevel { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *BlockExecution) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*BlockExecution) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Report) EqualVT(that *Report) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.ReportType != that.ReportType { + return false + } + if !this.LabelNames.EqualVT(that.LabelNames) { + return false + } + if !this.LabelValues.EqualVT(that.LabelValues) { + return false + } + if !this.SeriesLabels.EqualVT(that.SeriesLabels) { + return false + } + if !this.TimeSeries.EqualVT(that.TimeSeries) { + return false + } + if !this.Tree.EqualVT(that.Tree) { + return false + } + if !this.Pprof.EqualVT(that.Pprof) { + return false + } + if !this.Heatmap.EqualVT(that.Heatmap) { + return false + } + if !this.TimeSeriesCompact.EqualVT(that.TimeSeriesCompact) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Report) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Report) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *LabelNamesQuery) EqualVT(that *LabelNamesQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *LabelNamesQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*LabelNamesQuery) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *LabelNamesReport) EqualVT(that *LabelNamesReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if len(this.LabelNames) != len(that.LabelNames) { + return false + } + for i, vx := range this.LabelNames { + vy := that.LabelNames[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *LabelNamesReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*LabelNamesReport) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *LabelValuesQuery) EqualVT(that *LabelValuesQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.LabelName != that.LabelName { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *LabelValuesQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*LabelValuesQuery) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *LabelValuesReport) EqualVT(that *LabelValuesReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if len(this.LabelValues) != len(that.LabelValues) { + return false + } + for i, vx := range this.LabelValues { + vy := that.LabelValues[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *LabelValuesReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*LabelValuesReport) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *SeriesLabelsQuery) EqualVT(that *SeriesLabelsQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.LabelNames) != len(that.LabelNames) { + return false + } + for i, vx := range this.LabelNames { + vy := that.LabelNames[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *SeriesLabelsQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*SeriesLabelsQuery) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *SeriesLabelsReport) EqualVT(that *SeriesLabelsReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if len(this.SeriesLabels) != len(that.SeriesLabels) { + return false + } + for i, vx := range this.SeriesLabels { + vy := that.SeriesLabels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v11.Labels{} + } + if q == nil { + q = &v11.Labels{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v11.Labels) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *SeriesLabelsReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*SeriesLabelsReport) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TimeSeriesQuery) EqualVT(that *TimeSeriesQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Step != that.Step { + return false + } + if len(this.GroupBy) != len(that.GroupBy) { + return false + } + for i, vx := range this.GroupBy { + vy := that.GroupBy[i] + if vx != vy { + return false + } + } + if this.Limit != that.Limit { + return false + } + if this.ExemplarType != that.ExemplarType { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TimeSeriesQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TimeSeriesQuery) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TimeSeriesReport) EqualVT(that *TimeSeriesReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if len(this.TimeSeries) != len(that.TimeSeries) { + return false + } + for i, vx := range this.TimeSeries { + vy := that.TimeSeries[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v11.Series{} + } + if q == nil { + q = &v11.Series{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v11.Series) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TimeSeriesReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TimeSeriesReport) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TreeQuery) EqualVT(that *TreeQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.MaxNodes != that.MaxNodes { + return false + } + if len(this.SpanSelector) != len(that.SpanSelector) { + return false + } + for i, vx := range this.SpanSelector { + vy := that.SpanSelector[i] + if vx != vy { + return false + } + } + if equal, ok := interface{}(this.StackTraceSelector).(interface { + EqualVT(*v11.StackTraceSelector) bool + }); ok { + if !equal.EqualVT(that.StackTraceSelector) { + return false + } + } else if !proto.Equal(this.StackTraceSelector, that.StackTraceSelector) { + return false + } + if len(this.ProfileIdSelector) != len(that.ProfileIdSelector) { + return false + } + for i, vx := range this.ProfileIdSelector { + vy := that.ProfileIdSelector[i] + if vx != vy { + return false + } + } + if this.FullSymbols != that.FullSymbols { + return false + } + if len(this.TraceIdSelector) != len(that.TraceIdSelector) { + return false + } + for i, vx := range this.TraceIdSelector { + vy := that.TraceIdSelector[i] + if vx != vy { + return false + } + } + if this.SymbolMode != that.SymbolMode { + return false + } + if this.MaxUnresolvedLocations != that.MaxUnresolvedLocations { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TreeQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TreeQuery) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TreeSymbols) EqualVT(that *TreeSymbols) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Mappings) != len(that.Mappings) { + return false + } + for i, vx := range this.Mappings { + vy := that.Mappings[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v12.Mapping{} + } + if q == nil { + q = &v12.Mapping{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v12.Mapping) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + if len(this.Locations) != len(that.Locations) { + return false + } + for i, vx := range this.Locations { + vy := that.Locations[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v12.Location{} + } + if q == nil { + q = &v12.Location{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v12.Location) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + if len(this.Functions) != len(that.Functions) { + return false + } + for i, vx := range this.Functions { + vy := that.Functions[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v12.Function{} + } + if q == nil { + q = &v12.Function{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v12.Function) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + if len(this.Strings) != len(that.Strings) { + return false + } + for i, vx := range this.Strings { + vy := that.Strings[i] + if vx != vy { + return false + } + } + if len(this.MappingHashes) != len(that.MappingHashes) { + return false + } + for i, vx := range this.MappingHashes { + vy := that.MappingHashes[i] + if vx != vy { + return false + } + } + if len(this.LocationHashes) != len(that.LocationHashes) { + return false + } + for i, vx := range this.LocationHashes { + vy := that.LocationHashes[i] + if vx != vy { + return false + } + } + if len(this.FunctionHashes) != len(that.FunctionHashes) { + return false + } + for i, vx := range this.FunctionHashes { + vy := that.FunctionHashes[i] + if vx != vy { + return false + } + } + if len(this.StringHashes) != len(that.StringHashes) { + return false + } + for i, vx := range this.StringHashes { + vy := that.StringHashes[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TreeSymbols) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TreeSymbols) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *SymbolRefTable) EqualVT(that *SymbolRefTable) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Names) != len(that.Names) { + return false + } + for i, vx := range this.Names { + vy := that.Names[i] + if vx != vy { + return false + } + } + if len(this.BuildIds) != len(that.BuildIds) { + return false + } + for i, vx := range this.BuildIds { + vy := that.BuildIds[i] + if vx != vy { + return false + } + } + if len(this.BinaryNames) != len(that.BinaryNames) { + return false + } + for i, vx := range this.BinaryNames { + vy := that.BinaryNames[i] + if vx != vy { + return false + } + } + if len(this.UnresolvedBuildId) != len(that.UnresolvedBuildId) { + return false + } + for i, vx := range this.UnresolvedBuildId { + vy := that.UnresolvedBuildId[i] + if vx != vy { + return false + } + } + if len(this.UnresolvedAddress) != len(that.UnresolvedAddress) { + return false + } + for i, vx := range this.UnresolvedAddress { + vy := that.UnresolvedAddress[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *SymbolRefTable) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*SymbolRefTable) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TreeReport) EqualVT(that *TreeReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if string(this.Tree) != string(that.Tree) { + return false + } + if !this.Symbols.EqualVT(that.Symbols) { + return false + } + if !this.SymbolRefs.EqualVT(that.SymbolRefs) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TreeReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TreeReport) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *PprofQuery) EqualVT(that *PprofQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.MaxNodes != that.MaxNodes { + return false + } + if equal, ok := interface{}(this.StackTraceSelector).(interface { + EqualVT(*v11.StackTraceSelector) bool + }); ok { + if !equal.EqualVT(that.StackTraceSelector) { + return false + } + } else if !proto.Equal(this.StackTraceSelector, that.StackTraceSelector) { + return false + } + if len(this.ProfileIdSelector) != len(that.ProfileIdSelector) { + return false + } + for i, vx := range this.ProfileIdSelector { + vy := that.ProfileIdSelector[i] + if vx != vy { + return false + } + } + if len(this.SpanSelector) != len(that.SpanSelector) { + return false + } + for i, vx := range this.SpanSelector { + vy := that.SpanSelector[i] + if vx != vy { + return false + } + } + if len(this.TraceIdSelector) != len(that.TraceIdSelector) { + return false + } + for i, vx := range this.TraceIdSelector { + vy := that.TraceIdSelector[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *PprofQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*PprofQuery) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *PprofReport) EqualVT(that *PprofReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if string(this.Pprof) != string(that.Pprof) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *PprofReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*PprofReport) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *HeatmapQuery) EqualVT(that *HeatmapQuery) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Step != that.Step { + return false + } + if len(this.GroupBy) != len(that.GroupBy) { + return false + } + for i, vx := range this.GroupBy { + vy := that.GroupBy[i] + if vx != vy { + return false + } + } + if this.QueryType != that.QueryType { + return false + } + if this.Limit != that.Limit { + return false + } + if this.ExemplarType != that.ExemplarType { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *HeatmapQuery) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*HeatmapQuery) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *AttributeTable) EqualVT(that *AttributeTable) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Keys) != len(that.Keys) { + return false + } + for i, vx := range this.Keys { + vy := that.Keys[i] + if vx != vy { + return false + } + } + if len(this.Values) != len(that.Values) { + return false + } + for i, vx := range this.Values { + vy := that.Values[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *AttributeTable) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*AttributeTable) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *HeatmapPoint) EqualVT(that *HeatmapPoint) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Timestamp != that.Timestamp { + return false + } + if this.ProfileId != that.ProfileId { + return false + } + if this.SpanId != that.SpanId { + return false + } + if this.Value != that.Value { + return false + } + if len(this.AttributeRefs) != len(that.AttributeRefs) { + return false + } + for i, vx := range this.AttributeRefs { + vy := that.AttributeRefs[i] + if vx != vy { + return false + } + } + if string(this.TraceId) != string(that.TraceId) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *HeatmapPoint) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*HeatmapPoint) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *HeatmapSeries) EqualVT(that *HeatmapSeries) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.AttributeRefs) != len(that.AttributeRefs) { + return false + } + for i, vx := range this.AttributeRefs { + vy := that.AttributeRefs[i] + if vx != vy { + return false + } + } + if len(this.Points) != len(that.Points) { + return false + } + for i, vx := range this.Points { + vy := that.Points[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &HeatmapPoint{} + } + if q == nil { + q = &HeatmapPoint{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *HeatmapSeries) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*HeatmapSeries) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *HeatmapReport) EqualVT(that *HeatmapReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if len(this.HeatmapSeries) != len(that.HeatmapSeries) { + return false + } + for i, vx := range this.HeatmapSeries { + vy := that.HeatmapSeries[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &HeatmapSeries{} + } + if q == nil { + q = &HeatmapSeries{} + } + if !p.EqualVT(q) { + return false + } + } + } + if !this.AttributeTable.EqualVT(that.AttributeTable) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *HeatmapReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*HeatmapReport) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Exemplar) EqualVT(that *Exemplar) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Timestamp != that.Timestamp { + return false + } + if this.ProfileId != that.ProfileId { + return false + } + if this.SpanId != that.SpanId { + return false + } + if this.Value != that.Value { + return false + } + if len(this.AttributeRefs) != len(that.AttributeRefs) { + return false + } + for i, vx := range this.AttributeRefs { + vy := that.AttributeRefs[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Exemplar) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Exemplar) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Point) EqualVT(that *Point) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Value != that.Value { + return false + } + if this.Timestamp != that.Timestamp { + return false + } + if len(this.Exemplars) != len(that.Exemplars) { + return false + } + for i, vx := range this.Exemplars { + vy := that.Exemplars[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Exemplar{} + } + if q == nil { + q = &Exemplar{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.AnnotationRefs) != len(that.AnnotationRefs) { + return false + } + for i, vx := range this.AnnotationRefs { + vy := that.AnnotationRefs[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Point) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Point) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *Series) EqualVT(that *Series) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.AttributeRefs) != len(that.AttributeRefs) { + return false + } + for i, vx := range this.AttributeRefs { + vy := that.AttributeRefs[i] + if vx != vy { + return false + } + } + if len(this.Points) != len(that.Points) { + return false + } + for i, vx := range this.Points { + vy := that.Points[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Point{} + } + if q == nil { + q = &Point{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *Series) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Series) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *TimeSeriesCompactReport) EqualVT(that *TimeSeriesCompactReport) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Query.EqualVT(that.Query) { + return false + } + if len(this.TimeSeries) != len(that.TimeSeries) { + return false + } + for i, vx := range this.TimeSeries { + vy := that.TimeSeries[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Series{} + } + if q == nil { + q = &Series{} + } + if !p.EqualVT(q) { + return false + } + } + } + if !this.AttributeTable.EqualVT(that.AttributeTable) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *TimeSeriesCompactReport) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*TimeSeriesCompactReport) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// QueryFrontendServiceClient is the client API for QueryFrontendService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QueryFrontendServiceClient interface { + Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) +} + +type queryFrontendServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewQueryFrontendServiceClient(cc grpc.ClientConnInterface) QueryFrontendServiceClient { + return &queryFrontendServiceClient{cc} +} + +func (c *queryFrontendServiceClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) { + out := new(QueryResponse) + err := c.cc.Invoke(ctx, "/query.v1.QueryFrontendService/Query", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryFrontendServiceServer is the server API for QueryFrontendService service. +// All implementations must embed UnimplementedQueryFrontendServiceServer +// for forward compatibility +type QueryFrontendServiceServer interface { + Query(context.Context, *QueryRequest) (*QueryResponse, error) + mustEmbedUnimplementedQueryFrontendServiceServer() +} + +// UnimplementedQueryFrontendServiceServer must be embedded to have forward compatible implementations. +type UnimplementedQueryFrontendServiceServer struct { +} + +func (UnimplementedQueryFrontendServiceServer) Query(context.Context, *QueryRequest) (*QueryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Query not implemented") +} +func (UnimplementedQueryFrontendServiceServer) mustEmbedUnimplementedQueryFrontendServiceServer() {} + +// UnsafeQueryFrontendServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QueryFrontendServiceServer will +// result in compilation errors. +type UnsafeQueryFrontendServiceServer interface { + mustEmbedUnimplementedQueryFrontendServiceServer() +} + +func RegisterQueryFrontendServiceServer(s grpc.ServiceRegistrar, srv QueryFrontendServiceServer) { + s.RegisterService(&QueryFrontendService_ServiceDesc, srv) +} + +func _QueryFrontendService_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryFrontendServiceServer).Query(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/query.v1.QueryFrontendService/Query", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryFrontendServiceServer).Query(ctx, req.(*QueryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// QueryFrontendService_ServiceDesc is the grpc.ServiceDesc for QueryFrontendService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var QueryFrontendService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "query.v1.QueryFrontendService", + HandlerType: (*QueryFrontendServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Query", + Handler: _QueryFrontendService_Query_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "query/v1/query.proto", +} + +// QueryBackendServiceClient is the client API for QueryBackendService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QueryBackendServiceClient interface { + Invoke(ctx context.Context, in *InvokeRequest, opts ...grpc.CallOption) (*InvokeResponse, error) +} + +type queryBackendServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewQueryBackendServiceClient(cc grpc.ClientConnInterface) QueryBackendServiceClient { + return &queryBackendServiceClient{cc} +} + +func (c *queryBackendServiceClient) Invoke(ctx context.Context, in *InvokeRequest, opts ...grpc.CallOption) (*InvokeResponse, error) { + out := new(InvokeResponse) + err := c.cc.Invoke(ctx, "/query.v1.QueryBackendService/Invoke", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryBackendServiceServer is the server API for QueryBackendService service. +// All implementations must embed UnimplementedQueryBackendServiceServer +// for forward compatibility +type QueryBackendServiceServer interface { + Invoke(context.Context, *InvokeRequest) (*InvokeResponse, error) + mustEmbedUnimplementedQueryBackendServiceServer() +} + +// UnimplementedQueryBackendServiceServer must be embedded to have forward compatible implementations. +type UnimplementedQueryBackendServiceServer struct { +} + +func (UnimplementedQueryBackendServiceServer) Invoke(context.Context, *InvokeRequest) (*InvokeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Invoke not implemented") +} +func (UnimplementedQueryBackendServiceServer) mustEmbedUnimplementedQueryBackendServiceServer() {} + +// UnsafeQueryBackendServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QueryBackendServiceServer will +// result in compilation errors. +type UnsafeQueryBackendServiceServer interface { + mustEmbedUnimplementedQueryBackendServiceServer() +} + +func RegisterQueryBackendServiceServer(s grpc.ServiceRegistrar, srv QueryBackendServiceServer) { + s.RegisterService(&QueryBackendService_ServiceDesc, srv) +} + +func _QueryBackendService_Invoke_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InvokeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryBackendServiceServer).Invoke(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/query.v1.QueryBackendService/Invoke", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryBackendServiceServer).Invoke(ctx, req.(*InvokeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// QueryBackendService_ServiceDesc is the grpc.ServiceDesc for QueryBackendService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var QueryBackendService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "query.v1.QueryBackendService", + HandlerType: (*QueryBackendServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Invoke", + Handler: _QueryBackendService_Invoke_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "query/v1/query.proto", +} + +func (m *QueryRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Query) > 0 { + for iNdEx := len(m.Query) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Query[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + } + if len(m.LabelSelector) > 0 { + i -= len(m.LabelSelector) + copy(dAtA[i:], m.LabelSelector) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelSelector))) + i-- + dAtA[i] = 0x1a + } + if m.EndTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.EndTime)) + i-- + dAtA[i] = 0x10 + } + if m.StartTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Reports) > 0 { + for iNdEx := len(m.Reports) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Reports[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *InvokeOptions) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InvokeOptions) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *InvokeOptions) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CollectDiagnostics { + i-- + if m.CollectDiagnostics { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.SanitizeOnMerge { + i-- + if m.SanitizeOnMerge { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *InvokeRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InvokeRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *InvokeRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Options != nil { + size, err := m.Options.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x3a + } + if m.QueryPlan != nil { + size, err := m.QueryPlan.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + if len(m.Query) > 0 { + for iNdEx := len(m.Query) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Query[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + } + if len(m.LabelSelector) > 0 { + i -= len(m.LabelSelector) + copy(dAtA[i:], m.LabelSelector) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelSelector))) + i-- + dAtA[i] = 0x22 + } + if m.EndTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.EndTime)) + i-- + dAtA[i] = 0x18 + } + if m.StartTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x10 + } + if len(m.Tenant) > 0 { + for iNdEx := len(m.Tenant) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Tenant[iNdEx]) + copy(dAtA[i:], m.Tenant[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tenant[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryPlan) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryPlan) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryPlan) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Root != nil { + size, err := m.Root.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryNode) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryNode) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *QueryNode) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Blocks) > 0 { + for iNdEx := len(m.Blocks) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Blocks[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Blocks[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Children) > 0 { + for iNdEx := len(m.Children) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Children[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if m.Type != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Query) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Query) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Query) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.TimeSeriesCompact != nil { + size, err := m.TimeSeriesCompact.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x4a + } + if m.Heatmap != nil { + size, err := m.Heatmap.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } + if m.Pprof != nil { + size, err := m.Pprof.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x3a + } + if m.Tree != nil { + size, err := m.Tree.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + if m.TimeSeries != nil { + size, err := m.TimeSeries.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + if m.SeriesLabels != nil { + size, err := m.SeriesLabels.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + if m.LabelValues != nil { + size, err := m.LabelValues.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if m.LabelNames != nil { + size, err := m.LabelNames.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.QueryType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.QueryType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *InvokeResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InvokeResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *InvokeResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Diagnostics != nil { + size, err := m.Diagnostics.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if len(m.Reports) > 0 { + for iNdEx := len(m.Reports) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Reports[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Diagnostics) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Diagnostics) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Diagnostics) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.ExecutionNode != nil { + size, err := m.ExecutionNode.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.QueryPlan != nil { + size, err := m.QueryPlan.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ExecutionNode) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExecutionNode) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ExecutionNode) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Error) > 0 { + i -= len(m.Error) + copy(dAtA[i:], m.Error) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Error))) + i-- + dAtA[i] = 0x3a + } + if m.Stats != nil { + size, err := m.Stats.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + if len(m.Children) > 0 { + for iNdEx := len(m.Children) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Children[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + } + if m.EndTimeNs != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.EndTimeNs)) + i-- + dAtA[i] = 0x20 + } + if m.StartTimeNs != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StartTimeNs)) + i-- + dAtA[i] = 0x18 + } + if len(m.Executor) > 0 { + i -= len(m.Executor) + copy(dAtA[i:], m.Executor) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Executor))) + i-- + dAtA[i] = 0x12 + } + if m.Type != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ExecutionStats) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExecutionStats) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ExecutionStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.BytesFetched != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.BytesFetched)) + i-- + dAtA[i] = 0x20 + } + if len(m.BlockExecutions) > 0 { + for iNdEx := len(m.BlockExecutions) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.BlockExecutions[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + } + if m.DatasetsProcessed != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.DatasetsProcessed)) + i-- + dAtA[i] = 0x10 + } + if m.BlocksRead != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.BlocksRead)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *BlockExecution) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockExecution) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *BlockExecution) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CompactionLevel != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CompactionLevel)) + i-- + dAtA[i] = 0x38 + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x30 + } + if m.Size != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size)) + i-- + dAtA[i] = 0x28 + } + if m.DatasetsProcessed != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.DatasetsProcessed)) + i-- + dAtA[i] = 0x20 + } + if m.EndTimeNs != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.EndTimeNs)) + i-- + dAtA[i] = 0x18 + } + if m.StartTimeNs != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StartTimeNs)) + i-- + dAtA[i] = 0x10 + } + if len(m.BlockId) > 0 { + i -= len(m.BlockId) + copy(dAtA[i:], m.BlockId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BlockId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Report) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Report) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Report) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.TimeSeriesCompact != nil { + size, err := m.TimeSeriesCompact.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x4a + } + if m.Heatmap != nil { + size, err := m.Heatmap.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } + if m.Pprof != nil { + size, err := m.Pprof.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x3a + } + if m.Tree != nil { + size, err := m.Tree.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + if m.TimeSeries != nil { + size, err := m.TimeSeries.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + if m.SeriesLabels != nil { + size, err := m.SeriesLabels.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + if m.LabelValues != nil { + size, err := m.LabelValues.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if m.LabelNames != nil { + size, err := m.LabelNames.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.ReportType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ReportType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *LabelNamesQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LabelNamesQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *LabelNamesQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *LabelNamesReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LabelNamesReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *LabelNamesReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.LabelNames) > 0 { + for iNdEx := len(m.LabelNames) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.LabelNames[iNdEx]) + copy(dAtA[i:], m.LabelNames[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelNames[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LabelValuesQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LabelValuesQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *LabelValuesQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.LabelName) > 0 { + i -= len(m.LabelName) + copy(dAtA[i:], m.LabelName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LabelValuesReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LabelValuesReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *LabelValuesReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.LabelValues) > 0 { + for iNdEx := len(m.LabelValues) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.LabelValues[iNdEx]) + copy(dAtA[i:], m.LabelValues[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelValues[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SeriesLabelsQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SeriesLabelsQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *SeriesLabelsQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.LabelNames) > 0 { + for iNdEx := len(m.LabelNames) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.LabelNames[iNdEx]) + copy(dAtA[i:], m.LabelNames[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LabelNames[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *SeriesLabelsReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SeriesLabelsReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *SeriesLabelsReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.SeriesLabels) > 0 { + for iNdEx := len(m.SeriesLabels) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.SeriesLabels[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.SeriesLabels[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TimeSeriesQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TimeSeriesQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TimeSeriesQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.ExemplarType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ExemplarType)) + i-- + dAtA[i] = 0x20 + } + if m.Limit != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x18 + } + if len(m.GroupBy) > 0 { + for iNdEx := len(m.GroupBy) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.GroupBy[iNdEx]) + copy(dAtA[i:], m.GroupBy[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GroupBy[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Step != 0 { + i -= 8 + binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Step)))) + i-- + dAtA[i] = 0x9 + } + return len(dAtA) - i, nil +} + +func (m *TimeSeriesReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TimeSeriesReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TimeSeriesReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TimeSeries) > 0 { + for iNdEx := len(m.TimeSeries) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.TimeSeries[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.TimeSeries[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TreeQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TreeQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TreeQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.MaxUnresolvedLocations != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxUnresolvedLocations)) + i-- + dAtA[i] = 0x40 + } + if m.SymbolMode != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.SymbolMode)) + i-- + dAtA[i] = 0x38 + } + if len(m.TraceIdSelector) > 0 { + for iNdEx := len(m.TraceIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TraceIdSelector[iNdEx]) + copy(dAtA[i:], m.TraceIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TraceIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x32 + } + } + if m.FullSymbols { + i-- + if m.FullSymbols { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if len(m.ProfileIdSelector) > 0 { + for iNdEx := len(m.ProfileIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProfileIdSelector[iNdEx]) + copy(dAtA[i:], m.ProfileIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if m.StackTraceSelector != nil { + if vtmsg, ok := interface{}(m.StackTraceSelector).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.StackTraceSelector) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x1a + } + if len(m.SpanSelector) > 0 { + for iNdEx := len(m.SpanSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SpanSelector[iNdEx]) + copy(dAtA[i:], m.SpanSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpanSelector[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.MaxNodes != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxNodes)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TreeSymbols) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TreeSymbols) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TreeSymbols) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.StringHashes) > 0 { + var pksize2 int + for _, num := range m.StringHashes { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num := range m.StringHashes { + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x42 + } + if len(m.FunctionHashes) > 0 { + var pksize4 int + for _, num := range m.FunctionHashes { + pksize4 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize4 + j3 := i + for _, num := range m.FunctionHashes { + for num >= 1<<7 { + dAtA[j3] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j3++ + } + dAtA[j3] = uint8(num) + j3++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize4)) + i-- + dAtA[i] = 0x3a + } + if len(m.LocationHashes) > 0 { + var pksize6 int + for _, num := range m.LocationHashes { + pksize6 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize6 + j5 := i + for _, num := range m.LocationHashes { + for num >= 1<<7 { + dAtA[j5] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j5++ + } + dAtA[j5] = uint8(num) + j5++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize6)) + i-- + dAtA[i] = 0x32 + } + if len(m.MappingHashes) > 0 { + var pksize8 int + for _, num := range m.MappingHashes { + pksize8 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize8 + j7 := i + for _, num := range m.MappingHashes { + for num >= 1<<7 { + dAtA[j7] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j7++ + } + dAtA[j7] = uint8(num) + j7++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize8)) + i-- + dAtA[i] = 0x2a + } + if len(m.Strings) > 0 { + for iNdEx := len(m.Strings) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Strings[iNdEx]) + copy(dAtA[i:], m.Strings[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Strings[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.Functions) > 0 { + for iNdEx := len(m.Functions) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Functions[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Functions[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Locations) > 0 { + for iNdEx := len(m.Locations) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Locations[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Locations[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Mappings) > 0 { + for iNdEx := len(m.Mappings) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Mappings[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Mappings[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *SymbolRefTable) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SymbolRefTable) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *SymbolRefTable) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.UnresolvedAddress) > 0 { + var pksize2 int + for _, num := range m.UnresolvedAddress { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num := range m.UnresolvedAddress { + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x2a + } + if len(m.UnresolvedBuildId) > 0 { + var pksize4 int + for _, num := range m.UnresolvedBuildId { + pksize4 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize4 + j3 := i + for _, num := range m.UnresolvedBuildId { + for num >= 1<<7 { + dAtA[j3] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j3++ + } + dAtA[j3] = uint8(num) + j3++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize4)) + i-- + dAtA[i] = 0x22 + } + if len(m.BinaryNames) > 0 { + for iNdEx := len(m.BinaryNames) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.BinaryNames[iNdEx]) + copy(dAtA[i:], m.BinaryNames[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BinaryNames[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.BuildIds) > 0 { + for iNdEx := len(m.BuildIds) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.BuildIds[iNdEx]) + copy(dAtA[i:], m.BuildIds[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BuildIds[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Names) > 0 { + for iNdEx := len(m.Names) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Names[iNdEx]) + copy(dAtA[i:], m.Names[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Names[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *TreeReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TreeReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TreeReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.SymbolRefs != nil { + size, err := m.SymbolRefs.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + if m.Symbols != nil { + size, err := m.Symbols.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if len(m.Tree) > 0 { + i -= len(m.Tree) + copy(dAtA[i:], m.Tree) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tree))) + i-- + dAtA[i] = 0x12 + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PprofQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PprofQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PprofQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TraceIdSelector) > 0 { + for iNdEx := len(m.TraceIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TraceIdSelector[iNdEx]) + copy(dAtA[i:], m.TraceIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TraceIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.SpanSelector) > 0 { + for iNdEx := len(m.SpanSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SpanSelector[iNdEx]) + copy(dAtA[i:], m.SpanSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpanSelector[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.ProfileIdSelector) > 0 { + for iNdEx := len(m.ProfileIdSelector) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProfileIdSelector[iNdEx]) + copy(dAtA[i:], m.ProfileIdSelector[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileIdSelector[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.StackTraceSelector != nil { + if vtmsg, ok := interface{}(m.StackTraceSelector).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.StackTraceSelector) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + if m.MaxNodes != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxNodes)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *PprofReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PprofReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PprofReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Pprof) > 0 { + i -= len(m.Pprof) + copy(dAtA[i:], m.Pprof) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Pprof))) + i-- + dAtA[i] = 0x12 + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *HeatmapQuery) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HeatmapQuery) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *HeatmapQuery) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.ExemplarType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ExemplarType)) + i-- + dAtA[i] = 0x28 + } + if m.Limit != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x20 + } + if m.QueryType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.QueryType)) + i-- + dAtA[i] = 0x18 + } + if len(m.GroupBy) > 0 { + for iNdEx := len(m.GroupBy) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.GroupBy[iNdEx]) + copy(dAtA[i:], m.GroupBy[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GroupBy[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.Step != 0 { + i -= 8 + binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Step)))) + i-- + dAtA[i] = 0x9 + } + return len(dAtA) - i, nil +} + +func (m *AttributeTable) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AttributeTable) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AttributeTable) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Values) > 0 { + for iNdEx := len(m.Values) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Values[iNdEx]) + copy(dAtA[i:], m.Values[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Values[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Keys) > 0 { + for iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Keys[iNdEx]) + copy(dAtA[i:], m.Keys[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Keys[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *HeatmapPoint) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HeatmapPoint) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *HeatmapPoint) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TraceId) > 0 { + i -= len(m.TraceId) + copy(dAtA[i:], m.TraceId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TraceId))) + i-- + dAtA[i] = 0x32 + } + if len(m.AttributeRefs) > 0 { + var pksize2 int + for _, num := range m.AttributeRefs { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.AttributeRefs { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x2a + } + if m.Value != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Value)) + i-- + dAtA[i] = 0x20 + } + if m.SpanId != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.SpanId)) + i-- + dAtA[i] = 0x18 + } + if m.ProfileId != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProfileId)) + i-- + dAtA[i] = 0x10 + } + if m.Timestamp != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *HeatmapSeries) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HeatmapSeries) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *HeatmapSeries) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Points) > 0 { + for iNdEx := len(m.Points) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Points[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.AttributeRefs) > 0 { + var pksize2 int + for _, num := range m.AttributeRefs { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.AttributeRefs { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *HeatmapReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HeatmapReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *HeatmapReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.AttributeTable != nil { + size, err := m.AttributeTable.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if len(m.HeatmapSeries) > 0 { + for iNdEx := len(m.HeatmapSeries) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.HeatmapSeries[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Exemplar) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Exemplar) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Exemplar) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.AttributeRefs) > 0 { + var pksize2 int + for _, num := range m.AttributeRefs { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.AttributeRefs { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x2a + } + if m.Value != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Value)) + i-- + dAtA[i] = 0x20 + } + if len(m.SpanId) > 0 { + i -= len(m.SpanId) + copy(dAtA[i:], m.SpanId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpanId))) + i-- + dAtA[i] = 0x1a + } + if len(m.ProfileId) > 0 { + i -= len(m.ProfileId) + copy(dAtA[i:], m.ProfileId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileId))) + i-- + dAtA[i] = 0x12 + } + if m.Timestamp != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Point) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Point) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Point) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.AnnotationRefs) > 0 { + var pksize2 int + for _, num := range m.AnnotationRefs { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.AnnotationRefs { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x2a + } + if len(m.Exemplars) > 0 { + for iNdEx := len(m.Exemplars) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Exemplars[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + } + if m.Timestamp != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x10 + } + if m.Value != 0 { + i -= 8 + binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Value)))) + i-- + dAtA[i] = 0x9 + } + return len(dAtA) - i, nil +} + +func (m *Series) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Series) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Series) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Points) > 0 { + for iNdEx := len(m.Points) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Points[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.AttributeRefs) > 0 { + var pksize2 int + for _, num := range m.AttributeRefs { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.AttributeRefs { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TimeSeriesCompactReport) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TimeSeriesCompactReport) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TimeSeriesCompactReport) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.AttributeTable != nil { + size, err := m.AttributeTable.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if len(m.TimeSeries) > 0 { + for iNdEx := len(m.TimeSeries) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.TimeSeries[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if m.Query != nil { + size, err := m.Query.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.StartTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.StartTime)) + } + if m.EndTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.EndTime)) + } + l = len(m.LabelSelector) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Query) > 0 { + for _, e := range m.Query { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *QueryResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Reports) > 0 { + for _, e := range m.Reports { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *InvokeOptions) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SanitizeOnMerge { + n += 2 + } + if m.CollectDiagnostics { + n += 2 + } + n += len(m.unknownFields) + return n +} + +func (m *InvokeRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Tenant) > 0 { + for _, s := range m.Tenant { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.StartTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.StartTime)) + } + if m.EndTime != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.EndTime)) + } + l = len(m.LabelSelector) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Query) > 0 { + for _, e := range m.Query { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.QueryPlan != nil { + l = m.QueryPlan.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Options != nil { + l = m.Options.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *QueryPlan) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Root != nil { + l = m.Root.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *QueryNode) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Type)) + } + if len(m.Children) > 0 { + for _, e := range m.Children { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Blocks) > 0 { + for _, e := range m.Blocks { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *Query) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.QueryType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.QueryType)) + } + if m.LabelNames != nil { + l = m.LabelNames.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.LabelValues != nil { + l = m.LabelValues.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.SeriesLabels != nil { + l = m.SeriesLabels.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.TimeSeries != nil { + l = m.TimeSeries.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Tree != nil { + l = m.Tree.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Pprof != nil { + l = m.Pprof.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Heatmap != nil { + l = m.Heatmap.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.TimeSeriesCompact != nil { + l = m.TimeSeriesCompact.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *InvokeResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Reports) > 0 { + for _, e := range m.Reports { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Diagnostics != nil { + l = m.Diagnostics.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *Diagnostics) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.QueryPlan != nil { + l = m.QueryPlan.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.ExecutionNode != nil { + l = m.ExecutionNode.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *ExecutionNode) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Type)) + } + l = len(m.Executor) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.StartTimeNs != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.StartTimeNs)) + } + if m.EndTimeNs != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.EndTimeNs)) + } + if len(m.Children) > 0 { + for _, e := range m.Children { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Stats != nil { + l = m.Stats.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Error) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *ExecutionStats) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BlocksRead != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.BlocksRead)) + } + if m.DatasetsProcessed != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.DatasetsProcessed)) + } + if len(m.BlockExecutions) > 0 { + for _, e := range m.BlockExecutions { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.BytesFetched != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.BytesFetched)) + } + n += len(m.unknownFields) + return n +} + +func (m *BlockExecution) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.BlockId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.StartTimeNs != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.StartTimeNs)) + } + if m.EndTimeNs != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.EndTimeNs)) + } + if m.DatasetsProcessed != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.DatasetsProcessed)) + } + if m.Size != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Size)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + if m.CompactionLevel != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CompactionLevel)) + } + n += len(m.unknownFields) + return n +} + +func (m *Report) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ReportType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ReportType)) + } + if m.LabelNames != nil { + l = m.LabelNames.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.LabelValues != nil { + l = m.LabelValues.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.SeriesLabels != nil { + l = m.SeriesLabels.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.TimeSeries != nil { + l = m.TimeSeries.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Tree != nil { + l = m.Tree.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Pprof != nil { + l = m.Pprof.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Heatmap != nil { + l = m.Heatmap.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.TimeSeriesCompact != nil { + l = m.TimeSeriesCompact.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *LabelNamesQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *LabelNamesReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.LabelNames) > 0 { + for _, s := range m.LabelNames { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *LabelValuesQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.LabelName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *LabelValuesReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.LabelValues) > 0 { + for _, s := range m.LabelValues { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *SeriesLabelsQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.LabelNames) > 0 { + for _, s := range m.LabelNames { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *SeriesLabelsReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.SeriesLabels) > 0 { + for _, e := range m.SeriesLabels { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *TimeSeriesQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Step != 0 { + n += 9 + } + if len(m.GroupBy) > 0 { + for _, s := range m.GroupBy { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Limit != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Limit)) + } + if m.ExemplarType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ExemplarType)) + } + n += len(m.unknownFields) + return n +} + +func (m *TimeSeriesReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.TimeSeries) > 0 { + for _, e := range m.TimeSeries { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *TreeQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MaxNodes != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MaxNodes)) + } + if len(m.SpanSelector) > 0 { + for _, s := range m.SpanSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.StackTraceSelector != nil { + if size, ok := interface{}(m.StackTraceSelector).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.StackTraceSelector) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.ProfileIdSelector) > 0 { + for _, s := range m.ProfileIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.FullSymbols { + n += 2 + } + if len(m.TraceIdSelector) > 0 { + for _, s := range m.TraceIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.SymbolMode != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.SymbolMode)) + } + if m.MaxUnresolvedLocations != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MaxUnresolvedLocations)) + } + n += len(m.unknownFields) + return n +} + +func (m *TreeSymbols) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Mappings) > 0 { + for _, e := range m.Mappings { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Locations) > 0 { + for _, e := range m.Locations { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Functions) > 0 { + for _, e := range m.Functions { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Strings) > 0 { + for _, s := range m.Strings { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.MappingHashes) > 0 { + l = 0 + for _, e := range m.MappingHashes { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.LocationHashes) > 0 { + l = 0 + for _, e := range m.LocationHashes { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.FunctionHashes) > 0 { + l = 0 + for _, e := range m.FunctionHashes { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.StringHashes) > 0 { + l = 0 + for _, e := range m.StringHashes { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + n += len(m.unknownFields) + return n +} + +func (m *SymbolRefTable) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Names) > 0 { + for _, s := range m.Names { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.BuildIds) > 0 { + for _, s := range m.BuildIds { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.BinaryNames) > 0 { + for _, s := range m.BinaryNames { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.UnresolvedBuildId) > 0 { + l = 0 + for _, e := range m.UnresolvedBuildId { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.UnresolvedAddress) > 0 { + l = 0 + for _, e := range m.UnresolvedAddress { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + n += len(m.unknownFields) + return n +} + +func (m *TreeReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Tree) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Symbols != nil { + l = m.Symbols.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.SymbolRefs != nil { + l = m.SymbolRefs.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *PprofQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MaxNodes != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MaxNodes)) + } + if m.StackTraceSelector != nil { + if size, ok := interface{}(m.StackTraceSelector).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.StackTraceSelector) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.ProfileIdSelector) > 0 { + for _, s := range m.ProfileIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.SpanSelector) > 0 { + for _, s := range m.SpanSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.TraceIdSelector) > 0 { + for _, s := range m.TraceIdSelector { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *PprofReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Pprof) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *HeatmapQuery) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Step != 0 { + n += 9 + } + if len(m.GroupBy) > 0 { + for _, s := range m.GroupBy { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.QueryType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.QueryType)) + } + if m.Limit != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Limit)) + } + if m.ExemplarType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ExemplarType)) + } + n += len(m.unknownFields) + return n +} + +func (m *AttributeTable) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Keys) > 0 { + for _, s := range m.Keys { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Values) > 0 { + for _, s := range m.Values { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *HeatmapPoint) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Timestamp != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Timestamp)) + } + if m.ProfileId != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ProfileId)) + } + if m.SpanId != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.SpanId)) + } + if m.Value != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Value)) + } + if len(m.AttributeRefs) > 0 { + l = 0 + for _, e := range m.AttributeRefs { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + l = len(m.TraceId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *HeatmapSeries) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.AttributeRefs) > 0 { + l = 0 + for _, e := range m.AttributeRefs { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.Points) > 0 { + for _, e := range m.Points { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *HeatmapReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.HeatmapSeries) > 0 { + for _, e := range m.HeatmapSeries { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.AttributeTable != nil { + l = m.AttributeTable.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *Exemplar) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Timestamp != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Timestamp)) + } + l = len(m.ProfileId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.SpanId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Value != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Value)) + } + if len(m.AttributeRefs) > 0 { + l = 0 + for _, e := range m.AttributeRefs { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + n += len(m.unknownFields) + return n +} + +func (m *Point) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Value != 0 { + n += 9 + } + if m.Timestamp != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Timestamp)) + } + if len(m.Exemplars) > 0 { + for _, e := range m.Exemplars { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.AnnotationRefs) > 0 { + l = 0 + for _, e := range m.AnnotationRefs { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + n += len(m.unknownFields) + return n +} + +func (m *Series) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.AttributeRefs) > 0 { + l = 0 + for _, e := range m.AttributeRefs { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.Points) > 0 { + for _, e := range m.Points { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *TimeSeriesCompactReport) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Query != nil { + l = m.Query.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.TimeSeries) > 0 { + for _, e := range m.TimeSeries { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.AttributeTable != nil { + l = m.AttributeTable.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *QueryRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + m.EndTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelSelector = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = append(m.Query, &Query{}) + if err := m.Query[len(m.Query)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reports", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reports = append(m.Reports, &Report{}) + if err := m.Reports[len(m.Reports)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InvokeOptions) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InvokeOptions: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InvokeOptions: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SanitizeOnMerge", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SanitizeOnMerge = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CollectDiagnostics", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CollectDiagnostics = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InvokeRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InvokeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InvokeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenant = append(m.Tenant, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + m.EndTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelSelector = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = append(m.Query, &Query{}) + if err := m.Query[len(m.Query)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryPlan", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.QueryPlan == nil { + m.QueryPlan = &QueryPlan{} + } + if err := m.QueryPlan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Options", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Options == nil { + m.Options = &InvokeOptions{} + } + if err := m.Options.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryPlan) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryPlan: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPlan: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Root", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Root == nil { + m.Root = &QueryNode{} + } + if err := m.Root.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryNode) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryNode: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryNode: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= QueryNode_Type(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Children", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Children = append(m.Children, &QueryNode{}) + if err := m.Children[len(m.Children)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Blocks = append(m.Blocks, &v1.BlockMeta{}) + if unmarshal, ok := interface{}(m.Blocks[len(m.Blocks)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Blocks[len(m.Blocks)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Query) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Query: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Query: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryType", wireType) + } + m.QueryType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.QueryType |= QueryType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelNames", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.LabelNames == nil { + m.LabelNames = &LabelNamesQuery{} + } + if err := m.LabelNames.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelValues", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.LabelValues == nil { + m.LabelValues = &LabelValuesQuery{} + } + if err := m.LabelValues.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SeriesLabels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SeriesLabels == nil { + m.SeriesLabels = &SeriesLabelsQuery{} + } + if err := m.SeriesLabels.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeSeries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TimeSeries == nil { + m.TimeSeries = &TimeSeriesQuery{} + } + if err := m.TimeSeries.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tree", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Tree == nil { + m.Tree = &TreeQuery{} + } + if err := m.Tree.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pprof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pprof == nil { + m.Pprof = &PprofQuery{} + } + if err := m.Pprof.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Heatmap", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Heatmap == nil { + m.Heatmap = &HeatmapQuery{} + } + if err := m.Heatmap.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeSeriesCompact", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TimeSeriesCompact == nil { + m.TimeSeriesCompact = &TimeSeriesQuery{} + } + if err := m.TimeSeriesCompact.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InvokeResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InvokeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InvokeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reports", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reports = append(m.Reports, &Report{}) + if err := m.Reports[len(m.Reports)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Diagnostics", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Diagnostics == nil { + m.Diagnostics = &Diagnostics{} + } + if err := m.Diagnostics.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Diagnostics) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Diagnostics: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Diagnostics: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryPlan", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.QueryPlan == nil { + m.QueryPlan = &QueryPlan{} + } + if err := m.QueryPlan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionNode", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ExecutionNode == nil { + m.ExecutionNode = &ExecutionNode{} + } + if err := m.ExecutionNode.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ExecutionNode) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExecutionNode: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExecutionNode: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= QueryNode_Type(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Executor", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Executor = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTimeNs", wireType) + } + m.StartTimeNs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTimeNs |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTimeNs", wireType) + } + m.EndTimeNs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTimeNs |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Children", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Children = append(m.Children, &ExecutionNode{}) + if err := m.Children[len(m.Children)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Stats", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Stats == nil { + m.Stats = &ExecutionStats{} + } + if err := m.Stats.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Error = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ExecutionStats) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExecutionStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExecutionStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlocksRead", wireType) + } + m.BlocksRead = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlocksRead |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DatasetsProcessed", wireType) + } + m.DatasetsProcessed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DatasetsProcessed |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockExecutions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockExecutions = append(m.BlockExecutions, &BlockExecution{}) + if err := m.BlockExecutions[len(m.BlockExecutions)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BytesFetched", wireType) + } + m.BytesFetched = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BytesFetched |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlockExecution) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockExecution: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockExecution: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTimeNs", wireType) + } + m.StartTimeNs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTimeNs |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTimeNs", wireType) + } + m.EndTimeNs = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EndTimeNs |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DatasetsProcessed", wireType) + } + m.DatasetsProcessed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DatasetsProcessed |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) + } + m.Size = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CompactionLevel", wireType) + } + m.CompactionLevel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CompactionLevel |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Report) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Report: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Report: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReportType", wireType) + } + m.ReportType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReportType |= ReportType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelNames", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.LabelNames == nil { + m.LabelNames = &LabelNamesReport{} + } + if err := m.LabelNames.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelValues", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.LabelValues == nil { + m.LabelValues = &LabelValuesReport{} + } + if err := m.LabelValues.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SeriesLabels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SeriesLabels == nil { + m.SeriesLabels = &SeriesLabelsReport{} + } + if err := m.SeriesLabels.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeSeries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TimeSeries == nil { + m.TimeSeries = &TimeSeriesReport{} + } + if err := m.TimeSeries.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tree", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Tree == nil { + m.Tree = &TreeReport{} + } + if err := m.Tree.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pprof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pprof == nil { + m.Pprof = &PprofReport{} + } + if err := m.Pprof.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Heatmap", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Heatmap == nil { + m.Heatmap = &HeatmapReport{} + } + if err := m.Heatmap.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeSeriesCompact", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TimeSeriesCompact == nil { + m.TimeSeriesCompact = &TimeSeriesCompactReport{} + } + if err := m.TimeSeriesCompact.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LabelNamesQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LabelNamesQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LabelNamesQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LabelNamesReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LabelNamesReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LabelNamesReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &LabelNamesQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelNames", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelNames = append(m.LabelNames, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LabelValuesQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LabelValuesQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LabelValuesQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LabelValuesReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LabelValuesReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LabelValuesReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &LabelValuesQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelValues", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelValues = append(m.LabelValues, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SeriesLabelsQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SeriesLabelsQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SeriesLabelsQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelNames", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LabelNames = append(m.LabelNames, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SeriesLabelsReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SeriesLabelsReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SeriesLabelsReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &SeriesLabelsQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SeriesLabels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SeriesLabels = append(m.SeriesLabels, &v11.Labels{}) + if unmarshal, ok := interface{}(m.SeriesLabels[len(m.SeriesLabels)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.SeriesLabels[len(m.SeriesLabels)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TimeSeriesQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TimeSeriesQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TimeSeriesQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Step", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Step = float64(math.Float64frombits(v)) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupBy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GroupBy = append(m.GroupBy, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExemplarType", wireType) + } + m.ExemplarType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExemplarType |= v11.ExemplarType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TimeSeriesReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TimeSeriesReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TimeSeriesReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &TimeSeriesQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeSeries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TimeSeries = append(m.TimeSeries, &v11.Series{}) + if unmarshal, ok := interface{}(m.TimeSeries[len(m.TimeSeries)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.TimeSeries[len(m.TimeSeries)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TreeQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TreeQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TreeQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxNodes", wireType) + } + m.MaxNodes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxNodes |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpanSelector = append(m.SpanSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StackTraceSelector", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StackTraceSelector == nil { + m.StackTraceSelector = &v11.StackTraceSelector{} + } + if unmarshal, ok := interface{}(m.StackTraceSelector).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.StackTraceSelector); err != nil { + return err + } + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileIdSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileIdSelector = append(m.ProfileIdSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FullSymbols", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.FullSymbols = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TraceIdSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TraceIdSelector = append(m.TraceIdSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SymbolMode", wireType) + } + m.SymbolMode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SymbolMode |= SymbolMode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxUnresolvedLocations", wireType) + } + m.MaxUnresolvedLocations = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxUnresolvedLocations |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TreeSymbols) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TreeSymbols: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TreeSymbols: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Mappings", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Mappings = append(m.Mappings, &v12.Mapping{}) + if unmarshal, ok := interface{}(m.Mappings[len(m.Mappings)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Mappings[len(m.Mappings)-1]); err != nil { + return err + } + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Locations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Locations = append(m.Locations, &v12.Location{}) + if unmarshal, ok := interface{}(m.Locations[len(m.Locations)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Locations[len(m.Locations)-1]); err != nil { + return err + } + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Functions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Functions = append(m.Functions, &v12.Function{}) + if unmarshal, ok := interface{}(m.Functions[len(m.Functions)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Functions[len(m.Functions)-1]); err != nil { + return err + } + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Strings", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Strings = append(m.Strings, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MappingHashes = append(m.MappingHashes, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.MappingHashes) == 0 { + m.MappingHashes = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MappingHashes = append(m.MappingHashes, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field MappingHashes", wireType) + } + case 6: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.LocationHashes = append(m.LocationHashes, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.LocationHashes) == 0 { + m.LocationHashes = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.LocationHashes = append(m.LocationHashes, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field LocationHashes", wireType) + } + case 7: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.FunctionHashes = append(m.FunctionHashes, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.FunctionHashes) == 0 { + m.FunctionHashes = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.FunctionHashes = append(m.FunctionHashes, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field FunctionHashes", wireType) + } + case 8: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.StringHashes = append(m.StringHashes, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.StringHashes) == 0 { + m.StringHashes = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.StringHashes = append(m.StringHashes, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field StringHashes", wireType) + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SymbolRefTable) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SymbolRefTable: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SymbolRefTable: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Names", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Names = append(m.Names, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BuildIds", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BuildIds = append(m.BuildIds, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BinaryNames", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BinaryNames = append(m.BinaryNames, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType == 0 { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UnresolvedBuildId = append(m.UnresolvedBuildId, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.UnresolvedBuildId) == 0 { + m.UnresolvedBuildId = make([]uint32, 0, elementCount) + } + for iNdEx < postIndex { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UnresolvedBuildId = append(m.UnresolvedBuildId, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field UnresolvedBuildId", wireType) + } + case 5: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UnresolvedAddress = append(m.UnresolvedAddress, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.UnresolvedAddress) == 0 { + m.UnresolvedAddress = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UnresolvedAddress = append(m.UnresolvedAddress, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field UnresolvedAddress", wireType) + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TreeReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TreeReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TreeReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &TreeQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tree", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tree = append(m.Tree[:0], dAtA[iNdEx:postIndex]...) + if m.Tree == nil { + m.Tree = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Symbols", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Symbols == nil { + m.Symbols = &TreeSymbols{} + } + if err := m.Symbols.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SymbolRefs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SymbolRefs == nil { + m.SymbolRefs = &SymbolRefTable{} + } + if err := m.SymbolRefs.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PprofQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PprofQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PprofQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxNodes", wireType) + } + m.MaxNodes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxNodes |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StackTraceSelector", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StackTraceSelector == nil { + m.StackTraceSelector = &v11.StackTraceSelector{} + } + if unmarshal, ok := interface{}(m.StackTraceSelector).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.StackTraceSelector); err != nil { + return err + } + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileIdSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileIdSelector = append(m.ProfileIdSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpanSelector = append(m.SpanSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TraceIdSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TraceIdSelector = append(m.TraceIdSelector, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PprofReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PprofReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PprofReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &PprofQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pprof", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pprof = append(m.Pprof[:0], dAtA[iNdEx:postIndex]...) + if m.Pprof == nil { + m.Pprof = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeatmapQuery) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HeatmapQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeatmapQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Step", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Step = float64(math.Float64frombits(v)) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupBy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GroupBy = append(m.GroupBy, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryType", wireType) + } + m.QueryType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.QueryType |= v13.HeatmapQueryType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExemplarType", wireType) + } + m.ExemplarType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExemplarType |= v11.ExemplarType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AttributeTable) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AttributeTable: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AttributeTable: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Keys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Keys = append(m.Keys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Values = append(m.Values, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeatmapPoint) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HeatmapPoint: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeatmapPoint: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileId", wireType) + } + m.ProfileId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProfileId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) + } + m.SpanId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SpanId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + m.Value = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Value |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType == 0 { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.AttributeRefs) == 0 { + m.AttributeRefs = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field AttributeRefs", wireType) + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TraceId = append(m.TraceId[:0], dAtA[iNdEx:postIndex]...) + if m.TraceId == nil { + m.TraceId = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeatmapSeries) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HeatmapSeries: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeatmapSeries: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.AttributeRefs) == 0 { + m.AttributeRefs = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field AttributeRefs", wireType) + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Points", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Points = append(m.Points, &HeatmapPoint{}) + if err := m.Points[len(m.Points)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeatmapReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HeatmapReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeatmapReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &HeatmapQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HeatmapSeries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HeatmapSeries = append(m.HeatmapSeries, &HeatmapSeries{}) + if err := m.HeatmapSeries[len(m.HeatmapSeries)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AttributeTable", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.AttributeTable == nil { + m.AttributeTable = &AttributeTable{} + } + if err := m.AttributeTable.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Exemplar) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Exemplar: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Exemplar: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpanId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + m.Value = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Value |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType == 0 { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.AttributeRefs) == 0 { + m.AttributeRefs = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field AttributeRefs", wireType) + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Point) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Point: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Point: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Value = float64(math.Float64frombits(v)) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Exemplars", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Exemplars = append(m.Exemplars, &Exemplar{}) + if err := m.Exemplars[len(m.Exemplars)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType == 0 { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AnnotationRefs = append(m.AnnotationRefs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.AnnotationRefs) == 0 { + m.AnnotationRefs = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AnnotationRefs = append(m.AnnotationRefs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field AnnotationRefs", wireType) + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Series) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Series: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Series: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.AttributeRefs) == 0 { + m.AttributeRefs = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AttributeRefs = append(m.AttributeRefs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field AttributeRefs", wireType) + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Points", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Points = append(m.Points, &Point{}) + if err := m.Points[len(m.Points)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TimeSeriesCompactReport) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TimeSeriesCompactReport: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TimeSeriesCompactReport: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Query == nil { + m.Query = &TimeSeriesQuery{} + } + if err := m.Query.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeSeries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TimeSeries = append(m.TimeSeries, &Series{}) + if err := m.TimeSeries[len(m.TimeSeries)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AttributeTable", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.AttributeTable == nil { + m.AttributeTable = &AttributeTable{} + } + if err := m.AttributeTable.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/query/v1/queryv1connect/query.connect.go b/api/gen/proto/go/query/v1/queryv1connect/query.connect.go new file mode 100644 index 0000000000..631b1cf2a2 --- /dev/null +++ b/api/gen/proto/go/query/v1/queryv1connect/query.connect.go @@ -0,0 +1,184 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: query/v1/query.proto + +package queryv1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // QueryFrontendServiceName is the fully-qualified name of the QueryFrontendService service. + QueryFrontendServiceName = "query.v1.QueryFrontendService" + // QueryBackendServiceName is the fully-qualified name of the QueryBackendService service. + QueryBackendServiceName = "query.v1.QueryBackendService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // QueryFrontendServiceQueryProcedure is the fully-qualified name of the QueryFrontendService's + // Query RPC. + QueryFrontendServiceQueryProcedure = "/query.v1.QueryFrontendService/Query" + // QueryBackendServiceInvokeProcedure is the fully-qualified name of the QueryBackendService's + // Invoke RPC. + QueryBackendServiceInvokeProcedure = "/query.v1.QueryBackendService/Invoke" +) + +// QueryFrontendServiceClient is a client for the query.v1.QueryFrontendService service. +type QueryFrontendServiceClient interface { + Query(context.Context, *connect.Request[v1.QueryRequest]) (*connect.Response[v1.QueryResponse], error) +} + +// NewQueryFrontendServiceClient constructs a client for the query.v1.QueryFrontendService service. +// By default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped +// responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewQueryFrontendServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) QueryFrontendServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + queryFrontendServiceMethods := v1.File_query_v1_query_proto.Services().ByName("QueryFrontendService").Methods() + return &queryFrontendServiceClient{ + query: connect.NewClient[v1.QueryRequest, v1.QueryResponse]( + httpClient, + baseURL+QueryFrontendServiceQueryProcedure, + connect.WithSchema(queryFrontendServiceMethods.ByName("Query")), + connect.WithClientOptions(opts...), + ), + } +} + +// queryFrontendServiceClient implements QueryFrontendServiceClient. +type queryFrontendServiceClient struct { + query *connect.Client[v1.QueryRequest, v1.QueryResponse] +} + +// Query calls query.v1.QueryFrontendService.Query. +func (c *queryFrontendServiceClient) Query(ctx context.Context, req *connect.Request[v1.QueryRequest]) (*connect.Response[v1.QueryResponse], error) { + return c.query.CallUnary(ctx, req) +} + +// QueryFrontendServiceHandler is an implementation of the query.v1.QueryFrontendService service. +type QueryFrontendServiceHandler interface { + Query(context.Context, *connect.Request[v1.QueryRequest]) (*connect.Response[v1.QueryResponse], error) +} + +// NewQueryFrontendServiceHandler builds an HTTP handler from the service implementation. It returns +// the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewQueryFrontendServiceHandler(svc QueryFrontendServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + queryFrontendServiceMethods := v1.File_query_v1_query_proto.Services().ByName("QueryFrontendService").Methods() + queryFrontendServiceQueryHandler := connect.NewUnaryHandler( + QueryFrontendServiceQueryProcedure, + svc.Query, + connect.WithSchema(queryFrontendServiceMethods.ByName("Query")), + connect.WithHandlerOptions(opts...), + ) + return "/query.v1.QueryFrontendService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case QueryFrontendServiceQueryProcedure: + queryFrontendServiceQueryHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedQueryFrontendServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedQueryFrontendServiceHandler struct{} + +func (UnimplementedQueryFrontendServiceHandler) Query(context.Context, *connect.Request[v1.QueryRequest]) (*connect.Response[v1.QueryResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("query.v1.QueryFrontendService.Query is not implemented")) +} + +// QueryBackendServiceClient is a client for the query.v1.QueryBackendService service. +type QueryBackendServiceClient interface { + Invoke(context.Context, *connect.Request[v1.InvokeRequest]) (*connect.Response[v1.InvokeResponse], error) +} + +// NewQueryBackendServiceClient constructs a client for the query.v1.QueryBackendService service. By +// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, +// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewQueryBackendServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) QueryBackendServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + queryBackendServiceMethods := v1.File_query_v1_query_proto.Services().ByName("QueryBackendService").Methods() + return &queryBackendServiceClient{ + invoke: connect.NewClient[v1.InvokeRequest, v1.InvokeResponse]( + httpClient, + baseURL+QueryBackendServiceInvokeProcedure, + connect.WithSchema(queryBackendServiceMethods.ByName("Invoke")), + connect.WithClientOptions(opts...), + ), + } +} + +// queryBackendServiceClient implements QueryBackendServiceClient. +type queryBackendServiceClient struct { + invoke *connect.Client[v1.InvokeRequest, v1.InvokeResponse] +} + +// Invoke calls query.v1.QueryBackendService.Invoke. +func (c *queryBackendServiceClient) Invoke(ctx context.Context, req *connect.Request[v1.InvokeRequest]) (*connect.Response[v1.InvokeResponse], error) { + return c.invoke.CallUnary(ctx, req) +} + +// QueryBackendServiceHandler is an implementation of the query.v1.QueryBackendService service. +type QueryBackendServiceHandler interface { + Invoke(context.Context, *connect.Request[v1.InvokeRequest]) (*connect.Response[v1.InvokeResponse], error) +} + +// NewQueryBackendServiceHandler builds an HTTP handler from the service implementation. It returns +// the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewQueryBackendServiceHandler(svc QueryBackendServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + queryBackendServiceMethods := v1.File_query_v1_query_proto.Services().ByName("QueryBackendService").Methods() + queryBackendServiceInvokeHandler := connect.NewUnaryHandler( + QueryBackendServiceInvokeProcedure, + svc.Invoke, + connect.WithSchema(queryBackendServiceMethods.ByName("Invoke")), + connect.WithHandlerOptions(opts...), + ) + return "/query.v1.QueryBackendService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case QueryBackendServiceInvokeProcedure: + queryBackendServiceInvokeHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedQueryBackendServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedQueryBackendServiceHandler struct{} + +func (UnimplementedQueryBackendServiceHandler) Invoke(context.Context, *connect.Request[v1.InvokeRequest]) (*connect.Response[v1.InvokeResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("query.v1.QueryBackendService.Invoke is not implemented")) +} diff --git a/api/gen/proto/go/query/v1/queryv1connect/query.connect.mux.go b/api/gen/proto/go/query/v1/queryv1connect/query.connect.mux.go new file mode 100644 index 0000000000..f57faef705 --- /dev/null +++ b/api/gen/proto/go/query/v1/queryv1connect/query.connect.mux.go @@ -0,0 +1,37 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: query/v1/query.proto + +package queryv1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterQueryFrontendServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterQueryFrontendServiceHandler(mux *mux.Router, svc QueryFrontendServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/query.v1.QueryFrontendService/Query", connect.NewUnaryHandler( + "/query.v1.QueryFrontendService/Query", + svc.Query, + opts..., + )) +} + +// RegisterQueryBackendServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterQueryBackendServiceHandler(mux *mux.Router, svc QueryBackendServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/query.v1.QueryBackendService/Invoke", connect.NewUnaryHandler( + "/query.v1.QueryBackendService/Invoke", + svc.Invoke, + opts..., + )) +} diff --git a/api/gen/proto/go/segmentwriter/v1/push.pb.go b/api/gen/proto/go/segmentwriter/v1/push.pb.go new file mode 100644 index 0000000000..bbc90c1ae6 --- /dev/null +++ b/api/gen/proto/go/segmentwriter/v1/push.pb.go @@ -0,0 +1,222 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: segmentwriter/v1/push.proto + +package segmentwriterv1 + +import ( + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PushResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PushResponse) Reset() { + *x = PushResponse{} + mi := &file_segmentwriter_v1_push_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PushResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushResponse) ProtoMessage() {} + +func (x *PushResponse) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_v1_push_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushResponse.ProtoReflect.Descriptor instead. +func (*PushResponse) Descriptor() ([]byte, []int) { + return file_segmentwriter_v1_push_proto_rawDescGZIP(), []int{0} +} + +type PushRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Unique identifier for the tenant submitting the request. + TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + // Label KV pairs of the series the profile belongs to. + Labels []*v1.LabelPair `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty"` + // Profile data in binary format. Default format is pprof. + Profile []byte `protobuf:"bytes,4,opt,name=profile,proto3" json:"profile,omitempty"` + // Unique identifier of the profile. + ProfileId []byte `protobuf:"bytes,5,opt,name=profile_id,json=profileId,proto3" json:"profile_id,omitempty"` + // Shard identifier the profile belongs to. + Shard uint32 `protobuf:"varint,6,opt,name=shard,proto3" json:"shard,omitempty"` + // Profile annotations with additional metadata. + Annotations []*v1.ProfileAnnotation `protobuf:"bytes,7,rep,name=annotations,proto3" json:"annotations,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PushRequest) Reset() { + *x = PushRequest{} + mi := &file_segmentwriter_v1_push_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PushRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushRequest) ProtoMessage() {} + +func (x *PushRequest) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_v1_push_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushRequest.ProtoReflect.Descriptor instead. +func (*PushRequest) Descriptor() ([]byte, []int) { + return file_segmentwriter_v1_push_proto_rawDescGZIP(), []int{1} +} + +func (x *PushRequest) GetTenantId() string { + if x != nil { + return x.TenantId + } + return "" +} + +func (x *PushRequest) GetLabels() []*v1.LabelPair { + if x != nil { + return x.Labels + } + return nil +} + +func (x *PushRequest) GetProfile() []byte { + if x != nil { + return x.Profile + } + return nil +} + +func (x *PushRequest) GetProfileId() []byte { + if x != nil { + return x.ProfileId + } + return nil +} + +func (x *PushRequest) GetShard() uint32 { + if x != nil { + return x.Shard + } + return 0 +} + +func (x *PushRequest) GetAnnotations() []*v1.ProfileAnnotation { + if x != nil { + return x.Annotations + } + return nil +} + +var File_segmentwriter_v1_push_proto protoreflect.FileDescriptor + +const file_segmentwriter_v1_push_proto_rawDesc = "" + + "\n" + + "\x1bsegmentwriter/v1/push.proto\x12\x10segmentwriter.v1\x1a\x14types/v1/types.proto\"\x0e\n" + + "\fPushResponse\"\xeb\x01\n" + + "\vPushRequest\x12\x1b\n" + + "\ttenant_id\x18\x01 \x01(\tR\btenantId\x12+\n" + + "\x06labels\x18\x02 \x03(\v2\x13.types.v1.LabelPairR\x06labels\x12\x18\n" + + "\aprofile\x18\x04 \x01(\fR\aprofile\x12\x1d\n" + + "\n" + + "profile_id\x18\x05 \x01(\fR\tprofileId\x12\x14\n" + + "\x05shard\x18\x06 \x01(\rR\x05shard\x12=\n" + + "\vannotations\x18\a \x03(\v2\x1b.types.v1.ProfileAnnotationR\vannotationsJ\x04\b\x03\x10\x042_\n" + + "\x14SegmentWriterService\x12G\n" + + "\x04Push\x12\x1d.segmentwriter.v1.PushRequest\x1a\x1e.segmentwriter.v1.PushResponse\"\x00B\xd2\x01\n" + + "\x14com.segmentwriter.v1B\tPushProtoP\x01ZNgithub.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1;segmentwriterv1\xa2\x02\x03SXX\xaa\x02\x10Segmentwriter.V1\xca\x02\x10Segmentwriter\\V1\xe2\x02\x1cSegmentwriter\\V1\\GPBMetadata\xea\x02\x11Segmentwriter::V1b\x06proto3" + +var ( + file_segmentwriter_v1_push_proto_rawDescOnce sync.Once + file_segmentwriter_v1_push_proto_rawDescData []byte +) + +func file_segmentwriter_v1_push_proto_rawDescGZIP() []byte { + file_segmentwriter_v1_push_proto_rawDescOnce.Do(func() { + file_segmentwriter_v1_push_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_segmentwriter_v1_push_proto_rawDesc), len(file_segmentwriter_v1_push_proto_rawDesc))) + }) + return file_segmentwriter_v1_push_proto_rawDescData +} + +var file_segmentwriter_v1_push_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_segmentwriter_v1_push_proto_goTypes = []any{ + (*PushResponse)(nil), // 0: segmentwriter.v1.PushResponse + (*PushRequest)(nil), // 1: segmentwriter.v1.PushRequest + (*v1.LabelPair)(nil), // 2: types.v1.LabelPair + (*v1.ProfileAnnotation)(nil), // 3: types.v1.ProfileAnnotation +} +var file_segmentwriter_v1_push_proto_depIdxs = []int32{ + 2, // 0: segmentwriter.v1.PushRequest.labels:type_name -> types.v1.LabelPair + 3, // 1: segmentwriter.v1.PushRequest.annotations:type_name -> types.v1.ProfileAnnotation + 1, // 2: segmentwriter.v1.SegmentWriterService.Push:input_type -> segmentwriter.v1.PushRequest + 0, // 3: segmentwriter.v1.SegmentWriterService.Push:output_type -> segmentwriter.v1.PushResponse + 3, // [3:4] is the sub-list for method output_type + 2, // [2:3] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_segmentwriter_v1_push_proto_init() } +func file_segmentwriter_v1_push_proto_init() { + if File_segmentwriter_v1_push_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_segmentwriter_v1_push_proto_rawDesc), len(file_segmentwriter_v1_push_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_segmentwriter_v1_push_proto_goTypes, + DependencyIndexes: file_segmentwriter_v1_push_proto_depIdxs, + MessageInfos: file_segmentwriter_v1_push_proto_msgTypes, + }.Build() + File_segmentwriter_v1_push_proto = out.File + file_segmentwriter_v1_push_proto_goTypes = nil + file_segmentwriter_v1_push_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/segmentwriter/v1/push_vtproto.pb.go b/api/gen/proto/go/segmentwriter/v1/push_vtproto.pb.go new file mode 100644 index 0000000000..09ab9e15dd --- /dev/null +++ b/api/gen/proto/go/segmentwriter/v1/push_vtproto.pb.go @@ -0,0 +1,776 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: segmentwriter/v1/push.proto + +package segmentwriterv1 + +import ( + context "context" + fmt "fmt" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *PushResponse) CloneVT() *PushResponse { + if m == nil { + return (*PushResponse)(nil) + } + r := new(PushResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *PushResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *PushRequest) CloneVT() *PushRequest { + if m == nil { + return (*PushRequest)(nil) + } + r := new(PushRequest) + r.TenantId = m.TenantId + r.Shard = m.Shard + if rhs := m.Labels; rhs != nil { + tmpContainer := make([]*v1.LabelPair, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.LabelPair }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.LabelPair) + } + } + r.Labels = tmpContainer + } + if rhs := m.Profile; rhs != nil { + tmpBytes := make([]byte, len(rhs)) + copy(tmpBytes, rhs) + r.Profile = tmpBytes + } + if rhs := m.ProfileId; rhs != nil { + tmpBytes := make([]byte, len(rhs)) + copy(tmpBytes, rhs) + r.ProfileId = tmpBytes + } + if rhs := m.Annotations; rhs != nil { + tmpContainer := make([]*v1.ProfileAnnotation, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.ProfileAnnotation }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.ProfileAnnotation) + } + } + r.Annotations = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *PushRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *PushResponse) EqualVT(that *PushResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *PushResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*PushResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *PushRequest) EqualVT(that *PushRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.TenantId != that.TenantId { + return false + } + if len(this.Labels) != len(that.Labels) { + return false + } + for i, vx := range this.Labels { + vy := that.Labels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.LabelPair{} + } + if q == nil { + q = &v1.LabelPair{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.LabelPair) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + if string(this.Profile) != string(that.Profile) { + return false + } + if string(this.ProfileId) != string(that.ProfileId) { + return false + } + if this.Shard != that.Shard { + return false + } + if len(this.Annotations) != len(that.Annotations) { + return false + } + for i, vx := range this.Annotations { + vy := that.Annotations[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.ProfileAnnotation{} + } + if q == nil { + q = &v1.ProfileAnnotation{} + } + if equal, ok := interface{}(p).(interface { + EqualVT(*v1.ProfileAnnotation) bool + }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *PushRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*PushRequest) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// SegmentWriterServiceClient is the client API for SegmentWriterService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type SegmentWriterServiceClient interface { + Push(ctx context.Context, in *PushRequest, opts ...grpc.CallOption) (*PushResponse, error) +} + +type segmentWriterServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewSegmentWriterServiceClient(cc grpc.ClientConnInterface) SegmentWriterServiceClient { + return &segmentWriterServiceClient{cc} +} + +func (c *segmentWriterServiceClient) Push(ctx context.Context, in *PushRequest, opts ...grpc.CallOption) (*PushResponse, error) { + out := new(PushResponse) + err := c.cc.Invoke(ctx, "/segmentwriter.v1.SegmentWriterService/Push", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SegmentWriterServiceServer is the server API for SegmentWriterService service. +// All implementations must embed UnimplementedSegmentWriterServiceServer +// for forward compatibility +type SegmentWriterServiceServer interface { + Push(context.Context, *PushRequest) (*PushResponse, error) + mustEmbedUnimplementedSegmentWriterServiceServer() +} + +// UnimplementedSegmentWriterServiceServer must be embedded to have forward compatible implementations. +type UnimplementedSegmentWriterServiceServer struct { +} + +func (UnimplementedSegmentWriterServiceServer) Push(context.Context, *PushRequest) (*PushResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Push not implemented") +} +func (UnimplementedSegmentWriterServiceServer) mustEmbedUnimplementedSegmentWriterServiceServer() {} + +// UnsafeSegmentWriterServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to SegmentWriterServiceServer will +// result in compilation errors. +type UnsafeSegmentWriterServiceServer interface { + mustEmbedUnimplementedSegmentWriterServiceServer() +} + +func RegisterSegmentWriterServiceServer(s grpc.ServiceRegistrar, srv SegmentWriterServiceServer) { + s.RegisterService(&SegmentWriterService_ServiceDesc, srv) +} + +func _SegmentWriterService_Push_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PushRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SegmentWriterServiceServer).Push(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/segmentwriter.v1.SegmentWriterService/Push", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SegmentWriterServiceServer).Push(ctx, req.(*PushRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// SegmentWriterService_ServiceDesc is the grpc.ServiceDesc for SegmentWriterService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var SegmentWriterService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "segmentwriter.v1.SegmentWriterService", + HandlerType: (*SegmentWriterServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Push", + Handler: _SegmentWriterService_Push_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "segmentwriter/v1/push.proto", +} + +func (m *PushResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PushResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PushResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *PushRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PushRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PushRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Annotations) > 0 { + for iNdEx := len(m.Annotations) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Annotations[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Annotations[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x3a + } + } + if m.Shard != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shard)) + i-- + dAtA[i] = 0x30 + } + if len(m.ProfileId) > 0 { + i -= len(m.ProfileId) + copy(dAtA[i:], m.ProfileId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileId))) + i-- + dAtA[i] = 0x2a + } + if len(m.Profile) > 0 { + i -= len(m.Profile) + copy(dAtA[i:], m.Profile) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Profile))) + i-- + dAtA[i] = 0x22 + } + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.Labels[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Labels[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.TenantId) > 0 { + i -= len(m.TenantId) + copy(dAtA[i:], m.TenantId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PushResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *PushRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TenantId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Labels) > 0 { + for _, e := range m.Labels { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + l = len(m.Profile) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.ProfileId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Shard != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Shard)) + } + if len(m.Annotations) > 0 { + for _, e := range m.Annotations { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *PushResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PushResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PushResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PushRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PushRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PushRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Labels = append(m.Labels, &v1.LabelPair{}) + if unmarshal, ok := interface{}(m.Labels[len(m.Labels)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Labels[len(m.Labels)-1]); err != nil { + return err + } + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Profile", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Profile = append(m.Profile[:0], dAtA[iNdEx:postIndex]...) + if m.Profile == nil { + m.Profile = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileId = append(m.ProfileId[:0], dAtA[iNdEx:postIndex]...) + if m.ProfileId == nil { + m.ProfileId = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + m.Shard = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shard |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Annotations = append(m.Annotations, &v1.ProfileAnnotation{}) + if unmarshal, ok := interface{}(m.Annotations[len(m.Annotations)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Annotations[len(m.Annotations)-1]); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/segmentwriter/v1/segmentwriterv1connect/push.connect.go b/api/gen/proto/go/segmentwriter/v1/segmentwriterv1connect/push.connect.go new file mode 100644 index 0000000000..fe3bf9e9de --- /dev/null +++ b/api/gen/proto/go/segmentwriter/v1/segmentwriterv1connect/push.connect.go @@ -0,0 +1,110 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: segmentwriter/v1/push.proto + +package segmentwriterv1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // SegmentWriterServiceName is the fully-qualified name of the SegmentWriterService service. + SegmentWriterServiceName = "segmentwriter.v1.SegmentWriterService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // SegmentWriterServicePushProcedure is the fully-qualified name of the SegmentWriterService's Push + // RPC. + SegmentWriterServicePushProcedure = "/segmentwriter.v1.SegmentWriterService/Push" +) + +// SegmentWriterServiceClient is a client for the segmentwriter.v1.SegmentWriterService service. +type SegmentWriterServiceClient interface { + Push(context.Context, *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) +} + +// NewSegmentWriterServiceClient constructs a client for the segmentwriter.v1.SegmentWriterService +// service. By default, it uses the Connect protocol with the binary Protobuf Codec, asks for +// gzipped responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply +// the connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewSegmentWriterServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) SegmentWriterServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + segmentWriterServiceMethods := v1.File_segmentwriter_v1_push_proto.Services().ByName("SegmentWriterService").Methods() + return &segmentWriterServiceClient{ + push: connect.NewClient[v1.PushRequest, v1.PushResponse]( + httpClient, + baseURL+SegmentWriterServicePushProcedure, + connect.WithSchema(segmentWriterServiceMethods.ByName("Push")), + connect.WithClientOptions(opts...), + ), + } +} + +// segmentWriterServiceClient implements SegmentWriterServiceClient. +type segmentWriterServiceClient struct { + push *connect.Client[v1.PushRequest, v1.PushResponse] +} + +// Push calls segmentwriter.v1.SegmentWriterService.Push. +func (c *segmentWriterServiceClient) Push(ctx context.Context, req *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) { + return c.push.CallUnary(ctx, req) +} + +// SegmentWriterServiceHandler is an implementation of the segmentwriter.v1.SegmentWriterService +// service. +type SegmentWriterServiceHandler interface { + Push(context.Context, *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) +} + +// NewSegmentWriterServiceHandler builds an HTTP handler from the service implementation. It returns +// the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewSegmentWriterServiceHandler(svc SegmentWriterServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + segmentWriterServiceMethods := v1.File_segmentwriter_v1_push_proto.Services().ByName("SegmentWriterService").Methods() + segmentWriterServicePushHandler := connect.NewUnaryHandler( + SegmentWriterServicePushProcedure, + svc.Push, + connect.WithSchema(segmentWriterServiceMethods.ByName("Push")), + connect.WithHandlerOptions(opts...), + ) + return "/segmentwriter.v1.SegmentWriterService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case SegmentWriterServicePushProcedure: + segmentWriterServicePushHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedSegmentWriterServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedSegmentWriterServiceHandler struct{} + +func (UnimplementedSegmentWriterServiceHandler) Push(context.Context, *connect.Request[v1.PushRequest]) (*connect.Response[v1.PushResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("segmentwriter.v1.SegmentWriterService.Push is not implemented")) +} diff --git a/api/gen/proto/go/segmentwriter/v1/segmentwriterv1connect/push.connect.mux.go b/api/gen/proto/go/segmentwriter/v1/segmentwriterv1connect/push.connect.mux.go new file mode 100644 index 0000000000..a335402be4 --- /dev/null +++ b/api/gen/proto/go/segmentwriter/v1/segmentwriterv1connect/push.connect.mux.go @@ -0,0 +1,27 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: segmentwriter/v1/push.proto + +package segmentwriterv1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterSegmentWriterServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterSegmentWriterServiceHandler(mux *mux.Router, svc SegmentWriterServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/segmentwriter.v1.SegmentWriterService/Push", connect.NewUnaryHandler( + "/segmentwriter.v1.SegmentWriterService/Push", + svc.Push, + opts..., + )) +} diff --git a/api/gen/proto/go/settings/v1/recording_rules.pb.go b/api/gen/proto/go/settings/v1/recording_rules.pb.go new file mode 100644 index 0000000000..54630102b0 --- /dev/null +++ b/api/gen/proto/go/settings/v1/recording_rules.pb.go @@ -0,0 +1,997 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: settings/v1/recording_rules.proto + +package settingsv1 + +import ( + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type MetricType int32 + +const ( + MetricType_TOTAL MetricType = 0 +) + +// Enum value maps for MetricType. +var ( + MetricType_name = map[int32]string{ + 0: "TOTAL", + } + MetricType_value = map[string]int32{ + "TOTAL": 0, + } +) + +func (x MetricType) Enum() *MetricType { + p := new(MetricType) + *p = x + return p +} + +func (x MetricType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (MetricType) Descriptor() protoreflect.EnumDescriptor { + return file_settings_v1_recording_rules_proto_enumTypes[0].Descriptor() +} + +func (MetricType) Type() protoreflect.EnumType { + return &file_settings_v1_recording_rules_proto_enumTypes[0] +} + +func (x MetricType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MetricType.Descriptor instead. +func (MetricType) EnumDescriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{0} +} + +type GetRecordingRuleRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetRecordingRuleRequest) Reset() { + *x = GetRecordingRuleRequest{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRecordingRuleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRecordingRuleRequest) ProtoMessage() {} + +func (x *GetRecordingRuleRequest) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRecordingRuleRequest.ProtoReflect.Descriptor instead. +func (*GetRecordingRuleRequest) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{0} +} + +func (x *GetRecordingRuleRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetRecordingRuleResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Rule *RecordingRule `protobuf:"bytes,1,opt,name=rule,proto3" json:"rule,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetRecordingRuleResponse) Reset() { + *x = GetRecordingRuleResponse{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetRecordingRuleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRecordingRuleResponse) ProtoMessage() {} + +func (x *GetRecordingRuleResponse) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRecordingRuleResponse.ProtoReflect.Descriptor instead. +func (*GetRecordingRuleResponse) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{1} +} + +func (x *GetRecordingRuleResponse) GetRule() *RecordingRule { + if x != nil { + return x.Rule + } + return nil +} + +type ListRecordingRulesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListRecordingRulesRequest) Reset() { + *x = ListRecordingRulesRequest{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListRecordingRulesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRecordingRulesRequest) ProtoMessage() {} + +func (x *ListRecordingRulesRequest) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListRecordingRulesRequest.ProtoReflect.Descriptor instead. +func (*ListRecordingRulesRequest) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{2} +} + +type ListRecordingRulesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Rules []*RecordingRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListRecordingRulesResponse) Reset() { + *x = ListRecordingRulesResponse{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListRecordingRulesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRecordingRulesResponse) ProtoMessage() {} + +func (x *ListRecordingRulesResponse) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListRecordingRulesResponse.ProtoReflect.Descriptor instead. +func (*ListRecordingRulesResponse) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{3} +} + +func (x *ListRecordingRulesResponse) GetRules() []*RecordingRule { + if x != nil { + return x.Rules + } + return nil +} + +type UpsertRecordingRuleRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The unique id of the recording rule. If an id is not provided, this will + // create a new recording rule. If an id is provided, it will replace the + // existing recording rule. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + MetricName string `protobuf:"bytes,2,opt,name=metric_name,json=metricName,proto3" json:"metric_name,omitempty"` + Matchers []string `protobuf:"bytes,3,rep,name=matchers,proto3" json:"matchers,omitempty"` + GroupBy []string `protobuf:"bytes,4,rep,name=group_by,json=groupBy,proto3" json:"group_by,omitempty"` + ExternalLabels []*v1.LabelPair `protobuf:"bytes,5,rep,name=external_labels,json=externalLabels,proto3" json:"external_labels,omitempty"` + // The observed generation of this recording rule. If this value does not + // match the generation stored in the database, this upsert will be rejected. + Generation int64 `protobuf:"varint,6,opt,name=generation,proto3" json:"generation,omitempty"` + StacktraceFilter *StacktraceFilter `protobuf:"bytes,7,opt,name=stacktrace_filter,json=stacktraceFilter,proto3,oneof" json:"stacktrace_filter,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpsertRecordingRuleRequest) Reset() { + *x = UpsertRecordingRuleRequest{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpsertRecordingRuleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertRecordingRuleRequest) ProtoMessage() {} + +func (x *UpsertRecordingRuleRequest) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpsertRecordingRuleRequest.ProtoReflect.Descriptor instead. +func (*UpsertRecordingRuleRequest) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{4} +} + +func (x *UpsertRecordingRuleRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpsertRecordingRuleRequest) GetMetricName() string { + if x != nil { + return x.MetricName + } + return "" +} + +func (x *UpsertRecordingRuleRequest) GetMatchers() []string { + if x != nil { + return x.Matchers + } + return nil +} + +func (x *UpsertRecordingRuleRequest) GetGroupBy() []string { + if x != nil { + return x.GroupBy + } + return nil +} + +func (x *UpsertRecordingRuleRequest) GetExternalLabels() []*v1.LabelPair { + if x != nil { + return x.ExternalLabels + } + return nil +} + +func (x *UpsertRecordingRuleRequest) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *UpsertRecordingRuleRequest) GetStacktraceFilter() *StacktraceFilter { + if x != nil { + return x.StacktraceFilter + } + return nil +} + +type UpsertRecordingRuleResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Rule *RecordingRule `protobuf:"bytes,1,opt,name=rule,proto3" json:"rule,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpsertRecordingRuleResponse) Reset() { + *x = UpsertRecordingRuleResponse{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpsertRecordingRuleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertRecordingRuleResponse) ProtoMessage() {} + +func (x *UpsertRecordingRuleResponse) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpsertRecordingRuleResponse.ProtoReflect.Descriptor instead. +func (*UpsertRecordingRuleResponse) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{5} +} + +func (x *UpsertRecordingRuleResponse) GetRule() *RecordingRule { + if x != nil { + return x.Rule + } + return nil +} + +type DeleteRecordingRuleRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteRecordingRuleRequest) Reset() { + *x = DeleteRecordingRuleRequest{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteRecordingRuleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRecordingRuleRequest) ProtoMessage() {} + +func (x *DeleteRecordingRuleRequest) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRecordingRuleRequest.ProtoReflect.Descriptor instead. +func (*DeleteRecordingRuleRequest) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{6} +} + +func (x *DeleteRecordingRuleRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type DeleteRecordingRuleResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteRecordingRuleResponse) Reset() { + *x = DeleteRecordingRuleResponse{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteRecordingRuleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRecordingRuleResponse) ProtoMessage() {} + +func (x *DeleteRecordingRuleResponse) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRecordingRuleResponse.ProtoReflect.Descriptor instead. +func (*DeleteRecordingRuleResponse) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{7} +} + +type RecordingRule struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The unique id of the recording rule. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The name of the recording rule, this does not necessarily need to be + // unique. + MetricName string `protobuf:"bytes,2,opt,name=metric_name,json=metricName,proto3" json:"metric_name,omitempty"` + // Used in the UI to display what type of profile type this recording rule is + // generated from. + // + // This should be the standard format of: + // + // :::: + // + // For example: + // + // process_cpu:cpu:nanoseconds:cpu:nanoseconds + ProfileType string `protobuf:"bytes,3,opt,name=profile_type,json=profileType,proto3" json:"profile_type,omitempty"` + Matchers []string `protobuf:"bytes,4,rep,name=matchers,proto3" json:"matchers,omitempty"` + GroupBy []string `protobuf:"bytes,5,rep,name=group_by,json=groupBy,proto3" json:"group_by,omitempty"` + ExternalLabels []*v1.LabelPair `protobuf:"bytes,6,rep,name=external_labels,json=externalLabels,proto3" json:"external_labels,omitempty"` + // The observed generation of this recording rule. This value should be + // provided when making updates to this record, to avoid conflicting + // concurrent updates. + Generation int64 `protobuf:"varint,7,opt,name=generation,proto3" json:"generation,omitempty"` + // The stacktrace filter allows filtering on particular function names in the stacktrace. + // This allows recording rules to focus on specific functions and calculate their "total" + // resource usage. + StacktraceFilter *StacktraceFilter `protobuf:"bytes,8,opt,name=stacktrace_filter,json=stacktraceFilter,proto3,oneof" json:"stacktrace_filter,omitempty"` + // Provisioned rules are added by config and can't be Upsert or Deleted + Provisioned bool `protobuf:"varint,9,opt,name=provisioned,proto3" json:"provisioned,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RecordingRule) Reset() { + *x = RecordingRule{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RecordingRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RecordingRule) ProtoMessage() {} + +func (x *RecordingRule) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RecordingRule.ProtoReflect.Descriptor instead. +func (*RecordingRule) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{8} +} + +func (x *RecordingRule) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RecordingRule) GetMetricName() string { + if x != nil { + return x.MetricName + } + return "" +} + +func (x *RecordingRule) GetProfileType() string { + if x != nil { + return x.ProfileType + } + return "" +} + +func (x *RecordingRule) GetMatchers() []string { + if x != nil { + return x.Matchers + } + return nil +} + +func (x *RecordingRule) GetGroupBy() []string { + if x != nil { + return x.GroupBy + } + return nil +} + +func (x *RecordingRule) GetExternalLabels() []*v1.LabelPair { + if x != nil { + return x.ExternalLabels + } + return nil +} + +func (x *RecordingRule) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *RecordingRule) GetStacktraceFilter() *StacktraceFilter { + if x != nil { + return x.StacktraceFilter + } + return nil +} + +func (x *RecordingRule) GetProvisioned() bool { + if x != nil { + return x.Provisioned + } + return false +} + +type StacktraceFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + FunctionName *StacktraceFilterFunctionName `protobuf:"bytes,1,opt,name=function_name,json=functionName,proto3,oneof" json:"function_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StacktraceFilter) Reset() { + *x = StacktraceFilter{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StacktraceFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StacktraceFilter) ProtoMessage() {} + +func (x *StacktraceFilter) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StacktraceFilter.ProtoReflect.Descriptor instead. +func (*StacktraceFilter) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{9} +} + +func (x *StacktraceFilter) GetFunctionName() *StacktraceFilterFunctionName { + if x != nil { + return x.FunctionName + } + return nil +} + +type StacktraceFilterFunctionName struct { + state protoimpl.MessageState `protogen:"open.v1"` + FunctionName string `protobuf:"bytes,1,opt,name=function_name,json=functionName,proto3" json:"function_name,omitempty"` + MetricType MetricType `protobuf:"varint,2,opt,name=metric_type,json=metricType,proto3,enum=settings.v1.MetricType" json:"metric_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StacktraceFilterFunctionName) Reset() { + *x = StacktraceFilterFunctionName{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StacktraceFilterFunctionName) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StacktraceFilterFunctionName) ProtoMessage() {} + +func (x *StacktraceFilterFunctionName) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StacktraceFilterFunctionName.ProtoReflect.Descriptor instead. +func (*StacktraceFilterFunctionName) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{10} +} + +func (x *StacktraceFilterFunctionName) GetFunctionName() string { + if x != nil { + return x.FunctionName + } + return "" +} + +func (x *StacktraceFilterFunctionName) GetMetricType() MetricType { + if x != nil { + return x.MetricType + } + return MetricType_TOTAL +} + +type RecordingRuleStore struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + MetricName string `protobuf:"bytes,2,opt,name=metric_name,json=metricName,proto3" json:"metric_name,omitempty"` + PrometheusDataSource string `protobuf:"bytes,3,opt,name=prometheus_data_source,json=prometheusDataSource,proto3" json:"prometheus_data_source,omitempty"` + Matchers []string `protobuf:"bytes,4,rep,name=matchers,proto3" json:"matchers,omitempty"` + GroupBy []string `protobuf:"bytes,5,rep,name=group_by,json=groupBy,proto3" json:"group_by,omitempty"` + ExternalLabels []*v1.LabelPair `protobuf:"bytes,6,rep,name=external_labels,json=externalLabels,proto3" json:"external_labels,omitempty"` + Generation int64 `protobuf:"varint,7,opt,name=generation,proto3" json:"generation,omitempty"` + StacktraceFilter *StacktraceFilter `protobuf:"bytes,8,opt,name=stacktrace_filter,json=stacktraceFilter,proto3,oneof" json:"stacktrace_filter,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RecordingRuleStore) Reset() { + *x = RecordingRuleStore{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RecordingRuleStore) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RecordingRuleStore) ProtoMessage() {} + +func (x *RecordingRuleStore) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RecordingRuleStore.ProtoReflect.Descriptor instead. +func (*RecordingRuleStore) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{11} +} + +func (x *RecordingRuleStore) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RecordingRuleStore) GetMetricName() string { + if x != nil { + return x.MetricName + } + return "" +} + +func (x *RecordingRuleStore) GetPrometheusDataSource() string { + if x != nil { + return x.PrometheusDataSource + } + return "" +} + +func (x *RecordingRuleStore) GetMatchers() []string { + if x != nil { + return x.Matchers + } + return nil +} + +func (x *RecordingRuleStore) GetGroupBy() []string { + if x != nil { + return x.GroupBy + } + return nil +} + +func (x *RecordingRuleStore) GetExternalLabels() []*v1.LabelPair { + if x != nil { + return x.ExternalLabels + } + return nil +} + +func (x *RecordingRuleStore) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *RecordingRuleStore) GetStacktraceFilter() *StacktraceFilter { + if x != nil { + return x.StacktraceFilter + } + return nil +} + +type RecordingRulesStore struct { + state protoimpl.MessageState `protogen:"open.v1"` + Rules []*RecordingRuleStore `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + Generation int64 `protobuf:"varint,2,opt,name=generation,proto3" json:"generation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RecordingRulesStore) Reset() { + *x = RecordingRulesStore{} + mi := &file_settings_v1_recording_rules_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RecordingRulesStore) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RecordingRulesStore) ProtoMessage() {} + +func (x *RecordingRulesStore) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_recording_rules_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RecordingRulesStore.ProtoReflect.Descriptor instead. +func (*RecordingRulesStore) Descriptor() ([]byte, []int) { + return file_settings_v1_recording_rules_proto_rawDescGZIP(), []int{12} +} + +func (x *RecordingRulesStore) GetRules() []*RecordingRuleStore { + if x != nil { + return x.Rules + } + return nil +} + +func (x *RecordingRulesStore) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +var File_settings_v1_recording_rules_proto protoreflect.FileDescriptor + +const file_settings_v1_recording_rules_proto_rawDesc = "" + + "\n" + + "!settings/v1/recording_rules.proto\x12\vsettings.v1\x1a\x14types/v1/types.proto\")\n" + + "\x17GetRecordingRuleRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"J\n" + + "\x18GetRecordingRuleResponse\x12.\n" + + "\x04rule\x18\x01 \x01(\v2\x1a.settings.v1.RecordingRuleR\x04rule\"\x1b\n" + + "\x19ListRecordingRulesRequest\"N\n" + + "\x1aListRecordingRulesResponse\x120\n" + + "\x05rules\x18\x01 \x03(\v2\x1a.settings.v1.RecordingRuleR\x05rules\"\xc9\x02\n" + + "\x1aUpsertRecordingRuleRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1f\n" + + "\vmetric_name\x18\x02 \x01(\tR\n" + + "metricName\x12\x1a\n" + + "\bmatchers\x18\x03 \x03(\tR\bmatchers\x12\x19\n" + + "\bgroup_by\x18\x04 \x03(\tR\agroupBy\x12<\n" + + "\x0fexternal_labels\x18\x05 \x03(\v2\x13.types.v1.LabelPairR\x0eexternalLabels\x12\x1e\n" + + "\n" + + "generation\x18\x06 \x01(\x03R\n" + + "generation\x12O\n" + + "\x11stacktrace_filter\x18\a \x01(\v2\x1d.settings.v1.StacktraceFilterH\x00R\x10stacktraceFilter\x88\x01\x01B\x14\n" + + "\x12_stacktrace_filter\"M\n" + + "\x1bUpsertRecordingRuleResponse\x12.\n" + + "\x04rule\x18\x01 \x01(\v2\x1a.settings.v1.RecordingRuleR\x04rule\",\n" + + "\x1aDeleteRecordingRuleRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"\x1d\n" + + "\x1bDeleteRecordingRuleResponse\"\x81\x03\n" + + "\rRecordingRule\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1f\n" + + "\vmetric_name\x18\x02 \x01(\tR\n" + + "metricName\x12!\n" + + "\fprofile_type\x18\x03 \x01(\tR\vprofileType\x12\x1a\n" + + "\bmatchers\x18\x04 \x03(\tR\bmatchers\x12\x19\n" + + "\bgroup_by\x18\x05 \x03(\tR\agroupBy\x12<\n" + + "\x0fexternal_labels\x18\x06 \x03(\v2\x13.types.v1.LabelPairR\x0eexternalLabels\x12\x1e\n" + + "\n" + + "generation\x18\a \x01(\x03R\n" + + "generation\x12O\n" + + "\x11stacktrace_filter\x18\b \x01(\v2\x1d.settings.v1.StacktraceFilterH\x00R\x10stacktraceFilter\x88\x01\x01\x12 \n" + + "\vprovisioned\x18\t \x01(\bR\vprovisionedB\x14\n" + + "\x12_stacktrace_filter\"y\n" + + "\x10StacktraceFilter\x12S\n" + + "\rfunction_name\x18\x01 \x01(\v2).settings.v1.StacktraceFilterFunctionNameH\x00R\ffunctionName\x88\x01\x01B\x10\n" + + "\x0e_function_name\"}\n" + + "\x1cStacktraceFilterFunctionName\x12#\n" + + "\rfunction_name\x18\x01 \x01(\tR\ffunctionName\x128\n" + + "\vmetric_type\x18\x02 \x01(\x0e2\x17.settings.v1.MetricTypeR\n" + + "metricType\"\xf7\x02\n" + + "\x12RecordingRuleStore\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1f\n" + + "\vmetric_name\x18\x02 \x01(\tR\n" + + "metricName\x124\n" + + "\x16prometheus_data_source\x18\x03 \x01(\tR\x14prometheusDataSource\x12\x1a\n" + + "\bmatchers\x18\x04 \x03(\tR\bmatchers\x12\x19\n" + + "\bgroup_by\x18\x05 \x03(\tR\agroupBy\x12<\n" + + "\x0fexternal_labels\x18\x06 \x03(\v2\x13.types.v1.LabelPairR\x0eexternalLabels\x12\x1e\n" + + "\n" + + "generation\x18\a \x01(\x03R\n" + + "generation\x12O\n" + + "\x11stacktrace_filter\x18\b \x01(\v2\x1d.settings.v1.StacktraceFilterH\x00R\x10stacktraceFilter\x88\x01\x01B\x14\n" + + "\x12_stacktrace_filter\"l\n" + + "\x13RecordingRulesStore\x125\n" + + "\x05rules\x18\x01 \x03(\v2\x1f.settings.v1.RecordingRuleStoreR\x05rules\x12\x1e\n" + + "\n" + + "generation\x18\x02 \x01(\x03R\n" + + "generation*\x17\n" + + "\n" + + "MetricType\x12\t\n" + + "\x05TOTAL\x10\x002\xbb\x03\n" + + "\x15RecordingRulesService\x12a\n" + + "\x10GetRecordingRule\x12$.settings.v1.GetRecordingRuleRequest\x1a%.settings.v1.GetRecordingRuleResponse\"\x00\x12g\n" + + "\x12ListRecordingRules\x12&.settings.v1.ListRecordingRulesRequest\x1a'.settings.v1.ListRecordingRulesResponse\"\x00\x12j\n" + + "\x13UpsertRecordingRule\x12'.settings.v1.UpsertRecordingRuleRequest\x1a(.settings.v1.UpsertRecordingRuleResponse\"\x00\x12j\n" + + "\x13DeleteRecordingRule\x12'.settings.v1.DeleteRecordingRuleRequest\x1a(.settings.v1.DeleteRecordingRuleResponse\"\x00B\xb9\x01\n" + + "\x0fcom.settings.v1B\x13RecordingRulesProtoP\x01ZDgithub.com/grafana/pyroscope/api/gen/proto/go/settings/v1;settingsv1\xa2\x02\x03SXX\xaa\x02\vSettings.V1\xca\x02\vSettings\\V1\xe2\x02\x17Settings\\V1\\GPBMetadata\xea\x02\fSettings::V1b\x06proto3" + +var ( + file_settings_v1_recording_rules_proto_rawDescOnce sync.Once + file_settings_v1_recording_rules_proto_rawDescData []byte +) + +func file_settings_v1_recording_rules_proto_rawDescGZIP() []byte { + file_settings_v1_recording_rules_proto_rawDescOnce.Do(func() { + file_settings_v1_recording_rules_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_settings_v1_recording_rules_proto_rawDesc), len(file_settings_v1_recording_rules_proto_rawDesc))) + }) + return file_settings_v1_recording_rules_proto_rawDescData +} + +var file_settings_v1_recording_rules_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_settings_v1_recording_rules_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_settings_v1_recording_rules_proto_goTypes = []any{ + (MetricType)(0), // 0: settings.v1.MetricType + (*GetRecordingRuleRequest)(nil), // 1: settings.v1.GetRecordingRuleRequest + (*GetRecordingRuleResponse)(nil), // 2: settings.v1.GetRecordingRuleResponse + (*ListRecordingRulesRequest)(nil), // 3: settings.v1.ListRecordingRulesRequest + (*ListRecordingRulesResponse)(nil), // 4: settings.v1.ListRecordingRulesResponse + (*UpsertRecordingRuleRequest)(nil), // 5: settings.v1.UpsertRecordingRuleRequest + (*UpsertRecordingRuleResponse)(nil), // 6: settings.v1.UpsertRecordingRuleResponse + (*DeleteRecordingRuleRequest)(nil), // 7: settings.v1.DeleteRecordingRuleRequest + (*DeleteRecordingRuleResponse)(nil), // 8: settings.v1.DeleteRecordingRuleResponse + (*RecordingRule)(nil), // 9: settings.v1.RecordingRule + (*StacktraceFilter)(nil), // 10: settings.v1.StacktraceFilter + (*StacktraceFilterFunctionName)(nil), // 11: settings.v1.StacktraceFilterFunctionName + (*RecordingRuleStore)(nil), // 12: settings.v1.RecordingRuleStore + (*RecordingRulesStore)(nil), // 13: settings.v1.RecordingRulesStore + (*v1.LabelPair)(nil), // 14: types.v1.LabelPair +} +var file_settings_v1_recording_rules_proto_depIdxs = []int32{ + 9, // 0: settings.v1.GetRecordingRuleResponse.rule:type_name -> settings.v1.RecordingRule + 9, // 1: settings.v1.ListRecordingRulesResponse.rules:type_name -> settings.v1.RecordingRule + 14, // 2: settings.v1.UpsertRecordingRuleRequest.external_labels:type_name -> types.v1.LabelPair + 10, // 3: settings.v1.UpsertRecordingRuleRequest.stacktrace_filter:type_name -> settings.v1.StacktraceFilter + 9, // 4: settings.v1.UpsertRecordingRuleResponse.rule:type_name -> settings.v1.RecordingRule + 14, // 5: settings.v1.RecordingRule.external_labels:type_name -> types.v1.LabelPair + 10, // 6: settings.v1.RecordingRule.stacktrace_filter:type_name -> settings.v1.StacktraceFilter + 11, // 7: settings.v1.StacktraceFilter.function_name:type_name -> settings.v1.StacktraceFilterFunctionName + 0, // 8: settings.v1.StacktraceFilterFunctionName.metric_type:type_name -> settings.v1.MetricType + 14, // 9: settings.v1.RecordingRuleStore.external_labels:type_name -> types.v1.LabelPair + 10, // 10: settings.v1.RecordingRuleStore.stacktrace_filter:type_name -> settings.v1.StacktraceFilter + 12, // 11: settings.v1.RecordingRulesStore.rules:type_name -> settings.v1.RecordingRuleStore + 1, // 12: settings.v1.RecordingRulesService.GetRecordingRule:input_type -> settings.v1.GetRecordingRuleRequest + 3, // 13: settings.v1.RecordingRulesService.ListRecordingRules:input_type -> settings.v1.ListRecordingRulesRequest + 5, // 14: settings.v1.RecordingRulesService.UpsertRecordingRule:input_type -> settings.v1.UpsertRecordingRuleRequest + 7, // 15: settings.v1.RecordingRulesService.DeleteRecordingRule:input_type -> settings.v1.DeleteRecordingRuleRequest + 2, // 16: settings.v1.RecordingRulesService.GetRecordingRule:output_type -> settings.v1.GetRecordingRuleResponse + 4, // 17: settings.v1.RecordingRulesService.ListRecordingRules:output_type -> settings.v1.ListRecordingRulesResponse + 6, // 18: settings.v1.RecordingRulesService.UpsertRecordingRule:output_type -> settings.v1.UpsertRecordingRuleResponse + 8, // 19: settings.v1.RecordingRulesService.DeleteRecordingRule:output_type -> settings.v1.DeleteRecordingRuleResponse + 16, // [16:20] is the sub-list for method output_type + 12, // [12:16] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_settings_v1_recording_rules_proto_init() } +func file_settings_v1_recording_rules_proto_init() { + if File_settings_v1_recording_rules_proto != nil { + return + } + file_settings_v1_recording_rules_proto_msgTypes[4].OneofWrappers = []any{} + file_settings_v1_recording_rules_proto_msgTypes[8].OneofWrappers = []any{} + file_settings_v1_recording_rules_proto_msgTypes[9].OneofWrappers = []any{} + file_settings_v1_recording_rules_proto_msgTypes[11].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_settings_v1_recording_rules_proto_rawDesc), len(file_settings_v1_recording_rules_proto_rawDesc)), + NumEnums: 1, + NumMessages: 13, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_settings_v1_recording_rules_proto_goTypes, + DependencyIndexes: file_settings_v1_recording_rules_proto_depIdxs, + EnumInfos: file_settings_v1_recording_rules_proto_enumTypes, + MessageInfos: file_settings_v1_recording_rules_proto_msgTypes, + }.Build() + File_settings_v1_recording_rules_proto = out.File + file_settings_v1_recording_rules_proto_goTypes = nil + file_settings_v1_recording_rules_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/settings/v1/recording_rules_vtproto.pb.go b/api/gen/proto/go/settings/v1/recording_rules_vtproto.pb.go new file mode 100644 index 0000000000..f42cfb59c9 --- /dev/null +++ b/api/gen/proto/go/settings/v1/recording_rules_vtproto.pb.go @@ -0,0 +1,3745 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: settings/v1/recording_rules.proto + +package settingsv1 + +import ( + context "context" + fmt "fmt" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + proto "google.golang.org/protobuf/proto" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *GetRecordingRuleRequest) CloneVT() *GetRecordingRuleRequest { + if m == nil { + return (*GetRecordingRuleRequest)(nil) + } + r := new(GetRecordingRuleRequest) + r.Id = m.Id + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetRecordingRuleRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetRecordingRuleResponse) CloneVT() *GetRecordingRuleResponse { + if m == nil { + return (*GetRecordingRuleResponse)(nil) + } + r := new(GetRecordingRuleResponse) + r.Rule = m.Rule.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetRecordingRuleResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ListRecordingRulesRequest) CloneVT() *ListRecordingRulesRequest { + if m == nil { + return (*ListRecordingRulesRequest)(nil) + } + r := new(ListRecordingRulesRequest) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ListRecordingRulesRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *ListRecordingRulesResponse) CloneVT() *ListRecordingRulesResponse { + if m == nil { + return (*ListRecordingRulesResponse)(nil) + } + r := new(ListRecordingRulesResponse) + if rhs := m.Rules; rhs != nil { + tmpContainer := make([]*RecordingRule, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Rules = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ListRecordingRulesResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *UpsertRecordingRuleRequest) CloneVT() *UpsertRecordingRuleRequest { + if m == nil { + return (*UpsertRecordingRuleRequest)(nil) + } + r := new(UpsertRecordingRuleRequest) + r.Id = m.Id + r.MetricName = m.MetricName + r.Generation = m.Generation + r.StacktraceFilter = m.StacktraceFilter.CloneVT() + if rhs := m.Matchers; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Matchers = tmpContainer + } + if rhs := m.GroupBy; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.GroupBy = tmpContainer + } + if rhs := m.ExternalLabels; rhs != nil { + tmpContainer := make([]*v1.LabelPair, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.LabelPair }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.LabelPair) + } + } + r.ExternalLabels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *UpsertRecordingRuleRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *UpsertRecordingRuleResponse) CloneVT() *UpsertRecordingRuleResponse { + if m == nil { + return (*UpsertRecordingRuleResponse)(nil) + } + r := new(UpsertRecordingRuleResponse) + r.Rule = m.Rule.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *UpsertRecordingRuleResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *DeleteRecordingRuleRequest) CloneVT() *DeleteRecordingRuleRequest { + if m == nil { + return (*DeleteRecordingRuleRequest)(nil) + } + r := new(DeleteRecordingRuleRequest) + r.Id = m.Id + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteRecordingRuleRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *DeleteRecordingRuleResponse) CloneVT() *DeleteRecordingRuleResponse { + if m == nil { + return (*DeleteRecordingRuleResponse)(nil) + } + r := new(DeleteRecordingRuleResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteRecordingRuleResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *RecordingRule) CloneVT() *RecordingRule { + if m == nil { + return (*RecordingRule)(nil) + } + r := new(RecordingRule) + r.Id = m.Id + r.MetricName = m.MetricName + r.ProfileType = m.ProfileType + r.Generation = m.Generation + r.StacktraceFilter = m.StacktraceFilter.CloneVT() + r.Provisioned = m.Provisioned + if rhs := m.Matchers; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Matchers = tmpContainer + } + if rhs := m.GroupBy; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.GroupBy = tmpContainer + } + if rhs := m.ExternalLabels; rhs != nil { + tmpContainer := make([]*v1.LabelPair, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.LabelPair }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.LabelPair) + } + } + r.ExternalLabels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *RecordingRule) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *StacktraceFilter) CloneVT() *StacktraceFilter { + if m == nil { + return (*StacktraceFilter)(nil) + } + r := new(StacktraceFilter) + r.FunctionName = m.FunctionName.CloneVT() + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *StacktraceFilter) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *StacktraceFilterFunctionName) CloneVT() *StacktraceFilterFunctionName { + if m == nil { + return (*StacktraceFilterFunctionName)(nil) + } + r := new(StacktraceFilterFunctionName) + r.FunctionName = m.FunctionName + r.MetricType = m.MetricType + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *StacktraceFilterFunctionName) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *RecordingRuleStore) CloneVT() *RecordingRuleStore { + if m == nil { + return (*RecordingRuleStore)(nil) + } + r := new(RecordingRuleStore) + r.Id = m.Id + r.MetricName = m.MetricName + r.PrometheusDataSource = m.PrometheusDataSource + r.Generation = m.Generation + r.StacktraceFilter = m.StacktraceFilter.CloneVT() + if rhs := m.Matchers; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Matchers = tmpContainer + } + if rhs := m.GroupBy; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.GroupBy = tmpContainer + } + if rhs := m.ExternalLabels; rhs != nil { + tmpContainer := make([]*v1.LabelPair, len(rhs)) + for k, v := range rhs { + if vtpb, ok := interface{}(v).(interface{ CloneVT() *v1.LabelPair }); ok { + tmpContainer[k] = vtpb.CloneVT() + } else { + tmpContainer[k] = proto.Clone(v).(*v1.LabelPair) + } + } + r.ExternalLabels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *RecordingRuleStore) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *RecordingRulesStore) CloneVT() *RecordingRulesStore { + if m == nil { + return (*RecordingRulesStore)(nil) + } + r := new(RecordingRulesStore) + r.Generation = m.Generation + if rhs := m.Rules; rhs != nil { + tmpContainer := make([]*RecordingRuleStore, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Rules = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *RecordingRulesStore) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (this *GetRecordingRuleRequest) EqualVT(that *GetRecordingRuleRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Id != that.Id { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetRecordingRuleRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetRecordingRuleRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetRecordingRuleResponse) EqualVT(that *GetRecordingRuleResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Rule.EqualVT(that.Rule) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetRecordingRuleResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetRecordingRuleResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ListRecordingRulesRequest) EqualVT(that *ListRecordingRulesRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ListRecordingRulesRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ListRecordingRulesRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *ListRecordingRulesResponse) EqualVT(that *ListRecordingRulesResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Rules) != len(that.Rules) { + return false + } + for i, vx := range this.Rules { + vy := that.Rules[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &RecordingRule{} + } + if q == nil { + q = &RecordingRule{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ListRecordingRulesResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ListRecordingRulesResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *UpsertRecordingRuleRequest) EqualVT(that *UpsertRecordingRuleRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Id != that.Id { + return false + } + if this.MetricName != that.MetricName { + return false + } + if len(this.Matchers) != len(that.Matchers) { + return false + } + for i, vx := range this.Matchers { + vy := that.Matchers[i] + if vx != vy { + return false + } + } + if len(this.GroupBy) != len(that.GroupBy) { + return false + } + for i, vx := range this.GroupBy { + vy := that.GroupBy[i] + if vx != vy { + return false + } + } + if len(this.ExternalLabels) != len(that.ExternalLabels) { + return false + } + for i, vx := range this.ExternalLabels { + vy := that.ExternalLabels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.LabelPair{} + } + if q == nil { + q = &v1.LabelPair{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.LabelPair) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + if this.Generation != that.Generation { + return false + } + if !this.StacktraceFilter.EqualVT(that.StacktraceFilter) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *UpsertRecordingRuleRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*UpsertRecordingRuleRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *UpsertRecordingRuleResponse) EqualVT(that *UpsertRecordingRuleResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.Rule.EqualVT(that.Rule) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *UpsertRecordingRuleResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*UpsertRecordingRuleResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *DeleteRecordingRuleRequest) EqualVT(that *DeleteRecordingRuleRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Id != that.Id { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteRecordingRuleRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteRecordingRuleRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *DeleteRecordingRuleResponse) EqualVT(that *DeleteRecordingRuleResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteRecordingRuleResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteRecordingRuleResponse) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *RecordingRule) EqualVT(that *RecordingRule) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Id != that.Id { + return false + } + if this.MetricName != that.MetricName { + return false + } + if this.ProfileType != that.ProfileType { + return false + } + if len(this.Matchers) != len(that.Matchers) { + return false + } + for i, vx := range this.Matchers { + vy := that.Matchers[i] + if vx != vy { + return false + } + } + if len(this.GroupBy) != len(that.GroupBy) { + return false + } + for i, vx := range this.GroupBy { + vy := that.GroupBy[i] + if vx != vy { + return false + } + } + if len(this.ExternalLabels) != len(that.ExternalLabels) { + return false + } + for i, vx := range this.ExternalLabels { + vy := that.ExternalLabels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.LabelPair{} + } + if q == nil { + q = &v1.LabelPair{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.LabelPair) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + if this.Generation != that.Generation { + return false + } + if !this.StacktraceFilter.EqualVT(that.StacktraceFilter) { + return false + } + if this.Provisioned != that.Provisioned { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *RecordingRule) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*RecordingRule) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *StacktraceFilter) EqualVT(that *StacktraceFilter) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if !this.FunctionName.EqualVT(that.FunctionName) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *StacktraceFilter) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*StacktraceFilter) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *StacktraceFilterFunctionName) EqualVT(that *StacktraceFilterFunctionName) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.FunctionName != that.FunctionName { + return false + } + if this.MetricType != that.MetricType { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *StacktraceFilterFunctionName) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*StacktraceFilterFunctionName) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *RecordingRuleStore) EqualVT(that *RecordingRuleStore) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Id != that.Id { + return false + } + if this.MetricName != that.MetricName { + return false + } + if this.PrometheusDataSource != that.PrometheusDataSource { + return false + } + if len(this.Matchers) != len(that.Matchers) { + return false + } + for i, vx := range this.Matchers { + vy := that.Matchers[i] + if vx != vy { + return false + } + } + if len(this.GroupBy) != len(that.GroupBy) { + return false + } + for i, vx := range this.GroupBy { + vy := that.GroupBy[i] + if vx != vy { + return false + } + } + if len(this.ExternalLabels) != len(that.ExternalLabels) { + return false + } + for i, vx := range this.ExternalLabels { + vy := that.ExternalLabels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &v1.LabelPair{} + } + if q == nil { + q = &v1.LabelPair{} + } + if equal, ok := interface{}(p).(interface{ EqualVT(*v1.LabelPair) bool }); ok { + if !equal.EqualVT(q) { + return false + } + } else if !proto.Equal(p, q) { + return false + } + } + } + if this.Generation != that.Generation { + return false + } + if !this.StacktraceFilter.EqualVT(that.StacktraceFilter) { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *RecordingRuleStore) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*RecordingRuleStore) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *RecordingRulesStore) EqualVT(that *RecordingRulesStore) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Rules) != len(that.Rules) { + return false + } + for i, vx := range this.Rules { + vy := that.Rules[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &RecordingRuleStore{} + } + if q == nil { + q = &RecordingRuleStore{} + } + if !p.EqualVT(q) { + return false + } + } + } + if this.Generation != that.Generation { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *RecordingRulesStore) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*RecordingRulesStore) + if !ok { + return false + } + return this.EqualVT(that) +} + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// RecordingRulesServiceClient is the client API for RecordingRulesService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type RecordingRulesServiceClient interface { + GetRecordingRule(ctx context.Context, in *GetRecordingRuleRequest, opts ...grpc.CallOption) (*GetRecordingRuleResponse, error) + ListRecordingRules(ctx context.Context, in *ListRecordingRulesRequest, opts ...grpc.CallOption) (*ListRecordingRulesResponse, error) + UpsertRecordingRule(ctx context.Context, in *UpsertRecordingRuleRequest, opts ...grpc.CallOption) (*UpsertRecordingRuleResponse, error) + DeleteRecordingRule(ctx context.Context, in *DeleteRecordingRuleRequest, opts ...grpc.CallOption) (*DeleteRecordingRuleResponse, error) +} + +type recordingRulesServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewRecordingRulesServiceClient(cc grpc.ClientConnInterface) RecordingRulesServiceClient { + return &recordingRulesServiceClient{cc} +} + +func (c *recordingRulesServiceClient) GetRecordingRule(ctx context.Context, in *GetRecordingRuleRequest, opts ...grpc.CallOption) (*GetRecordingRuleResponse, error) { + out := new(GetRecordingRuleResponse) + err := c.cc.Invoke(ctx, "/settings.v1.RecordingRulesService/GetRecordingRule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *recordingRulesServiceClient) ListRecordingRules(ctx context.Context, in *ListRecordingRulesRequest, opts ...grpc.CallOption) (*ListRecordingRulesResponse, error) { + out := new(ListRecordingRulesResponse) + err := c.cc.Invoke(ctx, "/settings.v1.RecordingRulesService/ListRecordingRules", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *recordingRulesServiceClient) UpsertRecordingRule(ctx context.Context, in *UpsertRecordingRuleRequest, opts ...grpc.CallOption) (*UpsertRecordingRuleResponse, error) { + out := new(UpsertRecordingRuleResponse) + err := c.cc.Invoke(ctx, "/settings.v1.RecordingRulesService/UpsertRecordingRule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *recordingRulesServiceClient) DeleteRecordingRule(ctx context.Context, in *DeleteRecordingRuleRequest, opts ...grpc.CallOption) (*DeleteRecordingRuleResponse, error) { + out := new(DeleteRecordingRuleResponse) + err := c.cc.Invoke(ctx, "/settings.v1.RecordingRulesService/DeleteRecordingRule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RecordingRulesServiceServer is the server API for RecordingRulesService service. +// All implementations must embed UnimplementedRecordingRulesServiceServer +// for forward compatibility +type RecordingRulesServiceServer interface { + GetRecordingRule(context.Context, *GetRecordingRuleRequest) (*GetRecordingRuleResponse, error) + ListRecordingRules(context.Context, *ListRecordingRulesRequest) (*ListRecordingRulesResponse, error) + UpsertRecordingRule(context.Context, *UpsertRecordingRuleRequest) (*UpsertRecordingRuleResponse, error) + DeleteRecordingRule(context.Context, *DeleteRecordingRuleRequest) (*DeleteRecordingRuleResponse, error) + mustEmbedUnimplementedRecordingRulesServiceServer() +} + +// UnimplementedRecordingRulesServiceServer must be embedded to have forward compatible implementations. +type UnimplementedRecordingRulesServiceServer struct { +} + +func (UnimplementedRecordingRulesServiceServer) GetRecordingRule(context.Context, *GetRecordingRuleRequest) (*GetRecordingRuleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRecordingRule not implemented") +} +func (UnimplementedRecordingRulesServiceServer) ListRecordingRules(context.Context, *ListRecordingRulesRequest) (*ListRecordingRulesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListRecordingRules not implemented") +} +func (UnimplementedRecordingRulesServiceServer) UpsertRecordingRule(context.Context, *UpsertRecordingRuleRequest) (*UpsertRecordingRuleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpsertRecordingRule not implemented") +} +func (UnimplementedRecordingRulesServiceServer) DeleteRecordingRule(context.Context, *DeleteRecordingRuleRequest) (*DeleteRecordingRuleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteRecordingRule not implemented") +} +func (UnimplementedRecordingRulesServiceServer) mustEmbedUnimplementedRecordingRulesServiceServer() {} + +// UnsafeRecordingRulesServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to RecordingRulesServiceServer will +// result in compilation errors. +type UnsafeRecordingRulesServiceServer interface { + mustEmbedUnimplementedRecordingRulesServiceServer() +} + +func RegisterRecordingRulesServiceServer(s grpc.ServiceRegistrar, srv RecordingRulesServiceServer) { + s.RegisterService(&RecordingRulesService_ServiceDesc, srv) +} + +func _RecordingRulesService_GetRecordingRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRecordingRuleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RecordingRulesServiceServer).GetRecordingRule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/settings.v1.RecordingRulesService/GetRecordingRule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RecordingRulesServiceServer).GetRecordingRule(ctx, req.(*GetRecordingRuleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RecordingRulesService_ListRecordingRules_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListRecordingRulesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RecordingRulesServiceServer).ListRecordingRules(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/settings.v1.RecordingRulesService/ListRecordingRules", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RecordingRulesServiceServer).ListRecordingRules(ctx, req.(*ListRecordingRulesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RecordingRulesService_UpsertRecordingRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpsertRecordingRuleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RecordingRulesServiceServer).UpsertRecordingRule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/settings.v1.RecordingRulesService/UpsertRecordingRule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RecordingRulesServiceServer).UpsertRecordingRule(ctx, req.(*UpsertRecordingRuleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RecordingRulesService_DeleteRecordingRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteRecordingRuleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RecordingRulesServiceServer).DeleteRecordingRule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/settings.v1.RecordingRulesService/DeleteRecordingRule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RecordingRulesServiceServer).DeleteRecordingRule(ctx, req.(*DeleteRecordingRuleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// RecordingRulesService_ServiceDesc is the grpc.ServiceDesc for RecordingRulesService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var RecordingRulesService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "settings.v1.RecordingRulesService", + HandlerType: (*RecordingRulesServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetRecordingRule", + Handler: _RecordingRulesService_GetRecordingRule_Handler, + }, + { + MethodName: "ListRecordingRules", + Handler: _RecordingRulesService_ListRecordingRules_Handler, + }, + { + MethodName: "UpsertRecordingRule", + Handler: _RecordingRulesService_UpsertRecordingRule_Handler, + }, + { + MethodName: "DeleteRecordingRule", + Handler: _RecordingRulesService_DeleteRecordingRule_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "settings/v1/recording_rules.proto", +} + +func (m *GetRecordingRuleRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetRecordingRuleRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetRecordingRuleRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetRecordingRuleResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetRecordingRuleResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetRecordingRuleResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Rule != nil { + size, err := m.Rule.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ListRecordingRulesRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListRecordingRulesRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ListRecordingRulesRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *ListRecordingRulesResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListRecordingRulesResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ListRecordingRulesResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Rules) > 0 { + for iNdEx := len(m.Rules) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Rules[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *UpsertRecordingRuleRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpsertRecordingRuleRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *UpsertRecordingRuleRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.StacktraceFilter != nil { + size, err := m.StacktraceFilter.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x3a + } + if m.Generation != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Generation)) + i-- + dAtA[i] = 0x30 + } + if len(m.ExternalLabels) > 0 { + for iNdEx := len(m.ExternalLabels) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.ExternalLabels[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.ExternalLabels[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.GroupBy) > 0 { + for iNdEx := len(m.GroupBy) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.GroupBy[iNdEx]) + copy(dAtA[i:], m.GroupBy[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GroupBy[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.Matchers) > 0 { + for iNdEx := len(m.Matchers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Matchers[iNdEx]) + copy(dAtA[i:], m.Matchers[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Matchers[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.MetricName) > 0 { + i -= len(m.MetricName) + copy(dAtA[i:], m.MetricName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MetricName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UpsertRecordingRuleResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpsertRecordingRuleResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *UpsertRecordingRuleResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Rule != nil { + size, err := m.Rule.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DeleteRecordingRuleRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteRecordingRuleRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteRecordingRuleRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DeleteRecordingRuleResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteRecordingRuleResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteRecordingRuleResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *RecordingRule) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RecordingRule) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *RecordingRule) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Provisioned { + i-- + if m.Provisioned { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x48 + } + if m.StacktraceFilter != nil { + size, err := m.StacktraceFilter.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } + if m.Generation != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Generation)) + i-- + dAtA[i] = 0x38 + } + if len(m.ExternalLabels) > 0 { + for iNdEx := len(m.ExternalLabels) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.ExternalLabels[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.ExternalLabels[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.GroupBy) > 0 { + for iNdEx := len(m.GroupBy) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.GroupBy[iNdEx]) + copy(dAtA[i:], m.GroupBy[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GroupBy[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.Matchers) > 0 { + for iNdEx := len(m.Matchers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Matchers[iNdEx]) + copy(dAtA[i:], m.Matchers[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Matchers[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.ProfileType) > 0 { + i -= len(m.ProfileType) + copy(dAtA[i:], m.ProfileType) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileType))) + i-- + dAtA[i] = 0x1a + } + if len(m.MetricName) > 0 { + i -= len(m.MetricName) + copy(dAtA[i:], m.MetricName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MetricName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StacktraceFilter) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StacktraceFilter) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StacktraceFilter) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.FunctionName != nil { + size, err := m.FunctionName.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StacktraceFilterFunctionName) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StacktraceFilterFunctionName) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StacktraceFilterFunctionName) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.MetricType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MetricType)) + i-- + dAtA[i] = 0x10 + } + if len(m.FunctionName) > 0 { + i -= len(m.FunctionName) + copy(dAtA[i:], m.FunctionName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FunctionName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RecordingRuleStore) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RecordingRuleStore) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *RecordingRuleStore) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.StacktraceFilter != nil { + size, err := m.StacktraceFilter.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } + if m.Generation != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Generation)) + i-- + dAtA[i] = 0x38 + } + if len(m.ExternalLabels) > 0 { + for iNdEx := len(m.ExternalLabels) - 1; iNdEx >= 0; iNdEx-- { + if vtmsg, ok := interface{}(m.ExternalLabels[iNdEx]).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.ExternalLabels[iNdEx]) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.GroupBy) > 0 { + for iNdEx := len(m.GroupBy) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.GroupBy[iNdEx]) + copy(dAtA[i:], m.GroupBy[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GroupBy[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.Matchers) > 0 { + for iNdEx := len(m.Matchers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Matchers[iNdEx]) + copy(dAtA[i:], m.Matchers[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Matchers[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.PrometheusDataSource) > 0 { + i -= len(m.PrometheusDataSource) + copy(dAtA[i:], m.PrometheusDataSource) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PrometheusDataSource))) + i-- + dAtA[i] = 0x1a + } + if len(m.MetricName) > 0 { + i -= len(m.MetricName) + copy(dAtA[i:], m.MetricName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MetricName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RecordingRulesStore) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RecordingRulesStore) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *RecordingRulesStore) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Generation != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Generation)) + i-- + dAtA[i] = 0x10 + } + if len(m.Rules) > 0 { + for iNdEx := len(m.Rules) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Rules[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *GetRecordingRuleRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *GetRecordingRuleResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Rule != nil { + l = m.Rule.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *ListRecordingRulesRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *ListRecordingRulesResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Rules) > 0 { + for _, e := range m.Rules { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *UpsertRecordingRuleRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.MetricName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Matchers) > 0 { + for _, s := range m.Matchers { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.GroupBy) > 0 { + for _, s := range m.GroupBy { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.ExternalLabels) > 0 { + for _, e := range m.ExternalLabels { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Generation != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Generation)) + } + if m.StacktraceFilter != nil { + l = m.StacktraceFilter.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *UpsertRecordingRuleResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Rule != nil { + l = m.Rule.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DeleteRecordingRuleRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DeleteRecordingRuleResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *RecordingRule) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.MetricName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.ProfileType) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Matchers) > 0 { + for _, s := range m.Matchers { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.GroupBy) > 0 { + for _, s := range m.GroupBy { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.ExternalLabels) > 0 { + for _, e := range m.ExternalLabels { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Generation != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Generation)) + } + if m.StacktraceFilter != nil { + l = m.StacktraceFilter.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Provisioned { + n += 2 + } + n += len(m.unknownFields) + return n +} + +func (m *StacktraceFilter) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.FunctionName != nil { + l = m.FunctionName.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *StacktraceFilterFunctionName) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FunctionName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.MetricType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MetricType)) + } + n += len(m.unknownFields) + return n +} + +func (m *RecordingRuleStore) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.MetricName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.PrometheusDataSource) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Matchers) > 0 { + for _, s := range m.Matchers { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.GroupBy) > 0 { + for _, s := range m.GroupBy { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.ExternalLabels) > 0 { + for _, e := range m.ExternalLabels { + if size, ok := interface{}(e).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(e) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Generation != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Generation)) + } + if m.StacktraceFilter != nil { + l = m.StacktraceFilter.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *RecordingRulesStore) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Rules) > 0 { + for _, e := range m.Rules { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.Generation != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Generation)) + } + n += len(m.unknownFields) + return n +} + +func (m *GetRecordingRuleRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetRecordingRuleRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetRecordingRuleRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetRecordingRuleResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetRecordingRuleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetRecordingRuleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rule", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Rule == nil { + m.Rule = &RecordingRule{} + } + if err := m.Rule.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListRecordingRulesRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListRecordingRulesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListRecordingRulesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListRecordingRulesResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListRecordingRulesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListRecordingRulesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rules", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rules = append(m.Rules, &RecordingRule{}) + if err := m.Rules[len(m.Rules)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpsertRecordingRuleRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpsertRecordingRuleRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpsertRecordingRuleRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetricName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Matchers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Matchers = append(m.Matchers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupBy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GroupBy = append(m.GroupBy, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExternalLabels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExternalLabels = append(m.ExternalLabels, &v1.LabelPair{}) + if unmarshal, ok := interface{}(m.ExternalLabels[len(m.ExternalLabels)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExternalLabels[len(m.ExternalLabels)-1]); err != nil { + return err + } + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Generation", wireType) + } + m.Generation = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Generation |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StacktraceFilter", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StacktraceFilter == nil { + m.StacktraceFilter = &StacktraceFilter{} + } + if err := m.StacktraceFilter.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpsertRecordingRuleResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpsertRecordingRuleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpsertRecordingRuleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rule", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Rule == nil { + m.Rule = &RecordingRule{} + } + if err := m.Rule.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteRecordingRuleRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteRecordingRuleRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteRecordingRuleRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteRecordingRuleResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteRecordingRuleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteRecordingRuleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RecordingRule) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RecordingRule: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RecordingRule: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetricName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Matchers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Matchers = append(m.Matchers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupBy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GroupBy = append(m.GroupBy, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExternalLabels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExternalLabels = append(m.ExternalLabels, &v1.LabelPair{}) + if unmarshal, ok := interface{}(m.ExternalLabels[len(m.ExternalLabels)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExternalLabels[len(m.ExternalLabels)-1]); err != nil { + return err + } + } + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Generation", wireType) + } + m.Generation = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Generation |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StacktraceFilter", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StacktraceFilter == nil { + m.StacktraceFilter = &StacktraceFilter{} + } + if err := m.StacktraceFilter.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Provisioned", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Provisioned = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StacktraceFilter) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StacktraceFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StacktraceFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FunctionName", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FunctionName == nil { + m.FunctionName = &StacktraceFilterFunctionName{} + } + if err := m.FunctionName.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StacktraceFilterFunctionName) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StacktraceFilterFunctionName: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StacktraceFilterFunctionName: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FunctionName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FunctionName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricType", wireType) + } + m.MetricType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MetricType |= MetricType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RecordingRuleStore) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RecordingRuleStore: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RecordingRuleStore: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetricName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PrometheusDataSource", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PrometheusDataSource = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Matchers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Matchers = append(m.Matchers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupBy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.GroupBy = append(m.GroupBy, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExternalLabels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExternalLabels = append(m.ExternalLabels, &v1.LabelPair{}) + if unmarshal, ok := interface{}(m.ExternalLabels[len(m.ExternalLabels)-1]).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExternalLabels[len(m.ExternalLabels)-1]); err != nil { + return err + } + } + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Generation", wireType) + } + m.Generation = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Generation |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StacktraceFilter", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StacktraceFilter == nil { + m.StacktraceFilter = &StacktraceFilter{} + } + if err := m.StacktraceFilter.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RecordingRulesStore) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RecordingRulesStore: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RecordingRulesStore: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rules", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rules = append(m.Rules, &RecordingRuleStore{}) + if err := m.Rules[len(m.Rules)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Generation", wireType) + } + m.Generation = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Generation |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/settings/v1/setting.pb.go b/api/gen/proto/go/settings/v1/setting.pb.go index fe25258daf..90964221cb 100644 --- a/api/gen/proto/go/settings/v1/setting.pb.go +++ b/api/gen/proto/go/settings/v1/setting.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: settings/v1/setting.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,18 +22,16 @@ const ( ) type GetSettingsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetSettingsRequest) Reset() { *x = GetSettingsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_settings_v1_setting_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_settings_v1_setting_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetSettingsRequest) String() string { @@ -43,7 +42,7 @@ func (*GetSettingsRequest) ProtoMessage() {} func (x *GetSettingsRequest) ProtoReflect() protoreflect.Message { mi := &file_settings_v1_setting_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -59,20 +58,17 @@ func (*GetSettingsRequest) Descriptor() ([]byte, []int) { } type GetSettingsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Settings []*Setting `protobuf:"bytes,1,rep,name=settings,proto3" json:"settings,omitempty"` unknownFields protoimpl.UnknownFields - - Settings []*Setting `protobuf:"bytes,1,rep,name=settings,proto3" json:"settings,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetSettingsResponse) Reset() { *x = GetSettingsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_settings_v1_setting_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_settings_v1_setting_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetSettingsResponse) String() string { @@ -83,7 +79,7 @@ func (*GetSettingsResponse) ProtoMessage() {} func (x *GetSettingsResponse) ProtoReflect() protoreflect.Message { mi := &file_settings_v1_setting_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -106,20 +102,17 @@ func (x *GetSettingsResponse) GetSettings() []*Setting { } type SetSettingsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Setting *Setting `protobuf:"bytes,1,opt,name=setting,proto3" json:"setting,omitempty"` unknownFields protoimpl.UnknownFields - - Setting *Setting `protobuf:"bytes,1,opt,name=setting,proto3" json:"setting,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetSettingsRequest) Reset() { *x = SetSettingsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_settings_v1_setting_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_settings_v1_setting_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetSettingsRequest) String() string { @@ -130,7 +123,7 @@ func (*SetSettingsRequest) ProtoMessage() {} func (x *SetSettingsRequest) ProtoReflect() protoreflect.Message { mi := &file_settings_v1_setting_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -153,20 +146,17 @@ func (x *SetSettingsRequest) GetSetting() *Setting { } type SetSettingsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Setting *Setting `protobuf:"bytes,1,opt,name=setting,proto3" json:"setting,omitempty"` unknownFields protoimpl.UnknownFields - - Setting *Setting `protobuf:"bytes,1,opt,name=setting,proto3" json:"setting,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SetSettingsResponse) Reset() { *x = SetSettingsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_settings_v1_setting_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_settings_v1_setting_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetSettingsResponse) String() string { @@ -177,7 +167,7 @@ func (*SetSettingsResponse) ProtoMessage() {} func (x *SetSettingsResponse) ProtoReflect() protoreflect.Message { mi := &file_settings_v1_setting_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -199,23 +189,100 @@ func (x *SetSettingsResponse) GetSetting() *Setting { return nil } -type Setting struct { - state protoimpl.MessageState +type DeleteSettingsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache +} + +func (x *DeleteSettingsRequest) Reset() { + *x = DeleteSettingsRequest{} + mi := &file_settings_v1_setting_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteSettingsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSettingsRequest) ProtoMessage() {} + +func (x *DeleteSettingsRequest) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_setting_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSettingsRequest.ProtoReflect.Descriptor instead. +func (*DeleteSettingsRequest) Descriptor() ([]byte, []int) { + return file_settings_v1_setting_proto_rawDescGZIP(), []int{4} +} + +func (x *DeleteSettingsRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type DeleteSettingsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` - ModifiedAt int64 `protobuf:"varint,3,opt,name=modifiedAt,proto3" json:"modifiedAt,omitempty"` +func (x *DeleteSettingsResponse) Reset() { + *x = DeleteSettingsResponse{} + mi := &file_settings_v1_setting_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *Setting) Reset() { - *x = Setting{} - if protoimpl.UnsafeEnabled { - mi := &file_settings_v1_setting_proto_msgTypes[4] +func (x *DeleteSettingsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSettingsResponse) ProtoMessage() {} + +func (x *DeleteSettingsResponse) ProtoReflect() protoreflect.Message { + mi := &file_settings_v1_setting_proto_msgTypes[5] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSettingsResponse.ProtoReflect.Descriptor instead. +func (*DeleteSettingsResponse) Descriptor() ([]byte, []int) { + return file_settings_v1_setting_proto_rawDescGZIP(), []int{5} +} + +type Setting struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + ModifiedAt int64 `protobuf:"varint,3,opt,name=modifiedAt,proto3" json:"modifiedAt,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Setting) Reset() { + *x = Setting{} + mi := &file_settings_v1_setting_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Setting) String() string { @@ -225,8 +292,8 @@ func (x *Setting) String() string { func (*Setting) ProtoMessage() {} func (x *Setting) ProtoReflect() protoreflect.Message { - mi := &file_settings_v1_setting_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_settings_v1_setting_proto_msgTypes[6] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -238,7 +305,7 @@ func (x *Setting) ProtoReflect() protoreflect.Message { // Deprecated: Use Setting.ProtoReflect.Descriptor instead. func (*Setting) Descriptor() ([]byte, []int) { - return file_settings_v1_setting_proto_rawDescGZIP(), []int{4} + return file_settings_v1_setting_proto_rawDescGZIP(), []int{6} } func (x *Setting) GetName() string { @@ -264,85 +331,65 @@ func (x *Setting) GetModifiedAt() int64 { var File_settings_v1_setting_proto protoreflect.FileDescriptor -var file_settings_v1_setting_proto_rawDesc = []byte{ - 0x0a, 0x19, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x47, - 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x44, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, - 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x45, 0x0a, - 0x13, 0x53, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x22, 0x53, 0x0a, 0x07, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6d, - 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, 0x74, 0x32, 0xa9, 0x01, 0x0a, 0x0f, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, - 0x03, 0x47, 0x65, 0x74, 0x12, 0x1f, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x03, 0x53, 0x65, 0x74, - 0x12, 0x1f, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xb2, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, - 0x72, 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x76, 0x31, 0xa2, - 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x5c, 0x56, - 0x31, 0xe2, 0x02, 0x17, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x5c, 0x56, 0x31, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, -} +const file_settings_v1_setting_proto_rawDesc = "" + + "\n" + + "\x19settings/v1/setting.proto\x12\vsettings.v1\"\x14\n" + + "\x12GetSettingsRequest\"G\n" + + "\x13GetSettingsResponse\x120\n" + + "\bsettings\x18\x01 \x03(\v2\x14.settings.v1.SettingR\bsettings\"D\n" + + "\x12SetSettingsRequest\x12.\n" + + "\asetting\x18\x01 \x01(\v2\x14.settings.v1.SettingR\asetting\"E\n" + + "\x13SetSettingsResponse\x12.\n" + + "\asetting\x18\x01 \x01(\v2\x14.settings.v1.SettingR\asetting\"+\n" + + "\x15DeleteSettingsRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"\x18\n" + + "\x16DeleteSettingsResponse\"S\n" + + "\aSetting\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value\x12\x1e\n" + + "\n" + + "modifiedAt\x18\x03 \x01(\x03R\n" + + "modifiedAt2\xfe\x01\n" + + "\x0fSettingsService\x12J\n" + + "\x03Get\x12\x1f.settings.v1.GetSettingsRequest\x1a .settings.v1.GetSettingsResponse\"\x00\x12J\n" + + "\x03Set\x12\x1f.settings.v1.SetSettingsRequest\x1a .settings.v1.SetSettingsResponse\"\x00\x12S\n" + + "\x06Delete\x12\".settings.v1.DeleteSettingsRequest\x1a#.settings.v1.DeleteSettingsResponse\"\x00B\xb2\x01\n" + + "\x0fcom.settings.v1B\fSettingProtoP\x01ZDgithub.com/grafana/pyroscope/api/gen/proto/go/settings/v1;settingsv1\xa2\x02\x03SXX\xaa\x02\vSettings.V1\xca\x02\vSettings\\V1\xe2\x02\x17Settings\\V1\\GPBMetadata\xea\x02\fSettings::V1b\x06proto3" var ( file_settings_v1_setting_proto_rawDescOnce sync.Once - file_settings_v1_setting_proto_rawDescData = file_settings_v1_setting_proto_rawDesc + file_settings_v1_setting_proto_rawDescData []byte ) func file_settings_v1_setting_proto_rawDescGZIP() []byte { file_settings_v1_setting_proto_rawDescOnce.Do(func() { - file_settings_v1_setting_proto_rawDescData = protoimpl.X.CompressGZIP(file_settings_v1_setting_proto_rawDescData) + file_settings_v1_setting_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_settings_v1_setting_proto_rawDesc), len(file_settings_v1_setting_proto_rawDesc))) }) return file_settings_v1_setting_proto_rawDescData } -var file_settings_v1_setting_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_settings_v1_setting_proto_goTypes = []interface{}{ - (*GetSettingsRequest)(nil), // 0: settings.v1.GetSettingsRequest - (*GetSettingsResponse)(nil), // 1: settings.v1.GetSettingsResponse - (*SetSettingsRequest)(nil), // 2: settings.v1.SetSettingsRequest - (*SetSettingsResponse)(nil), // 3: settings.v1.SetSettingsResponse - (*Setting)(nil), // 4: settings.v1.Setting +var file_settings_v1_setting_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_settings_v1_setting_proto_goTypes = []any{ + (*GetSettingsRequest)(nil), // 0: settings.v1.GetSettingsRequest + (*GetSettingsResponse)(nil), // 1: settings.v1.GetSettingsResponse + (*SetSettingsRequest)(nil), // 2: settings.v1.SetSettingsRequest + (*SetSettingsResponse)(nil), // 3: settings.v1.SetSettingsResponse + (*DeleteSettingsRequest)(nil), // 4: settings.v1.DeleteSettingsRequest + (*DeleteSettingsResponse)(nil), // 5: settings.v1.DeleteSettingsResponse + (*Setting)(nil), // 6: settings.v1.Setting } var file_settings_v1_setting_proto_depIdxs = []int32{ - 4, // 0: settings.v1.GetSettingsResponse.settings:type_name -> settings.v1.Setting - 4, // 1: settings.v1.SetSettingsRequest.setting:type_name -> settings.v1.Setting - 4, // 2: settings.v1.SetSettingsResponse.setting:type_name -> settings.v1.Setting + 6, // 0: settings.v1.GetSettingsResponse.settings:type_name -> settings.v1.Setting + 6, // 1: settings.v1.SetSettingsRequest.setting:type_name -> settings.v1.Setting + 6, // 2: settings.v1.SetSettingsResponse.setting:type_name -> settings.v1.Setting 0, // 3: settings.v1.SettingsService.Get:input_type -> settings.v1.GetSettingsRequest 2, // 4: settings.v1.SettingsService.Set:input_type -> settings.v1.SetSettingsRequest - 1, // 5: settings.v1.SettingsService.Get:output_type -> settings.v1.GetSettingsResponse - 3, // 6: settings.v1.SettingsService.Set:output_type -> settings.v1.SetSettingsResponse - 5, // [5:7] is the sub-list for method output_type - 3, // [3:5] is the sub-list for method input_type + 4, // 5: settings.v1.SettingsService.Delete:input_type -> settings.v1.DeleteSettingsRequest + 1, // 6: settings.v1.SettingsService.Get:output_type -> settings.v1.GetSettingsResponse + 3, // 7: settings.v1.SettingsService.Set:output_type -> settings.v1.SetSettingsResponse + 5, // 8: settings.v1.SettingsService.Delete:output_type -> settings.v1.DeleteSettingsResponse + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name 3, // [3:3] is the sub-list for extension extendee 0, // [0:3] is the sub-list for field type_name @@ -353,75 +400,13 @@ func file_settings_v1_setting_proto_init() { if File_settings_v1_setting_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_settings_v1_setting_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSettingsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_settings_v1_setting_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSettingsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_settings_v1_setting_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SetSettingsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_settings_v1_setting_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SetSettingsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_settings_v1_setting_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Setting); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_settings_v1_setting_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_settings_v1_setting_proto_rawDesc), len(file_settings_v1_setting_proto_rawDesc)), NumEnums: 0, - NumMessages: 5, + NumMessages: 7, NumExtensions: 0, NumServices: 1, }, @@ -430,7 +415,6 @@ func file_settings_v1_setting_proto_init() { MessageInfos: file_settings_v1_setting_proto_msgTypes, }.Build() File_settings_v1_setting_proto = out.File - file_settings_v1_setting_proto_rawDesc = nil file_settings_v1_setting_proto_goTypes = nil file_settings_v1_setting_proto_depIdxs = nil } diff --git a/api/gen/proto/go/settings/v1/setting_vtproto.pb.go b/api/gen/proto/go/settings/v1/setting_vtproto.pb.go index ce4853fd6b..64ddbfad97 100644 --- a/api/gen/proto/go/settings/v1/setting_vtproto.pb.go +++ b/api/gen/proto/go/settings/v1/setting_vtproto.pb.go @@ -96,6 +96,39 @@ func (m *SetSettingsResponse) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *DeleteSettingsRequest) CloneVT() *DeleteSettingsRequest { + if m == nil { + return (*DeleteSettingsRequest)(nil) + } + r := new(DeleteSettingsRequest) + r.Name = m.Name + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteSettingsRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *DeleteSettingsResponse) CloneVT() *DeleteSettingsResponse { + if m == nil { + return (*DeleteSettingsResponse)(nil) + } + r := new(DeleteSettingsResponse) + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *DeleteSettingsResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *Setting) CloneVT() *Setting { if m == nil { return (*Setting)(nil) @@ -202,6 +235,41 @@ func (this *SetSettingsResponse) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *DeleteSettingsRequest) EqualVT(that *DeleteSettingsRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Name != that.Name { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteSettingsRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteSettingsRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *DeleteSettingsResponse) EqualVT(that *DeleteSettingsResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *DeleteSettingsResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*DeleteSettingsResponse) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *Setting) EqualVT(that *Setting) bool { if this == that { return true @@ -239,6 +307,7 @@ const _ = grpc.SupportPackageIsVersion7 type SettingsServiceClient interface { Get(ctx context.Context, in *GetSettingsRequest, opts ...grpc.CallOption) (*GetSettingsResponse, error) Set(ctx context.Context, in *SetSettingsRequest, opts ...grpc.CallOption) (*SetSettingsResponse, error) + Delete(ctx context.Context, in *DeleteSettingsRequest, opts ...grpc.CallOption) (*DeleteSettingsResponse, error) } type settingsServiceClient struct { @@ -267,12 +336,22 @@ func (c *settingsServiceClient) Set(ctx context.Context, in *SetSettingsRequest, return out, nil } +func (c *settingsServiceClient) Delete(ctx context.Context, in *DeleteSettingsRequest, opts ...grpc.CallOption) (*DeleteSettingsResponse, error) { + out := new(DeleteSettingsResponse) + err := c.cc.Invoke(ctx, "/settings.v1.SettingsService/Delete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // SettingsServiceServer is the server API for SettingsService service. // All implementations must embed UnimplementedSettingsServiceServer // for forward compatibility type SettingsServiceServer interface { Get(context.Context, *GetSettingsRequest) (*GetSettingsResponse, error) Set(context.Context, *SetSettingsRequest) (*SetSettingsResponse, error) + Delete(context.Context, *DeleteSettingsRequest) (*DeleteSettingsResponse, error) mustEmbedUnimplementedSettingsServiceServer() } @@ -286,6 +365,9 @@ func (UnimplementedSettingsServiceServer) Get(context.Context, *GetSettingsReque func (UnimplementedSettingsServiceServer) Set(context.Context, *SetSettingsRequest) (*SetSettingsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Set not implemented") } +func (UnimplementedSettingsServiceServer) Delete(context.Context, *DeleteSettingsRequest) (*DeleteSettingsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") +} func (UnimplementedSettingsServiceServer) mustEmbedUnimplementedSettingsServiceServer() {} // UnsafeSettingsServiceServer may be embedded to opt out of forward compatibility for this service. @@ -335,6 +417,24 @@ func _SettingsService_Set_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } +func _SettingsService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSettingsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SettingsServiceServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/settings.v1.SettingsService/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SettingsServiceServer).Delete(ctx, req.(*DeleteSettingsRequest)) + } + return interceptor(ctx, in, info, handler) +} + // SettingsService_ServiceDesc is the grpc.ServiceDesc for SettingsService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -350,6 +450,10 @@ var SettingsService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Set", Handler: _SettingsService_Set_Handler, }, + { + MethodName: "Delete", + Handler: _SettingsService_Delete_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "settings/v1/setting.proto", @@ -519,6 +623,79 @@ func (m *SetSettingsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *DeleteSettingsRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteSettingsRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteSettingsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DeleteSettingsResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteSettingsResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DeleteSettingsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + func (m *Setting) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -625,6 +802,30 @@ func (m *SetSettingsResponse) SizeVT() (n int) { return n } +func (m *DeleteSettingsRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DeleteSettingsResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + func (m *Setting) SizeVT() (n int) { if m == nil { return 0 @@ -956,6 +1157,140 @@ func (m *SetSettingsResponse) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *DeleteSettingsRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteSettingsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteSettingsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteSettingsResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeleteSettingsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteSettingsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Setting) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/api/gen/proto/go/settings/v1/settingsv1connect/recording_rules.connect.go b/api/gen/proto/go/settings/v1/settingsv1connect/recording_rules.connect.go new file mode 100644 index 0000000000..c1620f728d --- /dev/null +++ b/api/gen/proto/go/settings/v1/settingsv1connect/recording_rules.connect.go @@ -0,0 +1,197 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: settings/v1/recording_rules.proto + +package settingsv1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // RecordingRulesServiceName is the fully-qualified name of the RecordingRulesService service. + RecordingRulesServiceName = "settings.v1.RecordingRulesService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // RecordingRulesServiceGetRecordingRuleProcedure is the fully-qualified name of the + // RecordingRulesService's GetRecordingRule RPC. + RecordingRulesServiceGetRecordingRuleProcedure = "/settings.v1.RecordingRulesService/GetRecordingRule" + // RecordingRulesServiceListRecordingRulesProcedure is the fully-qualified name of the + // RecordingRulesService's ListRecordingRules RPC. + RecordingRulesServiceListRecordingRulesProcedure = "/settings.v1.RecordingRulesService/ListRecordingRules" + // RecordingRulesServiceUpsertRecordingRuleProcedure is the fully-qualified name of the + // RecordingRulesService's UpsertRecordingRule RPC. + RecordingRulesServiceUpsertRecordingRuleProcedure = "/settings.v1.RecordingRulesService/UpsertRecordingRule" + // RecordingRulesServiceDeleteRecordingRuleProcedure is the fully-qualified name of the + // RecordingRulesService's DeleteRecordingRule RPC. + RecordingRulesServiceDeleteRecordingRuleProcedure = "/settings.v1.RecordingRulesService/DeleteRecordingRule" +) + +// RecordingRulesServiceClient is a client for the settings.v1.RecordingRulesService service. +type RecordingRulesServiceClient interface { + GetRecordingRule(context.Context, *connect.Request[v1.GetRecordingRuleRequest]) (*connect.Response[v1.GetRecordingRuleResponse], error) + ListRecordingRules(context.Context, *connect.Request[v1.ListRecordingRulesRequest]) (*connect.Response[v1.ListRecordingRulesResponse], error) + UpsertRecordingRule(context.Context, *connect.Request[v1.UpsertRecordingRuleRequest]) (*connect.Response[v1.UpsertRecordingRuleResponse], error) + DeleteRecordingRule(context.Context, *connect.Request[v1.DeleteRecordingRuleRequest]) (*connect.Response[v1.DeleteRecordingRuleResponse], error) +} + +// NewRecordingRulesServiceClient constructs a client for the settings.v1.RecordingRulesService +// service. By default, it uses the Connect protocol with the binary Protobuf Codec, asks for +// gzipped responses, and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply +// the connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewRecordingRulesServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) RecordingRulesServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + recordingRulesServiceMethods := v1.File_settings_v1_recording_rules_proto.Services().ByName("RecordingRulesService").Methods() + return &recordingRulesServiceClient{ + getRecordingRule: connect.NewClient[v1.GetRecordingRuleRequest, v1.GetRecordingRuleResponse]( + httpClient, + baseURL+RecordingRulesServiceGetRecordingRuleProcedure, + connect.WithSchema(recordingRulesServiceMethods.ByName("GetRecordingRule")), + connect.WithClientOptions(opts...), + ), + listRecordingRules: connect.NewClient[v1.ListRecordingRulesRequest, v1.ListRecordingRulesResponse]( + httpClient, + baseURL+RecordingRulesServiceListRecordingRulesProcedure, + connect.WithSchema(recordingRulesServiceMethods.ByName("ListRecordingRules")), + connect.WithClientOptions(opts...), + ), + upsertRecordingRule: connect.NewClient[v1.UpsertRecordingRuleRequest, v1.UpsertRecordingRuleResponse]( + httpClient, + baseURL+RecordingRulesServiceUpsertRecordingRuleProcedure, + connect.WithSchema(recordingRulesServiceMethods.ByName("UpsertRecordingRule")), + connect.WithClientOptions(opts...), + ), + deleteRecordingRule: connect.NewClient[v1.DeleteRecordingRuleRequest, v1.DeleteRecordingRuleResponse]( + httpClient, + baseURL+RecordingRulesServiceDeleteRecordingRuleProcedure, + connect.WithSchema(recordingRulesServiceMethods.ByName("DeleteRecordingRule")), + connect.WithClientOptions(opts...), + ), + } +} + +// recordingRulesServiceClient implements RecordingRulesServiceClient. +type recordingRulesServiceClient struct { + getRecordingRule *connect.Client[v1.GetRecordingRuleRequest, v1.GetRecordingRuleResponse] + listRecordingRules *connect.Client[v1.ListRecordingRulesRequest, v1.ListRecordingRulesResponse] + upsertRecordingRule *connect.Client[v1.UpsertRecordingRuleRequest, v1.UpsertRecordingRuleResponse] + deleteRecordingRule *connect.Client[v1.DeleteRecordingRuleRequest, v1.DeleteRecordingRuleResponse] +} + +// GetRecordingRule calls settings.v1.RecordingRulesService.GetRecordingRule. +func (c *recordingRulesServiceClient) GetRecordingRule(ctx context.Context, req *connect.Request[v1.GetRecordingRuleRequest]) (*connect.Response[v1.GetRecordingRuleResponse], error) { + return c.getRecordingRule.CallUnary(ctx, req) +} + +// ListRecordingRules calls settings.v1.RecordingRulesService.ListRecordingRules. +func (c *recordingRulesServiceClient) ListRecordingRules(ctx context.Context, req *connect.Request[v1.ListRecordingRulesRequest]) (*connect.Response[v1.ListRecordingRulesResponse], error) { + return c.listRecordingRules.CallUnary(ctx, req) +} + +// UpsertRecordingRule calls settings.v1.RecordingRulesService.UpsertRecordingRule. +func (c *recordingRulesServiceClient) UpsertRecordingRule(ctx context.Context, req *connect.Request[v1.UpsertRecordingRuleRequest]) (*connect.Response[v1.UpsertRecordingRuleResponse], error) { + return c.upsertRecordingRule.CallUnary(ctx, req) +} + +// DeleteRecordingRule calls settings.v1.RecordingRulesService.DeleteRecordingRule. +func (c *recordingRulesServiceClient) DeleteRecordingRule(ctx context.Context, req *connect.Request[v1.DeleteRecordingRuleRequest]) (*connect.Response[v1.DeleteRecordingRuleResponse], error) { + return c.deleteRecordingRule.CallUnary(ctx, req) +} + +// RecordingRulesServiceHandler is an implementation of the settings.v1.RecordingRulesService +// service. +type RecordingRulesServiceHandler interface { + GetRecordingRule(context.Context, *connect.Request[v1.GetRecordingRuleRequest]) (*connect.Response[v1.GetRecordingRuleResponse], error) + ListRecordingRules(context.Context, *connect.Request[v1.ListRecordingRulesRequest]) (*connect.Response[v1.ListRecordingRulesResponse], error) + UpsertRecordingRule(context.Context, *connect.Request[v1.UpsertRecordingRuleRequest]) (*connect.Response[v1.UpsertRecordingRuleResponse], error) + DeleteRecordingRule(context.Context, *connect.Request[v1.DeleteRecordingRuleRequest]) (*connect.Response[v1.DeleteRecordingRuleResponse], error) +} + +// NewRecordingRulesServiceHandler builds an HTTP handler from the service implementation. It +// returns the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewRecordingRulesServiceHandler(svc RecordingRulesServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + recordingRulesServiceMethods := v1.File_settings_v1_recording_rules_proto.Services().ByName("RecordingRulesService").Methods() + recordingRulesServiceGetRecordingRuleHandler := connect.NewUnaryHandler( + RecordingRulesServiceGetRecordingRuleProcedure, + svc.GetRecordingRule, + connect.WithSchema(recordingRulesServiceMethods.ByName("GetRecordingRule")), + connect.WithHandlerOptions(opts...), + ) + recordingRulesServiceListRecordingRulesHandler := connect.NewUnaryHandler( + RecordingRulesServiceListRecordingRulesProcedure, + svc.ListRecordingRules, + connect.WithSchema(recordingRulesServiceMethods.ByName("ListRecordingRules")), + connect.WithHandlerOptions(opts...), + ) + recordingRulesServiceUpsertRecordingRuleHandler := connect.NewUnaryHandler( + RecordingRulesServiceUpsertRecordingRuleProcedure, + svc.UpsertRecordingRule, + connect.WithSchema(recordingRulesServiceMethods.ByName("UpsertRecordingRule")), + connect.WithHandlerOptions(opts...), + ) + recordingRulesServiceDeleteRecordingRuleHandler := connect.NewUnaryHandler( + RecordingRulesServiceDeleteRecordingRuleProcedure, + svc.DeleteRecordingRule, + connect.WithSchema(recordingRulesServiceMethods.ByName("DeleteRecordingRule")), + connect.WithHandlerOptions(opts...), + ) + return "/settings.v1.RecordingRulesService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case RecordingRulesServiceGetRecordingRuleProcedure: + recordingRulesServiceGetRecordingRuleHandler.ServeHTTP(w, r) + case RecordingRulesServiceListRecordingRulesProcedure: + recordingRulesServiceListRecordingRulesHandler.ServeHTTP(w, r) + case RecordingRulesServiceUpsertRecordingRuleProcedure: + recordingRulesServiceUpsertRecordingRuleHandler.ServeHTTP(w, r) + case RecordingRulesServiceDeleteRecordingRuleProcedure: + recordingRulesServiceDeleteRecordingRuleHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedRecordingRulesServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedRecordingRulesServiceHandler struct{} + +func (UnimplementedRecordingRulesServiceHandler) GetRecordingRule(context.Context, *connect.Request[v1.GetRecordingRuleRequest]) (*connect.Response[v1.GetRecordingRuleResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("settings.v1.RecordingRulesService.GetRecordingRule is not implemented")) +} + +func (UnimplementedRecordingRulesServiceHandler) ListRecordingRules(context.Context, *connect.Request[v1.ListRecordingRulesRequest]) (*connect.Response[v1.ListRecordingRulesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("settings.v1.RecordingRulesService.ListRecordingRules is not implemented")) +} + +func (UnimplementedRecordingRulesServiceHandler) UpsertRecordingRule(context.Context, *connect.Request[v1.UpsertRecordingRuleRequest]) (*connect.Response[v1.UpsertRecordingRuleResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("settings.v1.RecordingRulesService.UpsertRecordingRule is not implemented")) +} + +func (UnimplementedRecordingRulesServiceHandler) DeleteRecordingRule(context.Context, *connect.Request[v1.DeleteRecordingRuleRequest]) (*connect.Response[v1.DeleteRecordingRuleResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("settings.v1.RecordingRulesService.DeleteRecordingRule is not implemented")) +} diff --git a/api/gen/proto/go/settings/v1/settingsv1connect/recording_rules.connect.mux.go b/api/gen/proto/go/settings/v1/settingsv1connect/recording_rules.connect.mux.go new file mode 100644 index 0000000000..677a1534c4 --- /dev/null +++ b/api/gen/proto/go/settings/v1/settingsv1connect/recording_rules.connect.mux.go @@ -0,0 +1,42 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: settings/v1/recording_rules.proto + +package settingsv1connect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterRecordingRulesServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterRecordingRulesServiceHandler(mux *mux.Router, svc RecordingRulesServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/settings.v1.RecordingRulesService/GetRecordingRule", connect.NewUnaryHandler( + "/settings.v1.RecordingRulesService/GetRecordingRule", + svc.GetRecordingRule, + opts..., + )) + mux.Handle("/settings.v1.RecordingRulesService/ListRecordingRules", connect.NewUnaryHandler( + "/settings.v1.RecordingRulesService/ListRecordingRules", + svc.ListRecordingRules, + opts..., + )) + mux.Handle("/settings.v1.RecordingRulesService/UpsertRecordingRule", connect.NewUnaryHandler( + "/settings.v1.RecordingRulesService/UpsertRecordingRule", + svc.UpsertRecordingRule, + opts..., + )) + mux.Handle("/settings.v1.RecordingRulesService/DeleteRecordingRule", connect.NewUnaryHandler( + "/settings.v1.RecordingRulesService/DeleteRecordingRule", + svc.DeleteRecordingRule, + opts..., + )) +} diff --git a/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.go b/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.go index a053c45aae..a2fa092803 100644 --- a/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.go +++ b/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.go @@ -37,19 +37,15 @@ const ( SettingsServiceGetProcedure = "/settings.v1.SettingsService/Get" // SettingsServiceSetProcedure is the fully-qualified name of the SettingsService's Set RPC. SettingsServiceSetProcedure = "/settings.v1.SettingsService/Set" -) - -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - settingsServiceServiceDescriptor = v1.File_settings_v1_setting_proto.Services().ByName("SettingsService") - settingsServiceGetMethodDescriptor = settingsServiceServiceDescriptor.Methods().ByName("Get") - settingsServiceSetMethodDescriptor = settingsServiceServiceDescriptor.Methods().ByName("Set") + // SettingsServiceDeleteProcedure is the fully-qualified name of the SettingsService's Delete RPC. + SettingsServiceDeleteProcedure = "/settings.v1.SettingsService/Delete" ) // SettingsServiceClient is a client for the settings.v1.SettingsService service. type SettingsServiceClient interface { Get(context.Context, *connect.Request[v1.GetSettingsRequest]) (*connect.Response[v1.GetSettingsResponse], error) Set(context.Context, *connect.Request[v1.SetSettingsRequest]) (*connect.Response[v1.SetSettingsResponse], error) + Delete(context.Context, *connect.Request[v1.DeleteSettingsRequest]) (*connect.Response[v1.DeleteSettingsResponse], error) } // NewSettingsServiceClient constructs a client for the settings.v1.SettingsService service. By @@ -61,17 +57,24 @@ type SettingsServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewSettingsServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) SettingsServiceClient { baseURL = strings.TrimRight(baseURL, "/") + settingsServiceMethods := v1.File_settings_v1_setting_proto.Services().ByName("SettingsService").Methods() return &settingsServiceClient{ get: connect.NewClient[v1.GetSettingsRequest, v1.GetSettingsResponse]( httpClient, baseURL+SettingsServiceGetProcedure, - connect.WithSchema(settingsServiceGetMethodDescriptor), + connect.WithSchema(settingsServiceMethods.ByName("Get")), connect.WithClientOptions(opts...), ), set: connect.NewClient[v1.SetSettingsRequest, v1.SetSettingsResponse]( httpClient, baseURL+SettingsServiceSetProcedure, - connect.WithSchema(settingsServiceSetMethodDescriptor), + connect.WithSchema(settingsServiceMethods.ByName("Set")), + connect.WithClientOptions(opts...), + ), + delete: connect.NewClient[v1.DeleteSettingsRequest, v1.DeleteSettingsResponse]( + httpClient, + baseURL+SettingsServiceDeleteProcedure, + connect.WithSchema(settingsServiceMethods.ByName("Delete")), connect.WithClientOptions(opts...), ), } @@ -79,8 +82,9 @@ func NewSettingsServiceClient(httpClient connect.HTTPClient, baseURL string, opt // settingsServiceClient implements SettingsServiceClient. type settingsServiceClient struct { - get *connect.Client[v1.GetSettingsRequest, v1.GetSettingsResponse] - set *connect.Client[v1.SetSettingsRequest, v1.SetSettingsResponse] + get *connect.Client[v1.GetSettingsRequest, v1.GetSettingsResponse] + set *connect.Client[v1.SetSettingsRequest, v1.SetSettingsResponse] + delete *connect.Client[v1.DeleteSettingsRequest, v1.DeleteSettingsResponse] } // Get calls settings.v1.SettingsService.Get. @@ -93,10 +97,16 @@ func (c *settingsServiceClient) Set(ctx context.Context, req *connect.Request[v1 return c.set.CallUnary(ctx, req) } +// Delete calls settings.v1.SettingsService.Delete. +func (c *settingsServiceClient) Delete(ctx context.Context, req *connect.Request[v1.DeleteSettingsRequest]) (*connect.Response[v1.DeleteSettingsResponse], error) { + return c.delete.CallUnary(ctx, req) +} + // SettingsServiceHandler is an implementation of the settings.v1.SettingsService service. type SettingsServiceHandler interface { Get(context.Context, *connect.Request[v1.GetSettingsRequest]) (*connect.Response[v1.GetSettingsResponse], error) Set(context.Context, *connect.Request[v1.SetSettingsRequest]) (*connect.Response[v1.SetSettingsResponse], error) + Delete(context.Context, *connect.Request[v1.DeleteSettingsRequest]) (*connect.Response[v1.DeleteSettingsResponse], error) } // NewSettingsServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -105,16 +115,23 @@ type SettingsServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewSettingsServiceHandler(svc SettingsServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + settingsServiceMethods := v1.File_settings_v1_setting_proto.Services().ByName("SettingsService").Methods() settingsServiceGetHandler := connect.NewUnaryHandler( SettingsServiceGetProcedure, svc.Get, - connect.WithSchema(settingsServiceGetMethodDescriptor), + connect.WithSchema(settingsServiceMethods.ByName("Get")), connect.WithHandlerOptions(opts...), ) settingsServiceSetHandler := connect.NewUnaryHandler( SettingsServiceSetProcedure, svc.Set, - connect.WithSchema(settingsServiceSetMethodDescriptor), + connect.WithSchema(settingsServiceMethods.ByName("Set")), + connect.WithHandlerOptions(opts...), + ) + settingsServiceDeleteHandler := connect.NewUnaryHandler( + SettingsServiceDeleteProcedure, + svc.Delete, + connect.WithSchema(settingsServiceMethods.ByName("Delete")), connect.WithHandlerOptions(opts...), ) return "/settings.v1.SettingsService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -123,6 +140,8 @@ func NewSettingsServiceHandler(svc SettingsServiceHandler, opts ...connect.Handl settingsServiceGetHandler.ServeHTTP(w, r) case SettingsServiceSetProcedure: settingsServiceSetHandler.ServeHTTP(w, r) + case SettingsServiceDeleteProcedure: + settingsServiceDeleteHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -139,3 +158,7 @@ func (UnimplementedSettingsServiceHandler) Get(context.Context, *connect.Request func (UnimplementedSettingsServiceHandler) Set(context.Context, *connect.Request[v1.SetSettingsRequest]) (*connect.Response[v1.SetSettingsResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("settings.v1.SettingsService.Set is not implemented")) } + +func (UnimplementedSettingsServiceHandler) Delete(context.Context, *connect.Request[v1.DeleteSettingsRequest]) (*connect.Response[v1.DeleteSettingsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("settings.v1.SettingsService.Delete is not implemented")) +} diff --git a/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.mux.go b/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.mux.go index 8ae527a905..8e17c144b2 100644 --- a/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.mux.go +++ b/api/gen/proto/go/settings/v1/settingsv1connect/setting.connect.mux.go @@ -29,4 +29,9 @@ func RegisterSettingsServiceHandler(mux *mux.Router, svc SettingsServiceHandler, svc.Set, opts..., )) + mux.Handle("/settings.v1.SettingsService/Delete", connect.NewUnaryHandler( + "/settings.v1.SettingsService/Delete", + svc.Delete, + opts..., + )) } diff --git a/api/gen/proto/go/status/v1/status.pb.go b/api/gen/proto/go/status/v1/status.pb.go index dbf3e21ef2..b1aca0b77e 100644 --- a/api/gen/proto/go/status/v1/status.pb.go +++ b/api/gen/proto/go/status/v1/status.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: status/v1/status.proto @@ -13,6 +13,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -23,18 +24,16 @@ const ( ) type GetBuildInfoRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetBuildInfoRequest) Reset() { *x = GetBuildInfoRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_status_v1_status_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_status_v1_status_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetBuildInfoRequest) String() string { @@ -45,7 +44,7 @@ func (*GetBuildInfoRequest) ProtoMessage() {} func (x *GetBuildInfoRequest) ProtoReflect() protoreflect.Message { mi := &file_status_v1_status_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -61,21 +60,18 @@ func (*GetBuildInfoRequest) Descriptor() ([]byte, []int) { } type GetBuildInfoResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + Data *GetBuildInfoData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields - - Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - Data *GetBuildInfoData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetBuildInfoResponse) Reset() { *x = GetBuildInfoResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_status_v1_status_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_status_v1_status_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetBuildInfoResponse) String() string { @@ -86,7 +82,7 @@ func (*GetBuildInfoResponse) ProtoMessage() {} func (x *GetBuildInfoResponse) ProtoReflect() protoreflect.Message { mi := &file_status_v1_status_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -116,25 +112,22 @@ func (x *GetBuildInfoResponse) GetData() *GetBuildInfoData { } type GetBuildInfoData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"` + Branch string `protobuf:"bytes,3,opt,name=branch,proto3" json:"branch,omitempty"` + BuildUser string `protobuf:"bytes,4,opt,name=build_user,json=buildUser,proto3" json:"build_user,omitempty"` + BuildDate string `protobuf:"bytes,5,opt,name=build_date,json=buildDate,proto3" json:"build_date,omitempty"` + GoVersion string `protobuf:"bytes,6,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"` unknownFields protoimpl.UnknownFields - - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` - Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"` - Branch string `protobuf:"bytes,3,opt,name=branch,proto3" json:"branch,omitempty"` - BuildUser string `protobuf:"bytes,4,opt,name=build_user,json=buildUser,proto3" json:"build_user,omitempty"` - BuildDate string `protobuf:"bytes,5,opt,name=build_date,json=buildDate,proto3" json:"build_date,omitempty"` - GoVersion string `protobuf:"bytes,6,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetBuildInfoData) Reset() { *x = GetBuildInfoData{} - if protoimpl.UnsafeEnabled { - mi := &file_status_v1_status_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_status_v1_status_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetBuildInfoData) String() string { @@ -145,7 +138,7 @@ func (*GetBuildInfoData) ProtoMessage() {} func (x *GetBuildInfoData) ProtoReflect() protoreflect.Message { mi := &file_status_v1_status_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -203,18 +196,16 @@ func (x *GetBuildInfoData) GetGoVersion() string { } type GetConfigRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetConfigRequest) Reset() { *x = GetConfigRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_status_v1_status_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_status_v1_status_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetConfigRequest) String() string { @@ -225,7 +216,7 @@ func (*GetConfigRequest) ProtoMessage() {} func (x *GetConfigRequest) ProtoReflect() protoreflect.Message { mi := &file_status_v1_status_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -241,18 +232,16 @@ func (*GetConfigRequest) Descriptor() ([]byte, []int) { } type GetConfigResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetConfigResponse) Reset() { *x = GetConfigResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_status_v1_status_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_status_v1_status_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetConfigResponse) String() string { @@ -263,7 +252,7 @@ func (*GetConfigResponse) ProtoMessage() {} func (x *GetConfigResponse) ProtoReflect() protoreflect.Message { mi := &file_status_v1_status_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -280,90 +269,47 @@ func (*GetConfigResponse) Descriptor() ([]byte, []int) { var File_status_v1_status_proto protoreflect.FileDescriptor -var file_status_v1_status_proto_rawDesc = []byte{ - 0x0a, 0x16, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x74, - 0x74, 0x70, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x15, 0x0a, 0x13, - 0x47, 0x65, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x5f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, - 0x64, 0x61, 0x74, 0x61, 0x22, 0xbd, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x16, 0x0a, 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, - 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, - 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, - 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6f, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x13, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb7, 0x03, - 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x71, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x1e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x6e, - 0x66, 0x6f, 0x12, 0x5d, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x1b, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, - 0x64, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x66, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x44, 0x69, 0x66, 0x66, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x1b, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, - 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x64, 0x69, 0x66, 0x66, 0x12, 0x6c, 0x0a, 0x10, 0x47, 0x65, 0x74, - 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1b, 0x2e, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, - 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0xa3, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, - 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x76, - 0x31, 0x3b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, - 0xaa, 0x02, 0x09, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_status_v1_status_proto_rawDesc = "" + + "\n" + + "\x16status/v1/status.proto\x12\tstatus.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x19google/api/httpbody.proto\"\x15\n" + + "\x13GetBuildInfoRequest\"_\n" + + "\x14GetBuildInfoResponse\x12\x16\n" + + "\x06status\x18\x01 \x01(\tR\x06status\x12/\n" + + "\x04data\x18\x02 \x01(\v2\x1b.status.v1.GetBuildInfoDataR\x04data\"\xbd\x01\n" + + "\x10GetBuildInfoData\x12\x18\n" + + "\aversion\x18\x01 \x01(\tR\aversion\x12\x1a\n" + + "\brevision\x18\x02 \x01(\tR\brevision\x12\x16\n" + + "\x06branch\x18\x03 \x01(\tR\x06branch\x12\x1d\n" + + "\n" + + "build_user\x18\x04 \x01(\tR\tbuildUser\x12\x1d\n" + + "\n" + + "build_date\x18\x05 \x01(\tR\tbuildDate\x12\x1d\n" + + "\n" + + "go_version\x18\x06 \x01(\tR\tgoVersion\"\x12\n" + + "\x10GetConfigRequest\"\x13\n" + + "\x11GetConfigResponse2\xb7\x03\n" + + "\rStatusService\x12q\n" + + "\fGetBuildInfo\x12\x1e.status.v1.GetBuildInfoRequest\x1a\x1f.status.v1.GetBuildInfoResponse\" \x82\xd3\xe4\x93\x02\x1a\x12\x18/api/v1/status/buildinfo\x12]\n" + + "\tGetConfig\x12\x1b.status.v1.GetConfigRequest\x1a\x14.google.api.HttpBody\"\x1d\x82\xd3\xe4\x93\x02\x17\x12\x15/api/v1/status/config\x12f\n" + + "\rGetDiffConfig\x12\x1b.status.v1.GetConfigRequest\x1a\x14.google.api.HttpBody\"\"\x82\xd3\xe4\x93\x02\x1c\x12\x1a/api/v1/status/config/diff\x12l\n" + + "\x10GetDefaultConfig\x12\x1b.status.v1.GetConfigRequest\x1a\x14.google.api.HttpBody\"%\x82\xd3\xe4\x93\x02\x1f\x12\x1d/api/v1/status/config/defaultB\xa3\x01\n" + + "\rcom.status.v1B\vStatusProtoP\x01Z@github.com/grafana/pyroscope/api/gen/proto/go/status/v1;statusv1\xa2\x02\x03SXX\xaa\x02\tStatus.V1\xca\x02\tStatus\\V1\xe2\x02\x15Status\\V1\\GPBMetadata\xea\x02\n" + + "Status::V1b\x06proto3" var ( file_status_v1_status_proto_rawDescOnce sync.Once - file_status_v1_status_proto_rawDescData = file_status_v1_status_proto_rawDesc + file_status_v1_status_proto_rawDescData []byte ) func file_status_v1_status_proto_rawDescGZIP() []byte { file_status_v1_status_proto_rawDescOnce.Do(func() { - file_status_v1_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_status_v1_status_proto_rawDescData) + file_status_v1_status_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_status_v1_status_proto_rawDesc), len(file_status_v1_status_proto_rawDesc))) }) return file_status_v1_status_proto_rawDescData } var file_status_v1_status_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_status_v1_status_proto_goTypes = []interface{}{ +var file_status_v1_status_proto_goTypes = []any{ (*GetBuildInfoRequest)(nil), // 0: status.v1.GetBuildInfoRequest (*GetBuildInfoResponse)(nil), // 1: status.v1.GetBuildInfoResponse (*GetBuildInfoData)(nil), // 2: status.v1.GetBuildInfoData @@ -393,73 +339,11 @@ func file_status_v1_status_proto_init() { if File_status_v1_status_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_status_v1_status_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBuildInfoRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_status_v1_status_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBuildInfoResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_status_v1_status_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBuildInfoData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_status_v1_status_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConfigRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_status_v1_status_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConfigResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_status_v1_status_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_status_v1_status_proto_rawDesc), len(file_status_v1_status_proto_rawDesc)), NumEnums: 0, NumMessages: 5, NumExtensions: 0, @@ -470,7 +354,6 @@ func file_status_v1_status_proto_init() { MessageInfos: file_status_v1_status_proto_msgTypes, }.Build() File_status_v1_status_proto = out.File - file_status_v1_status_proto_rawDesc = nil file_status_v1_status_proto_goTypes = nil file_status_v1_status_proto_depIdxs = nil } diff --git a/api/gen/proto/go/status/v1/status.pb.gw.go b/api/gen/proto/go/status/v1/status.pb.gw.go index dbe07d0039..6ccd7f77dd 100644 --- a/api/gen/proto/go/status/v1/status.pb.gw.go +++ b/api/gen/proto/go/status/v1/status.pb.gw.go @@ -10,6 +10,7 @@ package statusv1 import ( "context" + "errors" "io" "net/http" @@ -24,100 +25,113 @@ import ( ) // Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = metadata.Join +var ( + _ codes.Code + _ io.Reader + _ status.Status + _ = errors.New + _ = runtime.String + _ = utilities.NewDoubleArray + _ = metadata.Join +) func request_StatusService_GetBuildInfo_0(ctx context.Context, marshaler runtime.Marshaler, client StatusServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetBuildInfoRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetBuildInfoRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetBuildInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err - } func local_request_StatusService_GetBuildInfo_0(ctx context.Context, marshaler runtime.Marshaler, server StatusServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetBuildInfoRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetBuildInfoRequest + metadata runtime.ServerMetadata + ) msg, err := server.GetBuildInfo(ctx, &protoReq) return msg, metadata, err - } func request_StatusService_GetConfig_0(ctx context.Context, marshaler runtime.Marshaler, client StatusServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetConfigRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetConfigRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err - } func local_request_StatusService_GetConfig_0(ctx context.Context, marshaler runtime.Marshaler, server StatusServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetConfigRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetConfigRequest + metadata runtime.ServerMetadata + ) msg, err := server.GetConfig(ctx, &protoReq) return msg, metadata, err - } func request_StatusService_GetDiffConfig_0(ctx context.Context, marshaler runtime.Marshaler, client StatusServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetConfigRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetConfigRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDiffConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err - } func local_request_StatusService_GetDiffConfig_0(ctx context.Context, marshaler runtime.Marshaler, server StatusServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetConfigRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetConfigRequest + metadata runtime.ServerMetadata + ) msg, err := server.GetDiffConfig(ctx, &protoReq) return msg, metadata, err - } func request_StatusService_GetDefaultConfig_0(ctx context.Context, marshaler runtime.Marshaler, client StatusServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetConfigRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetConfigRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } msg, err := client.GetDefaultConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err - } func local_request_StatusService_GetDefaultConfig_0(ctx context.Context, marshaler runtime.Marshaler, server StatusServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetConfigRequest - var metadata runtime.ServerMetadata - + var ( + protoReq GetConfigRequest + metadata runtime.ServerMetadata + ) msg, err := server.GetDefaultConfig(ctx, &protoReq) return msg, metadata, err - } // RegisterStatusServiceHandlerServer registers the http handlers for service StatusService to "mux". // UnaryRPC :call StatusServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterStatusServiceHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. func RegisterStatusServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server StatusServiceServer) error { - - mux.Handle("GET", pattern_StatusService_GetBuildInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetBuildInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetBuildInfo", runtime.WithHTTPPathPattern("/api/v1/status/buildinfo")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetBuildInfo", runtime.WithHTTPPathPattern("/api/v1/status/buildinfo")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -129,20 +143,15 @@ func RegisterStatusServiceHandlerServer(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetBuildInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - mux.Handle("GET", pattern_StatusService_GetConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetConfig", runtime.WithHTTPPathPattern("/api/v1/status/config")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetConfig", runtime.WithHTTPPathPattern("/api/v1/status/config")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -154,20 +163,15 @@ func RegisterStatusServiceHandlerServer(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - mux.Handle("GET", pattern_StatusService_GetDiffConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetDiffConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetDiffConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/diff")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetDiffConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/diff")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -179,20 +183,15 @@ func RegisterStatusServiceHandlerServer(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetDiffConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - mux.Handle("GET", pattern_StatusService_GetDefaultConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetDefaultConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetDefaultConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/default")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/status.v1.StatusService/GetDefaultConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/default")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -204,9 +203,7 @@ func RegisterStatusServiceHandlerServer(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetDefaultConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) return nil @@ -215,25 +212,24 @@ func RegisterStatusServiceHandlerServer(ctx context.Context, mux *runtime.ServeM // RegisterStatusServiceHandlerFromEndpoint is same as RegisterStatusServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterStatusServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.DialContext(ctx, endpoint, opts...) + conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() - return RegisterStatusServiceHandler(ctx, mux, conn) } @@ -247,16 +243,13 @@ func RegisterStatusServiceHandler(ctx context.Context, mux *runtime.ServeMux, co // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "StatusServiceClient". // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "StatusServiceClient" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "StatusServiceClient" to call the correct interceptors. +// "StatusServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares. func RegisterStatusServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client StatusServiceClient) error { - - mux.Handle("GET", pattern_StatusService_GetBuildInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetBuildInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetBuildInfo", runtime.WithHTTPPathPattern("/api/v1/status/buildinfo")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetBuildInfo", runtime.WithHTTPPathPattern("/api/v1/status/buildinfo")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -267,18 +260,13 @@ func RegisterStatusServiceHandlerClient(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetBuildInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - mux.Handle("GET", pattern_StatusService_GetConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetConfig", runtime.WithHTTPPathPattern("/api/v1/status/config")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetConfig", runtime.WithHTTPPathPattern("/api/v1/status/config")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -289,18 +277,13 @@ func RegisterStatusServiceHandlerClient(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - mux.Handle("GET", pattern_StatusService_GetDiffConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetDiffConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetDiffConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/diff")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetDiffConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/diff")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -311,18 +294,13 @@ func RegisterStatusServiceHandlerClient(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetDiffConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - - mux.Handle("GET", pattern_StatusService_GetDefaultConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodGet, pattern_StatusService_GetDefaultConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetDefaultConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/default")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/status.v1.StatusService/GetDefaultConfig", runtime.WithHTTPPathPattern("/api/v1/status/config/default")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -333,30 +311,21 @@ func RegisterStatusServiceHandlerClient(ctx context.Context, mux *runtime.ServeM runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_StatusService_GetDefaultConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - return nil } var ( - pattern_StatusService_GetBuildInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "status", "buildinfo"}, "")) - - pattern_StatusService_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "status", "config"}, "")) - - pattern_StatusService_GetDiffConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"api", "v1", "status", "config", "diff"}, "")) - + pattern_StatusService_GetBuildInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "status", "buildinfo"}, "")) + pattern_StatusService_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "status", "config"}, "")) + pattern_StatusService_GetDiffConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"api", "v1", "status", "config", "diff"}, "")) pattern_StatusService_GetDefaultConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"api", "v1", "status", "config", "default"}, "")) ) var ( - forward_StatusService_GetBuildInfo_0 = runtime.ForwardResponseMessage - - forward_StatusService_GetConfig_0 = runtime.ForwardResponseMessage - - forward_StatusService_GetDiffConfig_0 = runtime.ForwardResponseMessage - + forward_StatusService_GetBuildInfo_0 = runtime.ForwardResponseMessage + forward_StatusService_GetConfig_0 = runtime.ForwardResponseMessage + forward_StatusService_GetDiffConfig_0 = runtime.ForwardResponseMessage forward_StatusService_GetDefaultConfig_0 = runtime.ForwardResponseMessage ) diff --git a/api/gen/proto/go/status/v1/statusv1connect/status.connect.go b/api/gen/proto/go/status/v1/statusv1connect/status.connect.go index b4aad0c474..8f4dcd0fec 100644 --- a/api/gen/proto/go/status/v1/statusv1connect/status.connect.go +++ b/api/gen/proto/go/status/v1/statusv1connect/status.connect.go @@ -47,15 +47,6 @@ const ( StatusServiceGetDefaultConfigProcedure = "/status.v1.StatusService/GetDefaultConfig" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - statusServiceServiceDescriptor = v1.File_status_v1_status_proto.Services().ByName("StatusService") - statusServiceGetBuildInfoMethodDescriptor = statusServiceServiceDescriptor.Methods().ByName("GetBuildInfo") - statusServiceGetConfigMethodDescriptor = statusServiceServiceDescriptor.Methods().ByName("GetConfig") - statusServiceGetDiffConfigMethodDescriptor = statusServiceServiceDescriptor.Methods().ByName("GetDiffConfig") - statusServiceGetDefaultConfigMethodDescriptor = statusServiceServiceDescriptor.Methods().ByName("GetDefaultConfig") -) - // StatusServiceClient is a client for the status.v1.StatusService service. type StatusServiceClient interface { // Retrieve build information about the binary @@ -76,29 +67,30 @@ type StatusServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewStatusServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) StatusServiceClient { baseURL = strings.TrimRight(baseURL, "/") + statusServiceMethods := v1.File_status_v1_status_proto.Services().ByName("StatusService").Methods() return &statusServiceClient{ getBuildInfo: connect.NewClient[v1.GetBuildInfoRequest, v1.GetBuildInfoResponse]( httpClient, baseURL+StatusServiceGetBuildInfoProcedure, - connect.WithSchema(statusServiceGetBuildInfoMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetBuildInfo")), connect.WithClientOptions(opts...), ), getConfig: connect.NewClient[v1.GetConfigRequest, httpbody.HttpBody]( httpClient, baseURL+StatusServiceGetConfigProcedure, - connect.WithSchema(statusServiceGetConfigMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetConfig")), connect.WithClientOptions(opts...), ), getDiffConfig: connect.NewClient[v1.GetConfigRequest, httpbody.HttpBody]( httpClient, baseURL+StatusServiceGetDiffConfigProcedure, - connect.WithSchema(statusServiceGetDiffConfigMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetDiffConfig")), connect.WithClientOptions(opts...), ), getDefaultConfig: connect.NewClient[v1.GetConfigRequest, httpbody.HttpBody]( httpClient, baseURL+StatusServiceGetDefaultConfigProcedure, - connect.WithSchema(statusServiceGetDefaultConfigMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetDefaultConfig")), connect.WithClientOptions(opts...), ), } @@ -149,28 +141,29 @@ type StatusServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewStatusServiceHandler(svc StatusServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + statusServiceMethods := v1.File_status_v1_status_proto.Services().ByName("StatusService").Methods() statusServiceGetBuildInfoHandler := connect.NewUnaryHandler( StatusServiceGetBuildInfoProcedure, svc.GetBuildInfo, - connect.WithSchema(statusServiceGetBuildInfoMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetBuildInfo")), connect.WithHandlerOptions(opts...), ) statusServiceGetConfigHandler := connect.NewUnaryHandler( StatusServiceGetConfigProcedure, svc.GetConfig, - connect.WithSchema(statusServiceGetConfigMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetConfig")), connect.WithHandlerOptions(opts...), ) statusServiceGetDiffConfigHandler := connect.NewUnaryHandler( StatusServiceGetDiffConfigProcedure, svc.GetDiffConfig, - connect.WithSchema(statusServiceGetDiffConfigMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetDiffConfig")), connect.WithHandlerOptions(opts...), ) statusServiceGetDefaultConfigHandler := connect.NewUnaryHandler( StatusServiceGetDefaultConfigProcedure, svc.GetDefaultConfig, - connect.WithSchema(statusServiceGetDefaultConfigMethodDescriptor), + connect.WithSchema(statusServiceMethods.ByName("GetDefaultConfig")), connect.WithHandlerOptions(opts...), ) return "/status.v1.StatusService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/api/gen/proto/go/storegateway/v1/storegateway.pb.go b/api/gen/proto/go/storegateway/v1/storegateway.pb.go index 9248db42b9..3d9b915efa 100644 --- a/api/gen/proto/go/storegateway/v1/storegateway.pb.go +++ b/api/gen/proto/go/storegateway/v1/storegateway.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: storegateway/v1/storegateway.proto @@ -14,6 +14,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" + unsafe "unsafe" ) const ( @@ -25,94 +26,24 @@ const ( var File_storegateway_v1_storegateway_proto protoreflect.FileDescriptor -var file_storegateway_v1_storegateway_proto_rawDesc = []byte{ - 0x0a, 0x22, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x76, - 0x31, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x2e, 0x76, 0x31, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x76, 0x31, - 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, - 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x67, 0x65, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x70, 0x75, 0x73, 0x68, - 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x75, 0x73, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xc1, 0x07, 0x0a, 0x13, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x47, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7d, 0x0a, 0x18, - 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x53, 0x74, 0x61, - 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, - 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x6e, 0x0a, 0x13, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x12, 0x27, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x69, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x6b, 0x0a, 0x12, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x70, 0x72, 0x6f, - 0x66, 0x12, 0x26, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x70, 0x72, - 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x69, 0x6e, 0x67, 0x65, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x65, 0x0a, 0x10, 0x4d, 0x65, 0x72, 0x67, - 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x2e, 0x69, - 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, - 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, - 0x55, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, - 0x20, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0a, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, - 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x43, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x69, 0x6e, 0x67, 0x65, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, - 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, - 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, - 0x21, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xd3, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, - 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x76, 0x31, - 0x42, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, - 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x0f, 0x53, 0x74, 0x6f, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x53, 0x74, - 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, - 0x53, 0x74, 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5c, 0x56, 0x31, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x10, 0x53, 0x74, - 0x6f, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_storegateway_v1_storegateway_proto_rawDesc = "" + + "\n" + + "\"storegateway/v1/storegateway.proto\x12\x0fstoregateway.v1\x1a\x17google/v1/profile.proto\x1a\x1aingester/v1/ingester.proto\x1a\x12push/v1/push.proto\x1a\x14types/v1/types.proto2\xc1\a\n" + + "\x13StoreGatewayService\x12}\n" + + "\x18MergeProfilesStacktraces\x12,.ingester.v1.MergeProfilesStacktracesRequest\x1a-.ingester.v1.MergeProfilesStacktracesResponse\"\x00(\x010\x01\x12n\n" + + "\x13MergeProfilesLabels\x12'.ingester.v1.MergeProfilesLabelsRequest\x1a(.ingester.v1.MergeProfilesLabelsResponse\"\x00(\x010\x01\x12k\n" + + "\x12MergeProfilesPprof\x12&.ingester.v1.MergeProfilesPprofRequest\x1a'.ingester.v1.MergeProfilesPprofResponse\"\x00(\x010\x01\x12e\n" + + "\x10MergeSpanProfile\x12$.ingester.v1.MergeSpanProfileRequest\x1a%.ingester.v1.MergeSpanProfileResponse\"\x00(\x010\x01\x12U\n" + + "\fProfileTypes\x12 .ingester.v1.ProfileTypesRequest\x1a!.ingester.v1.ProfileTypesResponse\"\x00\x12L\n" + + "\vLabelValues\x12\x1c.types.v1.LabelValuesRequest\x1a\x1d.types.v1.LabelValuesResponse\"\x00\x12I\n" + + "\n" + + "LabelNames\x12\x1b.types.v1.LabelNamesRequest\x1a\x1c.types.v1.LabelNamesResponse\"\x00\x12C\n" + + "\x06Series\x12\x1a.ingester.v1.SeriesRequest\x1a\x1b.ingester.v1.SeriesResponse\"\x00\x12X\n" + + "\rBlockMetadata\x12!.ingester.v1.BlockMetadataRequest\x1a\".ingester.v1.BlockMetadataResponse\"\x00\x12X\n" + + "\rGetBlockStats\x12!.ingester.v1.GetBlockStatsRequest\x1a\".ingester.v1.GetBlockStatsResponse\"\x00B\xd3\x01\n" + + "\x13com.storegateway.v1B\x11StoregatewayProtoP\x01ZLgithub.com/grafana/pyroscope/api/gen/proto/go/storegateway/v1;storegatewayv1\xa2\x02\x03SXX\xaa\x02\x0fStoregateway.V1\xca\x02\x0fStoregateway\\V1\xe2\x02\x1bStoregateway\\V1\\GPBMetadata\xea\x02\x10Storegateway::V1b\x06proto3" -var file_storegateway_v1_storegateway_proto_goTypes = []interface{}{ +var file_storegateway_v1_storegateway_proto_goTypes = []any{ (*v1.MergeProfilesStacktracesRequest)(nil), // 0: ingester.v1.MergeProfilesStacktracesRequest (*v1.MergeProfilesLabelsRequest)(nil), // 1: ingester.v1.MergeProfilesLabelsRequest (*v1.MergeProfilesPprofRequest)(nil), // 2: ingester.v1.MergeProfilesPprofRequest @@ -171,7 +102,7 @@ func file_storegateway_v1_storegateway_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_storegateway_v1_storegateway_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_storegateway_v1_storegateway_proto_rawDesc), len(file_storegateway_v1_storegateway_proto_rawDesc)), NumEnums: 0, NumMessages: 0, NumExtensions: 0, @@ -181,7 +112,6 @@ func file_storegateway_v1_storegateway_proto_init() { DependencyIndexes: file_storegateway_v1_storegateway_proto_depIdxs, }.Build() File_storegateway_v1_storegateway_proto = out.File - file_storegateway_v1_storegateway_proto_rawDesc = nil file_storegateway_v1_storegateway_proto_goTypes = nil file_storegateway_v1_storegateway_proto_depIdxs = nil } diff --git a/api/gen/proto/go/storegateway/v1/storegatewayv1connect/storegateway.connect.go b/api/gen/proto/go/storegateway/v1/storegatewayv1connect/storegateway.connect.go index c92896ddb6..b969dcc604 100644 --- a/api/gen/proto/go/storegateway/v1/storegatewayv1connect/storegateway.connect.go +++ b/api/gen/proto/go/storegateway/v1/storegatewayv1connect/storegateway.connect.go @@ -8,9 +8,9 @@ import ( connect "connectrpc.com/connect" context "context" errors "errors" - v11 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - v1 "github.com/grafana/pyroscope/api/gen/proto/go/storegateway/v1" - v12 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" + v12 "github.com/grafana/pyroscope/api/gen/proto/go/storegateway/v1" + v11 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" http "net/http" strings "strings" ) @@ -67,35 +67,20 @@ const ( StoreGatewayServiceGetBlockStatsProcedure = "/storegateway.v1.StoreGatewayService/GetBlockStats" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - storeGatewayServiceServiceDescriptor = v1.File_storegateway_v1_storegateway_proto.Services().ByName("StoreGatewayService") - storeGatewayServiceMergeProfilesStacktracesMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("MergeProfilesStacktraces") - storeGatewayServiceMergeProfilesLabelsMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("MergeProfilesLabels") - storeGatewayServiceMergeProfilesPprofMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("MergeProfilesPprof") - storeGatewayServiceMergeSpanProfileMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("MergeSpanProfile") - storeGatewayServiceProfileTypesMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("ProfileTypes") - storeGatewayServiceLabelValuesMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("LabelValues") - storeGatewayServiceLabelNamesMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("LabelNames") - storeGatewayServiceSeriesMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("Series") - storeGatewayServiceBlockMetadataMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("BlockMetadata") - storeGatewayServiceGetBlockStatsMethodDescriptor = storeGatewayServiceServiceDescriptor.Methods().ByName("GetBlockStats") -) - // StoreGatewayServiceClient is a client for the storegateway.v1.StoreGatewayService service. type StoreGatewayServiceClient interface { - MergeProfilesStacktraces(context.Context) *connect.BidiStreamForClient[v11.MergeProfilesStacktracesRequest, v11.MergeProfilesStacktracesResponse] - MergeProfilesLabels(context.Context) *connect.BidiStreamForClient[v11.MergeProfilesLabelsRequest, v11.MergeProfilesLabelsResponse] - MergeProfilesPprof(context.Context) *connect.BidiStreamForClient[v11.MergeProfilesPprofRequest, v11.MergeProfilesPprofResponse] - MergeSpanProfile(context.Context) *connect.BidiStreamForClient[v11.MergeSpanProfileRequest, v11.MergeSpanProfileResponse] + MergeProfilesStacktraces(context.Context) *connect.BidiStreamForClient[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse] + MergeProfilesLabels(context.Context) *connect.BidiStreamForClient[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse] + MergeProfilesPprof(context.Context) *connect.BidiStreamForClient[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse] + MergeSpanProfile(context.Context) *connect.BidiStreamForClient[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse] // Deprecated: ProfileType call is deprecated in the store components // TODO: Remove this call in release v1.4 - ProfileTypes(context.Context, *connect.Request[v11.ProfileTypesRequest]) (*connect.Response[v11.ProfileTypesResponse], error) - LabelValues(context.Context, *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) - LabelNames(context.Context, *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) - Series(context.Context, *connect.Request[v11.SeriesRequest]) (*connect.Response[v11.SeriesResponse], error) - BlockMetadata(context.Context, *connect.Request[v11.BlockMetadataRequest]) (*connect.Response[v11.BlockMetadataResponse], error) - GetBlockStats(context.Context, *connect.Request[v11.GetBlockStatsRequest]) (*connect.Response[v11.GetBlockStatsResponse], error) + ProfileTypes(context.Context, *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) + LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) + LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) + Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) + BlockMetadata(context.Context, *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) + GetBlockStats(context.Context, *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) } // NewStoreGatewayServiceClient constructs a client for the storegateway.v1.StoreGatewayService @@ -107,65 +92,66 @@ type StoreGatewayServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewStoreGatewayServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) StoreGatewayServiceClient { baseURL = strings.TrimRight(baseURL, "/") + storeGatewayServiceMethods := v12.File_storegateway_v1_storegateway_proto.Services().ByName("StoreGatewayService").Methods() return &storeGatewayServiceClient{ - mergeProfilesStacktraces: connect.NewClient[v11.MergeProfilesStacktracesRequest, v11.MergeProfilesStacktracesResponse]( + mergeProfilesStacktraces: connect.NewClient[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse]( httpClient, baseURL+StoreGatewayServiceMergeProfilesStacktracesProcedure, - connect.WithSchema(storeGatewayServiceMergeProfilesStacktracesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeProfilesStacktraces")), connect.WithClientOptions(opts...), ), - mergeProfilesLabels: connect.NewClient[v11.MergeProfilesLabelsRequest, v11.MergeProfilesLabelsResponse]( + mergeProfilesLabels: connect.NewClient[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse]( httpClient, baseURL+StoreGatewayServiceMergeProfilesLabelsProcedure, - connect.WithSchema(storeGatewayServiceMergeProfilesLabelsMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeProfilesLabels")), connect.WithClientOptions(opts...), ), - mergeProfilesPprof: connect.NewClient[v11.MergeProfilesPprofRequest, v11.MergeProfilesPprofResponse]( + mergeProfilesPprof: connect.NewClient[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse]( httpClient, baseURL+StoreGatewayServiceMergeProfilesPprofProcedure, - connect.WithSchema(storeGatewayServiceMergeProfilesPprofMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeProfilesPprof")), connect.WithClientOptions(opts...), ), - mergeSpanProfile: connect.NewClient[v11.MergeSpanProfileRequest, v11.MergeSpanProfileResponse]( + mergeSpanProfile: connect.NewClient[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse]( httpClient, baseURL+StoreGatewayServiceMergeSpanProfileProcedure, - connect.WithSchema(storeGatewayServiceMergeSpanProfileMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeSpanProfile")), connect.WithClientOptions(opts...), ), - profileTypes: connect.NewClient[v11.ProfileTypesRequest, v11.ProfileTypesResponse]( + profileTypes: connect.NewClient[v1.ProfileTypesRequest, v1.ProfileTypesResponse]( httpClient, baseURL+StoreGatewayServiceProfileTypesProcedure, - connect.WithSchema(storeGatewayServiceProfileTypesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("ProfileTypes")), connect.WithClientOptions(opts...), ), - labelValues: connect.NewClient[v12.LabelValuesRequest, v12.LabelValuesResponse]( + labelValues: connect.NewClient[v11.LabelValuesRequest, v11.LabelValuesResponse]( httpClient, baseURL+StoreGatewayServiceLabelValuesProcedure, - connect.WithSchema(storeGatewayServiceLabelValuesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("LabelValues")), connect.WithClientOptions(opts...), ), - labelNames: connect.NewClient[v12.LabelNamesRequest, v12.LabelNamesResponse]( + labelNames: connect.NewClient[v11.LabelNamesRequest, v11.LabelNamesResponse]( httpClient, baseURL+StoreGatewayServiceLabelNamesProcedure, - connect.WithSchema(storeGatewayServiceLabelNamesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("LabelNames")), connect.WithClientOptions(opts...), ), - series: connect.NewClient[v11.SeriesRequest, v11.SeriesResponse]( + series: connect.NewClient[v1.SeriesRequest, v1.SeriesResponse]( httpClient, baseURL+StoreGatewayServiceSeriesProcedure, - connect.WithSchema(storeGatewayServiceSeriesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("Series")), connect.WithClientOptions(opts...), ), - blockMetadata: connect.NewClient[v11.BlockMetadataRequest, v11.BlockMetadataResponse]( + blockMetadata: connect.NewClient[v1.BlockMetadataRequest, v1.BlockMetadataResponse]( httpClient, baseURL+StoreGatewayServiceBlockMetadataProcedure, - connect.WithSchema(storeGatewayServiceBlockMetadataMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("BlockMetadata")), connect.WithClientOptions(opts...), ), - getBlockStats: connect.NewClient[v11.GetBlockStatsRequest, v11.GetBlockStatsResponse]( + getBlockStats: connect.NewClient[v1.GetBlockStatsRequest, v1.GetBlockStatsResponse]( httpClient, baseURL+StoreGatewayServiceGetBlockStatsProcedure, - connect.WithSchema(storeGatewayServiceGetBlockStatsMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("GetBlockStats")), connect.WithClientOptions(opts...), ), } @@ -173,83 +159,83 @@ func NewStoreGatewayServiceClient(httpClient connect.HTTPClient, baseURL string, // storeGatewayServiceClient implements StoreGatewayServiceClient. type storeGatewayServiceClient struct { - mergeProfilesStacktraces *connect.Client[v11.MergeProfilesStacktracesRequest, v11.MergeProfilesStacktracesResponse] - mergeProfilesLabels *connect.Client[v11.MergeProfilesLabelsRequest, v11.MergeProfilesLabelsResponse] - mergeProfilesPprof *connect.Client[v11.MergeProfilesPprofRequest, v11.MergeProfilesPprofResponse] - mergeSpanProfile *connect.Client[v11.MergeSpanProfileRequest, v11.MergeSpanProfileResponse] - profileTypes *connect.Client[v11.ProfileTypesRequest, v11.ProfileTypesResponse] - labelValues *connect.Client[v12.LabelValuesRequest, v12.LabelValuesResponse] - labelNames *connect.Client[v12.LabelNamesRequest, v12.LabelNamesResponse] - series *connect.Client[v11.SeriesRequest, v11.SeriesResponse] - blockMetadata *connect.Client[v11.BlockMetadataRequest, v11.BlockMetadataResponse] - getBlockStats *connect.Client[v11.GetBlockStatsRequest, v11.GetBlockStatsResponse] + mergeProfilesStacktraces *connect.Client[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse] + mergeProfilesLabels *connect.Client[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse] + mergeProfilesPprof *connect.Client[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse] + mergeSpanProfile *connect.Client[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse] + profileTypes *connect.Client[v1.ProfileTypesRequest, v1.ProfileTypesResponse] + labelValues *connect.Client[v11.LabelValuesRequest, v11.LabelValuesResponse] + labelNames *connect.Client[v11.LabelNamesRequest, v11.LabelNamesResponse] + series *connect.Client[v1.SeriesRequest, v1.SeriesResponse] + blockMetadata *connect.Client[v1.BlockMetadataRequest, v1.BlockMetadataResponse] + getBlockStats *connect.Client[v1.GetBlockStatsRequest, v1.GetBlockStatsResponse] } // MergeProfilesStacktraces calls storegateway.v1.StoreGatewayService.MergeProfilesStacktraces. -func (c *storeGatewayServiceClient) MergeProfilesStacktraces(ctx context.Context) *connect.BidiStreamForClient[v11.MergeProfilesStacktracesRequest, v11.MergeProfilesStacktracesResponse] { +func (c *storeGatewayServiceClient) MergeProfilesStacktraces(ctx context.Context) *connect.BidiStreamForClient[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse] { return c.mergeProfilesStacktraces.CallBidiStream(ctx) } // MergeProfilesLabels calls storegateway.v1.StoreGatewayService.MergeProfilesLabels. -func (c *storeGatewayServiceClient) MergeProfilesLabels(ctx context.Context) *connect.BidiStreamForClient[v11.MergeProfilesLabelsRequest, v11.MergeProfilesLabelsResponse] { +func (c *storeGatewayServiceClient) MergeProfilesLabels(ctx context.Context) *connect.BidiStreamForClient[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse] { return c.mergeProfilesLabels.CallBidiStream(ctx) } // MergeProfilesPprof calls storegateway.v1.StoreGatewayService.MergeProfilesPprof. -func (c *storeGatewayServiceClient) MergeProfilesPprof(ctx context.Context) *connect.BidiStreamForClient[v11.MergeProfilesPprofRequest, v11.MergeProfilesPprofResponse] { +func (c *storeGatewayServiceClient) MergeProfilesPprof(ctx context.Context) *connect.BidiStreamForClient[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse] { return c.mergeProfilesPprof.CallBidiStream(ctx) } // MergeSpanProfile calls storegateway.v1.StoreGatewayService.MergeSpanProfile. -func (c *storeGatewayServiceClient) MergeSpanProfile(ctx context.Context) *connect.BidiStreamForClient[v11.MergeSpanProfileRequest, v11.MergeSpanProfileResponse] { +func (c *storeGatewayServiceClient) MergeSpanProfile(ctx context.Context) *connect.BidiStreamForClient[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse] { return c.mergeSpanProfile.CallBidiStream(ctx) } // ProfileTypes calls storegateway.v1.StoreGatewayService.ProfileTypes. -func (c *storeGatewayServiceClient) ProfileTypes(ctx context.Context, req *connect.Request[v11.ProfileTypesRequest]) (*connect.Response[v11.ProfileTypesResponse], error) { +func (c *storeGatewayServiceClient) ProfileTypes(ctx context.Context, req *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) { return c.profileTypes.CallUnary(ctx, req) } // LabelValues calls storegateway.v1.StoreGatewayService.LabelValues. -func (c *storeGatewayServiceClient) LabelValues(ctx context.Context, req *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) { +func (c *storeGatewayServiceClient) LabelValues(ctx context.Context, req *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) { return c.labelValues.CallUnary(ctx, req) } // LabelNames calls storegateway.v1.StoreGatewayService.LabelNames. -func (c *storeGatewayServiceClient) LabelNames(ctx context.Context, req *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) { +func (c *storeGatewayServiceClient) LabelNames(ctx context.Context, req *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) { return c.labelNames.CallUnary(ctx, req) } // Series calls storegateway.v1.StoreGatewayService.Series. -func (c *storeGatewayServiceClient) Series(ctx context.Context, req *connect.Request[v11.SeriesRequest]) (*connect.Response[v11.SeriesResponse], error) { +func (c *storeGatewayServiceClient) Series(ctx context.Context, req *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) { return c.series.CallUnary(ctx, req) } // BlockMetadata calls storegateway.v1.StoreGatewayService.BlockMetadata. -func (c *storeGatewayServiceClient) BlockMetadata(ctx context.Context, req *connect.Request[v11.BlockMetadataRequest]) (*connect.Response[v11.BlockMetadataResponse], error) { +func (c *storeGatewayServiceClient) BlockMetadata(ctx context.Context, req *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) { return c.blockMetadata.CallUnary(ctx, req) } // GetBlockStats calls storegateway.v1.StoreGatewayService.GetBlockStats. -func (c *storeGatewayServiceClient) GetBlockStats(ctx context.Context, req *connect.Request[v11.GetBlockStatsRequest]) (*connect.Response[v11.GetBlockStatsResponse], error) { +func (c *storeGatewayServiceClient) GetBlockStats(ctx context.Context, req *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) { return c.getBlockStats.CallUnary(ctx, req) } // StoreGatewayServiceHandler is an implementation of the storegateway.v1.StoreGatewayService // service. type StoreGatewayServiceHandler interface { - MergeProfilesStacktraces(context.Context, *connect.BidiStream[v11.MergeProfilesStacktracesRequest, v11.MergeProfilesStacktracesResponse]) error - MergeProfilesLabels(context.Context, *connect.BidiStream[v11.MergeProfilesLabelsRequest, v11.MergeProfilesLabelsResponse]) error - MergeProfilesPprof(context.Context, *connect.BidiStream[v11.MergeProfilesPprofRequest, v11.MergeProfilesPprofResponse]) error - MergeSpanProfile(context.Context, *connect.BidiStream[v11.MergeSpanProfileRequest, v11.MergeSpanProfileResponse]) error + MergeProfilesStacktraces(context.Context, *connect.BidiStream[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse]) error + MergeProfilesLabels(context.Context, *connect.BidiStream[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse]) error + MergeProfilesPprof(context.Context, *connect.BidiStream[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse]) error + MergeSpanProfile(context.Context, *connect.BidiStream[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse]) error // Deprecated: ProfileType call is deprecated in the store components // TODO: Remove this call in release v1.4 - ProfileTypes(context.Context, *connect.Request[v11.ProfileTypesRequest]) (*connect.Response[v11.ProfileTypesResponse], error) - LabelValues(context.Context, *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) - LabelNames(context.Context, *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) - Series(context.Context, *connect.Request[v11.SeriesRequest]) (*connect.Response[v11.SeriesResponse], error) - BlockMetadata(context.Context, *connect.Request[v11.BlockMetadataRequest]) (*connect.Response[v11.BlockMetadataResponse], error) - GetBlockStats(context.Context, *connect.Request[v11.GetBlockStatsRequest]) (*connect.Response[v11.GetBlockStatsResponse], error) + ProfileTypes(context.Context, *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) + LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) + LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) + Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) + BlockMetadata(context.Context, *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) + GetBlockStats(context.Context, *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) } // NewStoreGatewayServiceHandler builds an HTTP handler from the service implementation. It returns @@ -258,64 +244,65 @@ type StoreGatewayServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewStoreGatewayServiceHandler(svc StoreGatewayServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + storeGatewayServiceMethods := v12.File_storegateway_v1_storegateway_proto.Services().ByName("StoreGatewayService").Methods() storeGatewayServiceMergeProfilesStacktracesHandler := connect.NewBidiStreamHandler( StoreGatewayServiceMergeProfilesStacktracesProcedure, svc.MergeProfilesStacktraces, - connect.WithSchema(storeGatewayServiceMergeProfilesStacktracesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeProfilesStacktraces")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceMergeProfilesLabelsHandler := connect.NewBidiStreamHandler( StoreGatewayServiceMergeProfilesLabelsProcedure, svc.MergeProfilesLabels, - connect.WithSchema(storeGatewayServiceMergeProfilesLabelsMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeProfilesLabels")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceMergeProfilesPprofHandler := connect.NewBidiStreamHandler( StoreGatewayServiceMergeProfilesPprofProcedure, svc.MergeProfilesPprof, - connect.WithSchema(storeGatewayServiceMergeProfilesPprofMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeProfilesPprof")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceMergeSpanProfileHandler := connect.NewBidiStreamHandler( StoreGatewayServiceMergeSpanProfileProcedure, svc.MergeSpanProfile, - connect.WithSchema(storeGatewayServiceMergeSpanProfileMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("MergeSpanProfile")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceProfileTypesHandler := connect.NewUnaryHandler( StoreGatewayServiceProfileTypesProcedure, svc.ProfileTypes, - connect.WithSchema(storeGatewayServiceProfileTypesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("ProfileTypes")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceLabelValuesHandler := connect.NewUnaryHandler( StoreGatewayServiceLabelValuesProcedure, svc.LabelValues, - connect.WithSchema(storeGatewayServiceLabelValuesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("LabelValues")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceLabelNamesHandler := connect.NewUnaryHandler( StoreGatewayServiceLabelNamesProcedure, svc.LabelNames, - connect.WithSchema(storeGatewayServiceLabelNamesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("LabelNames")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceSeriesHandler := connect.NewUnaryHandler( StoreGatewayServiceSeriesProcedure, svc.Series, - connect.WithSchema(storeGatewayServiceSeriesMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("Series")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceBlockMetadataHandler := connect.NewUnaryHandler( StoreGatewayServiceBlockMetadataProcedure, svc.BlockMetadata, - connect.WithSchema(storeGatewayServiceBlockMetadataMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("BlockMetadata")), connect.WithHandlerOptions(opts...), ) storeGatewayServiceGetBlockStatsHandler := connect.NewUnaryHandler( StoreGatewayServiceGetBlockStatsProcedure, svc.GetBlockStats, - connect.WithSchema(storeGatewayServiceGetBlockStatsMethodDescriptor), + connect.WithSchema(storeGatewayServiceMethods.ByName("GetBlockStats")), connect.WithHandlerOptions(opts...), ) return "/storegateway.v1.StoreGatewayService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -349,42 +336,42 @@ func NewStoreGatewayServiceHandler(svc StoreGatewayServiceHandler, opts ...conne // UnimplementedStoreGatewayServiceHandler returns CodeUnimplemented from all methods. type UnimplementedStoreGatewayServiceHandler struct{} -func (UnimplementedStoreGatewayServiceHandler) MergeProfilesStacktraces(context.Context, *connect.BidiStream[v11.MergeProfilesStacktracesRequest, v11.MergeProfilesStacktracesResponse]) error { +func (UnimplementedStoreGatewayServiceHandler) MergeProfilesStacktraces(context.Context, *connect.BidiStream[v1.MergeProfilesStacktracesRequest, v1.MergeProfilesStacktracesResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.MergeProfilesStacktraces is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) MergeProfilesLabels(context.Context, *connect.BidiStream[v11.MergeProfilesLabelsRequest, v11.MergeProfilesLabelsResponse]) error { +func (UnimplementedStoreGatewayServiceHandler) MergeProfilesLabels(context.Context, *connect.BidiStream[v1.MergeProfilesLabelsRequest, v1.MergeProfilesLabelsResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.MergeProfilesLabels is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) MergeProfilesPprof(context.Context, *connect.BidiStream[v11.MergeProfilesPprofRequest, v11.MergeProfilesPprofResponse]) error { +func (UnimplementedStoreGatewayServiceHandler) MergeProfilesPprof(context.Context, *connect.BidiStream[v1.MergeProfilesPprofRequest, v1.MergeProfilesPprofResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.MergeProfilesPprof is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) MergeSpanProfile(context.Context, *connect.BidiStream[v11.MergeSpanProfileRequest, v11.MergeSpanProfileResponse]) error { +func (UnimplementedStoreGatewayServiceHandler) MergeSpanProfile(context.Context, *connect.BidiStream[v1.MergeSpanProfileRequest, v1.MergeSpanProfileResponse]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.MergeSpanProfile is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) ProfileTypes(context.Context, *connect.Request[v11.ProfileTypesRequest]) (*connect.Response[v11.ProfileTypesResponse], error) { +func (UnimplementedStoreGatewayServiceHandler) ProfileTypes(context.Context, *connect.Request[v1.ProfileTypesRequest]) (*connect.Response[v1.ProfileTypesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.ProfileTypes is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) LabelValues(context.Context, *connect.Request[v12.LabelValuesRequest]) (*connect.Response[v12.LabelValuesResponse], error) { +func (UnimplementedStoreGatewayServiceHandler) LabelValues(context.Context, *connect.Request[v11.LabelValuesRequest]) (*connect.Response[v11.LabelValuesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.LabelValues is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) LabelNames(context.Context, *connect.Request[v12.LabelNamesRequest]) (*connect.Response[v12.LabelNamesResponse], error) { +func (UnimplementedStoreGatewayServiceHandler) LabelNames(context.Context, *connect.Request[v11.LabelNamesRequest]) (*connect.Response[v11.LabelNamesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.LabelNames is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) Series(context.Context, *connect.Request[v11.SeriesRequest]) (*connect.Response[v11.SeriesResponse], error) { +func (UnimplementedStoreGatewayServiceHandler) Series(context.Context, *connect.Request[v1.SeriesRequest]) (*connect.Response[v1.SeriesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.Series is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) BlockMetadata(context.Context, *connect.Request[v11.BlockMetadataRequest]) (*connect.Response[v11.BlockMetadataResponse], error) { +func (UnimplementedStoreGatewayServiceHandler) BlockMetadata(context.Context, *connect.Request[v1.BlockMetadataRequest]) (*connect.Response[v1.BlockMetadataResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.BlockMetadata is not implemented")) } -func (UnimplementedStoreGatewayServiceHandler) GetBlockStats(context.Context, *connect.Request[v11.GetBlockStatsRequest]) (*connect.Response[v11.GetBlockStatsResponse], error) { +func (UnimplementedStoreGatewayServiceHandler) GetBlockStats(context.Context, *connect.Request[v1.GetBlockStatsRequest]) (*connect.Response[v1.GetBlockStatsResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("storegateway.v1.StoreGatewayService.GetBlockStats is not implemented")) } diff --git a/api/gen/proto/go/types/v1/types.pb.go b/api/gen/proto/go/types/v1/types.pb.go index fdf11d8222..e039e67173 100644 --- a/api/gen/proto/go/types/v1/types.pb.go +++ b/api/gen/proto/go/types/v1/types.pb.go @@ -1,16 +1,18 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: types/v1/types.proto package typesv1 import ( + _ "github.com/google/gnostic/openapiv3" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -66,22 +68,73 @@ func (TimeSeriesAggregationType) EnumDescriptor() ([]byte, []int) { return file_types_v1_types_proto_rawDescGZIP(), []int{0} } +type ExemplarType int32 + +const ( + ExemplarType_EXEMPLAR_TYPE_UNSPECIFIED ExemplarType = 0 + ExemplarType_EXEMPLAR_TYPE_NONE ExemplarType = 1 + ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL ExemplarType = 2 + ExemplarType_EXEMPLAR_TYPE_SPAN ExemplarType = 3 +) + +// Enum value maps for ExemplarType. +var ( + ExemplarType_name = map[int32]string{ + 0: "EXEMPLAR_TYPE_UNSPECIFIED", + 1: "EXEMPLAR_TYPE_NONE", + 2: "EXEMPLAR_TYPE_INDIVIDUAL", + 3: "EXEMPLAR_TYPE_SPAN", + } + ExemplarType_value = map[string]int32{ + "EXEMPLAR_TYPE_UNSPECIFIED": 0, + "EXEMPLAR_TYPE_NONE": 1, + "EXEMPLAR_TYPE_INDIVIDUAL": 2, + "EXEMPLAR_TYPE_SPAN": 3, + } +) + +func (x ExemplarType) Enum() *ExemplarType { + p := new(ExemplarType) + *p = x + return p +} + +func (x ExemplarType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ExemplarType) Descriptor() protoreflect.EnumDescriptor { + return file_types_v1_types_proto_enumTypes[1].Descriptor() +} + +func (ExemplarType) Type() protoreflect.EnumType { + return &file_types_v1_types_proto_enumTypes[1] +} + +func (x ExemplarType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ExemplarType.Descriptor instead. +func (ExemplarType) EnumDescriptor() ([]byte, []int) { + return file_types_v1_types_proto_rawDescGZIP(), []int{1} +} + type LabelPair struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + // Label name + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Label value + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LabelPair) Reset() { *x = LabelPair{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LabelPair) String() string { @@ -92,7 +145,7 @@ func (*LabelPair) ProtoMessage() {} func (x *LabelPair) ProtoReflect() protoreflect.Message { mi := &file_types_v1_types_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -122,25 +175,22 @@ func (x *LabelPair) GetValue() string { } type ProfileType struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + SampleType string `protobuf:"bytes,4,opt,name=sample_type,json=sampleType,proto3" json:"sample_type,omitempty"` + SampleUnit string `protobuf:"bytes,5,opt,name=sample_unit,json=sampleUnit,proto3" json:"sample_unit,omitempty"` + PeriodType string `protobuf:"bytes,6,opt,name=period_type,json=periodType,proto3" json:"period_type,omitempty"` + PeriodUnit string `protobuf:"bytes,7,opt,name=period_unit,json=periodUnit,proto3" json:"period_unit,omitempty"` unknownFields protoimpl.UnknownFields - - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - SampleType string `protobuf:"bytes,4,opt,name=sample_type,json=sampleType,proto3" json:"sample_type,omitempty"` - SampleUnit string `protobuf:"bytes,5,opt,name=sample_unit,json=sampleUnit,proto3" json:"sample_unit,omitempty"` - PeriodType string `protobuf:"bytes,6,opt,name=period_type,json=periodType,proto3" json:"period_type,omitempty"` - PeriodUnit string `protobuf:"bytes,7,opt,name=period_unit,json=periodUnit,proto3" json:"period_unit,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ProfileType) Reset() { *x = ProfileType{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProfileType) String() string { @@ -151,7 +201,7 @@ func (*ProfileType) ProtoMessage() {} func (x *ProfileType) ProtoReflect() protoreflect.Message { mi := &file_types_v1_types_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -209,21 +259,18 @@ func (x *ProfileType) GetPeriodUnit() string { } type Labels struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // LabelPair is the key value pairs to identify the corresponding profile - Labels []*LabelPair `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"` + Labels []*LabelPair `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Labels) Reset() { *x = Labels{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Labels) String() string { @@ -234,7 +281,7 @@ func (*Labels) ProtoMessage() {} func (x *Labels) ProtoReflect() protoreflect.Message { mi := &file_types_v1_types_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -257,21 +304,18 @@ func (x *Labels) GetLabels() []*LabelPair { } type Series struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Labels []*LabelPair `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"` + Points []*Point `protobuf:"bytes,2,rep,name=points,proto3" json:"points,omitempty"` unknownFields protoimpl.UnknownFields - - Labels []*LabelPair `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"` - Points []*Point `protobuf:"bytes,2,rep,name=points,proto3" json:"points,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Series) Reset() { *x = Series{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Series) String() string { @@ -282,7 +326,7 @@ func (*Series) ProtoMessage() {} func (x *Series) ProtoReflect() protoreflect.Message { mi := &file_types_v1_types_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -312,22 +356,22 @@ func (x *Series) GetPoints() []*Point { } type Point struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"` // Milliseconds unix timestamp - Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Annotations []*ProfileAnnotation `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty"` + // Exemplars are samples of individual profiles that contributed to this aggregated point + Exemplars []*Exemplar `protobuf:"bytes,4,rep,name=exemplars,proto3" json:"exemplars,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Point) Reset() { *x = Point{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Point) String() string { @@ -338,7 +382,7 @@ func (*Point) ProtoMessage() {} func (x *Point) ProtoReflect() protoreflect.Message { mi := &file_types_v1_types_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -367,24 +411,101 @@ func (x *Point) GetTimestamp() int64 { return 0 } -type LabelValuesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache +func (x *Point) GetAnnotations() []*ProfileAnnotation { + if x != nil { + return x.Annotations + } + return nil +} + +func (x *Point) GetExemplars() []*Exemplar { + if x != nil { + return x.Exemplars + } + return nil +} + +// Annotations provide additional metadata for a profile. +// +// The main differences between labels and annotations are: +// - annotations cannot be used in query selectors +// - annotation keys don't have to be unique +// +// Currently annotations are applied internally by distributors, +// any annotation passed via the push API will be dropped. +type ProfileAnnotation struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Annotation key [hidden] + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // Annotation value [hidden] + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +func (x *ProfileAnnotation) Reset() { + *x = ProfileAnnotation{} + mi := &file_types_v1_types_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProfileAnnotation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProfileAnnotation) ProtoMessage() {} + +func (x *ProfileAnnotation) ProtoReflect() protoreflect.Message { + mi := &file_types_v1_types_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProfileAnnotation.ProtoReflect.Descriptor instead. +func (*ProfileAnnotation) Descriptor() ([]byte, []int) { + return file_types_v1_types_proto_rawDescGZIP(), []int{5} +} + +func (x *ProfileAnnotation) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *ProfileAnnotation) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +type LabelValuesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Name of the label + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // List of Label selectors Matchers []string `protobuf:"bytes,2,rep,name=matchers,proto3" json:"matchers,omitempty"` - Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` - End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + // Query from this point in time, given in Milliseconds since epoch. + Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` + // Query to this point in time, given in Milliseconds since epoch. + End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LabelValuesRequest) Reset() { *x = LabelValuesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LabelValuesRequest) String() string { @@ -394,8 +515,8 @@ func (x *LabelValuesRequest) String() string { func (*LabelValuesRequest) ProtoMessage() {} func (x *LabelValuesRequest) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[6] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -407,7 +528,7 @@ func (x *LabelValuesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LabelValuesRequest.ProtoReflect.Descriptor instead. func (*LabelValuesRequest) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{5} + return file_types_v1_types_proto_rawDescGZIP(), []int{6} } func (x *LabelValuesRequest) GetName() string { @@ -439,20 +560,17 @@ func (x *LabelValuesRequest) GetEnd() int64 { } type LabelValuesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` unknownFields protoimpl.UnknownFields - - Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LabelValuesResponse) Reset() { *x = LabelValuesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LabelValuesResponse) String() string { @@ -462,8 +580,8 @@ func (x *LabelValuesResponse) String() string { func (*LabelValuesResponse) ProtoMessage() {} func (x *LabelValuesResponse) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[7] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -475,7 +593,7 @@ func (x *LabelValuesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LabelValuesResponse.ProtoReflect.Descriptor instead. func (*LabelValuesResponse) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{6} + return file_types_v1_types_proto_rawDescGZIP(), []int{7} } func (x *LabelValuesResponse) GetNames() []string { @@ -486,22 +604,22 @@ func (x *LabelValuesResponse) GetNames() []string { } type LabelNamesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` + // List of Label selectors Matchers []string `protobuf:"bytes,1,rep,name=matchers,proto3" json:"matchers,omitempty"` - Start int64 `protobuf:"varint,2,opt,name=start,proto3" json:"start,omitempty"` - End int64 `protobuf:"varint,3,opt,name=end,proto3" json:"end,omitempty"` + // Query from this point in time, given in Milliseconds since epoch. + Start int64 `protobuf:"varint,2,opt,name=start,proto3" json:"start,omitempty"` + // Query to this point in time, given in Milliseconds since epoch. + End int64 `protobuf:"varint,3,opt,name=end,proto3" json:"end,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LabelNamesRequest) Reset() { *x = LabelNamesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LabelNamesRequest) String() string { @@ -511,8 +629,8 @@ func (x *LabelNamesRequest) String() string { func (*LabelNamesRequest) ProtoMessage() {} func (x *LabelNamesRequest) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[8] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -524,7 +642,7 @@ func (x *LabelNamesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LabelNamesRequest.ProtoReflect.Descriptor instead. func (*LabelNamesRequest) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{7} + return file_types_v1_types_proto_rawDescGZIP(), []int{8} } func (x *LabelNamesRequest) GetMatchers() []string { @@ -549,20 +667,17 @@ func (x *LabelNamesRequest) GetEnd() int64 { } type LabelNamesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` unknownFields protoimpl.UnknownFields - - Names []string `protobuf:"bytes,1,rep,name=names,proto3" json:"names,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LabelNamesResponse) Reset() { *x = LabelNamesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LabelNamesResponse) String() string { @@ -572,8 +687,8 @@ func (x *LabelNamesResponse) String() string { func (*LabelNamesResponse) ProtoMessage() {} func (x *LabelNamesResponse) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[9] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -585,7 +700,7 @@ func (x *LabelNamesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LabelNamesResponse.ProtoReflect.Descriptor instead. func (*LabelNamesResponse) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{8} + return file_types_v1_types_proto_rawDescGZIP(), []int{9} } func (x *LabelNamesResponse) GetNames() []string { @@ -596,24 +711,21 @@ func (x *LabelNamesResponse) GetNames() []string { } type BlockInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Ulid string `protobuf:"bytes,1,opt,name=ulid,proto3" json:"ulid,omitempty"` + MinTime int64 `protobuf:"varint,2,opt,name=min_time,json=minTime,proto3" json:"min_time,omitempty"` + MaxTime int64 `protobuf:"varint,3,opt,name=max_time,json=maxTime,proto3" json:"max_time,omitempty"` + Compaction *BlockCompaction `protobuf:"bytes,4,opt,name=compaction,proto3" json:"compaction,omitempty"` + Labels []*LabelPair `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty"` unknownFields protoimpl.UnknownFields - - Ulid string `protobuf:"bytes,1,opt,name=ulid,proto3" json:"ulid,omitempty"` - MinTime int64 `protobuf:"varint,2,opt,name=min_time,json=minTime,proto3" json:"min_time,omitempty"` - MaxTime int64 `protobuf:"varint,3,opt,name=max_time,json=maxTime,proto3" json:"max_time,omitempty"` - Compaction *BlockCompaction `protobuf:"bytes,4,opt,name=compaction,proto3" json:"compaction,omitempty"` - Labels []*LabelPair `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BlockInfo) Reset() { *x = BlockInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BlockInfo) String() string { @@ -623,8 +735,8 @@ func (x *BlockInfo) String() string { func (*BlockInfo) ProtoMessage() {} func (x *BlockInfo) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[10] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -636,7 +748,7 @@ func (x *BlockInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockInfo.ProtoReflect.Descriptor instead. func (*BlockInfo) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{9} + return file_types_v1_types_proto_rawDescGZIP(), []int{10} } func (x *BlockInfo) GetUlid() string { @@ -675,22 +787,19 @@ func (x *BlockInfo) GetLabels() []*LabelPair { } type BlockCompaction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Level int32 `protobuf:"varint,1,opt,name=level,proto3" json:"level,omitempty"` + Sources []string `protobuf:"bytes,2,rep,name=sources,proto3" json:"sources,omitempty"` + Parents []string `protobuf:"bytes,3,rep,name=parents,proto3" json:"parents,omitempty"` unknownFields protoimpl.UnknownFields - - Level int32 `protobuf:"varint,1,opt,name=level,proto3" json:"level,omitempty"` - Sources []string `protobuf:"bytes,2,rep,name=sources,proto3" json:"sources,omitempty"` - Parents []string `protobuf:"bytes,3,rep,name=parents,proto3" json:"parents,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BlockCompaction) Reset() { *x = BlockCompaction{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BlockCompaction) String() string { @@ -700,8 +809,8 @@ func (x *BlockCompaction) String() string { func (*BlockCompaction) ProtoMessage() {} func (x *BlockCompaction) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[11] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -713,7 +822,7 @@ func (x *BlockCompaction) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockCompaction.ProtoReflect.Descriptor instead. func (*BlockCompaction) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{10} + return file_types_v1_types_proto_rawDescGZIP(), []int{11} } func (x *BlockCompaction) GetLevel() int32 { @@ -739,23 +848,23 @@ func (x *BlockCompaction) GetParents() []string { // StackTraceSelector is used for filtering stack traces by locations. type StackTraceSelector struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Stack trace of the call site. Root at call_site[0]. // Only stack traces having the prefix provided will be selected. // If empty, the filter is ignored. CallSite []*Location `protobuf:"bytes,1,rep,name=call_site,json=callSite,proto3" json:"call_site,omitempty"` + // Stack trace selector for profiles purposed for Go PGO. + // If set, call_site is ignored. + GoPgo *GoPGO `protobuf:"bytes,2,opt,name=go_pgo,json=goPgo,proto3" json:"go_pgo,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StackTraceSelector) Reset() { *x = StackTraceSelector{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StackTraceSelector) String() string { @@ -765,8 +874,8 @@ func (x *StackTraceSelector) String() string { func (*StackTraceSelector) ProtoMessage() {} func (x *StackTraceSelector) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[12] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -778,7 +887,7 @@ func (x *StackTraceSelector) ProtoReflect() protoreflect.Message { // Deprecated: Use StackTraceSelector.ProtoReflect.Descriptor instead. func (*StackTraceSelector) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{11} + return file_types_v1_types_proto_rawDescGZIP(), []int{12} } func (x *StackTraceSelector) GetCallSite() []*Location { @@ -788,21 +897,25 @@ func (x *StackTraceSelector) GetCallSite() []*Location { return nil } +func (x *StackTraceSelector) GetGoPgo() *GoPGO { + if x != nil { + return x.GoPgo + } + return nil +} + type Location struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Location) Reset() { *x = Location{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Location) String() string { @@ -812,8 +925,8 @@ func (x *Location) String() string { func (*Location) ProtoMessage() {} func (x *Location) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[13] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -825,7 +938,7 @@ func (x *Location) ProtoReflect() protoreflect.Message { // Deprecated: Use Location.ProtoReflect.Descriptor instead. func (*Location) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{12} + return file_types_v1_types_proto_rawDescGZIP(), []int{13} } func (x *Location) GetName() string { @@ -835,19 +948,72 @@ func (x *Location) GetName() string { return "" } +type GoPGO struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Specifies the number of leaf locations to keep. + KeepLocations uint32 `protobuf:"varint,1,opt,name=keep_locations,json=keepLocations,proto3" json:"keep_locations,omitempty"` + // Aggregate callees causes the leaf location line number to be ignored, + // thus aggregating all callee samples (but not callers). + AggregateCallees bool `protobuf:"varint,2,opt,name=aggregate_callees,json=aggregateCallees,proto3" json:"aggregate_callees,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GoPGO) Reset() { + *x = GoPGO{} + mi := &file_types_v1_types_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GoPGO) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GoPGO) ProtoMessage() {} + +func (x *GoPGO) ProtoReflect() protoreflect.Message { + mi := &file_types_v1_types_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GoPGO.ProtoReflect.Descriptor instead. +func (*GoPGO) Descriptor() ([]byte, []int) { + return file_types_v1_types_proto_rawDescGZIP(), []int{14} +} + +func (x *GoPGO) GetKeepLocations() uint32 { + if x != nil { + return x.KeepLocations + } + return 0 +} + +func (x *GoPGO) GetAggregateCallees() bool { + if x != nil { + return x.AggregateCallees + } + return false +} + type GetProfileStatsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetProfileStatsRequest) Reset() { *x = GetProfileStatsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetProfileStatsRequest) String() string { @@ -857,8 +1023,8 @@ func (x *GetProfileStatsRequest) String() string { func (*GetProfileStatsRequest) ProtoMessage() {} func (x *GetProfileStatsRequest) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[15] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -870,29 +1036,26 @@ func (x *GetProfileStatsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProfileStatsRequest.ProtoReflect.Descriptor instead. func (*GetProfileStatsRequest) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{13} + return file_types_v1_types_proto_rawDescGZIP(), []int{15} } type GetProfileStatsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Whether we received any data at any time in the past. DataIngested bool `protobuf:"varint,1,opt,name=data_ingested,json=dataIngested,proto3" json:"data_ingested,omitempty"` // Milliseconds since epoch. OldestProfileTime int64 `protobuf:"varint,2,opt,name=oldest_profile_time,json=oldestProfileTime,proto3" json:"oldest_profile_time,omitempty"` // Milliseconds since epoch. NewestProfileTime int64 `protobuf:"varint,3,opt,name=newest_profile_time,json=newestProfileTime,proto3" json:"newest_profile_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetProfileStatsResponse) Reset() { *x = GetProfileStatsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_types_v1_types_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_types_v1_types_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetProfileStatsResponse) String() string { @@ -902,8 +1065,8 @@ func (x *GetProfileStatsResponse) String() string { func (*GetProfileStatsResponse) ProtoMessage() {} func (x *GetProfileStatsResponse) ProtoReflect() protoreflect.Message { - mi := &file_types_v1_types_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + mi := &file_types_v1_types_proto_msgTypes[16] + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -915,7 +1078,7 @@ func (x *GetProfileStatsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProfileStatsResponse.ProtoReflect.Descriptor instead. func (*GetProfileStatsResponse) Descriptor() ([]byte, []int) { - return file_types_v1_types_proto_rawDescGZIP(), []int{14} + return file_types_v1_types_proto_rawDescGZIP(), []int{16} } func (x *GetProfileStatsResponse) GetDataIngested() bool { @@ -939,157 +1102,381 @@ func (x *GetProfileStatsResponse) GetNewestProfileTime() int64 { return 0 } -var File_types_v1_types_proto protoreflect.FileDescriptor +// Exemplar represents metadata for an individual profile sample. +// Exemplars allow users to drill down from aggregated timeline views +// to specific profile instances. +type Exemplar struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Milliseconds since epoch when the profile was captured. + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // Unique identifier for the profile (UUID). + ProfileId string `protobuf:"bytes,2,opt,name=profile_id,json=profileId,proto3" json:"profile_id,omitempty"` + // Span ID if this profile was split by span during ingestion. + SpanId string `protobuf:"bytes,3,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"` + // Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + Value int64 `protobuf:"varint,4,opt,name=value,proto3" json:"value,omitempty"` + // Labels specific to this exemplar (e.g., pod name, node name). When an exemplar + // label overlaps with the series label, it is not included here. + Labels []*LabelPair `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty"` + // Trace ID associated with the span, encoded as 32 lowercase hexadecimal characters. + TraceId string `protobuf:"bytes,6,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Exemplar) Reset() { + *x = Exemplar{} + mi := &file_types_v1_types_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Exemplar) String() string { + return protoimpl.X.MessageStringOf(x) +} -var file_types_v1_types_proto_rawDesc = []byte{ - 0x0a, 0x14, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x22, 0x35, 0x0a, 0x09, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xb5, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x55, 0x6e, 0x69, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x55, 0x6e, 0x69, 0x74, 0x22, - 0x35, 0x0a, 0x06, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x2b, 0x0a, 0x06, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x06, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x22, 0x5e, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x12, 0x2b, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x27, 0x0a, - 0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x3b, 0x0a, 0x05, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x22, 0x6c, 0x0a, 0x12, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, - 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, - 0x64, 0x22, 0x2b, 0x0a, 0x13, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x57, - 0x0a, 0x11, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x12, - 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x2a, 0x0a, 0x12, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x22, 0xbd, 0x01, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x75, 0x6c, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, - 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x06, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x22, 0x5b, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, - 0x22, 0x45, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x54, 0x72, 0x61, 0x63, 0x65, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x73, - 0x69, 0x74, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x63, - 0x61, 0x6c, 0x6c, 0x53, 0x69, 0x74, 0x65, 0x22, 0x1e, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x9e, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, - 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x11, 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x6e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x11, 0x6e, 0x65, 0x77, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x2a, 0x6b, 0x0a, 0x19, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x24, 0x0a, 0x20, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x53, 0x45, 0x52, 0x49, 0x45, 0x53, 0x5f, 0x41, - 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x53, 0x55, 0x4d, 0x10, 0x00, 0x12, 0x28, 0x0a, 0x24, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x53, 0x45, - 0x52, 0x49, 0x45, 0x53, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x56, 0x45, 0x52, 0x41, 0x47, 0x45, 0x10, 0x01, 0x42, - 0x9b, 0x01, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x42, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, - 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x08, 0x54, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x56, 0x31, 0xca, - 0x02, 0x08, 0x54, 0x79, 0x70, 0x65, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x14, 0x54, 0x79, 0x70, - 0x65, 0x73, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x09, 0x54, 0x79, 0x70, 0x65, 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, +func (*Exemplar) ProtoMessage() {} + +func (x *Exemplar) ProtoReflect() protoreflect.Message { + mi := &file_types_v1_types_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Exemplar.ProtoReflect.Descriptor instead. +func (*Exemplar) Descriptor() ([]byte, []int) { + return file_types_v1_types_proto_rawDescGZIP(), []int{17} } +func (x *Exemplar) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *Exemplar) GetProfileId() string { + if x != nil { + return x.ProfileId + } + return "" +} + +func (x *Exemplar) GetSpanId() string { + if x != nil { + return x.SpanId + } + return "" +} + +func (x *Exemplar) GetValue() int64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *Exemplar) GetLabels() []*LabelPair { + if x != nil { + return x.Labels + } + return nil +} + +func (x *Exemplar) GetTraceId() string { + if x != nil { + return x.TraceId + } + return "" +} + +type HeatmapSeries struct { + state protoimpl.MessageState `protogen:"open.v1"` + Labels []*LabelPair `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"` + Slots []*HeatmapSlot `protobuf:"bytes,2,rep,name=slots,proto3" json:"slots,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HeatmapSeries) Reset() { + *x = HeatmapSeries{} + mi := &file_types_v1_types_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HeatmapSeries) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeatmapSeries) ProtoMessage() {} + +func (x *HeatmapSeries) ProtoReflect() protoreflect.Message { + mi := &file_types_v1_types_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeatmapSeries.ProtoReflect.Descriptor instead. +func (*HeatmapSeries) Descriptor() ([]byte, []int) { + return file_types_v1_types_proto_rawDescGZIP(), []int{18} +} + +func (x *HeatmapSeries) GetLabels() []*LabelPair { + if x != nil { + return x.Labels + } + return nil +} + +func (x *HeatmapSeries) GetSlots() []*HeatmapSlot { + if x != nil { + return x.Slots + } + return nil +} + +type HeatmapSlot struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Milliseconds unix timestamp of the right edge (x_max) of this slot. + // The slot covers the half-open interval (timestamp - step, timestamp]. + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // Minimum y value + YMin []float64 `protobuf:"fixed64,2,rep,packed,name=y_min,json=yMin,proto3" json:"y_min,omitempty"` + // How many matches + Counts []int32 `protobuf:"varint,3,rep,packed,name=counts,proto3" json:"counts,omitempty"` + // Provide exemplars + Exemplars []*Exemplar `protobuf:"bytes,4,rep,name=exemplars,proto3" json:"exemplars,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HeatmapSlot) Reset() { + *x = HeatmapSlot{} + mi := &file_types_v1_types_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HeatmapSlot) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeatmapSlot) ProtoMessage() {} + +func (x *HeatmapSlot) ProtoReflect() protoreflect.Message { + mi := &file_types_v1_types_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeatmapSlot.ProtoReflect.Descriptor instead. +func (*HeatmapSlot) Descriptor() ([]byte, []int) { + return file_types_v1_types_proto_rawDescGZIP(), []int{19} +} + +func (x *HeatmapSlot) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *HeatmapSlot) GetYMin() []float64 { + if x != nil { + return x.YMin + } + return nil +} + +func (x *HeatmapSlot) GetCounts() []int32 { + if x != nil { + return x.Counts + } + return nil +} + +func (x *HeatmapSlot) GetExemplars() []*Exemplar { + if x != nil { + return x.Exemplars + } + return nil +} + +var File_types_v1_types_proto protoreflect.FileDescriptor + +const file_types_v1_types_proto_rawDesc = "" + + "\n" + + "\x14types/v1/types.proto\x12\btypes.v1\x1a$gnostic/openapi/v3/annotations.proto\"]\n" + + "\tLabelPair\x12'\n" + + "\x04name\x18\x01 \x01(\tB\x13\xbaG\x10:\x0e\x12\fservice_nameR\x04name\x12'\n" + + "\x05value\x18\x02 \x01(\tB\x11\xbaG\x0e:\f\x12\n" + + "my_serviceR\x05value\"\xb5\x01\n" + + "\vProfileType\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\tR\x02ID\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1f\n" + + "\vsample_type\x18\x04 \x01(\tR\n" + + "sampleType\x12\x1f\n" + + "\vsample_unit\x18\x05 \x01(\tR\n" + + "sampleUnit\x12\x1f\n" + + "\vperiod_type\x18\x06 \x01(\tR\n" + + "periodType\x12\x1f\n" + + "\vperiod_unit\x18\a \x01(\tR\n" + + "periodUnit\"5\n" + + "\x06Labels\x12+\n" + + "\x06labels\x18\x01 \x03(\v2\x13.types.v1.LabelPairR\x06labels\"^\n" + + "\x06Series\x12+\n" + + "\x06labels\x18\x01 \x03(\v2\x13.types.v1.LabelPairR\x06labels\x12'\n" + + "\x06points\x18\x02 \x03(\v2\x0f.types.v1.PointR\x06points\"\xac\x01\n" + + "\x05Point\x12\x14\n" + + "\x05value\x18\x01 \x01(\x01R\x05value\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\x12=\n" + + "\vannotations\x18\x03 \x03(\v2\x1b.types.v1.ProfileAnnotationR\vannotations\x120\n" + + "\texemplars\x18\x04 \x03(\v2\x12.types.v1.ExemplarR\texemplars\";\n" + + "\x11ProfileAnnotation\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value\"\xad\x01\n" + + "\x12LabelValuesRequest\x12'\n" + + "\x04name\x18\x01 \x01(\tB\x13\xbaG\x10:\x0e\x12\fservice_nameR\x04name\x12\x1a\n" + + "\bmatchers\x18\x02 \x03(\tR\bmatchers\x12*\n" + + "\x05start\x18\x03 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x04 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\"+\n" + + "\x13LabelValuesResponse\x12\x14\n" + + "\x05names\x18\x01 \x03(\tR\x05names\"\x83\x01\n" + + "\x11LabelNamesRequest\x12\x1a\n" + + "\bmatchers\x18\x01 \x03(\tR\bmatchers\x12*\n" + + "\x05start\x18\x02 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676282400000R\x05start\x12&\n" + + "\x03end\x18\x03 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1676289600000R\x03end\"*\n" + + "\x12LabelNamesResponse\x12\x14\n" + + "\x05names\x18\x01 \x03(\tR\x05names\"\xbd\x01\n" + + "\tBlockInfo\x12\x12\n" + + "\x04ulid\x18\x01 \x01(\tR\x04ulid\x12\x19\n" + + "\bmin_time\x18\x02 \x01(\x03R\aminTime\x12\x19\n" + + "\bmax_time\x18\x03 \x01(\x03R\amaxTime\x129\n" + + "\n" + + "compaction\x18\x04 \x01(\v2\x19.types.v1.BlockCompactionR\n" + + "compaction\x12+\n" + + "\x06labels\x18\x05 \x03(\v2\x13.types.v1.LabelPairR\x06labels\"[\n" + + "\x0fBlockCompaction\x12\x14\n" + + "\x05level\x18\x01 \x01(\x05R\x05level\x12\x18\n" + + "\asources\x18\x02 \x03(\tR\asources\x12\x18\n" + + "\aparents\x18\x03 \x03(\tR\aparents\"m\n" + + "\x12StackTraceSelector\x12/\n" + + "\tcall_site\x18\x01 \x03(\v2\x12.types.v1.LocationR\bcallSite\x12&\n" + + "\x06go_pgo\x18\x02 \x01(\v2\x0f.types.v1.GoPGOR\x05goPgo\"\x1e\n" + + "\bLocation\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"[\n" + + "\x05GoPGO\x12%\n" + + "\x0ekeep_locations\x18\x01 \x01(\rR\rkeepLocations\x12+\n" + + "\x11aggregate_callees\x18\x02 \x01(\bR\x10aggregateCallees\"\x18\n" + + "\x16GetProfileStatsRequest\"\x9e\x01\n" + + "\x17GetProfileStatsResponse\x12#\n" + + "\rdata_ingested\x18\x01 \x01(\bR\fdataIngested\x12.\n" + + "\x13oldest_profile_time\x18\x02 \x01(\x03R\x11oldestProfileTime\x12.\n" + + "\x13newest_profile_time\x18\x03 \x01(\x03R\x11newestProfileTime\"\xd6\x02\n" + + "\bExemplar\x122\n" + + "\ttimestamp\x18\x01 \x01(\x03B\x14\xbaG\x11:\x0f\x12\r1730000023000R\ttimestamp\x12J\n" + + "\n" + + "profile_id\x18\x02 \x01(\tB+\xbaG(:&\x12$7c9e6679-7425-40de-944b-e07fc1f90ae7R\tprofileId\x120\n" + + "\aspan_id\x18\x03 \x01(\tB\x17\xbaG\x14:\x12\x12\x1000f067aa0ba902b7R\x06spanId\x12'\n" + + "\x05value\x18\x04 \x01(\x03B\x11\xbaG\x0e:\f\x12\n" + + "2450000000R\x05value\x12+\n" + + "\x06labels\x18\x05 \x03(\v2\x13.types.v1.LabelPairR\x06labels\x12B\n" + + "\btrace_id\x18\x06 \x01(\tB'\xbaG$:\"\x12 4bf92f3577b34da6a3ce929d0e0e4736R\atraceId\"i\n" + + "\rHeatmapSeries\x12+\n" + + "\x06labels\x18\x01 \x03(\v2\x13.types.v1.LabelPairR\x06labels\x12+\n" + + "\x05slots\x18\x02 \x03(\v2\x15.types.v1.HeatmapSlotR\x05slots\"\x8a\x01\n" + + "\vHeatmapSlot\x12\x1c\n" + + "\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12\x13\n" + + "\x05y_min\x18\x02 \x03(\x01R\x04yMin\x12\x16\n" + + "\x06counts\x18\x03 \x03(\x05R\x06counts\x120\n" + + "\texemplars\x18\x04 \x03(\v2\x12.types.v1.ExemplarR\texemplars*k\n" + + "\x19TimeSeriesAggregationType\x12$\n" + + " TIME_SERIES_AGGREGATION_TYPE_SUM\x10\x00\x12(\n" + + "$TIME_SERIES_AGGREGATION_TYPE_AVERAGE\x10\x01*{\n" + + "\fExemplarType\x12\x1d\n" + + "\x19EXEMPLAR_TYPE_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12EXEMPLAR_TYPE_NONE\x10\x01\x12\x1c\n" + + "\x18EXEMPLAR_TYPE_INDIVIDUAL\x10\x02\x12\x16\n" + + "\x12EXEMPLAR_TYPE_SPAN\x10\x03B\x9b\x01\n" + + "\fcom.types.v1B\n" + + "TypesProtoP\x01Z>github.com/grafana/pyroscope/api/gen/proto/go/types/v1;typesv1\xa2\x02\x03TXX\xaa\x02\bTypes.V1\xca\x02\bTypes\\V1\xe2\x02\x14Types\\V1\\GPBMetadata\xea\x02\tTypes::V1b\x06proto3" + var ( file_types_v1_types_proto_rawDescOnce sync.Once - file_types_v1_types_proto_rawDescData = file_types_v1_types_proto_rawDesc + file_types_v1_types_proto_rawDescData []byte ) func file_types_v1_types_proto_rawDescGZIP() []byte { file_types_v1_types_proto_rawDescOnce.Do(func() { - file_types_v1_types_proto_rawDescData = protoimpl.X.CompressGZIP(file_types_v1_types_proto_rawDescData) + file_types_v1_types_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_types_v1_types_proto_rawDesc), len(file_types_v1_types_proto_rawDesc))) }) return file_types_v1_types_proto_rawDescData } -var file_types_v1_types_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_types_v1_types_proto_msgTypes = make([]protoimpl.MessageInfo, 15) -var file_types_v1_types_proto_goTypes = []interface{}{ +var file_types_v1_types_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_types_v1_types_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_types_v1_types_proto_goTypes = []any{ (TimeSeriesAggregationType)(0), // 0: types.v1.TimeSeriesAggregationType - (*LabelPair)(nil), // 1: types.v1.LabelPair - (*ProfileType)(nil), // 2: types.v1.ProfileType - (*Labels)(nil), // 3: types.v1.Labels - (*Series)(nil), // 4: types.v1.Series - (*Point)(nil), // 5: types.v1.Point - (*LabelValuesRequest)(nil), // 6: types.v1.LabelValuesRequest - (*LabelValuesResponse)(nil), // 7: types.v1.LabelValuesResponse - (*LabelNamesRequest)(nil), // 8: types.v1.LabelNamesRequest - (*LabelNamesResponse)(nil), // 9: types.v1.LabelNamesResponse - (*BlockInfo)(nil), // 10: types.v1.BlockInfo - (*BlockCompaction)(nil), // 11: types.v1.BlockCompaction - (*StackTraceSelector)(nil), // 12: types.v1.StackTraceSelector - (*Location)(nil), // 13: types.v1.Location - (*GetProfileStatsRequest)(nil), // 14: types.v1.GetProfileStatsRequest - (*GetProfileStatsResponse)(nil), // 15: types.v1.GetProfileStatsResponse + (ExemplarType)(0), // 1: types.v1.ExemplarType + (*LabelPair)(nil), // 2: types.v1.LabelPair + (*ProfileType)(nil), // 3: types.v1.ProfileType + (*Labels)(nil), // 4: types.v1.Labels + (*Series)(nil), // 5: types.v1.Series + (*Point)(nil), // 6: types.v1.Point + (*ProfileAnnotation)(nil), // 7: types.v1.ProfileAnnotation + (*LabelValuesRequest)(nil), // 8: types.v1.LabelValuesRequest + (*LabelValuesResponse)(nil), // 9: types.v1.LabelValuesResponse + (*LabelNamesRequest)(nil), // 10: types.v1.LabelNamesRequest + (*LabelNamesResponse)(nil), // 11: types.v1.LabelNamesResponse + (*BlockInfo)(nil), // 12: types.v1.BlockInfo + (*BlockCompaction)(nil), // 13: types.v1.BlockCompaction + (*StackTraceSelector)(nil), // 14: types.v1.StackTraceSelector + (*Location)(nil), // 15: types.v1.Location + (*GoPGO)(nil), // 16: types.v1.GoPGO + (*GetProfileStatsRequest)(nil), // 17: types.v1.GetProfileStatsRequest + (*GetProfileStatsResponse)(nil), // 18: types.v1.GetProfileStatsResponse + (*Exemplar)(nil), // 19: types.v1.Exemplar + (*HeatmapSeries)(nil), // 20: types.v1.HeatmapSeries + (*HeatmapSlot)(nil), // 21: types.v1.HeatmapSlot } var file_types_v1_types_proto_depIdxs = []int32{ - 1, // 0: types.v1.Labels.labels:type_name -> types.v1.LabelPair - 1, // 1: types.v1.Series.labels:type_name -> types.v1.LabelPair - 5, // 2: types.v1.Series.points:type_name -> types.v1.Point - 11, // 3: types.v1.BlockInfo.compaction:type_name -> types.v1.BlockCompaction - 1, // 4: types.v1.BlockInfo.labels:type_name -> types.v1.LabelPair - 13, // 5: types.v1.StackTraceSelector.call_site:type_name -> types.v1.Location - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 2, // 0: types.v1.Labels.labels:type_name -> types.v1.LabelPair + 2, // 1: types.v1.Series.labels:type_name -> types.v1.LabelPair + 6, // 2: types.v1.Series.points:type_name -> types.v1.Point + 7, // 3: types.v1.Point.annotations:type_name -> types.v1.ProfileAnnotation + 19, // 4: types.v1.Point.exemplars:type_name -> types.v1.Exemplar + 13, // 5: types.v1.BlockInfo.compaction:type_name -> types.v1.BlockCompaction + 2, // 6: types.v1.BlockInfo.labels:type_name -> types.v1.LabelPair + 15, // 7: types.v1.StackTraceSelector.call_site:type_name -> types.v1.Location + 16, // 8: types.v1.StackTraceSelector.go_pgo:type_name -> types.v1.GoPGO + 2, // 9: types.v1.Exemplar.labels:type_name -> types.v1.LabelPair + 2, // 10: types.v1.HeatmapSeries.labels:type_name -> types.v1.LabelPair + 21, // 11: types.v1.HeatmapSeries.slots:type_name -> types.v1.HeatmapSlot + 19, // 12: types.v1.HeatmapSlot.exemplars:type_name -> types.v1.Exemplar + 13, // [13:13] is the sub-list for method output_type + 13, // [13:13] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_types_v1_types_proto_init() } @@ -1097,195 +1484,13 @@ func file_types_v1_types_proto_init() { if File_types_v1_types_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_types_v1_types_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LabelPair); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProfileType); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Labels); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Series); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Point); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LabelValuesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LabelValuesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LabelNamesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LabelNamesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockCompaction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StackTraceSelector); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Location); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetProfileStatsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_types_v1_types_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetProfileStatsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_types_v1_types_proto_rawDesc, - NumEnums: 1, - NumMessages: 15, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_v1_types_proto_rawDesc), len(file_types_v1_types_proto_rawDesc)), + NumEnums: 2, + NumMessages: 20, NumExtensions: 0, NumServices: 0, }, @@ -1295,7 +1500,6 @@ func file_types_v1_types_proto_init() { MessageInfos: file_types_v1_types_proto_msgTypes, }.Build() File_types_v1_types_proto = out.File - file_types_v1_types_proto_rawDesc = nil file_types_v1_types_proto_goTypes = nil file_types_v1_types_proto_depIdxs = nil } diff --git a/api/gen/proto/go/types/v1/types_vtproto.pb.go b/api/gen/proto/go/types/v1/types_vtproto.pb.go index 6d0a40477d..44b0e29485 100644 --- a/api/gen/proto/go/types/v1/types_vtproto.pb.go +++ b/api/gen/proto/go/types/v1/types_vtproto.pb.go @@ -121,6 +121,20 @@ func (m *Point) CloneVT() *Point { r := new(Point) r.Value = m.Value r.Timestamp = m.Timestamp + if rhs := m.Annotations; rhs != nil { + tmpContainer := make([]*ProfileAnnotation, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Annotations = tmpContainer + } + if rhs := m.Exemplars; rhs != nil { + tmpContainer := make([]*Exemplar, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Exemplars = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -132,6 +146,24 @@ func (m *Point) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *ProfileAnnotation) CloneVT() *ProfileAnnotation { + if m == nil { + return (*ProfileAnnotation)(nil) + } + r := new(ProfileAnnotation) + r.Key = m.Key + r.Value = m.Value + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *ProfileAnnotation) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *LabelValuesRequest) CloneVT() *LabelValuesRequest { if m == nil { return (*LabelValuesRequest)(nil) @@ -280,6 +312,7 @@ func (m *StackTraceSelector) CloneVT() *StackTraceSelector { return (*StackTraceSelector)(nil) } r := new(StackTraceSelector) + r.GoPgo = m.GoPgo.CloneVT() if rhs := m.CallSite; rhs != nil { tmpContainer := make([]*Location, len(rhs)) for k, v := range rhs { @@ -315,6 +348,24 @@ func (m *Location) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *GoPGO) CloneVT() *GoPGO { + if m == nil { + return (*GoPGO)(nil) + } + r := new(GoPGO) + r.KeepLocations = m.KeepLocations + r.AggregateCallees = m.AggregateCallees + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GoPGO) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *GetProfileStatsRequest) CloneVT() *GetProfileStatsRequest { if m == nil { return (*GetProfileStatsRequest)(nil) @@ -350,6 +401,98 @@ func (m *GetProfileStatsResponse) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *Exemplar) CloneVT() *Exemplar { + if m == nil { + return (*Exemplar)(nil) + } + r := new(Exemplar) + r.Timestamp = m.Timestamp + r.ProfileId = m.ProfileId + r.SpanId = m.SpanId + r.Value = m.Value + r.TraceId = m.TraceId + if rhs := m.Labels; rhs != nil { + tmpContainer := make([]*LabelPair, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Labels = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *Exemplar) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *HeatmapSeries) CloneVT() *HeatmapSeries { + if m == nil { + return (*HeatmapSeries)(nil) + } + r := new(HeatmapSeries) + if rhs := m.Labels; rhs != nil { + tmpContainer := make([]*LabelPair, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Labels = tmpContainer + } + if rhs := m.Slots; rhs != nil { + tmpContainer := make([]*HeatmapSlot, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Slots = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *HeatmapSeries) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *HeatmapSlot) CloneVT() *HeatmapSlot { + if m == nil { + return (*HeatmapSlot)(nil) + } + r := new(HeatmapSlot) + r.Timestamp = m.Timestamp + if rhs := m.YMin; rhs != nil { + tmpContainer := make([]float64, len(rhs)) + copy(tmpContainer, rhs) + r.YMin = tmpContainer + } + if rhs := m.Counts; rhs != nil { + tmpContainer := make([]int32, len(rhs)) + copy(tmpContainer, rhs) + r.Counts = tmpContainer + } + if rhs := m.Exemplars; rhs != nil { + tmpContainer := make([]*Exemplar, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Exemplars = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *HeatmapSlot) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (this *LabelPair) EqualVT(that *LabelPair) bool { if this == that { return true @@ -501,6 +644,40 @@ func (this *Point) EqualVT(that *Point) bool { if this.Timestamp != that.Timestamp { return false } + if len(this.Annotations) != len(that.Annotations) { + return false + } + for i, vx := range this.Annotations { + vy := that.Annotations[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &ProfileAnnotation{} + } + if q == nil { + q = &ProfileAnnotation{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.Exemplars) != len(that.Exemplars) { + return false + } + for i, vx := range this.Exemplars { + vy := that.Exemplars[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Exemplar{} + } + if q == nil { + q = &Exemplar{} + } + if !p.EqualVT(q) { + return false + } + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -511,6 +688,28 @@ func (this *Point) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *ProfileAnnotation) EqualVT(that *ProfileAnnotation) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Key != that.Key { + return false + } + if this.Value != that.Value { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *ProfileAnnotation) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*ProfileAnnotation) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *LabelValuesRequest) EqualVT(that *LabelValuesRequest) bool { if this == that { return true @@ -731,6 +930,9 @@ func (this *StackTraceSelector) EqualVT(that *StackTraceSelector) bool { } } } + if !this.GoPgo.EqualVT(that.GoPgo) { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -760,6 +962,28 @@ func (this *Location) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *GoPGO) EqualVT(that *GoPGO) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.KeepLocations != that.KeepLocations { + return false + } + if this.AggregateCallees != that.AggregateCallees { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GoPGO) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GoPGO) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *GetProfileStatsRequest) EqualVT(that *GetProfileStatsRequest) bool { if this == that { return true @@ -801,80 +1025,232 @@ func (this *GetProfileStatsResponse) EqualMessageVT(thatMsg proto.Message) bool } return this.EqualVT(that) } -func (m *LabelPair) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil +func (this *Exemplar) EqualVT(that *Exemplar) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err + if this.Timestamp != that.Timestamp { + return false } - return dAtA[:n], nil -} - -func (m *LabelPair) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *LabelPair) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil + if this.ProfileId != that.ProfileId { + return false } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) + if this.SpanId != that.SpanId { + return false } - if len(m.Value) > 0 { - i -= len(m.Value) - copy(dAtA[i:], m.Value) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value))) - i-- - dAtA[i] = 0x12 + if this.Value != that.Value { + return false } - if len(m.Name) > 0 { - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0xa + if len(this.Labels) != len(that.Labels) { + return false } - return len(dAtA) - i, nil -} - -func (m *ProfileType) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil + for i, vx := range this.Labels { + vy := that.Labels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &LabelPair{} + } + if q == nil { + q = &LabelPair{} + } + if !p.EqualVT(q) { + return false + } + } } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err + if this.TraceId != that.TraceId { + return false } - return dAtA[:n], nil + return string(this.unknownFields) == string(that.unknownFields) } -func (m *ProfileType) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) +func (this *Exemplar) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*Exemplar) + if !ok { + return false + } + return this.EqualVT(that) } - -func (m *ProfileType) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil +func (this *HeatmapSeries) EqualVT(that *HeatmapSeries) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { + if len(this.Labels) != len(that.Labels) { + return false + } + for i, vx := range this.Labels { + vy := that.Labels[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &LabelPair{} + } + if q == nil { + q = &LabelPair{} + } + if !p.EqualVT(q) { + return false + } + } + } + if len(this.Slots) != len(that.Slots) { + return false + } + for i, vx := range this.Slots { + vy := that.Slots[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &HeatmapSlot{} + } + if q == nil { + q = &HeatmapSlot{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *HeatmapSeries) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*HeatmapSeries) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *HeatmapSlot) EqualVT(that *HeatmapSlot) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Timestamp != that.Timestamp { + return false + } + if len(this.YMin) != len(that.YMin) { + return false + } + for i, vx := range this.YMin { + vy := that.YMin[i] + if vx != vy { + return false + } + } + if len(this.Counts) != len(that.Counts) { + return false + } + for i, vx := range this.Counts { + vy := that.Counts[i] + if vx != vy { + return false + } + } + if len(this.Exemplars) != len(that.Exemplars) { + return false + } + for i, vx := range this.Exemplars { + vy := that.Exemplars[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &Exemplar{} + } + if q == nil { + q = &Exemplar{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *HeatmapSlot) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*HeatmapSlot) + if !ok { + return false + } + return this.EqualVT(that) +} +func (m *LabelPair) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LabelPair) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *LabelPair) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ProfileType) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ProfileType) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ProfileType) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } @@ -1055,6 +1431,30 @@ func (m *Point) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.Exemplars) > 0 { + for iNdEx := len(m.Exemplars) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Exemplars[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + } + if len(m.Annotations) > 0 { + for iNdEx := len(m.Annotations) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Annotations[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + } if m.Timestamp != 0 { i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timestamp)) i-- @@ -1069,6 +1469,53 @@ func (m *Point) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ProfileAnnotation) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ProfileAnnotation) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ProfileAnnotation) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *LabelValuesRequest) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -1422,6 +1869,16 @@ func (m *StackTraceSelector) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.GoPgo != nil { + size, err := m.GoPgo.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } if len(m.CallSite) > 0 { for iNdEx := len(m.CallSite) - 1; iNdEx >= 0; iNdEx-- { size, err := m.CallSite[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) @@ -1477,7 +1934,7 @@ func (m *Location) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *GetProfileStatsRequest) MarshalVT() (dAtA []byte, err error) { +func (m *GoPGO) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -1490,12 +1947,12 @@ func (m *GetProfileStatsRequest) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *GetProfileStatsRequest) MarshalToVT(dAtA []byte) (int, error) { +func (m *GoPGO) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *GetProfileStatsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *GoPGO) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -1507,10 +1964,25 @@ func (m *GetProfileStatsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.AggregateCallees { + i-- + if m.AggregateCallees { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.KeepLocations != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.KeepLocations)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } -func (m *GetProfileStatsResponse) MarshalVT() (dAtA []byte, err error) { +func (m *GetProfileStatsRequest) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -1523,12 +1995,12 @@ func (m *GetProfileStatsResponse) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *GetProfileStatsResponse) MarshalToVT(dAtA []byte) (int, error) { +func (m *GetProfileStatsRequest) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *GetProfileStatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *GetProfileStatsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -1540,26 +2012,273 @@ func (m *GetProfileStatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, erro i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if m.NewestProfileTime != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.NewestProfileTime)) - i-- - dAtA[i] = 0x18 - } - if m.OldestProfileTime != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.OldestProfileTime)) - i-- - dAtA[i] = 0x10 - } - if m.DataIngested { - i-- - if m.DataIngested { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x8 - } + return len(dAtA) - i, nil +} + +func (m *GetProfileStatsResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetProfileStatsResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetProfileStatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.NewestProfileTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.NewestProfileTime)) + i-- + dAtA[i] = 0x18 + } + if m.OldestProfileTime != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.OldestProfileTime)) + i-- + dAtA[i] = 0x10 + } + if m.DataIngested { + i-- + if m.DataIngested { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Exemplar) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Exemplar) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *Exemplar) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TraceId) > 0 { + i -= len(m.TraceId) + copy(dAtA[i:], m.TraceId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TraceId))) + i-- + dAtA[i] = 0x32 + } + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Labels[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x2a + } + } + if m.Value != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Value)) + i-- + dAtA[i] = 0x20 + } + if len(m.SpanId) > 0 { + i -= len(m.SpanId) + copy(dAtA[i:], m.SpanId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpanId))) + i-- + dAtA[i] = 0x1a + } + if len(m.ProfileId) > 0 { + i -= len(m.ProfileId) + copy(dAtA[i:], m.ProfileId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProfileId))) + i-- + dAtA[i] = 0x12 + } + if m.Timestamp != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *HeatmapSeries) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HeatmapSeries) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *HeatmapSeries) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Slots) > 0 { + for iNdEx := len(m.Slots) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Slots[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Labels[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *HeatmapSlot) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HeatmapSlot) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *HeatmapSlot) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Exemplars) > 0 { + for iNdEx := len(m.Exemplars) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Exemplars[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + } + if len(m.Counts) > 0 { + var pksize2 int + for _, num := range m.Counts { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num1 := range m.Counts { + num := uint64(num1) + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x1a + } + if len(m.YMin) > 0 { + for iNdEx := len(m.YMin) - 1; iNdEx >= 0; iNdEx-- { + f3 := math.Float64bits(float64(m.YMin[iNdEx])) + i -= 8 + binary.LittleEndian.PutUint64(dAtA[i:], uint64(f3)) + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.YMin)*8)) + i-- + dAtA[i] = 0x12 + } + if m.Timestamp != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -1665,6 +2384,36 @@ func (m *Point) SizeVT() (n int) { if m.Timestamp != 0 { n += 1 + protohelpers.SizeOfVarint(uint64(m.Timestamp)) } + if len(m.Annotations) > 0 { + for _, e := range m.Annotations { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Exemplars) > 0 { + for _, e := range m.Exemplars { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *ProfileAnnotation) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -1816,6 +2565,10 @@ func (m *StackTraceSelector) SizeVT() (n int) { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } } + if m.GoPgo != nil { + l = m.GoPgo.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -1834,6 +2587,22 @@ func (m *Location) SizeVT() (n int) { return n } +func (m *GoPGO) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.KeepLocations != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.KeepLocations)) + } + if m.AggregateCallees { + n += 2 + } + n += len(m.unknownFields) + return n +} + func (m *GetProfileStatsRequest) SizeVT() (n int) { if m == nil { return 0 @@ -1863,10 +2632,95 @@ func (m *GetProfileStatsResponse) SizeVT() (n int) { return n } -func (m *LabelPair) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { +func (m *Exemplar) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Timestamp != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Timestamp)) + } + l = len(m.ProfileId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.SpanId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Value != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Value)) + } + if len(m.Labels) > 0 { + for _, e := range m.Labels { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + l = len(m.TraceId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *HeatmapSeries) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Labels) > 0 { + for _, e := range m.Labels { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Slots) > 0 { + for _, e := range m.Slots { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *HeatmapSlot) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Timestamp != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Timestamp)) + } + if len(m.YMin) > 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(len(m.YMin)*8)) + len(m.YMin)*8 + } + if len(m.Counts) > 0 { + l = 0 + for _, e := range m.Counts { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.Exemplars) > 0 { + for _, e := range m.Exemplars { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *LabelPair) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { @@ -2484,6 +3338,189 @@ func (m *Point) UnmarshalVT(dAtA []byte) error { break } } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Annotations = append(m.Annotations, &ProfileAnnotation{}) + if err := m.Annotations[len(m.Annotations)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Exemplars", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Exemplars = append(m.Exemplars, &Exemplar{}) + if err := m.Exemplars[len(m.Exemplars)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ProfileAnnotation) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ProfileAnnotation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ProfileAnnotation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -3334,17 +4371,53 @@ func (m *StackTraceSelector) UnmarshalVT(dAtA []byte) error { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GoPgo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.GoPgo == nil { + m.GoPgo = &GoPGO{} + } + if err := m.GoPgo.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF } m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy @@ -3439,6 +4512,96 @@ func (m *Location) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *GoPGO) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GoPGO: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GoPGO: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field KeepLocations", wireType) + } + m.KeepLocations = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.KeepLocations |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AggregateCallees", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AggregateCallees = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *GetProfileStatsRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3599,3 +4762,575 @@ func (m *GetProfileStatsResponse) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *Exemplar) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Exemplar: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Exemplar: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProfileId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProfileId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpanId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + m.Value = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Value |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Labels = append(m.Labels, &LabelPair{}) + if err := m.Labels[len(m.Labels)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TraceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeatmapSeries) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HeatmapSeries: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeatmapSeries: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Labels = append(m.Labels, &LabelPair{}) + if err := m.Labels[len(m.Labels)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Slots", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Slots = append(m.Slots, &HeatmapSlot{}) + if err := m.Slots[len(m.Slots)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeatmapSlot) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HeatmapSlot: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeatmapSlot: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType == 1 { + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + v2 := float64(math.Float64frombits(v)) + m.YMin = append(m.YMin, v2) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + elementCount = packedLen / 8 + if elementCount != 0 && len(m.YMin) == 0 { + m.YMin = make([]float64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + v2 := float64(math.Float64frombits(v)) + m.YMin = append(m.YMin, v2) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field YMin", wireType) + } + case 3: + if wireType == 0 { + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Counts = append(m.Counts, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Counts) == 0 { + m.Counts = make([]int32, 0, elementCount) + } + for iNdEx < postIndex { + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Counts = append(m.Counts, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Counts", wireType) + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Exemplars", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Exemplars = append(m.Exemplars, &Exemplar{}) + if err := m.Exemplars[len(m.Exemplars)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/api/gen/proto/go/vcs/v1/vcs.pb.go b/api/gen/proto/go/vcs/v1/vcs.pb.go index ee5a294d38..1c31bd7927 100644 --- a/api/gen/proto/go/vcs/v1/vcs.pb.go +++ b/api/gen/proto/go/vcs/v1/vcs.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: vcs/v1/vcs.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,18 +22,16 @@ const ( ) type GithubAppRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GithubAppRequest) Reset() { *x = GithubAppRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GithubAppRequest) String() string { @@ -43,7 +42,7 @@ func (*GithubAppRequest) ProtoMessage() {} func (x *GithubAppRequest) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -59,20 +58,23 @@ func (*GithubAppRequest) Descriptor() ([]byte, []int) { } type GithubAppResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` + // clientID must be propagated when calling + // https://github.com/login/oauth/authorize in the client_id query parameter. ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` + // If callbackURL is not empty, the URL should be propagated when + // calling https://github.com/login/oauth/authorize in the + // redirect_uri query parameter. + CallbackURL string `protobuf:"bytes,2,opt,name=callbackURL,proto3" json:"callbackURL,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GithubAppResponse) Reset() { *x = GithubAppResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GithubAppResponse) String() string { @@ -83,7 +85,7 @@ func (*GithubAppResponse) ProtoMessage() {} func (x *GithubAppResponse) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -105,21 +107,25 @@ func (x *GithubAppResponse) GetClientID() string { return "" } -type GithubLoginRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *GithubAppResponse) GetCallbackURL() string { + if x != nil { + return x.CallbackURL + } + return "" +} - AuthorizationCode string `protobuf:"bytes,1,opt,name=authorizationCode,proto3" json:"authorizationCode,omitempty"` +type GithubLoginRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + AuthorizationCode string `protobuf:"bytes,1,opt,name=authorizationCode,proto3" json:"authorizationCode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GithubLoginRequest) Reset() { *x = GithubLoginRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GithubLoginRequest) String() string { @@ -130,7 +136,7 @@ func (*GithubLoginRequest) ProtoMessage() {} func (x *GithubLoginRequest) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -153,20 +159,29 @@ func (x *GithubLoginRequest) GetAuthorizationCode() string { } type GithubLoginResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` + // Deprecated + // In future version, this cookie won't be sent. Now, old cookie is sent + // alongside the new expected data (token, token_expires_at and + // refresh_token_expires_at). Frontend will be responsible of computing its + // own cookie from the new data. Remove after completing + // https://github.com/grafana/explore-profiles/issues/187 Cookie string `protobuf:"bytes,1,opt,name=cookie,proto3" json:"cookie,omitempty"` + // base64 encoded encrypted token + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + // Unix ms timestamp of when the token expires. + TokenExpiresAt int64 `protobuf:"varint,3,opt,name=token_expires_at,json=tokenExpiresAt,proto3" json:"token_expires_at,omitempty"` + // Unix ms timestamp of when the refresh token expires. + RefreshTokenExpiresAt int64 `protobuf:"varint,4,opt,name=refresh_token_expires_at,json=refreshTokenExpiresAt,proto3" json:"refresh_token_expires_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GithubLoginResponse) Reset() { *x = GithubLoginResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GithubLoginResponse) String() string { @@ -177,7 +192,7 @@ func (*GithubLoginResponse) ProtoMessage() {} func (x *GithubLoginResponse) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -199,19 +214,38 @@ func (x *GithubLoginResponse) GetCookie() string { return "" } +func (x *GithubLoginResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *GithubLoginResponse) GetTokenExpiresAt() int64 { + if x != nil { + return x.TokenExpiresAt + } + return 0 +} + +func (x *GithubLoginResponse) GetRefreshTokenExpiresAt() int64 { + if x != nil { + return x.RefreshTokenExpiresAt + } + return 0 +} + type GithubRefreshRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GithubRefreshRequest) Reset() { *x = GithubRefreshRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GithubRefreshRequest) String() string { @@ -222,7 +256,7 @@ func (*GithubRefreshRequest) ProtoMessage() {} func (x *GithubRefreshRequest) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -238,20 +272,29 @@ func (*GithubRefreshRequest) Descriptor() ([]byte, []int) { } type GithubRefreshResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` + // Deprecated + // In future version, this cookie won't be sent. Now, old cookie is sent + // alongside the new expected data (token, token_expires_at and + // refresh_token_expires_at). Frontend will be responsible of computing its + // own cookie from the new data. Remove after completing + // https://github.com/grafana/explore-profiles/issues/187 Cookie string `protobuf:"bytes,1,opt,name=cookie,proto3" json:"cookie,omitempty"` + // base64 encoded encrypted token + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + // Unix ms timestamp of when the token expires. + TokenExpiresAt int64 `protobuf:"varint,3,opt,name=token_expires_at,json=tokenExpiresAt,proto3" json:"token_expires_at,omitempty"` + // Unix ms timestamp of when the refresh token expires. + RefreshTokenExpiresAt int64 `protobuf:"varint,4,opt,name=refresh_token_expires_at,json=refreshTokenExpiresAt,proto3" json:"refresh_token_expires_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GithubRefreshResponse) Reset() { *x = GithubRefreshResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GithubRefreshResponse) String() string { @@ -262,7 +305,7 @@ func (*GithubRefreshResponse) ProtoMessage() {} func (x *GithubRefreshResponse) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -284,26 +327,48 @@ func (x *GithubRefreshResponse) GetCookie() string { return "" } -type GetFileRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *GithubRefreshResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *GithubRefreshResponse) GetTokenExpiresAt() int64 { + if x != nil { + return x.TokenExpiresAt + } + return 0 +} + +func (x *GithubRefreshResponse) GetRefreshTokenExpiresAt() int64 { + if x != nil { + return x.RefreshTokenExpiresAt + } + return 0 +} +type GetFileRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` // the full path to the repository RepositoryURL string `protobuf:"bytes,1,opt,name=repositoryURL,proto3" json:"repositoryURL,omitempty"` // the vcs ref to get the file from Ref string `protobuf:"bytes,2,opt,name=ref,proto3" json:"ref,omitempty"` // the path to the file as provided by the symbols LocalPath string `protobuf:"bytes,3,opt,name=localPath,proto3" json:"localPath,omitempty"` + // the root path where the project lives inside the repository + RootPath string `protobuf:"bytes,4,opt,name=rootPath,proto3" json:"rootPath,omitempty"` + // the function name as provided by the symbols + FunctionName string `protobuf:"bytes,5,opt,name=functionName,proto3" json:"functionName,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetFileRequest) Reset() { *x = GetFileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetFileRequest) String() string { @@ -314,7 +379,7 @@ func (*GetFileRequest) ProtoMessage() {} func (x *GetFileRequest) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -350,24 +415,35 @@ func (x *GetFileRequest) GetLocalPath() string { return "" } -type GetFileResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *GetFileRequest) GetRootPath() string { + if x != nil { + return x.RootPath + } + return "" +} + +func (x *GetFileRequest) GetFunctionName() string { + if x != nil { + return x.FunctionName + } + return "" +} +type GetFileResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` // base64 content of the file Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` // the full URL to the file - URL string `protobuf:"bytes,2,opt,name=URL,proto3" json:"URL,omitempty"` + URL string `protobuf:"bytes,2,opt,name=URL,proto3" json:"URL,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetFileResponse) Reset() { *x = GetFileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetFileResponse) String() string { @@ -378,7 +454,7 @@ func (*GetFileResponse) ProtoMessage() {} func (x *GetFileResponse) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -408,23 +484,20 @@ func (x *GetFileResponse) GetURL() string { } type GetCommitRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // the full path to the repository RepositoryURL string `protobuf:"bytes,1,opt,name=repositoryURL,proto3" json:"repositoryURL,omitempty"` // the vcs ref to get the file from - Ref string `protobuf:"bytes,2,opt,name=ref,proto3" json:"ref,omitempty"` + Ref string `protobuf:"bytes,2,opt,name=ref,proto3" json:"ref,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetCommitRequest) Reset() { *x = GetCommitRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetCommitRequest) String() string { @@ -435,7 +508,7 @@ func (*GetCommitRequest) ProtoMessage() {} func (x *GetCommitRequest) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -465,10 +538,7 @@ func (x *GetCommitRequest) GetRef() string { } type GetCommitResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // the commit message Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` // the commit author login @@ -478,16 +548,16 @@ type GetCommitResponse struct { // the commit sha Sha string `protobuf:"bytes,4,opt,name=sha,proto3" json:"sha,omitempty"` // the full URL to the commit - URL string `protobuf:"bytes,5,opt,name=URL,proto3" json:"URL,omitempty"` + URL string `protobuf:"bytes,5,opt,name=URL,proto3" json:"URL,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetCommitResponse) Reset() { *x = GetCommitResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetCommitResponse) String() string { @@ -498,7 +568,7 @@ func (*GetCommitResponse) ProtoMessage() {} func (x *GetCommitResponse) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -549,23 +619,20 @@ func (x *GetCommitResponse) GetURL() string { } type CommitAuthor struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // the author login Login string `protobuf:"bytes,1,opt,name=login,proto3" json:"login,omitempty"` // the author avatar URL - AvatarURL string `protobuf:"bytes,2,opt,name=avatarURL,proto3" json:"avatarURL,omitempty"` + AvatarURL string `protobuf:"bytes,2,opt,name=avatarURL,proto3" json:"avatarURL,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CommitAuthor) Reset() { *x = CommitAuthor{} - if protoimpl.UnsafeEnabled { - mi := &file_vcs_v1_vcs_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_vcs_v1_vcs_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CommitAuthor) String() string { @@ -576,7 +643,7 @@ func (*CommitAuthor) ProtoMessage() {} func (x *CommitAuthor) ProtoReflect() protoreflect.Message { mi := &file_vcs_v1_vcs_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -605,104 +672,265 @@ func (x *CommitAuthor) GetAvatarURL() string { return "" } -var File_vcs_v1_vcs_proto protoreflect.FileDescriptor +type CommitInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + // the commit message + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + // the commit author login + Author *CommitAuthor `protobuf:"bytes,2,opt,name=author,proto3" json:"author,omitempty"` + // the commit date + Date string `protobuf:"bytes,3,opt,name=date,proto3" json:"date,omitempty"` + // the commit sha + Sha string `protobuf:"bytes,4,opt,name=sha,proto3" json:"sha,omitempty"` + // the full URL to the commit + URL string `protobuf:"bytes,5,opt,name=URL,proto3" json:"URL,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CommitInfo) Reset() { + *x = CommitInfo{} + mi := &file_vcs_v1_vcs_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommitInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommitInfo) ProtoMessage() {} + +func (x *CommitInfo) ProtoReflect() protoreflect.Message { + mi := &file_vcs_v1_vcs_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommitInfo.ProtoReflect.Descriptor instead. +func (*CommitInfo) Descriptor() ([]byte, []int) { + return file_vcs_v1_vcs_proto_rawDescGZIP(), []int{11} +} + +func (x *CommitInfo) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} -var file_vcs_v1_vcs_proto_rawDesc = []byte{ - 0x0a, 0x10, 0x76, 0x63, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x06, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x22, 0x12, 0x0a, 0x10, 0x47, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2f, - 0x0a, 0x11, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x70, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x22, - 0x42, 0x0a, 0x12, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x64, 0x65, 0x22, 0x2d, 0x0a, 0x13, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, - 0x6f, 0x6b, 0x69, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6f, 0x6b, - 0x69, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x52, 0x65, 0x66, 0x72, - 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2f, 0x0a, 0x15, 0x47, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x22, 0x66, 0x0a, 0x0e, 0x47, - 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, - 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x55, 0x52, 0x4c, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, - 0x55, 0x52, 0x4c, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x61, - 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, - 0x61, 0x74, 0x68, 0x22, 0x3d, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, - 0x52, 0x4c, 0x22, 0x4a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x6f, 0x72, 0x79, 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, - 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x55, 0x52, 0x4c, 0x12, 0x10, 0x0a, 0x03, - 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x22, 0x93, - 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, - 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, - 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x73, 0x68, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, - 0x68, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x52, 0x4c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x55, 0x52, 0x4c, 0x22, 0x42, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x55, 0x52, 0x4c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, - 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x52, 0x4c, 0x32, 0xec, 0x02, 0x0a, 0x0a, 0x56, 0x43, 0x53, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x42, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x41, 0x70, 0x70, 0x12, 0x18, 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x41, 0x70, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, - 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x70, - 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0b, 0x47, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1a, 0x2e, 0x76, 0x63, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0d, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x52, - 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x1c, 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, - 0x12, 0x16, 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x12, 0x18, 0x2e, 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x76, 0x63, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x8b, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, - 0x76, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x08, 0x56, 0x63, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, - 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, - 0x6f, 0x2f, 0x76, 0x63, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x63, 0x73, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x56, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x56, 0x63, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, - 0x56, 0x63, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x12, 0x56, 0x63, 0x73, 0x5c, 0x56, 0x31, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x56, 0x63, - 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +func (x *CommitInfo) GetAuthor() *CommitAuthor { + if x != nil { + return x.Author + } + return nil +} + +func (x *CommitInfo) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *CommitInfo) GetSha() string { + if x != nil { + return x.Sha + } + return "" +} + +func (x *CommitInfo) GetURL() string { + if x != nil { + return x.URL + } + return "" +} + +// New messages for the GetCommits method +type GetCommitsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + RepositoryUrl string `protobuf:"bytes,1,opt,name=repository_url,json=repositoryUrl,proto3" json:"repository_url,omitempty"` + Refs []string `protobuf:"bytes,2,rep,name=refs,proto3" json:"refs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetCommitsRequest) Reset() { + *x = GetCommitsRequest{} + mi := &file_vcs_v1_vcs_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCommitsRequest) String() string { + return protoimpl.X.MessageStringOf(x) } +func (*GetCommitsRequest) ProtoMessage() {} + +func (x *GetCommitsRequest) ProtoReflect() protoreflect.Message { + mi := &file_vcs_v1_vcs_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCommitsRequest.ProtoReflect.Descriptor instead. +func (*GetCommitsRequest) Descriptor() ([]byte, []int) { + return file_vcs_v1_vcs_proto_rawDescGZIP(), []int{12} +} + +func (x *GetCommitsRequest) GetRepositoryUrl() string { + if x != nil { + return x.RepositoryUrl + } + return "" +} + +func (x *GetCommitsRequest) GetRefs() []string { + if x != nil { + return x.Refs + } + return nil +} + +type GetCommitsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Commits []*CommitInfo `protobuf:"bytes,1,rep,name=commits,proto3" json:"commits,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetCommitsResponse) Reset() { + *x = GetCommitsResponse{} + mi := &file_vcs_v1_vcs_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCommitsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCommitsResponse) ProtoMessage() {} + +func (x *GetCommitsResponse) ProtoReflect() protoreflect.Message { + mi := &file_vcs_v1_vcs_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCommitsResponse.ProtoReflect.Descriptor instead. +func (*GetCommitsResponse) Descriptor() ([]byte, []int) { + return file_vcs_v1_vcs_proto_rawDescGZIP(), []int{13} +} + +func (x *GetCommitsResponse) GetCommits() []*CommitInfo { + if x != nil { + return x.Commits + } + return nil +} + +var File_vcs_v1_vcs_proto protoreflect.FileDescriptor + +const file_vcs_v1_vcs_proto_rawDesc = "" + + "\n" + + "\x10vcs/v1/vcs.proto\x12\x06vcs.v1\"\x12\n" + + "\x10GithubAppRequest\"Q\n" + + "\x11GithubAppResponse\x12\x1a\n" + + "\bclientID\x18\x01 \x01(\tR\bclientID\x12 \n" + + "\vcallbackURL\x18\x02 \x01(\tR\vcallbackURL\"B\n" + + "\x12GithubLoginRequest\x12,\n" + + "\x11authorizationCode\x18\x01 \x01(\tR\x11authorizationCode\"\xa6\x01\n" + + "\x13GithubLoginResponse\x12\x16\n" + + "\x06cookie\x18\x01 \x01(\tR\x06cookie\x12\x14\n" + + "\x05token\x18\x02 \x01(\tR\x05token\x12(\n" + + "\x10token_expires_at\x18\x03 \x01(\x03R\x0etokenExpiresAt\x127\n" + + "\x18refresh_token_expires_at\x18\x04 \x01(\x03R\x15refreshTokenExpiresAt\"\x16\n" + + "\x14GithubRefreshRequest\"\xa8\x01\n" + + "\x15GithubRefreshResponse\x12\x16\n" + + "\x06cookie\x18\x01 \x01(\tR\x06cookie\x12\x14\n" + + "\x05token\x18\x02 \x01(\tR\x05token\x12(\n" + + "\x10token_expires_at\x18\x03 \x01(\x03R\x0etokenExpiresAt\x127\n" + + "\x18refresh_token_expires_at\x18\x04 \x01(\x03R\x15refreshTokenExpiresAt\"\xa6\x01\n" + + "\x0eGetFileRequest\x12$\n" + + "\rrepositoryURL\x18\x01 \x01(\tR\rrepositoryURL\x12\x10\n" + + "\x03ref\x18\x02 \x01(\tR\x03ref\x12\x1c\n" + + "\tlocalPath\x18\x03 \x01(\tR\tlocalPath\x12\x1a\n" + + "\brootPath\x18\x04 \x01(\tR\brootPath\x12\"\n" + + "\ffunctionName\x18\x05 \x01(\tR\ffunctionName\"=\n" + + "\x0fGetFileResponse\x12\x18\n" + + "\acontent\x18\x01 \x01(\tR\acontent\x12\x10\n" + + "\x03URL\x18\x02 \x01(\tR\x03URL\"J\n" + + "\x10GetCommitRequest\x12$\n" + + "\rrepositoryURL\x18\x01 \x01(\tR\rrepositoryURL\x12\x10\n" + + "\x03ref\x18\x02 \x01(\tR\x03ref\"\x93\x01\n" + + "\x11GetCommitResponse\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage\x12,\n" + + "\x06author\x18\x02 \x01(\v2\x14.vcs.v1.CommitAuthorR\x06author\x12\x12\n" + + "\x04date\x18\x03 \x01(\tR\x04date\x12\x10\n" + + "\x03sha\x18\x04 \x01(\tR\x03sha\x12\x10\n" + + "\x03URL\x18\x05 \x01(\tR\x03URL\"B\n" + + "\fCommitAuthor\x12\x14\n" + + "\x05login\x18\x01 \x01(\tR\x05login\x12\x1c\n" + + "\tavatarURL\x18\x02 \x01(\tR\tavatarURL\"\x8c\x01\n" + + "\n" + + "CommitInfo\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage\x12,\n" + + "\x06author\x18\x02 \x01(\v2\x14.vcs.v1.CommitAuthorR\x06author\x12\x12\n" + + "\x04date\x18\x03 \x01(\tR\x04date\x12\x10\n" + + "\x03sha\x18\x04 \x01(\tR\x03sha\x12\x10\n" + + "\x03URL\x18\x05 \x01(\tR\x03URL\"N\n" + + "\x11GetCommitsRequest\x12%\n" + + "\x0erepository_url\x18\x01 \x01(\tR\rrepositoryUrl\x12\x12\n" + + "\x04refs\x18\x02 \x03(\tR\x04refs\"B\n" + + "\x12GetCommitsResponse\x12,\n" + + "\acommits\x18\x01 \x03(\v2\x12.vcs.v1.CommitInfoR\acommits2\xb3\x03\n" + + "\n" + + "VCSService\x12B\n" + + "\tGithubApp\x12\x18.vcs.v1.GithubAppRequest\x1a\x19.vcs.v1.GithubAppResponse\"\x00\x12H\n" + + "\vGithubLogin\x12\x1a.vcs.v1.GithubLoginRequest\x1a\x1b.vcs.v1.GithubLoginResponse\"\x00\x12N\n" + + "\rGithubRefresh\x12\x1c.vcs.v1.GithubRefreshRequest\x1a\x1d.vcs.v1.GithubRefreshResponse\"\x00\x12<\n" + + "\aGetFile\x12\x16.vcs.v1.GetFileRequest\x1a\x17.vcs.v1.GetFileResponse\"\x00\x12B\n" + + "\tGetCommit\x12\x18.vcs.v1.GetCommitRequest\x1a\x19.vcs.v1.GetCommitResponse\"\x00\x12E\n" + + "\n" + + "GetCommits\x12\x19.vcs.v1.GetCommitsRequest\x1a\x1a.vcs.v1.GetCommitsResponse\"\x00B\x8b\x01\n" + + "\n" + + "com.vcs.v1B\bVcsProtoP\x01Z:github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1;vcsv1\xa2\x02\x03VXX\xaa\x02\x06Vcs.V1\xca\x02\x06Vcs\\V1\xe2\x02\x12Vcs\\V1\\GPBMetadata\xea\x02\aVcs::V1b\x06proto3" + var ( file_vcs_v1_vcs_proto_rawDescOnce sync.Once - file_vcs_v1_vcs_proto_rawDescData = file_vcs_v1_vcs_proto_rawDesc + file_vcs_v1_vcs_proto_rawDescData []byte ) func file_vcs_v1_vcs_proto_rawDescGZIP() []byte { file_vcs_v1_vcs_proto_rawDescOnce.Do(func() { - file_vcs_v1_vcs_proto_rawDescData = protoimpl.X.CompressGZIP(file_vcs_v1_vcs_proto_rawDescData) + file_vcs_v1_vcs_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vcs_v1_vcs_proto_rawDesc), len(file_vcs_v1_vcs_proto_rawDesc))) }) return file_vcs_v1_vcs_proto_rawDescData } -var file_vcs_v1_vcs_proto_msgTypes = make([]protoimpl.MessageInfo, 11) -var file_vcs_v1_vcs_proto_goTypes = []interface{}{ +var file_vcs_v1_vcs_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_vcs_v1_vcs_proto_goTypes = []any{ (*GithubAppRequest)(nil), // 0: vcs.v1.GithubAppRequest (*GithubAppResponse)(nil), // 1: vcs.v1.GithubAppResponse (*GithubLoginRequest)(nil), // 2: vcs.v1.GithubLoginRequest @@ -714,24 +942,31 @@ var file_vcs_v1_vcs_proto_goTypes = []interface{}{ (*GetCommitRequest)(nil), // 8: vcs.v1.GetCommitRequest (*GetCommitResponse)(nil), // 9: vcs.v1.GetCommitResponse (*CommitAuthor)(nil), // 10: vcs.v1.CommitAuthor + (*CommitInfo)(nil), // 11: vcs.v1.CommitInfo + (*GetCommitsRequest)(nil), // 12: vcs.v1.GetCommitsRequest + (*GetCommitsResponse)(nil), // 13: vcs.v1.GetCommitsResponse } var file_vcs_v1_vcs_proto_depIdxs = []int32{ 10, // 0: vcs.v1.GetCommitResponse.author:type_name -> vcs.v1.CommitAuthor - 0, // 1: vcs.v1.VCSService.GithubApp:input_type -> vcs.v1.GithubAppRequest - 2, // 2: vcs.v1.VCSService.GithubLogin:input_type -> vcs.v1.GithubLoginRequest - 4, // 3: vcs.v1.VCSService.GithubRefresh:input_type -> vcs.v1.GithubRefreshRequest - 6, // 4: vcs.v1.VCSService.GetFile:input_type -> vcs.v1.GetFileRequest - 8, // 5: vcs.v1.VCSService.GetCommit:input_type -> vcs.v1.GetCommitRequest - 1, // 6: vcs.v1.VCSService.GithubApp:output_type -> vcs.v1.GithubAppResponse - 3, // 7: vcs.v1.VCSService.GithubLogin:output_type -> vcs.v1.GithubLoginResponse - 5, // 8: vcs.v1.VCSService.GithubRefresh:output_type -> vcs.v1.GithubRefreshResponse - 7, // 9: vcs.v1.VCSService.GetFile:output_type -> vcs.v1.GetFileResponse - 9, // 10: vcs.v1.VCSService.GetCommit:output_type -> vcs.v1.GetCommitResponse - 6, // [6:11] is the sub-list for method output_type - 1, // [1:6] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 10, // 1: vcs.v1.CommitInfo.author:type_name -> vcs.v1.CommitAuthor + 11, // 2: vcs.v1.GetCommitsResponse.commits:type_name -> vcs.v1.CommitInfo + 0, // 3: vcs.v1.VCSService.GithubApp:input_type -> vcs.v1.GithubAppRequest + 2, // 4: vcs.v1.VCSService.GithubLogin:input_type -> vcs.v1.GithubLoginRequest + 4, // 5: vcs.v1.VCSService.GithubRefresh:input_type -> vcs.v1.GithubRefreshRequest + 6, // 6: vcs.v1.VCSService.GetFile:input_type -> vcs.v1.GetFileRequest + 8, // 7: vcs.v1.VCSService.GetCommit:input_type -> vcs.v1.GetCommitRequest + 12, // 8: vcs.v1.VCSService.GetCommits:input_type -> vcs.v1.GetCommitsRequest + 1, // 9: vcs.v1.VCSService.GithubApp:output_type -> vcs.v1.GithubAppResponse + 3, // 10: vcs.v1.VCSService.GithubLogin:output_type -> vcs.v1.GithubLoginResponse + 5, // 11: vcs.v1.VCSService.GithubRefresh:output_type -> vcs.v1.GithubRefreshResponse + 7, // 12: vcs.v1.VCSService.GetFile:output_type -> vcs.v1.GetFileResponse + 9, // 13: vcs.v1.VCSService.GetCommit:output_type -> vcs.v1.GetCommitResponse + 13, // 14: vcs.v1.VCSService.GetCommits:output_type -> vcs.v1.GetCommitsResponse + 9, // [9:15] is the sub-list for method output_type + 3, // [3:9] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_vcs_v1_vcs_proto_init() } @@ -739,147 +974,13 @@ func file_vcs_v1_vcs_proto_init() { if File_vcs_v1_vcs_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_vcs_v1_vcs_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GithubAppRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GithubAppResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GithubLoginRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GithubLoginResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GithubRefreshRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GithubRefreshResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetFileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetFileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCommitRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCommitResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vcs_v1_vcs_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CommitAuthor); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_vcs_v1_vcs_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_vcs_v1_vcs_proto_rawDesc), len(file_vcs_v1_vcs_proto_rawDesc)), NumEnums: 0, - NumMessages: 11, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, @@ -888,7 +989,6 @@ func file_vcs_v1_vcs_proto_init() { MessageInfos: file_vcs_v1_vcs_proto_msgTypes, }.Build() File_vcs_v1_vcs_proto = out.File - file_vcs_v1_vcs_proto_rawDesc = nil file_vcs_v1_vcs_proto_goTypes = nil file_vcs_v1_vcs_proto_depIdxs = nil } diff --git a/api/gen/proto/go/vcs/v1/vcs_vtproto.pb.go b/api/gen/proto/go/vcs/v1/vcs_vtproto.pb.go index 2fdca50621..a23579eb9e 100644 --- a/api/gen/proto/go/vcs/v1/vcs_vtproto.pb.go +++ b/api/gen/proto/go/vcs/v1/vcs_vtproto.pb.go @@ -45,6 +45,7 @@ func (m *GithubAppResponse) CloneVT() *GithubAppResponse { } r := new(GithubAppResponse) r.ClientID = m.ClientID + r.CallbackURL = m.CallbackURL if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -79,6 +80,9 @@ func (m *GithubLoginResponse) CloneVT() *GithubLoginResponse { } r := new(GithubLoginResponse) r.Cookie = m.Cookie + r.Token = m.Token + r.TokenExpiresAt = m.TokenExpiresAt + r.RefreshTokenExpiresAt = m.RefreshTokenExpiresAt if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -112,6 +116,9 @@ func (m *GithubRefreshResponse) CloneVT() *GithubRefreshResponse { } r := new(GithubRefreshResponse) r.Cookie = m.Cookie + r.Token = m.Token + r.TokenExpiresAt = m.TokenExpiresAt + r.RefreshTokenExpiresAt = m.RefreshTokenExpiresAt if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -131,6 +138,8 @@ func (m *GetFileRequest) CloneVT() *GetFileRequest { r.RepositoryURL = m.RepositoryURL r.Ref = m.Ref r.LocalPath = m.LocalPath + r.RootPath = m.RootPath + r.FunctionName = m.FunctionName if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -217,6 +226,72 @@ func (m *CommitAuthor) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *CommitInfo) CloneVT() *CommitInfo { + if m == nil { + return (*CommitInfo)(nil) + } + r := new(CommitInfo) + r.Message = m.Message + r.Author = m.Author.CloneVT() + r.Date = m.Date + r.Sha = m.Sha + r.URL = m.URL + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CommitInfo) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetCommitsRequest) CloneVT() *GetCommitsRequest { + if m == nil { + return (*GetCommitsRequest)(nil) + } + r := new(GetCommitsRequest) + r.RepositoryUrl = m.RepositoryUrl + if rhs := m.Refs; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.Refs = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetCommitsRequest) CloneMessageVT() proto.Message { + return m.CloneVT() +} + +func (m *GetCommitsResponse) CloneVT() *GetCommitsResponse { + if m == nil { + return (*GetCommitsResponse)(nil) + } + r := new(GetCommitsResponse) + if rhs := m.Commits; rhs != nil { + tmpContainer := make([]*CommitInfo, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.Commits = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *GetCommitsResponse) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (this *GithubAppRequest) EqualVT(that *GithubAppRequest) bool { if this == that { return true @@ -242,6 +317,9 @@ func (this *GithubAppResponse) EqualVT(that *GithubAppResponse) bool { if this.ClientID != that.ClientID { return false } + if this.CallbackURL != that.CallbackURL { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -280,6 +358,15 @@ func (this *GithubLoginResponse) EqualVT(that *GithubLoginResponse) bool { if this.Cookie != that.Cookie { return false } + if this.Token != that.Token { + return false + } + if this.TokenExpiresAt != that.TokenExpiresAt { + return false + } + if this.RefreshTokenExpiresAt != that.RefreshTokenExpiresAt { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -315,6 +402,15 @@ func (this *GithubRefreshResponse) EqualVT(that *GithubRefreshResponse) bool { if this.Cookie != that.Cookie { return false } + if this.Token != that.Token { + return false + } + if this.TokenExpiresAt != that.TokenExpiresAt { + return false + } + if this.RefreshTokenExpiresAt != that.RefreshTokenExpiresAt { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -340,6 +436,12 @@ func (this *GetFileRequest) EqualVT(that *GetFileRequest) bool { if this.LocalPath != that.LocalPath { return false } + if this.RootPath != that.RootPath { + return false + } + if this.FunctionName != that.FunctionName { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -447,6 +549,98 @@ func (this *CommitAuthor) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *CommitInfo) EqualVT(that *CommitInfo) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.Message != that.Message { + return false + } + if !this.Author.EqualVT(that.Author) { + return false + } + if this.Date != that.Date { + return false + } + if this.Sha != that.Sha { + return false + } + if this.URL != that.URL { + return false + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CommitInfo) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CommitInfo) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetCommitsRequest) EqualVT(that *GetCommitsRequest) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.RepositoryUrl != that.RepositoryUrl { + return false + } + if len(this.Refs) != len(that.Refs) { + return false + } + for i, vx := range this.Refs { + vy := that.Refs[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetCommitsRequest) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetCommitsRequest) + if !ok { + return false + } + return this.EqualVT(that) +} +func (this *GetCommitsResponse) EqualVT(that *GetCommitsResponse) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if len(this.Commits) != len(that.Commits) { + return false + } + for i, vx := range this.Commits { + vy := that.Commits[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &CommitInfo{} + } + if q == nil { + q = &CommitInfo{} + } + if !p.EqualVT(q) { + return false + } + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *GetCommitsResponse) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*GetCommitsResponse) + if !ok { + return false + } + return this.EqualVT(that) +} // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. @@ -462,6 +656,7 @@ type VCSServiceClient interface { GithubRefresh(ctx context.Context, in *GithubRefreshRequest, opts ...grpc.CallOption) (*GithubRefreshResponse, error) GetFile(ctx context.Context, in *GetFileRequest, opts ...grpc.CallOption) (*GetFileResponse, error) GetCommit(ctx context.Context, in *GetCommitRequest, opts ...grpc.CallOption) (*GetCommitResponse, error) + GetCommits(ctx context.Context, in *GetCommitsRequest, opts ...grpc.CallOption) (*GetCommitsResponse, error) } type vCSServiceClient struct { @@ -517,6 +712,15 @@ func (c *vCSServiceClient) GetCommit(ctx context.Context, in *GetCommitRequest, return out, nil } +func (c *vCSServiceClient) GetCommits(ctx context.Context, in *GetCommitsRequest, opts ...grpc.CallOption) (*GetCommitsResponse, error) { + out := new(GetCommitsResponse) + err := c.cc.Invoke(ctx, "/vcs.v1.VCSService/GetCommits", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // VCSServiceServer is the server API for VCSService service. // All implementations must embed UnimplementedVCSServiceServer // for forward compatibility @@ -526,6 +730,7 @@ type VCSServiceServer interface { GithubRefresh(context.Context, *GithubRefreshRequest) (*GithubRefreshResponse, error) GetFile(context.Context, *GetFileRequest) (*GetFileResponse, error) GetCommit(context.Context, *GetCommitRequest) (*GetCommitResponse, error) + GetCommits(context.Context, *GetCommitsRequest) (*GetCommitsResponse, error) mustEmbedUnimplementedVCSServiceServer() } @@ -548,6 +753,9 @@ func (UnimplementedVCSServiceServer) GetFile(context.Context, *GetFileRequest) ( func (UnimplementedVCSServiceServer) GetCommit(context.Context, *GetCommitRequest) (*GetCommitResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetCommit not implemented") } +func (UnimplementedVCSServiceServer) GetCommits(context.Context, *GetCommitsRequest) (*GetCommitsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCommits not implemented") +} func (UnimplementedVCSServiceServer) mustEmbedUnimplementedVCSServiceServer() {} // UnsafeVCSServiceServer may be embedded to opt out of forward compatibility for this service. @@ -651,6 +859,24 @@ func _VCSService_GetCommit_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _VCSService_GetCommits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetCommitsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VCSServiceServer).GetCommits(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vcs.v1.VCSService/GetCommits", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VCSServiceServer).GetCommits(ctx, req.(*GetCommitsRequest)) + } + return interceptor(ctx, in, info, handler) +} + // VCSService_ServiceDesc is the grpc.ServiceDesc for VCSService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -678,6 +904,10 @@ var VCSService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetCommit", Handler: _VCSService_GetCommit_Handler, }, + { + MethodName: "GetCommits", + Handler: _VCSService_GetCommits_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "vcs/v1/vcs.proto", @@ -746,6 +976,13 @@ func (m *GithubAppResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.CallbackURL) > 0 { + i -= len(m.CallbackURL) + copy(dAtA[i:], m.CallbackURL) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CallbackURL))) + i-- + dAtA[i] = 0x12 + } if len(m.ClientID) > 0 { i -= len(m.ClientID) copy(dAtA[i:], m.ClientID) @@ -826,6 +1063,23 @@ func (m *GithubLoginResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.RefreshTokenExpiresAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.RefreshTokenExpiresAt)) + i-- + dAtA[i] = 0x20 + } + if m.TokenExpiresAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.TokenExpiresAt)) + i-- + dAtA[i] = 0x18 + } + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Token))) + i-- + dAtA[i] = 0x12 + } if len(m.Cookie) > 0 { i -= len(m.Cookie) copy(dAtA[i:], m.Cookie) @@ -899,6 +1153,23 @@ func (m *GithubRefreshResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.RefreshTokenExpiresAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.RefreshTokenExpiresAt)) + i-- + dAtA[i] = 0x20 + } + if m.TokenExpiresAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.TokenExpiresAt)) + i-- + dAtA[i] = 0x18 + } + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Token))) + i-- + dAtA[i] = 0x12 + } if len(m.Cookie) > 0 { i -= len(m.Cookie) copy(dAtA[i:], m.Cookie) @@ -939,6 +1210,20 @@ func (m *GetFileRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.FunctionName) > 0 { + i -= len(m.FunctionName) + copy(dAtA[i:], m.FunctionName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FunctionName))) + i-- + dAtA[i] = 0x2a + } + if len(m.RootPath) > 0 { + i -= len(m.RootPath) + copy(dAtA[i:], m.RootPath) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RootPath))) + i-- + dAtA[i] = 0x22 + } if len(m.LocalPath) > 0 { i -= len(m.LocalPath) copy(dAtA[i:], m.LocalPath) @@ -1175,78 +1460,267 @@ func (m *CommitAuthor) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *GithubAppRequest) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - n += len(m.unknownFields) - return n -} - -func (m *GithubAppResponse) SizeVT() (n int) { +func (m *CommitInfo) MarshalVT() (dAtA []byte, err error) { if m == nil { - return 0 + return nil, nil } - var l int - _ = l - l = len(m.ClientID) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err } - n += len(m.unknownFields) - return n + return dAtA[:n], nil } -func (m *GithubLoginRequest) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.AuthorizationCode) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - n += len(m.unknownFields) - return n +func (m *CommitInfo) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *GithubLoginResponse) SizeVT() (n int) { +func (m *CommitInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { - return 0 + return 0, nil } + i := len(dAtA) + _ = i var l int _ = l - l = len(m.Cookie) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) } - n += len(m.unknownFields) - return n -} - -func (m *GithubRefreshRequest) SizeVT() (n int) { - if m == nil { - return 0 + if len(m.URL) > 0 { + i -= len(m.URL) + copy(dAtA[i:], m.URL) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.URL))) + i-- + dAtA[i] = 0x2a } - var l int - _ = l - n += len(m.unknownFields) - return n -} - -func (m *GithubRefreshResponse) SizeVT() (n int) { - if m == nil { - return 0 + if len(m.Sha) > 0 { + i -= len(m.Sha) + copy(dAtA[i:], m.Sha) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Sha))) + i-- + dAtA[i] = 0x22 } - var l int - _ = l - l = len(m.Cookie) + if len(m.Date) > 0 { + i -= len(m.Date) + copy(dAtA[i:], m.Date) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Date))) + i-- + dAtA[i] = 0x1a + } + if m.Author != nil { + size, err := m.Author.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if len(m.Message) > 0 { + i -= len(m.Message) + copy(dAtA[i:], m.Message) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Message))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetCommitsRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetCommitsRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetCommitsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Refs) > 0 { + for iNdEx := len(m.Refs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Refs[iNdEx]) + copy(dAtA[i:], m.Refs[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Refs[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.RepositoryUrl) > 0 { + i -= len(m.RepositoryUrl) + copy(dAtA[i:], m.RepositoryUrl) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RepositoryUrl))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetCommitsResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetCommitsResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *GetCommitsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Commits) > 0 { + for iNdEx := len(m.Commits) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Commits[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *GithubAppRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *GithubAppResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientID) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.CallbackURL) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *GithubLoginRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AuthorizationCode) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *GithubLoginResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Cookie) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.TokenExpiresAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.TokenExpiresAt)) + } + if m.RefreshTokenExpiresAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.RefreshTokenExpiresAt)) + } + n += len(m.unknownFields) + return n +} + +func (m *GithubRefreshRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *GithubRefreshResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Cookie) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Token) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.TokenExpiresAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.TokenExpiresAt)) + } + if m.RefreshTokenExpiresAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.RefreshTokenExpiresAt)) + } n += len(m.unknownFields) return n } @@ -1269,6 +1743,14 @@ func (m *GetFileRequest) SizeVT() (n int) { if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + l = len(m.RootPath) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.FunctionName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -1357,6 +1839,72 @@ func (m *CommitAuthor) SizeVT() (n int) { return n } +func (m *CommitInfo) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Message) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Author != nil { + l = m.Author.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Date) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Sha) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.URL) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *GetCommitsRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RepositoryUrl) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Refs) > 0 { + for _, s := range m.Refs { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *GetCommitsResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Commits) > 0 { + for _, e := range m.Commits { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + func (m *GithubAppRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1469,23 +2017,55 @@ func (m *GithubAppResponse) UnmarshalVT(dAtA []byte) error { } m.ClientID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CallbackURL", wireType) } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CallbackURL = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + if iNdEx > l { return io.ErrUnexpectedEOF } @@ -1635,6 +2215,76 @@ func (m *GithubLoginResponse) UnmarshalVT(dAtA []byte) error { } m.Cookie = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenExpiresAt", wireType) + } + m.TokenExpiresAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TokenExpiresAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RefreshTokenExpiresAt", wireType) + } + m.RefreshTokenExpiresAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RefreshTokenExpiresAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -1667,25 +2317,504 @@ func (m *GithubRefreshRequest) UnmarshalVT(dAtA []byte) error { if shift >= 64 { return protohelpers.ErrIntOverflow } - if iNdEx >= l { + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GithubRefreshRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GithubRefreshRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GithubRefreshResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GithubRefreshResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GithubRefreshResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cookie", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cookie = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenExpiresAt", wireType) + } + m.TokenExpiresAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TokenExpiresAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RefreshTokenExpiresAt", wireType) + } + m.RefreshTokenExpiresAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RefreshTokenExpiresAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetFileRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetFileRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetFileRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RepositoryURL", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RepositoryURL = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ref = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LocalPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LocalPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RootPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RootPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FunctionName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FunctionName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetFileResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetFileResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetFileResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Content = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field URL", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: GithubRefreshRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: GithubRefreshRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { + m.URL = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -1708,7 +2837,7 @@ func (m *GithubRefreshRequest) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *GithubRefreshResponse) UnmarshalVT(dAtA []byte) error { +func (m *GetCommitRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1731,15 +2860,15 @@ func (m *GithubRefreshResponse) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GithubRefreshResponse: wiretype end group for non-group") + return fmt.Errorf("proto: GetCommitRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GithubRefreshResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GetCommitRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Cookie", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RepositoryURL", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1767,7 +2896,39 @@ func (m *GithubRefreshResponse) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Cookie = string(dAtA[iNdEx:postIndex]) + m.RepositoryURL = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ref = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1791,7 +2952,7 @@ func (m *GithubRefreshResponse) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *GetFileRequest) UnmarshalVT(dAtA []byte) error { +func (m *GetCommitResponse) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1814,15 +2975,15 @@ func (m *GetFileRequest) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GetFileRequest: wiretype end group for non-group") + return fmt.Errorf("proto: GetCommitResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GetFileRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GetCommitResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RepositoryURL", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1850,13 +3011,13 @@ func (m *GetFileRequest) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RepositoryURL = string(dAtA[iNdEx:postIndex]) + m.Message = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Author", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1866,27 +3027,31 @@ func (m *GetFileRequest) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Ref = string(dAtA[iNdEx:postIndex]) + if m.Author == nil { + m.Author = &CommitAuthor{} + } + if err := m.Author.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LocalPath", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Date", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1914,62 +3079,11 @@ func (m *GetFileRequest) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.LocalPath = string(dAtA[iNdEx:postIndex]) + m.Date = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *GetFileResponse) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: GetFileResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: GetFileResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Sha", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1997,9 +3111,9 @@ func (m *GetFileResponse) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Content = string(dAtA[iNdEx:postIndex]) + m.Sha = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field URL", wireType) } @@ -2053,7 +3167,7 @@ func (m *GetFileResponse) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *GetCommitRequest) UnmarshalVT(dAtA []byte) error { +func (m *CommitAuthor) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2076,15 +3190,15 @@ func (m *GetCommitRequest) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GetCommitRequest: wiretype end group for non-group") + return fmt.Errorf("proto: CommitAuthor: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GetCommitRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: CommitAuthor: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RepositoryURL", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Login", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2112,11 +3226,11 @@ func (m *GetCommitRequest) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RepositoryURL = string(dAtA[iNdEx:postIndex]) + m.Login = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AvatarURL", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2144,7 +3258,7 @@ func (m *GetCommitRequest) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Ref = string(dAtA[iNdEx:postIndex]) + m.AvatarURL = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -2168,7 +3282,7 @@ func (m *GetCommitRequest) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *GetCommitResponse) UnmarshalVT(dAtA []byte) error { +func (m *CommitInfo) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2191,10 +3305,10 @@ func (m *GetCommitResponse) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GetCommitResponse: wiretype end group for non-group") + return fmt.Errorf("proto: CommitInfo: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GetCommitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: CommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -2383,7 +3497,7 @@ func (m *GetCommitResponse) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *CommitAuthor) UnmarshalVT(dAtA []byte) error { +func (m *GetCommitsRequest) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2406,15 +3520,15 @@ func (m *CommitAuthor) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: CommitAuthor: wiretype end group for non-group") + return fmt.Errorf("proto: GetCommitsRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: CommitAuthor: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GetCommitsRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Login", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RepositoryUrl", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2442,11 +3556,11 @@ func (m *CommitAuthor) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Login = string(dAtA[iNdEx:postIndex]) + m.RepositoryUrl = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AvatarURL", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Refs", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2474,7 +3588,92 @@ func (m *CommitAuthor) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.AvatarURL = string(dAtA[iNdEx:postIndex]) + m.Refs = append(m.Refs, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetCommitsResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetCommitsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetCommitsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commits", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Commits = append(m.Commits, &CommitInfo{}) + if err := m.Commits[len(m.Commits)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex diff --git a/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.go b/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.go index 1176a6bb5b..9502c58ffb 100644 --- a/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.go +++ b/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.go @@ -44,16 +44,8 @@ const ( VCSServiceGetFileProcedure = "/vcs.v1.VCSService/GetFile" // VCSServiceGetCommitProcedure is the fully-qualified name of the VCSService's GetCommit RPC. VCSServiceGetCommitProcedure = "/vcs.v1.VCSService/GetCommit" -) - -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - vCSServiceServiceDescriptor = v1.File_vcs_v1_vcs_proto.Services().ByName("VCSService") - vCSServiceGithubAppMethodDescriptor = vCSServiceServiceDescriptor.Methods().ByName("GithubApp") - vCSServiceGithubLoginMethodDescriptor = vCSServiceServiceDescriptor.Methods().ByName("GithubLogin") - vCSServiceGithubRefreshMethodDescriptor = vCSServiceServiceDescriptor.Methods().ByName("GithubRefresh") - vCSServiceGetFileMethodDescriptor = vCSServiceServiceDescriptor.Methods().ByName("GetFile") - vCSServiceGetCommitMethodDescriptor = vCSServiceServiceDescriptor.Methods().ByName("GetCommit") + // VCSServiceGetCommitsProcedure is the fully-qualified name of the VCSService's GetCommits RPC. + VCSServiceGetCommitsProcedure = "/vcs.v1.VCSService/GetCommits" ) // VCSServiceClient is a client for the vcs.v1.VCSService service. @@ -63,6 +55,7 @@ type VCSServiceClient interface { GithubRefresh(context.Context, *connect.Request[v1.GithubRefreshRequest]) (*connect.Response[v1.GithubRefreshResponse], error) GetFile(context.Context, *connect.Request[v1.GetFileRequest]) (*connect.Response[v1.GetFileResponse], error) GetCommit(context.Context, *connect.Request[v1.GetCommitRequest]) (*connect.Response[v1.GetCommitResponse], error) + GetCommits(context.Context, *connect.Request[v1.GetCommitsRequest]) (*connect.Response[v1.GetCommitsResponse], error) } // NewVCSServiceClient constructs a client for the vcs.v1.VCSService service. By default, it uses @@ -74,35 +67,42 @@ type VCSServiceClient interface { // http://api.acme.com or https://acme.com/grpc). func NewVCSServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) VCSServiceClient { baseURL = strings.TrimRight(baseURL, "/") + vCSServiceMethods := v1.File_vcs_v1_vcs_proto.Services().ByName("VCSService").Methods() return &vCSServiceClient{ githubApp: connect.NewClient[v1.GithubAppRequest, v1.GithubAppResponse]( httpClient, baseURL+VCSServiceGithubAppProcedure, - connect.WithSchema(vCSServiceGithubAppMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GithubApp")), connect.WithClientOptions(opts...), ), githubLogin: connect.NewClient[v1.GithubLoginRequest, v1.GithubLoginResponse]( httpClient, baseURL+VCSServiceGithubLoginProcedure, - connect.WithSchema(vCSServiceGithubLoginMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GithubLogin")), connect.WithClientOptions(opts...), ), githubRefresh: connect.NewClient[v1.GithubRefreshRequest, v1.GithubRefreshResponse]( httpClient, baseURL+VCSServiceGithubRefreshProcedure, - connect.WithSchema(vCSServiceGithubRefreshMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GithubRefresh")), connect.WithClientOptions(opts...), ), getFile: connect.NewClient[v1.GetFileRequest, v1.GetFileResponse]( httpClient, baseURL+VCSServiceGetFileProcedure, - connect.WithSchema(vCSServiceGetFileMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GetFile")), connect.WithClientOptions(opts...), ), getCommit: connect.NewClient[v1.GetCommitRequest, v1.GetCommitResponse]( httpClient, baseURL+VCSServiceGetCommitProcedure, - connect.WithSchema(vCSServiceGetCommitMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GetCommit")), + connect.WithClientOptions(opts...), + ), + getCommits: connect.NewClient[v1.GetCommitsRequest, v1.GetCommitsResponse]( + httpClient, + baseURL+VCSServiceGetCommitsProcedure, + connect.WithSchema(vCSServiceMethods.ByName("GetCommits")), connect.WithClientOptions(opts...), ), } @@ -115,6 +115,7 @@ type vCSServiceClient struct { githubRefresh *connect.Client[v1.GithubRefreshRequest, v1.GithubRefreshResponse] getFile *connect.Client[v1.GetFileRequest, v1.GetFileResponse] getCommit *connect.Client[v1.GetCommitRequest, v1.GetCommitResponse] + getCommits *connect.Client[v1.GetCommitsRequest, v1.GetCommitsResponse] } // GithubApp calls vcs.v1.VCSService.GithubApp. @@ -142,6 +143,11 @@ func (c *vCSServiceClient) GetCommit(ctx context.Context, req *connect.Request[v return c.getCommit.CallUnary(ctx, req) } +// GetCommits calls vcs.v1.VCSService.GetCommits. +func (c *vCSServiceClient) GetCommits(ctx context.Context, req *connect.Request[v1.GetCommitsRequest]) (*connect.Response[v1.GetCommitsResponse], error) { + return c.getCommits.CallUnary(ctx, req) +} + // VCSServiceHandler is an implementation of the vcs.v1.VCSService service. type VCSServiceHandler interface { GithubApp(context.Context, *connect.Request[v1.GithubAppRequest]) (*connect.Response[v1.GithubAppResponse], error) @@ -149,6 +155,7 @@ type VCSServiceHandler interface { GithubRefresh(context.Context, *connect.Request[v1.GithubRefreshRequest]) (*connect.Response[v1.GithubRefreshResponse], error) GetFile(context.Context, *connect.Request[v1.GetFileRequest]) (*connect.Response[v1.GetFileResponse], error) GetCommit(context.Context, *connect.Request[v1.GetCommitRequest]) (*connect.Response[v1.GetCommitResponse], error) + GetCommits(context.Context, *connect.Request[v1.GetCommitsRequest]) (*connect.Response[v1.GetCommitsResponse], error) } // NewVCSServiceHandler builds an HTTP handler from the service implementation. It returns the path @@ -157,34 +164,41 @@ type VCSServiceHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewVCSServiceHandler(svc VCSServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + vCSServiceMethods := v1.File_vcs_v1_vcs_proto.Services().ByName("VCSService").Methods() vCSServiceGithubAppHandler := connect.NewUnaryHandler( VCSServiceGithubAppProcedure, svc.GithubApp, - connect.WithSchema(vCSServiceGithubAppMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GithubApp")), connect.WithHandlerOptions(opts...), ) vCSServiceGithubLoginHandler := connect.NewUnaryHandler( VCSServiceGithubLoginProcedure, svc.GithubLogin, - connect.WithSchema(vCSServiceGithubLoginMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GithubLogin")), connect.WithHandlerOptions(opts...), ) vCSServiceGithubRefreshHandler := connect.NewUnaryHandler( VCSServiceGithubRefreshProcedure, svc.GithubRefresh, - connect.WithSchema(vCSServiceGithubRefreshMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GithubRefresh")), connect.WithHandlerOptions(opts...), ) vCSServiceGetFileHandler := connect.NewUnaryHandler( VCSServiceGetFileProcedure, svc.GetFile, - connect.WithSchema(vCSServiceGetFileMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GetFile")), connect.WithHandlerOptions(opts...), ) vCSServiceGetCommitHandler := connect.NewUnaryHandler( VCSServiceGetCommitProcedure, svc.GetCommit, - connect.WithSchema(vCSServiceGetCommitMethodDescriptor), + connect.WithSchema(vCSServiceMethods.ByName("GetCommit")), + connect.WithHandlerOptions(opts...), + ) + vCSServiceGetCommitsHandler := connect.NewUnaryHandler( + VCSServiceGetCommitsProcedure, + svc.GetCommits, + connect.WithSchema(vCSServiceMethods.ByName("GetCommits")), connect.WithHandlerOptions(opts...), ) return "/vcs.v1.VCSService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -199,6 +213,8 @@ func NewVCSServiceHandler(svc VCSServiceHandler, opts ...connect.HandlerOption) vCSServiceGetFileHandler.ServeHTTP(w, r) case VCSServiceGetCommitProcedure: vCSServiceGetCommitHandler.ServeHTTP(w, r) + case VCSServiceGetCommitsProcedure: + vCSServiceGetCommitsHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -227,3 +243,7 @@ func (UnimplementedVCSServiceHandler) GetFile(context.Context, *connect.Request[ func (UnimplementedVCSServiceHandler) GetCommit(context.Context, *connect.Request[v1.GetCommitRequest]) (*connect.Response[v1.GetCommitResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("vcs.v1.VCSService.GetCommit is not implemented")) } + +func (UnimplementedVCSServiceHandler) GetCommits(context.Context, *connect.Request[v1.GetCommitsRequest]) (*connect.Response[v1.GetCommitsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("vcs.v1.VCSService.GetCommits is not implemented")) +} diff --git a/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.mux.go b/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.mux.go index 51ade2586d..a8e61ecae4 100644 --- a/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.mux.go +++ b/api/gen/proto/go/vcs/v1/vcsv1connect/vcs.connect.mux.go @@ -44,4 +44,9 @@ func RegisterVCSServiceHandler(mux *mux.Router, svc VCSServiceHandler, opts ...c svc.GetCommit, opts..., )) + mux.Handle("/vcs.v1.VCSService/GetCommits", connect.NewUnaryHandler( + "/vcs.v1.VCSService/GetCommits", + svc.GetCommits, + opts..., + )) } diff --git a/api/gen/proto/go/version/v1/version.pb.go b/api/gen/proto/go/version/v1/version.pb.go index 9909712bfa..a59e280a36 100644 --- a/api/gen/proto/go/version/v1/version.pb.go +++ b/api/gen/proto/go/version/v1/version.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: version/v1/version.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,18 +22,16 @@ const ( ) type VersionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *VersionRequest) Reset() { *x = VersionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_version_v1_version_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_version_v1_version_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *VersionRequest) String() string { @@ -43,7 +42,7 @@ func (*VersionRequest) ProtoMessage() {} func (x *VersionRequest) ProtoReflect() protoreflect.Message { mi := &file_version_v1_version_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -59,20 +58,17 @@ func (*VersionRequest) Descriptor() ([]byte, []int) { } type VersionResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + QuerierAPI uint64 `protobuf:"varint,1,opt,name=QuerierAPI,proto3" json:"QuerierAPI,omitempty"` unknownFields protoimpl.UnknownFields - - QuerierAPI uint64 `protobuf:"varint,1,opt,name=QuerierAPI,proto3" json:"QuerierAPI,omitempty"` + sizeCache protoimpl.SizeCache } func (x *VersionResponse) Reset() { *x = VersionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_version_v1_version_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_version_v1_version_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *VersionResponse) String() string { @@ -83,7 +79,7 @@ func (*VersionResponse) ProtoMessage() {} func (x *VersionResponse) ProtoReflect() protoreflect.Message { mi := &file_version_v1_version_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -106,28 +102,25 @@ func (x *VersionResponse) GetQuerierAPI() uint64 { } type InstanceVersion struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` - Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` // Unix timestamp (with nanoseconds precision) of the last heartbeat sent // by this instance. Timestamp int64 `protobuf:"varint,3,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"` // Querier Service API version QuerierAPI uint64 `protobuf:"varint,4,opt,name=QuerierAPI,proto3" json:"QuerierAPI,omitempty"` // Tells if the instance is running or has left cluster. - Left bool `protobuf:"varint,5,opt,name=left,proto3" json:"left,omitempty"` + Left bool `protobuf:"varint,5,opt,name=left,proto3" json:"left,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *InstanceVersion) Reset() { *x = InstanceVersion{} - if protoimpl.UnsafeEnabled { - mi := &file_version_v1_version_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_version_v1_version_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *InstanceVersion) String() string { @@ -138,7 +131,7 @@ func (*InstanceVersion) ProtoMessage() {} func (x *InstanceVersion) ProtoReflect() protoreflect.Message { mi := &file_version_v1_version_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -190,20 +183,17 @@ func (x *InstanceVersion) GetLeft() bool { // Versions is the top-level type used to model version for all instances, containing information for individual instances. type Versions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Instances map[string]*InstanceVersion `protobuf:"bytes,1,rep,name=instances,proto3" json:"instances,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` unknownFields protoimpl.UnknownFields - - Instances map[string]*InstanceVersion `protobuf:"bytes,1,rep,name=instances,proto3" json:"instances,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + sizeCache protoimpl.SizeCache } func (x *Versions) Reset() { *x = Versions{} - if protoimpl.UnsafeEnabled { - mi := &file_version_v1_version_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_version_v1_version_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Versions) String() string { @@ -214,7 +204,7 @@ func (*Versions) ProtoMessage() {} func (x *Versions) ProtoReflect() protoreflect.Message { mi := &file_version_v1_version_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -238,66 +228,48 @@ func (x *Versions) GetInstances() map[string]*InstanceVersion { var File_version_v1_version_proto protoreflect.FileDescriptor -var file_version_v1_version_proto_rawDesc = []byte{ - 0x0a, 0x18, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x22, 0x10, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x51, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x41, 0x50, 0x49, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0a, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x41, 0x50, 0x49, 0x22, 0x87, 0x01, 0x0a, 0x0f, - 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, - 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, - 0x64, 0x64, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x41, 0x50, 0x49, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x41, 0x50, - 0x49, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x04, 0x6c, 0x65, 0x66, 0x74, 0x22, 0xa8, 0x01, 0x0a, 0x08, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x41, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x73, 0x1a, 0x59, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x32, 0x4f, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0xab, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, - 0x70, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x56, 0x58, 0x58, 0xaa, 0x02, - 0x0a, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0a, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x16, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x0b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_version_v1_version_proto_rawDesc = "" + + "\n" + + "\x18version/v1/version.proto\x12\n" + + "version.v1\"\x10\n" + + "\x0eVersionRequest\"1\n" + + "\x0fVersionResponse\x12\x1e\n" + + "\n" + + "QuerierAPI\x18\x01 \x01(\x04R\n" + + "QuerierAPI\"\x87\x01\n" + + "\x0fInstanceVersion\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\tR\x02ID\x12\x12\n" + + "\x04addr\x18\x02 \x01(\tR\x04addr\x12\x1c\n" + + "\tTimestamp\x18\x03 \x01(\x03R\tTimestamp\x12\x1e\n" + + "\n" + + "QuerierAPI\x18\x04 \x01(\x04R\n" + + "QuerierAPI\x12\x12\n" + + "\x04left\x18\x05 \x01(\bR\x04left\"\xa8\x01\n" + + "\bVersions\x12A\n" + + "\tinstances\x18\x01 \x03(\v2#.version.v1.Versions.InstancesEntryR\tinstances\x1aY\n" + + "\x0eInstancesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x121\n" + + "\x05value\x18\x02 \x01(\v2\x1b.version.v1.InstanceVersionR\x05value:\x028\x012O\n" + + "\aVersion\x12D\n" + + "\aVersion\x12\x1a.version.v1.VersionRequest\x1a\x1b.version.v1.VersionResponse\"\x00B\xab\x01\n" + + "\x0ecom.version.v1B\fVersionProtoP\x01ZBgithub.com/grafana/pyroscope/api/gen/proto/go/version/v1;versionv1\xa2\x02\x03VXX\xaa\x02\n" + + "Version.V1\xca\x02\n" + + "Version\\V1\xe2\x02\x16Version\\V1\\GPBMetadata\xea\x02\vVersion::V1b\x06proto3" var ( file_version_v1_version_proto_rawDescOnce sync.Once - file_version_v1_version_proto_rawDescData = file_version_v1_version_proto_rawDesc + file_version_v1_version_proto_rawDescData []byte ) func file_version_v1_version_proto_rawDescGZIP() []byte { file_version_v1_version_proto_rawDescOnce.Do(func() { - file_version_v1_version_proto_rawDescData = protoimpl.X.CompressGZIP(file_version_v1_version_proto_rawDescData) + file_version_v1_version_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_version_v1_version_proto_rawDesc), len(file_version_v1_version_proto_rawDesc))) }) return file_version_v1_version_proto_rawDescData } var file_version_v1_version_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_version_v1_version_proto_goTypes = []interface{}{ +var file_version_v1_version_proto_goTypes = []any{ (*VersionRequest)(nil), // 0: version.v1.VersionRequest (*VersionResponse)(nil), // 1: version.v1.VersionResponse (*InstanceVersion)(nil), // 2: version.v1.InstanceVersion @@ -321,61 +293,11 @@ func file_version_v1_version_proto_init() { if File_version_v1_version_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_version_v1_version_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VersionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_version_v1_version_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VersionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_version_v1_version_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InstanceVersion); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_version_v1_version_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Versions); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_version_v1_version_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_version_v1_version_proto_rawDesc), len(file_version_v1_version_proto_rawDesc)), NumEnums: 0, NumMessages: 5, NumExtensions: 0, @@ -386,7 +308,6 @@ func file_version_v1_version_proto_init() { MessageInfos: file_version_v1_version_proto_msgTypes, }.Build() File_version_v1_version_proto = out.File - file_version_v1_version_proto_rawDesc = nil file_version_v1_version_proto_goTypes = nil file_version_v1_version_proto_depIdxs = nil } diff --git a/api/gen/proto/go/version/v1/versionv1connect/version.connect.go b/api/gen/proto/go/version/v1/versionv1connect/version.connect.go index 090e02bb19..189062605a 100644 --- a/api/gen/proto/go/version/v1/versionv1connect/version.connect.go +++ b/api/gen/proto/go/version/v1/versionv1connect/version.connect.go @@ -37,12 +37,6 @@ const ( VersionVersionProcedure = "/version.v1.Version/Version" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - versionServiceDescriptor = v1.File_version_v1_version_proto.Services().ByName("Version") - versionVersionMethodDescriptor = versionServiceDescriptor.Methods().ByName("Version") -) - // VersionClient is a client for the version.v1.Version service. type VersionClient interface { Version(context.Context, *connect.Request[v1.VersionRequest]) (*connect.Response[v1.VersionResponse], error) @@ -57,11 +51,12 @@ type VersionClient interface { // http://api.acme.com or https://acme.com/grpc). func NewVersionClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) VersionClient { baseURL = strings.TrimRight(baseURL, "/") + versionMethods := v1.File_version_v1_version_proto.Services().ByName("Version").Methods() return &versionClient{ version: connect.NewClient[v1.VersionRequest, v1.VersionResponse]( httpClient, baseURL+VersionVersionProcedure, - connect.WithSchema(versionVersionMethodDescriptor), + connect.WithSchema(versionMethods.ByName("Version")), connect.WithClientOptions(opts...), ), } @@ -88,10 +83,11 @@ type VersionHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewVersionHandler(svc VersionHandler, opts ...connect.HandlerOption) (string, http.Handler) { + versionMethods := v1.File_version_v1_version_proto.Services().ByName("Version").Methods() versionVersionHandler := connect.NewUnaryHandler( VersionVersionProcedure, svc.Version, - connect.WithSchema(versionVersionMethodDescriptor), + connect.WithSchema(versionMethods.ByName("Version")), connect.WithHandlerOptions(opts...), ) return "/version.v1.Version/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/api/go.mod b/api/go.mod index 8954335576..c221262f60 100644 --- a/api/go.mod +++ b/api/go.mod @@ -1,22 +1,33 @@ module github.com/grafana/pyroscope/api -go 1.21 +go 1.25.0 + +toolchain go1.25.12 require ( - connectrpc.com/connect v1.16.2 - github.com/gorilla/mux v1.8.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 - github.com/planetscale/vtprotobuf v0.6.0 - github.com/prometheus/common v0.52.3 - google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.34.1 + connectrpc.com/connect v1.19.2 + github.com/google/gnostic v0.7.1 + github.com/gorilla/mux v1.8.1 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 + github.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25 + github.com/prometheus/common v0.67.5 + github.com/stretchr/testify v1.11.1 + google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 + google.golang.org/grpc v1.81.0 + google.golang.org/protobuf v1.36.11 ) require ( - github.com/golang/protobuf v1.5.3 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/api/go.sum b/api/go.sum index a19aa1f4c4..60663b9635 100644 --- a/api/go.sum +++ b/api/go.sum @@ -1,33 +1,73 @@ -connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= -connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= -github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA= -github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= -github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA= -github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 h1:8eadJkXbwDEMNwcB5O0s5Y5eCfyuCLdvaiOIaGTrWmQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +connectrpc.com/connect v1.19.2 h1:McQ83FGdzL+t60peksi0gXC7MQ/iLKgLduAnThbM0mo= +connectrpc.com/connect v1.19.2/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic v0.7.1 h1:t5Kc7j/8kYr8t2u11rykRrPPovlEMG4+xdc/SpekATs= +github.com/google/gnostic v0.7.1/go.mod h1:KSw6sxnxEBFM8jLPfJd46xZP+yQcfE8XkiqfZx5zR28= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25 h1:S1hI5JiKP7883xBzZAr1ydcxrKNSVNm7+3+JwjxZEsg= +github.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25/go.mod h1:ZQntvDG8TkPgljxtA0R9frDoND4QORU1VXz015N5Ks4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 h1:U8orV30l6KpDsi9dxU0CoJZGbjS8EEpw+6ba+XwGPQA= +google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348/go.mod h1:Yzdzr5OOZFgSsEV2D/Xi9NL3bszpXFAg0hFJiRohcD8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 h1:tEkOQcXgF6dH1G+MVKZrfpYvozGrzb91k6ha7jireSM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= +google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/api/metastore/v1/compactor.proto b/api/metastore/v1/compactor.proto new file mode 100644 index 0000000000..e057b31581 --- /dev/null +++ b/api/metastore/v1/compactor.proto @@ -0,0 +1,78 @@ +syntax = "proto3"; + +package metastore.v1; + +import "metastore/v1/types.proto"; + +service CompactionService { + // Used to both retrieve jobs and update the jobs status at the same time. + rpc PollCompactionJobs(PollCompactionJobsRequest) returns (PollCompactionJobsResponse) {} +} + +message PollCompactionJobsRequest { + repeated CompactionJobStatusUpdate status_updates = 1; + // How many new jobs a worker can be assigned to. + uint32 job_capacity = 2; +} + +message PollCompactionJobsResponse { + repeated CompactionJob compaction_jobs = 1; + repeated CompactionJobAssignment assignments = 2; +} + +message CompactionJob { + string name = 1; + uint32 shard = 2; + string tenant = 3; + uint32 compaction_level = 4; + repeated string source_blocks = 5; + repeated Tombstones tombstones = 6; +} + +// Tombstones represent objects removed from the index but still stored. +message Tombstones { + BlockTombstones blocks = 1; + ShardTombstone shard = 2; +} + +message BlockTombstones { + string name = 1; + uint32 shard = 2; + string tenant = 3; + uint32 compaction_level = 4; + repeated string blocks = 5; +} + +message ShardTombstone { + string name = 1; + // Lower time boundary. Unix epoch in nanoseconds. + int64 timestamp = 2; + int64 duration = 3; + uint32 shard = 4; + string tenant = 5; +} + +message CompactionJobAssignment { + string name = 1; + uint64 token = 2; + int64 lease_expires_at = 3; +} + +message CompactionJobStatusUpdate { + string name = 1; + uint64 token = 2; + CompactionJobStatus status = 3; + // Only present if the job completed successfully. + CompactedBlocks compacted_blocks = 4; +} + +message CompactedBlocks { + metastore.v1.BlockList source_blocks = 1; + repeated metastore.v1.BlockMeta new_blocks = 2; +} + +enum CompactionJobStatus { + COMPACTION_STATUS_UNSPECIFIED = 0; + COMPACTION_STATUS_IN_PROGRESS = 1; + COMPACTION_STATUS_SUCCESS = 2; +} diff --git a/api/metastore/v1/index.proto b/api/metastore/v1/index.proto new file mode 100644 index 0000000000..f79bd43b98 --- /dev/null +++ b/api/metastore/v1/index.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package metastore.v1; + +import "metastore/v1/types.proto"; + +service IndexService { + rpc AddBlock(AddBlockRequest) returns (AddBlockResponse) {} + rpc GetBlockMetadata(GetBlockMetadataRequest) returns (GetBlockMetadataResponse) {} +} + +message AddBlockRequest { + BlockMeta block = 1; +} + +message AddBlockResponse {} + +message GetBlockMetadataRequest { + BlockList blocks = 1; +} + +message GetBlockMetadataResponse { + repeated BlockMeta blocks = 1; +} diff --git a/api/metastore/v1/query.proto b/api/metastore/v1/query.proto new file mode 100644 index 0000000000..3af1a0e21f --- /dev/null +++ b/api/metastore/v1/query.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; + +package metastore.v1; + +import "metastore/v1/types.proto"; +import "types/v1/types.proto"; + +service MetadataQueryService { + rpc QueryMetadata(QueryMetadataRequest) returns (QueryMetadataResponse) {} + rpc QueryMetadataLabels(QueryMetadataLabelsRequest) returns (QueryMetadataLabelsResponse) {} +} + +message QueryMetadataRequest { + repeated string tenant_id = 1; + int64 start_time = 2; + int64 end_time = 3; + string query = 4; + repeated string labels = 5; +} + +message QueryMetadataResponse { + repeated BlockMeta blocks = 1; +} + +message QueryMetadataLabelsRequest { + repeated string tenant_id = 1; + int64 start_time = 2; + int64 end_time = 3; + string query = 4; + repeated string labels = 5; +} + +message QueryMetadataLabelsResponse { + repeated types.v1.Labels labels = 1; +} diff --git a/api/metastore/v1/raft_log/raft_log.proto b/api/metastore/v1/raft_log/raft_log.proto new file mode 100644 index 0000000000..27afb60493 --- /dev/null +++ b/api/metastore/v1/raft_log/raft_log.proto @@ -0,0 +1,118 @@ +syntax = "proto3"; + +package raft_log; + +import "metastore/v1/compactor.proto"; +import "metastore/v1/types.proto"; + +enum RaftCommand { + RAFT_COMMAND_UNKNOWN = 0; + RAFT_COMMAND_ADD_BLOCK_METADATA = 1; + RAFT_COMMAND_GET_COMPACTION_PLAN_UPDATE = 2; + RAFT_COMMAND_UPDATE_COMPACTION_PLAN = 3; + RAFT_COMMAND_TRUNCATE_INDEX = 4; +} + +message AddBlockMetadataRequest { + metastore.v1.BlockMeta metadata = 1; +} + +message AddBlockMetadataResponse {} + +// GetCompactionPlanUpdateRequest requests CompactionPlanUpdate. +// The resulting plan should be proposed to the raft members. +// This is a read-only operation: it MUST NOT alter the state. +message GetCompactionPlanUpdateRequest { + // CompactionJobStatusUpdate is a change + // requested by the compaction worker. + repeated CompactionJobStatusUpdate status_updates = 1; + uint32 assign_jobs_max = 2; +} + +message CompactionJobStatusUpdate { + string name = 1; + uint64 token = 2; + metastore.v1.CompactionJobStatus status = 3; +} + +// GetCompactionPlanUpdateResponse includes the planned change. +// The plan should be proposed to the raft members. +message GetCompactionPlanUpdateResponse { + uint64 term = 1; + CompactionPlanUpdate plan_update = 2; +} + +message CompactionPlanUpdate { + repeated NewCompactionJob new_jobs = 1; + repeated AssignedCompactionJob assigned_jobs = 2; + repeated UpdatedCompactionJob updated_jobs = 3; + repeated CompletedCompactionJob completed_jobs = 4; + repeated EvictedCompactionJob evicted_jobs = 5; +} + +message NewCompactionJob { + CompactionJobState state = 1; + CompactionJobPlan plan = 2; +} + +message AssignedCompactionJob { + CompactionJobState state = 1; + CompactionJobPlan plan = 2; +} + +message UpdatedCompactionJob { + CompactionJobState state = 1; +} + +message CompletedCompactionJob { + CompactionJobState state = 1; + metastore.v1.CompactedBlocks compacted_blocks = 2; +} + +message EvictedCompactionJob { + CompactionJobState state = 1; +} + +// CompactionJobState is produced in response to +// the compaction worker status update request. +// +// Compaction level and other attributes that +// affect the scheduling order or status update +// handling should be included into the message. +message CompactionJobState { + string name = 1; + uint32 compaction_level = 2; + metastore.v1.CompactionJobStatus status = 3; + uint64 token = 4; + int64 lease_expires_at = 5; + int64 added_at = 6; + uint32 failures = 7; +} + +message CompactionJobPlan { + string name = 1; + // Blocks to be compacted. + string tenant = 2; + uint32 shard = 3; + uint32 compaction_level = 4; + repeated string source_blocks = 5; + // Objects to be deleted. + repeated metastore.v1.Tombstones tombstones = 6; +} + +// UpdateCompactionPlanRequest proposes compaction plan changes. +message UpdateCompactionPlanRequest { + uint64 term = 1; + CompactionPlanUpdate plan_update = 2; +} + +message UpdateCompactionPlanResponse { + CompactionPlanUpdate plan_update = 1; +} + +message TruncateIndexRequest { + uint64 term = 1; + repeated metastore.v1.Tombstones tombstones = 2; +} + +message TruncateIndexResponse {} diff --git a/api/metastore/v1/tenant.proto b/api/metastore/v1/tenant.proto new file mode 100644 index 0000000000..598e249594 --- /dev/null +++ b/api/metastore/v1/tenant.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package metastore.v1; + +service TenantService { + rpc GetTenants(GetTenantsRequest) returns (GetTenantsResponse) {} + rpc GetTenant(GetTenantRequest) returns (GetTenantResponse) {} + rpc DeleteTenant(DeleteTenantRequest) returns (DeleteTenantResponse) {} +} + +message GetTenantsRequest {} + +message GetTenantsResponse { + repeated string tenant_ids = 1; +} + +message GetTenantRequest { + string tenant_id = 1; +} + +message GetTenantResponse { + TenantStats stats = 1; +} + +message TenantStats { + // Whether we received any data at any time in the past. + bool data_ingested = 1; + // Milliseconds since epoch. + int64 oldest_profile_time = 2; + // Milliseconds since epoch. + int64 newest_profile_time = 3; +} + +message DeleteTenantRequest { + string tenant_id = 1; +} + +message DeleteTenantResponse {} diff --git a/api/metastore/v1/types.proto b/api/metastore/v1/types.proto new file mode 100644 index 0000000000..78dcc1edba --- /dev/null +++ b/api/metastore/v1/types.proto @@ -0,0 +1,122 @@ +syntax = "proto3"; + +package metastore.v1; + +// BlockMeta is a metadata entry that describes the block's contents. A block +// is a collection of datasets that share certain properties, such as shard ID, +// compaction level, tenant ID, time range, creation time, and more. +// +// The block content's format denotes the binary format of the datasets and the +// metadata entry (to address logical dependencies). Each dataset has its own +// table of contents that lists the sections within the dataset. Each dataset +// has its own set of attributes (labels) that describe its specific contents. +message BlockMeta { + uint32 format_version = 1; + + // Block ID is a unique identifier for the block. + // This is the only field that is not included into + // the string table. + string id = 2; + + // If empty, datasets belong to distinct tenants. + int32 tenant = 3; + uint32 shard = 4; + uint32 compaction_level = 5; + int64 min_time = 6; + int64 max_time = 7; + int32 created_by = 8; + uint64 metadata_offset = 12; + uint64 size = 9; + repeated Dataset datasets = 10; + + // String table contains strings of the block. + // By convention, the first string is always an empty string. + repeated string string_table = 11; +} + +message Dataset { + uint32 format = 9; + + int32 tenant = 1; + int32 name = 2; + int64 min_time = 3; + int64 max_time = 4; + + // Table of contents lists data sections within the tenant + // service region. The offsets are absolute. + // + // The interpretation of the table of contents is specific + // to the format. + // + // By default (format 0), the sections are: + // - 0: profiles.parquet + // - 1: index.tsdb + // - 2: symbols.symdb + // + // Format 1 corresponds to the tenant-wide index: + // - 0: index.tsdb (dataset index) + repeated uint64 table_of_contents = 5; + + // Size of the dataset in bytes. + uint64 size = 6; + reserved 7; + + // Length prefixed label key-value pairs. + // + // Multiple label sets can be associated with a dataset to denote relationships + // across multiple dimensions. For example, each dataset currently stores data + // for multiple profile types: + // - service_name=A, profile_type=cpu + // - service_name=A, profile_type=memory + // + // Labels are primarily used to filter datasets based on their attributes. + // For instance, labels can be used to select datasets containing a specific + // service. + // + // The set of attributes is extensible and can grow over time. For example, a + // namespace attribute could be added to datasets: + // - service_name=A, profile_type=cpu + // - service_name=A, profile_type=memory + // - service_name=B, namespace=N, profile_type=cpu + // - service_name=B, namespace=N, profile_type=memory + // - service_name=C, namespace=N, profile_type=cpu + // - service_name=C, namespace=N, profile_type=memory + // + // This organization enables querying datasets by namespace without accessing + // the block contents, which significantly improves performance. + // + // Metadata labels are not required to be included in the block's TSDB index + // and may be orthogonal to the data dimensions. Generally, attributes serve + // two primary purposes: + // - To create data scopes that span multiple service, reducing the need to + // scan the entire set of block satisfying the query expression, i.e., + // the time range and tenant ID. + // - To provide additional information about datasets without altering the + // storage schema or access methods. + // + // For example, this approach can support cost attribution or similar breakdown + // analyses. It can also handle data dependencies (e.g., links to external data) + // using labels. + // + // The cardinality of the labels is expected to remain relatively low (fewer + // than a million unique combinations globally). However, this depends on the + // metadata storage system. + // + // Metadata labels are represented as a slice of `int32` values that refer to + // strings in the metadata entry's string table. The slice is a sequence of + // length-prefixed key-value (KV) pairs: + // + // len(2) | k1 | v1 | k2 | v2 | len(3) | k1 | v3 | k2 | v4 | k3 | v5 + // + // The order of KV pairs is not defined. The format is optimized for indexing + // rather than querying, and it is not intended to be the most space-efficient + // representation. Since entries are supposed to be indexed, the redundancy of + // denormalized relationships is not a concern. + repeated int32 labels = 8; +} + +message BlockList { + string tenant = 1; + uint32 shard = 2; + repeated string blocks = 3; +} diff --git a/api/model/labelset/labelset.go b/api/model/labelset/labelset.go new file mode 100644 index 0000000000..b4acd8f830 --- /dev/null +++ b/api/model/labelset/labelset.go @@ -0,0 +1,269 @@ +// Package labelset implements parsing/normalizing of string representation of the Label Set of a profile. +// +// This is used by the /ingest endpoint, as described in the original Pyroscope API. We keep this mainly for backwards compatibility. +package labelset + +import ( + "bytes" + "errors" + "sort" + "strconv" + "strings" + "sync" + "time" +) + +type LabelSet struct { + labels map[string]string +} + +type ParserState int + +const ( + nameParserState ParserState = iota + tagLabelSetParserState + tagValueParserState + doneParserState +) + +func New(labels map[string]string) *LabelSet { return &LabelSet{labels: labels} } + +func Parse(name string) (*LabelSet, error) { + k := &LabelSet{labels: make(map[string]string)} + p, ok := parserPool.Get().(*parser) + if !ok { + return nil, errParserPoolFailure + } + defer parserPool.Put(p) + p.reset() + var err error + for _, r := range name + "{" { + switch p.parserState { + case nameParserState: + err = p.nameParserCase(r, k) + case tagLabelSetParserState: + p.tagLabelSetParserCase(r) + case tagValueParserState: + err = p.tagValueParserCase(r, k) + case doneParserState: + // No action needed + } + if err != nil { + return nil, err + } + } + + return k, nil +} + +func ValidateLabelSet(k *LabelSet) error { + if k == nil { + return ErrInvalidLabelSet + } + + for key, v := range k.labels { + if key == ReservedLabelNameName { + if err := ValidateServiceName(v); err != nil { + return err + } + } else { + if err := ValidateLabelName(key); err != nil { + return err + } + } + } + + return nil +} + +type parser struct { + parserState ParserState + key *bytes.Buffer + value *bytes.Buffer +} + +var parserPool = sync.Pool{ //nolint:gochecknoglobals + New: func() any { + return &parser{ + parserState: nameParserState, + key: new(bytes.Buffer), + value: new(bytes.Buffer), + } + }, +} + +func (p *parser) reset() { + p.parserState = nameParserState + p.key.Reset() + p.value.Reset() +} + +// Parse's nameParserState switch case +func (p *parser) nameParserCase(r int32, k *LabelSet) error { + switch r { + case '{': + p.parserState = tagLabelSetParserState + serviceName := strings.TrimSpace(p.value.String()) + if err := ValidateServiceName(serviceName); err != nil { + return err + } + k.labels["__name__"] = serviceName + default: + p.value.WriteRune(r) + } + + return nil +} + +// Parse's tagLabelSetParserState switch case +func (p *parser) tagLabelSetParserCase(r rune) { + switch r { + case '}': + p.parserState = doneParserState + case '=': + p.parserState = tagValueParserState + p.value.Reset() + default: + p.key.WriteRune(r) + } +} + +// Parse's tagValueParserState switch case +func (p *parser) tagValueParserCase(r rune, k *LabelSet) error { + switch r { + case ',', '}': + p.parserState = tagLabelSetParserState + key := strings.TrimSpace(p.key.String()) + if !IsLabelNameReserved(key) { + if err := ValidateLabelName(key); err != nil { + return err + } + } + k.labels[key] = strings.TrimSpace(p.value.String()) + p.key.Reset() + default: + p.value.WriteRune(r) + } + + return nil +} + +func (k *LabelSet) LabelSet() string { + return k.Normalized() +} + +const ProfileIDLabelName = "profile_id" + +func (k *LabelSet) HasProfileID() bool { + v, ok := k.labels[ProfileIDLabelName] + + return ok && v != "" +} + +func (k *LabelSet) ProfileID() (string, bool) { + id, ok := k.labels[ProfileIDLabelName] + + return id, ok +} + +func ServiceNameLabelSet(appName string) string { return appName + "{}" } + +func TreeLabelSet(k string, depth int, unixTime int64) string { + return k + ":" + strconv.Itoa(depth) + ":" + strconv.FormatInt(unixTime, 10) +} + +func (k *LabelSet) TreeLabelSet(depth int, t time.Time) string { + return TreeLabelSet(k.Normalized(), depth, t.Unix()) +} + +var ( + errLabelSetInvalid = errors.New("invalid key") + errParserPoolFailure = errors.New("failed to get parser from pool") +) + +// ParseTreeLabelSet retrieves tree time and depth level from the given key. +func ParseTreeLabelSet(k string) (time.Time, int, error) { + a := strings.Split(k, ":") + if len(a) < 3 { + return time.Time{}, 0, errLabelSetInvalid + } + level, err := strconv.Atoi(a[1]) + if err != nil { + return time.Time{}, 0, err + } + v, err := strconv.Atoi(a[2]) + if err != nil { + return time.Time{}, 0, err + } + + return time.Unix(int64(v), 0), level, err +} + +func (k *LabelSet) DictLabelSet() string { + return k.labels[ReservedLabelNameName] +} + +// FromTreeToDictLabelSet returns app name from tree key k: given tree key +// "foo{}:0:1234567890", the call returns "foo". +// +// Before tags support, segment key form (i.e. app name + tags: foo{key=value}) +// has been used to reference a dictionary (trie). +func FromTreeToDictLabelSet(k string) string { + return k[0:strings.IndexAny(k, "{")] +} + +func (l *LabelSet) Normalized() string { + var sb strings.Builder + + labelNames := make([]string, 0, len(l.labels)) + for k, v := range l.labels { + if k == ReservedLabelNameName { + sb.WriteString(v) + } else { + labelNames = append(labelNames, k) + } + } + + sort.Slice(labelNames, func(i, j int) bool { + return labelNames[i] < labelNames[j] + }) + + sb.WriteString("{") + for i, k := range labelNames { + v := l.labels[k] + if i != 0 { + sb.WriteString(",") + } + sb.WriteString(k) + sb.WriteString("=") + sb.WriteString(v) + } + sb.WriteString("}") + + return sb.String() +} + +func (k *LabelSet) Clone() *LabelSet { + newMap := make(map[string]string) + for k, v := range k.labels { + newMap[k] = v + } + + return &LabelSet{labels: newMap} +} + +func (k *LabelSet) ServiceName() string { + return k.labels[ReservedLabelNameName] +} + +func (k *LabelSet) Labels() map[string]string { + return k.labels +} + +func (k *LabelSet) Add(key, value string) { + if value == "" { + delete(k.labels, key) + } else { + k.labels[key] = value + } +} diff --git a/api/model/labelset/labelset_bench_test.go b/api/model/labelset/labelset_bench_test.go new file mode 100644 index 0000000000..dc068bf519 --- /dev/null +++ b/api/model/labelset/labelset_bench_test.go @@ -0,0 +1,48 @@ +package labelset + +import ( + "math/rand" + "testing" +) + +func BenchmarkKey_Parse(b *testing.B) { + const ( + labelsSize = 10 + minLen = 6 + maxLen = 16 + ) + + // Duplicates are okay. + labels := make(map[string]string, labelsSize+1) + for i := 0; i < labelsSize; i++ { + labels[randString(randInt(minLen, maxLen))] = randString(randInt(minLen, maxLen)) + } + + labels["__name__"] = "benchmark.key.parse" + keyStr := New(labels).Normalized() + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + if _, err := Parse(keyStr); err != nil { + b.Fatal(err) + } + } +} + +func randInt(minVal, maxVal int) int { return rand.Intn(maxVal-minVal) + minVal } //nolint:gosec + +// TODO(kolesnikovae): This is not near perfect way of generating strings. +// It makes sense to create a package for util functions like this. + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func randString(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] //nolint:gosec + } + + return string(b) +} diff --git a/api/model/labelset/labelset_test.go b/api/model/labelset/labelset_test.go new file mode 100644 index 0000000000..366b7ae75e --- /dev/null +++ b/api/model/labelset/labelset_test.go @@ -0,0 +1,47 @@ +package labelset + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseLabelSet(t *testing.T) { + t.Run("no tags version works", func(t *testing.T) { + k, err := Parse("foo") + require.NoError(t, err) + require.Equal(t, map[string]string{"__name__": "foo"}, k.labels) + }) + + t.Run("simple values work", func(t *testing.T) { + k, err := Parse("foo{bar=1,baz=2}") + require.NoError(t, err) + require.Equal(t, map[string]string{"__name__": "foo", "bar": "1", "baz": "2"}, k.labels) + }) + + t.Run("simple values with spaces work", func(t *testing.T) { + k, err := Parse(" foo { bar = 1 , baz = 2 } ") + require.NoError(t, err) + require.Equal(t, map[string]string{"__name__": "foo", "bar": "1", "baz": "2"}, k.labels) + }) +} + +func TestKeyNormalize(t *testing.T) { + t.Run("no tags version works", func(t *testing.T) { + k, err := Parse("foo") + require.NoError(t, err) + require.Equal(t, "foo{}", k.Normalized()) + }) + + t.Run("simple values work", func(t *testing.T) { + k, err := Parse("foo{bar=1,baz=2}") + require.NoError(t, err) + require.Equal(t, "foo{bar=1,baz=2}", k.Normalized()) + }) + + t.Run("unsorted values work", func(t *testing.T) { + k, err := Parse("foo{baz=1,bar=2}") + require.NoError(t, err) + require.Equal(t, "foo{bar=2,baz=1}", k.Normalized()) + }) +} diff --git a/api/model/labelset/validate.go b/api/model/labelset/validate.go new file mode 100644 index 0000000000..822f6e437e --- /dev/null +++ b/api/model/labelset/validate.go @@ -0,0 +1,97 @@ +package labelset + +import ( + "errors" + "fmt" +) + +var ( + ErrInvalidServiceName = errors.New("invalid service name") + ErrInvalidLabelSet = errors.New("invalid label set") + ErrInvalidLabelName = errors.New("invalid label name") + ErrServiceNameIsRequired = errors.New("service name is required") + ErrLabelNameIsRequired = errors.New("label name is required") + ErrLabelNameReserved = errors.New("label name is reserved") +) + +const ReservedLabelNameName = "__name__" + +var reservedLabelNames = []string{ //nolint:gochecknoglobals + ReservedLabelNameName, +} + +type Error struct { + Inner error + Expr string + // TODO: add offset? +} + +func newErr(err error, expr string) *Error { return &Error{Inner: err, Expr: expr} } + +func (e *Error) Error() string { return e.Inner.Error() + ": " + e.Expr } + +func (e *Error) Unwrap() error { return e.Inner } + +func newInvalidLabelNameRuneError(k string, r rune) *Error { + return newInvalidRuneError(ErrInvalidLabelName, k, r) +} + +func NewInvalidServiceNameRuneError(k string, r rune) *Error { + return newInvalidRuneError(ErrInvalidServiceName, k, r) +} + +func newInvalidRuneError(err error, k string, r rune) *Error { + return newErr(err, fmt.Sprintf("%s: character is not allowed: %q", k, r)) +} + +// ValidateLabelName report an error if the given key k violates constraints. +// +// The function should be used to validate user input. The function returns +// ErrLabelNameReserved if the key is valid but reserved for internal use. +func ValidateLabelName(k string) error { + if len(k) == 0 { + return ErrLabelNameIsRequired + } + for _, r := range k { + if !IsLabelNameRuneAllowed(r) { + return newInvalidLabelNameRuneError(k, r) + } + } + if IsLabelNameReserved(k) { + return newErr(ErrLabelNameReserved, k) + } + + return nil +} + +// ValidateServiceName report an error if the given app name n violates constraints. +func ValidateServiceName(n string) error { + if len(n) == 0 { + return ErrServiceNameIsRequired + } + for _, r := range n { + if !IsServiceNameRuneAllowed(r) { + return NewInvalidServiceNameRuneError(n, r) + } + } + + return nil +} + +func IsLabelNameRuneAllowed(r rune) bool { + return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' || r == '.' +} + +func IsServiceNameRuneAllowed(r rune) bool { + return r == '-' || r == '.' || r == '/' || IsLabelNameRuneAllowed(r) +} + +func IsLabelNameReserved(k string) bool { + for _, s := range reservedLabelNames { + if s == k { + return true + } + } + + return false +} diff --git a/api/openapiv2/gen/phlare.swagger.json b/api/openapiv2/gen/phlare.swagger.json index 1162fbcc02..65323d18cf 100644 --- a/api/openapiv2/gen/phlare.swagger.json +++ b/api/openapiv2/gen/phlare.swagger.json @@ -8,15 +8,45 @@ { "name": "AdHocProfileService" }, + { + "name": "FeatureFlagsService" + }, + { + "name": "DebuginfoService" + }, { "name": "PusherService" }, { "name": "IngesterService" }, + { + "name": "CompactionService" + }, + { + "name": "IndexService" + }, + { + "name": "MetadataQueryService" + }, + { + "name": "TenantService" + }, { "name": "QuerierService" }, + { + "name": "QueryFrontendService" + }, + { + "name": "QueryBackendService" + }, + { + "name": "SegmentWriterService" + }, + { + "name": "RecordingRulesService" + }, { "name": "SettingsService" }, @@ -156,182 +186,6 @@ }, "description": "Message that represents an arbitrary HTTP body. It should only be used for\npayload formats that can't be represented as JSON, such as raw binary or\nan HTML page.\n\n\nThis message can be used both in streaming and non-streaming API methods in\nthe request as well as the response.\n\nIt can be used as a top-level request field, which is convenient if one\nwants to extract parameters from either the URL or HTTP template into the\nrequest fields and also want access to the raw HTTP body.\n\nExample:\n\n message GetResourceRequest {\n // A unique request id.\n string request_id = 1;\n\n // The raw HTTP body is bound to this field.\n google.api.HttpBody http_body = 2;\n\n }\n\n service ResourceService {\n rpc GetResource(GetResourceRequest)\n returns (google.api.HttpBody);\n rpc UpdateResource(google.api.HttpBody)\n returns (google.protobuf.Empty);\n\n }\n\nExample with streaming methods:\n\n service CaldavService {\n rpc GetCalendar(stream google.api.HttpBody)\n returns (stream google.api.HttpBody);\n rpc UpdateCalendar(stream google.api.HttpBody)\n returns (stream google.api.HttpBody);\n\n }\n\nUse of this type only changes how the request and response bodies are\nhandled, all other features will continue to work unchanged." }, - "googlev1Label": { - "type": "object", - "properties": { - "key": { - "type": "string", - "format": "int64", - "title": "Index into string table" - }, - "str": { - "type": "string", - "format": "int64", - "description": "Index into string table", - "title": "At most one of the following must be present" - }, - "num": { - "type": "string", - "format": "int64" - }, - "numUnit": { - "type": "string", - "format": "int64", - "description": "Should only be present when num is present.\nSpecifies the units of num.\nUse arbitrary string (for example, \"requests\") as a custom count unit.\nIf no unit is specified, consumer may apply heuristic to deduce the unit.\nConsumers may also interpret units like \"bytes\" and \"kilobytes\" as memory\nunits and units like \"seconds\" and \"nanoseconds\" as time units,\nand apply appropriate unit conversions to these.\n\nIndex into string table" - } - } - }, - "googlev1Location": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uint64", - "description": "Unique nonzero id for the location. A profile could use\ninstruction addresses or any integer sequence as ids." - }, - "mappingId": { - "type": "string", - "format": "uint64", - "description": "The id of the corresponding profile.Mapping for this location.\nIt can be unset if the mapping is unknown or not applicable for\nthis profile type." - }, - "address": { - "type": "string", - "format": "uint64", - "description": "The instruction address for this location, if available. It\nshould be within [Mapping.memory_start...Mapping.memory_limit]\nfor the corresponding mapping. A non-leaf address may be in the\nmiddle of a call instruction. It is up to display tools to find\nthe beginning of the instruction if necessary." - }, - "line": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Line" - }, - "description": "Multiple line indicates this location has inlined functions,\nwhere the last entry represents the caller into which the\npreceding entries were inlined.\n\nE.g., if memcpy() is inlined into printf:\n line[0].function_name == \"memcpy\"\n line[1].function_name == \"printf\"" - }, - "isFolded": { - "type": "boolean", - "description": "Provides an indication that multiple symbols map to this location's\naddress, for example due to identical code folding by the linker. In that\ncase the line information above represents one of the multiple\nsymbols. This field must be recomputed when the symbolization state of the\nprofile changes." - } - }, - "description": "Describes function and line table debug information." - }, - "googlev1Profile": { - "type": "object", - "properties": { - "sampleType": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ValueType" - }, - "description": "A description of the samples associated with each Sample.value.\nFor a cpu profile this might be:\n [[\"cpu\",\"nanoseconds\"]] or [[\"wall\",\"seconds\"]] or [[\"syscall\",\"count\"]]\nFor a heap profile, this might be:\n [[\"allocations\",\"count\"], [\"space\",\"bytes\"]],\nIf one of the values represents the number of events represented\nby the sample, by convention it should be at index 0 and use\nsample_type.unit == \"count\"." - }, - "sample": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Sample" - }, - "description": "The set of samples recorded in this profile." - }, - "mapping": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Mapping" - }, - "description": "Mapping from address ranges to the image/binary/library mapped\ninto that address range. mapping[0] will be the main binary." - }, - "location": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/googlev1Location" - }, - "title": "Useful program location" - }, - "function": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Function" - }, - "title": "Functions referenced by locations" - }, - "stringTable": { - "type": "array", - "items": { - "type": "string" - }, - "description": "A common table for strings referenced by various messages.\nstring_table[0] must always be \"\"." - }, - "dropFrames": { - "type": "string", - "format": "int64", - "description": "frames with Function.function_name fully matching the following\nregexp will be dropped from the samples, along with their successors.\n\nIndex into string table." - }, - "keepFrames": { - "type": "string", - "format": "int64", - "description": "frames with Function.function_name fully matching the following\nregexp will be kept, even if it matches drop_frames.\n\nIndex into string table." - }, - "timeNanos": { - "type": "string", - "format": "int64", - "description": "Time of collection (UTC) represented as nanoseconds past the epoch." - }, - "durationNanos": { - "type": "string", - "format": "int64", - "description": "Duration of the profile, if a duration makes sense." - }, - "periodType": { - "$ref": "#/definitions/v1ValueType", - "title": "The kind of events between sampled ocurrences.\ne.g [ \"cpu\",\"cycles\" ] or [ \"heap\",\"bytes\" ]" - }, - "period": { - "type": "string", - "format": "int64", - "description": "The number of events between sampled occurrences." - }, - "comment": { - "type": "array", - "items": { - "type": "string", - "format": "int64" - }, - "description": "Freeform text associated to the profile.\n\nIndices into string table." - }, - "defaultSampleType": { - "type": "string", - "format": "int64", - "description": "Index into the string table of the type of the preferred sample\nvalue. If unset, clients should default to the last sample value." - } - } - }, - "ingesterv1ProfileTypesResponse": { - "type": "object", - "properties": { - "profileTypes": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ProfileType" - } - } - } - }, - "ingesterv1SeriesResponse": { - "type": "object", - "properties": { - "labelsSet": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Labels" - } - } - } - }, "protobufAny": { "type": "object", "properties": { @@ -343,30 +197,6 @@ "additionalProperties": {}, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, - "querierv1ProfileTypesResponse": { - "type": "object", - "properties": { - "profileTypes": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ProfileType" - } - } - } - }, - "querierv1SeriesResponse": { - "type": "object", - "properties": { - "labelsSet": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Labels" - } - } - } - }, "rpcStatus": { "type": "object", "properties": { @@ -386,1127 +216,39 @@ } } }, - "typesv1Location": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - }, - "v1AdHocProfilesGetResponse": { + "v1GetBuildInfoData": { "type": "object", "properties": { - "id": { + "version": { "type": "string" }, - "name": { + "revision": { "type": "string" }, - "uploadedAt": { - "type": "string", - "format": "int64", - "title": "timestamp in milliseconds" - }, - "profileType": { + "branch": { "type": "string" }, - "profileTypes": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Some profiles formats (like pprof) can contain multiple profile (sample) types inside. One of these can be passed\nin the Get request using the profile_type field." - }, - "flamebearerProfile": { - "type": "string" - } - } - }, - "v1AdHocProfilesListResponse": { - "type": "object", - "properties": { - "profiles": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1AdHocProfilesProfileMetadata" - } - } - } - }, - "v1AdHocProfilesProfileMetadata": { - "type": "object", - "properties": { - "id": { + "buildUser": { "type": "string" }, - "name": { + "buildDate": { "type": "string" }, - "uploadedAt": { - "type": "string", - "format": "int64", - "title": "timestamp in milliseconds" - } - } - }, - "v1AnalyzeQueryResponse": { - "type": "object", - "properties": { - "queryScopes": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QueryScope" - }, - "title": "detailed view of what the query will require" - }, - "queryImpact": { - "$ref": "#/definitions/v1QueryImpact", - "title": "summary of the query impact / performance" - } - } - }, - "v1BlockCompaction": { - "type": "object", - "properties": { - "level": { - "type": "integer", - "format": "int32" - }, - "sources": { - "type": "array", - "items": { - "type": "string" - } - }, - "parents": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "v1BlockHints": { - "type": "object", - "properties": { - "ulids": { - "type": "array", - "items": { - "type": "string" - }, - "title": "The ULID of blocks to query" - }, - "deduplication": { - "type": "boolean", - "description": "When all blocks are compacted, there is no effect of the replication factor, hence we do not need to run deduplication." - } - } - }, - "v1BlockInfo": { - "type": "object", - "properties": { - "ulid": { + "goVersion": { "type": "string" - }, - "minTime": { - "type": "string", - "format": "int64" - }, - "maxTime": { - "type": "string", - "format": "int64" - }, - "compaction": { - "$ref": "#/definitions/v1BlockCompaction" - }, - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1LabelPair" - } - } - } - }, - "v1BlockMetadataResponse": { - "type": "object", - "properties": { - "blocks": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1BlockInfo" - }, - "title": "Blocks that are present on the instance for the start to end period" - } - } - }, - "v1BlockStats": { - "type": "object", - "properties": { - "seriesCount": { - "type": "string", - "format": "uint64" - }, - "profileCount": { - "type": "string", - "format": "uint64" - }, - "sampleCount": { - "type": "string", - "format": "uint64" - }, - "indexBytes": { - "type": "string", - "format": "uint64" - }, - "profileBytes": { - "type": "string", - "format": "uint64" - }, - "symbolBytes": { - "type": "string", - "format": "uint64" } } }, - "v1CommitAuthor": { + "v1GetBuildInfoResponse": { "type": "object", "properties": { - "login": { - "type": "string", - "title": "the author login" - }, - "avatarURL": { - "type": "string", - "title": "the author avatar URL" - } - } - }, - "v1DiffResponse": { - "type": "object", - "properties": { - "flamegraph": { - "$ref": "#/definitions/v1FlameGraphDiff" - } - } - }, - "v1FlameGraph": { - "type": "object", - "properties": { - "names": { - "type": "array", - "items": { - "type": "string" - } - }, - "levels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Level" - } - }, - "total": { - "type": "string", - "format": "int64" - }, - "maxSelf": { - "type": "string", - "format": "int64" - } - } - }, - "v1FlameGraphDiff": { - "type": "object", - "properties": { - "names": { - "type": "array", - "items": { - "type": "string" - } - }, - "levels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Level" - } - }, - "total": { - "type": "string", - "format": "int64" - }, - "maxSelf": { - "type": "string", - "format": "int64" - }, - "leftTicks": { - "type": "string", - "format": "int64" - }, - "rightTicks": { - "type": "string", - "format": "int64" - } - } - }, - "v1FlushResponse": { - "type": "object" - }, - "v1Function": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uint64", - "description": "Unique nonzero id for the function." - }, - "name": { - "type": "string", - "format": "int64", - "description": "Name of the function, in human-readable form if available.\n\nIndex into string table" - }, - "systemName": { - "type": "string", - "format": "int64", - "description": "Name of the function, as identified by the system.\nFor instance, it can be a C++ mangled name.\n\nIndex into string table" - }, - "filename": { - "type": "string", - "format": "int64", - "description": "Source file containing the function.\n\nIndex into string table" - }, - "startLine": { - "type": "string", - "format": "int64", - "description": "Line number in source file." - } - } - }, - "v1GetBlockStatsResponse": { - "type": "object", - "properties": { - "blockStats": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1BlockStats" - } - } - } - }, - "v1GetBuildInfoData": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "revision": { - "type": "string" - }, - "branch": { - "type": "string" - }, - "buildUser": { - "type": "string" - }, - "buildDate": { - "type": "string" - }, - "goVersion": { - "type": "string" - } - } - }, - "v1GetBuildInfoResponse": { - "type": "object", - "properties": { - "status": { - "type": "string" + "status": { + "type": "string" }, "data": { "$ref": "#/definitions/v1GetBuildInfoData" } } - }, - "v1GetCommitResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "title": "the commit message" - }, - "author": { - "$ref": "#/definitions/v1CommitAuthor", - "title": "the commit author login" - }, - "date": { - "type": "string", - "title": "the commit date" - }, - "sha": { - "type": "string", - "title": "the commit sha" - }, - "URL": { - "type": "string", - "title": "the full URL to the commit" - } - } - }, - "v1GetFileResponse": { - "type": "object", - "properties": { - "content": { - "type": "string", - "title": "base64 content of the file" - }, - "URL": { - "type": "string", - "title": "the full URL to the file" - } - } - }, - "v1GetProfileStatsResponse": { - "type": "object", - "properties": { - "dataIngested": { - "type": "boolean", - "description": "Whether we received any data at any time in the past." - }, - "oldestProfileTime": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - }, - "newestProfileTime": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - } - } - }, - "v1GetSettingsResponse": { - "type": "object", - "properties": { - "settings": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Setting" - } - } - } - }, - "v1GithubAppResponse": { - "type": "object", - "properties": { - "clientID": { - "type": "string" - } - } - }, - "v1GithubLoginResponse": { - "type": "object", - "properties": { - "cookie": { - "type": "string" - } - } - }, - "v1GithubRefreshResponse": { - "type": "object", - "properties": { - "cookie": { - "type": "string" - } - } - }, - "v1Hints": { - "type": "object", - "properties": { - "block": { - "$ref": "#/definitions/v1BlockHints" - } - }, - "title": "Hints are used to propagate information about querying" - }, - "v1LabelNamesResponse": { - "type": "object", - "properties": { - "names": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "v1LabelPair": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "v1LabelValuesResponse": { - "type": "object", - "properties": { - "names": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "v1Labels": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1LabelPair" - }, - "title": "LabelPair is the key value pairs to identify the corresponding profile" - } - } - }, - "v1Level": { - "type": "object", - "properties": { - "values": { - "type": "array", - "items": { - "type": "string", - "format": "int64" - } - } - } - }, - "v1Line": { - "type": "object", - "properties": { - "functionId": { - "type": "string", - "format": "uint64", - "description": "The id of the corresponding profile.Function for this line." - }, - "line": { - "type": "string", - "format": "int64", - "description": "Line number in source code." - } - } - }, - "v1Mapping": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uint64", - "description": "Unique nonzero id for the mapping." - }, - "memoryStart": { - "type": "string", - "format": "uint64", - "description": "Address at which the binary (or DLL) is loaded into memory." - }, - "memoryLimit": { - "type": "string", - "format": "uint64", - "description": "The limit of the address range occupied by this mapping." - }, - "fileOffset": { - "type": "string", - "format": "uint64", - "description": "Offset in the binary that corresponds to the first mapped address." - }, - "filename": { - "type": "string", - "format": "int64", - "description": "The object this entry is loaded from. This can be a filename on\ndisk for the main binary and shared libraries, or virtual\nabstractions like \"[vdso]\".\n\nIndex into string table" - }, - "buildId": { - "type": "string", - "format": "int64", - "description": "A string that uniquely identifies a particular program version\nwith high probability. E.g., for binaries generated by GNU tools,\nit could be the contents of the .note.gnu.build-id field.\n\nIndex into string table" - }, - "hasFunctions": { - "type": "boolean", - "description": "The following fields indicate the resolution of symbolic info." - }, - "hasFilenames": { - "type": "boolean" - }, - "hasLineNumbers": { - "type": "boolean" - }, - "hasInlineFrames": { - "type": "boolean" - } - } - }, - "v1MergeProfilesLabelsResponse": { - "type": "object", - "properties": { - "selectedProfiles": { - "$ref": "#/definitions/v1ProfileSets", - "description": "The server replies batch of profiles.\nA last message without profiles signals the next message will be the result of the merge." - }, - "series": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Series" - }, - "title": "The list of series for the profile with their respective value" - } - } - }, - "v1MergeProfilesPprofResponse": { - "type": "object", - "properties": { - "selectedProfiles": { - "$ref": "#/definitions/v1ProfileSets", - "description": "The server replies batch of profiles.\nA last message without profiles signals the next message will be the result of the merge." - }, - "result": { - "type": "string", - "format": "byte", - "description": "The merge result in the pprof format." - } - } - }, - "v1MergeProfilesStacktracesResponse": { - "type": "object", - "properties": { - "selectedProfiles": { - "$ref": "#/definitions/v1ProfileSets", - "description": "The server replies batch of profiles.\nA last message without profiles signals the next message will be the result of the merge." - }, - "result": { - "$ref": "#/definitions/v1MergeProfilesStacktracesResult", - "title": "The list of stracktraces for the profile with their respective value" - } - } - }, - "v1MergeProfilesStacktracesResult": { - "type": "object", - "properties": { - "format": { - "$ref": "#/definitions/v1StacktracesMergeFormat" - }, - "stacktraces": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1StacktraceSample" - }, - "title": "The list of stracktraces with their respective value" - }, - "functionNames": { - "type": "array", - "items": { - "type": "string" - } - }, - "treeBytes": { - "type": "string", - "format": "byte", - "description": "Merge result marshaled to pyroscope tree bytes." - } - } - }, - "v1MergeSpanProfileResponse": { - "type": "object", - "properties": { - "selectedProfiles": { - "$ref": "#/definitions/v1ProfileSets", - "description": "The server replies batch of profiles.\nA last message without profiles signals the next message will be the result of the merge." - }, - "result": { - "$ref": "#/definitions/v1MergeSpanProfileResult", - "title": "The list of stracktraces for the profile with their respective value" - } - } - }, - "v1MergeSpanProfileResult": { - "type": "object", - "properties": { - "treeBytes": { - "type": "string", - "format": "byte" - } - } - }, - "v1Point": { - "type": "object", - "properties": { - "value": { - "type": "number", - "format": "double" - }, - "timestamp": { - "type": "string", - "format": "int64", - "title": "Milliseconds unix timestamp" - } - } - }, - "v1ProfileFormat": { - "type": "string", - "enum": [ - "PROFILE_FORMAT_UNSPECIFIED", - "PROFILE_FORMAT_FLAMEGRAPH", - "PROFILE_FORMAT_TREE" - ], - "default": "PROFILE_FORMAT_UNSPECIFIED" - }, - "v1ProfileSets": { - "type": "object", - "properties": { - "labelsSets": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Labels" - }, - "description": "DEPRECATED: Use fingerprints instead." - }, - "profiles": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1SeriesProfile" - } - }, - "fingerprints": { - "type": "array", - "items": { - "type": "string", - "format": "uint64" - } - } - } - }, - "v1ProfileType": { - "type": "object", - "properties": { - "ID": { - "type": "string" - }, - "name": { - "type": "string" - }, - "sampleType": { - "type": "string" - }, - "sampleUnit": { - "type": "string" - }, - "periodType": { - "type": "string" - }, - "periodUnit": { - "type": "string" - } - } - }, - "v1PushResponse": { - "type": "object" - }, - "v1QueryImpact": { - "type": "object", - "properties": { - "totalBytesInTimeRange": { - "type": "string", - "format": "uint64" - }, - "totalQueriedSeries": { - "type": "string", - "format": "uint64" - }, - "deduplicationNeeded": { - "type": "boolean" - } - } - }, - "v1QueryScope": { - "type": "object", - "properties": { - "componentType": { - "type": "string", - "title": "a descriptive high level name of the component processing one part of the query (e.g., \"short term storage\")" - }, - "componentCount": { - "type": "string", - "format": "uint64", - "title": "how many components of this type will process the query (indicator of read-path replication)" - }, - "blockCount": { - "type": "string", - "format": "uint64" - }, - "seriesCount": { - "type": "string", - "format": "uint64" - }, - "profileCount": { - "type": "string", - "format": "uint64" - }, - "sampleCount": { - "type": "string", - "format": "uint64" - }, - "indexBytes": { - "type": "string", - "format": "uint64" - }, - "profileBytes": { - "type": "string", - "format": "uint64" - }, - "symbolBytes": { - "type": "string", - "format": "uint64" - } - } - }, - "v1RawProfileSeries": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1LabelPair" - }, - "title": "LabelPair is the key value pairs to identify the corresponding profile" - }, - "samples": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1RawSample" - }, - "title": "samples are the set of profile bytes" - } - }, - "title": "RawProfileSeries represents the pprof profile and its associated labels" - }, - "v1RawSample": { - "type": "object", - "properties": { - "rawProfile": { - "type": "string", - "format": "byte", - "title": "raw_profile is the set of bytes of the pprof profile" - }, - "ID": { - "type": "string", - "title": "unique ID of the profile" - } - }, - "title": "RawSample is the set of bytes that correspond to a pprof profile" - }, - "v1Sample": { - "type": "object", - "properties": { - "locationId": { - "type": "array", - "items": { - "type": "string", - "format": "uint64" - }, - "description": "The ids recorded here correspond to a Profile.location.id.\nThe leaf is at location_id[0]." - }, - "value": { - "type": "array", - "items": { - "type": "string", - "format": "int64" - }, - "description": "The type and unit of each value is defined by the corresponding\nentry in Profile.sample_type. All samples must have the same\nnumber of values, the same as the length of Profile.sample_type.\nWhen aggregating multiple samples into a single sample, the\nresult has a list of values that is the element-wise sum of the\nlists of the originals." - }, - "label": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/googlev1Label" - }, - "title": "label includes additional context for this sample. It can include\nthings like a thread id, allocation size, etc" - } - }, - "description": "Each Sample records values encountered in some program\ncontext. The program context is typically a stack trace, perhaps\naugmented with auxiliary information like the thread-id, some\nindicator of a higher level request being handled etc." - }, - "v1SelectMergeSpanProfileResponse": { - "type": "object", - "properties": { - "flamegraph": { - "$ref": "#/definitions/v1FlameGraph" - }, - "tree": { - "type": "string", - "format": "byte", - "description": "Pyroscope tree bytes." - } - } - }, - "v1SelectMergeStacktracesRequest": { - "type": "object", - "properties": { - "profileTypeID": { - "type": "string" - }, - "labelSelector": { - "type": "string" - }, - "start": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - }, - "end": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - }, - "maxNodes": { - "type": "string", - "format": "int64", - "title": "Limit the nodes returned to only show the node with the max_node's biggest total" - }, - "format": { - "$ref": "#/definitions/v1ProfileFormat", - "description": "Profile format specifies the format of profile to be returned.\nIf not specified, the profile will be returned in flame graph format." - } - } - }, - "v1SelectMergeStacktracesResponse": { - "type": "object", - "properties": { - "flamegraph": { - "$ref": "#/definitions/v1FlameGraph" - }, - "tree": { - "type": "string", - "format": "byte", - "description": "Pyroscope tree bytes." - } - } - }, - "v1SelectProfilesRequest": { - "type": "object", - "properties": { - "labelSelector": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/v1ProfileType" - }, - "start": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - }, - "end": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - }, - "hints": { - "$ref": "#/definitions/v1Hints", - "title": "Optional: Hints for querying" - }, - "aggregation": { - "$ref": "#/definitions/v1TimeSeriesAggregationType", - "title": "Optional: Aggregation" - } - } - }, - "v1SelectSeriesResponse": { - "type": "object", - "properties": { - "series": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Series" - } - } - } - }, - "v1SelectSpanProfileRequest": { - "type": "object", - "properties": { - "labelSelector": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/v1ProfileType" - }, - "start": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - }, - "end": { - "type": "string", - "format": "int64", - "description": "Milliseconds since epoch." - }, - "spanSelector": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of span identifiers." - }, - "hints": { - "$ref": "#/definitions/v1Hints", - "title": "Optional: Hints for querying" - } - } - }, - "v1Series": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1LabelPair" - } - }, - "points": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Point" - } - } - } - }, - "v1SeriesProfile": { - "type": "object", - "properties": { - "labelIndex": { - "type": "integer", - "format": "int32", - "title": "The labels index of the series" - }, - "timestamp": { - "type": "string", - "format": "int64", - "title": "timestamp in milliseconds" - } - } - }, - "v1SetSettingsResponse": { - "type": "object", - "properties": { - "setting": { - "$ref": "#/definitions/v1Setting" - } - } - }, - "v1Setting": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - }, - "modifiedAt": { - "type": "string", - "format": "int64" - } - } - }, - "v1StackTraceSelector": { - "type": "object", - "properties": { - "callSite": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/typesv1Location" - }, - "description": "Stack trace of the call site. Root at call_site[0].\nOnly stack traces having the prefix provided will be selected.\nIf empty, the filter is ignored." - } - }, - "description": "StackTraceSelector is used for filtering stack traces by locations." - }, - "v1StacktraceSample": { - "type": "object", - "properties": { - "functionIds": { - "type": "array", - "items": { - "type": "integer", - "format": "int32" - } - }, - "value": { - "type": "string", - "format": "int64" - } - } - }, - "v1StacktracesMergeFormat": { - "type": "string", - "enum": [ - "MERGE_FORMAT_UNSPECIFIED", - "MERGE_FORMAT_STACKTRACES", - "MERGE_FORMAT_TREE" - ], - "default": "MERGE_FORMAT_UNSPECIFIED" - }, - "v1TimeSeriesAggregationType": { - "type": "string", - "enum": [ - "TIME_SERIES_AGGREGATION_TYPE_SUM", - "TIME_SERIES_AGGREGATION_TYPE_AVERAGE" - ], - "default": "TIME_SERIES_AGGREGATION_TYPE_SUM" - }, - "v1ValueType": { - "type": "object", - "properties": { - "type": { - "type": "string", - "format": "int64", - "description": "Index into string table." - }, - "unit": { - "type": "string", - "format": "int64", - "description": "Index into string table." - } - }, - "description": "ValueType describes the semantics and measurement units of a value." - }, - "v1VersionResponse": { - "type": "object", - "properties": { - "QuerierAPI": { - "type": "string", - "format": "uint64" - } - } } } } diff --git a/api/push/v1/push.proto b/api/push/v1/push.proto index a7cb99207c..5d9e28f869 100644 --- a/api/push/v1/push.proto +++ b/api/push/v1/push.proto @@ -1,11 +1,15 @@ syntax = "proto3"; +// This is the API to send profiles to Pyroscope package push.v1; +import "gnostic/openapi/v3/annotations.proto"; import "types/v1/types.proto"; service PusherService { - rpc Push(PushRequest) returns (PushResponse) {} + rpc Push(PushRequest) returns (PushResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } } message PushResponse {} @@ -23,12 +27,22 @@ message RawProfileSeries { // samples are the set of profile bytes repeated RawSample samples = 2; + + // Annotations provide additional metadata for a profile. + // + // The main differences between labels and annotations are: + // - annotations cannot be used in query selectors + // - annotation keys don't have to be unique + // + // Currently annotations are applied internally by distributors, + // any annotation passed via the push API will be dropped. + repeated types.v1.ProfileAnnotation annotations = 3; } // RawSample is the set of bytes that correspond to a pprof profile message RawSample { // raw_profile is the set of bytes of the pprof profile - bytes raw_profile = 1; - // unique ID of the profile - string ID = 2; + bytes raw_profile = 1 [(gnostic.openapi.v3.property).example = {yaml: "PROFILE_BASE64"}]; + // UUID of the profile + string ID = 2 [(gnostic.openapi.v3.property).example = {yaml: "734FD599-6865-419E-9475-932762D8F469"}]; } diff --git a/api/querier/v1/querier.proto b/api/querier/v1/querier.proto index 78ae0da066..80e04ab11f 100644 --- a/api/querier/v1/querier.proto +++ b/api/querier/v1/querier.proto @@ -1,43 +1,87 @@ syntax = "proto3"; +// Provides the ability to query the Pyroscope database. Most of the calls in +// this group are considered public. package querier.v1; +import "gnostic/openapi/v3/annotations.proto"; import "google/v1/profile.proto"; import "types/v1/types.proto"; service QuerierService { // ProfileType returns a list of the existing profile types. - rpc ProfileTypes(ProfileTypesRequest) returns (ProfileTypesResponse) {} + rpc ProfileTypes(ProfileTypesRequest) returns (ProfileTypesResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } // LabelValues returns the existing label values for the provided label names. - rpc LabelValues(types.v1.LabelValuesRequest) returns (types.v1.LabelValuesResponse) {} + rpc LabelValues(types.v1.LabelValuesRequest) returns (types.v1.LabelValuesResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } // LabelNames returns a list of the existing label names. - rpc LabelNames(types.v1.LabelNamesRequest) returns (types.v1.LabelNamesResponse) {} - // Series returns profiles series matching the request. A series is a unique label set. - rpc Series(SeriesRequest) returns (SeriesResponse) {} - // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. - rpc SelectMergeStacktraces(SelectMergeStacktracesRequest) returns (SelectMergeStacktracesResponse) {} - // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph format. It will combine samples from within the same callstack, with each element being grouped by its function name. - rpc SelectMergeSpanProfile(SelectMergeSpanProfileRequest) returns (SelectMergeSpanProfileResponse) {} - // SelectMergeProfile returns matching profiles aggregated in pprof format. It will contain all information stored (so including filenames and line number, if ingested). - rpc SelectMergeProfile(SelectMergeProfileRequest) returns (google.v1.Profile) {} - // SelectSeries returns a time series for the total sum of the requested profiles. - rpc SelectSeries(SelectSeriesRequest) returns (SelectSeriesResponse) {} + rpc LabelNames(types.v1.LabelNamesRequest) returns (types.v1.LabelNamesResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } + // Series returns profiles series matching the request. A series is a unique + // label set. + rpc Series(SeriesRequest) returns (SeriesResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } + // SelectMergeStacktraces returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. + rpc SelectMergeStacktraces(SelectMergeStacktracesRequest) returns (SelectMergeStacktracesResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } + // Deprecated: Use SelectMergeStacktraces with span_selector instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph + // format. It will combine samples from within the same callstack, with each + // element being grouped by its function name. + rpc SelectMergeSpanProfile(SelectMergeSpanProfileRequest) returns (SelectMergeSpanProfileResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } + // Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. + // This RPC will remain supported in querier.v1 for backward compatibility; + // future breaking API changes may be introduced in querier.v2. + // SelectMergeProfile returns matching profiles aggregated in pprof format. It + // will contain all information stored (so including filenames and line + // number, if ingested). + rpc SelectMergeProfile(SelectMergeProfileRequest) returns (google.v1.Profile) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } + // SelectSeries returns a time series for the total sum of the requested + // profiles. + rpc SelectSeries(SelectSeriesRequest) returns (SelectSeriesResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } + // SelectHeatmap returns a heatmap visualization for the requested profiles. + // Note: This endpoint is only available in the v2 storage layer + rpc SelectHeatmap(SelectHeatmapRequest) returns (SelectHeatmapResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } // Diff returns a diff of two profiles - rpc Diff(DiffRequest) returns (DiffResponse) {} + rpc Diff(DiffRequest) returns (DiffResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/public"; + } // GetProfileStats returns profile stats for the current tenant. - rpc GetProfileStats(types.v1.GetProfileStatsRequest) returns (types.v1.GetProfileStatsResponse) {} - rpc AnalyzeQuery(AnalyzeQueryRequest) returns (AnalyzeQueryResponse) {} + rpc GetProfileStats(types.v1.GetProfileStatsRequest) returns (types.v1.GetProfileStatsResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/internal"; + } + rpc AnalyzeQuery(AnalyzeQueryRequest) returns (AnalyzeQueryResponse) { + option (gnostic.openapi.v3.operation).tags = "scope/internal"; + } } message ProfileTypesRequest { // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. - int64 start = 1; + int64 start = 1 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. - int64 end = 2; + int64 end = 2 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; } message ProfileTypesResponse { @@ -45,14 +89,16 @@ message ProfileTypesResponse { } message SeriesRequest { - repeated string matchers = 1; + // List of label selector to apply to the result. + repeated string matchers = 1 [(gnostic.openapi.v3.property).example = {yaml: "['{namespace=\"my-namespace\"}']"}]; + // List of label_names to request. If empty will return all label names in the + // result. repeated string label_names = 2; // Milliseconds since epoch. If missing or zero, only the ingesters will be // queried. - int64 start = 3; - // Milliseconds since epoch. If missing or zero, only the ingesters will be + int64 start = 3 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; // queried. - int64 end = 4; + int64 end = 4 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; } message SeriesResponse { @@ -60,40 +106,115 @@ message SeriesResponse { } message SelectMergeStacktracesRequest { - string profile_typeID = 1; - string label_selector = 2; + // Profile Type ID string in the form + // ::::. + string profile_typeID = 1 [(gnostic.openapi.v3.property).example = {yaml: "process_cpu:cpu:nanoseconds:cpu:nanoseconds"}]; + // Label selector string + string label_selector = 2 [(gnostic.openapi.v3.property).example = {yaml: "'{namespace=\"my-namespace\"}'"}]; // Milliseconds since epoch. - int64 start = 3; + int64 start = 3 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; // Milliseconds since epoch. - int64 end = 4; - // Limit the nodes returned to only show the node with the max_node's biggest total + int64 end = 4 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; + // Limit the nodes returned to only show the node with the max_node's biggest + // total optional int64 max_nodes = 5; // Profile format specifies the format of profile to be returned. // If not specified, the profile will be returned in flame graph format. ProfileFormat format = 6; + // Select stack traces that match the provided selector. + optional types.v1.StackTraceSelector stack_trace_selector = 7; + // List of Profile UUIDs to query + repeated string profile_id_selector = 8 [(gnostic.openapi.v3.property).example = {yaml: "['7c9e6679-7425-40de-944b-e07fc1f90ae7']"}]; + // (experimental) Used for making and polling async queries. + optional AsyncQueryRequest async = 9; + // List of trace IDs (32 hex characters, 128-bit) to filter samples by. + repeated string trace_id_selector = 10 [(gnostic.openapi.v3.property).example = {yaml: "['7c9e66797425440de944be07fc1f90ae']"}]; + // List of span IDs (16 hex characters, 64-bit) to filter samples by. + repeated string span_selector = 11 [(gnostic.openapi.v3.property).example = {yaml: "['9a517183f26a089d','5a4fe264a9c987fe']"}]; } enum ProfileFormat { + // Equivalent to PROFILE_FORMAT_FLAMEGRAPH. Preserved for backward + // compatibility. PROFILE_FORMAT_UNSPECIFIED = 0; + // Return a Flamebearer-compatible, single-profile flame graph. Samples + // sharing the same function-name call stack are aggregated into the names + // and levels representation used by the Pyroscope flame graph renderer. + // Format: https://github.com/grafana/pyroscope/blob/main/pkg/og/structs/flamebearer/flamebearer.go PROFILE_FORMAT_FLAMEGRAPH = 1; + // Return a compact, function-name-only Pyroscope tree serialization in + // SelectMergeStacktracesResponse.tree. PROFILE_FORMAT_TREE = 2; + // Return a Graphviz DOT directed graph. Nodes represent functions and edges + // represent caller-callee relationships, annotated with aggregated sample + // values. The resulting text can be rendered by Graphviz-compatible tools. + PROFILE_FORMAT_DOT = 3; + // Return a pprof profile, including available mappings, locations, filenames, + // and line numbers, in SelectMergeStacktracesResponse.pprof. + PROFILE_FORMAT_PPROF = 4; } message SelectMergeStacktracesResponse { FlameGraph flamegraph = 1; // Pyroscope tree bytes. bytes tree = 2; + // DOT graph representation. + string dot = 3; + // (experimental) Used for responding to async queries. + optional AsyncQueryResponse async = 4; + // Profile in pprof format. + PprofProfile pprof = 5; +} + +// PprofProfile contains pprof output and related response metadata. +message PprofProfile { + google.v1.Profile profile = 1; +} + +message AsyncQueryRequest { + // If set, this is a polling request. + string request_id = 1; + // Sets the kind of async query. + AsyncQueryType type = 2; +} + +message AsyncQueryResponse { + // Id of the async query. + string request_id = 1; + // Status of the query: unknown, in_progress, success, failed + AsyncQueryStatus status = 2; + // Populated on FAILURE. + string error_message = 3; +} + +enum AsyncQueryType { + // The query should not be async. + ASYNC_QUERY_TYPE_DISABLED = 0; + // The query must be async. + ASYNC_QUERY_TYPE_FORCE = 1; +} + +enum AsyncQueryStatus { + ASYNC_QUERY_STATUS_UNKNOWN = 0; + ASYNC_QUERY_STATUS_IN_PROGRESS = 1; + ASYNC_QUERY_STATUS_SUCCESS = 2; + ASYNC_QUERY_STATUS_FAILURE = 3; } message SelectMergeSpanProfileRequest { - string profile_typeID = 1; - string label_selector = 2; - repeated string span_selector = 3; + // Profile Type ID string in the form + // ::::. + string profile_typeID = 1 [(gnostic.openapi.v3.property).example = {yaml: "process_cpu:cpu:nanoseconds:cpu:nanoseconds"}]; + // Label selector string + string label_selector = 2 [(gnostic.openapi.v3.property).example = {yaml: "'{namespace=\"my-namespace\"}'"}]; + // List of Span IDs to query + repeated string span_selector = 3 [(gnostic.openapi.v3.property).example = {yaml: "['9a517183f26a089d','5a4fe264a9c987fe']"}]; // Milliseconds since epoch. - int64 start = 4; + int64 start = 4 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; // Milliseconds since epoch. - int64 end = 5; - // Limit the nodes returned to only show the node with the max_node's biggest total + int64 end = 5 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; + // Limit the nodes returned to only show the node with the max_node's biggest + // total optional int64 max_nodes = 6; // Profile format specifies the format of profile to be returned. // If not specified, the profile will be returned in flame graph format. @@ -107,6 +228,7 @@ message SelectMergeSpanProfileResponse { } message DiffRequest { + // The format of each request is ignored; diff queries always compare trees. SelectMergeStacktracesRequest left = 1; SelectMergeStacktracesRequest right = 2; } @@ -137,37 +259,84 @@ message Level { } message SelectMergeProfileRequest { - string profile_typeID = 1; - string label_selector = 2; + // Profile Type ID string in the form + // ::::. + string profile_typeID = 1 [(gnostic.openapi.v3.property).example = {yaml: "process_cpu:cpu:nanoseconds:cpu:nanoseconds"}]; + // Label selector string + string label_selector = 2 [(gnostic.openapi.v3.property).example = {yaml: "'{namespace=\"my-namespace\"}'"}]; // Milliseconds since epoch. - int64 start = 3; + int64 start = 3 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; // Milliseconds since epoch. - int64 end = 4; - // Limit the nodes returned to only show the node with the max_node's biggest total + int64 end = 4 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; + // Limit the nodes returned to only show the node with the max_node's biggest + // total optional int64 max_nodes = 5; // Select stack traces that match the provided selector. optional types.v1.StackTraceSelector stack_trace_selector = 6; + // List of Profile UUIDs to query + repeated string profile_id_selector = 7 [(gnostic.openapi.v3.property).example = {yaml: "['7c9e6679-7425-40de-944b-e07fc1f90ae7']"}]; + // List of trace IDs (32 hex characters, 128-bit) to filter samples by. + repeated string trace_id_selector = 8 [(gnostic.openapi.v3.property).example = {yaml: "['7c9e66797425440de944be07fc1f90ae']"}]; } message SelectSeriesRequest { - string profile_typeID = 1; - string label_selector = 2; + // Profile Type ID string in the form + // ::::. + string profile_typeID = 1 [(gnostic.openapi.v3.property).example = {yaml: "process_cpu:cpu:nanoseconds:cpu:nanoseconds"}]; + // Label selector string + string label_selector = 2 [(gnostic.openapi.v3.property).example = {yaml: "'{namespace=\"my-namespace\"}'"}]; // Milliseconds since epoch. - int64 start = 3; + int64 start = 3 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; // Milliseconds since epoch. - int64 end = 4; - repeated string group_by = 5; + int64 end = 4 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; + repeated string group_by = 5 [(gnostic.openapi.v3.property).example = {yaml: "['pod']"}]; double step = 6; // Query resolution step width in seconds optional types.v1.TimeSeriesAggregationType aggregation = 7; // Select stack traces that match the provided selector. optional types.v1.StackTraceSelector stack_trace_selector = 8; + // Select the top N series by total value. + optional int64 limit = 9; + // Type of exemplars to include in the response. + types.v1.ExemplarType exemplar_type = 10; } message SelectSeriesResponse { repeated types.v1.Series series = 1; } +enum HeatmapQueryType { + HEATMAP_QUERY_TYPE_UNSPECIFIED = 0; + HEATMAP_QUERY_TYPE_INDIVIDUAL = 1; + HEATMAP_QUERY_TYPE_SPAN = 2; +} + +message SelectHeatmapRequest { + // Profile Type ID string in the form + // ::::. + string profile_typeID = 1 [(gnostic.openapi.v3.property).example = {yaml: "process_cpu:cpu:nanoseconds:cpu:nanoseconds"}]; + // Label selector string + string label_selector = 2 [(gnostic.openapi.v3.property).example = {yaml: "'{namespace=\"my-namespace\"}'"}]; + // Milliseconds since epoch. + int64 start = 3 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; + // Milliseconds since epoch. + int64 end = 4 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; + // Query resolution step width in seconds + double step = 5; + // Group by labels + repeated string group_by = 6 [(gnostic.openapi.v3.property).example = {yaml: "['pod']"}]; + // Query type: individual profiles or span profiles + HeatmapQueryType query_type = 7 [(gnostic.openapi.v3.property).example = {yaml: "'HEATMAP_QUERY_TYPE_SPAN'"}]; + // Type of exemplars to include in the response. Needs to matching query_type or be NONE + types.v1.ExemplarType exemplar_type = 8 [(gnostic.openapi.v3.property).example = {yaml: "'EXEMPLAR_TYPE_SPAN'"}]; + // Select the top N series by total value. + optional int64 limit = 9; +} + +message SelectHeatmapResponse { + repeated types.v1.HeatmapSeries series = 1; +} + message AnalyzeQueryRequest { int64 start = 2; int64 end = 3; @@ -180,8 +349,10 @@ message AnalyzeQueryResponse { } message QueryScope { - string component_type = 1; // a descriptive high level name of the component processing one part of the query (e.g., "short term storage") - uint64 component_count = 2; // how many components of this type will process the query (indicator of read-path replication) + string component_type = 1; // a descriptive high level name of the component processing one part + // of the query (e.g., "short term storage") + uint64 component_count = 2; // how many components of this type will process + // the query (indicator of read-path replication) uint64 block_count = 3; uint64 series_count = 4; diff --git a/api/query/v1/query.proto b/api/query/v1/query.proto new file mode 100644 index 0000000000..7489332db5 --- /dev/null +++ b/api/query/v1/query.proto @@ -0,0 +1,363 @@ +syntax = "proto3"; + +package query.v1; + +import "google/v1/profile.proto"; +import "metastore/v1/types.proto"; +import "querier/v1/querier.proto"; +import "types/v1/types.proto"; + +// QueryFrontendService is supposed to handle both access to the time series +// profiling data through the QueryBackendService and metadata queries through +// the MetastoreService. Example metadata queries: listing datasets (services) +// and their available profile types, accessing tenant statistics, analyzing +// the queries, etc. However, metadata queries should not be mixed with the +// time series profiling queries, therefore the API is to be extended. +// +// QueryFrontendService is supposed to be a public interface, available to +// the external clients, while QueryBackendService and MetastoreService are +// supposed to be private, accessed through the QueryFrontendService. + +service QueryFrontendService { + rpc Query(QueryRequest) returns (QueryResponse) {} +} + +message QueryRequest { + int64 start_time = 1; + int64 end_time = 2; + string label_selector = 3; + repeated Query query = 4; +} + +message QueryResponse { + repeated Report reports = 1; +} + +service QueryBackendService { + rpc Invoke(InvokeRequest) returns (InvokeResponse) {} +} + +message InvokeOptions { + // Query workers might not have access to the tenant + // overrides, therefore all the necessary options should + // be listed in the request explicitly. + bool sanitize_on_merge = 1; + bool collect_diagnostics = 2; +} + +message InvokeRequest { + repeated string tenant = 1; + int64 start_time = 2; + int64 end_time = 3; + string label_selector = 4; + repeated Query query = 5; + QueryPlan query_plan = 6; + InvokeOptions options = 7; +} + +// A query plan is represented by a directed acyclic graph (DAG), +// where each node is either a "merge" node or a "read" node. +// +// Merge nodes reference other nodes in the plan as their "children". +// Read nodes reference the blocks which contain the actual data to be processed. +message QueryPlan { + QueryNode root = 1; +} + +message QueryNode { + Type type = 1; + repeated QueryNode children = 2; + repeated metastore.v1.BlockMeta blocks = 3; + + enum Type { + UNKNOWN = 0; + MERGE = 1; + READ = 2; + } +} + +message Query { + QueryType query_type = 1; + // Exactly one of the following fields should be set, + // depending on the query type. + LabelNamesQuery label_names = 2; + LabelValuesQuery label_values = 3; + SeriesLabelsQuery series_labels = 4; + TimeSeriesQuery time_series = 5; + TreeQuery tree = 6; + PprofQuery pprof = 7; + HeatmapQuery heatmap = 8; + TimeSeriesQuery time_series_compact = 9; + // function_details + // call_graph + // top_table + // ... +} + +enum QueryType { + QUERY_UNSPECIFIED = 0; + QUERY_LABEL_NAMES = 1; + QUERY_LABEL_VALUES = 2; + QUERY_SERIES_LABELS = 3; + QUERY_TIME_SERIES = 4; + QUERY_TREE = 5; + QUERY_PPROF = 6; + QUERY_HEATMAP = 7; + QUERY_TIME_SERIES_COMPACT = 8; +} + +message InvokeResponse { + repeated Report reports = 1; + Diagnostics diagnostics = 2; +} + +// Diagnostic messages, events, statistics, analytics, etc. +message Diagnostics { + QueryPlan query_plan = 1; + ExecutionNode execution_node = 2; +} + +// ExecutionNode captures how a query plan node was actually executed. +message ExecutionNode { + QueryNode.Type type = 1; + string executor = 2; + int64 start_time_ns = 3; + int64 end_time_ns = 4; + repeated ExecutionNode children = 5; + ExecutionStats stats = 6; + string error = 7; +} + +// ExecutionStats captures statistics for READ node execution. +message ExecutionStats { + int64 blocks_read = 1; + int64 datasets_processed = 2; + repeated BlockExecution block_executions = 3; + // bytes_fetched is the total number of bytes requested from object storage + // during this invocation. It counts only the bytes from this single, + // successful Invoke call: retried or hedged calls that did not produce a + // response are not included, so the value is deterministic across retries. + uint64 bytes_fetched = 4; +} + +// BlockExecution captures execution details for a single block. +message BlockExecution { + string block_id = 1; + int64 start_time_ns = 2; + int64 end_time_ns = 3; + int64 datasets_processed = 4; + uint64 size = 5; + uint32 shard = 6; + uint32 compaction_level = 7; +} + +message Report { + ReportType report_type = 1; + // Exactly one of the following fields should be set, + // depending on the report type. + LabelNamesReport label_names = 2; + LabelValuesReport label_values = 3; + SeriesLabelsReport series_labels = 4; + TimeSeriesReport time_series = 5; + TreeReport tree = 6; + PprofReport pprof = 7; + HeatmapReport heatmap = 8; + TimeSeriesCompactReport time_series_compact = 9; +} + +enum ReportType { + REPORT_UNSPECIFIED = 0; + REPORT_LABEL_NAMES = 1; + REPORT_LABEL_VALUES = 2; + REPORT_SERIES_LABELS = 3; + REPORT_TIME_SERIES = 4; + REPORT_TREE = 5; + REPORT_PPROF = 6; + REPORT_HEATMAP = 7; + REPORT_TIME_SERIES_COMPACT = 8; +} + +message LabelNamesQuery {} + +message LabelNamesReport { + LabelNamesQuery query = 1; + repeated string label_names = 2; +} + +message LabelValuesQuery { + string label_name = 1; +} + +message LabelValuesReport { + LabelValuesQuery query = 1; + repeated string label_values = 2; +} + +message SeriesLabelsQuery { + repeated string label_names = 1; +} + +message SeriesLabelsReport { + SeriesLabelsQuery query = 1; + repeated types.v1.Labels series_labels = 2; +} + +message TimeSeriesQuery { + double step = 1; + repeated string group_by = 2; + int64 limit = 3; + types.v1.ExemplarType exemplar_type = 4; +} + +message TimeSeriesReport { + TimeSeriesQuery query = 1; + repeated types.v1.Series time_series = 2; +} + +// SymbolMode selects how a TreeQuery reports frame symbols. +enum SymbolMode { + SYMBOL_MODE_UNSPECIFIED = 0; + SYMBOL_MODE_NAME = 1; // frame names only + SYMBOL_MODE_FULL = 2; // full pprof symbol tables alongside the tree + SYMBOL_MODE_REFS = 3; // compact symbol-ref side table for deferred resolution +} + +message TreeQuery { + int64 max_nodes = 1; + repeated string span_selector = 2; + optional types.v1.StackTraceSelector stack_trace_selector = 3; + repeated string profile_id_selector = 4; + // Deprecated: use symbol_mode = SYMBOL_MODE_FULL. Retained for wire + // compatibility; will be removed in a couple of releases. + bool full_symbols = 5; + repeated string trace_id_selector = 6; + // symbol_mode selects the symbol output. When unset, full_symbols is honored + // for back-compat. + SymbolMode symbol_mode = 7; + // max_unresolved_locations bounds the distinct unresolved locations a + // symbol-ref tree result may carry; the query fails past it. Zero means + // unlimited. Effective only with SYMBOL_MODE_REFS. + int64 max_unresolved_locations = 8; +} + +message TreeSymbols { + repeated google.v1.Mapping mappings = 1; + repeated google.v1.Location locations = 2; + repeated google.v1.Function functions = 3; + repeated string strings = 4; + repeated uint64 mapping_hashes = 5; + repeated uint64 location_hashes = 6; + repeated uint64 function_hashes = 7; + repeated uint64 string_hashes = 8; +} + +// SymbolRefTable resolves the integer frame references in a symbol-ref tree. +// Each tree node stores one frame reference r; whether r is resolved depends on +// whether it falls inside the names slice: +// +// r < len(names): resolved -> names[r] is the frame name. +// r >= len(names): unresolved -> u = r - len(names) indexes the parallel +// unresolved_* arrays: +// build_ids[unresolved_build_id[u]] build ID of the binary +// unresolved_address[u] address within it +// +// build_ids and binary_names are parallel and 1:1 (binary_names[k] is the +// "binary!0xaddr" fallback display for build_ids[k]); each (build ID, +// binary name) pair appears once — the same build ID may repeat under +// different binary names, each retained exactly as stored. +// unresolved_build_id and unresolved_address are parallel, one entry per +// unresolved location, sorted by (build ID, binary name, address). +message SymbolRefTable { + repeated string names = 1; + repeated string build_ids = 2; + repeated string binary_names = 3; + repeated uint32 unresolved_build_id = 4; + repeated uint64 unresolved_address = 5; +} + +message TreeReport { + TreeQuery query = 1; + bytes tree = 2; + optional TreeSymbols symbols = 3; + optional SymbolRefTable symbol_refs = 4; +} + +message PprofQuery { + int64 max_nodes = 1; + optional types.v1.StackTraceSelector stack_trace_selector = 2; + repeated string profile_id_selector = 3; + repeated string span_selector = 4; + repeated string trace_id_selector = 5; + // TODO(kolesnikovae): Go PGO options. +} + +message PprofReport { + PprofQuery query = 1; + bytes pprof = 2; +} + +message HeatmapQuery { + double step = 1; + repeated string group_by = 2; + querier.v1.HeatmapQueryType query_type = 3; + int64 limit = 4; + types.v1.ExemplarType exemplar_type = 5; +} + +message AttributeTable { + repeated string keys = 1; + repeated string values = 2; +} + +message HeatmapPoint { + int64 timestamp = 1; // Milliseconds since epoch when the profile was captured. + int64 profile_id = 2; // Unique identifier for the profile (UUID), reference into AttributeTable with only value set + uint64 span_id = 3; // Span ID if this profile was split by span during ingestion + int64 value = 4; // Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + repeated int64 attribute_refs = 5; // labels as references into AttributeTable + bytes trace_id = 6; // Trace ID associated with the span, if present. +} + +message HeatmapSeries { + repeated int64 attribute_refs = 1; + repeated HeatmapPoint points = 2; // Points are timestamp, then span_id, then porfile_id ordered +} + +message HeatmapReport { + HeatmapQuery query = 1; + repeated HeatmapSeries heatmap_series = 2; + AttributeTable attribute_table = 3; +} + +message Exemplar { + // Milliseconds unix timestamp + int64 timestamp = 1; + string profile_id = 2; + string span_id = 3; + int64 value = 4; + repeated int64 attribute_refs = 5; +} + +message Point { + double value = 1; + // Milliseconds unix timestamp + int64 timestamp = 2; + // Annotations as references into AttributeTable + repeated int64 annotation_refs = 5; + // Exemplars are samples of individual profiles that contributed to this aggregated point + repeated Exemplar exemplars = 4; +} + +// Series represents a time series with optimized label storage using attribute references. +message Series { + // References to label key-value pairs in the AttributeTable that identify this series. + repeated int64 attribute_refs = 1; + // Time series data points. Each point may contain exemplars with their own attribute_refs. + repeated Point points = 2; +} + +message TimeSeriesCompactReport { + TimeSeriesQuery query = 1; + repeated Series time_series = 2; + AttributeTable attribute_table = 3; +} diff --git a/api/segmentwriter/v1/push.proto b/api/segmentwriter/v1/push.proto new file mode 100644 index 0000000000..146d055c3b --- /dev/null +++ b/api/segmentwriter/v1/push.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package segmentwriter.v1; + +import "types/v1/types.proto"; + +service SegmentWriterService { + rpc Push(PushRequest) returns (PushResponse) {} +} + +message PushResponse {} + +message PushRequest { + // Unique identifier for the tenant submitting the request. + string tenant_id = 1; + // Label KV pairs of the series the profile belongs to. + repeated types.v1.LabelPair labels = 2; + reserved 3; // Reserved for format. + // Profile data in binary format. Default format is pprof. + bytes profile = 4; + // Unique identifier of the profile. + bytes profile_id = 5; + // Shard identifier the profile belongs to. + uint32 shard = 6; + // Profile annotations with additional metadata. + repeated types.v1.ProfileAnnotation annotations = 7; +} diff --git a/api/settings/v1/recording_rules.proto b/api/settings/v1/recording_rules.proto new file mode 100644 index 0000000000..694c4daa31 --- /dev/null +++ b/api/settings/v1/recording_rules.proto @@ -0,0 +1,121 @@ +syntax = "proto3"; + +package settings.v1; + +import "types/v1/types.proto"; + +service RecordingRulesService { + rpc GetRecordingRule(GetRecordingRuleRequest) returns (GetRecordingRuleResponse) {} + rpc ListRecordingRules(ListRecordingRulesRequest) returns (ListRecordingRulesResponse) {} + rpc UpsertRecordingRule(UpsertRecordingRuleRequest) returns (UpsertRecordingRuleResponse) {} + rpc DeleteRecordingRule(DeleteRecordingRuleRequest) returns (DeleteRecordingRuleResponse) {} +} + +message GetRecordingRuleRequest { + string id = 1; +} + +message GetRecordingRuleResponse { + RecordingRule rule = 1; +} + +message ListRecordingRulesRequest {} + +message ListRecordingRulesResponse { + repeated RecordingRule rules = 1; +} + +message UpsertRecordingRuleRequest { + // The unique id of the recording rule. If an id is not provided, this will + // create a new recording rule. If an id is provided, it will replace the + // existing recording rule. + string id = 1; + + string metric_name = 2; + repeated string matchers = 3; + repeated string group_by = 4; + repeated types.v1.LabelPair external_labels = 5; + + // The observed generation of this recording rule. If this value does not + // match the generation stored in the database, this upsert will be rejected. + int64 generation = 6; + + optional StacktraceFilter stacktrace_filter = 7; +} + +message UpsertRecordingRuleResponse { + RecordingRule rule = 1; +} + +message DeleteRecordingRuleRequest { + string id = 1; +} + +message DeleteRecordingRuleResponse {} + +message RecordingRule { + // The unique id of the recording rule. + string id = 1; + + // The name of the recording rule, this does not necessarily need to be + // unique. + string metric_name = 2; + + // Used in the UI to display what type of profile type this recording rule is + // generated from. + // + // This should be the standard format of: + // + // :::: + // + // For example: + // + // process_cpu:cpu:nanoseconds:cpu:nanoseconds + string profile_type = 3; + + repeated string matchers = 4; + repeated string group_by = 5; + repeated types.v1.LabelPair external_labels = 6; + + // The observed generation of this recording rule. This value should be + // provided when making updates to this record, to avoid conflicting + // concurrent updates. + int64 generation = 7; + + // The stacktrace filter allows filtering on particular function names in the stacktrace. + // This allows recording rules to focus on specific functions and calculate their "total" + // resource usage. + optional StacktraceFilter stacktrace_filter = 8; + + // Provisioned rules are added by config and can't be Upsert or Deleted + bool provisioned = 9; +} + +message StacktraceFilter { + optional StacktraceFilterFunctionName function_name = 1; +} + +enum MetricType { + TOTAL = 0; +} + +message StacktraceFilterFunctionName { + string function_name = 1; + MetricType metric_type = 2; +} + +message RecordingRuleStore { + string id = 1; + string metric_name = 2; + string prometheus_data_source = 3; + repeated string matchers = 4; + repeated string group_by = 5; + repeated types.v1.LabelPair external_labels = 6; + int64 generation = 7; + optional StacktraceFilter stacktrace_filter = 8; +} + +message RecordingRulesStore { + repeated RecordingRuleStore rules = 1; + int64 generation = 2; +} diff --git a/api/settings/v1/setting.proto b/api/settings/v1/setting.proto index fb7375bfb9..bac30d8314 100644 --- a/api/settings/v1/setting.proto +++ b/api/settings/v1/setting.proto @@ -5,6 +5,7 @@ package settings.v1; service SettingsService { rpc Get(GetSettingsRequest) returns (GetSettingsResponse) {} rpc Set(SetSettingsRequest) returns (SetSettingsResponse) {} + rpc Delete(DeleteSettingsRequest) returns (DeleteSettingsResponse) {} } message GetSettingsRequest {} @@ -21,6 +22,12 @@ message SetSettingsResponse { Setting setting = 1; } +message DeleteSettingsRequest { + string name = 1; +} + +message DeleteSettingsResponse {} + message Setting { string name = 1; string value = 2; diff --git a/api/types/v1/types.proto b/api/types/v1/types.proto index 09012a1319..69abfeb312 100644 --- a/api/types/v1/types.proto +++ b/api/types/v1/types.proto @@ -2,9 +2,14 @@ syntax = "proto3"; package types.v1; +import "gnostic/openapi/v3/annotations.proto"; + message LabelPair { - string name = 1; - string value = 2; + // Label name + string name = 1 [(gnostic.openapi.v3.property).example = {yaml: "service_name"}]; + + // Label value + string value = 2 [(gnostic.openapi.v3.property).example = {yaml: "my_service"}]; } message ProfileType { @@ -30,13 +35,35 @@ message Point { double value = 1; // Milliseconds unix timestamp int64 timestamp = 2; + repeated ProfileAnnotation annotations = 3; + // Exemplars are samples of individual profiles that contributed to this aggregated point + repeated Exemplar exemplars = 4; +} + +// Annotations provide additional metadata for a profile. +// +// The main differences between labels and annotations are: +// - annotations cannot be used in query selectors +// - annotation keys don't have to be unique +// +// Currently annotations are applied internally by distributors, +// any annotation passed via the push API will be dropped. +message ProfileAnnotation { + // Annotation key [hidden] + string key = 1; + // Annotation value [hidden] + string value = 2; } message LabelValuesRequest { - string name = 1; + // Name of the label + string name = 1 [(gnostic.openapi.v3.property).example = {yaml: "service_name"}]; + // List of Label selectors repeated string matchers = 2; - int64 start = 3; - int64 end = 4; + // Query from this point in time, given in Milliseconds since epoch. + int64 start = 3 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; + // Query to this point in time, given in Milliseconds since epoch. + int64 end = 4 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; } message LabelValuesResponse { @@ -44,9 +71,12 @@ message LabelValuesResponse { } message LabelNamesRequest { + // List of Label selectors repeated string matchers = 1; - int64 start = 2; - int64 end = 3; + // Query from this point in time, given in Milliseconds since epoch. + int64 start = 2 [(gnostic.openapi.v3.property).example = {yaml: "1676282400000"}]; + // Query to this point in time, given in Milliseconds since epoch. + int64 end = 3 [(gnostic.openapi.v3.property).example = {yaml: "1676289600000"}]; } message LabelNamesResponse { @@ -72,18 +102,36 @@ enum TimeSeriesAggregationType { TIME_SERIES_AGGREGATION_TYPE_AVERAGE = 1; } +enum ExemplarType { + EXEMPLAR_TYPE_UNSPECIFIED = 0; + EXEMPLAR_TYPE_NONE = 1; + EXEMPLAR_TYPE_INDIVIDUAL = 2; + EXEMPLAR_TYPE_SPAN = 3; +} + // StackTraceSelector is used for filtering stack traces by locations. message StackTraceSelector { // Stack trace of the call site. Root at call_site[0]. // Only stack traces having the prefix provided will be selected. // If empty, the filter is ignored. repeated Location call_site = 1; + // Stack trace selector for profiles purposed for Go PGO. + // If set, call_site is ignored. + GoPGO go_pgo = 2; } message Location { string name = 1; } +message GoPGO { + // Specifies the number of leaf locations to keep. + uint32 keep_locations = 1; + // Aggregate callees causes the leaf location line number to be ignored, + // thus aggregating all callee samples (but not callers). + bool aggregate_callees = 2; +} + message GetProfileStatsRequest {} message GetProfileStatsResponse { @@ -94,3 +142,44 @@ message GetProfileStatsResponse { // Milliseconds since epoch. int64 newest_profile_time = 3; } + +// Exemplar represents metadata for an individual profile sample. +// Exemplars allow users to drill down from aggregated timeline views +// to specific profile instances. +message Exemplar { + // Milliseconds since epoch when the profile was captured. + int64 timestamp = 1 [(gnostic.openapi.v3.property).example = {yaml: "1730000023000"}]; + + // Unique identifier for the profile (UUID). + string profile_id = 2 [(gnostic.openapi.v3.property).example = {yaml: "7c9e6679-7425-40de-944b-e07fc1f90ae7"}]; + + // Span ID if this profile was split by span during ingestion. + string span_id = 3 [(gnostic.openapi.v3.property).example = {yaml: "00f067aa0ba902b7"}]; + + // Total sample value for this profile (e.g., CPU nanoseconds, bytes allocated). + int64 value = 4 [(gnostic.openapi.v3.property).example = {yaml: "2450000000"}]; + + // Labels specific to this exemplar (e.g., pod name, node name). When an exemplar + // label overlaps with the series label, it is not included here. + repeated LabelPair labels = 5; + + // Trace ID associated with the span, encoded as 32 lowercase hexadecimal characters. + string trace_id = 6 [(gnostic.openapi.v3.property).example = {yaml: "4bf92f3577b34da6a3ce929d0e0e4736"}]; +} + +message HeatmapSeries { + repeated LabelPair labels = 1; + repeated HeatmapSlot slots = 2; +} + +message HeatmapSlot { + // Milliseconds unix timestamp of the right edge (x_max) of this slot. + // The slot covers the half-open interval (timestamp - step, timestamp]. + int64 timestamp = 1; + // Minimum y value + repeated double y_min = 2; + // How many matches + repeated int32 counts = 3; + // Provide exemplars + repeated Exemplar exemplars = 4; +} diff --git a/api/vcs/v1/vcs.proto b/api/vcs/v1/vcs.proto index a691241886..e5c7d26401 100644 --- a/api/vcs/v1/vcs.proto +++ b/api/vcs/v1/vcs.proto @@ -8,11 +8,18 @@ service VCSService { rpc GithubRefresh(GithubRefreshRequest) returns (GithubRefreshResponse) {} rpc GetFile(GetFileRequest) returns (GetFileResponse) {} rpc GetCommit(GetCommitRequest) returns (GetCommitResponse) {} + rpc GetCommits(GetCommitsRequest) returns (GetCommitsResponse) {} } message GithubAppRequest {} message GithubAppResponse { + // clientID must be propagated when calling + // https://github.com/login/oauth/authorize in the client_id query parameter. string clientID = 1; + // If callbackURL is not empty, the URL should be propagated when + // calling https://github.com/login/oauth/authorize in the + // redirect_uri query parameter. + string callbackURL = 2; } message GithubLoginRequest { @@ -20,13 +27,37 @@ message GithubLoginRequest { } message GithubLoginResponse { + // Deprecated + // In future version, this cookie won't be sent. Now, old cookie is sent + // alongside the new expected data (token, token_expires_at and + // refresh_token_expires_at). Frontend will be responsible of computing its + // own cookie from the new data. Remove after completing + // https://github.com/grafana/explore-profiles/issues/187 string cookie = 1; + // base64 encoded encrypted token + string token = 2; + // Unix ms timestamp of when the token expires. + int64 token_expires_at = 3; + // Unix ms timestamp of when the refresh token expires. + int64 refresh_token_expires_at = 4; } message GithubRefreshRequest {} message GithubRefreshResponse { + // Deprecated + // In future version, this cookie won't be sent. Now, old cookie is sent + // alongside the new expected data (token, token_expires_at and + // refresh_token_expires_at). Frontend will be responsible of computing its + // own cookie from the new data. Remove after completing + // https://github.com/grafana/explore-profiles/issues/187 string cookie = 1; + // base64 encoded encrypted token + string token = 2; + // Unix ms timestamp of when the token expires. + int64 token_expires_at = 3; + // Unix ms timestamp of when the refresh token expires. + int64 refresh_token_expires_at = 4; } message GetFileRequest { @@ -36,6 +67,10 @@ message GetFileRequest { string ref = 2; // the path to the file as provided by the symbols string localPath = 3; + // the root path where the project lives inside the repository + string rootPath = 4; + // the function name as provided by the symbols + string functionName = 5; } message GetFileResponse { @@ -71,3 +106,26 @@ message CommitAuthor { // the author avatar URL string avatarURL = 2; } + +message CommitInfo { + // the commit message + string message = 1; + // the commit author login + CommitAuthor author = 2; + // the commit date + string date = 3; + // the commit sha + string sha = 4; + // the full URL to the commit + string URL = 5; +} + +// New messages for the GetCommits method +message GetCommitsRequest { + string repository_url = 1; + repeated string refs = 2; +} + +message GetCommitsResponse { + repeated CommitInfo commits = 1; +} diff --git a/cmd/profilecli/blocks.go b/cmd/profilecli/blocks.go index 9757aaa31f..fb6db4b768 100644 --- a/cmd/profilecli/blocks.go +++ b/cmd/profilecli/blocks.go @@ -9,11 +9,10 @@ import ( "github.com/dustin/go-humanize" "github.com/go-kit/log/level" - "github.com/olekukonko/tablewriter" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) func fileInfo(f *block.File) string { @@ -37,7 +36,7 @@ func blocksList(ctx context.Context) error { return err } - table := tablewriter.NewWriter(output(ctx)) + table := newTableWriter(output(ctx)) table.SetHeader([]string{"Block ID", "MinTime", "MaxTime", "Duration", "Index", "Profiles", "Stacktraces", "Locations", "Functions", "Strings"}) for _, blockInfo := range metas { table.Append([]string{ diff --git a/cmd/profilecli/bucket.go b/cmd/profilecli/bucket.go index 88c8ac9751..9fd2bcf20c 100644 --- a/cmd/profilecli/bucket.go +++ b/cmd/profilecli/bucket.go @@ -3,66 +3,115 @@ package main import ( "context" "embed" - _ "embed" + "errors" + "flag" "fmt" "log" "net/http" + "strconv" + "strings" + "time" + "github.com/dustin/go-humanize" "github.com/grafana/dskit/server" + "github.com/oklog/ulid/v2" + "github.com/olekukonko/tablewriter" + "github.com/prometheus/common/model" + "github.com/thanos-io/objstore" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - objstoreclient "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/gcs" - "github.com/grafana/pyroscope/pkg/operations" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/operations" ) +type bucketParams struct { + objectStoreCfg objstoreclient.Config +} + +func (b *bucketParams) initClient(ctx context.Context) (phlareobj.Bucket, error) { + return objstoreclient.NewBucket( + ctx, + b.objectStoreCfg, + "storage", + ) +} + type bucketWebToolParams struct { - httpListenPort int - objectStoreType string - bucketName string + *bucketParams + httpListenPort int +} + +func addBucketParams(cmd commander) *bucketParams { + var ( + params = &bucketParams{} + ) + // keep in sync with objstoreclient.RegisterFlags + fs := flag.NewFlagSet("", flag.ContinueOnError) + params.objectStoreCfg.RegisterFlagsWithPrefix("storage.", fs) + fs.VisitAll(func(f *flag.Flag) { + switch f.Name { + case "storage.backend": + cmd.Flag(f.Name, f.Usage).Default("filesystem").StringVar(¶ms.objectStoreCfg.Backend) + case "storage.prefix": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.Prefix) + case "storage.filesystem.dir": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.Filesystem.Directory) + case "storage.gcs.bucket-name": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.GCS.BucketName) + case "storage.s3.bucket-name": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.S3.BucketName) + case "storage.s3.endpoint": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.S3.Endpoint) + case "storage.s3.region": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.S3.Region) + case "storage.azure.container-name": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.Azure.ContainerName) + case "storage.azure.account-name": + cmd.Flag(f.Name, f.Usage).Default(f.DefValue).StringVar(¶ms.objectStoreCfg.Azure.StorageAccountName) + default: + break + } + }) + return params } //go:embed static var staticFiles embed.FS -func addBucketWebToolParams(bucketWebToolCmd commander) *bucketWebToolParams { +func addBucketWebToolParams(cmd commander) *bucketWebToolParams { var ( params = &bucketWebToolParams{} ) - bucketWebToolCmd.Flag("object-store-type", "The type of the object storage (e.g., gcs).").Default("gcs").StringVar(¶ms.objectStoreType) - bucketWebToolCmd.Flag("bucket-name", "The name of the object storage bucket.").StringVar(¶ms.bucketName) - bucketWebToolCmd.Flag("http-listen-port", "The port to run the HTTP server on.").Default("4201").IntVar(¶ms.httpListenPort) + params.bucketParams = addBucketParams(cmd) + cmd.Flag("http-listen-port", "The port to run the HTTP server on.").Default("4201").IntVar(¶ms.httpListenPort) return params } type bucketWebTool struct { params *bucketWebToolParams - server *server.Server } func newBucketWebTool(params *bucketWebToolParams) *bucketWebTool { - var ( - serverCfg = server.Config{ - HTTPListenPort: params.httpListenPort, - Log: logger, - } - ) + return &bucketWebTool{ + params: params, + } +} - s, err := server.New(serverCfg) +func (t *bucketWebTool) run(ctx context.Context) error { + s, err := server.New(server.Config{ + HTTPListenPort: t.params.httpListenPort, + Log: logger, + }) if err != nil { - log.Fatal(err) - return nil + return err } - b, err := initObjectStoreBucket(params) + b, err := t.params.initClient(ctx) if err != nil { log.Fatal(err) - return nil - } - - tool := &bucketWebTool{ - params: params, - server: s, + return err } handlers := operations.Handlers{ @@ -75,34 +124,214 @@ func newBucketWebTool(params *bucketWebToolParams) *bucketWebTool { s.HTTP.Path("/ops/object-store/tenants/{tenant}/blocks").HandlerFunc(handlers.CreateBlocksHandler()) s.HTTP.Path("/ops/object-store/tenants/{tenant}/blocks/{block}").HandlerFunc(handlers.CreateBlockDetailsHandler()) - return tool + out := output(ctx) + + fmt.Fprintf(out, "The bucket web tool is available at http://localhost:%d/ops/object-store/tenants\n", t.params.httpListenPort) + + if err := s.Run(); err != nil { + return err + } + + return nil } -func initObjectStoreBucket(params *bucketWebToolParams) (phlareobj.Bucket, error) { - objectStoreConfig := objstoreclient.Config{ - StoragePrefix: "", - StorageBackendConfig: objstoreclient.StorageBackendConfig{ - Backend: params.objectStoreType, - GCS: gcs.Config{ - BucketName: params.bucketName, - }, - }, +func labelStrings(v []int32, s []string, sb *strings.Builder) { + pairs := metadata.LabelPairs(v) + for pairs.Next() { + p := pairs.At() + first := true + for len(p) > 0 { + if first { + first = false + _, _ = sb.WriteString("- ") + } else { + _, _ = sb.WriteString(" ") + } + _, _ = sb.WriteString(s[p[0]]) + _, _ = sb.WriteString(`="`) + _, _ = sb.WriteString(s[p[1]]) + _, _ = sb.WriteString(`"`) + _, _ = sb.WriteString("\n") + p = p[2:] + } } - return objstoreclient.NewBucket( - context.Background(), - objectStoreConfig, - "storage", - ) } -func (t *bucketWebTool) run(ctx context.Context) error { - out := output(ctx) +func bucketInspectV2(ctx context.Context, params *bucketParams, paths []string) error { + b, err := params.initClient(ctx) + if err != nil { + return err + } - fmt.Fprintf(out, "The bucket web tool is available at http://localhost:%d/ops/object-store/tenants\n", t.params.httpListenPort) + lst := bucketList{} + + for _, path := range paths { + obj, err := block.NewObjectFromPath(ctx, b, path) + if err != nil { + return err + } + + e, err := bucketListElemFromPath(path) + if err != nil { + return err + } - if err := t.server.Run(); err != nil { + meta := obj.Metadata() + stringTable := meta.GetStringTable() + e.Size = meta.GetSize() + e.CompactionLevel = meta.GetCompactionLevel() + + lst.lst = lst.lst[:0] + lst.lst = append(lst.lst, *e) + lst.renderInspectTable(ctx) + + sb := new(strings.Builder) + tbl := newTableWriter(output(ctx)) + tbl.SetAutoWrapText(false) + tbl.SetHeader([]string{"Tenant", "Dataset Name", "From", "Duration", "Size", "Labels"}) + + for _, ds := range meta.Datasets { + sb.Reset() + labelStrings(ds.Labels, stringTable, sb) + tbl.Append([]string{ + stringTable[ds.Tenant], + stringTable[ds.Name], + model.Time(ds.MinTime).Time().Format(time.RFC3339), + (time.Duration(ds.MaxTime-ds.MinTime) * time.Millisecond).String(), + humanize.Bytes(ds.Size), + strings.TrimRight(sb.String(), "\n"), + }) + } + tbl.Render() + + } + + return nil +} + +type bucketList struct { + lst []bucketListElem + tbl *tablewriter.Table +} + +func (b bucketList) renderInspectTable(ctx context.Context) { + if b.tbl == nil { + b.tbl = newTableWriter(output(ctx)) + } else { + b.tbl.ClearRows() + } + b.tbl.SetHeader([]string{"Block ID", "Time", "Type", "Shard", "Tenant", "Compaction Level", "Size", "Path"}) + for _, e := range b.lst { + b.tbl.Append([]string{ + e.ID.String(), + e.ID.Timestamp().Format(time.RFC3339), + e.Type, + strconv.Itoa(e.Shard), + e.Tenant, + strconv.Itoa(int(e.CompactionLevel)), + humanize.Bytes(e.Size), + e.Path, + }) + + } + b.tbl.Render() +} + +func (b bucketList) renderListTable(ctx context.Context) { + if b.tbl == nil { + b.tbl = newTableWriter(output(ctx)) + } else { + b.tbl.ClearRows() + } + b.tbl.SetHeader([]string{"Block ID", "Time", "Type", "Shard", "Tenant", "Path"}) + for _, e := range b.lst { + b.tbl.Append([]string{ + e.ID.String(), + e.ID.Timestamp().Format(time.RFC3339), + e.Type, + strconv.Itoa(e.Shard), + e.Tenant, + e.Path, + }) + + } + b.tbl.Render() +} + +type bucketListElem struct { + ID ulid.ULID + Type string + Shard int + Tenant string + Path string + CompactionLevel uint32 + Size uint64 +} + +var errUnexpectedPath = errors.New("unexpected path") + +func bucketListElemFromPath(s string) (*bucketListElem, error) { + parts := strings.Split(s, "/") + if parts[len(parts)-1] != "block.bin" { + return nil, errUnexpectedPath + } + + id, err := ulid.Parse(parts[len(parts)-2]) + if err != nil { + return nil, err + } + shard, err := strconv.Atoi(parts[1]) + if err != nil { + return nil, err + } + + tenant := parts[2] + if parts[0] == "segments" { + tenant = "various" + } + + return &bucketListElem{ + ID: id, + Type: parts[0], + Shard: shard, + Tenant: tenant, + Path: s, + }, nil +} + +func bucketListV2(ctx context.Context, params *bucketParams) error { + b, err := params.initClient(ctx) + if err != nil { return err } + lst := bucketList{} + limit := 40 // might be depending on the size of the terminal + + addBlock := func(name string) error { + e, err := bucketListElemFromPath(name) + if err != nil { + if err == errUnexpectedPath { + return nil + } + return err + } + + lst.lst = append(lst.lst, *e) + if len(lst.lst) > limit { + lst.renderListTable(ctx) + lst.lst = lst.lst[:0] + } + + return nil + } + + if err := b.Iter(ctx, "segments", addBlock, objstore.WithRecursiveIter()); err != nil { + return err + } + if err := b.Iter(ctx, "blocks", addBlock, objstore.WithRecursiveIter()); err != nil { + return err + } + lst.renderListTable(ctx) return nil } diff --git a/cmd/profilecli/canary_exporter.go b/cmd/profilecli/canary_exporter.go index b3e6a0a1f1..e28237574f 100644 --- a/cmd/profilecli/canary_exporter.go +++ b/cmd/profilecli/canary_exporter.go @@ -7,7 +7,6 @@ package main import ( - "bytes" "context" "crypto/sha256" "crypto/tls" @@ -22,26 +21,20 @@ import ( "sync" "time" - "connectrpc.com/connect" "github.com/go-kit/log/level" - "github.com/google/go-cmp/cmp" - gprofile "github.com/google/pprof/profile" - "github.com/google/uuid" - "github.com/pkg/errors" + "github.com/grafana/dskit/multierror" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" "go.uber.org/atomic" - - pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" - querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" ) type canaryExporterParams struct { *phlareClient ListenAddress string TestFrequency time.Duration + TestDelay time.Duration + QueryProbeSet string } func addCanaryExporterParams(ceCmd commander) *canaryExporterParams { @@ -50,11 +43,18 @@ func addCanaryExporterParams(ceCmd commander) *canaryExporterParams { ) ceCmd.Flag("listen-address", "Listen address for the canary exporter.").Default(":4101").StringVar(¶ms.ListenAddress) ceCmd.Flag("test-frequency", "How often the specified Pyroscope cell should be tested.").Default("15s").DurationVar(¶ms.TestFrequency) + ceCmd.Flag("test-delay", "The delay between ingest and query requests.").Default("2s").DurationVar(¶ms.TestDelay) + ceCmd.Flag("query-probe-set", "Which set of probes to use for query requests. Available sets are \"default\", \"extended\", and \"all\" (extended + v2 only tests).").Default("default").EnumVar(¶ms.QueryProbeSet, "default", "extended", "all") params.phlareClient = addPhlareClient(ceCmd) return params } +type queryProbe struct { + name string + f func(ctx context.Context, now time.Time) error +} + type canaryExporter struct { params *canaryExporterParams reg *prometheus.Registry @@ -63,6 +63,8 @@ type canaryExporter struct { defaultTransport http.RoundTripper metrics *canaryExporterMetrics + queryProbes []*queryProbe + hostname string } @@ -153,6 +155,29 @@ func newCanaryExporter(params *canaryExporterParams) *canaryExporter { defaultTransport: params.httpClient().Transport, metrics: newCanaryExporterMetrics(reg), + + queryProbes: make([]*queryProbe, 0), + } + + ce.queryProbes = append(ce.queryProbes, &queryProbe{name: "query-select-merge-profile", f: ce.testSelectMergeProfile}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{name: "query-select-merge-otlp-profile", f: ce.testSelectMergeOTLPProfile}) + + if params.QueryProbeSet == "extended" || params.QueryProbeSet == "all" { + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-profile-types", ce.testProfileTypes}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-series", ce.testSeries}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-label-names", ce.testLabelNames}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-label-values", ce.testLabelValues}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-select-series", ce.testSelectSeries}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-select-merge-stacktraces", ce.testSelectMergeStacktraces}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-select-merge-span-profile", ce.testSelectMergeSpanProfile}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-get-profile-stats", ce.testGetProfileStats}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"render", ce.testRender}) + ce.queryProbes = append(ce.queryProbes, &queryProbe{"render-diff", ce.testRenderDiff}) + } + + if params.QueryProbeSet == "all" { + // for v2 only + ce.queryProbes = append(ce.queryProbes, &queryProbe{"query-exemplars", ce.testQueryExemplars}) } metricsPath := "/metrics" @@ -219,7 +244,7 @@ func (ce *canaryExporter) run(ctx context.Context) error { } func (ce *canaryExporter) doTrace(ctx context.Context, probeName string) (rCtx context.Context, done func(bool)) { - level.Info(logger).Log("msg", "starting probe", "probeName", probeName) + level.Info(logger).Log("msg", "starting probe", "probe_name", probeName) tt := newInstrumentedTransport(ce.defaultTransport, ce.metrics, probeName) ce.params.client.Transport = tt @@ -237,7 +262,10 @@ func (ce *canaryExporter) doTrace(ctx context.Context, probeName string) (rCtx c return rCtx, func(result bool) { // At this point body is fully read and we can write end time. - tt.current.end = time.Now() + // Note: tt.current may be nil for non-HTTP probes (e.g., gRPC) + if tt.current != nil { + tt.current.end = time.Now() + } // record body size ce.metrics.bodyUncompressedLength.WithLabelValues(probeName).Set(float64(tt.bodySize.Load())) @@ -281,132 +309,92 @@ func (ce *canaryExporter) doTrace(ctx context.Context, probeName string) (rCtx c } if m := ce.metrics.success.WithLabelValues(probeName); result { - level.Info(logger).Log("msg", "probe successful", "probeName", probeName) m.Set(1) } else { - level.Info(logger).Log("msg", "probe failed", "probeName", probeName) m.Set(0) } } } func (ce *canaryExporter) testPyroscopeCell(ctx context.Context) error { - now := time.Now() - p := testhelper.NewProfileBuilder(now.UnixNano()) - p.Labels = p.Labels[:0] - p.CustomProfile("deadmans_switch", "made_up", "profilos", "made_up", "profilos") - p.WithLabels( - "job", "canary-exporter", - "instance", ce.hostname, - ) - p.UUID = uuid.New() - p.ForStacktraceString("func1", "func2").AddSamples(10) - p.ForStacktraceString("func1").AddSamples(20) - data, err := p.Profile.MarshalVT() - if err != nil { - return err - } + // Run all ingest probes + var ingestErrors multierror.MultiError - // ingest a fake profile - err = func() error { - rCtx, done := ce.doTrace(ctx, "ingest") - result := false - defer func() { - done(result) - }() - - if _, err := ce.params.pusherClient().Push(rCtx, connect.NewRequest(&pushv1.PushRequest{ - Series: []*pushv1.RawProfileSeries{ - { - Labels: p.Labels, - Samples: []*pushv1.RawSample{{ - ID: uuid.New().String(), - RawProfile: data, - }}, - }, - }, - })); err != nil { - return err - } + // ingest a fake profile using the original method + if err := ce.runProbe(ctx, "ingest", func(rCtx context.Context) error { + return ce.testIngestProfile(rCtx, now) + }); err != nil { + ingestErrors.Add(fmt.Errorf("error during standard ingestion: %w", err)) + } - result = true - return err - }() - if err != nil { - return fmt.Errorf("error during ingestion: %w", err) + // ingest via OTLP gRPC + // if err := ce.runProbe(ctx, "ingest-otlp-grpc", func(rCtx context.Context) error { + // return ce.testIngestOTLPGrpc(rCtx, now) + // }); err != nil { + // ingestErrors.Add(fmt.Errorf("error during OTLP gRPC ingestion: %w", err)) + // } + + // ingest via OTLP HTTP/JSON + if err := ce.runProbe(ctx, "ingest-otlp-http-json", func(rCtx context.Context) error { + return ce.testIngestOTLPHttpJson(rCtx, now) + }); err != nil { + ingestErrors.Add(fmt.Errorf("error during OTLP HTTP/JSON ingestion: %w", err)) } - level.Info(logger).Log("msg", "successfully ingested profile", "uuid", p.UUID.String()) - - // now try to query it back - err = func() error { - rCtx, done := ce.doTrace(ctx, "query-instant") - result := false - defer func() { - done(result) - }() - - respQueryInstant, err := ce.params.queryClient().SelectMergeProfile(rCtx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ - Start: now.UnixMilli(), - End: now.Add(5 * time.Second).UnixMilli(), - LabelSelector: fmt.Sprintf(`{job="canary-exporter", instance="%s"}`, ce.hostname), - ProfileTypeID: "deadmans_switch:made_up:profilos:made_up:profilos", - })) - if err != nil { - return err - } + // ingest via OTLP HTTP/Protobuf + // Note: HTTP endpoints are not yet implemented in Pyroscope (see pkg/api/api.go:204-205) + if err := ce.runProbe(ctx, "ingest-otlp-http-protobuf", func(rCtx context.Context) error { + return ce.testIngestOTLPHttpProtobuf(rCtx, now) + }); err != nil { + ingestErrors.Add(fmt.Errorf("error during OTLP HTTP/Protobuf ingestion: %w", err)) + } - buf, err := respQueryInstant.Msg.MarshalVT() - if err != nil { - return errors.Wrap(err, "failed to marshal protobuf") + // Report ingestion errors if any + if ingestErrors.Err() != nil { + for _, line := range strings.Split(ingestErrors.Err().Error(), "\n") { + level.Error(logger).Log("msg", "ingestion error", "err", line) } + } - gp, err := gprofile.Parse(bytes.NewReader(buf)) - if err != nil { - return errors.Wrap(err, "failed to parse profile") + if ce.params.TestDelay > 0 { + level.Info(logger).Log("msg", "waiting before running a query", "delay", ce.params.TestDelay) + select { + case <-time.After(ce.params.TestDelay): + case <-ctx.Done(): } + } - expected := map[string]int64{ - "func1>func2": 10, - "func1": 20, - } - actual := make(map[string]int64) - - var sb strings.Builder - for _, s := range gp.Sample { - sb.Reset() - for _, loc := range s.Location { - if sb.Len() != 0 { - _, err := sb.WriteRune('>') - if err != nil { - return err - } - } - for _, line := range loc.Line { - _, err := sb.WriteString(line.Function.Name) - if err != nil { - return err - } - } - } - actual[sb.String()] = actual[sb.String()] + s.Value[0] - } + // Now try to query the data back + var multiError multierror.MultiError + for _, probe := range ce.queryProbes { + err := ce.runProbe(ctx, probe.name, func(rCtx context.Context) error { + return probe.f(rCtx, now) + }) + multiError.Add(err) + } + if multiError.Err() != nil { + return fmt.Errorf("%d error(s) reported from query probes", len(multiError)) + } - if diff := cmp.Diff(expected, actual); diff != "" { - return fmt.Errorf("query instantly mismatch (-expected, +actual):\n%s", diff) - } + return nil +} - result = true - return nil +func (ce *canaryExporter) runProbe(ctx context.Context, probeName string, probeFunc func(ctx context.Context) error) error { + rCtx, done := ce.doTrace(ctx, probeName) + result := false + defer func() { + done(result) }() + err := probeFunc(rCtx) if err != nil { - return fmt.Errorf("error during instant query probe: %w", err) + level.Error(logger).Log("msg", "probe failed", "probe_name", probeName, "err", err) + } else { + level.Info(logger).Log("msg", "probe successful", "probe_name", probeName) + result = true } - - return nil - + return err } // roundTripTrace holds timings for a single HTTP roundtrip. diff --git a/cmd/profilecli/canary_exporter_probes.go b/cmd/profilecli/canary_exporter_probes.go new file mode 100644 index 0000000000..0a026d54a7 --- /dev/null +++ b/cmd/profilecli/canary_exporter_probes.go @@ -0,0 +1,841 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "math" + "net/http" + "net/url" + "strings" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/google/go-cmp/cmp" + gprofile "github.com/google/pprof/profile" + "github.com/google/uuid" + + profilesv1 "go.opentelemetry.io/proto/otlp/collector/profiles/v1development" + commonv1 "go.opentelemetry.io/proto/otlp/common/v1" + otlpprofiles "go.opentelemetry.io/proto/otlp/profiles/v1development" + resourcev1 "go.opentelemetry.io/proto/otlp/resource/v1" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" +) + +const ( + profileTypeID = "deadmans_switch:made_up:profilos:made_up:profilos" + otlpProfileTypeID = "otlp_test:otlp_test:count:otlp_test:samples" + canaryExporterServiceName = "pyroscope-canary-exporter" +) + +func (ce *canaryExporter) testIngestProfile(ctx context.Context, now time.Time) error { + p := testhelper.NewProfileBuilder(now.UnixNano()) + p.Labels = p.Labels[:0] + p.CustomProfile("deadmans_switch", "made_up", "profilos", "made_up", "profilos") + p.WithLabels( + "service_name", canaryExporterServiceName, + "job", "canary-exporter", + "instance", ce.hostname, + ) + p.UUID = uuid.New() + p.ForStacktraceString("func1", "func2").AddSamples(10) + p.ForStacktraceString("func1").AddSamples(20) + + // for testing the span selection + p.StringTable = append(p.StringTable, "profile_id", "00000bac2a5ab0c7") + p.Sample[1].Label = []*googlev1.Label{{Key: int64(len(p.StringTable) - 2), Str: int64(len(p.StringTable) - 1)}} + + data, err := p.MarshalVT() + if err != nil { + return err + } + + if _, err := ce.params.pusherClient().Push(ctx, connect.NewRequest(&pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{ + { + Labels: p.Labels, + Samples: []*pushv1.RawSample{{ + ID: p.UUID.String(), + RawProfile: data, + }}, + }, + }, + })); err != nil { + return err + } + + level.Info(logger).Log("msg", "successfully ingested profile", "uuid", p.UUID.String()) + return nil +} + +// generateOTLPProfile creates an OTLP profile with the specified ingestion method label + +func (ce *canaryExporter) generateOTLPProfile(now time.Time, ingestionMethod string) *profilesv1.ExportProfilesServiceRequest { + // Sanitize the ingestion method label value by replacing "/" with "_" + sanitizedMethod := strings.ReplaceAll(ingestionMethod, "/", "_") + + // Create the profile dictionary with custom profile type similar to pprof probe + dictionary := &otlpprofiles.ProfilesDictionary{ + StringTable: []string{ + "", // 0: empty string + "otlp_test", // 1 + "samples", // 2 + "count", // 3 + "func1", // 4 + "func2", // 5 + "ingestion_method", // 6 + sanitizedMethod, // 7 + }, + MappingTable: []*otlpprofiles.Mapping{ + {}, // 0: empty mapping (required null entry) + }, + FunctionTable: []*otlpprofiles.Function{ + {NameStrindex: 0}, // 0: empty + {NameStrindex: 4}, // 1: func1 + {NameStrindex: 5}, // 2: func2 + }, + LocationTable: []*otlpprofiles.Location{ + {Lines: []*otlpprofiles.Line{{FunctionIndex: 1}}}, // 0: func1 + {Lines: []*otlpprofiles.Line{{FunctionIndex: 2}}}, // 1: func2 + }, + StackTable: []*otlpprofiles.Stack{ + {LocationIndices: []int32{}}, // 0: empty (required null entry) + {LocationIndices: []int32{1, 0}}, // 1: func2, func1 stack + {LocationIndices: []int32{0}}, // 2: func1 stack + }, + } + + // Create profile with two samples matching the original pprof profile + profile := &otlpprofiles.Profile{ + TimeUnixNano: uint64(now.UnixNano()), + DurationNano: 0, + Period: 1, + SampleType: &otlpprofiles.ValueType{ + TypeStrindex: 1, // "otlp_test" + UnitStrindex: 3, // "count" + }, + PeriodType: &otlpprofiles.ValueType{ + TypeStrindex: 1, // "otlp_test" + UnitStrindex: 2, // "samples" + }, + Samples: []*otlpprofiles.Sample{ + { + // func1>func2 with value 10 + StackIndex: 1, // stack_table[1] + Values: []int64{10}, + }, + { + // func1 with value 20 + StackIndex: 2, // stack_table[2] + Values: []int64{20}, + }, + }, + } + + // Create the resource attributes + resourceAttrs := []*commonv1.KeyValue{ + { + Key: "service.name", + Value: &commonv1.AnyValue{Value: &commonv1.AnyValue_StringValue{StringValue: canaryExporterServiceName}}, + }, + { + Key: "job", + Value: &commonv1.AnyValue{Value: &commonv1.AnyValue_StringValue{StringValue: "canary-exporter"}}, + }, + { + Key: "instance", + Value: &commonv1.AnyValue{Value: &commonv1.AnyValue_StringValue{StringValue: ce.hostname}}, + }, + { + Key: "ingestion_method", + Value: &commonv1.AnyValue{Value: &commonv1.AnyValue_StringValue{StringValue: sanitizedMethod}}, + }, + } + + // Create the OTLP request + req := &profilesv1.ExportProfilesServiceRequest{ + Dictionary: dictionary, + ResourceProfiles: []*otlpprofiles.ResourceProfiles{ + { + Resource: &resourcev1.Resource{ + Attributes: resourceAttrs, + }, + ScopeProfiles: []*otlpprofiles.ScopeProfiles{ + { + Scope: &commonv1.InstrumentationScope{ + Name: "pyroscope-canary-exporter", + }, + Profiles: []*otlpprofiles.Profile{profile}, + }, + }, + }, + }, + } + + return req +} + +/* + func (ce *canaryExporter) testIngestOTLPGrpc(ctx context.Context, now time.Time) error { + // Generate the OTLP profile with the appropriate ingestion method label + req := ce.generateOTLPProfile(now, "otlp/grpc") + + // Parse URL to extract host and port + parsedURL, err := url.Parse(ce.params.URL) + if err != nil { + return fmt.Errorf("failed to parse URL: %w", err) + } + port := parsedURL.Port() + if port == "" && parsedURL.Scheme == "http" { + port = "80" + } else if port == "" && parsedURL.Scheme == "https" { + port = "443" + } else { + port = "4317" // default OTLP gRPC port + } + grpcAddr := fmt.Sprintf("%s:%s", parsedURL.Hostname(), port) + + // Create gRPC connection + conn, err := grpc.NewClient(grpcAddr, + grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return fmt.Errorf("failed to connect to gRPC server: %w", err) + } + defer conn.Close() + + // Create OTLP profiles service client + client := profilesv1.NewProfilesServiceClient(conn) + + // Send the profile + _, err = client.Export(ctx, req) + if err != nil { + return fmt.Errorf("failed to export OTLP profile via gRPC: %w", err) + } + + level.Info(logger).Log("msg", "successfully ingested OTLP profile via gRPC") + return nil + } +*/ + +func (ce *canaryExporter) testIngestOTLPHttpJson(ctx context.Context, now time.Time) error { + // Generate the OTLP profile with the appropriate ingestion method label + req := ce.generateOTLPProfile(now, "otlp/http/json") + + // Marshal to JSON + jsonData, err := protojson.Marshal(req) + if err != nil { + return fmt.Errorf("failed to marshal OTLP profile to JSON: %w", err) + } + + // Create HTTP request using the instrumented client + url := ce.params.URL + "/v1development/profiles" + httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(jsonData)) + if err != nil { + return fmt.Errorf("failed to create HTTP request: %w", err) + } + httpReq.Header.Set("Content-Type", "application/json") + + // Send the request using the instrumented client (ce.params.client is set by doTrace) + resp, err := ce.params.client.Do(httpReq) + if err != nil { + return fmt.Errorf("failed to send HTTP request: %w", err) + } + defer resp.Body.Close() + + // Read the body to ensure the transport is fully traced + body, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("failed to read response body: %w", err) + } + + // Check response status + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body)) + } + + level.Info(logger).Log("msg", "successfully ingested OTLP profile via HTTP/JSON") + return nil +} + +func (ce *canaryExporter) testIngestOTLPHttpProtobuf(ctx context.Context, now time.Time) error { + // Generate the OTLP profile with the appropriate ingestion method label + req := ce.generateOTLPProfile(now, "otlp/http/protobuf") + + // Marshal to protobuf + protoData, err := proto.Marshal(req) + if err != nil { + return fmt.Errorf("failed to marshal OTLP profile to protobuf: %w", err) + } + + // Create HTTP request using the instrumented client + url := ce.params.URL + "/v1development/profiles" + httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(protoData)) + if err != nil { + return fmt.Errorf("failed to create HTTP request: %w", err) + } + httpReq.Header.Set("Content-Type", "application/x-protobuf") + + // Send the request using the instrumented client (ce.params.client is set by doTrace) + resp, err := ce.params.client.Do(httpReq) + if err != nil { + return fmt.Errorf("failed to send HTTP request: %w", err) + } + defer resp.Body.Close() + + // Read the body to ensure the transport is fully traced + body, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("failed to read response body: %w", err) + } + + // Check response status + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body)) + } + + level.Info(logger).Log("msg", "successfully ingested OTLP profile via HTTP/Protobuf") + return nil +} +func (ce *canaryExporter) testSelectMergeProfile(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ //nolint:staticcheck // Legacy querier.v1 compatibility probe. + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + LabelSelector: ce.createLabelSelector(), + ProfileTypeID: profileTypeID, + })) + if err != nil { + return err + } + + buf, err := respQuery.Msg.MarshalVT() + if err != nil { + return fmt.Errorf("failed to marshal protobuf: %w", err) + } + + gp, err := gprofile.Parse(bytes.NewReader(buf)) + if err != nil { + return fmt.Errorf("failed to parse profile: %w", err) + } + + expected := map[string]int64{ + "func1>func2": 10, + "func1": 20, + } + actual := make(map[string]int64) + + var sb strings.Builder + for _, s := range gp.Sample { + sb.Reset() + for _, loc := range s.Location { + if sb.Len() != 0 { + _, err := sb.WriteRune('>') + if err != nil { + return err + } + } + for _, line := range loc.Line { + _, err := sb.WriteString(line.Function.Name) + if err != nil { + return err + } + } + } + actual[sb.String()] = actual[sb.String()] + s.Value[0] + } + + if diff := cmp.Diff(expected, actual); diff != "" { + return fmt.Errorf("query mismatch (-expected, +actual):\n%s", diff) + } + + return nil +} + +func (ce *canaryExporter) testSelectMergeOTLPProfile(ctx context.Context, now time.Time) error { + // Query specifically for OTLP gRPC ingested profiles using the custom profile type + //labelSelector := fmt.Sprintf(`{service_name="%s", job="canary-exporter", instance="%s"}`, canaryExporterServiceName, ce.hostname) + + respQuery, err := ce.params.queryClient().SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ //nolint:staticcheck // Legacy querier.v1 compatibility probe. + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + LabelSelector: ce.createLabelSelector(), + ProfileTypeID: otlpProfileTypeID, + })) + if err != nil { + return fmt.Errorf("failed to query OTLP profile: %w", err) + } + + buf, err := respQuery.Msg.MarshalVT() + if err != nil { + return fmt.Errorf("failed to marshal protobuf: %w", err) + } + + gp, err := gprofile.Parse(bytes.NewReader(buf)) + if err != nil { + return fmt.Errorf("failed to parse profile: %w", err) + } + + // Verify the expected stacktraces from the OTLP profile + expected := map[string]int64{ + "func2>func1": 20, // 10 samples from each of the 2 ingestion methods + "func1": 40, // 20 samples * 2 + } + actual := make(map[string]int64) + + var sb strings.Builder + for _, s := range gp.Sample { + sb.Reset() + for _, loc := range s.Location { + if sb.Len() != 0 { + _, err := sb.WriteRune('>') + if err != nil { + return err + } + } + for _, line := range loc.Line { + _, err := sb.WriteString(line.Function.Name) + if err != nil { + return err + } + } + } + actual[sb.String()] = actual[sb.String()] + s.Value[0] + } + + if diff := cmp.Diff(expected, actual); diff != "" { + return fmt.Errorf("OTLP profile query mismatch (-expected, +actual):\n%s", diff) + } + + level.Info(logger).Log("msg", "successfully queried OTLP profile via gRPC") + return nil +} + +func (ce *canaryExporter) testProfileTypes(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().ProfileTypes(ctx, connect.NewRequest(&querierv1.ProfileTypesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + })) + if err != nil { + return err + } + + for _, pt := range respQuery.Msg.ProfileTypes { + if pt.ID == profileTypeID { + level.Info(logger).Log("msg", "found expected profile type", "id", pt.ID) + return nil + } + } + + return fmt.Errorf("expected profile type %s not found", profileTypeID) +} + +func (ce *canaryExporter) testSeries(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().Series(ctx, connect.NewRequest(&querierv1.SeriesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + LabelNames: []string{model.LabelNameServiceName, model.LabelNameProfileType}, + })) + + if err != nil { + return err + } + labelSets := respQuery.Msg.LabelsSet + + if len(labelSets) < 1 { + return fmt.Errorf("expected at least 1 label set, got %d", len(labelSets)) + } + + for _, ls := range labelSets { + labels := model.Labels(ls.Labels) + + serviceName := labels.Get(model.LabelNameServiceName) + if serviceName == "" { + return fmt.Errorf("expected service_name label to be set") + } + if serviceName != canaryExporterServiceName { + continue + } + profileType := labels.Get(model.LabelNameProfileType) + if profileType == "" { + return fmt.Errorf("expected profile_type label to be set") + } + if profileType != profileTypeID { + continue + } + return nil // found the expected series + } + + return fmt.Errorf("expected series with service_name=%s and profile_type=%s not found", canaryExporterServiceName, profileTypeID) +} + +func (ce *canaryExporter) testLabelNames(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().LabelNames(ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + // we have to pass this matcher to skip the tenant-wide index in v2 which is not ready until after compaction + Matchers: []string{fmt.Sprintf(`{service_name="%s"}`, canaryExporterServiceName)}, + })) + + if err != nil { + return err + } + + labelNames := respQuery.Msg.Names + + expectedLabelNames := []string{ + model.LabelNameProfileName, + model.LabelNamePeriodType, + model.LabelNamePeriodUnit, + model.LabelNameProfileType, + model.LabelNameServiceNamePrivate, + model.LabelNameType, + model.LabelNameUnit, + //"service.name", // todo: return once write path is ready for utf8 labels + model.LabelNameServiceName, + } + + // Use map as set for O(1) lookups + labelNamesSet := make(map[string]struct{}, len(labelNames)) + for _, label := range labelNames { + labelNamesSet[label] = struct{}{} + } + + missingLabels := []string{} + for _, expectedLabel := range expectedLabelNames { + if _, exists := labelNamesSet[expectedLabel]; !exists { + missingLabels = append(missingLabels, expectedLabel) + } + } + if len(missingLabels) > 0 { + return fmt.Errorf("missing expected labels: %s", missingLabels) + } + + return nil +} + +func (ce *canaryExporter) testLabelValues(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().LabelValues(ctx, connect.NewRequest(&typesv1.LabelValuesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + Name: model.LabelNameServiceName, + // we have to pass this matcher to skip the tenant-wide index in v2 which is not ready until after compaction + Matchers: []string{fmt.Sprintf(`{service_name="%s"}`, canaryExporterServiceName)}, + })) + + if err != nil { + return err + } + + if len(respQuery.Msg.Names) != 1 { + return fmt.Errorf("expected 1 label value, got %d", len(respQuery.Msg.Names)) + } + + serviceName := respQuery.Msg.Names[0] + + if serviceName != canaryExporterServiceName { + return fmt.Errorf("expected service_name label to be %s, got %s", canaryExporterServiceName, serviceName) + } + + return nil +} + +func (ce *canaryExporter) testSelectSeries(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().SelectSeries(ctx, connect.NewRequest(&querierv1.SelectSeriesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + Step: 1000, + LabelSelector: ce.createLabelSelector(), + ProfileTypeID: profileTypeID, + GroupBy: []string{model.LabelNameServiceName}, + })) + + if err != nil { + return err + } + + if len(respQuery.Msg.Series) != 1 { + return fmt.Errorf("expected 1 series, got %d", len(respQuery.Msg.Series)) + } + + series := respQuery.Msg.Series[0] + + if len(series.Points) != 1 { + return fmt.Errorf("expected 1 points, got %d", len(series.Points)) + } + + labels := model.Labels(series.Labels) + + if len(labels) != 1 { + return fmt.Errorf("expected 1 labels, got %d", len(labels)) + } + + serviceName := labels.Get(model.LabelNameServiceName) + if serviceName == "" { + return fmt.Errorf("expected service_name label to be set") + } + if serviceName != canaryExporterServiceName { + return fmt.Errorf("expected service_name label to be %s, got %s", canaryExporterServiceName, serviceName) + } + + return nil +} + +func (ce *canaryExporter) testSelectMergeStacktraces(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + LabelSelector: ce.createLabelSelector(), + ProfileTypeID: profileTypeID, + })) + + if err != nil { + return err + } + + flamegraph := respQuery.Msg.Flamegraph + + if len(flamegraph.Names) != 3 { + return fmt.Errorf("expected 3 names in flamegraph, got %d", len(flamegraph.Names)) + } + + if len(flamegraph.Levels) != 3 { + return fmt.Errorf("expected 3 levels in flamegraph, got %d", len(flamegraph.Levels)) + } + + return nil +} + +func (ce *canaryExporter) testSelectMergeSpanProfile(ctx context.Context, now time.Time) error { + respQuery, err := ce.params.queryClient().SelectMergeSpanProfile(ctx, connect.NewRequest(&querierv1.SelectMergeSpanProfileRequest{ //nolint:staticcheck // Legacy querier.v1 compatibility probe. + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + LabelSelector: ce.createLabelSelector(), + ProfileTypeID: profileTypeID, + SpanSelector: []string{"00000bac2a5ab0c7"}, + })) + + if err != nil { + return err + } + + flamegraph := respQuery.Msg.Flamegraph + + if flamegraph == nil { + return fmt.Errorf("expected flamegraph to be set") + } + + if len(flamegraph.Names) != 2 { + return fmt.Errorf("expected 2 names in flamegraph, got %d", len(flamegraph.Names)) + } + + if len(flamegraph.Levels) != 2 { + return fmt.Errorf("expected 2 levels in flamegraph, got %d", len(flamegraph.Levels)) + } + + return nil +} + +func (ce *canaryExporter) testQueryExemplars(ctx context.Context, now time.Time) error { + selectSeriesResp, err := ce.params.queryClient().SelectSeries(ctx, connect.NewRequest(&querierv1.SelectSeriesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + Step: 5, + LabelSelector: ce.createLabelSelector(), + ProfileTypeID: profileTypeID, + ExemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL, + })) + + if err != nil { + return err + } + + if len(selectSeriesResp.Msg.Series) != 1 { + return fmt.Errorf("expected 1 series, got %d", len(selectSeriesResp.Msg.Series)) + } + + series := selectSeriesResp.Msg.Series[0] + + if len(series.Points) != 1 { + return fmt.Errorf("expected 1 points, got %d", len(series.Points)) + } + + point := series.Points[0] + + if len(point.Exemplars) != 1 { + return fmt.Errorf("expected 1 exemplar, got %d", len(point.Exemplars)) + } + + exemplar := point.Exemplars[0] + + if exemplar.Value != 30 { + return fmt.Errorf("expected exemplar value to be 30, got %d", exemplar.Value) + } + + respQuery, err := ce.params.queryClient().SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + Start: now.UnixMilli(), + End: now.Add(5 * time.Second).UnixMilli(), + LabelSelector: ce.createLabelSelector(), + ProfileTypeID: profileTypeID, + ProfileIdSelector: []string{exemplar.ProfileId}, + })) + + if err != nil { + return err + } + + flamegraph := respQuery.Msg.Flamegraph + + if len(flamegraph.Names) != 3 { + return fmt.Errorf("expected 3 names in flamegraph, got %d", len(flamegraph.Names)) + } + + if len(flamegraph.Levels) != 3 { + return fmt.Errorf("expected 3 levels in flamegraph, got %d", len(flamegraph.Levels)) + } + + return nil +} + +func (ce *canaryExporter) testRender(ctx context.Context, now time.Time) error { + query := profileTypeID + ce.createLabelSelector() + startTime := now.UnixMilli() + endTime := now.Add(5 * time.Second).UnixMilli() + + baseURL, err := url.Parse(ce.params.URL) + if err != nil { + return err + } + baseURL.Path = "/pyroscope/render" + + params := url.Values{} + params.Add("query", query) + params.Add("from", fmt.Sprintf("%d", startTime)) + params.Add("until", fmt.Sprintf("%d", endTime)) + + baseURL.RawQuery = params.Encode() + reqURL := baseURL.String() + level.Debug(logger).Log("msg", "requesting render", "url", reqURL) + + req, err := http.NewRequestWithContext(ctx, "GET", reqURL, nil) + if err != nil { + return err + } + + resp, err := ce.params.httpClient().Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body)) + } + + var flamebearerProfile flamebearer.FlamebearerProfile + if err := json.NewDecoder(resp.Body).Decode(&flamebearerProfile); err != nil { + return err + } + + if len(flamebearerProfile.Flamebearer.Names) != 3 { + return fmt.Errorf("expected 3 names in flamegraph, got %d", len(flamebearerProfile.Flamebearer.Names)) + } + + if len(flamebearerProfile.Flamebearer.Levels) != 3 { + return fmt.Errorf("expected 3 levels in flamegraph, got %d", len(flamebearerProfile.Flamebearer.Levels)) + } + + return nil +} + +func (ce *canaryExporter) testRenderDiff(ctx context.Context, now time.Time) error { + query := profileTypeID + ce.createLabelSelector() + startTime := now.UnixMilli() + endTime := now.Add(5 * time.Second).UnixMilli() + + baseURL, err := url.Parse(ce.params.URL) + if err != nil { + return err + } + baseURL.Path = "/pyroscope/render-diff" + + params := url.Values{} + params.Add("leftQuery", query) + params.Add("leftFrom", fmt.Sprintf("%d", startTime)) + params.Add("leftUntil", fmt.Sprintf("%d", endTime)) + params.Add("rightQuery", query) + params.Add("rightFrom", fmt.Sprintf("%d", startTime)) + params.Add("rightUntil", fmt.Sprintf("%d", endTime)) + + baseURL.RawQuery = params.Encode() + reqURL := baseURL.String() + level.Debug(logger).Log("msg", "requesting diff", "url", reqURL) + + req, err := http.NewRequestWithContext(ctx, "GET", reqURL, nil) + if err != nil { + return err + } + + resp, err := ce.params.httpClient().Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body)) + } + + var flamebearerProfile flamebearer.FlamebearerProfile + if err := json.NewDecoder(resp.Body).Decode(&flamebearerProfile); err != nil { + return err + } + + if len(flamebearerProfile.Flamebearer.Names) != 3 { + return fmt.Errorf("expected 3 names in flamegraph, got %d", len(flamebearerProfile.Flamebearer.Names)) + } + + if len(flamebearerProfile.Flamebearer.Levels) != 3 { + return fmt.Errorf("expected 3 levels in flamegraph, got %d", len(flamebearerProfile.Flamebearer.Levels)) + } + + return nil +} + +func (ce *canaryExporter) testGetProfileStats(ctx context.Context, now time.Time) error { + resp, err := ce.params.queryClient().GetProfileStats(ctx, connect.NewRequest(&typesv1.GetProfileStatsRequest{})) + + if err != nil { + return err + } + + if !resp.Msg.DataIngested { + return fmt.Errorf("expected data to be ingested") + } + + if resp.Msg.OldestProfileTime == math.MinInt64 { + return fmt.Errorf("expected oldest profile time to be set") + } + + if resp.Msg.NewestProfileTime == math.MaxInt64 { + return fmt.Errorf("expected newest profile time to be set") + } + + return nil +} + +func (ce *canaryExporter) createLabelSelector() string { + return fmt.Sprintf(`{service_name="%s", job="canary-exporter", instance="%s"}`, canaryExporterServiceName, ce.hostname) +} diff --git a/cmd/profilecli/client.go b/cmd/profilecli/client.go index 8ca3a8030d..7a6a6bfd61 100644 --- a/cmd/profilecli/client.go +++ b/cmd/profilecli/client.go @@ -3,26 +3,67 @@ package main import ( "fmt" "net/http" + "strings" + "connectrpc.com/connect" + "github.com/alecthomas/kingpin/v2" "github.com/prometheus/common/version" - "gopkg.in/alecthomas/kingpin.v2" + + querydiagnostics "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend/diagnostics" ) const ( envPrefix = "PROFILECLI_" + + protocolTypeConnect = "connect" + protocolTypeGRPC = "grpc" + protocolTypeGRPCWeb = "grpc-web" + + acceptHeaderMimeType = "*/*" ) +var acceptHeaderClientCapabilities = []string{ + "allow-utf8-labelnames=true", +} + var userAgentHeader = fmt.Sprintf("pyroscope/%s", version.Version) +func addClientCapabilitiesHeader(r *http.Request, mime string, clientCapabilities []string) { + missingClientCapabilities := make([]string, 0, len(clientCapabilities)) + for _, capability := range clientCapabilities { + found := false + // Check if any header value already contains this capability + for _, value := range r.Header.Values("Accept") { + if strings.Contains(value, capability) { + found = true + break + } + } + + if !found { + missingClientCapabilities = append(missingClientCapabilities, capability) + } + } + + if len(missingClientCapabilities) > 0 { + acceptHeader := mime + acceptHeader += ";" + strings.Join(missingClientCapabilities, ";") + r.Header.Add("Accept", acceptHeader) + } +} + type phlareClient struct { - TenantID string - URL string - BasicAuth struct { + TenantID string + URL string + BearerToken string + CollectDiagnostics bool + BasicAuth struct { Username string Password string } defaultTransport http.RoundTripper client *http.Client + protocol string } type authRoundTripper struct { @@ -37,9 +78,15 @@ func (a *authRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) } if c.BasicAuth.Username != "" || c.BasicAuth.Password != "" { req.SetBasicAuth(c.BasicAuth.Username, c.BasicAuth.Password) + } else if c.BearerToken != "" { + req.Header.Set("Authorization", "Bearer "+c.BearerToken) + } + if c.CollectDiagnostics { + req.Header.Set(querydiagnostics.RequestHeader, "true") } } + addClientCapabilitiesHeader(req, acceptHeaderMimeType, acceptHeaderClientCapabilities) req.Header.Set("User-Agent", userAgentHeader) return a.next.RoundTrip(req) } @@ -57,6 +104,19 @@ func (c *phlareClient) httpClient() *http.Client { return c.client } +func (c *phlareClient) protocolOption() connect.ClientOption { + switch c.protocol { + case protocolTypeGRPC: + return connect.WithGRPC() + case protocolTypeGRPCWeb: + return connect.WithGRPCWeb() + case protocolTypeConnect: + return connect.WithClientOptions() + default: + return connect.WithClientOptions() + } +} + type commander interface { Flag(name, help string) *kingpin.FlagClause Arg(name, help string) *kingpin.ArgClause @@ -65,9 +125,13 @@ type commander interface { func addPhlareClient(cmd commander) *phlareClient { client := &phlareClient{} - cmd.Flag("url", "URL of the profile store.").Default("http://localhost:4040").Envar(envPrefix + "URL").StringVar(&client.URL) + cmd.Flag("url", "URL of the Pyroscope Endpoint. (Examples: https://profiles-prod-001.grafana.net for a Grafana Cloud endpoint, https://grafana.example.net/api/datasources/proxy/uid/ when using the Grafana data source proxy)").Default("http://localhost:4040").Envar(envPrefix + "URL").StringVar(&client.URL) cmd.Flag("tenant-id", "The tenant ID to be used for the X-Scope-OrgID header.").Default("").Envar(envPrefix + "TENANT_ID").StringVar(&client.TenantID) + cmd.Flag("token", "The bearer token to be used for communication with the server. Particularly useful when connecting to Grafana data source URLs (bearer token should be a Grafana Service Account token of the form 'glsa_[...]') or Grafana Cloud (tokens of the form 'glc_[...]')").Default("").Envar(envPrefix + "TOKEN").StringVar(&client.BearerToken) cmd.Flag("username", "The username to be used for basic auth.").Default("").Envar(envPrefix + "USERNAME").StringVar(&client.BasicAuth.Username) cmd.Flag("password", "The password to be used for basic auth.").Default("").Envar(envPrefix + "PASSWORD").StringVar(&client.BasicAuth.Password) + cmd.Flag("protocol", "The protocol to be used for communicating with the server.").Default(protocolTypeConnect).EnumVar(&client.protocol, + protocolTypeConnect, protocolTypeGRPC, protocolTypeGRPCWeb) + cmd.Flag("collect-diagnostics", "Request query diagnostics collection. The server will return a diagnostics ID in a response header.").Default("false").Envar(envPrefix + "COLLECT_DIAGNOSTICS").BoolVar(&client.CollectDiagnostics) return client } diff --git a/cmd/profilecli/client_test.go b/cmd/profilecli/client_test.go new file mode 100644 index 0000000000..4073b0e6a8 --- /dev/null +++ b/cmd/profilecli/client_test.go @@ -0,0 +1,79 @@ +package main + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_AcceptHeader(t *testing.T) { + tests := []struct { + Name string + Header http.Header + ClientCapabilities []string + Want []string + }{ + { + Name: "empty header adds capability", + Header: http.Header{}, + ClientCapabilities: []string{ + "allow-utf8-labelnames=true", + }, + Want: []string{"*/*;allow-utf8-labelnames=true"}, + }, + { + Name: "existing header appends capability", + Header: http.Header{ + "Accept": []string{"application/json"}, + }, + ClientCapabilities: []string{ + "allow-utf8-labelnames=true", + }, + Want: []string{"application/json", "*/*;allow-utf8-labelnames=true"}, + }, + { + Name: "multiple existing values appends capability", + Header: http.Header{ + "Accept": []string{"application/json", "text/plain"}, + }, + ClientCapabilities: []string{ + "allow-utf8-labelnames=true", + }, + Want: []string{"application/json", "text/plain", "*/*;allow-utf8-labelnames=true"}, + }, + { + Name: "existing capability is not duplicated", + Header: http.Header{ + "Accept": []string{"*/*;allow-utf8-labelnames=true"}, + }, + ClientCapabilities: []string{ + "allow-utf8-labelnames=true", + }, + Want: []string{"*/*;allow-utf8-labelnames=true"}, + }, + { + Name: "multiple client capabilities appends capability", + Header: http.Header{ + "Accept": []string{"*/*;allow-utf8-labelnames=true"}, + }, + ClientCapabilities: []string{ + "allow-utf8-labelnames=true", + "capability2=false", + }, + Want: []string{"*/*;allow-utf8-labelnames=true", "*/*;capability2=false"}, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + req, _ := http.NewRequest("GET", "example.com", nil) + req.Header = tt.Header + clientCapabilities := tt.ClientCapabilities + + addClientCapabilitiesHeader(req, acceptHeaderMimeType, clientCapabilities) + require.Equal(t, tt.Want, req.Header.Values("Accept")) + }) + } +} diff --git a/cmd/profilecli/compact.go b/cmd/profilecli/compact.go index 32f107c452..dbee2e27b3 100644 --- a/cmd/profilecli/compact.go +++ b/cmd/profilecli/compact.go @@ -2,23 +2,21 @@ package main import ( "context" + "errors" "fmt" "os" "path/filepath" "time" - "github.com/briandowns/spinner" "github.com/dustin/go-humanize" "github.com/go-kit/log" - "github.com/olekukonko/tablewriter" - "github.com/pkg/errors" "golang.org/x/sync/errgroup" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) func blocksCompact(ctx context.Context, src, dst string, shards int) error { @@ -51,7 +49,7 @@ func compact(ctx context.Context, src, dst string, metas []*block.Meta, shards i // create the destination directory if it doesn't exist if _, err := os.Stat(dst); errors.Is(err, os.ErrNotExist) { if err := os.MkdirAll(dst, 0o755); err != nil { - return errors.Wrap(err, "create dir") + return fmt.Errorf("create dir: %w", err) } } @@ -66,7 +64,7 @@ func compact(ctx context.Context, src, dst string, metas []*block.Meta, shards i Directory: src, }, }, - StoragePrefix: "", + Prefix: "", }, "profilecli") if err != nil { return err @@ -78,9 +76,6 @@ func compact(ctx context.Context, src, dst string, metas []*block.Meta, shards i } fmt.Fprintln(output(ctx), "Found Input blocks:") printMeta(ctx, in) - s := spinner.New(spinner.CharSets[11], 100*time.Millisecond, spinner.WithWriter(output(ctx))) - s.Suffix = " Loading data..." - s.Start() g, groupCtx := errgroup.WithContext(ctx) for _, b := range blocks { @@ -90,13 +85,9 @@ func compact(ctx context.Context, src, dst string, metas []*block.Meta, shards i }) } if err := g.Wait(); err != nil { - s.Stop() return err } - s.Suffix = " Compacting data..." - s.Restart() - out, err := phlaredb.CompactWithSplitting(ctx, phlaredb.CompactWithSplittingOpts{ Src: blocks, Dst: dst, @@ -107,18 +98,16 @@ func compact(ctx context.Context, src, dst string, metas []*block.Meta, shards i Logger: logger, }) if err != nil { - s.Stop() return err } - s.Stop() fmt.Fprintln(output(ctx), "Output blocks:") printMeta(ctx, out) return nil } func printMeta(ctx context.Context, metas []block.Meta) { - table := tablewriter.NewWriter(output(ctx)) + table := newTableWriter(output(ctx)) table.SetHeader([]string{"Block ID", "MinTime", "MaxTime", "Duration", "Index", "Profiles", "Symbols", "Labels"}) for _, blockInfo := range metas { table.Append([]string{ diff --git a/cmd/profilecli/debuginfo.go b/cmd/profilecli/debuginfo.go new file mode 100644 index 0000000000..d89d08fb05 --- /dev/null +++ b/cmd/profilecli/debuginfo.go @@ -0,0 +1,264 @@ +package main + +import ( + "context" + "debug/elf" + "encoding/binary" + "encoding/hex" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + + debuginfov1alpha1 "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1" + debuginfov1alpha1connect "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/debuginfo" +) + +func (c *phlareClient) debuginfoServiceClient() debuginfov1alpha1connect.DebuginfoServiceClient { + return debuginfov1alpha1connect.NewDebuginfoServiceClient( + c.httpClient(), + c.URL, + append( + connectapi.DefaultClientOptions(), + c.protocolOption(), + )..., + ) +} + +// extractGnuBuildIdFromReader parses the GNU build ID out of an already-open +// ELF file. The caller is responsible for closing/seeking the reader. +func extractGnuBuildIdFromReader(r io.ReaderAt) (string, error) { + elfFile, err := elf.NewFile(r) + if err != nil { + return "", err + } + defer elfFile.Close() + + for _, section := range elfFile.Sections { + if section.Name != ".note.gnu.build-id" { + continue + } + data, err := section.Data() + if err != nil { + return "", err + } + if len(data) < 12 { + return "", fmt.Errorf(".note.gnu.build-id section too short: %d bytes", len(data)) + } + namesz := binary.LittleEndian.Uint32(data[0:4]) + descsz := binary.LittleEndian.Uint32(data[4:8]) + nameEnd := 12 + int(namesz) + descStart := (nameEnd + 3) &^ 3 // align to 4 bytes + descEnd := descStart + int(descsz) + if descStart < nameEnd || descEnd > len(data) { + return "", fmt.Errorf(".note.gnu.build-id section truncated: need %d bytes, have %d", descEnd, len(data)) + } + return hex.EncodeToString(data[descStart:descEnd]), nil + } + return "", nil +} + +// extractGnuBuildId opens path and returns the file's GNU build ID. +func extractGnuBuildId(path string) (string, error) { + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + return extractGnuBuildIdFromReader(f) +} + +func shouldInitiateUploadCheck(ctx context.Context, client debuginfov1alpha1connect.DebuginfoServiceClient, gnuBuildId string, fileName string, fileType debuginfov1alpha1.FileMetadata_Type) (bool, string, error) { + req := &debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: gnuBuildId, + Name: fileName, + Type: fileType, + }, + } + resp, err := client.ShouldInitiateUpload(ctx, connect.NewRequest(req)) + if err != nil { + return false, "", err + } + return resp.Msg.ShouldInitiateUpload, resp.Msg.Reason, nil +} + +func uploadDebuginfo(ctx context.Context, params *debuginfoUploadParams) error { + client := params.debuginfoServiceClient() + + f, err := os.Open(params.path) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer f.Close() + + gnuBuildId, err := extractGnuBuildIdFromReader(f) + if err != nil { + return fmt.Errorf("failed to extract GNU build ID from %q: %w", params.path, err) + } + if gnuBuildId == "" { + return fmt.Errorf("file %q has no .note.gnu.build-id section; cannot upload", params.path) + } + + var fileType debuginfov1alpha1.FileMetadata_Type + switch params.fileType { + case "executable-full": + fileType = debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL + case "executable-no-text": + fileType = debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_NO_TEXT + default: + fileType = debuginfov1alpha1.FileMetadata_TYPE_UNSPECIFIED + } + + shouldUpload, reason, err := shouldInitiateUploadCheck(ctx, client, gnuBuildId, filepath.Base(params.path), fileType) + if err != nil { + return fmt.Errorf("ShouldInitiateUpload check failed: %w", err) + } + if !shouldUpload { + if reason == debuginfo.ReasonDisabled { + return fmt.Errorf("server has debuginfo upload disabled") + } + level.Info(logger).Log("msg", "server declined upload", "build_id", gnuBuildId, "reason", reason) + return nil + } + + // Rewind so the upload reads the file from the start. + if _, err := f.Seek(0, io.SeekStart); err != nil { + return fmt.Errorf("failed to rewind file: %w", err) + } + + uploadURL := params.URL + "/debuginfo.v1alpha1.DebuginfoService/Upload/" + gnuBuildId + req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, f) + if err != nil { + return fmt.Errorf("failed to create upload request: %w", err) + } + + resp, err := params.httpClient().Do(req) + if err != nil { + return fmt.Errorf("failed to upload: %w", err) + } + defer resp.Body.Close() + _, _ = io.Copy(io.Discard, resp.Body) + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("upload failed with status %s", resp.Status) + } + + if _, err := client.UploadFinished(ctx, connect.NewRequest(&debuginfov1alpha1.UploadFinishedRequest{ + GnuBuildId: gnuBuildId, + })); err != nil { + return fmt.Errorf("failed to finish upload: %w", err) + } + + level.Info(logger).Log("msg", "successfully uploaded debuginfo", "build_id", gnuBuildId, "path", params.path) + return nil +} + +type debuginfoUploadParams struct { + path string + fileType string + *phlareClient +} + +func addDebuginfoUploadParams(cmd commander) *debuginfoUploadParams { + params := new(debuginfoUploadParams) + cmd.Arg("path", "Path to the file to upload").Required().ExistingFileVar(¶ms.path) + cmd.Flag("type", "Type of executable: executable-full, executable-no-text").Default("executable-full").StringVar(¶ms.fileType) + + params.phlareClient = addPhlareClient(cmd) + return params +} + +type debuginfoListParams struct { + *phlareClient +} + +func addDebuginfoListParams(cmd commander) *debuginfoListParams { + params := new(debuginfoListParams) + params.phlareClient = addPhlareClient(cmd) + return params +} + +func listDebuginfo(ctx context.Context, params *debuginfoListParams) error { + client := params.debuginfoServiceClient() + + req := &debuginfov1alpha1.ListDebuginfoRequest{} + + resp, err := client.ListDebuginfo(ctx, connect.NewRequest(req)) + if err != nil { + return fmt.Errorf("failed to list debuginfo: %w", err) + } + + for _, object := range resp.Msg.GetObject() { + file := object.GetFile() + fmt.Printf("build_id=%s name=%s type=%s state=%s size=%s uploaded_at=%s\n", + file.GetGnuBuildId(), + file.GetName(), + file.GetType().String(), + object.GetState().String(), + humanizeBytes(object.GetSizeBytes()), + formatUploadedAt(object.GetFinishedAt()), + ) + } + + return nil +} + +type debuginfoDeleteParams struct { + gnuBuildID string + *phlareClient +} + +func addDebuginfoDeleteParams(cmd commander) *debuginfoDeleteParams { + params := new(debuginfoDeleteParams) + cmd.Arg("gnu-build-id", "GNU build ID to delete").Required().StringVar(¶ms.gnuBuildID) + params.phlareClient = addPhlareClient(cmd) + return params +} + +func deleteDebuginfo(ctx context.Context, params *debuginfoDeleteParams) error { + client := params.debuginfoServiceClient() + + _, err := client.DeleteDebuginfo(ctx, connect.NewRequest(&debuginfov1alpha1.DeleteDebuginfoRequest{ + GnuBuildId: params.gnuBuildID, + })) + if err != nil { + return fmt.Errorf("failed to delete debuginfo: %w", err) + } + + fmt.Printf("deleted debuginfo build_id=%s\n", params.gnuBuildID) + return nil +} + +func formatUploadedAt(ts *timestamppb.Timestamp) string { + if ts == nil { + return "in-progress" + } + return ts.AsTime().Format("2006-01-02T15:04:05Z") +} + +const unknownSize = "unknown" + +func humanizeBytes(b int64) string { + if b == 0 { + return unknownSize + } + const unit = 1024 + if b < unit { + return fmt.Sprintf("%d B", b) + } + div, exp := int64(unit), 0 + for n := b / unit; n >= unit; n /= unit { + div *= unit + exp++ + } + return fmt.Sprintf("%.1f %ciB", float64(b)/float64(div), "KMGTPE"[exp]) +} diff --git a/cmd/profilecli/debuginfo_test.go b/cmd/profilecli/debuginfo_test.go new file mode 100644 index 0000000000..30c75c939b --- /dev/null +++ b/cmd/profilecli/debuginfo_test.go @@ -0,0 +1,195 @@ +package main + +import ( + "bytes" + "context" + "debug/elf" + "encoding/binary" + "net/http/httptest" + "os" + "path/filepath" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/gorilla/mux" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + debuginfov1alpha1connect "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect" + "github.com/grafana/pyroscope/v2/pkg/debuginfo" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + "github.com/grafana/pyroscope/v2/pkg/tenant" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +// makeTestELF writes a minimal 64-bit ELF with a .note.gnu.build-id section +// containing buildID, and returns its path. Uses debug/elf's exported header +// types so we don't have to lay out raw bytes by hand. +func makeTestELF(t *testing.T, buildID []byte) string { + t.Helper() + + // Note payload: namesz | descsz | type | "GNU\0" | buildID | pad to 4. + // Errors from binary.Write to a bytes.Buffer are impossible, so we ignore them. + var note bytes.Buffer + _ = binary.Write(¬e, binary.LittleEndian, uint32(4)) // namesz: len("GNU\0") + _ = binary.Write(¬e, binary.LittleEndian, uint32(len(buildID))) // descsz + _ = binary.Write(¬e, binary.LittleEndian, uint32(3)) // NT_GNU_BUILD_ID + note.WriteString("GNU\x00") + note.Write(buildID) + for note.Len()%4 != 0 { + note.WriteByte(0) + } + + shstrtab := []byte("\x00.note.gnu.build-id\x00.shstrtab\x00") + const ehdrSz, phdrSz, shdrSz = 64, 56, 64 + noteOff := uint64(ehdrSz + phdrSz) + shstrOff := noteOff + uint64(note.Len()) + shdrOff := shstrOff + uint64(len(shstrtab)) + + var buf bytes.Buffer + _ = binary.Write(&buf, binary.LittleEndian, elf.Header64{ + Ident: [16]byte{0x7f, 'E', 'L', 'F', 2 /*64-bit*/, 1 /*LE*/, 1 /*ver*/}, + Type: uint16(elf.ET_EXEC), + Machine: uint16(elf.EM_X86_64), + Version: 1, + Phoff: ehdrSz, + Shoff: shdrOff, + Ehsize: ehdrSz, + Phentsize: phdrSz, + Phnum: 1, + Shentsize: shdrSz, + Shnum: 3, // null, .note.gnu.build-id, .shstrtab + Shstrndx: 2, + }) + _ = binary.Write(&buf, binary.LittleEndian, elf.Prog64{ + Type: uint32(elf.PT_NOTE), + Flags: uint32(elf.PF_R), + Off: noteOff, + Filesz: uint64(note.Len()), + Memsz: uint64(note.Len()), + Align: 4, + }) + buf.Write(note.Bytes()) + buf.Write(shstrtab) + + // Three section headers: null, .note.gnu.build-id, .shstrtab. + _ = binary.Write(&buf, binary.LittleEndian, elf.Section64{}) + _ = binary.Write(&buf, binary.LittleEndian, elf.Section64{ + Name: 1, Type: uint32(elf.SHT_NOTE), + Off: noteOff, Size: uint64(note.Len()), Addralign: 4, + }) + _ = binary.Write(&buf, binary.LittleEndian, elf.Section64{ + Name: 20, Type: uint32(elf.SHT_STRTAB), + Off: shstrOff, Size: uint64(len(shstrtab)), Addralign: 1, + }) + + path := filepath.Join(t.TempDir(), "test.elf") + require.NoError(t, os.WriteFile(path, buf.Bytes(), 0o644)) + return path +} + +func startDebuginfoTestServer(t *testing.T, enabled bool) *httptest.Server { + t.Helper() + store, err := debuginfo.NewStore(log.NewNopLogger(), memory.NewInMemBucket(), debuginfo.Config{ + Enabled: enabled, + MaxUploadSize: 100 * 1024 * 1024, + UploadStalePeriod: time.Minute, + }) + require.NoError(t, err) + + router := mux.NewRouter() + debuginfov1alpha1connect.RegisterDebuginfoServiceHandler( + router, store, + connect.WithInterceptors(tenant.NewAuthInterceptor(true)), + ) + router.Handle( + "/debuginfo.v1alpha1.DebuginfoService/Upload/{gnu_build_id}", + httputil.AuthenticateUser(true).Wrap(store.UploadHTTPHandler()), + ).Methods("POST") + + srv := httptest.NewServer(router) + t.Cleanup(srv.Close) + return srv +} + +func TestExtractGnuBuildId(t *testing.T) { + t.Parallel() + + id := []byte{0xde, 0xad, 0xbe, 0xef, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10} + got, err := extractGnuBuildId(makeTestELF(t, id)) + require.NoError(t, err) + assert.Equal(t, "deadbeef0102030405060708090a0b0c0d0e0f10", got) + + _, err = extractGnuBuildId("/nonexistent") + require.Error(t, err) +} + +// TestExtractGnuBuildId_Truncated checks that a .note.gnu.build-id section +// with a descsz larger than the actual data returns an error instead of +// panicking on out-of-bounds slicing. +func TestExtractGnuBuildId_Truncated(t *testing.T) { + t.Parallel() + + // Build an ELF with a valid build ID, then patch the note's descsz field + // to claim a much larger payload than is actually present. + path := makeTestELF(t, []byte{0xaa, 0xbb, 0xcc, 0xdd}) + data, err := os.ReadFile(path) + require.NoError(t, err) + + // Note payload starts at ehdrSz+phdrSz = 64+56 = 120; descsz is at offset +4. + const noteOff = 120 + binary.LittleEndian.PutUint32(data[noteOff+4:], 0xffff) + require.NoError(t, os.WriteFile(path, data, 0o644)) + + _, err = extractGnuBuildId(path) + require.Error(t, err) + assert.Contains(t, err.Error(), "truncated") +} + +func TestUploadDebuginfo(t *testing.T) { + t.Parallel() + srv := startDebuginfoTestServer(t, true) + id := []byte{0xca, 0xfe, 0xba, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + + params := &debuginfoUploadParams{ + path: makeTestELF(t, id), + fileType: "executable-full", + phlareClient: &phlareClient{URL: srv.URL, TenantID: "t1"}, + } + + // First upload succeeds, second is a no-op (server says it already has it). + require.NoError(t, uploadDebuginfo(context.Background(), params)) + require.NoError(t, uploadDebuginfo(context.Background(), params)) +} + +func TestUploadDebuginfo_Disabled(t *testing.T) { + t.Parallel() + srv := startDebuginfoTestServer(t, false) + id := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2} + + err := uploadDebuginfo(context.Background(), &debuginfoUploadParams{ + path: makeTestELF(t, id), + fileType: "executable-full", + phlareClient: &phlareClient{URL: srv.URL, TenantID: "t2"}, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "disabled") +} + +func TestUploadDebuginfo_NotAnELF(t *testing.T) { + t.Parallel() + srv := startDebuginfoTestServer(t, true) + + bogus := filepath.Join(t.TempDir(), "not-an-elf") + require.NoError(t, os.WriteFile(bogus, []byte("not elf"), 0o644)) + + err := uploadDebuginfo(context.Background(), &debuginfoUploadParams{ + path: bogus, + fileType: "executable-full", + phlareClient: &phlareClient{URL: srv.URL, TenantID: "t3"}, + }) + require.Error(t, err) +} diff --git a/cmd/profilecli/kube_proxy.go b/cmd/profilecli/kube_proxy.go new file mode 100644 index 0000000000..37fe2a2a1b --- /dev/null +++ b/cmd/profilecli/kube_proxy.go @@ -0,0 +1,565 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "os" + "os/exec" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/go-kit/log/level" +) + +type kubeProxyParams struct { + *phlareClient + Context string + Namespace string + LabelSelector string + ListenAddr string +} + +type pyroscopeService struct { + Name string // e.g., "pyroscope-distributor" + Component string // e.g., "distributor" + Port int // Service port + PortName string // e.g., "http" +} + +type routingRule struct { + PathPrefix string // e.g., "/ingest" + Component string // e.g., "distributor" +} + +type reverseProxyManager struct { + params *kubeProxyParams + services map[string]*pyroscopeService // component -> service + kubectlProcess *exec.Cmd + kubectlSocketPath string + routingRules []routingRule + httpServer *http.Server + ctx context.Context + cancel context.CancelFunc +} + +func addKubeProxyParams(cmd commander) *kubeProxyParams { + params := &kubeProxyParams{} + params.phlareClient = addPhlareClient(cmd) + + cmd.Flag("context", "Kubernetes context to use").Short('c').Default("").Envar("KUBERNETES_CONTEXT").StringVar(¶ms.Context) + cmd.Flag("namespace", "Kubernetes namespace").Short('n').Default("default").Envar("KUBERNETES_NAMESPACE").StringVar(¶ms.Namespace) + cmd.Flag("label-selector", "Label selector for Pyroscope services").Short('l'). + Default("").StringVar(¶ms.LabelSelector) + cmd.Flag("listen-addr", "Address to listen on (host:port)"). + Default("127.0.0.1:4242").StringVar(¶ms.ListenAddr) + + return params +} + +func kubeProxyCommand(ctx context.Context, params *kubeProxyParams) error { + mgr := &reverseProxyManager{ + params: params, + } + mgr.ctx, mgr.cancel = context.WithCancel(ctx) + defer mgr.cancel() + + // Discover services + if err := mgr.discoverServices(); err != nil { + return fmt.Errorf("service discovery failed: %w", err) + } + + // Start kubectl proxy in background + if err := mgr.startKubectlProxy(); err != nil { + return fmt.Errorf("failed to start kubectl proxy: %w", err) + } + + // Initialize routing rules + mgr.initRoutingRules() + + // Start reverse proxy server + if err := mgr.startReverseProxy(); err != nil { + mgr.shutdown() + return fmt.Errorf("failed to start reverse proxy: %w", err) + } + + // Print connection info + mgr.printConnectionInfo() + + // Wait for shutdown signal + return mgr.run() +} + +func (m *reverseProxyManager) discoverServices() error { + args := []string{ + "get", "services", + "--selector", m.params.LabelSelector, + "-o", "json", + } + + if m.params.Context != "" { + args = append([]string{"--context", m.params.Context}, args...) + } + args = append([]string{"--namespace", m.params.Namespace}, args...) + + cmd := exec.Command("kubectl", args...) + output, err := cmd.Output() + if err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + return fmt.Errorf("kubectl failed: %s", string(exitErr.Stderr)) + } + return fmt.Errorf("failed to run kubectl: %w", err) + } + + var serviceList struct { + Items []struct { + Metadata struct { + Name string `json:"name"` + Labels map[string]string `json:"labels"` + } `json:"metadata"` + Spec struct { + ClusterIP string `json:"clusterIP"` + Ports []struct { + Name string `json:"name"` + Port int `json:"port"` + } `json:"ports"` + } `json:"spec"` + } `json:"items"` + } + + if err := json.Unmarshal(output, &serviceList); err != nil { + return fmt.Errorf("failed to parse services JSON: %w", err) + } + + // Filter to user-facing services only + allowedComponents := map[string]bool{ + "distributor": true, + "query-frontend": true, + "tenant-settings": true, + "ad-hoc-profiles": true, + } + + m.services = make(map[string]*pyroscopeService) + + for _, item := range serviceList.Items { + // Skip headless services + if item.Spec.ClusterIP == "None" { + level.Debug(logger).Log("msg", "skipping headless service", "name", item.Metadata.Name) + continue + } + + component := item.Metadata.Labels["app.kubernetes.io/component"] + if component == "" || !allowedComponents[component] { + continue + } + + // Find HTTP port + var port int + var portName string + for _, p := range item.Spec.Ports { + if p.Name == "http" || p.Name == "http-metrics" { + port = p.Port + portName = p.Name + break + } + } + if port == 0 && len(item.Spec.Ports) > 0 { + port = item.Spec.Ports[0].Port + portName = item.Spec.Ports[0].Name + } + + m.services[component] = &pyroscopeService{ + Name: item.Metadata.Name, + Component: component, + Port: port, + PortName: portName, + } + + level.Info(logger).Log("msg", "discovered service", "name", item.Metadata.Name, "component", component) + } + + if len(m.services) == 0 { + return fmt.Errorf("no user-facing Pyroscope services found (looking for: distributor, query-frontend, tenant-settings, ad-hoc-profiles)") + } + + return nil +} + +func (m *reverseProxyManager) startKubectlProxy() error { + // Create Unix socket path for kubectl proxy + m.kubectlSocketPath = "/tmp/pyroscope-kubectl-proxy.sock" + + // Remove socket if it already exists + if _, err := os.Stat(m.kubectlSocketPath); err == nil { + if err := os.Remove(m.kubectlSocketPath); err != nil { + return fmt.Errorf("failed to remove existing kubectl socket: %w", err) + } + } + + args := []string{ + "proxy", + "--unix-socket", m.kubectlSocketPath, + "--disable-filter=true", + } + + if m.params.Context != "" { + args = append([]string{"--context", m.params.Context}, args...) + } + + cmd := exec.CommandContext(m.ctx, "kubectl", args...) + + // Capture stderr for error reporting + stderr := &strings.Builder{} + cmd.Stderr = stderr + + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start kubectl proxy: %w", err) + } + + m.kubectlProcess = cmd + level.Info(logger).Log("msg", "started kubectl proxy", "socket", m.kubectlSocketPath, "pid", cmd.Process.Pid) + + // Wait for kubectl proxy to be ready + if err := m.waitForKubectlProxy(); err != nil { + if stderr.Len() > 0 { + return fmt.Errorf("%w (stderr: %s)", err, stderr.String()) + } + return err + } + + // Set appropriate permissions on the socket (user only) + if err := os.Chmod(m.kubectlSocketPath, 0600); err != nil { + level.Warn(logger).Log("msg", "failed to set kubectl socket permissions", "err", err) + } + + return nil +} + +func (m *reverseProxyManager) waitForKubectlProxy() error { + timeout := time.After(10 * time.Second) + ticker := time.NewTicker(200 * time.Millisecond) + defer ticker.Stop() + + client := &http.Client{ + Transport: &http.Transport{ + DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { + return net.Dial("unix", m.kubectlSocketPath) + }, + }, + Timeout: 2 * time.Second, + } + + for { + select { + case <-timeout: + return fmt.Errorf("timeout waiting for kubectl proxy to start") + case <-ticker.C: + // Check if socket exists + if _, err := os.Stat(m.kubectlSocketPath); err != nil { + continue + } + + // Try to connect + resp, err := client.Get("http://unix/api") + if err == nil { + resp.Body.Close() + level.Info(logger).Log("msg", "kubectl proxy is ready") + return nil + } + } + } +} + +func (m *reverseProxyManager) initRoutingRules() { + // Order matters - most specific first! + m.routingRules = []routingRule{ + // Distributor (write path) + {PathPrefix: "/push.v1.PusherService/", Component: "distributor"}, + {PathPrefix: "/ingest", Component: "distributor"}, + {PathPrefix: "/pyroscope/ingest", Component: "distributor"}, + {PathPrefix: "/v1development/profiles", Component: "distributor"}, + {PathPrefix: "/opentelemetry.proto.collector.profiles", Component: "distributor"}, + + // Tenant Settings + {PathPrefix: "/settings.v1.SettingsService/", Component: "tenant-settings"}, + {PathPrefix: "/settings.v1.RecordingRulesService/", Component: "tenant-settings"}, + + // Ad-Hoc Profiles + {PathPrefix: "/adhocprofiles.v1.AdHocProfileService/", Component: "ad-hoc-profiles"}, + + // Default to query-frontend for root and UI paths + {PathPrefix: "/", Component: "query-frontend"}, + } +} + +func (m *reverseProxyManager) startReverseProxy() error { + mux := http.NewServeMux() + mux.HandleFunc("/", m.handleRequest) + + m.httpServer = &http.Server{ + Handler: mux, + } + + listener, err := net.Listen("tcp", m.params.ListenAddr) + if err != nil { + return fmt.Errorf("failed to listen on %s: %w", m.params.ListenAddr, err) + } + + level.Info(logger).Log("msg", "reverse proxy listening", "addr", m.params.ListenAddr) + + // Start serving in background + go func() { + if err := m.httpServer.Serve(listener); err != nil && err != http.ErrServerClosed { + level.Error(logger).Log("msg", "HTTP server error", "err", err) + } + }() + + return nil +} + +func (m *reverseProxyManager) handleRequest(w http.ResponseWriter, r *http.Request) { + // Route to appropriate service + svc, err := m.routeRequest(r) + if err != nil { + level.Warn(logger).Log("msg", "routing failed", "err", err, "path", r.URL.Path) + http.Error(w, fmt.Sprintf("Routing error: %v", err), http.StatusBadGateway) + return + } + + level.Debug(logger).Log("msg", "routing request", "method", r.Method, "path", r.URL.Path, "service", svc.Name, "component", svc.Component) + + // Proxy to service via kubectl + m.proxyToService(w, r, svc) +} + +func (m *reverseProxyManager) routeRequest(r *http.Request) (*pyroscopeService, error) { + path := r.URL.Path + + // Check each routing rule + for _, rule := range m.routingRules { + if strings.HasPrefix(path, rule.PathPrefix) { + // Find service for this component + svc, ok := m.services[rule.Component] + if !ok { + return nil, fmt.Errorf("service not found for component: %s", rule.Component) + } + + return svc, nil + } + } + + return nil, fmt.Errorf("no routing rule matched for path: %s", path) +} + +func (m *reverseProxyManager) proxyToService(w http.ResponseWriter, r *http.Request, svc *pyroscopeService) { + // Build target URL via kubectl proxy (using unix socket) + targetPath := fmt.Sprintf( + "/api/v1/namespaces/%s/services/%s:%s/proxy%s", + m.params.Namespace, + svc.Name, + svc.PortName, + r.URL.Path, + ) + + // Add query string if present + if r.URL.RawQuery != "" { + targetPath += "?" + r.URL.RawQuery + } + + targetURL := "http://unix" + targetPath + + // Create proxy request + proxyReq, err := http.NewRequestWithContext(r.Context(), r.Method, targetURL, r.Body) + if err != nil { + level.Error(logger).Log("msg", "failed to create proxy request", "err", err) + http.Error(w, "Failed to create proxy request", http.StatusInternalServerError) + return + } + + // Copy headers, but skip Authorization to avoid interfering with kubectl's auth + for key, values := range r.Header { + // Skip Authorization header - kubectl proxy uses kubeconfig auth, not incoming auth + if key == "Authorization" { + level.Debug(logger).Log("msg", "skipping Authorization header from incoming request") + continue + } + for _, value := range values { + proxyReq.Header.Add(key, value) + } + } + + // Inject tenant ID if configured + if m.params.TenantID != "" { + proxyReq.Header.Set("X-Scope-OrgID", m.params.TenantID) + level.Debug(logger).Log("msg", "injected tenant ID", "tenant_id", m.params.TenantID) + } + + // Execute request via Unix socket + client := &http.Client{ + Transport: &http.Transport{ + DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { + return net.Dial("unix", m.kubectlSocketPath) + }, + }, + Timeout: 5 * time.Minute, + } + + resp, err := client.Do(proxyReq) + if err != nil { + level.Error(logger).Log("msg", "proxy request failed", "err", err, "path", targetPath) + http.Error(w, fmt.Sprintf("Proxy error: %v", err), http.StatusBadGateway) + return + } + defer resp.Body.Close() + + // Copy response headers + for key, values := range resp.Header { + for _, value := range values { + w.Header().Add(key, value) + } + } + + // Copy status code + w.WriteHeader(resp.StatusCode) + + // Copy response body + io.Copy(w, resp.Body) +} + +func (m *reverseProxyManager) printConnectionInfo() { + baseURL := fmt.Sprintf("curl http://%s", m.params.ListenAddr) + + fmt.Fprintf(output(m.ctx), "\nPyroscope Kubernetes Reverse Proxy\n") + fmt.Fprintf(output(m.ctx), "===================================\n\n") + fmt.Fprintf(output(m.ctx), "Context: %s\n", m.params.Context) + fmt.Fprintf(output(m.ctx), "Namespace: %s\n", m.params.Namespace) + fmt.Fprintf(output(m.ctx), "Services: %d discovered\n", len(m.services)) + fmt.Fprintf(output(m.ctx), "Listening: %s\n\n", m.params.ListenAddr) + + fmt.Fprintf(output(m.ctx), "Routing Examples:\n") + fmt.Fprintf(output(m.ctx), "-----------------\n\n") + + // Show routing examples for each service + type example struct { + title string + cmds []string + } + + examples := map[string]example{ + "query-frontend": { + title: "Query profiles:", + cmds: []string{ + fmt.Sprintf(" %s/render?query=process_cpu&from=now-1h", baseURL), + fmt.Sprintf(" %s/querier.v1.QuerierService/ProfileTypes -X POST -d '{}' -H 'content-type: application/json'", baseURL), + }, + }, + "distributor": { + title: "Push profiles:", + cmds: []string{ + fmt.Sprintf(" %s/ingest -X POST -d @profile.pprof", baseURL), + }, + }, + "tenant-settings": { + title: "Manage settings:", + cmds: []string{ + fmt.Sprintf(" %s/settings.v1.SettingsService/Get -X POST -d '{}' -H 'content-type: application/json'", baseURL), + }, + }, + "ad-hoc-profiles": { + title: "Ad-hoc profiles:", + cmds: []string{ + fmt.Sprintf(" %s/adhocprofiles.v1.AdHocProfileService/List -X POST -d '{}' -H 'content-type: application/json'", baseURL), + }, + }, + } + + // Display in logical order + for _, component := range []string{"query-frontend", "distributor", "tenant-settings", "ad-hoc-profiles"} { + if _, ok := m.services[component]; !ok { + continue + } + + if ex, ok := examples[component]; ok { + fmt.Fprintf(output(m.ctx), "%s\n", ex.title) + for _, cmd := range ex.cmds { + fmt.Fprintf(output(m.ctx), "%s\n", cmd) + } + fmt.Fprintf(output(m.ctx), "\n") + } + } + + fmt.Fprintf(output(m.ctx), "The proxy automatically routes requests to the correct service!\n") + fmt.Fprintf(output(m.ctx), "\nPress Ctrl+C to stop\n") +} + +func (m *reverseProxyManager) run() error { + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) + + processDone := make(chan error, 1) + go func() { + processDone <- m.kubectlProcess.Wait() + }() + + select { + case sig := <-sigChan: + level.Info(logger).Log("msg", "received signal", "signal", sig) + return m.shutdown() + case err := <-processDone: + if err != nil { + level.Error(logger).Log("msg", "kubectl proxy exited unexpectedly", "err", err) + } + m.shutdown() + return err + } +} + +func (m *reverseProxyManager) shutdown() error { + level.Info(logger).Log("msg", "shutting down") + + // Stop HTTP server + if m.httpServer != nil { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := m.httpServer.Shutdown(ctx); err != nil { + level.Warn(logger).Log("msg", "HTTP server shutdown error", "err", err) + } + } + + // Stop kubectl proxy + if m.kubectlProcess != nil && m.kubectlProcess.Process != nil { + if err := m.kubectlProcess.Process.Signal(syscall.SIGTERM); err != nil { + level.Warn(logger).Log("msg", "failed to send SIGTERM to kubectl", "err", err) + m.kubectlProcess.Process.Kill() + } + + done := make(chan error, 1) + go func() { + done <- m.kubectlProcess.Wait() + }() + + select { + case <-time.After(5 * time.Second): + level.Warn(logger).Log("msg", "kubectl proxy didn't stop, killing") + m.kubectlProcess.Process.Kill() + case <-done: + } + } + + // Clean up kubectl socket + if m.kubectlSocketPath != "" { + if err := os.Remove(m.kubectlSocketPath); err != nil && !os.IsNotExist(err) { + level.Warn(logger).Log("msg", "failed to remove kubectl socket", "err", err) + } else { + level.Info(logger).Log("msg", "removed kubectl socket", "path", m.kubectlSocketPath) + } + } + + level.Info(logger).Log("msg", "shutdown complete") + return nil +} diff --git a/cmd/profilecli/main.go b/cmd/profilecli/main.go index 124b160cff..0ded4424c2 100644 --- a/cmd/profilecli/main.go +++ b/cmd/profilecli/main.go @@ -7,13 +7,13 @@ import ( "os" "path/filepath" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/common/version" - "gopkg.in/alecthomas/kingpin.v2" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - _ "github.com/grafana/pyroscope/pkg/util/build" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + _ "github.com/grafana/pyroscope/v2/pkg/util/build" ) var cfg struct { @@ -46,7 +46,7 @@ func main() { adminCmd := app.Command("admin", "Administrative tasks for Pyroscope cluster operators.") blocksCmd := adminCmd.Command("blocks", "Operate on Grafana Pyroscope's blocks.") - blocksCmd.Flag("path", "Path to blocks directory").Default("./data/local").StringVar(&cfg.blocks.path) + blocksCmd.Flag("path", "Path to blocks directory").Default("./data/anonymous/local").StringVar(&cfg.blocks.path) blocksListCmd := blocksCmd.Command("list", "List blocks.") blocksListCmd.Flag("restore-missing-meta", "").Default("false").BoolVar(&cfg.blocks.restoreMissingMeta) @@ -56,6 +56,12 @@ func main() { blocksCompactCmd.Arg("dest", "The destination where compacted blocks should be stored.").Required().StringVar(&cfg.blocks.compact.dst) blocksCompactCmd.Flag("shards", "The amount of shards to split output blocks into.").Default("0").IntVar(&cfg.blocks.compact.shards) + blocksQueryCmd := blocksCmd.Command("query", "Query on local/remote blocks.") + blocksQuerySeriesCmd := blocksQueryCmd.Command("series", "Request series labels on local/remote blocks.") + blocksQuerySeriesParams := addBlocksQuerySeriesParams(blocksQuerySeriesCmd) + blocksQueryProfileCmd := blocksQueryCmd.Command("profile", "Request merged profile on local/remote block.").Alias("merge") + blocksQueryProfileParams := addBlocksQueryProfileParams(blocksQueryProfileCmd) + parquetCmd := adminCmd.Command("parquet", "Operate on a Parquet file.") parquetInspectCmd := parquetCmd.Command("inspect", "Inspect a parquet file's structure.") parquetInspectFiles := parquetInspectCmd.Arg("file", "parquet file path").Required().ExistingFiles() @@ -65,11 +71,29 @@ func main() { tsdbSeriesFiles := tsdbSeriesCmd.Arg("file", "tsdb file path").Required().ExistingFiles() queryCmd := app.Command("query", "Query profile store.") - queryMergeCmd := queryCmd.Command("merge", "Request merged profile.") - queryMergeOutput := queryMergeCmd.Flag("output", "How to output the result, examples: console, raw, pprof=./my.pprof").Default("console").String() - queryMergeParams := addQueryMergeParams(queryMergeCmd) + queryProfileCmd := queryCmd.Command("profile", "Request merged profile.").Alias("merge") + queryProfileOutput := queryProfileCmd.Flag("output", "How to output the result, examples: console, raw, pprof=./my.pprof").Default("console").String() + queryProfileForce := queryProfileCmd.Flag("force", "Overwrite the output file if it already exists.").Short('f').Default("false").Bool() + queryProfileFunctionNamesOnly := queryProfileCmd.Flag("function-names-only", "Faster call, without details about mappings, line number, and inlining").Default("false").Bool() + queryProfileAsync := queryProfileCmd.Flag("async", "Force async query execution, polling until results are ready.").Default("false").Bool() + queryProfileParams := addQueryProfileParams(queryProfileCmd) + queryProfileCmd.Flag("profile-id", "Profile ID (UUID) to query a specific profile. Repeatable for multiple IDs. Use 'query exemplars profile' to find IDs.").StringsVar(&queryProfileParams.ProfileIDs) + queryProfileCmd.Flag("trace-id", "Trace ID (32 hex characters) to filter samples by. Repeatable for multiple traces.").StringsVar(&queryProfileParams.TraceIDs) + queryGoPGOCmd := queryCmd.Command("go-pgo", "Request profile for Go PGO.") + queryGoPGOOutput := queryGoPGOCmd.Flag("output", "How to output the result, examples: console, raw, pprof=./my.pprof").Default("pprof=./default.pgo").String() + queryGoPGOForce := queryGoPGOCmd.Flag("force", "Overwrite the output file if it already exists.").Short('f').Default("false").Bool() + queryGoPGOParams := addQueryGoPGOParams(queryGoPGOCmd) querySeriesCmd := queryCmd.Command("series", "Request series labels.") querySeriesParams := addQuerySeriesParams(querySeriesCmd) + queryLabelValuesCardinalityCmd := queryCmd.Command("label-values-cardinality", "Request label values cardinality.") + queryLabelValuesCardinalityParams := addQueryLabelValuesCardinalityParams(queryLabelValuesCardinalityCmd) + queryTopCmd := queryCmd.Command("top", "List top N label values by total value for a time window.") + queryTopParams := addQueryTopParams(queryTopCmd) + queryExemplarsCmd := queryCmd.Command("exemplars", "Query exemplars from profile data. V2 only.") + queryExemplarsProfileCmd := queryExemplarsCmd.Command("profile", "List profile exemplars for a time window.") + queryExemplarsParams := addQueryExemplarsParams(queryExemplarsProfileCmd) + queryExemplarsSpanCmd := queryExemplarsCmd.Command("span", "List span exemplars for a time window. Requires span-aware SDK instrumentation. V2 only.") + queryExemplarsSpanParams := addQueryExemplarsParams(queryExemplarsSpanCmd) queryTracerCmd := app.Command("query-tracer", "Analyze query traces.") queryTracerParams := addQueryTracerParams(queryTracerCmd) @@ -84,6 +108,51 @@ func main() { bucketWebCmd := bucketCmd.Command("web", "Run the web tool for visualizing blocks in object-store buckets.") bucketWebParams := addBucketWebToolParams(bucketWebCmd) + bucketListV2Cmd := bucketCmd.Command("list-v2-blocks", "List Pyroscope v2 segments and blocks in object-store buckets.") + bucketListV2Params := addBucketParams(bucketListV2Cmd) + + bucketInspectV2Cmd := bucketCmd.Command("inspect-v2-blocks", "Inspect Pyroscope v2 segments and blocks in object-store buckets.") + bucketInspectV2Params := addBucketParams(bucketInspectV2Cmd) + bucketInspectV2Paths := bucketInspectV2Cmd.Arg("path", "block paths").Required().Strings() + + readyCmd := app.Command("ready", "Check Pyroscope health.") + readyParams := addReadyParams(readyCmd) + + sourceCodeCmd := app.Command("source-code", "Operations on source code mappings and configurations.") + sourceCodeCoverageCmd := sourceCodeCmd.Command("coverage", "Measure the coverage of .pyroscope.yaml source code mappings for translating function names/paths from a pprof profile to VCS source files.") + sourceCodeCoverageParams := addSourceCodeCoverageParams(sourceCodeCoverageCmd) + + raftCmd := adminCmd.Command("raft", "Operate on Raft cluster.") + raftInfoCmd := raftCmd.Command("info", "Print info about a Raft node.") + raftInfoParams := addRaftInfoParams(raftInfoCmd) + + v2MigrationCmd := adminCmd.Command("v2-migration", "Operation to aid the v1 to v2 storage migration.") + v2MigrationBucketCleanupCmd := v2MigrationCmd.Command("bucket-cleanup", "Clean up v1 artificats from data bucket.") + v2MigrationBucketCleanupParams := addV2MigrationBackupCleanupParam(v2MigrationBucketCleanupCmd) + + kubeProxyCmd := adminCmd.Command("kube-proxy", "Start a reverse proxy unifying all the micro services in a single endpoint.") + kubeProxyParams := addKubeProxyParams(kubeProxyCmd) + + recordingRulesCmd := app.Command("recording-rules", "Operations on recording rules. When accessing a Grafana Cloud datasource, requires a token with the \"profiles-config:read\" and/or \"profiles-config:write\" scopes.") + recordingRulesListCmd := recordingRulesCmd.Command("list", "List recording rules. When accessing a Grafana Cloud datasource, requires a token with the \"profiles-config:read\" scope.") + recordingRulesGetCmd := recordingRulesCmd.Command("get", "Get a specific recording rule. When accessing a Grafana Cloud datasource, requires a token with the \"profiles-config:read\" scope.") + recordingRulesGetId := recordingRulesGetCmd.Arg("rule_id", "Recording rule Id to retrieve").Required().String() + recordingRulesGetOutput := recordingRulesGetCmd.Flag("output", "Write rule to file instead of stdout").Short('o').String() + recordingRulesCreateCmd := recordingRulesCmd.Command("create", "Create a recording rule. When accessing a Grafana Cloud datasource, requires a token with the \"profiles-config:write\" scope.\n"+createRuleExampleMsg) + recordingRulesCreateFile := recordingRulesCreateCmd.Flag("file", "Path to YAML or JSON file containing the recording rule definition").Short('f').Required().String() + + recordingRulesDeleteCmd := recordingRulesCmd.Command("delete", "Delete a recording rule. When accessing a Grafana Cloud datasource, requires a token with the \"profiles-config:write\" scope.") + recordingRulesDeleteId := recordingRulesDeleteCmd.Arg("rule_id", "Recording rule Id to delete").Required().String() + recordingRulesParams := addRecordingRulesListParams(recordingRulesCmd) + + debuginfoCmd := app.Command("debuginfo", "Operations on debuginfo (experimental).") + debuginfoUploadCmd := debuginfoCmd.Command("upload", "Upload debuginfo.") + debuginfoUploadParams := addDebuginfoUploadParams(debuginfoUploadCmd) + debuginfoListCmd := debuginfoCmd.Command("list", "List debuginfo.") + debuginfoListParams := addDebuginfoListParams(debuginfoListCmd) + debuginfoDeleteCmd := debuginfoCmd.Command("delete", "Delete debuginfo by GNU build ID.") + debuginfoDeleteParams := addDebuginfoDeleteParams(debuginfoDeleteCmd) + // parse command line arguments parsedCmd := kingpin.MustParse(app.Parse(os.Args[1:])) @@ -107,8 +176,12 @@ func main() { os.Exit(checkError(err)) } } - case queryMergeCmd.FullCommand(): - if err := queryMerge(ctx, queryMergeParams, *queryMergeOutput); err != nil { + case queryProfileCmd.FullCommand(): + if err := queryProfile(ctx, queryProfileParams, *queryProfileOutput, *queryProfileForce, *queryProfileFunctionNamesOnly, *queryProfileAsync); err != nil { + os.Exit(checkError(err)) + } + case queryGoPGOCmd.FullCommand(): + if err := queryGoPGO(ctx, queryGoPGOParams, *queryGoPGOOutput, *queryGoPGOForce); err != nil { os.Exit(checkError(err)) } case querySeriesCmd.FullCommand(): @@ -116,6 +189,32 @@ func main() { os.Exit(checkError(err)) } + case blocksQuerySeriesCmd.FullCommand(): + if err := blocksQuerySeries(ctx, blocksQuerySeriesParams); err != nil { + os.Exit(checkError(err)) + } + case blocksQueryProfileCmd.FullCommand(): + if err := blocksQueryProfile(ctx, blocksQueryProfileParams); err != nil { + os.Exit(checkError(err)) + } + + case queryLabelValuesCardinalityCmd.FullCommand(): + if err := queryLabelValuesCardinality(ctx, queryLabelValuesCardinalityParams); err != nil { + os.Exit(checkError(err)) + } + case queryTopCmd.FullCommand(): + if err := queryTop(ctx, queryTopParams); err != nil { + os.Exit(checkError(err)) + } + case queryExemplarsProfileCmd.FullCommand(): + if err := queryExemplars(ctx, queryExemplarsParams); err != nil { + os.Exit(checkError(err)) + } + case queryExemplarsSpanCmd.FullCommand(): + if err := querySpanExemplars(ctx, queryExemplarsSpanParams); err != nil { + os.Exit(checkError(err)) + } + case queryTracerCmd.FullCommand(): if err := queryTracer(ctx, queryTracerParams); err != nil { os.Exit(checkError(err)) @@ -133,21 +232,82 @@ func main() { if err := newBucketWebTool(bucketWebParams).run(ctx); err != nil { os.Exit(checkError(err)) } + case bucketListV2Cmd.FullCommand(): + if err := bucketListV2(ctx, bucketListV2Params); err != nil { + os.Exit(checkError(err)) + } + case bucketInspectV2Cmd.FullCommand(): + if err := bucketInspectV2(ctx, bucketInspectV2Params, *bucketInspectV2Paths); err != nil { + os.Exit(checkError(err)) + } case blocksCompactCmd.FullCommand(): if err := blocksCompact(ctx, cfg.blocks.compact.src, cfg.blocks.compact.dst, cfg.blocks.compact.shards); err != nil { os.Exit(checkError(err)) } + case readyCmd.FullCommand(): + if err := ready(ctx, readyParams); err != nil { + os.Exit(checkError(err)) + } + case sourceCodeCoverageCmd.FullCommand(): + if err := sourceCodeCoverage(ctx, sourceCodeCoverageParams); err != nil { + os.Exit(checkError(err)) + } + case raftInfoCmd.FullCommand(): + if err := raftInfo(ctx, raftInfoParams); err != nil { + os.Exit(checkError(err)) + } + case v2MigrationBucketCleanupCmd.FullCommand(): + if err := v2MigrationBucketCleanup(ctx, v2MigrationBucketCleanupParams); err != nil { + os.Exit(checkError(err)) + } + case kubeProxyCmd.FullCommand(): + if err := kubeProxyCommand(ctx, kubeProxyParams); err != nil { + os.Exit(checkError(err)) + } + case recordingRulesListCmd.FullCommand(): + if err := listRecordingRules(ctx, recordingRulesParams); err != nil { + os.Exit(checkError(err)) + } + case recordingRulesGetCmd.FullCommand(): + if err := getRecordingRule(ctx, recordingRulesGetId, recordingRulesGetOutput, recordingRulesParams); err != nil { + os.Exit(checkError(err)) + } + case recordingRulesCreateCmd.FullCommand(): + if err := createRecordingRule(ctx, recordingRulesCreateFile, recordingRulesParams); err != nil { + os.Exit(checkError(err)) + } + case recordingRulesDeleteCmd.FullCommand(): + if err := deleteRecordingRule(ctx, recordingRulesDeleteId, recordingRulesParams); err != nil { + os.Exit(checkError(err)) + } + case debuginfoUploadCmd.FullCommand(): + if err := uploadDebuginfo(ctx, debuginfoUploadParams); err != nil { + os.Exit(checkError(err)) + } + case debuginfoListCmd.FullCommand(): + if err := listDebuginfo(ctx, debuginfoListParams); err != nil { + os.Exit(checkError(err)) + } + case debuginfoDeleteCmd.FullCommand(): + if err := deleteDebuginfo(ctx, debuginfoDeleteParams); err != nil { + os.Exit(checkError(err)) + } default: level.Error(logger).Log("msg", "unknown command", "cmd", parsedCmd) } } func checkError(err error) int { - if err != nil { + switch err { + case nil: + return 0 + case notReadyErr: + // The reason for the failed ready is already logged, so just exit with + // an error code. + default: fmt.Fprintf(os.Stderr, "error: %v\n", err) - return 1 } - return 0 + return 1 } type contextKey uint8 diff --git a/cmd/profilecli/my.pprof b/cmd/profilecli/my.pprof deleted file mode 100644 index 02b748a080..0000000000 Binary files a/cmd/profilecli/my.pprof and /dev/null differ diff --git a/cmd/profilecli/output.go b/cmd/profilecli/output.go new file mode 100644 index 0000000000..db7780dea8 --- /dev/null +++ b/cmd/profilecli/output.go @@ -0,0 +1,154 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "sort" + "strings" + "time" + + gprofile "github.com/google/pprof/profile" + "github.com/grafana/dskit/runutil" + "github.com/klauspost/compress/gzip" + "github.com/olekukonko/tablewriter" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +const ( + outputConsole = "console" + outputPprof = "pprof=" + outputJSON = "json" +) + +func newTableWriter(w io.Writer) *tablewriter.Table { + t := tablewriter.NewWriter(w) + t.SetAutoFormatHeaders(false) + return t +} + +func outputSeries(ctx context.Context, result []*typesv1.Labels, format string, from, to time.Time) error { + switch format { + case outputJSON: + return outputSeriesJSON(ctx, result, from, to) + default: + return outputSeriesTable(ctx, result) + } +} + +func outputSeriesJSON(ctx context.Context, result []*typesv1.Labels, from, to time.Time) error { + type jsonOutput struct { + From time.Time `json:"from"` + To time.Time `json:"to"` + Series []map[string]string `json:"series"` + } + out := jsonOutput{ + From: from, + To: to, + Series: make([]map[string]string, len(result)), + } + for i, s := range result { + m := make(map[string]string, len(s.Labels)) + for _, l := range s.Labels { + m[l.Name] = l.Value + } + out.Series[i] = m + } + enc := json.NewEncoder(output(ctx)) + enc.SetIndent("", " ") + return enc.Encode(out) +} + +func outputSeriesTable(ctx context.Context, result []*typesv1.Labels) error { + if len(result) == 0 { + return nil + } + + // Collect all unique label names in a stable order. + seen := make(map[string]struct{}) + var colNames []string + for _, s := range result { + for _, l := range s.Labels { + if _, ok := seen[l.Name]; !ok { + seen[l.Name] = struct{}{} + colNames = append(colNames, l.Name) + } + } + } + sort.Strings(colNames) + + table := newTableWriter(output(ctx)) + table.SetHeader(colNames) + for _, s := range result { + vals := make(map[string]string, len(s.Labels)) + for _, l := range s.Labels { + vals[l.Name] = l.Value + } + row := make([]string, len(colNames)) + for i, name := range colNames { + row[i] = vals[name] + } + table.Append(row) + } + table.Render() + return nil +} + +func outputMergeProfile(ctx context.Context, outputFlag string, force bool, profile *googlev1.Profile) error { + if outputFlag == outputConsole { + buf, err := profile.MarshalVT() + if err != nil { + return fmt.Errorf("failed to marshal protobuf: %w", err) + } + + p, err := gprofile.Parse(bytes.NewReader(buf)) + if err != nil { + return fmt.Errorf("failed to parse profile: %w", err) + } + + fmt.Fprintln(output(ctx), p.String()) + return nil + + } + + if strings.HasPrefix(outputFlag, outputPprof) { + filePath := strings.TrimPrefix(outputFlag, outputPprof) + if filePath == "" { + return errors.New("no file path specified after pprof=") + } + buf, err := profile.MarshalVT() + if err != nil { + return fmt.Errorf("failed to marshal protobuf: %w", err) + } + + // open new file, fail when the file already exists unless force is set + flags := os.O_RDWR | os.O_CREATE + if force { + flags |= os.O_TRUNC + } else { + flags |= os.O_EXCL + } + f, err := os.OpenFile(filePath, flags, 0644) + if err != nil { + return fmt.Errorf("failed to create pprof file: %w", err) + } + defer runutil.CloseWithErrCapture(&err, f, "failed to close pprof file") + + gzipWriter := gzip.NewWriter(f) + defer runutil.CloseWithErrCapture(&err, gzipWriter, "failed to close pprof gzip writer") + + if _, err := io.Copy(gzipWriter, bytes.NewReader(buf)); err != nil { + return fmt.Errorf("failed to write pprof: %w", err) + } + + return nil + } + + return fmt.Errorf("unknown output %s", outputFlag) +} diff --git a/cmd/profilecli/output_test.go b/cmd/profilecli/output_test.go new file mode 100644 index 0000000000..e7d0c24f23 --- /dev/null +++ b/cmd/profilecli/output_test.go @@ -0,0 +1,62 @@ +package main + +import ( + "bytes" + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +// TestOutputSeriesTable_LabelNamesPreserved verifies that label names are +// rendered exactly as received: no uppercasing, no character stripping. +func TestOutputSeriesTable_LabelNamesPreserved(t *testing.T) { + t.Parallel() + + series := []*typesv1.Labels{ + {Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "frontend"}, + {Name: "http.method", Value: "GET"}, + {Name: "camelCase", Value: "val1"}, + }}, + {Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "backend"}, + {Name: "http.method", Value: "POST"}, + {Name: "camelCase", Value: "val2"}, + }}, + } + + var buf bytes.Buffer + ctx := withOutput(context.Background(), &buf) + + err := outputSeriesTable(ctx, series) + require.NoError(t, err) + + out := buf.String() + + // Header names must appear as-is, not uppercased or modified. + assert.Contains(t, out, "service_name", "underscore label name must not be transformed") + assert.Contains(t, out, "http.method", "dot in label name must not be stripped") + assert.Contains(t, out, "camelCase", "mixed-case label name must not be uppercased") + + // Values must appear as-is. + assert.Contains(t, out, "frontend") + assert.Contains(t, out, "backend") + assert.Contains(t, out, "GET") + assert.Contains(t, out, "POST") +} + +// TestOutputSeriesTable_Empty verifies that an empty result produces no output. +func TestOutputSeriesTable_Empty(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + ctx := withOutput(context.Background(), &buf) + + err := outputSeriesTable(ctx, nil) + require.NoError(t, err) + assert.Empty(t, buf.String()) +} diff --git a/cmd/profilecli/parquet.go b/cmd/profilecli/parquet.go index bd9ab70bae..0266ee5c78 100644 --- a/cmd/profilecli/parquet.go +++ b/cmd/profilecli/parquet.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/dustin/go-humanize" - "github.com/olekukonko/tablewriter" "github.com/parquet-go/parquet-go" ) @@ -36,7 +35,7 @@ func parquetInspect(ctx context.Context, path string) error { fmt.Fprintln(out, "\t\t Row Count:", rg.NumRows) fmt.Fprintln(out, "\t\t Row size:", humanize.Bytes(uint64(rg.TotalByteSize))) fmt.Fprintln(out, "\t\t Columns:") - table := tablewriter.NewWriter(out) + table := newTableWriter(out) table.SetHeader([]string{ "Col", "Type", "NumVal", "TotalCompressedSize", "TotalUncompressedSize", "Compression", "%", "PageCount", "PageSize", }) diff --git a/cmd/profilecli/query-blocks.go b/cmd/profilecli/query-blocks.go new file mode 100644 index 0000000000..9352346c46 --- /dev/null +++ b/cmd/profilecli/query-blocks.go @@ -0,0 +1,193 @@ +package main + +import ( + "context" + "errors" + "fmt" + "math" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + + ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/gcs" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" +) + +type blocksQueryParams struct { + BucketName string + BlockIds []string + TenantID string + ObjectStoreType string + Query string +} + +type blocksQueryProfileParams struct { + *blocksQueryParams + Output string + Force bool + ProfileType string + StacktraceSelector []string +} + +type blocksQuerySeriesParams struct { + *blocksQueryParams + LabelNames []string + Output string +} + +func addBlocksQueryParams(queryCmd commander) *blocksQueryParams { + params := new(blocksQueryParams) + queryCmd.Flag("bucket-name", "The name of the object storage bucket.").StringVar(¶ms.BucketName) + queryCmd.Flag("object-store-type", "The type of the object storage (e.g., gcs).").Default("gcs").StringVar(¶ms.ObjectStoreType) + queryCmd.Flag("block", "Block ids to query on (accepts multiples)").StringsVar(¶ms.BlockIds) + queryCmd.Flag("tenant-id", "Tenant id of the queried block for remote bucket").StringVar(¶ms.TenantID) + queryCmd.Flag("query", "Label selector to query.").Default("{}").StringVar(¶ms.Query) + return params +} + +func addBlocksQueryProfileParams(queryCmd commander) *blocksQueryProfileParams { + params := new(blocksQueryProfileParams) + params.blocksQueryParams = addBlocksQueryParams(queryCmd) + queryCmd.Flag("output", "How to output the result, examples: console, raw, pprof=./my.pprof").Default("console").StringVar(¶ms.Output) + queryCmd.Flag("force", "Overwrite the output file if it already exists.").Short('f').Default("false").BoolVar(¶ms.Force) + queryCmd.Flag("profile-type", "Profile type to query.").Default("process_cpu:cpu:nanoseconds:cpu:nanoseconds").StringVar(¶ms.ProfileType) + queryCmd.Flag("stacktrace-selector", "Only query locations with those symbols. Provide multiple times starting with the root").StringsVar(¶ms.StacktraceSelector) + return params +} + +func addBlocksQuerySeriesParams(queryCmd commander) *blocksQuerySeriesParams { + params := new(blocksQuerySeriesParams) + params.blocksQueryParams = addBlocksQueryParams(queryCmd) + queryCmd.Flag("label-names", "Filter returned labels to the supplied label names. Without any filter all labels are returned.").StringsVar(¶ms.LabelNames) + queryCmd.Flag("output", "Output format, one of: table, json.").Default("table").StringVar(¶ms.Output) + return params +} + +func blocksQueryProfile(ctx context.Context, params *blocksQueryProfileParams) error { + level.Info(logger).Log("msg", "blocks query profile", "blockIds", fmt.Sprintf("%v", params.BlockIds), "path", + cfg.blocks.path, "bucketName", params.BucketName, "tenantId", params.TenantID, "query", params.Query, "type", params.ProfileType) + + if len(params.BlockIds) > 1 { + return errors.New("query profile is limited to a single block") + } + + profileType, err := model.ParseProfileTypeSelector(params.ProfileType) + if err != nil { + return err + } + + var stackTraceSelectors *typesv1.StackTraceSelector = nil + if len(params.StacktraceSelector) > 0 { + locations := make([]*typesv1.Location, 0, len(params.StacktraceSelector)) + for _, cs := range params.StacktraceSelector { + locations = append(locations, &typesv1.Location{ + Name: cs, + }) + } + stackTraceSelectors = &typesv1.StackTraceSelector{ + CallSite: locations, + } + level.Info(logger).Log("msg", "selecting with stackstrace selector", "call-site", fmt.Sprintf("%#+v", params.StacktraceSelector)) + } + + bucket, err := getBucket(ctx, params.blocksQueryParams) + if err != nil { + return err + } + + meta, err := phlaredb.NewBlockQuerier(ctx, bucket).BlockMeta(ctx, params.BlockIds[0]) + if err != nil { + return err + } + + resp, err := phlaredb.NewSingleBlockQuerierFromMeta(ctx, bucket, meta).SelectMergePprof( + ctx, + &ingestv1.SelectProfilesRequest{ + LabelSelector: params.Query, + Type: profileType, + Start: meta.MinTime.Time().UnixMilli(), + End: meta.MaxTime.Time().UnixMilli(), + }, + 0, + stackTraceSelectors, + ) + if err != nil { + return fmt.Errorf("failed to query: %w", err) + } + + return outputMergeProfile(ctx, params.Output, params.Force, resp) +} + +func blocksQuerySeries(ctx context.Context, params *blocksQuerySeriesParams) error { + level.Info(logger).Log("msg", "blocks query series", "labelNames", fmt.Sprintf("%v", params.LabelNames), + "blockIds", fmt.Sprintf("%v", params.BlockIds), "path", cfg.blocks.path, "bucketName", params.BucketName, "tenantId", params.TenantID) + + bucket, err := getBucket(ctx, params.blocksQueryParams) + if err != nil { + return err + } + + blockQuerier := phlaredb.NewBlockQuerier(ctx, bucket) + + if len(params.BlockIds) == 0 { + return errors.New("specify at least one --block to query") + } + + var from, to int64 + from, to = math.MaxInt64, math.MinInt64 + var targetBlockQueriers phlaredb.Queriers + for _, blockId := range params.BlockIds { + meta, err := blockQuerier.BlockMeta(ctx, blockId) + if err != nil { + return err + } + from = min(from, meta.MinTime.Time().UnixMilli()) + to = max(to, meta.MaxTime.Time().UnixMilli()) + targetBlockQueriers = append(targetBlockQueriers, phlaredb.NewSingleBlockQuerierFromMeta(ctx, bucket, meta)) + } + + response, err := targetBlockQueriers.Series(ctx, connect.NewRequest( + &ingestv1.SeriesRequest{ + Start: from, + End: to, + Matchers: []string{params.Query}, + LabelNames: params.LabelNames, + }, + )) + if err != nil { + return err + } + + return outputSeries(ctx, response.Msg.LabelsSet, params.Output, + time.UnixMilli(from), time.UnixMilli(to)) +} + +func getBucket(ctx context.Context, params *blocksQueryParams) (objstore.Bucket, error) { + if params.BucketName != "" { + return getRemoteBucket(ctx, params) + } else { + return filesystem.NewBucket(cfg.blocks.path) + } +} + +func getRemoteBucket(ctx context.Context, params *blocksQueryParams) (objstore.Bucket, error) { + if params.TenantID == "" { + return nil, errors.New("specify tenant id for remote bucket") + } + return objstoreclient.NewBucket(ctx, objstoreclient.Config{ + StorageBackendConfig: objstoreclient.StorageBackendConfig{ + Backend: params.ObjectStoreType, + GCS: gcs.Config{ + BucketName: params.BucketName, + }, + }, + Prefix: fmt.Sprintf("%s/phlaredb", params.TenantID), + }, params.BucketName) +} diff --git a/cmd/profilecli/query-exemplars.go b/cmd/profilecli/query-exemplars.go new file mode 100644 index 0000000000..802a6d6b2b --- /dev/null +++ b/cmd/profilecli/query-exemplars.go @@ -0,0 +1,483 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "sort" + "strings" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/olekukonko/tablewriter" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +type queryExemplarsParams struct { + *queryParams + ProfileType string + Output string + TopN uint64 + MaxLabelColumns int +} + +func addQueryExemplarsParams(queryCmd commander) *queryExemplarsParams { + params := new(queryExemplarsParams) + params.queryParams = addQueryParams(queryCmd) + queryCmd.Flag("profile-type", "Profile type to query.").Default("process_cpu:cpu:nanoseconds:cpu:nanoseconds").StringVar(¶ms.ProfileType) + queryCmd.Flag("output", "Output format, one of: table, json.").Default("table").StringVar(¶ms.Output) + queryCmd.Flag("top-n", "Maximum number of exemplars to show.").Default("100").Uint64Var(¶ms.TopN) + queryCmd.Flag("max-label-columns", "Maximum number of label columns to show in table output. Set to 0 to hide labels.").Default("3").IntVar(¶ms.MaxLabelColumns) + return params +} + +// exemplarEntry is a flattened representation of a single exemplar extracted +// from a SelectSeries response point. +type exemplarEntry struct { + ProfileID string + Timestamp time.Time + Value int64 + SpanID string + TraceID string + Labels map[string]string +} + +func queryExemplars(ctx context.Context, params *queryExemplarsParams) error { + from, to, err := params.parseFromTo() + if err != nil { + return err + } + + level.Info(logger).Log( + "msg", "querying exemplars", + "url", params.URL, + "from", from, + "to", to, + "query", params.Query, + "type", params.ProfileType, + "top_n", params.TopN, + ) + + // Calculate step: divide time range into approximately topN buckets so we + // get roughly one exemplar per bucket (DefaultMaxExemplarsPerPoint = 1). + rangeSeconds := to.Sub(from).Seconds() + stepSeconds := rangeSeconds / float64(params.TopN) + if stepSeconds < 1 { + stepSeconds = 1 + } + + qc := params.queryClient() + resp, err := qc.SelectSeries(ctx, connect.NewRequest(&querierv1.SelectSeriesRequest{ + ProfileTypeID: params.ProfileType, + LabelSelector: params.Query, + Start: from.UnixMilli(), + End: to.UnixMilli(), + Step: stepSeconds, + ExemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL, + })) + if err != nil { + return fmt.Errorf("failed to query exemplars: %w", err) + } + + logDiagnostics(params.phlareClient, resp.Header()) + + // Extract exemplars from all series points into a flat slice. + // Pre-count to avoid repeated slice growth. + var totalExemplars int + for _, s := range resp.Msg.Series { + for _, p := range s.Points { + totalExemplars += len(p.Exemplars) + } + } + entries := make([]exemplarEntry, 0, totalExemplars) + for _, s := range resp.Msg.Series { + // Build series-level labels map for context. + seriesLabels := make(map[string]string, len(s.Labels)) + for _, lp := range s.Labels { + seriesLabels[lp.Name] = lp.Value + } + + for _, p := range s.Points { + for _, ex := range p.Exemplars { + lbls := make(map[string]string, len(seriesLabels)+len(ex.Labels)) + for k, v := range seriesLabels { + lbls[k] = v + } + for _, lp := range ex.Labels { + lbls[lp.Name] = lp.Value + } + entries = append(entries, exemplarEntry{ + ProfileID: ex.ProfileId, + Timestamp: time.UnixMilli(ex.Timestamp), + Value: ex.Value, + SpanID: ex.SpanId, + TraceID: ex.TraceId, + Labels: lbls, + }) + } + } + } + + // Sort by value descending (highest value = most interesting). + sort.Slice(entries, func(i, j int) bool { + return entries[i].Value > entries[j].Value + }) + + if uint64(len(entries)) > params.TopN { + entries = entries[:params.TopN] + } + + if len(entries) == 0 { + level.Info(logger).Log("msg", "no exemplars found") + } + + profileType, err := model.ParseProfileTypeSelector(params.ProfileType) + if err != nil { + return fmt.Errorf("failed to parse profile type: %w", err) + } + + // Auto-detect the highest-cardinality labels for table columns + // (most distinct values = most differentiating, capped by --max-label-columns). + tableLabels := topCardinalityLabels(entries, params.MaxLabelColumns) + + switch params.Output { + case outputJSON: + return outputExemplarsJSON(ctx, entries, from, to, params.ProfileType) + default: + return outputExemplarsTable(ctx, entries, profileType.SampleUnit, tableLabels) + } +} + +// topCardinalityLabels returns up to N label names to show as table columns, +// excluding internal labels. It prefers labels with higher cardinality (more +// distinct values = more differentiating). If no high-cardinality labels exist +// (e.g. single-service data), it falls back to the first N labels alphabetically. +func topCardinalityLabels(entries []exemplarEntry, n int) []string { + if len(entries) == 0 || n <= 0 { + return nil + } + + // Count distinct values per label name. + distinctValues := make(map[string]map[string]struct{}) + for _, e := range entries { + for k, v := range e.Labels { + if isInternalLabel(k) { + continue + } + if distinctValues[k] == nil { + distinctValues[k] = make(map[string]struct{}) + } + distinctValues[k][v] = struct{}{} + } + } + + type labelCardinality struct { + name string + cardinality int + } + var candidates []labelCardinality + for name, vals := range distinctValues { + candidates = append(candidates, labelCardinality{name, len(vals)}) + } + + // Sort by cardinality descending, then alphabetically for ties. + sort.Slice(candidates, func(i, j int) bool { + if candidates[i].cardinality != candidates[j].cardinality { + return candidates[i].cardinality > candidates[j].cardinality + } + return candidates[i].name < candidates[j].name + }) + + if len(candidates) > n { + candidates = candidates[:n] + } + + result := make([]string, len(candidates)) + for i, c := range candidates { + result[i] = c.name + } + return result +} + +// isInternalLabel returns true for labels that are internal metadata +// (e.g. __name__, __period_type__) and should be hidden from user output. +func isInternalLabel(name string) bool { + return strings.HasPrefix(name, "__") && strings.HasSuffix(name, "__") +} + +// filterLabels returns a copy of labels with internal labels removed. +func filterLabels(labels map[string]string) map[string]string { + filtered := make(map[string]string, len(labels)) + for k, v := range labels { + if !isInternalLabel(k) { + filtered[k] = v + } + } + return filtered +} + +func outputExemplarsJSON(ctx context.Context, entries []exemplarEntry, from, to time.Time, profileType string) error { + type jsonExemplar struct { + ProfileID string `json:"profile_id"` + Timestamp time.Time `json:"timestamp"` + Value int64 `json:"value"` + SpanID string `json:"span_id,omitempty"` + TraceID string `json:"trace_id,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + } + type jsonOutput struct { + From time.Time `json:"from"` + To time.Time `json:"to"` + ProfileType string `json:"profile_type"` + Exemplars []jsonExemplar `json:"exemplars"` + } + + out := jsonOutput{ + From: from, + To: to, + ProfileType: profileType, + Exemplars: make([]jsonExemplar, len(entries)), + } + for i, e := range entries { + out.Exemplars[i] = jsonExemplar{ + ProfileID: e.ProfileID, + Timestamp: e.Timestamp, + Value: e.Value, + SpanID: e.SpanID, + TraceID: e.TraceID, + Labels: filterLabels(e.Labels), + } + } + + enc := json.NewEncoder(output(ctx)) + enc.SetIndent("", " ") + return enc.Encode(out) +} + +// querySpanExemplars lists span exemplars by calling SelectHeatmap with +// HEATMAP_QUERY_TYPE_SPAN, which is already fully implemented in the backend. +// The heatmap slots each carry at most one exemplar (the highest-value span in +// that time×value bucket), so iterating all slots gives a representative sample +// of the most expensive spans in the requested window. +func querySpanExemplars(ctx context.Context, params *queryExemplarsParams) error { + from, to, err := params.parseFromTo() + if err != nil { + return err + } + + level.Info(logger).Log( + "msg", "querying span exemplars", + "url", params.URL, + "from", from, + "to", to, + "query", params.Query, + "type", params.ProfileType, + "top_n", params.TopN, + ) + + rangeSeconds := to.Sub(from).Seconds() + stepSeconds := rangeSeconds / float64(params.TopN) + if stepSeconds < 1 { + stepSeconds = 1 + } + + limit := int64(params.TopN) + qc := params.queryClient() + resp, err := qc.SelectHeatmap(ctx, connect.NewRequest(&querierv1.SelectHeatmapRequest{ + ProfileTypeID: params.ProfileType, + LabelSelector: params.Query, + Start: from.UnixMilli(), + End: to.UnixMilli(), + Step: stepSeconds, + QueryType: querierv1.HeatmapQueryType_HEATMAP_QUERY_TYPE_SPAN, + ExemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_SPAN, + Limit: &limit, + })) + if err != nil { + return fmt.Errorf("failed to query span exemplars: %w", err) + } + + logDiagnostics(params.phlareClient, resp.Header()) + + var entries []exemplarEntry + for _, series := range resp.Msg.Series { + seriesLabels := make(map[string]string, len(series.Labels)) + for _, lp := range series.Labels { + seriesLabels[lp.Name] = lp.Value + } + for _, slot := range series.Slots { + for _, ex := range slot.Exemplars { + if ex.SpanId == "" { + continue + } + lbls := make(map[string]string, len(seriesLabels)+len(ex.Labels)) + for k, v := range seriesLabels { + lbls[k] = v + } + for _, lp := range ex.Labels { + lbls[lp.Name] = lp.Value + } + entries = append(entries, exemplarEntry{ + SpanID: ex.SpanId, + TraceID: ex.TraceId, + Timestamp: time.UnixMilli(ex.Timestamp), + Value: ex.Value, + Labels: lbls, + }) + } + } + } + + sort.Slice(entries, func(i, j int) bool { + return entries[i].Value > entries[j].Value + }) + if uint64(len(entries)) > params.TopN { + entries = entries[:params.TopN] + } + + if len(entries) == 0 { + level.Info(logger).Log("msg", "no span exemplars found") + } + + profileType, err := model.ParseProfileTypeSelector(params.ProfileType) + if err != nil { + return fmt.Errorf("failed to parse profile type: %w", err) + } + + tableLabels := topCardinalityLabels(entries, params.MaxLabelColumns) + + switch params.Output { + case outputJSON: + return outputSpanExemplarsJSON(ctx, entries, from, to, params.ProfileType) + default: + return outputSpanExemplarsTable(ctx, entries, profileType.SampleUnit, tableLabels) + } +} + +func outputSpanExemplarsJSON(ctx context.Context, entries []exemplarEntry, from, to time.Time, profileType string) error { + type jsonExemplar struct { + SpanID string `json:"span_id"` + TraceID string `json:"trace_id,omitempty"` + Timestamp time.Time `json:"timestamp"` + Value int64 `json:"value"` + Labels map[string]string `json:"labels,omitempty"` + } + type jsonOutput struct { + From time.Time `json:"from"` + To time.Time `json:"to"` + ProfileType string `json:"profile_type"` + Exemplars []jsonExemplar `json:"exemplars"` + } + + out := jsonOutput{ + From: from, + To: to, + ProfileType: profileType, + Exemplars: make([]jsonExemplar, len(entries)), + } + for i, e := range entries { + out.Exemplars[i] = jsonExemplar{ + SpanID: e.SpanID, + TraceID: e.TraceID, + Timestamp: e.Timestamp, + Value: e.Value, + Labels: filterLabels(e.Labels), + } + } + enc := json.NewEncoder(output(ctx)) + enc.SetIndent("", " ") + return enc.Encode(out) +} + +func outputSpanExemplarsTable(ctx context.Context, entries []exemplarEntry, sampleUnit string, labelColumns []string) error { + // Only show the Trace ID column when at least one entry actually has one, + // since blocks without a trace ID column will leave it empty for every row. + hasTraceID := false + for _, e := range entries { + if e.TraceID != "" { + hasTraceID = true + break + } + } + + headers := []string{"Span ID", "Timestamp", fmt.Sprintf("Value (%s)", sampleUnit)} + aligns := []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT} + if hasTraceID { + headers = append([]string{"Trace ID"}, headers...) + aligns = append([]int{tablewriter.ALIGN_LEFT}, aligns...) + } + for _, name := range labelColumns { + headers = append(headers, name) + aligns = append(aligns, tablewriter.ALIGN_LEFT) + } + + table := newTableWriter(output(ctx)) + table.SetHeader(headers) + table.SetColumnAlignment(aligns) + + for _, e := range entries { + row := []string{e.SpanID, e.Timestamp.Format(time.RFC3339), formatUnit(float64(e.Value), sampleUnit)} + if hasTraceID { + row = append([]string{e.TraceID}, row...) + } + for _, name := range labelColumns { + row = append(row, e.Labels[name]) + } + table.Append(row) + } + table.Render() + return nil +} + +func outputExemplarsTable(ctx context.Context, entries []exemplarEntry, sampleUnit string, labelColumns []string) error { + headers := []string{"Profile ID", "Timestamp", fmt.Sprintf("Value (%s)", sampleUnit)} + aligns := []int{ + tablewriter.ALIGN_LEFT, + tablewriter.ALIGN_LEFT, + tablewriter.ALIGN_RIGHT, + } + + // Only add Span ID column if any entry has one. + hasSpanID := false + for _, e := range entries { + if e.SpanID != "" { + hasSpanID = true + break + } + } + if hasSpanID { + headers = append(headers, "Span ID") + aligns = append(aligns, tablewriter.ALIGN_LEFT) + } + + // Show auto-detected label columns. + for _, name := range labelColumns { + headers = append(headers, name) + aligns = append(aligns, tablewriter.ALIGN_LEFT) + } + + table := newTableWriter(output(ctx)) + table.SetHeader(headers) + table.SetColumnAlignment(aligns) + + for _, e := range entries { + row := []string{ + e.ProfileID, + e.Timestamp.Format(time.RFC3339), + formatUnit(float64(e.Value), sampleUnit), + } + if hasSpanID { + row = append(row, e.SpanID) + } + for _, name := range labelColumns { + row = append(row, e.Labels[name]) + } + table.Append(row) + } + table.Render() + return nil +} diff --git a/cmd/profilecli/query-exemplars_test.go b/cmd/profilecli/query-exemplars_test.go new file mode 100644 index 0000000000..583401a78f --- /dev/null +++ b/cmd/profilecli/query-exemplars_test.go @@ -0,0 +1,259 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +func TestOutputExemplarsTable(t *testing.T) { + t.Parallel() + + entries := []exemplarEntry{ + { + ProfileID: "550e8400-e29b-41d4-a716-446655440000", + Timestamp: time.Date(2024, 3, 20, 10, 0, 0, 0, time.UTC), + Value: 42000000000, // 42s in nanoseconds + SpanID: "abc123", + Labels: map[string]string{"service_name": "frontend"}, + }, + { + ProfileID: "660e8400-e29b-41d4-a716-446655440001", + Timestamp: time.Date(2024, 3, 20, 10, 5, 0, 0, time.UTC), + Value: 21000000000, // 21s in nanoseconds + SpanID: "", + Labels: map[string]string{"service_name": "backend"}, + }, + } + + var buf bytes.Buffer + ctx := withOutput(context.Background(), &buf) + + err := outputExemplarsTable(ctx, entries, "nanoseconds", []string{"service_name"}) + require.NoError(t, err) + + out := buf.String() + assert.Contains(t, out, "550e8400-e29b-41d4-a716-446655440000") + assert.Contains(t, out, "660e8400-e29b-41d4-a716-446655440001") + assert.Contains(t, out, "abc123") + assert.Contains(t, out, "frontend") + assert.Contains(t, out, "backend") + assert.Contains(t, out, "Profile ID") + assert.Contains(t, out, "service_name") +} + +func TestOutputExemplarsTable_NoGroupBy(t *testing.T) { + t.Parallel() + + entries := []exemplarEntry{ + { + ProfileID: "550e8400-e29b-41d4-a716-446655440000", + Timestamp: time.Date(2024, 3, 20, 10, 0, 0, 0, time.UTC), + Value: 42000000000, + Labels: map[string]string{"service_name": "frontend"}, + }, + } + + var buf bytes.Buffer + ctx := withOutput(context.Background(), &buf) + + err := outputExemplarsTable(ctx, entries, "nanoseconds", nil) + require.NoError(t, err) + + out := buf.String() + assert.Contains(t, out, "Profile ID") + assert.NotContains(t, out, "service_name") +} + +func TestOutputExemplarsJSON(t *testing.T) { + t.Parallel() + + from := time.Date(2024, 3, 20, 9, 0, 0, 0, time.UTC) + to := time.Date(2024, 3, 20, 10, 0, 0, 0, time.UTC) + + entries := []exemplarEntry{ + { + ProfileID: "550e8400-e29b-41d4-a716-446655440000", + Timestamp: time.Date(2024, 3, 20, 9, 30, 0, 0, time.UTC), + Value: 42000, + SpanID: "abc123", + Labels: map[string]string{ + "service_name": "frontend", + "__name__": "process_cpu", + "__period_type__": "cpu", + "__profile_type__": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + }, + }, + } + + var buf bytes.Buffer + ctx := withOutput(context.Background(), &buf) + + err := outputExemplarsJSON(ctx, entries, from, to, "process_cpu:cpu:nanoseconds:cpu:nanoseconds") + require.NoError(t, err) + + var result struct { + From time.Time `json:"from"` + To time.Time `json:"to"` + ProfileType string `json:"profile_type"` + Exemplars []struct { + ProfileID string `json:"profile_id"` + Timestamp time.Time `json:"timestamp"` + Value int64 `json:"value"` + SpanID string `json:"span_id"` + Labels map[string]string `json:"labels"` + } `json:"exemplars"` + } + err = json.Unmarshal(buf.Bytes(), &result) + require.NoError(t, err) + + assert.Equal(t, from, result.From) + assert.Equal(t, to, result.To) + assert.Equal(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds", result.ProfileType) + require.Len(t, result.Exemplars, 1) + assert.Equal(t, "550e8400-e29b-41d4-a716-446655440000", result.Exemplars[0].ProfileID) + assert.Equal(t, int64(42000), result.Exemplars[0].Value) + assert.Equal(t, "abc123", result.Exemplars[0].SpanID) + assert.Equal(t, "frontend", result.Exemplars[0].Labels["service_name"]) + // Internal labels should be filtered out. + assert.NotContains(t, result.Exemplars[0].Labels, "__name__") + assert.NotContains(t, result.Exemplars[0].Labels, "__period_type__") + assert.NotContains(t, result.Exemplars[0].Labels, "__profile_type__") +} + +func TestOutputSpanExemplarsIncludesTraceID(t *testing.T) { + t.Parallel() + + entries := []exemplarEntry{{ + SpanID: "00f067aa0ba902b7", + TraceID: "4bf92f3577b34da6a3ce929d0e0e4736", + Timestamp: time.Date(2024, 3, 20, 9, 30, 0, 0, time.UTC), + Value: 42000, + }} + from := time.Date(2024, 3, 20, 9, 0, 0, 0, time.UTC) + to := time.Date(2024, 3, 20, 10, 0, 0, 0, time.UTC) + + var jsonBuf bytes.Buffer + err := outputSpanExemplarsJSON(withOutput(context.Background(), &jsonBuf), entries, from, to, "process_cpu:cpu:nanoseconds:cpu:nanoseconds") + require.NoError(t, err) + assert.Contains(t, jsonBuf.String(), `"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"`) + + var tableBuf bytes.Buffer + err = outputSpanExemplarsTable(withOutput(context.Background(), &tableBuf), entries, "nanoseconds", nil) + require.NoError(t, err) + assert.Contains(t, tableBuf.String(), "Trace ID") + assert.Contains(t, tableBuf.String(), "4bf92f3577b34da6a3ce929d0e0e4736") +} + +func TestOutputExemplarsTable_Empty(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + ctx := withOutput(context.Background(), &buf) + + err := outputExemplarsTable(ctx, nil, "nanoseconds", nil) + require.NoError(t, err) + // Empty entries should still render a table (with only headers) +} + +func TestTopCardinalityLabels(t *testing.T) { + t.Parallel() + + entries := []exemplarEntry{ + {Labels: map[string]string{ + "__name__": "process_cpu", + "service_name": "frontend", + "namespace": "prod", + "pod": "frontend-abc", + "region": "us-east-1", + }}, + {Labels: map[string]string{ + "__name__": "process_cpu", + "service_name": "backend", + "namespace": "prod", + "pod": "backend-xyz", + "region": "eu-west-1", + }}, + {Labels: map[string]string{ + "__name__": "process_cpu", + "service_name": "frontend", + "namespace": "staging", + "pod": "frontend-def", + "region": "us-east-1", + }}, + } + + result := topCardinalityLabels(entries, 3) + + // pod has 3 distinct values, service_name/namespace/region have 2 each. + // __name__ has 1 (skipped). namespace=prod appears twice but staging once = 2 distinct. + require.Len(t, result, 3) + assert.Equal(t, "pod", result[0]) // 3 distinct values + // The remaining 3 labels all have cardinality 2, sorted alphabetically. + assert.Equal(t, "namespace", result[1]) + assert.Equal(t, "region", result[2]) +} + +func TestTopCardinalityLabels_FiltersInternalShowsConstant(t *testing.T) { + t.Parallel() + + entries := []exemplarEntry{ + {Labels: map[string]string{ + "__name__": "process_cpu", + "service_name": "frontend", + "constant": "same", + }}, + {Labels: map[string]string{ + "__name__": "process_cpu", + "service_name": "frontend", + "constant": "same", + }}, + } + + result := topCardinalityLabels(entries, 3) + + // __name__ is internal (filtered). service_name and constant have cardinality 1 + // but are still shown (alphabetically) since they're the only non-internal labels. + require.Len(t, result, 2) + assert.Equal(t, "constant", result[0]) + assert.Equal(t, "service_name", result[1]) +} + +func TestExemplarEntry_FromProtoExemplar(t *testing.T) { + t.Parallel() + + // Verify that our exemplarEntry struct correctly maps from the proto Exemplar type. + ex := &typesv1.Exemplar{ + Timestamp: 1710928800000, // 2024-03-20T10:00:00Z in millis + ProfileId: "550e8400-e29b-41d4-a716-446655440000", + SpanId: "deadbeef", + TraceId: "4bf92f3577b34da6a3ce929d0e0e4736", + Value: 99999, + Labels: []*typesv1.LabelPair{ + {Name: "pod", Value: "frontend-abc"}, + }, + } + + entry := exemplarEntry{ + ProfileID: ex.ProfileId, + Timestamp: time.UnixMilli(ex.Timestamp), + Value: ex.Value, + SpanID: ex.SpanId, + TraceID: ex.TraceId, + Labels: map[string]string{"pod": "frontend-abc"}, + } + + assert.Equal(t, "550e8400-e29b-41d4-a716-446655440000", entry.ProfileID) + assert.Equal(t, time.UnixMilli(1710928800000), entry.Timestamp) + assert.Equal(t, int64(99999), entry.Value) + assert.Equal(t, "deadbeef", entry.SpanID) + assert.Equal(t, "4bf92f3577b34da6a3ce929d0e0e4736", entry.TraceID) + assert.Equal(t, "frontend-abc", entry.Labels["pod"]) +} diff --git a/cmd/profilecli/query-top.go b/cmd/profilecli/query-top.go new file mode 100644 index 0000000000..ae1b5b41ea --- /dev/null +++ b/cmd/profilecli/query-top.go @@ -0,0 +1,186 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "sort" + "time" + + "connectrpc.com/connect" + "github.com/dustin/go-humanize" + "github.com/go-kit/log/level" + "github.com/olekukonko/tablewriter" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +type queryTopParams struct { + *queryParams + ProfileType string + TopN uint64 + LabelNames []string + Output string +} + +func addQueryTopParams(queryCmd commander) *queryTopParams { + params := new(queryTopParams) + params.queryParams = addQueryParams(queryCmd) + queryCmd.Flag("profile-type", "Profile type to query.").Default("process_cpu:cpu:nanoseconds:cpu:nanoseconds").StringVar(¶ms.ProfileType) + queryCmd.Flag("top-n", "Number of top results to show.").Default("10").Uint64Var(¶ms.TopN) + queryCmd.Flag("label-names", "Label name(s) to group by. Can be specified multiple times.").Default(model.LabelNameServiceName).StringsVar(¶ms.LabelNames) + queryCmd.Flag("output", "Output format, one of: table, json.").Default("table").StringVar(¶ms.Output) + return params +} + +func queryTop(ctx context.Context, params *queryTopParams) error { + from, to, err := params.parseFromTo() + if err != nil { + return err + } + + level.Info(logger).Log( + "msg", "querying top series", + "url", params.URL, + "from", from, + "to", to, + "query", params.Query, + "type", params.ProfileType, + "labels", fmt.Sprintf("%v", params.LabelNames), + "top_n", params.TopN, + ) + + stepSeconds := to.Sub(from).Seconds() + + qc := params.queryClient() + resp, err := qc.SelectSeries(ctx, connect.NewRequest(&querierv1.SelectSeriesRequest{ + ProfileTypeID: params.ProfileType, + LabelSelector: params.Query, + Start: from.UnixMilli(), + End: to.UnixMilli(), + Step: stepSeconds, + GroupBy: params.LabelNames, + })) + if err != nil { + return fmt.Errorf("failed to query series: %w", err) + } + logDiagnostics(params.phlareClient, resp.Header()) + series := resp.Msg.Series + + type seriesTotal struct { + labelValues []string + total float64 + } + + totals := make([]seriesTotal, 0, len(series)) + startMs := from.UnixMilli() + for _, s := range series { + total := sumPointsAfter(s.Points, startMs) + lbls := model.Labels(s.Labels) + vals := make([]string, len(params.LabelNames)) + for i, name := range params.LabelNames { + if v := lbls.Get(name); v != "" { + vals[i] = v + } else { + vals[i] = "" + } + } + totals = append(totals, seriesTotal{labelValues: vals, total: total}) + } + + sort.Slice(totals, func(i, j int) bool { + return totals[i].total > totals[j].total + }) + + if uint64(len(totals)) > params.TopN { + totals = totals[:params.TopN] + } + + profileType, err := model.ParseProfileTypeSelector(params.ProfileType) + if err != nil { + return fmt.Errorf("failed to parse profile type: %w", err) + } + + switch params.Output { + case outputJSON: + type jsonSeries struct { + Labels map[string]string `json:"labels"` + Total float64 `json:"total"` + } + type jsonOutput struct { + From time.Time `json:"from"` + To time.Time `json:"to"` + ProfileType string `json:"profile_type"` + Series []jsonSeries `json:"series"` + } + out := jsonOutput{ + From: from, + To: to, + ProfileType: params.ProfileType, + Series: make([]jsonSeries, len(totals)), + } + for i, t := range totals { + lbls := make(map[string]string, len(params.LabelNames)) + for j, name := range params.LabelNames { + lbls[name] = t.labelValues[j] + } + out.Series[i] = jsonSeries{Labels: lbls, Total: t.total} + } + enc := json.NewEncoder(output(ctx)) + enc.SetIndent("", " ") + if err := enc.Encode(out); err != nil { + return err + } + default: + headers := append([]string{"Rank"}, params.LabelNames...) + headers = append(headers, fmt.Sprintf("Total (%s)", profileType.SampleUnit)) + aligns := make([]int, len(headers)) + aligns[0] = tablewriter.ALIGN_RIGHT + for i := 1; i < len(headers)-1; i++ { + aligns[i] = tablewriter.ALIGN_LEFT + } + aligns[len(aligns)-1] = tablewriter.ALIGN_RIGHT + + table := newTableWriter(output(ctx)) + table.SetHeader(headers) + table.SetColumnAlignment(aligns) + for i, t := range totals { + row := []string{fmt.Sprintf("%d", i+1)} + row = append(row, t.labelValues...) + row = append(row, formatUnit(t.total, profileType.SampleUnit)) + table.Append(row) + } + table.Render() + } + + return nil +} + +// sumPointsAfter sums point values with timestamps strictly after startMs. +// SelectSeries fetches one extra step before the window so that the boundary +// point at `start` renders as a complete bucket in charts; that point +// aggregates (start-step, start], which lies entirely before the requested +// window. With step = window size, counting it roughly doubles the total. +func sumPointsAfter(points []*typesv1.Point, startMs int64) float64 { + var total float64 + for _, p := range points { + if p.Timestamp <= startMs { + continue + } + total += p.Value + } + return total +} + +func formatUnit(v float64, unit string) string { + switch unit { + case "nanoseconds": + return time.Duration(int64(v)).String() + case "bytes": + return humanize.Bytes(uint64(v)) + default: + return humanize.FormatFloat("#,###.##", v) + } +} diff --git a/cmd/profilecli/query-top_test.go b/cmd/profilecli/query-top_test.go new file mode 100644 index 0000000000..0c36004477 --- /dev/null +++ b/cmd/profilecli/query-top_test.go @@ -0,0 +1,35 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +func TestSumPointsAfter(t *testing.T) { + const startMs = int64(1_784_130_300_000) // window start + const stepMs = int64(3_600_000) + + // SelectSeries with step = window size returns two points: the boundary + // point at `start` holding pre-window data, and the point at `end` + // holding the actual window total. + points := []*typesv1.Point{ + {Timestamp: startMs, Value: 8_778_052_796_311}, + {Timestamp: startMs + stepMs, Value: 4_005_116_752_500}, + } + require.Equal(t, float64(4_005_116_752_500), sumPointsAfter(points, startMs)) + + t.Run("all points within window", func(t *testing.T) { + points := []*typesv1.Point{ + {Timestamp: startMs + 1, Value: 1}, + {Timestamp: startMs + 2, Value: 2}, + } + require.Equal(t, float64(3), sumPointsAfter(points, startMs)) + }) + + t.Run("no points", func(t *testing.T) { + require.Equal(t, float64(0), sumPointsAfter(nil, startMs)) + }) +} diff --git a/cmd/profilecli/query-tracer.go b/cmd/profilecli/query-tracer.go index 8f0ea92c16..4d71fa1778 100644 --- a/cmd/profilecli/query-tracer.go +++ b/cmd/profilecli/query-tracer.go @@ -377,7 +377,7 @@ func queryTracer(ctx context.Context, params *queryTracerParams) (err error) { if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) - return fmt.Errorf("Tempo returned status code [%d]: %s ", resp.StatusCode, body) + return fmt.Errorf("tempo returned status code [%d]: %s ", resp.StatusCode, body) } var respBody struct { @@ -454,7 +454,7 @@ func queryTracer(ctx context.Context, params *queryTracerParams) (err error) { if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) - return fmt.Errorf("Tempo returned status code [%d]: %s ", resp.StatusCode, body) + return fmt.Errorf("tempo returned status code [%d]: %s ", resp.StatusCode, body) } data, err := io.ReadAll(resp.Body) diff --git a/cmd/profilecli/query.go b/cmd/profilecli/query.go index aff60f16a3..d0e4e4ae3b 100644 --- a/cmd/profilecli/query.go +++ b/cmd/profilecli/query.go @@ -1,44 +1,41 @@ package main import ( - "bytes" "context" - "encoding/json" + "errors" "fmt" - "io" - "os" - "strings" + "net/http" + "sort" "time" "connectrpc.com/connect" + "github.com/dustin/go-humanize" "github.com/go-kit/log/level" - gprofile "github.com/google/pprof/profile" - "github.com/grafana/dskit/runutil" + "github.com/google/uuid" + "golang.org/x/sync/errgroup" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1/ingesterv1connect" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" "github.com/grafana/pyroscope/api/gen/proto/go/storegateway/v1/storegatewayv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/operations" - "github.com/k0kubun/pp/v3" - "github.com/klauspost/compress/gzip" - "github.com/mattn/go-isatty" - "github.com/pkg/errors" -) - -const ( - outputConsole = "console" - outputRaw = "raw" - outputPprof = "pprof=" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + querydiagnostics "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend/diagnostics" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/operations" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) func (c *phlareClient) queryClient() querierv1connect.QuerierServiceClient { return querierv1connect.NewQuerierServiceClient( c.httpClient(), c.URL, - connectapi.DefaultClientOptions()..., + append( + connectapi.DefaultClientOptions(), + c.protocolOption(), + )..., ) } @@ -46,7 +43,10 @@ func (c *phlareClient) storeGatewayClient() storegatewayv1connect.StoreGatewaySe return storegatewayv1connect.NewStoreGatewayServiceClient( c.httpClient(), c.URL, - connectapi.DefaultClientOptions()..., + append( + connectapi.DefaultClientOptions(), + c.protocolOption(), + )..., ) } @@ -54,7 +54,10 @@ func (c *phlareClient) ingesterClient() ingesterv1connect.IngesterServiceClient return ingesterv1connect.NewIngesterServiceClient( c.httpClient(), c.URL, - connectapi.DefaultClientOptions()..., + append( + connectapi.DefaultClientOptions(), + c.protocolOption(), + )..., ) } @@ -68,15 +71,15 @@ type queryParams struct { func (p *queryParams) parseFromTo() (from time.Time, to time.Time, err error) { from, err = operations.ParseTime(p.From) if err != nil { - return time.Time{}, time.Time{}, errors.Wrap(err, "failed to parse from") + return time.Time{}, time.Time{}, fmt.Errorf("failed to parse from: %w", err) } to, err = operations.ParseTime(p.To) if err != nil { - return time.Time{}, time.Time{}, errors.Wrap(err, "failed to parse to") + return time.Time{}, time.Time{}, fmt.Errorf("failed to parse to: %w", err) } if to.Before(from) { - return time.Time{}, time.Time{}, errors.Wrap(err, "from cannot be after") + return time.Time{}, time.Time{}, errors.New("from cannot be after") } return from, to, nil @@ -92,98 +95,360 @@ func addQueryParams(queryCmd commander) *queryParams { return params } -type queryMergeParams struct { +type queryProfileParams struct { *queryParams - ProfileType string + ProfileType string + StacktraceSelector []string + SpanSelector []string + ProfileIDs []string + TraceIDs []string + MaxNodes int64 } -func addQueryMergeParams(queryCmd commander) *queryMergeParams { - params := new(queryMergeParams) +func addQueryProfileParams(queryCmd commander) *queryProfileParams { + params := new(queryProfileParams) params.queryParams = addQueryParams(queryCmd) queryCmd.Flag("profile-type", "Profile type to query.").Default("process_cpu:cpu:nanoseconds:cpu:nanoseconds").StringVar(¶ms.ProfileType) + queryCmd.Flag("stacktrace-selector", "Only query locations with those symbols. Provide multiple times starting with the root").StringsVar(¶ms.StacktraceSelector) + queryCmd.Flag("span-selector", "Only query profiles with the given span IDs. Provide multiple times for multiple spans.").StringsVar(¶ms.SpanSelector) + queryCmd.Flag("max-nodes", "Maximum number of nodes to return in the profile").Int64Var(¶ms.MaxNodes) return params } -func queryMerge(ctx context.Context, params *queryMergeParams, outputFlag string) (err error) { +// validateQueryProfileParams checks for mutual exclusion between flags and +// validates the --profile-id format when provided. +func validateQueryProfileParams(params *queryProfileParams) error { + if len(params.SpanSelector) > 0 && len(params.StacktraceSelector) > 0 { + return errors.New("--span-selector and --stacktrace-selector cannot be used together") + } + + // --profile-id and --span-selector serve different purposes and cannot be combined. + // ProfileIdSelector uses profile_id (UUID) for drilling down from exemplars. + // SpanSelector uses span_id for span-filtered queries. See PR #4872. + if len(params.ProfileIDs) > 0 && len(params.SpanSelector) > 0 { + return errors.New("--profile-id and --span-selector cannot be used together. --profile-id selects a specific profile by UUID (from exemplar queries). --span-selector filters by trace span ID.") + } + + // --trace-id is a sample-level filter; it can't combine with span or profile selectors. + if len(params.TraceIDs) > 0 && len(params.SpanSelector) > 0 { + return errors.New("--trace-id and --span-selector cannot be used together") + } + if len(params.TraceIDs) > 0 && len(params.ProfileIDs) > 0 { + return errors.New("--trace-id and --profile-id cannot be used together. --profile-id selects a whole profile by UUID; --trace-id filters samples by trace id.") + } + + // Validate each --profile-id is a valid UUID if provided. + for _, id := range params.ProfileIDs { + if _, err := uuid.Parse(id); err != nil { + return errors.New("--profile-id must be a valid UUID (e.g. 550e8400-e29b-41d4-a716-446655440000). Did you mean --span-selector for span IDs?") + } + } + + // Validate each --trace-id is a 32-character hex trace id. + for _, id := range params.TraceIDs { + if _, err := model.DecodeTraceID(id); err != nil { + return fmt.Errorf("--trace-id must be a 32-character hex string (128-bit trace id): %w", err) + } + } + + return nil +} + +func queryProfile(ctx context.Context, params *queryProfileParams, outputFlag string, force bool, profileTree bool, async bool) (err error) { from, to, err := params.parseFromTo() if err != nil { return err } - level.Info(logger).Log("msg", "query aggregated profile from profile store", "url", params.URL, "from", from, "to", to, "query", params.Query, "type", params.ProfileType) - qc := params.phlareClient.queryClient() + if err := validateQueryProfileParams(params); err != nil { + return err + } - resp, err := qc.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + var profile *googlev1.Profile + if async { + if len(params.SpanSelector) > 0 { + return errors.New("--async is not supported with --span-selector (only SelectMergeStacktraces queries can run async)") + } + var locations []*typesv1.Location + if len(params.StacktraceSelector) > 0 { + locations = make([]*typesv1.Location, 0, len(params.StacktraceSelector)) + for _, cs := range params.StacktraceSelector { + locations = append(locations, &typesv1.Location{Name: cs}) + } + } + profile, err = asyncQueryProfileTree(ctx, params, from, to, locations) + } else if len(params.SpanSelector) > 0 { + level.Info(logger).Log("msg", "selecting with span selector", "spans", fmt.Sprintf("%v", params.SpanSelector)) + profile, err = querySpanProfile(ctx, params, from, to) + } else { + var locations []*typesv1.Location + if len(params.StacktraceSelector) > 0 { + locations = make([]*typesv1.Location, 0, len(params.StacktraceSelector)) + for _, cs := range params.StacktraceSelector { + locations = append(locations, &typesv1.Location{Name: cs}) + } + level.Info(logger).Log("msg", "selecting with stackstrace selector", "call-site", fmt.Sprintf("%#+v", params.StacktraceSelector)) + } + if profileTree { + profile, err = queryProfileTree(ctx, params, from, to, locations) + } else { + profile, err = queryProfilePprof(ctx, params, from, to, locations) + } + } + if err != nil { + return err + } + + return outputMergeProfile(ctx, outputFlag, force, profile) +} + +func querySpanProfile(ctx context.Context, params *queryProfileParams, from time.Time, to time.Time) (*googlev1.Profile, error) { + req := &querierv1.SelectMergeStacktracesRequest{ ProfileTypeID: params.ProfileType, Start: from.UnixMilli(), End: to.UnixMilli(), LabelSelector: params.Query, - })) + SpanSelector: params.SpanSelector, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + } + + if params.MaxNodes > 0 { + req.MaxNodes = ¶ms.MaxNodes + } + + qc := params.phlareClient.queryClient() + resp, err := qc.SelectMergeStacktraces(ctx, connect.NewRequest(req)) + if err != nil { + return nil, fmt.Errorf("failed to query span profile: %w", err) + } + + logDiagnostics(params.phlareClient, resp.Header()) + + if resp.Msg.GetPprof().GetProfile() != nil { + return resp.Msg.Pprof.Profile, nil + } + legacyReq := &querierv1.SelectMergeSpanProfileRequest{ + ProfileTypeID: req.ProfileTypeID, + LabelSelector: req.LabelSelector, + SpanSelector: req.SpanSelector, + Start: req.Start, + End: req.End, + MaxNodes: req.MaxNodes, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_TREE, + } + legacyResp, err := qc.SelectMergeSpanProfile(ctx, connect.NewRequest(legacyReq)) + if err != nil { + return nil, fmt.Errorf("failed to query span profile using legacy API: %w", err) + } + logDiagnostics(params.phlareClient, legacyResp.Header()) + tree, err := model.UnmarshalTree[model.FunctionName, model.FunctionNameI](legacyResp.Msg.Tree) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal tree: %w", err) + } + profileType, err := model.ParseProfileTypeSelector(params.ProfileType) if err != nil { - return errors.Wrap(err, "failed to query") + return nil, err } + return pprof.FromTree(tree, profileType, req.End*1e6), nil +} - mypp := pp.New() - mypp.SetColoringEnabled(isatty.IsTerminal(os.Stdout.Fd())) - mypp.SetExportedOnly(true) +func queryProfilePprof(ctx context.Context, params *queryProfileParams, from time.Time, to time.Time, locations []*typesv1.Location) (*googlev1.Profile, error) { + req := &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: params.ProfileType, + Start: from.UnixMilli(), + End: to.UnixMilli(), + LabelSelector: params.Query, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + } - if outputFlag == outputConsole { - buf, err := resp.Msg.MarshalVT() - if err != nil { - return errors.Wrap(err, "failed to marshal protobuf") - } + if params.MaxNodes > 0 { + req.MaxNodes = ¶ms.MaxNodes + } - p, err := gprofile.Parse(bytes.NewReader(buf)) - if err != nil { - return errors.Wrap(err, "failed to parse profile") + if len(params.StacktraceSelector) > 0 { + req.StackTraceSelector = &typesv1.StackTraceSelector{ + CallSite: locations, } + } - fmt.Fprintln(output(ctx), p.String()) - return nil + // ProfileIdSelector uses profile_id (UUID), NOT span_id. See PR #4872. + if len(params.ProfileIDs) > 0 { + req.ProfileIdSelector = params.ProfileIDs + } + if len(params.TraceIDs) > 0 { + req.TraceIdSelector = params.TraceIDs } - if outputFlag == outputRaw { - mypp.Print(resp.Msg) - return nil + qc := params.phlareClient.queryClient() + + profile, headers, err := queryPprofWithFallback(ctx, qc, req) + if err != nil { + return nil, err } - if strings.HasPrefix(outputFlag, outputPprof) { - filePath := strings.TrimPrefix(outputFlag, outputPprof) - if filePath == "" { - return errors.New("no file path specified after pprof=") - } - buf, err := resp.Msg.MarshalVT() - if err != nil { - return errors.Wrap(err, "failed to marshal protobuf") - } + logDiagnostics(params.phlareClient, headers) + return profile, nil +} - // open new file, fail when the file already exists - f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644) - if err != nil { - return errors.Wrap(err, "failed to create pprof file") - } - defer runutil.CloseWithErrCapture(&err, f, "failed to close pprof file") +func queryProfileTree(ctx context.Context, params *queryProfileParams, from time.Time, to time.Time, locations []*typesv1.Location) (*googlev1.Profile, error) { + req := &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: params.ProfileType, + Start: from.UnixMilli(), + End: to.UnixMilli(), + LabelSelector: params.Query, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_TREE, + } - gzipWriter := gzip.NewWriter(f) - defer runutil.CloseWithErrCapture(&err, gzipWriter, "failed to close pprof gzip writer") + if params.MaxNodes > 0 { + req.MaxNodes = ¶ms.MaxNodes + } - if _, err := io.Copy(gzipWriter, bytes.NewReader(buf)); err != nil { - return errors.Wrap(err, "failed to write pprof") + if len(params.StacktraceSelector) > 0 { + req.StackTraceSelector = &typesv1.StackTraceSelector{ + CallSite: locations, } + } - return nil + // ProfileIdSelector uses profile_id (UUID), NOT span_id. See PR #4872. + if len(params.ProfileIDs) > 0 { + req.ProfileIdSelector = params.ProfileIDs } - return errors.Errorf("unknown output %s", outputFlag) + if len(params.TraceIDs) > 0 { + req.TraceIdSelector = params.TraceIDs + } + + qc := params.phlareClient.queryClient() + resp, err := qc.SelectMergeStacktraces(ctx, connect.NewRequest(req)) + if err != nil { + return nil, fmt.Errorf("failed to query: %w", err) + } + + logDiagnostics(params.phlareClient, resp.Header()) + + tree, err := model.UnmarshalTree[model.FunctionName, model.FunctionNameI](resp.Msg.Tree) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal tree: %w", err) + } + + ty, err := model.ParseProfileTypeSelector(params.ProfileType) + if err != nil { + return nil, err + } + + return pprof.FromTree(tree, ty, req.End*1e6), nil +} + +func selectMergeProfile(ctx context.Context, client *phlareClient, outputFlag string, force bool, req *querierv1.SelectMergeStacktracesRequest) error { + req.Format = querierv1.ProfileFormat_PROFILE_FORMAT_PPROF + qc := client.queryClient() + profile, headers, err := queryPprofWithFallback(ctx, qc, req) + if err != nil { + return fmt.Errorf("failed to query: %w", err) + } + + logDiagnostics(client, headers) + return outputMergeProfile(ctx, outputFlag, force, profile) +} + +func queryPprofWithFallback( + ctx context.Context, + client querierv1connect.QuerierServiceClient, + req *querierv1.SelectMergeStacktracesRequest, +) (*googlev1.Profile, http.Header, error) { + resp, err := client.SelectMergeStacktraces(ctx, connect.NewRequest(req)) + if err != nil { + return nil, nil, err + } + if resp.Msg.GetPprof().GetProfile() != nil { + return resp.Msg.Pprof.Profile, resp.Header(), nil + } + + legacyResp, err := client.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: req.ProfileTypeID, + LabelSelector: req.LabelSelector, + Start: req.Start, + End: req.End, + MaxNodes: req.MaxNodes, + StackTraceSelector: req.StackTraceSelector, + ProfileIdSelector: req.ProfileIdSelector, + TraceIdSelector: req.TraceIdSelector, + })) + if err != nil { + return nil, nil, fmt.Errorf("failed to query profile using legacy API: %w", err) + } + return legacyResp.Msg, legacyResp.Header(), nil +} + +func logDiagnostics(client *phlareClient, headers http.Header) { + if !client.CollectDiagnostics { + return + } + + diagID := headers.Get(querydiagnostics.IdHeader) + + if diagID != "" { + level.Info(logger).Log( + "msg", "query diagnostics", + "diagnostics_id", diagID, + ) + } +} + +type queryGoPGOParams struct { + *queryProfileParams + KeepLocations uint32 + AggregateCallees bool +} + +func addQueryGoPGOParams(queryCmd commander) *queryGoPGOParams { + params := new(queryGoPGOParams) + params.queryProfileParams = addQueryProfileParams(queryCmd) + queryCmd.Flag("keep-locations", "Number of leaf locations to keep.").Default("5").Uint32Var(¶ms.KeepLocations) + queryCmd.Flag("aggregate-callees", "Default: true. Aggregate samples for the same callee by ignoring the line numbers in the leaf locations. Use --aggregate-callees to enable or --no-aggregate-callees to disable.").Default("true").BoolVar(¶ms.AggregateCallees) + return params +} + +func queryGoPGO(ctx context.Context, params *queryGoPGOParams, outputFlag string, force bool) (err error) { + from, to, err := params.parseFromTo() + if err != nil { + return err + } + level.Info(logger).Log("msg", "querying pprof profile for Go PGO", + "url", params.URL, + "query", params.Query, + "from", from, + "to", to, + "type", params.ProfileType, + "output", outputFlag, + "keep-locations", params.KeepLocations, + "aggregate-callees", params.AggregateCallees, + ) + stackTraceSelector := &typesv1.StackTraceSelector{ + GoPgo: &typesv1.GoPGO{ + KeepLocations: params.KeepLocations, + AggregateCallees: params.AggregateCallees, + }, + } + + req := &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: params.ProfileType, + Start: from.UnixMilli(), + End: to.UnixMilli(), + LabelSelector: params.Query, + StackTraceSelector: stackTraceSelector, + } + return selectMergeProfile(ctx, params.phlareClient, outputFlag, force, req) } type querySeriesParams struct { *queryParams LabelNames []string APIType string + Output string } func addQuerySeriesParams(queryCmd commander) *querySeriesParams { @@ -191,6 +456,7 @@ func addQuerySeriesParams(queryCmd commander) *querySeriesParams { params.queryParams = addQueryParams(queryCmd) queryCmd.Flag("label-names", "Filter returned labels to the supplied label names. Without any filter all labels are returned.").StringsVar(¶ms.LabelNames) queryCmd.Flag("api-type", "Which API type to query (querier, ingester or store-gateway).").Default("querier").StringVar(¶ms.APIType) + queryCmd.Flag("output", "Output format, one of: table, json.").Default("table").StringVar(¶ms.Output) return params } @@ -213,8 +479,9 @@ func querySeries(ctx context.Context, params *querySeriesParams) (err error) { LabelNames: params.LabelNames, })) if err != nil { - return errors.Wrap(err, "failed to query") + return fmt.Errorf("failed to query: %w", err) } + logDiagnostics(params.phlareClient, resp.Header()) result = resp.Msg.LabelsSet case "ingester": ic := params.phlareClient.ingesterClient() @@ -225,7 +492,7 @@ func querySeries(ctx context.Context, params *querySeriesParams) (err error) { LabelNames: params.LabelNames, })) if err != nil { - return errors.Wrap(err, "failed to query") + return fmt.Errorf("failed to query: %w", err) } result = resp.Msg.LabelsSet case "store-gateway": @@ -237,27 +504,94 @@ func querySeries(ctx context.Context, params *querySeriesParams) (err error) { LabelNames: params.LabelNames, })) if err != nil { - return errors.Wrap(err, "failed to query") + return fmt.Errorf("failed to query: %w", err) } result = resp.Msg.LabelsSet default: - return errors.Errorf("unknown api type %s", params.APIType) + return fmt.Errorf("unknown api type %s", params.APIType) } - enc := json.NewEncoder(os.Stdout) - m := make(map[string]interface{}) - for _, s := range result { - for k := range m { - delete(m, k) - } - for _, l := range s.Labels { - m[l.Name] = l.Value - } - if err := enc.Encode(m); err != nil { - return err - } + return outputSeries(ctx, result, params.Output, from, to) +} + +type queryLabelValuesCardinalityParams struct { + *queryParams + TopN uint64 +} + +func addQueryLabelValuesCardinalityParams(queryCmd commander) *queryLabelValuesCardinalityParams { + params := new(queryLabelValuesCardinalityParams) + params.queryParams = addQueryParams(queryCmd) + queryCmd.Flag("top-n", "Show the top N high cardinality label values").Default("20").Uint64Var(¶ms.TopN) + return params +} + +func queryLabelValuesCardinality(ctx context.Context, params *queryLabelValuesCardinalityParams) (err error) { + from, to, err := params.parseFromTo() + if err != nil { + return err } - return nil + level.Info(logger).Log("msg", "query label names", "url", params.URL, "from", from, "to", to) + qc := params.phlareClient.queryClient() + resp, err := qc.LabelNames(ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: from.UnixMilli(), + End: to.UnixMilli(), + Matchers: []string{params.Query}, + })) + if err != nil { + return fmt.Errorf("failed to query: %w", err) + } + logDiagnostics(params.phlareClient, resp.Header()) + + level.Info(logger).Log("msg", fmt.Sprintf("received %d label names", len(resp.Msg.Names))) + + g, gctx := errgroup.WithContext(ctx) + g.SetLimit(8) + result := make([]struct { + count int + name string + }, len(resp.Msg.Names)) + + for idx := range resp.Msg.Names { + idx := idx + g.Go(func() error { + name := resp.Msg.Names[idx] + resp, err := qc.LabelValues(gctx, connect.NewRequest(&typesv1.LabelValuesRequest{ + Name: name, + Start: from.UnixMilli(), + End: to.UnixMilli(), + Matchers: []string{params.Query}, + })) + if err != nil { + return fmt.Errorf("failed to query label values for %s: %w", name, err) + } + + result[idx].name = name + result[idx].count = len(resp.Msg.Names) + + return nil + }) + } + if err := g.Wait(); err != nil { + return err + } + + // sort the result + sort.Slice(result, func(i, j int) bool { + return result[i].count > result[j].count + }) + + table := newTableWriter(output(ctx)) + table.SetHeader([]string{"LabelName", "Value count"}) + if len(result) > int(params.TopN) { + result = result[:params.TopN] + } + for _, r := range result { + table.Append([]string{r.name, humanize.FormatInteger("#,###.", r.count)}) + } + table.Render() + + return nil } diff --git a/cmd/profilecli/query_async.go b/cmd/profilecli/query_async.go new file mode 100644 index 0000000000..e9cea33484 --- /dev/null +++ b/cmd/profilecli/query_async.go @@ -0,0 +1,123 @@ +package main + +import ( + "context" + "errors" + "fmt" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "google.golang.org/protobuf/proto" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" +) + +// runAsyncSelectMergeStacktraces submits the given request via +// SelectMergeStacktraces with Async.Type=FORCE, then polls until the +// query completes. +func runAsyncSelectMergeStacktraces( + ctx context.Context, + client querierv1connect.QuerierServiceClient, + req *querierv1.SelectMergeStacktracesRequest, +) (*querierv1.SelectMergeStacktracesResponse, error) { + submitReq := proto.Clone(req).(*querierv1.SelectMergeStacktracesRequest) + submitReq.Async = &querierv1.AsyncQueryRequest{Type: querierv1.AsyncQueryType_ASYNC_QUERY_TYPE_FORCE} + + submit, err := client.SelectMergeStacktraces(ctx, connect.NewRequest(submitReq)) + if err != nil { + if connectErr := new(connect.Error); errors.As(err, &connectErr) && connectErr.Code() == connect.CodeUnimplemented { + return nil, fmt.Errorf("server has async queries disabled (set -query-frontend.async-queries-enabled=true)") + } + return nil, err + } + if submit.Msg.GetAsync() == nil || submit.Msg.Async.RequestId == "" { + return nil, fmt.Errorf("server did not return an async request_id") + } + requestID := submit.Msg.Async.RequestId + level.Info(logger).Log("msg", "async query submitted", "request_id", requestID) + + pollReq := &querierv1.SelectMergeStacktracesRequest{ + Async: &querierv1.AsyncQueryRequest{ + Type: querierv1.AsyncQueryType_ASYNC_QUERY_TYPE_FORCE, + RequestId: requestID, + }, + } + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + start := time.Now() + for { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-ticker.C: + } + + poll, err := client.SelectMergeStacktraces(ctx, connect.NewRequest(pollReq)) + if err != nil { + return nil, fmt.Errorf("failed to poll async query: %w", err) + } + + async := poll.Msg.GetAsync() + if async == nil { + return nil, fmt.Errorf("server returned no async metadata for poll request %s", requestID) + } + + switch async.Status { + case querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_IN_PROGRESS: + level.Info(logger).Log("msg", "waiting for async query", "request_id", requestID, "elapsed", time.Since(start).Truncate(time.Second)) + continue + case querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_SUCCESS: + level.Info(logger).Log("msg", "async query completed", "request_id", requestID, "elapsed", time.Since(start).Truncate(time.Second)) + // Strip the Async marker so the caller sees a normal sync response shape. + poll.Msg.Async = nil + return poll.Msg, nil + case querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_FAILURE: + return nil, fmt.Errorf("async query failed: %s", async.ErrorMessage) + default: + return nil, fmt.Errorf("unexpected async query status: %v", async.Status) + } + } +} + +// asyncQueryProfileTree mirrors queryProfileTree but executes via the +// async query path on SelectMergeStacktraces. +func asyncQueryProfileTree(ctx context.Context, params *queryProfileParams, from, to time.Time, locations []*typesv1.Location) (*googlev1.Profile, error) { + req := &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: params.ProfileType, + Start: from.UnixMilli(), + End: to.UnixMilli(), + LabelSelector: params.Query, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_TREE, + } + if params.MaxNodes > 0 { + req.MaxNodes = ¶ms.MaxNodes + } + if len(params.StacktraceSelector) > 0 { + req.StackTraceSelector = &typesv1.StackTraceSelector{CallSite: locations} + } + if len(params.ProfileIDs) > 0 { + req.ProfileIdSelector = params.ProfileIDs + } + + resp, err := runAsyncSelectMergeStacktraces(ctx, params.queryClient(), req) + if err != nil { + return nil, err + } + + tree, err := model.UnmarshalTree[model.FunctionName, model.FunctionNameI](resp.Tree) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal tree: %w", err) + } + ty, err := model.ParseProfileTypeSelector(params.ProfileType) + if err != nil { + return nil, err + } + return pprof.FromTree(tree, ty, req.End*1e6), nil +} diff --git a/cmd/profilecli/query_test.go b/cmd/profilecli/query_test.go new file mode 100644 index 0000000000..f873cc18bf --- /dev/null +++ b/cmd/profilecli/query_test.go @@ -0,0 +1,177 @@ +package main + +import ( + "context" + "testing" + + "connectrpc.com/connect" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockquerierv1connect" +) + +func TestQueryPprofWithFallback(t *testing.T) { + client := mockquerierv1connect.NewMockQuerierServiceClient(t) + req := &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + LabelSelector: "{}", + Start: 1, + End: 2, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + } + client.On("SelectMergeStacktraces", mock.Anything, connect.NewRequest(req)). + Return(connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Flamegraph: &querierv1.FlameGraph{}, + }), nil).Once() + want := &profilev1.Profile{Sample: []*profilev1.Sample{{Value: []int64{1}}}} + client.On("SelectMergeProfile", mock.Anything, mock.MatchedBy(func(req *connect.Request[querierv1.SelectMergeProfileRequest]) bool { + return req.Msg.ProfileTypeID == "process_cpu:cpu:nanoseconds:cpu:nanoseconds" && req.Msg.Start == 1 && req.Msg.End == 2 + })).Return(connect.NewResponse(want), nil).Once() + + got, _, err := queryPprofWithFallback(context.Background(), client, req) + + require.NoError(t, err) + require.Same(t, want, got) +} + +func TestQueryProfileParams_ProfileIDValidation(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + profileIDs []string + wantErr bool + }{ + { + name: "valid UUID", + profileIDs: []string{"550e8400-e29b-41d4-a716-446655440000"}, + wantErr: false, + }, + { + name: "valid UUID v4", + profileIDs: []string{uuid.New().String()}, + wantErr: false, + }, + { + name: "multiple valid UUIDs", + profileIDs: []string{"550e8400-e29b-41d4-a716-446655440000", uuid.New().String()}, + wantErr: false, + }, + { + name: "invalid UUID - span ID", + profileIDs: []string{"deadbeef12345678"}, + wantErr: true, + }, + { + name: "invalid UUID - random string", + profileIDs: []string{"not-a-uuid"}, + wantErr: true, + }, + { + name: "one valid one invalid", + profileIDs: []string{"550e8400-e29b-41d4-a716-446655440000", "not-a-uuid"}, + wantErr: true, + }, + { + name: "empty slice is valid (not provided)", + profileIDs: nil, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + params := &queryProfileParams{ProfileIDs: tt.profileIDs} + err := validateQueryProfileParams(params) + if tt.wantErr { + require.Error(t, err) + assert.Contains(t, err.Error(), "--profile-id must be a valid UUID") + } else { + require.NoError(t, err) + } + }) + } +} + +func TestQueryProfileParams_MutualExclusion(t *testing.T) { + t.Parallel() + + // --profile-id and --span-selector cannot be used together. + err := validateQueryProfileParams(&queryProfileParams{ + ProfileIDs: []string{"550e8400-e29b-41d4-a716-446655440000"}, + SpanSelector: []string{"deadbeef12345678"}, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "--profile-id and --span-selector cannot be used together") + + // No conflict when only profile-id is set. + err = validateQueryProfileParams(&queryProfileParams{ + ProfileIDs: []string{"550e8400-e29b-41d4-a716-446655440000"}, + }) + require.NoError(t, err) + + // No conflict when only span-selector is set. + err = validateQueryProfileParams(&queryProfileParams{ + SpanSelector: []string{"deadbeef12345678"}, + }) + require.NoError(t, err) + + // --span-selector and --stacktrace-selector cannot be used together. + err = validateQueryProfileParams(&queryProfileParams{ + SpanSelector: []string{"deadbeef12345678"}, + StacktraceSelector: []string{"main"}, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "--span-selector and --stacktrace-selector cannot be used together") + + // --trace-id and --span-selector cannot be used together. + err = validateQueryProfileParams(&queryProfileParams{ + TraceIDs: []string{"0123456789abcdef0123456789abcdef"}, + SpanSelector: []string{"deadbeef12345678"}, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "--trace-id and --span-selector cannot be used together") + + // --trace-id and --profile-id cannot be used together. + err = validateQueryProfileParams(&queryProfileParams{ + TraceIDs: []string{"0123456789abcdef0123456789abcdef"}, + ProfileIDs: []string{"550e8400-e29b-41d4-a716-446655440000"}, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "--trace-id and --profile-id cannot be used together") +} + +func TestQueryProfileParams_TraceIDValidation(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + traceIDs []string + wantErr bool + }{ + {name: "valid 32-char hex", traceIDs: []string{"0123456789abcdef0123456789abcdef"}, wantErr: false}, + {name: "multiple valid", traceIDs: []string{"0123456789abcdef0123456789abcdef", "ffffffffffffffffffffffffffffffff"}, wantErr: false}, + {name: "too short (span id)", traceIDs: []string{"deadbeef12345678"}, wantErr: true}, + {name: "invalid hex", traceIDs: []string{"0123456789abcdef0123456789abcdeg"}, wantErr: true}, + {name: "empty slice is valid", traceIDs: nil, wantErr: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + err := validateQueryProfileParams(&queryProfileParams{TraceIDs: tt.traceIDs}) + if tt.wantErr { + require.Error(t, err) + assert.Contains(t, err.Error(), "--trace-id must be a 32-character hex string") + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/cmd/profilecli/raft.go b/cmd/profilecli/raft.go new file mode 100644 index 0000000000..35ea201018 --- /dev/null +++ b/cmd/profilecli/raft.go @@ -0,0 +1,140 @@ +package main + +import ( + "context" + "fmt" + "strings" + + "connectrpc.com/connect" + "google.golang.org/protobuf/encoding/protojson" + + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb/raftnodepbconnect" +) + +func (c *phlareClient) metadataOperatorClient() raftnodepbconnect.RaftNodeServiceClient { + return raftnodepbconnect.NewRaftNodeServiceClient( + c.httpClient(), + c.URL, + append( + connectapi.DefaultClientOptions(), + c.protocolOption(), + )..., + ) +} + +type raftInfoParams struct { + *phlareClient + + HumanFormat bool +} + +func addRaftInfoParams(cmd commander) *raftInfoParams { + params := &raftInfoParams{} + params.phlareClient = addPhlareClient(cmd) + + cmd.Flag("human", "Human readable output").Short('H').BoolVar(¶ms.HumanFormat) + + return params +} + +func raftInfo(ctx context.Context, params *raftInfoParams) error { + client := params.metadataOperatorClient() + + res, err := client.NodeInfo(ctx, connect.NewRequest(&raftnodepb.NodeInfoRequest{})) + if err != nil { + return err + } + + var s string + switch { + case params.HumanFormat: + s = formatHumanRaftInfo(res.Msg.Node) + default: + s, err = formatJSONRaftInfo(res.Msg.Node) + if err != nil { + return err + } + } + + fmt.Println(s) + return nil +} + +func formatHumanRaftInfo(node *raftnodepb.NodeInfo) string { + maxKeyPadding := func(keys []string) int { + max := 0 + for _, k := range keys { + if len(k) > max { + max = len(k) + } + } + return max + } + + appendPairs := func(sb *strings.Builder, pairs [][]string) { + keys := make([]string, 0, len(pairs)) + for _, pair := range pairs { + keys = append(keys, pair[0]) + } + + keyPadding := maxKeyPadding(keys) + for _, pair := range pairs { + key, value := pair[0], pair[1] + fmt.Fprintf(sb, "%s:", key) + sb.WriteString(strings.Repeat(" ", keyPadding-len(key)+1)) + fmt.Fprintf(sb, "%s\n", value) + } + } + + var sb strings.Builder + appendPairs(&sb, [][]string{ + {"ID", node.ServerId}, + {"Address", node.AdvertisedAddress}, + {"State", node.State}, + {"Leader ID", node.LeaderId}, + }) + + sb.WriteString("Log:\n") + appendPairs(&sb, [][]string{ + {" Commit index", fmt.Sprint(node.CommitIndex)}, + {" Applied index", fmt.Sprint(node.AppliedIndex)}, + {" Last index", fmt.Sprint(node.LastIndex)}, + }) + + sb.WriteString("Stats:\n") + for i := range node.Stats.Name { + appendPairs(&sb, [][]string{ + {" " + node.Stats.Name[i], node.Stats.Value[i]}, + }) + } + + sb.WriteString("Peers:\n") + for _, peer := range node.Peers { + appendPairs(&sb, [][]string{ + {" ID", peer.ServerId}, + {" Address", peer.ServerAddress}, + {" Suffrage", peer.Suffrage}, + }) + sb.WriteString("\n") // Give some space between entries. + } + + return strings.TrimSpace(sb.String()) +} + +func formatJSONRaftInfo(node *raftnodepb.NodeInfo) (string, error) { + // Pretty print the protobuf json and don't omit default values. + opts := protojson.MarshalOptions{ + Multiline: true, + Indent: " ", + EmitUnpopulated: true, + } + + bytes, err := opts.Marshal(node) + if err != nil { + return "", err + } + + return string(bytes), nil +} diff --git a/cmd/profilecli/ready.go b/cmd/profilecli/ready.go new file mode 100644 index 0000000000..9fb98624d5 --- /dev/null +++ b/cmd/profilecli/ready.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + + "github.com/go-kit/log/level" +) + +var ( + // Occurs when Pyroscope is not ready. + notReadyErr = errors.New("not ready") +) + +type readyParams struct { + *phlareClient +} + +func addReadyParams(cmd commander) *readyParams { + params := &readyParams{} + params.phlareClient = addPhlareClient(cmd) + + return params +} + +func ready(ctx context.Context, params *readyParams) error { + req, err := http.NewRequest("GET", fmt.Sprintf("%s/ready", params.URL), nil) + if err != nil { + return err + } + req = req.WithContext(ctx) + + client := params.phlareClient.httpClient() + res, err := client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + bytes, err := io.ReadAll(res.Body) + if err != nil { + return err + } + + if res.StatusCode != http.StatusOK { + level.Error(logger).Log("msg", "not ready", "status", res.Status, "body", string(bytes)) + return notReadyErr + } + + level.Info(logger).Log("msg", "ready") + return nil +} diff --git a/cmd/profilecli/recording_rules.go b/cmd/profilecli/recording_rules.go new file mode 100644 index 0000000000..5887930163 --- /dev/null +++ b/cmd/profilecli/recording_rules.go @@ -0,0 +1,190 @@ +package main + +import ( + "context" + "fmt" + "os" + + "connectrpc.com/connect" + "go.yaml.in/yaml/v3" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1/settingsv1connect" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" +) + +const createRuleExampleMsg = ` + Example: + # Create a rule that records the total CPU usage of the garbage collector function for every service in the "emea" region: + profilecli recording-rules create -f rule.yaml + + # rule.yaml: + matchers: + - '{ __profile_type__="process_cpu:cpu:nanoseconds:cpu:nanoseconds", region="emea"}' + metric_name: profiles_recorded_cpu_usage_function_total_gc_nanoseconds + group_by: + - service_name + function_name: runtime.gcBgMarkWorker` + +func (c *phlareClient) recordingRulesClient() settingsv1connect.RecordingRulesServiceClient { + return settingsv1connect.NewRecordingRulesServiceClient( + c.httpClient(), + c.URL, + append( + connectapi.DefaultClientOptions(), + c.protocolOption(), + )..., + ) +} + +type recordingRule struct { + Matchers []string `yaml:"matchers,omitempty" json:"matchers,omitempty"` + MetricName string `yaml:"metric_name,omitempty" json:"metric_name,omitempty"` + GroupBy []string `yaml:"group_by,omitempty" json:"group_by,omitempty"` + ExternalLabels []*v1.LabelPair `yaml:"external_labels,omitempty" json:"external_labels,omitempty"` + FunctionName string `yaml:"function_name,omitempty" json:"function_name,omitempty"` +} + +// convertToRecordingRule converts a protobuf RecordingRule to the local recordingRule struct +func convertToRecordingRule(r *settingsv1.RecordingRule) recordingRule { + rule := recordingRule{ + Matchers: make([]string, 0), + MetricName: r.MetricName, + GroupBy: r.GroupBy, + ExternalLabels: r.ExternalLabels, + } + for _, m := range r.Matchers { + if m != "{}" { + rule.Matchers = append(rule.Matchers, m) + } + } + if r.StacktraceFilter != nil && r.StacktraceFilter.FunctionName != nil { + rule.FunctionName = r.StacktraceFilter.FunctionName.FunctionName + } + return rule +} + +// formatAndPrintRecordingRule converts a protobuf RecordingRule to YAML and prints it +func formatAndPrintRecordingRule(r *settingsv1.RecordingRule) error { + rule := convertToRecordingRule(r) + + fmt.Printf("Rule with Id %s", r.Id) + if r.Provisioned { + fmt.Print(" (backend provisioned - read only)") + } + fmt.Println() + + data, err := yaml.Marshal(rule) + if err != nil { + return fmt.Errorf("failed to marshal rule to YAML: %w", err) + } + + fmt.Println(string(data)) + return nil +} + +func listRecordingRules(ctx context.Context, params *recordingRulesCmdParams) error { + client := params.recordingRulesClient() + req := settingsv1.ListRecordingRulesRequest{} + resp, err := client.ListRecordingRules(ctx, connect.NewRequest(&req)) + if err != nil { + return err + } + for _, r := range resp.Msg.Rules { + if err := formatAndPrintRecordingRule(r); err != nil { + return err + } + } + return nil +} + +func getRecordingRule(ctx context.Context, id *string, outputFile *string, params *recordingRulesCmdParams) error { + client := params.recordingRulesClient() + req := settingsv1.GetRecordingRuleRequest{ + Id: *id, + } + resp, err := client.GetRecordingRule(ctx, connect.NewRequest(&req)) + if err != nil { + return err + } + + r := resp.Msg.Rule + + // If output file is specified, write to file + if outputFile != nil && *outputFile != "" { + rule := convertToRecordingRule(r) + data, err := yaml.Marshal(rule) + if err != nil { + return fmt.Errorf("failed to marshal rule to YAML: %w", err) + } + + err = os.WriteFile(*outputFile, data, 0644) + if err != nil { + return fmt.Errorf("failed to write to file: %w", err) + } + + fmt.Printf("Rule with Id %s written to %s\n", r.Id, *outputFile) + return nil + } + + // Otherwise, print to stdout + return formatAndPrintRecordingRule(r) +} + +func createRecordingRule(ctx context.Context, filePath *string, params *recordingRulesCmdParams) error { + client := params.recordingRulesClient() + + // Read the rule from file + data, err := os.ReadFile(*filePath) + if err != nil { + return fmt.Errorf("failed to read file: %w", err) + } + + var newRule recordingRule + err = yaml.Unmarshal(data, &newRule) + if err != nil { + return fmt.Errorf("failed to parse file: %w", err) + } + req := settingsv1.UpsertRecordingRuleRequest{ + MetricName: newRule.MetricName, + Matchers: newRule.Matchers, + GroupBy: newRule.GroupBy, + ExternalLabels: newRule.ExternalLabels, + } + if newRule.FunctionName != "" { + req.StacktraceFilter = &settingsv1.StacktraceFilter{FunctionName: &settingsv1.StacktraceFilterFunctionName{ + FunctionName: newRule.FunctionName, + MetricType: settingsv1.MetricType_TOTAL, + }} + } + resp, err := client.UpsertRecordingRule(ctx, connect.NewRequest(&req)) + if err != nil { + return err + } + fmt.Println("New recorded rule created with id:", resp.Msg.Rule.Id) + return nil +} + +func deleteRecordingRule(ctx context.Context, id *string, params *recordingRulesCmdParams) error { + client := params.recordingRulesClient() + req := settingsv1.DeleteRecordingRuleRequest{ + Id: *id, + } + _, err := client.DeleteRecordingRule(ctx, connect.NewRequest(&req)) + if err != nil { + return err + } + fmt.Println("Deleted recording rule with id:", *id) + return nil +} + +type recordingRulesCmdParams struct { + *phlareClient +} + +func addRecordingRulesListParams(recordingRulesListCmd commander) *recordingRulesCmdParams { + params := new(recordingRulesCmdParams) + params.phlareClient = addPhlareClient(recordingRulesListCmd) + return params +} diff --git a/cmd/profilecli/source_code_coverage.go b/cmd/profilecli/source_code_coverage.go new file mode 100644 index 0000000000..19bd01e7d3 --- /dev/null +++ b/cmd/profilecli/source_code_coverage.go @@ -0,0 +1,556 @@ +package main + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "sort" + "strings" + "time" + + "github.com/go-kit/log" + giturl "github.com/kubescape/go-git-url" + "golang.org/x/oauth2" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/source" + "github.com/grafana/pyroscope/v2/pkg/pprof" +) + +type hybridVCSClient struct { + configContent []byte + configPath string + realClient source.VCSClient +} + +func (c *hybridVCSClient) GetFile(ctx context.Context, req client.FileRequest) (client.File, error) { + // Intercept .pyroscope.yaml requests + // Check if this is a request for the config file + if req.Path == c.configPath || + req.Path == config.PyroscopeConfigPath || + strings.HasSuffix(req.Path, ".pyroscope.yaml") || + strings.HasSuffix(req.Path, "/.pyroscope.yaml") { + // Don't need real url since this is for config file + url := req.Path + return client.File{ + Content: string(c.configContent), + URL: url, + }, nil + } + // Delegate to real client for actual source files + return c.realClient.GetFile(ctx, req) +} + +type functionResult struct { + FunctionName string + Path string + Covered bool + Error string + ResolvedURL string + SampleCount int64 +} + +type coverageReport struct { + TotalFunctions int + CoveredFunctions int + UncoveredFunctions int + CoveragePercentage float64 + Results []functionResult +} + +type sourceCodeCoverageParams struct { + ProfilePath string + ConfigPath string + GithubToken string + OutputFormat string + ListFunctions bool + FunctionName string + TopN int +} + +func addSourceCodeCoverageParams(cmd commander) *sourceCodeCoverageParams { + params := new(sourceCodeCoverageParams) + cmd.Flag("profile", "Path to pprof profile file").Required().StringVar(¶ms.ProfilePath) + cmd.Flag("config", "Path to .pyroscope.yaml file").StringVar(¶ms.ConfigPath) + cmd.Flag("output", "Output format: text or detailed").Default("text").StringVar(¶ms.OutputFormat) + cmd.Flag("list-functions", "List all functions in the profile and exit").BoolVar(¶ms.ListFunctions) + cmd.Flag("function", "Check coverage for a specific function (by name or path)").StringVar(¶ms.FunctionName) + cmd.Flag("top", "Only process the top N functions by sample count (0 = process all)").Default("0").IntVar(¶ms.TopN) + cmd.Flag("github-token", "GitHub token for API access").Envar(envPrefix + "GITHUB_TOKEN").StringVar(¶ms.GithubToken) + return params +} + +func sourceCodeCoverage(ctx context.Context, params *sourceCodeCoverageParams) error { + // List functions mode + if params.ListFunctions { + return listAllFunctions(params.ProfilePath) + } + + // Single function check mode + if params.FunctionName != "" { + if params.ConfigPath == "" { + return errors.New("--config is required when using --function") + } + return checkSingleFunction(ctx, params) + } + + // Full coverage analysis mode + if params.ConfigPath == "" { + return errors.New("--config is required for full coverage analysis") + } + + return runCoverageAnalysis(ctx, params) +} + +func loadConfigAndProfile(configPath, profilePath string) (*config.PyroscopeConfig, []byte, *pprof.Profile, error) { + fmt.Fprintf(os.Stderr, "Reading configuration from %s...\n", configPath) + configData, err := os.ReadFile(configPath) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to read config file: %w", err) + } + + cfg, err := config.ParsePyroscopeConfig(configData) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to parse config: %w", err) + } + fmt.Fprintf(os.Stderr, "✓ Loaded configuration with %d mapping(s)\n", len(cfg.SourceCode.Mappings)) + + fmt.Fprintf(os.Stderr, "Reading profile from %s...\n", profilePath) + profile, err := pprof.OpenFile(profilePath) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to read profile: %w", err) + } + + return cfg, configData, profile, nil +} + +func setupVCSClient(ctx context.Context, configData []byte, githubToken string) (source.VCSClient, *http.Client, error) { + fmt.Fprintf(os.Stderr, "Setting up GitHub client...\n") + if githubToken == "" { + return nil, nil, errors.New("GitHub token required (use --github-token flag or PROFILECLI_GITHUB_TOKEN env var)") + } + + token := &oauth2.Token{AccessToken: githubToken} + httpClient := &http.Client{Timeout: 30 * time.Second} + ghClient, err := client.GithubClient(ctx, token, httpClient) + if err != nil { + return nil, nil, fmt.Errorf("failed to create GitHub client: %w", err) + } + fmt.Fprintf(os.Stderr, "✓ GitHub client ready\n") + + configPathInRepo := config.PyroscopeConfigPath + vcsClient := &hybridVCSClient{ + configContent: configData, + configPath: configPathInRepo, + realClient: ghClient, + } + + return vcsClient, httpClient, nil +} + +func checkFunctionCoverage(ctx context.Context, fn config.FileSpec, cfg *config.PyroscopeConfig, vcsClient source.VCSClient, httpClient *http.Client, logger log.Logger) functionResult { + result := functionResult{ + FunctionName: fn.FunctionName, + Path: fn.Path, + } + + mapping := cfg.FindMapping(fn) + + if mapping == nil { + result.Covered = false + result.Error = "no mapping found" + } else { + dummyRepo, _ := giturl.NewGitURL("https://github.com/dummy/repo") + + finder := source.NewFileFinder( + vcsClient, + dummyRepo, + fn, + "", + "", + httpClient, + logger, + ) + + response, err := finder.Find(ctx) + if err != nil { + result.Covered = false + result.Error = err.Error() + } else { + result.Covered = true + result.ResolvedURL = response.URL + } + } + + return result +} + +func runCoverageAnalysis(ctx context.Context, params *sourceCodeCoverageParams) error { + cfg, configData, profile, err := loadConfigAndProfile(params.ConfigPath, params.ProfilePath) + if err != nil { + return err + } + + fmt.Fprintf(os.Stderr, "Extracting functions from profile...\n") + functions := extractFunctions(profile.Profile) + fmt.Fprintf(os.Stderr, "✓ Found %d unique function(s)\n", len(functions)) + + fmt.Fprintf(os.Stderr, "Calculating sample counts and sorting functions...\n") + sampleCounts := calculateSampleCountsMap(profile.Profile) + + type funcWithCount struct { + fn config.FileSpec + count int64 + } + funcsWithCounts := make([]funcWithCount, 0, len(functions)) + for _, fn := range functions { + key := fmt.Sprintf("%s|%s", fn.FunctionName, fn.Path) + count := sampleCounts[key] + funcsWithCounts = append(funcsWithCounts, funcWithCount{fn: fn, count: count}) + } + + // Sort by sample count in descending order + sort.Slice(funcsWithCounts, func(i, j int) bool { + return funcsWithCounts[i].count > funcsWithCounts[j].count + }) + + if params.TopN > 0 && params.TopN < len(funcsWithCounts) { + funcsWithCounts = funcsWithCounts[:params.TopN] + fmt.Fprintf(os.Stderr, "✓ Filtered to top %d functions by sample count\n", len(funcsWithCounts)) + } else { + fmt.Fprintf(os.Stderr, "✓ Sorted %d functions by sample count\n", len(funcsWithCounts)) + } + + functions = make([]config.FileSpec, len(funcsWithCounts)) + for i, fwc := range funcsWithCounts { + functions[i] = fwc.fn + } + + vcsClient, httpClient, err := setupVCSClient(ctx, configData, params.GithubToken) + if err != nil { + return err + } + + logger := log.NewNopLogger() + fmt.Fprintf(os.Stderr, "\nAnalyzing coverage (this may take a while)...\n") + report := analyzeCoverage(ctx, profile.Profile, functions, cfg, vcsClient, httpClient, logger) + + fmt.Fprintf(os.Stderr, "\nGenerating report...\n") + return generateOutput(report, params.OutputFormat) +} + +func extractFunctions(profile *profilev1.Profile) []config.FileSpec { + seen := make(map[string]bool) + var functions []config.FileSpec + + for _, fn := range profile.Function { + var functionName, filePath string + + if fn.Name > 0 && int(fn.Name) < len(profile.StringTable) { + functionName = profile.StringTable[fn.Name] + } + if fn.Filename > 0 && int(fn.Filename) < len(profile.StringTable) { + filePath = profile.StringTable[fn.Filename] + } + + // Skip functions with no name or path + if functionName == "" && filePath == "" { + continue + } + + // Create a unique key for this function + key := fmt.Sprintf("%s|%s", functionName, filePath) + if seen[key] { + continue + } + seen[key] = true + + functions = append(functions, config.FileSpec{ + FunctionName: functionName, + Path: filePath, + }) + } + + return functions +} + +func analyzeCoverage(ctx context.Context, profile *profilev1.Profile, functions []config.FileSpec, cfg *config.PyroscopeConfig, vcsClient source.VCSClient, httpClient *http.Client, logger log.Logger) *coverageReport { + report := &coverageReport{ + TotalFunctions: len(functions), + Results: make([]functionResult, 0, len(functions)), + } + + functionSampleCounts := calculateSampleCountsMap(profile) + + total := len(functions) + for i, fn := range functions { + key := fmt.Sprintf("%s|%s", fn.FunctionName, fn.Path) + sampleCount := functionSampleCounts[key] + + fmt.Fprintf(os.Stderr, "Processing function %d/%d: %s", i+1, total, fn.FunctionName) + if fn.Path != "" { + fmt.Fprintf(os.Stderr, " (%s)", fn.Path) + } + fmt.Fprintf(os.Stderr, " (samples: %d)... ", sampleCount) + + result := checkFunctionCoverage(ctx, fn, cfg, vcsClient, httpClient, logger) + result.SampleCount = sampleCount + + if result.Covered { + fmt.Fprintf(os.Stderr, "✓\n") + report.CoveredFunctions++ + } else { + fmt.Fprintf(os.Stderr, "✗\n") + } + + report.Results = append(report.Results, result) + } + + report.UncoveredFunctions = report.TotalFunctions - report.CoveredFunctions + if report.TotalFunctions > 0 { + report.CoveragePercentage = float64(report.CoveredFunctions) / float64(report.TotalFunctions) * 100 + } + + report.sortBySampleCount() + + fmt.Fprintf(os.Stderr, "\n✓ Analysis complete: %d/%d functions covered (%.2f%%)\n", + report.CoveredFunctions, report.TotalFunctions, report.CoveragePercentage) + + return report +} + +func calculateSampleCountsMap(profile *profilev1.Profile) map[string]int64 { + functionSampleCounts := make(map[string]int64) + + // Build maps for efficient lookup by ID (IDs are 1-indexed and may not be sequential) + locationMap := make(map[uint64]*profilev1.Location) + for _, loc := range profile.Location { + locationMap[loc.Id] = loc + } + + functionMap := make(map[uint64]*profilev1.Function) + for _, fn := range profile.Function { + functionMap[fn.Id] = fn + } + + // Process each sample in the profile + for _, sample := range profile.Sample { + // Sum all sample values (there can be multiple sample types) + var sampleValue int64 + for _, value := range sample.Value { + sampleValue += value + } + + if sampleValue == 0 { + continue + } + + // Count samples for each function in the stack + seenFunctions := make(map[string]bool) + for _, locationID := range sample.LocationId { + location, ok := locationMap[locationID] + if !ok { + continue + } + for _, line := range location.Line { + if line.FunctionId == 0 { + continue + } + fn, ok := functionMap[line.FunctionId] + if !ok { + continue + } + + // Extract function name and path + var functionName, filePath string + if fn.Name > 0 && int(fn.Name) < len(profile.StringTable) { + functionName = profile.StringTable[fn.Name] + } + if fn.Filename > 0 && int(fn.Filename) < len(profile.StringTable) { + filePath = profile.StringTable[fn.Filename] + } + + // Use function key to avoid double counting in the same sample + key := fmt.Sprintf("%s|%s", functionName, filePath) + if !seenFunctions[key] { + functionSampleCounts[key] += sampleValue + seenFunctions[key] = true + } + } + } + } + + return functionSampleCounts +} + +func (r *coverageReport) sortBySampleCount() { + sort.Slice(r.Results, func(i, j int) bool { + return r.Results[i].SampleCount > r.Results[j].SampleCount + }) +} + +func generateOutput(report *coverageReport, format string) error { + switch format { + case "text": + outputText(report) + case "detailed": + outputDetailed(report) + default: + return fmt.Errorf("unknown output format: %s", format) + } + + return nil +} + +func outputText(report *coverageReport) { + fmt.Println("=== Coverage Summary ===") + fmt.Printf("Total Functions: %d\n", report.TotalFunctions) + fmt.Printf("Covered Functions: %d\n", report.CoveredFunctions) + fmt.Printf("Uncovered Functions: %d\n", report.UncoveredFunctions) + fmt.Printf("Coverage: %.2f%%\n", report.CoveragePercentage) + fmt.Println() +} + +func outputDetailed(report *coverageReport) { + fmt.Println("=== Detailed Results (ordered by sample count) ===") + fmt.Println() + + // Results are already sorted by sample count in descending order + for _, result := range report.Results { + if result.Covered { + fmt.Printf(" ✓ %s", result.FunctionName) + } else { + fmt.Printf(" ✗ %s", result.FunctionName) + } + fmt.Printf(" (samples: %d)\n", result.SampleCount) + if result.Path != "" { + fmt.Printf(" Path: %s\n", result.Path) + } + if result.Covered { + if result.ResolvedURL != "" { + fmt.Printf(" URL: %s\n", result.ResolvedURL) + } + } else { + if result.Error != "" { + fmt.Printf(" Error: %s\n", result.Error) + } + if result.Error == "no mapping found" { + fmt.Printf(" No mapping found\n") + } + } + fmt.Println() + } +} + +func listAllFunctions(profilePath string) error { + fmt.Fprintf(os.Stderr, "Reading profile from %s...\n", profilePath) + profile, err := pprof.OpenFile(profilePath) + if err != nil { + return fmt.Errorf("failed to read profile: %w", err) + } + + fmt.Fprintf(os.Stderr, "Extracting functions from profile...\n") + functions := extractFunctions(profile.Profile) + fmt.Fprintf(os.Stderr, "✓ Found %d unique function(s)\n\n", len(functions)) + + fmt.Println("=== Functions in Profile ===") + fmt.Printf("Total: %d\n\n", len(functions)) + for i, fn := range functions { + fmt.Printf("%d. Function: %s\n", i+1, fn.FunctionName) + if fn.Path != "" { + fmt.Printf(" Path: %s\n", fn.Path) + } + fmt.Println() + } + + return nil +} + +func checkSingleFunction(ctx context.Context, params *sourceCodeCoverageParams) error { + cfg, configData, profile, err := loadConfigAndProfile(params.ConfigPath, params.ProfilePath) + if err != nil { + return err + } + + fmt.Fprintf(os.Stderr, "Extracting functions from profile...\n") + allFunctions := extractFunctions(profile.Profile) + + var matchingFunctions []config.FileSpec + for _, fn := range allFunctions { + if fn.FunctionName == params.FunctionName || fn.Path == params.FunctionName || + strings.Contains(fn.FunctionName, params.FunctionName) || + strings.Contains(fn.Path, params.FunctionName) { + matchingFunctions = append(matchingFunctions, fn) + } + } + + if len(matchingFunctions) == 0 { + return fmt.Errorf("no function found matching: %s", params.FunctionName) + } + + if len(matchingFunctions) > 1 { + fmt.Fprintf(os.Stderr, "⚠ Found %d matching functions, checking all of them...\n\n", len(matchingFunctions)) + } + + vcsClient, httpClient, err := setupVCSClient(ctx, configData, params.GithubToken) + if err != nil { + return err + } + + logger := log.NewNopLogger() + fmt.Fprintf(os.Stderr, "\nChecking coverage for function(s)...\n") + results := make([]functionResult, 0, len(matchingFunctions)) + + for i, fn := range matchingFunctions { + if len(matchingFunctions) > 1 { + fmt.Fprintf(os.Stderr, "\n[%d/%d] ", i+1, len(matchingFunctions)) + } + fmt.Fprintf(os.Stderr, "Function: %s", fn.FunctionName) + if fn.Path != "" { + fmt.Fprintf(os.Stderr, " (Path: %s)", fn.Path) + } + fmt.Fprintf(os.Stderr, "... ") + + result := checkFunctionCoverage(ctx, fn, cfg, vcsClient, httpClient, logger) + if result.Covered { + fmt.Fprintf(os.Stderr, "✓\n") + } else { + fmt.Fprintf(os.Stderr, "✗\n") + } + + results = append(results, result) + } + + fmt.Fprintf(os.Stderr, "\nGenerating report...\n\n") + return outputSingleFunctionResults(results) +} + +func outputSingleFunctionResults(results []functionResult) error { + for i, result := range results { + if len(results) > 1 { + fmt.Printf("=== Function %d ===\n", i+1) + } else { + fmt.Println("=== Function Coverage ===") + } + fmt.Printf("Function Name: %s\n", result.FunctionName) + if result.Path != "" { + fmt.Printf("Path: %s\n", result.Path) + } + fmt.Printf("Covered: %v\n", result.Covered) + if result.Covered { + fmt.Printf("Resolved URL: %s\n", result.ResolvedURL) + } else { + if result.Error != "" { + fmt.Printf("Error: %s\n", result.Error) + } + } + if i < len(results)-1 { + fmt.Println() + } + } + return nil +} diff --git a/cmd/profilecli/source_code_coverage_test.go b/cmd/profilecli/source_code_coverage_test.go new file mode 100644 index 0000000000..91d394b8f5 --- /dev/null +++ b/cmd/profilecli/source_code_coverage_test.go @@ -0,0 +1,594 @@ +package main + +import ( + "context" + "net/http" + "os" + "path/filepath" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" +) + +func TestExtractFunctions(t *testing.T) { + tests := []struct { + name string + profile *profilev1.Profile + expected []config.FileSpec + }{ + { + name: "extract functions with names and paths", + profile: &profilev1.Profile{ + StringTable: []string{"", "main", "foo", "bar", "/path/to/main.go", "/path/to/bar.go"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 4}, // main in /path/to/main.go + {Id: 2, Name: 2, Filename: 4}, // foo in /path/to/main.go + {Id: 3, Name: 3, Filename: 5}, // bar in /path/to/bar.go + }, + }, + expected: []config.FileSpec{ + {FunctionName: "main", Path: "/path/to/main.go"}, + {FunctionName: "foo", Path: "/path/to/main.go"}, + {FunctionName: "bar", Path: "/path/to/bar.go"}, + }, + }, + { + name: "skip functions with no name or path", + profile: &profilev1.Profile{ + StringTable: []string{"", "main", "/path/to/main.go"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 2}, // main in /path/to/main.go + {Id: 2, Name: 0, Filename: 0}, // no name or path - should be skipped + }, + }, + expected: []config.FileSpec{ + {FunctionName: "main", Path: "/path/to/main.go"}, + }, + }, + { + name: "deduplicate functions", + profile: &profilev1.Profile{ + StringTable: []string{"", "main", "/path/to/main.go"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 2}, // main in /path/to/main.go + {Id: 2, Name: 1, Filename: 2}, // duplicate - should be skipped + }, + }, + expected: []config.FileSpec{ + {FunctionName: "main", Path: "/path/to/main.go"}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractFunctions(tt.profile) + require.Equal(t, len(tt.expected), len(result)) + for i, expected := range tt.expected { + require.Equal(t, expected.FunctionName, result[i].FunctionName) + require.Equal(t, expected.Path, result[i].Path) + } + }) + } +} + +func TestCalculateSampleCountsMap(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{"", "main", "foo", "/path/to/main.go", "/path/to/foo.go"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 3}, // main in /path/to/main.go + {Id: 2, Name: 2, Filename: 4}, // foo in /path/to/foo.go + }, + Location: []*profilev1.Location{ + {Id: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 10}}}, + {Id: 2, Line: []*profilev1.Line{{FunctionId: 2, Line: 20}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{5}}, // 5 samples for main + {LocationId: []uint64{1}, Value: []int64{3}}, // 3 more samples for main + {LocationId: []uint64{2}, Value: []int64{2}}, // 2 samples for foo + {LocationId: []uint64{1, 2}, Value: []int64{1}}, // 1 sample for both (should count both) + }, + } + + result := calculateSampleCountsMap(profile) + + require.Equal(t, int64(9), result["main|/path/to/main.go"]) // 5 + 3 + 1 + require.Equal(t, int64(3), result["foo|/path/to/foo.go"]) // 2 + 1 +} + +func TestGenerateOutput(t *testing.T) { + report := &coverageReport{ + TotalFunctions: 10, + CoveredFunctions: 7, + UncoveredFunctions: 3, + CoveragePercentage: 70.0, + Results: []functionResult{ + {FunctionName: "main", Path: "/main.go", Covered: true, SampleCount: 100}, + {FunctionName: "foo", Path: "/foo.go", Covered: false, SampleCount: 50}, + }, + } + + t.Run("text format", func(t *testing.T) { + // Capture stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + err := generateOutput(report, "text") + require.NoError(t, err) + + w.Close() + os.Stdout = oldStdout + + output := make([]byte, 1024) + n, _ := r.Read(output) + outputStr := string(output[:n]) + + require.Contains(t, outputStr, "Coverage Summary") + require.Contains(t, outputStr, "Total Functions: 10") + require.Contains(t, outputStr, "Covered Functions: 7") + require.Contains(t, outputStr, "Coverage: 70.00%") + }) + + t.Run("detailed format", func(t *testing.T) { + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + err := generateOutput(report, "detailed") + require.NoError(t, err) + + w.Close() + os.Stdout = oldStdout + + output := make([]byte, 1024) + n, _ := r.Read(output) + outputStr := string(output[:n]) + + require.Contains(t, outputStr, "Detailed Results") + require.Contains(t, outputStr, "main") + require.Contains(t, outputStr, "foo") + }) + + t.Run("unknown format", func(t *testing.T) { + err := generateOutput(report, "unknown") + require.Error(t, err) + require.Contains(t, err.Error(), "unknown output format") + }) +} + +func TestListAllFunctions(t *testing.T) { + // Create a temporary profile file + builder := testhelper.NewProfileBuilder(1000). + CPUProfile(). + ForStacktraceString("main", "foo", "bar").AddSamples(10) + + profileBytes, err := builder.MarshalVT() + require.NoError(t, err) + + tmpFile, err := os.CreateTemp("", "test-profile-*.pprof") + require.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + _, err = tmpFile.Write(profileBytes) + require.NoError(t, err) + tmpFile.Close() + + t.Run("text output", func(t *testing.T) { + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + err := listAllFunctions(tmpFile.Name()) + require.NoError(t, err) + + w.Close() + os.Stdout = oldStdout + + output := make([]byte, 1024) + n, _ := r.Read(output) + outputStr := string(output[:n]) + + require.Contains(t, outputStr, "Functions in Profile") + require.Contains(t, outputStr, "Total:") + }) + + t.Run("invalid profile file", func(t *testing.T) { + err := listAllFunctions("/nonexistent/file.pprof") + require.Error(t, err) + }) +} + +func TestCoverageReportSortBySampleCount(t *testing.T) { + report := &coverageReport{ + Results: []functionResult{ + {FunctionName: "low", SampleCount: 10}, + {FunctionName: "high", SampleCount: 100}, + {FunctionName: "medium", SampleCount: 50}, + }, + } + + report.sortBySampleCount() + + require.Equal(t, "high", report.Results[0].FunctionName) + require.Equal(t, int64(100), report.Results[0].SampleCount) + require.Equal(t, "medium", report.Results[1].FunctionName) + require.Equal(t, int64(50), report.Results[1].SampleCount) + require.Equal(t, "low", report.Results[2].FunctionName) + require.Equal(t, int64(10), report.Results[2].SampleCount) +} + +func TestHybridVCSClient(t *testing.T) { + configContent := []byte("source_code:\n mappings: []") + configPath := ".pyroscope.yaml" + + mockClient := &mockVCSClient{} + hybridClient := &hybridVCSClient{ + configContent: configContent, + configPath: configPath, + realClient: mockClient, + } + + t.Run("intercepts config file requests", func(t *testing.T) { + req := client.FileRequest{ + Owner: "test", + Repo: "repo", + Ref: "main", + Path: configPath, + } + + file, err := hybridClient.GetFile(context.Background(), req) + require.NoError(t, err) + require.Equal(t, string(configContent), file.Content) + }) + + t.Run("delegates to real client for source files", func(t *testing.T) { + req := client.FileRequest{ + Owner: "test", + Repo: "repo", + Ref: "main", + Path: "src/main.go", + } + + file, err := hybridClient.GetFile(context.Background(), req) + require.NoError(t, err) + require.Equal(t, "mock content", file.Content) + require.Equal(t, "https://github.com/test/repo/blob/main/src/main.go", file.URL) + }) +} + +type mockVCSClient struct{} + +func (m *mockVCSClient) GetFile(ctx context.Context, req client.FileRequest) (client.File, error) { + return client.File{ + Content: "mock content", + URL: "https://github.com/" + req.Owner + "/" + req.Repo + "/blob/" + req.Ref + "/" + req.Path, + }, nil +} + +func TestOutputSingleFunctionResults(t *testing.T) { + results := []functionResult{ + { + FunctionName: "testFunc", + Path: "/test.go", + Covered: true, + ResolvedURL: "https://github.com/test/repo/blob/main/test.go", + SampleCount: 100, + }, + } + + t.Run("text output", func(t *testing.T) { + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + err := outputSingleFunctionResults(results) + require.NoError(t, err) + + w.Close() + os.Stdout = oldStdout + + output := make([]byte, 1024) + n, _ := r.Read(output) + outputStr := string(output[:n]) + + require.Contains(t, outputStr, "Function Coverage") + require.Contains(t, outputStr, "testFunc") + require.Contains(t, outputStr, "/test.go") + require.Contains(t, outputStr, "Covered: true") + }) + +} + +func TestAnalyzeCoverage(t *testing.T) { + builder := testhelper.NewProfileBuilder(1000). + CPUProfile(). + ForStacktraceString("main", "foo").AddSamples(10) + + profileBytes, err := builder.MarshalVT() + require.NoError(t, err) + + profile, err := pprof.RawFromBytes(profileBytes) + require.NoError(t, err) + + cfg := &config.PyroscopeConfig{ + SourceCode: config.SourceCodeConfig{ + Mappings: []config.MappingConfig{}, + }, + } + + mockClient := &mockVCSClient{} + + functions := extractFunctions(profile.Profile) + require.Equal(t, len(functions), 2) + + logger := log.NewNopLogger() + httpClient := &http.Client{Timeout: 30 * time.Second} + report := analyzeCoverage( + context.Background(), + profile.Profile, + functions, + cfg, + mockClient, + httpClient, + logger, + ) + + require.Equal(t, len(functions), report.TotalFunctions) + require.Equal(t, report.CoveredFunctions, 0) + // No mappings in config + require.Equal(t, report.UncoveredFunctions, 2) + require.Equal(t, len(functions), len(report.Results)) +} + +func TestRunCoverageAnalysis_InvalidProfile(t *testing.T) { + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, ".pyroscope.yaml") + profilePath := filepath.Join(tmpDir, "nonexistent.pprof") + + configContent := `source_code: + mappings: []` + err := os.WriteFile(configPath, []byte(configContent), 0644) + require.NoError(t, err) + + params := &sourceCodeCoverageParams{ + ProfilePath: profilePath, + ConfigPath: configPath, + GithubToken: "test-token", + OutputFormat: "text", + TopN: 0, + } + + err = runCoverageAnalysis(context.Background(), params) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to read profile") +} + +func TestRunCoverageAnalysis_InvalidConfig(t *testing.T) { + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, ".pyroscope.yaml") + profilePath := filepath.Join(tmpDir, "test.pprof") + + // Create invalid config file + err := os.WriteFile(configPath, []byte("invalid yaml: [["), 0644) + require.NoError(t, err) + + builder := testhelper.NewProfileBuilder(1000).CPUProfile() + profileBytes, err := builder.MarshalVT() + require.NoError(t, err) + err = os.WriteFile(profilePath, profileBytes, 0644) + require.NoError(t, err) + + params := &sourceCodeCoverageParams{ + ProfilePath: profilePath, + ConfigPath: configPath, + GithubToken: "test-token", + OutputFormat: "text", + TopN: 0, + } + + err = runCoverageAnalysis(context.Background(), params) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to parse config") +} + +func TestSourceCodeCoverage_ListFunctionsMode(t *testing.T) { + builder := testhelper.NewProfileBuilder(1000). + CPUProfile(). + ForStacktraceString("main", "foo").AddSamples(10) + + profileBytes, err := builder.MarshalVT() + require.NoError(t, err) + + tmpFile, err := os.CreateTemp("", "test-profile-*.pprof") + require.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + _, err = tmpFile.Write(profileBytes) + require.NoError(t, err) + tmpFile.Close() + + params := &sourceCodeCoverageParams{ + ProfilePath: tmpFile.Name(), + ListFunctions: true, + OutputFormat: "text", + } + + err = sourceCodeCoverage(context.Background(), params) + require.NoError(t, err) +} + +func TestSourceCodeCoverage_ValidationErrors(t *testing.T) { + t.Run("missing config and repo for function check", func(t *testing.T) { + params := &sourceCodeCoverageParams{ + ProfilePath: "test.pprof", + FunctionName: "testFunc", + } + + err := sourceCodeCoverage(context.Background(), params) + require.Error(t, err) + require.Contains(t, err.Error(), "--config is required") + }) +} + +func TestOutputDetailed_ShowsErrors(t *testing.T) { + report := &coverageReport{ + Results: []functionResult{ + { + FunctionName: "func1", + Path: "/path/to/func1.go", + Covered: false, + Error: "file not found", + SampleCount: 10, + }, + { + FunctionName: "func2", + Path: "/path/to/func2.go", + Covered: true, + ResolvedURL: "https://github.com/test/repo/blob/main/path/to/func2.go", + SampleCount: 20, + }, + }, + } + + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + outputDetailed(report) + + w.Close() + os.Stdout = oldStdout + + output := make([]byte, 2048) + n, _ := r.Read(output) + outputStr := string(output[:n]) + + // Errors should always be shown + require.Contains(t, outputStr, "file not found") + require.Contains(t, outputStr, "func1") + require.Contains(t, outputStr, "func2") + require.Contains(t, outputStr, "URL:") +} + +func TestCheckSingleFunction_NoMatch(t *testing.T) { + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, ".pyroscope.yaml") + profilePath := filepath.Join(tmpDir, "test.pprof") + + configContent := `source_code: + mappings: []` + err := os.WriteFile(configPath, []byte(configContent), 0644) + require.NoError(t, err) + + builder := testhelper.NewProfileBuilder(1000).CPUProfile() + profileBytes, err := builder.MarshalVT() + require.NoError(t, err) + err = os.WriteFile(profilePath, profileBytes, 0644) + require.NoError(t, err) + + params := &sourceCodeCoverageParams{ + ProfilePath: profilePath, + ConfigPath: configPath, + FunctionName: "nonexistentFunction", + GithubToken: "test-token", + OutputFormat: "text", + } + + err = checkSingleFunction(context.Background(), params) + require.Error(t, err) + require.Contains(t, err.Error(), "no function found matching") +} + +func TestExtractFunctions_EdgeCases(t *testing.T) { + t.Run("empty profile", func(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{""}, + Function: []*profilev1.Function{}, + } + result := extractFunctions(profile) + require.Empty(t, result) + }) + + t.Run("function with only name", func(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{"", "main"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 0}, + }, + } + result := extractFunctions(profile) + require.Len(t, result, 1) + require.Equal(t, "main", result[0].FunctionName) + require.Equal(t, "", result[0].Path) + }) + + t.Run("function with only path", func(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{"", "/path/to/file.go"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 0, Filename: 1}, + }, + } + result := extractFunctions(profile) + require.Len(t, result, 1) + require.Equal(t, "", result[0].FunctionName) + require.Equal(t, "/path/to/file.go", result[0].Path) + }) +} + +func TestCalculateSampleCountsMap_EdgeCases(t *testing.T) { + t.Run("empty samples", func(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{""}, + Function: []*profilev1.Function{}, + Location: []*profilev1.Location{}, + Sample: []*profilev1.Sample{}, + } + result := calculateSampleCountsMap(profile) + require.Empty(t, result) + }) + + t.Run("sample with zero value", func(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{"", "main", "/main.go"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 2}, + }, + Location: []*profilev1.Location{ + {Id: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 10}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{0}}, // Zero value - should be skipped + }, + } + result := calculateSampleCountsMap(profile) + require.Empty(t, result) + }) + + t.Run("multiple sample types", func(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{"", "main", "/main.go"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 2}, + }, + Location: []*profilev1.Location{ + {Id: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 10}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{5, 10}}, // Multiple values - should sum + }, + } + result := calculateSampleCountsMap(profile) + require.Equal(t, int64(15), result["main|/main.go"]) // 5 + 10 + }) +} diff --git a/cmd/profilecli/static/bootstrap-5.1.3.bundle.min.js b/cmd/profilecli/static/bootstrap-5.1.3.bundle.min.js deleted file mode 100644 index cc0a25561d..0000000000 --- a/cmd/profilecli/static/bootstrap-5.1.3.bundle.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/cmd/profilecli/static/bootstrap-5.1.3.min.css b/cmd/profilecli/static/bootstrap-5.1.3.min.css deleted file mode 100644 index 1472dec059..0000000000 --- a/cmd/profilecli/static/bootstrap-5.1.3.min.css +++ /dev/null @@ -1,7 +0,0 @@ -@charset "UTF-8";/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:33,37,41;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + .5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:.2rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.3rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-bottom,.navbar-expand-sm .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-bottom,.navbar-expand-md .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-bottom,.navbar-expand-lg .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-bottom,.navbar-expand-xl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-bottom,.navbar-expand-xxl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-bottom,.navbar-expand .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{-webkit-animation:placeholder-glow 2s ease-in-out infinite;animation:placeholder-glow 2s ease-in-out infinite}@-webkit-keyframes placeholder-glow{50%{opacity:.2}}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;-webkit-animation:placeholder-wave 2s linear infinite;animation:placeholder-wave 2s linear infinite}@-webkit-keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:#6c757d!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/cmd/profilecli/static/bootstrap-5.3.3.bundle.min.js b/cmd/profilecli/static/bootstrap-5.3.3.bundle.min.js new file mode 100644 index 0000000000..04e9185bd6 --- /dev/null +++ b/cmd/profilecli/static/bootstrap-5.3.3.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.3"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>n(t))).join(","):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",jt="collapsing",Mt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(jt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(jt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(Mt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function je(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const Me={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:je(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:je(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,jn=`hide${xn}`,Mn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,jn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,Mn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Mn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",js="Home",Ms="End",Fs="active",Hs="fade",Ws="show",Bs=".dropdown-toggle",zs=`:not(${Bs})`,Rs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',qs=`.nav-link${zs}, .list-group-item${zs}, [role="tab"]${zs}, ${Rs}`,Vs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Ks extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,js,Ms].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([js,Ms].includes(t.key))i=e[t.key===js?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Ks.getOrCreateInstance(i).show())}_getChildren(){return z.find(qs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Bs,Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(qs)?t:z.findOne(qs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Ks.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,Rs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Ks.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(Vs))Ks.getOrCreateInstance(t)})),m(Ks);const Qs=".bs.toast",Xs=`mouseover${Qs}`,Ys=`mouseout${Qs}`,Us=`focusin${Qs}`,Gs=`focusout${Qs}`,Js=`hide${Qs}`,Zs=`hidden${Qs}`,to=`show${Qs}`,eo=`shown${Qs}`,io="hide",no="show",so="showing",oo={animation:"boolean",autohide:"boolean",delay:"number"},ro={animation:!0,autohide:!0,delay:5e3};class ao extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return ro}static get DefaultType(){return oo}static get NAME(){return"toast"}show(){N.trigger(this._element,to).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(io),d(this._element),this._element.classList.add(no,so),this._queueCallback((()=>{this._element.classList.remove(so),N.trigger(this._element,eo),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Js).defaultPrevented||(this._element.classList.add(so),this._queueCallback((()=>{this._element.classList.add(io),this._element.classList.remove(so,no),N.trigger(this._element,Zs)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(no),super.dispose()}isShown(){return this._element.classList.contains(no)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Xs,(t=>this._onInteraction(t,!0))),N.on(this._element,Ys,(t=>this._onInteraction(t,!1))),N.on(this._element,Us,(t=>this._onInteraction(t,!0))),N.on(this._element,Gs,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ao.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ao),m(ao),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Ks,Toast:ao,Tooltip:cs}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/cmd/profilecli/static/bootstrap-5.3.3.min.css b/cmd/profilecli/static/bootstrap-5.3.3.min.css new file mode 100644 index 0000000000..39934146ff --- /dev/null +++ b/cmd/profilecli/static/bootstrap-5.3.3.min.css @@ -0,0 +1,6 @@ +@charset "UTF-8";/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--bs-offcanvas-padding-y)) calc(-.5 * var(--bs-offcanvas-padding-x)) calc(-.5 * var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/cmd/profilecli/tsdb.go b/cmd/profilecli/tsdb.go index 6c0d7264f6..6e9da32056 100644 --- a/cmd/profilecli/tsdb.go +++ b/cmd/profilecli/tsdb.go @@ -7,9 +7,9 @@ import ( "github.com/prometheus/prometheus/model/labels" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" ) func tsdbSeries(ctx context.Context, path string) error { diff --git a/cmd/profilecli/upload.go b/cmd/profilecli/upload.go index 19ca7a18f4..b2a096ec51 100644 --- a/cmd/profilecli/upload.go +++ b/cmd/profilecli/upload.go @@ -11,16 +11,19 @@ import ( pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/pprof" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) func (c *phlareClient) pusherClient() pushv1connect.PusherServiceClient { return pushv1connect.NewPusherServiceClient( c.httpClient(), c.URL, - connectapi.DefaultClientOptions()..., + append( + connectapi.DefaultClientOptions(), + c.protocolOption(), + )..., ) } @@ -46,7 +49,7 @@ func addUploadParams(cmd commander) *uploadParams { } func upload(ctx context.Context, params *uploadParams) (err error) { - pc := params.phlareClient.pusherClient() + pc := params.pusherClient() lblStrings := make([]string, 0, len(params.extraLabels)*2) for key, value := range params.extraLabels { @@ -82,7 +85,7 @@ func upload(ctx context.Context, params *uploadParams) (err error) { // detect name if no name has been set if lbl.Get(model.LabelNameProfileName) == "" { name := "unknown" - for _, t := range profile.Profile.SampleType { + for _, t := range profile.SampleType { if sid := int(t.Type); sid < len(profile.StringTable) { if s := profile.StringTable[sid]; s == "cpu" { name = "process_cpu" diff --git a/cmd/profilecli/v2-migration.go b/cmd/profilecli/v2-migration.go new file mode 100644 index 0000000000..9b358a062c --- /dev/null +++ b/cmd/profilecli/v2-migration.go @@ -0,0 +1,176 @@ +package main + +import ( + "container/list" + "context" + "flag" + "fmt" + "strings" + "time" + + "github.com/grafana/dskit/flagext" + "golang.org/x/sync/errgroup" + + pyroscopecfg "github.com/grafana/pyroscope/v2/pkg/cfg" + pyroscopeobj "github.com/grafana/pyroscope/v2/pkg/objstore" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" +) + +type v2MigrationBucketCleanupParams struct { + configFile string + configExpandEnv bool + dryRun string +} + +func (p *v2MigrationBucketCleanupParams) isDryRun() bool { + return p.dryRun != "false" +} + +type minimalConfig struct { + Bucket objstoreclient.Config `yaml:"storage"` +} + +// Note: These are not the flags used, but we need to register them to get the defaults. +func (c *minimalConfig) RegisterFlags(f *flag.FlagSet) { + c.Bucket.RegisterFlags(f) +} + +func (c *minimalConfig) ApplyDynamicConfig() pyroscopecfg.Source { + return func(dst pyroscopecfg.Cloneable) error { + return nil + } +} + +func (c *minimalConfig) Clone() flagext.Registerer { + return func(c minimalConfig) *minimalConfig { + return &c + }(*c) +} + +func clientFromParams(ctx context.Context, params *v2MigrationBucketCleanupParams) (pyroscopeobj.Bucket, error) { + if params.configFile == "" { + return nil, fmt.Errorf("config file is required") + } + cfg := &minimalConfig{} + fs := flag.NewFlagSet("config-file-loader", flag.ContinueOnError) + if err := pyroscopecfg.Unmarshal(cfg, + pyroscopecfg.Defaults(fs), + pyroscopecfg.YAMLIgnoreUnknownFields(params.configFile, params.configExpandEnv), + ); err != nil { + return nil, fmt.Errorf("failed parsing config: %w", err) + } + + return objstoreclient.NewBucket(ctx, cfg.Bucket, "profilecli") +} + +func addV2MigrationBackupCleanupParam(c commander) *v2MigrationBucketCleanupParams { + var ( + params = &v2MigrationBucketCleanupParams{} + ) + c.Flag("config.file", "The path to the pyroscope config").Default("/etc/pyroscope/config.yaml").StringVar(¶ms.configFile) + c.Flag("config.expand-env", "").Default("false").BoolVar(¶ms.configExpandEnv) + c.Flag("dry-run", "Dry run the operation.").Default("true").StringVar(¶ms.dryRun) + return params +} + +func v2MigrationBucketCleanup(ctx context.Context, params *v2MigrationBucketCleanupParams) error { + client, err := clientFromParams(ctx, params) + if err != nil { + return fmt.Errorf("failed to create client: %w", err) + } + + var pathsToDelete []string + // find prefix called "phlaredb/" on the second level + if err := client.Iter(ctx, "", func(name string) error { + if !strings.HasSuffix(name, "/") { + return nil + } + err := client.Iter(ctx, name, func(name string) error { + if strings.HasSuffix(name, "phlaredb/") { + pathsToDelete = append(pathsToDelete, name) + } + return nil + }) + if err != nil { + return err + } + + return nil + }); err != nil { + return fmt.Errorf("failed to list tenants: %w", err) + } + + if len(pathsToDelete) == 0 { + fmt.Println("No paths to delete") + return nil + } + + if params.isDryRun() { + fmt.Println("DRY-RUN: If ran with --dry-run=false, this will delete everything under:") + } else { + fmt.Println("This will delete everything under:") + } + for _, path := range pathsToDelete { + fmt.Println(" - ", path) + } + + if params.isDryRun() { + fmt.Println("DRY-RUN: If ran with --dry-run=false, this will delete those object store keys:") + return recurse(ctx, client, func(key string) error { + fmt.Println(" - ", key) + return nil + }, pathsToDelete) + } + + // We do actually delete here + fmt.Println("Last chance to cancel, waiting 3 seconds...") + <-time.After(3 * time.Second) + + fmt.Println("Deleted object store keys:") + return recurse(ctx, client, func(key string) error { + if err := client.Delete(ctx, key); err != nil { + return fmt.Errorf("failed to delete %s: %w", key, err) + } + fmt.Println(" - ", key) + return nil + }, pathsToDelete) +} + +const maxConcurrentActions = 16 + +func recurse(ctx context.Context, b pyroscopeobj.Bucket, action func(key string) error, paths []string) error { + g, gctx := errgroup.WithContext(ctx) + g.SetLimit(maxConcurrentActions) + + g.Go(func() error { + iters := list.New() + for _, path := range paths { + iters.PushBack(path) + } + + for iters.Len() > 0 { + e := iters.Front() + path := e.Value.(string) + + if err := b.Iter(gctx, path, func(path string) error { + if strings.HasSuffix(path, "/") { + iters.PushBack(path) + return nil + } + + g.Go(func() error { + return action(path) + }) + + return nil + }); err != nil { + return fmt.Errorf("failed to iterate over %s: %w", path, err) + } + iters.Remove(e) + } + + return nil + }) + + return g.Wait() +} diff --git a/cmd/pyroscope/Dockerfile b/cmd/pyroscope/Dockerfile index aa0591eea4..b017104ada 100644 --- a/cmd/pyroscope/Dockerfile +++ b/cmd/pyroscope/Dockerfile @@ -1,17 +1,28 @@ -FROM alpine:3.18.6 +FROM gcr.io/distroless/static:debug@sha256:7dc183cc0aea6abd9d105135e49d37b7474a79391ebea7eb55557cd4486d2225 AS debug -RUN apk add --no-cache ca-certificates +SHELL [ "/busybox/sh", "-c" ] + +RUN addgroup -g 10001 -S pyroscope && \ + adduser -u 10001 -S pyroscope -G pyroscope -h /data + +FROM gcr.io/distroless/static@sha256:87bce11be0af225e4ca761c40babb06d6d559f5767fbf7dc3c47f0f1a466b92c + +COPY --from=debug /etc/passwd /etc/passwd +COPY --from=debug /etc/group /etc/group + +# Copy folder from debug container, this folder needs to have the correct UID +# in order for the container to run as non-root. +VOLUME /data +COPY --chown=pyroscope:pyroscope --from=debug /data /data +VOLUME /data-compactor +COPY --chown=pyroscope:pyroscope --from=debug /data /data-compactor +VOLUME /data-metastore +COPY --chown=pyroscope:pyroscope --from=debug /data /data-metastore COPY cmd/pyroscope/pyroscope.yaml /etc/pyroscope/config.yaml COPY profilecli /usr/bin/profilecli COPY pyroscope /usr/bin/pyroscope -RUN addgroup -g 10001 -S pyroscope && \ - adduser -u 10001 -S pyroscope -G pyroscope -RUN mkdir -p /data && \ - chown -R pyroscope:pyroscope /data -VOLUME /data - USER pyroscope EXPOSE 4040 ENTRYPOINT [ "/usr/bin/pyroscope" ] diff --git a/cmd/pyroscope/debug.Dockerfile b/cmd/pyroscope/debug.Dockerfile index ab963b74d4..6f33bc8df5 100644 --- a/cmd/pyroscope/debug.Dockerfile +++ b/cmd/pyroscope/debug.Dockerfile @@ -1,22 +1,22 @@ -FROM golang as builder +FROM gcr.io/distroless/static:debug@sha256:7dc183cc0aea6abd9d105135e49d37b7474a79391ebea7eb55557cd4486d2225 -WORKDIR /app -FROM alpine:3.18.6 +SHELL [ "/busybox/sh", "-c" ] -RUN apk add --no-cache ca-certificates +RUN addgroup -g 10001 -S pyroscope && \ + adduser -u 10001 -S pyroscope -G pyroscope -h /data -COPY .tmp/bin/linux_amd64/dlv /usr/bin/dlv +# Ensure folders are created correctly +VOLUME /data +VOLUME /data-compactor +VOLUME /data-metastore +RUN mkdir -p /data /data-compactor /data-metastore && \ + chown pyroscope:pyroscope /data /data-compactor /data-metastore +COPY .tmp/bin/dlv /usr/bin/dlv COPY cmd/pyroscope/pyroscope.yaml /etc/pyroscope/config.yaml COPY profilecli /usr/bin/profilecli COPY pyroscope /usr/bin/pyroscope -RUN addgroup -g 10001 -S pyroscope && \ - adduser -u 10001 -S pyroscope -G pyroscope -RUN mkdir -p /data && \ - chown -R pyroscope:pyroscope /data -VOLUME /data - USER pyroscope EXPOSE 4040 ENTRYPOINT ["/usr/bin/dlv", "--listen=:40000", "--headless=true", "--log", "--continue", "--accept-multiclient" , "--api-version=2", "exec", "/usr/bin/pyroscope", "--"] diff --git a/cmd/pyroscope/frontend.Dockerfile b/cmd/pyroscope/frontend.Dockerfile index d516e956d1..d9cfac6cf8 100644 --- a/cmd/pyroscope/frontend.Dockerfile +++ b/cmd/pyroscope/frontend.Dockerfile @@ -1,13 +1,15 @@ -FROM node:18 as builder -RUN apt-get update && apt-get install -y libpango1.0-dev libcairo2-dev -WORKDIR /pyroscope -COPY yarn.lock package.json tsconfig.json ./ -RUN yarn --frozen-lockfile -COPY scripts/webpack ./scripts/webpack/ -COPY public/app ./public/app -COPY public/templates ./public/templates +FROM node:24@sha256:bb20cf73b3ad7212834ec48e2174cdcb5775f6550510a5336b842ae32741ce6c AS builder + +WORKDIR /pyroscope/ui +COPY ui/package.json ui/yarn.lock ui/.yarnrc.yml ui/.npmrc ./ +RUN corepack enable && yarn install --immutable +COPY ui/index.html ui/vite.config.ts ./ +COPY ui/tsconfig*.json ./ +COPY ui/src ./src +COPY ui/public ./public RUN yarn build +# Output lands at /pyroscope/ui/dist/ (set by build.outDir in vite.config.ts) -# Usage: docker build -f cmd/pyroscope/frontend.Dockerfile --output=public/build . +# Usage: docker build -f cmd/pyroscope/frontend.Dockerfile --output=ui/dist . FROM scratch -COPY --from=builder /pyroscope/public/build / \ No newline at end of file +COPY --from=builder /pyroscope/ui/dist / diff --git a/cmd/pyroscope/help-all.txt.tmpl b/cmd/pyroscope/help-all.txt.tmpl index bf47cbe097..0a246412d8 100644 --- a/cmd/pyroscope/help-all.txt.tmpl +++ b/cmd/pyroscope/help-all.txt.tmpl @@ -1,6 +1,48 @@ Usage of ./pyroscope: + -adaptive-placement.burst-window duration + Duration of the burst window. During this time, scale-outs are more aggressive. (default 17m0s) + -adaptive-placement.decay-window duration + Duration of the decay window. During this time, scale-ins are delayed. (default 19m0s) + -adaptive-placement.default-dataset-shards uint + Default number of shards per dataset. (default 1) + -adaptive-placement.export-shard-limit-metrics + If enabled, shard limit metrics are exported as Prometheus metrics. (default true) + -adaptive-placement.export-shard-usage-breakdown-metrics + If enabled, shard utilization breakdown metrics, including shard ownership, are exported as Prometheus metrics. + -adaptive-placement.export-shard-usage-metrics + If enabled, shard utilization metrics are exported as Prometheus metrics. + -adaptive-placement.load-balancing value + Load balancing strategy; valid options: fingerprint, round-robin, dynamic. (default "dynamic") + -adaptive-placement.max-dataset-shards uint + Maximum number of shards per dataset. (default 1024) + -adaptive-placement.min-dataset-shards uint + Minimum number of shards per dataset. (default 1) + -adaptive-placement.placement-rules-retention-period duration + Retention period for inactive placement rules. (default 15m0s) + -adaptive-placement.placement-rules-update-interval duration + Interval between updates to placement rules. (default 15s) + -adaptive-placement.stats-aggregation-window duration + Time window for aggregating shard stats. (default 3m0s) + -adaptive-placement.stats-confidence-period duration + Confidence period for stats. During this period, placement rules are not updated. If 0, placement rules may be applied using incomplete stats. + -adaptive-placement.stats-retention-period duration + Retention period for stats that are no longer updated. (default 15m0s) + -adaptive-placement.tenant-shards uint + Number of shards per tenant. If 0, the limit is not applied. + -adaptive-placement.unit-size-bytes uint + Shards are allocated based on the utilisation of units per second. The option specifies the unit size in bytes. (default 131072) + -admin-server.http-listen-address string + Address for the admin HTTP server. Defaults to localhost so the port is not exposed externally. Use :: or 0.0.0.0 to listen on all interfaces. (default "localhost") + -admin-server.http-listen-port int + Port for the admin HTTP server (metrics, pprof, admin). (default 4042) + -admin-server.mode value + Controls the admin server for metrics, pprof and admin endpoints. 'disabled': all routes on the main port (default). 'additional': admin server started, operational routes served on both ports. 'exclusive': admin server started, operational routes removed from main port. (default "disabled") -api.base-url string base URL for when the server is behind a reverse proxy with a different path + -architecture.storage value + Storage architecture layer. Use 'v1' to use legacy ingester-based storage, 'v2' for new storage, and 'v1-v2-dual' to use new storage while being able to query old data. (default "v1-v2-dual") + -async-ingest + If true, the write path will not wait for the segment-writer to finish processing the request. Writes to ingester always synchronous. -auth.multitenancy-enabled When set to true, incoming HTTP requests must specify tenant ID in HTTP X-Scope-OrgId header. When set to false, tenant ID anonymous is used instead. -blocks-storage.bucket-store.ignore-blocks-within duration @@ -15,130 +57,152 @@ Usage of ./pyroscope: How frequently to scan the bucket, or to refresh the bucket index (if enabled), in order to look for changes (new blocks shipped by ingesters and blocks deleted by retention or compaction). (default 15m0s) -blocks-storage.bucket-store.tenant-sync-concurrency int Maximum number of concurrent tenants synching blocks. (default 10) + -compaction-worker.cleanup-max-duration duration + Maximum duration of the cleanup operations. (default 15s) + -compaction-worker.job-concurrency int + Number of concurrent jobs compaction worker will run. Defaults to the number of CPU cores. + -compaction-worker.job-poll-interval duration + Interval between job requests (default 5s) + -compaction-worker.metrics-exporter.enabled + This parameter specifies whether the metrics exporter is enabled. + -compaction-worker.metrics-exporter.remote-write-address string + The address to use for metrics tenant. + -compaction-worker.metrics-exporter.rules-source.client-address string + The address to use for the recording rules client connection. + -compaction-worker.metrics-exporter.rules-source.static value + [experimental] List of static recording rules of the type settingsv1.RecordingRule. Will only be use in the absence of a recording rules client. (default []) + -compaction-worker.request-timeout duration + Job request timeout. (default 5s) + -compaction-worker.small-object-size-bytes int + Size of the object that can be loaded in memory. (default 8388608) + -compaction-worker.temp-dir string + Temporary directory for compaction jobs. (default "/tmp") -compactor.block-ranges value - List of compaction time ranges. (default 1h0m0s,2h0m0s,8h0m0s) + [v1 storage only] List of compaction time ranges. (default 1h0m0s,2h0m0s,8h0m0s) -compactor.block-sync-concurrency int - Number of Go routines to use when downloading blocks for compaction and uploading resulting blocks. (default 8) + [v1 storage only] Number of Go routines to use when downloading blocks for compaction and uploading resulting blocks. (default 8) -compactor.blocks-retention-period duration - Delete blocks containing samples older than the specified retention period. 0 to disable. + [v1 storage only] Delete blocks containing samples older than the specified retention period. 0 to disable. -compactor.cleanup-concurrency int - Max number of tenants for which blocks cleanup and maintenance should run concurrently. (default 20) + [v1 storage only] Max number of tenants for which blocks cleanup and maintenance should run concurrently. (default 20) -compactor.cleanup-interval duration - How frequently compactor should run blocks cleanup and maintenance, as well as update the bucket index. (default 15m0s) + [v1 storage only] How frequently compactor should run blocks cleanup and maintenance, as well as update the bucket index. (default 15m0s) -compactor.compaction-concurrency int - Max number of concurrent compactions running. (default 1) + [v1 storage only] Max number of concurrent compactions running. (default 1) -compactor.compaction-interval duration - The frequency at which the compaction runs (default 30m0s) + [v1 storage only] The frequency at which the compaction runs (default 30m0s) -compactor.compaction-jobs-order string - The sorting to use when deciding which compaction jobs should run first for a given tenant. Supported values are: smallest-range-oldest-blocks-first, newest-blocks-first. (default "smallest-range-oldest-blocks-first") + [v1 storage only] The sorting to use when deciding which compaction jobs should run first for a given tenant. Supported values are: smallest-range-oldest-blocks-first, newest-blocks-first. (default "smallest-range-oldest-blocks-first") -compactor.compaction-retries int - How many times to retry a failed compaction within a single compaction run. (default 3) + [v1 storage only] How many times to retry a failed compaction within a single compaction run. (default 3) -compactor.compaction-split-by string - Experimental: The strategy to use when splitting blocks during compaction. Supported values are: fingerprint, stacktracePartition. (default "fingerprint") + [v1 storage only] Experimental: The strategy to use when splitting blocks during compaction. Supported values are: fingerprint, stacktracePartition. (default "fingerprint") -compactor.compactor-downsampler-enabled - If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. (default true) + [v1 storage only] If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. Note: This set the default for the teanant overrides, in order to be effective it also requires compactor.downsampler-enabled to be set to true. (default true) -compactor.compactor-tenant-shard-size int - Max number of compactors that can compact blocks for single tenant. 0 to disable the limit and use all compactors. + [v1 storage only] Max number of compactors that can compact blocks for single tenant. 0 to disable the limit and use all compactors. -compactor.data-dir string - Directory to temporarily store blocks during compaction. This directory is not required to be persisted between restarts. (default "./data-compactor") + [v1 storage only] Directory to temporarily store blocks during compaction. This directory is not required to be persisted between restarts. (default "./data-compactor") -compactor.deletion-delay duration - Time before a block marked for deletion is deleted from bucket. If not 0, blocks will be marked for deletion and compactor component will permanently delete blocks marked for deletion from the bucket. If 0, blocks will be deleted straight away. Note that deleting blocks immediately can cause query failures. (default 12h0m0s) + [v1 storage only] Time before a block marked for deletion is deleted from bucket. If not 0, blocks will be marked for deletion and compactor component will permanently delete blocks marked for deletion from the bucket. If 0, blocks will be deleted straight away. Note that deleting blocks immediately can cause query failures. (default 12h0m0s) -compactor.disabled-tenants comma-separated-list-of-strings - Comma separated list of tenants that cannot be compacted by this compactor. If specified, and compactor would normally pick given tenant for compaction (via -compactor.enabled-tenants or sharding), it will be ignored instead. + [v1 storage only] Comma separated list of tenants that cannot be compacted by this compactor. If specified, and compactor would normally pick given tenant for compaction (via -compactor.enabled-tenants or sharding), it will be ignored instead. -compactor.downsampler-enabled - If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. + [v1 storage only] If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. -compactor.enabled-tenants comma-separated-list-of-strings - Comma separated list of tenants that can be compacted. If specified, only these tenants will be compacted by compactor, otherwise all tenants can be compacted. Subject to sharding. + [v1 storage only] Comma separated list of tenants that can be compacted. If specified, only these tenants will be compacted by compactor, otherwise all tenants can be compacted. Subject to sharding. -compactor.first-level-compaction-wait-period duration - How long the compactor waits before compacting first-level blocks that are uploaded by the ingesters. This configuration option allows for the reduction of cases where the compactor begins to compact blocks before all ingesters have uploaded their blocks to the storage. (default 25m0s) + [v1 storage only] How long the compactor waits before compacting first-level blocks that are uploaded by the ingesters. This configuration option allows for the reduction of cases where the compactor begins to compact blocks before all ingesters have uploaded their blocks to the storage. (default 25m0s) -compactor.max-compaction-time duration - Max time for starting compactions for a single tenant. After this time no new compactions for the tenant are started before next compaction cycle. This can help in multi-tenant environments to avoid single tenant using all compaction time, but also in single-tenant environments to force new discovery of blocks more often. 0 = disabled. (default 1h0m0s) + [v1 storage only] Max time for starting compactions for a single tenant. After this time no new compactions for the tenant are started before next compaction cycle. This can help in multi-tenant environments to avoid single tenant using all compaction time, but also in single-tenant environments to force new discovery of blocks more often. 0 = disabled. (default 1h0m0s) -compactor.max-opening-blocks-concurrency int - Number of goroutines opening blocks before compaction. (default 16) + [v1 storage only] Number of goroutines opening blocks before compaction. (default 16) -compactor.meta-sync-concurrency int - Number of Go routines to use when syncing block meta files from the long term storage. (default 20) + [v1 storage only] Number of Go routines to use when syncing block meta files from the long term storage. (default 20) -compactor.no-blocks-file-cleanup-enabled - [experimental] If enabled, will delete the bucket-index, markers and debug files in the tenant bucket when there are no blocks left in the index. + [experimental] [v1 storage only] If enabled, will delete the bucket-index, markers and debug files in the tenant bucket when there are no blocks left in the index. -compactor.partial-block-deletion-delay duration - If a partial block (unfinished block without meta.json file) hasn't been modified for this time, it will be marked for deletion. The minimum accepted value is 4h0m0s: a lower value will be ignored and the feature disabled. 0 to disable. (default 1d) + [v1 storage only] If a partial block (unfinished block without meta.json file) hasn't been modified for this time, it will be marked for deletion. The minimum accepted value is 4h0m0s: a lower value will be ignored and the feature disabled. 0 to disable. (default 1d) -compactor.ring.consul.acl-token string - ACL Token used to interact with Consul. + [v1 storage only] ACL Token used to interact with Consul. -compactor.ring.consul.cas-retry-delay duration - Maximum duration to wait before retrying a Compare And Swap (CAS) operation. (default 1s) + [v1 storage only] Maximum duration to wait before retrying a Compare And Swap (CAS) operation. (default 1s) -compactor.ring.consul.client-timeout duration - HTTP timeout when talking to Consul (default 20s) + [v1 storage only] HTTP timeout when talking to Consul (default 20s) -compactor.ring.consul.consistent-reads - Enable consistent reads to Consul. + [v1 storage only] Enable consistent reads to Consul. -compactor.ring.consul.hostname string - Hostname and port of Consul. (default "localhost:8500") + [v1 storage only] Hostname and port of Consul. (default "localhost:8500") -compactor.ring.consul.watch-burst-size int - Burst size used in rate limit. Values less than 1 are treated as 1. (default 1) + [v1 storage only] Burst size used in rate limit. Values less than 1 are treated as 1. (default 1) -compactor.ring.consul.watch-rate-limit float - Rate limit when watching key or prefix in Consul, in requests per second. 0 disables the rate limit. (default 1) + [v1 storage only] Rate limit when watching key or prefix in Consul, in requests per second. 0 disables the rate limit. (default 1) -compactor.ring.etcd.dial-timeout duration - The dial timeout for the etcd connection. (default 10s) + [v1 storage only] The dial timeout for the etcd connection. (default 10s) -compactor.ring.etcd.endpoints string - The etcd endpoints to connect to. + [v1 storage only] The etcd endpoints to connect to. -compactor.ring.etcd.max-retries int - The maximum number of retries to do for failed ops. (default 10) + [v1 storage only] The maximum number of retries to do for failed ops. (default 10) -compactor.ring.etcd.password string - Etcd password. + [v1 storage only] Etcd password. -compactor.ring.etcd.tls-ca-path string - Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used. + [v1 storage only] Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used. -compactor.ring.etcd.tls-cert-path string - Path to the client certificate, which will be used for authenticating with the server. Also requires the key path to be configured. + [v1 storage only] Path to the client certificate, which will be used for authenticating with the server. Also requires the key path to be configured. -compactor.ring.etcd.tls-cipher-suites string - Override the default cipher suite list (separated by commas). + [v1 storage only] Override the default cipher suite list (separated by commas). -compactor.ring.etcd.tls-enabled - Enable TLS. + [v1 storage only] Enable TLS. -compactor.ring.etcd.tls-insecure-skip-verify - Skip validating server certificate. + [v1 storage only] Skip validating server certificate. -compactor.ring.etcd.tls-key-path string - Path to the key for the client certificate. Also requires the client certificate to be configured. + [v1 storage only] Path to the key for the client certificate. Also requires the client certificate to be configured. -compactor.ring.etcd.tls-min-version string - Override the default minimum TLS version. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 + [v1 storage only] Override the default minimum TLS version. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 -compactor.ring.etcd.tls-server-name string - Override the expected name on the server certificate. + [v1 storage only] Override the expected name on the server certificate. -compactor.ring.etcd.username string - Etcd username. + [v1 storage only] Etcd username. -compactor.ring.heartbeat-period duration - Period at which to heartbeat to the ring. 0 = disabled. (default 15s) + [v1 storage only] Period at which to heartbeat to the ring. 0 = disabled. (default 15s) -compactor.ring.heartbeat-timeout duration - The heartbeat timeout after which compactors are considered unhealthy within the ring. 0 = never (timeout disabled). (default 1m0s) + [v1 storage only] The heartbeat timeout after which compactors are considered unhealthy within the ring. 0 = never (timeout disabled). (default 1m0s) -compactor.ring.instance-addr string - IP address to advertise in the ring. Default is auto-detected. + [v1 storage only] IP address to advertise in the ring. Default is auto-detected. -compactor.ring.instance-enable-ipv6 - Enable using a IPv6 instance address. (default false) + [v1 storage only] Enable using a IPv6 instance address. (default false) -compactor.ring.instance-id string - Instance ID to register in the ring. (default "") + [v1 storage only] Instance ID to register in the ring. (default "") -compactor.ring.instance-interface-names string - List of network interface names to look up when finding the instance IP address. (default []) + [v1 storage only] List of network interface names to look up when finding the instance IP address. (default []) -compactor.ring.instance-port int - Port to advertise in the ring (defaults to -server.http-listen-port). + [v1 storage only] Port to advertise in the ring (defaults to -server.http-listen-port). -compactor.ring.multi.mirror-enabled - Mirror writes to secondary store. + [v1 storage only] Mirror writes to the secondary store. -compactor.ring.multi.mirror-timeout duration - Timeout for storing value to secondary store. (default 2s) + [v1 storage only] Timeout for storing a value to the secondary store. (default 2s) -compactor.ring.multi.primary string - Primary backend storage used by multi-client. + [v1 storage only] Primary backend storage used by multi-client. -compactor.ring.multi.secondary string - Secondary backend storage used by multi-client. + [v1 storage only] Secondary backend storage used by multi-client. -compactor.ring.prefix string - The prefix for the keys in the store. Should end with a /. (default "collectors/") + [v1 storage only] The prefix for the keys in the store. Should end with a /. (default "collectors/") -compactor.ring.store string - Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") + [v1 storage only] Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") -compactor.ring.wait-active-instance-timeout duration - Timeout for waiting on compactor to become ACTIVE in the ring. (default 10m0s) + [v1 storage only] Timeout for waiting on compactor to become ACTIVE in the ring. (default 10m0s) -compactor.ring.wait-stability-max-duration duration - Maximum time to wait for ring stability at startup. If the compactor ring keeps changing after this period of time, the compactor will start anyway. (default 5m0s) + [v1 storage only] Maximum time to wait for ring stability at startup. If the compactor ring keeps changing after this period of time, the compactor will start anyway. (default 5m0s) -compactor.ring.wait-stability-min-duration duration - Minimum time to wait for ring stability at startup. 0 to disable. + [v1 storage only] Minimum time to wait for ring stability at startup. 0 to disable. + -compactor.shutdown-timeout duration + [v1 storage only] Maximum time to wait for in-flight cleanup and ring operations to finish during shutdown. If the timeout is reached, the compactor will forcefully stop. 0 = no timeout (wait indefinitely). -compactor.split-and-merge-shards int - The number of shards to use when splitting blocks. 0 to disable splitting. + [v1 storage only] The number of shards to use when splitting blocks. 0 to disable splitting. -compactor.split-and-merge-stage-size int - Number of stages split shards will be written to. Number of output split shards is controlled by -compactor.split-and-merge-shards. + [v1 storage only] Number of stages split shards will be written to. Number of output split shards is controlled by -compactor.split-and-merge-shards. -compactor.split-groups int - Number of groups that blocks for splitting should be grouped into. Each group of blocks is then split separately. Number of output split shards is controlled by -compactor.split-and-merge-shards. (default 1) + [v1 storage only] Number of groups that blocks for splitting should be grouped into. Each group of blocks is then split separately. Number of output split shards is controlled by -compactor.split-and-merge-shards. (default 1) -config.expand-env Expands ${var} in config according to the values of the environment variables. -config.file string @@ -159,6 +223,14 @@ Usage of ./pyroscope: Burst size used in rate limit. Values less than 1 are treated as 1. (default 1) -consul.watch-rate-limit float Rate limit when watching key or prefix in Consul, in requests per second. 0 disables the rate limit. (default 1) + -debug-info.enabled + Enable debug info. (default true) + -debug-info.max-upload-size int + Maximum size of a single debug info upload in bytes. (default 1073741824) + -debug-info.upload-stale-period duration + Period after which a pending upload is considered stale and can be retried. (default 5m0s) + -debug-info.upload-timeout duration + Timeout for a single debug info upload request. Overrides server HTTP write timeout for this handler. (default 2m0s) -distributor.aggregation-period duration Duration of the distributor aggregation period. Requires aggregation window to be specified. 0 to disable. -distributor.aggregation-window duration @@ -171,12 +243,22 @@ Usage of ./pyroscope: Run a health check on each ingester client during periodic cleanup. (default true) -distributor.health-check-timeout duration Timeout for ingester client healthcheck RPCs. (default 5s) + -distributor.ingestion-artificial-delay duration + [experimental] Target ingestion delay to apply to all tenants. If set to a non-zero value, the distributor will artificially delay ingestion time-frame by the specified duration by computing the difference between actual ingestion and the target. There is no delay on actual ingestion of samples, it is only the response back to the client. + -distributor.ingestion-body-limit-mb float + Per-tenant ingestion body size limit in MB, before decompressing. 0 to disable. (default 256) -distributor.ingestion-burst-size-mb float Per-tenant allowed ingestion burst size (in sample size). Units in MB. The burst size refers to the per-distributor local rate limiter, and should be set at least to the maximum profile size expected in a single push request. (default 2) -distributor.ingestion-rate-limit-mb float Per-tenant ingestion rate limit in sample size per second. Units in MB. (default 4) + -distributor.ingestion-relabeling-default-rules-position value + Position of the default ingestion relabeling rules in relation to relabel rules from overrides. Valid values are 'first', 'last' or 'disabled'. (default "first") + -distributor.ingestion-relabeling-rules value + List of ingestion relabel configurations. The relabeling rules work the same way, as those of [Prometheus](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config). All rules are applied in the order they are specified. Note: In most situations, it is more effective to use relabeling directly in Grafana Alloy. -distributor.ingestion-tenant-shard-size int The tenant's shard size used by shuffle-sharding. Must be set both on ingesters and distributors. 0 disables shuffle sharding. + -distributor.push.max-concurrency int + Maximum number of series within a single batched push that are processed concurrently. 0 = unbounded (legacy behavior); 1 = serialize pushes (kill switch). (default 256) -distributor.push.timeout duration Timeout when pushing data to ingester. (default 5s) -distributor.replication-factor int @@ -236,9 +318,9 @@ Usage of ./pyroscope: -distributor.ring.instance-port int Port to advertise in the ring (defaults to -server.http-listen-port). -distributor.ring.multi.mirror-enabled - Mirror writes to secondary store. + Mirror writes to the secondary store. -distributor.ring.multi.mirror-timeout duration - Timeout for storing value to secondary store. (default 2s) + Timeout for storing a value to the secondary store. (default 2s) -distributor.ring.multi.primary string Primary backend storage used by multi-client. -distributor.ring.multi.secondary string @@ -247,8 +329,22 @@ Usage of ./pyroscope: The prefix for the keys in the store. Should end with a /. (default "collectors/") -distributor.ring.store string Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") + -distributor.sample-type-relabeling-rules value + List of sample type relabel configurations. Rules are applied to sample types with __type__ and __unit__ labels, along with all series labels. + -distributor.sampling.keep-stripped-profiles + When a profile is sampled out, retain its totals and labels with stacktraces stripped (marked __sampled__) instead of dropping it. -distributor.zone-awareness-enabled True to enable the zone-awareness and replicate ingested samples across different availability zones. + -embedded-grafana.data-path string + The directory where the Grafana data will be stored. (default "./data/__embedded_grafana/") + -embedded-grafana.listen-port int + The port on which the Grafana will listen. (default 4041) + -embedded-grafana.pyroscope-url string + The URL of the Pyroscope instance to use for the Grafana datasources. (default "http://localhost:4040") + -enable-query-backend + This parameter specifies whether the new query backend is enabled. (default true) + -enable-query-backend-from value + This parameter specifies the point in time from which data is queried from the new query backend. The value can be an RFC3339 timestamp (2020-10-20T00:00:00Z) or "auto" to automatically determine the split point from the tenant's oldest profile time in the metastore. (default auto) -etcd.dial-timeout duration The dial timeout for the etcd connection. (default 10s) -etcd.endpoints string @@ -282,47 +378,53 @@ Usage of ./pyroscope: -help-all Print help, also including advanced and experimental parameters. -ingester.availability-zone string - The availability zone where this instance is running. + [v1 storage only] The availability zone where this instance is running. -ingester.enable-inet6 - Enable IPv6 support. Required to make use of IP addresses from IPv6 interfaces. + [v1 storage only] Enable IPv6 support. Required to make use of IP addresses from IPv6 interfaces. -ingester.final-sleep duration - Duration to sleep for before exiting, to ensure metrics are scraped. + [v1 storage only] Duration to sleep for before exiting, to ensure metrics are scraped. -ingester.heartbeat-period duration - Period at which to heartbeat to consul. 0 = disabled. (default 5s) + [v1 storage only] Period at which to heartbeat to consul. (default 5s) -ingester.heartbeat-timeout duration - Heartbeat timeout after which instance is assumed to be unhealthy. 0 = disabled. (default 1m0s) + [v1 storage only] Heartbeat timeout after which instance is assumed to be unhealthy. (default 1m0s) -ingester.join-after duration - Period to wait for a claim from another member; will join automatically after this. + [v1 storage only] Period to wait for a claim from another member; will join automatically after this. -ingester.lifecycler.ID string - ID to register in the ring. (default "") + [v1 storage only] ID to register in the ring. (default "") -ingester.lifecycler.addr string - IP address to advertise in the ring. + [v1 storage only] IP address to advertise in the ring. -ingester.lifecycler.interface string - Name of network interface to read address from. (default []) + [v1 storage only] Name of network interface to read address from. (default []) -ingester.lifecycler.port int - port to advertise in consul (defaults to server.grpc-listen-port). + [v1 storage only] port to advertise in consul (defaults to server.grpc-listen-port). -ingester.max-global-series-per-tenant int - Maximum number of active series of profiles per tenant, across the cluster. 0 to disable. When the global limit is enabled, each ingester is configured with a dynamic local limit based on the replication factor and the current number of healthy ingesters, and is kept updated whenever the number of ingesters change. (default 5000) + [v1 storage only] Maximum number of active series of profiles per tenant, across the cluster. 0 to disable. When the global limit is enabled, each ingester is configured with a dynamic local limit based on the replication factor and the current number of healthy ingesters, and is kept updated whenever the number of ingesters change. (default 5000) -ingester.max-local-series-per-tenant int - Maximum number of active series of profiles per tenant, per ingester. 0 to disable. + [v1 storage only] Maximum number of active series of profiles per tenant, per ingester. 0 to disable. -ingester.min-ready-duration duration - Minimum duration to wait after the internal readiness checks have passed but before succeeding the readiness endpoint. This is used to slowdown deployment controllers (eg. Kubernetes) after an instance is ready and before they proceed with a rolling update, to give the rest of the cluster instances enough time to receive ring updates. (default 15s) + [v1 storage only] Minimum duration to wait after the internal readiness checks have passed but before succeeding the readiness endpoint. This is used to slowdown deployment controllers (eg. Kubernetes) after an instance is ready and before they proceed with a rolling update, to give the rest of the cluster instances enough time to receive ring updates. (default 15s) -ingester.num-tokens int - Number of tokens for each ingester. (default 128) + [v1 storage only] Number of tokens for each ingester. (default 128) -ingester.observe-period duration - Observe tokens after generating to resolve collisions. Useful when using gossiping ring. + [v1 storage only] Observe tokens after generating to resolve collisions. Useful when using gossiping ring. -ingester.readiness-check-ring-health - When enabled the readiness probe succeeds only after all instances are ACTIVE and healthy in the ring, otherwise only the instance itself is checked. This option should be disabled if in your cluster multiple instances can be rolled out simultaneously, otherwise rolling updates may be slowed down. (default true) + [v1 storage only] When enabled the readiness probe succeeds only after all instances are ACTIVE and healthy in the ring, otherwise only the instance itself is checked. This option should be disabled if in your cluster multiple instances can be rolled out simultaneously, otherwise rolling updates may be slowed down. (default true) -ingester.tokens-file-path string - File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup. + [v1 storage only] File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup. -ingester.unregister-on-shutdown - Unregister from the ring upon clean shutdown. It can be useful to disable for rolling restarts with consistent naming in conjunction with -distributor.extend-writes=false. (default true) + [v1 storage only] Unregister from the ring upon clean shutdown. It can be useful to disable for rolling restarts with consistent naming in conjunction with -distributor.extend-writes=false. (default true) -log.format string Output log messages in the given format. Valid formats: [logfmt, json] (default "logfmt") -log.level value Only log messages with the given severity or above. Valid levels: [debug, info, warn, error] (default info) + -memberlist.abort-if-fast-join-fails + Abort if this node fails the fast memberlist cluster joining procedure at startup. When enabled, it's guaranteed that other services, depending on memberlist, have an updated view over the cluster state when they're started. + -memberlist.abort-if-fast-join-fails-min-nodes int + Minimum number of seed nodes that must be successfully joined during fast-join for it to succeed. Only applies when -memberlist.abort-if-fast-join-fails is enabled. (default 1) -memberlist.abort-if-join-fails - If this node fails to join memberlist cluster, abort. + Abort if this node fails to join memberlist cluster at startup. When enabled, it's not guaranteed that other services are started only after the cluster state has been successfully updated; use 'abort-if-fast-join-fails' instead. + -memberlist.acquire-writer-timeout duration + Timeout for acquiring one of the concurrent write slots. After this time, the message will be dropped. (default 250ms) -memberlist.advertise-addr string Gossip address to advertise to other members in the cluster. Used for NAT traversal. -memberlist.advertise-port int @@ -331,10 +433,14 @@ Usage of ./pyroscope: IP address to listen on for gossip messages. Multiple addresses may be specified. Defaults to 0.0.0.0 -memberlist.bind-port int Port to listen on for gossip messages. (default 7946) + -memberlist.broadcast-timeout-for-local-updates-on-shutdown duration + Timeout for broadcasting all remaining locally-generated updates to other nodes when shutting down. Only used if there are nodes left in the memberlist cluster, and only applies to locally-generated updates, not to broadcast messages that are result of incoming gossip updates. 0 = no timeout, wait until all locally-generated updates are sent. (default 10s) -memberlist.cluster-label string The cluster label is an optional string to include in outbound packets and gossip streams. Other members in the memberlist cluster will discard any message whose label doesn't match the configured one, unless the 'cluster-label-verification-disabled' configuration option is set to true. -memberlist.cluster-label-verification-disabled When true, memberlist doesn't verify that inbound packets and gossip streams have the cluster label matching the configured one. This verification should be disabled while rolling out the change to the configured cluster label in a live memberlist cluster. + -memberlist.compression-algorithm string + Compression algorithm used for outgoing messages when -memberlist.compression-enabled is true. Supported values: lzw, snappy. Ignored when -memberlist.compression-enabled is false. (default "lzw") -memberlist.compression-enabled Enable message compression. This can be used to reduce bandwidth usage at the cost of slightly more CPU utilization. (default true) -memberlist.dead-node-reclaim-time duration @@ -345,12 +451,14 @@ Usage of ./pyroscope: How many nodes to gossip to. (default 3) -memberlist.gossip-to-dead-nodes-time duration How long to keep gossiping to dead nodes, to give them chance to refute their death. (default 30s) - -memberlist.join string - Other cluster members to join. Can be specified multiple times. It can be an IP, hostname or an entry specified in the DNS Service Discovery format. + -memberlist.join value + Other cluster members to join. Can be specified multiple times or as a comma-separated list. It can be an IP, hostname or an entry specified in the DNS Service Discovery format. -memberlist.leave-timeout duration Timeout for leaving memberlist cluster. (default 20s) -memberlist.left-ingesters-timeout duration How long to keep LEFT ingesters in the ring. (default 5m0s) + -memberlist.max-concurrent-writes int + Maximum number of concurrent writes to other nodes. (default 3) -memberlist.max-join-backoff duration Max backoff duration to join other cluster members. (default 1m0s) -memberlist.max-join-retries int @@ -361,20 +469,38 @@ Usage of ./pyroscope: Min backoff duration to join other cluster members. (default 1s) -memberlist.nodename string Name of the node in memberlist cluster. Defaults to hostname. + -memberlist.notify-interval duration + How frequently to notify watchers when a key changes. Can reduce CPU activity in large memberlist deployments. 0 to notify without delay. + -memberlist.obsolete-entries-timeout duration + [experimental] How long to keep obsolete entries in the KV store. (default 30s) -memberlist.packet-dial-timeout duration Timeout used when connecting to other nodes to send packet. (default 2s) -memberlist.packet-write-timeout duration Timeout for writing 'packet' data. (default 5s) + -memberlist.processed-messages-queue-size int + Size of the per-key internal queue for processing messages received from other nodes. Increasing this value may help to avoid dropping per-key updates when the node is processing many updates for the same key. (default 1024) + -memberlist.propagation-delay-tracker.beacon-interval duration + [experimental] How often to publish beacons for propagation tracking. (default 1m0s) + -memberlist.propagation-delay-tracker.beacon-lifetime duration + [experimental] How long a beacon lives before being garbage collected. (default 10m0s) + -memberlist.propagation-delay-tracker.enabled + [experimental] Enable the propagation delay tracker to measure gossip propagation delay. + -memberlist.propagation-delay-tracker.log-beacons-latency-longer-than duration + [experimental] Log warning when beacon propagation delay exceeds this threshold. 0 disables logging. -memberlist.pullpush-interval duration How often to use pull/push sync. (default 30s) -memberlist.randomize-node-name Add random suffix to the node name. (default true) + -memberlist.received-messages-queue-size int + Size of the internal queue for messages received from other nodes. Increasing this value may help to avoid dropping messages when the node is processing a large number of messages from other nodes. (default 1024) -memberlist.rejoin-interval duration If not 0, how often to rejoin the cluster. Occasional rejoin can help to fix the cluster split issue, and is harmless otherwise. For example when using only few components as a seed nodes (via -memberlist.join), then it's recommended to use rejoin. If -memberlist.join points to dynamic service that resolves to all gossiping nodes (eg. Kubernetes headless service), then rejoin is not needed. + -memberlist.rejoin-seed-nodes value + [experimental] Seed nodes to use for periodic rejoin. Takes precedence over -memberlist.join for rejoining. If not specified, -memberlist.join is used. Can be specified multiple times or as a comma-separated list. Supports IP, hostname, or DNS Service Discovery format. -memberlist.retransmit-factor int Multiplication factor used when sending out messages (factor * log(N+1)). (default 4) -memberlist.stream-timeout duration - The timeout for establishing a connection with a remote node, and for read/write operations. (default 10s) + The timeout for establishing a connection with a remote node, and for read/write operations. (default 2s) -memberlist.tls-ca-path string Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used. -memberlist.tls-cert-path string @@ -393,12 +519,138 @@ Usage of ./pyroscope: Override the expected name on the server certificate. -memberlist.transport-debug Log debug transport messages. Note: global log.level must be at debug level as well. + -memberlist.watch-prefix-buffer-size int + Size of the buffered channel for the WatchPrefix function. (default 128) + -memberlist.zone-aware-routing.enabled + [experimental] Enable zone-aware routing for memberlist gossip. + -memberlist.zone-aware-routing.instance-availability-zone string + [experimental] Availability zone where this node is running. + -memberlist.zone-aware-routing.role string + [experimental] Role of this node in the cluster. Valid values: member, bridge. (default "member") + -metastore.address string + (default "localhost:9095") + -metastore.compaction-job-lease-duration duration + (default 15s) + -metastore.compaction-max-failures uint + (default 3) + -metastore.compaction-max-job-queue-size uint + (default 10000) + -metastore.data-dir string + Directory to store the data. (default "./data/v2/metastore/data") + -metastore.grpc-client-config.backoff-max-period duration + Maximum delay when backing off. (default 10s) + -metastore.grpc-client-config.backoff-min-period duration + Minimum delay when backing off. (default 100ms) + -metastore.grpc-client-config.backoff-on-ratelimits + Enable backoff and retry when we hit rate limits. + -metastore.grpc-client-config.backoff-retries int + Number of times to backoff and retry before failing. (default 10) + -metastore.grpc-client-config.cluster-validation.label string + [experimental] Primary cluster validation label. + -metastore.grpc-client-config.connect-backoff-base-delay duration + Initial backoff delay after first connection failure. Only relevant if ConnectTimeout > 0. (default 1s) + -metastore.grpc-client-config.connect-backoff-max-delay duration + Maximum backoff delay when establishing a connection. Only relevant if ConnectTimeout > 0. (default 5s) + -metastore.grpc-client-config.connect-timeout duration + The maximum amount of time to establish a connection. A value of 0 means default gRPC client connect timeout and backoff. (default 5s) + -metastore.grpc-client-config.grpc-client-rate-limit float + Rate limit for gRPC client; 0 means disabled. + -metastore.grpc-client-config.grpc-client-rate-limit-burst int + Rate limit burst for gRPC client. + -metastore.grpc-client-config.grpc-compression string + Use compression when sending messages. Supported values are: 'gzip', 'snappy' and '' (disable compression) + -metastore.grpc-client-config.grpc-max-recv-msg-size int + gRPC client max receive message size (bytes). (default 104857600) + -metastore.grpc-client-config.grpc-max-send-msg-size int + gRPC client max send message size (bytes). (default 104857600) + -metastore.grpc-client-config.initial-connection-window-size value + [experimental] Initial connection window size. Values less than the default are not supported and are ignored. Setting this to a value other than the default disables the BDP estimator. (default 63KiB1023B) + -metastore.grpc-client-config.initial-stream-window-size value + [experimental] Initial stream window size. Values less than the default are not supported and are ignored. Setting this to a value other than the default disables the BDP estimator. (default 63KiB1023B) + -metastore.grpc-client-config.tls-ca-path string + Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used. + -metastore.grpc-client-config.tls-cert-path string + Path to the client certificate, which will be used for authenticating with the server. Also requires the key path to be configured. + -metastore.grpc-client-config.tls-cipher-suites string + Override the default cipher suite list (separated by commas). + -metastore.grpc-client-config.tls-enabled + Enable TLS in the gRPC client. This flag needs to be enabled when any other TLS flag is set. If set to false, insecure connection to gRPC server will be used. + -metastore.grpc-client-config.tls-insecure-skip-verify + Skip validating server certificate. + -metastore.grpc-client-config.tls-key-path string + Path to the key for the client certificate. Also requires the client certificate to be configured. + -metastore.grpc-client-config.tls-min-version string + Override the default minimum TLS version. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 + -metastore.grpc-client-config.tls-server-name string + Override the expected name on the server certificate. + -metastore.index.block-read-cache-size int + Maximum number of read blocks to keep in memory (default 100000) + -metastore.index.block-write-cache-size int + Maximum number of written blocks to keep in memory (default 10000) + -metastore.index.cleanup-grace-period duration + After a partition is eligible for deletion, it will be kept for this period before actually being evaluated. The period should cover the time difference between the block creation time and the data timestamps. Blocks are only deleted if all data in the block has passed the retention period, and the grace period delays the moment when the partition is evaluated for deletion. (default 6h0m0s) + -metastore.index.cleanup-interval duration + Interval for index cleanup check. 0 to disable. (default 15m0s) + -metastore.index.cleanup-max-partitions int + Maximum number of partitions to cleanup at once. A partition is qualified by partition key, tenant, and shard. (default 32) + -metastore.index.dlq-recovery-check-interval duration + Dead Letter Queue check interval. 0 to disable. (default 15s) + -metastore.index.shard-cache-size int + Maximum number of shards to keep in memory (default 2000) + -metastore.min-ready-duration duration + Minimum duration to wait after the internal readiness checks have passed but before succeeding the readiness endpoint. This is used to slowdown deployment controllers (eg. Kubernetes) after an instance is ready and before they proceed with a rolling update, to give the rest of the cluster instances enough time to receive some (DNS?) updates. (default 15s) + -metastore.raft.advertise-address string + (default "localhost:9099") + -metastore.raft.apply-timeout duration + (default 5s) + -metastore.raft.auto-join + If enabled, new nodes (without a state) will try to join an existing cluster on startup. + -metastore.raft.bind-address string + (default "localhost:9099") + -metastore.raft.bootstrap-expect-peers int + Expected number of peers including the local node. (default 1) + -metastore.raft.bootstrap-peers string + + -metastore.raft.dir string + Directory to store WAL and raft state. It must be a persistent directory, not a tmpfs or similar. (default "./data/v2/metastore/raft") + -metastore.raft.log-index-check-interval duration + (default 14ms) + -metastore.raft.log-store-timeout duration + (default 10s) + -metastore.raft.read-index-max-distance uint + (default 10240) + -metastore.raft.server-id string + (default "localhost:9099") + -metastore.raft.snapshot-interval duration + (default 3m0s) + -metastore.raft.snapshot-threshold uint + (default 8192) + -metastore.raft.snapshots-dir string + Directory to store FSM snapshots. Raft creates 'snapshots' subdirectory in this directory. It must be a persistent directory, not a tmpfs or similar. (default "./data/v2/metastore/raft") + -metastore.raft.snapshots-import-dir string + Directory to import snapshots from; the directory must contain 'snapshots' subdirectory. If not set, no import will be done. + -metastore.raft.snapshots-retain uint + (default 3) + -metastore.raft.trailing-logs uint + (default 18432) + -metastore.raft.transport-conn-pool-size uint + (default 10) + -metastore.raft.transport-timeout duration + (default 10s) + -metastore.raft.wal-cache-entries uint + (default 512) + -metastore.snapshot-compact-on-restore + Compact the database on restore. + -metastore.snapshot-compression string + Compression algorithm to use for snapshots. Supported compressions: zstd. (default "zstd") + -metastore.snapshot-rate-limit int + Rate limit for snapshot writer in MB/s. (default 15) -modules List available modules that can be used as target and exit. -multi.mirror-enabled - Mirror writes to secondary store. + Mirror writes to the secondary store. -multi.mirror-timeout duration - Timeout for storing value to secondary store. (default 2s) + Timeout for storing a value to the secondary store. (default 2s) -multi.primary string Primary backend storage used by multi-client. -multi.secondary string @@ -458,9 +710,9 @@ Usage of ./pyroscope: -overrides-exporter.ring.instance-port int Port to advertise in the ring (defaults to -server.http-listen-port). -overrides-exporter.ring.multi.mirror-enabled - Mirror writes to secondary store. + Mirror writes to the secondary store. -overrides-exporter.ring.multi.mirror-timeout duration - Timeout for storing value to secondary store. (default 2s) + Timeout for storing a value to the secondary store. (default 2s) -overrides-exporter.ring.multi.primary string Primary backend storage used by multi-client. -overrides-exporter.ring.multi.secondary string @@ -474,19 +726,21 @@ Usage of ./pyroscope: -overrides-exporter.ring.wait-stability-min-duration duration Minimum time to wait for ring stability at startup, if set to positive value. Set to 0 to disable. -pyroscopedb.data-path string - Directory used for local storage. (default "./data") + [v1 storage only] Directory used for local storage. (default "./data") -pyroscopedb.max-block-duration duration - Upper limit to the duration of a Pyroscope block. (default 1h0m0s) + [v1 storage only] Upper limit to the duration of a Pyroscope block. (default 1h0m0s) -pyroscopedb.retention-policy-disable - Disable retention policy enforcement + [v1 storage only] Disable retention policy enforcement -pyroscopedb.retention-policy-enforcement-interval duration - How often to enforce disk retention (default 5m0s) + [v1 storage only] How often to enforce disk retention (default 5m0s) -pyroscopedb.retention-policy-min-disk-available-percentage float - Which percentage of free disk space to keep (default 0.05) + [v1 storage only] Which percentage of free disk space to keep (default 0.05) -pyroscopedb.retention-policy-min-free-disk-gb uint - How much available disk space to keep in GiB (default 10) + [v1 storage only] How much available disk space to keep in GiB (default 10) -pyroscopedb.row-group-target-size uint - How big should a single row group be uncompressed (default 1342177280) + [v1 storage only] How big should a single row group be uncompressed (default 1342177280) + -pyroscopedb.symbols-partition-label string + [v1 storage only] Specifies the dimension by which symbols are partitioned. By default, the partitioning is determined automatically. -querier.client-cleanup-period duration How frequently to clean up clients for ingesters that have gone away. (default 15s) -querier.frontend-client.backoff-max-period duration @@ -497,6 +751,8 @@ Usage of ./pyroscope: Enable backoff and retry when we hit rate limits. -querier.frontend-client.backoff-retries int Number of times to backoff and retry before failing. (default 10) + -querier.frontend-client.cluster-validation.label string + [experimental] Primary cluster validation label. -querier.frontend-client.connect-backoff-base-delay duration Initial backoff delay after first connection failure. Only relevant if ConnectTimeout > 0. (default 1s) -querier.frontend-client.connect-backoff-max-delay duration @@ -544,7 +800,9 @@ Usage of ./pyroscope: -querier.max-flamegraph-nodes-default int Maximum number of flame graph nodes by default. 0 to disable. (default 8192) -querier.max-flamegraph-nodes-max int - Maximum number of flame graph nodes allowed. 0 to disable. + Maximum number of flame graph nodes allowed. 0 to disable. (default 1048576) + -querier.max-flamegraph-nodes-on-select-merge-profile + Enforce the max nodes limits and defaults on SelectMergeProfile API. Historically this limit was not enforced to enable to gather full pprof profiles without truncation. -querier.max-query-length duration The limit to length of queries. 0 to disable. (default 1d) -querier.max-query-lookback duration @@ -557,8 +815,66 @@ Usage of ./pyroscope: Whether the series portion of query analysis is enabled. If disabled, no series data (e.g., series count) will be calculated by the /AnalyzeQuery endpoint. -querier.query-store-after duration The time after which a metric should be queried from storage and not just ingesters. 0 means all queries are sent to store. If this option is enabled, the time range of the query sent to the store-gateway will be manipulated to ensure the query end is not more recent than 'now - query-store-after'. (default 4h0m0s) + -querier.query-tree-enabled + [experimental] Use the tree-based query path for SelectMergeProfile. Experimental. + -querier.sanitize-on-merge + Whether profiles should be sanitized when merging. (default true) -querier.split-queries-by-interval duration Split queries by a time interval and execute in parallel. The value 0 disables splitting by time + -query-backend.address string + (default "localhost:9095") + -query-backend.client-timeout duration + Timeout for query-backend client requests. (default 30s) + -query-backend.grpc-client-config.backoff-max-period duration + Maximum delay when backing off. (default 10s) + -query-backend.grpc-client-config.backoff-min-period duration + Minimum delay when backing off. (default 100ms) + -query-backend.grpc-client-config.backoff-on-ratelimits + Enable backoff and retry when we hit rate limits. + -query-backend.grpc-client-config.backoff-retries int + Number of times to backoff and retry before failing. (default 10) + -query-backend.grpc-client-config.cluster-validation.label string + [experimental] Primary cluster validation label. + -query-backend.grpc-client-config.connect-backoff-base-delay duration + Initial backoff delay after first connection failure. Only relevant if ConnectTimeout > 0. (default 1s) + -query-backend.grpc-client-config.connect-backoff-max-delay duration + Maximum backoff delay when establishing a connection. Only relevant if ConnectTimeout > 0. (default 5s) + -query-backend.grpc-client-config.connect-timeout duration + The maximum amount of time to establish a connection. A value of 0 means default gRPC client connect timeout and backoff. (default 5s) + -query-backend.grpc-client-config.grpc-client-rate-limit float + Rate limit for gRPC client; 0 means disabled. + -query-backend.grpc-client-config.grpc-client-rate-limit-burst int + Rate limit burst for gRPC client. + -query-backend.grpc-client-config.grpc-compression string + Use compression when sending messages. Supported values are: 'gzip', 'snappy' and '' (disable compression) + -query-backend.grpc-client-config.grpc-max-recv-msg-size int + gRPC client max receive message size (bytes). (default 104857600) + -query-backend.grpc-client-config.grpc-max-send-msg-size int + gRPC client max send message size (bytes). (default 104857600) + -query-backend.grpc-client-config.initial-connection-window-size value + [experimental] Initial connection window size. Values less than the default are not supported and are ignored. Setting this to a value other than the default disables the BDP estimator. (default 63KiB1023B) + -query-backend.grpc-client-config.initial-stream-window-size value + [experimental] Initial stream window size. Values less than the default are not supported and are ignored. Setting this to a value other than the default disables the BDP estimator. (default 63KiB1023B) + -query-backend.grpc-client-config.tls-ca-path string + Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used. + -query-backend.grpc-client-config.tls-cert-path string + Path to the client certificate, which will be used for authenticating with the server. Also requires the key path to be configured. + -query-backend.grpc-client-config.tls-cipher-suites string + Override the default cipher suite list (separated by commas). + -query-backend.grpc-client-config.tls-enabled + Enable TLS in the gRPC client. This flag needs to be enabled when any other TLS flag is set. If set to false, insecure connection to gRPC server will be used. + -query-backend.grpc-client-config.tls-insecure-skip-verify + Skip validating server certificate. + -query-backend.grpc-client-config.tls-key-path string + Path to the key for the client certificate. Also requires the client certificate to be configured. + -query-backend.grpc-client-config.tls-min-version string + Override the default minimum TLS version. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 + -query-backend.grpc-client-config.tls-server-name string + Override the expected name on the server certificate. + -query-backend.include-stripped-profiles + Include profiles that were sampled out and stored with stacktraces stripped (marked __sampled__) in query results. + -query-frontend.async-queries-enabled + [experimental] Enable the experimental asynchronous query path on SelectMergeStacktraces (default false) -query-frontend.grpc-client-config.backoff-max-period duration Maximum delay when backing off. (default 10s) -query-frontend.grpc-client-config.backoff-min-period duration @@ -567,6 +883,8 @@ Usage of ./pyroscope: Enable backoff and retry when we hit rate limits. -query-frontend.grpc-client-config.backoff-retries int Number of times to backoff and retry before failing. (default 10) + -query-frontend.grpc-client-config.cluster-validation.label string + [experimental] Primary cluster validation label. -query-frontend.grpc-client-config.connect-backoff-base-delay duration Initial backoff delay after first connection failure. Only relevant if ConnectTimeout > 0. (default 1s) -query-frontend.grpc-client-config.connect-backoff-max-delay duration @@ -605,8 +923,14 @@ Usage of ./pyroscope: Override the expected name on the server certificate. -query-frontend.instance-addr string IP address to advertise to the querier (via scheduler) (default is auto-detected from network interfaces). + -query-frontend.instance-enable-ipv6 + Enable using a IPv6 instance address. (default false) -query-frontend.instance-interface-names string List of network interface names to look up when finding the instance IP address. This address is sent to query-scheduler and querier, which uses it to send the query response back to query-frontend. (default []) + -query-frontend.instance-port int + Port to advertise to query-scheduler and querier (defaults to -server.http-listen-port). + -query-frontend.max-async-query-concurrency int + Maximum number of concurrent async queries per tenant. 0 to disable async queries. (default 5) -query-frontend.scheduler-worker-concurrency int Number of concurrent workers forwarding queries to single query-scheduler. (default 5) -query-scheduler.grpc-client-config.backoff-max-period duration @@ -617,6 +941,8 @@ Usage of ./pyroscope: Enable backoff and retry when we hit rate limits. -query-scheduler.grpc-client-config.backoff-retries int Number of times to backoff and retry before failing. (default 10) + -query-scheduler.grpc-client-config.cluster-validation.label string + [experimental] Primary cluster validation label. -query-scheduler.grpc-client-config.connect-backoff-base-delay duration Initial backoff delay after first connection failure. Only relevant if ConnectTimeout > 0. (default 1s) -query-scheduler.grpc-client-config.connect-backoff-max-delay duration @@ -714,9 +1040,9 @@ Usage of ./pyroscope: -query-scheduler.ring.instance-port int Port to advertise in the ring (defaults to -server.http-listen-port). -query-scheduler.ring.multi.mirror-enabled - Mirror writes to secondary store. + Mirror writes to the secondary store. -query-scheduler.ring.multi.mirror-timeout duration - Timeout for storing value to secondary store. (default 2s) + Timeout for storing a value to the secondary store. (default 2s) -query-scheduler.ring.multi.primary string Primary backend storage used by multi-client. -query-scheduler.ring.multi.secondary string @@ -727,24 +1053,222 @@ Usage of ./pyroscope: Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") -query-scheduler.service-discovery-mode string [experimental] Service discovery mode that query-frontends and queriers use to find query-scheduler instances. When query-scheduler ring-based service discovery is enabled, this option needs be set on query-schedulers, query-frontends and queriers. Supported values are: dns, ring. (default "ring") + -recording-rules.max-rules-per-tenant int + Maximum number of recording rules a tenant can create. 0 to disable. (default 25) + -retention-period duration + Retention period for the data. 0 means data never deleted. (default 31d) -ring.heartbeat-timeout duration - The heartbeat timeout after which ingesters are skipped for reads/writes. 0 = never (timeout disabled). (default 1m0s) + The heartbeat timeout after which ingesters are skipped for reads/writes. (default 1m0s) -ring.prefix string The prefix for the keys in the store. Should end with a /. (default "collectors/") -ring.store string Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") -runtime-config.file comma-separated-list-of-strings - Comma separated list of yaml files with the configuration that can be updated at runtime. Runtime config files will be merged from left to right. + Comma separated list of yaml files or URLs with the configuration that can be updated at runtime. Runtime config files will be merged from left to right. + -runtime-config.http-client-cluster-validation.label string + [experimental] Primary cluster validation label. + -runtime-config.http-client-disable-keep-alives + Disable HTTP keep-alives for the runtime config HTTP client. When enabled, each reload opens a new connection, which prevents long-lived connections from being pinned to a single backend when the runtime config URL is served by multiple replicas behind a connection-level (L4) load balancer, such as a Kubernetes Service. (default true) + -runtime-config.http-client-timeout duration + HTTP client timeout when fetching runtime config from URLs. (default 30s) -runtime-config.reload-period duration How often to check runtime config files. (default 10s) + -segment-writer.availability-zone string + The availability zone where this instance is running. + -segment-writer.bucket-health-check-enabled + Enables bucket health check on startup. This both validates credentials and warms up the connection to reduce latency for the first write. (default true) + -segment-writer.bucket-health-check-timeout duration + Timeout for bucket health check operations. (default 10s) + -segment-writer.consul.acl-token string + ACL Token used to interact with Consul. + -segment-writer.consul.cas-retry-delay duration + Maximum duration to wait before retrying a Compare And Swap (CAS) operation. (default 1s) + -segment-writer.consul.client-timeout duration + HTTP timeout when talking to Consul (default 20s) + -segment-writer.consul.consistent-reads + Enable consistent reads to Consul. + -segment-writer.consul.hostname string + Hostname and port of Consul. (default "localhost:8500") + -segment-writer.consul.watch-burst-size int + Burst size used in rate limit. Values less than 1 are treated as 1. (default 1) + -segment-writer.consul.watch-rate-limit float + Rate limit when watching key or prefix in Consul, in requests per second. 0 disables the rate limit. (default 1) + -segment-writer.distributor.excluded-zones comma-separated-list-of-strings + Comma-separated list of zones to exclude from the ring. Instances in excluded zones will be filtered out from the ring. + -segment-writer.distributor.replication-factor int + The number of ingesters to write to and read from. (default 3) + -segment-writer.distributor.zone-awareness-enabled + True to enable the zone-awareness and replicate ingested samples across different availability zones. + -segment-writer.enable-inet6 + Enable IPv6 support. Required to make use of IP addresses from IPv6 interfaces. + -segment-writer.etcd.dial-timeout duration + The dial timeout for the etcd connection. (default 10s) + -segment-writer.etcd.endpoints string + The etcd endpoints to connect to. + -segment-writer.etcd.max-retries int + The maximum number of retries to do for failed ops. (default 10) + -segment-writer.etcd.password string + Etcd password. + -segment-writer.etcd.tls-ca-path string + Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used. + -segment-writer.etcd.tls-cert-path string + Path to the client certificate, which will be used for authenticating with the server. Also requires the key path to be configured. + -segment-writer.etcd.tls-cipher-suites string + Override the default cipher suite list (separated by commas). + -segment-writer.etcd.tls-enabled + Enable TLS. + -segment-writer.etcd.tls-insecure-skip-verify + Skip validating server certificate. + -segment-writer.etcd.tls-key-path string + Path to the key for the client certificate. Also requires the client certificate to be configured. + -segment-writer.etcd.tls-min-version string + Override the default minimum TLS version. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 + -segment-writer.etcd.tls-server-name string + Override the expected name on the server certificate. + -segment-writer.etcd.username string + Etcd username. + -segment-writer.final-sleep duration + Duration to sleep for before exiting, to ensure metrics are scraped. + -segment-writer.flush-concurrency uint + Number of concurrent flushes. Defaults to the number of CPUs, but not less than 8. + -segment-writer.grpc-client-config.backoff-max-period duration + Maximum delay when backing off. (default 10s) + -segment-writer.grpc-client-config.backoff-min-period duration + Minimum delay when backing off. (default 100ms) + -segment-writer.grpc-client-config.backoff-on-ratelimits + Enable backoff and retry when we hit rate limits. + -segment-writer.grpc-client-config.backoff-retries int + Number of times to backoff and retry before failing. (default 10) + -segment-writer.grpc-client-config.cluster-validation.label string + [experimental] Primary cluster validation label. + -segment-writer.grpc-client-config.connect-backoff-base-delay duration + Initial backoff delay after first connection failure. Only relevant if ConnectTimeout > 0. (default 1s) + -segment-writer.grpc-client-config.connect-backoff-max-delay duration + Maximum backoff delay when establishing a connection. Only relevant if ConnectTimeout > 0. (default 5s) + -segment-writer.grpc-client-config.connect-timeout duration + The maximum amount of time to establish a connection. A value of 0 means default gRPC client connect timeout and backoff. (default 1s) + -segment-writer.grpc-client-config.grpc-client-rate-limit float + Rate limit for gRPC client; 0 means disabled. + -segment-writer.grpc-client-config.grpc-client-rate-limit-burst int + Rate limit burst for gRPC client. + -segment-writer.grpc-client-config.grpc-compression string + Use compression when sending messages. Supported values are: 'gzip', 'snappy' and '' (disable compression) + -segment-writer.grpc-client-config.grpc-max-recv-msg-size int + gRPC client max receive message size (bytes). (default 104857600) + -segment-writer.grpc-client-config.grpc-max-send-msg-size int + gRPC client max send message size (bytes). (default 104857600) + -segment-writer.grpc-client-config.initial-connection-window-size value + [experimental] Initial connection window size. Values less than the default are not supported and are ignored. Setting this to a value other than the default disables the BDP estimator. (default 63KiB1023B) + -segment-writer.grpc-client-config.initial-stream-window-size value + [experimental] Initial stream window size. Values less than the default are not supported and are ignored. Setting this to a value other than the default disables the BDP estimator. (default 63KiB1023B) + -segment-writer.grpc-client-config.tls-ca-path string + Path to the CA certificates to validate server certificate against. If not set, the host's root CA certificates are used. + -segment-writer.grpc-client-config.tls-cert-path string + Path to the client certificate, which will be used for authenticating with the server. Also requires the key path to be configured. + -segment-writer.grpc-client-config.tls-cipher-suites string + Override the default cipher suite list (separated by commas). + -segment-writer.grpc-client-config.tls-enabled + Enable TLS in the gRPC client. This flag needs to be enabled when any other TLS flag is set. If set to false, insecure connection to gRPC server will be used. + -segment-writer.grpc-client-config.tls-insecure-skip-verify + Skip validating server certificate. + -segment-writer.grpc-client-config.tls-key-path string + Path to the key for the client certificate. Also requires the client certificate to be configured. + -segment-writer.grpc-client-config.tls-min-version string + Override the default minimum TLS version. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 + -segment-writer.grpc-client-config.tls-server-name string + Override the expected name on the server certificate. + -segment-writer.heartbeat-period duration + Period at which to heartbeat to consul. (default 5s) + -segment-writer.heartbeat-timeout duration + Heartbeat timeout after which instance is assumed to be unhealthy. (default 1m0s) + -segment-writer.join-after duration + Period to wait for a claim from another member; will join automatically after this. + -segment-writer.lifecycler.ID string + ID to register in the ring. (default "") + -segment-writer.lifecycler.addr string + IP address to advertise in the ring. + -segment-writer.lifecycler.interface string + Name of network interface to read address from. (default []) + -segment-writer.lifecycler.port int + port to advertise in consul (defaults to server.grpc-listen-port). + -segment-writer.metadata-dlq-enabled + Enables dead letter queue (DLQ) for metadata. If the metadata update fails, it will be stored and updated asynchronously. (default true) + -segment-writer.metadata-update-timeout duration + Timeout for metadata update requests. (default 2s) + -segment-writer.min-ready-duration duration + Minimum duration to wait after the internal readiness checks have passed but before succeeding the readiness endpoint. This is used to slowdown deployment controllers (eg. Kubernetes) after an instance is ready and before they proceed with a rolling update, to give the rest of the cluster instances enough time to receive ring updates. (default 30s) + -segment-writer.multi.mirror-enabled + Mirror writes to the secondary store. + -segment-writer.multi.mirror-timeout duration + Timeout for storing a value to the secondary store. (default 2s) + -segment-writer.multi.primary string + Primary backend storage used by multi-client. + -segment-writer.multi.secondary string + Secondary backend storage used by multi-client. + -segment-writer.num-tokens int + Number of tokens for each ingester. (default 4) + -segment-writer.observe-period duration + Observe tokens after generating to resolve collisions. Useful when using gossiping ring. + -segment-writer.prefix string + The prefix for the keys in the store. Should end with a /. (default "collectors/") + -segment-writer.readiness-check-ring-health + When enabled the readiness probe succeeds only after all instances are ACTIVE and healthy in the ring, otherwise only the instance itself is checked. This option should be disabled if in your cluster multiple instances can be rolled out simultaneously, otherwise rolling updates may be slowed down. (default true) + -segment-writer.ring.heartbeat-timeout duration + The heartbeat timeout after which ingesters are skipped for reads/writes. (default 1m0s) + -segment-writer.segment-duration duration + Timeout when flushing segments to bucket. (default 500ms) + -segment-writer.store string + Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") + -segment-writer.tokens-file-path string + File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup. + -segment-writer.unregister-on-shutdown + Unregister from the ring upon clean shutdown. It can be useful to disable for rolling restarts with consistent naming in conjunction with -distributor.extend-writes=false. + -segment-writer.upload-hedge-after duration + Time after which to hedge the upload request. (default 500ms) + -segment-writer.upload-hedge-rate-burst uint + Maximum number of hedged requests in a burst. (default 10) + -segment-writer.upload-hedge-rate-max float + Maximum number of hedged requests per second. 0 disables rate limiting. (default 2) + -segment-writer.upload-max-retries int + Number of times to backoff and retry before failing. (default 3) + -segment-writer.upload-retry-max-period duration + Maximum delay when backing off. (default 500ms) + -segment-writer.upload-retry-min-period duration + Minimum delay when backing off. (default 50ms) + -segment-writer.upload-timeout duration + Timeout for upload requests, including retries. (default 2s) -self-profiling.block-profile-rate int (default 5) -self-profiling.disable-push When running in single binary (--target=all) Pyroscope will push (Go SDK) profiles to itself. Set to true to disable self-profiling. -self-profiling.mutex-profile-fraction int (default 5) + -self-profiling.tenant-id string + Tenant ID for self-profiling data. If empty, no tenant header is sent (anonymous). + -self-profiling.use-k6-middleware + Read k6 labels from request headers and set them as dynamic profile tags. + -server.cluster-validation.additional-labels comma-separated-list-of-strings + [experimental] Comma-separated list of additional cluster validation labels that the server will accept from incoming requests. + -server.cluster-validation.grpc.enabled + [experimental] When enabled, cluster label validation is executed: configured cluster validation label is compared with the cluster validation label received through the requests. + -server.cluster-validation.grpc.soft-validation + [experimental] When enabled, soft cluster label validation is executed. Can be enabled only together with server.cluster-validation.grpc.enabled + -server.cluster-validation.http.enabled + [experimental] When enabled, cluster label validation is executed: configured cluster validation label is compared with the cluster validation label received through the requests. + -server.cluster-validation.http.excluded-paths comma-separated-list-of-strings + [experimental] Comma-separated list of url paths that are excluded from the cluster validation check. + -server.cluster-validation.http.excluded-user-agents comma-separated-list-of-strings + [experimental] Comma-separated list of user agents that are excluded from the cluster validation check. + -server.cluster-validation.http.soft-validation + [experimental] When enabled, soft cluster label validation is executed. Can be enabled only together with server.cluster-validation.http.enabled + -server.cluster-validation.label string + [experimental] Primary cluster validation label. + -server.create-new-traces + Creates new traces for each call rather than continuing the existing trace. A span link is used to allow navigation to the parent trace. Only works when using Open-Telemetry tracing. -server.graceful-shutdown-timeout duration Timeout for graceful shutdowns (default 30s) + -server.grpc-collect-max-streams-by-conn + If true, the max streams by connection gauge will be collected. (default true) -server.grpc-conn-limit int Maximum number of simultaneous grpc connections, <=0 to disable -server.grpc-listen-address string @@ -756,9 +1280,9 @@ Usage of ./pyroscope: -server.grpc-max-concurrent-streams uint Limit on the number of concurrent streams for gRPC calls per client connection (0 = unlimited) (default 100) -server.grpc-max-recv-msg-size-bytes int - Limit on the size of a gRPC message this server can receive (bytes). (default 4194304) + Limit on the size of a gRPC message this server can receive (bytes). (default 104857600) -server.grpc-max-send-msg-size-bytes int - Limit on the size of a gRPC message this server can send (bytes). (default 4194304) + Limit on the size of a gRPC message this server can send (bytes). (default 104857600) -server.grpc-tls-ca-path string GRPC TLS Client CA path. -server.grpc-tls-cert-path string @@ -774,7 +1298,7 @@ Usage of ./pyroscope: -server.grpc.keepalive.max-connection-idle duration The duration after which an idle connection should be closed. Default: infinity (default 2562047h47m16.854775807s) -server.grpc.keepalive.min-time-between-pings duration - Minimum amount of time a client should wait before sending a keepalive ping. If client sends keepalive ping more often, server will send GOAWAY and close the connection. (default 5m0s) + Minimum amount of time a client should wait before sending a keepalive ping. If client sends keepalive ping more often, server will send GOAWAY and close the connection. (default 1s) -server.grpc.keepalive.ping-without-stream-allowed If true, server allows keepalive pings even when there are no active streams(RPCs). If false, and client sends ping when there are no active streams, server will send GOAWAY and close the connection. -server.grpc.keepalive.time duration @@ -783,6 +1307,14 @@ Usage of ./pyroscope: After having pinged for keepalive check, the duration after which an idle connection should be closed, Default: 20s (default 20s) -server.grpc.num-workers int If non-zero, configures the amount of GRPC server workers used to serve the requests. + -server.grpc.read-buffer-size-bytes int + Size of the read buffer for each gRPC connection (bytes). A smaller buffer may reduce memory usage but may lead to more system calls. (default 32768) + -server.grpc.recv-buffer-pools-enabled + Deprecated option, has no effect and will be removed in a future version. + -server.grpc.stats-tracking-enabled + If true, the request_message_bytes, response_message_bytes, and inflight_requests metrics will be tracked. Enabling this option prevents the use of memory pools for parsing gRPC request bodies and may lead to more memory allocations. (default true) + -server.grpc.write-buffer-size-bytes int + Size of the write buffer for each gRPC connection (bytes). A smaller buffer may reduce memory usage but may lead to more system calls. (default 32768) -server.http-conn-limit int Maximum number of simultaneous http connections, <=0 to disable -server.http-idle-timeout duration @@ -817,24 +1349,44 @@ Usage of ./pyroscope: Comma separated list of headers to exclude from loggin. Only used if server.log-request-headers is true. -server.log-source-ips-enabled Optionally log the source IPs. + -server.log-source-ips-full + Log all source IPs instead of only the originating one. Only used if server.log-source-ips-enabled is true -server.log-source-ips-header string Header field storing the source IPs. Only used if server.log-source-ips-enabled is true. If not set the default Forwarded, X-Real-IP and X-Forwarded-For headers are used -server.log-source-ips-regex string Regex for matching the source IPs. Only used if server.log-source-ips-enabled is true. If not set the default Forwarded, X-Real-IP and X-Forwarded-For headers are used -server.path-prefix string Base path to serve all API routes from (e.g. /v1/) + -server.proxy-protocol-enabled + Enables PROXY protocol. -server.register-instrumentation Register the intrumentation handlers (/metrics etc). (default true) -server.report-grpc-codes-in-instrumentation-label-enabled If set to true, gRPC statuses will be reported in instrumentation labels with their string representations. Otherwise, they will be reported as "error". + -server.throughput.latency-cutoff duration + Requests taking over the cutoff are be observed to measure throughput. Server-Timing header is used with specified unit as the indicator, for example 'Server-Timing: unit;val=8.2'. If set to 0, the throughput is not calculated. + -server.throughput.unit string + Unit of the server throughput metric, for example 'processed_bytes' or 'samples_processed'. Observed values are gathered from the 'Server-Timing' header with the 'val' key. If set, it is appended to the request_server_throughput metric name. (default "samples_processed") -server.tls-cipher-suites string Comma-separated list of cipher suites to use. If blank, the default Go cipher suites is used. -server.tls-min-version string Minimum TLS version to use. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. If blank, the Go TLS minimum version is used. + -server.trace-request-headers + Optionally add request headers to tracing spans. + -server.trace-request-headers-exclude-list string + Comma separated list of headers to exclude from tracing spans. Only used if server.trace-request-headers is true. The following headers are always excluded: Authorization, Cookie, X-Access-Token, X-Csrf-Token, X-Grafana-Id. + -shutdown-delay duration + Wait time before shutting down after a termination signal. -storage.azure.account-key string Azure storage account key. If unset, Azure managed identities will be used for authentication instead. -storage.azure.account-name string Azure storage account name + -storage.azure.az-tenant-id string + Azure Active Directory tenant ID. If set alongside `client-id` and `client-secret`, these values will be used for authentication via a client secret credential. + -storage.azure.client-id string + Azure Active Directory client ID. If set alongside `az-tenant-id` and `client-secret`, these values will be used for authentication via a client secret credential. + -storage.azure.client-secret string + Azure Active Directory client secret. If set alongside `az-tenant-id` and `client-id`, these values will be used for authentication via a client secret credential. -storage.azure.connection-string string If `connection-string` is set, the value of `endpoint-suffix` will not be used. Use this method over `account-key` if you need to authenticate via a SAS token. Or if you use the Azurite emulator. -storage.azure.container-name string @@ -846,7 +1398,7 @@ Usage of ./pyroscope: -storage.azure.user-assigned-id string User assigned managed identity. If empty, then System assigned identity is used. -storage.backend string - Backend storage to use. Supported backends are: s3, gcs, azure, swift, filesystem, cos. + Backend storage to use. Supported backends are: s3, gcs, azure, swift, filesystem, cos. (default "filesystem") -storage.cos.app-id string COS app id -storage.cos.bucket string @@ -876,13 +1428,33 @@ Usage of ./pyroscope: -storage.cos.tls-handshake-timeout duration Maximum time to wait for a TLS handshake. 0 means no limit. (default 10s) -storage.filesystem.dir string - Local filesystem storage directory. (default "./data-shared") + Local filesystem storage directory. (default "./data/v2/shared") -storage.gcs.bucket-name string GCS bucket name + -storage.gcs.expect-continue-timeout duration + The time to wait for a server's first response headers after fully writing the request headers if the request has an Expect header. 0 to send the request body immediately. (default 1s) + -storage.gcs.http.idle-conn-timeout duration + The time an idle connection will remain idle before closing. (default 10m0s) + -storage.gcs.http.insecure-skip-verify + If the client connects to GCS via HTTPS and this option is enabled, the client will accept any certificate and hostname. + -storage.gcs.http.response-header-timeout duration + The amount of time the client will wait for a servers response headers. (default 2m0s) + -storage.gcs.max-connections-per-host int + Maximum number of connections per host. 0 means no limit. + -storage.gcs.max-idle-connections int + Maximum number of idle (keep-alive) connections across all hosts. 0 means no limit. + -storage.gcs.max-idle-connections-per-host int + Maximum number of idle (keep-alive) connections to keep per-host. If 0, a built-in default value is used. (default 1000) -storage.gcs.service-account string JSON either from a Google Developers Console client_credentials.json file, or a Google Developers service account key. Needs to be valid JSON, not a filesystem path. + -storage.gcs.tls-handshake-timeout duration + Maximum time to wait for a TLS handshake. 0 means no limit. (default 10s) + -storage.prefix string + Prefix for all objects stored in the backend storage. For simplicity, it may only contain digits and English alphabet characters, hyphens, underscores, dots and forward slashes. -storage.s3.access-key-id string S3 access key ID + -storage.s3.bucket-lookup-type string + S3 bucket lookup style, use one of: [path-style virtual-hosted-style auto] (default "auto") -storage.s3.bucket-name string S3 bucket name -storage.s3.endpoint string @@ -890,9 +1462,9 @@ Usage of ./pyroscope: -storage.s3.expect-continue-timeout duration The time to wait for a server's first response headers after fully writing the request headers if the request has an Expect header. 0 to send the request body immediately. (default 1s) -storage.s3.force-path-style - Set this to `true` to force the bucket lookup to be using path-style. + Deprecated, use s3.bucket-lookup-type instead. Set this to `true` to force the bucket lookup to be using path-style. -storage.s3.http.idle-conn-timeout duration - The time an idle connection will remain idle before closing. (default 1m30s) + The time an idle connection will remain idle before closing. (default 10m0s) -storage.s3.http.insecure-skip-verify If the client connects to S3 via HTTPS and this option is enabled, the client will accept any certificate and hostname. -storage.s3.http.response-header-timeout duration @@ -902,9 +1474,11 @@ Usage of ./pyroscope: -storage.s3.max-connections-per-host int Maximum number of connections per host. 0 means no limit. -storage.s3.max-idle-connections int - Maximum number of idle (keep-alive) connections across all hosts. 0 means no limit. (default 100) + Maximum number of idle (keep-alive) connections across all hosts. 0 means no limit. -storage.s3.max-idle-connections-per-host int - Maximum number of idle (keep-alive) connections to keep per-host. If 0, a built-in default value is used. (default 100) + Maximum number of idle (keep-alive) connections to keep per-host. If 0, a built-in default value is used. (default 1000) + -storage.s3.native-aws-auth-enabled + [experimental] If enabled, it will use the default authentication methods of the AWS SDK for go based on known environment variables and known AWS config files. -storage.s3.region string S3 region. If unset, the client will issue a S3 GetBucketLocation API call to autodetect it. -storage.s3.secret-access-key string @@ -920,7 +1494,7 @@ Usage of ./pyroscope: -storage.s3.tls-handshake-timeout duration Maximum time to wait for a TLS handshake. 0 means no limit. (default 10s) -storage.storage-prefix string - [experimental] Prefix for all objects stored in the backend storage. For simplicity, it may only contain digits and English alphabet letters. + [experimental] Deprecated: Use 'storage..prefix' instead. Prefix for all objects stored in the backend storage. For simplicity, it may only contain digits and English alphabet characters, hyphens, underscores, dots and forward slashes. -storage.swift.auth-url string OpenStack Swift authentication URL -storage.swift.auth-version int @@ -1014,9 +1588,9 @@ Usage of ./pyroscope: -store-gateway.sharding-ring.instance-port int Port to advertise in the ring (defaults to -server.http-listen-port). -store-gateway.sharding-ring.multi.mirror-enabled - Mirror writes to secondary store. + Mirror writes to the secondary store. -store-gateway.sharding-ring.multi.mirror-timeout duration - Timeout for storing value to secondary store. (default 2s) + Timeout for storing a value to the secondary store. (default 2s) -store-gateway.sharding-ring.multi.primary string Primary backend storage used by multi-client. -store-gateway.sharding-ring.multi.secondary string @@ -1039,14 +1613,26 @@ Usage of ./pyroscope: True to enable zone-awareness and replicate blocks across different availability zones. This option needs be set both on the store-gateway and querier when running in microservices mode. -store-gateway.tenant-shard-size int The tenant's shard size, used when store-gateway sharding is enabled. Value of 0 disables shuffle sharding for the tenant, that is all tenant blocks are sharded across all store-gateway replicas. + -symbolizer.debuginfod-url string + URL of the debuginfod server (default "https://debuginfod.elfutils.org") + -symbolizer.enabled + [experimental] Enable symbolization for tenants by default. + -symbolizer.max-debuginfod-concurrency int + Maximum number of concurrent symbolization requests to debuginfod server. (default 10) -target comma-separated-list-of-strings Comma-separated list of Pyroscope modules to load. The alias 'all' can be used in the list to load a number of core modules and will enable single-binary mode. (default all) + -tenant-settings.recording-rules.enabled + [experimental] Enable the storing of recording rules in tenant settings. -tracing.enabled Set to false to disable tracing. (default true) -tracing.profiling-enabled [experimental] Set to true to enable profiling integration. -usage-stats.enabled - Enable anonymous usage reporting. (default true) + Enable anonymous usage statistics collection. For more details about usage statistics, refer to https://grafana.com/docs/pyroscope/latest/configure-server/anonymous-usage-statistics-reporting/ (default true) + -valdation.symbolizer.max-symbol-size-bytes int + Maximum size of a symbol in bytes. This an upper limits to both the compressed and uncompressed size. 0 to disable. (default 536870912) + -validation.disable-label-sanitization + Disable label name sanitization (converting dots to underscores). When disabled, labels with dots are accepted as-is using UTF-8 validation. (default true) -validation.enforce-labels-order Enforce labels order optimization. -validation.max-label-names-per-series int @@ -1073,3 +1659,13 @@ Usage of ./pyroscope: This limits how far into the past profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 1h. (default 1h) -version Show the version of pyroscope and exit + -write-path value + Controls the write path route; valid options: ingester, segment-writer, combined. (default "segment-writer") + -write-path.compression value + Compression algorithm to use for segment writer requests; valid compression options: none, gzip. (default "none") + -write-path.ingester-weight float + Specifies the fraction [0:1] that should be send to ingester in combined mode. 0 means no traffics is sent to ingester. 1 means 100% of requests are sent to ingester. (default 1) + -write-path.segment-writer-timeout duration + Timeout for segment writer requests. (default 5s) + -write-path.segment-writer-weight float + Specifies the fraction [0:1] that should be send to segment-writer in combined mode. 0 means no traffics is sent to segment-writer. 1 means 100% of requests are sent to segment-writer. diff --git a/cmd/pyroscope/help.txt.tmpl b/cmd/pyroscope/help.txt.tmpl index ad077e714e..965f73e09f 100644 --- a/cmd/pyroscope/help.txt.tmpl +++ b/cmd/pyroscope/help.txt.tmpl @@ -1,40 +1,48 @@ Usage of ./pyroscope: + -admin-server.http-listen-address string + Address for the admin HTTP server. Defaults to localhost so the port is not exposed externally. Use :: or 0.0.0.0 to listen on all interfaces. (default "localhost") + -admin-server.http-listen-port int + Port for the admin HTTP server (metrics, pprof, admin). (default 4042) + -admin-server.mode value + Controls the admin server for metrics, pprof and admin endpoints. 'disabled': all routes on the main port (default). 'additional': admin server started, operational routes served on both ports. 'exclusive': admin server started, operational routes removed from main port. (default "disabled") -api.base-url string base URL for when the server is behind a reverse proxy with a different path + -architecture.storage value + Storage architecture layer. Use 'v1' to use legacy ingester-based storage, 'v2' for new storage, and 'v1-v2-dual' to use new storage while being able to query old data. (default "v1-v2-dual") -auth.multitenancy-enabled When set to true, incoming HTTP requests must specify tenant ID in HTTP X-Scope-OrgId header. When set to false, tenant ID anonymous is used instead. -blocks-storage.bucket-store.sync-dir string Directory to store synchronized pyroscope block headers. This directory is not required to be persisted between restarts, but it's highly recommended in order to improve the store-gateway startup time. (default "./data/pyroscope-sync/") -compactor.blocks-retention-period duration - Delete blocks containing samples older than the specified retention period. 0 to disable. + [v1 storage only] Delete blocks containing samples older than the specified retention period. 0 to disable. -compactor.compactor-downsampler-enabled - If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. (default true) + [v1 storage only] If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. Note: This set the default for the teanant overrides, in order to be effective it also requires compactor.downsampler-enabled to be set to true. (default true) -compactor.compactor-tenant-shard-size int - Max number of compactors that can compact blocks for single tenant. 0 to disable the limit and use all compactors. + [v1 storage only] Max number of compactors that can compact blocks for single tenant. 0 to disable the limit and use all compactors. -compactor.data-dir string - Directory to temporarily store blocks during compaction. This directory is not required to be persisted between restarts. (default "./data-compactor") + [v1 storage only] Directory to temporarily store blocks during compaction. This directory is not required to be persisted between restarts. (default "./data-compactor") -compactor.first-level-compaction-wait-period duration - How long the compactor waits before compacting first-level blocks that are uploaded by the ingesters. This configuration option allows for the reduction of cases where the compactor begins to compact blocks before all ingesters have uploaded their blocks to the storage. (default 25m0s) + [v1 storage only] How long the compactor waits before compacting first-level blocks that are uploaded by the ingesters. This configuration option allows for the reduction of cases where the compactor begins to compact blocks before all ingesters have uploaded their blocks to the storage. (default 25m0s) -compactor.partial-block-deletion-delay duration - If a partial block (unfinished block without meta.json file) hasn't been modified for this time, it will be marked for deletion. The minimum accepted value is 4h0m0s: a lower value will be ignored and the feature disabled. 0 to disable. (default 1d) + [v1 storage only] If a partial block (unfinished block without meta.json file) hasn't been modified for this time, it will be marked for deletion. The minimum accepted value is 4h0m0s: a lower value will be ignored and the feature disabled. 0 to disable. (default 1d) -compactor.ring.consul.hostname string - Hostname and port of Consul. (default "localhost:8500") + [v1 storage only] Hostname and port of Consul. (default "localhost:8500") -compactor.ring.etcd.endpoints string - The etcd endpoints to connect to. + [v1 storage only] The etcd endpoints to connect to. -compactor.ring.etcd.password string - Etcd password. + [v1 storage only] Etcd password. -compactor.ring.etcd.username string - Etcd username. + [v1 storage only] Etcd username. -compactor.ring.instance-interface-names string - List of network interface names to look up when finding the instance IP address. (default []) + [v1 storage only] List of network interface names to look up when finding the instance IP address. (default []) -compactor.ring.store string - Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") + [v1 storage only] Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") -compactor.split-and-merge-shards int - The number of shards to use when splitting blocks. 0 to disable splitting. + [v1 storage only] The number of shards to use when splitting blocks. 0 to disable splitting. -compactor.split-and-merge-stage-size int - Number of stages split shards will be written to. Number of output split shards is controlled by -compactor.split-and-merge-shards. + [v1 storage only] Number of stages split shards will be written to. Number of output split shards is controlled by -compactor.split-and-merge-shards. -compactor.split-groups int - Number of groups that blocks for splitting should be grouped into. Each group of blocks is then split separately. Number of output split shards is controlled by -compactor.split-and-merge-shards. (default 1) + [v1 storage only] Number of groups that blocks for splitting should be grouped into. Each group of blocks is then split separately. Number of output split shards is controlled by -compactor.split-and-merge-shards. (default 1) -config.expand-env Expands ${var} in config according to the values of the environment variables. -config.file string @@ -59,6 +67,8 @@ Usage of ./pyroscope: Per-tenant ingestion rate limit in sample size per second. Units in MB. (default 4) -distributor.ingestion-tenant-shard-size int The tenant's shard size used by shuffle-sharding. Must be set both on ingesters and distributors. 0 disables shuffle sharding. + -distributor.push.max-concurrency int + Maximum number of series within a single batched push that are processed concurrently. 0 = unbounded (legacy behavior); 1 = serialize pushes (kill switch). (default 256) -distributor.push.timeout duration Timeout when pushing data to ingester. (default 5s) -distributor.replication-factor int @@ -75,8 +85,18 @@ Usage of ./pyroscope: List of network interface names to look up when finding the instance IP address. (default []) -distributor.ring.store string Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") + -distributor.sampling.keep-stripped-profiles + When a profile is sampled out, retain its totals and labels with stacktraces stripped (marked __sampled__) instead of dropping it. -distributor.zone-awareness-enabled True to enable the zone-awareness and replicate ingested samples across different availability zones. + -embedded-grafana.data-path string + The directory where the Grafana data will be stored. (default "./data/__embedded_grafana/") + -embedded-grafana.listen-port int + The port on which the Grafana will listen. (default 4041) + -embedded-grafana.pyroscope-url string + The URL of the Pyroscope instance to use for the Grafana datasources. (default "http://localhost:4040") + -enable-query-backend-from value + This parameter specifies the point in time from which data is queried from the new query backend. The value can be an RFC3339 timestamp (2020-10-20T00:00:00Z) or "auto" to automatically determine the split point from the tenant's oldest profile time in the metastore. (default auto) -etcd.endpoints string The etcd endpoints to connect to. -etcd.password string @@ -90,21 +110,21 @@ Usage of ./pyroscope: -help-all Print help, also including advanced and experimental parameters. -ingester.availability-zone string - The availability zone where this instance is running. + [v1 storage only] The availability zone where this instance is running. -ingester.lifecycler.interface string - Name of network interface to read address from. (default []) + [v1 storage only] Name of network interface to read address from. (default []) -ingester.max-global-series-per-tenant int - Maximum number of active series of profiles per tenant, across the cluster. 0 to disable. When the global limit is enabled, each ingester is configured with a dynamic local limit based on the replication factor and the current number of healthy ingesters, and is kept updated whenever the number of ingesters change. (default 5000) + [v1 storage only] Maximum number of active series of profiles per tenant, across the cluster. 0 to disable. When the global limit is enabled, each ingester is configured with a dynamic local limit based on the replication factor and the current number of healthy ingesters, and is kept updated whenever the number of ingesters change. (default 5000) -ingester.max-local-series-per-tenant int - Maximum number of active series of profiles per tenant, per ingester. 0 to disable. + [v1 storage only] Maximum number of active series of profiles per tenant, per ingester. 0 to disable. -ingester.tokens-file-path string - File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup. + [v1 storage only] File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup. -log.format string Output log messages in the given format. Valid formats: [logfmt, json] (default "logfmt") -log.level value Only log messages with the given severity or above. Valid levels: [debug, info, warn, error] (default info) -memberlist.abort-if-join-fails - If this node fails to join memberlist cluster, abort. + Abort if this node fails to join memberlist cluster at startup. When enabled, it's not guaranteed that other services are started only after the cluster state has been successfully updated; use 'abort-if-fast-join-fails' instead. -memberlist.advertise-addr string Gossip address to advertise to other members in the cluster. Used for NAT traversal. -memberlist.advertise-port int @@ -113,8 +133,14 @@ Usage of ./pyroscope: IP address to listen on for gossip messages. Multiple addresses may be specified. Defaults to 0.0.0.0 -memberlist.bind-port int Port to listen on for gossip messages. (default 7946) - -memberlist.join string - Other cluster members to join. Can be specified multiple times. It can be an IP, hostname or an entry specified in the DNS Service Discovery format. + -memberlist.join value + Other cluster members to join. Can be specified multiple times or as a comma-separated list. It can be an IP, hostname or an entry specified in the DNS Service Discovery format. + -metastore.data-dir string + Directory to store the data. (default "./data/v2/metastore/data") + -metastore.raft.dir string + Directory to store WAL and raft state. It must be a persistent directory, not a tmpfs or similar. (default "./data/v2/metastore/raft") + -metastore.raft.snapshots-dir string + Directory to store FSM snapshots. Raft creates 'snapshots' subdirectory in this directory. It must be a persistent directory, not a tmpfs or similar. (default "./data/v2/metastore/raft") -modules List available modules that can be used as target and exit. -overrides-exporter.ring.consul.hostname string @@ -130,19 +156,21 @@ Usage of ./pyroscope: -overrides-exporter.ring.store string Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") -pyroscopedb.data-path string - Directory used for local storage. (default "./data") + [v1 storage only] Directory used for local storage. (default "./data") -pyroscopedb.max-block-duration duration - Upper limit to the duration of a Pyroscope block. (default 1h0m0s) + [v1 storage only] Upper limit to the duration of a Pyroscope block. (default 1h0m0s) -pyroscopedb.retention-policy-disable - Disable retention policy enforcement + [v1 storage only] Disable retention policy enforcement -pyroscopedb.retention-policy-enforcement-interval duration - How often to enforce disk retention (default 5m0s) + [v1 storage only] How often to enforce disk retention (default 5m0s) -pyroscopedb.retention-policy-min-disk-available-percentage float - Which percentage of free disk space to keep (default 0.05) + [v1 storage only] Which percentage of free disk space to keep (default 0.05) -pyroscopedb.retention-policy-min-free-disk-gb uint - How much available disk space to keep in GiB (default 10) + [v1 storage only] How much available disk space to keep in GiB (default 10) -pyroscopedb.row-group-target-size uint - How big should a single row group be uncompressed (default 1342177280) + [v1 storage only] How big should a single row group be uncompressed (default 1342177280) + -pyroscopedb.symbols-partition-label string + [v1 storage only] Specifies the dimension by which symbols are partitioned. By default, the partitioning is determined automatically. -querier.client-cleanup-period duration How frequently to clean up clients for ingesters that have gone away. (default 15s) -querier.health-check-ingesters @@ -152,7 +180,7 @@ Usage of ./pyroscope: -querier.max-flamegraph-nodes-default int Maximum number of flame graph nodes by default. 0 to disable. (default 8192) -querier.max-flamegraph-nodes-max int - Maximum number of flame graph nodes allowed. 0 to disable. + Maximum number of flame graph nodes allowed. 0 to disable. (default 1048576) -querier.max-query-length duration The limit to length of queries. 0 to disable. (default 1d) -querier.max-query-lookback duration @@ -163,8 +191,14 @@ Usage of ./pyroscope: Whether query analysis is enabled in the query frontend. If disabled, the /AnalyzeQuery endpoint will return an empty response. (default true) -querier.query-analysis-series-enabled Whether the series portion of query analysis is enabled. If disabled, no series data (e.g., series count) will be calculated by the /AnalyzeQuery endpoint. + -querier.sanitize-on-merge + Whether profiles should be sanitized when merging. (default true) -querier.split-queries-by-interval duration Split queries by a time interval and execute in parallel. The value 0 disables splitting by time + -query-backend.include-stripped-profiles + Include profiles that were sampled out and stored with stacktraces stripped (marked __sampled__) in query results. + -query-frontend.max-async-query-concurrency int + Maximum number of concurrent async queries per tenant. 0 to disable async queries. (default 5) -query-scheduler.max-outstanding-requests-per-tenant int Maximum number of outstanding requests per tenant per query-scheduler. In-flight requests above this limit will fail with HTTP response status code 429. (default 100) -query-scheduler.ring.consul.hostname string @@ -179,18 +213,30 @@ Usage of ./pyroscope: List of network interface names to look up when finding the instance IP address. (default []) -query-scheduler.ring.store string Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") + -recording-rules.max-rules-per-tenant int + Maximum number of recording rules a tenant can create. 0 to disable. (default 25) + -retention-period duration + Retention period for the data. 0 means data never deleted. (default 31d) -ring.store string Backend storage to use for the ring. Supported values are: consul, etcd, inmemory, memberlist, multi. (default "memberlist") -runtime-config.file comma-separated-list-of-strings - Comma separated list of yaml files with the configuration that can be updated at runtime. Runtime config files will be merged from left to right. + Comma separated list of yaml files or URLs with the configuration that can be updated at runtime. Runtime config files will be merged from left to right. -self-profiling.block-profile-rate int (default 5) -self-profiling.disable-push When running in single binary (--target=all) Pyroscope will push (Go SDK) profiles to itself. Set to true to disable self-profiling. -self-profiling.mutex-profile-fraction int (default 5) + -self-profiling.tenant-id string + Tenant ID for self-profiling data. If empty, no tenant header is sent (anonymous). + -self-profiling.use-k6-middleware + Read k6 labels from request headers and set them as dynamic profile tags. + -server.create-new-traces + Creates new traces for each call rather than continuing the existing trace. A span link is used to allow navigation to the parent trace. Only works when using Open-Telemetry tracing. -server.graceful-shutdown-timeout duration Timeout for graceful shutdowns (default 30s) + -server.grpc-collect-max-streams-by-conn + If true, the max streams by connection gauge will be collected. (default true) -server.grpc-conn-limit int Maximum number of simultaneous grpc connections, <=0 to disable -server.grpc-listen-address string @@ -202,9 +248,9 @@ Usage of ./pyroscope: -server.grpc-max-concurrent-streams uint Limit on the number of concurrent streams for gRPC calls per client connection (0 = unlimited) (default 100) -server.grpc-max-recv-msg-size-bytes int - Limit on the size of a gRPC message this server can receive (bytes). (default 4194304) + Limit on the size of a gRPC message this server can receive (bytes). (default 104857600) -server.grpc-max-send-msg-size-bytes int - Limit on the size of a gRPC message this server can send (bytes). (default 4194304) + Limit on the size of a gRPC message this server can send (bytes). (default 104857600) -server.grpc-tls-ca-path string GRPC TLS Client CA path. -server.grpc-tls-cert-path string @@ -220,7 +266,7 @@ Usage of ./pyroscope: -server.grpc.keepalive.max-connection-idle duration The duration after which an idle connection should be closed. Default: infinity (default 2562047h47m16.854775807s) -server.grpc.keepalive.min-time-between-pings duration - Minimum amount of time a client should wait before sending a keepalive ping. If client sends keepalive ping more often, server will send GOAWAY and close the connection. (default 5m0s) + Minimum amount of time a client should wait before sending a keepalive ping. If client sends keepalive ping more often, server will send GOAWAY and close the connection. (default 1s) -server.grpc.keepalive.ping-without-stream-allowed If true, server allows keepalive pings even when there are no active streams(RPCs). If false, and client sends ping when there are no active streams, server will send GOAWAY and close the connection. -server.grpc.keepalive.time duration @@ -229,6 +275,14 @@ Usage of ./pyroscope: After having pinged for keepalive check, the duration after which an idle connection should be closed, Default: 20s (default 20s) -server.grpc.num-workers int If non-zero, configures the amount of GRPC server workers used to serve the requests. + -server.grpc.read-buffer-size-bytes int + Size of the read buffer for each gRPC connection (bytes). A smaller buffer may reduce memory usage but may lead to more system calls. (default 32768) + -server.grpc.recv-buffer-pools-enabled + Deprecated option, has no effect and will be removed in a future version. + -server.grpc.stats-tracking-enabled + If true, the request_message_bytes, response_message_bytes, and inflight_requests metrics will be tracked. Enabling this option prevents the use of memory pools for parsing gRPC request bodies and may lead to more memory allocations. (default true) + -server.grpc.write-buffer-size-bytes int + Size of the write buffer for each gRPC connection (bytes). A smaller buffer may reduce memory usage but may lead to more system calls. (default 32768) -server.http-conn-limit int Maximum number of simultaneous http connections, <=0 to disable -server.http-idle-timeout duration @@ -263,24 +317,44 @@ Usage of ./pyroscope: Comma separated list of headers to exclude from loggin. Only used if server.log-request-headers is true. -server.log-source-ips-enabled Optionally log the source IPs. + -server.log-source-ips-full + Log all source IPs instead of only the originating one. Only used if server.log-source-ips-enabled is true -server.log-source-ips-header string Header field storing the source IPs. Only used if server.log-source-ips-enabled is true. If not set the default Forwarded, X-Real-IP and X-Forwarded-For headers are used -server.log-source-ips-regex string Regex for matching the source IPs. Only used if server.log-source-ips-enabled is true. If not set the default Forwarded, X-Real-IP and X-Forwarded-For headers are used -server.path-prefix string Base path to serve all API routes from (e.g. /v1/) + -server.proxy-protocol-enabled + Enables PROXY protocol. -server.register-instrumentation Register the intrumentation handlers (/metrics etc). (default true) -server.report-grpc-codes-in-instrumentation-label-enabled If set to true, gRPC statuses will be reported in instrumentation labels with their string representations. Otherwise, they will be reported as "error". + -server.throughput.latency-cutoff duration + Requests taking over the cutoff are be observed to measure throughput. Server-Timing header is used with specified unit as the indicator, for example 'Server-Timing: unit;val=8.2'. If set to 0, the throughput is not calculated. + -server.throughput.unit string + Unit of the server throughput metric, for example 'processed_bytes' or 'samples_processed'. Observed values are gathered from the 'Server-Timing' header with the 'val' key. If set, it is appended to the request_server_throughput metric name. (default "samples_processed") -server.tls-cipher-suites string Comma-separated list of cipher suites to use. If blank, the default Go cipher suites is used. -server.tls-min-version string Minimum TLS version to use. Allowed values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13. If blank, the Go TLS minimum version is used. + -server.trace-request-headers + Optionally add request headers to tracing spans. + -server.trace-request-headers-exclude-list string + Comma separated list of headers to exclude from tracing spans. Only used if server.trace-request-headers is true. The following headers are always excluded: Authorization, Cookie, X-Access-Token, X-Csrf-Token, X-Grafana-Id. + -shutdown-delay duration + Wait time before shutting down after a termination signal. -storage.azure.account-key string Azure storage account key. If unset, Azure managed identities will be used for authentication instead. -storage.azure.account-name string Azure storage account name + -storage.azure.az-tenant-id string + Azure Active Directory tenant ID. If set alongside `client-id` and `client-secret`, these values will be used for authentication via a client secret credential. + -storage.azure.client-id string + Azure Active Directory client ID. If set alongside `az-tenant-id` and `client-secret`, these values will be used for authentication via a client secret credential. + -storage.azure.client-secret string + Azure Active Directory client secret. If set alongside `az-tenant-id` and `client-id`, these values will be used for authentication via a client secret credential. -storage.azure.connection-string string If `connection-string` is set, the value of `endpoint-suffix` will not be used. Use this method over `account-key` if you need to authenticate via a SAS token. Or if you use the Azurite emulator. -storage.azure.container-name string @@ -288,7 +362,7 @@ Usage of ./pyroscope: -storage.azure.endpoint-suffix string Azure storage endpoint suffix without schema. The account name will be prefixed to this value to create the FQDN. If set to empty string, default endpoint suffix is used. -storage.backend string - Backend storage to use. Supported backends are: s3, gcs, azure, swift, filesystem, cos. + Backend storage to use. Supported backends are: s3, gcs, azure, swift, filesystem, cos. (default "filesystem") -storage.cos.app-id string COS app id -storage.cos.bucket string @@ -302,11 +376,13 @@ Usage of ./pyroscope: -storage.cos.secret-key string COS secret key -storage.filesystem.dir string - Local filesystem storage directory. (default "./data-shared") + Local filesystem storage directory. (default "./data/v2/shared") -storage.gcs.bucket-name string GCS bucket name -storage.gcs.service-account string JSON either from a Google Developers Console client_credentials.json file, or a Google Developers service account key. Needs to be valid JSON, not a filesystem path. + -storage.prefix string + Prefix for all objects stored in the backend storage. For simplicity, it may only contain digits and English alphabet characters, hyphens, underscores, dots and forward slashes. -storage.s3.access-key-id string S3 access key ID -storage.s3.bucket-name string @@ -380,7 +456,9 @@ Usage of ./pyroscope: -tracing.enabled Set to false to disable tracing. (default true) -usage-stats.enabled - Enable anonymous usage reporting. (default true) + Enable anonymous usage statistics collection. For more details about usage statistics, refer to https://grafana.com/docs/pyroscope/latest/configure-server/anonymous-usage-statistics-reporting/ (default true) + -validation.disable-label-sanitization + Disable label name sanitization (converting dots to underscores). When disabled, labels with dots are accepted as-is using UTF-8 validation. (default true) -validation.enforce-labels-order Enforce labels order optimization. -validation.max-label-names-per-series int @@ -407,5 +485,7 @@ Usage of ./pyroscope: This limits how far into the past profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 1h. (default 1h) -version Show the version of pyroscope and exit + -write-path value + Controls the write path route; valid options: ingester, segment-writer, combined. (default "segment-writer") To see all flags, use -help-all diff --git a/cmd/pyroscope/main.go b/cmd/pyroscope/main.go index 3028654762..4edfb12f75 100644 --- a/cmd/pyroscope/main.go +++ b/cmd/pyroscope/main.go @@ -12,14 +12,14 @@ import ( _ "github.com/grafana/pyroscope-go/godeltaprof/http/pprof" - "github.com/grafana/pyroscope/pkg/cfg" - "github.com/grafana/pyroscope/pkg/phlare" - "github.com/grafana/pyroscope/pkg/usage" - _ "github.com/grafana/pyroscope/pkg/util/build" + "github.com/grafana/pyroscope/v2/pkg/cfg" + "github.com/grafana/pyroscope/v2/pkg/pyroscope" + "github.com/grafana/pyroscope/v2/pkg/usage" + _ "github.com/grafana/pyroscope/v2/pkg/util/build" ) type mainFlags struct { - phlare.Config `yaml:",inline"` + pyroscope.Config `yaml:",inline"` PrintVersion bool `yaml:"-"` PrintModules bool `yaml:"-"` @@ -33,7 +33,7 @@ func (mf *mainFlags) Clone() flagext.Registerer { }(*mf) } -func (mf *mainFlags) PhlareConfig() *phlare.Config { +func (mf *mainFlags) PhlareConfig() *pyroscope.Config { return &mf.Config } @@ -53,9 +53,7 @@ func errorHandler() { } func main() { - var ( - flags mainFlags - ) + var flags mainFlags if err := cfg.DynamicUnmarshal(&flags, os.Args[1:], flag.CommandLine); err != nil { fmt.Fprintf(os.Stderr, "failed parsing config: %v\n", err) @@ -63,24 +61,7 @@ func main() { return } - if args := flag.Args(); len(args) > 0 { - switch args[0] { - // server mode is the pyroscope's only mode from 1.0 - case "server": - break - case "agent", "ebpf": - fmt.Printf("%s mode is deprecated. Please use Grafana Agent instead.\n", args[0]) - os.Exit(1) - case "connect", "exec": - fmt.Printf("%s mode is deprecated. Please use Pyroscope 0.37 or earlier.\n", args[0]) - os.Exit(1) - default: - fmt.Printf("unknown mode: %s\n", args[0]) - os.Exit(1) - } - } - - f, err := phlare.New(flags.Config) + f, err := pyroscope.New(flags.Config) if err != nil { fmt.Fprintf(os.Stderr, "failed creating pyroscope: %v\n", err) errorHandler() @@ -93,7 +74,7 @@ func main() { } if flags.PrintModules { - allDeps := f.ModuleManager.DependenciesForModule(phlare.All) + allDeps := f.ModuleManager.DependenciesForModule(pyroscope.All) for _, m := range f.ModuleManager.UserVisibleModuleNames() { ix := sort.SearchStrings(allDeps, m) diff --git a/cmd/pyroscope/main_test.go b/cmd/pyroscope/main_test.go index 4ee9c79b11..f0fb0592e4 100644 --- a/cmd/pyroscope/main_test.go +++ b/cmd/pyroscope/main_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/cfg" - "github.com/grafana/pyroscope/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/cfg" + "github.com/grafana/pyroscope/v2/pkg/test" ) func TestFlagParsing(t *testing.T) { @@ -39,8 +39,8 @@ func TestFlagParsing(t *testing.T) { }, "user visible module listing": { arguments: []string{"-modules"}, - stdoutMessage: "ingester *\n", - stderrExcluded: "ingester\n", + stdoutMessage: "segment-writer *\n", + stderrExcluded: "segment-writer\n", }, "version": { arguments: []string{"-version"}, @@ -55,7 +55,7 @@ func TestFlagParsing(t *testing.T) { }, } { t.Run(name, func(t *testing.T) { - _ = os.Setenv("TARGET", "ingester") + _ = os.Setenv("TARGET", "segment-writer") oldDefaultRegistry := prometheus.DefaultRegisterer defer func() { prometheus.DefaultRegisterer = oldDefaultRegistry @@ -108,6 +108,9 @@ func TestHelp(t *testing.T) { // "duplicate metrics collector registration attempted" errors. prometheus.DefaultRegisterer = prometheus.NewRegistry() + // Mocking TMPDIR for predictable output + t.Setenv("TMPDIR", "/tmp") + co := test.CaptureOutput(t) const cmd = "./pyroscope" diff --git a/cmd/pyroscope/pyroscope.yaml b/cmd/pyroscope/pyroscope.yaml index 4fe52dda9a..3bcb3d6bc0 100644 --- a/cmd/pyroscope/pyroscope.yaml +++ b/cmd/pyroscope/pyroscope.yaml @@ -1,2 +1,838 @@ +# Pyroscope example configuration file. +# +# All fields are shown with their default values, commented out. +# Uncomment and modify the ones you want to override. +# For the full reference see: +# https://grafana.com/docs/pyroscope/latest/configure-server/reference-configuration-parameters/ + +# Comma-separated list of Pyroscope modules to load. The alias 'all' can be used +# in the list to load a number of core modules and will enable single-binary +# mode. +# target: "all" + +api: + # base URL for when the server is behind a reverse proxy with a different path + # base-url: "" + server: - http_listen_port: 4040 + # HTTP server listen network, default tcp + # http_listen_network: "tcp" + + # HTTP server listen address. + # http_listen_address: "" + + # HTTP server listen port. + # http_listen_port: 4040 + + # Maximum number of simultaneous http connections, <=0 to disable + # http_listen_conn_limit: 0 + + # gRPC server listen network + # grpc_listen_network: "tcp" + + # gRPC server listen address. + # grpc_listen_address: "" + + # gRPC server listen port. + # grpc_listen_port: 9095 + + # Maximum number of simultaneous grpc connections, <=0 to disable + # grpc_listen_conn_limit: 0 + + # If true, the max streams by connection gauge will be collected. + # grpc_collect_max_streams_by_conn: true + + # Enables PROXY protocol. + # proxy_protocol_enabled: false + + # Comma-separated list of cipher suites to use. If blank, the default Go + # cipher suites is used. + # tls_cipher_suites: "" + + # Minimum TLS version to use. Allowed values: VersionTLS10, VersionTLS11, + # VersionTLS12, VersionTLS13. If blank, the Go TLS minimum version is used. + # tls_min_version: "" + + http_tls_config: + # Server TLS certificate. This configuration parameter is YAML only. + # cert: "" + + # Server TLS key. This configuration parameter is YAML only. + # key: "" + + # Root certificate authority used to verify client certificates. This + # configuration parameter is YAML only. + # client_ca: "" + + # HTTP server cert path. + # cert_file: "" + + # HTTP server key path. + # key_file: "" + + # HTTP TLS Client Auth type. + # client_auth_type: "" + + # HTTP TLS Client CA path. + # client_ca_file: "" + + grpc_tls_config: + # Server TLS certificate. This configuration parameter is YAML only. + # cert: "" + + # Server TLS key. This configuration parameter is YAML only. + # key: "" + + # Root certificate authority used to verify client certificates. This + # configuration parameter is YAML only. + # client_ca: "" + + # GRPC TLS server cert path. + # cert_file: "" + + # GRPC TLS server key path. + # key_file: "" + + # GRPC TLS Client Auth type. + # client_auth_type: "" + + # GRPC TLS Client CA path. + # client_ca_file: "" + + # Register the intrumentation handlers (/metrics etc). + # register_instrumentation: true + + # If set to true, gRPC statuses will be reported in instrumentation labels + # with their string representations. Otherwise, they will be reported as + # "error". + # report_grpc_codes_in_instrumentation_label_enabled: false + + # Timeout for graceful shutdowns + # graceful_shutdown_timeout: 30s + + # Read timeout for entire HTTP request, including headers and body. + # http_server_read_timeout: 30s + + # Read timeout for HTTP request headers. If set to 0, value of + # -server.http-read-timeout is used. + # http_server_read_header_timeout: 0s + + # Write timeout for HTTP server + # http_server_write_timeout: 30s + + # Idle timeout for HTTP server + # http_server_idle_timeout: 2m + + # Log closed connections that did not receive any response, most likely + # because client didn't send any request within timeout. + # http_log_closed_connections_without_response_enabled: false + + # Limit on the size of a gRPC message this server can receive (bytes). + # grpc_server_max_recv_msg_size: 104857600 + + # Limit on the size of a gRPC message this server can send (bytes). + # grpc_server_max_send_msg_size: 104857600 + + # Limit on the number of concurrent streams for gRPC calls per client + # connection (0 = unlimited) + # grpc_server_max_concurrent_streams: 100 + + # The duration after which an idle connection should be closed. Default: + # infinity + # grpc_server_max_connection_idle: 2562047h47m16.854775807s + + # The duration for the maximum amount of time a connection may exist before it + # will be closed. Default: infinity + # grpc_server_max_connection_age: 2562047h47m16.854775807s + + # An additive period after max-connection-age after which the connection will + # be forcibly closed. Default: infinity + # grpc_server_max_connection_age_grace: 2562047h47m16.854775807s + + # Duration after which a keepalive probe is sent in case of no activity over + # the connection., Default: 2h + # grpc_server_keepalive_time: 2h + + # After having pinged for keepalive check, the duration after which an idle + # connection should be closed, Default: 20s + # grpc_server_keepalive_timeout: 20s + + # Minimum amount of time a client should wait before sending a keepalive ping. + # If client sends keepalive ping more often, server will send GOAWAY and close + # the connection. + # grpc_server_min_time_between_pings: 1s + + # If true, server allows keepalive pings even when there are no active + # streams(RPCs). If false, and client sends ping when there are no active + # streams, server will send GOAWAY and close the connection. + # grpc_server_ping_without_stream_allowed: false + + # If non-zero, configures the amount of GRPC server workers used to serve the + # requests. + # grpc_server_num_workers: 0 + + # If true, the request_message_bytes, response_message_bytes, and + # inflight_requests metrics will be tracked. Enabling this option prevents the + # use of memory pools for parsing gRPC request bodies and may lead to more + # memory allocations. + # grpc_server_stats_tracking_enabled: true + + # Deprecated option, has no effect and will be removed in a future version. + # grpc_server_recv_buffer_pools_enabled: false + + # Size of the read buffer for each gRPC connection (bytes). A smaller buffer + # may reduce memory usage but may lead to more system calls. + # grpc_server_read_buffer_size: 32768 + + # Size of the write buffer for each gRPC connection (bytes). A smaller buffer + # may reduce memory usage but may lead to more system calls. + # grpc_server_write_buffer_size: 32768 + + # Output log messages in the given format. Valid formats: [logfmt, json] + # log_format: "logfmt" + + # Only log messages with the given severity or above. Valid levels: [debug, + # info, warn, error] + # log_level: "info" + + # Optionally log the source IPs. + # log_source_ips_enabled: false + + # Log all source IPs instead of only the originating one. Only used if + # server.log-source-ips-enabled is true + # log_source_ips_full: false + + # Header field storing the source IPs. Only used if + # server.log-source-ips-enabled is true. If not set the default Forwarded, + # X-Real-IP and X-Forwarded-For headers are used + # log_source_ips_header: "" + + # Regex for matching the source IPs. Only used if + # server.log-source-ips-enabled is true. If not set the default Forwarded, + # X-Real-IP and X-Forwarded-For headers are used + # log_source_ips_regex: "" + + # Optionally log request headers. + # log_request_headers: false + + # Optionally log requests at info level instead of debug level. Applies to + # request headers as well if server.log-request-headers is enabled. + # log_request_at_info_level_enabled: false + + # Comma separated list of headers to exclude from loggin. Only used if + # server.log-request-headers is true. + # log_request_exclude_headers_list: "" + + # Optionally add request headers to tracing spans. + # trace_request_headers: false + + # Comma separated list of headers to exclude from tracing spans. Only used if + # server.trace-request-headers is true. The following headers are always + # excluded: Authorization, Cookie, X-Access-Token, X-Csrf-Token, X-Grafana-Id. + # trace_request_exclude_headers_list: "" + + # Base path to serve all API routes from (e.g. /v1/) + # http_path_prefix: "" + + # Creates new traces for each call rather than continuing the existing trace. + # A span link is used to allow navigation to the parent trace. Only works when + # using Open-Telemetry tracing. + # create_new_traces: false + +metastore: + raft: + # Directory to store WAL and raft state. It must be a persistent directory, + # not a tmpfs or similar. + # dir: "./data/v2/metastore/raft" + + # Directory to store the data. + # data_dir: "./data/v2/metastore/data" + + # levels: 0 + + # cleanupbatchsize: 0 + + # cleanupdelay: 0s + + # cleanupjobminlevel: 0 + + # cleanupjobmaxlevel: 0 + +distributor: + # Timeout when pushing data to ingester. + # pushtimeout: 5s + + pool_config: + # How frequently to clean up clients for ingesters that have gone away. + # client_cleanup_period: 15s + + # Run a health check on each ingester client during periodic cleanup. + # health_check_ingesters: true + + # Timeout for ingester client healthcheck RPCs. + # remote_timeout: 5s + + ring: + kvstore: + # Backend storage to use for the ring. Supported values are: consul, etcd, + # inmemory, memberlist, multi. + # store: "memberlist" + + consul: + # Hostname and port of Consul. + # host: "localhost:8500" + + etcd: + # The etcd endpoints to connect to. + # endpoints: [] + + # Etcd username. + # username: "" + + # Etcd password. + # password: "" + + # List of network interface names to look up when finding the instance IP + # address. + # instance_interface_names: [] + +limits: + # Per-tenant ingestion rate limit in sample size per second. Units in MB. + # ingestion_rate_mb: 4 + + # Per-tenant allowed ingestion burst size (in sample size). Units in MB. The + # burst size refers to the per-distributor local rate limiter, and should be + # set at least to the maximum profile size expected in a single push request. + # ingestion_burst_size_mb: 2 + + # When a profile is sampled out, retain its totals and labels with stacktraces + # stripped (marked __sampled__) instead of dropping it. + # keep_stripped_profiles: false + + # Maximum length accepted for label names. + # max_label_name_length: 1024 + + # Maximum length accepted for label value. This setting also applies to the + # metric name. + # max_label_value_length: 2048 + + # Maximum number of label names per series. + # max_label_names_per_series: 30 + + # Maximum number of sessions per series. 0 to disable. + # max_sessions_per_series: 0 + + # Enforce labels order optimization. + # enforce_labels_order: false + + # Disable label name sanitization (converting dots to underscores). When + # disabled, labels with dots are accepted as-is using UTF-8 validation. + # disable_label_sanitization: true + + # Maximum number of series within a single batched push that are processed + # concurrently. 0 = unbounded (legacy behavior); 1 = serialize pushes (kill + # switch). + # push_max_concurrency: 256 + + # Maximum size of a profile in bytes. This is based off the uncompressed size. + # 0 to disable. + # max_profile_size_bytes: 4194304 + + # Maximum number of samples in a profile. 0 to disable. + # max_profile_stacktrace_samples: 16000 + + # Maximum number of labels in a profile sample. 0 to disable. + # max_profile_stacktrace_sample_labels: 100 + + # Maximum depth of a profile stacktrace. Profiles are not rejected instead + # stacktraces are truncated. 0 to disable. + # max_profile_stacktrace_depth: 1000 + + # Maximum length of a profile symbol value (labels, function names and + # filenames, etc...). Profiles are not rejected instead symbol values are + # truncated. 0 to disable. + # max_profile_symbol_value_length: 65535 + + # Duration of the distributor aggregation window. Requires aggregation period + # to be specified. 0 to disable. + # distributor_aggregation_window: 0s + + # Duration of the distributor aggregation period. Requires aggregation window + # to be specified. 0 to disable. + # distributor_aggregation_period: 0s + + # The tenant's shard size used by shuffle-sharding. Must be set both on + # ingesters and distributors. 0 disables shuffle sharding. + # ingestion_tenant_shard_size: 0 + + # [v1 storage only] Maximum number of active series of profiles per tenant, + # per ingester. 0 to disable. + # max_local_series_per_tenant: 0 + + # [v1 storage only] Maximum number of active series of profiles per tenant, + # across the cluster. 0 to disable. When the global limit is enabled, each + # ingester is configured with a dynamic local limit based on the replication + # factor and the current number of healthy ingesters, and is kept updated + # whenever the number of ingesters change. + # max_global_series_per_tenant: 5000 + + # Limit how far back in profiling data can be queried, up until lookback + # duration ago. This limit is enforced in the query frontend. If the requested + # time range is outside the allowed range, the request will not fail, but will + # be modified to only query data within the allowed time range. 0 to disable, + # default to 7d. + # max_query_lookback: 1w + + # The limit to length of queries. 0 to disable. + # max_query_length: 1d + + # Maximum number of queries that will be scheduled in parallel by the + # frontend. + # max_query_parallelism: 0 + + # Whether query analysis is enabled in the query frontend. If disabled, the + # /AnalyzeQuery endpoint will return an empty response. + # query_analysis_enabled: true + + # Whether the series portion of query analysis is enabled. If disabled, no + # series data (e.g., series count) will be calculated by the /AnalyzeQuery + # endpoint. + # query_analysis_series_enabled: false + + # Include profiles that were sampled out and stored with stacktraces stripped + # (marked __sampled__) in query results. + # include_stripped_profiles: false + + # Maximum number of flame graph nodes by default. 0 to disable. + # max_flamegraph_nodes_default: 8192 + + # Maximum number of flame graph nodes allowed. 0 to disable. + # max_flamegraph_nodes_max: 1048576 + + # The tenant's shard size, used when store-gateway sharding is enabled. Value + # of 0 disables shuffle sharding for the tenant, that is all tenant blocks are + # sharded across all store-gateway replicas. + # store_gateway_tenant_shard_size: 0 + + # Split queries by a time interval and execute in parallel. The value 0 + # disables splitting by time + # split_queries_by_interval: 0s + + # Whether profiles should be sanitized when merging. + # query_sanitize_on_merge: true + + # Maximum number of concurrent async queries per tenant. 0 to disable async + # queries. + # max_async_query_concurrency: 5 + + # [v1 storage only] Delete blocks containing samples older than the specified + # retention period. 0 to disable. + # compactor_blocks_retention_period: 0s + + # [v1 storage only] The number of shards to use when splitting blocks. 0 to + # disable splitting. + # compactor_split_and_merge_shards: 0 + + # [v1 storage only] Number of stages split shards will be written to. Number + # of output split shards is controlled by -compactor.split-and-merge-shards. + # compactor_split_and_merge_stage_size: 0 + + # [v1 storage only] Number of groups that blocks for splitting should be + # grouped into. Each group of blocks is then split separately. Number of + # output split shards is controlled by -compactor.split-and-merge-shards. + # compactor_split_groups: 1 + + # [v1 storage only] Max number of compactors that can compact blocks for + # single tenant. 0 to disable the limit and use all compactors. + # compactor_tenant_shard_size: 0 + + # [v1 storage only] If a partial block (unfinished block without meta.json + # file) hasn't been modified for this time, it will be marked for deletion. + # The minimum accepted value is 4h0m0s: a lower value will be ignored and the + # feature disabled. 0 to disable. + # compactor_partial_block_deletion_delay: 1d + + # [v1 storage only] If enabled, the compactor will downsample profiles in + # blocks at compaction level 3 and above. The original profiles are also kept. + # Note: This set the default for the teanant overrides, in order to be + # effective it also requires compactor.downsampler-enabled to be set to true. + # compactor_downsampler_enabled: true + + # S3 server-side encryption type. Required to enable server-side encryption + # overrides for a specific tenant. If not set, the default S3 client settings + # are used. + # s3_sse_type: "" + + # S3 server-side encryption KMS Key ID. Ignored if the SSE type override is + # not set. + # s3_sse_kms_key_id: "" + + # S3 server-side encryption KMS encryption context. If unset and the key ID + # override is set, the encryption context will not be provided to S3. Ignored + # if the SSE type override is not set. + # s3_sse_kms_encryption_context: "" + + # This limits how far into the past profiling data can be ingested. This limit + # is enforced in the distributor. 0 to disable, defaults to 1h. + # reject_older_than: 1h + + # This limits how far into the future profiling data can be ingested. This + # limit is enforced in the distributor. 0 to disable, defaults to 10m. + # reject_newer_than: 10m + + # Maximum number of recording rules a tenant can create. 0 to disable. + # max_recording_rules: 25 + +segment_writer: + lifecycler: + ring: + kvstore: + # Backend storage to use for the ring. Supported values are: consul, + # etcd, inmemory, memberlist, multi. + # store: "consul" + + consul: + # Hostname and port of Consul. + # host: "localhost:8500" + + etcd: + # The etcd endpoints to connect to. + # endpoints: [] + + # Etcd username. + # username: "" + + # Etcd password. + # password: "" + + # The number of ingesters to write to and read from. + # replication_factor: 3 + + # True to enable the zone-awareness and replicate ingested samples across + # different availability zones. + # zone_awareness_enabled: false + + # Name of network interface to read address from. + # interface_names: [] + + # File path where tokens are stored. If empty, tokens are not stored at + # shutdown and restored at startup. + # tokens_file_path: "" + + # The availability zone where this instance is running. + # availability_zone: "" + +memberlist: + # Gossip address to advertise to other members in the cluster. Used for NAT + # traversal. + # advertise_addr: "" + + # Gossip port to advertise to other members in the cluster. Used for NAT + # traversal. + # advertise_port: 7946 + + # Other cluster members to join. Can be specified multiple times or as a + # comma-separated list. It can be an IP, hostname or an entry specified in the + # DNS Service Discovery format. + # join_members: 0 + + # Abort if this node fails to join memberlist cluster at startup. When + # enabled, it's not guaranteed that other services are started only after the + # cluster state has been successfully updated; use 'abort-if-fast-join-fails' + # instead. + # abort_if_cluster_join_fails: false + + # IP address to listen on for gossip messages. Multiple addresses may be + # specified. Defaults to 0.0.0.0 + # bind_addr: [] + + # Port to listen on for gossip messages. + # bind_port: 7946 + +pyroscopedb: + # [v1 storage only] Directory used for local storage. + # data_path: "./data" + + # [v1 storage only] Upper limit to the duration of a Pyroscope block. + # max_block_duration: 1h + + # [v1 storage only] How big should a single row group be uncompressed + # row_group_target_size: 1342177280 + + # [v1 storage only] Specifies the dimension by which symbols are partitioned. + # By default, the partitioning is determined automatically. + # symbols_partition_label: "" + + # [v1 storage only] How much available disk space to keep in GiB + # min_free_disk_gb: 10 + + # [v1 storage only] Which percentage of free disk space to keep + # min_disk_available_percentage: 0.05 + + # [v1 storage only] How often to enforce disk retention + # enforcement_interval: 5m + + # [v1 storage only] Disable retention policy enforcement + # disable_enforcement: false + +tracing: + # Set to false to disable tracing. + # enabled: true + +overrides_exporter: + ring: + kvstore: + # Backend storage to use for the ring. Supported values are: consul, etcd, + # inmemory, memberlist, multi. + # store: "memberlist" + + consul: + # Hostname and port of Consul. + # host: "localhost:8500" + + etcd: + # The etcd endpoints to connect to. + # endpoints: [] + + # Etcd username. + # username: "" + + # Etcd password. + # password: "" + + # List of network interface names to look up when finding the instance IP + # address. + # instance_interface_names: [] + +runtime_config: + # Comma separated list of yaml files or URLs with the configuration that can + # be updated at runtime. Runtime config files will be merged from left to + # right. + # file: "" + +storage: + # Backend storage to use. Supported backends are: s3, gcs, azure, swift, + # filesystem, cos. + # backend: "filesystem" + + s3: + # The S3 bucket endpoint. It could be an AWS S3 endpoint listed at + # https://docs.aws.amazon.com/general/latest/gr/s3.html or the address of an + # S3-compatible service in hostname:port format. + # endpoint: "" + + # S3 region. If unset, the client will issue a S3 GetBucketLocation API call + # to autodetect it. + # region: "" + + # S3 bucket name + # bucket_name: "" + + # S3 secret access key + # secret_access_key: "" + + # S3 access key ID + # access_key_id: "" + + sse: + # Enable AWS Server Side Encryption. Supported values: SSE-KMS, SSE-S3. + # type: "" + + # KMS Key ID used to encrypt objects in S3 + # kms_key_id: "" + + # KMS Encryption Context used for object encryption. It expects JSON + # formatted string. + # kms_encryption_context: "" + + gcs: + # GCS bucket name + # bucket_name: "" + + # JSON either from a Google Developers Console client_credentials.json file, + # or a Google Developers service account key. Needs to be valid JSON, not a + # filesystem path. If empty, fallback to Google default logic: + # 1. A JSON file whose path is specified by the + # GOOGLE_APPLICATION_CREDENTIALS environment variable. For workload identity + # federation, refer to + # https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation + # on how to generate the JSON configuration file for on-prem/non-Google + # cloud platforms. + # 2. A JSON file in a location known to the gcloud command-line tool: + # $HOME/.config/gcloud/application_default_credentials.json. + # 3. On Google Compute Engine it fetches credentials from the metadata + # server. + # service_account: "" + + azure: + # Azure Active Directory tenant ID. If set alongside `client-id` and + # `client-secret`, these values will be used for authentication via a client + # secret credential. + # az_tenant_id: "" + + # Azure Active Directory client ID. If set alongside `az-tenant-id` and + # `client-secret`, these values will be used for authentication via a client + # secret credential. + # client_id: "" + + # Azure Active Directory client secret. If set alongside `az-tenant-id` and + # `client-id`, these values will be used for authentication via a client + # secret credential. + # client_secret: "" + + # Azure storage account name + # account_name: "" + + # Azure storage account key. If unset, Azure managed identities will be used + # for authentication instead. + # account_key: "" + + # If `connection-string` is set, the value of `endpoint-suffix` will not be + # used. Use this method over `account-key` if you need to authenticate via a + # SAS token. Or if you use the Azurite emulator. + # connection_string: "" + + # Azure storage container name + # container_name: "" + + # Azure storage endpoint suffix without schema. The account name will be + # prefixed to this value to create the FQDN. If set to empty string, default + # endpoint suffix is used. + # endpoint_suffix: "" + + swift: + # OpenStack Swift authentication API version. 0 to autodetect. + # auth_version: 0 + + # OpenStack Swift authentication URL + # auth_url: "" + + # OpenStack Swift username. + # username: "" + + # OpenStack Swift user's domain name. + # user_domain_name: "" + + # OpenStack Swift user's domain ID. + # user_domain_id: "" + + # OpenStack Swift user ID. + # user_id: "" + + # OpenStack Swift API key. + # password: "" + + # OpenStack Swift user's domain ID. + # domain_id: "" + + # OpenStack Swift user's domain name. + # domain_name: "" + + # OpenStack Swift project ID (v2,v3 auth only). + # project_id: "" + + # OpenStack Swift project name (v2,v3 auth only). + # project_name: "" + + # ID of the OpenStack Swift project's domain (v3 auth only), only needed if + # it differs the from user domain. + # project_domain_id: "" + + # Name of the OpenStack Swift project's domain (v3 auth only), only needed + # if it differs from the user domain. + # project_domain_name: "" + + # OpenStack Swift Region to use (v2,v3 auth only). + # region_name: "" + + # Name of the OpenStack Swift container to put chunks in. + # container_name: "" + + cos: + # COS bucket name + # bucket: "" + + # COS region name + # region: "" + + # COS app id + # app_id: "" + + # COS storage endpoint + # endpoint: "" + + # COS secret key + # secret_key: "" + + # COS secret id + # secret_id: "" + + filesystem: + # Local filesystem storage directory. + # dir: "./data/v2/shared" + + # Prefix for all objects stored in the backend storage. For simplicity, it may + # only contain digits and English alphabet characters, hyphens, underscores, + # dots and forward slashes. + # prefix: "" + +self_profiling: + # When running in single binary (--target=all) Pyroscope will push (Go SDK) + # profiles to itself. Set to true to disable self-profiling. + # disable_push: false + + # mutex_profile_fraction: 5 + + # block_profile_rate: 5 + + # Read k6 labels from request headers and set them as dynamic profile tags. + # use_k6_middleware: false + + # Tenant ID for self-profiling data. If empty, no tenant header is sent + # (anonymous). + # tenant_id: "" + +# When set to true, incoming HTTP requests must specify tenant ID in HTTP +# X-Scope-OrgId header. When set to false, tenant ID anonymous is used instead. +# multitenancy_enabled: false + +analytics: + # Enable anonymous usage statistics collection. For more details about usage + # statistics, refer to + # https://grafana.com/docs/pyroscope/latest/configure-server/anonymous-usage-statistics-reporting/ + # reporting_enabled: true + +# Prints the application banner at startup. +# show_banner: true + +# Wait time before shutting down after a termination signal. +# shutdown_delay: 0s + +# Storage architecture layer. Use 'v1' to use legacy ingester-based storage, +# 'v2' for new storage, and 'v1-v2-dual' to use new storage while being able to +# query old data. +# architecture_storage: "v1-v2-dual" + +admin_server: + # Controls the admin server for metrics, pprof and admin endpoints. + # 'disabled': all routes on the main port (default). 'additional': admin + # server started, operational routes served on both ports. 'exclusive': admin + # server started, operational routes removed from main port. + # mode: "disabled" + + # Address for the admin HTTP server. Defaults to localhost so the port is not + # exposed externally. Use :: or 0.0.0.0 to listen on all interfaces. + # http_listen_address: "localhost" + + # Port for the admin HTTP server (metrics, pprof, admin). + # http_listen_port: 4042 + +embedded_grafana: + # The directory where the Grafana data will be stored. + # data_path: "./data/__embedded_grafana/" + + # The port on which the Grafana will listen. + # listen_port: 4041 + + # The URL of the Pyroscope instance to use for the Grafana datasources. + # pyroscope_url: "http://localhost:4040" diff --git a/cypress.config.ts b/cypress.config.ts deleted file mode 100644 index 03861ab029..0000000000 --- a/cypress.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - e2e: { - baseUrl: 'http://localhost:4040', - video: false, - }, -}); diff --git a/cypress/ci-base-path.ts b/cypress/ci-base-path.ts deleted file mode 100644 index cf11dae349..0000000000 --- a/cypress/ci-base-path.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - e2e: { - baseUrl: 'http://localhost:8080/foobar/', - env: { - apiBasePath: '/foobar', - }, - video: false, - }, -}); diff --git a/cypress/ci.ts b/cypress/ci.ts deleted file mode 100644 index f0a94bc050..0000000000 --- a/cypress/ci.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - e2e: { - baseUrl: 'http://localhost:4040/ui/', - video: false, - }, -}); diff --git a/cypress/e2e/smoke.cy.ts b/cypress/e2e/smoke.cy.ts deleted file mode 100644 index 9756ceccfb..0000000000 --- a/cypress/e2e/smoke.cy.ts +++ /dev/null @@ -1,59 +0,0 @@ -// / -describe('smoke', () => { - beforeEach(function () { - const apiBasePath = Cypress.env('apiBasePath') || ''; - - cy.intercept(`${apiBasePath}/querier.v1.QuerierService/LabelNames`, { - fixture: 'profileTypes.json', - }).as('profileTypes'); - }); - - it('loads admin page', () => { - cy.visit('/admin'); - }); - - it('loads single view (/)', () => { - cy.visit('/'); - cy.wait(`@profileTypes`); - }); - - it('loads comparison view (/comparison)', () => { - cy.visit('/comparison'); - cy.wait(`@profileTypes`); - }); - - it('loads diff view (/comparison-diff)', () => { - cy.visit('/comparison-diff'); - cy.wait(`@profileTypes`); - }); - - it('changes path when navigating', () => { - const clickSidebar = (name: string) => { - cy.get('nav.pro-menu .pro-item-content') - .filter(`:contains("${name}")`) - .parent() - .parent() - .click(); - }; - - cy.visit('/'); - cy.url().should('contain', '/'); - cy.title().should('include', 'Single'); - - clickSidebar('Comparison View'); - cy.url().should('contain', '/comparison'); - cy.title().should('include', 'Comparison'); - - clickSidebar('Diff View'); - cy.url().should('contain', '/comparison-diff'); - cy.title().should('include', 'Diff'); - - clickSidebar('Tag Explorer'); - cy.url().should('contain', '/explore'); - cy.title().should('include', 'Tag Explorer'); - - clickSidebar('Single'); - cy.url().should('contain', '/'); - cy.title().should('include', 'Single'); - }); -}); diff --git a/cypress/fixtures/profileTypes.json b/cypress/fixtures/profileTypes.json deleted file mode 100644 index 43ad4b78d2..0000000000 --- a/cypress/fixtures/profileTypes.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "memory:alloc_objects:count::", - "memory:alloc_space:bytes::", - "memory:inuse_objects:count::", - "memory:inuse_space:bytes::", - "process_cpu:cpu:nanoseconds:cpu:nanoseconds" -] diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts deleted file mode 100644 index 96a86d12c1..0000000000 --- a/cypress/support/commands.ts +++ /dev/null @@ -1,38 +0,0 @@ -/// -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -// -// declare global { -// namespace Cypress { -// interface Chainable { -// login(email: string, password: string): Chainable -// drag(subject: string, options?: Partial): Chainable -// dismiss(subject: string, options?: Partial): Chainable -// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable -// } -// } -// } -import '@testing-library/cypress/add-commands'; diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts deleted file mode 100644 index 598ab5f0d7..0000000000 --- a/cypress/support/e2e.ts +++ /dev/null @@ -1,20 +0,0 @@ -// *********************************************************** -// This example support/e2e.ts is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands'; - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json deleted file mode 100644 index 0ca312fddc..0000000000 --- a/cypress/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "target": "es2015", - "lib": ["es2015", "dom"], - "types": ["cypress", "@testing-library/cypress"] - }, - "include": ["**/*.ts"] -} diff --git a/docs/Makefile b/docs/Makefile index 272be1340f..dfefedeea2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -10,4 +10,4 @@ include docs.mk .PHONY: test test: - docker run -v $(CURDIR)/sources:/hugo/content/docs/phlare/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'exec make hugo' + docker run -v $(CURDIR)/sources:/hugo/content/docs/pyroscope/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'exec make hugo' diff --git a/docs/docs.mk b/docs/docs.mk index c0aae10ba5..d23c8fe589 100644 --- a/docs/docs.mk +++ b/docs/docs.mk @@ -31,9 +31,6 @@ ifeq ($(PROJECTS),) $(error "PROJECTS variable must be defined in variables.mk") endif -# First project is considered the primary one used for doc-validator. -PRIMARY_PROJECT := $(subst /,-,$(firstword $(subst :, ,$(firstword $(PROJECTS))))) - # Host port to publish container port to. ifeq ($(origin DOCS_HOST_PORT), undefined) export DOCS_HOST_PORT := 3002 @@ -44,12 +41,7 @@ ifeq ($(origin DOCS_IMAGE), undefined) export DOCS_IMAGE := grafana/docs-base:latest endif -# Container image used for doc-validator linting. -ifeq ($(origin DOC_VALIDATOR_IMAGE), undefined) -export DOC_VALIDATOR_IMAGE := grafana/doc-validator:latest -endif - -# Container image used for vale linting. +# Container image used for Vale linting. ifeq ($(origin VALE_IMAGE), undefined) export VALE_IMAGE := grafana/vale:latest endif @@ -97,15 +89,7 @@ endif .PHONY: docs-debug docs-debug: ## Run Hugo web server with debugging enabled. TODO: support all SERVER_FLAGS defined in website Makefile. docs-debug: make-docs - WEBSITE_EXEC='hugo server --bind 0.0.0.0 --port 3002 --debug' $(CURDIR)/make-docs $(PROJECTS) - -.PHONY: doc-validator -doc-validator: ## Run doc-validator on the entire docs folder which includes pulling the latest `DOC_VALIDATOR_IMAGE` (default: `grafana/doc-validator:latest`) container image. To not pull the image, set `PULL=false`. -doc-validator: make-docs -ifeq ($(PULL), true) - $(PODMAN) pull -q $(DOC_VALIDATOR_IMAGE) -endif - DOCS_IMAGE=$(DOC_VALIDATOR_IMAGE) $(CURDIR)/make-docs $(PROJECTS) + WEBSITE_EXEC='hugo server --bind 0.0.0.0 --port 3002 --logLevel debug' $(CURDIR)/make-docs $(PROJECTS) .PHONY: vale vale: ## Run vale on the entire docs folder which includes pulling the latest `VALE_IMAGE` (default: `grafana/vale:latest`) container image. To not pull the image, set `PULL=false`. @@ -120,3 +104,12 @@ update: ## Fetch the latest version of this Makefile and the `make-docs` script curl -s -LO https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/docs.mk curl -s -LO https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/make-docs chmod +x make-docs + +# ls static/templates/ | sed 's/-template\.md//' | xargs +TOPIC_TYPES := concept multiple-tasks reference section task tutorial visualization +.PHONY: $(patsubst %,topic/%,$(TOPIC_TYPES)) +topic/%: ## Create a topic from the Writers' Toolkit template. Specify the topic type as the target, for example, `make topic/task TOPIC_PATH=sources/my-new-topic.md`. +$(patsubst %,topic/%,$(TOPIC_TYPES)): + $(if $(TOPIC_PATH),,$(error "You must set the TOPIC_PATH variable to the path where the $(@F) topic will be created. For example: make $(@) TOPIC_PATH=sources/my-new-topic.md")) + mkdir -p $(dir $(TOPIC_PATH)) + curl -s -o $(TOPIC_PATH) https://raw.githubusercontent.com/grafana/writers-toolkit/refs/heads/main/docs/static/templates/$(@F)-template.md diff --git a/docs/internal/RELEASE.md b/docs/internal/RELEASE.md index a3c6ed82ee..b59810f570 100644 --- a/docs/internal/RELEASE.md +++ b/docs/internal/RELEASE.md @@ -2,47 +2,109 @@ ## Automatic Release Process -To release a new version of the project you need to follow the following steps: - -1. Create a new branch for the release (e.g., `release/vX.Y`) -2. Create the tag for the release (e.g., `vX.Y.Z`) -3. Push the release branch and tag to the remote -4. Create a GitHub label for backports: +### GitHub Release + +1. Check for open security PRs from Dependabot or Renovate. Review and merge any applicable security fixes to avoid shipping known vulnerabilities. +2. Create a new branch for the release (e.g., `release/vX.Y`). + > [!IMPORTANT] + > The release branch should only contain the major (X) and minor (Y) version, but not the patch level (Z), for example: + > + > ✅ Correct: `release/v1.3` + > + > ⚠️ Incorrect: `release/v1.3.0` +3. Update `renovate.json` so `baseBranchPatterns` includes the new release branch and only the latest two release branches. +4. Create a signed tag for the release using the version as the tag message (e.g., `git tag -s "vX.Y.Z" -m "vX.Y.Z"`) +5. Push the release branch and tag to the remote. Note that the tag will kick off a release workflow via [goreleaser](https://github.com/grafana/pyroscope/actions/workflows/release.yml). +6. Create a GitHub label for backports: ```gh label create "backport release/vX.Y" -d "This label will backport a merged PR to the release/vX.Y branch" -c "#0052cc"``` -> [!IMPORTANT] -> The release branch should only contain the major (X) and minor (Y) version, but not the patch level (Z), for example: -> -> ✅ Correct: `release/v1.3` -> -> ⚠️ Incorrect: `release/v1.3.0` +The CI will automatically handle the build and then create and publish a new GitHub release. +Please do not delete GitHub releases that were once public. -The CI will automatically handle the build and create a draft GitHub release. +#### GitHub Release Notes -Once ready, you can edit and publish the draft release on GitHub. You will need to take the release notes and append them to the `CHANGELOG.md` file in the root of the repository. +Once the release is published, you should edit the release notes in GitHub. Use the already generated changelog and summarize it in the main categories: +- Features and enhancements +- (optional) Breaking changes +- Bug fixes +- Documentation updates -The list of changes from the CHANGELOG.md file form the basis of the public-facing release notes. Release notes are added to the [public Pyroscope documentation](https://grafana.com/docs/pyroscope/latest/release-notes/). These release notes follow the same pattern for each release: +Keep the generated changelog as is, after the summary sections. -1. Copy the previous release's page (i.e., V1-3.md) to the new release number. Change the version information and page weight in the file's frontmatter. -2. Update the page title (Version x.x release notes) and add a few sentences about the main updates in the release. -3. Features and enhancements section with list of updates -4. (optional) Breaking changes section with a list of these changes and their impact (this section can also be used to update the [Upgrade page](https://grafana.com/docs/pyroscope/latest/upgrade-guide/)). -5. Bug fixes section with a list of updates. -6. Documentation updates section with a list of updates. +Make sure each release note has full links to the relevant pull requests. -For help writing release notes, refer to the [Writers' Toolkit](https://grafana.com/docs/writers-toolkit/write/). +### Homebrew -Please do not delete GitHub releases that were once public. +For releases that publish the `latest` tag (`IMAGE_PUBLISH_LATEST=true`), the release workflow dispatches the [`update-homebrew-formulas`](../../.github/workflows/update-homebrew-formulas.yml) workflow, which regenerates the Homebrew formulas and opens a pull request against [grafana/homebrew-pyroscope](https://github.com/grafana/homebrew-pyroscope). The tap's ruleset requires verified commit signatures and reviewed PRs on `main`, so the workflow creates the commit through the GitHub API (which signs it on behalf of the app) and opens a PR instead of pushing to `main`. **A maintainer must review and merge that PR to publish the new version via `brew`.** This step does not block the rest of the release; the binaries, container images, and GitHub release are published regardless. + +If the formula update needs to be re-run (for example, the release run failed after publishing), dispatch `update-homebrew-formulas` manually with the release tag as input. + +### Website Release Notes + +The list of changes from the GitHub release forms the basis of the public-facing release notes. +Release notes are added to the [public Pyroscope documentation](https://grafana.com/docs/pyroscope/latest/release-notes/). + +#### GitHub Workflow + +The website release notes need to be added to both the `release/vX.Y` branch and the main branch. The recommended workflow is to: +1. Add the changes with a PR against the main branch +2. Add a [backport](#backport) label and a `type/docs` label to the PR +3. Address feedback from reviewers and merge the PR + +#### Writing Website Release Notes + +The release notes follow the same pattern for each release: +1. Copy the previous release's page (i.e., V1-3.md) to the new release number. Change the version information and [page weight](https://grafana.com/docs/writers-toolkit/write/front-matter/#weight) in the file's frontmatter. +2. Update the page title (Version X.Y release notes) and add a few sentences about the main updates in the release. +3. Copy over the summary sections from the GitHub release notes. Make sure to use full links to the relevant pull requests. + +For help writing release notes, refer to the [Writers' Toolkit](https://grafana.com/docs/writers-toolkit/write/). -To release a minor version simply merge fixes to the release branch then create and push a new tag. (e.g. `v0.x.1`) +### Helm Chart Update -> For helm charts, you need to merge a PR that bumps the chart version in the main branch (no tagging required), the ci will automatically publish the chart to the [helm repository](https://grafana.github.io/helm-charts). +Merge a PR that bumps the chart version and updates the appVersion to the latest release Pyroscope in the main branch (no tagging required), the CI will automatically publish the chart to the [helm repository](https://grafana.github.io/helm-charts). + +#### Helm Chart Versioning + +The Helm chart version and Pyroscope application version are **separate and won't always match**. The `Chart.yaml` file contains two distinct version fields: +- `version`: The Helm chart version +- `appVersion`: The Pyroscope application version + +**Versioning Strategy:** +- We aim for a **best effort match** between chart version and Pyroscope version when releasing new Pyroscope versions +- Changes that **only affect the Helm chart** (templates, values, chart configuration) should be released as **patch releases of the chart only**, without requiring a new Pyroscope release +- Example: If the current chart is `v1.10.2` (with `appVersion: v1.10.2`), a chart-only fix would bump to `v1.10.3` while keeping `appVersion: v1.10.2` + +## Backport + +A PR to be backported must have the appropriate `backport release/vX.Y` label(s). Backport PRs are created automatically when the labeled PR is merged, or when the label is added to an already-merged PR. + +[Example backport PR](https://github.com/grafana/pyroscope/pull/4352) + +## Patch Releases + +When a patch release is needed, make PRs containing the necessary changes against the appropriate `release/vX.Y` branch. + +Changes done in patch releases should be documented in the existing website release notes for that version under a new heading with +the version number. These documentation changes should be done with a PR against the appropriate release branch and then [backported](#backport) to the main branch. + +Before tagging, check for open security PRs from Dependabot or Renovate. Review, merge, and backport any applicable security fixes to the `release/vX.Y` branch. + +Once the release notes are merged, a signed `vX.Y.Z` patch release tag must be created using the version as the tag message and pushed to remote to create a new release. + +> [!WARNING] +> If you are releasing a patch version, for an older major/minor version (example: +> you are releasing `v1.15.2`, but the current latest release is `v1.16.0`), +> you need to make sure the release's actions to publish a `:latest` docker +> image tag and a `home-brew` formula are removed: +> +> This can be done by updating `release.yml` in the previous release branches to set `$IMAGE_PUBLISH_LATEST=false`. ## Manual Release Process The release process uses [goreleaser](https://goreleaser.com/scm/github/?h=github#github) and can be configured -using the [.goreleaser.yml](./.goreleaser.yml). +using the [.goreleaser.yaml](./.goreleaser.yaml). To create a new release first prepare the release using: @@ -52,10 +114,10 @@ make release/prepare This will build and packages all artifacts without pushing or creating the GitHub release. -Once you're ready you can then tag your release. +Once you're ready you can then create a signed tag for your release. ```bash -git tag v0.1.0 +git tag -s "v0.1.0" -m "v0.1.0" ``` And finally push the release using: @@ -66,4 +128,4 @@ make release > Make sure to have a [GitHub Token](https://goreleaser.com/scm/github/?h=github#github) `GITHUB_TOKEN` correctly set. -Make sure to create the release notes and CHANGELOG for any manual release. +Make sure to create the release notes and CHANGELOG for any manual release. diff --git a/docs/internal/V2-MIGRATION.md b/docs/internal/V2-MIGRATION.md new file mode 100644 index 0000000000..77665965c5 --- /dev/null +++ b/docs/internal/V2-MIGRATION.md @@ -0,0 +1,99 @@ +# Migration v1 to v2 + +## Single binary + +### First deploy v1 + +- Note: Needs persistence enabled otherwise data will be lost after restart + +``` +helm upgrade \ + pyroscope \ + ./operations/pyroscope/helm/pyroscope \ + --install \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=false \ + --set pyroscope.persistence.enabled=true +``` + +### Step: 2: Deploy v2 and enable dual ingest + +- Note: The python command will switch to the v2 read path for data ingested 10 minutes after it is run. + +``` +helm upgrade \ + pyroscope \ + ./operations/pyroscope/helm/pyroscope \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=true \ + --set pyroscope.persistence.enabled=true \ + --set architecture.storage.migration.queryBackendFrom=$(python3 -c "import datetime; print((datetime.datetime.now(datetime.UTC)+ datetime.timedelta(minutes = 10)).strftime('%Y-%m-%dT%H:%M:%SZ'))") +``` + +### Step 3: Remove v1 components + +Once data before Step 2 is no longer relevant, we can get rid of the v1 components. This will loose all data before Step 2. + +``` +helm upgrade \ + pyroscope \ + ./operations/pyroscope/helm/pyroscope \ + --set architecture.storage.v1=false \ + --set architecture.storage.v2=true \ + --set pyroscope.persistence.enabled=true +``` + + +## Micro-Services + +### First deploy v1 + +- Note: Needs persistence enabled otherwise data will be lost after restart +- Note: `--set architecture.overwriteResources.requests.cpu=10m` allow this to be tested without allocation many resources, this should not be used in production + + +``` +helm upgrade \ + pyroscope \ + ./operations/pyroscope/helm/pyroscope \ + --install \ + --set architecture.microservices.enabled=true \ + --set architecture.overwriteResources.requests.cpu=10m \ + --set minio.enabled=true \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=false \ + --set pyroscope.persistence.enabled=true +``` + +### Step: 2: Deploy v2 and enable dual ingest + +- Note: The python command will switch to the v2 read path for data ingested 10 minutes after it is run. + +``` +helm upgrade \ + pyroscope \ + ./operations/pyroscope/helm/pyroscope \ + --set architecture.microservices.enabled=true \ + --set architecture.overwriteResources.requests.cpu=10m \ + --set minio.enabled=true \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=true \ + --set pyroscope.persistence.enabled=true \ + --set architecture.storage.migration.queryBackendFrom=$(python3 -c "import datetime; print((datetime.datetime.now(datetime.UTC)+ datetime.timedelta(minutes = 10)).strftime('%Y-%m-%dT%H:%M:%SZ'))") +``` + + +### Step 3: Remove v1 components + +Once data before Step 2 is no longer relevant, we can get rid of the v1 components. This will loose all data before Step 2. + +``` +helm upgrade \ + pyroscope \ + ./operations/pyroscope/helm/pyroscope \ + --set architecture.microservices.enabled=true \ + --set minio.enabled=true \ + --set architecture.storage.v1=false \ + --set architecture.storage.v2=true \ + --set pyroscope.persistence.enabled=true + diff --git a/docs/internal/contributing/README.md b/docs/internal/contributing/README.md index 44192cf4fe..486ef4dcbd 100644 --- a/docs/internal/contributing/README.md +++ b/docs/internal/contributing/README.md @@ -15,11 +15,18 @@ a piece of work is finished it should: - Have unit for new functionality or tests that would have caught the bug being fixed. - If you have made any changes to flags, configs and/or protobuf definitions, run `make generate` and commit the changed files. +### Use signed commits in PRs + +Effective June 22, 2026, all Grafana Labs repositories, including Pyroscope, [require signed commits](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-signed-commits). +To learn how to enable commit verification, refer to [about commit signature verification](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) and this page to learn about [checking your commit signature verification status](https://docs.github.com/en/authentication/troubleshooting-commit-signature-verification/checking-your-commit-and-tag-signature-verification-status). + +**NOTE** Unsigned commits and pull requests will be rejected and closed. This includes pull requests that have been authored by Agents. + ## Requirement To be able to run make targets you'll need to install: -- [Go](https://go.dev/doc/install) (> 1.19) +- [Go](https://go.dev/doc/install) (>= 1.25, see `go.mod`) - [Docker](https://docs.docker.com/engine/install/) All other required tools will be automatically downloaded `$(pwd)/.tmp/bin`. @@ -66,61 +73,54 @@ make GOOS=linux GOARCH=amd64 docker-image/pyroscope/build make IMAGE_PLATFORM=linux/arm64 GOOS=linux GOARCH=arm64 docker-image/pyroscope/build ``` -#### Apple arm64 builds (M1/M2 chips) - -If you encounter errors during the installation of the node packages due to missing arm64 build of `canvas`: - -``` -brew install pkg-config cairo pango libpng jpeg giflib librsvg -``` - -See https://github.com/Automattic/node-canvas/issues/1662 - #### Running examples locally replace `image: grafana/pyroscope` with the local tag name you got from docker-image/pyroscope/build (i.e): ``` pyroscope: - image: us.gcr.io/kubernetes-dev/pyroscope:main-470125e1-WIP + image: grafana/pyroscope:main-470125e1-WIP ports: - '4040:4040' ``` -#### Front end development +#### Run with Pyroscope with embedded Grafana + Profiles Drilldown -**Versions for development tools**: -- Node v18 -- Yarn v1.22 +To quickly test the whole stack it is possible to run an embedded Grafana by using the target parameter: -The front end code is all located in the `public/app` directory, although its `plugin.json` -file exists at the repository root. - -To run the local front end source code: -```sh -yarn -yarn dev ``` +go run ./cmd/pyroscope --target all,embedded-grafana +``` + +This will Pyroscope on `:4040` and the embedded Grafana on port `:4041`. + +#### Frontend development + +The frontend application is not in active development. While the UI it provides is usable and stable, +the recommended way to view and analyze profiling data is to use the +[Profiles Drilldown](https://grafana.com/docs/grafana/latest/visualizations/simplified-exploration/profiles/) Grafana app (pre-installed in recent Grafana versions). -This will install / update front end dependencies and launch a process that will build -the front end code, launch a pyroscope web app service at `http://localhost:4041`, -and keep that web app updated any time you save the front end source code. -The resulting web app will not initially be connected to a pyroscope server, -so all attempts to fetch data will fail. +If you do need to make changes to the frontend code, the following instructions should get you started. + +The web UI lives in the `ui/` directory and is a dependency-minimal rewrite (React + Vite + TypeScript) +of the older `public/app` UI. See [`ui/CLAUDE.md`](../../../ui/CLAUDE.md) and +[`ui/DESIGN.md`](../../../ui/DESIGN.md) for the authoritative frontend guide. + +The frontend uses **Yarn 4 (Berry)** and its `package.json` lives in `ui/` (not at the repository root). +To run it in development mode: -To launch a pyroscope server for development purposes: ```sh -yarn backend:dev +cd ui +yarn install +yarn dev ``` -This yarn script actually runs the following: +This serves the app at `http://localhost:5173` and proxies API requests to a Pyroscope server at +`http://localhost:4040`. In a separate terminal, start a server for it to talk to, for example: + ```sh -make build run 'PARAMS=--config.file ./cmd/pyroscope/pyroscope.yaml' +go run ./cmd/pyroscope ``` -It will take a while for this process to build and start serving pyroscope data, but -once it is fully active, the pyroscope web app service at `http://localhost:4041` -will be able to interact with it. - ### Dependency management We use [Go modules](https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more) to manage dependencies on external packages. @@ -148,6 +148,6 @@ Commit the changes to `go.mod` and `go.sum` before submitting your pull request. The Grafana Pyroscope documentation is compiled into a website published at [grafana.com](https://grafana.com/). -To start the website locally you can use `make docs/docs` and follow console instructions to access the website. +To start the website locally you can use `make docs/docs`. The command will print instructions on how to access the website. Note: if you attempt to view pages on GitHub, it's likely that you might find broken links or pages. That is expected and should not be addressed unless it is causing issues with the site that occur as part of the build. diff --git a/docs/make-docs b/docs/make-docs index f531df2ebb..7c8efd4513 100755 --- a/docs/make-docs +++ b/docs/make-docs @@ -1,4 +1,6 @@ #!/bin/sh +# shellcheck disable=SC2034 +# # The source of this file is https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/make-docs. # # `make-docs` procedure changelog # @@ -6,6 +8,86 @@ # [Semantic versioning](https://semver.org/) is used to help the reader identify the significance of changes. # Changes are relevant to this script and the support docs.mk GNU Make interface. # +# ## 10.1.0 (2025-11-11) +# +# ### Fixed +# +# - Extend readiness probes to prevent confusing output. +# +# Before, the probes could fail too soon and long an error message which contradicted the service starting up. +# +# ## 10.0.0 (2025-10-13) +# +# ### Changed +# +# - Hugo no longer supports the `--debug` option, use `--logLevel debug` instead. +# +# Thank you to @karlskewes for their contribution! +# +# ## 9.0.0 (2025-04-05) +# +# ### Removed +# +# - doc-validator target and associated scripts. +# +# Most useful rules have been migrated to Vale and the others are often false positives. +# +# ## 8.5.2 (2025-02-28) +# +# ### Fixed +# +# - topic/ targets are no longer no-ops as a result of 8.5.1. +# +# ## 8.5.1 (2025-02-18) +# +# ### Fixed +# +# - PHONY declaration for topic/ targets. +# +# ## 8.5.0 (2025-02-13) +# +# ### Added +# +# - make topic/ TOPIC_PATH= target to create a new topic from the Writers' Toolkit templates. +# +# ## 8.4.0 (2025-01-27) +# +# ### Fixed +# +# - Correct mount for the /docs/grafana-cloud/send-data/fleet-management/ project. +# +# ## 8.3.0 (2024-12-27) +# +# ### Added +# +# - Debug output of the final command when DEBUG=true. +# +# Useful to inspect if the script is correctly constructing the final command. +# +# ## 8.2.0 (2024-12-22) +# +# ### Removed +# +# - Special cases for Oracle and Datadog plugins now that they exist in the plugins monorepo. +# +# ## 8.1.0 (2024-08-22) +# +# ### Added +# +# - Additional website mounts for projects that use the website repository. +# +# Mounts are required for `make docs` to work in the website repository or with the website project. +# The Makefile is also mounted for convenient development of the procedure in that repository. +# +# ## 8.0.1 (2024-07-01) +# +# ### Fixed +# +# - Update log suppression to catch new format of website /docs/ homepage REF_NOT_FOUND warnings. +# +# These warnings are related to missing some pages during the build that are required for the /docs/ homepage. +# They were previously suppressed but the log format changed and without this change they reappear in the latest builds. +# # ## 8.0.0 (2024-05-28) # # ### Changed @@ -272,6 +354,7 @@ PODMAN="$(if command -v podman >/dev/null 2>&1; then echo podman; else echo dock if ! command -v curl >/dev/null 2>&1; then if ! command -v wget >/dev/null 2>&1; then + # shellcheck disable=SC2016 errr 'either `curl` or `wget` must be installed for this script to work.' exit 1 @@ -279,6 +362,7 @@ if ! command -v curl >/dev/null 2>&1; then fi if ! command -v "${PODMAN}" >/dev/null 2>&1; then + # shellcheck disable=SC2016 errr 'either `podman` or `docker` must be installed for this script to work.' exit 1 @@ -325,6 +409,10 @@ EOF exit 1 fi +# The following variables comprise a pseudo associative array of project names to source repositories. +# You only need to set a SOURCES variable if the project name does not match the source repository name. +# You can get a key identifier using the `identifier` function. +# To look up the value of any pseudo associative array, use the `aget` function. SOURCES_as_code='as-code-docs' SOURCES_enterprise_metrics='backend-enterprise' SOURCES_enterprise_metrics_='backend-enterprise' @@ -334,13 +422,16 @@ SOURCES_grafana_cloud_alerting_and_irm_slo='slo' SOURCES_grafana_cloud_k6='k6-docs' SOURCES_grafana_cloud_data_configuration_integrations='cloud-onboarding' SOURCES_grafana_cloud_frontend_observability_faro_web_sdk='faro-web-sdk' +SOURCES_grafana_cloud_send_data_fleet_management='fleet-management' SOURCES_helm_charts_mimir_distributed='mimir' SOURCES_helm_charts_tempo_distributed='tempo' SOURCES_opentelemetry='opentelemetry-docs' -SOURCES_plugins_grafana_datadog_datasource='datadog-datasource' -SOURCES_plugins_grafana_oracle_datasource='oracle-datasource' SOURCES_resources='website' +# The following variables comprise a pseudo associative array of project names to versions. +# You only need to set a VERSIONS variable if it is not the default of 'latest'. +# You can get a key identifier using the `identifier` function. +# To look up the value of any pseudo associative array, use the `aget` function. VERSIONS_as_code='UNVERSIONED' VERSIONS_grafana_cloud='UNVERSIONED' VERSIONS_grafana_cloud_alerting_and_irm_machine_learning='UNVERSIONED' @@ -348,20 +439,21 @@ VERSIONS_grafana_cloud_alerting_and_irm_slo='UNVERSIONED' VERSIONS_grafana_cloud_k6='UNVERSIONED' VERSIONS_grafana_cloud_data_configuration_integrations='UNVERSIONED' VERSIONS_grafana_cloud_frontend_observability_faro_web_sdk='UNVERSIONED' +VERSIONS_grafana_cloud_send_data_fleet_management='UNVERSIONED' VERSIONS_opentelemetry='UNVERSIONED' -VERSIONS_plugins_grafana_datadog_datasource='latest' -VERSIONS_plugins_grafana_oracle_datasource='latest' VERSIONS_resources='UNVERSIONED' VERSIONS_technical_documentation='UNVERSIONED' VERSIONS_website='UNVERSIONED' VERSIONS_writers_toolkit='UNVERSIONED' +# The following variables comprise a pseudo associative array of project names to source repository paths. +# You only need to set a PATHS variable if it is not the default of 'docs/sources'. +# You can get a key identifier using the `identifier` function. +# To look up the value of any pseudo associative array, use the `aget` function. PATHS_grafana_cloud='content/docs/grafana-cloud' PATHS_helm_charts_mimir_distributed='docs/sources/helm-charts/mimir-distributed' PATHS_helm_charts_tempo_distributed='docs/sources/helm-charts/tempo-distributed' PATHS_mimir='docs/sources/mimir' -PATHS_plugins_grafana_datadog_datasource='docs/sources' -PATHS_plugins_grafana_oracle_datasource='docs/sources' PATHS_resources='content' PATHS_tempo='docs/sources/tempo' PATHS_website='content' @@ -613,7 +705,7 @@ POSIX_HERESTRING case "${_project}" in # Workaround for arbitrary mounts where the version field is expected to be the local directory - # and the repo field is expected to be the container directory. + # and the repo field is expected to be the container directory. arbitrary) echo "${_project}^${_version}^${_repo}^" # TODO ;; @@ -648,6 +740,10 @@ await_build() { url="$1" req="$(if command -v curl >/dev/null 2>&1; then echo 'curl -s -o /dev/null'; else echo 'wget -q'; fi)" + # Initial delay to allow container to start before beginning healthchecks + sleep 3 + + # Fast retries for initial startup (10 attempts, 1 second apart) i=1 max=10 while [ "${i}" -ne "${max}" ] @@ -676,6 +772,37 @@ POSIX_HERESTRING fi done + # Continue checking with longer intervals for slower builds + # This prevents false positives for large builds that take longer to start + i=1 + max=20 + while [ "${i}" -ne "${max}" ] + do + sleep 2 + debg "Continuing to check web server (build may be taking longer than expected)." + i=$((i + 1)) + + if ${req} "${url}"; then + printf '\r\nView documentation locally:\r\n' + for x in ${url_src_dst_vers}; do + IFS='^' read -r url _ _ </dev/null 2>&1; then - errr '`jq` must be installed for the `doc-validator` target to work.' - note 'To install `jq`, refer to https://jqlang.github.io/jq/download/,' - - exit 1 - fi - - ${cmd} \ - | jq -r '"ERROR: \(.location.path):\(.location.range.start.line // 1):\(.location.range.start.column // 1): \(.message)" + if .suggestions[0].text then "\nSuggestion: \(.suggestions[0].text)" else "" end' - ;; - json) - ${cmd} - ;; - *) # default - errr "Invalid output format '${OUTPUT_FORMAT}'" - esac - ;; 'grafana/vale') proj="$(new_proj "$1")" printf '\r\n' @@ -816,6 +907,10 @@ EOF /hugo/content/docs EOF + if [ -n "${DEBUG}" ]; then + debg "${cmd}" + fi + case "${OUTPUT_FORMAT}" in human) ${cmd} --output=line \ @@ -905,7 +1000,7 @@ EOF -e '/Press Ctrl+C to stop/ d' \ -e '/make/ d' \ -e '/WARNING: The manual_mount source directory/ d' \ - -e '/docs\/_index.md .* not found/ d' + -e '/"docs\/_index.md" not found/d' fi ;; esac diff --git a/docs/sources/_index.md b/docs/sources/_index.md index 66bdb8ff23..f27bd7cf67 100644 --- a/docs/sources/_index.md +++ b/docs/sources/_index.md @@ -1,6 +1,8 @@ --- title: "Grafana Pyroscope" weight: 1 +cascade: + GRAFANA_VERSION: latest description: Grafana Pyroscope is an open source software project for aggregating continuous profiling data. keywords: - Grafana Pyroscope @@ -8,8 +10,10 @@ keywords: - TSDB - profiles storage - profiles datastore + - profiles database - observability - continuous profiling + - performance engineering hero: title: Grafana Pyroscope level: 1 @@ -30,7 +34,7 @@ cards: description: Learn how to install and configure Grafana Pyroscope with several examples. - title: Instrument your app and configure the client href: ./configure-client/ - description: When sending profiles to Pyroscope, you can choose between SDK instrumentation and auto-instrumentation using the Grafana Agent. This document explains these two techniques and guide you when to choose each one. + description: When sending profiles to Pyroscope, you can choose between SDK instrumentation and auto-instrumentation using Grafana Alloy. This document explains these two techniques and helps you choose one. - title: Configure the server href: ./configure-server/ description: Configure your Pyroscope server to meet your needs by setting disk storage, tenant IDs, memberlist, proxies, shuffle sharding, and more. You can also use the server HTTP API. @@ -52,8 +56,8 @@ Grafana Pyroscope is a multi-tenant, continuous profiling aggregation system, al This integration enables a cohesive correlation of profiling data with existing metrics, logs, and traces. Explore continuous profiling data to gain insights into application performance. -You can query and analyze production data in a structure way. -Use the Pyroscope UI or Grafana to visualize the data. +You can query and analyze production data in a structured way. +Use the Pyroscope UI or Grafana to visualize the data. B["Pyroscope
stores & aggregates
profiling data
"] + B -- query --> C["Grafana
visualize as
flamegraphs
"] +{{< /mermaid >}} + +1. **OpenTelemetry eBPF Profiler** runs as an OpenTelemetry Collector distribution with the `profiling` receiver. It attaches eBPF probes to collect CPU stack traces at 97 samples per second from every process on the host. +2. **Pyroscope** receives profiles via OTLP gRPC on port 4040 and stores them. +3. **Grafana** queries Pyroscope to visualize profiles as flamegraphs. + +The profiler requires host PID namespace access and several host filesystem mounts (`/proc`, `/sys/kernel`, `/lib/modules`) to resolve stack traces. + +## Configure the collector + +The profiler runs as a specialized OpenTelemetry Collector. Configure it with a `profiling` receiver and an `otlp_grpc` exporter pointing to Pyroscope: + +```yaml +receivers: + profiling: + samples_per_second: 97 + +exporters: + otlp_grpc: + endpoint: pyroscope:4040 + tls: + insecure: true + +service: + pipelines: + profiles: + receivers: [profiling] + exporters: [otlp_grpc] +``` + +The collector must be started with the `--feature-gates=service.profilesSupport` flag. + +### Service name resolution + +By default, the profiler sets `process.executable.name` on each profile but does not set `service_name`, which Pyroscope uses as the primary label. To map executable names to service names, configure Pyroscope with an ingestion relabeling rule: + +```yaml +limits: + ingestion_relabeling_rules: + - action: labelmap + regex: ^process.executable.name$ + replacement: service_name +``` + +### Kubernetes metadata enrichment + +In Kubernetes, you can add a `k8sattributes` processor to enrich profiles with pod, namespace, deployment, and node metadata: + +```yaml +processors: + k8sattributes/profiles: + auth_type: serviceAccount + passthrough: false + extract: + metadata: + - k8s.pod.name + - k8s.pod.uid + - k8s.namespace.name + - k8s.deployment.name + - k8s.node.name + - k8s.container.name + - container.image.name + - container.image.tag + - service.name + - service.namespace + - service.instance.id + otel_annotations: true + pod_association: + - sources: + - from: resource_attribute + name: container.id + +service: + pipelines: + profiles: + receivers: [profiling] + processors: [k8sattributes/profiles] + exporters: [otlp_grpc] +``` + +This requires a `ServiceAccount` with RBAC permissions to read pods, namespaces, nodes, and workload resources. See the [example RBAC manifest](https://github.com/grafana/pyroscope/tree/main/examples/otel-collector/ebpf/kubernetes/rbac.yaml). + +## Deploy with Docker Compose + +A minimal Docker Compose setup runs the profiler, Pyroscope, and Grafana: + +```yaml +services: + otel-ebpf-profiler: + image: otel/opentelemetry-collector-ebpf-profiler:0.147.0 + command: + - --config=/etc/ebpf-profiler-config.yaml + - --feature-gates=service.profilesSupport + privileged: true + pid: "host" + volumes: + - ./config/ebpf-profiler-config.yaml:/etc/ebpf-profiler-config.yaml:ro + - /sys/kernel/debug:/sys/kernel/debug:ro + - /sys/fs/cgroup:/sys/fs/cgroup:ro + - /proc:/proc:ro + + pyroscope: + image: grafana/pyroscope:1.18.1 + command: + - -self-profiling.disable-push=true + - -config.file=/etc/pyroscope.yaml + ports: + - "4040:4040" + + grafana: + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + ports: + - "3000:3000" +``` + +For a complete working example, see the [Docker example](https://github.com/grafana/pyroscope/tree/main/examples/otel-collector/ebpf/docker). + +## Deploy on Kubernetes + +On Kubernetes, deploy the profiler as a DaemonSet so it runs on every node: + +```yaml +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: otel-ebpf-profiler +spec: + selector: + matchLabels: + app: otel-ebpf-profiler + template: + metadata: + labels: + app: otel-ebpf-profiler + spec: + hostPID: true + serviceAccountName: otel-ebpf-profiler + containers: + - name: profiler + image: otel/opentelemetry-collector-ebpf-profiler:0.147.0 + args: + - "--config=/etc/otel/config.yaml" + - "--feature-gates=+service.profilesSupport" + securityContext: + privileged: true + volumeMounts: + - name: sys-kernel + mountPath: /sys/kernel + readOnly: true + - name: proc + mountPath: /proc + readOnly: true + volumes: + - name: sys-kernel + hostPath: + path: /sys/kernel + - name: proc + hostPath: + path: /proc + tolerations: + - operator: Exists +``` + +For a complete working example with kustomize, Pyroscope, Grafana, RBAC, and a sample workload, see the [Kubernetes example](https://github.com/grafana/pyroscope/tree/main/examples/otel-collector/ebpf/kubernetes). + +Deploy it with: + +```bash +git clone --depth 1 --filter=tree:0 --no-checkout https://github.com/grafana/pyroscope.git +cd pyroscope +git sparse-checkout set examples/otel-collector/ebpf +git checkout +kubectl apply -k examples/otel-collector/ebpf/kubernetes/ +``` + +## Verify + +After deploying, open Grafana (http://localhost:3000 for Docker, or port-forward in Kubernetes) and navigate to **Explore** with the Pyroscope data source. You should see profiles grouped by `service_name` appearing within a few minutes. + +![Profiles in Grafana](https://github.com/user-attachments/assets/15ff58d4-218a-43dd-9835-df12e13ced3f) diff --git a/docs/sources/configure-client/profile-types.md b/docs/sources/configure-client/profile-types.md new file mode 100644 index 0000000000..6f24251970 --- /dev/null +++ b/docs/sources/configure-client/profile-types.md @@ -0,0 +1,104 @@ +--- +title: Profile types and instrumentation +menuTitle: Profile types and instrumentation +description: Learn about the different profiling types available in Pyroscope and +weight: 100 +aliases: + - ../ingest-and-analyze-profile-data/profiling-types/ + - ../view-and-analyze-profile-data/profiling-types/ # /docs/pyroscope/latest/view-and-analyze-profile-data/profiling-types/ +keywords: + - pyroscope + - profiling types + - application performance + - flame graphs +--- + +# Profile types and instrumentation + +Profiling is an essential tool for understanding and optimizing application performance. In Pyroscope, various profiling types allow for an in-depth analysis of different aspects of your application. This guide explores these types and explain their impact on your program. + +Profiling types refer to different dimensions of application performance analysis, focusing on specific aspects like CPU usage, memory allocation, or thread synchronization. + +Note that when Pyroscope receives a Java wall profile, both `cpu` and `wall` profiles are automatically ingested, even if `cpu` profiling is turned off. + +[//]: # 'Shared content for available profile types' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/available-profile-types.md' + +{{< docs/shared source="pyroscope" lookup="available-profile-types.md" version="latest" >}} + +Refer to [Understand profiling types and their uses in Pyroscope](https://grafana.com/docs/pyroscope//introduction/profiling-types/) for more details about the profile types. + +## Profile type support by instrumentation method + +The instrumentation method you use determines which profile types are available. You can use either auto or manual instrumentation. + +### Auto-instrumentation with Grafana Alloy + +You can send data from your application using Grafana Alloy collector. Alloy supports profiling with eBPF, Java, and Golang in pull mode. + +[//]: # 'Shared content for supported languages with eBPF' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/supported-languages-ebpf.md' + +{{< docs/shared source="pyroscope" lookup="supported-languages-ebpf.md" version="latest" >}} + +For more information, refer to [Configure the client to send profiles with Grafana Alloy](https://grafana.com/docs/pyroscope//configure-client/grafana-alloy/). + +This table lists the available profile types based on auto instrumentation using Alloy. + +| Profile type | Go (pull) | Java | eBPF | +| -------------- | --------- | ---- | --------- | +| CPU | Yes | Yes | Yes | +| Alloc Objects | Yes | Yes | | +| Alloc Space | Yes | Yes | | +| Inuse Objects | | | | +| Inuse Space | | | | +| Goroutines | Yes | | | +| Mutex Count | | | | +| Mutex Duration | | | | +| Block Count | Yes | | | +| Block Duration | Yes | | | +| Lock Count | | Yes | | +| Lock Duration | | Yes | | +| Exceptions | | | | +| Wall | | Yes | | +| Heap | | | | + +### Instrumentation with SDKs + +Using the Pyroscope language SDKs lets you instrument your application directly for precise profiling. You can customize the profiling process according to your application’s specific requirements. + +For more information on the language SDKs, refer to [Pyroscope language SDKs](https://grafana.com/docs/pyroscope//configure-client/language-sdks/). For the operating systems and CPU architectures each SDK supports, refer to [Supported operating systems and architectures](https://grafana.com/docs/pyroscope//configure-client/supported-platforms/). + +This table lists the available profile types based on the language SDK. + +| Profile type | Go (push) | Java | .NET | Ruby | Python | Rust | Node.js | +| -------------- | --------- | ---- | ---------- | ---- | ------ | ---- | ------- | +| CPU | Yes | Yes | Yes | Yes | Yes | Yes | Yes | +| Alloc Objects | Yes | Yes | Yes | | | | | +| Alloc Space | Yes | Yes | Yes | | | | | +| Inuse Objects | Yes | | Yes (7.0+) | | | | | +| Inuse Space | Yes | | Yes (7.0+) | | | | | +| Goroutines | Yes | | | | | | | +| Mutex Count | Yes | | Yes | | | | | +| Mutex Duration | Yes | | Yes | | | | | +| Block Count | Yes | | | | | | | +| Block Duration | Yes | | | | | | | +| Lock Count | | Yes | Yes | | | | | +| Lock Duration | | Yes | Yes | | | | | +| Exceptions | | | Yes | | | | | +| Wall | | Yes | Yes | | | | Yes | +| Heap | | | Yes (7.0+) | | | | Yes | + +## Profile types supported with span profiles + +Pyroscope can integrate with distributed tracing systems supporting the OpenTelemetry standard. This integration lets you link traces with the profiling data and find resource usage for specific lines of code for your trace spans. + +Only CPU profile type is supported for span profiles. + +The following languages are supported: + +- [Go](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/go-span-profiles/) +- [Java](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/java-span-profiles/) +- [Ruby](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/ruby-span-profiles/) +- [.NET](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/dotnet-span-profiles/) +- [Python](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/python-span-profiles/) diff --git a/docs/sources/configure-client/supported-platforms.md b/docs/sources/configure-client/supported-platforms.md new file mode 100644 index 0000000000..1a2903ecf6 --- /dev/null +++ b/docs/sources/configure-client/supported-platforms.md @@ -0,0 +1,55 @@ +--- +title: Supported operating systems and architectures +menuTitle: Supported platforms +description: Operating system, CPU architecture, and libc support for each Pyroscope language SDK. +weight: 120 +keywords: + - pyroscope + - language sdks + - supported platforms + - operating systems + - architecture +--- + +# Supported operating systems and architectures + +The Pyroscope [language SDKs](https://grafana.com/docs/pyroscope//configure-client/language-sdks/) instrument your application in-process to send profiles to Pyroscope. Because most SDKs rely on a native profiling engine, the operating systems and CPU architectures they support vary. This page summarizes what each SDK supports. + +For the list of profile types each SDK produces, refer to [Profile types and instrumentation](https://grafana.com/docs/pyroscope//configure-client/profile-types/). + +## Support matrix + +| SDK | Linux x86_64 | Linux ARM64 | macOS x86_64 | macOS ARM64 | Windows x64 | +| --- | --- | --- | --- | --- | --- | +| Go | Yes | Yes | Yes | Yes | Yes | +| Java | Yes | Yes | Yes | Yes | No | +| .NET | Yes | Yes | No | No | Public preview (see note) | +| Python | Yes | Yes | Yes | Yes | No | +| Ruby | Yes | Yes | Yes | Yes | No | +| Rust | Yes | Yes | Yes | Yes | No | +| Node.js | Yes | Yes | Yes | Yes | Yes | + +{{< admonition type="note" >}} +Windows support for the .NET SDK is in [public preview](https://grafana.com/docs/release-life-cycle/), starting with profiler version 1.3.0. On .NET 8 and later it has full parity with Linux; on .NET Framework 4.8 only CPU profiling is available. Refer to the [.NET SDK documentation](https://grafana.com/docs/pyroscope//configure-client/language-sdks/dotnet/). +{{< /admonition >}} + + +## Linux libc: glibc and musl (Alpine) + +Most containerized deployments run on either `glibc` (for example, Debian or Ubuntu) or `musl` (Alpine) Linux. All SDKs support both, but they package it differently: + +* **Go** and **Java** work on both from a single build. Go is pure Go, and the Java agent bundles one native library per architecture that runs on either `libc`. +* **.NET**, **Python**, and **Node.js** publish separate `glibc` and `musl` builds. For .NET, download the tarball that matches your base image; for Python (`pip`) and Node.js (`npm`), the matching build is selected automatically. +* **Ruby** ships precompiled gems for `glibc` Linux only. On Alpine, the `gem` compiles its native extension at install time, which requires a Rust toolchain. + +## macOS + +macOS is intended for local development, not production. The Go, Java, Python, Ruby, and Rust SDKs run on macOS for both Intel and Apple Silicon. The .NET SDK does not support macOS. + +## Windows + +The Go and Node.js SDKs run on Windows. The .NET SDK supports Windows x64 in [public preview](https://grafana.com/docs/release-life-cycle/) (see the note under the support matrix). The Java, Python, Ruby, and Rust SDKs don't support Windows. + +## Auto-instrumentation with Grafana Alloy and eBPF + +The support above applies to the language SDKs, which instrument your application in-process. [Auto-instrumentation with Grafana Alloy](https://grafana.com/docs/pyroscope//configure-client/grafana-alloy/), including the eBPF profiler, runs only on Linux because it depends on Linux kernel features. It isn't available on macOS or Windows. diff --git a/docs/sources/configure-client/trace-span-profiles/_index.md b/docs/sources/configure-client/trace-span-profiles/_index.md index fd68b2c65f..2f47be235c 100644 --- a/docs/sources/configure-client/trace-span-profiles/_index.md +++ b/docs/sources/configure-client/trace-span-profiles/_index.md @@ -1,11 +1,11 @@ --- -title: "Linking tracing and profiling with Span Profiles" -menuTitle: "Linking traces and profiles" +title: "Link tracing and profiling with Span Profiles" +menuTitle: "Link traces and profiles" description: "Learn how to configure the client to Link tracing and profiling with span profiles." -weight: 35 +weight: 400 --- -# Linking tracing and profiling with Span Profiles +# Link tracing and profiling with Span Profiles Span Profiles are a powerful feature that further enhances the value of continuous profiling. Span Profiles offer a novel approach to profiling by providing detailed insights into specific execution scopes of applications, moving beyond the traditional system-wide analysis to offer a more dynamic, focused analysis of individual requests or trace spans. @@ -18,15 +18,21 @@ Key benefits and features: - Seamless integration: Smoothly transition from a high-level trace overview to detailed profiling of specific trace spans within Grafana’s trace view - Efficiency and cost savings: Quickly identify and address performance issues, reducing troubleshooting time and operational costs -Get started: +{{< admonition type="note">}} +Span profiling is only effective on spans longer than 20ms to ensure statistical accuracy. +{{< /admonition >}} + +## Get started + +Select an option from the list below: - Configure Pyroscope: Begin sending profiling data to unlock the full potential of Span Profiles - Client-side packages: Easily link traces and profiles using available packages for Go, Java, Ruby, .NET, and Python - - Go: [Span profiles with Traces to profiles (Go)]({{< relref "./go-span-profiles" >}}) - - Java: [Span profiles with Traces to profiles (Java)]({{< relref "./java-span-profiles" >}}) - - Ruby: [Span profiles with Traces to profiles (Ruby)]({{< relref "./ruby-span-profiles" >}}) - - .NET: [Span profiles with Traces to profiles (.NET)]({{< relref "./dotnet-span-profiles" >}}) - - Python: [Span profiles with Traces to profiles (Python)]({{< relref "./python-span-profiles" >}}) -- Grafana Tempo: Visualize and analyze Span Profiles within the Grafana using a Tempo data source. - -To learn more, check out our product announcement blog: [Introducing Span Profiles](/blog/2024/02/06/combining-tracing-and-profiling-for-enhanced-observability-introducing-span-profiles/). + - Go: [Span profiles with Traces to profiles (Go)](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/go-span-profiles/) + - Java: [Span profiles with Traces to profiles (Java)](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/java-span-profiles/) + - Ruby: [Span profiles with Traces to profiles (Ruby)](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/ruby-span-profiles/) + - .NET: [Span profiles with Traces to profiles (.NET)](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/dotnet-span-profiles/) + - Python: [Span profiles with Traces to profiles (Python)](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/python-span-profiles/) +- [Configure the Tempo data source in Grafana or Grafana Cloud](/docs/grafana-cloud/connect-externally-hosted/data-sources/tempo/configure-tempo-data-source/) to discover linked traces and profiles. + +To learn more, check out the product announcement blog: [Introducing Span Profiles](/blog/2024/02/06/combining-tracing-and-profiling-for-enhanced-observability-introducing-span-profiles/). diff --git a/docs/sources/configure-client/trace-span-profiles/dotnet-span-profiles.md b/docs/sources/configure-client/trace-span-profiles/dotnet-span-profiles.md index d924a2568f..908d3d195f 100644 --- a/docs/sources/configure-client/trace-span-profiles/dotnet-span-profiles.md +++ b/docs/sources/configure-client/trace-span-profiles/dotnet-span-profiles.md @@ -7,16 +7,16 @@ weight: 103 # Span profiles with Traces to profiles for .NET -Span Profiles represents a major shift in profiling methodology, enabling deeper analysis of both tracing and profiling data. +Span Profiles represent a shift in profiling methodology. Traditional continuous profiling provides an application-wide view over fixed intervals. In contrast, Span Profiles delivers focused, dynamic analysis on specific execution scopes within applications, such as individual requests or specific trace spans. -This shift enables a more granular view of performance, enhancing the utility of profiles by linking them directly with traces for a comprehensive understanding of application behavior. As a result, engineering teams can more efficiently identify and address performance bottlenecks. - To learn more about Span Profiles, refer to [Combining tracing and profiling for enhanced observability: Introducing Span Profiles](/blog/2024/02/06/combining-tracing-and-profiling-for-enhanced-observability-introducing-span-profiles/). ![span-profiles screenshot](https://grafana.com/static/img/docs/tempo/profiles/tempo-profiles-Span-link-profile-data-source.png) +## Supported profile types + Pyroscope integrates with distributed tracing systems supporting the [**OpenTelemetry**](https://opentelemetry.io/docs/languages/net/getting-started/) standard. This integration lets you link traces with the profiling data and find resource usage for specific lines of code for your trace spans. @@ -25,18 +25,22 @@ This integration lets you link traces with the profiling data and find resource * Because of how sampling profilers work, spans shorter than the sample interval may not be captured. {{< /admonition >}} +For a more detailed list of supported profile types, refer to [Profile types](https://grafana.com/docs/pyroscope/). + +## Before you begin + To use Span Profiles, you need to: -* [Configure Pyroscope to send profiling data]({{< relref "../../configure-client" >}}) +* [Configure Pyroscope to send profiling data](https://grafana.com/docs/pyroscope//configure-client/) * Configure a client-side package to link traces and profiles: [.NET](https://github.com/grafana/pyroscope-dotnet/tree/main/Pyroscope/Pyroscope.OpenTelemetry) * [Configure the Tempo data source in Grafana or Grafana Cloud to discover linked traces and profiles](/docs/grafana-cloud/connect-externally-hosted/data-sources/tempo/configure-tempo-data-source/) -## Before you begin +### Instrument your application for profiles Your applications must be instrumented for profiling and tracing before you can use span profiles. -* Profiling: Your application must be instrumented with Pyroscope's .NET instrumentation library. Refer to the [.NET]({{< relref "../language-sdks/dotnet" >}}) guide for instructions. -* Tracing: Your application must be instrumented with OpenTelemetry traces. Refer to the [OpenTelemetry](https://opentelemetry.io/docs/languages/net/getting-started/) guide for isntructions. +* Profiling: Your application must be instrumented with Pyroscope's .NET instrumentation library. Refer to the [.NET](../../language-sdks/dotnet/) guide for instructions. +* Tracing: Your application must be instrumented with OpenTelemetry traces. Refer to the [OpenTelemetry](https://opentelemetry.io/docs/languages/net/getting-started/) guide for instructions. {{< admonition type="note" >}} Span profiles in .NET are only supported using [OpenTelemetry manual instrumentation](https://opentelemetry.io/docs/languages/net/instrumentation/) @@ -68,12 +72,14 @@ builder.Services.AddOpenTelemetry() With the span processor registered, spans created automatically (for example, HTTP handlers) and manually (`ActivitySource.StartActivity()`) have profiling data associated with them. -## View the span profiles in Grafana Tempo +## View the span profiles in Grafana -To view the span profiles in Grafana Tempo, you need to have a Grafana instance running and a data source configured to link traces and profiles. +To view the span profiles in Grafana Explore or Grafana Traces Drilldown, you need to have a Grafana instance running and a Tempo data source configured to link traces and profiles. -Refer to the [data source configuration documentation](/docs/grafana/datasources/tempo/configure-tempo-data-source) to see how to configure the visualization to link traces with profiles. +Refer to the [Tempo data source configuration documentation](https://grafana.com/docs/grafana//datasources/tempo/configure-tempo-data-source) to see how to configure the visualization to link traces with profiles. ## Examples -Check out the [examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) directory for a complete demo application of span profiles in multiple languages. +Check out these demo applications for span profiles: +- [.NET example](https://github.com/grafana/pyroscope/tree/main/examples/tracing/dotnet) +- [Other examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) in multiple languages diff --git a/docs/sources/configure-client/trace-span-profiles/go-span-profiles.md b/docs/sources/configure-client/trace-span-profiles/go-span-profiles.md index 30a4319d36..cd51514098 100644 --- a/docs/sources/configure-client/trace-span-profiles/go-span-profiles.md +++ b/docs/sources/configure-client/trace-span-profiles/go-span-profiles.md @@ -10,7 +10,7 @@ weight: 100 # Span profiles with Traces to profiles for Go -Span Profiles represents a major shift in profiling methodology, enabling deeper analysis of both tracing and profiling data. +Span Profiles represent a major shift in profiling methodology, enabling deeper analysis of both tracing and profiling data. Traditional continuous profiling provides an application-wide view over fixed intervals. In contrast, Span Profiles delivers focused, dynamic analysis on specific execution scopes within applications, such as individual requests or specific trace spans. @@ -30,7 +30,7 @@ This integration lets you link traces with the profiling data and find resource To use Span Profiles, you need to: -* [Configure Pyroscope to send profiling data]({{< relref "../../configure-client" >}}) +* [Configure Pyroscope to send profiling data](../../) * Configure a client-side package to link traces and profiles: [Go](https://github.com/grafana/otel-profiling-go) * [Configure the Tempo data source in Grafana or Grafana Cloud to discover linked traces and profiles](/docs/grafana-cloud/connect-externally-hosted/data-sources/tempo/configure-tempo-data-source/) @@ -38,8 +38,8 @@ To use Span Profiles, you need to: Your applications must be instrumented for profiling and tracing before you can use span profiles. -* Profiling: Your application must be instrumented with Pyroscope's Go SDK. If you haven't done this yet, please refer to the [Go (push mode)]({{< relref "../language-sdks/go_push" >}}) guide. -* Tracing: Your application must be instrumented with OpenTelemetry traces. If you haven't done this yet, please refer to the [OpenTelemetry](https://opentelemetry.io/docs/go/getting-started/) guide. +* Profiling: Your application must be instrumented with Pyroscope's Go SDK. If you haven't done this yet, please refer to the [Go (push mode)](../../language-sdks/go_push/) guide. +* Tracing: Your application must be instrumented with OpenTelemetry traces. If you haven't done this yet, please refer to the [OpenTelemetry](https://opentelemetry.io/docs/languages/go/getting-started/) guide. ## Configure the `otel-profiling-go` package @@ -92,12 +92,12 @@ defer span.End() To view the span profiles in Grafana Tempo, you need to have a Grafana instance with a Tempo data source configured to link trace spans and profiles. Refer to the configuration documentation for [Grafana](/docs/grafana//datasources/tempo/configure-tempo-data-source) or [Grafana Cloud](/docs/grafana-cloud/connect-externally-hosted/data-sources/tempo/configure-tempo-data-source). -To learn how to set up Traces to profiles and view the span profiles, refer to [Traces to profiles]({{< relref "../../view-and-analyze-profile-data/profile-tracing/traces-to-profiles" >}}). +To learn how to set up Traces to profiles and view the span profiles, refer to [Traces to profiles](../../../view-and-analyze-profile-data/traces-to-profiles/). ## Examples -Check out the [examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) directory for a complete demo application that shows tracing integration features. +Check out the [examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/golang-push) directory for a complete demo application that shows tracing integration features. + +# Ride share tutorial with Pyroscope + +This tutorial demonstrates a basic use case of Pyroscope by profiling a "Ride Share" application. +In this example, you learn: + +- How an application is instrumented with Pyroscope, including techniques for dynamically tagging functions. +- How to view the resulting profile data in Grafana using the Profiles View. +- How to integrate Pyroscope with Grafana to visualize the profile data. + + + +## Before you begin + +You need to have the following prerequisites to complete this tutorial: +- Git +- [Docker](https://docs.docker.com/compose/install/) +- The Docker Compose plugin (included with Docker Desktop) + +{{< admonition type="tip" >}} +Try this tutorial in an interactive learning environment: [Ride share tutorial with Pyroscope](https://killercoda.com/grafana-labs/course/pyroscope/ride-share-tutorial). + +It's a fully configured environment with all the dependencies installed. + +Provide feedback, report bugs, and raise issues in the [Grafana Killercoda repository](https://github.com/grafana/killercoda). +{{< /admonition >}} + + + +## Background + +In this tutorial, you will profile a simple "Ride Share" application. The application is a Python Flask app that simulates a ride-sharing service. The app has three endpoints which are found in the `lib/server.py` file: + +- `/bike` : calls the `order_bike(search_radius)` function to order a bike +- `/car` : calls the `order_car(search_radius)` function to order a car +- `/scooter` : calls the `order_scooter(search_radius)` function to order a scooter + +To simulate a highly available and distributed system, the app is deployed on three distinct servers in 3 different regions: +- us-east +- eu-north +- ap-south + +This is simulated by running three instances of the server in Docker containers. Each server instance is tagged with the region it represents. + +{{< figure max-width="100%" src="/media/docs/pyroscope/ride-share-demo.gif" caption="Getting started sample application" alt="Getting started sample application" >}} + +In this scenario, a load generator will send mock-load to the three servers as well as their respective endpoints. This lets you see how the application performs per region and per vehicle type. + +{{}} +{{< admonition type="tip" >}} +A setup script runs in the background to install the necessary dependencies. This should take no longer than 30 seconds. Your instance will be ready to use once you `Setup complete. You may now begin the tutorial`. +{{< /admonition >}} +{{}} + + + + + +## Clone the repository + +1. Clone the repository to your local machine: + + ```bash + git clone https://github.com/grafana/pyroscope.git && cd pyroscope + ``` + +1. Navigate to the tutorial directory: + + ```bash + cd examples/language-sdk-instrumentation/python/rideshare/flask + ``` + +## Start the application + +Start the application using Docker Compose: + +```bash +docker compose up -d +``` + +This may take a few minutes to download the required images and build the demo application. Once ready, you will see the following output: + +```console + ✔ Network flask_default Created + ✔ Container flask-ap-south-1 Started + ✔ Container flask-grafana-1 Started + ✔ Container flask-pyroscope-1 Started + ✔ Container flask-load-generator-1 Started + ✔ Container flask-eu-north-1 Started + ✔ Container flask-us-east-1 Started +``` + +Optional: To verify the containers are running, run: + +```bash +docker ps -a +``` + + + + +## Accessing Profiles Drilldown in Grafana + +Grafana includes the [Profiles Drilldown](https://grafana.com/docs/grafana//explore/simplified-exploration/profiles/) app that you can use to view profile data. To access Profiles Drilldown, open a browser and navigate to [http://localhost:3000/a/grafana-pyroscope-app/explore](http://localhost:3000/a/grafana-pyroscope-app/explore). + +### How tagging works + +In this example, the application is instrumented with Pyroscope using the Python SDK. +The SDK allows you to tag functions with metadata that can be used to filter and group the profile data in the Profiles Drilldown. +This example uses static and dynamic tagging. + +To start, let's take a look at a static tag use case. Within the `lib/server.py` file, find the Pyroscope configuration: + +```python + pyroscope.configure( + application_name = app_name, + server_address = server_addr, + basic_auth_username = basic_auth_username, # for grafana cloud + basic_auth_password = basic_auth_password, # for grafana cloud + tags = { + "region": f'{os.getenv("REGION")}', + } + ) +``` +This tag is considered static because the tag is set at the start of the application and doesn't change. +In this case, it's useful for grouping profiles on a per region basis, which lets you see the performance of the application per region. + +1. Open Grafana using the following url: [http://localhost:3000/a/grafana-pyroscope-app/explore](http://localhost:3000/a/grafana-pyroscope-app/explore). +1. In the main menu, select **Drilldown** > **Profiles**. +1. Select **Labels** in the **Exploration** path. +1. Select **ride-sharing-app** in the **Service** drop-down menu. +1. Select the **region** tab in the **Group by labels** section. + +You should now see a list of regions that the application is running in. You can see that `eu-north` is experiencing the most load. + +{{< figure max-width="100%" src="/media/docs/pyroscope/ride-share-tag-region-2.png" caption="Region Tag" alt="Region Tag" >}} + +Next, look at a dynamic tag use case. Within the `lib/utility/utility.py` file, find the following function: + +```python + def find_nearest_vehicle(n, vehicle): + with pyroscope.tag_wrapper({ "vehicle": vehicle}): + i = 0 + start_time = time.time() + while time.time() - start_time < n: + i += 1 + if vehicle == "car": + check_driver_availability(n) +``` + +This example uses `tag_wrapper` to tag the function with the vehicle type. +Notice that the tag is dynamic as it changes based on the vehicle type. +This is useful for grouping profiles on a per vehicle basis, allowing us to see the performance of the application per vehicle type being requested. + +Use Profiles Drilldown to see how this tag is used: +1. Open Profiles Drilldown using the following url: [http://localhost:3000/a/grafana-pyroscope-app/explore](http://localhost:3000/a/grafana-pyroscope-app/explore). +1. Select on **Labels** in the **Exploration** path. +1. In the **Group by labels** section, select the **vehicle** tab. + +You should now see a list of vehicle types that the application is using. You can see that `car` is experiencing the most load. + + + + + +## Identifying the performance bottleneck + +The first step when analyzing a profile outputted from your application, is to take note of the largest node which is where your application is spending the most resources. +To discover this, you can use the **Flame graph** view: + +1. Open Profiles Drilldown using the following url: [http://localhost:3000/a/grafana-pyroscope-app/explore](http://localhost:3000/a/grafana-pyroscope-app/explore). +1. Select **Flame graph** from the **Exploration** path. +1. Verify that `ride-sharing-app` is selected in the **Service** drop-down menu and `process_cpu/cpu` in the **Profile type** drop-down menu. + +It should look something like this: + +{{< figure max-width="100%" src="/media/docs/pyroscope/ride-share-bottle-neck-3.png" caption="Bottleneck" alt="Bottleneck" >}} + +The flask `dispatch_request` function is the parent to three functions that correspond to the three endpoints of the application: +- `order_bike` +- `order_car` +- `order_scooter` + +By tagging both `region` and `vehicle` and looking at the [**Labels** view](https://grafana.com/docs/grafana//explore/simplified-exploration/profiles/choose-a-view/#labels), you can hypothesize: + +- Something is wrong with the `/car` endpoint code where `car` vehicle tag is consuming **68% of CPU** +- Something is wrong with one of our regions where `eu-north` region tag is consuming **54% of CPU** + +From the flame graph, you can see that for the `eu-north` tag the biggest performance impact comes from the `find_nearest_vehicle()` function which consumes close to **68% of cpu**. +To analyze this, go directly to the comparison page using the comparison dropdown. + +### Comparing two time periods + +The **Diff flame graph** view lets you compare two time periods side by side. +This is useful for identifying changes in performance over time. +This example compares the performance of the `eu-north` region within a given time period against the other regions. + +1. Open Profiles Drilldown in Grafana using the following url: [http://localhost:3000/a/grafana-pyroscope-app/explore](http://localhost:3000/a/grafana-pyroscope-app/explore). +1. Select **Diff flame graph** in the **Exploration** path. +1. Verify that `ride-sharing-app` is selected in the **Service** drop-down menu and `process_cpu/cpu` in the **Profile type** drop-down menu. +1. In **Baseline**, filter by `region` and select `!= eu-north`. +1. In **Comparison**, filter by `region` and select `== eu-north`. +1. In **Choose a preset** drop-down, select the time period you want to compare against. + +Scroll down to compare the two time periods side by side. +Note that the `eu-north` region (right side) shows an excessive amount of time spent in the `find_nearest_vehicle` function. +This looks to be caused by a mutex lock that is causing the function to block. + +{{< figure max-width="100%" src="/media/docs/pyroscope/ride-share-time-comparison-2.png" caption="Time Comparison" alt="Time Comparison" >}} + + + + + +## How was Pyroscope integrated with Grafana in this tutorial? + +The `docker-compose.yml` file includes a Grafana container that's pre-configured with the Pyroscope plugin: + +```yaml + grafana: + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 +``` + +Grafana is also pre-configured with the Pyroscope data source. + +### Challenge + +As a challenge, see if you can generate a similar comparison with the `vehicle` tag. + + + + + +## Summary + +In this tutorial, you learned how to profile a simple "Ride Share" application using Pyroscope. +You have learned some of the core instrumentation concepts such as tagging and how to use Profiles Drilldown identify performance bottlenecks. + +### Next steps + +- Learn more about the Pyroscope SDKs and how to [instrument your application with Pyroscope](https://grafana.com/docs/pyroscope//configure-client/). +- Deploy Pyroscope in a production environment using the [Pyroscope Helm chart](https://grafana.com/docs/pyroscope//deploy-kubernetes/). +- Continue exploring your profile data using [Profiles Drilldown](https://grafana.com/docs/grafana//explore/simplified-exploration/profiles/investigate/) + + + + + + + + + + diff --git a/docs/sources/introduction/continuous-profiling/_index.md b/docs/sources/introduction/continuous-profiling/_index.md index 18bdbea487..90210477ca 100644 --- a/docs/sources/introduction/continuous-profiling/_index.md +++ b/docs/sources/introduction/continuous-profiling/_index.md @@ -1,72 +1,20 @@ --- -title: When to use continuous profiling -menuTitle: When to use continuous profiling +title: What is continuous profiling? +menuTitle: Continuous profiling description: Discover the benefits of continuous profiling and its role in modern application performance analysis. -weight: 20 +weight: 200 keywords: - - pyroscope - - phlare - continuous profiling - flame graphs +refs: + flame-graphs: + - pattern: /docs/pyroscope/ + destination: https://grafana.com/docs/pyroscope//introduction/flamegraphs/ --- -## When to use continuous profiling +# What is continuous profiling? -Continuous profiling is a systematic method of collecting and analyzing performance data from production systems. +[//]: # 'Shared content for the when to use continuous profiling.' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/intro/continuous-profiling.md' -Traditionally, profiling is used as an ad-hoc debugging tool in languages like Go and Java. -You are probably used to running a benchmark tool locally and getting a pprof file in Go or maybe connecting into a misbehaving prod instance and pulling a flame graph from a JFR file in Java. -This is great for debugging but not so great for production. - -![example flame graph](https://grafana.com/static/img/pyroscope/pyroscope-ui-single-2023-11-30.png) - -{{% admonition type="note" %}} -To learn more about flame graphs, refer to [Flame graphs: Visualizing performance data]({{< relref "../../view-and-analyze-profile-data/flamegraphs" >}}). -{{% /admonition %}} - -Continuous profiling is a modern approach which is safer and more scalable for production environments. -It uses low-overhead sampling to collect profiles from production systems and stores the profiles in a database for later analysis. -Using continuous profiling gives you a more holistic view of your application and how it behaves in production. - -## Benefits - -![Diagram showing 3 benefits of continuous profiling](https://grafana.com/static/img/pyroscope/profiling-use-cases-diagram.png) - -Why prioritize continuous profiling? - -1. **In-depth code insights:** It provides granular, line-level insights into how application code utilizes resources, offering the most detailed view of application performance. -2. **Complements other observability tools:** Continuous profiling fills critical gaps left by metrics, logs, and tracing, creating a more comprehensive observability strategy. -3. **Proactive performance optimization:** Regular profiling enables teams to proactively identify and resolve performance bottlenecks, leading to more efficient and reliable applications. - -## Use cases - -![Infographic illustrating key business benefits](https://grafana.com/static/img/pyroscope/cost-cutting-diagram.png) - -Adopting continuous profiling with tools like Pyroscope can lead to significant business advantages: - -1. **Reduced operational costs:** Optimization of resource usage can significantly cut down cloud and infrastructure expenses -2. **Reduced latency:** Identifying and addressing performance bottlenecks leads to faster and more efficient applications -3. **Enhanced incident management:** Faster problem identification and resolution, reducing Mean Time to Resolution (MTTR) and improving end-user experience - -### Reduce operational costs - -Pyroscope's low-overhead profiling enables precise optimization of resource usage, directly impacting various cost centers in technology infrastructure. -By providing in-depth insights into application performance, Pyroscope allows teams to identify and eliminate inefficiencies, leading to significant savings in areas like observability, incident management, messaging/queuing, deployment tools, and infrastructure. - -By using sampling profilers, Pyroscope is able to collect data with minimal overhead (~2-5% depending on a few factors). -The [custom storage engine]({{< relref "../../reference-pyroscope-architecture/about-grafana-pyroscope-architecture" >}}) compresses and stores the data efficiently. -Some advantages of this are: - -- Low CPU overhead thanks to sampling profiler technology -- Control over profiling data granularity (10s to multiple years) -- Efficient compression, low disk space requirements and cost - -### Reduced latency - -Pyroscope plays a pivotal role in reducing application latency by identifying performance bottlenecks at the code level. -This granular insight allows for targeted optimization, leading to faster application response times, improved user experience, and consequently, better business outcomes like increased customer satisfaction and revenue. - -### Enhanced incident management - -Pyroscope streamlines incident management by offering immediate, actionable insights into application performance issues. -With continuous profiling, teams can quickly pinpoint the root cause of an incident, reducing the mean time to resolution (MTTR) and enhancing overall system reliability and user satisfaction. +{{< docs/shared source="pyroscope" lookup="intro/continuous-profiling.md" version="" >}} diff --git a/docs/sources/introduction/flamegraphs.md b/docs/sources/introduction/flamegraphs.md new file mode 100644 index 0000000000..ab3e679eb4 --- /dev/null +++ b/docs/sources/introduction/flamegraphs.md @@ -0,0 +1,19 @@ +--- +title: Flame graphs +menuTitle: Flame graphs +description: Learn about flame graphs to help visualize performance data. +weight: 400 +aliases: + - ../view-and-analyze-profile-data/flamegraphs # https://grafana.com/docs/pyroscope//view-and-analyze-profile-data/flamegraphs/ + - +keywords: + - Pyroscope + - flame graph +--- + +# Flame graphs + +[//]: # 'Shared content for intro to flame graphs.' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/intro/flame-graphs.md' + +{{< docs/shared source="pyroscope" lookup="intro/flame-graphs.md" version="" >}} diff --git a/docs/sources/introduction/profile-tracing/_index.md b/docs/sources/introduction/profile-tracing/_index.md new file mode 100644 index 0000000000..22a6b4df97 --- /dev/null +++ b/docs/sources/introduction/profile-tracing/_index.md @@ -0,0 +1,21 @@ +--- +title: Profiling and tracing integration +menuTitle: Profiling and tracing +description: Learning about how profiling and tracing work together. +weight: 400 +aliases: + - ../introduction/traces-to-profiles/ + - ../introduction/profile-tracing/ + - ../view-and-analyze-profile-data/profile-tracing/ # https://grafana.com/docs/pyroscope/latest/view-and-analyze-profile-data/profile-tracing/ +keywords: + - pyroscope + - continuous profiling + - tracing +--- + +# Profiling and tracing integration + + +[//]: # 'Shared content for Trace to profiles in the Pyroscope data source' + +{{< docs/shared source="grafana" lookup="datasources/pyroscope-profile-tracing-intro.md" version="" >}} diff --git a/docs/sources/introduction/profiling-types/_index.md b/docs/sources/introduction/profiling-types/_index.md new file mode 100644 index 0000000000..8b54f2cf94 --- /dev/null +++ b/docs/sources/introduction/profiling-types/_index.md @@ -0,0 +1,37 @@ +--- +title: Profiling types and their uses +menuTitle: Profiling types +description: Learn about the different profiling types available in Pyroscope and how to effectively use them in your application performance analysis. +weight: 300 +keywords: + - profiles + - profiling types + - application performance + - flame graphs +--- + +# Profiling types and their uses + +Profiling is an essential tool for understanding and optimizing application performance. +In Grafana Pyroscope, various profiling types allow for an in-depth analysis of different aspects of your application. + +## Profiling types + +Profiling types refer to different dimensions of application performance analysis, focusing on specific aspects like CPU usage, memory allocation, or thread synchronization. + +[//]: # 'Shared content for available profile types' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/available-profile-types.md' + +{{< docs/shared source="pyroscope" lookup="available-profile-types.md" version="latest" >}} + +Refer to the [Profile types tables](https://grafana.com/docs/pyroscope//configure-client/profile-types/) for information on supported profile types based on instrumentation method. + +For information on auto-instrumentation and supported language SDKs, refer to [Configure the client](https://grafana.com/docs/pyroscope//configure-client/). + + + +[//]: # 'Shared content for profile type explanations.' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/intro/profile-types-descriptions.md' + +{{< docs/shared source="pyroscope" lookup="intro/profile-types-descriptions.md" version="latest" >}} + diff --git a/docs/sources/introduction/profiling.md b/docs/sources/introduction/profiling.md deleted file mode 100644 index 892ed9740d..0000000000 --- a/docs/sources/introduction/profiling.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: Profiling fundamentals -menuTitle: Profiling fundamentals -description: Discover the benefits of continuous profiling and its role in modern application performance analysis. -weight: 20 -keywords: - - pyroscope - - continuous profiling - - flame graphs ---- - -# Profiling fundamentals - -Profiling is a technique used in software development to measure and analyze the runtime behavior of a program. -By profiling a program, developers can identify which parts of the program consume the most resources, such as CPU time, memory, or I/O operations. -This information can then be used to optimize the program, making it run faster or use fewer resources. - -Pyroscope can be used for both traditional and continuous profiling. - -## Traditional profiling (non-continuous) - -Traditional profiling, often referred to as "sample-based" or "instrumentation-based" profiling, has its roots in the early days of computing. Back then, the primary challenge was understanding how a program utilized the limited computational resources available. - -- **Sample-based profiling**: In this method, the profiler interrupts the program at regular intervals, capturing the program's state each time. By analyzing these snapshots, developers can deduce the frequency at which parts of the code execute. - -- **Instrumentation-based profiling**: Here, developers insert additional code into the program that records information about its execution. This approach provides detailed insights but can alter the program's behavior due to the added code overhead. - -### Benefits - -Traditional profiling provides: - -- **Precision**: Offers a deep dive into specific sections of the code. -- **Control**: Developers can initiate profiling sessions at their discretion, allowing for targeted optimization efforts. -- **Detailed reports**: Provides granular data about program execution, making it easier to pinpoint bottlenecks. - -## Continuous profiling - -As software systems grew in complexity and scale, the limitations of traditional profiling became evident. Issues could arise in production that weren't apparent during limited profiling sessions in the development or staging environments. - -This led to the development of continuous profiling, a method where the profiling data is continuously collected in the background with minimal overhead. By doing so, developers gain a more comprehensive view of a program's behavior over time, helping to identify sporadic or long-term performance issues. - -### Benefits - -Continuous profiling provides: - -- **Consistent monitoring**: Unlike traditional methods that offer snapshots, continuous profiling maintains an uninterrupted view, exposing both immediate and long-term performance issues. -- **Proactive bottleneck detection**: By consistently capturing data, performance bottlenecks are identified and addressed before they escalate, reducing system downtime and ensuring smoother operations. -- **Broad performance landscape**: Provides insights across various platforms, from varied technology stacks to different operating systems, ensuring comprehensive coverage. -- **Bridging the Dev-Prod gap**: Continuous profiling excels in highlighting differences between development and production: - - **Hardware discrepancies**: Unearths issues stemming from differences in machine specifications. - - **Software inconsistencies**: Sheds light on variations in software components that might affect performance. - - **Real-world workload challenges**: Highlights potential pitfalls when real user interactions and loads don't align with development simulations. -- **Economical advantages**: - - **Resource optimization**: Continual monitoring ensures resources aren't wasted, leading to cost savings. - - **Rapid problem resolution**: Faster troubleshooting means reduced time and monetary investment in issue rectification, letting developers channel their efforts into productive endeavors. -- **Non-intrusive operation**: Specifically designed to work quietly in the background, continuous profiling doesn't compromise the performance of live environments. -7. **Real-time response**: It equips teams with the ability to act instantly, addressing issues as they arise rather than post-occurrence, which is crucial for maintaining high system availability. - -## How to choose between traditional and continuous profiling - -In many modern development workflows, both methods are useful. - -### Traditional profiling - - - **When**: During development or testing phases. - - **Advantages**: Offers detailed insights that can target specific parts of code. - - **Disadvantages**: Higher overhead provides only a snapshot in time. - -### Continuous profiling - - - **When**: In production environments or during extended performance tests. - - **Advantages**: Provides a continuous view of system performance, often with minimal overhead, making it suitable for live environments. - - **Disadvantages**: It might be less detailed than traditional profiling due to the need to minimize impact on the running system. diff --git a/docs/sources/introduction/pyroscope-in-grafana.md b/docs/sources/introduction/pyroscope-in-grafana.md index a5f1f6f000..5f10c1b909 100644 --- a/docs/sources/introduction/pyroscope-in-grafana.md +++ b/docs/sources/introduction/pyroscope-in-grafana.md @@ -2,7 +2,7 @@ title: Pyroscope and profiling in Grafana menuTitle: Pyroscope in Grafana description: Learn about how you can use profile data in Grafana. -weight: 200 +weight: 500 keywords: - Pyroscope - Profiling @@ -13,15 +13,15 @@ keywords: # Pyroscope and profiling in Grafana -Pyroscope can be used alongside the other Grafana tools such as Loki, Tempo, Mimir, and k6. -You can use Pyroscope to get the most granular insight into your application and how you can use it to fix issues that you may have identified via metrics, logs, traces, or anything else. +Grafana Pyroscope can be used alongside other Grafana products such as Loki, Tempo, Mimir, and k6. +You can use Pyroscope to get the most granular insight into your application and how you can use it to fix issues that you may have identified using metrics, logs, traces, or anything else. -You can use Pyroscope within Grafana by using the [Pyroscope data source plugin](/docs/grafana/datasources/grafana-pyroscope/). -This plugin lets you query Pyroscope data from within Grafana and visualize it alongside your other Grafana data. +Within Grafana and Grafana Cloud, you can use the [Pyroscope data source](https://grafana.com/docs/grafana//datasources/grafana-pyroscope/) to query and visualize profile data from within Grafana. ## Visualize traces and profiles data -Here is a screenshot of the **Explore** page where combined traces and profiles to be able to see granular line-level detail when available for a trace span. This allows you to see the exact function that's causing a bottleneck in your application as well as a specific request. +Here is a screenshot of the **Explore** page that combines traces and profiles to be able to see granular line-level detail when available for a trace span. +This lets you see the exact function that's causing a bottleneck in your application as well as a specific request. ![trace-profiler-view](https://grafana.com/static/img/pyroscope/pyroscope-trace-profiler-view-2023-11-30.png) diff --git a/docs/sources/introduction/what-is-profiling.md b/docs/sources/introduction/what-is-profiling.md new file mode 100644 index 0000000000..4dae810f81 --- /dev/null +++ b/docs/sources/introduction/what-is-profiling.md @@ -0,0 +1,19 @@ +--- +title: What is profiling? +menuTitle: What is profiling? +description: Discover the types of profiling and how to apply each profiling method. +weight: 100 +keywords: + - pyroscope + - continuous profiling + - flame graphs +aliases: + - ./profiling-fundamentals/ # https://grafana.com/docs/pyroscope//introduction/profiling-fundamentals/ +--- + +# What is profiling? + +[//]: # 'Shared content for What is profiling?' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/intro/what-is-profiling.md' + +{{< docs/shared source="pyroscope" lookup="intro/what-is-profiling.md" version="" >}} diff --git a/docs/sources/reference-pyroscope-architecture/_index.md b/docs/sources/reference-pyroscope-architecture/_index.md index 41c5572759..db2c067b62 100644 --- a/docs/sources/reference-pyroscope-architecture/_index.md +++ b/docs/sources/reference-pyroscope-architecture/_index.md @@ -1,11 +1,11 @@ --- -title: "Pyroscope architecture" -menuTitle: "Reference: Pyroscope Architecture" -description: "Learn about the Pyroscope architecture components and services." +title: "Pyroscope v1 architecture" +menuTitle: "Reference: v1 Architecture" +description: "Learn about the Pyroscope v1 architecture components and services." weight: 600 --- -# Pyroscope architecture +# Pyroscope v1 architecture The following topics include overviews of the Pyroscope architecture. diff --git a/docs/sources/reference-pyroscope-architecture/about-grafana-pyroscope-architecture/index.md b/docs/sources/reference-pyroscope-architecture/about-grafana-pyroscope-architecture/index.md index e15a24c4bc..1d3ce079cb 100644 --- a/docs/sources/reference-pyroscope-architecture/about-grafana-pyroscope-architecture/index.md +++ b/docs/sources/reference-pyroscope-architecture/about-grafana-pyroscope-architecture/index.md @@ -1,35 +1,42 @@ --- -title: "About the Pyroscope architecture" +title: "About the Pyroscope v1 architecture" menuTitle: "About the architecture" -description: "Learn about the Pyroscope architecture." +description: "Learn about the Pyroscope v1 architecture." weight: 10 aliases: - /docs/phlare/latest/operators-guide/architecture/about-grafana-phlare-architecture/ - /docs/phlare/latest/reference-phlare-architecture/about-grafana-phlare-architecture/ --- -# About the Pyroscope architecture +# About the Pyroscope v1 architecture + +{{< admonition type="note" >}} +The Pyroscope v1 architecture is no longer in active development. New deployments should use the [v2 architecture]({{< relref "../reference-pyroscope-v2-architecture/about-pyroscope-v2-architecture" >}}). The v1 architecture will be formally deprecated with the release of Pyroscope v2.0, with the plan to be removed in a future Pyroscope v3.0 release. +{{< /admonition >}} Pyroscope has a microservices-based architecture. The system has multiple horizontally scalable microservices that can run separately and in parallel. Pyroscope microservices are called components. Pyroscope's design compiles the code for all components into a single binary. -The `-target` parameter controls which component(s) that single binary will behave as. For those looking for a simple way to get started, Pyroscope can also be run in [monolithic mode]({{< relref "../deployment-modes/index.md#monolithic-mode" >}}), with all components running simultaneously in one process. -For more information, refer to [Deployment modes]({{< relref "../deployment-modes/index.md" >}}). +The `-target` parameter controls which component(s) that single binary will behave as. For those looking for a simple way to get started, Pyroscope can also be run in [monolithic mode](../deployment-modes/#monolithic-mode), with all components running simultaneously in one process. +For more information, refer to [Deployment modes](../deployment-modes/). ## Pyroscope components -Most components are stateless and do not require any data persisted between process restarts. Some components are stateful and rely on non-volatile storage to prevent data loss between process restarts. For details about each component, see its page in [Components]({{< relref "../components/_index.md" >}}). +Most components are stateless and do not require any data persisted between process restarts. Some components are stateful and rely on non-volatile storage to prevent data loss between process restarts. For details about each component, see its page in [Components](../components/). ### The write path -[//]: # "To edit open with https://mermaid.live/edit#pako{...}" - -

- Architecture of Pyroscope's write path - -

+{{< mermaid >}} +flowchart TD + A["Writes"]:::highlight --> B["Distributor"] + B --> C["Ingester"] + C --> D[("Object storage")]:::highlight + D --> E["Compactor"] + E --> D + classDef highlight fill:#c084fc,color:#000,stroke:#a855f7 +{{< /mermaid >}} Ingesters receive incoming profiles from the distributors. Each push request belongs to a tenant, and the ingester appends the received profiles to the specific per-tenant Pyroscope database that is stored on the local disk. @@ -38,34 +45,38 @@ The per-tenant Pyroscope database is lazily created in each ingester as soon as The in-memory profiles are periodically flushed to disk and new block is created. -For more information, refer to [Ingester]({{< relref "../components/ingester.md" >}}). +For more information, refer to [Ingester](../components/ingester/). #### Series sharding and replication -By default, each profile series is replicated to three ingesters, and each ingester writes its own block to the long-term storage. The [Compactor]({{< relref "../components/compactor" >}}) merges blocks from multiple ingesters into a single block, and removes duplicate samples. Blocks compaction significantly reduces storage utilization. +By default, each profile series is replicated to three ingesters, and each ingester writes its own block to the long-term storage. The [Compactor](../components/compactor/) merges blocks from multiple ingesters into a single block, and removes duplicate samples. Blocks compaction significantly reduces storage utilization. ### The read path -[//]: # "To edit open with https://mermaid.live/edit#pako{...}" - -

- Architecture of Pyroscope's read path - -

+{{< mermaid >}} +flowchart TD + A["Reads"]:::highlight --> B["Query frontend"] + B --> C["Query scheduler"] + D["Querier"] --> C + D --> E["Ingester"] + D --> F["Store-gateway"] + F --> G[("Object storage")]:::highlight + classDef highlight fill:#c084fc,color:#000,stroke:#a855f7 +{{< /mermaid >}} -Queries coming into Pyroscope arrive at [query-frontend]({{< relref "../components/query-frontend" >}}) component which is responsible for accelerating queries and dispatching them to the [query-scheduler]({{< relref "../components/query-scheduler" >}}). +Queries coming into Pyroscope arrive at [query-frontend](../components/query-frontend/) component which is responsible for accelerating queries and dispatching them to the [query-scheduler](../components/query-scheduler/). -The [query-scheduler]({{< relref "../components/query-scheduler" >}}) maintains a queue of queries and ensures that each tenant's queries are fairly executed. +The [query-scheduler](../components/query-scheduler/) maintains a queue of queries and ensures that each tenant's queries are fairly executed. -The [queriers]({{< relref "../components/querier" >}}) act as workers, pulling queries from the queue in the query-scheduler. The queriers connect to the ingesters to fetch all the data needed to execute a query. For more information about how the query is executed, refer to [querier]({{< relref "../components/querier.md" >}}). +The [queriers](../components/querier/) act as workers, pulling queries from the queue in the query-scheduler. The queriers connect to the ingesters to fetch all the data needed to execute a query. For more information about how the query is executed, refer to [querier](../components/querier/). -Depending on the time window selected, the querier involves [ingesters]({{< relref "../components/ingester" >}}) for recent data and [store-gateways]({{< relref "../components/store-gateway" >}}) for data from long-term storage. +Depending on the time window selected, the querier involves [ingesters](../components/ingester/) for recent data and [store-gateways](../components/store-gateway/) for data from long-term storage. ## Long-term storage -The Pyroscope storage format is described in detail in on the [block format page]({{< relref "../block-format" >}}). +The Pyroscope storage format is described in detail on the [block format page](../block-format/). The Pyroscope storage format stores each tenant's profiles into their own on-disk block. Each on-disk block directory contains an index file, a file containing metadata, and the Parquet tables. Pyroscope requires any of the following object stores for the block files: @@ -78,4 +89,4 @@ Pyroscope requires any of the following object stores for the block files: - [OpenStack Swift](https://wiki.openstack.org/wiki/Swift) - Local Filesystem (single node only) -For more information, refer to [configure object storage]({{< relref "../../configure-server/configure-object-storage-backend.md" >}}) and [configure disk storage]({{< relref "../../configure-server/configure-disk-storage.md" >}}). +For more information, refer to [configure object storage](https://grafana.com/docs/pyroscope//configure-server/storage/configure-object-storage-backend/) and [configure disk storage](https://grafana.com/docs/pyroscope//configure-server/storage/configure-disk-storage/). diff --git a/docs/sources/reference-pyroscope-architecture/block-format/_index.md b/docs/sources/reference-pyroscope-architecture/block-format/_index.md index 915c6b1b9e..865cf93688 100644 --- a/docs/sources/reference-pyroscope-architecture/block-format/_index.md +++ b/docs/sources/reference-pyroscope-architecture/block-format/_index.md @@ -9,6 +9,10 @@ aliases: # Pyroscope Block format +{{< admonition type="note" >}} +This page describes the v1 block format. For the v2 block format, refer to [Pyroscope v2 block format]({{< relref "../../reference-pyroscope-v2-architecture/block-format" >}}). +{{< /admonition >}} + This document describes how Pyroscope stores the data in its blocks. Each block belongs to a single tenant and is identified by a unique [ULID]. Within the block there are multiple files: @@ -23,12 +27,7 @@ the block there are multiple files: * `profiles.parquet` [parquet] table that contains profiles. -* `symbols` sub-directory contains profiling symbols that provide a link between - the compiled or interpreted binary code and the original source code: - - A `index.symdb` file with meta information, which helps to find symbols for a specific profile. - - A `stacktraces.symdb` file contains stack traces compacted in the [parent pointer tree]. - - Parquet tables for models referenced by stack traces: - `locations.parquet`, `functions.parquet`, `mappings.parquet`, `strings.parquet`. +* `symbols.symdb` that contains symbolic information for the profiles stored in the block. ## Data model diff --git a/docs/sources/reference-pyroscope-architecture/bucket-index/index.md b/docs/sources/reference-pyroscope-architecture/bucket-index/index.md index bce82cd89b..c47b29b7b9 100644 --- a/docs/sources/reference-pyroscope-architecture/bucket-index/index.md +++ b/docs/sources/reference-pyroscope-architecture/bucket-index/index.md @@ -13,7 +13,7 @@ The bucket index is a per-tenant file that contains the list of blocks and block ## Benefits -The [store-gateway]({{< relref "../components/store-gateway" >}}) must have an almost[^1] up-to-date view of the storage bucket, in order to find the right blocks to look up at query time and to load a block. +The [store-gateway](../components/store-gateway/) must have an almost[^1] up-to-date view of the storage bucket, in order to find the right blocks to look up at query time and to load a block. Because of this, they need to periodically scan the bucket to look for new blocks uploaded by ingesters or compactors, and blocks deleted (or marked for deletion) by compactors. @@ -37,7 +37,7 @@ The `bucket-index.json.gz` contains: ## How it gets updated -The [compactor]({{< relref "../components/compactor" >}}) periodically scans the bucket and uploads an updated bucket index to the storage. +The [compactor](../components/compactor/) periodically scans the bucket and uploads an updated bucket index to the storage. You can configure the frequency with which the bucket index is updated via `-compactor.cleanup-interval`. The use of the bucket index is optional, but the index is built and updated by the compactor even if `-blocks-storage.bucket-store.bucket-index.enabled=false`. @@ -46,7 +46,7 @@ The overhead introduced by keeping the bucket index updated is not significant. ## How it's used by the store-gateway -The [store-gateway]({{< relref "../components/store-gateway" >}}), at startup and periodically, fetches the bucket index for each tenant that belongs to its shard, and uses it as the source of truth for the blocks and deletion marks in the storage. This removes the need to periodically scan the bucket to discover blocks belonging to its shard. +The [store-gateway](../components/store-gateway/), at startup and periodically, fetches the bucket index for each tenant that belongs to its shard, and uses it as the source of truth for the blocks and deletion marks in the storage. This removes the need to periodically scan the bucket to discover blocks belonging to its shard. [^1]: Ingesters regularly add new blocks to the bucket as they offload data to long-term storage, diff --git a/docs/sources/reference-pyroscope-architecture/components/compactor/index.md b/docs/sources/reference-pyroscope-architecture/components/compactor/index.md index 67a2030e18..db9fff6127 100644 --- a/docs/sources/reference-pyroscope-architecture/components/compactor/index.md +++ b/docs/sources/reference-pyroscope-architecture/components/compactor/index.md @@ -9,12 +9,16 @@ weight: 10 # Grafana Pyroscope compactor +{{< admonition type="note" >}} +The compactor is a v1 architecture component. For the v2 equivalent, refer to [compaction worker]({{< relref "../../reference-pyroscope-v2-architecture/components/compaction-worker" >}}). +{{< /admonition >}} + The compactor increases query performance and reduces long-term storage usage by combining blocks. The compactor is the component responsible for: - Compacting multiple blocks of a given tenant into a single, optimized larger block. This deduplicates chunks and reduces the size of the index, resulting in reduced storage costs. Querying fewer blocks is faster, so it also increases query speed. -- Keeping the per-tenant bucket index updated. The [bucket index]({{< relref "../../bucket-index" >}}) is used by [queriers]({{< relref "../querier" >}}) and [store-gateways]({{< relref "../store-gateway" >}}) to discover both new blocks and deleted blocks in the storage. +- Keeping the per-tenant bucket index updated. The [bucket index](../../bucket-index/) is used by [queriers](../querier/) and [store-gateways](../store-gateway/) to discover both new blocks and deleted blocks in the storage. The compactor is stateless. @@ -39,7 +43,7 @@ Compaction can be tuned for clusters with large tenants. Configuration specifies - **Vertical scaling**
The setting `-compactor.compaction-concurrency` configures the max number of concurrent compactions running in a single compactor instance. Each compaction uses one CPU core. - **Horizontal scaling**
- By default, tenant blocks can be compacted by any Grafana Pyroscope compactor. When you enable compactor [shuffle sharding]({{< relref "../../../configure-server/configure-shuffle-sharding" >}}) by setting `-compactor.compactor-tenant-shard-size` (or its respective YAML configuration option) to a value higher than `0` and lower than the number of available compactors, only the specified number of compactors are eligible to compact blocks for a given tenant. + By default, tenant blocks can be compacted by any Grafana Pyroscope compactor. When you enable compactor [shuffle sharding](../../../configure-server/configure-shuffle-sharding/) by setting `-compactor.compactor-tenant-shard-size` (or its respective YAML configuration option) to a value higher than `0` and lower than the number of available compactors, only the specified number of compactors are eligible to compact blocks for a given tenant. ## Compaction algorithm @@ -74,9 +78,9 @@ The compactor shards compaction jobs, either from a single tenant or multiple te Whenever the pool of compactors grows or shrinks, tenants and jobs are resharded across the available compactor instances without any manual intervention. -Compactor sharding uses a [hash ring]({{< relref "../../hash-ring/index.md" >}}). At startup, a compactor generates random tokens and registers itself to the compactor hash ring. While running, it periodically scans the storage bucket at every interval defined by `-compactor.compaction-interval`, to discover the list of tenants in storage and to compact blocks for each tenant whose hash matches the token ranges assigned to the instance itself within the hash ring. +Compactor sharding uses a [hash ring](../../hash-ring/). At startup, a compactor generates random tokens and registers itself to the compactor hash ring. While running, it periodically scans the storage bucket at every interval defined by `-compactor.compaction-interval`, to discover the list of tenants in storage and to compact blocks for each tenant whose hash matches the token ranges assigned to the instance itself within the hash ring. -To configure the compactors' hash ring, refer to [configuring memberlist]({{< relref "../../../configure-server/configuring-memberlist" >}}). +To configure the compactors' hash ring, refer to [configuring memberlist](../../../configure-server/configuring-memberlist/). ### Waiting for a stable hash ring at startup @@ -128,5 +132,5 @@ compactor.compaction-concurrency * max_compaction_range_blocks_size * 2 ## Compactor configuration -Refer to the [compactor]({{< relref "../../../configure-server/reference-configuration-parameters#compactor" >}}) -block section and the [limits]({{< relref "../../../configure-server/reference-configuration-parameters#limits" >}}) block section for details of compaction-related configuration. +Refer to the [compactor](../../../configure-server/reference-configuration-parameters/#compactor) +block section and the [limits](../../../configure-server/reference-configuration-parameters/#limits) block section for details of compaction-related configuration. diff --git a/docs/sources/reference-pyroscope-architecture/components/distributor.md b/docs/sources/reference-pyroscope-architecture/components/distributor.md index d9ba6ea9c4..6cfd75603e 100644 --- a/docs/sources/reference-pyroscope-architecture/components/distributor.md +++ b/docs/sources/reference-pyroscope-architecture/components/distributor.md @@ -10,7 +10,7 @@ aliases: # Pyroscope distributor The distributor is a stateless component that receives profiling data from the agent. -The distributor then divides the data into batches and sends it to multiple [ingesters]({{< relref "./ingester.md" >}}) in parallel, shards the series among ingesters, and replicates each series by the configured replication factor. By default, the configured replication factor is three. +The distributor then divides the data into batches and sends it to multiple [ingesters](../ingester/) in parallel, shards the series among ingesters, and replicates each series by the configured replication factor. By default, the configured replication factor is three. ## Validation @@ -35,7 +35,7 @@ For each incoming series, the distributor computes a hash using the profile name The computed hash is called a _token_. The distributor looks up the token in the hash ring to determine which ingesters to write a series to. -For more information, see [hash ring]({{< relref "../hash-ring/index.md" >}}). +For more information, see [hash ring](../../hash-ring/). #### Quorum consistency diff --git a/docs/sources/reference-pyroscope-architecture/components/ingester.md b/docs/sources/reference-pyroscope-architecture/components/ingester.md index 6ead3a13f4..131345f0c9 100644 --- a/docs/sources/reference-pyroscope-architecture/components/ingester.md +++ b/docs/sources/reference-pyroscope-architecture/components/ingester.md @@ -9,13 +9,17 @@ aliases: # Pyroscope ingester -The ingester is a stateful component that writes incoming profiles first to [on disk storage]({{< relref "../about-grafana-pyroscope-architecture/index.md#long-term-storage" >}}) on the write path and returns series samples for queries on the read path. +{{< admonition type="note" >}} +The ingester is a v1 architecture component. For the v2 equivalent, refer to [segment writer]({{< relref "../../reference-pyroscope-v2-architecture/components/segment-writer" >}}). +{{< /admonition >}} -Incoming profiles from [distributors]({{< relref "./distributor.md" >}}) are not immediately written to the long-term storage but are either kept in the ingester's memory or offloaded to the ingester's disk. +The ingester is a stateful component that writes incoming profiles first to [on disk storage](../../about-grafana-pyroscope-architecture/#long-term-storage) on the write path and returns series samples for queries on the read path. + +Incoming profiles from [distributors](../distributor/) are not immediately written to the long-term storage but are either kept in the ingester's memory or offloaded to the ingester's disk. Eventually, all profiles are written to disk and periodically uploaded to the long-term storage. -For this reason, the [queriers]({{< relref "./querier.md" >}}) might need to fetch samples from both ingesters and long-term storage while executing a query on the read path. +For this reason, the [queriers](../querier/) might need to fetch samples from both ingesters and long-term storage while executing a query on the read path. -Any Pyroscope component that calls the ingesters starts by first looking up ingesters registered in the [hash ring]({{< relref "../hash-ring/index.md" >}}) to determine which ingesters are available. +Any Pyroscope component that calls the ingesters starts by first looking up ingesters registered in the [hash ring](../../hash-ring/) to determine which ingesters are available. Each ingester could be in one of the following states: - `PENDING`
@@ -31,7 +35,7 @@ Each ingester could be in one of the following states: - `UNHEALTHY`
The ingester has failed to heartbeat to the hash ring. While in this state, distributors bypass the ingester, which means that the ingester does not receive write or read requests. -To configure the ingesters' hash ring, refer to [configuring memberlist]({{< relref "../../configure-server/configuring-memberlist.md" >}}). +To configure the ingesters' hash ring, refer to [configuring memberlist](../../../configure-server/configuring-memberlist/). ## Ingesters write de-amplification diff --git a/docs/sources/reference-pyroscope-architecture/components/querier.md b/docs/sources/reference-pyroscope-architecture/components/querier.md index b34614edc1..10f02886ae 100644 --- a/docs/sources/reference-pyroscope-architecture/components/querier.md +++ b/docs/sources/reference-pyroscope-architecture/components/querier.md @@ -7,9 +7,13 @@ weight: 50 # Pyroscope querier +{{< admonition type="note" >}} +The querier is a v1 architecture component. For the v2 equivalent, refer to [query backend]({{< relref "../../reference-pyroscope-v2-architecture/components/query-backend" >}}). +{{< /admonition >}} + The querier is a stateless component that evaluates query expressions by fetching profiles series and labels on the read path. -The querier uses the [ingesters]({{< relref "./ingester.md" >}}) for gathering recently written data and the [store-gateways] for the [long-term storage]({{< relref "../about-grafana-pyroscope-architecture/index.md#long-term-storage" >}}). +The querier uses the [ingesters](../ingester/) for gathering recently written data and the [store-gateways] for the [long-term storage](../../about-grafana-pyroscope-architecture/#long-term-storage). ### Connecting to ingesters @@ -17,4 +21,4 @@ You must configure the querier with the same `-ingester.ring.*` flags (or their ## Querier configuration -For details about querier configuration, refer to [querier]({{< relref "../../configure-server/reference-configuration-parameters/index.md#querier" >}}). +For details about querier configuration, refer to [querier](../../../configure-server/reference-configuration-parameters/#querier). diff --git a/docs/sources/reference-pyroscope-architecture/components/query-frontend/index.md b/docs/sources/reference-pyroscope-architecture/components/query-frontend/index.md index ffd289ef34..d6f0ea7f2b 100644 --- a/docs/sources/reference-pyroscope-architecture/components/query-frontend/index.md +++ b/docs/sources/reference-pyroscope-architecture/components/query-frontend/index.md @@ -7,13 +7,13 @@ weight: 60 # Pyroscope query-frontend -The query-frontend is a stateless component that provides the same API as the [querier]({{< relref "../querier.md" >}}) and can be used to accelerate the read path and ensure fair scheduling between tenants using the [query-scheduler]({{< relref "../query-scheduler/index.md" >}}). +The query-frontend is a stateless component that provides the same API as the [querier](../querier/) and can be used to accelerate the read path and ensure fair scheduling between tenants using the [query-scheduler](../query-scheduler/). In this situation, queriers act as workers that pull jobs from the queue, execute them, and return the results to the query-frontend for aggregation. We recommend that you run at least two query-frontend replicas for high-availability reasons. -> Because the [query-scheduler]({{< relref "../query-scheduler" >}}) is a mandatory component when using the query-frontend, you must run at least one query-scheduler replica. +> Because the [query-scheduler](../query-scheduler/) is a mandatory component when using the query-frontend, you must run at least one query-scheduler replica. The following steps describe how a query moves through the query-frontend. diff --git a/docs/sources/reference-pyroscope-architecture/components/query-scheduler/index.md b/docs/sources/reference-pyroscope-architecture/components/query-scheduler/index.md index 22e8257b60..72620e1e67 100644 --- a/docs/sources/reference-pyroscope-architecture/components/query-scheduler/index.md +++ b/docs/sources/reference-pyroscope-architecture/components/query-scheduler/index.md @@ -7,9 +7,13 @@ weight: 120 # Pyroscope query-scheduler -The query-scheduler is a stateless component that retains a queue of queries to execute, and distributes the workload to available [queriers]({{< relref "../querier.md" >}}). +{{< admonition type="note" >}} +The query-scheduler is a v1 architecture component. In v2, the [query frontend]({{< relref "../../reference-pyroscope-v2-architecture/components/query-frontend" >}}) communicates directly with [query backends]({{< relref "../../reference-pyroscope-v2-architecture/components/query-backend" >}}) without an intermediary scheduler. +{{< /admonition >}} -The query-scheduler is a required component when using the [query-frontend]({{< relref "../query-frontend/index.md" >}}). +The query-scheduler is a stateless component that retains a queue of queries to execute, and distributes the workload to available [queriers](../querier/). + +The query-scheduler is a required component when using the [query-frontend](../query-frontend/). ![Query-scheduler architecture](query-scheduler-architecture.png) @@ -17,7 +21,7 @@ The query-scheduler is a required component when using the [query-frontend]({{< The following flow describes how a query moves through a Pyroscope cluster: -1. The [query-frontend]({{< relref "../query-frontend/index.md" >}}) receives queries, and then either splits and shards them, or serves them from the cache. +1. The [query-frontend](../query-frontend/) receives queries, and then either splits and shards them, or serves them from the cache. 1. The query-frontend enqueues the queries into a query-scheduler. 1. The query-scheduler stores the queries in an in-memory queue where they wait for a querier to pick them up. 1. Queriers pick up the queries, and executes them. @@ -30,7 +34,7 @@ Query-scheduler enables the scaling of query-frontends. To learn more, see Mimir ## Configuration To use the query-scheduler, query-frontends and queriers need to discover the addresses of query-scheduler instances. -To advertise itself, the query-scheduler uses Ring-based service discovery which is configured via the [memberlist configuration]({{< relref "../../../configure-server/configuring-memberlist.md" >}}). +To advertise itself, the query-scheduler uses Ring-based service discovery which is configured via the [memberlist configuration](../../../configure-server/configuring-memberlist/). ## Operational considerations diff --git a/docs/sources/reference-pyroscope-architecture/components/store-gateway.md b/docs/sources/reference-pyroscope-architecture/components/store-gateway.md index 8793d665be..a810a8f485 100644 --- a/docs/sources/reference-pyroscope-architecture/components/store-gateway.md +++ b/docs/sources/reference-pyroscope-architecture/components/store-gateway.md @@ -7,8 +7,12 @@ weight: 55 # Pyroscope Store-gateway -The store-gateways in Pyroscope are responsible for looking up profiling data in the [long-term storage]({{< relref "../about-grafana-pyroscope-architecture/index.md#long-term-storage" >}}) bucket. A single store-gateway is responsible for a subset of the blocks in the long-term storage and will be involved by a [querier]. +{{< admonition type="note" >}} +The store-gateway is a v1 architecture component. In v2, its responsibilities are handled by the [metastore]({{< relref "../../reference-pyroscope-v2-architecture/components/metastore" >}}) (for metadata) and [query backend]({{< relref "../../reference-pyroscope-v2-architecture/components/query-backend" >}}) (for data access). +{{< /admonition >}} + +The store-gateways in Pyroscope are responsible for looking up profiling data in the [long-term storage](../../about-grafana-pyroscope-architecture/#long-term-storage) bucket. A single store-gateway is responsible for a subset of the blocks in the long-term storage and will be involved by a [querier]. ## Store-gateway configuration -For details about store-gateway configuration, refer to [store-gateway]({{< relref "../../configure-server/reference-configuration-parameters/index.md#store_gateway" >}}). +For details about store-gateway configuration, refer to [store-gateway](../../../configure-server/reference-configuration-parameters/#store_gateway). diff --git a/docs/sources/reference-pyroscope-architecture/deployment-modes/index.md b/docs/sources/reference-pyroscope-architecture/deployment-modes/index.md index 5897e1331d..21b6ce03d4 100644 --- a/docs/sources/reference-pyroscope-architecture/deployment-modes/index.md +++ b/docs/sources/reference-pyroscope-architecture/deployment-modes/index.md @@ -36,7 +36,7 @@ Monolithic mode can be horizontally scaled out by deploying multiple Pyroscope b In microservices mode, components are deployed in distinct processes. Scaling is per component, which allows for greater flexibility in scaling and more granular failure domains. Microservices mode is the preferred method for a production deployment, but it is also the most complex. -In microservices mode, each Pyroscope process is invoked with its `-target` parameter set to a specific Pyroscope component (for example, `-target=ingester` or `-target=distributor`). To get a working Pyroscope instance, you must deploy every required component. For more information about each of the Pyroscope components, refer to [Architecture]({{< relref ".." >}}). +In microservices mode, each Pyroscope process is invoked with its `-target` parameter set to a specific Pyroscope component (for example, `-target=ingester` or `-target=distributor`). To get a working Pyroscope instance, you must deploy every required component. For more information about each of the Pyroscope components, refer to [Architecture](../). If you are interested in deploying Pyroscope in microservices mode, we recommend that you use [Kubernetes](https://kubernetes.io/). diff --git a/docs/sources/reference-pyroscope-architecture/hash-ring/index.md b/docs/sources/reference-pyroscope-architecture/hash-ring/index.md index a411031df0..5743b7d108 100644 --- a/docs/sources/reference-pyroscope-architecture/hash-ring/index.md +++ b/docs/sources/reference-pyroscope-architecture/hash-ring/index.md @@ -19,7 +19,7 @@ This value is called _token_ and used as the ID of the data. The token determines the location on the hash ring deterministically. This allows independent determination of what instance of Pyroscope is the authoritative owner of any specific data. -For example, profiles are sharded across [ingesters]({{< relref "../components/ingester.md" >}}). +For example, profiles are sharded across [ingesters](../components/ingester/). The token of a given profile is computed by hashing all of the profile’s labels and the tenant ID: the result of which is an unsigned 32-bit integer within the space of the tokens. The ingester that owns that series is the instance that owns the range of the tokens, including the profile token. @@ -72,8 +72,8 @@ On average, the number of tokens that need to move to a different instance is on There are several Pyroscope components that need a hash ring. Each of the following components builds an independent hash ring: -- [Ingesters]({{< relref "../components/ingester.md" >}}) shard and replicate series. -- [Distributors]({{< relref "../components/distributor.md" >}}) enforce rate limits. +- [Ingesters](../components/ingester/) shard and replicate series. +- [Distributors](../components/distributor/) enforce rate limits. ## How the hash ring is shared between Pyroscope instances @@ -81,7 +81,7 @@ Hash ring data structures need to be shared between Pyroscope instances. To propagate changes to the hash ring, Pyroscope uses a key-value store. The key-value store is required and can be configured independently for the hash rings of different components. -For more information, see the [memberlist documentation]({{< relref "../memberlist-and-the-gossip-protocol.md" >}}). +For more information, see the [memberlist documentation](../memberlist-and-the-gossip-protocol/). ## Features that are built using the hash ring diff --git a/docs/sources/reference-pyroscope-architecture/memberlist-and-the-gossip-protocol.md b/docs/sources/reference-pyroscope-architecture/memberlist-and-the-gossip-protocol.md index a09644fb2f..3521e110d3 100644 --- a/docs/sources/reference-pyroscope-architecture/memberlist-and-the-gossip-protocol.md +++ b/docs/sources/reference-pyroscope-architecture/memberlist-and-the-gossip-protocol.md @@ -10,13 +10,13 @@ weight: 80 [Memberlist](https://github.com/hashicorp/memberlist) is a Go library that manages cluster membership, node failure detection, and message passing using a gossip-based protocol. Memberlist is eventually consistent and network partitions are partially tolerated by attempting to communicate to potentially dead nodes through multiple routes. -Pyroscope uses memberlist to implement the [hash ring]({{< relref "./hash-ring" >}}) data structures between instances. +Pyroscope uses memberlist to implement the [hash ring](../hash-ring/) data structures between instances. Each instance maintains a copy of the hash rings. Each Pyroscope instance updates a hash ring locally and uses memberlist to propagate the changes to other instances. Updates generated locally and updates received from other instances are merged together to form the current state of the ring on the instance. -To configure memberlist, refer to [configuring memberlist]({{< relref "../configure-server/configuring-memberlist.md" >}}). +To configure memberlist, refer to [configuring memberlist](../../configure-server/configuring-memberlist/). ## How memberlist propagates hash ring changes diff --git a/docs/sources/reference-pyroscope-v2-architecture/_index.md b/docs/sources/reference-pyroscope-v2-architecture/_index.md new file mode 100644 index 0000000000..9ac10f89e7 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/_index.md @@ -0,0 +1,14 @@ +--- +title: "Pyroscope v2 architecture" +menuTitle: "Reference: v2 Architecture" +description: "Learn about the Pyroscope v2 architecture components and services." +weight: 601 +--- + +# Pyroscope v2 architecture + +Pyroscope v2 is a complete architectural redesign focused on improving scalability, performance, and cost-efficiency. The biggest change in v2 is how it handles storage: data is written directly to object storage, removing the need for local disks in ingesters. + +The following topics include overviews of the Pyroscope v2 architecture. + +{{< section menuTitle="true" >}} diff --git a/docs/sources/reference-pyroscope-v2-architecture/about-pyroscope-v2-architecture/index.md b/docs/sources/reference-pyroscope-v2-architecture/about-pyroscope-v2-architecture/index.md new file mode 100644 index 0000000000..b33587f049 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/about-pyroscope-v2-architecture/index.md @@ -0,0 +1,121 @@ +--- +title: "About the Pyroscope v2 architecture" +menuTitle: "About the architecture" +description: "Learn about the Pyroscope v2 architecture and its key design principles." +weight: 10 +keywords: + - Pyroscope v2 + - architecture + - object storage + - scalability +--- + +# About the Pyroscope v2 architecture + +Pyroscope v2 is a complete architectural redesign focused on improving scalability, performance, and cost-efficiency. The architecture is built around the following goals: + +- Deliver high write throughput +- Provide cost-effective storage +- Enable scalable query performance +- Reduce operational overhead + +For background on the v1 limitations that motivated this redesign, refer to [Design motivation](../design-motivation/). + +## Key design changes + +The biggest change in Pyroscope v2 is how it handles storage: data is written directly to object storage, removing the need for local disks in ingesters. For single-node deployments, local file systems can still be used as object storage, but this setup isn't supported in microservice mode. + +Pyroscope v2 also decouples the write and query paths. This means each path can scale independently, so even the heaviest queries won't interfere with ingestion performance. The read path can scale to hundreds of instances instantly. + +## Architecture overview + +The high-level components of the architecture include: + +{{< mermaid >}} +graph TD + + subgraph entry_points[" "] + ingest_entry["Ingest Path"]:::entry_ingest --> distributor + query_entry["Query Path"]:::entry_query --> query_frontend + end + + distributor -->|writes to| segment_writer + segment_writer -->|updates| metastore + segment_writer -->|creates segments| object_storage + + metastore -->|coordinates| compaction_worker + compaction_worker -->|compacts| object_storage + + query_frontend -->|invokes| query_backend + query_backend -->|reads from| object_storage + query_frontend -->|queries| metastore + + distributor["distributor"] + segment_writer["segment-writer"] + metastore["metastore"] + compaction_worker["compaction-worker"] + query_backend["query-backend"] + query_frontend["query-frontend"] + + subgraph object_storage["object storage"] + segments + blocks + end + + linkStyle 0 stroke:#a855f7,stroke-width:2px + linkStyle 1 stroke:#3b82f6,stroke-width:2px + linkStyle 2,3,4 stroke:#a855f7,stroke-width:2px + linkStyle 6 stroke:#a855f7,stroke-width:2px + linkStyle 7,8,9 stroke:#3b82f6,stroke-width:2px + + classDef entry_ingest stroke:#a855f7,stroke-width:2px,font-weight:bold + classDef entry_query stroke:#3b82f6,stroke-width:2px,font-weight:bold +{{< /mermaid >}} + +## Pyroscope v2 components + +Most components in v2 are stateless and don't require any data persisted between process restarts. The metastore is the only stateful component, using Raft consensus for replication. For details about each component, refer to [Components](../components/). + +### The write path + +Profiles are ingested through the Push RPC API and HTTP `/ingest` API to [distributors](../components/distributor/). The write path includes distributor and [segment-writer](../components/segment-writer/) services: both are stateless, disk-less, and scale horizontally with high efficiency. + +Profile ingest requests are distributed among distributors, which then route them to segment-writers to co-locate profiles from the same application. This ensures that profiles likely to be queried together are stored together. + +The segment-writer service accumulates profiles in small blocks (segments) and writes them to object storage while updating the block index with metadata of newly added objects. Each writer produces a single object per shard containing data of all tenant services per shard; this approach minimizes the number of write operations to the object storage, optimizing the cost of the solution. + +Ingestion clients are blocked until data is durably stored in object storage and an entry for the object is created in the metadata index. By default, ingestion is synchronous, with median latency expected to be less than 500ms using default settings. + +### The read path + +Profiling data is queried through the Query API available in the [query-frontend](../components/query-frontend/) service. + +A regular flame graph query users see in the UI may require fetching many gigabytes of data from storage. Moreover, the raw profiling data needs expensive post-processing to be displayed in flame graph format. Pyroscope addresses this challenge through adaptive data placement that minimizes the number of objects that need to be read to satisfy a query, and high parallelism in query execution. + +The query frontend is responsible for preliminary query planning and routing the query to the [query-backend](../components/query-backend/) service. Data objects are located using the [metastore](../components/metastore/) service, which maintains the metadata index. + +Queries are executed by the query-backend service with high parallelism. Query execution is represented as a graph where the results of sub-queries are combined and optimized. This minimizes network overhead and enables horizontal scalability of the read path without needing traditional disk-based solutions or even a caching layer. + +Both query-frontend and query-backend are stateless services that can scale out to hundreds of instances. + +### Compaction + +The number of objects created in storage can reach millions per hour. This can severely degrade query performance due to high read amplification and excessive calls to object storage. Additionally, a high number of metadata entries can degrade performance across the entire cluster, impacting the write path as well. + +To ensure high query performance, data objects are compacted in the background. The [compaction-worker](../components/compaction-worker/) service is responsible for merging small segments into larger blocks, which are then written back to object storage. Compaction workers compact data as soon as possible after it's written to object storage, with median time to the first compaction not exceeding 15 seconds. + +Compaction workers are coordinated by the metastore service, which maintains the metadata index and schedules compaction jobs. Compaction workers are stateless and don't require any local storage. + +For more details, refer to [Compaction](../compaction/). + +## Object storage + +Pyroscope v2 is designed to operate without local disks, relying entirely on object storage. This approach minimizes operational overhead and cost. + +Pyroscope requires any of the following object stores for block files: + +- [Amazon S3](https://aws.amazon.com/s3) +- [Google Cloud Storage](https://cloud.google.com/storage/) +- [Microsoft Azure Storage](https://azure.microsoft.com/en-us/services/storage/) +- [OpenStack Swift](https://wiki.openstack.org/wiki/Swift) +- Local Filesystem (single node only) diff --git a/docs/sources/reference-pyroscope-v2-architecture/block-format/index.md b/docs/sources/reference-pyroscope-v2-architecture/block-format/index.md new file mode 100644 index 0000000000..9b33e654ca --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/block-format/index.md @@ -0,0 +1,77 @@ +--- +title: "Block format" +menuTitle: "Block format" +description: "Learn how Pyroscope v2 stores profiling data in object storage." +weight: 40 +keywords: + - Pyroscope v2 + - block format + - object storage + - datasets +--- + +# Block format + +In Pyroscope v2, a block is a single object in object storage (`block.bin`) containing data from one or more _datasets_. Each dataset holds profiling data for a specific service and includes its own TSDB index, symbol data, and profile tables. Block metadata — stored in the [metastore](../components/metastore/) and embedded in the object itself — describes the datasets, their labels, and byte offsets within the object. + +## Object storage layout + +Segments (level 0, not yet compacted) and compacted blocks are stored in separate top-level directories. Segments are not yet split by tenant and use an anonymous tenant directory. After compaction, blocks are organized by tenant: + +``` +segments/ + {shard}/ + anonymous/ + {block_id}/ + block.bin + +blocks/ + {shard}/ + {tenant}/ + {block_id}/ + block.bin + +dlq/ + {shard}/ + {tenant}/ + {block_id}/ + block.bin +``` + +## Block structure + +Each `block.bin` object contains a sequence of datasets followed by a metadata footer: + +``` +Offset | Content +----------|------------------------------------------- +0 | Dataset 0 data + | Dataset 1 data + | ... + | Dataset N data + | Protobuf-encoded block metadata +end-8 | uint32 (big-endian): raw metadata size +end-4 | uint32 (big-endian): CRC32 of metadata + size +``` + +## Datasets + +A dataset is a self-contained region within the block that stores profiling data for a specific service. Each dataset contains: + +* A [TSDB index](https://ganeshvernekar.com/blog/prometheus-tsdb-persistent-block-and-its-index/) mapping series labels to profiles +* Symbol data (`symbols.symdb`) for stack traces and function names +* A [Parquet](https://parquet.apache.org/docs/) table of profile samples + +Datasets are annotated with labels (such as `service_name` and `profile_type`) that allow the query path to select only the relevant datasets without reading the entire block. + +A separate tenant-wide dataset index allows queries that don't target a specific service to locate the relevant datasets. + +## Block metadata + +Block metadata is a protobuf-encoded structure that describes the block's contents: + +* Block ID ([ULID](https://github.com/ulid/spec)), tenant, shard, compaction level, and time range +* A list of datasets with their byte offsets (table of contents), labels, and sizes +* A string table for deduplicating strings across the metadata entry + +The metadata is stored both in the [metastore](../components/metastore/) index and embedded in the block object itself. diff --git a/docs/sources/reference-pyroscope-v2-architecture/compaction/index.md b/docs/sources/reference-pyroscope-v2-architecture/compaction/index.md new file mode 100644 index 0000000000..5bcab89013 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/compaction/index.md @@ -0,0 +1,156 @@ +--- +title: "Compaction" +menuTitle: "Compaction" +description: "Learn how Pyroscope v2 compacts segments into optimized blocks." +weight: 60 +keywords: + - Pyroscope v2 + - compaction + - blocks + - segments +--- + +# Compaction + +Compaction is the process of merging multiple small segments into larger, optimized blocks. This is essential for maintaining query performance and controlling metadata index size. + +## Why compaction matters + +The ingestion pipeline creates many small segments—potentially millions of objects per hour at scale. Without compaction: + +- **Read amplification**: Queries must fetch many small objects +- **API costs**: More calls to object storage +- **Metadata bloat**: The metastore index grows unboundedly +- **Performance degradation**: Impacts both read and write paths + +## How it works + +Compaction in Pyroscope v2 is coordinated by the [metastore](../components/metastore/) and executed by [compaction-workers](../components/compaction-worker/). + +{{< mermaid >}} +sequenceDiagram + participant W as Compaction Worker + participant M as Metastore + participant S as Object Storage + + loop Continuous + W->>M: Poll for jobs + M->>W: Assign job with source blocks + W->>S: Download source segments + W->>W: Merge segments into block + W->>S: Upload compacted block + W->>M: Report completion + M->>M: Update metadata index + end +{{< /mermaid >}} + +## Compaction service + +The compaction service runs within the metastore and is responsible for: + +- **Job planning**: Creating compaction jobs when enough segments are available +- **Job scheduling**: Assigning jobs to workers based on capacity +- **Job tracking**: Monitoring progress and handling failures +- **Index updates**: Replacing source block entries with compacted block entries + +### Raft consistency + +The compaction service relies on Raft to guarantee consistency: + +1. **Plan preparation**: The leader prepares job state changes (read-only). +1. **Plan proposal**: Changes are committed to the Raft log. +1. **State update**: All replicas apply the changes atomically. + +This ensures all replicas maintain consistent views of compaction state. + +## Job planner + +The job planner maintains a queue of blocks eligible for compaction: + +- **Queue structure**: FIFO queue, segmented by tenant, shard, and level +- **Job creation**: Jobs are created when enough blocks are queued +- **Boundaries**: Compaction never crosses tenant, shard, or level boundaries + +### Data layout + +Profiling data from each service is stored as a separate dataset within a block. During compaction: + +- Matching datasets from source blocks are merged +- TSDB indexes are combined +- Symbols and profile tables are merged and rewritten +- Output block contains optimized, non-overlapping datasets + +## Job scheduler + +The scheduler uses a **Small Job First** strategy: + +1. Lower-level blocks are prioritized (smaller, affect read amplification more). +1. Within a level, unassigned jobs are processed first. +1. Jobs with fewer failures are prioritized. +1. Jobs with earlier lease expiration are considered first. + +### Adaptive capacity + +Workers specify available capacity when polling for jobs. The scheduler: + +- Creates jobs based on reported worker capacity +- Balances queue size with worker utilization +- Adapts to available resources automatically + +## Job ownership + +Jobs are assigned using a lease-based model: + +- **Lease duration**: Workers are granted ownership for a limited time +- **Fencing tokens**: Raft log index serves as a unique token +- **Lease refresh**: Workers must refresh leases before expiration +- **Reassignment**: Expired leases allow job reassignment + +### Failure handling + +When a worker fails: + +1. The job lease expires. +1. The metastore detects the expired lease. +1. The job is reassigned to another worker. +1. Source blocks remain until compaction succeeds. + +Jobs that repeatedly fail are deprioritized to prevent blocking the queue. + +## Job status lifecycle + +{{< mermaid >}} +stateDiagram-v2 + [*] --> Unassigned : Create Job + Unassigned --> InProgress : Assign Job + InProgress --> Success : Job Completed + InProgress --> LeaseExpired: Job Lease Expires + LeaseExpired: Abandoned Job + + LeaseExpired --> Excluded: Failure Threshold Exceeded + Excluded: Faulty Job + + Success --> [*] : Remove Job from Schedule + LeaseExpired --> InProgress : Reassign Job +{{< /mermaid >}} + +## Performance characteristics + +- **Median time to first compaction**: Less than 15 seconds +- **Continuous operation**: Workers constantly poll for new jobs +- **Horizontal scaling**: Add more workers to handle compaction backlog +- **Priority-based**: Smaller blocks compacted first for fastest impact + +## Block deletion + +After successful compaction: + +1. **Tombstone creation**: Source blocks are marked for deletion. +1. **Delay period**: Blocks are retained to allow in-flight queries to complete. +1. **Hard deletion**: After the delay, source blocks are removed from storage. + +This two-phase deletion prevents query failures during compaction. + +## Implementation details + +For detailed implementation information, including job scheduling algorithms and lease management, refer to the [internal documentation](https://github.com/grafana/pyroscope/blob/main/pkg/metastore/compaction/README.md). diff --git a/docs/sources/reference-pyroscope-v2-architecture/components/_index.md b/docs/sources/reference-pyroscope-v2-architecture/components/_index.md new file mode 100644 index 0000000000..2e67114423 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/components/_index.md @@ -0,0 +1,22 @@ +--- +title: "Pyroscope v2 components" +menuTitle: "Components" +description: "Pyroscope v2 includes a set of components that interact to form a cluster." +weight: 30 +keywords: + - Pyroscope v2 components + - Pyroscope distributor + - Pyroscope segment-writer + - Pyroscope metastore + - Pyroscope compaction-worker + - Pyroscope query-frontend + - Pyroscope query-backend +--- + +# Pyroscope v2 components + +Pyroscope v2 includes a set of components that interact to form a cluster. + +Most components are stateless and don't require any data persisted between process restarts. The [metastore](metastore/) is the only stateful component in the architecture, using Raft consensus for replication and fault tolerance. + +{{< section menuTitle="true" >}} diff --git a/docs/sources/reference-pyroscope-v2-architecture/components/compaction-worker.md b/docs/sources/reference-pyroscope-v2-architecture/components/compaction-worker.md new file mode 100644 index 0000000000..6100575948 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/components/compaction-worker.md @@ -0,0 +1,87 @@ +--- +title: "Pyroscope v2 compaction-worker" +menuTitle: "Compaction-worker" +description: "The compaction-worker merges small segments into larger blocks." +weight: 40 +keywords: + - Pyroscope v2 + - compaction-worker + - compaction + - blocks +--- + +# Pyroscope v2 compaction-worker + +The compaction-worker is a stateless component responsible for merging small segments into larger blocks. This improves query performance by reducing the number of objects that need to be read from object storage. + +## Why compaction is needed + +The ingestion pipeline creates many small segments—potentially millions of objects per hour at scale. Without compaction, this leads to: + +- **Read amplification**: Queries must fetch many small objects +- **Increased costs**: More API calls to object storage +- **Metadata bloat**: The metastore index grows unboundedly +- **Performance degradation**: Both read and write paths slow down + +## How it works + +1. **Job polling**: Workers poll the [metastore](../metastore/) for available compaction jobs. +1. **Segment download**: Workers download source segments from object storage. +1. **Merge operation**: Matching datasets from different segments are merged. +1. **Block upload**: The compacted block is uploaded to object storage. +1. **Status report**: Workers report job completion to the metastore. + +## Compaction speed + +Compaction workers compact data as soon as possible after it's written to object storage: + +- **Median time to first compaction**: Less than 15 seconds +- **Continuous operation**: Workers constantly poll for new jobs + +This ensures that query performance remains optimal even during high ingestion rates. + +## Job scheduling + +Compaction jobs are coordinated by the metastore, which: + +- Creates jobs when enough segments are available for compaction +- Assigns jobs to workers based on available capacity +- Tracks job progress and handles failures +- Uses a "Small Job First" strategy to prioritize smaller blocks + +Workers specify their available capacity when polling for jobs, allowing the system to adapt to the available resources. + +## Data layout + +Profiling data from each service (identified by the `service_name` label) is stored as a separate dataset within a block. During compaction: + +- Matching datasets from different blocks are merged +- TSDB indexes are combined +- Symbols and profile tables are merged and rewritten + +The output block contains non-overlapping, independent datasets optimized for efficient reading. + +## Stateless design + +Compaction workers are completely stateless: + +- Require no persistent local storage +- Scale horizontally by adding more instances +- Allow instances to be added or removed at any time +- Use default concurrency based on available CPU cores + +## Fault tolerance + +If a compaction worker fails: + +- The job lease expires +- The metastore reassigns the job to another worker +- Source segments remain in object storage until compaction succeeds + +Jobs that repeatedly fail are deprioritized to prevent blocking the compaction queue. + +## Garbage collection + +After compaction completes, the original source blocks are not immediately deleted. Instead, tombstones are created in the metastore. The actual deletion happens after a configurable delay, giving queries time to discover the new compacted blocks and stop accessing the original ones. Eventually, tombstones are included in compaction jobs, and the worker removes the source objects from object storage. + +For detailed information about the compaction process, refer to [Compaction](../../compaction/). diff --git a/docs/sources/reference-pyroscope-v2-architecture/components/distributor.md b/docs/sources/reference-pyroscope-v2-architecture/components/distributor.md new file mode 100644 index 0000000000..2b09187207 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/components/distributor.md @@ -0,0 +1,59 @@ +--- +title: "Pyroscope v2 distributor" +menuTitle: "Distributor" +description: "The distributor receives profiling data and routes it to segment-writers." +weight: 10 +keywords: + - Pyroscope v2 + - distributor + - ingestion +--- + +# Pyroscope v2 distributor + +The distributor is a stateless component that serves as the entry point for the ingestion path. It receives profiling data from agents and routes it to [segment-writers](../segment-writer/) for storage. + +## Profile routing + +Unlike v1 where profiles are routed to ingesters based on hash ring token distribution, the v2 distributor routes profiles to segment-writers based on the profile's `service_name` label. This co-location strategy ensures that profiles from the same application are stored together, which is crucial for: + +- **Query performance**: Profiles likely to be queried together are stored in the same blocks +- **Compaction efficiency**: Related data can be compacted more effectively +- **Storage optimization**: Reduces the number of objects needed to satisfy typical queries + +## Distribution algorithm + +The distributor uses a three-step process to determine where to place a profile: + +1. **Tenant shards**: Find suitable locations from the total shards using the `tenant_id`. +1. **Dataset shards**: Narrow down to locations suitable for the `service_name` label. +1. **Final placement**: Select the exact shard using consistent hashing or adaptive load balancing. + +This algorithm balances data locality with even distribution across the cluster. + +For detailed information about the distribution algorithm, refer to [Data distribution](../../data-distribution/). + +## Validation + +The distributor cleans and validates data before sending it to segment-writers: + +- Ensures profiles have timestamps set (defaults to receive time if missing) +- Removes samples with zero values +- Sums samples that share the same stacktrace + +If a request contains invalid data, the distributor returns a 400 HTTP status code with details in the response body. + +## Load balancing + +Randomly load balance write requests across distributor instances. If you're running Pyroscope in a Kubernetes cluster, you can define a Kubernetes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) as ingress for the distributors. + +The distributor discovers segment-writers through memberlist-based ring discovery, which maintains the list of available segment-writer instances. + +## Stateless design + +The distributor is completely stateless and disk-less: + +- Requires no local storage +- Scales horizontally by adding more instances +- Allows instances to be added or removed without data migration +- Supports deployment in ephemeral containers diff --git a/docs/sources/reference-pyroscope-v2-architecture/components/metastore/index.md b/docs/sources/reference-pyroscope-v2-architecture/components/metastore/index.md new file mode 100644 index 0000000000..3696b5fbc0 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/components/metastore/index.md @@ -0,0 +1,100 @@ +--- +title: "Pyroscope v2 metastore" +menuTitle: "Metastore" +description: "The metastore maintains the metadata index and coordinates compaction." +weight: 30 +keywords: + - Pyroscope v2 + - metastore + - Raft + - metadata +--- + +# Pyroscope v2 metastore + +The metastore is the only stateful component in the Pyroscope v2 architecture. It maintains the metadata index for all data objects stored in object storage and coordinates the compaction process. + +## Responsibilities + +The metastore service is responsible for: + +- **Metadata index**: Maintaining an index of all blocks and segments in object storage +- **Compaction coordination**: Scheduling and coordinating compaction jobs for [compaction-workers](../compaction-worker/) +- **Query planning**: Providing metadata to [query-frontend](../query-frontend/) for locating data objects +- **Data placement**: Managing placement rules for the data distribution algorithm +- **Retention enforcement**: Applying time-based retention policies and generating tombstones for expired data + +## Raft consensus + +The metastore uses the Raft protocol for consensus and replication, ensuring: + +- **Consistency**: All replicas maintain the same view of the metadata +- **High availability**: The cluster can continue operating if some nodes fail +- **Fault tolerance**: Data is replicated across multiple nodes + +### Fault tolerance + +| Cluster size | Tolerated failures | +|--------------|-------------------| +| 3 nodes | 1 node | +| 5 nodes | 2 nodes | + +## Storage requirements + +Even at large scale, the metastore only needs a few gigabytes of disk space for the metadata index. The index is implemented using BoltDB as the underlying key-value store. + +For better performance, the index database can be stored on an in-memory volume, as it's recovered from the Raft log and snapshot on startup. Durable storage is not required for the index itself—only for the Raft log. + +## Metadata index + +The metadata index stores information about data objects (blocks and segments) including: + +- Block identifiers (ULID) +- Tenant and shard assignments +- Time ranges +- Dataset information (service names, profile types) + +The index is partitioned by time, with each partition covering a 6-hour window. Within each partition, data is organized by tenant and shard. + +For detailed information about the metadata index structure, refer to [Metadata index](../../metadata-index/). + +## Compaction coordination + +The metastore coordinates the compaction process by: + +1. **Job planning**: Creates compaction jobs when enough segments are available. +1. **Job scheduling**: Assigns jobs to available compaction-workers. +1. **Job tracking**: Monitors job progress and handles failures. +1. **Index updates**: Updates the metadata index when compaction completes. + +The compaction service uses a lease-based ownership model with fencing tokens to prevent conflicts when workers fail or become unresponsive. + +For detailed information about the compaction process, refer to [Compaction](../../compaction/). + +## Dead letter queue + +If the metastore is temporarily unavailable, [segment writers](../segment-writer/) fall back to writing metadata to a dead letter queue (DLQ) directory in object storage. The metastore recovers these entries in the background once it becomes available again. + +## Retention + +The metastore enforces time-based retention policies on a per-tenant basis. Retention operates at the partition level: entire partitions are removed when they exceed the configured retention period, rather than evaluating individual blocks. When partitions are deleted, tombstones are created for the underlying data objects, which are eventually cleaned up by compaction workers. + +## Query support + +The metastore provides linearizable reads for query operations, ensuring that: + +- Queries observe the most recent committed state +- Previous writes are visible to read operations +- Both leader and follower replicas can serve queries + +## Leader election + +One metastore instance is elected as the leader through Raft consensus. The leader is responsible for: + +- Processing write requests +- Coordinating compaction scheduling +- Enforcing retention policies +- Running cleanup operations +- Recovering metadata entries from the dead letter queue + +Follower replicas can serve read requests, distributing the query load across the cluster. diff --git a/docs/sources/reference-pyroscope-v2-architecture/components/query-backend.md b/docs/sources/reference-pyroscope-v2-architecture/components/query-backend.md new file mode 100644 index 0000000000..46c088e22b --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/components/query-backend.md @@ -0,0 +1,59 @@ +--- +title: "Pyroscope v2 query-backend" +menuTitle: "Query-backend" +description: "The query-backend executes queries with high parallelism." +weight: 60 +keywords: + - Pyroscope v2 + - query-backend + - queries + - parallel execution +--- + +# Pyroscope v2 query-backend + +The query-backend is a stateless component that executes queries with high parallelism. It reads data directly from object storage and processes it according to the query plan received from the [query-frontend](../query-frontend/). + +## How it works + +The [query frontend](../query-frontend/) builds a physical query plan as a tree structure: + +- **Read nodes** (leaves) fetch and process data from specific blocks in object storage. +- **Merge nodes** (intermediate) combine results from their child nodes. + +The query frontend sends the plan root to a query backend instance. That instance distributes subtrees to other query backend instances for parallel execution, collects their results, and merges them. The final merged result is returned to the query frontend, which forwards it to the client. + +This tree-based execution allows queries to fan out across many query backend instances in parallel, with merging happening at each level of the tree rather than in a single aggregation point. + +## Direct object storage access + +Unlike v1 where queries may need to access ingesters for recent data, the v2 query-backend reads directly from object storage: + +- No coordination with write-path components needed +- Simplified query execution +- Better isolation between read and write paths +- Easier horizontal scaling + +## Stateless design + +The query-backend is completely stateless: + +- Requires no persistent storage +- Needs no caching layer (reads directly from object storage) +- Scales horizontally to hundreds of instances +- Allows instances to be added or removed without coordination + +## Scalability + +The query-backend enables horizontal scaling of the read path: + +- Handles heavier query workloads by adding more instances +- Scales independently of the write path +- Shares no state between instances +- Supports auto-scaling based on query load + +## Performance characteristics + +- **High parallelism**: Multiple blocks processed concurrently +- **Memory efficient**: Tree-based execution minimizes memory requirements +- **Network optimized**: Results combined close to the data source diff --git a/docs/sources/reference-pyroscope-v2-architecture/components/query-frontend.md b/docs/sources/reference-pyroscope-v2-architecture/components/query-frontend.md new file mode 100644 index 0000000000..0c8ef2e3a5 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/components/query-frontend.md @@ -0,0 +1,53 @@ +--- +title: "Pyroscope v2 query-frontend" +menuTitle: "Query-frontend" +description: "The query-frontend handles query planning and routes requests to query-backends." +weight: 50 +keywords: + - Pyroscope v2 + - query-frontend + - queries +--- + +# Pyroscope v2 query-frontend + +The query-frontend is a stateless component that serves as the entry point for the query path. It handles query planning and routes requests to [query-backend](../query-backend/) instances for execution. + +## Responsibilities + +The query-frontend is responsible for: + +- **Receiving and validating queries** through the Query API +- **Executing queries** by using the [metastore](../metastore/) for block discovery and delegating execution to [query-backend](../query-backend/) instances + +## Query flow + +When a query arrives, the query frontend: + +1. Validates the query request. +1. Queries the [metastore](../metastore/) to find all blocks matching the query criteria (time range, tenant, and optionally service name). +1. Builds a physical query plan as a tree: leaf nodes are read operations targeting specific blocks and datasets, while intermediate nodes are merge operations that combine results from their children. +1. Sends the plan root to a [query backend](../query-backend/) instance, which distributes subtrees to other query backend instances for parallel execution and merging. For more details, refer to [Query backend](../query-backend/). + +Because the metastore serves block metadata from memory with linearizable reads, query planning is fast and does not require the query frontend to maintain any local state about blocks. + +## Stateless design + +The query-frontend is completely stateless: + +- Requires no persistent storage +- Scales horizontally to hundreds of instances +- Allows instances to be added or removed without coordination +- Supports auto-scaling based on query load + +## Scalability + +The query-frontend can scale independently of the write path: + +- Heavy query workloads don't impact ingestion performance +- Handles increased query volume by adding more instances +- Works with any number of query-backend instances + +## Load balancing + +Query-frontends can be load balanced using standard HTTP load balancers. Each instance can handle any query, making round-robin load balancing effective. diff --git a/docs/sources/reference-pyroscope-v2-architecture/components/segment-writer.md b/docs/sources/reference-pyroscope-v2-architecture/components/segment-writer.md new file mode 100644 index 0000000000..35acdfbb6b --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/components/segment-writer.md @@ -0,0 +1,88 @@ +--- +title: "Pyroscope v2 segment-writer" +menuTitle: "Segment-writer" +description: "The segment-writer accumulates profiles and writes them to object storage." +weight: 20 +keywords: + - Pyroscope v2 + - segment-writer + - ingestion + - object storage +--- + +# Pyroscope v2 segment-writer + +The segment-writer is a stateless component that accumulates incoming profiles in memory and periodically writes them to object storage as segments. This is a new component in v2 that replaces the ingester's role in the write path. + +## How it works + +1. **Profile accumulation**: The segment-writer receives profiles from [distributors](../distributor/) and accumulates them in memory. +1. **Segment creation**: Profiles are batched into small blocks called segments. +1. **Object storage write**: Segments are written directly to object storage. +1. **Metadata update**: The segment-writer updates the [metastore](../metastore/) with metadata about newly created segments. + +## Key features + +### Single object per shard + +Each segment-writer produces a single object per shard containing data from all tenant services assigned to that shard. This approach minimizes the number of write operations to object storage, significantly reducing costs compared to writing individual objects for each tenant or service. + +### Synchronous ingestion + +Ingestion clients are blocked until data is durably stored in object storage and an entry for the object is created in the metadata index. This guarantees data durability without requiring local disk persistence. + +By default, ingestion is synchronous with median latency expected to be less than 500ms using default settings and popular object storage providers such as Amazon S3, Google Cloud Storage, and Azure Blob Storage. + +### In-memory accumulation + +Profiles are accumulated in an in-memory database before being flushed to object storage. The in-memory structure includes: + +- **Profile index**: Efficient indexing for accumulated profiles +- **Inverted index**: For label-based lookups during segment creation + +### Data co-location + +Profiles from the same application (identified by the `service_name` label) are co-located in the same segments. This co-location is maintained by the distributor's routing algorithm and is crucial for: + +- Improves query performance +- Increases compaction efficiency +- Optimizes storage usage + +## Stateless design + +Unlike the v1 ingester which required local disk storage, the segment-writer is completely stateless: + +- Requires no persistent local storage +- Writes all data directly to object storage +- Scales horizontally by adding more instances +- Allows instances to be added or removed without data migration +- Recovers immediately after failure (no WAL replay needed) + +## Segment lifecycle + +1. **Creation**: Profiles are accumulated in memory. +1. **Flush**: When conditions are met (time or size thresholds), a segment is written to object storage. +1. **Registration**: Segment metadata is registered in the metastore. +1. **Compaction**: Small segments are later merged into larger blocks by [compaction-workers](../compaction-worker/). + +## Failure handling + +The segment writer relies on at-least-once delivery semantics. If a write fails after the segment has been uploaded to object storage but before the metastore acknowledges the metadata, the client retries the request. This can result in the same profile appearing in multiple segments, which is resolved during compaction. + +### Dead letter queue + +If the segment writer cannot register metadata with the metastore (for example, during metastore unavailability), the metadata is written to a dead letter queue (DLQ) directory in object storage. The metastore recovers these entries in the background, ensuring that data is eventually made visible to queries. + +## Deployment + +- The segment writer runs as a StatefulSet without persistent volumes. +- It participates in a hash ring used by the [distributor](../distributor/) to route profiles. +- Multiple segment writers can write to the same shard during topology changes (for example, scaling events or rollouts). This is expected and handled by compaction. + +## Configuration + +The segment-writer flush behavior can be configured to balance between: + +- **Latency**: How quickly data becomes queryable +- **Cost**: Number of write operations to object storage +- **Memory usage**: Amount of data held in memory before flush diff --git a/docs/sources/reference-pyroscope-v2-architecture/data-distribution/index.md b/docs/sources/reference-pyroscope-v2-architecture/data-distribution/index.md new file mode 100644 index 0000000000..97c9f5b482 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/data-distribution/index.md @@ -0,0 +1,157 @@ +--- +title: "Data distribution" +menuTitle: "Data distribution" +description: "Learn how Pyroscope v2 distributes profile data across shards and segment-writers." +weight: 50 +keywords: + - Pyroscope v2 + - data distribution + - sharding + - placement +--- + +# Data distribution + +Pyroscope v2 uses a sophisticated data distribution algorithm to place profiles across segment-writers. The algorithm ensures that profiles from the same application are co-located while maintaining even load distribution across the cluster. + +## Design goals + +The distribution algorithm is designed to achieve: + +- **Data co-location**: Profiles from the same tenant service are stored together +- **Query performance**: Co-located data reduces the number of objects needed for queries +- **Compaction efficiency**: Related data can be compacted more effectively +- **Even distribution**: Load is balanced across segment-writers +- **Minimal re-balancing**: Changes to the cluster minimize data movement + +## Three-step placement + +The choice of placement for a profile involves a three-step process: + +1. **Tenant shards**: Find *m* suitable locations from the total *N* shards using the `tenant_id`. +1. **Dataset shards**: Find *n* suitable locations from *m* options using the `service_name` label. +1. **Final placement**: Select the exact shard *s* from *n* options. + +Where: +- **N** is the total number of shards in the deployment +- **m** (tenant shard limit) is configured explicitly +- **n** (dataset shard limit) is selected dynamically based on observed ingestion rate + +{{< mermaid >}} +block-beta + columns 15 + + shards["ring"]:2 + space + shard_0["0"] + shard_1["1"] + shard_2["2"] + shard_3["3"] + shard_4["4"] + shard_5["5"] + shard_6["6"] + shard_7["7"] + shard_8["8"] + shard_9["9"] + shard_10["10"] + shard_11["11"] + + tenant["tenant"]:2 + space:4 + ts_3["3"] + ts_4["4"] + ts_5["5"] + ts_6["6"] + ts_7["7"] + ts_8["8"] + ts_9["9"] + space:2 + + dataset["dataset"]:2 + space:5 + ds_4["4"] + ds_5["5"] + ds_6["6"] + ds_7["7"] + space:4 +{{< /mermaid >}} + +In this example: +- The tenant's shard range starts at offset 3 with size 8 +- The dataset's shard range is a subset within the tenant's range, starting at offset 1 with 4 shards + +## Consistent hashing + +Pyroscope uses [Jump consistent hash](https://arxiv.org/pdf/1406.2294) to select positions within each subring. This algorithm ensures: + +- **Balance**: Objects are evenly distributed among buckets +- **Monotonicity**: When buckets are added, objects only move from old to new buckets + +This minimizes data re-balancing when the cluster size changes. + +## Hot spot mitigation + +To prevent hot spots where many datasets end up on the same node, shards are mapped to instances through a separate mapping table. This mapping: + +- Ensures even distribution across nodes +- Is updated when nodes are added or removed +- Preserves existing mappings as much as possible + +{{< mermaid >}} +graph LR + Distributor==>SegmentWriter + PlacementAgent-.-PlacementRules + SegmentWriter-->|metadata|PlacementManager + SegmentWriter==>|data|Segments + PlacementManager-.->PlacementRules + + subgraph Distributor["distributor"] + PlacementAgent + end + + subgraph Metastore["metastore"] + PlacementManager + end + + subgraph ObjectStore["object store"] + PlacementRules(placement rules) + Segments(segments) + end + + subgraph SegmentWriter["segment-writer"] + end +{{< /mermaid >}} + +## Adaptive load balancing + +Due to the nature of continuous profiling, data can be distributed unevenly across profile series. To mitigate this: + +- By default: `fingerprint mod n` is used as the distribution key +- When skew is detected: Switches to `random(n)` distribution + +This adaptive approach handles uneven data distribution while maintaining locality when possible. + +## Placement management + +The Placement Manager runs on the metastore leader and: + +- Tracks dataset statistics from segment-writer metadata +- Builds placement rules at regular intervals +- Determines the number of shards for each dataset +- Decides the load balancing strategy (fingerprint mod vs round robin) + +Placement rules are stored in object storage and fetched by distributors. Since actual data re-balancing is not performed, placement rules don't need to be synchronized in real-time. + +## Failure handling + +If a segment-writer fails: + +1. The distributor selects the next suitable segment-writer from available options. +1. The shard identifier is specified explicitly in the request. +1. Data locality is maintained even during transient failures. + +Two requests with the same distribution key may occasionally end up in different shards, but this is expected to be rare. + +## Implementation details + +For detailed implementation information, including the full algorithm specification and shard mapping procedures, refer to the [internal documentation](https://github.com/grafana/pyroscope/blob/main/pkg/segmentwriter/client/distributor/README.md). diff --git a/docs/sources/reference-pyroscope-v2-architecture/deployment-modes/index.md b/docs/sources/reference-pyroscope-v2-architecture/deployment-modes/index.md new file mode 100644 index 0000000000..7ab6146a92 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/deployment-modes/index.md @@ -0,0 +1,130 @@ +--- +title: "Pyroscope v2 deployment modes" +menuTitle: "Deployment modes" +description: "Learn about the deployment options for Pyroscope v2." +weight: 40 +keywords: + - Pyroscope v2 + - deployment + - Kubernetes + - microservices +--- + +# Pyroscope v2 deployment modes + +Pyroscope v2 can be deployed in different configurations depending on your scale and operational requirements. + +## Microservices mode + +In microservices mode, each component runs as a separate process. This is the recommended deployment for production environments at scale. + +### Benefits + +- **Independent scaling**: Scale each component based on its specific load +- **Fault isolation**: Component failures don't affect other components +- **Resource optimization**: Allocate resources based on component needs +- **Rolling updates**: Update components independently + +### Components to deploy + +| Component | Instances | Stateful | Notes | +|-----------|-----------|----------|-------| +| Distributor | 2+ | No | Scale based on ingestion rate | +| Segment-writer | 2+ | No | Scale based on ingestion rate | +| Metastore | 3 or 5 | Yes | Odd number for Raft consensus | +| Compaction-worker | 2+ | No | Scale based on compaction backlog | +| Query-frontend | 2+ | No | Scale based on query load | +| Query-backend | 2+ | No | Scale based on query load | + +### Object storage requirement + +Microservices mode requires object storage (Amazon S3, Google Cloud Storage, Azure Blob Storage, or OpenStack Swift). Local filesystem storage is not supported in this mode. + +## Single-node mode + +For evaluation, development, or small-scale deployments, Pyroscope v2 can run as a single process with all components enabled. + +### Benefits + +- **Simple deployment**: Single binary to run +- **Lower resource requirements**: Suitable for smaller workloads +- **Local storage option**: Can use local filesystem for storage + +### Limitations + +- **No high availability**: Single point of failure +- **Limited scalability**: Cannot scale individual components +- **Not recommended for production**: Use microservices mode for production workloads + +## Kubernetes deployment + +For Kubernetes deployments, use the Helm chart with v2 storage enabled. + +### Single-binary mode + +```bash +helm install pyroscope grafana/pyroscope --version 1.20.3 \ + --set architecture.storage.v1=false \ + --set architecture.storage.v2=true +``` + +### Microservices mode + +```bash +helm install pyroscope grafana/pyroscope --version 1.20.3 \ + --set architecture.microservices.enabled=true \ + --set architecture.storage.v1=false \ + --set architecture.storage.v2=true +``` + +For migrating an existing v1 deployment, refer to the [migration guide](../migrate-from-v1/). + +### Helm chart considerations + +When deploying on Kubernetes: + +- Configure persistent volumes for metastore nodes +- Set up object storage credentials +- Configure resource requests and limits for each component +- Set up ingress for distributor and query-frontend + +## Storage configuration + +### Object storage + +Pyroscope v2 supports the following object storage backends: + +- **Amazon S3**: Recommended for AWS deployments +- **Google Cloud Storage**: Recommended for GCP deployments +- **Azure Blob Storage**: Recommended for Azure deployments +- **OpenStack Swift**: For OpenStack environments + +### Local filesystem + +Local filesystem storage is only supported for single-node deployments and is not suitable for production use in microservices mode. + +## Resource planning + +### Metastore + +The metastore is the only component requiring persistent storage: + +- **Disk space**: A few gigabytes, even at large scale +- **Memory**: Benefits from keeping the index in memory +- **CPU**: Moderate usage for Raft consensus operations + +### Stateless components + +All other components are stateless and primarily need: + +- **CPU**: For data processing +- **Memory**: For in-flight data and query execution +- **Network**: For object storage access + +### Object storage + +Plan for object storage costs based on: + +- **Write operations**: Segment flushes and compaction uploads +- **Read operations**: Query execution +- **Storage**: Retained profile data diff --git a/docs/sources/reference-pyroscope-v2-architecture/design-motivation/index.md b/docs/sources/reference-pyroscope-v2-architecture/design-motivation/index.md new file mode 100644 index 0000000000..e2bd2988d4 --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/design-motivation/index.md @@ -0,0 +1,50 @@ +--- +title: "Design motivation" +menuTitle: "Design motivation" +description: "Learn about the v1 limitations that motivated the Pyroscope v2 architecture redesign." +weight: 5 +keywords: + - Pyroscope v2 + - v1 limitations + - architecture +--- + +# Design motivation + +The v2 architecture addresses fundamental scalability and resilience limitations in v1 that cannot be resolved incrementally. + +## Write path limitations in v1 + +- **No write-ahead log (WAL)**: Ingesters accumulate profiles in memory and periodically flush them to disk, but there is no WAL to durably record writes on arrival. If an ingester crashes between flushes, the in-memory profiles are lost. Replication mitigates this but cannot fully prevent data loss when multiple ingesters fail. +- **Deduplication overhead**: In v1, each profile series is replicated to N ingesters, and each ingester writes its own block. At query time, these duplicates have to be merged and deduplicated. This becomes increasingly expensive as the number of ingesters grows. +- **Weak read/write isolation**: Ingestion latency spikes can cause distributor out-of-memory (OOM) errors. Expensive queries can increase ingestion latency due to broad locks, and can themselves cause ingester OOM. +- **Suboptimal data distribution**: The label-hash-based sharding distributes profiles of the same service across all ingesters, causing excessive duplication of symbolic information and reducing query selectivity. +- **Slow rollouts**: Ingester rollouts can take hours in large deployments due to the need to flush in-memory data before shutdown. + +## Read path limitations in v1 + +- **Store-gateway instability**: Heavy queries can cause store-gateway OOM. The block index overhead grows with the number of blocks, putting memory pressure on store-gateways. +- **Limited elasticity**: The querier and store-gateway services are difficult to scale dynamically, as store-gateways need to load block indexes before serving queries. +- **Slow rollouts**: Like ingesters, store-gateway rollouts can be slow due to the need to load block indexes on startup. + +## Compaction limitations in v1 + +- **Scalability**: The v1 compactor can struggle to keep up with large tenants as data is replicated during ingestion. Delays in compaction place pressure on the read path, as queries have to process and deduplicate more uncompacted blocks. + +## Extensibility + +- Adding a new data access method (for example, a new API endpoint for heatmaps) in v1 requires changes across many components. The tight coupling between ingesters, store-gateways, and queriers makes the codebase harder to maintain and extend. + +## Comparison with v1 + +| Aspect | v1 | v2 | +|-----------------|--------------------------------------------------------------------------------------|---------------------------------------------------------------------| +| **Write path** | Distributor → Ingester → Object Storage | Distributor → Segment writer → Object storage + Metastore | +| **Metadata** | Per-tenant bucket index in object storage | Metastore (Raft-based, in-memory index) | +| **Read path** | Query frontend → Query scheduler → Querier → Ingester / Store-gateway | Query frontend → Metastore + Query backend | +| **Compaction** | Compactor (hash-ring sharded, per-tenant) | Compaction worker orchestrated by metastore | +| **Replication** | Write replication to N ingesters | No write replication; durability via object storage | + +v2 addresses these issues by eliminating write replication in favor of object storage durability, centralizing metadata in the metastore for fast query planning and enabling stateless query backends that access object storage directly, and decoupling compaction into a more scalable job-based system orchestrated by the metastore. + +For details on how the v2 architecture works, refer to [About the Pyroscope v2 architecture](../about-pyroscope-v2-architecture/). diff --git a/docs/sources/reference-pyroscope-v2-architecture/metadata-index/index.md b/docs/sources/reference-pyroscope-v2-architecture/metadata-index/index.md new file mode 100644 index 0000000000..1ff71e43aa --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/metadata-index/index.md @@ -0,0 +1,195 @@ +--- +title: "Metadata index" +menuTitle: "Metadata index" +description: "Learn how the Pyroscope v2 metadata index stores and queries block information." +weight: 70 +keywords: + - Pyroscope v2 + - metadata index + - metastore + - blocks +--- + +# Metadata index + +The metadata index stores information about all data objects (blocks and segments) in object storage. It is maintained by the [metastore](../components/metastore/) service and provides fast lookups for query planning. + +## Purpose + +The metadata index enables: + +- **Block discovery**: Finding blocks that match a query's time range and filters +- **Query planning**: Identifying exactly which objects need to be read +- **Compaction coordination**: Tracking which blocks can be compacted together +- **Retention enforcement**: Managing block lifecycle and cleanup + +## Implementation + +The index is implemented using: + +- **BoltDB**: Key-value store for metadata entries +- **Raft**: Consensus protocol for replication and consistency + +BoltDB was chosen for its simplicity and efficiency with a single writer and concurrent readers. For better performance, the index can be stored on an in-memory volume since it's recovered from the Raft log on startup. + +## Block metadata + +Each block in object storage has a corresponding metadata entry containing: + +- **Block ID**: Unique identifier (ULID) based on creation time +- **Tenant**: The tenant that owns the data +- **Shard**: The shard assignment for data distribution +- **Time range**: Start and end timestamps of the data +- **Datasets**: Information about contained datasets (services) + +### Dataset information + +Each dataset within a block includes: + +- **Service name**: The `service_name` label identifying the application +- **Labels**: Additional metadata labels for filtering +- **Table of contents**: Offsets to data sections within the dataset + +## Index structure + +The index is partitioned by time, with each partition covering a 6-hour window: + +``` +Partition (6h window) +├── Tenant A +│ ├── Shard 0 +│ ├── Shard 1 +│ └── Shard N +└── Tenant B + ├── Shard 0 + └── Shard N +``` + +Within each shard: + +- **Block entries**: Key-value pairs (block ID → metadata) +- **String table**: Deduplicated strings for space efficiency +- **Shard index**: Time range for efficient filtering + +## Index writes + +Index writes are performed by [segment-writers](../components/segment-writer/) when new segments are created: + +{{< mermaid >}} +sequenceDiagram + participant SW as segment-writer + participant M as Metastore + participant R as Raft + participant I as Index + + SW->>M: AddBlock(metadata) + M->>R: Propose ADD_BLOCK + R->>R: Commit to log + R->>I: Insert block + I-->>R: Success + R-->>M: Committed + M-->>SW: Success +{{< /mermaid >}} + +### Tombstone protection + +Before adding a block, the index checks for tombstones to prevent re-adding blocks that were already compacted. This handles cases where: + +- A writer's response was lost but the block was added +- The block was already compacted before the retry + +## Index queries + +Queries use the linearizable read pattern to ensure consistency: + +1. **Read index request**: Query asks for the current commit index. +1. **Leader check**: Verifies the current leader. +1. **Wait for commit**: Waits until the commit index is applied locally. +1. **Read state**: Reads from the local state machine. + +This allows both leader and follower replicas to serve queries while ensuring they see the latest committed state. + +### Query types + +The index supports two main query patterns: + +**Metadata queries**: Find blocks matching criteria +``` +Query: + - Time range: [start, end] + - Tenant: ["tenant-1"] + - Labels: {service_name="frontend"} +``` + +**Label queries**: List available labels without reading data +``` +Query: + - Return: distinct values for "profile_type" label + - Filter: {service_name="frontend"} +``` + +## Retention + +### Compaction-based retention + +When blocks are compacted: + +1. Source block entries are replaced with compacted block entry. +1. Tombstones are created for source blocks. +1. Tombstones trigger eventual deletion of source objects. + +### Time-based retention + +Retention policies delete entire partitions based on: + +- **Block creation time**: Primary retention criteria +- **Data timestamps**: Blocks are only deleted if data is also past retention + +Retention policies are tenant-specific and configurable per tenant. + +## Cleanup process + +The cleaner runs on the Raft leader and: + +1. Lists partitions and applies retention policy. +1. Identifies partitions to delete. +1. Proposes deletion to Raft. +1. Creates tombstones for affected blocks. +1. Tombstones are processed during compaction. + +{{< mermaid >}} +sequenceDiagram + participant C as Cleaner + participant M as Metastore + participant R as Raft + participant I as Index + + C->>M: TruncateIndex(policy) + M->>I: List partitions + I-->>M: Partition list + M->>M: Apply retention policy + M->>R: Propose TRUNCATE_INDEX + R->>I: Delete partitions + R->>I: Add tombstones + R-->>M: Committed + M-->>C: Success +{{< /mermaid >}} + +## Performance + +### Caching + +The index uses several caches: + +- **Shard cache**: Keeps shard indexes and string tables in memory +- **Block cache**: Stores decoded metadata entries + +### Scalability + +- **Storage requirements**: A few gigabytes even at large scale +- **Query performance**: Sub-millisecond lookups with caching +- **Write throughput**: Limited by Raft consensus, typically sufficient for ingestion rates + +## Implementation details + +For detailed implementation information, including the protobuf schema and internal structures, refer to the [internal documentation](https://github.com/grafana/pyroscope/blob/main/pkg/metastore/index/README.md). diff --git a/docs/sources/reference-pyroscope-v2-architecture/migrate-from-v1/index.md b/docs/sources/reference-pyroscope-v2-architecture/migrate-from-v1/index.md new file mode 100644 index 0000000000..183a04d26b --- /dev/null +++ b/docs/sources/reference-pyroscope-v2-architecture/migrate-from-v1/index.md @@ -0,0 +1,403 @@ +--- +title: "Migrate from v1 to v2 storage using Helm" +menuTitle: "Migrate from v1 using Helm" +description: "Step-by-step guide to migrate your Pyroscope Helm installation from v1 to v2 storage architecture." +weight: 900 +--- + +# Migrate from v1 to v2 storage using Helm + +This guide walks you through migrating a Pyroscope installation from v1 to v2 storage architecture using the Helm chart. The migration uses a phased approach that lets you run both storage backends simultaneously before fully cutting over to v2. + +For an overview of what changed in v2 and why, refer to [About the v2 architecture](../about-pyroscope-v2-architecture/) and [Design motivation](../design-motivation/). + +## Prerequisites + +Before starting the migration, make sure you have: + +- **Helm chart version 1.19.2 or later**. Verify with: + + ```bash + helm list -n pyroscope -f pyroscope + ``` + + Check that the `CHART` column shows `pyroscope-1.19.2` or higher. If your chart is older, upgrade it first. + +- **Pyroscope running on v1 storage via Helm.** Verify with: + + ```bash + helm get values -n pyroscope pyroscope -o yaml --all | grep -A8 'storage:' | grep -E 'v1:|v2:' + ``` + + You should see `v1: true` and `v2: false`. If you see `v2: true`, your installation is already using v2 or is mid-migration. + +- **Object storage configured.** v2 writes directly to object storage — it doesn't use local disk for block storage. If you haven't configured object storage yet, add it to your Helm values. For example, for S3: + + ```yaml + pyroscope: + structuredConfig: + storage: + backend: s3 + s3: + endpoint: s3.us-east-1.amazonaws.com + bucket_name: pyroscope-data + access_key_id: "${AWS_ACCESS_KEY_ID}" + secret_access_key: "${AWS_SECRET_ACCESS_KEY}" + ``` + + For other backends (GCS, Azure, Swift), refer to [Configure object storage backend](https://grafana.com/docs/pyroscope//configure-server/storage/configure-object-storage-backend/). You can also use the `filesystem` backend, but in Kubernetes, this requires a `ReadWriteMany` volume that is shared across all pods. + +- **`kubectl` and `helm` CLI access** to your cluster. + +{{< admonition type="note" >}} +The examples in this guide assume Pyroscope is installed in the `pyroscope` namespace with the release name `pyroscope`. Adjust the `-n` namespace flag and release name in `helm` and `kubectl` commands if your installation differs. +{{< /admonition >}} + +## Migration overview + +The migration has three phases: + +| Phase | What happens | Reversible? | +|--------------------------|-------------------------------------------------------------------------|-------------| +| 1. Dual ingest | v2 components deploy alongside v1. Writes go to both storage backends. | Yes | +| 2. Validate | Run both backends for at least 24 hours. Verify v2 data and compaction. | Yes | +| 3. Remove v1 | Remove v1 components. Only v2 serves reads and writes. | Partial | + +The steps below are specific to your deployment mode. Follow the section that matches your installation. + +## Single-binary mode + +### Phase 1: Enable dual ingest + +In this phase, the single-binary process enables the v2 storage modules alongside v1. Writes go to both storage backends simultaneously, and the read path serves data from both v1 and v2. + +```bash +helm upgrade -n pyroscope pyroscope grafana/pyroscope --version 2.0.0 \ + --reset-then-reuse-values \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=true +``` + +The `--reuse-values` flag preserves your existing configuration. Alternatively, you can pass your values file with `-f values.yaml`. + +#### Verify Phase 1 + +After the upgrade completes, check that the pod has restarted and is running: + +```bash +kubectl get pods -n pyroscope -l app.kubernetes.io/instance=pyroscope +``` + +Check the Helm release notes for migration status: + +```bash +helm get notes -n pyroscope pyroscope +``` + +You should see output similar to: + +``` +# Pyroscope v2 Migration is active + +Write traffic will be written to: +- 100% v1: ingester +- 100% v2: segment-writer + +Read traffic is served from v2 read path from as soon as data was first ingested to v2. +``` + +Also verify: + +- The **metastore** raft has initialized. Check the pod logs for a message like `entering leader state`: + + ```bash + kubectl logs -n pyroscope -l app.kubernetes.io/instance=pyroscope --tail=500 | grep -i "entering leader state" + ``` + +- The **segment-writer** ring is healthy: + + ```bash + kubectl port-forward -n pyroscope svc/pyroscope 4040:4040 & + PF_PID=$! + sleep 2 + curl -s http://localhost:4040/ring-segment-writer | grep -o 'ACTIVE' | wc -l + kill $PF_PID + ``` + + In single-binary mode, the count should be 1. + +### Phase 2: Validate v2 is working + +Run both storage backends simultaneously for at least 24 hours before proceeding. During this time, you should be able to query data ingested to v2. + +#### Verify data is being written to v2 + +Query recent profiling data. The v2 read path should serve data ingested after Phase 1. You can use `profilecli`, the Pyroscope UI, or the API to query profiles from the last hour and confirm results are returned: + +```bash +kubectl port-forward -n pyroscope svc/pyroscope 4040:4040 & +PF_PID=$! +sleep 2 +profilecli query series --url http://localhost:4040 --from "now-1h" --to "now" +kill $PF_PID +``` + +You should see series labels for the profiling data being ingested. If no results are returned, check the distributor and segment-writer logs for errors. + +#### Verify v2 compaction is running + +The compaction-worker compacts segments through the L0 → L1 → L2 levels. Verify that compaction jobs are completing: + +```bash +kubectl logs -n pyroscope -l app.kubernetes.io/instance=pyroscope --tail=500 | grep "compaction finished successfully" +``` + +You should see log lines like: + +``` +msg="compaction finished successfully" input_blocks=20 output_blocks=1 +``` + +Compaction typically starts within minutes of ingestion, the first block is created once enough segments accumulate for a shard. + +#### Verify error rates are stable + +Check that write and read error rates haven't increased since enabling v2. If you have Prometheus metrics configured: + +```promql +sum(rate(pyroscope_request_duration_seconds_count{status_code=~"5.."}[5m])) +``` + +Error rates should be zero or negligible. Compare against pre-migration baselines to confirm no regression. + +### Phase 3: Switch to v2 storage + +Once you're confident that v2 is working correctly and you no longer need to query data ingested before Phase 1, you can disable the v1 storage. + +{{< admonition type="warning" >}} +After this step, data ingested before Phase 1 is no longer queryable through Pyroscope. The data still exists in object storage, but the v1 storage modules that serve it will be disabled. Make sure you don't need to query historical data from before the migration started. +{{< /admonition >}} + +```bash +helm upgrade -n pyroscope pyroscope grafana/pyroscope --version 2.0.0 \ + --reset-then-reuse-values \ + --set architecture.storage.v1=false \ + --set architecture.storage.v2=true +``` + +#### Verify Phase 3 + +Verify that the Pyroscope pod has restarted: + +```bash +kubectl get pods -n pyroscope -l app.kubernetes.io/instance=pyroscope +``` + +Verify that queries still return data: + +```bash +kubectl port-forward -n pyroscope svc/pyroscope 4040:4040 & +PF_PID=$! +sleep 2 +profilecli query series --url http://localhost:4040 --from "now-1h" --to "now" +kill $PF_PID +``` + +You should see series labels for recent profiling data. You can also open the Pyroscope UI at `http://localhost:4040` and verify that you can query recent profiles. An empty or errored UI indicates a problem — see [Rollback](#rollback). + +## Microservices mode + +If you deployed Pyroscope using the `values-micro-services.yaml` file as described in [Deploy on Kubernetes](https://grafana.com/docs/pyroscope//deploy-kubernetes/helm/), follow the steps below. + +### Phase 1: Deploy v2 components alongside v1 + +In this phase, you deploy the v2 components (segment-writer, metastore, compaction-worker, query-backend) alongside your existing v1 installation. The distributor starts writing to both storage backends simultaneously. The read path serves data from both v1 and v2. + +```bash +helm upgrade -n pyroscope pyroscope grafana/pyroscope \ + --reuse-values \ + --set architecture.microservices.enabled=true \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=true +``` + +The `--reuse-values` flag preserves your existing configuration. Alternatively, you can pass your values file with `-f values.yaml`. + +#### Verify Phase 1 + +After the upgrade completes, check that the new components are running: + +```bash +kubectl get pods -n pyroscope -l app.kubernetes.io/instance=pyroscope +``` + +Check the Helm release notes for migration status: + +```bash +helm get notes -n pyroscope pyroscope +``` + +You should see output similar to: + +``` +# Pyroscope v2 Migration is active + +Write traffic will be written to: +- 100% v1: ingester +- 100% v2: segment-writer + +Read traffic is served from v2 read path from as soon as data was first ingested to v2. +``` + +Also verify: + +- The **metastore** raft cluster has elected a leader: + + ```bash + kubectl logs -n pyroscope -l app.kubernetes.io/component=metastore --tail=500 | grep -i "entering leader state" + ``` + +- The **segment-writer** ring is healthy. All instances should show as `ACTIVE`: + + ```bash + kubectl port-forward -n pyroscope svc/pyroscope-distributor 4040:4040 & + PF_PID=$! + sleep 2 + curl -s http://localhost:4040/ring-segment-writer | grep -o 'ACTIVE' | wc -l + kill $PF_PID + ``` + + The count should match the number of segment-writer instances. + +### Phase 2: Validate v2 is working + +Run both storage backends simultaneously for at least 24 hours before proceeding. During this time, you should be able to query data ingested to v2. + +#### Verify data is being written to v2 + +Query recent profiling data. The v2 read path should serve data ingested after Phase 1. You can use `profilecli`, the Pyroscope UI, or the API to query profiles from the last hour and confirm results are returned: + +```bash +kubectl port-forward -n pyroscope svc/pyroscope-query-frontend 4040:4040 & +PF_PID=$! +sleep 2 +profilecli query series --url http://localhost:4040 --from "now-1h" --to "now" +kill $PF_PID +``` + +You should see series labels for the profiling data being ingested. If no results are returned, check the distributor and segment-writer logs for errors. + +#### Verify v2 compaction is running + +The compaction-worker compacts segments through the L0 → L1 → L2 levels. Verify that compaction jobs are completing: + +```bash +kubectl logs -n pyroscope -l app.kubernetes.io/component=compaction-worker --tail=500 | grep "compaction finished successfully" +``` + +You should see log lines like: + +``` +msg="compaction finished successfully" input_blocks=20 output_blocks=1 +``` + +Compaction typically starts within minutes of ingestion, the first block is created once enough segments accumulate for a shard. + +#### Verify error rates are stable + +Check that write and read error rates haven't increased since enabling v2. If you have Prometheus metrics configured, query error rates per component: + +```promql +# Server-side errors by component (distributor, segment-writer, query-frontend, query-backend, etc.) +sum by (component) (rate(pyroscope_request_duration_seconds_count{status_code=~"5.."}[5m])) +``` + +All components should show zero or negligible error rates. Compare against pre-migration baselines to confirm no regression. + +### Phase 3: Remove v1 components + +Once you're confident that v2 is working correctly and you no longer need to query data ingested before Phase 1, you can remove the v1 components. + +{{< admonition type="warning" >}} +After this step, data ingested before Phase 1 is no longer queryable through Pyroscope. The data still exists in object storage, but the v1 read path components (ingester, store-gateway, querier) that serve it will be removed. Make sure you don't need to query historical data from before the migration started. +{{< /admonition >}} + +```bash +helm upgrade -n pyroscope pyroscope grafana/pyroscope \ + --reuse-values \ + --set architecture.storage.v1=false \ + --set architecture.storage.v2=true +``` + +The Helm chart automatically removes v1-only components (ingester, compactor, store-gateway, querier, query-scheduler) when `architecture.storage.v1` is set to `false`, even if your values file or `--reuse-values` state still contains overrides for those components. + +#### Verify Phase 3 + +Check that v1 components have been removed and v2 is serving all traffic: + +```bash +# v1 components (ingester, store-gateway, querier, compactor, query-scheduler) should be gone +kubectl get pods -n pyroscope -l app.kubernetes.io/instance=pyroscope +``` + +Verify that queries still return data: + +```bash +kubectl port-forward -n pyroscope svc/pyroscope-query-frontend 4040:4040 & +PF_PID=$! +sleep 2 +profilecli query series --url http://localhost:4040 --from "now-1h" --to "now" +kill $PF_PID +``` + +You should see series labels for recent profiling data. You can also open the Pyroscope UI at `http://localhost:4040` and verify that you can query recent profiles. An empty or errored UI indicates a problem — see [Rollback](#rollback). + +## Rollback + +### During Phase 1 or Phase 2 + +Rolling back is straightforward — set `architecture.storage.v2=false` to remove the v2 components and return to v1-only: + +```bash +helm upgrade -n pyroscope pyroscope grafana/pyroscope \ + --reuse-values \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=false +``` + +Data written to v2 during the dual-ingest period is orphaned but doesn't affect v1 operation. + +### During or after Phase 3 + +If you removed v1 components (Phase 3), rolling back requires redeploying them: + +```bash +helm upgrade -n pyroscope pyroscope grafana/pyroscope \ + --reuse-values \ + --set architecture.storage.v1=true \ + --set architecture.storage.v2=true +``` + +This returns you to dual-ingest mode (Phase 1). Note that any data ingested between Phase 3 and the rollback was only written to v2 and won't be visible through the v1 read path. + +## Helm values reference + +The following Helm values control the v1/v2 storage configuration and migration behavior. + +### Storage layer toggles + +| Value | Type | Default | Description | +|---------------------------|------|---------|-----------------------------------------------------------------------------------------------------| +| `architecture.storage.v1` | bool | `true` | Enable v1 storage and its components (ingester, store-gateway, querier, compactor). | +| `architecture.storage.v2` | bool | `false` | Enable v2 storage and its components (segment-writer, metastore, compaction-worker, query-backend). | + +### Migration tuning + +These values only apply when both `v1` and `v2` are enabled (dual-ingest mode). All values are under `architecture.storage.migration`. + +| Value | Type | Default | Description | +|--------------------------------|--------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `.ingesterWeight` | float | `1.0` | Fraction `[0, 1]` of write traffic sent to v1 ingesters. | +| `.segmentWriterWeight` | float | `1.0` | Fraction `[0, 1]` of write traffic sent to v2 segment-writers. | +| `.queryBackend` | bool | `true` | Enable the v2 query backend for reads. | +| `.queryBackendFrom` | string | `"auto"` | RFC 3339 timestamp (e.g. `2025-01-01T00:00:00Z`) from which the v2 read path serves traffic. When set to `auto`, the query frontend consults the metastore per tenant to determine when v2 data first appeared. If no v2 data exists for a tenant, queries fall back to v1. | diff --git a/docs/sources/reference-server-api/index.md b/docs/sources/reference-server-api/index.md new file mode 100644 index 0000000000..59697b97d5 --- /dev/null +++ b/docs/sources/reference-server-api/index.md @@ -0,0 +1,1123 @@ +--- +description: Learn about the Pyroscope server API +menuTitle: "Reference: Server API" +title: Server HTTP API +aliases: + - ../configure-server/about-server-api/ # https://grafana.com/docs/pyroscope/latest/configure-server/about-server-api/ +weight: 650 +--- + +# Grafana Pyroscope server API + +## Authentication + +Pyroscope doesn't include an authentication layer. Operators should use an authenticating reverse proxy for security. + +In multi-tenant mode, Pyroscope requires the X-Scope-OrgID HTTP header set to a string identifying the tenant. +The authenticating reverse proxy handles this responsibility. For more information, refer to the [multi-tenancy documentation](https://grafana.com/docs/pyroscope//configure-server/about-tenant-ids/). + + +## Connect API + +The Pyroscope Connect API uses the [Connect protocol](https://connectrpc.com/), which provides a unified approach to building APIs that work seamlessly across multiple protocols and formats: + +- **Protocol Flexibility**: Connect APIs work over both HTTP/1.1 and HTTP/2, supporting JSON and binary protobuf encoding +- **gRPC Compatibility**: Full compatibility with existing gRPC clients and servers while offering better browser and HTTP tooling support +- **Type Safety**: Generated from protobuf definitions, ensuring consistent types across client and server implementations +- **Developer Experience**: Simpler debugging with standard HTTP tools like curl, while maintaining the performance benefits of protobuf + +The API definitions are available in the [`api/`](https://github.com/grafana/pyroscope/tree/main/api) directory of the Pyroscope repository, with protobuf schemas organized by service. + +Pyroscope APIs are categorized into two scopes: + +- **Public APIs** (`scope/public`): These APIs are considered stable. Breaking changes will be communicated in advance and include migration paths. +- **Internal APIs** (`scope/internal`): These APIs are used for internal communication between Pyroscope components. They may change without notice and should not be used by external clients. + +### Ingestion Path + +#### `/push.v1.PusherService/Push` + + + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`series[].labels[].name` | Label name | `service_name` | +|`series[].labels[].value` | Label value | `my_service` | +|`series[].samples[].ID` | UUID of the profile | `734FD599-6865-419E-9475-932762D8F469` | +|`series[].samples[].rawProfile` | raw_profile is the set of bytes of the pprof profile | `PROFILE_BASE64` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "series": [ + { + "labels": [ + { + "name": "__name__", + "value": "process_cpu" + }, + { + "name": "service_name", + "value": "my_service" + } + ], + "samples": [ + { + "ID": "734FD599-6865-419E-9475-932762D8F469", + "rawProfile": "'$(cat cpu.pb.gz| base64 -w 0)'" + } + ] + } + ] + }' \ + http://localhost:4040/push.v1.PusherService/Push +``` + +```python +import requests +import base64 +body = { + "series": [ + { + "labels": [ + { + "name": "__name__", + "value": "process_cpu" + }, + { + "name": "service_name", + "value": "my_service" + } + ], + "samples": [ + { + "ID": "734FD599-6865-419E-9475-932762D8F469", + "rawProfile": base64.b64encode(open('cpu.pb.gz', 'rb').read()).decode('ascii') + } + ] + } + ] + } +url = 'http://localhost:4040/push.v1.PusherService/Push' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} + + +### Querying profiling data + +#### `/querier.v1.QuerierService/Diff` + +Diff returns a diff of two profiles + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`left.start` | Milliseconds since epoch. | `1676282400000` | +|`left.end` | Milliseconds since epoch. | `1676289600000` | +|`left.async.requestId` | If set, this is a polling request. | | +|`left.async.type` | Sets the kind of async query.. Possible values: `ASYNC_QUERY_TYPE_DISABLED`, `ASYNC_QUERY_TYPE_FORCE` | | +|`left.format` | Profile format specifies the format of profile to be returned. If not specified, the profile will be returned in flame graph format.. Possible values: `PROFILE_FORMAT_UNSPECIFIED`, `PROFILE_FORMAT_FLAMEGRAPH`, `PROFILE_FORMAT_TREE`, `PROFILE_FORMAT_DOT`, `PROFILE_FORMAT_PPROF` | | +|`left.labelSelector` | Label selector string | `{namespace="my-namespace"}` | +|`left.maxNodes` | Limit the nodes returned to only show the node with the max_node's biggest total | | +|`left.profileIdSelector` | List of Profile UUIDs to query | `["7c9e6679-7425-40de-944b-e07fc1f90ae7"]` | +|`left.profileTypeID` | Profile Type ID string in the form ::::. | `process_cpu:cpu:nanoseconds:cpu:nanoseconds` | +|`left.spanSelector` | List of span IDs (16 hex characters, 64-bit) to filter samples by. | `["9a517183f26a089d","5a4fe264a9c987fe"]` | +|`left.stackTraceSelector.callSite[].name` | | | +|`left.stackTraceSelector.goPgo.aggregateCallees` | Aggregate callees causes the leaf location line number to be ignored, thus aggregating all callee samples (but not callers). | | +|`left.stackTraceSelector.goPgo.keepLocations` | Specifies the number of leaf locations to keep. | | +|`left.traceIdSelector` | List of trace IDs (32 hex characters, 128-bit) to filter samples by. | `["7c9e66797425440de944be07fc1f90ae"]` | +|`right.start` | Milliseconds since epoch. | `1676282400000` | +|`right.end` | Milliseconds since epoch. | `1676289600000` | +|`right.async.requestId` | If set, this is a polling request. | | +|`right.async.type` | Sets the kind of async query.. Possible values: `ASYNC_QUERY_TYPE_DISABLED`, `ASYNC_QUERY_TYPE_FORCE` | | +|`right.format` | Profile format specifies the format of profile to be returned. If not specified, the profile will be returned in flame graph format.. Possible values: `PROFILE_FORMAT_UNSPECIFIED`, `PROFILE_FORMAT_FLAMEGRAPH`, `PROFILE_FORMAT_TREE`, `PROFILE_FORMAT_DOT`, `PROFILE_FORMAT_PPROF` | | +|`right.labelSelector` | Label selector string | `{namespace="my-namespace"}` | +|`right.maxNodes` | Limit the nodes returned to only show the node with the max_node's biggest total | | +|`right.profileIdSelector` | List of Profile UUIDs to query | `["7c9e6679-7425-40de-944b-e07fc1f90ae7"]` | +|`right.profileTypeID` | Profile Type ID string in the form ::::. | `process_cpu:cpu:nanoseconds:cpu:nanoseconds` | +|`right.spanSelector` | List of span IDs (16 hex characters, 64-bit) to filter samples by. | `["9a517183f26a089d","5a4fe264a9c987fe"]` | +|`right.stackTraceSelector.callSite[].name` | | | +|`right.stackTraceSelector.goPgo.aggregateCallees` | Aggregate callees causes the leaf location line number to be ignored, thus aggregating all callee samples (but not callers). | | +|`right.stackTraceSelector.goPgo.keepLocations` | Specifies the number of leaf locations to keep. | | +|`right.traceIdSelector` | List of trace IDs (32 hex characters, 128-bit) to filter samples by. | `["7c9e66797425440de944be07fc1f90ae"]` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "left": { + "end": '$(date +%s)000', + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": '$(expr $(date +%s) - 3600 )000', + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + }, + "right": { + "end": '$(date +%s)000', + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": '$(expr $(date +%s) - 3600 )000', + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + } + }' \ + http://localhost:4040/querier.v1.QuerierService/Diff +``` + +```python +import requests +import datetime +body = { + "left": { + "end": int(datetime.datetime.now().timestamp() * 1000), + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000), + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + }, + "right": { + "end": int(datetime.datetime.now().timestamp() * 1000), + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000), + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + } + } +url = 'http://localhost:4040/querier.v1.QuerierService/Diff' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/LabelNames` + +LabelNames returns a list of the existing label names. + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Query from this point in time, given in Milliseconds since epoch. | `1676282400000` | +|`end` | Query to this point in time, given in Milliseconds since epoch. | `1676289600000` | +|`matchers` | List of Label selectors | | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "start": '$(expr $(date +%s) - 3600 )000' + }' \ + http://localhost:4040/querier.v1.QuerierService/LabelNames +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000) + } +url = 'http://localhost:4040/querier.v1.QuerierService/LabelNames' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/LabelValues` + +LabelValues returns the existing label values for the provided label names. + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Query from this point in time, given in Milliseconds since epoch. | `1676282400000` | +|`end` | Query to this point in time, given in Milliseconds since epoch. | `1676289600000` | +|`matchers` | List of Label selectors | | +|`name` | Name of the label | `service_name` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "name": "service_name", + "start": '$(expr $(date +%s) - 3600 )000' + }' \ + http://localhost:4040/querier.v1.QuerierService/LabelValues +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "name": "service_name", + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000) + } +url = 'http://localhost:4040/querier.v1.QuerierService/LabelValues' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/ProfileTypes` + +ProfileType returns a list of the existing profile types. + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Milliseconds since epoch. If missing or zero, only the ingesters will be queried. | `1676282400000` | +|`end` | Milliseconds since epoch. If missing or zero, only the ingesters will be queried. | `1676289600000` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "start": '$(expr $(date +%s) - 3600 )000' + }' \ + http://localhost:4040/querier.v1.QuerierService/ProfileTypes +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000) + } +url = 'http://localhost:4040/querier.v1.QuerierService/ProfileTypes' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/SelectHeatmap` + +SelectHeatmap returns a heatmap visualization for the requested profiles. + Note: This endpoint is only available in the v2 storage layer + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Milliseconds since epoch. | `1676282400000` | +|`end` | Milliseconds since epoch. | `1676289600000` | +|`exemplarType` | Type of exemplars to include in the response. Needs to matching query_type or be NONE. Possible values: `EXEMPLAR_TYPE_UNSPECIFIED`, `EXEMPLAR_TYPE_NONE`, `EXEMPLAR_TYPE_INDIVIDUAL`, `EXEMPLAR_TYPE_SPAN` | `EXEMPLAR_TYPE_SPAN` | +|`groupBy` | Group by labels | `["pod"]` | +|`labelSelector` | Label selector string | `{namespace="my-namespace"}` | +|`limit` | Select the top N series by total value. | | +|`profileTypeID` | Profile Type ID string in the form ::::. | `process_cpu:cpu:nanoseconds:cpu:nanoseconds` | +|`queryType` | Query type: individual profiles or span profiles. Possible values: `HEATMAP_QUERY_TYPE_UNSPECIFIED`, `HEATMAP_QUERY_TYPE_INDIVIDUAL`, `HEATMAP_QUERY_TYPE_SPAN` | `HEATMAP_QUERY_TYPE_SPAN` | +|`step` | Query resolution step width in seconds | | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "exemplarType": "EXEMPLAR_TYPE_SPAN", + "groupBy": [ + "pod" + ], + "labelSelector": "{namespace=\"my-namespace\"}", + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "queryType": "HEATMAP_QUERY_TYPE_SPAN", + "start": '$(expr $(date +%s) - 3600 )000' + }' \ + http://localhost:4040/querier.v1.QuerierService/SelectHeatmap +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "exemplarType": "EXEMPLAR_TYPE_SPAN", + "groupBy": [ + "pod" + ], + "labelSelector": "{namespace=\"my-namespace\"}", + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "queryType": "HEATMAP_QUERY_TYPE_SPAN", + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000) + } +url = 'http://localhost:4040/querier.v1.QuerierService/SelectHeatmap' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/SelectMergeProfile` + +Deprecated: Use SelectMergeStacktraces with PROFILE_FORMAT_PPROF instead. + This RPC will remain supported in querier.v1 for backward compatibility; + future breaking API changes may be introduced in querier.v2. + SelectMergeProfile returns matching profiles aggregated in pprof format. It + will contain all information stored (so including filenames and line + number, if ingested). + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Milliseconds since epoch. | `1676282400000` | +|`end` | Milliseconds since epoch. | `1676289600000` | +|`labelSelector` | Label selector string | `{namespace="my-namespace"}` | +|`maxNodes` | Limit the nodes returned to only show the node with the max_node's biggest total | | +|`profileIdSelector` | List of Profile UUIDs to query | `["7c9e6679-7425-40de-944b-e07fc1f90ae7"]` | +|`profileTypeID` | Profile Type ID string in the form ::::. | `process_cpu:cpu:nanoseconds:cpu:nanoseconds` | +|`stackTraceSelector.callSite[].name` | | | +|`stackTraceSelector.goPgo.aggregateCallees` | Aggregate callees causes the leaf location line number to be ignored, thus aggregating all callee samples (but not callers). | | +|`stackTraceSelector.goPgo.keepLocations` | Specifies the number of leaf locations to keep. | | +|`traceIdSelector` | List of trace IDs (32 hex characters, 128-bit) to filter samples by. | `["7c9e66797425440de944be07fc1f90ae"]` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "start": '$(expr $(date +%s) - 3600 )000', + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + }' \ + http://localhost:4040/querier.v1.QuerierService/SelectMergeProfile +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000), + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + } +url = 'http://localhost:4040/querier.v1.QuerierService/SelectMergeProfile' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/SelectMergeSpanProfile` + +Deprecated: Use SelectMergeStacktraces with span_selector instead. + This RPC will remain supported in querier.v1 for backward compatibility; + future breaking API changes may be introduced in querier.v2. + SelectMergeSpanProfile returns matching profiles aggregated in a flamegraph + format. It will combine samples from within the same callstack, with each + element being grouped by its function name. + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Milliseconds since epoch. | `1676282400000` | +|`end` | Milliseconds since epoch. | `1676289600000` | +|`format` | Profile format specifies the format of profile to be returned. If not specified, the profile will be returned in flame graph format.. Possible values: `PROFILE_FORMAT_UNSPECIFIED`, `PROFILE_FORMAT_FLAMEGRAPH`, `PROFILE_FORMAT_TREE`, `PROFILE_FORMAT_DOT`, `PROFILE_FORMAT_PPROF` | | +|`labelSelector` | Label selector string | `{namespace="my-namespace"}` | +|`maxNodes` | Limit the nodes returned to only show the node with the max_node's biggest total | | +|`profileTypeID` | Profile Type ID string in the form ::::. | `process_cpu:cpu:nanoseconds:cpu:nanoseconds` | +|`spanSelector` | List of Span IDs to query | `["9a517183f26a089d","5a4fe264a9c987fe"]` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "labelSelector": "{namespace=\"my-namespace\"}", + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": '$(expr $(date +%s) - 3600 )000' + }' \ + http://localhost:4040/querier.v1.QuerierService/SelectMergeSpanProfile +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "labelSelector": "{namespace=\"my-namespace\"}", + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000) + } +url = 'http://localhost:4040/querier.v1.QuerierService/SelectMergeSpanProfile' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/SelectMergeStacktraces` + +SelectMergeStacktraces returns matching profiles aggregated in a flamegraph + format. It will combine samples from within the same callstack, with each + element being grouped by its function name. + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Milliseconds since epoch. | `1676282400000` | +|`end` | Milliseconds since epoch. | `1676289600000` | +|`async.requestId` | If set, this is a polling request. | | +|`async.type` | Sets the kind of async query.. Possible values: `ASYNC_QUERY_TYPE_DISABLED`, `ASYNC_QUERY_TYPE_FORCE` | | +|`format` | Profile format specifies the format of profile to be returned. If not specified, the profile will be returned in flame graph format.. Possible values: `PROFILE_FORMAT_UNSPECIFIED`, `PROFILE_FORMAT_FLAMEGRAPH`, `PROFILE_FORMAT_TREE`, `PROFILE_FORMAT_DOT`, `PROFILE_FORMAT_PPROF` | | +|`labelSelector` | Label selector string | `{namespace="my-namespace"}` | +|`maxNodes` | Limit the nodes returned to only show the node with the max_node's biggest total | | +|`profileIdSelector` | List of Profile UUIDs to query | `["7c9e6679-7425-40de-944b-e07fc1f90ae7"]` | +|`profileTypeID` | Profile Type ID string in the form ::::. | `process_cpu:cpu:nanoseconds:cpu:nanoseconds` | +|`spanSelector` | List of span IDs (16 hex characters, 64-bit) to filter samples by. | `["9a517183f26a089d","5a4fe264a9c987fe"]` | +|`stackTraceSelector.callSite[].name` | | | +|`stackTraceSelector.goPgo.aggregateCallees` | Aggregate callees causes the leaf location line number to be ignored, thus aggregating all callee samples (but not callers). | | +|`stackTraceSelector.goPgo.keepLocations` | Specifies the number of leaf locations to keep. | | +|`traceIdSelector` | List of trace IDs (32 hex characters, 128-bit) to filter samples by. | `["7c9e66797425440de944be07fc1f90ae"]` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": '$(expr $(date +%s) - 3600 )000', + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + }' \ + http://localhost:4040/querier.v1.QuerierService/SelectMergeStacktraces +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "labelSelector": "{namespace=\"my-namespace\"}", + "profileIdSelector": [ + "7c9e6679-7425-40de-944b-e07fc1f90ae7" + ], + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "spanSelector": [ + "9a517183f26a089d", + "5a4fe264a9c987fe" + ], + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000), + "traceIdSelector": [ + "7c9e66797425440de944be07fc1f90ae" + ] + } +url = 'http://localhost:4040/querier.v1.QuerierService/SelectMergeStacktraces' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/SelectSeries` + +SelectSeries returns a time series for the total sum of the requested + profiles. + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Milliseconds since epoch. | `1676282400000` | +|`end` | Milliseconds since epoch. | `1676289600000` | +|`aggregation` | Query resolution step width in seconds. Possible values: `TIME_SERIES_AGGREGATION_TYPE_SUM`, `TIME_SERIES_AGGREGATION_TYPE_AVERAGE` | | +|`exemplarType` | Type of exemplars to include in the response.. Possible values: `EXEMPLAR_TYPE_UNSPECIFIED`, `EXEMPLAR_TYPE_NONE`, `EXEMPLAR_TYPE_INDIVIDUAL`, `EXEMPLAR_TYPE_SPAN` | | +|`groupBy` | | `["pod"]` | +|`labelSelector` | Label selector string | `{namespace="my-namespace"}` | +|`limit` | Select the top N series by total value. | | +|`profileTypeID` | Profile Type ID string in the form ::::. | `process_cpu:cpu:nanoseconds:cpu:nanoseconds` | +|`stackTraceSelector.callSite[].name` | | | +|`stackTraceSelector.goPgo.aggregateCallees` | Aggregate callees causes the leaf location line number to be ignored, thus aggregating all callee samples (but not callers). | | +|`stackTraceSelector.goPgo.keepLocations` | Specifies the number of leaf locations to keep. | | +|`step` | | | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "groupBy": [ + "pod" + ], + "labelSelector": "{namespace=\"my-namespace\"}", + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "start": '$(expr $(date +%s) - 3600 )000' + }' \ + http://localhost:4040/querier.v1.QuerierService/SelectSeries +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "groupBy": [ + "pod" + ], + "labelSelector": "{namespace=\"my-namespace\"}", + "profileTypeID": "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000) + } +url = 'http://localhost:4040/querier.v1.QuerierService/SelectSeries' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} +#### `/querier.v1.QuerierService/Series` + +Series returns profiles series matching the request. A series is a unique + label set. + +A request body with the following fields is required: + +|Field | Description | Example | +|:-----|:------------|:--------| +|`start` | Milliseconds since epoch. If missing or zero, only the ingesters will be queried. | `1676282400000` | +|`end` | queried. | `1676289600000` | +|`labelNames` | List of label_names to request. If empty will return all label names in the result. | | +|`matchers` | List of label selector to apply to the result. | `["{namespace=\"my-namespace\"}"]` | + +{{< code >}} +```curl +curl \ + -H "Content-Type: application/json" \ + -d '{ + "end": '$(date +%s)000', + "matchers": [ + "{namespace=\"my-namespace\"}" + ], + "start": '$(expr $(date +%s) - 3600 )000' + }' \ + http://localhost:4040/querier.v1.QuerierService/Series +``` + +```python +import requests +import datetime +body = { + "end": int(datetime.datetime.now().timestamp() * 1000), + "matchers": [ + "{namespace=\"my-namespace\"}" + ], + "start": int((datetime.datetime.now()- datetime.timedelta(hours = 1)).timestamp() * 1000) + } +url = 'http://localhost:4040/querier.v1.QuerierService/Series' +resp = requests.post(url, json=body) +print(resp) +print(resp.content) +``` + +{{< /code >}} + + + +## Pyroscope Legacy HTTP API + +Grafana Pyroscope exposes an HTTP API for querying profiling data and ingesting profiling data from other sources. + + +### Ingestion + +There is one primary endpoint: `POST /ingest`. +It accepts profile data in the request body and metadata as query parameters. + +The following query parameters are accepted: + +| Name | Description | Notes | +|:-------------------|:----------------------------------------|:-------------------------------| +| `name` | application name | required | +| `from` | UNIX time of when the profiling started | required | +| `until` | UNIX time of when the profiling stopped | required | +| `format` | format of the profiling data | optional (default is `folded`) | +| `sampleRate` | sample rate used in Hz | optional (default is `100` Hz) | +| `spyName` | name of the spy used | optional | +| `units` | name of the profiling data unit | optional (default is `samples` | +| `aggregationType` | type of aggregation to merge profiles | optional (default is `sum`) | + + +`name` specifies application name. For example: +``` +my.awesome.app.cpu{env=staging,region=us-west-1} +``` + +The request body contains profiling data, and the Content-Type header may be used alongside format to determine the data format. + +Some of the query parameters depend on the format of profiling data. Pyroscope currently supports three major ingestion formats. + +#### Text formats + +These formats handle simple ingestion of profiling data, such as `cpu` samples, and typically don't support metadata (for example, labels) within the format. +All necessary metadata is derived from query parameters, and the format is specified by the `format` query parameter. + +**Supported formats:** + +- **Folded**: Also known as `collapsed`, this is the default format. Each line contains a stacktrace followed by the sample count for that stacktrace. For example: +``` +foo;bar 100 +foo;baz 200 +``` + +- **Lines**: Similar to `folded`, but it represents each sample as a separate line rather than aggregating samples per stacktrace. For example: +``` +foo;bar +foo;bar +foo;baz +foo;bar +``` + +#### The `pprof` format + +The `pprof` format is a widely used binary profiling data format, particularly prevalent in the Go ecosystem. + +When using this format, certain query parameters have specific behaviors: + +- **format**: This should be set to `pprof`. +- **name**: This parameter contains the _prefix_ of the application name. Since a single request might include multiple profile types, the complete application name is formed by concatenating this prefix with the profile type. For instance, if you send CPU profiling data and set `name` to `my-app{}`, it is displayed in Pyroscope as `my-app.cpu{}`. +- **units**, **aggregationType**, and **sampleRate**: These parameters are ignored. The actual values are determined based on the profile types present in the data (refer to the "Sample Type Configuration" section for more details). + +##### Sample type configuration + +Pyroscope server inherently supports standard Go profile types such as `cpu`, `inuse_objects`, `inuse_space`, `alloc_objects`, and `alloc_space`. When dealing with software that generates data in `pprof` format, you may need to supply a custom sample type configuration for Pyroscope to interpret the data correctly. + +For an example Python script to ingest a `pprof` file with a custom sample type configuration, see **[this Python script](https://github.com/grafana/pyroscope/tree/main/examples/api/ingest_pprof.py).** + +To ingest `pprof` data with custom sample type configuration, modify your requests as follows: +* Set Content-Type to `multipart/form-data`. +* Upload the profile data in a form file field named `profile`. +* Include the sample type configuration in a form file field named `sample_type_config`. + +A sample type configuration is a JSON object formatted like this: + +```json +{ + "inuse_space": { + "units": "bytes", + "aggregation": "average", + "display-name": "inuse_space_bytes", + "sampled": false + }, + "alloc_objects": { + "units": "objects", + "aggregation": "sum", + "display-name": "alloc_objects_count", + "sampled": true + }, + "cpu": { + "units": "samples", + "aggregation": "sum", + "display-name": "cpu_samples", + "sampled": true + }, + // pprof supports multiple profiles types in one file, + // so there can be multiple of these objects +} +``` + +Explanation of sample type configuration fields: + +- **units** + - Supported values: `samples`, `objects`, `bytes` + - Description: Changes the units displayed in the frontend. `samples` = CPU samples, `objects` = objects in RAM, `bytes` = bytes in RAM. +- **display-name** + - Supported values: Any string. + - Description: This becomes a suffix of the app name, e.g., `my-app.inuse_space_bytes`. +- **aggregation** + - Supported values: `sum`, `average`. + - Description: Alters how data is aggregated on the frontend. Use `sum` for data to be summed over time (e.g., CPU samples, memory allocations), and `average` for data to be averaged over time (e.g., memory in-use objects). +- **sampled** + - Supported values: `true`, `false`. + - Description: Determines if the sample rate (specified in the pprof file) is considered. Set to `true` for sampled events (e.g., CPU samples), and `false` for memory profiles. + +This configuration allows for customized visualization and analysis of various profile types within Pyroscope. + +#### JFR format + +This is the [Java Flight Recorder](https://openjdk.java.net/jeps/328) format, typically used by JVM-based profilers, also supported by our Java integration. + +When this format is used, some of the query parameters behave slightly different: +* `format` should be set to `jfr`. +* `name` contains the _prefix_ of the application name. Since a single request may contain multiple profile types, the final application name is created concatenating this prefix and the profile type. For example, if you send cpu profiling data and set `name` to `my-app{}`, it will appear in pyroscope as `my-app.cpu{}`. +* `units` is ignored, and the actual units depends on the profile types available in the data. +* `aggregationType` is ignored, and the actual aggregation type depends on the profile types available in the data. + +JFR ingestion support uses the profile metadata to determine which profile types are included, which depend on the kind of profiling being done. Currently supported profile types include: +* `cpu` samples, which includes only profiling data from runnable threads. +* `itimer` samples, similar to `cpu` profiling. +* `wall` samples, which includes samples from any threads independently of their state. +* `alloc_in_new_tlab_objects`, which indicates the number of new TLAB objects created. +* `alloc_in_new_tlab_bytes`, which indicates the size in bytes of new TLAB objects created. +* `alloc_outside_tlab_objects`, which indicates the number of new allocated objects outside any TLAB. +* `alloc_outside_tlab_bytes`, which indicates the size in bytes of new allocated objects outside any TLAB. + +##### JFR with labels + +In order to ingest JFR data with dynamic labels, you have to make the following changes to your requests: +* use an HTTP form (`multipart/form-data`) Content-Type. +* send the JFR data in a form file field called `jfr`. +* send `LabelsSnapshot` protobuf message in a form file field called `labels`. + +```protobuf +message Context { + // string_id -> string_id + map labels = 1; +} +message LabelsSnapshot { + // context_id -> Context + map contexts = 1; + // string_id -> string + map strings = 2; +} + +``` +Where `context_id` is a parameter [set in async-profiler](https://github.com/pyroscope-io/async-profiler/pull/1/files#diff-34c624b2fbf52c68fc3f15dee43a73caec11b9524319c3a581cd84ec3fd2aacfR218) + +#### Examples + +Here's a sample code that uploads a very simple profile to pyroscope: + +{{< code >}} + +```curl +printf "foo;bar 100\n foo;baz 200" | curl \ +-X POST \ +--data-binary @- \ +'http://localhost:4040/ingest?name=curl-test-app&from=1615709120&until=1615709130' + +``` + +```python +import requests +import urllib.parse +from datetime import datetime + +now = round(datetime.now().timestamp()) / 10 * 10 +params = {'from': f'{now - 10}', 'name': 'python.example{foo=bar}'} + +url = f'http://localhost:4040/ingest?{urllib.parse.urlencode(params)}' +data = "foo;bar 100\n" \ +"foo;baz 200" + +requests.post(url, data = data) +``` + +{{< /code >}} + + +Here's a sample code that uploads a JFR profile with labels to pyroscope: + +{{< code >}} + +```curl +curl -X POST \ + -F jfr=@profile.jfr \ + -F labels=@labels.pb \ + "http://localhost:4040/ingest?name=curl-test-app&units=samples&aggregationType=sum&sampleRate=100&from=1655834200&until=1655834210&spyName=javaspy&format=jfr" +``` + +{{< /code >}} + + +### Querying profile data + +There is one primary endpoint for querying profile data: `GET /pyroscope/render`. + +The search input is provided via query parameters. +The output is typically a JSON object containing one or more time series and a flame graph. + +#### Query parameters + +Here is an overview of the accepted query parameters: + +| Name | Description | Notes | +|:-----------|:---------------------------------------------------------------------------------------|:-----------------------------------------------------| +| `query` | contains the profile type and label selectors | required | +| `from` | UNIX time for the start of the search window | required | +| `until` | UNIX time for the end of the search window | optional (default is `now`) | +| `format` | format of the profiling data | optional (default is `json`) | +| `maxNodes` | the maximum number of nodes the resulting flame graph will contain | optional (default is `max_flamegraph_nodes_default`) | +| `groupBy` | one or more label names to group the time series by (doesn't apply to the flame graph) | optional (default is no grouping) | + +##### `query` + +The `query` parameter is the only required search input. It carries the profile type and any labels we want to use to narrow down the output. +The format for this parameter is similar to that of a PromQL query and can be defined as: + +`{="", ="", ...}` + +Here is a specific example: + +`process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name="my_application_name"}` + +In a Kubernetes environment, a query could also look like: + +`process_cpu:cpu:nanoseconds:cpu:nanoseconds{namespace="dev", container="my_application_name"}` + +{{% admonition type="note" %}} +Refer to the [profiling types documentation](https://grafana.com/docs/pyroscope//configure-client/profile-types/) for more information and [profile-metrics.json](https://github.com/grafana/pyroscope/blob/main/public/app/constants/profile-metrics.json) for a list of valid profile types. +{{% /admonition %}} + +##### `from` and `until` + +The `from` and `until` parameters determine the start and end of the time period for the query. +They can be provided in absolute and relative form. + +**Absolute time** + +This table details the options for passing absolute values. + +| Option | Example | Notes | +|:-----------------------|:----------------------|:-------------------| +| Date | `20231223` | Format: `YYYYMMDD` | +| Unix Time seconds | `1577836800` | | +| Unix Time milliseconds | `1577836800000` | | +| Unix Time microseconds | `1577836800000000` | | +| Unix Time nanoseconds | `1577836800000000000` | | + +**Relative time** + +Relative values are always expressed as offsets from `now`. + +| Option | Example | +|:---------------|:---------------------| +| 3 hours ago | `now-3h` | +| 30 minutes ago | `now-30m` | +| 2 days ago | `now-2d` | +| 1 week ago | `now-7d` or `now-1w` | + +Note that a single offset has to be provided, values such as `now-3h30m` will not work. + +**Validation** + +The `from` and `until` parameters are subject to validation rules related to `max_query_lookback` and `max_query_length` server parameters. +You can find more details on these parameters in the [limits section](https://grafana.com/docs/pyroscope//configure-server/reference-configuration-parameters#limits) of the server configuration docs. + +- If `max_query_lookback` is configured and`from` is before `now - max_query_lookback`, `from` will be set to `now - max_query_lookback`. +- If `max_query_lookback` is configured and `until` is before `now - max_query_lookback` the query will not be executed. +- If `max_query_length` is configured and the query interval is longer than this configuration, the query will no tbe executed. + +#### `format` + +The format can either be: +- `json`, in which case the response will contain a JSON object +- `dot`, in which case the response will be text containing a DOT representation of the profile + +See the [Query output](#query-output) section for more information on the response structure. + +#### `maxNodes` + +The `maxNodes` parameter truncates the number of elements in the profile response, to allow tools (for example, a frontend) to render large profiles efficiently. +This is typically used for profiles that are known to have large stack traces. + +When no value is provided, the default is taken from the `max_flamegraph_nodes_default` configuration parameter. +When a value is provided, it is capped to the `max_flamegraph_nodes_max` configuration parameter. + +#### `groupBy` + +The `groupBy` parameter impacts the output for the time series portion of the response. +When a valid label is provided, the response contains as many series as there are label values for the given label. + +{{% admonition type="note" %}} +Pyroscope supports a single label for the group by functionality. +{{% /admonition %}} + +### Query output + +The output of the `/pyroscope/render` endpoint is a JSON object based on the following [schema](https://github.com/grafana/pyroscope/blob/80959aeba2426f3698077fd8d2cd222d25d5a873/pkg/og/structs/flamebearer/flamebearer.go#L28-L43): + +```go +type FlamebearerProfileV1 struct { + Flamebearer FlamebearerV1 `json:"flamebearer"` + Metadata FlamebearerMetadataV1 `json:"metadata"` + Timeline *FlamebearerTimelineV1 `json:"timeline"` + Groups map[string]*FlamebearerTimelineV1 `json:"groups"` +} +``` + +#### `flamebearer` + +The `flamebearer` field contains data in a form suitable for rendering a flame graph. +Data within the `flamebearer` is organized in separate arrays containing the profile symbols and the sample values. + +#### `metadata` + +The `metadata` field contains additional information that is helpful to interpret the `flamebearer` data such as the unit (nanoseconds, bytes), sample rate and more. + +#### `timeline` + +The `timeline` field represents the time series for the profile. +Pyroscope pre-computes the step interval (resolution) of the timeline using the query interval (`from` and `until`). The minimum step interval is 10 seconds. + +The raw profile sample data is down-sampled to the step interval (resolution) using an aggregation function. Currently only `sum` is supported. + +A timeline contains a start time, a list of sample values and the step interval: + +```json +{ + "timeline": { + "startTime": 1577836800, + "samples": [ + 100, + 200, + 400 + ], + "durationDelta": 10 + } +} +``` + +#### `groups` + +The `groups` field is only populated when grouping is requested by the `groupBy` query parameter. +When this is the case, the `groups` field has an entry for every label value found for the query. + +This example groups by a cluster: + +```json +{ + "groups": { + "eu-west-2": { "startTime": 1577836800, "samples": [ 200, 300, 500 ] }, + "us-east-1": { "startTime": 1577836800, "samples": [ 100, 200, 400 ] } + } +} +``` + +### Alternative query output + +When the `format` query parameter is `dot`, the endpoint responds with a [DOT format](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) data representing the queried profile. +This can be used to create an alternative visualization of the profile. + +### Example queries + +This example queries a local Pyroscope server for a CPU profile from the `pyroscope` service for the last hour. + +```curl +curl \ + 'http://localhost:4040/pyroscope/render?query=process_cpu%3Acpu%3Ananoseconds%3Acpu%3Ananoseconds%7Bservice_name%3D%22pyroscope%22%7D&from=now-1h' +``` + +Here is the same query made more readable: + +```curl +curl --get \ + --data-urlencode "query=process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name=\"pyroscope\"}" \ + --data-urlencode "from=now-1h" \ + http://localhost:4040/pyroscope/render +``` + +Here is the same example in Python: + +```python +import requests + +application_name = 'my_application_name' +query = f'process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name="{application_name}"}' +query_from = 'now-1h' +url = f'http://localhost:4040/pyroscope/render?query={query}&from={query_from}' + +requests.get(url) +``` + +See [this Python script](https://github.com/grafana/pyroscope/tree/main/examples/api/query.py) for a complete example. + +## Profile CLI + +The `profilecli` tool can also be used to interact with the Pyroscope server API. +The tool supports operations such as ingesting profiles, querying for existing profiles, and more. +Refer to the [Profile CLI](https://grafana.com/docs/pyroscope//view-and-analyze-profile-data/profile-cli/) page for more information. diff --git a/docs/sources/reference-server-api/index.template b/docs/sources/reference-server-api/index.template new file mode 100644 index 0000000000..2a109b960b --- /dev/null +++ b/docs/sources/reference-server-api/index.template @@ -0,0 +1,457 @@ +--- +description: Learn about the Pyroscope server API +menuTitle: "Reference: Server API" +title: Server HTTP API +aliases: + - ../configure-server/about-server-api/ # https://grafana.com/docs/pyroscope/latest/configure-server/about-server-api/ +weight: 650 +--- + +# Grafana Pyroscope server API + +## Authentication + +Pyroscope doesn't include an authentication layer. Operators should use an authenticating reverse proxy for security. + +In multi-tenant mode, Pyroscope requires the X-Scope-OrgID HTTP header set to a string identifying the tenant. +The authenticating reverse proxy handles this responsibility. For more information, refer to the [multi-tenancy documentation](https://grafana.com/docs/pyroscope//configure-server/about-tenant-ids/). + + +## Connect API + +The Pyroscope Connect API uses the [Connect protocol](https://connectrpc.com/), which provides a unified approach to building APIs that work seamlessly across multiple protocols and formats: + +- **Protocol Flexibility**: Connect APIs work over both HTTP/1.1 and HTTP/2, supporting JSON and binary protobuf encoding +- **gRPC Compatibility**: Full compatibility with existing gRPC clients and servers while offering better browser and HTTP tooling support +- **Type Safety**: Generated from protobuf definitions, ensuring consistent types across client and server implementations +- **Developer Experience**: Simpler debugging with standard HTTP tools like curl, while maintaining the performance benefits of protobuf + +The API definitions are available in the [`api/`](https://github.com/grafana/pyroscope/tree/main/api) directory of the Pyroscope repository, with protobuf schemas organized by service. + +Pyroscope APIs are categorized into two scopes: + +- **Public APIs** (`scope/public`): These APIs are considered stable. Breaking changes will be communicated in advance and include migration paths. +- **Internal APIs** (`scope/internal`): These APIs are used for internal communication between Pyroscope components. They may change without notice and should not be used by external clients. + +### Ingestion Path + +{{ .RenderAPIGroup "/push.v1.PusherService" }} + +### Querying profiling data + +{{ .RenderAPIGroup "/querier.v1.QuerierService" }} + + +## Pyroscope Legacy HTTP API + +Grafana Pyroscope exposes an HTTP API for querying profiling data and ingesting profiling data from other sources. + + +### Ingestion + +There is one primary endpoint: `POST /ingest`. +It accepts profile data in the request body and metadata as query parameters. + +The following query parameters are accepted: + +| Name | Description | Notes | +|:-------------------|:----------------------------------------|:-------------------------------| +| `name` | application name | required | +| `from` | UNIX time of when the profiling started | required | +| `until` | UNIX time of when the profiling stopped | required | +| `format` | format of the profiling data | optional (default is `folded`) | +| `sampleRate` | sample rate used in Hz | optional (default is `100` Hz) | +| `spyName` | name of the spy used | optional | +| `units` | name of the profiling data unit | optional (default is `samples` | +| `aggregationType` | type of aggregation to merge profiles | optional (default is `sum`) | + + +`name` specifies application name. For example: +``` +my.awesome.app.cpu{env=staging,region=us-west-1} +``` + +The request body contains profiling data, and the Content-Type header may be used alongside format to determine the data format. + +Some of the query parameters depend on the format of profiling data. Pyroscope currently supports three major ingestion formats. + +#### Text formats + +These formats handle simple ingestion of profiling data, such as `cpu` samples, and typically don't support metadata (for example, labels) within the format. +All necessary metadata is derived from query parameters, and the format is specified by the `format` query parameter. + +**Supported formats:** + +- **Folded**: Also known as `collapsed`, this is the default format. Each line contains a stacktrace followed by the sample count for that stacktrace. For example: +``` +foo;bar 100 +foo;baz 200 +``` + +- **Lines**: Similar to `folded`, but it represents each sample as a separate line rather than aggregating samples per stacktrace. For example: +``` +foo;bar +foo;bar +foo;baz +foo;bar +``` + +#### The `pprof` format + +The `pprof` format is a widely used binary profiling data format, particularly prevalent in the Go ecosystem. + +When using this format, certain query parameters have specific behaviors: + +- **format**: This should be set to `pprof`. +- **name**: This parameter contains the _prefix_ of the application name. Since a single request might include multiple profile types, the complete application name is formed by concatenating this prefix with the profile type. For instance, if you send CPU profiling data and set `name` to `my-app{}`, it is displayed in Pyroscope as `my-app.cpu{}`. +- **units**, **aggregationType**, and **sampleRate**: These parameters are ignored. The actual values are determined based on the profile types present in the data (refer to the "Sample Type Configuration" section for more details). + +##### Sample type configuration + +Pyroscope server inherently supports standard Go profile types such as `cpu`, `inuse_objects`, `inuse_space`, `alloc_objects`, and `alloc_space`. When dealing with software that generates data in `pprof` format, you may need to supply a custom sample type configuration for Pyroscope to interpret the data correctly. + +For an example Python script to ingest a `pprof` file with a custom sample type configuration, see **[this Python script](https://github.com/grafana/pyroscope/tree/main/examples/api/ingest_pprof.py).** + +To ingest `pprof` data with custom sample type configuration, modify your requests as follows: +* Set Content-Type to `multipart/form-data`. +* Upload the profile data in a form file field named `profile`. +* Include the sample type configuration in a form file field named `sample_type_config`. + +A sample type configuration is a JSON object formatted like this: + +```json +{ + "inuse_space": { + "units": "bytes", + "aggregation": "average", + "display-name": "inuse_space_bytes", + "sampled": false + }, + "alloc_objects": { + "units": "objects", + "aggregation": "sum", + "display-name": "alloc_objects_count", + "sampled": true + }, + "cpu": { + "units": "samples", + "aggregation": "sum", + "display-name": "cpu_samples", + "sampled": true + }, + // pprof supports multiple profiles types in one file, + // so there can be multiple of these objects +} +``` + +Explanation of sample type configuration fields: + +- **units** + - Supported values: `samples`, `objects`, `bytes` + - Description: Changes the units displayed in the frontend. `samples` = CPU samples, `objects` = objects in RAM, `bytes` = bytes in RAM. +- **display-name** + - Supported values: Any string. + - Description: This becomes a suffix of the app name, e.g., `my-app.inuse_space_bytes`. +- **aggregation** + - Supported values: `sum`, `average`. + - Description: Alters how data is aggregated on the frontend. Use `sum` for data to be summed over time (e.g., CPU samples, memory allocations), and `average` for data to be averaged over time (e.g., memory in-use objects). +- **sampled** + - Supported values: `true`, `false`. + - Description: Determines if the sample rate (specified in the pprof file) is considered. Set to `true` for sampled events (e.g., CPU samples), and `false` for memory profiles. + +This configuration allows for customized visualization and analysis of various profile types within Pyroscope. + +#### JFR format + +This is the [Java Flight Recorder](https://openjdk.java.net/jeps/328) format, typically used by JVM-based profilers, also supported by our Java integration. + +When this format is used, some of the query parameters behave slightly different: +* `format` should be set to `jfr`. +* `name` contains the _prefix_ of the application name. Since a single request may contain multiple profile types, the final application name is created concatenating this prefix and the profile type. For example, if you send cpu profiling data and set `name` to `my-app{}`, it will appear in pyroscope as `my-app.cpu{}`. +* `units` is ignored, and the actual units depends on the profile types available in the data. +* `aggregationType` is ignored, and the actual aggregation type depends on the profile types available in the data. + +JFR ingestion support uses the profile metadata to determine which profile types are included, which depend on the kind of profiling being done. Currently supported profile types include: +* `cpu` samples, which includes only profiling data from runnable threads. +* `itimer` samples, similar to `cpu` profiling. +* `wall` samples, which includes samples from any threads independently of their state. +* `alloc_in_new_tlab_objects`, which indicates the number of new TLAB objects created. +* `alloc_in_new_tlab_bytes`, which indicates the size in bytes of new TLAB objects created. +* `alloc_outside_tlab_objects`, which indicates the number of new allocated objects outside any TLAB. +* `alloc_outside_tlab_bytes`, which indicates the size in bytes of new allocated objects outside any TLAB. + +##### JFR with labels + +In order to ingest JFR data with dynamic labels, you have to make the following changes to your requests: +* use an HTTP form (`multipart/form-data`) Content-Type. +* send the JFR data in a form file field called `jfr`. +* send `LabelsSnapshot` protobuf message in a form file field called `labels`. + +```protobuf +message Context { + // string_id -> string_id + map labels = 1; +} +message LabelsSnapshot { + // context_id -> Context + map contexts = 1; + // string_id -> string + map strings = 2; +} + +``` +Where `context_id` is a parameter [set in async-profiler](https://github.com/pyroscope-io/async-profiler/pull/1/files#diff-34c624b2fbf52c68fc3f15dee43a73caec11b9524319c3a581cd84ec3fd2aacfR218) + +#### Examples + +Here's a sample code that uploads a very simple profile to pyroscope: + +{{"{{< code >}}"}} + +```curl +printf "foo;bar 100\n foo;baz 200" | curl \ +-X POST \ +--data-binary @- \ +'http://localhost:4040/ingest?name=curl-test-app&from=1615709120&until=1615709130' + +``` + +```python +import requests +import urllib.parse +from datetime import datetime + +now = round(datetime.now().timestamp()) / 10 * 10 +params = {'from': f'{now - 10}', 'name': 'python.example{foo=bar}'} + +url = f'http://localhost:4040/ingest?{urllib.parse.urlencode(params)}' +data = "foo;bar 100\n" \ +"foo;baz 200" + +requests.post(url, data = data) +``` + +{{"{{< /code >}}"}} + + +Here's a sample code that uploads a JFR profile with labels to pyroscope: + +{{"{{< code >}}"}} + +```curl +curl -X POST \ + -F jfr=@profile.jfr \ + -F labels=@labels.pb \ + "http://localhost:4040/ingest?name=curl-test-app&units=samples&aggregationType=sum&sampleRate=100&from=1655834200&until=1655834210&spyName=javaspy&format=jfr" +``` + +{{"{{< /code >}}"}} + + +### Querying profile data + +There is one primary endpoint for querying profile data: `GET /pyroscope/render`. + +The search input is provided via query parameters. +The output is typically a JSON object containing one or more time series and a flame graph. + +#### Query parameters + +Here is an overview of the accepted query parameters: + +| Name | Description | Notes | +|:-----------|:---------------------------------------------------------------------------------------|:-----------------------------------------------------| +| `query` | contains the profile type and label selectors | required | +| `from` | UNIX time for the start of the search window | required | +| `until` | UNIX time for the end of the search window | optional (default is `now`) | +| `format` | format of the profiling data | optional (default is `json`) | +| `maxNodes` | the maximum number of nodes the resulting flame graph will contain | optional (default is `max_flamegraph_nodes_default`) | +| `groupBy` | one or more label names to group the time series by (doesn't apply to the flame graph) | optional (default is no grouping) | + +##### `query` + +The `query` parameter is the only required search input. It carries the profile type and any labels we want to use to narrow down the output. +The format for this parameter is similar to that of a PromQL query and can be defined as: + +`{="", ="", ...}` + +Here is a specific example: + +`process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name="my_application_name"}` + +In a Kubernetes environment, a query could also look like: + +`process_cpu:cpu:nanoseconds:cpu:nanoseconds{namespace="dev", container="my_application_name"}` + +{{"{{% admonition type=\"note\" %}}"}} +Refer to the [profiling types documentation](https://grafana.com/docs/pyroscope//configure-client/profile-types/) for more information and [profile-metrics.json](https://github.com/grafana/pyroscope/blob/main/public/app/constants/profile-metrics.json) for a list of valid profile types. +{{"{{% /admonition %}}"}} + +##### `from` and `until` + +The `from` and `until` parameters determine the start and end of the time period for the query. +They can be provided in absolute and relative form. + +**Absolute time** + +This table details the options for passing absolute values. + +| Option | Example | Notes | +|:-----------------------|:----------------------|:-------------------| +| Date | `20231223` | Format: `YYYYMMDD` | +| Unix Time seconds | `1577836800` | | +| Unix Time milliseconds | `1577836800000` | | +| Unix Time microseconds | `1577836800000000` | | +| Unix Time nanoseconds | `1577836800000000000` | | + +**Relative time** + +Relative values are always expressed as offsets from `now`. + +| Option | Example | +|:---------------|:---------------------| +| 3 hours ago | `now-3h` | +| 30 minutes ago | `now-30m` | +| 2 days ago | `now-2d` | +| 1 week ago | `now-7d` or `now-1w` | + +Note that a single offset has to be provided, values such as `now-3h30m` will not work. + +**Validation** + +The `from` and `until` parameters are subject to validation rules related to `max_query_lookback` and `max_query_length` server parameters. +You can find more details on these parameters in the [limits section](https://grafana.com/docs/pyroscope//configure-server/reference-configuration-parameters#limits) of the server configuration docs. + +- If `max_query_lookback` is configured and`from` is before `now - max_query_lookback`, `from` will be set to `now - max_query_lookback`. +- If `max_query_lookback` is configured and `until` is before `now - max_query_lookback` the query will not be executed. +- If `max_query_length` is configured and the query interval is longer than this configuration, the query will no tbe executed. + +#### `format` + +The format can either be: +- `json`, in which case the response will contain a JSON object +- `dot`, in which case the response will be text containing a DOT representation of the profile + +See the [Query output](#query-output) section for more information on the response structure. + +#### `maxNodes` + +The `maxNodes` parameter truncates the number of elements in the profile response, to allow tools (for example, a frontend) to render large profiles efficiently. +This is typically used for profiles that are known to have large stack traces. + +When no value is provided, the default is taken from the `max_flamegraph_nodes_default` configuration parameter. +When a value is provided, it is capped to the `max_flamegraph_nodes_max` configuration parameter. + +#### `groupBy` + +The `groupBy` parameter impacts the output for the time series portion of the response. +When a valid label is provided, the response contains as many series as there are label values for the given label. + +{{"{{% admonition type=\"note\" %}}"}} +Pyroscope supports a single label for the group by functionality. +{{"{{% /admonition %}}"}} + +### Query output + +The output of the `/pyroscope/render` endpoint is a JSON object based on the following [schema](https://github.com/grafana/pyroscope/blob/80959aeba2426f3698077fd8d2cd222d25d5a873/pkg/og/structs/flamebearer/flamebearer.go#L28-L43): + +```go +type FlamebearerProfileV1 struct { + Flamebearer FlamebearerV1 `json:"flamebearer"` + Metadata FlamebearerMetadataV1 `json:"metadata"` + Timeline *FlamebearerTimelineV1 `json:"timeline"` + Groups map[string]*FlamebearerTimelineV1 `json:"groups"` +} +``` + +#### `flamebearer` + +The `flamebearer` field contains data in a form suitable for rendering a flame graph. +Data within the `flamebearer` is organized in separate arrays containing the profile symbols and the sample values. + +#### `metadata` + +The `metadata` field contains additional information that is helpful to interpret the `flamebearer` data such as the unit (nanoseconds, bytes), sample rate and more. + +#### `timeline` + +The `timeline` field represents the time series for the profile. +Pyroscope pre-computes the step interval (resolution) of the timeline using the query interval (`from` and `until`). The minimum step interval is 10 seconds. + +The raw profile sample data is down-sampled to the step interval (resolution) using an aggregation function. Currently only `sum` is supported. + +A timeline contains a start time, a list of sample values and the step interval: + +```json +{ + "timeline": { + "startTime": 1577836800, + "samples": [ + 100, + 200, + 400 + ], + "durationDelta": 10 + } +} +``` + +#### `groups` + +The `groups` field is only populated when grouping is requested by the `groupBy` query parameter. +When this is the case, the `groups` field has an entry for every label value found for the query. + +This example groups by a cluster: + +```json +{ + "groups": { + "eu-west-2": { "startTime": 1577836800, "samples": [ 200, 300, 500 ] }, + "us-east-1": { "startTime": 1577836800, "samples": [ 100, 200, 400 ] } + } +} +``` + +### Alternative query output + +When the `format` query parameter is `dot`, the endpoint responds with a [DOT format](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) data representing the queried profile. +This can be used to create an alternative visualization of the profile. + +### Example queries + +This example queries a local Pyroscope server for a CPU profile from the `pyroscope` service for the last hour. + +```curl +curl \ + 'http://localhost:4040/pyroscope/render?query=process_cpu%3Acpu%3Ananoseconds%3Acpu%3Ananoseconds%7Bservice_name%3D%22pyroscope%22%7D&from=now-1h' +``` + +Here is the same query made more readable: + +```curl +curl --get \ + --data-urlencode "query=process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name=\"pyroscope\"}" \ + --data-urlencode "from=now-1h" \ + http://localhost:4040/pyroscope/render +``` + +Here is the same example in Python: + +```python +import requests + +application_name = 'my_application_name' +query = f'process_cpu:cpu:nanoseconds:cpu:nanoseconds{service_name="{application_name}"}' +query_from = 'now-1h' +url = f'http://localhost:4040/pyroscope/render?query={query}&from={query_from}' + +requests.get(url) +``` + +See [this Python script](https://github.com/grafana/pyroscope/tree/main/examples/api/query.py) for a complete example. + +## Profile CLI + +The `profilecli` tool can also be used to interact with the Pyroscope server API. +The tool supports operations such as ingesting profiles, querying for existing profiles, and more. +Refer to the [Profile CLI](https://grafana.com/docs/pyroscope//view-and-analyze-profile-data/profile-cli/) page for more information. diff --git a/docs/sources/release-notes/_index.md b/docs/sources/release-notes/_index.md index 536dc80065..a30cb358e7 100644 --- a/docs/sources/release-notes/_index.md +++ b/docs/sources/release-notes/_index.md @@ -9,6 +9,8 @@ weight: 100 Release notes for Grafana Pyroscope are in the CHANGELOG for the release and listed here by version number. +The last two minor versions of Grafana Pyroscope are supported and get security updates and bug fixes. + Packages are linked in the [Assets section for each Pyroscope release](https://github.com/grafana/pyroscope/releases). -{{< section >}} \ No newline at end of file +{{< section >}} diff --git a/docs/sources/release-notes/v1-1.md b/docs/sources/release-notes/v1-1.md index d14297ea19..6ec0ac025d 100644 --- a/docs/sources/release-notes/v1-1.md +++ b/docs/sources/release-notes/v1-1.md @@ -2,7 +2,7 @@ title: Version 1.1 release notes menuTitle: V1.1 description: Release notes for Grafana Pyroscope 1.1 -weight: 850 +weight: 890 --- # Version 1.1 release notes diff --git a/docs/sources/release-notes/v1-10.md b/docs/sources/release-notes/v1-10.md new file mode 100644 index 0000000000..ae6696ed94 --- /dev/null +++ b/docs/sources/release-notes/v1-10.md @@ -0,0 +1,36 @@ +--- +title: Version 1.10 release notes +menuTitle: V1.10 +description: Release notes for Grafana Pyroscope 1.10 +weight: 800 +--- + +# Version 1.10 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.10. + +This version of Pyroscope adds experimental support for OpenTelemetry profiles ([#2177](https://github.com/grafana/pyroscope/pull/2177)). +The OTLP protocol is not stable. For more information about the protocol, refer to [OpenTelemetry announces support for profiling](https://opentelemetry.io/blog/2024/profiling/). + +In addition, this release improves stability, performance, and documentation. + +Notable changes are listed below. For more details, check out the [1.10.0 changelog](https://github.com/grafana/pyroscope/compare/v1.9.0...v1.10.0). + +## Improvements and updates + +* Use `profilecli admin blocks query` to execute queries directly to single or multiple blocks hosted in your local host or remote bucket. ([#3618](https://github.com/grafana/pyroscope/pull/3618), [#3625](https://github.com/grafana/pyroscope/pull/3625), [#3610](https://github.com/grafana/pyroscope/pull/3610)) +* Rename `merge` commands to `profile` in [Profile CLI (`profilecli`)](https://grafana.com/docs/pyroscope/v1.10.x/view-and-analyze-profile-data/profile-cli/) ([#3630](https://github.com/grafana/pyroscope/pull/3630)) +* Deprecate cookie generated on server for GitHub integration ([#3573](https://github.com/grafana/pyroscope/pull/3573)) +* Add k6 middleware to Pyroscope ([#3580](https://github.com/grafana/pyroscope/pull/3580)) + +## Fixes + +* (eBPF) Use uint64 for proc offset ([#3656](https://github.com/grafana/pyroscope/pull/3656)) +* CI fixes ([#3634](https://github.com/grafana/pyroscope/pull/3634), [#3629](https://github.com/grafana/pyroscope/pull/3629), [#3632](https://github.com/grafana/pyroscope/pull/3632), [#3631](https://github.com/grafana/pyroscope/pull/3631), [#3636](https://github.com/grafana/pyroscope/pull/3636), [#3605](https://github.com/grafana/pyroscope/pull/3605), [#3525](https://github.com/grafana/pyroscope/pull/3625)) + +## Documentation + +* Add instructions for [how to receive profiles from Pyroscope SDKs](https://grafana.com/docs/pyroscope/v1.10.x/configure-client/grafana-alloy/receive_profiles//) for Grafana Alloy ([#3685](https://github.com/grafana/pyroscope/pull/3658)) +* Update [examples and references to Grafana Alloy](https://grafana.com/docs/pyroscope/v1.10.x/configure-client/grafana-alloy/) from Grafana Agent ([#3621](https://github.com/grafana/pyroscope/pull/3621)) +* Update and expand profiling types documentation for the [introduction](https://grafana.com/docs/pyroscope/v1.10.x/introduction/profiling-types/) and [instrumentation](https://grafana.com/docs/pyroscope/v1.10.x/configure-client/profile-types/) ([#3659](https://github.com/grafana/pyroscope/pull/3659)) +* Other documentation and example updates ([#3662](https://github.com/grafana/pyroscope/pull/3662), [#3644](https://github.com/grafana/pyroscope/pull/3644), [#3607](https://github.com/grafana/pyroscope/pull/3607), [#3655](https://github.com/grafana/pyroscope/pull/3655), [#3611](https://github.com/grafana/pyroscope/pull/3611), [#3638](https://github.com/grafana/pyroscope/pull/3638), [#3661](https://github.com/grafana/pyroscope/pull/3661), [#3614](https://github.com/grafana/pyroscope/pull/3614), [#3612](https://github.com/grafana/pyroscope/pull/3612), [#3648](https://github.com/grafana/pyroscope/pull/3648)) diff --git a/docs/sources/release-notes/v1-11.md b/docs/sources/release-notes/v1-11.md new file mode 100644 index 0000000000..48ebd73ee8 --- /dev/null +++ b/docs/sources/release-notes/v1-11.md @@ -0,0 +1,25 @@ +--- +title: Version 1.11 release notes +menuTitle: V1.11 +description: Release notes for Grafana Pyroscope 1.11 +weight: 790 +--- + +# Version 1.11 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.11. + +This release improves stability, performance, and documentation. + +Notable changes are listed below. For more details, check out the [1.11.0 changelog](https://github.com/grafana/pyroscope/compare/v1.10.0...v1.11.0). + + +## Fixes + +* Remove export to flamegraph.com ([#3729](https://github.com/grafana/pyroscope/pull/3729)) +* Flameql: allow slashes in application name ([#3722](https://github.com/grafana/pyroscope/pull/3722)) +* OTEL format fixes ([#3741](https://github.com/grafana/pyroscope/pull/3741), [#3792](https://github.com/grafana/pyroscope/pull/3792)) + +## Documentation + +* Documentation and example updates ([#3727](https://github.com/grafana/pyroscope/pull/3727), [#3664](https://github.com/grafana/pyroscope/pull/3664), [#3762](https://github.com/grafana/pyroscope/pull/3762), [#3686](https://github.com/grafana/pyroscope/pull/3686), [#3693](https://github.com/grafana/pyroscope/pull/3693), [#3770](https://github.com/grafana/pyroscope/pull/3770), [#3772](https://github.com/grafana/pyroscope/pull/3772), [#3695](https://github.com/grafana/pyroscope/pull/3695), [#3674](https://github.com/grafana/pyroscope/pull/3674), [#3584](https://github.com/grafana/pyroscope/pull/3584), [#3658](https://github.com/grafana/pyroscope/pull/3658), [#3678](https://github.com/grafana/pyroscope/pull/3678), [#3713](https://github.com/grafana/pyroscope/pull/3713), [#3777](https://github.com/grafana/pyroscope/pull/3777), [#3701](https://github.com/grafana/pyroscope/pull/3701), [#3789](https://github.com/grafana/pyroscope/pull/3789), [#3775](https://github.com/grafana/pyroscope/pull/3775), [#3698](https://github.com/grafana/pyroscope/pull/3698), [#3764](https://github.com/grafana/pyroscope/pull/3764), [#3780](https://github.com/grafana/pyroscope/pull/3780), [#3696](https://github.com/grafana/pyroscope/pull/3696), [#3753](https://github.com/grafana/pyroscope/pull/3753), [#3740](https://github.com/grafana/pyroscope/pull/3740), [#3782](https://github.com/grafana/pyroscope/pull/3782), [#3668](https://github.com/grafana/pyroscope/pull/3668), [#3773](https://github.com/grafana/pyroscope/pull/3773)) diff --git a/docs/sources/release-notes/v1-12.md b/docs/sources/release-notes/v1-12.md new file mode 100644 index 0000000000..2befb07f19 --- /dev/null +++ b/docs/sources/release-notes/v1-12.md @@ -0,0 +1,42 @@ +--- +title: Version 1.12 release notes +menuTitle: V1.12 +description: Release notes for Grafana Pyroscope 1.12 +weight: 780 +--- + +# Version 1.12.1 release notes + +To address bugs found in v1.12.0, we have released a patch version. + +Notable changes are listed below. For more details, check out the [1.12.1 changelog](https://github.com/grafana/pyroscope/compare/v1.12.0...v1.12.1). + +### Fixes +* Storage prefix validation (#4044) + +### Changes +* Update to golang 1.23.7 (necessary for a decendency upgrade) + +## Version 1.12.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.12. + +This release contains enhancements, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.12.0 changelog](https://github.com/grafana/pyroscope/compare/v1.11.0...v1.12.0). + +### Enhancements + +* Added metadata label query capability in v2 ([#3749](https://github.com/grafana/pyroscope/pull/3749)) +* Implemented configurable symbols partitioning ([#3820](https://github.com/grafana/pyroscope/pull/3820)) +* S3 storage can now configure the bucket-lookup-type ([#3788](https://github.com/grafana/pyroscope/pull/3788)) + +### Fixes +* String table access validation in distributor ([#3818](https://github.com/grafana/pyroscope/pull/3818)) +* Several OpenTelemetry (OTel) related fixes: ([#3795](https://github.com/grafana/pyroscope/pull/3795), [#3793](https://github.com/grafana/pyroscope/pull/3793), [#3794](https://github.com/grafana/pyroscope/pull/3794)) +* Config struct validation implementation ([#3837](https://github.com/grafana/pyroscope/pull/3837)) +* Expanded error logging to include 400 errors ([#3832](https://github.com/grafana/pyroscope/pull/3832)) + +### Documentation +* Restructure Pyroscope documentation and share content ([#3798](https://github.com/grafana/pyroscope/pull/3798)) +* Documentation fixes and example updates ([#3812](https://github.com/grafana/pyroscope/pull/3812), [#3806](https://github.com/grafana/pyroscope/pull/3806), [#3828](https://github.com/grafana/pyroscope/pull/3828), [#3809](https://github.com/grafana/pyroscope/pull/3809), [#3823](https://github.com/grafana/pyroscope/pull/3823)) diff --git a/docs/sources/release-notes/v1-13.md b/docs/sources/release-notes/v1-13.md new file mode 100644 index 0000000000..2b22003bfb --- /dev/null +++ b/docs/sources/release-notes/v1-13.md @@ -0,0 +1,75 @@ +--- +title: Version 1.13 release notes +menuTitle: V1.13 +description: Release notes for Grafana Pyroscope 1.13 +weight: 770 +--- + +## Version 1.13.6 release notes + +Maintenance release to address security advisories. + + +### Changes + +* Update golang version to 1.23.1 ([05cd2005](https://github.com/grafana/pyroscope/commits/05cd20055b6462211e774580a09137259cb58dae)) +* chore: Remove oauth2-proxy ([#4345](https://github.com/grafana/pyroscope/pull/4345)) + +## Version 1.13.5 release notes + +Maintenance release to address security advisories. + + +### Changes + +* Update golang version to 1.23.10 ([#4245](https://github.com/grafana/pyroscope/pull/4245)) +* Update golang.org/x/net to v0.38.0 to address CVE-2025-22872 + + +## Version 1.13.4 release notes + +This was a release to test the health of our CI pipelines + +## Version 1.13.3 + +This release version was skipped + +## Version 1.13.2 release notes + +To address bugs found in v1.13.1, we have released a patch version + +Notable changes are listed below. For more details, check out the [1.13.2 changelog](https://github.com/grafana/pyroscope/compare/v1.13.1...v1.13.2). + +### Changes + +* Update golang version to 1.23.8 ([#4116](https://github.com/grafana/pyroscope/pull/4116)) + + +## Version 1.13.1 release notes + +To address bugs found in v1.13.0, we have released a patch version + +Notable changes are listed below. For more details, check out the [1.13.1 changelog](https://github.com/grafana/pyroscope/compare/v1.13.0...v1.13.1). + +### Fixes + +* Storage prefix validation ([#4044](https://github.com/grafana/pyroscope/pull/4044)) +* Update minio-go to restore AWS STS auth ([#4056](https://github.com/grafana/pyroscope/pull/4056)) + +## Version 1.13.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.13.0 + +This release contains enhancements, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.13.0 changelog](https://github.com/grafana/pyroscope/compare/v1.12.0...v1.13.0). + +### Enhancements +* gzip: escape heap allocation ([#3922](https://github.com/grafana/pyroscope/pull/3922)) +* perf: add log buffer ([#3947](https://github.com/grafana/pyroscope/pull/3947)) +* perf: add async log writer ([#3953](https://github.com/grafana/pyroscope/pull/3953)) + +### Fixes +* Remove duplicate service_name and app_name labels during ingestion ([#3951](https://github.com/grafana/pyroscope/pull/3951)) +* IPv6 support fixes ([#3919](https://github.com/grafana/pyroscope/pull/3919)) +* Drop negative samples ([#3955](https://github.com/grafana/pyroscope/pull/3955)) diff --git a/docs/sources/release-notes/v1-14.md b/docs/sources/release-notes/v1-14.md new file mode 100644 index 0000000000..b72a651e07 --- /dev/null +++ b/docs/sources/release-notes/v1-14.md @@ -0,0 +1,46 @@ +--- +title: Version 1.14 release notes +menuTitle: V1.14 +description: Release notes for Grafana Pyroscope 1.14 +weight: 760 +--- + +## Version 1.14.1 release notes + +Maintenance release to address security advisories. + + +### Changes + +* Update golang version to 1.23.1 ([99610e61](https://github.com/grafana/pyroscope/commits/99610e61efeeeb34e45ef16d0ab3a6f9d1534a70)) +* chore: Remove oauth2-proxy ([#4345](https://github.com/grafana/pyroscope/pull/4345)) + +## Version 1.14.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.14.0 + +This release contains enhancements, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.14.0 changelog](https://github.com/grafana/pyroscope/compare/v1.13.0...v1.14.0). + +### Enhancements +* Profile throttling (#3956) +* Improve performance of `*stacktraceTree.insert` (#4033) +* Improve performance of `*deduplicatingSlice.ingest` (#4037) +* Symbolization support (#4093, #3799, #4173, #4259) +* Dynamically named usage groups (#4210, #4231) +* Mark storage.prefix as non experimental (#4086) + +### Fixes +* Validate query range that start <= end (#4229) +* Fix goroutine leaks (#4239, #4237) +* Fix panic in vcs getCommit when author empty (#4152) +* Storage prefix validation (#4044) +* Drop malformed locations (#4051) +* Fix object download error branch panic (#4102) +* Separate query and block context (#4122) + +### Documentation +* Add documentation about usage stats (#4104) +* Add OSS documentation on the Source Code GitHub integration (#4129) +* Add profiling instructions for MacOS (#4202) diff --git a/docs/sources/release-notes/v1-15.md b/docs/sources/release-notes/v1-15.md new file mode 100644 index 0000000000..60be06254d --- /dev/null +++ b/docs/sources/release-notes/v1-15.md @@ -0,0 +1,95 @@ +--- +title: Version 1.15 release notes +menuTitle: V1.15 +description: Release notes for Grafana Pyroscope 1.15 +weight: 750 +--- + +## Version 1.15.3 release notes + +Maintenance release to update Go version and address security vulnerability. + +### Changes + +* Update golang version to 1.24.11 ([#4707](https://github.com/grafana/pyroscope/pull/4707)) +* Patch golang.org/x/crypto/ssh vulnerability ([#4707](https://github.com/grafana/pyroscope/pull/4707)) + +## Version 1.15.2 release notes + +Maintenance release to address a security issue. + +### Changes + +* Fix: mask COS provider secret_key config CVE-2025-41118 ([#4700](https://github.com/grafana/pyroscope/pull/4700)) + +### Documentation + +* Generate API docs for connect-go API ([#4408](https://github.com/grafana/pyroscope/pull/4408)) +* Fix docs release workflow ([#4534](https://github.com/grafana/pyroscope/pull/4534)) + +## Version 1.15.1 release notes + +Maintenance release to update Go version. + +### Changes + +* Update golang version to 1.24.9 ([#4596](https://github.com/grafana/pyroscope/pull/4596)) + +## Version 1.15.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.15.0 + +This release contains enhancements, fixes, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.15.0 changelog](https://github.com/grafana/pyroscope/compare/v1.14.0...v1.15.0). + +### Enhancements +* Metastore auto-join (#4474) +* Bearer token support in profilecli (#4475) +* Helm support for v1/v2 storage (#4417) +* Sample type relabeling in distributor (#4376) +* Stacktrace selector support for `SelectMergeStacktraces` requests (#4380) +* Metadata index retention policy (#4148) +* Azure ClientSecretCredential authentication support (#4477) +* Add --max-nodes flag to query profile command in profilecli (#4433) +* Allow to optionally enforce maxNodes through limits (#4436) +* Set querier.max-flamegraph-nodes-max default to 1,048,576 (#4370) +* Annotate sampled profiles (#4375) +* Improve request observability (#4400) +* Serve recording rules from config in tenant-settings (#4299) +* Add block list/inspect to profilecli (#4412) +* Extract signal correlation information from OTEL profiles (#4393) +* Distributor performance improvements: single profile series processing (#4342), new metrics (#4367), multi-stage receive metrics (#4384) +* Performance: Use stacktrace tree for adhoc uploads (#4438) +* Performance: Initialize dataset segment head lazily (#4274) +* Performance: Avoid merging single profiles (#4421) +* Performance: Add searchHint to getSeriesIndex (#4286) +* Reduce memory allocations when rendering diff flamegraphs (#4430) +* Improve distributor sampling rule evaluation (#4347) + +### Fixes +* Fix panic in query pprof path (#4429) +* Fix panic when handling error in metastore snapshot compaction (#4313) +* Fix JFR: merge EnhancerBySpringCGLIB classes (#4471) +* Fix issue in pprof split when using `relabel.LabelDrop` (#4365) +* Fix breaking change in ProfileTypes v2 (#4398) +* Fix GetTenantStats reports wrong stats (#4394) +* Fix goroutine leak in compaction-worker (#4409) +* Fix location with empty lines parquet roundtrip (#4407) +* Fix nil check for empty stacktrace filters (#4308) +* Fix revert unintended change in profile merge (#4410) +* Fix vcs.decodeToken can eat an error (#4336) +* Fix Docker ebpf-otel example matches k8s versions (#4386) +* Fix integration test data of partially symbolized profile (#4446) +* Reapply: Handle duplicate validation correctly when sanitizing (#4265) +* Revert: Correct HasFunctions flags for mixed symbolization profiles (#4457) + +### Documentation +* Update docs and examples for .NET to add LD_LIBRARY_PATH (#4456) +* Add doc for finding URL, password, and user in Cloud Profiles (#4352) +* Update architecture and OS requirements for .NET (#4334) +* Update ebpf supported languages content (#4338) +* Fix typo and update link for GitHub integration (#4374) +* Update ride share tutorial documentation (#4277) +* Mention the dependency on the compactor feature flag (#4302) +* Fix .NET naming (#4289) diff --git a/docs/sources/release-notes/v1-16.md b/docs/sources/release-notes/v1-16.md new file mode 100644 index 0000000000..edd5d82539 --- /dev/null +++ b/docs/sources/release-notes/v1-16.md @@ -0,0 +1,78 @@ +--- +title: Version 1.16 release notes +menuTitle: V1.16 +description: Release notes for Grafana Pyroscope 1.16 +weight: 740 +--- + +## Version 1.16.2 release notes + +Maintenance release to update Go version and address security vulnerability. + +### Changes + +* Update golang version to 1.24.11 ([#4708](https://github.com/grafana/pyroscope/pull/4708)) +* Patch golang.org/x/crypto/ssh vulnerability ([#4708](https://github.com/grafana/pyroscope/pull/4708)) + +## Version 1.16.1 release notes + +Maintenance release to address a security issue. + +### Changes + +* Fix: mask COS provider secret_key config CVE-2025-41118 ([#4700](https://github.com/grafana/pyroscope/pull/4700)) + +## Version 1.16.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.16.0 + +This release contains enhancements, fixes, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.16.0 changelog](https://github.com/grafana/pyroscope/compare/v1.15.0...v1.16.0). + +### Enhancements +* Add OTLP HTTP/json and HTTP/protobuf ingestion (#4495) +* Add a basic metric for metastore DLQ recovery (#4563) +* Improve metastore observability (#4580) +* Add option to add annotations to headless service (#4451) +* Add admin pages for inspecting v2 blocks (#4480, #4543, #4555, #4560) +* Performance: Cancel artificial delay on async ingest (#4261) +* Add sanitized_label_names_total counter metric (#4501) +* Add pyroscope-monitoring helm chart (#4525) +* Implement utf8 label name client capability and use in UI/profilecli (#4442, #4490, #4493) +* Add OTLP canary query (#4488) +* Performance: add health check/warmup to segmentwriter to reduce first-write latency (#4453) +* Update golang version to 1.24.9 (#4596) + +### Fixes +* Fix distributor sampling rule processing priority (#4491) +* Fix panic in ad-hoc profile upload (#4556) +* Add ingest limits to connect push requests (#4586) +* Add profile_name label to Speedscope profile ingestion (#4588) +* Add stricter validation for metrics from profiles fields (#4522) +* Ensure to build the same architecture image, as the current machine (#4552) +* Fix go get in update-examples-cron.yml (#4547) +* Handle Speedscope sample types in ingestion (#4568) +* Handle utf-8 matchers correctly (#4496) +* Fix Helm release only supports one changed chart at a time (#4583) +* Fix OTLP: Guard against profiles with no lines (#4517) +* Redirect to admin pages when no query API available (#4553) +* Replace nop logger used in label validation (#4531) +* Skip duplicated label name filtering in some cases (#4502) +* Update deprecated GF_INSTALL_PLUGINS env var (#4554) +* Avoid flushing empty tenant settings (quick win) (#4458) +* Fix create fallback symbols for mappings without BuildIDs (#4527) +* Fix go version for update-contributors (#4582) +* Fix golang-push examples test (#4558) +* Fix incorrect multitenancy header handling in new HTTP OTLP endpoint (#4559) +* Fix not missing recording rules symbols by relaxing ObserveSymbols condition (#4545) +* Fix opentelemetry-collector otlphttp exporter compatibility: gzip compression (#4579) +* Fix panic when handling unsafe tenant name (#4519) +* Use github app to update-make-docs workflow (#4548) +* Don't 500 on bad profile types (#4537) +* Fix flaky admin test (#4528) +* Pin node to v23 in examples until latest (v25) is supported (#4561) + +### Documentation +* Update make docs procedure (#4551) +* Generate API docs for connect-go API (#4408) diff --git a/docs/sources/release-notes/v1-17.md b/docs/sources/release-notes/v1-17.md new file mode 100644 index 0000000000..6d0816b2a4 --- /dev/null +++ b/docs/sources/release-notes/v1-17.md @@ -0,0 +1,45 @@ +--- +title: Version 1.17 release notes +menuTitle: V1.17 +description: Release notes for Grafana Pyroscope 1.17 +weight: 730 +--- + +## Version 1.17.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.17.0 + +This release contains enhancements, fixes, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.17.0 changelog](https://github.com/grafana/pyroscope/compare/v1.16.0...v1.17.0). + +### Enhancements +* Exemplar support for individual profile retrieval (#4615) (#4621) (#4657) (#4657) (#4686) (#4605) (#4631) +* Introduce additional metastore compaction metrics (#4625) +* Add trace spans for query-frontend (#4620) +* Add tracing instrumentation to source code integration #4607) +* Minor symbolizer metrics improvements (#4597) +* Parallelize mapping symbolization to improve query performance (#4594) +* Add metric to track unsymbolized profile blocks at ingestion (#4619) +* lidia: dynsym symbols (#4691) +* perf: Merge duplicate annotations (#4646) +* vcs: Allow to provide functionName to the GetFile API. (#4613) + +### Fixes +* Address npm CVEs (#4682) +* Fix update-examples after ruby upgrade (#4687) +* Fix panic in pprof split when using relabel.LabelDrop (#4699) +* Assign appropriate HTTP status codes (#4684) +* Fetching go stdlib without configs (#4655) +* Implement Speedscope profile merging (#4592) +* limit max nodes in symbolization queries (#4629) +* mask COS provider secret_key config CVE-2025-41118 (#4700) +* Source code module path parsing (#4609) +* Set file name and line number in symbolization (#4610) +* SelectSeries not correct for single reports (#4617) +* Return modified labels after validation sanitization (#4662) + +### Documentation +* Fix reference to `.goreleaser.yaml` (#4658) +* Update release documentation to address pain points (#4626) +* Update release note docs to address website release notes (#4598) diff --git a/docs/sources/release-notes/v1-18.md b/docs/sources/release-notes/v1-18.md new file mode 100644 index 0000000000..97991ffbe4 --- /dev/null +++ b/docs/sources/release-notes/v1-18.md @@ -0,0 +1,37 @@ +--- +title: Version 1.18 release notes +menuTitle: V1.18 +description: Release notes for Grafana Pyroscope 1.18 +weight: 720 +--- + +## Version 1.18.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.18.0 + +This release contains enhancements, fixes, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.18.0 changelog](https://github.com/grafana/pyroscope/compare/v1.17.1...v1.18.0). + +### Enhancements +* The source code integration now supports Python ([#4726](https://github.com/grafana/pyroscope/pull/4726), [#4732](https://github.com/grafana/pyroscope/pull/4732), [#4730](https://github.com/grafana/pyroscope/pull/4730)) +* Implement comprehensive profile size limits across ingestion endpoints ([#4734](https://github.com/grafana/pyroscope/pull/4734)) +* Update golang version to 1.24.12 ([#4760](https://github.com/grafana/pyroscope/pull/4760)) +* Set a maximum ingestion body size by default ([#4761](https://github.com/grafana/pyroscope/pull/4761)) +* Update OpenTelemetry dependencies, `proto=v1.9.0` `profiles=v0.2.0` ([#4731](https://github.com/grafana/pyroscope/pull/4731)) +* Enforce maxNodes optionally on SelectMergeProfile through limits in v2 ([#4723](https://github.com/grafana/pyroscope/pull/4723)) +* Add benchmarks for timeseries query performance with exemplars ([#4665](https://github.com/grafana/pyroscope/pull/4665)) + +### Fixes +* Fix exemplar value calculation for split profiles ([#4753](https://github.com/grafana/pyroscope/pull/4753)) +* Relative matching for source code mapping ([#4754](https://github.com/grafana/pyroscope/pull/4754)) +* VCS Service: Failed file lookup should be 404 instead of 500 ([#4759](https://github.com/grafana/pyroscope/pull/4759)) +* Remove unintended double base64 encoding in vcs service ([#4703](https://github.com/grafana/pyroscope/pull/4703)) +* Frontend: Bump `qs` to address CVE-2025-15284 ([#4724](https://github.com/grafana/pyroscope/pull/4724)) +* Frontend: Bump `sweetalert2` to address GHSA-457r-cqc8-9vj9, GHSA-8jh9-wqpf-q52c and GHSA-pg98-6v7f-2xfv ([#4727](https://github.com/grafana/pyroscope/pull/4727)) +* Frontend: Bump `@remix-run/router` and `react-router` to address CVE-2026-22029 and CVE-2025-68470 ([#4763](https://github.com/grafana/pyroscope/pull/4763)) + +### Documentation +* Rename GitHub integration to source code integration ([#4755](https://github.com/grafana/pyroscope/pull/4755)) +* Update source code integration docs to include Java and Python support ([#4651](https://github.com/grafana/pyroscope/pull/4651)) +* Fix inline link in eBPF docs ([#4733](https://github.com/grafana/pyroscope/pull/4733)) diff --git a/docs/sources/release-notes/v1-19.md b/docs/sources/release-notes/v1-19.md new file mode 100644 index 0000000000..e64acdbef0 --- /dev/null +++ b/docs/sources/release-notes/v1-19.md @@ -0,0 +1,70 @@ +--- +title: Version 1.19 release notes +menuTitle: V1.19 +description: Release notes for Grafana Pyroscope 1.19 +weight: 710 +--- + +## Version 1.19.3 release notes + +### Improvements +* Update Go toolchain to 1.25.9 ([#5015](https://github.com/grafana/pyroscope/pull/5015)) + +## Version 1.19.2 release notes + +### Security fixes +* Update `github.com/go-jose/go-jose/v4` to v4.1.4 (security) ([#4984](https://github.com/grafana/pyroscope/pull/4984)) + +### Documentation +* Update .NET documentation ([#4949](https://github.com/grafana/pyroscope/pull/4949)) + +## Version 1.19.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.19.0 + +This release contains enhancements, fixes, improves stability & performance. + +Notable changes are listed below. For more details, check out the [1.19.0 changelog](https://github.com/grafana/pyroscope/compare/v1.18.0...v1.19.0). + +### Enhancements +* **profilecli**: Add `query top` command for top function analysis ([#4889](https://github.com/grafana/pyroscope/pull/4889)) +* **profilecli**: Add `recording-rules` command for rules self-service ([#4823](https://github.com/grafana/pyroscope/pull/4823)) +* **profilecli**: Add `kube-proxy` command for unified microservice access ([#4777](https://github.com/grafana/pyroscope/pull/4777)) +* **profilecli**: Add `--output=table|json` to `query series` ([#4890](https://github.com/grafana/pyroscope/pull/4890)) +* **profilecli**: Add `--span-selector` flag to `query profile` command ([#4873](https://github.com/grafana/pyroscope/pull/4873)) +* **profilecli**: Add `--force/-f` flag to overwrite output files ([#4776](https://github.com/grafana/pyroscope/pull/4776)) +* **profilecli**: Use `SelectMergeStacktraces` instead of `SelectMergeProfile` when `--tree` ([#4795](https://github.com/grafana/pyroscope/pull/4795)) +* Add support for Javascript and Typescript source code integration ([#4797](https://github.com/grafana/pyroscope/pull/4797)) +* Add configuration to skip label sanitization ([#4796](https://github.com/grafana/pyroscope/pull/4796)) +* Add S3 `aws_sdk_auth` config option ([#4819](https://github.com/grafana/pyroscope/pull/4819)) +* Add ad-hoc profiles Diff RPC ([#4850](https://github.com/grafana/pyroscope/pull/4850)) +* Add debug info upload service ([#4648](https://github.com/grafana/pyroscope/pull/4648)) +* Implement AttributeTable with string interning for exemplar labels ([#4756](https://github.com/grafana/pyroscope/pull/4756)) +* Allow retrieving heatmap from spans/individual profiles ([#4736](https://github.com/grafana/pyroscope/pull/4736)) +* Add normalization stats ([#4820](https://github.com/grafana/pyroscope/pull/4820)) +* Query diagnostics for v2 admin ([#4806](https://github.com/grafana/pyroscope/pull/4806)) +* Refactor symbolization into per-query backendWrapper ([#4887](https://github.com/grafana/pyroscope/pull/4887)) +* lidia: Add gopclntab support for Go symbol resolution ([#4782](https://github.com/grafana/pyroscope/pull/4782)) +* Update ebpf-profiler docs/examples to use official builds ([#4891](https://github.com/grafana/pyroscope/pull/4891)) +* Helm: Add `extraContainers` field to pyroscope helm chart ([#4783](https://github.com/grafana/pyroscope/pull/4783)) +* Helm: Allow to control mounting of shared volume ([#4809](https://github.com/grafana/pyroscope/pull/4809)) +* Update Go to 1.25.8 ([#4883](https://github.com/grafana/pyroscope/pull/4883)) + +### Fixes +* Filter profile IDs post-join instead of predicate push-down ([#4888](https://github.com/grafana/pyroscope/pull/4888)) +* Add `pyroscope_` prefix to memberlist metrics ([#4885](https://github.com/grafana/pyroscope/pull/4885)) +* Correctly visit str value on labels to not drop incorrect values from the string table ([#4826](https://github.com/grafana/pyroscope/pull/4826)) +* Correct datatype for Exemplar value uint64→int64 ([#4779](https://github.com/grafana/pyroscope/pull/4779)) +* Prevent panic in `Tree.IterateStacks` with >1024 root nodes ([#4841](https://github.com/grafana/pyroscope/pull/4841)) +* lidia: Use stable sort ([#4758](https://github.com/grafana/pyroscope/pull/4758)) +* Replace regex with manual string scanning in `DropGoTypeParameters` ([#4828](https://github.com/grafana/pyroscope/pull/4828)) +* Bump jfr-parser to v0.15.0 ([#4881](https://github.com/grafana/pyroscope/pull/4881)) + +### Documentation +* Update Java profile types support ([#4893](https://github.com/grafana/pyroscope/pull/4893)) +* Update profilecli docs for latest changes ([#4894](https://github.com/grafana/pyroscope/pull/4894)) +* Update profile-cli.md for #4980 ([#4902](https://github.com/grafana/pyroscope/pull/4902)) +* Update eBPF profiler supported languages ([#4822](https://github.com/grafana/pyroscope/pull/4822)) +* Remove `detect_subprocesses` from python client config ([#4854](https://github.com/grafana/pyroscope/pull/4854)) +* Clarify helm chart versioning strategy in release docs ([#4833](https://github.com/grafana/pyroscope/pull/4833)) +* Add traces-to-profiles example using wall profiles for Java ([#4863](https://github.com/grafana/pyroscope/pull/4863)) diff --git a/docs/sources/release-notes/v1-2.md b/docs/sources/release-notes/v1-2.md index d56e69dc1b..9f04f6410a 100644 --- a/docs/sources/release-notes/v1-2.md +++ b/docs/sources/release-notes/v1-2.md @@ -2,7 +2,7 @@ title: Version 1.2 release notes menuTitle: V1.2 description: Release notes for Grafana Pyroscope 1.2 -weight: 800 +weight: 880 --- # Version 1.2 release notes diff --git a/docs/sources/release-notes/v1-20.md b/docs/sources/release-notes/v1-20.md new file mode 100644 index 0000000000..9762b8501a --- /dev/null +++ b/docs/sources/release-notes/v1-20.md @@ -0,0 +1,82 @@ +--- +title: Version 1.20 release notes +menuTitle: V1.20 +description: Release notes for Grafana Pyroscope 1.20 +weight: 700 +--- + +## Version 1.20.4 release notes + +### Security fixes +* Bump `protocol-buffers-schema` to 3.6.1 (security) ([#5059](https://github.com/grafana/pyroscope/pull/5059)) +* Bump `protobufjs` to 7.5.5 (security) ([#5062](https://github.com/grafana/pyroscope/pull/5062)) + +## Version 1.20.3 release notes + +### Improvements +* Update Go toolchain to 1.25.9 ([#5015](https://github.com/grafana/pyroscope/pull/5015)) + +## Version 1.20.2 release notes + +### Security fixes +* Update `github.com/go-jose/go-jose/v4` to v4.1.4 (security) ([#4984](https://github.com/grafana/pyroscope/pull/4984)) + +## Version 1.20.1 release notes + +### Security fixes +* Update dependency vite to v8.0.5 (security) ([#4994](https://github.com/grafana/pyroscope/pull/4994)) + +## Version 1.20.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.20.0. + +This release contains enhancements, fixes, improves stability & performance, and ships new v1 → v2 migration documentation. + +Notable changes are listed below. For more details, check out the [1.20.0 changelog](https://github.com/grafana/pyroscope/compare/v1.19.1...v1.20.0). + +### Enhancements +* Add flags to disable v1 components in single-binary v2 mode ([#4934](https://github.com/grafana/pyroscope/pull/4934)) +* Implement `SelectMergeTree` via the `model.Tree` ([#4790](https://github.com/grafana/pyroscope/pull/4790)) +* Switch tracing instrumentation to OpenTelemetry ([#4855](https://github.com/grafana/pyroscope/pull/4855)) +* Add trace ID field to profile storage schema ([#4884](https://github.com/grafana/pyroscope/pull/4884)) +* Add tenant ID config for self-profiling ([#4880](https://github.com/grafana/pyroscope/pull/4880)) +* Enable native histograms across all classic-only histogram metrics ([#4961](https://github.com/grafana/pyroscope/pull/4961)) +* Log query weight on the read path ([#4964](https://github.com/grafana/pyroscope/pull/4964)) +* Log decompressed size of JFR, OTLP (and other non-pprof) profiles ([#4968](https://github.com/grafana/pyroscope/pull/4968)) +* Frontend: support `auto` for `--enable-query-backend-from` flag ([#4926](https://github.com/grafana/pyroscope/pull/4926)) +* Metastore: add log store write timeout to prevent stuck raft leader ([#4892](https://github.com/grafana/pyroscope/pull/4892)) +* **profilecli**: Add exemplar query and profile-id drill-down ([#4939](https://github.com/grafana/pyroscope/pull/4939)) +* **profilecli**: Add span exemplar query command ([#4953](https://github.com/grafana/pyroscope/pull/4953)) +* **profilecli**: Rename `exemplars individual` to `exemplars profile` ([#4954](https://github.com/grafana/pyroscope/pull/4954)) +* Helm: Support `global.imageRegistry` ([#4866](https://github.com/grafana/pyroscope/pull/4866)) +* JFR: Switch to `klauspost/compress` for gzip decompression ([#4958](https://github.com/grafana/pyroscope/pull/4958)) +* Bump `jfr-parser` to v0.16.0 ([#4960](https://github.com/grafana/pyroscope/pull/4960)) +* Update OTLP version ([#4952](https://github.com/grafana/pyroscope/pull/4952)) +* Update `parquet-go` to v0.26.4 ([#4925](https://github.com/grafana/pyroscope/pull/4925)) +* Embedded UI v2 refactor ([#4948](https://github.com/grafana/pyroscope/pull/4948)) +* Prune `infiniteStrategy` from distributor ([#4913](https://github.com/grafana/pyroscope/pull/4913)) +* Exercise exemplars on the canary exporter ([#4959](https://github.com/grafana/pyroscope/pull/4959)) + +### Fixes +* OTLP: Extend `v1.AnyValue` possible types in `stringValueFromAnyValue` ([#4988](https://github.com/grafana/pyroscope/pull/4988)) +* OTLP: Handle slice-typed sample attributes from pprof OTLP profiles ([#4966](https://github.com/grafana/pyroscope/pull/4966)) +* Symbolizer: Skip locations with `MappingId 0` instead of erroring ([#4985](https://github.com/grafana/pyroscope/pull/4985)) +* symdb: Bounds-check mapping and function IDs in `SymbolMerger` ([#4967](https://github.com/grafana/pyroscope/pull/4967)) +* Fix `BinaryJoinIterator` unalignment bug ([#4950](https://github.com/grafana/pyroscope/pull/4950)) +* Metastore: Implement `MonotonicLogStore` on `timeoutLogStore` ([#4935](https://github.com/grafana/pyroscope/pull/4935)) +* Querier: Surface previously dropped errors ([#4914](https://github.com/grafana/pyroscope/pull/4914)) +* **profilecli**: Remove duplicate `--collect-diagnostics` flag ([#4911](https://github.com/grafana/pyroscope/pull/4911)) +* debug-info: Use `LimitReader` ([#4898](https://github.com/grafana/pyroscope/pull/4898)) +* lidia: Tolerate `elf.ErrNoSymbols` when both symbol tables are missing ([#4895](https://github.com/grafana/pyroscope/pull/4895)) +* Helm: Filter `pyroscope.components` by storage flags in microservices mode ([#4946](https://github.com/grafana/pyroscope/pull/4946)) +* Fix CVE vulnerabilities in `go.mod` files ([#4970](https://github.com/grafana/pyroscope/pull/4970)) +* Update `google.golang.org/grpc` to v1.79.3 (security) ([#4921](https://github.com/grafana/pyroscope/pull/4921)) +* Update `github.com/buger/jsonparser` to v1.1.2 (security) ([#4962](https://github.com/grafana/pyroscope/pull/4962)) + +### Documentation +* Add v1 → v2 migration guide ([#4927](https://github.com/grafana/pyroscope/pull/4927)) +* v2 architecture and components docs ([#4912](https://github.com/grafana/pyroscope/pull/4912)) +* Update .NET documentation ([#4949](https://github.com/grafana/pyroscope/pull/4949)) +* Move otel-collector eBPF example and update docs ([#4969](https://github.com/grafana/pyroscope/pull/4969)) +* Add V2 run instructions to `AGENTS.md` ([#4899](https://github.com/grafana/pyroscope/pull/4899)) +* Update list of contributors in README ([#4963](https://github.com/grafana/pyroscope/pull/4963)) diff --git a/docs/sources/release-notes/v1-21.md b/docs/sources/release-notes/v1-21.md new file mode 100644 index 0000000000..1287843669 --- /dev/null +++ b/docs/sources/release-notes/v1-21.md @@ -0,0 +1,67 @@ +--- +title: Version 1.21 release notes +menuTitle: V1.21 +description: Release notes for Grafana Pyroscope 1.21 +weight: 690 +--- + +## Version 1.21.1 release notes + +### Fixes +* **querier**: Clone label values to prevent buffer reuse-after-free in concurrent `LabelValues` queries ([#5116](https://github.com/grafana/pyroscope/pull/5116)) + +### Security fixes +* Update `github.com/prometheus/prometheus` to v0.311.3 (security) ([#5113](https://github.com/grafana/pyroscope/pull/5113)) +* Bump `postcss` from 8.5.8 to 8.5.13 in `/ui` (security) ([#5105](https://github.com/grafana/pyroscope/pull/5105)) +* Bump `ip-address` from 10.1.0 to 10.2.0 in `/ui` (security) ([#5114](https://github.com/grafana/pyroscope/pull/5114)) +* Bump `uuid` from 11.1.0 to 11.1.1 in `/ui` (security) ([#5123](https://github.com/grafana/pyroscope/pull/5123)) + +## Version 1.21.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 1.21.0. + +This release contains enhancements, fixes, and improves stability & performance. It is the final v1.x feature release before Pyroscope 2.0 ships v2 storage as the default. + +Notable changes are listed below. For the full diff, check out the [1.21.0 changelog](https://github.com/grafana/pyroscope/compare/v1.20.4...v1.21.0). + +### Enhancements + +* **debuginfo**: Rewrite upload API to work over HTTP/1.1 ([#5046](https://github.com/grafana/pyroscope/pull/5046)) +* **debuginfo**: Add per-request timeout for upload handler ([#5056](https://github.com/grafana/pyroscope/pull/5056)) +* **querier**: Add DOT format support to `SelectMergeStacktraces` Connect API ([#5047](https://github.com/grafana/pyroscope/pull/5047)) +* **query-frontend**: Log `user_agent` on query log lines ([#5042](https://github.com/grafana/pyroscope/pull/5042)) +* **v2**: Move default storage paths under `./data/v2/` ([#4978](https://github.com/grafana/pyroscope/pull/4978)) +* Log HTTP protocol version in per-request logs ([#5014](https://github.com/grafana/pyroscope/pull/5014)) +* Helm: Add `pyroscope.rbac.create` toggle ([#5067](https://github.com/grafana/pyroscope/pull/5067)) +* Helm: Add `HTTPRoute` support ([#4983](https://github.com/grafana/pyroscope/pull/4983)) +* Bump `go.opentelemetry.io/otel` to v1.43.0 across all modules ([#5037](https://github.com/grafana/pyroscope/pull/5037)) +* Update Go toolchain to 1.25.9 ([#5015](https://github.com/grafana/pyroscope/pull/5015)) + +### Fixes + +* **compactor**: Fix blocks cleaner hanging indefinitely after `SIGTERM` ([#4992](https://github.com/grafana/pyroscope/pull/4992)) +* **segment-writer**: Tolerate `ErrServerStopped` in client test suite ([#4977](https://github.com/grafana/pyroscope/pull/4977)) +* **scheduler**: Replace `bufconn` with TCP listener to fix flaky test ([#5052](https://github.com/grafana/pyroscope/pull/5052)) +* **ui**: Align time-series line graph with actual data points ([#5041](https://github.com/grafana/pyroscope/pull/5041)) +* **ui**: Fix file-naming collision when building UI on macOS ([#5055](https://github.com/grafana/pyroscope/pull/5055)) +* **ui**: Bump `dompurify`, `immutable`, `brace-expansion` to fix Trivy CVEs ([#5070](https://github.com/grafana/pyroscope/pull/5070)) +* **profilecli**: Preserve label-name casing in table output ([#4989](https://github.com/grafana/pyroscope/pull/4989)) +* Helm: Remove redundant adaptive-placement default ([#5057](https://github.com/grafana/pyroscope/pull/5057)) +* Fix `pkg/test/integration.TestStatusCode` ([#5058](https://github.com/grafana/pyroscope/pull/5058)) + +### Security fixes + +* Bump `protobufjs` to 7.5.5 (security) ([#5062](https://github.com/grafana/pyroscope/pull/5062)) +* Bump `protocol-buffers-schema` to 3.6.1 (security) ([#5059](https://github.com/grafana/pyroscope/pull/5059)) +* Bump `axios` (security) ([#5045](https://github.com/grafana/pyroscope/pull/5045)) +* Bump `lodash` from 4.17.23 to 4.18.1 (security) ([#4974](https://github.com/grafana/pyroscope/pull/4974)) +* Bump `rack-session` (security) ([#5003](https://github.com/grafana/pyroscope/pull/5003)) +* Bump `rack-session` in `/examples/tracing/ruby` (security) ([#5011](https://github.com/grafana/pyroscope/pull/5011)) +* Update `vite` to v8.0.5 (security) ([#4994](https://github.com/grafana/pyroscope/pull/4994)) +* Update `github.com/go-jose/go-jose/v4` to v4.1.4 (security) ([#4984](https://github.com/grafana/pyroscope/pull/4984)) + +### Documentation + +* Fix v1 → v2 migration guide prereq check and port-forward race ([#5044](https://github.com/grafana/pyroscope/pull/5044)) +* Clarify `HeatmapSlot` timestamp semantics ([#4986](https://github.com/grafana/pyroscope/pull/4986)) +* Fix Rust SDK documentation and examples for v2.0.0 ([#4972](https://github.com/grafana/pyroscope/pull/4972)) diff --git a/docs/sources/release-notes/v1-3.md b/docs/sources/release-notes/v1-3.md index c98576c9ac..d58317acfc 100644 --- a/docs/sources/release-notes/v1-3.md +++ b/docs/sources/release-notes/v1-3.md @@ -2,7 +2,7 @@ title: Version 1.3 release notes menuTitle: V1.3 description: Release notes for Grafana Pyroscope 1.3 -weight: 750 +weight: 870 --- # Version 1.3 release notes @@ -19,7 +19,7 @@ Several major improvements were made to the compaction process: * Improved system stability during compaction shutdown * Added a `profilecli compact` command -Notable changes are listed below. For more details, check out the **Full 1.3.0 Changelog**: https://github.com/grafana/pyroscope/compare/v1.2.1...v1.3.0 +Notable changes are listed below. For more details, check out the [1.3.0 changelog](https://github.com/grafana/pyroscope/compare/v1.2.1...v1.3.0). ## Features and enhancements diff --git a/docs/sources/release-notes/v1-4.md b/docs/sources/release-notes/v1-4.md index 4b37a31ed1..90d9153b43 100644 --- a/docs/sources/release-notes/v1-4.md +++ b/docs/sources/release-notes/v1-4.md @@ -2,7 +2,7 @@ title: Version 1.4 release notes menuTitle: V1.4 description: Release notes for Grafana Pyroscope 1.4 -weight: 700 +weight: 860 --- # Version 1.4 release notes @@ -17,7 +17,7 @@ This release includes several new features which are precursors to larger projec Additionally, numerous other changes improve stability, performance, and documentation. -Notable changes are listed below. For more details, check out the Full 1.4.0 Changelog: https://github.com/grafana/pyroscope/compare/v1.3.0...v1.4.0. +Notable changes are listed below. For more details, check out the [1.4.0 changelog](https://github.com/grafana/pyroscope/compare/v1.3.0...v1.4.0). ## Features and enhancements diff --git a/docs/sources/release-notes/v1-5.md b/docs/sources/release-notes/v1-5.md index 11683308de..15bbaa9bf4 100644 --- a/docs/sources/release-notes/v1-5.md +++ b/docs/sources/release-notes/v1-5.md @@ -2,7 +2,7 @@ title: Version 1.5 release notes menuTitle: V1.5 description: Release notes for Grafana Pyroscope 1.5 -weight: 650 +weight: 850 --- # Version 1.5 release notes @@ -11,7 +11,7 @@ We are excited to present Grafana Pyroscope 1.5. This release focuses on improving stability and interoperability to make Pyroscope more reliable and easier to use. -Notable changes are listed below. For more details, check out the Full 1.5.0 Changelog: https://github.com/grafana/pyroscope/compare/v1.4.0...v1.5.0. +Notable changes are listed below. For more details, check out the [1.5.0 changelog](https://github.com/grafana/pyroscope/compare/v1.4.0...v1.5.0). ### Improvements and updates diff --git a/docs/sources/release-notes/v1-6.md b/docs/sources/release-notes/v1-6.md index c3d9532444..62f65d3845 100644 --- a/docs/sources/release-notes/v1-6.md +++ b/docs/sources/release-notes/v1-6.md @@ -2,7 +2,7 @@ title: Version 1.6 release notes menuTitle: V1.6 description: Release notes for Grafana Pyroscope 1.6 -weight: 600 +weight: 840 --- # Version 1.6 release notes @@ -13,7 +13,7 @@ This release focuses on improving stability and performance to make Pyroscope mo Notable changes are listed below. For more details, check out the Full 1.6.0 Changelog: https://github.com/grafana/pyroscope/compare/v1.5.0...v1.6.0. -### Improvements and updates +## Improvements and updates Version 1.6 includes the following improvements and updates: @@ -27,7 +27,6 @@ Version 1.6 includes the following improvements and updates: * Config: Add S3 force-path-style parameter (https://github.com/grafana/pyroscope/pull/3158) * Config: Add flag to disable printing banner (https://github.com/grafana/pyroscope/pull/3123) - ## Fixes Version 1.6 includes the following fixes: @@ -40,7 +39,6 @@ Version 1.6 includes the following fixes: * eBPF: Fix issue when a cls arg is a cell (https://github.com/grafana/pyroscope/pull/3280) * eBPF: handle case when self is put in cell (https://github.com/grafana/pyroscope/pull/3284) - ## Documentation improvements Version 1.6 includes the following documentation updates: diff --git a/docs/sources/release-notes/v1-7.md b/docs/sources/release-notes/v1-7.md new file mode 100644 index 0000000000..8c1d143d1b --- /dev/null +++ b/docs/sources/release-notes/v1-7.md @@ -0,0 +1,61 @@ +--- +title: Version 1.7 release notes +menuTitle: V1.7 +description: Release notes for Grafana Pyroscope 1.7 +weight: 830 +--- + +# Version 1.7 release notes + +We are excited to present Grafana Pyroscope 1.7. + +This release includes several new features: + +* The ability to relabel profiles at ingest time +* Per-app (service) usage metrics +* Stacktrace selectors for merge profile queries +* Profile `pprof` export tailored to Go PGO + +Additionally, we've improved stability, performance, and documentation. + +Notable changes are listed below. For more details, check out the [1.7.0 changelog](https://github.com/grafana/pyroscope/compare/v1.6.0...v1.7.0). + +## Improvements and updates + +Version 1.7 includes the following improvements and updates: + +* Ability to relabel profiles at ingest ([#3369](https://github.com/grafana/pyroscope/pull/3369)) +* Use Grafana Alloy (instead of Grafana Agent) in the Helm chart ([#3381](https://github.com/grafana/pyroscope/pull/3381)) +* Per-app usage metrics ([#3429](https://github.com/grafana/pyroscope/pull/3429)) +* Add stacktrace selectors to query merge ([#3412](https://github.com/grafana/pyroscope/pull/3412)) +* `pprof` export for Go PGO ([#3360](https://github.com/grafana/pyroscope/pull/3360)) +* Custom binary format for symdb ([#3138](https://github.com/grafana/pyroscope/pull/3138)) +* Repair truncated Go CPU profiles ([#3344](https://github.com/grafana/pyroscope/pull/3344)) +* Add initial load tests ([#3331](https://github.com/grafana/pyroscope/pull/3331)) +* Align default step for `/render` with Grafana ([#3326](https://github.com/grafana/pyroscope/pull/3326)) +* Allow use of different protocols in `profilecli` ([#3368](https://github.com/grafana/pyroscope/pull/3368)) +* Various performance improvements (#3395, #3345, #3349, #3351, #3386, #3348, #3358) +* Improve readiness check for ingesters and frontend ([#3435](https://github.com/grafana/pyroscope/pull/3435)) + +## Fixes + +Version 1.7 includes the following fixes: + +* Fix error handling in filterProfiles ([#3338](https://github.com/grafana/pyroscope/pull/3338)) +* Fix frontend header handling ([#3363](https://github.com/grafana/pyroscope/pull/3363)) +* Fix line numbers for pyspy ([#3337](https://github.com/grafana/pyroscope/pull/3337)) +* Don't compute delta on relabeled `godeltaprof` memory profiles ([#3398](https://github.com/grafana/pyroscope/pull/3398)) +* Honor stacktrace partitions at downsampling ([#3408](https://github.com/grafana/pyroscope/pull/3408)) +* Fix infinite loop in index writer ([#3356](https://github.com/grafana/pyroscope/pull/3356)) + +## Documentation improvements + +Version 1.7 includes the following documentation updates: + +* Add a Grafana installation to all examples ([#3431](https://github.com/grafana/pyroscope/pull/3431)) +* Fix broken links ([#3440](https://github.com/grafana/pyroscope/pull/3440)) +* Remove `--stability-level` for Alloy v1.2 ([#3382](https://github.com/grafana/pyroscope/pull/3382)) +* Add parameters from otel-profiling-java ([#3444](https://github.com/grafana/pyroscope/pull/3444)) +* Add supported languages for eBPF ([#3434](https://github.com/grafana/pyroscope/pull/3434)) +* Link to supported languages ([#3432](https://github.com/grafana/pyroscope/pull/3432)) +* Update link to play.grafana.org ([#3433](https://github.com/grafana/pyroscope/pull/3433)) diff --git a/docs/sources/release-notes/v1-8.md b/docs/sources/release-notes/v1-8.md new file mode 100644 index 0000000000..4f3c1536aa --- /dev/null +++ b/docs/sources/release-notes/v1-8.md @@ -0,0 +1,38 @@ +--- +title: Version 1.8 release notes +menuTitle: V1.8 +description: Release notes for Grafana Pyroscope 1.8 +weight: 820 +--- + +# Version 1.8 release notes + +We are excited to present Grafana Pyroscope 1.8. + +We've improved stability, performance, and documentation. + +Notable changes are listed below. For more details, check out the [1.8.0 changelog](https://github.com/grafana/pyroscope/compare/v1.7.0...v1.8.0). + +## Improvements and updates + +Version 1.8 includes the following improvements and updates: + +* Add ready command to profilecli ([#3497](https://github.com/grafana/pyroscope/pull/3497)) + +## Fixes + +Version 1.8 includes the following fixes: + +* Handle context correctly in selectTree during queries on store-gateway with deduplication ([#3504](https://github.com/grafana/pyroscope/pull/3504)) +* Bring back update-contributors but in go ([#3512](https://github.com/grafana/pyroscope/pull/3512)) +* FlameQL: allow dots in tag name ([#3479](https://github.com/grafana/pyroscope/pull/3479)) +* Fix pprof grouping for samples with span_id ([#3450](https://github.com/grafana/pyroscope/pull/3450)) + +## Documentation improvements + +Version 1.8 includes the following documentation updates: + +* Fix broken links from doc 404 report ([#3489](https://github.com/grafana/pyroscope/pull/3489)) +* Clarify which URL to use with profilecli ([#3526](https://github.com/grafana/pyroscope/pull/3526)) +* Add notice about heap profiling ([#3494](https://github.com/grafana/pyroscope/pull/3494)) +* Remove old GF_FEATURE_TOGGLES_ENABLE=flameGraph ([#3446](https://github.com/grafana/pyroscope/pull/3446)) diff --git a/docs/sources/release-notes/v1-9.md b/docs/sources/release-notes/v1-9.md new file mode 100644 index 0000000000..bc2f179385 --- /dev/null +++ b/docs/sources/release-notes/v1-9.md @@ -0,0 +1,36 @@ +--- +title: Version 1.9 release notes +menuTitle: V1.9 +description: Release notes for Grafana Pyroscope 1.9 +weight: 810 +--- + +# Version 1.9 release notes + +We are excited to present Grafana Pyroscope 1.9. + +We've improved stability, performance, and documentation. + +Notable changes are listed below. For more details, check out the [1.9.0 changelog](https://github.com/grafana/pyroscope/compare/v1.8.0...v1.9.0). + +## Improvements and updates + +* Performance improvement during profile ingestion (https://github.com/grafana/pyroscope/pull/3569, https://github.com/grafana/pyroscope/pull/3561) +* Support resolve symbols in mini debug info (https://github.com/grafana/pyroscope/pull/3590) +* Make service_name configurable through environment variable (https://github.com/grafana/pyroscope/pull/3589) +* Add limit to SelectSeries API (https://github.com/grafana/pyroscope/pull/3602) +* Add topologySpreadConstraint in Helm (https://github.com/grafana/pyroscope/pull/3539) +* Rename GitSession to `pyroscope_git_session` (https://github.com/grafana/pyroscope/pull/3542) + +## Fixes + +* Make pprof merge thread-safe (https://github.com/grafana/pyroscope/pull/3564) +* Fix flaky tests (https://github.com/grafana/pyroscope/pull/3571) +* Fix slice init length (https://github.com/grafana/pyroscope/pull/3600) +* Fix issues when porting alloy/pyroscope to android (https://github.com/grafana/pyroscope/pull/3582) + +## Documentation improvements + +* Update the README to highlight explore profiles (https://github.com/grafana/pyroscope/pull/3581) +* Update NodeJS examples (https://github.com/grafana/pyroscope/pull/3555) +* Example for Java profiling using Grafana Alloy in Kubernetes (https://github.com/grafana/pyroscope/pull/3603) diff --git a/docs/sources/release-notes/v2-0.md b/docs/sources/release-notes/v2-0.md new file mode 100644 index 0000000000..5367249cf6 --- /dev/null +++ b/docs/sources/release-notes/v2-0.md @@ -0,0 +1,101 @@ +--- +title: Version 2.0 release notes +menuTitle: V2.0 +description: Release notes for Grafana Pyroscope 2.0 +weight: 680 +--- + +## Version 2.0.6 release notes + +### Security fixes +* Update Go toolchain to 1.25.12, addressing CVE-2026-42505 and CVE-2026-39822 (security) ([#5338](https://github.com/grafana/pyroscope/pull/5338)) + +## Version 2.0.5 release notes + +### Security fixes +* Update `golang.org/x/image` to v0.43.0 and refresh related `golang.org/x` dependencies for CVE fixes (security) ([#5281](https://github.com/grafana/pyroscope/pull/5281)) + +## Version 2.0.4 release notes + +### Security fixes +* Refresh the `/ui` dependency tree to clear known frontend vulnerabilities. The flame graph is now vendored, removing `@grafana/flamegraph` and its vulnerable transitive dependencies `protobufjs` (CVE-2026-44293, CVE-2026-44291, CVE-2026-48712) and `dompurify` (CVE-2026-49978, GHSA-vxr8-fq34-vvx9, GHSA-gvmj-g25r-r7wr, GHSA-x4vx-rjvf-j5p4); and `vite` (CVE-2026-53571), `@babel/core` (CVE-2026-49356), `tar` (CVE-2026-53655), and `js-yaml` (CVE-2026-53550) are updated to patched versions (security) ([#5264](https://github.com/grafana/pyroscope/pull/5264)) + +## Version 2.0.3 release notes + +### Fixes +* **store-gateway**: Validate `tenantID` ([#5194](https://github.com/grafana/pyroscope/pull/5194)) +* **query-backend**: Don't panic on unknown `QueryNode` type ([#5196](https://github.com/grafana/pyroscope/pull/5196)) +* **embedded grafana**: Clean up zip-slip/tar-slip in archive extraction ([#5195](https://github.com/grafana/pyroscope/pull/5195)) +* **embedded grafana**: Close files properly in `extractZip` and `extractTarGz` ([#5206](https://github.com/grafana/pyroscope/pull/5206)) + +### Security fixes +* Update Go toolchain to 1.25.11, addressing CVE-2026-27145, CVE-2026-42504, and CVE-2026-42507 (security) ([#5228](https://github.com/grafana/pyroscope/pull/5228)) +* Update `golang.org/x/crypto` to v0.52.0 (security) ([#5197](https://github.com/grafana/pyroscope/pull/5197)) +* Update `golang.org/x/net` to v0.55.0 (security) ([#5131](https://github.com/grafana/pyroscope/pull/5131)) +* Update `golang.org/x/image` to v0.41.0 (security) ([#5216](https://github.com/grafana/pyroscope/pull/5216)) +* Patch CVE-2026-45149 and CVE-2026-46625 in `/ui` yarn dependencies ([#5181](https://github.com/grafana/pyroscope/pull/5181)) + +## Version 2.0.2 release notes + +### Fixes +* **querier**: Clone label values to prevent buffer reuse-after-free in concurrent `LabelValues` queries ([#5116](https://github.com/grafana/pyroscope/pull/5116)) + +### Security fixes +* Update `github.com/prometheus/prometheus` to v0.311.3 (security) ([#5113](https://github.com/grafana/pyroscope/pull/5113)) +* Bump `postcss` from 8.5.8 to 8.5.13 in `/ui` (security) ([#5105](https://github.com/grafana/pyroscope/pull/5105)) +* Bump `ip-address` from 10.1.0 to 10.2.0 in `/ui` (security) ([#5114](https://github.com/grafana/pyroscope/pull/5114)) +* Bump `uuid` from 11.1.0 to 11.1.1 in `/ui` (security) ([#5123](https://github.com/grafana/pyroscope/pull/5123)) + +## Version 2.0.1 release notes + +### Fixes + +* **goreleaser**: Stamp `github.com/grafana/pyroscope/v2/pkg/util/build` in build ldflags so `pyroscope -version` and the `pyroscope_build_info` metric report `Version`, `Branch`, `Revision`, and `BuildDate` correctly. Restores the v2.0.0 regression where those fields were empty ([#5084](https://github.com/grafana/pyroscope/pull/5084)) + +## Version 2.0.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 2.0.0. + +Pyroscope 2.0 makes the v2 storage architecture (segment-writer, query-backend, metastore, compaction-worker) the default for OSS users. v2 writes profiles directly to object storage and removes the need for in-memory ingesters, simplifying operations and reducing resource usage at scale. v1 remains available via an opt-in flag so existing deployments can upgrade without data loss. + +This release contains breaking changes. Review the [v1 to v2 migration guide](../../reference-pyroscope-v2-architecture/migrate-from-v1/) before upgrading. + +Notable changes are listed below. For the full diff, check out the [2.0.0 changelog](https://github.com/grafana/pyroscope/compare/v1.21.0...v2.0.0). + +### Breaking changes + +* Go module path bumped to `github.com/grafana/pyroscope/v2`. Library consumers must update their imports ([#5073](https://github.com/grafana/pyroscope/pull/5073)) +* Default write path flipped from `ingester` to `segment-writer`. Set `-write-path=ingester` to preserve v1 behavior ([#5038](https://github.com/grafana/pyroscope/pull/5038)) +* Default storage backend flipped from empty to `filesystem` ([#5038](https://github.com/grafana/pyroscope/pull/5038)) +* New `-architecture.storage` flag (`v1` | `v1-v2-dual` | `v2`), default `v1-v2-dual` ([#5038](https://github.com/grafana/pyroscope/pull/5038)) +* Error at startup when `-architecture.storage` includes v2 and no object-storage backend is configured ([#5074](https://github.com/grafana/pyroscope/pull/5074)) +* Default filesystem paths moved under `./data/v2/` ([#5038](https://github.com/grafana/pyroscope/pull/5038)) +* Removed `PYROSCOPE_V2_EXPERIMENTAL` environment variable ([#5038](https://github.com/grafana/pyroscope/pull/5038)) +* Removed legacy positional `server` argument from the `pyroscope` binary ([#5038](https://github.com/grafana/pyroscope/pull/5038)) +* Label sanitization disabled by default; UTF-8 label names with dots are accepted as-is. Set `-validation.disable-label-sanitization=false` to restore previous behavior ([#5038](https://github.com/grafana/pyroscope/pull/5038)) +* Helm chart 2.0.0 replaces `all.enable-v1-write-path` / `all.enable-v1-read-path` with `architecture.storage`, removes `persistence.shared` and `migration.queryBackend`, and forwards `ingesterWeight` / `segmentWriterWeight` correctly ([#5076](https://github.com/grafana/pyroscope/pull/5076)) + +### Enhancements + +* **profilecli**: Add `debuginfo upload` subcommand ([#5080](https://github.com/grafana/pyroscope/pull/5080)) + +### Fixes + +* Fix missed v1 import path in `pyroscope_test.go` after module bump to v2 ([#5077](https://github.com/grafana/pyroscope/pull/5077)) +* **make**: Add `frontend/build` dependency to `reference-help` target ([#5071](https://github.com/grafana/pyroscope/pull/5071)) + +### Documentation + +* Improve v1 → v2 migration docs: switch to `--reset-then-reuse-values`, target chart 2.0.0 ([#5079](https://github.com/grafana/pyroscope/pull/5079)) +* Add v1.21 release notes ([#5082](https://github.com/grafana/pyroscope/pull/5082)) +* Fix contributors grid layout in README ([#5078](https://github.com/grafana/pyroscope/pull/5078)) + +### Upgrade + +To upgrade from v1.21.x: + +1. Read the [v1 to v2 migration guide](../../reference-pyroscope-v2-architecture/migrate-from-v1/). +2. If you import Pyroscope as a Go library, update imports to `github.com/grafana/pyroscope/v2`. +3. If you deploy with Helm, upgrade to chart `2.0.0` and review the removed and renamed values listed above. +4. If you run the binary directly and want to stay on v1 storage, set `-architecture.storage=v1` and `-write-path=ingester` explicitly — the previous defaults no longer apply. +5. If you want to move to v2, configure object storage and set `-architecture.storage=v2` (or leave `v1-v2-dual` during the transition). diff --git a/docs/sources/release-notes/v2-1.md b/docs/sources/release-notes/v2-1.md new file mode 100644 index 0000000000..4b19c10cd7 --- /dev/null +++ b/docs/sources/release-notes/v2-1.md @@ -0,0 +1,69 @@ +--- +title: Version 2.1 release notes +menuTitle: V2.1 +description: Release notes for Grafana Pyroscope 2.1 +weight: 670 +--- + +## Version 2.1.1 release notes + +### Security fixes +* Update Go toolchain to 1.25.12, addressing CVE-2026-42505 and CVE-2026-39822 (security) ([#5338](https://github.com/grafana/pyroscope/pull/5338)) + +## Version 2.1.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 2.1.0. + +This release adds new operational metrics, expands debug information management APIs, improves Helm chart defaults for the v2 storage architecture, and includes stability and security fixes across the read path, store-gateway, metastore, UI, and dependencies. + +Notable changes are listed below. For the full diff, check out the [2.1.0 changelog](https://github.com/grafana/pyroscope/compare/v2.0.3...v2.1.0). + +### Enhancements + +* **distributor**: Add readiness checks ([#5142](https://github.com/grafana/pyroscope/pull/5142)) +* **debuginfo**: Add list and delete APIs, including `profilecli` support ([#5217](https://github.com/grafana/pyroscope/pull/5217)) +* **segment-writer**: Build dataset indexes in segments ([#5112](https://github.com/grafana/pyroscope/pull/5112)) +* **metastore**: Add cache hit and miss metrics ([#5156](https://github.com/grafana/pyroscope/pull/5156)) +* **distributor**: Add ingest parse duration histogram metrics for `/ingest` ([#5107](https://github.com/grafana/pyroscope/pull/5107)) +* **query-backend**: Add per-tenant, per-query bytes-fetched metrics ([#5180](https://github.com/grafana/pyroscope/pull/5180)) +* **query-frontend**: Add estimation accuracy histogram metrics and log ratio output ([#5252](https://github.com/grafana/pyroscope/pull/5252)) +* Add per-tenant limits for the number of recording rules ([#5247](https://github.com/grafana/pyroscope/pull/5247)) +* Helm: Default to the v2 storage architecture ([#5160](https://github.com/grafana/pyroscope/pull/5160)) +* Helm: Add `extraObjects` for deploying extra Kubernetes manifests ([#5097](https://github.com/grafana/pyroscope/pull/5097)) +* Monitoring: Migrate dashboards to native histograms ([#5048](https://github.com/grafana/pyroscope/pull/5048)) + +### Fixes + +* Fix an out-of-bounds panic in `clearAddresses` ([#5250](https://github.com/grafana/pyroscope/pull/5250)) +* Fix nil matcher handling for recording rule upserts ([#5134](https://github.com/grafana/pyroscope/pull/5134)) +* **store-gateway**: Validate tenant IDs ([#5194](https://github.com/grafana/pyroscope/pull/5194)) +* Fix archive extraction issues, including zip-slip/tar-slip cleanup and file closure handling ([#5195](https://github.com/grafana/pyroscope/pull/5195), [#5206](https://github.com/grafana/pyroscope/pull/5206)) +* Fix label value cloning to avoid buffer reuse-after-free issues ([#5116](https://github.com/grafana/pyroscope/pull/5116)) +* **query-backend**: Restore the original start time for `RangeSeries` bucketing ([#5161](https://github.com/grafana/pyroscope/pull/5161)) +* **read path**: Reject sub-millisecond `step` parameters ([#5137](https://github.com/grafana/pyroscope/pull/5137)) +* Fix a panic on unknown `QueryNode` types ([#5196](https://github.com/grafana/pyroscope/pull/5196)) +* **store-gateway**: Restore the ring info route from `/tenants` to `/ring` ([#5130](https://github.com/grafana/pyroscope/pull/5130)) +* **speedscope**: Return an error instead of panicking for unknown unit values ([#5143](https://github.com/grafana/pyroscope/pull/5143)) +* **metastore**: Version shard cache reads ([#5189](https://github.com/grafana/pyroscope/pull/5189)) +* **compaction-worker**: Correct `time_to_compaction_seconds` histogram buckets ([#5164](https://github.com/grafana/pyroscope/pull/5164)) +* Helm: Add `apiVersion` and `kind` to `volumeClaimTemplates` ([#5203](https://github.com/grafana/pyroscope/pull/5203)) + +### Security fixes + +* **ui**: Update Vite to v8.0.16 ([#5260](https://github.com/grafana/pyroscope/pull/5260)) +* **ui**: Bump `tar`, `js-yaml`, and `@babel/core` ([#5263](https://github.com/grafana/pyroscope/pull/5263)) +* **ui**: Bump `uuid` from 11.1.0 to 11.1.1 ([#5123](https://github.com/grafana/pyroscope/pull/5123)) +* **ui**: Patch CVE-2026-45149 and CVE-2026-46625 in Yarn dependencies ([#5181](https://github.com/grafana/pyroscope/pull/5181)) +* Update `golang.org/x/net` to v0.53.0 ([#5131](https://github.com/grafana/pyroscope/pull/5131)) +* Update `golang.org/x/crypto` to v0.52.0 ([#5197](https://github.com/grafana/pyroscope/pull/5197)) +* Update `golang.org/x/image` to v0.41.0 ([#5216](https://github.com/grafana/pyroscope/pull/5216)) +* Update `github.com/prometheus/prometheus` to v0.311.3 ([#5113](https://github.com/grafana/pyroscope/pull/5113)) +* Update the Go toolchain directive to v1.25.11 ([#5228](https://github.com/grafana/pyroscope/pull/5228)) + +### Documentation + +* Add generated YAML examples and documentation for v2 configuration blocks ([#5151](https://github.com/grafana/pyroscope/pull/5151)) +* Remove the public preview note from `pyroscope.receive_http` documentation ([#5176](https://github.com/grafana/pyroscope/pull/5176)) +* Update supported .NET versions to 8, 9, and 10 ([#5096](https://github.com/grafana/pyroscope/pull/5096)) +* Refresh README content and agent guides for the v2 layout, Go version, and tracing updates ([#5246](https://github.com/grafana/pyroscope/pull/5246), [#5183](https://github.com/grafana/pyroscope/pull/5183)) +* Fix a broken Grafana Cloud Profiles link in SDK guides ([#5132](https://github.com/grafana/pyroscope/pull/5132)) diff --git a/docs/sources/release-notes/v2-2.md b/docs/sources/release-notes/v2-2.md new file mode 100644 index 0000000000..4bc422a23a --- /dev/null +++ b/docs/sources/release-notes/v2-2.md @@ -0,0 +1,59 @@ +--- +title: Version 2.2 release notes +menuTitle: V2.2 +description: Release notes for Grafana Pyroscope 2.2 +weight: 660 +--- + +## Version 2.2.0 release notes + +The Pyroscope team is excited to present Grafana Pyroscope 2.2.0. + +This release adds experimental asynchronous query execution, trace ID filtering in the v2 read path, and stability and performance fixes across the write and read paths. + +Notable changes are listed below. For the full diff, check out the [2.2.0 changelog](https://github.com/grafana/pyroscope/compare/v2.1.0...v2.2.0). + +### Enhancements + +* Add experimental support for asynchronous query execution ([#4995](https://github.com/grafana/pyroscope/pull/4995)) +* **read path**: Support `trace_id_selector` in the v2 read path ([#5284](https://github.com/grafana/pyroscope/pull/5284)) +* **profilecli**: Add a `--trace-id` flag to filter query profile samples by trace ([#5300](https://github.com/grafana/pyroscope/pull/5300)) +* **query API**: Add `SymbolRefTable` and `symbol_refs` tree fields ([#5318](https://github.com/grafana/pyroscope/pull/5318)) +* **symbolizer**: Expose address-level symbol resolution as a public API ([#5317](https://github.com/grafana/pyroscope/pull/5317)) +* Add an optional admin HTTP server on a separate port ([#5191](https://github.com/grafana/pyroscope/pull/5191)) +* Keep totals and labels of sampled-out profiles ([#5354](https://github.com/grafana/pyroscope/pull/5354)) +* **ui**: Add autocomplete to the v2 embedded UI query bar ([#5172](https://github.com/grafana/pyroscope/pull/5172)) +* **querier**: Unify merged profile query formats ([#5358](https://github.com/grafana/pyroscope/pull/5358)) +* **distributor**: Add a `push_batch_series` histogram ([#5305](https://github.com/grafana/pyroscope/pull/5305)) +* **pprof**: Make language detection deterministic and ~40% faster ([#5309](https://github.com/grafana/pyroscope/pull/5309)) +* Improve label validation performance ([#5313](https://github.com/grafana/pyroscope/pull/5313)) +* Helm: Add a `service_name` relabel rule to the Alloy scrape config ([#5262](https://github.com/grafana/pyroscope/pull/5262)) + +### Fixes + +* **ingester**: Return HTTP 429 for ingestion-limit rejections on the OTLP and `/ingest` paths ([#5372](https://github.com/grafana/pyroscope/pull/5372)) +* **otlp**: Send all converted profiles in a single `PushBatch` per export ([#5339](https://github.com/grafana/pyroscope/pull/5339)) +* **distributor**: Bound `PushBatch` series fan-out with a per-tenant limit ([#5306](https://github.com/grafana/pyroscope/pull/5306)) +* Enforce tenant header extraction in the auth interceptor ([#5251](https://github.com/grafana/pyroscope/pull/5251)) +* Reject non-positive ingest sample rates and improve sample rate errors ([#5253](https://github.com/grafana/pyroscope/pull/5253), [#5276](https://github.com/grafana/pyroscope/pull/5276)) +* **metastore**: Enable retention cleanup by default ([#5280](https://github.com/grafana/pyroscope/pull/5280)) +* **metastore**: Retain shards with recent data ([#5360](https://github.com/grafana/pyroscope/pull/5360)) +* **query-backend**: Forward and apply span selectors in pprof and tree query paths ([#5273](https://github.com/grafana/pyroscope/pull/5273)) +* Return trace IDs in span heatmaps ([#5353](https://github.com/grafana/pyroscope/pull/5353)) +* **pprof**: Treat two nil value types as compatible in `ProfileMerge` ([#5315](https://github.com/grafana/pyroscope/pull/5315)) +* **symdb**: Preserve line-less locations when rewriting partitions without functions ([#5337](https://github.com/grafana/pyroscope/pull/5337)) +* Add bounds checks to tree deserialization ([#5145](https://github.com/grafana/pyroscope/pull/5145)) +* Fix a data race in usage stats counters ([#5303](https://github.com/grafana/pyroscope/pull/5303)) +* **debuginfo**: Decline empty build IDs during upload initiation ([#5302](https://github.com/grafana/pyroscope/pull/5302)) +* **debuginfo**: Improve `ListDebugInfo` performance for large tenants ([#5286](https://github.com/grafana/pyroscope/pull/5286)) +* Helm: Respect metastore raft `extraArgs` overrides ([#5275](https://github.com/grafana/pyroscope/pull/5275)) + +### Security fixes + +* Update Go toolchain to 1.25.12, addressing CVE-2026-42505 and CVE-2026-39822 ([#5338](https://github.com/grafana/pyroscope/pull/5338)) + +### Documentation + +* Clarify which flags are v1-exclusive ([#5308](https://github.com/grafana/pyroscope/pull/5308)) +* Add supported platforms documentation ([#5316](https://github.com/grafana/pyroscope/pull/5316)) +* Document Python SDK fork safety ([#5364](https://github.com/grafana/pyroscope/pull/5364)) diff --git a/docs/sources/shared/available-profile-types.md b/docs/sources/shared/available-profile-types.md new file mode 100644 index 0000000000..c0336467f6 --- /dev/null +++ b/docs/sources/shared/available-profile-types.md @@ -0,0 +1,23 @@ +--- +headless: true +description: Shared file for available profile types. +--- + +[//]: # 'This file documents the available profile types in Pyroscope.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/pyroscope/docs/sources/configure-client/profile-types.md' +[//]: # '/pyroscope/docs/sources/introduction/profiling-types.md' +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + +Pyroscope supports these profile types: + +* CPU (CPU time, wall time) +* Memory (allocation objects, allocation space, heap) +* In use objects and in-use space +* Goroutines +* Mutex count and duration +* Block count and duration +* Lock count and duration +* Exceptions \ No newline at end of file diff --git a/docs/sources/shared/index.md b/docs/sources/shared/index.md new file mode 100644 index 0000000000..79fffb20f0 --- /dev/null +++ b/docs/sources/shared/index.md @@ -0,0 +1,4 @@ +--- +description: No description necessary for a shared file index. +headless: true +--- \ No newline at end of file diff --git a/docs/sources/shared/intro/continuous-profiling.md b/docs/sources/shared/intro/continuous-profiling.md new file mode 100644 index 0000000000..7cef205aec --- /dev/null +++ b/docs/sources/shared/intro/continuous-profiling.md @@ -0,0 +1,74 @@ +--- +headless: true +description: Shared file for intro to continuous profiling. +--- + +[//]: # 'When to use continuous profiling.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/pyroscope/docs/sources/introduction/continuous-profiling.md' +[//]: # '/website/content/grafana-cloud/monitor-applications/profiles/introduction/continuous-profiling.md' +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + + + +Continuous profiling is a systematic method of collecting and analyzing performance data from production systems. + +Traditionally, profiling is used to debug applications on an as-needed basis. +For example, you can run a benchmark tool locally and get a `pprof` file in Go or connect to a misbehaving prod instance and pull a flame graph from a `JFR` file in Java. +This method is good for debugging, but not robust enough for production. + +![example flame graph](https://grafana.com/static/img/pyroscope/pyroscope-ui-single-2023-11-30.png) + +Refer to [Flame graphs](ref:flame-graphs) to learn more. + +Continuous profiling is a modern approach which is safer and more scalable for production environments. +It uses low-overhead sampling to collect profiles from production systems and stores the profiles in a database for later analysis. +Using continuous profiling gives you a more holistic view of your application and how it behaves in production. + +Grafana offers Grafana Pyroscope and Grafana Cloud Profiles (powered by Pyroscope) to collect and store your profiling data. +You can use Grafana Profiles Drilldown to inspect profile data and investigate issues. + +## Benefits + +Why prioritize continuous profiling? + +1. **In-depth code insights:** It provides granular, line-level insights into how application code utilizes resources, offering the most detailed view of application performance. +2. **Complements other observability tools:** Continuous profiling fills critical gaps left by metrics, logs, and tracing, creating a more comprehensive observability strategy. +3. **Proactive performance optimization:** Regular profiling enables teams to proactively identify and resolve performance bottlenecks, leading to more efficient and reliable applications. +![Diagram showing 3 benefits of continuous profiling](https://grafana.com/static/img/pyroscope/profiling-use-cases-diagram.png) + +## Use cases + +Adopting continuous profiling with tools like Grafana Pyroscope and Profiles Drilldown can lead to significant business advantages: + +1. **Reduced operational costs:** Optimization of resource usage can significantly cut down cloud and infrastructure expenses +2. **Reduced latency:** Identifying and addressing performance bottlenecks leads to faster and more efficient applications +3. **Enhanced incident management:** Faster problem identification and resolution, reducing Mean Time to Resolution (MTTR) and improving end-user experience + +![Infographic illustrating key business benefits](https://grafana.com/static/img/pyroscope/cost-cutting-diagram.png) + +### Reduced operational costs + +By providing in-depth insights into application performance, profiling empowers teams to identify and eliminate inefficiencies, leading to significant savings in areas like observability, incident management, messaging/queuing, deployment tools, and infrastructure. + + +By using sampling profilers, Pyroscope and Cloud Profiles can collect data with minimal overhead (~2-5% depending on a few factors). +The [custom storage engine](https://grafana.com/docs/pyroscope//reference-pyroscope-architecture/about-grafana-pyroscope-architecture/) compresses and stores the data efficiently. +Some advantages of this are: + +- Low CPU overhead thanks to sampling profiler technology + +- Control over profiling data granularity (10s to multiple years) +- Efficient compression, low disk space requirements and cost + +### Reduced latency + +Profiles play a pivotal role in reducing application latency by identifying performance bottlenecks at the code level. +This granular insight allows for targeted optimization, leading to faster application response times, improved user experience, and consequently, better business outcomes like increased customer satisfaction and revenue. + +### Enhanced incident management + +Pyroscope and Profiles Drilldown streamline incident management by offering immediate, actionable insights into application performance issues. +With continuous profiling, teams can quickly pinpoint the root cause of an incident, reducing the mean time to resolution (MTTR) and enhancing overall system reliability and user satisfaction. \ No newline at end of file diff --git a/docs/sources/shared/intro/flame-graphs.md b/docs/sources/shared/intro/flame-graphs.md new file mode 100644 index 0000000000..0c164114b5 --- /dev/null +++ b/docs/sources/shared/intro/flame-graphs.md @@ -0,0 +1,56 @@ +--- +headless: true +description: Shared file for intro to flame graphs. +--- + +[//]: # 'Learn about flame graphs.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/pyroscope/docs/sources/introduction/flamegraphs.md' +[//]: # '/website/content/grafana-cloud/monitor-applications/profiles/introduction/flamegraphs.md' +[//]: # '/explore-profiles/docs/sources/introduction/flame-graphs.md' +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + + + +Flame graphs provide a visual summary of your profile data. +A flame graph is a complete visualization of hierarchical data, for example stack trace and, file system contents, with a metric, typically resource usage, attached to the data. + +A fundamental aspect of continuous profiling is the flame graph, a convenient way to visualize performance data. +These graphs provide a clear, intuitive understanding of resource allocation and bottlenecks within the application. + + + +[Brendan Gregg](https://www.brendangregg.com/flamegraphs.html), the creator of flame graphs, was inspired by the inability to view, read, and understand stack traces using the regular profilers to debug performance issues. + + + +## How Pyroscope creates flame graphs + +This diagram shows how code is turned into a flame graph. +In this case, Pyroscope samples the stacktrace of your application to understand how many CPU cycles are spent in each function. +It then aggregates this data and turns it into a flame graph. + +![code to flame graph diagram](https://grafana.com/static/img/pyroscope/code-to-flamegraph-animation.gif) + +## What does a flame graph represent? + +Horizontally, the flame graph represents 100% of the time that this application was running. +The width of each node represents the amount of time spent in that function. +The wider the node, the more time spent in that function. The narrower the node, the less time spent in that function. + +Vertically, the nodes in the flame graph represent the hierarchy of functions called and time spent in each function. +The top node is the root node and represents the total amount of time spent in the application. +The nodes below it represent the functions called and time spent in each function. +The nodes below those represent the functions called from those functions and time spent in each function. +This continues until you reach the bottom of the flame graph. + +This is a CPU profile, but profiles can represent many other types of resource such as memory, network, disk, etc. + +![flame graph](https://grafana.com/static/img/pyroscope/pyroscope-flamegraph-2023-11-30.png) + +## Flame graph visualization panel UI + +To learn more about the flame graph user interface in Grafana, Grafana Cloud, and Grafana Profiles Drilldown, refer to [Flame graph visualization panel](https://grafana.com/docs/grafana-cloud/visualizations/panels-visualizations/visualizations/flame-graph). + +To learn more about the flame graph in the Pyroscope UI, refer to [Pyroscope UI](https://grafana.com/docs/pyroscope//view-and-analyze-profile-data/pyroscope-ui/). \ No newline at end of file diff --git a/docs/sources/shared/intro/profile-types-descriptions.md b/docs/sources/shared/intro/profile-types-descriptions.md new file mode 100644 index 0000000000..6979836dc4 --- /dev/null +++ b/docs/sources/shared/intro/profile-types-descriptions.md @@ -0,0 +1,75 @@ +--- +headless: true +description: Shared file for profile types. +--- + +[//]: # 'Profile types descriptions.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/pyroscope/docs/sources/introduction/profiling-types.md' +[//]: # '/website/content/grafana-cloud/monitor-applications/profiles/introduction/profiling-types.md' +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + + + +## CPU profiling + +CPU profiling measures the amount of CPU time consumed by different parts of your application code. +High CPU usage can indicate inefficient code, leading to poor performance and increased operational costs. +It's used to identify and optimize CPU-intensive functions in your application. + +- **When to use**: To identify and optimize CPU-intensive functions +- **Flame graph insight**: The width of blocks indicates the CPU time consumed by each function + +The UI shows a spike in CPU along with the flame graph associated with that spike. +You may get similar insights from metrics, however, with profiling, you have more details into the specific cause of a spike in CPU usage at the line level. + +![Example flame graph](https://grafana.com/static/img/pyroscope/pyroscope-ui-single-2023-11-30.png) + +## Memory allocation profiling + +Memory allocation profiling tracks the amount and frequency of memory allocations by the application. +Excessive or inefficient memory allocation can lead to memory leaks and high garbage collection overhead, impacting application efficiency. + + +- **Types**: Alloc Objects, Alloc Space + +- **When to use**: For identifying and optimizing memory usage patterns +- **Flame graph insight**: Highlights functions where memory allocation is high + +The timeline shows memory allocations over time and is great for debugging memory related issues. +A common example is when a memory leak is created due to improper handling of memory in a function. +This can be identified by looking at the timeline and seeing a gradual increase in memory allocations that never goes down. +This is a clear indicator of a memory leak. + +![memory leak example](https://grafana.com/static/img/pyroscope/pyroscope-memory-leak-2023-11-30.png) + +Without profiling, this may be something that's exhibited in metrics or out-of-memory errors (OOM) logs but with profiling you have more details into the specific function that's allocating the memory which is causing the leak at the line level. + +## Goroutine profiling + +Goroutines are lightweight threads in Go, used for concurrent operations. +Goroutine profiling measures the usage and performance of these threads. +Poor management can lead to issues like deadlocks and excessive resource usage. + +- **When to use**: Especially useful in Go applications for concurrency management +- **Flame graph insight**: Provides a view of goroutine distribution and issues + +## Mutex profiling + +Mutex profiling involves analyzing mutex (mutual exclusion) locks, used to prevent simultaneous access to shared resources. +Excessive or long-duration mutex locks can cause delays and reduced application throughput. + +- **Types**: Mutex Count, Mutex Duration +- **When to use**: To optimize thread synchronization and reduce lock contention +- **Flame graph insight**: Shows frequency and duration of mutex operations + +## Block profiling + +Block profiling measures the frequency and duration of blocking operations, where a thread is paused or delayed. +Blocking can significantly slow down application processes, leading to performance bottlenecks. + +- **Types**: Block Count, Block Duration +- **When to use**: To identify and reduce blocking delays +- **Flame graph insight**: Identifies where and how long threads are blocked diff --git a/docs/sources/shared/intro/what-is-profiling.md b/docs/sources/shared/intro/what-is-profiling.md new file mode 100644 index 0000000000..feb6dfa759 --- /dev/null +++ b/docs/sources/shared/intro/what-is-profiling.md @@ -0,0 +1,74 @@ +--- +headless: true +description: Shared file for intro to profiling. +--- + +[//]: # 'What is profiling? Traditional vs continuous profiling.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/pyroscope/docs/sources/introduction/continuous-profiling.md' +[//]: # '/website/content/grafana-cloud/monitor-applications/profiles/introduction/continuous-profiling.md' +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + + + +Profiling is a technique used in software development to measure and analyze the runtime behavior of a program. +By profiling a program, developers can identify which parts of the program consume the most resources, such as CPU time, memory, or I/O operations. +You can use this information to optimize the program, making it run faster or use fewer resources. + +Pyroscope can be used for both traditional and continuous profiling. + +## Traditional profiling (non-continuous) + +Traditional profiling, often referred to as __sample-based__ or __instrumentation-based__ profiling, has its roots in the early days of computing. +Back then, the primary challenge was understanding how a program utilized the limited computational resources available. + +With sample-based profiling, the profiler interrupts the program at regular intervals, capturing the program's state each time. +By analyzing these snapshots, developers can deduce the frequency at which parts of the code execute. + +With instrumentation-based profiling, developers insert additional code into the program that records information about its execution. +This approach provides detailed insights but can alter the program's behavior due to the added code overhead. + +### Benefits + +Traditional profiling provides: + +- **Precision**: Offers a deep dive into specific sections of the code. +- **Control**: Developers can initiate profiling sessions at their discretion, allowing for targeted optimization efforts. +- **Detailed reports**: Provides granular data about program execution, making it easier to pinpoint bottlenecks. + +## Continuous profiling + +As software systems grew in complexity and scale, the limitations of traditional profiling became evident. +Issues could arise in production that weren't apparent during limited profiling sessions in the development or staging environments. + +This led to the development of continuous profiling, a method where the profiling data is continuously collected in the background with minimal overhead. +By doing so, developers gain a more comprehensive view of a program's behavior over time, helping to identify sporadic or long-term performance issues. + +### Benefits + +Continuous profiling provides: + +- **Consistent monitoring**: Unlike traditional methods that offer snapshots, continuous profiling maintains an uninterrupted view, exposing both immediate and long-term performance issues. +- **Proactive bottleneck detection**: By consistently capturing data, performance bottlenecks are identified and addressed before they escalate, reducing system downtime and ensuring smoother operations. +- **Broad performance landscape**: Provides insights across various platforms, from varied technology stacks to different operating systems, ensuring comprehensive coverage. +- **Bridging the Dev-Prod gap**: Continuous profiling excels in highlighting differences between development and production: + - **Hardware discrepancies**: Unearths issues stemming from differences in machine specifications. + - **Software inconsistencies**: Sheds light on variations in software components that might affect performance. + - **Real-world workload challenges**: Highlights potential pitfalls when real user interactions and loads don't align with development simulations. +- **Economical advantages**: + - **Resource optimization**: Continual monitoring ensures resources aren't wasted, leading to cost savings. + - **Rapid problem resolution**: Faster troubleshooting means reduced time and monetary investment in issue rectification, letting developers channel their efforts into productive endeavors. +- **Non-intrusive operation**: Specifically designed to work quietly in the background, continuous profiling doesn't compromise the performance of live environments. +- **Real-time response**: It equips teams with the ability to act instantly, addressing issues as they arise rather than post-occurrence, which is crucial for maintaining high system availability. + +## Choose between traditional and continuous profiling + +In many modern development workflows, both methods are useful. + +| | **Traditional profiling** | **Continuous profiling** | +|---|---|---| +| When to use | During development or testing phases | In production environments or during extended performance tests. | +| Advantages | Offers detailed insights that can target specific parts of code. | Provides a continuous view of system performance, often with minimal overhead, making it suitable for live environments. | +| Disadvantages | Higher overhead provides only a snapshot in time. | It might be less detailed than traditional profiling due to the need to minimize impact on the running system. | \ No newline at end of file diff --git a/docs/sources/shared/locate-url-pw-user-cloud-profiles.md b/docs/sources/shared/locate-url-pw-user-cloud-profiles.md new file mode 100644 index 0000000000..e6cbe19fd0 --- /dev/null +++ b/docs/sources/shared/locate-url-pw-user-cloud-profiles.md @@ -0,0 +1,27 @@ +--- +headless: true +description: Shared file for available profile types. +--- + +[//]: # 'This file where to locate the username, password, and URL in Cloud Profiles.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/website/docs/grafana-cloud/monitor-applications/profiles/send-profile-data.md' +[//]: # +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + + + +When you configure Alloy or your SDK, you need to provide the URL, user, and password for your Grafana Cloud stack. +This information is located in the **Pyroscope** section of your Grafana Cloud stack. + +1. Navigate to your Grafana Cloud stack. +1. Select **Details** next to your stack. +1. Locate the **Pyroscope** section and select **Details**. +1. Copy the **URL**, **User**, and **Password** values in the **Configure the client and data source using Grafana credentials** section. + ![Locate the SDK or Grafana Alloy configuration values](/media/docs/pyroscope/cloud-profiles-url-user-password.png) +1. Use these values to complete the configuration. + +As an alternative, you can also create a Cloud Access Policy and generate a token to use instead of the user and password. +For more information, refer to [Create a Cloud Access Policy](https://grafana.com/docs/grafana-cloud/security-and-account-management/authentication-and-permissions/access-policies/create-access-policies/). \ No newline at end of file diff --git a/docs/sources/shared/supported-languages-ebpf.md b/docs/sources/shared/supported-languages-ebpf.md new file mode 100644 index 0000000000..f82ac30f5c --- /dev/null +++ b/docs/sources/shared/supported-languages-ebpf.md @@ -0,0 +1,19 @@ +--- +headless: true +description: Shared file for supported languages when using eBPF. +--- + +[//]: # 'This file documents the supported languages when using eBPF in Pyroscope.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/pyroscope/docs/sources/configure-client/grafana-alloy/_index.md' +[//]: # '/pyroscope/docs/sources/configure-client/grafana-alloy/ebpf/_index.md' +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + +The eBPF profiler collects CPU profiles. +Natively compiled languages like C/C++, Go, Rust, and Zig are supported. Frame pointers are not required — the profiler uses `.eh_frame` data for unwinding. +Refer to [Troubleshooting unknown symbols](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/ebpf/troubleshooting/#troubleshoot-unknown-symbols) for additional requirements and information. + +The following high-level languages are also supported: Java (Hotspot JVM), .NET, Python, Ruby, PHP, Node.js, and Perl. +Each high-level language can be individually enabled or disabled in the [pyroscope.ebpf](https://grafana.com/docs/alloy/latest/reference/components/pyroscope/pyroscope.ebpf/) Alloy component configuration. diff --git a/docs/sources/shared/use-explore-profiles.md b/docs/sources/shared/use-explore-profiles.md new file mode 100644 index 0000000000..9609674b6a --- /dev/null +++ b/docs/sources/shared/use-explore-profiles.md @@ -0,0 +1,59 @@ +--- +headless: true +description: Shared file for Profiles Drilldown overview. +--- + +[//]: # 'This file documents an introduction to Profiles Drilldown.' +[//]: # 'This shared file is included in these locations:' +[//]: # '/pyroscope/docs/sources/configure-client/profile-types.md' +[//]: # '/pyroscope/docs/sources/introduction/profiling-types.md' +[//]: # +[//]: # 'If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included.' +[//]: # 'Any links should be fully qualified and not relative: /docs/grafana/ instead of ../grafana/.' + + +{{< docs/public-preview product="Profiles Drilldown" >}} + +[Grafana Profiles Drilldown](https://grafana.com/docs/grafana-cloud/visualizations/simplified-exploration/profiles/) is designed to make it easy to visualize and analyze profiling data. +There are several different modes for viewing, analyzing, and comparing profiling data. + +The main use cases are the following: + +- Proactive: Cutting costs, addressing latency issues, or optimizing memory usage for applications +- Reactive: Resolving incidents with line-level accuracy or debugging active latency/memory issues + +Profiles Drilldown provides an intuitive interface to specifically support these use cases. +You get a holistic view of all of your services and how they're functioning, but also the ability to drill down for more targeted root cause analysis. + +![Profiles Drilldown home screen](/media/docs/explore-profiles/explore-profiles-homescreen-v1.png) + +Profiles Drilldown offers a convenient platform to analyze profiles and get insights that are impossible to get from using other traditional signals like logs, metrics, or tracing. + +{{< youtube id="x9aPw_CbIQc" >}} + +{{< docs/play title="the Grafana Play site" url="https://play.grafana.org/a/grafana-pyroscope-app/explore" >}} + +## Continuous profiling + +While code profiling has been a long-standing practice, continuous profiling represents a modern and more advanced approach to performance monitoring. + +This technique adds two critical dimensions to traditional profiles: + +Time +: Profiling data is collected _continuously_, providing a time-centric view that allows querying performance data from any point in the past. + +Metadata +: Metadata enriches profiling data, adding contextual depth to the performance data. + +These dimensions, coupled with the detailed nature of performance profiles, make continuous profiling a uniquely valuable tool. + +## Flame graphs + + + +Flame graphs help you visualize resource allocation and performance bottlenecks, and you even get suggested recommendations and performance fixes via AI-driven flame graph analysis, as well as line-level insights from our GitHub integration. + + + +On views with a flame graph, you can use **Explain flame graph** to provide an AI flame graph analysis that explains the performance bottleneck, root cause, and recommended fix. +For more information, refer to [Flame graph AI](https://grafana.com/docs/grafana-cloud/monitor-applications/profiles/flamegraph-ai/). diff --git a/docs/sources/upgrade-guide/_index.md b/docs/sources/upgrade-guide/_index.md index 751508b948..07dda0a511 100644 --- a/docs/sources/upgrade-guide/_index.md +++ b/docs/sources/upgrade-guide/_index.md @@ -54,7 +54,7 @@ The new local storage format is entirely new, optimized for object storage. We d #### Configuration file changes -The configuration file parameters as well as the default location for the configuration file have changed. The old config file is usually located at `/etc/pyroscope/server.yml` and the new config file is at `/etc/pyroscope/config.yaml`. You can find detailed descriptions of all configuration parameters [here]({{< relref "../configure-server/reference-configuration-parameters" >}}). +The configuration file parameters as well as the default location for the configuration file have changed. The old config file is usually located at `/etc/pyroscope/server.yml` and the new config file is at `/etc/pyroscope/config.yaml`. You can find detailed descriptions of all configuration parameters [here](../configure-server/reference-configuration-parameters/). #### Dropping support for certain subcommands @@ -64,7 +64,9 @@ We stripped the pyroscope CLI of all subcommands that were related to the client * `pyroscope connect` * `pyroscope agent` -This strategic shift has been in the works for some time as we transition away from CLI-based profiling towards embracing native integrations. Moving forward, we encourage users to take advantage of native integrations tailored to specific programming languages, such as pip packages for Python, .NET packages for .NET applications, Ruby gems for Ruby applications, and so on. Our [eBPF integration]({{< relref "../configure-client/grafana-agent/ebpf" >}}) is also a good way to get profiling data for your whole cluster. +This strategic shift has been in the works for some time as we transition away from CLI-based profiling towards embracing native integrations. +Moving forward, we encourage users to take advantage of native integrations tailored to specific programming languages, such as pip packages for Python, .NET packages for .NET applications, Ruby gems for Ruby applications, and so on. +The [eBPF integration](https://grafana.com/docs/pyroscope//configure-client/grafana-alloy/ebpf/) is also a good way to get profiling data for your whole cluster. By adopting native integrations, we aim to provide users with a more streamlined and efficient profiling experience, leveraging language-specific tools and libraries to deliver better performance, ease of use, and seamless integration with their respective applications. @@ -90,7 +92,7 @@ We provide the following checklists to help you upgrade to v1.0. #### Upgrade Checklist for Docker deployments When upgrading to v1.0, we suggest that you follow this checklist: -* Migrate your configuration from the old format to the new format (old config is usually located at `/etc/pyroscope/server.yml` and the new config is at `/etc/pyroscope/config.yaml`). There's a detailed description of all configuration parameters [here]({{< relref "../configure-server/reference-configuration-parameters" >}}). +* Migrate your configuration from the old format to the new format (old config is usually located at `/etc/pyroscope/server.yml` and the new config is at `/etc/pyroscope/config.yaml`). There's a detailed description of all configuration parameters [here](../configure-server/reference-configuration-parameters/). * Upgrade docker image from `pyroscope/pyroscope` to `grafana/pyroscope`. Link to the new docker image is [here](https://hub.docker.com/r/grafana/pyroscope). * Delete old data (typically found at `/var/lib/pyroscope`). @@ -98,7 +100,7 @@ When upgrading to v1.0, we suggest that you follow this checklist: When upgrading to v1.0, we suggest that you follow this checklist: -* Migrate your configuration from the old format to the new format (old config is usually located at `/etc/pyroscope/server.yml` and the new config is at `/etc/pyroscope/config.yaml`). There's a detailed description of all configuration parameters [here]({{< relref "../configure-server/reference-configuration-parameters" >}}). +* Migrate your configuration from the old format to the new format (old config is usually located at `/etc/pyroscope/server.yml` and the new config is at `/etc/pyroscope/config.yaml`). There's a detailed description of all configuration parameters [here](../configure-server/reference-configuration-parameters/). * Delete the old Helm chart: ```bash helm delete pyroscope # replace pyroscope with the name you used when installing the chart @@ -110,4 +112,4 @@ When upgrading to v1.0, we suggest that you follow this checklist: helm repo update helm -n pyroscope install pyroscope grafana/pyroscope ``` - For more information on how to install the Helm chart, see our Helm documentation [here]({{< relref "../deploy-kubernetes" >}}). + For more information on how to install the Helm chart, see our Helm documentation [here](../deploy-kubernetes/). diff --git a/docs/sources/view-and-analyze-profile-data/_index.md b/docs/sources/view-and-analyze-profile-data/_index.md index 6c78a8c2c8..a7e4622f7c 100644 --- a/docs/sources/view-and-analyze-profile-data/_index.md +++ b/docs/sources/view-and-analyze-profile-data/_index.md @@ -32,12 +32,8 @@ Integrating Pyroscope with Grafana is a common and recommended approach for visu Options for visualizing data in Grafana: -- **Pyroscope App Plugin**: This plugin is specifically designed for Pyroscope data. It allows for easy browsing, analysis, and comparison of multiple profiles across different labels or time periods. This is particularly useful for a comprehensive overview of your application's performance. +- **Profiles Drilldown app**: This app is specifically designed for Pyroscope data. It allows for easy browsing, analysis, and comparison of multiple profiles across different labels or time periods. This is particularly useful for a comprehensive overview of your application's performance. - **Explore tab**: In Grafana, **Explore** is suited for making targeted queries on your profiling data. This is useful for in-depth analysis of specific aspects of your application's performance. - **Dashboard**: Grafana dashboards are excellent for integrating profiling data with other metrics. You can display Pyroscope data alongside other dashboard items, creating a unified view of your application’s overall health and performance. -For more information on using profiles in Grafana, refer to [Pyroscope and profiles in Grafana]({{< relref "../introduction/pyroscope-in-grafana#pyroscope-and-profiling-in-grafana" >}}). - -The Pyroscope app plugin works for Grafana Cloud. - -For more information on configuring these data sources, refer to the Pyroscope data source documentation in [Grafana Cloud](/docs/grafana-cloud/connect-externally-hosted/data-sources/pyroscope/) and [Grafana](/docs/grafana/latest/datasources/grafana-pyroscope/). +For more information on configuring these data sources, refer to the Pyroscope data source documentation in [Grafana Cloud](/docs/grafana-cloud/connect-externally-hosted/data-sources/pyroscope/) and [Grafana](/docs/grafana//datasources/pyroscope/). diff --git a/docs/sources/view-and-analyze-profile-data/analyze-profiles/_index.md b/docs/sources/view-and-analyze-profile-data/analyze-profiles/_index.md index ade1a1851b..7300c346eb 100644 --- a/docs/sources/view-and-analyze-profile-data/analyze-profiles/_index.md +++ b/docs/sources/view-and-analyze-profile-data/analyze-profiles/_index.md @@ -18,7 +18,7 @@ keywords: Pyroscope's UI is designed to make it easy to visualize and analyze profiling data. There are several different modes for viewing, analyzing, uploading, and comparing profiling data. -These modes are discussed in the [Pyroscope UI documentation]({{< relref "../pyroscope-ui" >}}). +These modes are discussed in the [Pyroscope UI documentation](../pyroscope-ui/). ![Screenshots of Pyroscope's UI](https://grafana.com/static/img/pyroscope/pyroscope-ui-diff-2023-11-30.png) diff --git a/docs/sources/view-and-analyze-profile-data/explore-profiles.md b/docs/sources/view-and-analyze-profile-data/explore-profiles.md new file mode 100644 index 0000000000..eb9db3973b --- /dev/null +++ b/docs/sources/view-and-analyze-profile-data/explore-profiles.md @@ -0,0 +1,17 @@ +--- +title: Use Profiles Drilldown to investigate issues +menuTitle: Use Profiles Drilldown +description: Learn about Profiles Drilldown app to investigate issues using your profiling data. +weight: 100 +keywords: + - profiles + - performance analysis + - Profiles Drilldown +--- + +# Use Profiles Drilldown to investigate issues + +[//]: # 'Introduction to Profiles Drilldown.' +[//]: # 'This content is located in /pyroscope/docs/sources/shared/intro/use-explore-profiles.md' + +{{< docs/shared source="pyroscope" lookup="use-explore-profiles.md" version="" >}} \ No newline at end of file diff --git a/docs/sources/view-and-analyze-profile-data/flamegraphs.md b/docs/sources/view-and-analyze-profile-data/flamegraphs.md deleted file mode 100644 index 6ef8d7f748..0000000000 --- a/docs/sources/view-and-analyze-profile-data/flamegraphs.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: "Flame graphs: Visualizing performance data" -menuTitle: Flame graphs -description: Learn about flame graphs to help visualize performance data. -weight: 33 -aliases: - - ../introduction/flamegraphs/ -keywords: - - Pyroscope - - Profiling ---- - -# Flame graphs: Visualizing performance data - -A fundamental aspect of continuous profiling is the flame graph, a convenient way to visualize performance data. -These graphs provide a clear, intuitive understanding of resource allocation and bottlenecks within the application. Pyroscope extends this functionality with additional visualization formats like tree graphs and top lists. - -## How is a flame graph created? - -![code to flame graph diagram](https://grafana.com/static/img/pyroscope/code-to-flamegraph-animation.gif) - -This diagram shows how code is turned into a flame graph. In this case Pyroscope would sample the stacktrace of your application to understand how many CPU cycles are being spent in each function. It would then aggregate this data and turn it into a flame graph. This is a very simplified example but it gives you an idea of how Pyroscope works. - -## What does a flame graph represent? - -![flame graph](https://grafana.com/static/img/pyroscope/pyroscope-flamegraph-2023-11-30.png) - -Horizontally, the flame graph represents 100% of the time that this application was running. -The width of each node represents the amount of time spent in that function. -The wider the node, the more time spent in that function. The narrower the node, the less time spent in that function. - -Vertically, the nodes in the flame graph represent the hierarchy of which functions were called and how much time was spent in each function. -The top node is the root node and represents the total amount of time spent in the application. -The nodes below it represent the functions that were called and how much time was spent in each function. -The nodes below those represent the functions that were called from those functions and how much time was spent in each function. -This continues until you reach the bottom of the flame graph. - -This is a CPU profile, but profiles can represent many other types of resource such as memory, network, disk, etc. - -## Flame graph visualization panel UI - -To learn more about the flame graph in the Pyroscope UI, refer to [Pyroscope UI]({{< relref "./pyroscope-ui" >}}). - -To learn more about the flame graph user interface in Grafana, refer to [Flame graph visualization panel](https://grafana.com/docs/grafana-cloud/visualizations/panels-visualizations/visualizations/flame-graph). diff --git a/docs/sources/view-and-analyze-profile-data/line-by-line.md b/docs/sources/view-and-analyze-profile-data/line-by-line.md new file mode 100644 index 0000000000..6a4f5db893 --- /dev/null +++ b/docs/sources/view-and-analyze-profile-data/line-by-line.md @@ -0,0 +1,454 @@ +--- +description: Integrate your source code on GitHub with Pyroscope profiling data. +keywords: + - GitHub + - continuous profiling + - flame graphs +menuTitle: Show usage line by line +title: Integrate your source code on GitHub with Pyroscope profiling data. +weight: 550 +--- + +# Integrate your source code on GitHub with Pyroscope profiling data. + +The Grafana Pyroscope source code integration offers seamless integration between your GitHub code repositories and Grafana. +Using this app, you can map your code directly within Grafana and visualize resource performance line by line. +With these powerful capabilities, you can gain deep insights into your code's execution and identify performance bottlenecks. + +Every profile type works with the integration for code written in Go, Java, and Python. + +For information on profile types and the profiles available with Go, Java, and Python, refer to [Profiling types and their uses](../../introduction/profiling-types/). + +![Example of a flame graph with the function details populated](/media/docs/grafana-cloud/profiles/screenshot-profiles-github-integration.png) + +## How it works + +The Pyroscope source code integration uses labels configured in the application being profiled to associate profiles with source code. +The integration is available for Go, Java, and Python applications. + +The Pyroscope source code integration uses three labels, `service_repository`, `service_git_ref`, and `service_root_path`, to add commit information, repository link, and an enhanced source code preview to the **Function Details** screen. + +{{< admonition type="note" >}} +The source code mapping is only available to people who have access to the source code in GitHub. +{{< /admonition >}} + +## Before you begin + +To use the Pyroscope source code integration with GitHub, you need an application that emits profiling data, a GitHub account, and a Grafana instance with a Grafana Pyroscope backend. + +### Application with profiling data requirements + +{{< admonition type="warning" >}} + - Applications in other languages aren't supported +{{< /admonition >}} + +- A Go application which is profiled by Grafana Alloy's `pyroscope.scrape`, `pyroscope.ebpf` (Alloy v1.11.0+), or using the [Go Push SDK](../../configure-client/language-sdks/go_push/). +- A Java application which is profiled by Grafana Alloy's `pyroscope.java`, `pyroscope.ebpf` (Alloy v1.11.0+), or using the [Java SDK](../../configure-client/language-sdks/java). For Java applications, a committed `.pyroscope.yaml` file is required to map package names to source code locations (see [Advanced source code mapping with `.pyroscope.yaml`](#advanced-source-code-mapping-with-pyroscopeyaml)). +- A Python application which is profiled by Grafana Alloy's `pyroscope.ebpf` (Alloy v1.11.0+) or using the [Python SDK](../../configure-client/language-sdks/python). + +Your application provides the following labels (tags): + +- `service_git_ref` points to the Git commit or [reference](https://docs.github.com/en/rest/git/refs?apiVersion=2022-11-28#about-git-references) from which the binary was built +- `service_repository` is the GitHub repository that hosts the source code +- `service_root_path` (Optional) is the path where the code lives inside the repository + +To activate this integration, add at least the two mandatory labels when +sending profiles: `service_repository` and `service_git_ref`. Set them to the +full repository GitHub URL and the current [`git +ref`](https://docs.github.com/en/rest/git/refs?apiVersion=2022-11-28#about-git-references) +respectively. + +For example, using the Go SDK you can set these labels as tags in the configuration: + +```go +pyroscope.Start(pyroscope.Config{ + Tags: map[string]string{ + "service_git_ref": "", + "service_repository": "https://github.com//", + "service_root_path": "", // optional + }, + // Other configuration + }) +``` + +You can also override these values directly in the UI by clicking the edit +button next to the repository information in the Function Details panel. This +is useful for testing new configurations before deploying label changes, or for +quickly setting up source code viewing during an incident. + +![Edit service repository settings](/media/docs/pyroscope/pyroscope-edit-service-repository.png) + +### GitHub requirements + +- A GitHub account +- Source code hosted on GitHub + +{{< admonition type="note" >}} +Data from your GitHub repository may be limited if your GitHub organization or repository restricts third-party applications. +For example, the organization may need to add this app to an allowlist to access organizational resources. +Contact your organization administrator for assistance. +Refer to [Requesting a GitHub App from your organization owner](https://docs.github.com/en/apps/using-github-apps/requesting-a-github-app-from-your-organization-owner). +{{< /admonition >}} + +### Ensure the source code integration is configured in Grafana Pyroscope + +Refer to [Configure Pyroscope source code integration](../../configure-server/configuring-github-integration/) on the steps required. + +### Ensure the Grafana Pyroscope data source is configured correctly + +In order to make use of the GitHub integration, the Pyroscope data source needs to be configured to pass a particular cookie through. + +To configure cookie passthrough in Grafana: + +1. Navigate to **Configuration** > **Data sources** in Grafana. +1. Select your Pyroscope data source. +1. Under **Additional settings** > **Advanced HTTP settings** , locate **Allowed cookies**. +1. Add `pyroscope_git_session` to the list of cookies to forward. +1. Click **Save & test** to apply the changes. + + +![Additional data source settings for Pyroscope source code integration](/media/docs/pyroscope/pyroscope-data-source-additional-settings.png) + +{{< admonition type="note" >}} +Cookie forwarding must be enabled for the source code integration to work properly. Without it, you won't be able to connect to GitHub repositories from within Grafana Profiles Drilldown. +{{< /admonition >}} + + +## Authorize access to GitHub + +You can authorize with GitHub using the **Connect to GitHub** in the **Function Details** panel. + +1. From within **Single view** with a configured Pyroscope app plugin. +1. Select **Pyroscope service**. For this example, select `cpu_profile`. +1. Click in the flame graph on a function you want to explore. Select **Function details**. +1. On **Function Details**, locate the **Repository** field and select **Connect to \**, where `` is replaced with the repository name where the files reside. In this case, it’s connecting to the `grafana/pyroscope` repository. +1. If prompted, log in to GitHub. +1. After Grafana connects to your GitHub account, review the permissions and select **Authorize Grafana Pyroscope**. + +{{< admonition type="note" >}} +Organization owners may disallow third-party apps for the entire organization or specific organization resources, like repositories. +If this is the case, you won't be able authorize the Grafana Pyroscope GitHub integration to view source code or commit information for the protected resources. +{{< /admonition >}} + +### Modify or remove the Pyroscope source code integration from your GitHub account + +The Pyroscope source code integration for GitHub uses a GitHub app called "Grafana Pyroscope" to connect to GitHub. +This application authorizes Grafana Cloud to access source code and commit information. + +After authorizing the app, your GitHub account, **GitHub** > **Settings** > **Applications** lists the Grafana Pyroscope app. + +You can change the repositories the Pyroscope source code integration can access on the **Applications** page. + +You can use also remove the app's permissions by selecting **Revoke**. +Revoking the permissions disables the integration in your Grafana Cloud account. + +For more information about GitHub applications: + +- [Using GitHub apps](https://docs.github.com/en/apps/using-github-apps/about-using-github-apps) +- [Authorizing GitHub apps](https://docs.github.com/en/apps/using-github-apps/authorizing-github-apps) +- [Differences between installing and authorizing apps](https://docs.github.com/en/apps/using-github-apps/installing-a-github-app-from-a-third-party#difference-between-installation-and-authorization) + +## How your GitHub code shows up in profile data queries + +After authorizing the Pyroscope Grafana source code integration, you see more details in the **Function Details** from flame graphs in Profiles Drilldown. + +1. Open a browser to your Pyroscope instance. +1. Sign in to your account, if prompted. +1. After the Grafana instance loads, select **Drilldown**. +1. Next, select **Profiles** > **Single view** from the left-side menu. +1. Optional: Select a **Service** and **Profile**. +1. Click in the flame graph and select **Function details** from the pop-up menu. + +### Function Details + +The Function Details section provides information about the function you selected from the flame graph. + +{{< figure max-width="80%" class="center" caption-align="center" src="/media/docs/grafana-cloud/profiles/screenshot-profiles-github-funct-details-v3.png" caption="Function Details panel from a connected Pyroscope source code integration." >}} + +The table explains the main fields in the table. +The values for some of the fields, such as Self and Total, change depending whether a profile uses time or memory amount. +Refer to [Understand Self versus Total metrics in profiling with Pyroscope](https://grafana.com/docs/pyroscope/latest/view-and-analyze-profile-data/self-vs-total/) for more information. + +| Field | Meaning | Notes | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- | +| Function name | The name of the selected function | | +| Start time | The line where the function definition starts | | +| File | Path where the function is defined | You can use the clipboard icon to copy the path. | +| Repository | The repository configured for the selected service | | +| Commit | The version of the application (commit) where the function is defined. Use the drop-down menu to target a specific commit. | Click the Commit ID to view the commit in the repository. | +| Breakdown per line (table) | Provides the function location in the code and self and total values. | | +| Self | 'Self' refers to the resource usage (CPU time, memory allocation, etc.) directly attributed to a specific function or a code segment, excluding the resources used by its sub-functions or calls | This value can be a time or memory amount depending on the profile selected. | +| Total | 'Total' encompasses the combined resource usage of a function along with all the functions it calls. | This value can be a time or memory amount depending on the profile selected. | + +## Advanced source code mapping with `.pyroscope.yaml` + +For more complex applications with multiple dependencies and external libraries, you can configure custom source code mappings using a `.pyroscope.yaml` configuration file in your repository. This feature enables Pyroscope to resolve and display source code from: + +- Multiple GitHub repositories (for example, third-party dependencies) +- Different versions and branches of dependencies +- Standard library code (Go, Java) +- Vendor directories and local paths + +### How source code mapping works + +When you click on a function in the flame graph, Pyroscope performs the following steps to retrieve the source code: + +1. **Load configuration**: Pyroscope checks for a `.pyroscope.yaml` file in your service's root path. This is determined by labels on the profiling data as mentioned in [How this works](#how-this-works). +2. **Match file location**: If a configuration file exists, the system matches the file path or function name from the profiling data against the configured mappings using a longest-prefix-match algorithm. +3. **Resolve matched source location**: If a mapping matches, Pyroscope determines whether to fetch code from: + - A local path within your repository + - An external GitHub repository at a specific version +4. **Automatic mapping**: If no configuration file exists or no mappings matched, the system tries to find the related source code using heuristics: + - Go: Detect standard library functions and `go.mod` dependencies + - All languages: Resolve using the file path relative to the service root +5. **Fetch and display**: The source code is retrieved and displayed in the Function Details panel with line-by-line profiling data + +### Supported languages + +Pyroscope's source code integration supports the following languages: + +- **Go**: Full support including standard library, Go modules, and vendor directories. Works automatically without configuration, but can be customized with `.pyroscope.yaml`. +- **Python**: Full support including standard library and installed packages. Works automatically without configuration, but can be customized with `.pyroscope.yaml`. +- **Java**: Requires a `.pyroscope.yaml` file with explicit mappings for application code and dependencies. + +{{< admonition type="note" >}} +While Go and Python work automatically, you can use a `.pyroscope.yaml` file to customize source mappings for any language. +{{< /admonition >}} + +### Configuration file format + +Create a `.pyroscope.yaml` file in the root of your repository (or in the path specified by `service_root_path` if configured) with the following structure: + +```yaml +version: v1 # Config format version (currently only v1 is supported) +source_code: + mappings: # Array of source-to-repository mappings + - path: # Match files by path prefix (optional if function_name is specified) + - prefix: path/to/match + - prefix: another/path + function_name: # Match by function name prefix (optional if path is specified) + - prefix: function/prefix + language: go # Required: "go", "java", or "python" + source: # Define where to fetch the source code + local: + path: src/main/java # Path relative to the location of the .pyroscope.yaml file + # OR + github: + owner: organization # GitHub repository owner + repo: repository # GitHub repository name + ref: v1.0.0 # Branch, tag, or commit SHA + path: src # Path within the external repository +``` + +### Configuration rules + +- Each mapping must specify either a `local` or `github` source (not both) +- Multiple `path` or `function_name` prefixes can be specified per mapping (they are OR'd together) +- Mappings are evaluated using longest-prefix-match (more specific mappings take precedence) +- If no mapping matches, Pyroscope falls back to language-specific default behavior (automatic resolution for Go; Java requires explicit mappings) + +### Example: Go standard library mapping + +Map the Go standard library to a specific Go version: + +```yaml +version: v1 +source_code: + mappings: + - path: + - prefix: $GOROOT/src + language: go + source: + github: + owner: golang + repo: go + ref: go1.24.10 + path: src +``` + +This configuration ensures that when you view standard library functions like `fmt.Println` or `net/http.Server`, Pyroscope fetches the source code from the `golang/go` repository at version 1.24.10. + +### Example: Java application with dependencies + +Configure mappings for a Java Spring application: + +```yaml +version: v1 +source_code: + mappings: + # Local application code + - function_name: + - prefix: org/example/myapp + language: java + source: + local: + path: src/main/java + + # JDK standard library + - function_name: + - prefix: java + - prefix: javax + language: java + source: + github: + owner: openjdk + repo: jdk + ref: jdk-17+0 + path: src/java.base/share/classes + + # Spring Framework dependencies + - function_name: + - prefix: org/springframework/web/servlet + language: java + source: + github: + owner: spring-projects + repo: spring-framework + ref: v5.3.20 + path: spring-webmvc/src/main/java + + - function_name: + - prefix: org/springframework/web + - prefix: org/springframework/http + language: java + source: + github: + owner: spring-projects + repo: spring-framework + ref: v5.3.20 + path: spring-web/src/main/java +``` + +This configuration demonstrates: + +- **Longest-prefix matching**: `org/springframework/web/servlet` matches the more specific mapping, while `org/springframework/web/client` matches the less specific one +- **Multiple prefixes**: HTTP and web packages from Spring are grouped together +- **Mixed sources**: Local application code and external dependencies + +### Example: Go application with vendor dependencies + +Map vendored dependencies and modules: + +```yaml +version: v1 +source_code: + mappings: + # Vendor directory (for dependencies copied into your repo) + - path: + - prefix: vendor/ + language: go + source: + local: + path: vendor + + # External dependency at specific version + - path: + - prefix: github.com/prometheus/client_golang + language: go + source: + github: + owner: prometheus + repo: client_golang + ref: v1.19.0 + path: "" +``` + +### Example: Python application with dependencies + +Map Python application code and external dependencies: + +```yaml +version: v1 +source_code: + mappings: + # Local application code + - path: + - prefix: /app/src + language: python + source: + local: + path: src + + # Python standard library + - path: + - prefix: /usr/lib/python3.12 + - prefix: /usr/local/lib/python3.12 + language: python + source: + github: + owner: python + repo: cpython + ref: v3.12.0 + path: Lib + + # External package (requests) + - path: + - prefix: /usr/local/lib/python3.12/site-packages/requests + language: python + source: + github: + owner: psf + repo: requests + ref: v2.31.0 + path: src/requests +``` + +This configuration demonstrates: + +- **Local application code**: Maps your application's source directory +- **Standard library**: Maps Python standard library paths to the CPython repository +- **External packages**: Maps third-party packages to their GitHub repositories + +### Language-specific behavior + +#### Go + +For Go applications, Pyroscope provides intelligent fallback behavior even without a `.pyroscope.yaml` file: + +- **Standard library**: Automatically detected and mapped to the appropriate `golang/go` repository version +- **Go modules**: Parsed from `go.mod` in your repository, with automatic version resolution +- **Vanity URLs**: Resolved to canonical repositories (for example, `gopkg.in`, `google.golang.org`) +- **Vendor directories**: Files in `vendor/` are searched relative to repository root + +The system extracts Go version information from paths like `/usr/local/go/go1.24.10/src/fmt/print.go`. + +#### Java + +Java applications **require** explicit mappings in `.pyroscope.yaml`: + +- **Function name conversion**: Java function names like `org/example/App$Inner.method` are automatically converted to `org/example/App.java` +- **No fallback**: Unlike Go and Python, Java files cannot be resolved without configuration +- **Inner classes**: Automatically handled (inner class markers are stripped) + +#### Python + +For Python applications, Pyroscope provides intelligent fallback behavior similar to Go: + +- **Standard library**: Automatically detected and mapped to the appropriate `python/cpython` repository version +- **Installed packages**: Resolved from virtual environments or system packages +- **File paths**: Direct file paths are used when available from profiling data + +The system extracts Python version information from paths to map to the correct CPython repository version. + +### Troubleshooting + +**No source code displayed** + +- Verify the `.pyroscope.yaml` file is in your service's configured root path and that the root path is configured as expected +- Check that the `path` or `function_name` prefixes match your profiling data +- For Java applications, ensure all dependencies have mappings configured +- Confirm GitHub OAuth authorization is active and hasn't expired + +**Wrong version displayed** + +- Check the `ref` field in your mapping points to the correct branch, tag, or commit +- For Go standard library, verify the Go version in your mapping matches your application's Go version +- Use explicit commit SHAs for reproducibility + +**Mapping precedence issues** + +Pyroscope uses longest-prefix-match. If a more specific mapping isn't being used: + +- Verify the prefix exactly matches the beginning of the path or function name +- Check that more specific mappings are listed in the configuration (order doesn't matter, but clarity helps) +- Test with exact prefixes from your profiling data diff --git a/docs/sources/view-and-analyze-profile-data/profile-cli.md b/docs/sources/view-and-analyze-profile-data/profile-cli.md index 86fdacfb50..dc6926d66c 100644 --- a/docs/sources/view-and-analyze-profile-data/profile-cli.md +++ b/docs/sources/view-and-analyze-profile-data/profile-cli.md @@ -7,16 +7,20 @@ aliases: description: Getting started with the profile CLI tool. menuTitle: Profile CLI title: Profile CLI -weight: 60 +weight: 500 --- # Profile CLI -`profilecli` is a command-line utility that enables various productivity flows such as: +Pyroscope provides a command-line interface (CLI), `profilecli`. +This utility enables various productivity flows such as: + - Interacting with a running Pyroscope server to upload profiles, query data, and more - Inspecting [Parquet](https://parquet.apache.org/docs/) files -> Hint: Use the `help` command (`profilecli help`) to get a full list of capabilities as well as additional help information. +{{< admonition type="tip">}} +Use the `help` command (`profilecli help`) for a full list of capabilities and help information. +{{< /admonition>}} ## Install Profile CLI @@ -24,7 +28,7 @@ You can install Profile CLI using a package or by compiling the code. ### Install using a package -On macOS, you can install Profile CLI using [HomeBrew](https://brew.sh): +On macOS, you can install Profile CLI using [Homebrew](https://brew.sh): ```bash brew install pyroscope-io/brew/profilecli @@ -37,7 +41,7 @@ For example, for Linux with the AMD64 architecture: 1. Download and extract the package (archive). ```bash - curl -fL https://github.com/grafana/pyroscope/releases/download/v1.1.5/profilecli_1.1.5_linux_amd64.tar.gz | tar xvz + curl -fL https://github.com/grafana/pyroscope/releases/download/v1.13.2/profilecli_1.13.2_linux_amd64.tar.gz | tar xvz ``` 1. Make `profilecli` executable: @@ -56,7 +60,7 @@ For example, for Linux with the AMD64 architecture: To build from source code, you must have: -- Go installed (> 1.19). +- Go 1.24.6 or later installed. - Either `$GOPATH` or `$GOBIN` configured and added to your `PATH` environment variable. To build the source code: @@ -74,47 +78,92 @@ To build the source code: go install ./cmd/profilecli ``` - The command places the `profilecli` executable in `$GOPATH/bin/` (or `$GOBIN/`) and make it available to use. + The command places the `profilecli` executable in `$GOPATH/bin/` (or `$GOBIN/`) and makes it available to use. ## Common flags and environment variables -The `profilecli` commands that interact with a Pyroscope server require a server URL and optionally authentication details. These can be provided as command-line flags or environment variables. +The `profilecli` commands that interact with a Pyroscope server use the same connection and authentication flags. You can pass them as command flags or environment variables. + +| Purpose | Flag | Environment variable | Default | When it helps | +| --- | --- | --- | --- | --- | +| Pyroscope endpoint | `--url` | `PROFILECLI_URL` | `http://localhost:4040` | Point the command to your local server, Grafana Cloud Profiles endpoint, or Grafana data source proxy URL. | +| Basic authentication | `--username`, `--password` | `PROFILECLI_USERNAME`, `PROFILECLI_PASSWORD` | empty | Authenticate with a Cloud Profiles endpoint using stack ID and API token. | +| Bearer token | `--token` | `PROFILECLI_TOKEN` | empty | Authenticate through Grafana data source proxy URLs or token-based environments. | +| Tenant header | `--tenant-id` | `PROFILECLI_TENANT_ID` | empty | Set `X-Scope-OrgID` when you query or upload against multi-tenant deployments. | +| Transport protocol | `--protocol` | Not available | `connect` | Troubleshoot compatibility by switching to `grpc` or `grpc-web` if needed. | + +### Authentication examples + +Use the method that matches your environment. + +#### Basic auth example + +Use this pattern when you connect directly to a Cloud Profiles endpoint. + +```bash +export PROFILECLI_URL=https://profiles-prod-001.grafana.net +export PROFILECLI_USERNAME= +export PROFILECLI_PASSWORD= +profilecli query series --query='{service_name="checkout"}' +``` + +This is the most common setup when you are querying Cloud Profiles directly. -1. Server URL +#### Bearer token example - `default: http://localhost:4040` +Use this pattern when you connect through a Grafana data source proxy URL. - The `--url` flag specifies the server against which the command will run. - If using Grafana Cloud, an example URL could be `https://profiles-prod-001.grafana.net`. - For local instances, the URL could look like `http://localhost:4040`. +```bash +export PROFILECLI_URL=https://grafana.example.net/api/datasources/proxy/uid/ +export PROFILECLI_TOKEN= +profilecli query profile --profile-type=process_cpu:cpu:nanoseconds:cpu:nanoseconds +``` + +This is helpful when you want to use existing Grafana access controls instead of direct Pyroscope credentials. -1. Authentication details. +#### Multi-tenant example - `default: ` +Use this pattern for self-managed, multi-tenant Pyroscope deployments. + +```bash +export PROFILECLI_URL=https://pyroscope.example.net +export PROFILECLI_TENANT_ID=team-a +profilecli upload --extra-labels=service_name=payments ./cpu.pprof +``` - If using Grafana Cloud or authentication is enabled on your Pyroscope server, you will need to provide a username and password using the `--username` and `--password` flags respectively. - For Grafana Cloud, the username will be the Stack ID and the password the generated API token. +This is useful when a shared Pyroscope deployment routes data by tenant. ### Environment variable naming -You can use environment variables to avoid passing flags to the command every time you use it, or to protect sensitive information. -Environment variables have a `PROFILECLI_` prefix. Here is an example of providing the server URL and credentials for the `profilecli` tool: +You can use environment variables to avoid passing flags to every command and to reduce accidental credential exposure in shell history. +Environment variables have a `PROFILECLI_` prefix. Here is an example: ```bash export PROFILECLI_URL= export PROFILECLI_USERNAME= export PROFILECLI_PASSWORD= -# now we can run a profilecli command without specifying the url or credentials: +# now you can run profilecli commands without repeating URL or credentials: profilecli ``` +{{< admonition type="caution" >}} +If you're querying data from Cloud Profiles, use the URL of your Cloud Profiles server in `PROFILECLI_URL` (for example, `https://profiles-prod-001.grafana.net`) and **not** the URL of your Grafana Cloud tenant (for example, `.grafana.net`). +{{< /admonition >}} -## Uploading a profile to a Pyroscope server using `profilecli` +## Upload a profile to a Pyroscope server using `profilecli` Using `profilecli` streamlines the process of uploading profiles to Pyroscope, making it a convenient alternative to manual HTTP requests. -### Prerequisites +### Why this command helps + +Use `profilecli upload` when you have an exported pprof file and want to: + +- Reproduce a production issue in a test environment. +- Backfill a profile collected outside your normal instrumentation pipeline. +- Attach labels at upload time to make the data easier to query later. + +### Before you begin - Ensure you have `profilecli` installed on your system by following the [installation](#install-profile-cli) steps above. - Have a profile file ready for upload. Note that you can only upload pprof files at this time. @@ -130,6 +179,7 @@ Using `profilecli` streamlines the process of uploading profiles to Pyroscope, m - You can add additional labels to your uploaded profile using the `--extra-labels` flag. - You can provide the name of the application that the profile was captured from via the `service_name` label (defaults to `profilecli-upload`). This will be useful when querying the data via `profilecli` or the UI. - You can use the flag multiple times to add several labels. + - Use `--override-timestamp` if you want the uploaded profile to be treated as "now" instead of its original capture time. 1. Construct and execute the Upload command. @@ -163,26 +213,43 @@ Using `profilecli` streamlines the process of uploading profiles to Pyroscope, m path/to/your/pprof-file.pprof ``` + - Example command with timestamp override: + ```bash + profilecli upload \ + --override-timestamp \ + --extra-labels=service_name=debug-replay \ + ./local-capture.pprof + ``` + 1. Check for successful upload. - After running the command, you should see a confirmation message indicating a successful upload. If there are any issues, `profilecli` provides error messages to help you troubleshoot. -## Querying a Pyroscope server using `profilecli` +## Query a Pyroscope server using `profilecli` -You can use the `profilecli query` command to look up the available profiles on a Pyroscope server and read actual profile data. This can be useful for debugging purposes or for integrating profiling in CI pipelines (for example to facilitate [profile-guided optimization](https://go.dev/doc/pgo)). +You can use the `profilecli query` command to look up the available profiles on a Pyroscope server and read actual profile data. +This can be useful for debugging purposes or for integrating profiling in CI pipelines (for example to facilitate [profile-guided optimization](https://go.dev/doc/pgo)). -### Looking up available profiles on a Pyroscope server +### Look up available profiles on a Pyroscope server You can use the `profilecli query series` command to look up the available profiles on a Pyroscope server. By default, it queries the last hour of data, though this can be controlled with the `--from` and `--to` flags. You can narrow the results down with the `--query` flag. See `profilecli help query series` for more information. +This command is most helpful when you are exploring an unfamiliar environment and need to discover: + +- Which services are currently sending profiles. +- Which profile types are available for a service. +- Which label keys and values you can use for follow-up queries. + #### Query series steps -1. Optional: Specify a Query and a Time Range. +1. Optional: Specify a query, time range, and output format. - You can provide a label selector using the `--query` flag, for example: `--query='{service_name="my_application_name"}'`. - You can provide a custom time range using the `--from` and `--to` flags, for example, `--from="now-3h" --to="now"`. + - You can filter which label names appear in the output using the `--label-names` flag, for example, `--label-names=__profile_type__,service_name`. + - You can control the output format using `--output=table` (default) or `--output=json`. The table view renders one row per series with label names as sorted column headers. The JSON format emits a structured envelope containing `from`, `to`, and a `series` array, which is useful for scripting and pipeline integrations. 1. Construct and execute the Query Series command. @@ -204,36 +271,73 @@ You can narrow the results down with the `--query` flag. See `profilecli help qu profilecli query series --query='{service_name="my_application_name"}' ``` - - Example output: + - Example command with label filtering and default table output: + ```bash + profilecli query series \ + --query='{service_name="my_application_name"}' \ + --label-names=__profile_type__ \ + --label-names=service_name + ``` + + - Example table output (default): + ``` + +---------------------------------------------+---------------------+ + | PROFILE TYPE | SERVICE NAME | + +---------------------------------------------+---------------------+ + | memory:inuse_objects:count:space:bytes | my_application_name | + | process_cpu:cpu:nanoseconds:cpu:nanoseconds | my_application_name | + +---------------------------------------------+---------------------+ + ``` + + Columns are sorted alphabetically by their raw label name. Column headers are derived from label names with underscores replaced by spaces and converted to uppercase (for example, `__profile_type__` becomes `PROFILE TYPE`). + + - Example command using `--output=json`: + ```bash + profilecli query series \ + --query='{service_name="my_application_name"}' \ + --output=json + ``` + + - Example JSON output: ```json { - "__name__":"memory", - "__period_type__":"space", - "__period_unit__":"bytes", - "__profile_type__":"memory:inuse_objects:count:space:bytes", - "__service_name__":"my_application_name", - "__type__":"inuse_objects", - "__unit__":"count", - "cluster":"eu-west-1", - "service_name":"my_application_name" - } + "from": "2026-03-12T08:54:07.667114Z", + "to": "2026-03-12T09:54:07.667114Z", + "series": [ + { + "__name__": "memory", + "__period_type__": "space", + "__period_unit__": "bytes", + "__profile_type__": "memory:inuse_objects:count:space:bytes", + "__service_name__": "my_application_name", + "__type__": "inuse_objects", + "__unit__": "count", + "cluster": "eu-west-1", + "service_name": "my_application_name" + } + ] + } ``` -### Reading a raw profile from a Pyroscope server +### Read a raw profile from a Pyroscope server -You can use the `profilecli query merge` command to retrieve a merged (aggregated) profile from a Pyroscope server. +You can use the `profilecli query profile` command to retrieve a merged (aggregated) profile from a Pyroscope server. The command merges all samples found in the profile store for the specified query and time range. By default it looks for samples within the last hour, though this can be controlled with the `--from` and `--to` flags. The source data can be narrowed down with the `--query` flag in the same way as with the `series` command. -#### Query merge steps +This command is useful when you want to inspect merged profile data directly, save it for offline analysis, or compare profile windows in scripts and CI jobs. + +#### Query profile steps 1. Specify optional flags. - You can provide a label selector using the `--query` flag, for example, `--query='{service_name="my_application_name"}'`. - You can provide a custom time range using the `--from` and `--to` flags, for example, `--from="now-3h" --to="now"`. - You can specify the profile type via the `--profile-type` flag. The available profile types are listed in the output of the `profilecli query series` command. + - You can set `--output=pprof=./result.pprof` to save the merged profile as a pprof file. + - You can use `--function-names-only` for faster responses when you don't need full mapping and line details. -1. Construct and execute the Query Merge command. +2. Construct and execute the `query profile` command. - Here's a basic command template: ```bash @@ -241,9 +345,9 @@ By default it looks for samples within the last hour, though this can be control export PROFILECLI_USERNAME= export PROFILECLI_PASSWORD= - profilecli query merge \ + profilecli query profile \ --profile-type= \ - --query='{=""' \ + --query='{=""}' \ --from="" --to="" ``` @@ -253,12 +357,21 @@ By default it looks for samples within the last hour, though this can be control export PROFILECLI_USERNAME=my_username export PROFILECLI_PASSWORD=my_password - profilecli query merge \ + profilecli query profile \ --profile-type=memory:inuse_space:bytes:space:bytes \ --query='{service_name="my_application_name"}' \ --from="now-1h" --to="now" ``` + - Example command saving pprof output: + ```bash + profilecli query profile \ + --profile-type=process_cpu:cpu:nanoseconds:cpu:nanoseconds \ + --query='{service_name="checkout"}' \ + --from="now-30m" --to="now" \ + --output=pprof=./checkout-cpu.pprof + ``` + - Example output: ```bash level=info msg="query aggregated profile from profile store" url=http://localhost:4040 from=2023-12-11T13:38:33.115683-04:00 to=2023-12-11T14:38:33.115684-04:00 query={} type=memory:inuse_space:bytes:space:bytes @@ -271,3 +384,97 @@ By default it looks for samples within the last hour, though this can be control 115366240: 107 13 14 15 16 17 1 2 3 ... ``` + +### Export a profile for Go PGO + +You can use the `profilecli query go-pgo` command to retrieve an aggregated profile from a Pyroscope server for use with Go PGO. +Profiles retrieved with `profilecli query profile` include all samples found in the profile store, resulting in a large profile size. +The profile size may cause issues with network transfer and slow down the PGO process. +In contrast, profiles retrieved with `profilecli query go-pgo` include only the information used in Go PGO, making them significantly smaller and more efficient to handle. +By default, it looks for samples within the last hour, though this can be controlled with the `--from` and `--to` flags. The source data can be narrowed down with the `--query` flag in the same way as with the `query` command. + +1. Specify optional flags. + + - You can provide a label selector using the `--query` flag, for example, `--query='{service_name="my_application_name"}'`. + - You can provide a custom time range using the `--from` and `--to` flags, for example, `--from="now-3h" --to="now"`. + - You can specify the profile type via the `--profile-type` flag. The available profile types are listed in the output of the `profilecli query series` command. + - You can specify the number of leaf locations to keep via the `--keep-locations` flag. The default value is `5`. The Go compiler does not use the full stack trace. Reducing the number helps to minimize the profile size. + - You can control whether to use callee aggregation with the `--aggregate-callees` flag. By default, this option is enabled, meaning samples are aggregated based on the leaf location, disregarding the callee line number, which the Go compiler does not utilize. To disable aggregation, use the `--no-aggregate-callees` flag. + +2. Construct and execute the command. + + - Example command: + ```bash + export PROFILECLI_URL=https://profiles-prod-001.grafana.net + export PROFILECLI_USERNAME=my_username + export PROFILECLI_PASSWORD=my_password + + profilecli query go-pgo \ + --query='{service_name="my_service"}' \ + --from="now-1h" --to="now" + ``` + + - Example output: + ```bash + level=info msg="querying pprof profile for Go PGO" url=https://localhost:4040 query="{service_name=\"my_service\"}" from=2024-06-20T12:32:20+08:00 to=2024-06-20T15:24:40+08:00 type=process_cpu:cpu:nanoseconds:cpu:nanoseconds output="pprof=default.pgo" keep-locations=5 aggregate-callees=true + # By default, the profile is saved to the current directory as `default.pgo` + ``` + +## Other useful commands + +The following commands are also useful in day-to-day operations. + +### Find top contributors by label value + +Use `profilecli query top` to identify the biggest contributors in a time window. +This is useful when triaging spikes and you need a quick ranked view before doing deeper exploration. + +```bash +profilecli query top \ + --query='{__profile_type__="process_cpu:cpu:nanoseconds:cpu:nanoseconds"}' \ + --label-names=service_name \ + --top-n=10 +``` + +### Detect high-cardinality labels + +Use `profilecli query label-values-cardinality` to find label keys with many values. +This is useful when troubleshooting query cost, dashboard slowness, or label design issues. + +```bash +profilecli query label-values-cardinality \ + --query='{service_name=~".+"}' \ + --top-n=20 +``` + +### Check endpoint readiness quickly + +Use `profilecli ready` in scripts and CI checks to verify endpoint health before running upload or query automation. + +```bash +profilecli ready --url=http://localhost:4040 +``` + +### Manage recording rules from the CLI + +Use `profilecli recording-rules` commands to list, create, get, and delete recording rules without leaving your terminal. +This is useful for GitOps-style workflows and automated rollout validation. + +```bash +profilecli recording-rules list +``` + +### Validate source mapping coverage + +Use `profilecli source-code coverage` to measure how well your `.pyroscope.yaml` mappings translate symbols from a pprof profile to source files. +This is useful when source links in the UI are missing or incomplete. +The command requires GitHub API access. Provide a token with `--github-token` or `PROFILECLI_GITHUB_TOKEN`. + +```bash +export PROFILECLI_GITHUB_TOKEN= + +profilecli source-code coverage \ + --profile=./cpu.pprof \ + --config=./.pyroscope.yaml \ + --output=detailed +``` diff --git a/docs/sources/view-and-analyze-profile-data/profile-tracing/_index.md b/docs/sources/view-and-analyze-profile-data/profile-tracing/_index.md deleted file mode 100644 index d166dc2c0e..0000000000 --- a/docs/sources/view-and-analyze-profile-data/profile-tracing/_index.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Profiling and tracing integration -menuTitle: Profiling and tracing -description: Learning about how profiling and tracing work together. -weight: 50 -aliases: - - ../introduction/traces-to-profiles/ - - ../introduction/profile-tracing/ -keywords: - - pyroscope - - continuous profiling - - tracing ---- - -# Profiling and tracing integration - - -[//]: # 'Shared content for Trace to profiles in the Pyroscope data source' - -{{< docs/shared source="grafana" lookup="datasources/pyroscope-profile-tracing-intro.md" version="" >}} diff --git a/docs/sources/view-and-analyze-profile-data/profile-tracing/traces-to-profiles.md b/docs/sources/view-and-analyze-profile-data/profile-tracing/traces-to-profiles.md deleted file mode 100644 index 2669b61a6c..0000000000 --- a/docs/sources/view-and-analyze-profile-data/profile-tracing/traces-to-profiles.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Traces to profiles -menuTitle: Traces to profiles -description: Learning about traces to profiles integration in Grafana and Grafana Cloud. -weight: 150 -keywords: - - pyroscope - - continuous profiling - - tracing ---- - -# Traces to profiles - -{{< admonition type="note" >}} - -Your application must be instrumented for profiles and traces. For more information, refer to [Span profiles for Traces to profiles]({{< relref "../../configure-client/trace-span-profiles" >}}). - -{{< /admonition >}} - -[//]: # 'Shared content for Trace to profiles in the Tempo data source' - -{{< docs/shared source="grafana" lookup="datasources/tempo-traces-to-profiles.md" version="" >}} diff --git a/docs/sources/view-and-analyze-profile-data/profiling-types/_index.md b/docs/sources/view-and-analyze-profile-data/profiling-types/_index.md deleted file mode 100644 index 97e36b016e..0000000000 --- a/docs/sources/view-and-analyze-profile-data/profiling-types/_index.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Understand profiling types and their uses in Pyroscope -menuTitle: Understand profiling types -description: Learn about the different profiling types available in Pyroscope and how to effectively use them in your application performance analysis. -weight: 30 -aliases: - - ../ingest-and-analyze-profile-data/profiling-types/ -keywords: - - pyroscope - - profiling types - - application performance - - flame graphs ---- - -# Understand profiling types and their uses in Pyroscope - -Profiling is an essential tool for understanding and optimizing application performance. In Pyroscope, various profiling types allow for an in-depth analysis of different aspects of your application. This guide explores these types and explain their impact on your program. - -## Profiling types - -In Pyroscope, profiling types refer to different dimensions of application performance analysis, focusing on specific aspects like CPU usage, memory allocation, or thread synchronization. - -For information on auto-instrumentation and supported language SDKs, refer to [Configure the client]({{< relref "../../configure-client" >}}). - -### Available profiling types - -Various languages support different profiling types. -Pyroscope supports the following profiling types: - -| Profile Type | Go | Java | .NET | Ruby | Python | Rust | Node.js | eBPF (Go) | eBPF (Python) | -|--------------------|-------|-------|-------|-------|--------|-------|---------|-----------|--------------| -| CPU | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | -| Alloc Objects | Yes | Yes | Yes | | | | | | | -| Alloc Space | Yes | Yes | Yes | | | | | | | -| Inuse Objects | Yes | | | | | | | | | -| Inuse Space | Yes | | | | | | | | | -| Goroutines | Yes | | | | | | | | | -| Mutex Count | Yes | | Yes | | | | | | | -| Mutex Duration | Yes | | Yes | | | | | | | -| Block Count | Yes | | | | | | | | | -| Block Duration | Yes | | | | | | | | | -| Lock Count | | Yes | Yes | | | | | | | -| Lock Duration | | Yes | Yes | | | | | | | -| Exceptions | | | Yes | | | | | | | -| Wall | | | Yes | | | | | | | -| Heap | | | | | | | Yes | | | - -## CPU profiling - - - -CPU profiling measures the amount of CPU time consumed by different parts of your application code. -High CPU usage can indicate inefficient code, leading to poor performance and increased operational costs. -It's used to identify and optimize CPU-intensive functions in your application. - -- **When to use**: To identify and optimize CPU-intensive functions -- **Flame graph insight**: The width of blocks indicates the CPU time consumed by each function - -As you can see here, the UI shows a spike in CPU along with the flame graph associated with that spike. -Often times without profiling you may get similar insights from metrics, but with profiling you have more details into the specific cause of a spike in CPU usage at the line level - -![example flame graph](https://grafana.com/static/img/pyroscope/pyroscope-ui-single-2023-11-30.png) - - - -## Memory allocation profiling - -Memory allocation profiling tracks the amount and frequency of memory allocations by the application. -Excessive or inefficient memory allocation can lead to memory leaks and high garbage collection overhead, impacting application efficiency. - -- **Types**: Alloc Objects, Alloc Space -- **When to use**: For identifying and optimizing memory usage patterns -- **Flame graph insight**: Highlights functions where memory allocation is high - -The timeline shows memory allocations over time and is great for debugging memory related issues. -A common example is when a memory leak is created due to improper handling of memory in a function. -This can be identified by looking at the timeline and seeing a gradual increase in memory allocations that never goes down. -This is a clear indicator of a memory leak. - -![memory leak example](https://grafana.com/static/img/pyroscope/pyroscope-memory-leak-2023-11-30.png) - -Without profiling, this may be something that's exhibited in metrics or out-of-memory errors (OOM) logs but with profiling you have more details into the specific function that's allocating the memory which is causing the leak at the line level. - -## Goroutine profiling - -Goroutines are lightweight threads in Go, used for concurrent operations. -Goroutine profiling measures the usage and performance of these threads. -Poor management can lead to issues like deadlocks and excessive resource usage. - -- **When to use**: Especially useful in Go applications for concurrency management -- **Flame graph insight**: Provides a view of goroutine distribution and issues - -## Mutex profiling - -Mutex profiling involves analyzing mutex (mutual exclusion) locks, used to prevent simultaneous access to shared resources. -Excessive or long-duration mutex locks can cause delays and reduced application throughput. - -- **Types**: Mutex Count, Mutex Duration -- **When to use**: To optimize thread synchronization and reduce lock contention -- **Flame graph insight**: Shows frequency and duration of mutex operations - -## Block profiling - -Block profiling measures the frequency and duration of blocking operations, where a thread is paused or delayed. -Blocking can significantly slow down application processes, leading to performance bottlenecks. - -- **Types**: Block Count, Block Duration -- **When to use**: To identify and reduce blocking delays -- **Flame graph insight**: Identifies where and how long threads are blocked diff --git a/docs/sources/view-and-analyze-profile-data/pyroscope-ui.md b/docs/sources/view-and-analyze-profile-data/pyroscope-ui.md index 4aae7f2ffc..7ee90cf284 100644 --- a/docs/sources/view-and-analyze-profile-data/pyroscope-ui.md +++ b/docs/sources/view-and-analyze-profile-data/pyroscope-ui.md @@ -2,7 +2,7 @@ title: Use the Pyroscope UI to explore profiling data menuTitle: Use the Pyroscope UI description: How to use the Pyroscope UI to explore profile data. -weight: 40 +weight: 200 aliases: - ../ingest-and-analyze-profile-data/profile-ui/ keywords: @@ -16,6 +16,9 @@ keywords: Pyroscope's UI is designed to make it easy to visualize and analyze profiling data. There are several different modes for viewing, analyzing, uploading, and comparing profiling data. +The Pyroscope UI is only available with Pyroscope open source. +In Grafana and Grafana Cloud, you can use [Profiles Drilldown](https://grafana.com/docs/grafana//explore/simplified-exploration/profiles/) to inspect your profiling data. + ![Screenshot of Pyroscope UI](/media/docs/pyroscope/screenshot-pyroscope-comparison-view.png) While code profiling has been a long-standing practice, continuous profiling represents a modern and more advanced approach to performance monitoring. This technique adds two critical dimensions to traditional profiles: diff --git a/docs/sources/view-and-analyze-profile-data/self-vs-total.md b/docs/sources/view-and-analyze-profile-data/self-vs-total.md index 23fbb60769..6f6d7b6d9a 100644 --- a/docs/sources/view-and-analyze-profile-data/self-vs-total.md +++ b/docs/sources/view-and-analyze-profile-data/self-vs-total.md @@ -2,7 +2,7 @@ title: Understand 'self' vs. 'total' metrics in profiling with Pyroscope menuTitle: Understand 'self' vs. 'total' metrics description: Learn the differences between 'self' and 'total' metrics in profiling and their specific applications in CPU and Memory profiling with Pyroscope. -weight: 42 +weight: 300 aliases: - ../ingest-and-analyze-profile-data/self-vs-total/ keywords: diff --git a/docs/sources/view-and-analyze-profile-data/traces-to-profiles.md b/docs/sources/view-and-analyze-profile-data/traces-to-profiles.md new file mode 100644 index 0000000000..a948103cb8 --- /dev/null +++ b/docs/sources/view-and-analyze-profile-data/traces-to-profiles.md @@ -0,0 +1,24 @@ +--- +title: Traces to profiles +menuTitle: Traces to profiles +description: Learn about traces to profiles integration in Grafana and Grafana Cloud. +weight: 500 +keywords: + - pyroscope + - continuous profiling + - tracing +aliases: + - ./profile-tracing/traces-to-profiles/ # https://grafana.com/docs/pyroscope/latest/view-and-analyze-profile-data/profile-tracing/traces-to-profiles/ +--- + +# Traces to profiles + +{{< admonition type="note" >}} + +Your application must be instrumented for profiles and traces. For more information, refer to [Link traces to profiles](https://grafana.com/docs/pyroscope//configure-client/trace-span-profiles/). + +{{< /admonition >}} + +[//]: # 'Shared content for Trace to profiles in the Tempo data source' + +{{< docs/shared source="grafana" lookup="datasources/tempo-traces-to-profiles.md" version="" >}} diff --git a/docs/variables.mk b/docs/variables.mk index 9981eabc21..721814e653 100644 --- a/docs/variables.mk +++ b/docs/variables.mk @@ -5,9 +5,3 @@ # The source of the content is the current repository which is determined by the name of the parent directory of the git root. # This overrides the default behavior of assuming the repository directory is the same as the project name. PROJECTS := pyroscope::$(notdir $(basename $(shell git rev-parse --show-toplevel))) - -# Set the DOC_VALIDATOR_IMAGE to match the one defined in CI. -export DOC_VALIDATOR_IMAGE := $(shell sed -En 's, *image: "(grafana/doc-validator.*)",\1,p' "$(shell git rev-parse --show-toplevel)/.github/workflows/test.yml") - -# Skip some doc-validator checks. -export DOC_VALIDATOR_SKIP_CHECKS := $(shell sed -En "s, *'--skip-checks=(.+)',\1,p" "$(shell git rev-parse --show-toplevel)/.github/workflows/test.yml") diff --git a/ebpf/.gitignore b/ebpf/.gitignore deleted file mode 100644 index da38b3dcda..0000000000 --- a/ebpf/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -cmake-build-*/ -.tmp/ -main diff --git a/ebpf/CMakeLists.txt b/ebpf/CMakeLists.txt deleted file mode 100644 index ccf87cbc75..0000000000 --- a/ebpf/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.27) -project(pyrobpf C) -# This is a dumb project to help using IDE/tools to develop bpf program -# CLion can load cmake project -# Cmake+ninja can also generate compile_commands.json which may used by clangd etc -set(CMAKE_C_STANDARD 11) - -add_library(pyrobpf bpf/profile.bpf.c) -target_include_directories(pyrobpf PRIVATE bpf bpf/vmlinux bpf/libbpf) -target_compile_definitions(pyrobpf PRIVATE -D__TARGET_ARCH_x86) -target_compile_options(pyrobpf PRIVATE -nostdinc -nostdlib) - -add_library(pyperf bpf/pyperf.bpf.c) -target_include_directories(pyperf PRIVATE bpf bpf/vmlinux bpf/libbpf) -target_compile_definitions(pyperf PRIVATE -D__TARGET_ARCH_x86) -target_compile_options(pyperf PRIVATE -nostdinc -nostdlib) diff --git a/ebpf/Makefile b/ebpf/Makefile deleted file mode 100644 index 8731dd734c..0000000000 --- a/ebpf/Makefile +++ /dev/null @@ -1,110 +0,0 @@ -GO ?= go -RIDESHARE_REPO ?= pyroscope -RIDESHARE=testdata/rideshare-flask-no-pip - -ifeq ($(shell uname -s),Linux) -ifeq ($(shell uname -m),x86_64) -EBPF_GO_TEST_FLAGS_AMD64 = -v -race -cover -EBPF_CGO_ENABLED_AMD64 = 1 -EBPF_GO_TEST_FLAGS_ARM64 = -v -EBPF_CGO_ENABLED_ARM64 = 0 -else -EBPF_GO_TEST_FLAGS_AMD64 = -v -EBPF_CGO_ENABLED_AMD64 = 0 -EBPF_GO_TEST_FLAGS_ARM64 = -v -race -cover -EBPF_CGO_ENABLED_ARM64 = 1 -endif # $(shell uname -m),x86_64 -else -EBPF_GO_TEST_FLAGS_AMD64 = -v -EBPF_CGO_ENABLED_AMD64 = 0 -EBPF_GO_TEST_FLAGS_ARM64 = -v -EBPF_CGO_ENABLED_ARM64 = 0 -endif # $(shell uname -s),Linux - - - - -.phony: python/dwarfdump -python/dwarfdump: - git submodule update --init --recursive - - echo "//go:build amd64 && linux" > python/python_offsets_gen_amd64.go - go run cmd/python_dwarfdump/main.go $(shell find testdata/python-x64 -name libpy\*.so\* | grep -v pyston) \ - $(shell find testdata/python-x64 | grep -E "/python3\\.[0-9]+") >> python/python_offsets_gen_amd64.go - go fmt python/python_offsets_gen_amd64.go - - echo "//go:build arm64 && linux" > python/python_offsets_gen_arm64.go - go run cmd/python_dwarfdump/main.go $(shell find testdata/python-arm64 -name libpy\*.so\* | grep -v pyston) \ - $(shell find testdata/python-arm64 | grep -E "/python3\\.[0-9]+") >> python/python_offsets_gen_arm64.go - go fmt python/python_offsets_gen_arm64.go - - -.phony: glibc/dwarfdump -glibc/dwarfdump: - git submodule update --init --recursive - - echo "//go:build amd64 && linux" > python/glibc_offsets_gen_amd64.go - go run cmd/glibc_dwarfdump/main.go $(shell find testdata/glibc-x64 -name libc.so.6 ) >> python/glibc_offsets_gen_amd64.go - go fmt python/glibc_offsets_gen_amd64.go - - echo "//go:build arm64 && linux" > python/glibc_offsets_gen_arm64.go - go run cmd/glibc_dwarfdump/main.go $(shell find testdata/glibc-arm64 -name libc.so.6 ) >> python/glibc_offsets_gen_arm64.go - go fmt python/glibc_offsets_gen_arm64.go - -.phony: musl/dwarfdump -musl/dwarfdump: - git submodule update --init --recursive - - echo "//go:build amd64 && linux" > python/musl_offsets_gen_amd64.go - go run cmd/musl_dwarfdump/main.go $(shell find testdata/alpine-amd64 -name ld-musl-x86_64.so.1.debug ) >> python/musl_offsets_gen_amd64.go - go fmt python/musl_offsets_gen_amd64.go - - echo "//go:build arm64 && linux" > python/musl_offsets_gen_arm64.go - go run cmd/musl_dwarfdump/main.go $(shell find testdata/alpine-arm64 -name ld-musl-aarch64.so.1.debug) >> python/musl_offsets_gen_arm64.go - go fmt python/musl_offsets_gen_arm64.go - -.phony: bpf/gen -bpf/gen: - go generate pyrobpf/gen.go - go generate python/gen.go - -.PHONY: ebpf.amd64.test -ebpf.amd64.test: - CGO_ENABLED=$(EBPF_CGO_ENABLED_AMD64) GOOS=linux GOARCH=amd64 \ - $(GO) test -c $(EBPF_GO_TEST_FLAGS_AMD64) -o ebpf.amd64.test ./ - -.PHONY: ebpf.arm64.test -ebpf.arm64.test: - CGO_ENABLED=$(EBPF_CGO_ENABLED_ARM64) GOOS=linux GOARCH=arm64 \ - $(GO) test -c $(EBPF_GO_TEST_FLAGS_ARM64) -o ebpf.arm64.test ./ - -.PHONY: go/test/amd64 -go/test/amd64: ebpf.amd64.test - whoami | grep root - uname -m | grep x86_64 - ./ebpf.amd64.test - -.PHONY: go/test/arm64 -go/test/arm64: ebpf.arm64.test - whoami | grep root - uname -m | grep aarch64 - ./ebpf.arm64.test - - -.phony: rideshare/gen -rideshare/gen: - git submodule update --init --recursive - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.8-slim --build-arg="PYTHON_VERSION=3.8-slim" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.9-slim --build-arg="PYTHON_VERSION=3.9-slim" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.10-slim --build-arg="PYTHON_VERSION=3.10-slim" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.11-slim --build-arg="PYTHON_VERSION=3.11-slim" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.12-slim --build-arg="PYTHON_VERSION=3.12-slim" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.13-rc-slim --build-arg="PYTHON_VERSION=3.13-rc-slim" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.8-alpine --build-arg="PYTHON_VERSION=3.8-alpine" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.9-alpine --build-arg="PYTHON_VERSION=3.9-alpine" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.10-alpine --build-arg="PYTHON_VERSION=3.10-alpine" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.11-alpine --build-arg="PYTHON_VERSION=3.11-alpine" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.12-alpine --build-arg="PYTHON_VERSION=3.12-alpine" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:3.13-rc-alpine --build-arg="PYTHON_VERSION=3.13-rc-alpine" $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:ubuntu-20.04 --build-arg="BASE=ubuntu:20.04" --build-arg="FLASK_VERSION=3.0.3" -f $(RIDESHARE)/ubuntu.Dockerfile $(RIDESHARE) - docker buildx build --platform=linux/amd64,linux/arm64 --push -t $(RIDESHARE_REPO)/ebpf-testdata-rideshare:ubuntu-22.04 --build-arg="BASE=ubuntu:22.04" --build-arg="FLASK_VERSION=3.0.3" -f $(RIDESHARE)/ubuntu.Dockerfile $(RIDESHARE) diff --git a/ebpf/bpf/.gitignore b/ebpf/bpf/.gitignore deleted file mode 100644 index ebcc964bfe..0000000000 --- a/ebpf/bpf/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -CMakeLists.txt -cmake-build-debug -pyperf.so \ No newline at end of file diff --git a/ebpf/bpf/Makefile b/ebpf/bpf/Makefile deleted file mode 100644 index 0592b5a640..0000000000 --- a/ebpf/bpf/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -LIBBPF_VERSION=0.6.1 -LIBBPF_PREFIX="https://raw.githubusercontent.com/libbpf/libbpf/v$(LIBBPF_VERSION)" - -.PHONY: get-headers -get-headers: get-libbpf-headers get-vmlinux-header - -.PHONY: get-libbpf-headers -get-libbpf-headers: - cd libbpf && \ - curl -O $(LIBBPF_PREFIX)/src/bpf_endian.h && \ - curl -O $(LIBBPF_PREFIX)/src/bpf_helper_defs.h && \ - curl -O $(LIBBPF_PREFIX)/src/bpf_helpers.h && \ - curl -O $(LIBBPF_PREFIX)/src/bpf_tracing.h && \ - curl -O $(LIBBPF_PREFIX)/src/bpf_core_read.h - -.PHONY: get-vmlinux-header -get-vmlinux-header: - cd vmlinux && \ - curl -o vmlinux.h https://raw.githubusercontent.com/iovisor/bcc/v0.27.0/libbpf-tools/x86/vmlinux_518.h - -.PHONY: clean -clean: - rm -rf libbpf/*.h vmlinux/*.h diff --git a/ebpf/bpf/hash.h b/ebpf/bpf/hash.h deleted file mode 100644 index 0e2ec200c7..0000000000 --- a/ebpf/bpf/hash.h +++ /dev/null @@ -1,44 +0,0 @@ - - -// murmurhash2 from -// https://github.com/aappleby/smhasher/blob/92cf3702fcfaadc84eb7bef59825a23e0cd84f56/src/MurmurHash2.cpp/* */ -// https://github.com/parca-dev/parca-agent/blob/main/bpf/unwinders/hash.h - -// Hash limit in bytes, set to size of python stack -#define HASH_LIMIT 32 * 3 * 4 -// len should be multiple of 4 -static __always_inline uint64_t MurmurHash64A ( const void * key, uint64_t len, uint64_t seed ) -{ - const uint64_t m = 0xc6a4a7935bd1e995ULL; - const int r = 47; - - uint64_t h = seed ^ (len * m); - - const uint64_t * data = key; - int i = 0; - for (; i < len/8 && i < HASH_LIMIT/8; i++) - { - uint64_t k = data[i]; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - } - - - const unsigned char * data2 = (const unsigned char*)&data[i]; - if(len & 7) - { - h ^= (uint64_t)(((uint32_t*)data2)[0]); - h *= m; - }; - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; -} \ No newline at end of file diff --git a/ebpf/bpf/libbpf/bpf_core_read.h b/ebpf/bpf/libbpf/bpf_core_read.h deleted file mode 100644 index e4aa9996a5..0000000000 --- a/ebpf/bpf/libbpf/bpf_core_read.h +++ /dev/null @@ -1,444 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#ifndef __BPF_CORE_READ_H__ -#define __BPF_CORE_READ_H__ - -/* - * enum bpf_field_info_kind is passed as a second argument into - * __builtin_preserve_field_info() built-in to get a specific aspect of - * a field, captured as a first argument. __builtin_preserve_field_info(field, - * info_kind) returns __u32 integer and produces BTF field relocation, which - * is understood and processed by libbpf during BPF object loading. See - * selftests/bpf for examples. - */ -enum bpf_field_info_kind { - BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */ - BPF_FIELD_BYTE_SIZE = 1, - BPF_FIELD_EXISTS = 2, /* field existence in target kernel */ - BPF_FIELD_SIGNED = 3, - BPF_FIELD_LSHIFT_U64 = 4, - BPF_FIELD_RSHIFT_U64 = 5, -}; - -/* second argument to __builtin_btf_type_id() built-in */ -enum bpf_type_id_kind { - BPF_TYPE_ID_LOCAL = 0, /* BTF type ID in local program */ - BPF_TYPE_ID_TARGET = 1, /* BTF type ID in target kernel */ -}; - -/* second argument to __builtin_preserve_type_info() built-in */ -enum bpf_type_info_kind { - BPF_TYPE_EXISTS = 0, /* type existence in target kernel */ - BPF_TYPE_SIZE = 1, /* type size in target kernel */ -}; - -/* second argument to __builtin_preserve_enum_value() built-in */ -enum bpf_enum_value_kind { - BPF_ENUMVAL_EXISTS = 0, /* enum value existence in kernel */ - BPF_ENUMVAL_VALUE = 1, /* enum value value relocation */ -}; - -#define __CORE_RELO(src, field, info) \ - __builtin_preserve_field_info((src)->field, BPF_FIELD_##info) - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \ - bpf_probe_read_kernel( \ - (void *)dst, \ - __CORE_RELO(src, fld, BYTE_SIZE), \ - (const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET)) -#else -/* semantics of LSHIFT_64 assumes loading values into low-ordered bytes, so - * for big-endian we need to adjust destination pointer accordingly, based on - * field byte size - */ -#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \ - bpf_probe_read_kernel( \ - (void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \ - __CORE_RELO(src, fld, BYTE_SIZE), \ - (const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET)) -#endif - -/* - * Extract bitfield, identified by s->field, and return its value as u64. - * All this is done in relocatable manner, so bitfield changes such as - * signedness, bit size, offset changes, this will be handled automatically. - * This version of macro is using bpf_probe_read_kernel() to read underlying - * integer storage. Macro functions as an expression and its return type is - * bpf_probe_read_kernel()'s return value: 0, on success, <0 on error. - */ -#define BPF_CORE_READ_BITFIELD_PROBED(s, field) ({ \ - unsigned long long val = 0; \ - \ - __CORE_BITFIELD_PROBE_READ(&val, s, field); \ - val <<= __CORE_RELO(s, field, LSHIFT_U64); \ - if (__CORE_RELO(s, field, SIGNED)) \ - val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64); \ - else \ - val = val >> __CORE_RELO(s, field, RSHIFT_U64); \ - val; \ -}) - -/* - * Extract bitfield, identified by s->field, and return its value as u64. - * This version of macro is using direct memory reads and should be used from - * BPF program types that support such functionality (e.g., typed raw - * tracepoints). - */ -#define BPF_CORE_READ_BITFIELD(s, field) ({ \ - const void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \ - unsigned long long val; \ - \ - /* This is a so-called barrier_var() operation that makes specified \ - * variable "a black box" for optimizing compiler. \ - * It forces compiler to perform BYTE_OFFSET relocation on p and use \ - * its calculated value in the switch below, instead of applying \ - * the same relocation 4 times for each individual memory load. \ - */ \ - asm volatile("" : "=r"(p) : "0"(p)); \ - \ - switch (__CORE_RELO(s, field, BYTE_SIZE)) { \ - case 1: val = *(const unsigned char *)p; break; \ - case 2: val = *(const unsigned short *)p; break; \ - case 4: val = *(const unsigned int *)p; break; \ - case 8: val = *(const unsigned long long *)p; break; \ - } \ - val <<= __CORE_RELO(s, field, LSHIFT_U64); \ - if (__CORE_RELO(s, field, SIGNED)) \ - val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64); \ - else \ - val = val >> __CORE_RELO(s, field, RSHIFT_U64); \ - val; \ -}) - -/* - * Convenience macro to check that field actually exists in target kernel's. - * Returns: - * 1, if matching field is present in target kernel; - * 0, if no matching field found. - */ -#define bpf_core_field_exists(field) \ - __builtin_preserve_field_info(field, BPF_FIELD_EXISTS) - -/* - * Convenience macro to get the byte size of a field. Works for integers, - * struct/unions, pointers, arrays, and enums. - */ -#define bpf_core_field_size(field) \ - __builtin_preserve_field_info(field, BPF_FIELD_BYTE_SIZE) - -/* - * Convenience macro to get BTF type ID of a specified type, using a local BTF - * information. Return 32-bit unsigned integer with type ID from program's own - * BTF. Always succeeds. - */ -#define bpf_core_type_id_local(type) \ - __builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL) - -/* - * Convenience macro to get BTF type ID of a target kernel's type that matches - * specified local type. - * Returns: - * - valid 32-bit unsigned type ID in kernel BTF; - * - 0, if no matching type was found in a target kernel BTF. - */ -#define bpf_core_type_id_kernel(type) \ - __builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET) - -/* - * Convenience macro to check that provided named type - * (struct/union/enum/typedef) exists in a target kernel. - * Returns: - * 1, if such type is present in target kernel's BTF; - * 0, if no matching type is found. - */ -#define bpf_core_type_exists(type) \ - __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS) - -/* - * Convenience macro to get the byte size of a provided named type - * (struct/union/enum/typedef) in a target kernel. - * Returns: - * >= 0 size (in bytes), if type is present in target kernel's BTF; - * 0, if no matching type is found. - */ -#define bpf_core_type_size(type) \ - __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE) - -/* - * Convenience macro to check that provided enumerator value is defined in - * a target kernel. - * Returns: - * 1, if specified enum type and its enumerator value are present in target - * kernel's BTF; - * 0, if no matching enum and/or enum value within that enum is found. - */ -#define bpf_core_enum_value_exists(enum_type, enum_value) \ - __builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS) - -/* - * Convenience macro to get the integer value of an enumerator value in - * a target kernel. - * Returns: - * 64-bit value, if specified enum type and its enumerator value are - * present in target kernel's BTF; - * 0, if no matching enum and/or enum value within that enum is found. - */ -#define bpf_core_enum_value(enum_type, enum_value) \ - __builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE) - -/* - * bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures - * offset relocation for source address using __builtin_preserve_access_index() - * built-in, provided by Clang. - * - * __builtin_preserve_access_index() takes as an argument an expression of - * taking an address of a field within struct/union. It makes compiler emit - * a relocation, which records BTF type ID describing root struct/union and an - * accessor string which describes exact embedded field that was used to take - * an address. See detailed description of this relocation format and - * semantics in comments to struct bpf_field_reloc in libbpf_internal.h. - * - * This relocation allows libbpf to adjust BPF instruction to use correct - * actual field offset, based on target kernel BTF type that matches original - * (local) BTF, used to record relocation. - */ -#define bpf_core_read(dst, sz, src) \ - bpf_probe_read_kernel(dst, sz, (const void *)__builtin_preserve_access_index(src)) - -/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */ -#define bpf_core_read_user(dst, sz, src) \ - bpf_probe_read_user(dst, sz, (const void *)__builtin_preserve_access_index(src)) -/* - * bpf_core_read_str() is a thin wrapper around bpf_probe_read_str() - * additionally emitting BPF CO-RE field relocation for specified source - * argument. - */ -#define bpf_core_read_str(dst, sz, src) \ - bpf_probe_read_kernel_str(dst, sz, (const void *)__builtin_preserve_access_index(src)) - -/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */ -#define bpf_core_read_user_str(dst, sz, src) \ - bpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src)) - -#define ___concat(a, b) a ## b -#define ___apply(fn, n) ___concat(fn, n) -#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N - -/* - * return number of provided arguments; used for switch-based variadic macro - * definitions (see ___last, ___arrow, etc below) - */ -#define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -/* - * return 0 if no arguments are passed, N - otherwise; used for - * recursively-defined macros to specify termination (0) case, and generic - * (N) case (e.g., ___read_ptrs, ___core_read) - */ -#define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0) - -#define ___last1(x) x -#define ___last2(a, x) x -#define ___last3(a, b, x) x -#define ___last4(a, b, c, x) x -#define ___last5(a, b, c, d, x) x -#define ___last6(a, b, c, d, e, x) x -#define ___last7(a, b, c, d, e, f, x) x -#define ___last8(a, b, c, d, e, f, g, x) x -#define ___last9(a, b, c, d, e, f, g, h, x) x -#define ___last10(a, b, c, d, e, f, g, h, i, x) x -#define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__) - -#define ___nolast2(a, _) a -#define ___nolast3(a, b, _) a, b -#define ___nolast4(a, b, c, _) a, b, c -#define ___nolast5(a, b, c, d, _) a, b, c, d -#define ___nolast6(a, b, c, d, e, _) a, b, c, d, e -#define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f -#define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g -#define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h -#define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i -#define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__) - -#define ___arrow1(a) a -#define ___arrow2(a, b) a->b -#define ___arrow3(a, b, c) a->b->c -#define ___arrow4(a, b, c, d) a->b->c->d -#define ___arrow5(a, b, c, d, e) a->b->c->d->e -#define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f -#define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g -#define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h -#define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i -#define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j -#define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__) - -#define ___type(...) typeof(___arrow(__VA_ARGS__)) - -#define ___read(read_fn, dst, src_type, src, accessor) \ - read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor) - -/* "recursively" read a sequence of inner pointers using local __t var */ -#define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a); -#define ___rd_last(fn, ...) \ - ___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__)); -#define ___rd_p1(fn, ...) const void *__t; ___rd_first(fn, __VA_ARGS__) -#define ___rd_p2(fn, ...) ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___rd_p3(fn, ...) ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___rd_p4(fn, ...) ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___rd_p5(fn, ...) ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___rd_p6(fn, ...) ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___rd_p7(fn, ...) ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___rd_p8(fn, ...) ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___rd_p9(fn, ...) ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) -#define ___read_ptrs(fn, src, ...) \ - ___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__) - -#define ___core_read0(fn, fn_ptr, dst, src, a) \ - ___read(fn, dst, ___type(src), src, a); -#define ___core_readN(fn, fn_ptr, dst, src, ...) \ - ___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__)) \ - ___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \ - ___last(__VA_ARGS__)); -#define ___core_read(fn, fn_ptr, dst, src, a, ...) \ - ___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst, \ - src, a, ##__VA_ARGS__) - -/* - * BPF_CORE_READ_INTO() is a more performance-conscious variant of - * BPF_CORE_READ(), in which final field is read into user-provided storage. - * See BPF_CORE_READ() below for more details on general usage. - */ -#define BPF_CORE_READ_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_core_read, bpf_core_read, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* - * Variant of BPF_CORE_READ_INTO() for reading from user-space memory. - * - * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. - */ -#define BPF_CORE_READ_USER_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_core_read_user, bpf_core_read_user, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* Non-CO-RE variant of BPF_CORE_READ_INTO() */ -#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_probe_read, bpf_probe_read, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* Non-CO-RE variant of BPF_CORE_READ_USER_INTO(). - * - * As no CO-RE relocations are emitted, source types can be arbitrary and are - * not restricted to kernel types only. - */ -#define BPF_PROBE_READ_USER_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_probe_read_user, bpf_probe_read_user, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* - * BPF_CORE_READ_STR_INTO() does same "pointer chasing" as - * BPF_CORE_READ() for intermediate pointers, but then executes (and returns - * corresponding error code) bpf_core_read_str() for final string read. - */ -#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_core_read_str, bpf_core_read, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* - * Variant of BPF_CORE_READ_STR_INTO() for reading from user-space memory. - * - * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. - */ -#define BPF_CORE_READ_USER_STR_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_core_read_user_str, bpf_core_read_user, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */ -#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_probe_read_str, bpf_probe_read, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* - * Non-CO-RE variant of BPF_CORE_READ_USER_STR_INTO(). - * - * As no CO-RE relocations are emitted, source types can be arbitrary and are - * not restricted to kernel types only. - */ -#define BPF_PROBE_READ_USER_STR_INTO(dst, src, a, ...) ({ \ - ___core_read(bpf_probe_read_user_str, bpf_probe_read_user, \ - dst, (src), a, ##__VA_ARGS__) \ -}) - -/* - * BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially - * when there are few pointer chasing steps. - * E.g., what in non-BPF world (or in BPF w/ BCC) would be something like: - * int x = s->a.b.c->d.e->f->g; - * can be succinctly achieved using BPF_CORE_READ as: - * int x = BPF_CORE_READ(s, a.b.c, d.e, f, g); - * - * BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF - * CO-RE relocatable bpf_probe_read_kernel() wrapper) calls, logically - * equivalent to: - * 1. const void *__t = s->a.b.c; - * 2. __t = __t->d.e; - * 3. __t = __t->f; - * 4. return __t->g; - * - * Equivalence is logical, because there is a heavy type casting/preservation - * involved, as well as all the reads are happening through - * bpf_probe_read_kernel() calls using __builtin_preserve_access_index() to - * emit CO-RE relocations. - * - * N.B. Only up to 9 "field accessors" are supported, which should be more - * than enough for any practical purpose. - */ -#define BPF_CORE_READ(src, a, ...) ({ \ - ___type((src), a, ##__VA_ARGS__) __r; \ - BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \ - __r; \ -}) - -/* - * Variant of BPF_CORE_READ() for reading from user-space memory. - * - * NOTE: all the source types involved are still *kernel types* and need to - * exist in kernel (or kernel module) BTF, otherwise CO-RE relocation will - * fail. Custom user types are not relocatable with CO-RE. - * The typical situation in which BPF_CORE_READ_USER() might be used is to - * read kernel UAPI types from the user-space memory passed in as a syscall - * input argument. - */ -#define BPF_CORE_READ_USER(src, a, ...) ({ \ - ___type((src), a, ##__VA_ARGS__) __r; \ - BPF_CORE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__); \ - __r; \ -}) - -/* Non-CO-RE variant of BPF_CORE_READ() */ -#define BPF_PROBE_READ(src, a, ...) ({ \ - ___type((src), a, ##__VA_ARGS__) __r; \ - BPF_PROBE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \ - __r; \ -}) - -/* - * Non-CO-RE variant of BPF_CORE_READ_USER(). - * - * As no CO-RE relocations are emitted, source types can be arbitrary and are - * not restricted to kernel types only. - */ -#define BPF_PROBE_READ_USER(src, a, ...) ({ \ - ___type((src), a, ##__VA_ARGS__) __r; \ - BPF_PROBE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__); \ - __r; \ -}) - -#endif - diff --git a/ebpf/bpf/libbpf/bpf_endian.h b/ebpf/bpf/libbpf/bpf_endian.h deleted file mode 100644 index ec9db4feca..0000000000 --- a/ebpf/bpf/libbpf/bpf_endian.h +++ /dev/null @@ -1,99 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#ifndef __BPF_ENDIAN__ -#define __BPF_ENDIAN__ - -/* - * Isolate byte #n and put it into byte #m, for __u##b type. - * E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64: - * 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx - * 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000 - * 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn - * 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000 - */ -#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8)) - -#define ___bpf_swab16(x) ((__u16)( \ - ___bpf_mvb(x, 16, 0, 1) | \ - ___bpf_mvb(x, 16, 1, 0))) - -#define ___bpf_swab32(x) ((__u32)( \ - ___bpf_mvb(x, 32, 0, 3) | \ - ___bpf_mvb(x, 32, 1, 2) | \ - ___bpf_mvb(x, 32, 2, 1) | \ - ___bpf_mvb(x, 32, 3, 0))) - -#define ___bpf_swab64(x) ((__u64)( \ - ___bpf_mvb(x, 64, 0, 7) | \ - ___bpf_mvb(x, 64, 1, 6) | \ - ___bpf_mvb(x, 64, 2, 5) | \ - ___bpf_mvb(x, 64, 3, 4) | \ - ___bpf_mvb(x, 64, 4, 3) | \ - ___bpf_mvb(x, 64, 5, 2) | \ - ___bpf_mvb(x, 64, 6, 1) | \ - ___bpf_mvb(x, 64, 7, 0))) - -/* LLVM's BPF target selects the endianness of the CPU - * it compiles on, or the user specifies (bpfel/bpfeb), - * respectively. The used __BYTE_ORDER__ is defined by - * the compiler, we cannot rely on __BYTE_ORDER from - * libc headers, since it doesn't reflect the actual - * requested byte order. - * - * Note, LLVM's BPF target has different __builtin_bswapX() - * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE - * in bpfel and bpfeb case, which means below, that we map - * to cpu_to_be16(). We could use it unconditionally in BPF - * case, but better not rely on it, so that this header here - * can be used from application and BPF program side, which - * use different targets. - */ -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define __bpf_ntohs(x) __builtin_bswap16(x) -# define __bpf_htons(x) __builtin_bswap16(x) -# define __bpf_constant_ntohs(x) ___bpf_swab16(x) -# define __bpf_constant_htons(x) ___bpf_swab16(x) -# define __bpf_ntohl(x) __builtin_bswap32(x) -# define __bpf_htonl(x) __builtin_bswap32(x) -# define __bpf_constant_ntohl(x) ___bpf_swab32(x) -# define __bpf_constant_htonl(x) ___bpf_swab32(x) -# define __bpf_be64_to_cpu(x) __builtin_bswap64(x) -# define __bpf_cpu_to_be64(x) __builtin_bswap64(x) -# define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x) -# define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x) -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define __bpf_ntohs(x) (x) -# define __bpf_htons(x) (x) -# define __bpf_constant_ntohs(x) (x) -# define __bpf_constant_htons(x) (x) -# define __bpf_ntohl(x) (x) -# define __bpf_htonl(x) (x) -# define __bpf_constant_ntohl(x) (x) -# define __bpf_constant_htonl(x) (x) -# define __bpf_be64_to_cpu(x) (x) -# define __bpf_cpu_to_be64(x) (x) -# define __bpf_constant_be64_to_cpu(x) (x) -# define __bpf_constant_cpu_to_be64(x) (x) -#else -# error "Fix your compiler's __BYTE_ORDER__?!" -#endif - -#define bpf_htons(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_htons(x) : __bpf_htons(x)) -#define bpf_ntohs(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_ntohs(x) : __bpf_ntohs(x)) -#define bpf_htonl(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_htonl(x) : __bpf_htonl(x)) -#define bpf_ntohl(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_ntohl(x) : __bpf_ntohl(x)) -#define bpf_cpu_to_be64(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x)) -#define bpf_be64_to_cpu(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x)) - -#endif /* __BPF_ENDIAN__ */ diff --git a/ebpf/bpf/libbpf/bpf_helper_defs.h b/ebpf/bpf/libbpf/bpf_helper_defs.h deleted file mode 100644 index 3fbe7ff2a5..0000000000 --- a/ebpf/bpf/libbpf/bpf_helper_defs.h +++ /dev/null @@ -1,4139 +0,0 @@ -/* This is auto-generated file. See bpf_doc.py for details. */ - -/* Forward declarations of BPF structs */ -struct bpf_fib_lookup; -struct bpf_sk_lookup; -struct bpf_perf_event_data; -struct bpf_perf_event_value; -struct bpf_pidns_info; -struct bpf_redir_neigh; -struct bpf_sock; -struct bpf_sock_addr; -struct bpf_sock_ops; -struct bpf_sock_tuple; -struct bpf_spin_lock; -struct bpf_sysctl; -struct bpf_tcp_sock; -struct bpf_tunnel_key; -struct bpf_xfrm_state; -struct linux_binprm; -struct pt_regs; -struct sk_reuseport_md; -struct sockaddr; -struct tcphdr; -struct seq_file; -struct tcp6_sock; -struct tcp_sock; -struct tcp_timewait_sock; -struct tcp_request_sock; -struct udp6_sock; -struct unix_sock; -struct task_struct; -struct __sk_buff; -struct sk_msg_md; -struct xdp_md; -struct path; -struct btf_ptr; -struct inode; -struct socket; -struct file; -struct bpf_timer; - -/* - * bpf_map_lookup_elem - * - * Perform a lookup in *map* for an entry associated to *key*. - * - * Returns - * Map value associated to *key*, or **NULL** if no entry was - * found. - */ -static void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1; - -/* - * bpf_map_update_elem - * - * Add or update the value of the entry associated to *key* in - * *map* with *value*. *flags* is one of: - * - * **BPF_NOEXIST** - * The entry for *key* must not exist in the map. - * **BPF_EXIST** - * The entry for *key* must already exist in the map. - * **BPF_ANY** - * No condition on the existence of the entry for *key*. - * - * Flag value **BPF_NOEXIST** cannot be used for maps of types - * **BPF_MAP_TYPE_ARRAY** or **BPF_MAP_TYPE_PERCPU_ARRAY** (all - * elements always exist), the helper would return an error. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_map_update_elem)(void *map, const void *key, const void *value, __u64 flags) = (void *) 2; - -/* - * bpf_map_delete_elem - * - * Delete entry with *key* from *map*. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_map_delete_elem)(void *map, const void *key) = (void *) 3; - -/* - * bpf_probe_read - * - * For tracing programs, safely attempt to read *size* bytes from - * kernel space address *unsafe_ptr* and store the data in *dst*. - * - * Generally, use **bpf_probe_read_user**\ () or - * **bpf_probe_read_kernel**\ () instead. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_probe_read)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 4; - -/* - * bpf_ktime_get_ns - * - * Return the time elapsed since system boot, in nanoseconds. - * Does not include time the system was suspended. - * See: **clock_gettime**\ (**CLOCK_MONOTONIC**) - * - * Returns - * Current *ktime*. - */ -static __u64 (*bpf_ktime_get_ns)(void) = (void *) 5; - -/* - * bpf_trace_printk - * - * This helper is a "printk()-like" facility for debugging. It - * prints a message defined by format *fmt* (of size *fmt_size*) - * to file *\/sys/kernel/debug/tracing/trace* from DebugFS, if - * available. It can take up to three additional **u64** - * arguments (as an eBPF helpers, the total number of arguments is - * limited to five). - * - * Each time the helper is called, it appends a line to the trace. - * Lines are discarded while *\/sys/kernel/debug/tracing/trace* is - * open, use *\/sys/kernel/debug/tracing/trace_pipe* to avoid this. - * The format of the trace is customizable, and the exact output - * one will get depends on the options set in - * *\/sys/kernel/debug/tracing/trace_options* (see also the - * *README* file under the same directory). However, it usually - * defaults to something like: - * - * :: - * - * telnet-470 [001] .N.. 419421.045894: 0x00000001: - * - * In the above: - * - * * ``telnet`` is the name of the current task. - * * ``470`` is the PID of the current task. - * * ``001`` is the CPU number on which the task is - * running. - * * In ``.N..``, each character refers to a set of - * options (whether irqs are enabled, scheduling - * options, whether hard/softirqs are running, level of - * preempt_disabled respectively). **N** means that - * **TIF_NEED_RESCHED** and **PREEMPT_NEED_RESCHED** - * are set. - * * ``419421.045894`` is a timestamp. - * * ``0x00000001`` is a fake value used by BPF for the - * instruction pointer register. - * * ```` is the message formatted with - * *fmt*. - * - * The conversion specifiers supported by *fmt* are similar, but - * more limited than for printk(). They are **%d**, **%i**, - * **%u**, **%x**, **%ld**, **%li**, **%lu**, **%lx**, **%lld**, - * **%lli**, **%llu**, **%llx**, **%p**, **%s**. No modifier (size - * of field, padding with zeroes, etc.) is available, and the - * helper will return **-EINVAL** (but print nothing) if it - * encounters an unknown specifier. - * - * Also, note that **bpf_trace_printk**\ () is slow, and should - * only be used for debugging purposes. For this reason, a notice - * block (spanning several lines) is printed to kernel logs and - * states that the helper should not be used "for production use" - * the first time this helper is used (or more precisely, when - * **trace_printk**\ () buffers are allocated). For passing values - * to user space, perf events should be preferred. - * - * Returns - * The number of bytes written to the buffer, or a negative error - * in case of failure. - */ -static long (*bpf_trace_printk)(const char *fmt, __u32 fmt_size, ...) = (void *) 6; - -/* - * bpf_get_prandom_u32 - * - * Get a pseudo-random number. - * - * From a security point of view, this helper uses its own - * pseudo-random internal state, and cannot be used to infer the - * seed of other random functions in the kernel. However, it is - * essential to note that the generator used by the helper is not - * cryptographically secure. - * - * Returns - * A random 32-bit unsigned value. - */ -static __u32 (*bpf_get_prandom_u32)(void) = (void *) 7; - -/* - * bpf_get_smp_processor_id - * - * Get the SMP (symmetric multiprocessing) processor id. Note that - * all programs run with migration disabled, which means that the - * SMP processor id is stable during all the execution of the - * program. - * - * Returns - * The SMP id of the processor running the program. - */ -static __u32 (*bpf_get_smp_processor_id)(void) = (void *) 8; - -/* - * bpf_skb_store_bytes - * - * Store *len* bytes from address *from* into the packet - * associated to *skb*, at *offset*. *flags* are a combination of - * **BPF_F_RECOMPUTE_CSUM** (automatically recompute the - * checksum for the packet after storing the bytes) and - * **BPF_F_INVALIDATE_HASH** (set *skb*\ **->hash**, *skb*\ - * **->swhash** and *skb*\ **->l4hash** to 0). - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_store_bytes)(struct __sk_buff *skb, __u32 offset, const void *from, __u32 len, __u64 flags) = (void *) 9; - -/* - * bpf_l3_csum_replace - * - * Recompute the layer 3 (e.g. IP) checksum for the packet - * associated to *skb*. Computation is incremental, so the helper - * must know the former value of the header field that was - * modified (*from*), the new value of this field (*to*), and the - * number of bytes (2 or 4) for this field, stored in *size*. - * Alternatively, it is possible to store the difference between - * the previous and the new values of the header field in *to*, by - * setting *from* and *size* to 0. For both methods, *offset* - * indicates the location of the IP checksum within the packet. - * - * This helper works in combination with **bpf_csum_diff**\ (), - * which does not update the checksum in-place, but offers more - * flexibility and can handle sizes larger than 2 or 4 for the - * checksum to update. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_l3_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 from, __u64 to, __u64 size) = (void *) 10; - -/* - * bpf_l4_csum_replace - * - * Recompute the layer 4 (e.g. TCP, UDP or ICMP) checksum for the - * packet associated to *skb*. Computation is incremental, so the - * helper must know the former value of the header field that was - * modified (*from*), the new value of this field (*to*), and the - * number of bytes (2 or 4) for this field, stored on the lowest - * four bits of *flags*. Alternatively, it is possible to store - * the difference between the previous and the new values of the - * header field in *to*, by setting *from* and the four lowest - * bits of *flags* to 0. For both methods, *offset* indicates the - * location of the IP checksum within the packet. In addition to - * the size of the field, *flags* can be added (bitwise OR) actual - * flags. With **BPF_F_MARK_MANGLED_0**, a null checksum is left - * untouched (unless **BPF_F_MARK_ENFORCE** is added as well), and - * for updates resulting in a null checksum the value is set to - * **CSUM_MANGLED_0** instead. Flag **BPF_F_PSEUDO_HDR** indicates - * the checksum is to be computed against a pseudo-header. - * - * This helper works in combination with **bpf_csum_diff**\ (), - * which does not update the checksum in-place, but offers more - * flexibility and can handle sizes larger than 2 or 4 for the - * checksum to update. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_l4_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 from, __u64 to, __u64 flags) = (void *) 11; - -/* - * bpf_tail_call - * - * This special helper is used to trigger a "tail call", or in - * other words, to jump into another eBPF program. The same stack - * frame is used (but values on stack and in registers for the - * caller are not accessible to the callee). This mechanism allows - * for program chaining, either for raising the maximum number of - * available eBPF instructions, or to execute given programs in - * conditional blocks. For security reasons, there is an upper - * limit to the number of successive tail calls that can be - * performed. - * - * Upon call of this helper, the program attempts to jump into a - * program referenced at index *index* in *prog_array_map*, a - * special map of type **BPF_MAP_TYPE_PROG_ARRAY**, and passes - * *ctx*, a pointer to the context. - * - * If the call succeeds, the kernel immediately runs the first - * instruction of the new program. This is not a function call, - * and it never returns to the previous program. If the call - * fails, then the helper has no effect, and the caller continues - * to run its subsequent instructions. A call can fail if the - * destination program for the jump does not exist (i.e. *index* - * is superior to the number of entries in *prog_array_map*), or - * if the maximum number of tail calls has been reached for this - * chain of programs. This limit is defined in the kernel by the - * macro **MAX_TAIL_CALL_CNT** (not accessible to user space), - * which is currently set to 33. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_tail_call)(void *ctx, void *prog_array_map, __u32 index) = (void *) 12; - -/* - * bpf_clone_redirect - * - * Clone and redirect the packet associated to *skb* to another - * net device of index *ifindex*. Both ingress and egress - * interfaces can be used for redirection. The **BPF_F_INGRESS** - * value in *flags* is used to make the distinction (ingress path - * is selected if the flag is present, egress path otherwise). - * This is the only flag supported for now. - * - * In comparison with **bpf_redirect**\ () helper, - * **bpf_clone_redirect**\ () has the associated cost of - * duplicating the packet buffer, but this can be executed out of - * the eBPF program. Conversely, **bpf_redirect**\ () is more - * efficient, but it is handled through an action code where the - * redirection happens only after the eBPF program has returned. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_clone_redirect)(struct __sk_buff *skb, __u32 ifindex, __u64 flags) = (void *) 13; - -/* - * bpf_get_current_pid_tgid - * - * - * Returns - * A 64-bit integer containing the current tgid and pid, and - * created as such: - * *current_task*\ **->tgid << 32 \|** - * *current_task*\ **->pid**. - */ -static __u64 (*bpf_get_current_pid_tgid)(void) = (void *) 14; - -/* - * bpf_get_current_uid_gid - * - * - * Returns - * A 64-bit integer containing the current GID and UID, and - * created as such: *current_gid* **<< 32 \|** *current_uid*. - */ -static __u64 (*bpf_get_current_uid_gid)(void) = (void *) 15; - -/* - * bpf_get_current_comm - * - * Copy the **comm** attribute of the current task into *buf* of - * *size_of_buf*. The **comm** attribute contains the name of - * the executable (excluding the path) for the current task. The - * *size_of_buf* must be strictly positive. On success, the - * helper makes sure that the *buf* is NUL-terminated. On failure, - * it is filled with zeroes. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_get_current_comm)(void *buf, __u32 size_of_buf) = (void *) 16; - -/* - * bpf_get_cgroup_classid - * - * Retrieve the classid for the current task, i.e. for the net_cls - * cgroup to which *skb* belongs. - * - * This helper can be used on TC egress path, but not on ingress. - * - * The net_cls cgroup provides an interface to tag network packets - * based on a user-provided identifier for all traffic coming from - * the tasks belonging to the related cgroup. See also the related - * kernel documentation, available from the Linux sources in file - * *Documentation/admin-guide/cgroup-v1/net_cls.rst*. - * - * The Linux kernel has two versions for cgroups: there are - * cgroups v1 and cgroups v2. Both are available to users, who can - * use a mixture of them, but note that the net_cls cgroup is for - * cgroup v1 only. This makes it incompatible with BPF programs - * run on cgroups, which is a cgroup-v2-only feature (a socket can - * only hold data for one version of cgroups at a time). - * - * This helper is only available is the kernel was compiled with - * the **CONFIG_CGROUP_NET_CLASSID** configuration option set to - * "**y**" or to "**m**". - * - * Returns - * The classid, or 0 for the default unconfigured classid. - */ -static __u32 (*bpf_get_cgroup_classid)(struct __sk_buff *skb) = (void *) 17; - -/* - * bpf_skb_vlan_push - * - * Push a *vlan_tci* (VLAN tag control information) of protocol - * *vlan_proto* to the packet associated to *skb*, then update - * the checksum. Note that if *vlan_proto* is different from - * **ETH_P_8021Q** and **ETH_P_8021AD**, it is considered to - * be **ETH_P_8021Q**. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_vlan_push)(struct __sk_buff *skb, __be16 vlan_proto, __u16 vlan_tci) = (void *) 18; - -/* - * bpf_skb_vlan_pop - * - * Pop a VLAN header from the packet associated to *skb*. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_vlan_pop)(struct __sk_buff *skb) = (void *) 19; - -/* - * bpf_skb_get_tunnel_key - * - * Get tunnel metadata. This helper takes a pointer *key* to an - * empty **struct bpf_tunnel_key** of **size**, that will be - * filled with tunnel metadata for the packet associated to *skb*. - * The *flags* can be set to **BPF_F_TUNINFO_IPV6**, which - * indicates that the tunnel is based on IPv6 protocol instead of - * IPv4. - * - * The **struct bpf_tunnel_key** is an object that generalizes the - * principal parameters used by various tunneling protocols into a - * single struct. This way, it can be used to easily make a - * decision based on the contents of the encapsulation header, - * "summarized" in this struct. In particular, it holds the IP - * address of the remote end (IPv4 or IPv6, depending on the case) - * in *key*\ **->remote_ipv4** or *key*\ **->remote_ipv6**. Also, - * this struct exposes the *key*\ **->tunnel_id**, which is - * generally mapped to a VNI (Virtual Network Identifier), making - * it programmable together with the **bpf_skb_set_tunnel_key**\ - * () helper. - * - * Let's imagine that the following code is part of a program - * attached to the TC ingress interface, on one end of a GRE - * tunnel, and is supposed to filter out all messages coming from - * remote ends with IPv4 address other than 10.0.0.1: - * - * :: - * - * int ret; - * struct bpf_tunnel_key key = {}; - * - * ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); - * if (ret < 0) - * return TC_ACT_SHOT; // drop packet - * - * if (key.remote_ipv4 != 0x0a000001) - * return TC_ACT_SHOT; // drop packet - * - * return TC_ACT_OK; // accept packet - * - * This interface can also be used with all encapsulation devices - * that can operate in "collect metadata" mode: instead of having - * one network device per specific configuration, the "collect - * metadata" mode only requires a single device where the - * configuration can be extracted from this helper. - * - * This can be used together with various tunnels such as VXLan, - * Geneve, GRE or IP in IP (IPIP). - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_get_tunnel_key)(struct __sk_buff *skb, struct bpf_tunnel_key *key, __u32 size, __u64 flags) = (void *) 20; - -/* - * bpf_skb_set_tunnel_key - * - * Populate tunnel metadata for packet associated to *skb.* The - * tunnel metadata is set to the contents of *key*, of *size*. The - * *flags* can be set to a combination of the following values: - * - * **BPF_F_TUNINFO_IPV6** - * Indicate that the tunnel is based on IPv6 protocol - * instead of IPv4. - * **BPF_F_ZERO_CSUM_TX** - * For IPv4 packets, add a flag to tunnel metadata - * indicating that checksum computation should be skipped - * and checksum set to zeroes. - * **BPF_F_DONT_FRAGMENT** - * Add a flag to tunnel metadata indicating that the - * packet should not be fragmented. - * **BPF_F_SEQ_NUMBER** - * Add a flag to tunnel metadata indicating that a - * sequence number should be added to tunnel header before - * sending the packet. This flag was added for GRE - * encapsulation, but might be used with other protocols - * as well in the future. - * - * Here is a typical usage on the transmit path: - * - * :: - * - * struct bpf_tunnel_key key; - * populate key ... - * bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0); - * bpf_clone_redirect(skb, vxlan_dev_ifindex, 0); - * - * See also the description of the **bpf_skb_get_tunnel_key**\ () - * helper for additional information. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_set_tunnel_key)(struct __sk_buff *skb, struct bpf_tunnel_key *key, __u32 size, __u64 flags) = (void *) 21; - -/* - * bpf_perf_event_read - * - * Read the value of a perf event counter. This helper relies on a - * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The nature of - * the perf event counter is selected when *map* is updated with - * perf event file descriptors. The *map* is an array whose size - * is the number of available CPUs, and each cell contains a value - * relative to one CPU. The value to retrieve is indicated by - * *flags*, that contains the index of the CPU to look up, masked - * with **BPF_F_INDEX_MASK**. Alternatively, *flags* can be set to - * **BPF_F_CURRENT_CPU** to indicate that the value for the - * current CPU should be retrieved. - * - * Note that before Linux 4.13, only hardware perf event can be - * retrieved. - * - * Also, be aware that the newer helper - * **bpf_perf_event_read_value**\ () is recommended over - * **bpf_perf_event_read**\ () in general. The latter has some ABI - * quirks where error and counter value are used as a return code - * (which is wrong to do since ranges may overlap). This issue is - * fixed with **bpf_perf_event_read_value**\ (), which at the same - * time provides more features over the **bpf_perf_event_read**\ - * () interface. Please refer to the description of - * **bpf_perf_event_read_value**\ () for details. - * - * Returns - * The value of the perf event counter read from the map, or a - * negative error code in case of failure. - */ -static __u64 (*bpf_perf_event_read)(void *map, __u64 flags) = (void *) 22; - -/* - * bpf_redirect - * - * Redirect the packet to another net device of index *ifindex*. - * This helper is somewhat similar to **bpf_clone_redirect**\ - * (), except that the packet is not cloned, which provides - * increased performance. - * - * Except for XDP, both ingress and egress interfaces can be used - * for redirection. The **BPF_F_INGRESS** value in *flags* is used - * to make the distinction (ingress path is selected if the flag - * is present, egress path otherwise). Currently, XDP only - * supports redirection to the egress interface, and accepts no - * flag at all. - * - * The same effect can also be attained with the more generic - * **bpf_redirect_map**\ (), which uses a BPF map to store the - * redirect target instead of providing it directly to the helper. - * - * Returns - * For XDP, the helper returns **XDP_REDIRECT** on success or - * **XDP_ABORTED** on error. For other program types, the values - * are **TC_ACT_REDIRECT** on success or **TC_ACT_SHOT** on - * error. - */ -static long (*bpf_redirect)(__u32 ifindex, __u64 flags) = (void *) 23; - -/* - * bpf_get_route_realm - * - * Retrieve the realm or the route, that is to say the - * **tclassid** field of the destination for the *skb*. The - * identifier retrieved is a user-provided tag, similar to the - * one used with the net_cls cgroup (see description for - * **bpf_get_cgroup_classid**\ () helper), but here this tag is - * held by a route (a destination entry), not by a task. - * - * Retrieving this identifier works with the clsact TC egress hook - * (see also **tc-bpf(8)**), or alternatively on conventional - * classful egress qdiscs, but not on TC ingress path. In case of - * clsact TC egress hook, this has the advantage that, internally, - * the destination entry has not been dropped yet in the transmit - * path. Therefore, the destination entry does not need to be - * artificially held via **netif_keep_dst**\ () for a classful - * qdisc until the *skb* is freed. - * - * This helper is available only if the kernel was compiled with - * **CONFIG_IP_ROUTE_CLASSID** configuration option. - * - * Returns - * The realm of the route for the packet associated to *skb*, or 0 - * if none was found. - */ -static __u32 (*bpf_get_route_realm)(struct __sk_buff *skb) = (void *) 24; - -/* - * bpf_perf_event_output - * - * Write raw *data* blob into a special BPF perf event held by - * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf - * event must have the following attributes: **PERF_SAMPLE_RAW** - * as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and - * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. - * - * The *flags* are used to indicate the index in *map* for which - * the value must be put, masked with **BPF_F_INDEX_MASK**. - * Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU** - * to indicate that the index of the current CPU core should be - * used. - * - * The value to write, of *size*, is passed through eBPF stack and - * pointed by *data*. - * - * The context of the program *ctx* needs also be passed to the - * helper. - * - * On user space, a program willing to read the values needs to - * call **perf_event_open**\ () on the perf event (either for - * one or for all CPUs) and to store the file descriptor into the - * *map*. This must be done before the eBPF program can send data - * into it. An example is available in file - * *samples/bpf/trace_output_user.c* in the Linux kernel source - * tree (the eBPF program counterpart is in - * *samples/bpf/trace_output_kern.c*). - * - * **bpf_perf_event_output**\ () achieves better performance - * than **bpf_trace_printk**\ () for sharing data with user - * space, and is much better suitable for streaming data from eBPF - * programs. - * - * Note that this helper is not restricted to tracing use cases - * and can be used with programs attached to TC or XDP as well, - * where it allows for passing data to user space listeners. Data - * can be: - * - * * Only custom structs, - * * Only the packet payload, or - * * A combination of both. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_perf_event_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 25; - -/* - * bpf_skb_load_bytes - * - * This helper was provided as an easy way to load data from a - * packet. It can be used to load *len* bytes from *offset* from - * the packet associated to *skb*, into the buffer pointed by - * *to*. - * - * Since Linux 4.7, usage of this helper has mostly been replaced - * by "direct packet access", enabling packet data to be - * manipulated with *skb*\ **->data** and *skb*\ **->data_end** - * pointing respectively to the first byte of packet data and to - * the byte after the last byte of packet data. However, it - * remains useful if one wishes to read large quantities of data - * at once from a packet into the eBPF stack. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_load_bytes)(const void *skb, __u32 offset, void *to, __u32 len) = (void *) 26; - -/* - * bpf_get_stackid - * - * Walk a user or a kernel stack and return its id. To achieve - * this, the helper needs *ctx*, which is a pointer to the context - * on which the tracing program is executed, and a pointer to a - * *map* of type **BPF_MAP_TYPE_STACK_TRACE**. - * - * The last argument, *flags*, holds the number of stack frames to - * skip (from 0 to 255), masked with - * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set - * a combination of the following flags: - * - * **BPF_F_USER_STACK** - * Collect a user space stack instead of a kernel stack. - * **BPF_F_FAST_STACK_CMP** - * Compare stacks by hash only. - * **BPF_F_REUSE_STACKID** - * If two different stacks hash into the same *stackid*, - * discard the old one. - * - * The stack id retrieved is a 32 bit long integer handle which - * can be further combined with other data (including other stack - * ids) and used as a key into maps. This can be useful for - * generating a variety of graphs (such as flame graphs or off-cpu - * graphs). - * - * For walking a stack, this helper is an improvement over - * **bpf_probe_read**\ (), which can be used with unrolled loops - * but is not efficient and consumes a lot of eBPF instructions. - * Instead, **bpf_get_stackid**\ () can collect up to - * **PERF_MAX_STACK_DEPTH** both kernel and user frames. Note that - * this limit can be controlled with the **sysctl** program, and - * that it should be manually increased in order to profile long - * user stacks (such as stacks for Java programs). To do so, use: - * - * :: - * - * # sysctl kernel.perf_event_max_stack= - * - * Returns - * The positive or null stack id on success, or a negative error - * in case of failure. - */ -static long (*bpf_get_stackid)(void *ctx, void *map, __u64 flags) = (void *) 27; - -/* - * bpf_csum_diff - * - * Compute a checksum difference, from the raw buffer pointed by - * *from*, of length *from_size* (that must be a multiple of 4), - * towards the raw buffer pointed by *to*, of size *to_size* - * (same remark). An optional *seed* can be added to the value - * (this can be cascaded, the seed may come from a previous call - * to the helper). - * - * This is flexible enough to be used in several ways: - * - * * With *from_size* == 0, *to_size* > 0 and *seed* set to - * checksum, it can be used when pushing new data. - * * With *from_size* > 0, *to_size* == 0 and *seed* set to - * checksum, it can be used when removing data from a packet. - * * With *from_size* > 0, *to_size* > 0 and *seed* set to 0, it - * can be used to compute a diff. Note that *from_size* and - * *to_size* do not need to be equal. - * - * This helper can be used in combination with - * **bpf_l3_csum_replace**\ () and **bpf_l4_csum_replace**\ (), to - * which one can feed in the difference computed with - * **bpf_csum_diff**\ (). - * - * Returns - * The checksum result, or a negative error code in case of - * failure. - */ -static __s64 (*bpf_csum_diff)(__be32 *from, __u32 from_size, __be32 *to, __u32 to_size, __wsum seed) = (void *) 28; - -/* - * bpf_skb_get_tunnel_opt - * - * Retrieve tunnel options metadata for the packet associated to - * *skb*, and store the raw tunnel option data to the buffer *opt* - * of *size*. - * - * This helper can be used with encapsulation devices that can - * operate in "collect metadata" mode (please refer to the related - * note in the description of **bpf_skb_get_tunnel_key**\ () for - * more details). A particular example where this can be used is - * in combination with the Geneve encapsulation protocol, where it - * allows for pushing (with **bpf_skb_get_tunnel_opt**\ () helper) - * and retrieving arbitrary TLVs (Type-Length-Value headers) from - * the eBPF program. This allows for full customization of these - * headers. - * - * Returns - * The size of the option data retrieved. - */ -static long (*bpf_skb_get_tunnel_opt)(struct __sk_buff *skb, void *opt, __u32 size) = (void *) 29; - -/* - * bpf_skb_set_tunnel_opt - * - * Set tunnel options metadata for the packet associated to *skb* - * to the option data contained in the raw buffer *opt* of *size*. - * - * See also the description of the **bpf_skb_get_tunnel_opt**\ () - * helper for additional information. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_set_tunnel_opt)(struct __sk_buff *skb, void *opt, __u32 size) = (void *) 30; - -/* - * bpf_skb_change_proto - * - * Change the protocol of the *skb* to *proto*. Currently - * supported are transition from IPv4 to IPv6, and from IPv6 to - * IPv4. The helper takes care of the groundwork for the - * transition, including resizing the socket buffer. The eBPF - * program is expected to fill the new headers, if any, via - * **skb_store_bytes**\ () and to recompute the checksums with - * **bpf_l3_csum_replace**\ () and **bpf_l4_csum_replace**\ - * (). The main case for this helper is to perform NAT64 - * operations out of an eBPF program. - * - * Internally, the GSO type is marked as dodgy so that headers are - * checked and segments are recalculated by the GSO/GRO engine. - * The size for GSO target is adapted as well. - * - * All values for *flags* are reserved for future usage, and must - * be left at zero. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_change_proto)(struct __sk_buff *skb, __be16 proto, __u64 flags) = (void *) 31; - -/* - * bpf_skb_change_type - * - * Change the packet type for the packet associated to *skb*. This - * comes down to setting *skb*\ **->pkt_type** to *type*, except - * the eBPF program does not have a write access to *skb*\ - * **->pkt_type** beside this helper. Using a helper here allows - * for graceful handling of errors. - * - * The major use case is to change incoming *skb*s to - * **PACKET_HOST** in a programmatic way instead of having to - * recirculate via **redirect**\ (..., **BPF_F_INGRESS**), for - * example. - * - * Note that *type* only allows certain values. At this time, they - * are: - * - * **PACKET_HOST** - * Packet is for us. - * **PACKET_BROADCAST** - * Send packet to all. - * **PACKET_MULTICAST** - * Send packet to group. - * **PACKET_OTHERHOST** - * Send packet to someone else. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_change_type)(struct __sk_buff *skb, __u32 type) = (void *) 32; - -/* - * bpf_skb_under_cgroup - * - * Check whether *skb* is a descendant of the cgroup2 held by - * *map* of type **BPF_MAP_TYPE_CGROUP_ARRAY**, at *index*. - * - * Returns - * The return value depends on the result of the test, and can be: - * - * * 0, if the *skb* failed the cgroup2 descendant test. - * * 1, if the *skb* succeeded the cgroup2 descendant test. - * * A negative error code, if an error occurred. - */ -static long (*bpf_skb_under_cgroup)(struct __sk_buff *skb, void *map, __u32 index) = (void *) 33; - -/* - * bpf_get_hash_recalc - * - * Retrieve the hash of the packet, *skb*\ **->hash**. If it is - * not set, in particular if the hash was cleared due to mangling, - * recompute this hash. Later accesses to the hash can be done - * directly with *skb*\ **->hash**. - * - * Calling **bpf_set_hash_invalid**\ (), changing a packet - * prototype with **bpf_skb_change_proto**\ (), or calling - * **bpf_skb_store_bytes**\ () with the - * **BPF_F_INVALIDATE_HASH** are actions susceptible to clear - * the hash and to trigger a new computation for the next call to - * **bpf_get_hash_recalc**\ (). - * - * Returns - * The 32-bit hash. - */ -static __u32 (*bpf_get_hash_recalc)(struct __sk_buff *skb) = (void *) 34; - -/* - * bpf_get_current_task - * - * - * Returns - * A pointer to the current task struct. - */ -static __u64 (*bpf_get_current_task)(void) = (void *) 35; - -/* - * bpf_probe_write_user - * - * Attempt in a safe way to write *len* bytes from the buffer - * *src* to *dst* in memory. It only works for threads that are in - * user context, and *dst* must be a valid user space address. - * - * This helper should not be used to implement any kind of - * security mechanism because of TOC-TOU attacks, but rather to - * debug, divert, and manipulate execution of semi-cooperative - * processes. - * - * Keep in mind that this feature is meant for experiments, and it - * has a risk of crashing the system and running programs. - * Therefore, when an eBPF program using this helper is attached, - * a warning including PID and process name is printed to kernel - * logs. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_probe_write_user)(void *dst, const void *src, __u32 len) = (void *) 36; - -/* - * bpf_current_task_under_cgroup - * - * Check whether the probe is being run is the context of a given - * subset of the cgroup2 hierarchy. The cgroup2 to test is held by - * *map* of type **BPF_MAP_TYPE_CGROUP_ARRAY**, at *index*. - * - * Returns - * The return value depends on the result of the test, and can be: - * - * * 0, if current task belongs to the cgroup2. - * * 1, if current task does not belong to the cgroup2. - * * A negative error code, if an error occurred. - */ -static long (*bpf_current_task_under_cgroup)(void *map, __u32 index) = (void *) 37; - -/* - * bpf_skb_change_tail - * - * Resize (trim or grow) the packet associated to *skb* to the - * new *len*. The *flags* are reserved for future usage, and must - * be left at zero. - * - * The basic idea is that the helper performs the needed work to - * change the size of the packet, then the eBPF program rewrites - * the rest via helpers like **bpf_skb_store_bytes**\ (), - * **bpf_l3_csum_replace**\ (), **bpf_l3_csum_replace**\ () - * and others. This helper is a slow path utility intended for - * replies with control messages. And because it is targeted for - * slow path, the helper itself can afford to be slow: it - * implicitly linearizes, unclones and drops offloads from the - * *skb*. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_change_tail)(struct __sk_buff *skb, __u32 len, __u64 flags) = (void *) 38; - -/* - * bpf_skb_pull_data - * - * Pull in non-linear data in case the *skb* is non-linear and not - * all of *len* are part of the linear section. Make *len* bytes - * from *skb* readable and writable. If a zero value is passed for - * *len*, then the whole length of the *skb* is pulled. - * - * This helper is only needed for reading and writing with direct - * packet access. - * - * For direct packet access, testing that offsets to access - * are within packet boundaries (test on *skb*\ **->data_end**) is - * susceptible to fail if offsets are invalid, or if the requested - * data is in non-linear parts of the *skb*. On failure the - * program can just bail out, or in the case of a non-linear - * buffer, use a helper to make the data available. The - * **bpf_skb_load_bytes**\ () helper is a first solution to access - * the data. Another one consists in using **bpf_skb_pull_data** - * to pull in once the non-linear parts, then retesting and - * eventually access the data. - * - * At the same time, this also makes sure the *skb* is uncloned, - * which is a necessary condition for direct write. As this needs - * to be an invariant for the write part only, the verifier - * detects writes and adds a prologue that is calling - * **bpf_skb_pull_data()** to effectively unclone the *skb* from - * the very beginning in case it is indeed cloned. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_pull_data)(struct __sk_buff *skb, __u32 len) = (void *) 39; - -/* - * bpf_csum_update - * - * Add the checksum *csum* into *skb*\ **->csum** in case the - * driver has supplied a checksum for the entire packet into that - * field. Return an error otherwise. This helper is intended to be - * used in combination with **bpf_csum_diff**\ (), in particular - * when the checksum needs to be updated after data has been - * written into the packet through direct packet access. - * - * Returns - * The checksum on success, or a negative error code in case of - * failure. - */ -static __s64 (*bpf_csum_update)(struct __sk_buff *skb, __wsum csum) = (void *) 40; - -/* - * bpf_set_hash_invalid - * - * Invalidate the current *skb*\ **->hash**. It can be used after - * mangling on headers through direct packet access, in order to - * indicate that the hash is outdated and to trigger a - * recalculation the next time the kernel tries to access this - * hash or when the **bpf_get_hash_recalc**\ () helper is called. - * - */ -static void (*bpf_set_hash_invalid)(struct __sk_buff *skb) = (void *) 41; - -/* - * bpf_get_numa_node_id - * - * Return the id of the current NUMA node. The primary use case - * for this helper is the selection of sockets for the local NUMA - * node, when the program is attached to sockets using the - * **SO_ATTACH_REUSEPORT_EBPF** option (see also **socket(7)**), - * but the helper is also available to other eBPF program types, - * similarly to **bpf_get_smp_processor_id**\ (). - * - * Returns - * The id of current NUMA node. - */ -static long (*bpf_get_numa_node_id)(void) = (void *) 42; - -/* - * bpf_skb_change_head - * - * Grows headroom of packet associated to *skb* and adjusts the - * offset of the MAC header accordingly, adding *len* bytes of - * space. It automatically extends and reallocates memory as - * required. - * - * This helper can be used on a layer 3 *skb* to push a MAC header - * for redirection into a layer 2 device. - * - * All values for *flags* are reserved for future usage, and must - * be left at zero. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_change_head)(struct __sk_buff *skb, __u32 len, __u64 flags) = (void *) 43; - -/* - * bpf_xdp_adjust_head - * - * Adjust (move) *xdp_md*\ **->data** by *delta* bytes. Note that - * it is possible to use a negative value for *delta*. This helper - * can be used to prepare the packet for pushing or popping - * headers. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_xdp_adjust_head)(struct xdp_md *xdp_md, int delta) = (void *) 44; - -/* - * bpf_probe_read_str - * - * Copy a NUL terminated string from an unsafe kernel address - * *unsafe_ptr* to *dst*. See **bpf_probe_read_kernel_str**\ () for - * more details. - * - * Generally, use **bpf_probe_read_user_str**\ () or - * **bpf_probe_read_kernel_str**\ () instead. - * - * Returns - * On success, the strictly positive length of the string, - * including the trailing NUL character. On error, a negative - * value. - */ -static long (*bpf_probe_read_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 45; - -/* - * bpf_get_socket_cookie - * - * If the **struct sk_buff** pointed by *skb* has a known socket, - * retrieve the cookie (generated by the kernel) of this socket. - * If no cookie has been set yet, generate a new cookie. Once - * generated, the socket cookie remains stable for the life of the - * socket. This helper can be useful for monitoring per socket - * networking traffic statistics as it provides a global socket - * identifier that can be assumed unique. - * - * Returns - * A 8-byte long unique number on success, or 0 if the socket - * field is missing inside *skb*. - */ -static __u64 (*bpf_get_socket_cookie)(void *ctx) = (void *) 46; - -/* - * bpf_get_socket_uid - * - * - * Returns - * The owner UID of the socket associated to *skb*. If the socket - * is **NULL**, or if it is not a full socket (i.e. if it is a - * time-wait or a request socket instead), **overflowuid** value - * is returned (note that **overflowuid** might also be the actual - * UID value for the socket). - */ -static __u32 (*bpf_get_socket_uid)(struct __sk_buff *skb) = (void *) 47; - -/* - * bpf_set_hash - * - * Set the full hash for *skb* (set the field *skb*\ **->hash**) - * to value *hash*. - * - * Returns - * 0 - */ -static long (*bpf_set_hash)(struct __sk_buff *skb, __u32 hash) = (void *) 48; - -/* - * bpf_setsockopt - * - * Emulate a call to **setsockopt()** on the socket associated to - * *bpf_socket*, which must be a full socket. The *level* at - * which the option resides and the name *optname* of the option - * must be specified, see **setsockopt(2)** for more information. - * The option value of length *optlen* is pointed by *optval*. - * - * *bpf_socket* should be one of the following: - * - * * **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**. - * * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT** - * and **BPF_CGROUP_INET6_CONNECT**. - * - * This helper actually implements a subset of **setsockopt()**. - * It supports the following *level*\ s: - * - * * **SOL_SOCKET**, which supports the following *optname*\ s: - * **SO_RCVBUF**, **SO_SNDBUF**, **SO_MAX_PACING_RATE**, - * **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**, - * **SO_BINDTODEVICE**, **SO_KEEPALIVE**. - * * **IPPROTO_TCP**, which supports the following *optname*\ s: - * **TCP_CONGESTION**, **TCP_BPF_IW**, - * **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**, - * **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**, - * **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**. - * * **IPPROTO_IP**, which supports *optname* **IP_TOS**. - * * **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_setsockopt)(void *bpf_socket, int level, int optname, void *optval, int optlen) = (void *) 49; - -/* - * bpf_skb_adjust_room - * - * Grow or shrink the room for data in the packet associated to - * *skb* by *len_diff*, and according to the selected *mode*. - * - * By default, the helper will reset any offloaded checksum - * indicator of the skb to CHECKSUM_NONE. This can be avoided - * by the following flag: - * - * * **BPF_F_ADJ_ROOM_NO_CSUM_RESET**: Do not reset offloaded - * checksum data of the skb to CHECKSUM_NONE. - * - * There are two supported modes at this time: - * - * * **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer - * (room space is added or removed below the layer 2 header). - * - * * **BPF_ADJ_ROOM_NET**: Adjust room at the network layer - * (room space is added or removed below the layer 3 header). - * - * The following flags are supported at this time: - * - * * **BPF_F_ADJ_ROOM_FIXED_GSO**: Do not adjust gso_size. - * Adjusting mss in this way is not allowed for datagrams. - * - * * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4**, - * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6**: - * Any new space is reserved to hold a tunnel header. - * Configure skb offsets and other fields accordingly. - * - * * **BPF_F_ADJ_ROOM_ENCAP_L4_GRE**, - * **BPF_F_ADJ_ROOM_ENCAP_L4_UDP**: - * Use with ENCAP_L3 flags to further specify the tunnel type. - * - * * **BPF_F_ADJ_ROOM_ENCAP_L2**\ (*len*): - * Use with ENCAP_L3/L4 flags to further specify the tunnel - * type; *len* is the length of the inner MAC header. - * - * * **BPF_F_ADJ_ROOM_ENCAP_L2_ETH**: - * Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the - * L2 type as Ethernet. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_adjust_room)(struct __sk_buff *skb, __s32 len_diff, __u32 mode, __u64 flags) = (void *) 50; - -/* - * bpf_redirect_map - * - * Redirect the packet to the endpoint referenced by *map* at - * index *key*. Depending on its type, this *map* can contain - * references to net devices (for forwarding packets through other - * ports), or to CPUs (for redirecting XDP frames to another CPU; - * but this is only implemented for native XDP (with driver - * support) as of this writing). - * - * The lower two bits of *flags* are used as the return code if - * the map lookup fails. This is so that the return value can be - * one of the XDP program return codes up to **XDP_TX**, as chosen - * by the caller. The higher bits of *flags* can be set to - * BPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below. - * - * With BPF_F_BROADCAST the packet will be broadcasted to all the - * interfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress - * interface will be excluded when do broadcasting. - * - * See also **bpf_redirect**\ (), which only supports redirecting - * to an ifindex, but doesn't require a map to do so. - * - * Returns - * **XDP_REDIRECT** on success, or the value of the two lower bits - * of the *flags* argument on error. - */ -static long (*bpf_redirect_map)(void *map, __u32 key, __u64 flags) = (void *) 51; - -/* - * bpf_sk_redirect_map - * - * Redirect the packet to the socket referenced by *map* (of type - * **BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and - * egress interfaces can be used for redirection. The - * **BPF_F_INGRESS** value in *flags* is used to make the - * distinction (ingress path is selected if the flag is present, - * egress path otherwise). This is the only flag supported for now. - * - * Returns - * **SK_PASS** on success, or **SK_DROP** on error. - */ -static long (*bpf_sk_redirect_map)(struct __sk_buff *skb, void *map, __u32 key, __u64 flags) = (void *) 52; - -/* - * bpf_sock_map_update - * - * Add an entry to, or update a *map* referencing sockets. The - * *skops* is used as a new value for the entry associated to - * *key*. *flags* is one of: - * - * **BPF_NOEXIST** - * The entry for *key* must not exist in the map. - * **BPF_EXIST** - * The entry for *key* must already exist in the map. - * **BPF_ANY** - * No condition on the existence of the entry for *key*. - * - * If the *map* has eBPF programs (parser and verdict), those will - * be inherited by the socket being added. If the socket is - * already attached to eBPF programs, this results in an error. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_sock_map_update)(struct bpf_sock_ops *skops, void *map, void *key, __u64 flags) = (void *) 53; - -/* - * bpf_xdp_adjust_meta - * - * Adjust the address pointed by *xdp_md*\ **->data_meta** by - * *delta* (which can be positive or negative). Note that this - * operation modifies the address stored in *xdp_md*\ **->data**, - * so the latter must be loaded only after the helper has been - * called. - * - * The use of *xdp_md*\ **->data_meta** is optional and programs - * are not required to use it. The rationale is that when the - * packet is processed with XDP (e.g. as DoS filter), it is - * possible to push further meta data along with it before passing - * to the stack, and to give the guarantee that an ingress eBPF - * program attached as a TC classifier on the same device can pick - * this up for further post-processing. Since TC works with socket - * buffers, it remains possible to set from XDP the **mark** or - * **priority** pointers, or other pointers for the socket buffer. - * Having this scratch space generic and programmable allows for - * more flexibility as the user is free to store whatever meta - * data they need. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_xdp_adjust_meta)(struct xdp_md *xdp_md, int delta) = (void *) 54; - -/* - * bpf_perf_event_read_value - * - * Read the value of a perf event counter, and store it into *buf* - * of size *buf_size*. This helper relies on a *map* of type - * **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The nature of the perf event - * counter is selected when *map* is updated with perf event file - * descriptors. The *map* is an array whose size is the number of - * available CPUs, and each cell contains a value relative to one - * CPU. The value to retrieve is indicated by *flags*, that - * contains the index of the CPU to look up, masked with - * **BPF_F_INDEX_MASK**. Alternatively, *flags* can be set to - * **BPF_F_CURRENT_CPU** to indicate that the value for the - * current CPU should be retrieved. - * - * This helper behaves in a way close to - * **bpf_perf_event_read**\ () helper, save that instead of - * just returning the value observed, it fills the *buf* - * structure. This allows for additional data to be retrieved: in - * particular, the enabled and running times (in *buf*\ - * **->enabled** and *buf*\ **->running**, respectively) are - * copied. In general, **bpf_perf_event_read_value**\ () is - * recommended over **bpf_perf_event_read**\ (), which has some - * ABI issues and provides fewer functionalities. - * - * These values are interesting, because hardware PMU (Performance - * Monitoring Unit) counters are limited resources. When there are - * more PMU based perf events opened than available counters, - * kernel will multiplex these events so each event gets certain - * percentage (but not all) of the PMU time. In case that - * multiplexing happens, the number of samples or counter value - * will not reflect the case compared to when no multiplexing - * occurs. This makes comparison between different runs difficult. - * Typically, the counter value should be normalized before - * comparing to other experiments. The usual normalization is done - * as follows. - * - * :: - * - * normalized_counter = counter * t_enabled / t_running - * - * Where t_enabled is the time enabled for event and t_running is - * the time running for event since last normalization. The - * enabled and running times are accumulated since the perf event - * open. To achieve scaling factor between two invocations of an - * eBPF program, users can use CPU id as the key (which is - * typical for perf array usage model) to remember the previous - * value and do the calculation inside the eBPF program. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_perf_event_read_value)(void *map, __u64 flags, struct bpf_perf_event_value *buf, __u32 buf_size) = (void *) 55; - -/* - * bpf_perf_prog_read_value - * - * For en eBPF program attached to a perf event, retrieve the - * value of the event counter associated to *ctx* and store it in - * the structure pointed by *buf* and of size *buf_size*. Enabled - * and running times are also stored in the structure (see - * description of helper **bpf_perf_event_read_value**\ () for - * more details). - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_perf_prog_read_value)(struct bpf_perf_event_data *ctx, struct bpf_perf_event_value *buf, __u32 buf_size) = (void *) 56; - -/* - * bpf_getsockopt - * - * Emulate a call to **getsockopt()** on the socket associated to - * *bpf_socket*, which must be a full socket. The *level* at - * which the option resides and the name *optname* of the option - * must be specified, see **getsockopt(2)** for more information. - * The retrieved value is stored in the structure pointed by - * *opval* and of length *optlen*. - * - * *bpf_socket* should be one of the following: - * - * * **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**. - * * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT** - * and **BPF_CGROUP_INET6_CONNECT**. - * - * This helper actually implements a subset of **getsockopt()**. - * It supports the following *level*\ s: - * - * * **IPPROTO_TCP**, which supports *optname* - * **TCP_CONGESTION**. - * * **IPPROTO_IP**, which supports *optname* **IP_TOS**. - * * **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_getsockopt)(void *bpf_socket, int level, int optname, void *optval, int optlen) = (void *) 57; - -/* - * bpf_override_return - * - * Used for error injection, this helper uses kprobes to override - * the return value of the probed function, and to set it to *rc*. - * The first argument is the context *regs* on which the kprobe - * works. - * - * This helper works by setting the PC (program counter) - * to an override function which is run in place of the original - * probed function. This means the probed function is not run at - * all. The replacement function just returns with the required - * value. - * - * This helper has security implications, and thus is subject to - * restrictions. It is only available if the kernel was compiled - * with the **CONFIG_BPF_KPROBE_OVERRIDE** configuration - * option, and in this case it only works on functions tagged with - * **ALLOW_ERROR_INJECTION** in the kernel code. - * - * Also, the helper is only available for the architectures having - * the CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing, - * x86 architecture is the only one to support this feature. - * - * Returns - * 0 - */ -static long (*bpf_override_return)(struct pt_regs *regs, __u64 rc) = (void *) 58; - -/* - * bpf_sock_ops_cb_flags_set - * - * Attempt to set the value of the **bpf_sock_ops_cb_flags** field - * for the full TCP socket associated to *bpf_sock_ops* to - * *argval*. - * - * The primary use of this field is to determine if there should - * be calls to eBPF programs of type - * **BPF_PROG_TYPE_SOCK_OPS** at various points in the TCP - * code. A program of the same type can change its value, per - * connection and as necessary, when the connection is - * established. This field is directly accessible for reading, but - * this helper must be used for updates in order to return an - * error if an eBPF program tries to set a callback that is not - * supported in the current kernel. - * - * *argval* is a flag array which can combine these flags: - * - * * **BPF_SOCK_OPS_RTO_CB_FLAG** (retransmission time out) - * * **BPF_SOCK_OPS_RETRANS_CB_FLAG** (retransmission) - * * **BPF_SOCK_OPS_STATE_CB_FLAG** (TCP state change) - * * **BPF_SOCK_OPS_RTT_CB_FLAG** (every RTT) - * - * Therefore, this function can be used to clear a callback flag by - * setting the appropriate bit to zero. e.g. to disable the RTO - * callback: - * - * **bpf_sock_ops_cb_flags_set(bpf_sock,** - * **bpf_sock->bpf_sock_ops_cb_flags & ~BPF_SOCK_OPS_RTO_CB_FLAG)** - * - * Here are some examples of where one could call such eBPF - * program: - * - * * When RTO fires. - * * When a packet is retransmitted. - * * When the connection terminates. - * * When a packet is sent. - * * When a packet is received. - * - * Returns - * Code **-EINVAL** if the socket is not a full TCP socket; - * otherwise, a positive number containing the bits that could not - * be set is returned (which comes down to 0 if all bits were set - * as required). - */ -static long (*bpf_sock_ops_cb_flags_set)(struct bpf_sock_ops *bpf_sock, int argval) = (void *) 59; - -/* - * bpf_msg_redirect_map - * - * This helper is used in programs implementing policies at the - * socket level. If the message *msg* is allowed to pass (i.e. if - * the verdict eBPF program returns **SK_PASS**), redirect it to - * the socket referenced by *map* (of type - * **BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and - * egress interfaces can be used for redirection. The - * **BPF_F_INGRESS** value in *flags* is used to make the - * distinction (ingress path is selected if the flag is present, - * egress path otherwise). This is the only flag supported for now. - * - * Returns - * **SK_PASS** on success, or **SK_DROP** on error. - */ -static long (*bpf_msg_redirect_map)(struct sk_msg_md *msg, void *map, __u32 key, __u64 flags) = (void *) 60; - -/* - * bpf_msg_apply_bytes - * - * For socket policies, apply the verdict of the eBPF program to - * the next *bytes* (number of bytes) of message *msg*. - * - * For example, this helper can be used in the following cases: - * - * * A single **sendmsg**\ () or **sendfile**\ () system call - * contains multiple logical messages that the eBPF program is - * supposed to read and for which it should apply a verdict. - * * An eBPF program only cares to read the first *bytes* of a - * *msg*. If the message has a large payload, then setting up - * and calling the eBPF program repeatedly for all bytes, even - * though the verdict is already known, would create unnecessary - * overhead. - * - * When called from within an eBPF program, the helper sets a - * counter internal to the BPF infrastructure, that is used to - * apply the last verdict to the next *bytes*. If *bytes* is - * smaller than the current data being processed from a - * **sendmsg**\ () or **sendfile**\ () system call, the first - * *bytes* will be sent and the eBPF program will be re-run with - * the pointer for start of data pointing to byte number *bytes* - * **+ 1**. If *bytes* is larger than the current data being - * processed, then the eBPF verdict will be applied to multiple - * **sendmsg**\ () or **sendfile**\ () calls until *bytes* are - * consumed. - * - * Note that if a socket closes with the internal counter holding - * a non-zero value, this is not a problem because data is not - * being buffered for *bytes* and is sent as it is received. - * - * Returns - * 0 - */ -static long (*bpf_msg_apply_bytes)(struct sk_msg_md *msg, __u32 bytes) = (void *) 61; - -/* - * bpf_msg_cork_bytes - * - * For socket policies, prevent the execution of the verdict eBPF - * program for message *msg* until *bytes* (byte number) have been - * accumulated. - * - * This can be used when one needs a specific number of bytes - * before a verdict can be assigned, even if the data spans - * multiple **sendmsg**\ () or **sendfile**\ () calls. The extreme - * case would be a user calling **sendmsg**\ () repeatedly with - * 1-byte long message segments. Obviously, this is bad for - * performance, but it is still valid. If the eBPF program needs - * *bytes* bytes to validate a header, this helper can be used to - * prevent the eBPF program to be called again until *bytes* have - * been accumulated. - * - * Returns - * 0 - */ -static long (*bpf_msg_cork_bytes)(struct sk_msg_md *msg, __u32 bytes) = (void *) 62; - -/* - * bpf_msg_pull_data - * - * For socket policies, pull in non-linear data from user space - * for *msg* and set pointers *msg*\ **->data** and *msg*\ - * **->data_end** to *start* and *end* bytes offsets into *msg*, - * respectively. - * - * If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a - * *msg* it can only parse data that the (**data**, **data_end**) - * pointers have already consumed. For **sendmsg**\ () hooks this - * is likely the first scatterlist element. But for calls relying - * on the **sendpage** handler (e.g. **sendfile**\ ()) this will - * be the range (**0**, **0**) because the data is shared with - * user space and by default the objective is to avoid allowing - * user space to modify data while (or after) eBPF verdict is - * being decided. This helper can be used to pull in data and to - * set the start and end pointer to given values. Data will be - * copied if necessary (i.e. if data was not linear and if start - * and end pointers do not point to the same chunk). - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * All values for *flags* are reserved for future usage, and must - * be left at zero. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_msg_pull_data)(struct sk_msg_md *msg, __u32 start, __u32 end, __u64 flags) = (void *) 63; - -/* - * bpf_bind - * - * Bind the socket associated to *ctx* to the address pointed by - * *addr*, of length *addr_len*. This allows for making outgoing - * connection from the desired IP address, which can be useful for - * example when all processes inside a cgroup should use one - * single IP address on a host that has multiple IP configured. - * - * This helper works for IPv4 and IPv6, TCP and UDP sockets. The - * domain (*addr*\ **->sa_family**) must be **AF_INET** (or - * **AF_INET6**). It's advised to pass zero port (**sin_port** - * or **sin6_port**) which triggers IP_BIND_ADDRESS_NO_PORT-like - * behavior and lets the kernel efficiently pick up an unused - * port as long as 4-tuple is unique. Passing non-zero port might - * lead to degraded performance. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_bind)(struct bpf_sock_addr *ctx, struct sockaddr *addr, int addr_len) = (void *) 64; - -/* - * bpf_xdp_adjust_tail - * - * Adjust (move) *xdp_md*\ **->data_end** by *delta* bytes. It is - * possible to both shrink and grow the packet tail. - * Shrink done via *delta* being a negative integer. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_xdp_adjust_tail)(struct xdp_md *xdp_md, int delta) = (void *) 65; - -/* - * bpf_skb_get_xfrm_state - * - * Retrieve the XFRM state (IP transform framework, see also - * **ip-xfrm(8)**) at *index* in XFRM "security path" for *skb*. - * - * The retrieved value is stored in the **struct bpf_xfrm_state** - * pointed by *xfrm_state* and of length *size*. - * - * All values for *flags* are reserved for future usage, and must - * be left at zero. - * - * This helper is available only if the kernel was compiled with - * **CONFIG_XFRM** configuration option. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_get_xfrm_state)(struct __sk_buff *skb, __u32 index, struct bpf_xfrm_state *xfrm_state, __u32 size, __u64 flags) = (void *) 66; - -/* - * bpf_get_stack - * - * Return a user or a kernel stack in bpf program provided buffer. - * To achieve this, the helper needs *ctx*, which is a pointer - * to the context on which the tracing program is executed. - * To store the stacktrace, the bpf program provides *buf* with - * a nonnegative *size*. - * - * The last argument, *flags*, holds the number of stack frames to - * skip (from 0 to 255), masked with - * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set - * the following flags: - * - * **BPF_F_USER_STACK** - * Collect a user space stack instead of a kernel stack. - * **BPF_F_USER_BUILD_ID** - * Collect buildid+offset instead of ips for user stack, - * only valid if **BPF_F_USER_STACK** is also specified. - * - * **bpf_get_stack**\ () can collect up to - * **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject - * to sufficient large buffer size. Note that - * this limit can be controlled with the **sysctl** program, and - * that it should be manually increased in order to profile long - * user stacks (such as stacks for Java programs). To do so, use: - * - * :: - * - * # sysctl kernel.perf_event_max_stack= - * - * Returns - * A non-negative value equal to or less than *size* on success, - * or a negative error in case of failure. - */ -static long (*bpf_get_stack)(void *ctx, void *buf, __u32 size, __u64 flags) = (void *) 67; - -/* - * bpf_skb_load_bytes_relative - * - * This helper is similar to **bpf_skb_load_bytes**\ () in that - * it provides an easy way to load *len* bytes from *offset* - * from the packet associated to *skb*, into the buffer pointed - * by *to*. The difference to **bpf_skb_load_bytes**\ () is that - * a fifth argument *start_header* exists in order to select a - * base offset to start from. *start_header* can be one of: - * - * **BPF_HDR_START_MAC** - * Base offset to load data from is *skb*'s mac header. - * **BPF_HDR_START_NET** - * Base offset to load data from is *skb*'s network header. - * - * In general, "direct packet access" is the preferred method to - * access packet data, however, this helper is in particular useful - * in socket filters where *skb*\ **->data** does not always point - * to the start of the mac header and where "direct packet access" - * is not available. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_load_bytes_relative)(const void *skb, __u32 offset, void *to, __u32 len, __u32 start_header) = (void *) 68; - -/* - * bpf_fib_lookup - * - * Do FIB lookup in kernel tables using parameters in *params*. - * If lookup is successful and result shows packet is to be - * forwarded, the neighbor tables are searched for the nexthop. - * If successful (ie., FIB lookup shows forwarding and nexthop - * is resolved), the nexthop address is returned in ipv4_dst - * or ipv6_dst based on family, smac is set to mac address of - * egress device, dmac is set to nexthop mac address, rt_metric - * is set to metric from route (IPv4/IPv6 only), and ifindex - * is set to the device index of the nexthop from the FIB lookup. - * - * *plen* argument is the size of the passed in struct. - * *flags* argument can be a combination of one or more of the - * following values: - * - * **BPF_FIB_LOOKUP_DIRECT** - * Do a direct table lookup vs full lookup using FIB - * rules. - * **BPF_FIB_LOOKUP_OUTPUT** - * Perform lookup from an egress perspective (default is - * ingress). - * - * *ctx* is either **struct xdp_md** for XDP programs or - * **struct sk_buff** tc cls_act programs. - * - * Returns - * * < 0 if any input argument is invalid - * * 0 on success (packet is forwarded, nexthop neighbor exists) - * * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the - * packet is not forwarded or needs assist from full stack - * - * If lookup fails with BPF_FIB_LKUP_RET_FRAG_NEEDED, then the MTU - * was exceeded and output params->mtu_result contains the MTU. - */ -static long (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, int plen, __u32 flags) = (void *) 69; - -/* - * bpf_sock_hash_update - * - * Add an entry to, or update a sockhash *map* referencing sockets. - * The *skops* is used as a new value for the entry associated to - * *key*. *flags* is one of: - * - * **BPF_NOEXIST** - * The entry for *key* must not exist in the map. - * **BPF_EXIST** - * The entry for *key* must already exist in the map. - * **BPF_ANY** - * No condition on the existence of the entry for *key*. - * - * If the *map* has eBPF programs (parser and verdict), those will - * be inherited by the socket being added. If the socket is - * already attached to eBPF programs, this results in an error. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_sock_hash_update)(struct bpf_sock_ops *skops, void *map, void *key, __u64 flags) = (void *) 70; - -/* - * bpf_msg_redirect_hash - * - * This helper is used in programs implementing policies at the - * socket level. If the message *msg* is allowed to pass (i.e. if - * the verdict eBPF program returns **SK_PASS**), redirect it to - * the socket referenced by *map* (of type - * **BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and - * egress interfaces can be used for redirection. The - * **BPF_F_INGRESS** value in *flags* is used to make the - * distinction (ingress path is selected if the flag is present, - * egress path otherwise). This is the only flag supported for now. - * - * Returns - * **SK_PASS** on success, or **SK_DROP** on error. - */ -static long (*bpf_msg_redirect_hash)(struct sk_msg_md *msg, void *map, void *key, __u64 flags) = (void *) 71; - -/* - * bpf_sk_redirect_hash - * - * This helper is used in programs implementing policies at the - * skb socket level. If the sk_buff *skb* is allowed to pass (i.e. - * if the verdict eBPF program returns **SK_PASS**), redirect it - * to the socket referenced by *map* (of type - * **BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and - * egress interfaces can be used for redirection. The - * **BPF_F_INGRESS** value in *flags* is used to make the - * distinction (ingress path is selected if the flag is present, - * egress otherwise). This is the only flag supported for now. - * - * Returns - * **SK_PASS** on success, or **SK_DROP** on error. - */ -static long (*bpf_sk_redirect_hash)(struct __sk_buff *skb, void *map, void *key, __u64 flags) = (void *) 72; - -/* - * bpf_lwt_push_encap - * - * Encapsulate the packet associated to *skb* within a Layer 3 - * protocol header. This header is provided in the buffer at - * address *hdr*, with *len* its size in bytes. *type* indicates - * the protocol of the header and can be one of: - * - * **BPF_LWT_ENCAP_SEG6** - * IPv6 encapsulation with Segment Routing Header - * (**struct ipv6_sr_hdr**). *hdr* only contains the SRH, - * the IPv6 header is computed by the kernel. - * **BPF_LWT_ENCAP_SEG6_INLINE** - * Only works if *skb* contains an IPv6 packet. Insert a - * Segment Routing Header (**struct ipv6_sr_hdr**) inside - * the IPv6 header. - * **BPF_LWT_ENCAP_IP** - * IP encapsulation (GRE/GUE/IPIP/etc). The outer header - * must be IPv4 or IPv6, followed by zero or more - * additional headers, up to **LWT_BPF_MAX_HEADROOM** - * total bytes in all prepended headers. Please note that - * if **skb_is_gso**\ (*skb*) is true, no more than two - * headers can be prepended, and the inner header, if - * present, should be either GRE or UDP/GUE. - * - * **BPF_LWT_ENCAP_SEG6**\ \* types can be called by BPF programs - * of type **BPF_PROG_TYPE_LWT_IN**; **BPF_LWT_ENCAP_IP** type can - * be called by bpf programs of types **BPF_PROG_TYPE_LWT_IN** and - * **BPF_PROG_TYPE_LWT_XMIT**. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_lwt_push_encap)(struct __sk_buff *skb, __u32 type, void *hdr, __u32 len) = (void *) 73; - -/* - * bpf_lwt_seg6_store_bytes - * - * Store *len* bytes from address *from* into the packet - * associated to *skb*, at *offset*. Only the flags, tag and TLVs - * inside the outermost IPv6 Segment Routing Header can be - * modified through this helper. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_lwt_seg6_store_bytes)(struct __sk_buff *skb, __u32 offset, const void *from, __u32 len) = (void *) 74; - -/* - * bpf_lwt_seg6_adjust_srh - * - * Adjust the size allocated to TLVs in the outermost IPv6 - * Segment Routing Header contained in the packet associated to - * *skb*, at position *offset* by *delta* bytes. Only offsets - * after the segments are accepted. *delta* can be as well - * positive (growing) as negative (shrinking). - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_lwt_seg6_adjust_srh)(struct __sk_buff *skb, __u32 offset, __s32 delta) = (void *) 75; - -/* - * bpf_lwt_seg6_action - * - * Apply an IPv6 Segment Routing action of type *action* to the - * packet associated to *skb*. Each action takes a parameter - * contained at address *param*, and of length *param_len* bytes. - * *action* can be one of: - * - * **SEG6_LOCAL_ACTION_END_X** - * End.X action: Endpoint with Layer-3 cross-connect. - * Type of *param*: **struct in6_addr**. - * **SEG6_LOCAL_ACTION_END_T** - * End.T action: Endpoint with specific IPv6 table lookup. - * Type of *param*: **int**. - * **SEG6_LOCAL_ACTION_END_B6** - * End.B6 action: Endpoint bound to an SRv6 policy. - * Type of *param*: **struct ipv6_sr_hdr**. - * **SEG6_LOCAL_ACTION_END_B6_ENCAP** - * End.B6.Encap action: Endpoint bound to an SRv6 - * encapsulation policy. - * Type of *param*: **struct ipv6_sr_hdr**. - * - * A call to this helper is susceptible to change the underlying - * packet buffer. Therefore, at load time, all checks on pointers - * previously done by the verifier are invalidated and must be - * performed again, if the helper is used in combination with - * direct packet access. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_lwt_seg6_action)(struct __sk_buff *skb, __u32 action, void *param, __u32 param_len) = (void *) 76; - -/* - * bpf_rc_repeat - * - * This helper is used in programs implementing IR decoding, to - * report a successfully decoded repeat key message. This delays - * the generation of a key up event for previously generated - * key down event. - * - * Some IR protocols like NEC have a special IR message for - * repeating last button, for when a button is held down. - * - * The *ctx* should point to the lirc sample as passed into - * the program. - * - * This helper is only available is the kernel was compiled with - * the **CONFIG_BPF_LIRC_MODE2** configuration option set to - * "**y**". - * - * Returns - * 0 - */ -static long (*bpf_rc_repeat)(void *ctx) = (void *) 77; - -/* - * bpf_rc_keydown - * - * This helper is used in programs implementing IR decoding, to - * report a successfully decoded key press with *scancode*, - * *toggle* value in the given *protocol*. The scancode will be - * translated to a keycode using the rc keymap, and reported as - * an input key down event. After a period a key up event is - * generated. This period can be extended by calling either - * **bpf_rc_keydown**\ () again with the same values, or calling - * **bpf_rc_repeat**\ (). - * - * Some protocols include a toggle bit, in case the button was - * released and pressed again between consecutive scancodes. - * - * The *ctx* should point to the lirc sample as passed into - * the program. - * - * The *protocol* is the decoded protocol number (see - * **enum rc_proto** for some predefined values). - * - * This helper is only available is the kernel was compiled with - * the **CONFIG_BPF_LIRC_MODE2** configuration option set to - * "**y**". - * - * Returns - * 0 - */ -static long (*bpf_rc_keydown)(void *ctx, __u32 protocol, __u64 scancode, __u32 toggle) = (void *) 78; - -/* - * bpf_skb_cgroup_id - * - * Return the cgroup v2 id of the socket associated with the *skb*. - * This is roughly similar to the **bpf_get_cgroup_classid**\ () - * helper for cgroup v1 by providing a tag resp. identifier that - * can be matched on or used for map lookups e.g. to implement - * policy. The cgroup v2 id of a given path in the hierarchy is - * exposed in user space through the f_handle API in order to get - * to the same 64-bit id. - * - * This helper can be used on TC egress path, but not on ingress, - * and is available only if the kernel was compiled with the - * **CONFIG_SOCK_CGROUP_DATA** configuration option. - * - * Returns - * The id is returned or 0 in case the id could not be retrieved. - */ -static __u64 (*bpf_skb_cgroup_id)(struct __sk_buff *skb) = (void *) 79; - -/* - * bpf_get_current_cgroup_id - * - * - * Returns - * A 64-bit integer containing the current cgroup id based - * on the cgroup within which the current task is running. - */ -static __u64 (*bpf_get_current_cgroup_id)(void) = (void *) 80; - -/* - * bpf_get_local_storage - * - * Get the pointer to the local storage area. - * The type and the size of the local storage is defined - * by the *map* argument. - * The *flags* meaning is specific for each map type, - * and has to be 0 for cgroup local storage. - * - * Depending on the BPF program type, a local storage area - * can be shared between multiple instances of the BPF program, - * running simultaneously. - * - * A user should care about the synchronization by himself. - * For example, by using the **BPF_ATOMIC** instructions to alter - * the shared data. - * - * Returns - * A pointer to the local storage area. - */ -static void *(*bpf_get_local_storage)(void *map, __u64 flags) = (void *) 81; - -/* - * bpf_sk_select_reuseport - * - * Select a **SO_REUSEPORT** socket from a - * **BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*. - * It checks the selected socket is matching the incoming - * request in the socket buffer. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_sk_select_reuseport)(struct sk_reuseport_md *reuse, void *map, void *key, __u64 flags) = (void *) 82; - -/* - * bpf_skb_ancestor_cgroup_id - * - * Return id of cgroup v2 that is ancestor of cgroup associated - * with the *skb* at the *ancestor_level*. The root cgroup is at - * *ancestor_level* zero and each step down the hierarchy - * increments the level. If *ancestor_level* == level of cgroup - * associated with *skb*, then return value will be same as that - * of **bpf_skb_cgroup_id**\ (). - * - * The helper is useful to implement policies based on cgroups - * that are upper in hierarchy than immediate cgroup associated - * with *skb*. - * - * The format of returned id and helper limitations are same as in - * **bpf_skb_cgroup_id**\ (). - * - * Returns - * The id is returned or 0 in case the id could not be retrieved. - */ -static __u64 (*bpf_skb_ancestor_cgroup_id)(struct __sk_buff *skb, int ancestor_level) = (void *) 83; - -/* - * bpf_sk_lookup_tcp - * - * Look for TCP socket matching *tuple*, optionally in a child - * network namespace *netns*. The return value must be checked, - * and if non-**NULL**, released via **bpf_sk_release**\ (). - * - * The *ctx* should point to the context of the program, such as - * the skb or socket (depending on the hook in use). This is used - * to determine the base network namespace for the lookup. - * - * *tuple_size* must be one of: - * - * **sizeof**\ (*tuple*\ **->ipv4**) - * Look for an IPv4 socket. - * **sizeof**\ (*tuple*\ **->ipv6**) - * Look for an IPv6 socket. - * - * If the *netns* is a negative signed 32-bit integer, then the - * socket lookup table in the netns associated with the *ctx* - * will be used. For the TC hooks, this is the netns of the device - * in the skb. For socket hooks, this is the netns of the socket. - * If *netns* is any other signed 32-bit value greater than or - * equal to zero then it specifies the ID of the netns relative to - * the netns associated with the *ctx*. *netns* values beyond the - * range of 32-bit integers are reserved for future use. - * - * All values for *flags* are reserved for future usage, and must - * be left at zero. - * - * This helper is available only if the kernel was compiled with - * **CONFIG_NET** configuration option. - * - * Returns - * Pointer to **struct bpf_sock**, or **NULL** in case of failure. - * For sockets with reuseport option, the **struct bpf_sock** - * result is from *reuse*\ **->socks**\ [] using the hash of the - * tuple. - */ -static struct bpf_sock *(*bpf_sk_lookup_tcp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 84; - -/* - * bpf_sk_lookup_udp - * - * Look for UDP socket matching *tuple*, optionally in a child - * network namespace *netns*. The return value must be checked, - * and if non-**NULL**, released via **bpf_sk_release**\ (). - * - * The *ctx* should point to the context of the program, such as - * the skb or socket (depending on the hook in use). This is used - * to determine the base network namespace for the lookup. - * - * *tuple_size* must be one of: - * - * **sizeof**\ (*tuple*\ **->ipv4**) - * Look for an IPv4 socket. - * **sizeof**\ (*tuple*\ **->ipv6**) - * Look for an IPv6 socket. - * - * If the *netns* is a negative signed 32-bit integer, then the - * socket lookup table in the netns associated with the *ctx* - * will be used. For the TC hooks, this is the netns of the device - * in the skb. For socket hooks, this is the netns of the socket. - * If *netns* is any other signed 32-bit value greater than or - * equal to zero then it specifies the ID of the netns relative to - * the netns associated with the *ctx*. *netns* values beyond the - * range of 32-bit integers are reserved for future use. - * - * All values for *flags* are reserved for future usage, and must - * be left at zero. - * - * This helper is available only if the kernel was compiled with - * **CONFIG_NET** configuration option. - * - * Returns - * Pointer to **struct bpf_sock**, or **NULL** in case of failure. - * For sockets with reuseport option, the **struct bpf_sock** - * result is from *reuse*\ **->socks**\ [] using the hash of the - * tuple. - */ -static struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 85; - -/* - * bpf_sk_release - * - * Release the reference held by *sock*. *sock* must be a - * non-**NULL** pointer that was returned from - * **bpf_sk_lookup_xxx**\ (). - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_sk_release)(void *sock) = (void *) 86; - -/* - * bpf_map_push_elem - * - * Push an element *value* in *map*. *flags* is one of: - * - * **BPF_EXIST** - * If the queue/stack is full, the oldest element is - * removed to make room for this. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_map_push_elem)(void *map, const void *value, __u64 flags) = (void *) 87; - -/* - * bpf_map_pop_elem - * - * Pop an element from *map*. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_map_pop_elem)(void *map, void *value) = (void *) 88; - -/* - * bpf_map_peek_elem - * - * Get an element from *map* without removing it. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_map_peek_elem)(void *map, void *value) = (void *) 89; - -/* - * bpf_msg_push_data - * - * For socket policies, insert *len* bytes into *msg* at offset - * *start*. - * - * If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a - * *msg* it may want to insert metadata or options into the *msg*. - * This can later be read and used by any of the lower layer BPF - * hooks. - * - * This helper may fail if under memory pressure (a malloc - * fails) in these cases BPF programs will get an appropriate - * error and BPF programs will need to handle them. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_msg_push_data)(struct sk_msg_md *msg, __u32 start, __u32 len, __u64 flags) = (void *) 90; - -/* - * bpf_msg_pop_data - * - * Will remove *len* bytes from a *msg* starting at byte *start*. - * This may result in **ENOMEM** errors under certain situations if - * an allocation and copy are required due to a full ring buffer. - * However, the helper will try to avoid doing the allocation - * if possible. Other errors can occur if input parameters are - * invalid either due to *start* byte not being valid part of *msg* - * payload and/or *pop* value being to large. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_msg_pop_data)(struct sk_msg_md *msg, __u32 start, __u32 len, __u64 flags) = (void *) 91; - -/* - * bpf_rc_pointer_rel - * - * This helper is used in programs implementing IR decoding, to - * report a successfully decoded pointer movement. - * - * The *ctx* should point to the lirc sample as passed into - * the program. - * - * This helper is only available is the kernel was compiled with - * the **CONFIG_BPF_LIRC_MODE2** configuration option set to - * "**y**". - * - * Returns - * 0 - */ -static long (*bpf_rc_pointer_rel)(void *ctx, __s32 rel_x, __s32 rel_y) = (void *) 92; - -/* - * bpf_spin_lock - * - * Acquire a spinlock represented by the pointer *lock*, which is - * stored as part of a value of a map. Taking the lock allows to - * safely update the rest of the fields in that value. The - * spinlock can (and must) later be released with a call to - * **bpf_spin_unlock**\ (\ *lock*\ ). - * - * Spinlocks in BPF programs come with a number of restrictions - * and constraints: - * - * * **bpf_spin_lock** objects are only allowed inside maps of - * types **BPF_MAP_TYPE_HASH** and **BPF_MAP_TYPE_ARRAY** (this - * list could be extended in the future). - * * BTF description of the map is mandatory. - * * The BPF program can take ONE lock at a time, since taking two - * or more could cause dead locks. - * * Only one **struct bpf_spin_lock** is allowed per map element. - * * When the lock is taken, calls (either BPF to BPF or helpers) - * are not allowed. - * * The **BPF_LD_ABS** and **BPF_LD_IND** instructions are not - * allowed inside a spinlock-ed region. - * * The BPF program MUST call **bpf_spin_unlock**\ () to release - * the lock, on all execution paths, before it returns. - * * The BPF program can access **struct bpf_spin_lock** only via - * the **bpf_spin_lock**\ () and **bpf_spin_unlock**\ () - * helpers. Loading or storing data into the **struct - * bpf_spin_lock** *lock*\ **;** field of a map is not allowed. - * * To use the **bpf_spin_lock**\ () helper, the BTF description - * of the map value must be a struct and have **struct - * bpf_spin_lock** *anyname*\ **;** field at the top level. - * Nested lock inside another struct is not allowed. - * * The **struct bpf_spin_lock** *lock* field in a map value must - * be aligned on a multiple of 4 bytes in that value. - * * Syscall with command **BPF_MAP_LOOKUP_ELEM** does not copy - * the **bpf_spin_lock** field to user space. - * * Syscall with command **BPF_MAP_UPDATE_ELEM**, or update from - * a BPF program, do not update the **bpf_spin_lock** field. - * * **bpf_spin_lock** cannot be on the stack or inside a - * networking packet (it can only be inside of a map values). - * * **bpf_spin_lock** is available to root only. - * * Tracing programs and socket filter programs cannot use - * **bpf_spin_lock**\ () due to insufficient preemption checks - * (but this may change in the future). - * * **bpf_spin_lock** is not allowed in inner maps of map-in-map. - * - * Returns - * 0 - */ -static long (*bpf_spin_lock)(struct bpf_spin_lock *lock) = (void *) 93; - -/* - * bpf_spin_unlock - * - * Release the *lock* previously locked by a call to - * **bpf_spin_lock**\ (\ *lock*\ ). - * - * Returns - * 0 - */ -static long (*bpf_spin_unlock)(struct bpf_spin_lock *lock) = (void *) 94; - -/* - * bpf_sk_fullsock - * - * This helper gets a **struct bpf_sock** pointer such - * that all the fields in this **bpf_sock** can be accessed. - * - * Returns - * A **struct bpf_sock** pointer on success, or **NULL** in - * case of failure. - */ -static struct bpf_sock *(*bpf_sk_fullsock)(struct bpf_sock *sk) = (void *) 95; - -/* - * bpf_tcp_sock - * - * This helper gets a **struct bpf_tcp_sock** pointer from a - * **struct bpf_sock** pointer. - * - * Returns - * A **struct bpf_tcp_sock** pointer on success, or **NULL** in - * case of failure. - */ -static struct bpf_tcp_sock *(*bpf_tcp_sock)(struct bpf_sock *sk) = (void *) 96; - -/* - * bpf_skb_ecn_set_ce - * - * Set ECN (Explicit Congestion Notification) field of IP header - * to **CE** (Congestion Encountered) if current value is **ECT** - * (ECN Capable Transport). Otherwise, do nothing. Works with IPv6 - * and IPv4. - * - * Returns - * 1 if the **CE** flag is set (either by the current helper call - * or because it was already present), 0 if it is not set. - */ -static long (*bpf_skb_ecn_set_ce)(struct __sk_buff *skb) = (void *) 97; - -/* - * bpf_get_listener_sock - * - * Return a **struct bpf_sock** pointer in **TCP_LISTEN** state. - * **bpf_sk_release**\ () is unnecessary and not allowed. - * - * Returns - * A **struct bpf_sock** pointer on success, or **NULL** in - * case of failure. - */ -static struct bpf_sock *(*bpf_get_listener_sock)(struct bpf_sock *sk) = (void *) 98; - -/* - * bpf_skc_lookup_tcp - * - * Look for TCP socket matching *tuple*, optionally in a child - * network namespace *netns*. The return value must be checked, - * and if non-**NULL**, released via **bpf_sk_release**\ (). - * - * This function is identical to **bpf_sk_lookup_tcp**\ (), except - * that it also returns timewait or request sockets. Use - * **bpf_sk_fullsock**\ () or **bpf_tcp_sock**\ () to access the - * full structure. - * - * This helper is available only if the kernel was compiled with - * **CONFIG_NET** configuration option. - * - * Returns - * Pointer to **struct bpf_sock**, or **NULL** in case of failure. - * For sockets with reuseport option, the **struct bpf_sock** - * result is from *reuse*\ **->socks**\ [] using the hash of the - * tuple. - */ -static struct bpf_sock *(*bpf_skc_lookup_tcp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 99; - -/* - * bpf_tcp_check_syncookie - * - * Check whether *iph* and *th* contain a valid SYN cookie ACK for - * the listening socket in *sk*. - * - * *iph* points to the start of the IPv4 or IPv6 header, while - * *iph_len* contains **sizeof**\ (**struct iphdr**) or - * **sizeof**\ (**struct ip6hdr**). - * - * *th* points to the start of the TCP header, while *th_len* - * contains **sizeof**\ (**struct tcphdr**). - * - * Returns - * 0 if *iph* and *th* are a valid SYN cookie ACK, or a negative - * error otherwise. - */ -static long (*bpf_tcp_check_syncookie)(void *sk, void *iph, __u32 iph_len, struct tcphdr *th, __u32 th_len) = (void *) 100; - -/* - * bpf_sysctl_get_name - * - * Get name of sysctl in /proc/sys/ and copy it into provided by - * program buffer *buf* of size *buf_len*. - * - * The buffer is always NUL terminated, unless it's zero-sized. - * - * If *flags* is zero, full name (e.g. "net/ipv4/tcp_mem") is - * copied. Use **BPF_F_SYSCTL_BASE_NAME** flag to copy base name - * only (e.g. "tcp_mem"). - * - * Returns - * Number of character copied (not including the trailing NUL). - * - * **-E2BIG** if the buffer wasn't big enough (*buf* will contain - * truncated name in this case). - */ -static long (*bpf_sysctl_get_name)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len, __u64 flags) = (void *) 101; - -/* - * bpf_sysctl_get_current_value - * - * Get current value of sysctl as it is presented in /proc/sys - * (incl. newline, etc), and copy it as a string into provided - * by program buffer *buf* of size *buf_len*. - * - * The whole value is copied, no matter what file position user - * space issued e.g. sys_read at. - * - * The buffer is always NUL terminated, unless it's zero-sized. - * - * Returns - * Number of character copied (not including the trailing NUL). - * - * **-E2BIG** if the buffer wasn't big enough (*buf* will contain - * truncated name in this case). - * - * **-EINVAL** if current value was unavailable, e.g. because - * sysctl is uninitialized and read returns -EIO for it. - */ -static long (*bpf_sysctl_get_current_value)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len) = (void *) 102; - -/* - * bpf_sysctl_get_new_value - * - * Get new value being written by user space to sysctl (before - * the actual write happens) and copy it as a string into - * provided by program buffer *buf* of size *buf_len*. - * - * User space may write new value at file position > 0. - * - * The buffer is always NUL terminated, unless it's zero-sized. - * - * Returns - * Number of character copied (not including the trailing NUL). - * - * **-E2BIG** if the buffer wasn't big enough (*buf* will contain - * truncated name in this case). - * - * **-EINVAL** if sysctl is being read. - */ -static long (*bpf_sysctl_get_new_value)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len) = (void *) 103; - -/* - * bpf_sysctl_set_new_value - * - * Override new value being written by user space to sysctl with - * value provided by program in buffer *buf* of size *buf_len*. - * - * *buf* should contain a string in same form as provided by user - * space on sysctl write. - * - * User space may write new value at file position > 0. To override - * the whole sysctl value file position should be set to zero. - * - * Returns - * 0 on success. - * - * **-E2BIG** if the *buf_len* is too big. - * - * **-EINVAL** if sysctl is being read. - */ -static long (*bpf_sysctl_set_new_value)(struct bpf_sysctl *ctx, const char *buf, unsigned long buf_len) = (void *) 104; - -/* - * bpf_strtol - * - * Convert the initial part of the string from buffer *buf* of - * size *buf_len* to a long integer according to the given base - * and save the result in *res*. - * - * The string may begin with an arbitrary amount of white space - * (as determined by **isspace**\ (3)) followed by a single - * optional '**-**' sign. - * - * Five least significant bits of *flags* encode base, other bits - * are currently unused. - * - * Base must be either 8, 10, 16 or 0 to detect it automatically - * similar to user space **strtol**\ (3). - * - * Returns - * Number of characters consumed on success. Must be positive but - * no more than *buf_len*. - * - * **-EINVAL** if no valid digits were found or unsupported base - * was provided. - * - * **-ERANGE** if resulting value was out of range. - */ -static long (*bpf_strtol)(const char *buf, unsigned long buf_len, __u64 flags, long *res) = (void *) 105; - -/* - * bpf_strtoul - * - * Convert the initial part of the string from buffer *buf* of - * size *buf_len* to an unsigned long integer according to the - * given base and save the result in *res*. - * - * The string may begin with an arbitrary amount of white space - * (as determined by **isspace**\ (3)). - * - * Five least significant bits of *flags* encode base, other bits - * are currently unused. - * - * Base must be either 8, 10, 16 or 0 to detect it automatically - * similar to user space **strtoul**\ (3). - * - * Returns - * Number of characters consumed on success. Must be positive but - * no more than *buf_len*. - * - * **-EINVAL** if no valid digits were found or unsupported base - * was provided. - * - * **-ERANGE** if resulting value was out of range. - */ -static long (*bpf_strtoul)(const char *buf, unsigned long buf_len, __u64 flags, unsigned long *res) = (void *) 106; - -/* - * bpf_sk_storage_get - * - * Get a bpf-local-storage from a *sk*. - * - * Logically, it could be thought of getting the value from - * a *map* with *sk* as the **key**. From this - * perspective, the usage is not much different from - * **bpf_map_lookup_elem**\ (*map*, **&**\ *sk*) except this - * helper enforces the key must be a full socket and the map must - * be a **BPF_MAP_TYPE_SK_STORAGE** also. - * - * Underneath, the value is stored locally at *sk* instead of - * the *map*. The *map* is used as the bpf-local-storage - * "type". The bpf-local-storage "type" (i.e. the *map*) is - * searched against all bpf-local-storages residing at *sk*. - * - * *sk* is a kernel **struct sock** pointer for LSM program. - * *sk* is a **struct bpf_sock** pointer for other program types. - * - * An optional *flags* (**BPF_SK_STORAGE_GET_F_CREATE**) can be - * used such that a new bpf-local-storage will be - * created if one does not exist. *value* can be used - * together with **BPF_SK_STORAGE_GET_F_CREATE** to specify - * the initial value of a bpf-local-storage. If *value* is - * **NULL**, the new bpf-local-storage will be zero initialized. - * - * Returns - * A bpf-local-storage pointer is returned on success. - * - * **NULL** if not found or there was an error in adding - * a new bpf-local-storage. - */ -static void *(*bpf_sk_storage_get)(void *map, void *sk, void *value, __u64 flags) = (void *) 107; - -/* - * bpf_sk_storage_delete - * - * Delete a bpf-local-storage from a *sk*. - * - * Returns - * 0 on success. - * - * **-ENOENT** if the bpf-local-storage cannot be found. - * **-EINVAL** if sk is not a fullsock (e.g. a request_sock). - */ -static long (*bpf_sk_storage_delete)(void *map, void *sk) = (void *) 108; - -/* - * bpf_send_signal - * - * Send signal *sig* to the process of the current task. - * The signal may be delivered to any of this process's threads. - * - * Returns - * 0 on success or successfully queued. - * - * **-EBUSY** if work queue under nmi is full. - * - * **-EINVAL** if *sig* is invalid. - * - * **-EPERM** if no permission to send the *sig*. - * - * **-EAGAIN** if bpf program can try again. - */ -static long (*bpf_send_signal)(__u32 sig) = (void *) 109; - -/* - * bpf_tcp_gen_syncookie - * - * Try to issue a SYN cookie for the packet with corresponding - * IP/TCP headers, *iph* and *th*, on the listening socket in *sk*. - * - * *iph* points to the start of the IPv4 or IPv6 header, while - * *iph_len* contains **sizeof**\ (**struct iphdr**) or - * **sizeof**\ (**struct ip6hdr**). - * - * *th* points to the start of the TCP header, while *th_len* - * contains the length of the TCP header. - * - * Returns - * On success, lower 32 bits hold the generated SYN cookie in - * followed by 16 bits which hold the MSS value for that cookie, - * and the top 16 bits are unused. - * - * On failure, the returned value is one of the following: - * - * **-EINVAL** SYN cookie cannot be issued due to error - * - * **-ENOENT** SYN cookie should not be issued (no SYN flood) - * - * **-EOPNOTSUPP** kernel configuration does not enable SYN cookies - * - * **-EPROTONOSUPPORT** IP packet version is not 4 or 6 - */ -static __s64 (*bpf_tcp_gen_syncookie)(void *sk, void *iph, __u32 iph_len, struct tcphdr *th, __u32 th_len) = (void *) 110; - -/* - * bpf_skb_output - * - * Write raw *data* blob into a special BPF perf event held by - * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf - * event must have the following attributes: **PERF_SAMPLE_RAW** - * as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and - * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. - * - * The *flags* are used to indicate the index in *map* for which - * the value must be put, masked with **BPF_F_INDEX_MASK**. - * Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU** - * to indicate that the index of the current CPU core should be - * used. - * - * The value to write, of *size*, is passed through eBPF stack and - * pointed by *data*. - * - * *ctx* is a pointer to in-kernel struct sk_buff. - * - * This helper is similar to **bpf_perf_event_output**\ () but - * restricted to raw_tracepoint bpf programs. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_skb_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 111; - -/* - * bpf_probe_read_user - * - * Safely attempt to read *size* bytes from user space address - * *unsafe_ptr* and store the data in *dst*. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_probe_read_user)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 112; - -/* - * bpf_probe_read_kernel - * - * Safely attempt to read *size* bytes from kernel space address - * *unsafe_ptr* and store the data in *dst*. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_probe_read_kernel)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 113; - -/* - * bpf_probe_read_user_str - * - * Copy a NUL terminated string from an unsafe user address - * *unsafe_ptr* to *dst*. The *size* should include the - * terminating NUL byte. In case the string length is smaller than - * *size*, the target is not padded with further NUL bytes. If the - * string length is larger than *size*, just *size*-1 bytes are - * copied and the last byte is set to NUL. - * - * On success, returns the number of bytes that were written, - * including the terminal NUL. This makes this helper useful in - * tracing programs for reading strings, and more importantly to - * get its length at runtime. See the following snippet: - * - * :: - * - * SEC("kprobe/sys_open") - * void bpf_sys_open(struct pt_regs *ctx) - * { - * char buf[PATHLEN]; // PATHLEN is defined to 256 - * int res = bpf_probe_read_user_str(buf, sizeof(buf), - * ctx->di); - * - * // Consume buf, for example push it to - * // userspace via bpf_perf_event_output(); we - * // can use res (the string length) as event - * // size, after checking its boundaries. - * } - * - * In comparison, using **bpf_probe_read_user**\ () helper here - * instead to read the string would require to estimate the length - * at compile time, and would often result in copying more memory - * than necessary. - * - * Another useful use case is when parsing individual process - * arguments or individual environment variables navigating - * *current*\ **->mm->arg_start** and *current*\ - * **->mm->env_start**: using this helper and the return value, - * one can quickly iterate at the right offset of the memory area. - * - * Returns - * On success, the strictly positive length of the output string, - * including the trailing NUL character. On error, a negative - * value. - */ -static long (*bpf_probe_read_user_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 114; - -/* - * bpf_probe_read_kernel_str - * - * Copy a NUL terminated string from an unsafe kernel address *unsafe_ptr* - * to *dst*. Same semantics as with **bpf_probe_read_user_str**\ () apply. - * - * Returns - * On success, the strictly positive length of the string, including - * the trailing NUL character. On error, a negative value. - */ -static long (*bpf_probe_read_kernel_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 115; - -/* - * bpf_tcp_send_ack - * - * Send out a tcp-ack. *tp* is the in-kernel struct **tcp_sock**. - * *rcv_nxt* is the ack_seq to be sent out. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_tcp_send_ack)(void *tp, __u32 rcv_nxt) = (void *) 116; - -/* - * bpf_send_signal_thread - * - * Send signal *sig* to the thread corresponding to the current task. - * - * Returns - * 0 on success or successfully queued. - * - * **-EBUSY** if work queue under nmi is full. - * - * **-EINVAL** if *sig* is invalid. - * - * **-EPERM** if no permission to send the *sig*. - * - * **-EAGAIN** if bpf program can try again. - */ -static long (*bpf_send_signal_thread)(__u32 sig) = (void *) 117; - -/* - * bpf_jiffies64 - * - * Obtain the 64bit jiffies - * - * Returns - * The 64 bit jiffies - */ -static __u64 (*bpf_jiffies64)(void) = (void *) 118; - -/* - * bpf_read_branch_records - * - * For an eBPF program attached to a perf event, retrieve the - * branch records (**struct perf_branch_entry**) associated to *ctx* - * and store it in the buffer pointed by *buf* up to size - * *size* bytes. - * - * Returns - * On success, number of bytes written to *buf*. On error, a - * negative value. - * - * The *flags* can be set to **BPF_F_GET_BRANCH_RECORDS_SIZE** to - * instead return the number of bytes required to store all the - * branch entries. If this flag is set, *buf* may be NULL. - * - * **-EINVAL** if arguments invalid or **size** not a multiple - * of **sizeof**\ (**struct perf_branch_entry**\ ). - * - * **-ENOENT** if architecture does not support branch records. - */ -static long (*bpf_read_branch_records)(struct bpf_perf_event_data *ctx, void *buf, __u32 size, __u64 flags) = (void *) 119; - -/* - * bpf_get_ns_current_pid_tgid - * - * Returns 0 on success, values for *pid* and *tgid* as seen from the current - * *namespace* will be returned in *nsdata*. - * - * Returns - * 0 on success, or one of the following in case of failure: - * - * **-EINVAL** if dev and inum supplied don't match dev_t and inode number - * with nsfs of current task, or if dev conversion to dev_t lost high bits. - * - * **-ENOENT** if pidns does not exists for the current task. - */ -static long (*bpf_get_ns_current_pid_tgid)(__u64 dev, __u64 ino, struct bpf_pidns_info *nsdata, __u32 size) = (void *) 120; - -/* - * bpf_xdp_output - * - * Write raw *data* blob into a special BPF perf event held by - * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf - * event must have the following attributes: **PERF_SAMPLE_RAW** - * as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and - * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. - * - * The *flags* are used to indicate the index in *map* for which - * the value must be put, masked with **BPF_F_INDEX_MASK**. - * Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU** - * to indicate that the index of the current CPU core should be - * used. - * - * The value to write, of *size*, is passed through eBPF stack and - * pointed by *data*. - * - * *ctx* is a pointer to in-kernel struct xdp_buff. - * - * This helper is similar to **bpf_perf_eventoutput**\ () but - * restricted to raw_tracepoint bpf programs. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_xdp_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 121; - -/* - * bpf_get_netns_cookie - * - * Retrieve the cookie (generated by the kernel) of the network - * namespace the input *ctx* is associated with. The network - * namespace cookie remains stable for its lifetime and provides - * a global identifier that can be assumed unique. If *ctx* is - * NULL, then the helper returns the cookie for the initial - * network namespace. The cookie itself is very similar to that - * of **bpf_get_socket_cookie**\ () helper, but for network - * namespaces instead of sockets. - * - * Returns - * A 8-byte long opaque number. - */ -static __u64 (*bpf_get_netns_cookie)(void *ctx) = (void *) 122; - -/* - * bpf_get_current_ancestor_cgroup_id - * - * Return id of cgroup v2 that is ancestor of the cgroup associated - * with the current task at the *ancestor_level*. The root cgroup - * is at *ancestor_level* zero and each step down the hierarchy - * increments the level. If *ancestor_level* == level of cgroup - * associated with the current task, then return value will be the - * same as that of **bpf_get_current_cgroup_id**\ (). - * - * The helper is useful to implement policies based on cgroups - * that are upper in hierarchy than immediate cgroup associated - * with the current task. - * - * The format of returned id and helper limitations are same as in - * **bpf_get_current_cgroup_id**\ (). - * - * Returns - * The id is returned or 0 in case the id could not be retrieved. - */ -static __u64 (*bpf_get_current_ancestor_cgroup_id)(int ancestor_level) = (void *) 123; - -/* - * bpf_sk_assign - * - * Helper is overloaded depending on BPF program type. This - * description applies to **BPF_PROG_TYPE_SCHED_CLS** and - * **BPF_PROG_TYPE_SCHED_ACT** programs. - * - * Assign the *sk* to the *skb*. When combined with appropriate - * routing configuration to receive the packet towards the socket, - * will cause *skb* to be delivered to the specified socket. - * Subsequent redirection of *skb* via **bpf_redirect**\ (), - * **bpf_clone_redirect**\ () or other methods outside of BPF may - * interfere with successful delivery to the socket. - * - * This operation is only valid from TC ingress path. - * - * The *flags* argument must be zero. - * - * Returns - * 0 on success, or a negative error in case of failure: - * - * **-EINVAL** if specified *flags* are not supported. - * - * **-ENOENT** if the socket is unavailable for assignment. - * - * **-ENETUNREACH** if the socket is unreachable (wrong netns). - * - * **-EOPNOTSUPP** if the operation is not supported, for example - * a call from outside of TC ingress. - * - * **-ESOCKTNOSUPPORT** if the socket type is not supported - * (reuseport). - */ -static long (*bpf_sk_assign)(void *ctx, void *sk, __u64 flags) = (void *) 124; - -/* - * bpf_ktime_get_boot_ns - * - * Return the time elapsed since system boot, in nanoseconds. - * Does include the time the system was suspended. - * See: **clock_gettime**\ (**CLOCK_BOOTTIME**) - * - * Returns - * Current *ktime*. - */ -static __u64 (*bpf_ktime_get_boot_ns)(void) = (void *) 125; - -/* - * bpf_seq_printf - * - * **bpf_seq_printf**\ () uses seq_file **seq_printf**\ () to print - * out the format string. - * The *m* represents the seq_file. The *fmt* and *fmt_size* are for - * the format string itself. The *data* and *data_len* are format string - * arguments. The *data* are a **u64** array and corresponding format string - * values are stored in the array. For strings and pointers where pointees - * are accessed, only the pointer values are stored in the *data* array. - * The *data_len* is the size of *data* in bytes - must be a multiple of 8. - * - * Formats **%s**, **%p{i,I}{4,6}** requires to read kernel memory. - * Reading kernel memory may fail due to either invalid address or - * valid address but requiring a major memory fault. If reading kernel memory - * fails, the string for **%s** will be an empty string, and the ip - * address for **%p{i,I}{4,6}** will be 0. Not returning error to - * bpf program is consistent with what **bpf_trace_printk**\ () does for now. - * - * Returns - * 0 on success, or a negative error in case of failure: - * - * **-EBUSY** if per-CPU memory copy buffer is busy, can try again - * by returning 1 from bpf program. - * - * **-EINVAL** if arguments are invalid, or if *fmt* is invalid/unsupported. - * - * **-E2BIG** if *fmt* contains too many format specifiers. - * - * **-EOVERFLOW** if an overflow happened: The same object will be tried again. - */ -static long (*bpf_seq_printf)(struct seq_file *m, const char *fmt, __u32 fmt_size, const void *data, __u32 data_len) = (void *) 126; - -/* - * bpf_seq_write - * - * **bpf_seq_write**\ () uses seq_file **seq_write**\ () to write the data. - * The *m* represents the seq_file. The *data* and *len* represent the - * data to write in bytes. - * - * Returns - * 0 on success, or a negative error in case of failure: - * - * **-EOVERFLOW** if an overflow happened: The same object will be tried again. - */ -static long (*bpf_seq_write)(struct seq_file *m, const void *data, __u32 len) = (void *) 127; - -/* - * bpf_sk_cgroup_id - * - * Return the cgroup v2 id of the socket *sk*. - * - * *sk* must be a non-**NULL** pointer to a socket, e.g. one - * returned from **bpf_sk_lookup_xxx**\ (), - * **bpf_sk_fullsock**\ (), etc. The format of returned id is - * same as in **bpf_skb_cgroup_id**\ (). - * - * This helper is available only if the kernel was compiled with - * the **CONFIG_SOCK_CGROUP_DATA** configuration option. - * - * Returns - * The id is returned or 0 in case the id could not be retrieved. - */ -static __u64 (*bpf_sk_cgroup_id)(void *sk) = (void *) 128; - -/* - * bpf_sk_ancestor_cgroup_id - * - * Return id of cgroup v2 that is ancestor of cgroup associated - * with the *sk* at the *ancestor_level*. The root cgroup is at - * *ancestor_level* zero and each step down the hierarchy - * increments the level. If *ancestor_level* == level of cgroup - * associated with *sk*, then return value will be same as that - * of **bpf_sk_cgroup_id**\ (). - * - * The helper is useful to implement policies based on cgroups - * that are upper in hierarchy than immediate cgroup associated - * with *sk*. - * - * The format of returned id and helper limitations are same as in - * **bpf_sk_cgroup_id**\ (). - * - * Returns - * The id is returned or 0 in case the id could not be retrieved. - */ -static __u64 (*bpf_sk_ancestor_cgroup_id)(void *sk, int ancestor_level) = (void *) 129; - -/* - * bpf_ringbuf_output - * - * Copy *size* bytes from *data* into a ring buffer *ringbuf*. - * If **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification - * of new data availability is sent. - * If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification - * of new data availability is sent unconditionally. - * If **0** is specified in *flags*, an adaptive notification - * of new data availability is sent. - * - * An adaptive notification is a notification sent whenever the user-space - * process has caught up and consumed all available payloads. In case the user-space - * process is still processing a previous payload, then no notification is needed - * as it will process the newly added payload automatically. - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_ringbuf_output)(void *ringbuf, void *data, __u64 size, __u64 flags) = (void *) 130; - -/* - * bpf_ringbuf_reserve - * - * Reserve *size* bytes of payload in a ring buffer *ringbuf*. - * *flags* must be 0. - * - * Returns - * Valid pointer with *size* bytes of memory available; NULL, - * otherwise. - */ -static void *(*bpf_ringbuf_reserve)(void *ringbuf, __u64 size, __u64 flags) = (void *) 131; - -/* - * bpf_ringbuf_submit - * - * Submit reserved ring buffer sample, pointed to by *data*. - * If **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification - * of new data availability is sent. - * If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification - * of new data availability is sent unconditionally. - * If **0** is specified in *flags*, an adaptive notification - * of new data availability is sent. - * - * See 'bpf_ringbuf_output()' for the definition of adaptive notification. - * - * Returns - * Nothing. Always succeeds. - */ -static void (*bpf_ringbuf_submit)(void *data, __u64 flags) = (void *) 132; - -/* - * bpf_ringbuf_discard - * - * Discard reserved ring buffer sample, pointed to by *data*. - * If **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification - * of new data availability is sent. - * If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification - * of new data availability is sent unconditionally. - * If **0** is specified in *flags*, an adaptive notification - * of new data availability is sent. - * - * See 'bpf_ringbuf_output()' for the definition of adaptive notification. - * - * Returns - * Nothing. Always succeeds. - */ -static void (*bpf_ringbuf_discard)(void *data, __u64 flags) = (void *) 133; - -/* - * bpf_ringbuf_query - * - * Query various characteristics of provided ring buffer. What - * exactly is queries is determined by *flags*: - * - * * **BPF_RB_AVAIL_DATA**: Amount of data not yet consumed. - * * **BPF_RB_RING_SIZE**: The size of ring buffer. - * * **BPF_RB_CONS_POS**: Consumer position (can wrap around). - * * **BPF_RB_PROD_POS**: Producer(s) position (can wrap around). - * - * Data returned is just a momentary snapshot of actual values - * and could be inaccurate, so this facility should be used to - * power heuristics and for reporting, not to make 100% correct - * calculation. - * - * Returns - * Requested value, or 0, if *flags* are not recognized. - */ -static __u64 (*bpf_ringbuf_query)(void *ringbuf, __u64 flags) = (void *) 134; - -/* - * bpf_csum_level - * - * Change the skbs checksum level by one layer up or down, or - * reset it entirely to none in order to have the stack perform - * checksum validation. The level is applicable to the following - * protocols: TCP, UDP, GRE, SCTP, FCOE. For example, a decap of - * | ETH | IP | UDP | GUE | IP | TCP | into | ETH | IP | TCP | - * through **bpf_skb_adjust_room**\ () helper with passing in - * **BPF_F_ADJ_ROOM_NO_CSUM_RESET** flag would require one call - * to **bpf_csum_level**\ () with **BPF_CSUM_LEVEL_DEC** since - * the UDP header is removed. Similarly, an encap of the latter - * into the former could be accompanied by a helper call to - * **bpf_csum_level**\ () with **BPF_CSUM_LEVEL_INC** if the - * skb is still intended to be processed in higher layers of the - * stack instead of just egressing at tc. - * - * There are three supported level settings at this time: - * - * * **BPF_CSUM_LEVEL_INC**: Increases skb->csum_level for skbs - * with CHECKSUM_UNNECESSARY. - * * **BPF_CSUM_LEVEL_DEC**: Decreases skb->csum_level for skbs - * with CHECKSUM_UNNECESSARY. - * * **BPF_CSUM_LEVEL_RESET**: Resets skb->csum_level to 0 and - * sets CHECKSUM_NONE to force checksum validation by the stack. - * * **BPF_CSUM_LEVEL_QUERY**: No-op, returns the current - * skb->csum_level. - * - * Returns - * 0 on success, or a negative error in case of failure. In the - * case of **BPF_CSUM_LEVEL_QUERY**, the current skb->csum_level - * is returned or the error code -EACCES in case the skb is not - * subject to CHECKSUM_UNNECESSARY. - */ -static long (*bpf_csum_level)(struct __sk_buff *skb, __u64 level) = (void *) 135; - -/* - * bpf_skc_to_tcp6_sock - * - * Dynamically cast a *sk* pointer to a *tcp6_sock* pointer. - * - * Returns - * *sk* if casting is valid, or **NULL** otherwise. - */ -static struct tcp6_sock *(*bpf_skc_to_tcp6_sock)(void *sk) = (void *) 136; - -/* - * bpf_skc_to_tcp_sock - * - * Dynamically cast a *sk* pointer to a *tcp_sock* pointer. - * - * Returns - * *sk* if casting is valid, or **NULL** otherwise. - */ -static struct tcp_sock *(*bpf_skc_to_tcp_sock)(void *sk) = (void *) 137; - -/* - * bpf_skc_to_tcp_timewait_sock - * - * Dynamically cast a *sk* pointer to a *tcp_timewait_sock* pointer. - * - * Returns - * *sk* if casting is valid, or **NULL** otherwise. - */ -static struct tcp_timewait_sock *(*bpf_skc_to_tcp_timewait_sock)(void *sk) = (void *) 138; - -/* - * bpf_skc_to_tcp_request_sock - * - * Dynamically cast a *sk* pointer to a *tcp_request_sock* pointer. - * - * Returns - * *sk* if casting is valid, or **NULL** otherwise. - */ -static struct tcp_request_sock *(*bpf_skc_to_tcp_request_sock)(void *sk) = (void *) 139; - -/* - * bpf_skc_to_udp6_sock - * - * Dynamically cast a *sk* pointer to a *udp6_sock* pointer. - * - * Returns - * *sk* if casting is valid, or **NULL** otherwise. - */ -static struct udp6_sock *(*bpf_skc_to_udp6_sock)(void *sk) = (void *) 140; - -/* - * bpf_get_task_stack - * - * Return a user or a kernel stack in bpf program provided buffer. - * To achieve this, the helper needs *task*, which is a valid - * pointer to **struct task_struct**. To store the stacktrace, the - * bpf program provides *buf* with a nonnegative *size*. - * - * The last argument, *flags*, holds the number of stack frames to - * skip (from 0 to 255), masked with - * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set - * the following flags: - * - * **BPF_F_USER_STACK** - * Collect a user space stack instead of a kernel stack. - * **BPF_F_USER_BUILD_ID** - * Collect buildid+offset instead of ips for user stack, - * only valid if **BPF_F_USER_STACK** is also specified. - * - * **bpf_get_task_stack**\ () can collect up to - * **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject - * to sufficient large buffer size. Note that - * this limit can be controlled with the **sysctl** program, and - * that it should be manually increased in order to profile long - * user stacks (such as stacks for Java programs). To do so, use: - * - * :: - * - * # sysctl kernel.perf_event_max_stack= - * - * Returns - * A non-negative value equal to or less than *size* on success, - * or a negative error in case of failure. - */ -static long (*bpf_get_task_stack)(struct task_struct *task, void *buf, __u32 size, __u64 flags) = (void *) 141; - -/* - * bpf_load_hdr_opt - * - * Load header option. Support reading a particular TCP header - * option for bpf program (**BPF_PROG_TYPE_SOCK_OPS**). - * - * If *flags* is 0, it will search the option from the - * *skops*\ **->skb_data**. The comment in **struct bpf_sock_ops** - * has details on what skb_data contains under different - * *skops*\ **->op**. - * - * The first byte of the *searchby_res* specifies the - * kind that it wants to search. - * - * If the searching kind is an experimental kind - * (i.e. 253 or 254 according to RFC6994). It also - * needs to specify the "magic" which is either - * 2 bytes or 4 bytes. It then also needs to - * specify the size of the magic by using - * the 2nd byte which is "kind-length" of a TCP - * header option and the "kind-length" also - * includes the first 2 bytes "kind" and "kind-length" - * itself as a normal TCP header option also does. - * - * For example, to search experimental kind 254 with - * 2 byte magic 0xeB9F, the searchby_res should be - * [ 254, 4, 0xeB, 0x9F, 0, 0, .... 0 ]. - * - * To search for the standard window scale option (3), - * the *searchby_res* should be [ 3, 0, 0, .... 0 ]. - * Note, kind-length must be 0 for regular option. - * - * Searching for No-Op (0) and End-of-Option-List (1) are - * not supported. - * - * *len* must be at least 2 bytes which is the minimal size - * of a header option. - * - * Supported flags: - * - * * **BPF_LOAD_HDR_OPT_TCP_SYN** to search from the - * saved_syn packet or the just-received syn packet. - * - * - * Returns - * > 0 when found, the header option is copied to *searchby_res*. - * The return value is the total length copied. On failure, a - * negative error code is returned: - * - * **-EINVAL** if a parameter is invalid. - * - * **-ENOMSG** if the option is not found. - * - * **-ENOENT** if no syn packet is available when - * **BPF_LOAD_HDR_OPT_TCP_SYN** is used. - * - * **-ENOSPC** if there is not enough space. Only *len* number of - * bytes are copied. - * - * **-EFAULT** on failure to parse the header options in the - * packet. - * - * **-EPERM** if the helper cannot be used under the current - * *skops*\ **->op**. - */ -static long (*bpf_load_hdr_opt)(struct bpf_sock_ops *skops, void *searchby_res, __u32 len, __u64 flags) = (void *) 142; - -/* - * bpf_store_hdr_opt - * - * Store header option. The data will be copied - * from buffer *from* with length *len* to the TCP header. - * - * The buffer *from* should have the whole option that - * includes the kind, kind-length, and the actual - * option data. The *len* must be at least kind-length - * long. The kind-length does not have to be 4 byte - * aligned. The kernel will take care of the padding - * and setting the 4 bytes aligned value to th->doff. - * - * This helper will check for duplicated option - * by searching the same option in the outgoing skb. - * - * This helper can only be called during - * **BPF_SOCK_OPS_WRITE_HDR_OPT_CB**. - * - * - * Returns - * 0 on success, or negative error in case of failure: - * - * **-EINVAL** If param is invalid. - * - * **-ENOSPC** if there is not enough space in the header. - * Nothing has been written - * - * **-EEXIST** if the option already exists. - * - * **-EFAULT** on failrue to parse the existing header options. - * - * **-EPERM** if the helper cannot be used under the current - * *skops*\ **->op**. - */ -static long (*bpf_store_hdr_opt)(struct bpf_sock_ops *skops, const void *from, __u32 len, __u64 flags) = (void *) 143; - -/* - * bpf_reserve_hdr_opt - * - * Reserve *len* bytes for the bpf header option. The - * space will be used by **bpf_store_hdr_opt**\ () later in - * **BPF_SOCK_OPS_WRITE_HDR_OPT_CB**. - * - * If **bpf_reserve_hdr_opt**\ () is called multiple times, - * the total number of bytes will be reserved. - * - * This helper can only be called during - * **BPF_SOCK_OPS_HDR_OPT_LEN_CB**. - * - * - * Returns - * 0 on success, or negative error in case of failure: - * - * **-EINVAL** if a parameter is invalid. - * - * **-ENOSPC** if there is not enough space in the header. - * - * **-EPERM** if the helper cannot be used under the current - * *skops*\ **->op**. - */ -static long (*bpf_reserve_hdr_opt)(struct bpf_sock_ops *skops, __u32 len, __u64 flags) = (void *) 144; - -/* - * bpf_inode_storage_get - * - * Get a bpf_local_storage from an *inode*. - * - * Logically, it could be thought of as getting the value from - * a *map* with *inode* as the **key**. From this - * perspective, the usage is not much different from - * **bpf_map_lookup_elem**\ (*map*, **&**\ *inode*) except this - * helper enforces the key must be an inode and the map must also - * be a **BPF_MAP_TYPE_INODE_STORAGE**. - * - * Underneath, the value is stored locally at *inode* instead of - * the *map*. The *map* is used as the bpf-local-storage - * "type". The bpf-local-storage "type" (i.e. the *map*) is - * searched against all bpf_local_storage residing at *inode*. - * - * An optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be - * used such that a new bpf_local_storage will be - * created if one does not exist. *value* can be used - * together with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify - * the initial value of a bpf_local_storage. If *value* is - * **NULL**, the new bpf_local_storage will be zero initialized. - * - * Returns - * A bpf_local_storage pointer is returned on success. - * - * **NULL** if not found or there was an error in adding - * a new bpf_local_storage. - */ -static void *(*bpf_inode_storage_get)(void *map, void *inode, void *value, __u64 flags) = (void *) 145; - -/* - * bpf_inode_storage_delete - * - * Delete a bpf_local_storage from an *inode*. - * - * Returns - * 0 on success. - * - * **-ENOENT** if the bpf_local_storage cannot be found. - */ -static int (*bpf_inode_storage_delete)(void *map, void *inode) = (void *) 146; - -/* - * bpf_d_path - * - * Return full path for given **struct path** object, which - * needs to be the kernel BTF *path* object. The path is - * returned in the provided buffer *buf* of size *sz* and - * is zero terminated. - * - * - * Returns - * On success, the strictly positive length of the string, - * including the trailing NUL character. On error, a negative - * value. - */ -static long (*bpf_d_path)(struct path *path, char *buf, __u32 sz) = (void *) 147; - -/* - * bpf_copy_from_user - * - * Read *size* bytes from user space address *user_ptr* and store - * the data in *dst*. This is a wrapper of **copy_from_user**\ (). - * - * Returns - * 0 on success, or a negative error in case of failure. - */ -static long (*bpf_copy_from_user)(void *dst, __u32 size, const void *user_ptr) = (void *) 148; - -/* - * bpf_snprintf_btf - * - * Use BTF to store a string representation of *ptr*->ptr in *str*, - * using *ptr*->type_id. This value should specify the type - * that *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1) - * can be used to look up vmlinux BTF type ids. Traversing the - * data structure using BTF, the type information and values are - * stored in the first *str_size* - 1 bytes of *str*. Safe copy of - * the pointer data is carried out to avoid kernel crashes during - * operation. Smaller types can use string space on the stack; - * larger programs can use map data to store the string - * representation. - * - * The string can be subsequently shared with userspace via - * bpf_perf_event_output() or ring buffer interfaces. - * bpf_trace_printk() is to be avoided as it places too small - * a limit on string size to be useful. - * - * *flags* is a combination of - * - * **BTF_F_COMPACT** - * no formatting around type information - * **BTF_F_NONAME** - * no struct/union member names/types - * **BTF_F_PTR_RAW** - * show raw (unobfuscated) pointer values; - * equivalent to printk specifier %px. - * **BTF_F_ZERO** - * show zero-valued struct/union members; they - * are not displayed by default - * - * - * Returns - * The number of bytes that were written (or would have been - * written if output had to be truncated due to string size), - * or a negative error in cases of failure. - */ -static long (*bpf_snprintf_btf)(char *str, __u32 str_size, struct btf_ptr *ptr, __u32 btf_ptr_size, __u64 flags) = (void *) 149; - -/* - * bpf_seq_printf_btf - * - * Use BTF to write to seq_write a string representation of - * *ptr*->ptr, using *ptr*->type_id as per bpf_snprintf_btf(). - * *flags* are identical to those used for bpf_snprintf_btf. - * - * Returns - * 0 on success or a negative error in case of failure. - */ -static long (*bpf_seq_printf_btf)(struct seq_file *m, struct btf_ptr *ptr, __u32 ptr_size, __u64 flags) = (void *) 150; - -/* - * bpf_skb_cgroup_classid - * - * See **bpf_get_cgroup_classid**\ () for the main description. - * This helper differs from **bpf_get_cgroup_classid**\ () in that - * the cgroup v1 net_cls class is retrieved only from the *skb*'s - * associated socket instead of the current process. - * - * Returns - * The id is returned or 0 in case the id could not be retrieved. - */ -static __u64 (*bpf_skb_cgroup_classid)(struct __sk_buff *skb) = (void *) 151; - -/* - * bpf_redirect_neigh - * - * Redirect the packet to another net device of index *ifindex* - * and fill in L2 addresses from neighboring subsystem. This helper - * is somewhat similar to **bpf_redirect**\ (), except that it - * populates L2 addresses as well, meaning, internally, the helper - * relies on the neighbor lookup for the L2 address of the nexthop. - * - * The helper will perform a FIB lookup based on the skb's - * networking header to get the address of the next hop, unless - * this is supplied by the caller in the *params* argument. The - * *plen* argument indicates the len of *params* and should be set - * to 0 if *params* is NULL. - * - * The *flags* argument is reserved and must be 0. The helper is - * currently only supported for tc BPF program types, and enabled - * for IPv4 and IPv6 protocols. - * - * Returns - * The helper returns **TC_ACT_REDIRECT** on success or - * **TC_ACT_SHOT** on error. - */ -static long (*bpf_redirect_neigh)(__u32 ifindex, struct bpf_redir_neigh *params, int plen, __u64 flags) = (void *) 152; - -/* - * bpf_per_cpu_ptr - * - * Take a pointer to a percpu ksym, *percpu_ptr*, and return a - * pointer to the percpu kernel variable on *cpu*. A ksym is an - * extern variable decorated with '__ksym'. For ksym, there is a - * global var (either static or global) defined of the same name - * in the kernel. The ksym is percpu if the global var is percpu. - * The returned pointer points to the global percpu var on *cpu*. - * - * bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the - * kernel, except that bpf_per_cpu_ptr() may return NULL. This - * happens if *cpu* is larger than nr_cpu_ids. The caller of - * bpf_per_cpu_ptr() must check the returned value. - * - * Returns - * A pointer pointing to the kernel percpu variable on *cpu*, or - * NULL, if *cpu* is invalid. - */ -static void *(*bpf_per_cpu_ptr)(const void *percpu_ptr, __u32 cpu) = (void *) 153; - -/* - * bpf_this_cpu_ptr - * - * Take a pointer to a percpu ksym, *percpu_ptr*, and return a - * pointer to the percpu kernel variable on this cpu. See the - * description of 'ksym' in **bpf_per_cpu_ptr**\ (). - * - * bpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in - * the kernel. Different from **bpf_per_cpu_ptr**\ (), it would - * never return NULL. - * - * Returns - * A pointer pointing to the kernel percpu variable on this cpu. - */ -static void *(*bpf_this_cpu_ptr)(const void *percpu_ptr) = (void *) 154; - -/* - * bpf_redirect_peer - * - * Redirect the packet to another net device of index *ifindex*. - * This helper is somewhat similar to **bpf_redirect**\ (), except - * that the redirection happens to the *ifindex*' peer device and - * the netns switch takes place from ingress to ingress without - * going through the CPU's backlog queue. - * - * The *flags* argument is reserved and must be 0. The helper is - * currently only supported for tc BPF program types at the ingress - * hook and for veth device types. The peer device must reside in a - * different network namespace. - * - * Returns - * The helper returns **TC_ACT_REDIRECT** on success or - * **TC_ACT_SHOT** on error. - */ -static long (*bpf_redirect_peer)(__u32 ifindex, __u64 flags) = (void *) 155; - -/* - * bpf_task_storage_get - * - * Get a bpf_local_storage from the *task*. - * - * Logically, it could be thought of as getting the value from - * a *map* with *task* as the **key**. From this - * perspective, the usage is not much different from - * **bpf_map_lookup_elem**\ (*map*, **&**\ *task*) except this - * helper enforces the key must be an task_struct and the map must also - * be a **BPF_MAP_TYPE_TASK_STORAGE**. - * - * Underneath, the value is stored locally at *task* instead of - * the *map*. The *map* is used as the bpf-local-storage - * "type". The bpf-local-storage "type" (i.e. the *map*) is - * searched against all bpf_local_storage residing at *task*. - * - * An optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be - * used such that a new bpf_local_storage will be - * created if one does not exist. *value* can be used - * together with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify - * the initial value of a bpf_local_storage. If *value* is - * **NULL**, the new bpf_local_storage will be zero initialized. - * - * Returns - * A bpf_local_storage pointer is returned on success. - * - * **NULL** if not found or there was an error in adding - * a new bpf_local_storage. - */ -static void *(*bpf_task_storage_get)(void *map, struct task_struct *task, void *value, __u64 flags) = (void *) 156; - -/* - * bpf_task_storage_delete - * - * Delete a bpf_local_storage from a *task*. - * - * Returns - * 0 on success. - * - * **-ENOENT** if the bpf_local_storage cannot be found. - */ -static long (*bpf_task_storage_delete)(void *map, struct task_struct *task) = (void *) 157; - -/* - * bpf_get_current_task_btf - * - * Return a BTF pointer to the "current" task. - * This pointer can also be used in helpers that accept an - * *ARG_PTR_TO_BTF_ID* of type *task_struct*. - * - * Returns - * Pointer to the current task. - */ -static struct task_struct *(*bpf_get_current_task_btf)(void) = (void *) 158; - -/* - * bpf_bprm_opts_set - * - * Set or clear certain options on *bprm*: - * - * **BPF_F_BPRM_SECUREEXEC** Set the secureexec bit - * which sets the **AT_SECURE** auxv for glibc. The bit - * is cleared if the flag is not specified. - * - * Returns - * **-EINVAL** if invalid *flags* are passed, zero otherwise. - */ -static long (*bpf_bprm_opts_set)(struct linux_binprm *bprm, __u64 flags) = (void *) 159; - -/* - * bpf_ktime_get_coarse_ns - * - * Return a coarse-grained version of the time elapsed since - * system boot, in nanoseconds. Does not include time the system - * was suspended. - * - * See: **clock_gettime**\ (**CLOCK_MONOTONIC_COARSE**) - * - * Returns - * Current *ktime*. - */ -static __u64 (*bpf_ktime_get_coarse_ns)(void) = (void *) 160; - -/* - * bpf_ima_inode_hash - * - * Returns the stored IMA hash of the *inode* (if it's avaialable). - * If the hash is larger than *size*, then only *size* - * bytes will be copied to *dst* - * - * Returns - * The **hash_algo** is returned on success, - * **-EOPNOTSUP** if IMA is disabled or **-EINVAL** if - * invalid arguments are passed. - */ -static long (*bpf_ima_inode_hash)(struct inode *inode, void *dst, __u32 size) = (void *) 161; - -/* - * bpf_sock_from_file - * - * If the given file represents a socket, returns the associated - * socket. - * - * Returns - * A pointer to a struct socket on success or NULL if the file is - * not a socket. - */ -static struct socket *(*bpf_sock_from_file)(struct file *file) = (void *) 162; - -/* - * bpf_check_mtu - * - * Check packet size against exceeding MTU of net device (based - * on *ifindex*). This helper will likely be used in combination - * with helpers that adjust/change the packet size. - * - * The argument *len_diff* can be used for querying with a planned - * size change. This allows to check MTU prior to changing packet - * ctx. Providing an *len_diff* adjustment that is larger than the - * actual packet size (resulting in negative packet size) will in - * principle not exceed the MTU, why it is not considered a - * failure. Other BPF-helpers are needed for performing the - * planned size change, why the responsibility for catch a negative - * packet size belong in those helpers. - * - * Specifying *ifindex* zero means the MTU check is performed - * against the current net device. This is practical if this isn't - * used prior to redirect. - * - * On input *mtu_len* must be a valid pointer, else verifier will - * reject BPF program. If the value *mtu_len* is initialized to - * zero then the ctx packet size is use. When value *mtu_len* is - * provided as input this specify the L3 length that the MTU check - * is done against. Remember XDP and TC length operate at L2, but - * this value is L3 as this correlate to MTU and IP-header tot_len - * values which are L3 (similar behavior as bpf_fib_lookup). - * - * The Linux kernel route table can configure MTUs on a more - * specific per route level, which is not provided by this helper. - * For route level MTU checks use the **bpf_fib_lookup**\ () - * helper. - * - * *ctx* is either **struct xdp_md** for XDP programs or - * **struct sk_buff** for tc cls_act programs. - * - * The *flags* argument can be a combination of one or more of the - * following values: - * - * **BPF_MTU_CHK_SEGS** - * This flag will only works for *ctx* **struct sk_buff**. - * If packet context contains extra packet segment buffers - * (often knows as GSO skb), then MTU check is harder to - * check at this point, because in transmit path it is - * possible for the skb packet to get re-segmented - * (depending on net device features). This could still be - * a MTU violation, so this flag enables performing MTU - * check against segments, with a different violation - * return code to tell it apart. Check cannot use len_diff. - * - * On return *mtu_len* pointer contains the MTU value of the net - * device. Remember the net device configured MTU is the L3 size, - * which is returned here and XDP and TC length operate at L2. - * Helper take this into account for you, but remember when using - * MTU value in your BPF-code. - * - * - * Returns - * * 0 on success, and populate MTU value in *mtu_len* pointer. - * - * * < 0 if any input argument is invalid (*mtu_len* not updated) - * - * MTU violations return positive values, but also populate MTU - * value in *mtu_len* pointer, as this can be needed for - * implementing PMTU handing: - * - * * **BPF_MTU_CHK_RET_FRAG_NEEDED** - * * **BPF_MTU_CHK_RET_SEGS_TOOBIG** - */ -static long (*bpf_check_mtu)(void *ctx, __u32 ifindex, __u32 *mtu_len, __s32 len_diff, __u64 flags) = (void *) 163; - -/* - * bpf_for_each_map_elem - * - * For each element in **map**, call **callback_fn** function with - * **map**, **callback_ctx** and other map-specific parameters. - * The **callback_fn** should be a static function and - * the **callback_ctx** should be a pointer to the stack. - * The **flags** is used to control certain aspects of the helper. - * Currently, the **flags** must be 0. - * - * The following are a list of supported map types and their - * respective expected callback signatures: - * - * BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_PERCPU_HASH, - * BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH, - * BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PERCPU_ARRAY - * - * long (\*callback_fn)(struct bpf_map \*map, const void \*key, void \*value, void \*ctx); - * - * For per_cpu maps, the map_value is the value on the cpu where the - * bpf_prog is running. - * - * If **callback_fn** return 0, the helper will continue to the next - * element. If return value is 1, the helper will skip the rest of - * elements and return. Other return values are not used now. - * - * - * Returns - * The number of traversed map elements for success, **-EINVAL** for - * invalid **flags**. - */ -static long (*bpf_for_each_map_elem)(void *map, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 164; - -/* - * bpf_snprintf - * - * Outputs a string into the **str** buffer of size **str_size** - * based on a format string stored in a read-only map pointed by - * **fmt**. - * - * Each format specifier in **fmt** corresponds to one u64 element - * in the **data** array. For strings and pointers where pointees - * are accessed, only the pointer values are stored in the *data* - * array. The *data_len* is the size of *data* in bytes - must be - * a multiple of 8. - * - * Formats **%s** and **%p{i,I}{4,6}** require to read kernel - * memory. Reading kernel memory may fail due to either invalid - * address or valid address but requiring a major memory fault. If - * reading kernel memory fails, the string for **%s** will be an - * empty string, and the ip address for **%p{i,I}{4,6}** will be 0. - * Not returning error to bpf program is consistent with what - * **bpf_trace_printk**\ () does for now. - * - * - * Returns - * The strictly positive length of the formatted string, including - * the trailing zero character. If the return value is greater than - * **str_size**, **str** contains a truncated string, guaranteed to - * be zero-terminated except when **str_size** is 0. - * - * Or **-EBUSY** if the per-CPU memory copy buffer is busy. - */ -static long (*bpf_snprintf)(char *str, __u32 str_size, const char *fmt, __u64 *data, __u32 data_len) = (void *) 165; - -/* - * bpf_sys_bpf - * - * Execute bpf syscall with given arguments. - * - * Returns - * A syscall result. - */ -static long (*bpf_sys_bpf)(__u32 cmd, void *attr, __u32 attr_size) = (void *) 166; - -/* - * bpf_btf_find_by_name_kind - * - * Find BTF type with given name and kind in vmlinux BTF or in module's BTFs. - * - * Returns - * Returns btf_id and btf_obj_fd in lower and upper 32 bits. - */ -static long (*bpf_btf_find_by_name_kind)(char *name, int name_sz, __u32 kind, int flags) = (void *) 167; - -/* - * bpf_sys_close - * - * Execute close syscall for given FD. - * - * Returns - * A syscall result. - */ -static long (*bpf_sys_close)(__u32 fd) = (void *) 168; - -/* - * bpf_timer_init - * - * Initialize the timer. - * First 4 bits of *flags* specify clockid. - * Only CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed. - * All other bits of *flags* are reserved. - * The verifier will reject the program if *timer* is not from - * the same *map*. - * - * Returns - * 0 on success. - * **-EBUSY** if *timer* is already initialized. - * **-EINVAL** if invalid *flags* are passed. - * **-EPERM** if *timer* is in a map that doesn't have any user references. - * The user space should either hold a file descriptor to a map with timers - * or pin such map in bpffs. When map is unpinned or file descriptor is - * closed all timers in the map will be cancelled and freed. - */ -static long (*bpf_timer_init)(struct bpf_timer *timer, void *map, __u64 flags) = (void *) 169; - -/* - * bpf_timer_set_callback - * - * Configure the timer to call *callback_fn* static function. - * - * Returns - * 0 on success. - * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier. - * **-EPERM** if *timer* is in a map that doesn't have any user references. - * The user space should either hold a file descriptor to a map with timers - * or pin such map in bpffs. When map is unpinned or file descriptor is - * closed all timers in the map will be cancelled and freed. - */ -static long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn) = (void *) 170; - -/* - * bpf_timer_start - * - * Set timer expiration N nanoseconds from the current time. The - * configured callback will be invoked in soft irq context on some cpu - * and will not repeat unless another bpf_timer_start() is made. - * In such case the next invocation can migrate to a different cpu. - * Since struct bpf_timer is a field inside map element the map - * owns the timer. The bpf_timer_set_callback() will increment refcnt - * of BPF program to make sure that callback_fn code stays valid. - * When user space reference to a map reaches zero all timers - * in a map are cancelled and corresponding program's refcnts are - * decremented. This is done to make sure that Ctrl-C of a user - * process doesn't leave any timers running. If map is pinned in - * bpffs the callback_fn can re-arm itself indefinitely. - * bpf_map_update/delete_elem() helpers and user space sys_bpf commands - * cancel and free the timer in the given map element. - * The map can contain timers that invoke callback_fn-s from different - * programs. The same callback_fn can serve different timers from - * different maps if key/value layout matches across maps. - * Every bpf_timer_set_callback() can have different callback_fn. - * - * - * Returns - * 0 on success. - * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier - * or invalid *flags* are passed. - */ -static long (*bpf_timer_start)(struct bpf_timer *timer, __u64 nsecs, __u64 flags) = (void *) 171; - -/* - * bpf_timer_cancel - * - * Cancel the timer and wait for callback_fn to finish if it was running. - * - * Returns - * 0 if the timer was not active. - * 1 if the timer was active. - * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier. - * **-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its - * own timer which would have led to a deadlock otherwise. - */ -static long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *) 172; - -/* - * bpf_get_func_ip - * - * Get address of the traced function (for tracing and kprobe programs). - * - * Returns - * Address of the traced function. - */ -static __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173; - -/* - * bpf_get_attach_cookie - * - * Get bpf_cookie value provided (optionally) during the program - * attachment. It might be different for each individual - * attachment, even if BPF program itself is the same. - * Expects BPF program context *ctx* as a first argument. - * - * Supported for the following program types: - * - kprobe/uprobe; - * - tracepoint; - * - perf_event. - * - * Returns - * Value specified by user at BPF link creation/attachment time - * or 0, if it was not specified. - */ -static __u64 (*bpf_get_attach_cookie)(void *ctx) = (void *) 174; - -/* - * bpf_task_pt_regs - * - * Get the struct pt_regs associated with **task**. - * - * Returns - * A pointer to struct pt_regs. - */ -static long (*bpf_task_pt_regs)(struct task_struct *task) = (void *) 175; - -/* - * bpf_get_branch_snapshot - * - * Get branch trace from hardware engines like Intel LBR. The - * hardware engine is stopped shortly after the helper is - * called. Therefore, the user need to filter branch entries - * based on the actual use case. To capture branch trace - * before the trigger point of the BPF program, the helper - * should be called at the beginning of the BPF program. - * - * The data is stored as struct perf_branch_entry into output - * buffer *entries*. *size* is the size of *entries* in bytes. - * *flags* is reserved for now and must be zero. - * - * - * Returns - * On success, number of bytes written to *buf*. On error, a - * negative value. - * - * **-EINVAL** if *flags* is not zero. - * - * **-ENOENT** if architecture does not support branch records. - */ -static long (*bpf_get_branch_snapshot)(void *entries, __u32 size, __u64 flags) = (void *) 176; - -/* - * bpf_trace_vprintk - * - * Behaves like **bpf_trace_printk**\ () helper, but takes an array of u64 - * to format and can handle more format args as a result. - * - * Arguments are to be used as in **bpf_seq_printf**\ () helper. - * - * Returns - * The number of bytes written to the buffer, or a negative error - * in case of failure. - */ -static long (*bpf_trace_vprintk)(const char *fmt, __u32 fmt_size, const void *data, __u32 data_len) = (void *) 177; - -/* - * bpf_skc_to_unix_sock - * - * Dynamically cast a *sk* pointer to a *unix_sock* pointer. - * - * Returns - * *sk* if casting is valid, or **NULL** otherwise. - */ -static struct unix_sock *(*bpf_skc_to_unix_sock)(void *sk) = (void *) 178; - -/* - * bpf_kallsyms_lookup_name - * - * Get the address of a kernel symbol, returned in *res*. *res* is - * set to 0 if the symbol is not found. - * - * Returns - * On success, zero. On error, a negative value. - * - * **-EINVAL** if *flags* is not zero. - * - * **-EINVAL** if string *name* is not the same size as *name_sz*. - * - * **-ENOENT** if symbol is not found. - * - * **-EPERM** if caller does not have permission to obtain kernel address. - */ -static long (*bpf_kallsyms_lookup_name)(const char *name, int name_sz, int flags, __u64 *res) = (void *) 179; - -/* - * bpf_find_vma - * - * Find vma of *task* that contains *addr*, call *callback_fn* - * function with *task*, *vma*, and *callback_ctx*. - * The *callback_fn* should be a static function and - * the *callback_ctx* should be a pointer to the stack. - * The *flags* is used to control certain aspects of the helper. - * Currently, the *flags* must be 0. - * - * The expected callback signature is - * - * long (\*callback_fn)(struct task_struct \*task, struct vm_area_struct \*vma, void \*callback_ctx); - * - * - * Returns - * 0 on success. - * **-ENOENT** if *task->mm* is NULL, or no vma contains *addr*. - * **-EBUSY** if failed to try lock mmap_lock. - * **-EINVAL** for invalid **flags**. - */ -static long (*bpf_find_vma)(struct task_struct *task, __u64 addr, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 180; - - diff --git a/ebpf/bpf/libbpf/bpf_helpers.h b/ebpf/bpf/libbpf/bpf_helpers.h deleted file mode 100644 index 963b1060d9..0000000000 --- a/ebpf/bpf/libbpf/bpf_helpers.h +++ /dev/null @@ -1,262 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#ifndef __BPF_HELPERS__ -#define __BPF_HELPERS__ - -/* - * Note that bpf programs need to include either - * vmlinux.h (auto-generated from BTF) or linux/types.h - * in advance since bpf_helper_defs.h uses such types - * as __u64. - */ -#include "bpf_helper_defs.h" - -#define __uint(name, val) int (*name)[val] -#define __type(name, val) typeof(val) *name -#define __array(name, val) typeof(val) *name[] - -/* - * Helper macro to place programs, maps, license in - * different sections in elf_bpf file. Section names - * are interpreted by libbpf depending on the context (BPF programs, BPF maps, - * extern variables, etc). - * To allow use of SEC() with externs (e.g., for extern .maps declarations), - * make sure __attribute__((unused)) doesn't trigger compilation warning. - */ -#define SEC(name) \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \ - __attribute__((section(name), used)) \ - _Pragma("GCC diagnostic pop") \ - -/* Avoid 'linux/stddef.h' definition of '__always_inline'. */ -#undef __always_inline -#define __always_inline inline __attribute__((always_inline)) - -#ifndef __noinline -#define __noinline __attribute__((noinline)) -#endif -#ifndef __weak -#define __weak __attribute__((weak)) -#endif - -/* - * Use __hidden attribute to mark a non-static BPF subprogram effectively - * static for BPF verifier's verification algorithm purposes, allowing more - * extensive and permissive BPF verification process, taking into account - * subprogram's caller context. - */ -#define __hidden __attribute__((visibility("hidden"))) - -/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include - * any system-level headers (such as stddef.h, linux/version.h, etc), and - * commonly-used macros like NULL and KERNEL_VERSION aren't available through - * vmlinux.h. This just adds unnecessary hurdles and forces users to re-define - * them on their own. So as a convenience, provide such definitions here. - */ -#ifndef NULL -#define NULL ((void *)0) -#endif - -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c))) -#endif - -/* - * Helper macros to manipulate data structures - */ -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER) -#endif -#ifndef container_of -#define container_of(ptr, type, member) \ - ({ \ - void *__mptr = (void *)(ptr); \ - ((type *)(__mptr - offsetof(type, member))); \ - }) -#endif - -/* - * Helper macro to throw a compilation error if __bpf_unreachable() gets - * built into the resulting code. This works given BPF back end does not - * implement __builtin_trap(). This is useful to assert that certain paths - * of the program code are never used and hence eliminated by the compiler. - * - * For example, consider a switch statement that covers known cases used by - * the program. __bpf_unreachable() can then reside in the default case. If - * the program gets extended such that a case is not covered in the switch - * statement, then it will throw a build error due to the default case not - * being compiled out. - */ -#ifndef __bpf_unreachable -# define __bpf_unreachable() __builtin_trap() -#endif - -/* - * Helper function to perform a tail call with a constant/immediate map slot. - */ -#if __clang_major__ >= 8 && defined(__bpf__) -static __always_inline void -bpf_tail_call_static(void *ctx, const void *map, const __u32 slot) -{ - if (!__builtin_constant_p(slot)) - __bpf_unreachable(); - - /* - * Provide a hard guarantee that LLVM won't optimize setting r2 (map - * pointer) and r3 (constant map index) from _different paths_ ending - * up at the _same_ call insn as otherwise we won't be able to use the - * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel - * given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key - * tracking for prog array pokes") for details on verifier tracking. - * - * Note on clobber list: we need to stay in-line with BPF calling - * convention, so even if we don't end up using r0, r4, r5, we need - * to mark them as clobber so that LLVM doesn't end up using them - * before / after the call. - */ - asm volatile("r1 = %[ctx]\n\t" - "r2 = %[map]\n\t" - "r3 = %[slot]\n\t" - "call 12" - :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot) - : "r0", "r1", "r2", "r3", "r4", "r5"); -} -#endif - -/* - * Helper structure used by eBPF C program - * to describe BPF map attributes to libbpf loader - */ -struct bpf_map_def { - unsigned int type; - unsigned int key_size; - unsigned int value_size; - unsigned int max_entries; - unsigned int map_flags; -}; - -enum libbpf_pin_type { - LIBBPF_PIN_NONE, - /* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */ - LIBBPF_PIN_BY_NAME, -}; - -enum libbpf_tristate { - TRI_NO = 0, - TRI_YES = 1, - TRI_MODULE = 2, -}; - -#define __kconfig __attribute__((section(".kconfig"))) -#define __ksym __attribute__((section(".ksyms"))) - -#ifndef ___bpf_concat -#define ___bpf_concat(a, b) a ## b -#endif -#ifndef ___bpf_apply -#define ___bpf_apply(fn, n) ___bpf_concat(fn, n) -#endif -#ifndef ___bpf_nth -#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N -#endif -#ifndef ___bpf_narg -#define ___bpf_narg(...) \ - ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#endif - -#define ___bpf_fill0(arr, p, x) do {} while (0) -#define ___bpf_fill1(arr, p, x) arr[p] = x -#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args) -#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args) -#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args) -#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args) -#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args) -#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args) -#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args) -#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args) -#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args) -#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args) -#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args) -#define ___bpf_fill(arr, args...) \ - ___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args) - -/* - * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values - * in a structure. - */ -#define BPF_SEQ_PRINTF(seq, fmt, args...) \ -({ \ - static const char ___fmt[] = fmt; \ - unsigned long long ___param[___bpf_narg(args)]; \ - \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - ___bpf_fill(___param, args); \ - _Pragma("GCC diagnostic pop") \ - \ - bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \ - ___param, sizeof(___param)); \ -}) - -/* - * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of - * an array of u64. - */ -#define BPF_SNPRINTF(out, out_size, fmt, args...) \ -({ \ - static const char ___fmt[] = fmt; \ - unsigned long long ___param[___bpf_narg(args)]; \ - \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - ___bpf_fill(___param, args); \ - _Pragma("GCC diagnostic pop") \ - \ - bpf_snprintf(out, out_size, ___fmt, \ - ___param, sizeof(___param)); \ -}) - -#ifdef BPF_NO_GLOBAL_DATA -#define BPF_PRINTK_FMT_MOD -#else -#define BPF_PRINTK_FMT_MOD static const -#endif - -#define __bpf_printk(fmt, ...) \ -({ \ - BPF_PRINTK_FMT_MOD char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - -/* - * __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments - * instead of an array of u64. - */ -#define __bpf_vprintk(fmt, args...) \ -({ \ - static const char ___fmt[] = fmt; \ - unsigned long long ___param[___bpf_narg(args)]; \ - \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - ___bpf_fill(___param, args); \ - _Pragma("GCC diagnostic pop") \ - \ - bpf_trace_vprintk(___fmt, sizeof(___fmt), \ - ___param, sizeof(___param)); \ -}) - -/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args - * Otherwise use __bpf_vprintk - */ -#define ___bpf_pick_printk(...) \ - ___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \ - __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \ - __bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\ - __bpf_printk /*1*/, __bpf_printk /*0*/) - -/* Helper macro to print out debug messages */ -#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args) - -#endif diff --git a/ebpf/bpf/libbpf/bpf_tracing.h b/ebpf/bpf/libbpf/bpf_tracing.h deleted file mode 100644 index db05a59371..0000000000 --- a/ebpf/bpf/libbpf/bpf_tracing.h +++ /dev/null @@ -1,492 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#ifndef __BPF_TRACING_H__ -#define __BPF_TRACING_H__ - -/* Scan the ARCH passed in from ARCH env variable (see Makefile) */ -#if defined(__TARGET_ARCH_x86) - #define bpf_target_x86 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_s390) - #define bpf_target_s390 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_arm) - #define bpf_target_arm - #define bpf_target_defined -#elif defined(__TARGET_ARCH_arm64) - #define bpf_target_arm64 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_mips) - #define bpf_target_mips - #define bpf_target_defined -#elif defined(__TARGET_ARCH_powerpc) - #define bpf_target_powerpc - #define bpf_target_defined -#elif defined(__TARGET_ARCH_sparc) - #define bpf_target_sparc - #define bpf_target_defined -#elif defined(__TARGET_ARCH_riscv) - #define bpf_target_riscv - #define bpf_target_defined -#else - -/* Fall back to what the compiler says */ -#if defined(__x86_64__) - #define bpf_target_x86 - #define bpf_target_defined -#elif defined(__s390__) - #define bpf_target_s390 - #define bpf_target_defined -#elif defined(__arm__) - #define bpf_target_arm - #define bpf_target_defined -#elif defined(__aarch64__) - #define bpf_target_arm64 - #define bpf_target_defined -#elif defined(__mips__) - #define bpf_target_mips - #define bpf_target_defined -#elif defined(__powerpc__) - #define bpf_target_powerpc - #define bpf_target_defined -#elif defined(__sparc__) - #define bpf_target_sparc - #define bpf_target_defined -#elif defined(__riscv) && __riscv_xlen == 64 - #define bpf_target_riscv - #define bpf_target_defined -#endif /* no compiler target */ - -#endif - -#ifndef __BPF_TARGET_MISSING -#define __BPF_TARGET_MISSING "GCC error \"Must specify a BPF target arch via __TARGET_ARCH_xxx\"" -#endif - -#if defined(bpf_target_x86) - -#if defined(__KERNEL__) || defined(__VMLINUX_H__) - -#define PT_REGS_PARM1(x) ((x)->di) -#define PT_REGS_PARM2(x) ((x)->si) -#define PT_REGS_PARM3(x) ((x)->dx) -#define PT_REGS_PARM4(x) ((x)->cx) -#define PT_REGS_PARM5(x) ((x)->r8) -#define PT_REGS_RET(x) ((x)->sp) -#define PT_REGS_FP(x) ((x)->bp) -#define PT_REGS_RC(x) ((x)->ax) -#define PT_REGS_SP(x) ((x)->sp) -#define PT_REGS_IP(x) ((x)->ip) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), di) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), si) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), dx) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), cx) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), sp) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), bp) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), ax) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), ip) - -#else - -#ifdef __i386__ -/* i386 kernel is built with -mregparm=3 */ -#define PT_REGS_PARM1(x) ((x)->eax) -#define PT_REGS_PARM2(x) ((x)->edx) -#define PT_REGS_PARM3(x) ((x)->ecx) -#define PT_REGS_PARM4(x) 0 -#define PT_REGS_PARM5(x) 0 -#define PT_REGS_RET(x) ((x)->esp) -#define PT_REGS_FP(x) ((x)->ebp) -#define PT_REGS_RC(x) ((x)->eax) -#define PT_REGS_SP(x) ((x)->esp) -#define PT_REGS_IP(x) ((x)->eip) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), eax) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), edx) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), ecx) -#define PT_REGS_PARM4_CORE(x) 0 -#define PT_REGS_PARM5_CORE(x) 0 -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), esp) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), ebp) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), eax) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), esp) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), eip) - -#else - -#define PT_REGS_PARM1(x) ((x)->rdi) -#define PT_REGS_PARM2(x) ((x)->rsi) -#define PT_REGS_PARM3(x) ((x)->rdx) -#define PT_REGS_PARM4(x) ((x)->rcx) -#define PT_REGS_PARM5(x) ((x)->r8) -#define PT_REGS_RET(x) ((x)->rsp) -#define PT_REGS_FP(x) ((x)->rbp) -#define PT_REGS_RC(x) ((x)->rax) -#define PT_REGS_SP(x) ((x)->rsp) -#define PT_REGS_IP(x) ((x)->rip) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), rdi) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), rsi) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), rdx) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), rcx) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), rsp) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), rbp) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), rax) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), rsp) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), rip) - -#endif -#endif - -#elif defined(bpf_target_s390) - -/* s390 provides user_pt_regs instead of struct pt_regs to userspace */ -struct pt_regs; -#define PT_REGS_S390 const volatile user_pt_regs -#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2]) -#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3]) -#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4]) -#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5]) -#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6]) -#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14]) -/* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11]) -#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2]) -#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15]) -#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2]) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[3]) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[4]) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[5]) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[6]) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[14]) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[11]) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2]) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[15]) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), psw.addr) - -#elif defined(bpf_target_arm) - -#define PT_REGS_PARM1(x) ((x)->uregs[0]) -#define PT_REGS_PARM2(x) ((x)->uregs[1]) -#define PT_REGS_PARM3(x) ((x)->uregs[2]) -#define PT_REGS_PARM4(x) ((x)->uregs[3]) -#define PT_REGS_PARM5(x) ((x)->uregs[4]) -#define PT_REGS_RET(x) ((x)->uregs[14]) -#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_RC(x) ((x)->uregs[0]) -#define PT_REGS_SP(x) ((x)->uregs[13]) -#define PT_REGS_IP(x) ((x)->uregs[12]) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), uregs[0]) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), uregs[1]) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), uregs[2]) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), uregs[3]) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), uregs[4]) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), uregs[14]) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), uregs[11]) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), uregs[0]) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), uregs[13]) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), uregs[12]) - -#elif defined(bpf_target_arm64) - -/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */ -struct pt_regs; -#define PT_REGS_ARM64 const volatile struct user_pt_regs -#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0]) -#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1]) -#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2]) -#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3]) -#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4]) -#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30]) -/* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29]) -#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0]) -#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp) -#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0]) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[1]) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[2]) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[3]) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[4]) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[30]) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[29]) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0]) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), sp) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), pc) - -#elif defined(bpf_target_mips) - -#define PT_REGS_PARM1(x) ((x)->regs[4]) -#define PT_REGS_PARM2(x) ((x)->regs[5]) -#define PT_REGS_PARM3(x) ((x)->regs[6]) -#define PT_REGS_PARM4(x) ((x)->regs[7]) -#define PT_REGS_PARM5(x) ((x)->regs[8]) -#define PT_REGS_RET(x) ((x)->regs[31]) -#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_RC(x) ((x)->regs[2]) -#define PT_REGS_SP(x) ((x)->regs[29]) -#define PT_REGS_IP(x) ((x)->cp0_epc) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), regs[4]) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), regs[5]) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), regs[6]) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), regs[7]) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), regs[8]) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), regs[31]) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), regs[30]) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), regs[2]) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), regs[29]) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), cp0_epc) - -#elif defined(bpf_target_powerpc) - -#define PT_REGS_PARM1(x) ((x)->gpr[3]) -#define PT_REGS_PARM2(x) ((x)->gpr[4]) -#define PT_REGS_PARM3(x) ((x)->gpr[5]) -#define PT_REGS_PARM4(x) ((x)->gpr[6]) -#define PT_REGS_PARM5(x) ((x)->gpr[7]) -#define PT_REGS_RC(x) ((x)->gpr[3]) -#define PT_REGS_SP(x) ((x)->sp) -#define PT_REGS_IP(x) ((x)->nip) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), gpr[3]) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), gpr[4]) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), gpr[5]) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), gpr[6]) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), gpr[7]) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), gpr[3]) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), nip) - -#elif defined(bpf_target_sparc) - -#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) -#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) -#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) -#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) -#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) -#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) -#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) -#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0]) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I1]) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I2]) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I3]) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I4]) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I7]) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0]) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), u_regs[UREG_FP]) - -/* Should this also be a bpf_target check for the sparc case? */ -#if defined(__arch64__) -#define PT_REGS_IP(x) ((x)->tpc) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), tpc) -#else -#define PT_REGS_IP(x) ((x)->pc) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), pc) -#endif - -#elif defined(bpf_target_riscv) - -struct pt_regs; -#define PT_REGS_RV const volatile struct user_regs_struct -#define PT_REGS_PARM1(x) (((PT_REGS_RV *)(x))->a0) -#define PT_REGS_PARM2(x) (((PT_REGS_RV *)(x))->a1) -#define PT_REGS_PARM3(x) (((PT_REGS_RV *)(x))->a2) -#define PT_REGS_PARM4(x) (((PT_REGS_RV *)(x))->a3) -#define PT_REGS_PARM5(x) (((PT_REGS_RV *)(x))->a4) -#define PT_REGS_RET(x) (((PT_REGS_RV *)(x))->ra) -#define PT_REGS_FP(x) (((PT_REGS_RV *)(x))->s5) -#define PT_REGS_RC(x) (((PT_REGS_RV *)(x))->a5) -#define PT_REGS_SP(x) (((PT_REGS_RV *)(x))->sp) -#define PT_REGS_IP(x) (((PT_REGS_RV *)(x))->epc) - -#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a0) -#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a1) -#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a2) -#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a3) -#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a4) -#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), ra) -#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), fp) -#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a5) -#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), sp) -#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), epc) - -#endif - -#if defined(bpf_target_powerpc) -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) -#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP -#elif defined(bpf_target_sparc) -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) -#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP -#elif defined(bpf_target_defined) -#define BPF_KPROBE_READ_RET_IP(ip, ctx) \ - ({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) -#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \ - ({ bpf_probe_read_kernel(&(ip), sizeof(ip), \ - (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) -#endif - -#if !defined(bpf_target_defined) - -#define PT_REGS_PARM1(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM2(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_SP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_IP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) - -#define PT_REGS_PARM1_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM2_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_SP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define PT_REGS_IP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) - -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) -#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) - -#endif /* !defined(bpf_target_defined) */ - -#ifndef ___bpf_concat -#define ___bpf_concat(a, b) a ## b -#endif -#ifndef ___bpf_apply -#define ___bpf_apply(fn, n) ___bpf_concat(fn, n) -#endif -#ifndef ___bpf_nth -#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N -#endif -#ifndef ___bpf_narg -#define ___bpf_narg(...) \ - ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#endif - -#define ___bpf_ctx_cast0() ctx -#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0] -#define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), (void *)ctx[1] -#define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), (void *)ctx[2] -#define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), (void *)ctx[3] -#define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), (void *)ctx[4] -#define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), (void *)ctx[5] -#define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), (void *)ctx[6] -#define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), (void *)ctx[7] -#define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), (void *)ctx[8] -#define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), (void *)ctx[9] -#define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), (void *)ctx[10] -#define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), (void *)ctx[11] -#define ___bpf_ctx_cast(args...) \ - ___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args) - -/* - * BPF_PROG is a convenience wrapper for generic tp_btf/fentry/fexit and - * similar kinds of BPF programs, that accept input arguments as a single - * pointer to untyped u64 array, where each u64 can actually be a typed - * pointer or integer of different size. Instead of requring user to write - * manual casts and work with array elements by index, BPF_PROG macro - * allows user to declare a list of named and typed input arguments in the - * same syntax as for normal C function. All the casting is hidden and - * performed transparently, while user code can just assume working with - * function arguments of specified type and name. - * - * Original raw context argument is preserved as well as 'ctx' argument. - * This is useful when using BPF helpers that expect original context - * as one of the parameters (e.g., for bpf_perf_event_output()). - */ -#define BPF_PROG(name, args...) \ -name(unsigned long long *ctx); \ -static __attribute__((always_inline)) typeof(name(0)) \ -____##name(unsigned long long *ctx, ##args); \ -typeof(name(0)) name(unsigned long long *ctx) \ -{ \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - return ____##name(___bpf_ctx_cast(args)); \ - _Pragma("GCC diagnostic pop") \ -} \ -static __attribute__((always_inline)) typeof(name(0)) \ -____##name(unsigned long long *ctx, ##args) - -struct pt_regs; - -#define ___bpf_kprobe_args0() ctx -#define ___bpf_kprobe_args1(x) \ - ___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx) -#define ___bpf_kprobe_args2(x, args...) \ - ___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx) -#define ___bpf_kprobe_args3(x, args...) \ - ___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx) -#define ___bpf_kprobe_args4(x, args...) \ - ___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx) -#define ___bpf_kprobe_args5(x, args...) \ - ___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx) -#define ___bpf_kprobe_args(args...) \ - ___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args) - -/* - * BPF_KPROBE serves the same purpose for kprobes as BPF_PROG for - * tp_btf/fentry/fexit BPF programs. It hides the underlying platform-specific - * low-level way of getting kprobe input arguments from struct pt_regs, and - * provides a familiar typed and named function arguments syntax and - * semantics of accessing kprobe input paremeters. - * - * Original struct pt_regs* context is preserved as 'ctx' argument. This might - * be necessary when using BPF helpers like bpf_perf_event_output(). - */ -#define BPF_KPROBE(name, args...) \ -name(struct pt_regs *ctx); \ -static __attribute__((always_inline)) typeof(name(0)) \ -____##name(struct pt_regs *ctx, ##args); \ -typeof(name(0)) name(struct pt_regs *ctx) \ -{ \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - return ____##name(___bpf_kprobe_args(args)); \ - _Pragma("GCC diagnostic pop") \ -} \ -static __attribute__((always_inline)) typeof(name(0)) \ -____##name(struct pt_regs *ctx, ##args) - -#define ___bpf_kretprobe_args0() ctx -#define ___bpf_kretprobe_args1(x) \ - ___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx) -#define ___bpf_kretprobe_args(args...) \ - ___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args) - -/* - * BPF_KRETPROBE is similar to BPF_KPROBE, except, it only provides optional - * return value (in addition to `struct pt_regs *ctx`), but no input - * arguments, because they will be clobbered by the time probed function - * returns. - */ -#define BPF_KRETPROBE(name, args...) \ -name(struct pt_regs *ctx); \ -static __attribute__((always_inline)) typeof(name(0)) \ -____##name(struct pt_regs *ctx, ##args); \ -typeof(name(0)) name(struct pt_regs *ctx) \ -{ \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - return ____##name(___bpf_kretprobe_args(args)); \ - _Pragma("GCC diagnostic pop") \ -} \ -static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args) - -#endif diff --git a/ebpf/bpf/pid.h b/ebpf/bpf/pid.h deleted file mode 100644 index c1165d7e00..0000000000 --- a/ebpf/bpf/pid.h +++ /dev/null @@ -1,39 +0,0 @@ -#if !defined(PYROSCOPE_PID) -#define PYROSCOPE_PID - -#include "bpf_core_read.h" -#include "bpf_helpers.h" -#include "vmlinux.h" - -#define PID_NESTED_NAMESPACES_MAX 4 - -static __always_inline void current_pid(uint64_t ns_pid_ino, uint32_t *pid) { - unsigned int inum; - - // fallback to host pid, if no inode provided - if (ns_pid_ino == 0) { - uint64_t pid_tgid = bpf_get_current_pid_tgid(); - *pid = (u32)(pid_tgid >> 32); - return; - } - - struct task_struct *task = (struct task_struct *)bpf_get_current_task(); - - // retrieve level nested namespaces - unsigned int level = BPF_CORE_READ(task, group_leader, nsproxy, pid_ns_for_children, level); - - // match the level with pid ns inode -#pragma unroll - for (int i = 0; i < PID_NESTED_NAMESPACES_MAX; i++) { - if ((level - i) < 0) { - break; - } - inum = BPF_CORE_READ(task, group_leader, thread_pid, numbers[level - i].ns, ns.inum); - if (inum == ns_pid_ino) { - *pid = BPF_CORE_READ(task, group_leader, thread_pid, numbers[level - i].nr); - break; - } - } -} - -#endif // PYROSCOPE_PID diff --git a/ebpf/bpf/profile.bpf.c b/ebpf/bpf/profile.bpf.c deleted file mode 100644 index e430835e91..0000000000 --- a/ebpf/bpf/profile.bpf.c +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include "vmlinux.h" -#include "bpf_helpers.h" -#include "bpf_tracing.h" -#include "profile.bpf.h" -#include "pid.h" -#include "ume.h" - -#define PF_KTHREAD 0x00200000 - -struct global_config_t { - uint64_t ns_pid_ino; -}; - -const volatile struct global_config_t global_config; - -SEC("perf_event") -int do_perf_event(struct bpf_perf_event_data *ctx) { - u32 tgid = 0; - current_pid(global_config.ns_pid_ino, &tgid); - - struct sample_key key = {}; - u32 *val, one = 1; - - struct task_struct *task = (struct task_struct *)bpf_get_current_task(); - if (tgid == 0 || task == 0) { - return 0; - } - int flags = 0; - if (pyro_bpf_core_read(&flags, sizeof(flags), &task->flags)) { - bpf_dbg_printk("failed to read task->flags\n"); - return 0; - } - if (flags & PF_KTHREAD) { - bpf_dbg_printk("skipping kthread %d\n", tgid); - return 0; - } - - struct pid_config *config = bpf_map_lookup_elem(&pids, &tgid); - if (config == NULL) { - struct pid_config unknown = { - .type = PROFILING_TYPE_UNKNOWN, - .collect_kernel = 0, - .collect_user = 0, - .padding_ = 0 - }; - if (bpf_map_update_elem(&pids, &tgid, &unknown, BPF_NOEXIST)) { - bpf_dbg_printk("failed to update pids map. probably concurrent update\n"); - return 0; - } - struct pid_event event = { - .op = OP_REQUEST_UNKNOWN_PROCESS_INFO, - .pid = tgid - }; - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; - } - - if (config->type == PROFILING_TYPE_ERROR || config->type == PROFILING_TYPE_UNKNOWN) { - return 0; - } - - if (config->type == PROFILING_TYPE_PYTHON) { - bpf_tail_call(ctx, &progs, PROG_IDX_PYTHON); - return 0; - } - - if (config->type == PROFILING_TYPE_FRAMEPOINTERS) { - key.pid = tgid; - key.kern_stack = -1; - key.user_stack = -1; - - if (config->collect_kernel) { - key.kern_stack = bpf_get_stackid(ctx, &stacks, KERN_STACKID_FLAGS); - } - if (config->collect_user) { - key.user_stack = bpf_get_stackid(ctx, &stacks, USER_STACKID_FLAGS); - } - - val = bpf_map_lookup_elem(&counts, &key); - if (val) - (*val)++; - else - bpf_map_update_elem(&counts, &key, &one, BPF_NOEXIST); - } - return 0; -} - - -SEC("kprobe/disassociate_ctty") -int BPF_KPROBE(disassociate_ctty, int on_exit) { - if (!on_exit) { - return 0; - } - u32 pid = 0; - current_pid(global_config.ns_pid_ino, &pid); - if (pid == 0) { - return 0; - } - bpf_map_delete_elem(&pids, &pid); - struct pid_event event = { - .op = OP_PID_DEAD, - .pid = pid - }; - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; -} - -// execve/execveat -SEC("kprobe/exec") -int BPF_KPROBE(exec, void *_) { - u32 pid = 0; - current_pid(global_config.ns_pid_ino, &pid); - if (pid == 0) { - return 0; - } - struct pid_event event = { - .op = OP_REQUEST_EXEC_PROCESS_INFO, - .pid = pid - }; - bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); - return 0; -} - -char _license[] SEC("license") = "GPL"; diff --git a/ebpf/bpf/profile.bpf.h b/ebpf/bpf/profile.bpf.h deleted file mode 100644 index 6f22c97814..0000000000 --- a/ebpf/bpf/profile.bpf.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef PROFILE_BPF_H -#define PROFILE_BPF_H - - - - - -#define PROFILING_TYPE_UNKNOWN 1 -#define PROFILING_TYPE_FRAMEPOINTERS 2 -#define PROFILING_TYPE_PYTHON 3 -#define PROFILING_TYPE_ERROR 4 - -struct pid_config { - uint8_t type; - uint8_t collect_user; - uint8_t collect_kernel; - uint8_t padding_; -}; - -#define OP_REQUEST_UNKNOWN_PROCESS_INFO 1 -#define OP_PID_DEAD 2 -#define OP_REQUEST_EXEC_PROCESS_INFO 3 - -struct pid_event { - uint32_t op; - uint32_t pid; -}; -struct pid_event e__; - - - - - - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, u32); - __type(value, struct pid_config); - __uint(max_entries, 2048); -} pids SEC(".maps"); - - -struct { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(u32)); -} events SEC(".maps"); - - -struct { - __uint(type, BPF_MAP_TYPE_PROG_ARRAY); - __uint(max_entries, 1); - __type(key, int); - __array(values, int (void *)); -} progs SEC(".maps"); - -#define PROG_IDX_PYTHON 0 - -#include "stacks.h" - - - -#endif // PROFILE_BPF_H \ No newline at end of file diff --git a/ebpf/bpf/pthread.bpf.h b/ebpf/bpf/pthread.bpf.h deleted file mode 100644 index 5b2f76df8e..0000000000 --- a/ebpf/bpf/pthread.bpf.h +++ /dev/null @@ -1,25 +0,0 @@ - - -#ifndef PYROEBPF_PTHREAD_BPF_H -#define PYROEBPF_PTHREAD_BPF_H - - - - -#if defined(__TARGET_ARCH_x86) - -#include "pthread_amd64.h" - -#elif defined(__TARGET_ARCH_arm64) - -#include "pthread_arm64.h" - -#else - -#error "Unknown architecture" - -#endif - - - -#endif //PYROEBPF_PTHREAD_BPF_H diff --git a/ebpf/bpf/pthread_amd64.h b/ebpf/bpf/pthread_amd64.h deleted file mode 100644 index 222bf00ac9..0000000000 --- a/ebpf/bpf/pthread_amd64.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// Created by korniltsev on 11/21/23. -// - -#ifndef PYROEBPF_PTHREAD_AMD64_H -#define PYROEBPF_PTHREAD_AMD64_H - -#include "vmlinux.h" -#include "bpf_helpers.h" -#include "ume.h" -#include "pyoffsets.h" - - -#if !defined(__TARGET_ARCH_x86) -#error "Wrong architecture" -#endif - -static int pthread_getspecific_musl(const struct libc *libc, int32_t key, void **out, const void *tls_base); -static int pthread_getspecific_glibc(const struct libc *libc, int32_t key, void **out, const void *tls_base); - -static __always_inline int pyro_pthread_getspecific(struct libc *libc, int32_t key, void **out) { - if (key == -1) { - return -1; - } - struct task_struct *task = (struct task_struct *) bpf_get_current_task(); - if (task == NULL) { - return -1; - } - void *tls_base = NULL; - - - if (pyro_bpf_core_read(&tls_base, sizeof(tls_base), &task->thread.fsbase)) { - return -1; - } - - - if (libc->musl) { - return pthread_getspecific_musl(libc, key, out, tls_base); - - } - return pthread_getspecific_glibc(libc, key, out, tls_base); - -} - -static __always_inline int pthread_getspecific_glibc(const struct libc *libc, int32_t key, void **out, const void *tls_base) { - void *tmp = NULL; - if (key >= 32) { - return -1; // it is possible to implement this branch, but it's not needed as autoTLSkey is almost always 0 - } - // This assumes autoTLSkey < 32, which means that the TLS is stored in -// pthread->specific_1stblock[autoTLSkey] - if (bpf_probe_read_user( - &tmp, - sizeof(tmp), - tls_base + libc->pthread_specific1stblock + key * 0x10 + 0x08)) { - return -1; - } - *out = tmp; - return 0; -} - -static __always_inline int pthread_getspecific_musl(const struct libc *libc, int32_t key, void **out, - const void *tls_base) { - // example from musl 1.2.4 from alpine 3.18 -// static void *__pthread_getspecific(pthread_key_t k) -// { -// struct pthread *self = __pthread_self(); -// return self->tsd[k]; -// } -// -// #define __pthread_self() ((pthread_t)__get_tp()) -// -// static inline uintptr_t __get_tp() -// { -// uintptr_t tp; -// __asm__ ("mov %%fs:0,%0" : "=r" (tp) ); -// return tp; -// } -// -//00000000000563f7 : -// 563f7: 64 48 8b 04 25 00 00 mov rax,QWORD PTR fs:0x0 -// 563fe: 00 00 -// 56400: 48 8b 80 80 00 00 00 mov rax,QWORD PTR [rax+0x80] ; << tsd -// 56407: 89 ff mov edi,edi -// 56409: 48 8b 04 f8 mov rax,QWORD PTR [rax+rdi*8] -// 5640d: c3 ret - void *tmp = NULL; - - if (bpf_probe_read_user(&tmp,sizeof(tmp), tls_base)) { - return -1; - } - if (bpf_probe_read_user(&tmp, sizeof(tmp), tmp + libc->pthread_specific1stblock)) { - return -1; - } - if (bpf_probe_read_user(&tmp, sizeof(tmp), tmp + key * 0x8)) { - return -1; - } - *out = tmp; - return 0; -} - -#endif //PYROEBPF_PTHREAD_AMD64_H diff --git a/ebpf/bpf/pthread_arm64.h b/ebpf/bpf/pthread_arm64.h deleted file mode 100644 index da2a77f028..0000000000 --- a/ebpf/bpf/pthread_arm64.h +++ /dev/null @@ -1,96 +0,0 @@ -// -// Created by korniltsev on 11/21/23. -// - -#ifndef PYROEBPF_PTHREAD_ARM64_H -#define PYROEBPF_PTHREAD_ARM64_H - -#include "vmlinux.h" -#include "bpf_helpers.h" -#include "ume.h" -#include "pyoffsets.h" - -#if !defined(__TARGET_ARCH_arm64) -#error "Wrong architecture" -#endif - -static int pthread_getspecific_musl(const struct libc *libc, int32_t key, void **out, const void *tls_base); -static int pthread_getspecific_glibc(const struct libc *libc, int32_t key, void **out, const void *tls_base); - -static __always_inline int pyro_pthread_getspecific(struct libc *libc, int32_t key, void **out) { - if (key == -1) { - return -1; - } - struct task_struct *task = (struct task_struct *) bpf_get_current_task(); - if (task == NULL) { - return -1; - } - void *tls_base = NULL; - - if (pyro_bpf_core_read(&tls_base, sizeof(tls_base), &task->thread.uw.tp_value)) { - return -1; - } - - - if (libc->musl) { - return pthread_getspecific_musl(libc, key, out, tls_base); - } else { - return pthread_getspecific_glibc(libc, key, out, tls_base); - } - - return 0; -} - -int __always_inline pthread_getspecific_glibc(const struct libc *libc, int32_t key, void **out, const void *tls_base) { - void *res = NULL; - if (key >= 32) { - return -1; // it is possible to implement this branch, but it's not needed as autoTLSkey is almost always 0 - } - // This assumes autoTLSkey < 32, which means that the TLS is stored in - // pthread->specific_1stblock[autoTLSkey] - // # define THREAD_SELF \ - // ((struct pthread *)__builtin_thread_pointer () - 1) - - tls_base -= libc->pthread_size; - - if (bpf_probe_read_user( - &res, - sizeof(res), - tls_base + libc->pthread_specific1stblock + key * 0x10 + 0x08)) { - return -1; - } - *out = res; - return 0; -} - -int __always_inline pthread_getspecific_musl(const struct libc *libc, int32_t key, void **out, const void *tls_base) { - -// example from musl 1.2.4 from alpine 3.18 -// static void *__pthread_getspecific(pthread_key_t k) -// { -// struct pthread *self = __pthread_self(); -// return self->tsd[k]; -// } - -// #define __pthread_self() ((pthread_t)(__get_tp() - sizeof(struct __pthread) - TP_OFFSET)) - -//000000000005fc54 : -// 5fc54: d53bd041 mrs x1, tpidr_el0 -// 5fc58: f85a8021 ldur x1, [x1, #-88] -// 5fc5c: f8605820 ldr x0, [x1, w0, uxtw #3] -// 5fc60: d65f03c0 ret - void *tmp; - if (bpf_probe_read_user(&tmp,sizeof(tmp), tls_base - libc->pthread_size + libc->pthread_specific1stblock)) { - return -1; - } - if (bpf_probe_read_user(&tmp, sizeof(tmp), tmp + key * 0x8)) { - return -1; - } - *out = tmp; - return 0; -} - - - - -#endif //PYROEBPF_PTHREAD_ARM64_H diff --git a/ebpf/bpf/pyoffsets.h b/ebpf/bpf/pyoffsets.h deleted file mode 100644 index 103dea2ca6..0000000000 --- a/ebpf/bpf/pyoffsets.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Created by korniltsev on 11/2/23. -// - -#ifndef PYROEBPF_PYOFFSETS_H -#define PYROEBPF_PYOFFSETS_H - - - -enum frame_owner { - FRAME_OWNED_BY_THREAD = 0, - FRAME_OWNED_BY_GENERATOR = 1, - FRAME_OWNED_BY_FRAME_OBJECT = 2, - FRAME_OWNED_BY_CSTACK = 3, -}; - -struct libc { - bool musl; // - int16_t pthread_size; - int16_t pthread_specific1stblock; // tsd for musl, specific_1stblock for glibc -}; - -typedef struct { - int16_t PyThreadState_frame; - int16_t PyThreadState_cframe; - int16_t PyCFrame_current_frame; - int16_t PyCodeObject_co_filename; - int16_t PyCodeObject_co_name; - int16_t PyCodeObject_co_varnames; - int16_t PyCodeObject_co_localsplusnames; - int16_t PyCodeObject__co_cell2arg; - int16_t PyCodeObject__co_cellvars; - int16_t PyCodeObject__co_nlocals; - int16_t PyTupleObject_ob_item; - - int16_t PyVarObject_ob_size; - int16_t PyObject_ob_type; - int16_t PyTypeObject_tp_name; - - int16_t VFrame_code; // PyFrameObject_f_code pre 311 or PyInterpreterFrame_f_code post 311 - int16_t VFrame_previous; // PyFrameObject_f_back pre 311 or PyInterpreterFrame_previous post 311 - int16_t VFrame_localsplus; // PyFrameObject_localsplus pre 311 or PyInterpreterFrame_localsplus post 311 - int16_t PyInterpreterFrame_owner; - int16_t PyASCIIObject_size; // sizeof(PyASCIIObject) - int16_t PyCompactUnicodeObject_size; // sizeof(PyCompactUnicodeObject) - int16_t PyCellObject_ob_ref; - - uint64_t base; - uint64_t PyCell_Type;// absolute address of PyCell_Type -} py_offset_config; - -#endif //PYROEBPF_PYOFFSETS_H diff --git a/ebpf/bpf/pyperf.bpf.c b/ebpf/bpf/pyperf.bpf.c deleted file mode 100644 index 1b481fda1e..0000000000 --- a/ebpf/bpf/pyperf.bpf.c +++ /dev/null @@ -1,649 +0,0 @@ -#ifndef PYPERF_H -#define PYPERF_H - -#include "vmlinux.h" -#include "bpf_helpers.h" - -#include "pthread.bpf.h" -#include "pid.h" -#include "stacks.h" -#include "pystr.h" -#include "pyoffsets.h" -#include "hash.h" - -#define PYTHON_STACK_FRAMES_PER_PROG 32 -#define PYTHON_STACK_PROG_CNT 3 -#define PYTHON_STACK_MAX_LEN (PYTHON_STACK_FRAMES_PER_PROG * PYTHON_STACK_PROG_CNT) -#define PYTHON_CLASS_NAME_LEN 32 -#define PYTHON_FUNCTION_NAME_LEN 64 -#define PYTHON_FILE_NAME_LEN 128 - -enum { - PY_ERROR_GENERIC = 1, - PY_ERROR_THREAD_STATE = 2, - PY_ERROR_THREAD_STATE_NULL = 3, - PY_ERROR_TOP_FRAME = 4, - PY_ERROR_FRAME_CODE = 5, - PY_ERROR_FRAME_PREV = 6, - PY_ERROR_SYMBOL = 7, - PY_ERROR_TLSBASE = 8, - PY_ERROR_FIRST_ARG = 9, - PY_ERROR_CLASS_NAME = 10, - PY_ERROR_FILE_NAME = 11, - PY_ERROR_NAME = 12, - PY_ERROR_FRAME_OWNER = 13, - PY_ERROR_FRAME_OWNER_INVALID = 14, - - -}; - -struct global_config_t { - uint8_t bpf_log_err; - uint8_t bpf_log_debug; - uint64_t ns_pid_ino; -}; - -const volatile struct global_config_t global_config; -#define log_error(fmt, ...) if (global_config.bpf_log_err) bpf_printk("[> error <] " fmt, ##__VA_ARGS__) -#define log_debug(fmt, ...) if (global_config.bpf_log_debug) bpf_printk("[ debug ] " fmt, ##__VA_ARGS__) - -#define try_read_or_fail(dst, src) if (bpf_probe_read_user(&(dst), sizeof((dst)), (src))) { \ - log_error("failed to read 0x%llx %s:%d", (src), __FILE__, __LINE__); \ - return -1; \ -} - -#define try_read_or_err(dst, src, err) if (bpf_probe_read_user(&(dst), sizeof((dst)), (src))) { \ - log_error("failed to read 0x%llx %s:%d", (src), __FILE__, __LINE__); \ - return -(err); \ -} - -#define try_or_err(expr, err) if (expr) { \ - log_error("try failed %s:%d", __FILE__, __LINE__); \ - return -(err); \ -} - -#define try_or_fail(expr) if (expr) { \ - log_error("try failed %s:%d", __FILE__, __LINE__); \ - return -1; \ -} - - -typedef struct { - uint32_t major; - uint32_t minor; - uint32_t patch; -} py_version; - -typedef struct { - py_offset_config offsets; - py_version version; - struct libc libc; - int32_t tssKey; - uint8_t collect_kernel; -} py_pid_data; - -typedef struct { - char classname[PYTHON_CLASS_NAME_LEN]; - char name[PYTHON_FUNCTION_NAME_LEN]; - char file[PYTHON_FILE_NAME_LEN]; - - struct py_str_type classname_type; - struct py_str_type name_type; - struct py_str_type file_type; - struct py_str_type __padding; - - // NOTE: PyFrameObject also has line number but it is typically just the - // first line of that function and PyCode_Addr2Line needs to be called - // to get the actual line -} py_symbol; - - -typedef uint32_t py_symbol_id; - -typedef struct { - struct sample_key k; - uint32_t stack_len; - // instead of storing symbol name here directly, we add it to another - // hashmap with Symbols and only store the ids here - py_symbol_id stack[PYTHON_STACK_MAX_LEN]; -} py_event; - -#define _STR_CONCAT(str1, str2) str1##str2 -#define STR_CONCAT(str1, str2) _STR_CONCAT(str1, str2) -#define FAIL_COMPILATION_IF(condition) \ - typedef struct { \ - char _condition_check[1 - 2 * !!(condition)]; \ - } STR_CONCAT(compile_time_condition_check, __COUNTER__); -// See comments in get_frame_data -FAIL_COMPILATION_IF(sizeof(py_symbol) == sizeof(struct bpf_perf_event_value)) -FAIL_COMPILATION_IF(HASH_LIMIT != PYTHON_STACK_MAX_LEN * sizeof(py_symbol_id)) - -typedef struct { - int64_t symbol_counter; - py_offset_config offsets; - uint32_t cur_cpu; - uint64_t frame_ptr; - int64_t python_stack_prog_call_cnt; - py_symbol sym; - py_event event; - uint64_t padding;// satisfy verifier for hash function -} py_sample_state_t; - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(key_size, sizeof(u32)); - __uint(value_size, PYTHON_STACK_MAX_LEN * sizeof(py_symbol_id)); - __uint(max_entries, PROFILE_MAPS_SIZE); -} python_stacks SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); - __type(key, u32); - __type(value, py_sample_state_t); - __uint(max_entries, 1); -} py_state_heap SEC(".maps"); - - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, py_symbol); - __type(value, py_symbol_id); - __uint(max_entries, 16384); -} py_symbols SEC(".maps"); - - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, pid_t); - __type(value, py_pid_data); - __uint(max_entries, 10240); -} py_pid_config SEC(".maps"); - -#define PYTHON_PROG_IDX_READ_PYTHON_STACK 0 - -int read_python_stack(struct bpf_perf_event_data *ctx); - - -struct { - __uint(type, BPF_MAP_TYPE_PROG_ARRAY); - __uint(max_entries, 2); - __type(key, int); - __array(values, int (void *)); -} py_progs SEC(".maps") = { - .values = { - [PYTHON_PROG_IDX_READ_PYTHON_STACK] = (void *) &read_python_stack, - }, -}; - - -static __always_inline int get_thread_state( - py_pid_data *pid_data, - void **out_thread_state) { - return pyro_pthread_getspecific(&pid_data->libc, pid_data->tssKey, out_thread_state); -} - -static __always_inline int submit_sample( - py_sample_state_t* state) { - uint32_t one = 1; - if (state->event.stack_len < PYTHON_STACK_MAX_LEN) { - state->event.stack[state->event.stack_len] = 0; - } - u64 h = MurmurHash64A(&state->event.stack, state->event.stack_len * sizeof(state->event.stack[0]), 0); - state->event.k.user_stack = h; - if (bpf_map_update_elem(&python_stacks, &h, &state->event.stack, BPF_ANY)) { - return -1; - } - uint32_t* val = bpf_map_lookup_elem(&counts, &state->event.k); - if (val) { - (*val)++; - } - else { - bpf_map_update_elem(&counts, &state->event.k, &one, BPF_NOEXIST); - } - - - return 0; -} - -static __always_inline int submit_error_sample( - uint8_t err) { //todo replace with more useful log - log_error("pyperf_err: %d\n", err); - return -1; -} - -// this function is trivial, but we need to do map lookup in separate function, -// because BCC doesn't allow direct map calls (including lookups) from inside -// a macro (which we want to do in GET_STATE() macro below) -static __always_inline py_sample_state_t *get_state() { - int zero = 0; - return bpf_map_lookup_elem(&py_state_heap, &zero); -} - -#define GET_STATE() \ - py_sample_state_t* state = get_state(); \ - if (!state) { \ - return -1; /* should never happen */ \ - } - -static __always_inline int get_top_frame(py_pid_data *pid_data, py_sample_state_t *state, void *thread_state) { - if (pid_data->offsets.PyThreadState_frame == -1) { - // >= py311 && <= py312 - void *cframe; - if (bpf_probe_read_user( - &cframe, - sizeof(void *), - thread_state + pid_data->offsets.PyThreadState_cframe)) { - return -1; - } - if (cframe == 0) { - return -1; - } - if (bpf_probe_read_user( - &state->frame_ptr, - sizeof(void *), - cframe + pid_data->offsets.PyCFrame_current_frame)) { - return -1; - } - return 0; - } - // < py311 && >= py313 - if (bpf_probe_read_user( - &state->frame_ptr, - sizeof(void *), - thread_state + pid_data->offsets.PyThreadState_frame)) { - return -1; - } - return 0; -} - -static __always_inline int pyperf_collect_impl(struct bpf_perf_event_data* ctx, pid_t pid) { - py_pid_data *pid_data = bpf_map_lookup_elem(&py_pid_config, &pid); - if (!pid_data) { - return 0; - } - - GET_STATE(); - - state->offsets = pid_data->offsets; - state->cur_cpu = bpf_get_smp_processor_id(); - state->python_stack_prog_call_cnt = 0; - state->frame_ptr = 0; - - py_event *event = &state->event; - event->k.pid = pid; - if (pid_data->collect_kernel) { - event->k.kern_stack = bpf_get_stackid(ctx, &stacks, KERN_STACKID_FLAGS); - } else { - event->k.kern_stack = -1; - } - - - // Read PyThreadState of this Thread from TLS - void *thread_state = NULL; - if (get_thread_state(pid_data, &thread_state)) { - return submit_error_sample(PY_ERROR_THREAD_STATE); - } - log_debug("thread_state %llx", thread_state); - - // pre-initialize event struct in case any subprogram below fails - event->stack_len = 0; - - if (thread_state != 0) { - if (get_top_frame(pid_data, state, thread_state)) { - return submit_error_sample(PY_ERROR_TOP_FRAME); - } - // jump to reading first set of Python frames - bpf_tail_call(ctx, &py_progs, PYTHON_PROG_IDX_READ_PYTHON_STACK); - // we won't ever get here - } - return submit_error_sample(PY_ERROR_THREAD_STATE_NULL); -} - -SEC("perf_event") -int pyperf_collect(struct bpf_perf_event_data *ctx) { - u32 pid; - current_pid(global_config.ns_pid_ino, &pid); - if (pid == 0) { - return 0; - } - return pyperf_collect_impl(ctx, (pid_t) pid); -} - - -static __always_inline int check_first_arg(void *code_ptr, - py_offset_config *offsets, - py_symbol *symbol, - bool *out_first_self, - bool *out_first_cls) { - // Figure out if we want to parse class name, basically checking the name of - // the first argument, - // ((PyTupleObject*)$frame->f_code->co_varnames)->ob_item[0] - // If it's 'self', we get the type and it's name, if it's cls, we just get - // the name. This is not perfect but there is no better way to figure this - // out from the code object. - void *args_ptr; - uint64_t args_size; - if (offsets->PyCodeObject_co_varnames == -1) { - if (bpf_probe_read_user( - &args_ptr, sizeof(void *), code_ptr + offsets->PyCodeObject_co_localsplusnames)) { - return -1; - } - } else { - if (bpf_probe_read_user( - &args_ptr, sizeof(void *), code_ptr + offsets->PyCodeObject_co_varnames)) { - return -1; - } - } - if (args_ptr == 0) { - *out_first_self = false; - *out_first_cls = false; - return 0; - } - if (bpf_probe_read_user( - &args_size, sizeof(args_size), args_ptr + offsets->PyVarObject_ob_size)) { - return -1; - } - if (args_size < 1) { - *out_first_self = false; - *out_first_cls = false; - return 0; - } - if (bpf_probe_read_user( - &args_ptr, sizeof(void *), args_ptr + offsets->PyTupleObject_ob_item)) { - return -1; - } - *((uint64_t *)&symbol->name) = 0; - if (pystr_read(args_ptr, offsets, symbol->name, sizeof(symbol->name), &symbol->name_type)) { - return -1; - } - // compare strings as ints to save instructions - char self_str[4] = {'s', 'e', 'l', 'f'}; - char cls_str[4] = {'c', 'l', 's', '\0'}; - *out_first_self = *(int32_t *) symbol->name == *(int32_t *) self_str; - *out_first_cls = *(int32_t *) symbol->name == *(int32_t *) cls_str; - log_debug("first arg %s ", symbol->name); - - - return 0; -} - -// https://github.com/python/cpython/blob/f82b32410ba220165eab7b8d6dcc61a09744512c/Objects/typeobject.c#L8103-L8114 -static __always_inline int get_first_arg_cell(void *frame_ptr, void *code_ptr, py_offset_config *offsets, void **out_first_arg_cell) { - void *co_cellvars = NULL; - void *ob_type = NULL; - void *first_arg_cell = NULL; - ssize_t co_cellvars_size = 0; - ssize_t *co_cell2arg = NULL; - int co_nlocals = 0; - ssize_t argno = 0; - - *out_first_arg_cell = 0; - - if (offsets->PyCodeObject__co_cell2arg == -1 || offsets->PyCodeObject__co_cellvars == -1) { - return 0; // removed in 3.11 - } - - try_read_or_fail(co_cellvars, code_ptr +offsets->PyCodeObject__co_cellvars); - try_read_or_fail(co_cell2arg, code_ptr + offsets->PyCodeObject__co_cell2arg); - try_read_or_fail(co_nlocals, code_ptr + offsets->PyCodeObject__co_nlocals); - if (co_cellvars == NULL || co_cell2arg == NULL) { - return 0; - } - log_debug("co_cellvars %llx co_cell2arg %llx", co_cellvars, co_cell2arg); - try_read_or_fail(co_cellvars_size, (void*)co_cellvars + offsets->PyVarObject_ob_size); - if (co_cellvars_size < 1) { - return 0; - } -#pragma unroll - for (int i = 0; i < 8; i++) { - if (i >= co_cellvars_size) { - break; - } - try_read_or_fail(argno , co_cell2arg + i); - if (argno != 0) { - continue; - } - try_read_or_fail(first_arg_cell, frame_ptr + offsets->VFrame_localsplus + (co_nlocals + i) * sizeof(void*)) - if (first_arg_cell == NULL) { - return 0; - } - try_read_or_fail(ob_type, first_arg_cell + offsets->PyObject_ob_type); - log_debug("first arg cell %llx is_cell = %d", first_arg_cell, ob_type == (void*)offsets->PyCell_Type); - if (ob_type != (void *) offsets->PyCell_Type) { - return 0; - } - *out_first_arg_cell = first_arg_cell; - return 0; - } - log_debug("no first arg cell found %d", co_cellvars_size); - return 0; -} - -static __always_inline int -get_class_name(void *cur_frame, void *code_ptr, py_offset_config *offsets, bool first_self, py_symbol *symbol) { - void *ptr = NULL, *ptr_ob_type = NULL; - // Read class name from $frame->f_localsplus[0]->ob_type->tp_name. - try_read_or_fail(ptr, cur_frame + offsets->VFrame_localsplus) - if (!ptr) { - try_or_fail(get_first_arg_cell(cur_frame, code_ptr, offsets, &ptr)) - } - if (!ptr) { - log_debug("first arg NULL"); - symbol->classname_type.type = PYSTR_TYPE_1BYTE | PYSTR_TYPE_ASCII; - symbol->classname_type.size_codepoints = 0; - return 0; - } - try_read_or_fail(ptr_ob_type, ptr + offsets->PyObject_ob_type) - if (ptr_ob_type == (void *) offsets->PyCell_Type) { - try_read_or_fail(ptr, ptr + offsets->PyCellObject_ob_ref) - log_debug("ob_ref %Llx", ptr); - if (!ptr) { - symbol->classname_type.type = PYSTR_TYPE_1BYTE | PYSTR_TYPE_ASCII; - symbol->classname_type.size_codepoints = 0; - return 0; - } - } - if (first_self) { - // we are working with an instance, first we need to get type - try_read_or_fail(ptr, ptr + offsets->PyObject_ob_type) - } - // todo consider typechecking ptr is _typeobject somehow (note: ob_type may be not `type`) - - // https://github.com/python/cpython/blob/d73501602f863a54c872ce103cd3fa119e38bac9/Include/cpython/object.h#L106 - try_read_or_fail(ptr, ptr + offsets->PyTypeObject_tp_name); - long len = bpf_probe_read_user_str(&symbol->classname, sizeof(symbol->classname), ptr); - if (len < 0) { - log_error("failed to read class name at %x\n", ptr); - return -1; - } - symbol->classname_type.type = PYSTR_TYPE_UTF8; - symbol->classname_type.size_codepoints = len - 1; - - log_debug("cls %s", symbol->classname); - return 0; -} - -// return -PY_ERR_XX on error, 0 on success -static __always_inline int get_names( - void *cur_frame, - void *code_ptr, - py_offset_config *offsets, - py_symbol *symbol, - void *ctx) { - void *pystr_ptr = NULL; - bool first_self = false; - bool first_cls = false; - try_or_err(check_first_arg(code_ptr, offsets, symbol, &first_self, &first_cls), PY_ERROR_FIRST_ARG) - - // We re-use the same py_symbol instance across loop iterations, which means - // we will have left-over data in the struct. Although this won't affect - // correctness of the result because we have '\0' at end of the strings read, - // it would affect effectiveness of the deduplication. - // Helper bpf_perf_prog_read_value clears the buffer on error, so here we - // (ab)use this behavior to clear the memory. It requires the size of py_symbol - // to be different from struct bpf_perf_event_value, which we check at - // compilation time using the FAIL_COMPILATION_IF macro. - bpf_perf_prog_read_value(ctx, (struct bpf_perf_event_value *) symbol, sizeof(py_symbol)); - - if (first_self || first_cls) { - try_or_err(get_class_name(cur_frame, code_ptr, offsets, first_self, symbol), PY_ERROR_CLASS_NAME) - } - - try_read_or_err(pystr_ptr, code_ptr + offsets->PyCodeObject_co_filename, PY_ERROR_FILE_NAME) - if (pystr_ptr == 0) { - symbol->file_type.type = PYSTR_TYPE_1BYTE | PYSTR_TYPE_ASCII; - symbol->file_type.size_codepoints = 0;; - } else { - try_or_err(pystr_read(pystr_ptr, offsets, symbol->file, sizeof(symbol->file), &symbol->file_type), PY_ERROR_FILE_NAME) - } - log_debug("file %s", symbol->file); - - try_read_or_err(pystr_ptr, code_ptr + offsets->PyCodeObject_co_name, PY_ERROR_NAME) - try_or_err(pystr_read(pystr_ptr, offsets, symbol->name, sizeof(symbol->name), &symbol->name_type), PY_ERROR_NAME) - log_debug("sym %s", symbol->name); - return 0; -} - -// get_frame_data reads current PyFrameObject filename/name and updates -// stack_info->frame_ptr with pointer to next PyFrameObject -// since 311 frame_ptr is pointing to _PyInterpreterFrame -// returns -PY_ERR_XXX on error, 1 on success, 0 if no more frames -static __always_inline int get_frame_data( - void **frame_ptr, - py_offset_config *offsets, - py_symbol *symbol, - // ctx is only used to call helper to clear symbol, see documentation below - void *ctx) { - void *code_ptr; - void *cur_frame = *frame_ptr; - if (!cur_frame) { - return 0; - } - - if (offsets->PyInterpreterFrame_owner != -1) { - // https://github.com/python/cpython/blob/e7331365b488382d906ce6733ab1349ded49c928/Python/traceback.c#L991 - char owner = 0; - if (bpf_probe_read_user( - &owner, sizeof(owner), (void *) (cur_frame + offsets->PyInterpreterFrame_owner))) { - return -PY_ERROR_FRAME_OWNER; - } - if (owner == FRAME_OWNED_BY_CSTACK) { - if (bpf_probe_read_user( - frame_ptr, sizeof(void *), (void *) (cur_frame + offsets->VFrame_previous))) { - return -PY_ERROR_FRAME_PREV; - } - cur_frame = *frame_ptr; - if (!cur_frame) { - return 0; - } - } else if (owner != FRAME_OWNED_BY_THREAD && - owner != FRAME_OWNED_BY_GENERATOR && - owner != FRAME_OWNED_BY_FRAME_OBJECT) { - return -PY_ERROR_FRAME_OWNER_INVALID; - } - } - // read PyCodeObject first, if that fails, then no point reading next frame - if (bpf_probe_read_user( - &code_ptr, sizeof(void *), (void *) (cur_frame + offsets->VFrame_code))) { - return -PY_ERROR_FRAME_CODE; - } - if (!code_ptr) { - return 0; // todo learn when this happens, c extension? - } - log_debug("code %llx", code_ptr); - int res = get_names(cur_frame, code_ptr, offsets, symbol, ctx); - if (res < 0) { - return res; - } - - // read next PyFrameObject/PyInterpreterFrame pointer, update in place - if (bpf_probe_read_user( - frame_ptr, sizeof(void *), (void *) (cur_frame + offsets->VFrame_previous))) { - return -PY_ERROR_FRAME_PREV; - } - - return 1; -} -// should be enough -#define PY_NUM_CPU 512 - -// To avoid duplicate ids, every CPU needs to use different ids when inserting -// into the hashmap. NUM_CPUS is defined at PyPerf backend side and passed -// through CFlag. -static __always_inline int get_symbol_id( - py_sample_state_t *state, - py_symbol *sym, - py_symbol_id *out_symbol_id) { - - py_symbol_id *symbol_id_ptr = bpf_map_lookup_elem(&py_symbols, sym); - if (symbol_id_ptr) { - *out_symbol_id = *symbol_id_ptr; - return 0; - } - // the symbol is new, bump the counter - state->symbol_counter++; - py_symbol_id symbol_id = state->symbol_counter * PY_NUM_CPU + state->cur_cpu; - if (bpf_map_update_elem(&py_symbols, sym, &symbol_id, BPF_NOEXIST) == 0) { - *out_symbol_id = symbol_id; - return 0; - } - symbol_id_ptr = bpf_map_lookup_elem(&py_symbols, sym); - if (symbol_id_ptr) { - *out_symbol_id = *symbol_id_ptr; - return 0; - } - *out_symbol_id = 0; - return -1; -} - -SEC("perf_event") -int read_python_stack(struct bpf_perf_event_data *ctx) { - GET_STATE(); - - state->python_stack_prog_call_cnt++; - py_event *sample = &state->event; - - int last_res; - py_symbol *sym = &state->sym; -#pragma unroll - for (int i = 0; i < PYTHON_STACK_FRAMES_PER_PROG; i++) { - log_debug("----- frame %d %llx -----", sample->stack_len, state->frame_ptr); - last_res = get_frame_data((void **) &state->frame_ptr, &state->offsets, sym, ctx); - if (last_res < 0) { - return submit_error_sample((uint8_t) (-last_res)); - } - if (last_res == 0) { - break; - } - if (last_res == 1) { - py_symbol_id symbol_id; - if (get_symbol_id(state, sym, &symbol_id)) { - return submit_error_sample(PY_ERROR_SYMBOL); - } - uint32_t cur_len = sample->stack_len; - if (cur_len < PYTHON_STACK_MAX_LEN) { - sample->stack[cur_len] = symbol_id; - sample->stack_len++; - } - } - } - - if (last_res == 0) { - sample->k.flags = SAMPLE_KEY_FLAG_PYTHON_STACK; - } else { - sample->k.flags = (SAMPLE_KEY_FLAG_PYTHON_STACK|SAMPLE_KEY_FLAG_STACK_TRUNCATED); - } - - if (sample->k.flags == (SAMPLE_KEY_FLAG_PYTHON_STACK|SAMPLE_KEY_FLAG_STACK_TRUNCATED) && - state->python_stack_prog_call_cnt < PYTHON_STACK_PROG_CNT) { - // read next batch of frames - bpf_tail_call(ctx, &py_progs, PYTHON_PROG_IDX_READ_PYTHON_STACK); - return -1; - } - - return submit_sample(state); -} - -#endif // PYPERF_H - -char _license[] SEC("license") = "GPL"; diff --git a/ebpf/bpf/pystr.h b/ebpf/bpf/pystr.h deleted file mode 100644 index 736f8b8929..0000000000 --- a/ebpf/bpf/pystr.h +++ /dev/null @@ -1,81 +0,0 @@ -// -// Created by korniltsev on 11/2/23. -// - -#ifndef PYROEBPF_PYSTR_H -#define PYROEBPF_PYSTR_H - -#include "pyoffsets.h" - -#define PYSTR_TYPE_1BYTE 1 -#define PYSTR_TYPE_2BYTE 2 -#define PYSTR_TYPE_4BYTE 4 -#define PYSTR_TYPE_ASCII 8 -#define PYSTR_TYPE_UTF8 16 -#define PYSTR_TYPE_NOT_COMPACT 32 - - -struct py_str_type { - uint8_t type; - uint8_t size_codepoints; -} ; - - -struct _object { - union { - u64 ob_refcnt; /* 0 8 */ - uint32_t ob_refcnt_split[2]; /* 0 8 */ - }; /* 0 8 */ - void * ob_type; /* 8 8 */ -}; - - -// Note: it is incomplete -// Some state fields may be omitted -// Also wstr field is omitted -// Only first 32 bytes are here -typedef struct { - struct _object ob_base; /* 0 16 */ - u64 length; /* 16 8 */ - u64 hash; /* 24 8 */ - struct { - unsigned int interned:2; /* 32: 0 4 */ - unsigned int kind:3; /* 32: 2 4 */ - unsigned int compact:1; /* 32: 5 4 */ - unsigned int ascii:1; /* 32: 6 4 */ - } state; /* 32 4 */ -} PyASCIIObject; - -// Read compact strings from PyASCIIObject or PyCompactUnicodeObject -static __always_inline int pystr_read(void *str, py_offset_config *offsets, char *buf, u64 buf_size, struct py_str_type *typ) { - PyASCIIObject pystr = {}; - if (bpf_probe_read_user(&pystr, sizeof(PyASCIIObject), str)) { - return -1; - } - if (pystr.state.compact == 0) { // not implemented, skip - typ->type = PYSTR_TYPE_NOT_COMPACT; - return 0; - } - u64 sz_bytes = pystr.state.kind * pystr.length; - if (sz_bytes > buf_size) { - sz_bytes = buf_size; - typ->size_codepoints = sz_bytes/pystr.state.kind; - } else { - typ->size_codepoints = pystr.length; - } - void *data; - if (pystr.state.ascii) { - typ->type = pystr.state.kind | PYSTR_TYPE_ASCII; - data = str + offsets->PyASCIIObject_size; - } else { - typ->type = pystr.state.kind; - data = str + offsets->PyCompactUnicodeObject_size; - } - - if (bpf_probe_read_user(buf, sz_bytes, data)) { - return -1; - }; - return 0; -} - -#endif //PYROEBPF_PYSTR_H diff --git a/ebpf/bpf/stacks.h b/ebpf/bpf/stacks.h deleted file mode 100644 index afe6bb5722..0000000000 --- a/ebpf/bpf/stacks.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef PYROSCOPE_STACKS_H -#define PYROSCOPE_STACKS_H - -#define PERF_MAX_STACK_DEPTH 127 -#define PROFILE_MAPS_SIZE 16384 - -#define KERN_STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP) -#define USER_STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP | BPF_F_USER_STACK) - -#define SAMPLE_KEY_FLAG_PYTHON_STACK 1 -#define SAMPLE_KEY_FLAG_STACK_TRUNCATED 2 - -struct sample_key { - __u32 pid; - __u32 flags; - __s64 kern_stack; - __s64 user_stack; -}; - -struct { - __uint(type, BPF_MAP_TYPE_STACK_TRACE); - __uint(key_size, sizeof(u32)); - __uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64)); - __uint(max_entries, PROFILE_MAPS_SIZE); -} stacks SEC(".maps"); - - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, struct sample_key); - __type(value, u32); - __uint(max_entries, PROFILE_MAPS_SIZE); -} counts SEC(".maps"); - - -#endif \ No newline at end of file diff --git a/ebpf/bpf/ume.h b/ebpf/bpf/ume.h deleted file mode 100644 index 3961d50ba5..0000000000 --- a/ebpf/bpf/ume.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef UME_H -#define UME_H - - -#if defined(PYROSCOPE_UME) - -#define pyro_bpf_core_read(dst, sz, src) \ - bpf_probe_read_kernel(dst, sz, src) - - -#else - -#include "bpf_core_read.h" - -#define pyro_bpf_core_read(dst, sz, src) \ - bpf_core_read(dst, sz, src) - - -#endif - -//#define BPF_DEBUG - -#if defined(BPF_DEBUG) -#define bpf_dbg_printk(fmt, args...) bpf_printk(fmt, ##args) -#else -#define bpf_dbg_printk(fmt, args...) -#endif - -#endif // UME_H \ No newline at end of file diff --git a/ebpf/bpf/vmlinux/vmlinux-arm64.h b/ebpf/bpf/vmlinux/vmlinux-arm64.h deleted file mode 100644 index b0acc5483d..0000000000 --- a/ebpf/bpf/vmlinux/vmlinux-arm64.h +++ /dev/null @@ -1,97288 +0,0 @@ -#ifndef __VMLINUX_H__ -#define __VMLINUX_H__ - -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) -#endif - -typedef signed char __s8; - -typedef unsigned char __u8; - -typedef short unsigned int __u16; - -typedef int __s32; - -typedef unsigned int __u32; - -typedef long long int __s64; - -typedef long long unsigned int __u64; - -typedef __s8 s8; - -typedef __u8 u8; - -typedef __u16 u16; - -typedef __s32 s32; - -typedef __u32 u32; - -typedef __s64 s64; - -typedef __u64 u64; - -enum { - false = 0, - true = 1, -}; - -typedef long int __kernel_long_t; - -typedef long unsigned int __kernel_ulong_t; - -typedef int __kernel_pid_t; - -typedef unsigned int __kernel_uid32_t; - -typedef unsigned int __kernel_gid32_t; - -typedef __kernel_ulong_t __kernel_size_t; - -typedef __kernel_long_t __kernel_ssize_t; - -typedef long long int __kernel_loff_t; - -typedef long long int __kernel_time64_t; - -typedef __kernel_long_t __kernel_clock_t; - -typedef int __kernel_timer_t; - -typedef int __kernel_clockid_t; - -typedef __u32 __le32; - -typedef unsigned int __poll_t; - -typedef u32 __kernel_dev_t; - -typedef __kernel_dev_t dev_t; - -typedef short unsigned int umode_t; - -typedef __kernel_pid_t pid_t; - -typedef __kernel_clockid_t clockid_t; - -typedef _Bool bool; - -typedef __kernel_uid32_t uid_t; - -typedef __kernel_gid32_t gid_t; - -typedef __kernel_loff_t loff_t; - -typedef __kernel_size_t size_t; - -typedef __kernel_ssize_t ssize_t; - -typedef s32 int32_t; - -typedef u32 uint32_t; - -typedef u64 sector_t; - -typedef u64 blkcnt_t; - -typedef unsigned int gfp_t; - -typedef unsigned int fmode_t; - -typedef u64 phys_addr_t; - -typedef long unsigned int irq_hw_number_t; - -typedef struct { - int counter; -} atomic_t; - -typedef struct { - s64 counter; -} atomic64_t; - -struct list_head { - struct list_head *next; - struct list_head *prev; -}; - -struct hlist_node; - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next; - struct hlist_node **pprev; -}; - -struct callback_head { - struct callback_head *next; - void (*func)(struct callback_head *); -}; - -struct kernel_symbol { - int value_offset; - int name_offset; - int namespace_offset; -}; - -struct jump_entry { - s32 code; - s32 target; - long int key; -}; - -struct static_key_mod; - -struct static_key { - atomic_t enabled; - union { - long unsigned int type; - struct jump_entry *entries; - struct static_key_mod *next; - }; -}; - -struct static_key_false { - struct static_key key; -}; - -typedef int (*initcall_t)(); - -typedef int initcall_entry_t; - -struct lock_class_key {}; - -struct fs_context; - -struct fs_parameter_spec; - -struct dentry; - -struct super_block; - -struct module; - -struct file_system_type { - const char *name; - int fs_flags; - int (*init_fs_context)(struct fs_context *); - const struct fs_parameter_spec *parameters; - struct dentry * (*mount)(struct file_system_type *, int, const char *, void *); - void (*kill_sb)(struct super_block *); - struct module *owner; - struct file_system_type *next; - struct hlist_head fs_supers; - struct lock_class_key s_lock_key; - struct lock_class_key s_umount_key; - struct lock_class_key s_vfs_rename_key; - struct lock_class_key s_writers_key[3]; - struct lock_class_key i_lock_key; - struct lock_class_key i_mutex_key; - struct lock_class_key i_mutex_dir_key; -}; - -struct obs_kernel_param { - const char *str; - int (*setup_func)(char *); - int early; -}; - -typedef atomic64_t atomic_long_t; - -struct qspinlock { - union { - atomic_t val; - struct { - u8 locked; - u8 pending; - }; - struct { - u16 locked_pending; - u16 tail; - }; - }; -}; - -typedef struct qspinlock arch_spinlock_t; - -struct qrwlock { - union { - atomic_t cnts; - struct { - u8 wlocked; - u8 __lstate[3]; - }; - }; - arch_spinlock_t wait_lock; -}; - -typedef struct qrwlock arch_rwlock_t; - -struct lockdep_map {}; - -struct raw_spinlock { - arch_spinlock_t raw_lock; -}; - -typedef struct raw_spinlock raw_spinlock_t; - -struct spinlock { - union { - struct raw_spinlock rlock; - }; -}; - -typedef struct spinlock spinlock_t; - -typedef struct { - arch_rwlock_t raw_lock; -} rwlock_t; - -struct ratelimit_state { - raw_spinlock_t lock; - int interval; - int burst; - int printed; - int missed; - long unsigned int begin; - long unsigned int flags; -}; - -typedef void *fl_owner_t; - -struct file; - -struct kiocb; - -struct iov_iter; - -struct dir_context; - -struct poll_table_struct; - -struct vm_area_struct; - -struct inode; - -struct file_lock; - -struct page; - -struct pipe_inode_info; - -struct seq_file; - -struct file_operations { - struct module *owner; - loff_t (*llseek)(struct file *, loff_t, int); - ssize_t (*read)(struct file *, char *, size_t, loff_t *); - ssize_t (*write)(struct file *, const char *, size_t, loff_t *); - ssize_t (*read_iter)(struct kiocb *, struct iov_iter *); - ssize_t (*write_iter)(struct kiocb *, struct iov_iter *); - int (*iopoll)(struct kiocb *, bool); - int (*iterate)(struct file *, struct dir_context *); - int (*iterate_shared)(struct file *, struct dir_context *); - __poll_t (*poll)(struct file *, struct poll_table_struct *); - long int (*unlocked_ioctl)(struct file *, unsigned int, long unsigned int); - long int (*compat_ioctl)(struct file *, unsigned int, long unsigned int); - int (*mmap)(struct file *, struct vm_area_struct *); - long unsigned int mmap_supported_flags; - int (*open)(struct inode *, struct file *); - int (*flush)(struct file *, fl_owner_t); - int (*release)(struct inode *, struct file *); - int (*fsync)(struct file *, loff_t, loff_t, int); - int (*fasync)(int, struct file *, int); - int (*lock)(struct file *, int, struct file_lock *); - ssize_t (*sendpage)(struct file *, struct page *, int, size_t, loff_t *, int); - long unsigned int (*get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - int (*check_flags)(int); - int (*flock)(struct file *, int, struct file_lock *); - ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); - ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); - int (*setlease)(struct file *, long int, struct file_lock **, void **); - long int (*fallocate)(struct file *, int, loff_t, loff_t); - void (*show_fdinfo)(struct seq_file *, struct file *); - ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); - loff_t (*remap_file_range)(struct file *, loff_t, struct file *, loff_t, loff_t, unsigned int); - int (*fadvise)(struct file *, loff_t, loff_t, int); -}; - -enum system_states { - SYSTEM_BOOTING = 0, - SYSTEM_SCHEDULING = 1, - SYSTEM_RUNNING = 2, - SYSTEM_HALT = 3, - SYSTEM_POWER_OFF = 4, - SYSTEM_RESTART = 5, - SYSTEM_SUSPEND = 6, -}; - -typedef __s64 time64_t; - -struct __kernel_timespec { - __kernel_time64_t tv_sec; - long long int tv_nsec; -}; - -struct timespec64 { - time64_t tv_sec; - long int tv_nsec; -}; - -struct bug_entry { - int bug_addr_disp; - int file_disp; - short unsigned int line; - short unsigned int flags; -}; - -struct cpumask { - long unsigned int bits[4]; -}; - -typedef struct cpumask cpumask_t; - -typedef struct cpumask cpumask_var_t[1]; - -struct llist_node { - struct llist_node *next; -}; - -struct __call_single_node { - struct llist_node llist; - union { - unsigned int u_flags; - atomic_t a_flags; - }; - u16 src; - u16 dst; -}; - -typedef void (*smp_call_func_t)(void *); - -struct __call_single_data { - union { - struct __call_single_node node; - struct { - struct llist_node llist; - unsigned int flags; - u16 src; - u16 dst; - }; - }; - smp_call_func_t func; - void *info; -}; - -enum timespec_type { - TT_NONE = 0, - TT_NATIVE = 1, - TT_COMPAT = 2, -}; - -typedef s32 old_time32_t; - -struct old_timespec32 { - old_time32_t tv_sec; - s32 tv_nsec; -}; - -struct pollfd { - int fd; - short int events; - short int revents; -}; - -struct restart_block { - long int (*fn)(struct restart_block *); - union { - struct { - u32 *uaddr; - u32 val; - u32 flags; - u32 bitset; - u64 time; - u32 *uaddr2; - } futex; - struct { - clockid_t clockid; - enum timespec_type type; - union { - struct __kernel_timespec *rmtp; - struct old_timespec32 *compat_rmtp; - }; - u64 expires; - } nanosleep; - struct { - struct pollfd *ufds; - int nfds; - int has_timeout; - long unsigned int tv_sec; - long unsigned int tv_nsec; - } poll; - }; -}; - -typedef long unsigned int mm_segment_t; - -struct thread_info { - long unsigned int flags; - mm_segment_t addr_limit; - union { - u64 preempt_count; - struct { - u32 count; - u32 need_resched; - } preempt; - }; -}; - -struct refcount_struct { - atomic_t refs; -}; - -typedef struct refcount_struct refcount_t; - -struct load_weight { - long unsigned int weight; - u32 inv_weight; -}; - -struct rb_node { - long unsigned int __rb_parent_color; - struct rb_node *rb_right; - struct rb_node *rb_left; -}; - -struct sched_statistics { - u64 wait_start; - u64 wait_max; - u64 wait_count; - u64 wait_sum; - u64 iowait_count; - u64 iowait_sum; - u64 sleep_start; - u64 sleep_max; - s64 sum_sleep_runtime; - u64 block_start; - u64 block_max; - u64 exec_max; - u64 slice_max; - u64 nr_migrations_cold; - u64 nr_failed_migrations_affine; - u64 nr_failed_migrations_running; - u64 nr_failed_migrations_hot; - u64 nr_forced_migrations; - u64 nr_wakeups; - u64 nr_wakeups_sync; - u64 nr_wakeups_migrate; - u64 nr_wakeups_local; - u64 nr_wakeups_remote; - u64 nr_wakeups_affine; - u64 nr_wakeups_affine_attempts; - u64 nr_wakeups_passive; - u64 nr_wakeups_idle; -}; - -struct util_est { - unsigned int enqueued; - unsigned int ewma; -}; - -struct sched_avg { - u64 last_update_time; - u64 load_sum; - u64 runnable_sum; - u32 util_sum; - u32 period_contrib; - long unsigned int load_avg; - long unsigned int runnable_avg; - long unsigned int util_avg; - struct util_est util_est; -}; - -struct cfs_rq; - -struct sched_entity { - struct load_weight load; - struct rb_node run_node; - struct list_head group_node; - unsigned int on_rq; - u64 exec_start; - u64 sum_exec_runtime; - u64 vruntime; - u64 prev_sum_exec_runtime; - u64 nr_migrations; - struct sched_statistics statistics; - int depth; - struct sched_entity *parent; - struct cfs_rq *cfs_rq; - struct cfs_rq *my_q; - long unsigned int runnable_weight; - long: 64; - long: 64; - long: 64; - struct sched_avg avg; -}; - -struct sched_rt_entity { - struct list_head run_list; - long unsigned int timeout; - long unsigned int watchdog_stamp; - unsigned int time_slice; - short unsigned int on_rq; - short unsigned int on_list; - struct sched_rt_entity *back; -}; - -typedef s64 ktime_t; - -struct timerqueue_node { - struct rb_node node; - ktime_t expires; -}; - -enum hrtimer_restart { - HRTIMER_NORESTART = 0, - HRTIMER_RESTART = 1, -}; - -struct hrtimer_clock_base; - -struct hrtimer { - struct timerqueue_node node; - ktime_t _softexpires; - enum hrtimer_restart (*function)(struct hrtimer *); - struct hrtimer_clock_base *base; - u8 state; - u8 is_rel; - u8 is_soft; - u8 is_hard; -}; - -struct sched_dl_entity { - struct rb_node rb_node; - u64 dl_runtime; - u64 dl_deadline; - u64 dl_period; - u64 dl_bw; - u64 dl_density; - s64 runtime; - u64 deadline; - unsigned int flags; - unsigned int dl_throttled: 1; - unsigned int dl_yielded: 1; - unsigned int dl_non_contending: 1; - unsigned int dl_overrun: 1; - struct hrtimer dl_timer; - struct hrtimer inactive_timer; - struct sched_dl_entity *pi_se; -}; - -union rcu_special { - struct { - u8 blocked; - u8 need_qs; - u8 exp_hint; - u8 need_mb; - } b; - u32 s; -}; - -struct sched_info { - long unsigned int pcount; - long long unsigned int run_delay; - long long unsigned int last_arrival; - long long unsigned int last_queued; -}; - -struct plist_node { - int prio; - struct list_head prio_list; - struct list_head node_list; -}; - -struct vmacache { - u64 seqnum; - struct vm_area_struct *vmas[4]; -}; - -struct task_rss_stat { - int events; - int count[4]; -}; - -struct prev_cputime { - u64 utime; - u64 stime; - raw_spinlock_t lock; -}; - -struct rb_root { - struct rb_node *rb_node; -}; - -struct rb_root_cached { - struct rb_root rb_root; - struct rb_node *rb_leftmost; -}; - -struct timerqueue_head { - struct rb_root_cached rb_root; -}; - -struct posix_cputimer_base { - u64 nextevt; - struct timerqueue_head tqhead; -}; - -struct posix_cputimers { - struct posix_cputimer_base bases[3]; - unsigned int timers_active; - unsigned int expiry_active; -}; - -struct sem_undo_list; - -struct sysv_sem { - struct sem_undo_list *undo_list; -}; - -struct sysv_shm { - struct list_head shm_clist; -}; - -typedef struct { - long unsigned int sig[1]; -} sigset_t; - -struct sigpending { - struct list_head list; - sigset_t signal; -}; - -typedef struct { - uid_t val; -} kuid_t; - -struct seccomp_filter; - -struct seccomp { - int mode; - atomic_t filter_count; - struct seccomp_filter *filter; -}; - -struct wake_q_node { - struct wake_q_node *next; -}; - -struct irqtrace_events { - unsigned int irq_events; - long unsigned int hardirq_enable_ip; - long unsigned int hardirq_disable_ip; - unsigned int hardirq_enable_event; - unsigned int hardirq_disable_event; - long unsigned int softirq_disable_ip; - long unsigned int softirq_enable_ip; - unsigned int softirq_disable_event; - unsigned int softirq_enable_event; -}; - -struct task_io_accounting { - u64 rchar; - u64 wchar; - u64 syscr; - u64 syscw; - u64 read_bytes; - u64 write_bytes; - u64 cancelled_write_bytes; -}; - -typedef struct { - long unsigned int bits[1]; -} nodemask_t; - -struct seqcount { - unsigned int sequence; -}; - -typedef struct seqcount seqcount_t; - -struct seqcount_spinlock { - seqcount_t seqcount; -}; - -typedef struct seqcount_spinlock seqcount_spinlock_t; - -struct optimistic_spin_queue { - atomic_t tail; -}; - -struct mutex { - atomic_long_t owner; - spinlock_t wait_lock; - struct optimistic_spin_queue osq; - struct list_head wait_list; -}; - -struct tlbflush_unmap_batch {}; - -struct page_frag { - struct page *page; - __u32 offset; - __u32 size; -}; - -struct latency_record { - long unsigned int backtrace[12]; - unsigned int count; - long unsigned int time; - long unsigned int max; -}; - -struct cpu_context { - long unsigned int x19; - long unsigned int x20; - long unsigned int x21; - long unsigned int x22; - long unsigned int x23; - long unsigned int x24; - long unsigned int x25; - long unsigned int x26; - long unsigned int x27; - long unsigned int x28; - long unsigned int fp; - long unsigned int sp; - long unsigned int pc; -}; - -struct user_fpsimd_state { - __int128 unsigned vregs[32]; - __u32 fpsr; - __u32 fpcr; - __u32 __reserved[2]; -}; - -struct perf_event; - -struct debug_info { - int suspended_step; - int bps_disabled; - int wps_disabled; - struct perf_event *hbp_break[16]; - struct perf_event *hbp_watch[16]; -}; - -struct ptrauth_key { - long unsigned int lo; - long unsigned int hi; -}; - -struct ptrauth_keys_user { - struct ptrauth_key apia; - struct ptrauth_key apib; - struct ptrauth_key apda; - struct ptrauth_key apdb; - struct ptrauth_key apga; -}; - -struct ptrauth_keys_kernel { - struct ptrauth_key apia; -}; - -struct thread_struct { - struct cpu_context cpu_context; - long: 64; - struct { - long unsigned int tp_value; - long unsigned int tp2_value; - struct user_fpsimd_state fpsimd_state; - } uw; - unsigned int fpsimd_cpu; - void *sve_state; - unsigned int sve_vl; - unsigned int sve_vl_onexec; - long unsigned int fault_address; - long unsigned int fault_code; - struct debug_info debug; - struct ptrauth_keys_user keys_user; - struct ptrauth_keys_kernel keys_kernel; - u64 sctlr_tcf0; - u64 gcr_user_incl; - long: 64; -}; - -struct sched_class; - -struct task_group; - -struct rcu_node; - -struct mm_struct; - -struct pid; - -struct completion; - -struct cred; - -struct key; - -struct nameidata; - -struct fs_struct; - -struct files_struct; - -struct io_uring_task; - -struct nsproxy; - -struct signal_struct; - -struct sighand_struct; - -struct audit_context; - -struct rt_mutex_waiter; - -struct bio_list; - -struct blk_plug; - -struct reclaim_state; - -struct backing_dev_info; - -struct io_context; - -struct capture_control; - -struct kernel_siginfo; - -typedef struct kernel_siginfo kernel_siginfo_t; - -struct css_set; - -struct robust_list_head; - -struct compat_robust_list_head; - -struct futex_pi_state; - -struct perf_event_context; - -struct rseq; - -struct task_delay_info; - -struct ftrace_ret_stack; - -struct mem_cgroup; - -struct request_queue; - -struct vm_struct; - -struct task_struct { - struct thread_info thread_info; - volatile long int state; - void *stack; - refcount_t usage; - unsigned int flags; - unsigned int ptrace; - int on_cpu; - struct __call_single_node wake_entry; - unsigned int cpu; - unsigned int wakee_flips; - long unsigned int wakee_flip_decay_ts; - struct task_struct *last_wakee; - int recent_used_cpu; - int wake_cpu; - int on_rq; - int prio; - int static_prio; - int normal_prio; - unsigned int rt_priority; - const struct sched_class *sched_class; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct sched_entity se; - struct sched_rt_entity rt; - struct task_group *sched_task_group; - struct sched_dl_entity dl; - struct hlist_head preempt_notifiers; - unsigned int btrace_seq; - unsigned int policy; - int nr_cpus_allowed; - const cpumask_t *cpus_ptr; - cpumask_t cpus_mask; - int rcu_read_lock_nesting; - union rcu_special rcu_read_unlock_special; - struct list_head rcu_node_entry; - struct rcu_node *rcu_blocked_node; - long unsigned int rcu_tasks_nvcsw; - u8 rcu_tasks_holdout; - u8 rcu_tasks_idx; - int rcu_tasks_idle_cpu; - struct list_head rcu_tasks_holdout_list; - int trc_reader_nesting; - int trc_ipi_to_cpu; - union rcu_special trc_reader_special; - bool trc_reader_checked; - struct list_head trc_holdout_list; - struct sched_info sched_info; - struct list_head tasks; - struct plist_node pushable_tasks; - struct rb_node pushable_dl_tasks; - struct mm_struct *mm; - struct mm_struct *active_mm; - struct vmacache vmacache; - struct task_rss_stat rss_stat; - int exit_state; - int exit_code; - int exit_signal; - int pdeath_signal; - long unsigned int jobctl; - unsigned int personality; - unsigned int sched_reset_on_fork: 1; - unsigned int sched_contributes_to_load: 1; - unsigned int sched_migrated: 1; - int: 29; - unsigned int sched_remote_wakeup: 1; - unsigned int in_execve: 1; - unsigned int in_iowait: 1; - unsigned int in_user_fault: 1; - unsigned int no_cgroup_migration: 1; - unsigned int frozen: 1; - unsigned int use_memdelay: 1; - long unsigned int atomic_flags; - struct restart_block restart_block; - pid_t pid; - pid_t tgid; - long unsigned int stack_canary; - struct task_struct *real_parent; - struct task_struct *parent; - struct list_head children; - struct list_head sibling; - struct task_struct *group_leader; - struct list_head ptraced; - struct list_head ptrace_entry; - struct pid *thread_pid; - struct hlist_node pid_links[4]; - struct list_head thread_group; - struct list_head thread_node; - struct completion *vfork_done; - int *set_child_tid; - int *clear_child_tid; - u64 utime; - u64 stime; - u64 gtime; - struct prev_cputime prev_cputime; - long unsigned int nvcsw; - long unsigned int nivcsw; - u64 start_time; - u64 start_boottime; - long unsigned int min_flt; - long unsigned int maj_flt; - struct posix_cputimers posix_cputimers; - const struct cred *ptracer_cred; - const struct cred *real_cred; - const struct cred *cred; - struct key *cached_requested_key; - char comm[16]; - struct nameidata *nameidata; - struct sysv_sem sysvsem; - struct sysv_shm sysvshm; - long unsigned int last_switch_count; - long unsigned int last_switch_time; - struct fs_struct *fs; - struct files_struct *files; - struct io_uring_task *io_uring; - struct nsproxy *nsproxy; - struct signal_struct *signal; - struct sighand_struct *sighand; - sigset_t blocked; - sigset_t real_blocked; - sigset_t saved_sigmask; - struct sigpending pending; - long unsigned int sas_ss_sp; - size_t sas_ss_size; - unsigned int sas_ss_flags; - struct callback_head *task_works; - struct audit_context *audit_context; - kuid_t loginuid; - unsigned int sessionid; - struct seccomp seccomp; - u64 parent_exec_id; - u64 self_exec_id; - spinlock_t alloc_lock; - raw_spinlock_t pi_lock; - struct wake_q_node wake_q; - struct rb_root_cached pi_waiters; - struct task_struct *pi_top_task; - struct rt_mutex_waiter *pi_blocked_on; - struct irqtrace_events irqtrace; - unsigned int hardirq_threaded; - u64 hardirq_chain_key; - int softirqs_enabled; - int softirq_context; - int irq_config; - void *journal_info; - struct bio_list *bio_list; - struct blk_plug *plug; - struct reclaim_state *reclaim_state; - struct backing_dev_info *backing_dev_info; - struct io_context *io_context; - struct capture_control *capture_control; - long unsigned int ptrace_message; - kernel_siginfo_t *last_siginfo; - struct task_io_accounting ioac; - u64 acct_rss_mem1; - u64 acct_vm_mem1; - u64 acct_timexpd; - nodemask_t mems_allowed; - seqcount_spinlock_t mems_allowed_seq; - int cpuset_mem_spread_rotor; - int cpuset_slab_spread_rotor; - struct css_set *cgroups; - struct list_head cg_list; - struct robust_list_head *robust_list; - struct compat_robust_list_head *compat_robust_list; - struct list_head pi_state_list; - struct futex_pi_state *pi_state_cache; - struct mutex futex_exit_mutex; - unsigned int futex_state; - struct perf_event_context *perf_event_ctxp[2]; - struct mutex perf_event_mutex; - struct list_head perf_event_list; - long unsigned int preempt_disable_ip; - struct rseq *rseq; - u32 rseq_sig; - long unsigned int rseq_event_mask; - struct tlbflush_unmap_batch tlb_ubc; - union { - refcount_t rcu_users; - struct callback_head rcu; - }; - struct pipe_inode_info *splice_pipe; - struct page_frag task_frag; - struct task_delay_info *delays; - int nr_dirtied; - int nr_dirtied_pause; - long unsigned int dirty_paused_when; - int latency_record_count; - struct latency_record latency_record[32]; - u64 timer_slack_ns; - u64 default_timer_slack_ns; - int curr_ret_stack; - int curr_ret_depth; - struct ftrace_ret_stack *ret_stack; - long long unsigned int ftrace_timestamp; - atomic_t trace_overrun; - atomic_t tracing_graph_pause; - long unsigned int trace; - long unsigned int trace_recursion; - struct mem_cgroup *memcg_in_oom; - gfp_t memcg_oom_gfp_mask; - int memcg_oom_order; - unsigned int memcg_nr_pages_over_high; - struct mem_cgroup *active_memcg; - struct request_queue *throttle_queue; - int pagefault_disabled; - struct task_struct *oom_reaper_list; - struct vm_struct *stack_vm_area; - refcount_t stack_refcount; - void *security; - long: 64; - struct thread_struct thread; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef s32 compat_long_t; - -typedef u32 compat_uptr_t; - -struct user_pt_regs { - __u64 regs[31]; - __u64 sp; - __u64 pc; - __u64 pstate; -}; - -struct pt_regs { - union { - struct user_pt_regs user_regs; - struct { - u64 regs[31]; - u64 sp; - u64 pc; - u64 pstate; - }; - }; - u64 orig_x0; - s32 syscallno; - u32 unused2; - u64 orig_addr_limit; - u64 pmr_save; - u64 stackframe[2]; - u64 lockdep_hardirqs; - u64 exit_rcu; -}; - -struct arch_hw_breakpoint_ctrl { - u32 __reserved: 19; - u32 len: 8; - u32 type: 2; - u32 privilege: 2; - u32 enabled: 1; -}; - -struct arch_hw_breakpoint { - u64 address; - u64 trigger; - struct arch_hw_breakpoint_ctrl ctrl; -}; - -typedef u64 pteval_t; - -typedef u64 pmdval_t; - -typedef u64 pgdval_t; - -typedef struct { - pteval_t pte; -} pte_t; - -typedef struct { - pmdval_t pmd; -} pmd_t; - -typedef struct { - pgdval_t pgd; -} pgd_t; - -typedef struct { - pteval_t pgprot; -} pgprot_t; - -typedef struct { - pgd_t pgd; -} p4d_t; - -typedef struct { - p4d_t p4d; -} pud_t; - -enum module_state { - MODULE_STATE_LIVE = 0, - MODULE_STATE_COMING = 1, - MODULE_STATE_GOING = 2, - MODULE_STATE_UNFORMED = 3, -}; - -struct kref { - refcount_t refcount; -}; - -struct kset; - -struct kobj_type; - -struct kernfs_node; - -struct kobject { - const char *name; - struct list_head entry; - struct kobject *parent; - struct kset *kset; - struct kobj_type *ktype; - struct kernfs_node *sd; - struct kref kref; - unsigned int state_initialized: 1; - unsigned int state_in_sysfs: 1; - unsigned int state_add_uevent_sent: 1; - unsigned int state_remove_uevent_sent: 1; - unsigned int uevent_suppress: 1; -}; - -struct module_param_attrs; - -struct module_kobject { - struct kobject kobj; - struct module *mod; - struct kobject *drivers_dir; - struct module_param_attrs *mp; - struct completion *kobj_completion; -}; - -struct latch_tree_node { - struct rb_node node[2]; -}; - -struct mod_tree_node { - struct module *mod; - struct latch_tree_node node; -}; - -struct module_layout { - void *base; - unsigned int size; - unsigned int text_size; - unsigned int ro_size; - unsigned int ro_after_init_size; - struct mod_tree_node mtn; -}; - -struct mod_plt_sec { - int plt_shndx; - int plt_num_entries; - int plt_max_entries; -}; - -struct plt_entry; - -struct mod_arch_specific { - struct mod_plt_sec core; - struct mod_plt_sec init; - struct plt_entry *ftrace_trampolines; -}; - -struct elf64_sym; - -typedef struct elf64_sym Elf64_Sym; - -struct mod_kallsyms { - Elf64_Sym *symtab; - unsigned int num_symtab; - char *strtab; - char *typetab; -}; - -typedef const int tracepoint_ptr_t; - -struct module_attribute; - -struct kernel_param; - -struct exception_table_entry; - -struct module_sect_attrs; - -struct module_notes_attrs; - -struct srcu_struct; - -struct bpf_raw_event_map; - -struct trace_event_call; - -struct trace_eval_map; - -struct error_injection_entry; - -struct module { - enum module_state state; - struct list_head list; - char name[56]; - struct module_kobject mkobj; - struct module_attribute *modinfo_attrs; - const char *version; - const char *srcversion; - struct kobject *holders_dir; - const struct kernel_symbol *syms; - const s32 *crcs; - unsigned int num_syms; - struct mutex param_lock; - struct kernel_param *kp; - unsigned int num_kp; - unsigned int num_gpl_syms; - const struct kernel_symbol *gpl_syms; - const s32 *gpl_crcs; - bool using_gplonly_symbols; - bool async_probe_requested; - const struct kernel_symbol *gpl_future_syms; - const s32 *gpl_future_crcs; - unsigned int num_gpl_future_syms; - unsigned int num_exentries; - struct exception_table_entry *extable; - int (*init)(); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct module_layout core_layout; - struct module_layout init_layout; - struct mod_arch_specific arch; - long unsigned int taints; - unsigned int num_bugs; - struct list_head bug_list; - struct bug_entry *bug_table; - struct mod_kallsyms *kallsyms; - struct mod_kallsyms core_kallsyms; - struct module_sect_attrs *sect_attrs; - struct module_notes_attrs *notes_attrs; - char *args; - void *percpu; - unsigned int percpu_size; - void *noinstr_text_start; - unsigned int noinstr_text_size; - unsigned int num_tracepoints; - tracepoint_ptr_t *tracepoints_ptrs; - unsigned int num_srcu_structs; - struct srcu_struct **srcu_struct_ptrs; - unsigned int num_bpf_raw_events; - struct bpf_raw_event_map *bpf_raw_events; - struct jump_entry *jump_entries; - unsigned int num_jump_entries; - unsigned int num_trace_bprintk_fmt; - const char **trace_bprintk_fmt_start; - struct trace_event_call **trace_events; - unsigned int num_trace_events; - struct trace_eval_map **trace_evals; - unsigned int num_trace_evals; - unsigned int num_ftrace_callsites; - long unsigned int *ftrace_callsites; - void *kprobes_text_start; - unsigned int kprobes_text_size; - long unsigned int *kprobe_blacklist; - unsigned int num_kprobe_blacklist; - struct list_head source_list; - struct list_head target_list; - void (*exit)(); - atomic_t refcnt; - struct error_injection_entry *ei_funcs; - unsigned int num_ei_funcs; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum perf_event_state { - PERF_EVENT_STATE_DEAD = 4294967292, - PERF_EVENT_STATE_EXIT = 4294967293, - PERF_EVENT_STATE_ERROR = 4294967294, - PERF_EVENT_STATE_OFF = 4294967295, - PERF_EVENT_STATE_INACTIVE = 0, - PERF_EVENT_STATE_ACTIVE = 1, -}; - -typedef struct { - atomic_long_t a; -} local_t; - -typedef struct { - local_t a; -} local64_t; - -struct perf_event_attr { - __u32 type; - __u32 size; - __u64 config; - union { - __u64 sample_period; - __u64 sample_freq; - }; - __u64 sample_type; - __u64 read_format; - __u64 disabled: 1; - __u64 inherit: 1; - __u64 pinned: 1; - __u64 exclusive: 1; - __u64 exclude_user: 1; - __u64 exclude_kernel: 1; - __u64 exclude_hv: 1; - __u64 exclude_idle: 1; - __u64 mmap: 1; - __u64 comm: 1; - __u64 freq: 1; - __u64 inherit_stat: 1; - __u64 enable_on_exec: 1; - __u64 task: 1; - __u64 watermark: 1; - __u64 precise_ip: 2; - __u64 mmap_data: 1; - __u64 sample_id_all: 1; - __u64 exclude_host: 1; - __u64 exclude_guest: 1; - __u64 exclude_callchain_kernel: 1; - __u64 exclude_callchain_user: 1; - __u64 mmap2: 1; - __u64 comm_exec: 1; - __u64 use_clockid: 1; - __u64 context_switch: 1; - __u64 write_backward: 1; - __u64 namespaces: 1; - __u64 ksymbol: 1; - __u64 bpf_event: 1; - __u64 aux_output: 1; - __u64 cgroup: 1; - __u64 text_poke: 1; - __u64 __reserved_1: 30; - union { - __u32 wakeup_events; - __u32 wakeup_watermark; - }; - __u32 bp_type; - union { - __u64 bp_addr; - __u64 kprobe_func; - __u64 uprobe_path; - __u64 config1; - }; - union { - __u64 bp_len; - __u64 kprobe_addr; - __u64 probe_offset; - __u64 config2; - }; - __u64 branch_sample_type; - __u64 sample_regs_user; - __u32 sample_stack_user; - __s32 clockid; - __u64 sample_regs_intr; - __u32 aux_watermark; - __u16 sample_max_stack; - __u16 __reserved_2; - __u32 aux_sample_size; - __u32 __reserved_3; -}; - -struct hw_perf_event_extra { - u64 config; - unsigned int reg; - int alloc; - int idx; -}; - -struct hw_perf_event { - union { - struct { - u64 config; - u64 last_tag; - long unsigned int config_base; - long unsigned int event_base; - int event_base_rdpmc; - int idx; - int last_cpu; - int flags; - struct hw_perf_event_extra extra_reg; - struct hw_perf_event_extra branch_reg; - }; - struct { - struct hrtimer hrtimer; - }; - struct { - struct list_head tp_list; - }; - struct { - u64 pwr_acc; - u64 ptsc; - }; - struct { - struct arch_hw_breakpoint info; - struct list_head bp_list; - }; - struct { - u8 iommu_bank; - u8 iommu_cntr; - u16 padding; - u64 conf; - u64 conf1; - }; - }; - struct task_struct *target; - void *addr_filters; - long unsigned int addr_filters_gen; - int state; - local64_t prev_count; - u64 sample_period; - union { - struct { - u64 last_period; - local64_t period_left; - }; - struct { - u64 saved_metric; - u64 saved_slots; - }; - }; - u64 interrupts_seq; - u64 interrupts; - u64 freq_time_stamp; - u64 freq_count_stamp; -}; - -struct wait_queue_head { - spinlock_t lock; - struct list_head head; -}; - -typedef struct wait_queue_head wait_queue_head_t; - -struct irq_work { - union { - struct __call_single_node node; - struct { - struct llist_node llnode; - atomic_t flags; - }; - }; - void (*func)(struct irq_work *); -}; - -struct perf_addr_filters_head { - struct list_head list; - raw_spinlock_t lock; - unsigned int nr_file_filters; -}; - -struct perf_sample_data; - -typedef void (*perf_overflow_handler_t)(struct perf_event *, struct perf_sample_data *, struct pt_regs *); - -struct ftrace_ops; - -typedef void (*ftrace_func_t)(long unsigned int, long unsigned int, struct ftrace_ops *, struct pt_regs *); - -struct ftrace_hash; - -struct ftrace_ops_hash { - struct ftrace_hash *notrace_hash; - struct ftrace_hash *filter_hash; - struct mutex regex_lock; -}; - -struct ftrace_ops { - ftrace_func_t func; - struct ftrace_ops *next; - long unsigned int flags; - void *private; - ftrace_func_t saved_func; - struct ftrace_ops_hash local_hash; - struct ftrace_ops_hash *func_hash; - struct ftrace_ops_hash old_hash; - long unsigned int trampoline; - long unsigned int trampoline_size; - struct list_head list; -}; - -struct pmu; - -struct perf_buffer; - -struct fasync_struct; - -struct perf_addr_filter_range; - -struct pid_namespace; - -struct bpf_prog; - -struct event_filter; - -struct perf_cgroup; - -struct perf_event { - struct list_head event_entry; - struct list_head sibling_list; - struct list_head active_list; - struct rb_node group_node; - u64 group_index; - struct list_head migrate_entry; - struct hlist_node hlist_entry; - struct list_head active_entry; - int nr_siblings; - int event_caps; - int group_caps; - struct perf_event *group_leader; - struct pmu *pmu; - void *pmu_private; - enum perf_event_state state; - unsigned int attach_state; - local64_t count; - atomic64_t child_count; - u64 total_time_enabled; - u64 total_time_running; - u64 tstamp; - u64 shadow_ctx_time; - struct perf_event_attr attr; - u16 header_size; - u16 id_header_size; - u16 read_size; - struct hw_perf_event hw; - struct perf_event_context *ctx; - atomic_long_t refcount; - atomic64_t child_total_time_enabled; - atomic64_t child_total_time_running; - struct mutex child_mutex; - struct list_head child_list; - struct perf_event *parent; - int oncpu; - int cpu; - struct list_head owner_entry; - struct task_struct *owner; - struct mutex mmap_mutex; - atomic_t mmap_count; - struct perf_buffer *rb; - struct list_head rb_entry; - long unsigned int rcu_batches; - int rcu_pending; - wait_queue_head_t waitq; - struct fasync_struct *fasync; - int pending_wakeup; - int pending_kill; - int pending_disable; - struct irq_work pending; - atomic_t event_limit; - struct perf_addr_filters_head addr_filters; - struct perf_addr_filter_range *addr_filter_ranges; - long unsigned int addr_filters_gen; - struct perf_event *aux_event; - void (*destroy)(struct perf_event *); - struct callback_head callback_head; - struct pid_namespace *ns; - u64 id; - u64 (*clock)(); - perf_overflow_handler_t overflow_handler; - void *overflow_handler_context; - perf_overflow_handler_t orig_overflow_handler; - struct bpf_prog *prog; - struct trace_event_call *tp_event; - struct event_filter *filter; - struct ftrace_ops ftrace_ops; - struct perf_cgroup *cgrp; - void *security; - struct list_head sb_list; -}; - -struct wait_queue_entry; - -typedef int (*wait_queue_func_t)(struct wait_queue_entry *, unsigned int, int, void *); - -struct wait_queue_entry { - unsigned int flags; - void *private; - wait_queue_func_t func; - struct list_head entry; -}; - -typedef struct wait_queue_entry wait_queue_entry_t; - -enum refcount_saturation_type { - REFCOUNT_ADD_NOT_ZERO_OVF = 0, - REFCOUNT_ADD_OVF = 1, - REFCOUNT_ADD_UAF = 2, - REFCOUNT_SUB_UAF = 3, - REFCOUNT_DEC_LEAK = 4, -}; - -enum pid_type { - PIDTYPE_PID = 0, - PIDTYPE_TGID = 1, - PIDTYPE_PGID = 2, - PIDTYPE_SID = 3, - PIDTYPE_MAX = 4, -}; - -struct upid { - int nr; - struct pid_namespace *ns; -}; - -struct xarray { - spinlock_t xa_lock; - gfp_t xa_flags; - void *xa_head; -}; - -struct idr { - struct xarray idr_rt; - unsigned int idr_base; - unsigned int idr_next; -}; - -struct proc_ns_operations; - -struct ns_common { - atomic_long_t stashed; - const struct proc_ns_operations *ops; - unsigned int inum; -}; - -struct kmem_cache; - -struct fs_pin; - -struct user_namespace; - -struct ucounts; - -struct pid_namespace { - struct kref kref; - struct idr idr; - struct callback_head rcu; - unsigned int pid_allocated; - struct task_struct *child_reaper; - struct kmem_cache *pid_cachep; - unsigned int level; - struct pid_namespace *parent; - struct fs_pin *bacct; - struct user_namespace *user_ns; - struct ucounts *ucounts; - int reboot; - struct ns_common ns; -}; - -struct pid { - refcount_t count; - unsigned int level; - spinlock_t lock; - struct hlist_head tasks[4]; - struct hlist_head inodes; - wait_queue_head_t wait_pidfd; - struct callback_head rcu; - struct upid numbers[1]; -}; - -struct uid_gid_extent { - u32 first; - u32 lower_first; - u32 count; -}; - -struct uid_gid_map { - u32 nr_extents; - union { - struct uid_gid_extent extent[5]; - struct { - struct uid_gid_extent *forward; - struct uid_gid_extent *reverse; - }; - }; -}; - -typedef struct { - gid_t val; -} kgid_t; - -struct rw_semaphore { - atomic_long_t count; - atomic_long_t owner; - struct optimistic_spin_queue osq; - raw_spinlock_t wait_lock; - struct list_head wait_list; -}; - -struct work_struct; - -typedef void (*work_func_t)(struct work_struct *); - -struct work_struct { - atomic_long_t data; - struct list_head entry; - work_func_t func; -}; - -struct ctl_table; - -struct ctl_table_root; - -struct ctl_table_set; - -struct ctl_dir; - -struct ctl_node; - -struct ctl_table_header { - union { - struct { - struct ctl_table *ctl_table; - int used; - int count; - int nreg; - }; - struct callback_head rcu; - }; - struct completion *unregistering; - struct ctl_table *ctl_table_arg; - struct ctl_table_root *root; - struct ctl_table_set *set; - struct ctl_dir *parent; - struct ctl_node *node; - struct hlist_head inodes; -}; - -struct ctl_dir { - struct ctl_table_header header; - struct rb_root root; -}; - -struct ctl_table_set { - int (*is_seen)(struct ctl_table_set *); - struct ctl_dir dir; -}; - -struct user_namespace { - struct uid_gid_map uid_map; - struct uid_gid_map gid_map; - struct uid_gid_map projid_map; - atomic_t count; - struct user_namespace *parent; - int level; - kuid_t owner; - kgid_t group; - struct ns_common ns; - long unsigned int flags; - bool parent_could_setfcap; - struct list_head keyring_name_list; - struct key *user_keyring_register; - struct rw_semaphore keyring_sem; - struct work_struct work; - struct ctl_table_set set; - struct ctl_table_header *sysctls; - struct ucounts *ucounts; - int ucount_max[10]; -}; - -struct timer_list { - struct hlist_node entry; - long unsigned int expires; - void (*function)(struct timer_list *); - u32 flags; -}; - -struct workqueue_struct; - -struct delayed_work { - struct work_struct work; - struct timer_list timer; - struct workqueue_struct *wq; - int cpu; -}; - -struct rcu_work { - struct work_struct work; - struct callback_head rcu; - struct workqueue_struct *wq; -}; - -typedef struct page *pgtable_t; - -struct address_space; - -struct dev_pagemap; - -struct obj_cgroup; - -struct page { - long unsigned int flags; - union { - struct { - struct list_head lru; - struct address_space *mapping; - long unsigned int index; - long unsigned int private; - }; - struct { - long unsigned int dma_addr[2]; - }; - struct { - union { - struct list_head slab_list; - struct { - struct page *next; - int pages; - int pobjects; - }; - }; - struct kmem_cache *slab_cache; - void *freelist; - union { - void *s_mem; - long unsigned int counters; - struct { - unsigned int inuse: 16; - unsigned int objects: 15; - unsigned int frozen: 1; - }; - }; - }; - struct { - long unsigned int compound_head; - unsigned char compound_dtor; - unsigned char compound_order; - atomic_t compound_mapcount; - unsigned int compound_nr; - }; - struct { - long unsigned int _compound_pad_1; - atomic_t hpage_pinned_refcount; - struct list_head deferred_list; - }; - struct { - long unsigned int _pt_pad_1; - pgtable_t pmd_huge_pte; - long unsigned int _pt_pad_2; - union { - struct mm_struct *pt_mm; - atomic_t pt_frag_refcount; - }; - spinlock_t ptl; - }; - struct { - struct dev_pagemap *pgmap; - void *zone_device_data; - }; - struct callback_head callback_head; - }; - union { - atomic_t _mapcount; - unsigned int page_type; - unsigned int active; - int units; - }; - atomic_t _refcount; - union { - struct mem_cgroup *mem_cgroup; - struct obj_cgroup **obj_cgroups; - }; -}; - -struct seqcount_raw_spinlock { - seqcount_t seqcount; -}; - -typedef struct seqcount_raw_spinlock seqcount_raw_spinlock_t; - -typedef struct { - seqcount_spinlock_t seqcount; - spinlock_t lock; -} seqlock_t; - -struct hrtimer_cpu_base; - -struct hrtimer_clock_base { - struct hrtimer_cpu_base *cpu_base; - unsigned int index; - clockid_t clockid; - seqcount_raw_spinlock_t seq; - struct hrtimer *running; - struct timerqueue_head active; - ktime_t (*get_time)(); - ktime_t offset; -}; - -struct hrtimer_cpu_base { - raw_spinlock_t lock; - unsigned int cpu; - unsigned int active_bases; - unsigned int clock_was_set_seq; - unsigned int hres_active: 1; - unsigned int in_hrtirq: 1; - unsigned int hang_detected: 1; - unsigned int softirq_activated: 1; - unsigned int nr_events; - short unsigned int nr_retries; - short unsigned int nr_hangs; - unsigned int max_hang_time; - ktime_t expires_next; - struct hrtimer *next_timer; - ktime_t softirq_expires_next; - struct hrtimer *softirq_next_timer; - struct hrtimer_clock_base clock_base[8]; -}; - -enum node_states { - N_POSSIBLE = 0, - N_ONLINE = 1, - N_NORMAL_MEMORY = 2, - N_HIGH_MEMORY = 2, - N_MEMORY = 3, - N_CPU = 4, - N_GENERIC_INITIATOR = 5, - NR_NODE_STATES = 6, -}; - -struct rlimit { - __kernel_ulong_t rlim_cur; - __kernel_ulong_t rlim_max; -}; - -struct task_cputime { - u64 stime; - u64 utime; - long long unsigned int sum_exec_runtime; -}; - -typedef void __signalfn_t(int); - -typedef __signalfn_t *__sighandler_t; - -typedef void __restorefn_t(); - -typedef __restorefn_t *__sigrestore_t; - -union sigval { - int sival_int; - void *sival_ptr; -}; - -typedef union sigval sigval_t; - -union __sifields { - struct { - __kernel_pid_t _pid; - __kernel_uid32_t _uid; - } _kill; - struct { - __kernel_timer_t _tid; - int _overrun; - sigval_t _sigval; - int _sys_private; - } _timer; - struct { - __kernel_pid_t _pid; - __kernel_uid32_t _uid; - sigval_t _sigval; - } _rt; - struct { - __kernel_pid_t _pid; - __kernel_uid32_t _uid; - int _status; - __kernel_clock_t _utime; - __kernel_clock_t _stime; - } _sigchld; - struct { - void *_addr; - union { - short int _addr_lsb; - struct { - char _dummy_bnd[8]; - void *_lower; - void *_upper; - } _addr_bnd; - struct { - char _dummy_pkey[8]; - __u32 _pkey; - } _addr_pkey; - }; - } _sigfault; - struct { - long int _band; - int _fd; - } _sigpoll; - struct { - void *_call_addr; - int _syscall; - unsigned int _arch; - } _sigsys; -}; - -struct kernel_siginfo { - struct { - int si_signo; - int si_errno; - int si_code; - union __sifields _sifields; - }; -}; - -struct user_struct { - refcount_t __count; - atomic_t processes; - atomic_t sigpending; - atomic_t fanotify_listeners; - atomic_long_t epoll_watches; - long unsigned int mq_bytes; - long unsigned int locked_shm; - long unsigned int unix_inflight; - atomic_long_t pipe_bufs; - struct hlist_node uidhash_node; - kuid_t uid; - atomic_long_t locked_vm; - struct ratelimit_state ratelimit; -}; - -struct sigaction { - __sighandler_t sa_handler; - long unsigned int sa_flags; - __sigrestore_t sa_restorer; - sigset_t sa_mask; -}; - -struct k_sigaction { - struct sigaction sa; -}; - -struct vm_userfaultfd_ctx {}; - -struct anon_vma; - -struct vm_operations_struct; - -struct vm_area_struct { - long unsigned int vm_start; - long unsigned int vm_end; - struct vm_area_struct *vm_next; - struct vm_area_struct *vm_prev; - struct rb_node vm_rb; - long unsigned int rb_subtree_gap; - struct mm_struct *vm_mm; - pgprot_t vm_page_prot; - long unsigned int vm_flags; - struct { - struct rb_node rb; - long unsigned int rb_subtree_last; - } shared; - struct list_head anon_vma_chain; - struct anon_vma *anon_vma; - const struct vm_operations_struct *vm_ops; - long unsigned int vm_pgoff; - struct file *vm_file; - void *vm_private_data; - atomic_long_t swap_readahead_info; - struct vm_userfaultfd_ctx vm_userfaultfd_ctx; -}; - -struct mm_rss_stat { - atomic_long_t count[4]; -}; - -struct cpu_itimer { - u64 expires; - u64 incr; -}; - -struct task_cputime_atomic { - atomic64_t utime; - atomic64_t stime; - atomic64_t sum_exec_runtime; -}; - -struct thread_group_cputimer { - struct task_cputime_atomic cputime_atomic; -}; - -struct pacct_struct { - int ac_flag; - long int ac_exitcode; - long unsigned int ac_mem; - u64 ac_utime; - u64 ac_stime; - long unsigned int ac_minflt; - long unsigned int ac_majflt; -}; - -struct tty_struct; - -struct autogroup; - -struct taskstats; - -struct tty_audit_buf; - -struct signal_struct { - refcount_t sigcnt; - atomic_t live; - int nr_threads; - struct list_head thread_head; - wait_queue_head_t wait_chldexit; - struct task_struct *curr_target; - struct sigpending shared_pending; - struct hlist_head multiprocess; - int group_exit_code; - int notify_count; - struct task_struct *group_exit_task; - int group_stop_count; - unsigned int flags; - unsigned int is_child_subreaper: 1; - unsigned int has_child_subreaper: 1; - int posix_timer_id; - struct list_head posix_timers; - struct hrtimer real_timer; - ktime_t it_real_incr; - struct cpu_itimer it[2]; - struct thread_group_cputimer cputimer; - struct posix_cputimers posix_cputimers; - struct pid *pids[4]; - struct pid *tty_old_pgrp; - int leader; - struct tty_struct *tty; - struct autogroup *autogroup; - seqlock_t stats_lock; - u64 utime; - u64 stime; - u64 cutime; - u64 cstime; - u64 gtime; - u64 cgtime; - struct prev_cputime prev_cputime; - long unsigned int nvcsw; - long unsigned int nivcsw; - long unsigned int cnvcsw; - long unsigned int cnivcsw; - long unsigned int min_flt; - long unsigned int maj_flt; - long unsigned int cmin_flt; - long unsigned int cmaj_flt; - long unsigned int inblock; - long unsigned int oublock; - long unsigned int cinblock; - long unsigned int coublock; - long unsigned int maxrss; - long unsigned int cmaxrss; - struct task_io_accounting ioac; - long long unsigned int sum_sched_runtime; - struct rlimit rlim[16]; - struct pacct_struct pacct; - struct taskstats *stats; - unsigned int audit_tty; - struct tty_audit_buf *tty_audit_buf; - bool oom_flag_origin; - short int oom_score_adj; - short int oom_score_adj_min; - struct mm_struct *oom_mm; - struct mutex cred_guard_mutex; - struct rw_semaphore exec_update_lock; -}; - -struct rseq { - __u32 cpu_id_start; - __u32 cpu_id; - union { - __u64 ptr64; - __u64 ptr; - } rseq_cs; - __u32 flags; - long: 32; - long: 64; -}; - -struct rq; - -struct rq_flags; - -struct sched_class { - void (*enqueue_task)(struct rq *, struct task_struct *, int); - void (*dequeue_task)(struct rq *, struct task_struct *, int); - void (*yield_task)(struct rq *); - bool (*yield_to_task)(struct rq *, struct task_struct *); - void (*check_preempt_curr)(struct rq *, struct task_struct *, int); - struct task_struct * (*pick_next_task)(struct rq *); - void (*put_prev_task)(struct rq *, struct task_struct *); - void (*set_next_task)(struct rq *, struct task_struct *, bool); - int (*balance)(struct rq *, struct task_struct *, struct rq_flags *); - int (*select_task_rq)(struct task_struct *, int, int, int); - void (*migrate_task_rq)(struct task_struct *, int); - void (*task_woken)(struct rq *, struct task_struct *); - void (*set_cpus_allowed)(struct task_struct *, const struct cpumask *); - void (*rq_online)(struct rq *); - void (*rq_offline)(struct rq *); - void (*task_tick)(struct rq *, struct task_struct *, int); - void (*task_fork)(struct task_struct *); - void (*task_dead)(struct task_struct *); - void (*switched_from)(struct rq *, struct task_struct *); - void (*switched_to)(struct rq *, struct task_struct *); - void (*prio_changed)(struct rq *, struct task_struct *, int); - unsigned int (*get_rr_interval)(struct rq *, struct task_struct *); - void (*update_curr)(struct rq *); - void (*task_change_group)(struct task_struct *, int); -}; - -typedef struct { - atomic64_t id; - void *sigpage; - refcount_t pinned; - void *vdso; - long unsigned int flags; -} mm_context_t; - -struct uprobes_state {}; - -struct linux_binfmt; - -struct core_state; - -struct kioctx_table; - -struct mmu_notifier_subscriptions; - -struct mm_struct { - struct { - struct vm_area_struct *mmap; - struct rb_root mm_rb; - u64 vmacache_seqnum; - long unsigned int (*get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - long unsigned int mmap_base; - long unsigned int mmap_legacy_base; - long unsigned int task_size; - long unsigned int highest_vm_end; - pgd_t *pgd; - atomic_t membarrier_state; - atomic_t mm_users; - atomic_t mm_count; - atomic_t has_pinned; - atomic_long_t pgtables_bytes; - int map_count; - spinlock_t page_table_lock; - struct rw_semaphore mmap_lock; - struct list_head mmlist; - long unsigned int hiwater_rss; - long unsigned int hiwater_vm; - long unsigned int total_vm; - long unsigned int locked_vm; - atomic64_t pinned_vm; - long unsigned int data_vm; - long unsigned int exec_vm; - long unsigned int stack_vm; - long unsigned int def_flags; - seqcount_t write_protect_seq; - spinlock_t arg_lock; - long unsigned int start_code; - long unsigned int end_code; - long unsigned int start_data; - long unsigned int end_data; - long unsigned int start_brk; - long unsigned int brk; - long unsigned int start_stack; - long unsigned int arg_start; - long unsigned int arg_end; - long unsigned int env_start; - long unsigned int env_end; - long unsigned int saved_auxv[46]; - struct mm_rss_stat rss_stat; - struct linux_binfmt *binfmt; - mm_context_t context; - long unsigned int flags; - struct core_state *core_state; - spinlock_t ioctx_lock; - struct kioctx_table *ioctx_table; - struct task_struct *owner; - struct user_namespace *user_ns; - struct file *exe_file; - struct mmu_notifier_subscriptions *notifier_subscriptions; - atomic_t tlb_flush_pending; - struct uprobes_state uprobes_state; - struct work_struct async_put_work; - }; - long unsigned int cpu_bitmap[0]; -}; - -struct swait_queue_head { - raw_spinlock_t lock; - struct list_head task_list; -}; - -struct completion { - unsigned int done; - struct swait_queue_head wait; -}; - -struct kernel_cap_struct { - __u32 cap[2]; -}; - -typedef struct kernel_cap_struct kernel_cap_t; - -struct group_info; - -struct cred { - atomic_t usage; - kuid_t uid; - kgid_t gid; - kuid_t suid; - kgid_t sgid; - kuid_t euid; - kgid_t egid; - kuid_t fsuid; - kgid_t fsgid; - unsigned int securebits; - kernel_cap_t cap_inheritable; - kernel_cap_t cap_permitted; - kernel_cap_t cap_effective; - kernel_cap_t cap_bset; - kernel_cap_t cap_ambient; - unsigned char jit_keyring; - struct key *session_keyring; - struct key *process_keyring; - struct key *thread_keyring; - struct key *request_key_auth; - void *security; - struct user_struct *user; - struct user_namespace *user_ns; - struct group_info *group_info; - union { - int non_rcu; - struct callback_head rcu; - }; -}; - -typedef int32_t key_serial_t; - -typedef uint32_t key_perm_t; - -struct key_type; - -struct key_tag; - -struct keyring_index_key { - long unsigned int hash; - union { - struct { - u16 desc_len; - char desc[6]; - }; - long unsigned int x; - }; - struct key_type *type; - struct key_tag *domain_tag; - const char *description; -}; - -union key_payload { - void *rcu_data0; - void *data[4]; -}; - -struct assoc_array_ptr; - -struct assoc_array { - struct assoc_array_ptr *root; - long unsigned int nr_leaves_on_tree; -}; - -struct key_user; - -struct key_restriction; - -struct key { - refcount_t usage; - key_serial_t serial; - union { - struct list_head graveyard_link; - struct rb_node serial_node; - }; - struct rw_semaphore sem; - struct key_user *user; - void *security; - union { - time64_t expiry; - time64_t revoked_at; - }; - time64_t last_used_at; - kuid_t uid; - kgid_t gid; - key_perm_t perm; - short unsigned int quotalen; - short unsigned int datalen; - short int state; - long unsigned int flags; - union { - struct keyring_index_key index_key; - struct { - long unsigned int hash; - long unsigned int len_desc; - struct key_type *type; - struct key_tag *domain_tag; - char *description; - }; - }; - union { - union key_payload payload; - struct { - struct list_head name_link; - struct assoc_array keys; - }; - }; - struct key_restriction *restrict_link; -}; - -struct uts_namespace; - -struct ipc_namespace; - -struct mnt_namespace; - -struct net; - -struct time_namespace; - -struct cgroup_namespace; - -struct nsproxy { - atomic_t count; - struct uts_namespace *uts_ns; - struct ipc_namespace *ipc_ns; - struct mnt_namespace *mnt_ns; - struct pid_namespace *pid_ns_for_children; - struct net *net_ns; - struct time_namespace *time_ns; - struct time_namespace *time_ns_for_children; - struct cgroup_namespace *cgroup_ns; -}; - -struct sighand_struct { - spinlock_t siglock; - refcount_t count; - wait_queue_head_t signalfd_wqh; - struct k_sigaction action[64]; -}; - -struct bio; - -struct bio_list { - struct bio *head; - struct bio *tail; -}; - -struct blk_plug { - struct list_head mq_list; - struct list_head cb_list; - short unsigned int rq_count; - bool multiple_queues; - bool nowait; -}; - -struct reclaim_state { - long unsigned int reclaimed_slab; -}; - -struct percpu_counter { - raw_spinlock_t lock; - s64 count; - s32 *counters; -}; - -struct fprop_local_percpu { - struct percpu_counter events; - unsigned int period; - raw_spinlock_t lock; -}; - -enum wb_reason { - WB_REASON_BACKGROUND = 0, - WB_REASON_VMSCAN = 1, - WB_REASON_SYNC = 2, - WB_REASON_PERIODIC = 3, - WB_REASON_LAPTOP_TIMER = 4, - WB_REASON_FS_FREE_SPACE = 5, - WB_REASON_FORKER_THREAD = 6, - WB_REASON_FOREIGN_FLUSH = 7, - WB_REASON_MAX = 8, -}; - -struct percpu_ref_data; - -struct percpu_ref { - long unsigned int percpu_count_ptr; - struct percpu_ref_data *data; -}; - -struct cgroup_subsys_state; - -struct bdi_writeback { - struct backing_dev_info *bdi; - long unsigned int state; - long unsigned int last_old_flush; - struct list_head b_dirty; - struct list_head b_io; - struct list_head b_more_io; - struct list_head b_dirty_time; - spinlock_t list_lock; - struct percpu_counter stat[4]; - long unsigned int congested; - long unsigned int bw_time_stamp; - long unsigned int dirtied_stamp; - long unsigned int written_stamp; - long unsigned int write_bandwidth; - long unsigned int avg_write_bandwidth; - long unsigned int dirty_ratelimit; - long unsigned int balanced_dirty_ratelimit; - struct fprop_local_percpu completions; - int dirty_exceeded; - enum wb_reason start_all_reason; - spinlock_t work_lock; - struct list_head work_list; - struct delayed_work dwork; - long unsigned int dirty_sleep; - struct list_head bdi_node; - struct percpu_ref refcnt; - struct fprop_local_percpu memcg_completions; - struct cgroup_subsys_state *memcg_css; - struct cgroup_subsys_state *blkcg_css; - struct list_head memcg_node; - struct list_head blkcg_node; - union { - struct work_struct release_work; - struct callback_head rcu; - }; -}; - -struct device; - -struct backing_dev_info { - u64 id; - struct rb_node rb_node; - struct list_head bdi_list; - long unsigned int ra_pages; - long unsigned int io_pages; - struct kref refcnt; - unsigned int capabilities; - unsigned int min_ratio; - unsigned int max_ratio; - unsigned int max_prop_frac; - atomic_long_t tot_write_bandwidth; - struct bdi_writeback wb; - struct list_head wb_list; - struct xarray cgwb_tree; - struct mutex cgwb_release_mutex; - struct rw_semaphore wb_switch_rwsem; - wait_queue_head_t wb_waitq; - struct device *dev; - char dev_name[64]; - struct device *owner; - struct timer_list laptop_mode_wb_timer; - struct dentry *debug_dir; -}; - -struct io_cq; - -struct io_context { - atomic_long_t refcount; - atomic_t active_ref; - atomic_t nr_tasks; - spinlock_t lock; - short unsigned int ioprio; - struct xarray icq_tree; - struct io_cq *icq_hint; - struct hlist_head icq_list; - struct work_struct release_work; -}; - -struct cgroup; - -struct css_set { - struct cgroup_subsys_state *subsys[11]; - refcount_t refcount; - struct css_set *dom_cset; - struct cgroup *dfl_cgrp; - int nr_tasks; - struct list_head tasks; - struct list_head mg_tasks; - struct list_head dying_tasks; - struct list_head task_iters; - struct list_head e_cset_node[11]; - struct list_head threaded_csets; - struct list_head threaded_csets_node; - struct hlist_node hlist; - struct list_head cgrp_links; - struct list_head mg_preload_node; - struct list_head mg_node; - struct cgroup *mg_src_cgrp; - struct cgroup *mg_dst_cgrp; - struct css_set *mg_dst_cset; - bool dead; - struct callback_head callback_head; -}; - -struct compat_robust_list { - compat_uptr_t next; -}; - -struct compat_robust_list_head { - struct compat_robust_list list; - compat_long_t futex_offset; - compat_uptr_t list_op_pending; -}; - -struct perf_event_groups { - struct rb_root tree; - u64 index; -}; - -struct perf_event_context { - struct pmu *pmu; - raw_spinlock_t lock; - struct mutex mutex; - struct list_head active_ctx_list; - struct perf_event_groups pinned_groups; - struct perf_event_groups flexible_groups; - struct list_head event_list; - struct list_head pinned_active; - struct list_head flexible_active; - int nr_events; - int nr_active; - int is_active; - int nr_stat; - int nr_freq; - int rotate_disable; - int rotate_necessary; - refcount_t refcount; - struct task_struct *task; - u64 time; - u64 timestamp; - struct perf_event_context *parent_ctx; - u64 parent_gen; - u64 generation; - int pin_count; - int nr_cgroups; - void *task_ctx_data; - struct callback_head callback_head; -}; - -struct task_delay_info { - raw_spinlock_t lock; - unsigned int flags; - u64 blkio_start; - u64 blkio_delay; - u64 swapin_delay; - u32 blkio_count; - u32 swapin_count; - u64 freepages_start; - u64 freepages_delay; - u64 thrashing_start; - u64 thrashing_delay; - u32 freepages_count; - u32 thrashing_count; -}; - -struct ftrace_ret_stack { - long unsigned int ret; - long unsigned int func; - long long unsigned int calltime; - long long unsigned int subtime; - long unsigned int fp; -}; - -struct cgroup_subsys; - -struct cgroup_subsys_state { - struct cgroup *cgroup; - struct cgroup_subsys *ss; - struct percpu_ref refcnt; - struct list_head sibling; - struct list_head children; - struct list_head rstat_css_node; - int id; - unsigned int flags; - u64 serial_nr; - atomic_t online_cnt; - struct work_struct destroy_work; - struct rcu_work destroy_rwork; - struct cgroup_subsys_state *parent; -}; - -struct mem_cgroup_id { - int id; - refcount_t ref; -}; - -struct page_counter { - atomic_long_t usage; - long unsigned int min; - long unsigned int low; - long unsigned int high; - long unsigned int max; - struct page_counter *parent; - long unsigned int emin; - atomic_long_t min_usage; - atomic_long_t children_min_usage; - long unsigned int elow; - atomic_long_t low_usage; - atomic_long_t children_low_usage; - long unsigned int watermark; - long unsigned int failcnt; -}; - -struct vmpressure { - long unsigned int scanned; - long unsigned int reclaimed; - long unsigned int tree_scanned; - long unsigned int tree_reclaimed; - spinlock_t sr_lock; - struct list_head events; - struct mutex events_lock; - struct work_struct work; -}; - -struct cgroup_file { - struct kernfs_node *kn; - long unsigned int notified_at; - struct timer_list notify_timer; -}; - -struct mem_cgroup_threshold_ary; - -struct mem_cgroup_thresholds { - struct mem_cgroup_threshold_ary *primary; - struct mem_cgroup_threshold_ary *spare; -}; - -struct memcg_padding { - char x[0]; -}; - -enum memcg_kmem_state { - KMEM_NONE = 0, - KMEM_ALLOCATED = 1, - KMEM_ONLINE = 2, -}; - -struct fprop_global { - struct percpu_counter events; - unsigned int period; - seqcount_t sequence; -}; - -struct wb_domain { - spinlock_t lock; - struct fprop_global completions; - struct timer_list period_timer; - long unsigned int period_time; - long unsigned int dirty_limit_tstamp; - long unsigned int dirty_limit; -}; - -struct wb_completion { - atomic_t cnt; - wait_queue_head_t *waitq; -}; - -struct memcg_cgwb_frn { - u64 bdi_id; - int memcg_id; - u64 at; - struct wb_completion done; -}; - -struct memcg_vmstats_percpu; - -struct mem_cgroup_per_node; - -struct mem_cgroup { - struct cgroup_subsys_state css; - struct mem_cgroup_id id; - struct page_counter memory; - union { - struct page_counter swap; - struct page_counter memsw; - }; - struct page_counter kmem; - struct page_counter tcpmem; - struct work_struct high_work; - long unsigned int soft_limit; - struct vmpressure vmpressure; - bool use_hierarchy; - bool oom_group; - bool oom_lock; - int under_oom; - int swappiness; - int oom_kill_disable; - struct cgroup_file events_file; - struct cgroup_file events_local_file; - struct cgroup_file swap_events_file; - struct mutex thresholds_lock; - struct mem_cgroup_thresholds thresholds; - struct mem_cgroup_thresholds memsw_thresholds; - struct list_head oom_notify; - long unsigned int move_charge_at_immigrate; - spinlock_t move_lock; - long unsigned int move_lock_flags; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct memcg_padding _pad1_; - atomic_long_t vmstats[40]; - atomic_long_t vmevents[67]; - atomic_long_t memory_events[8]; - atomic_long_t memory_events_local[8]; - long unsigned int socket_pressure; - bool tcpmem_active; - int tcpmem_pressure; - int kmemcg_id; - enum memcg_kmem_state kmem_state; - struct obj_cgroup *objcg; - struct list_head objcg_list; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct memcg_padding _pad2_; - atomic_t moving_account; - struct task_struct *move_lock_task; - struct memcg_vmstats_percpu *vmstats_local; - struct memcg_vmstats_percpu *vmstats_percpu; - struct list_head cgwb_list; - struct wb_domain cgwb_domain; - struct memcg_cgwb_frn cgwb_frn[4]; - struct list_head event_list; - spinlock_t event_list_lock; - struct mem_cgroup_per_node *nodeinfo[0]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum rpm_status { - RPM_ACTIVE = 0, - RPM_RESUMING = 1, - RPM_SUSPENDED = 2, - RPM_SUSPENDING = 3, -}; - -struct blk_rq_stat { - u64 mean; - u64 min; - u64 max; - u32 nr_samples; - u64 batch; -}; - -enum blk_zoned_model { - BLK_ZONED_NONE = 0, - BLK_ZONED_HA = 1, - BLK_ZONED_HM = 2, -}; - -struct queue_limits { - long unsigned int bounce_pfn; - long unsigned int seg_boundary_mask; - long unsigned int virt_boundary_mask; - unsigned int max_hw_sectors; - unsigned int max_dev_sectors; - unsigned int chunk_sectors; - unsigned int max_sectors; - unsigned int max_segment_size; - unsigned int physical_block_size; - unsigned int logical_block_size; - unsigned int alignment_offset; - unsigned int io_min; - unsigned int io_opt; - unsigned int max_discard_sectors; - unsigned int max_hw_discard_sectors; - unsigned int max_write_same_sectors; - unsigned int max_write_zeroes_sectors; - unsigned int max_zone_append_sectors; - unsigned int discard_granularity; - unsigned int discard_alignment; - short unsigned int max_segments; - short unsigned int max_integrity_segments; - short unsigned int max_discard_segments; - unsigned char misaligned; - unsigned char discard_misaligned; - unsigned char raid_partial_stripes_expensive; - enum blk_zoned_model zoned; -}; - -struct bsg_ops; - -struct bsg_class_device { - struct device *class_dev; - int minor; - struct request_queue *queue; - const struct bsg_ops *ops; -}; - -typedef void *mempool_alloc_t(gfp_t, void *); - -typedef void mempool_free_t(void *, void *); - -struct mempool_s { - spinlock_t lock; - int min_nr; - int curr_nr; - void **elements; - void *pool_data; - mempool_alloc_t *alloc; - mempool_free_t *free; - wait_queue_head_t wait; -}; - -typedef struct mempool_s mempool_t; - -struct bio_set { - struct kmem_cache *bio_slab; - unsigned int front_pad; - mempool_t bio_pool; - mempool_t bvec_pool; - spinlock_t rescue_lock; - struct bio_list rescue_list; - struct work_struct rescue_work; - struct workqueue_struct *rescue_workqueue; -}; - -struct request; - -struct elevator_queue; - -struct blk_queue_stats; - -struct rq_qos; - -struct blk_mq_ops; - -struct blk_mq_ctx; - -struct blk_mq_hw_ctx; - -struct blk_stat_callback; - -struct blkcg_gq; - -struct blk_trace; - -struct blk_flush_queue; - -struct throtl_data; - -struct blk_mq_tag_set; - -struct request_queue { - struct request *last_merge; - struct elevator_queue *elevator; - struct percpu_ref q_usage_counter; - struct blk_queue_stats *stats; - struct rq_qos *rq_qos; - const struct blk_mq_ops *mq_ops; - struct blk_mq_ctx *queue_ctx; - unsigned int queue_depth; - struct blk_mq_hw_ctx **queue_hw_ctx; - unsigned int nr_hw_queues; - struct backing_dev_info *backing_dev_info; - void *queuedata; - long unsigned int queue_flags; - atomic_t pm_only; - int id; - gfp_t bounce_gfp; - spinlock_t queue_lock; - struct kobject kobj; - struct kobject *mq_kobj; - struct device *dev; - enum rpm_status rpm_status; - unsigned int nr_pending; - long unsigned int nr_requests; - unsigned int dma_pad_mask; - unsigned int dma_alignment; - unsigned int rq_timeout; - int poll_nsec; - struct blk_stat_callback *poll_cb; - struct blk_rq_stat poll_stat[16]; - struct timer_list timeout; - struct work_struct timeout_work; - atomic_t nr_active_requests_shared_sbitmap; - struct list_head icq_list; - long unsigned int blkcg_pols[1]; - struct blkcg_gq *root_blkg; - struct list_head blkg_list; - struct queue_limits limits; - unsigned int required_elevator_features; - unsigned int sg_timeout; - unsigned int sg_reserved_size; - int node; - struct mutex debugfs_mutex; - struct blk_trace *blk_trace; - struct blk_flush_queue *fq; - struct list_head requeue_list; - spinlock_t requeue_lock; - struct delayed_work requeue_work; - struct mutex sysfs_lock; - struct mutex sysfs_dir_lock; - struct list_head unused_hctx_list; - spinlock_t unused_hctx_lock; - int mq_freeze_depth; - struct bsg_class_device bsg_dev; - struct throtl_data *td; - struct callback_head callback_head; - wait_queue_head_t mq_freeze_wq; - struct mutex mq_freeze_lock; - struct blk_mq_tag_set *tag_set; - struct list_head tag_set_list; - struct bio_set bio_split; - struct dentry *debugfs_dir; - struct dentry *sched_debugfs_dir; - struct dentry *rqos_debugfs_dir; - bool mq_sysfs_init_done; - size_t cmd_size; - u64 write_hints[5]; -}; - -struct vm_struct { - struct vm_struct *next; - void *addr; - long unsigned int size; - long unsigned int flags; - struct page **pages; - unsigned int nr_pages; - phys_addr_t phys_addr; - const void *caller; -}; - -struct kstat { - u32 result_mask; - umode_t mode; - unsigned int nlink; - uint32_t blksize; - u64 attributes; - u64 attributes_mask; - u64 ino; - dev_t dev; - dev_t rdev; - kuid_t uid; - kgid_t gid; - loff_t size; - struct timespec64 atime; - struct timespec64 mtime; - struct timespec64 ctime; - struct timespec64 btime; - u64 blocks; - u64 mnt_id; -}; - -typedef u32 errseq_t; - -struct address_space_operations; - -struct address_space { - struct inode *host; - struct xarray i_pages; - gfp_t gfp_mask; - atomic_t i_mmap_writable; - struct rb_root_cached i_mmap; - struct rw_semaphore i_mmap_rwsem; - long unsigned int nrpages; - long unsigned int nrexceptional; - long unsigned int writeback_index; - const struct address_space_operations *a_ops; - long unsigned int flags; - errseq_t wb_err; - spinlock_t private_lock; - struct list_head private_list; - void *private_data; -}; - -struct vmem_altmap { - const long unsigned int base_pfn; - const long unsigned int end_pfn; - const long unsigned int reserve; - long unsigned int free; - long unsigned int align; - long unsigned int alloc; -}; - -enum memory_type { - MEMORY_DEVICE_PRIVATE = 1, - MEMORY_DEVICE_FS_DAX = 2, - MEMORY_DEVICE_GENERIC = 3, - MEMORY_DEVICE_PCI_P2PDMA = 4, -}; - -struct range { - u64 start; - u64 end; -}; - -struct dev_pagemap_ops; - -struct dev_pagemap { - struct vmem_altmap altmap; - struct percpu_ref *ref; - struct percpu_ref internal_ref; - struct completion done; - enum memory_type type; - unsigned int flags; - const struct dev_pagemap_ops *ops; - void *owner; - int nr_range; - union { - struct range range; - struct range ranges[0]; - }; -}; - -struct obj_cgroup { - struct percpu_ref refcnt; - struct mem_cgroup *memcg; - atomic_t nr_charged_bytes; - union { - struct list_head list; - struct callback_head rcu; - }; -}; - -struct vfsmount; - -struct path { - struct vfsmount *mnt; - struct dentry *dentry; -}; - -enum rw_hint { - WRITE_LIFE_NOT_SET = 0, - WRITE_LIFE_NONE = 1, - WRITE_LIFE_SHORT = 2, - WRITE_LIFE_MEDIUM = 3, - WRITE_LIFE_LONG = 4, - WRITE_LIFE_EXTREME = 5, -}; - -struct fown_struct { - rwlock_t lock; - struct pid *pid; - enum pid_type pid_type; - kuid_t uid; - kuid_t euid; - int signum; -}; - -struct file_ra_state { - long unsigned int start; - unsigned int size; - unsigned int async_size; - unsigned int ra_pages; - unsigned int mmap_miss; - loff_t prev_pos; -}; - -struct file { - union { - struct llist_node fu_llist; - struct callback_head fu_rcuhead; - } f_u; - struct path f_path; - struct inode *f_inode; - const struct file_operations *f_op; - spinlock_t f_lock; - enum rw_hint f_write_hint; - atomic_long_t f_count; - unsigned int f_flags; - fmode_t f_mode; - struct mutex f_pos_lock; - loff_t f_pos; - struct fown_struct f_owner; - const struct cred *f_cred; - struct file_ra_state f_ra; - u64 f_version; - void *f_security; - void *private_data; - struct list_head f_ep_links; - struct list_head f_tfile_llink; - struct address_space *f_mapping; - errseq_t f_wb_err; - errseq_t f_sb_err; -}; - -struct anon_vma { - struct anon_vma *root; - struct rw_semaphore rwsem; - atomic_t refcount; - unsigned int degree; - struct anon_vma *parent; - struct rb_root_cached rb_root; -}; - -typedef unsigned int vm_fault_t; - -enum page_entry_size { - PE_SIZE_PTE = 0, - PE_SIZE_PMD = 1, - PE_SIZE_PUD = 2, -}; - -struct vm_fault; - -struct vm_operations_struct { - void (*open)(struct vm_area_struct *); - void (*close)(struct vm_area_struct *); - int (*split)(struct vm_area_struct *, long unsigned int); - int (*mremap)(struct vm_area_struct *); - vm_fault_t (*fault)(struct vm_fault *); - vm_fault_t (*huge_fault)(struct vm_fault *, enum page_entry_size); - void (*map_pages)(struct vm_fault *, long unsigned int, long unsigned int); - long unsigned int (*pagesize)(struct vm_area_struct *); - vm_fault_t (*page_mkwrite)(struct vm_fault *); - vm_fault_t (*pfn_mkwrite)(struct vm_fault *); - int (*access)(struct vm_area_struct *, long unsigned int, void *, int, int); - const char * (*name)(struct vm_area_struct *); - struct page * (*find_special_page)(struct vm_area_struct *, long unsigned int); -}; - -struct core_thread { - struct task_struct *task; - struct core_thread *next; -}; - -struct core_state { - atomic_t nr_threads; - struct core_thread dumper; - struct completion startup; -}; - -struct linux_binprm; - -struct coredump_params; - -struct linux_binfmt { - struct list_head lh; - struct module *module; - int (*load_binary)(struct linux_binprm *); - int (*load_shlib)(struct file *); - int (*core_dump)(struct coredump_params *); - long unsigned int min_coredump; -}; - -struct vm_fault { - struct vm_area_struct *vma; - unsigned int flags; - gfp_t gfp_mask; - long unsigned int pgoff; - long unsigned int address; - pmd_t *pmd; - pud_t *pud; - pte_t orig_pte; - struct page *cow_page; - struct page *page; - pte_t *pte; - spinlock_t *ptl; - pgtable_t prealloc_pte; -}; - -struct free_area { - struct list_head free_list[6]; - long unsigned int nr_free; -}; - -struct zone_padding { - char x[0]; -}; - -enum node_stat_item { - NR_LRU_BASE = 0, - NR_INACTIVE_ANON = 0, - NR_ACTIVE_ANON = 1, - NR_INACTIVE_FILE = 2, - NR_ACTIVE_FILE = 3, - NR_UNEVICTABLE = 4, - NR_SLAB_RECLAIMABLE_B = 5, - NR_SLAB_UNRECLAIMABLE_B = 6, - NR_ISOLATED_ANON = 7, - NR_ISOLATED_FILE = 8, - WORKINGSET_NODES = 9, - WORKINGSET_REFAULT_BASE = 10, - WORKINGSET_REFAULT_ANON = 10, - WORKINGSET_REFAULT_FILE = 11, - WORKINGSET_ACTIVATE_BASE = 12, - WORKINGSET_ACTIVATE_ANON = 12, - WORKINGSET_ACTIVATE_FILE = 13, - WORKINGSET_RESTORE_BASE = 14, - WORKINGSET_RESTORE_ANON = 14, - WORKINGSET_RESTORE_FILE = 15, - WORKINGSET_NODERECLAIM = 16, - NR_ANON_MAPPED = 17, - NR_FILE_MAPPED = 18, - NR_FILE_PAGES = 19, - NR_FILE_DIRTY = 20, - NR_WRITEBACK = 21, - NR_WRITEBACK_TEMP = 22, - NR_SHMEM = 23, - NR_SHMEM_THPS = 24, - NR_SHMEM_PMDMAPPED = 25, - NR_FILE_THPS = 26, - NR_FILE_PMDMAPPED = 27, - NR_ANON_THPS = 28, - NR_VMSCAN_WRITE = 29, - NR_VMSCAN_IMMEDIATE = 30, - NR_DIRTIED = 31, - NR_WRITTEN = 32, - NR_KERNEL_MISC_RECLAIMABLE = 33, - NR_FOLL_PIN_ACQUIRED = 34, - NR_FOLL_PIN_RELEASED = 35, - NR_KERNEL_STACK_KB = 36, - NR_VM_NODE_STAT_ITEMS = 37, -}; - -enum lru_list { - LRU_INACTIVE_ANON = 0, - LRU_ACTIVE_ANON = 1, - LRU_INACTIVE_FILE = 2, - LRU_ACTIVE_FILE = 3, - LRU_UNEVICTABLE = 4, - NR_LRU_LISTS = 5, -}; - -struct pglist_data; - -struct lruvec { - struct list_head lists[5]; - long unsigned int anon_cost; - long unsigned int file_cost; - atomic_long_t nonresident_age; - long unsigned int refaults[2]; - long unsigned int flags; - struct pglist_data *pgdat; -}; - -struct per_cpu_pageset; - -struct zone { - long unsigned int _watermark[3]; - long unsigned int watermark_boost; - long unsigned int nr_reserved_highatomic; - long int lowmem_reserve[4]; - struct pglist_data *zone_pgdat; - struct per_cpu_pageset *pageset; - long unsigned int zone_start_pfn; - atomic_long_t managed_pages; - long unsigned int spanned_pages; - long unsigned int present_pages; - const char *name; - long unsigned int nr_isolate_pageblock; - int initialized; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct zone_padding _pad1_; - struct free_area free_area[11]; - long unsigned int flags; - spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct zone_padding _pad2_; - long unsigned int percpu_drift_mark; - long unsigned int compact_cached_free_pfn; - long unsigned int compact_cached_migrate_pfn[2]; - long unsigned int compact_init_migrate_pfn; - long unsigned int compact_init_free_pfn; - unsigned int compact_considered; - unsigned int compact_defer_shift; - int compact_order_failed; - bool compact_blockskip_flush; - bool contiguous; - short: 16; - struct zone_padding _pad3_; - atomic_long_t vm_stat[12]; - atomic_long_t vm_numa_stat[0]; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct zoneref { - struct zone *zone; - int zone_idx; -}; - -struct zonelist { - struct zoneref _zonerefs[5]; -}; - -enum zone_type { - ZONE_DMA = 0, - ZONE_DMA32 = 1, - ZONE_NORMAL = 2, - ZONE_MOVABLE = 3, - __MAX_NR_ZONES = 4, -}; - -struct per_cpu_nodestat; - -struct pglist_data { - struct zone node_zones[4]; - struct zonelist node_zonelists[1]; - int nr_zones; - long unsigned int node_start_pfn; - long unsigned int node_present_pages; - long unsigned int node_spanned_pages; - int node_id; - wait_queue_head_t kswapd_wait; - wait_queue_head_t pfmemalloc_wait; - struct task_struct *kswapd; - int kswapd_order; - enum zone_type kswapd_highest_zoneidx; - int kswapd_failures; - int kcompactd_max_order; - enum zone_type kcompactd_highest_zoneidx; - wait_queue_head_t kcompactd_wait; - struct task_struct *kcompactd; - long unsigned int totalreserve_pages; - long: 64; - long: 64; - struct zone_padding _pad1_; - spinlock_t lru_lock; - struct lruvec __lruvec; - long unsigned int flags; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct zone_padding _pad2_; - struct per_cpu_nodestat *per_cpu_nodestats; - atomic_long_t vm_stat[37]; - long: 64; - long: 64; -}; - -typedef unsigned int isolate_mode_t; - -struct per_cpu_pages { - int count; - int high; - int batch; - struct list_head lists[3]; -}; - -struct per_cpu_pageset { - struct per_cpu_pages pcp; - s8 stat_threshold; - s8 vm_stat_diff[12]; -}; - -struct per_cpu_nodestat { - s8 stat_threshold; - s8 vm_node_stat_diff[37]; -}; - -struct rcu_segcblist { - struct callback_head *head; - struct callback_head **tails[4]; - long unsigned int gp_seq[4]; - long int len; - u8 enabled; - u8 offloaded; -}; - -struct srcu_node; - -struct srcu_data { - long unsigned int srcu_lock_count[2]; - long unsigned int srcu_unlock_count[2]; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t lock; - struct rcu_segcblist srcu_cblist; - long unsigned int srcu_gp_seq_needed; - long unsigned int srcu_gp_seq_needed_exp; - bool srcu_cblist_invoking; - struct timer_list delay_work; - struct work_struct work; - struct callback_head srcu_barrier_head; - struct srcu_node *mynode; - long unsigned int grpmask; - int cpu; - struct srcu_struct *ssp; - long: 64; - long: 64; -}; - -struct srcu_node { - spinlock_t lock; - long unsigned int srcu_have_cbs[4]; - long unsigned int srcu_data_have_cbs[4]; - long unsigned int srcu_gp_seq_needed_exp; - struct srcu_node *srcu_parent; - int grplo; - int grphi; -}; - -struct srcu_struct { - struct srcu_node node[17]; - struct srcu_node *level[3]; - struct mutex srcu_cb_mutex; - spinlock_t lock; - struct mutex srcu_gp_mutex; - unsigned int srcu_idx; - long unsigned int srcu_gp_seq; - long unsigned int srcu_gp_seq_needed; - long unsigned int srcu_gp_seq_needed_exp; - long unsigned int srcu_last_gp_end; - struct srcu_data *sda; - long unsigned int srcu_barrier_seq; - struct mutex srcu_barrier_mutex; - struct completion srcu_barrier_completion; - atomic_t srcu_barrier_cpu_cnt; - struct delayed_work work; -}; - -typedef int proc_handler(struct ctl_table *, int, void *, size_t *, loff_t *); - -struct ctl_table_poll; - -struct ctl_table { - const char *procname; - void *data; - int maxlen; - umode_t mode; - struct ctl_table *child; - proc_handler *proc_handler; - struct ctl_table_poll *poll; - void *extra1; - void *extra2; -}; - -struct ctl_table_poll { - atomic_t event; - wait_queue_head_t wait; -}; - -struct ctl_node { - struct rb_node node; - struct ctl_table_header *header; -}; - -struct ctl_table_root { - struct ctl_table_set default_set; - struct ctl_table_set * (*lookup)(struct ctl_table_root *); - void (*set_ownership)(struct ctl_table_header *, struct ctl_table *, kuid_t *, kgid_t *); - int (*permissions)(struct ctl_table_header *, struct ctl_table *); -}; - -enum umh_disable_depth { - UMH_ENABLED = 0, - UMH_FREEZING = 1, - UMH_DISABLED = 2, -}; - -typedef __u64 Elf64_Addr; - -typedef __u16 Elf64_Half; - -typedef __u32 Elf64_Word; - -typedef __u64 Elf64_Xword; - -struct elf64_sym { - Elf64_Word st_name; - unsigned char st_info; - unsigned char st_other; - Elf64_Half st_shndx; - Elf64_Addr st_value; - Elf64_Xword st_size; -}; - -struct hlist_bl_node; - -struct hlist_bl_head { - struct hlist_bl_node *first; -}; - -struct hlist_bl_node { - struct hlist_bl_node *next; - struct hlist_bl_node **pprev; -}; - -struct lockref { - union { - __u64 lock_count; - struct { - spinlock_t lock; - int count; - }; - }; -}; - -struct qstr { - union { - struct { - u32 hash; - u32 len; - }; - u64 hash_len; - }; - const unsigned char *name; -}; - -struct dentry_operations; - -struct dentry { - unsigned int d_flags; - seqcount_spinlock_t d_seq; - struct hlist_bl_node d_hash; - struct dentry *d_parent; - struct qstr d_name; - struct inode *d_inode; - unsigned char d_iname[32]; - struct lockref d_lockref; - const struct dentry_operations *d_op; - struct super_block *d_sb; - long unsigned int d_time; - void *d_fsdata; - union { - struct list_head d_lru; - wait_queue_head_t *d_wait; - }; - struct list_head d_child; - struct list_head d_subdirs; - union { - struct hlist_node d_alias; - struct hlist_bl_node d_in_lookup_hash; - struct callback_head d_rcu; - } d_u; -}; - -struct posix_acl; - -struct inode_operations; - -struct file_lock_context; - -struct block_device; - -struct cdev; - -struct fsnotify_mark_connector; - -struct fscrypt_info; - -struct inode { - umode_t i_mode; - short unsigned int i_opflags; - kuid_t i_uid; - kgid_t i_gid; - unsigned int i_flags; - struct posix_acl *i_acl; - struct posix_acl *i_default_acl; - const struct inode_operations *i_op; - struct super_block *i_sb; - struct address_space *i_mapping; - void *i_security; - long unsigned int i_ino; - union { - const unsigned int i_nlink; - unsigned int __i_nlink; - }; - dev_t i_rdev; - loff_t i_size; - struct timespec64 i_atime; - struct timespec64 i_mtime; - struct timespec64 i_ctime; - spinlock_t i_lock; - short unsigned int i_bytes; - u8 i_blkbits; - u8 i_write_hint; - blkcnt_t i_blocks; - long unsigned int i_state; - struct rw_semaphore i_rwsem; - long unsigned int dirtied_when; - long unsigned int dirtied_time_when; - struct hlist_node i_hash; - struct list_head i_io_list; - struct bdi_writeback *i_wb; - int i_wb_frn_winner; - u16 i_wb_frn_avg_time; - u16 i_wb_frn_history; - struct list_head i_lru; - struct list_head i_sb_list; - struct list_head i_wb_list; - union { - struct hlist_head i_dentry; - struct callback_head i_rcu; - }; - atomic64_t i_version; - atomic64_t i_sequence; - atomic_t i_count; - atomic_t i_dio_count; - atomic_t i_writecount; - atomic_t i_readcount; - union { - const struct file_operations *i_fop; - void (*free_inode)(struct inode *); - }; - struct file_lock_context *i_flctx; - struct address_space i_data; - struct list_head i_devices; - union { - struct pipe_inode_info *i_pipe; - struct block_device *i_bdev; - struct cdev *i_cdev; - char *i_link; - unsigned int i_dir_seq; - }; - __u32 i_generation; - __u32 i_fsnotify_mask; - struct fsnotify_mark_connector *i_fsnotify_marks; - struct fscrypt_info *i_crypt_info; - void *i_private; -}; - -struct dentry_operations { - int (*d_revalidate)(struct dentry *, unsigned int); - int (*d_weak_revalidate)(struct dentry *, unsigned int); - int (*d_hash)(const struct dentry *, struct qstr *); - int (*d_compare)(const struct dentry *, unsigned int, const char *, const struct qstr *); - int (*d_delete)(const struct dentry *); - int (*d_init)(struct dentry *); - void (*d_release)(struct dentry *); - void (*d_prune)(struct dentry *); - void (*d_iput)(struct dentry *, struct inode *); - char * (*d_dname)(struct dentry *, char *, int); - struct vfsmount * (*d_automount)(struct path *); - int (*d_manage)(const struct path *, bool); - struct dentry * (*d_real)(struct dentry *, const struct inode *); - long: 64; - long: 64; - long: 64; -}; - -struct mtd_info; - -typedef long long int qsize_t; - -struct quota_format_type; - -struct mem_dqinfo { - struct quota_format_type *dqi_format; - int dqi_fmt_id; - struct list_head dqi_dirty_list; - long unsigned int dqi_flags; - unsigned int dqi_bgrace; - unsigned int dqi_igrace; - qsize_t dqi_max_spc_limit; - qsize_t dqi_max_ino_limit; - void *dqi_priv; -}; - -struct quota_format_ops; - -struct quota_info { - unsigned int flags; - struct rw_semaphore dqio_sem; - struct inode *files[3]; - struct mem_dqinfo info[3]; - const struct quota_format_ops *ops[3]; -}; - -struct rcu_sync { - int gp_state; - int gp_count; - wait_queue_head_t gp_wait; - struct callback_head cb_head; -}; - -struct rcuwait { - struct task_struct *task; -}; - -struct percpu_rw_semaphore { - struct rcu_sync rss; - unsigned int *read_count; - struct rcuwait writer; - wait_queue_head_t waiters; - atomic_t block; -}; - -struct sb_writers { - int frozen; - wait_queue_head_t wait_unfrozen; - struct percpu_rw_semaphore rw_sem[3]; -}; - -typedef struct { - __u8 b[16]; -} uuid_t; - -struct shrink_control; - -struct shrinker { - long unsigned int (*count_objects)(struct shrinker *, struct shrink_control *); - long unsigned int (*scan_objects)(struct shrinker *, struct shrink_control *); - long int batch; - int seeks; - unsigned int flags; - struct list_head list; - int id; - atomic_long_t *nr_deferred; -}; - -struct list_lru_node; - -struct list_lru { - struct list_lru_node *node; - struct list_head list; - int shrinker_id; - bool memcg_aware; -}; - -struct super_operations; - -struct dquot_operations; - -struct quotactl_ops; - -struct export_operations; - -struct xattr_handler; - -struct fscrypt_operations; - -struct super_block { - struct list_head s_list; - dev_t s_dev; - unsigned char s_blocksize_bits; - long unsigned int s_blocksize; - loff_t s_maxbytes; - struct file_system_type *s_type; - const struct super_operations *s_op; - const struct dquot_operations *dq_op; - const struct quotactl_ops *s_qcop; - const struct export_operations *s_export_op; - long unsigned int s_flags; - long unsigned int s_iflags; - long unsigned int s_magic; - struct dentry *s_root; - struct rw_semaphore s_umount; - int s_count; - atomic_t s_active; - void *s_security; - const struct xattr_handler **s_xattr; - const struct fscrypt_operations *s_cop; - struct key *s_master_keys; - struct hlist_bl_head s_roots; - struct list_head s_mounts; - struct block_device *s_bdev; - struct backing_dev_info *s_bdi; - struct mtd_info *s_mtd; - struct hlist_node s_instances; - unsigned int s_quota_types; - struct quota_info s_dquot; - struct sb_writers s_writers; - void *s_fs_info; - u32 s_time_gran; - time64_t s_time_min; - time64_t s_time_max; - __u32 s_fsnotify_mask; - struct fsnotify_mark_connector *s_fsnotify_marks; - char s_id[32]; - uuid_t s_uuid; - unsigned int s_max_links; - fmode_t s_mode; - struct mutex s_vfs_rename_mutex; - const char *s_subtype; - const struct dentry_operations *s_d_op; - int cleancache_poolid; - struct shrinker s_shrink; - atomic_long_t s_remove_count; - atomic_long_t s_fsnotify_inode_refs; - int s_readonly_remount; - errseq_t s_wb_err; - struct workqueue_struct *s_dio_done_wq; - struct hlist_head s_pins; - struct user_namespace *s_user_ns; - struct list_lru s_dentry_lru; - struct list_lru s_inode_lru; - struct callback_head rcu; - struct work_struct destroy_work; - struct mutex s_sync_lock; - int s_stack_depth; - long: 32; - long: 64; - long: 64; - long: 64; - spinlock_t s_inode_list_lock; - struct list_head s_inodes; - spinlock_t s_inode_wblist_lock; - struct list_head s_inodes_wb; - long: 64; - long: 64; -}; - -struct shrink_control { - gfp_t gfp_mask; - int nid; - long unsigned int nr_to_scan; - long unsigned int nr_scanned; - struct mem_cgroup *memcg; -}; - -struct list_lru_one { - struct list_head list; - long int nr_items; -}; - -struct list_lru_memcg { - struct callback_head rcu; - struct list_lru_one *lru[0]; -}; - -struct list_lru_node { - spinlock_t lock; - struct list_lru_one lru; - struct list_lru_memcg *memcg_lrus; - long int nr_items; - long: 64; - long: 64; -}; - -enum migrate_mode { - MIGRATE_ASYNC = 0, - MIGRATE_SYNC_LIGHT = 1, - MIGRATE_SYNC = 2, - MIGRATE_SYNC_NO_COPY = 3, -}; - -struct exception_table_entry { - int insn; - int fixup; -}; - -struct cgroup_base_stat { - struct task_cputime cputime; -}; - -struct psi_group {}; - -struct bpf_prog_array; - -struct cgroup_bpf { - struct bpf_prog_array *effective[38]; - struct list_head progs[38]; - u32 flags[38]; - struct list_head storages; - struct bpf_prog_array *inactive; - struct percpu_ref refcnt; - struct work_struct release_work; -}; - -struct cgroup_freezer_state { - bool freeze; - int e_freeze; - int nr_frozen_descendants; - int nr_frozen_tasks; -}; - -struct cgroup_root; - -struct cgroup_rstat_cpu; - -struct cgroup { - struct cgroup_subsys_state self; - long unsigned int flags; - int level; - int max_depth; - int nr_descendants; - int nr_dying_descendants; - int max_descendants; - int nr_populated_csets; - int nr_populated_domain_children; - int nr_populated_threaded_children; - int nr_threaded_children; - struct kernfs_node *kn; - struct cgroup_file procs_file; - struct cgroup_file events_file; - u16 subtree_control; - u16 subtree_ss_mask; - u16 old_subtree_control; - u16 old_subtree_ss_mask; - struct cgroup_subsys_state *subsys[11]; - struct cgroup_root *root; - struct list_head cset_links; - struct list_head e_csets[11]; - struct cgroup *dom_cgrp; - struct cgroup *old_dom_cgrp; - struct cgroup_rstat_cpu *rstat_cpu; - struct list_head rstat_css_list; - struct cgroup_base_stat last_bstat; - struct cgroup_base_stat bstat; - struct prev_cputime prev_cputime; - struct list_head pidlists; - struct mutex pidlist_mutex; - wait_queue_head_t offline_waitq; - struct work_struct release_agent_work; - struct psi_group psi; - struct cgroup_bpf bpf; - atomic_t congestion_count; - struct cgroup_freezer_state freezer; - u64 ancestor_ids[0]; -}; - -struct key_tag { - struct callback_head rcu; - refcount_t usage; - bool removed; -}; - -typedef int (*request_key_actor_t)(struct key *, void *); - -struct key_preparsed_payload; - -struct key_match_data; - -struct kernel_pkey_params; - -struct kernel_pkey_query; - -struct key_type { - const char *name; - size_t def_datalen; - unsigned int flags; - int (*vet_description)(const char *); - int (*preparse)(struct key_preparsed_payload *); - void (*free_preparse)(struct key_preparsed_payload *); - int (*instantiate)(struct key *, struct key_preparsed_payload *); - int (*update)(struct key *, struct key_preparsed_payload *); - int (*match_preparse)(struct key_match_data *); - void (*match_free)(struct key_match_data *); - void (*revoke)(struct key *); - void (*destroy)(struct key *); - void (*describe)(const struct key *, struct seq_file *); - long int (*read)(const struct key *, char *, size_t); - request_key_actor_t request_key; - struct key_restriction * (*lookup_restriction)(const char *); - int (*asym_query)(const struct kernel_pkey_params *, struct kernel_pkey_query *); - int (*asym_eds_op)(struct kernel_pkey_params *, const void *, void *); - int (*asym_verify_signature)(struct kernel_pkey_params *, const void *, const void *); - struct list_head link; - struct lock_class_key lock_class; -}; - -typedef int (*key_restrict_link_func_t)(struct key *, const struct key_type *, const union key_payload *, struct key *); - -struct key_restriction { - key_restrict_link_func_t check; - struct key *key; - struct key_type *keytype; -}; - -struct group_info { - atomic_t usage; - int ngroups; - kgid_t gid[0]; -}; - -struct taskstats { - __u16 version; - __u32 ac_exitcode; - __u8 ac_flag; - __u8 ac_nice; - __u64 cpu_count; - __u64 cpu_delay_total; - __u64 blkio_count; - __u64 blkio_delay_total; - __u64 swapin_count; - __u64 swapin_delay_total; - __u64 cpu_run_real_total; - __u64 cpu_run_virtual_total; - char ac_comm[32]; - __u8 ac_sched; - __u8 ac_pad[3]; - int: 32; - __u32 ac_uid; - __u32 ac_gid; - __u32 ac_pid; - __u32 ac_ppid; - __u32 ac_btime; - __u64 ac_etime; - __u64 ac_utime; - __u64 ac_stime; - __u64 ac_minflt; - __u64 ac_majflt; - __u64 coremem; - __u64 virtmem; - __u64 hiwater_rss; - __u64 hiwater_vm; - __u64 read_char; - __u64 write_char; - __u64 read_syscalls; - __u64 write_syscalls; - __u64 read_bytes; - __u64 write_bytes; - __u64 cancelled_write_bytes; - __u64 nvcsw; - __u64 nivcsw; - __u64 ac_utimescaled; - __u64 ac_stimescaled; - __u64 cpu_scaled_run_real_total; - __u64 freepages_count; - __u64 freepages_delay_total; - __u64 thrashing_count; - __u64 thrashing_delay_total; - __u64 ac_btime64; -}; - -struct delayed_call { - void (*fn)(void *); - void *arg; -}; - -struct io_cq { - struct request_queue *q; - struct io_context *ioc; - union { - struct list_head q_node; - struct kmem_cache *__rcu_icq_cache; - }; - union { - struct hlist_node ioc_node; - struct callback_head __rcu_head; - }; - unsigned int flags; -}; - -struct wait_page_queue; - -struct kiocb { - struct file *ki_filp; - loff_t ki_pos; - void (*ki_complete)(struct kiocb *, long int, long int); - void *private; - int ki_flags; - u16 ki_hint; - u16 ki_ioprio; - union { - unsigned int ki_cookie; - struct wait_page_queue *ki_waitq; - }; -}; - -struct iattr { - unsigned int ia_valid; - umode_t ia_mode; - kuid_t ia_uid; - kgid_t ia_gid; - loff_t ia_size; - struct timespec64 ia_atime; - struct timespec64 ia_mtime; - struct timespec64 ia_ctime; - struct file *ia_file; -}; - -typedef __kernel_uid32_t projid_t; - -typedef struct { - projid_t val; -} kprojid_t; - -enum quota_type { - USRQUOTA = 0, - GRPQUOTA = 1, - PRJQUOTA = 2, -}; - -struct kqid { - union { - kuid_t uid; - kgid_t gid; - kprojid_t projid; - }; - enum quota_type type; -}; - -struct mem_dqblk { - qsize_t dqb_bhardlimit; - qsize_t dqb_bsoftlimit; - qsize_t dqb_curspace; - qsize_t dqb_rsvspace; - qsize_t dqb_ihardlimit; - qsize_t dqb_isoftlimit; - qsize_t dqb_curinodes; - time64_t dqb_btime; - time64_t dqb_itime; -}; - -struct dquot { - struct hlist_node dq_hash; - struct list_head dq_inuse; - struct list_head dq_free; - struct list_head dq_dirty; - struct mutex dq_lock; - spinlock_t dq_dqb_lock; - atomic_t dq_count; - struct super_block *dq_sb; - struct kqid dq_id; - loff_t dq_off; - long unsigned int dq_flags; - struct mem_dqblk dq_dqb; -}; - -struct quota_format_type { - int qf_fmt_id; - const struct quota_format_ops *qf_ops; - struct module *qf_owner; - struct quota_format_type *qf_next; -}; - -struct quota_format_ops { - int (*check_quota_file)(struct super_block *, int); - int (*read_file_info)(struct super_block *, int); - int (*write_file_info)(struct super_block *, int); - int (*free_file_info)(struct super_block *, int); - int (*read_dqblk)(struct dquot *); - int (*commit_dqblk)(struct dquot *); - int (*release_dqblk)(struct dquot *); - int (*get_next_id)(struct super_block *, struct kqid *); -}; - -struct dquot_operations { - int (*write_dquot)(struct dquot *); - struct dquot * (*alloc_dquot)(struct super_block *, int); - void (*destroy_dquot)(struct dquot *); - int (*acquire_dquot)(struct dquot *); - int (*release_dquot)(struct dquot *); - int (*mark_dirty)(struct dquot *); - int (*write_info)(struct super_block *, int); - qsize_t * (*get_reserved_space)(struct inode *); - int (*get_projid)(struct inode *, kprojid_t *); - int (*get_inode_usage)(struct inode *, qsize_t *); - int (*get_next_id)(struct super_block *, struct kqid *); -}; - -struct qc_dqblk { - int d_fieldmask; - u64 d_spc_hardlimit; - u64 d_spc_softlimit; - u64 d_ino_hardlimit; - u64 d_ino_softlimit; - u64 d_space; - u64 d_ino_count; - s64 d_ino_timer; - s64 d_spc_timer; - int d_ino_warns; - int d_spc_warns; - u64 d_rt_spc_hardlimit; - u64 d_rt_spc_softlimit; - u64 d_rt_space; - s64 d_rt_spc_timer; - int d_rt_spc_warns; -}; - -struct qc_type_state { - unsigned int flags; - unsigned int spc_timelimit; - unsigned int ino_timelimit; - unsigned int rt_spc_timelimit; - unsigned int spc_warnlimit; - unsigned int ino_warnlimit; - unsigned int rt_spc_warnlimit; - long long unsigned int ino; - blkcnt_t blocks; - blkcnt_t nextents; -}; - -struct qc_state { - unsigned int s_incoredqs; - struct qc_type_state s_state[3]; -}; - -struct qc_info { - int i_fieldmask; - unsigned int i_flags; - unsigned int i_spc_timelimit; - unsigned int i_ino_timelimit; - unsigned int i_rt_spc_timelimit; - unsigned int i_spc_warnlimit; - unsigned int i_ino_warnlimit; - unsigned int i_rt_spc_warnlimit; -}; - -struct quotactl_ops { - int (*quota_on)(struct super_block *, int, int, const struct path *); - int (*quota_off)(struct super_block *, int); - int (*quota_enable)(struct super_block *, unsigned int); - int (*quota_disable)(struct super_block *, unsigned int); - int (*quota_sync)(struct super_block *, int); - int (*set_info)(struct super_block *, int, struct qc_info *); - int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); - int (*get_nextdqblk)(struct super_block *, struct kqid *, struct qc_dqblk *); - int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); - int (*get_state)(struct super_block *, struct qc_state *); - int (*rm_xquota)(struct super_block *, unsigned int); -}; - -struct wait_page_queue { - struct page *page; - int bit_nr; - wait_queue_entry_t wait; -}; - -struct writeback_control; - -struct readahead_control; - -struct swap_info_struct; - -struct address_space_operations { - int (*writepage)(struct page *, struct writeback_control *); - int (*readpage)(struct file *, struct page *); - int (*writepages)(struct address_space *, struct writeback_control *); - int (*set_page_dirty)(struct page *); - int (*readpages)(struct file *, struct address_space *, struct list_head *, unsigned int); - void (*readahead)(struct readahead_control *); - int (*write_begin)(struct file *, struct address_space *, loff_t, unsigned int, unsigned int, struct page **, void **); - int (*write_end)(struct file *, struct address_space *, loff_t, unsigned int, unsigned int, struct page *, void *); - sector_t (*bmap)(struct address_space *, sector_t); - void (*invalidatepage)(struct page *, unsigned int, unsigned int); - int (*releasepage)(struct page *, gfp_t); - void (*freepage)(struct page *); - ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *); - int (*migratepage)(struct address_space *, struct page *, struct page *, enum migrate_mode); - bool (*isolate_page)(struct page *, isolate_mode_t); - void (*putback_page)(struct page *); - int (*launder_page)(struct page *); - int (*is_partially_uptodate)(struct page *, long unsigned int, long unsigned int); - void (*is_dirty_writeback)(struct page *, bool *, bool *); - int (*error_remove_page)(struct address_space *, struct page *); - int (*swap_activate)(struct swap_info_struct *, struct file *, sector_t *); - void (*swap_deactivate)(struct file *); -}; - -enum writeback_sync_modes { - WB_SYNC_NONE = 0, - WB_SYNC_ALL = 1, -}; - -struct writeback_control { - long int nr_to_write; - long int pages_skipped; - loff_t range_start; - loff_t range_end; - enum writeback_sync_modes sync_mode; - unsigned int for_kupdate: 1; - unsigned int for_background: 1; - unsigned int tagged_writepages: 1; - unsigned int for_reclaim: 1; - unsigned int range_cyclic: 1; - unsigned int for_sync: 1; - unsigned int no_cgroup_owner: 1; - unsigned int punt_to_cgroup: 1; - struct bdi_writeback *wb; - struct inode *inode; - int wb_id; - int wb_lcand_id; - int wb_tcand_id; - size_t wb_bytes; - size_t wb_lcand_bytes; - size_t wb_tcand_bytes; -}; - -struct readahead_control { - struct file *file; - struct address_space *mapping; - long unsigned int _index; - unsigned int _nr_pages; - unsigned int _batch_count; -}; - -struct iovec; - -struct kvec; - -struct bio_vec; - -struct iov_iter { - unsigned int type; - size_t iov_offset; - size_t count; - union { - const struct iovec *iov; - const struct kvec *kvec; - const struct bio_vec *bvec; - struct pipe_inode_info *pipe; - }; - union { - long unsigned int nr_segs; - struct { - unsigned int head; - unsigned int start_head; - }; - }; -}; - -struct swap_cluster_info { - spinlock_t lock; - unsigned int data: 24; - unsigned int flags: 8; -}; - -struct swap_cluster_list { - struct swap_cluster_info head; - struct swap_cluster_info tail; -}; - -struct percpu_cluster; - -struct swap_info_struct { - long unsigned int flags; - short int prio; - struct plist_node list; - signed char type; - unsigned int max; - unsigned char *swap_map; - struct swap_cluster_info *cluster_info; - struct swap_cluster_list free_clusters; - unsigned int lowest_bit; - unsigned int highest_bit; - unsigned int pages; - unsigned int inuse_pages; - unsigned int cluster_next; - unsigned int cluster_nr; - unsigned int *cluster_next_cpu; - struct percpu_cluster *percpu_cluster; - struct rb_root swap_extent_root; - struct block_device *bdev; - struct file *swap_file; - unsigned int old_block_size; - long unsigned int *frontswap_map; - atomic_t frontswap_pages; - spinlock_t lock; - spinlock_t cont_lock; - struct work_struct discard_work; - struct swap_cluster_list discard_clusters; - struct plist_node avail_lists[0]; -}; - -struct hd_struct; - -struct gendisk; - -struct block_device { - dev_t bd_dev; - int bd_openers; - struct inode *bd_inode; - struct super_block *bd_super; - struct mutex bd_mutex; - void *bd_claiming; - void *bd_holder; - int bd_holders; - bool bd_write_holder; - struct list_head bd_holder_disks; - struct block_device *bd_contains; - u8 bd_partno; - struct hd_struct *bd_part; - unsigned int bd_part_count; - spinlock_t bd_size_lock; - struct gendisk *bd_disk; - struct backing_dev_info *bd_bdi; - int bd_fsfreeze_count; - struct mutex bd_fsfreeze_mutex; -}; - -struct cdev { - struct kobject kobj; - struct module *owner; - const struct file_operations *ops; - struct list_head list; - dev_t dev; - unsigned int count; -}; - -struct fiemap_extent_info; - -struct inode_operations { - struct dentry * (*lookup)(struct inode *, struct dentry *, unsigned int); - const char * (*get_link)(struct dentry *, struct inode *, struct delayed_call *); - int (*permission)(struct inode *, int); - struct posix_acl * (*get_acl)(struct inode *, int); - int (*readlink)(struct dentry *, char *, int); - int (*create)(struct inode *, struct dentry *, umode_t, bool); - int (*link)(struct dentry *, struct inode *, struct dentry *); - int (*unlink)(struct inode *, struct dentry *); - int (*symlink)(struct inode *, struct dentry *, const char *); - int (*mkdir)(struct inode *, struct dentry *, umode_t); - int (*rmdir)(struct inode *, struct dentry *); - int (*mknod)(struct inode *, struct dentry *, umode_t, dev_t); - int (*rename)(struct inode *, struct dentry *, struct inode *, struct dentry *, unsigned int); - int (*setattr)(struct dentry *, struct iattr *); - int (*getattr)(const struct path *, struct kstat *, u32, unsigned int); - ssize_t (*listxattr)(struct dentry *, char *, size_t); - int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64, u64); - int (*update_time)(struct inode *, struct timespec64 *, int); - int (*atomic_open)(struct inode *, struct dentry *, struct file *, unsigned int, umode_t); - int (*tmpfile)(struct inode *, struct dentry *, umode_t); - int (*set_acl)(struct inode *, struct posix_acl *, int); - long: 64; - long: 64; - long: 64; -}; - -struct file_lock_context { - spinlock_t flc_lock; - struct list_head flc_flock; - struct list_head flc_posix; - struct list_head flc_lease; -}; - -struct file_lock_operations { - void (*fl_copy_lock)(struct file_lock *, struct file_lock *); - void (*fl_release_private)(struct file_lock *); -}; - -struct nlm_lockowner; - -struct nfs_lock_info { - u32 state; - struct nlm_lockowner *owner; - struct list_head list; -}; - -struct nfs4_lock_state; - -struct nfs4_lock_info { - struct nfs4_lock_state *owner; -}; - -struct lock_manager_operations; - -struct file_lock { - struct file_lock *fl_blocker; - struct list_head fl_list; - struct hlist_node fl_link; - struct list_head fl_blocked_requests; - struct list_head fl_blocked_member; - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - unsigned int fl_pid; - int fl_link_cpu; - wait_queue_head_t fl_wait; - struct file *fl_file; - loff_t fl_start; - loff_t fl_end; - struct fasync_struct *fl_fasync; - long unsigned int fl_break_time; - long unsigned int fl_downgrade_time; - const struct file_lock_operations *fl_ops; - const struct lock_manager_operations *fl_lmops; - union { - struct nfs_lock_info nfs_fl; - struct nfs4_lock_info nfs4_fl; - struct { - struct list_head link; - int state; - unsigned int debug_id; - } afs; - } fl_u; -}; - -struct lock_manager_operations { - fl_owner_t (*lm_get_owner)(fl_owner_t); - void (*lm_put_owner)(fl_owner_t); - void (*lm_notify)(struct file_lock *); - int (*lm_grant)(struct file_lock *, int); - bool (*lm_break)(struct file_lock *); - int (*lm_change)(struct file_lock *, int, struct list_head *); - void (*lm_setup)(struct file_lock *, void **); - bool (*lm_breaker_owns_lease)(struct file_lock *); -}; - -struct fasync_struct { - rwlock_t fa_lock; - int magic; - int fa_fd; - struct fasync_struct *fa_next; - struct file *fa_file; - struct callback_head fa_rcu; -}; - -struct kstatfs; - -struct super_operations { - struct inode * (*alloc_inode)(struct super_block *); - void (*destroy_inode)(struct inode *); - void (*free_inode)(struct inode *); - void (*dirty_inode)(struct inode *, int); - int (*write_inode)(struct inode *, struct writeback_control *); - int (*drop_inode)(struct inode *); - void (*evict_inode)(struct inode *); - void (*put_super)(struct super_block *); - int (*sync_fs)(struct super_block *, int); - int (*freeze_super)(struct super_block *); - int (*freeze_fs)(struct super_block *); - int (*thaw_super)(struct super_block *); - int (*unfreeze_fs)(struct super_block *); - int (*statfs)(struct dentry *, struct kstatfs *); - int (*remount_fs)(struct super_block *, int *, char *); - void (*umount_begin)(struct super_block *); - int (*show_options)(struct seq_file *, struct dentry *); - int (*show_devname)(struct seq_file *, struct dentry *); - int (*show_path)(struct seq_file *, struct dentry *); - int (*show_stats)(struct seq_file *, struct dentry *); - ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); - ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); - struct dquot ** (*get_dquots)(struct inode *); - int (*bdev_try_to_free_page)(struct super_block *, struct page *, gfp_t); - long int (*nr_cached_objects)(struct super_block *, struct shrink_control *); - long int (*free_cached_objects)(struct super_block *, struct shrink_control *); -}; - -struct iomap; - -struct fid; - -struct export_operations { - int (*encode_fh)(struct inode *, __u32 *, int *, struct inode *); - struct dentry * (*fh_to_dentry)(struct super_block *, struct fid *, int, int); - struct dentry * (*fh_to_parent)(struct super_block *, struct fid *, int, int); - int (*get_name)(struct dentry *, char *, struct dentry *); - struct dentry * (*get_parent)(struct dentry *); - int (*commit_metadata)(struct inode *); - int (*get_uuid)(struct super_block *, u8 *, u32 *, u64 *); - int (*map_blocks)(struct inode *, loff_t, u64, struct iomap *, bool, u32 *); - int (*commit_blocks)(struct inode *, struct iomap *, int, struct iattr *); -}; - -struct xattr_handler { - const char *name; - const char *prefix; - int flags; - bool (*list)(struct dentry *); - int (*get)(const struct xattr_handler *, struct dentry *, struct inode *, const char *, void *, size_t); - int (*set)(const struct xattr_handler *, struct dentry *, struct inode *, const char *, const void *, size_t, int); -}; - -union fscrypt_policy; - -struct fscrypt_operations { - unsigned int flags; - const char *key_prefix; - int (*get_context)(struct inode *, void *, size_t); - int (*set_context)(struct inode *, const void *, size_t, void *); - const union fscrypt_policy * (*get_dummy_policy)(struct super_block *); - bool (*empty_dir)(struct inode *); - unsigned int max_namelen; - bool (*has_stable_inodes)(struct super_block *); - void (*get_ino_and_lblk_bits)(struct super_block *, int *, int *); - int (*get_num_devices)(struct super_block *); - void (*get_devices)(struct super_block *, struct request_queue **); -}; - -typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64, unsigned int); - -struct dir_context { - filldir_t actor; - loff_t pos; -}; - -typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); - -struct poll_table_struct { - poll_queue_proc _qproc; - __poll_t _key; -}; - -struct seq_operations; - -struct seq_file { - char *buf; - size_t size; - size_t from; - size_t count; - size_t pad_until; - loff_t index; - loff_t read_pos; - struct mutex lock; - const struct seq_operations *op; - int poll_event; - const struct file *file; - void *private; -}; - -struct fc_log; - -struct p_log { - const char *prefix; - struct fc_log *log; -}; - -enum fs_context_purpose { - FS_CONTEXT_FOR_MOUNT = 0, - FS_CONTEXT_FOR_SUBMOUNT = 1, - FS_CONTEXT_FOR_RECONFIGURE = 2, -}; - -enum fs_context_phase { - FS_CONTEXT_CREATE_PARAMS = 0, - FS_CONTEXT_CREATING = 1, - FS_CONTEXT_AWAITING_MOUNT = 2, - FS_CONTEXT_AWAITING_RECONF = 3, - FS_CONTEXT_RECONF_PARAMS = 4, - FS_CONTEXT_RECONFIGURING = 5, - FS_CONTEXT_FAILED = 6, -}; - -struct fs_context_operations; - -struct fs_context { - const struct fs_context_operations *ops; - struct mutex uapi_mutex; - struct file_system_type *fs_type; - void *fs_private; - void *sget_key; - struct dentry *root; - struct user_namespace *user_ns; - struct net *net_ns; - const struct cred *cred; - struct p_log log; - const char *source; - void *security; - void *s_fs_info; - unsigned int sb_flags; - unsigned int sb_flags_mask; - unsigned int s_iflags; - unsigned int lsm_flags; - enum fs_context_purpose purpose: 8; - enum fs_context_phase phase: 8; - bool need_free: 1; - bool global: 1; - bool oldapi: 1; -}; - -struct fs_parameter; - -struct fs_parse_result; - -typedef int fs_param_type(struct p_log *, const struct fs_parameter_spec *, struct fs_parameter *, struct fs_parse_result *); - -struct fs_parameter_spec { - const char *name; - fs_param_type *type; - u8 opt; - short unsigned int flags; - const void *data; -}; - -struct audit_names; - -struct filename { - const char *name; - const char *uptr; - int refcnt; - struct audit_names *aname; - const char iname[0]; -}; - -typedef u8 blk_status_t; - -struct bvec_iter { - sector_t bi_sector; - unsigned int bi_size; - unsigned int bi_idx; - unsigned int bi_bvec_done; -}; - -typedef void bio_end_io_t(struct bio *); - -struct bio_issue { - u64 value; -}; - -struct bio_vec { - struct page *bv_page; - unsigned int bv_len; - unsigned int bv_offset; -}; - -struct bio { - struct bio *bi_next; - struct gendisk *bi_disk; - unsigned int bi_opf; - short unsigned int bi_flags; - short unsigned int bi_ioprio; - short unsigned int bi_write_hint; - blk_status_t bi_status; - u8 bi_partno; - atomic_t __bi_remaining; - struct bvec_iter bi_iter; - bio_end_io_t *bi_end_io; - void *bi_private; - struct blkcg_gq *bi_blkg; - struct bio_issue bi_issue; - union { }; - short unsigned int bi_vcnt; - short unsigned int bi_max_vecs; - atomic_t __bi_cnt; - struct bio_vec *bi_io_vec; - struct bio_set *bi_pool; - struct bio_vec bi_inline_vecs[0]; -}; - -struct kernfs_root; - -struct kernfs_elem_dir { - long unsigned int subdirs; - struct rb_root children; - struct kernfs_root *root; -}; - -struct kernfs_syscall_ops; - -struct kernfs_root { - struct kernfs_node *kn; - unsigned int flags; - struct idr ino_idr; - u32 last_id_lowbits; - u32 id_highbits; - struct kernfs_syscall_ops *syscall_ops; - struct list_head supers; - wait_queue_head_t deactivate_waitq; -}; - -struct kernfs_elem_symlink { - struct kernfs_node *target_kn; -}; - -struct kernfs_ops; - -struct kernfs_open_node; - -struct kernfs_elem_attr { - const struct kernfs_ops *ops; - struct kernfs_open_node *open; - loff_t size; - struct kernfs_node *notify_next; -}; - -struct kernfs_iattrs; - -struct kernfs_node { - atomic_t count; - atomic_t active; - struct kernfs_node *parent; - const char *name; - struct rb_node rb; - const void *ns; - unsigned int hash; - union { - struct kernfs_elem_dir dir; - struct kernfs_elem_symlink symlink; - struct kernfs_elem_attr attr; - }; - void *priv; - u64 id; - short unsigned int flags; - umode_t mode; - struct kernfs_iattrs *iattr; -}; - -struct kernfs_open_file; - -struct kernfs_ops { - int (*open)(struct kernfs_open_file *); - void (*release)(struct kernfs_open_file *); - int (*seq_show)(struct seq_file *, void *); - void * (*seq_start)(struct seq_file *, loff_t *); - void * (*seq_next)(struct seq_file *, void *, loff_t *); - void (*seq_stop)(struct seq_file *, void *); - ssize_t (*read)(struct kernfs_open_file *, char *, size_t, loff_t); - size_t atomic_write_len; - bool prealloc; - ssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t); - __poll_t (*poll)(struct kernfs_open_file *, struct poll_table_struct *); - int (*mmap)(struct kernfs_open_file *, struct vm_area_struct *); -}; - -struct kernfs_syscall_ops { - int (*show_options)(struct seq_file *, struct kernfs_root *); - int (*mkdir)(struct kernfs_node *, const char *, umode_t); - int (*rmdir)(struct kernfs_node *); - int (*rename)(struct kernfs_node *, struct kernfs_node *, const char *); - int (*show_path)(struct seq_file *, struct kernfs_node *, struct kernfs_root *); -}; - -struct kernfs_open_file { - struct kernfs_node *kn; - struct file *file; - struct seq_file *seq_file; - void *priv; - struct mutex mutex; - struct mutex prealloc_mutex; - int event; - struct list_head list; - char *prealloc_buf; - size_t atomic_write_len; - bool mmapped: 1; - bool released: 1; - const struct vm_operations_struct *vm_ops; -}; - -enum kobj_ns_type { - KOBJ_NS_TYPE_NONE = 0, - KOBJ_NS_TYPE_NET = 1, - KOBJ_NS_TYPES = 2, -}; - -struct sock; - -struct kobj_ns_type_operations { - enum kobj_ns_type type; - bool (*current_may_mount)(); - void * (*grab_current_ns)(); - const void * (*netlink_ns)(struct sock *); - const void * (*initial_ns)(); - void (*drop_ns)(void *); -}; - -struct attribute { - const char *name; - umode_t mode; -}; - -struct bin_attribute; - -struct attribute_group { - const char *name; - umode_t (*is_visible)(struct kobject *, struct attribute *, int); - umode_t (*is_bin_visible)(struct kobject *, struct bin_attribute *, int); - struct attribute **attrs; - struct bin_attribute **bin_attrs; -}; - -struct bin_attribute { - struct attribute attr; - size_t size; - void *private; - ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t); - ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t); - int (*mmap)(struct file *, struct kobject *, struct bin_attribute *, struct vm_area_struct *); -}; - -struct sysfs_ops { - ssize_t (*show)(struct kobject *, struct attribute *, char *); - ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); -}; - -struct kset_uevent_ops; - -struct kset { - struct list_head list; - spinlock_t list_lock; - struct kobject kobj; - const struct kset_uevent_ops *uevent_ops; -}; - -struct kobj_type { - void (*release)(struct kobject *); - const struct sysfs_ops *sysfs_ops; - struct attribute **default_attrs; - const struct attribute_group **default_groups; - const struct kobj_ns_type_operations * (*child_ns_type)(struct kobject *); - const void * (*namespace)(struct kobject *); - void (*get_ownership)(struct kobject *, kuid_t *, kgid_t *); -}; - -struct kobj_uevent_env { - char *argv[3]; - char *envp[64]; - int envp_idx; - char buf[2048]; - int buflen; -}; - -struct kset_uevent_ops { - int (* const filter)(struct kset *, struct kobject *); - const char * (* const name)(struct kset *, struct kobject *); - int (* const uevent)(struct kset *, struct kobject *, struct kobj_uevent_env *); -}; - -struct kernel_param_ops { - unsigned int flags; - int (*set)(const char *, const struct kernel_param *); - int (*get)(char *, const struct kernel_param *); - void (*free)(void *); -}; - -struct kparam_string; - -struct kparam_array; - -struct kernel_param { - const char *name; - struct module *mod; - const struct kernel_param_ops *ops; - const u16 perm; - s8 level; - u8 flags; - union { - void *arg; - const struct kparam_string *str; - const struct kparam_array *arr; - }; -}; - -struct kparam_string { - unsigned int maxlen; - char *string; -}; - -struct kparam_array { - unsigned int max; - unsigned int elemsize; - unsigned int *num; - const struct kernel_param_ops *ops; - void *elem; -}; - -struct error_injection_entry { - long unsigned int addr; - int etype; -}; - -struct tracepoint_func { - void *func; - void *data; - int prio; -}; - -struct static_call_key; - -struct tracepoint { - const char *name; - struct static_key key; - struct static_call_key *static_call_key; - void *static_call_tramp; - void *iterator; - int (*regfunc)(); - void (*unregfunc)(); - struct tracepoint_func *funcs; -}; - -struct static_call_key { - void *func; -}; - -struct bpf_raw_event_map { - struct tracepoint *tp; - void *bpf_func; - u32 num_args; - u32 writable_size; - long: 64; -}; - -struct plt_entry { - __le32 adrp; - __le32 add; - __le32 br; -}; - -struct module_attribute { - struct attribute attr; - ssize_t (*show)(struct module_attribute *, struct module_kobject *, char *); - ssize_t (*store)(struct module_attribute *, struct module_kobject *, const char *, size_t); - void (*setup)(struct module *, const char *); - int (*test)(struct module *); - void (*free)(struct module *); -}; - -struct trace_event_functions; - -struct trace_event { - struct hlist_node node; - struct list_head list; - int type; - struct trace_event_functions *funcs; -}; - -struct trace_event_class; - -struct trace_event_call { - struct list_head list; - struct trace_event_class *class; - union { - char *name; - struct tracepoint *tp; - }; - struct trace_event event; - char *print_fmt; - struct event_filter *filter; - void *mod; - void *data; - int flags; - int perf_refcount; - struct hlist_head *perf_events; - struct bpf_prog_array *prog_array; - int (*perf_perm)(struct trace_event_call *, struct perf_event *); -}; - -struct trace_eval_map { - const char *system; - const char *eval_string; - long unsigned int eval_value; -}; - -struct linux_binprm { - struct vm_area_struct *vma; - long unsigned int vma_pages; - struct mm_struct *mm; - long unsigned int p; - long unsigned int argmin; - unsigned int have_execfd: 1; - unsigned int execfd_creds: 1; - unsigned int secureexec: 1; - unsigned int point_of_no_return: 1; - struct file *executable; - struct file *interpreter; - struct file *file; - struct cred *cred; - int unsafe; - unsigned int per_clear; - int argc; - int envc; - const char *filename; - const char *interp; - const char *fdpath; - unsigned int interp_flags; - int execfd; - long unsigned int loader; - long unsigned int exec; - struct rlimit rlim_stack; - char buf[256]; -}; - -struct coredump_params { - const kernel_siginfo_t *siginfo; - struct pt_regs *regs; - struct file *file; - long unsigned int limit; - long unsigned int mm_flags; - loff_t written; - loff_t pos; -}; - -struct pm_message { - int event; -}; - -typedef struct pm_message pm_message_t; - -struct dev_pm_ops { - int (*prepare)(struct device *); - void (*complete)(struct device *); - int (*suspend)(struct device *); - int (*resume)(struct device *); - int (*freeze)(struct device *); - int (*thaw)(struct device *); - int (*poweroff)(struct device *); - int (*restore)(struct device *); - int (*suspend_late)(struct device *); - int (*resume_early)(struct device *); - int (*freeze_late)(struct device *); - int (*thaw_early)(struct device *); - int (*poweroff_late)(struct device *); - int (*restore_early)(struct device *); - int (*suspend_noirq)(struct device *); - int (*resume_noirq)(struct device *); - int (*freeze_noirq)(struct device *); - int (*thaw_noirq)(struct device *); - int (*poweroff_noirq)(struct device *); - int (*restore_noirq)(struct device *); - int (*runtime_suspend)(struct device *); - int (*runtime_resume)(struct device *); - int (*runtime_idle)(struct device *); -}; - -enum dl_dev_state { - DL_DEV_NO_DRIVER = 0, - DL_DEV_PROBING = 1, - DL_DEV_DRIVER_BOUND = 2, - DL_DEV_UNBINDING = 3, -}; - -struct dev_links_info { - struct list_head suppliers; - struct list_head consumers; - struct list_head needs_suppliers; - struct list_head defer_hook; - bool need_for_probe; - enum dl_dev_state status; -}; - -enum rpm_request { - RPM_REQ_NONE = 0, - RPM_REQ_IDLE = 1, - RPM_REQ_SUSPEND = 2, - RPM_REQ_AUTOSUSPEND = 3, - RPM_REQ_RESUME = 4, -}; - -struct wake_irq; - -struct pm_subsys_data; - -struct dev_pm_qos; - -struct dev_pm_info { - pm_message_t power_state; - unsigned int can_wakeup: 1; - unsigned int async_suspend: 1; - bool in_dpm_list: 1; - bool is_prepared: 1; - bool is_suspended: 1; - bool is_noirq_suspended: 1; - bool is_late_suspended: 1; - bool no_pm: 1; - bool early_init: 1; - bool direct_complete: 1; - u32 driver_flags; - spinlock_t lock; - unsigned int should_wakeup: 1; - struct hrtimer suspend_timer; - u64 timer_expires; - struct work_struct work; - wait_queue_head_t wait_queue; - struct wake_irq *wakeirq; - atomic_t usage_count; - atomic_t child_count; - unsigned int disable_depth: 3; - unsigned int idle_notification: 1; - unsigned int request_pending: 1; - unsigned int deferred_resume: 1; - unsigned int needs_force_resume: 1; - unsigned int runtime_auto: 1; - bool ignore_children: 1; - unsigned int no_callbacks: 1; - unsigned int irq_safe: 1; - unsigned int use_autosuspend: 1; - unsigned int timer_autosuspends: 1; - unsigned int memalloc_noio: 1; - unsigned int links_count; - enum rpm_request request; - enum rpm_status runtime_status; - int runtime_error; - int autosuspend_delay; - u64 last_busy; - u64 active_time; - u64 suspended_time; - u64 accounting_timestamp; - struct pm_subsys_data *subsys_data; - void (*set_latency_tolerance)(struct device *, s32); - struct dev_pm_qos *qos; -}; - -struct dev_archdata {}; - -struct dev_iommu; - -struct device_private; - -struct device_type; - -struct bus_type; - -struct device_driver; - -struct dev_pm_domain; - -struct irq_domain; - -struct dev_pin_info; - -struct bus_dma_region; - -struct device_dma_parameters; - -struct dma_coherent_mem; - -struct cma; - -struct device_node; - -struct fwnode_handle; - -struct class; - -struct iommu_group; - -struct device { - struct kobject kobj; - struct device *parent; - struct device_private *p; - const char *init_name; - const struct device_type *type; - struct bus_type *bus; - struct device_driver *driver; - void *platform_data; - void *driver_data; - struct mutex mutex; - struct dev_links_info links; - struct dev_pm_info power; - struct dev_pm_domain *pm_domain; - struct irq_domain *msi_domain; - struct dev_pin_info *pins; - raw_spinlock_t msi_lock; - struct list_head msi_list; - u64 *dma_mask; - u64 coherent_dma_mask; - u64 bus_dma_limit; - const struct bus_dma_region *dma_range_map; - struct device_dma_parameters *dma_parms; - struct list_head dma_pools; - struct dma_coherent_mem *dma_mem; - struct cma *cma_area; - struct dev_archdata archdata; - struct device_node *of_node; - struct fwnode_handle *fwnode; - dev_t devt; - u32 id; - spinlock_t devres_lock; - struct list_head devres_head; - struct class *class; - const struct attribute_group **groups; - void (*release)(struct device *); - struct iommu_group *iommu_group; - struct dev_iommu *iommu; - bool offline_disabled: 1; - bool offline: 1; - bool of_node_reused: 1; - bool state_synced: 1; - bool dma_coherent: 1; -}; - -struct pm_domain_data; - -struct pm_subsys_data { - spinlock_t lock; - unsigned int refcount; - struct list_head clock_list; - struct pm_domain_data *domain_data; -}; - -struct dev_pm_domain { - struct dev_pm_ops ops; - int (*start)(struct device *); - void (*detach)(struct device *, bool); - int (*activate)(struct device *); - void (*sync)(struct device *); - void (*dismiss)(struct device *); -}; - -struct iommu_ops; - -struct subsys_private; - -struct bus_type { - const char *name; - const char *dev_name; - struct device *dev_root; - const struct attribute_group **bus_groups; - const struct attribute_group **dev_groups; - const struct attribute_group **drv_groups; - int (*match)(struct device *, struct device_driver *); - int (*uevent)(struct device *, struct kobj_uevent_env *); - int (*probe)(struct device *); - void (*sync_state)(struct device *); - int (*remove)(struct device *); - void (*shutdown)(struct device *); - int (*online)(struct device *); - int (*offline)(struct device *); - int (*suspend)(struct device *, pm_message_t); - int (*resume)(struct device *); - int (*num_vf)(struct device *); - int (*dma_configure)(struct device *); - const struct dev_pm_ops *pm; - const struct iommu_ops *iommu_ops; - struct subsys_private *p; - struct lock_class_key lock_key; - bool need_parent_lock; -}; - -enum probe_type { - PROBE_DEFAULT_STRATEGY = 0, - PROBE_PREFER_ASYNCHRONOUS = 1, - PROBE_FORCE_SYNCHRONOUS = 2, -}; - -struct of_device_id; - -struct acpi_device_id; - -struct driver_private; - -struct device_driver { - const char *name; - struct bus_type *bus; - struct module *owner; - const char *mod_name; - bool suppress_bind_attrs; - enum probe_type probe_type; - const struct of_device_id *of_match_table; - const struct acpi_device_id *acpi_match_table; - int (*probe)(struct device *); - void (*sync_state)(struct device *); - int (*remove)(struct device *); - void (*shutdown)(struct device *); - int (*suspend)(struct device *, pm_message_t); - int (*resume)(struct device *); - const struct attribute_group **groups; - const struct attribute_group **dev_groups; - const struct dev_pm_ops *pm; - void (*coredump)(struct device *); - struct driver_private *p; -}; - -struct iommu_ops {}; - -struct device_type { - const char *name; - const struct attribute_group **groups; - int (*uevent)(struct device *, struct kobj_uevent_env *); - char * (*devnode)(struct device *, umode_t *, kuid_t *, kgid_t *); - void (*release)(struct device *); - const struct dev_pm_ops *pm; -}; - -struct class { - const char *name; - struct module *owner; - const struct attribute_group **class_groups; - const struct attribute_group **dev_groups; - struct kobject *dev_kobj; - int (*dev_uevent)(struct device *, struct kobj_uevent_env *); - char * (*devnode)(struct device *, umode_t *); - void (*class_release)(struct class *); - void (*dev_release)(struct device *); - int (*shutdown_pre)(struct device *); - const struct kobj_ns_type_operations *ns_type; - const void * (*namespace)(struct device *); - void (*get_ownership)(struct device *, kuid_t *, kgid_t *); - const struct dev_pm_ops *pm; - struct subsys_private *p; -}; - -struct of_device_id { - char name[32]; - char type[32]; - char compatible[128]; - const void *data; -}; - -typedef long unsigned int kernel_ulong_t; - -struct acpi_device_id { - __u8 id[9]; - kernel_ulong_t driver_data; - __u32 cls; - __u32 cls_msk; -}; - -struct device_dma_parameters { - unsigned int max_segment_size; - unsigned int min_align_mask; - long unsigned int segment_boundary_mask; -}; - -enum irq_domain_bus_token { - DOMAIN_BUS_ANY = 0, - DOMAIN_BUS_WIRED = 1, - DOMAIN_BUS_GENERIC_MSI = 2, - DOMAIN_BUS_PCI_MSI = 3, - DOMAIN_BUS_PLATFORM_MSI = 4, - DOMAIN_BUS_NEXUS = 5, - DOMAIN_BUS_IPI = 6, - DOMAIN_BUS_FSL_MC_MSI = 7, - DOMAIN_BUS_TI_SCI_INTA_MSI = 8, - DOMAIN_BUS_WAKEUP = 9, - DOMAIN_BUS_VMD_MSI = 10, -}; - -struct irq_domain_ops; - -struct irq_domain_chip_generic; - -struct irq_domain { - struct list_head link; - const char *name; - const struct irq_domain_ops *ops; - void *host_data; - unsigned int flags; - unsigned int mapcount; - struct fwnode_handle *fwnode; - enum irq_domain_bus_token bus_token; - struct irq_domain_chip_generic *gc; - struct irq_domain *parent; - struct dentry *debugfs_file; - irq_hw_number_t hwirq_max; - unsigned int revmap_direct_max_irq; - unsigned int revmap_size; - struct xarray revmap_tree; - struct mutex revmap_tree_mutex; - unsigned int linear_revmap[0]; -}; - -typedef u64 dma_addr_t; - -struct bus_dma_region { - phys_addr_t cpu_start; - dma_addr_t dma_start; - u64 size; - u64 offset; -}; - -typedef u32 phandle; - -struct fwnode_operations; - -struct fwnode_handle { - struct fwnode_handle *secondary; - const struct fwnode_operations *ops; - struct device *dev; -}; - -struct property; - -struct device_node { - const char *name; - phandle phandle; - const char *full_name; - struct fwnode_handle fwnode; - struct property *properties; - struct property *deadprops; - struct device_node *parent; - struct device_node *child; - struct device_node *sibling; - struct kobject kobj; - long unsigned int _flags; - void *data; -}; - -enum cpuhp_state { - CPUHP_INVALID = 4294967295, - CPUHP_OFFLINE = 0, - CPUHP_CREATE_THREADS = 1, - CPUHP_PERF_PREPARE = 2, - CPUHP_PERF_X86_PREPARE = 3, - CPUHP_PERF_X86_AMD_UNCORE_PREP = 4, - CPUHP_PERF_POWER = 5, - CPUHP_PERF_SUPERH = 6, - CPUHP_X86_HPET_DEAD = 7, - CPUHP_X86_APB_DEAD = 8, - CPUHP_X86_MCE_DEAD = 9, - CPUHP_VIRT_NET_DEAD = 10, - CPUHP_SLUB_DEAD = 11, - CPUHP_DEBUG_OBJ_DEAD = 12, - CPUHP_MM_WRITEBACK_DEAD = 13, - CPUHP_MM_VMSTAT_DEAD = 14, - CPUHP_SOFTIRQ_DEAD = 15, - CPUHP_NET_MVNETA_DEAD = 16, - CPUHP_CPUIDLE_DEAD = 17, - CPUHP_ARM64_FPSIMD_DEAD = 18, - CPUHP_ARM_OMAP_WAKE_DEAD = 19, - CPUHP_IRQ_POLL_DEAD = 20, - CPUHP_BLOCK_SOFTIRQ_DEAD = 21, - CPUHP_ACPI_CPUDRV_DEAD = 22, - CPUHP_S390_PFAULT_DEAD = 23, - CPUHP_BLK_MQ_DEAD = 24, - CPUHP_FS_BUFF_DEAD = 25, - CPUHP_PRINTK_DEAD = 26, - CPUHP_MM_MEMCQ_DEAD = 27, - CPUHP_PERCPU_CNT_DEAD = 28, - CPUHP_RADIX_DEAD = 29, - CPUHP_PAGE_ALLOC_DEAD = 30, - CPUHP_NET_DEV_DEAD = 31, - CPUHP_PCI_XGENE_DEAD = 32, - CPUHP_IOMMU_INTEL_DEAD = 33, - CPUHP_LUSTRE_CFS_DEAD = 34, - CPUHP_AP_ARM_CACHE_B15_RAC_DEAD = 35, - CPUHP_PADATA_DEAD = 36, - CPUHP_WORKQUEUE_PREP = 37, - CPUHP_POWER_NUMA_PREPARE = 38, - CPUHP_HRTIMERS_PREPARE = 39, - CPUHP_PROFILE_PREPARE = 40, - CPUHP_X2APIC_PREPARE = 41, - CPUHP_SMPCFD_PREPARE = 42, - CPUHP_RELAY_PREPARE = 43, - CPUHP_SLAB_PREPARE = 44, - CPUHP_MD_RAID5_PREPARE = 45, - CPUHP_RCUTREE_PREP = 46, - CPUHP_CPUIDLE_COUPLED_PREPARE = 47, - CPUHP_POWERPC_PMAC_PREPARE = 48, - CPUHP_POWERPC_MMU_CTX_PREPARE = 49, - CPUHP_XEN_PREPARE = 50, - CPUHP_XEN_EVTCHN_PREPARE = 51, - CPUHP_ARM_SHMOBILE_SCU_PREPARE = 52, - CPUHP_SH_SH3X_PREPARE = 53, - CPUHP_NET_FLOW_PREPARE = 54, - CPUHP_TOPOLOGY_PREPARE = 55, - CPUHP_NET_IUCV_PREPARE = 56, - CPUHP_ARM_BL_PREPARE = 57, - CPUHP_TRACE_RB_PREPARE = 58, - CPUHP_MM_ZS_PREPARE = 59, - CPUHP_MM_ZSWP_MEM_PREPARE = 60, - CPUHP_MM_ZSWP_POOL_PREPARE = 61, - CPUHP_KVM_PPC_BOOK3S_PREPARE = 62, - CPUHP_ZCOMP_PREPARE = 63, - CPUHP_TIMERS_PREPARE = 64, - CPUHP_MIPS_SOC_PREPARE = 65, - CPUHP_BP_PREPARE_DYN = 66, - CPUHP_BP_PREPARE_DYN_END = 86, - CPUHP_BRINGUP_CPU = 87, - CPUHP_AP_IDLE_DEAD = 88, - CPUHP_AP_OFFLINE = 89, - CPUHP_AP_SCHED_STARTING = 90, - CPUHP_AP_RCUTREE_DYING = 91, - CPUHP_AP_CPU_PM_STARTING = 92, - CPUHP_AP_IRQ_GIC_STARTING = 93, - CPUHP_AP_IRQ_HIP04_STARTING = 94, - CPUHP_AP_IRQ_ARMADA_XP_STARTING = 95, - CPUHP_AP_IRQ_BCM2836_STARTING = 96, - CPUHP_AP_IRQ_MIPS_GIC_STARTING = 97, - CPUHP_AP_IRQ_RISCV_STARTING = 98, - CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING = 99, - CPUHP_AP_ARM_MVEBU_COHERENCY = 100, - CPUHP_AP_MICROCODE_LOADER = 101, - CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING = 102, - CPUHP_AP_PERF_X86_STARTING = 103, - CPUHP_AP_PERF_X86_AMD_IBS_STARTING = 104, - CPUHP_AP_PERF_X86_CQM_STARTING = 105, - CPUHP_AP_PERF_X86_CSTATE_STARTING = 106, - CPUHP_AP_PERF_XTENSA_STARTING = 107, - CPUHP_AP_MIPS_OP_LOONGSON3_STARTING = 108, - CPUHP_AP_ARM_SDEI_STARTING = 109, - CPUHP_AP_ARM_VFP_STARTING = 110, - CPUHP_AP_ARM64_DEBUG_MONITORS_STARTING = 111, - CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING = 112, - CPUHP_AP_PERF_ARM_ACPI_STARTING = 113, - CPUHP_AP_PERF_ARM_STARTING = 114, - CPUHP_AP_ARM_L2X0_STARTING = 115, - CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING = 116, - CPUHP_AP_ARM_ARCH_TIMER_STARTING = 117, - CPUHP_AP_ARM_GLOBAL_TIMER_STARTING = 118, - CPUHP_AP_JCORE_TIMER_STARTING = 119, - CPUHP_AP_ARM_TWD_STARTING = 120, - CPUHP_AP_QCOM_TIMER_STARTING = 121, - CPUHP_AP_TEGRA_TIMER_STARTING = 122, - CPUHP_AP_ARMADA_TIMER_STARTING = 123, - CPUHP_AP_MARCO_TIMER_STARTING = 124, - CPUHP_AP_MIPS_GIC_TIMER_STARTING = 125, - CPUHP_AP_ARC_TIMER_STARTING = 126, - CPUHP_AP_RISCV_TIMER_STARTING = 127, - CPUHP_AP_CLINT_TIMER_STARTING = 128, - CPUHP_AP_CSKY_TIMER_STARTING = 129, - CPUHP_AP_TI_GP_TIMER_STARTING = 130, - CPUHP_AP_HYPERV_TIMER_STARTING = 131, - CPUHP_AP_KVM_STARTING = 132, - CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING = 133, - CPUHP_AP_KVM_ARM_VGIC_STARTING = 134, - CPUHP_AP_KVM_ARM_TIMER_STARTING = 135, - CPUHP_AP_DUMMY_TIMER_STARTING = 136, - CPUHP_AP_ARM_XEN_STARTING = 137, - CPUHP_AP_ARM_CORESIGHT_STARTING = 138, - CPUHP_AP_ARM_CORESIGHT_CTI_STARTING = 139, - CPUHP_AP_ARM64_ISNDEP_STARTING = 140, - CPUHP_AP_SMPCFD_DYING = 141, - CPUHP_AP_X86_TBOOT_DYING = 142, - CPUHP_AP_ARM_CACHE_B15_RAC_DYING = 143, - CPUHP_AP_ONLINE = 144, - CPUHP_TEARDOWN_CPU = 145, - CPUHP_AP_ONLINE_IDLE = 146, - CPUHP_AP_SMPBOOT_THREADS = 147, - CPUHP_AP_X86_VDSO_VMA_ONLINE = 148, - CPUHP_AP_IRQ_AFFINITY_ONLINE = 149, - CPUHP_AP_BLK_MQ_ONLINE = 150, - CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS = 151, - CPUHP_AP_X86_INTEL_EPB_ONLINE = 152, - CPUHP_AP_PERF_ONLINE = 153, - CPUHP_AP_PERF_X86_ONLINE = 154, - CPUHP_AP_PERF_X86_UNCORE_ONLINE = 155, - CPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE = 156, - CPUHP_AP_PERF_X86_AMD_POWER_ONLINE = 157, - CPUHP_AP_PERF_X86_RAPL_ONLINE = 158, - CPUHP_AP_PERF_X86_CQM_ONLINE = 159, - CPUHP_AP_PERF_X86_CSTATE_ONLINE = 160, - CPUHP_AP_PERF_S390_CF_ONLINE = 161, - CPUHP_AP_PERF_S390_SF_ONLINE = 162, - CPUHP_AP_PERF_ARM_CCI_ONLINE = 163, - CPUHP_AP_PERF_ARM_CCN_ONLINE = 164, - CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE = 165, - CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE = 166, - CPUHP_AP_PERF_ARM_HISI_L3_ONLINE = 167, - CPUHP_AP_PERF_ARM_L2X0_ONLINE = 168, - CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE = 169, - CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE = 170, - CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE = 171, - CPUHP_AP_PERF_ARM_CAVIUM_TX2_UNCORE_ONLINE = 172, - CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE = 173, - CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE = 174, - CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE = 175, - CPUHP_AP_PERF_POWERPC_TRACE_IMC_ONLINE = 176, - CPUHP_AP_PERF_POWERPC_HV_24x7_ONLINE = 177, - CPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE = 178, - CPUHP_AP_WATCHDOG_ONLINE = 179, - CPUHP_AP_WORKQUEUE_ONLINE = 180, - CPUHP_AP_RCUTREE_ONLINE = 181, - CPUHP_AP_BASE_CACHEINFO_ONLINE = 182, - CPUHP_AP_ONLINE_DYN = 183, - CPUHP_AP_ONLINE_DYN_END = 213, - CPUHP_AP_X86_HPET_ONLINE = 214, - CPUHP_AP_X86_KVM_CLK_ONLINE = 215, - CPUHP_AP_ACTIVE = 216, - CPUHP_ONLINE = 217, -}; - -typedef void percpu_ref_func_t(struct percpu_ref *); - -struct percpu_ref_data { - atomic_long_t count; - percpu_ref_func_t *release; - percpu_ref_func_t *confirm_switch; - bool force_atomic: 1; - bool allow_reinit: 1; - struct callback_head rcu; - struct percpu_ref *ref; -}; - -struct dev_pagemap_ops { - void (*page_free)(struct page *); - void (*kill)(struct dev_pagemap *); - void (*cleanup)(struct dev_pagemap *); - vm_fault_t (*migrate_to_ram)(struct vm_fault *); -}; - -enum vm_event_item { - PGPGIN = 0, - PGPGOUT = 1, - PSWPIN = 2, - PSWPOUT = 3, - PGALLOC_DMA = 4, - PGALLOC_DMA32 = 5, - PGALLOC_NORMAL = 6, - PGALLOC_MOVABLE = 7, - ALLOCSTALL_DMA = 8, - ALLOCSTALL_DMA32 = 9, - ALLOCSTALL_NORMAL = 10, - ALLOCSTALL_MOVABLE = 11, - PGSCAN_SKIP_DMA = 12, - PGSCAN_SKIP_DMA32 = 13, - PGSCAN_SKIP_NORMAL = 14, - PGSCAN_SKIP_MOVABLE = 15, - PGFREE = 16, - PGACTIVATE = 17, - PGDEACTIVATE = 18, - PGLAZYFREE = 19, - PGFAULT = 20, - PGMAJFAULT = 21, - PGLAZYFREED = 22, - PGREFILL = 23, - PGREUSE = 24, - PGSTEAL_KSWAPD = 25, - PGSTEAL_DIRECT = 26, - PGSCAN_KSWAPD = 27, - PGSCAN_DIRECT = 28, - PGSCAN_DIRECT_THROTTLE = 29, - PGSCAN_ANON = 30, - PGSCAN_FILE = 31, - PGSTEAL_ANON = 32, - PGSTEAL_FILE = 33, - PGINODESTEAL = 34, - SLABS_SCANNED = 35, - KSWAPD_INODESTEAL = 36, - KSWAPD_LOW_WMARK_HIT_QUICKLY = 37, - KSWAPD_HIGH_WMARK_HIT_QUICKLY = 38, - PAGEOUTRUN = 39, - PGROTATED = 40, - DROP_PAGECACHE = 41, - DROP_SLAB = 42, - OOM_KILL = 43, - PGMIGRATE_SUCCESS = 44, - PGMIGRATE_FAIL = 45, - THP_MIGRATION_SUCCESS = 46, - THP_MIGRATION_FAIL = 47, - THP_MIGRATION_SPLIT = 48, - COMPACTMIGRATE_SCANNED = 49, - COMPACTFREE_SCANNED = 50, - COMPACTISOLATED = 51, - COMPACTSTALL = 52, - COMPACTFAIL = 53, - COMPACTSUCCESS = 54, - KCOMPACTD_WAKE = 55, - KCOMPACTD_MIGRATE_SCANNED = 56, - KCOMPACTD_FREE_SCANNED = 57, - UNEVICTABLE_PGCULLED = 58, - UNEVICTABLE_PGSCANNED = 59, - UNEVICTABLE_PGRESCUED = 60, - UNEVICTABLE_PGMLOCKED = 61, - UNEVICTABLE_PGMUNLOCKED = 62, - UNEVICTABLE_PGCLEARED = 63, - UNEVICTABLE_PGSTRANDED = 64, - SWAP_RA = 65, - SWAP_RA_HIT = 66, - NR_VM_EVENT_ITEMS = 67, -}; - -struct seq_operations { - void * (*start)(struct seq_file *, loff_t *); - void (*stop)(struct seq_file *, void *); - void * (*next)(struct seq_file *, void *, loff_t *); - int (*show)(struct seq_file *, void *); -}; - -struct ring_buffer_event { - u32 type_len: 5; - u32 time_delta: 27; - u32 array[0]; -}; - -struct seq_buf { - char *buffer; - size_t size; - size_t len; - loff_t readpos; -}; - -struct trace_seq { - char buffer[4096]; - struct seq_buf seq; - int full; -}; - -enum perf_sw_ids { - PERF_COUNT_SW_CPU_CLOCK = 0, - PERF_COUNT_SW_TASK_CLOCK = 1, - PERF_COUNT_SW_PAGE_FAULTS = 2, - PERF_COUNT_SW_CONTEXT_SWITCHES = 3, - PERF_COUNT_SW_CPU_MIGRATIONS = 4, - PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, - PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, - PERF_COUNT_SW_ALIGNMENT_FAULTS = 7, - PERF_COUNT_SW_EMULATION_FAULTS = 8, - PERF_COUNT_SW_DUMMY = 9, - PERF_COUNT_SW_BPF_OUTPUT = 10, - PERF_COUNT_SW_MAX = 11, -}; - -union perf_mem_data_src { - __u64 val; - struct { - __u64 mem_op: 5; - __u64 mem_lvl: 14; - __u64 mem_snoop: 5; - __u64 mem_lock: 2; - __u64 mem_dtlb: 7; - __u64 mem_lvl_num: 4; - __u64 mem_remote: 1; - __u64 mem_snoopx: 2; - __u64 mem_rsvd: 24; - }; -}; - -struct perf_branch_entry { - __u64 from; - __u64 to; - __u64 mispred: 1; - __u64 predicted: 1; - __u64 in_tx: 1; - __u64 abort: 1; - __u64 cycles: 16; - __u64 type: 4; - __u64 reserved: 40; -}; - -struct new_utsname { - char sysname[65]; - char nodename[65]; - char release[65]; - char version[65]; - char machine[65]; - char domainname[65]; -}; - -struct uts_namespace { - struct kref kref; - struct new_utsname name; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct ns_common ns; -}; - -struct cgroup_namespace { - refcount_t count; - struct ns_common ns; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct css_set *root_cset; -}; - -struct nsset { - unsigned int flags; - struct nsproxy *nsproxy; - struct fs_struct *fs; - const struct cred *cred; -}; - -struct proc_ns_operations { - const char *name; - const char *real_ns_name; - int type; - struct ns_common * (*get)(struct task_struct *); - void (*put)(struct ns_common *); - int (*install)(struct nsset *, struct ns_common *); - struct user_namespace * (*owner)(struct ns_common *); - struct ns_common * (*get_parent)(struct ns_common *); -}; - -struct ucounts { - struct hlist_node node; - struct user_namespace *ns; - kuid_t uid; - int count; - atomic_t ucount[10]; -}; - -struct iovec { - void *iov_base; - __kernel_size_t iov_len; -}; - -struct kvec { - void *iov_base; - size_t iov_len; -}; - -struct perf_regs { - __u64 abi; - struct pt_regs *regs; -}; - -struct u64_stats_sync {}; - -struct bpf_cgroup_storage_key { - __u64 cgroup_inode_id; - __u32 attach_type; -}; - -struct bpf_cgroup_storage; - -struct bpf_prog_array_item { - struct bpf_prog *prog; - struct bpf_cgroup_storage *cgroup_storage[2]; -}; - -struct bpf_storage_buffer; - -struct bpf_cgroup_storage_map; - -struct bpf_cgroup_storage { - union { - struct bpf_storage_buffer *buf; - void *percpu_buf; - }; - struct bpf_cgroup_storage_map *map; - struct bpf_cgroup_storage_key key; - struct list_head list_map; - struct list_head list_cg; - struct rb_node node; - struct callback_head rcu; -}; - -struct bpf_prog_array { - struct callback_head rcu; - struct bpf_prog_array_item items[0]; -}; - -struct bpf_storage_buffer { - struct callback_head rcu; - char data[0]; -}; - -struct cgroup_taskset; - -struct cftype; - -struct cgroup_subsys { - struct cgroup_subsys_state * (*css_alloc)(struct cgroup_subsys_state *); - int (*css_online)(struct cgroup_subsys_state *); - void (*css_offline)(struct cgroup_subsys_state *); - void (*css_released)(struct cgroup_subsys_state *); - void (*css_free)(struct cgroup_subsys_state *); - void (*css_reset)(struct cgroup_subsys_state *); - void (*css_rstat_flush)(struct cgroup_subsys_state *, int); - int (*css_extra_stat_show)(struct seq_file *, struct cgroup_subsys_state *); - int (*can_attach)(struct cgroup_taskset *); - void (*cancel_attach)(struct cgroup_taskset *); - void (*attach)(struct cgroup_taskset *); - void (*post_attach)(); - int (*can_fork)(struct task_struct *, struct css_set *); - void (*cancel_fork)(struct task_struct *, struct css_set *); - void (*fork)(struct task_struct *); - void (*exit)(struct task_struct *); - void (*release)(struct task_struct *); - void (*bind)(struct cgroup_subsys_state *); - bool early_init: 1; - bool implicit_on_dfl: 1; - bool threaded: 1; - bool broken_hierarchy: 1; - bool warned_broken_hierarchy: 1; - int id; - const char *name; - const char *legacy_name; - struct cgroup_root *root; - struct idr css_idr; - struct list_head cfts; - struct cftype *dfl_cftypes; - struct cftype *legacy_cftypes; - unsigned int depends_on; -}; - -struct cgroup_rstat_cpu { - struct u64_stats_sync bsync; - struct cgroup_base_stat bstat; - struct cgroup_base_stat last_bstat; - struct cgroup *updated_children; - struct cgroup *updated_next; -}; - -struct cgroup_root { - struct kernfs_root *kf_root; - unsigned int subsys_mask; - int hierarchy_id; - struct cgroup cgrp; - u64 cgrp_ancestor_id_storage; - atomic_t nr_cgrps; - struct list_head root_list; - unsigned int flags; - char release_agent_path[4096]; - char name[64]; -}; - -struct cftype { - char name[64]; - long unsigned int private; - size_t max_write_len; - unsigned int flags; - unsigned int file_offset; - struct cgroup_subsys *ss; - struct list_head node; - struct kernfs_ops *kf_ops; - int (*open)(struct kernfs_open_file *); - void (*release)(struct kernfs_open_file *); - u64 (*read_u64)(struct cgroup_subsys_state *, struct cftype *); - s64 (*read_s64)(struct cgroup_subsys_state *, struct cftype *); - int (*seq_show)(struct seq_file *, void *); - void * (*seq_start)(struct seq_file *, loff_t *); - void * (*seq_next)(struct seq_file *, void *, loff_t *); - void (*seq_stop)(struct seq_file *, void *); - int (*write_u64)(struct cgroup_subsys_state *, struct cftype *, u64); - int (*write_s64)(struct cgroup_subsys_state *, struct cftype *, s64); - ssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t); - __poll_t (*poll)(struct kernfs_open_file *, struct poll_table_struct *); -}; - -enum kmalloc_cache_type { - KMALLOC_NORMAL = 0, - KMALLOC_RECLAIM = 1, - KMALLOC_DMA = 2, - NR_KMALLOC_TYPES = 3, -}; - -struct perf_callchain_entry { - __u64 nr; - __u64 ip[0]; -}; - -typedef long unsigned int (*perf_copy_f)(void *, const void *, long unsigned int, long unsigned int); - -struct perf_raw_frag { - union { - struct perf_raw_frag *next; - long unsigned int pad; - }; - perf_copy_f copy; - void *data; - u32 size; -} __attribute__((packed)); - -struct perf_raw_record { - struct perf_raw_frag frag; - u32 size; -}; - -struct perf_branch_stack { - __u64 nr; - __u64 hw_idx; - struct perf_branch_entry entries[0]; -}; - -struct perf_cpu_context; - -struct perf_output_handle; - -struct pmu { - struct list_head entry; - struct module *module; - struct device *dev; - const struct attribute_group **attr_groups; - const struct attribute_group **attr_update; - const char *name; - int type; - int capabilities; - int *pmu_disable_count; - struct perf_cpu_context *pmu_cpu_context; - atomic_t exclusive_cnt; - int task_ctx_nr; - int hrtimer_interval_ms; - unsigned int nr_addr_filters; - void (*pmu_enable)(struct pmu *); - void (*pmu_disable)(struct pmu *); - int (*event_init)(struct perf_event *); - void (*event_mapped)(struct perf_event *, struct mm_struct *); - void (*event_unmapped)(struct perf_event *, struct mm_struct *); - int (*add)(struct perf_event *, int); - void (*del)(struct perf_event *, int); - void (*start)(struct perf_event *, int); - void (*stop)(struct perf_event *, int); - void (*read)(struct perf_event *); - void (*start_txn)(struct pmu *, unsigned int); - int (*commit_txn)(struct pmu *); - void (*cancel_txn)(struct pmu *); - int (*event_idx)(struct perf_event *); - void (*sched_task)(struct perf_event_context *, bool); - struct kmem_cache *task_ctx_cache; - void (*swap_task_ctx)(struct perf_event_context *, struct perf_event_context *); - void * (*setup_aux)(struct perf_event *, void **, int, bool); - void (*free_aux)(void *); - long int (*snapshot_aux)(struct perf_event *, struct perf_output_handle *, long unsigned int); - int (*addr_filters_validate)(struct list_head *); - void (*addr_filters_sync)(struct perf_event *); - int (*aux_output_match)(struct perf_event *); - int (*filter_match)(struct perf_event *); - int (*check_period)(struct perf_event *, u64); -}; - -struct perf_cpu_context { - struct perf_event_context ctx; - struct perf_event_context *task_ctx; - int active_oncpu; - int exclusive; - raw_spinlock_t hrtimer_lock; - struct hrtimer hrtimer; - ktime_t hrtimer_interval; - unsigned int hrtimer_active; - struct perf_cgroup *cgrp; - struct list_head cgrp_cpuctx_entry; - struct list_head sched_cb_entry; - int sched_cb_usage; - int online; - int heap_size; - struct perf_event **heap; - struct perf_event *heap_default[2]; -}; - -struct perf_output_handle { - struct perf_event *event; - struct perf_buffer *rb; - long unsigned int wakeup; - long unsigned int size; - u64 aux_flags; - union { - void *addr; - long unsigned int head; - }; - int page; -}; - -struct perf_addr_filter_range { - long unsigned int start; - long unsigned int size; -}; - -struct perf_sample_data { - u64 addr; - struct perf_raw_record *raw; - struct perf_branch_stack *br_stack; - u64 period; - u64 weight; - u64 txn; - union perf_mem_data_src data_src; - u64 type; - u64 ip; - struct { - u32 pid; - u32 tid; - } tid_entry; - u64 time; - u64 id; - u64 stream_id; - struct { - u32 cpu; - u32 reserved; - } cpu_entry; - struct perf_callchain_entry *callchain; - u64 aux_size; - struct perf_regs regs_user; - struct perf_regs regs_intr; - u64 stack_user_size; - u64 phys_addr; - u64 cgroup; - long: 64; -}; - -struct perf_cgroup_info; - -struct perf_cgroup { - struct cgroup_subsys_state css; - struct perf_cgroup_info *info; -}; - -struct perf_cgroup_info { - u64 time; - u64 timestamp; -}; - -struct trace_entry { - short unsigned int type; - unsigned char flags; - unsigned char preempt_count; - int pid; -}; - -struct trace_array; - -struct tracer; - -struct array_buffer; - -struct ring_buffer_iter; - -struct trace_iterator { - struct trace_array *tr; - struct tracer *trace; - struct array_buffer *array_buffer; - void *private; - int cpu_file; - struct mutex mutex; - struct ring_buffer_iter **buffer_iter; - long unsigned int iter_flags; - void *temp; - unsigned int temp_size; - struct trace_seq tmp_seq; - cpumask_var_t started; - bool snapshot; - struct trace_seq seq; - struct trace_entry *ent; - long unsigned int lost_events; - int leftover; - int ent_size; - int cpu; - u64 ts; - loff_t pos; - long int idx; -}; - -enum print_line_t { - TRACE_TYPE_PARTIAL_LINE = 0, - TRACE_TYPE_HANDLED = 1, - TRACE_TYPE_UNHANDLED = 2, - TRACE_TYPE_NO_CONSUME = 3, -}; - -typedef enum print_line_t (*trace_print_func)(struct trace_iterator *, int, struct trace_event *); - -struct trace_event_functions { - trace_print_func trace; - trace_print_func raw; - trace_print_func hex; - trace_print_func binary; -}; - -enum trace_reg { - TRACE_REG_REGISTER = 0, - TRACE_REG_UNREGISTER = 1, - TRACE_REG_PERF_REGISTER = 2, - TRACE_REG_PERF_UNREGISTER = 3, - TRACE_REG_PERF_OPEN = 4, - TRACE_REG_PERF_CLOSE = 5, - TRACE_REG_PERF_ADD = 6, - TRACE_REG_PERF_DEL = 7, -}; - -struct trace_event_fields { - const char *type; - union { - struct { - const char *name; - const int size; - const int align; - const int is_signed; - const int filter_type; - }; - int (*define_fields)(struct trace_event_call *); - }; -}; - -struct trace_event_class { - const char *system; - void *probe; - void *perf_probe; - int (*reg)(struct trace_event_call *, enum trace_reg, void *); - struct trace_event_fields *fields_array; - struct list_head * (*get_fields)(struct trace_event_call *); - struct list_head fields; - int (*raw_init)(struct trace_event_call *); -}; - -struct trace_buffer; - -struct trace_event_file; - -struct trace_event_buffer { - struct trace_buffer *buffer; - struct ring_buffer_event *event; - struct trace_event_file *trace_file; - void *entry; - long unsigned int flags; - int pc; - struct pt_regs *regs; -}; - -struct trace_subsystem_dir; - -struct trace_event_file { - struct list_head list; - struct trace_event_call *event_call; - struct event_filter *filter; - struct dentry *dir; - struct trace_array *tr; - struct trace_subsystem_dir *system; - struct list_head triggers; - long unsigned int flags; - atomic_t sm_ref; - atomic_t tm_ref; -}; - -enum { - TRACE_EVENT_FL_FILTERED_BIT = 0, - TRACE_EVENT_FL_CAP_ANY_BIT = 1, - TRACE_EVENT_FL_NO_SET_FILTER_BIT = 2, - TRACE_EVENT_FL_IGNORE_ENABLE_BIT = 3, - TRACE_EVENT_FL_TRACEPOINT_BIT = 4, - TRACE_EVENT_FL_KPROBE_BIT = 5, - TRACE_EVENT_FL_UPROBE_BIT = 6, -}; - -enum { - TRACE_EVENT_FL_FILTERED = 1, - TRACE_EVENT_FL_CAP_ANY = 2, - TRACE_EVENT_FL_NO_SET_FILTER = 4, - TRACE_EVENT_FL_IGNORE_ENABLE = 8, - TRACE_EVENT_FL_TRACEPOINT = 16, - TRACE_EVENT_FL_KPROBE = 32, - TRACE_EVENT_FL_UPROBE = 64, -}; - -enum { - EVENT_FILE_FL_ENABLED_BIT = 0, - EVENT_FILE_FL_RECORDED_CMD_BIT = 1, - EVENT_FILE_FL_RECORDED_TGID_BIT = 2, - EVENT_FILE_FL_FILTERED_BIT = 3, - EVENT_FILE_FL_NO_SET_FILTER_BIT = 4, - EVENT_FILE_FL_SOFT_MODE_BIT = 5, - EVENT_FILE_FL_SOFT_DISABLED_BIT = 6, - EVENT_FILE_FL_TRIGGER_MODE_BIT = 7, - EVENT_FILE_FL_TRIGGER_COND_BIT = 8, - EVENT_FILE_FL_PID_FILTER_BIT = 9, - EVENT_FILE_FL_WAS_ENABLED_BIT = 10, -}; - -enum { - EVENT_FILE_FL_ENABLED = 1, - EVENT_FILE_FL_RECORDED_CMD = 2, - EVENT_FILE_FL_RECORDED_TGID = 4, - EVENT_FILE_FL_FILTERED = 8, - EVENT_FILE_FL_NO_SET_FILTER = 16, - EVENT_FILE_FL_SOFT_MODE = 32, - EVENT_FILE_FL_SOFT_DISABLED = 64, - EVENT_FILE_FL_TRIGGER_MODE = 128, - EVENT_FILE_FL_TRIGGER_COND = 256, - EVENT_FILE_FL_PID_FILTER = 512, - EVENT_FILE_FL_WAS_ENABLED = 1024, -}; - -enum { - FILTER_OTHER = 0, - FILTER_STATIC_STRING = 1, - FILTER_DYN_STRING = 2, - FILTER_PTR_STRING = 3, - FILTER_TRACE_FN = 4, - FILTER_COMM = 5, - FILTER_CPU = 6, -}; - -struct fwnode_reference_args; - -struct fwnode_endpoint; - -struct fwnode_operations { - struct fwnode_handle * (*get)(struct fwnode_handle *); - void (*put)(struct fwnode_handle *); - bool (*device_is_available)(const struct fwnode_handle *); - const void * (*device_get_match_data)(const struct fwnode_handle *, const struct device *); - bool (*property_present)(const struct fwnode_handle *, const char *); - int (*property_read_int_array)(const struct fwnode_handle *, const char *, unsigned int, void *, size_t); - int (*property_read_string_array)(const struct fwnode_handle *, const char *, const char **, size_t); - const char * (*get_name)(const struct fwnode_handle *); - const char * (*get_name_prefix)(const struct fwnode_handle *); - struct fwnode_handle * (*get_parent)(const struct fwnode_handle *); - struct fwnode_handle * (*get_next_child_node)(const struct fwnode_handle *, struct fwnode_handle *); - struct fwnode_handle * (*get_named_child_node)(const struct fwnode_handle *, const char *); - int (*get_reference_args)(const struct fwnode_handle *, const char *, const char *, unsigned int, unsigned int, struct fwnode_reference_args *); - struct fwnode_handle * (*graph_get_next_endpoint)(const struct fwnode_handle *, struct fwnode_handle *); - struct fwnode_handle * (*graph_get_remote_endpoint)(const struct fwnode_handle *); - struct fwnode_handle * (*graph_get_port_parent)(struct fwnode_handle *); - int (*graph_parse_endpoint)(const struct fwnode_handle *, struct fwnode_endpoint *); - int (*add_links)(const struct fwnode_handle *, struct device *); -}; - -struct fwnode_endpoint { - unsigned int port; - unsigned int id; - const struct fwnode_handle *local_fwnode; -}; - -struct fwnode_reference_args { - struct fwnode_handle *fwnode; - unsigned int nargs; - u64 args[8]; -}; - -struct property { - char *name; - int length; - void *value; - struct property *next; - long unsigned int _flags; - struct bin_attribute attr; -}; - -struct irq_fwspec { - struct fwnode_handle *fwnode; - int param_count; - u32 param[16]; -}; - -struct irq_data; - -struct irq_domain_ops { - int (*match)(struct irq_domain *, struct device_node *, enum irq_domain_bus_token); - int (*select)(struct irq_domain *, struct irq_fwspec *, enum irq_domain_bus_token); - int (*map)(struct irq_domain *, unsigned int, irq_hw_number_t); - void (*unmap)(struct irq_domain *, unsigned int); - int (*xlate)(struct irq_domain *, struct device_node *, const u32 *, unsigned int, long unsigned int *, unsigned int *); - int (*alloc)(struct irq_domain *, unsigned int, unsigned int, void *); - void (*free)(struct irq_domain *, unsigned int, unsigned int); - int (*activate)(struct irq_domain *, struct irq_data *, bool); - void (*deactivate)(struct irq_domain *, struct irq_data *); - int (*translate)(struct irq_domain *, struct irq_fwspec *, long unsigned int *, unsigned int *); - void (*debug_show)(struct seq_file *, struct irq_domain *, struct irq_data *, int); -}; - -enum wb_stat_item { - WB_RECLAIMABLE = 0, - WB_WRITEBACK = 1, - WB_DIRTIED = 2, - WB_WRITTEN = 3, - NR_WB_STAT_ITEMS = 4, -}; - -struct disk_stats; - -struct partition_meta_info; - -struct hd_struct { - sector_t start_sect; - sector_t nr_sects; - long unsigned int stamp; - struct disk_stats *dkstats; - struct percpu_ref ref; - struct device __dev; - struct kobject *holder_dir; - int policy; - int partno; - struct partition_meta_info *info; - struct rcu_work rcu_work; -}; - -struct disk_part_tbl; - -struct block_device_operations; - -struct timer_rand_state; - -struct disk_events; - -struct cdrom_device_info; - -struct badblocks; - -struct gendisk { - int major; - int first_minor; - int minors; - char disk_name[32]; - short unsigned int events; - short unsigned int event_flags; - struct disk_part_tbl *part_tbl; - struct hd_struct part0; - const struct block_device_operations *fops; - struct request_queue *queue; - void *private_data; - int flags; - long unsigned int state; - struct rw_semaphore lookup_sem; - struct kobject *slave_dir; - struct timer_rand_state *random; - atomic_t sync_io; - struct disk_events *ev; - struct cdrom_device_info *cdi; - int node_id; - struct badblocks *bb; - struct lockdep_map lockdep_map; -}; - -struct blkg_iostat { - u64 bytes[3]; - u64 ios[3]; -}; - -struct blkg_iostat_set { - struct u64_stats_sync sync; - struct blkg_iostat cur; - struct blkg_iostat last; -}; - -struct blkcg; - -struct blkg_policy_data; - -struct blkcg_gq { - struct request_queue *q; - struct list_head q_node; - struct hlist_node blkcg_node; - struct blkcg *blkcg; - struct blkcg_gq *parent; - struct percpu_ref refcnt; - bool online; - struct blkg_iostat_set *iostat_cpu; - struct blkg_iostat_set iostat; - struct blkg_policy_data *pd[5]; - spinlock_t async_bio_lock; - struct bio_list async_bios; - struct work_struct async_bio_work; - atomic_t use_delay; - atomic64_t delay_nsec; - atomic64_t delay_start; - u64 last_delay; - int last_use; - struct callback_head callback_head; -}; - -typedef unsigned int blk_qc_t; - -struct partition_meta_info { - char uuid[37]; - u8 volname[64]; -}; - -struct disk_part_tbl { - struct callback_head callback_head; - int len; - struct hd_struct *last_lookup; - struct hd_struct *part[0]; -}; - -struct blk_zone; - -typedef int (*report_zones_cb)(struct blk_zone *, unsigned int, void *); - -struct hd_geometry; - -struct pr_ops; - -struct block_device_operations { - blk_qc_t (*submit_bio)(struct bio *); - int (*open)(struct block_device *, fmode_t); - void (*release)(struct gendisk *, fmode_t); - int (*rw_page)(struct block_device *, sector_t, struct page *, unsigned int); - int (*ioctl)(struct block_device *, fmode_t, unsigned int, long unsigned int); - int (*compat_ioctl)(struct block_device *, fmode_t, unsigned int, long unsigned int); - unsigned int (*check_events)(struct gendisk *, unsigned int); - void (*unlock_native_capacity)(struct gendisk *); - int (*revalidate_disk)(struct gendisk *); - int (*getgeo)(struct block_device *, struct hd_geometry *); - void (*swap_slot_free_notify)(struct block_device *, long unsigned int); - int (*report_zones)(struct gendisk *, sector_t, unsigned int, report_zones_cb, void *); - char * (*devnode)(struct gendisk *, umode_t *); - struct module *owner; - const struct pr_ops *pr_ops; -}; - -struct sg_io_v4 { - __s32 guard; - __u32 protocol; - __u32 subprotocol; - __u32 request_len; - __u64 request; - __u64 request_tag; - __u32 request_attr; - __u32 request_priority; - __u32 request_extra; - __u32 max_response_len; - __u64 response; - __u32 dout_iovec_count; - __u32 dout_xfer_len; - __u32 din_iovec_count; - __u32 din_xfer_len; - __u64 dout_xferp; - __u64 din_xferp; - __u32 timeout; - __u32 flags; - __u64 usr_ptr; - __u32 spare_in; - __u32 driver_status; - __u32 transport_status; - __u32 device_status; - __u32 retry_delay; - __u32 info; - __u32 duration; - __u32 response_len; - __s32 din_resid; - __s32 dout_resid; - __u64 generated_tag; - __u32 spare_out; - __u32 padding; -}; - -struct bsg_ops { - int (*check_proto)(struct sg_io_v4 *); - int (*fill_hdr)(struct request *, struct sg_io_v4 *, fmode_t); - int (*complete_rq)(struct request *, struct sg_io_v4 *); - void (*free_rq)(struct request *); -}; - -typedef __u32 req_flags_t; - -typedef void rq_end_io_fn(struct request *, blk_status_t); - -enum mq_rq_state { - MQ_RQ_IDLE = 0, - MQ_RQ_IN_FLIGHT = 1, - MQ_RQ_COMPLETE = 2, -}; - -struct request { - struct request_queue *q; - struct blk_mq_ctx *mq_ctx; - struct blk_mq_hw_ctx *mq_hctx; - unsigned int cmd_flags; - req_flags_t rq_flags; - int tag; - int internal_tag; - unsigned int __data_len; - sector_t __sector; - struct bio *bio; - struct bio *biotail; - struct list_head queuelist; - union { - struct hlist_node hash; - struct list_head ipi_list; - }; - union { - struct rb_node rb_node; - struct bio_vec special_vec; - void *completion_data; - int error_count; - }; - union { - struct { - struct io_cq *icq; - void *priv[2]; - } elv; - struct { - unsigned int seq; - struct list_head list; - rq_end_io_fn *saved_end_io; - } flush; - }; - struct gendisk *rq_disk; - struct hd_struct *part; - u64 start_time_ns; - u64 io_start_time_ns; - short unsigned int stats_sectors; - short unsigned int nr_phys_segments; - short unsigned int write_hint; - short unsigned int ioprio; - enum mq_rq_state state; - refcount_t ref; - unsigned int timeout; - long unsigned int deadline; - union { - struct __call_single_data csd; - u64 fifo_time; - }; - rq_end_io_fn *end_io; - void *end_io_data; -}; - -struct blk_zone { - __u64 start; - __u64 len; - __u64 wp; - __u8 type; - __u8 cond; - __u8 non_seq; - __u8 reset; - __u8 resv[4]; - __u64 capacity; - __u8 reserved[24]; -}; - -enum elv_merge { - ELEVATOR_NO_MERGE = 0, - ELEVATOR_FRONT_MERGE = 1, - ELEVATOR_BACK_MERGE = 2, - ELEVATOR_DISCARD_MERGE = 3, -}; - -struct elevator_type; - -struct blk_mq_alloc_data; - -struct elevator_mq_ops { - int (*init_sched)(struct request_queue *, struct elevator_type *); - void (*exit_sched)(struct elevator_queue *); - int (*init_hctx)(struct blk_mq_hw_ctx *, unsigned int); - void (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int); - void (*depth_updated)(struct blk_mq_hw_ctx *); - bool (*allow_merge)(struct request_queue *, struct request *, struct bio *); - bool (*bio_merge)(struct request_queue *, struct bio *, unsigned int); - int (*request_merge)(struct request_queue *, struct request **, struct bio *); - void (*request_merged)(struct request_queue *, struct request *, enum elv_merge); - void (*requests_merged)(struct request_queue *, struct request *, struct request *); - void (*limit_depth)(unsigned int, struct blk_mq_alloc_data *); - void (*prepare_request)(struct request *); - void (*finish_request)(struct request *); - void (*insert_requests)(struct blk_mq_hw_ctx *, struct list_head *, bool); - struct request * (*dispatch_request)(struct blk_mq_hw_ctx *); - bool (*has_work)(struct blk_mq_hw_ctx *); - void (*completed_request)(struct request *, u64); - void (*requeue_request)(struct request *); - struct request * (*former_request)(struct request_queue *, struct request *); - struct request * (*next_request)(struct request_queue *, struct request *); - void (*init_icq)(struct io_cq *); - void (*exit_icq)(struct io_cq *); -}; - -struct elv_fs_entry; - -struct blk_mq_debugfs_attr; - -struct elevator_type { - struct kmem_cache *icq_cache; - struct elevator_mq_ops ops; - size_t icq_size; - size_t icq_align; - struct elv_fs_entry *elevator_attrs; - const char *elevator_name; - const char *elevator_alias; - const unsigned int elevator_features; - struct module *elevator_owner; - const struct blk_mq_debugfs_attr *queue_debugfs_attrs; - const struct blk_mq_debugfs_attr *hctx_debugfs_attrs; - char icq_cache_name[22]; - struct list_head list; -}; - -struct elevator_queue { - struct elevator_type *type; - void *elevator_data; - struct kobject kobj; - struct mutex sysfs_lock; - unsigned int registered: 1; - struct hlist_head hash[64]; -}; - -struct elv_fs_entry { - struct attribute attr; - ssize_t (*show)(struct elevator_queue *, char *); - ssize_t (*store)(struct elevator_queue *, const char *, size_t); -}; - -struct blk_mq_debugfs_attr { - const char *name; - umode_t mode; - int (*show)(void *, struct seq_file *); - ssize_t (*write)(void *, const char *, size_t, loff_t *); - const struct seq_operations *seq_ops; -}; - -enum blk_eh_timer_return { - BLK_EH_DONE = 0, - BLK_EH_RESET_TIMER = 1, -}; - -struct blk_mq_queue_data; - -struct blk_mq_ops { - blk_status_t (*queue_rq)(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *); - void (*commit_rqs)(struct blk_mq_hw_ctx *); - bool (*get_budget)(struct request_queue *); - void (*put_budget)(struct request_queue *); - enum blk_eh_timer_return (*timeout)(struct request *, bool); - int (*poll)(struct blk_mq_hw_ctx *); - void (*complete)(struct request *); - int (*init_hctx)(struct blk_mq_hw_ctx *, void *, unsigned int); - void (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int); - int (*init_request)(struct blk_mq_tag_set *, struct request *, unsigned int, unsigned int); - void (*exit_request)(struct blk_mq_tag_set *, struct request *, unsigned int); - void (*initialize_rq_fn)(struct request *); - void (*cleanup_rq)(struct request *); - bool (*busy)(struct request_queue *); - int (*map_queues)(struct blk_mq_tag_set *); - void (*show_rq)(struct seq_file *, struct request *); -}; - -enum pr_type { - PR_WRITE_EXCLUSIVE = 1, - PR_EXCLUSIVE_ACCESS = 2, - PR_WRITE_EXCLUSIVE_REG_ONLY = 3, - PR_EXCLUSIVE_ACCESS_REG_ONLY = 4, - PR_WRITE_EXCLUSIVE_ALL_REGS = 5, - PR_EXCLUSIVE_ACCESS_ALL_REGS = 6, -}; - -struct pr_ops { - int (*pr_register)(struct block_device *, u64, u64, u32); - int (*pr_reserve)(struct block_device *, u64, enum pr_type, u32); - int (*pr_release)(struct block_device *, u64, enum pr_type); - int (*pr_preempt)(struct block_device *, u64, u64, enum pr_type, bool); - int (*pr_clear)(struct block_device *, u64); -}; - -enum blkg_iostat_type { - BLKG_IOSTAT_READ = 0, - BLKG_IOSTAT_WRITE = 1, - BLKG_IOSTAT_DISCARD = 2, - BLKG_IOSTAT_NR = 3, -}; - -struct blkcg_policy_data; - -struct blkcg { - struct cgroup_subsys_state css; - spinlock_t lock; - refcount_t online_pin; - struct xarray blkg_tree; - struct blkcg_gq *blkg_hint; - struct hlist_head blkg_list; - struct blkcg_policy_data *cpd[5]; - struct list_head all_blkcgs_node; - struct list_head cgwb_list; -}; - -struct blkcg_policy_data { - struct blkcg *blkcg; - int plid; -}; - -struct blkg_policy_data { - struct blkcg_gq *blkg; - int plid; -}; - -enum memcg_stat_item { - MEMCG_SWAP = 37, - MEMCG_SOCK = 38, - MEMCG_PERCPU_B = 39, - MEMCG_NR_STAT = 40, -}; - -enum memcg_memory_event { - MEMCG_LOW = 0, - MEMCG_HIGH = 1, - MEMCG_MAX = 2, - MEMCG_OOM = 3, - MEMCG_OOM_KILL = 4, - MEMCG_SWAP_HIGH = 5, - MEMCG_SWAP_MAX = 6, - MEMCG_SWAP_FAIL = 7, - MEMCG_NR_MEMORY_EVENTS = 8, -}; - -enum mem_cgroup_events_target { - MEM_CGROUP_TARGET_THRESH = 0, - MEM_CGROUP_TARGET_SOFTLIMIT = 1, - MEM_CGROUP_NTARGETS = 2, -}; - -struct memcg_vmstats_percpu { - long int stat[40]; - long unsigned int events[67]; - long unsigned int nr_page_events; - long unsigned int targets[2]; -}; - -struct mem_cgroup_reclaim_iter { - struct mem_cgroup *position; - unsigned int generation; -}; - -struct lruvec_stat { - long int count[37]; -}; - -struct memcg_shrinker_map { - struct callback_head rcu; - long unsigned int map[0]; -}; - -struct mem_cgroup_per_node { - struct lruvec lruvec; - struct lruvec_stat *lruvec_stat_local; - struct lruvec_stat *lruvec_stat_cpu; - atomic_long_t lruvec_stat[37]; - long unsigned int lru_zone_size[20]; - struct mem_cgroup_reclaim_iter iter; - struct memcg_shrinker_map *shrinker_map; - struct rb_node tree_node; - long unsigned int usage_in_excess; - bool on_tree; - struct mem_cgroup *memcg; -}; - -struct eventfd_ctx; - -struct mem_cgroup_threshold { - struct eventfd_ctx *eventfd; - long unsigned int threshold; -}; - -struct mem_cgroup_threshold_ary { - int current_threshold; - unsigned int size; - struct mem_cgroup_threshold entries[0]; -}; - -struct percpu_cluster { - struct swap_cluster_info index; - unsigned int next; -}; - -enum fs_value_type { - fs_value_is_undefined = 0, - fs_value_is_flag = 1, - fs_value_is_string = 2, - fs_value_is_blob = 3, - fs_value_is_filename = 4, - fs_value_is_file = 5, -}; - -struct fs_parameter { - const char *key; - enum fs_value_type type: 8; - union { - char *string; - void *blob; - struct filename *name; - struct file *file; - }; - size_t size; - int dirfd; -}; - -struct fc_log { - refcount_t usage; - u8 head; - u8 tail; - u8 need_free; - struct module *owner; - char *buffer[8]; -}; - -struct fs_context_operations { - void (*free)(struct fs_context *); - int (*dup)(struct fs_context *, struct fs_context *); - int (*parse_param)(struct fs_context *, struct fs_parameter *); - int (*parse_monolithic)(struct fs_context *, void *); - int (*get_tree)(struct fs_context *); - int (*reconfigure)(struct fs_context *); -}; - -struct fs_parse_result { - bool negated; - union { - bool boolean; - int int_32; - unsigned int uint_32; - u64 uint_64; - }; -}; - -struct trace_event_raw_initcall_level { - struct trace_entry ent; - u32 __data_loc_level; - char __data[0]; -}; - -struct trace_event_raw_initcall_start { - struct trace_entry ent; - initcall_t func; - char __data[0]; -}; - -struct trace_event_raw_initcall_finish { - struct trace_entry ent; - initcall_t func; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_initcall_level { - u32 level; -}; - -struct trace_event_data_offsets_initcall_start {}; - -struct trace_event_data_offsets_initcall_finish {}; - -typedef void (*btf_trace_initcall_level)(void *, const char *); - -typedef void (*btf_trace_initcall_start)(void *, initcall_t); - -typedef void (*btf_trace_initcall_finish)(void *, initcall_t, int); - -struct blacklist_entry { - struct list_head next; - char *buf; -}; - -typedef __u32 Elf32_Word; - -struct elf32_note { - Elf32_Word n_namesz; - Elf32_Word n_descsz; - Elf32_Word n_type; -}; - -enum pcpu_fc { - PCPU_FC_AUTO = 0, - PCPU_FC_EMBED = 1, - PCPU_FC_PAGE = 2, - PCPU_FC_NR = 3, -}; - -enum { - UNAME26 = 131072, - ADDR_NO_RANDOMIZE = 262144, - FDPIC_FUNCPTRS = 524288, - MMAP_PAGE_ZERO = 1048576, - ADDR_COMPAT_LAYOUT = 2097152, - READ_IMPLIES_EXEC = 4194304, - ADDR_LIMIT_32BIT = 8388608, - SHORT_INODE = 16777216, - WHOLE_SECONDS = 33554432, - STICKY_TIMEOUTS = 67108864, - ADDR_LIMIT_3GB = 134217728, -}; - -enum hrtimer_base_type { - HRTIMER_BASE_MONOTONIC = 0, - HRTIMER_BASE_REALTIME = 1, - HRTIMER_BASE_BOOTTIME = 2, - HRTIMER_BASE_TAI = 3, - HRTIMER_BASE_MONOTONIC_SOFT = 4, - HRTIMER_BASE_REALTIME_SOFT = 5, - HRTIMER_BASE_BOOTTIME_SOFT = 6, - HRTIMER_BASE_TAI_SOFT = 7, - HRTIMER_MAX_CLOCK_BASES = 8, -}; - -enum { - MM_FILEPAGES = 0, - MM_ANONPAGES = 1, - MM_SWAPENTS = 2, - MM_SHMEMPAGES = 3, - NR_MM_COUNTERS = 4, -}; - -enum rseq_cs_flags_bit { - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, -}; - -enum perf_event_task_context { - perf_invalid_context = 4294967295, - perf_hw_context = 0, - perf_sw_context = 1, - perf_nr_task_contexts = 2, -}; - -enum rseq_event_mask_bits { - RSEQ_EVENT_PREEMPT_BIT = 0, - RSEQ_EVENT_SIGNAL_BIT = 1, - RSEQ_EVENT_MIGRATE_BIT = 2, -}; - -enum { - PROC_ROOT_INO = 1, - PROC_IPC_INIT_INO = 4026531839, - PROC_UTS_INIT_INO = 4026531838, - PROC_USER_INIT_INO = 4026531837, - PROC_PID_INIT_INO = 4026531836, - PROC_CGROUP_INIT_INO = 4026531835, - PROC_TIME_INIT_INO = 4026531834, -}; - -typedef short int __s16; - -typedef __s16 s16; - -typedef __u16 __le16; - -typedef __u16 __be16; - -typedef __u32 __be32; - -typedef __u64 __be64; - -typedef __u32 __wsum; - -typedef unsigned int slab_flags_t; - -struct llist_head { - struct llist_node *first; -}; - -struct rhash_head { - struct rhash_head *next; -}; - -struct rhashtable; - -struct rhashtable_compare_arg { - struct rhashtable *ht; - const void *key; -}; - -typedef u32 (*rht_hashfn_t)(const void *, u32, u32); - -typedef u32 (*rht_obj_hashfn_t)(const void *, u32, u32); - -typedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *, const void *); - -struct rhashtable_params { - u16 nelem_hint; - u16 key_len; - u16 key_offset; - u16 head_offset; - unsigned int max_size; - u16 min_size; - bool automatic_shrinking; - rht_hashfn_t hashfn; - rht_obj_hashfn_t obj_hashfn; - rht_obj_cmpfn_t obj_cmpfn; -}; - -struct bucket_table; - -struct rhashtable { - struct bucket_table *tbl; - unsigned int key_len; - unsigned int max_elems; - struct rhashtable_params p; - bool rhlist; - struct work_struct run_work; - struct mutex mutex; - spinlock_t lock; - atomic_t nelems; -}; - -struct fs_struct { - int users; - spinlock_t lock; - seqcount_spinlock_t seq; - int umask; - int in_exec; - struct path root; - struct path pwd; -}; - -struct pipe_buffer; - -struct pipe_inode_info { - struct mutex mutex; - wait_queue_head_t rd_wait; - wait_queue_head_t wr_wait; - unsigned int head; - unsigned int tail; - unsigned int max_usage; - unsigned int ring_size; - unsigned int nr_accounted; - unsigned int readers; - unsigned int writers; - unsigned int files; - unsigned int r_counter; - unsigned int w_counter; - unsigned int poll_usage; - struct page *tmp_page; - struct fasync_struct *fasync_readers; - struct fasync_struct *fasync_writers; - struct pipe_buffer *bufs; - struct user_struct *user; -}; - -struct notifier_block; - -typedef int (*notifier_fn_t)(struct notifier_block *, long unsigned int, void *); - -struct notifier_block { - notifier_fn_t notifier_call; - struct notifier_block *next; - int priority; -}; - -struct blocking_notifier_head { - struct rw_semaphore rwsem; - struct notifier_block *head; -}; - -struct raw_notifier_head { - struct notifier_block *head; -}; - -struct vfsmount { - struct dentry *mnt_root; - struct super_block *mnt_sb; - int mnt_flags; -}; - -struct ld_semaphore { - atomic_long_t count; - raw_spinlock_t wait_lock; - unsigned int wait_readers; - struct list_head read_wait; - struct list_head write_wait; -}; - -typedef unsigned int tcflag_t; - -typedef unsigned char cc_t; - -typedef unsigned int speed_t; - -struct ktermios { - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[19]; - speed_t c_ispeed; - speed_t c_ospeed; -}; - -struct winsize { - short unsigned int ws_row; - short unsigned int ws_col; - short unsigned int ws_xpixel; - short unsigned int ws_ypixel; -}; - -struct tty_driver; - -struct tty_operations; - -struct tty_ldisc; - -struct tty_port; - -struct tty_struct { - int magic; - struct kref kref; - struct device *dev; - struct tty_driver *driver; - const struct tty_operations *ops; - int index; - struct ld_semaphore ldisc_sem; - struct tty_ldisc *ldisc; - struct mutex atomic_write_lock; - struct mutex legacy_mutex; - struct mutex throttle_mutex; - struct rw_semaphore termios_rwsem; - struct mutex winsize_mutex; - spinlock_t ctrl_lock; - spinlock_t flow_lock; - struct ktermios termios; - struct ktermios termios_locked; - char name[64]; - struct pid *pgrp; - struct pid *session; - long unsigned int flags; - int count; - struct winsize winsize; - long unsigned int stopped: 1; - long unsigned int flow_stopped: 1; - int: 30; - long unsigned int unused: 62; - int hw_stopped; - long unsigned int ctrl_status: 8; - long unsigned int packet: 1; - int: 23; - long unsigned int unused_ctrl: 55; - unsigned int receive_room; - int flow_change; - struct tty_struct *link; - struct fasync_struct *fasync; - wait_queue_head_t write_wait; - wait_queue_head_t read_wait; - struct work_struct hangup_work; - void *disc_data; - void *driver_data; - spinlock_t files_lock; - struct list_head tty_files; - int closing; - unsigned char *write_buf; - int write_cnt; - struct work_struct SAK_work; - struct tty_port *port; -}; - -typedef struct { - size_t written; - size_t count; - union { - char *buf; - void *data; - } arg; - int error; -} read_descriptor_t; - -struct posix_acl_entry { - short int e_tag; - short unsigned int e_perm; - union { - kuid_t e_uid; - kgid_t e_gid; - }; -}; - -struct posix_acl { - refcount_t a_refcount; - struct callback_head a_rcu; - unsigned int a_count; - struct posix_acl_entry a_entries[0]; -}; - -typedef __u64 __addrpair; - -typedef __u32 __portpair; - -typedef struct { - struct net *net; -} possible_net_t; - -struct in6_addr { - union { - __u8 u6_addr8[16]; - __be16 u6_addr16[8]; - __be32 u6_addr32[4]; - } in6_u; -}; - -struct hlist_nulls_node { - struct hlist_nulls_node *next; - struct hlist_nulls_node **pprev; -}; - -struct proto; - -struct inet_timewait_death_row; - -struct sock_common { - union { - __addrpair skc_addrpair; - struct { - __be32 skc_daddr; - __be32 skc_rcv_saddr; - }; - }; - union { - unsigned int skc_hash; - __u16 skc_u16hashes[2]; - }; - union { - __portpair skc_portpair; - struct { - __be16 skc_dport; - __u16 skc_num; - }; - }; - short unsigned int skc_family; - volatile unsigned char skc_state; - unsigned char skc_reuse: 4; - unsigned char skc_reuseport: 1; - unsigned char skc_ipv6only: 1; - unsigned char skc_net_refcnt: 1; - int skc_bound_dev_if; - union { - struct hlist_node skc_bind_node; - struct hlist_node skc_portaddr_node; - }; - struct proto *skc_prot; - possible_net_t skc_net; - struct in6_addr skc_v6_daddr; - struct in6_addr skc_v6_rcv_saddr; - atomic64_t skc_cookie; - union { - long unsigned int skc_flags; - struct sock *skc_listener; - struct inet_timewait_death_row *skc_tw_dr; - }; - int skc_dontcopy_begin[0]; - union { - struct hlist_node skc_node; - struct hlist_nulls_node skc_nulls_node; - }; - short unsigned int skc_tx_queue_mapping; - short unsigned int skc_rx_queue_mapping; - union { - int skc_incoming_cpu; - u32 skc_rcv_wnd; - u32 skc_tw_rcv_nxt; - }; - refcount_t skc_refcnt; - int skc_dontcopy_end[0]; - union { - u32 skc_rxhash; - u32 skc_window_clamp; - u32 skc_tw_snd_nxt; - }; -}; - -typedef struct { - spinlock_t slock; - int owned; - wait_queue_head_t wq; -} socket_lock_t; - -struct sk_buff; - -struct sk_buff_head { - struct sk_buff *next; - struct sk_buff *prev; - __u32 qlen; - spinlock_t lock; -}; - -typedef u64 netdev_features_t; - -struct sock_cgroup_data { - union { - struct { - u8 is_data: 1; - u8 no_refcnt: 1; - u8 unused: 6; - u8 padding; - u16 prioidx; - u32 classid; - }; - u64 val; - }; -}; - -struct sk_filter; - -struct socket_wq; - -struct xfrm_policy; - -struct dst_entry; - -struct socket; - -struct sock_reuseport; - -struct bpf_local_storage; - -struct sock { - struct sock_common __sk_common; - socket_lock_t sk_lock; - atomic_t sk_drops; - int sk_rcvlowat; - struct sk_buff_head sk_error_queue; - struct sk_buff *sk_rx_skb_cache; - struct sk_buff_head sk_receive_queue; - struct { - atomic_t rmem_alloc; - int len; - struct sk_buff *head; - struct sk_buff *tail; - } sk_backlog; - int sk_forward_alloc; - unsigned int sk_ll_usec; - unsigned int sk_napi_id; - int sk_rcvbuf; - struct sk_filter *sk_filter; - union { - struct socket_wq *sk_wq; - struct socket_wq *sk_wq_raw; - }; - struct xfrm_policy *sk_policy[2]; - struct dst_entry *sk_rx_dst; - struct dst_entry *sk_dst_cache; - atomic_t sk_omem_alloc; - int sk_sndbuf; - int sk_wmem_queued; - refcount_t sk_wmem_alloc; - long unsigned int sk_tsq_flags; - union { - struct sk_buff *sk_send_head; - struct rb_root tcp_rtx_queue; - }; - struct sk_buff *sk_tx_skb_cache; - struct sk_buff_head sk_write_queue; - __s32 sk_peek_off; - int sk_write_pending; - __u32 sk_dst_pending_confirm; - u32 sk_pacing_status; - long int sk_sndtimeo; - struct timer_list sk_timer; - __u32 sk_priority; - __u32 sk_mark; - long unsigned int sk_pacing_rate; - long unsigned int sk_max_pacing_rate; - struct page_frag sk_frag; - netdev_features_t sk_route_caps; - netdev_features_t sk_route_nocaps; - netdev_features_t sk_route_forced_caps; - int sk_gso_type; - unsigned int sk_gso_max_size; - gfp_t sk_allocation; - __u32 sk_txhash; - u8 sk_padding: 1; - u8 sk_kern_sock: 1; - u8 sk_no_check_tx: 1; - u8 sk_no_check_rx: 1; - u8 sk_userlocks: 4; - u8 sk_pacing_shift; - u16 sk_type; - u16 sk_protocol; - u16 sk_gso_max_segs; - long unsigned int sk_lingertime; - struct proto *sk_prot_creator; - rwlock_t sk_callback_lock; - int sk_err; - int sk_err_soft; - u32 sk_ack_backlog; - u32 sk_max_ack_backlog; - kuid_t sk_uid; - spinlock_t sk_peer_lock; - struct pid *sk_peer_pid; - const struct cred *sk_peer_cred; - long int sk_rcvtimeo; - ktime_t sk_stamp; - u16 sk_tsflags; - u8 sk_shutdown; - u32 sk_tskey; - atomic_t sk_zckey; - u8 sk_clockid; - u8 sk_txtime_deadline_mode: 1; - u8 sk_txtime_report_errors: 1; - u8 sk_txtime_unused: 6; - struct socket *sk_socket; - void *sk_user_data; - void *sk_security; - struct sock_cgroup_data sk_cgrp_data; - struct mem_cgroup *sk_memcg; - void (*sk_state_change)(struct sock *); - void (*sk_data_ready)(struct sock *); - void (*sk_write_space)(struct sock *); - void (*sk_error_report)(struct sock *); - int (*sk_backlog_rcv)(struct sock *, struct sk_buff *); - void (*sk_destruct)(struct sock *); - struct sock_reuseport *sk_reuseport_cb; - struct bpf_local_storage *sk_bpf_storage; - struct callback_head sk_rcu; -}; - -typedef short unsigned int __kernel_sa_family_t; - -typedef __kernel_sa_family_t sa_family_t; - -struct sockaddr { - sa_family_t sa_family; - char sa_data[14]; -}; - -struct msghdr { - void *msg_name; - int msg_namelen; - struct iov_iter msg_iter; - union { - void *msg_control; - void *msg_control_user; - }; - bool msg_control_is_user: 1; - __kernel_size_t msg_controllen; - unsigned int msg_flags; - struct kiocb *msg_iocb; -}; - -typedef struct { - unsigned int clock_rate; - unsigned int clock_type; - short unsigned int loopback; -} sync_serial_settings; - -typedef struct { - unsigned int clock_rate; - unsigned int clock_type; - short unsigned int loopback; - unsigned int slot_map; -} te1_settings; - -typedef struct { - short unsigned int encoding; - short unsigned int parity; -} raw_hdlc_proto; - -typedef struct { - unsigned int t391; - unsigned int t392; - unsigned int n391; - unsigned int n392; - unsigned int n393; - short unsigned int lmi; - short unsigned int dce; -} fr_proto; - -typedef struct { - unsigned int dlci; -} fr_proto_pvc; - -typedef struct { - unsigned int dlci; - char master[16]; -} fr_proto_pvc_info; - -typedef struct { - unsigned int interval; - unsigned int timeout; -} cisco_proto; - -typedef struct { - short unsigned int dce; - unsigned int modulo; - unsigned int window; - unsigned int t1; - unsigned int t2; - unsigned int n2; -} x25_hdlc_proto; - -struct ifmap { - long unsigned int mem_start; - long unsigned int mem_end; - short unsigned int base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct if_settings { - unsigned int type; - unsigned int size; - union { - raw_hdlc_proto *raw_hdlc; - cisco_proto *cisco; - fr_proto *fr; - fr_proto_pvc *fr_pvc; - fr_proto_pvc_info *fr_pvc_info; - x25_hdlc_proto *x25; - sync_serial_settings *sync; - te1_settings *te1; - } ifs_ifsu; -}; - -struct ifreq { - union { - char ifrn_name[16]; - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short int ifru_flags; - int ifru_ivalue; - int ifru_mtu; - struct ifmap ifru_map; - char ifru_slave[16]; - char ifru_newname[16]; - void *ifru_data; - struct if_settings ifru_settings; - } ifr_ifru; -}; - -struct serial_icounter_struct; - -struct serial_struct; - -struct tty_operations { - struct tty_struct * (*lookup)(struct tty_driver *, struct file *, int); - int (*install)(struct tty_driver *, struct tty_struct *); - void (*remove)(struct tty_driver *, struct tty_struct *); - int (*open)(struct tty_struct *, struct file *); - void (*close)(struct tty_struct *, struct file *); - void (*shutdown)(struct tty_struct *); - void (*cleanup)(struct tty_struct *); - int (*write)(struct tty_struct *, const unsigned char *, int); - int (*put_char)(struct tty_struct *, unsigned char); - void (*flush_chars)(struct tty_struct *); - int (*write_room)(struct tty_struct *); - int (*chars_in_buffer)(struct tty_struct *); - int (*ioctl)(struct tty_struct *, unsigned int, long unsigned int); - long int (*compat_ioctl)(struct tty_struct *, unsigned int, long unsigned int); - void (*set_termios)(struct tty_struct *, struct ktermios *); - void (*throttle)(struct tty_struct *); - void (*unthrottle)(struct tty_struct *); - void (*stop)(struct tty_struct *); - void (*start)(struct tty_struct *); - void (*hangup)(struct tty_struct *); - int (*break_ctl)(struct tty_struct *, int); - void (*flush_buffer)(struct tty_struct *); - void (*set_ldisc)(struct tty_struct *); - void (*wait_until_sent)(struct tty_struct *, int); - void (*send_xchar)(struct tty_struct *, char); - int (*tiocmget)(struct tty_struct *); - int (*tiocmset)(struct tty_struct *, unsigned int, unsigned int); - int (*resize)(struct tty_struct *, struct winsize *); - int (*get_icount)(struct tty_struct *, struct serial_icounter_struct *); - int (*get_serial)(struct tty_struct *, struct serial_struct *); - int (*set_serial)(struct tty_struct *, struct serial_struct *); - void (*show_fdinfo)(struct tty_struct *, struct seq_file *); - int (*poll_init)(struct tty_driver *, int, char *); - int (*poll_get_char)(struct tty_driver *, int); - void (*poll_put_char)(struct tty_driver *, int, char); - int (*proc_show)(struct seq_file *, void *); -}; - -struct proc_dir_entry; - -struct tty_driver { - int magic; - struct kref kref; - struct cdev **cdevs; - struct module *owner; - const char *driver_name; - const char *name; - int name_base; - int major; - int minor_start; - unsigned int num; - short int type; - short int subtype; - struct ktermios init_termios; - long unsigned int flags; - struct proc_dir_entry *proc_entry; - struct tty_driver *other; - struct tty_struct **ttys; - struct tty_port **ports; - struct ktermios **termios; - void *driver_state; - const struct tty_operations *ops; - struct list_head tty_drivers; -}; - -struct tty_buffer { - union { - struct tty_buffer *next; - struct llist_node free; - }; - int used; - int size; - int commit; - int read; - int flags; - long unsigned int data[0]; -}; - -struct tty_bufhead { - struct tty_buffer *head; - struct work_struct work; - struct mutex lock; - atomic_t priority; - struct tty_buffer sentinel; - struct llist_head free; - atomic_t mem_used; - int mem_limit; - struct tty_buffer *tail; -}; - -struct tty_port_operations; - -struct tty_port_client_operations; - -struct tty_port { - struct tty_bufhead buf; - struct tty_struct *tty; - struct tty_struct *itty; - const struct tty_port_operations *ops; - const struct tty_port_client_operations *client_ops; - spinlock_t lock; - int blocked_open; - int count; - wait_queue_head_t open_wait; - wait_queue_head_t delta_msr_wait; - long unsigned int flags; - long unsigned int iflags; - unsigned char console: 1; - unsigned char low_latency: 1; - struct mutex mutex; - struct mutex buf_mutex; - unsigned char *xmit_buf; - unsigned int close_delay; - unsigned int closing_wait; - int drain_delay; - struct kref kref; - void *client_data; -}; - -struct tty_ldisc_ops { - int magic; - char *name; - int num; - int flags; - int (*open)(struct tty_struct *); - void (*close)(struct tty_struct *); - void (*flush_buffer)(struct tty_struct *); - ssize_t (*read)(struct tty_struct *, struct file *, unsigned char *, size_t, void **, long unsigned int); - ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t); - int (*ioctl)(struct tty_struct *, struct file *, unsigned int, long unsigned int); - int (*compat_ioctl)(struct tty_struct *, struct file *, unsigned int, long unsigned int); - void (*set_termios)(struct tty_struct *, struct ktermios *); - __poll_t (*poll)(struct tty_struct *, struct file *, struct poll_table_struct *); - int (*hangup)(struct tty_struct *); - void (*receive_buf)(struct tty_struct *, const unsigned char *, char *, int); - void (*write_wakeup)(struct tty_struct *); - void (*dcd_change)(struct tty_struct *, unsigned int); - int (*receive_buf2)(struct tty_struct *, const unsigned char *, char *, int); - struct module *owner; - int refcount; -}; - -struct tty_ldisc { - struct tty_ldisc_ops *ops; - struct tty_struct *tty; -}; - -struct tty_port_operations { - int (*carrier_raised)(struct tty_port *); - void (*dtr_rts)(struct tty_port *, int); - void (*shutdown)(struct tty_port *); - int (*activate)(struct tty_port *, struct tty_struct *); - void (*destruct)(struct tty_port *); -}; - -struct tty_port_client_operations { - int (*receive_buf)(struct tty_port *, const unsigned char *, const unsigned char *, size_t); - void (*write_wakeup)(struct tty_port *); -}; - -struct prot_inuse; - -struct netns_core { - struct ctl_table_header *sysctl_hdr; - int sysctl_somaxconn; - int *sock_inuse; - struct prot_inuse *prot_inuse; -}; - -struct tcp_mib; - -struct ipstats_mib; - -struct linux_mib; - -struct udp_mib; - -struct icmp_mib; - -struct icmpmsg_mib; - -struct icmpv6_mib; - -struct icmpv6msg_mib; - -struct netns_mib { - struct tcp_mib *tcp_statistics; - struct ipstats_mib *ip_statistics; - struct linux_mib *net_statistics; - struct udp_mib *udp_statistics; - struct udp_mib *udplite_statistics; - struct icmp_mib *icmp_statistics; - struct icmpmsg_mib *icmpmsg_statistics; - struct proc_dir_entry *proc_net_devsnmp6; - struct udp_mib *udp_stats_in6; - struct udp_mib *udplite_stats_in6; - struct ipstats_mib *ipv6_statistics; - struct icmpv6_mib *icmpv6_statistics; - struct icmpv6msg_mib *icmpv6msg_statistics; -}; - -struct netns_packet { - struct mutex sklist_lock; - struct hlist_head sklist; -}; - -struct netns_unix { - int sysctl_max_dgram_qlen; - struct ctl_table_header *ctl; -}; - -struct netns_nexthop { - struct rb_root rb_root; - struct hlist_head *devhash; - unsigned int seq; - u32 last_id_allocated; - struct blocking_notifier_head notifier_chain; -}; - -struct local_ports { - seqlock_t lock; - int range[2]; - bool warned; -}; - -struct inet_hashinfo; - -struct inet_timewait_death_row { - atomic_t tw_count; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct inet_hashinfo *hashinfo; - int sysctl_max_tw_buckets; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct ping_group_range { - seqlock_t lock; - kgid_t range[2]; -}; - -typedef struct { - u64 key[2]; -} siphash_key_t; - -struct ipv4_devconf; - -struct ip_ra_chain; - -struct fib_rules_ops; - -struct fib_table; - -struct inet_peer_base; - -struct fqdir; - -struct xt_table; - -struct tcp_congestion_ops; - -struct tcp_fastopen_context; - -struct fib_notifier_ops; - -struct netns_ipv4 { - struct ctl_table_header *forw_hdr; - struct ctl_table_header *frags_hdr; - struct ctl_table_header *ipv4_hdr; - struct ctl_table_header *route_hdr; - struct ctl_table_header *xfrm4_hdr; - struct ipv4_devconf *devconf_all; - struct ipv4_devconf *devconf_dflt; - struct ip_ra_chain *ra_chain; - struct mutex ra_mutex; - struct fib_rules_ops *rules_ops; - bool fib_has_custom_rules; - unsigned int fib_rules_require_fldissect; - struct fib_table *fib_main; - struct fib_table *fib_default; - bool fib_has_custom_local_routes; - atomic_t fib_num_tclassid_users; - struct hlist_head *fib_table_hash; - bool fib_offload_disabled; - struct sock *fibnl; - struct sock **icmp_sk; - struct sock *mc_autojoin_sk; - struct inet_peer_base *peers; - struct sock **tcp_sk; - struct fqdir *fqdir; - struct xt_table *iptable_filter; - struct xt_table *iptable_mangle; - struct xt_table *iptable_raw; - struct xt_table *arptable_filter; - struct xt_table *iptable_security; - struct xt_table *nat_table; - int sysctl_icmp_echo_ignore_all; - int sysctl_icmp_echo_ignore_broadcasts; - int sysctl_icmp_ignore_bogus_error_responses; - int sysctl_icmp_ratelimit; - int sysctl_icmp_ratemask; - int sysctl_icmp_errors_use_inbound_ifaddr; - struct local_ports ip_local_ports; - int sysctl_tcp_ecn; - int sysctl_tcp_ecn_fallback; - int sysctl_ip_default_ttl; - int sysctl_ip_no_pmtu_disc; - int sysctl_ip_fwd_use_pmtu; - int sysctl_ip_fwd_update_priority; - int sysctl_ip_nonlocal_bind; - int sysctl_ip_autobind_reuse; - int sysctl_ip_dynaddr; - int sysctl_ip_early_demux; - int sysctl_raw_l3mdev_accept; - int sysctl_tcp_early_demux; - int sysctl_udp_early_demux; - int sysctl_nexthop_compat_mode; - int sysctl_fwmark_reflect; - int sysctl_tcp_fwmark_accept; - int sysctl_tcp_l3mdev_accept; - int sysctl_tcp_mtu_probing; - int sysctl_tcp_mtu_probe_floor; - int sysctl_tcp_base_mss; - int sysctl_tcp_min_snd_mss; - int sysctl_tcp_probe_threshold; - u32 sysctl_tcp_probe_interval; - int sysctl_tcp_keepalive_time; - int sysctl_tcp_keepalive_probes; - int sysctl_tcp_keepalive_intvl; - int sysctl_tcp_syn_retries; - int sysctl_tcp_synack_retries; - int sysctl_tcp_syncookies; - int sysctl_tcp_reordering; - int sysctl_tcp_retries1; - int sysctl_tcp_retries2; - int sysctl_tcp_orphan_retries; - int sysctl_tcp_fin_timeout; - unsigned int sysctl_tcp_notsent_lowat; - int sysctl_tcp_tw_reuse; - int sysctl_tcp_sack; - int sysctl_tcp_window_scaling; - int sysctl_tcp_timestamps; - int sysctl_tcp_early_retrans; - int sysctl_tcp_recovery; - int sysctl_tcp_thin_linear_timeouts; - int sysctl_tcp_slow_start_after_idle; - int sysctl_tcp_retrans_collapse; - int sysctl_tcp_stdurg; - int sysctl_tcp_rfc1337; - int sysctl_tcp_abort_on_overflow; - int sysctl_tcp_fack; - int sysctl_tcp_max_reordering; - int sysctl_tcp_dsack; - int sysctl_tcp_app_win; - int sysctl_tcp_adv_win_scale; - int sysctl_tcp_frto; - int sysctl_tcp_nometrics_save; - int sysctl_tcp_no_ssthresh_metrics_save; - int sysctl_tcp_moderate_rcvbuf; - int sysctl_tcp_tso_win_divisor; - int sysctl_tcp_workaround_signed_windows; - int sysctl_tcp_limit_output_bytes; - int sysctl_tcp_challenge_ack_limit; - int sysctl_tcp_min_tso_segs; - int sysctl_tcp_min_rtt_wlen; - int sysctl_tcp_autocorking; - int sysctl_tcp_invalid_ratelimit; - int sysctl_tcp_pacing_ss_ratio; - int sysctl_tcp_pacing_ca_ratio; - int sysctl_tcp_wmem[3]; - int sysctl_tcp_rmem[3]; - int sysctl_tcp_comp_sack_nr; - long unsigned int sysctl_tcp_comp_sack_delay_ns; - long unsigned int sysctl_tcp_comp_sack_slack_ns; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct inet_timewait_death_row tcp_death_row; - int sysctl_max_syn_backlog; - int sysctl_tcp_fastopen; - const struct tcp_congestion_ops *tcp_congestion_control; - struct tcp_fastopen_context *tcp_fastopen_ctx; - spinlock_t tcp_fastopen_ctx_lock; - unsigned int sysctl_tcp_fastopen_blackhole_timeout; - atomic_t tfo_active_disable_times; - long unsigned int tfo_active_disable_stamp; - int sysctl_tcp_reflect_tos; - int sysctl_udp_wmem_min; - int sysctl_udp_rmem_min; - int sysctl_udp_l3mdev_accept; - int sysctl_igmp_max_memberships; - int sysctl_igmp_max_msf; - int sysctl_igmp_llm_reports; - int sysctl_igmp_qrv; - struct ping_group_range ping_group_range; - atomic_t dev_addr_genid; - long unsigned int *sysctl_local_reserved_ports; - int sysctl_ip_prot_sock; - struct list_head mr_tables; - struct fib_rules_ops *mr_rules_ops; - int sysctl_fib_multipath_use_neigh; - int sysctl_fib_multipath_hash_policy; - struct fib_notifier_ops *notifier_ops; - unsigned int fib_seq; - struct fib_notifier_ops *ipmr_notifier_ops; - unsigned int ipmr_seq; - atomic_t rt_genid; - siphash_key_t ip_id_key; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct netns_sysctl_ipv6 { - struct ctl_table_header *hdr; - struct ctl_table_header *route_hdr; - struct ctl_table_header *icmp_hdr; - struct ctl_table_header *frags_hdr; - struct ctl_table_header *xfrm6_hdr; - int bindv6only; - int flush_delay; - int ip6_rt_max_size; - int ip6_rt_gc_min_interval; - int ip6_rt_gc_timeout; - int ip6_rt_gc_interval; - int ip6_rt_gc_elasticity; - int ip6_rt_mtu_expires; - int ip6_rt_min_advmss; - int multipath_hash_policy; - int flowlabel_consistency; - int auto_flowlabels; - int icmpv6_time; - int icmpv6_echo_ignore_all; - int icmpv6_echo_ignore_multicast; - int icmpv6_echo_ignore_anycast; - long unsigned int icmpv6_ratemask[4]; - long unsigned int *icmpv6_ratemask_ptr; - int anycast_src_echo_reply; - int ip_nonlocal_bind; - int fwmark_reflect; - int idgen_retries; - int idgen_delay; - int flowlabel_state_ranges; - int flowlabel_reflect; - int max_dst_opts_cnt; - int max_hbh_opts_cnt; - int max_dst_opts_len; - int max_hbh_opts_len; - int seg6_flowlabel; - bool skip_notify_on_dev_down; -}; - -struct net_device; - -struct neighbour; - -struct dst_ops { - short unsigned int family; - unsigned int gc_thresh; - int (*gc)(struct dst_ops *); - struct dst_entry * (*check)(struct dst_entry *, __u32); - unsigned int (*default_advmss)(const struct dst_entry *); - unsigned int (*mtu)(const struct dst_entry *); - u32 * (*cow_metrics)(struct dst_entry *, long unsigned int); - void (*destroy)(struct dst_entry *); - void (*ifdown)(struct dst_entry *, struct net_device *, int); - struct dst_entry * (*negative_advice)(struct dst_entry *); - void (*link_failure)(struct sk_buff *); - void (*update_pmtu)(struct dst_entry *, struct sock *, struct sk_buff *, u32, bool); - void (*redirect)(struct dst_entry *, struct sock *, struct sk_buff *); - int (*local_out)(struct net *, struct sock *, struct sk_buff *); - struct neighbour * (*neigh_lookup)(const struct dst_entry *, struct sk_buff *, const void *); - void (*confirm_neigh)(const struct dst_entry *, const void *); - struct kmem_cache *kmem_cachep; - struct percpu_counter pcpuc_entries; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct ipv6_devconf; - -struct fib6_info; - -struct rt6_info; - -struct rt6_statistics; - -struct fib6_table; - -struct seg6_pernet_data; - -struct netns_ipv6 { - struct netns_sysctl_ipv6 sysctl; - struct ipv6_devconf *devconf_all; - struct ipv6_devconf *devconf_dflt; - struct inet_peer_base *peers; - struct fqdir *fqdir; - struct xt_table *ip6table_filter; - struct xt_table *ip6table_mangle; - struct xt_table *ip6table_raw; - struct xt_table *ip6table_security; - struct xt_table *ip6table_nat; - struct fib6_info *fib6_null_entry; - struct rt6_info *ip6_null_entry; - struct rt6_statistics *rt6_stats; - struct timer_list ip6_fib_timer; - struct hlist_head *fib_table_hash; - struct fib6_table *fib6_main_tbl; - struct list_head fib6_walkers; - long: 64; - long: 64; - struct dst_ops ip6_dst_ops; - rwlock_t fib6_walker_lock; - spinlock_t fib6_gc_lock; - unsigned int ip6_rt_gc_expire; - long unsigned int ip6_rt_last_gc; - unsigned int fib6_rules_require_fldissect; - bool fib6_has_custom_rules; - unsigned int fib6_routes_require_src; - struct rt6_info *ip6_prohibit_entry; - struct rt6_info *ip6_blk_hole_entry; - struct fib6_table *fib6_local_tbl; - struct fib_rules_ops *fib6_rules_ops; - struct sock **icmp_sk; - struct sock *ndisc_sk; - struct sock *tcp_sk; - struct sock *igmp_sk; - struct sock *mc_autojoin_sk; - struct list_head mr6_tables; - struct fib_rules_ops *mr6_rules_ops; - atomic_t dev_addr_genid; - atomic_t fib6_sernum; - struct seg6_pernet_data *seg6_data; - struct fib_notifier_ops *notifier_ops; - struct fib_notifier_ops *ip6mr_notifier_ops; - unsigned int ipmr_seq; - struct { - struct hlist_head head; - spinlock_t lock; - u32 seq; - } ip6addrlbl_table; -}; - -struct sctp_mib; - -struct netns_sctp { - struct sctp_mib *sctp_statistics; - struct proc_dir_entry *proc_net_sctp; - struct ctl_table_header *sysctl_header; - struct sock *ctl_sock; - struct list_head local_addr_list; - struct list_head addr_waitq; - struct timer_list addr_wq_timer; - struct list_head auto_asconf_splist; - spinlock_t addr_wq_lock; - spinlock_t local_addr_lock; - unsigned int rto_initial; - unsigned int rto_min; - unsigned int rto_max; - int rto_alpha; - int rto_beta; - int max_burst; - int cookie_preserve_enable; - char *sctp_hmac_alg; - unsigned int valid_cookie_life; - unsigned int sack_timeout; - unsigned int hb_interval; - int max_retrans_association; - int max_retrans_path; - int max_retrans_init; - int pf_retrans; - int ps_retrans; - int pf_enable; - int pf_expose; - int sndbuf_policy; - int rcvbuf_policy; - int default_auto_asconf; - int addip_enable; - int addip_noauth; - int prsctp_enable; - int reconf_enable; - int auth_enable; - int intl_enable; - int ecn_enable; - int scope_policy; - int rwnd_upd_shift; - long unsigned int max_autoclose; -}; - -struct nf_queue_handler; - -struct nf_logger; - -struct nf_hook_entries; - -struct netns_nf { - struct proc_dir_entry *proc_netfilter; - const struct nf_queue_handler *queue_handler; - const struct nf_logger *nf_loggers[13]; - struct ctl_table_header *nf_log_dir_header; - struct nf_hook_entries *hooks_ipv4[5]; - struct nf_hook_entries *hooks_ipv6[5]; - struct nf_hook_entries *hooks_arp[3]; - struct nf_hook_entries *hooks_bridge[5]; - bool defrag_ipv4; - bool defrag_ipv6; -}; - -struct ebt_table; - -struct netns_xt { - struct list_head tables[13]; - bool notrack_deprecated_warning; - bool clusterip_deprecated_warning; - struct ebt_table *broute_table; - struct ebt_table *frame_filter; - struct ebt_table *frame_nat; -}; - -struct nf_generic_net { - unsigned int timeout; -}; - -struct nf_tcp_net { - unsigned int timeouts[14]; - int tcp_loose; - int tcp_be_liberal; - int tcp_max_retrans; -}; - -struct nf_udp_net { - unsigned int timeouts[2]; -}; - -struct nf_icmp_net { - unsigned int timeout; -}; - -struct nf_dccp_net { - int dccp_loose; - unsigned int dccp_timeout[10]; -}; - -struct nf_sctp_net { - unsigned int timeouts[10]; -}; - -struct nf_gre_net { - struct list_head keymap_list; - unsigned int timeouts[2]; -}; - -struct nf_ip_net { - struct nf_generic_net generic; - struct nf_tcp_net tcp; - struct nf_udp_net udp; - struct nf_icmp_net icmp; - struct nf_icmp_net icmpv6; - struct nf_dccp_net dccp; - struct nf_sctp_net sctp; - struct nf_gre_net gre; -}; - -struct ct_pcpu; - -struct ip_conntrack_stat; - -struct nf_ct_event_notifier; - -struct nf_exp_event_notifier; - -struct netns_ct { - atomic_t count; - unsigned int expect_count; - struct delayed_work ecache_dwork; - bool ecache_dwork_pending; - bool auto_assign_helper_warned; - struct ctl_table_header *sysctl_header; - unsigned int sysctl_log_invalid; - int sysctl_events; - int sysctl_acct; - int sysctl_auto_assign_helper; - int sysctl_tstamp; - int sysctl_checksum; - struct ct_pcpu *pcpu_lists; - struct ip_conntrack_stat *stat; - struct nf_ct_event_notifier *nf_conntrack_event_cb; - struct nf_exp_event_notifier *nf_expect_event_cb; - struct nf_ip_net nf_ct_proto; - unsigned int labels_used; -}; - -struct netns_nftables { - struct list_head tables; - struct list_head commit_list; - struct list_head module_list; - struct list_head notify_list; - struct mutex commit_mutex; - unsigned int base_seq; - u8 gencursor; - u8 validate_state; -}; - -struct netns_nf_frag { - struct fqdir *fqdir; -}; - -struct netns_bpf { - struct bpf_prog_array *run_array[2]; - struct bpf_prog *progs[2]; - struct list_head links[2]; -}; - -struct xfrm_policy_hash { - struct hlist_head *table; - unsigned int hmask; - u8 dbits4; - u8 sbits4; - u8 dbits6; - u8 sbits6; -}; - -struct xfrm_policy_hthresh { - struct work_struct work; - seqlock_t lock; - u8 lbits4; - u8 rbits4; - u8 lbits6; - u8 rbits6; -}; - -struct netns_xfrm { - struct list_head state_all; - struct hlist_head *state_bydst; - struct hlist_head *state_bysrc; - struct hlist_head *state_byspi; - unsigned int state_hmask; - unsigned int state_num; - struct work_struct state_hash_work; - struct list_head policy_all; - struct hlist_head *policy_byidx; - unsigned int policy_idx_hmask; - struct hlist_head policy_inexact[3]; - struct xfrm_policy_hash policy_bydst[3]; - unsigned int policy_count[6]; - struct work_struct policy_hash_work; - struct xfrm_policy_hthresh policy_hthresh; - struct list_head inexact_bins; - struct sock *nlsk; - struct sock *nlsk_stash; - u32 sysctl_aevent_etime; - u32 sysctl_aevent_rseqth; - int sysctl_larval_drop; - u32 sysctl_acq_expires; - struct ctl_table_header *sysctl_hdr; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct dst_ops xfrm4_dst_ops; - struct dst_ops xfrm6_dst_ops; - spinlock_t xfrm_state_lock; - seqcount_t xfrm_state_hash_generation; - seqcount_spinlock_t xfrm_policy_hash_generation; - spinlock_t xfrm_policy_lock; - struct mutex xfrm_cfg_mutex; - long: 64; - long: 64; -}; - -struct netns_ipvs; - -struct mpls_route; - -struct netns_mpls { - int ip_ttl_propagate; - int default_ttl; - size_t platform_labels; - struct mpls_route **platform_label; - struct ctl_table_header *ctl; -}; - -struct uevent_sock; - -struct net_generic; - -struct net { - refcount_t passive; - refcount_t count; - spinlock_t rules_mod_lock; - unsigned int dev_unreg_count; - unsigned int dev_base_seq; - int ifindex; - spinlock_t nsid_lock; - atomic_t fnhe_genid; - struct list_head list; - struct list_head exit_list; - struct llist_node cleanup_list; - struct key_tag *key_domain; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct idr netns_ids; - struct ns_common ns; - struct list_head dev_base_head; - struct proc_dir_entry *proc_net; - struct proc_dir_entry *proc_net_stat; - struct ctl_table_set sysctls; - struct sock *rtnl; - struct sock *genl_sock; - struct uevent_sock *uevent_sock; - struct hlist_head *dev_name_head; - struct hlist_head *dev_index_head; - struct raw_notifier_head netdev_chain; - u32 hash_mix; - struct net_device *loopback_dev; - struct list_head rules_ops; - struct netns_core core; - struct netns_mib mib; - struct netns_packet packet; - struct netns_unix unx; - struct netns_nexthop nexthop; - long: 64; - long: 64; - long: 64; - struct netns_ipv4 ipv4; - struct netns_ipv6 ipv6; - struct netns_sctp sctp; - struct netns_nf nf; - struct netns_xt xt; - struct netns_ct ct; - struct netns_nftables nft; - struct netns_nf_frag nf_frag; - struct ctl_table_header *nf_frag_frags_hdr; - struct sock *nfnl; - struct sock *nfnl_stash; - struct list_head nfnl_acct_list; - struct sk_buff_head wext_nlevents; - struct net_generic *gen; - struct netns_bpf bpf; - struct netns_xfrm xfrm; - atomic64_t net_cookie; - struct netns_ipvs *ipvs; - struct netns_mpls mpls; - struct sock *crypto_nlsk; - struct sock *diag_nlsk; -}; - -typedef struct { - local64_t v; -} u64_stats_t; - -struct bpf_insn { - __u8 code; - __u8 dst_reg: 4; - __u8 src_reg: 4; - __s16 off; - __s32 imm; -}; - -enum bpf_map_type { - BPF_MAP_TYPE_UNSPEC = 0, - BPF_MAP_TYPE_HASH = 1, - BPF_MAP_TYPE_ARRAY = 2, - BPF_MAP_TYPE_PROG_ARRAY = 3, - BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4, - BPF_MAP_TYPE_PERCPU_HASH = 5, - BPF_MAP_TYPE_PERCPU_ARRAY = 6, - BPF_MAP_TYPE_STACK_TRACE = 7, - BPF_MAP_TYPE_CGROUP_ARRAY = 8, - BPF_MAP_TYPE_LRU_HASH = 9, - BPF_MAP_TYPE_LRU_PERCPU_HASH = 10, - BPF_MAP_TYPE_LPM_TRIE = 11, - BPF_MAP_TYPE_ARRAY_OF_MAPS = 12, - BPF_MAP_TYPE_HASH_OF_MAPS = 13, - BPF_MAP_TYPE_DEVMAP = 14, - BPF_MAP_TYPE_SOCKMAP = 15, - BPF_MAP_TYPE_CPUMAP = 16, - BPF_MAP_TYPE_XSKMAP = 17, - BPF_MAP_TYPE_SOCKHASH = 18, - BPF_MAP_TYPE_CGROUP_STORAGE = 19, - BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20, - BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21, - BPF_MAP_TYPE_QUEUE = 22, - BPF_MAP_TYPE_STACK = 23, - BPF_MAP_TYPE_SK_STORAGE = 24, - BPF_MAP_TYPE_DEVMAP_HASH = 25, - BPF_MAP_TYPE_STRUCT_OPS = 26, - BPF_MAP_TYPE_RINGBUF = 27, - BPF_MAP_TYPE_INODE_STORAGE = 28, -}; - -enum bpf_prog_type { - BPF_PROG_TYPE_UNSPEC = 0, - BPF_PROG_TYPE_SOCKET_FILTER = 1, - BPF_PROG_TYPE_KPROBE = 2, - BPF_PROG_TYPE_SCHED_CLS = 3, - BPF_PROG_TYPE_SCHED_ACT = 4, - BPF_PROG_TYPE_TRACEPOINT = 5, - BPF_PROG_TYPE_XDP = 6, - BPF_PROG_TYPE_PERF_EVENT = 7, - BPF_PROG_TYPE_CGROUP_SKB = 8, - BPF_PROG_TYPE_CGROUP_SOCK = 9, - BPF_PROG_TYPE_LWT_IN = 10, - BPF_PROG_TYPE_LWT_OUT = 11, - BPF_PROG_TYPE_LWT_XMIT = 12, - BPF_PROG_TYPE_SOCK_OPS = 13, - BPF_PROG_TYPE_SK_SKB = 14, - BPF_PROG_TYPE_CGROUP_DEVICE = 15, - BPF_PROG_TYPE_SK_MSG = 16, - BPF_PROG_TYPE_RAW_TRACEPOINT = 17, - BPF_PROG_TYPE_CGROUP_SOCK_ADDR = 18, - BPF_PROG_TYPE_LWT_SEG6LOCAL = 19, - BPF_PROG_TYPE_LIRC_MODE2 = 20, - BPF_PROG_TYPE_SK_REUSEPORT = 21, - BPF_PROG_TYPE_FLOW_DISSECTOR = 22, - BPF_PROG_TYPE_CGROUP_SYSCTL = 23, - BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 24, - BPF_PROG_TYPE_CGROUP_SOCKOPT = 25, - BPF_PROG_TYPE_TRACING = 26, - BPF_PROG_TYPE_STRUCT_OPS = 27, - BPF_PROG_TYPE_EXT = 28, - BPF_PROG_TYPE_LSM = 29, - BPF_PROG_TYPE_SK_LOOKUP = 30, -}; - -enum bpf_attach_type { - BPF_CGROUP_INET_INGRESS = 0, - BPF_CGROUP_INET_EGRESS = 1, - BPF_CGROUP_INET_SOCK_CREATE = 2, - BPF_CGROUP_SOCK_OPS = 3, - BPF_SK_SKB_STREAM_PARSER = 4, - BPF_SK_SKB_STREAM_VERDICT = 5, - BPF_CGROUP_DEVICE = 6, - BPF_SK_MSG_VERDICT = 7, - BPF_CGROUP_INET4_BIND = 8, - BPF_CGROUP_INET6_BIND = 9, - BPF_CGROUP_INET4_CONNECT = 10, - BPF_CGROUP_INET6_CONNECT = 11, - BPF_CGROUP_INET4_POST_BIND = 12, - BPF_CGROUP_INET6_POST_BIND = 13, - BPF_CGROUP_UDP4_SENDMSG = 14, - BPF_CGROUP_UDP6_SENDMSG = 15, - BPF_LIRC_MODE2 = 16, - BPF_FLOW_DISSECTOR = 17, - BPF_CGROUP_SYSCTL = 18, - BPF_CGROUP_UDP4_RECVMSG = 19, - BPF_CGROUP_UDP6_RECVMSG = 20, - BPF_CGROUP_GETSOCKOPT = 21, - BPF_CGROUP_SETSOCKOPT = 22, - BPF_TRACE_RAW_TP = 23, - BPF_TRACE_FENTRY = 24, - BPF_TRACE_FEXIT = 25, - BPF_MODIFY_RETURN = 26, - BPF_LSM_MAC = 27, - BPF_TRACE_ITER = 28, - BPF_CGROUP_INET4_GETPEERNAME = 29, - BPF_CGROUP_INET6_GETPEERNAME = 30, - BPF_CGROUP_INET4_GETSOCKNAME = 31, - BPF_CGROUP_INET6_GETSOCKNAME = 32, - BPF_XDP_DEVMAP = 33, - BPF_CGROUP_INET_SOCK_RELEASE = 34, - BPF_XDP_CPUMAP = 35, - BPF_SK_LOOKUP = 36, - BPF_XDP = 37, - __MAX_BPF_ATTACH_TYPE = 38, -}; - -union bpf_attr { - struct { - __u32 map_type; - __u32 key_size; - __u32 value_size; - __u32 max_entries; - __u32 map_flags; - __u32 inner_map_fd; - __u32 numa_node; - char map_name[16]; - __u32 map_ifindex; - __u32 btf_fd; - __u32 btf_key_type_id; - __u32 btf_value_type_id; - __u32 btf_vmlinux_value_type_id; - }; - struct { - __u32 map_fd; - __u64 key; - union { - __u64 value; - __u64 next_key; - }; - __u64 flags; - }; - struct { - __u64 in_batch; - __u64 out_batch; - __u64 keys; - __u64 values; - __u32 count; - __u32 map_fd; - __u64 elem_flags; - __u64 flags; - } batch; - struct { - __u32 prog_type; - __u32 insn_cnt; - __u64 insns; - __u64 license; - __u32 log_level; - __u32 log_size; - __u64 log_buf; - __u32 kern_version; - __u32 prog_flags; - char prog_name[16]; - __u32 prog_ifindex; - __u32 expected_attach_type; - __u32 prog_btf_fd; - __u32 func_info_rec_size; - __u64 func_info; - __u32 func_info_cnt; - __u32 line_info_rec_size; - __u64 line_info; - __u32 line_info_cnt; - __u32 attach_btf_id; - __u32 attach_prog_fd; - }; - struct { - __u64 pathname; - __u32 bpf_fd; - __u32 file_flags; - }; - struct { - __u32 target_fd; - __u32 attach_bpf_fd; - __u32 attach_type; - __u32 attach_flags; - __u32 replace_bpf_fd; - }; - struct { - __u32 prog_fd; - __u32 retval; - __u32 data_size_in; - __u32 data_size_out; - __u64 data_in; - __u64 data_out; - __u32 repeat; - __u32 duration; - __u32 ctx_size_in; - __u32 ctx_size_out; - __u64 ctx_in; - __u64 ctx_out; - __u32 flags; - __u32 cpu; - } test; - struct { - union { - __u32 start_id; - __u32 prog_id; - __u32 map_id; - __u32 btf_id; - __u32 link_id; - }; - __u32 next_id; - __u32 open_flags; - }; - struct { - __u32 bpf_fd; - __u32 info_len; - __u64 info; - } info; - struct { - __u32 target_fd; - __u32 attach_type; - __u32 query_flags; - __u32 attach_flags; - __u64 prog_ids; - __u32 prog_cnt; - } query; - struct { - __u64 name; - __u32 prog_fd; - } raw_tracepoint; - struct { - __u64 btf; - __u64 btf_log_buf; - __u32 btf_size; - __u32 btf_log_size; - __u32 btf_log_level; - }; - struct { - __u32 pid; - __u32 fd; - __u32 flags; - __u32 buf_len; - __u64 buf; - __u32 prog_id; - __u32 fd_type; - __u64 probe_offset; - __u64 probe_addr; - } task_fd_query; - struct { - __u32 prog_fd; - union { - __u32 target_fd; - __u32 target_ifindex; - }; - __u32 attach_type; - __u32 flags; - union { - __u32 target_btf_id; - struct { - __u64 iter_info; - __u32 iter_info_len; - }; - }; - } link_create; - struct { - __u32 link_fd; - __u32 new_prog_fd; - __u32 flags; - __u32 old_prog_fd; - } link_update; - struct { - __u32 link_fd; - } link_detach; - struct { - __u32 type; - } enable_stats; - struct { - __u32 link_fd; - __u32 flags; - } iter_create; - struct { - __u32 prog_fd; - __u32 map_fd; - __u32 flags; - } prog_bind_map; -}; - -struct bpf_func_info { - __u32 insn_off; - __u32 type_id; -}; - -struct bpf_line_info { - __u32 insn_off; - __u32 file_name_off; - __u32 line_off; - __u32 line_col; -}; - -struct bpf_iter_aux_info; - -typedef int (*bpf_iter_init_seq_priv_t)(void *, struct bpf_iter_aux_info *); - -struct bpf_map; - -struct bpf_iter_aux_info { - struct bpf_map *map; -}; - -typedef void (*bpf_iter_fini_seq_priv_t)(void *); - -struct bpf_iter_seq_info { - const struct seq_operations *seq_ops; - bpf_iter_init_seq_priv_t init_seq_private; - bpf_iter_fini_seq_priv_t fini_seq_private; - u32 seq_priv_size; -}; - -struct btf; - -struct btf_type; - -struct bpf_prog_aux; - -struct bpf_local_storage_map; - -struct bpf_map_ops { - int (*map_alloc_check)(union bpf_attr *); - struct bpf_map * (*map_alloc)(union bpf_attr *); - void (*map_release)(struct bpf_map *, struct file *); - void (*map_free)(struct bpf_map *); - int (*map_get_next_key)(struct bpf_map *, void *, void *); - void (*map_release_uref)(struct bpf_map *); - void * (*map_lookup_elem_sys_only)(struct bpf_map *, void *); - int (*map_lookup_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - int (*map_lookup_and_delete_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - int (*map_update_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - int (*map_delete_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - void * (*map_lookup_elem)(struct bpf_map *, void *); - int (*map_update_elem)(struct bpf_map *, void *, void *, u64); - int (*map_delete_elem)(struct bpf_map *, void *); - int (*map_push_elem)(struct bpf_map *, void *, u64); - int (*map_pop_elem)(struct bpf_map *, void *); - int (*map_peek_elem)(struct bpf_map *, void *); - void * (*map_fd_get_ptr)(struct bpf_map *, struct file *, int); - void (*map_fd_put_ptr)(void *); - int (*map_gen_lookup)(struct bpf_map *, struct bpf_insn *); - u32 (*map_fd_sys_lookup_elem)(void *); - void (*map_seq_show_elem)(struct bpf_map *, void *, struct seq_file *); - int (*map_check_btf)(const struct bpf_map *, const struct btf *, const struct btf_type *, const struct btf_type *); - int (*map_poke_track)(struct bpf_map *, struct bpf_prog_aux *); - void (*map_poke_untrack)(struct bpf_map *, struct bpf_prog_aux *); - void (*map_poke_run)(struct bpf_map *, u32, struct bpf_prog *, struct bpf_prog *); - int (*map_direct_value_addr)(const struct bpf_map *, u64 *, u32); - int (*map_direct_value_meta)(const struct bpf_map *, u64, u32 *); - int (*map_mmap)(struct bpf_map *, struct vm_area_struct *); - __poll_t (*map_poll)(struct bpf_map *, struct file *, struct poll_table_struct *); - int (*map_local_storage_charge)(struct bpf_local_storage_map *, void *, u32); - void (*map_local_storage_uncharge)(struct bpf_local_storage_map *, void *, u32); - struct bpf_local_storage ** (*map_owner_storage_ptr)(void *); - bool (*map_meta_equal)(const struct bpf_map *, const struct bpf_map *); - const char * const map_btf_name; - int *map_btf_id; - const struct bpf_iter_seq_info *iter_seq_info; -}; - -struct bpf_map_memory { - u32 pages; - struct user_struct *user; -}; - -struct bpf_map { - const struct bpf_map_ops *ops; - struct bpf_map *inner_map_meta; - void *security; - enum bpf_map_type map_type; - u32 key_size; - u32 value_size; - u32 max_entries; - u32 map_flags; - int spin_lock_off; - u32 id; - int numa_node; - u32 btf_key_type_id; - u32 btf_value_type_id; - struct btf *btf; - struct bpf_map_memory memory; - char name[16]; - u32 btf_vmlinux_value_type_id; - bool bypass_spec_v1; - bool frozen; - long: 16; - long: 64; - long: 64; - atomic64_t refcnt; - atomic64_t usercnt; - struct work_struct work; - struct mutex freeze_mutex; - atomic64_t writecnt; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct btf_header { - __u16 magic; - __u8 version; - __u8 flags; - __u32 hdr_len; - __u32 type_off; - __u32 type_len; - __u32 str_off; - __u32 str_len; -}; - -struct btf { - void *data; - struct btf_type **types; - u32 *resolved_ids; - u32 *resolved_sizes; - const char *strings; - void *nohdr_data; - struct btf_header hdr; - u32 nr_types; - u32 types_size; - u32 data_size; - refcount_t refcnt; - u32 id; - struct callback_head rcu; -}; - -struct btf_type { - __u32 name_off; - __u32 info; - union { - __u32 size; - __u32 type; - }; -}; - -struct bpf_ksym { - long unsigned int start; - long unsigned int end; - char name[128]; - struct list_head lnode; - struct latch_tree_node tnode; - bool prog; -}; - -struct bpf_ctx_arg_aux; - -struct bpf_trampoline; - -struct bpf_jit_poke_descriptor; - -struct bpf_prog_ops; - -struct bpf_prog_offload; - -struct bpf_func_info_aux; - -struct bpf_prog_stats; - -struct bpf_prog_aux { - atomic64_t refcnt; - u32 used_map_cnt; - u32 max_ctx_offset; - u32 max_pkt_offset; - u32 max_tp_access; - u32 stack_depth; - u32 id; - u32 func_cnt; - u32 func_idx; - u32 attach_btf_id; - u32 ctx_arg_info_size; - u32 max_rdonly_access; - u32 max_rdwr_access; - const struct bpf_ctx_arg_aux *ctx_arg_info; - struct mutex dst_mutex; - struct bpf_prog *dst_prog; - struct bpf_trampoline *dst_trampoline; - enum bpf_prog_type saved_dst_prog_type; - enum bpf_attach_type saved_dst_attach_type; - bool verifier_zext; - bool offload_requested; - bool attach_btf_trace; - bool func_proto_unreliable; - bool sleepable; - bool tail_call_reachable; - struct hlist_node tramp_hlist; - const struct btf_type *attach_func_proto; - const char *attach_func_name; - struct bpf_prog **func; - void *jit_data; - struct bpf_jit_poke_descriptor *poke_tab; - u32 size_poke_tab; - struct bpf_ksym ksym; - const struct bpf_prog_ops *ops; - struct bpf_map **used_maps; - struct mutex used_maps_mutex; - struct bpf_prog *prog; - struct user_struct *user; - u64 load_time; - struct bpf_map *cgroup_storage[2]; - char name[16]; - void *security; - struct bpf_prog_offload *offload; - struct btf *btf; - struct bpf_func_info *func_info; - struct bpf_func_info_aux *func_info_aux; - struct bpf_line_info *linfo; - void **jited_linfo; - u32 func_info_cnt; - u32 nr_linfo; - u32 linfo_idx; - u32 num_exentries; - struct exception_table_entry *extable; - struct bpf_prog_stats *stats; - union { - struct work_struct work; - struct callback_head rcu; - }; -}; - -struct sock_filter { - __u16 code; - __u8 jt; - __u8 jf; - __u32 k; -}; - -struct sock_fprog_kern; - -struct bpf_prog { - u16 pages; - u16 jited: 1; - u16 jit_requested: 1; - u16 gpl_compatible: 1; - u16 cb_access: 1; - u16 dst_needed: 1; - u16 blinded: 1; - u16 is_func: 1; - u16 kprobe_override: 1; - u16 has_callchain_buf: 1; - u16 enforce_expected_attach_type: 1; - u16 call_get_stack: 1; - enum bpf_prog_type type; - enum bpf_attach_type expected_attach_type; - u32 len; - u32 jited_len; - u8 tag[8]; - struct bpf_prog_aux *aux; - struct sock_fprog_kern *orig_prog; - unsigned int (*bpf_func)(const void *, const struct bpf_insn *); - struct sock_filter insns[0]; - struct bpf_insn insnsi[0]; -}; - -struct bpf_offloaded_map; - -struct bpf_map_dev_ops { - int (*map_get_next_key)(struct bpf_offloaded_map *, void *, void *); - int (*map_lookup_elem)(struct bpf_offloaded_map *, void *, void *); - int (*map_update_elem)(struct bpf_offloaded_map *, void *, void *, u64); - int (*map_delete_elem)(struct bpf_offloaded_map *, void *); -}; - -struct bpf_offloaded_map { - struct bpf_map map; - struct net_device *netdev; - const struct bpf_map_dev_ops *dev_ops; - void *dev_priv; - struct list_head offloads; - long: 64; - long: 64; - long: 64; -}; - -struct net_device_stats { - long unsigned int rx_packets; - long unsigned int tx_packets; - long unsigned int rx_bytes; - long unsigned int tx_bytes; - long unsigned int rx_errors; - long unsigned int tx_errors; - long unsigned int rx_dropped; - long unsigned int tx_dropped; - long unsigned int multicast; - long unsigned int collisions; - long unsigned int rx_length_errors; - long unsigned int rx_over_errors; - long unsigned int rx_crc_errors; - long unsigned int rx_frame_errors; - long unsigned int rx_fifo_errors; - long unsigned int rx_missed_errors; - long unsigned int tx_aborted_errors; - long unsigned int tx_carrier_errors; - long unsigned int tx_fifo_errors; - long unsigned int tx_heartbeat_errors; - long unsigned int tx_window_errors; - long unsigned int rx_compressed; - long unsigned int tx_compressed; -}; - -struct netdev_hw_addr_list { - struct list_head list; - int count; -}; - -struct wpan_dev; - -enum rx_handler_result { - RX_HANDLER_CONSUMED = 0, - RX_HANDLER_ANOTHER = 1, - RX_HANDLER_EXACT = 2, - RX_HANDLER_PASS = 3, -}; - -typedef enum rx_handler_result rx_handler_result_t; - -typedef rx_handler_result_t rx_handler_func_t(struct sk_buff **); - -enum netdev_ml_priv_type { - ML_PRIV_NONE = 0, - ML_PRIV_CAN = 1, -}; - -struct pcpu_dstats; - -struct garp_port; - -struct netdev_tc_txq { - u16 count; - u16 offset; -}; - -struct sfp_bus; - -struct udp_tunnel_nic; - -struct bpf_xdp_link; - -struct bpf_xdp_entity { - struct bpf_prog *prog; - struct bpf_xdp_link *link; -}; - -struct netdev_name_node; - -struct dev_ifalias; - -struct iw_handler_def; - -struct iw_public_data; - -struct net_device_ops; - -struct ethtool_ops; - -struct l3mdev_ops; - -struct ndisc_ops; - -struct xfrmdev_ops; - -struct header_ops; - -struct vlan_info; - -struct in_device; - -struct inet6_dev; - -struct wireless_dev; - -struct netdev_rx_queue; - -struct mini_Qdisc; - -struct netdev_queue; - -struct cpu_rmap; - -struct Qdisc; - -struct xdp_dev_bulk_queue; - -struct xps_dev_maps; - -struct netpoll_info; - -struct pcpu_lstats; - -struct pcpu_sw_netstats; - -struct rtnl_link_ops; - -struct netprio_map; - -struct phy_device; - -struct udp_tunnel_nic_info; - -struct net_device { - char name[16]; - struct netdev_name_node *name_node; - struct dev_ifalias *ifalias; - long unsigned int mem_end; - long unsigned int mem_start; - long unsigned int base_addr; - int irq; - long unsigned int state; - struct list_head dev_list; - struct list_head napi_list; - struct list_head unreg_list; - struct list_head close_list; - struct list_head ptype_all; - struct list_head ptype_specific; - struct { - struct list_head upper; - struct list_head lower; - } adj_list; - netdev_features_t features; - netdev_features_t hw_features; - netdev_features_t wanted_features; - netdev_features_t vlan_features; - netdev_features_t hw_enc_features; - netdev_features_t mpls_features; - netdev_features_t gso_partial_features; - int ifindex; - int group; - struct net_device_stats stats; - atomic_long_t rx_dropped; - atomic_long_t tx_dropped; - atomic_long_t rx_nohandler; - atomic_t carrier_up_count; - atomic_t carrier_down_count; - const struct iw_handler_def *wireless_handlers; - struct iw_public_data *wireless_data; - const struct net_device_ops *netdev_ops; - const struct ethtool_ops *ethtool_ops; - const struct l3mdev_ops *l3mdev_ops; - const struct ndisc_ops *ndisc_ops; - const struct xfrmdev_ops *xfrmdev_ops; - const struct header_ops *header_ops; - unsigned int flags; - unsigned int priv_flags; - short unsigned int gflags; - short unsigned int padded; - unsigned char operstate; - unsigned char link_mode; - unsigned char if_port; - unsigned char dma; - unsigned int mtu; - unsigned int min_mtu; - unsigned int max_mtu; - short unsigned int type; - short unsigned int hard_header_len; - unsigned char min_header_len; - unsigned char name_assign_type; - short unsigned int needed_headroom; - short unsigned int needed_tailroom; - unsigned char perm_addr[32]; - unsigned char addr_assign_type; - unsigned char addr_len; - unsigned char upper_level; - unsigned char lower_level; - short unsigned int neigh_priv_len; - short unsigned int dev_id; - short unsigned int dev_port; - spinlock_t addr_list_lock; - struct netdev_hw_addr_list uc; - struct netdev_hw_addr_list mc; - struct netdev_hw_addr_list dev_addrs; - struct kset *queues_kset; - unsigned int promiscuity; - unsigned int allmulti; - bool uc_promisc; - struct vlan_info *vlan_info; - struct in_device *ip_ptr; - struct inet6_dev *ip6_ptr; - struct wireless_dev *ieee80211_ptr; - struct wpan_dev *ieee802154_ptr; - unsigned char *dev_addr; - struct netdev_rx_queue *_rx; - unsigned int num_rx_queues; - unsigned int real_num_rx_queues; - struct bpf_prog *xdp_prog; - long unsigned int gro_flush_timeout; - int napi_defer_hard_irqs; - rx_handler_func_t *rx_handler; - void *rx_handler_data; - struct mini_Qdisc *miniq_ingress; - struct netdev_queue *ingress_queue; - struct nf_hook_entries *nf_hooks_ingress; - unsigned char broadcast[32]; - struct cpu_rmap *rx_cpu_rmap; - struct hlist_node index_hlist; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct netdev_queue *_tx; - unsigned int num_tx_queues; - unsigned int real_num_tx_queues; - struct Qdisc *qdisc; - unsigned int tx_queue_len; - spinlock_t tx_global_lock; - struct xdp_dev_bulk_queue *xdp_bulkq; - struct xps_dev_maps *xps_cpus_map; - struct xps_dev_maps *xps_rxqs_map; - struct mini_Qdisc *miniq_egress; - struct hlist_head qdisc_hash[16]; - struct timer_list watchdog_timer; - int watchdog_timeo; - u32 proto_down_reason; - struct list_head todo_list; - int *pcpu_refcnt; - struct list_head link_watch_list; - enum { - NETREG_UNINITIALIZED = 0, - NETREG_REGISTERED = 1, - NETREG_UNREGISTERING = 2, - NETREG_UNREGISTERED = 3, - NETREG_RELEASED = 4, - NETREG_DUMMY = 5, - } reg_state: 8; - bool dismantle; - enum { - RTNL_LINK_INITIALIZED = 0, - RTNL_LINK_INITIALIZING = 1, - } rtnl_link_state: 16; - bool needs_free_netdev; - void (*priv_destructor)(struct net_device *); - struct netpoll_info *npinfo; - possible_net_t nd_net; - void *ml_priv; - enum netdev_ml_priv_type ml_priv_type; - union { - struct pcpu_lstats *lstats; - struct pcpu_sw_netstats *tstats; - struct pcpu_dstats *dstats; - }; - struct garp_port *garp_port; - struct device dev; - const struct attribute_group *sysfs_groups[4]; - const struct attribute_group *sysfs_rx_queue_group; - const struct rtnl_link_ops *rtnl_link_ops; - unsigned int gso_max_size; - u16 gso_max_segs; - s16 num_tc; - struct netdev_tc_txq tc_to_txq[16]; - u8 prio_tc_map[16]; - struct netprio_map *priomap; - struct phy_device *phydev; - struct sfp_bus *sfp_bus; - struct lock_class_key *qdisc_tx_busylock; - struct lock_class_key *qdisc_running_key; - bool proto_down; - unsigned int wol_enabled: 1; - struct list_head net_notifier_list; - const struct udp_tunnel_nic_info *udp_tunnel_nic_info; - struct udp_tunnel_nic *udp_tunnel_nic; - struct bpf_xdp_entity xdp_state[3]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum bpf_reg_type { - NOT_INIT = 0, - SCALAR_VALUE = 1, - PTR_TO_CTX = 2, - CONST_PTR_TO_MAP = 3, - PTR_TO_MAP_VALUE = 4, - PTR_TO_MAP_VALUE_OR_NULL = 5, - PTR_TO_STACK = 6, - PTR_TO_PACKET_META = 7, - PTR_TO_PACKET = 8, - PTR_TO_PACKET_END = 9, - PTR_TO_FLOW_KEYS = 10, - PTR_TO_SOCKET = 11, - PTR_TO_SOCKET_OR_NULL = 12, - PTR_TO_SOCK_COMMON = 13, - PTR_TO_SOCK_COMMON_OR_NULL = 14, - PTR_TO_TCP_SOCK = 15, - PTR_TO_TCP_SOCK_OR_NULL = 16, - PTR_TO_TP_BUFFER = 17, - PTR_TO_XDP_SOCK = 18, - PTR_TO_BTF_ID = 19, - PTR_TO_BTF_ID_OR_NULL = 20, - PTR_TO_MEM = 21, - PTR_TO_MEM_OR_NULL = 22, - PTR_TO_RDONLY_BUF = 23, - PTR_TO_RDONLY_BUF_OR_NULL = 24, - PTR_TO_RDWR_BUF = 25, - PTR_TO_RDWR_BUF_OR_NULL = 26, - PTR_TO_PERCPU_BTF_ID = 27, -}; - -struct bpf_prog_ops { - int (*test_run)(struct bpf_prog *, const union bpf_attr *, union bpf_attr *); -}; - -struct bpf_offload_dev; - -struct bpf_prog_offload { - struct bpf_prog *prog; - struct net_device *netdev; - struct bpf_offload_dev *offdev; - void *dev_priv; - struct list_head offloads; - bool dev_state; - bool opt_failed; - void *jited_image; - u32 jited_len; -}; - -struct bpf_prog_stats { - u64 cnt; - u64 nsecs; - struct u64_stats_sync syncp; -}; - -struct btf_func_model { - u8 ret_size; - u8 nr_args; - u8 arg_size[12]; -}; - -struct bpf_tramp_image { - void *image; - struct bpf_ksym ksym; - struct percpu_ref pcref; - void *ip_after_call; - void *ip_epilogue; - union { - struct callback_head rcu; - struct work_struct work; - }; -}; - -struct bpf_trampoline { - struct hlist_node hlist; - struct mutex mutex; - refcount_t refcnt; - u64 key; - struct { - struct btf_func_model model; - void *addr; - bool ftrace_managed; - } func; - struct bpf_prog *extension_prog; - struct hlist_head progs_hlist[3]; - int progs_cnt[3]; - struct bpf_tramp_image *cur_image; - u64 selector; -}; - -struct bpf_func_info_aux { - u16 linkage; - bool unreliable; -}; - -struct bpf_jit_poke_descriptor { - void *tailcall_target; - void *tailcall_bypass; - void *bypass_addr; - void *aux; - union { - struct { - struct bpf_map *map; - u32 key; - } tail_call; - }; - bool tailcall_target_stable; - u8 adj_off; - u16 reason; - u32 insn_idx; -}; - -struct bpf_ctx_arg_aux { - u32 offset; - enum bpf_reg_type reg_type; - u32 btf_id; -}; - -typedef unsigned int sk_buff_data_t; - -struct skb_ext; - -struct sk_buff { - union { - struct { - struct sk_buff *next; - struct sk_buff *prev; - union { - struct net_device *dev; - long unsigned int dev_scratch; - }; - }; - struct rb_node rbnode; - struct list_head list; - }; - union { - struct sock *sk; - int ip_defrag_offset; - }; - union { - ktime_t tstamp; - u64 skb_mstamp_ns; - }; - char cb[48]; - union { - struct { - long unsigned int _skb_refdst; - void (*destructor)(struct sk_buff *); - }; - struct list_head tcp_tsorted_anchor; - }; - long unsigned int _nfct; - unsigned int len; - unsigned int data_len; - __u16 mac_len; - __u16 hdr_len; - __u16 queue_mapping; - __u8 __cloned_offset[0]; - __u8 cloned: 1; - __u8 nohdr: 1; - __u8 fclone: 2; - __u8 peeked: 1; - __u8 head_frag: 1; - __u8 pfmemalloc: 1; - __u8 active_extensions; - __u32 headers_start[0]; - __u8 __pkt_type_offset[0]; - __u8 pkt_type: 3; - __u8 ignore_df: 1; - __u8 nf_trace: 1; - __u8 ip_summed: 2; - __u8 ooo_okay: 1; - __u8 l4_hash: 1; - __u8 sw_hash: 1; - __u8 wifi_acked_valid: 1; - __u8 wifi_acked: 1; - __u8 no_fcs: 1; - __u8 encapsulation: 1; - __u8 encap_hdr_csum: 1; - __u8 csum_valid: 1; - __u8 __pkt_vlan_present_offset[0]; - __u8 vlan_present: 1; - __u8 csum_complete_sw: 1; - __u8 csum_level: 2; - __u8 csum_not_inet: 1; - __u8 dst_pending_confirm: 1; - __u8 ndisc_nodetype: 2; - __u8 ipvs_property: 1; - __u8 inner_protocol_type: 1; - __u8 remcsum_offload: 1; - __u8 tc_skip_classify: 1; - __u8 tc_at_ingress: 1; - __u8 redirected: 1; - __u8 from_ingress: 1; - __u16 tc_index; - union { - __wsum csum; - struct { - __u16 csum_start; - __u16 csum_offset; - }; - }; - __u32 priority; - int skb_iif; - __u32 hash; - __be16 vlan_proto; - __u16 vlan_tci; - union { - unsigned int napi_id; - unsigned int sender_cpu; - }; - union { - __u32 mark; - __u32 reserved_tailroom; - }; - union { - __be16 inner_protocol; - __u8 inner_ipproto; - }; - __u16 inner_transport_header; - __u16 inner_network_header; - __u16 inner_mac_header; - __be16 protocol; - __u16 transport_header; - __u16 network_header; - __u16 mac_header; - __u32 headers_end[0]; - sk_buff_data_t tail; - sk_buff_data_t end; - unsigned char *head; - unsigned char *data; - unsigned int truesize; - refcount_t users; - struct skb_ext *extensions; -}; - -enum { - Root_NFS = 255, - Root_CIFS = 254, - Root_RAM0 = 1048576, - Root_RAM1 = 1048577, - Root_FD0 = 2097152, - Root_HDA1 = 3145729, - Root_HDA2 = 3145730, - Root_SDA1 = 8388609, - Root_SDA2 = 8388610, - Root_HDC1 = 23068673, - Root_SR0 = 11534336, -}; - -struct ethhdr { - unsigned char h_dest[6]; - unsigned char h_source[6]; - __be16 h_proto; -}; - -struct flowi_tunnel { - __be64 tun_id; -}; - -struct flowi_common { - int flowic_oif; - int flowic_iif; - __u32 flowic_mark; - __u8 flowic_tos; - __u8 flowic_scope; - __u8 flowic_proto; - __u8 flowic_flags; - __u32 flowic_secid; - kuid_t flowic_uid; - struct flowi_tunnel flowic_tun_key; - __u32 flowic_multipath_hash; -}; - -union flowi_uli { - struct { - __be16 dport; - __be16 sport; - } ports; - struct { - __u8 type; - __u8 code; - } icmpt; - struct { - __le16 dport; - __le16 sport; - } dnports; - __be32 spi; - __be32 gre_key; - struct { - __u8 type; - } mht; -}; - -struct flowi4 { - struct flowi_common __fl_common; - __be32 saddr; - __be32 daddr; - union flowi_uli uli; -}; - -struct flowi6 { - struct flowi_common __fl_common; - struct in6_addr daddr; - struct in6_addr saddr; - __be32 flowlabel; - union flowi_uli uli; - __u32 mp_hash; -}; - -struct flowidn { - struct flowi_common __fl_common; - __le16 daddr; - __le16 saddr; - union flowi_uli uli; -}; - -struct flowi { - union { - struct flowi_common __fl_common; - struct flowi4 ip4; - struct flowi6 ip6; - struct flowidn dn; - } u; -}; - -struct ipstats_mib { - u64 mibs[37]; - struct u64_stats_sync syncp; -}; - -struct icmp_mib { - long unsigned int mibs[28]; -}; - -struct icmpmsg_mib { - atomic_long_t mibs[512]; -}; - -struct icmpv6_mib { - long unsigned int mibs[6]; -}; - -struct icmpv6_mib_device { - atomic_long_t mibs[6]; -}; - -struct icmpv6msg_mib { - atomic_long_t mibs[512]; -}; - -struct icmpv6msg_mib_device { - atomic_long_t mibs[512]; -}; - -struct tcp_mib { - long unsigned int mibs[16]; -}; - -struct udp_mib { - long unsigned int mibs[9]; -}; - -struct linux_mib { - long unsigned int mibs[124]; -}; - -struct inet_frags; - -struct fqdir { - long int high_thresh; - long int low_thresh; - int timeout; - int max_dist; - struct inet_frags *f; - struct net *net; - bool dead; - long: 56; - long: 64; - long: 64; - struct rhashtable rhashtable; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - atomic_long_t mem; - struct work_struct destroy_work; - long: 64; - long: 64; - long: 64; -}; - -struct inet_frag_queue; - -struct inet_frags { - unsigned int qsize; - void (*constructor)(struct inet_frag_queue *, const void *); - void (*destructor)(struct inet_frag_queue *); - void (*frag_expire)(struct timer_list *); - struct kmem_cache *frags_cachep; - const char *frags_cache_name; - struct rhashtable_params rhash_params; - refcount_t refcnt; - struct completion completion; -}; - -struct frag_v4_compare_key { - __be32 saddr; - __be32 daddr; - u32 user; - u32 vif; - __be16 id; - u16 protocol; -}; - -struct frag_v6_compare_key { - struct in6_addr saddr; - struct in6_addr daddr; - u32 user; - __be32 id; - u32 iif; -}; - -struct inet_frag_queue { - struct rhash_head node; - union { - struct frag_v4_compare_key v4; - struct frag_v6_compare_key v6; - } key; - struct timer_list timer; - spinlock_t lock; - refcount_t refcnt; - struct rb_root rb_fragments; - struct sk_buff *fragments_tail; - struct sk_buff *last_run_head; - ktime_t stamp; - int len; - int meat; - __u8 flags; - u16 max_size; - struct fqdir *fqdir; - struct callback_head rcu; -}; - -struct fib_rule; - -struct fib_lookup_arg; - -struct fib_rule_hdr; - -struct nlattr; - -struct netlink_ext_ack; - -struct nla_policy; - -struct fib_rules_ops { - int family; - struct list_head list; - int rule_size; - int addr_size; - int unresolved_rules; - int nr_goto_rules; - unsigned int fib_rules_seq; - int (*action)(struct fib_rule *, struct flowi *, int, struct fib_lookup_arg *); - bool (*suppress)(struct fib_rule *, int, struct fib_lookup_arg *); - int (*match)(struct fib_rule *, struct flowi *, int); - int (*configure)(struct fib_rule *, struct sk_buff *, struct fib_rule_hdr *, struct nlattr **, struct netlink_ext_ack *); - int (*delete)(struct fib_rule *); - int (*compare)(struct fib_rule *, struct fib_rule_hdr *, struct nlattr **); - int (*fill)(struct fib_rule *, struct sk_buff *, struct fib_rule_hdr *); - size_t (*nlmsg_payload)(struct fib_rule *); - void (*flush_cache)(struct fib_rules_ops *); - int nlgroup; - const struct nla_policy *policy; - struct list_head rules_list; - struct module *owner; - struct net *fro_net; - struct callback_head rcu; -}; - -enum tcp_ca_event { - CA_EVENT_TX_START = 0, - CA_EVENT_CWND_RESTART = 1, - CA_EVENT_COMPLETE_CWR = 2, - CA_EVENT_LOSS = 3, - CA_EVENT_ECN_NO_CE = 4, - CA_EVENT_ECN_IS_CE = 5, -}; - -struct ack_sample; - -struct rate_sample; - -union tcp_cc_info; - -struct tcp_congestion_ops { - struct list_head list; - u32 key; - u32 flags; - void (*init)(struct sock *); - void (*release)(struct sock *); - u32 (*ssthresh)(struct sock *); - void (*cong_avoid)(struct sock *, u32, u32); - void (*set_state)(struct sock *, u8); - void (*cwnd_event)(struct sock *, enum tcp_ca_event); - void (*in_ack_event)(struct sock *, u32); - u32 (*undo_cwnd)(struct sock *); - void (*pkts_acked)(struct sock *, const struct ack_sample *); - u32 (*min_tso_segs)(struct sock *); - u32 (*sndbuf_expand)(struct sock *); - void (*cong_control)(struct sock *, const struct rate_sample *); - size_t (*get_info)(struct sock *, u32, int *, union tcp_cc_info *); - char name[16]; - struct module *owner; -}; - -struct fib_notifier_ops { - int family; - struct list_head list; - unsigned int (*fib_seq_read)(struct net *); - int (*fib_dump)(struct net *, struct notifier_block *, struct netlink_ext_ack *); - struct module *owner; - struct callback_head rcu; -}; - -struct xfrm_state; - -struct lwtunnel_state; - -struct dst_entry { - struct net_device *dev; - struct dst_ops *ops; - long unsigned int _metrics; - long unsigned int expires; - struct xfrm_state *xfrm; - int (*input)(struct sk_buff *); - int (*output)(struct net *, struct sock *, struct sk_buff *); - short unsigned int flags; - short int obsolete; - short unsigned int header_len; - short unsigned int trailer_len; - atomic_t __refcnt; - int __use; - long unsigned int lastuse; - struct lwtunnel_state *lwtstate; - struct callback_head callback_head; - short int error; - short int __pad; - __u32 tclassid; -}; - -struct hh_cache { - unsigned int hh_len; - seqlock_t hh_lock; - long unsigned int hh_data[16]; -}; - -struct neigh_table; - -struct neigh_parms; - -struct neigh_ops; - -struct neighbour { - struct neighbour *next; - struct neigh_table *tbl; - struct neigh_parms *parms; - long unsigned int confirmed; - long unsigned int updated; - rwlock_t lock; - refcount_t refcnt; - unsigned int arp_queue_len_bytes; - struct sk_buff_head arp_queue; - struct timer_list timer; - long unsigned int used; - atomic_t probes; - __u8 flags; - __u8 nud_state; - __u8 type; - __u8 dead; - u8 protocol; - seqlock_t ha_lock; - int: 32; - unsigned char ha[32]; - struct hh_cache hh; - int (*output)(struct neighbour *, struct sk_buff *); - const struct neigh_ops *ops; - struct list_head gc_list; - struct callback_head rcu; - struct net_device *dev; - u8 primary_key[0]; -}; - -struct ipv6_stable_secret { - bool initialized; - struct in6_addr secret; -}; - -struct ipv6_devconf { - __s32 forwarding; - __s32 hop_limit; - __s32 mtu6; - __s32 accept_ra; - __s32 accept_redirects; - __s32 autoconf; - __s32 dad_transmits; - __s32 rtr_solicits; - __s32 rtr_solicit_interval; - __s32 rtr_solicit_max_interval; - __s32 rtr_solicit_delay; - __s32 force_mld_version; - __s32 mldv1_unsolicited_report_interval; - __s32 mldv2_unsolicited_report_interval; - __s32 use_tempaddr; - __s32 temp_valid_lft; - __s32 temp_prefered_lft; - __s32 regen_max_retry; - __s32 max_desync_factor; - __s32 max_addresses; - __s32 accept_ra_defrtr; - __s32 accept_ra_min_hop_limit; - __s32 accept_ra_pinfo; - __s32 ignore_routes_with_linkdown; - __s32 accept_ra_rtr_pref; - __s32 rtr_probe_interval; - __s32 accept_ra_rt_info_min_plen; - __s32 accept_ra_rt_info_max_plen; - __s32 proxy_ndp; - __s32 accept_source_route; - __s32 accept_ra_from_local; - __s32 mc_forwarding; - __s32 disable_ipv6; - __s32 drop_unicast_in_l2_multicast; - __s32 accept_dad; - __s32 force_tllao; - __s32 ndisc_notify; - __s32 suppress_frag_ndisc; - __s32 accept_ra_mtu; - __s32 drop_unsolicited_na; - struct ipv6_stable_secret stable_secret; - __s32 use_oif_addrs_only; - __s32 keep_addr_on_down; - __s32 seg6_enabled; - __u32 enhanced_dad; - __u32 addr_gen_mode; - __s32 disable_policy; - __s32 ndisc_tclass; - __s32 rpl_seg_enabled; - struct ctl_table_header *sysctl_header; -}; - -struct nf_queue_entry; - -struct nf_queue_handler { - int (*outfn)(struct nf_queue_entry *, unsigned int); - void (*nf_hook_drop)(struct net *); -}; - -enum nf_log_type { - NF_LOG_TYPE_LOG = 0, - NF_LOG_TYPE_ULOG = 1, - NF_LOG_TYPE_MAX = 2, -}; - -typedef u8 u_int8_t; - -struct nf_loginfo; - -typedef void nf_logfn(struct net *, u_int8_t, unsigned int, const struct sk_buff *, const struct net_device *, const struct net_device *, const struct nf_loginfo *, const char *); - -struct nf_logger { - char *name; - enum nf_log_type type; - nf_logfn *logfn; - struct module *me; -}; - -struct hlist_nulls_head { - struct hlist_nulls_node *first; -}; - -struct ip_conntrack_stat { - unsigned int found; - unsigned int invalid; - unsigned int insert; - unsigned int insert_failed; - unsigned int clash_resolve; - unsigned int drop; - unsigned int early_drop; - unsigned int error; - unsigned int expect_new; - unsigned int expect_create; - unsigned int expect_delete; - unsigned int search_restart; -}; - -struct ct_pcpu { - spinlock_t lock; - struct hlist_nulls_head unconfirmed; - struct hlist_nulls_head dying; -}; - -typedef struct { - union { - void *kernel; - void *user; - }; - bool is_kernel: 1; -} sockptr_t; - -typedef enum { - SS_FREE = 0, - SS_UNCONNECTED = 1, - SS_CONNECTING = 2, - SS_CONNECTED = 3, - SS_DISCONNECTING = 4, -} socket_state; - -struct socket_wq { - wait_queue_head_t wait; - struct fasync_struct *fasync_list; - long unsigned int flags; - struct callback_head rcu; - long: 64; -}; - -struct proto_ops; - -struct socket { - socket_state state; - short int type; - long unsigned int flags; - struct file *file; - struct sock *sk; - const struct proto_ops *ops; - long: 64; - long: 64; - long: 64; - struct socket_wq wq; -}; - -typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, unsigned int, size_t); - -struct proto_ops { - int family; - unsigned int flags; - struct module *owner; - int (*release)(struct socket *); - int (*bind)(struct socket *, struct sockaddr *, int); - int (*connect)(struct socket *, struct sockaddr *, int, int); - int (*socketpair)(struct socket *, struct socket *); - int (*accept)(struct socket *, struct socket *, int, bool); - int (*getname)(struct socket *, struct sockaddr *, int); - __poll_t (*poll)(struct file *, struct socket *, struct poll_table_struct *); - int (*ioctl)(struct socket *, unsigned int, long unsigned int); - int (*compat_ioctl)(struct socket *, unsigned int, long unsigned int); - int (*gettstamp)(struct socket *, void *, bool, bool); - int (*listen)(struct socket *, int); - int (*shutdown)(struct socket *, int); - int (*setsockopt)(struct socket *, int, int, sockptr_t, unsigned int); - int (*getsockopt)(struct socket *, int, int, char *, int *); - void (*show_fdinfo)(struct seq_file *, struct socket *); - int (*sendmsg)(struct socket *, struct msghdr *, size_t); - int (*recvmsg)(struct socket *, struct msghdr *, size_t, int); - int (*mmap)(struct file *, struct socket *, struct vm_area_struct *); - ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); - ssize_t (*splice_read)(struct socket *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); - int (*set_peek_off)(struct sock *, int); - int (*peek_len)(struct socket *); - int (*read_sock)(struct sock *, read_descriptor_t *, sk_read_actor_t); - int (*sendpage_locked)(struct sock *, struct page *, int, size_t, int); - int (*sendmsg_locked)(struct sock *, struct msghdr *, size_t); - int (*set_rcvlowat)(struct sock *, int); -}; - -struct pipe_buf_operations; - -struct pipe_buffer { - struct page *page; - unsigned int offset; - unsigned int len; - const struct pipe_buf_operations *ops; - unsigned int flags; - long unsigned int private; -}; - -struct pipe_buf_operations { - int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *); - void (*release)(struct pipe_inode_info *, struct pipe_buffer *); - bool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *); - bool (*get)(struct pipe_inode_info *, struct pipe_buffer *); -}; - -struct skb_ext { - refcount_t refcnt; - u8 offset[2]; - u8 chunks; - char: 8; - char data[0]; -}; - -struct dql { - unsigned int num_queued; - unsigned int adj_limit; - unsigned int last_obj_cnt; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - unsigned int limit; - unsigned int num_completed; - unsigned int prev_ovlimit; - unsigned int prev_num_queued; - unsigned int prev_last_obj_cnt; - unsigned int lowest_slack; - long unsigned int slack_start_time; - unsigned int max_limit; - unsigned int min_limit; - unsigned int slack_hold_time; - long: 32; - long: 64; - long: 64; -}; - -struct ethtool_drvinfo { - __u32 cmd; - char driver[32]; - char version[32]; - char fw_version[32]; - char bus_info[32]; - char erom_version[32]; - char reserved2[12]; - __u32 n_priv_flags; - __u32 n_stats; - __u32 testinfo_len; - __u32 eedump_len; - __u32 regdump_len; -}; - -struct ethtool_wolinfo { - __u32 cmd; - __u32 supported; - __u32 wolopts; - __u8 sopass[6]; -}; - -struct ethtool_tunable { - __u32 cmd; - __u32 id; - __u32 type_id; - __u32 len; - void *data[0]; -}; - -struct ethtool_regs { - __u32 cmd; - __u32 version; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_eeprom { - __u32 cmd; - __u32 magic; - __u32 offset; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_eee { - __u32 cmd; - __u32 supported; - __u32 advertised; - __u32 lp_advertised; - __u32 eee_active; - __u32 eee_enabled; - __u32 tx_lpi_enabled; - __u32 tx_lpi_timer; - __u32 reserved[2]; -}; - -struct ethtool_modinfo { - __u32 cmd; - __u32 type; - __u32 eeprom_len; - __u32 reserved[8]; -}; - -struct ethtool_coalesce { - __u32 cmd; - __u32 rx_coalesce_usecs; - __u32 rx_max_coalesced_frames; - __u32 rx_coalesce_usecs_irq; - __u32 rx_max_coalesced_frames_irq; - __u32 tx_coalesce_usecs; - __u32 tx_max_coalesced_frames; - __u32 tx_coalesce_usecs_irq; - __u32 tx_max_coalesced_frames_irq; - __u32 stats_block_coalesce_usecs; - __u32 use_adaptive_rx_coalesce; - __u32 use_adaptive_tx_coalesce; - __u32 pkt_rate_low; - __u32 rx_coalesce_usecs_low; - __u32 rx_max_coalesced_frames_low; - __u32 tx_coalesce_usecs_low; - __u32 tx_max_coalesced_frames_low; - __u32 pkt_rate_high; - __u32 rx_coalesce_usecs_high; - __u32 rx_max_coalesced_frames_high; - __u32 tx_coalesce_usecs_high; - __u32 tx_max_coalesced_frames_high; - __u32 rate_sample_interval; -}; - -struct ethtool_ringparam { - __u32 cmd; - __u32 rx_max_pending; - __u32 rx_mini_max_pending; - __u32 rx_jumbo_max_pending; - __u32 tx_max_pending; - __u32 rx_pending; - __u32 rx_mini_pending; - __u32 rx_jumbo_pending; - __u32 tx_pending; -}; - -struct ethtool_channels { - __u32 cmd; - __u32 max_rx; - __u32 max_tx; - __u32 max_other; - __u32 max_combined; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -struct ethtool_pauseparam { - __u32 cmd; - __u32 autoneg; - __u32 rx_pause; - __u32 tx_pause; -}; - -enum ethtool_link_ext_state { - ETHTOOL_LINK_EXT_STATE_AUTONEG = 0, - ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE = 1, - ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH = 2, - ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY = 3, - ETHTOOL_LINK_EXT_STATE_NO_CABLE = 4, - ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE = 5, - ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE = 6, - ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE = 7, - ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED = 8, - ETHTOOL_LINK_EXT_STATE_OVERHEAT = 9, -}; - -enum ethtool_link_ext_substate_autoneg { - ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED = 1, - ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED = 2, - ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED = 3, - ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE = 4, - ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE = 5, - ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD = 6, -}; - -enum ethtool_link_ext_substate_link_training { - ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED = 1, - ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT = 2, - ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY = 3, - ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT = 4, -}; - -enum ethtool_link_ext_substate_link_logical_mismatch { - ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK = 1, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK = 2, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS = 3, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED = 4, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED = 5, -}; - -enum ethtool_link_ext_substate_bad_signal_integrity { - ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS = 1, - ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE = 2, -}; - -enum ethtool_link_ext_substate_cable_issue { - ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE = 1, - ETHTOOL_LINK_EXT_SUBSTATE_CI_CABLE_TEST_FAILURE = 2, -}; - -struct ethtool_test { - __u32 cmd; - __u32 flags; - __u32 reserved; - __u32 len; - __u64 data[0]; -}; - -struct ethtool_stats { - __u32 cmd; - __u32 n_stats; - __u64 data[0]; -}; - -struct ethtool_tcpip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be16 psrc; - __be16 pdst; - __u8 tos; -}; - -struct ethtool_ah_espip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be32 spi; - __u8 tos; -}; - -struct ethtool_usrip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be32 l4_4_bytes; - __u8 tos; - __u8 ip_ver; - __u8 proto; -}; - -struct ethtool_tcpip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be16 psrc; - __be16 pdst; - __u8 tclass; -}; - -struct ethtool_ah_espip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be32 spi; - __u8 tclass; -}; - -struct ethtool_usrip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be32 l4_4_bytes; - __u8 tclass; - __u8 l4_proto; -}; - -union ethtool_flow_union { - struct ethtool_tcpip4_spec tcp_ip4_spec; - struct ethtool_tcpip4_spec udp_ip4_spec; - struct ethtool_tcpip4_spec sctp_ip4_spec; - struct ethtool_ah_espip4_spec ah_ip4_spec; - struct ethtool_ah_espip4_spec esp_ip4_spec; - struct ethtool_usrip4_spec usr_ip4_spec; - struct ethtool_tcpip6_spec tcp_ip6_spec; - struct ethtool_tcpip6_spec udp_ip6_spec; - struct ethtool_tcpip6_spec sctp_ip6_spec; - struct ethtool_ah_espip6_spec ah_ip6_spec; - struct ethtool_ah_espip6_spec esp_ip6_spec; - struct ethtool_usrip6_spec usr_ip6_spec; - struct ethhdr ether_spec; - __u8 hdata[52]; -}; - -struct ethtool_flow_ext { - __u8 padding[2]; - unsigned char h_dest[6]; - __be16 vlan_etype; - __be16 vlan_tci; - __be32 data[2]; -}; - -struct ethtool_rx_flow_spec { - __u32 flow_type; - union ethtool_flow_union h_u; - struct ethtool_flow_ext h_ext; - union ethtool_flow_union m_u; - struct ethtool_flow_ext m_ext; - __u64 ring_cookie; - __u32 location; -}; - -struct ethtool_rxnfc { - __u32 cmd; - __u32 flow_type; - __u64 data; - struct ethtool_rx_flow_spec fs; - union { - __u32 rule_cnt; - __u32 rss_context; - }; - __u32 rule_locs[0]; -}; - -struct ethtool_flash { - __u32 cmd; - __u32 region; - char data[128]; -}; - -struct ethtool_dump { - __u32 cmd; - __u32 version; - __u32 flag; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_ts_info { - __u32 cmd; - __u32 so_timestamping; - __s32 phc_index; - __u32 tx_types; - __u32 tx_reserved[3]; - __u32 rx_filters; - __u32 rx_reserved[3]; -}; - -struct ethtool_fecparam { - __u32 cmd; - __u32 active_fec; - __u32 fec; - __u32 reserved; -}; - -struct ethtool_link_settings { - __u32 cmd; - __u32 speed; - __u8 duplex; - __u8 port; - __u8 phy_address; - __u8 autoneg; - __u8 mdio_support; - __u8 eth_tp_mdix; - __u8 eth_tp_mdix_ctrl; - __s8 link_mode_masks_nwords; - __u8 transceiver; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u8 reserved1[1]; - __u32 reserved[7]; - __u32 link_mode_masks[0]; -}; - -enum ethtool_phys_id_state { - ETHTOOL_ID_INACTIVE = 0, - ETHTOOL_ID_ACTIVE = 1, - ETHTOOL_ID_ON = 2, - ETHTOOL_ID_OFF = 3, -}; - -struct ethtool_link_ext_state_info { - enum ethtool_link_ext_state link_ext_state; - union { - enum ethtool_link_ext_substate_autoneg autoneg; - enum ethtool_link_ext_substate_link_training link_training; - enum ethtool_link_ext_substate_link_logical_mismatch link_logical_mismatch; - enum ethtool_link_ext_substate_bad_signal_integrity bad_signal_integrity; - enum ethtool_link_ext_substate_cable_issue cable_issue; - u8 __link_ext_substate; - }; -}; - -struct ethtool_link_ksettings { - struct ethtool_link_settings base; - struct { - long unsigned int supported[2]; - long unsigned int advertising[2]; - long unsigned int lp_advertising[2]; - } link_modes; -}; - -struct ethtool_pause_stats { - u64 tx_pause_frames; - u64 rx_pause_frames; -}; - -struct ethtool_ops { - u32 supported_coalesce_params; - void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); - int (*get_regs_len)(struct net_device *); - void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); - void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); - int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); - u32 (*get_msglevel)(struct net_device *); - void (*set_msglevel)(struct net_device *, u32); - int (*nway_reset)(struct net_device *); - u32 (*get_link)(struct net_device *); - int (*get_link_ext_state)(struct net_device *, struct ethtool_link_ext_state_info *); - int (*get_eeprom_len)(struct net_device *); - int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); - int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); - int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); - int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); - void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *); - int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *); - void (*get_pause_stats)(struct net_device *, struct ethtool_pause_stats *); - void (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam *); - int (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam *); - void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); - void (*get_strings)(struct net_device *, u32, u8 *); - int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state); - void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); - int (*begin)(struct net_device *); - void (*complete)(struct net_device *); - u32 (*get_priv_flags)(struct net_device *); - int (*set_priv_flags)(struct net_device *, u32); - int (*get_sset_count)(struct net_device *, int); - int (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, u32 *); - int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); - int (*flash_device)(struct net_device *, struct ethtool_flash *); - int (*reset)(struct net_device *, u32 *); - u32 (*get_rxfh_key_size)(struct net_device *); - u32 (*get_rxfh_indir_size)(struct net_device *); - int (*get_rxfh)(struct net_device *, u32 *, u8 *, u8 *); - int (*set_rxfh)(struct net_device *, const u32 *, const u8 *, const u8); - int (*get_rxfh_context)(struct net_device *, u32 *, u8 *, u8 *, u32); - int (*set_rxfh_context)(struct net_device *, const u32 *, const u8 *, const u8, u32 *, bool); - void (*get_channels)(struct net_device *, struct ethtool_channels *); - int (*set_channels)(struct net_device *, struct ethtool_channels *); - int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); - int (*get_dump_data)(struct net_device *, struct ethtool_dump *, void *); - int (*set_dump)(struct net_device *, struct ethtool_dump *); - int (*get_ts_info)(struct net_device *, struct ethtool_ts_info *); - int (*get_module_info)(struct net_device *, struct ethtool_modinfo *); - int (*get_module_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); - int (*get_eee)(struct net_device *, struct ethtool_eee *); - int (*set_eee)(struct net_device *, struct ethtool_eee *); - int (*get_tunable)(struct net_device *, const struct ethtool_tunable *, void *); - int (*set_tunable)(struct net_device *, const struct ethtool_tunable *, const void *); - int (*get_per_queue_coalesce)(struct net_device *, u32, struct ethtool_coalesce *); - int (*set_per_queue_coalesce)(struct net_device *, u32, struct ethtool_coalesce *); - int (*get_link_ksettings)(struct net_device *, struct ethtool_link_ksettings *); - int (*set_link_ksettings)(struct net_device *, const struct ethtool_link_ksettings *); - int (*get_fecparam)(struct net_device *, struct ethtool_fecparam *); - int (*set_fecparam)(struct net_device *, struct ethtool_fecparam *); - void (*get_ethtool_phy_stats)(struct net_device *, struct ethtool_stats *, u64 *); - int (*get_phy_tunable)(struct net_device *, const struct ethtool_tunable *, void *); - int (*set_phy_tunable)(struct net_device *, const struct ethtool_tunable *, const void *); -}; - -struct netlink_ext_ack { - const char *_msg; - const struct nlattr *bad_attr; - const struct nla_policy *policy; - u8 cookie[20]; - u8 cookie_len; -}; - -struct netprio_map { - struct callback_head rcu; - u32 priomap_len; - u32 priomap[0]; -}; - -struct xdp_mem_info { - u32 type; - u32 id; -}; - -struct xdp_rxq_info { - struct net_device *dev; - u32 queue_index; - u32 reg_state; - struct xdp_mem_info mem; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct xdp_frame { - void *data; - u16 len; - u16 headroom; - u32 metasize: 8; - u32 frame_sz: 24; - struct xdp_mem_info mem; - struct net_device *dev_rx; -}; - -struct nlmsghdr { - __u32 nlmsg_len; - __u16 nlmsg_type; - __u16 nlmsg_flags; - __u32 nlmsg_seq; - __u32 nlmsg_pid; -}; - -struct nlattr { - __u16 nla_len; - __u16 nla_type; -}; - -struct netlink_range_validation; - -struct netlink_range_validation_signed; - -struct nla_policy { - u8 type; - u8 validation_type; - u16 len; - union { - const u32 bitfield32_valid; - const u32 mask; - const char *reject_message; - const struct nla_policy *nested_policy; - struct netlink_range_validation *range; - struct netlink_range_validation_signed *range_signed; - struct { - s16 min; - s16 max; - }; - int (*validate)(const struct nlattr *, struct netlink_ext_ack *); - u16 strict_start_type; - }; -}; - -struct netlink_callback { - struct sk_buff *skb; - const struct nlmsghdr *nlh; - int (*dump)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - void *data; - struct module *module; - struct netlink_ext_ack *extack; - u16 family; - u16 answer_flags; - u32 min_dump_alloc; - unsigned int prev_seq; - unsigned int seq; - bool strict_check; - union { - u8 ctx[48]; - long int args[6]; - }; -}; - -struct ndmsg { - __u8 ndm_family; - __u8 ndm_pad1; - __u16 ndm_pad2; - __s32 ndm_ifindex; - __u16 ndm_state; - __u8 ndm_flags; - __u8 ndm_type; -}; - -struct rtnl_link_stats64 { - __u64 rx_packets; - __u64 tx_packets; - __u64 rx_bytes; - __u64 tx_bytes; - __u64 rx_errors; - __u64 tx_errors; - __u64 rx_dropped; - __u64 tx_dropped; - __u64 multicast; - __u64 collisions; - __u64 rx_length_errors; - __u64 rx_over_errors; - __u64 rx_crc_errors; - __u64 rx_frame_errors; - __u64 rx_fifo_errors; - __u64 rx_missed_errors; - __u64 tx_aborted_errors; - __u64 tx_carrier_errors; - __u64 tx_fifo_errors; - __u64 tx_heartbeat_errors; - __u64 tx_window_errors; - __u64 rx_compressed; - __u64 tx_compressed; - __u64 rx_nohandler; -}; - -struct ifla_vf_guid { - __u32 vf; - __u64 guid; -}; - -struct ifla_vf_stats { - __u64 rx_packets; - __u64 tx_packets; - __u64 rx_bytes; - __u64 tx_bytes; - __u64 broadcast; - __u64 multicast; - __u64 rx_dropped; - __u64 tx_dropped; -}; - -struct ifla_vf_info { - __u32 vf; - __u8 mac[32]; - __u32 vlan; - __u32 qos; - __u32 spoofchk; - __u32 linkstate; - __u32 min_tx_rate; - __u32 max_tx_rate; - __u32 rss_query_en; - __u32 trusted; - __be16 vlan_proto; -}; - -struct tc_stats { - __u64 bytes; - __u32 packets; - __u32 drops; - __u32 overlimits; - __u32 bps; - __u32 pps; - __u32 qlen; - __u32 backlog; -}; - -struct tc_sizespec { - unsigned char cell_log; - unsigned char size_log; - short int cell_align; - int overhead; - unsigned int linklayer; - unsigned int mpu; - unsigned int mtu; - unsigned int tsize; -}; - -enum netdev_tx { - __NETDEV_TX_MIN = 2147483648, - NETDEV_TX_OK = 0, - NETDEV_TX_BUSY = 16, -}; - -typedef enum netdev_tx netdev_tx_t; - -struct header_ops { - int (*create)(struct sk_buff *, struct net_device *, short unsigned int, const void *, const void *, unsigned int); - int (*parse)(const struct sk_buff *, unsigned char *); - int (*cache)(const struct neighbour *, struct hh_cache *, __be16); - void (*cache_update)(struct hh_cache *, const struct net_device *, const unsigned char *); - bool (*validate)(const char *, unsigned int); - __be16 (*parse_protocol)(const struct sk_buff *); -}; - -struct netdev_queue { - struct net_device *dev; - struct Qdisc *qdisc; - struct Qdisc *qdisc_sleeping; - struct kobject kobj; - long unsigned int tx_maxrate; - long unsigned int trans_timeout; - struct net_device *sb_dev; - long: 64; - long: 64; - spinlock_t _xmit_lock; - int xmit_lock_owner; - long unsigned int trans_start; - long unsigned int state; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct dql dql; -}; - -struct qdisc_skb_head { - struct sk_buff *head; - struct sk_buff *tail; - __u32 qlen; - spinlock_t lock; -}; - -struct gnet_stats_basic_packed { - __u64 bytes; - __u64 packets; -}; - -struct gnet_stats_queue { - __u32 qlen; - __u32 backlog; - __u32 drops; - __u32 requeues; - __u32 overlimits; -}; - -struct Qdisc_ops; - -struct qdisc_size_table; - -struct net_rate_estimator; - -struct gnet_stats_basic_cpu; - -struct Qdisc { - int (*enqueue)(struct sk_buff *, struct Qdisc *, struct sk_buff **); - struct sk_buff * (*dequeue)(struct Qdisc *); - unsigned int flags; - u32 limit; - const struct Qdisc_ops *ops; - struct qdisc_size_table *stab; - struct hlist_node hash; - u32 handle; - u32 parent; - struct netdev_queue *dev_queue; - struct net_rate_estimator *rate_est; - struct gnet_stats_basic_cpu *cpu_bstats; - struct gnet_stats_queue *cpu_qstats; - int pad; - refcount_t refcnt; - long: 64; - long: 64; - long: 64; - struct sk_buff_head gso_skb; - struct qdisc_skb_head q; - struct gnet_stats_basic_packed bstats; - seqcount_t running; - struct gnet_stats_queue qstats; - long unsigned int state; - struct Qdisc *next_sched; - struct sk_buff_head skb_bad_txq; - spinlock_t busylock; - spinlock_t seqlock; - bool empty; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long int privdata[0]; -}; - -struct rps_map { - unsigned int len; - struct callback_head rcu; - u16 cpus[0]; -}; - -struct rps_dev_flow { - u16 cpu; - u16 filter; - unsigned int last_qtail; -}; - -struct rps_dev_flow_table { - unsigned int mask; - struct callback_head rcu; - struct rps_dev_flow flows[0]; -}; - -struct netdev_rx_queue { - struct rps_map *rps_map; - struct rps_dev_flow_table *rps_flow_table; - struct kobject kobj; - struct net_device *dev; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct xdp_rxq_info xdp_rxq; -}; - -struct xps_map { - unsigned int len; - unsigned int alloc_len; - struct callback_head rcu; - u16 queues[0]; -}; - -struct xps_dev_maps { - struct callback_head rcu; - struct xps_map *attr_map[0]; -}; - -struct netdev_phys_item_id { - unsigned char id[32]; - unsigned char id_len; -}; - -enum tc_setup_type { - TC_SETUP_QDISC_MQPRIO = 0, - TC_SETUP_CLSU32 = 1, - TC_SETUP_CLSFLOWER = 2, - TC_SETUP_CLSMATCHALL = 3, - TC_SETUP_CLSBPF = 4, - TC_SETUP_BLOCK = 5, - TC_SETUP_QDISC_CBS = 6, - TC_SETUP_QDISC_RED = 7, - TC_SETUP_QDISC_PRIO = 8, - TC_SETUP_QDISC_MQ = 9, - TC_SETUP_QDISC_ETF = 10, - TC_SETUP_ROOT_QDISC = 11, - TC_SETUP_QDISC_GRED = 12, - TC_SETUP_QDISC_TAPRIO = 13, - TC_SETUP_FT = 14, - TC_SETUP_QDISC_ETS = 15, - TC_SETUP_QDISC_TBF = 16, - TC_SETUP_QDISC_FIFO = 17, -}; - -enum bpf_netdev_command { - XDP_SETUP_PROG = 0, - XDP_SETUP_PROG_HW = 1, - BPF_OFFLOAD_MAP_ALLOC = 2, - BPF_OFFLOAD_MAP_FREE = 3, - XDP_SETUP_XSK_POOL = 4, -}; - -struct xsk_buff_pool; - -struct netdev_bpf { - enum bpf_netdev_command command; - union { - struct { - u32 flags; - struct bpf_prog *prog; - struct netlink_ext_ack *extack; - }; - struct { - struct bpf_offloaded_map *offmap; - }; - struct { - struct xsk_buff_pool *pool; - u16 queue_id; - } xsk; - }; -}; - -struct xfrmdev_ops { - int (*xdo_dev_state_add)(struct xfrm_state *); - void (*xdo_dev_state_delete)(struct xfrm_state *); - void (*xdo_dev_state_free)(struct xfrm_state *); - bool (*xdo_dev_offload_ok)(struct sk_buff *, struct xfrm_state *); - void (*xdo_dev_state_advance_esn)(struct xfrm_state *); -}; - -struct dev_ifalias { - struct callback_head rcuhead; - char ifalias[0]; -}; - -struct netdev_name_node { - struct hlist_node hlist; - struct list_head list; - struct net_device *dev; - const char *name; -}; - -struct udp_tunnel_info; - -struct devlink_port; - -struct ip_tunnel_parm; - -struct net_device_ops { - int (*ndo_init)(struct net_device *); - void (*ndo_uninit)(struct net_device *); - int (*ndo_open)(struct net_device *); - int (*ndo_stop)(struct net_device *); - netdev_tx_t (*ndo_start_xmit)(struct sk_buff *, struct net_device *); - netdev_features_t (*ndo_features_check)(struct sk_buff *, struct net_device *, netdev_features_t); - u16 (*ndo_select_queue)(struct net_device *, struct sk_buff *, struct net_device *); - void (*ndo_change_rx_flags)(struct net_device *, int); - void (*ndo_set_rx_mode)(struct net_device *); - int (*ndo_set_mac_address)(struct net_device *, void *); - int (*ndo_validate_addr)(struct net_device *); - int (*ndo_do_ioctl)(struct net_device *, struct ifreq *, int); - int (*ndo_set_config)(struct net_device *, struct ifmap *); - int (*ndo_change_mtu)(struct net_device *, int); - int (*ndo_neigh_setup)(struct net_device *, struct neigh_parms *); - void (*ndo_tx_timeout)(struct net_device *, unsigned int); - void (*ndo_get_stats64)(struct net_device *, struct rtnl_link_stats64 *); - bool (*ndo_has_offload_stats)(const struct net_device *, int); - int (*ndo_get_offload_stats)(int, const struct net_device *, void *); - struct net_device_stats * (*ndo_get_stats)(struct net_device *); - int (*ndo_vlan_rx_add_vid)(struct net_device *, __be16, u16); - int (*ndo_vlan_rx_kill_vid)(struct net_device *, __be16, u16); - void (*ndo_poll_controller)(struct net_device *); - int (*ndo_netpoll_setup)(struct net_device *, struct netpoll_info *); - void (*ndo_netpoll_cleanup)(struct net_device *); - int (*ndo_set_vf_mac)(struct net_device *, int, u8 *); - int (*ndo_set_vf_vlan)(struct net_device *, int, u16, u8, __be16); - int (*ndo_set_vf_rate)(struct net_device *, int, int, int); - int (*ndo_set_vf_spoofchk)(struct net_device *, int, bool); - int (*ndo_set_vf_trust)(struct net_device *, int, bool); - int (*ndo_get_vf_config)(struct net_device *, int, struct ifla_vf_info *); - int (*ndo_set_vf_link_state)(struct net_device *, int, int); - int (*ndo_get_vf_stats)(struct net_device *, int, struct ifla_vf_stats *); - int (*ndo_set_vf_port)(struct net_device *, int, struct nlattr **); - int (*ndo_get_vf_port)(struct net_device *, int, struct sk_buff *); - int (*ndo_get_vf_guid)(struct net_device *, int, struct ifla_vf_guid *, struct ifla_vf_guid *); - int (*ndo_set_vf_guid)(struct net_device *, int, u64, int); - int (*ndo_set_vf_rss_query_en)(struct net_device *, int, bool); - int (*ndo_setup_tc)(struct net_device *, enum tc_setup_type, void *); - int (*ndo_rx_flow_steer)(struct net_device *, const struct sk_buff *, u16, u32); - int (*ndo_add_slave)(struct net_device *, struct net_device *, struct netlink_ext_ack *); - int (*ndo_del_slave)(struct net_device *, struct net_device *); - struct net_device * (*ndo_get_xmit_slave)(struct net_device *, struct sk_buff *, bool); - netdev_features_t (*ndo_fix_features)(struct net_device *, netdev_features_t); - int (*ndo_set_features)(struct net_device *, netdev_features_t); - int (*ndo_neigh_construct)(struct net_device *, struct neighbour *); - void (*ndo_neigh_destroy)(struct net_device *, struct neighbour *); - int (*ndo_fdb_add)(struct ndmsg *, struct nlattr **, struct net_device *, const unsigned char *, u16, u16, struct netlink_ext_ack *); - int (*ndo_fdb_del)(struct ndmsg *, struct nlattr **, struct net_device *, const unsigned char *, u16); - int (*ndo_fdb_dump)(struct sk_buff *, struct netlink_callback *, struct net_device *, struct net_device *, int *); - int (*ndo_fdb_get)(struct sk_buff *, struct nlattr **, struct net_device *, const unsigned char *, u16, u32, u32, struct netlink_ext_ack *); - int (*ndo_bridge_setlink)(struct net_device *, struct nlmsghdr *, u16, struct netlink_ext_ack *); - int (*ndo_bridge_getlink)(struct sk_buff *, u32, u32, struct net_device *, u32, int); - int (*ndo_bridge_dellink)(struct net_device *, struct nlmsghdr *, u16); - int (*ndo_change_carrier)(struct net_device *, bool); - int (*ndo_get_phys_port_id)(struct net_device *, struct netdev_phys_item_id *); - int (*ndo_get_port_parent_id)(struct net_device *, struct netdev_phys_item_id *); - int (*ndo_get_phys_port_name)(struct net_device *, char *, size_t); - void (*ndo_udp_tunnel_add)(struct net_device *, struct udp_tunnel_info *); - void (*ndo_udp_tunnel_del)(struct net_device *, struct udp_tunnel_info *); - void * (*ndo_dfwd_add_station)(struct net_device *, struct net_device *); - void (*ndo_dfwd_del_station)(struct net_device *, void *); - int (*ndo_set_tx_maxrate)(struct net_device *, int, u32); - int (*ndo_get_iflink)(const struct net_device *); - int (*ndo_change_proto_down)(struct net_device *, bool); - int (*ndo_fill_metadata_dst)(struct net_device *, struct sk_buff *); - void (*ndo_set_rx_headroom)(struct net_device *, int); - int (*ndo_bpf)(struct net_device *, struct netdev_bpf *); - int (*ndo_xdp_xmit)(struct net_device *, int, struct xdp_frame **, u32); - int (*ndo_xsk_wakeup)(struct net_device *, u32, u32); - struct devlink_port * (*ndo_get_devlink_port)(struct net_device *); - int (*ndo_tunnel_ctl)(struct net_device *, struct ip_tunnel_parm *, int); - struct net_device * (*ndo_get_peer_dev)(struct net_device *); -}; - -struct neigh_parms { - possible_net_t net; - struct net_device *dev; - struct list_head list; - int (*neigh_setup)(struct neighbour *); - struct neigh_table *tbl; - void *sysctl_table; - int dead; - refcount_t refcnt; - struct callback_head callback_head; - int reachable_time; - int data[13]; - long unsigned int data_state[1]; -}; - -struct pcpu_lstats { - u64_stats_t packets; - u64_stats_t bytes; - struct u64_stats_sync syncp; -}; - -struct pcpu_sw_netstats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; -}; - -struct iw_request_info; - -union iwreq_data; - -typedef int (*iw_handler)(struct net_device *, struct iw_request_info *, union iwreq_data *, char *); - -struct iw_priv_args; - -struct iw_statistics; - -struct iw_handler_def { - const iw_handler *standard; - __u16 num_standard; - __u16 num_private; - __u16 num_private_args; - const iw_handler *private; - const struct iw_priv_args *private_args; - struct iw_statistics * (*get_wireless_stats)(struct net_device *); -}; - -struct l3mdev_ops { - u32 (*l3mdev_fib_table)(const struct net_device *); - struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *, struct sk_buff *, u16); - struct sk_buff * (*l3mdev_l3_out)(struct net_device *, struct sock *, struct sk_buff *, u16); - struct dst_entry * (*l3mdev_link_scope_lookup)(const struct net_device *, struct flowi6 *); -}; - -struct nd_opt_hdr; - -struct ndisc_options; - -struct prefix_info; - -struct ndisc_ops { - int (*is_useropt)(u8); - int (*parse_options)(const struct net_device *, struct nd_opt_hdr *, struct ndisc_options *); - void (*update)(const struct net_device *, struct neighbour *, u32, u8, const struct ndisc_options *); - int (*opt_addr_space)(const struct net_device *, u8, struct neighbour *, u8 *, u8 **); - void (*fill_addr_option)(const struct net_device *, struct sk_buff *, u8, const u8 *); - void (*prefix_rcv_add_addr)(struct net *, struct net_device *, const struct prefix_info *, struct inet6_dev *, struct in6_addr *, int, u32, bool, bool, __u32, u32, bool); -}; - -struct ipv6_devstat { - struct proc_dir_entry *proc_dir_entry; - struct ipstats_mib *ipv6; - struct icmpv6_mib_device *icmpv6dev; - struct icmpv6msg_mib_device *icmpv6msgdev; -}; - -struct ifmcaddr6; - -struct ifacaddr6; - -struct inet6_dev { - struct net_device *dev; - struct list_head addr_list; - struct ifmcaddr6 *mc_list; - struct ifmcaddr6 *mc_tomb; - spinlock_t mc_lock; - unsigned char mc_qrv; - unsigned char mc_gq_running; - unsigned char mc_ifc_count; - unsigned char mc_dad_count; - long unsigned int mc_v1_seen; - long unsigned int mc_qi; - long unsigned int mc_qri; - long unsigned int mc_maxdelay; - struct timer_list mc_gq_timer; - struct timer_list mc_ifc_timer; - struct timer_list mc_dad_timer; - struct ifacaddr6 *ac_list; - rwlock_t lock; - refcount_t refcnt; - __u32 if_flags; - int dead; - u32 desync_factor; - struct list_head tempaddr_list; - struct in6_addr token; - struct neigh_parms *nd_parms; - struct ipv6_devconf cnf; - struct ipv6_devstat stats; - struct timer_list rs_timer; - __s32 rs_interval; - __u8 rs_probes; - long unsigned int tstamp; - struct callback_head rcu; -}; - -struct tcf_proto; - -struct tcf_block; - -struct mini_Qdisc { - struct tcf_proto *filter_list; - struct tcf_block *block; - struct gnet_stats_basic_cpu *cpu_bstats; - struct gnet_stats_queue *cpu_qstats; - struct callback_head rcu; -}; - -struct rtnl_link_ops { - struct list_head list; - const char *kind; - size_t priv_size; - void (*setup)(struct net_device *); - bool netns_refund; - unsigned int maxtype; - const struct nla_policy *policy; - int (*validate)(struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - int (*newlink)(struct net *, struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - int (*changelink)(struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - void (*dellink)(struct net_device *, struct list_head *); - size_t (*get_size)(const struct net_device *); - int (*fill_info)(struct sk_buff *, const struct net_device *); - size_t (*get_xstats_size)(const struct net_device *); - int (*fill_xstats)(struct sk_buff *, const struct net_device *); - unsigned int (*get_num_tx_queues)(); - unsigned int (*get_num_rx_queues)(); - unsigned int slave_maxtype; - const struct nla_policy *slave_policy; - int (*slave_changelink)(struct net_device *, struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - size_t (*get_slave_size)(const struct net_device *, const struct net_device *); - int (*fill_slave_info)(struct sk_buff *, const struct net_device *, const struct net_device *); - struct net * (*get_link_net)(const struct net_device *); - size_t (*get_linkxstats_size)(const struct net_device *, int); - int (*fill_linkxstats)(struct sk_buff *, const struct net_device *, int *, int); -}; - -struct udp_tunnel_nic_table_info { - unsigned int n_entries; - unsigned int tunnel_types; -}; - -struct udp_tunnel_nic_shared; - -struct udp_tunnel_nic_info { - int (*set_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *); - int (*unset_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *); - int (*sync_table)(struct net_device *, unsigned int); - struct udp_tunnel_nic_shared *shared; - unsigned int flags; - struct udp_tunnel_nic_table_info tables[4]; -}; - -enum { - RTAX_UNSPEC = 0, - RTAX_LOCK = 1, - RTAX_MTU = 2, - RTAX_WINDOW = 3, - RTAX_RTT = 4, - RTAX_RTTVAR = 5, - RTAX_SSTHRESH = 6, - RTAX_CWND = 7, - RTAX_ADVMSS = 8, - RTAX_REORDERING = 9, - RTAX_HOPLIMIT = 10, - RTAX_INITCWND = 11, - RTAX_FEATURES = 12, - RTAX_RTO_MIN = 13, - RTAX_INITRWND = 14, - RTAX_QUICKACK = 15, - RTAX_CC_ALGO = 16, - RTAX_FASTOPEN_NO_COOKIE = 17, - __RTAX_MAX = 18, -}; - -struct tcmsg { - unsigned char tcm_family; - unsigned char tcm__pad1; - short unsigned int tcm__pad2; - int tcm_ifindex; - __u32 tcm_handle; - __u32 tcm_parent; - __u32 tcm_info; -}; - -struct gnet_stats_basic_cpu { - struct gnet_stats_basic_packed bstats; - struct u64_stats_sync syncp; -}; - -struct gnet_dump { - spinlock_t *lock; - struct sk_buff *skb; - struct nlattr *tail; - int compat_tc_stats; - int compat_xstats; - int padattr; - void *xstats; - int xstats_len; - struct tc_stats tc_stats; -}; - -struct netlink_range_validation { - u64 min; - u64 max; -}; - -struct netlink_range_validation_signed { - s64 min; - s64 max; -}; - -enum flow_action_hw_stats_bit { - FLOW_ACTION_HW_STATS_IMMEDIATE_BIT = 0, - FLOW_ACTION_HW_STATS_DELAYED_BIT = 1, - FLOW_ACTION_HW_STATS_DISABLED_BIT = 2, - FLOW_ACTION_HW_STATS_NUM_BITS = 3, -}; - -struct flow_block { - struct list_head cb_list; -}; - -typedef int flow_setup_cb_t(enum tc_setup_type, void *, void *); - -struct qdisc_size_table { - struct callback_head rcu; - struct list_head list; - struct tc_sizespec szopts; - int refcnt; - u16 data[0]; -}; - -struct Qdisc_class_ops; - -struct Qdisc_ops { - struct Qdisc_ops *next; - const struct Qdisc_class_ops *cl_ops; - char id[16]; - int priv_size; - unsigned int static_flags; - int (*enqueue)(struct sk_buff *, struct Qdisc *, struct sk_buff **); - struct sk_buff * (*dequeue)(struct Qdisc *); - struct sk_buff * (*peek)(struct Qdisc *); - int (*init)(struct Qdisc *, struct nlattr *, struct netlink_ext_ack *); - void (*reset)(struct Qdisc *); - void (*destroy)(struct Qdisc *); - int (*change)(struct Qdisc *, struct nlattr *, struct netlink_ext_ack *); - void (*attach)(struct Qdisc *); - int (*change_tx_queue_len)(struct Qdisc *, unsigned int); - void (*change_real_num_tx)(struct Qdisc *, unsigned int); - int (*dump)(struct Qdisc *, struct sk_buff *); - int (*dump_stats)(struct Qdisc *, struct gnet_dump *); - void (*ingress_block_set)(struct Qdisc *, u32); - void (*egress_block_set)(struct Qdisc *, u32); - u32 (*ingress_block_get)(struct Qdisc *); - u32 (*egress_block_get)(struct Qdisc *); - struct module *owner; -}; - -struct qdisc_walker; - -struct Qdisc_class_ops { - unsigned int flags; - struct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *); - int (*graft)(struct Qdisc *, long unsigned int, struct Qdisc *, struct Qdisc **, struct netlink_ext_ack *); - struct Qdisc * (*leaf)(struct Qdisc *, long unsigned int); - void (*qlen_notify)(struct Qdisc *, long unsigned int); - long unsigned int (*find)(struct Qdisc *, u32); - int (*change)(struct Qdisc *, u32, u32, struct nlattr **, long unsigned int *, struct netlink_ext_ack *); - int (*delete)(struct Qdisc *, long unsigned int); - void (*walk)(struct Qdisc *, struct qdisc_walker *); - struct tcf_block * (*tcf_block)(struct Qdisc *, long unsigned int, struct netlink_ext_ack *); - long unsigned int (*bind_tcf)(struct Qdisc *, long unsigned int, u32); - void (*unbind_tcf)(struct Qdisc *, long unsigned int); - int (*dump)(struct Qdisc *, long unsigned int, struct sk_buff *, struct tcmsg *); - int (*dump_stats)(struct Qdisc *, long unsigned int, struct gnet_dump *); -}; - -struct tcf_chain; - -struct tcf_block { - struct mutex lock; - struct list_head chain_list; - u32 index; - u32 classid; - refcount_t refcnt; - struct net *net; - struct Qdisc *q; - struct rw_semaphore cb_lock; - struct flow_block flow_block; - struct list_head owner_list; - bool keep_dst; - atomic_t offloadcnt; - unsigned int nooffloaddevcnt; - unsigned int lockeddevcnt; - struct { - struct tcf_chain *chain; - struct list_head filter_chain_list; - } chain0; - struct callback_head rcu; - struct hlist_head proto_destroy_ht[128]; - struct mutex proto_destroy_lock; -}; - -struct tcf_result; - -struct tcf_proto_ops; - -struct tcf_proto { - struct tcf_proto *next; - void *root; - int (*classify)(struct sk_buff *, const struct tcf_proto *, struct tcf_result *); - __be16 protocol; - u32 prio; - void *data; - const struct tcf_proto_ops *ops; - struct tcf_chain *chain; - spinlock_t lock; - bool deleting; - refcount_t refcnt; - struct callback_head rcu; - struct hlist_node destroy_ht_node; -}; - -struct tcf_result { - union { - struct { - long unsigned int class; - u32 classid; - }; - const struct tcf_proto *goto_tp; - struct { - bool ingress; - struct gnet_stats_queue *qstats; - }; - }; -}; - -struct tcf_walker; - -struct tcf_proto_ops { - struct list_head head; - char kind[16]; - int (*classify)(struct sk_buff *, const struct tcf_proto *, struct tcf_result *); - int (*init)(struct tcf_proto *); - void (*destroy)(struct tcf_proto *, bool, struct netlink_ext_ack *); - void * (*get)(struct tcf_proto *, u32); - void (*put)(struct tcf_proto *, void *); - int (*change)(struct net *, struct sk_buff *, struct tcf_proto *, long unsigned int, u32, struct nlattr **, void **, bool, bool, struct netlink_ext_ack *); - int (*delete)(struct tcf_proto *, void *, bool *, bool, struct netlink_ext_ack *); - bool (*delete_empty)(struct tcf_proto *); - void (*walk)(struct tcf_proto *, struct tcf_walker *, bool); - int (*reoffload)(struct tcf_proto *, bool, flow_setup_cb_t *, void *, struct netlink_ext_ack *); - void (*hw_add)(struct tcf_proto *, void *); - void (*hw_del)(struct tcf_proto *, void *); - void (*bind_class)(void *, u32, long unsigned int, void *, long unsigned int); - void * (*tmplt_create)(struct net *, struct tcf_chain *, struct nlattr **, struct netlink_ext_ack *); - void (*tmplt_destroy)(void *); - int (*dump)(struct net *, struct tcf_proto *, void *, struct sk_buff *, struct tcmsg *, bool); - int (*terse_dump)(struct net *, struct tcf_proto *, void *, struct sk_buff *, struct tcmsg *, bool); - int (*tmplt_dump)(struct sk_buff *, struct net *, void *); - struct module *owner; - int flags; -}; - -struct tcf_chain { - struct mutex filter_chain_lock; - struct tcf_proto *filter_chain; - struct list_head list; - struct tcf_block *block; - u32 index; - unsigned int refcnt; - unsigned int action_refcnt; - bool explicitly_created; - bool flushing; - const struct tcf_proto_ops *tmplt_ops; - void *tmplt_priv; - struct callback_head rcu; -}; - -struct sock_fprog_kern { - u16 len; - struct sock_filter *filter; -}; - -struct sk_filter { - refcount_t refcnt; - struct callback_head rcu; - struct bpf_prog *prog; -}; - -enum { - NEIGH_VAR_MCAST_PROBES = 0, - NEIGH_VAR_UCAST_PROBES = 1, - NEIGH_VAR_APP_PROBES = 2, - NEIGH_VAR_MCAST_REPROBES = 3, - NEIGH_VAR_RETRANS_TIME = 4, - NEIGH_VAR_BASE_REACHABLE_TIME = 5, - NEIGH_VAR_DELAY_PROBE_TIME = 6, - NEIGH_VAR_GC_STALETIME = 7, - NEIGH_VAR_QUEUE_LEN_BYTES = 8, - NEIGH_VAR_PROXY_QLEN = 9, - NEIGH_VAR_ANYCAST_DELAY = 10, - NEIGH_VAR_PROXY_DELAY = 11, - NEIGH_VAR_LOCKTIME = 12, - NEIGH_VAR_QUEUE_LEN = 13, - NEIGH_VAR_RETRANS_TIME_MS = 14, - NEIGH_VAR_BASE_REACHABLE_TIME_MS = 15, - NEIGH_VAR_GC_INTERVAL = 16, - NEIGH_VAR_GC_THRESH1 = 17, - NEIGH_VAR_GC_THRESH2 = 18, - NEIGH_VAR_GC_THRESH3 = 19, - NEIGH_VAR_MAX = 20, -}; - -struct pneigh_entry; - -struct neigh_statistics; - -struct neigh_hash_table; - -struct neigh_table { - int family; - unsigned int entry_size; - unsigned int key_len; - __be16 protocol; - __u32 (*hash)(const void *, const struct net_device *, __u32 *); - bool (*key_eq)(const struct neighbour *, const void *); - int (*constructor)(struct neighbour *); - int (*pconstructor)(struct pneigh_entry *); - void (*pdestructor)(struct pneigh_entry *); - void (*proxy_redo)(struct sk_buff *); - int (*is_multicast)(const void *); - bool (*allow_add)(const struct net_device *, struct netlink_ext_ack *); - char *id; - struct neigh_parms parms; - struct list_head parms_list; - int gc_interval; - int gc_thresh1; - int gc_thresh2; - int gc_thresh3; - long unsigned int last_flush; - struct delayed_work gc_work; - struct timer_list proxy_timer; - struct sk_buff_head proxy_queue; - atomic_t entries; - atomic_t gc_entries; - struct list_head gc_list; - rwlock_t lock; - long unsigned int last_rand; - struct neigh_statistics *stats; - struct neigh_hash_table *nht; - struct pneigh_entry **phash_buckets; -}; - -struct neigh_statistics { - long unsigned int allocs; - long unsigned int destroys; - long unsigned int hash_grows; - long unsigned int res_failed; - long unsigned int lookups; - long unsigned int hits; - long unsigned int rcv_probes_mcast; - long unsigned int rcv_probes_ucast; - long unsigned int periodic_gc_runs; - long unsigned int forced_gc_runs; - long unsigned int unres_discards; - long unsigned int table_fulls; -}; - -struct neigh_ops { - int family; - void (*solicit)(struct neighbour *, struct sk_buff *); - void (*error_report)(struct neighbour *, struct sk_buff *); - int (*output)(struct neighbour *, struct sk_buff *); - int (*connected_output)(struct neighbour *, struct sk_buff *); -}; - -struct pneigh_entry { - struct pneigh_entry *next; - possible_net_t net; - struct net_device *dev; - u8 flags; - u8 protocol; - u8 key[0]; -}; - -struct neigh_hash_table { - struct neighbour **hash_buckets; - unsigned int hash_shift; - __u32 hash_rnd[4]; - struct callback_head rcu; -}; - -enum { - TCP_ESTABLISHED = 1, - TCP_SYN_SENT = 2, - TCP_SYN_RECV = 3, - TCP_FIN_WAIT1 = 4, - TCP_FIN_WAIT2 = 5, - TCP_TIME_WAIT = 6, - TCP_CLOSE = 7, - TCP_CLOSE_WAIT = 8, - TCP_LAST_ACK = 9, - TCP_LISTEN = 10, - TCP_CLOSING = 11, - TCP_NEW_SYN_RECV = 12, - TCP_MAX_STATES = 13, -}; - -struct fib_rule_hdr { - __u8 family; - __u8 dst_len; - __u8 src_len; - __u8 tos; - __u8 table; - __u8 res1; - __u8 res2; - __u8 action; - __u32 flags; -}; - -struct fib_rule_port_range { - __u16 start; - __u16 end; -}; - -struct fib_kuid_range { - kuid_t start; - kuid_t end; -}; - -struct fib_rule { - struct list_head list; - int iifindex; - int oifindex; - u32 mark; - u32 mark_mask; - u32 flags; - u32 table; - u8 action; - u8 l3mdev; - u8 proto; - u8 ip_proto; - u32 target; - __be64 tun_id; - struct fib_rule *ctarget; - struct net *fr_net; - refcount_t refcnt; - u32 pref; - int suppress_ifgroup; - int suppress_prefixlen; - char iifname[16]; - char oifname[16]; - struct fib_kuid_range uid_range; - struct fib_rule_port_range sport_range; - struct fib_rule_port_range dport_range; - struct callback_head rcu; -}; - -struct fib_lookup_arg { - void *lookup_ptr; - const void *lookup_data; - void *result; - struct fib_rule *rule; - u32 table; - int flags; -}; - -struct smc_hashinfo; - -struct request_sock_ops; - -struct timewait_sock_ops; - -struct udp_table; - -struct raw_hashinfo; - -struct proto { - void (*close)(struct sock *, long int); - int (*pre_connect)(struct sock *, struct sockaddr *, int); - int (*connect)(struct sock *, struct sockaddr *, int); - int (*disconnect)(struct sock *, int); - struct sock * (*accept)(struct sock *, int, int *, bool); - int (*ioctl)(struct sock *, int, long unsigned int); - int (*init)(struct sock *); - void (*destroy)(struct sock *); - void (*shutdown)(struct sock *, int); - int (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int); - int (*getsockopt)(struct sock *, int, int, char *, int *); - void (*keepalive)(struct sock *, int); - int (*compat_ioctl)(struct sock *, unsigned int, long unsigned int); - int (*sendmsg)(struct sock *, struct msghdr *, size_t); - int (*recvmsg)(struct sock *, struct msghdr *, size_t, int, int, int *); - int (*sendpage)(struct sock *, struct page *, int, size_t, int); - int (*bind)(struct sock *, struct sockaddr *, int); - int (*bind_add)(struct sock *, struct sockaddr *, int); - int (*backlog_rcv)(struct sock *, struct sk_buff *); - void (*release_cb)(struct sock *); - int (*hash)(struct sock *); - void (*unhash)(struct sock *); - void (*rehash)(struct sock *); - int (*get_port)(struct sock *, short unsigned int); - unsigned int inuse_idx; - bool (*stream_memory_free)(const struct sock *, int); - bool (*stream_memory_read)(const struct sock *); - void (*enter_memory_pressure)(struct sock *); - void (*leave_memory_pressure)(struct sock *); - atomic_long_t *memory_allocated; - struct percpu_counter *sockets_allocated; - long unsigned int *memory_pressure; - long int *sysctl_mem; - int *sysctl_wmem; - int *sysctl_rmem; - u32 sysctl_wmem_offset; - u32 sysctl_rmem_offset; - int max_header; - bool no_autobind; - struct kmem_cache *slab; - unsigned int obj_size; - slab_flags_t slab_flags; - unsigned int useroffset; - unsigned int usersize; - unsigned int *orphan_count; - struct request_sock_ops *rsk_prot; - struct timewait_sock_ops *twsk_prot; - union { - struct inet_hashinfo *hashinfo; - struct udp_table *udp_table; - struct raw_hashinfo *raw_hash; - struct smc_hashinfo *smc_hash; - } h; - struct module *owner; - char name[32]; - struct list_head node; - int (*diag_destroy)(struct sock *, int); -}; - -struct request_sock; - -struct request_sock_ops { - int family; - unsigned int obj_size; - struct kmem_cache *slab; - char *slab_name; - int (*rtx_syn_ack)(const struct sock *, struct request_sock *); - void (*send_ack)(const struct sock *, struct sk_buff *, struct request_sock *); - void (*send_reset)(const struct sock *, struct sk_buff *); - void (*destructor)(struct request_sock *); - void (*syn_ack_timeout)(const struct request_sock *); -}; - -struct timewait_sock_ops { - struct kmem_cache *twsk_slab; - char *twsk_slab_name; - unsigned int twsk_obj_size; - int (*twsk_unique)(struct sock *, struct sock *, void *); - void (*twsk_destructor)(struct sock *); -}; - -struct saved_syn; - -struct request_sock { - struct sock_common __req_common; - struct request_sock *dl_next; - u16 mss; - u8 num_retrans; - u8 syncookie: 1; - u8 num_timeout: 7; - u32 ts_recent; - struct timer_list rsk_timer; - const struct request_sock_ops *rsk_ops; - struct sock *sk; - struct saved_syn *saved_syn; - u32 secid; - u32 peer_secid; -}; - -struct saved_syn { - u32 mac_hdrlen; - u32 network_hdrlen; - u32 tcp_hdrlen; - u8 data[0]; -}; - -enum tsq_enum { - TSQ_THROTTLED = 0, - TSQ_QUEUED = 1, - TCP_TSQ_DEFERRED = 2, - TCP_WRITE_TIMER_DEFERRED = 3, - TCP_DELACK_TIMER_DEFERRED = 4, - TCP_MTU_REDUCED_DEFERRED = 5, -}; - -struct ip6_sf_list { - struct ip6_sf_list *sf_next; - struct in6_addr sf_addr; - long unsigned int sf_count[2]; - unsigned char sf_gsresp; - unsigned char sf_oldin; - unsigned char sf_crcount; -}; - -struct ifmcaddr6 { - struct in6_addr mca_addr; - struct inet6_dev *idev; - struct ifmcaddr6 *next; - struct ip6_sf_list *mca_sources; - struct ip6_sf_list *mca_tomb; - unsigned int mca_sfmode; - unsigned char mca_crcount; - long unsigned int mca_sfcount[2]; - struct timer_list mca_timer; - unsigned int mca_flags; - int mca_users; - refcount_t mca_refcnt; - spinlock_t mca_lock; - long unsigned int mca_cstamp; - long unsigned int mca_tstamp; -}; - -struct ifacaddr6 { - struct in6_addr aca_addr; - struct fib6_info *aca_rt; - struct ifacaddr6 *aca_next; - struct hlist_node aca_addr_lst; - int aca_users; - refcount_t aca_refcnt; - long unsigned int aca_cstamp; - long unsigned int aca_tstamp; - struct callback_head rcu; -}; - -enum { - __ND_OPT_PREFIX_INFO_END = 0, - ND_OPT_SOURCE_LL_ADDR = 1, - ND_OPT_TARGET_LL_ADDR = 2, - ND_OPT_PREFIX_INFO = 3, - ND_OPT_REDIRECT_HDR = 4, - ND_OPT_MTU = 5, - ND_OPT_NONCE = 14, - __ND_OPT_ARRAY_MAX = 15, - ND_OPT_ROUTE_INFO = 24, - ND_OPT_RDNSS = 25, - ND_OPT_DNSSL = 31, - ND_OPT_6CO = 34, - ND_OPT_CAPTIVE_PORTAL = 37, - ND_OPT_PREF64 = 38, - __ND_OPT_MAX = 39, -}; - -struct nd_opt_hdr { - __u8 nd_opt_type; - __u8 nd_opt_len; -}; - -struct ndisc_options { - struct nd_opt_hdr *nd_opt_array[15]; - struct nd_opt_hdr *nd_opts_ri; - struct nd_opt_hdr *nd_opts_ri_end; - struct nd_opt_hdr *nd_useropts; - struct nd_opt_hdr *nd_useropts_end; -}; - -struct prefix_info { - __u8 type; - __u8 length; - __u8 prefix_len; - __u8 reserved: 6; - __u8 autoconf: 1; - __u8 onlink: 1; - __be32 valid; - __be32 prefered; - __be32 reserved2; - struct in6_addr prefix; -}; - -enum nfs_opnum4 { - OP_ACCESS = 3, - OP_CLOSE = 4, - OP_COMMIT = 5, - OP_CREATE = 6, - OP_DELEGPURGE = 7, - OP_DELEGRETURN = 8, - OP_GETATTR = 9, - OP_GETFH = 10, - OP_LINK = 11, - OP_LOCK = 12, - OP_LOCKT = 13, - OP_LOCKU = 14, - OP_LOOKUP = 15, - OP_LOOKUPP = 16, - OP_NVERIFY = 17, - OP_OPEN = 18, - OP_OPENATTR = 19, - OP_OPEN_CONFIRM = 20, - OP_OPEN_DOWNGRADE = 21, - OP_PUTFH = 22, - OP_PUTPUBFH = 23, - OP_PUTROOTFH = 24, - OP_READ = 25, - OP_READDIR = 26, - OP_READLINK = 27, - OP_REMOVE = 28, - OP_RENAME = 29, - OP_RENEW = 30, - OP_RESTOREFH = 31, - OP_SAVEFH = 32, - OP_SECINFO = 33, - OP_SETATTR = 34, - OP_SETCLIENTID = 35, - OP_SETCLIENTID_CONFIRM = 36, - OP_VERIFY = 37, - OP_WRITE = 38, - OP_RELEASE_LOCKOWNER = 39, - OP_BACKCHANNEL_CTL = 40, - OP_BIND_CONN_TO_SESSION = 41, - OP_EXCHANGE_ID = 42, - OP_CREATE_SESSION = 43, - OP_DESTROY_SESSION = 44, - OP_FREE_STATEID = 45, - OP_GET_DIR_DELEGATION = 46, - OP_GETDEVICEINFO = 47, - OP_GETDEVICELIST = 48, - OP_LAYOUTCOMMIT = 49, - OP_LAYOUTGET = 50, - OP_LAYOUTRETURN = 51, - OP_SECINFO_NO_NAME = 52, - OP_SEQUENCE = 53, - OP_SET_SSV = 54, - OP_TEST_STATEID = 55, - OP_WANT_DELEGATION = 56, - OP_DESTROY_CLIENTID = 57, - OP_RECLAIM_COMPLETE = 58, - OP_ALLOCATE = 59, - OP_COPY = 60, - OP_COPY_NOTIFY = 61, - OP_DEALLOCATE = 62, - OP_IO_ADVISE = 63, - OP_LAYOUTERROR = 64, - OP_LAYOUTSTATS = 65, - OP_OFFLOAD_CANCEL = 66, - OP_OFFLOAD_STATUS = 67, - OP_READ_PLUS = 68, - OP_SEEK = 69, - OP_WRITE_SAME = 70, - OP_CLONE = 71, - OP_GETXATTR = 72, - OP_SETXATTR = 73, - OP_LISTXATTRS = 74, - OP_REMOVEXATTR = 75, - OP_ILLEGAL = 10044, -}; - -enum perf_branch_sample_type_shift { - PERF_SAMPLE_BRANCH_USER_SHIFT = 0, - PERF_SAMPLE_BRANCH_KERNEL_SHIFT = 1, - PERF_SAMPLE_BRANCH_HV_SHIFT = 2, - PERF_SAMPLE_BRANCH_ANY_SHIFT = 3, - PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT = 4, - PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT = 5, - PERF_SAMPLE_BRANCH_IND_CALL_SHIFT = 6, - PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT = 7, - PERF_SAMPLE_BRANCH_IN_TX_SHIFT = 8, - PERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9, - PERF_SAMPLE_BRANCH_COND_SHIFT = 10, - PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11, - PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12, - PERF_SAMPLE_BRANCH_CALL_SHIFT = 13, - PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT = 14, - PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT = 15, - PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT = 16, - PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT = 17, - PERF_SAMPLE_BRANCH_MAX_SHIFT = 18, -}; - -struct uuidcmp { - const char *uuid; - int len; -}; - -typedef __u64 __le64; - -struct minix_super_block { - __u16 s_ninodes; - __u16 s_nzones; - __u16 s_imap_blocks; - __u16 s_zmap_blocks; - __u16 s_firstdatazone; - __u16 s_log_zone_size; - __u32 s_max_size; - __u16 s_magic; - __u16 s_state; - __u32 s_zones; -}; - -struct romfs_super_block { - __be32 word0; - __be32 word1; - __be32 size; - __be32 checksum; - char name[0]; -}; - -struct cramfs_inode { - __u32 mode: 16; - __u32 uid: 16; - __u32 size: 24; - __u32 gid: 8; - __u32 namelen: 6; - __u32 offset: 26; -}; - -struct cramfs_info { - __u32 crc; - __u32 edition; - __u32 blocks; - __u32 files; -}; - -struct cramfs_super { - __u32 magic; - __u32 size; - __u32 flags; - __u32 future; - __u8 signature[16]; - struct cramfs_info fsid; - __u8 name[16]; - struct cramfs_inode root; -}; - -struct squashfs_super_block { - __le32 s_magic; - __le32 inodes; - __le32 mkfs_time; - __le32 block_size; - __le32 fragments; - __le16 compression; - __le16 block_log; - __le16 flags; - __le16 no_ids; - __le16 s_major; - __le16 s_minor; - __le64 root_inode; - __le64 bytes_used; - __le64 id_table_start; - __le64 xattr_id_table_start; - __le64 inode_table_start; - __le64 directory_table_start; - __le64 fragment_table_start; - __le64 lookup_table_start; -}; - -typedef int (*decompress_fn)(unsigned char *, long int, long int (*)(void *, long unsigned int), long int (*)(void *, long unsigned int), unsigned char *, long int *, void (*)(char *)); - -struct subprocess_info { - struct work_struct work; - struct completion *complete; - const char *path; - char **argv; - char **envp; - int wait; - int retval; - int (*init)(struct subprocess_info *, struct cred *); - void (*cleanup)(struct subprocess_info *); - void *data; -}; - -struct hash { - int ino; - int minor; - int major; - umode_t mode; - struct hash *next; - char name[4098]; -}; - -struct dir_entry { - struct list_head list; - char *name; - time64_t mtime; -}; - -enum state { - Start = 0, - Collect = 1, - GotHeader = 2, - SkipIt = 3, - GotName = 4, - CopyFile = 5, - GotSymlink = 6, - Reset = 7, -}; - -enum migratetype { - MIGRATE_UNMOVABLE = 0, - MIGRATE_MOVABLE = 1, - MIGRATE_RECLAIMABLE = 2, - MIGRATE_PCPTYPES = 3, - MIGRATE_HIGHATOMIC = 3, - MIGRATE_CMA = 4, - MIGRATE_ISOLATE = 5, - MIGRATE_TYPES = 6, -}; - -enum zone_stat_item { - NR_FREE_PAGES = 0, - NR_ZONE_LRU_BASE = 1, - NR_ZONE_INACTIVE_ANON = 1, - NR_ZONE_ACTIVE_ANON = 2, - NR_ZONE_INACTIVE_FILE = 3, - NR_ZONE_ACTIVE_FILE = 4, - NR_ZONE_UNEVICTABLE = 5, - NR_ZONE_WRITE_PENDING = 6, - NR_MLOCK = 7, - NR_PAGETABLE = 8, - NR_BOUNCE = 9, - NR_ZSPAGES = 10, - NR_FREE_CMA_PAGES = 11, - NR_VM_ZONE_STAT_ITEMS = 12, -}; - -enum zone_watermarks { - WMARK_MIN = 0, - WMARK_LOW = 1, - WMARK_HIGH = 2, - NR_WMARK = 3, -}; - -enum { - ZONELIST_FALLBACK = 0, - MAX_ZONELISTS = 1, -}; - -enum { - DQF_ROOT_SQUASH_B = 0, - DQF_SYS_FILE_B = 16, - DQF_PRIVATE = 17, -}; - -enum { - DQST_LOOKUPS = 0, - DQST_DROPS = 1, - DQST_READS = 2, - DQST_WRITES = 3, - DQST_CACHE_HITS = 4, - DQST_ALLOC_DQUOTS = 5, - DQST_FREE_DQUOTS = 6, - DQST_SYNCS = 7, - _DQST_DQSTAT_LAST = 8, -}; - -enum { - SB_UNFROZEN = 0, - SB_FREEZE_WRITE = 1, - SB_FREEZE_PAGEFAULT = 2, - SB_FREEZE_FS = 3, - SB_FREEZE_COMPLETE = 4, -}; - -enum compound_dtor_id { - NULL_COMPOUND_DTOR = 0, - COMPOUND_PAGE_DTOR = 1, - NR_COMPOUND_DTORS = 2, -}; - -enum { - TSK_TRACE_FL_TRACE_BIT = 0, - TSK_TRACE_FL_GRAPH_BIT = 1, -}; - -enum ucount_type { - UCOUNT_USER_NAMESPACES = 0, - UCOUNT_PID_NAMESPACES = 1, - UCOUNT_UTS_NAMESPACES = 2, - UCOUNT_IPC_NAMESPACES = 3, - UCOUNT_NET_NAMESPACES = 4, - UCOUNT_MNT_NAMESPACES = 5, - UCOUNT_CGROUP_NAMESPACES = 6, - UCOUNT_TIME_NAMESPACES = 7, - UCOUNT_INOTIFY_INSTANCES = 8, - UCOUNT_INOTIFY_WATCHES = 9, - UCOUNT_COUNTS = 10, -}; - -enum flow_dissector_key_id { - FLOW_DISSECTOR_KEY_CONTROL = 0, - FLOW_DISSECTOR_KEY_BASIC = 1, - FLOW_DISSECTOR_KEY_IPV4_ADDRS = 2, - FLOW_DISSECTOR_KEY_IPV6_ADDRS = 3, - FLOW_DISSECTOR_KEY_PORTS = 4, - FLOW_DISSECTOR_KEY_PORTS_RANGE = 5, - FLOW_DISSECTOR_KEY_ICMP = 6, - FLOW_DISSECTOR_KEY_ETH_ADDRS = 7, - FLOW_DISSECTOR_KEY_TIPC = 8, - FLOW_DISSECTOR_KEY_ARP = 9, - FLOW_DISSECTOR_KEY_VLAN = 10, - FLOW_DISSECTOR_KEY_FLOW_LABEL = 11, - FLOW_DISSECTOR_KEY_GRE_KEYID = 12, - FLOW_DISSECTOR_KEY_MPLS_ENTROPY = 13, - FLOW_DISSECTOR_KEY_ENC_KEYID = 14, - FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS = 15, - FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS = 16, - FLOW_DISSECTOR_KEY_ENC_CONTROL = 17, - FLOW_DISSECTOR_KEY_ENC_PORTS = 18, - FLOW_DISSECTOR_KEY_MPLS = 19, - FLOW_DISSECTOR_KEY_TCP = 20, - FLOW_DISSECTOR_KEY_IP = 21, - FLOW_DISSECTOR_KEY_CVLAN = 22, - FLOW_DISSECTOR_KEY_ENC_IP = 23, - FLOW_DISSECTOR_KEY_ENC_OPTS = 24, - FLOW_DISSECTOR_KEY_META = 25, - FLOW_DISSECTOR_KEY_CT = 26, - FLOW_DISSECTOR_KEY_HASH = 27, - FLOW_DISSECTOR_KEY_MAX = 28, -}; - -enum { - IPSTATS_MIB_NUM = 0, - IPSTATS_MIB_INPKTS = 1, - IPSTATS_MIB_INOCTETS = 2, - IPSTATS_MIB_INDELIVERS = 3, - IPSTATS_MIB_OUTFORWDATAGRAMS = 4, - IPSTATS_MIB_OUTPKTS = 5, - IPSTATS_MIB_OUTOCTETS = 6, - IPSTATS_MIB_INHDRERRORS = 7, - IPSTATS_MIB_INTOOBIGERRORS = 8, - IPSTATS_MIB_INNOROUTES = 9, - IPSTATS_MIB_INADDRERRORS = 10, - IPSTATS_MIB_INUNKNOWNPROTOS = 11, - IPSTATS_MIB_INTRUNCATEDPKTS = 12, - IPSTATS_MIB_INDISCARDS = 13, - IPSTATS_MIB_OUTDISCARDS = 14, - IPSTATS_MIB_OUTNOROUTES = 15, - IPSTATS_MIB_REASMTIMEOUT = 16, - IPSTATS_MIB_REASMREQDS = 17, - IPSTATS_MIB_REASMOKS = 18, - IPSTATS_MIB_REASMFAILS = 19, - IPSTATS_MIB_FRAGOKS = 20, - IPSTATS_MIB_FRAGFAILS = 21, - IPSTATS_MIB_FRAGCREATES = 22, - IPSTATS_MIB_INMCASTPKTS = 23, - IPSTATS_MIB_OUTMCASTPKTS = 24, - IPSTATS_MIB_INBCASTPKTS = 25, - IPSTATS_MIB_OUTBCASTPKTS = 26, - IPSTATS_MIB_INMCASTOCTETS = 27, - IPSTATS_MIB_OUTMCASTOCTETS = 28, - IPSTATS_MIB_INBCASTOCTETS = 29, - IPSTATS_MIB_OUTBCASTOCTETS = 30, - IPSTATS_MIB_CSUMERRORS = 31, - IPSTATS_MIB_NOECTPKTS = 32, - IPSTATS_MIB_ECT1PKTS = 33, - IPSTATS_MIB_ECT0PKTS = 34, - IPSTATS_MIB_CEPKTS = 35, - IPSTATS_MIB_REASM_OVERLAPS = 36, - __IPSTATS_MIB_MAX = 37, -}; - -enum { - ICMP_MIB_NUM = 0, - ICMP_MIB_INMSGS = 1, - ICMP_MIB_INERRORS = 2, - ICMP_MIB_INDESTUNREACHS = 3, - ICMP_MIB_INTIMEEXCDS = 4, - ICMP_MIB_INPARMPROBS = 5, - ICMP_MIB_INSRCQUENCHS = 6, - ICMP_MIB_INREDIRECTS = 7, - ICMP_MIB_INECHOS = 8, - ICMP_MIB_INECHOREPS = 9, - ICMP_MIB_INTIMESTAMPS = 10, - ICMP_MIB_INTIMESTAMPREPS = 11, - ICMP_MIB_INADDRMASKS = 12, - ICMP_MIB_INADDRMASKREPS = 13, - ICMP_MIB_OUTMSGS = 14, - ICMP_MIB_OUTERRORS = 15, - ICMP_MIB_OUTDESTUNREACHS = 16, - ICMP_MIB_OUTTIMEEXCDS = 17, - ICMP_MIB_OUTPARMPROBS = 18, - ICMP_MIB_OUTSRCQUENCHS = 19, - ICMP_MIB_OUTREDIRECTS = 20, - ICMP_MIB_OUTECHOS = 21, - ICMP_MIB_OUTECHOREPS = 22, - ICMP_MIB_OUTTIMESTAMPS = 23, - ICMP_MIB_OUTTIMESTAMPREPS = 24, - ICMP_MIB_OUTADDRMASKS = 25, - ICMP_MIB_OUTADDRMASKREPS = 26, - ICMP_MIB_CSUMERRORS = 27, - __ICMP_MIB_MAX = 28, -}; - -enum { - ICMP6_MIB_NUM = 0, - ICMP6_MIB_INMSGS = 1, - ICMP6_MIB_INERRORS = 2, - ICMP6_MIB_OUTMSGS = 3, - ICMP6_MIB_OUTERRORS = 4, - ICMP6_MIB_CSUMERRORS = 5, - __ICMP6_MIB_MAX = 6, -}; - -enum { - TCP_MIB_NUM = 0, - TCP_MIB_RTOALGORITHM = 1, - TCP_MIB_RTOMIN = 2, - TCP_MIB_RTOMAX = 3, - TCP_MIB_MAXCONN = 4, - TCP_MIB_ACTIVEOPENS = 5, - TCP_MIB_PASSIVEOPENS = 6, - TCP_MIB_ATTEMPTFAILS = 7, - TCP_MIB_ESTABRESETS = 8, - TCP_MIB_CURRESTAB = 9, - TCP_MIB_INSEGS = 10, - TCP_MIB_OUTSEGS = 11, - TCP_MIB_RETRANSSEGS = 12, - TCP_MIB_INERRS = 13, - TCP_MIB_OUTRSTS = 14, - TCP_MIB_CSUMERRORS = 15, - __TCP_MIB_MAX = 16, -}; - -enum { - UDP_MIB_NUM = 0, - UDP_MIB_INDATAGRAMS = 1, - UDP_MIB_NOPORTS = 2, - UDP_MIB_INERRORS = 3, - UDP_MIB_OUTDATAGRAMS = 4, - UDP_MIB_RCVBUFERRORS = 5, - UDP_MIB_SNDBUFERRORS = 6, - UDP_MIB_CSUMERRORS = 7, - UDP_MIB_IGNOREDMULTI = 8, - __UDP_MIB_MAX = 9, -}; - -enum { - LINUX_MIB_NUM = 0, - LINUX_MIB_SYNCOOKIESSENT = 1, - LINUX_MIB_SYNCOOKIESRECV = 2, - LINUX_MIB_SYNCOOKIESFAILED = 3, - LINUX_MIB_EMBRYONICRSTS = 4, - LINUX_MIB_PRUNECALLED = 5, - LINUX_MIB_RCVPRUNED = 6, - LINUX_MIB_OFOPRUNED = 7, - LINUX_MIB_OUTOFWINDOWICMPS = 8, - LINUX_MIB_LOCKDROPPEDICMPS = 9, - LINUX_MIB_ARPFILTER = 10, - LINUX_MIB_TIMEWAITED = 11, - LINUX_MIB_TIMEWAITRECYCLED = 12, - LINUX_MIB_TIMEWAITKILLED = 13, - LINUX_MIB_PAWSACTIVEREJECTED = 14, - LINUX_MIB_PAWSESTABREJECTED = 15, - LINUX_MIB_DELAYEDACKS = 16, - LINUX_MIB_DELAYEDACKLOCKED = 17, - LINUX_MIB_DELAYEDACKLOST = 18, - LINUX_MIB_LISTENOVERFLOWS = 19, - LINUX_MIB_LISTENDROPS = 20, - LINUX_MIB_TCPHPHITS = 21, - LINUX_MIB_TCPPUREACKS = 22, - LINUX_MIB_TCPHPACKS = 23, - LINUX_MIB_TCPRENORECOVERY = 24, - LINUX_MIB_TCPSACKRECOVERY = 25, - LINUX_MIB_TCPSACKRENEGING = 26, - LINUX_MIB_TCPSACKREORDER = 27, - LINUX_MIB_TCPRENOREORDER = 28, - LINUX_MIB_TCPTSREORDER = 29, - LINUX_MIB_TCPFULLUNDO = 30, - LINUX_MIB_TCPPARTIALUNDO = 31, - LINUX_MIB_TCPDSACKUNDO = 32, - LINUX_MIB_TCPLOSSUNDO = 33, - LINUX_MIB_TCPLOSTRETRANSMIT = 34, - LINUX_MIB_TCPRENOFAILURES = 35, - LINUX_MIB_TCPSACKFAILURES = 36, - LINUX_MIB_TCPLOSSFAILURES = 37, - LINUX_MIB_TCPFASTRETRANS = 38, - LINUX_MIB_TCPSLOWSTARTRETRANS = 39, - LINUX_MIB_TCPTIMEOUTS = 40, - LINUX_MIB_TCPLOSSPROBES = 41, - LINUX_MIB_TCPLOSSPROBERECOVERY = 42, - LINUX_MIB_TCPRENORECOVERYFAIL = 43, - LINUX_MIB_TCPSACKRECOVERYFAIL = 44, - LINUX_MIB_TCPRCVCOLLAPSED = 45, - LINUX_MIB_TCPDSACKOLDSENT = 46, - LINUX_MIB_TCPDSACKOFOSENT = 47, - LINUX_MIB_TCPDSACKRECV = 48, - LINUX_MIB_TCPDSACKOFORECV = 49, - LINUX_MIB_TCPABORTONDATA = 50, - LINUX_MIB_TCPABORTONCLOSE = 51, - LINUX_MIB_TCPABORTONMEMORY = 52, - LINUX_MIB_TCPABORTONTIMEOUT = 53, - LINUX_MIB_TCPABORTONLINGER = 54, - LINUX_MIB_TCPABORTFAILED = 55, - LINUX_MIB_TCPMEMORYPRESSURES = 56, - LINUX_MIB_TCPMEMORYPRESSURESCHRONO = 57, - LINUX_MIB_TCPSACKDISCARD = 58, - LINUX_MIB_TCPDSACKIGNOREDOLD = 59, - LINUX_MIB_TCPDSACKIGNOREDNOUNDO = 60, - LINUX_MIB_TCPSPURIOUSRTOS = 61, - LINUX_MIB_TCPMD5NOTFOUND = 62, - LINUX_MIB_TCPMD5UNEXPECTED = 63, - LINUX_MIB_TCPMD5FAILURE = 64, - LINUX_MIB_SACKSHIFTED = 65, - LINUX_MIB_SACKMERGED = 66, - LINUX_MIB_SACKSHIFTFALLBACK = 67, - LINUX_MIB_TCPBACKLOGDROP = 68, - LINUX_MIB_PFMEMALLOCDROP = 69, - LINUX_MIB_TCPMINTTLDROP = 70, - LINUX_MIB_TCPDEFERACCEPTDROP = 71, - LINUX_MIB_IPRPFILTER = 72, - LINUX_MIB_TCPTIMEWAITOVERFLOW = 73, - LINUX_MIB_TCPREQQFULLDOCOOKIES = 74, - LINUX_MIB_TCPREQQFULLDROP = 75, - LINUX_MIB_TCPRETRANSFAIL = 76, - LINUX_MIB_TCPRCVCOALESCE = 77, - LINUX_MIB_TCPBACKLOGCOALESCE = 78, - LINUX_MIB_TCPOFOQUEUE = 79, - LINUX_MIB_TCPOFODROP = 80, - LINUX_MIB_TCPOFOMERGE = 81, - LINUX_MIB_TCPCHALLENGEACK = 82, - LINUX_MIB_TCPSYNCHALLENGE = 83, - LINUX_MIB_TCPFASTOPENACTIVE = 84, - LINUX_MIB_TCPFASTOPENACTIVEFAIL = 85, - LINUX_MIB_TCPFASTOPENPASSIVE = 86, - LINUX_MIB_TCPFASTOPENPASSIVEFAIL = 87, - LINUX_MIB_TCPFASTOPENLISTENOVERFLOW = 88, - LINUX_MIB_TCPFASTOPENCOOKIEREQD = 89, - LINUX_MIB_TCPFASTOPENBLACKHOLE = 90, - LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES = 91, - LINUX_MIB_BUSYPOLLRXPACKETS = 92, - LINUX_MIB_TCPAUTOCORKING = 93, - LINUX_MIB_TCPFROMZEROWINDOWADV = 94, - LINUX_MIB_TCPTOZEROWINDOWADV = 95, - LINUX_MIB_TCPWANTZEROWINDOWADV = 96, - LINUX_MIB_TCPSYNRETRANS = 97, - LINUX_MIB_TCPORIGDATASENT = 98, - LINUX_MIB_TCPHYSTARTTRAINDETECT = 99, - LINUX_MIB_TCPHYSTARTTRAINCWND = 100, - LINUX_MIB_TCPHYSTARTDELAYDETECT = 101, - LINUX_MIB_TCPHYSTARTDELAYCWND = 102, - LINUX_MIB_TCPACKSKIPPEDSYNRECV = 103, - LINUX_MIB_TCPACKSKIPPEDPAWS = 104, - LINUX_MIB_TCPACKSKIPPEDSEQ = 105, - LINUX_MIB_TCPACKSKIPPEDFINWAIT2 = 106, - LINUX_MIB_TCPACKSKIPPEDTIMEWAIT = 107, - LINUX_MIB_TCPACKSKIPPEDCHALLENGE = 108, - LINUX_MIB_TCPWINPROBE = 109, - LINUX_MIB_TCPKEEPALIVE = 110, - LINUX_MIB_TCPMTUPFAIL = 111, - LINUX_MIB_TCPMTUPSUCCESS = 112, - LINUX_MIB_TCPDELIVERED = 113, - LINUX_MIB_TCPDELIVEREDCE = 114, - LINUX_MIB_TCPACKCOMPRESSED = 115, - LINUX_MIB_TCPZEROWINDOWDROP = 116, - LINUX_MIB_TCPRCVQDROP = 117, - LINUX_MIB_TCPWQUEUETOOBIG = 118, - LINUX_MIB_TCPFASTOPENPASSIVEALTKEY = 119, - LINUX_MIB_TCPTIMEOUTREHASH = 120, - LINUX_MIB_TCPDUPLICATEDATAREHASH = 121, - LINUX_MIB_TCPDSACKRECVSEGS = 122, - LINUX_MIB_TCPDSACKIGNOREDDUBIOUS = 123, - __LINUX_MIB_MAX = 124, -}; - -enum { - LINUX_MIB_XFRMNUM = 0, - LINUX_MIB_XFRMINERROR = 1, - LINUX_MIB_XFRMINBUFFERERROR = 2, - LINUX_MIB_XFRMINHDRERROR = 3, - LINUX_MIB_XFRMINNOSTATES = 4, - LINUX_MIB_XFRMINSTATEPROTOERROR = 5, - LINUX_MIB_XFRMINSTATEMODEERROR = 6, - LINUX_MIB_XFRMINSTATESEQERROR = 7, - LINUX_MIB_XFRMINSTATEEXPIRED = 8, - LINUX_MIB_XFRMINSTATEMISMATCH = 9, - LINUX_MIB_XFRMINSTATEINVALID = 10, - LINUX_MIB_XFRMINTMPLMISMATCH = 11, - LINUX_MIB_XFRMINNOPOLS = 12, - LINUX_MIB_XFRMINPOLBLOCK = 13, - LINUX_MIB_XFRMINPOLERROR = 14, - LINUX_MIB_XFRMOUTERROR = 15, - LINUX_MIB_XFRMOUTBUNDLEGENERROR = 16, - LINUX_MIB_XFRMOUTBUNDLECHECKERROR = 17, - LINUX_MIB_XFRMOUTNOSTATES = 18, - LINUX_MIB_XFRMOUTSTATEPROTOERROR = 19, - LINUX_MIB_XFRMOUTSTATEMODEERROR = 20, - LINUX_MIB_XFRMOUTSTATESEQERROR = 21, - LINUX_MIB_XFRMOUTSTATEEXPIRED = 22, - LINUX_MIB_XFRMOUTPOLBLOCK = 23, - LINUX_MIB_XFRMOUTPOLDEAD = 24, - LINUX_MIB_XFRMOUTPOLERROR = 25, - LINUX_MIB_XFRMFWDHDRERROR = 26, - LINUX_MIB_XFRMOUTSTATEINVALID = 27, - LINUX_MIB_XFRMACQUIREERROR = 28, - __LINUX_MIB_XFRMMAX = 29, -}; - -enum { - LINUX_MIB_TLSNUM = 0, - LINUX_MIB_TLSCURRTXSW = 1, - LINUX_MIB_TLSCURRRXSW = 2, - LINUX_MIB_TLSCURRTXDEVICE = 3, - LINUX_MIB_TLSCURRRXDEVICE = 4, - LINUX_MIB_TLSTXSW = 5, - LINUX_MIB_TLSRXSW = 6, - LINUX_MIB_TLSTXDEVICE = 7, - LINUX_MIB_TLSRXDEVICE = 8, - LINUX_MIB_TLSDECRYPTERROR = 9, - LINUX_MIB_TLSRXDEVICERESYNC = 10, - __LINUX_MIB_TLSMAX = 11, -}; - -enum nf_inet_hooks { - NF_INET_PRE_ROUTING = 0, - NF_INET_LOCAL_IN = 1, - NF_INET_FORWARD = 2, - NF_INET_LOCAL_OUT = 3, - NF_INET_POST_ROUTING = 4, - NF_INET_NUMHOOKS = 5, - NF_INET_INGRESS = 5, -}; - -enum { - NFPROTO_UNSPEC = 0, - NFPROTO_INET = 1, - NFPROTO_IPV4 = 2, - NFPROTO_ARP = 3, - NFPROTO_NETDEV = 5, - NFPROTO_BRIDGE = 7, - NFPROTO_IPV6 = 10, - NFPROTO_DECNET = 12, - NFPROTO_NUMPROTO = 13, -}; - -enum tcp_conntrack { - TCP_CONNTRACK_NONE = 0, - TCP_CONNTRACK_SYN_SENT = 1, - TCP_CONNTRACK_SYN_RECV = 2, - TCP_CONNTRACK_ESTABLISHED = 3, - TCP_CONNTRACK_FIN_WAIT = 4, - TCP_CONNTRACK_CLOSE_WAIT = 5, - TCP_CONNTRACK_LAST_ACK = 6, - TCP_CONNTRACK_TIME_WAIT = 7, - TCP_CONNTRACK_CLOSE = 8, - TCP_CONNTRACK_LISTEN = 9, - TCP_CONNTRACK_MAX = 10, - TCP_CONNTRACK_IGNORE = 11, - TCP_CONNTRACK_RETRANS = 12, - TCP_CONNTRACK_UNACK = 13, - TCP_CONNTRACK_TIMEOUT_MAX = 14, -}; - -enum ct_dccp_states { - CT_DCCP_NONE = 0, - CT_DCCP_REQUEST = 1, - CT_DCCP_RESPOND = 2, - CT_DCCP_PARTOPEN = 3, - CT_DCCP_OPEN = 4, - CT_DCCP_CLOSEREQ = 5, - CT_DCCP_CLOSING = 6, - CT_DCCP_TIMEWAIT = 7, - CT_DCCP_IGNORE = 8, - CT_DCCP_INVALID = 9, - __CT_DCCP_MAX = 10, -}; - -enum ip_conntrack_dir { - IP_CT_DIR_ORIGINAL = 0, - IP_CT_DIR_REPLY = 1, - IP_CT_DIR_MAX = 2, -}; - -enum sctp_conntrack { - SCTP_CONNTRACK_NONE = 0, - SCTP_CONNTRACK_CLOSED = 1, - SCTP_CONNTRACK_COOKIE_WAIT = 2, - SCTP_CONNTRACK_COOKIE_ECHOED = 3, - SCTP_CONNTRACK_ESTABLISHED = 4, - SCTP_CONNTRACK_SHUTDOWN_SENT = 5, - SCTP_CONNTRACK_SHUTDOWN_RECD = 6, - SCTP_CONNTRACK_SHUTDOWN_ACK_SENT = 7, - SCTP_CONNTRACK_HEARTBEAT_SENT = 8, - SCTP_CONNTRACK_HEARTBEAT_ACKED = 9, - SCTP_CONNTRACK_MAX = 10, -}; - -enum udp_conntrack { - UDP_CT_UNREPLIED = 0, - UDP_CT_REPLIED = 1, - UDP_CT_MAX = 2, -}; - -enum gre_conntrack { - GRE_CT_UNREPLIED = 0, - GRE_CT_REPLIED = 1, - GRE_CT_MAX = 2, -}; - -enum { - XFRM_POLICY_IN = 0, - XFRM_POLICY_OUT = 1, - XFRM_POLICY_FWD = 2, - XFRM_POLICY_MASK = 3, - XFRM_POLICY_MAX = 3, -}; - -enum netns_bpf_attach_type { - NETNS_BPF_INVALID = 4294967295, - NETNS_BPF_FLOW_DISSECTOR = 0, - NETNS_BPF_SK_LOOKUP = 1, - MAX_NETNS_BPF_ATTACH_TYPE = 2, -}; - -enum cpu_idle_type { - CPU_IDLE = 0, - CPU_NOT_IDLE = 1, - CPU_NEWLY_IDLE = 2, - CPU_MAX_IDLE_TYPES = 3, -}; - -enum { - __SD_BALANCE_NEWIDLE = 0, - __SD_BALANCE_EXEC = 1, - __SD_BALANCE_FORK = 2, - __SD_BALANCE_WAKE = 3, - __SD_WAKE_AFFINE = 4, - __SD_ASYM_CPUCAPACITY = 5, - __SD_SHARE_CPUCAPACITY = 6, - __SD_SHARE_PKG_RESOURCES = 7, - __SD_SERIALIZE = 8, - __SD_ASYM_PACKING = 9, - __SD_PREFER_SIBLING = 10, - __SD_OVERLAP = 11, - __SD_NUMA = 12, - __SD_FLAG_CNT = 13, -}; - -enum skb_ext_id { - SKB_EXT_BRIDGE_NF = 0, - SKB_EXT_SEC_PATH = 1, - SKB_EXT_NUM = 2, -}; - -enum audit_ntp_type { - AUDIT_NTP_OFFSET = 0, - AUDIT_NTP_FREQ = 1, - AUDIT_NTP_STATUS = 2, - AUDIT_NTP_TAI = 3, - AUDIT_NTP_TICK = 4, - AUDIT_NTP_ADJUST = 5, - AUDIT_NTP_NVALS = 6, -}; - -typedef long unsigned int uintptr_t; - -struct step_hook { - struct list_head node; - int (*fn)(struct pt_regs *, unsigned int); -}; - -struct break_hook { - struct list_head node; - int (*fn)(struct pt_regs *, unsigned int); - u16 imm; - u16 mask; -}; - -enum dbg_active_el { - DBG_ACTIVE_EL0 = 0, - DBG_ACTIVE_EL1 = 1, -}; - -struct nmi_ctx { - u64 hcr; - unsigned int cnt; -}; - -struct midr_range { - u32 model; - u32 rv_min; - u32 rv_max; -}; - -struct arm64_midr_revidr { - u32 midr_rv; - u32 revidr_mask; -}; - -struct arm64_cpu_capabilities { - const char *desc; - u16 capability; - u16 type; - bool (*matches)(const struct arm64_cpu_capabilities *, int); - void (*cpu_enable)(const struct arm64_cpu_capabilities *); - union { - struct { - struct midr_range midr_range; - const struct arm64_midr_revidr * const fixed_revs; - }; - const struct midr_range *midr_range_list; - struct { - u32 sys_reg; - u8 field_pos; - u8 min_field_value; - u8 hwcap_type; - bool sign; - long unsigned int hwcap; - }; - }; - const struct arm64_cpu_capabilities *match_list; -}; - -enum cpu_pm_event { - CPU_PM_ENTER = 0, - CPU_PM_ENTER_FAILED = 1, - CPU_PM_EXIT = 2, - CPU_CLUSTER_PM_ENTER = 3, - CPU_CLUSTER_PM_ENTER_FAILED = 4, - CPU_CLUSTER_PM_EXIT = 5, -}; - -enum { - HI_SOFTIRQ = 0, - TIMER_SOFTIRQ = 1, - NET_TX_SOFTIRQ = 2, - NET_RX_SOFTIRQ = 3, - BLOCK_SOFTIRQ = 4, - IRQ_POLL_SOFTIRQ = 5, - TASKLET_SOFTIRQ = 6, - SCHED_SOFTIRQ = 7, - HRTIMER_SOFTIRQ = 8, - RCU_SOFTIRQ = 9, - NR_SOFTIRQS = 10, -}; - -struct fpsimd_last_state_struct { - struct user_fpsimd_state *st; - void *sve_state; - unsigned int sve_vl; -}; - -enum ctx_state { - CONTEXT_DISABLED = 4294967295, - CONTEXT_KERNEL = 0, - CONTEXT_USER = 1, - CONTEXT_GUEST = 2, -}; - -typedef void (*bp_hardening_cb_t)(); - -struct bp_hardening_data { - int hyp_vectors_slot; - bp_hardening_cb_t fn; -}; - -struct plist_head { - struct list_head node_list; -}; - -typedef struct { - __u8 b[16]; -} guid_t; - -enum pm_qos_type { - PM_QOS_UNITIALIZED = 0, - PM_QOS_MAX = 1, - PM_QOS_MIN = 2, -}; - -struct pm_qos_constraints { - struct plist_head list; - s32 target_value; - s32 default_value; - s32 no_constraint_value; - enum pm_qos_type type; - struct blocking_notifier_head *notifiers; -}; - -struct freq_constraints { - struct pm_qos_constraints min_freq; - struct blocking_notifier_head min_freq_notifiers; - struct pm_qos_constraints max_freq; - struct blocking_notifier_head max_freq_notifiers; -}; - -struct pm_qos_flags { - struct list_head list; - s32 effective_flags; -}; - -struct dev_pm_qos_request; - -struct dev_pm_qos { - struct pm_qos_constraints resume_latency; - struct pm_qos_constraints latency_tolerance; - struct freq_constraints freq; - struct pm_qos_flags flags; - struct dev_pm_qos_request *resume_latency_req; - struct dev_pm_qos_request *latency_tolerance_req; - struct dev_pm_qos_request *flags_req; -}; - -enum reboot_mode { - REBOOT_UNDEFINED = 4294967295, - REBOOT_COLD = 0, - REBOOT_WARM = 1, - REBOOT_HARD = 2, - REBOOT_SOFT = 3, - REBOOT_GPIO = 4, -}; - -typedef long unsigned int efi_status_t; - -typedef u8 efi_bool_t; - -typedef u16 efi_char16_t; - -typedef guid_t efi_guid_t; - -typedef struct { - u64 signature; - u32 revision; - u32 headersize; - u32 crc32; - u32 reserved; -} efi_table_hdr_t; - -typedef struct { - u32 type; - u32 pad; - u64 phys_addr; - u64 virt_addr; - u64 num_pages; - u64 attribute; -} efi_memory_desc_t; - -typedef struct { - efi_guid_t guid; - u32 headersize; - u32 flags; - u32 imagesize; -} efi_capsule_header_t; - -typedef struct { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 minute; - u8 second; - u8 pad1; - u32 nanosecond; - s16 timezone; - u8 daylight; - u8 pad2; -} efi_time_t; - -typedef struct { - u32 resolution; - u32 accuracy; - u8 sets_to_zero; -} efi_time_cap_t; - -typedef struct { - efi_table_hdr_t hdr; - u32 get_time; - u32 set_time; - u32 get_wakeup_time; - u32 set_wakeup_time; - u32 set_virtual_address_map; - u32 convert_pointer; - u32 get_variable; - u32 get_next_variable; - u32 set_variable; - u32 get_next_high_mono_count; - u32 reset_system; - u32 update_capsule; - u32 query_capsule_caps; - u32 query_variable_info; -} efi_runtime_services_32_t; - -typedef efi_status_t efi_get_time_t(efi_time_t *, efi_time_cap_t *); - -typedef efi_status_t efi_set_time_t(efi_time_t *); - -typedef efi_status_t efi_get_wakeup_time_t(efi_bool_t *, efi_bool_t *, efi_time_t *); - -typedef efi_status_t efi_set_wakeup_time_t(efi_bool_t, efi_time_t *); - -typedef efi_status_t efi_get_variable_t(efi_char16_t *, efi_guid_t *, u32 *, long unsigned int *, void *); - -typedef efi_status_t efi_get_next_variable_t(long unsigned int *, efi_char16_t *, efi_guid_t *); - -typedef efi_status_t efi_set_variable_t(efi_char16_t *, efi_guid_t *, u32, long unsigned int, void *); - -typedef efi_status_t efi_get_next_high_mono_count_t(u32 *); - -typedef void efi_reset_system_t(int, efi_status_t, long unsigned int, efi_char16_t *); - -typedef efi_status_t efi_set_virtual_address_map_t(long unsigned int, long unsigned int, u32, efi_memory_desc_t *); - -typedef efi_status_t efi_query_variable_info_t(u32, u64 *, u64 *, u64 *); - -typedef efi_status_t efi_update_capsule_t(efi_capsule_header_t **, long unsigned int, long unsigned int); - -typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **, long unsigned int, u64 *, int *); - -typedef union { - struct { - efi_table_hdr_t hdr; - efi_get_time_t *get_time; - efi_set_time_t *set_time; - efi_get_wakeup_time_t *get_wakeup_time; - efi_set_wakeup_time_t *set_wakeup_time; - efi_set_virtual_address_map_t *set_virtual_address_map; - void *convert_pointer; - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_get_next_high_mono_count_t *get_next_high_mono_count; - efi_reset_system_t *reset_system; - efi_update_capsule_t *update_capsule; - efi_query_capsule_caps_t *query_capsule_caps; - efi_query_variable_info_t *query_variable_info; - }; - efi_runtime_services_32_t mixed_mode; -} efi_runtime_services_t; - -struct efi_memory_map { - phys_addr_t phys_map; - void *map; - void *map_end; - int nr_map; - long unsigned int desc_version; - long unsigned int desc_size; - long unsigned int flags; -}; - -struct efi { - const efi_runtime_services_t *runtime; - unsigned int runtime_version; - unsigned int runtime_supported_mask; - long unsigned int acpi; - long unsigned int acpi20; - long unsigned int smbios; - long unsigned int smbios3; - long unsigned int esrt; - long unsigned int tpm_log; - long unsigned int tpm_final_log; - long unsigned int mokvar_table; - efi_get_time_t *get_time; - efi_set_time_t *set_time; - efi_get_wakeup_time_t *get_wakeup_time; - efi_set_wakeup_time_t *set_wakeup_time; - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_set_variable_t *set_variable_nonblocking; - efi_query_variable_info_t *query_variable_info; - efi_query_variable_info_t *query_variable_info_nonblocking; - efi_update_capsule_t *update_capsule; - efi_query_capsule_caps_t *query_capsule_caps; - efi_get_next_high_mono_count_t *get_next_high_mono_count; - efi_reset_system_t *reset_system; - struct efi_memory_map memmap; - long unsigned int flags; -}; - -struct arch_elf_state { - int flags; -}; - -struct pm_qos_flags_request { - struct list_head node; - s32 flags; -}; - -enum freq_qos_req_type { - FREQ_QOS_MIN = 1, - FREQ_QOS_MAX = 2, -}; - -struct freq_qos_request { - enum freq_qos_req_type type; - struct plist_node pnode; - struct freq_constraints *qos; -}; - -enum dev_pm_qos_req_type { - DEV_PM_QOS_RESUME_LATENCY = 1, - DEV_PM_QOS_LATENCY_TOLERANCE = 2, - DEV_PM_QOS_MIN_FREQUENCY = 3, - DEV_PM_QOS_MAX_FREQUENCY = 4, - DEV_PM_QOS_FLAGS = 5, -}; - -struct dev_pm_qos_request { - enum dev_pm_qos_req_type type; - union { - struct plist_node pnode; - struct pm_qos_flags_request flr; - struct freq_qos_request freq; - } data; - struct device *dev; -}; - -enum stack_type { - STACK_TYPE_UNKNOWN = 0, - STACK_TYPE_TASK = 1, - STACK_TYPE_IRQ = 2, - STACK_TYPE_OVERFLOW = 3, - STACK_TYPE_SDEI_NORMAL = 4, - STACK_TYPE_SDEI_CRITICAL = 5, - __NR_STACK_TYPES = 6, -}; - -struct stackframe { - long unsigned int fp; - long unsigned int pc; - long unsigned int stacks_done[1]; - long unsigned int prev_fp; - enum stack_type prev_type; - int graph; -}; - -struct user_sve_header { - __u32 size; - __u32 max_size; - __u16 vl; - __u16 max_vl; - __u16 flags; - __u16 __reserved; -}; - -struct user_pac_mask { - __u64 data_mask; - __u64 insn_mask; -}; - -typedef u32 compat_ulong_t; - -enum perf_type_id { - PERF_TYPE_HARDWARE = 0, - PERF_TYPE_SOFTWARE = 1, - PERF_TYPE_TRACEPOINT = 2, - PERF_TYPE_HW_CACHE = 3, - PERF_TYPE_RAW = 4, - PERF_TYPE_BREAKPOINT = 5, - PERF_TYPE_MAX = 6, -}; - -enum { - TASKSTATS_CMD_UNSPEC = 0, - TASKSTATS_CMD_GET = 1, - TASKSTATS_CMD_NEW = 2, - __TASKSTATS_CMD_MAX = 3, -}; - -enum cpu_usage_stat { - CPUTIME_USER = 0, - CPUTIME_NICE = 1, - CPUTIME_SYSTEM = 2, - CPUTIME_SOFTIRQ = 3, - CPUTIME_IRQ = 4, - CPUTIME_IDLE = 5, - CPUTIME_IOWAIT = 6, - CPUTIME_STEAL = 7, - CPUTIME_GUEST = 8, - CPUTIME_GUEST_NICE = 9, - NR_STATS = 10, -}; - -enum bpf_cgroup_storage_type { - BPF_CGROUP_STORAGE_SHARED = 0, - BPF_CGROUP_STORAGE_PERCPU = 1, - __BPF_CGROUP_STORAGE_MAX = 2, -}; - -enum bpf_tramp_prog_type { - BPF_TRAMP_FENTRY = 0, - BPF_TRAMP_FEXIT = 1, - BPF_TRAMP_MODIFY_RETURN = 2, - BPF_TRAMP_MAX = 3, - BPF_TRAMP_REPLACE = 4, -}; - -enum cgroup_subsys_id { - cpuset_cgrp_id = 0, - cpu_cgrp_id = 1, - cpuacct_cgrp_id = 2, - io_cgrp_id = 3, - memory_cgrp_id = 4, - devices_cgrp_id = 5, - freezer_cgrp_id = 6, - net_cls_cgrp_id = 7, - perf_event_cgrp_id = 8, - net_prio_cgrp_id = 9, - pids_cgrp_id = 10, - CGROUP_SUBSYS_COUNT = 11, -}; - -enum { - HW_BREAKPOINT_LEN_1 = 1, - HW_BREAKPOINT_LEN_2 = 2, - HW_BREAKPOINT_LEN_3 = 3, - HW_BREAKPOINT_LEN_4 = 4, - HW_BREAKPOINT_LEN_5 = 5, - HW_BREAKPOINT_LEN_6 = 6, - HW_BREAKPOINT_LEN_7 = 7, - HW_BREAKPOINT_LEN_8 = 8, -}; - -enum { - HW_BREAKPOINT_EMPTY = 0, - HW_BREAKPOINT_R = 1, - HW_BREAKPOINT_W = 2, - HW_BREAKPOINT_RW = 3, - HW_BREAKPOINT_X = 4, - HW_BREAKPOINT_INVALID = 7, -}; - -enum bp_type_idx { - TYPE_INST = 0, - TYPE_DATA = 1, - TYPE_MAX = 2, -}; - -struct membuf { - void *p; - size_t left; -}; - -struct user_regset; - -typedef int user_regset_active_fn(struct task_struct *, const struct user_regset *); - -typedef int user_regset_get2_fn(struct task_struct *, const struct user_regset *, struct membuf); - -typedef int user_regset_set_fn(struct task_struct *, const struct user_regset *, unsigned int, unsigned int, const void *, const void *); - -typedef int user_regset_writeback_fn(struct task_struct *, const struct user_regset *, int); - -struct user_regset { - user_regset_get2_fn *regset_get; - user_regset_set_fn *set; - user_regset_active_fn *active; - user_regset_writeback_fn *writeback; - unsigned int n; - unsigned int size; - unsigned int align; - unsigned int bias; - unsigned int core_note_type; -}; - -struct user_regset_view { - const char *name; - const struct user_regset *regsets; - unsigned int n; - u32 e_flags; - u16 e_machine; - u8 ei_osabi; -}; - -struct stack_info { - long unsigned int low; - long unsigned int high; - enum stack_type type; -}; - -struct trace_event_raw_sys_enter { - struct trace_entry ent; - long int id; - long unsigned int args[6]; - char __data[0]; -}; - -struct trace_event_raw_sys_exit { - struct trace_entry ent; - long int id; - long int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_sys_enter {}; - -struct trace_event_data_offsets_sys_exit {}; - -typedef void (*btf_trace_sys_enter)(void *, struct pt_regs *, long int); - -typedef void (*btf_trace_sys_exit)(void *, struct pt_regs *, long int); - -struct pt_regs_offset { - const char *name; - int offset; -}; - -enum aarch64_regset { - REGSET_GPR = 0, - REGSET_FPR = 1, - REGSET_TLS = 2, - REGSET_HW_BREAK = 3, - REGSET_HW_WATCH = 4, - REGSET_SYSTEM_CALL = 5, - REGSET_SVE = 6, - REGSET_PAC_MASK = 7, - REGSET_TAGGED_ADDR_CTRL = 8, -}; - -enum compat_regset { - REGSET_COMPAT_GPR = 0, - REGSET_COMPAT_VFP = 1, -}; - -enum ptrace_syscall_dir { - PTRACE_SYSCALL_ENTER = 0, - PTRACE_SYSCALL_EXIT = 1, -}; - -typedef phys_addr_t resource_size_t; - -struct resource { - resource_size_t start; - resource_size_t end; - const char *name; - long unsigned int flags; - long unsigned int desc; - struct resource *parent; - struct resource *sibling; - struct resource *child; -}; - -struct atomic_notifier_head { - spinlock_t lock; - struct notifier_block *head; -}; - -struct cpu { - int node_id; - int hotpluggable; - struct device dev; -}; - -enum memblock_flags { - MEMBLOCK_NONE = 0, - MEMBLOCK_HOTPLUG = 1, - MEMBLOCK_MIRROR = 2, - MEMBLOCK_NOMAP = 4, -}; - -struct memblock_region { - phys_addr_t base; - phys_addr_t size; - enum memblock_flags flags; -}; - -struct memblock_type { - long unsigned int cnt; - long unsigned int max; - phys_addr_t total_size; - struct memblock_region *regions; - char *name; -}; - -struct memblock { - bool bottom_up; - phys_addr_t current_limit; - struct memblock_type memory; - struct memblock_type reserved; -}; - -struct mpidr_hash { - u64 mask; - u32 shift_aff[4]; - u32 bits; -}; - -struct cpuinfo_arm64 { - struct cpu cpu; - struct kobject kobj; - u32 reg_ctr; - u32 reg_cntfrq; - u32 reg_dczid; - u32 reg_midr; - u32 reg_revidr; - u64 reg_id_aa64dfr0; - u64 reg_id_aa64dfr1; - u64 reg_id_aa64isar0; - u64 reg_id_aa64isar1; - u64 reg_id_aa64mmfr0; - u64 reg_id_aa64mmfr1; - u64 reg_id_aa64mmfr2; - u64 reg_id_aa64pfr0; - u64 reg_id_aa64pfr1; - u64 reg_id_aa64zfr0; - u32 reg_id_dfr0; - u32 reg_id_dfr1; - u32 reg_id_isar0; - u32 reg_id_isar1; - u32 reg_id_isar2; - u32 reg_id_isar3; - u32 reg_id_isar4; - u32 reg_id_isar5; - u32 reg_id_isar6; - u32 reg_id_mmfr0; - u32 reg_id_mmfr1; - u32 reg_id_mmfr2; - u32 reg_id_mmfr3; - u32 reg_id_mmfr4; - u32 reg_id_mmfr5; - u32 reg_id_pfr0; - u32 reg_id_pfr1; - u32 reg_id_pfr2; - u32 reg_mvfr0; - u32 reg_mvfr1; - u32 reg_mvfr2; - u64 reg_zcr; -}; - -struct sigcontext { - __u64 fault_address; - __u64 regs[31]; - __u64 sp; - __u64 pc; - __u64 pstate; - long: 64; - __u8 __reserved[4096]; -}; - -struct _aarch64_ctx { - __u32 magic; - __u32 size; -}; - -struct fpsimd_context { - struct _aarch64_ctx head; - __u32 fpsr; - __u32 fpcr; - __int128 unsigned vregs[32]; -}; - -struct esr_context { - struct _aarch64_ctx head; - __u64 esr; -}; - -struct extra_context { - struct _aarch64_ctx head; - __u64 datap; - __u32 size; - __u32 __reserved[3]; -}; - -struct sve_context { - struct _aarch64_ctx head; - __u16 vl; - __u16 __reserved[3]; -}; - -struct sigaltstack { - void *ss_sp; - int ss_flags; - size_t ss_size; -}; - -typedef struct sigaltstack stack_t; - -struct siginfo { - union { - struct { - int si_signo; - int si_errno; - int si_code; - union __sifields _sifields; - }; - int _si_pad[32]; - }; -}; - -struct ksignal { - struct k_sigaction ka; - kernel_siginfo_t info; - int sig; -}; - -enum { - EI_ETYPE_NONE = 0, - EI_ETYPE_NULL = 1, - EI_ETYPE_ERRNO = 2, - EI_ETYPE_ERRNO_NULL = 3, - EI_ETYPE_TRUE = 4, -}; - -struct ucontext { - long unsigned int uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - sigset_t uc_sigmask; - __u8 __unused[120]; - long: 64; - struct sigcontext uc_mcontext; -}; - -struct rt_sigframe { - struct siginfo info; - struct ucontext uc; -}; - -struct frame_record { - u64 fp; - u64 lr; -}; - -struct rt_sigframe_user_layout { - struct rt_sigframe *sigframe; - struct frame_record *next_frame; - long unsigned int size; - long unsigned int limit; - long unsigned int fpsimd_offset; - long unsigned int esr_offset; - long unsigned int sve_offset; - long unsigned int extra_offset; - long unsigned int end_offset; -}; - -struct user_ctxs { - struct fpsimd_context *fpsimd; - struct sve_context *sve; -}; - -enum { - PER_LINUX = 0, - PER_LINUX_32BIT = 8388608, - PER_LINUX_FDPIC = 524288, - PER_SVR4 = 68157441, - PER_SVR3 = 83886082, - PER_SCOSVR3 = 117440515, - PER_OSR5 = 100663299, - PER_WYSEV386 = 83886084, - PER_ISCR4 = 67108869, - PER_BSD = 6, - PER_SUNOS = 67108870, - PER_XENIX = 83886087, - PER_LINUX32 = 8, - PER_LINUX32_3GB = 134217736, - PER_IRIX32 = 67108873, - PER_IRIXN32 = 67108874, - PER_IRIX64 = 67108875, - PER_RISCOS = 12, - PER_SOLARIS = 67108877, - PER_UW7 = 68157454, - PER_OSF4 = 15, - PER_HPUX = 16, - PER_MASK = 255, -}; - -typedef long int (*syscall_fn_t)(const struct pt_regs *); - -typedef bool (*stack_trace_consume_fn)(void *, long unsigned int); - -typedef bool pstate_check_t(long unsigned int); - -enum lockdep_ok { - LOCKDEP_STILL_OK = 0, - LOCKDEP_NOW_UNRELIABLE = 1, -}; - -enum bug_trap_type { - BUG_TRAP_TYPE_NONE = 0, - BUG_TRAP_TYPE_WARN = 1, - BUG_TRAP_TYPE_BUG = 2, -}; - -enum ftr_type { - FTR_EXACT = 0, - FTR_LOWER_SAFE = 1, - FTR_HIGHER_SAFE = 2, - FTR_HIGHER_OR_ZERO_SAFE = 3, -}; - -struct arm64_ftr_bits { - bool sign; - bool visible; - bool strict; - enum ftr_type type; - u8 shift; - u8 width; - s64 safe_val; -}; - -struct arm64_ftr_reg { - const char *name; - u64 strict_mask; - u64 user_mask; - u64 sys_val; - u64 user_val; - const struct arm64_ftr_bits *ftr_bits; -}; - -enum siginfo_layout { - SIL_KILL = 0, - SIL_TIMER = 1, - SIL_POLL = 2, - SIL_FAULT = 3, - SIL_FAULT_MCEERR = 4, - SIL_FAULT_BNDERR = 5, - SIL_FAULT_PKUERR = 6, - SIL_CHLD = 7, - SIL_RT = 8, - SIL_SYS = 9, -}; - -enum die_val { - DIE_UNUSED = 0, - DIE_OOPS = 1, -}; - -struct undef_hook { - struct list_head node; - u32 instr_mask; - u32 instr_val; - u64 pstate_mask; - u64 pstate_val; - int (*fn)(struct pt_regs *, u32); -}; - -struct sys64_hook { - unsigned int esr_mask; - unsigned int esr_val; - void (*handler)(unsigned int, struct pt_regs *); -}; - -struct timens_offset { - s64 sec; - u64 nsec; -}; - -enum vm_fault_reason { - VM_FAULT_OOM = 1, - VM_FAULT_SIGBUS = 2, - VM_FAULT_MAJOR = 4, - VM_FAULT_WRITE = 8, - VM_FAULT_HWPOISON = 16, - VM_FAULT_HWPOISON_LARGE = 32, - VM_FAULT_SIGSEGV = 64, - VM_FAULT_NOPAGE = 256, - VM_FAULT_LOCKED = 512, - VM_FAULT_RETRY = 1024, - VM_FAULT_FALLBACK = 2048, - VM_FAULT_DONE_COW = 4096, - VM_FAULT_NEEDDSYNC = 8192, - VM_FAULT_HINDEX_MASK = 983040, -}; - -struct vm_special_mapping { - const char *name; - struct page **pages; - vm_fault_t (*fault)(const struct vm_special_mapping *, struct vm_area_struct *, struct vm_fault *); - int (*mremap)(const struct vm_special_mapping *, struct vm_area_struct *); -}; - -struct timens_offsets { - struct timespec64 monotonic; - struct timespec64 boottime; -}; - -struct time_namespace { - struct kref kref; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct ns_common ns; - struct timens_offsets offsets; - struct page *vvar_page; - bool frozen_offsets; -}; - -struct arch_vdso_data {}; - -struct vdso_timestamp { - u64 sec; - u64 nsec; -}; - -struct vdso_data { - u32 seq; - s32 clock_mode; - u64 cycle_last; - u64 mask; - u32 mult; - u32 shift; - union { - struct vdso_timestamp basetime[12]; - struct timens_offset offset[12]; - }; - s32 tz_minuteswest; - s32 tz_dsttime; - u32 hrtimer_res; - u32 __unused; - struct arch_vdso_data arch_data; -}; - -enum vdso_abi { - VDSO_ABI_AA64 = 0, - VDSO_ABI_AA32 = 1, -}; - -enum vvar_pages { - VVAR_DATA_PAGE_OFFSET = 0, - VVAR_TIMENS_PAGE_OFFSET = 1, - VVAR_NR_PAGES = 2, -}; - -struct vdso_abi_info { - const char *name; - const char *vdso_code_start; - const char *vdso_code_end; - long unsigned int vdso_pages; - struct vm_special_mapping *dm; - struct vm_special_mapping *cm; -}; - -enum aarch32_map { - AA32_MAP_VECTORS = 0, - AA32_MAP_SIGPAGE = 1, - AA32_MAP_VVAR = 2, - AA32_MAP_VDSO = 3, -}; - -enum aarch64_map { - AA64_MAP_VVAR = 0, - AA64_MAP_VDSO = 1, -}; - -struct psci_operations { - u32 (*get_version)(); - int (*cpu_suspend)(u32, long unsigned int); - int (*cpu_off)(u32); - int (*cpu_on)(long unsigned int, long unsigned int); - int (*migrate)(long unsigned int); - int (*affinity_info)(long unsigned int, long unsigned int); - int (*migrate_info_type)(); -}; - -struct cpu_operations { - const char *name; - int (*cpu_init)(unsigned int); - int (*cpu_prepare)(unsigned int); - int (*cpu_boot)(unsigned int); - void (*cpu_postboot)(); - int (*cpu_init_idle)(unsigned int); - int (*cpu_suspend)(long unsigned int); -}; - -enum aarch64_insn_encoding_class { - AARCH64_INSN_CLS_UNKNOWN = 0, - AARCH64_INSN_CLS_DP_IMM = 1, - AARCH64_INSN_CLS_DP_REG = 2, - AARCH64_INSN_CLS_DP_FPSIMD = 3, - AARCH64_INSN_CLS_LDST = 4, - AARCH64_INSN_CLS_BR_SYS = 5, -}; - -enum aarch64_insn_hint_cr_op { - AARCH64_INSN_HINT_NOP = 0, - AARCH64_INSN_HINT_YIELD = 32, - AARCH64_INSN_HINT_WFE = 64, - AARCH64_INSN_HINT_WFI = 96, - AARCH64_INSN_HINT_SEV = 128, - AARCH64_INSN_HINT_SEVL = 160, - AARCH64_INSN_HINT_XPACLRI = 224, - AARCH64_INSN_HINT_PACIA_1716 = 256, - AARCH64_INSN_HINT_PACIB_1716 = 320, - AARCH64_INSN_HINT_AUTIA_1716 = 384, - AARCH64_INSN_HINT_AUTIB_1716 = 448, - AARCH64_INSN_HINT_PACIAZ = 768, - AARCH64_INSN_HINT_PACIASP = 800, - AARCH64_INSN_HINT_PACIBZ = 832, - AARCH64_INSN_HINT_PACIBSP = 864, - AARCH64_INSN_HINT_AUTIAZ = 896, - AARCH64_INSN_HINT_AUTIASP = 928, - AARCH64_INSN_HINT_AUTIBZ = 960, - AARCH64_INSN_HINT_AUTIBSP = 992, - AARCH64_INSN_HINT_ESB = 512, - AARCH64_INSN_HINT_PSB = 544, - AARCH64_INSN_HINT_TSB = 576, - AARCH64_INSN_HINT_CSDB = 640, - AARCH64_INSN_HINT_BTI = 1024, - AARCH64_INSN_HINT_BTIC = 1088, - AARCH64_INSN_HINT_BTIJ = 1152, - AARCH64_INSN_HINT_BTIJC = 1216, -}; - -enum aarch64_insn_imm_type { - AARCH64_INSN_IMM_ADR = 0, - AARCH64_INSN_IMM_26 = 1, - AARCH64_INSN_IMM_19 = 2, - AARCH64_INSN_IMM_16 = 3, - AARCH64_INSN_IMM_14 = 4, - AARCH64_INSN_IMM_12 = 5, - AARCH64_INSN_IMM_9 = 6, - AARCH64_INSN_IMM_7 = 7, - AARCH64_INSN_IMM_6 = 8, - AARCH64_INSN_IMM_S = 9, - AARCH64_INSN_IMM_R = 10, - AARCH64_INSN_IMM_N = 11, - AARCH64_INSN_IMM_MAX = 12, -}; - -enum aarch64_insn_register_type { - AARCH64_INSN_REGTYPE_RT = 0, - AARCH64_INSN_REGTYPE_RN = 1, - AARCH64_INSN_REGTYPE_RT2 = 2, - AARCH64_INSN_REGTYPE_RM = 3, - AARCH64_INSN_REGTYPE_RD = 4, - AARCH64_INSN_REGTYPE_RA = 5, - AARCH64_INSN_REGTYPE_RS = 6, -}; - -enum aarch64_insn_register { - AARCH64_INSN_REG_0 = 0, - AARCH64_INSN_REG_1 = 1, - AARCH64_INSN_REG_2 = 2, - AARCH64_INSN_REG_3 = 3, - AARCH64_INSN_REG_4 = 4, - AARCH64_INSN_REG_5 = 5, - AARCH64_INSN_REG_6 = 6, - AARCH64_INSN_REG_7 = 7, - AARCH64_INSN_REG_8 = 8, - AARCH64_INSN_REG_9 = 9, - AARCH64_INSN_REG_10 = 10, - AARCH64_INSN_REG_11 = 11, - AARCH64_INSN_REG_12 = 12, - AARCH64_INSN_REG_13 = 13, - AARCH64_INSN_REG_14 = 14, - AARCH64_INSN_REG_15 = 15, - AARCH64_INSN_REG_16 = 16, - AARCH64_INSN_REG_17 = 17, - AARCH64_INSN_REG_18 = 18, - AARCH64_INSN_REG_19 = 19, - AARCH64_INSN_REG_20 = 20, - AARCH64_INSN_REG_21 = 21, - AARCH64_INSN_REG_22 = 22, - AARCH64_INSN_REG_23 = 23, - AARCH64_INSN_REG_24 = 24, - AARCH64_INSN_REG_25 = 25, - AARCH64_INSN_REG_26 = 26, - AARCH64_INSN_REG_27 = 27, - AARCH64_INSN_REG_28 = 28, - AARCH64_INSN_REG_29 = 29, - AARCH64_INSN_REG_FP = 29, - AARCH64_INSN_REG_30 = 30, - AARCH64_INSN_REG_LR = 30, - AARCH64_INSN_REG_ZR = 31, - AARCH64_INSN_REG_SP = 31, -}; - -enum aarch64_insn_variant { - AARCH64_INSN_VARIANT_32BIT = 0, - AARCH64_INSN_VARIANT_64BIT = 1, -}; - -enum aarch64_insn_condition { - AARCH64_INSN_COND_EQ = 0, - AARCH64_INSN_COND_NE = 1, - AARCH64_INSN_COND_CS = 2, - AARCH64_INSN_COND_CC = 3, - AARCH64_INSN_COND_MI = 4, - AARCH64_INSN_COND_PL = 5, - AARCH64_INSN_COND_VS = 6, - AARCH64_INSN_COND_VC = 7, - AARCH64_INSN_COND_HI = 8, - AARCH64_INSN_COND_LS = 9, - AARCH64_INSN_COND_GE = 10, - AARCH64_INSN_COND_LT = 11, - AARCH64_INSN_COND_GT = 12, - AARCH64_INSN_COND_LE = 13, - AARCH64_INSN_COND_AL = 14, -}; - -enum aarch64_insn_branch_type { - AARCH64_INSN_BRANCH_NOLINK = 0, - AARCH64_INSN_BRANCH_LINK = 1, - AARCH64_INSN_BRANCH_RETURN = 2, - AARCH64_INSN_BRANCH_COMP_ZERO = 3, - AARCH64_INSN_BRANCH_COMP_NONZERO = 4, -}; - -enum aarch64_insn_size_type { - AARCH64_INSN_SIZE_8 = 0, - AARCH64_INSN_SIZE_16 = 1, - AARCH64_INSN_SIZE_32 = 2, - AARCH64_INSN_SIZE_64 = 3, -}; - -enum aarch64_insn_ldst_type { - AARCH64_INSN_LDST_LOAD_REG_OFFSET = 0, - AARCH64_INSN_LDST_STORE_REG_OFFSET = 1, - AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX = 2, - AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX = 3, - AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX = 4, - AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX = 5, - AARCH64_INSN_LDST_LOAD_EX = 6, - AARCH64_INSN_LDST_STORE_EX = 7, -}; - -enum aarch64_insn_adsb_type { - AARCH64_INSN_ADSB_ADD = 0, - AARCH64_INSN_ADSB_SUB = 1, - AARCH64_INSN_ADSB_ADD_SETFLAGS = 2, - AARCH64_INSN_ADSB_SUB_SETFLAGS = 3, -}; - -enum aarch64_insn_movewide_type { - AARCH64_INSN_MOVEWIDE_ZERO = 0, - AARCH64_INSN_MOVEWIDE_KEEP = 1, - AARCH64_INSN_MOVEWIDE_INVERSE = 2, -}; - -enum aarch64_insn_bitfield_type { - AARCH64_INSN_BITFIELD_MOVE = 0, - AARCH64_INSN_BITFIELD_MOVE_UNSIGNED = 1, - AARCH64_INSN_BITFIELD_MOVE_SIGNED = 2, -}; - -enum aarch64_insn_data1_type { - AARCH64_INSN_DATA1_REVERSE_16 = 0, - AARCH64_INSN_DATA1_REVERSE_32 = 1, - AARCH64_INSN_DATA1_REVERSE_64 = 2, -}; - -enum aarch64_insn_data2_type { - AARCH64_INSN_DATA2_UDIV = 0, - AARCH64_INSN_DATA2_SDIV = 1, - AARCH64_INSN_DATA2_LSLV = 2, - AARCH64_INSN_DATA2_LSRV = 3, - AARCH64_INSN_DATA2_ASRV = 4, - AARCH64_INSN_DATA2_RORV = 5, -}; - -enum aarch64_insn_data3_type { - AARCH64_INSN_DATA3_MADD = 0, - AARCH64_INSN_DATA3_MSUB = 1, -}; - -enum aarch64_insn_logic_type { - AARCH64_INSN_LOGIC_AND = 0, - AARCH64_INSN_LOGIC_BIC = 1, - AARCH64_INSN_LOGIC_ORR = 2, - AARCH64_INSN_LOGIC_ORN = 3, - AARCH64_INSN_LOGIC_EOR = 4, - AARCH64_INSN_LOGIC_EON = 5, - AARCH64_INSN_LOGIC_AND_SETFLAGS = 6, - AARCH64_INSN_LOGIC_BIC_SETFLAGS = 7, -}; - -enum aarch64_insn_prfm_type { - AARCH64_INSN_PRFM_TYPE_PLD = 0, - AARCH64_INSN_PRFM_TYPE_PLI = 1, - AARCH64_INSN_PRFM_TYPE_PST = 2, -}; - -enum aarch64_insn_prfm_target { - AARCH64_INSN_PRFM_TARGET_L1 = 0, - AARCH64_INSN_PRFM_TARGET_L2 = 1, - AARCH64_INSN_PRFM_TARGET_L3 = 2, -}; - -enum aarch64_insn_prfm_policy { - AARCH64_INSN_PRFM_POLICY_KEEP = 0, - AARCH64_INSN_PRFM_POLICY_STRM = 1, -}; - -enum aarch64_insn_adr_type { - AARCH64_INSN_ADR_TYPE_ADRP = 0, - AARCH64_INSN_ADR_TYPE_ADR = 1, -}; - -enum fixed_addresses { - FIX_HOLE = 0, - FIX_FDT_END = 1, - FIX_FDT = 1024, - FIX_EARLYCON_MEM_BASE = 1025, - FIX_TEXT_POKE0 = 1026, - FIX_ENTRY_TRAMP_DATA = 1027, - FIX_ENTRY_TRAMP_TEXT = 1028, - __end_of_permanent_fixed_addresses = 1029, - FIX_BTMAP_END = 1029, - FIX_BTMAP_BEGIN = 1476, - FIX_PTE = 1477, - FIX_PMD = 1478, - FIX_PUD = 1479, - FIX_PGD = 1480, - __end_of_fixed_addresses = 1481, -}; - -struct aarch64_insn_patch { - void **text_addrs; - u32 *new_insns; - int insn_cnt; - atomic_t cpu_count; -}; - -struct return_address_data { - unsigned int level; - void *addr; -}; - -struct kobj_attribute { - struct attribute attr; - ssize_t (*show)(struct kobject *, struct kobj_attribute *, char *); - ssize_t (*store)(struct kobject *, struct kobj_attribute *, const char *, size_t); -}; - -enum { - CAP_HWCAP = 1, - CAP_COMPAT_HWCAP = 2, - CAP_COMPAT_HWCAP2 = 3, -}; - -struct secondary_data { - void *stack; - struct task_struct *task; - long int status; -}; - -enum pageflags { - PG_locked = 0, - PG_referenced = 1, - PG_uptodate = 2, - PG_dirty = 3, - PG_lru = 4, - PG_active = 5, - PG_workingset = 6, - PG_waiters = 7, - PG_error = 8, - PG_slab = 9, - PG_owner_priv_1 = 10, - PG_arch_1 = 11, - PG_reserved = 12, - PG_private = 13, - PG_private_2 = 14, - PG_writeback = 15, - PG_head = 16, - PG_mappedtodisk = 17, - PG_reclaim = 18, - PG_swapbacked = 19, - PG_unevictable = 20, - PG_mlocked = 21, - PG_arch_2 = 22, - __NR_PAGEFLAGS = 23, - PG_checked = 10, - PG_swapcache = 10, - PG_fscache = 14, - PG_pinned = 10, - PG_savepinned = 3, - PG_foreign = 10, - PG_xen_remapped = 10, - PG_slob_free = 13, - PG_double_map = 6, - PG_isolated = 18, - PG_reported = 2, -}; - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device *, struct device_attribute *, char *); - ssize_t (*store)(struct device *, struct device_attribute *, const char *, size_t); -}; - -struct __ftr_reg_entry { - u32 sys_id; - struct arm64_ftr_reg *reg; -}; - -typedef void kpti_remap_fn(int, int, phys_addr_t); - -typedef void ttbr_replace_func(phys_addr_t); - -struct alt_instr { - s32 orig_offset; - s32 alt_offset; - u16 cpufeature; - u8 orig_len; - u8 alt_len; -}; - -typedef void (*alternative_cb_t)(struct alt_instr *, __le32 *, __le32 *, int); - -struct alt_region { - struct alt_instr *begin; - struct alt_instr *end; -}; - -enum cache_type { - CACHE_TYPE_NOCACHE = 0, - CACHE_TYPE_INST = 1, - CACHE_TYPE_DATA = 2, - CACHE_TYPE_SEPARATE = 3, - CACHE_TYPE_UNIFIED = 4, -}; - -struct cacheinfo { - unsigned int id; - enum cache_type type; - unsigned int level; - unsigned int coherency_line_size; - unsigned int number_of_sets; - unsigned int ways_of_associativity; - unsigned int physical_line_partition; - unsigned int size; - cpumask_t shared_cpu_map; - unsigned int attributes; - void *fw_token; - bool disable_sysfs; - void *priv; -}; - -struct cpu_cacheinfo { - struct cacheinfo *info_list; - unsigned int num_levels; - unsigned int num_leaves; - bool cpu_map_populated; -}; - -struct irq_desc; - -typedef void (*irq_flow_handler_t)(struct irq_desc *); - -struct msi_desc; - -struct irq_common_data { - unsigned int state_use_accessors; - void *handler_data; - struct msi_desc *msi_desc; - cpumask_var_t affinity; - cpumask_var_t effective_affinity; - unsigned int ipi_offset; -}; - -struct irq_chip; - -struct irq_data { - u32 mask; - unsigned int irq; - long unsigned int hwirq; - struct irq_common_data *common; - struct irq_chip *chip; - struct irq_domain *domain; - struct irq_data *parent_data; - void *chip_data; -}; - -struct irqaction; - -struct irq_affinity_notify; - -struct irq_desc { - struct irq_common_data irq_common_data; - struct irq_data irq_data; - unsigned int *kstat_irqs; - irq_flow_handler_t handle_irq; - struct irqaction *action; - unsigned int status_use_accessors; - unsigned int core_internal_state__do_not_mess_with_it; - unsigned int depth; - unsigned int wake_depth; - unsigned int tot_count; - unsigned int irq_count; - long unsigned int last_unhandled; - unsigned int irqs_unhandled; - atomic_t threads_handled; - int threads_handled_last; - raw_spinlock_t lock; - struct cpumask *percpu_enabled; - const struct cpumask *percpu_affinity; - const struct cpumask *affinity_hint; - struct irq_affinity_notify *affinity_notify; - long unsigned int threads_oneshot; - atomic_t threads_active; - wait_queue_head_t wait_for_threads; - struct proc_dir_entry *dir; - struct dentry *debugfs_file; - const char *dev_name; - struct callback_head rcu; - struct kobject kobj; - struct mutex request_mutex; - int parent_irq; - struct module *owner; - const char *name; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum irq_gc_flags { - IRQ_GC_INIT_MASK_CACHE = 1, - IRQ_GC_INIT_NESTED_LOCK = 2, - IRQ_GC_MASK_CACHE_PER_TYPE = 4, - IRQ_GC_NO_MASK = 8, - IRQ_GC_BE_IO = 16, -}; - -struct irq_chip_generic; - -struct irq_domain_chip_generic { - unsigned int irqs_per_chip; - unsigned int num_chips; - unsigned int irq_flags_to_clear; - unsigned int irq_flags_to_set; - enum irq_gc_flags gc_flags; - struct irq_chip_generic *gc[0]; -}; - -enum irqreturn { - IRQ_NONE = 0, - IRQ_HANDLED = 1, - IRQ_WAKE_THREAD = 2, -}; - -typedef enum irqreturn irqreturn_t; - -typedef irqreturn_t (*irq_handler_t)(int, void *); - -struct irqaction { - irq_handler_t handler; - void *dev_id; - void *percpu_dev_id; - struct irqaction *next; - irq_handler_t thread_fn; - struct task_struct *thread; - struct irqaction *secondary; - unsigned int irq; - unsigned int flags; - long unsigned int thread_flags; - long unsigned int thread_mask; - const char *name; - struct proc_dir_entry *dir; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct irq_affinity_notify { - unsigned int irq; - struct kref kref; - struct work_struct work; - void (*notify)(struct irq_affinity_notify *, const cpumask_t *); - void (*release)(struct kref *); -}; - -struct irq_affinity_desc { - struct cpumask mask; - unsigned int is_managed: 1; -}; - -enum irqchip_irq_state { - IRQCHIP_STATE_PENDING = 0, - IRQCHIP_STATE_ACTIVE = 1, - IRQCHIP_STATE_MASKED = 2, - IRQCHIP_STATE_LINE_LEVEL = 3, -}; - -enum { - IRQ_TYPE_NONE = 0, - IRQ_TYPE_EDGE_RISING = 1, - IRQ_TYPE_EDGE_FALLING = 2, - IRQ_TYPE_EDGE_BOTH = 3, - IRQ_TYPE_LEVEL_HIGH = 4, - IRQ_TYPE_LEVEL_LOW = 8, - IRQ_TYPE_LEVEL_MASK = 12, - IRQ_TYPE_SENSE_MASK = 15, - IRQ_TYPE_DEFAULT = 15, - IRQ_TYPE_PROBE = 16, - IRQ_LEVEL = 256, - IRQ_PER_CPU = 512, - IRQ_NOPROBE = 1024, - IRQ_NOREQUEST = 2048, - IRQ_NOAUTOEN = 4096, - IRQ_NO_BALANCING = 8192, - IRQ_MOVE_PCNTXT = 16384, - IRQ_NESTED_THREAD = 32768, - IRQ_NOTHREAD = 65536, - IRQ_PER_CPU_DEVID = 131072, - IRQ_IS_POLLED = 262144, - IRQ_DISABLE_UNLAZY = 524288, - IRQ_HIDDEN = 1048576, -}; - -struct msi_msg { - u32 address_lo; - u32 address_hi; - u32 data; -}; - -struct platform_msi_priv_data; - -struct platform_msi_desc { - struct platform_msi_priv_data *msi_priv_data; - u16 msi_index; -}; - -struct fsl_mc_msi_desc { - u16 msi_index; -}; - -struct ti_sci_inta_msi_desc { - u16 dev_index; -}; - -struct msi_desc { - struct list_head list; - unsigned int irq; - unsigned int nvec_used; - struct device *dev; - struct msi_msg msg; - struct irq_affinity_desc *affinity; - void (*write_msi_msg)(struct msi_desc *, void *); - void *write_msi_msg_data; - union { - struct { - u32 masked; - struct { - u8 is_msix: 1; - u8 multiple: 3; - u8 multi_cap: 3; - u8 maskbit: 1; - u8 is_64: 1; - u8 is_virtual: 1; - u16 entry_nr; - unsigned int default_irq; - } msi_attrib; - union { - u8 mask_pos; - void *mask_base; - }; - }; - struct platform_msi_desc platform; - struct fsl_mc_msi_desc fsl_mc; - struct ti_sci_inta_msi_desc inta; - }; -}; - -struct irq_chip { - struct device *parent_device; - const char *name; - unsigned int (*irq_startup)(struct irq_data *); - void (*irq_shutdown)(struct irq_data *); - void (*irq_enable)(struct irq_data *); - void (*irq_disable)(struct irq_data *); - void (*irq_ack)(struct irq_data *); - void (*irq_mask)(struct irq_data *); - void (*irq_mask_ack)(struct irq_data *); - void (*irq_unmask)(struct irq_data *); - void (*irq_eoi)(struct irq_data *); - int (*irq_set_affinity)(struct irq_data *, const struct cpumask *, bool); - int (*irq_retrigger)(struct irq_data *); - int (*irq_set_type)(struct irq_data *, unsigned int); - int (*irq_set_wake)(struct irq_data *, unsigned int); - void (*irq_bus_lock)(struct irq_data *); - void (*irq_bus_sync_unlock)(struct irq_data *); - void (*irq_cpu_online)(struct irq_data *); - void (*irq_cpu_offline)(struct irq_data *); - void (*irq_suspend)(struct irq_data *); - void (*irq_resume)(struct irq_data *); - void (*irq_pm_shutdown)(struct irq_data *); - void (*irq_calc_mask)(struct irq_data *); - void (*irq_print_chip)(struct irq_data *, struct seq_file *); - int (*irq_request_resources)(struct irq_data *); - void (*irq_release_resources)(struct irq_data *); - void (*irq_compose_msi_msg)(struct irq_data *, struct msi_msg *); - void (*irq_write_msi_msg)(struct irq_data *, struct msi_msg *); - int (*irq_get_irqchip_state)(struct irq_data *, enum irqchip_irq_state, bool *); - int (*irq_set_irqchip_state)(struct irq_data *, enum irqchip_irq_state, bool); - int (*irq_set_vcpu_affinity)(struct irq_data *, void *); - void (*ipi_send_single)(struct irq_data *, unsigned int); - void (*ipi_send_mask)(struct irq_data *, const struct cpumask *); - int (*irq_nmi_setup)(struct irq_data *); - void (*irq_nmi_teardown)(struct irq_data *); - long unsigned int flags; -}; - -struct irq_chip_regs { - long unsigned int enable; - long unsigned int disable; - long unsigned int mask; - long unsigned int ack; - long unsigned int eoi; - long unsigned int type; - long unsigned int polarity; -}; - -struct irq_chip_type { - struct irq_chip chip; - struct irq_chip_regs regs; - irq_flow_handler_t handler; - u32 type; - u32 mask_cache_priv; - u32 *mask_cache; -}; - -struct irq_chip_generic { - raw_spinlock_t lock; - void *reg_base; - u32 (*reg_readl)(void *); - void (*reg_writel)(u32, void *); - void (*suspend)(struct irq_chip_generic *); - void (*resume)(struct irq_chip_generic *); - unsigned int irq_base; - unsigned int irq_cnt; - u32 mask_cache; - u32 type_cache; - u32 polarity_cache; - u32 wake_enabled; - u32 wake_active; - unsigned int num_ct; - void *private; - long unsigned int installed; - long unsigned int unused; - struct irq_domain *domain; - struct list_head list; - struct irq_chip_type chip_types[0]; -}; - -enum vcpu_sysreg { - __INVALID_SYSREG__ = 0, - MPIDR_EL1 = 1, - CSSELR_EL1 = 2, - SCTLR_EL1 = 3, - ACTLR_EL1 = 4, - CPACR_EL1 = 5, - ZCR_EL1 = 6, - TTBR0_EL1 = 7, - TTBR1_EL1 = 8, - TCR_EL1 = 9, - ESR_EL1 = 10, - AFSR0_EL1 = 11, - AFSR1_EL1 = 12, - FAR_EL1 = 13, - MAIR_EL1 = 14, - VBAR_EL1 = 15, - CONTEXTIDR_EL1 = 16, - TPIDR_EL0 = 17, - TPIDRRO_EL0 = 18, - TPIDR_EL1 = 19, - AMAIR_EL1 = 20, - CNTKCTL_EL1 = 21, - PAR_EL1 = 22, - MDSCR_EL1 = 23, - MDCCINT_EL1 = 24, - DISR_EL1 = 25, - PMCR_EL0 = 26, - PMSELR_EL0 = 27, - PMEVCNTR0_EL0 = 28, - PMEVCNTR30_EL0 = 58, - PMCCNTR_EL0 = 59, - PMEVTYPER0_EL0 = 60, - PMEVTYPER30_EL0 = 90, - PMCCFILTR_EL0 = 91, - PMCNTENSET_EL0 = 92, - PMINTENSET_EL1 = 93, - PMOVSSET_EL0 = 94, - PMSWINC_EL0 = 95, - PMUSERENR_EL0 = 96, - APIAKEYLO_EL1 = 97, - APIAKEYHI_EL1 = 98, - APIBKEYLO_EL1 = 99, - APIBKEYHI_EL1 = 100, - APDAKEYLO_EL1 = 101, - APDAKEYHI_EL1 = 102, - APDBKEYLO_EL1 = 103, - APDBKEYHI_EL1 = 104, - APGAKEYLO_EL1 = 105, - APGAKEYHI_EL1 = 106, - ELR_EL1 = 107, - SP_EL1 = 108, - SPSR_EL1 = 109, - CNTVOFF_EL2 = 110, - CNTV_CVAL_EL0 = 111, - CNTV_CTL_EL0 = 112, - CNTP_CVAL_EL0 = 113, - CNTP_CTL_EL0 = 114, - DACR32_EL2 = 115, - IFSR32_EL2 = 116, - FPEXC32_EL2 = 117, - DBGVCR32_EL2 = 118, - NR_SYS_REGS = 119, -}; - -enum kvm_bus { - KVM_MMIO_BUS = 0, - KVM_PIO_BUS = 1, - KVM_VIRTIO_CCW_NOTIFY_BUS = 2, - KVM_FAST_MMIO_BUS = 3, - KVM_NR_BUSES = 4, -}; - -struct trace_event_raw_ipi_raise { - struct trace_entry ent; - u32 __data_loc_target_cpus; - const char *reason; - char __data[0]; -}; - -struct trace_event_raw_ipi_handler { - struct trace_entry ent; - const char *reason; - char __data[0]; -}; - -struct trace_event_data_offsets_ipi_raise { - u32 target_cpus; -}; - -struct trace_event_data_offsets_ipi_handler {}; - -typedef void (*btf_trace_ipi_raise)(void *, const struct cpumask *, const char *); - -typedef void (*btf_trace_ipi_entry)(void *, const char *); - -typedef void (*btf_trace_ipi_exit)(void *, const char *); - -enum ipi_msg_type { - IPI_RESCHEDULE = 0, - IPI_CALL_FUNC = 1, - IPI_CPU_STOP = 2, - IPI_CPU_CRASH_STOP = 3, - IPI_TIMER = 4, - IPI_IRQ_WORK = 5, - IPI_WAKEUP = 6, - NR_IPI = 7, -}; - -struct cpu_topology { - int thread_id; - int core_id; - int package_id; - int llc_id; - cpumask_t thread_sibling; - cpumask_t core_sibling; - cpumask_t llc_sibling; -}; - -enum cpufreq_table_sorting { - CPUFREQ_TABLE_UNSORTED = 0, - CPUFREQ_TABLE_SORTED_ASCENDING = 1, - CPUFREQ_TABLE_SORTED_DESCENDING = 2, -}; - -struct cpufreq_cpuinfo { - unsigned int max_freq; - unsigned int min_freq; - unsigned int transition_latency; -}; - -struct clk; - -struct cpufreq_governor; - -struct cpufreq_frequency_table; - -struct cpufreq_stats; - -struct thermal_cooling_device; - -struct cpufreq_policy { - cpumask_var_t cpus; - cpumask_var_t related_cpus; - cpumask_var_t real_cpus; - unsigned int shared_type; - unsigned int cpu; - struct clk *clk; - struct cpufreq_cpuinfo cpuinfo; - unsigned int min; - unsigned int max; - unsigned int cur; - unsigned int restore_freq; - unsigned int suspend_freq; - unsigned int policy; - unsigned int last_policy; - struct cpufreq_governor *governor; - void *governor_data; - char last_governor[16]; - struct work_struct update; - struct freq_constraints constraints; - struct freq_qos_request *min_freq_req; - struct freq_qos_request *max_freq_req; - struct cpufreq_frequency_table *freq_table; - enum cpufreq_table_sorting freq_table_sorted; - struct list_head policy_list; - struct kobject kobj; - struct completion kobj_unregister; - struct rw_semaphore rwsem; - bool fast_switch_possible; - bool fast_switch_enabled; - bool strict_target; - unsigned int transition_delay_us; - bool dvfs_possible_from_any_cpu; - unsigned int cached_target_freq; - unsigned int cached_resolved_idx; - bool transition_ongoing; - spinlock_t transition_lock; - wait_queue_head_t transition_wait; - struct task_struct *transition_task; - struct cpufreq_stats *stats; - void *driver_data; - struct thermal_cooling_device *cdev; - struct notifier_block nb_min; - struct notifier_block nb_max; -}; - -struct cpufreq_governor { - char name[16]; - int (*init)(struct cpufreq_policy *); - void (*exit)(struct cpufreq_policy *); - int (*start)(struct cpufreq_policy *); - void (*stop)(struct cpufreq_policy *); - void (*limits)(struct cpufreq_policy *); - ssize_t (*show_setspeed)(struct cpufreq_policy *, char *); - int (*store_setspeed)(struct cpufreq_policy *, unsigned int); - struct list_head governor_list; - struct module *owner; - u8 flags; -}; - -struct cpufreq_frequency_table { - unsigned int flags; - unsigned int driver_data; - unsigned int frequency; -}; - -enum arm_smccc_conduit { - SMCCC_CONDUIT_NONE = 0, - SMCCC_CONDUIT_SMC = 1, - SMCCC_CONDUIT_HVC = 2, -}; - -struct arm_smccc_res { - long unsigned int a0; - long unsigned int a1; - long unsigned int a2; - long unsigned int a3; -}; - -enum mitigation_state { - SPECTRE_UNAFFECTED = 0, - SPECTRE_MITIGATED = 1, - SPECTRE_VULNERABLE = 2, -}; - -enum spectre_v4_policy { - SPECTRE_V4_POLICY_MITIGATION_DYNAMIC = 0, - SPECTRE_V4_POLICY_MITIGATION_ENABLED = 1, - SPECTRE_V4_POLICY_MITIGATION_DISABLED = 2, -}; - -struct spectre_v4_param { - const char *str; - enum spectre_v4_policy policy; -}; - -typedef u32 compat_size_t; - -struct compat_statfs64; - -typedef s32 compat_clock_t; - -typedef s32 compat_pid_t; - -typedef s32 compat_timer_t; - -typedef s32 compat_int_t; - -typedef u64 compat_u64; - -typedef u32 __compat_uid32_t; - -typedef u32 compat_sigset_word; - -struct compat_sigaltstack { - compat_uptr_t ss_sp; - int ss_flags; - compat_size_t ss_size; -}; - -typedef struct compat_sigaltstack compat_stack_t; - -typedef struct { - compat_sigset_word sig[2]; -} compat_sigset_t; - -union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -}; - -typedef union compat_sigval compat_sigval_t; - -struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - union { - int _pad[29]; - struct { - compat_pid_t _pid; - __compat_uid32_t _uid; - } _kill; - struct { - compat_timer_t _tid; - int _overrun; - compat_sigval_t _sigval; - } _timer; - struct { - compat_pid_t _pid; - __compat_uid32_t _uid; - compat_sigval_t _sigval; - } _rt; - struct { - compat_pid_t _pid; - __compat_uid32_t _uid; - int _status; - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - struct { - compat_uptr_t _addr; - union { - short int _addr_lsb; - struct { - char _dummy_bnd[4]; - compat_uptr_t _lower; - compat_uptr_t _upper; - } _addr_bnd; - struct { - char _dummy_pkey[4]; - u32 _pkey; - } _addr_pkey; - }; - } _sigfault; - struct { - compat_long_t _band; - int _fd; - } _sigpoll; - struct { - compat_uptr_t _call_addr; - int _syscall; - unsigned int _arch; - } _sigsys; - } _sifields; -}; - -struct compat_sigcontext { - compat_ulong_t trap_no; - compat_ulong_t error_code; - compat_ulong_t oldmask; - compat_ulong_t arm_r0; - compat_ulong_t arm_r1; - compat_ulong_t arm_r2; - compat_ulong_t arm_r3; - compat_ulong_t arm_r4; - compat_ulong_t arm_r5; - compat_ulong_t arm_r6; - compat_ulong_t arm_r7; - compat_ulong_t arm_r8; - compat_ulong_t arm_r9; - compat_ulong_t arm_r10; - compat_ulong_t arm_fp; - compat_ulong_t arm_ip; - compat_ulong_t arm_sp; - compat_ulong_t arm_lr; - compat_ulong_t arm_pc; - compat_ulong_t arm_cpsr; - compat_ulong_t fault_address; -}; - -struct compat_ucontext { - compat_ulong_t uc_flags; - compat_uptr_t uc_link; - compat_stack_t uc_stack; - struct compat_sigcontext uc_mcontext; - compat_sigset_t uc_sigmask; - int __unused[30]; - compat_ulong_t uc_regspace[128]; -}; - -struct compat_sigframe { - struct compat_ucontext uc; - compat_ulong_t retcode[2]; -}; - -struct compat_rt_sigframe { - struct compat_siginfo info; - struct compat_sigframe sig; -}; - -struct compat_user_vfp { - compat_u64 fpregs[32]; - compat_ulong_t fpscr; -}; - -struct compat_user_vfp_exc { - compat_ulong_t fpexc; - compat_ulong_t fpinst; - compat_ulong_t fpinst2; -}; - -struct compat_vfp_sigframe { - compat_ulong_t magic; - compat_ulong_t size; - struct compat_user_vfp ufp; - struct compat_user_vfp_exc ufp_exc; -}; - -struct compat_aux_sigframe { - struct compat_vfp_sigframe vfp; - long unsigned int end_magic; -}; - -union __fpsimd_vreg { - __int128 unsigned raw; - struct { - u64 lo; - u64 hi; - }; -}; - -struct dyn_arch_ftrace {}; - -struct dyn_ftrace { - long unsigned int ip; - long unsigned int flags; - struct dyn_arch_ftrace arch; -}; - -enum { - FTRACE_UPDATE_CALLS = 1, - FTRACE_DISABLE_CALLS = 2, - FTRACE_UPDATE_TRACE_FUNC = 4, - FTRACE_START_FUNC_RET = 8, - FTRACE_STOP_FUNC_RET = 16, - FTRACE_MAY_SLEEP = 32, -}; - -typedef __u64 Elf64_Off; - -typedef __s64 Elf64_Sxword; - -struct elf64_rela { - Elf64_Addr r_offset; - Elf64_Xword r_info; - Elf64_Sxword r_addend; -}; - -typedef struct elf64_rela Elf64_Rela; - -struct elf64_hdr { - unsigned char e_ident[16]; - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; - Elf64_Off e_phoff; - Elf64_Off e_shoff; - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -}; - -typedef struct elf64_hdr Elf64_Ehdr; - -struct elf64_shdr { - Elf64_Word sh_name; - Elf64_Word sh_type; - Elf64_Xword sh_flags; - Elf64_Addr sh_addr; - Elf64_Off sh_offset; - Elf64_Xword sh_size; - Elf64_Word sh_link; - Elf64_Word sh_info; - Elf64_Xword sh_addralign; - Elf64_Xword sh_entsize; -}; - -typedef struct elf64_shdr Elf64_Shdr; - -enum aarch64_reloc_op { - RELOC_OP_NONE = 0, - RELOC_OP_ABS = 1, - RELOC_OP_PREL = 2, - RELOC_OP_PAGE = 3, -}; - -enum aarch64_insn_movw_imm_type { - AARCH64_INSN_IMM_MOVNZ = 0, - AARCH64_INSN_IMM_MOVKZ = 1, -}; - -enum perf_sample_regs_abi { - PERF_SAMPLE_REGS_ABI_NONE = 0, - PERF_SAMPLE_REGS_ABI_32 = 1, - PERF_SAMPLE_REGS_ABI_64 = 2, -}; - -enum perf_event_arm_regs { - PERF_REG_ARM64_X0 = 0, - PERF_REG_ARM64_X1 = 1, - PERF_REG_ARM64_X2 = 2, - PERF_REG_ARM64_X3 = 3, - PERF_REG_ARM64_X4 = 4, - PERF_REG_ARM64_X5 = 5, - PERF_REG_ARM64_X6 = 6, - PERF_REG_ARM64_X7 = 7, - PERF_REG_ARM64_X8 = 8, - PERF_REG_ARM64_X9 = 9, - PERF_REG_ARM64_X10 = 10, - PERF_REG_ARM64_X11 = 11, - PERF_REG_ARM64_X12 = 12, - PERF_REG_ARM64_X13 = 13, - PERF_REG_ARM64_X14 = 14, - PERF_REG_ARM64_X15 = 15, - PERF_REG_ARM64_X16 = 16, - PERF_REG_ARM64_X17 = 17, - PERF_REG_ARM64_X18 = 18, - PERF_REG_ARM64_X19 = 19, - PERF_REG_ARM64_X20 = 20, - PERF_REG_ARM64_X21 = 21, - PERF_REG_ARM64_X22 = 22, - PERF_REG_ARM64_X23 = 23, - PERF_REG_ARM64_X24 = 24, - PERF_REG_ARM64_X25 = 25, - PERF_REG_ARM64_X26 = 26, - PERF_REG_ARM64_X27 = 27, - PERF_REG_ARM64_X28 = 28, - PERF_REG_ARM64_X29 = 29, - PERF_REG_ARM64_LR = 30, - PERF_REG_ARM64_SP = 31, - PERF_REG_ARM64_PC = 32, - PERF_REG_ARM64_MAX = 33, -}; - -struct perf_guest_info_callbacks { - int (*is_in_guest)(); - int (*is_user_mode)(); - long unsigned int (*get_guest_ip)(); - void (*handle_intel_pt_intr)(); -}; - -struct perf_callchain_entry_ctx { - struct perf_callchain_entry *entry; - u32 max_stack; - u32 nr; - short int contexts; - bool contexts_maxed; -}; - -struct frame_tail { - struct frame_tail *fp; - long unsigned int lr; -}; - -struct compat_frame_tail { - compat_uptr_t fp; - u32 sp; - u32 lr; -}; - -struct platform_device_id { - char name[20]; - kernel_ulong_t driver_data; -}; - -struct pdev_archdata {}; - -enum perf_hw_id { - PERF_COUNT_HW_CPU_CYCLES = 0, - PERF_COUNT_HW_INSTRUCTIONS = 1, - PERF_COUNT_HW_CACHE_REFERENCES = 2, - PERF_COUNT_HW_CACHE_MISSES = 3, - PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, - PERF_COUNT_HW_BRANCH_MISSES = 5, - PERF_COUNT_HW_BUS_CYCLES = 6, - PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7, - PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8, - PERF_COUNT_HW_REF_CPU_CYCLES = 9, - PERF_COUNT_HW_MAX = 10, -}; - -enum perf_hw_cache_id { - PERF_COUNT_HW_CACHE_L1D = 0, - PERF_COUNT_HW_CACHE_L1I = 1, - PERF_COUNT_HW_CACHE_LL = 2, - PERF_COUNT_HW_CACHE_DTLB = 3, - PERF_COUNT_HW_CACHE_ITLB = 4, - PERF_COUNT_HW_CACHE_BPU = 5, - PERF_COUNT_HW_CACHE_NODE = 6, - PERF_COUNT_HW_CACHE_MAX = 7, -}; - -enum perf_hw_cache_op_id { - PERF_COUNT_HW_CACHE_OP_READ = 0, - PERF_COUNT_HW_CACHE_OP_WRITE = 1, - PERF_COUNT_HW_CACHE_OP_PREFETCH = 2, - PERF_COUNT_HW_CACHE_OP_MAX = 3, -}; - -enum perf_hw_cache_op_result_id { - PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0, - PERF_COUNT_HW_CACHE_RESULT_MISS = 1, - PERF_COUNT_HW_CACHE_RESULT_MAX = 2, -}; - -struct perf_event_mmap_page { - __u32 version; - __u32 compat_version; - __u32 lock; - __u32 index; - __s64 offset; - __u64 time_enabled; - __u64 time_running; - union { - __u64 capabilities; - struct { - __u64 cap_bit0: 1; - __u64 cap_bit0_is_deprecated: 1; - __u64 cap_user_rdpmc: 1; - __u64 cap_user_time: 1; - __u64 cap_user_time_zero: 1; - __u64 cap_user_time_short: 1; - __u64 cap_____res: 58; - }; - }; - __u16 pmc_width; - __u16 time_shift; - __u32 time_mult; - __u64 time_offset; - __u64 time_zero; - __u32 size; - __u32 __reserved_1; - __u64 time_cycles; - __u64 time_mask; - __u8 __reserved[928]; - __u64 data_head; - __u64 data_tail; - __u64 data_offset; - __u64 data_size; - __u64 aux_head; - __u64 aux_tail; - __u64 aux_offset; - __u64 aux_size; -}; - -struct perf_pmu_events_attr { - struct device_attribute attr; - u64 id; - const char *event_str; -}; - -struct mfd_cell; - -struct platform_device { - const char *name; - int id; - bool id_auto; - struct device dev; - u64 platform_dma_mask; - struct device_dma_parameters dma_parms; - u32 num_resources; - struct resource *resource; - const struct platform_device_id *id_entry; - char *driver_override; - struct mfd_cell *mfd_cell; - struct pdev_archdata archdata; -}; - -struct platform_driver { - int (*probe)(struct platform_device *); - int (*remove)(struct platform_device *); - void (*shutdown)(struct platform_device *); - int (*suspend)(struct platform_device *, pm_message_t); - int (*resume)(struct platform_device *); - struct device_driver driver; - const struct platform_device_id *id_table; - bool prevent_deferred_probe; -}; - -struct arm_pmu; - -struct pmu_hw_events { - struct perf_event *events[32]; - long unsigned int used_mask[1]; - raw_spinlock_t pmu_lock; - struct arm_pmu *percpu_pmu; - int irq; -}; - -struct arm_pmu { - struct pmu pmu; - cpumask_t supported_cpus; - char *name; - int pmuver; - irqreturn_t (*handle_irq)(struct arm_pmu *); - void (*enable)(struct perf_event *); - void (*disable)(struct perf_event *); - int (*get_event_idx)(struct pmu_hw_events *, struct perf_event *); - void (*clear_event_idx)(struct pmu_hw_events *, struct perf_event *); - int (*set_event_filter)(struct hw_perf_event *, struct perf_event_attr *); - u64 (*read_counter)(struct perf_event *); - void (*write_counter)(struct perf_event *, u64); - void (*start)(struct arm_pmu *); - void (*stop)(struct arm_pmu *); - void (*reset)(void *); - int (*map_event)(struct perf_event *); - int (*filter_match)(struct perf_event *); - int num_events; - bool secure_access; - long unsigned int pmceid_bitmap[1]; - long unsigned int pmceid_ext_bitmap[1]; - struct platform_device *plat_device; - struct pmu_hw_events *hw_events; - struct hlist_node node; - struct notifier_block cpu_pm_nb; - const struct attribute_group *attr_groups[5]; - u64 reg_pmmir; - long unsigned int acpi_cpuid; -}; - -enum armpmu_attr_groups { - ARMPMU_ATTR_GROUP_COMMON = 0, - ARMPMU_ATTR_GROUP_EVENTS = 1, - ARMPMU_ATTR_GROUP_FORMATS = 2, - ARMPMU_ATTR_GROUP_CAPS = 3, - ARMPMU_NR_ATTR_GROUPS = 4, -}; - -struct clock_read_data { - u64 epoch_ns; - u64 epoch_cyc; - u64 sched_clock_mask; - u64 (*read_sched_clock)(); - u32 mult; - u32 shift; -}; - -struct armv8pmu_probe_info { - struct arm_pmu *pmu; - bool present; -}; - -enum hw_breakpoint_ops { - HW_BREAKPOINT_INSTALL = 0, - HW_BREAKPOINT_UNINSTALL = 1, - HW_BREAKPOINT_RESTORE = 2, -}; - -struct cpu_suspend_ctx { - u64 ctx_regs[13]; - u64 sp; -}; - -struct sleep_stack_data { - struct cpu_suspend_ctx system_regs; - long unsigned int callee_saved_regs[12]; -}; - -enum jump_label_type { - JUMP_LABEL_NOP = 0, - JUMP_LABEL_JMP = 1, -}; - -struct die_args { - struct pt_regs *regs; - const char *str; - long int err; - int trapnr; - int signr; -}; - -enum kgdb_bptype { - BP_BREAKPOINT = 0, - BP_HARDWARE_BREAKPOINT = 1, - BP_WRITE_WATCHPOINT = 2, - BP_READ_WATCHPOINT = 3, - BP_ACCESS_WATCHPOINT = 4, - BP_POKE_BREAKPOINT = 5, -}; - -enum kgdb_bpstate { - BP_UNDEFINED = 0, - BP_REMOVED = 1, - BP_SET = 2, - BP_ACTIVE = 3, -}; - -struct kgdb_bkpt { - long unsigned int bpt_addr; - unsigned char saved_instr[4]; - enum kgdb_bptype type; - enum kgdb_bpstate state; -}; - -struct dbg_reg_def_t { - char *name; - int size; - int offset; -}; - -struct kgdb_arch { - unsigned char gdb_bpt_instr[4]; - long unsigned int flags; - int (*set_breakpoint)(long unsigned int, char *); - int (*remove_breakpoint)(long unsigned int, char *); - int (*set_hw_breakpoint)(long unsigned int, int, enum kgdb_bptype); - int (*remove_hw_breakpoint)(long unsigned int, int, enum kgdb_bptype); - void (*disable_hw_break)(struct pt_regs *); - void (*remove_all_hw_break)(); - void (*correct_hw_break)(); - void (*enable_nmi)(bool); -}; - -struct screen_info { - __u8 orig_x; - __u8 orig_y; - __u16 ext_mem_k; - __u16 orig_video_page; - __u8 orig_video_mode; - __u8 orig_video_cols; - __u8 flags; - __u8 unused2; - __u16 orig_video_ega_bx; - __u16 unused3; - __u8 orig_video_lines; - __u8 orig_video_isVGA; - __u16 orig_video_points; - __u16 lfb_width; - __u16 lfb_height; - __u16 lfb_depth; - __u32 lfb_base; - __u32 lfb_size; - __u16 cl_magic; - __u16 cl_offset; - __u16 lfb_linelength; - __u8 red_size; - __u8 red_pos; - __u8 green_size; - __u8 green_pos; - __u8 blue_size; - __u8 blue_pos; - __u8 rsvd_size; - __u8 rsvd_pos; - __u16 vesapm_seg; - __u16 vesapm_off; - __u16 pages; - __u16 vesa_attributes; - __u32 capabilities; - __u32 ext_lfb_base; - __u8 _reserved[2]; -} __attribute__((packed)); - -struct pci_device_id { - __u32 vendor; - __u32 device; - __u32 subvendor; - __u32 subdevice; - __u32 class; - __u32 class_mask; - kernel_ulong_t driver_data; -}; - -struct pci_bus; - -struct hotplug_slot; - -struct pci_slot { - struct pci_bus *bus; - struct list_head list; - struct hotplug_slot *hotplug; - unsigned char number; - struct kobject kobj; -}; - -typedef short unsigned int pci_bus_flags_t; - -struct pci_dev; - -struct pci_ops; - -struct msi_controller; - -struct pci_bus { - struct list_head node; - struct pci_bus *parent; - struct list_head children; - struct list_head devices; - struct pci_dev *self; - struct list_head slots; - struct resource *resource[4]; - struct list_head resources; - struct resource busn_res; - struct pci_ops *ops; - struct msi_controller *msi; - void *sysdata; - struct proc_dir_entry *procdir; - unsigned char number; - unsigned char primary; - unsigned char max_bus_speed; - unsigned char cur_bus_speed; - int domain_nr; - char name[48]; - short unsigned int bridge_ctl; - pci_bus_flags_t bus_flags; - struct device *bridge; - struct device dev; - struct bin_attribute *legacy_io; - struct bin_attribute *legacy_mem; - unsigned int is_added: 1; -}; - -typedef int pci_power_t; - -typedef unsigned int pci_channel_state_t; - -typedef short unsigned int pci_dev_flags_t; - -struct pci_driver; - -struct pcie_link_state; - -struct pci_vpd; - -struct pci_dev { - struct list_head bus_list; - struct pci_bus *bus; - struct pci_bus *subordinate; - void *sysdata; - struct proc_dir_entry *procent; - struct pci_slot *slot; - unsigned int devfn; - short unsigned int vendor; - short unsigned int device; - short unsigned int subsystem_vendor; - short unsigned int subsystem_device; - unsigned int class; - u8 revision; - u8 hdr_type; - u8 pcie_cap; - u8 msi_cap; - u8 msix_cap; - u8 pcie_mpss: 3; - u8 rom_base_reg; - u8 pin; - u16 pcie_flags_reg; - long unsigned int *dma_alias_mask; - struct pci_driver *driver; - u64 dma_mask; - struct device_dma_parameters dma_parms; - pci_power_t current_state; - unsigned int imm_ready: 1; - u8 pm_cap; - unsigned int pme_support: 5; - unsigned int pme_poll: 1; - unsigned int d1_support: 1; - unsigned int d2_support: 1; - unsigned int no_d1d2: 1; - unsigned int no_d3cold: 1; - unsigned int bridge_d3: 1; - unsigned int d3cold_allowed: 1; - unsigned int mmio_always_on: 1; - unsigned int wakeup_prepared: 1; - unsigned int runtime_d3cold: 1; - unsigned int skip_bus_pm: 1; - unsigned int ignore_hotplug: 1; - unsigned int hotplug_user_indicators: 1; - unsigned int clear_retrain_link: 1; - unsigned int d3hot_delay; - unsigned int d3cold_delay; - struct pcie_link_state *link_state; - unsigned int ltr_path: 1; - int l1ss; - unsigned int eetlp_prefix_path: 1; - pci_channel_state_t error_state; - struct device dev; - int cfg_size; - unsigned int irq; - struct resource resource[11]; - bool match_driver; - unsigned int transparent: 1; - unsigned int io_window: 1; - unsigned int pref_window: 1; - unsigned int pref_64_window: 1; - unsigned int multifunction: 1; - unsigned int is_busmaster: 1; - unsigned int no_msi: 1; - unsigned int no_64bit_msi: 1; - unsigned int block_cfg_access: 1; - unsigned int broken_parity_status: 1; - unsigned int irq_reroute_variant: 2; - unsigned int msi_enabled: 1; - unsigned int msix_enabled: 1; - unsigned int ari_enabled: 1; - unsigned int ats_enabled: 1; - unsigned int pasid_enabled: 1; - unsigned int pri_enabled: 1; - unsigned int is_managed: 1; - unsigned int needs_freset: 1; - unsigned int state_saved: 1; - unsigned int is_physfn: 1; - unsigned int is_virtfn: 1; - unsigned int reset_fn: 1; - unsigned int is_hotplug_bridge: 1; - unsigned int shpc_managed: 1; - unsigned int is_thunderbolt: 1; - unsigned int untrusted: 1; - unsigned int external_facing: 1; - unsigned int broken_intx_masking: 1; - unsigned int io_window_1k: 1; - unsigned int irq_managed: 1; - unsigned int non_compliant_bars: 1; - unsigned int is_probed: 1; - unsigned int link_active_reporting: 1; - unsigned int no_vf_scan: 1; - unsigned int no_command_memory: 1; - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; - u32 saved_config_space[16]; - struct hlist_head saved_cap_space; - struct bin_attribute *rom_attr; - int rom_attr_enabled; - struct bin_attribute *res_attr[11]; - struct bin_attribute *res_attr_wc[11]; - const struct attribute_group **msi_irq_groups; - struct pci_vpd *vpd; - u16 acs_cap; - phys_addr_t rom; - size_t romlen; - char *driver_override; - long unsigned int priv_flags; -}; - -struct pci_dynids { - spinlock_t lock; - struct list_head list; -}; - -struct pci_error_handlers; - -struct pci_driver { - struct list_head node; - const char *name; - const struct pci_device_id *id_table; - int (*probe)(struct pci_dev *, const struct pci_device_id *); - void (*remove)(struct pci_dev *); - int (*suspend)(struct pci_dev *, pm_message_t); - int (*resume)(struct pci_dev *); - void (*shutdown)(struct pci_dev *); - int (*sriov_configure)(struct pci_dev *, int); - const struct pci_error_handlers *err_handler; - const struct attribute_group **groups; - struct device_driver driver; - struct pci_dynids dynids; -}; - -struct pci_ops { - int (*add_bus)(struct pci_bus *); - void (*remove_bus)(struct pci_bus *); - void * (*map_bus)(struct pci_bus *, unsigned int, int); - int (*read)(struct pci_bus *, unsigned int, int, int, u32 *); - int (*write)(struct pci_bus *, unsigned int, int, int, u32); -}; - -typedef unsigned int pci_ers_result_t; - -struct pci_error_handlers { - pci_ers_result_t (*error_detected)(struct pci_dev *, pci_channel_state_t); - pci_ers_result_t (*mmio_enabled)(struct pci_dev *); - pci_ers_result_t (*slot_reset)(struct pci_dev *); - void (*reset_prepare)(struct pci_dev *); - void (*reset_done)(struct pci_dev *); - void (*resume)(struct pci_dev *); -}; - -struct trace_event_raw_instruction_emulation { - struct trace_entry ent; - u32 __data_loc_instr; - u64 addr; - char __data[0]; -}; - -struct trace_event_data_offsets_instruction_emulation { - u32 instr; -}; - -typedef void (*btf_trace_instruction_emulation)(void *, const char *, u64); - -enum insn_emulation_mode { - INSN_UNDEF = 0, - INSN_EMULATE = 1, - INSN_HW = 2, -}; - -enum legacy_insn_status { - INSN_DEPRECATED = 0, - INSN_OBSOLETE = 1, -}; - -struct insn_emulation_ops { - const char *name; - enum legacy_insn_status status; - struct undef_hook *hooks; - int (*set_hw_mode)(bool); -}; - -struct insn_emulation { - struct list_head node; - struct insn_emulation_ops *ops; - int current_mode; - int min; - int max; -}; - -typedef struct { - long unsigned int val; -} swp_entry_t; - -typedef u32 probe_opcode_t; - -typedef void probes_handler_t(u32, long int, struct pt_regs *); - -struct arch_probe_insn { - probe_opcode_t *insn; - pstate_check_t *pstate_cc; - probes_handler_t *handler; - long unsigned int restore; -}; - -typedef u32 kprobe_opcode_t; - -struct arch_specific_insn { - struct arch_probe_insn api; -}; - -struct kprobe; - -struct prev_kprobe { - struct kprobe *kp; - unsigned int status; -}; - -typedef int (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *); - -typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *, long unsigned int); - -typedef int (*kprobe_fault_handler_t)(struct kprobe *, struct pt_regs *, int); - -struct kprobe { - struct hlist_node hlist; - struct list_head list; - long unsigned int nmissed; - kprobe_opcode_t *addr; - const char *symbol_name; - unsigned int offset; - kprobe_pre_handler_t pre_handler; - kprobe_post_handler_t post_handler; - kprobe_fault_handler_t fault_handler; - kprobe_opcode_t opcode; - struct arch_specific_insn ainsn; - u32 flags; -}; - -struct kprobe_step_ctx { - long unsigned int ss_pending; - long unsigned int match_addr; -}; - -struct kprobe_ctlblk { - unsigned int kprobe_status; - long unsigned int saved_irqflag; - struct prev_kprobe prev_kprobe; - struct kprobe_step_ctx ss_ctx; -}; - -struct kretprobe_instance; - -typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *); - -struct kretprobe; - -struct kretprobe_instance { - union { - struct hlist_node hlist; - struct callback_head rcu; - }; - struct kretprobe *rp; - kprobe_opcode_t *ret_addr; - struct task_struct *task; - void *fp; - char data[0]; -}; - -struct kretprobe { - struct kprobe kp; - kretprobe_handler_t handler; - kretprobe_handler_t entry_handler; - int maxactive; - int nmissed; - size_t data_size; - struct hlist_head free_instances; - raw_spinlock_t lock; -}; - -struct kprobe_insn_cache { - struct mutex mutex; - void * (*alloc)(); - void (*free)(void *); - const char *sym; - struct list_head pages; - size_t insn_size; - int nr_garbage; -}; - -enum probe_insn { - INSN_REJECTED = 0, - INSN_GOOD_NO_SLOT = 1, - INSN_GOOD = 2, -}; - -enum aarch64_insn_special_register { - AARCH64_INSN_SPCLREG_SPSR_EL1 = 49664, - AARCH64_INSN_SPCLREG_ELR_EL1 = 49665, - AARCH64_INSN_SPCLREG_SP_EL0 = 49672, - AARCH64_INSN_SPCLREG_SPSEL = 49680, - AARCH64_INSN_SPCLREG_CURRENTEL = 49682, - AARCH64_INSN_SPCLREG_DAIF = 55825, - AARCH64_INSN_SPCLREG_NZCV = 55824, - AARCH64_INSN_SPCLREG_FPCR = 55840, - AARCH64_INSN_SPCLREG_DSPSR_EL0 = 55848, - AARCH64_INSN_SPCLREG_DLR_EL0 = 55849, - AARCH64_INSN_SPCLREG_SPSR_EL2 = 57856, - AARCH64_INSN_SPCLREG_ELR_EL2 = 57857, - AARCH64_INSN_SPCLREG_SP_EL1 = 57864, - AARCH64_INSN_SPCLREG_SPSR_INQ = 57880, - AARCH64_INSN_SPCLREG_SPSR_ABT = 57881, - AARCH64_INSN_SPCLREG_SPSR_UND = 57882, - AARCH64_INSN_SPCLREG_SPSR_FIQ = 57883, - AARCH64_INSN_SPCLREG_SPSR_EL3 = 61952, - AARCH64_INSN_SPCLREG_ELR_EL3 = 61953, - AARCH64_INSN_SPCLREG_SP_EL2 = 61968, -}; - -enum dma_data_direction { - DMA_BIDIRECTIONAL = 0, - DMA_TO_DEVICE = 1, - DMA_FROM_DEVICE = 2, - DMA_NONE = 3, -}; - -typedef u64 pudval_t; - -struct fault_info { - int (*fn)(long unsigned int, unsigned int, struct pt_regs *); - int sig; - int code; - const char *name; -}; - -struct mem_section_usage { - long unsigned int subsection_map[8]; - long unsigned int pageblock_flags[0]; -}; - -struct mem_section { - long unsigned int section_mem_map; - struct mem_section_usage *usage; -}; - -enum swiotlb_force { - SWIOTLB_NORMAL = 0, - SWIOTLB_FORCE = 1, - SWIOTLB_NO_FORCE = 2, -}; - -typedef u8 uint8_t; - -typedef u64 p4dval_t; - -typedef __be32 fdt32_t; - -struct fdt_header { - fdt32_t magic; - fdt32_t totalsize; - fdt32_t off_dt_struct; - fdt32_t off_dt_strings; - fdt32_t off_mem_rsvmap; - fdt32_t version; - fdt32_t last_comp_version; - fdt32_t boot_cpuid_phys; - fdt32_t size_dt_strings; - fdt32_t size_dt_struct; -}; - -struct page_change_data { - pgprot_t set_mask; - pgprot_t clear_mask; -}; - -struct xa_node { - unsigned char shift; - unsigned char offset; - unsigned char count; - unsigned char nr_values; - struct xa_node *parent; - struct xarray *array; - union { - struct list_head private_list; - struct callback_head callback_head; - }; - void *slots[64]; - union { - long unsigned int tags[3]; - long unsigned int marks[3]; - }; -}; - -typedef void (*xa_update_node_t)(struct xa_node *); - -struct xa_state { - struct xarray *xa; - long unsigned int xa_index; - unsigned char xa_shift; - unsigned char xa_sibs; - unsigned char xa_offset; - unsigned char xa_pad; - struct xa_node *xa_node; - struct xa_node *xa_alloc; - xa_update_node_t xa_update; -}; - -typedef __kernel_long_t __kernel_off_t; - -typedef __kernel_off_t off_t; - -enum { - BPF_REG_0 = 0, - BPF_REG_1 = 1, - BPF_REG_2 = 2, - BPF_REG_3 = 3, - BPF_REG_4 = 4, - BPF_REG_5 = 5, - BPF_REG_6 = 6, - BPF_REG_7 = 7, - BPF_REG_8 = 8, - BPF_REG_9 = 9, - BPF_REG_10 = 10, - __MAX_BPF_REG = 11, -}; - -enum { - DUMP_PREFIX_NONE = 0, - DUMP_PREFIX_ADDRESS = 1, - DUMP_PREFIX_OFFSET = 2, -}; - -struct bpf_binary_header { - u32 pages; - int: 32; - u8 image[0]; -}; - -struct jit_ctx { - const struct bpf_prog *prog; - int idx; - int epilogue_offset; - int *offset; - int exentry_idx; - __le32 *image; - u32 stack_size; -}; - -struct arm64_jit_data { - struct bpf_binary_header *header; - u8 *image; - struct jit_ctx ctx; -}; - -typedef long unsigned int ulong; - -typedef u64 gpa_t; - -typedef u64 gfn_t; - -typedef u64 hpa_t; - -typedef u64 hfn_t; - -typedef hfn_t kvm_pfn_t; - -struct kvm_memory_slot; - -struct gfn_to_hva_cache { - u64 generation; - gpa_t gpa; - long unsigned int hva; - long unsigned int len; - struct kvm_memory_slot *memslot; -}; - -struct kvm_arch_memory_slot {}; - -struct kvm_memory_slot { - gfn_t base_gfn; - long unsigned int npages; - long unsigned int *dirty_bitmap; - struct kvm_arch_memory_slot arch; - long unsigned int userspace_addr; - u32 flags; - short int id; - u16 as_id; -}; - -struct gfn_to_pfn_cache { - u64 generation; - gfn_t gfn; - kvm_pfn_t pfn; - bool dirty; -}; - -struct kvm_mmu_memory_cache { - int nobjs; - gfp_t gfp_zero; - struct kmem_cache *kmem_cache; - void *objects[40]; -}; - -struct kvm_vcpu; - -struct kvm_io_device; - -struct kvm_io_device_ops { - int (*read)(struct kvm_vcpu *, struct kvm_io_device *, gpa_t, int, void *); - int (*write)(struct kvm_vcpu *, struct kvm_io_device *, gpa_t, int, const void *); - void (*destructor)(struct kvm_io_device *); -}; - -struct preempt_ops; - -struct preempt_notifier { - struct hlist_node link; - struct preempt_ops *ops; -}; - -struct kvm_vcpu_stat { - u64 halt_successful_poll; - u64 halt_attempted_poll; - u64 halt_poll_success_ns; - u64 halt_poll_fail_ns; - u64 halt_poll_invalid; - u64 halt_wakeup; - u64 hvc_exit_stat; - u64 wfe_exit_stat; - u64 wfi_exit_stat; - u64 mmio_exit_user; - u64 mmio_exit_kernel; - u64 exits; -}; - -struct kvm_mmio_fragment { - gpa_t gpa; - void *data; - unsigned int len; -}; - -struct kvm_cpu_context { - struct user_pt_regs regs; - u64 spsr_abt; - u64 spsr_und; - u64 spsr_irq; - u64 spsr_fiq; - struct user_fpsimd_state fp_regs; - union { - u64 sys_regs[119]; - u32 copro[238]; - }; - struct kvm_vcpu *__hyp_running_vcpu; -}; - -struct kvm_vcpu_fault_info { - u32 esr_el2; - u64 far_el2; - u64 hpfar_el2; - u64 disr_el1; -}; - -struct kvm_guest_debug_arch { - __u64 dbg_bcr[16]; - __u64 dbg_bvr[16]; - __u64 dbg_wcr[16]; - __u64 dbg_wvr[16]; -}; - -struct vgic_v2_cpu_if { - u32 vgic_hcr; - u32 vgic_vmcr; - u32 vgic_apr; - u32 vgic_lr[64]; - unsigned int used_lrs; -}; - -struct its_vm; - -struct its_vpe { - struct page *vpt_page; - struct its_vm *its_vm; - atomic_t vlpi_count; - int irq; - irq_hw_number_t vpe_db_lpi; - bool resident; - union { - struct { - int vpe_proxy_event; - bool idai; - }; - struct { - struct fwnode_handle *fwnode; - struct irq_domain *sgi_domain; - struct { - u8 priority; - bool enabled; - bool group; - } sgi_config[16]; - atomic_t vmapp_count; - }; - }; - raw_spinlock_t vpe_lock; - u16 col_idx; - u16 vpe_id; - bool pending_last; -}; - -struct vgic_v3_cpu_if { - u32 vgic_hcr; - u32 vgic_vmcr; - u32 vgic_sre; - u32 vgic_ap0r[4]; - u32 vgic_ap1r[4]; - u64 vgic_lr[16]; - struct its_vpe its_vpe; - unsigned int used_lrs; -}; - -enum vgic_irq_config { - VGIC_CONFIG_EDGE = 0, - VGIC_CONFIG_LEVEL = 1, -}; - -struct vgic_irq { - raw_spinlock_t irq_lock; - struct list_head lpi_list; - struct list_head ap_list; - struct kvm_vcpu *vcpu; - struct kvm_vcpu *target_vcpu; - u32 intid; - bool line_level; - bool pending_latch; - bool active; - bool enabled; - bool hw; - struct kref refcount; - u32 hwintid; - unsigned int host_irq; - union { - u8 targets; - u32 mpidr; - }; - u8 source; - u8 active_source; - u8 priority; - u8 group; - enum vgic_irq_config config; - bool (*get_input_level)(int); - void *owner; -}; - -enum iodev_type { - IODEV_CPUIF = 0, - IODEV_DIST = 1, - IODEV_REDIST = 2, - IODEV_ITS = 3, -}; - -struct kvm_io_device { - const struct kvm_io_device_ops *ops; -}; - -struct vgic_its; - -struct vgic_register_region; - -struct vgic_io_device { - gpa_t base_addr; - union { - struct kvm_vcpu *redist_vcpu; - struct vgic_its *its; - }; - const struct vgic_register_region *regions; - enum iodev_type iodev_type; - int nr_regions; - struct kvm_io_device dev; -}; - -struct vgic_redist_region; - -struct vgic_cpu { - union { - struct vgic_v2_cpu_if vgic_v2; - struct vgic_v3_cpu_if vgic_v3; - }; - struct vgic_irq private_irqs[32]; - raw_spinlock_t ap_list_lock; - struct list_head ap_list_head; - struct vgic_io_device rd_iodev; - struct vgic_redist_region *rdreg; - u64 pendbaser; - bool lpis_enabled; - u32 num_pri_bits; - u32 num_id_bits; -}; - -struct kvm_irq_level { - union { - __u32 irq; - __s32 status; - }; - __u32 level; -}; - -struct arch_timer_context { - struct kvm_vcpu *vcpu; - struct kvm_irq_level irq; - struct hrtimer hrtimer; - bool loaded; - u32 host_timer_irq; - u32 host_timer_irq_flags; -}; - -struct arch_timer_cpu { - struct arch_timer_context timers[2]; - struct hrtimer bg_timer; - bool enabled; -}; - -struct kvm_pmc { - u8 idx; - struct perf_event *perf_event; -}; - -struct kvm_pmu { - int irq_num; - struct kvm_pmc pmc[32]; - long unsigned int chained[1]; - bool ready; - bool created; - bool irq_level; - struct irq_work overflow_work; -}; - -struct vcpu_reset_state { - long unsigned int pc; - long unsigned int r0; - bool be; - bool reset; -}; - -struct kvm_s2_mmu; - -struct kvm_vcpu_arch { - struct kvm_cpu_context ctxt; - void *sve_state; - unsigned int sve_max_vl; - struct kvm_s2_mmu *hw_mmu; - u64 hcr_el2; - u32 mdcr_el2; - struct kvm_vcpu_fault_info fault; - u64 workaround_flags; - u64 flags; - struct kvm_guest_debug_arch *debug_ptr; - struct kvm_guest_debug_arch vcpu_debug_state; - struct kvm_guest_debug_arch external_debug_state; - struct thread_info *host_thread_info; - struct user_fpsimd_state *host_fpsimd_state; - struct { - struct kvm_guest_debug_arch regs; - u64 pmscr_el1; - } host_debug_state; - struct vgic_cpu vgic_cpu; - struct arch_timer_cpu timer_cpu; - struct kvm_pmu pmu; - struct { - u32 mdscr_el1; - } guest_debug_preserved; - bool power_off; - bool pause; - struct kvm_mmu_memory_cache mmu_page_cache; - int target; - long unsigned int features[1]; - bool has_run_once; - u64 vsesr_el2; - struct vcpu_reset_state reset_state; - bool sysregs_loaded_on_cpu; - struct { - u64 last_steal; - gpa_t base; - } steal; -}; - -struct kvm; - -struct kvm_run; - -struct kvm_vcpu { - struct kvm *kvm; - struct preempt_notifier preempt_notifier; - int cpu; - int vcpu_id; - int vcpu_idx; - int srcu_idx; - int mode; - u64 requests; - long unsigned int guest_debug; - int pre_pcpu; - struct list_head blocked_vcpu_list; - struct mutex mutex; - struct kvm_run *run; - struct rcuwait wait; - struct pid *pid; - int sigset_active; - sigset_t sigset; - struct kvm_vcpu_stat stat; - unsigned int halt_poll_ns; - bool valid_wakeup; - int mmio_needed; - int mmio_read_completed; - int mmio_is_write; - int mmio_cur_fragment; - int mmio_nr_fragments; - struct kvm_mmio_fragment mmio_fragments[2]; - struct { - bool in_spin_loop; - bool dy_eligible; - } spin_loop; - bool preempted; - bool ready; - struct kvm_vcpu_arch arch; -}; - -struct preempt_ops { - void (*sched_in)(struct preempt_notifier *, int); - void (*sched_out)(struct preempt_notifier *, struct task_struct *); -}; - -struct trace_print_flags { - long unsigned int mask; - const char *name; -}; - -enum mmu_notifier_event { - MMU_NOTIFY_UNMAP = 0, - MMU_NOTIFY_CLEAR = 1, - MMU_NOTIFY_PROTECTION_VMA = 2, - MMU_NOTIFY_PROTECTION_PAGE = 3, - MMU_NOTIFY_SOFT_DIRTY = 4, - MMU_NOTIFY_RELEASE = 5, - MMU_NOTIFY_MIGRATE = 6, -}; - -struct mmu_notifier; - -struct mmu_notifier_range; - -struct mmu_notifier_ops { - void (*release)(struct mmu_notifier *, struct mm_struct *); - int (*clear_flush_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int); - int (*clear_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int); - int (*test_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int); - void (*change_pte)(struct mmu_notifier *, struct mm_struct *, long unsigned int, pte_t); - int (*invalidate_range_start)(struct mmu_notifier *, const struct mmu_notifier_range *); - void (*invalidate_range_end)(struct mmu_notifier *, const struct mmu_notifier_range *); - void (*invalidate_range)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int); - struct mmu_notifier * (*alloc_notifier)(struct mm_struct *); - void (*free_notifier)(struct mmu_notifier *); -}; - -struct mmu_notifier { - struct hlist_node hlist; - const struct mmu_notifier_ops *ops; - struct mm_struct *mm; - struct callback_head rcu; - unsigned int users; -}; - -struct mmu_notifier_range { - struct vm_area_struct *vma; - struct mm_struct *mm; - long unsigned int start; - long unsigned int end; - unsigned int flags; - enum mmu_notifier_event event; - void *migrate_pgmap_owner; -}; - -enum kobject_action { - KOBJ_ADD = 0, - KOBJ_REMOVE = 1, - KOBJ_CHANGE = 2, - KOBJ_MOVE = 3, - KOBJ_ONLINE = 4, - KOBJ_OFFLINE = 5, - KOBJ_BIND = 6, - KOBJ_UNBIND = 7, -}; - -struct kvm_regs { - struct user_pt_regs regs; - __u64 sp_el1; - __u64 elr_el1; - __u64 spsr[5]; - long: 64; - struct user_fpsimd_state fp_regs; -}; - -struct kvm_sregs {}; - -struct kvm_fpu {}; - -struct kvm_debug_exit_arch { - __u32 hsr; - __u64 far; -}; - -struct kvm_sync_regs { - __u64 device_irq_level; -}; - -struct kvm_userspace_memory_region { - __u32 slot; - __u32 flags; - __u64 guest_phys_addr; - __u64 memory_size; - __u64 userspace_addr; -}; - -struct kvm_hyperv_exit { - __u32 type; - __u32 pad1; - union { - struct { - __u32 msr; - __u32 pad2; - __u64 control; - __u64 evt_page; - __u64 msg_page; - } synic; - struct { - __u64 input; - __u64 result; - __u64 params[2]; - } hcall; - struct { - __u32 msr; - __u32 pad2; - __u64 control; - __u64 status; - __u64 send_page; - __u64 recv_page; - __u64 pending_page; - } syndbg; - } u; -}; - -struct kvm_run { - __u8 request_interrupt_window; - __u8 immediate_exit; - __u8 padding1[6]; - __u32 exit_reason; - __u8 ready_for_interrupt_injection; - __u8 if_flag; - __u16 flags; - __u64 cr8; - __u64 apic_base; - union { - struct { - __u64 hardware_exit_reason; - } hw; - struct { - __u64 hardware_entry_failure_reason; - __u32 cpu; - } fail_entry; - struct { - __u32 exception; - __u32 error_code; - } ex; - struct { - __u8 direction; - __u8 size; - __u16 port; - __u32 count; - __u64 data_offset; - } io; - struct { - struct kvm_debug_exit_arch arch; - } debug; - struct { - __u64 phys_addr; - __u8 data[8]; - __u32 len; - __u8 is_write; - } mmio; - struct { - __u64 nr; - __u64 args[6]; - __u64 ret; - __u32 longmode; - __u32 pad; - } hypercall; - struct { - __u64 rip; - __u32 is_write; - __u32 pad; - } tpr_access; - struct { - __u8 icptcode; - __u16 ipa; - __u32 ipb; - } s390_sieic; - __u64 s390_reset_flags; - struct { - __u64 trans_exc_code; - __u32 pgm_code; - } s390_ucontrol; - struct { - __u32 dcrn; - __u32 data; - __u8 is_write; - } dcr; - struct { - __u32 suberror; - __u32 ndata; - __u64 data[16]; - } internal; - struct { - __u64 gprs[32]; - } osi; - struct { - __u64 nr; - __u64 ret; - __u64 args[9]; - } papr_hcall; - struct { - __u16 subchannel_id; - __u16 subchannel_nr; - __u32 io_int_parm; - __u32 io_int_word; - __u32 ipb; - __u8 dequeued; - } s390_tsch; - struct { - __u32 epr; - } epr; - struct { - __u32 type; - __u64 flags; - } system_event; - struct { - __u64 addr; - __u8 ar; - __u8 reserved; - __u8 fc; - __u8 sel1; - __u16 sel2; - } s390_stsi; - struct { - __u8 vector; - } eoi; - struct kvm_hyperv_exit hyperv; - struct { - __u64 esr_iss; - __u64 fault_ipa; - } arm_nisv; - struct { - __u8 error; - __u8 pad[7]; - __u32 reason; - __u32 index; - __u64 data; - } msr; - char padding[256]; - }; - __u64 kvm_valid_regs; - __u64 kvm_dirty_regs; - union { - struct kvm_sync_regs regs; - char padding[2048]; - } s; -}; - -struct kvm_coalesced_mmio_zone { - __u64 addr; - __u32 size; - union { - __u32 pad; - __u32 pio; - }; -}; - -struct kvm_coalesced_mmio { - __u64 phys_addr; - __u32 len; - union { - __u32 pad; - __u32 pio; - }; - __u8 data[8]; -}; - -struct kvm_coalesced_mmio_ring { - __u32 first; - __u32 last; - struct kvm_coalesced_mmio coalesced_mmio[0]; -}; - -struct kvm_translation { - __u64 linear_address; - __u64 physical_address; - __u8 valid; - __u8 writeable; - __u8 usermode; - __u8 pad[5]; -}; - -struct kvm_dirty_log { - __u32 slot; - __u32 padding1; - union { - void *dirty_bitmap; - __u64 padding2; - }; -}; - -struct kvm_clear_dirty_log { - __u32 slot; - __u32 num_pages; - __u64 first_page; - union { - void *dirty_bitmap; - __u64 padding2; - }; -}; - -struct kvm_signal_mask { - __u32 len; - __u8 sigset[0]; -}; - -struct kvm_mp_state { - __u32 mp_state; -}; - -struct kvm_guest_debug { - __u32 control; - __u32 pad; - struct kvm_guest_debug_arch arch; -}; - -struct kvm_ioeventfd { - __u64 datamatch; - __u64 addr; - __u32 len; - __s32 fd; - __u32 flags; - __u8 pad[36]; -}; - -struct kvm_enable_cap { - __u32 cap; - __u32 flags; - __u64 args[4]; - __u8 pad[64]; -}; - -struct kvm_irq_routing_irqchip { - __u32 irqchip; - __u32 pin; -}; - -struct kvm_irq_routing_msi { - __u32 address_lo; - __u32 address_hi; - __u32 data; - union { - __u32 pad; - __u32 devid; - }; -}; - -struct kvm_irq_routing_s390_adapter { - __u64 ind_addr; - __u64 summary_addr; - __u64 ind_offset; - __u32 summary_offset; - __u32 adapter_id; -}; - -struct kvm_irq_routing_hv_sint { - __u32 vcpu; - __u32 sint; -}; - -struct kvm_irq_routing_entry { - __u32 gsi; - __u32 type; - __u32 flags; - __u32 pad; - union { - struct kvm_irq_routing_irqchip irqchip; - struct kvm_irq_routing_msi msi; - struct kvm_irq_routing_s390_adapter adapter; - struct kvm_irq_routing_hv_sint hv_sint; - __u32 pad[8]; - } u; -}; - -struct kvm_irq_routing { - __u32 nr; - __u32 flags; - struct kvm_irq_routing_entry entries[0]; -}; - -struct kvm_irqfd { - __u32 fd; - __u32 gsi; - __u32 flags; - __u32 resamplefd; - __u8 pad[16]; -}; - -struct kvm_msi { - __u32 address_lo; - __u32 address_hi; - __u32 data; - __u32 flags; - __u32 devid; - __u8 pad[12]; -}; - -struct kvm_create_device { - __u32 type; - __u32 fd; - __u32 flags; -}; - -struct kvm_device_attr { - __u32 flags; - __u32 group; - __u64 attr; - __u64 addr; -}; - -enum kvm_device_type { - KVM_DEV_TYPE_FSL_MPIC_20 = 1, - KVM_DEV_TYPE_FSL_MPIC_42 = 2, - KVM_DEV_TYPE_XICS = 3, - KVM_DEV_TYPE_VFIO = 4, - KVM_DEV_TYPE_ARM_VGIC_V2 = 5, - KVM_DEV_TYPE_FLIC = 6, - KVM_DEV_TYPE_ARM_VGIC_V3 = 7, - KVM_DEV_TYPE_ARM_VGIC_ITS = 8, - KVM_DEV_TYPE_XIVE = 9, - KVM_DEV_TYPE_ARM_PV_TIME = 10, - KVM_DEV_TYPE_MAX = 11, -}; - -struct its_vm { - struct fwnode_handle *fwnode; - struct irq_domain *domain; - struct page *vprop_page; - struct its_vpe **vpes; - int nr_vpes; - irq_hw_number_t db_lpi_base; - long unsigned int *db_bitmap; - int nr_db_lpis; - u32 vlpi_count[16]; -}; - -struct kvm_device; - -struct vgic_its { - gpa_t vgic_its_base; - bool enabled; - struct vgic_io_device iodev; - struct kvm_device *dev; - u64 baser_device_table; - u64 baser_coll_table; - struct mutex cmd_lock; - u64 cbaser; - u32 creadr; - u32 cwriter; - u32 abi_rev; - struct mutex its_lock; - struct list_head device_list; - struct list_head collection_list; -}; - -struct vgic_register_region { - unsigned int reg_offset; - unsigned int len; - unsigned int bits_per_irq; - unsigned int access_flags; - union { - long unsigned int (*read)(struct kvm_vcpu *, gpa_t, unsigned int); - long unsigned int (*its_read)(struct kvm *, struct vgic_its *, gpa_t, unsigned int); - }; - union { - void (*write)(struct kvm_vcpu *, gpa_t, unsigned int, long unsigned int); - void (*its_write)(struct kvm *, struct vgic_its *, gpa_t, unsigned int, long unsigned int); - }; - long unsigned int (*uaccess_read)(struct kvm_vcpu *, gpa_t, unsigned int); - union { - int (*uaccess_write)(struct kvm_vcpu *, gpa_t, unsigned int, long unsigned int); - int (*uaccess_its_write)(struct kvm *, struct vgic_its *, gpa_t, unsigned int, long unsigned int); - }; -}; - -struct kvm_device_ops; - -struct kvm_device { - const struct kvm_device_ops *ops; - struct kvm *kvm; - void *private; - struct list_head vm_node; -}; - -struct vgic_redist_region { - u32 index; - gpa_t base; - u32 count; - u32 free_index; - struct list_head list; -}; - -struct vgic_state_iter; - -struct vgic_dist { - bool in_kernel; - bool ready; - bool initialized; - u32 vgic_model; - u32 implementation_rev; - bool v2_groups_user_writable; - bool msis_require_devid; - int nr_spis; - gpa_t vgic_dist_base; - union { - gpa_t vgic_cpu_base; - struct list_head rd_regions; - }; - bool enabled; - bool nassgireq; - struct vgic_irq *spis; - struct vgic_io_device dist_iodev; - bool has_its; - u64 propbaser; - raw_spinlock_t lpi_list_lock; - struct list_head lpi_list_head; - int lpi_list_count; - struct list_head lpi_translation_cache; - struct vgic_state_iter *iter; - struct its_vm its_vm; -}; - -struct kvm_vmid { - u64 vmid_gen; - u32 vmid; -}; - -struct kvm_pgtable; - -struct kvm_s2_mmu { - struct kvm_vmid vmid; - phys_addr_t pgd_phys; - struct kvm_pgtable *pgt; - int *last_vcpu_ran; - struct kvm *kvm; -}; - -struct kvm_vm_stat { - ulong remote_tlb_flush; -}; - -struct kvm_arch { - struct kvm_s2_mmu mmu; - u64 vtcr; - int max_vcpus; - struct vgic_dist vgic; - u32 psci_version; - bool return_nisv_io_abort_to_user; - long unsigned int *pmu_filter; - unsigned int pmuver; - u8 pfr0_csv2; -}; - -struct kvm_memslots; - -struct kvm_io_bus; - -struct kvm_irq_routing_table; - -struct kvm_stat_data; - -struct kvm { - spinlock_t mmu_lock; - struct mutex slots_lock; - struct mm_struct *mm; - struct kvm_memslots *memslots[1]; - struct kvm_vcpu *vcpus[512]; - atomic_t online_vcpus; - int created_vcpus; - int last_boosted_vcpu; - struct list_head vm_list; - struct mutex lock; - struct kvm_io_bus *buses[4]; - struct { - spinlock_t lock; - struct list_head items; - struct list_head resampler_list; - struct mutex resampler_lock; - } irqfds; - struct list_head ioeventfds; - struct kvm_vm_stat stat; - struct kvm_arch arch; - refcount_t users_count; - struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; - spinlock_t ring_lock; - struct list_head coalesced_zones; - struct mutex irq_lock; - struct kvm_irq_routing_table *irq_routing; - struct hlist_head irq_ack_notifier_list; - struct mmu_notifier mmu_notifier; - long unsigned int mmu_notifier_seq; - long int mmu_notifier_count; - long int tlbs_dirty; - struct list_head devices; - u64 manual_dirty_log_protect; - struct dentry *debugfs_dentry; - struct kvm_stat_data **debugfs_stat_data; - struct srcu_struct srcu; - struct srcu_struct irq_srcu; - pid_t userspace_pid; - unsigned int max_halt_poll_ns; -}; - -struct kvm_io_range { - gpa_t addr; - int len; - struct kvm_io_device *dev; -}; - -struct kvm_io_bus { - int dev_count; - int ioeventfd_count; - struct kvm_io_range range[0]; -}; - -enum { - OUTSIDE_GUEST_MODE = 0, - IN_GUEST_MODE = 1, - EXITING_GUEST_MODE = 2, - READING_SHADOW_PAGE_TABLES = 3, -}; - -struct kvm_host_map { - struct page *page; - void *hva; - kvm_pfn_t pfn; - kvm_pfn_t gfn; -}; - -struct kvm_irq_routing_table { - int chip[988]; - u32 nr_rt_entries; - struct hlist_head map[0]; -}; - -struct kvm_memslots { - u64 generation; - short int id_to_index[512]; - atomic_t lru_slot; - int used_slots; - struct kvm_memory_slot memslots[0]; -}; - -struct kvm_stats_debugfs_item; - -struct kvm_stat_data { - struct kvm *kvm; - struct kvm_stats_debugfs_item *dbgfs_item; -}; - -enum kvm_mr_change { - KVM_MR_CREATE = 0, - KVM_MR_DELETE = 1, - KVM_MR_MOVE = 2, - KVM_MR_FLAGS_ONLY = 3, -}; - -enum kvm_stat_kind { - KVM_STAT_VM = 0, - KVM_STAT_VCPU = 1, -}; - -struct kvm_stats_debugfs_item { - const char *name; - int offset; - enum kvm_stat_kind kind; - int mode; -}; - -struct kvm_device_ops { - const char *name; - int (*create)(struct kvm_device *, u32); - void (*init)(struct kvm_device *); - void (*destroy)(struct kvm_device *); - void (*release)(struct kvm_device *); - int (*set_attr)(struct kvm_device *, struct kvm_device_attr *); - int (*get_attr)(struct kvm_device *, struct kvm_device_attr *); - int (*has_attr)(struct kvm_device *, struct kvm_device_attr *); - long int (*ioctl)(struct kvm_device *, unsigned int, long unsigned int); - int (*mmap)(struct kvm_device *, struct vm_area_struct *); -}; - -typedef int (*kvm_vm_thread_fn_t)(struct kvm *, uintptr_t); - -struct miscdevice { - int minor; - const char *name; - const struct file_operations *fops; - struct list_head list; - struct device *parent; - struct device *this_device; - const struct attribute_group **groups; - const char *nodename; - umode_t mode; -}; - -struct syscore_ops { - struct list_head node; - int (*suspend)(); - void (*resume)(); - void (*shutdown)(); -}; - -enum { - MEMREMAP_WB = 1, - MEMREMAP_WT = 2, - MEMREMAP_WC = 4, - MEMREMAP_ENC = 8, - MEMREMAP_DEC = 16, -}; - -struct trace_event_raw_kvm_userspace_exit { - struct trace_entry ent; - __u32 reason; - int errno; - char __data[0]; -}; - -struct trace_event_raw_kvm_vcpu_wakeup { - struct trace_entry ent; - __u64 ns; - bool waited; - bool valid; - char __data[0]; -}; - -struct trace_event_raw_kvm_set_irq { - struct trace_entry ent; - unsigned int gsi; - int level; - int irq_source_id; - char __data[0]; -}; - -struct trace_event_raw_kvm_ack_irq { - struct trace_entry ent; - unsigned int irqchip; - unsigned int pin; - char __data[0]; -}; - -struct trace_event_raw_kvm_mmio { - struct trace_entry ent; - u32 type; - u32 len; - u64 gpa; - u64 val; - char __data[0]; -}; - -struct trace_event_raw_kvm_fpu { - struct trace_entry ent; - u32 load; - char __data[0]; -}; - -struct trace_event_raw_kvm_age_page { - struct trace_entry ent; - u64 hva; - u64 gfn; - u8 level; - u8 referenced; - char __data[0]; -}; - -struct trace_event_raw_kvm_halt_poll_ns { - struct trace_entry ent; - bool grow; - unsigned int vcpu_id; - unsigned int new; - unsigned int old; - char __data[0]; -}; - -struct trace_event_data_offsets_kvm_userspace_exit {}; - -struct trace_event_data_offsets_kvm_vcpu_wakeup {}; - -struct trace_event_data_offsets_kvm_set_irq {}; - -struct trace_event_data_offsets_kvm_ack_irq {}; - -struct trace_event_data_offsets_kvm_mmio {}; - -struct trace_event_data_offsets_kvm_fpu {}; - -struct trace_event_data_offsets_kvm_age_page {}; - -struct trace_event_data_offsets_kvm_halt_poll_ns {}; - -typedef void (*btf_trace_kvm_userspace_exit)(void *, __u32, int); - -typedef void (*btf_trace_kvm_vcpu_wakeup)(void *, __u64, bool, bool); - -typedef void (*btf_trace_kvm_set_irq)(void *, unsigned int, int, int); - -typedef void (*btf_trace_kvm_ack_irq)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_kvm_mmio)(void *, int, int, u64, void *); - -typedef void (*btf_trace_kvm_fpu)(void *, int); - -typedef void (*btf_trace_kvm_age_page)(void *, ulong, int, struct kvm_memory_slot *, int); - -typedef void (*btf_trace_kvm_halt_poll_ns)(void *, bool, unsigned int, unsigned int, unsigned int); - -struct kvm_cpu_compat_check { - void *opaque; - int *ret; -}; - -struct kvm_vm_worker_thread_context { - struct kvm *kvm; - struct task_struct *parent; - struct completion init_done; - kvm_vm_thread_fn_t thread_fn; - uintptr_t data; - int err; -}; - -struct kvm_coalesced_mmio_dev { - struct list_head list; - struct kvm_io_device dev; - struct kvm *kvm; - struct kvm_coalesced_mmio_zone zone; -}; - -enum { - WORK_STRUCT_PENDING_BIT = 0, - WORK_STRUCT_DELAYED_BIT = 1, - WORK_STRUCT_PWQ_BIT = 2, - WORK_STRUCT_LINKED_BIT = 3, - WORK_STRUCT_COLOR_SHIFT = 4, - WORK_STRUCT_COLOR_BITS = 4, - WORK_STRUCT_PENDING = 1, - WORK_STRUCT_DELAYED = 2, - WORK_STRUCT_PWQ = 4, - WORK_STRUCT_LINKED = 8, - WORK_STRUCT_STATIC = 0, - WORK_NR_COLORS = 15, - WORK_NO_COLOR = 15, - WORK_CPU_UNBOUND = 256, - WORK_STRUCT_FLAG_BITS = 8, - WORK_OFFQ_FLAG_BASE = 4, - __WORK_OFFQ_CANCELING = 4, - WORK_OFFQ_CANCELING = 16, - WORK_OFFQ_FLAG_BITS = 1, - WORK_OFFQ_POOL_SHIFT = 5, - WORK_OFFQ_LEFT = 59, - WORK_OFFQ_POOL_BITS = 31, - WORK_OFFQ_POOL_NONE = 2147483647, - WORK_STRUCT_FLAG_MASK = 255, - WORK_STRUCT_WQ_DATA_MASK = 4294967040, - WORK_STRUCT_NO_POOL = 4294967264, - WORK_BUSY_PENDING = 1, - WORK_BUSY_RUNNING = 2, - WORKER_DESC_LEN = 24, -}; - -struct irq_bypass_consumer; - -struct irq_bypass_producer { - struct list_head node; - void *token; - int irq; - int (*add_consumer)(struct irq_bypass_producer *, struct irq_bypass_consumer *); - void (*del_consumer)(struct irq_bypass_producer *, struct irq_bypass_consumer *); - void (*stop)(struct irq_bypass_producer *); - void (*start)(struct irq_bypass_producer *); -}; - -struct irq_bypass_consumer { - struct list_head node; - void *token; - int (*add_producer)(struct irq_bypass_consumer *, struct irq_bypass_producer *); - void (*del_producer)(struct irq_bypass_consumer *, struct irq_bypass_producer *); - void (*stop)(struct irq_bypass_consumer *); - void (*start)(struct irq_bypass_consumer *); -}; - -enum { - kvm_ioeventfd_flag_nr_datamatch = 0, - kvm_ioeventfd_flag_nr_pio = 1, - kvm_ioeventfd_flag_nr_deassign = 2, - kvm_ioeventfd_flag_nr_virtio_ccw_notify = 3, - kvm_ioeventfd_flag_nr_fast_mmio = 4, - kvm_ioeventfd_flag_nr_max = 5, -}; - -struct fd { - struct file *file; - unsigned int flags; -}; - -struct kvm_s390_adapter_int { - u64 ind_addr; - u64 summary_addr; - u64 ind_offset; - u32 summary_offset; - u32 adapter_id; -}; - -struct kvm_hv_sint { - u32 vcpu; - u32 sint; -}; - -struct kvm_kernel_irq_routing_entry { - u32 gsi; - u32 type; - int (*set)(struct kvm_kernel_irq_routing_entry *, struct kvm *, int, int, bool); - union { - struct { - unsigned int irqchip; - unsigned int pin; - } irqchip; - struct { - u32 address_lo; - u32 address_hi; - u32 data; - u32 flags; - u32 devid; - } msi; - struct kvm_s390_adapter_int adapter; - struct kvm_hv_sint hv_sint; - }; - struct hlist_node link; -}; - -struct kvm_irq_ack_notifier { - struct hlist_node link; - unsigned int gsi; - void (*irq_acked)(struct kvm_irq_ack_notifier *); -}; - -typedef struct poll_table_struct poll_table; - -struct kvm_kernel_irqfd_resampler { - struct kvm *kvm; - struct list_head list; - struct kvm_irq_ack_notifier notifier; - struct list_head link; -}; - -struct kvm_kernel_irqfd { - struct kvm *kvm; - wait_queue_entry_t wait; - struct kvm_kernel_irq_routing_entry irq_entry; - seqcount_spinlock_t irq_entry_sc; - int gsi; - struct work_struct inject; - struct kvm_kernel_irqfd_resampler *resampler; - struct eventfd_ctx *resamplefd; - struct list_head resampler_link; - struct eventfd_ctx *eventfd; - struct list_head list; - poll_table pt; - struct work_struct shutdown; - struct irq_bypass_consumer consumer; - struct irq_bypass_producer *producer; -}; - -struct _ioeventfd { - struct list_head list; - u64 addr; - int length; - struct eventfd_ctx *eventfd; - u64 datamatch; - struct kvm_io_device dev; - u8 bus_idx; - bool wildcard; -}; - -struct iommu_group {}; - -struct vfio_group; - -struct kvm_vfio_group { - struct list_head node; - struct vfio_group *vfio_group; -}; - -struct kvm_vfio { - struct list_head group_list; - struct mutex lock; - bool noncoherent; -}; - -struct kvm_vcpu_init { - __u32 target; - __u32 features[7]; -}; - -struct kvm_vcpu_events { - struct { - __u8 serror_pending; - __u8 serror_has_esr; - __u8 ext_dabt_pending; - __u8 pad[5]; - __u64 serror_esr; - } exception; - __u32 reserved[12]; -}; - -struct kvm_reg_list { - __u64 n; - __u64 reg[0]; -}; - -struct kvm_one_reg { - __u64 id; - __u64 addr; -}; - -struct kvm_arm_device_addr { - __u64 id; - __u64 addr; -}; - -enum vgic_type { - VGIC_V2 = 0, - VGIC_V3 = 1, -}; - -struct vgic_global { - enum vgic_type type; - phys_addr_t vcpu_base; - void *vcpu_base_va; - void *vcpu_hyp_va; - void *vctrl_base; - void *vctrl_hyp; - int nr_lr; - unsigned int maint_irq; - int max_gic_vcpus; - bool can_emulate_gicv2; - bool has_gicv4; - bool has_gicv4_1; - struct static_key_false gicv3_cpuif; - u32 ich_vtr_el2; -}; - -struct timer_map { - struct arch_timer_context *direct_vtimer; - struct arch_timer_context *direct_ptimer; - struct arch_timer_context *emul_ptimer; -}; - -typedef u64 kvm_pte_t; - -struct kvm_pgtable { - u32 ia_bits; - u32 start_level; - kvm_pte_t *pgd; - struct kvm_s2_mmu *mmu; -}; - -struct kvm_pmu_events { - u32 events_host; - u32 events_guest; -}; - -struct kvm_host_data { - struct kvm_cpu_context host_ctxt; - struct kvm_pmu_events pmu_events; - long: 64; -}; - -struct trace_event_raw_kvm_entry { - struct trace_entry ent; - long unsigned int vcpu_pc; - char __data[0]; -}; - -struct trace_event_raw_kvm_exit { - struct trace_entry ent; - int ret; - unsigned int esr_ec; - long unsigned int vcpu_pc; - char __data[0]; -}; - -struct trace_event_raw_kvm_guest_fault { - struct trace_entry ent; - long unsigned int vcpu_pc; - long unsigned int hsr; - long unsigned int hxfar; - long long unsigned int ipa; - char __data[0]; -}; - -struct trace_event_raw_kvm_access_fault { - struct trace_entry ent; - long unsigned int ipa; - char __data[0]; -}; - -struct trace_event_raw_kvm_irq_line { - struct trace_entry ent; - unsigned int type; - int vcpu_idx; - int irq_num; - int level; - char __data[0]; -}; - -struct trace_event_raw_kvm_mmio_emulate { - struct trace_entry ent; - long unsigned int vcpu_pc; - long unsigned int instr; - long unsigned int cpsr; - char __data[0]; -}; - -struct trace_event_raw_kvm_unmap_hva_range { - struct trace_entry ent; - long unsigned int start; - long unsigned int end; - char __data[0]; -}; - -struct trace_event_raw_kvm_set_spte_hva { - struct trace_entry ent; - long unsigned int hva; - char __data[0]; -}; - -struct trace_event_raw_kvm_age_hva { - struct trace_entry ent; - long unsigned int start; - long unsigned int end; - char __data[0]; -}; - -struct trace_event_raw_kvm_test_age_hva { - struct trace_entry ent; - long unsigned int hva; - char __data[0]; -}; - -struct trace_event_raw_kvm_set_way_flush { - struct trace_entry ent; - long unsigned int vcpu_pc; - bool cache; - char __data[0]; -}; - -struct trace_event_raw_kvm_toggle_cache { - struct trace_entry ent; - long unsigned int vcpu_pc; - bool was; - bool now; - char __data[0]; -}; - -struct trace_event_raw_kvm_timer_update_irq { - struct trace_entry ent; - long unsigned int vcpu_id; - __u32 irq; - int level; - char __data[0]; -}; - -struct trace_event_raw_kvm_get_timer_map { - struct trace_entry ent; - long unsigned int vcpu_id; - int direct_vtimer; - int direct_ptimer; - int emul_ptimer; - char __data[0]; -}; - -struct trace_event_raw_kvm_timer_save_state { - struct trace_entry ent; - long unsigned int ctl; - long long unsigned int cval; - int timer_idx; - char __data[0]; -}; - -struct trace_event_raw_kvm_timer_restore_state { - struct trace_entry ent; - long unsigned int ctl; - long long unsigned int cval; - int timer_idx; - char __data[0]; -}; - -struct trace_event_raw_kvm_timer_hrtimer_expire { - struct trace_entry ent; - int timer_idx; - char __data[0]; -}; - -struct trace_event_raw_kvm_timer_emulate { - struct trace_entry ent; - int timer_idx; - bool should_fire; - char __data[0]; -}; - -struct trace_event_data_offsets_kvm_entry {}; - -struct trace_event_data_offsets_kvm_exit {}; - -struct trace_event_data_offsets_kvm_guest_fault {}; - -struct trace_event_data_offsets_kvm_access_fault {}; - -struct trace_event_data_offsets_kvm_irq_line {}; - -struct trace_event_data_offsets_kvm_mmio_emulate {}; - -struct trace_event_data_offsets_kvm_unmap_hva_range {}; - -struct trace_event_data_offsets_kvm_set_spte_hva {}; - -struct trace_event_data_offsets_kvm_age_hva {}; - -struct trace_event_data_offsets_kvm_test_age_hva {}; - -struct trace_event_data_offsets_kvm_set_way_flush {}; - -struct trace_event_data_offsets_kvm_toggle_cache {}; - -struct trace_event_data_offsets_kvm_timer_update_irq {}; - -struct trace_event_data_offsets_kvm_get_timer_map {}; - -struct trace_event_data_offsets_kvm_timer_save_state {}; - -struct trace_event_data_offsets_kvm_timer_restore_state {}; - -struct trace_event_data_offsets_kvm_timer_hrtimer_expire {}; - -struct trace_event_data_offsets_kvm_timer_emulate {}; - -typedef void (*btf_trace_kvm_entry)(void *, long unsigned int); - -typedef void (*btf_trace_kvm_exit)(void *, int, unsigned int, long unsigned int); - -typedef void (*btf_trace_kvm_guest_fault)(void *, long unsigned int, long unsigned int, long unsigned int, long long unsigned int); - -typedef void (*btf_trace_kvm_access_fault)(void *, long unsigned int); - -typedef void (*btf_trace_kvm_irq_line)(void *, unsigned int, int, int, int); - -typedef void (*btf_trace_kvm_mmio_emulate)(void *, long unsigned int, long unsigned int, long unsigned int); - -typedef void (*btf_trace_kvm_unmap_hva_range)(void *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_kvm_set_spte_hva)(void *, long unsigned int); - -typedef void (*btf_trace_kvm_age_hva)(void *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_kvm_test_age_hva)(void *, long unsigned int); - -typedef void (*btf_trace_kvm_set_way_flush)(void *, long unsigned int, bool); - -typedef void (*btf_trace_kvm_toggle_cache)(void *, long unsigned int, bool, bool); - -typedef void (*btf_trace_kvm_timer_update_irq)(void *, long unsigned int, __u32, int); - -typedef void (*btf_trace_kvm_get_timer_map)(void *, long unsigned int, struct timer_map *); - -typedef void (*btf_trace_kvm_timer_save_state)(void *, struct arch_timer_context *); - -typedef void (*btf_trace_kvm_timer_restore_state)(void *, struct arch_timer_context *); - -typedef void (*btf_trace_kvm_timer_hrtimer_expire)(void *, struct arch_timer_context *); - -typedef void (*btf_trace_kvm_timer_emulate)(void *, struct arch_timer_context *, bool); - -enum kvm_pgtable_prot { - KVM_PGTABLE_PROT_X = 1, - KVM_PGTABLE_PROT_W = 2, - KVM_PGTABLE_PROT_R = 4, - KVM_PGTABLE_PROT_DEVICE = 8, -}; - -typedef long unsigned int hva_t; - -struct hstate {}; - -enum kvm_arch_timers { - TIMER_PTIMER = 0, - TIMER_VTIMER = 1, - NR_KVM_TIMERS = 2, -}; - -struct pvclock_vcpu_stolen_time { - __le32 revision; - __le32 attributes; - __le64 stolen_time; - u8 padding[48]; -}; - -enum exception_type { - except_type_sync = 0, - except_type_irq = 128, - except_type_fiq = 256, - except_type_serror = 384, -}; - -struct sys_reg_params; - -struct sys_reg_desc { - const char *name; - u8 Op0; - u8 Op1; - u8 CRn; - u8 CRm; - u8 Op2; - bool (*access)(struct kvm_vcpu *, struct sys_reg_params *, const struct sys_reg_desc *); - void (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *); - int reg; - u64 val; - int (*__get_user)(struct kvm_vcpu *, const struct sys_reg_desc *, const struct kvm_one_reg *, void *); - int (*set_user)(struct kvm_vcpu *, const struct sys_reg_desc *, const struct kvm_one_reg *, void *); - unsigned int (*visibility)(const struct kvm_vcpu *, const struct sys_reg_desc *); -}; - -struct sys_reg_params { - u8 Op0; - u8 Op1; - u8 CRn; - u8 CRm; - u8 Op2; - u64 regval; - bool is_write; - bool is_aarch32; - bool is_32bit; -}; - -struct trace_event_raw_kvm_wfx_arm64 { - struct trace_entry ent; - long unsigned int vcpu_pc; - bool is_wfe; - char __data[0]; -}; - -struct trace_event_raw_kvm_hvc_arm64 { - struct trace_entry ent; - long unsigned int vcpu_pc; - long unsigned int r0; - long unsigned int imm; - char __data[0]; -}; - -struct trace_event_raw_kvm_arm_setup_debug { - struct trace_entry ent; - struct kvm_vcpu *vcpu; - __u32 guest_debug; - char __data[0]; -}; - -struct trace_event_raw_kvm_arm_clear_debug { - struct trace_entry ent; - __u32 guest_debug; - char __data[0]; -}; - -struct trace_event_raw_kvm_arm_set_dreg32 { - struct trace_entry ent; - const char *name; - __u32 value; - char __data[0]; -}; - -struct trace_event_raw_kvm_arm_set_regset { - struct trace_entry ent; - const char *name; - int len; - u64 ctrls[16]; - u64 values[16]; - char __data[0]; -}; - -struct trace_event_raw_trap_reg { - struct trace_entry ent; - const char *fn; - int reg; - bool is_write; - u64 write_value; - char __data[0]; -}; - -struct trace_event_raw_kvm_handle_sys_reg { - struct trace_entry ent; - long unsigned int hsr; - char __data[0]; -}; - -struct trace_event_raw_kvm_sys_access { - struct trace_entry ent; - long unsigned int vcpu_pc; - bool is_write; - const char *name; - u8 Op0; - u8 Op1; - u8 CRn; - u8 CRm; - u8 Op2; - char __data[0]; -}; - -struct trace_event_raw_kvm_set_guest_debug { - struct trace_entry ent; - struct kvm_vcpu *vcpu; - __u32 guest_debug; - char __data[0]; -}; - -struct trace_event_data_offsets_kvm_wfx_arm64 {}; - -struct trace_event_data_offsets_kvm_hvc_arm64 {}; - -struct trace_event_data_offsets_kvm_arm_setup_debug {}; - -struct trace_event_data_offsets_kvm_arm_clear_debug {}; - -struct trace_event_data_offsets_kvm_arm_set_dreg32 {}; - -struct trace_event_data_offsets_kvm_arm_set_regset {}; - -struct trace_event_data_offsets_trap_reg {}; - -struct trace_event_data_offsets_kvm_handle_sys_reg {}; - -struct trace_event_data_offsets_kvm_sys_access {}; - -struct trace_event_data_offsets_kvm_set_guest_debug {}; - -typedef void (*btf_trace_kvm_wfx_arm64)(void *, long unsigned int, bool); - -typedef void (*btf_trace_kvm_hvc_arm64)(void *, long unsigned int, long unsigned int, long unsigned int); - -typedef void (*btf_trace_kvm_arm_setup_debug)(void *, struct kvm_vcpu *, __u32); - -typedef void (*btf_trace_kvm_arm_clear_debug)(void *, __u32); - -typedef void (*btf_trace_kvm_arm_set_dreg32)(void *, const char *, __u32); - -typedef void (*btf_trace_kvm_arm_set_regset)(void *, const char *, int, __u64 *, __u64 *); - -typedef void (*btf_trace_trap_reg)(void *, const char *, int, bool, u64); - -typedef void (*btf_trace_kvm_handle_sys_reg)(void *, long unsigned int); - -typedef void (*btf_trace_kvm_sys_access)(void *, long unsigned int, struct sys_reg_params *, const struct sys_reg_desc *); - -typedef void (*btf_trace_kvm_set_guest_debug)(void *, struct kvm_vcpu *, __u32); - -typedef int (*exit_handle_fn)(struct kvm_vcpu *); - -struct sve_state_reg_region { - unsigned int koffset; - unsigned int klen; - unsigned int upad; -}; - -struct __va_list { - void *__stack; - void *__gr_top; - void *__vr_top; - int __gr_offs; - int __vr_offs; -}; - -typedef struct __va_list __gnuc_va_list; - -typedef __gnuc_va_list va_list; - -struct va_format { - const char *fmt; - va_list *va; -}; - -enum kvm_arch_timer_regs { - TIMER_REG_CNT = 0, - TIMER_REG_CVAL = 1, - TIMER_REG_TVAL = 2, - TIMER_REG_CTL = 3, -}; - -struct vgic_vmcr { - u32 grpen0; - u32 grpen1; - u32 ackctl; - u32 fiqen; - u32 cbpr; - u32 eoim; - u32 abpr; - u32 bpr; - u32 pmr; -}; - -struct cyclecounter { - u64 (*read)(const struct cyclecounter *); - u64 mask; - u32 mult; - u32 shift; -}; - -struct timecounter { - const struct cyclecounter *cc; - u64 cycle_last; - u64 nsec; - u64 mask; - u64 frac; -}; - -struct arch_timer_kvm_info { - struct timecounter timecounter; - int virtual_irq; - int physical_irq; -}; - -enum hrtimer_mode { - HRTIMER_MODE_ABS = 0, - HRTIMER_MODE_REL = 1, - HRTIMER_MODE_PINNED = 2, - HRTIMER_MODE_SOFT = 4, - HRTIMER_MODE_HARD = 8, - HRTIMER_MODE_ABS_PINNED = 2, - HRTIMER_MODE_REL_PINNED = 3, - HRTIMER_MODE_ABS_SOFT = 4, - HRTIMER_MODE_REL_SOFT = 5, - HRTIMER_MODE_ABS_PINNED_SOFT = 6, - HRTIMER_MODE_REL_PINNED_SOFT = 7, - HRTIMER_MODE_ABS_HARD = 8, - HRTIMER_MODE_REL_HARD = 9, - HRTIMER_MODE_ABS_PINNED_HARD = 10, - HRTIMER_MODE_REL_PINNED_HARD = 11, -}; - -enum { - IRQD_TRIGGER_MASK = 15, - IRQD_SETAFFINITY_PENDING = 256, - IRQD_ACTIVATED = 512, - IRQD_NO_BALANCING = 1024, - IRQD_PER_CPU = 2048, - IRQD_AFFINITY_SET = 4096, - IRQD_LEVEL = 8192, - IRQD_WAKEUP_STATE = 16384, - IRQD_MOVE_PCNTXT = 32768, - IRQD_IRQ_DISABLED = 65536, - IRQD_IRQ_MASKED = 131072, - IRQD_IRQ_INPROGRESS = 262144, - IRQD_WAKEUP_ARMED = 524288, - IRQD_FORWARDED_TO_VCPU = 1048576, - IRQD_AFFINITY_MANAGED = 2097152, - IRQD_IRQ_STARTED = 4194304, - IRQD_MANAGED_SHUTDOWN = 8388608, - IRQD_SINGLE_TARGET = 16777216, - IRQD_DEFAULT_TRIGGER_SET = 33554432, - IRQD_CAN_RESERVE = 67108864, - IRQD_MSI_NOMASK_QUIRK = 134217728, - IRQD_HANDLE_ENFORCE_IRQCTX = 268435456, - IRQD_AFFINITY_ON_ACTIVATE = 536870912, - IRQD_IRQ_ENABLED_ON_SUSPEND = 1073741824, -}; - -struct trace_event_raw_vgic_update_irq_pending { - struct trace_entry ent; - long unsigned int vcpu_id; - __u32 irq; - bool level; - char __data[0]; -}; - -struct trace_event_data_offsets_vgic_update_irq_pending {}; - -typedef void (*btf_trace_vgic_update_irq_pending)(void *, long unsigned int, __u32, bool); - -enum gic_type { - GIC_V2 = 0, - GIC_V3 = 1, -}; - -struct gic_kvm_info { - enum gic_type type; - struct resource vcpu; - unsigned int maint_irq; - struct resource vctrl; - bool has_v4; - bool has_v4_1; -}; - -struct its_vlpi_map { - struct its_vm *vm; - struct its_vpe *vpe; - u32 vintid; - u8 properties; - bool db_enabled; -}; - -struct vgic_reg_attr { - struct kvm_vcpu *vcpu; - gpa_t addr; -}; - -struct its_device { - struct list_head dev_list; - struct list_head itt_head; - u32 num_eventid_bits; - gpa_t itt_addr; - u32 device_id; -}; - -struct its_collection { - struct list_head coll_list; - u32 collection_id; - u32 target_addr; -}; - -struct its_ite { - struct list_head ite_list; - struct vgic_irq *irq; - struct its_collection *collection; - u32 event_id; -}; - -struct vgic_translation_cache_entry { - struct list_head entry; - phys_addr_t db; - u32 devid; - u32 eventid; - struct vgic_irq *irq; -}; - -struct vgic_its_abi { - int cte_esz; - int dte_esz; - int ite_esz; - int (*save_tables)(struct vgic_its *); - int (*restore_tables)(struct vgic_its *); - int (*commit)(struct vgic_its *); -}; - -typedef int (*entry_fn_t)(struct vgic_its *, u32, void *, void *); - -struct vgic_state_iter { - int nr_cpus; - int nr_spis; - int nr_lpis; - int dist_id; - int vcpu_id; - int intid; - int lpi_idx; - u32 *lpi_array; -}; - -struct kvm_pmu_event_filter { - __u16 base_event; - __u16 nevents; - __u8 action; - __u8 pad[3]; -}; - -struct tlb_inv_context { - long unsigned int flags; - u64 tcr; - u64 sctlr; -}; - -struct tlb_inv_context___2 { - u64 tcr; -}; - -enum kvm_pgtable_walk_flags { - KVM_PGTABLE_WALK_LEAF = 1, - KVM_PGTABLE_WALK_TABLE_PRE = 2, - KVM_PGTABLE_WALK_TABLE_POST = 4, -}; - -typedef int (*kvm_pgtable_visitor_fn_t)(u64, u64, u32, kvm_pte_t *, enum kvm_pgtable_walk_flags, void * const); - -struct kvm_pgtable_walker { - const kvm_pgtable_visitor_fn_t cb; - void * const arg; - const enum kvm_pgtable_walk_flags flags; -}; - -struct kvm_pgtable_walk_data { - struct kvm_pgtable *pgt; - struct kvm_pgtable_walker *walker; - u64 addr; - u64 end; -}; - -struct hyp_map_data { - u64 phys; - kvm_pte_t attr; -}; - -struct stage2_map_data { - u64 phys; - kvm_pte_t attr; - kvm_pte_t *anchor; - struct kvm_s2_mmu *mmu; - struct kvm_mmu_memory_cache *memcache; -}; - -struct stage2_attr_data { - kvm_pte_t attr_set; - kvm_pte_t attr_clr; - kvm_pte_t pte; - u32 level; -}; - -struct static_key_true { - struct static_key key; -}; - -enum tk_offsets { - TK_OFFS_REAL = 0, - TK_OFFS_BOOT = 1, - TK_OFFS_TAI = 2, - TK_OFFS_MAX = 3, -}; - -typedef struct pglist_data pg_data_t; - -struct clone_args { - __u64 flags; - __u64 pidfd; - __u64 child_tid; - __u64 parent_tid; - __u64 exit_signal; - __u64 stack; - __u64 stack_size; - __u64 tls; - __u64 set_tid; - __u64 set_tid_size; - __u64 cgroup; -}; - -struct fdtable { - unsigned int max_fds; - struct file **fd; - long unsigned int *close_on_exec; - long unsigned int *open_fds; - long unsigned int *full_fds_bits; - struct callback_head rcu; -}; - -struct files_struct { - atomic_t count; - bool resize_in_progress; - wait_queue_head_t resize_wait; - struct fdtable *fdt; - struct fdtable fdtab; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t file_lock; - unsigned int next_fd; - long unsigned int close_on_exec_init[1]; - long unsigned int open_fds_init[1]; - long unsigned int full_fds_bits_init[1]; - struct file *fd_array[64]; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct io_identity { - struct files_struct *files; - struct mm_struct *mm; - struct cgroup_subsys_state *blkcg_css; - const struct cred *creds; - struct nsproxy *nsproxy; - struct fs_struct *fs; - long unsigned int fsize; - kuid_t loginuid; - unsigned int sessionid; - refcount_t count; -}; - -struct io_uring_task { - struct xarray xa; - struct wait_queue_head wait; - struct file *last; - struct percpu_counter inflight; - struct io_identity __identity; - struct io_identity *identity; - atomic_t in_idle; - bool sqpoll; -}; - -struct robust_list { - struct robust_list *next; -}; - -struct robust_list_head { - struct robust_list list; - long int futex_offset; - struct robust_list *list_op_pending; -}; - -struct kernel_clone_args { - u64 flags; - int *pidfd; - int *child_tid; - int *parent_tid; - int exit_signal; - long unsigned int stack; - long unsigned int stack_size; - long unsigned int tls; - pid_t *set_tid; - size_t set_tid_size; - int cgroup; - struct cgroup *cgrp; - struct css_set *cset; -}; - -struct multiprocess_signals { - sigset_t signal; - struct hlist_node node; -}; - -typedef int (*proc_visitor)(struct task_struct *, void *); - -enum { - IOPRIO_CLASS_NONE = 0, - IOPRIO_CLASS_RT = 1, - IOPRIO_CLASS_BE = 2, - IOPRIO_CLASS_IDLE = 3, -}; - -struct mempolicy {}; - -enum { - FUTEX_STATE_OK = 0, - FUTEX_STATE_EXITING = 1, - FUTEX_STATE_DEAD = 2, -}; - -enum proc_hidepid { - HIDEPID_OFF = 0, - HIDEPID_NO_ACCESS = 1, - HIDEPID_INVISIBLE = 2, - HIDEPID_NOT_PTRACEABLE = 4, -}; - -enum proc_pidonly { - PROC_PIDONLY_OFF = 0, - PROC_PIDONLY_ON = 1, -}; - -struct proc_fs_info { - struct pid_namespace *pid_ns; - struct dentry *proc_self; - struct dentry *proc_thread_self; - kgid_t pid_gid; - enum proc_hidepid hide_pid; - enum proc_pidonly pidonly; -}; - -struct trace_event_raw_task_newtask { - struct trace_entry ent; - pid_t pid; - char comm[16]; - long unsigned int clone_flags; - short int oom_score_adj; - char __data[0]; -}; - -struct trace_event_raw_task_rename { - struct trace_entry ent; - pid_t pid; - char oldcomm[16]; - char newcomm[16]; - short int oom_score_adj; - char __data[0]; -}; - -struct trace_event_data_offsets_task_newtask {}; - -struct trace_event_data_offsets_task_rename {}; - -typedef void (*btf_trace_task_newtask)(void *, struct task_struct *, long unsigned int); - -typedef void (*btf_trace_task_rename)(void *, struct task_struct *, const char *); - -struct taint_flag { - char c_true; - char c_false; - bool module; -}; - -enum ftrace_dump_mode { - DUMP_NONE = 0, - DUMP_ALL = 1, - DUMP_ORIG = 2, -}; - -enum kmsg_dump_reason { - KMSG_DUMP_UNDEF = 0, - KMSG_DUMP_PANIC = 1, - KMSG_DUMP_OOPS = 2, - KMSG_DUMP_EMERG = 3, - KMSG_DUMP_SHUTDOWN = 4, - KMSG_DUMP_MAX = 5, -}; - -enum con_flush_mode { - CONSOLE_FLUSH_PENDING = 0, - CONSOLE_REPLAY_ALL = 1, -}; - -struct warn_args { - const char *fmt; - va_list args; -}; - -struct smp_hotplug_thread { - struct task_struct **store; - struct list_head list; - int (*thread_should_run)(unsigned int); - void (*thread_fn)(unsigned int); - void (*create)(unsigned int); - void (*setup)(unsigned int); - void (*cleanup)(unsigned int, bool); - void (*park)(unsigned int); - void (*unpark)(unsigned int); - bool selfparking; - const char *thread_comm; -}; - -struct trace_event_raw_cpuhp_enter { - struct trace_entry ent; - unsigned int cpu; - int target; - int idx; - void *fun; - char __data[0]; -}; - -struct trace_event_raw_cpuhp_multi_enter { - struct trace_entry ent; - unsigned int cpu; - int target; - int idx; - void *fun; - char __data[0]; -}; - -struct trace_event_raw_cpuhp_exit { - struct trace_entry ent; - unsigned int cpu; - int state; - int idx; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_cpuhp_enter {}; - -struct trace_event_data_offsets_cpuhp_multi_enter {}; - -struct trace_event_data_offsets_cpuhp_exit {}; - -typedef void (*btf_trace_cpuhp_enter)(void *, unsigned int, int, int, int (*)(unsigned int)); - -typedef void (*btf_trace_cpuhp_multi_enter)(void *, unsigned int, int, int, int (*)(unsigned int, struct hlist_node *), struct hlist_node *); - -typedef void (*btf_trace_cpuhp_exit)(void *, unsigned int, int, int, int); - -struct cpuhp_cpu_state { - enum cpuhp_state state; - enum cpuhp_state target; - enum cpuhp_state fail; - struct task_struct *thread; - bool should_run; - bool rollback; - bool single; - bool bringup; - struct hlist_node *node; - struct hlist_node *last; - enum cpuhp_state cb_state; - int result; - struct completion done_up; - struct completion done_down; -}; - -struct cpuhp_step { - const char *name; - union { - int (*single)(unsigned int); - int (*multi)(unsigned int, struct hlist_node *); - } startup; - union { - int (*single)(unsigned int); - int (*multi)(unsigned int, struct hlist_node *); - } teardown; - struct hlist_head list; - bool cant_stop; - bool multi_instance; -}; - -enum cpu_mitigations { - CPU_MITIGATIONS_OFF = 0, - CPU_MITIGATIONS_AUTO = 1, - CPU_MITIGATIONS_AUTO_NOSMT = 2, -}; - -struct __kernel_old_timeval { - __kernel_long_t tv_sec; - __kernel_long_t tv_usec; -}; - -struct old_timeval32 { - old_time32_t tv_sec; - s32 tv_usec; -}; - -struct rusage { - struct __kernel_old_timeval ru_utime; - struct __kernel_old_timeval ru_stime; - __kernel_long_t ru_maxrss; - __kernel_long_t ru_ixrss; - __kernel_long_t ru_idrss; - __kernel_long_t ru_isrss; - __kernel_long_t ru_minflt; - __kernel_long_t ru_majflt; - __kernel_long_t ru_nswap; - __kernel_long_t ru_inblock; - __kernel_long_t ru_oublock; - __kernel_long_t ru_msgsnd; - __kernel_long_t ru_msgrcv; - __kernel_long_t ru_nsignals; - __kernel_long_t ru_nvcsw; - __kernel_long_t ru_nivcsw; -}; - -typedef u32 compat_uint_t; - -struct compat_rusage { - struct old_timeval32 ru_utime; - struct old_timeval32 ru_stime; - compat_long_t ru_maxrss; - compat_long_t ru_ixrss; - compat_long_t ru_idrss; - compat_long_t ru_isrss; - compat_long_t ru_minflt; - compat_long_t ru_majflt; - compat_long_t ru_nswap; - compat_long_t ru_inblock; - compat_long_t ru_oublock; - compat_long_t ru_msgsnd; - compat_long_t ru_msgrcv; - compat_long_t ru_nsignals; - compat_long_t ru_nvcsw; - compat_long_t ru_nivcsw; -}; - -struct waitid_info { - pid_t pid; - uid_t uid; - int status; - int cause; -}; - -struct wait_opts { - enum pid_type wo_type; - int wo_flags; - struct pid *wo_pid; - struct waitid_info *wo_info; - int wo_stat; - struct rusage *wo_rusage; - wait_queue_entry_t child_wait; - int notask_error; -}; - -typedef struct { - unsigned int __softirq_pending; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -} irq_cpustat_t; - -struct softirq_action { - void (*action)(struct softirq_action *); -}; - -struct tasklet_struct { - struct tasklet_struct *next; - long unsigned int state; - atomic_t count; - bool use_callback; - union { - void (*func)(long unsigned int); - void (*callback)(struct tasklet_struct *); - }; - long unsigned int data; -}; - -enum { - TASKLET_STATE_SCHED = 0, - TASKLET_STATE_RUN = 1, -}; - -struct kernel_stat { - long unsigned int irqs_sum; - unsigned int softirqs[10]; -}; - -struct trace_event_raw_irq_handler_entry { - struct trace_entry ent; - int irq; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_irq_handler_exit { - struct trace_entry ent; - int irq; - int ret; - char __data[0]; -}; - -struct trace_event_raw_softirq { - struct trace_entry ent; - unsigned int vec; - char __data[0]; -}; - -struct trace_event_data_offsets_irq_handler_entry { - u32 name; -}; - -struct trace_event_data_offsets_irq_handler_exit {}; - -struct trace_event_data_offsets_softirq {}; - -typedef void (*btf_trace_irq_handler_entry)(void *, int, struct irqaction *); - -typedef void (*btf_trace_irq_handler_exit)(void *, int, struct irqaction *, int); - -typedef void (*btf_trace_softirq_entry)(void *, unsigned int); - -typedef void (*btf_trace_softirq_exit)(void *, unsigned int); - -typedef void (*btf_trace_softirq_raise)(void *, unsigned int); - -struct tasklet_head { - struct tasklet_struct *head; - struct tasklet_struct **tail; -}; - -enum { - IORES_DESC_NONE = 0, - IORES_DESC_CRASH_KERNEL = 1, - IORES_DESC_ACPI_TABLES = 2, - IORES_DESC_ACPI_NV_STORAGE = 3, - IORES_DESC_PERSISTENT_MEMORY = 4, - IORES_DESC_PERSISTENT_MEMORY_LEGACY = 5, - IORES_DESC_DEVICE_PRIVATE_MEMORY = 6, - IORES_DESC_RESERVED = 7, - IORES_DESC_SOFT_RESERVED = 8, -}; - -typedef void (*dr_release_t)(struct device *, void *); - -enum { - REGION_INTERSECTS = 0, - REGION_DISJOINT = 1, - REGION_MIXED = 2, -}; - -struct resource_entry { - struct list_head node; - struct resource *res; - resource_size_t offset; - struct resource __res; -}; - -struct resource_constraint { - resource_size_t min; - resource_size_t max; - resource_size_t align; - resource_size_t (*alignf)(void *, const struct resource *, resource_size_t, resource_size_t); - void *alignf_data; -}; - -enum { - MAX_IORES_LEVEL = 5, -}; - -struct region_devres { - struct resource *parent; - resource_size_t start; - resource_size_t n; -}; - -struct dentry_stat_t { - long int nr_dentry; - long int nr_unused; - long int age_limit; - long int want_pages; - long int nr_negative; - long int dummy; -}; - -struct files_stat_struct { - long unsigned int nr_files; - long unsigned int nr_free_files; - long unsigned int max_files; -}; - -struct inodes_stat_t { - long int nr_inodes; - long int nr_unused; - long int dummy[5]; -}; - -enum sched_tunable_scaling { - SCHED_TUNABLESCALING_NONE = 0, - SCHED_TUNABLESCALING_LOG = 1, - SCHED_TUNABLESCALING_LINEAR = 2, - SCHED_TUNABLESCALING_END = 3, -}; - -enum sysctl_writes_mode { - SYSCTL_WRITES_LEGACY = 4294967295, - SYSCTL_WRITES_WARN = 0, - SYSCTL_WRITES_STRICT = 1, -}; - -struct do_proc_dointvec_minmax_conv_param { - int *min; - int *max; -}; - -struct do_proc_douintvec_minmax_conv_param { - unsigned int *min; - unsigned int *max; -}; - -struct __user_cap_header_struct { - __u32 version; - int pid; -}; - -typedef struct __user_cap_header_struct *cap_user_header_t; - -struct __user_cap_data_struct { - __u32 effective; - __u32 permitted; - __u32 inheritable; -}; - -typedef struct __user_cap_data_struct *cap_user_data_t; - -typedef struct siginfo siginfo_t; - -struct sigqueue { - struct list_head list; - int flags; - kernel_siginfo_t info; - struct user_struct *user; -}; - -struct ptrace_peeksiginfo_args { - __u64 off; - __u32 flags; - __s32 nr; -}; - -struct ptrace_syscall_info { - __u8 op; - __u8 pad[3]; - __u32 arch; - __u64 instruction_pointer; - __u64 stack_pointer; - union { - struct { - __u64 nr; - __u64 args[6]; - } entry; - struct { - __s64 rval; - __u8 is_error; - } exit; - struct { - __u64 nr; - __u64 args[6]; - __u32 ret_data; - } seccomp; - }; -}; - -struct compat_iovec { - compat_uptr_t iov_base; - compat_size_t iov_len; -}; - -typedef struct compat_siginfo compat_siginfo_t; - -typedef long unsigned int old_sigset_t; - -typedef u32 compat_old_sigset_t; - -struct compat_sigaction { - compat_uptr_t sa_handler; - compat_ulong_t sa_flags; - compat_uptr_t sa_restorer; - compat_sigset_t sa_mask; -}; - -struct compat_old_sigaction { - compat_uptr_t sa_handler; - compat_old_sigset_t sa_mask; - compat_ulong_t sa_flags; - compat_uptr_t sa_restorer; -}; - -enum { - TRACE_SIGNAL_DELIVERED = 0, - TRACE_SIGNAL_IGNORED = 1, - TRACE_SIGNAL_ALREADY_PENDING = 2, - TRACE_SIGNAL_OVERFLOW_FAIL = 3, - TRACE_SIGNAL_LOSE_INFO = 4, -}; - -struct trace_event_raw_signal_generate { - struct trace_entry ent; - int sig; - int errno; - int code; - char comm[16]; - pid_t pid; - int group; - int result; - char __data[0]; -}; - -struct trace_event_raw_signal_deliver { - struct trace_entry ent; - int sig; - int errno; - int code; - long unsigned int sa_handler; - long unsigned int sa_flags; - char __data[0]; -}; - -struct trace_event_data_offsets_signal_generate {}; - -struct trace_event_data_offsets_signal_deliver {}; - -typedef void (*btf_trace_signal_generate)(void *, int, struct kernel_siginfo *, struct task_struct *, int, int); - -typedef void (*btf_trace_signal_deliver)(void *, int, struct kernel_siginfo *, struct k_sigaction *); - -typedef __kernel_clock_t clock_t; - -struct sysinfo { - __kernel_long_t uptime; - __kernel_ulong_t loads[3]; - __kernel_ulong_t totalram; - __kernel_ulong_t freeram; - __kernel_ulong_t sharedram; - __kernel_ulong_t bufferram; - __kernel_ulong_t totalswap; - __kernel_ulong_t freeswap; - __u16 procs; - __u16 pad; - __kernel_ulong_t totalhigh; - __kernel_ulong_t freehigh; - __u32 mem_unit; - char _f[0]; -}; - -struct rlimit64 { - __u64 rlim_cur; - __u64 rlim_max; -}; - -enum uts_proc { - UTS_PROC_OSTYPE = 0, - UTS_PROC_OSRELEASE = 1, - UTS_PROC_VERSION = 2, - UTS_PROC_HOSTNAME = 3, - UTS_PROC_DOMAINNAME = 4, -}; - -struct prctl_mm_map { - __u64 start_code; - __u64 end_code; - __u64 start_data; - __u64 end_data; - __u64 start_brk; - __u64 brk; - __u64 start_stack; - __u64 arg_start; - __u64 arg_end; - __u64 env_start; - __u64 env_end; - __u64 *auxv; - __u32 auxv_size; - __u32 exe_fd; -}; - -struct compat_tms { - compat_clock_t tms_utime; - compat_clock_t tms_stime; - compat_clock_t tms_cutime; - compat_clock_t tms_cstime; -}; - -struct compat_rlimit { - compat_ulong_t rlim_cur; - compat_ulong_t rlim_max; -}; - -struct tms { - __kernel_clock_t tms_utime; - __kernel_clock_t tms_stime; - __kernel_clock_t tms_cutime; - __kernel_clock_t tms_cstime; -}; - -struct getcpu_cache { - long unsigned int blob[16]; -}; - -struct compat_sysinfo { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - u16 procs; - u16 pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[8]; -}; - -struct wq_flusher; - -struct worker; - -struct workqueue_attrs; - -struct pool_workqueue; - -struct wq_device; - -struct workqueue_struct { - struct list_head pwqs; - struct list_head list; - struct mutex mutex; - int work_color; - int flush_color; - atomic_t nr_pwqs_to_flush; - struct wq_flusher *first_flusher; - struct list_head flusher_queue; - struct list_head flusher_overflow; - struct list_head maydays; - struct worker *rescuer; - int nr_drainers; - int saved_max_active; - struct workqueue_attrs *unbound_attrs; - struct pool_workqueue *dfl_pwq; - struct wq_device *wq_dev; - char name[24]; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - unsigned int flags; - struct pool_workqueue *cpu_pwqs; - struct pool_workqueue *numa_pwq_tbl[0]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct workqueue_attrs { - int nice; - cpumask_var_t cpumask; - bool no_numa; -}; - -struct execute_work { - struct work_struct work; -}; - -enum { - WQ_UNBOUND = 2, - WQ_FREEZABLE = 4, - WQ_MEM_RECLAIM = 8, - WQ_HIGHPRI = 16, - WQ_CPU_INTENSIVE = 32, - WQ_SYSFS = 64, - WQ_POWER_EFFICIENT = 128, - __WQ_DRAINING = 65536, - __WQ_ORDERED = 131072, - __WQ_LEGACY = 262144, - __WQ_ORDERED_EXPLICIT = 524288, - WQ_MAX_ACTIVE = 512, - WQ_MAX_UNBOUND_PER_CPU = 4, - WQ_DFL_ACTIVE = 256, -}; - -typedef unsigned int xa_mark_t; - -enum xa_lock_type { - XA_LOCK_IRQ = 1, - XA_LOCK_BH = 2, -}; - -struct ida { - struct xarray xa; -}; - -struct __una_u32 { - u32 x; -}; - -enum hk_flags { - HK_FLAG_TIMER = 1, - HK_FLAG_RCU = 2, - HK_FLAG_MISC = 4, - HK_FLAG_SCHED = 8, - HK_FLAG_TICK = 16, - HK_FLAG_DOMAIN = 32, - HK_FLAG_WQ = 64, - HK_FLAG_MANAGED_IRQ = 128, - HK_FLAG_KTHREAD = 256, -}; - -struct worker_pool; - -struct worker { - union { - struct list_head entry; - struct hlist_node hentry; - }; - struct work_struct *current_work; - work_func_t current_func; - struct pool_workqueue *current_pwq; - struct list_head scheduled; - struct task_struct *task; - struct worker_pool *pool; - struct list_head node; - long unsigned int last_active; - unsigned int flags; - int id; - int sleeping; - char desc[24]; - struct workqueue_struct *rescue_wq; - work_func_t last_func; -}; - -struct pool_workqueue { - struct worker_pool *pool; - struct workqueue_struct *wq; - int work_color; - int flush_color; - int refcnt; - int nr_in_flight[15]; - int nr_active; - int max_active; - struct list_head delayed_works; - struct list_head pwqs_node; - struct list_head mayday_node; - struct work_struct unbound_release_work; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct worker_pool { - raw_spinlock_t lock; - int cpu; - int node; - int id; - unsigned int flags; - long unsigned int watchdog_ts; - struct list_head worklist; - int nr_workers; - int nr_idle; - struct list_head idle_list; - struct timer_list idle_timer; - struct timer_list mayday_timer; - struct hlist_head busy_hash[64]; - struct worker *manager; - struct list_head workers; - struct completion *detach_completion; - struct ida worker_ida; - struct workqueue_attrs *attrs; - struct hlist_node hash_node; - int refcnt; - long: 32; - long: 64; - long: 64; - long: 64; - atomic_t nr_running; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum { - POOL_MANAGER_ACTIVE = 1, - POOL_DISASSOCIATED = 4, - WORKER_DIE = 2, - WORKER_IDLE = 4, - WORKER_PREP = 8, - WORKER_CPU_INTENSIVE = 64, - WORKER_UNBOUND = 128, - WORKER_REBOUND = 256, - WORKER_NOT_RUNNING = 456, - NR_STD_WORKER_POOLS = 2, - UNBOUND_POOL_HASH_ORDER = 6, - BUSY_WORKER_HASH_ORDER = 6, - MAX_IDLE_WORKERS_RATIO = 4, - IDLE_WORKER_TIMEOUT = 75000, - MAYDAY_INITIAL_TIMEOUT = 2, - MAYDAY_INTERVAL = 25, - CREATE_COOLDOWN = 250, - RESCUER_NICE_LEVEL = 4294967276, - HIGHPRI_NICE_LEVEL = 4294967276, - WQ_NAME_LEN = 24, -}; - -struct wq_flusher { - struct list_head list; - int flush_color; - struct completion done; -}; - -struct wq_device { - struct workqueue_struct *wq; - struct device dev; -}; - -struct trace_event_raw_workqueue_queue_work { - struct trace_entry ent; - void *work; - void *function; - void *workqueue; - unsigned int req_cpu; - unsigned int cpu; - char __data[0]; -}; - -struct trace_event_raw_workqueue_activate_work { - struct trace_entry ent; - void *work; - char __data[0]; -}; - -struct trace_event_raw_workqueue_execute_start { - struct trace_entry ent; - void *work; - void *function; - char __data[0]; -}; - -struct trace_event_raw_workqueue_execute_end { - struct trace_entry ent; - void *work; - void *function; - char __data[0]; -}; - -struct trace_event_data_offsets_workqueue_queue_work {}; - -struct trace_event_data_offsets_workqueue_activate_work {}; - -struct trace_event_data_offsets_workqueue_execute_start {}; - -struct trace_event_data_offsets_workqueue_execute_end {}; - -typedef void (*btf_trace_workqueue_queue_work)(void *, unsigned int, struct pool_workqueue *, struct work_struct *); - -typedef void (*btf_trace_workqueue_activate_work)(void *, struct work_struct *); - -typedef void (*btf_trace_workqueue_execute_start)(void *, struct work_struct *); - -typedef void (*btf_trace_workqueue_execute_end)(void *, struct work_struct *, work_func_t); - -struct wq_barrier { - struct work_struct work; - struct completion done; - struct task_struct *task; -}; - -struct cwt_wait { - wait_queue_entry_t wait; - struct work_struct *work; -}; - -struct apply_wqattrs_ctx { - struct workqueue_struct *wq; - struct workqueue_attrs *attrs; - struct list_head list; - struct pool_workqueue *dfl_pwq; - struct pool_workqueue *pwq_tbl[0]; -}; - -struct work_for_cpu { - struct work_struct work; - long int (*fn)(void *); - void *arg; - long int ret; -}; - -typedef struct {} local_lock_t; - -struct radix_tree_preload { - local_lock_t lock; - unsigned int nr; - struct xa_node *nodes; -}; - -typedef void (*task_work_func_t)(struct callback_head *); - -enum task_work_notify_mode { - TWA_NONE = 0, - TWA_RESUME = 1, - TWA_SIGNAL = 2, -}; - -enum { - KERNEL_PARAM_OPS_FL_NOARG = 1, -}; - -enum { - KERNEL_PARAM_FL_UNSAFE = 1, - KERNEL_PARAM_FL_HWPARAM = 2, -}; - -struct param_attribute { - struct module_attribute mattr; - const struct kernel_param *param; -}; - -struct module_param_attrs { - unsigned int num; - struct attribute_group grp; - struct param_attribute attrs[0]; -}; - -struct module_version_attribute { - struct module_attribute mattr; - const char *module_name; - const char *version; -}; - -enum lockdown_reason { - LOCKDOWN_NONE = 0, - LOCKDOWN_MODULE_SIGNATURE = 1, - LOCKDOWN_DEV_MEM = 2, - LOCKDOWN_EFI_TEST = 3, - LOCKDOWN_KEXEC = 4, - LOCKDOWN_HIBERNATION = 5, - LOCKDOWN_PCI_ACCESS = 6, - LOCKDOWN_IOPORT = 7, - LOCKDOWN_MSR = 8, - LOCKDOWN_ACPI_TABLES = 9, - LOCKDOWN_PCMCIA_CIS = 10, - LOCKDOWN_TIOCSSERIAL = 11, - LOCKDOWN_MODULE_PARAMETERS = 12, - LOCKDOWN_MMIOTRACE = 13, - LOCKDOWN_DEBUGFS = 14, - LOCKDOWN_XMON_WR = 15, - LOCKDOWN_BPF_WRITE_USER = 16, - LOCKDOWN_INTEGRITY_MAX = 17, - LOCKDOWN_KCORE = 18, - LOCKDOWN_KPROBES = 19, - LOCKDOWN_BPF_READ = 20, - LOCKDOWN_PERF = 21, - LOCKDOWN_TRACEFS = 22, - LOCKDOWN_XMON_RW = 23, - LOCKDOWN_CONFIDENTIALITY_MAX = 24, -}; - -struct kmalloced_param { - struct list_head list; - char val[0]; -}; - -struct sched_param { - int sched_priority; -}; - -enum { - __PERCPU_REF_ATOMIC = 1, - __PERCPU_REF_DEAD = 2, - __PERCPU_REF_ATOMIC_DEAD = 3, - __PERCPU_REF_FLAG_BITS = 2, -}; - -struct kthread_work; - -typedef void (*kthread_work_func_t)(struct kthread_work *); - -struct kthread_worker; - -struct kthread_work { - struct list_head node; - kthread_work_func_t func; - struct kthread_worker *worker; - int canceling; -}; - -enum { - KTW_FREEZABLE = 1, -}; - -struct kthread_worker { - unsigned int flags; - raw_spinlock_t lock; - struct list_head work_list; - struct list_head delayed_work_list; - struct task_struct *task; - struct kthread_work *current_work; -}; - -struct kthread_delayed_work { - struct kthread_work work; - struct timer_list timer; -}; - -enum { - CSS_NO_REF = 1, - CSS_ONLINE = 2, - CSS_RELEASED = 4, - CSS_VISIBLE = 8, - CSS_DYING = 16, -}; - -struct kthread_create_info { - int (*threadfn)(void *); - void *data; - int node; - struct task_struct *result; - struct completion *done; - struct list_head list; -}; - -struct kthread { - long unsigned int flags; - unsigned int cpu; - int (*threadfn)(void *); - void *data; - mm_segment_t oldfs; - struct completion parked; - struct completion exited; - struct cgroup_subsys_state *blkcg_css; -}; - -enum KTHREAD_BITS { - KTHREAD_IS_PER_CPU = 0, - KTHREAD_SHOULD_STOP = 1, - KTHREAD_SHOULD_PARK = 2, -}; - -struct kthread_flush_work { - struct kthread_work work; - struct completion done; -}; - -struct pt_regs___2; - -struct ipc_ids { - int in_use; - short unsigned int seq; - struct rw_semaphore rwsem; - struct idr ipcs_idr; - int max_idx; - int last_idx; - struct rhashtable key_ht; -}; - -struct ipc_namespace { - refcount_t count; - struct ipc_ids ids[3]; - int sem_ctls[4]; - int used_sems; - unsigned int msg_ctlmax; - unsigned int msg_ctlmnb; - unsigned int msg_ctlmni; - atomic_t msg_bytes; - atomic_t msg_hdrs; - size_t shm_ctlmax; - size_t shm_ctlall; - long unsigned int shm_tot; - int shm_ctlmni; - int shm_rmid_forced; - struct notifier_block ipcns_nb; - struct vfsmount *mq_mnt; - unsigned int mq_queues_count; - unsigned int mq_queues_max; - unsigned int mq_msg_max; - unsigned int mq_msgsize_max; - unsigned int mq_msg_default; - unsigned int mq_msgsize_default; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct llist_node mnt_llist; - struct ns_common ns; -}; - -struct srcu_notifier_head { - struct mutex mutex; - struct srcu_struct srcu; - struct notifier_block *head; -}; - -enum what { - PROC_EVENT_NONE = 0, - PROC_EVENT_FORK = 1, - PROC_EVENT_EXEC = 2, - PROC_EVENT_UID = 4, - PROC_EVENT_GID = 64, - PROC_EVENT_SID = 128, - PROC_EVENT_PTRACE = 256, - PROC_EVENT_COMM = 512, - PROC_EVENT_COREDUMP = 1073741824, - PROC_EVENT_EXIT = 2147483648, -}; - -enum reboot_type { - BOOT_TRIPLE = 116, - BOOT_KBD = 107, - BOOT_BIOS = 98, - BOOT_ACPI = 97, - BOOT_EFI = 101, - BOOT_CF9_FORCE = 112, - BOOT_CF9_SAFE = 113, -}; - -typedef u64 async_cookie_t; - -typedef void (*async_func_t)(void *, async_cookie_t); - -struct async_domain { - struct list_head pending; - unsigned int registered: 1; -}; - -struct async_entry { - struct list_head domain_list; - struct list_head global_list; - struct work_struct work; - async_cookie_t cookie; - async_func_t func; - void *data; - struct async_domain *domain; -}; - -struct smpboot_thread_data { - unsigned int cpu; - unsigned int status; - struct smp_hotplug_thread *ht; -}; - -enum { - HP_THREAD_NONE = 0, - HP_THREAD_ACTIVE = 1, - HP_THREAD_PARKED = 2, -}; - -typedef u64 uint64_t; - -struct pin_cookie {}; - -enum { - CSD_FLAG_LOCK = 1, - IRQ_WORK_PENDING = 1, - IRQ_WORK_BUSY = 2, - IRQ_WORK_LAZY = 4, - IRQ_WORK_HARD_IRQ = 8, - IRQ_WORK_CLAIMED = 3, - CSD_TYPE_ASYNC = 0, - CSD_TYPE_SYNC = 16, - CSD_TYPE_IRQ_WORK = 32, - CSD_TYPE_TTWU = 48, - CSD_FLAG_TYPE_MASK = 240, -}; - -typedef struct __call_single_data call_single_data_t; - -struct dl_bw { - raw_spinlock_t lock; - u64 bw; - u64 total_bw; -}; - -struct cpudl_item; - -struct cpudl { - raw_spinlock_t lock; - int size; - cpumask_var_t free_cpus; - struct cpudl_item *elements; -}; - -struct cpupri_vec { - atomic_t count; - cpumask_var_t mask; -}; - -struct cpupri { - struct cpupri_vec pri_to_cpu[102]; - int *cpu_to_pri; -}; - -struct perf_domain; - -struct root_domain { - atomic_t refcount; - atomic_t rto_count; - struct callback_head rcu; - cpumask_var_t span; - cpumask_var_t online; - int overload; - int overutilized; - cpumask_var_t dlo_mask; - atomic_t dlo_count; - struct dl_bw dl_bw; - struct cpudl cpudl; - struct irq_work rto_push_work; - raw_spinlock_t rto_lock; - int rto_loop; - int rto_cpu; - atomic_t rto_loop_next; - atomic_t rto_loop_start; - cpumask_var_t rto_mask; - struct cpupri cpupri; - long unsigned int max_cpu_capacity; - struct perf_domain *pd; -}; - -struct cfs_rq { - struct load_weight load; - unsigned int nr_running; - unsigned int h_nr_running; - unsigned int idle_h_nr_running; - u64 exec_clock; - u64 min_vruntime; - struct rb_root_cached tasks_timeline; - struct sched_entity *curr; - struct sched_entity *next; - struct sched_entity *last; - struct sched_entity *skip; - unsigned int nr_spread_over; - long: 32; - long: 64; - long: 64; - long: 64; - struct sched_avg avg; - struct { - raw_spinlock_t lock; - int nr; - long unsigned int load_avg; - long unsigned int util_avg; - long unsigned int runnable_avg; - long: 64; - long: 64; - long: 64; - long: 64; - } removed; - long unsigned int tg_load_avg_contrib; - long int propagate; - long int prop_runnable_sum; - long unsigned int h_load; - u64 last_h_load_update; - struct sched_entity *h_load_next; - struct rq *rq; - int on_list; - struct list_head leaf_cfs_rq_list; - struct task_group *tg; - int runtime_enabled; - s64 runtime_remaining; - u64 throttled_clock; - u64 throttled_clock_task; - u64 throttled_clock_task_time; - int throttled; - int throttle_count; - struct list_head throttled_list; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct cfs_bandwidth { - raw_spinlock_t lock; - ktime_t period; - u64 quota; - u64 runtime; - s64 hierarchical_quota; - u8 idle; - u8 period_active; - u8 slack_started; - struct hrtimer period_timer; - struct hrtimer slack_timer; - struct list_head throttled_cfs_rq; - int nr_periods; - int nr_throttled; - u64 throttled_time; -}; - -struct task_group { - struct cgroup_subsys_state css; - struct sched_entity **se; - struct cfs_rq **cfs_rq; - long unsigned int shares; - long: 64; - long: 64; - long: 64; - long: 64; - atomic_long_t load_avg; - struct callback_head rcu; - struct list_head list; - struct task_group *parent; - struct list_head siblings; - struct list_head children; - struct autogroup *autogroup; - struct cfs_bandwidth cfs_bandwidth; - long: 64; - long: 64; - long: 64; -}; - -enum { - SD_BALANCE_NEWIDLE = 1, - SD_BALANCE_EXEC = 2, - SD_BALANCE_FORK = 4, - SD_BALANCE_WAKE = 8, - SD_WAKE_AFFINE = 16, - SD_ASYM_CPUCAPACITY = 32, - SD_SHARE_CPUCAPACITY = 64, - SD_SHARE_PKG_RESOURCES = 128, - SD_SERIALIZE = 256, - SD_ASYM_PACKING = 512, - SD_PREFER_SIBLING = 1024, - SD_OVERLAP = 2048, - SD_NUMA = 4096, -}; - -struct sched_domain_shared { - atomic_t ref; - atomic_t nr_busy_cpus; - int has_idle_cores; -}; - -struct sched_group; - -struct sched_domain { - struct sched_domain *parent; - struct sched_domain *child; - struct sched_group *groups; - long unsigned int min_interval; - long unsigned int max_interval; - unsigned int busy_factor; - unsigned int imbalance_pct; - unsigned int cache_nice_tries; - int nohz_idle; - int flags; - int level; - long unsigned int last_balance; - unsigned int balance_interval; - unsigned int nr_balance_failed; - u64 max_newidle_lb_cost; - long unsigned int next_decay_max_lb_cost; - u64 avg_scan_cost; - unsigned int lb_count[3]; - unsigned int lb_failed[3]; - unsigned int lb_balanced[3]; - unsigned int lb_imbalance[3]; - unsigned int lb_gained[3]; - unsigned int lb_hot_gained[3]; - unsigned int lb_nobusyg[3]; - unsigned int lb_nobusyq[3]; - unsigned int alb_count; - unsigned int alb_failed; - unsigned int alb_pushed; - unsigned int sbe_count; - unsigned int sbe_balanced; - unsigned int sbe_pushed; - unsigned int sbf_count; - unsigned int sbf_balanced; - unsigned int sbf_pushed; - unsigned int ttwu_wake_remote; - unsigned int ttwu_move_affine; - unsigned int ttwu_move_balance; - char *name; - union { - void *private; - struct callback_head rcu; - }; - struct sched_domain_shared *shared; - unsigned int span_weight; - long unsigned int span[0]; -}; - -struct sched_group_capacity; - -struct sched_group { - struct sched_group *next; - atomic_t ref; - unsigned int group_weight; - struct sched_group_capacity *sgc; - int asym_prefer_cpu; - long unsigned int cpumask[0]; -}; - -struct sched_group_capacity { - atomic_t ref; - long unsigned int capacity; - long unsigned int min_capacity; - long unsigned int max_capacity; - long unsigned int next_update; - int imbalance; - int id; - long unsigned int cpumask[0]; -}; - -struct em_perf_state { - long unsigned int frequency; - long unsigned int power; - long unsigned int cost; -}; - -struct em_perf_domain { - struct em_perf_state *table; - int nr_perf_states; - long unsigned int cpus[0]; -}; - -struct autogroup { - struct kref kref; - struct task_group *tg; - struct rw_semaphore lock; - long unsigned int id; - int nice; -}; - -struct kernel_cpustat { - u64 cpustat[10]; -}; - -enum { - CFTYPE_ONLY_ON_ROOT = 1, - CFTYPE_NOT_ON_ROOT = 2, - CFTYPE_NS_DELEGATABLE = 4, - CFTYPE_NO_PREFIX = 8, - CFTYPE_WORLD_WRITABLE = 16, - CFTYPE_DEBUG = 32, - __CFTYPE_ONLY_ON_DFL = 65536, - __CFTYPE_NOT_ON_DFL = 131072, -}; - -struct trace_event_raw_sched_kthread_stop { - struct trace_entry ent; - char comm[16]; - pid_t pid; - char __data[0]; -}; - -struct trace_event_raw_sched_kthread_stop_ret { - struct trace_entry ent; - int ret; - char __data[0]; -}; - -struct trace_event_raw_sched_wakeup_template { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - int success; - int target_cpu; - char __data[0]; -}; - -struct trace_event_raw_sched_switch { - struct trace_entry ent; - char prev_comm[16]; - pid_t prev_pid; - int prev_prio; - long int prev_state; - char next_comm[16]; - pid_t next_pid; - int next_prio; - char __data[0]; -}; - -struct trace_event_raw_sched_migrate_task { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - int orig_cpu; - int dest_cpu; - char __data[0]; -}; - -struct trace_event_raw_sched_process_template { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - char __data[0]; -}; - -struct trace_event_raw_sched_process_wait { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - char __data[0]; -}; - -struct trace_event_raw_sched_process_fork { - struct trace_entry ent; - char parent_comm[16]; - pid_t parent_pid; - char child_comm[16]; - pid_t child_pid; - char __data[0]; -}; - -struct trace_event_raw_sched_process_exec { - struct trace_entry ent; - u32 __data_loc_filename; - pid_t pid; - pid_t old_pid; - char __data[0]; -}; - -struct trace_event_raw_sched_stat_template { - struct trace_entry ent; - char comm[16]; - pid_t pid; - u64 delay; - char __data[0]; -}; - -struct trace_event_raw_sched_stat_runtime { - struct trace_entry ent; - char comm[16]; - pid_t pid; - u64 runtime; - u64 vruntime; - char __data[0]; -}; - -struct trace_event_raw_sched_pi_setprio { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int oldprio; - int newprio; - char __data[0]; -}; - -struct trace_event_raw_sched_process_hang { - struct trace_entry ent; - char comm[16]; - pid_t pid; - char __data[0]; -}; - -struct trace_event_raw_sched_move_numa { - struct trace_entry ent; - pid_t pid; - pid_t tgid; - pid_t ngid; - int src_cpu; - int src_nid; - int dst_cpu; - int dst_nid; - char __data[0]; -}; - -struct trace_event_raw_sched_numa_pair_template { - struct trace_entry ent; - pid_t src_pid; - pid_t src_tgid; - pid_t src_ngid; - int src_cpu; - int src_nid; - pid_t dst_pid; - pid_t dst_tgid; - pid_t dst_ngid; - int dst_cpu; - int dst_nid; - char __data[0]; -}; - -struct trace_event_raw_sched_wake_idle_without_ipi { - struct trace_entry ent; - int cpu; - char __data[0]; -}; - -struct trace_event_data_offsets_sched_kthread_stop {}; - -struct trace_event_data_offsets_sched_kthread_stop_ret {}; - -struct trace_event_data_offsets_sched_wakeup_template {}; - -struct trace_event_data_offsets_sched_switch {}; - -struct trace_event_data_offsets_sched_migrate_task {}; - -struct trace_event_data_offsets_sched_process_template {}; - -struct trace_event_data_offsets_sched_process_wait {}; - -struct trace_event_data_offsets_sched_process_fork {}; - -struct trace_event_data_offsets_sched_process_exec { - u32 filename; -}; - -struct trace_event_data_offsets_sched_stat_template {}; - -struct trace_event_data_offsets_sched_stat_runtime {}; - -struct trace_event_data_offsets_sched_pi_setprio {}; - -struct trace_event_data_offsets_sched_process_hang {}; - -struct trace_event_data_offsets_sched_move_numa {}; - -struct trace_event_data_offsets_sched_numa_pair_template {}; - -struct trace_event_data_offsets_sched_wake_idle_without_ipi {}; - -typedef void (*btf_trace_sched_kthread_stop)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_kthread_stop_ret)(void *, int); - -typedef void (*btf_trace_sched_waking)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_wakeup)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_wakeup_new)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_switch)(void *, bool, struct task_struct *, struct task_struct *); - -typedef void (*btf_trace_sched_migrate_task)(void *, struct task_struct *, int); - -typedef void (*btf_trace_sched_process_free)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_process_exit)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_wait_task)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_process_wait)(void *, struct pid *); - -typedef void (*btf_trace_sched_process_fork)(void *, struct task_struct *, struct task_struct *); - -typedef void (*btf_trace_sched_process_exec)(void *, struct task_struct *, pid_t, struct linux_binprm *); - -typedef void (*btf_trace_sched_stat_wait)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_sleep)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_iowait)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_blocked)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_runtime)(void *, struct task_struct *, u64, u64); - -typedef void (*btf_trace_sched_pi_setprio)(void *, struct task_struct *, struct task_struct *); - -typedef void (*btf_trace_sched_process_hang)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_move_numa)(void *, struct task_struct *, int, int); - -typedef void (*btf_trace_sched_stick_numa)(void *, struct task_struct *, int, struct task_struct *, int); - -typedef void (*btf_trace_sched_swap_numa)(void *, struct task_struct *, int, struct task_struct *, int); - -typedef void (*btf_trace_sched_wake_idle_without_ipi)(void *, int); - -enum { - MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY = 1, - MEMBARRIER_STATE_PRIVATE_EXPEDITED = 2, - MEMBARRIER_STATE_GLOBAL_EXPEDITED_READY = 4, - MEMBARRIER_STATE_GLOBAL_EXPEDITED = 8, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY = 16, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE = 32, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ_READY = 64, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ = 128, -}; - -struct wake_q_head { - struct wake_q_node *first; - struct wake_q_node **lastp; -}; - -struct sched_attr { - __u32 size; - __u32 sched_policy; - __u64 sched_flags; - __s32 sched_nice; - __u32 sched_priority; - __u64 sched_runtime; - __u64 sched_deadline; - __u64 sched_period; - __u32 sched_util_min; - __u32 sched_util_max; -}; - -struct cpuidle_state_usage { - long long unsigned int disable; - long long unsigned int usage; - u64 time_ns; - long long unsigned int above; - long long unsigned int below; - long long unsigned int rejected; -}; - -struct cpuidle_device; - -struct cpuidle_driver; - -struct cpuidle_state { - char name[16]; - char desc[32]; - u64 exit_latency_ns; - u64 target_residency_ns; - unsigned int flags; - unsigned int exit_latency; - int power_usage; - unsigned int target_residency; - int (*enter)(struct cpuidle_device *, struct cpuidle_driver *, int); - int (*enter_dead)(struct cpuidle_device *, int); - int (*enter_s2idle)(struct cpuidle_device *, struct cpuidle_driver *, int); -}; - -struct cpuidle_state_kobj; - -struct cpuidle_driver_kobj; - -struct cpuidle_device_kobj; - -struct cpuidle_device { - unsigned int registered: 1; - unsigned int enabled: 1; - unsigned int poll_time_limit: 1; - unsigned int cpu; - ktime_t next_hrtimer; - int last_state_idx; - u64 last_residency_ns; - u64 poll_limit_ns; - u64 forced_idle_latency_limit_ns; - struct cpuidle_state_usage states_usage[10]; - struct cpuidle_state_kobj *kobjs[10]; - struct cpuidle_driver_kobj *kobj_driver; - struct cpuidle_device_kobj *kobj_dev; - struct list_head device_list; -}; - -struct cpuidle_driver { - const char *name; - struct module *owner; - unsigned int bctimer: 1; - struct cpuidle_state states[10]; - int state_count; - int safe_state_index; - struct cpumask *cpumask; - const char *governor; -}; - -typedef int (*cpu_stop_fn_t)(void *); - -struct cpu_stop_done; - -struct cpu_stop_work { - struct list_head list; - cpu_stop_fn_t fn; - void *arg; - struct cpu_stop_done *done; -}; - -struct cpudl_item { - u64 dl; - int cpu; - int idx; -}; - -struct rt_prio_array { - long unsigned int bitmap[2]; - struct list_head queue[100]; -}; - -struct rt_bandwidth { - raw_spinlock_t rt_runtime_lock; - ktime_t rt_period; - u64 rt_runtime; - struct hrtimer rt_period_timer; - unsigned int rt_period_active; -}; - -struct dl_bandwidth { - raw_spinlock_t dl_runtime_lock; - u64 dl_runtime; - u64 dl_period; -}; - -typedef int (*tg_visitor)(struct task_group *, void *); - -struct rt_rq { - struct rt_prio_array active; - unsigned int rt_nr_running; - unsigned int rr_nr_running; - struct { - int curr; - int next; - } highest_prio; - long unsigned int rt_nr_migratory; - long unsigned int rt_nr_total; - int overloaded; - struct plist_head pushable_tasks; - int rt_queued; - int rt_throttled; - u64 rt_time; - u64 rt_runtime; - raw_spinlock_t rt_runtime_lock; -}; - -struct dl_rq { - struct rb_root_cached root; - long unsigned int dl_nr_running; - struct { - u64 curr; - u64 next; - } earliest_dl; - long unsigned int dl_nr_migratory; - int overloaded; - struct rb_root_cached pushable_dl_tasks_root; - u64 running_bw; - u64 this_bw; - u64 extra_bw; - u64 bw_ratio; -}; - -struct rq { - raw_spinlock_t lock; - unsigned int nr_running; - long unsigned int last_blocked_load_update_tick; - unsigned int has_blocked_load; - long: 32; - long: 64; - call_single_data_t nohz_csd; - unsigned int nohz_tick_stopped; - atomic_t nohz_flags; - unsigned int ttwu_pending; - u64 nr_switches; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct cfs_rq cfs; - struct rt_rq rt; - struct dl_rq dl; - struct list_head leaf_cfs_rq_list; - struct list_head *tmp_alone_branch; - long unsigned int nr_uninterruptible; - struct task_struct *curr; - struct task_struct *idle; - struct task_struct *stop; - long unsigned int next_balance; - struct mm_struct *prev_mm; - unsigned int clock_update_flags; - u64 clock; - long: 64; - long: 64; - long: 64; - u64 clock_task; - u64 clock_pelt; - long unsigned int lost_idle_time; - atomic_t nr_iowait; - int membarrier_state; - struct root_domain *rd; - struct sched_domain *sd; - long unsigned int cpu_capacity; - long unsigned int cpu_capacity_orig; - struct callback_head *balance_callback; - unsigned char nohz_idle_balance; - unsigned char idle_balance; - long unsigned int misfit_task_load; - int active_balance; - int push_cpu; - struct cpu_stop_work active_balance_work; - int cpu; - int online; - struct list_head cfs_tasks; - long: 64; - long: 64; - long: 64; - long: 64; - struct sched_avg avg_rt; - struct sched_avg avg_dl; - u64 idle_stamp; - u64 avg_idle; - u64 max_idle_balance_cost; - long unsigned int calc_load_update; - long int calc_load_active; - long: 64; - long: 64; - long: 64; - call_single_data_t hrtick_csd; - struct hrtimer hrtick_timer; - ktime_t hrtick_time; - struct sched_info rq_sched_info; - long long unsigned int rq_cpu_time; - unsigned int yld_count; - unsigned int sched_count; - unsigned int sched_goidle; - unsigned int ttwu_count; - unsigned int ttwu_local; - struct cpuidle_state *idle_state; - long: 64; - long: 64; -}; - -struct perf_domain { - struct em_perf_domain *em_pd; - struct perf_domain *next; - struct callback_head rcu; -}; - -struct rq_flags { - long unsigned int flags; - struct pin_cookie cookie; - unsigned int clock_update_flags; -}; - -enum { - __SCHED_FEAT_GENTLE_FAIR_SLEEPERS = 0, - __SCHED_FEAT_START_DEBIT = 1, - __SCHED_FEAT_NEXT_BUDDY = 2, - __SCHED_FEAT_LAST_BUDDY = 3, - __SCHED_FEAT_CACHE_HOT_BUDDY = 4, - __SCHED_FEAT_WAKEUP_PREEMPTION = 5, - __SCHED_FEAT_HRTICK = 6, - __SCHED_FEAT_DOUBLE_TICK = 7, - __SCHED_FEAT_NONTASK_CAPACITY = 8, - __SCHED_FEAT_TTWU_QUEUE = 9, - __SCHED_FEAT_SIS_AVG_CPU = 10, - __SCHED_FEAT_SIS_PROP = 11, - __SCHED_FEAT_WARN_DOUBLE_CLOCK = 12, - __SCHED_FEAT_RT_PUSH_IPI = 13, - __SCHED_FEAT_RT_RUNTIME_SHARE = 14, - __SCHED_FEAT_LB_MIN = 15, - __SCHED_FEAT_ATTACH_AGE_LOAD = 16, - __SCHED_FEAT_WA_IDLE = 17, - __SCHED_FEAT_WA_WEIGHT = 18, - __SCHED_FEAT_WA_BIAS = 19, - __SCHED_FEAT_UTIL_EST = 20, - __SCHED_FEAT_UTIL_EST_FASTUP = 21, - __SCHED_FEAT_ALT_PERIOD = 22, - __SCHED_FEAT_BASE_SLICE = 23, - __SCHED_FEAT_NR = 24, -}; - -struct migration_arg { - struct task_struct *task; - int dest_cpu; -}; - -struct cfs_schedulable_data { - struct task_group *tg; - u64 period; - u64 quota; -}; - -enum { - cpuset = 0, - possible = 1, - fail = 2, -}; - -struct idle_timer { - struct hrtimer timer; - int done; -}; - -struct update_util_data { - void (*func)(struct update_util_data *, u64, unsigned int); -}; - -enum schedutil_type { - FREQUENCY_UTIL = 0, - ENERGY_UTIL = 1, -}; - -enum fbq_type { - regular = 0, - remote = 1, - all = 2, -}; - -enum group_type { - group_has_spare = 0, - group_fully_busy = 1, - group_misfit_task = 2, - group_asym_packing = 3, - group_imbalanced = 4, - group_overloaded = 5, -}; - -enum migration_type { - migrate_load = 0, - migrate_util = 1, - migrate_task = 2, - migrate_misfit = 3, -}; - -struct lb_env { - struct sched_domain *sd; - struct rq *src_rq; - int src_cpu; - int dst_cpu; - struct rq *dst_rq; - struct cpumask *dst_grpmask; - int new_dst_cpu; - enum cpu_idle_type idle; - long int imbalance; - struct cpumask *cpus; - unsigned int flags; - unsigned int loop; - unsigned int loop_break; - unsigned int loop_max; - enum fbq_type fbq_type; - enum migration_type migration_type; - struct list_head tasks; -}; - -struct sg_lb_stats { - long unsigned int avg_load; - long unsigned int group_load; - long unsigned int group_capacity; - long unsigned int group_util; - long unsigned int group_runnable; - unsigned int sum_nr_running; - unsigned int sum_h_nr_running; - unsigned int idle_cpus; - unsigned int group_weight; - enum group_type group_type; - unsigned int group_asym_packing; - long unsigned int group_misfit_task_load; -}; - -struct sd_lb_stats { - struct sched_group *busiest; - struct sched_group *local; - long unsigned int total_load; - long unsigned int total_capacity; - long unsigned int avg_load; - unsigned int prefer_sibling; - struct sg_lb_stats busiest_stat; - struct sg_lb_stats local_stat; -}; - -typedef struct rt_rq *rt_rq_iter_t; - -struct wait_bit_key { - void *flags; - int bit_nr; - long unsigned int timeout; -}; - -struct wait_bit_queue_entry { - struct wait_bit_key key; - struct wait_queue_entry wq_entry; -}; - -typedef int wait_bit_action_f(struct wait_bit_key *, int); - -struct swait_queue { - struct task_struct *task; - struct list_head task_list; -}; - -struct sd_flag_debug { - unsigned int meta_flags; - char *name; -}; - -struct sched_domain_attr { - int relax_domain_level; -}; - -typedef const struct cpumask * (*sched_domain_mask_f)(int); - -typedef int (*sched_domain_flags_f)(); - -struct sd_data { - struct sched_domain **sd; - struct sched_domain_shared **sds; - struct sched_group **sg; - struct sched_group_capacity **sgc; -}; - -struct sched_domain_topology_level { - sched_domain_mask_f mask; - sched_domain_flags_f sd_flags; - int flags; - int numa_level; - struct sd_data data; - char *name; -}; - -struct s_data { - struct sched_domain **sd; - struct root_domain *rd; -}; - -enum s_alloc { - sa_rootdomain = 0, - sa_sd = 1, - sa_sd_storage = 2, - sa_none = 3, -}; - -enum cpuacct_stat_index { - CPUACCT_STAT_USER = 0, - CPUACCT_STAT_SYSTEM = 1, - CPUACCT_STAT_NSTATS = 2, -}; - -struct cpuacct_usage { - u64 usages[2]; -}; - -struct cpuacct { - struct cgroup_subsys_state css; - struct cpuacct_usage *cpuusage; - struct kernel_cpustat *cpustat; -}; - -struct gov_attr_set { - struct kobject kobj; - struct list_head policy_list; - struct mutex update_lock; - int usage_count; -}; - -struct governor_attr { - struct attribute attr; - ssize_t (*show)(struct gov_attr_set *, char *); - ssize_t (*store)(struct gov_attr_set *, const char *, size_t); -}; - -struct sugov_tunables { - struct gov_attr_set attr_set; - unsigned int rate_limit_us; -}; - -struct sugov_policy { - struct cpufreq_policy *policy; - struct sugov_tunables *tunables; - struct list_head tunables_hook; - raw_spinlock_t update_lock; - u64 last_freq_update_time; - s64 freq_update_delay_ns; - unsigned int next_freq; - unsigned int cached_raw_freq; - struct irq_work irq_work; - struct kthread_work work; - struct mutex work_lock; - struct kthread_worker worker; - struct task_struct *thread; - bool work_in_progress; - bool limits_changed; - bool need_freq_update; -}; - -struct sugov_cpu { - struct update_util_data update_util; - struct sugov_policy *sg_policy; - unsigned int cpu; - bool iowait_boost_pending; - unsigned int iowait_boost; - u64 last_update; - long unsigned int bw_dl; - long unsigned int max; - long unsigned int saved_idle_calls; -}; - -enum { - MEMBARRIER_FLAG_SYNC_CORE = 1, - MEMBARRIER_FLAG_RSEQ = 2, -}; - -enum membarrier_cmd { - MEMBARRIER_CMD_QUERY = 0, - MEMBARRIER_CMD_GLOBAL = 1, - MEMBARRIER_CMD_GLOBAL_EXPEDITED = 2, - MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = 4, - MEMBARRIER_CMD_PRIVATE_EXPEDITED = 8, - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = 16, - MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = 32, - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = 64, - MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ = 128, - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ = 256, - MEMBARRIER_CMD_SHARED = 1, -}; - -enum membarrier_cmd_flag { - MEMBARRIER_CMD_FLAG_CPU = 1, -}; - -struct ww_acquire_ctx; - -struct ww_mutex { - struct mutex base; - struct ww_acquire_ctx *ctx; -}; - -struct ww_acquire_ctx { - struct task_struct *task; - long unsigned int stamp; - unsigned int acquired; - short unsigned int wounded; - short unsigned int is_wait_die; -}; - -struct mutex_waiter { - struct list_head list; - struct task_struct *task; - struct ww_acquire_ctx *ww_ctx; -}; - -enum mutex_trylock_recursive_enum { - MUTEX_TRYLOCK_FAILED = 0, - MUTEX_TRYLOCK_SUCCESS = 1, - MUTEX_TRYLOCK_RECURSIVE = 2, -}; - -struct semaphore { - raw_spinlock_t lock; - unsigned int count; - struct list_head wait_list; -}; - -struct semaphore_waiter { - struct list_head list; - struct task_struct *task; - bool up; -}; - -enum rwsem_waiter_type { - RWSEM_WAITING_FOR_WRITE = 0, - RWSEM_WAITING_FOR_READ = 1, -}; - -struct rwsem_waiter { - struct list_head list; - struct task_struct *task; - enum rwsem_waiter_type type; - long unsigned int timeout; - long unsigned int last_rowner; -}; - -enum rwsem_wake_type { - RWSEM_WAKE_ANY = 0, - RWSEM_WAKE_READERS = 1, - RWSEM_WAKE_READ_OWNED = 2, -}; - -enum writer_wait_state { - WRITER_NOT_FIRST = 0, - WRITER_FIRST = 1, - WRITER_HANDOFF = 2, -}; - -enum owner_state { - OWNER_NULL = 1, - OWNER_WRITER = 2, - OWNER_READER = 4, - OWNER_NONSPINNABLE = 8, -}; - -struct task_struct___2; - -struct optimistic_spin_node { - struct optimistic_spin_node *next; - struct optimistic_spin_node *prev; - int locked; - int cpu; -}; - -struct mcs_spinlock { - struct mcs_spinlock *next; - int locked; - int count; -}; - -struct qnode { - struct mcs_spinlock mcs; -}; - -struct hrtimer_sleeper { - struct hrtimer timer; - struct task_struct *task; -}; - -struct rt_mutex; - -struct rt_mutex_waiter { - struct rb_node tree_entry; - struct rb_node pi_tree_entry; - struct task_struct *task; - struct rt_mutex *lock; - int prio; - u64 deadline; -}; - -struct rt_mutex { - raw_spinlock_t wait_lock; - struct rb_root_cached waiters; - struct task_struct *owner; -}; - -enum rtmutex_chainwalk { - RT_MUTEX_MIN_CHAINWALK = 0, - RT_MUTEX_FULL_CHAINWALK = 1, -}; - -struct pm_qos_request { - struct plist_node node; - struct pm_qos_constraints *qos; -}; - -enum pm_qos_req_action { - PM_QOS_ADD_REQ = 0, - PM_QOS_UPDATE_REQ = 1, - PM_QOS_REMOVE_REQ = 2, -}; - -typedef int suspend_state_t; - -struct sysrq_key_op { - void (* const handler)(int); - const char * const help_msg; - const char * const action_msg; - const int enable_mask; -}; - -typedef unsigned int uint; - -struct dev_printk_info { - char subsystem[16]; - char device[48]; -}; - -struct console { - char name[16]; - void (*write)(struct console *, const char *, unsigned int); - int (*read)(struct console *, char *, unsigned int); - struct tty_driver * (*device)(struct console *, int *); - void (*unblank)(); - int (*setup)(struct console *, char *); - int (*exit)(struct console *); - int (*match)(struct console *, char *, int, char *); - short int flags; - short int index; - int cflag; - uint ispeed; - uint ospeed; - void *data; - struct console *next; -}; - -struct kmsg_dumper { - struct list_head list; - void (*dump)(struct kmsg_dumper *, enum kmsg_dump_reason); - enum kmsg_dump_reason max_reason; - bool active; - bool registered; - u32 cur_idx; - u32 next_idx; - u64 cur_seq; - u64 next_seq; -}; - -struct trace_event_raw_console { - struct trace_entry ent; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_data_offsets_console { - u32 msg; -}; - -typedef void (*btf_trace_console)(void *, const char *, size_t); - -struct printk_info { - u64 seq; - u64 ts_nsec; - u16 text_len; - u8 facility; - u8 flags: 5; - u8 level: 3; - u32 caller_id; - struct dev_printk_info dev_info; -}; - -struct printk_record { - struct printk_info *info; - char *text_buf; - unsigned int text_buf_size; -}; - -struct prb_data_blk_lpos { - long unsigned int begin; - long unsigned int next; -}; - -struct prb_desc { - atomic_long_t state_var; - struct prb_data_blk_lpos text_blk_lpos; -}; - -struct prb_data_ring { - unsigned int size_bits; - char *data; - atomic_long_t head_lpos; - atomic_long_t tail_lpos; -}; - -struct prb_desc_ring { - unsigned int count_bits; - struct prb_desc *descs; - struct printk_info *infos; - atomic_long_t head_id; - atomic_long_t tail_id; -}; - -struct printk_ringbuffer { - struct prb_desc_ring desc_ring; - struct prb_data_ring text_data_ring; - atomic_long_t fail; -}; - -struct prb_reserved_entry { - struct printk_ringbuffer *rb; - long unsigned int irqflags; - long unsigned int id; - unsigned int text_space; -}; - -enum desc_state { - desc_miss = 4294967295, - desc_reserved = 0, - desc_committed = 1, - desc_finalized = 2, - desc_reusable = 3, -}; - -struct console_cmdline { - char name[16]; - int index; - bool user_specified; - char *options; -}; - -enum devkmsg_log_bits { - __DEVKMSG_LOG_BIT_ON = 0, - __DEVKMSG_LOG_BIT_OFF = 1, - __DEVKMSG_LOG_BIT_LOCK = 2, -}; - -enum devkmsg_log_masks { - DEVKMSG_LOG_MASK_ON = 1, - DEVKMSG_LOG_MASK_OFF = 2, - DEVKMSG_LOG_MASK_LOCK = 4, -}; - -enum con_msg_format_flags { - MSG_FORMAT_DEFAULT = 0, - MSG_FORMAT_SYSLOG = 1, -}; - -enum log_flags { - LOG_NEWLINE = 2, - LOG_CONT = 8, -}; - -struct devkmsg_user { - u64 seq; - struct ratelimit_state rs; - struct mutex lock; - char buf[8192]; - struct printk_info info; - char text_buf[8192]; - struct printk_record record; -}; - -enum kdb_msgsrc { - KDB_MSGSRC_INTERNAL = 0, - KDB_MSGSRC_PRINTK = 1, -}; - -struct printk_safe_seq_buf { - atomic_t len; - atomic_t message_lost; - struct irq_work work; - unsigned char buffer[8160]; -}; - -struct prb_data_block { - long unsigned int id; - char data[0]; -}; - -enum { - IRQS_AUTODETECT = 1, - IRQS_SPURIOUS_DISABLED = 2, - IRQS_POLL_INPROGRESS = 8, - IRQS_ONESHOT = 32, - IRQS_REPLAY = 64, - IRQS_WAITING = 128, - IRQS_PENDING = 512, - IRQS_SUSPENDED = 2048, - IRQS_TIMINGS = 4096, - IRQS_NMI = 8192, -}; - -enum { - _IRQ_DEFAULT_INIT_FLAGS = 0, - _IRQ_PER_CPU = 512, - _IRQ_LEVEL = 256, - _IRQ_NOPROBE = 1024, - _IRQ_NOREQUEST = 2048, - _IRQ_NOTHREAD = 65536, - _IRQ_NOAUTOEN = 4096, - _IRQ_MOVE_PCNTXT = 16384, - _IRQ_NO_BALANCING = 8192, - _IRQ_NESTED_THREAD = 32768, - _IRQ_PER_CPU_DEVID = 131072, - _IRQ_IS_POLLED = 262144, - _IRQ_DISABLE_UNLAZY = 524288, - _IRQ_HIDDEN = 1048576, - _IRQF_MODIFY_MASK = 2096911, -}; - -enum { - IRQTF_RUNTHREAD = 0, - IRQTF_WARNED = 1, - IRQTF_AFFINITY = 2, - IRQTF_FORCED_THREAD = 3, -}; - -enum { - IRQ_SET_MASK_OK = 0, - IRQ_SET_MASK_OK_NOCOPY = 1, - IRQ_SET_MASK_OK_DONE = 2, -}; - -enum { - IRQCHIP_SET_TYPE_MASKED = 1, - IRQCHIP_EOI_IF_HANDLED = 2, - IRQCHIP_MASK_ON_SUSPEND = 4, - IRQCHIP_ONOFFLINE_ENABLED = 8, - IRQCHIP_SKIP_SET_WAKE = 16, - IRQCHIP_ONESHOT_SAFE = 32, - IRQCHIP_EOI_THREADED = 64, - IRQCHIP_SUPPORTS_LEVEL_MSI = 128, - IRQCHIP_SUPPORTS_NMI = 256, - IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = 512, - IRQCHIP_AFFINITY_PRE_STARTUP = 1024, -}; - -enum { - IRQC_IS_HARDIRQ = 0, - IRQC_IS_NESTED = 1, -}; - -enum { - IRQ_STARTUP_NORMAL = 0, - IRQ_STARTUP_MANAGED = 1, - IRQ_STARTUP_ABORT = 2, -}; - -struct irq_devres { - unsigned int irq; - void *dev_id; -}; - -struct irq_desc_devres { - unsigned int from; - unsigned int cnt; -}; - -struct irq_generic_chip_devres { - struct irq_chip_generic *gc; - u32 msk; - unsigned int clr; - unsigned int set; -}; - -struct of_phandle_args { - struct device_node *np; - int args_count; - uint32_t args[16]; -}; - -enum { - IRQ_DOMAIN_FLAG_HIERARCHY = 1, - IRQ_DOMAIN_NAME_ALLOCATED = 2, - IRQ_DOMAIN_FLAG_IPI_PER_CPU = 4, - IRQ_DOMAIN_FLAG_IPI_SINGLE = 8, - IRQ_DOMAIN_FLAG_MSI = 16, - IRQ_DOMAIN_FLAG_MSI_REMAP = 32, - IRQ_DOMAIN_MSI_NOMASK_QUIRK = 64, - IRQ_DOMAIN_FLAG_NONCORE = 65536, -}; - -enum { - IRQCHIP_FWNODE_REAL = 0, - IRQCHIP_FWNODE_NAMED = 1, - IRQCHIP_FWNODE_NAMED_ID = 2, -}; - -struct irqchip_fwid { - struct fwnode_handle fwnode; - unsigned int type; - char *name; - phys_addr_t *pa; -}; - -struct irq_sim_work_ctx { - struct irq_work work; - int irq_base; - unsigned int irq_count; - long unsigned int *pending; - struct irq_domain *domain; -}; - -struct irq_sim_irq_ctx { - int irqnum; - bool enabled; - struct irq_sim_work_ctx *work_ctx; -}; - -struct irq_sim_devres { - struct irq_domain *domain; -}; - -struct proc_ops { - unsigned int proc_flags; - int (*proc_open)(struct inode *, struct file *); - ssize_t (*proc_read)(struct file *, char *, size_t, loff_t *); - ssize_t (*proc_read_iter)(struct kiocb *, struct iov_iter *); - ssize_t (*proc_write)(struct file *, const char *, size_t, loff_t *); - loff_t (*proc_lseek)(struct file *, loff_t, int); - int (*proc_release)(struct inode *, struct file *); - __poll_t (*proc_poll)(struct file *, struct poll_table_struct *); - long int (*proc_ioctl)(struct file *, unsigned int, long unsigned int); - long int (*proc_compat_ioctl)(struct file *, unsigned int, long unsigned int); - int (*proc_mmap)(struct file *, struct vm_area_struct *); - long unsigned int (*proc_get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); -}; - -enum { - AFFINITY = 0, - AFFINITY_LIST = 1, - EFFECTIVE = 2, - EFFECTIVE_LIST = 3, -}; - -struct msi_alloc_info { - struct msi_desc *desc; - irq_hw_number_t hwirq; - union { - long unsigned int ul; - void *ptr; - } scratchpad[2]; -}; - -typedef struct msi_alloc_info msi_alloc_info_t; - -struct msi_domain_info; - -struct msi_domain_ops { - irq_hw_number_t (*get_hwirq)(struct msi_domain_info *, msi_alloc_info_t *); - int (*msi_init)(struct irq_domain *, struct msi_domain_info *, unsigned int, irq_hw_number_t, msi_alloc_info_t *); - void (*msi_free)(struct irq_domain *, struct msi_domain_info *, unsigned int); - int (*msi_check)(struct irq_domain *, struct msi_domain_info *, struct device *); - int (*msi_prepare)(struct irq_domain *, struct device *, int, msi_alloc_info_t *); - void (*msi_finish)(msi_alloc_info_t *, int); - void (*set_desc)(msi_alloc_info_t *, struct msi_desc *); - int (*handle_error)(struct irq_domain *, struct msi_desc *, int); - int (*domain_alloc_irqs)(struct irq_domain *, struct device *, int); - void (*domain_free_irqs)(struct irq_domain *, struct device *); -}; - -struct msi_domain_info { - u32 flags; - struct msi_domain_ops *ops; - struct irq_chip *chip; - void *chip_data; - irq_flow_handler_t handler; - void *handler_data; - const char *handler_name; - void *data; -}; - -enum { - MSI_FLAG_USE_DEF_DOM_OPS = 1, - MSI_FLAG_USE_DEF_CHIP_OPS = 2, - MSI_FLAG_MULTI_PCI_MSI = 4, - MSI_FLAG_PCI_MSIX = 8, - MSI_FLAG_ACTIVATE_EARLY = 16, - MSI_FLAG_MUST_REACTIVATE = 32, - MSI_FLAG_LEVEL_CAPABLE = 64, -}; - -struct irq_affinity { - unsigned int pre_vectors; - unsigned int post_vectors; - unsigned int nr_sets; - unsigned int set_size[4]; - void (*calc_sets)(struct irq_affinity *, unsigned int); - void *priv; -}; - -struct node_vectors { - unsigned int id; - union { - unsigned int nvectors; - unsigned int ncpus; - }; -}; - -struct irq_bit_descr { - unsigned int mask; - char *name; -}; - -typedef void (*rcu_callback_t)(struct callback_head *); - -typedef void (*call_rcu_func_t)(struct callback_head *, rcu_callback_t); - -struct rcu_synchronize { - struct callback_head head; - struct completion completion; -}; - -struct trace_event_raw_rcu_utilization { - struct trace_entry ent; - const char *s; - char __data[0]; -}; - -struct trace_event_raw_rcu_grace_period { - struct trace_entry ent; - const char *rcuname; - long int gp_seq; - const char *gpevent; - char __data[0]; -}; - -struct trace_event_raw_rcu_future_grace_period { - struct trace_entry ent; - const char *rcuname; - long int gp_seq; - long int gp_seq_req; - u8 level; - int grplo; - int grphi; - const char *gpevent; - char __data[0]; -}; - -struct trace_event_raw_rcu_grace_period_init { - struct trace_entry ent; - const char *rcuname; - long int gp_seq; - u8 level; - int grplo; - int grphi; - long unsigned int qsmask; - char __data[0]; -}; - -struct trace_event_raw_rcu_exp_grace_period { - struct trace_entry ent; - const char *rcuname; - long int gpseq; - const char *gpevent; - char __data[0]; -}; - -struct trace_event_raw_rcu_exp_funnel_lock { - struct trace_entry ent; - const char *rcuname; - u8 level; - int grplo; - int grphi; - const char *gpevent; - char __data[0]; -}; - -struct trace_event_raw_rcu_preempt_task { - struct trace_entry ent; - const char *rcuname; - long int gp_seq; - int pid; - char __data[0]; -}; - -struct trace_event_raw_rcu_unlock_preempted_task { - struct trace_entry ent; - const char *rcuname; - long int gp_seq; - int pid; - char __data[0]; -}; - -struct trace_event_raw_rcu_quiescent_state_report { - struct trace_entry ent; - const char *rcuname; - long int gp_seq; - long unsigned int mask; - long unsigned int qsmask; - u8 level; - int grplo; - int grphi; - u8 gp_tasks; - char __data[0]; -}; - -struct trace_event_raw_rcu_fqs { - struct trace_entry ent; - const char *rcuname; - long int gp_seq; - int cpu; - const char *qsevent; - char __data[0]; -}; - -struct trace_event_raw_rcu_dyntick { - struct trace_entry ent; - const char *polarity; - long int oldnesting; - long int newnesting; - int dynticks; - char __data[0]; -}; - -struct trace_event_raw_rcu_callback { - struct trace_entry ent; - const char *rcuname; - void *rhp; - void *func; - long int qlen; - char __data[0]; -}; - -struct trace_event_raw_rcu_kvfree_callback { - struct trace_entry ent; - const char *rcuname; - void *rhp; - long unsigned int offset; - long int qlen; - char __data[0]; -}; - -struct trace_event_raw_rcu_batch_start { - struct trace_entry ent; - const char *rcuname; - long int qlen; - long int blimit; - char __data[0]; -}; - -struct trace_event_raw_rcu_invoke_callback { - struct trace_entry ent; - const char *rcuname; - void *rhp; - void *func; - char __data[0]; -}; - -struct trace_event_raw_rcu_invoke_kvfree_callback { - struct trace_entry ent; - const char *rcuname; - void *rhp; - long unsigned int offset; - char __data[0]; -}; - -struct trace_event_raw_rcu_invoke_kfree_bulk_callback { - struct trace_entry ent; - const char *rcuname; - long unsigned int nr_records; - void **p; - char __data[0]; -}; - -struct trace_event_raw_rcu_batch_end { - struct trace_entry ent; - const char *rcuname; - int callbacks_invoked; - char cb; - char nr; - char iit; - char risk; - char __data[0]; -}; - -struct trace_event_raw_rcu_torture_read { - struct trace_entry ent; - char rcutorturename[8]; - struct callback_head *rhp; - long unsigned int secs; - long unsigned int c_old; - long unsigned int c; - char __data[0]; -}; - -struct trace_event_raw_rcu_barrier { - struct trace_entry ent; - const char *rcuname; - const char *s; - int cpu; - int cnt; - long unsigned int done; - char __data[0]; -}; - -struct trace_event_data_offsets_rcu_utilization {}; - -struct trace_event_data_offsets_rcu_grace_period {}; - -struct trace_event_data_offsets_rcu_future_grace_period {}; - -struct trace_event_data_offsets_rcu_grace_period_init {}; - -struct trace_event_data_offsets_rcu_exp_grace_period {}; - -struct trace_event_data_offsets_rcu_exp_funnel_lock {}; - -struct trace_event_data_offsets_rcu_preempt_task {}; - -struct trace_event_data_offsets_rcu_unlock_preempted_task {}; - -struct trace_event_data_offsets_rcu_quiescent_state_report {}; - -struct trace_event_data_offsets_rcu_fqs {}; - -struct trace_event_data_offsets_rcu_dyntick {}; - -struct trace_event_data_offsets_rcu_callback {}; - -struct trace_event_data_offsets_rcu_kvfree_callback {}; - -struct trace_event_data_offsets_rcu_batch_start {}; - -struct trace_event_data_offsets_rcu_invoke_callback {}; - -struct trace_event_data_offsets_rcu_invoke_kvfree_callback {}; - -struct trace_event_data_offsets_rcu_invoke_kfree_bulk_callback {}; - -struct trace_event_data_offsets_rcu_batch_end {}; - -struct trace_event_data_offsets_rcu_torture_read {}; - -struct trace_event_data_offsets_rcu_barrier {}; - -typedef void (*btf_trace_rcu_utilization)(void *, const char *); - -typedef void (*btf_trace_rcu_grace_period)(void *, const char *, long unsigned int, const char *); - -typedef void (*btf_trace_rcu_future_grace_period)(void *, const char *, long unsigned int, long unsigned int, u8, int, int, const char *); - -typedef void (*btf_trace_rcu_grace_period_init)(void *, const char *, long unsigned int, u8, int, int, long unsigned int); - -typedef void (*btf_trace_rcu_exp_grace_period)(void *, const char *, long unsigned int, const char *); - -typedef void (*btf_trace_rcu_exp_funnel_lock)(void *, const char *, u8, int, int, const char *); - -typedef void (*btf_trace_rcu_preempt_task)(void *, const char *, int, long unsigned int); - -typedef void (*btf_trace_rcu_unlock_preempted_task)(void *, const char *, long unsigned int, int); - -typedef void (*btf_trace_rcu_quiescent_state_report)(void *, const char *, long unsigned int, long unsigned int, long unsigned int, u8, int, int, int); - -typedef void (*btf_trace_rcu_fqs)(void *, const char *, long unsigned int, int, const char *); - -typedef void (*btf_trace_rcu_dyntick)(void *, const char *, long int, long int, int); - -typedef void (*btf_trace_rcu_callback)(void *, const char *, struct callback_head *, long int); - -typedef void (*btf_trace_rcu_kvfree_callback)(void *, const char *, struct callback_head *, long unsigned int, long int); - -typedef void (*btf_trace_rcu_batch_start)(void *, const char *, long int, long int); - -typedef void (*btf_trace_rcu_invoke_callback)(void *, const char *, struct callback_head *); - -typedef void (*btf_trace_rcu_invoke_kvfree_callback)(void *, const char *, struct callback_head *, long unsigned int); - -typedef void (*btf_trace_rcu_invoke_kfree_bulk_callback)(void *, const char *, long unsigned int, void **); - -typedef void (*btf_trace_rcu_batch_end)(void *, const char *, int, char, char, char, char); - -typedef void (*btf_trace_rcu_torture_read)(void *, const char *, struct callback_head *, long unsigned int, long unsigned int, long unsigned int); - -typedef void (*btf_trace_rcu_barrier)(void *, const char *, const char *, int, int, long unsigned int); - -struct rcu_tasks; - -typedef void (*rcu_tasks_gp_func_t)(struct rcu_tasks *); - -typedef void (*pregp_func_t)(); - -typedef void (*pertask_func_t)(struct task_struct *, struct list_head *); - -typedef void (*postscan_func_t)(struct list_head *); - -typedef void (*holdouts_func_t)(struct list_head *, bool, bool *); - -typedef void (*postgp_func_t)(struct rcu_tasks *); - -struct rcu_tasks { - struct callback_head *cbs_head; - struct callback_head **cbs_tail; - struct wait_queue_head cbs_wq; - raw_spinlock_t cbs_lock; - int gp_state; - int gp_sleep; - int init_fract; - long unsigned int gp_jiffies; - long unsigned int gp_start; - long unsigned int n_gps; - long unsigned int n_ipis; - long unsigned int n_ipis_fails; - struct task_struct *kthread_ptr; - rcu_tasks_gp_func_t gp_func; - pregp_func_t pregp_func; - pertask_func_t pertask_func; - postscan_func_t postscan_func; - holdouts_func_t holdouts_func; - postgp_func_t postgp_func; - call_rcu_func_t call_func; - char *name; - char *kname; -}; - -enum { - GP_IDLE = 0, - GP_ENTER = 1, - GP_PASSED = 2, - GP_EXIT = 3, - GP_REPLAY = 4, -}; - -struct rcu_cblist { - struct callback_head *head; - struct callback_head **tail; - long int len; -}; - -enum rcutorture_type { - RCU_FLAVOR = 0, - RCU_TASKS_FLAVOR = 1, - RCU_TASKS_RUDE_FLAVOR = 2, - RCU_TASKS_TRACING_FLAVOR = 3, - RCU_TRIVIAL_FLAVOR = 4, - SRCU_FLAVOR = 5, - INVALID_RCU_FLAVOR = 6, -}; - -struct rcu_exp_work { - long unsigned int rew_s; - struct work_struct rew_work; -}; - -struct rcu_node { - raw_spinlock_t lock; - long unsigned int gp_seq; - long unsigned int gp_seq_needed; - long unsigned int completedqs; - long unsigned int qsmask; - long unsigned int rcu_gp_init_mask; - long unsigned int qsmaskinit; - long unsigned int qsmaskinitnext; - long unsigned int expmask; - long unsigned int expmaskinit; - long unsigned int expmaskinitnext; - long unsigned int cbovldmask; - long unsigned int ffmask; - long unsigned int grpmask; - int grplo; - int grphi; - u8 grpnum; - u8 level; - bool wait_blkd_tasks; - struct rcu_node *parent; - struct list_head blkd_tasks; - struct list_head *gp_tasks; - struct list_head *exp_tasks; - struct list_head *boost_tasks; - struct rt_mutex boost_mtx; - long unsigned int boost_time; - struct task_struct *boost_kthread_task; - unsigned int boost_kthread_status; - long: 32; - long: 64; - long: 64; - long: 64; - raw_spinlock_t fqslock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t exp_lock; - long unsigned int exp_seq_rq; - wait_queue_head_t exp_wq[4]; - struct rcu_exp_work rew; - bool exp_need_flush; - long: 56; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum tick_dep_bits { - TICK_DEP_BIT_POSIX_TIMER = 0, - TICK_DEP_BIT_PERF_EVENTS = 1, - TICK_DEP_BIT_SCHED = 2, - TICK_DEP_BIT_CLOCK_UNSTABLE = 3, - TICK_DEP_BIT_RCU = 4, - TICK_DEP_BIT_RCU_EXP = 5, -}; - -union rcu_noqs { - struct { - u8 norm; - u8 exp; - } b; - u16 s; -}; - -struct rcu_data { - long unsigned int gp_seq; - long unsigned int gp_seq_needed; - union rcu_noqs cpu_no_qs; - bool core_needs_qs; - bool beenonline; - bool gpwrap; - bool exp_deferred_qs; - bool cpu_started; - struct rcu_node *mynode; - long unsigned int grpmask; - long unsigned int ticks_this_gp; - struct irq_work defer_qs_iw; - bool defer_qs_iw_pending; - struct work_struct strict_work; - struct rcu_segcblist cblist; - long int qlen_last_fqs_check; - long unsigned int n_cbs_invoked; - long unsigned int n_force_qs_snap; - long int blimit; - int dynticks_snap; - long int dynticks_nesting; - long int dynticks_nmi_nesting; - atomic_t dynticks; - bool rcu_need_heavy_qs; - bool rcu_urgent_qs; - bool rcu_forced_tick; - bool rcu_forced_tick_exp; - struct callback_head barrier_head; - int exp_dynticks_snap; - struct task_struct *rcu_cpu_kthread_task; - unsigned int rcu_cpu_kthread_status; - char rcu_cpu_has_work; - unsigned int softirq_snap; - struct irq_work rcu_iw; - bool rcu_iw_pending; - long unsigned int rcu_iw_gp_seq; - long unsigned int rcu_ofl_gp_seq; - short int rcu_ofl_gp_flags; - long unsigned int rcu_onl_gp_seq; - short int rcu_onl_gp_flags; - long unsigned int last_fqs_resched; - int cpu; -}; - -struct rcu_state { - struct rcu_node node[17]; - struct rcu_node *level[3]; - int ncpus; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - u8 boost; - long unsigned int gp_seq; - long unsigned int gp_max; - struct task_struct *gp_kthread; - struct swait_queue_head gp_wq; - short int gp_flags; - short int gp_state; - long unsigned int gp_wake_time; - long unsigned int gp_wake_seq; - struct mutex barrier_mutex; - atomic_t barrier_cpu_count; - struct completion barrier_completion; - long unsigned int barrier_sequence; - struct mutex exp_mutex; - struct mutex exp_wake_mutex; - long unsigned int expedited_sequence; - atomic_t expedited_need_qs; - struct swait_queue_head expedited_wq; - int ncpus_snap; - u8 cbovld; - u8 cbovldnext; - long unsigned int jiffies_force_qs; - long unsigned int jiffies_kick_kthreads; - long unsigned int n_force_qs; - long unsigned int gp_start; - long unsigned int gp_end; - long unsigned int gp_activity; - long unsigned int gp_req_activity; - long unsigned int jiffies_stall; - long unsigned int jiffies_resched; - long unsigned int n_force_qs_gpstart; - const char *name; - char abbr; - long: 56; - long: 64; - long: 64; - raw_spinlock_t ofl_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct kvfree_rcu_bulk_data { - long unsigned int nr_records; - struct kvfree_rcu_bulk_data *next; - void *records[0]; -}; - -struct kfree_rcu_cpu; - -struct kfree_rcu_cpu_work { - struct rcu_work rcu_work; - struct callback_head *head_free; - struct kvfree_rcu_bulk_data *bkvhead_free[2]; - struct kfree_rcu_cpu *krcp; -}; - -struct kfree_rcu_cpu { - struct callback_head *head; - struct kvfree_rcu_bulk_data *bkvhead[2]; - struct kfree_rcu_cpu_work krw_arr[2]; - raw_spinlock_t lock; - struct delayed_work monitor_work; - bool monitor_todo; - bool initialized; - int count; - struct work_struct page_cache_work; - atomic_t work_in_progress; - struct hrtimer hrtimer; - struct llist_head bkvcache; - int nr_bkv_objs; -}; - -struct rcu_stall_chk_rdr { - int nesting; - union rcu_special rs; - bool on_blkd_list; -}; - -struct scatterlist { - long unsigned int page_link; - unsigned int offset; - unsigned int length; - dma_addr_t dma_address; - unsigned int dma_length; -}; - -struct sg_table { - struct scatterlist *sgl; - unsigned int nents; - unsigned int orig_nents; -}; - -struct dma_map_ops { - void * (*alloc)(struct device *, size_t, dma_addr_t *, gfp_t, long unsigned int); - void (*free)(struct device *, size_t, void *, dma_addr_t, long unsigned int); - struct page * (*alloc_pages)(struct device *, size_t, dma_addr_t *, enum dma_data_direction, gfp_t); - void (*free_pages)(struct device *, size_t, struct page *, dma_addr_t, enum dma_data_direction); - void * (*alloc_noncoherent)(struct device *, size_t, dma_addr_t *, enum dma_data_direction, gfp_t); - void (*free_noncoherent)(struct device *, size_t, void *, dma_addr_t, enum dma_data_direction); - int (*mmap)(struct device *, struct vm_area_struct *, void *, dma_addr_t, size_t, long unsigned int); - int (*get_sgtable)(struct device *, struct sg_table *, void *, dma_addr_t, size_t, long unsigned int); - dma_addr_t (*map_page)(struct device *, struct page *, long unsigned int, size_t, enum dma_data_direction, long unsigned int); - void (*unmap_page)(struct device *, dma_addr_t, size_t, enum dma_data_direction, long unsigned int); - int (*map_sg)(struct device *, struct scatterlist *, int, enum dma_data_direction, long unsigned int); - void (*unmap_sg)(struct device *, struct scatterlist *, int, enum dma_data_direction, long unsigned int); - dma_addr_t (*map_resource)(struct device *, phys_addr_t, size_t, enum dma_data_direction, long unsigned int); - void (*unmap_resource)(struct device *, dma_addr_t, size_t, enum dma_data_direction, long unsigned int); - void (*sync_single_for_cpu)(struct device *, dma_addr_t, size_t, enum dma_data_direction); - void (*sync_single_for_device)(struct device *, dma_addr_t, size_t, enum dma_data_direction); - void (*sync_sg_for_cpu)(struct device *, struct scatterlist *, int, enum dma_data_direction); - void (*sync_sg_for_device)(struct device *, struct scatterlist *, int, enum dma_data_direction); - void (*cache_sync)(struct device *, void *, size_t, enum dma_data_direction); - int (*dma_supported)(struct device *, u64); - u64 (*get_required_mask)(struct device *); - size_t (*max_mapping_size)(struct device *); - long unsigned int (*get_merge_boundary)(struct device *); -}; - -enum dma_sync_target { - SYNC_FOR_CPU = 0, - SYNC_FOR_DEVICE = 1, -}; - -struct dma_devres { - size_t size; - void *vaddr; - dma_addr_t dma_handle; - long unsigned int attrs; -}; - -struct reserved_mem_ops; - -struct reserved_mem { - const char *name; - long unsigned int fdt_node; - long unsigned int phandle; - const struct reserved_mem_ops *ops; - phys_addr_t base; - phys_addr_t size; - void *priv; -}; - -struct reserved_mem_ops { - int (*device_init)(struct reserved_mem *, struct device *); - void (*device_release)(struct reserved_mem *, struct device *); -}; - -typedef int (*reservedmem_of_init_fn)(struct reserved_mem *); - -struct dma_coherent_mem { - void *virt_base; - dma_addr_t device_base; - long unsigned int pfn_base; - int size; - long unsigned int *bitmap; - spinlock_t spinlock; - bool use_dev_dma_pfn_offset; -}; - -struct trace_event_raw_swiotlb_bounced { - struct trace_entry ent; - u32 __data_loc_dev_name; - u64 dma_mask; - dma_addr_t dev_addr; - size_t size; - enum swiotlb_force swiotlb_force; - char __data[0]; -}; - -struct trace_event_data_offsets_swiotlb_bounced { - u32 dev_name; -}; - -typedef void (*btf_trace_swiotlb_bounced)(void *, struct device *, dma_addr_t, size_t, enum swiotlb_force); - -struct gen_pool; - -typedef long unsigned int (*genpool_algo_t)(long unsigned int *, long unsigned int, long unsigned int, unsigned int, void *, struct gen_pool *, long unsigned int); - -struct gen_pool { - spinlock_t lock; - struct list_head chunks; - int min_alloc_order; - genpool_algo_t algo; - void *data; - const char *name; -}; - -enum kcmp_type { - KCMP_FILE = 0, - KCMP_VM = 1, - KCMP_FILES = 2, - KCMP_FS = 3, - KCMP_SIGHAND = 4, - KCMP_IO = 5, - KCMP_SYSVSEM = 6, - KCMP_EPOLL_TFD = 7, - KCMP_TYPES = 8, -}; - -struct kcmp_epoll_slot { - __u32 efd; - __u32 tfd; - __u32 toff; -}; - -enum profile_type { - PROFILE_TASK_EXIT = 0, - PROFILE_MUNMAP = 1, -}; - -struct profile_hit { - u32 pc; - u32 hits; -}; - -struct stacktrace_cookie { - long unsigned int *store; - unsigned int size; - unsigned int skip; - unsigned int len; -}; - -typedef __kernel_long_t __kernel_suseconds_t; - -typedef __kernel_suseconds_t suseconds_t; - -typedef __u64 timeu64_t; - -struct __kernel_itimerspec { - struct __kernel_timespec it_interval; - struct __kernel_timespec it_value; -}; - -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - -struct itimerspec64 { - struct timespec64 it_interval; - struct timespec64 it_value; -}; - -struct old_itimerspec32 { - struct old_timespec32 it_interval; - struct old_timespec32 it_value; -}; - -struct old_timex32 { - u32 modes; - s32 offset; - s32 freq; - s32 maxerror; - s32 esterror; - s32 status; - s32 constant; - s32 precision; - s32 tolerance; - struct old_timeval32 time; - s32 tick; - s32 ppsfreq; - s32 jitter; - s32 shift; - s32 stabil; - s32 jitcnt; - s32 calcnt; - s32 errcnt; - s32 stbcnt; - s32 tai; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct __kernel_timex_timeval { - __kernel_time64_t tv_sec; - long long int tv_usec; -}; - -struct __kernel_timex { - unsigned int modes; - long long int offset; - long long int freq; - long long int maxerror; - long long int esterror; - int status; - long long int constant; - long long int precision; - long long int tolerance; - struct __kernel_timex_timeval time; - long long int tick; - long long int ppsfreq; - long long int jitter; - int shift; - long long int stabil; - long long int jitcnt; - long long int calcnt; - long long int errcnt; - long long int stbcnt; - int tai; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct trace_event_raw_timer_class { - struct trace_entry ent; - void *timer; - char __data[0]; -}; - -struct trace_event_raw_timer_start { - struct trace_entry ent; - void *timer; - void *function; - long unsigned int expires; - long unsigned int now; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_timer_expire_entry { - struct trace_entry ent; - void *timer; - long unsigned int now; - void *function; - long unsigned int baseclk; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_init { - struct trace_entry ent; - void *hrtimer; - clockid_t clockid; - enum hrtimer_mode mode; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_start { - struct trace_entry ent; - void *hrtimer; - void *function; - s64 expires; - s64 softexpires; - enum hrtimer_mode mode; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_expire_entry { - struct trace_entry ent; - void *hrtimer; - s64 now; - void *function; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_class { - struct trace_entry ent; - void *hrtimer; - char __data[0]; -}; - -struct trace_event_raw_itimer_state { - struct trace_entry ent; - int which; - long long unsigned int expires; - long int value_sec; - long int value_nsec; - long int interval_sec; - long int interval_nsec; - char __data[0]; -}; - -struct trace_event_raw_itimer_expire { - struct trace_entry ent; - int which; - pid_t pid; - long long unsigned int now; - char __data[0]; -}; - -struct trace_event_raw_tick_stop { - struct trace_entry ent; - int success; - int dependency; - char __data[0]; -}; - -struct trace_event_data_offsets_timer_class {}; - -struct trace_event_data_offsets_timer_start {}; - -struct trace_event_data_offsets_timer_expire_entry {}; - -struct trace_event_data_offsets_hrtimer_init {}; - -struct trace_event_data_offsets_hrtimer_start {}; - -struct trace_event_data_offsets_hrtimer_expire_entry {}; - -struct trace_event_data_offsets_hrtimer_class {}; - -struct trace_event_data_offsets_itimer_state {}; - -struct trace_event_data_offsets_itimer_expire {}; - -struct trace_event_data_offsets_tick_stop {}; - -typedef void (*btf_trace_timer_init)(void *, struct timer_list *); - -typedef void (*btf_trace_timer_start)(void *, struct timer_list *, long unsigned int, unsigned int); - -typedef void (*btf_trace_timer_expire_entry)(void *, struct timer_list *, long unsigned int); - -typedef void (*btf_trace_timer_expire_exit)(void *, struct timer_list *); - -typedef void (*btf_trace_timer_cancel)(void *, struct timer_list *); - -typedef void (*btf_trace_hrtimer_init)(void *, struct hrtimer *, clockid_t, enum hrtimer_mode); - -typedef void (*btf_trace_hrtimer_start)(void *, struct hrtimer *, enum hrtimer_mode); - -typedef void (*btf_trace_hrtimer_expire_entry)(void *, struct hrtimer *, ktime_t *); - -typedef void (*btf_trace_hrtimer_expire_exit)(void *, struct hrtimer *); - -typedef void (*btf_trace_hrtimer_cancel)(void *, struct hrtimer *); - -typedef void (*btf_trace_itimer_state)(void *, int, const struct itimerspec64 * const, long long unsigned int); - -typedef void (*btf_trace_itimer_expire)(void *, int, struct pid *, long long unsigned int); - -typedef void (*btf_trace_tick_stop)(void *, int, int); - -struct timer_base { - raw_spinlock_t lock; - struct timer_list *running_timer; - long unsigned int clk; - long unsigned int next_expiry; - unsigned int cpu; - bool next_expiry_recalc; - bool is_idle; - bool timers_pending; - long unsigned int pending_map[9]; - struct hlist_head vectors[576]; - long: 64; - long: 64; -}; - -struct process_timer { - struct timer_list timer; - struct task_struct *task; -}; - -enum clock_event_state { - CLOCK_EVT_STATE_DETACHED = 0, - CLOCK_EVT_STATE_SHUTDOWN = 1, - CLOCK_EVT_STATE_PERIODIC = 2, - CLOCK_EVT_STATE_ONESHOT = 3, - CLOCK_EVT_STATE_ONESHOT_STOPPED = 4, -}; - -struct clock_event_device { - void (*event_handler)(struct clock_event_device *); - int (*set_next_event)(long unsigned int, struct clock_event_device *); - int (*set_next_ktime)(ktime_t, struct clock_event_device *); - ktime_t next_event; - u64 max_delta_ns; - u64 min_delta_ns; - u32 mult; - u32 shift; - enum clock_event_state state_use_accessors; - unsigned int features; - long unsigned int retries; - int (*set_state_periodic)(struct clock_event_device *); - int (*set_state_oneshot)(struct clock_event_device *); - int (*set_state_oneshot_stopped)(struct clock_event_device *); - int (*set_state_shutdown)(struct clock_event_device *); - int (*tick_resume)(struct clock_event_device *); - void (*broadcast)(const struct cpumask *); - void (*suspend)(struct clock_event_device *); - void (*resume)(struct clock_event_device *); - long unsigned int min_delta_ticks; - long unsigned int max_delta_ticks; - const char *name; - int rating; - int irq; - int bound_on; - const struct cpumask *cpumask; - struct list_head list; - struct module *owner; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct ktime_timestamps { - u64 mono; - u64 boot; - u64 real; -}; - -struct system_time_snapshot { - u64 cycles; - ktime_t real; - ktime_t raw; - unsigned int clock_was_set_seq; - u8 cs_was_changed_seq; -}; - -struct system_device_crosststamp { - ktime_t device; - ktime_t sys_realtime; - ktime_t sys_monoraw; -}; - -struct clocksource; - -struct system_counterval_t { - u64 cycles; - struct clocksource *cs; -}; - -enum vdso_clock_mode { - VDSO_CLOCKMODE_NONE = 0, - VDSO_CLOCKMODE_ARCHTIMER = 1, - VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT = 2, - VDSO_CLOCKMODE_MAX = 3, - VDSO_CLOCKMODE_TIMENS = 2147483647, -}; - -struct clocksource { - u64 (*read)(struct clocksource *); - u64 mask; - u32 mult; - u32 shift; - u64 max_idle_ns; - u32 maxadj; - u64 max_cycles; - const char *name; - struct list_head list; - int rating; - enum vdso_clock_mode vdso_clock_mode; - long unsigned int flags; - int (*enable)(struct clocksource *); - void (*disable)(struct clocksource *); - void (*suspend)(struct clocksource *); - void (*resume)(struct clocksource *); - void (*mark_unstable)(struct clocksource *); - void (*tick_stable)(struct clocksource *); - struct module *owner; -}; - -typedef struct { - seqcount_t seqcount; -} seqcount_latch_t; - -struct tk_read_base { - struct clocksource *clock; - u64 mask; - u64 cycle_last; - u32 mult; - u32 shift; - u64 xtime_nsec; - ktime_t base; - u64 base_real; -}; - -struct timekeeper { - struct tk_read_base tkr_mono; - struct tk_read_base tkr_raw; - u64 xtime_sec; - long unsigned int ktime_sec; - struct timespec64 wall_to_monotonic; - ktime_t offs_real; - ktime_t offs_boot; - ktime_t offs_tai; - s32 tai_offset; - unsigned int clock_was_set_seq; - u8 cs_was_changed_seq; - ktime_t next_leap_ktime; - u64 raw_sec; - struct timespec64 monotonic_to_boot; - u64 cycle_interval; - u64 xtime_interval; - s64 xtime_remainder; - u64 raw_interval; - u64 ntp_tick; - s64 ntp_error; - u32 ntp_error_shift; - u32 ntp_err_mult; - u32 skip_second_overflow; -}; - -struct audit_ntp_val { - long long int oldval; - long long int newval; -}; - -struct audit_ntp_data { - struct audit_ntp_val vals[6]; -}; - -enum timekeeping_adv_mode { - TK_ADV_TICK = 0, - TK_ADV_FREQ = 1, -}; - -struct tk_fast { - seqcount_latch_t seq; - struct tk_read_base base[2]; -}; - -enum tick_device_mode { - TICKDEV_MODE_PERIODIC = 0, - TICKDEV_MODE_ONESHOT = 1, -}; - -struct tick_device { - struct clock_event_device *evtdev; - enum tick_device_mode mode; -}; - -enum tick_nohz_mode { - NOHZ_MODE_INACTIVE = 0, - NOHZ_MODE_LOWRES = 1, - NOHZ_MODE_HIGHRES = 2, -}; - -struct tick_sched { - struct hrtimer sched_timer; - long unsigned int check_clocks; - enum tick_nohz_mode nohz_mode; - unsigned int inidle: 1; - unsigned int tick_stopped: 1; - unsigned int idle_active: 1; - unsigned int do_timer_last: 1; - unsigned int got_idle_tick: 1; - ktime_t last_tick; - ktime_t next_tick; - long unsigned int idle_jiffies; - long unsigned int idle_calls; - long unsigned int idle_sleeps; - ktime_t idle_entrytime; - ktime_t idle_waketime; - ktime_t idle_exittime; - ktime_t idle_sleeptime; - ktime_t iowait_sleeptime; - long unsigned int last_jiffies; - u64 timer_expires; - u64 timer_expires_base; - u64 next_timer; - ktime_t idle_expires; - atomic_t tick_dep_mask; -}; - -struct timer_list_iter { - int cpu; - bool second_pass; - u64 now; -}; - -struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - long int tm_year; - int tm_wday; - int tm_yday; -}; - -typedef __kernel_timer_t timer_t; - -struct rtc_time { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -struct rtc_wkalrm { - unsigned char enabled; - unsigned char pending; - struct rtc_time time; -}; - -enum alarmtimer_type { - ALARM_REALTIME = 0, - ALARM_BOOTTIME = 1, - ALARM_NUMTYPE = 2, - ALARM_REALTIME_FREEZER = 3, - ALARM_BOOTTIME_FREEZER = 4, -}; - -enum alarmtimer_restart { - ALARMTIMER_NORESTART = 0, - ALARMTIMER_RESTART = 1, -}; - -struct alarm { - struct timerqueue_node node; - struct hrtimer timer; - enum alarmtimer_restart (*function)(struct alarm *, ktime_t); - enum alarmtimer_type type; - int state; - void *data; -}; - -struct cpu_timer { - struct timerqueue_node node; - struct timerqueue_head *head; - struct pid *pid; - struct list_head elist; - int firing; -}; - -struct k_clock; - -struct k_itimer { - struct list_head list; - struct hlist_node t_hash; - spinlock_t it_lock; - const struct k_clock *kclock; - clockid_t it_clock; - timer_t it_id; - int it_active; - s64 it_overrun; - s64 it_overrun_last; - int it_requeue_pending; - int it_sigev_notify; - ktime_t it_interval; - struct signal_struct *it_signal; - union { - struct pid *it_pid; - struct task_struct *it_process; - }; - struct sigqueue *sigq; - union { - struct { - struct hrtimer timer; - } real; - struct cpu_timer cpu; - struct { - struct alarm alarmtimer; - } alarm; - } it; - struct callback_head rcu; -}; - -struct k_clock { - int (*clock_getres)(const clockid_t, struct timespec64 *); - int (*clock_set)(const clockid_t, const struct timespec64 *); - int (*clock_get_timespec)(const clockid_t, struct timespec64 *); - ktime_t (*clock_get_ktime)(const clockid_t); - int (*clock_adj)(const clockid_t, struct __kernel_timex *); - int (*timer_create)(struct k_itimer *); - int (*nsleep)(const clockid_t, int, const struct timespec64 *); - int (*timer_set)(struct k_itimer *, int, struct itimerspec64 *, struct itimerspec64 *); - int (*timer_del)(struct k_itimer *); - void (*timer_get)(struct k_itimer *, struct itimerspec64 *); - void (*timer_rearm)(struct k_itimer *); - s64 (*timer_forward)(struct k_itimer *, ktime_t); - ktime_t (*timer_remaining)(struct k_itimer *, ktime_t); - int (*timer_try_to_cancel)(struct k_itimer *); - void (*timer_arm)(struct k_itimer *, ktime_t, bool, bool); - void (*timer_wait_running)(struct k_itimer *); -}; - -struct class_interface { - struct list_head node; - struct class *class; - int (*add_dev)(struct device *, struct class_interface *); - void (*remove_dev)(struct device *, struct class_interface *); -}; - -struct rtc_class_ops { - int (*ioctl)(struct device *, unsigned int, long unsigned int); - int (*read_time)(struct device *, struct rtc_time *); - int (*set_time)(struct device *, struct rtc_time *); - int (*read_alarm)(struct device *, struct rtc_wkalrm *); - int (*set_alarm)(struct device *, struct rtc_wkalrm *); - int (*proc)(struct device *, struct seq_file *); - int (*alarm_irq_enable)(struct device *, unsigned int); - int (*read_offset)(struct device *, long int *); - int (*set_offset)(struct device *, long int); -}; - -struct rtc_device; - -struct rtc_timer { - struct timerqueue_node node; - ktime_t period; - void (*func)(struct rtc_device *); - struct rtc_device *rtc; - int enabled; -}; - -struct rtc_device { - struct device dev; - struct module *owner; - int id; - const struct rtc_class_ops *ops; - struct mutex ops_lock; - struct cdev char_dev; - long unsigned int flags; - long unsigned int irq_data; - spinlock_t irq_lock; - wait_queue_head_t irq_queue; - struct fasync_struct *async_queue; - int irq_freq; - int max_user_freq; - struct timerqueue_head timerqueue; - struct rtc_timer aie_timer; - struct rtc_timer uie_rtctimer; - struct hrtimer pie_timer; - int pie_enabled; - struct work_struct irqwork; - int uie_unsupported; - long int set_offset_nsec; - bool registered; - bool nvram_old_abi; - struct bin_attribute *nvram; - time64_t range_min; - timeu64_t range_max; - time64_t start_secs; - time64_t offset_secs; - bool set_start_time; -}; - -struct property_entry; - -struct platform_device_info { - struct device *parent; - struct fwnode_handle *fwnode; - bool of_node_reused; - const char *name; - int id; - const struct resource *res; - unsigned int num_res; - const void *data; - size_t size_data; - u64 dma_mask; - const struct property_entry *properties; -}; - -enum dev_prop_type { - DEV_PROP_U8 = 0, - DEV_PROP_U16 = 1, - DEV_PROP_U32 = 2, - DEV_PROP_U64 = 3, - DEV_PROP_STRING = 4, - DEV_PROP_REF = 5, -}; - -struct property_entry { - const char *name; - size_t length; - bool is_inline; - enum dev_prop_type type; - union { - const void *pointer; - union { - u8 u8_data[8]; - u16 u16_data[4]; - u32 u32_data[2]; - u64 u64_data[1]; - const char *str[1]; - } value; - }; -}; - -struct trace_event_raw_alarmtimer_suspend { - struct trace_entry ent; - s64 expires; - unsigned char alarm_type; - char __data[0]; -}; - -struct trace_event_raw_alarm_class { - struct trace_entry ent; - void *alarm; - unsigned char alarm_type; - s64 expires; - s64 now; - char __data[0]; -}; - -struct trace_event_data_offsets_alarmtimer_suspend {}; - -struct trace_event_data_offsets_alarm_class {}; - -typedef void (*btf_trace_alarmtimer_suspend)(void *, ktime_t, int); - -typedef void (*btf_trace_alarmtimer_fired)(void *, struct alarm *, ktime_t); - -typedef void (*btf_trace_alarmtimer_start)(void *, struct alarm *, ktime_t); - -typedef void (*btf_trace_alarmtimer_cancel)(void *, struct alarm *, ktime_t); - -struct alarm_base { - spinlock_t lock; - struct timerqueue_head timerqueue; - ktime_t (*get_ktime)(); - void (*get_timespec)(struct timespec64 *); - clockid_t base_clockid; -}; - -struct sigevent { - sigval_t sigev_value; - int sigev_signo; - int sigev_notify; - union { - int _pad[12]; - int _tid; - struct { - void (*_function)(sigval_t); - void *_attribute; - } _sigev_thread; - } _sigev_un; -}; - -typedef struct sigevent sigevent_t; - -struct compat_sigevent { - compat_sigval_t sigev_value; - compat_int_t sigev_signo; - compat_int_t sigev_notify; - union { - compat_int_t _pad[13]; - compat_int_t _tid; - struct { - compat_uptr_t _function; - compat_uptr_t _attribute; - } _sigev_thread; - } _sigev_un; -}; - -struct posix_clock; - -struct posix_clock_operations { - struct module *owner; - int (*clock_adjtime)(struct posix_clock *, struct __kernel_timex *); - int (*clock_gettime)(struct posix_clock *, struct timespec64 *); - int (*clock_getres)(struct posix_clock *, struct timespec64 *); - int (*clock_settime)(struct posix_clock *, const struct timespec64 *); - long int (*ioctl)(struct posix_clock *, unsigned int, long unsigned int); - int (*open)(struct posix_clock *, fmode_t); - __poll_t (*poll)(struct posix_clock *, struct file *, poll_table *); - int (*release)(struct posix_clock *); - ssize_t (*read)(struct posix_clock *, uint, char *, size_t); -}; - -struct posix_clock { - struct posix_clock_operations ops; - struct cdev cdev; - struct device *dev; - struct rw_semaphore rwsem; - bool zombie; -}; - -struct posix_clock_desc { - struct file *fp; - struct posix_clock *clk; -}; - -struct __kernel_old_itimerval { - struct __kernel_old_timeval it_interval; - struct __kernel_old_timeval it_value; -}; - -struct old_itimerval32 { - struct old_timeval32 it_interval; - struct old_timeval32 it_value; -}; - -typedef s64 int64_t; - -struct ce_unbind { - struct clock_event_device *ce; - int res; -}; - -enum tick_broadcast_state { - TICK_BROADCAST_EXIT = 0, - TICK_BROADCAST_ENTER = 1, -}; - -enum tick_broadcast_mode { - TICK_BROADCAST_OFF = 0, - TICK_BROADCAST_ON = 1, - TICK_BROADCAST_FORCE = 2, -}; - -struct clock_data { - seqcount_latch_t seq; - struct clock_read_data read_data[2]; - ktime_t wrap_kt; - long unsigned int rate; - u64 (*actual_read_sched_clock)(); -}; - -struct proc_timens_offset { - int clockid; - struct timespec64 val; -}; - -union futex_key { - struct { - u64 i_seq; - long unsigned int pgoff; - unsigned int offset; - } shared; - struct { - union { - struct mm_struct *mm; - u64 __tmp; - }; - long unsigned int address; - unsigned int offset; - } private; - struct { - u64 ptr; - long unsigned int word; - unsigned int offset; - } both; -}; - -struct futex_pi_state { - struct list_head list; - struct rt_mutex pi_mutex; - struct task_struct *owner; - refcount_t refcount; - union futex_key key; -}; - -struct futex_q { - struct plist_node list; - struct task_struct *task; - spinlock_t *lock_ptr; - union futex_key key; - struct futex_pi_state *pi_state; - struct rt_mutex_waiter *rt_waiter; - union futex_key *requeue_pi_key; - u32 bitset; -}; - -struct futex_hash_bucket { - atomic_t waiters; - spinlock_t lock; - struct plist_head chain; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum futex_access { - FUTEX_READ = 0, - FUTEX_WRITE = 1, -}; - -typedef bool (*smp_cond_func_t)(int, void *); - -struct call_function_data { - call_single_data_t *csd; - cpumask_var_t cpumask; - cpumask_var_t cpumask_ipi; -}; - -struct smp_call_on_cpu_struct { - struct work_struct work; - struct completion done; - int (*func)(void *); - void *data; - int ret; - int cpu; -}; - -typedef short unsigned int __kernel_old_uid_t; - -typedef short unsigned int __kernel_old_gid_t; - -typedef __kernel_old_uid_t old_uid_t; - -typedef __kernel_old_gid_t old_gid_t; - -struct latch_tree_root { - seqcount_latch_t seq; - struct rb_root tree[2]; -}; - -struct latch_tree_ops { - bool (*less)(struct latch_tree_node *, struct latch_tree_node *); - int (*comp)(void *, struct latch_tree_node *); -}; - -struct modversion_info { - long unsigned int crc; - char name[56]; -}; - -struct module_use { - struct list_head source_list; - struct list_head target_list; - struct module *source; - struct module *target; -}; - -struct module_sect_attr { - struct bin_attribute battr; - long unsigned int address; -}; - -struct module_sect_attrs { - struct attribute_group grp; - unsigned int nsections; - struct module_sect_attr attrs[0]; -}; - -struct module_notes_attrs { - struct kobject *dir; - unsigned int notes; - struct bin_attribute attrs[0]; -}; - -enum mod_license { - NOT_GPL_ONLY = 0, - GPL_ONLY = 1, - WILL_BE_GPL_ONLY = 2, -}; - -struct symsearch { - const struct kernel_symbol *start; - const struct kernel_symbol *stop; - const s32 *crcs; - enum mod_license license; - bool unused; -}; - -enum kernel_read_file_id { - READING_UNKNOWN = 0, - READING_FIRMWARE = 1, - READING_MODULE = 2, - READING_KEXEC_IMAGE = 3, - READING_KEXEC_INITRAMFS = 4, - READING_POLICY = 5, - READING_X509_CERTIFICATE = 6, - READING_MAX_ID = 7, -}; - -enum kernel_load_data_id { - LOADING_UNKNOWN = 0, - LOADING_FIRMWARE = 1, - LOADING_MODULE = 2, - LOADING_KEXEC_IMAGE = 3, - LOADING_KEXEC_INITRAMFS = 4, - LOADING_POLICY = 5, - LOADING_X509_CERTIFICATE = 6, - LOADING_MAX_ID = 7, -}; - -enum { - PROC_ENTRY_PERMANENT = 1, -}; - -struct _ddebug { - const char *modname; - const char *function; - const char *filename; - const char *format; - unsigned int lineno: 18; - unsigned int flags: 8; - union { - struct static_key_true dd_key_true; - struct static_key_false dd_key_false; - } key; -}; - -struct load_info { - const char *name; - struct module *mod; - Elf64_Ehdr *hdr; - long unsigned int len; - Elf64_Shdr *sechdrs; - char *secstrings; - char *strtab; - long unsigned int symoffs; - long unsigned int stroffs; - long unsigned int init_typeoffs; - long unsigned int core_typeoffs; - struct _ddebug *debug; - unsigned int num_debug; - bool sig_ok; - long unsigned int mod_kallsyms_init_off; - struct { - unsigned int sym; - unsigned int str; - unsigned int mod; - unsigned int vers; - unsigned int info; - unsigned int pcpu; - } index; -}; - -struct trace_event_raw_module_load { - struct trace_entry ent; - unsigned int taints; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_module_free { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_module_refcnt { - struct trace_entry ent; - long unsigned int ip; - int refcnt; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_module_request { - struct trace_entry ent; - long unsigned int ip; - bool wait; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_data_offsets_module_load { - u32 name; -}; - -struct trace_event_data_offsets_module_free { - u32 name; -}; - -struct trace_event_data_offsets_module_refcnt { - u32 name; -}; - -struct trace_event_data_offsets_module_request { - u32 name; -}; - -typedef void (*btf_trace_module_load)(void *, struct module *); - -typedef void (*btf_trace_module_free)(void *, struct module *); - -typedef void (*btf_trace_module_get)(void *, struct module *, long unsigned int); - -typedef void (*btf_trace_module_put)(void *, struct module *, long unsigned int); - -typedef void (*btf_trace_module_request)(void *, char *, bool, long unsigned int); - -struct mod_tree_root { - struct latch_tree_root root; - long unsigned int addr_min; - long unsigned int addr_max; -}; - -struct find_symbol_arg { - const char *name; - bool gplok; - bool warn; - struct module *owner; - const s32 *crc; - const struct kernel_symbol *sym; - enum mod_license license; -}; - -struct mod_initfree { - struct llist_node node; - void *module_init; -}; - -struct kallsym_iter { - loff_t pos; - loff_t pos_arch_end; - loff_t pos_mod_end; - loff_t pos_ftrace_mod_end; - loff_t pos_bpf_end; - long unsigned int value; - unsigned int nameoff; - char type; - char name[128]; - char module_name[56]; - int exported; - int show_value; -}; - -typedef struct { - int val[2]; -} __kernel_fsid_t; - -struct kstatfs { - long int f_type; - long int f_bsize; - u64 f_blocks; - u64 f_bfree; - u64 f_bavail; - u64 f_files; - u64 f_ffree; - __kernel_fsid_t f_fsid; - long int f_namelen; - long int f_frsize; - long int f_flags; - long int f_spare[4]; -}; - -typedef __u16 comp_t; - -struct acct_v3 { - char ac_flag; - char ac_version; - __u16 ac_tty; - __u32 ac_exitcode; - __u32 ac_uid; - __u32 ac_gid; - __u32 ac_pid; - __u32 ac_ppid; - __u32 ac_btime; - __u32 ac_etime; - comp_t ac_utime; - comp_t ac_stime; - comp_t ac_mem; - comp_t ac_io; - comp_t ac_rw; - comp_t ac_minflt; - comp_t ac_majflt; - comp_t ac_swaps; - char ac_comm[16]; -}; - -typedef struct acct_v3 acct_t; - -struct fs_pin { - wait_queue_head_t wait; - int done; - struct hlist_node s_list; - struct hlist_node m_list; - void (*kill)(struct fs_pin *); -}; - -struct bsd_acct_struct { - struct fs_pin pin; - atomic_long_t count; - struct callback_head rcu; - struct mutex lock; - int active; - long unsigned int needcheck; - struct file *file; - struct pid_namespace *ns; - struct work_struct work; - struct completion done; -}; - -enum migrate_reason { - MR_COMPACTION = 0, - MR_MEMORY_FAILURE = 1, - MR_MEMORY_HOTPLUG = 2, - MR_SYSCALL = 3, - MR_MEMPOLICY_MBIND = 4, - MR_NUMA_MISPLACED = 5, - MR_CONTIG_RANGE = 6, - MR_TYPES = 7, -}; - -typedef __kernel_ulong_t __kernel_ino_t; - -typedef __kernel_ino_t ino_t; - -enum kernfs_node_type { - KERNFS_DIR = 1, - KERNFS_FILE = 2, - KERNFS_LINK = 4, -}; - -enum kernfs_root_flag { - KERNFS_ROOT_CREATE_DEACTIVATED = 1, - KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK = 2, - KERNFS_ROOT_SUPPORT_EXPORTOP = 4, - KERNFS_ROOT_SUPPORT_USER_XATTR = 8, -}; - -struct kernfs_fs_context { - struct kernfs_root *root; - void *ns_tag; - long unsigned int magic; - bool new_sb_created; -}; - -enum bpf_link_type { - BPF_LINK_TYPE_UNSPEC = 0, - BPF_LINK_TYPE_RAW_TRACEPOINT = 1, - BPF_LINK_TYPE_TRACING = 2, - BPF_LINK_TYPE_CGROUP = 3, - BPF_LINK_TYPE_ITER = 4, - BPF_LINK_TYPE_NETNS = 5, - BPF_LINK_TYPE_XDP = 6, - MAX_BPF_LINK_TYPE = 7, -}; - -struct bpf_link_info { - __u32 type; - __u32 id; - __u32 prog_id; - union { - struct { - __u64 tp_name; - __u32 tp_name_len; - } raw_tracepoint; - struct { - __u32 attach_type; - } tracing; - struct { - __u64 cgroup_id; - __u32 attach_type; - } cgroup; - struct { - __u64 target_name; - __u32 target_name_len; - union { - struct { - __u32 map_id; - } map; - }; - } iter; - struct { - __u32 netns_ino; - __u32 attach_type; - } netns; - struct { - __u32 ifindex; - } xdp; - }; -}; - -struct bpf_link_ops; - -struct bpf_link { - atomic64_t refcnt; - u32 id; - enum bpf_link_type type; - const struct bpf_link_ops *ops; - struct bpf_prog *prog; - struct work_struct work; -}; - -struct bpf_link_ops { - void (*release)(struct bpf_link *); - void (*dealloc)(struct bpf_link *); - int (*detach)(struct bpf_link *); - int (*update_prog)(struct bpf_link *, struct bpf_prog *, struct bpf_prog *); - void (*show_fdinfo)(const struct bpf_link *, struct seq_file *); - int (*fill_link_info)(const struct bpf_link *, struct bpf_link_info *); -}; - -struct bpf_cgroup_link { - struct bpf_link link; - struct cgroup *cgroup; - enum bpf_attach_type type; -}; - -enum { - CGRP_NOTIFY_ON_RELEASE = 0, - CGRP_CPUSET_CLONE_CHILDREN = 1, - CGRP_FREEZE = 2, - CGRP_FROZEN = 3, -}; - -enum { - CGRP_ROOT_NOPREFIX = 2, - CGRP_ROOT_XATTR = 4, - CGRP_ROOT_NS_DELEGATE = 8, - CGRP_ROOT_CPUSET_V2_MODE = 16, - CGRP_ROOT_MEMORY_LOCAL_EVENTS = 32, - CGRP_ROOT_MEMORY_RECURSIVE_PROT = 64, -}; - -struct cgroup_taskset { - struct list_head src_csets; - struct list_head dst_csets; - int nr_tasks; - int ssid; - struct list_head *csets; - struct css_set *cur_cset; - struct task_struct *cur_task; -}; - -struct css_task_iter { - struct cgroup_subsys *ss; - unsigned int flags; - struct list_head *cset_pos; - struct list_head *cset_head; - struct list_head *tcset_pos; - struct list_head *tcset_head; - struct list_head *task_pos; - struct list_head *cur_tasks_head; - struct css_set *cur_cset; - struct css_set *cur_dcset; - struct task_struct *cur_task; - struct list_head iters_node; -}; - -struct cgroup_fs_context { - struct kernfs_fs_context kfc; - struct cgroup_root *root; - struct cgroup_namespace *ns; - unsigned int flags; - bool cpuset_clone_children; - bool none; - bool all_ss; - u16 subsys_mask; - char *name; - char *release_agent; -}; - -struct cgrp_cset_link { - struct cgroup *cgrp; - struct css_set *cset; - struct list_head cset_link; - struct list_head cgrp_link; -}; - -struct cgroup_mgctx { - struct list_head preloaded_src_csets; - struct list_head preloaded_dst_csets; - struct cgroup_taskset tset; - u16 ss_mask; -}; - -struct trace_event_raw_cgroup_root { - struct trace_entry ent; - int root; - u16 ss_mask; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_cgroup { - struct trace_entry ent; - int root; - int id; - int level; - u32 __data_loc_path; - char __data[0]; -}; - -struct trace_event_raw_cgroup_migrate { - struct trace_entry ent; - int dst_root; - int dst_id; - int dst_level; - int pid; - u32 __data_loc_dst_path; - u32 __data_loc_comm; - char __data[0]; -}; - -struct trace_event_raw_cgroup_event { - struct trace_entry ent; - int root; - int id; - int level; - u32 __data_loc_path; - int val; - char __data[0]; -}; - -struct trace_event_data_offsets_cgroup_root { - u32 name; -}; - -struct trace_event_data_offsets_cgroup { - u32 path; -}; - -struct trace_event_data_offsets_cgroup_migrate { - u32 dst_path; - u32 comm; -}; - -struct trace_event_data_offsets_cgroup_event { - u32 path; -}; - -typedef void (*btf_trace_cgroup_setup_root)(void *, struct cgroup_root *); - -typedef void (*btf_trace_cgroup_destroy_root)(void *, struct cgroup_root *); - -typedef void (*btf_trace_cgroup_remount)(void *, struct cgroup_root *); - -typedef void (*btf_trace_cgroup_mkdir)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_rmdir)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_release)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_rename)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_freeze)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_unfreeze)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_attach_task)(void *, struct cgroup *, const char *, struct task_struct *, bool); - -typedef void (*btf_trace_cgroup_transfer_tasks)(void *, struct cgroup *, const char *, struct task_struct *, bool); - -typedef void (*btf_trace_cgroup_notify_populated)(void *, struct cgroup *, const char *, int); - -typedef void (*btf_trace_cgroup_notify_frozen)(void *, struct cgroup *, const char *, int); - -enum cgroup2_param { - Opt_nsdelegate = 0, - Opt_memory_localevents = 1, - Opt_memory_recursiveprot = 2, - nr__cgroup2_params = 3, -}; - -struct cgroupstats { - __u64 nr_sleeping; - __u64 nr_running; - __u64 nr_stopped; - __u64 nr_uninterruptible; - __u64 nr_io_wait; -}; - -enum cgroup_filetype { - CGROUP_FILE_PROCS = 0, - CGROUP_FILE_TASKS = 1, -}; - -struct cgroup_pidlist { - struct { - enum cgroup_filetype type; - struct pid_namespace *ns; - } key; - pid_t *list; - int length; - struct list_head links; - struct cgroup *owner; - struct delayed_work destroy_dwork; -}; - -enum cgroup1_param { - Opt_all = 0, - Opt_clone_children = 1, - Opt_cpuset_v2_mode = 2, - Opt_name = 3, - Opt_none = 4, - Opt_noprefix = 5, - Opt_release_agent = 6, - Opt_xattr = 7, -}; - -enum freezer_state_flags { - CGROUP_FREEZER_ONLINE = 1, - CGROUP_FREEZING_SELF = 2, - CGROUP_FREEZING_PARENT = 4, - CGROUP_FROZEN = 8, - CGROUP_FREEZING = 6, -}; - -struct freezer { - struct cgroup_subsys_state css; - unsigned int state; -}; - -struct pids_cgroup { - struct cgroup_subsys_state css; - atomic64_t counter; - atomic64_t limit; - struct cgroup_file events_file; - atomic64_t events_limit; -}; - -struct root_domain___2; - -struct fmeter { - int cnt; - int val; - time64_t time; - spinlock_t lock; -}; - -struct cpuset { - struct cgroup_subsys_state css; - long unsigned int flags; - cpumask_var_t cpus_allowed; - nodemask_t mems_allowed; - cpumask_var_t effective_cpus; - nodemask_t effective_mems; - cpumask_var_t subparts_cpus; - nodemask_t old_mems_allowed; - struct fmeter fmeter; - int attach_in_progress; - int pn; - int relax_domain_level; - int nr_subparts_cpus; - int partition_root_state; - int use_parent_ecpus; - int child_ecpus_count; -}; - -struct tmpmasks { - cpumask_var_t addmask; - cpumask_var_t delmask; - cpumask_var_t new_cpus; -}; - -typedef enum { - CS_ONLINE = 0, - CS_CPU_EXCLUSIVE = 1, - CS_MEM_EXCLUSIVE = 2, - CS_MEM_HARDWALL = 3, - CS_MEMORY_MIGRATE = 4, - CS_SCHED_LOAD_BALANCE = 5, - CS_SPREAD_PAGE = 6, - CS_SPREAD_SLAB = 7, -} cpuset_flagbits_t; - -enum subparts_cmd { - partcmd_enable = 0, - partcmd_disable = 1, - partcmd_update = 2, -}; - -struct cpuset_migrate_mm_work { - struct work_struct work; - struct mm_struct *mm; - nodemask_t from; - nodemask_t to; -}; - -typedef enum { - FILE_MEMORY_MIGRATE = 0, - FILE_CPULIST = 1, - FILE_MEMLIST = 2, - FILE_EFFECTIVE_CPULIST = 3, - FILE_EFFECTIVE_MEMLIST = 4, - FILE_SUBPARTS_CPULIST = 5, - FILE_CPU_EXCLUSIVE = 6, - FILE_MEM_EXCLUSIVE = 7, - FILE_MEM_HARDWALL = 8, - FILE_SCHED_LOAD_BALANCE = 9, - FILE_PARTITION_ROOT = 10, - FILE_SCHED_RELAX_DOMAIN_LEVEL = 11, - FILE_MEMORY_PRESSURE_ENABLED = 12, - FILE_MEMORY_PRESSURE = 13, - FILE_SPREAD_PAGE = 14, - FILE_SPREAD_SLAB = 15, -} cpuset_filetype_t; - -struct kernel_pkey_query { - __u32 supported_ops; - __u32 key_size; - __u16 max_data_size; - __u16 max_sig_size; - __u16 max_enc_size; - __u16 max_dec_size; -}; - -enum kernel_pkey_operation { - kernel_pkey_encrypt = 0, - kernel_pkey_decrypt = 1, - kernel_pkey_sign = 2, - kernel_pkey_verify = 3, -}; - -struct kernel_pkey_params { - struct key *key; - const char *encoding; - const char *hash_algo; - char *info; - __u32 in_len; - union { - __u32 out_len; - __u32 in2_len; - }; - enum kernel_pkey_operation op: 8; -}; - -struct key_preparsed_payload { - char *description; - union key_payload payload; - const void *data; - size_t datalen; - size_t quotalen; - time64_t expiry; -}; - -struct key_match_data { - bool (*cmp)(const struct key *, const struct key_match_data *); - const void *raw_data; - void *preparsed; - unsigned int lookup_type; -}; - -struct idmap_key { - bool map_up; - u32 id; - u32 count; -}; - -struct cpu_stop_done { - atomic_t nr_todo; - int ret; - struct completion completion; -}; - -struct cpu_stopper { - struct task_struct *thread; - raw_spinlock_t lock; - bool enabled; - struct list_head works; - struct cpu_stop_work stop_work; -}; - -enum multi_stop_state { - MULTI_STOP_NONE = 0, - MULTI_STOP_PREPARE = 1, - MULTI_STOP_DISABLE_IRQ = 2, - MULTI_STOP_RUN = 3, - MULTI_STOP_EXIT = 4, -}; - -struct multi_stop_data { - cpu_stop_fn_t fn; - void *data; - unsigned int num_threads; - const struct cpumask *active_cpus; - enum multi_stop_state state; - atomic_t thread_ack; -}; - -typedef int __kernel_mqd_t; - -typedef __kernel_mqd_t mqd_t; - -enum audit_state { - AUDIT_DISABLED = 0, - AUDIT_BUILD_CONTEXT = 1, - AUDIT_RECORD_CONTEXT = 2, -}; - -struct audit_cap_data { - kernel_cap_t permitted; - kernel_cap_t inheritable; - union { - unsigned int fE; - kernel_cap_t effective; - }; - kernel_cap_t ambient; - kuid_t rootid; -}; - -struct audit_names { - struct list_head list; - struct filename *name; - int name_len; - bool hidden; - long unsigned int ino; - dev_t dev; - umode_t mode; - kuid_t uid; - kgid_t gid; - dev_t rdev; - u32 osid; - struct audit_cap_data fcap; - unsigned int fcap_ver; - unsigned char type; - bool should_free; -}; - -struct mq_attr { - __kernel_long_t mq_flags; - __kernel_long_t mq_maxmsg; - __kernel_long_t mq_msgsize; - __kernel_long_t mq_curmsgs; - __kernel_long_t __reserved[4]; -}; - -struct audit_proctitle { - int len; - char *value; -}; - -struct audit_aux_data; - -struct __kernel_sockaddr_storage; - -struct audit_tree_refs; - -struct audit_context { - int dummy; - int in_syscall; - enum audit_state state; - enum audit_state current_state; - unsigned int serial; - int major; - struct timespec64 ctime; - long unsigned int argv[4]; - long int return_code; - u64 prio; - int return_valid; - struct audit_names preallocated_names[5]; - int name_count; - struct list_head names_list; - char *filterkey; - struct path pwd; - struct audit_aux_data *aux; - struct audit_aux_data *aux_pids; - struct __kernel_sockaddr_storage *sockaddr; - size_t sockaddr_len; - pid_t pid; - pid_t ppid; - kuid_t uid; - kuid_t euid; - kuid_t suid; - kuid_t fsuid; - kgid_t gid; - kgid_t egid; - kgid_t sgid; - kgid_t fsgid; - long unsigned int personality; - int arch; - pid_t target_pid; - kuid_t target_auid; - kuid_t target_uid; - unsigned int target_sessionid; - u32 target_sid; - char target_comm[16]; - struct audit_tree_refs *trees; - struct audit_tree_refs *first_trees; - struct list_head killed_trees; - int tree_count; - int type; - union { - struct { - int nargs; - long int args[6]; - } socketcall; - struct { - kuid_t uid; - kgid_t gid; - umode_t mode; - u32 osid; - int has_perm; - uid_t perm_uid; - gid_t perm_gid; - umode_t perm_mode; - long unsigned int qbytes; - } ipc; - struct { - mqd_t mqdes; - struct mq_attr mqstat; - } mq_getsetattr; - struct { - mqd_t mqdes; - int sigev_signo; - } mq_notify; - struct { - mqd_t mqdes; - size_t msg_len; - unsigned int msg_prio; - struct timespec64 abs_timeout; - } mq_sendrecv; - struct { - int oflag; - umode_t mode; - struct mq_attr attr; - } mq_open; - struct { - pid_t pid; - struct audit_cap_data cap; - } capset; - struct { - int fd; - int flags; - } mmap; - struct { - int argc; - } execve; - struct { - char *name; - } module; - }; - int fds[2]; - struct audit_proctitle proctitle; -}; - -struct __kernel_sockaddr_storage { - union { - struct { - __kernel_sa_family_t ss_family; - char __data[126]; - }; - void *__align; - }; -}; - -enum audit_nlgrps { - AUDIT_NLGRP_NONE = 0, - AUDIT_NLGRP_READLOG = 1, - __AUDIT_NLGRP_MAX = 2, -}; - -struct audit_status { - __u32 mask; - __u32 enabled; - __u32 failure; - __u32 pid; - __u32 rate_limit; - __u32 backlog_limit; - __u32 lost; - __u32 backlog; - union { - __u32 version; - __u32 feature_bitmap; - }; - __u32 backlog_wait_time; - __u32 backlog_wait_time_actual; -}; - -struct audit_features { - __u32 vers; - __u32 mask; - __u32 features; - __u32 lock; -}; - -struct audit_tty_status { - __u32 enabled; - __u32 log_passwd; -}; - -struct audit_sig_info { - uid_t uid; - pid_t pid; - char ctx[0]; -}; - -struct net_generic { - union { - struct { - unsigned int len; - struct callback_head rcu; - } s; - void *ptr[0]; - }; -}; - -struct pernet_operations { - struct list_head list; - int (*init)(struct net *); - void (*pre_exit)(struct net *); - void (*exit)(struct net *); - void (*exit_batch)(struct list_head *); - unsigned int *id; - size_t size; -}; - -struct scm_creds { - u32 pid; - kuid_t uid; - kgid_t gid; -}; - -struct netlink_skb_parms { - struct scm_creds creds; - __u32 portid; - __u32 dst_group; - __u32 flags; - struct sock *sk; - bool nsid_is_set; - int nsid; -}; - -struct netlink_kernel_cfg { - unsigned int groups; - unsigned int flags; - void (*input)(struct sk_buff *); - struct mutex *cb_mutex; - int (*bind)(struct net *, int); - void (*unbind)(struct net *, int); - bool (*compare)(struct net *, struct sock *); -}; - -struct audit_netlink_list { - __u32 portid; - struct net *net; - struct sk_buff_head q; -}; - -struct audit_net { - struct sock *sk; -}; - -struct auditd_connection { - struct pid *pid; - u32 portid; - struct net *net; - struct callback_head rcu; -}; - -struct audit_ctl_mutex { - struct mutex lock; - void *owner; -}; - -struct audit_buffer { - struct sk_buff *skb; - struct audit_context *ctx; - gfp_t gfp_mask; -}; - -struct audit_reply { - __u32 portid; - struct net *net; - struct sk_buff *skb; -}; - -enum { - Audit_equal = 0, - Audit_not_equal = 1, - Audit_bitmask = 2, - Audit_bittest = 3, - Audit_lt = 4, - Audit_gt = 5, - Audit_le = 6, - Audit_ge = 7, - Audit_bad = 8, -}; - -struct audit_rule_data { - __u32 flags; - __u32 action; - __u32 field_count; - __u32 mask[64]; - __u32 fields[64]; - __u32 values[64]; - __u32 fieldflags[64]; - __u32 buflen; - char buf[0]; -}; - -struct audit_field; - -struct audit_watch; - -struct audit_tree; - -struct audit_fsnotify_mark; - -struct audit_krule { - u32 pflags; - u32 flags; - u32 listnr; - u32 action; - u32 mask[64]; - u32 buflen; - u32 field_count; - char *filterkey; - struct audit_field *fields; - struct audit_field *arch_f; - struct audit_field *inode_f; - struct audit_watch *watch; - struct audit_tree *tree; - struct audit_fsnotify_mark *exe; - struct list_head rlist; - struct list_head list; - u64 prio; -}; - -struct audit_field { - u32 type; - union { - u32 val; - kuid_t uid; - kgid_t gid; - struct { - char *lsm_str; - void *lsm_rule; - }; - }; - u32 op; -}; - -struct audit_entry { - struct list_head list; - struct callback_head rcu; - struct audit_krule rule; -}; - -struct audit_buffer___2; - -typedef int __kernel_key_t; - -typedef __kernel_key_t key_t; - -struct kern_ipc_perm { - spinlock_t lock; - bool deleted; - int id; - key_t key; - kuid_t uid; - kgid_t gid; - kuid_t cuid; - kgid_t cgid; - umode_t mode; - long unsigned int seq; - void *security; - struct rhash_head khtnode; - struct callback_head rcu; - refcount_t refcount; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct cpu_vfs_cap_data { - __u32 magic_etc; - kernel_cap_t permitted; - kernel_cap_t inheritable; - kuid_t rootid; -}; - -typedef struct fsnotify_mark_connector *fsnotify_connp_t; - -struct fsnotify_mark_connector { - spinlock_t lock; - short unsigned int type; - short unsigned int flags; - __kernel_fsid_t fsid; - union { - fsnotify_connp_t *obj; - struct fsnotify_mark_connector *destroy_next; - }; - struct hlist_head list; -}; - -enum audit_nfcfgop { - AUDIT_XT_OP_REGISTER = 0, - AUDIT_XT_OP_REPLACE = 1, - AUDIT_XT_OP_UNREGISTER = 2, - AUDIT_NFT_OP_TABLE_REGISTER = 3, - AUDIT_NFT_OP_TABLE_UNREGISTER = 4, - AUDIT_NFT_OP_CHAIN_REGISTER = 5, - AUDIT_NFT_OP_CHAIN_UNREGISTER = 6, - AUDIT_NFT_OP_RULE_REGISTER = 7, - AUDIT_NFT_OP_RULE_UNREGISTER = 8, - AUDIT_NFT_OP_SET_REGISTER = 9, - AUDIT_NFT_OP_SET_UNREGISTER = 10, - AUDIT_NFT_OP_SETELEM_REGISTER = 11, - AUDIT_NFT_OP_SETELEM_UNREGISTER = 12, - AUDIT_NFT_OP_GEN_REGISTER = 13, - AUDIT_NFT_OP_OBJ_REGISTER = 14, - AUDIT_NFT_OP_OBJ_UNREGISTER = 15, - AUDIT_NFT_OP_OBJ_RESET = 16, - AUDIT_NFT_OP_FLOWTABLE_REGISTER = 17, - AUDIT_NFT_OP_FLOWTABLE_UNREGISTER = 18, - AUDIT_NFT_OP_INVALID = 19, -}; - -enum fsnotify_obj_type { - FSNOTIFY_OBJ_TYPE_INODE = 0, - FSNOTIFY_OBJ_TYPE_PARENT = 1, - FSNOTIFY_OBJ_TYPE_VFSMOUNT = 2, - FSNOTIFY_OBJ_TYPE_SB = 3, - FSNOTIFY_OBJ_TYPE_COUNT = 4, - FSNOTIFY_OBJ_TYPE_DETACHED = 4, -}; - -struct audit_aux_data { - struct audit_aux_data *next; - int type; -}; - -struct audit_chunk; - -struct audit_tree_refs { - struct audit_tree_refs *next; - struct audit_chunk *c[31]; -}; - -struct audit_aux_data_pids { - struct audit_aux_data d; - pid_t target_pid[16]; - kuid_t target_auid[16]; - kuid_t target_uid[16]; - unsigned int target_sessionid[16]; - u32 target_sid[16]; - char target_comm[256]; - int pid_count; -}; - -struct audit_aux_data_bprm_fcaps { - struct audit_aux_data d; - struct audit_cap_data fcap; - unsigned int fcap_ver; - struct audit_cap_data old_pcap; - struct audit_cap_data new_pcap; -}; - -struct audit_nfcfgop_tab { - enum audit_nfcfgop op; - const char *s; -}; - -struct audit_parent; - -struct audit_watch { - refcount_t count; - dev_t dev; - char *path; - long unsigned int ino; - struct audit_parent *parent; - struct list_head wlist; - struct list_head rules; -}; - -struct fsnotify_group; - -struct fsnotify_iter_info; - -struct fsnotify_mark; - -struct fsnotify_event; - -struct fsnotify_ops { - int (*handle_event)(struct fsnotify_group *, u32, const void *, int, struct inode *, const struct qstr *, u32, struct fsnotify_iter_info *); - int (*handle_inode_event)(struct fsnotify_mark *, u32, struct inode *, struct inode *, const struct qstr *, u32); - void (*free_group_priv)(struct fsnotify_group *); - void (*freeing_mark)(struct fsnotify_mark *, struct fsnotify_group *); - void (*free_event)(struct fsnotify_event *); - void (*free_mark)(struct fsnotify_mark *); -}; - -struct inotify_group_private_data { - spinlock_t idr_lock; - struct idr idr; - struct ucounts *ucounts; -}; - -struct fanotify_group_private_data { - struct list_head access_list; - wait_queue_head_t access_waitq; - int flags; - int f_flags; - unsigned int max_marks; - struct user_struct *user; -}; - -struct fsnotify_group { - const struct fsnotify_ops *ops; - refcount_t refcnt; - spinlock_t notification_lock; - struct list_head notification_list; - wait_queue_head_t notification_waitq; - unsigned int q_len; - unsigned int max_events; - unsigned int priority; - bool shutdown; - struct mutex mark_mutex; - atomic_t num_marks; - atomic_t user_waits; - struct list_head marks_list; - struct fasync_struct *fsn_fa; - struct fsnotify_event *overflow_event; - struct mem_cgroup *memcg; - union { - void *private; - struct inotify_group_private_data inotify_data; - struct fanotify_group_private_data fanotify_data; - }; -}; - -struct fsnotify_iter_info { - struct fsnotify_mark *marks[4]; - unsigned int report_mask; - int srcu_idx; -}; - -struct fsnotify_mark { - __u32 mask; - refcount_t refcnt; - struct fsnotify_group *group; - struct list_head g_list; - spinlock_t lock; - struct hlist_node obj_list; - struct fsnotify_mark_connector *connector; - __u32 ignored_mask; - unsigned int flags; -}; - -struct fsnotify_event { - struct list_head list; - long unsigned int objectid; -}; - -struct audit_parent { - struct list_head watches; - struct fsnotify_mark mark; -}; - -struct audit_fsnotify_mark { - dev_t dev; - long unsigned int ino; - char *path; - struct fsnotify_mark mark; - struct audit_krule *rule; -}; - -struct audit_chunk___2; - -struct audit_tree { - refcount_t count; - int goner; - struct audit_chunk___2 *root; - struct list_head chunks; - struct list_head rules; - struct list_head list; - struct list_head same_root; - struct callback_head head; - char pathname[0]; -}; - -struct node { - struct list_head list; - struct audit_tree *owner; - unsigned int index; -}; - -struct audit_chunk___2 { - struct list_head hash; - long unsigned int key; - struct fsnotify_mark *mark; - struct list_head trees; - int count; - atomic_long_t refs; - struct callback_head head; - struct node owners[0]; -}; - -struct audit_tree_mark { - struct fsnotify_mark mark; - struct audit_chunk___2 *chunk; -}; - -enum { - HASH_SIZE = 128, -}; - -struct kprobe_blacklist_entry { - struct list_head list; - long unsigned int start_addr; - long unsigned int end_addr; -}; - -enum perf_record_ksymbol_type { - PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0, - PERF_RECORD_KSYMBOL_TYPE_BPF = 1, - PERF_RECORD_KSYMBOL_TYPE_OOL = 2, - PERF_RECORD_KSYMBOL_TYPE_MAX = 3, -}; - -struct kprobe_insn_page { - struct list_head list; - kprobe_opcode_t *insns; - struct kprobe_insn_cache *cache; - int nused; - int ngarbage; - char slot_used[0]; -}; - -enum kprobe_slot_state { - SLOT_CLEAN = 0, - SLOT_DIRTY = 1, - SLOT_USED = 2, -}; - -struct serial_icounter_struct { - int cts; - int dsr; - int rng; - int dcd; - int rx; - int tx; - int frame; - int overrun; - int parity; - int brk; - int buf_overrun; - int reserved[9]; -}; - -struct serial_struct { - int type; - int line; - unsigned int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - short unsigned int close_delay; - char io_type; - char reserved_char[1]; - int hub6; - short unsigned int closing_wait; - short unsigned int closing_wait2; - unsigned char *iomem_base; - short unsigned int iomem_reg_shift; - unsigned int port_high; - long unsigned int iomap_base; -}; - -struct kgdb_io { - const char *name; - int (*read_char)(); - void (*write_char)(u8); - void (*flush)(); - int (*init)(); - void (*deinit)(); - void (*pre_exception)(); - void (*post_exception)(); - struct console *cons; -}; - -enum { - KDB_NOT_INITIALIZED = 0, - KDB_INIT_EARLY = 1, - KDB_INIT_FULL = 2, -}; - -struct kgdb_state { - int ex_vector; - int signo; - int err_code; - int cpu; - int pass_exception; - long unsigned int thr_query; - long unsigned int threadid; - long int kgdb_usethreadid; - struct pt_regs *linux_regs; - atomic_t *send_ready; -}; - -struct debuggerinfo_struct { - void *debuggerinfo; - struct task_struct *task; - int exception_state; - int ret_state; - int irq_depth; - int enter_kgdb; - bool rounding_up; -}; - -typedef int (*get_char_func)(); - -typedef enum { - KDB_ENABLE_ALL = 1, - KDB_ENABLE_MEM_READ = 2, - KDB_ENABLE_MEM_WRITE = 4, - KDB_ENABLE_REG_READ = 8, - KDB_ENABLE_REG_WRITE = 16, - KDB_ENABLE_INSPECT = 32, - KDB_ENABLE_FLOW_CTRL = 64, - KDB_ENABLE_SIGNAL = 128, - KDB_ENABLE_REBOOT = 256, - KDB_ENABLE_ALWAYS_SAFE = 512, - KDB_ENABLE_MASK = 1023, - KDB_ENABLE_ALL_NO_ARGS = 1024, - KDB_ENABLE_MEM_READ_NO_ARGS = 2048, - KDB_ENABLE_MEM_WRITE_NO_ARGS = 4096, - KDB_ENABLE_REG_READ_NO_ARGS = 8192, - KDB_ENABLE_REG_WRITE_NO_ARGS = 16384, - KDB_ENABLE_INSPECT_NO_ARGS = 32768, - KDB_ENABLE_FLOW_CTRL_NO_ARGS = 65536, - KDB_ENABLE_SIGNAL_NO_ARGS = 131072, - KDB_ENABLE_REBOOT_NO_ARGS = 262144, - KDB_ENABLE_ALWAYS_SAFE_NO_ARGS = 524288, - KDB_ENABLE_MASK_NO_ARGS = 1047552, - KDB_REPEAT_NO_ARGS = 1073741824, - KDB_REPEAT_WITH_ARGS = 2147483648, -} kdb_cmdflags_t; - -typedef int (*kdb_func_t)(int, const char **); - -typedef enum { - KDB_REASON_ENTER = 1, - KDB_REASON_ENTER_SLAVE = 2, - KDB_REASON_BREAK = 3, - KDB_REASON_DEBUG = 4, - KDB_REASON_OOPS = 5, - KDB_REASON_SWITCH = 6, - KDB_REASON_KEYBOARD = 7, - KDB_REASON_NMI = 8, - KDB_REASON_RECURSE = 9, - KDB_REASON_SSTEP = 10, - KDB_REASON_SYSTEM_NMI = 11, -} kdb_reason_t; - -struct __ksymtab { - long unsigned int value; - const char *mod_name; - long unsigned int mod_start; - long unsigned int mod_end; - const char *sec_name; - long unsigned int sec_start; - long unsigned int sec_end; - const char *sym_name; - long unsigned int sym_start; - long unsigned int sym_end; -}; - -typedef struct __ksymtab kdb_symtab_t; - -struct _kdbtab { - char *cmd_name; - kdb_func_t cmd_func; - char *cmd_usage; - char *cmd_help; - short int cmd_minlen; - kdb_cmdflags_t cmd_flags; -}; - -typedef struct _kdbtab kdbtab_t; - -typedef enum { - KDB_DB_BPT = 0, - KDB_DB_SS = 1, - KDB_DB_SSBPT = 2, - KDB_DB_NOBPT = 3, -} kdb_dbtrap_t; - -struct _kdbmsg { - int km_diag; - char *km_msg; -}; - -typedef struct _kdbmsg kdbmsg_t; - -struct defcmd_set { - int count; - bool usable; - char *name; - char *usage; - char *help; - char **command; -}; - -struct debug_alloc_header { - u32 next; - u32 size; - void *caller; -}; - -struct _kdb_bp { - long unsigned int bp_addr; - unsigned int bp_free: 1; - unsigned int bp_enabled: 1; - unsigned int bp_type: 4; - unsigned int bp_installed: 1; - unsigned int bp_delay: 1; - unsigned int bp_delayed: 1; - unsigned int bph_length; -}; - -typedef struct _kdb_bp kdb_bp_t; - -typedef short unsigned int u_short; - -struct seccomp_data { - int nr; - __u32 arch; - __u64 instruction_pointer; - __u64 args[6]; -}; - -struct seccomp_notif_sizes { - __u16 seccomp_notif; - __u16 seccomp_notif_resp; - __u16 seccomp_data; -}; - -struct seccomp_notif { - __u64 id; - __u32 pid; - __u32 flags; - struct seccomp_data data; -}; - -struct seccomp_notif_resp { - __u64 id; - __s64 val; - __s32 error; - __u32 flags; -}; - -struct seccomp_notif_addfd { - __u64 id; - __u32 flags; - __u32 srcfd; - __u32 newfd; - __u32 newfd_flags; -}; - -struct notification; - -struct seccomp_filter { - refcount_t refs; - refcount_t users; - bool log; - struct seccomp_filter *prev; - struct bpf_prog *prog; - struct notification *notif; - struct mutex notify_lock; - wait_queue_head_t wqh; -}; - -struct ctl_path { - const char *procname; -}; - -struct sock_fprog { - short unsigned int len; - struct sock_filter *filter; -}; - -struct compat_sock_fprog { - u16 len; - compat_uptr_t filter; -}; - -enum notify_state { - SECCOMP_NOTIFY_INIT = 0, - SECCOMP_NOTIFY_SENT = 1, - SECCOMP_NOTIFY_REPLIED = 2, -}; - -struct seccomp_knotif { - struct task_struct *task; - u64 id; - const struct seccomp_data *data; - enum notify_state state; - int error; - long int val; - u32 flags; - struct completion ready; - struct list_head list; - struct list_head addfd; -}; - -struct seccomp_kaddfd { - struct file *file; - int fd; - unsigned int flags; - int ret; - struct completion completion; - struct list_head list; -}; - -struct notification { - struct semaphore request; - u64 next_id; - struct list_head notifications; -}; - -struct seccomp_log_name { - u32 log; - const char *name; -}; - -struct rchan; - -struct rchan_buf { - void *start; - void *data; - size_t offset; - size_t subbufs_produced; - size_t subbufs_consumed; - struct rchan *chan; - wait_queue_head_t read_wait; - struct irq_work wakeup_work; - struct dentry *dentry; - struct kref kref; - struct page **page_array; - unsigned int page_count; - unsigned int finalized; - size_t *padding; - size_t prev_padding; - size_t bytes_consumed; - size_t early_bytes; - unsigned int cpu; - long: 32; - long: 64; - long: 64; - long: 64; -}; - -struct rchan_callbacks; - -struct rchan { - u32 version; - size_t subbuf_size; - size_t n_subbufs; - size_t alloc_size; - struct rchan_callbacks *cb; - struct kref kref; - void *private_data; - size_t last_toobig; - struct rchan_buf **buf; - int is_global; - struct list_head list; - struct dentry *parent; - int has_base_filename; - char base_filename[255]; -}; - -struct rchan_callbacks { - int (*subbuf_start)(struct rchan_buf *, void *, void *, size_t); - void (*buf_mapped)(struct rchan_buf *, struct file *); - void (*buf_unmapped)(struct rchan_buf *, struct file *); - struct dentry * (*create_buf_file)(const char *, struct dentry *, umode_t, struct rchan_buf *, int *); - int (*remove_buf_file)(struct dentry *); -}; - -struct partial_page { - unsigned int offset; - unsigned int len; - long unsigned int private; -}; - -struct splice_pipe_desc { - struct page **pages; - struct partial_page *partial; - int nr_pages; - unsigned int nr_pages_max; - const struct pipe_buf_operations *ops; - void (*spd_release)(struct splice_pipe_desc *, unsigned int); -}; - -struct rchan_percpu_buf_dispatcher { - struct rchan_buf *buf; - struct dentry *dentry; -}; - -enum { - TASKSTATS_TYPE_UNSPEC = 0, - TASKSTATS_TYPE_PID = 1, - TASKSTATS_TYPE_TGID = 2, - TASKSTATS_TYPE_STATS = 3, - TASKSTATS_TYPE_AGGR_PID = 4, - TASKSTATS_TYPE_AGGR_TGID = 5, - TASKSTATS_TYPE_NULL = 6, - __TASKSTATS_TYPE_MAX = 7, -}; - -enum { - TASKSTATS_CMD_ATTR_UNSPEC = 0, - TASKSTATS_CMD_ATTR_PID = 1, - TASKSTATS_CMD_ATTR_TGID = 2, - TASKSTATS_CMD_ATTR_REGISTER_CPUMASK = 3, - TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 4, - __TASKSTATS_CMD_ATTR_MAX = 5, -}; - -enum { - CGROUPSTATS_CMD_UNSPEC = 3, - CGROUPSTATS_CMD_GET = 4, - CGROUPSTATS_CMD_NEW = 5, - __CGROUPSTATS_CMD_MAX = 6, -}; - -enum { - CGROUPSTATS_TYPE_UNSPEC = 0, - CGROUPSTATS_TYPE_CGROUP_STATS = 1, - __CGROUPSTATS_TYPE_MAX = 2, -}; - -enum { - CGROUPSTATS_CMD_ATTR_UNSPEC = 0, - CGROUPSTATS_CMD_ATTR_FD = 1, - __CGROUPSTATS_CMD_ATTR_MAX = 2, -}; - -struct genlmsghdr { - __u8 cmd; - __u8 version; - __u16 reserved; -}; - -enum { - NLA_UNSPEC = 0, - NLA_U8 = 1, - NLA_U16 = 2, - NLA_U32 = 3, - NLA_U64 = 4, - NLA_STRING = 5, - NLA_FLAG = 6, - NLA_MSECS = 7, - NLA_NESTED = 8, - NLA_NESTED_ARRAY = 9, - NLA_NUL_STRING = 10, - NLA_BINARY = 11, - NLA_S8 = 12, - NLA_S16 = 13, - NLA_S32 = 14, - NLA_S64 = 15, - NLA_BITFIELD32 = 16, - NLA_REJECT = 17, - __NLA_TYPE_MAX = 18, -}; - -struct genl_multicast_group { - char name[16]; -}; - -struct genl_ops; - -struct genl_info; - -struct genl_small_ops; - -struct genl_family { - int id; - unsigned int hdrsize; - char name[16]; - unsigned int version; - unsigned int maxattr; - unsigned int mcgrp_offset; - u8 netnsok: 1; - u8 parallel_ops: 1; - u8 n_ops; - u8 n_small_ops; - u8 n_mcgrps; - const struct nla_policy *policy; - int (*pre_doit)(const struct genl_ops *, struct sk_buff *, struct genl_info *); - void (*post_doit)(const struct genl_ops *, struct sk_buff *, struct genl_info *); - const struct genl_ops *ops; - const struct genl_small_ops *small_ops; - const struct genl_multicast_group *mcgrps; - struct module *module; -}; - -struct genl_ops { - int (*doit)(struct sk_buff *, struct genl_info *); - int (*start)(struct netlink_callback *); - int (*dumpit)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - const struct nla_policy *policy; - unsigned int maxattr; - u8 cmd; - u8 internal_flags; - u8 flags; - u8 validate; -}; - -struct genl_info { - u32 snd_seq; - u32 snd_portid; - struct nlmsghdr *nlhdr; - struct genlmsghdr *genlhdr; - void *userhdr; - struct nlattr **attrs; - possible_net_t _net; - void *user_ptr[2]; - struct netlink_ext_ack *extack; -}; - -struct genl_small_ops { - int (*doit)(struct sk_buff *, struct genl_info *); - int (*dumpit)(struct sk_buff *, struct netlink_callback *); - u8 cmd; - u8 internal_flags; - u8 flags; - u8 validate; -}; - -enum genl_validate_flags { - GENL_DONT_VALIDATE_STRICT = 1, - GENL_DONT_VALIDATE_DUMP = 2, - GENL_DONT_VALIDATE_DUMP_STRICT = 4, -}; - -struct listener { - struct list_head list; - pid_t pid; - char valid; -}; - -struct listener_list { - struct rw_semaphore sem; - struct list_head list; -}; - -enum actions { - REGISTER = 0, - DEREGISTER = 1, - CPU_DONT_CARE = 2, -}; - -struct tp_module { - struct list_head list; - struct module *mod; -}; - -enum tp_func_state { - TP_FUNC_0 = 0, - TP_FUNC_1 = 1, - TP_FUNC_2 = 2, - TP_FUNC_N = 3, -}; - -enum tp_transition_sync { - TP_TRANSITION_SYNC_1_0_1 = 0, - TP_TRANSITION_SYNC_N_2_1 = 1, - _NR_TP_TRANSITION_SYNC = 2, -}; - -struct tp_transition_snapshot { - long unsigned int rcu; - long unsigned int srcu; - bool ongoing; -}; - -struct tp_probes { - struct callback_head rcu; - struct tracepoint_func probes[0]; -}; - -typedef int (*cmp_func_t)(const void *, const void *); - -enum { - FTRACE_OPS_FL_ENABLED = 1, - FTRACE_OPS_FL_DYNAMIC = 2, - FTRACE_OPS_FL_SAVE_REGS = 4, - FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 8, - FTRACE_OPS_FL_RECURSION_SAFE = 16, - FTRACE_OPS_FL_STUB = 32, - FTRACE_OPS_FL_INITIALIZED = 64, - FTRACE_OPS_FL_DELETED = 128, - FTRACE_OPS_FL_ADDING = 256, - FTRACE_OPS_FL_REMOVING = 512, - FTRACE_OPS_FL_MODIFYING = 1024, - FTRACE_OPS_FL_ALLOC_TRAMP = 2048, - FTRACE_OPS_FL_IPMODIFY = 4096, - FTRACE_OPS_FL_PID = 8192, - FTRACE_OPS_FL_RCU = 16384, - FTRACE_OPS_FL_TRACE_ARRAY = 32768, - FTRACE_OPS_FL_PERMANENT = 65536, - FTRACE_OPS_FL_DIRECT = 131072, -}; - -struct ftrace_hash { - long unsigned int size_bits; - struct hlist_head *buckets; - long unsigned int count; - long unsigned int flags; - struct callback_head rcu; -}; - -struct ftrace_func_entry { - struct hlist_node hlist; - long unsigned int ip; - long unsigned int direct; -}; - -enum ftrace_bug_type { - FTRACE_BUG_UNKNOWN = 0, - FTRACE_BUG_INIT = 1, - FTRACE_BUG_NOP = 2, - FTRACE_BUG_CALL = 3, - FTRACE_BUG_UPDATE = 4, -}; - -enum { - FTRACE_FL_ENABLED = 2147483648, - FTRACE_FL_REGS = 1073741824, - FTRACE_FL_REGS_EN = 536870912, - FTRACE_FL_TRAMP = 268435456, - FTRACE_FL_TRAMP_EN = 134217728, - FTRACE_FL_IPMODIFY = 67108864, - FTRACE_FL_DISABLED = 33554432, - FTRACE_FL_DIRECT = 16777216, - FTRACE_FL_DIRECT_EN = 8388608, -}; - -enum { - FTRACE_UPDATE_IGNORE = 0, - FTRACE_UPDATE_MAKE_CALL = 1, - FTRACE_UPDATE_MODIFY_CALL = 2, - FTRACE_UPDATE_MAKE_NOP = 3, -}; - -enum { - FTRACE_ITER_FILTER = 1, - FTRACE_ITER_NOTRACE = 2, - FTRACE_ITER_PRINTALL = 4, - FTRACE_ITER_DO_PROBES = 8, - FTRACE_ITER_PROBE = 16, - FTRACE_ITER_MOD = 32, - FTRACE_ITER_ENABLED = 64, -}; - -struct ftrace_graph_ent { - long unsigned int func; - int depth; -} __attribute__((packed)); - -struct ftrace_graph_ret { - long unsigned int func; - long unsigned int overrun; - long long unsigned int calltime; - long long unsigned int rettime; - int depth; -} __attribute__((packed)); - -typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); - -typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); - -struct fgraph_ops { - trace_func_graph_ent_t entryfunc; - trace_func_graph_ret_t retfunc; -}; - -struct prog_entry; - -struct event_filter { - struct prog_entry *prog; - char *filter_string; -}; - -struct trace_array_cpu; - -struct array_buffer { - struct trace_array *tr; - struct trace_buffer *buffer; - struct trace_array_cpu *data; - u64 time_start; - int cpu; -}; - -struct trace_pid_list; - -struct trace_options; - -struct cond_snapshot; - -struct trace_array { - struct list_head list; - char *name; - struct array_buffer array_buffer; - struct array_buffer max_buffer; - bool allocated_snapshot; - long unsigned int max_latency; - struct dentry *d_max_latency; - struct work_struct fsnotify_work; - struct irq_work fsnotify_irqwork; - struct trace_pid_list *filtered_pids; - struct trace_pid_list *filtered_no_pids; - arch_spinlock_t max_lock; - int buffer_disabled; - int stop_count; - int clock_id; - int nr_topts; - bool clear_trace; - int buffer_percent; - unsigned int n_err_log_entries; - struct tracer *current_trace; - unsigned int trace_flags; - unsigned char trace_flags_index[32]; - unsigned int flags; - raw_spinlock_t start_lock; - struct list_head err_log; - struct dentry *dir; - struct dentry *options; - struct dentry *percpu_dir; - struct dentry *event_dir; - struct trace_options *topts; - struct list_head systems; - struct list_head events; - struct trace_event_file *trace_marker_file; - cpumask_var_t tracing_cpumask; - int ref; - int trace_ref; - struct ftrace_ops *ops; - struct trace_pid_list *function_pids; - struct trace_pid_list *function_no_pids; - struct list_head func_probes; - struct list_head mod_trace; - struct list_head mod_notrace; - int function_enabled; - int time_stamp_abs_ref; - struct list_head hist_vars; - struct cond_snapshot *cond_snapshot; -}; - -struct tracer_flags; - -struct tracer { - const char *name; - int (*init)(struct trace_array *); - void (*reset)(struct trace_array *); - void (*start)(struct trace_array *); - void (*stop)(struct trace_array *); - int (*update_thresh)(struct trace_array *); - void (*open)(struct trace_iterator *); - void (*pipe_open)(struct trace_iterator *); - void (*close)(struct trace_iterator *); - void (*pipe_close)(struct trace_iterator *); - ssize_t (*read)(struct trace_iterator *, struct file *, char *, size_t, loff_t *); - ssize_t (*splice_read)(struct trace_iterator *, struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); - void (*print_header)(struct seq_file *); - enum print_line_t (*print_line)(struct trace_iterator *); - int (*set_flag)(struct trace_array *, u32, u32, int); - int (*flag_changed)(struct trace_array *, u32, int); - struct tracer *next; - struct tracer_flags *flags; - int enabled; - bool print_max; - bool allow_instances; - bool use_max_tr; - bool noboot; -}; - -struct event_subsystem; - -struct trace_subsystem_dir { - struct list_head list; - struct event_subsystem *subsystem; - struct trace_array *tr; - struct dentry *entry; - int ref_count; - int nr_events; -}; - -struct trace_array_cpu { - atomic_t disabled; - void *buffer_page; - long unsigned int entries; - long unsigned int saved_latency; - long unsigned int critical_start; - long unsigned int critical_end; - long unsigned int critical_sequence; - long unsigned int nice; - long unsigned int policy; - long unsigned int rt_priority; - long unsigned int skipped_entries; - u64 preempt_timestamp; - pid_t pid; - kuid_t uid; - char comm[16]; - int ftrace_ignore_pid; - bool ignore_pid; -}; - -struct trace_option_dentry; - -struct trace_options { - struct tracer *tracer; - struct trace_option_dentry *topts; -}; - -struct tracer_opt; - -struct trace_option_dentry { - struct tracer_opt *opt; - struct tracer_flags *flags; - struct trace_array *tr; - struct dentry *entry; -}; - -struct trace_pid_list { - int pid_max; - long unsigned int *pids; -}; - -enum { - TRACE_PIDS = 1, - TRACE_NO_PIDS = 2, -}; - -typedef bool (*cond_update_fn_t)(struct trace_array *, void *); - -struct cond_snapshot { - void *cond_data; - cond_update_fn_t update; -}; - -enum { - TRACE_ARRAY_FL_GLOBAL = 1, -}; - -struct tracer_opt { - const char *name; - u32 bit; -}; - -struct tracer_flags { - u32 val; - struct tracer_opt *opts; - struct tracer *trace; -}; - -enum { - TRACE_FTRACE_BIT = 0, - TRACE_FTRACE_NMI_BIT = 1, - TRACE_FTRACE_IRQ_BIT = 2, - TRACE_FTRACE_SIRQ_BIT = 3, - TRACE_FTRACE_TRANSITION_BIT = 4, - TRACE_INTERNAL_BIT = 5, - TRACE_INTERNAL_NMI_BIT = 6, - TRACE_INTERNAL_IRQ_BIT = 7, - TRACE_INTERNAL_SIRQ_BIT = 8, - TRACE_INTERNAL_TRANSITION_BIT = 9, - TRACE_BRANCH_BIT = 10, - TRACE_IRQ_BIT = 11, - TRACE_GRAPH_BIT = 12, - TRACE_GRAPH_DEPTH_START_BIT = 13, - TRACE_GRAPH_DEPTH_END_BIT = 14, - TRACE_GRAPH_NOTRACE_BIT = 15, -}; - -enum { - TRACE_CTX_NMI = 0, - TRACE_CTX_IRQ = 1, - TRACE_CTX_SOFTIRQ = 2, - TRACE_CTX_NORMAL = 3, - TRACE_CTX_TRANSITION = 4, -}; - -struct ftrace_mod_load { - struct list_head list; - char *func; - char *module; - int enable; -}; - -enum { - FTRACE_HASH_FL_MOD = 1, -}; - -struct ftrace_func_command { - struct list_head list; - char *name; - int (*func)(struct trace_array *, struct ftrace_hash *, char *, char *, char *, int); -}; - -struct ftrace_probe_ops { - void (*func)(long unsigned int, long unsigned int, struct trace_array *, struct ftrace_probe_ops *, void *); - int (*init)(struct ftrace_probe_ops *, struct trace_array *, long unsigned int, void *, void **); - void (*free)(struct ftrace_probe_ops *, struct trace_array *, long unsigned int, void *); - int (*print)(struct seq_file *, long unsigned int, struct ftrace_probe_ops *, void *); -}; - -typedef int (*ftrace_mapper_func)(void *); - -struct trace_parser { - bool cont; - char *buffer; - unsigned int idx; - unsigned int size; -}; - -enum trace_iterator_bits { - TRACE_ITER_PRINT_PARENT_BIT = 0, - TRACE_ITER_SYM_OFFSET_BIT = 1, - TRACE_ITER_SYM_ADDR_BIT = 2, - TRACE_ITER_VERBOSE_BIT = 3, - TRACE_ITER_RAW_BIT = 4, - TRACE_ITER_HEX_BIT = 5, - TRACE_ITER_BIN_BIT = 6, - TRACE_ITER_BLOCK_BIT = 7, - TRACE_ITER_PRINTK_BIT = 8, - TRACE_ITER_ANNOTATE_BIT = 9, - TRACE_ITER_USERSTACKTRACE_BIT = 10, - TRACE_ITER_SYM_USEROBJ_BIT = 11, - TRACE_ITER_PRINTK_MSGONLY_BIT = 12, - TRACE_ITER_CONTEXT_INFO_BIT = 13, - TRACE_ITER_LATENCY_FMT_BIT = 14, - TRACE_ITER_RECORD_CMD_BIT = 15, - TRACE_ITER_RECORD_TGID_BIT = 16, - TRACE_ITER_OVERWRITE_BIT = 17, - TRACE_ITER_STOP_ON_FREE_BIT = 18, - TRACE_ITER_IRQ_INFO_BIT = 19, - TRACE_ITER_MARKERS_BIT = 20, - TRACE_ITER_EVENT_FORK_BIT = 21, - TRACE_ITER_PAUSE_ON_TRACE_BIT = 22, - TRACE_ITER_FUNCTION_BIT = 23, - TRACE_ITER_FUNC_FORK_BIT = 24, - TRACE_ITER_DISPLAY_GRAPH_BIT = 25, - TRACE_ITER_STACKTRACE_BIT = 26, - TRACE_ITER_LAST_BIT = 27, -}; - -struct event_subsystem { - struct list_head list; - const char *name; - struct event_filter *filter; - int ref_count; -}; - -enum regex_type { - MATCH_FULL = 0, - MATCH_FRONT_ONLY = 1, - MATCH_MIDDLE_ONLY = 2, - MATCH_END_ONLY = 3, - MATCH_GLOB = 4, - MATCH_INDEX = 5, -}; - -struct tracer_stat { - const char *name; - void * (*stat_start)(struct tracer_stat *); - void * (*stat_next)(void *, int); - cmp_func_t stat_cmp; - int (*stat_show)(struct seq_file *, void *); - void (*stat_release)(void *); - int (*stat_headers)(struct seq_file *); -}; - -enum { - FTRACE_MODIFY_ENABLE_FL = 1, - FTRACE_MODIFY_MAY_SLEEP_FL = 2, -}; - -struct ftrace_profile { - struct hlist_node node; - long unsigned int ip; - long unsigned int counter; - long long unsigned int time; - long long unsigned int time_squared; -}; - -struct ftrace_profile_page { - struct ftrace_profile_page *next; - long unsigned int index; - struct ftrace_profile records[0]; -}; - -struct ftrace_profile_stat { - atomic_t disabled; - struct hlist_head *hash; - struct ftrace_profile_page *pages; - struct ftrace_profile_page *start; - struct tracer_stat stat; -}; - -struct ftrace_func_probe { - struct ftrace_probe_ops *probe_ops; - struct ftrace_ops ops; - struct trace_array *tr; - struct list_head list; - void *data; - int ref; -}; - -struct ftrace_page { - struct ftrace_page *next; - struct dyn_ftrace *records; - int index; - int size; -}; - -struct ftrace_rec_iter { - struct ftrace_page *pg; - int index; -}; - -struct ftrace_iterator { - loff_t pos; - loff_t func_pos; - loff_t mod_pos; - struct ftrace_page *pg; - struct dyn_ftrace *func; - struct ftrace_func_probe *probe; - struct ftrace_func_entry *probe_entry; - struct trace_parser parser; - struct ftrace_hash *hash; - struct ftrace_ops *ops; - struct trace_array *tr; - struct list_head *mod_list; - int pidx; - int idx; - unsigned int flags; -}; - -struct ftrace_glob { - char *search; - unsigned int len; - int type; -}; - -struct ftrace_func_map { - struct ftrace_func_entry entry; - void *data; -}; - -struct ftrace_func_mapper { - struct ftrace_hash hash; -}; - -enum graph_filter_type { - GRAPH_FILTER_NOTRACE = 0, - GRAPH_FILTER_FUNCTION = 1, -}; - -struct ftrace_graph_data { - struct ftrace_hash *hash; - struct ftrace_func_entry *entry; - int idx; - enum graph_filter_type type; - struct ftrace_hash *new_hash; - const struct seq_operations *seq_ops; - struct trace_parser parser; -}; - -struct ftrace_mod_func { - struct list_head list; - char *name; - long unsigned int ip; - unsigned int size; -}; - -struct ftrace_mod_map { - struct callback_head rcu; - struct list_head list; - struct module *mod; - long unsigned int start_addr; - long unsigned int end_addr; - struct list_head funcs; - unsigned int num_funcs; -}; - -struct ftrace_init_func { - struct list_head list; - long unsigned int ip; -}; - -enum ring_buffer_type { - RINGBUF_TYPE_DATA_TYPE_LEN_MAX = 28, - RINGBUF_TYPE_PADDING = 29, - RINGBUF_TYPE_TIME_EXTEND = 30, - RINGBUF_TYPE_TIME_STAMP = 31, -}; - -enum ring_buffer_flags { - RB_FL_OVERWRITE = 1, -}; - -struct ring_buffer_per_cpu; - -struct buffer_page; - -struct ring_buffer_iter { - struct ring_buffer_per_cpu *cpu_buffer; - long unsigned int head; - long unsigned int next_event; - struct buffer_page *head_page; - struct buffer_page *cache_reader_page; - long unsigned int cache_read; - u64 read_stamp; - u64 page_stamp; - struct ring_buffer_event *event; - int missed_events; -}; - -struct rb_irq_work { - struct irq_work work; - wait_queue_head_t waiters; - wait_queue_head_t full_waiters; - bool waiters_pending; - bool full_waiters_pending; - bool wakeup_full; -}; - -struct trace_buffer___2 { - unsigned int flags; - int cpus; - atomic_t record_disabled; - cpumask_var_t cpumask; - struct lock_class_key *reader_lock_key; - struct mutex mutex; - struct ring_buffer_per_cpu **buffers; - struct hlist_node node; - u64 (*clock)(); - struct rb_irq_work irq_work; - bool time_stamp_abs; -}; - -enum { - RB_LEN_TIME_EXTEND = 8, - RB_LEN_TIME_STAMP = 8, -}; - -struct buffer_data_page { - u64 time_stamp; - local_t commit; - unsigned char data[0]; -}; - -struct buffer_page { - struct list_head list; - local_t write; - unsigned int read; - local_t entries; - long unsigned int real_end; - struct buffer_data_page *page; -}; - -struct rb_event_info { - u64 ts; - u64 delta; - u64 before; - u64 after; - long unsigned int length; - struct buffer_page *tail_page; - int add_timestamp; -}; - -enum { - RB_ADD_STAMP_NONE = 0, - RB_ADD_STAMP_EXTEND = 2, - RB_ADD_STAMP_ABSOLUTE = 4, - RB_ADD_STAMP_FORCE = 8, -}; - -enum { - RB_CTX_TRANSITION = 0, - RB_CTX_NMI = 1, - RB_CTX_IRQ = 2, - RB_CTX_SOFTIRQ = 3, - RB_CTX_NORMAL = 4, - RB_CTX_MAX = 5, -}; - -struct rb_time_struct { - local64_t time; -}; - -typedef struct rb_time_struct rb_time_t; - -struct ring_buffer_per_cpu { - int cpu; - atomic_t record_disabled; - atomic_t resize_disabled; - struct trace_buffer___2 *buffer; - raw_spinlock_t reader_lock; - arch_spinlock_t lock; - struct lock_class_key lock_key; - struct buffer_data_page *free_page; - long unsigned int nr_pages; - unsigned int current_context; - struct list_head *pages; - struct buffer_page *head_page; - struct buffer_page *tail_page; - struct buffer_page *commit_page; - struct buffer_page *reader_page; - long unsigned int lost_events; - long unsigned int last_overrun; - long unsigned int nest; - local_t entries_bytes; - local_t entries; - local_t overrun; - local_t commit_overrun; - local_t dropped_events; - local_t committing; - local_t commits; - local_t pages_touched; - local_t pages_read; - long int last_pages_touch; - size_t shortest_full; - long unsigned int read; - long unsigned int read_bytes; - rb_time_t write_stamp; - rb_time_t before_stamp; - u64 read_stamp; - long int nr_pages_to_update; - struct list_head new_pages; - struct work_struct update_pages_work; - struct completion update_done; - struct rb_irq_work irq_work; -}; - -struct trace_export { - struct trace_export *next; - void (*write)(struct trace_export *, const void *, unsigned int); - int flags; -}; - -enum fsnotify_data_type { - FSNOTIFY_EVENT_NONE = 0, - FSNOTIFY_EVENT_PATH = 1, - FSNOTIFY_EVENT_INODE = 2, -}; - -enum trace_iter_flags { - TRACE_FILE_LAT_FMT = 1, - TRACE_FILE_ANNOTATE = 2, - TRACE_FILE_TIME_IN_NS = 4, -}; - -enum event_trigger_type { - ETT_NONE = 0, - ETT_TRACE_ONOFF = 1, - ETT_SNAPSHOT = 2, - ETT_STACKTRACE = 4, - ETT_EVENT_ENABLE = 8, - ETT_EVENT_HIST = 16, - ETT_HIST_ENABLE = 32, -}; - -enum trace_type { - __TRACE_FIRST_TYPE = 0, - TRACE_FN = 1, - TRACE_CTX = 2, - TRACE_WAKE = 3, - TRACE_STACK = 4, - TRACE_PRINT = 5, - TRACE_BPRINT = 6, - TRACE_MMIO_RW = 7, - TRACE_MMIO_MAP = 8, - TRACE_BRANCH = 9, - TRACE_GRAPH_RET = 10, - TRACE_GRAPH_ENT = 11, - TRACE_USER_STACK = 12, - TRACE_BLK = 13, - TRACE_BPUTS = 14, - TRACE_HWLAT = 15, - TRACE_RAW_DATA = 16, - __TRACE_LAST_TYPE = 17, -}; - -struct ftrace_entry { - struct trace_entry ent; - long unsigned int ip; - long unsigned int parent_ip; -}; - -struct stack_entry { - struct trace_entry ent; - int size; - long unsigned int caller[8]; -}; - -struct bprint_entry { - struct trace_entry ent; - long unsigned int ip; - const char *fmt; - u32 buf[0]; -}; - -struct print_entry { - struct trace_entry ent; - long unsigned int ip; - char buf[0]; -}; - -struct raw_data_entry { - struct trace_entry ent; - unsigned int id; - char buf[0]; -}; - -struct bputs_entry { - struct trace_entry ent; - long unsigned int ip; - const char *str; -}; - -enum trace_flag_type { - TRACE_FLAG_IRQS_OFF = 1, - TRACE_FLAG_IRQS_NOSUPPORT = 2, - TRACE_FLAG_NEED_RESCHED = 4, - TRACE_FLAG_HARDIRQ = 8, - TRACE_FLAG_SOFTIRQ = 16, - TRACE_FLAG_PREEMPT_RESCHED = 32, - TRACE_FLAG_NMI = 64, -}; - -enum trace_iterator_flags { - TRACE_ITER_PRINT_PARENT = 1, - TRACE_ITER_SYM_OFFSET = 2, - TRACE_ITER_SYM_ADDR = 4, - TRACE_ITER_VERBOSE = 8, - TRACE_ITER_RAW = 16, - TRACE_ITER_HEX = 32, - TRACE_ITER_BIN = 64, - TRACE_ITER_BLOCK = 128, - TRACE_ITER_PRINTK = 256, - TRACE_ITER_ANNOTATE = 512, - TRACE_ITER_USERSTACKTRACE = 1024, - TRACE_ITER_SYM_USEROBJ = 2048, - TRACE_ITER_PRINTK_MSGONLY = 4096, - TRACE_ITER_CONTEXT_INFO = 8192, - TRACE_ITER_LATENCY_FMT = 16384, - TRACE_ITER_RECORD_CMD = 32768, - TRACE_ITER_RECORD_TGID = 65536, - TRACE_ITER_OVERWRITE = 131072, - TRACE_ITER_STOP_ON_FREE = 262144, - TRACE_ITER_IRQ_INFO = 524288, - TRACE_ITER_MARKERS = 1048576, - TRACE_ITER_EVENT_FORK = 2097152, - TRACE_ITER_PAUSE_ON_TRACE = 4194304, - TRACE_ITER_FUNCTION = 8388608, - TRACE_ITER_FUNC_FORK = 16777216, - TRACE_ITER_DISPLAY_GRAPH = 33554432, - TRACE_ITER_STACKTRACE = 67108864, -}; - -struct saved_cmdlines_buffer { - unsigned int map_pid_to_cmdline[32769]; - unsigned int *map_cmdline_to_pid; - unsigned int cmdline_num; - int cmdline_idx; - char *saved_cmdlines; -}; - -struct ftrace_stack { - long unsigned int calls[1024]; -}; - -struct ftrace_stacks { - struct ftrace_stack stacks[4]; -}; - -struct trace_buffer_struct { - int nesting; - char buffer[4096]; -}; - -struct ftrace_buffer_info { - struct trace_iterator iter; - void *spare; - unsigned int spare_cpu; - unsigned int read; -}; - -struct err_info { - const char **errs; - u8 type; - u8 pos; - u64 ts; -}; - -struct tracing_log_err { - struct list_head list; - struct err_info info; - char loc[128]; - char cmd[256]; -}; - -struct buffer_ref { - struct trace_buffer *buffer; - void *page; - int cpu; - refcount_t refcount; -}; - -struct ftrace_func_mapper___2; - -struct ctx_switch_entry { - struct trace_entry ent; - unsigned int prev_pid; - unsigned int next_pid; - unsigned int next_cpu; - unsigned char prev_prio; - unsigned char prev_state; - unsigned char next_prio; - unsigned char next_state; -}; - -struct userstack_entry { - struct trace_entry ent; - unsigned int tgid; - long unsigned int caller[8]; -}; - -struct hwlat_entry { - struct trace_entry ent; - u64 duration; - u64 outer_duration; - u64 nmi_total_ts; - struct timespec64 timestamp; - unsigned int nmi_count; - unsigned int seqnum; - unsigned int count; -}; - -struct trace_mark { - long long unsigned int val; - char sym; -}; - -struct stat_node { - struct rb_node node; - void *stat; -}; - -struct stat_session { - struct list_head session_list; - struct tracer_stat *ts; - struct rb_root stat_root; - struct mutex stat_mutex; - struct dentry *file; -}; - -struct trace_bprintk_fmt { - struct list_head list; - const char *fmt; -}; - -enum { - TRACE_FUNC_OPT_STACK = 1, -}; - -struct trace_event_raw_preemptirq_template { - struct trace_entry ent; - s32 caller_offs; - s32 parent_offs; - char __data[0]; -}; - -struct trace_event_data_offsets_preemptirq_template {}; - -typedef void (*btf_trace_irq_disable)(void *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_irq_enable)(void *, long unsigned int, long unsigned int); - -enum { - TRACER_IRQS_OFF = 2, - TRACER_PREEMPT_OFF = 4, -}; - -enum { - TRACE_NOP_OPT_ACCEPT = 1, - TRACE_NOP_OPT_REFUSE = 2, -}; - -struct ftrace_graph_ent_entry { - struct trace_entry ent; - struct ftrace_graph_ent graph_ent; -} __attribute__((packed)); - -struct ftrace_graph_ret_entry { - struct trace_entry ent; - struct ftrace_graph_ret ret; -} __attribute__((packed)); - -struct fgraph_cpu_data { - pid_t last_pid; - int depth; - int depth_irq; - int ignore; - long unsigned int enter_funcs[50]; -}; - -struct fgraph_data { - struct fgraph_cpu_data *cpu_data; - struct ftrace_graph_ent_entry ent; - struct ftrace_graph_ret_entry ret; - int failed; - int cpu; -} __attribute__((packed)); - -enum { - FLAGS_FILL_FULL = 268435456, - FLAGS_FILL_START = 536870912, - FLAGS_FILL_END = 805306368, -}; - -typedef __u32 blk_mq_req_flags_t; - -enum req_opf { - REQ_OP_READ = 0, - REQ_OP_WRITE = 1, - REQ_OP_FLUSH = 2, - REQ_OP_DISCARD = 3, - REQ_OP_SECURE_ERASE = 5, - REQ_OP_WRITE_SAME = 7, - REQ_OP_WRITE_ZEROES = 9, - REQ_OP_ZONE_OPEN = 10, - REQ_OP_ZONE_CLOSE = 11, - REQ_OP_ZONE_FINISH = 12, - REQ_OP_ZONE_APPEND = 13, - REQ_OP_ZONE_RESET = 15, - REQ_OP_ZONE_RESET_ALL = 17, - REQ_OP_SCSI_IN = 32, - REQ_OP_SCSI_OUT = 33, - REQ_OP_DRV_IN = 34, - REQ_OP_DRV_OUT = 35, - REQ_OP_LAST = 36, -}; - -enum req_flag_bits { - __REQ_FAILFAST_DEV = 8, - __REQ_FAILFAST_TRANSPORT = 9, - __REQ_FAILFAST_DRIVER = 10, - __REQ_SYNC = 11, - __REQ_META = 12, - __REQ_PRIO = 13, - __REQ_NOMERGE = 14, - __REQ_IDLE = 15, - __REQ_INTEGRITY = 16, - __REQ_FUA = 17, - __REQ_PREFLUSH = 18, - __REQ_RAHEAD = 19, - __REQ_BACKGROUND = 20, - __REQ_NOWAIT = 21, - __REQ_CGROUP_PUNT = 22, - __REQ_NOUNMAP = 23, - __REQ_HIPRI = 24, - __REQ_DRV = 25, - __REQ_SWAP = 26, - __REQ_NR_BITS = 27, -}; - -struct disk_stats { - u64 nsecs[4]; - long unsigned int sectors[4]; - long unsigned int ios[4]; - long unsigned int merges[4]; - long unsigned int io_ticks; - local_t in_flight[2]; -}; - -struct blk_mq_ctxs; - -struct blk_mq_ctx { - struct { - spinlock_t lock; - struct list_head rq_lists[3]; - long: 64; - }; - unsigned int cpu; - short unsigned int index_hw[3]; - struct blk_mq_hw_ctx *hctxs[3]; - long unsigned int rq_dispatched[2]; - long unsigned int rq_merged; - long unsigned int rq_completed[2]; - struct request_queue *queue; - struct blk_mq_ctxs *ctxs; - struct kobject kobj; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct sbitmap_word; - -struct sbitmap { - unsigned int depth; - unsigned int shift; - unsigned int map_nr; - struct sbitmap_word *map; -}; - -struct blk_mq_tags; - -struct blk_mq_hw_ctx { - struct { - spinlock_t lock; - struct list_head dispatch; - long unsigned int state; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct delayed_work run_work; - cpumask_var_t cpumask; - int next_cpu; - int next_cpu_batch; - long unsigned int flags; - void *sched_data; - struct request_queue *queue; - struct blk_flush_queue *fq; - void *driver_data; - struct sbitmap ctx_map; - struct blk_mq_ctx *dispatch_from; - unsigned int dispatch_busy; - short unsigned int type; - short unsigned int nr_ctx; - struct blk_mq_ctx **ctxs; - spinlock_t dispatch_wait_lock; - wait_queue_entry_t dispatch_wait; - atomic_t wait_index; - struct blk_mq_tags *tags; - struct blk_mq_tags *sched_tags; - long unsigned int queued; - long unsigned int run; - long unsigned int dispatched[7]; - unsigned int numa_node; - unsigned int queue_num; - atomic_t nr_active; - atomic_t elevator_queued; - struct hlist_node cpuhp_online; - struct hlist_node cpuhp_dead; - struct kobject kobj; - long unsigned int poll_considered; - long unsigned int poll_invoked; - long unsigned int poll_success; - struct dentry *debugfs_dir; - struct dentry *sched_debugfs_dir; - struct list_head hctx_list; - struct srcu_struct srcu[0]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct blk_mq_alloc_data { - struct request_queue *q; - blk_mq_req_flags_t flags; - unsigned int shallow_depth; - unsigned int cmd_flags; - struct blk_mq_ctx *ctx; - struct blk_mq_hw_ctx *hctx; -}; - -struct blk_stat_callback { - struct list_head list; - struct timer_list timer; - struct blk_rq_stat *cpu_stat; - int (*bucket_fn)(const struct request *); - unsigned int buckets; - struct blk_rq_stat *stat; - void (*timer_fn)(struct blk_stat_callback *); - void *data; - struct callback_head rcu; -}; - -struct blk_trace { - int trace_state; - struct rchan *rchan; - long unsigned int *sequence; - unsigned char *msg_data; - u16 act_mask; - u64 start_lba; - u64 end_lba; - u32 pid; - u32 dev; - struct dentry *dir; - struct dentry *dropped_file; - struct dentry *msg_file; - struct list_head running_list; - atomic_t dropped; -}; - -struct blk_flush_queue { - unsigned int flush_pending_idx: 1; - unsigned int flush_running_idx: 1; - blk_status_t rq_status; - long unsigned int flush_pending_since; - struct list_head flush_queue[2]; - struct list_head flush_data_in_flight; - struct request *flush_rq; - struct lock_class_key key; - spinlock_t mq_flush_lock; -}; - -struct blk_mq_queue_map { - unsigned int *mq_map; - unsigned int nr_queues; - unsigned int queue_offset; -}; - -struct sbq_wait_state; - -struct sbitmap_queue { - struct sbitmap sb; - unsigned int *alloc_hint; - unsigned int wake_batch; - atomic_t wake_index; - struct sbq_wait_state *ws; - atomic_t ws_active; - bool round_robin; - unsigned int min_shallow_depth; -}; - -struct blk_mq_tag_set { - struct blk_mq_queue_map map[3]; - unsigned int nr_maps; - const struct blk_mq_ops *ops; - unsigned int nr_hw_queues; - unsigned int queue_depth; - unsigned int reserved_tags; - unsigned int cmd_size; - int numa_node; - unsigned int timeout; - unsigned int flags; - void *driver_data; - atomic_t active_queues_shared_sbitmap; - struct sbitmap_queue __bitmap_tags; - struct sbitmap_queue __breserved_tags; - struct blk_mq_tags **tags; - struct mutex tag_list_lock; - struct list_head tag_list; -}; - -enum blktrace_cat { - BLK_TC_READ = 1, - BLK_TC_WRITE = 2, - BLK_TC_FLUSH = 4, - BLK_TC_SYNC = 8, - BLK_TC_SYNCIO = 8, - BLK_TC_QUEUE = 16, - BLK_TC_REQUEUE = 32, - BLK_TC_ISSUE = 64, - BLK_TC_COMPLETE = 128, - BLK_TC_FS = 256, - BLK_TC_PC = 512, - BLK_TC_NOTIFY = 1024, - BLK_TC_AHEAD = 2048, - BLK_TC_META = 4096, - BLK_TC_DISCARD = 8192, - BLK_TC_DRV_DATA = 16384, - BLK_TC_FUA = 32768, - BLK_TC_END = 32768, -}; - -enum blktrace_act { - __BLK_TA_QUEUE = 1, - __BLK_TA_BACKMERGE = 2, - __BLK_TA_FRONTMERGE = 3, - __BLK_TA_GETRQ = 4, - __BLK_TA_SLEEPRQ = 5, - __BLK_TA_REQUEUE = 6, - __BLK_TA_ISSUE = 7, - __BLK_TA_COMPLETE = 8, - __BLK_TA_PLUG = 9, - __BLK_TA_UNPLUG_IO = 10, - __BLK_TA_UNPLUG_TIMER = 11, - __BLK_TA_INSERT = 12, - __BLK_TA_SPLIT = 13, - __BLK_TA_BOUNCE = 14, - __BLK_TA_REMAP = 15, - __BLK_TA_ABORT = 16, - __BLK_TA_DRV_DATA = 17, - __BLK_TA_CGROUP = 256, -}; - -enum blktrace_notify { - __BLK_TN_PROCESS = 0, - __BLK_TN_TIMESTAMP = 1, - __BLK_TN_MESSAGE = 2, - __BLK_TN_CGROUP = 256, -}; - -struct blk_io_trace { - __u32 magic; - __u32 sequence; - __u64 time; - __u64 sector; - __u32 bytes; - __u32 action; - __u32 pid; - __u32 device; - __u32 cpu; - __u16 error; - __u16 pdu_len; -}; - -struct blk_io_trace_remap { - __be32 device_from; - __be32 device_to; - __be64 sector_from; -}; - -enum { - Blktrace_setup = 1, - Blktrace_running = 2, - Blktrace_stopped = 3, -}; - -struct blk_user_trace_setup { - char name[32]; - __u16 act_mask; - __u32 buf_size; - __u32 buf_nr; - __u64 start_lba; - __u64 end_lba; - __u32 pid; -}; - -struct sbitmap_word { - long unsigned int depth; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int word; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int cleared; - spinlock_t swap_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct sbq_wait_state { - atomic_t wait_cnt; - wait_queue_head_t wait; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct blk_mq_tags { - unsigned int nr_tags; - unsigned int nr_reserved_tags; - atomic_t active_queues; - struct sbitmap_queue *bitmap_tags; - struct sbitmap_queue *breserved_tags; - struct sbitmap_queue __bitmap_tags; - struct sbitmap_queue __breserved_tags; - struct request **rqs; - struct request **static_rqs; - struct list_head page_list; - spinlock_t lock; -}; - -struct blk_mq_queue_data { - struct request *rq; - bool last; -}; - -struct blk_mq_ctxs { - struct kobject kobj; - struct blk_mq_ctx *queue_ctx; -}; - -typedef void blk_log_action_t(struct trace_iterator *, const char *, bool); - -struct ftrace_event_field { - struct list_head link; - const char *name; - const char *type; - int filter_type; - int offset; - int size; - int is_signed; -}; - -enum { - FORMAT_HEADER = 1, - FORMAT_FIELD_SEPERATOR = 2, - FORMAT_PRINTFMT = 3, -}; - -struct event_probe_data { - struct trace_event_file *file; - long unsigned int count; - int ref; - bool enable; -}; - -enum perf_event_sample_format { - PERF_SAMPLE_IP = 1, - PERF_SAMPLE_TID = 2, - PERF_SAMPLE_TIME = 4, - PERF_SAMPLE_ADDR = 8, - PERF_SAMPLE_READ = 16, - PERF_SAMPLE_CALLCHAIN = 32, - PERF_SAMPLE_ID = 64, - PERF_SAMPLE_CPU = 128, - PERF_SAMPLE_PERIOD = 256, - PERF_SAMPLE_STREAM_ID = 512, - PERF_SAMPLE_RAW = 1024, - PERF_SAMPLE_BRANCH_STACK = 2048, - PERF_SAMPLE_REGS_USER = 4096, - PERF_SAMPLE_STACK_USER = 8192, - PERF_SAMPLE_WEIGHT = 16384, - PERF_SAMPLE_DATA_SRC = 32768, - PERF_SAMPLE_IDENTIFIER = 65536, - PERF_SAMPLE_TRANSACTION = 131072, - PERF_SAMPLE_REGS_INTR = 262144, - PERF_SAMPLE_PHYS_ADDR = 524288, - PERF_SAMPLE_AUX = 1048576, - PERF_SAMPLE_CGROUP = 2097152, - PERF_SAMPLE_MAX = 4194304, - __PERF_SAMPLE_CALLCHAIN_EARLY = 0, -}; - -typedef long unsigned int perf_trace_t[256]; - -struct filter_pred; - -struct prog_entry { - int target; - int when_to_branch; - struct filter_pred *pred; -}; - -typedef int (*filter_pred_fn_t)(struct filter_pred *, void *); - -struct regex; - -typedef int (*regex_match_func)(char *, struct regex *, int); - -struct regex { - char pattern[256]; - int len; - int field_len; - regex_match_func match; -}; - -struct filter_pred { - filter_pred_fn_t fn; - u64 val; - struct regex regex; - short unsigned int *ops; - struct ftrace_event_field *field; - int offset; - int not; - int op; -}; - -enum filter_op_ids { - OP_GLOB = 0, - OP_NE = 1, - OP_EQ = 2, - OP_LE = 3, - OP_LT = 4, - OP_GE = 5, - OP_GT = 6, - OP_BAND = 7, - OP_MAX = 8, -}; - -enum { - FILT_ERR_NONE = 0, - FILT_ERR_INVALID_OP = 1, - FILT_ERR_TOO_MANY_OPEN = 2, - FILT_ERR_TOO_MANY_CLOSE = 3, - FILT_ERR_MISSING_QUOTE = 4, - FILT_ERR_OPERAND_TOO_LONG = 5, - FILT_ERR_EXPECT_STRING = 6, - FILT_ERR_EXPECT_DIGIT = 7, - FILT_ERR_ILLEGAL_FIELD_OP = 8, - FILT_ERR_FIELD_NOT_FOUND = 9, - FILT_ERR_ILLEGAL_INTVAL = 10, - FILT_ERR_BAD_SUBSYS_FILTER = 11, - FILT_ERR_TOO_MANY_PREDS = 12, - FILT_ERR_INVALID_FILTER = 13, - FILT_ERR_IP_FIELD_ONLY = 14, - FILT_ERR_INVALID_VALUE = 15, - FILT_ERR_ERRNO = 16, - FILT_ERR_NO_FILTER = 17, -}; - -struct filter_parse_error { - int lasterr; - int lasterr_pos; -}; - -typedef int (*parse_pred_fn)(const char *, void *, int, struct filter_parse_error *, struct filter_pred **); - -enum { - INVERT = 1, - PROCESS_AND = 2, - PROCESS_OR = 4, -}; - -enum { - TOO_MANY_CLOSE = 4294967295, - TOO_MANY_OPEN = 4294967294, - MISSING_QUOTE = 4294967293, -}; - -struct filter_list { - struct list_head list; - struct event_filter *filter; -}; - -struct function_filter_data { - struct ftrace_ops *ops; - int first_filter; - int first_notrace; -}; - -struct event_trigger_ops; - -struct event_command; - -struct event_trigger_data { - long unsigned int count; - int ref; - struct event_trigger_ops *ops; - struct event_command *cmd_ops; - struct event_filter *filter; - char *filter_str; - void *private_data; - bool paused; - bool paused_tmp; - struct list_head list; - char *name; - struct list_head named_list; - struct event_trigger_data *named_data; -}; - -struct event_trigger_ops { - void (*func)(struct event_trigger_data *, void *, struct ring_buffer_event *); - int (*init)(struct event_trigger_ops *, struct event_trigger_data *); - void (*free)(struct event_trigger_ops *, struct event_trigger_data *); - int (*print)(struct seq_file *, struct event_trigger_ops *, struct event_trigger_data *); -}; - -struct event_command { - struct list_head list; - char *name; - enum event_trigger_type trigger_type; - int flags; - int (*func)(struct event_command *, struct trace_event_file *, char *, char *, char *); - int (*reg)(char *, struct event_trigger_ops *, struct event_trigger_data *, struct trace_event_file *); - void (*unreg)(char *, struct event_trigger_ops *, struct event_trigger_data *, struct trace_event_file *); - void (*unreg_all)(struct trace_event_file *); - int (*set_filter)(char *, struct event_trigger_data *, struct trace_event_file *); - struct event_trigger_ops * (*get_trigger_ops)(char *, char *); -}; - -struct enable_trigger_data { - struct trace_event_file *file; - bool enable; - bool hist; -}; - -enum event_command_flags { - EVENT_CMD_FL_POST_TRIGGER = 1, - EVENT_CMD_FL_NEEDS_REC = 2, -}; - -enum bpf_func_id { - BPF_FUNC_unspec = 0, - BPF_FUNC_map_lookup_elem = 1, - BPF_FUNC_map_update_elem = 2, - BPF_FUNC_map_delete_elem = 3, - BPF_FUNC_probe_read = 4, - BPF_FUNC_ktime_get_ns = 5, - BPF_FUNC_trace_printk = 6, - BPF_FUNC_get_prandom_u32 = 7, - BPF_FUNC_get_smp_processor_id = 8, - BPF_FUNC_skb_store_bytes = 9, - BPF_FUNC_l3_csum_replace = 10, - BPF_FUNC_l4_csum_replace = 11, - BPF_FUNC_tail_call = 12, - BPF_FUNC_clone_redirect = 13, - BPF_FUNC_get_current_pid_tgid = 14, - BPF_FUNC_get_current_uid_gid = 15, - BPF_FUNC_get_current_comm = 16, - BPF_FUNC_get_cgroup_classid = 17, - BPF_FUNC_skb_vlan_push = 18, - BPF_FUNC_skb_vlan_pop = 19, - BPF_FUNC_skb_get_tunnel_key = 20, - BPF_FUNC_skb_set_tunnel_key = 21, - BPF_FUNC_perf_event_read = 22, - BPF_FUNC_redirect = 23, - BPF_FUNC_get_route_realm = 24, - BPF_FUNC_perf_event_output = 25, - BPF_FUNC_skb_load_bytes = 26, - BPF_FUNC_get_stackid = 27, - BPF_FUNC_csum_diff = 28, - BPF_FUNC_skb_get_tunnel_opt = 29, - BPF_FUNC_skb_set_tunnel_opt = 30, - BPF_FUNC_skb_change_proto = 31, - BPF_FUNC_skb_change_type = 32, - BPF_FUNC_skb_under_cgroup = 33, - BPF_FUNC_get_hash_recalc = 34, - BPF_FUNC_get_current_task = 35, - BPF_FUNC_probe_write_user = 36, - BPF_FUNC_current_task_under_cgroup = 37, - BPF_FUNC_skb_change_tail = 38, - BPF_FUNC_skb_pull_data = 39, - BPF_FUNC_csum_update = 40, - BPF_FUNC_set_hash_invalid = 41, - BPF_FUNC_get_numa_node_id = 42, - BPF_FUNC_skb_change_head = 43, - BPF_FUNC_xdp_adjust_head = 44, - BPF_FUNC_probe_read_str = 45, - BPF_FUNC_get_socket_cookie = 46, - BPF_FUNC_get_socket_uid = 47, - BPF_FUNC_set_hash = 48, - BPF_FUNC_setsockopt = 49, - BPF_FUNC_skb_adjust_room = 50, - BPF_FUNC_redirect_map = 51, - BPF_FUNC_sk_redirect_map = 52, - BPF_FUNC_sock_map_update = 53, - BPF_FUNC_xdp_adjust_meta = 54, - BPF_FUNC_perf_event_read_value = 55, - BPF_FUNC_perf_prog_read_value = 56, - BPF_FUNC_getsockopt = 57, - BPF_FUNC_override_return = 58, - BPF_FUNC_sock_ops_cb_flags_set = 59, - BPF_FUNC_msg_redirect_map = 60, - BPF_FUNC_msg_apply_bytes = 61, - BPF_FUNC_msg_cork_bytes = 62, - BPF_FUNC_msg_pull_data = 63, - BPF_FUNC_bind = 64, - BPF_FUNC_xdp_adjust_tail = 65, - BPF_FUNC_skb_get_xfrm_state = 66, - BPF_FUNC_get_stack = 67, - BPF_FUNC_skb_load_bytes_relative = 68, - BPF_FUNC_fib_lookup = 69, - BPF_FUNC_sock_hash_update = 70, - BPF_FUNC_msg_redirect_hash = 71, - BPF_FUNC_sk_redirect_hash = 72, - BPF_FUNC_lwt_push_encap = 73, - BPF_FUNC_lwt_seg6_store_bytes = 74, - BPF_FUNC_lwt_seg6_adjust_srh = 75, - BPF_FUNC_lwt_seg6_action = 76, - BPF_FUNC_rc_repeat = 77, - BPF_FUNC_rc_keydown = 78, - BPF_FUNC_skb_cgroup_id = 79, - BPF_FUNC_get_current_cgroup_id = 80, - BPF_FUNC_get_local_storage = 81, - BPF_FUNC_sk_select_reuseport = 82, - BPF_FUNC_skb_ancestor_cgroup_id = 83, - BPF_FUNC_sk_lookup_tcp = 84, - BPF_FUNC_sk_lookup_udp = 85, - BPF_FUNC_sk_release = 86, - BPF_FUNC_map_push_elem = 87, - BPF_FUNC_map_pop_elem = 88, - BPF_FUNC_map_peek_elem = 89, - BPF_FUNC_msg_push_data = 90, - BPF_FUNC_msg_pop_data = 91, - BPF_FUNC_rc_pointer_rel = 92, - BPF_FUNC_spin_lock = 93, - BPF_FUNC_spin_unlock = 94, - BPF_FUNC_sk_fullsock = 95, - BPF_FUNC_tcp_sock = 96, - BPF_FUNC_skb_ecn_set_ce = 97, - BPF_FUNC_get_listener_sock = 98, - BPF_FUNC_skc_lookup_tcp = 99, - BPF_FUNC_tcp_check_syncookie = 100, - BPF_FUNC_sysctl_get_name = 101, - BPF_FUNC_sysctl_get_current_value = 102, - BPF_FUNC_sysctl_get_new_value = 103, - BPF_FUNC_sysctl_set_new_value = 104, - BPF_FUNC_strtol = 105, - BPF_FUNC_strtoul = 106, - BPF_FUNC_sk_storage_get = 107, - BPF_FUNC_sk_storage_delete = 108, - BPF_FUNC_send_signal = 109, - BPF_FUNC_tcp_gen_syncookie = 110, - BPF_FUNC_skb_output = 111, - BPF_FUNC_probe_read_user = 112, - BPF_FUNC_probe_read_kernel = 113, - BPF_FUNC_probe_read_user_str = 114, - BPF_FUNC_probe_read_kernel_str = 115, - BPF_FUNC_tcp_send_ack = 116, - BPF_FUNC_send_signal_thread = 117, - BPF_FUNC_jiffies64 = 118, - BPF_FUNC_read_branch_records = 119, - BPF_FUNC_get_ns_current_pid_tgid = 120, - BPF_FUNC_xdp_output = 121, - BPF_FUNC_get_netns_cookie = 122, - BPF_FUNC_get_current_ancestor_cgroup_id = 123, - BPF_FUNC_sk_assign = 124, - BPF_FUNC_ktime_get_boot_ns = 125, - BPF_FUNC_seq_printf = 126, - BPF_FUNC_seq_write = 127, - BPF_FUNC_sk_cgroup_id = 128, - BPF_FUNC_sk_ancestor_cgroup_id = 129, - BPF_FUNC_ringbuf_output = 130, - BPF_FUNC_ringbuf_reserve = 131, - BPF_FUNC_ringbuf_submit = 132, - BPF_FUNC_ringbuf_discard = 133, - BPF_FUNC_ringbuf_query = 134, - BPF_FUNC_csum_level = 135, - BPF_FUNC_skc_to_tcp6_sock = 136, - BPF_FUNC_skc_to_tcp_sock = 137, - BPF_FUNC_skc_to_tcp_timewait_sock = 138, - BPF_FUNC_skc_to_tcp_request_sock = 139, - BPF_FUNC_skc_to_udp6_sock = 140, - BPF_FUNC_get_task_stack = 141, - BPF_FUNC_load_hdr_opt = 142, - BPF_FUNC_store_hdr_opt = 143, - BPF_FUNC_reserve_hdr_opt = 144, - BPF_FUNC_inode_storage_get = 145, - BPF_FUNC_inode_storage_delete = 146, - BPF_FUNC_d_path = 147, - BPF_FUNC_copy_from_user = 148, - BPF_FUNC_snprintf_btf = 149, - BPF_FUNC_seq_printf_btf = 150, - BPF_FUNC_skb_cgroup_classid = 151, - BPF_FUNC_redirect_neigh = 152, - BPF_FUNC_per_cpu_ptr = 153, - BPF_FUNC_this_cpu_ptr = 154, - BPF_FUNC_redirect_peer = 155, - __BPF_FUNC_MAX_ID = 156, -}; - -enum { - BPF_F_INDEX_MASK = 4294967295, - BPF_F_CURRENT_CPU = 4294967295, - BPF_F_CTXLEN_MASK = 0, -}; - -struct bpf_perf_event_value { - __u64 counter; - __u64 enabled; - __u64 running; -}; - -struct bpf_raw_tracepoint_args { - __u64 args[0]; -}; - -enum bpf_task_fd_type { - BPF_FD_TYPE_RAW_TRACEPOINT = 0, - BPF_FD_TYPE_TRACEPOINT = 1, - BPF_FD_TYPE_KPROBE = 2, - BPF_FD_TYPE_KRETPROBE = 3, - BPF_FD_TYPE_UPROBE = 4, - BPF_FD_TYPE_URETPROBE = 5, -}; - -struct btf_ptr { - void *ptr; - __u32 type_id; - __u32 flags; -}; - -enum { - BTF_F_COMPACT = 1, - BTF_F_NONAME = 2, - BTF_F_PTR_RAW = 4, - BTF_F_ZERO = 8, -}; - -enum bpf_arg_type { - ARG_DONTCARE = 0, - ARG_CONST_MAP_PTR = 1, - ARG_PTR_TO_MAP_KEY = 2, - ARG_PTR_TO_MAP_VALUE = 3, - ARG_PTR_TO_UNINIT_MAP_VALUE = 4, - ARG_PTR_TO_MAP_VALUE_OR_NULL = 5, - ARG_PTR_TO_MEM = 6, - ARG_PTR_TO_MEM_OR_NULL = 7, - ARG_PTR_TO_UNINIT_MEM = 8, - ARG_CONST_SIZE = 9, - ARG_CONST_SIZE_OR_ZERO = 10, - ARG_PTR_TO_CTX = 11, - ARG_PTR_TO_CTX_OR_NULL = 12, - ARG_ANYTHING = 13, - ARG_PTR_TO_SPIN_LOCK = 14, - ARG_PTR_TO_SOCK_COMMON = 15, - ARG_PTR_TO_INT = 16, - ARG_PTR_TO_LONG = 17, - ARG_PTR_TO_SOCKET = 18, - ARG_PTR_TO_SOCKET_OR_NULL = 19, - ARG_PTR_TO_BTF_ID = 20, - ARG_PTR_TO_ALLOC_MEM = 21, - ARG_PTR_TO_ALLOC_MEM_OR_NULL = 22, - ARG_CONST_ALLOC_SIZE_OR_ZERO = 23, - ARG_PTR_TO_BTF_ID_SOCK_COMMON = 24, - ARG_PTR_TO_PERCPU_BTF_ID = 25, - __BPF_ARG_TYPE_MAX = 26, -}; - -enum bpf_return_type { - RET_INTEGER = 0, - RET_VOID = 1, - RET_PTR_TO_MAP_VALUE = 2, - RET_PTR_TO_MAP_VALUE_OR_NULL = 3, - RET_PTR_TO_SOCKET_OR_NULL = 4, - RET_PTR_TO_TCP_SOCK_OR_NULL = 5, - RET_PTR_TO_SOCK_COMMON_OR_NULL = 6, - RET_PTR_TO_ALLOC_MEM_OR_NULL = 7, - RET_PTR_TO_BTF_ID_OR_NULL = 8, - RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL = 9, - RET_PTR_TO_MEM_OR_BTF_ID = 10, -}; - -struct bpf_func_proto { - u64 (*func)(u64, u64, u64, u64, u64); - bool gpl_only; - bool pkt_access; - enum bpf_return_type ret_type; - union { - struct { - enum bpf_arg_type arg1_type; - enum bpf_arg_type arg2_type; - enum bpf_arg_type arg3_type; - enum bpf_arg_type arg4_type; - enum bpf_arg_type arg5_type; - }; - enum bpf_arg_type arg_type[5]; - }; - union { - struct { - u32 *arg1_btf_id; - u32 *arg2_btf_id; - u32 *arg3_btf_id; - u32 *arg4_btf_id; - u32 *arg5_btf_id; - }; - u32 *arg_btf_id[5]; - }; - int *ret_btf_id; - bool (*allowed)(const struct bpf_prog *); -}; - -enum bpf_access_type { - BPF_READ = 1, - BPF_WRITE = 2, -}; - -struct bpf_verifier_log; - -struct bpf_insn_access_aux { - enum bpf_reg_type reg_type; - union { - int ctx_field_size; - u32 btf_id; - }; - struct bpf_verifier_log *log; -}; - -struct bpf_verifier_ops { - const struct bpf_func_proto * (*get_func_proto)(enum bpf_func_id, const struct bpf_prog *); - bool (*is_valid_access)(int, int, enum bpf_access_type, const struct bpf_prog *, struct bpf_insn_access_aux *); - int (*gen_prologue)(struct bpf_insn *, bool, const struct bpf_prog *); - int (*gen_ld_abs)(const struct bpf_insn *, struct bpf_insn *); - u32 (*convert_ctx_access)(enum bpf_access_type, const struct bpf_insn *, struct bpf_insn *, struct bpf_prog *, u32 *); - int (*btf_struct_access)(struct bpf_verifier_log *, const struct btf_type *, int, int, enum bpf_access_type, u32 *); -}; - -struct bpf_array_aux { - struct { - spinlock_t lock; - enum bpf_prog_type type; - bool jited; - } owner; - struct list_head poke_progs; - struct bpf_map *map; - struct mutex poke_mutex; - struct work_struct work; -}; - -struct bpf_array { - struct bpf_map map; - u32 elem_size; - u32 index_mask; - struct bpf_array_aux *aux; - union { - char value[0]; - void *ptrs[0]; - void *pptrs[0]; - }; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_event_entry { - struct perf_event *event; - struct file *perf_file; - struct file *map_file; - struct callback_head rcu; -}; - -typedef long unsigned int (*bpf_ctx_copy_t)(void *, const void *, long unsigned int, long unsigned int); - -typedef struct user_pt_regs bpf_user_pt_regs_t; - -struct bpf_perf_event_data { - bpf_user_pt_regs_t regs; - __u64 sample_period; - __u64 addr; -}; - -struct perf_event_query_bpf { - __u32 ids_len; - __u32 prog_cnt; - __u32 ids[0]; -}; - -struct bpf_perf_event_data_kern { - bpf_user_pt_regs_t *regs; - struct perf_sample_data *data; - struct perf_event *event; -}; - -struct btf_id_set { - u32 cnt; - u32 ids[0]; -}; - -struct trace_event_raw_bpf_trace_printk { - struct trace_entry ent; - u32 __data_loc_bpf_string; - char __data[0]; -}; - -struct trace_event_data_offsets_bpf_trace_printk { - u32 bpf_string; -}; - -typedef void (*btf_trace_bpf_trace_printk)(void *, const char *); - -struct bpf_trace_module { - struct module *module; - struct list_head list; -}; - -typedef u64 (*btf_bpf_probe_read_user)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_user_str)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_kernel)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_kernel_str)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_compat)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_compat_str)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_write_user)(void *, const void *, u32); - -typedef u64 (*btf_bpf_trace_printk)(char *, u32, u64, u64, u64); - -struct bpf_seq_printf_buf { - char buf[768]; -}; - -typedef u64 (*btf_bpf_seq_printf)(struct seq_file *, char *, u32, const void *, u32); - -typedef u64 (*btf_bpf_seq_write)(struct seq_file *, const void *, u32); - -typedef u64 (*btf_bpf_seq_printf_btf)(struct seq_file *, struct btf_ptr *, u32, u64); - -typedef u64 (*btf_bpf_perf_event_read)(struct bpf_map *, u64); - -typedef u64 (*btf_bpf_perf_event_read_value)(struct bpf_map *, u64, struct bpf_perf_event_value *, u32); - -struct bpf_trace_sample_data { - struct perf_sample_data sds[3]; -}; - -typedef u64 (*btf_bpf_perf_event_output)(struct pt_regs *, struct bpf_map *, u64, void *, u64); - -struct bpf_nested_pt_regs { - struct pt_regs regs[3]; -}; - -typedef u64 (*btf_bpf_get_current_task)(); - -typedef u64 (*btf_bpf_current_task_under_cgroup)(struct bpf_map *, u32); - -struct send_signal_irq_work { - struct irq_work irq_work; - struct task_struct *task; - u32 sig; - enum pid_type type; -}; - -typedef u64 (*btf_bpf_send_signal)(u32); - -typedef u64 (*btf_bpf_send_signal_thread)(u32); - -typedef u64 (*btf_bpf_d_path)(struct path *, char *, u32); - -typedef u64 (*btf_bpf_snprintf_btf)(char *, u32, struct btf_ptr *, u32, u64); - -typedef u64 (*btf_bpf_perf_event_output_tp)(void *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_get_stackid_tp)(void *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stack_tp)(void *, void *, u32, u64); - -typedef u64 (*btf_bpf_perf_prog_read_value)(struct bpf_perf_event_data_kern *, struct bpf_perf_event_value *, u32); - -typedef u64 (*btf_bpf_read_branch_records)(struct bpf_perf_event_data_kern *, void *, u32, u64); - -struct bpf_raw_tp_regs { - struct pt_regs regs[3]; -}; - -typedef u64 (*btf_bpf_perf_event_output_raw_tp)(struct bpf_raw_tracepoint_args *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_get_stackid_raw_tp)(struct bpf_raw_tracepoint_args *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stack_raw_tp)(struct bpf_raw_tracepoint_args *, void *, u32, u64); - -enum dynevent_type { - DYNEVENT_TYPE_SYNTH = 1, - DYNEVENT_TYPE_KPROBE = 2, - DYNEVENT_TYPE_NONE = 3, -}; - -struct dynevent_cmd; - -typedef int (*dynevent_create_fn_t)(struct dynevent_cmd *); - -struct dynevent_cmd { - struct seq_buf seq; - const char *event_name; - unsigned int n_fields; - enum dynevent_type type; - dynevent_create_fn_t run_command; - void *private_data; -}; - -struct kprobe_trace_entry_head { - struct trace_entry ent; - long unsigned int ip; -}; - -struct kretprobe_trace_entry_head { - struct trace_entry ent; - long unsigned int func; - long unsigned int ret_ip; -}; - -struct dyn_event; - -struct dyn_event_operations { - struct list_head list; - int (*create)(int, const char **); - int (*show)(struct seq_file *, struct dyn_event *); - bool (*is_busy)(struct dyn_event *); - int (*free)(struct dyn_event *); - bool (*match)(const char *, const char *, int, const char **, struct dyn_event *); -}; - -struct dyn_event { - struct list_head list; - struct dyn_event_operations *ops; -}; - -struct dynevent_arg { - const char *str; - char separator; -}; - -typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); - -enum fetch_op { - FETCH_OP_NOP = 0, - FETCH_OP_REG = 1, - FETCH_OP_STACK = 2, - FETCH_OP_STACKP = 3, - FETCH_OP_RETVAL = 4, - FETCH_OP_IMM = 5, - FETCH_OP_COMM = 6, - FETCH_OP_ARG = 7, - FETCH_OP_FOFFS = 8, - FETCH_OP_DATA = 9, - FETCH_OP_DEREF = 10, - FETCH_OP_UDEREF = 11, - FETCH_OP_ST_RAW = 12, - FETCH_OP_ST_MEM = 13, - FETCH_OP_ST_UMEM = 14, - FETCH_OP_ST_STRING = 15, - FETCH_OP_ST_USTRING = 16, - FETCH_OP_MOD_BF = 17, - FETCH_OP_LP_ARRAY = 18, - FETCH_OP_END = 19, - FETCH_NOP_SYMBOL = 20, -}; - -struct fetch_insn { - enum fetch_op op; - union { - unsigned int param; - struct { - unsigned int size; - int offset; - }; - struct { - unsigned char basesize; - unsigned char lshift; - unsigned char rshift; - }; - long unsigned int immediate; - void *data; - }; -}; - -struct fetch_type { - const char *name; - size_t size; - int is_signed; - print_type_func_t print; - const char *fmt; - const char *fmttype; -}; - -struct probe_arg { - struct fetch_insn *code; - bool dynamic; - unsigned int offset; - unsigned int count; - const char *name; - const char *comm; - char *fmt; - const struct fetch_type *type; -}; - -struct trace_uprobe_filter { - rwlock_t rwlock; - int nr_systemwide; - struct list_head perf_events; -}; - -struct trace_probe_event { - unsigned int flags; - struct trace_event_class class; - struct trace_event_call call; - struct list_head files; - struct list_head probes; - struct trace_uprobe_filter filter[0]; -}; - -struct trace_probe { - struct list_head list; - struct trace_probe_event *event; - ssize_t size; - unsigned int nr_args; - struct probe_arg args[0]; -}; - -struct event_file_link { - struct trace_event_file *file; - struct list_head list; -}; - -enum { - TP_ERR_FILE_NOT_FOUND = 0, - TP_ERR_NO_REGULAR_FILE = 1, - TP_ERR_BAD_REFCNT = 2, - TP_ERR_REFCNT_OPEN_BRACE = 3, - TP_ERR_BAD_REFCNT_SUFFIX = 4, - TP_ERR_BAD_UPROBE_OFFS = 5, - TP_ERR_MAXACT_NO_KPROBE = 6, - TP_ERR_BAD_MAXACT = 7, - TP_ERR_MAXACT_TOO_BIG = 8, - TP_ERR_BAD_PROBE_ADDR = 9, - TP_ERR_BAD_RETPROBE = 10, - TP_ERR_BAD_ADDR_SUFFIX = 11, - TP_ERR_NO_GROUP_NAME = 12, - TP_ERR_GROUP_TOO_LONG = 13, - TP_ERR_BAD_GROUP_NAME = 14, - TP_ERR_NO_EVENT_NAME = 15, - TP_ERR_EVENT_TOO_LONG = 16, - TP_ERR_BAD_EVENT_NAME = 17, - TP_ERR_EVENT_EXIST = 18, - TP_ERR_RETVAL_ON_PROBE = 19, - TP_ERR_BAD_STACK_NUM = 20, - TP_ERR_BAD_ARG_NUM = 21, - TP_ERR_BAD_VAR = 22, - TP_ERR_BAD_REG_NAME = 23, - TP_ERR_BAD_MEM_ADDR = 24, - TP_ERR_BAD_IMM = 25, - TP_ERR_IMMSTR_NO_CLOSE = 26, - TP_ERR_FILE_ON_KPROBE = 27, - TP_ERR_BAD_FILE_OFFS = 28, - TP_ERR_SYM_ON_UPROBE = 29, - TP_ERR_TOO_MANY_OPS = 30, - TP_ERR_DEREF_NEED_BRACE = 31, - TP_ERR_BAD_DEREF_OFFS = 32, - TP_ERR_DEREF_OPEN_BRACE = 33, - TP_ERR_COMM_CANT_DEREF = 34, - TP_ERR_BAD_FETCH_ARG = 35, - TP_ERR_ARRAY_NO_CLOSE = 36, - TP_ERR_BAD_ARRAY_SUFFIX = 37, - TP_ERR_BAD_ARRAY_NUM = 38, - TP_ERR_ARRAY_TOO_BIG = 39, - TP_ERR_BAD_TYPE = 40, - TP_ERR_BAD_STRING = 41, - TP_ERR_BAD_BITFIELD = 42, - TP_ERR_ARG_NAME_TOO_LONG = 43, - TP_ERR_NO_ARG_NAME = 44, - TP_ERR_BAD_ARG_NAME = 45, - TP_ERR_USED_ARG_NAME = 46, - TP_ERR_ARG_TOO_LONG = 47, - TP_ERR_NO_ARG_BODY = 48, - TP_ERR_BAD_INSN_BNDRY = 49, - TP_ERR_FAIL_REG_PROBE = 50, - TP_ERR_DIFF_PROBE_TYPE = 51, - TP_ERR_DIFF_ARG_TYPE = 52, - TP_ERR_SAME_PROBE = 53, -}; - -struct trace_kprobe { - struct dyn_event devent; - struct kretprobe rp; - long unsigned int *nhit; - const char *symbol; - struct trace_probe tp; -}; - -struct trace_event_raw_cpu { - struct trace_entry ent; - u32 state; - u32 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_powernv_throttle { - struct trace_entry ent; - int chip_id; - u32 __data_loc_reason; - int pmax; - char __data[0]; -}; - -struct trace_event_raw_pstate_sample { - struct trace_entry ent; - u32 core_busy; - u32 scaled_busy; - u32 from; - u32 to; - u64 mperf; - u64 aperf; - u64 tsc; - u32 freq; - u32 io_boost; - char __data[0]; -}; - -struct trace_event_raw_cpu_frequency_limits { - struct trace_entry ent; - u32 min_freq; - u32 max_freq; - u32 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_device_pm_callback_start { - struct trace_entry ent; - u32 __data_loc_device; - u32 __data_loc_driver; - u32 __data_loc_parent; - u32 __data_loc_pm_ops; - int event; - char __data[0]; -}; - -struct trace_event_raw_device_pm_callback_end { - struct trace_entry ent; - u32 __data_loc_device; - u32 __data_loc_driver; - int error; - char __data[0]; -}; - -struct trace_event_raw_suspend_resume { - struct trace_entry ent; - const char *action; - int val; - bool start; - char __data[0]; -}; - -struct trace_event_raw_wakeup_source { - struct trace_entry ent; - u32 __data_loc_name; - u64 state; - char __data[0]; -}; - -struct trace_event_raw_clock { - struct trace_entry ent; - u32 __data_loc_name; - u64 state; - u64 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_power_domain { - struct trace_entry ent; - u32 __data_loc_name; - u64 state; - u64 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_cpu_latency_qos_request { - struct trace_entry ent; - s32 value; - char __data[0]; -}; - -struct trace_event_raw_pm_qos_update { - struct trace_entry ent; - enum pm_qos_req_action action; - int prev_value; - int curr_value; - char __data[0]; -}; - -struct trace_event_raw_dev_pm_qos_request { - struct trace_entry ent; - u32 __data_loc_name; - enum dev_pm_qos_req_type type; - s32 new_value; - char __data[0]; -}; - -struct trace_event_data_offsets_cpu {}; - -struct trace_event_data_offsets_powernv_throttle { - u32 reason; -}; - -struct trace_event_data_offsets_pstate_sample {}; - -struct trace_event_data_offsets_cpu_frequency_limits {}; - -struct trace_event_data_offsets_device_pm_callback_start { - u32 device; - u32 driver; - u32 parent; - u32 pm_ops; -}; - -struct trace_event_data_offsets_device_pm_callback_end { - u32 device; - u32 driver; -}; - -struct trace_event_data_offsets_suspend_resume {}; - -struct trace_event_data_offsets_wakeup_source { - u32 name; -}; - -struct trace_event_data_offsets_clock { - u32 name; -}; - -struct trace_event_data_offsets_power_domain { - u32 name; -}; - -struct trace_event_data_offsets_cpu_latency_qos_request {}; - -struct trace_event_data_offsets_pm_qos_update {}; - -struct trace_event_data_offsets_dev_pm_qos_request { - u32 name; -}; - -typedef void (*btf_trace_cpu_idle)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_powernv_throttle)(void *, int, const char *, int); - -typedef void (*btf_trace_pstate_sample)(void *, u32, u32, u32, u32, u64, u64, u64, u32, u32); - -typedef void (*btf_trace_cpu_frequency)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_cpu_frequency_limits)(void *, struct cpufreq_policy *); - -typedef void (*btf_trace_device_pm_callback_start)(void *, struct device *, const char *, int); - -typedef void (*btf_trace_device_pm_callback_end)(void *, struct device *, int); - -typedef void (*btf_trace_suspend_resume)(void *, const char *, int, bool); - -typedef void (*btf_trace_wakeup_source_activate)(void *, const char *, unsigned int); - -typedef void (*btf_trace_wakeup_source_deactivate)(void *, const char *, unsigned int); - -typedef void (*btf_trace_clock_enable)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_clock_disable)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_clock_set_rate)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_power_domain_target)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_pm_qos_add_request)(void *, s32); - -typedef void (*btf_trace_pm_qos_update_request)(void *, s32); - -typedef void (*btf_trace_pm_qos_remove_request)(void *, s32); - -typedef void (*btf_trace_pm_qos_update_target)(void *, enum pm_qos_req_action, int, int); - -typedef void (*btf_trace_pm_qos_update_flags)(void *, enum pm_qos_req_action, int, int); - -typedef void (*btf_trace_dev_pm_qos_add_request)(void *, const char *, enum dev_pm_qos_req_type, s32); - -typedef void (*btf_trace_dev_pm_qos_update_request)(void *, const char *, enum dev_pm_qos_req_type, s32); - -typedef void (*btf_trace_dev_pm_qos_remove_request)(void *, const char *, enum dev_pm_qos_req_type, s32); - -struct trace_event_raw_rpm_internal { - struct trace_entry ent; - u32 __data_loc_name; - int flags; - int usage_count; - int disable_depth; - int runtime_auto; - int request_pending; - int irq_safe; - int child_count; - char __data[0]; -}; - -struct trace_event_raw_rpm_return_int { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int ip; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_rpm_internal { - u32 name; -}; - -struct trace_event_data_offsets_rpm_return_int { - u32 name; -}; - -typedef void (*btf_trace_rpm_suspend)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_resume)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_idle)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_usage)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_return_int)(void *, struct device *, long unsigned int, int); - -typedef int (*dynevent_check_arg_fn_t)(void *); - -struct dynevent_arg_pair { - const char *lhs; - const char *rhs; - char operator; - char separator; -}; - -struct trace_probe_log { - const char *subsystem; - const char **argv; - int argc; - int index; -}; - -struct rnd_state { - __u32 s1; - __u32 s2; - __u32 s3; - __u32 s4; -}; - -struct rhash_lock_head; - -struct bucket_table { - unsigned int size; - unsigned int nest; - u32 hash_rnd; - struct list_head walkers; - struct callback_head rcu; - struct bucket_table *future_tbl; - struct lockdep_map dep_map; - long: 64; - struct rhash_lock_head *buckets[0]; -}; - -enum xdp_action { - XDP_ABORTED = 0, - XDP_DROP = 1, - XDP_PASS = 2, - XDP_TX = 3, - XDP_REDIRECT = 4, -}; - -enum bpf_jit_poke_reason { - BPF_POKE_REASON_TAIL_CALL = 0, -}; - -enum bpf_text_poke_type { - BPF_MOD_CALL = 0, - BPF_MOD_JUMP = 1, -}; - -enum xdp_mem_type { - MEM_TYPE_PAGE_SHARED = 0, - MEM_TYPE_PAGE_ORDER0 = 1, - MEM_TYPE_PAGE_POOL = 2, - MEM_TYPE_XSK_BUFF_POOL = 3, - MEM_TYPE_MAX = 4, -}; - -struct xdp_cpumap_stats { - unsigned int redirect; - unsigned int pass; - unsigned int drop; -}; - -typedef void (*bpf_jit_fill_hole_t)(void *, unsigned int); - -struct bpf_prog_dummy { - struct bpf_prog prog; -}; - -typedef u64 (*btf_bpf_user_rnd_u32)(); - -typedef u64 (*btf_bpf_get_raw_cpu_id)(); - -struct _bpf_dtab_netdev { - struct net_device *dev; -}; - -struct rhash_lock_head {}; - -struct zero_copy_allocator; - -struct page_pool; - -struct xdp_mem_allocator { - struct xdp_mem_info mem; - union { - void *allocator; - struct page_pool *page_pool; - struct zero_copy_allocator *zc_alloc; - }; - struct rhash_head node; - struct callback_head rcu; -}; - -struct trace_event_raw_xdp_exception { - struct trace_entry ent; - int prog_id; - u32 act; - int ifindex; - char __data[0]; -}; - -struct trace_event_raw_xdp_bulk_tx { - struct trace_entry ent; - int ifindex; - u32 act; - int drops; - int sent; - int err; - char __data[0]; -}; - -struct trace_event_raw_xdp_redirect_template { - struct trace_entry ent; - int prog_id; - u32 act; - int ifindex; - int err; - int to_ifindex; - u32 map_id; - int map_index; - char __data[0]; -}; - -struct trace_event_raw_xdp_cpumap_kthread { - struct trace_entry ent; - int map_id; - u32 act; - int cpu; - unsigned int drops; - unsigned int processed; - int sched; - unsigned int xdp_pass; - unsigned int xdp_drop; - unsigned int xdp_redirect; - char __data[0]; -}; - -struct trace_event_raw_xdp_cpumap_enqueue { - struct trace_entry ent; - int map_id; - u32 act; - int cpu; - unsigned int drops; - unsigned int processed; - int to_cpu; - char __data[0]; -}; - -struct trace_event_raw_xdp_devmap_xmit { - struct trace_entry ent; - int from_ifindex; - u32 act; - int to_ifindex; - int drops; - int sent; - int err; - char __data[0]; -}; - -struct trace_event_raw_mem_disconnect { - struct trace_entry ent; - const struct xdp_mem_allocator *xa; - u32 mem_id; - u32 mem_type; - const void *allocator; - char __data[0]; -}; - -struct trace_event_raw_mem_connect { - struct trace_entry ent; - const struct xdp_mem_allocator *xa; - u32 mem_id; - u32 mem_type; - const void *allocator; - const struct xdp_rxq_info *rxq; - int ifindex; - char __data[0]; -}; - -struct trace_event_raw_mem_return_failed { - struct trace_entry ent; - const struct page *page; - u32 mem_id; - u32 mem_type; - char __data[0]; -}; - -struct trace_event_data_offsets_xdp_exception {}; - -struct trace_event_data_offsets_xdp_bulk_tx {}; - -struct trace_event_data_offsets_xdp_redirect_template {}; - -struct trace_event_data_offsets_xdp_cpumap_kthread {}; - -struct trace_event_data_offsets_xdp_cpumap_enqueue {}; - -struct trace_event_data_offsets_xdp_devmap_xmit {}; - -struct trace_event_data_offsets_mem_disconnect {}; - -struct trace_event_data_offsets_mem_connect {}; - -struct trace_event_data_offsets_mem_return_failed {}; - -typedef void (*btf_trace_xdp_exception)(void *, const struct net_device *, const struct bpf_prog *, u32); - -typedef void (*btf_trace_xdp_bulk_tx)(void *, const struct net_device *, int, int, int); - -typedef void (*btf_trace_xdp_redirect)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, const struct bpf_map *, u32); - -typedef void (*btf_trace_xdp_redirect_err)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, const struct bpf_map *, u32); - -typedef void (*btf_trace_xdp_redirect_map)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, const struct bpf_map *, u32); - -typedef void (*btf_trace_xdp_redirect_map_err)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, const struct bpf_map *, u32); - -typedef void (*btf_trace_xdp_cpumap_kthread)(void *, int, unsigned int, unsigned int, int, struct xdp_cpumap_stats *); - -typedef void (*btf_trace_xdp_cpumap_enqueue)(void *, int, unsigned int, unsigned int, int); - -typedef void (*btf_trace_xdp_devmap_xmit)(void *, const struct net_device *, const struct net_device *, int, int, int); - -typedef void (*btf_trace_mem_disconnect)(void *, const struct xdp_mem_allocator *); - -typedef void (*btf_trace_mem_connect)(void *, const struct xdp_mem_allocator *, const struct xdp_rxq_info *); - -typedef void (*btf_trace_mem_return_failed)(void *, const struct xdp_mem_info *, const struct page *); - -enum bpf_cmd { - BPF_MAP_CREATE = 0, - BPF_MAP_LOOKUP_ELEM = 1, - BPF_MAP_UPDATE_ELEM = 2, - BPF_MAP_DELETE_ELEM = 3, - BPF_MAP_GET_NEXT_KEY = 4, - BPF_PROG_LOAD = 5, - BPF_OBJ_PIN = 6, - BPF_OBJ_GET = 7, - BPF_PROG_ATTACH = 8, - BPF_PROG_DETACH = 9, - BPF_PROG_TEST_RUN = 10, - BPF_PROG_GET_NEXT_ID = 11, - BPF_MAP_GET_NEXT_ID = 12, - BPF_PROG_GET_FD_BY_ID = 13, - BPF_MAP_GET_FD_BY_ID = 14, - BPF_OBJ_GET_INFO_BY_FD = 15, - BPF_PROG_QUERY = 16, - BPF_RAW_TRACEPOINT_OPEN = 17, - BPF_BTF_LOAD = 18, - BPF_BTF_GET_FD_BY_ID = 19, - BPF_TASK_FD_QUERY = 20, - BPF_MAP_LOOKUP_AND_DELETE_ELEM = 21, - BPF_MAP_FREEZE = 22, - BPF_BTF_GET_NEXT_ID = 23, - BPF_MAP_LOOKUP_BATCH = 24, - BPF_MAP_LOOKUP_AND_DELETE_BATCH = 25, - BPF_MAP_UPDATE_BATCH = 26, - BPF_MAP_DELETE_BATCH = 27, - BPF_LINK_CREATE = 28, - BPF_LINK_UPDATE = 29, - BPF_LINK_GET_FD_BY_ID = 30, - BPF_LINK_GET_NEXT_ID = 31, - BPF_ENABLE_STATS = 32, - BPF_ITER_CREATE = 33, - BPF_LINK_DETACH = 34, - BPF_PROG_BIND_MAP = 35, -}; - -enum { - BPF_ANY = 0, - BPF_NOEXIST = 1, - BPF_EXIST = 2, - BPF_F_LOCK = 4, -}; - -enum { - BPF_F_NO_PREALLOC = 1, - BPF_F_NO_COMMON_LRU = 2, - BPF_F_NUMA_NODE = 4, - BPF_F_RDONLY = 8, - BPF_F_WRONLY = 16, - BPF_F_STACK_BUILD_ID = 32, - BPF_F_ZERO_SEED = 64, - BPF_F_RDONLY_PROG = 128, - BPF_F_WRONLY_PROG = 256, - BPF_F_CLONE = 512, - BPF_F_MMAPABLE = 1024, - BPF_F_PRESERVE_ELEMS = 2048, - BPF_F_INNER_MAP = 4096, -}; - -enum bpf_stats_type { - BPF_STATS_RUN_TIME = 0, -}; - -struct bpf_prog_info { - __u32 type; - __u32 id; - __u8 tag[8]; - __u32 jited_prog_len; - __u32 xlated_prog_len; - __u64 jited_prog_insns; - __u64 xlated_prog_insns; - __u64 load_time; - __u32 created_by_uid; - __u32 nr_map_ids; - __u64 map_ids; - char name[16]; - __u32 ifindex; - __u32 gpl_compatible: 1; - __u64 netns_dev; - __u64 netns_ino; - __u32 nr_jited_ksyms; - __u32 nr_jited_func_lens; - __u64 jited_ksyms; - __u64 jited_func_lens; - __u32 btf_id; - __u32 func_info_rec_size; - __u64 func_info; - __u32 nr_func_info; - __u32 nr_line_info; - __u64 line_info; - __u64 jited_line_info; - __u32 nr_jited_line_info; - __u32 line_info_rec_size; - __u32 jited_line_info_rec_size; - __u32 nr_prog_tags; - __u64 prog_tags; - __u64 run_time_ns; - __u64 run_cnt; -}; - -struct bpf_map_info { - __u32 type; - __u32 id; - __u32 key_size; - __u32 value_size; - __u32 max_entries; - __u32 map_flags; - char name[16]; - __u32 ifindex; - __u32 btf_vmlinux_value_type_id; - __u64 netns_dev; - __u64 netns_ino; - __u32 btf_id; - __u32 btf_key_type_id; - __u32 btf_value_type_id; -}; - -struct bpf_btf_info { - __u64 btf; - __u32 btf_size; - __u32 id; -}; - -struct bpf_spin_lock { - __u32 val; -}; - -struct bpf_attach_target_info { - struct btf_func_model fmodel; - long int tgt_addr; - const char *tgt_name; - const struct btf_type *tgt_type; -}; - -struct bpf_link_primer { - struct bpf_link *link; - struct file *file; - int fd; - u32 id; -}; - -enum perf_bpf_event_type { - PERF_BPF_EVENT_UNKNOWN = 0, - PERF_BPF_EVENT_PROG_LOAD = 1, - PERF_BPF_EVENT_PROG_UNLOAD = 2, - PERF_BPF_EVENT_MAX = 3, -}; - -enum bpf_audit { - BPF_AUDIT_LOAD = 0, - BPF_AUDIT_UNLOAD = 1, - BPF_AUDIT_MAX = 2, -}; - -struct bpf_tracing_link { - struct bpf_link link; - enum bpf_attach_type attach_type; - struct bpf_trampoline *trampoline; - struct bpf_prog *tgt_prog; -}; - -struct bpf_raw_tp_link { - struct bpf_link link; - struct bpf_raw_event_map *btp; -}; - -struct btf_member { - __u32 name_off; - __u32 type; - __u32 offset; -}; - -enum btf_func_linkage { - BTF_FUNC_STATIC = 0, - BTF_FUNC_GLOBAL = 1, - BTF_FUNC_EXTERN = 2, -}; - -struct btf_var_secinfo { - __u32 type; - __u32 offset; - __u32 size; -}; - -enum sk_action { - SK_DROP = 0, - SK_PASS = 1, -}; - -struct bpf_verifier_log { - u32 level; - char kbuf[1024]; - char *ubuf; - u32 len_used; - u32 len_total; -}; - -struct bpf_subprog_info { - u32 start; - u32 linfo_idx; - u16 stack_depth; - bool has_tail_call; - bool tail_call_reachable; - bool has_ld_abs; -}; - -struct bpf_id_pair { - u32 old; - u32 cur; -}; - -struct bpf_verifier_stack_elem; - -struct bpf_verifier_state; - -struct bpf_verifier_state_list; - -struct bpf_insn_aux_data; - -struct bpf_verifier_env { - u32 insn_idx; - u32 prev_insn_idx; - struct bpf_prog *prog; - const struct bpf_verifier_ops *ops; - struct bpf_verifier_stack_elem *head; - int stack_size; - bool strict_alignment; - bool test_state_freq; - struct bpf_verifier_state *cur_state; - struct bpf_verifier_state_list **explored_states; - struct bpf_verifier_state_list *free_list; - struct bpf_map *used_maps[64]; - u32 used_map_cnt; - u32 id_gen; - bool explore_alu_limits; - bool allow_ptr_leaks; - bool allow_uninit_stack; - bool allow_ptr_to_map_access; - bool bpf_capable; - bool bypass_spec_v1; - bool bypass_spec_v4; - bool seen_direct_write; - struct bpf_insn_aux_data *insn_aux_data; - const struct bpf_line_info *prev_linfo; - struct bpf_verifier_log log; - struct bpf_subprog_info subprog_info[257]; - struct bpf_id_pair idmap_scratch[75]; - struct { - int *insn_state; - int *insn_stack; - int cur_stack; - } cfg; - u32 pass_cnt; - u32 subprog_cnt; - u32 prev_insn_processed; - u32 insn_processed; - u32 prev_jmps_processed; - u32 jmps_processed; - u64 verification_time; - u32 max_states_per_insn; - u32 total_states; - u32 peak_states; - u32 longest_mark_read_walk; -}; - -struct bpf_struct_ops { - const struct bpf_verifier_ops *verifier_ops; - int (*init)(struct btf *); - int (*check_member)(const struct btf_type *, const struct btf_member *); - int (*init_member)(const struct btf_type *, const struct btf_member *, void *, const void *); - int (*reg)(void *); - void (*unreg)(void *); - const struct btf_type *type; - const struct btf_type *value_type; - const char *name; - struct btf_func_model func_models[64]; - u32 type_id; - u32 value_id; -}; - -typedef u32 (*bpf_convert_ctx_access_t)(enum bpf_access_type, const struct bpf_insn *, struct bpf_insn *, struct bpf_prog *, u32 *); - -struct tnum { - u64 value; - u64 mask; -}; - -enum bpf_reg_liveness { - REG_LIVE_NONE = 0, - REG_LIVE_READ32 = 1, - REG_LIVE_READ64 = 2, - REG_LIVE_READ = 3, - REG_LIVE_WRITTEN = 4, - REG_LIVE_DONE = 8, -}; - -struct bpf_reg_state { - enum bpf_reg_type type; - union { - u16 range; - struct bpf_map *map_ptr; - u32 btf_id; - u32 mem_size; - long unsigned int raw; - }; - s32 off; - u32 id; - u32 ref_obj_id; - struct tnum var_off; - s64 smin_value; - s64 smax_value; - u64 umin_value; - u64 umax_value; - s32 s32_min_value; - s32 s32_max_value; - u32 u32_min_value; - u32 u32_max_value; - struct bpf_reg_state *parent; - u32 frameno; - s32 subreg_def; - enum bpf_reg_liveness live; - bool precise; -}; - -enum bpf_stack_slot_type { - STACK_INVALID = 0, - STACK_SPILL = 1, - STACK_MISC = 2, - STACK_ZERO = 3, -}; - -struct bpf_stack_state { - struct bpf_reg_state spilled_ptr; - u8 slot_type[8]; -}; - -struct bpf_reference_state { - int id; - int insn_idx; -}; - -struct bpf_func_state { - struct bpf_reg_state regs[11]; - int callsite; - u32 frameno; - u32 subprogno; - int acquired_refs; - struct bpf_reference_state *refs; - int allocated_stack; - struct bpf_stack_state *stack; -}; - -struct bpf_idx_pair { - u32 prev_idx; - u32 idx; -}; - -struct bpf_verifier_state { - struct bpf_func_state *frame[8]; - struct bpf_verifier_state *parent; - u32 branches; - u32 insn_idx; - u32 curframe; - u32 active_spin_lock; - bool speculative; - u32 first_insn_idx; - u32 last_insn_idx; - struct bpf_idx_pair *jmp_history; - u32 jmp_history_cnt; -}; - -struct bpf_verifier_state_list { - struct bpf_verifier_state state; - struct bpf_verifier_state_list *next; - int miss_cnt; - int hit_cnt; -}; - -struct bpf_insn_aux_data { - union { - enum bpf_reg_type ptr_type; - long unsigned int map_ptr_state; - s32 call_imm; - u32 alu_limit; - struct { - u32 map_index; - u32 map_off; - }; - struct { - enum bpf_reg_type reg_type; - union { - u32 btf_id; - u32 mem_size; - }; - } btf_var; - }; - u64 map_key_state; - int ctx_field_size; - u32 seen; - bool sanitize_stack_spill; - bool zext_dst; - u8 alu_state; - unsigned int orig_idx; - bool prune_point; -}; - -struct bpf_verifier_stack_elem { - struct bpf_verifier_state st; - int insn_idx; - int prev_insn_idx; - struct bpf_verifier_stack_elem *next; - u32 log_pos; -}; - -enum { - BTF_SOCK_TYPE_INET = 0, - BTF_SOCK_TYPE_INET_CONN = 1, - BTF_SOCK_TYPE_INET_REQ = 2, - BTF_SOCK_TYPE_INET_TW = 3, - BTF_SOCK_TYPE_REQ = 4, - BTF_SOCK_TYPE_SOCK = 5, - BTF_SOCK_TYPE_SOCK_COMMON = 6, - BTF_SOCK_TYPE_TCP = 7, - BTF_SOCK_TYPE_TCP_REQ = 8, - BTF_SOCK_TYPE_TCP_TW = 9, - BTF_SOCK_TYPE_TCP6 = 10, - BTF_SOCK_TYPE_UDP = 11, - BTF_SOCK_TYPE_UDP6 = 12, - MAX_BTF_SOCK_TYPE = 13, -}; - -typedef void (*bpf_insn_print_t)(void *, const char *, ...); - -typedef const char * (*bpf_insn_revmap_call_t)(void *, const struct bpf_insn *); - -typedef const char * (*bpf_insn_print_imm_t)(void *, const struct bpf_insn *, __u64); - -struct bpf_insn_cbs { - bpf_insn_print_t cb_print; - bpf_insn_revmap_call_t cb_call; - bpf_insn_print_imm_t cb_imm; - void *private_data; -}; - -struct bpf_call_arg_meta { - struct bpf_map *map_ptr; - bool raw_mode; - bool pkt_access; - int regno; - int access_size; - int mem_size; - u64 msize_max_value; - int ref_obj_id; - int func_id; - u32 btf_id; - u32 ret_btf_id; -}; - -enum reg_arg_type { - SRC_OP = 0, - DST_OP = 1, - DST_OP_NO_MARK = 2, -}; - -enum stack_access_src { - ACCESS_DIRECT = 1, - ACCESS_HELPER = 2, -}; - -struct bpf_reg_types { - const enum bpf_reg_type types[10]; - u32 *btf_id; -}; - -enum { - REASON_BOUNDS = 4294967295, - REASON_TYPE = 4294967294, - REASON_PATHS = 4294967293, - REASON_LIMIT = 4294967292, - REASON_STACK = 4294967291, -}; - -struct bpf_sanitize_info { - struct bpf_insn_aux_data aux; - bool mask_to_left; -}; - -enum { - DISCOVERED = 16, - EXPLORED = 32, - FALLTHROUGH = 1, - BRANCH = 2, -}; - -struct tree_descr { - const char *name; - const struct file_operations *ops; - int mode; -}; - -struct umd_info { - const char *driver_name; - struct file *pipe_to_umh; - struct file *pipe_from_umh; - struct path wd; - struct pid *tgid; -}; - -struct bpf_preload_info { - char link_name[16]; - int link_id; -}; - -struct bpf_preload_ops { - struct umd_info info; - int (*preload)(struct bpf_preload_info *); - int (*finish)(); - struct module *owner; -}; - -enum bpf_type { - BPF_TYPE_UNSPEC = 0, - BPF_TYPE_PROG = 1, - BPF_TYPE_MAP = 2, - BPF_TYPE_LINK = 3, -}; - -struct map_iter { - void *key; - bool done; -}; - -enum { - OPT_MODE = 0, -}; - -struct bpf_mount_opts { - umode_t mode; -}; - -struct bpf_pidns_info { - __u32 pid; - __u32 tgid; -}; - -struct bpf_cgroup_storage_info { - struct task_struct *task; - struct bpf_cgroup_storage *storage[2]; -}; - -typedef u64 (*btf_bpf_map_lookup_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_map_update_elem)(struct bpf_map *, void *, void *, u64); - -typedef u64 (*btf_bpf_map_delete_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_map_push_elem)(struct bpf_map *, void *, u64); - -typedef u64 (*btf_bpf_map_pop_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_map_peek_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_get_smp_processor_id)(); - -typedef u64 (*btf_bpf_get_numa_node_id)(); - -typedef u64 (*btf_bpf_ktime_get_ns)(); - -typedef u64 (*btf_bpf_ktime_get_boot_ns)(); - -typedef u64 (*btf_bpf_get_current_pid_tgid)(); - -typedef u64 (*btf_bpf_get_current_uid_gid)(); - -typedef u64 (*btf_bpf_get_current_comm)(char *, u32); - -typedef u64 (*btf_bpf_spin_lock)(struct bpf_spin_lock *); - -typedef u64 (*btf_bpf_spin_unlock)(struct bpf_spin_lock *); - -typedef u64 (*btf_bpf_jiffies64)(); - -typedef u64 (*btf_bpf_get_current_cgroup_id)(); - -typedef u64 (*btf_bpf_get_current_ancestor_cgroup_id)(int); - -typedef u64 (*btf_bpf_get_local_storage)(struct bpf_map *, u64); - -typedef u64 (*btf_bpf_strtol)(const char *, size_t, u64, long int *); - -typedef u64 (*btf_bpf_strtoul)(const char *, size_t, u64, long unsigned int *); - -typedef u64 (*btf_bpf_get_ns_current_pid_tgid)(u64, u64, struct bpf_pidns_info *, u32); - -typedef u64 (*btf_bpf_event_output_data)(void *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_copy_from_user)(void *, u32, const void *); - -typedef u64 (*btf_bpf_per_cpu_ptr)(const void *, u32); - -typedef u64 (*btf_bpf_this_cpu_ptr)(const void *); - -union bpf_iter_link_info { - struct { - __u32 map_fd; - } map; -}; - -typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *, union bpf_iter_link_info *, struct bpf_iter_aux_info *); - -typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *); - -typedef void (*bpf_iter_show_fdinfo_t)(const struct bpf_iter_aux_info *, struct seq_file *); - -typedef int (*bpf_iter_fill_link_info_t)(const struct bpf_iter_aux_info *, struct bpf_link_info *); - -struct bpf_iter_reg { - const char *target; - bpf_iter_attach_target_t attach_target; - bpf_iter_detach_target_t detach_target; - bpf_iter_show_fdinfo_t show_fdinfo; - bpf_iter_fill_link_info_t fill_link_info; - u32 ctx_arg_info_size; - struct bpf_ctx_arg_aux ctx_arg_info[2]; - const struct bpf_iter_seq_info *seq_info; -}; - -struct bpf_iter_meta { - union { - struct seq_file *seq; - }; - u64 session_id; - u64 seq_num; -}; - -struct bpf_iter_target_info { - struct list_head list; - const struct bpf_iter_reg *reg_info; - u32 btf_id; -}; - -struct bpf_iter_link { - struct bpf_link link; - struct bpf_iter_aux_info aux; - struct bpf_iter_target_info *tinfo; -}; - -struct bpf_iter_priv_data { - struct bpf_iter_target_info *tinfo; - const struct bpf_iter_seq_info *seq_info; - struct bpf_prog *prog; - u64 session_id; - u64 seq_num; - bool done_stop; - long: 56; - u8 target_private[0]; -}; - -struct bpf_iter_seq_map_info { - u32 map_id; -}; - -struct bpf_iter__bpf_map { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_map *map; - }; -}; - -struct bpf_iter_seq_task_common { - struct pid_namespace *ns; -}; - -struct bpf_iter_seq_task_info { - struct bpf_iter_seq_task_common common; - u32 tid; -}; - -struct bpf_iter__task { - union { - struct bpf_iter_meta *meta; - }; - union { - struct task_struct *task; - }; -}; - -struct bpf_iter_seq_task_file_info { - struct bpf_iter_seq_task_common common; - struct task_struct *task; - struct files_struct *files; - u32 tid; - u32 fd; -}; - -struct bpf_iter__task_file { - union { - struct bpf_iter_meta *meta; - }; - union { - struct task_struct *task; - }; - u32 fd; - union { - struct file *file; - }; -}; - -struct bpf_iter_seq_prog_info { - u32 prog_id; -}; - -struct bpf_iter__bpf_prog { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_prog *prog; - }; -}; - -struct bpf_iter__bpf_map_elem { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_map *map; - }; - union { - void *key; - }; - union { - void *value; - }; -}; - -struct pcpu_freelist_node; - -struct pcpu_freelist_head { - struct pcpu_freelist_node *first; - raw_spinlock_t lock; -}; - -struct pcpu_freelist_node { - struct pcpu_freelist_node *next; -}; - -struct pcpu_freelist { - struct pcpu_freelist_head *freelist; - struct pcpu_freelist_head extralist; -}; - -struct bpf_lru_node { - struct list_head list; - u16 cpu; - u8 type; - u8 ref; -}; - -struct bpf_lru_list { - struct list_head lists[3]; - unsigned int counts[2]; - struct list_head *next_inactive_rotation; - raw_spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_lru_locallist { - struct list_head lists[2]; - u16 next_steal; - raw_spinlock_t lock; -}; - -struct bpf_common_lru { - struct bpf_lru_list lru_list; - struct bpf_lru_locallist *local_list; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef bool (*del_from_htab_func)(void *, struct bpf_lru_node *); - -struct bpf_lru { - union { - struct bpf_common_lru common_lru; - struct bpf_lru_list *percpu_lru; - }; - del_from_htab_func del_from_htab; - void *del_arg; - unsigned int hash_offset; - unsigned int nr_scans; - bool percpu; - long: 56; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bucket { - struct hlist_nulls_head head; - union { - raw_spinlock_t raw_lock; - spinlock_t lock; - }; -}; - -struct htab_elem; - -struct bpf_htab { - struct bpf_map map; - struct bucket *buckets; - void *elems; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct pcpu_freelist freelist; - struct bpf_lru lru; - }; - struct htab_elem **extra_elems; - atomic_t count; - u32 n_buckets; - u32 elem_size; - u32 hashrnd; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct htab_elem { - union { - struct hlist_nulls_node hash_node; - struct { - void *padding; - union { - struct bpf_htab *htab; - struct pcpu_freelist_node fnode; - struct htab_elem *batch_flink; - }; - }; - }; - union { - struct callback_head rcu; - struct bpf_lru_node lru_node; - }; - u32 hash; - int: 32; - char key[0]; -}; - -struct bpf_iter_seq_hash_map_info { - struct bpf_map *map; - struct bpf_htab *htab; - void *percpu_value_buf; - u32 bucket_id; - u32 skip_elems; -}; - -struct bpf_iter_seq_array_map_info { - struct bpf_map *map; - void *percpu_value_buf; - u32 index; -}; - -struct prog_poke_elem { - struct list_head list; - struct bpf_prog_aux *aux; -}; - -enum bpf_lru_list_type { - BPF_LRU_LIST_T_ACTIVE = 0, - BPF_LRU_LIST_T_INACTIVE = 1, - BPF_LRU_LIST_T_FREE = 2, - BPF_LRU_LOCAL_LIST_T_FREE = 3, - BPF_LRU_LOCAL_LIST_T_PENDING = 4, -}; - -struct bpf_lpm_trie_key { - __u32 prefixlen; - __u8 data[0]; -}; - -struct lpm_trie_node { - struct callback_head rcu; - struct lpm_trie_node *child[2]; - u32 prefixlen; - u32 flags; - u8 data[0]; -}; - -struct lpm_trie { - struct bpf_map map; - struct lpm_trie_node *root; - size_t n_entries; - size_t max_prefixlen; - size_t data_size; - spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_cgroup_storage_map { - struct bpf_map map; - spinlock_t lock; - struct rb_root root; - struct list_head list; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_queue_stack { - struct bpf_map map; - raw_spinlock_t lock; - u32 head; - u32 tail; - u32 size; - char elements[0]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum { - BPF_RB_NO_WAKEUP = 1, - BPF_RB_FORCE_WAKEUP = 2, -}; - -enum { - BPF_RB_AVAIL_DATA = 0, - BPF_RB_RING_SIZE = 1, - BPF_RB_CONS_POS = 2, - BPF_RB_PROD_POS = 3, -}; - -enum { - BPF_RINGBUF_BUSY_BIT = 2147483648, - BPF_RINGBUF_DISCARD_BIT = 1073741824, - BPF_RINGBUF_HDR_SZ = 8, -}; - -struct bpf_ringbuf { - wait_queue_head_t waitq; - struct irq_work work; - u64 mask; - struct page **pages; - int nr_pages; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t spinlock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int consumer_pos; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int producer_pos; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - char data[0]; -}; - -struct bpf_ringbuf_map { - struct bpf_map map; - struct bpf_map_memory memory; - struct bpf_ringbuf *rb; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_ringbuf_hdr { - u32 len; - u32 pg_off; -}; - -typedef u64 (*btf_bpf_ringbuf_reserve)(struct bpf_map *, u64, u64); - -typedef u64 (*btf_bpf_ringbuf_submit)(void *, u64); - -typedef u64 (*btf_bpf_ringbuf_discard)(void *, u64); - -typedef u64 (*btf_bpf_ringbuf_output)(struct bpf_map *, void *, u64, u64); - -typedef u64 (*btf_bpf_ringbuf_query)(struct bpf_map *, u64); - -struct bpf_tramp_progs { - struct bpf_prog *progs[40]; - int nr_progs; -}; - -struct btf_enum { - __u32 name_off; - __s32 val; -}; - -struct btf_array { - __u32 type; - __u32 index_type; - __u32 nelems; -}; - -struct btf_param { - __u32 name_off; - __u32 type; -}; - -enum { - BTF_VAR_STATIC = 0, - BTF_VAR_GLOBAL_ALLOCATED = 1, - BTF_VAR_GLOBAL_EXTERN = 2, -}; - -struct btf_var { - __u32 linkage; -}; - -struct bpf_flow_keys { - __u16 nhoff; - __u16 thoff; - __u16 addr_proto; - __u8 is_frag; - __u8 is_first_frag; - __u8 is_encap; - __u8 ip_proto; - __be16 n_proto; - __be16 sport; - __be16 dport; - union { - struct { - __be32 ipv4_src; - __be32 ipv4_dst; - }; - struct { - __u32 ipv6_src[4]; - __u32 ipv6_dst[4]; - }; - }; - __u32 flags; - __be32 flow_label; -}; - -struct bpf_sock { - __u32 bound_dev_if; - __u32 family; - __u32 type; - __u32 protocol; - __u32 mark; - __u32 priority; - __u32 src_ip4; - __u32 src_ip6[4]; - __u32 src_port; - __u32 dst_port; - __u32 dst_ip4; - __u32 dst_ip6[4]; - __u32 state; - __s32 rx_queue_mapping; -}; - -struct __sk_buff { - __u32 len; - __u32 pkt_type; - __u32 mark; - __u32 queue_mapping; - __u32 protocol; - __u32 vlan_present; - __u32 vlan_tci; - __u32 vlan_proto; - __u32 priority; - __u32 ingress_ifindex; - __u32 ifindex; - __u32 tc_index; - __u32 cb[5]; - __u32 hash; - __u32 tc_classid; - __u32 data; - __u32 data_end; - __u32 napi_id; - __u32 family; - __u32 remote_ip4; - __u32 local_ip4; - __u32 remote_ip6[4]; - __u32 local_ip6[4]; - __u32 remote_port; - __u32 local_port; - __u32 data_meta; - union { - struct bpf_flow_keys *flow_keys; - }; - __u64 tstamp; - __u32 wire_len; - __u32 gso_segs; - union { - struct bpf_sock *sk; - }; - __u32 gso_size; -}; - -struct xdp_md { - __u32 data; - __u32 data_end; - __u32 data_meta; - __u32 ingress_ifindex; - __u32 rx_queue_index; - __u32 egress_ifindex; -}; - -struct sk_msg_md { - union { - void *data; - }; - union { - void *data_end; - }; - __u32 family; - __u32 remote_ip4; - __u32 local_ip4; - __u32 remote_ip6[4]; - __u32 local_ip6[4]; - __u32 remote_port; - __u32 local_port; - __u32 size; - union { - struct bpf_sock *sk; - }; -}; - -struct sk_reuseport_md { - union { - void *data; - }; - union { - void *data_end; - }; - __u32 len; - __u32 eth_protocol; - __u32 ip_protocol; - __u32 bind_inany; - __u32 hash; -}; - -struct bpf_sock_addr { - __u32 user_family; - __u32 user_ip4; - __u32 user_ip6[4]; - __u32 user_port; - __u32 family; - __u32 type; - __u32 protocol; - __u32 msg_src_ip4; - __u32 msg_src_ip6[4]; - union { - struct bpf_sock *sk; - }; -}; - -struct bpf_sock_ops { - __u32 op; - union { - __u32 args[4]; - __u32 reply; - __u32 replylong[4]; - }; - __u32 family; - __u32 remote_ip4; - __u32 local_ip4; - __u32 remote_ip6[4]; - __u32 local_ip6[4]; - __u32 remote_port; - __u32 local_port; - __u32 is_fullsock; - __u32 snd_cwnd; - __u32 srtt_us; - __u32 bpf_sock_ops_cb_flags; - __u32 state; - __u32 rtt_min; - __u32 snd_ssthresh; - __u32 rcv_nxt; - __u32 snd_nxt; - __u32 snd_una; - __u32 mss_cache; - __u32 ecn_flags; - __u32 rate_delivered; - __u32 rate_interval_us; - __u32 packets_out; - __u32 retrans_out; - __u32 total_retrans; - __u32 segs_in; - __u32 data_segs_in; - __u32 segs_out; - __u32 data_segs_out; - __u32 lost_out; - __u32 sacked_out; - __u32 sk_txhash; - __u64 bytes_received; - __u64 bytes_acked; - union { - struct bpf_sock *sk; - }; - union { - void *skb_data; - }; - union { - void *skb_data_end; - }; - __u32 skb_len; - __u32 skb_tcp_flags; -}; - -struct bpf_cgroup_dev_ctx { - __u32 access_type; - __u32 major; - __u32 minor; -}; - -struct bpf_sysctl { - __u32 write; - __u32 file_pos; -}; - -struct bpf_sockopt { - union { - struct bpf_sock *sk; - }; - union { - void *optval; - }; - union { - void *optval_end; - }; - __s32 level; - __s32 optname; - __s32 optlen; - __s32 retval; -}; - -struct bpf_sk_lookup { - union { - struct bpf_sock *sk; - }; - __u32 family; - __u32 protocol; - __u32 remote_ip4; - __u32 remote_ip6[4]; - __u32 remote_port; - __u32 local_ip4; - __u32 local_ip6[4]; - __u32 local_port; -}; - -struct sk_reuseport_kern { - struct sk_buff *skb; - struct sock *sk; - struct sock *selected_sk; - void *data_end; - u32 hash; - u32 reuseport_id; - bool bind_inany; -}; - -struct bpf_flow_dissector { - struct bpf_flow_keys *flow_keys; - const struct sk_buff *skb; - void *data; - void *data_end; -}; - -struct inet_listen_hashbucket { - spinlock_t lock; - unsigned int count; - union { - struct hlist_head head; - struct hlist_nulls_head nulls_head; - }; -}; - -struct inet_ehash_bucket; - -struct inet_bind_hashbucket; - -struct inet_hashinfo { - struct inet_ehash_bucket *ehash; - spinlock_t *ehash_locks; - unsigned int ehash_mask; - unsigned int ehash_locks_mask; - struct kmem_cache *bind_bucket_cachep; - struct inet_bind_hashbucket *bhash; - unsigned int bhash_size; - unsigned int lhash2_mask; - struct inet_listen_hashbucket *lhash2; - long: 64; - struct inet_listen_hashbucket listening_hash[32]; -}; - -struct ip_ra_chain { - struct ip_ra_chain *next; - struct sock *sk; - union { - void (*destructor)(struct sock *); - struct sock *saved_sk; - }; - struct callback_head rcu; -}; - -struct fib_table { - struct hlist_node tb_hlist; - u32 tb_id; - int tb_num_default; - struct callback_head rcu; - long unsigned int *tb_data; - long unsigned int __data[0]; -}; - -struct inet_peer_base { - struct rb_root rb_root; - seqlock_t lock; - int total; -}; - -struct tcp_fastopen_context { - siphash_key_t key[2]; - int num; - struct callback_head rcu; -}; - -struct xdp_txq_info { - struct net_device *dev; -}; - -struct xdp_buff { - void *data; - void *data_end; - void *data_meta; - void *data_hard_start; - struct xdp_rxq_info *rxq; - struct xdp_txq_info *txq; - u32 frame_sz; -}; - -struct bpf_sock_addr_kern { - struct sock *sk; - struct sockaddr *uaddr; - u64 tmp_reg; - void *t_ctx; -}; - -struct bpf_sock_ops_kern { - struct sock *sk; - union { - u32 args[4]; - u32 reply; - u32 replylong[4]; - }; - struct sk_buff *syn_skb; - struct sk_buff *skb; - void *skb_data_end; - u8 op; - u8 is_fullsock; - u8 remaining_opt_len; - u64 temp; -}; - -struct bpf_sysctl_kern { - struct ctl_table_header *head; - struct ctl_table *table; - void *cur_val; - size_t cur_len; - void *new_val; - size_t new_len; - int new_updated; - int write; - loff_t *ppos; - u64 tmp_reg; -}; - -struct bpf_sockopt_kern { - struct sock *sk; - u8 *optval; - u8 *optval_end; - s32 level; - s32 optname; - s32 optlen; - s32 retval; -}; - -struct bpf_sk_lookup_kern { - u16 family; - u16 protocol; - __be16 sport; - u16 dport; - struct { - __be32 saddr; - __be32 daddr; - } v4; - struct { - const struct in6_addr *saddr; - const struct in6_addr *daddr; - } v6; - struct sock *selected_sk; - bool no_reuseport; -}; - -struct lwtunnel_state { - __u16 type; - __u16 flags; - __u16 headroom; - atomic_t refcnt; - int (*orig_output)(struct net *, struct sock *, struct sk_buff *); - int (*orig_input)(struct sk_buff *); - struct callback_head rcu; - __u8 data[0]; -}; - -struct sock_reuseport { - struct callback_head rcu; - u16 max_socks; - u16 num_socks; - unsigned int synq_overflow_ts; - unsigned int reuseport_id; - unsigned int bind_inany: 1; - unsigned int has_conns: 1; - struct bpf_prog *prog; - struct sock *socks[0]; -}; - -struct inet_ehash_bucket { - struct hlist_nulls_head chain; -}; - -struct inet_bind_hashbucket { - spinlock_t lock; - struct hlist_head chain; -}; - -struct ack_sample { - u32 pkts_acked; - s32 rtt_us; - u32 in_flight; -}; - -struct rate_sample { - u64 prior_mstamp; - u32 prior_delivered; - s32 delivered; - long int interval_us; - u32 snd_interval_us; - u32 rcv_interval_us; - long int rtt_us; - int losses; - u32 acked_sacked; - u32 prior_in_flight; - bool is_app_limited; - bool is_retrans; - bool is_ack_delayed; -}; - -struct sk_msg_sg { - u32 start; - u32 curr; - u32 end; - u32 size; - u32 copybreak; - long unsigned int copy; - struct scatterlist data[19]; -}; - -struct sk_msg { - struct sk_msg_sg sg; - void *data; - void *data_end; - u32 apply_bytes; - u32 cork_bytes; - u32 flags; - struct sk_buff *skb; - struct sock *sk_redir; - struct sock *sk; - struct list_head list; -}; - -enum verifier_phase { - CHECK_META = 0, - CHECK_TYPE = 1, -}; - -struct resolve_vertex { - const struct btf_type *t; - u32 type_id; - u16 next_member; -}; - -enum visit_state { - NOT_VISITED = 0, - VISITED = 1, - RESOLVED = 2, -}; - -enum resolve_mode { - RESOLVE_TBD = 0, - RESOLVE_PTR = 1, - RESOLVE_STRUCT_OR_ARRAY = 2, -}; - -struct btf_sec_info { - u32 off; - u32 len; -}; - -struct btf_verifier_env { - struct btf *btf; - u8 *visit_states; - struct resolve_vertex stack[32]; - struct bpf_verifier_log log; - u32 log_type_id; - u32 top_stack; - enum verifier_phase phase; - enum resolve_mode resolve_mode; -}; - -struct btf_show { - u64 flags; - void *target; - void (*showfn)(struct btf_show *, const char *, va_list); - const struct btf *btf; - struct { - u8 depth; - u8 depth_to_show; - u8 depth_check; - u8 array_member: 1; - u8 array_terminated: 1; - u16 array_encoding; - u32 type_id; - int status; - const struct btf_type *type; - const struct btf_member *member; - char name[80]; - } state; - struct { - u32 size; - void *head; - void *data; - u8 safe[32]; - } obj; -}; - -struct btf_kind_operations { - s32 (*check_meta)(struct btf_verifier_env *, const struct btf_type *, u32); - int (*resolve)(struct btf_verifier_env *, const struct resolve_vertex *); - int (*check_member)(struct btf_verifier_env *, const struct btf_type *, const struct btf_member *, const struct btf_type *); - int (*check_kflag_member)(struct btf_verifier_env *, const struct btf_type *, const struct btf_member *, const struct btf_type *); - void (*log_details)(struct btf_verifier_env *, const struct btf_type *); - void (*show)(const struct btf *, const struct btf_type *, u32, void *, u8, struct btf_show *); -}; - -struct bpf_ctx_convert { - struct __sk_buff BPF_PROG_TYPE_SOCKET_FILTER_prog; - struct sk_buff BPF_PROG_TYPE_SOCKET_FILTER_kern; - struct __sk_buff BPF_PROG_TYPE_SCHED_CLS_prog; - struct sk_buff BPF_PROG_TYPE_SCHED_CLS_kern; - struct __sk_buff BPF_PROG_TYPE_SCHED_ACT_prog; - struct sk_buff BPF_PROG_TYPE_SCHED_ACT_kern; - struct xdp_md BPF_PROG_TYPE_XDP_prog; - struct xdp_buff BPF_PROG_TYPE_XDP_kern; - struct __sk_buff BPF_PROG_TYPE_CGROUP_SKB_prog; - struct sk_buff BPF_PROG_TYPE_CGROUP_SKB_kern; - struct bpf_sock BPF_PROG_TYPE_CGROUP_SOCK_prog; - struct sock BPF_PROG_TYPE_CGROUP_SOCK_kern; - struct bpf_sock_addr BPF_PROG_TYPE_CGROUP_SOCK_ADDR_prog; - struct bpf_sock_addr_kern BPF_PROG_TYPE_CGROUP_SOCK_ADDR_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_IN_prog; - struct sk_buff BPF_PROG_TYPE_LWT_IN_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_OUT_prog; - struct sk_buff BPF_PROG_TYPE_LWT_OUT_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_XMIT_prog; - struct sk_buff BPF_PROG_TYPE_LWT_XMIT_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_SEG6LOCAL_prog; - struct sk_buff BPF_PROG_TYPE_LWT_SEG6LOCAL_kern; - struct bpf_sock_ops BPF_PROG_TYPE_SOCK_OPS_prog; - struct bpf_sock_ops_kern BPF_PROG_TYPE_SOCK_OPS_kern; - struct __sk_buff BPF_PROG_TYPE_SK_SKB_prog; - struct sk_buff BPF_PROG_TYPE_SK_SKB_kern; - struct sk_msg_md BPF_PROG_TYPE_SK_MSG_prog; - struct sk_msg BPF_PROG_TYPE_SK_MSG_kern; - struct __sk_buff BPF_PROG_TYPE_FLOW_DISSECTOR_prog; - struct bpf_flow_dissector BPF_PROG_TYPE_FLOW_DISSECTOR_kern; - bpf_user_pt_regs_t BPF_PROG_TYPE_KPROBE_prog; - struct pt_regs BPF_PROG_TYPE_KPROBE_kern; - __u64 BPF_PROG_TYPE_TRACEPOINT_prog; - u64 BPF_PROG_TYPE_TRACEPOINT_kern; - struct bpf_perf_event_data BPF_PROG_TYPE_PERF_EVENT_prog; - struct bpf_perf_event_data_kern BPF_PROG_TYPE_PERF_EVENT_kern; - struct bpf_raw_tracepoint_args BPF_PROG_TYPE_RAW_TRACEPOINT_prog; - u64 BPF_PROG_TYPE_RAW_TRACEPOINT_kern; - struct bpf_raw_tracepoint_args BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE_prog; - u64 BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE_kern; - void *BPF_PROG_TYPE_TRACING_prog; - void *BPF_PROG_TYPE_TRACING_kern; - struct bpf_cgroup_dev_ctx BPF_PROG_TYPE_CGROUP_DEVICE_prog; - struct bpf_cgroup_dev_ctx BPF_PROG_TYPE_CGROUP_DEVICE_kern; - struct bpf_sysctl BPF_PROG_TYPE_CGROUP_SYSCTL_prog; - struct bpf_sysctl_kern BPF_PROG_TYPE_CGROUP_SYSCTL_kern; - struct bpf_sockopt BPF_PROG_TYPE_CGROUP_SOCKOPT_prog; - struct bpf_sockopt_kern BPF_PROG_TYPE_CGROUP_SOCKOPT_kern; - __u32 BPF_PROG_TYPE_LIRC_MODE2_prog; - u32 BPF_PROG_TYPE_LIRC_MODE2_kern; - struct sk_reuseport_md BPF_PROG_TYPE_SK_REUSEPORT_prog; - struct sk_reuseport_kern BPF_PROG_TYPE_SK_REUSEPORT_kern; - struct bpf_sk_lookup BPF_PROG_TYPE_SK_LOOKUP_prog; - struct bpf_sk_lookup_kern BPF_PROG_TYPE_SK_LOOKUP_kern; - void *BPF_PROG_TYPE_STRUCT_OPS_prog; - void *BPF_PROG_TYPE_STRUCT_OPS_kern; - void *BPF_PROG_TYPE_EXT_prog; - void *BPF_PROG_TYPE_EXT_kern; -}; - -enum { - __ctx_convertBPF_PROG_TYPE_SOCKET_FILTER = 0, - __ctx_convertBPF_PROG_TYPE_SCHED_CLS = 1, - __ctx_convertBPF_PROG_TYPE_SCHED_ACT = 2, - __ctx_convertBPF_PROG_TYPE_XDP = 3, - __ctx_convertBPF_PROG_TYPE_CGROUP_SKB = 4, - __ctx_convertBPF_PROG_TYPE_CGROUP_SOCK = 5, - __ctx_convertBPF_PROG_TYPE_CGROUP_SOCK_ADDR = 6, - __ctx_convertBPF_PROG_TYPE_LWT_IN = 7, - __ctx_convertBPF_PROG_TYPE_LWT_OUT = 8, - __ctx_convertBPF_PROG_TYPE_LWT_XMIT = 9, - __ctx_convertBPF_PROG_TYPE_LWT_SEG6LOCAL = 10, - __ctx_convertBPF_PROG_TYPE_SOCK_OPS = 11, - __ctx_convertBPF_PROG_TYPE_SK_SKB = 12, - __ctx_convertBPF_PROG_TYPE_SK_MSG = 13, - __ctx_convertBPF_PROG_TYPE_FLOW_DISSECTOR = 14, - __ctx_convertBPF_PROG_TYPE_KPROBE = 15, - __ctx_convertBPF_PROG_TYPE_TRACEPOINT = 16, - __ctx_convertBPF_PROG_TYPE_PERF_EVENT = 17, - __ctx_convertBPF_PROG_TYPE_RAW_TRACEPOINT = 18, - __ctx_convertBPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 19, - __ctx_convertBPF_PROG_TYPE_TRACING = 20, - __ctx_convertBPF_PROG_TYPE_CGROUP_DEVICE = 21, - __ctx_convertBPF_PROG_TYPE_CGROUP_SYSCTL = 22, - __ctx_convertBPF_PROG_TYPE_CGROUP_SOCKOPT = 23, - __ctx_convertBPF_PROG_TYPE_LIRC_MODE2 = 24, - __ctx_convertBPF_PROG_TYPE_SK_REUSEPORT = 25, - __ctx_convertBPF_PROG_TYPE_SK_LOOKUP = 26, - __ctx_convertBPF_PROG_TYPE_STRUCT_OPS = 27, - __ctx_convertBPF_PROG_TYPE_EXT = 28, - __ctx_convert_unused = 29, -}; - -enum bpf_struct_walk_result { - WALK_SCALAR = 0, - WALK_PTR = 1, - WALK_STRUCT = 2, -}; - -struct btf_show_snprintf { - struct btf_show show; - int len_left; - int len; -}; - -struct bpf_dispatcher_prog { - struct bpf_prog *prog; - refcount_t users; -}; - -struct bpf_dispatcher { - struct mutex mutex; - void *func; - struct bpf_dispatcher_prog progs[48]; - int num_progs; - void *image; - u32 image_off; - struct bpf_ksym ksym; -}; - -struct bpf_devmap_val { - __u32 ifindex; - union { - int fd; - __u32 id; - } bpf_prog; -}; - -enum net_device_flags { - IFF_UP = 1, - IFF_BROADCAST = 2, - IFF_DEBUG = 4, - IFF_LOOPBACK = 8, - IFF_POINTOPOINT = 16, - IFF_NOTRAILERS = 32, - IFF_RUNNING = 64, - IFF_NOARP = 128, - IFF_PROMISC = 256, - IFF_ALLMULTI = 512, - IFF_MASTER = 1024, - IFF_SLAVE = 2048, - IFF_MULTICAST = 4096, - IFF_PORTSEL = 8192, - IFF_AUTOMEDIA = 16384, - IFF_DYNAMIC = 32768, - IFF_LOWER_UP = 65536, - IFF_DORMANT = 131072, - IFF_ECHO = 262144, -}; - -struct xdp_dev_bulk_queue { - struct xdp_frame *q[16]; - struct list_head flush_node; - struct net_device *dev; - struct net_device *dev_rx; - unsigned int count; -}; - -enum netdev_cmd { - NETDEV_UP = 1, - NETDEV_DOWN = 2, - NETDEV_REBOOT = 3, - NETDEV_CHANGE = 4, - NETDEV_REGISTER = 5, - NETDEV_UNREGISTER = 6, - NETDEV_CHANGEMTU = 7, - NETDEV_CHANGEADDR = 8, - NETDEV_PRE_CHANGEADDR = 9, - NETDEV_GOING_DOWN = 10, - NETDEV_CHANGENAME = 11, - NETDEV_FEAT_CHANGE = 12, - NETDEV_BONDING_FAILOVER = 13, - NETDEV_PRE_UP = 14, - NETDEV_PRE_TYPE_CHANGE = 15, - NETDEV_POST_TYPE_CHANGE = 16, - NETDEV_POST_INIT = 17, - NETDEV_RELEASE = 18, - NETDEV_NOTIFY_PEERS = 19, - NETDEV_JOIN = 20, - NETDEV_CHANGEUPPER = 21, - NETDEV_RESEND_IGMP = 22, - NETDEV_PRECHANGEMTU = 23, - NETDEV_CHANGEINFODATA = 24, - NETDEV_BONDING_INFO = 25, - NETDEV_PRECHANGEUPPER = 26, - NETDEV_CHANGELOWERSTATE = 27, - NETDEV_UDP_TUNNEL_PUSH_INFO = 28, - NETDEV_UDP_TUNNEL_DROP_INFO = 29, - NETDEV_CHANGE_TX_QUEUE_LEN = 30, - NETDEV_CVLAN_FILTER_PUSH_INFO = 31, - NETDEV_CVLAN_FILTER_DROP_INFO = 32, - NETDEV_SVLAN_FILTER_PUSH_INFO = 33, - NETDEV_SVLAN_FILTER_DROP_INFO = 34, -}; - -struct netdev_notifier_info { - struct net_device *dev; - struct netlink_ext_ack *extack; -}; - -struct bpf_dtab; - -struct bpf_dtab_netdev { - struct net_device *dev; - struct hlist_node index_hlist; - struct bpf_dtab *dtab; - struct bpf_prog *xdp_prog; - struct callback_head rcu; - unsigned int idx; - struct bpf_devmap_val val; -}; - -struct bpf_dtab { - struct bpf_map map; - struct bpf_dtab_netdev **netdev_map; - struct list_head list; - struct hlist_head *dev_index_head; - spinlock_t index_lock; - unsigned int items; - u32 n_buckets; - long: 32; - long: 64; - long: 64; -}; - -struct bpf_cpumap_val { - __u32 qsize; - union { - int fd; - __u32 id; - } bpf_prog; -}; - -typedef struct bio_vec skb_frag_t; - -struct skb_shared_hwtstamps { - ktime_t hwtstamp; -}; - -struct skb_shared_info { - __u8 __unused; - __u8 meta_len; - __u8 nr_frags; - __u8 tx_flags; - short unsigned int gso_size; - short unsigned int gso_segs; - struct sk_buff *frag_list; - struct skb_shared_hwtstamps hwtstamps; - unsigned int gso_type; - u32 tskey; - atomic_t dataref; - void *destructor_arg; - skb_frag_t frags[17]; -}; - -struct bpf_nh_params { - u32 nh_family; - union { - u32 ipv4_nh; - struct in6_addr ipv6_nh; - }; -}; - -struct bpf_redirect_info { - u32 flags; - u32 tgt_index; - void *tgt_value; - struct bpf_map *map; - u32 kern_flags; - struct bpf_nh_params nh; -}; - -struct ptr_ring { - int producer; - spinlock_t producer_lock; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - int consumer_head; - int consumer_tail; - spinlock_t consumer_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - int size; - int batch; - void **queue; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_cpu_map_entry; - -struct xdp_bulk_queue { - void *q[8]; - struct list_head flush_node; - struct bpf_cpu_map_entry *obj; - unsigned int count; -}; - -struct bpf_cpu_map; - -struct bpf_cpu_map_entry { - u32 cpu; - int map_id; - struct xdp_bulk_queue *bulkq; - struct bpf_cpu_map *cmap; - struct ptr_ring *queue; - struct task_struct *kthread; - struct bpf_cpumap_val value; - struct bpf_prog *prog; - atomic_t refcnt; - struct callback_head rcu; - struct work_struct kthread_stop_wq; -}; - -struct bpf_cpu_map { - struct bpf_map map; - struct bpf_cpu_map_entry **cpu_map; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_local_storage_map_bucket; - -struct bpf_local_storage_map { - struct bpf_map map; - struct bpf_local_storage_map_bucket *buckets; - u32 bucket_log; - u16 elem_size; - u16 cache_idx; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_local_storage_data; - -struct bpf_local_storage { - struct bpf_local_storage_data *cache[16]; - struct hlist_head list; - void *owner; - struct callback_head rcu; - raw_spinlock_t lock; -}; - -struct bpf_local_storage_map_bucket { - struct hlist_head list; - raw_spinlock_t lock; -}; - -struct bpf_local_storage_data { - struct bpf_local_storage_map *smap; - u8 data[0]; -}; - -struct bpf_local_storage_elem { - struct hlist_node map_node; - struct hlist_node snode; - struct bpf_local_storage *local_storage; - struct callback_head rcu; - long: 64; - struct bpf_local_storage_data sdata; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_local_storage_cache { - spinlock_t idx_lock; - u64 idx_usage_counts[16]; -}; - -struct rhlist_head { - struct rhash_head rhead; - struct rhlist_head *next; -}; - -struct bpf_prog_offload_ops { - int (*insn_hook)(struct bpf_verifier_env *, int, int); - int (*finalize)(struct bpf_verifier_env *); - int (*replace_insn)(struct bpf_verifier_env *, u32, struct bpf_insn *); - int (*remove_insns)(struct bpf_verifier_env *, u32, u32); - int (*prepare)(struct bpf_prog *); - int (*translate)(struct bpf_prog *); - void (*destroy)(struct bpf_prog *); -}; - -struct bpf_offload_dev { - const struct bpf_prog_offload_ops *ops; - struct list_head netdevs; - void *priv; -}; - -struct bpf_offload_netdev { - struct rhash_head l; - struct net_device *netdev; - struct bpf_offload_dev *offdev; - struct list_head progs; - struct list_head maps; - struct list_head offdev_netdevs; -}; - -struct ns_get_path_bpf_prog_args { - struct bpf_prog *prog; - struct bpf_prog_info *info; -}; - -struct ns_get_path_bpf_map_args { - struct bpf_offloaded_map *offmap; - struct bpf_map_info *info; -}; - -struct bpf_netns_link { - struct bpf_link link; - enum bpf_attach_type type; - enum netns_bpf_attach_type netns_type; - struct net *net; - struct list_head node; -}; - -enum bpf_stack_build_id_status { - BPF_STACK_BUILD_ID_EMPTY = 0, - BPF_STACK_BUILD_ID_VALID = 1, - BPF_STACK_BUILD_ID_IP = 2, -}; - -struct bpf_stack_build_id { - __s32 status; - unsigned char build_id[20]; - union { - __u64 offset; - __u64 ip; - }; -}; - -enum { - BPF_F_SKIP_FIELD_MASK = 255, - BPF_F_USER_STACK = 256, - BPF_F_FAST_STACK_CMP = 512, - BPF_F_REUSE_STACKID = 1024, - BPF_F_USER_BUILD_ID = 2048, -}; - -typedef __u32 Elf32_Addr; - -typedef __u16 Elf32_Half; - -typedef __u32 Elf32_Off; - -struct elf32_hdr { - unsigned char e_ident[16]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -}; - -typedef struct elf32_hdr Elf32_Ehdr; - -struct elf32_phdr { - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -}; - -typedef struct elf32_phdr Elf32_Phdr; - -struct elf64_phdr { - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; - Elf64_Addr p_vaddr; - Elf64_Addr p_paddr; - Elf64_Xword p_filesz; - Elf64_Xword p_memsz; - Elf64_Xword p_align; -}; - -typedef struct elf64_phdr Elf64_Phdr; - -typedef struct elf32_note Elf32_Nhdr; - -enum perf_callchain_context { - PERF_CONTEXT_HV = 4294967264, - PERF_CONTEXT_KERNEL = 4294967168, - PERF_CONTEXT_USER = 4294966784, - PERF_CONTEXT_GUEST = 4294965248, - PERF_CONTEXT_GUEST_KERNEL = 4294965120, - PERF_CONTEXT_GUEST_USER = 4294964736, - PERF_CONTEXT_MAX = 4294963201, -}; - -struct stack_map_bucket { - struct pcpu_freelist_node fnode; - u32 hash; - u32 nr; - u64 data[0]; -}; - -struct bpf_stack_map { - struct bpf_map map; - void *elems; - struct pcpu_freelist freelist; - u32 n_buckets; - struct stack_map_bucket *buckets[0]; - long: 64; - long: 64; - long: 64; -}; - -struct stack_map_irq_work { - struct irq_work irq_work; - struct mm_struct *mm; -}; - -typedef u64 (*btf_bpf_get_stackid)(struct pt_regs *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stackid_pe)(struct bpf_perf_event_data_kern *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stack)(struct pt_regs *, void *, u32, u64); - -typedef u64 (*btf_bpf_get_task_stack)(struct task_struct *, void *, u32, u64); - -typedef u64 (*btf_bpf_get_stack_pe)(struct bpf_perf_event_data_kern *, void *, u32, u64); - -enum { - BPF_F_SYSCTL_BASE_NAME = 1, -}; - -struct bpf_prog_list { - struct list_head node; - struct bpf_prog *prog; - struct bpf_cgroup_link *link; - struct bpf_cgroup_storage *storage[2]; -}; - -struct qdisc_skb_cb { - struct { - unsigned int pkt_len; - u16 slave_dev_queue_mapping; - u16 tc_classid; - }; - unsigned char data[20]; - u16 mru; -}; - -struct bpf_skb_data_end { - struct qdisc_skb_cb qdisc_cb; - void *data_meta; - void *data_end; -}; - -enum { - TCPF_ESTABLISHED = 2, - TCPF_SYN_SENT = 4, - TCPF_SYN_RECV = 8, - TCPF_FIN_WAIT1 = 16, - TCPF_FIN_WAIT2 = 32, - TCPF_TIME_WAIT = 64, - TCPF_CLOSE = 128, - TCPF_CLOSE_WAIT = 256, - TCPF_LAST_ACK = 512, - TCPF_LISTEN = 1024, - TCPF_CLOSING = 2048, - TCPF_NEW_SYN_RECV = 4096, -}; - -typedef u64 (*btf_bpf_sysctl_get_name)(struct bpf_sysctl_kern *, char *, size_t, u64); - -typedef u64 (*btf_bpf_sysctl_get_current_value)(struct bpf_sysctl_kern *, char *, size_t); - -typedef u64 (*btf_bpf_sysctl_get_new_value)(struct bpf_sysctl_kern *, char *, size_t); - -typedef u64 (*btf_bpf_sysctl_set_new_value)(struct bpf_sysctl_kern *, const char *, size_t); - -enum sock_type { - SOCK_STREAM = 1, - SOCK_DGRAM = 2, - SOCK_RAW = 3, - SOCK_RDM = 4, - SOCK_SEQPACKET = 5, - SOCK_DCCP = 6, - SOCK_PACKET = 10, -}; - -enum { - IPPROTO_IP = 0, - IPPROTO_ICMP = 1, - IPPROTO_IGMP = 2, - IPPROTO_IPIP = 4, - IPPROTO_TCP = 6, - IPPROTO_EGP = 8, - IPPROTO_PUP = 12, - IPPROTO_UDP = 17, - IPPROTO_IDP = 22, - IPPROTO_TP = 29, - IPPROTO_DCCP = 33, - IPPROTO_IPV6 = 41, - IPPROTO_RSVP = 46, - IPPROTO_GRE = 47, - IPPROTO_ESP = 50, - IPPROTO_AH = 51, - IPPROTO_MTP = 92, - IPPROTO_BEETPH = 94, - IPPROTO_ENCAP = 98, - IPPROTO_PIM = 103, - IPPROTO_COMP = 108, - IPPROTO_SCTP = 132, - IPPROTO_UDPLITE = 136, - IPPROTO_MPLS = 137, - IPPROTO_ETHERNET = 143, - IPPROTO_RAW = 255, - IPPROTO_MPTCP = 262, - IPPROTO_MAX = 263, -}; - -enum sock_flags { - SOCK_DEAD = 0, - SOCK_DONE = 1, - SOCK_URGINLINE = 2, - SOCK_KEEPOPEN = 3, - SOCK_LINGER = 4, - SOCK_DESTROY = 5, - SOCK_BROADCAST = 6, - SOCK_TIMESTAMP = 7, - SOCK_ZAPPED = 8, - SOCK_USE_WRITE_QUEUE = 9, - SOCK_DBG = 10, - SOCK_RCVTSTAMP = 11, - SOCK_RCVTSTAMPNS = 12, - SOCK_LOCALROUTE = 13, - SOCK_MEMALLOC = 14, - SOCK_TIMESTAMPING_RX_SOFTWARE = 15, - SOCK_FASYNC = 16, - SOCK_RXQ_OVFL = 17, - SOCK_ZEROCOPY = 18, - SOCK_WIFI_STATUS = 19, - SOCK_NOFCS = 20, - SOCK_FILTER_LOCKED = 21, - SOCK_SELECT_ERR_QUEUE = 22, - SOCK_RCU_FREE = 23, - SOCK_TXTIME = 24, - SOCK_XDP = 25, - SOCK_TSTAMP_NEW = 26, -}; - -struct reuseport_array { - struct bpf_map map; - struct sock *ptrs[0]; -}; - -enum bpf_struct_ops_state { - BPF_STRUCT_OPS_STATE_INIT = 0, - BPF_STRUCT_OPS_STATE_INUSE = 1, - BPF_STRUCT_OPS_STATE_TOBEFREE = 2, -}; - -struct bpf_struct_ops_value { - refcount_t refcnt; - enum bpf_struct_ops_state state; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - char data[0]; -}; - -struct bpf_struct_ops_map { - struct bpf_map map; - const struct bpf_struct_ops *st_ops; - struct mutex lock; - struct bpf_prog **progs; - void *image; - struct bpf_struct_ops_value *uvalue; - struct bpf_struct_ops_value kvalue; -}; - -struct bpf_struct_ops_tcp_congestion_ops { - refcount_t refcnt; - enum bpf_struct_ops_state state; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct tcp_congestion_ops data; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum perf_branch_sample_type { - PERF_SAMPLE_BRANCH_USER = 1, - PERF_SAMPLE_BRANCH_KERNEL = 2, - PERF_SAMPLE_BRANCH_HV = 4, - PERF_SAMPLE_BRANCH_ANY = 8, - PERF_SAMPLE_BRANCH_ANY_CALL = 16, - PERF_SAMPLE_BRANCH_ANY_RETURN = 32, - PERF_SAMPLE_BRANCH_IND_CALL = 64, - PERF_SAMPLE_BRANCH_ABORT_TX = 128, - PERF_SAMPLE_BRANCH_IN_TX = 256, - PERF_SAMPLE_BRANCH_NO_TX = 512, - PERF_SAMPLE_BRANCH_COND = 1024, - PERF_SAMPLE_BRANCH_CALL_STACK = 2048, - PERF_SAMPLE_BRANCH_IND_JUMP = 4096, - PERF_SAMPLE_BRANCH_CALL = 8192, - PERF_SAMPLE_BRANCH_NO_FLAGS = 16384, - PERF_SAMPLE_BRANCH_NO_CYCLES = 32768, - PERF_SAMPLE_BRANCH_TYPE_SAVE = 65536, - PERF_SAMPLE_BRANCH_HW_INDEX = 131072, - PERF_SAMPLE_BRANCH_MAX = 262144, -}; - -enum perf_event_read_format { - PERF_FORMAT_TOTAL_TIME_ENABLED = 1, - PERF_FORMAT_TOTAL_TIME_RUNNING = 2, - PERF_FORMAT_ID = 4, - PERF_FORMAT_GROUP = 8, - PERF_FORMAT_MAX = 16, -}; - -enum perf_event_ioc_flags { - PERF_IOC_FLAG_GROUP = 1, -}; - -struct perf_event_header { - __u32 type; - __u16 misc; - __u16 size; -}; - -struct perf_ns_link_info { - __u64 dev; - __u64 ino; -}; - -enum { - NET_NS_INDEX = 0, - UTS_NS_INDEX = 1, - IPC_NS_INDEX = 2, - PID_NS_INDEX = 3, - USER_NS_INDEX = 4, - MNT_NS_INDEX = 5, - CGROUP_NS_INDEX = 6, - NR_NAMESPACES = 7, -}; - -enum perf_event_type { - PERF_RECORD_MMAP = 1, - PERF_RECORD_LOST = 2, - PERF_RECORD_COMM = 3, - PERF_RECORD_EXIT = 4, - PERF_RECORD_THROTTLE = 5, - PERF_RECORD_UNTHROTTLE = 6, - PERF_RECORD_FORK = 7, - PERF_RECORD_READ = 8, - PERF_RECORD_SAMPLE = 9, - PERF_RECORD_MMAP2 = 10, - PERF_RECORD_AUX = 11, - PERF_RECORD_ITRACE_START = 12, - PERF_RECORD_LOST_SAMPLES = 13, - PERF_RECORD_SWITCH = 14, - PERF_RECORD_SWITCH_CPU_WIDE = 15, - PERF_RECORD_NAMESPACES = 16, - PERF_RECORD_KSYMBOL = 17, - PERF_RECORD_BPF_EVENT = 18, - PERF_RECORD_CGROUP = 19, - PERF_RECORD_TEXT_POKE = 20, - PERF_RECORD_MAX = 21, -}; - -enum perf_addr_filter_action_t { - PERF_ADDR_FILTER_ACTION_STOP = 0, - PERF_ADDR_FILTER_ACTION_START = 1, - PERF_ADDR_FILTER_ACTION_FILTER = 2, -}; - -struct perf_addr_filter { - struct list_head entry; - struct path path; - long unsigned int offset; - long unsigned int size; - enum perf_addr_filter_action_t action; -}; - -struct swevent_hlist { - struct hlist_head heads[256]; - struct callback_head callback_head; -}; - -struct pmu_event_list { - raw_spinlock_t lock; - struct list_head list; -}; - -struct perf_buffer { - refcount_t refcount; - struct callback_head callback_head; - int nr_pages; - int overwrite; - int paused; - atomic_t poll; - local_t head; - unsigned int nest; - local_t events; - local_t wakeup; - local_t lost; - long int watermark; - long int aux_watermark; - spinlock_t event_lock; - struct list_head event_list; - atomic_t mmap_count; - long unsigned int mmap_locked; - struct user_struct *mmap_user; - long int aux_head; - unsigned int aux_nest; - long int aux_wakeup; - long unsigned int aux_pgoff; - int aux_nr_pages; - int aux_overwrite; - atomic_t aux_mmap_count; - long unsigned int aux_mmap_locked; - void (*free_aux)(void *); - refcount_t aux_refcount; - int aux_in_sampling; - void **aux_pages; - void *aux_priv; - struct perf_event_mmap_page *user_page; - void *data_pages[0]; -}; - -struct match_token { - int token; - const char *pattern; -}; - -enum { - MAX_OPT_ARGS = 3, -}; - -typedef struct { - char *from; - char *to; -} substring_t; - -struct min_heap { - void *data; - int nr; - int size; -}; - -struct min_heap_callbacks { - int elem_size; - bool (*less)(const void *, const void *); - void (*swp)(void *, void *); -}; - -typedef int (*remote_function_f)(void *); - -struct remote_function_call { - struct task_struct *p; - remote_function_f func; - void *info; - int ret; -}; - -typedef void (*event_f)(struct perf_event *, struct perf_cpu_context *, struct perf_event_context *, void *); - -struct event_function_struct { - struct perf_event *event; - event_f func; - void *data; -}; - -enum event_type_t { - EVENT_FLEXIBLE = 1, - EVENT_PINNED = 2, - EVENT_TIME = 4, - EVENT_CPU = 8, - EVENT_ALL = 3, -}; - -struct stop_event_data { - struct perf_event *event; - unsigned int restart; -}; - -struct perf_read_data { - struct perf_event *event; - bool group; - int ret; -}; - -struct perf_read_event { - struct perf_event_header header; - u32 pid; - u32 tid; -}; - -typedef void perf_iterate_f(struct perf_event *, void *); - -struct remote_output { - struct perf_buffer *rb; - int err; -}; - -struct perf_task_event { - struct task_struct *task; - struct perf_event_context *task_ctx; - struct { - struct perf_event_header header; - u32 pid; - u32 ppid; - u32 tid; - u32 ptid; - u64 time; - } event_id; -}; - -struct perf_comm_event { - struct task_struct *task; - char *comm; - int comm_size; - struct { - struct perf_event_header header; - u32 pid; - u32 tid; - } event_id; -}; - -struct perf_namespaces_event { - struct task_struct *task; - struct { - struct perf_event_header header; - u32 pid; - u32 tid; - u64 nr_namespaces; - struct perf_ns_link_info link_info[7]; - } event_id; -}; - -struct perf_cgroup_event { - char *path; - int path_size; - struct { - struct perf_event_header header; - u64 id; - char path[0]; - } event_id; -}; - -struct perf_mmap_event { - struct vm_area_struct *vma; - const char *file_name; - int file_size; - int maj; - int min; - u64 ino; - u64 ino_generation; - u32 prot; - u32 flags; - struct { - struct perf_event_header header; - u32 pid; - u32 tid; - u64 start; - u64 len; - u64 pgoff; - } event_id; -}; - -struct perf_switch_event { - struct task_struct *task; - struct task_struct *next_prev; - struct { - struct perf_event_header header; - u32 next_prev_pid; - u32 next_prev_tid; - } event_id; -}; - -struct perf_ksymbol_event { - const char *name; - int name_len; - struct { - struct perf_event_header header; - u64 addr; - u32 len; - u16 ksym_type; - u16 flags; - } event_id; -}; - -struct perf_bpf_event { - struct bpf_prog *prog; - struct { - struct perf_event_header header; - u16 type; - u16 flags; - u32 id; - u8 tag[8]; - } event_id; -}; - -struct perf_text_poke_event { - const void *old_bytes; - const void *new_bytes; - size_t pad; - u16 old_len; - u16 new_len; - struct { - struct perf_event_header header; - u64 addr; - } event_id; -}; - -struct swevent_htable { - struct swevent_hlist *swevent_hlist; - struct mutex hlist_mutex; - int hlist_refcount; - int recursion[4]; -}; - -enum perf_probe_config { - PERF_PROBE_CONFIG_IS_RETPROBE = 1, - PERF_UPROBE_REF_CTR_OFFSET_BITS = 32, - PERF_UPROBE_REF_CTR_OFFSET_SHIFT = 32, -}; - -enum { - IF_ACT_NONE = 4294967295, - IF_ACT_FILTER = 0, - IF_ACT_START = 1, - IF_ACT_STOP = 2, - IF_SRC_FILE = 3, - IF_SRC_KERNEL = 4, - IF_SRC_FILEADDR = 5, - IF_SRC_KERNELADDR = 6, -}; - -enum { - IF_STATE_ACTION = 0, - IF_STATE_SOURCE = 1, - IF_STATE_END = 2, -}; - -struct perf_aux_event { - struct perf_event_header header; - u32 pid; - u32 tid; -}; - -struct perf_aux_event___2 { - struct perf_event_header header; - u64 offset; - u64 size; - u64 flags; -}; - -struct callchain_cpus_entries { - struct callback_head callback_head; - struct perf_callchain_entry *cpu_entries[0]; -}; - -struct bp_cpuinfo { - unsigned int cpu_pinned; - unsigned int *tsk_pinned; - unsigned int flexible; -}; - -struct bp_busy_slots { - unsigned int pinned; - unsigned int flexible; -}; - -struct static_key_mod { - struct static_key_mod *next; - struct jump_entry *entries; - struct module *mod; -}; - -struct static_key_deferred { - struct static_key key; - long unsigned int timeout; - struct delayed_work work; -}; - -enum rseq_cpu_id_state { - RSEQ_CPU_ID_UNINITIALIZED = 4294967295, - RSEQ_CPU_ID_REGISTRATION_FAILED = 4294967294, -}; - -enum rseq_flags { - RSEQ_FLAG_UNREGISTER = 1, -}; - -enum rseq_cs_flags { - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = 1, - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = 2, - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = 4, -}; - -struct rseq_cs { - __u32 version; - __u32 flags; - __u64 start_ip; - __u64 post_commit_offset; - __u64 abort_ip; -}; - -struct trace_event_raw_rseq_update { - struct trace_entry ent; - s32 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_rseq_ip_fixup { - struct trace_entry ent; - long unsigned int regs_ip; - long unsigned int start_ip; - long unsigned int post_commit_offset; - long unsigned int abort_ip; - char __data[0]; -}; - -struct trace_event_data_offsets_rseq_update {}; - -struct trace_event_data_offsets_rseq_ip_fixup {}; - -typedef void (*btf_trace_rseq_update)(void *, struct task_struct *); - -typedef void (*btf_trace_rseq_ip_fixup)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - -enum key_being_used_for { - VERIFYING_MODULE_SIGNATURE = 0, - VERIFYING_FIRMWARE_SIGNATURE = 1, - VERIFYING_KEXEC_PE_SIGNATURE = 2, - VERIFYING_KEY_SIGNATURE = 3, - VERIFYING_KEY_SELF_SIGNATURE = 4, - VERIFYING_UNSPECIFIED_SIGNATURE = 5, - NR__KEY_BEING_USED_FOR = 6, -}; - -struct pkcs7_message; - -struct __key_reference_with_attributes; - -typedef struct __key_reference_with_attributes *key_ref_t; - -struct compact_control; - -struct capture_control { - struct compact_control *cc; - struct page *page; -}; - -typedef int __kernel_rwf_t; - -enum positive_aop_returns { - AOP_WRITEPAGE_ACTIVATE = 524288, - AOP_TRUNCATED_PAGE = 524289, -}; - -struct vm_event_state { - long unsigned int event[67]; -}; - -enum iter_type { - ITER_IOVEC = 4, - ITER_KVEC = 8, - ITER_BVEC = 16, - ITER_PIPE = 32, - ITER_DISCARD = 64, -}; - -enum mapping_flags { - AS_EIO = 0, - AS_ENOSPC = 1, - AS_MM_ALL_LOCKS = 2, - AS_UNEVICTABLE = 3, - AS_EXITING = 4, - AS_NO_WRITEBACK_TAGS = 5, - AS_THP_SUPPORT = 6, -}; - -struct wait_page_key { - struct page *page; - int bit_nr; - int page_match; -}; - -struct pagevec { - unsigned char nr; - bool percpu_pvec_drained; - struct page *pages[15]; -}; - -struct fid { - union { - struct { - u32 ino; - u32 gen; - u32 parent_ino; - u32 parent_gen; - } i32; - struct { - u32 block; - u16 partref; - u16 parent_partref; - u32 generation; - u32 parent_block; - u32 parent_generation; - } udf; - __u32 raw[0]; - }; -}; - -struct compact_control { - struct list_head freepages; - struct list_head migratepages; - unsigned int nr_freepages; - unsigned int nr_migratepages; - long unsigned int free_pfn; - long unsigned int migrate_pfn; - long unsigned int fast_start_pfn; - struct zone *zone; - long unsigned int total_migrate_scanned; - long unsigned int total_free_scanned; - short unsigned int fast_search_fail; - short int search_order; - const gfp_t gfp_mask; - int order; - int migratetype; - const unsigned int alloc_flags; - const int highest_zoneidx; - enum migrate_mode mode; - bool ignore_skip_hint; - bool no_set_skip_hint; - bool ignore_block_suitable; - bool direct_compaction; - bool proactive_compaction; - bool whole_zone; - bool contended; - bool rescan; - bool alloc_contig; -}; - -struct trace_event_raw_mm_filemap_op_page_cache { - struct trace_entry ent; - long unsigned int pfn; - long unsigned int i_ino; - long unsigned int index; - dev_t s_dev; - char __data[0]; -}; - -struct trace_event_raw_filemap_set_wb_err { - struct trace_entry ent; - long unsigned int i_ino; - dev_t s_dev; - errseq_t errseq; - char __data[0]; -}; - -struct trace_event_raw_file_check_and_advance_wb_err { - struct trace_entry ent; - struct file *file; - long unsigned int i_ino; - dev_t s_dev; - errseq_t old; - errseq_t new; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_filemap_op_page_cache {}; - -struct trace_event_data_offsets_filemap_set_wb_err {}; - -struct trace_event_data_offsets_file_check_and_advance_wb_err {}; - -typedef void (*btf_trace_mm_filemap_delete_from_page_cache)(void *, struct page *); - -typedef void (*btf_trace_mm_filemap_add_to_page_cache)(void *, struct page *); - -typedef void (*btf_trace_filemap_set_wb_err)(void *, struct address_space *, errseq_t); - -typedef void (*btf_trace_file_check_and_advance_wb_err)(void *, struct file *, errseq_t); - -enum behavior { - EXCLUSIVE = 0, - SHARED = 1, - DROP = 2, -}; - -struct reciprocal_value { - u32 m; - u8 sh1; - u8 sh2; -}; - -struct kmem_cache_order_objects { - unsigned int x; -}; - -struct kmem_cache_cpu; - -struct kmem_cache_node; - -struct kmem_cache { - struct kmem_cache_cpu *cpu_slab; - slab_flags_t flags; - long unsigned int min_partial; - unsigned int size; - unsigned int object_size; - struct reciprocal_value reciprocal_size; - unsigned int offset; - unsigned int cpu_partial; - struct kmem_cache_order_objects oo; - struct kmem_cache_order_objects max; - struct kmem_cache_order_objects min; - gfp_t allocflags; - int refcount; - void (*ctor)(void *); - unsigned int inuse; - unsigned int align; - unsigned int red_left_pad; - const char *name; - struct list_head list; - struct kobject kobj; - unsigned int useroffset; - unsigned int usersize; - struct kmem_cache_node *node[1]; -}; - -struct kmem_cache_cpu { - void **freelist; - long unsigned int tid; - struct page *page; - struct page *partial; -}; - -struct kmem_cache_node { - spinlock_t list_lock; - long unsigned int nr_partial; - struct list_head partial; - atomic_long_t nr_slabs; - atomic_long_t total_objects; - struct list_head full; -}; - -enum oom_constraint { - CONSTRAINT_NONE = 0, - CONSTRAINT_CPUSET = 1, - CONSTRAINT_MEMORY_POLICY = 2, - CONSTRAINT_MEMCG = 3, -}; - -struct oom_control { - struct zonelist *zonelist; - nodemask_t *nodemask; - struct mem_cgroup *memcg; - const gfp_t gfp_mask; - const int order; - long unsigned int totalpages; - struct task_struct *chosen; - long int chosen_points; - enum oom_constraint constraint; -}; - -struct mmu_table_batch { - struct callback_head rcu; - unsigned int nr; - void *tables[0]; -}; - -struct mmu_gather_batch { - struct mmu_gather_batch *next; - unsigned int nr; - unsigned int max; - struct page *pages[0]; -}; - -struct mmu_gather { - struct mm_struct *mm; - struct mmu_table_batch *batch; - long unsigned int start; - long unsigned int end; - unsigned int fullmm: 1; - unsigned int need_flush_all: 1; - unsigned int freed_tables: 1; - unsigned int cleared_ptes: 1; - unsigned int cleared_pmds: 1; - unsigned int cleared_puds: 1; - unsigned int cleared_p4ds: 1; - unsigned int vma_exec: 1; - unsigned int vma_huge: 1; - unsigned int batch_count; - struct mmu_gather_batch *active; - struct mmu_gather_batch local; - struct page *__pages[8]; -}; - -enum compact_priority { - COMPACT_PRIO_SYNC_FULL = 0, - MIN_COMPACT_PRIORITY = 0, - COMPACT_PRIO_SYNC_LIGHT = 1, - MIN_COMPACT_COSTLY_PRIORITY = 1, - DEF_COMPACT_PRIORITY = 1, - COMPACT_PRIO_ASYNC = 2, - INIT_COMPACT_PRIORITY = 2, -}; - -enum compact_result { - COMPACT_NOT_SUITABLE_ZONE = 0, - COMPACT_SKIPPED = 1, - COMPACT_DEFERRED = 2, - COMPACT_NO_SUITABLE_PAGE = 3, - COMPACT_CONTINUE = 4, - COMPACT_COMPLETE = 5, - COMPACT_PARTIAL_SKIPPED = 6, - COMPACT_CONTENDED = 7, - COMPACT_SUCCESS = 8, -}; - -struct trace_event_raw_oom_score_adj_update { - struct trace_entry ent; - pid_t pid; - char comm[16]; - short int oom_score_adj; - char __data[0]; -}; - -struct trace_event_raw_reclaim_retry_zone { - struct trace_entry ent; - int node; - int zone_idx; - int order; - long unsigned int reclaimable; - long unsigned int available; - long unsigned int min_wmark; - int no_progress_loops; - bool wmark_check; - char __data[0]; -}; - -struct trace_event_raw_mark_victim { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_wake_reaper { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_start_task_reaping { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_finish_task_reaping { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_skip_task_reaping { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_compact_retry { - struct trace_entry ent; - int order; - int priority; - int result; - int retries; - int max_retries; - bool ret; - char __data[0]; -}; - -struct trace_event_data_offsets_oom_score_adj_update {}; - -struct trace_event_data_offsets_reclaim_retry_zone {}; - -struct trace_event_data_offsets_mark_victim {}; - -struct trace_event_data_offsets_wake_reaper {}; - -struct trace_event_data_offsets_start_task_reaping {}; - -struct trace_event_data_offsets_finish_task_reaping {}; - -struct trace_event_data_offsets_skip_task_reaping {}; - -struct trace_event_data_offsets_compact_retry {}; - -typedef void (*btf_trace_oom_score_adj_update)(void *, struct task_struct *); - -typedef void (*btf_trace_reclaim_retry_zone)(void *, struct zoneref *, int, long unsigned int, long unsigned int, long unsigned int, int, bool); - -typedef void (*btf_trace_mark_victim)(void *, int); - -typedef void (*btf_trace_wake_reaper)(void *, int); - -typedef void (*btf_trace_start_task_reaping)(void *, int); - -typedef void (*btf_trace_finish_task_reaping)(void *, int); - -typedef void (*btf_trace_skip_task_reaping)(void *, int); - -typedef void (*btf_trace_compact_retry)(void *, int, enum compact_priority, enum compact_result, int, int, bool); - -enum wb_congested_state { - WB_async_congested = 0, - WB_sync_congested = 1, -}; - -enum { - XA_CHECK_SCHED = 4096, -}; - -enum wb_state { - WB_registered = 0, - WB_writeback_running = 1, - WB_has_dirty_io = 2, - WB_start_all = 3, -}; - -enum { - BLK_RW_ASYNC = 0, - BLK_RW_SYNC = 1, -}; - -struct wb_lock_cookie { - bool locked; - long unsigned int flags; -}; - -typedef int (*writepage_t)(struct page *, struct writeback_control *, void *); - -struct dirty_throttle_control { - struct wb_domain *dom; - struct dirty_throttle_control *gdtc; - struct bdi_writeback *wb; - struct fprop_local_percpu *wb_completions; - long unsigned int avail; - long unsigned int dirty; - long unsigned int thresh; - long unsigned int bg_thresh; - long unsigned int wb_dirty; - long unsigned int wb_thresh; - long unsigned int wb_bg_thresh; - long unsigned int pos_ratio; -}; - -typedef void compound_page_dtor(struct page *); - -struct trace_event_raw_mm_lru_insertion { - struct trace_entry ent; - struct page *page; - long unsigned int pfn; - int lru; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_mm_lru_activate { - struct trace_entry ent; - struct page *page; - long unsigned int pfn; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_lru_insertion {}; - -struct trace_event_data_offsets_mm_lru_activate {}; - -typedef void (*btf_trace_mm_lru_insertion)(void *, struct page *, int); - -typedef void (*btf_trace_mm_lru_activate)(void *, struct page *); - -struct lru_rotate { - local_lock_t lock; - struct pagevec pvec; -}; - -struct lru_pvecs { - local_lock_t lock; - struct pagevec lru_add; - struct pagevec lru_deactivate_file; - struct pagevec lru_deactivate; - struct pagevec lru_lazyfree; - struct pagevec activate_page; -}; - -enum lruvec_flags { - LRUVEC_CONGESTED = 0, -}; - -enum pgdat_flags { - PGDAT_DIRTY = 0, - PGDAT_WRITEBACK = 1, - PGDAT_RECLAIM_LOCKED = 2, -}; - -struct reclaim_stat { - unsigned int nr_dirty; - unsigned int nr_unqueued_dirty; - unsigned int nr_congested; - unsigned int nr_writeback; - unsigned int nr_immediate; - unsigned int nr_pageout; - unsigned int nr_activate[2]; - unsigned int nr_ref_keep; - unsigned int nr_unmap_fail; - unsigned int nr_lazyfree_fail; -}; - -enum ttu_flags { - TTU_MIGRATION = 1, - TTU_MUNLOCK = 2, - TTU_SPLIT_HUGE_PMD = 4, - TTU_IGNORE_MLOCK = 8, - TTU_SYNC = 16, - TTU_IGNORE_HWPOISON = 32, - TTU_BATCH_FLUSH = 64, - TTU_RMAP_LOCKED = 128, - TTU_SPLIT_FREEZE = 256, -}; - -struct trace_event_raw_mm_vmscan_kswapd_sleep { - struct trace_entry ent; - int nid; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_kswapd_wake { - struct trace_entry ent; - int nid; - int zid; - int order; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_wakeup_kswapd { - struct trace_entry ent; - int nid; - int zid; - int order; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_direct_reclaim_begin_template { - struct trace_entry ent; - int order; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_direct_reclaim_end_template { - struct trace_entry ent; - long unsigned int nr_reclaimed; - char __data[0]; -}; - -struct trace_event_raw_mm_shrink_slab_start { - struct trace_entry ent; - struct shrinker *shr; - void *shrink; - int nid; - long int nr_objects_to_shrink; - gfp_t gfp_flags; - long unsigned int cache_items; - long long unsigned int delta; - long unsigned int total_scan; - int priority; - char __data[0]; -}; - -struct trace_event_raw_mm_shrink_slab_end { - struct trace_entry ent; - struct shrinker *shr; - int nid; - void *shrink; - long int unused_scan; - long int new_scan; - int retval; - long int total_scan; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_lru_isolate { - struct trace_entry ent; - int highest_zoneidx; - int order; - long unsigned int nr_requested; - long unsigned int nr_scanned; - long unsigned int nr_skipped; - long unsigned int nr_taken; - isolate_mode_t isolate_mode; - int lru; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_writepage { - struct trace_entry ent; - long unsigned int pfn; - int reclaim_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_lru_shrink_inactive { - struct trace_entry ent; - int nid; - long unsigned int nr_scanned; - long unsigned int nr_reclaimed; - long unsigned int nr_dirty; - long unsigned int nr_writeback; - long unsigned int nr_congested; - long unsigned int nr_immediate; - unsigned int nr_activate0; - unsigned int nr_activate1; - long unsigned int nr_ref_keep; - long unsigned int nr_unmap_fail; - int priority; - int reclaim_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_lru_shrink_active { - struct trace_entry ent; - int nid; - long unsigned int nr_taken; - long unsigned int nr_active; - long unsigned int nr_deactivated; - long unsigned int nr_referenced; - int priority; - int reclaim_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_inactive_list_is_low { - struct trace_entry ent; - int nid; - int reclaim_idx; - long unsigned int total_inactive; - long unsigned int inactive; - long unsigned int total_active; - long unsigned int active; - long unsigned int ratio; - int reclaim_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_node_reclaim_begin { - struct trace_entry ent; - int nid; - int order; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_vmscan_kswapd_sleep {}; - -struct trace_event_data_offsets_mm_vmscan_kswapd_wake {}; - -struct trace_event_data_offsets_mm_vmscan_wakeup_kswapd {}; - -struct trace_event_data_offsets_mm_vmscan_direct_reclaim_begin_template {}; - -struct trace_event_data_offsets_mm_vmscan_direct_reclaim_end_template {}; - -struct trace_event_data_offsets_mm_shrink_slab_start {}; - -struct trace_event_data_offsets_mm_shrink_slab_end {}; - -struct trace_event_data_offsets_mm_vmscan_lru_isolate {}; - -struct trace_event_data_offsets_mm_vmscan_writepage {}; - -struct trace_event_data_offsets_mm_vmscan_lru_shrink_inactive {}; - -struct trace_event_data_offsets_mm_vmscan_lru_shrink_active {}; - -struct trace_event_data_offsets_mm_vmscan_inactive_list_is_low {}; - -struct trace_event_data_offsets_mm_vmscan_node_reclaim_begin {}; - -typedef void (*btf_trace_mm_vmscan_kswapd_sleep)(void *, int); - -typedef void (*btf_trace_mm_vmscan_kswapd_wake)(void *, int, int, int); - -typedef void (*btf_trace_mm_vmscan_wakeup_kswapd)(void *, int, int, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_direct_reclaim_begin)(void *, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_memcg_reclaim_begin)(void *, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_memcg_softlimit_reclaim_begin)(void *, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_direct_reclaim_end)(void *, long unsigned int); - -typedef void (*btf_trace_mm_vmscan_memcg_reclaim_end)(void *, long unsigned int); - -typedef void (*btf_trace_mm_vmscan_memcg_softlimit_reclaim_end)(void *, long unsigned int); - -typedef void (*btf_trace_mm_shrink_slab_start)(void *, struct shrinker *, struct shrink_control *, long int, long unsigned int, long long unsigned int, long unsigned int, int); - -typedef void (*btf_trace_mm_shrink_slab_end)(void *, struct shrinker *, int, int, long int, long int, long int); - -typedef void (*btf_trace_mm_vmscan_lru_isolate)(void *, int, int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, isolate_mode_t, int); - -typedef void (*btf_trace_mm_vmscan_writepage)(void *, struct page *); - -typedef void (*btf_trace_mm_vmscan_lru_shrink_inactive)(void *, int, long unsigned int, long unsigned int, struct reclaim_stat *, int, int); - -typedef void (*btf_trace_mm_vmscan_lru_shrink_active)(void *, int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, int, int); - -typedef void (*btf_trace_mm_vmscan_inactive_list_is_low)(void *, int, int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, int); - -typedef void (*btf_trace_mm_vmscan_node_reclaim_begin)(void *, int, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_node_reclaim_end)(void *, long unsigned int); - -struct scan_control { - long unsigned int nr_to_reclaim; - nodemask_t *nodemask; - struct mem_cgroup *target_mem_cgroup; - long unsigned int anon_cost; - long unsigned int file_cost; - unsigned int may_deactivate: 2; - unsigned int force_deactivate: 1; - unsigned int skipped_deactivate: 1; - unsigned int may_writepage: 1; - unsigned int may_unmap: 1; - unsigned int may_swap: 1; - unsigned int memcg_low_reclaim: 1; - unsigned int memcg_low_skipped: 1; - unsigned int hibernation_mode: 1; - unsigned int compaction_ready: 1; - unsigned int cache_trim_mode: 1; - unsigned int file_is_tiny: 1; - s8 order; - s8 priority; - s8 reclaim_idx; - gfp_t gfp_mask; - long unsigned int nr_scanned; - long unsigned int nr_reclaimed; - struct { - unsigned int dirty; - unsigned int unqueued_dirty; - unsigned int congested; - unsigned int writeback; - unsigned int immediate; - unsigned int file_taken; - unsigned int taken; - } nr; - struct reclaim_state reclaim_state; -}; - -typedef enum { - PAGE_KEEP = 0, - PAGE_ACTIVATE = 1, - PAGE_SUCCESS = 2, - PAGE_CLEAN = 3, -} pageout_t; - -enum page_references { - PAGEREF_RECLAIM = 0, - PAGEREF_RECLAIM_CLEAN = 1, - PAGEREF_KEEP = 2, - PAGEREF_ACTIVATE = 3, -}; - -enum scan_balance { - SCAN_EQUAL = 0, - SCAN_FRACT = 1, - SCAN_ANON = 2, - SCAN_FILE = 3, -}; - -struct xattr { - const char *name; - void *value; - size_t value_len; -}; - -struct constant_table { - const char *name; - int value; -}; - -struct shared_policy {}; - -struct simple_xattrs { - struct list_head head; - spinlock_t lock; -}; - -struct simple_xattr { - struct list_head list; - char *name; - size_t size; - char value[0]; -}; - -struct shmem_inode_info { - spinlock_t lock; - unsigned int seals; - long unsigned int flags; - long unsigned int alloced; - long unsigned int swapped; - struct list_head shrinklist; - struct list_head swaplist; - struct shared_policy policy; - struct simple_xattrs xattrs; - atomic_t stop_eviction; - struct inode vfs_inode; -}; - -struct shmem_sb_info { - long unsigned int max_blocks; - struct percpu_counter used_blocks; - long unsigned int max_inodes; - long unsigned int free_inodes; - spinlock_t stat_lock; - umode_t mode; - unsigned char huge; - kuid_t uid; - kgid_t gid; - bool full_inums; - ino_t next_ino; - ino_t *ino_batch; - struct mempolicy *mpol; - spinlock_t shrinklist_lock; - struct list_head shrinklist; - long unsigned int shrinklist_len; -}; - -enum sgp_type { - SGP_READ = 0, - SGP_CACHE = 1, - SGP_NOHUGE = 2, - SGP_HUGE = 3, - SGP_WRITE = 4, - SGP_FALLOC = 5, -}; - -enum fid_type { - FILEID_ROOT = 0, - FILEID_INO32_GEN = 1, - FILEID_INO32_GEN_PARENT = 2, - FILEID_BTRFS_WITHOUT_PARENT = 77, - FILEID_BTRFS_WITH_PARENT = 78, - FILEID_BTRFS_WITH_PARENT_ROOT = 79, - FILEID_UDF_WITHOUT_PARENT = 81, - FILEID_UDF_WITH_PARENT = 82, - FILEID_NILFS_WITHOUT_PARENT = 97, - FILEID_NILFS_WITH_PARENT = 98, - FILEID_FAT_WITHOUT_PARENT = 113, - FILEID_FAT_WITH_PARENT = 114, - FILEID_LUSTRE = 151, - FILEID_KERNFS = 254, - FILEID_INVALID = 255, -}; - -struct shmem_falloc { - wait_queue_head_t *waitq; - long unsigned int start; - long unsigned int next; - long unsigned int nr_falloced; - long unsigned int nr_unswapped; -}; - -struct shmem_options { - long long unsigned int blocks; - long long unsigned int inodes; - struct mempolicy *mpol; - kuid_t uid; - kgid_t gid; - umode_t mode; - bool full_inums; - int huge; - int seen; -}; - -enum shmem_param { - Opt_gid = 0, - Opt_huge = 1, - Opt_mode = 2, - Opt_mpol = 3, - Opt_nr_blocks = 4, - Opt_nr_inodes = 5, - Opt_size = 6, - Opt_uid = 7, - Opt_inode32 = 8, - Opt_inode64 = 9, -}; - -enum writeback_stat_item { - NR_DIRTY_THRESHOLD = 0, - NR_DIRTY_BG_THRESHOLD = 1, - NR_VM_WRITEBACK_STAT_ITEMS = 2, -}; - -struct contig_page_info { - long unsigned int free_pages; - long unsigned int free_blocks_total; - long unsigned int free_blocks_suitable; -}; - -struct radix_tree_iter { - long unsigned int index; - long unsigned int next_index; - long unsigned int tags; - struct xa_node *node; -}; - -enum { - RADIX_TREE_ITER_TAG_MASK = 15, - RADIX_TREE_ITER_TAGGED = 16, - RADIX_TREE_ITER_CONTIG = 32, -}; - -enum mminit_level { - MMINIT_WARNING = 0, - MMINIT_VERIFY = 1, - MMINIT_TRACE = 2, -}; - -struct pcpu_group_info { - int nr_units; - long unsigned int base_offset; - unsigned int *cpu_map; -}; - -struct pcpu_alloc_info { - size_t static_size; - size_t reserved_size; - size_t dyn_size; - size_t unit_size; - size_t atom_size; - size_t alloc_size; - size_t __ai_size; - int nr_groups; - struct pcpu_group_info groups[0]; -}; - -typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int, size_t, size_t); - -typedef void (*pcpu_fc_free_fn_t)(void *, size_t); - -typedef int pcpu_fc_cpu_distance_fn_t(unsigned int, unsigned int); - -struct trace_event_raw_percpu_alloc_percpu { - struct trace_entry ent; - bool reserved; - bool is_atomic; - size_t size; - size_t align; - void *base_addr; - int off; - void *ptr; - char __data[0]; -}; - -struct trace_event_raw_percpu_free_percpu { - struct trace_entry ent; - void *base_addr; - int off; - void *ptr; - char __data[0]; -}; - -struct trace_event_raw_percpu_alloc_percpu_fail { - struct trace_entry ent; - bool reserved; - bool is_atomic; - size_t size; - size_t align; - char __data[0]; -}; - -struct trace_event_raw_percpu_create_chunk { - struct trace_entry ent; - void *base_addr; - char __data[0]; -}; - -struct trace_event_raw_percpu_destroy_chunk { - struct trace_entry ent; - void *base_addr; - char __data[0]; -}; - -struct trace_event_data_offsets_percpu_alloc_percpu {}; - -struct trace_event_data_offsets_percpu_free_percpu {}; - -struct trace_event_data_offsets_percpu_alloc_percpu_fail {}; - -struct trace_event_data_offsets_percpu_create_chunk {}; - -struct trace_event_data_offsets_percpu_destroy_chunk {}; - -typedef void (*btf_trace_percpu_alloc_percpu)(void *, bool, bool, size_t, size_t, void *, int, void *); - -typedef void (*btf_trace_percpu_free_percpu)(void *, void *, int, void *); - -typedef void (*btf_trace_percpu_alloc_percpu_fail)(void *, bool, bool, size_t, size_t); - -typedef void (*btf_trace_percpu_create_chunk)(void *, void *); - -typedef void (*btf_trace_percpu_destroy_chunk)(void *, void *); - -enum pcpu_chunk_type { - PCPU_CHUNK_ROOT = 0, - PCPU_CHUNK_MEMCG = 1, - PCPU_NR_CHUNK_TYPES = 2, - PCPU_FAIL_ALLOC = 2, -}; - -struct pcpu_block_md { - int scan_hint; - int scan_hint_start; - int contig_hint; - int contig_hint_start; - int left_free; - int right_free; - int first_free; - int nr_bits; -}; - -struct pcpu_chunk { - struct list_head list; - int free_bytes; - struct pcpu_block_md chunk_md; - void *base_addr; - long unsigned int *alloc_map; - long unsigned int *bound_map; - struct pcpu_block_md *md_blocks; - void *data; - bool immutable; - int start_offset; - int end_offset; - struct obj_cgroup **obj_cgroups; - int nr_pages; - int nr_populated; - int nr_empty_pop_pages; - long unsigned int populated[0]; -}; - -struct trace_event_raw_kmem_alloc { - struct trace_entry ent; - long unsigned int call_site; - const void *ptr; - size_t bytes_req; - size_t bytes_alloc; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_raw_kmem_alloc_node { - struct trace_entry ent; - long unsigned int call_site; - const void *ptr; - size_t bytes_req; - size_t bytes_alloc; - gfp_t gfp_flags; - int node; - char __data[0]; -}; - -struct trace_event_raw_kmem_free { - struct trace_entry ent; - long unsigned int call_site; - const void *ptr; - char __data[0]; -}; - -struct trace_event_raw_mm_page_free { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - char __data[0]; -}; - -struct trace_event_raw_mm_page_free_batched { - struct trace_entry ent; - long unsigned int pfn; - char __data[0]; -}; - -struct trace_event_raw_mm_page_alloc { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - gfp_t gfp_flags; - int migratetype; - char __data[0]; -}; - -struct trace_event_raw_mm_page { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - int migratetype; - char __data[0]; -}; - -struct trace_event_raw_mm_page_pcpu_drain { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - int migratetype; - char __data[0]; -}; - -struct trace_event_raw_mm_page_alloc_extfrag { - struct trace_entry ent; - long unsigned int pfn; - int alloc_order; - int fallback_order; - int alloc_migratetype; - int fallback_migratetype; - int change_ownership; - char __data[0]; -}; - -struct trace_event_raw_rss_stat { - struct trace_entry ent; - unsigned int mm_id; - unsigned int curr; - int member; - long int size; - char __data[0]; -}; - -struct trace_event_data_offsets_kmem_alloc {}; - -struct trace_event_data_offsets_kmem_alloc_node {}; - -struct trace_event_data_offsets_kmem_free {}; - -struct trace_event_data_offsets_mm_page_free {}; - -struct trace_event_data_offsets_mm_page_free_batched {}; - -struct trace_event_data_offsets_mm_page_alloc {}; - -struct trace_event_data_offsets_mm_page {}; - -struct trace_event_data_offsets_mm_page_pcpu_drain {}; - -struct trace_event_data_offsets_mm_page_alloc_extfrag {}; - -struct trace_event_data_offsets_rss_stat {}; - -typedef void (*btf_trace_kmalloc)(void *, long unsigned int, const void *, size_t, size_t, gfp_t); - -typedef void (*btf_trace_kmem_cache_alloc)(void *, long unsigned int, const void *, size_t, size_t, gfp_t); - -typedef void (*btf_trace_kmalloc_node)(void *, long unsigned int, const void *, size_t, size_t, gfp_t, int); - -typedef void (*btf_trace_kmem_cache_alloc_node)(void *, long unsigned int, const void *, size_t, size_t, gfp_t, int); - -typedef void (*btf_trace_kfree)(void *, long unsigned int, const void *); - -typedef void (*btf_trace_kmem_cache_free)(void *, long unsigned int, const void *); - -typedef void (*btf_trace_mm_page_free)(void *, struct page *, unsigned int); - -typedef void (*btf_trace_mm_page_free_batched)(void *, struct page *); - -typedef void (*btf_trace_mm_page_alloc)(void *, struct page *, unsigned int, gfp_t, int); - -typedef void (*btf_trace_mm_page_alloc_zone_locked)(void *, struct page *, unsigned int, int); - -typedef void (*btf_trace_mm_page_pcpu_drain)(void *, struct page *, unsigned int, int); - -typedef void (*btf_trace_mm_page_alloc_extfrag)(void *, struct page *, int, int, int, int); - -typedef void (*btf_trace_rss_stat)(void *, struct mm_struct *, int, long int); - -enum slab_state { - DOWN = 0, - PARTIAL = 1, - PARTIAL_NODE = 2, - UP = 3, - FULL = 4, -}; - -struct kmalloc_info_struct { - const char *name[3]; - unsigned int size; -}; - -struct slabinfo { - long unsigned int active_objs; - long unsigned int num_objs; - long unsigned int active_slabs; - long unsigned int num_slabs; - long unsigned int shared_avail; - unsigned int limit; - unsigned int batchcount; - unsigned int shared; - unsigned int objects_per_slab; - unsigned int cache_order; -}; - -enum pageblock_bits { - PB_migrate = 0, - PB_migrate_end = 2, - PB_migrate_skip = 3, - NR_PAGEBLOCK_BITS = 4, -}; - -struct alloc_context { - struct zonelist *zonelist; - nodemask_t *nodemask; - struct zoneref *preferred_zoneref; - int migratetype; - enum zone_type highest_zoneidx; - bool spread_dirty_pages; -}; - -struct trace_event_raw_mm_compaction_isolate_template { - struct trace_entry ent; - long unsigned int start_pfn; - long unsigned int end_pfn; - long unsigned int nr_scanned; - long unsigned int nr_taken; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_migratepages { - struct trace_entry ent; - long unsigned int nr_migrated; - long unsigned int nr_failed; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_begin { - struct trace_entry ent; - long unsigned int zone_start; - long unsigned int migrate_pfn; - long unsigned int free_pfn; - long unsigned int zone_end; - bool sync; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_end { - struct trace_entry ent; - long unsigned int zone_start; - long unsigned int migrate_pfn; - long unsigned int free_pfn; - long unsigned int zone_end; - bool sync; - int status; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_try_to_compact_pages { - struct trace_entry ent; - int order; - gfp_t gfp_mask; - int prio; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_suitable_template { - struct trace_entry ent; - int nid; - enum zone_type idx; - int order; - int ret; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_defer_template { - struct trace_entry ent; - int nid; - enum zone_type idx; - int order; - unsigned int considered; - unsigned int defer_shift; - int order_failed; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_kcompactd_sleep { - struct trace_entry ent; - int nid; - char __data[0]; -}; - -struct trace_event_raw_kcompactd_wake_template { - struct trace_entry ent; - int nid; - int order; - enum zone_type highest_zoneidx; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_compaction_isolate_template {}; - -struct trace_event_data_offsets_mm_compaction_migratepages {}; - -struct trace_event_data_offsets_mm_compaction_begin {}; - -struct trace_event_data_offsets_mm_compaction_end {}; - -struct trace_event_data_offsets_mm_compaction_try_to_compact_pages {}; - -struct trace_event_data_offsets_mm_compaction_suitable_template {}; - -struct trace_event_data_offsets_mm_compaction_defer_template {}; - -struct trace_event_data_offsets_mm_compaction_kcompactd_sleep {}; - -struct trace_event_data_offsets_kcompactd_wake_template {}; - -typedef void (*btf_trace_mm_compaction_isolate_migratepages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - -typedef void (*btf_trace_mm_compaction_isolate_freepages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - -typedef void (*btf_trace_mm_compaction_migratepages)(void *, long unsigned int, int, struct list_head *); - -typedef void (*btf_trace_mm_compaction_begin)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, bool); - -typedef void (*btf_trace_mm_compaction_end)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, bool, int); - -typedef void (*btf_trace_mm_compaction_try_to_compact_pages)(void *, int, gfp_t, int); - -typedef void (*btf_trace_mm_compaction_finished)(void *, struct zone *, int, int); - -typedef void (*btf_trace_mm_compaction_suitable)(void *, struct zone *, int, int); - -typedef void (*btf_trace_mm_compaction_deferred)(void *, struct zone *, int); - -typedef void (*btf_trace_mm_compaction_defer_compaction)(void *, struct zone *, int); - -typedef void (*btf_trace_mm_compaction_defer_reset)(void *, struct zone *, int); - -typedef void (*btf_trace_mm_compaction_kcompactd_sleep)(void *, int); - -typedef void (*btf_trace_mm_compaction_wakeup_kcompactd)(void *, int, int, enum zone_type); - -typedef void (*btf_trace_mm_compaction_kcompactd_wake)(void *, int, int, enum zone_type); - -typedef enum { - ISOLATE_ABORT = 0, - ISOLATE_NONE = 1, - ISOLATE_SUCCESS = 2, -} isolate_migrate_t; - -struct anon_vma_chain { - struct vm_area_struct *vma; - struct anon_vma *anon_vma; - struct list_head same_vma; - struct rb_node rb; - long unsigned int rb_subtree_last; -}; - -struct rb_augment_callbacks { - void (*propagate)(struct rb_node *, struct rb_node *); - void (*copy)(struct rb_node *, struct rb_node *); - void (*rotate)(struct rb_node *, struct rb_node *); -}; - -enum lru_status { - LRU_REMOVED = 0, - LRU_REMOVED_RETRY = 1, - LRU_ROTATE = 2, - LRU_SKIP = 3, - LRU_RETRY = 4, -}; - -typedef enum lru_status (*list_lru_walk_cb)(struct list_head *, struct list_lru_one *, spinlock_t *, void *); - -typedef long unsigned int vm_flags_t; - -typedef struct { - long unsigned int pd; -} hugepd_t; - -struct migration_target_control { - int nid; - nodemask_t *nmask; - gfp_t gfp_mask; -}; - -struct follow_page_context { - struct dev_pagemap *pgmap; - unsigned int page_mask; -}; - -typedef struct { - u64 val; -} pfn_t; - -typedef unsigned int pgtbl_mod_mask; - -struct zap_details { - struct address_space *check_mapping; - long unsigned int first_index; - long unsigned int last_index; - struct page *single_page; -}; - -typedef int (*pte_fn_t)(pte_t *, long unsigned int, void *); - -enum { - SWP_USED = 1, - SWP_WRITEOK = 2, - SWP_DISCARDABLE = 4, - SWP_DISCARDING = 8, - SWP_SOLIDSTATE = 16, - SWP_CONTINUED = 32, - SWP_BLKDEV = 64, - SWP_ACTIVATED = 128, - SWP_FS_OPS = 256, - SWP_AREA_DISCARD = 512, - SWP_PAGE_DISCARD = 1024, - SWP_STABLE_WRITES = 2048, - SWP_SYNCHRONOUS_IO = 4096, - SWP_VALID = 8192, - SWP_SCANNING = 16384, -}; - -struct mm_walk; - -struct mm_walk_ops { - int (*pgd_entry)(pgd_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*p4d_entry)(p4d_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pud_entry)(pud_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pmd_entry)(pmd_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pte_entry)(pte_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pte_hole)(long unsigned int, long unsigned int, int, struct mm_walk *); - int (*hugetlb_entry)(pte_t *, long unsigned int, long unsigned int, long unsigned int, struct mm_walk *); - int (*test_walk)(long unsigned int, long unsigned int, struct mm_walk *); - int (*pre_vma)(long unsigned int, long unsigned int, struct mm_walk *); - void (*post_vma)(struct mm_walk *); -}; - -enum page_walk_action { - ACTION_SUBTREE = 0, - ACTION_CONTINUE = 1, - ACTION_AGAIN = 2, -}; - -struct mm_walk { - const struct mm_walk_ops *ops; - struct mm_struct *mm; - pgd_t *pgd; - struct vm_area_struct *vma; - enum page_walk_action action; - bool no_vma; - void *private; -}; - -struct vm_unmapped_area_info { - long unsigned int flags; - long unsigned int length; - long unsigned int low_limit; - long unsigned int high_limit; - long unsigned int align_mask; - long unsigned int align_offset; -}; - -enum { - HUGETLB_SHMFS_INODE = 1, - HUGETLB_ANONHUGE_INODE = 2, -}; - -struct trace_event_raw_vm_unmapped_area { - struct trace_entry ent; - long unsigned int addr; - long unsigned int total_vm; - long unsigned int flags; - long unsigned int length; - long unsigned int low_limit; - long unsigned int high_limit; - long unsigned int align_mask; - long unsigned int align_offset; - char __data[0]; -}; - -struct trace_event_data_offsets_vm_unmapped_area {}; - -typedef void (*btf_trace_vm_unmapped_area)(void *, long unsigned int, struct vm_unmapped_area_info *); - -struct page_vma_mapped_walk { - struct page *page; - struct vm_area_struct *vma; - long unsigned int address; - pmd_t *pmd; - pte_t *pte; - spinlock_t *ptl; - unsigned int flags; -}; - -struct rmap_walk_control { - void *arg; - bool (*rmap_one)(struct page *, struct vm_area_struct *, long unsigned int, void *); - int (*done)(struct page *); - struct anon_vma * (*anon_lock)(struct page *); - bool (*invalid_vma)(struct vm_area_struct *, void *); -}; - -struct page_referenced_arg { - int mapcount; - int referenced; - long unsigned int vm_flags; - struct mem_cgroup *memcg; -}; - -struct vmap_area { - long unsigned int va_start; - long unsigned int va_end; - struct rb_node rb_node; - struct list_head list; - union { - long unsigned int subtree_max_size; - struct vm_struct *vm; - struct llist_node purge_list; - }; -}; - -struct vfree_deferred { - struct llist_head list; - struct work_struct wq; -}; - -enum fit_type { - NOTHING_FIT = 0, - FL_FIT_TYPE = 1, - LE_FIT_TYPE = 2, - RE_FIT_TYPE = 3, - NE_FIT_TYPE = 4, -}; - -struct vmap_block_queue { - spinlock_t lock; - struct list_head free; -}; - -struct vmap_block { - spinlock_t lock; - struct vmap_area *va; - long unsigned int free; - long unsigned int dirty; - long unsigned int dirty_min; - long unsigned int dirty_max; - struct list_head free_list; - struct callback_head callback_head; - struct list_head purge; -}; - -struct page_frag_cache { - void *va; - __u16 offset; - __u16 size; - unsigned int pagecnt_bias; - bool pfmemalloc; -}; - -enum zone_flags { - ZONE_BOOSTED_WATERMARK = 0, -}; - -enum meminit_context { - MEMINIT_EARLY = 0, - MEMINIT_HOTPLUG = 1, -}; - -typedef int fpi_t; - -struct pcpu_drain { - struct zone *zone; - struct work_struct work; -}; - -struct madvise_walk_private { - struct mmu_gather *tlb; - bool pageout; -}; - -enum { - BIO_NO_PAGE_REF = 0, - BIO_CLONED = 1, - BIO_BOUNCED = 2, - BIO_WORKINGSET = 3, - BIO_QUIET = 4, - BIO_CHAIN = 5, - BIO_REFFED = 6, - BIO_THROTTLED = 7, - BIO_TRACE_COMPLETION = 8, - BIO_CGROUP_ACCT = 9, - BIO_TRACKED = 10, - BIO_FLAG_LAST = 11, -}; - -struct vma_swap_readahead { - short unsigned int win; - short unsigned int offset; - short unsigned int nr_pte; - pte_t *ptes; -}; - -union swap_header { - struct { - char reserved[4086]; - char magic[10]; - } magic; - struct { - char bootbits[1024]; - __u32 version; - __u32 last_page; - __u32 nr_badpages; - unsigned char sws_uuid[16]; - unsigned char sws_volume[16]; - __u32 padding[117]; - __u32 badpages[1]; - } info; -}; - -struct swap_extent { - struct rb_node rb_node; - long unsigned int start_page; - long unsigned int nr_pages; - sector_t start_block; -}; - -struct swap_slots_cache { - bool lock_initialized; - struct mutex alloc_lock; - swp_entry_t *slots; - int nr; - int cur; - spinlock_t free_lock; - swp_entry_t *slots_ret; - int n_ret; -}; - -struct frontswap_ops { - void (*init)(unsigned int); - int (*store)(unsigned int, long unsigned int, struct page *); - int (*load)(unsigned int, long unsigned int, struct page *); - void (*invalidate_page)(unsigned int, long unsigned int); - void (*invalidate_area)(unsigned int); - struct frontswap_ops *next; -}; - -struct crypto_alg; - -struct crypto_tfm { - u32 crt_flags; - int node; - void (*exit)(struct crypto_tfm *); - struct crypto_alg *__crt_alg; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__crt_ctx[0]; -}; - -struct cipher_alg { - unsigned int cia_min_keysize; - unsigned int cia_max_keysize; - int (*cia_setkey)(struct crypto_tfm *, const u8 *, unsigned int); - void (*cia_encrypt)(struct crypto_tfm *, u8 *, const u8 *); - void (*cia_decrypt)(struct crypto_tfm *, u8 *, const u8 *); -}; - -struct compress_alg { - int (*coa_compress)(struct crypto_tfm *, const u8 *, unsigned int, u8 *, unsigned int *); - int (*coa_decompress)(struct crypto_tfm *, const u8 *, unsigned int, u8 *, unsigned int *); -}; - -struct crypto_type; - -struct crypto_alg { - struct list_head cra_list; - struct list_head cra_users; - u32 cra_flags; - unsigned int cra_blocksize; - unsigned int cra_ctxsize; - unsigned int cra_alignmask; - int cra_priority; - refcount_t cra_refcnt; - char cra_name[128]; - char cra_driver_name[128]; - const struct crypto_type *cra_type; - union { - struct cipher_alg cipher; - struct compress_alg compress; - } cra_u; - int (*cra_init)(struct crypto_tfm *); - void (*cra_exit)(struct crypto_tfm *); - void (*cra_destroy)(struct crypto_alg *); - struct module *cra_module; -}; - -struct crypto_instance; - -struct crypto_type { - unsigned int (*ctxsize)(struct crypto_alg *, u32, u32); - unsigned int (*extsize)(struct crypto_alg *); - int (*init)(struct crypto_tfm *, u32, u32); - int (*init_tfm)(struct crypto_tfm *); - void (*show)(struct seq_file *, struct crypto_alg *); - int (*report)(struct sk_buff *, struct crypto_alg *); - void (*free)(struct crypto_instance *); - unsigned int type; - unsigned int maskclear; - unsigned int maskset; - unsigned int tfmsize; -}; - -struct crypto_comp { - struct crypto_tfm base; -}; - -struct zpool; - -struct zpool_ops { - int (*evict)(struct zpool *, long unsigned int); -}; - -enum zpool_mapmode { - ZPOOL_MM_RW = 0, - ZPOOL_MM_RO = 1, - ZPOOL_MM_WO = 2, - ZPOOL_MM_DEFAULT = 0, -}; - -struct zswap_pool { - struct zpool *zpool; - struct crypto_comp **tfm; - struct kref kref; - struct list_head list; - struct work_struct release_work; - struct work_struct shrink_work; - struct hlist_node node; - char tfm_name[128]; -}; - -struct zswap_entry { - struct rb_node rbnode; - long unsigned int offset; - int refcount; - unsigned int length; - struct zswap_pool *pool; - union { - long unsigned int handle; - long unsigned int value; - }; -}; - -struct zswap_header { - swp_entry_t swpentry; -}; - -struct zswap_tree { - struct rb_root rbroot; - spinlock_t lock; -}; - -enum zswap_get_swap_ret { - ZSWAP_SWAPCACHE_NEW = 0, - ZSWAP_SWAPCACHE_EXIST = 1, - ZSWAP_SWAPCACHE_FAIL = 2, -}; - -struct dma_pool { - struct list_head page_list; - spinlock_t lock; - size_t size; - struct device *dev; - size_t allocation; - size_t boundary; - char name[32]; - struct list_head pools; -}; - -struct dma_page { - struct list_head page_list; - void *vaddr; - dma_addr_t dma; - unsigned int in_use; - unsigned int offset; -}; - -struct mmu_notifier_subscriptions { - struct hlist_head list; - bool has_itree; - spinlock_t lock; - long unsigned int invalidate_seq; - long unsigned int active_invalidate_ranges; - struct rb_root_cached itree; - wait_queue_head_t wq; - struct hlist_head deferred_list; -}; - -struct interval_tree_node { - struct rb_node rb; - long unsigned int start; - long unsigned int last; - long unsigned int __subtree_last; -}; - -struct mmu_interval_notifier; - -struct mmu_interval_notifier_ops { - bool (*invalidate)(struct mmu_interval_notifier *, const struct mmu_notifier_range *, long unsigned int); -}; - -struct mmu_interval_notifier { - struct interval_tree_node interval_tree; - const struct mmu_interval_notifier_ops *ops; - struct mm_struct *mm; - struct hlist_node deferred_item; - long unsigned int invalidate_seq; -}; - -enum stat_item { - ALLOC_FASTPATH = 0, - ALLOC_SLOWPATH = 1, - FREE_FASTPATH = 2, - FREE_SLOWPATH = 3, - FREE_FROZEN = 4, - FREE_ADD_PARTIAL = 5, - FREE_REMOVE_PARTIAL = 6, - ALLOC_FROM_PARTIAL = 7, - ALLOC_SLAB = 8, - ALLOC_REFILL = 9, - ALLOC_NODE_MISMATCH = 10, - FREE_SLAB = 11, - CPUSLAB_FLUSH = 12, - DEACTIVATE_FULL = 13, - DEACTIVATE_EMPTY = 14, - DEACTIVATE_TO_HEAD = 15, - DEACTIVATE_TO_TAIL = 16, - DEACTIVATE_REMOTE_FREES = 17, - DEACTIVATE_BYPASS = 18, - ORDER_FALLBACK = 19, - CMPXCHG_DOUBLE_CPU_FAIL = 20, - CMPXCHG_DOUBLE_FAIL = 21, - CPU_PARTIAL_ALLOC = 22, - CPU_PARTIAL_FREE = 23, - CPU_PARTIAL_NODE = 24, - CPU_PARTIAL_DRAIN = 25, - NR_SLUB_STAT_ITEMS = 26, -}; - -struct track { - long unsigned int addr; - long unsigned int addrs[16]; - int cpu; - int pid; - long unsigned int when; -}; - -enum track_item { - TRACK_ALLOC = 0, - TRACK_FREE = 1, -}; - -struct detached_freelist { - struct page *page; - void *tail; - void *freelist; - int cnt; - struct kmem_cache *s; -}; - -struct location { - long unsigned int count; - long unsigned int addr; - long long int sum_time; - long int min_time; - long int max_time; - long int min_pid; - long int max_pid; - long unsigned int cpus[4]; - nodemask_t nodes; -}; - -struct loc_track { - long unsigned int max; - long unsigned int count; - struct location *loc; -}; - -enum slab_stat_type { - SL_ALL = 0, - SL_PARTIAL = 1, - SL_CPU = 2, - SL_OBJECTS = 3, - SL_TOTAL = 4, -}; - -struct slab_attribute { - struct attribute attr; - ssize_t (*show)(struct kmem_cache *, char *); - ssize_t (*store)(struct kmem_cache *, const char *, size_t); -}; - -struct saved_alias { - struct kmem_cache *s; - const char *name; - struct saved_alias *next; -}; - -enum slab_modes { - M_NONE = 0, - M_PARTIAL = 1, - M_FULL = 2, - M_FREE = 3, -}; - -struct buffer_head; - -typedef void bh_end_io_t(struct buffer_head *, int); - -struct buffer_head { - long unsigned int b_state; - struct buffer_head *b_this_page; - struct page *b_page; - sector_t b_blocknr; - size_t b_size; - char *b_data; - struct block_device *b_bdev; - bh_end_io_t *b_end_io; - void *b_private; - struct list_head b_assoc_buffers; - struct address_space *b_assoc_map; - atomic_t b_count; - spinlock_t b_uptodate_lock; -}; - -typedef struct page *new_page_t(struct page *, long unsigned int); - -typedef void free_page_t(struct page *, long unsigned int); - -enum bh_state_bits { - BH_Uptodate = 0, - BH_Dirty = 1, - BH_Lock = 2, - BH_Req = 3, - BH_Mapped = 4, - BH_New = 5, - BH_Async_Read = 6, - BH_Async_Write = 7, - BH_Delay = 8, - BH_Boundary = 9, - BH_Write_EIO = 10, - BH_Unwritten = 11, - BH_Quiet = 12, - BH_Meta = 13, - BH_Prio = 14, - BH_Defer_Completion = 15, - BH_PrivateStart = 16, -}; - -struct trace_event_raw_mm_migrate_pages { - struct trace_entry ent; - long unsigned int succeeded; - long unsigned int failed; - long unsigned int thp_succeeded; - long unsigned int thp_failed; - long unsigned int thp_split; - enum migrate_mode mode; - int reason; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_migrate_pages {}; - -typedef void (*btf_trace_mm_migrate_pages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, enum migrate_mode, int); - -struct mem_cgroup_reclaim_cookie { - pg_data_t *pgdat; - unsigned int generation; -}; - -struct mem_cgroup_tree_per_node { - struct rb_root rb_root; - struct rb_node *rb_rightmost; - spinlock_t lock; -}; - -struct mem_cgroup_tree { - struct mem_cgroup_tree_per_node *rb_tree_per_node[1]; -}; - -struct mem_cgroup_eventfd_list { - struct list_head list; - struct eventfd_ctx *eventfd; -}; - -struct mem_cgroup_event { - struct mem_cgroup *memcg; - struct eventfd_ctx *eventfd; - struct list_head list; - int (*register_event)(struct mem_cgroup *, struct eventfd_ctx *, const char *); - void (*unregister_event)(struct mem_cgroup *, struct eventfd_ctx *); - poll_table pt; - wait_queue_head_t *wqh; - wait_queue_entry_t wait; - struct work_struct remove; -}; - -struct move_charge_struct { - spinlock_t lock; - struct mm_struct *mm; - struct mem_cgroup *from; - struct mem_cgroup *to; - long unsigned int flags; - long unsigned int precharge; - long unsigned int moved_charge; - long unsigned int moved_swap; - struct task_struct *moving_task; - wait_queue_head_t waitq; -}; - -enum res_type { - _MEM = 0, - _MEMSWAP = 1, - _OOM_TYPE = 2, - _KMEM = 3, - _TCP = 4, -}; - -struct memory_stat { - const char *name; - unsigned int ratio; - unsigned int idx; -}; - -struct oom_wait_info { - struct mem_cgroup *memcg; - wait_queue_entry_t wait; -}; - -enum oom_status { - OOM_SUCCESS = 0, - OOM_FAILED = 1, - OOM_ASYNC = 2, - OOM_SKIPPED = 3, -}; - -struct memcg_stock_pcp { - struct mem_cgroup *cached; - unsigned int nr_pages; - struct obj_cgroup *cached_objcg; - unsigned int nr_bytes; - struct work_struct work; - long unsigned int flags; -}; - -enum { - RES_USAGE = 0, - RES_LIMIT = 1, - RES_MAX_USAGE = 2, - RES_FAILCNT = 3, - RES_SOFT_LIMIT = 4, -}; - -union mc_target { - struct page *page; - swp_entry_t ent; -}; - -enum mc_target_type { - MC_TARGET_NONE = 0, - MC_TARGET_PAGE = 1, - MC_TARGET_SWAP = 2, - MC_TARGET_DEVICE = 3, -}; - -struct uncharge_gather { - struct mem_cgroup *memcg; - long unsigned int nr_pages; - long unsigned int pgpgout; - long unsigned int nr_kmem; - struct page *dummy_page; -}; - -enum vmpressure_levels { - VMPRESSURE_LOW = 0, - VMPRESSURE_MEDIUM = 1, - VMPRESSURE_CRITICAL = 2, - VMPRESSURE_NUM_LEVELS = 3, -}; - -enum vmpressure_modes { - VMPRESSURE_NO_PASSTHROUGH = 0, - VMPRESSURE_HIERARCHY = 1, - VMPRESSURE_LOCAL = 2, - VMPRESSURE_NUM_MODES = 3, -}; - -struct vmpressure_event { - struct eventfd_ctx *efd; - enum vmpressure_levels level; - enum vmpressure_modes mode; - struct list_head node; -}; - -struct swap_cgroup_ctrl { - struct page **map; - long unsigned int length; - spinlock_t lock; -}; - -struct swap_cgroup { - short unsigned int id; -}; - -struct cleancache_filekey { - union { - ino_t ino; - __u32 fh[6]; - u32 key[6]; - } u; -}; - -struct cleancache_ops { - int (*init_fs)(size_t); - int (*init_shared_fs)(uuid_t *, size_t); - int (*get_page)(int, struct cleancache_filekey, long unsigned int, struct page *); - void (*put_page)(int, struct cleancache_filekey, long unsigned int, struct page *); - void (*invalidate_page)(int, struct cleancache_filekey, long unsigned int); - void (*invalidate_inode)(int, struct cleancache_filekey); - void (*invalidate_fs)(int); -}; - -struct trace_event_raw_test_pages_isolated { - struct trace_entry ent; - long unsigned int start_pfn; - long unsigned int end_pfn; - long unsigned int fin_pfn; - char __data[0]; -}; - -struct trace_event_data_offsets_test_pages_isolated {}; - -typedef void (*btf_trace_test_pages_isolated)(void *, long unsigned int, long unsigned int, long unsigned int); - -struct zpool_driver; - -struct zpool { - struct zpool_driver *driver; - void *pool; - const struct zpool_ops *ops; - bool evictable; - struct list_head list; -}; - -struct zpool_driver { - char *type; - struct module *owner; - atomic_t refcount; - struct list_head list; - void * (*create)(const char *, gfp_t, const struct zpool_ops *, struct zpool *); - void (*destroy)(void *); - bool malloc_support_movable; - int (*malloc)(void *, size_t, gfp_t, long unsigned int *); - void (*free)(void *, long unsigned int); - int (*shrink)(void *, unsigned int, unsigned int *); - void * (*map)(void *, long unsigned int, enum zpool_mapmode); - void (*unmap)(void *, long unsigned int); - u64 (*total_size)(void *); -}; - -typedef void (*exitcall_t)(); - -struct zbud_pool; - -struct zbud_ops { - int (*evict)(struct zbud_pool *, long unsigned int); -}; - -struct zbud_pool { - spinlock_t lock; - struct list_head unbuddied[63]; - struct list_head buddied; - struct list_head lru; - u64 pages_nr; - const struct zbud_ops *ops; - struct zpool *zpool; - const struct zpool_ops *zpool_ops; -}; - -struct zbud_header { - struct list_head buddy; - struct list_head lru; - unsigned int first_chunks; - unsigned int last_chunks; - bool under_reclaim; -}; - -enum buddy { - FIRST = 0, - LAST = 1, -}; - -struct cma { - long unsigned int base_pfn; - long unsigned int count; - long unsigned int *bitmap; - unsigned int order_per_bit; - struct mutex lock; - char name[64]; -}; - -struct trace_event_raw_cma_alloc { - struct trace_entry ent; - long unsigned int pfn; - const struct page *page; - unsigned int count; - unsigned int align; - char __data[0]; -}; - -struct trace_event_raw_cma_release { - struct trace_entry ent; - long unsigned int pfn; - const struct page *page; - unsigned int count; - char __data[0]; -}; - -struct trace_event_data_offsets_cma_alloc {}; - -struct trace_event_data_offsets_cma_release {}; - -typedef void (*btf_trace_cma_alloc)(void *, long unsigned int, const struct page *, unsigned int, unsigned int); - -typedef void (*btf_trace_cma_release)(void *, long unsigned int, const struct page *, unsigned int); - -typedef s32 compat_off_t; - -struct open_how { - __u64 flags; - __u64 mode; - __u64 resolve; -}; - -struct open_flags { - int open_flag; - umode_t mode; - int acc_mode; - int intent; - int lookup_flags; -}; - -typedef s64 compat_loff_t; - -typedef __kernel_rwf_t rwf_t; - -struct fscrypt_policy_v1 { - __u8 version; - __u8 contents_encryption_mode; - __u8 filenames_encryption_mode; - __u8 flags; - __u8 master_key_descriptor[8]; -}; - -struct fscrypt_policy_v2 { - __u8 version; - __u8 contents_encryption_mode; - __u8 filenames_encryption_mode; - __u8 flags; - __u8 __reserved[4]; - __u8 master_key_identifier[16]; -}; - -union fscrypt_policy { - u8 version; - struct fscrypt_policy_v1 v1; - struct fscrypt_policy_v2 v2; -}; - -enum vfs_get_super_keying { - vfs_get_single_super = 0, - vfs_get_single_reconf_super = 1, - vfs_get_keyed_super = 2, - vfs_get_independent_super = 3, -}; - -struct kobj_map; - -struct char_device_struct { - struct char_device_struct *next; - unsigned int major; - unsigned int baseminor; - int minorct; - char name[64]; - struct cdev *cdev; -}; - -struct stat { - long unsigned int st_dev; - long unsigned int st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - long unsigned int st_rdev; - long unsigned int __pad1; - long int st_size; - int st_blksize; - int __pad2; - long int st_blocks; - long int st_atime; - long unsigned int st_atime_nsec; - long int st_mtime; - long unsigned int st_mtime_nsec; - long int st_ctime; - long unsigned int st_ctime_nsec; - unsigned int __unused4; - unsigned int __unused5; -}; - -typedef u32 compat_ino_t; - -typedef u16 compat_ushort_t; - -typedef s64 compat_s64; - -typedef u16 __compat_uid16_t; - -typedef u16 __compat_gid16_t; - -typedef u16 compat_mode_t; - -typedef u32 compat_dev_t; - -struct compat_stat { - compat_dev_t st_dev; - compat_ino_t st_ino; - compat_mode_t st_mode; - compat_ushort_t st_nlink; - __compat_uid16_t st_uid; - __compat_gid16_t st_gid; - compat_dev_t st_rdev; - compat_off_t st_size; - compat_off_t st_blksize; - compat_off_t st_blocks; - old_time32_t st_atime; - compat_ulong_t st_atime_nsec; - old_time32_t st_mtime; - compat_ulong_t st_mtime_nsec; - old_time32_t st_ctime; - compat_ulong_t st_ctime_nsec; - compat_ulong_t __unused4[2]; -}; - -struct stat64 { - compat_u64 st_dev; - unsigned char __pad0[4]; - compat_ulong_t __st_ino; - compat_uint_t st_mode; - compat_uint_t st_nlink; - compat_ulong_t st_uid; - compat_ulong_t st_gid; - compat_u64 st_rdev; - unsigned char __pad3[4]; - compat_s64 st_size; - compat_ulong_t st_blksize; - compat_u64 st_blocks; - compat_ulong_t st_atime; - compat_ulong_t st_atime_nsec; - compat_ulong_t st_mtime; - compat_ulong_t st_mtime_nsec; - compat_ulong_t st_ctime; - compat_ulong_t st_ctime_nsec; - compat_u64 st_ino; -}; - -struct statx_timestamp { - __s64 tv_sec; - __u32 tv_nsec; - __s32 __reserved; -}; - -struct statx { - __u32 stx_mask; - __u32 stx_blksize; - __u64 stx_attributes; - __u32 stx_nlink; - __u32 stx_uid; - __u32 stx_gid; - __u16 stx_mode; - __u16 __spare0[1]; - __u64 stx_ino; - __u64 stx_size; - __u64 stx_blocks; - __u64 stx_attributes_mask; - struct statx_timestamp stx_atime; - struct statx_timestamp stx_btime; - struct statx_timestamp stx_ctime; - struct statx_timestamp stx_mtime; - __u32 stx_rdev_major; - __u32 stx_rdev_minor; - __u32 stx_dev_major; - __u32 stx_dev_minor; - __u64 stx_mnt_id; - __u64 __spare2; - __u64 __spare3[12]; -}; - -struct mount; - -struct mnt_namespace { - atomic_t count; - struct ns_common ns; - struct mount *root; - struct list_head list; - spinlock_t ns_lock; - struct user_namespace *user_ns; - struct ucounts *ucounts; - u64 seq; - wait_queue_head_t poll; - u64 event; - unsigned int mounts; - unsigned int pending_mounts; -}; - -struct mnt_pcp; - -struct mountpoint; - -struct mount { - struct hlist_node mnt_hash; - struct mount *mnt_parent; - struct dentry *mnt_mountpoint; - struct vfsmount mnt; - union { - struct callback_head mnt_rcu; - struct llist_node mnt_llist; - }; - struct mnt_pcp *mnt_pcp; - struct list_head mnt_mounts; - struct list_head mnt_child; - struct list_head mnt_instance; - const char *mnt_devname; - struct list_head mnt_list; - struct list_head mnt_expire; - struct list_head mnt_share; - struct list_head mnt_slave_list; - struct list_head mnt_slave; - struct mount *mnt_master; - struct mnt_namespace *mnt_ns; - struct mountpoint *mnt_mp; - union { - struct hlist_node mnt_mp_list; - struct hlist_node mnt_umount; - }; - struct list_head mnt_umounting; - struct fsnotify_mark_connector *mnt_fsnotify_marks; - __u32 mnt_fsnotify_mask; - int mnt_id; - int mnt_group_id; - int mnt_expiry_mark; - struct hlist_head mnt_pins; - struct hlist_head mnt_stuck_children; -}; - -struct mnt_pcp { - int mnt_count; - int mnt_writers; -}; - -struct mountpoint { - struct hlist_node m_hash; - struct dentry *m_dentry; - struct hlist_head m_list; - int m_count; -}; - -typedef short unsigned int ushort; - -struct user_arg_ptr { - bool is_compat; - union { - const char * const *native; - const compat_uptr_t *compat; - } ptr; -}; - -enum inode_i_mutex_lock_class { - I_MUTEX_NORMAL = 0, - I_MUTEX_PARENT = 1, - I_MUTEX_CHILD = 2, - I_MUTEX_XATTR = 3, - I_MUTEX_NONDIR2 = 4, - I_MUTEX_PARENT2 = 5, -}; - -struct pseudo_fs_context { - const struct super_operations *ops; - const struct xattr_handler **xattr; - const struct dentry_operations *dops; - long unsigned int magic; -}; - -struct name_snapshot { - struct qstr name; - unsigned char inline_name[32]; -}; - -struct saved { - struct path link; - struct delayed_call done; - const char *name; - unsigned int seq; -}; - -struct nameidata { - struct path path; - struct qstr last; - struct path root; - struct inode *inode; - unsigned int flags; - unsigned int seq; - unsigned int m_seq; - unsigned int r_seq; - int last_type; - unsigned int depth; - int total_link_count; - struct saved *stack; - struct saved internal[2]; - struct filename *name; - struct nameidata *saved; - unsigned int root_seq; - int dfd; - kuid_t dir_uid; - umode_t dir_mode; -}; - -enum { - LAST_NORM = 0, - LAST_ROOT = 1, - LAST_DOT = 2, - LAST_DOTDOT = 3, -}; - -enum { - WALK_TRAILING = 1, - WALK_MORE = 2, - WALK_NOFOLLOW = 4, -}; - -struct word_at_a_time { - const long unsigned int one_bits; - const long unsigned int high_bits; -}; - -struct compat_flock { - short int l_type; - short int l_whence; - compat_off_t l_start; - compat_off_t l_len; - compat_pid_t l_pid; -}; - -struct compat_flock64 { - short int l_type; - short int l_whence; - compat_loff_t l_start; - compat_loff_t l_len; - compat_pid_t l_pid; -}; - -struct f_owner_ex { - int type; - __kernel_pid_t pid; -}; - -struct flock { - short int l_type; - short int l_whence; - __kernel_off_t l_start; - __kernel_off_t l_len; - __kernel_pid_t l_pid; -}; - -struct file_clone_range { - __s64 src_fd; - __u64 src_offset; - __u64 src_length; - __u64 dest_offset; -}; - -struct file_dedupe_range_info { - __s64 dest_fd; - __u64 dest_offset; - __u64 bytes_deduped; - __s32 status; - __u32 reserved; -}; - -struct file_dedupe_range { - __u64 src_offset; - __u64 src_length; - __u16 dest_count; - __u16 reserved1; - __u32 reserved2; - struct file_dedupe_range_info info[0]; -}; - -typedef int get_block_t(struct inode *, sector_t, struct buffer_head *, int); - -struct fiemap_extent; - -struct fiemap_extent_info { - unsigned int fi_flags; - unsigned int fi_extents_mapped; - unsigned int fi_extents_max; - struct fiemap_extent *fi_extents_start; -}; - -struct space_resv { - __s16 l_type; - __s16 l_whence; - __s64 l_start; - __s64 l_len; - __s32 l_sysid; - __u32 l_pid; - __s32 l_pad[4]; -}; - -struct fiemap_extent { - __u64 fe_logical; - __u64 fe_physical; - __u64 fe_length; - __u64 fe_reserved64[2]; - __u32 fe_flags; - __u32 fe_reserved[3]; -}; - -struct fiemap { - __u64 fm_start; - __u64 fm_length; - __u32 fm_flags; - __u32 fm_mapped_extents; - __u32 fm_extent_count; - __u32 fm_reserved; - struct fiemap_extent fm_extents[0]; -}; - -struct linux_dirent64 { - u64 d_ino; - s64 d_off; - short unsigned int d_reclen; - unsigned char d_type; - char d_name[0]; -}; - -struct linux_dirent { - long unsigned int d_ino; - long unsigned int d_off; - short unsigned int d_reclen; - char d_name[1]; -}; - -struct getdents_callback { - struct dir_context ctx; - struct linux_dirent *current_dir; - int prev_reclen; - int count; - int error; -}; - -struct getdents_callback64 { - struct dir_context ctx; - struct linux_dirent64 *current_dir; - int prev_reclen; - int count; - int error; -}; - -struct compat_old_linux_dirent { - compat_ulong_t d_ino; - compat_ulong_t d_offset; - short unsigned int d_namlen; - char d_name[1]; -}; - -struct compat_readdir_callback { - struct dir_context ctx; - struct compat_old_linux_dirent *dirent; - int result; -}; - -struct compat_linux_dirent { - compat_ulong_t d_ino; - compat_ulong_t d_off; - short unsigned int d_reclen; - char d_name[1]; -}; - -struct compat_getdents_callback { - struct dir_context ctx; - struct compat_linux_dirent *current_dir; - int prev_reclen; - int count; - int error; -}; - -typedef struct { - long unsigned int fds_bits[16]; -} __kernel_fd_set; - -typedef __kernel_fd_set fd_set; - -struct poll_table_entry { - struct file *filp; - __poll_t key; - wait_queue_entry_t wait; - wait_queue_head_t *wait_address; -}; - -struct poll_table_page; - -struct poll_wqueues { - poll_table pt; - struct poll_table_page *table; - struct task_struct *polling_task; - int triggered; - int error; - int inline_index; - struct poll_table_entry inline_entries[9]; -}; - -struct poll_table_page { - struct poll_table_page *next; - struct poll_table_entry *entry; - struct poll_table_entry entries[0]; -}; - -enum poll_time_type { - PT_TIMEVAL = 0, - PT_OLD_TIMEVAL = 1, - PT_TIMESPEC = 2, - PT_OLD_TIMESPEC = 3, -}; - -typedef struct { - long unsigned int *in; - long unsigned int *out; - long unsigned int *ex; - long unsigned int *res_in; - long unsigned int *res_out; - long unsigned int *res_ex; -} fd_set_bits; - -struct sigset_argpack { - sigset_t *p; - size_t size; -}; - -struct poll_list { - struct poll_list *next; - int len; - struct pollfd entries[0]; -}; - -struct compat_sel_arg_struct { - compat_ulong_t n; - compat_uptr_t inp; - compat_uptr_t outp; - compat_uptr_t exp; - compat_uptr_t tvp; -}; - -struct compat_sigset_argpack { - compat_uptr_t p; - compat_size_t size; -}; - -enum dentry_d_lock_class { - DENTRY_D_LOCK_NORMAL = 0, - DENTRY_D_LOCK_NESTED = 1, -}; - -struct external_name { - union { - atomic_t count; - struct callback_head head; - } u; - unsigned char name[0]; -}; - -enum d_walk_ret { - D_WALK_CONTINUE = 0, - D_WALK_QUIT = 1, - D_WALK_NORETRY = 2, - D_WALK_SKIP = 3, -}; - -struct check_mount { - struct vfsmount *mnt; - unsigned int mounted; -}; - -struct select_data { - struct dentry *start; - union { - long int found; - struct dentry *victim; - }; - struct list_head dispose; -}; - -struct fsxattr { - __u32 fsx_xflags; - __u32 fsx_extsize; - __u32 fsx_nextents; - __u32 fsx_projid; - __u32 fsx_cowextsize; - unsigned char fsx_pad[8]; -}; - -enum file_time_flags { - S_ATIME = 1, - S_MTIME = 2, - S_CTIME = 4, - S_VERSION = 8, -}; - -struct proc_mounts { - struct mnt_namespace *ns; - struct path root; - int (*show)(struct seq_file *, struct vfsmount *); - struct mount cursor; -}; - -enum umount_tree_flags { - UMOUNT_SYNC = 1, - UMOUNT_PROPAGATE = 2, - UMOUNT_CONNECTED = 4, -}; - -struct simple_transaction_argresp { - ssize_t size; - char data[0]; -}; - -struct simple_attr { - int (*get)(void *, u64 *); - int (*set)(void *, u64); - char get_buf[24]; - char set_buf[24]; - void *data; - const char *fmt; - struct mutex mutex; -}; - -struct wb_writeback_work { - long int nr_pages; - struct super_block *sb; - enum writeback_sync_modes sync_mode; - unsigned int tagged_writepages: 1; - unsigned int for_kupdate: 1; - unsigned int range_cyclic: 1; - unsigned int for_background: 1; - unsigned int for_sync: 1; - unsigned int auto_free: 1; - enum wb_reason reason; - struct list_head list; - struct wb_completion *done; -}; - -struct trace_event_raw_writeback_page_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int index; - char __data[0]; -}; - -struct trace_event_raw_writeback_dirty_inode_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int state; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_inode_foreign_history { - struct trace_entry ent; - char name[32]; - ino_t ino; - ino_t cgroup_ino; - unsigned int history; - char __data[0]; -}; - -struct trace_event_raw_inode_switch_wbs { - struct trace_entry ent; - char name[32]; - ino_t ino; - ino_t old_cgroup_ino; - ino_t new_cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_track_foreign_dirty { - struct trace_entry ent; - char name[32]; - u64 bdi_id; - ino_t ino; - unsigned int memcg_id; - ino_t cgroup_ino; - ino_t page_cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_flush_foreign { - struct trace_entry ent; - char name[32]; - ino_t cgroup_ino; - unsigned int frn_bdi_id; - unsigned int frn_memcg_id; - char __data[0]; -}; - -struct trace_event_raw_writeback_write_inode_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - int sync_mode; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_work_class { - struct trace_entry ent; - char name[32]; - long int nr_pages; - dev_t sb_dev; - int sync_mode; - int for_kupdate; - int range_cyclic; - int for_background; - int reason; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_pages_written { - struct trace_entry ent; - long int pages; - char __data[0]; -}; - -struct trace_event_raw_writeback_class { - struct trace_entry ent; - char name[32]; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_bdi_register { - struct trace_entry ent; - char name[32]; - char __data[0]; -}; - -struct trace_event_raw_wbc_class { - struct trace_entry ent; - char name[32]; - long int nr_to_write; - long int pages_skipped; - int sync_mode; - int for_kupdate; - int for_background; - int for_reclaim; - int range_cyclic; - long int range_start; - long int range_end; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_queue_io { - struct trace_entry ent; - char name[32]; - long unsigned int older; - long int age; - int moved; - int reason; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_global_dirty_state { - struct trace_entry ent; - long unsigned int nr_dirty; - long unsigned int nr_writeback; - long unsigned int background_thresh; - long unsigned int dirty_thresh; - long unsigned int dirty_limit; - long unsigned int nr_dirtied; - long unsigned int nr_written; - char __data[0]; -}; - -struct trace_event_raw_bdi_dirty_ratelimit { - struct trace_entry ent; - char bdi[32]; - long unsigned int write_bw; - long unsigned int avg_write_bw; - long unsigned int dirty_rate; - long unsigned int dirty_ratelimit; - long unsigned int task_ratelimit; - long unsigned int balanced_dirty_ratelimit; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_balance_dirty_pages { - struct trace_entry ent; - char bdi[32]; - long unsigned int limit; - long unsigned int setpoint; - long unsigned int dirty; - long unsigned int bdi_setpoint; - long unsigned int bdi_dirty; - long unsigned int dirty_ratelimit; - long unsigned int task_ratelimit; - unsigned int dirtied; - unsigned int dirtied_pause; - long unsigned int paused; - long int pause; - long unsigned int period; - long int think; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_sb_inodes_requeue { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int state; - long unsigned int dirtied_when; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_congest_waited_template { - struct trace_entry ent; - unsigned int usec_timeout; - unsigned int usec_delayed; - char __data[0]; -}; - -struct trace_event_raw_writeback_single_inode_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int state; - long unsigned int dirtied_when; - long unsigned int writeback_index; - long int nr_to_write; - long unsigned int wrote; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_inode_template { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int state; - __u16 mode; - long unsigned int dirtied_when; - char __data[0]; -}; - -struct trace_event_data_offsets_writeback_page_template {}; - -struct trace_event_data_offsets_writeback_dirty_inode_template {}; - -struct trace_event_data_offsets_inode_foreign_history {}; - -struct trace_event_data_offsets_inode_switch_wbs {}; - -struct trace_event_data_offsets_track_foreign_dirty {}; - -struct trace_event_data_offsets_flush_foreign {}; - -struct trace_event_data_offsets_writeback_write_inode_template {}; - -struct trace_event_data_offsets_writeback_work_class {}; - -struct trace_event_data_offsets_writeback_pages_written {}; - -struct trace_event_data_offsets_writeback_class {}; - -struct trace_event_data_offsets_writeback_bdi_register {}; - -struct trace_event_data_offsets_wbc_class {}; - -struct trace_event_data_offsets_writeback_queue_io {}; - -struct trace_event_data_offsets_global_dirty_state {}; - -struct trace_event_data_offsets_bdi_dirty_ratelimit {}; - -struct trace_event_data_offsets_balance_dirty_pages {}; - -struct trace_event_data_offsets_writeback_sb_inodes_requeue {}; - -struct trace_event_data_offsets_writeback_congest_waited_template {}; - -struct trace_event_data_offsets_writeback_single_inode_template {}; - -struct trace_event_data_offsets_writeback_inode_template {}; - -typedef void (*btf_trace_writeback_dirty_page)(void *, struct page *, struct address_space *); - -typedef void (*btf_trace_wait_on_page_writeback)(void *, struct page *, struct address_space *); - -typedef void (*btf_trace_writeback_mark_inode_dirty)(void *, struct inode *, int); - -typedef void (*btf_trace_writeback_dirty_inode_start)(void *, struct inode *, int); - -typedef void (*btf_trace_writeback_dirty_inode)(void *, struct inode *, int); - -typedef void (*btf_trace_inode_foreign_history)(void *, struct inode *, struct writeback_control *, unsigned int); - -typedef void (*btf_trace_inode_switch_wbs)(void *, struct inode *, struct bdi_writeback *, struct bdi_writeback *); - -typedef void (*btf_trace_track_foreign_dirty)(void *, struct page *, struct bdi_writeback *); - -typedef void (*btf_trace_flush_foreign)(void *, struct bdi_writeback *, unsigned int, unsigned int); - -typedef void (*btf_trace_writeback_write_inode_start)(void *, struct inode *, struct writeback_control *); - -typedef void (*btf_trace_writeback_write_inode)(void *, struct inode *, struct writeback_control *); - -typedef void (*btf_trace_writeback_queue)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_exec)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_start)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_written)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_wait)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_pages_written)(void *, long int); - -typedef void (*btf_trace_writeback_wake_background)(void *, struct bdi_writeback *); - -typedef void (*btf_trace_writeback_bdi_register)(void *, struct backing_dev_info *); - -typedef void (*btf_trace_wbc_writepage)(void *, struct writeback_control *, struct backing_dev_info *); - -typedef void (*btf_trace_writeback_queue_io)(void *, struct bdi_writeback *, struct wb_writeback_work *, long unsigned int, int); - -typedef void (*btf_trace_global_dirty_state)(void *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_bdi_dirty_ratelimit)(void *, struct bdi_writeback *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_balance_dirty_pages)(void *, struct bdi_writeback *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long int, long unsigned int); - -typedef void (*btf_trace_writeback_sb_inodes_requeue)(void *, struct inode *); - -typedef void (*btf_trace_writeback_congestion_wait)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_writeback_wait_iff_congested)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_writeback_single_inode_start)(void *, struct inode *, struct writeback_control *, long unsigned int); - -typedef void (*btf_trace_writeback_single_inode)(void *, struct inode *, struct writeback_control *, long unsigned int); - -typedef void (*btf_trace_writeback_lazytime)(void *, struct inode *); - -typedef void (*btf_trace_writeback_lazytime_iput)(void *, struct inode *); - -typedef void (*btf_trace_writeback_dirty_inode_enqueue)(void *, struct inode *); - -typedef void (*btf_trace_sb_mark_inode_writeback)(void *, struct inode *); - -typedef void (*btf_trace_sb_clear_inode_writeback)(void *, struct inode *); - -struct inode_switch_wbs_context { - struct inode *inode; - struct bdi_writeback *new_wb; - struct callback_head callback_head; - struct work_struct work; -}; - -struct splice_desc { - size_t total_len; - unsigned int len; - unsigned int flags; - union { - void *userptr; - struct file *file; - void *data; - } u; - loff_t pos; - loff_t *opos; - size_t num_spliced; - bool need_wakeup; -}; - -typedef int splice_actor(struct pipe_inode_info *, struct pipe_buffer *, struct splice_desc *); - -typedef int splice_direct_actor(struct pipe_inode_info *, struct splice_desc *); - -struct old_utimbuf32 { - old_time32_t actime; - old_time32_t modtime; -}; - -typedef int __kernel_daddr_t; - -struct ustat { - __kernel_daddr_t f_tfree; - __kernel_ino_t f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -typedef s32 compat_daddr_t; - -typedef __kernel_fsid_t compat_fsid_t; - -struct compat_statfs { - int f_type; - int f_bsize; - int f_blocks; - int f_bfree; - int f_bavail; - int f_files; - int f_ffree; - compat_fsid_t f_fsid; - int f_namelen; - int f_frsize; - int f_flags; - int f_spare[4]; -}; - -struct compat_ustat { - compat_daddr_t f_tfree; - compat_ino_t f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -struct statfs { - __kernel_long_t f_type; - __kernel_long_t f_bsize; - __kernel_long_t f_blocks; - __kernel_long_t f_bfree; - __kernel_long_t f_bavail; - __kernel_long_t f_files; - __kernel_long_t f_ffree; - __kernel_fsid_t f_fsid; - __kernel_long_t f_namelen; - __kernel_long_t f_frsize; - __kernel_long_t f_flags; - __kernel_long_t f_spare[4]; -}; - -struct statfs64 { - __kernel_long_t f_type; - __kernel_long_t f_bsize; - __u64 f_blocks; - __u64 f_bfree; - __u64 f_bavail; - __u64 f_files; - __u64 f_ffree; - __kernel_fsid_t f_fsid; - __kernel_long_t f_namelen; - __kernel_long_t f_frsize; - __kernel_long_t f_flags; - __kernel_long_t f_spare[4]; -}; - -struct compat_statfs64___2 { - __u32 f_type; - __u32 f_bsize; - __u64 f_blocks; - __u64 f_bfree; - __u64 f_bavail; - __u64 f_files; - __u64 f_ffree; - __kernel_fsid_t f_fsid; - __u32 f_namelen; - __u32 f_frsize; - __u32 f_flags; - __u32 f_spare[4]; -} __attribute__((packed)); - -typedef struct ns_common *ns_get_path_helper_t(void *); - -struct ns_get_path_task_args { - const struct proc_ns_operations *ns_ops; - struct task_struct *task; -}; - -enum legacy_fs_param { - LEGACY_FS_UNSET_PARAMS = 0, - LEGACY_FS_MONOLITHIC_PARAMS = 1, - LEGACY_FS_INDIVIDUAL_PARAMS = 2, -}; - -struct legacy_fs_context { - char *legacy_data; - size_t data_size; - enum legacy_fs_param param_type; -}; - -enum fsconfig_command { - FSCONFIG_SET_FLAG = 0, - FSCONFIG_SET_STRING = 1, - FSCONFIG_SET_BINARY = 2, - FSCONFIG_SET_PATH = 3, - FSCONFIG_SET_PATH_EMPTY = 4, - FSCONFIG_SET_FD = 5, - FSCONFIG_CMD_CREATE = 6, - FSCONFIG_CMD_RECONFIGURE = 7, -}; - -struct dax_device; - -struct iomap_page_ops; - -struct iomap___2 { - u64 addr; - loff_t offset; - u64 length; - u16 type; - u16 flags; - struct block_device *bdev; - struct dax_device *dax_dev; - void *inline_data; - void *private; - const struct iomap_page_ops *page_ops; -}; - -struct iomap_page_ops { - int (*page_prepare)(struct inode *, loff_t, unsigned int, struct iomap___2 *); - void (*page_done)(struct inode *, loff_t, unsigned int, struct page *, struct iomap___2 *); -}; - -struct decrypt_bh_ctx { - struct work_struct work; - struct buffer_head *bh; -}; - -struct bh_lru { - struct buffer_head *bhs[16]; -}; - -struct bh_accounting { - int nr; - int ratelimit; -}; - -enum { - DISK_EVENT_MEDIA_CHANGE = 1, - DISK_EVENT_EJECT_REQUEST = 2, -}; - -struct blk_integrity_profile; - -struct blk_integrity { - const struct blk_integrity_profile *profile; - unsigned char flags; - unsigned char tuple_size; - unsigned char interval_exp; - unsigned char tag_size; -}; - -enum { - BIOSET_NEED_BVECS = 1, - BIOSET_NEED_RESCUER = 2, -}; - -struct bdev_inode { - struct block_device bdev; - struct inode vfs_inode; -}; - -struct blkdev_dio { - union { - struct kiocb *iocb; - struct task_struct *waiter; - }; - size_t size; - atomic_t ref; - bool multi_bio: 1; - bool should_dirty: 1; - bool is_sync: 1; - struct bio bio; -}; - -struct bd_holder_disk { - struct list_head list; - struct gendisk *disk; - int refcnt; -}; - -typedef int dio_iodone_t(struct kiocb *, loff_t, ssize_t, void *); - -typedef void dio_submit_t(struct bio *, struct inode *, loff_t); - -enum { - DIO_LOCKING = 1, - DIO_SKIP_HOLES = 2, -}; - -struct dio_submit { - struct bio *bio; - unsigned int blkbits; - unsigned int blkfactor; - unsigned int start_zero_done; - int pages_in_io; - sector_t block_in_file; - unsigned int blocks_available; - int reap_counter; - sector_t final_block_in_request; - int boundary; - get_block_t *get_block; - dio_submit_t *submit_io; - loff_t logical_offset_in_bio; - sector_t final_block_in_bio; - sector_t next_block_for_io; - struct page *cur_page; - unsigned int cur_page_offset; - unsigned int cur_page_len; - sector_t cur_page_block; - loff_t cur_page_fs_offset; - struct iov_iter *iter; - unsigned int head; - unsigned int tail; - size_t from; - size_t to; -}; - -struct dio { - int flags; - int op; - int op_flags; - blk_qc_t bio_cookie; - struct gendisk *bio_disk; - struct inode *inode; - loff_t i_size; - dio_iodone_t *end_io; - void *private; - spinlock_t bio_lock; - int page_errors; - int is_async; - bool defer_completion; - bool should_dirty; - int io_error; - long unsigned int refcount; - struct bio *bio_list; - struct task_struct *waiter; - struct kiocb *iocb; - ssize_t result; - union { - struct page *pages[64]; - struct work_struct complete_work; - }; - long: 64; -}; - -struct bvec_iter_all { - struct bio_vec bv; - int idx; - unsigned int done; -}; - -struct mpage_readpage_args { - struct bio *bio; - struct page *page; - unsigned int nr_pages; - bool is_readahead; - sector_t last_block_in_bio; - struct buffer_head map_bh; - long unsigned int first_logical_block; - get_block_t *get_block; -}; - -struct mpage_data { - struct bio *bio; - sector_t last_block_in_bio; - get_block_t *get_block; - unsigned int use_writepage; -}; - -typedef u32 nlink_t; - -typedef int (*proc_write_t)(struct file *, char *, size_t); - -struct proc_dir_entry { - atomic_t in_use; - refcount_t refcnt; - struct list_head pde_openers; - spinlock_t pde_unload_lock; - struct completion *pde_unload_completion; - const struct inode_operations *proc_iops; - union { - const struct proc_ops *proc_ops; - const struct file_operations *proc_dir_ops; - }; - const struct dentry_operations *proc_dops; - union { - const struct seq_operations *seq_ops; - int (*single_show)(struct seq_file *, void *); - }; - proc_write_t write; - void *data; - unsigned int state_size; - unsigned int low_ino; - nlink_t nlink; - kuid_t uid; - kgid_t gid; - loff_t size; - struct proc_dir_entry *parent; - struct rb_root subdir; - struct rb_node subdir_node; - char *name; - umode_t mode; - u8 flags; - u8 namelen; - char inline_name[0]; -}; - -union proc_op { - int (*proc_get_link)(struct dentry *, struct path *); - int (*proc_show)(struct seq_file *, struct pid_namespace *, struct pid *, struct task_struct *); - const char *lsm; -}; - -struct proc_inode { - struct pid *pid; - unsigned int fd; - union proc_op op; - struct proc_dir_entry *pde; - struct ctl_table_header *sysctl; - struct ctl_table *sysctl_entry; - struct hlist_node sibling_inodes; - const struct proc_ns_operations *ns_ops; - struct inode vfs_inode; -}; - -struct proc_fs_opts { - int flag; - const char *str; -}; - -struct file_handle { - __u32 handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -struct inotify_inode_mark { - struct fsnotify_mark fsn_mark; - int wd; -}; - -struct dnotify_struct { - struct dnotify_struct *dn_next; - __u32 dn_mask; - int dn_fd; - struct file *dn_filp; - fl_owner_t dn_owner; -}; - -struct dnotify_mark { - struct fsnotify_mark fsn_mark; - struct dnotify_struct *dn; -}; - -struct inotify_event_info { - struct fsnotify_event fse; - u32 mask; - int wd; - u32 sync_cookie; - int name_len; - char name[0]; -}; - -struct inotify_event { - __s32 wd; - __u32 mask; - __u32 cookie; - __u32 len; - char name[0]; -}; - -enum { - FAN_EVENT_INIT = 0, - FAN_EVENT_REPORTED = 1, - FAN_EVENT_ANSWERED = 2, - FAN_EVENT_CANCELED = 3, -}; - -struct fanotify_fh { - u8 type; - u8 len; - u8 flags; - u8 pad; - unsigned char buf[0]; -}; - -struct fanotify_info { - u8 dir_fh_totlen; - u8 file_fh_totlen; - u8 name_len; - u8 pad; - unsigned char buf[0]; -}; - -enum fanotify_event_type { - FANOTIFY_EVENT_TYPE_FID = 0, - FANOTIFY_EVENT_TYPE_FID_NAME = 1, - FANOTIFY_EVENT_TYPE_PATH = 2, - FANOTIFY_EVENT_TYPE_PATH_PERM = 3, - FANOTIFY_EVENT_TYPE_OVERFLOW = 4, -}; - -struct fanotify_event { - struct fsnotify_event fse; - u32 mask; - enum fanotify_event_type type; - struct pid *pid; -}; - -struct fanotify_fid_event { - struct fanotify_event fae; - __kernel_fsid_t fsid; - struct fanotify_fh object_fh; - unsigned char _inline_fh_buf[12]; -}; - -struct fanotify_name_event { - struct fanotify_event fae; - __kernel_fsid_t fsid; - struct fanotify_info info; -}; - -struct fanotify_path_event { - struct fanotify_event fae; - struct path path; -}; - -struct fanotify_perm_event { - struct fanotify_event fae; - struct path path; - short unsigned int response; - short unsigned int state; - int fd; -}; - -struct fanotify_event_metadata { - __u32 event_len; - __u8 vers; - __u8 reserved; - __u16 metadata_len; - __u64 mask; - __s32 fd; - __s32 pid; -}; - -struct fanotify_event_info_header { - __u8 info_type; - __u8 pad; - __u16 len; -}; - -struct fanotify_event_info_fid { - struct fanotify_event_info_header hdr; - __kernel_fsid_t fsid; - unsigned char handle[0]; -}; - -struct fanotify_response { - __s32 fd; - __u32 response; -}; - -struct epoll_event { - __poll_t events; - __u64 data; -}; - -struct wakeup_source { - const char *name; - int id; - struct list_head entry; - spinlock_t lock; - struct wake_irq *wakeirq; - struct timer_list timer; - long unsigned int timer_expires; - ktime_t total_time; - ktime_t max_time; - ktime_t last_time; - ktime_t start_prevent_time; - ktime_t prevent_sleep_time; - long unsigned int event_count; - long unsigned int active_count; - long unsigned int relax_count; - long unsigned int expire_count; - long unsigned int wakeup_count; - struct device *dev; - bool active: 1; - bool autosleep_enabled: 1; -}; - -struct epoll_filefd { - struct file *file; - int fd; -} __attribute__((packed)); - -struct nested_call_node { - struct list_head llink; - void *cookie; - void *ctx; -}; - -struct nested_calls { - struct list_head tasks_call_list; - spinlock_t lock; -}; - -struct eventpoll; - -struct epitem { - union { - struct rb_node rbn; - struct callback_head rcu; - }; - struct list_head rdllink; - struct epitem *next; - struct epoll_filefd ffd; - int nwait; - struct list_head pwqlist; - struct eventpoll *ep; - struct list_head fllink; - struct wakeup_source *ws; - struct epoll_event event; -}; - -struct eventpoll { - struct mutex mtx; - wait_queue_head_t wq; - wait_queue_head_t poll_wait; - struct list_head rdllist; - rwlock_t lock; - struct rb_root_cached rbr; - struct epitem *ovflist; - struct wakeup_source *ws; - struct user_struct *user; - struct file *file; - u64 gen; - unsigned int napi_id; -}; - -struct eppoll_entry { - struct list_head llink; - struct epitem *base; - wait_queue_entry_t wait; - wait_queue_head_t *whead; -}; - -struct ep_pqueue { - poll_table pt; - struct epitem *epi; -}; - -struct ep_send_events_data { - int maxevents; - struct epoll_event *events; - int res; -}; - -struct signalfd_siginfo { - __u32 ssi_signo; - __s32 ssi_errno; - __s32 ssi_code; - __u32 ssi_pid; - __u32 ssi_uid; - __s32 ssi_fd; - __u32 ssi_tid; - __u32 ssi_band; - __u32 ssi_overrun; - __u32 ssi_trapno; - __s32 ssi_status; - __s32 ssi_int; - __u64 ssi_ptr; - __u64 ssi_utime; - __u64 ssi_stime; - __u64 ssi_addr; - __u16 ssi_addr_lsb; - __u16 __pad2; - __s32 ssi_syscall; - __u64 ssi_call_addr; - __u32 ssi_arch; - __u8 __pad[28]; -}; - -struct signalfd_ctx { - sigset_t sigmask; -}; - -struct timerfd_ctx { - union { - struct hrtimer tmr; - struct alarm alarm; - } t; - ktime_t tintv; - ktime_t moffs; - wait_queue_head_t wqh; - u64 ticks; - int clockid; - short unsigned int expired; - short unsigned int settime_flags; - struct callback_head rcu; - struct list_head clist; - spinlock_t cancel_lock; - bool might_cancel; -}; - -struct eventfd_ctx___2 { - struct kref kref; - wait_queue_head_t wqh; - __u64 count; - unsigned int flags; - int id; -}; - -typedef u32 compat_aio_context_t; - -struct kioctx; - -struct kioctx_table { - struct callback_head rcu; - unsigned int nr; - struct kioctx *table[0]; -}; - -typedef __kernel_ulong_t aio_context_t; - -enum { - IOCB_CMD_PREAD = 0, - IOCB_CMD_PWRITE = 1, - IOCB_CMD_FSYNC = 2, - IOCB_CMD_FDSYNC = 3, - IOCB_CMD_POLL = 5, - IOCB_CMD_NOOP = 6, - IOCB_CMD_PREADV = 7, - IOCB_CMD_PWRITEV = 8, -}; - -struct io_event { - __u64 data; - __u64 obj; - __s64 res; - __s64 res2; -}; - -struct iocb { - __u64 aio_data; - __u32 aio_key; - __kernel_rwf_t aio_rw_flags; - __u16 aio_lio_opcode; - __s16 aio_reqprio; - __u32 aio_fildes; - __u64 aio_buf; - __u64 aio_nbytes; - __s64 aio_offset; - __u64 aio_reserved2; - __u32 aio_flags; - __u32 aio_resfd; -}; - -typedef int kiocb_cancel_fn(struct kiocb *); - -struct aio_ring { - unsigned int id; - unsigned int nr; - unsigned int head; - unsigned int tail; - unsigned int magic; - unsigned int compat_features; - unsigned int incompat_features; - unsigned int header_length; - struct io_event io_events[0]; -}; - -struct kioctx_cpu; - -struct ctx_rq_wait; - -struct kioctx { - struct percpu_ref users; - atomic_t dead; - struct percpu_ref reqs; - long unsigned int user_id; - struct kioctx_cpu *cpu; - unsigned int req_batch; - unsigned int max_reqs; - unsigned int nr_events; - long unsigned int mmap_base; - long unsigned int mmap_size; - struct page **ring_pages; - long int nr_pages; - struct rcu_work free_rwork; - struct ctx_rq_wait *rq_wait; - long: 64; - long: 64; - long: 64; - struct { - atomic_t reqs_available; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - spinlock_t ctx_lock; - struct list_head active_reqs; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - struct mutex ring_lock; - wait_queue_head_t wait; - long: 64; - }; - struct { - unsigned int tail; - unsigned int completed_events; - spinlock_t completion_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct page *internal_pages[8]; - struct file *aio_ring_file; - unsigned int id; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct kioctx_cpu { - unsigned int reqs_available; -}; - -struct ctx_rq_wait { - struct completion comp; - atomic_t count; -}; - -struct fsync_iocb { - struct file *file; - struct work_struct work; - bool datasync; - struct cred *creds; -}; - -struct poll_iocb { - struct file *file; - struct wait_queue_head *head; - __poll_t events; - bool cancelled; - bool work_scheduled; - bool work_need_resched; - struct wait_queue_entry wait; - struct work_struct work; -}; - -struct aio_kiocb { - union { - struct file *ki_filp; - struct kiocb rw; - struct fsync_iocb fsync; - struct poll_iocb poll; - }; - struct kioctx *ki_ctx; - kiocb_cancel_fn *ki_cancel; - struct io_event ki_res; - struct list_head ki_list; - refcount_t ki_refcnt; - struct eventfd_ctx *ki_eventfd; -}; - -struct aio_poll_table { - struct poll_table_struct pt; - struct aio_kiocb *iocb; - bool queued; - int error; -}; - -struct __aio_sigset { - const sigset_t *sigmask; - size_t sigsetsize; -}; - -struct __compat_aio_sigset { - compat_uptr_t sigmask; - compat_size_t sigsetsize; -}; - -typedef s32 compat_ssize_t; - -struct xa_limit { - u32 max; - u32 min; -}; - -enum { - PERCPU_REF_INIT_ATOMIC = 1, - PERCPU_REF_INIT_DEAD = 2, - PERCPU_REF_ALLOW_REINIT = 4, -}; - -struct user_msghdr { - void *msg_name; - int msg_namelen; - struct iovec *msg_iov; - __kernel_size_t msg_iovlen; - void *msg_control; - __kernel_size_t msg_controllen; - unsigned int msg_flags; -}; - -struct compat_msghdr { - compat_uptr_t msg_name; - compat_int_t msg_namelen; - compat_uptr_t msg_iov; - compat_size_t msg_iovlen; - compat_uptr_t msg_control; - compat_size_t msg_controllen; - compat_uint_t msg_flags; -}; - -struct scm_fp_list { - short int count; - short int max; - struct user_struct *user; - struct file *fp[253]; -}; - -struct unix_skb_parms { - struct pid *pid; - kuid_t uid; - kgid_t gid; - struct scm_fp_list *fp; - u32 secid; - u32 consumed; -}; - -struct trace_event_raw_io_uring_create { - struct trace_entry ent; - int fd; - void *ctx; - u32 sq_entries; - u32 cq_entries; - u32 flags; - char __data[0]; -}; - -struct trace_event_raw_io_uring_register { - struct trace_entry ent; - void *ctx; - unsigned int opcode; - unsigned int nr_files; - unsigned int nr_bufs; - bool eventfd; - long int ret; - char __data[0]; -}; - -struct trace_event_raw_io_uring_file_get { - struct trace_entry ent; - void *ctx; - int fd; - char __data[0]; -}; - -struct io_wq_work; - -struct trace_event_raw_io_uring_queue_async_work { - struct trace_entry ent; - void *ctx; - int rw; - void *req; - struct io_wq_work *work; - unsigned int flags; - char __data[0]; -}; - -struct io_wq_work_node { - struct io_wq_work_node *next; -}; - -struct io_wq_work { - struct io_wq_work_node list; - struct io_identity *identity; - unsigned int flags; -}; - -struct trace_event_raw_io_uring_defer { - struct trace_entry ent; - void *ctx; - void *req; - long long unsigned int data; - char __data[0]; -}; - -struct trace_event_raw_io_uring_link { - struct trace_entry ent; - void *ctx; - void *req; - void *target_req; - char __data[0]; -}; - -struct trace_event_raw_io_uring_cqring_wait { - struct trace_entry ent; - void *ctx; - int min_events; - char __data[0]; -}; - -struct trace_event_raw_io_uring_fail_link { - struct trace_entry ent; - void *req; - void *link; - char __data[0]; -}; - -struct trace_event_raw_io_uring_complete { - struct trace_entry ent; - void *ctx; - u64 user_data; - long int res; - char __data[0]; -}; - -struct trace_event_raw_io_uring_submit_sqe { - struct trace_entry ent; - void *ctx; - u8 opcode; - u64 user_data; - bool force_nonblock; - bool sq_thread; - char __data[0]; -}; - -struct trace_event_raw_io_uring_poll_arm { - struct trace_entry ent; - void *ctx; - u8 opcode; - u64 user_data; - int mask; - int events; - char __data[0]; -}; - -struct trace_event_raw_io_uring_poll_wake { - struct trace_entry ent; - void *ctx; - u8 opcode; - u64 user_data; - int mask; - char __data[0]; -}; - -struct trace_event_raw_io_uring_task_add { - struct trace_entry ent; - void *ctx; - u8 opcode; - u64 user_data; - int mask; - char __data[0]; -}; - -struct trace_event_raw_io_uring_task_run { - struct trace_entry ent; - void *ctx; - u8 opcode; - u64 user_data; - char __data[0]; -}; - -struct trace_event_data_offsets_io_uring_create {}; - -struct trace_event_data_offsets_io_uring_register {}; - -struct trace_event_data_offsets_io_uring_file_get {}; - -struct trace_event_data_offsets_io_uring_queue_async_work {}; - -struct trace_event_data_offsets_io_uring_defer {}; - -struct trace_event_data_offsets_io_uring_link {}; - -struct trace_event_data_offsets_io_uring_cqring_wait {}; - -struct trace_event_data_offsets_io_uring_fail_link {}; - -struct trace_event_data_offsets_io_uring_complete {}; - -struct trace_event_data_offsets_io_uring_submit_sqe {}; - -struct trace_event_data_offsets_io_uring_poll_arm {}; - -struct trace_event_data_offsets_io_uring_poll_wake {}; - -struct trace_event_data_offsets_io_uring_task_add {}; - -struct trace_event_data_offsets_io_uring_task_run {}; - -typedef void (*btf_trace_io_uring_create)(void *, int, void *, u32, u32, u32); - -typedef void (*btf_trace_io_uring_register)(void *, void *, unsigned int, unsigned int, unsigned int, bool, long int); - -typedef void (*btf_trace_io_uring_file_get)(void *, void *, int); - -typedef void (*btf_trace_io_uring_queue_async_work)(void *, void *, int, void *, struct io_wq_work *, unsigned int); - -typedef void (*btf_trace_io_uring_defer)(void *, void *, void *, long long unsigned int); - -typedef void (*btf_trace_io_uring_link)(void *, void *, void *, void *); - -typedef void (*btf_trace_io_uring_cqring_wait)(void *, void *, int); - -typedef void (*btf_trace_io_uring_fail_link)(void *, void *, void *); - -typedef void (*btf_trace_io_uring_complete)(void *, void *, u64, long int); - -typedef void (*btf_trace_io_uring_submit_sqe)(void *, void *, u8, u64, bool, bool); - -typedef void (*btf_trace_io_uring_poll_arm)(void *, void *, u8, u64, int, int); - -typedef void (*btf_trace_io_uring_poll_wake)(void *, void *, u8, u64, int); - -typedef void (*btf_trace_io_uring_task_add)(void *, void *, u8, u64, int); - -typedef void (*btf_trace_io_uring_task_run)(void *, void *, u8, u64); - -struct io_uring_sqe { - __u8 opcode; - __u8 flags; - __u16 ioprio; - __s32 fd; - union { - __u64 off; - __u64 addr2; - }; - union { - __u64 addr; - __u64 splice_off_in; - }; - __u32 len; - union { - __kernel_rwf_t rw_flags; - __u32 fsync_flags; - __u16 poll_events; - __u32 poll32_events; - __u32 sync_range_flags; - __u32 msg_flags; - __u32 timeout_flags; - __u32 accept_flags; - __u32 cancel_flags; - __u32 open_flags; - __u32 statx_flags; - __u32 fadvise_advice; - __u32 splice_flags; - }; - __u64 user_data; - union { - struct { - union { - __u16 buf_index; - __u16 buf_group; - }; - __u16 personality; - __s32 splice_fd_in; - }; - __u64 __pad2[3]; - }; -}; - -enum { - IOSQE_FIXED_FILE_BIT = 0, - IOSQE_IO_DRAIN_BIT = 1, - IOSQE_IO_LINK_BIT = 2, - IOSQE_IO_HARDLINK_BIT = 3, - IOSQE_ASYNC_BIT = 4, - IOSQE_BUFFER_SELECT_BIT = 5, -}; - -enum { - IORING_OP_NOP = 0, - IORING_OP_READV = 1, - IORING_OP_WRITEV = 2, - IORING_OP_FSYNC = 3, - IORING_OP_READ_FIXED = 4, - IORING_OP_WRITE_FIXED = 5, - IORING_OP_POLL_ADD = 6, - IORING_OP_POLL_REMOVE = 7, - IORING_OP_SYNC_FILE_RANGE = 8, - IORING_OP_SENDMSG = 9, - IORING_OP_RECVMSG = 10, - IORING_OP_TIMEOUT = 11, - IORING_OP_TIMEOUT_REMOVE = 12, - IORING_OP_ACCEPT = 13, - IORING_OP_ASYNC_CANCEL = 14, - IORING_OP_LINK_TIMEOUT = 15, - IORING_OP_CONNECT = 16, - IORING_OP_FALLOCATE = 17, - IORING_OP_OPENAT = 18, - IORING_OP_CLOSE = 19, - IORING_OP_FILES_UPDATE = 20, - IORING_OP_STATX = 21, - IORING_OP_READ = 22, - IORING_OP_WRITE = 23, - IORING_OP_FADVISE = 24, - IORING_OP_MADVISE = 25, - IORING_OP_SEND = 26, - IORING_OP_RECV = 27, - IORING_OP_OPENAT2 = 28, - IORING_OP_EPOLL_CTL = 29, - IORING_OP_SPLICE = 30, - IORING_OP_PROVIDE_BUFFERS = 31, - IORING_OP_REMOVE_BUFFERS = 32, - IORING_OP_TEE = 33, - IORING_OP_LAST = 34, -}; - -struct io_uring_cqe { - __u64 user_data; - __s32 res; - __u32 flags; -}; - -enum { - IORING_CQE_BUFFER_SHIFT = 16, -}; - -struct io_sqring_offsets { - __u32 head; - __u32 tail; - __u32 ring_mask; - __u32 ring_entries; - __u32 flags; - __u32 dropped; - __u32 array; - __u32 resv1; - __u64 resv2; -}; - -struct io_cqring_offsets { - __u32 head; - __u32 tail; - __u32 ring_mask; - __u32 ring_entries; - __u32 overflow; - __u32 cqes; - __u32 flags; - __u32 resv1; - __u64 resv2; -}; - -struct io_uring_params { - __u32 sq_entries; - __u32 cq_entries; - __u32 flags; - __u32 sq_thread_cpu; - __u32 sq_thread_idle; - __u32 features; - __u32 wq_fd; - __u32 resv[3]; - struct io_sqring_offsets sq_off; - struct io_cqring_offsets cq_off; -}; - -enum { - IORING_REGISTER_BUFFERS = 0, - IORING_UNREGISTER_BUFFERS = 1, - IORING_REGISTER_FILES = 2, - IORING_UNREGISTER_FILES = 3, - IORING_REGISTER_EVENTFD = 4, - IORING_UNREGISTER_EVENTFD = 5, - IORING_REGISTER_FILES_UPDATE = 6, - IORING_REGISTER_EVENTFD_ASYNC = 7, - IORING_REGISTER_PROBE = 8, - IORING_REGISTER_PERSONALITY = 9, - IORING_UNREGISTER_PERSONALITY = 10, - IORING_REGISTER_RESTRICTIONS = 11, - IORING_REGISTER_ENABLE_RINGS = 12, - IORING_REGISTER_LAST = 13, -}; - -struct io_uring_files_update { - __u32 offset; - __u32 resv; - __u64 fds; -}; - -struct io_uring_probe_op { - __u8 op; - __u8 resv; - __u16 flags; - __u32 resv2; -}; - -struct io_uring_probe { - __u8 last_op; - __u8 ops_len; - __u16 resv; - __u32 resv2[3]; - struct io_uring_probe_op ops[0]; -}; - -struct io_uring_restriction { - __u16 opcode; - union { - __u8 register_op; - __u8 sqe_op; - __u8 sqe_flags; - }; - __u8 resv; - __u32 resv2[3]; -}; - -enum { - IORING_RESTRICTION_REGISTER_OP = 0, - IORING_RESTRICTION_SQE_OP = 1, - IORING_RESTRICTION_SQE_FLAGS_ALLOWED = 2, - IORING_RESTRICTION_SQE_FLAGS_REQUIRED = 3, - IORING_RESTRICTION_LAST = 4, -}; - -enum { - IO_WQ_WORK_CANCEL = 1, - IO_WQ_WORK_HASHED = 2, - IO_WQ_WORK_UNBOUND = 4, - IO_WQ_WORK_NO_CANCEL = 8, - IO_WQ_WORK_CONCURRENT = 16, - IO_WQ_WORK_FILES = 32, - IO_WQ_WORK_FS = 64, - IO_WQ_WORK_MM = 128, - IO_WQ_WORK_CREDS = 256, - IO_WQ_WORK_BLKCG = 512, - IO_WQ_WORK_FSIZE = 1024, - IO_WQ_HASH_SHIFT = 24, -}; - -enum io_wq_cancel { - IO_WQ_CANCEL_OK = 0, - IO_WQ_CANCEL_RUNNING = 1, - IO_WQ_CANCEL_NOTFOUND = 2, -}; - -typedef void free_work_fn(struct io_wq_work *); - -typedef struct io_wq_work *io_wq_work_fn(struct io_wq_work *); - -struct io_wq_data { - struct user_struct *user; - io_wq_work_fn *do_work; - free_work_fn *free_work; -}; - -struct io_uring { - u32 head; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 tail; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct io_rings { - struct io_uring sq; - struct io_uring cq; - u32 sq_ring_mask; - u32 cq_ring_mask; - u32 sq_ring_entries; - u32 cq_ring_entries; - u32 sq_dropped; - u32 sq_flags; - u32 cq_flags; - u32 cq_overflow; - long: 64; - long: 64; - long: 64; - long: 64; - struct io_uring_cqe cqes[0]; -}; - -struct io_mapped_ubuf { - u64 ubuf; - size_t len; - struct bio_vec *bvec; - unsigned int nr_bvecs; - long unsigned int acct_pages; -}; - -struct fixed_file_table { - struct file **files; -}; - -struct fixed_file_data; - -struct fixed_file_ref_node { - struct percpu_ref refs; - struct list_head node; - struct list_head file_list; - struct fixed_file_data *file_data; - struct llist_node llist; - bool done; -}; - -struct io_ring_ctx; - -struct fixed_file_data { - struct fixed_file_table *table; - struct io_ring_ctx *ctx; - struct fixed_file_ref_node *node; - struct percpu_ref refs; - struct completion done; - struct list_head ref_list; - spinlock_t lock; -}; - -struct io_wq; - -struct io_restriction { - long unsigned int register_op[1]; - long unsigned int sqe_op[1]; - u8 sqe_flags_allowed; - u8 sqe_flags_required; - bool registered; -}; - -struct io_sq_data; - -struct io_kiocb; - -struct io_ring_ctx { - struct { - struct percpu_ref refs; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - unsigned int flags; - unsigned int compat: 1; - unsigned int limit_mem: 1; - unsigned int cq_overflow_flushed: 1; - unsigned int drain_next: 1; - unsigned int eventfd_async: 1; - unsigned int restricted: 1; - unsigned int sqo_dead: 1; - u32 *sq_array; - unsigned int cached_sq_head; - unsigned int sq_entries; - unsigned int sq_mask; - unsigned int sq_thread_idle; - unsigned int cached_sq_dropped; - unsigned int cached_cq_overflow; - long unsigned int sq_check_overflow; - struct list_head defer_list; - struct list_head timeout_list; - struct list_head cq_overflow_list; - struct io_uring_sqe *sq_sqes; - long: 64; - long: 64; - long: 64; - }; - struct io_rings *rings; - struct io_wq *io_wq; - struct task_struct *sqo_task; - struct mm_struct *mm_account; - struct cgroup_subsys_state *sqo_blkcg_css; - struct io_sq_data *sq_data; - struct wait_queue_head sqo_sq_wait; - struct wait_queue_entry sqo_wait_entry; - struct list_head sqd_list; - struct fixed_file_data *file_data; - unsigned int nr_user_files; - unsigned int nr_user_bufs; - struct io_mapped_ubuf *user_bufs; - struct user_struct *user; - const struct cred *creds; - kuid_t loginuid; - unsigned int sessionid; - struct completion ref_comp; - struct completion sq_thread_comp; - struct io_kiocb *fallback_req; - struct socket *ring_sock; - struct xarray io_buffers; - struct xarray personalities; - u32 pers_next; - long: 32; - long: 64; - long: 64; - long: 64; - struct { - unsigned int cached_cq_tail; - unsigned int cq_entries; - unsigned int cq_mask; - atomic_t cq_timeouts; - unsigned int cq_last_tm_flush; - long unsigned int cq_check_overflow; - struct wait_queue_head cq_wait; - struct fasync_struct *cq_fasync; - struct eventfd_ctx *cq_ev_fd; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - struct mutex uring_lock; - wait_queue_head_t wait; - long: 64; - }; - struct { - spinlock_t completion_lock; - struct list_head iopoll_list; - struct hlist_head *cancel_hash; - unsigned int cancel_hash_bits; - bool poll_multi_file; - spinlock_t inflight_lock; - struct list_head inflight_list; - }; - struct delayed_work file_put_work; - struct llist_head file_put_llist; - struct work_struct exit_work; - struct io_restriction restrictions; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct io_buffer { - struct list_head list; - __u64 addr; - __u32 len; - __u16 bid; -}; - -struct io_sq_data { - refcount_t refs; - struct mutex lock; - struct list_head ctx_list; - struct list_head ctx_new_list; - struct mutex ctx_lock; - struct task_struct *thread; - struct wait_queue_head wait; -}; - -struct io_rw { - struct kiocb kiocb; - u64 addr; - u64 len; -}; - -struct io_poll_iocb { - struct file *file; - union { - struct wait_queue_head *head; - u64 addr; - }; - __poll_t events; - bool done; - bool canceled; - struct wait_queue_entry wait; -}; - -struct io_accept { - struct file *file; - struct sockaddr *addr; - int *addr_len; - int flags; - long unsigned int nofile; -}; - -struct io_sync { - struct file *file; - loff_t len; - loff_t off; - int flags; - int mode; -}; - -struct io_cancel { - struct file *file; - u64 addr; -}; - -struct io_timeout { - struct file *file; - u32 off; - u32 target_seq; - struct list_head list; -}; - -struct io_timeout_rem { - struct file *file; - u64 addr; -}; - -struct io_connect { - struct file *file; - struct sockaddr *addr; - int addr_len; -}; - -struct io_sr_msg { - struct file *file; - union { - struct user_msghdr *umsg; - void *buf; - }; - int msg_flags; - int bgid; - size_t len; - struct io_buffer *kbuf; -}; - -struct io_open { - struct file *file; - int dfd; - bool ignore_nonblock; - struct filename *filename; - struct open_how how; - long unsigned int nofile; -}; - -struct io_close { - struct file *file; - struct file *put_file; - int fd; -}; - -struct io_files_update { - struct file *file; - u64 arg; - u32 nr_args; - u32 offset; -}; - -struct io_fadvise { - struct file *file; - u64 offset; - u32 len; - u32 advice; -}; - -struct io_madvise { - struct file *file; - u64 addr; - u32 len; - u32 advice; -}; - -struct io_epoll { - struct file *file; - int epfd; - int op; - int fd; - struct epoll_event event; -}; - -struct io_splice { - struct file *file_out; - struct file *file_in; - loff_t off_out; - loff_t off_in; - u64 len; - unsigned int flags; -}; - -struct io_provide_buf { - struct file *file; - __u64 addr; - __u32 len; - __u32 bgid; - __u16 nbufs; - __u16 bid; -}; - -struct io_statx { - struct file *file; - int dfd; - unsigned int mask; - unsigned int flags; - const char *filename; - struct statx *buffer; -}; - -struct io_completion { - struct file *file; - struct list_head list; - u32 cflags; -}; - -struct async_poll; - -struct io_kiocb { - union { - struct file *file; - struct io_rw rw; - struct io_poll_iocb poll; - struct io_accept accept; - struct io_sync sync; - struct io_cancel cancel; - struct io_timeout timeout; - struct io_timeout_rem timeout_rem; - struct io_connect connect; - struct io_sr_msg sr_msg; - struct io_open open; - struct io_close close; - struct io_files_update files_update; - struct io_fadvise fadvise; - struct io_madvise madvise; - struct io_epoll epoll; - struct io_splice splice; - struct io_provide_buf pbuf; - struct io_statx statx; - struct io_completion compl; - }; - void *async_data; - u8 opcode; - u8 iopoll_completed; - u16 buf_index; - u32 result; - struct io_ring_ctx *ctx; - unsigned int flags; - refcount_t refs; - struct task_struct *task; - u64 user_data; - struct list_head link_list; - struct list_head inflight_entry; - struct percpu_ref *fixed_file_refs; - struct callback_head task_work; - struct hlist_node hash_node; - struct async_poll *apoll; - struct io_wq_work work; -}; - -struct io_timeout_data { - struct io_kiocb *req; - struct hrtimer timer; - struct timespec64 ts; - enum hrtimer_mode mode; -}; - -struct io_async_connect { - struct __kernel_sockaddr_storage address; -}; - -struct io_async_msghdr { - struct iovec fast_iov[8]; - struct iovec *iov; - struct sockaddr *uaddr; - struct msghdr msg; - struct __kernel_sockaddr_storage addr; -}; - -struct io_async_rw { - struct iovec fast_iov[8]; - const struct iovec *free_iovec; - struct iov_iter iter; - size_t bytes_done; - struct wait_page_queue wpq; -}; - -enum { - REQ_F_FIXED_FILE_BIT = 0, - REQ_F_IO_DRAIN_BIT = 1, - REQ_F_LINK_BIT = 2, - REQ_F_HARDLINK_BIT = 3, - REQ_F_FORCE_ASYNC_BIT = 4, - REQ_F_BUFFER_SELECT_BIT = 5, - REQ_F_LINK_HEAD_BIT = 6, - REQ_F_FAIL_LINK_BIT = 7, - REQ_F_INFLIGHT_BIT = 8, - REQ_F_CUR_POS_BIT = 9, - REQ_F_NOWAIT_BIT = 10, - REQ_F_LINK_TIMEOUT_BIT = 11, - REQ_F_ISREG_BIT = 12, - REQ_F_NEED_CLEANUP_BIT = 13, - REQ_F_POLLED_BIT = 14, - REQ_F_BUFFER_SELECTED_BIT = 15, - REQ_F_NO_FILE_TABLE_BIT = 16, - REQ_F_WORK_INITIALIZED_BIT = 17, - REQ_F_LTIMEOUT_ACTIVE_BIT = 18, - __REQ_F_LAST_BIT = 19, -}; - -enum { - REQ_F_FIXED_FILE = 1, - REQ_F_IO_DRAIN = 2, - REQ_F_LINK = 4, - REQ_F_HARDLINK = 8, - REQ_F_FORCE_ASYNC = 16, - REQ_F_BUFFER_SELECT = 32, - REQ_F_LINK_HEAD = 64, - REQ_F_FAIL_LINK = 128, - REQ_F_INFLIGHT = 256, - REQ_F_CUR_POS = 512, - REQ_F_NOWAIT = 1024, - REQ_F_LINK_TIMEOUT = 2048, - REQ_F_ISREG = 4096, - REQ_F_NEED_CLEANUP = 8192, - REQ_F_POLLED = 16384, - REQ_F_BUFFER_SELECTED = 32768, - REQ_F_NO_FILE_TABLE = 65536, - REQ_F_WORK_INITIALIZED = 131072, - REQ_F_LTIMEOUT_ACTIVE = 262144, -}; - -struct async_poll { - struct io_poll_iocb poll; - struct io_poll_iocb *double_poll; -}; - -struct io_defer_entry { - struct list_head list; - struct io_kiocb *req; - u32 seq; -}; - -struct io_comp_state { - unsigned int nr; - struct list_head list; - struct io_ring_ctx *ctx; -}; - -struct io_submit_state { - struct blk_plug plug; - void *reqs[8]; - unsigned int free_reqs; - struct io_comp_state comp; - struct file *file; - unsigned int fd; - unsigned int has_refs; - unsigned int ios_left; -}; - -struct io_op_def { - unsigned int needs_file: 1; - unsigned int needs_file_no_error: 1; - unsigned int hash_reg_file: 1; - unsigned int unbound_nonreg_file: 1; - unsigned int not_supported: 1; - unsigned int pollin: 1; - unsigned int pollout: 1; - unsigned int buffer_select: 1; - unsigned int needs_async_data: 1; - short unsigned int async_size; - unsigned int work_flags; -}; - -enum io_mem_account { - ACCT_LOCKED = 0, - ACCT_PINNED = 1, -}; - -struct req_batch { - void *reqs[8]; - int to_free; - struct task_struct *task; - int task_refs; -}; - -struct io_poll_table { - struct poll_table_struct pt; - struct io_kiocb *req; - int nr_entries; - int error; -}; - -enum sq_ret { - SQT_IDLE = 1, - SQT_SPIN = 2, - SQT_DID_WORK = 4, -}; - -struct io_wait_queue { - struct wait_queue_entry wq; - struct io_ring_ctx *ctx; - unsigned int to_wait; - unsigned int nr_timeouts; -}; - -struct io_file_put { - struct list_head list; - struct file *file; -}; - -struct io_task_cancel { - struct task_struct *task; - struct files_struct *files; -}; - -struct io_identify; - -struct io_wq_work_list { - struct io_wq_work_node *first; - struct io_wq_work_node *last; -}; - -typedef bool work_cancel_fn(struct io_wq_work *, void *); - -enum { - IO_WORKER_F_UP = 1, - IO_WORKER_F_RUNNING = 2, - IO_WORKER_F_FREE = 4, - IO_WORKER_F_FIXED = 8, - IO_WORKER_F_BOUND = 16, -}; - -enum { - IO_WQ_BIT_EXIT = 0, - IO_WQ_BIT_CANCEL = 1, - IO_WQ_BIT_ERROR = 2, -}; - -enum { - IO_WQE_FLAG_STALLED = 1, -}; - -struct io_wqe; - -struct io_worker { - refcount_t ref; - unsigned int flags; - struct hlist_nulls_node nulls_node; - struct list_head all_list; - struct task_struct *task; - struct io_wqe *wqe; - struct io_wq_work *cur_work; - spinlock_t lock; - struct callback_head rcu; - struct mm_struct *mm; - struct cgroup_subsys_state *blkcg_css; - const struct cred *cur_creds; - const struct cred *saved_creds; - struct files_struct *restore_files; - struct nsproxy *restore_nsproxy; - struct fs_struct *restore_fs; -}; - -struct io_wqe_acct { - unsigned int nr_workers; - unsigned int max_workers; - atomic_t nr_running; -}; - -struct io_wq___2; - -struct io_wqe { - struct { - raw_spinlock_t lock; - struct io_wq_work_list work_list; - long unsigned int hash_map; - unsigned int flags; - long: 32; - long: 64; - long: 64; - long: 64; - }; - int node; - struct io_wqe_acct acct[2]; - struct hlist_nulls_head free_list; - struct list_head all_list; - struct io_wq___2 *wq; - struct io_wq_work *hash_tail[64]; -}; - -enum { - IO_WQ_ACCT_BOUND = 0, - IO_WQ_ACCT_UNBOUND = 1, -}; - -struct io_wq___2 { - struct io_wqe **wqes; - long unsigned int state; - free_work_fn *free_work; - io_wq_work_fn *do_work; - struct task_struct *manager; - struct user_struct *user; - refcount_t refs; - struct completion done; - struct hlist_node cpuhp_node; - refcount_t use_refs; -}; - -struct io_cb_cancel_data { - work_cancel_fn *fn; - void *data; - int nr_running; - int nr_pending; - bool cancel_all; -}; - -struct crypto_skcipher; - -struct fscrypt_prepared_key { - struct crypto_skcipher *tfm; -}; - -struct fscrypt_mode; - -struct fscrypt_direct_key; - -struct fscrypt_info { - struct fscrypt_prepared_key ci_enc_key; - bool ci_owns_key; - struct fscrypt_mode *ci_mode; - struct inode *ci_inode; - struct key *ci_master_key; - struct list_head ci_master_key_link; - struct fscrypt_direct_key *ci_direct_key; - siphash_key_t ci_dirhash_key; - bool ci_dirhash_key_initialized; - union fscrypt_policy ci_policy; - u8 ci_nonce[16]; - u32 ci_hashed_ino; -}; - -struct crypto_async_request; - -typedef void (*crypto_completion_t)(struct crypto_async_request *, int); - -struct crypto_async_request { - struct list_head list; - crypto_completion_t complete; - void *data; - struct crypto_tfm *tfm; - u32 flags; -}; - -struct crypto_wait { - struct completion completion; - int err; -}; - -struct skcipher_request { - unsigned int cryptlen; - u8 *iv; - struct scatterlist *src; - struct scatterlist *dst; - struct crypto_async_request base; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__ctx[0]; -}; - -struct crypto_skcipher { - unsigned int reqsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_tfm base; -}; - -enum blk_crypto_mode_num { - BLK_ENCRYPTION_MODE_INVALID = 0, - BLK_ENCRYPTION_MODE_AES_256_XTS = 1, - BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV = 2, - BLK_ENCRYPTION_MODE_ADIANTUM = 3, - BLK_ENCRYPTION_MODE_MAX = 4, -}; - -struct fscrypt_mode { - const char *friendly_name; - const char *cipher_str; - int keysize; - int security_strength; - int ivsize; - int logged_impl_name; - enum blk_crypto_mode_num blk_crypto_mode; -}; - -typedef enum { - FS_DECRYPT = 0, - FS_ENCRYPT = 1, -} fscrypt_direction_t; - -union fscrypt_iv { - struct { - __le64 lblk_num; - u8 nonce[16]; - }; - u8 raw[32]; - __le64 dun[4]; -}; - -struct fscrypt_str { - unsigned char *name; - u32 len; -}; - -struct fscrypt_name { - const struct qstr *usr_fname; - struct fscrypt_str disk_name; - u32 hash; - u32 minor_hash; - struct fscrypt_str crypto_buf; - bool is_nokey_name; -}; - -struct fscrypt_nokey_name { - u32 dirhash[2]; - u8 bytes[149]; - u8 sha256[32]; -}; - -struct crypto_shash; - -struct shash_desc { - struct crypto_shash *tfm; - void *__ctx[0]; -}; - -struct crypto_shash { - unsigned int descsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_tfm base; -}; - -struct shash_alg { - int (*init)(struct shash_desc *); - int (*update)(struct shash_desc *, const u8 *, unsigned int); - int (*final)(struct shash_desc *, u8 *); - int (*finup)(struct shash_desc *, const u8 *, unsigned int, u8 *); - int (*digest)(struct shash_desc *, const u8 *, unsigned int, u8 *); - int (*export)(struct shash_desc *, void *); - int (*import)(struct shash_desc *, const void *); - int (*setkey)(struct crypto_shash *, const u8 *, unsigned int); - int (*init_tfm)(struct crypto_shash *); - void (*exit_tfm)(struct crypto_shash *); - unsigned int descsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - unsigned int digestsize; - unsigned int statesize; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct fscrypt_hkdf { - struct crypto_shash *hmac_tfm; -}; - -struct fscrypt_key_specifier { - __u32 type; - __u32 __reserved; - union { - __u8 __reserved[32]; - __u8 descriptor[8]; - __u8 identifier[16]; - } u; -}; - -struct fscrypt_symlink_data { - __le16 len; - char encrypted_path[1]; -} __attribute__((packed)); - -struct fscrypt_master_key_secret { - struct fscrypt_hkdf hkdf; - u32 size; - u8 raw[64]; -}; - -struct fscrypt_master_key { - struct fscrypt_master_key_secret mk_secret; - struct rw_semaphore mk_secret_sem; - struct fscrypt_key_specifier mk_spec; - struct key *mk_users; - refcount_t mk_refcount; - struct list_head mk_decrypted_inodes; - spinlock_t mk_decrypted_inodes_lock; - struct fscrypt_prepared_key mk_direct_keys[10]; - struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[10]; - struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[10]; - siphash_key_t mk_ino_hash_key; - bool mk_ino_hash_key_initialized; -}; - -enum key_need_perm { - KEY_NEED_UNSPECIFIED = 0, - KEY_NEED_VIEW = 1, - KEY_NEED_READ = 2, - KEY_NEED_WRITE = 3, - KEY_NEED_SEARCH = 4, - KEY_NEED_LINK = 5, - KEY_NEED_SETATTR = 6, - KEY_NEED_UNLINK = 7, - KEY_SYSADMIN_OVERRIDE = 8, - KEY_AUTHTOKEN_OVERRIDE = 9, - KEY_DEFER_PERM_CHECK = 10, -}; - -enum key_state { - KEY_IS_UNINSTANTIATED = 0, - KEY_IS_POSITIVE = 1, -}; - -struct fscrypt_provisioning_key_payload { - __u32 type; - __u32 __reserved; - __u8 raw[0]; -}; - -struct fscrypt_add_key_arg { - struct fscrypt_key_specifier key_spec; - __u32 raw_size; - __u32 key_id; - __u32 __reserved[8]; - __u8 raw[0]; -}; - -struct fscrypt_remove_key_arg { - struct fscrypt_key_specifier key_spec; - __u32 removal_status_flags; - __u32 __reserved[5]; -}; - -struct fscrypt_get_key_status_arg { - struct fscrypt_key_specifier key_spec; - __u32 __reserved[6]; - __u32 status; - __u32 status_flags; - __u32 user_count; - __u32 __out_reserved[13]; -}; - -struct skcipher_alg { - int (*setkey)(struct crypto_skcipher *, const u8 *, unsigned int); - int (*encrypt)(struct skcipher_request *); - int (*decrypt)(struct skcipher_request *); - int (*init)(struct crypto_skcipher *); - void (*exit)(struct crypto_skcipher *); - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; - unsigned int chunksize; - unsigned int walksize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct fscrypt_context_v1 { - u8 version; - u8 contents_encryption_mode; - u8 filenames_encryption_mode; - u8 flags; - u8 master_key_descriptor[8]; - u8 nonce[16]; -}; - -struct fscrypt_context_v2 { - u8 version; - u8 contents_encryption_mode; - u8 filenames_encryption_mode; - u8 flags; - u8 __reserved[4]; - u8 master_key_identifier[16]; - u8 nonce[16]; -}; - -union fscrypt_context { - u8 version; - struct fscrypt_context_v1 v1; - struct fscrypt_context_v2 v2; -}; - -struct crypto_template; - -struct crypto_spawn; - -struct crypto_instance { - struct crypto_alg alg; - struct crypto_template *tmpl; - union { - struct hlist_node list; - struct crypto_spawn *spawns; - }; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__ctx[0]; -}; - -struct crypto_spawn { - struct list_head list; - struct crypto_alg *alg; - union { - struct crypto_instance *inst; - struct crypto_spawn *next; - }; - const struct crypto_type *frontend; - u32 mask; - bool dead; - bool registered; -}; - -struct rtattr; - -struct crypto_template { - struct list_head list; - struct hlist_head instances; - struct module *module; - int (*create)(struct crypto_template *, struct rtattr **); - char name[128]; -}; - -struct user_key_payload { - struct callback_head rcu; - short unsigned int datalen; - long: 48; - char data[0]; -}; - -struct fscrypt_key { - __u32 mode; - __u8 raw[64]; - __u32 size; -}; - -struct fscrypt_direct_key { - struct hlist_node dk_node; - refcount_t dk_refcount; - const struct fscrypt_mode *dk_mode; - struct fscrypt_prepared_key dk_key; - u8 dk_descriptor[8]; - u8 dk_raw[64]; -}; - -struct fscrypt_get_policy_ex_arg { - __u64 policy_size; - union { - __u8 version; - struct fscrypt_policy_v1 v1; - struct fscrypt_policy_v2 v2; - } policy; -}; - -struct fscrypt_dummy_policy { - const union fscrypt_policy *policy; -}; - -struct flock64 { - short int l_type; - short int l_whence; - __kernel_loff_t l_start; - __kernel_loff_t l_len; - __kernel_pid_t l_pid; -}; - -struct trace_event_raw_locks_get_lock_context { - struct trace_entry ent; - long unsigned int i_ino; - dev_t s_dev; - unsigned char type; - struct file_lock_context *ctx; - char __data[0]; -}; - -struct trace_event_raw_filelock_lock { - struct trace_entry ent; - struct file_lock *fl; - long unsigned int i_ino; - dev_t s_dev; - struct file_lock *fl_blocker; - fl_owner_t fl_owner; - unsigned int fl_pid; - unsigned int fl_flags; - unsigned char fl_type; - loff_t fl_start; - loff_t fl_end; - int ret; - char __data[0]; -}; - -struct trace_event_raw_filelock_lease { - struct trace_entry ent; - struct file_lock *fl; - long unsigned int i_ino; - dev_t s_dev; - struct file_lock *fl_blocker; - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - long unsigned int fl_break_time; - long unsigned int fl_downgrade_time; - char __data[0]; -}; - -struct trace_event_raw_generic_add_lease { - struct trace_entry ent; - long unsigned int i_ino; - int wcount; - int rcount; - int icount; - dev_t s_dev; - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - char __data[0]; -}; - -struct trace_event_raw_leases_conflict { - struct trace_entry ent; - void *lease; - void *breaker; - unsigned int l_fl_flags; - unsigned int b_fl_flags; - unsigned char l_fl_type; - unsigned char b_fl_type; - bool conflict; - char __data[0]; -}; - -struct trace_event_data_offsets_locks_get_lock_context {}; - -struct trace_event_data_offsets_filelock_lock {}; - -struct trace_event_data_offsets_filelock_lease {}; - -struct trace_event_data_offsets_generic_add_lease {}; - -struct trace_event_data_offsets_leases_conflict {}; - -typedef void (*btf_trace_locks_get_lock_context)(void *, struct inode *, int, struct file_lock_context *); - -typedef void (*btf_trace_posix_lock_inode)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_fcntl_setlk)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_locks_remove_posix)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_flock_lock_inode)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_break_lease_noblock)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_break_lease_block)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_break_lease_unblock)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_generic_delete_lease)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_time_out_leases)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_generic_add_lease)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_leases_conflict)(void *, bool, struct file_lock *, struct file_lock *); - -struct file_lock_list_struct { - spinlock_t lock; - struct hlist_head hlist; -}; - -struct locks_iterator { - int li_cpu; - loff_t li_pos; -}; - -typedef unsigned int __kernel_uid_t; - -typedef unsigned int __kernel_gid_t; - -struct elf64_note { - Elf64_Word n_namesz; - Elf64_Word n_descsz; - Elf64_Word n_type; -}; - -typedef long unsigned int elf_greg_t; - -typedef elf_greg_t elf_gregset_t[34]; - -struct gnu_property { - u32 pr_type; - u32 pr_datasz; -}; - -struct elf_siginfo { - int si_signo; - int si_code; - int si_errno; -}; - -struct elf_prstatus { - struct elf_siginfo pr_info; - short int pr_cursig; - long unsigned int pr_sigpend; - long unsigned int pr_sighold; - pid_t pr_pid; - pid_t pr_ppid; - pid_t pr_pgrp; - pid_t pr_sid; - struct __kernel_old_timeval pr_utime; - struct __kernel_old_timeval pr_stime; - struct __kernel_old_timeval pr_cutime; - struct __kernel_old_timeval pr_cstime; - elf_gregset_t pr_reg; - int pr_fpvalid; -}; - -struct elf_prpsinfo { - char pr_state; - char pr_sname; - char pr_zomb; - char pr_nice; - long unsigned int pr_flag; - __kernel_uid_t pr_uid; - __kernel_gid_t pr_gid; - pid_t pr_pid; - pid_t pr_ppid; - pid_t pr_pgrp; - pid_t pr_sid; - char pr_fname[16]; - char pr_psargs[80]; -}; - -struct core_vma_metadata { - long unsigned int start; - long unsigned int end; - long unsigned int flags; - long unsigned int dump_size; -}; - -struct memelfnote { - const char *name; - int type; - unsigned int datasz; - void *data; -}; - -struct elf_thread_core_info { - struct elf_thread_core_info *next; - struct task_struct *task; - struct elf_prstatus prstatus; - struct memelfnote notes[0]; -}; - -struct elf_note_info { - struct elf_thread_core_info *thread; - struct memelfnote psinfo; - struct memelfnote signote; - struct memelfnote auxv; - struct memelfnote files; - siginfo_t csigdata; - size_t size; - int thread_notes; -}; - -struct elf32_shdr { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -}; - -typedef u16 __compat_uid_t; - -typedef u16 __compat_gid_t; - -typedef unsigned int compat_elf_greg_t; - -typedef compat_elf_greg_t compat_elf_gregset_t[18]; - -struct compat_elf_siginfo { - compat_int_t si_signo; - compat_int_t si_code; - compat_int_t si_errno; -}; - -struct compat_elf_prstatus { - struct compat_elf_siginfo pr_info; - short int pr_cursig; - compat_ulong_t pr_sigpend; - compat_ulong_t pr_sighold; - compat_pid_t pr_pid; - compat_pid_t pr_ppid; - compat_pid_t pr_pgrp; - compat_pid_t pr_sid; - struct old_timeval32 pr_utime; - struct old_timeval32 pr_stime; - struct old_timeval32 pr_cutime; - struct old_timeval32 pr_cstime; - compat_elf_gregset_t pr_reg; - compat_int_t pr_fpvalid; -}; - -struct compat_elf_prpsinfo { - char pr_state; - char pr_sname; - char pr_zomb; - char pr_nice; - compat_ulong_t pr_flag; - __compat_uid_t pr_uid; - __compat_gid_t pr_gid; - compat_pid_t pr_pid; - compat_pid_t pr_ppid; - compat_pid_t pr_pgrp; - compat_pid_t pr_sid; - char pr_fname[16]; - char pr_psargs[80]; -}; - -struct elf_thread_core_info___2 { - struct elf_thread_core_info___2 *next; - struct task_struct *task; - struct compat_elf_prstatus prstatus; - struct memelfnote notes[0]; -}; - -struct elf_note_info___2 { - struct elf_thread_core_info___2 *thread; - struct memelfnote psinfo; - struct memelfnote signote; - struct memelfnote auxv; - struct memelfnote files; - compat_siginfo_t csigdata; - size_t size; - int thread_notes; -}; - -struct mb_cache_entry { - struct list_head e_list; - struct hlist_bl_node e_hash_list; - atomic_t e_refcnt; - u32 e_key; - u32 e_referenced: 1; - u32 e_reusable: 1; - u64 e_value; -}; - -struct mb_cache { - struct hlist_bl_head *c_hash; - int c_bucket_bits; - long unsigned int c_max_entries; - spinlock_t c_list_lock; - struct list_head c_list; - long unsigned int c_entry_count; - struct shrinker c_shrink; - struct work_struct c_shrink_work; -}; - -struct posix_acl_xattr_entry { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -}; - -struct posix_acl_xattr_header { - __le32 a_version; -}; - -struct xdr_buf { - struct kvec head[1]; - struct kvec tail[1]; - struct bio_vec *bvec; - struct page **pages; - unsigned int page_base; - unsigned int page_len; - unsigned int flags; - unsigned int buflen; - unsigned int len; -}; - -struct xdr_array2_desc; - -typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *, void *); - -struct xdr_array2_desc { - unsigned int elem_size; - unsigned int array_len; - unsigned int array_maxlen; - xdr_xcode_elem_t xcode; -}; - -struct nfsacl_encode_desc { - struct xdr_array2_desc desc; - unsigned int count; - struct posix_acl *acl; - int typeflag; - kuid_t uid; - kgid_t gid; -}; - -struct nfsacl_simple_acl { - struct posix_acl acl; - struct posix_acl_entry ace[4]; -}; - -struct nfsacl_decode_desc { - struct xdr_array2_desc desc; - unsigned int count; - struct posix_acl *acl; -}; - -struct lock_manager { - struct list_head list; - bool block_opens; -}; - -struct rpc_timer { - struct list_head list; - long unsigned int expires; - struct delayed_work dwork; -}; - -struct rpc_wait_queue { - spinlock_t lock; - struct list_head tasks[4]; - unsigned char maxpriority; - unsigned char priority; - unsigned char nr; - short unsigned int qlen; - struct rpc_timer timer_list; - const char *name; -}; - -struct nfs_seqid_counter { - ktime_t create_time; - int owner_id; - int flags; - u32 counter; - spinlock_t lock; - struct list_head list; - struct rpc_wait_queue wait; -}; - -struct nfs4_stateid_struct { - union { - char data[16]; - struct { - __be32 seqid; - char other[12]; - }; - }; - enum { - NFS4_INVALID_STATEID_TYPE = 0, - NFS4_SPECIAL_STATEID_TYPE = 1, - NFS4_OPEN_STATEID_TYPE = 2, - NFS4_LOCK_STATEID_TYPE = 3, - NFS4_DELEGATION_STATEID_TYPE = 4, - NFS4_LAYOUT_STATEID_TYPE = 5, - NFS4_PNFS_DS_STATEID_TYPE = 6, - NFS4_REVOKED_STATEID_TYPE = 7, - } type; -}; - -typedef struct nfs4_stateid_struct nfs4_stateid; - -struct nfs4_state; - -struct nfs4_lock_state { - struct list_head ls_locks; - struct nfs4_state *ls_state; - long unsigned int ls_flags; - struct nfs_seqid_counter ls_seqid; - nfs4_stateid ls_stateid; - refcount_t ls_count; - fl_owner_t ls_owner; -}; - -struct rpc_rqst; - -struct xdr_stream { - __be32 *p; - struct xdr_buf *buf; - __be32 *end; - struct kvec *iov; - struct kvec scratch; - struct page **page_ptr; - unsigned int nwords; - struct rpc_rqst *rqst; -}; - -struct rpc_xprt; - -struct rpc_task; - -struct rpc_cred; - -struct rpc_rqst { - struct rpc_xprt *rq_xprt; - struct xdr_buf rq_snd_buf; - struct xdr_buf rq_rcv_buf; - struct rpc_task *rq_task; - struct rpc_cred *rq_cred; - __be32 rq_xid; - int rq_cong; - u32 rq_seqno; - int rq_enc_pages_num; - struct page **rq_enc_pages; - void (*rq_release_snd_buf)(struct rpc_rqst *); - union { - struct list_head rq_list; - struct rb_node rq_recv; - }; - struct list_head rq_xmit; - struct list_head rq_xmit2; - void *rq_buffer; - size_t rq_callsize; - void *rq_rbuffer; - size_t rq_rcvsize; - size_t rq_xmit_bytes_sent; - size_t rq_reply_bytes_recvd; - struct xdr_buf rq_private_buf; - long unsigned int rq_majortimeo; - long unsigned int rq_minortimeo; - long unsigned int rq_timeout; - ktime_t rq_rtt; - unsigned int rq_retries; - unsigned int rq_connect_cookie; - atomic_t rq_pin; - u32 rq_bytes_sent; - ktime_t rq_xtime; - int rq_ntrans; - struct list_head rq_bc_list; - long unsigned int rq_bc_pa_state; - struct list_head rq_bc_pa_list; -}; - -typedef void (*kxdreproc_t)(struct rpc_rqst *, struct xdr_stream *, const void *); - -typedef int (*kxdrdproc_t)(struct rpc_rqst *, struct xdr_stream *, void *); - -struct rpc_procinfo; - -struct rpc_message { - const struct rpc_procinfo *rpc_proc; - void *rpc_argp; - void *rpc_resp; - const struct cred *rpc_cred; -}; - -struct rpc_procinfo { - u32 p_proc; - kxdreproc_t p_encode; - kxdrdproc_t p_decode; - unsigned int p_arglen; - unsigned int p_replen; - unsigned int p_timer; - u32 p_statidx; - const char *p_name; -}; - -struct rpc_wait { - struct list_head list; - struct list_head links; - struct list_head timer_list; -}; - -struct rpc_call_ops; - -struct rpc_clnt; - -struct rpc_task { - atomic_t tk_count; - int tk_status; - struct list_head tk_task; - void (*tk_callback)(struct rpc_task *); - void (*tk_action)(struct rpc_task *); - long unsigned int tk_timeout; - long unsigned int tk_runstate; - struct rpc_wait_queue *tk_waitqueue; - union { - struct work_struct tk_work; - struct rpc_wait tk_wait; - } u; - int tk_rpc_status; - struct rpc_message tk_msg; - void *tk_calldata; - const struct rpc_call_ops *tk_ops; - struct rpc_clnt *tk_client; - struct rpc_xprt *tk_xprt; - struct rpc_cred *tk_op_cred; - struct rpc_rqst *tk_rqstp; - struct workqueue_struct *tk_workqueue; - ktime_t tk_start; - pid_t tk_owner; - short unsigned int tk_flags; - short unsigned int tk_timeouts; - short unsigned int tk_pid; - unsigned char tk_priority: 2; - unsigned char tk_garb_retry: 2; - unsigned char tk_cred_retry: 2; - unsigned char tk_rebind_retry: 2; -}; - -struct rpc_call_ops { - void (*rpc_call_prepare)(struct rpc_task *, void *); - void (*rpc_call_done)(struct rpc_task *, void *); - void (*rpc_count_stats)(struct rpc_task *, void *); - void (*rpc_release)(void *); -}; - -struct rpc_pipe_dir_head { - struct list_head pdh_entries; - struct dentry *pdh_dentry; -}; - -struct rpc_rtt { - long unsigned int timeo; - long unsigned int srtt[5]; - long unsigned int sdrtt[5]; - int ntimeouts[5]; -}; - -struct rpc_timeout { - long unsigned int to_initval; - long unsigned int to_maxval; - long unsigned int to_increment; - unsigned int to_retries; - unsigned char to_exponential; -}; - -struct rpc_xprt_switch; - -struct rpc_xprt_iter_ops; - -struct rpc_xprt_iter { - struct rpc_xprt_switch *xpi_xpswitch; - struct rpc_xprt *xpi_cursor; - const struct rpc_xprt_iter_ops *xpi_ops; -}; - -struct rpc_auth; - -struct rpc_stat; - -struct rpc_iostats; - -struct rpc_program; - -struct rpc_clnt { - atomic_t cl_count; - unsigned int cl_clid; - struct list_head cl_clients; - struct list_head cl_tasks; - spinlock_t cl_lock; - struct rpc_xprt *cl_xprt; - const struct rpc_procinfo *cl_procinfo; - u32 cl_prog; - u32 cl_vers; - u32 cl_maxproc; - struct rpc_auth *cl_auth; - struct rpc_stat *cl_stats; - struct rpc_iostats *cl_metrics; - unsigned int cl_softrtry: 1; - unsigned int cl_softerr: 1; - unsigned int cl_discrtry: 1; - unsigned int cl_noretranstimeo: 1; - unsigned int cl_autobind: 1; - unsigned int cl_chatty: 1; - struct rpc_rtt *cl_rtt; - const struct rpc_timeout *cl_timeout; - atomic_t cl_swapper; - int cl_nodelen; - char cl_nodename[65]; - struct rpc_pipe_dir_head cl_pipedir_objects; - struct rpc_clnt *cl_parent; - struct rpc_rtt cl_rtt_default; - struct rpc_timeout cl_timeout_default; - const struct rpc_program *cl_program; - const char *cl_principal; - union { - struct rpc_xprt_iter cl_xpi; - struct work_struct cl_work; - }; - const struct cred *cl_cred; -}; - -struct rpc_xprt_ops; - -struct svc_xprt; - -struct svc_serv; - -struct rpc_xprt { - struct kref kref; - const struct rpc_xprt_ops *ops; - const struct rpc_timeout *timeout; - struct __kernel_sockaddr_storage addr; - size_t addrlen; - int prot; - long unsigned int cong; - long unsigned int cwnd; - size_t max_payload; - struct rpc_wait_queue binding; - struct rpc_wait_queue sending; - struct rpc_wait_queue pending; - struct rpc_wait_queue backlog; - struct list_head free; - unsigned int max_reqs; - unsigned int min_reqs; - unsigned int num_reqs; - long unsigned int state; - unsigned char resvport: 1; - unsigned char reuseport: 1; - atomic_t swapper; - unsigned int bind_index; - struct list_head xprt_switch; - long unsigned int bind_timeout; - long unsigned int reestablish_timeout; - unsigned int connect_cookie; - struct work_struct task_cleanup; - struct timer_list timer; - long unsigned int last_used; - long unsigned int idle_timeout; - long unsigned int connect_timeout; - long unsigned int max_reconnect_timeout; - atomic_long_t queuelen; - spinlock_t transport_lock; - spinlock_t reserve_lock; - spinlock_t queue_lock; - u32 xid; - struct rpc_task *snd_task; - struct list_head xmit_queue; - struct svc_xprt *bc_xprt; - struct svc_serv *bc_serv; - unsigned int bc_alloc_max; - unsigned int bc_alloc_count; - atomic_t bc_slot_count; - spinlock_t bc_pa_lock; - struct list_head bc_pa_list; - struct rb_root recv_queue; - struct { - long unsigned int bind_count; - long unsigned int connect_count; - long unsigned int connect_start; - long unsigned int connect_time; - long unsigned int sends; - long unsigned int recvs; - long unsigned int bad_xids; - long unsigned int max_slots; - long long unsigned int req_u; - long long unsigned int bklog_u; - long long unsigned int sending_u; - long long unsigned int pending_u; - } stat; - struct net *xprt_net; - const char *servername; - const char *address_strings[6]; - struct callback_head rcu; -}; - -struct rpc_credops; - -struct rpc_cred { - struct hlist_node cr_hash; - struct list_head cr_lru; - struct callback_head cr_rcu; - struct rpc_auth *cr_auth; - const struct rpc_credops *cr_ops; - long unsigned int cr_expire; - long unsigned int cr_flags; - refcount_t cr_count; - const struct cred *cr_cred; -}; - -typedef u32 rpc_authflavor_t; - -struct auth_cred { - const struct cred *cred; - const char *principal; -}; - -struct rpc_authops; - -struct rpc_cred_cache; - -struct rpc_auth { - unsigned int au_cslack; - unsigned int au_rslack; - unsigned int au_verfsize; - unsigned int au_ralign; - long unsigned int au_flags; - const struct rpc_authops *au_ops; - rpc_authflavor_t au_flavor; - refcount_t au_count; - struct rpc_cred_cache *au_credcache; -}; - -struct rpc_credops { - const char *cr_name; - int (*cr_init)(struct rpc_auth *, struct rpc_cred *); - void (*crdestroy)(struct rpc_cred *); - int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); - int (*crmarshal)(struct rpc_task *, struct xdr_stream *); - int (*crrefresh)(struct rpc_task *); - int (*crvalidate)(struct rpc_task *, struct xdr_stream *); - int (*crwrap_req)(struct rpc_task *, struct xdr_stream *); - int (*crunwrap_resp)(struct rpc_task *, struct xdr_stream *); - int (*crkey_timeout)(struct rpc_cred *); - char * (*crstringify_acceptor)(struct rpc_cred *); - bool (*crneed_reencode)(struct rpc_task *); -}; - -struct rpc_auth_create_args; - -struct rpcsec_gss_info; - -struct rpc_authops { - struct module *owner; - rpc_authflavor_t au_flavor; - char *au_name; - struct rpc_auth * (*create)(const struct rpc_auth_create_args *, struct rpc_clnt *); - void (*destroy)(struct rpc_auth *); - int (*hash_cred)(struct auth_cred *, unsigned int); - struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); - struct rpc_cred * (*crcreate)(struct rpc_auth *, struct auth_cred *, int, gfp_t); - rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *); - int (*flavor2info)(rpc_authflavor_t, struct rpcsec_gss_info *); - int (*key_timeout)(struct rpc_auth *, struct rpc_cred *); -}; - -struct rpc_auth_create_args { - rpc_authflavor_t pseudoflavor; - const char *target_name; -}; - -struct rpcsec_gss_oid { - unsigned int len; - u8 data[32]; -}; - -struct rpcsec_gss_info { - struct rpcsec_gss_oid oid; - u32 qop; - u32 service; -}; - -struct rpc_xprt_ops { - void (*set_buffer_size)(struct rpc_xprt *, size_t, size_t); - int (*reserve_xprt)(struct rpc_xprt *, struct rpc_task *); - void (*release_xprt)(struct rpc_xprt *, struct rpc_task *); - void (*alloc_slot)(struct rpc_xprt *, struct rpc_task *); - void (*free_slot)(struct rpc_xprt *, struct rpc_rqst *); - void (*rpcbind)(struct rpc_task *); - void (*set_port)(struct rpc_xprt *, short unsigned int); - void (*connect)(struct rpc_xprt *, struct rpc_task *); - int (*buf_alloc)(struct rpc_task *); - void (*buf_free)(struct rpc_task *); - void (*prepare_request)(struct rpc_rqst *); - int (*send_request)(struct rpc_rqst *); - void (*wait_for_reply_request)(struct rpc_task *); - void (*timer)(struct rpc_xprt *, struct rpc_task *); - void (*release_request)(struct rpc_task *); - void (*close)(struct rpc_xprt *); - void (*destroy)(struct rpc_xprt *); - void (*set_connect_timeout)(struct rpc_xprt *, long unsigned int, long unsigned int); - void (*print_stats)(struct rpc_xprt *, struct seq_file *); - int (*enable_swap)(struct rpc_xprt *); - void (*disable_swap)(struct rpc_xprt *); - void (*inject_disconnect)(struct rpc_xprt *); - int (*bc_setup)(struct rpc_xprt *, unsigned int); - size_t (*bc_maxpayload)(struct rpc_xprt *); - unsigned int (*bc_num_slots)(struct rpc_xprt *); - void (*bc_free_rqst)(struct rpc_rqst *); - void (*bc_destroy)(struct rpc_xprt *, unsigned int); -}; - -struct rpc_xprt_switch { - spinlock_t xps_lock; - struct kref xps_kref; - unsigned int xps_nxprts; - unsigned int xps_nactive; - atomic_long_t xps_queuelen; - struct list_head xps_xprt_list; - struct net *xps_net; - const struct rpc_xprt_iter_ops *xps_iter_ops; - struct callback_head xps_rcu; -}; - -struct rpc_stat { - const struct rpc_program *program; - unsigned int netcnt; - unsigned int netudpcnt; - unsigned int nettcpcnt; - unsigned int nettcpconn; - unsigned int netreconn; - unsigned int rpccnt; - unsigned int rpcretrans; - unsigned int rpcauthrefresh; - unsigned int rpcgarbage; -}; - -struct rpc_version; - -struct rpc_program { - const char *name; - u32 number; - unsigned int nrvers; - const struct rpc_version **version; - struct rpc_stat *stats; - const char *pipe_dir_name; -}; - -struct rpc_xprt_iter_ops { - void (*xpi_rewind)(struct rpc_xprt_iter *); - struct rpc_xprt * (*xpi_xprt)(struct rpc_xprt_iter *); - struct rpc_xprt * (*xpi_next)(struct rpc_xprt_iter *); -}; - -struct rpc_version { - u32 number; - unsigned int nrprocs; - const struct rpc_procinfo *procs; - unsigned int *counts; -}; - -struct nfs_fh { - short unsigned int size; - unsigned char data[128]; -}; - -enum nfs3_stable_how { - NFS_UNSTABLE = 0, - NFS_DATA_SYNC = 1, - NFS_FILE_SYNC = 2, - NFS_INVALID_STABLE_HOW = 4294967295, -}; - -struct nfs4_label { - uint32_t lfs; - uint32_t pi; - u32 len; - char *label; -}; - -typedef struct { - char data[8]; -} nfs4_verifier; - -struct nfs4_string { - unsigned int len; - char *data; -}; - -struct nfs_fsid { - uint64_t major; - uint64_t minor; -}; - -struct nfs4_threshold { - __u32 bm; - __u32 l_type; - __u64 rd_sz; - __u64 wr_sz; - __u64 rd_io_sz; - __u64 wr_io_sz; -}; - -struct nfs_fattr { - unsigned int valid; - umode_t mode; - __u32 nlink; - kuid_t uid; - kgid_t gid; - dev_t rdev; - __u64 size; - union { - struct { - __u32 blocksize; - __u32 blocks; - } nfs2; - struct { - __u64 used; - } nfs3; - } du; - struct nfs_fsid fsid; - __u64 fileid; - __u64 mounted_on_fileid; - struct timespec64 atime; - struct timespec64 mtime; - struct timespec64 ctime; - __u64 change_attr; - __u64 pre_change_attr; - __u64 pre_size; - struct timespec64 pre_mtime; - struct timespec64 pre_ctime; - long unsigned int time_start; - long unsigned int gencount; - struct nfs4_string *owner_name; - struct nfs4_string *group_name; - struct nfs4_threshold *mdsthreshold; - struct nfs4_label *label; -}; - -struct nfs_fsinfo { - struct nfs_fattr *fattr; - __u32 rtmax; - __u32 rtpref; - __u32 rtmult; - __u32 wtmax; - __u32 wtpref; - __u32 wtmult; - __u32 dtpref; - __u64 maxfilesize; - struct timespec64 time_delta; - __u32 lease_time; - __u32 nlayouttypes; - __u32 layouttype[8]; - __u32 blksize; - __u32 clone_blksize; - __u32 xattr_support; -}; - -struct nfs_fsstat { - struct nfs_fattr *fattr; - __u64 tbytes; - __u64 fbytes; - __u64 abytes; - __u64 tfiles; - __u64 ffiles; - __u64 afiles; -}; - -struct nfs_pathconf { - struct nfs_fattr *fattr; - __u32 max_link; - __u32 max_namelen; -}; - -struct nfs4_change_info { - u32 atomic; - u64 before; - u64 after; -}; - -struct nfs4_slot; - -struct nfs4_sequence_args { - struct nfs4_slot *sa_slot; - u8 sa_cache_this: 1; - u8 sa_privileged: 1; -}; - -struct nfs4_sequence_res { - struct nfs4_slot *sr_slot; - long unsigned int sr_timestamp; - int sr_status; - u32 sr_status_flags; - u32 sr_highest_slotid; - u32 sr_target_highest_slotid; -}; - -struct nfs_open_context; - -struct nfs_lock_context { - refcount_t count; - struct list_head list; - struct nfs_open_context *open_context; - fl_owner_t lockowner; - atomic_t io_count; - struct callback_head callback_head; -}; - -struct nfs_open_context { - struct nfs_lock_context lock_context; - fl_owner_t flock_owner; - struct dentry *dentry; - const struct cred *cred; - struct rpc_cred *ll_cred; - struct nfs4_state *state; - fmode_t mode; - long unsigned int flags; - int error; - struct list_head list; - struct nfs4_threshold *mdsthreshold; - struct callback_head callback_head; -}; - -struct nlm_host; - -struct nfs_auth_info { - unsigned int flavor_len; - rpc_authflavor_t flavors[12]; -}; - -struct nfs_client; - -struct nfs_iostats; - -struct nfs_fscache_key; - -struct fscache_cookie; - -struct pnfs_layoutdriver_type; - -struct nfs_server { - struct nfs_client *nfs_client; - struct list_head client_link; - struct list_head master_link; - struct rpc_clnt *client; - struct rpc_clnt *client_acl; - struct nlm_host *nlm_host; - struct nfs_iostats *io_stats; - atomic_long_t writeback; - int flags; - unsigned int caps; - unsigned int rsize; - unsigned int rpages; - unsigned int wsize; - unsigned int wpages; - unsigned int wtmult; - unsigned int dtsize; - short unsigned int port; - unsigned int bsize; - unsigned int gxasize; - unsigned int sxasize; - unsigned int lxasize; - unsigned int acregmin; - unsigned int acregmax; - unsigned int acdirmin; - unsigned int acdirmax; - unsigned int namelen; - unsigned int options; - unsigned int clone_blksize; - struct nfs_fsid fsid; - __u64 maxfilesize; - struct timespec64 time_delta; - long unsigned int mount_time; - struct super_block *super; - dev_t s_dev; - struct nfs_auth_info auth_info; - struct nfs_fscache_key *fscache_key; - struct fscache_cookie *fscache; - u32 pnfs_blksize; - u32 attr_bitmask[3]; - u32 attr_bitmask_nl[3]; - u32 exclcreat_bitmask[3]; - u32 cache_consistency_bitmask[3]; - u32 acl_bitmask; - u32 fh_expire_type; - struct pnfs_layoutdriver_type *pnfs_curr_ld; - struct rpc_wait_queue roc_rpcwaitq; - void *pnfs_ld_data; - struct rb_root state_owners; - struct ida openowner_id; - struct ida lockowner_id; - struct list_head state_owners_lru; - struct list_head layouts; - struct list_head delegations; - struct list_head ss_copies; - long unsigned int mig_gen; - long unsigned int mig_status; - void (*destroy)(struct nfs_server *); - atomic_t active; - struct __kernel_sockaddr_storage mountd_address; - size_t mountd_addrlen; - u32 mountd_version; - short unsigned int mountd_port; - short unsigned int mountd_protocol; - struct rpc_wait_queue uoc_rpcwaitq; - unsigned int read_hdrsize; - const struct cred *cred; -}; - -struct nfs_rpc_ops; - -struct nfs_subversion; - -struct idmap; - -struct nfs4_minor_version_ops; - -struct nfs4_slot_table; - -struct nfs4_session; - -struct nfs41_server_owner; - -struct nfs41_server_scope; - -struct nfs41_impl_id; - -struct nfs_client { - refcount_t cl_count; - atomic_t cl_mds_count; - int cl_cons_state; - long unsigned int cl_res_state; - long unsigned int cl_flags; - struct __kernel_sockaddr_storage cl_addr; - size_t cl_addrlen; - char *cl_hostname; - char *cl_acceptor; - struct list_head cl_share_link; - struct list_head cl_superblocks; - struct rpc_clnt *cl_rpcclient; - const struct nfs_rpc_ops *rpc_ops; - int cl_proto; - struct nfs_subversion *cl_nfs_mod; - u32 cl_minorversion; - unsigned int cl_nconnect; - const char *cl_principal; - struct list_head cl_ds_clients; - u64 cl_clientid; - nfs4_verifier cl_confirm; - long unsigned int cl_state; - spinlock_t cl_lock; - long unsigned int cl_lease_time; - long unsigned int cl_last_renewal; - struct delayed_work cl_renewd; - struct rpc_wait_queue cl_rpcwaitq; - struct idmap *cl_idmap; - const char *cl_owner_id; - u32 cl_cb_ident; - const struct nfs4_minor_version_ops *cl_mvops; - long unsigned int cl_mig_gen; - struct nfs4_slot_table *cl_slot_tbl; - u32 cl_seqid; - u32 cl_exchange_flags; - struct nfs4_session *cl_session; - bool cl_preserve_clid; - struct nfs41_server_owner *cl_serverowner; - struct nfs41_server_scope *cl_serverscope; - struct nfs41_impl_id *cl_implid; - long unsigned int cl_sp4_flags; - wait_queue_head_t cl_lock_waitq; - char cl_ipaddr[48]; - struct fscache_cookie *fscache; - struct net *cl_net; - struct list_head pending_cb_stateids; -}; - -struct nfs_seqid { - struct nfs_seqid_counter *sequence; - struct list_head list; - struct rpc_task *task; -}; - -struct nfs_write_verifier { - char data[8]; -}; - -struct nfs_writeverf { - struct nfs_write_verifier verifier; - enum nfs3_stable_how committed; -}; - -struct nfs_pgio_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - struct nfs_open_context *context; - struct nfs_lock_context *lock_context; - nfs4_stateid stateid; - __u64 offset; - __u32 count; - unsigned int pgbase; - struct page **pages; - union { - unsigned int replen; - struct { - const u32 *bitmask; - u32 bitmask_store[3]; - enum nfs3_stable_how stable; - }; - }; -}; - -struct nfs_pgio_res { - struct nfs4_sequence_res seq_res; - struct nfs_fattr *fattr; - __u64 count; - __u32 op_status; - union { - struct { - unsigned int replen; - int eof; - }; - struct { - struct nfs_writeverf *verf; - const struct nfs_server *server; - }; - }; -}; - -struct nfs_commitargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - __u64 offset; - __u32 count; - const u32 *bitmask; -}; - -struct nfs_commitres { - struct nfs4_sequence_res seq_res; - __u32 op_status; - struct nfs_fattr *fattr; - struct nfs_writeverf *verf; - const struct nfs_server *server; -}; - -struct nfs_removeargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - struct qstr name; -}; - -struct nfs_removeres { - struct nfs4_sequence_res seq_res; - struct nfs_server *server; - struct nfs_fattr *dir_attr; - struct nfs4_change_info cinfo; -}; - -struct nfs_renameargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *old_dir; - const struct nfs_fh *new_dir; - const struct qstr *old_name; - const struct qstr *new_name; -}; - -struct nfs_renameres { - struct nfs4_sequence_res seq_res; - struct nfs_server *server; - struct nfs4_change_info old_cinfo; - struct nfs_fattr *old_fattr; - struct nfs4_change_info new_cinfo; - struct nfs_fattr *new_fattr; -}; - -struct nfs_entry { - __u64 ino; - __u64 cookie; - __u64 prev_cookie; - const char *name; - unsigned int len; - int eof; - struct nfs_fh *fh; - struct nfs_fattr *fattr; - struct nfs4_label *label; - unsigned char d_type; - struct nfs_server *server; -}; - -struct nfs4_pathname { - unsigned int ncomponents; - struct nfs4_string components[512]; -}; - -struct nfs4_fs_location { - unsigned int nservers; - struct nfs4_string servers[10]; - struct nfs4_pathname rootpath; -}; - -struct nfs4_fs_locations { - struct nfs_fattr fattr; - const struct nfs_server *server; - struct nfs4_pathname fs_path; - int nlocations; - struct nfs4_fs_location locations[10]; -}; - -struct nfstime4 { - u64 seconds; - u32 nseconds; -}; - -struct pnfs_commit_ops; - -struct pnfs_ds_commit_info { - struct list_head commits; - unsigned int nwritten; - unsigned int ncommitting; - const struct pnfs_commit_ops *ops; -}; - -struct pnfs_layout_segment; - -struct nfs_commit_info; - -struct nfs_page; - -struct pnfs_commit_ops { - void (*setup_ds_info)(struct pnfs_ds_commit_info *, struct pnfs_layout_segment *); - void (*release_ds_info)(struct pnfs_ds_commit_info *, struct inode *); - int (*commit_pagelist)(struct inode *, struct list_head *, int, struct nfs_commit_info *); - void (*mark_request_commit)(struct nfs_page *, struct pnfs_layout_segment *, struct nfs_commit_info *, u32); - void (*clear_request_commit)(struct nfs_page *, struct nfs_commit_info *); - int (*scan_commit_lists)(struct nfs_commit_info *, int); - void (*recover_commit_reqs)(struct list_head *, struct nfs_commit_info *); - struct nfs_page * (*search_commit_reqs)(struct nfs_commit_info *, struct page *); -}; - -struct nfs41_server_owner { - uint64_t minor_id; - uint32_t major_id_sz; - char major_id[1024]; -}; - -struct nfs41_server_scope { - uint32_t server_scope_sz; - char server_scope[1024]; -}; - -struct nfs41_impl_id { - char domain[1025]; - char name[1025]; - struct nfstime4 date; -}; - -struct nfs_page_array { - struct page **pagevec; - unsigned int npages; - struct page *page_array[8]; -}; - -struct nfs_pgio_completion_ops; - -struct nfs_rw_ops; - -struct nfs_io_completion; - -struct nfs_direct_req; - -struct nfs_pgio_header { - struct inode *inode; - const struct cred *cred; - struct list_head pages; - struct nfs_page *req; - struct nfs_writeverf verf; - fmode_t rw_mode; - struct pnfs_layout_segment *lseg; - loff_t io_start; - const struct rpc_call_ops *mds_ops; - void (*release)(struct nfs_pgio_header *); - const struct nfs_pgio_completion_ops *completion_ops; - const struct nfs_rw_ops *rw_ops; - struct nfs_io_completion *io_completion; - struct nfs_direct_req *dreq; - int pnfs_error; - int error; - unsigned int good_bytes; - long unsigned int flags; - struct rpc_task task; - struct nfs_fattr fattr; - struct nfs_pgio_args args; - struct nfs_pgio_res res; - long unsigned int timestamp; - int (*pgio_done_cb)(struct rpc_task *, struct nfs_pgio_header *); - __u64 mds_offset; - struct nfs_page_array page_array; - struct nfs_client *ds_clp; - u32 ds_commit_idx; - u32 pgio_mirror_idx; -}; - -struct nfs_pgio_completion_ops { - void (*error_cleanup)(struct list_head *, int); - void (*init_hdr)(struct nfs_pgio_header *); - void (*completion)(struct nfs_pgio_header *); - void (*reschedule_io)(struct nfs_pgio_header *); -}; - -struct rpc_task_setup; - -struct nfs_rw_ops { - struct nfs_pgio_header * (*rw_alloc_header)(); - void (*rw_free_header)(struct nfs_pgio_header *); - int (*rw_done)(struct rpc_task *, struct nfs_pgio_header *, struct inode *); - void (*rw_result)(struct rpc_task *, struct nfs_pgio_header *); - void (*rw_initiate)(struct nfs_pgio_header *, struct rpc_message *, const struct nfs_rpc_ops *, struct rpc_task_setup *, int); -}; - -struct nfs_mds_commit_info { - atomic_t rpcs_out; - atomic_long_t ncommit; - struct list_head list; -}; - -struct nfs_commit_data; - -struct nfs_commit_completion_ops { - void (*completion)(struct nfs_commit_data *); - void (*resched_write)(struct nfs_commit_info *, struct nfs_page *); -}; - -struct nfs_commit_data { - struct rpc_task task; - struct inode *inode; - const struct cred *cred; - struct nfs_fattr fattr; - struct nfs_writeverf verf; - struct list_head pages; - struct list_head list; - struct nfs_direct_req *dreq; - struct nfs_commitargs args; - struct nfs_commitres res; - struct nfs_open_context *context; - struct pnfs_layout_segment *lseg; - struct nfs_client *ds_clp; - int ds_commit_index; - loff_t lwb; - const struct rpc_call_ops *mds_ops; - const struct nfs_commit_completion_ops *completion_ops; - int (*commit_done_cb)(struct rpc_task *, struct nfs_commit_data *); - long unsigned int flags; -}; - -struct nfs_commit_info { - struct inode *inode; - struct nfs_mds_commit_info *mds; - struct pnfs_ds_commit_info *ds; - struct nfs_direct_req *dreq; - const struct nfs_commit_completion_ops *completion_ops; -}; - -struct nfs_unlinkdata { - struct nfs_removeargs args; - struct nfs_removeres res; - struct dentry *dentry; - wait_queue_head_t wq; - const struct cred *cred; - struct nfs_fattr dir_attr; - long int timeout; -}; - -struct nfs_renamedata { - struct nfs_renameargs args; - struct nfs_renameres res; - const struct cred *cred; - struct inode *old_dir; - struct dentry *old_dentry; - struct nfs_fattr old_fattr; - struct inode *new_dir; - struct dentry *new_dentry; - struct nfs_fattr new_fattr; - void (*complete)(struct rpc_task *, struct nfs_renamedata *); - long int timeout; - bool cancelled; -}; - -struct nlmclnt_operations; - -struct nfs_access_entry; - -struct nfs_client_initdata; - -struct nfs_rpc_ops { - u32 version; - const struct dentry_operations *dentry_ops; - const struct inode_operations *dir_inode_ops; - const struct inode_operations *file_inode_ops; - const struct file_operations *file_ops; - const struct nlmclnt_operations *nlmclnt_ops; - int (*getroot)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); - int (*submount)(struct fs_context *, struct nfs_server *); - int (*try_get_tree)(struct fs_context *); - int (*getattr)(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *, struct inode *); - int (*setattr)(struct dentry *, struct nfs_fattr *, struct iattr *); - int (*lookup)(struct inode *, struct dentry *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *); - int (*lookupp)(struct inode *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *); - int (*access)(struct inode *, struct nfs_access_entry *); - int (*readlink)(struct inode *, struct page *, unsigned int, unsigned int); - int (*create)(struct inode *, struct dentry *, struct iattr *, int); - int (*remove)(struct inode *, struct dentry *); - void (*unlink_setup)(struct rpc_message *, struct dentry *, struct inode *); - void (*unlink_rpc_prepare)(struct rpc_task *, struct nfs_unlinkdata *); - int (*unlink_done)(struct rpc_task *, struct inode *); - void (*rename_setup)(struct rpc_message *, struct dentry *, struct dentry *); - void (*rename_rpc_prepare)(struct rpc_task *, struct nfs_renamedata *); - int (*rename_done)(struct rpc_task *, struct inode *, struct inode *); - int (*link)(struct inode *, struct inode *, const struct qstr *); - int (*symlink)(struct inode *, struct dentry *, struct page *, unsigned int, struct iattr *); - int (*mkdir)(struct inode *, struct dentry *, struct iattr *); - int (*rmdir)(struct inode *, const struct qstr *); - int (*readdir)(struct dentry *, const struct cred *, u64, struct page **, unsigned int, bool); - int (*mknod)(struct inode *, struct dentry *, struct iattr *, dev_t); - int (*statfs)(struct nfs_server *, struct nfs_fh *, struct nfs_fsstat *); - int (*fsinfo)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); - int (*pathconf)(struct nfs_server *, struct nfs_fh *, struct nfs_pathconf *); - int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); - int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, bool); - int (*pgio_rpc_prepare)(struct rpc_task *, struct nfs_pgio_header *); - void (*read_setup)(struct nfs_pgio_header *, struct rpc_message *); - int (*read_done)(struct rpc_task *, struct nfs_pgio_header *); - void (*write_setup)(struct nfs_pgio_header *, struct rpc_message *, struct rpc_clnt **); - int (*write_done)(struct rpc_task *, struct nfs_pgio_header *); - void (*commit_setup)(struct nfs_commit_data *, struct rpc_message *, struct rpc_clnt **); - void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *); - int (*commit_done)(struct rpc_task *, struct nfs_commit_data *); - int (*lock)(struct file *, int, struct file_lock *); - int (*lock_check_bounds)(const struct file_lock *); - void (*clear_acl_cache)(struct inode *); - void (*close_context)(struct nfs_open_context *, int); - struct inode * (*open_context)(struct inode *, struct nfs_open_context *, int, struct iattr *, int *); - int (*have_delegation)(struct inode *, fmode_t); - struct nfs_client * (*alloc_client)(const struct nfs_client_initdata *); - struct nfs_client * (*init_client)(struct nfs_client *, const struct nfs_client_initdata *); - void (*free_client)(struct nfs_client *); - struct nfs_server * (*create_server)(struct fs_context *); - struct nfs_server * (*clone_server)(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, rpc_authflavor_t); -}; - -struct nlmclnt_operations { - void (*nlmclnt_alloc_call)(void *); - bool (*nlmclnt_unlock_prepare)(struct rpc_task *, void *); - void (*nlmclnt_release_call)(void *); -}; - -struct nfs_access_entry { - struct rb_node rb_node; - struct list_head lru; - const struct cred *cred; - __u32 mask; - struct callback_head callback_head; -}; - -struct nfs_client_initdata { - long unsigned int init_flags; - const char *hostname; - const struct sockaddr *addr; - const char *nodename; - const char *ip_addr; - size_t addrlen; - struct nfs_subversion *nfs_mod; - int proto; - u32 minorversion; - unsigned int nconnect; - struct net *net; - const struct rpc_timeout *timeparms; - const struct cred *cred; -}; - -struct nfs4_state_recovery_ops; - -struct nfs4_state_maintenance_ops; - -struct nfs4_mig_recovery_ops; - -struct nfs4_minor_version_ops { - u32 minor_version; - unsigned int init_caps; - int (*init_client)(struct nfs_client *); - void (*shutdown_client)(struct nfs_client *); - bool (*match_stateid)(const nfs4_stateid *, const nfs4_stateid *); - int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); - void (*free_lock_state)(struct nfs_server *, struct nfs4_lock_state *); - int (*test_and_free_expired)(struct nfs_server *, nfs4_stateid *, const struct cred *); - struct nfs_seqid * (*alloc_seqid)(struct nfs_seqid_counter *, gfp_t); - void (*session_trunk)(struct rpc_clnt *, struct rpc_xprt *, void *); - const struct rpc_call_ops *call_sync_ops; - const struct nfs4_state_recovery_ops *reboot_recovery_ops; - const struct nfs4_state_recovery_ops *nograce_recovery_ops; - const struct nfs4_state_maintenance_ops *state_renewal_ops; - const struct nfs4_mig_recovery_ops *mig_recovery_ops; -}; - -struct nfs4_state_owner; - -struct nfs4_state { - struct list_head open_states; - struct list_head inode_states; - struct list_head lock_states; - struct nfs4_state_owner *owner; - struct inode *inode; - long unsigned int flags; - spinlock_t state_lock; - seqlock_t seqlock; - nfs4_stateid stateid; - nfs4_stateid open_stateid; - unsigned int n_rdonly; - unsigned int n_wronly; - unsigned int n_rdwr; - fmode_t state; - refcount_t count; - wait_queue_head_t waitq; - struct callback_head callback_head; -}; - -struct nfs4_ssc_client_ops; - -struct nfs_ssc_client_ops; - -struct nfs_ssc_client_ops_tbl { - const struct nfs4_ssc_client_ops *ssc_nfs4_ops; - const struct nfs_ssc_client_ops *ssc_nfs_ops; -}; - -struct nfs4_ssc_client_ops { - struct file * (*sco_open)(struct vfsmount *, struct nfs_fh *, nfs4_stateid *); - void (*sco_close)(struct file *); -}; - -struct nfs_ssc_client_ops { - void (*sco_sb_deactive)(struct super_block *); -}; - -struct nfs4_state_recovery_ops { - int owner_flag_bit; - int state_flag_bit; - int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); - int (*recover_lock)(struct nfs4_state *, struct file_lock *); - int (*establish_clid)(struct nfs_client *, const struct cred *); - int (*reclaim_complete)(struct nfs_client *, const struct cred *); - int (*detect_trunking)(struct nfs_client *, struct nfs_client **, const struct cred *); -}; - -struct nfs4_state_maintenance_ops { - int (*sched_state_renewal)(struct nfs_client *, const struct cred *, unsigned int); - const struct cred * (*get_state_renewal_cred)(struct nfs_client *); - int (*renew_lease)(struct nfs_client *, const struct cred *); -}; - -struct nfs4_mig_recovery_ops { - int (*get_locations)(struct inode *, struct nfs4_fs_locations *, struct page *, const struct cred *); - int (*fsid_present)(struct inode *, const struct cred *); -}; - -struct nfs4_state_owner { - struct nfs_server *so_server; - struct list_head so_lru; - long unsigned int so_expires; - struct rb_node so_server_node; - const struct cred *so_cred; - spinlock_t so_lock; - atomic_t so_count; - long unsigned int so_flags; - struct list_head so_states; - struct nfs_seqid_counter so_seqid; - seqcount_spinlock_t so_reclaim_seqcount; - struct mutex so_delegreturn_mutex; -}; - -struct core_name { - char *corename; - int used; - int size; -}; - -struct trace_event_raw_iomap_readpage_class { - struct trace_entry ent; - dev_t dev; - u64 ino; - int nr_pages; - char __data[0]; -}; - -struct trace_event_raw_iomap_range_class { - struct trace_entry ent; - dev_t dev; - u64 ino; - loff_t size; - long unsigned int offset; - unsigned int length; - char __data[0]; -}; - -struct trace_event_raw_iomap_class { - struct trace_entry ent; - dev_t dev; - u64 ino; - u64 addr; - loff_t offset; - u64 length; - u16 type; - u16 flags; - dev_t bdev; - char __data[0]; -}; - -struct trace_event_raw_iomap_apply { - struct trace_entry ent; - dev_t dev; - u64 ino; - loff_t pos; - loff_t length; - unsigned int flags; - const void *ops; - void *actor; - long unsigned int caller; - char __data[0]; -}; - -struct trace_event_data_offsets_iomap_readpage_class {}; - -struct trace_event_data_offsets_iomap_range_class {}; - -struct trace_event_data_offsets_iomap_class {}; - -struct trace_event_data_offsets_iomap_apply {}; - -typedef void (*btf_trace_iomap_readpage)(void *, struct inode *, int); - -typedef void (*btf_trace_iomap_readahead)(void *, struct inode *, int); - -typedef void (*btf_trace_iomap_writepage)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_releasepage)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_invalidatepage)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_dio_invalidate_fail)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_apply_dstmap)(void *, struct inode *, struct iomap___2 *); - -typedef void (*btf_trace_iomap_apply_srcmap)(void *, struct inode *, struct iomap___2 *); - -typedef void (*btf_trace_iomap_apply)(void *, struct inode *, loff_t, loff_t, unsigned int, const void *, void *, long unsigned int); - -struct iomap_ops { - int (*iomap_begin)(struct inode *, loff_t, loff_t, unsigned int, struct iomap___2 *, struct iomap___2 *); - int (*iomap_end)(struct inode *, loff_t, loff_t, ssize_t, unsigned int, struct iomap___2 *); -}; - -typedef loff_t (*iomap_actor_t)(struct inode *, loff_t, loff_t, void *, struct iomap___2 *, struct iomap___2 *); - -struct iomap_ioend { - struct list_head io_list; - u16 io_type; - u16 io_flags; - struct inode *io_inode; - size_t io_size; - loff_t io_offset; - void *io_private; - struct bio *io_bio; - struct bio io_inline_bio; -}; - -struct iomap_writepage_ctx; - -struct iomap_writeback_ops { - int (*map_blocks)(struct iomap_writepage_ctx *, struct inode *, loff_t); - int (*prepare_ioend)(struct iomap_ioend *, int); - void (*discard_page)(struct page *, loff_t); -}; - -struct iomap_writepage_ctx { - struct iomap___2 iomap; - struct iomap_ioend *ioend; - const struct iomap_writeback_ops *ops; -}; - -struct iomap_page { - atomic_t read_bytes_pending; - atomic_t write_bytes_pending; - spinlock_t uptodate_lock; - long unsigned int uptodate[0]; -}; - -struct iomap_readpage_ctx { - struct page *cur_page; - bool cur_page_in_bio; - struct bio *bio; - struct readahead_control *rac; -}; - -enum { - IOMAP_WRITE_F_UNSHARE = 1, -}; - -struct iomap_dio_ops { - int (*end_io)(struct kiocb *, ssize_t, int, unsigned int); - blk_qc_t (*submit_io)(struct inode *, struct iomap___2 *, struct bio *, loff_t); -}; - -struct iomap_dio { - struct kiocb *iocb; - const struct iomap_dio_ops *dops; - loff_t i_size; - loff_t size; - atomic_t ref; - unsigned int flags; - int error; - bool wait_for_completion; - union { - struct { - struct iov_iter *iter; - struct task_struct *waiter; - struct request_queue *last_queue; - blk_qc_t cookie; - } submit; - struct { - struct work_struct work; - } aio; - }; -}; - -struct fiemap_ctx { - struct fiemap_extent_info *fi; - struct iomap___2 prev; -}; - -struct iomap_swapfile_info { - struct iomap___2 iomap; - struct swap_info_struct *sis; - uint64_t lowest_ppage; - uint64_t highest_ppage; - long unsigned int nr_pages; - int nr_extents; -}; - -enum { - QIF_BLIMITS_B = 0, - QIF_SPACE_B = 1, - QIF_ILIMITS_B = 2, - QIF_INODES_B = 3, - QIF_BTIME_B = 4, - QIF_ITIME_B = 5, -}; - -typedef __kernel_uid32_t qid_t; - -enum { - DQF_INFO_DIRTY_B = 17, -}; - -struct dqstats { - long unsigned int stat[8]; - struct percpu_counter counter[8]; -}; - -enum { - _DQUOT_USAGE_ENABLED = 0, - _DQUOT_LIMITS_ENABLED = 1, - _DQUOT_SUSPENDED = 2, - _DQUOT_STATE_FLAGS = 3, -}; - -struct quota_module_name { - int qm_fmt_id; - char *qm_mod_name; -}; - -struct dquot_warn { - struct super_block *w_sb; - struct kqid w_dq_id; - short int w_type; -}; - -struct fs_disk_quota { - __s8 d_version; - __s8 d_flags; - __u16 d_fieldmask; - __u32 d_id; - __u64 d_blk_hardlimit; - __u64 d_blk_softlimit; - __u64 d_ino_hardlimit; - __u64 d_ino_softlimit; - __u64 d_bcount; - __u64 d_icount; - __s32 d_itimer; - __s32 d_btimer; - __u16 d_iwarns; - __u16 d_bwarns; - __s8 d_itimer_hi; - __s8 d_btimer_hi; - __s8 d_rtbtimer_hi; - __s8 d_padding2; - __u64 d_rtb_hardlimit; - __u64 d_rtb_softlimit; - __u64 d_rtbcount; - __s32 d_rtbtimer; - __u16 d_rtbwarns; - __s16 d_padding3; - char d_padding4[8]; -}; - -struct fs_qfilestat { - __u64 qfs_ino; - __u64 qfs_nblks; - __u32 qfs_nextents; -}; - -typedef struct fs_qfilestat fs_qfilestat_t; - -struct fs_quota_stat { - __s8 qs_version; - __u16 qs_flags; - __s8 qs_pad; - fs_qfilestat_t qs_uquota; - fs_qfilestat_t qs_gquota; - __u32 qs_incoredqs; - __s32 qs_btimelimit; - __s32 qs_itimelimit; - __s32 qs_rtbtimelimit; - __u16 qs_bwarnlimit; - __u16 qs_iwarnlimit; -}; - -struct fs_qfilestatv { - __u64 qfs_ino; - __u64 qfs_nblks; - __u32 qfs_nextents; - __u32 qfs_pad; -}; - -struct fs_quota_statv { - __s8 qs_version; - __u8 qs_pad1; - __u16 qs_flags; - __u32 qs_incoredqs; - struct fs_qfilestatv qs_uquota; - struct fs_qfilestatv qs_gquota; - struct fs_qfilestatv qs_pquota; - __s32 qs_btimelimit; - __s32 qs_itimelimit; - __s32 qs_rtbtimelimit; - __u16 qs_bwarnlimit; - __u16 qs_iwarnlimit; - __u64 qs_pad2[8]; -}; - -struct if_dqblk { - __u64 dqb_bhardlimit; - __u64 dqb_bsoftlimit; - __u64 dqb_curspace; - __u64 dqb_ihardlimit; - __u64 dqb_isoftlimit; - __u64 dqb_curinodes; - __u64 dqb_btime; - __u64 dqb_itime; - __u32 dqb_valid; -}; - -struct if_nextdqblk { - __u64 dqb_bhardlimit; - __u64 dqb_bsoftlimit; - __u64 dqb_curspace; - __u64 dqb_ihardlimit; - __u64 dqb_isoftlimit; - __u64 dqb_curinodes; - __u64 dqb_btime; - __u64 dqb_itime; - __u32 dqb_valid; - __u32 dqb_id; -}; - -struct if_dqinfo { - __u64 dqi_bgrace; - __u64 dqi_igrace; - __u32 dqi_flags; - __u32 dqi_valid; -}; - -struct compat_if_dqblk { - compat_u64 dqb_bhardlimit; - compat_u64 dqb_bsoftlimit; - compat_u64 dqb_curspace; - compat_u64 dqb_ihardlimit; - compat_u64 dqb_isoftlimit; - compat_u64 dqb_curinodes; - compat_u64 dqb_btime; - compat_u64 dqb_itime; - compat_uint_t dqb_valid; -}; - -struct proc_maps_private { - struct inode *inode; - struct task_struct *task; - struct mm_struct *mm; - struct vm_area_struct *tail_vma; -}; - -struct mem_size_stats { - long unsigned int resident; - long unsigned int shared_clean; - long unsigned int shared_dirty; - long unsigned int private_clean; - long unsigned int private_dirty; - long unsigned int referenced; - long unsigned int anonymous; - long unsigned int lazyfree; - long unsigned int anonymous_thp; - long unsigned int shmem_thp; - long unsigned int file_thp; - long unsigned int swap; - long unsigned int shared_hugetlb; - long unsigned int private_hugetlb; - u64 pss; - u64 pss_anon; - u64 pss_file; - u64 pss_shmem; - u64 pss_locked; - u64 swap_pss; - bool check_shmem_swap; -}; - -enum clear_refs_types { - CLEAR_REFS_ALL = 1, - CLEAR_REFS_ANON = 2, - CLEAR_REFS_MAPPED = 3, - CLEAR_REFS_SOFT_DIRTY = 4, - CLEAR_REFS_MM_HIWATER_RSS = 5, - CLEAR_REFS_LAST = 6, -}; - -struct clear_refs_private { - enum clear_refs_types type; -}; - -typedef struct { - u64 pme; -} pagemap_entry_t; - -struct pagemapread { - int pos; - int len; - pagemap_entry_t *buffer; - bool show_pfn; -}; - -struct pde_opener { - struct list_head lh; - struct file *file; - bool closing; - struct completion *c; -}; - -enum { - BIAS = 2147483648, -}; - -struct proc_fs_context { - struct pid_namespace *pid_ns; - unsigned int mask; - enum proc_hidepid hidepid; - int gid; - enum proc_pidonly pidonly; -}; - -enum proc_param { - Opt_gid___2 = 0, - Opt_hidepid = 1, - Opt_subset = 2, -}; - -struct genradix_root; - -struct __genradix { - struct genradix_root *root; -}; - -struct syscall_info { - __u64 sp; - struct seccomp_data data; -}; - -typedef struct dentry *instantiate_t(struct dentry *, struct task_struct *, const void *); - -struct pid_entry { - const char *name; - unsigned int len; - umode_t mode; - const struct inode_operations *iop; - const struct file_operations *fop; - union proc_op op; -}; - -struct limit_names { - const char *name; - const char *unit; -}; - -struct map_files_info { - long unsigned int start; - long unsigned int end; - fmode_t mode; -}; - -struct tgid_iter { - unsigned int tgid; - struct task_struct *task; -}; - -struct fd_data { - fmode_t mode; - unsigned int fd; -}; - -struct sysctl_alias { - const char *kernel_param; - const char *sysctl_param; -}; - -struct seq_net_private { - struct net *net; -}; - -struct bpf_iter_aux_info___2; - -struct kernfs_iattrs { - kuid_t ia_uid; - kgid_t ia_gid; - struct timespec64 ia_atime; - struct timespec64 ia_mtime; - struct timespec64 ia_ctime; - struct simple_xattrs xattrs; - atomic_t nr_user_xattrs; - atomic_t user_xattr_size; -}; - -struct kernfs_super_info { - struct super_block *sb; - struct kernfs_root *root; - const void *ns; - struct list_head node; -}; - -enum kernfs_node_flag { - KERNFS_ACTIVATED = 16, - KERNFS_NS = 32, - KERNFS_HAS_SEQ_SHOW = 64, - KERNFS_HAS_MMAP = 128, - KERNFS_LOCKDEP = 256, - KERNFS_SUICIDAL = 1024, - KERNFS_SUICIDED = 2048, - KERNFS_EMPTY_DIR = 4096, - KERNFS_HAS_RELEASE = 8192, -}; - -struct kernfs_open_node { - atomic_t refcnt; - atomic_t event; - wait_queue_head_t poll; - struct list_head files; -}; - -struct config_group; - -struct config_item_type; - -struct config_item { - char *ci_name; - char ci_namebuf[20]; - struct kref ci_kref; - struct list_head ci_entry; - struct config_item *ci_parent; - struct config_group *ci_group; - const struct config_item_type *ci_type; - struct dentry *ci_dentry; -}; - -struct configfs_subsystem; - -struct config_group { - struct config_item cg_item; - struct list_head cg_children; - struct configfs_subsystem *cg_subsys; - struct list_head default_groups; - struct list_head group_entry; -}; - -struct configfs_item_operations; - -struct configfs_group_operations; - -struct configfs_attribute; - -struct configfs_bin_attribute; - -struct config_item_type { - struct module *ct_owner; - struct configfs_item_operations *ct_item_ops; - struct configfs_group_operations *ct_group_ops; - struct configfs_attribute **ct_attrs; - struct configfs_bin_attribute **ct_bin_attrs; -}; - -struct configfs_item_operations { - void (*release)(struct config_item *); - int (*allow_link)(struct config_item *, struct config_item *); - void (*drop_link)(struct config_item *, struct config_item *); -}; - -struct configfs_group_operations { - struct config_item * (*make_item)(struct config_group *, const char *); - struct config_group * (*make_group)(struct config_group *, const char *); - int (*commit_item)(struct config_item *); - void (*disconnect_notify)(struct config_group *, struct config_item *); - void (*drop_item)(struct config_group *, struct config_item *); -}; - -struct configfs_attribute { - const char *ca_name; - struct module *ca_owner; - umode_t ca_mode; - ssize_t (*show)(struct config_item *, char *); - ssize_t (*store)(struct config_item *, const char *, size_t); -}; - -struct configfs_bin_attribute { - struct configfs_attribute cb_attr; - void *cb_private; - size_t cb_max_size; - ssize_t (*read)(struct config_item *, void *, size_t); - ssize_t (*write)(struct config_item *, const void *, size_t); -}; - -struct configfs_subsystem { - struct config_group su_group; - struct mutex su_mutex; -}; - -struct configfs_fragment { - atomic_t frag_count; - struct rw_semaphore frag_sem; - bool frag_dead; -}; - -struct configfs_dirent { - atomic_t s_count; - int s_dependent_count; - struct list_head s_sibling; - struct list_head s_children; - int s_links; - void *s_element; - int s_type; - umode_t s_mode; - struct dentry *s_dentry; - struct iattr *s_iattr; - struct configfs_fragment *s_frag; -}; - -struct configfs_buffer { - size_t count; - loff_t pos; - char *page; - struct configfs_item_operations *ops; - struct mutex mutex; - int needs_read_fill; - bool read_in_progress; - bool write_in_progress; - char *bin_buffer; - int bin_buffer_size; - int cb_max_size; - struct config_item *item; - struct module *owner; - union { - struct configfs_attribute *attr; - struct configfs_bin_attribute *bin_attr; - }; -}; - -struct pts_mount_opts { - int setuid; - int setgid; - kuid_t uid; - kgid_t gid; - umode_t mode; - umode_t ptmxmode; - int reserve; - int max; -}; - -enum { - Opt_uid___2 = 0, - Opt_gid___3 = 1, - Opt_mode___2 = 2, - Opt_ptmxmode = 3, - Opt_newinstance = 4, - Opt_max = 5, - Opt_err = 6, -}; - -struct pts_fs_info { - struct ida allocated_ptys; - struct pts_mount_opts mount_opts; - struct super_block *sb; - struct dentry *ptmx_dentry; -}; - -struct dcookie_struct { - struct path path; - struct list_head hash_list; -}; - -struct dcookie_user { - struct list_head next; -}; - -typedef u16 uint16_t; - -typedef void (*fscache_rw_complete_t)(struct page *, void *, int); - -enum fscache_checkaux { - FSCACHE_CHECKAUX_OKAY = 0, - FSCACHE_CHECKAUX_NEEDS_UPDATE = 1, - FSCACHE_CHECKAUX_OBSOLETE = 2, -}; - -struct fscache_cache_tag; - -struct fscache_cookie_def { - char name[16]; - uint8_t type; - struct fscache_cache_tag * (*select_cache)(const void *, const void *); - enum fscache_checkaux (*check_aux)(void *, const void *, uint16_t, loff_t); - void (*get_context)(void *, void *); - void (*put_context)(void *, void *); - void (*mark_page_cached)(void *, struct address_space *, struct page *); -}; - -struct fscache_cache; - -struct fscache_cache_tag { - struct list_head link; - struct fscache_cache *cache; - long unsigned int flags; - atomic_t usage; - char name[0]; -}; - -struct fscache_cookie { - atomic_t usage; - atomic_t n_children; - atomic_t n_active; - spinlock_t lock; - spinlock_t stores_lock; - struct hlist_head backing_objects; - const struct fscache_cookie_def *def; - struct fscache_cookie *parent; - struct hlist_bl_node hash_link; - void *netfs_data; - struct xarray stores; - long unsigned int flags; - u8 type; - u8 key_len; - u8 aux_len; - u32 key_hash; - union { - void *key; - u8 inline_key[16]; - }; - union { - void *aux; - u8 inline_aux[8]; - }; -}; - -enum fscache_obj_ref_trace { - fscache_obj_get_add_to_deps = 0, - fscache_obj_get_queue = 1, - fscache_obj_put_alloc_fail = 2, - fscache_obj_put_attach_fail = 3, - fscache_obj_put_drop_obj = 4, - fscache_obj_put_enq_dep = 5, - fscache_obj_put_queue = 6, - fscache_obj_put_work = 7, - fscache_obj_ref__nr_traces = 8, -}; - -struct fscache_cache_ops; - -struct fscache_object; - -struct fscache_cache { - const struct fscache_cache_ops *ops; - struct fscache_cache_tag *tag; - struct kobject *kobj; - struct list_head link; - size_t max_index_size; - char identifier[36]; - struct work_struct op_gc; - struct list_head object_list; - struct list_head op_gc_list; - spinlock_t object_list_lock; - spinlock_t op_gc_list_lock; - atomic_t object_count; - struct fscache_object *fsdef; - long unsigned int flags; -}; - -struct fscache_retrieval; - -typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *, struct page *, gfp_t); - -typedef int (*fscache_pages_retrieval_func_t)(struct fscache_retrieval *, struct list_head *, unsigned int *, gfp_t); - -struct fscache_operation; - -struct fscache_storage; - -struct fscache_cache_ops { - const char *name; - struct fscache_object * (*alloc_object)(struct fscache_cache *, struct fscache_cookie *); - int (*lookup_object)(struct fscache_object *); - void (*lookup_complete)(struct fscache_object *); - struct fscache_object * (*grab_object)(struct fscache_object *, enum fscache_obj_ref_trace); - int (*pin_object)(struct fscache_object *); - void (*unpin_object)(struct fscache_object *); - int (*check_consistency)(struct fscache_operation *); - void (*update_object)(struct fscache_object *); - void (*invalidate_object)(struct fscache_operation *); - void (*drop_object)(struct fscache_object *); - void (*put_object)(struct fscache_object *, enum fscache_obj_ref_trace); - void (*sync_cache)(struct fscache_cache *); - int (*attr_changed)(struct fscache_object *); - int (*reserve_space)(struct fscache_object *, loff_t); - fscache_page_retrieval_func_t read_or_alloc_page; - fscache_pages_retrieval_func_t read_or_alloc_pages; - fscache_page_retrieval_func_t allocate_page; - fscache_pages_retrieval_func_t allocate_pages; - int (*write_page)(struct fscache_storage *, struct page *); - void (*uncache_page)(struct fscache_object *, struct page *); - void (*dissociate_pages)(struct fscache_cache *); -}; - -struct fscache_state; - -struct fscache_transition; - -struct fscache_object { - const struct fscache_state *state; - const struct fscache_transition *oob_table; - int debug_id; - int n_children; - int n_ops; - int n_obj_ops; - int n_in_progress; - int n_exclusive; - atomic_t n_reads; - spinlock_t lock; - long unsigned int lookup_jif; - long unsigned int oob_event_mask; - long unsigned int event_mask; - long unsigned int events; - long unsigned int flags; - struct list_head cache_link; - struct hlist_node cookie_link; - struct fscache_cache *cache; - struct fscache_cookie *cookie; - struct fscache_object *parent; - struct work_struct work; - struct list_head dependents; - struct list_head dep_link; - struct list_head pending_ops; - long unsigned int store_limit; - loff_t store_limit_l; -}; - -typedef void (*fscache_operation_release_t)(struct fscache_operation *); - -enum fscache_operation_state { - FSCACHE_OP_ST_BLANK = 0, - FSCACHE_OP_ST_INITIALISED = 1, - FSCACHE_OP_ST_PENDING = 2, - FSCACHE_OP_ST_IN_PROGRESS = 3, - FSCACHE_OP_ST_COMPLETE = 4, - FSCACHE_OP_ST_CANCELLED = 5, - FSCACHE_OP_ST_DEAD = 6, -}; - -typedef void (*fscache_operation_processor_t)(struct fscache_operation *); - -typedef void (*fscache_operation_cancel_t)(struct fscache_operation *); - -struct fscache_operation { - struct work_struct work; - struct list_head pend_link; - struct fscache_object *object; - long unsigned int flags; - enum fscache_operation_state state; - atomic_t usage; - unsigned int debug_id; - fscache_operation_processor_t processor; - fscache_operation_cancel_t cancel; - fscache_operation_release_t release; -}; - -struct fscache_retrieval { - struct fscache_operation op; - struct fscache_cookie *cookie; - struct address_space *mapping; - fscache_rw_complete_t end_io_func; - void *context; - struct list_head to_do; - long unsigned int start_time; - atomic_t n_pages; -}; - -struct fscache_storage { - struct fscache_operation op; - long unsigned int store_limit; -}; - -enum { - FSCACHE_OBJECT_EV_NEW_CHILD = 0, - FSCACHE_OBJECT_EV_PARENT_READY = 1, - FSCACHE_OBJECT_EV_UPDATE = 2, - FSCACHE_OBJECT_EV_INVALIDATE = 3, - FSCACHE_OBJECT_EV_CLEARED = 4, - FSCACHE_OBJECT_EV_ERROR = 5, - FSCACHE_OBJECT_EV_KILL = 6, - NR_FSCACHE_OBJECT_EVENTS = 7, -}; - -struct fscache_transition { - long unsigned int events; - const struct fscache_state *transit_to; -}; - -struct fscache_state { - char name[24]; - char short_name[8]; - const struct fscache_state * (*work)(struct fscache_object *, int); - const struct fscache_transition transitions[0]; -}; - -enum fscache_cookie_trace { - fscache_cookie_collision = 0, - fscache_cookie_discard = 1, - fscache_cookie_get_acquire_parent = 2, - fscache_cookie_get_attach_object = 3, - fscache_cookie_get_reacquire = 4, - fscache_cookie_get_register_netfs = 5, - fscache_cookie_put_acquire_nobufs = 6, - fscache_cookie_put_dup_netfs = 7, - fscache_cookie_put_relinquish = 8, - fscache_cookie_put_object = 9, - fscache_cookie_put_parent = 10, -}; - -enum fscache_page_op_trace { - fscache_page_op_alloc_one = 0, - fscache_page_op_attr_changed = 1, - fscache_page_op_check_consistency = 2, - fscache_page_op_invalidate = 3, - fscache_page_op_retr_multi = 4, - fscache_page_op_retr_one = 5, - fscache_page_op_write_one = 6, - fscache_page_op_trace__nr = 7, -}; - -struct fscache_netfs { - uint32_t version; - const char *name; - struct fscache_cookie *primary_index; -}; - -enum fscache_page_trace { - fscache_page_cached = 0, - fscache_page_inval = 1, - fscache_page_maybe_release = 2, - fscache_page_radix_clear_store = 3, - fscache_page_radix_delete = 4, - fscache_page_radix_insert = 5, - fscache_page_radix_pend2store = 6, - fscache_page_radix_set_pend = 7, - fscache_page_uncache = 8, - fscache_page_write = 9, - fscache_page_write_end = 10, - fscache_page_write_end_pend = 11, - fscache_page_write_end_noc = 12, - fscache_page_write_wait = 13, - fscache_page_trace__nr = 14, -}; - -enum fscache_op_trace { - fscache_op_cancel = 0, - fscache_op_cancel_all = 1, - fscache_op_cancelled = 2, - fscache_op_completed = 3, - fscache_op_enqueue_async = 4, - fscache_op_enqueue_mythread = 5, - fscache_op_gc = 6, - fscache_op_init = 7, - fscache_op_put = 8, - fscache_op_run = 9, - fscache_op_signal = 10, - fscache_op_submit = 11, - fscache_op_submit_ex = 12, - fscache_op_work = 13, - fscache_op_trace__nr = 14, -}; - -struct trace_event_raw_fscache_cookie { - struct trace_entry ent; - struct fscache_cookie *cookie; - struct fscache_cookie *parent; - enum fscache_cookie_trace where; - int usage; - int n_children; - int n_active; - u8 flags; - char __data[0]; -}; - -struct trace_event_raw_fscache_netfs { - struct trace_entry ent; - struct fscache_cookie *cookie; - char name[8]; - char __data[0]; -}; - -struct trace_event_raw_fscache_acquire { - struct trace_entry ent; - struct fscache_cookie *cookie; - struct fscache_cookie *parent; - char name[8]; - int p_usage; - int p_n_children; - u8 p_flags; - char __data[0]; -}; - -struct trace_event_raw_fscache_relinquish { - struct trace_entry ent; - struct fscache_cookie *cookie; - struct fscache_cookie *parent; - int usage; - int n_children; - int n_active; - u8 flags; - bool retire; - char __data[0]; -}; - -struct trace_event_raw_fscache_enable { - struct trace_entry ent; - struct fscache_cookie *cookie; - int usage; - int n_children; - int n_active; - u8 flags; - char __data[0]; -}; - -struct trace_event_raw_fscache_disable { - struct trace_entry ent; - struct fscache_cookie *cookie; - int usage; - int n_children; - int n_active; - u8 flags; - char __data[0]; -}; - -struct trace_event_raw_fscache_osm { - struct trace_entry ent; - struct fscache_cookie *cookie; - struct fscache_object *object; - char state[8]; - bool wait; - bool oob; - s8 event_num; - char __data[0]; -}; - -struct trace_event_raw_fscache_page { - struct trace_entry ent; - struct fscache_cookie *cookie; - long unsigned int page; - enum fscache_page_trace why; - char __data[0]; -}; - -struct trace_event_raw_fscache_check_page { - struct trace_entry ent; - struct fscache_cookie *cookie; - void *page; - void *val; - int n; - char __data[0]; -}; - -struct trace_event_raw_fscache_wake_cookie { - struct trace_entry ent; - struct fscache_cookie *cookie; - char __data[0]; -}; - -struct trace_event_raw_fscache_op { - struct trace_entry ent; - struct fscache_cookie *cookie; - struct fscache_operation *op; - enum fscache_op_trace why; - char __data[0]; -}; - -struct trace_event_raw_fscache_page_op { - struct trace_entry ent; - struct fscache_cookie *cookie; - long unsigned int page; - struct fscache_operation *op; - enum fscache_page_op_trace what; - char __data[0]; -}; - -struct trace_event_raw_fscache_wrote_page { - struct trace_entry ent; - struct fscache_cookie *cookie; - long unsigned int page; - struct fscache_operation *op; - int ret; - char __data[0]; -}; - -struct trace_event_raw_fscache_gang_lookup { - struct trace_entry ent; - struct fscache_cookie *cookie; - struct fscache_operation *op; - long unsigned int results0; - int n; - long unsigned int store_limit; - char __data[0]; -}; - -struct trace_event_data_offsets_fscache_cookie {}; - -struct trace_event_data_offsets_fscache_netfs {}; - -struct trace_event_data_offsets_fscache_acquire {}; - -struct trace_event_data_offsets_fscache_relinquish {}; - -struct trace_event_data_offsets_fscache_enable {}; - -struct trace_event_data_offsets_fscache_disable {}; - -struct trace_event_data_offsets_fscache_osm {}; - -struct trace_event_data_offsets_fscache_page {}; - -struct trace_event_data_offsets_fscache_check_page {}; - -struct trace_event_data_offsets_fscache_wake_cookie {}; - -struct trace_event_data_offsets_fscache_op {}; - -struct trace_event_data_offsets_fscache_page_op {}; - -struct trace_event_data_offsets_fscache_wrote_page {}; - -struct trace_event_data_offsets_fscache_gang_lookup {}; - -typedef void (*btf_trace_fscache_cookie)(void *, struct fscache_cookie *, enum fscache_cookie_trace, int); - -typedef void (*btf_trace_fscache_netfs)(void *, struct fscache_netfs *); - -typedef void (*btf_trace_fscache_acquire)(void *, struct fscache_cookie *); - -typedef void (*btf_trace_fscache_relinquish)(void *, struct fscache_cookie *, bool); - -typedef void (*btf_trace_fscache_enable)(void *, struct fscache_cookie *); - -typedef void (*btf_trace_fscache_disable)(void *, struct fscache_cookie *); - -typedef void (*btf_trace_fscache_osm)(void *, struct fscache_object *, const struct fscache_state *, bool, bool, s8); - -typedef void (*btf_trace_fscache_page)(void *, struct fscache_cookie *, struct page *, enum fscache_page_trace); - -typedef void (*btf_trace_fscache_check_page)(void *, struct fscache_cookie *, struct page *, void *, int); - -typedef void (*btf_trace_fscache_wake_cookie)(void *, struct fscache_cookie *); - -typedef void (*btf_trace_fscache_op)(void *, struct fscache_cookie *, struct fscache_operation *, enum fscache_op_trace); - -typedef void (*btf_trace_fscache_page_op)(void *, struct fscache_cookie *, struct page *, struct fscache_operation *, enum fscache_page_op_trace); - -typedef void (*btf_trace_fscache_wrote_page)(void *, struct fscache_cookie *, struct page *, struct fscache_operation *, int); - -typedef void (*btf_trace_fscache_gang_lookup)(void *, struct fscache_cookie *, struct fscache_operation *, void **, int, long unsigned int); - -enum fscache_why_object_killed { - FSCACHE_OBJECT_IS_STALE = 0, - FSCACHE_OBJECT_NO_SPACE = 1, - FSCACHE_OBJECT_WAS_RETIRED = 2, - FSCACHE_OBJECT_WAS_CULLED = 3, -}; - -typedef unsigned int tid_t; - -struct transaction_chp_stats_s { - long unsigned int cs_chp_time; - __u32 cs_forced_to_close; - __u32 cs_written; - __u32 cs_dropped; -}; - -struct journal_s; - -typedef struct journal_s journal_t; - -struct journal_head; - -struct transaction_s; - -typedef struct transaction_s transaction_t; - -struct transaction_s { - journal_t *t_journal; - tid_t t_tid; - enum { - T_RUNNING = 0, - T_LOCKED = 1, - T_SWITCH = 2, - T_FLUSH = 3, - T_COMMIT = 4, - T_COMMIT_DFLUSH = 5, - T_COMMIT_JFLUSH = 6, - T_COMMIT_CALLBACK = 7, - T_FINISHED = 8, - } t_state; - long unsigned int t_log_start; - int t_nr_buffers; - struct journal_head *t_reserved_list; - struct journal_head *t_buffers; - struct journal_head *t_forget; - struct journal_head *t_checkpoint_list; - struct journal_head *t_checkpoint_io_list; - struct journal_head *t_shadow_list; - struct list_head t_inode_list; - spinlock_t t_handle_lock; - long unsigned int t_max_wait; - long unsigned int t_start; - long unsigned int t_requested; - struct transaction_chp_stats_s t_chp_stats; - atomic_t t_updates; - atomic_t t_outstanding_credits; - atomic_t t_outstanding_revokes; - atomic_t t_handle_count; - transaction_t *t_cpnext; - transaction_t *t_cpprev; - long unsigned int t_expires; - ktime_t t_start_time; - unsigned int t_synchronous_commit: 1; - int t_need_data_flush; - struct list_head t_private_list; -}; - -struct jbd2_buffer_trigger_type; - -struct journal_head { - struct buffer_head *b_bh; - spinlock_t b_state_lock; - int b_jcount; - unsigned int b_jlist; - unsigned int b_modified; - char *b_frozen_data; - char *b_committed_data; - transaction_t *b_transaction; - transaction_t *b_next_transaction; - struct journal_head *b_tnext; - struct journal_head *b_tprev; - transaction_t *b_cp_transaction; - struct journal_head *b_cpnext; - struct journal_head *b_cpprev; - struct jbd2_buffer_trigger_type *b_triggers; - struct jbd2_buffer_trigger_type *b_frozen_triggers; -}; - -struct jbd2_buffer_trigger_type { - void (*t_frozen)(struct jbd2_buffer_trigger_type *, struct buffer_head *, void *, size_t); - void (*t_abort)(struct jbd2_buffer_trigger_type *, struct buffer_head *); -}; - -struct jbd2_journal_handle; - -typedef struct jbd2_journal_handle handle_t; - -struct jbd2_journal_handle { - union { - transaction_t *h_transaction; - journal_t *h_journal; - }; - handle_t *h_rsv_handle; - int h_total_credits; - int h_revoke_credits; - int h_revoke_credits_requested; - int h_ref; - int h_err; - unsigned int h_sync: 1; - unsigned int h_jdata: 1; - unsigned int h_reserved: 1; - unsigned int h_aborted: 1; - unsigned int h_type: 8; - unsigned int h_line_no: 16; - long unsigned int h_start_jiffies; - unsigned int h_requested_credits; - unsigned int saved_alloc_context; -}; - -struct transaction_run_stats_s { - long unsigned int rs_wait; - long unsigned int rs_request_delay; - long unsigned int rs_running; - long unsigned int rs_locked; - long unsigned int rs_flushing; - long unsigned int rs_logging; - __u32 rs_handle_count; - __u32 rs_blocks; - __u32 rs_blocks_logged; -}; - -struct transaction_stats_s { - long unsigned int ts_tid; - long unsigned int ts_requested; - struct transaction_run_stats_s run; -}; - -enum passtype { - PASS_SCAN = 0, - PASS_REVOKE = 1, - PASS_REPLAY = 2, -}; - -struct journal_superblock_s; - -typedef struct journal_superblock_s journal_superblock_t; - -struct jbd2_revoke_table_s; - -struct jbd2_inode; - -struct journal_s { - long unsigned int j_flags; - int j_errno; - struct mutex j_abort_mutex; - struct buffer_head *j_sb_buffer; - journal_superblock_t *j_superblock; - int j_format_version; - rwlock_t j_state_lock; - int j_barrier_count; - struct mutex j_barrier; - transaction_t *j_running_transaction; - transaction_t *j_committing_transaction; - transaction_t *j_checkpoint_transactions; - wait_queue_head_t j_wait_transaction_locked; - wait_queue_head_t j_wait_done_commit; - wait_queue_head_t j_wait_commit; - wait_queue_head_t j_wait_updates; - wait_queue_head_t j_wait_reserved; - wait_queue_head_t j_fc_wait; - struct mutex j_checkpoint_mutex; - struct buffer_head *j_chkpt_bhs[64]; - long unsigned int j_head; - long unsigned int j_tail; - long unsigned int j_free; - long unsigned int j_first; - long unsigned int j_last; - long unsigned int j_fc_first; - long unsigned int j_fc_off; - long unsigned int j_fc_last; - struct block_device *j_dev; - int j_blocksize; - long long unsigned int j_blk_offset; - char j_devname[56]; - struct block_device *j_fs_dev; - unsigned int j_total_len; - atomic_t j_reserved_credits; - spinlock_t j_list_lock; - struct inode *j_inode; - tid_t j_tail_sequence; - tid_t j_transaction_sequence; - tid_t j_commit_sequence; - tid_t j_commit_request; - __u8 j_uuid[16]; - struct task_struct *j_task; - int j_max_transaction_buffers; - int j_revoke_records_per_block; - long unsigned int j_commit_interval; - struct timer_list j_commit_timer; - spinlock_t j_revoke_lock; - struct jbd2_revoke_table_s *j_revoke; - struct jbd2_revoke_table_s *j_revoke_table[2]; - struct buffer_head **j_wbuf; - struct buffer_head **j_fc_wbuf; - int j_wbufsize; - int j_fc_wbufsize; - pid_t j_last_sync_writer; - u64 j_average_commit_time; - u32 j_min_batch_time; - u32 j_max_batch_time; - void (*j_commit_callback)(journal_t *, transaction_t *); - int (*j_submit_inode_data_buffers)(struct jbd2_inode *); - int (*j_finish_inode_data_buffers)(struct jbd2_inode *); - spinlock_t j_history_lock; - struct proc_dir_entry *j_proc_entry; - struct transaction_stats_s j_stats; - unsigned int j_failed_commit; - void *j_private; - struct crypto_shash *j_chksum_driver; - __u32 j_csum_seed; - void (*j_fc_cleanup_callback)(struct journal_s *, int); - int (*j_fc_replay_callback)(struct journal_s *, struct buffer_head *, enum passtype, int, tid_t); -}; - -struct journal_header_s { - __be32 h_magic; - __be32 h_blocktype; - __be32 h_sequence; -}; - -typedef struct journal_header_s journal_header_t; - -struct journal_superblock_s { - journal_header_t s_header; - __be32 s_blocksize; - __be32 s_maxlen; - __be32 s_first; - __be32 s_sequence; - __be32 s_start; - __be32 s_errno; - __be32 s_feature_compat; - __be32 s_feature_incompat; - __be32 s_feature_ro_compat; - __u8 s_uuid[16]; - __be32 s_nr_users; - __be32 s_dynsuper; - __be32 s_max_transaction; - __be32 s_max_trans_data; - __u8 s_checksum_type; - __u8 s_padding2[3]; - __be32 s_num_fc_blks; - __u32 s_padding[41]; - __be32 s_checksum; - __u8 s_users[768]; -}; - -enum jbd_state_bits { - BH_JBD = 16, - BH_JWrite = 17, - BH_Freed = 18, - BH_Revoked = 19, - BH_RevokeValid = 20, - BH_JBDDirty = 21, - BH_JournalHead = 22, - BH_Shadow = 23, - BH_Verified = 24, - BH_JBDPrivateStart = 25, -}; - -struct jbd2_inode { - transaction_t *i_transaction; - transaction_t *i_next_transaction; - struct list_head i_list; - struct inode *i_vfs_inode; - long unsigned int i_flags; - loff_t i_dirty_start; - loff_t i_dirty_end; -}; - -struct bgl_lock { - spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct blockgroup_lock { - struct bgl_lock locks[128]; -}; - -typedef int ext4_grpblk_t; - -typedef long long unsigned int ext4_fsblk_t; - -typedef __u32 ext4_lblk_t; - -typedef unsigned int ext4_group_t; - -struct ext4_allocation_request { - struct inode *inode; - unsigned int len; - ext4_lblk_t logical; - ext4_lblk_t lleft; - ext4_lblk_t lright; - ext4_fsblk_t goal; - ext4_fsblk_t pleft; - ext4_fsblk_t pright; - unsigned int flags; -}; - -struct ext4_system_blocks { - struct rb_root root; - struct callback_head rcu; -}; - -struct ext4_group_desc { - __le32 bg_block_bitmap_lo; - __le32 bg_inode_bitmap_lo; - __le32 bg_inode_table_lo; - __le16 bg_free_blocks_count_lo; - __le16 bg_free_inodes_count_lo; - __le16 bg_used_dirs_count_lo; - __le16 bg_flags; - __le32 bg_exclude_bitmap_lo; - __le16 bg_block_bitmap_csum_lo; - __le16 bg_inode_bitmap_csum_lo; - __le16 bg_itable_unused_lo; - __le16 bg_checksum; - __le32 bg_block_bitmap_hi; - __le32 bg_inode_bitmap_hi; - __le32 bg_inode_table_hi; - __le16 bg_free_blocks_count_hi; - __le16 bg_free_inodes_count_hi; - __le16 bg_used_dirs_count_hi; - __le16 bg_itable_unused_hi; - __le32 bg_exclude_bitmap_hi; - __le16 bg_block_bitmap_csum_hi; - __le16 bg_inode_bitmap_csum_hi; - __u32 bg_reserved; -}; - -struct flex_groups { - atomic64_t free_clusters; - atomic_t free_inodes; - atomic_t used_dirs; -}; - -struct extent_status { - struct rb_node rb_node; - ext4_lblk_t es_lblk; - ext4_lblk_t es_len; - ext4_fsblk_t es_pblk; -}; - -struct ext4_es_tree { - struct rb_root root; - struct extent_status *cache_es; -}; - -struct ext4_es_stats { - long unsigned int es_stats_shrunk; - struct percpu_counter es_stats_cache_hits; - struct percpu_counter es_stats_cache_misses; - u64 es_stats_scan_time; - u64 es_stats_max_scan_time; - struct percpu_counter es_stats_all_cnt; - struct percpu_counter es_stats_shk_cnt; -}; - -struct ext4_pending_tree { - struct rb_root root; -}; - -struct ext4_fc_stats { - unsigned int fc_ineligible_reason_count[10]; - long unsigned int fc_num_commits; - long unsigned int fc_ineligible_commits; - long unsigned int fc_numblks; -}; - -struct ext4_fc_alloc_region { - ext4_lblk_t lblk; - ext4_fsblk_t pblk; - int ino; - int len; -}; - -struct ext4_fc_replay_state { - int fc_replay_num_tags; - int fc_replay_expected_off; - int fc_current_pass; - int fc_cur_tag; - int fc_crc; - struct ext4_fc_alloc_region *fc_regions; - int fc_regions_size; - int fc_regions_used; - int fc_regions_valid; - int *fc_modified_inodes; - int fc_modified_inodes_used; - int fc_modified_inodes_size; -}; - -struct ext4_inode_info { - __le32 i_data[15]; - __u32 i_dtime; - ext4_fsblk_t i_file_acl; - ext4_group_t i_block_group; - ext4_lblk_t i_dir_start_lookup; - long unsigned int i_flags; - struct rw_semaphore xattr_sem; - struct list_head i_orphan; - struct list_head i_fc_list; - ext4_lblk_t i_fc_lblk_start; - ext4_lblk_t i_fc_lblk_len; - atomic_t i_fc_updates; - wait_queue_head_t i_fc_wait; - struct mutex i_fc_lock; - loff_t i_disksize; - struct rw_semaphore i_data_sem; - struct rw_semaphore i_mmap_sem; - struct inode vfs_inode; - struct jbd2_inode *jinode; - spinlock_t i_raw_lock; - struct timespec64 i_crtime; - atomic_t i_prealloc_active; - struct list_head i_prealloc_list; - spinlock_t i_prealloc_lock; - struct ext4_es_tree i_es_tree; - rwlock_t i_es_lock; - struct list_head i_es_list; - unsigned int i_es_all_nr; - unsigned int i_es_shk_nr; - ext4_lblk_t i_es_shrink_lblk; - ext4_group_t i_last_alloc_group; - unsigned int i_reserved_data_blocks; - struct ext4_pending_tree i_pending_tree; - __u16 i_extra_isize; - u16 i_inline_off; - u16 i_inline_size; - qsize_t i_reserved_quota; - spinlock_t i_completed_io_lock; - struct list_head i_rsv_conversion_list; - struct work_struct i_rsv_conversion_work; - atomic_t i_unwritten; - spinlock_t i_block_reservation_lock; - tid_t i_sync_tid; - tid_t i_datasync_tid; - struct dquot *i_dquot[3]; - __u32 i_csum_seed; - kprojid_t i_projid; -}; - -struct ext4_super_block { - __le32 s_inodes_count; - __le32 s_blocks_count_lo; - __le32 s_r_blocks_count_lo; - __le32 s_free_blocks_count_lo; - __le32 s_free_inodes_count; - __le32 s_first_data_block; - __le32 s_log_block_size; - __le32 s_log_cluster_size; - __le32 s_blocks_per_group; - __le32 s_clusters_per_group; - __le32 s_inodes_per_group; - __le32 s_mtime; - __le32 s_wtime; - __le16 s_mnt_count; - __le16 s_max_mnt_count; - __le16 s_magic; - __le16 s_state; - __le16 s_errors; - __le16 s_minor_rev_level; - __le32 s_lastcheck; - __le32 s_checkinterval; - __le32 s_creator_os; - __le32 s_rev_level; - __le16 s_def_resuid; - __le16 s_def_resgid; - __le32 s_first_ino; - __le16 s_inode_size; - __le16 s_block_group_nr; - __le32 s_feature_compat; - __le32 s_feature_incompat; - __le32 s_feature_ro_compat; - __u8 s_uuid[16]; - char s_volume_name[16]; - char s_last_mounted[64]; - __le32 s_algorithm_usage_bitmap; - __u8 s_prealloc_blocks; - __u8 s_prealloc_dir_blocks; - __le16 s_reserved_gdt_blocks; - __u8 s_journal_uuid[16]; - __le32 s_journal_inum; - __le32 s_journal_dev; - __le32 s_last_orphan; - __le32 s_hash_seed[4]; - __u8 s_def_hash_version; - __u8 s_jnl_backup_type; - __le16 s_desc_size; - __le32 s_default_mount_opts; - __le32 s_first_meta_bg; - __le32 s_mkfs_time; - __le32 s_jnl_blocks[17]; - __le32 s_blocks_count_hi; - __le32 s_r_blocks_count_hi; - __le32 s_free_blocks_count_hi; - __le16 s_min_extra_isize; - __le16 s_want_extra_isize; - __le32 s_flags; - __le16 s_raid_stride; - __le16 s_mmp_update_interval; - __le64 s_mmp_block; - __le32 s_raid_stripe_width; - __u8 s_log_groups_per_flex; - __u8 s_checksum_type; - __u8 s_encryption_level; - __u8 s_reserved_pad; - __le64 s_kbytes_written; - __le32 s_snapshot_inum; - __le32 s_snapshot_id; - __le64 s_snapshot_r_blocks_count; - __le32 s_snapshot_list; - __le32 s_error_count; - __le32 s_first_error_time; - __le32 s_first_error_ino; - __le64 s_first_error_block; - __u8 s_first_error_func[32]; - __le32 s_first_error_line; - __le32 s_last_error_time; - __le32 s_last_error_ino; - __le32 s_last_error_line; - __le64 s_last_error_block; - __u8 s_last_error_func[32]; - __u8 s_mount_opts[64]; - __le32 s_usr_quota_inum; - __le32 s_grp_quota_inum; - __le32 s_overhead_clusters; - __le32 s_backup_bgs[2]; - __u8 s_encrypt_algos[4]; - __u8 s_encrypt_pw_salt[16]; - __le32 s_lpf_ino; - __le32 s_prj_quota_inum; - __le32 s_checksum_seed; - __u8 s_wtime_hi; - __u8 s_mtime_hi; - __u8 s_mkfs_time_hi; - __u8 s_lastcheck_hi; - __u8 s_first_error_time_hi; - __u8 s_last_error_time_hi; - __u8 s_first_error_errcode; - __u8 s_last_error_errcode; - __le16 s_encoding; - __le16 s_encoding_flags; - __le32 s_reserved[95]; - __le32 s_checksum; -}; - -struct mb_cache___2; - -struct ext4_group_info; - -struct ext4_locality_group; - -struct ext4_li_request; - -struct ext4_sb_info { - long unsigned int s_desc_size; - long unsigned int s_inodes_per_block; - long unsigned int s_blocks_per_group; - long unsigned int s_clusters_per_group; - long unsigned int s_inodes_per_group; - long unsigned int s_itb_per_group; - long unsigned int s_gdb_count; - long unsigned int s_desc_per_block; - ext4_group_t s_groups_count; - ext4_group_t s_blockfile_groups; - long unsigned int s_overhead; - unsigned int s_cluster_ratio; - unsigned int s_cluster_bits; - loff_t s_bitmap_maxbytes; - struct buffer_head *s_sbh; - struct ext4_super_block *s_es; - struct buffer_head **s_group_desc; - unsigned int s_mount_opt; - unsigned int s_mount_opt2; - long unsigned int s_mount_flags; - unsigned int s_def_mount_opt; - ext4_fsblk_t s_sb_block; - atomic64_t s_resv_clusters; - kuid_t s_resuid; - kgid_t s_resgid; - short unsigned int s_mount_state; - short unsigned int s_pad; - int s_addr_per_block_bits; - int s_desc_per_block_bits; - int s_inode_size; - int s_first_ino; - unsigned int s_inode_readahead_blks; - unsigned int s_inode_goal; - u32 s_hash_seed[4]; - int s_def_hash_version; - int s_hash_unsigned; - struct percpu_counter s_freeclusters_counter; - struct percpu_counter s_freeinodes_counter; - struct percpu_counter s_dirs_counter; - struct percpu_counter s_dirtyclusters_counter; - struct percpu_counter s_sra_exceeded_retry_limit; - struct blockgroup_lock *s_blockgroup_lock; - struct proc_dir_entry *s_proc; - struct kobject s_kobj; - struct completion s_kobj_unregister; - struct super_block *s_sb; - struct buffer_head *s_mmp_bh; - struct journal_s *s_journal; - struct list_head s_orphan; - struct mutex s_orphan_lock; - long unsigned int s_ext4_flags; - long unsigned int s_commit_interval; - u32 s_max_batch_time; - u32 s_min_batch_time; - struct block_device *s_journal_bdev; - char *s_qf_names[3]; - int s_jquota_fmt; - unsigned int s_want_extra_isize; - struct ext4_system_blocks *s_system_blks; - struct ext4_group_info ***s_group_info; - struct inode *s_buddy_cache; - spinlock_t s_md_lock; - short unsigned int *s_mb_offsets; - unsigned int *s_mb_maxs; - unsigned int s_group_info_size; - unsigned int s_mb_free_pending; - struct list_head s_freed_data_list; - long unsigned int s_stripe; - unsigned int s_mb_stream_request; - unsigned int s_mb_max_to_scan; - unsigned int s_mb_min_to_scan; - unsigned int s_mb_stats; - unsigned int s_mb_order2_reqs; - unsigned int s_mb_group_prealloc; - unsigned int s_mb_max_inode_prealloc; - unsigned int s_max_dir_size_kb; - long unsigned int s_mb_last_group; - long unsigned int s_mb_last_start; - unsigned int s_mb_prefetch; - unsigned int s_mb_prefetch_limit; - atomic_t s_bal_reqs; - atomic_t s_bal_success; - atomic_t s_bal_allocated; - atomic_t s_bal_ex_scanned; - atomic_t s_bal_goals; - atomic_t s_bal_breaks; - atomic_t s_bal_2orders; - spinlock_t s_bal_lock; - long unsigned int s_mb_buddies_generated; - long long unsigned int s_mb_generation_time; - atomic_t s_mb_lost_chunks; - atomic_t s_mb_preallocated; - atomic_t s_mb_discarded; - atomic_t s_lock_busy; - struct ext4_locality_group *s_locality_groups; - long unsigned int s_sectors_written_start; - u64 s_kbytes_written; - unsigned int s_extent_max_zeroout_kb; - unsigned int s_log_groups_per_flex; - struct flex_groups **s_flex_groups; - ext4_group_t s_flex_groups_allocated; - struct workqueue_struct *rsv_conversion_wq; - struct timer_list s_err_report; - struct ext4_li_request *s_li_request; - unsigned int s_li_wait_mult; - struct task_struct *s_mmp_tsk; - atomic_t s_last_trim_minblks; - struct crypto_shash *s_chksum_driver; - __u32 s_csum_seed; - struct shrinker s_es_shrinker; - struct list_head s_es_list; - long int s_es_nr_inode; - struct ext4_es_stats s_es_stats; - struct mb_cache___2 *s_ea_block_cache; - struct mb_cache___2 *s_ea_inode_cache; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t s_es_lock; - struct ratelimit_state s_err_ratelimit_state; - struct ratelimit_state s_warning_ratelimit_state; - struct ratelimit_state s_msg_ratelimit_state; - atomic_t s_warning_count; - atomic_t s_msg_count; - struct fscrypt_dummy_policy s_dummy_enc_policy; - struct percpu_rw_semaphore s_writepages_rwsem; - struct dax_device *s_daxdev; - errseq_t s_bdev_wb_err; - spinlock_t s_bdev_wb_lock; - atomic_t s_fc_subtid; - atomic_t s_fc_ineligible_updates; - struct list_head s_fc_q[2]; - struct list_head s_fc_dentry_q[2]; - unsigned int s_fc_bytes; - spinlock_t s_fc_lock; - struct buffer_head *s_fc_bh; - struct ext4_fc_stats s_fc_stats; - u64 s_fc_avg_commit_time; - struct ext4_fc_replay_state s_fc_replay_state; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct ext4_group_info { - long unsigned int bb_state; - struct rb_root bb_free_root; - ext4_grpblk_t bb_first_free; - ext4_grpblk_t bb_free; - ext4_grpblk_t bb_fragments; - ext4_grpblk_t bb_largest_free_order; - struct list_head bb_prealloc_list; - struct rw_semaphore alloc_sem; - ext4_grpblk_t bb_counters[0]; -}; - -struct ext4_locality_group { - struct mutex lg_mutex; - struct list_head lg_prealloc_list[10]; - spinlock_t lg_prealloc_lock; -}; - -enum ext4_li_mode { - EXT4_LI_MODE_PREFETCH_BBITMAP = 0, - EXT4_LI_MODE_ITABLE = 1, -}; - -struct ext4_li_request { - struct super_block *lr_super; - enum ext4_li_mode lr_mode; - ext4_group_t lr_first_not_zeroed; - ext4_group_t lr_next_group; - struct list_head lr_request; - long unsigned int lr_next_sched; - long unsigned int lr_timeout; -}; - -struct ext4_map_blocks { - ext4_fsblk_t m_pblk; - ext4_lblk_t m_lblk; - unsigned int m_len; - unsigned int m_flags; -}; - -struct ext4_system_zone { - struct rb_node node; - ext4_fsblk_t start_blk; - unsigned int count; - u32 ino; -}; - -enum { - EXT4_INODE_SECRM = 0, - EXT4_INODE_UNRM = 1, - EXT4_INODE_COMPR = 2, - EXT4_INODE_SYNC = 3, - EXT4_INODE_IMMUTABLE = 4, - EXT4_INODE_APPEND = 5, - EXT4_INODE_NODUMP = 6, - EXT4_INODE_NOATIME = 7, - EXT4_INODE_DIRTY = 8, - EXT4_INODE_COMPRBLK = 9, - EXT4_INODE_NOCOMPR = 10, - EXT4_INODE_ENCRYPT = 11, - EXT4_INODE_INDEX = 12, - EXT4_INODE_IMAGIC = 13, - EXT4_INODE_JOURNAL_DATA = 14, - EXT4_INODE_NOTAIL = 15, - EXT4_INODE_DIRSYNC = 16, - EXT4_INODE_TOPDIR = 17, - EXT4_INODE_HUGE_FILE = 18, - EXT4_INODE_EXTENTS = 19, - EXT4_INODE_VERITY = 20, - EXT4_INODE_EA_INODE = 21, - EXT4_INODE_DAX = 25, - EXT4_INODE_INLINE_DATA = 28, - EXT4_INODE_PROJINHERIT = 29, - EXT4_INODE_CASEFOLD = 30, - EXT4_INODE_RESERVED = 31, -}; - -enum { - EXT4_FC_REASON_OK = 0, - EXT4_FC_REASON_INELIGIBLE = 1, - EXT4_FC_REASON_ALREADY_COMMITTED = 2, - EXT4_FC_REASON_FC_START_FAILED = 3, - EXT4_FC_REASON_FC_FAILED = 4, - EXT4_FC_REASON_XATTR = 0, - EXT4_FC_REASON_CROSS_RENAME = 1, - EXT4_FC_REASON_JOURNAL_FLAG_CHANGE = 2, - EXT4_FC_REASON_NOMEM = 3, - EXT4_FC_REASON_SWAP_BOOT = 4, - EXT4_FC_REASON_RESIZE = 5, - EXT4_FC_REASON_RENAME_DIR = 6, - EXT4_FC_REASON_FALLOC_RANGE = 7, - EXT4_FC_REASON_INODE_JOURNAL_DATA = 8, - EXT4_FC_COMMIT_FAILED = 9, - EXT4_FC_REASON_MAX = 10, -}; - -struct ext4_dir_entry_2 { - __le32 inode; - __le16 rec_len; - __u8 name_len; - __u8 file_type; - char name[255]; -}; - -struct fname; - -struct dir_private_info { - struct rb_root root; - struct rb_node *curr_node; - struct fname *extra_fname; - loff_t last_pos; - __u32 curr_hash; - __u32 curr_minor_hash; - __u32 next_hash; -}; - -struct fname { - __u32 hash; - __u32 minor_hash; - struct rb_node rb_hash; - struct fname *next; - __u32 inode; - __u8 name_len; - __u8 file_type; - char name[0]; -}; - -enum SHIFT_DIRECTION { - SHIFT_LEFT = 0, - SHIFT_RIGHT = 1, -}; - -struct ext4_io_end_vec { - struct list_head list; - loff_t offset; - ssize_t size; -}; - -struct ext4_io_end { - struct list_head list; - handle_t *handle; - struct inode *inode; - struct bio *bio; - unsigned int flag; - atomic_t count; - struct list_head list_vec; -}; - -typedef struct ext4_io_end ext4_io_end_t; - -enum { - ES_WRITTEN_B = 0, - ES_UNWRITTEN_B = 1, - ES_DELAYED_B = 2, - ES_HOLE_B = 3, - ES_REFERENCED_B = 4, - ES_FLAGS = 5, -}; - -enum { - EXT4_STATE_JDATA = 0, - EXT4_STATE_NEW = 1, - EXT4_STATE_XATTR = 2, - EXT4_STATE_NO_EXPAND = 3, - EXT4_STATE_DA_ALLOC_CLOSE = 4, - EXT4_STATE_EXT_MIGRATE = 5, - EXT4_STATE_NEWENTRY = 6, - EXT4_STATE_MAY_INLINE_DATA = 7, - EXT4_STATE_EXT_PRECACHED = 8, - EXT4_STATE_LUSTRE_EA_INODE = 9, - EXT4_STATE_VERITY_IN_PROGRESS = 10, - EXT4_STATE_FC_COMMITTING = 11, -}; - -struct ext4_iloc { - struct buffer_head *bh; - long unsigned int offset; - ext4_group_t block_group; -}; - -struct ext4_extent_tail { - __le32 et_checksum; -}; - -struct ext4_extent { - __le32 ee_block; - __le16 ee_len; - __le16 ee_start_hi; - __le32 ee_start_lo; -}; - -struct ext4_extent_idx { - __le32 ei_block; - __le32 ei_leaf_lo; - __le16 ei_leaf_hi; - __u16 ei_unused; -}; - -struct ext4_extent_header { - __le16 eh_magic; - __le16 eh_entries; - __le16 eh_max; - __le16 eh_depth; - __le32 eh_generation; -}; - -struct ext4_ext_path { - ext4_fsblk_t p_block; - __u16 p_depth; - __u16 p_maxdepth; - struct ext4_extent *p_ext; - struct ext4_extent_idx *p_idx; - struct ext4_extent_header *p_hdr; - struct buffer_head *p_bh; -}; - -struct partial_cluster { - ext4_fsblk_t pclu; - ext4_lblk_t lblk; - enum { - initial = 0, - tofree = 1, - nofree = 2, - } state; -}; - -struct pending_reservation { - struct rb_node rb_node; - ext4_lblk_t lclu; -}; - -struct rsvd_count { - int ndelonly; - bool first_do_lblk_found; - ext4_lblk_t first_do_lblk; - ext4_lblk_t last_do_lblk; - struct extent_status *left_es; - bool partial; - ext4_lblk_t lclu; -}; - -enum { - EXT4_MF_MNTDIR_SAMPLED = 0, - EXT4_MF_FS_ABORTED = 1, - EXT4_MF_FC_INELIGIBLE = 2, - EXT4_MF_FC_COMMITTING = 3, -}; - -struct fsverity_info; - -struct fsmap { - __u32 fmr_device; - __u32 fmr_flags; - __u64 fmr_physical; - __u64 fmr_owner; - __u64 fmr_offset; - __u64 fmr_length; - __u64 fmr_reserved[3]; -}; - -struct ext4_fsmap { - struct list_head fmr_list; - dev_t fmr_device; - uint32_t fmr_flags; - uint64_t fmr_physical; - uint64_t fmr_owner; - uint64_t fmr_length; -}; - -struct ext4_fsmap_head { - uint32_t fmh_iflags; - uint32_t fmh_oflags; - unsigned int fmh_count; - unsigned int fmh_entries; - struct ext4_fsmap fmh_keys[2]; -}; - -typedef int (*ext4_fsmap_format_t)(struct ext4_fsmap *, void *); - -struct ext4_getfsmap_info { - struct ext4_fsmap_head *gfi_head; - ext4_fsmap_format_t gfi_formatter; - void *gfi_format_arg; - ext4_fsblk_t gfi_next_fsblk; - u32 gfi_dev; - ext4_group_t gfi_agno; - struct ext4_fsmap gfi_low; - struct ext4_fsmap gfi_high; - struct ext4_fsmap gfi_lastfree; - struct list_head gfi_meta_list; - bool gfi_last; -}; - -struct ext4_getfsmap_dev { - int (*gfd_fn)(struct super_block *, struct ext4_fsmap *, struct ext4_getfsmap_info *); - u32 gfd_dev; -}; - -struct dx_hash_info { - u32 hash; - u32 minor_hash; - int hash_version; - u32 *seed; -}; - -typedef unsigned int __kernel_mode_t; - -typedef __kernel_mode_t mode_t; - -struct ext4_inode { - __le16 i_mode; - __le16 i_uid; - __le32 i_size_lo; - __le32 i_atime; - __le32 i_ctime; - __le32 i_mtime; - __le32 i_dtime; - __le16 i_gid; - __le16 i_links_count; - __le32 i_blocks_lo; - __le32 i_flags; - union { - struct { - __le32 l_i_version; - } linux1; - struct { - __u32 h_i_translator; - } hurd1; - struct { - __u32 m_i_reserved1; - } masix1; - } osd1; - __le32 i_block[15]; - __le32 i_generation; - __le32 i_file_acl_lo; - __le32 i_size_high; - __le32 i_obso_faddr; - union { - struct { - __le16 l_i_blocks_high; - __le16 l_i_file_acl_high; - __le16 l_i_uid_high; - __le16 l_i_gid_high; - __le16 l_i_checksum_lo; - __le16 l_i_reserved; - } linux2; - struct { - __le16 h_i_reserved1; - __u16 h_i_mode_high; - __u16 h_i_uid_high; - __u16 h_i_gid_high; - __u32 h_i_author; - } hurd2; - struct { - __le16 h_i_reserved1; - __le16 m_i_file_acl_high; - __u32 m_i_reserved2[2]; - } masix2; - } osd2; - __le16 i_extra_isize; - __le16 i_checksum_hi; - __le32 i_ctime_extra; - __le32 i_mtime_extra; - __le32 i_atime_extra; - __le32 i_crtime; - __le32 i_crtime_extra; - __le32 i_version_hi; - __le32 i_projid; -}; - -struct orlov_stats { - __u64 free_clusters; - __u32 free_inodes; - __u32 used_dirs; -}; - -typedef struct { - __le32 *p; - __le32 key; - struct buffer_head *bh; -} Indirect; - -struct ext4_filename { - const struct qstr *usr_fname; - struct fscrypt_str disk_name; - struct dx_hash_info hinfo; - struct fscrypt_str crypto_buf; -}; - -struct ext4_xattr_ibody_header { - __le32 h_magic; -}; - -struct ext4_xattr_entry { - __u8 e_name_len; - __u8 e_name_index; - __le16 e_value_offs; - __le32 e_value_inum; - __le32 e_value_size; - __le32 e_hash; - char e_name[0]; -}; - -struct ext4_xattr_info { - const char *name; - const void *value; - size_t value_len; - int name_index; - int in_inode; -}; - -struct ext4_xattr_search { - struct ext4_xattr_entry *first; - void *base; - void *end; - struct ext4_xattr_entry *here; - int not_found; -}; - -struct ext4_xattr_ibody_find { - struct ext4_xattr_search s; - struct ext4_iloc iloc; -}; - -typedef short unsigned int __kernel_uid16_t; - -typedef short unsigned int __kernel_gid16_t; - -typedef __kernel_uid16_t uid16_t; - -typedef __kernel_gid16_t gid16_t; - -struct ext4_io_submit { - struct writeback_control *io_wbc; - struct bio *io_bio; - ext4_io_end_t *io_end; - sector_t io_next_block; -}; - -typedef enum { - EXT4_IGET_NORMAL = 0, - EXT4_IGET_SPECIAL = 1, - EXT4_IGET_HANDLE = 2, -} ext4_iget_flags; - -struct ext4_xattr_inode_array { - unsigned int count; - struct inode *inodes[0]; -}; - -struct mpage_da_data { - struct inode *inode; - struct writeback_control *wbc; - long unsigned int first_page; - long unsigned int next_page; - long unsigned int last_page; - struct ext4_map_blocks map; - struct ext4_io_submit io_submit; - unsigned int do_map: 1; - unsigned int scanned_until_end: 1; -}; - -struct fstrim_range { - __u64 start; - __u64 len; - __u64 minlen; -}; - -struct ext4_new_group_input { - __u32 group; - __u64 block_bitmap; - __u64 inode_bitmap; - __u64 inode_table; - __u32 blocks_count; - __u16 reserved_blocks; - __u16 unused; -}; - -struct compat_ext4_new_group_input { - u32 group; - compat_u64 block_bitmap; - compat_u64 inode_bitmap; - compat_u64 inode_table; - u32 blocks_count; - u16 reserved_blocks; - u16 unused; -}; - -struct ext4_new_group_data { - __u32 group; - __u64 block_bitmap; - __u64 inode_bitmap; - __u64 inode_table; - __u32 blocks_count; - __u16 reserved_blocks; - __u16 mdata_blocks; - __u32 free_clusters_count; -}; - -struct move_extent { - __u32 reserved; - __u32 donor_fd; - __u64 orig_start; - __u64 donor_start; - __u64 len; - __u64 moved_len; -}; - -struct fsmap_head { - __u32 fmh_iflags; - __u32 fmh_oflags; - __u32 fmh_count; - __u32 fmh_entries; - __u64 fmh_reserved[6]; - struct fsmap fmh_keys[2]; - struct fsmap fmh_recs[0]; -}; - -struct getfsmap_info { - struct super_block *gi_sb; - struct fsmap_head *gi_data; - unsigned int gi_idx; - __u32 gi_last_flags; -}; - -enum blk_default_limits { - BLK_MAX_SEGMENTS = 128, - BLK_SAFE_MAX_SECTORS = 255, - BLK_DEF_MAX_SECTORS = 2560, - BLK_MAX_SEGMENT_SIZE = 65536, - BLK_SEG_BOUNDARY_MASK = 4294967295, -}; - -struct ext4_free_data { - struct list_head efd_list; - struct rb_node efd_node; - ext4_group_t efd_group; - ext4_grpblk_t efd_start_cluster; - ext4_grpblk_t efd_count; - tid_t efd_tid; -}; - -struct ext4_prealloc_space { - struct list_head pa_inode_list; - struct list_head pa_group_list; - union { - struct list_head pa_tmp_list; - struct callback_head pa_rcu; - } u; - spinlock_t pa_lock; - atomic_t pa_count; - unsigned int pa_deleted; - ext4_fsblk_t pa_pstart; - ext4_lblk_t pa_lstart; - ext4_grpblk_t pa_len; - ext4_grpblk_t pa_free; - short unsigned int pa_type; - spinlock_t *pa_obj_lock; - struct inode *pa_inode; -}; - -enum { - MB_INODE_PA = 0, - MB_GROUP_PA = 1, -}; - -struct ext4_free_extent { - ext4_lblk_t fe_logical; - ext4_grpblk_t fe_start; - ext4_group_t fe_group; - ext4_grpblk_t fe_len; -}; - -struct ext4_allocation_context { - struct inode *ac_inode; - struct super_block *ac_sb; - struct ext4_free_extent ac_o_ex; - struct ext4_free_extent ac_g_ex; - struct ext4_free_extent ac_b_ex; - struct ext4_free_extent ac_f_ex; - __u16 ac_groups_scanned; - __u16 ac_found; - __u16 ac_tail; - __u16 ac_buddy; - __u16 ac_flags; - __u8 ac_status; - __u8 ac_criteria; - __u8 ac_2order; - __u8 ac_op; - struct page *ac_bitmap_page; - struct page *ac_buddy_page; - struct ext4_prealloc_space *ac_pa; - struct ext4_locality_group *ac_lg; -}; - -struct ext4_buddy { - struct page *bd_buddy_page; - void *bd_buddy; - struct page *bd_bitmap_page; - void *bd_bitmap; - struct ext4_group_info *bd_info; - struct super_block *bd_sb; - __u16 bd_blkbits; - ext4_group_t bd_group; -}; - -typedef int (*ext4_mballoc_query_range_fn)(struct super_block *, ext4_group_t, ext4_grpblk_t, ext4_grpblk_t, void *); - -struct sg { - struct ext4_group_info info; - ext4_grpblk_t counters[18]; -}; - -struct migrate_struct { - ext4_lblk_t first_block; - ext4_lblk_t last_block; - ext4_lblk_t curr_block; - ext4_fsblk_t first_pblock; - ext4_fsblk_t last_pblock; -}; - -struct mmp_struct { - __le32 mmp_magic; - __le32 mmp_seq; - __le64 mmp_time; - char mmp_nodename[64]; - char mmp_bdevname[32]; - __le16 mmp_check_interval; - __le16 mmp_pad1; - __le32 mmp_pad2[226]; - __le32 mmp_checksum; -}; - -struct ext4_dir_entry { - __le32 inode; - __le16 rec_len; - __le16 name_len; - char name[255]; -}; - -struct ext4_dir_entry_tail { - __le32 det_reserved_zero1; - __le16 det_rec_len; - __u8 det_reserved_zero2; - __u8 det_reserved_ft; - __le32 det_checksum; -}; - -typedef enum { - EITHER = 0, - INDEX = 1, - DIRENT = 2, - DIRENT_HTREE = 3, -} dirblock_type_t; - -struct fake_dirent { - __le32 inode; - __le16 rec_len; - u8 name_len; - u8 file_type; -}; - -struct dx_countlimit { - __le16 limit; - __le16 count; -}; - -struct dx_entry { - __le32 hash; - __le32 block; -}; - -struct dx_root_info { - __le32 reserved_zero; - u8 hash_version; - u8 info_length; - u8 indirect_levels; - u8 unused_flags; -}; - -struct dx_root { - struct fake_dirent dot; - char dot_name[4]; - struct fake_dirent dotdot; - char dotdot_name[4]; - struct dx_root_info info; - struct dx_entry entries[0]; -}; - -struct dx_node { - struct fake_dirent fake; - struct dx_entry entries[0]; -}; - -struct dx_frame { - struct buffer_head *bh; - struct dx_entry *entries; - struct dx_entry *at; -}; - -struct dx_map_entry { - u32 hash; - u16 offs; - u16 size; -}; - -struct dx_tail { - u32 dt_reserved; - __le32 dt_checksum; -}; - -struct ext4_renament { - struct inode *dir; - struct dentry *dentry; - struct inode *inode; - bool is_dir; - int dir_nlink_delta; - struct buffer_head *bh; - struct ext4_dir_entry_2 *de; - int inlined; - struct buffer_head *dir_bh; - struct ext4_dir_entry_2 *parent_de; - int dir_inlined; -}; - -enum bio_post_read_step { - STEP_INITIAL = 0, - STEP_DECRYPT = 1, - STEP_VERITY = 2, - STEP_MAX = 3, -}; - -struct bio_post_read_ctx { - struct bio *bio; - struct work_struct work; - unsigned int cur_step; - unsigned int enabled_steps; -}; - -enum { - BLOCK_BITMAP = 0, - INODE_BITMAP = 1, - INODE_TABLE = 2, - GROUP_TABLE_COUNT = 3, -}; - -struct ext4_rcu_ptr { - struct callback_head rcu; - void *ptr; -}; - -struct ext4_new_flex_group_data { - struct ext4_new_group_data *groups; - __u16 *bg_flags; - ext4_group_t count; -}; - -enum stat_group { - STAT_READ = 0, - STAT_WRITE = 1, - STAT_DISCARD = 2, - STAT_FLUSH = 3, - NR_STAT_GROUPS = 4, -}; - -enum { - I_DATA_SEM_NORMAL = 0, - I_DATA_SEM_OTHER = 1, - I_DATA_SEM_QUOTA = 2, -}; - -struct ext4_lazy_init { - long unsigned int li_state; - struct list_head li_request_list; - struct mutex li_list_mtx; -}; - -struct ext4_journal_cb_entry { - struct list_head jce_list; - void (*jce_func)(struct super_block *, struct ext4_journal_cb_entry *, int); -}; - -struct trace_event_raw_ext4_other_inode_update_time { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ino_t orig_ino; - uid_t uid; - gid_t gid; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_free_inode { - struct trace_entry ent; - dev_t dev; - ino_t ino; - uid_t uid; - gid_t gid; - __u64 blocks; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_request_inode { - struct trace_entry ent; - dev_t dev; - ino_t dir; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_allocate_inode { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ino_t dir; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_evict_inode { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int nlink; - char __data[0]; -}; - -struct trace_event_raw_ext4_drop_inode { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int drop; - char __data[0]; -}; - -struct trace_event_raw_ext4_nfs_commit_metadata { - struct trace_entry ent; - dev_t dev; - ino_t ino; - char __data[0]; -}; - -struct trace_event_raw_ext4_mark_inode_dirty { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int ip; - char __data[0]; -}; - -struct trace_event_raw_ext4_begin_ordered_truncate { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t new_size; - char __data[0]; -}; - -struct trace_event_raw_ext4__write_begin { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - unsigned int len; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_ext4__write_end { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - unsigned int len; - unsigned int copied; - char __data[0]; -}; - -struct trace_event_raw_ext4_writepages { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long int nr_to_write; - long int pages_skipped; - loff_t range_start; - loff_t range_end; - long unsigned int writeback_index; - int sync_mode; - char for_kupdate; - char range_cyclic; - char __data[0]; -}; - -struct trace_event_raw_ext4_da_write_pages { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int first_page; - long int nr_to_write; - int sync_mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_da_write_pages_extent { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 lblk; - __u32 len; - __u32 flags; - char __data[0]; -}; - -struct trace_event_raw_ext4_writepages_result { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int ret; - int pages_written; - long int pages_skipped; - long unsigned int writeback_index; - int sync_mode; - char __data[0]; -}; - -struct trace_event_raw_ext4__page_op { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int index; - char __data[0]; -}; - -struct trace_event_raw_ext4_invalidatepage_op { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int index; - unsigned int offset; - unsigned int length; - char __data[0]; -}; - -struct trace_event_raw_ext4_discard_blocks { - struct trace_entry ent; - dev_t dev; - __u64 blk; - __u64 count; - char __data[0]; -}; - -struct trace_event_raw_ext4__mb_new_pa { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 pa_pstart; - __u64 pa_lstart; - __u32 pa_len; - char __data[0]; -}; - -struct trace_event_raw_ext4_mb_release_inode_pa { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 block; - __u32 count; - char __data[0]; -}; - -struct trace_event_raw_ext4_mb_release_group_pa { - struct trace_entry ent; - dev_t dev; - __u64 pa_pstart; - __u32 pa_len; - char __data[0]; -}; - -struct trace_event_raw_ext4_discard_preallocations { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int len; - unsigned int needed; - char __data[0]; -}; - -struct trace_event_raw_ext4_mb_discard_preallocations { - struct trace_entry ent; - dev_t dev; - int needed; - char __data[0]; -}; - -struct trace_event_raw_ext4_request_blocks { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int len; - __u32 logical; - __u32 lleft; - __u32 lright; - __u64 goal; - __u64 pleft; - __u64 pright; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_ext4_allocate_blocks { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 block; - unsigned int len; - __u32 logical; - __u32 lleft; - __u32 lright; - __u64 goal; - __u64 pleft; - __u64 pright; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_ext4_free_blocks { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 block; - long unsigned int count; - int flags; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_sync_file_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ino_t parent; - int datasync; - char __data[0]; -}; - -struct trace_event_raw_ext4_sync_file_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int ret; - char __data[0]; -}; - -struct trace_event_raw_ext4_sync_fs { - struct trace_entry ent; - dev_t dev; - int wait; - char __data[0]; -}; - -struct trace_event_raw_ext4_alloc_da_blocks { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int data_blocks; - char __data[0]; -}; - -struct trace_event_raw_ext4_mballoc_alloc { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u32 orig_logical; - int orig_start; - __u32 orig_group; - int orig_len; - __u32 goal_logical; - int goal_start; - __u32 goal_group; - int goal_len; - __u32 result_logical; - int result_start; - __u32 result_group; - int result_len; - __u16 found; - __u16 groups; - __u16 buddy; - __u16 flags; - __u16 tail; - __u8 cr; - char __data[0]; -}; - -struct trace_event_raw_ext4_mballoc_prealloc { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u32 orig_logical; - int orig_start; - __u32 orig_group; - int orig_len; - __u32 result_logical; - int result_start; - __u32 result_group; - int result_len; - char __data[0]; -}; - -struct trace_event_raw_ext4__mballoc { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int result_start; - __u32 result_group; - int result_len; - char __data[0]; -}; - -struct trace_event_raw_ext4_forget { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 block; - int is_metadata; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_da_update_reserve_space { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 i_blocks; - int used_blocks; - int reserved_data_blocks; - int quota_claim; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_da_reserve_space { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 i_blocks; - int reserved_data_blocks; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_da_release_space { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 i_blocks; - int freed_blocks; - int reserved_data_blocks; - __u16 mode; - char __data[0]; -}; - -struct trace_event_raw_ext4__bitmap_load { - struct trace_entry ent; - dev_t dev; - __u32 group; - char __data[0]; -}; - -struct trace_event_raw_ext4_read_block_bitmap_load { - struct trace_entry ent; - dev_t dev; - __u32 group; - bool prefetch; - char __data[0]; -}; - -struct trace_event_raw_ext4_direct_IO_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - long unsigned int len; - int rw; - char __data[0]; -}; - -struct trace_event_raw_ext4_direct_IO_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - long unsigned int len; - int rw; - int ret; - char __data[0]; -}; - -struct trace_event_raw_ext4__fallocate_mode { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t offset; - loff_t len; - int mode; - char __data[0]; -}; - -struct trace_event_raw_ext4_fallocate_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - unsigned int blocks; - int ret; - char __data[0]; -}; - -struct trace_event_raw_ext4_unlink_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ino_t parent; - loff_t size; - char __data[0]; -}; - -struct trace_event_raw_ext4_unlink_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int ret; - char __data[0]; -}; - -struct trace_event_raw_ext4__truncate { - struct trace_entry ent; - dev_t dev; - ino_t ino; - __u64 blocks; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_convert_to_initialized_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t m_lblk; - unsigned int m_len; - ext4_lblk_t u_lblk; - unsigned int u_len; - ext4_fsblk_t u_pblk; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_convert_to_initialized_fastpath { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t m_lblk; - unsigned int m_len; - ext4_lblk_t u_lblk; - unsigned int u_len; - ext4_fsblk_t u_pblk; - ext4_lblk_t i_lblk; - unsigned int i_len; - ext4_fsblk_t i_pblk; - char __data[0]; -}; - -struct trace_event_raw_ext4__map_blocks_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - unsigned int len; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_ext4__map_blocks_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int flags; - ext4_fsblk_t pblk; - ext4_lblk_t lblk; - unsigned int len; - unsigned int mflags; - int ret; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_load_extent { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_fsblk_t pblk; - ext4_lblk_t lblk; - char __data[0]; -}; - -struct trace_event_raw_ext4_load_inode { - struct trace_entry ent; - dev_t dev; - ino_t ino; - char __data[0]; -}; - -struct trace_event_raw_ext4_journal_start { - struct trace_entry ent; - dev_t dev; - long unsigned int ip; - int blocks; - int rsv_blocks; - int revoke_creds; - char __data[0]; -}; - -struct trace_event_raw_ext4_journal_start_reserved { - struct trace_entry ent; - dev_t dev; - long unsigned int ip; - int blocks; - char __data[0]; -}; - -struct trace_event_raw_ext4__trim { - struct trace_entry ent; - int dev_major; - int dev_minor; - __u32 group; - int start; - int len; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_handle_unwritten_extents { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int flags; - ext4_lblk_t lblk; - ext4_fsblk_t pblk; - unsigned int len; - unsigned int allocated; - ext4_fsblk_t newblk; - char __data[0]; -}; - -struct trace_event_raw_ext4_get_implied_cluster_alloc_exit { - struct trace_entry ent; - dev_t dev; - unsigned int flags; - ext4_lblk_t lblk; - ext4_fsblk_t pblk; - unsigned int len; - int ret; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_put_in_cache { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - unsigned int len; - ext4_fsblk_t start; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_in_cache { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - int ret; - char __data[0]; -}; - -struct trace_event_raw_ext4_find_delalloc_range { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t from; - ext4_lblk_t to; - int reverse; - int found; - ext4_lblk_t found_blk; - char __data[0]; -}; - -struct trace_event_raw_ext4_get_reserved_cluster_alloc { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - unsigned int len; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_show_extent { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_fsblk_t pblk; - ext4_lblk_t lblk; - short unsigned int len; - char __data[0]; -}; - -struct trace_event_raw_ext4_remove_blocks { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t from; - ext4_lblk_t to; - ext4_fsblk_t ee_pblk; - ext4_lblk_t ee_lblk; - short unsigned int ee_len; - ext4_fsblk_t pc_pclu; - ext4_lblk_t pc_lblk; - int pc_state; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_rm_leaf { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t start; - ext4_lblk_t ee_lblk; - ext4_fsblk_t ee_pblk; - short int ee_len; - ext4_fsblk_t pc_pclu; - ext4_lblk_t pc_lblk; - int pc_state; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_rm_idx { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_fsblk_t pblk; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_remove_space { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t start; - ext4_lblk_t end; - int depth; - char __data[0]; -}; - -struct trace_event_raw_ext4_ext_remove_space_done { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t start; - ext4_lblk_t end; - int depth; - ext4_fsblk_t pc_pclu; - ext4_lblk_t pc_lblk; - int pc_state; - short unsigned int eh_entries; - char __data[0]; -}; - -struct trace_event_raw_ext4__es_extent { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - ext4_lblk_t len; - ext4_fsblk_t pblk; - char status; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_remove_extent { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t lblk; - loff_t len; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_find_extent_range_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_find_extent_range_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - ext4_lblk_t len; - ext4_fsblk_t pblk; - char status; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_lookup_extent_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_lookup_extent_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - ext4_lblk_t len; - ext4_fsblk_t pblk; - char status; - int found; - char __data[0]; -}; - -struct trace_event_raw_ext4__es_shrink_enter { - struct trace_entry ent; - dev_t dev; - int nr_to_scan; - int cache_cnt; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_shrink_scan_exit { - struct trace_entry ent; - dev_t dev; - int nr_shrunk; - int cache_cnt; - char __data[0]; -}; - -struct trace_event_raw_ext4_collapse_range { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t offset; - loff_t len; - char __data[0]; -}; - -struct trace_event_raw_ext4_insert_range { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t offset; - loff_t len; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_shrink { - struct trace_entry ent; - dev_t dev; - int nr_shrunk; - long long unsigned int scan_time; - int nr_skipped; - int retried; - char __data[0]; -}; - -struct trace_event_raw_ext4_es_insert_delayed_block { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ext4_lblk_t lblk; - ext4_lblk_t len; - ext4_fsblk_t pblk; - char status; - bool allocated; - char __data[0]; -}; - -struct trace_event_raw_ext4_fsmap_class { - struct trace_entry ent; - dev_t dev; - dev_t keydev; - u32 agno; - u64 bno; - u64 len; - u64 owner; - char __data[0]; -}; - -struct trace_event_raw_ext4_getfsmap_class { - struct trace_entry ent; - dev_t dev; - dev_t keydev; - u64 block; - u64 len; - u64 owner; - u64 flags; - char __data[0]; -}; - -struct trace_event_raw_ext4_shutdown { - struct trace_entry ent; - dev_t dev; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_ext4_error { - struct trace_entry ent; - dev_t dev; - const char *function; - unsigned int line; - char __data[0]; -}; - -struct trace_event_raw_ext4_prefetch_bitmaps { - struct trace_entry ent; - dev_t dev; - __u32 group; - __u32 next; - __u32 ios; - char __data[0]; -}; - -struct trace_event_raw_ext4_lazy_itable_init { - struct trace_entry ent; - dev_t dev; - __u32 group; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_replay_scan { - struct trace_entry ent; - dev_t dev; - int error; - int off; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_replay { - struct trace_entry ent; - dev_t dev; - int tag; - int ino; - int priv1; - int priv2; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_commit_start { - struct trace_entry ent; - dev_t dev; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_commit_stop { - struct trace_entry ent; - dev_t dev; - int nblks; - int reason; - int num_fc; - int num_fc_ineligible; - int nblks_agg; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_stats { - struct trace_entry ent; - dev_t dev; - struct ext4_sb_info *sbi; - int count; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_track_create { - struct trace_entry ent; - dev_t dev; - int ino; - int error; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_track_link { - struct trace_entry ent; - dev_t dev; - int ino; - int error; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_track_unlink { - struct trace_entry ent; - dev_t dev; - int ino; - int error; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_track_inode { - struct trace_entry ent; - dev_t dev; - int ino; - int error; - char __data[0]; -}; - -struct trace_event_raw_ext4_fc_track_range { - struct trace_entry ent; - dev_t dev; - int ino; - long int start; - long int end; - int error; - char __data[0]; -}; - -struct trace_event_data_offsets_ext4_other_inode_update_time {}; - -struct trace_event_data_offsets_ext4_free_inode {}; - -struct trace_event_data_offsets_ext4_request_inode {}; - -struct trace_event_data_offsets_ext4_allocate_inode {}; - -struct trace_event_data_offsets_ext4_evict_inode {}; - -struct trace_event_data_offsets_ext4_drop_inode {}; - -struct trace_event_data_offsets_ext4_nfs_commit_metadata {}; - -struct trace_event_data_offsets_ext4_mark_inode_dirty {}; - -struct trace_event_data_offsets_ext4_begin_ordered_truncate {}; - -struct trace_event_data_offsets_ext4__write_begin {}; - -struct trace_event_data_offsets_ext4__write_end {}; - -struct trace_event_data_offsets_ext4_writepages {}; - -struct trace_event_data_offsets_ext4_da_write_pages {}; - -struct trace_event_data_offsets_ext4_da_write_pages_extent {}; - -struct trace_event_data_offsets_ext4_writepages_result {}; - -struct trace_event_data_offsets_ext4__page_op {}; - -struct trace_event_data_offsets_ext4_invalidatepage_op {}; - -struct trace_event_data_offsets_ext4_discard_blocks {}; - -struct trace_event_data_offsets_ext4__mb_new_pa {}; - -struct trace_event_data_offsets_ext4_mb_release_inode_pa {}; - -struct trace_event_data_offsets_ext4_mb_release_group_pa {}; - -struct trace_event_data_offsets_ext4_discard_preallocations {}; - -struct trace_event_data_offsets_ext4_mb_discard_preallocations {}; - -struct trace_event_data_offsets_ext4_request_blocks {}; - -struct trace_event_data_offsets_ext4_allocate_blocks {}; - -struct trace_event_data_offsets_ext4_free_blocks {}; - -struct trace_event_data_offsets_ext4_sync_file_enter {}; - -struct trace_event_data_offsets_ext4_sync_file_exit {}; - -struct trace_event_data_offsets_ext4_sync_fs {}; - -struct trace_event_data_offsets_ext4_alloc_da_blocks {}; - -struct trace_event_data_offsets_ext4_mballoc_alloc {}; - -struct trace_event_data_offsets_ext4_mballoc_prealloc {}; - -struct trace_event_data_offsets_ext4__mballoc {}; - -struct trace_event_data_offsets_ext4_forget {}; - -struct trace_event_data_offsets_ext4_da_update_reserve_space {}; - -struct trace_event_data_offsets_ext4_da_reserve_space {}; - -struct trace_event_data_offsets_ext4_da_release_space {}; - -struct trace_event_data_offsets_ext4__bitmap_load {}; - -struct trace_event_data_offsets_ext4_read_block_bitmap_load {}; - -struct trace_event_data_offsets_ext4_direct_IO_enter {}; - -struct trace_event_data_offsets_ext4_direct_IO_exit {}; - -struct trace_event_data_offsets_ext4__fallocate_mode {}; - -struct trace_event_data_offsets_ext4_fallocate_exit {}; - -struct trace_event_data_offsets_ext4_unlink_enter {}; - -struct trace_event_data_offsets_ext4_unlink_exit {}; - -struct trace_event_data_offsets_ext4__truncate {}; - -struct trace_event_data_offsets_ext4_ext_convert_to_initialized_enter {}; - -struct trace_event_data_offsets_ext4_ext_convert_to_initialized_fastpath {}; - -struct trace_event_data_offsets_ext4__map_blocks_enter {}; - -struct trace_event_data_offsets_ext4__map_blocks_exit {}; - -struct trace_event_data_offsets_ext4_ext_load_extent {}; - -struct trace_event_data_offsets_ext4_load_inode {}; - -struct trace_event_data_offsets_ext4_journal_start {}; - -struct trace_event_data_offsets_ext4_journal_start_reserved {}; - -struct trace_event_data_offsets_ext4__trim {}; - -struct trace_event_data_offsets_ext4_ext_handle_unwritten_extents {}; - -struct trace_event_data_offsets_ext4_get_implied_cluster_alloc_exit {}; - -struct trace_event_data_offsets_ext4_ext_put_in_cache {}; - -struct trace_event_data_offsets_ext4_ext_in_cache {}; - -struct trace_event_data_offsets_ext4_find_delalloc_range {}; - -struct trace_event_data_offsets_ext4_get_reserved_cluster_alloc {}; - -struct trace_event_data_offsets_ext4_ext_show_extent {}; - -struct trace_event_data_offsets_ext4_remove_blocks {}; - -struct trace_event_data_offsets_ext4_ext_rm_leaf {}; - -struct trace_event_data_offsets_ext4_ext_rm_idx {}; - -struct trace_event_data_offsets_ext4_ext_remove_space {}; - -struct trace_event_data_offsets_ext4_ext_remove_space_done {}; - -struct trace_event_data_offsets_ext4__es_extent {}; - -struct trace_event_data_offsets_ext4_es_remove_extent {}; - -struct trace_event_data_offsets_ext4_es_find_extent_range_enter {}; - -struct trace_event_data_offsets_ext4_es_find_extent_range_exit {}; - -struct trace_event_data_offsets_ext4_es_lookup_extent_enter {}; - -struct trace_event_data_offsets_ext4_es_lookup_extent_exit {}; - -struct trace_event_data_offsets_ext4__es_shrink_enter {}; - -struct trace_event_data_offsets_ext4_es_shrink_scan_exit {}; - -struct trace_event_data_offsets_ext4_collapse_range {}; - -struct trace_event_data_offsets_ext4_insert_range {}; - -struct trace_event_data_offsets_ext4_es_shrink {}; - -struct trace_event_data_offsets_ext4_es_insert_delayed_block {}; - -struct trace_event_data_offsets_ext4_fsmap_class {}; - -struct trace_event_data_offsets_ext4_getfsmap_class {}; - -struct trace_event_data_offsets_ext4_shutdown {}; - -struct trace_event_data_offsets_ext4_error {}; - -struct trace_event_data_offsets_ext4_prefetch_bitmaps {}; - -struct trace_event_data_offsets_ext4_lazy_itable_init {}; - -struct trace_event_data_offsets_ext4_fc_replay_scan {}; - -struct trace_event_data_offsets_ext4_fc_replay {}; - -struct trace_event_data_offsets_ext4_fc_commit_start {}; - -struct trace_event_data_offsets_ext4_fc_commit_stop {}; - -struct trace_event_data_offsets_ext4_fc_stats {}; - -struct trace_event_data_offsets_ext4_fc_track_create {}; - -struct trace_event_data_offsets_ext4_fc_track_link {}; - -struct trace_event_data_offsets_ext4_fc_track_unlink {}; - -struct trace_event_data_offsets_ext4_fc_track_inode {}; - -struct trace_event_data_offsets_ext4_fc_track_range {}; - -typedef void (*btf_trace_ext4_other_inode_update_time)(void *, struct inode *, ino_t); - -typedef void (*btf_trace_ext4_free_inode)(void *, struct inode *); - -typedef void (*btf_trace_ext4_request_inode)(void *, struct inode *, int); - -typedef void (*btf_trace_ext4_allocate_inode)(void *, struct inode *, struct inode *, int); - -typedef void (*btf_trace_ext4_evict_inode)(void *, struct inode *); - -typedef void (*btf_trace_ext4_drop_inode)(void *, struct inode *, int); - -typedef void (*btf_trace_ext4_nfs_commit_metadata)(void *, struct inode *); - -typedef void (*btf_trace_ext4_mark_inode_dirty)(void *, struct inode *, long unsigned int); - -typedef void (*btf_trace_ext4_begin_ordered_truncate)(void *, struct inode *, loff_t); - -typedef void (*btf_trace_ext4_write_begin)(void *, struct inode *, loff_t, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_da_write_begin)(void *, struct inode *, loff_t, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_write_end)(void *, struct inode *, loff_t, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_journalled_write_end)(void *, struct inode *, loff_t, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_da_write_end)(void *, struct inode *, loff_t, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_writepages)(void *, struct inode *, struct writeback_control *); - -typedef void (*btf_trace_ext4_da_write_pages)(void *, struct inode *, long unsigned int, struct writeback_control *); - -typedef void (*btf_trace_ext4_da_write_pages_extent)(void *, struct inode *, struct ext4_map_blocks *); - -typedef void (*btf_trace_ext4_writepages_result)(void *, struct inode *, struct writeback_control *, int, int); - -typedef void (*btf_trace_ext4_writepage)(void *, struct page *); - -typedef void (*btf_trace_ext4_readpage)(void *, struct page *); - -typedef void (*btf_trace_ext4_releasepage)(void *, struct page *); - -typedef void (*btf_trace_ext4_invalidatepage)(void *, struct page *, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_journalled_invalidatepage)(void *, struct page *, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_discard_blocks)(void *, struct super_block *, long long unsigned int, long long unsigned int); - -typedef void (*btf_trace_ext4_mb_new_inode_pa)(void *, struct ext4_allocation_context *, struct ext4_prealloc_space *); - -typedef void (*btf_trace_ext4_mb_new_group_pa)(void *, struct ext4_allocation_context *, struct ext4_prealloc_space *); - -typedef void (*btf_trace_ext4_mb_release_inode_pa)(void *, struct ext4_prealloc_space *, long long unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_mb_release_group_pa)(void *, struct super_block *, struct ext4_prealloc_space *); - -typedef void (*btf_trace_ext4_discard_preallocations)(void *, struct inode *, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_mb_discard_preallocations)(void *, struct super_block *, int); - -typedef void (*btf_trace_ext4_request_blocks)(void *, struct ext4_allocation_request *); - -typedef void (*btf_trace_ext4_allocate_blocks)(void *, struct ext4_allocation_request *, long long unsigned int); - -typedef void (*btf_trace_ext4_free_blocks)(void *, struct inode *, __u64, long unsigned int, int); - -typedef void (*btf_trace_ext4_sync_file_enter)(void *, struct file *, int); - -typedef void (*btf_trace_ext4_sync_file_exit)(void *, struct inode *, int); - -typedef void (*btf_trace_ext4_sync_fs)(void *, struct super_block *, int); - -typedef void (*btf_trace_ext4_alloc_da_blocks)(void *, struct inode *); - -typedef void (*btf_trace_ext4_mballoc_alloc)(void *, struct ext4_allocation_context *); - -typedef void (*btf_trace_ext4_mballoc_prealloc)(void *, struct ext4_allocation_context *); - -typedef void (*btf_trace_ext4_mballoc_discard)(void *, struct super_block *, struct inode *, ext4_group_t, ext4_grpblk_t, ext4_grpblk_t); - -typedef void (*btf_trace_ext4_mballoc_free)(void *, struct super_block *, struct inode *, ext4_group_t, ext4_grpblk_t, ext4_grpblk_t); - -typedef void (*btf_trace_ext4_forget)(void *, struct inode *, int, __u64); - -typedef void (*btf_trace_ext4_da_update_reserve_space)(void *, struct inode *, int, int); - -typedef void (*btf_trace_ext4_da_reserve_space)(void *, struct inode *); - -typedef void (*btf_trace_ext4_da_release_space)(void *, struct inode *, int); - -typedef void (*btf_trace_ext4_mb_bitmap_load)(void *, struct super_block *, long unsigned int); - -typedef void (*btf_trace_ext4_mb_buddy_bitmap_load)(void *, struct super_block *, long unsigned int); - -typedef void (*btf_trace_ext4_load_inode_bitmap)(void *, struct super_block *, long unsigned int); - -typedef void (*btf_trace_ext4_read_block_bitmap_load)(void *, struct super_block *, long unsigned int, bool); - -typedef void (*btf_trace_ext4_direct_IO_enter)(void *, struct inode *, loff_t, long unsigned int, int); - -typedef void (*btf_trace_ext4_direct_IO_exit)(void *, struct inode *, loff_t, long unsigned int, int, int); - -typedef void (*btf_trace_ext4_fallocate_enter)(void *, struct inode *, loff_t, loff_t, int); - -typedef void (*btf_trace_ext4_punch_hole)(void *, struct inode *, loff_t, loff_t, int); - -typedef void (*btf_trace_ext4_zero_range)(void *, struct inode *, loff_t, loff_t, int); - -typedef void (*btf_trace_ext4_fallocate_exit)(void *, struct inode *, loff_t, unsigned int, int); - -typedef void (*btf_trace_ext4_unlink_enter)(void *, struct inode *, struct dentry *); - -typedef void (*btf_trace_ext4_unlink_exit)(void *, struct dentry *, int); - -typedef void (*btf_trace_ext4_truncate_enter)(void *, struct inode *); - -typedef void (*btf_trace_ext4_truncate_exit)(void *, struct inode *); - -typedef void (*btf_trace_ext4_ext_convert_to_initialized_enter)(void *, struct inode *, struct ext4_map_blocks *, struct ext4_extent *); - -typedef void (*btf_trace_ext4_ext_convert_to_initialized_fastpath)(void *, struct inode *, struct ext4_map_blocks *, struct ext4_extent *, struct ext4_extent *); - -typedef void (*btf_trace_ext4_ext_map_blocks_enter)(void *, struct inode *, ext4_lblk_t, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_ind_map_blocks_enter)(void *, struct inode *, ext4_lblk_t, unsigned int, unsigned int); - -typedef void (*btf_trace_ext4_ext_map_blocks_exit)(void *, struct inode *, unsigned int, struct ext4_map_blocks *, int); - -typedef void (*btf_trace_ext4_ind_map_blocks_exit)(void *, struct inode *, unsigned int, struct ext4_map_blocks *, int); - -typedef void (*btf_trace_ext4_ext_load_extent)(void *, struct inode *, ext4_lblk_t, ext4_fsblk_t); - -typedef void (*btf_trace_ext4_load_inode)(void *, struct super_block *, long unsigned int); - -typedef void (*btf_trace_ext4_journal_start)(void *, struct super_block *, int, int, int, long unsigned int); - -typedef void (*btf_trace_ext4_journal_start_reserved)(void *, struct super_block *, int, long unsigned int); - -typedef void (*btf_trace_ext4_trim_extent)(void *, struct super_block *, ext4_group_t, ext4_grpblk_t, ext4_grpblk_t); - -typedef void (*btf_trace_ext4_trim_all_free)(void *, struct super_block *, ext4_group_t, ext4_grpblk_t, ext4_grpblk_t); - -typedef void (*btf_trace_ext4_ext_handle_unwritten_extents)(void *, struct inode *, struct ext4_map_blocks *, int, unsigned int, ext4_fsblk_t); - -typedef void (*btf_trace_ext4_get_implied_cluster_alloc_exit)(void *, struct super_block *, struct ext4_map_blocks *, int); - -typedef void (*btf_trace_ext4_ext_put_in_cache)(void *, struct inode *, ext4_lblk_t, unsigned int, ext4_fsblk_t); - -typedef void (*btf_trace_ext4_ext_in_cache)(void *, struct inode *, ext4_lblk_t, int); - -typedef void (*btf_trace_ext4_find_delalloc_range)(void *, struct inode *, ext4_lblk_t, ext4_lblk_t, int, int, ext4_lblk_t); - -typedef void (*btf_trace_ext4_get_reserved_cluster_alloc)(void *, struct inode *, ext4_lblk_t, unsigned int); - -typedef void (*btf_trace_ext4_ext_show_extent)(void *, struct inode *, ext4_lblk_t, ext4_fsblk_t, short unsigned int); - -typedef void (*btf_trace_ext4_remove_blocks)(void *, struct inode *, struct ext4_extent *, ext4_lblk_t, ext4_fsblk_t, struct partial_cluster *); - -typedef void (*btf_trace_ext4_ext_rm_leaf)(void *, struct inode *, ext4_lblk_t, struct ext4_extent *, struct partial_cluster *); - -typedef void (*btf_trace_ext4_ext_rm_idx)(void *, struct inode *, ext4_fsblk_t); - -typedef void (*btf_trace_ext4_ext_remove_space)(void *, struct inode *, ext4_lblk_t, ext4_lblk_t, int); - -typedef void (*btf_trace_ext4_ext_remove_space_done)(void *, struct inode *, ext4_lblk_t, ext4_lblk_t, int, struct partial_cluster *, __le16); - -typedef void (*btf_trace_ext4_es_insert_extent)(void *, struct inode *, struct extent_status *); - -typedef void (*btf_trace_ext4_es_cache_extent)(void *, struct inode *, struct extent_status *); - -typedef void (*btf_trace_ext4_es_remove_extent)(void *, struct inode *, ext4_lblk_t, ext4_lblk_t); - -typedef void (*btf_trace_ext4_es_find_extent_range_enter)(void *, struct inode *, ext4_lblk_t); - -typedef void (*btf_trace_ext4_es_find_extent_range_exit)(void *, struct inode *, struct extent_status *); - -typedef void (*btf_trace_ext4_es_lookup_extent_enter)(void *, struct inode *, ext4_lblk_t); - -typedef void (*btf_trace_ext4_es_lookup_extent_exit)(void *, struct inode *, struct extent_status *, int); - -typedef void (*btf_trace_ext4_es_shrink_count)(void *, struct super_block *, int, int); - -typedef void (*btf_trace_ext4_es_shrink_scan_enter)(void *, struct super_block *, int, int); - -typedef void (*btf_trace_ext4_es_shrink_scan_exit)(void *, struct super_block *, int, int); - -typedef void (*btf_trace_ext4_collapse_range)(void *, struct inode *, loff_t, loff_t); - -typedef void (*btf_trace_ext4_insert_range)(void *, struct inode *, loff_t, loff_t); - -typedef void (*btf_trace_ext4_es_shrink)(void *, struct super_block *, int, u64, int, int); - -typedef void (*btf_trace_ext4_es_insert_delayed_block)(void *, struct inode *, struct extent_status *, bool); - -typedef void (*btf_trace_ext4_fsmap_low_key)(void *, struct super_block *, u32, u32, u64, u64, u64); - -typedef void (*btf_trace_ext4_fsmap_high_key)(void *, struct super_block *, u32, u32, u64, u64, u64); - -typedef void (*btf_trace_ext4_fsmap_mapping)(void *, struct super_block *, u32, u32, u64, u64, u64); - -typedef void (*btf_trace_ext4_getfsmap_low_key)(void *, struct super_block *, struct ext4_fsmap *); - -typedef void (*btf_trace_ext4_getfsmap_high_key)(void *, struct super_block *, struct ext4_fsmap *); - -typedef void (*btf_trace_ext4_getfsmap_mapping)(void *, struct super_block *, struct ext4_fsmap *); - -typedef void (*btf_trace_ext4_shutdown)(void *, struct super_block *, long unsigned int); - -typedef void (*btf_trace_ext4_error)(void *, struct super_block *, const char *, unsigned int); - -typedef void (*btf_trace_ext4_prefetch_bitmaps)(void *, struct super_block *, ext4_group_t, ext4_group_t, unsigned int); - -typedef void (*btf_trace_ext4_lazy_itable_init)(void *, struct super_block *, ext4_group_t); - -typedef void (*btf_trace_ext4_fc_replay_scan)(void *, struct super_block *, int, int); - -typedef void (*btf_trace_ext4_fc_replay)(void *, struct super_block *, int, int, int, int); - -typedef void (*btf_trace_ext4_fc_commit_start)(void *, struct super_block *); - -typedef void (*btf_trace_ext4_fc_commit_stop)(void *, struct super_block *, int, int); - -typedef void (*btf_trace_ext4_fc_stats)(void *, struct super_block *); - -typedef void (*btf_trace_ext4_fc_track_create)(void *, struct inode *, struct dentry *, int); - -typedef void (*btf_trace_ext4_fc_track_link)(void *, struct inode *, struct dentry *, int); - -typedef void (*btf_trace_ext4_fc_track_unlink)(void *, struct inode *, struct dentry *, int); - -typedef void (*btf_trace_ext4_fc_track_inode)(void *, struct inode *, int); - -typedef void (*btf_trace_ext4_fc_track_range)(void *, struct inode *, long int, long int, int); - -enum { - Opt_bsd_df = 0, - Opt_minix_df = 1, - Opt_grpid = 2, - Opt_nogrpid = 3, - Opt_resgid = 4, - Opt_resuid = 5, - Opt_sb = 6, - Opt_err_cont = 7, - Opt_err_panic = 8, - Opt_err_ro = 9, - Opt_nouid32 = 10, - Opt_debug = 11, - Opt_removed = 12, - Opt_user_xattr = 13, - Opt_nouser_xattr = 14, - Opt_acl = 15, - Opt_noacl = 16, - Opt_auto_da_alloc = 17, - Opt_noauto_da_alloc = 18, - Opt_noload = 19, - Opt_commit = 20, - Opt_min_batch_time = 21, - Opt_max_batch_time = 22, - Opt_journal_dev = 23, - Opt_journal_path = 24, - Opt_journal_checksum = 25, - Opt_journal_async_commit = 26, - Opt_abort = 27, - Opt_data_journal = 28, - Opt_data_ordered = 29, - Opt_data_writeback = 30, - Opt_data_err_abort = 31, - Opt_data_err_ignore = 32, - Opt_test_dummy_encryption = 33, - Opt_inlinecrypt = 34, - Opt_usrjquota = 35, - Opt_grpjquota = 36, - Opt_offusrjquota = 37, - Opt_offgrpjquota = 38, - Opt_jqfmt_vfsold = 39, - Opt_jqfmt_vfsv0 = 40, - Opt_jqfmt_vfsv1 = 41, - Opt_quota = 42, - Opt_noquota = 43, - Opt_barrier = 44, - Opt_nobarrier = 45, - Opt_err___2 = 46, - Opt_usrquota = 47, - Opt_grpquota = 48, - Opt_prjquota = 49, - Opt_i_version = 50, - Opt_dax = 51, - Opt_dax_always = 52, - Opt_dax_inode = 53, - Opt_dax_never = 54, - Opt_stripe = 55, - Opt_delalloc = 56, - Opt_nodelalloc = 57, - Opt_warn_on_error = 58, - Opt_nowarn_on_error = 59, - Opt_mblk_io_submit = 60, - Opt_lazytime = 61, - Opt_nolazytime = 62, - Opt_debug_want_extra_isize = 63, - Opt_nomblk_io_submit = 64, - Opt_block_validity = 65, - Opt_noblock_validity = 66, - Opt_inode_readahead_blks = 67, - Opt_journal_ioprio = 68, - Opt_dioread_nolock = 69, - Opt_dioread_lock = 70, - Opt_discard = 71, - Opt_nodiscard = 72, - Opt_init_itable = 73, - Opt_noinit_itable = 74, - Opt_max_dir_size_kb = 75, - Opt_nojournal_checksum = 76, - Opt_nombcache = 77, - Opt_prefetch_block_bitmaps = 78, -}; - -struct mount_opts { - int token; - int mount_opt; - int flags; -}; - -struct ext4_mount_options { - long unsigned int s_mount_opt; - long unsigned int s_mount_opt2; - kuid_t s_resuid; - kgid_t s_resgid; - long unsigned int s_commit_interval; - u32 s_min_batch_time; - u32 s_max_batch_time; - int s_jquota_fmt; - char *s_qf_names[3]; -}; - -enum { - attr_noop = 0, - attr_delayed_allocation_blocks = 1, - attr_session_write_kbytes = 2, - attr_lifetime_write_kbytes = 3, - attr_reserved_clusters = 4, - attr_sra_exceeded_retry_limit = 5, - attr_inode_readahead = 6, - attr_trigger_test_error = 7, - attr_first_error_time = 8, - attr_last_error_time = 9, - attr_feature = 10, - attr_pointer_ui = 11, - attr_pointer_ul = 12, - attr_pointer_u64 = 13, - attr_pointer_u8 = 14, - attr_pointer_string = 15, - attr_pointer_atomic = 16, - attr_journal_task = 17, -}; - -enum { - ptr_explicit = 0, - ptr_ext4_sb_info_offset = 1, - ptr_ext4_super_block_offset = 2, -}; - -struct ext4_attr { - struct attribute attr; - short int attr_id; - short int attr_ptr; - short unsigned int attr_size; - union { - int offset; - void *explicit_ptr; - } u; -}; - -struct ext4_xattr_header { - __le32 h_magic; - __le32 h_refcount; - __le32 h_blocks; - __le32 h_hash; - __le32 h_checksum; - __u32 h_reserved[3]; -}; - -struct ext4_xattr_block_find { - struct ext4_xattr_search s; - struct buffer_head *bh; -}; - -struct ext4_fc_tl { - __le16 fc_tag; - __le16 fc_len; -}; - -struct ext4_fc_head { - __le32 fc_features; - __le32 fc_tid; -}; - -struct ext4_fc_add_range { - __le32 fc_ino; - __u8 fc_ex[12]; -}; - -struct ext4_fc_del_range { - __le32 fc_ino; - __le32 fc_lblk; - __le32 fc_len; -}; - -struct ext4_fc_dentry_info { - __le32 fc_parent_ino; - __le32 fc_ino; - u8 fc_dname[0]; -}; - -struct ext4_fc_inode { - __le32 fc_ino; - __u8 fc_raw_inode[0]; -}; - -struct ext4_fc_tail { - __le32 fc_tid; - __le32 fc_crc; -}; - -struct ext4_fc_dentry_update { - int fcd_op; - int fcd_parent; - int fcd_ino; - struct qstr fcd_name; - unsigned char fcd_iname[32]; - struct list_head fcd_list; -}; - -struct __track_dentry_update_args { - struct dentry *dentry; - int op; -}; - -struct __track_range_args { - ext4_lblk_t start; - ext4_lblk_t end; -}; - -struct dentry_info_args { - int parent_ino; - int dname_len; - int ino; - int inode_len; - char *dname; -}; - -typedef struct { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -} ext4_acl_entry; - -typedef struct { - __le32 a_version; -} ext4_acl_header; - -struct commit_header { - __be32 h_magic; - __be32 h_blocktype; - __be32 h_sequence; - unsigned char h_chksum_type; - unsigned char h_chksum_size; - unsigned char h_padding[2]; - __be32 h_chksum[8]; - __be64 h_commit_sec; - __be32 h_commit_nsec; -}; - -struct journal_block_tag3_s { - __be32 t_blocknr; - __be32 t_flags; - __be32 t_blocknr_high; - __be32 t_checksum; -}; - -typedef struct journal_block_tag3_s journal_block_tag3_t; - -struct journal_block_tag_s { - __be32 t_blocknr; - __be16 t_checksum; - __be16 t_flags; - __be32 t_blocknr_high; -}; - -typedef struct journal_block_tag_s journal_block_tag_t; - -struct jbd2_journal_block_tail { - __be32 t_checksum; -}; - -struct jbd2_journal_revoke_header_s { - journal_header_t r_header; - __be32 r_count; -}; - -typedef struct jbd2_journal_revoke_header_s jbd2_journal_revoke_header_t; - -struct recovery_info { - tid_t start_transaction; - tid_t end_transaction; - int nr_replays; - int nr_revokes; - int nr_revoke_hits; -}; - -struct jbd2_revoke_table_s { - int hash_size; - int hash_shift; - struct list_head *hash_table; -}; - -struct jbd2_revoke_record_s { - struct list_head hash; - tid_t sequence; - long long unsigned int blocknr; -}; - -struct trace_event_raw_jbd2_checkpoint { - struct trace_entry ent; - dev_t dev; - int result; - char __data[0]; -}; - -struct trace_event_raw_jbd2_commit { - struct trace_entry ent; - dev_t dev; - char sync_commit; - int transaction; - char __data[0]; -}; - -struct trace_event_raw_jbd2_end_commit { - struct trace_entry ent; - dev_t dev; - char sync_commit; - int transaction; - int head; - char __data[0]; -}; - -struct trace_event_raw_jbd2_submit_inode_data { - struct trace_entry ent; - dev_t dev; - ino_t ino; - char __data[0]; -}; - -struct trace_event_raw_jbd2_handle_start_class { - struct trace_entry ent; - dev_t dev; - long unsigned int tid; - unsigned int type; - unsigned int line_no; - int requested_blocks; - char __data[0]; -}; - -struct trace_event_raw_jbd2_handle_extend { - struct trace_entry ent; - dev_t dev; - long unsigned int tid; - unsigned int type; - unsigned int line_no; - int buffer_credits; - int requested_blocks; - char __data[0]; -}; - -struct trace_event_raw_jbd2_handle_stats { - struct trace_entry ent; - dev_t dev; - long unsigned int tid; - unsigned int type; - unsigned int line_no; - int interval; - int sync; - int requested_blocks; - int dirtied_blocks; - char __data[0]; -}; - -struct trace_event_raw_jbd2_run_stats { - struct trace_entry ent; - dev_t dev; - long unsigned int tid; - long unsigned int wait; - long unsigned int request_delay; - long unsigned int running; - long unsigned int locked; - long unsigned int flushing; - long unsigned int logging; - __u32 handle_count; - __u32 blocks; - __u32 blocks_logged; - char __data[0]; -}; - -struct trace_event_raw_jbd2_checkpoint_stats { - struct trace_entry ent; - dev_t dev; - long unsigned int tid; - long unsigned int chp_time; - __u32 forced_to_close; - __u32 written; - __u32 dropped; - char __data[0]; -}; - -struct trace_event_raw_jbd2_update_log_tail { - struct trace_entry ent; - dev_t dev; - tid_t tail_sequence; - tid_t first_tid; - long unsigned int block_nr; - long unsigned int freed; - char __data[0]; -}; - -struct trace_event_raw_jbd2_write_superblock { - struct trace_entry ent; - dev_t dev; - int write_op; - char __data[0]; -}; - -struct trace_event_raw_jbd2_lock_buffer_stall { - struct trace_entry ent; - dev_t dev; - long unsigned int stall_ms; - char __data[0]; -}; - -struct trace_event_data_offsets_jbd2_checkpoint {}; - -struct trace_event_data_offsets_jbd2_commit {}; - -struct trace_event_data_offsets_jbd2_end_commit {}; - -struct trace_event_data_offsets_jbd2_submit_inode_data {}; - -struct trace_event_data_offsets_jbd2_handle_start_class {}; - -struct trace_event_data_offsets_jbd2_handle_extend {}; - -struct trace_event_data_offsets_jbd2_handle_stats {}; - -struct trace_event_data_offsets_jbd2_run_stats {}; - -struct trace_event_data_offsets_jbd2_checkpoint_stats {}; - -struct trace_event_data_offsets_jbd2_update_log_tail {}; - -struct trace_event_data_offsets_jbd2_write_superblock {}; - -struct trace_event_data_offsets_jbd2_lock_buffer_stall {}; - -typedef void (*btf_trace_jbd2_checkpoint)(void *, journal_t *, int); - -typedef void (*btf_trace_jbd2_start_commit)(void *, journal_t *, transaction_t *); - -typedef void (*btf_trace_jbd2_commit_locking)(void *, journal_t *, transaction_t *); - -typedef void (*btf_trace_jbd2_commit_flushing)(void *, journal_t *, transaction_t *); - -typedef void (*btf_trace_jbd2_commit_logging)(void *, journal_t *, transaction_t *); - -typedef void (*btf_trace_jbd2_drop_transaction)(void *, journal_t *, transaction_t *); - -typedef void (*btf_trace_jbd2_end_commit)(void *, journal_t *, transaction_t *); - -typedef void (*btf_trace_jbd2_submit_inode_data)(void *, struct inode *); - -typedef void (*btf_trace_jbd2_handle_start)(void *, dev_t, long unsigned int, unsigned int, unsigned int, int); - -typedef void (*btf_trace_jbd2_handle_restart)(void *, dev_t, long unsigned int, unsigned int, unsigned int, int); - -typedef void (*btf_trace_jbd2_handle_extend)(void *, dev_t, long unsigned int, unsigned int, unsigned int, int, int); - -typedef void (*btf_trace_jbd2_handle_stats)(void *, dev_t, long unsigned int, unsigned int, unsigned int, int, int, int, int); - -typedef void (*btf_trace_jbd2_run_stats)(void *, dev_t, long unsigned int, struct transaction_run_stats_s *); - -typedef void (*btf_trace_jbd2_checkpoint_stats)(void *, dev_t, long unsigned int, struct transaction_chp_stats_s *); - -typedef void (*btf_trace_jbd2_update_log_tail)(void *, journal_t *, tid_t, long unsigned int, long unsigned int); - -typedef void (*btf_trace_jbd2_write_superblock)(void *, journal_t *, int); - -typedef void (*btf_trace_jbd2_lock_buffer_stall)(void *, dev_t, long unsigned int); - -struct jbd2_stats_proc_session { - journal_t *journal; - struct transaction_stats_s *stats; - int start; - int max; -}; - -struct ramfs_mount_opts { - umode_t mode; -}; - -struct ramfs_fs_info { - struct ramfs_mount_opts mount_opts; -}; - -enum ramfs_param { - Opt_mode___3 = 0, -}; - -typedef u16 wchar_t; - -struct nls_table { - const char *charset; - const char *alias; - int (*uni2char)(wchar_t, unsigned char *, int); - int (*char2uni)(const unsigned char *, int, wchar_t *); - const unsigned char *charset2lower; - const unsigned char *charset2upper; - struct module *owner; - struct nls_table *next; -}; - -struct fat_mount_options { - kuid_t fs_uid; - kgid_t fs_gid; - short unsigned int fs_fmask; - short unsigned int fs_dmask; - short unsigned int codepage; - int time_offset; - char *iocharset; - short unsigned int shortname; - unsigned char name_check; - unsigned char errors; - unsigned char nfs; - short unsigned int allow_utime; - unsigned int quiet: 1; - unsigned int showexec: 1; - unsigned int sys_immutable: 1; - unsigned int dotsOK: 1; - unsigned int isvfat: 1; - unsigned int utf8: 1; - unsigned int unicode_xlate: 1; - unsigned int numtail: 1; - unsigned int flush: 1; - unsigned int nocase: 1; - unsigned int usefree: 1; - unsigned int tz_set: 1; - unsigned int rodir: 1; - unsigned int discard: 1; - unsigned int dos1xfloppy: 1; -}; - -struct fatent_operations; - -struct msdos_sb_info { - short unsigned int sec_per_clus; - short unsigned int cluster_bits; - unsigned int cluster_size; - unsigned char fats; - unsigned char fat_bits; - short unsigned int fat_start; - long unsigned int fat_length; - long unsigned int dir_start; - short unsigned int dir_entries; - long unsigned int data_start; - long unsigned int max_cluster; - long unsigned int root_cluster; - long unsigned int fsinfo_sector; - struct mutex fat_lock; - struct mutex nfs_build_inode_lock; - struct mutex s_lock; - unsigned int prev_free; - unsigned int free_clusters; - unsigned int free_clus_valid; - struct fat_mount_options options; - struct nls_table *nls_disk; - struct nls_table *nls_io; - const void *dir_ops; - int dir_per_block; - int dir_per_block_bits; - unsigned int vol_id; - int fatent_shift; - const struct fatent_operations *fatent_ops; - struct inode *fat_inode; - struct inode *fsinfo_inode; - struct ratelimit_state ratelimit; - spinlock_t inode_hash_lock; - struct hlist_head inode_hashtable[256]; - spinlock_t dir_hash_lock; - struct hlist_head dir_hashtable[256]; - unsigned int dirty; - struct callback_head rcu; -}; - -struct fat_entry; - -struct fatent_operations { - void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); - void (*ent_set_ptr)(struct fat_entry *, int); - int (*ent_bread)(struct super_block *, struct fat_entry *, int, sector_t); - int (*ent_get)(struct fat_entry *); - void (*ent_put)(struct fat_entry *, int); - int (*ent_next)(struct fat_entry *); -}; - -struct msdos_inode_info { - spinlock_t cache_lru_lock; - struct list_head cache_lru; - int nr_caches; - unsigned int cache_valid_id; - loff_t mmu_private; - int i_start; - int i_logstart; - int i_attrs; - loff_t i_pos; - struct hlist_node i_fat_hash; - struct hlist_node i_dir_hash; - struct rw_semaphore truncate_lock; - struct inode vfs_inode; -}; - -struct fat_entry { - int entry; - union { - u8 *ent12_p[2]; - __le16 *ent16_p; - __le32 *ent32_p; - } u; - int nr_bhs; - struct buffer_head *bhs[2]; - struct inode *fat_inode; -}; - -struct fat_cache { - struct list_head cache_list; - int nr_contig; - int fcluster; - int dcluster; -}; - -struct fat_cache_id { - unsigned int id; - int nr_contig; - int fcluster; - int dcluster; -}; - -struct compat_dirent { - u32 d_ino; - compat_off_t d_off; - u16 d_reclen; - char d_name[256]; -}; - -enum utf16_endian { - UTF16_HOST_ENDIAN = 0, - UTF16_LITTLE_ENDIAN = 1, - UTF16_BIG_ENDIAN = 2, -}; - -struct __fat_dirent { - long int d_ino; - __kernel_off_t d_off; - short unsigned int d_reclen; - char d_name[256]; -}; - -struct msdos_dir_entry { - __u8 name[11]; - __u8 attr; - __u8 lcase; - __u8 ctime_cs; - __le16 ctime; - __le16 cdate; - __le16 adate; - __le16 starthi; - __le16 time; - __le16 date; - __le16 start; - __le32 size; -}; - -struct msdos_dir_slot { - __u8 id; - __u8 name0_4[10]; - __u8 attr; - __u8 reserved; - __u8 alias_checksum; - __u8 name5_10[12]; - __le16 start; - __u8 name11_12[4]; -}; - -struct fat_slot_info { - loff_t i_pos; - loff_t slot_off; - int nr_slots; - struct msdos_dir_entry *de; - struct buffer_head *bh; -}; - -typedef long long unsigned int llu; - -enum { - PARSE_INVALID = 1, - PARSE_NOT_LONGNAME = 2, - PARSE_EOF = 3, -}; - -struct fat_ioctl_filldir_callback { - struct dir_context ctx; - void *dirent; - int result; - const char *longname; - int long_len; - const char *shortname; - int short_len; -}; - -struct fatent_ra { - sector_t cur; - sector_t limit; - unsigned int ra_blocks; - sector_t ra_advance; - sector_t ra_next; - sector_t ra_limit; -}; - -struct fat_boot_sector { - __u8 ignored[3]; - __u8 system_id[8]; - __u8 sector_size[2]; - __u8 sec_per_clus; - __le16 reserved; - __u8 fats; - __u8 dir_entries[2]; - __u8 sectors[2]; - __u8 media; - __le16 fat_length; - __le16 secs_track; - __le16 heads; - __le32 hidden; - __le32 total_sect; - union { - struct { - __u8 drive_number; - __u8 state; - __u8 signature; - __u8 vol_id[4]; - __u8 vol_label[11]; - __u8 fs_type[8]; - } fat16; - struct { - __le32 length; - __le16 flags; - __u8 version[2]; - __le32 root_cluster; - __le16 info_sector; - __le16 backup_boot; - __le16 reserved2[6]; - __u8 drive_number; - __u8 state; - __u8 signature; - __u8 vol_id[4]; - __u8 vol_label[11]; - __u8 fs_type[8]; - } fat32; - }; -}; - -struct fat_boot_fsinfo { - __le32 signature1; - __le32 reserved1[120]; - __le32 signature2; - __le32 free_clusters; - __le32 next_cluster; - __le32 reserved2[4]; -}; - -struct fat_bios_param_block { - u16 fat_sector_size; - u8 fat_sec_per_clus; - u16 fat_reserved; - u8 fat_fats; - u16 fat_dir_entries; - u16 fat_sectors; - u16 fat_fat_length; - u32 fat_total_sect; - u8 fat16_state; - u32 fat16_vol_id; - u32 fat32_length; - u32 fat32_root_cluster; - u16 fat32_info_sector; - u8 fat32_state; - u32 fat32_vol_id; -}; - -struct fat_floppy_defaults { - unsigned int nr_sectors; - unsigned int sec_per_clus; - unsigned int dir_entries; - unsigned int media; - unsigned int fat_length; -}; - -enum { - Opt_check_n = 0, - Opt_check_r = 1, - Opt_check_s = 2, - Opt_uid___3 = 3, - Opt_gid___4 = 4, - Opt_umask = 5, - Opt_dmask = 6, - Opt_fmask = 7, - Opt_allow_utime = 8, - Opt_codepage = 9, - Opt_usefree = 10, - Opt_nocase = 11, - Opt_quiet = 12, - Opt_showexec = 13, - Opt_debug___2 = 14, - Opt_immutable = 15, - Opt_dots = 16, - Opt_nodots = 17, - Opt_charset = 18, - Opt_shortname_lower = 19, - Opt_shortname_win95 = 20, - Opt_shortname_winnt = 21, - Opt_shortname_mixed = 22, - Opt_utf8_no = 23, - Opt_utf8_yes = 24, - Opt_uni_xl_no = 25, - Opt_uni_xl_yes = 26, - Opt_nonumtail_no = 27, - Opt_nonumtail_yes = 28, - Opt_obsolete = 29, - Opt_flush = 30, - Opt_tz_utc = 31, - Opt_rodir = 32, - Opt_err_cont___2 = 33, - Opt_err_panic___2 = 34, - Opt_err_ro___2 = 35, - Opt_discard___2 = 36, - Opt_nfs = 37, - Opt_time_offset = 38, - Opt_nfs_stale_rw = 39, - Opt_nfs_nostale_ro = 40, - Opt_err___3 = 41, - Opt_dos1xfloppy = 42, -}; - -struct fat_fid { - u32 i_gen; - u32 i_pos_low; - u16 i_pos_hi; - u16 parent_i_pos_hi; - u32 parent_i_pos_low; - u32 parent_i_gen; -}; - -struct shortname_info { - unsigned char lower: 1; - unsigned char upper: 1; - unsigned char valid: 1; -}; - -struct in_addr { - __be32 s_addr; -}; - -struct sockaddr_in { - __kernel_sa_family_t sin_family; - __be16 sin_port; - struct in_addr sin_addr; - unsigned char __pad[8]; -}; - -struct sockaddr_in6 { - short unsigned int sin6_family; - __be16 sin6_port; - __be32 sin6_flowinfo; - struct in6_addr sin6_addr; - __u32 sin6_scope_id; -}; - -enum rpc_auth_flavors { - RPC_AUTH_NULL = 0, - RPC_AUTH_UNIX = 1, - RPC_AUTH_SHORT = 2, - RPC_AUTH_DES = 3, - RPC_AUTH_KRB = 4, - RPC_AUTH_GSS = 6, - RPC_AUTH_MAXFLAVOR = 8, - RPC_AUTH_GSS_KRB5 = 390003, - RPC_AUTH_GSS_KRB5I = 390004, - RPC_AUTH_GSS_KRB5P = 390005, - RPC_AUTH_GSS_LKEY = 390006, - RPC_AUTH_GSS_LKEYI = 390007, - RPC_AUTH_GSS_LKEYP = 390008, - RPC_AUTH_GSS_SPKM = 390009, - RPC_AUTH_GSS_SPKMI = 390010, - RPC_AUTH_GSS_SPKMP = 390011, -}; - -struct xdr_netobj { - unsigned int len; - u8 *data; -}; - -struct rpc_task_setup { - struct rpc_task *task; - struct rpc_clnt *rpc_client; - struct rpc_xprt *rpc_xprt; - struct rpc_cred *rpc_op_cred; - const struct rpc_message *rpc_message; - const struct rpc_call_ops *callback_ops; - void *callback_data; - struct workqueue_struct *workqueue; - short unsigned int flags; - signed char priority; -}; - -enum rpc_display_format_t { - RPC_DISPLAY_ADDR = 0, - RPC_DISPLAY_PORT = 1, - RPC_DISPLAY_PROTO = 2, - RPC_DISPLAY_HEX_ADDR = 3, - RPC_DISPLAY_HEX_PORT = 4, - RPC_DISPLAY_NETID = 5, - RPC_DISPLAY_MAX = 6, -}; - -enum xprt_transports { - XPRT_TRANSPORT_UDP = 17, - XPRT_TRANSPORT_TCP = 6, - XPRT_TRANSPORT_BC_TCP = 2147483654, - XPRT_TRANSPORT_RDMA = 256, - XPRT_TRANSPORT_BC_RDMA = 2147483904, - XPRT_TRANSPORT_LOCAL = 257, -}; - -struct svc_xprt_class; - -struct svc_xprt_ops; - -struct svc_xprt { - struct svc_xprt_class *xpt_class; - const struct svc_xprt_ops *xpt_ops; - struct kref xpt_ref; - struct list_head xpt_list; - struct list_head xpt_ready; - long unsigned int xpt_flags; - struct svc_serv *xpt_server; - atomic_t xpt_reserved; - atomic_t xpt_nr_rqsts; - struct mutex xpt_mutex; - spinlock_t xpt_lock; - void *xpt_auth_cache; - struct list_head xpt_deferred; - struct __kernel_sockaddr_storage xpt_local; - size_t xpt_locallen; - struct __kernel_sockaddr_storage xpt_remote; - size_t xpt_remotelen; - char xpt_remotebuf[58]; - struct list_head xpt_users; - struct net *xpt_net; - const struct cred *xpt_cred; - struct rpc_xprt *xpt_bc_xprt; - struct rpc_xprt_switch *xpt_bc_xps; -}; - -struct svc_program; - -struct svc_stat; - -struct svc_pool; - -struct svc_serv_ops; - -struct svc_serv { - struct svc_program *sv_program; - struct svc_stat *sv_stats; - spinlock_t sv_lock; - unsigned int sv_nrthreads; - unsigned int sv_maxconn; - unsigned int sv_max_payload; - unsigned int sv_max_mesg; - unsigned int sv_xdrsize; - struct list_head sv_permsocks; - struct list_head sv_tempsocks; - int sv_tmpcnt; - struct timer_list sv_temptimer; - char *sv_name; - unsigned int sv_nrpools; - struct svc_pool *sv_pools; - const struct svc_serv_ops *sv_ops; - struct list_head sv_cb_list; - spinlock_t sv_cb_lock; - wait_queue_head_t sv_cb_waitq; - bool sv_bc_enabled; -}; - -struct svc_stat { - struct svc_program *program; - unsigned int netcnt; - unsigned int netudpcnt; - unsigned int nettcpcnt; - unsigned int nettcpconn; - unsigned int rpccnt; - unsigned int rpcbadfmt; - unsigned int rpcbadauth; - unsigned int rpcbadclnt; -}; - -struct svc_version; - -struct svc_rqst; - -struct svc_process_info; - -struct svc_program { - struct svc_program *pg_next; - u32 pg_prog; - unsigned int pg_lovers; - unsigned int pg_hivers; - unsigned int pg_nvers; - const struct svc_version **pg_vers; - char *pg_name; - char *pg_class; - struct svc_stat *pg_stats; - int (*pg_authenticate)(struct svc_rqst *); - __be32 (*pg_init_request)(struct svc_rqst *, const struct svc_program *, struct svc_process_info *); - int (*pg_rpcbind_set)(struct net *, const struct svc_program *, u32, int, short unsigned int, short unsigned int); -}; - -struct rpc_pipe_msg { - struct list_head list; - void *data; - size_t len; - size_t copied; - int errno; -}; - -struct rpc_pipe_ops { - ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char *, size_t); - ssize_t (*downcall)(struct file *, const char *, size_t); - void (*release_pipe)(struct inode *); - int (*open_pipe)(struct inode *); - void (*destroy_msg)(struct rpc_pipe_msg *); -}; - -struct rpc_pipe { - struct list_head pipe; - struct list_head in_upcall; - struct list_head in_downcall; - int pipelen; - int nreaders; - int nwriters; - int flags; - struct delayed_work queue_timeout; - const struct rpc_pipe_ops *ops; - spinlock_t lock; - struct dentry *dentry; -}; - -struct rpc_iostats { - spinlock_t om_lock; - long unsigned int om_ops; - long unsigned int om_ntrans; - long unsigned int om_timeouts; - long long unsigned int om_bytes_sent; - long long unsigned int om_bytes_recv; - ktime_t om_queue; - ktime_t om_rtt; - ktime_t om_execute; - long unsigned int om_error_status; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct rpc_create_args { - struct net *net; - int protocol; - struct sockaddr *address; - size_t addrsize; - struct sockaddr *saddress; - const struct rpc_timeout *timeout; - const char *servername; - const char *nodename; - const struct rpc_program *program; - u32 prognumber; - u32 version; - rpc_authflavor_t authflavor; - u32 nconnect; - long unsigned int flags; - char *client_name; - struct svc_xprt *bc_xprt; - const struct cred *cred; -}; - -enum pnfs_iomode { - IOMODE_READ = 1, - IOMODE_RW = 2, - IOMODE_ANY = 3, -}; - -struct nfs4_deviceid { - char data[16]; -}; - -struct gss_api_mech; - -struct gss_ctx { - struct gss_api_mech *mech_type; - void *internal_ctx_id; - unsigned int slack; - unsigned int align; -}; - -struct gss_api_ops; - -struct pf_desc; - -struct gss_api_mech { - struct list_head gm_list; - struct module *gm_owner; - struct rpcsec_gss_oid gm_oid; - char *gm_name; - const struct gss_api_ops *gm_ops; - int gm_pf_num; - struct pf_desc *gm_pfs; - const char *gm_upcall_enctypes; -}; - -struct auth_domain; - -struct pf_desc { - u32 pseudoflavor; - u32 qop; - u32 service; - char *name; - char *auth_domain_name; - struct auth_domain *domain; - bool datatouch; -}; - -struct auth_ops; - -struct auth_domain { - struct kref ref; - struct hlist_node hash; - char *name; - struct auth_ops *flavour; - struct callback_head callback_head; -}; - -struct gss_api_ops { - int (*gss_import_sec_context)(const void *, size_t, struct gss_ctx *, time64_t *, gfp_t); - u32 (*gss_get_mic)(struct gss_ctx *, struct xdr_buf *, struct xdr_netobj *); - u32 (*gss_verify_mic)(struct gss_ctx *, struct xdr_buf *, struct xdr_netobj *); - u32 (*gss_wrap)(struct gss_ctx *, int, struct xdr_buf *, struct page **); - u32 (*gss_unwrap)(struct gss_ctx *, int, int, struct xdr_buf *); - void (*gss_delete_sec_context)(void *); -}; - -struct nfs4_xdr_opaque_data; - -struct nfs4_xdr_opaque_ops { - void (*encode)(struct xdr_stream *, const void *, const struct nfs4_xdr_opaque_data *); - void (*free)(struct nfs4_xdr_opaque_data *); -}; - -struct nfs4_xdr_opaque_data { - const struct nfs4_xdr_opaque_ops *ops; - void *data; -}; - -struct nfs4_layoutdriver_data { - struct page **pages; - __u32 pglen; - __u32 len; -}; - -struct pnfs_layout_range { - u32 iomode; - u64 offset; - u64 length; -}; - -struct nfs4_layoutget_res { - struct nfs4_sequence_res seq_res; - int status; - __u32 return_on_close; - struct pnfs_layout_range range; - __u32 type; - nfs4_stateid stateid; - struct nfs4_layoutdriver_data *layoutp; -}; - -struct pnfs_device { - struct nfs4_deviceid dev_id; - unsigned int layout_type; - unsigned int mincount; - unsigned int maxcount; - struct page **pages; - unsigned int pgbase; - unsigned int pglen; - unsigned char nocache: 1; -}; - -struct nfs4_layoutcommit_args { - struct nfs4_sequence_args seq_args; - nfs4_stateid stateid; - __u64 lastbytewritten; - struct inode *inode; - const u32 *bitmask; - size_t layoutupdate_len; - struct page *layoutupdate_page; - struct page **layoutupdate_pages; - __be32 *start_p; -}; - -struct nfs4_layoutcommit_res { - struct nfs4_sequence_res seq_res; - struct nfs_fattr *fattr; - const struct nfs_server *server; - int status; -}; - -struct nfs4_layoutcommit_data { - struct rpc_task task; - struct nfs_fattr fattr; - struct list_head lseg_list; - const struct cred *cred; - struct inode *inode; - struct nfs4_layoutcommit_args args; - struct nfs4_layoutcommit_res res; -}; - -struct pnfs_layout_hdr; - -struct nfs4_layoutreturn_args { - struct nfs4_sequence_args seq_args; - struct pnfs_layout_hdr *layout; - struct inode *inode; - struct pnfs_layout_range range; - nfs4_stateid stateid; - __u32 layout_type; - struct nfs4_xdr_opaque_data *ld_private; -}; - -struct pnfs_layout_hdr { - refcount_t plh_refcount; - atomic_t plh_outstanding; - struct list_head plh_layouts; - struct list_head plh_bulk_destroy; - struct list_head plh_segs; - struct list_head plh_return_segs; - long unsigned int plh_block_lgets; - long unsigned int plh_retry_timestamp; - long unsigned int plh_flags; - nfs4_stateid plh_stateid; - u32 plh_barrier; - u32 plh_return_seq; - enum pnfs_iomode plh_return_iomode; - loff_t plh_lwb; - const struct cred *plh_lc_cred; - struct inode *plh_inode; - struct callback_head plh_rcu; -}; - -struct nfs42_layoutstat_devinfo; - -struct nfs42_layoutstat_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - struct inode *inode; - nfs4_stateid stateid; - int num_dev; - struct nfs42_layoutstat_devinfo *devinfo; -}; - -struct nfs42_layoutstat_devinfo { - struct nfs4_deviceid dev_id; - __u64 offset; - __u64 length; - __u64 read_count; - __u64 read_bytes; - __u64 write_count; - __u64 write_bytes; - __u32 layout_type; - struct nfs4_xdr_opaque_data ld_private; -}; - -struct pnfs_layout_segment { - struct list_head pls_list; - struct list_head pls_lc_list; - struct list_head pls_commits; - struct pnfs_layout_range pls_range; - refcount_t pls_refcount; - u32 pls_seq; - long unsigned int pls_flags; - struct pnfs_layout_hdr *pls_layout; -}; - -struct nfs_page { - struct list_head wb_list; - struct page *wb_page; - struct nfs_lock_context *wb_lock_context; - long unsigned int wb_index; - unsigned int wb_offset; - unsigned int wb_pgbase; - unsigned int wb_bytes; - struct kref wb_kref; - long unsigned int wb_flags; - struct nfs_write_verifier wb_verf; - struct nfs_page *wb_this_page; - struct nfs_page *wb_head; - short unsigned int wb_nio; -}; - -struct nfs_subversion { - struct module *owner; - struct file_system_type *nfs_fs; - const struct rpc_version *rpc_vers; - const struct nfs_rpc_ops *rpc_ops; - const struct super_operations *sops; - const struct xattr_handler **xattr; - struct list_head list; -}; - -struct nfs_iostats { - long long unsigned int bytes[8]; - long long unsigned int fscache[5]; - long unsigned int events[27]; -}; - -struct nfs_fscache_key { - struct rb_node node; - struct nfs_client *nfs_client; - struct { - struct { - long unsigned int s_flags; - } super; - struct { - struct nfs_fsid fsid; - int flags; - unsigned int rsize; - unsigned int wsize; - unsigned int acregmin; - unsigned int acregmax; - unsigned int acdirmin; - unsigned int acdirmax; - } nfs_server; - struct { - rpc_authflavor_t au_flavor; - } rpc_auth; - u8 uniq_len; - char uniquifier[0]; - } key; -}; - -enum pnfs_try_status { - PNFS_ATTEMPTED = 0, - PNFS_NOT_ATTEMPTED = 1, - PNFS_TRY_AGAIN = 2, -}; - -struct nfs_pageio_ops; - -struct nfs4_deviceid_node; - -struct pnfs_layoutdriver_type { - struct list_head pnfs_tblid; - const u32 id; - const char *name; - struct module *owner; - unsigned int flags; - unsigned int max_deviceinfo_size; - unsigned int max_layoutget_response; - int (*set_layoutdriver)(struct nfs_server *, const struct nfs_fh *); - int (*clear_layoutdriver)(struct nfs_server *); - struct pnfs_layout_hdr * (*alloc_layout_hdr)(struct inode *, gfp_t); - void (*free_layout_hdr)(struct pnfs_layout_hdr *); - struct pnfs_layout_segment * (*alloc_lseg)(struct pnfs_layout_hdr *, struct nfs4_layoutget_res *, gfp_t); - void (*free_lseg)(struct pnfs_layout_segment *); - void (*add_lseg)(struct pnfs_layout_hdr *, struct pnfs_layout_segment *, struct list_head *); - void (*return_range)(struct pnfs_layout_hdr *, struct pnfs_layout_range *); - const struct nfs_pageio_ops *pg_read_ops; - const struct nfs_pageio_ops *pg_write_ops; - struct pnfs_ds_commit_info * (*get_ds_info)(struct inode *); - int (*sync)(struct inode *, bool); - enum pnfs_try_status (*read_pagelist)(struct nfs_pgio_header *); - enum pnfs_try_status (*write_pagelist)(struct nfs_pgio_header *, int); - void (*free_deviceid_node)(struct nfs4_deviceid_node *); - struct nfs4_deviceid_node * (*alloc_deviceid_node)(struct nfs_server *, struct pnfs_device *, gfp_t); - int (*prepare_layoutreturn)(struct nfs4_layoutreturn_args *); - void (*cleanup_layoutcommit)(struct nfs4_layoutcommit_data *); - int (*prepare_layoutcommit)(struct nfs4_layoutcommit_args *); - int (*prepare_layoutstats)(struct nfs42_layoutstat_args *); -}; - -struct svc_cred { - kuid_t cr_uid; - kgid_t cr_gid; - struct group_info *cr_group_info; - u32 cr_flavor; - char *cr_raw_principal; - char *cr_principal; - char *cr_targ_princ; - struct gss_api_mech *cr_gss_mech; -}; - -struct cache_deferred_req; - -struct cache_req { - struct cache_deferred_req * (*defer)(struct cache_req *); - int thread_wait; -}; - -struct svc_cacherep; - -struct svc_procedure; - -struct svc_deferred_req; - -struct svc_rqst { - struct list_head rq_all; - struct callback_head rq_rcu_head; - struct svc_xprt *rq_xprt; - struct __kernel_sockaddr_storage rq_addr; - size_t rq_addrlen; - struct __kernel_sockaddr_storage rq_daddr; - size_t rq_daddrlen; - struct svc_serv *rq_server; - struct svc_pool *rq_pool; - const struct svc_procedure *rq_procinfo; - struct auth_ops *rq_authop; - struct svc_cred rq_cred; - void *rq_xprt_ctxt; - struct svc_deferred_req *rq_deferred; - size_t rq_xprt_hlen; - struct xdr_buf rq_arg; - struct xdr_buf rq_res; - struct page *rq_pages[260]; - struct page **rq_respages; - struct page **rq_next_page; - struct page **rq_page_end; - struct kvec rq_vec[259]; - struct bio_vec rq_bvec[259]; - __be32 rq_xid; - u32 rq_prog; - u32 rq_vers; - u32 rq_proc; - u32 rq_prot; - int rq_cachetype; - long unsigned int rq_flags; - ktime_t rq_qtime; - void *rq_argp; - void *rq_resp; - void *rq_auth_data; - int rq_auth_slack; - int rq_reserved; - ktime_t rq_stime; - struct cache_req rq_chandle; - struct auth_domain *rq_client; - struct auth_domain *rq_gssclient; - struct svc_cacherep *rq_cacherep; - struct task_struct *rq_task; - spinlock_t rq_lock; - struct net *rq_bc_net; - void **rq_lease_breaker; -}; - -struct nlmclnt_initdata { - const char *hostname; - const struct sockaddr *address; - size_t addrlen; - short unsigned int protocol; - u32 nfs_version; - int noresvport; - struct net *net; - const struct nlmclnt_operations *nlmclnt_ops; - const struct cred *cred; -}; - -struct cache_head { - struct hlist_node cache_list; - time64_t expiry_time; - time64_t last_refresh; - struct kref ref; - long unsigned int flags; -}; - -struct cache_detail { - struct module *owner; - int hash_size; - struct hlist_head *hash_table; - spinlock_t hash_lock; - char *name; - void (*cache_put)(struct kref *); - int (*cache_upcall)(struct cache_detail *, struct cache_head *); - void (*cache_request)(struct cache_detail *, struct cache_head *, char **, int *); - int (*cache_parse)(struct cache_detail *, char *, int); - int (*cache_show)(struct seq_file *, struct cache_detail *, struct cache_head *); - void (*warn_no_listener)(struct cache_detail *, int); - struct cache_head * (*alloc)(); - void (*flush)(); - int (*match)(struct cache_head *, struct cache_head *); - void (*init)(struct cache_head *, struct cache_head *); - void (*update)(struct cache_head *, struct cache_head *); - time64_t flush_time; - struct list_head others; - time64_t nextcheck; - int entries; - struct list_head queue; - atomic_t writers; - time64_t last_close; - time64_t last_warn; - union { - struct proc_dir_entry *procfs; - struct dentry *pipefs; - }; - struct net *net; -}; - -struct cache_deferred_req { - struct hlist_node hash; - struct list_head recent; - struct cache_head *item; - void *owner; - void (*revisit)(struct cache_deferred_req *, int); -}; - -struct auth_ops { - char *name; - struct module *owner; - int flavour; - int (*accept)(struct svc_rqst *, __be32 *); - int (*release)(struct svc_rqst *); - void (*domain_release)(struct auth_domain *); - int (*set_client)(struct svc_rqst *); -}; - -struct svc_pool_stats { - atomic_long_t packets; - long unsigned int sockets_queued; - atomic_long_t threads_woken; - atomic_long_t threads_timedout; -}; - -struct svc_pool { - unsigned int sp_id; - spinlock_t sp_lock; - struct list_head sp_sockets; - unsigned int sp_nrthreads; - struct list_head sp_all_threads; - struct svc_pool_stats sp_stats; - long unsigned int sp_flags; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct svc_serv_ops { - void (*svo_shutdown)(struct svc_serv *, struct net *); - int (*svo_function)(void *); - void (*svo_enqueue_xprt)(struct svc_xprt *); - int (*svo_setup)(struct svc_serv *, struct svc_pool *, int); - struct module *svo_module; -}; - -struct svc_procedure { - __be32 (*pc_func)(struct svc_rqst *); - int (*pc_decode)(struct svc_rqst *, __be32 *); - int (*pc_encode)(struct svc_rqst *, __be32 *); - void (*pc_release)(struct svc_rqst *); - unsigned int pc_argsize; - unsigned int pc_ressize; - unsigned int pc_cachetype; - unsigned int pc_xdrressize; -}; - -struct svc_deferred_req { - u32 prot; - struct svc_xprt *xprt; - struct __kernel_sockaddr_storage addr; - size_t addrlen; - struct __kernel_sockaddr_storage daddr; - size_t daddrlen; - struct cache_deferred_req handle; - size_t xprt_hlen; - int argslen; - __be32 args[0]; -}; - -struct svc_process_info { - union { - int (*dispatch)(struct svc_rqst *, __be32 *); - struct { - unsigned int lovers; - unsigned int hivers; - } mismatch; - }; -}; - -struct svc_version { - u32 vs_vers; - u32 vs_nproc; - const struct svc_procedure *vs_proc; - unsigned int *vs_count; - u32 vs_xdrsize; - bool vs_hidden; - bool vs_rpcb_optnl; - bool vs_need_cong_ctrl; - int (*vs_dispatch)(struct svc_rqst *, __be32 *); -}; - -struct svc_xprt_ops { - struct svc_xprt * (*xpo_create)(struct svc_serv *, struct net *, struct sockaddr *, int, int); - struct svc_xprt * (*xpo_accept)(struct svc_xprt *); - int (*xpo_has_wspace)(struct svc_xprt *); - int (*xpo_recvfrom)(struct svc_rqst *); - int (*xpo_sendto)(struct svc_rqst *); - int (*xpo_read_payload)(struct svc_rqst *, unsigned int, unsigned int); - void (*xpo_release_rqst)(struct svc_rqst *); - void (*xpo_detach)(struct svc_xprt *); - void (*xpo_free)(struct svc_xprt *); - void (*xpo_secure_port)(struct svc_rqst *); - void (*xpo_kill_temp_xprt)(struct svc_xprt *); -}; - -struct svc_xprt_class { - const char *xcl_name; - struct module *xcl_owner; - const struct svc_xprt_ops *xcl_ops; - struct list_head xcl_list; - u32 xcl_max_payload; - int xcl_ident; -}; - -enum nfs_stat_bytecounters { - NFSIOS_NORMALREADBYTES = 0, - NFSIOS_NORMALWRITTENBYTES = 1, - NFSIOS_DIRECTREADBYTES = 2, - NFSIOS_DIRECTWRITTENBYTES = 3, - NFSIOS_SERVERREADBYTES = 4, - NFSIOS_SERVERWRITTENBYTES = 5, - NFSIOS_READPAGES = 6, - NFSIOS_WRITEPAGES = 7, - __NFSIOS_BYTESMAX = 8, -}; - -enum nfs_stat_eventcounters { - NFSIOS_INODEREVALIDATE = 0, - NFSIOS_DENTRYREVALIDATE = 1, - NFSIOS_DATAINVALIDATE = 2, - NFSIOS_ATTRINVALIDATE = 3, - NFSIOS_VFSOPEN = 4, - NFSIOS_VFSLOOKUP = 5, - NFSIOS_VFSACCESS = 6, - NFSIOS_VFSUPDATEPAGE = 7, - NFSIOS_VFSREADPAGE = 8, - NFSIOS_VFSREADPAGES = 9, - NFSIOS_VFSWRITEPAGE = 10, - NFSIOS_VFSWRITEPAGES = 11, - NFSIOS_VFSGETDENTS = 12, - NFSIOS_VFSSETATTR = 13, - NFSIOS_VFSFLUSH = 14, - NFSIOS_VFSFSYNC = 15, - NFSIOS_VFSLOCK = 16, - NFSIOS_VFSRELEASE = 17, - NFSIOS_CONGESTIONWAIT = 18, - NFSIOS_SETATTRTRUNC = 19, - NFSIOS_EXTENDWRITE = 20, - NFSIOS_SILLYRENAME = 21, - NFSIOS_SHORTREAD = 22, - NFSIOS_SHORTWRITE = 23, - NFSIOS_DELAY = 24, - NFSIOS_PNFS_READ = 25, - NFSIOS_PNFS_WRITE = 26, - __NFSIOS_COUNTSMAX = 27, -}; - -enum nfs_stat_fscachecounters { - NFSIOS_FSCACHE_PAGES_READ_OK = 0, - NFSIOS_FSCACHE_PAGES_READ_FAIL = 1, - NFSIOS_FSCACHE_PAGES_WRITTEN_OK = 2, - NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL = 3, - NFSIOS_FSCACHE_PAGES_UNCACHED = 4, - __NFSIOS_FSCACHEMAX = 5, -}; - -struct nfs_pageio_descriptor; - -struct nfs_pgio_mirror; - -struct nfs_pageio_ops { - void (*pg_init)(struct nfs_pageio_descriptor *, struct nfs_page *); - size_t (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); - int (*pg_doio)(struct nfs_pageio_descriptor *); - unsigned int (*pg_get_mirror_count)(struct nfs_pageio_descriptor *, struct nfs_page *); - void (*pg_cleanup)(struct nfs_pageio_descriptor *); - struct nfs_pgio_mirror * (*pg_get_mirror)(struct nfs_pageio_descriptor *, u32); - u32 (*pg_set_mirror)(struct nfs_pageio_descriptor *, u32); -}; - -struct nfs_pgio_mirror { - struct list_head pg_list; - long unsigned int pg_bytes_written; - size_t pg_count; - size_t pg_bsize; - unsigned int pg_base; - unsigned char pg_recoalesce: 1; -}; - -struct nfs_pageio_descriptor { - struct inode *pg_inode; - const struct nfs_pageio_ops *pg_ops; - const struct nfs_rw_ops *pg_rw_ops; - int pg_ioflags; - int pg_error; - const struct rpc_call_ops *pg_rpc_callops; - const struct nfs_pgio_completion_ops *pg_completion_ops; - struct pnfs_layout_segment *pg_lseg; - struct nfs_io_completion *pg_io_completion; - struct nfs_direct_req *pg_dreq; - unsigned int pg_bsize; - u32 pg_mirror_count; - struct nfs_pgio_mirror *pg_mirrors; - struct nfs_pgio_mirror pg_mirrors_static[1]; - struct nfs_pgio_mirror *pg_mirrors_dynamic; - u32 pg_mirror_idx; - short unsigned int pg_maxretrans; - unsigned char pg_moreio: 1; -}; - -struct nfs_clone_mount { - struct super_block *sb; - struct dentry *dentry; - struct nfs_fattr *fattr; - unsigned int inherited_bsize; -}; - -struct nfs_fs_context { - bool internal; - bool skip_reconfig_option_check; - bool need_mount; - bool sloppy; - unsigned int flags; - unsigned int rsize; - unsigned int wsize; - unsigned int timeo; - unsigned int retrans; - unsigned int acregmin; - unsigned int acregmax; - unsigned int acdirmin; - unsigned int acdirmax; - unsigned int namlen; - unsigned int options; - unsigned int bsize; - struct nfs_auth_info auth_info; - rpc_authflavor_t selected_flavor; - char *client_address; - unsigned int version; - unsigned int minorversion; - char *fscache_uniq; - short unsigned int protofamily; - short unsigned int mountfamily; - struct { - union { - struct sockaddr address; - struct __kernel_sockaddr_storage _address; - }; - size_t addrlen; - char *hostname; - u32 version; - int port; - short unsigned int protocol; - } mount_server; - struct { - union { - struct sockaddr address; - struct __kernel_sockaddr_storage _address; - }; - size_t addrlen; - char *hostname; - char *export_path; - int port; - short unsigned int protocol; - short unsigned int nconnect; - short unsigned int export_path_len; - } nfs_server; - struct nfs_fh *mntfh; - struct nfs_server *server; - struct nfs_subversion *nfs_mod; - struct nfs_clone_mount clone_data; -}; - -struct nfs4_deviceid_node { - struct hlist_node node; - struct hlist_node tmpnode; - const struct pnfs_layoutdriver_type *ld; - const struct nfs_client *nfs_client; - long unsigned int flags; - long unsigned int timestamp_unavailable; - struct nfs4_deviceid deviceid; - struct callback_head rcu; - atomic_t ref; -}; - -struct bl_dev_msg { - int32_t status; - uint32_t major; - uint32_t minor; -}; - -struct nfs_netns_client; - -struct nfs_net { - struct cache_detail *nfs_dns_resolve; - struct rpc_pipe *bl_device_pipe; - struct bl_dev_msg bl_mount_reply; - wait_queue_head_t bl_wq; - struct mutex bl_mutex; - struct list_head nfs_client_list; - struct list_head nfs_volume_list; - struct idr cb_ident_idr; - short unsigned int nfs_callback_tcpport; - short unsigned int nfs_callback_tcpport6; - int cb_users[3]; - struct nfs_netns_client *nfs_client; - spinlock_t nfs_client_lock; - ktime_t boot_time; - struct proc_dir_entry *proc_nfsfs; -}; - -struct nfs_netns_client { - struct kobject kobject; - struct net *net; - const char *identifier; -}; - -struct nfs_open_dir_context { - struct list_head list; - const struct cred *cred; - long unsigned int attr_gencount; - __u64 dir_cookie; - __u64 dup_cookie; - signed char duped; -}; - -struct nfs4_cached_acl; - -struct nfs_delegation; - -struct nfs4_xattr_cache; - -struct nfs_inode { - __u64 fileid; - struct nfs_fh fh; - long unsigned int flags; - long unsigned int cache_validity; - long unsigned int read_cache_jiffies; - long unsigned int attrtimeo; - long unsigned int attrtimeo_timestamp; - long unsigned int attr_gencount; - long unsigned int cache_change_attribute; - struct rb_root access_cache; - struct list_head access_cache_entry_lru; - struct list_head access_cache_inode_lru; - __be32 cookieverf[2]; - atomic_long_t nrequests; - struct nfs_mds_commit_info commit_info; - struct list_head open_files; - struct rw_semaphore rmdir_sem; - struct mutex commit_mutex; - long unsigned int page_index; - struct nfs4_cached_acl *nfs4_acl; - struct list_head open_states; - struct nfs_delegation *delegation; - struct rw_semaphore rwsem; - struct pnfs_layout_hdr *layout; - __u64 write_io; - __u64 read_io; - struct fscache_cookie *fscache; - struct inode vfs_inode; - struct nfs4_xattr_cache *xattr_cache; -}; - -struct nfs_delegation { - struct list_head super_list; - const struct cred *cred; - struct inode *inode; - nfs4_stateid stateid; - fmode_t type; - long unsigned int pagemod_limit; - __u64 change_attr; - long unsigned int flags; - refcount_t refcount; - spinlock_t lock; - struct callback_head rcu; -}; - -struct nfs_cache_array_entry { - u64 cookie; - u64 ino; - struct qstr string; - unsigned char d_type; -}; - -struct nfs_cache_array { - int size; - int eof_index; - u64 last_cookie; - struct nfs_cache_array_entry array[0]; -}; - -typedef struct { - struct file *file; - struct page *page; - struct dir_context *ctx; - long unsigned int page_index; - u64 *dir_cookie; - u64 last_cookie; - loff_t current_index; - loff_t prev_index; - long unsigned int dir_verifier; - long unsigned int timestamp; - long unsigned int gencount; - unsigned int cache_entry_index; - bool plus; - bool eof; -} nfs_readdir_descriptor_t; - -enum layoutdriver_policy_flags { - PNFS_LAYOUTRET_ON_SETATTR = 1, - PNFS_LAYOUTRET_ON_ERROR = 2, - PNFS_READ_WHOLE_PAGE = 4, - PNFS_LAYOUTGET_ON_OPEN = 8, -}; - -struct nfs_find_desc { - struct nfs_fh *fh; - struct nfs_fattr *fattr; -}; - -struct nfs4_sessionid { - unsigned char data[16]; -}; - -struct nfs4_channel_attrs { - u32 max_rqst_sz; - u32 max_resp_sz; - u32 max_resp_sz_cached; - u32 max_ops; - u32 max_reqs; -}; - -struct nfs4_slot { - struct nfs4_slot_table *table; - struct nfs4_slot *next; - long unsigned int generation; - u32 slot_nr; - u32 seq_nr; - u32 seq_nr_last_acked; - u32 seq_nr_highest_sent; - unsigned int privileged: 1; - unsigned int seq_done: 1; -}; - -struct nfs4_slot_table { - struct nfs4_session *session; - struct nfs4_slot *slots; - long unsigned int used_slots[16]; - spinlock_t slot_tbl_lock; - struct rpc_wait_queue slot_tbl_waitq; - wait_queue_head_t slot_waitq; - u32 max_slots; - u32 max_slotid; - u32 highest_used_slotid; - u32 target_highest_slotid; - u32 server_highest_slotid; - s32 d_target_highest_slotid; - s32 d2_target_highest_slotid; - long unsigned int generation; - struct completion complete; - long unsigned int slot_tbl_state; -}; - -struct nfs4_session { - struct nfs4_sessionid sess_id; - u32 flags; - long unsigned int session_state; - u32 hash_alg; - u32 ssv_len; - struct nfs4_channel_attrs fc_attrs; - struct nfs4_slot_table fc_slot_table; - struct nfs4_channel_attrs bc_attrs; - struct nfs4_slot_table bc_slot_table; - struct nfs_client *clp; -}; - -struct nfs_mount_request { - struct sockaddr *sap; - size_t salen; - char *hostname; - char *dirpath; - u32 version; - short unsigned int protocol; - struct nfs_fh *fh; - int noresvport; - unsigned int *auth_flav_len; - rpc_authflavor_t *auth_flavs; - struct net *net; -}; - -struct proc_nfs_info { - int flag; - const char *str; - const char *nostr; -}; - -struct pnfs_commit_bucket { - struct list_head written; - struct list_head committing; - struct pnfs_layout_segment *lseg; - struct nfs_writeverf direct_verf; -}; - -struct pnfs_commit_array { - struct list_head cinfo_list; - struct list_head lseg_list; - struct pnfs_layout_segment *lseg; - struct callback_head rcu; - refcount_t refcount; - unsigned int nbuckets; - struct pnfs_commit_bucket buckets[0]; -}; - -enum { - NFS_IOHDR_ERROR = 0, - NFS_IOHDR_EOF = 1, - NFS_IOHDR_REDO = 2, - NFS_IOHDR_STAT = 3, - NFS_IOHDR_RESEND_PNFS = 4, - NFS_IOHDR_RESEND_MDS = 5, -}; - -struct nfs_direct_req { - struct kref kref; - struct nfs_open_context *ctx; - struct nfs_lock_context *l_ctx; - struct kiocb *iocb; - struct inode *inode; - atomic_t io_count; - spinlock_t lock; - loff_t io_start; - ssize_t count; - ssize_t max_count; - ssize_t bytes_left; - ssize_t error; - struct completion completion; - struct nfs_mds_commit_info mds_cinfo; - struct pnfs_ds_commit_info ds_cinfo; - struct work_struct work; - int flags; -}; - -enum { - PG_BUSY = 0, - PG_MAPPED = 1, - PG_CLEAN = 2, - PG_COMMIT_TO_DS = 3, - PG_INODE_REF = 4, - PG_HEADLOCK = 5, - PG_TEARDOWN = 6, - PG_UNLOCKPAGE = 7, - PG_UPTODATE = 8, - PG_WB_END = 9, - PG_REMOVE = 10, - PG_CONTENDED1 = 11, - PG_CONTENDED2 = 12, -}; - -struct nfs_readdesc { - struct nfs_pageio_descriptor *pgio; - struct nfs_open_context *ctx; -}; - -struct nfs_io_completion { - void (*complete)(void *); - void *data; - struct kref refcount; -}; - -enum { - MOUNTPROC_NULL = 0, - MOUNTPROC_MNT = 1, - MOUNTPROC_DUMP = 2, - MOUNTPROC_UMNT = 3, - MOUNTPROC_UMNTALL = 4, - MOUNTPROC_EXPORT = 5, -}; - -enum { - MOUNTPROC3_NULL = 0, - MOUNTPROC3_MNT = 1, - MOUNTPROC3_DUMP = 2, - MOUNTPROC3_UMNT = 3, - MOUNTPROC3_UMNTALL = 4, - MOUNTPROC3_EXPORT = 5, -}; - -enum mountstat { - MNT_OK = 0, - MNT_EPERM = 1, - MNT_ENOENT = 2, - MNT_EACCES = 13, - MNT_EINVAL = 22, -}; - -enum mountstat3 { - MNT3_OK = 0, - MNT3ERR_PERM = 1, - MNT3ERR_NOENT = 2, - MNT3ERR_IO = 5, - MNT3ERR_ACCES = 13, - MNT3ERR_NOTDIR = 20, - MNT3ERR_INVAL = 22, - MNT3ERR_NAMETOOLONG = 63, - MNT3ERR_NOTSUPP = 10004, - MNT3ERR_SERVERFAULT = 10006, -}; - -struct mountres { - int errno; - struct nfs_fh *fh; - unsigned int *auth_count; - rpc_authflavor_t *auth_flavors; -}; - -enum nfs_stat { - NFS_OK = 0, - NFSERR_PERM = 1, - NFSERR_NOENT = 2, - NFSERR_IO = 5, - NFSERR_NXIO = 6, - NFSERR_EAGAIN = 11, - NFSERR_ACCES = 13, - NFSERR_EXIST = 17, - NFSERR_XDEV = 18, - NFSERR_NODEV = 19, - NFSERR_NOTDIR = 20, - NFSERR_ISDIR = 21, - NFSERR_INVAL = 22, - NFSERR_FBIG = 27, - NFSERR_NOSPC = 28, - NFSERR_ROFS = 30, - NFSERR_MLINK = 31, - NFSERR_OPNOTSUPP = 45, - NFSERR_NAMETOOLONG = 63, - NFSERR_NOTEMPTY = 66, - NFSERR_DQUOT = 69, - NFSERR_STALE = 70, - NFSERR_REMOTE = 71, - NFSERR_WFLUSH = 99, - NFSERR_BADHANDLE = 10001, - NFSERR_NOT_SYNC = 10002, - NFSERR_BAD_COOKIE = 10003, - NFSERR_NOTSUPP = 10004, - NFSERR_TOOSMALL = 10005, - NFSERR_SERVERFAULT = 10006, - NFSERR_BADTYPE = 10007, - NFSERR_JUKEBOX = 10008, - NFSERR_SAME = 10009, - NFSERR_DENIED = 10010, - NFSERR_EXPIRED = 10011, - NFSERR_LOCKED = 10012, - NFSERR_GRACE = 10013, - NFSERR_FHEXPIRED = 10014, - NFSERR_SHARE_DENIED = 10015, - NFSERR_WRONGSEC = 10016, - NFSERR_CLID_INUSE = 10017, - NFSERR_RESOURCE = 10018, - NFSERR_MOVED = 10019, - NFSERR_NOFILEHANDLE = 10020, - NFSERR_MINOR_VERS_MISMATCH = 10021, - NFSERR_STALE_CLIENTID = 10022, - NFSERR_STALE_STATEID = 10023, - NFSERR_OLD_STATEID = 10024, - NFSERR_BAD_STATEID = 10025, - NFSERR_BAD_SEQID = 10026, - NFSERR_NOT_SAME = 10027, - NFSERR_LOCK_RANGE = 10028, - NFSERR_SYMLINK = 10029, - NFSERR_RESTOREFH = 10030, - NFSERR_LEASE_MOVED = 10031, - NFSERR_ATTRNOTSUPP = 10032, - NFSERR_NO_GRACE = 10033, - NFSERR_RECLAIM_BAD = 10034, - NFSERR_RECLAIM_CONFLICT = 10035, - NFSERR_BAD_XDR = 10036, - NFSERR_LOCKS_HELD = 10037, - NFSERR_OPENMODE = 10038, - NFSERR_BADOWNER = 10039, - NFSERR_BADCHAR = 10040, - NFSERR_BADNAME = 10041, - NFSERR_BAD_RANGE = 10042, - NFSERR_LOCK_NOTSUPP = 10043, - NFSERR_OP_ILLEGAL = 10044, - NFSERR_DEADLOCK = 10045, - NFSERR_FILE_OPEN = 10046, - NFSERR_ADMIN_REVOKED = 10047, - NFSERR_CB_PATH_DOWN = 10048, -}; - -struct trace_event_raw_nfs_inode_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - u64 version; - char __data[0]; -}; - -struct trace_event_raw_nfs_inode_event_done { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u32 fhandle; - unsigned char type; - u64 fileid; - u64 version; - loff_t size; - long unsigned int nfsi_flags; - long unsigned int cache_validity; - char __data[0]; -}; - -struct trace_event_raw_nfs_access_exit { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u32 fhandle; - unsigned char type; - u64 fileid; - u64 version; - loff_t size; - long unsigned int nfsi_flags; - long unsigned int cache_validity; - unsigned int mask; - unsigned int permitted; - char __data[0]; -}; - -struct trace_event_raw_nfs_lookup_event { - struct trace_entry ent; - long unsigned int flags; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_lookup_event_done { - struct trace_entry ent; - long unsigned int error; - long unsigned int flags; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_atomic_open_enter { - struct trace_entry ent; - long unsigned int flags; - unsigned int fmode; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_atomic_open_exit { - struct trace_entry ent; - long unsigned int error; - long unsigned int flags; - unsigned int fmode; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_create_enter { - struct trace_entry ent; - long unsigned int flags; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_create_exit { - struct trace_entry ent; - long unsigned int error; - long unsigned int flags; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_directory_event { - struct trace_entry ent; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_directory_event_done { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_link_enter { - struct trace_entry ent; - dev_t dev; - u64 fileid; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_link_exit { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u64 fileid; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_rename_event { - struct trace_entry ent; - dev_t dev; - u64 old_dir; - u64 new_dir; - u32 __data_loc_old_name; - u32 __data_loc_new_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_rename_event_done { - struct trace_entry ent; - dev_t dev; - long unsigned int error; - u64 old_dir; - u32 __data_loc_old_name; - u64 new_dir; - u32 __data_loc_new_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_sillyrename_unlink { - struct trace_entry ent; - dev_t dev; - long unsigned int error; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs_initiate_read { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 count; - char __data[0]; -}; - -struct trace_event_raw_nfs_readpage_done { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 arg_count; - u32 res_count; - bool eof; - int status; - char __data[0]; -}; - -struct trace_event_raw_nfs_readpage_short { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 arg_count; - u32 res_count; - bool eof; - int status; - char __data[0]; -}; - -struct trace_event_raw_nfs_pgio_error { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 arg_count; - u32 res_count; - loff_t pos; - int status; - char __data[0]; -}; - -struct trace_event_raw_nfs_initiate_write { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 count; - enum nfs3_stable_how stable; - char __data[0]; -}; - -struct trace_event_raw_nfs_writeback_done { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 arg_count; - u32 res_count; - int status; - enum nfs3_stable_how stable; - char verifier[8]; - char __data[0]; -}; - -struct trace_event_raw_nfs_page_error_class { - struct trace_entry ent; - const void *req; - long unsigned int index; - unsigned int offset; - unsigned int pgbase; - unsigned int bytes; - int error; - char __data[0]; -}; - -struct trace_event_raw_nfs_initiate_commit { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 count; - char __data[0]; -}; - -struct trace_event_raw_nfs_commit_done { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - int status; - enum nfs3_stable_how stable; - char verifier[8]; - char __data[0]; -}; - -struct trace_event_raw_nfs_fh_to_dentry { - struct trace_entry ent; - int error; - dev_t dev; - u32 fhandle; - u64 fileid; - char __data[0]; -}; - -struct trace_event_raw_nfs_xdr_status { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - int version; - long unsigned int error; - u32 __data_loc_program; - u32 __data_loc_procedure; - char __data[0]; -}; - -struct trace_event_data_offsets_nfs_inode_event {}; - -struct trace_event_data_offsets_nfs_inode_event_done {}; - -struct trace_event_data_offsets_nfs_access_exit {}; - -struct trace_event_data_offsets_nfs_lookup_event { - u32 name; -}; - -struct trace_event_data_offsets_nfs_lookup_event_done { - u32 name; -}; - -struct trace_event_data_offsets_nfs_atomic_open_enter { - u32 name; -}; - -struct trace_event_data_offsets_nfs_atomic_open_exit { - u32 name; -}; - -struct trace_event_data_offsets_nfs_create_enter { - u32 name; -}; - -struct trace_event_data_offsets_nfs_create_exit { - u32 name; -}; - -struct trace_event_data_offsets_nfs_directory_event { - u32 name; -}; - -struct trace_event_data_offsets_nfs_directory_event_done { - u32 name; -}; - -struct trace_event_data_offsets_nfs_link_enter { - u32 name; -}; - -struct trace_event_data_offsets_nfs_link_exit { - u32 name; -}; - -struct trace_event_data_offsets_nfs_rename_event { - u32 old_name; - u32 new_name; -}; - -struct trace_event_data_offsets_nfs_rename_event_done { - u32 old_name; - u32 new_name; -}; - -struct trace_event_data_offsets_nfs_sillyrename_unlink { - u32 name; -}; - -struct trace_event_data_offsets_nfs_initiate_read {}; - -struct trace_event_data_offsets_nfs_readpage_done {}; - -struct trace_event_data_offsets_nfs_readpage_short {}; - -struct trace_event_data_offsets_nfs_pgio_error {}; - -struct trace_event_data_offsets_nfs_initiate_write {}; - -struct trace_event_data_offsets_nfs_writeback_done {}; - -struct trace_event_data_offsets_nfs_page_error_class {}; - -struct trace_event_data_offsets_nfs_initiate_commit {}; - -struct trace_event_data_offsets_nfs_commit_done {}; - -struct trace_event_data_offsets_nfs_fh_to_dentry {}; - -struct trace_event_data_offsets_nfs_xdr_status { - u32 program; - u32 procedure; -}; - -typedef void (*btf_trace_nfs_set_inode_stale)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_refresh_inode_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_refresh_inode_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_revalidate_inode_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_revalidate_inode_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_invalidate_mapping_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_invalidate_mapping_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_getattr_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_getattr_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_setattr_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_setattr_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_writeback_page_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_writeback_page_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_writeback_inode_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_writeback_inode_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_fsync_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_fsync_exit)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs_access_enter)(void *, const struct inode *); - -typedef void (*btf_trace_nfs_access_exit)(void *, const struct inode *, unsigned int, unsigned int, int); - -typedef void (*btf_trace_nfs_lookup_enter)(void *, const struct inode *, const struct dentry *, unsigned int); - -typedef void (*btf_trace_nfs_lookup_exit)(void *, const struct inode *, const struct dentry *, unsigned int, int); - -typedef void (*btf_trace_nfs_lookup_revalidate_enter)(void *, const struct inode *, const struct dentry *, unsigned int); - -typedef void (*btf_trace_nfs_lookup_revalidate_exit)(void *, const struct inode *, const struct dentry *, unsigned int, int); - -typedef void (*btf_trace_nfs_atomic_open_enter)(void *, const struct inode *, const struct nfs_open_context *, unsigned int); - -typedef void (*btf_trace_nfs_atomic_open_exit)(void *, const struct inode *, const struct nfs_open_context *, unsigned int, int); - -typedef void (*btf_trace_nfs_create_enter)(void *, const struct inode *, const struct dentry *, unsigned int); - -typedef void (*btf_trace_nfs_create_exit)(void *, const struct inode *, const struct dentry *, unsigned int, int); - -typedef void (*btf_trace_nfs_mknod_enter)(void *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_mknod_exit)(void *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_mkdir_enter)(void *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_mkdir_exit)(void *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_rmdir_enter)(void *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_rmdir_exit)(void *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_remove_enter)(void *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_remove_exit)(void *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_unlink_enter)(void *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_unlink_exit)(void *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_symlink_enter)(void *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_symlink_exit)(void *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_link_enter)(void *, const struct inode *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_link_exit)(void *, const struct inode *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_rename_enter)(void *, const struct inode *, const struct dentry *, const struct inode *, const struct dentry *); - -typedef void (*btf_trace_nfs_rename_exit)(void *, const struct inode *, const struct dentry *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_sillyrename_rename)(void *, const struct inode *, const struct dentry *, const struct inode *, const struct dentry *, int); - -typedef void (*btf_trace_nfs_sillyrename_unlink)(void *, const struct nfs_unlinkdata *, int); - -typedef void (*btf_trace_nfs_initiate_read)(void *, const struct nfs_pgio_header *); - -typedef void (*btf_trace_nfs_readpage_done)(void *, const struct rpc_task *, const struct nfs_pgio_header *); - -typedef void (*btf_trace_nfs_readpage_short)(void *, const struct rpc_task *, const struct nfs_pgio_header *); - -typedef void (*btf_trace_nfs_pgio_error)(void *, const struct nfs_pgio_header *, int, loff_t); - -typedef void (*btf_trace_nfs_initiate_write)(void *, const struct nfs_pgio_header *); - -typedef void (*btf_trace_nfs_writeback_done)(void *, const struct rpc_task *, const struct nfs_pgio_header *); - -typedef void (*btf_trace_nfs_write_error)(void *, const struct nfs_page *, int); - -typedef void (*btf_trace_nfs_comp_error)(void *, const struct nfs_page *, int); - -typedef void (*btf_trace_nfs_commit_error)(void *, const struct nfs_page *, int); - -typedef void (*btf_trace_nfs_initiate_commit)(void *, const struct nfs_commit_data *); - -typedef void (*btf_trace_nfs_commit_done)(void *, const struct rpc_task *, const struct nfs_commit_data *); - -typedef void (*btf_trace_nfs_fh_to_dentry)(void *, const struct super_block *, const struct nfs_fh *, u64, int); - -typedef void (*btf_trace_nfs_xdr_status)(void *, const struct xdr_stream *, int); - -enum { - FILEID_HIGH_OFF = 0, - FILEID_LOW_OFF = 1, - FILE_I_TYPE_OFF = 2, - EMBED_FH_OFF = 3, -}; - -struct nfs2_fh { - char data[32]; -}; - -struct nfs3_fh { - short unsigned int size; - unsigned char data[64]; -}; - -struct nfs_mount_data { - int version; - int fd; - struct nfs2_fh old_root; - int flags; - int rsize; - int wsize; - int timeo; - int retrans; - int acregmin; - int acregmax; - int acdirmin; - int acdirmax; - struct sockaddr_in addr; - char hostname[256]; - int namlen; - unsigned int bsize; - struct nfs3_fh root; - int pseudoflavor; - char context[257]; -}; - -struct nfs_string { - unsigned int len; - const char *data; -}; - -struct nfs4_mount_data { - int version; - int flags; - int rsize; - int wsize; - int timeo; - int retrans; - int acregmin; - int acregmax; - int acdirmin; - int acdirmax; - struct nfs_string client_addr; - struct nfs_string mnt_path; - struct nfs_string hostname; - unsigned int host_addrlen; - struct sockaddr *host_addr; - int proto; - int auth_flavourlen; - int *auth_flavours; -}; - -enum nfs_param { - Opt_ac = 0, - Opt_acdirmax = 1, - Opt_acdirmin = 2, - Opt_acl___2 = 3, - Opt_acregmax = 4, - Opt_acregmin = 5, - Opt_actimeo = 6, - Opt_addr = 7, - Opt_bg = 8, - Opt_bsize = 9, - Opt_clientaddr = 10, - Opt_cto = 11, - Opt_fg = 12, - Opt_fscache = 13, - Opt_fscache_flag = 14, - Opt_hard = 15, - Opt_intr = 16, - Opt_local_lock = 17, - Opt_lock = 18, - Opt_lookupcache = 19, - Opt_migration = 20, - Opt_minorversion = 21, - Opt_mountaddr = 22, - Opt_mounthost = 23, - Opt_mountport = 24, - Opt_mountproto = 25, - Opt_mountvers = 26, - Opt_namelen = 27, - Opt_nconnect = 28, - Opt_port = 29, - Opt_posix = 30, - Opt_proto = 31, - Opt_rdirplus = 32, - Opt_rdma = 33, - Opt_resvport = 34, - Opt_retrans = 35, - Opt_retry = 36, - Opt_rsize = 37, - Opt_sec = 38, - Opt_sharecache = 39, - Opt_sloppy = 40, - Opt_soft = 41, - Opt_softerr = 42, - Opt_softreval = 43, - Opt_source = 44, - Opt_tcp = 45, - Opt_timeo = 46, - Opt_udp = 47, - Opt_v = 48, - Opt_vers = 49, - Opt_wsize = 50, -}; - -enum { - Opt_local_lock_all = 0, - Opt_local_lock_flock = 1, - Opt_local_lock_none = 2, - Opt_local_lock_posix = 3, -}; - -enum { - Opt_lookupcache_all = 0, - Opt_lookupcache_none = 1, - Opt_lookupcache_positive = 2, -}; - -enum { - Opt_vers_2 = 0, - Opt_vers_3 = 1, - Opt_vers_4 = 2, - Opt_vers_4_0 = 3, - Opt_vers_4_1 = 4, - Opt_vers_4_2 = 5, -}; - -enum { - Opt_xprt_rdma = 0, - Opt_xprt_rdma6 = 1, - Opt_xprt_tcp = 2, - Opt_xprt_tcp6 = 3, - Opt_xprt_udp = 4, - Opt_xprt_udp6 = 5, - nr__Opt_xprt = 6, -}; - -enum { - Opt_sec_krb5 = 0, - Opt_sec_krb5i = 1, - Opt_sec_krb5p = 2, - Opt_sec_lkey = 3, - Opt_sec_lkeyi = 4, - Opt_sec_lkeyp = 5, - Opt_sec_none = 6, - Opt_sec_spkm = 7, - Opt_sec_spkmi = 8, - Opt_sec_spkmp = 9, - Opt_sec_sys = 10, - nr__Opt_sec = 11, -}; - -struct compat_nfs_string { - compat_uint_t len; - compat_uptr_t data; -}; - -struct compat_nfs4_mount_data_v1 { - compat_int_t version; - compat_int_t flags; - compat_int_t rsize; - compat_int_t wsize; - compat_int_t timeo; - compat_int_t retrans; - compat_int_t acregmin; - compat_int_t acregmax; - compat_int_t acdirmin; - compat_int_t acdirmax; - struct compat_nfs_string client_addr; - struct compat_nfs_string mnt_path; - struct compat_nfs_string hostname; - compat_uint_t host_addrlen; - compat_uptr_t host_addr; - compat_int_t proto; - compat_int_t auth_flavourlen; - compat_uptr_t auth_flavours; -}; - -struct nfs_fscache_inode_auxdata { - s64 mtime_sec; - s64 mtime_nsec; - s64 ctime_sec; - s64 ctime_nsec; - u64 change_attr; -}; - -struct nfs_server_key { - struct { - uint16_t nfsversion; - uint32_t minorversion; - uint16_t family; - __be16 port; - } hdr; - union { - struct in_addr ipv4_addr; - struct in6_addr ipv6_addr; - }; -}; - -struct nfs2_fsstat { - __u32 tsize; - __u32 bsize; - __u32 blocks; - __u32 bfree; - __u32 bavail; -}; - -struct nfs_sattrargs { - struct nfs_fh *fh; - struct iattr *sattr; -}; - -struct nfs_diropargs { - struct nfs_fh *fh; - const char *name; - unsigned int len; -}; - -struct nfs_createargs { - struct nfs_fh *fh; - const char *name; - unsigned int len; - struct iattr *sattr; -}; - -struct nfs_linkargs { - struct nfs_fh *fromfh; - struct nfs_fh *tofh; - const char *toname; - unsigned int tolen; -}; - -struct nfs_symlinkargs { - struct nfs_fh *fromfh; - const char *fromname; - unsigned int fromlen; - struct page **pages; - unsigned int pathlen; - struct iattr *sattr; -}; - -struct nfs_readdirargs { - struct nfs_fh *fh; - __u32 cookie; - unsigned int count; - struct page **pages; -}; - -struct nfs_diropok { - struct nfs_fh *fh; - struct nfs_fattr *fattr; -}; - -struct nfs_readlinkargs { - struct nfs_fh *fh; - unsigned int pgbase; - unsigned int pglen; - struct page **pages; -}; - -struct nfs_createdata { - struct nfs_createargs arg; - struct nfs_diropok res; - struct nfs_fh fhandle; - struct nfs_fattr fattr; -}; - -enum nfs_ftype { - NFNON = 0, - NFREG = 1, - NFDIR = 2, - NFBLK = 3, - NFCHR = 4, - NFLNK = 5, - NFSOCK = 6, - NFBAD = 7, - NFFIFO = 8, -}; - -enum nfs2_ftype { - NF2NON = 0, - NF2REG = 1, - NF2DIR = 2, - NF2BLK = 3, - NF2CHR = 4, - NF2LNK = 5, - NF2SOCK = 6, - NF2BAD = 7, - NF2FIFO = 8, -}; - -enum nfs3_createmode { - NFS3_CREATE_UNCHECKED = 0, - NFS3_CREATE_GUARDED = 1, - NFS3_CREATE_EXCLUSIVE = 2, -}; - -enum nfs3_ftype { - NF3NON = 0, - NF3REG = 1, - NF3DIR = 2, - NF3BLK = 3, - NF3CHR = 4, - NF3LNK = 5, - NF3SOCK = 6, - NF3FIFO = 7, - NF3BAD = 8, -}; - -struct nfs3_sattrargs { - struct nfs_fh *fh; - struct iattr *sattr; - unsigned int guard; - struct timespec64 guardtime; -}; - -struct nfs3_diropargs { - struct nfs_fh *fh; - const char *name; - unsigned int len; -}; - -struct nfs3_accessargs { - struct nfs_fh *fh; - __u32 access; -}; - -struct nfs3_createargs { - struct nfs_fh *fh; - const char *name; - unsigned int len; - struct iattr *sattr; - enum nfs3_createmode createmode; - __be32 verifier[2]; -}; - -struct nfs3_mkdirargs { - struct nfs_fh *fh; - const char *name; - unsigned int len; - struct iattr *sattr; -}; - -struct nfs3_symlinkargs { - struct nfs_fh *fromfh; - const char *fromname; - unsigned int fromlen; - struct page **pages; - unsigned int pathlen; - struct iattr *sattr; -}; - -struct nfs3_mknodargs { - struct nfs_fh *fh; - const char *name; - unsigned int len; - enum nfs3_ftype type; - struct iattr *sattr; - dev_t rdev; -}; - -struct nfs3_linkargs { - struct nfs_fh *fromfh; - struct nfs_fh *tofh; - const char *toname; - unsigned int tolen; -}; - -struct nfs3_readdirargs { - struct nfs_fh *fh; - __u64 cookie; - __be32 verf[2]; - bool plus; - unsigned int count; - struct page **pages; -}; - -struct nfs3_diropres { - struct nfs_fattr *dir_attr; - struct nfs_fh *fh; - struct nfs_fattr *fattr; -}; - -struct nfs3_accessres { - struct nfs_fattr *fattr; - __u32 access; -}; - -struct nfs3_readlinkargs { - struct nfs_fh *fh; - unsigned int pgbase; - unsigned int pglen; - struct page **pages; -}; - -struct nfs3_linkres { - struct nfs_fattr *dir_attr; - struct nfs_fattr *fattr; -}; - -struct nfs3_readdirres { - struct nfs_fattr *dir_attr; - __be32 *verf; - bool plus; -}; - -struct nfs3_createdata { - struct rpc_message msg; - union { - struct nfs3_createargs create; - struct nfs3_mkdirargs mkdir; - struct nfs3_symlinkargs symlink; - struct nfs3_mknodargs mknod; - } arg; - struct nfs3_diropres res; - struct nfs_fh fh; - struct nfs_fattr fattr; - struct nfs_fattr dir_attr; -}; - -struct nfs3_getaclargs { - struct nfs_fh *fh; - int mask; - struct page **pages; -}; - -struct nfs3_setaclargs { - struct inode *inode; - int mask; - struct posix_acl *acl_access; - struct posix_acl *acl_default; - size_t len; - unsigned int npages; - struct page **pages; -}; - -struct nfs3_getaclres { - struct nfs_fattr *fattr; - int mask; - unsigned int acl_access_count; - unsigned int acl_default_count; - struct posix_acl *acl_access; - struct posix_acl *acl_default; -}; - -enum nfsstat4 { - NFS4_OK = 0, - NFS4ERR_PERM = 1, - NFS4ERR_NOENT = 2, - NFS4ERR_IO = 5, - NFS4ERR_NXIO = 6, - NFS4ERR_ACCESS = 13, - NFS4ERR_EXIST = 17, - NFS4ERR_XDEV = 18, - NFS4ERR_NOTDIR = 20, - NFS4ERR_ISDIR = 21, - NFS4ERR_INVAL = 22, - NFS4ERR_FBIG = 27, - NFS4ERR_NOSPC = 28, - NFS4ERR_ROFS = 30, - NFS4ERR_MLINK = 31, - NFS4ERR_NAMETOOLONG = 63, - NFS4ERR_NOTEMPTY = 66, - NFS4ERR_DQUOT = 69, - NFS4ERR_STALE = 70, - NFS4ERR_BADHANDLE = 10001, - NFS4ERR_BAD_COOKIE = 10003, - NFS4ERR_NOTSUPP = 10004, - NFS4ERR_TOOSMALL = 10005, - NFS4ERR_SERVERFAULT = 10006, - NFS4ERR_BADTYPE = 10007, - NFS4ERR_DELAY = 10008, - NFS4ERR_SAME = 10009, - NFS4ERR_DENIED = 10010, - NFS4ERR_EXPIRED = 10011, - NFS4ERR_LOCKED = 10012, - NFS4ERR_GRACE = 10013, - NFS4ERR_FHEXPIRED = 10014, - NFS4ERR_SHARE_DENIED = 10015, - NFS4ERR_WRONGSEC = 10016, - NFS4ERR_CLID_INUSE = 10017, - NFS4ERR_RESOURCE = 10018, - NFS4ERR_MOVED = 10019, - NFS4ERR_NOFILEHANDLE = 10020, - NFS4ERR_MINOR_VERS_MISMATCH = 10021, - NFS4ERR_STALE_CLIENTID = 10022, - NFS4ERR_STALE_STATEID = 10023, - NFS4ERR_OLD_STATEID = 10024, - NFS4ERR_BAD_STATEID = 10025, - NFS4ERR_BAD_SEQID = 10026, - NFS4ERR_NOT_SAME = 10027, - NFS4ERR_LOCK_RANGE = 10028, - NFS4ERR_SYMLINK = 10029, - NFS4ERR_RESTOREFH = 10030, - NFS4ERR_LEASE_MOVED = 10031, - NFS4ERR_ATTRNOTSUPP = 10032, - NFS4ERR_NO_GRACE = 10033, - NFS4ERR_RECLAIM_BAD = 10034, - NFS4ERR_RECLAIM_CONFLICT = 10035, - NFS4ERR_BADXDR = 10036, - NFS4ERR_LOCKS_HELD = 10037, - NFS4ERR_OPENMODE = 10038, - NFS4ERR_BADOWNER = 10039, - NFS4ERR_BADCHAR = 10040, - NFS4ERR_BADNAME = 10041, - NFS4ERR_BAD_RANGE = 10042, - NFS4ERR_LOCK_NOTSUPP = 10043, - NFS4ERR_OP_ILLEGAL = 10044, - NFS4ERR_DEADLOCK = 10045, - NFS4ERR_FILE_OPEN = 10046, - NFS4ERR_ADMIN_REVOKED = 10047, - NFS4ERR_CB_PATH_DOWN = 10048, - NFS4ERR_BADIOMODE = 10049, - NFS4ERR_BADLAYOUT = 10050, - NFS4ERR_BAD_SESSION_DIGEST = 10051, - NFS4ERR_BADSESSION = 10052, - NFS4ERR_BADSLOT = 10053, - NFS4ERR_COMPLETE_ALREADY = 10054, - NFS4ERR_CONN_NOT_BOUND_TO_SESSION = 10055, - NFS4ERR_DELEG_ALREADY_WANTED = 10056, - NFS4ERR_BACK_CHAN_BUSY = 10057, - NFS4ERR_LAYOUTTRYLATER = 10058, - NFS4ERR_LAYOUTUNAVAILABLE = 10059, - NFS4ERR_NOMATCHING_LAYOUT = 10060, - NFS4ERR_RECALLCONFLICT = 10061, - NFS4ERR_UNKNOWN_LAYOUTTYPE = 10062, - NFS4ERR_SEQ_MISORDERED = 10063, - NFS4ERR_SEQUENCE_POS = 10064, - NFS4ERR_REQ_TOO_BIG = 10065, - NFS4ERR_REP_TOO_BIG = 10066, - NFS4ERR_REP_TOO_BIG_TO_CACHE = 10067, - NFS4ERR_RETRY_UNCACHED_REP = 10068, - NFS4ERR_UNSAFE_COMPOUND = 10069, - NFS4ERR_TOO_MANY_OPS = 10070, - NFS4ERR_OP_NOT_IN_SESSION = 10071, - NFS4ERR_HASH_ALG_UNSUPP = 10072, - NFS4ERR_CLIENTID_BUSY = 10074, - NFS4ERR_PNFS_IO_HOLE = 10075, - NFS4ERR_SEQ_FALSE_RETRY = 10076, - NFS4ERR_BAD_HIGH_SLOT = 10077, - NFS4ERR_DEADSESSION = 10078, - NFS4ERR_ENCR_ALG_UNSUPP = 10079, - NFS4ERR_PNFS_NO_LAYOUT = 10080, - NFS4ERR_NOT_ONLY_OP = 10081, - NFS4ERR_WRONG_CRED = 10082, - NFS4ERR_WRONG_TYPE = 10083, - NFS4ERR_DIRDELEG_UNAVAIL = 10084, - NFS4ERR_REJECT_DELEG = 10085, - NFS4ERR_RETURNCONFLICT = 10086, - NFS4ERR_DELEG_REVOKED = 10087, - NFS4ERR_PARTNER_NOTSUPP = 10088, - NFS4ERR_PARTNER_NO_AUTH = 10089, - NFS4ERR_UNION_NOTSUPP = 10090, - NFS4ERR_OFFLOAD_DENIED = 10091, - NFS4ERR_WRONG_LFS = 10092, - NFS4ERR_BADLABEL = 10093, - NFS4ERR_OFFLOAD_NO_REQS = 10094, - NFS4ERR_NOXATTR = 10095, - NFS4ERR_XATTR2BIG = 10096, -}; - -enum nfs_ftype4 { - NF4BAD = 0, - NF4REG = 1, - NF4DIR = 2, - NF4BLK = 3, - NF4CHR = 4, - NF4LNK = 5, - NF4SOCK = 6, - NF4FIFO = 7, - NF4ATTRDIR = 8, - NF4NAMEDATTR = 9, -}; - -enum open_claim_type4 { - NFS4_OPEN_CLAIM_NULL = 0, - NFS4_OPEN_CLAIM_PREVIOUS = 1, - NFS4_OPEN_CLAIM_DELEGATE_CUR = 2, - NFS4_OPEN_CLAIM_DELEGATE_PREV = 3, - NFS4_OPEN_CLAIM_FH = 4, - NFS4_OPEN_CLAIM_DELEG_CUR_FH = 5, - NFS4_OPEN_CLAIM_DELEG_PREV_FH = 6, -}; - -enum createmode4 { - NFS4_CREATE_UNCHECKED = 0, - NFS4_CREATE_GUARDED = 1, - NFS4_CREATE_EXCLUSIVE = 2, - NFS4_CREATE_EXCLUSIVE4_1 = 3, -}; - -enum { - NFSPROC4_CLNT_NULL = 0, - NFSPROC4_CLNT_READ = 1, - NFSPROC4_CLNT_WRITE = 2, - NFSPROC4_CLNT_COMMIT = 3, - NFSPROC4_CLNT_OPEN = 4, - NFSPROC4_CLNT_OPEN_CONFIRM = 5, - NFSPROC4_CLNT_OPEN_NOATTR = 6, - NFSPROC4_CLNT_OPEN_DOWNGRADE = 7, - NFSPROC4_CLNT_CLOSE = 8, - NFSPROC4_CLNT_SETATTR = 9, - NFSPROC4_CLNT_FSINFO = 10, - NFSPROC4_CLNT_RENEW = 11, - NFSPROC4_CLNT_SETCLIENTID = 12, - NFSPROC4_CLNT_SETCLIENTID_CONFIRM = 13, - NFSPROC4_CLNT_LOCK = 14, - NFSPROC4_CLNT_LOCKT = 15, - NFSPROC4_CLNT_LOCKU = 16, - NFSPROC4_CLNT_ACCESS = 17, - NFSPROC4_CLNT_GETATTR = 18, - NFSPROC4_CLNT_LOOKUP = 19, - NFSPROC4_CLNT_LOOKUP_ROOT = 20, - NFSPROC4_CLNT_REMOVE = 21, - NFSPROC4_CLNT_RENAME = 22, - NFSPROC4_CLNT_LINK = 23, - NFSPROC4_CLNT_SYMLINK = 24, - NFSPROC4_CLNT_CREATE = 25, - NFSPROC4_CLNT_PATHCONF = 26, - NFSPROC4_CLNT_STATFS = 27, - NFSPROC4_CLNT_READLINK = 28, - NFSPROC4_CLNT_READDIR = 29, - NFSPROC4_CLNT_SERVER_CAPS = 30, - NFSPROC4_CLNT_DELEGRETURN = 31, - NFSPROC4_CLNT_GETACL = 32, - NFSPROC4_CLNT_SETACL = 33, - NFSPROC4_CLNT_FS_LOCATIONS = 34, - NFSPROC4_CLNT_RELEASE_LOCKOWNER = 35, - NFSPROC4_CLNT_SECINFO = 36, - NFSPROC4_CLNT_FSID_PRESENT = 37, - NFSPROC4_CLNT_EXCHANGE_ID = 38, - NFSPROC4_CLNT_CREATE_SESSION = 39, - NFSPROC4_CLNT_DESTROY_SESSION = 40, - NFSPROC4_CLNT_SEQUENCE = 41, - NFSPROC4_CLNT_GET_LEASE_TIME = 42, - NFSPROC4_CLNT_RECLAIM_COMPLETE = 43, - NFSPROC4_CLNT_LAYOUTGET = 44, - NFSPROC4_CLNT_GETDEVICEINFO = 45, - NFSPROC4_CLNT_LAYOUTCOMMIT = 46, - NFSPROC4_CLNT_LAYOUTRETURN = 47, - NFSPROC4_CLNT_SECINFO_NO_NAME = 48, - NFSPROC4_CLNT_TEST_STATEID = 49, - NFSPROC4_CLNT_FREE_STATEID = 50, - NFSPROC4_CLNT_GETDEVICELIST = 51, - NFSPROC4_CLNT_BIND_CONN_TO_SESSION = 52, - NFSPROC4_CLNT_DESTROY_CLIENTID = 53, - NFSPROC4_CLNT_SEEK = 54, - NFSPROC4_CLNT_ALLOCATE = 55, - NFSPROC4_CLNT_DEALLOCATE = 56, - NFSPROC4_CLNT_LAYOUTSTATS = 57, - NFSPROC4_CLNT_CLONE = 58, - NFSPROC4_CLNT_COPY = 59, - NFSPROC4_CLNT_OFFLOAD_CANCEL = 60, - NFSPROC4_CLNT_LOOKUPP = 61, - NFSPROC4_CLNT_LAYOUTERROR = 62, - NFSPROC4_CLNT_COPY_NOTIFY = 63, - NFSPROC4_CLNT_GETXATTR = 64, - NFSPROC4_CLNT_SETXATTR = 65, - NFSPROC4_CLNT_LISTXATTRS = 66, - NFSPROC4_CLNT_REMOVEXATTR = 67, - NFSPROC4_CLNT_READ_PLUS = 68, -}; - -enum state_protect_how4 { - SP4_NONE = 0, - SP4_MACH_CRED = 1, - SP4_SSV = 2, -}; - -enum pnfs_notify_deviceid_type4 { - NOTIFY_DEVICEID4_CHANGE = 2, - NOTIFY_DEVICEID4_DELETE = 4, -}; - -struct nfs4_op_map { - union { - long unsigned int longs[2]; - u32 words[4]; - } u; -}; - -struct nfs4_get_lease_time_args { - struct nfs4_sequence_args la_seq_args; -}; - -struct nfs4_get_lease_time_res { - struct nfs4_sequence_res lr_seq_res; - struct nfs_fsinfo *lr_fsinfo; -}; - -struct nfs4_layoutget_args { - struct nfs4_sequence_args seq_args; - __u32 type; - struct pnfs_layout_range range; - __u64 minlength; - __u32 maxcount; - struct inode *inode; - struct nfs_open_context *ctx; - nfs4_stateid stateid; - struct nfs4_layoutdriver_data layout; -}; - -struct nfs4_layoutget { - struct nfs4_layoutget_args args; - struct nfs4_layoutget_res res; - const struct cred *cred; - gfp_t gfp_flags; -}; - -struct nfs4_getdeviceinfo_args { - struct nfs4_sequence_args seq_args; - struct pnfs_device *pdev; - __u32 notify_types; -}; - -struct nfs4_getdeviceinfo_res { - struct nfs4_sequence_res seq_res; - struct pnfs_device *pdev; - __u32 notification; -}; - -struct nfs4_layoutreturn_res { - struct nfs4_sequence_res seq_res; - u32 lrs_present; - nfs4_stateid stateid; -}; - -struct nfs4_layoutreturn { - struct nfs4_layoutreturn_args args; - struct nfs4_layoutreturn_res res; - const struct cred *cred; - struct nfs_client *clp; - struct inode *inode; - int rpc_status; - struct nfs4_xdr_opaque_data ld_private; -}; - -struct stateowner_id { - __u64 create_time; - __u32 uniquifier; -}; - -struct nfs_openargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - struct nfs_seqid *seqid; - int open_flags; - fmode_t fmode; - u32 share_access; - u32 access; - __u64 clientid; - struct stateowner_id id; - union { - struct { - struct iattr *attrs; - nfs4_verifier verifier; - }; - nfs4_stateid delegation; - fmode_t delegation_type; - } u; - const struct qstr *name; - const struct nfs_server *server; - const u32 *bitmask; - const u32 *open_bitmap; - enum open_claim_type4 claim; - enum createmode4 createmode; - const struct nfs4_label *label; - umode_t umask; - struct nfs4_layoutget_args *lg_args; -}; - -struct nfs_openres { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_fh fh; - struct nfs4_change_info cinfo; - __u32 rflags; - struct nfs_fattr *f_attr; - struct nfs4_label *f_label; - struct nfs_seqid *seqid; - const struct nfs_server *server; - fmode_t delegation_type; - nfs4_stateid delegation; - long unsigned int pagemod_limit; - __u32 do_recall; - __u32 attrset[3]; - struct nfs4_string *owner; - struct nfs4_string *group_owner; - __u32 access_request; - __u32 access_supported; - __u32 access_result; - struct nfs4_layoutget_res *lg_res; -}; - -struct nfs_open_confirmargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - nfs4_stateid *stateid; - struct nfs_seqid *seqid; -}; - -struct nfs_open_confirmres { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_seqid *seqid; -}; - -struct nfs_closeargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - nfs4_stateid stateid; - struct nfs_seqid *seqid; - fmode_t fmode; - u32 share_access; - const u32 *bitmask; - u32 bitmask_store[3]; - struct nfs4_layoutreturn_args *lr_args; -}; - -struct nfs_closeres { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_fattr *fattr; - struct nfs_seqid *seqid; - const struct nfs_server *server; - struct nfs4_layoutreturn_res *lr_res; - int lr_ret; -}; - -struct nfs_lowner { - __u64 clientid; - __u64 id; - dev_t s_dev; -}; - -struct nfs_lock_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - struct file_lock *fl; - struct nfs_seqid *lock_seqid; - nfs4_stateid lock_stateid; - struct nfs_seqid *open_seqid; - nfs4_stateid open_stateid; - struct nfs_lowner lock_owner; - unsigned char block: 1; - unsigned char reclaim: 1; - unsigned char new_lock: 1; - unsigned char new_lock_owner: 1; -}; - -struct nfs_lock_res { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_seqid *lock_seqid; - struct nfs_seqid *open_seqid; -}; - -struct nfs_locku_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - struct file_lock *fl; - struct nfs_seqid *seqid; - nfs4_stateid stateid; -}; - -struct nfs_locku_res { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_seqid *seqid; -}; - -struct nfs_lockt_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - struct file_lock *fl; - struct nfs_lowner lock_owner; -}; - -struct nfs_lockt_res { - struct nfs4_sequence_res seq_res; - struct file_lock *denied; -}; - -struct nfs_release_lockowner_args { - struct nfs4_sequence_args seq_args; - struct nfs_lowner lock_owner; -}; - -struct nfs_release_lockowner_res { - struct nfs4_sequence_res seq_res; -}; - -struct nfs4_delegreturnargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fhandle; - const nfs4_stateid *stateid; - const u32 *bitmask; - u32 bitmask_store[3]; - struct nfs4_layoutreturn_args *lr_args; -}; - -struct nfs4_delegreturnres { - struct nfs4_sequence_res seq_res; - struct nfs_fattr *fattr; - struct nfs_server *server; - struct nfs4_layoutreturn_res *lr_res; - int lr_ret; -}; - -struct nfs_setattrargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - nfs4_stateid stateid; - struct iattr *iap; - const struct nfs_server *server; - const u32 *bitmask; - const struct nfs4_label *label; -}; - -struct nfs_setaclargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - size_t acl_len; - struct page **acl_pages; -}; - -struct nfs_setaclres { - struct nfs4_sequence_res seq_res; -}; - -struct nfs_getaclargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - size_t acl_len; - struct page **acl_pages; -}; - -struct nfs_getaclres { - struct nfs4_sequence_res seq_res; - size_t acl_len; - size_t acl_data_offset; - int acl_flags; - struct page *acl_scratch; -}; - -struct nfs_setattrres { - struct nfs4_sequence_res seq_res; - struct nfs_fattr *fattr; - struct nfs4_label *label; - const struct nfs_server *server; -}; - -typedef u64 clientid4; - -struct nfs4_accessargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - const u32 *bitmask; - u32 access; -}; - -struct nfs4_accessres { - struct nfs4_sequence_res seq_res; - const struct nfs_server *server; - struct nfs_fattr *fattr; - u32 supported; - u32 access; -}; - -struct nfs4_create_arg { - struct nfs4_sequence_args seq_args; - u32 ftype; - union { - struct { - struct page **pages; - unsigned int len; - } symlink; - struct { - u32 specdata1; - u32 specdata2; - } device; - } u; - const struct qstr *name; - const struct nfs_server *server; - const struct iattr *attrs; - const struct nfs_fh *dir_fh; - const u32 *bitmask; - const struct nfs4_label *label; - umode_t umask; -}; - -struct nfs4_create_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server *server; - struct nfs_fh *fh; - struct nfs_fattr *fattr; - struct nfs4_label *label; - struct nfs4_change_info dir_cinfo; -}; - -struct nfs4_fsinfo_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - const u32 *bitmask; -}; - -struct nfs4_fsinfo_res { - struct nfs4_sequence_res seq_res; - struct nfs_fsinfo *fsinfo; -}; - -struct nfs4_getattr_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - const u32 *bitmask; -}; - -struct nfs4_getattr_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server *server; - struct nfs_fattr *fattr; - struct nfs4_label *label; -}; - -struct nfs4_link_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - const struct nfs_fh *dir_fh; - const struct qstr *name; - const u32 *bitmask; -}; - -struct nfs4_link_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server *server; - struct nfs_fattr *fattr; - struct nfs4_label *label; - struct nfs4_change_info cinfo; - struct nfs_fattr *dir_attr; -}; - -struct nfs4_lookup_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *dir_fh; - const struct qstr *name; - const u32 *bitmask; -}; - -struct nfs4_lookup_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server *server; - struct nfs_fattr *fattr; - struct nfs_fh *fh; - struct nfs4_label *label; -}; - -struct nfs4_lookupp_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - const u32 *bitmask; -}; - -struct nfs4_lookupp_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server *server; - struct nfs_fattr *fattr; - struct nfs_fh *fh; - struct nfs4_label *label; -}; - -struct nfs4_lookup_root_arg { - struct nfs4_sequence_args seq_args; - const u32 *bitmask; -}; - -struct nfs4_pathconf_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - const u32 *bitmask; -}; - -struct nfs4_pathconf_res { - struct nfs4_sequence_res seq_res; - struct nfs_pathconf *pathconf; -}; - -struct nfs4_readdir_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - u64 cookie; - nfs4_verifier verifier; - u32 count; - struct page **pages; - unsigned int pgbase; - const u32 *bitmask; - bool plus; -}; - -struct nfs4_readdir_res { - struct nfs4_sequence_res seq_res; - nfs4_verifier verifier; - unsigned int pgbase; -}; - -struct nfs4_readlink { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - unsigned int pgbase; - unsigned int pglen; - struct page **pages; -}; - -struct nfs4_readlink_res { - struct nfs4_sequence_res seq_res; -}; - -struct nfs4_setclientid { - const nfs4_verifier *sc_verifier; - u32 sc_prog; - unsigned int sc_netid_len; - char sc_netid[6]; - unsigned int sc_uaddr_len; - char sc_uaddr[58]; - struct nfs_client *sc_clnt; - struct rpc_cred *sc_cred; -}; - -struct nfs4_setclientid_res { - u64 clientid; - nfs4_verifier confirm; -}; - -struct nfs4_statfs_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - const u32 *bitmask; -}; - -struct nfs4_statfs_res { - struct nfs4_sequence_res seq_res; - struct nfs_fsstat *fsstat; -}; - -struct nfs4_server_caps_arg { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fhandle; - const u32 *bitmask; -}; - -struct nfs4_server_caps_res { - struct nfs4_sequence_res seq_res; - u32 attr_bitmask[3]; - u32 exclcreat_bitmask[3]; - u32 acl_bitmask; - u32 has_links; - u32 has_symlinks; - u32 fh_expire_type; -}; - -struct nfs4_fs_locations_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *dir_fh; - const struct nfs_fh *fh; - const struct qstr *name; - struct page *page; - const u32 *bitmask; - clientid4 clientid; - unsigned char migration: 1; - unsigned char renew: 1; -}; - -struct nfs4_fs_locations_res { - struct nfs4_sequence_res seq_res; - struct nfs4_fs_locations *fs_locations; - unsigned char migration: 1; - unsigned char renew: 1; -}; - -struct nfs4_secinfo4 { - u32 flavor; - struct rpcsec_gss_info flavor_info; -}; - -struct nfs4_secinfo_flavors { - unsigned int num_flavors; - struct nfs4_secinfo4 flavors[0]; -}; - -struct nfs4_secinfo_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *dir_fh; - const struct qstr *name; -}; - -struct nfs4_secinfo_res { - struct nfs4_sequence_res seq_res; - struct nfs4_secinfo_flavors *flavors; -}; - -struct nfs4_fsid_present_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - clientid4 clientid; - unsigned char renew: 1; -}; - -struct nfs4_fsid_present_res { - struct nfs4_sequence_res seq_res; - struct nfs_fh *fh; - unsigned char renew: 1; -}; - -struct nfs41_state_protection { - u32 how; - struct nfs4_op_map enforce; - struct nfs4_op_map allow; -}; - -struct nfs41_exchange_id_args { - struct nfs_client *client; - nfs4_verifier verifier; - u32 flags; - struct nfs41_state_protection state_protect; -}; - -struct nfs41_bind_conn_to_session_args { - struct nfs_client *client; - struct nfs4_sessionid sessionid; - u32 dir; - bool use_conn_in_rdma_mode; - int retries; -}; - -struct nfs41_bind_conn_to_session_res { - struct nfs4_sessionid sessionid; - u32 dir; - bool use_conn_in_rdma_mode; -}; - -struct nfs41_exchange_id_res { - u64 clientid; - u32 seqid; - u32 flags; - struct nfs41_server_owner *server_owner; - struct nfs41_server_scope *server_scope; - struct nfs41_impl_id *impl_id; - struct nfs41_state_protection state_protect; -}; - -struct nfs41_create_session_args { - struct nfs_client *client; - u64 clientid; - uint32_t seqid; - uint32_t flags; - uint32_t cb_program; - struct nfs4_channel_attrs fc_attrs; - struct nfs4_channel_attrs bc_attrs; -}; - -struct nfs41_create_session_res { - struct nfs4_sessionid sessionid; - uint32_t seqid; - uint32_t flags; - struct nfs4_channel_attrs fc_attrs; - struct nfs4_channel_attrs bc_attrs; -}; - -struct nfs41_reclaim_complete_args { - struct nfs4_sequence_args seq_args; - unsigned char one_fs: 1; -}; - -struct nfs41_reclaim_complete_res { - struct nfs4_sequence_res seq_res; -}; - -struct nfs41_secinfo_no_name_args { - struct nfs4_sequence_args seq_args; - int style; -}; - -struct nfs41_test_stateid_args { - struct nfs4_sequence_args seq_args; - nfs4_stateid *stateid; -}; - -struct nfs41_test_stateid_res { - struct nfs4_sequence_res seq_res; - unsigned int status; -}; - -struct nfs41_free_stateid_args { - struct nfs4_sequence_args seq_args; - nfs4_stateid stateid; -}; - -struct nfs41_free_stateid_res { - struct nfs4_sequence_res seq_res; - unsigned int status; -}; - -struct nfs4_cached_acl { - int cached; - size_t len; - char data[0]; -}; - -enum nfs4_client_state { - NFS4CLNT_MANAGER_RUNNING = 0, - NFS4CLNT_CHECK_LEASE = 1, - NFS4CLNT_LEASE_EXPIRED = 2, - NFS4CLNT_RECLAIM_REBOOT = 3, - NFS4CLNT_RECLAIM_NOGRACE = 4, - NFS4CLNT_DELEGRETURN = 5, - NFS4CLNT_SESSION_RESET = 6, - NFS4CLNT_LEASE_CONFIRM = 7, - NFS4CLNT_SERVER_SCOPE_MISMATCH = 8, - NFS4CLNT_PURGE_STATE = 9, - NFS4CLNT_BIND_CONN_TO_SESSION = 10, - NFS4CLNT_MOVED = 11, - NFS4CLNT_LEASE_MOVED = 12, - NFS4CLNT_DELEGATION_EXPIRED = 13, - NFS4CLNT_RUN_MANAGER = 14, - NFS4CLNT_RECALL_RUNNING = 15, - NFS4CLNT_RECALL_ANY_LAYOUT_READ = 16, - NFS4CLNT_RECALL_ANY_LAYOUT_RW = 17, - NFS4CLNT_DELEGRETURN_DELAYED = 18, -}; - -enum { - NFS_OWNER_RECLAIM_REBOOT = 0, - NFS_OWNER_RECLAIM_NOGRACE = 1, -}; - -enum { - LK_STATE_IN_USE = 0, - NFS_DELEGATED_STATE = 1, - NFS_OPEN_STATE = 2, - NFS_O_RDONLY_STATE = 3, - NFS_O_WRONLY_STATE = 4, - NFS_O_RDWR_STATE = 5, - NFS_STATE_RECLAIM_REBOOT = 6, - NFS_STATE_RECLAIM_NOGRACE = 7, - NFS_STATE_POSIX_LOCKS = 8, - NFS_STATE_RECOVERY_FAILED = 9, - NFS_STATE_MAY_NOTIFY_LOCK = 10, - NFS_STATE_CHANGE_WAIT = 11, - NFS_CLNT_DST_SSC_COPY_STATE = 12, - NFS_CLNT_SRC_SSC_COPY_STATE = 13, - NFS_SRV_SSC_COPY_STATE = 14, -}; - -struct nfs4_exception { - struct nfs4_state *state; - struct inode *inode; - nfs4_stateid *stateid; - long int timeout; - unsigned char task_is_privileged: 1; - unsigned char delay: 1; - unsigned char recovering: 1; - unsigned char retry: 1; - bool interruptible; -}; - -struct nfs4_opendata { - struct kref kref; - struct nfs_openargs o_arg; - struct nfs_openres o_res; - struct nfs_open_confirmargs c_arg; - struct nfs_open_confirmres c_res; - struct nfs4_string owner_name; - struct nfs4_string group_name; - struct nfs4_label *a_label; - struct nfs_fattr f_attr; - struct nfs4_label *f_label; - struct dentry *dir; - struct dentry *dentry; - struct nfs4_state_owner *owner; - struct nfs4_state *state; - struct iattr attrs; - struct nfs4_layoutget *lgp; - long unsigned int timestamp; - bool rpc_done; - bool file_created; - bool is_recover; - bool cancelled; - int rpc_status; -}; - -struct nfs4_add_xprt_data { - struct nfs_client *clp; - const struct cred *cred; -}; - -enum { - NFS_DELEGATION_NEED_RECLAIM = 0, - NFS_DELEGATION_RETURN = 1, - NFS_DELEGATION_RETURN_IF_CLOSED = 2, - NFS_DELEGATION_REFERENCED = 3, - NFS_DELEGATION_RETURNING = 4, - NFS_DELEGATION_REVOKED = 5, - NFS_DELEGATION_TEST_EXPIRED = 6, - NFS_DELEGATION_INODE_FREEING = 7, - NFS_DELEGATION_RETURN_DELAYED = 8, -}; - -struct cb_notify_lock_args { - struct nfs_fh cbnl_fh; - struct nfs_lowner cbnl_owner; - bool cbnl_valid; -}; - -enum { - NFS_LAYOUT_RO_FAILED = 0, - NFS_LAYOUT_RW_FAILED = 1, - NFS_LAYOUT_BULK_RECALL = 2, - NFS_LAYOUT_RETURN = 3, - NFS_LAYOUT_RETURN_LOCK = 4, - NFS_LAYOUT_RETURN_REQUESTED = 5, - NFS_LAYOUT_INVALID_STID = 6, - NFS_LAYOUT_FIRST_LAYOUTGET = 7, - NFS_LAYOUT_INODE_FREEING = 8, - NFS_LAYOUT_HASHED = 9, -}; - -enum nfs4_slot_tbl_state { - NFS4_SLOT_TBL_DRAINING = 0, -}; - -enum nfs4_session_state { - NFS4_SESSION_INITING = 0, - NFS4_SESSION_ESTABLISHED = 1, -}; - -struct nfs4_call_sync_data { - const struct nfs_server *seq_server; - struct nfs4_sequence_args *seq_args; - struct nfs4_sequence_res *seq_res; -}; - -struct nfs4_open_createattrs { - struct nfs4_label *label; - struct iattr *sattr; - const __u32 verf[2]; -}; - -struct nfs4_closedata { - struct inode *inode; - struct nfs4_state *state; - struct nfs_closeargs arg; - struct nfs_closeres res; - struct { - struct nfs4_layoutreturn_args arg; - struct nfs4_layoutreturn_res res; - struct nfs4_xdr_opaque_data ld_private; - u32 roc_barrier; - bool roc; - } lr; - struct nfs_fattr fattr; - long unsigned int timestamp; -}; - -struct nfs4_createdata { - struct rpc_message msg; - struct nfs4_create_arg arg; - struct nfs4_create_res res; - struct nfs_fh fh; - struct nfs_fattr fattr; - struct nfs4_label *label; -}; - -struct nfs4_renewdata { - struct nfs_client *client; - long unsigned int timestamp; -}; - -struct nfs4_delegreturndata { - struct nfs4_delegreturnargs args; - struct nfs4_delegreturnres res; - struct nfs_fh fh; - nfs4_stateid stateid; - long unsigned int timestamp; - struct { - struct nfs4_layoutreturn_args arg; - struct nfs4_layoutreturn_res res; - struct nfs4_xdr_opaque_data ld_private; - u32 roc_barrier; - bool roc; - } lr; - struct nfs_fattr fattr; - int rpc_status; - struct inode *inode; -}; - -struct nfs4_unlockdata { - struct nfs_locku_args arg; - struct nfs_locku_res res; - struct nfs4_lock_state *lsp; - struct nfs_open_context *ctx; - struct nfs_lock_context *l_ctx; - struct file_lock fl; - struct nfs_server *server; - long unsigned int timestamp; -}; - -struct nfs4_lockdata { - struct nfs_lock_args arg; - struct nfs_lock_res res; - struct nfs4_lock_state *lsp; - struct nfs_open_context *ctx; - struct file_lock fl; - long unsigned int timestamp; - int rpc_status; - int cancelled; - struct nfs_server *server; -}; - -struct nfs4_lock_waiter { - struct task_struct *task; - struct inode *inode; - struct nfs_lowner *owner; -}; - -struct nfs_release_lockowner_data { - struct nfs4_lock_state *lsp; - struct nfs_server *server; - struct nfs_release_lockowner_args args; - struct nfs_release_lockowner_res res; - long unsigned int timestamp; -}; - -struct rpc_bind_conn_calldata { - struct nfs_client *clp; - const struct cred *cred; -}; - -struct nfs41_exchange_id_data { - struct nfs41_exchange_id_res res; - struct nfs41_exchange_id_args args; -}; - -struct nfs4_get_lease_time_data { - struct nfs4_get_lease_time_args *args; - struct nfs4_get_lease_time_res *res; - struct nfs_client *clp; -}; - -struct nfs4_sequence_data { - struct nfs_client *clp; - struct nfs4_sequence_args args; - struct nfs4_sequence_res res; -}; - -struct nfs4_reclaim_complete_data { - struct nfs_client *clp; - struct nfs41_reclaim_complete_args arg; - struct nfs41_reclaim_complete_res res; -}; - -struct nfs_free_stateid_data { - struct nfs_server *server; - struct nfs41_free_stateid_args args; - struct nfs41_free_stateid_res res; -}; - -enum opentype4 { - NFS4_OPEN_NOCREATE = 0, - NFS4_OPEN_CREATE = 1, -}; - -enum limit_by4 { - NFS4_LIMIT_SIZE = 1, - NFS4_LIMIT_BLOCKS = 2, -}; - -enum open_delegation_type4 { - NFS4_OPEN_DELEGATE_NONE = 0, - NFS4_OPEN_DELEGATE_READ = 1, - NFS4_OPEN_DELEGATE_WRITE = 2, - NFS4_OPEN_DELEGATE_NONE_EXT = 3, -}; - -enum why_no_delegation4 { - WND4_NOT_WANTED = 0, - WND4_CONTENTION = 1, - WND4_RESOURCE = 2, - WND4_NOT_SUPP_FTYPE = 3, - WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4, - WND4_NOT_SUPP_UPGRADE = 5, - WND4_NOT_SUPP_DOWNGRADE = 6, - WND4_CANCELLED = 7, - WND4_IS_DIR = 8, -}; - -enum lock_type4 { - NFS4_UNLOCK_LT = 0, - NFS4_READ_LT = 1, - NFS4_WRITE_LT = 2, - NFS4_READW_LT = 3, - NFS4_WRITEW_LT = 4, -}; - -enum pnfs_layoutreturn_type { - RETURN_FILE = 1, - RETURN_FSID = 2, - RETURN_ALL = 3, -}; - -enum data_content4 { - NFS4_CONTENT_DATA = 0, - NFS4_CONTENT_HOLE = 1, -}; - -struct nfs42_netaddr { - char netid[5]; - char addr[58]; - u32 netid_len; - u32 addr_len; -}; - -enum netloc_type4 { - NL4_NAME = 1, - NL4_URL = 2, - NL4_NETADDR = 3, -}; - -struct nl4_server { - enum netloc_type4 nl4_type; - union { - struct { - int nl4_str_sz; - char nl4_str[1025]; - }; - struct nfs42_netaddr nl4_addr; - } u; -}; - -enum nfs4_setxattr_options { - SETXATTR4_EITHER = 0, - SETXATTR4_CREATE = 1, - SETXATTR4_REPLACE = 2, -}; - -struct nfs42_layoutstat_res { - struct nfs4_sequence_res seq_res; - int num_dev; - int rpc_status; -}; - -struct nfs42_device_error { - struct nfs4_deviceid dev_id; - int status; - enum nfs_opnum4 opnum; -}; - -struct nfs42_layout_error { - __u64 offset; - __u64 length; - nfs4_stateid stateid; - struct nfs42_device_error errors[1]; -}; - -struct nfs42_layouterror_args { - struct nfs4_sequence_args seq_args; - struct inode *inode; - unsigned int num_errors; - struct nfs42_layout_error errors[5]; -}; - -struct nfs42_layouterror_res { - struct nfs4_sequence_res seq_res; - unsigned int num_errors; - int rpc_status; -}; - -struct nfs42_clone_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *src_fh; - struct nfs_fh *dst_fh; - nfs4_stateid src_stateid; - nfs4_stateid dst_stateid; - __u64 src_offset; - __u64 dst_offset; - __u64 count; - const u32 *dst_bitmask; -}; - -struct nfs42_clone_res { - struct nfs4_sequence_res seq_res; - unsigned int rpc_status; - struct nfs_fattr *dst_fattr; - const struct nfs_server *server; -}; - -struct nfs42_falloc_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *falloc_fh; - nfs4_stateid falloc_stateid; - u64 falloc_offset; - u64 falloc_length; - const u32 *falloc_bitmask; -}; - -struct nfs42_falloc_res { - struct nfs4_sequence_res seq_res; - unsigned int status; - struct nfs_fattr *falloc_fattr; - const struct nfs_server *falloc_server; -}; - -struct nfs42_copy_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *src_fh; - nfs4_stateid src_stateid; - u64 src_pos; - struct nfs_fh *dst_fh; - nfs4_stateid dst_stateid; - u64 dst_pos; - u64 count; - bool sync; - struct nl4_server *cp_src; -}; - -struct nfs42_write_res { - nfs4_stateid stateid; - u64 count; - struct nfs_writeverf verifier; -}; - -struct nfs42_copy_res { - struct nfs4_sequence_res seq_res; - struct nfs42_write_res write_res; - bool consecutive; - bool synchronous; - struct nfs_commitres commit_res; -}; - -struct nfs42_offload_status_args { - struct nfs4_sequence_args osa_seq_args; - struct nfs_fh *osa_src_fh; - nfs4_stateid osa_stateid; -}; - -struct nfs42_offload_status_res { - struct nfs4_sequence_res osr_seq_res; - uint64_t osr_count; - int osr_status; -}; - -struct nfs42_copy_notify_args { - struct nfs4_sequence_args cna_seq_args; - struct nfs_fh *cna_src_fh; - nfs4_stateid cna_src_stateid; - struct nl4_server cna_dst; -}; - -struct nfs42_copy_notify_res { - struct nfs4_sequence_res cnr_seq_res; - struct nfstime4 cnr_lease_time; - nfs4_stateid cnr_stateid; - struct nl4_server cnr_src; -}; - -struct nfs42_seek_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *sa_fh; - nfs4_stateid sa_stateid; - u64 sa_offset; - u32 sa_what; -}; - -struct nfs42_seek_res { - struct nfs4_sequence_res seq_res; - unsigned int status; - u32 sr_eof; - u64 sr_offset; -}; - -struct nfs42_setxattrargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - const char *xattr_name; - u32 xattr_flags; - size_t xattr_len; - struct page **xattr_pages; -}; - -struct nfs42_setxattrres { - struct nfs4_sequence_res seq_res; - struct nfs4_change_info cinfo; -}; - -struct nfs42_getxattrargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - const char *xattr_name; - size_t xattr_len; - struct page **xattr_pages; -}; - -struct nfs42_getxattrres { - struct nfs4_sequence_res seq_res; - size_t xattr_len; -}; - -struct nfs42_listxattrsargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - u32 count; - u64 cookie; - struct page **xattr_pages; -}; - -struct nfs42_listxattrsres { - struct nfs4_sequence_res seq_res; - struct page *scratch; - void *xattr_buf; - size_t xattr_len; - u64 cookie; - bool eof; - size_t copied; -}; - -struct nfs42_removexattrargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - const char *xattr_name; -}; - -struct nfs42_removexattrres { - struct nfs4_sequence_res seq_res; - struct nfs4_change_info cinfo; -}; - -struct compound_hdr { - int32_t status; - uint32_t nops; - __be32 *nops_p; - uint32_t taglen; - char *tag; - uint32_t replen; - u32 minorversion; -}; - -struct nfs4_copy_state { - struct list_head copies; - struct list_head src_copies; - nfs4_stateid stateid; - struct completion completion; - uint64_t count; - struct nfs_writeverf verf; - int error; - int flags; - struct nfs4_state *parent_src_state; - struct nfs4_state *parent_dst_state; -}; - -struct nfs_referral_count { - struct list_head list; - const struct task_struct *task; - unsigned int referral_count; -}; - -struct rpc_pipe_dir_object_ops; - -struct rpc_pipe_dir_object { - struct list_head pdo_head; - const struct rpc_pipe_dir_object_ops *pdo_ops; - void *pdo_data; -}; - -struct rpc_pipe_dir_object_ops { - int (*create)(struct dentry *, struct rpc_pipe_dir_object *); - void (*destroy)(struct dentry *, struct rpc_pipe_dir_object *); -}; - -struct rpc_inode { - struct inode vfs_inode; - void *private; - struct rpc_pipe *pipe; - wait_queue_head_t waitq; -}; - -struct idmap_legacy_upcalldata; - -struct idmap { - struct rpc_pipe_dir_object idmap_pdo; - struct rpc_pipe *idmap_pipe; - struct idmap_legacy_upcalldata *idmap_upcall_data; - struct mutex idmap_mutex; - struct user_namespace *user_ns; -}; - -struct request_key_auth { - struct callback_head rcu; - struct key *target_key; - struct key *dest_keyring; - const struct cred *cred; - void *callout_info; - size_t callout_len; - pid_t pid; - char op[8]; -}; - -struct idmap_msg { - __u8 im_type; - __u8 im_conv; - char im_name[128]; - __u32 im_id; - __u8 im_status; -}; - -struct idmap_legacy_upcalldata { - struct rpc_pipe_msg pipe_msg; - struct idmap_msg idmap_msg; - struct key *authkey; - struct idmap *idmap; -}; - -enum { - Opt_find_uid = 0, - Opt_find_gid = 1, - Opt_find_user = 2, - Opt_find_group = 3, - Opt_find_err = 4, -}; - -enum nfs4_callback_procnum { - CB_NULL = 0, - CB_COMPOUND = 1, -}; - -struct nfs_callback_data { - unsigned int users; - struct svc_serv *serv; -}; - -enum rpc_accept_stat { - RPC_SUCCESS = 0, - RPC_PROG_UNAVAIL = 1, - RPC_PROG_MISMATCH = 2, - RPC_PROC_UNAVAIL = 3, - RPC_GARBAGE_ARGS = 4, - RPC_SYSTEM_ERR = 5, - RPC_DROP_REPLY = 60000, -}; - -enum rpc_auth_stat { - RPC_AUTH_OK = 0, - RPC_AUTH_BADCRED = 1, - RPC_AUTH_REJECTEDCRED = 2, - RPC_AUTH_BADVERF = 3, - RPC_AUTH_REJECTEDVERF = 4, - RPC_AUTH_TOOWEAK = 5, - RPCSEC_GSS_CREDPROBLEM = 13, - RPCSEC_GSS_CTXPROBLEM = 14, -}; - -enum nfs4_callback_opnum { - OP_CB_GETATTR = 3, - OP_CB_RECALL = 4, - OP_CB_LAYOUTRECALL = 5, - OP_CB_NOTIFY = 6, - OP_CB_PUSH_DELEG = 7, - OP_CB_RECALL_ANY = 8, - OP_CB_RECALLABLE_OBJ_AVAIL = 9, - OP_CB_RECALL_SLOT = 10, - OP_CB_SEQUENCE = 11, - OP_CB_WANTS_CANCELLED = 12, - OP_CB_NOTIFY_LOCK = 13, - OP_CB_NOTIFY_DEVICEID = 14, - OP_CB_OFFLOAD = 15, - OP_CB_ILLEGAL = 10044, -}; - -struct cb_process_state { - __be32 drc_status; - struct nfs_client *clp; - struct nfs4_slot *slot; - u32 minorversion; - struct net *net; -}; - -struct cb_compound_hdr_arg { - unsigned int taglen; - const char *tag; - unsigned int minorversion; - unsigned int cb_ident; - unsigned int nops; -}; - -struct cb_compound_hdr_res { - __be32 *status; - unsigned int taglen; - const char *tag; - __be32 *nops; -}; - -struct cb_getattrargs { - struct nfs_fh fh; - uint32_t bitmap[2]; -}; - -struct cb_getattrres { - __be32 status; - uint32_t bitmap[2]; - uint64_t size; - uint64_t change_attr; - struct timespec64 ctime; - struct timespec64 mtime; -}; - -struct cb_recallargs { - struct nfs_fh fh; - nfs4_stateid stateid; - uint32_t truncate; -}; - -struct referring_call { - uint32_t rc_sequenceid; - uint32_t rc_slotid; -}; - -struct referring_call_list { - struct nfs4_sessionid rcl_sessionid; - uint32_t rcl_nrefcalls; - struct referring_call *rcl_refcalls; -}; - -struct cb_sequenceargs { - struct sockaddr *csa_addr; - struct nfs4_sessionid csa_sessionid; - uint32_t csa_sequenceid; - uint32_t csa_slotid; - uint32_t csa_highestslotid; - uint32_t csa_cachethis; - uint32_t csa_nrclists; - struct referring_call_list *csa_rclists; -}; - -struct cb_sequenceres { - __be32 csr_status; - struct nfs4_sessionid csr_sessionid; - uint32_t csr_sequenceid; - uint32_t csr_slotid; - uint32_t csr_highestslotid; - uint32_t csr_target_highestslotid; -}; - -struct cb_recallanyargs { - uint32_t craa_objs_to_keep; - uint32_t craa_type_mask; -}; - -struct cb_recallslotargs { - uint32_t crsa_target_highest_slotid; -}; - -struct cb_layoutrecallargs { - uint32_t cbl_recall_type; - uint32_t cbl_layout_type; - uint32_t cbl_layoutchanged; - union { - struct { - struct nfs_fh cbl_fh; - struct pnfs_layout_range cbl_range; - nfs4_stateid cbl_stateid; - }; - struct nfs_fsid cbl_fsid; - }; -}; - -struct cb_devicenotifyitem { - uint32_t cbd_notify_type; - uint32_t cbd_layout_type; - struct nfs4_deviceid cbd_dev_id; - uint32_t cbd_immediate; -}; - -struct cb_devicenotifyargs { - int ndevs; - struct cb_devicenotifyitem *devs; -}; - -struct cb_offloadargs { - struct nfs_fh coa_fh; - nfs4_stateid coa_stateid; - uint32_t error; - uint64_t wr_count; - struct nfs_writeverf wr_writeverf; -}; - -struct callback_op { - __be32 (*process_op)(void *, void *, struct cb_process_state *); - __be32 (*decode_args)(struct svc_rqst *, struct xdr_stream *, void *); - __be32 (*encode_res)(struct svc_rqst *, struct xdr_stream *, const void *); - long int res_maxsize; -}; - -struct xprt_create { - int ident; - struct net *net; - struct sockaddr *srcaddr; - struct sockaddr *dstaddr; - size_t addrlen; - const char *servername; - struct svc_xprt *bc_xprt; - struct rpc_xprt_switch *bc_xps; - unsigned int flags; -}; - -struct nfs4_ds_server { - struct list_head list; - struct rpc_clnt *rpc_clnt; -}; - -enum pnfs_update_layout_reason { - PNFS_UPDATE_LAYOUT_UNKNOWN = 0, - PNFS_UPDATE_LAYOUT_NO_PNFS = 1, - PNFS_UPDATE_LAYOUT_RD_ZEROLEN = 2, - PNFS_UPDATE_LAYOUT_MDSTHRESH = 3, - PNFS_UPDATE_LAYOUT_NOMEM = 4, - PNFS_UPDATE_LAYOUT_BULK_RECALL = 5, - PNFS_UPDATE_LAYOUT_IO_TEST_FAIL = 6, - PNFS_UPDATE_LAYOUT_FOUND_CACHED = 7, - PNFS_UPDATE_LAYOUT_RETURN = 8, - PNFS_UPDATE_LAYOUT_RETRY = 9, - PNFS_UPDATE_LAYOUT_BLOCKED = 10, - PNFS_UPDATE_LAYOUT_INVALID_OPEN = 11, - PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET = 12, - PNFS_UPDATE_LAYOUT_EXIT = 13, -}; - -struct trace_event_raw_nfs4_clientid_event { - struct trace_entry ent; - u32 __data_loc_dstaddr; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_sequence_done { - struct trace_entry ent; - unsigned int session; - unsigned int slot_nr; - unsigned int seq_nr; - unsigned int highest_slotid; - unsigned int target_highest_slotid; - unsigned int status_flags; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_cb_sequence { - struct trace_entry ent; - unsigned int session; - unsigned int slot_nr; - unsigned int seq_nr; - unsigned int highest_slotid; - unsigned int cachethis; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_cb_seqid_err { - struct trace_entry ent; - unsigned int session; - unsigned int slot_nr; - unsigned int seq_nr; - unsigned int highest_slotid; - unsigned int cachethis; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_setup_sequence { - struct trace_entry ent; - unsigned int session; - unsigned int slot_nr; - unsigned int seq_nr; - unsigned int highest_used_slotid; - char __data[0]; -}; - -struct trace_event_raw_nfs4_state_mgr { - struct trace_entry ent; - long unsigned int state; - u32 __data_loc_hostname; - char __data[0]; -}; - -struct trace_event_raw_nfs4_state_mgr_failed { - struct trace_entry ent; - long unsigned int error; - long unsigned int state; - u32 __data_loc_hostname; - u32 __data_loc_section; - char __data[0]; -}; - -struct trace_event_raw_nfs4_xdr_status { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - u32 op; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_cb_error_class { - struct trace_entry ent; - u32 xid; - u32 cbident; - char __data[0]; -}; - -struct trace_event_raw_nfs4_open_event { - struct trace_entry ent; - long unsigned int error; - unsigned int flags; - unsigned int fmode; - dev_t dev; - u32 fhandle; - u64 fileid; - u64 dir; - u32 __data_loc_name; - int stateid_seq; - u32 stateid_hash; - int openstateid_seq; - u32 openstateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_cached_open { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - unsigned int fmode; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_close { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - unsigned int fmode; - long unsigned int error; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_lock_event { - struct trace_entry ent; - long unsigned int error; - int cmd; - char type; - loff_t start; - loff_t end; - dev_t dev; - u32 fhandle; - u64 fileid; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_set_lock { - struct trace_entry ent; - long unsigned int error; - int cmd; - char type; - loff_t start; - loff_t end; - dev_t dev; - u32 fhandle; - u64 fileid; - int stateid_seq; - u32 stateid_hash; - int lockstateid_seq; - u32 lockstateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_state_lock_reclaim { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - long unsigned int state_flags; - long unsigned int lock_flags; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_set_delegation_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - unsigned int fmode; - char __data[0]; -}; - -struct trace_event_raw_nfs4_delegreturn_exit { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - long unsigned int error; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_test_stateid_event { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u32 fhandle; - u64 fileid; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_lookup_event { - struct trace_entry ent; - dev_t dev; - long unsigned int error; - u64 dir; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs4_lookupp { - struct trace_entry ent; - dev_t dev; - u64 ino; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_rename { - struct trace_entry ent; - dev_t dev; - long unsigned int error; - u64 olddir; - u32 __data_loc_oldname; - u64 newdir; - u32 __data_loc_newname; - char __data[0]; -}; - -struct trace_event_raw_nfs4_inode_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_inode_stateid_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - long unsigned int error; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_getattr_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - unsigned int valid; - long unsigned int error; - char __data[0]; -}; - -struct trace_event_raw_nfs4_inode_callback_event { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u32 fhandle; - u64 fileid; - u32 __data_loc_dstaddr; - char __data[0]; -}; - -struct trace_event_raw_nfs4_inode_stateid_callback_event { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u32 fhandle; - u64 fileid; - u32 __data_loc_dstaddr; - int stateid_seq; - u32 stateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_idmap_event { - struct trace_entry ent; - long unsigned int error; - u32 id; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_nfs4_read_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 arg_count; - u32 res_count; - long unsigned int error; - int stateid_seq; - u32 stateid_hash; - int layoutstateid_seq; - u32 layoutstateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_write_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 arg_count; - u32 res_count; - long unsigned int error; - int stateid_seq; - u32 stateid_hash; - int layoutstateid_seq; - u32 layoutstateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_commit_event { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - long unsigned int error; - loff_t offset; - u32 count; - int layoutstateid_seq; - u32 layoutstateid_hash; - char __data[0]; -}; - -struct trace_event_raw_nfs4_layoutget { - struct trace_entry ent; - dev_t dev; - u32 fhandle; - u64 fileid; - u32 iomode; - u64 offset; - u64 count; - long unsigned int error; - int stateid_seq; - u32 stateid_hash; - int layoutstateid_seq; - u32 layoutstateid_hash; - char __data[0]; -}; - -struct trace_event_raw_pnfs_update_layout { - struct trace_entry ent; - dev_t dev; - u64 fileid; - u32 fhandle; - loff_t pos; - u64 count; - enum pnfs_iomode iomode; - int layoutstateid_seq; - u32 layoutstateid_hash; - long int lseg; - enum pnfs_update_layout_reason reason; - char __data[0]; -}; - -struct trace_event_raw_pnfs_layout_event { - struct trace_entry ent; - dev_t dev; - u64 fileid; - u32 fhandle; - loff_t pos; - u64 count; - enum pnfs_iomode iomode; - int layoutstateid_seq; - u32 layoutstateid_hash; - long int lseg; - char __data[0]; -}; - -struct trace_event_raw_nfs4_flexfiles_io_event { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 count; - int stateid_seq; - u32 stateid_hash; - u32 __data_loc_dstaddr; - char __data[0]; -}; - -struct trace_event_raw_ff_layout_commit_error { - struct trace_entry ent; - long unsigned int error; - dev_t dev; - u32 fhandle; - u64 fileid; - loff_t offset; - u32 count; - u32 __data_loc_dstaddr; - char __data[0]; -}; - -struct trace_event_data_offsets_nfs4_clientid_event { - u32 dstaddr; -}; - -struct trace_event_data_offsets_nfs4_sequence_done {}; - -struct trace_event_data_offsets_nfs4_cb_sequence {}; - -struct trace_event_data_offsets_nfs4_cb_seqid_err {}; - -struct trace_event_data_offsets_nfs4_setup_sequence {}; - -struct trace_event_data_offsets_nfs4_state_mgr { - u32 hostname; -}; - -struct trace_event_data_offsets_nfs4_state_mgr_failed { - u32 hostname; - u32 section; -}; - -struct trace_event_data_offsets_nfs4_xdr_status {}; - -struct trace_event_data_offsets_nfs4_cb_error_class {}; - -struct trace_event_data_offsets_nfs4_open_event { - u32 name; -}; - -struct trace_event_data_offsets_nfs4_cached_open {}; - -struct trace_event_data_offsets_nfs4_close {}; - -struct trace_event_data_offsets_nfs4_lock_event {}; - -struct trace_event_data_offsets_nfs4_set_lock {}; - -struct trace_event_data_offsets_nfs4_state_lock_reclaim {}; - -struct trace_event_data_offsets_nfs4_set_delegation_event {}; - -struct trace_event_data_offsets_nfs4_delegreturn_exit {}; - -struct trace_event_data_offsets_nfs4_test_stateid_event {}; - -struct trace_event_data_offsets_nfs4_lookup_event { - u32 name; -}; - -struct trace_event_data_offsets_nfs4_lookupp {}; - -struct trace_event_data_offsets_nfs4_rename { - u32 oldname; - u32 newname; -}; - -struct trace_event_data_offsets_nfs4_inode_event {}; - -struct trace_event_data_offsets_nfs4_inode_stateid_event {}; - -struct trace_event_data_offsets_nfs4_getattr_event {}; - -struct trace_event_data_offsets_nfs4_inode_callback_event { - u32 dstaddr; -}; - -struct trace_event_data_offsets_nfs4_inode_stateid_callback_event { - u32 dstaddr; -}; - -struct trace_event_data_offsets_nfs4_idmap_event { - u32 name; -}; - -struct trace_event_data_offsets_nfs4_read_event {}; - -struct trace_event_data_offsets_nfs4_write_event {}; - -struct trace_event_data_offsets_nfs4_commit_event {}; - -struct trace_event_data_offsets_nfs4_layoutget {}; - -struct trace_event_data_offsets_pnfs_update_layout {}; - -struct trace_event_data_offsets_pnfs_layout_event {}; - -struct trace_event_data_offsets_nfs4_flexfiles_io_event { - u32 dstaddr; -}; - -struct trace_event_data_offsets_ff_layout_commit_error { - u32 dstaddr; -}; - -typedef void (*btf_trace_nfs4_setclientid)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_setclientid_confirm)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_renew)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_renew_async)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_exchange_id)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_create_session)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_destroy_session)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_destroy_clientid)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_bind_conn_to_session)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_sequence)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_reclaim_complete)(void *, const struct nfs_client *, int); - -typedef void (*btf_trace_nfs4_sequence_done)(void *, const struct nfs4_session *, const struct nfs4_sequence_res *); - -typedef void (*btf_trace_nfs4_cb_sequence)(void *, const struct cb_sequenceargs *, const struct cb_sequenceres *, __be32); - -typedef void (*btf_trace_nfs4_cb_seqid_err)(void *, const struct cb_sequenceargs *, __be32); - -typedef void (*btf_trace_nfs4_setup_sequence)(void *, const struct nfs4_session *, const struct nfs4_sequence_args *); - -typedef void (*btf_trace_nfs4_state_mgr)(void *, const struct nfs_client *); - -typedef void (*btf_trace_nfs4_state_mgr_failed)(void *, const struct nfs_client *, const char *, int); - -typedef void (*btf_trace_nfs4_xdr_status)(void *, const struct xdr_stream *, u32, u32); - -typedef void (*btf_trace_nfs_cb_no_clp)(void *, __be32, u32); - -typedef void (*btf_trace_nfs_cb_badprinc)(void *, __be32, u32); - -typedef void (*btf_trace_nfs4_open_reclaim)(void *, const struct nfs_open_context *, int, int); - -typedef void (*btf_trace_nfs4_open_expired)(void *, const struct nfs_open_context *, int, int); - -typedef void (*btf_trace_nfs4_open_file)(void *, const struct nfs_open_context *, int, int); - -typedef void (*btf_trace_nfs4_cached_open)(void *, const struct nfs4_state *); - -typedef void (*btf_trace_nfs4_close)(void *, const struct nfs4_state *, const struct nfs_closeargs *, const struct nfs_closeres *, int); - -typedef void (*btf_trace_nfs4_get_lock)(void *, const struct file_lock *, const struct nfs4_state *, int, int); - -typedef void (*btf_trace_nfs4_unlock)(void *, const struct file_lock *, const struct nfs4_state *, int, int); - -typedef void (*btf_trace_nfs4_set_lock)(void *, const struct file_lock *, const struct nfs4_state *, const nfs4_stateid *, int, int); - -typedef void (*btf_trace_nfs4_state_lock_reclaim)(void *, const struct nfs4_state *, const struct nfs4_lock_state *); - -typedef void (*btf_trace_nfs4_set_delegation)(void *, const struct inode *, fmode_t); - -typedef void (*btf_trace_nfs4_reclaim_delegation)(void *, const struct inode *, fmode_t); - -typedef void (*btf_trace_nfs4_delegreturn_exit)(void *, const struct nfs4_delegreturnargs *, const struct nfs4_delegreturnres *, int); - -typedef void (*btf_trace_nfs4_test_delegation_stateid)(void *, const struct nfs4_state *, const struct nfs4_lock_state *, int); - -typedef void (*btf_trace_nfs4_test_open_stateid)(void *, const struct nfs4_state *, const struct nfs4_lock_state *, int); - -typedef void (*btf_trace_nfs4_test_lock_stateid)(void *, const struct nfs4_state *, const struct nfs4_lock_state *, int); - -typedef void (*btf_trace_nfs4_lookup)(void *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_symlink)(void *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_mkdir)(void *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_mknod)(void *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_remove)(void *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_get_fs_locations)(void *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_secinfo)(void *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_lookupp)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_rename)(void *, const struct inode *, const struct qstr *, const struct inode *, const struct qstr *, int); - -typedef void (*btf_trace_nfs4_access)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_readlink)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_readdir)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_get_acl)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_set_acl)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_get_security_label)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_set_security_label)(void *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_setattr)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_delegreturn)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_open_stateid_update)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_open_stateid_update_wait)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_close_stateid_update_wait)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_getattr)(void *, const struct nfs_server *, const struct nfs_fh *, const struct nfs_fattr *, int); - -typedef void (*btf_trace_nfs4_lookup_root)(void *, const struct nfs_server *, const struct nfs_fh *, const struct nfs_fattr *, int); - -typedef void (*btf_trace_nfs4_fsinfo)(void *, const struct nfs_server *, const struct nfs_fh *, const struct nfs_fattr *, int); - -typedef void (*btf_trace_nfs4_cb_getattr)(void *, const struct nfs_client *, const struct nfs_fh *, const struct inode *, int); - -typedef void (*btf_trace_nfs4_cb_recall)(void *, const struct nfs_client *, const struct nfs_fh *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_cb_layoutrecall_file)(void *, const struct nfs_client *, const struct nfs_fh *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_map_name_to_uid)(void *, const char *, int, u32, int); - -typedef void (*btf_trace_nfs4_map_group_to_gid)(void *, const char *, int, u32, int); - -typedef void (*btf_trace_nfs4_map_uid_to_name)(void *, const char *, int, u32, int); - -typedef void (*btf_trace_nfs4_map_gid_to_group)(void *, const char *, int, u32, int); - -typedef void (*btf_trace_nfs4_read)(void *, const struct nfs_pgio_header *, int); - -typedef void (*btf_trace_nfs4_pnfs_read)(void *, const struct nfs_pgio_header *, int); - -typedef void (*btf_trace_nfs4_write)(void *, const struct nfs_pgio_header *, int); - -typedef void (*btf_trace_nfs4_pnfs_write)(void *, const struct nfs_pgio_header *, int); - -typedef void (*btf_trace_nfs4_commit)(void *, const struct nfs_commit_data *, int); - -typedef void (*btf_trace_nfs4_pnfs_commit_ds)(void *, const struct nfs_commit_data *, int); - -typedef void (*btf_trace_nfs4_layoutget)(void *, const struct nfs_open_context *, const struct pnfs_layout_range *, const struct pnfs_layout_range *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_layoutcommit)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_layoutreturn)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_layoutreturn_on_close)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_layouterror)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_nfs4_layoutstats)(void *, const struct inode *, const nfs4_stateid *, int); - -typedef void (*btf_trace_pnfs_update_layout)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *, enum pnfs_update_layout_reason); - -typedef void (*btf_trace_pnfs_mds_fallback_pg_init_read)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *); - -typedef void (*btf_trace_pnfs_mds_fallback_pg_init_write)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *); - -typedef void (*btf_trace_pnfs_mds_fallback_pg_get_mirror_count)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *); - -typedef void (*btf_trace_pnfs_mds_fallback_read_done)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *); - -typedef void (*btf_trace_pnfs_mds_fallback_write_done)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *); - -typedef void (*btf_trace_pnfs_mds_fallback_read_pagelist)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *); - -typedef void (*btf_trace_pnfs_mds_fallback_write_pagelist)(void *, struct inode *, loff_t, u64, enum pnfs_iomode, struct pnfs_layout_hdr *, struct pnfs_layout_segment *); - -typedef void (*btf_trace_ff_layout_read_error)(void *, const struct nfs_pgio_header *); - -typedef void (*btf_trace_ff_layout_write_error)(void *, const struct nfs_pgio_header *); - -typedef void (*btf_trace_ff_layout_commit_error)(void *, const struct nfs_commit_data *); - -enum pnfs_layouttype { - LAYOUT_NFSV4_1_FILES = 1, - LAYOUT_OSD2_OBJECTS = 2, - LAYOUT_BLOCK_VOLUME = 3, - LAYOUT_FLEX_FILES = 4, - LAYOUT_SCSI = 5, - LAYOUT_TYPE_MAX = 6, -}; - -struct nfs42_layoutstat_data { - struct inode *inode; - struct nfs42_layoutstat_args args; - struct nfs42_layoutstat_res res; -}; - -enum { - NFS_LSEG_VALID = 0, - NFS_LSEG_ROC = 1, - NFS_LSEG_LAYOUTCOMMIT = 2, - NFS_LSEG_LAYOUTRETURN = 3, - NFS_LSEG_UNAVAILABLE = 4, -}; - -enum { - NFS_DEVICEID_INVALID = 0, - NFS_DEVICEID_UNAVAILABLE = 1, - NFS_DEVICEID_NOCACHE = 2, -}; - -struct rpc_add_xprt_test { - void (*add_xprt_test)(struct rpc_clnt *, struct rpc_xprt *, void *); - void *data; -}; - -struct nfs4_pnfs_ds_addr { - struct __kernel_sockaddr_storage da_addr; - size_t da_addrlen; - struct list_head da_node; - char *da_remotestr; -}; - -struct nfs4_pnfs_ds { - struct list_head ds_node; - char *ds_remotestr; - struct list_head ds_addrs; - struct nfs_client *ds_clp; - refcount_t ds_count; - long unsigned int ds_state; -}; - -struct nfs42_layouterror_data { - struct nfs42_layouterror_args args; - struct nfs42_layouterror_res res; - struct inode *inode; - struct pnfs_layout_segment *lseg; -}; - -struct nfs42_offloadcancel_data { - struct nfs_server *seq_server; - struct nfs42_offload_status_args args; - struct nfs42_offload_status_res res; -}; - -struct nfs4_xattr_bucket { - spinlock_t lock; - struct hlist_head hlist; - struct nfs4_xattr_cache *cache; - bool draining; -}; - -struct nfs4_xattr_entry; - -struct nfs4_xattr_cache { - struct kref ref; - struct nfs4_xattr_bucket buckets[64]; - struct list_head lru; - struct list_head dispose; - atomic_long_t nent; - spinlock_t listxattr_lock; - struct inode *inode; - struct nfs4_xattr_entry *listxattr; -}; - -struct nfs4_xattr_entry { - struct kref ref; - struct hlist_node hnode; - struct list_head lru; - struct list_head dispose; - char *xattr_name; - void *xattr_value; - size_t xattr_size; - struct nfs4_xattr_bucket *bucket; - uint32_t flags; -}; - -enum stripetype4 { - STRIPE_SPARSE = 1, - STRIPE_DENSE = 2, -}; - -struct nfs4_file_layout_dsaddr { - struct nfs4_deviceid_node id_node; - u32 stripe_count; - u8 *stripe_indices; - u32 ds_num; - struct nfs4_pnfs_ds *ds_list[1]; -}; - -struct nfs4_filelayout_segment { - struct pnfs_layout_segment generic_hdr; - u32 stripe_type; - u32 commit_through_mds; - u32 stripe_unit; - u32 first_stripe_index; - u64 pattern_offset; - struct nfs4_deviceid deviceid; - struct nfs4_file_layout_dsaddr *dsaddr; - unsigned int num_fh; - struct nfs_fh **fh_array; -}; - -struct nfs4_filelayout { - struct pnfs_layout_hdr generic_hdr; - struct pnfs_ds_commit_info commit_info; -}; - -struct nfs4_ff_ds_version { - u32 version; - u32 minor_version; - u32 rsize; - u32 wsize; - bool tightly_coupled; -}; - -struct nfs4_ff_layout_ds { - struct nfs4_deviceid_node id_node; - u32 ds_versions_cnt; - struct nfs4_ff_ds_version *ds_versions; - struct nfs4_pnfs_ds *ds; -}; - -struct nfs4_ff_layout_ds_err { - struct list_head list; - u64 offset; - u64 length; - int status; - enum nfs_opnum4 opnum; - nfs4_stateid stateid; - struct nfs4_deviceid deviceid; -}; - -struct nfs4_ff_io_stat { - __u64 ops_requested; - __u64 bytes_requested; - __u64 ops_completed; - __u64 bytes_completed; - __u64 bytes_not_delivered; - ktime_t total_busy_time; - ktime_t aggregate_completion_time; -}; - -struct nfs4_ff_busy_timer { - ktime_t start_time; - atomic_t n_ops; -}; - -struct nfs4_ff_layoutstat { - struct nfs4_ff_io_stat io_stat; - struct nfs4_ff_busy_timer busy_timer; -}; - -struct nfs4_ff_layout_mirror { - struct pnfs_layout_hdr *layout; - struct list_head mirrors; - u32 ds_count; - u32 efficiency; - struct nfs4_deviceid devid; - struct nfs4_ff_layout_ds *mirror_ds; - u32 fh_versions_cnt; - struct nfs_fh *fh_versions; - nfs4_stateid stateid; - const struct cred *ro_cred; - const struct cred *rw_cred; - refcount_t ref; - spinlock_t lock; - long unsigned int flags; - struct nfs4_ff_layoutstat read_stat; - struct nfs4_ff_layoutstat write_stat; - ktime_t start_time; - u32 report_interval; -}; - -struct nfs4_ff_layout_segment { - struct pnfs_layout_segment generic_hdr; - u64 stripe_unit; - u32 flags; - u32 mirror_array_cnt; - struct nfs4_ff_layout_mirror *mirror_array[0]; -}; - -struct nfs4_flexfile_layout { - struct pnfs_layout_hdr generic_hdr; - struct pnfs_ds_commit_info commit_info; - struct list_head mirrors; - struct list_head error_list; - ktime_t last_report_time; -}; - -struct nfs4_flexfile_layoutreturn_args { - struct list_head errors; - struct nfs42_layoutstat_devinfo devinfo[4]; - unsigned int num_errors; - unsigned int num_dev; - struct page *pages[1]; -}; - -struct getdents_callback___2 { - struct dir_context ctx; - char *name; - u64 ino; - int found; - int sequence; -}; - -struct nlm_host___2; - -struct nlm_lockowner { - struct list_head list; - refcount_t count; - struct nlm_host___2 *host; - fl_owner_t owner; - uint32_t pid; -}; - -struct nsm_handle; - -struct nlm_host___2 { - struct hlist_node h_hash; - struct __kernel_sockaddr_storage h_addr; - size_t h_addrlen; - struct __kernel_sockaddr_storage h_srcaddr; - size_t h_srcaddrlen; - struct rpc_clnt *h_rpcclnt; - char *h_name; - u32 h_version; - short unsigned int h_proto; - short unsigned int h_reclaiming: 1; - short unsigned int h_server: 1; - short unsigned int h_noresvport: 1; - short unsigned int h_inuse: 1; - wait_queue_head_t h_gracewait; - struct rw_semaphore h_rwsem; - u32 h_state; - u32 h_nsmstate; - u32 h_pidcount; - refcount_t h_count; - struct mutex h_mutex; - long unsigned int h_nextrebind; - long unsigned int h_expires; - struct list_head h_lockowners; - spinlock_t h_lock; - struct list_head h_granted; - struct list_head h_reclaim; - struct nsm_handle *h_nsmhandle; - char *h_addrbuf; - struct net *net; - const struct cred *h_cred; - char nodename[65]; - const struct nlmclnt_operations *h_nlmclnt_ops; -}; - -enum { - NLM_LCK_GRANTED = 0, - NLM_LCK_DENIED = 1, - NLM_LCK_DENIED_NOLOCKS = 2, - NLM_LCK_BLOCKED = 3, - NLM_LCK_DENIED_GRACE_PERIOD = 4, - NLM_DEADLCK = 5, - NLM_ROFS = 6, - NLM_STALE_FH = 7, - NLM_FBIG = 8, - NLM_FAILED = 9, -}; - -struct nsm_private { - unsigned char data[16]; -}; - -struct nlm_lock { - char *caller; - unsigned int len; - struct nfs_fh fh; - struct xdr_netobj oh; - u32 svid; - struct file_lock fl; -}; - -struct nlm_cookie { - unsigned char data[32]; - unsigned int len; -}; - -struct nlm_args { - struct nlm_cookie cookie; - struct nlm_lock lock; - u32 block; - u32 reclaim; - u32 state; - u32 monitor; - u32 fsm_access; - u32 fsm_mode; -}; - -struct nlm_res { - struct nlm_cookie cookie; - __be32 status; - struct nlm_lock lock; -}; - -struct nsm_handle { - struct list_head sm_link; - refcount_t sm_count; - char *sm_mon_name; - char *sm_name; - struct __kernel_sockaddr_storage sm_addr; - size_t sm_addrlen; - unsigned int sm_monitored: 1; - unsigned int sm_sticky: 1; - struct nsm_private sm_priv; - char sm_addrbuf[51]; -}; - -struct nlm_block; - -struct nlm_rqst { - refcount_t a_count; - unsigned int a_flags; - struct nlm_host___2 *a_host; - struct nlm_args a_args; - struct nlm_res a_res; - struct nlm_block *a_block; - unsigned int a_retries; - u8 a_owner[74]; - void *a_callback_data; -}; - -struct nlm_file; - -struct nlm_block { - struct kref b_count; - struct list_head b_list; - struct list_head b_flist; - struct nlm_rqst *b_call; - struct svc_serv *b_daemon; - struct nlm_host___2 *b_host; - long unsigned int b_when; - unsigned int b_id; - unsigned char b_granted; - struct nlm_file *b_file; - struct cache_req *b_cache_req; - struct cache_deferred_req *b_deferred_req; - unsigned int b_flags; -}; - -struct nlm_share; - -struct nlm_file { - struct hlist_node f_list; - struct nfs_fh f_handle; - struct file *f_file; - struct nlm_share *f_shares; - struct list_head f_blocks; - unsigned int f_locks; - unsigned int f_count; - struct mutex f_mutex; -}; - -struct nlm_wait { - struct list_head b_list; - wait_queue_head_t b_wait; - struct nlm_host___2 *b_host; - struct file_lock *b_lock; - short unsigned int b_reclaim; - __be32 b_status; -}; - -struct nlm_wait___2; - -struct nlm_reboot { - char *mon; - unsigned int len; - u32 state; - struct nsm_private priv; -}; - -struct lockd_net { - unsigned int nlmsvc_users; - long unsigned int next_gc; - long unsigned int nrhosts; - struct delayed_work grace_period_end; - struct lock_manager lockd_manager; - struct list_head nsm_handles; -}; - -struct nlm_lookup_host_info { - const int server; - const struct sockaddr *sap; - const size_t salen; - const short unsigned int protocol; - const u32 version; - const char *hostname; - const size_t hostname_len; - const int noresvport; - struct net *net; - const struct cred *cred; -}; - -struct ipv4_devconf { - void *sysctl; - int data[32]; - long unsigned int state[1]; -}; - -struct in_ifaddr; - -struct ip_mc_list; - -struct in_device { - struct net_device *dev; - refcount_t refcnt; - int dead; - struct in_ifaddr *ifa_list; - struct ip_mc_list *mc_list; - struct ip_mc_list **mc_hash; - int mc_count; - spinlock_t mc_tomb_lock; - struct ip_mc_list *mc_tomb; - long unsigned int mr_v1_seen; - long unsigned int mr_v2_seen; - long unsigned int mr_maxdelay; - long unsigned int mr_qi; - long unsigned int mr_qri; - unsigned char mr_qrv; - unsigned char mr_gq_running; - u32 mr_ifc_count; - struct timer_list mr_gq_timer; - struct timer_list mr_ifc_timer; - struct neigh_parms *arp_parms; - struct ipv4_devconf cnf; - struct callback_head callback_head; -}; - -struct in_ifaddr { - struct hlist_node hash; - struct in_ifaddr *ifa_next; - struct in_device *ifa_dev; - struct callback_head callback_head; - __be32 ifa_local; - __be32 ifa_address; - __be32 ifa_mask; - __u32 ifa_rt_priority; - __be32 ifa_broadcast; - unsigned char ifa_scope; - unsigned char ifa_prefixlen; - __u32 ifa_flags; - char ifa_label[16]; - __u32 ifa_valid_lft; - __u32 ifa_preferred_lft; - long unsigned int ifa_cstamp; - long unsigned int ifa_tstamp; -}; - -struct inet6_ifaddr { - struct in6_addr addr; - __u32 prefix_len; - __u32 rt_priority; - __u32 valid_lft; - __u32 prefered_lft; - refcount_t refcnt; - spinlock_t lock; - int state; - __u32 flags; - __u8 dad_probes; - __u8 stable_privacy_retry; - __u16 scope; - __u64 dad_nonce; - long unsigned int cstamp; - long unsigned int tstamp; - struct delayed_work dad_work; - struct inet6_dev *idev; - struct fib6_info *rt; - struct hlist_node addr_lst; - struct list_head if_list; - struct list_head tmp_list; - struct inet6_ifaddr *ifpub; - int regen_count; - bool tokenized; - struct callback_head rcu; - struct in6_addr peer_addr; -}; - -struct nlmsvc_binding { - __be32 (*fopen)(struct svc_rqst *, struct nfs_fh *, struct file **); - void (*fclose)(struct file *); -}; - -typedef int (*nlm_host_match_fn_t)(void *, struct nlm_host___2 *); - -struct nlm_share { - struct nlm_share *s_next; - struct nlm_host___2 *s_host; - struct nlm_file *s_file; - struct xdr_netobj s_owner; - u32 s_access; - u32 s_mode; -}; - -enum { - NSMPROC_NULL = 0, - NSMPROC_STAT = 1, - NSMPROC_MON = 2, - NSMPROC_UNMON = 3, - NSMPROC_UNMON_ALL = 4, - NSMPROC_SIMU_CRASH = 5, - NSMPROC_NOTIFY = 6, -}; - -struct nsm_args { - struct nsm_private *priv; - u32 prog; - u32 vers; - u32 proc; - char *mon_name; - const char *nodename; -}; - -struct nsm_res { - u32 status; - u32 state; -}; - -typedef u32 unicode_t; - -struct utf8_table { - int cmask; - int cval; - int shift; - long int lmask; - long int lval; -}; - -typedef unsigned int autofs_wqt_t; - -struct autofs_sb_info; - -struct autofs_info { - struct dentry *dentry; - struct inode *inode; - int flags; - struct completion expire_complete; - struct list_head active; - struct list_head expiring; - struct autofs_sb_info *sbi; - long unsigned int last_used; - int count; - kuid_t uid; - kgid_t gid; - struct callback_head rcu; -}; - -struct autofs_wait_queue; - -struct autofs_sb_info { - u32 magic; - int pipefd; - struct file *pipe; - struct pid *oz_pgrp; - int version; - int sub_version; - int min_proto; - int max_proto; - unsigned int flags; - long unsigned int exp_timeout; - unsigned int type; - struct super_block *sb; - struct mutex wq_mutex; - struct mutex pipe_mutex; - spinlock_t fs_lock; - struct autofs_wait_queue *queues; - spinlock_t lookup_lock; - struct list_head active_list; - struct list_head expiring_list; - struct callback_head rcu; -}; - -struct autofs_wait_queue { - wait_queue_head_t queue; - struct autofs_wait_queue *next; - autofs_wqt_t wait_queue_token; - struct qstr name; - u32 dev; - u64 ino; - kuid_t uid; - kgid_t gid; - pid_t pid; - pid_t tgid; - int status; - unsigned int wait_ctr; -}; - -enum { - Opt_err___4 = 0, - Opt_fd = 1, - Opt_uid___4 = 2, - Opt_gid___5 = 3, - Opt_pgrp = 4, - Opt_minproto = 5, - Opt_maxproto = 6, - Opt_indirect = 7, - Opt_direct = 8, - Opt_offset = 9, - Opt_strictexpire = 10, - Opt_ignore = 11, -}; - -enum { - AUTOFS_IOC_READY_CMD = 96, - AUTOFS_IOC_FAIL_CMD = 97, - AUTOFS_IOC_CATATONIC_CMD = 98, - AUTOFS_IOC_PROTOVER_CMD = 99, - AUTOFS_IOC_SETTIMEOUT_CMD = 100, - AUTOFS_IOC_EXPIRE_CMD = 101, -}; - -enum autofs_notify { - NFY_NONE = 0, - NFY_MOUNT = 1, - NFY_EXPIRE = 2, -}; - -enum { - AUTOFS_IOC_EXPIRE_MULTI_CMD = 102, - AUTOFS_IOC_PROTOSUBVER_CMD = 103, - AUTOFS_IOC_ASKUMOUNT_CMD = 112, -}; - -struct autofs_packet_hdr { - int proto_version; - int type; -}; - -struct autofs_packet_missing { - struct autofs_packet_hdr hdr; - autofs_wqt_t wait_queue_token; - int len; - char name[256]; -}; - -struct autofs_packet_expire { - struct autofs_packet_hdr hdr; - int len; - char name[256]; -}; - -struct autofs_packet_expire_multi { - struct autofs_packet_hdr hdr; - autofs_wqt_t wait_queue_token; - int len; - char name[256]; -}; - -union autofs_packet_union { - struct autofs_packet_hdr hdr; - struct autofs_packet_missing missing; - struct autofs_packet_expire expire; - struct autofs_packet_expire_multi expire_multi; -}; - -struct autofs_v5_packet { - struct autofs_packet_hdr hdr; - autofs_wqt_t wait_queue_token; - __u32 dev; - __u64 ino; - __u32 uid; - __u32 gid; - __u32 pid; - __u32 tgid; - __u32 len; - char name[256]; -}; - -typedef struct autofs_v5_packet autofs_packet_missing_indirect_t; - -typedef struct autofs_v5_packet autofs_packet_expire_indirect_t; - -typedef struct autofs_v5_packet autofs_packet_missing_direct_t; - -typedef struct autofs_v5_packet autofs_packet_expire_direct_t; - -union autofs_v5_packet_union { - struct autofs_packet_hdr hdr; - struct autofs_v5_packet v5_packet; - autofs_packet_missing_indirect_t missing_indirect; - autofs_packet_expire_indirect_t expire_indirect; - autofs_packet_missing_direct_t missing_direct; - autofs_packet_expire_direct_t expire_direct; -}; - -struct args_protover { - __u32 version; -}; - -struct args_protosubver { - __u32 sub_version; -}; - -struct args_openmount { - __u32 devid; -}; - -struct args_ready { - __u32 token; -}; - -struct args_fail { - __u32 token; - __s32 status; -}; - -struct args_setpipefd { - __s32 pipefd; -}; - -struct args_timeout { - __u64 timeout; -}; - -struct args_requester { - __u32 uid; - __u32 gid; -}; - -struct args_expire { - __u32 how; -}; - -struct args_askumount { - __u32 may_umount; -}; - -struct args_in { - __u32 type; -}; - -struct args_out { - __u32 devid; - __u32 magic; -}; - -struct args_ismountpoint { - union { - struct args_in in; - struct args_out out; - }; -}; - -struct autofs_dev_ioctl { - __u32 ver_major; - __u32 ver_minor; - __u32 size; - __s32 ioctlfd; - union { - struct args_protover protover; - struct args_protosubver protosubver; - struct args_openmount openmount; - struct args_ready ready; - struct args_fail fail; - struct args_setpipefd setpipefd; - struct args_timeout timeout; - struct args_requester requester; - struct args_expire expire; - struct args_askumount askumount; - struct args_ismountpoint ismountpoint; - }; - char path[0]; -}; - -enum { - AUTOFS_DEV_IOCTL_VERSION_CMD = 113, - AUTOFS_DEV_IOCTL_PROTOVER_CMD = 114, - AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD = 115, - AUTOFS_DEV_IOCTL_OPENMOUNT_CMD = 116, - AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD = 117, - AUTOFS_DEV_IOCTL_READY_CMD = 118, - AUTOFS_DEV_IOCTL_FAIL_CMD = 119, - AUTOFS_DEV_IOCTL_SETPIPEFD_CMD = 120, - AUTOFS_DEV_IOCTL_CATATONIC_CMD = 121, - AUTOFS_DEV_IOCTL_TIMEOUT_CMD = 122, - AUTOFS_DEV_IOCTL_REQUESTER_CMD = 123, - AUTOFS_DEV_IOCTL_EXPIRE_CMD = 124, - AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD = 125, - AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD = 126, -}; - -typedef int (*ioctl_fn)(struct file *, struct autofs_sb_info *, struct autofs_dev_ioctl *); - -struct cachefiles_lookup_data; - -struct cachefiles_object { - struct fscache_object fscache; - struct cachefiles_lookup_data *lookup_data; - struct dentry *dentry; - struct dentry *backer; - loff_t i_size; - long unsigned int flags; - atomic_t usage; - uint8_t type; - uint8_t new; - spinlock_t work_lock; - struct rb_node active_node; -}; - -struct cachefiles_cache { - struct fscache_cache cache; - struct vfsmount *mnt; - struct dentry *graveyard; - struct file *cachefilesd; - const struct cred *cache_cred; - struct mutex daemon_mutex; - wait_queue_head_t daemon_pollwq; - struct rb_root active_nodes; - rwlock_t active_lock; - atomic_t gravecounter; - atomic_t f_released; - atomic_long_t b_released; - unsigned int frun_percent; - unsigned int fcull_percent; - unsigned int fstop_percent; - unsigned int brun_percent; - unsigned int bcull_percent; - unsigned int bstop_percent; - unsigned int bsize; - unsigned int bshift; - uint64_t frun; - uint64_t fcull; - uint64_t fstop; - sector_t brun; - sector_t bcull; - sector_t bstop; - long unsigned int flags; - char *rootdirname; - char *secctx; - char *tag; -}; - -struct cachefiles_daemon_cmd { - char name[8]; - int (*handler)(struct cachefiles_cache *, char *); -}; - -struct cachefiles_xattr; - -struct cachefiles_lookup_data { - struct cachefiles_xattr *auxdata; - char *key; -}; - -struct cachefiles_xattr { - uint16_t len; - uint8_t type; - uint8_t data[0]; -}; - -enum cachefiles_obj_ref_trace { - cachefiles_obj_put_wait_retry = 8, - cachefiles_obj_put_wait_timeo = 9, - cachefiles_obj_ref__nr_traces = 10, -}; - -struct trace_event_raw_cachefiles_ref { - struct trace_entry ent; - struct cachefiles_object *obj; - struct fscache_cookie *cookie; - enum cachefiles_obj_ref_trace why; - int usage; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_lookup { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - struct inode *inode; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_mkdir { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - int ret; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_create { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - int ret; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_unlink { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - enum fscache_why_object_killed why; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_rename { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - struct dentry *to; - enum fscache_why_object_killed why; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_mark_active { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_wait_active { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - struct cachefiles_object *xobj; - u16 flags; - u16 fsc_flags; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_mark_inactive { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - struct inode *inode; - char __data[0]; -}; - -struct trace_event_raw_cachefiles_mark_buried { - struct trace_entry ent; - struct cachefiles_object *obj; - struct dentry *de; - enum fscache_why_object_killed why; - char __data[0]; -}; - -struct trace_event_data_offsets_cachefiles_ref {}; - -struct trace_event_data_offsets_cachefiles_lookup {}; - -struct trace_event_data_offsets_cachefiles_mkdir {}; - -struct trace_event_data_offsets_cachefiles_create {}; - -struct trace_event_data_offsets_cachefiles_unlink {}; - -struct trace_event_data_offsets_cachefiles_rename {}; - -struct trace_event_data_offsets_cachefiles_mark_active {}; - -struct trace_event_data_offsets_cachefiles_wait_active {}; - -struct trace_event_data_offsets_cachefiles_mark_inactive {}; - -struct trace_event_data_offsets_cachefiles_mark_buried {}; - -typedef void (*btf_trace_cachefiles_ref)(void *, struct cachefiles_object *, struct fscache_cookie *, enum cachefiles_obj_ref_trace, int); - -typedef void (*btf_trace_cachefiles_lookup)(void *, struct cachefiles_object *, struct dentry *, struct inode *); - -typedef void (*btf_trace_cachefiles_mkdir)(void *, struct cachefiles_object *, struct dentry *, int); - -typedef void (*btf_trace_cachefiles_create)(void *, struct cachefiles_object *, struct dentry *, int); - -typedef void (*btf_trace_cachefiles_unlink)(void *, struct cachefiles_object *, struct dentry *, enum fscache_why_object_killed); - -typedef void (*btf_trace_cachefiles_rename)(void *, struct cachefiles_object *, struct dentry *, struct dentry *, enum fscache_why_object_killed); - -typedef void (*btf_trace_cachefiles_mark_active)(void *, struct cachefiles_object *, struct dentry *); - -typedef void (*btf_trace_cachefiles_wait_active)(void *, struct cachefiles_object *, struct dentry *, struct cachefiles_object *); - -typedef void (*btf_trace_cachefiles_mark_inactive)(void *, struct cachefiles_object *, struct dentry *, struct inode *); - -typedef void (*btf_trace_cachefiles_mark_buried)(void *, struct cachefiles_object *, struct dentry *, enum fscache_why_object_killed); - -struct cachefiles_one_read { - wait_queue_entry_t monitor; - struct page *back_page; - struct page *netfs_page; - struct fscache_retrieval *op; - struct list_head op_link; -}; - -typedef struct vfsmount * (*debugfs_automount_t)(struct dentry *, void *); - -struct debugfs_fsdata { - const struct file_operations *real_fops; - refcount_t active_users; - struct completion active_users_drained; -}; - -struct debugfs_mount_opts { - kuid_t uid; - kgid_t gid; - umode_t mode; -}; - -enum { - Opt_uid___5 = 0, - Opt_gid___6 = 1, - Opt_mode___4 = 2, - Opt_err___5 = 3, -}; - -struct debugfs_fs_info { - struct debugfs_mount_opts mount_opts; -}; - -struct debugfs_blob_wrapper { - void *data; - long unsigned int size; -}; - -struct debugfs_reg32 { - char *name; - long unsigned int offset; -}; - -struct debugfs_regset32 { - const struct debugfs_reg32 *regs; - int nregs; - void *base; - struct device *dev; -}; - -struct debugfs_u32_array { - u32 *array; - u32 n_elements; -}; - -struct debugfs_devm_entry { - int (*read)(struct seq_file *, void *); - struct device *dev; -}; - -struct tracefs_dir_ops { - int (*mkdir)(const char *); - int (*rmdir)(const char *); -}; - -struct tracefs_mount_opts { - kuid_t uid; - kgid_t gid; - umode_t mode; -}; - -struct tracefs_fs_info { - struct tracefs_mount_opts mount_opts; -}; - -struct f2fs_device { - __u8 path[64]; - __le32 total_segments; -}; - -struct f2fs_super_block { - __le32 magic; - __le16 major_ver; - __le16 minor_ver; - __le32 log_sectorsize; - __le32 log_sectors_per_block; - __le32 log_blocksize; - __le32 log_blocks_per_seg; - __le32 segs_per_sec; - __le32 secs_per_zone; - __le32 checksum_offset; - __le64 block_count; - __le32 section_count; - __le32 segment_count; - __le32 segment_count_ckpt; - __le32 segment_count_sit; - __le32 segment_count_nat; - __le32 segment_count_ssa; - __le32 segment_count_main; - __le32 segment0_blkaddr; - __le32 cp_blkaddr; - __le32 sit_blkaddr; - __le32 nat_blkaddr; - __le32 ssa_blkaddr; - __le32 main_blkaddr; - __le32 root_ino; - __le32 node_ino; - __le32 meta_ino; - __u8 uuid[16]; - __le16 volume_name[512]; - __le32 extension_count; - __u8 extension_list[512]; - __le32 cp_payload; - __u8 version[256]; - __u8 init_version[256]; - __le32 feature; - __u8 encryption_level; - __u8 encrypt_pw_salt[16]; - struct f2fs_device devs[8]; - __le32 qf_ino[3]; - __u8 hot_ext_count; - __le16 s_encoding; - __le16 s_encoding_flags; - __u8 reserved[306]; - __le32 crc; -} __attribute__((packed)); - -struct f2fs_checkpoint { - __le64 checkpoint_ver; - __le64 user_block_count; - __le64 valid_block_count; - __le32 rsvd_segment_count; - __le32 overprov_segment_count; - __le32 free_segment_count; - __le32 cur_node_segno[8]; - __le16 cur_node_blkoff[8]; - __le32 cur_data_segno[8]; - __le16 cur_data_blkoff[8]; - __le32 ckpt_flags; - __le32 cp_pack_total_block_count; - __le32 cp_pack_start_sum; - __le32 valid_node_count; - __le32 valid_inode_count; - __le32 next_free_nid; - __le32 sit_ver_bitmap_bytesize; - __le32 nat_ver_bitmap_bytesize; - __le32 checksum_offset; - __le64 elapsed_time; - unsigned char alloc_type[16]; - unsigned char sit_nat_version_bitmap[1]; -} __attribute__((packed)); - -struct f2fs_extent { - __le32 fofs; - __le32 blk; - __le32 len; -}; - -struct f2fs_inode { - __le16 i_mode; - __u8 i_advise; - __u8 i_inline; - __le32 i_uid; - __le32 i_gid; - __le32 i_links; - __le64 i_size; - __le64 i_blocks; - __le64 i_atime; - __le64 i_ctime; - __le64 i_mtime; - __le32 i_atime_nsec; - __le32 i_ctime_nsec; - __le32 i_mtime_nsec; - __le32 i_generation; - union { - __le32 i_current_depth; - __le16 i_gc_failures; - }; - __le32 i_xattr_nid; - __le32 i_flags; - __le32 i_pino; - __le32 i_namelen; - __u8 i_name[255]; - __u8 i_dir_level; - struct f2fs_extent i_ext; - union { - struct { - __le16 i_extra_isize; - __le16 i_inline_xattr_size; - __le32 i_projid; - __le32 i_inode_checksum; - __le64 i_crtime; - __le32 i_crtime_nsec; - __le64 i_compr_blocks; - __u8 i_compress_algorithm; - __u8 i_log_cluster_size; - __le16 i_padding; - __le32 i_extra_end[0]; - } __attribute__((packed)); - __le32 i_addr[923]; - }; - __le32 i_nid[5]; -}; - -struct direct_node { - __le32 addr[1018]; -}; - -struct indirect_node { - __le32 nid[1018]; -}; - -struct node_footer { - __le32 nid; - __le32 ino; - __le32 flag; - __le64 cp_ver; - __le32 next_blkaddr; -} __attribute__((packed)); - -struct f2fs_node { - union { - struct f2fs_inode i; - struct direct_node dn; - struct indirect_node in; - }; - struct node_footer footer; -}; - -typedef __le32 f2fs_hash_t; - -struct f2fs_dir_entry { - __le32 hash_code; - __le32 ino; - __le16 name_len; - __u8 file_type; -} __attribute__((packed)); - -struct f2fs_dentry_block { - __u8 dentry_bitmap[27]; - __u8 reserved[3]; - struct f2fs_dir_entry dentry[214]; - __u8 filename[1712]; -} __attribute__((packed)); - -enum { - F2FS_FT_UNKNOWN = 0, - F2FS_FT_REG_FILE = 1, - F2FS_FT_DIR = 2, - F2FS_FT_CHRDEV = 3, - F2FS_FT_BLKDEV = 4, - F2FS_FT_FIFO = 5, - F2FS_FT_SOCK = 6, - F2FS_FT_SYMLINK = 7, - F2FS_FT_MAX = 8, -}; - -enum { - FAULT_KMALLOC = 0, - FAULT_KVMALLOC = 1, - FAULT_PAGE_ALLOC = 2, - FAULT_PAGE_GET = 3, - FAULT_ALLOC_BIO = 4, - FAULT_ALLOC_NID = 5, - FAULT_ORPHAN = 6, - FAULT_BLOCK = 7, - FAULT_DIR_DEPTH = 8, - FAULT_EVICT_INODE = 9, - FAULT_TRUNCATE = 10, - FAULT_READ_IO = 11, - FAULT_CHECKPOINT = 12, - FAULT_DISCARD = 13, - FAULT_WRITE_IO = 14, - FAULT_MAX = 15, -}; - -typedef u32 block_t; - -typedef u32 nid_t; - -struct f2fs_mount_info { - unsigned int opt; - int write_io_size_bits; - block_t root_reserved_blocks; - kuid_t s_resuid; - kgid_t s_resgid; - int active_logs; - int inline_xattr_size; - char *s_qf_names[3]; - int s_jquota_fmt; - int whint_mode; - int alloc_mode; - int fsync_mode; - int fs_mode; - int bggc_mode; - struct fscrypt_dummy_policy dummy_enc_policy; - block_t unusable_cap_perc; - block_t unusable_cap; - unsigned char compress_algorithm; - unsigned int compress_log_size; - unsigned char compress_ext_cnt; - unsigned char extensions[128]; -}; - -enum { - META_CP = 0, - META_NAT = 1, - META_SIT = 2, - META_SSA = 3, - META_MAX = 4, - META_POR = 5, - DATA_GENERIC = 6, - DATA_GENERIC_ENHANCE = 7, - DATA_GENERIC_ENHANCE_READ = 8, - META_GENERIC = 9, -}; - -enum { - ORPHAN_INO = 0, - APPEND_INO = 1, - UPDATE_INO = 2, - TRANS_DIR_INO = 3, - FLUSH_INO = 4, - MAX_INO_ENTRY = 5, -}; - -struct discard_cmd_control { - struct task_struct *f2fs_issue_discard; - struct list_head entry_list; - struct list_head pend_list[512]; - struct list_head wait_list; - struct list_head fstrim_list; - wait_queue_head_t discard_wait_queue; - unsigned int discard_wake; - struct mutex cmd_lock; - unsigned int nr_discards; - unsigned int max_discards; - unsigned int discard_granularity; - unsigned int undiscard_blks; - unsigned int next_pos; - atomic_t issued_discard; - atomic_t queued_discard; - atomic_t discard_cmd_cnt; - struct rb_root_cached root; - bool rbtree_check; -}; - -struct f2fs_filename { - const struct qstr *usr_fname; - struct fscrypt_str disk_name; - f2fs_hash_t hash; - struct fscrypt_str crypto_buf; -}; - -struct f2fs_dentry_ptr { - struct inode *inode; - void *bitmap; - struct f2fs_dir_entry *dentry; - __u8 (*filename)[8]; - int max; - int nr_bitmap; -}; - -struct extent_info { - unsigned int fofs; - unsigned int len; - u32 blk; -}; - -struct extent_tree; - -struct extent_node { - struct rb_node rb_node; - struct extent_info ei; - struct list_head list; - struct extent_tree *et; -}; - -struct extent_tree { - nid_t ino; - struct rb_root_cached root; - struct extent_node *cached_en; - struct extent_info largest; - struct list_head list; - rwlock_t lock; - atomic_t node_cnt; - bool largest_updated; -}; - -enum { - GC_FAILURE_PIN = 0, - GC_FAILURE_ATOMIC = 1, - MAX_GC_FAILURE = 2, -}; - -enum { - FI_NEW_INODE = 0, - FI_DIRTY_INODE = 1, - FI_AUTO_RECOVER = 2, - FI_DIRTY_DIR = 3, - FI_INC_LINK = 4, - FI_ACL_MODE = 5, - FI_NO_ALLOC = 6, - FI_FREE_NID = 7, - FI_NO_EXTENT = 8, - FI_INLINE_XATTR = 9, - FI_INLINE_DATA = 10, - FI_INLINE_DENTRY = 11, - FI_APPEND_WRITE = 12, - FI_UPDATE_WRITE = 13, - FI_NEED_IPU = 14, - FI_ATOMIC_FILE = 15, - FI_ATOMIC_COMMIT = 16, - FI_VOLATILE_FILE = 17, - FI_FIRST_BLOCK_WRITTEN = 18, - FI_DROP_CACHE = 19, - FI_DATA_EXIST = 20, - FI_INLINE_DOTS = 21, - FI_DO_DEFRAG = 22, - FI_DIRTY_FILE = 23, - FI_NO_PREALLOC = 24, - FI_HOT_DATA = 25, - FI_EXTRA_ATTR = 26, - FI_PROJ_INHERIT = 27, - FI_PIN_FILE = 28, - FI_ATOMIC_REVOKE_REQUEST = 29, - FI_VERITY_IN_PROGRESS = 30, - FI_COMPRESSED_FILE = 31, - FI_MMAP_FILE = 32, - FI_MAX = 33, -}; - -struct f2fs_inode_info { - struct inode vfs_inode; - long unsigned int i_flags; - unsigned char i_advise; - unsigned char i_dir_level; - unsigned int i_current_depth; - unsigned int i_gc_failures[2]; - unsigned int i_pino; - umode_t i_acl_mode; - long unsigned int flags[1]; - struct rw_semaphore i_sem; - atomic_t dirty_pages; - f2fs_hash_t chash; - unsigned int clevel; - struct task_struct *task; - struct task_struct *cp_task; - nid_t i_xattr_nid; - loff_t last_disk_size; - spinlock_t i_size_lock; - struct dquot *i_dquot[3]; - qsize_t i_reserved_quota; - struct list_head dirty_list; - struct list_head gdirty_list; - struct list_head inmem_ilist; - struct list_head inmem_pages; - struct task_struct *inmem_task; - struct mutex inmem_lock; - long unsigned int ra_offset; - struct extent_tree *extent_tree; - struct rw_semaphore i_gc_rwsem[2]; - struct rw_semaphore i_mmap_sem; - struct rw_semaphore i_xattr_sem; - int i_extra_isize; - kprojid_t i_projid; - int i_inline_xattr_size; - struct timespec64 i_crtime; - struct timespec64 i_disk_time[4]; - atomic_t i_compr_blocks; - unsigned char i_compress_algorithm; - unsigned char i_log_cluster_size; - unsigned int i_cluster_size; -}; - -enum nid_state { - FREE_NID = 0, - PREALLOC_NID = 1, - MAX_NID_STATE = 2, -}; - -enum nat_state { - TOTAL_NAT = 0, - DIRTY_NAT = 1, - RECLAIMABLE_NAT = 2, - MAX_NAT_STATE = 3, -}; - -struct f2fs_nm_info { - block_t nat_blkaddr; - nid_t max_nid; - nid_t available_nids; - nid_t next_scan_nid; - unsigned int ram_thresh; - unsigned int ra_nid_pages; - unsigned int dirty_nats_ratio; - struct xarray nat_root; - struct xarray nat_set_root; - struct rw_semaphore nat_tree_lock; - struct list_head nat_entries; - spinlock_t nat_list_lock; - unsigned int nat_cnt[3]; - unsigned int nat_blocks; - struct xarray free_nid_root; - struct list_head free_nid_list; - unsigned int nid_cnt[2]; - spinlock_t nid_list_lock; - struct mutex build_lock; - unsigned char **free_nid_bitmap; - unsigned char *nat_block_bitmap; - short unsigned int *free_nid_count; - char *nat_bitmap; - unsigned int nat_bits_blocks; - unsigned char *nat_bits; - unsigned char *full_nat_bits; - unsigned char *empty_nat_bits; - int bitmap_size; -}; - -struct flush_cmd_control { - struct task_struct *f2fs_issue_flush; - wait_queue_head_t flush_wait_queue; - atomic_t issued_flush; - atomic_t queued_flush; - struct llist_head issue_list; - struct llist_node *dispatch_list; -}; - -struct sit_info; - -struct free_segmap_info; - -struct dirty_seglist_info; - -struct curseg_info; - -struct f2fs_sm_info { - struct sit_info *sit_info; - struct free_segmap_info *free_info; - struct dirty_seglist_info *dirty_info; - struct curseg_info *curseg_array; - struct rw_semaphore curseg_lock; - block_t seg0_blkaddr; - block_t main_blkaddr; - block_t ssa_blkaddr; - unsigned int segment_count; - unsigned int main_segments; - unsigned int reserved_segments; - unsigned int ovp_segments; - unsigned int rec_prefree_segments; - unsigned int trim_sections; - struct list_head sit_entry_set; - unsigned int ipu_policy; - unsigned int min_ipu_util; - unsigned int min_fsync_blocks; - unsigned int min_seq_blocks; - unsigned int min_hot_blocks; - unsigned int min_ssr_sections; - struct flush_cmd_control *fcc_info; - struct discard_cmd_control *dcc_info; -}; - -enum count_type { - F2FS_DIRTY_DENTS = 0, - F2FS_DIRTY_DATA = 1, - F2FS_DIRTY_QDATA = 2, - F2FS_DIRTY_NODES = 3, - F2FS_DIRTY_META = 4, - F2FS_INMEM_PAGES = 5, - F2FS_DIRTY_IMETA = 6, - F2FS_WB_CP_DATA = 7, - F2FS_WB_DATA = 8, - F2FS_RD_DATA = 9, - F2FS_RD_NODE = 10, - F2FS_RD_META = 11, - F2FS_DIO_WRITE = 12, - F2FS_DIO_READ = 13, - NR_COUNT_TYPE = 14, -}; - -enum page_type { - DATA = 0, - NODE = 1, - META = 2, - NR_PAGE_TYPE = 3, - META_FLUSH = 4, - INMEM = 5, - INMEM_DROP = 6, - INMEM_INVALIDATE = 7, - INMEM_REVOKE = 8, - IPU = 9, - OPU = 10, -}; - -enum temp_type { - HOT = 0, - WARM = 1, - COLD = 2, - NR_TEMP_TYPE = 3, -}; - -enum iostat_type { - APP_DIRECT_IO = 0, - APP_BUFFERED_IO = 1, - APP_WRITE_IO = 2, - APP_MAPPED_IO = 3, - FS_DATA_IO = 4, - FS_NODE_IO = 5, - FS_META_IO = 6, - FS_GC_DATA_IO = 7, - FS_GC_NODE_IO = 8, - FS_CP_DATA_IO = 9, - FS_CP_NODE_IO = 10, - FS_CP_META_IO = 11, - APP_DIRECT_READ_IO = 12, - APP_BUFFERED_READ_IO = 13, - APP_READ_IO = 14, - APP_MAPPED_READ_IO = 15, - FS_DATA_READ_IO = 16, - FS_GDATA_READ_IO = 17, - FS_CDATA_READ_IO = 18, - FS_NODE_READ_IO = 19, - FS_META_READ_IO = 20, - FS_DISCARD = 21, - NR_IO_TYPE = 22, -}; - -struct f2fs_sb_info; - -struct f2fs_io_info { - struct f2fs_sb_info *sbi; - nid_t ino; - enum page_type type; - enum temp_type temp; - int op; - int op_flags; - block_t new_blkaddr; - block_t old_blkaddr; - struct page *page; - struct page *encrypted_page; - struct page *compressed_page; - struct list_head list; - bool submitted; - int need_lock; - bool in_list; - bool is_por; - bool retry; - int compr_blocks; - bool encrypted; - enum iostat_type io_type; - struct writeback_control *io_wbc; - struct bio **bio; - sector_t *last_block; - unsigned char version; -}; - -struct inode_management { - struct xarray ino_root; - spinlock_t ino_lock; - struct list_head ino_list; - long unsigned int ino_num; -}; - -struct atgc_management { - bool atgc_enabled; - struct rb_root_cached root; - struct list_head victim_list; - unsigned int victim_count; - unsigned int candidate_ratio; - unsigned int max_candidate_count; - unsigned int age_weight; - long long unsigned int age_threshold; -}; - -struct f2fs_bio_info; - -struct f2fs_gc_kthread; - -struct f2fs_stat_info; - -struct f2fs_dev_info; - -struct f2fs_sb_info { - struct super_block *sb; - struct proc_dir_entry *s_proc; - struct f2fs_super_block *raw_super; - struct rw_semaphore sb_lock; - int valid_super_block; - long unsigned int s_flag; - struct mutex writepages; - struct f2fs_nm_info *nm_info; - struct inode *node_inode; - struct f2fs_sm_info *sm_info; - struct f2fs_bio_info *write_io[3]; - struct rw_semaphore io_order_lock; - mempool_t *write_io_dummy; - struct f2fs_checkpoint *ckpt; - int cur_cp_pack; - spinlock_t cp_lock; - struct inode *meta_inode; - struct mutex cp_mutex; - struct rw_semaphore cp_rwsem; - struct rw_semaphore node_write; - struct rw_semaphore node_change; - wait_queue_head_t cp_wait; - long unsigned int last_time[6]; - long int interval_time[6]; - struct inode_management im[5]; - spinlock_t fsync_node_lock; - struct list_head fsync_node_list; - unsigned int fsync_seg_id; - unsigned int fsync_node_num; - unsigned int max_orphans; - struct list_head inode_list[4]; - spinlock_t inode_lock[4]; - struct mutex flush_lock; - struct xarray extent_tree_root; - struct mutex extent_tree_lock; - struct list_head extent_list; - spinlock_t extent_lock; - atomic_t total_ext_tree; - struct list_head zombie_list; - atomic_t total_zombie_tree; - atomic_t total_ext_node; - unsigned int log_sectors_per_block; - unsigned int log_blocksize; - unsigned int blocksize; - unsigned int root_ino_num; - unsigned int node_ino_num; - unsigned int meta_ino_num; - unsigned int log_blocks_per_seg; - unsigned int blocks_per_seg; - unsigned int segs_per_sec; - unsigned int secs_per_zone; - unsigned int total_sections; - unsigned int total_node_count; - unsigned int total_valid_node_count; - loff_t max_file_blocks; - int dir_level; - int readdir_ra; - block_t user_block_count; - block_t total_valid_block_count; - block_t discard_blks; - block_t last_valid_block_count; - block_t reserved_blocks; - block_t current_reserved_blocks; - block_t unusable_block_count; - unsigned int nquota_files; - struct rw_semaphore quota_sem; - atomic_t nr_pages[14]; - struct percpu_counter alloc_valid_block_count; - atomic_t wb_sync_req[2]; - struct percpu_counter total_valid_inode_count; - struct f2fs_mount_info mount_opt; - struct rw_semaphore gc_lock; - struct f2fs_gc_kthread *gc_thread; - struct atgc_management am; - unsigned int cur_victim_sec; - unsigned int gc_mode; - unsigned int next_victim_seg[2]; - unsigned int atomic_files; - long long unsigned int skipped_atomic_files[2]; - long long unsigned int skipped_gc_rwsem; - u64 gc_pin_file_threshold; - struct rw_semaphore pin_sem; - unsigned int max_victim_search; - unsigned int migration_granularity; - struct f2fs_stat_info *stat_info; - atomic_t meta_count[4]; - unsigned int segment_count[2]; - unsigned int block_count[2]; - atomic_t inplace_count; - atomic64_t total_hit_ext; - atomic64_t read_hit_rbtree; - atomic64_t read_hit_largest; - atomic64_t read_hit_cached; - atomic_t inline_xattr; - atomic_t inline_inode; - atomic_t inline_dir; - atomic_t compr_inode; - atomic64_t compr_blocks; - atomic_t vw_cnt; - atomic_t max_aw_cnt; - atomic_t max_vw_cnt; - unsigned int io_skip_bggc; - unsigned int other_skip_bggc; - unsigned int ndirty_inode[4]; - spinlock_t stat_lock; - spinlock_t iostat_lock; - long long unsigned int rw_iostat[22]; - long long unsigned int prev_rw_iostat[22]; - bool iostat_enable; - long unsigned int iostat_next_period; - unsigned int iostat_period_ms; - unsigned int data_io_flag; - unsigned int node_io_flag; - struct kobject s_kobj; - struct completion s_kobj_unregister; - struct list_head s_list; - int s_ndevs; - struct f2fs_dev_info *devs; - unsigned int dirty_device; - spinlock_t dev_lock; - struct mutex umount_mutex; - unsigned int shrinker_run_no; - u64 sectors_written_start; - u64 kbytes_written; - struct crypto_shash *s_chksum_driver; - __u32 s_chksum_seed; - struct workqueue_struct *post_read_wq; - struct kmem_cache *inline_xattr_slab; - unsigned int inline_xattr_slab_size; -}; - -struct f2fs_bio_info { - struct f2fs_sb_info *sbi; - struct bio *bio; - sector_t last_block_in_bio; - struct f2fs_io_info fio; - struct rw_semaphore io_rwsem; - spinlock_t io_lock; - struct list_head io_list; - struct list_head bio_list; - struct rw_semaphore bio_list_lock; -}; - -struct f2fs_dev_info { - struct block_device *bdev; - char path[64]; - unsigned int total_segments; - block_t start_blk; - block_t end_blk; -}; - -enum inode_type { - DIR_INODE = 0, - FILE_INODE = 1, - DIRTY_META = 2, - ATOMIC_FILE = 3, - NR_INODE_TYPE = 4, -}; - -enum { - SBI_IS_DIRTY = 0, - SBI_IS_CLOSE = 1, - SBI_NEED_FSCK = 2, - SBI_POR_DOING = 3, - SBI_NEED_SB_WRITE = 4, - SBI_NEED_CP = 5, - SBI_IS_SHUTDOWN = 6, - SBI_IS_RECOVERED = 7, - SBI_CP_DISABLED = 8, - SBI_CP_DISABLED_QUICK = 9, - SBI_QUOTA_NEED_FLUSH = 10, - SBI_QUOTA_SKIP_FLUSH = 11, - SBI_QUOTA_NEED_REPAIR = 12, - SBI_IS_RESIZEFS = 13, -}; - -enum { - CP_TIME = 0, - REQ_TIME = 1, - DISCARD_TIME = 2, - GC_TIME = 3, - DISABLE_TIME = 4, - UMOUNT_DISCARD_TIMEOUT = 5, - MAX_TIME = 6, -}; - -enum fsync_mode { - FSYNC_MODE_POSIX = 0, - FSYNC_MODE_STRICT = 1, - FSYNC_MODE_NOBARRIER = 2, -}; - -struct f2fs_stat_info { - struct list_head stat_list; - struct f2fs_sb_info *sbi; - int all_area_segs; - int sit_area_segs; - int nat_area_segs; - int ssa_area_segs; - int main_area_segs; - int main_area_sections; - int main_area_zones; - long long unsigned int hit_largest; - long long unsigned int hit_cached; - long long unsigned int hit_rbtree; - long long unsigned int hit_total; - long long unsigned int total_ext; - int ext_tree; - int zombie_tree; - int ext_node; - int ndirty_node; - int ndirty_dent; - int ndirty_meta; - int ndirty_imeta; - int ndirty_data; - int ndirty_qdata; - int inmem_pages; - unsigned int ndirty_dirs; - unsigned int ndirty_files; - unsigned int nquota_files; - unsigned int ndirty_all; - int nats; - int dirty_nats; - int sits; - int dirty_sits; - int free_nids; - int avail_nids; - int alloc_nids; - int total_count; - int utilization; - int bg_gc; - int nr_wb_cp_data; - int nr_wb_data; - int nr_rd_data; - int nr_rd_node; - int nr_rd_meta; - int nr_dio_read; - int nr_dio_write; - unsigned int io_skip_bggc; - unsigned int other_skip_bggc; - int nr_flushing; - int nr_flushed; - int flush_list_empty; - int nr_discarding; - int nr_discarded; - int nr_discard_cmd; - unsigned int undiscard_blks; - int inline_xattr; - int inline_inode; - int inline_dir; - int append; - int update; - int orphans; - int compr_inode; - long long unsigned int compr_blocks; - int aw_cnt; - int max_aw_cnt; - int vw_cnt; - int max_vw_cnt; - unsigned int valid_count; - unsigned int valid_node_count; - unsigned int valid_inode_count; - unsigned int discard_blks; - unsigned int bimodal; - unsigned int avg_vblocks; - int util_free; - int util_valid; - int util_invalid; - int rsvd_segs; - int overp_segs; - int dirty_count; - int node_pages; - int meta_pages; - int prefree_count; - int call_count; - int cp_count; - int bg_cp_count; - int tot_segs; - int node_segs; - int data_segs; - int free_segs; - int free_secs; - int bg_node_segs; - int bg_data_segs; - int tot_blks; - int data_blks; - int node_blks; - int bg_data_blks; - int bg_node_blks; - long long unsigned int skipped_atomic_files[2]; - int curseg[8]; - int cursec[8]; - int curzone[8]; - unsigned int dirty_seg[8]; - unsigned int full_seg[8]; - unsigned int valid_blks[8]; - unsigned int meta_count[4]; - unsigned int segment_count[2]; - unsigned int block_count[2]; - unsigned int inplace_count; - long long unsigned int base_mem; - long long unsigned int cache_mem; - long long unsigned int page_mem; -}; - -enum { - COLD_BIT_SHIFT = 0, - FSYNC_BIT_SHIFT = 1, - DENT_BIT_SHIFT = 2, - OFFSET_BIT_SHIFT = 3, -}; - -struct f2fs_nat_entry { - __u8 version; - __le32 ino; - __le32 block_addr; -} __attribute__((packed)); - -struct f2fs_sit_entry { - __le16 vblocks; - __u8 valid_map[64]; - __le64 mtime; -} __attribute__((packed)); - -struct f2fs_summary { - __le32 nid; - union { - __u8 reserved[3]; - struct { - __u8 version; - __le16 ofs_in_node; - } __attribute__((packed)); - }; -} __attribute__((packed)); - -struct summary_footer { - unsigned char entry_type; - __le32 check_sum; -} __attribute__((packed)); - -struct nat_journal_entry { - __le32 nid; - struct f2fs_nat_entry ne; -} __attribute__((packed)); - -struct nat_journal { - struct nat_journal_entry entries[38]; - __u8 reserved[11]; -} __attribute__((packed)); - -struct sit_journal_entry { - __le32 segno; - struct f2fs_sit_entry se; -} __attribute__((packed)); - -struct sit_journal { - struct sit_journal_entry entries[6]; - __u8 reserved[37]; -} __attribute__((packed)); - -struct f2fs_extra_info { - __le64 kbytes_written; - __u8 reserved[497]; -} __attribute__((packed)); - -struct f2fs_journal { - union { - __le16 n_nats; - __le16 n_sits; - }; - union { - struct nat_journal nat_j; - struct sit_journal sit_j; - struct f2fs_extra_info info; - }; -} __attribute__((packed)); - -struct f2fs_summary_block { - struct f2fs_summary entries[512]; - struct f2fs_journal journal; - struct summary_footer footer; -} __attribute__((packed)); - -enum { - ALLOC_NODE = 0, - LOOKUP_NODE = 1, - LOOKUP_NODE_RA = 2, -}; - -struct f2fs_map_blocks { - block_t m_pblk; - block_t m_lblk; - unsigned int m_len; - unsigned int m_flags; - long unsigned int *m_next_pgofs; - long unsigned int *m_next_extent; - int m_seg_type; - bool m_may_create; -}; - -enum { - F2FS_GET_BLOCK_DEFAULT = 0, - F2FS_GET_BLOCK_FIEMAP = 1, - F2FS_GET_BLOCK_BMAP = 2, - F2FS_GET_BLOCK_DIO = 3, - F2FS_GET_BLOCK_PRE_DIO = 4, - F2FS_GET_BLOCK_PRE_AIO = 5, - F2FS_GET_BLOCK_PRECACHE = 6, -}; - -struct dnode_of_data { - struct inode *inode; - struct page *inode_page; - struct page *node_page; - nid_t nid; - unsigned int ofs_in_node; - bool inode_page_locked; - bool node_changed; - char cur_level; - char max_level; - block_t data_blkaddr; -}; - -enum { - CURSEG_HOT_DATA = 0, - CURSEG_WARM_DATA = 1, - CURSEG_COLD_DATA = 2, - CURSEG_HOT_NODE = 3, - CURSEG_WARM_NODE = 4, - CURSEG_COLD_NODE = 5, - NR_PERSISTENT_LOG = 6, - CURSEG_COLD_DATA_PINNED = 6, - CURSEG_ALL_DATA_ATGC = 7, - NO_CHECK_TYPE = 8, -}; - -struct segment_allocation; - -struct seg_entry; - -struct sec_entry; - -struct sit_info { - const struct segment_allocation *s_ops; - block_t sit_base_addr; - block_t sit_blocks; - block_t written_valid_blocks; - char *bitmap; - char *sit_bitmap; - unsigned int bitmap_size; - long unsigned int *tmp_map; - long unsigned int *dirty_sentries_bitmap; - unsigned int dirty_sentries; - unsigned int sents_per_block; - struct rw_semaphore sentry_lock; - struct seg_entry *sentries; - struct sec_entry *sec_entries; - long long unsigned int elapsed_time; - long long unsigned int mounted_time; - long long unsigned int min_mtime; - long long unsigned int max_mtime; - long long unsigned int dirty_min_mtime; - long long unsigned int dirty_max_mtime; - unsigned int last_victim[5]; -}; - -struct free_segmap_info { - unsigned int start_segno; - unsigned int free_segments; - unsigned int free_sections; - spinlock_t segmap_lock; - long unsigned int *free_segmap; - long unsigned int *free_secmap; -}; - -struct victim_selection; - -struct dirty_seglist_info { - const struct victim_selection *v_ops; - long unsigned int *dirty_segmap[8]; - long unsigned int *dirty_secmap; - struct mutex seglist_lock; - int nr_dirty[8]; - long unsigned int *victim_secmap; -}; - -struct curseg_info { - struct mutex curseg_mutex; - struct f2fs_summary_block *sum_blk; - struct rw_semaphore journal_rwsem; - struct f2fs_journal *journal; - unsigned char alloc_type; - short unsigned int seg_type; - unsigned int segno; - short unsigned int next_blkoff; - unsigned int zone; - unsigned int next_segno; - bool inited; -}; - -enum cp_reason_type { - CP_NO_NEEDED = 0, - CP_NON_REGULAR = 1, - CP_COMPRESSED = 2, - CP_HARDLINK = 3, - CP_SB_NEED_CP = 4, - CP_WRONG_PINO = 5, - CP_NO_SPC_ROLL = 6, - CP_NODE_NEED_CP = 7, - CP_FASTBOOT_MODE = 8, - CP_SPEC_LOG_NUM = 9, - CP_RECOVER_DIR = 10, -}; - -enum { - FS_MODE_ADAPTIVE = 0, - FS_MODE_LFS = 1, -}; - -struct f2fs_gc_kthread { - struct task_struct *f2fs_gc_task; - wait_queue_head_t gc_wait_queue_head; - unsigned int urgent_sleep_time; - unsigned int min_sleep_time; - unsigned int max_sleep_time; - unsigned int no_gc_sleep_time; - unsigned int gc_wake; -}; - -struct node_info { - nid_t nid; - nid_t ino; - block_t blk_addr; - unsigned char version; - unsigned char flag; -}; - -enum { - GC_CB = 0, - GC_GREEDY = 1, - GC_AT = 2, - ALLOC_NEXT = 3, - FLUSH_DEVICE = 4, - MAX_GC_POLICY = 5, -}; - -struct seg_entry { - unsigned int type: 6; - unsigned int valid_blocks: 10; - unsigned int ckpt_valid_blocks: 10; - unsigned int padding: 6; - unsigned char *cur_valid_map; - unsigned char *ckpt_valid_map; - unsigned char *discard_map; - long long unsigned int mtime; -}; - -struct sec_entry { - unsigned int valid_blocks; -}; - -struct segment_allocation { - void (*allocate_segment)(struct f2fs_sb_info *, int, bool); -}; - -enum dirty_type { - DIRTY_HOT_DATA = 0, - DIRTY_WARM_DATA = 1, - DIRTY_COLD_DATA = 2, - DIRTY_HOT_NODE = 3, - DIRTY_WARM_NODE = 4, - DIRTY_COLD_NODE = 5, - DIRTY = 6, - PRE = 7, - NR_DIRTY_TYPE = 8, -}; - -struct victim_selection { - int (*get_victim)(struct f2fs_sb_info *, unsigned int *, int, int, char, long long unsigned int); -}; - -struct f2fs_gc_range { - __u32 sync; - __u64 start; - __u64 len; -}; - -struct f2fs_defragment { - __u64 start; - __u64 len; -}; - -struct f2fs_move_range { - __u32 dst_fd; - __u64 pos_in; - __u64 pos_out; - __u64 len; -}; - -struct f2fs_flush_device { - __u32 dev_num; - __u32 segments; -}; - -struct f2fs_sectrim_range { - __u64 start; - __u64 len; - __u64 flags; -}; - -struct compat_f2fs_gc_range { - u32 sync; - compat_u64 start; - compat_u64 len; -}; - -struct compat_f2fs_move_range { - u32 dst_fd; - compat_u64 pos_in; - compat_u64 pos_out; - compat_u64 len; -}; - -enum compress_algorithm_type { - COMPRESS_LZO = 0, - COMPRESS_LZ4 = 1, - COMPRESS_ZSTD = 2, - COMPRESS_LZORLE = 3, - COMPRESS_MAX = 4, -}; - -struct cp_control { - int reason; - __u64 trim_start; - __u64 trim_end; - __u64 trim_minlen; -}; - -enum { - BGGC_MODE_ON = 0, - BGGC_MODE_OFF = 1, - BGGC_MODE_SYNC = 2, -}; - -enum { - WHINT_MODE_OFF = 0, - WHINT_MODE_USER = 1, - WHINT_MODE_FS = 2, -}; - -enum { - ALLOC_MODE_DEFAULT = 0, - ALLOC_MODE_REUSE = 1, -}; - -enum { - LFS = 0, - SSR = 1, - AT_SSR = 2, -}; - -enum { - BG_GC = 0, - FG_GC = 1, - FORCE_FG_GC = 2, -}; - -struct victim_sel_policy { - int alloc_mode; - int gc_mode; - long unsigned int *dirty_bitmap; - unsigned int max_search; - unsigned int offset; - unsigned int ofs_unit; - unsigned int min_cost; - long long unsigned int oldest_age; - unsigned int min_segno; - long long unsigned int age; - long long unsigned int age_threshold; -}; - -enum { - F2FS_IPU_FORCE = 0, - F2FS_IPU_SSR = 1, - F2FS_IPU_UTIL = 2, - F2FS_IPU_SSR_UTIL = 3, - F2FS_IPU_FSYNC = 4, - F2FS_IPU_ASYNC = 5, - F2FS_IPU_NOCACHE = 6, -}; - -struct trace_event_raw_f2fs__inode { - struct trace_entry ent; - dev_t dev; - ino_t ino; - ino_t pino; - umode_t mode; - loff_t size; - unsigned int nlink; - blkcnt_t blocks; - __u8 advise; - char __data[0]; -}; - -struct trace_event_raw_f2fs__inode_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_sync_file_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int cp_reason; - int datasync; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_sync_fs { - struct trace_entry ent; - dev_t dev; - int dirty; - int wait; - char __data[0]; -}; - -struct trace_event_raw_f2fs_unlink_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t size; - blkcnt_t blocks; - const char *name; - char __data[0]; -}; - -struct trace_event_raw_f2fs_truncate_data_blocks_range { - struct trace_entry ent; - dev_t dev; - ino_t ino; - nid_t nid; - unsigned int ofs; - int free; - char __data[0]; -}; - -struct trace_event_raw_f2fs__truncate_op { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t size; - blkcnt_t blocks; - u64 from; - char __data[0]; -}; - -struct trace_event_raw_f2fs__truncate_node { - struct trace_entry ent; - dev_t dev; - ino_t ino; - nid_t nid; - block_t blk_addr; - char __data[0]; -}; - -struct trace_event_raw_f2fs_truncate_partial_nodes { - struct trace_entry ent; - dev_t dev; - ino_t ino; - nid_t nid[3]; - int depth; - int err; - char __data[0]; -}; - -struct trace_event_raw_f2fs_file_write_iter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int offset; - long unsigned int length; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_map_blocks { - struct trace_entry ent; - dev_t dev; - ino_t ino; - block_t m_lblk; - block_t m_pblk; - unsigned int m_len; - unsigned int m_flags; - int m_seg_type; - bool m_may_create; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_background_gc { - struct trace_entry ent; - dev_t dev; - unsigned int wait_ms; - unsigned int prefree; - unsigned int free; - char __data[0]; -}; - -struct trace_event_raw_f2fs_gc_begin { - struct trace_entry ent; - dev_t dev; - bool sync; - bool background; - long long int dirty_nodes; - long long int dirty_dents; - long long int dirty_imeta; - unsigned int free_sec; - unsigned int free_seg; - int reserved_seg; - unsigned int prefree_seg; - char __data[0]; -}; - -struct trace_event_raw_f2fs_gc_end { - struct trace_entry ent; - dev_t dev; - int ret; - int seg_freed; - int sec_freed; - long long int dirty_nodes; - long long int dirty_dents; - long long int dirty_imeta; - unsigned int free_sec; - unsigned int free_seg; - int reserved_seg; - unsigned int prefree_seg; - char __data[0]; -}; - -struct trace_event_raw_f2fs_get_victim { - struct trace_entry ent; - dev_t dev; - int type; - int gc_type; - int alloc_mode; - int gc_mode; - unsigned int victim; - unsigned int cost; - unsigned int ofs_unit; - unsigned int pre_victim; - unsigned int prefree; - unsigned int free; - char __data[0]; -}; - -struct trace_event_raw_f2fs_lookup_start { - struct trace_entry ent; - dev_t dev; - ino_t ino; - u32 __data_loc_name; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_f2fs_lookup_end { - struct trace_entry ent; - dev_t dev; - ino_t ino; - u32 __data_loc_name; - nid_t cino; - int err; - char __data[0]; -}; - -struct trace_event_raw_f2fs_readdir { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t start; - loff_t end; - int err; - char __data[0]; -}; - -struct trace_event_raw_f2fs_fallocate { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int mode; - loff_t offset; - loff_t len; - loff_t size; - blkcnt_t blocks; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_direct_IO_enter { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - long unsigned int len; - int rw; - char __data[0]; -}; - -struct trace_event_raw_f2fs_direct_IO_exit { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - long unsigned int len; - int rw; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_reserve_new_blocks { - struct trace_entry ent; - dev_t dev; - nid_t nid; - unsigned int ofs_in_node; - blkcnt_t count; - char __data[0]; -}; - -struct trace_event_raw_f2fs__submit_page_bio { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int index; - block_t old_blkaddr; - block_t new_blkaddr; - int op; - int op_flags; - int temp; - int type; - char __data[0]; -}; - -struct trace_event_raw_f2fs__bio { - struct trace_entry ent; - dev_t dev; - dev_t target; - int op; - int op_flags; - int type; - sector_t sector; - unsigned int size; - char __data[0]; -}; - -struct trace_event_raw_f2fs_write_begin { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - unsigned int len; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_f2fs_write_end { - struct trace_entry ent; - dev_t dev; - ino_t ino; - loff_t pos; - unsigned int len; - unsigned int copied; - char __data[0]; -}; - -struct trace_event_raw_f2fs__page { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int type; - int dir; - long unsigned int index; - int dirty; - int uptodate; - char __data[0]; -}; - -struct trace_event_raw_f2fs_filemap_fault { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int index; - long unsigned int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_writepages { - struct trace_entry ent; - dev_t dev; - ino_t ino; - int type; - int dir; - long int nr_to_write; - long int pages_skipped; - loff_t range_start; - loff_t range_end; - long unsigned int writeback_index; - int sync_mode; - char for_kupdate; - char for_background; - char tagged_writepages; - char for_reclaim; - char range_cyclic; - char for_sync; - char __data[0]; -}; - -struct trace_event_raw_f2fs_readpages { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int start; - unsigned int nrpage; - char __data[0]; -}; - -struct trace_event_raw_f2fs_write_checkpoint { - struct trace_entry ent; - dev_t dev; - int reason; - char *msg; - char __data[0]; -}; - -struct trace_event_raw_f2fs_discard { - struct trace_entry ent; - dev_t dev; - block_t blkstart; - block_t blklen; - char __data[0]; -}; - -struct trace_event_raw_f2fs_issue_reset_zone { - struct trace_entry ent; - dev_t dev; - block_t blkstart; - char __data[0]; -}; - -struct trace_event_raw_f2fs_issue_flush { - struct trace_entry ent; - dev_t dev; - unsigned int nobarrier; - unsigned int flush_merge; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_lookup_extent_tree_start { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int pgofs; - char __data[0]; -}; - -struct trace_event_raw_f2fs_lookup_extent_tree_end { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int pgofs; - unsigned int fofs; - u32 blk; - unsigned int len; - char __data[0]; -}; - -struct trace_event_raw_f2fs_update_extent_tree_range { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int pgofs; - u32 blk; - unsigned int len; - char __data[0]; -}; - -struct trace_event_raw_f2fs_shrink_extent_tree { - struct trace_entry ent; - dev_t dev; - unsigned int node_cnt; - unsigned int tree_cnt; - char __data[0]; -}; - -struct trace_event_raw_f2fs_destroy_extent_tree { - struct trace_entry ent; - dev_t dev; - ino_t ino; - unsigned int node_cnt; - char __data[0]; -}; - -struct trace_event_raw_f2fs_sync_dirty_inodes { - struct trace_entry ent; - dev_t dev; - int type; - s64 count; - char __data[0]; -}; - -struct trace_event_raw_f2fs_shutdown { - struct trace_entry ent; - dev_t dev; - unsigned int mode; - int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_zip_start { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int idx; - unsigned int size; - unsigned int algtype; - char __data[0]; -}; - -struct trace_event_raw_f2fs_zip_end { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int idx; - unsigned int size; - unsigned int ret; - char __data[0]; -}; - -struct trace_event_raw_f2fs_iostat { - struct trace_entry ent; - dev_t dev; - long long unsigned int app_dio; - long long unsigned int app_bio; - long long unsigned int app_wio; - long long unsigned int app_mio; - long long unsigned int fs_dio; - long long unsigned int fs_nio; - long long unsigned int fs_mio; - long long unsigned int fs_gc_dio; - long long unsigned int fs_gc_nio; - long long unsigned int fs_cp_dio; - long long unsigned int fs_cp_nio; - long long unsigned int fs_cp_mio; - long long unsigned int app_drio; - long long unsigned int app_brio; - long long unsigned int app_rio; - long long unsigned int app_mrio; - long long unsigned int fs_drio; - long long unsigned int fs_gdrio; - long long unsigned int fs_cdrio; - long long unsigned int fs_nrio; - long long unsigned int fs_mrio; - long long unsigned int fs_discard; - char __data[0]; -}; - -struct trace_event_raw_f2fs_bmap { - struct trace_entry ent; - dev_t dev; - ino_t ino; - sector_t lblock; - sector_t pblock; - char __data[0]; -}; - -struct trace_event_raw_f2fs_fiemap { - struct trace_entry ent; - dev_t dev; - ino_t ino; - sector_t lblock; - sector_t pblock; - long long unsigned int len; - unsigned int flags; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_f2fs__inode {}; - -struct trace_event_data_offsets_f2fs__inode_exit {}; - -struct trace_event_data_offsets_f2fs_sync_file_exit {}; - -struct trace_event_data_offsets_f2fs_sync_fs {}; - -struct trace_event_data_offsets_f2fs_unlink_enter {}; - -struct trace_event_data_offsets_f2fs_truncate_data_blocks_range {}; - -struct trace_event_data_offsets_f2fs__truncate_op {}; - -struct trace_event_data_offsets_f2fs__truncate_node {}; - -struct trace_event_data_offsets_f2fs_truncate_partial_nodes {}; - -struct trace_event_data_offsets_f2fs_file_write_iter {}; - -struct trace_event_data_offsets_f2fs_map_blocks {}; - -struct trace_event_data_offsets_f2fs_background_gc {}; - -struct trace_event_data_offsets_f2fs_gc_begin {}; - -struct trace_event_data_offsets_f2fs_gc_end {}; - -struct trace_event_data_offsets_f2fs_get_victim {}; - -struct trace_event_data_offsets_f2fs_lookup_start { - u32 name; -}; - -struct trace_event_data_offsets_f2fs_lookup_end { - u32 name; -}; - -struct trace_event_data_offsets_f2fs_readdir {}; - -struct trace_event_data_offsets_f2fs_fallocate {}; - -struct trace_event_data_offsets_f2fs_direct_IO_enter {}; - -struct trace_event_data_offsets_f2fs_direct_IO_exit {}; - -struct trace_event_data_offsets_f2fs_reserve_new_blocks {}; - -struct trace_event_data_offsets_f2fs__submit_page_bio {}; - -struct trace_event_data_offsets_f2fs__bio {}; - -struct trace_event_data_offsets_f2fs_write_begin {}; - -struct trace_event_data_offsets_f2fs_write_end {}; - -struct trace_event_data_offsets_f2fs__page {}; - -struct trace_event_data_offsets_f2fs_filemap_fault {}; - -struct trace_event_data_offsets_f2fs_writepages {}; - -struct trace_event_data_offsets_f2fs_readpages {}; - -struct trace_event_data_offsets_f2fs_write_checkpoint {}; - -struct trace_event_data_offsets_f2fs_discard {}; - -struct trace_event_data_offsets_f2fs_issue_reset_zone {}; - -struct trace_event_data_offsets_f2fs_issue_flush {}; - -struct trace_event_data_offsets_f2fs_lookup_extent_tree_start {}; - -struct trace_event_data_offsets_f2fs_lookup_extent_tree_end {}; - -struct trace_event_data_offsets_f2fs_update_extent_tree_range {}; - -struct trace_event_data_offsets_f2fs_shrink_extent_tree {}; - -struct trace_event_data_offsets_f2fs_destroy_extent_tree {}; - -struct trace_event_data_offsets_f2fs_sync_dirty_inodes {}; - -struct trace_event_data_offsets_f2fs_shutdown {}; - -struct trace_event_data_offsets_f2fs_zip_start {}; - -struct trace_event_data_offsets_f2fs_zip_end {}; - -struct trace_event_data_offsets_f2fs_iostat {}; - -struct trace_event_data_offsets_f2fs_bmap {}; - -struct trace_event_data_offsets_f2fs_fiemap {}; - -typedef void (*btf_trace_f2fs_sync_file_enter)(void *, struct inode *); - -typedef void (*btf_trace_f2fs_sync_file_exit)(void *, struct inode *, int, int, int); - -typedef void (*btf_trace_f2fs_sync_fs)(void *, struct super_block *, int); - -typedef void (*btf_trace_f2fs_iget)(void *, struct inode *); - -typedef void (*btf_trace_f2fs_iget_exit)(void *, struct inode *, int); - -typedef void (*btf_trace_f2fs_evict_inode)(void *, struct inode *); - -typedef void (*btf_trace_f2fs_new_inode)(void *, struct inode *, int); - -typedef void (*btf_trace_f2fs_unlink_enter)(void *, struct inode *, struct dentry *); - -typedef void (*btf_trace_f2fs_unlink_exit)(void *, struct inode *, int); - -typedef void (*btf_trace_f2fs_drop_inode)(void *, struct inode *, int); - -typedef void (*btf_trace_f2fs_truncate)(void *, struct inode *); - -typedef void (*btf_trace_f2fs_truncate_data_blocks_range)(void *, struct inode *, nid_t, unsigned int, int); - -typedef void (*btf_trace_f2fs_truncate_blocks_enter)(void *, struct inode *, u64); - -typedef void (*btf_trace_f2fs_truncate_blocks_exit)(void *, struct inode *, int); - -typedef void (*btf_trace_f2fs_truncate_inode_blocks_enter)(void *, struct inode *, u64); - -typedef void (*btf_trace_f2fs_truncate_inode_blocks_exit)(void *, struct inode *, int); - -typedef void (*btf_trace_f2fs_truncate_nodes_enter)(void *, struct inode *, nid_t, block_t); - -typedef void (*btf_trace_f2fs_truncate_nodes_exit)(void *, struct inode *, int); - -typedef void (*btf_trace_f2fs_truncate_node)(void *, struct inode *, nid_t, block_t); - -typedef void (*btf_trace_f2fs_truncate_partial_nodes)(void *, struct inode *, nid_t *, int, int); - -typedef void (*btf_trace_f2fs_file_write_iter)(void *, struct inode *, long unsigned int, long unsigned int, int); - -typedef void (*btf_trace_f2fs_map_blocks)(void *, struct inode *, struct f2fs_map_blocks *, int); - -typedef void (*btf_trace_f2fs_background_gc)(void *, struct super_block *, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_f2fs_gc_begin)(void *, struct super_block *, bool, bool, long long int, long long int, long long int, unsigned int, unsigned int, int, unsigned int); - -typedef void (*btf_trace_f2fs_gc_end)(void *, struct super_block *, int, int, int, long long int, long long int, long long int, unsigned int, unsigned int, int, unsigned int); - -typedef void (*btf_trace_f2fs_get_victim)(void *, struct super_block *, int, int, struct victim_sel_policy *, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_f2fs_lookup_start)(void *, struct inode *, struct dentry *, unsigned int); - -typedef void (*btf_trace_f2fs_lookup_end)(void *, struct inode *, struct dentry *, nid_t, int); - -typedef void (*btf_trace_f2fs_readdir)(void *, struct inode *, loff_t, loff_t, int); - -typedef void (*btf_trace_f2fs_fallocate)(void *, struct inode *, int, loff_t, loff_t, int); - -typedef void (*btf_trace_f2fs_direct_IO_enter)(void *, struct inode *, loff_t, long unsigned int, int); - -typedef void (*btf_trace_f2fs_direct_IO_exit)(void *, struct inode *, loff_t, long unsigned int, int, int); - -typedef void (*btf_trace_f2fs_reserve_new_blocks)(void *, struct inode *, nid_t, unsigned int, blkcnt_t); - -typedef void (*btf_trace_f2fs_submit_page_bio)(void *, struct page *, struct f2fs_io_info *); - -typedef void (*btf_trace_f2fs_submit_page_write)(void *, struct page *, struct f2fs_io_info *); - -typedef void (*btf_trace_f2fs_prepare_write_bio)(void *, struct super_block *, int, struct bio *); - -typedef void (*btf_trace_f2fs_prepare_read_bio)(void *, struct super_block *, int, struct bio *); - -typedef void (*btf_trace_f2fs_submit_read_bio)(void *, struct super_block *, int, struct bio *); - -typedef void (*btf_trace_f2fs_submit_write_bio)(void *, struct super_block *, int, struct bio *); - -typedef void (*btf_trace_f2fs_write_begin)(void *, struct inode *, loff_t, unsigned int, unsigned int); - -typedef void (*btf_trace_f2fs_write_end)(void *, struct inode *, loff_t, unsigned int, unsigned int); - -typedef void (*btf_trace_f2fs_writepage)(void *, struct page *, int); - -typedef void (*btf_trace_f2fs_do_write_data_page)(void *, struct page *, int); - -typedef void (*btf_trace_f2fs_readpage)(void *, struct page *, int); - -typedef void (*btf_trace_f2fs_set_page_dirty)(void *, struct page *, int); - -typedef void (*btf_trace_f2fs_vm_page_mkwrite)(void *, struct page *, int); - -typedef void (*btf_trace_f2fs_register_inmem_page)(void *, struct page *, int); - -typedef void (*btf_trace_f2fs_commit_inmem_page)(void *, struct page *, int); - -typedef void (*btf_trace_f2fs_filemap_fault)(void *, struct inode *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_f2fs_writepages)(void *, struct inode *, struct writeback_control *, int); - -typedef void (*btf_trace_f2fs_readpages)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_f2fs_write_checkpoint)(void *, struct super_block *, int, char *); - -typedef void (*btf_trace_f2fs_queue_discard)(void *, struct block_device *, block_t, block_t); - -typedef void (*btf_trace_f2fs_issue_discard)(void *, struct block_device *, block_t, block_t); - -typedef void (*btf_trace_f2fs_remove_discard)(void *, struct block_device *, block_t, block_t); - -typedef void (*btf_trace_f2fs_issue_reset_zone)(void *, struct block_device *, block_t); - -typedef void (*btf_trace_f2fs_issue_flush)(void *, struct block_device *, unsigned int, unsigned int, int); - -typedef void (*btf_trace_f2fs_lookup_extent_tree_start)(void *, struct inode *, unsigned int); - -typedef void (*btf_trace_f2fs_lookup_extent_tree_end)(void *, struct inode *, unsigned int, struct extent_info *); - -typedef void (*btf_trace_f2fs_update_extent_tree_range)(void *, struct inode *, unsigned int, block_t, unsigned int); - -typedef void (*btf_trace_f2fs_shrink_extent_tree)(void *, struct f2fs_sb_info *, unsigned int, unsigned int); - -typedef void (*btf_trace_f2fs_destroy_extent_tree)(void *, struct inode *, unsigned int); - -typedef void (*btf_trace_f2fs_sync_dirty_inodes_enter)(void *, struct super_block *, int, s64); - -typedef void (*btf_trace_f2fs_sync_dirty_inodes_exit)(void *, struct super_block *, int, s64); - -typedef void (*btf_trace_f2fs_shutdown)(void *, struct f2fs_sb_info *, unsigned int, int); - -typedef void (*btf_trace_f2fs_compress_pages_start)(void *, struct inode *, long unsigned int, unsigned int, unsigned char); - -typedef void (*btf_trace_f2fs_decompress_pages_start)(void *, struct inode *, long unsigned int, unsigned int, unsigned char); - -typedef void (*btf_trace_f2fs_compress_pages_end)(void *, struct inode *, long unsigned int, unsigned int, int); - -typedef void (*btf_trace_f2fs_decompress_pages_end)(void *, struct inode *, long unsigned int, unsigned int, int); - -typedef void (*btf_trace_f2fs_iostat)(void *, struct f2fs_sb_info *, long long unsigned int *); - -typedef void (*btf_trace_f2fs_bmap)(void *, struct inode *, sector_t, sector_t); - -typedef void (*btf_trace_f2fs_fiemap)(void *, struct inode *, sector_t, sector_t, long long unsigned int, unsigned int, int); - -enum { - Opt_gc_background = 0, - Opt_disable_roll_forward = 1, - Opt_norecovery = 2, - Opt_discard___3 = 3, - Opt_nodiscard___2 = 4, - Opt_noheap = 5, - Opt_heap = 6, - Opt_user_xattr___2 = 7, - Opt_nouser_xattr___2 = 8, - Opt_acl___3 = 9, - Opt_noacl___2 = 10, - Opt_active_logs = 11, - Opt_disable_ext_identify = 12, - Opt_inline_xattr = 13, - Opt_noinline_xattr = 14, - Opt_inline_xattr_size = 15, - Opt_inline_data = 16, - Opt_inline_dentry = 17, - Opt_noinline_dentry = 18, - Opt_flush_merge = 19, - Opt_noflush_merge = 20, - Opt_nobarrier___2 = 21, - Opt_fastboot = 22, - Opt_extent_cache = 23, - Opt_noextent_cache = 24, - Opt_noinline_data = 25, - Opt_data_flush = 26, - Opt_reserve_root = 27, - Opt_resgid___2 = 28, - Opt_resuid___2 = 29, - Opt_mode___5 = 30, - Opt_io_size_bits = 31, - Opt_fault_injection = 32, - Opt_fault_type = 33, - Opt_lazytime___2 = 34, - Opt_nolazytime___2 = 35, - Opt_quota___2 = 36, - Opt_noquota___2 = 37, - Opt_usrquota___2 = 38, - Opt_grpquota___2 = 39, - Opt_prjquota___2 = 40, - Opt_usrjquota___2 = 41, - Opt_grpjquota___2 = 42, - Opt_prjjquota = 43, - Opt_offusrjquota___2 = 44, - Opt_offgrpjquota___2 = 45, - Opt_offprjjquota = 46, - Opt_jqfmt_vfsold___2 = 47, - Opt_jqfmt_vfsv0___2 = 48, - Opt_jqfmt_vfsv1___2 = 49, - Opt_whint = 50, - Opt_alloc = 51, - Opt_fsync = 52, - Opt_test_dummy_encryption___2 = 53, - Opt_inlinecrypt___2 = 54, - Opt_checkpoint_disable = 55, - Opt_checkpoint_disable_cap = 56, - Opt_checkpoint_disable_cap_perc = 57, - Opt_checkpoint_enable = 58, - Opt_compress_algorithm = 59, - Opt_compress_log_size = 60, - Opt_compress_extension = 61, - Opt_atgc = 62, - Opt_err___6 = 63, -}; - -struct f2fs_orphan_block { - __le32 ino[1020]; - __le32 reserved; - __le16 blk_addr; - __le16 blk_count; - __le32 entry_count; - __le32 check_sum; -}; - -enum { - NAT_BITMAP = 0, - SIT_BITMAP = 1, -}; - -struct ino_entry { - struct list_head list; - nid_t ino; - unsigned int dirty_device; -}; - -struct free_nid { - struct list_head list; - nid_t nid; - int state; -}; - -struct inode_entry { - struct list_head list; - struct inode *inode; -}; - -struct rb_entry { - struct rb_node rb_node; - union { - struct { - unsigned int ofs; - unsigned int len; - }; - long long unsigned int key; - }; -}; - -enum need_lock_type { - LOCK_REQ = 0, - LOCK_DONE = 1, - LOCK_RETRY = 2, -}; - -enum { - GC_NORMAL = 0, - GC_IDLE_CB = 1, - GC_IDLE_GREEDY = 2, - GC_IDLE_AT = 3, - GC_URGENT_HIGH = 4, - GC_URGENT_LOW = 5, -}; - -struct gc_inode_list { - struct list_head ilist; - struct xarray iroot; -}; - -struct victim_info { - long long unsigned int mtime; - unsigned int segno; -}; - -struct victim_entry { - struct rb_node rb_node; - union { - struct { - long long unsigned int mtime; - unsigned int segno; - }; - struct victim_info vi; - }; - struct list_head list; -}; - -struct bio_entry { - struct bio *bio; - struct list_head list; -}; - -struct f2fs_private_dio { - struct inode *inode; - void *orig_private; - bio_end_io_t *orig_end_io; - bool write; -}; - -enum mem_type { - FREE_NIDS = 0, - NAT_ENTRIES = 1, - DIRTY_DENTS = 2, - INO_ENTRIES = 3, - EXTENT_CACHE = 4, - INMEM_PAGES = 5, - BASE_CHECK = 6, -}; - -struct inmem_pages { - struct list_head list; - struct page *page; - block_t old_addr; -}; - -enum bio_post_read_step___2 { - STEP_DECRYPT___2 = 0, - STEP_DECOMPRESS_NOWQ = 1, - STEP_DECOMPRESS = 2, - STEP_VERITY___2 = 3, -}; - -struct bio_post_read_ctx___2 { - struct bio *bio; - struct f2fs_sb_info *sbi; - struct work_struct work; - unsigned int enabled_steps; -}; - -struct f2fs_nat_block { - struct f2fs_nat_entry entries[455]; -} __attribute__((packed)); - -enum { - NAT_JOURNAL = 0, - SIT_JOURNAL = 1, -}; - -struct fsync_node_entry { - struct list_head list; - struct page *page; - unsigned int seq_id; -}; - -enum { - IS_CHECKPOINTED = 0, - HAS_FSYNCED_INODE = 1, - HAS_LAST_FSYNC = 2, - IS_DIRTY = 3, - IS_PREALLOC = 4, -}; - -struct nat_entry { - struct list_head list; - struct node_info ni; -}; - -struct nat_entry_set { - struct list_head set_list; - struct list_head entry_list; - nid_t set; - unsigned int entry_cnt; -}; - -struct f2fs_sit_block { - struct f2fs_sit_entry entries[55]; -} __attribute__((packed)); - -struct discard_entry { - struct list_head list; - block_t start_blkaddr; - unsigned char discard_map[64]; -}; - -enum { - D_PREP = 0, - D_PARTIAL = 1, - D_SUBMIT = 2, - D_DONE = 3, -}; - -struct discard_info { - block_t lstart; - block_t len; - block_t start; -}; - -struct discard_cmd { - struct rb_node rb_node; - union { - struct { - block_t lstart; - block_t len; - block_t start; - }; - struct discard_info di; - }; - struct list_head list; - struct completion wait; - struct block_device *bdev; - short unsigned int ref; - unsigned char state; - unsigned char queued; - int error; - spinlock_t lock; - short unsigned int bio_ref; -}; - -enum { - DPOLICY_BG = 0, - DPOLICY_FORCE = 1, - DPOLICY_FSTRIM = 2, - DPOLICY_UMOUNT = 3, - MAX_DPOLICY = 4, -}; - -struct discard_policy { - int type; - unsigned int min_interval; - unsigned int mid_interval; - unsigned int max_interval; - unsigned int max_requests; - unsigned int io_aware_gran; - bool io_aware; - bool sync; - bool ordered; - bool timeout; - unsigned int granularity; -}; - -struct flush_cmd { - struct completion wait; - struct llist_node llnode; - nid_t ino; - int ret; -}; - -enum { - ALLOC_RIGHT = 0, - ALLOC_LEFT = 1, -}; - -struct sit_entry_set { - struct list_head set_list; - unsigned int start_segno; - unsigned int entry_cnt; -}; - -struct fsync_inode_entry { - struct list_head list; - struct inode *inode; - block_t blkaddr; - block_t last_dentry; -}; - -enum { - GC_THREAD = 0, - SM_INFO = 1, - DCC_INFO = 2, - NM_INFO = 3, - F2FS_SBI = 4, - STAT_INFO = 5, - RESERVED_BLOCKS = 6, -}; - -struct f2fs_attr { - struct attribute attr; - ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); - ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *, const char *, size_t); - int struct_type; - int offset; - int id; -}; - -enum feat_id { - FEAT_CRYPTO = 0, - FEAT_BLKZONED = 1, - FEAT_ATOMIC_WRITE = 2, - FEAT_EXTRA_ATTR = 3, - FEAT_PROJECT_QUOTA = 4, - FEAT_INODE_CHECKSUM = 5, - FEAT_FLEXIBLE_INLINE_XATTR = 6, - FEAT_QUOTA_INO = 7, - FEAT_INODE_CRTIME = 8, - FEAT_LOST_FOUND = 9, - FEAT_VERITY = 10, - FEAT_SB_CHECKSUM = 11, - FEAT_CASEFOLD = 12, - FEAT_COMPRESSION = 13, - FEAT_TEST_DUMMY_ENCRYPTION_V2 = 14, -}; - -struct f2fs_xattr_header { - __le32 h_magic; - __le32 h_refcount; - __u32 h_reserved[4]; -}; - -struct f2fs_xattr_entry { - __u8 e_name_index; - __u8 e_name_len; - __le16 e_value_size; - char e_name[0]; -}; - -struct f2fs_acl_entry { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -}; - -struct f2fs_acl_header { - __le32 a_version; -}; - -typedef s32 compat_key_t; - -struct ipc64_perm { - __kernel_key_t key; - __kernel_uid32_t uid; - __kernel_gid32_t gid; - __kernel_uid32_t cuid; - __kernel_gid32_t cgid; - __kernel_mode_t mode; - unsigned char __pad1[0]; - short unsigned int seq; - short unsigned int __pad2; - __kernel_ulong_t __unused1; - __kernel_ulong_t __unused2; -}; - -typedef u32 __compat_gid32_t; - -struct compat_ipc64_perm { - compat_key_t key; - __compat_uid32_t uid; - __compat_gid32_t gid; - __compat_uid32_t cuid; - __compat_gid32_t cgid; - short unsigned int mode; - short unsigned int __pad1; - short unsigned int seq; - short unsigned int __pad2; - compat_ulong_t unused1; - compat_ulong_t unused2; -}; - -struct compat_ipc_perm { - key_t key; - __compat_uid_t uid; - __compat_gid_t gid; - __compat_uid_t cuid; - __compat_gid_t cgid; - compat_mode_t mode; - short unsigned int seq; -}; - -struct ipc_perm { - __kernel_key_t key; - __kernel_uid_t uid; - __kernel_gid_t gid; - __kernel_uid_t cuid; - __kernel_gid_t cgid; - __kernel_mode_t mode; - short unsigned int seq; -}; - -struct ipc_params { - key_t key; - int flg; - union { - size_t size; - int nsems; - } u; -}; - -struct ipc_ops { - int (*getnew)(struct ipc_namespace *, struct ipc_params *); - int (*associate)(struct kern_ipc_perm *, int); - int (*more_checks)(struct kern_ipc_perm *, struct ipc_params *); -}; - -struct ipc_proc_iface { - const char *path; - const char *header; - int ids; - int (*show)(struct seq_file *, void *); -}; - -struct ipc_proc_iter { - struct ipc_namespace *ns; - struct pid_namespace *pid_ns; - struct ipc_proc_iface *iface; -}; - -struct msg_msgseg; - -struct msg_msg { - struct list_head m_list; - long int m_type; - size_t m_ts; - struct msg_msgseg *next; - void *security; -}; - -struct msg_msgseg { - struct msg_msgseg *next; -}; - -typedef int __kernel_ipc_pid_t; - -typedef __kernel_long_t __kernel_old_time_t; - -struct msgbuf { - __kernel_long_t mtype; - char mtext[1]; -}; - -struct msg; - -struct msqid_ds { - struct ipc_perm msg_perm; - struct msg *msg_first; - struct msg *msg_last; - __kernel_old_time_t msg_stime; - __kernel_old_time_t msg_rtime; - __kernel_old_time_t msg_ctime; - long unsigned int msg_lcbytes; - long unsigned int msg_lqbytes; - short unsigned int msg_cbytes; - short unsigned int msg_qnum; - short unsigned int msg_qbytes; - __kernel_ipc_pid_t msg_lspid; - __kernel_ipc_pid_t msg_lrpid; -}; - -struct msqid64_ds { - struct ipc64_perm msg_perm; - long int msg_stime; - long int msg_rtime; - long int msg_ctime; - long unsigned int msg_cbytes; - long unsigned int msg_qnum; - long unsigned int msg_qbytes; - __kernel_pid_t msg_lspid; - __kernel_pid_t msg_lrpid; - long unsigned int __unused4; - long unsigned int __unused5; -}; - -struct msginfo { - int msgpool; - int msgmap; - int msgmax; - int msgmnb; - int msgmni; - int msgssz; - int msgtql; - short unsigned int msgseg; -}; - -typedef u16 compat_ipc_pid_t; - -struct compat_msqid64_ds { - struct compat_ipc64_perm msg_perm; - compat_ulong_t msg_stime; - compat_ulong_t msg_stime_high; - compat_ulong_t msg_rtime; - compat_ulong_t msg_rtime_high; - compat_ulong_t msg_ctime; - compat_ulong_t msg_ctime_high; - compat_ulong_t msg_cbytes; - compat_ulong_t msg_qnum; - compat_ulong_t msg_qbytes; - compat_pid_t msg_lspid; - compat_pid_t msg_lrpid; - compat_ulong_t __unused4; - compat_ulong_t __unused5; -}; - -struct msg_queue { - struct kern_ipc_perm q_perm; - time64_t q_stime; - time64_t q_rtime; - time64_t q_ctime; - long unsigned int q_cbytes; - long unsigned int q_qnum; - long unsigned int q_qbytes; - struct pid *q_lspid; - struct pid *q_lrpid; - struct list_head q_messages; - struct list_head q_receivers; - struct list_head q_senders; - long: 64; - long: 64; -}; - -struct msg_receiver { - struct list_head r_list; - struct task_struct *r_tsk; - int r_mode; - long int r_msgtype; - long int r_maxsize; - struct msg_msg *r_msg; -}; - -struct msg_sender { - struct list_head list; - struct task_struct *tsk; - size_t msgsz; -}; - -struct compat_msqid_ds { - struct compat_ipc_perm msg_perm; - compat_uptr_t msg_first; - compat_uptr_t msg_last; - old_time32_t msg_stime; - old_time32_t msg_rtime; - old_time32_t msg_ctime; - compat_ulong_t msg_lcbytes; - compat_ulong_t msg_lqbytes; - short unsigned int msg_cbytes; - short unsigned int msg_qnum; - short unsigned int msg_qbytes; - compat_ipc_pid_t msg_lspid; - compat_ipc_pid_t msg_lrpid; -}; - -struct compat_msgbuf { - compat_long_t mtype; - char mtext[1]; -}; - -struct sem; - -struct sem_queue; - -struct sem_undo; - -struct semid_ds { - struct ipc_perm sem_perm; - __kernel_old_time_t sem_otime; - __kernel_old_time_t sem_ctime; - struct sem *sem_base; - struct sem_queue *sem_pending; - struct sem_queue **sem_pending_last; - struct sem_undo *undo; - short unsigned int sem_nsems; -}; - -struct sem { - int semval; - struct pid *sempid; - spinlock_t lock; - struct list_head pending_alter; - struct list_head pending_const; - time64_t sem_otime; -}; - -struct sembuf; - -struct sem_queue { - struct list_head list; - struct task_struct *sleeper; - struct sem_undo *undo; - struct pid *pid; - int status; - struct sembuf *sops; - struct sembuf *blocking; - int nsops; - bool alter; - bool dupsop; -}; - -struct sem_undo { - struct list_head list_proc; - struct callback_head rcu; - struct sem_undo_list *ulp; - struct list_head list_id; - int semid; - short int *semadj; -}; - -struct semid64_ds { - struct ipc64_perm sem_perm; - long int sem_otime; - long int sem_ctime; - long unsigned int sem_nsems; - long unsigned int __unused3; - long unsigned int __unused4; -}; - -struct sembuf { - short unsigned int sem_num; - short int sem_op; - short int sem_flg; -}; - -struct seminfo { - int semmap; - int semmni; - int semmns; - int semmnu; - int semmsl; - int semopm; - int semume; - int semusz; - int semvmx; - int semaem; -}; - -struct sem_undo_list { - refcount_t refcnt; - spinlock_t lock; - struct list_head list_proc; -}; - -struct compat_semid64_ds { - struct compat_ipc64_perm sem_perm; - compat_ulong_t sem_otime; - compat_ulong_t sem_otime_high; - compat_ulong_t sem_ctime; - compat_ulong_t sem_ctime_high; - compat_ulong_t sem_nsems; - compat_ulong_t __unused3; - compat_ulong_t __unused4; -}; - -struct sem_array { - struct kern_ipc_perm sem_perm; - time64_t sem_ctime; - struct list_head pending_alter; - struct list_head pending_const; - struct list_head list_id; - int sem_nsems; - int complex_count; - unsigned int use_global_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct sem sems[0]; -}; - -struct compat_semid_ds { - struct compat_ipc_perm sem_perm; - old_time32_t sem_otime; - old_time32_t sem_ctime; - compat_uptr_t sem_base; - compat_uptr_t sem_pending; - compat_uptr_t sem_pending_last; - compat_uptr_t undo; - short unsigned int sem_nsems; -}; - -struct shmid_ds { - struct ipc_perm shm_perm; - int shm_segsz; - __kernel_old_time_t shm_atime; - __kernel_old_time_t shm_dtime; - __kernel_old_time_t shm_ctime; - __kernel_ipc_pid_t shm_cpid; - __kernel_ipc_pid_t shm_lpid; - short unsigned int shm_nattch; - short unsigned int shm_unused; - void *shm_unused2; - void *shm_unused3; -}; - -struct shmid64_ds { - struct ipc64_perm shm_perm; - size_t shm_segsz; - long int shm_atime; - long int shm_dtime; - long int shm_ctime; - __kernel_pid_t shm_cpid; - __kernel_pid_t shm_lpid; - long unsigned int shm_nattch; - long unsigned int __unused4; - long unsigned int __unused5; -}; - -struct shminfo64 { - long unsigned int shmmax; - long unsigned int shmmin; - long unsigned int shmmni; - long unsigned int shmseg; - long unsigned int shmall; - long unsigned int __unused1; - long unsigned int __unused2; - long unsigned int __unused3; - long unsigned int __unused4; -}; - -struct shminfo { - int shmmax; - int shmmin; - int shmmni; - int shmseg; - int shmall; -}; - -struct shm_info { - int used_ids; - __kernel_ulong_t shm_tot; - __kernel_ulong_t shm_rss; - __kernel_ulong_t shm_swp; - __kernel_ulong_t swap_attempts; - __kernel_ulong_t swap_successes; -}; - -struct compat_shmid64_ds { - struct compat_ipc64_perm shm_perm; - compat_size_t shm_segsz; - compat_ulong_t shm_atime; - compat_ulong_t shm_atime_high; - compat_ulong_t shm_dtime; - compat_ulong_t shm_dtime_high; - compat_ulong_t shm_ctime; - compat_ulong_t shm_ctime_high; - compat_pid_t shm_cpid; - compat_pid_t shm_lpid; - compat_ulong_t shm_nattch; - compat_ulong_t __unused4; - compat_ulong_t __unused5; -}; - -struct shmid_kernel { - struct kern_ipc_perm shm_perm; - struct file *shm_file; - long unsigned int shm_nattch; - long unsigned int shm_segsz; - time64_t shm_atim; - time64_t shm_dtim; - time64_t shm_ctim; - struct pid *shm_cprid; - struct pid *shm_lprid; - struct user_struct *mlock_user; - struct task_struct *shm_creator; - struct list_head shm_clist; - struct ipc_namespace *ns; - long: 64; - long: 64; - long: 64; -}; - -struct shm_file_data { - int id; - struct ipc_namespace *ns; - struct file *file; - const struct vm_operations_struct *vm_ops; -}; - -struct compat_shmid_ds { - struct compat_ipc_perm shm_perm; - int shm_segsz; - old_time32_t shm_atime; - old_time32_t shm_dtime; - old_time32_t shm_ctime; - compat_ipc_pid_t shm_cpid; - compat_ipc_pid_t shm_lpid; - short unsigned int shm_nattch; - short unsigned int shm_unused; - compat_uptr_t shm_unused2; - compat_uptr_t shm_unused3; -}; - -struct compat_shminfo64 { - compat_ulong_t shmmax; - compat_ulong_t shmmin; - compat_ulong_t shmmni; - compat_ulong_t shmseg; - compat_ulong_t shmall; - compat_ulong_t __unused1; - compat_ulong_t __unused2; - compat_ulong_t __unused3; - compat_ulong_t __unused4; -}; - -struct compat_shm_info { - compat_int_t used_ids; - compat_ulong_t shm_tot; - compat_ulong_t shm_rss; - compat_ulong_t shm_swp; - compat_ulong_t swap_attempts; - compat_ulong_t swap_successes; -}; - -struct mqueue_fs_context { - struct ipc_namespace *ipc_ns; -}; - -struct posix_msg_tree_node { - struct rb_node rb_node; - struct list_head msg_list; - int priority; -}; - -struct ext_wait_queue { - struct task_struct *task; - struct list_head list; - struct msg_msg *msg; - int state; -}; - -struct mqueue_inode_info { - spinlock_t lock; - struct inode vfs_inode; - wait_queue_head_t wait_q; - struct rb_root msg_tree; - struct rb_node *msg_tree_rightmost; - struct posix_msg_tree_node *node_cache; - struct mq_attr attr; - struct sigevent notify; - struct pid *notify_owner; - u32 notify_self_exec_id; - struct user_namespace *notify_user_ns; - struct user_struct *user; - struct sock *notify_sock; - struct sk_buff *notify_cookie; - struct ext_wait_queue e_wait_q[2]; - long unsigned int qsize; -}; - -struct compat_mq_attr { - compat_long_t mq_flags; - compat_long_t mq_maxmsg; - compat_long_t mq_msgsize; - compat_long_t mq_curmsgs; - compat_long_t __reserved[4]; -}; - -struct key_user { - struct rb_node node; - struct mutex cons_lock; - spinlock_t lock; - refcount_t usage; - atomic_t nkeys; - atomic_t nikeys; - kuid_t uid; - int qnkeys; - int qnbytes; -}; - -enum key_notification_subtype { - NOTIFY_KEY_INSTANTIATED = 0, - NOTIFY_KEY_UPDATED = 1, - NOTIFY_KEY_LINKED = 2, - NOTIFY_KEY_UNLINKED = 3, - NOTIFY_KEY_CLEARED = 4, - NOTIFY_KEY_REVOKED = 5, - NOTIFY_KEY_INVALIDATED = 6, - NOTIFY_KEY_SETATTR = 7, -}; - -struct assoc_array_edit; - -struct assoc_array_ops { - long unsigned int (*get_key_chunk)(const void *, int); - long unsigned int (*get_object_key_chunk)(const void *, int); - bool (*compare_object)(const void *, const void *); - int (*diff_objects)(const void *, const void *); - void (*free_object)(void *); -}; - -struct assoc_array_node { - struct assoc_array_ptr *back_pointer; - u8 parent_slot; - struct assoc_array_ptr *slots[16]; - long unsigned int nr_leaves_on_branch; -}; - -struct assoc_array_shortcut { - struct assoc_array_ptr *back_pointer; - int parent_slot; - int skip_to_level; - struct assoc_array_ptr *next_node; - long unsigned int index_key[0]; -}; - -struct assoc_array_edit___2 { - struct callback_head rcu; - struct assoc_array *array; - const struct assoc_array_ops *ops; - const struct assoc_array_ops *ops_for_excised_subtree; - struct assoc_array_ptr *leaf; - struct assoc_array_ptr **leaf_p; - struct assoc_array_ptr *dead_leaf; - struct assoc_array_ptr *new_meta[3]; - struct assoc_array_ptr *excised_meta[1]; - struct assoc_array_ptr *excised_subtree; - struct assoc_array_ptr **set_backpointers[16]; - struct assoc_array_ptr *set_backpointers_to; - struct assoc_array_node *adjust_count_on; - long int adjust_count_by; - struct { - struct assoc_array_ptr **ptr; - struct assoc_array_ptr *to; - } set[2]; - struct { - u8 *p; - u8 to; - } set_parent_slot[1]; - u8 segment_cache[17]; -}; - -struct keyring_search_context { - struct keyring_index_key index_key; - const struct cred *cred; - struct key_match_data match_data; - unsigned int flags; - int (*iterator)(const void *, void *); - int skipped_ret; - bool possessed; - key_ref_t result; - time64_t now; -}; - -struct keyring_read_iterator_context { - size_t buflen; - size_t count; - key_serial_t *buffer; -}; - -struct keyctl_dh_params { - union { - __s32 private; - __s32 priv; - }; - __s32 prime; - __s32 base; -}; - -struct keyctl_kdf_params { - char *hashname; - char *otherinfo; - __u32 otherinfolen; - __u32 __spare[8]; -}; - -struct keyctl_pkey_query { - __u32 supported_ops; - __u32 key_size; - __u16 max_data_size; - __u16 max_sig_size; - __u16 max_enc_size; - __u16 max_dec_size; - __u32 __spare[10]; -}; - -struct keyctl_pkey_params { - __s32 key_id; - __u32 in_len; - union { - __u32 out_len; - __u32 in2_len; - }; - __u32 __spare[7]; -}; - -enum { - Opt_err___7 = 0, - Opt_enc = 1, - Opt_hash = 2, -}; - -struct vfs_cap_data { - __le32 magic_etc; - struct { - __le32 permitted; - __le32 inheritable; - } data[2]; -}; - -struct vfs_ns_cap_data { - __le32 magic_etc; - struct { - __le32 permitted; - __le32 inheritable; - } data[2]; - __le32 rootid; -}; - -struct fs_parameter___2; - -struct sctp_endpoint; - -struct perf_event_attr___2; - -union security_list_options { - int (*binder_set_context_mgr)(const struct cred *); - int (*binder_transaction)(const struct cred *, const struct cred *); - int (*binder_transfer_binder)(const struct cred *, const struct cred *); - int (*binder_transfer_file)(const struct cred *, const struct cred *, struct file *); - int (*ptrace_access_check)(struct task_struct *, unsigned int); - int (*ptrace_traceme)(struct task_struct *); - int (*capget)(struct task_struct *, kernel_cap_t *, kernel_cap_t *, kernel_cap_t *); - int (*capset)(struct cred *, const struct cred *, const kernel_cap_t *, const kernel_cap_t *, const kernel_cap_t *); - int (*capable)(const struct cred *, struct user_namespace *, int, unsigned int); - int (*quotactl)(int, int, int, struct super_block *); - int (*quota_on)(struct dentry *); - int (*syslog)(int); - int (*settime)(const struct timespec64 *, const struct timezone *); - int (*vm_enough_memory)(struct mm_struct *, long int); - int (*bprm_creds_for_exec)(struct linux_binprm *); - int (*bprm_creds_from_file)(struct linux_binprm *, struct file *); - int (*bprm_check_security)(struct linux_binprm *); - void (*bprm_committing_creds)(struct linux_binprm *); - void (*bprm_committed_creds)(struct linux_binprm *); - int (*fs_context_dup)(struct fs_context *, struct fs_context *); - int (*fs_context_parse_param)(struct fs_context *, struct fs_parameter___2 *); - int (*sb_alloc_security)(struct super_block *); - void (*sb_free_security)(struct super_block *); - void (*sb_free_mnt_opts)(void *); - int (*sb_eat_lsm_opts)(char *, void **); - int (*sb_remount)(struct super_block *, void *); - int (*sb_kern_mount)(struct super_block *); - int (*sb_show_options)(struct seq_file *, struct super_block *); - int (*sb_statfs)(struct dentry *); - int (*sb_mount)(const char *, const struct path *, const char *, long unsigned int, void *); - int (*sb_umount)(struct vfsmount *, int); - int (*sb_pivotroot)(const struct path *, const struct path *); - int (*sb_set_mnt_opts)(struct super_block *, void *, long unsigned int, long unsigned int *); - int (*sb_clone_mnt_opts)(const struct super_block *, struct super_block *, long unsigned int, long unsigned int *); - int (*sb_add_mnt_opt)(const char *, const char *, int, void **); - int (*move_mount)(const struct path *, const struct path *); - int (*dentry_init_security)(struct dentry *, int, const struct qstr *, void **, u32 *); - int (*dentry_create_files_as)(struct dentry *, int, struct qstr *, const struct cred *, struct cred *); - int (*path_unlink)(const struct path *, struct dentry *); - int (*path_mkdir)(const struct path *, struct dentry *, umode_t); - int (*path_rmdir)(const struct path *, struct dentry *); - int (*path_mknod)(const struct path *, struct dentry *, umode_t, unsigned int); - int (*path_truncate)(const struct path *); - int (*path_symlink)(const struct path *, struct dentry *, const char *); - int (*path_link)(struct dentry *, const struct path *, struct dentry *); - int (*path_rename)(const struct path *, struct dentry *, const struct path *, struct dentry *); - int (*path_chmod)(const struct path *, umode_t); - int (*path_chown)(const struct path *, kuid_t, kgid_t); - int (*path_chroot)(const struct path *); - int (*path_notify)(const struct path *, u64, unsigned int); - int (*inode_alloc_security)(struct inode *); - void (*inode_free_security)(struct inode *); - int (*inode_init_security)(struct inode *, struct inode *, const struct qstr *, const char **, void **, size_t *); - int (*inode_create)(struct inode *, struct dentry *, umode_t); - int (*inode_link)(struct dentry *, struct inode *, struct dentry *); - int (*inode_unlink)(struct inode *, struct dentry *); - int (*inode_symlink)(struct inode *, struct dentry *, const char *); - int (*inode_mkdir)(struct inode *, struct dentry *, umode_t); - int (*inode_rmdir)(struct inode *, struct dentry *); - int (*inode_mknod)(struct inode *, struct dentry *, umode_t, dev_t); - int (*inode_rename)(struct inode *, struct dentry *, struct inode *, struct dentry *); - int (*inode_readlink)(struct dentry *); - int (*inode_follow_link)(struct dentry *, struct inode *, bool); - int (*inode_permission)(struct inode *, int); - int (*inode_setattr)(struct dentry *, struct iattr *); - int (*inode_getattr)(const struct path *); - int (*inode_setxattr)(struct dentry *, const char *, const void *, size_t, int); - void (*inode_post_setxattr)(struct dentry *, const char *, const void *, size_t, int); - int (*inode_getxattr)(struct dentry *, const char *); - int (*inode_listxattr)(struct dentry *); - int (*inode_removexattr)(struct dentry *, const char *); - int (*inode_need_killpriv)(struct dentry *); - int (*inode_killpriv)(struct dentry *); - int (*inode_getsecurity)(struct inode *, const char *, void **, bool); - int (*inode_setsecurity)(struct inode *, const char *, const void *, size_t, int); - int (*inode_listsecurity)(struct inode *, char *, size_t); - void (*inode_getsecid)(struct inode *, u32 *); - int (*inode_copy_up)(struct dentry *, struct cred **); - int (*inode_copy_up_xattr)(const char *); - int (*kernfs_init_security)(struct kernfs_node *, struct kernfs_node *); - int (*file_permission)(struct file *, int); - int (*file_alloc_security)(struct file *); - void (*file_free_security)(struct file *); - int (*file_ioctl)(struct file *, unsigned int, long unsigned int); - int (*mmap_addr)(long unsigned int); - int (*mmap_file)(struct file *, long unsigned int, long unsigned int, long unsigned int); - int (*file_mprotect)(struct vm_area_struct *, long unsigned int, long unsigned int); - int (*file_lock)(struct file *, unsigned int); - int (*file_fcntl)(struct file *, unsigned int, long unsigned int); - void (*file_set_fowner)(struct file *); - int (*file_send_sigiotask)(struct task_struct *, struct fown_struct *, int); - int (*file_receive)(struct file *); - int (*file_open)(struct file *); - int (*task_alloc)(struct task_struct *, long unsigned int); - void (*task_free)(struct task_struct *); - int (*cred_alloc_blank)(struct cred *, gfp_t); - void (*cred_free)(struct cred *); - int (*cred_prepare)(struct cred *, const struct cred *, gfp_t); - void (*cred_transfer)(struct cred *, const struct cred *); - void (*cred_getsecid)(const struct cred *, u32 *); - int (*kernel_act_as)(struct cred *, u32); - int (*kernel_create_files_as)(struct cred *, struct inode *); - int (*kernel_module_request)(char *); - int (*kernel_load_data)(enum kernel_load_data_id, bool); - int (*kernel_post_load_data)(char *, loff_t, enum kernel_load_data_id, char *); - int (*kernel_read_file)(struct file *, enum kernel_read_file_id, bool); - int (*kernel_post_read_file)(struct file *, char *, loff_t, enum kernel_read_file_id); - int (*task_fix_setuid)(struct cred *, const struct cred *, int); - int (*task_fix_setgid)(struct cred *, const struct cred *, int); - int (*task_setpgid)(struct task_struct *, pid_t); - int (*task_getpgid)(struct task_struct *); - int (*task_getsid)(struct task_struct *); - void (*task_getsecid)(struct task_struct *, u32 *); - int (*task_setnice)(struct task_struct *, int); - int (*task_setioprio)(struct task_struct *, int); - int (*task_getioprio)(struct task_struct *); - int (*task_prlimit)(const struct cred *, const struct cred *, unsigned int); - int (*task_setrlimit)(struct task_struct *, unsigned int, struct rlimit *); - int (*task_setscheduler)(struct task_struct *); - int (*task_getscheduler)(struct task_struct *); - int (*task_movememory)(struct task_struct *); - int (*task_kill)(struct task_struct *, struct kernel_siginfo *, int, const struct cred *); - int (*task_prctl)(int, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - void (*task_to_inode)(struct task_struct *, struct inode *); - int (*ipc_permission)(struct kern_ipc_perm *, short int); - void (*ipc_getsecid)(struct kern_ipc_perm *, u32 *); - int (*msg_msg_alloc_security)(struct msg_msg *); - void (*msg_msg_free_security)(struct msg_msg *); - int (*msg_queue_alloc_security)(struct kern_ipc_perm *); - void (*msg_queue_free_security)(struct kern_ipc_perm *); - int (*msg_queue_associate)(struct kern_ipc_perm *, int); - int (*msg_queue_msgctl)(struct kern_ipc_perm *, int); - int (*msg_queue_msgsnd)(struct kern_ipc_perm *, struct msg_msg *, int); - int (*msg_queue_msgrcv)(struct kern_ipc_perm *, struct msg_msg *, struct task_struct *, long int, int); - int (*shm_alloc_security)(struct kern_ipc_perm *); - void (*shm_free_security)(struct kern_ipc_perm *); - int (*shm_associate)(struct kern_ipc_perm *, int); - int (*shm_shmctl)(struct kern_ipc_perm *, int); - int (*shm_shmat)(struct kern_ipc_perm *, char *, int); - int (*sem_alloc_security)(struct kern_ipc_perm *); - void (*sem_free_security)(struct kern_ipc_perm *); - int (*sem_associate)(struct kern_ipc_perm *, int); - int (*sem_semctl)(struct kern_ipc_perm *, int); - int (*sem_semop)(struct kern_ipc_perm *, struct sembuf *, unsigned int, int); - int (*netlink_send)(struct sock *, struct sk_buff *); - void (*d_instantiate)(struct dentry *, struct inode *); - int (*getprocattr)(struct task_struct *, char *, char **); - int (*setprocattr)(const char *, void *, size_t); - int (*ismaclabel)(const char *); - int (*secid_to_secctx)(u32, char **, u32 *); - int (*secctx_to_secid)(const char *, u32, u32 *); - void (*release_secctx)(char *, u32); - void (*inode_invalidate_secctx)(struct inode *); - int (*inode_notifysecctx)(struct inode *, void *, u32); - int (*inode_setsecctx)(struct dentry *, void *, u32); - int (*inode_getsecctx)(struct inode *, void **, u32 *); - int (*unix_stream_connect)(struct sock *, struct sock *, struct sock *); - int (*unix_may_send)(struct socket *, struct socket *); - int (*socket_create)(int, int, int, int); - int (*socket_post_create)(struct socket *, int, int, int, int); - int (*socket_socketpair)(struct socket *, struct socket *); - int (*socket_bind)(struct socket *, struct sockaddr *, int); - int (*socket_connect)(struct socket *, struct sockaddr *, int); - int (*socket_listen)(struct socket *, int); - int (*socket_accept)(struct socket *, struct socket *); - int (*socket_sendmsg)(struct socket *, struct msghdr *, int); - int (*socket_recvmsg)(struct socket *, struct msghdr *, int, int); - int (*socket_getsockname)(struct socket *); - int (*socket_getpeername)(struct socket *); - int (*socket_getsockopt)(struct socket *, int, int); - int (*socket_setsockopt)(struct socket *, int, int); - int (*socket_shutdown)(struct socket *, int); - int (*socket_sock_rcv_skb)(struct sock *, struct sk_buff *); - int (*socket_getpeersec_stream)(struct socket *, char *, int *, unsigned int); - int (*socket_getpeersec_dgram)(struct socket *, struct sk_buff *, u32 *); - int (*sk_alloc_security)(struct sock *, int, gfp_t); - void (*sk_free_security)(struct sock *); - void (*sk_clone_security)(const struct sock *, struct sock *); - void (*sk_getsecid)(struct sock *, u32 *); - void (*sock_graft)(struct sock *, struct socket *); - int (*inet_conn_request)(struct sock *, struct sk_buff *, struct request_sock *); - void (*inet_csk_clone)(struct sock *, const struct request_sock *); - void (*inet_conn_established)(struct sock *, struct sk_buff *); - int (*secmark_relabel_packet)(u32); - void (*secmark_refcount_inc)(); - void (*secmark_refcount_dec)(); - void (*req_classify_flow)(const struct request_sock *, struct flowi *); - int (*tun_dev_alloc_security)(void **); - void (*tun_dev_free_security)(void *); - int (*tun_dev_create)(); - int (*tun_dev_attach_queue)(void *); - int (*tun_dev_attach)(struct sock *, void *); - int (*tun_dev_open)(void *); - int (*sctp_assoc_request)(struct sctp_endpoint *, struct sk_buff *); - int (*sctp_bind_connect)(struct sock *, int, struct sockaddr *, int); - void (*sctp_sk_clone)(struct sctp_endpoint *, struct sock *, struct sock *); - int (*key_alloc)(struct key *, const struct cred *, long unsigned int); - void (*key_free)(struct key *); - int (*key_permission)(key_ref_t, const struct cred *, enum key_need_perm); - int (*key_getsecurity)(struct key *, char **); - int (*audit_rule_init)(u32, u32, char *, void **); - int (*audit_rule_known)(struct audit_krule *); - int (*audit_rule_match)(u32, u32, u32, void *); - void (*audit_rule_free)(void *); - int (*bpf)(int, union bpf_attr *, unsigned int); - int (*bpf_map)(struct bpf_map *, fmode_t); - int (*bpf_prog)(struct bpf_prog *); - int (*bpf_map_alloc_security)(struct bpf_map *); - void (*bpf_map_free_security)(struct bpf_map *); - int (*bpf_prog_alloc_security)(struct bpf_prog_aux *); - void (*bpf_prog_free_security)(struct bpf_prog_aux *); - int (*locked_down)(enum lockdown_reason); - int (*perf_event_open)(struct perf_event_attr___2 *, int); - int (*perf_event_alloc)(struct perf_event *); - void (*perf_event_free)(struct perf_event *); - int (*perf_event_read)(struct perf_event *); - int (*perf_event_write)(struct perf_event *); -}; - -struct security_hook_heads { - struct hlist_head binder_set_context_mgr; - struct hlist_head binder_transaction; - struct hlist_head binder_transfer_binder; - struct hlist_head binder_transfer_file; - struct hlist_head ptrace_access_check; - struct hlist_head ptrace_traceme; - struct hlist_head capget; - struct hlist_head capset; - struct hlist_head capable; - struct hlist_head quotactl; - struct hlist_head quota_on; - struct hlist_head syslog; - struct hlist_head settime; - struct hlist_head vm_enough_memory; - struct hlist_head bprm_creds_for_exec; - struct hlist_head bprm_creds_from_file; - struct hlist_head bprm_check_security; - struct hlist_head bprm_committing_creds; - struct hlist_head bprm_committed_creds; - struct hlist_head fs_context_dup; - struct hlist_head fs_context_parse_param; - struct hlist_head sb_alloc_security; - struct hlist_head sb_free_security; - struct hlist_head sb_free_mnt_opts; - struct hlist_head sb_eat_lsm_opts; - struct hlist_head sb_remount; - struct hlist_head sb_kern_mount; - struct hlist_head sb_show_options; - struct hlist_head sb_statfs; - struct hlist_head sb_mount; - struct hlist_head sb_umount; - struct hlist_head sb_pivotroot; - struct hlist_head sb_set_mnt_opts; - struct hlist_head sb_clone_mnt_opts; - struct hlist_head sb_add_mnt_opt; - struct hlist_head move_mount; - struct hlist_head dentry_init_security; - struct hlist_head dentry_create_files_as; - struct hlist_head path_unlink; - struct hlist_head path_mkdir; - struct hlist_head path_rmdir; - struct hlist_head path_mknod; - struct hlist_head path_truncate; - struct hlist_head path_symlink; - struct hlist_head path_link; - struct hlist_head path_rename; - struct hlist_head path_chmod; - struct hlist_head path_chown; - struct hlist_head path_chroot; - struct hlist_head path_notify; - struct hlist_head inode_alloc_security; - struct hlist_head inode_free_security; - struct hlist_head inode_init_security; - struct hlist_head inode_create; - struct hlist_head inode_link; - struct hlist_head inode_unlink; - struct hlist_head inode_symlink; - struct hlist_head inode_mkdir; - struct hlist_head inode_rmdir; - struct hlist_head inode_mknod; - struct hlist_head inode_rename; - struct hlist_head inode_readlink; - struct hlist_head inode_follow_link; - struct hlist_head inode_permission; - struct hlist_head inode_setattr; - struct hlist_head inode_getattr; - struct hlist_head inode_setxattr; - struct hlist_head inode_post_setxattr; - struct hlist_head inode_getxattr; - struct hlist_head inode_listxattr; - struct hlist_head inode_removexattr; - struct hlist_head inode_need_killpriv; - struct hlist_head inode_killpriv; - struct hlist_head inode_getsecurity; - struct hlist_head inode_setsecurity; - struct hlist_head inode_listsecurity; - struct hlist_head inode_getsecid; - struct hlist_head inode_copy_up; - struct hlist_head inode_copy_up_xattr; - struct hlist_head kernfs_init_security; - struct hlist_head file_permission; - struct hlist_head file_alloc_security; - struct hlist_head file_free_security; - struct hlist_head file_ioctl; - struct hlist_head mmap_addr; - struct hlist_head mmap_file; - struct hlist_head file_mprotect; - struct hlist_head file_lock; - struct hlist_head file_fcntl; - struct hlist_head file_set_fowner; - struct hlist_head file_send_sigiotask; - struct hlist_head file_receive; - struct hlist_head file_open; - struct hlist_head task_alloc; - struct hlist_head task_free; - struct hlist_head cred_alloc_blank; - struct hlist_head cred_free; - struct hlist_head cred_prepare; - struct hlist_head cred_transfer; - struct hlist_head cred_getsecid; - struct hlist_head kernel_act_as; - struct hlist_head kernel_create_files_as; - struct hlist_head kernel_module_request; - struct hlist_head kernel_load_data; - struct hlist_head kernel_post_load_data; - struct hlist_head kernel_read_file; - struct hlist_head kernel_post_read_file; - struct hlist_head task_fix_setuid; - struct hlist_head task_fix_setgid; - struct hlist_head task_setpgid; - struct hlist_head task_getpgid; - struct hlist_head task_getsid; - struct hlist_head task_getsecid; - struct hlist_head task_setnice; - struct hlist_head task_setioprio; - struct hlist_head task_getioprio; - struct hlist_head task_prlimit; - struct hlist_head task_setrlimit; - struct hlist_head task_setscheduler; - struct hlist_head task_getscheduler; - struct hlist_head task_movememory; - struct hlist_head task_kill; - struct hlist_head task_prctl; - struct hlist_head task_to_inode; - struct hlist_head ipc_permission; - struct hlist_head ipc_getsecid; - struct hlist_head msg_msg_alloc_security; - struct hlist_head msg_msg_free_security; - struct hlist_head msg_queue_alloc_security; - struct hlist_head msg_queue_free_security; - struct hlist_head msg_queue_associate; - struct hlist_head msg_queue_msgctl; - struct hlist_head msg_queue_msgsnd; - struct hlist_head msg_queue_msgrcv; - struct hlist_head shm_alloc_security; - struct hlist_head shm_free_security; - struct hlist_head shm_associate; - struct hlist_head shm_shmctl; - struct hlist_head shm_shmat; - struct hlist_head sem_alloc_security; - struct hlist_head sem_free_security; - struct hlist_head sem_associate; - struct hlist_head sem_semctl; - struct hlist_head sem_semop; - struct hlist_head netlink_send; - struct hlist_head d_instantiate; - struct hlist_head getprocattr; - struct hlist_head setprocattr; - struct hlist_head ismaclabel; - struct hlist_head secid_to_secctx; - struct hlist_head secctx_to_secid; - struct hlist_head release_secctx; - struct hlist_head inode_invalidate_secctx; - struct hlist_head inode_notifysecctx; - struct hlist_head inode_setsecctx; - struct hlist_head inode_getsecctx; - struct hlist_head unix_stream_connect; - struct hlist_head unix_may_send; - struct hlist_head socket_create; - struct hlist_head socket_post_create; - struct hlist_head socket_socketpair; - struct hlist_head socket_bind; - struct hlist_head socket_connect; - struct hlist_head socket_listen; - struct hlist_head socket_accept; - struct hlist_head socket_sendmsg; - struct hlist_head socket_recvmsg; - struct hlist_head socket_getsockname; - struct hlist_head socket_getpeername; - struct hlist_head socket_getsockopt; - struct hlist_head socket_setsockopt; - struct hlist_head socket_shutdown; - struct hlist_head socket_sock_rcv_skb; - struct hlist_head socket_getpeersec_stream; - struct hlist_head socket_getpeersec_dgram; - struct hlist_head sk_alloc_security; - struct hlist_head sk_free_security; - struct hlist_head sk_clone_security; - struct hlist_head sk_getsecid; - struct hlist_head sock_graft; - struct hlist_head inet_conn_request; - struct hlist_head inet_csk_clone; - struct hlist_head inet_conn_established; - struct hlist_head secmark_relabel_packet; - struct hlist_head secmark_refcount_inc; - struct hlist_head secmark_refcount_dec; - struct hlist_head req_classify_flow; - struct hlist_head tun_dev_alloc_security; - struct hlist_head tun_dev_free_security; - struct hlist_head tun_dev_create; - struct hlist_head tun_dev_attach_queue; - struct hlist_head tun_dev_attach; - struct hlist_head tun_dev_open; - struct hlist_head sctp_assoc_request; - struct hlist_head sctp_bind_connect; - struct hlist_head sctp_sk_clone; - struct hlist_head key_alloc; - struct hlist_head key_free; - struct hlist_head key_permission; - struct hlist_head key_getsecurity; - struct hlist_head audit_rule_init; - struct hlist_head audit_rule_known; - struct hlist_head audit_rule_match; - struct hlist_head audit_rule_free; - struct hlist_head bpf; - struct hlist_head bpf_map; - struct hlist_head bpf_prog; - struct hlist_head bpf_map_alloc_security; - struct hlist_head bpf_map_free_security; - struct hlist_head bpf_prog_alloc_security; - struct hlist_head bpf_prog_free_security; - struct hlist_head locked_down; - struct hlist_head perf_event_open; - struct hlist_head perf_event_alloc; - struct hlist_head perf_event_free; - struct hlist_head perf_event_read; - struct hlist_head perf_event_write; -}; - -struct security_hook_list { - struct hlist_node list; - struct hlist_head *head; - union security_list_options hook; - char *lsm; -}; - -struct lsm_blob_sizes { - int lbs_cred; - int lbs_file; - int lbs_inode; - int lbs_ipc; - int lbs_msg_msg; - int lbs_task; -}; - -enum lsm_order { - LSM_ORDER_FIRST = 4294967295, - LSM_ORDER_MUTABLE = 0, -}; - -struct lsm_info { - const char *name; - enum lsm_order order; - long unsigned int flags; - int *enabled; - int (*init)(); - struct lsm_blob_sizes *blobs; -}; - -enum lsm_event { - LSM_POLICY_CHANGE = 0, -}; - -typedef int (*initxattrs)(struct inode *, const struct xattr *, void *); - -typedef __u16 __sum16; - -struct sockaddr_un { - __kernel_sa_family_t sun_family; - char sun_path[108]; -}; - -struct unix_address { - refcount_t refcnt; - int len; - unsigned int hash; - struct sockaddr_un name[0]; -}; - -struct scm_stat { - atomic_t nr_fds; -}; - -struct unix_sock { - struct sock sk; - struct unix_address *addr; - struct path path; - struct mutex iolock; - struct mutex bindlock; - struct sock *peer; - struct list_head link; - atomic_long_t inflight; - spinlock_t lock; - long unsigned int gc_flags; - long: 64; - struct socket_wq peer_wq; - wait_queue_entry_t peer_wake; - struct scm_stat scm_stat; - long: 32; - long: 64; - long: 64; -}; - -struct in6_pktinfo { - struct in6_addr ipi6_addr; - int ipi6_ifindex; -}; - -struct ipv6_rt_hdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 type; - __u8 segments_left; -}; - -struct ipv6_opt_hdr { - __u8 nexthdr; - __u8 hdrlen; -}; - -struct ipv6hdr { - __u8 priority: 4; - __u8 version: 4; - __u8 flow_lbl[3]; - __be16 payload_len; - __u8 nexthdr; - __u8 hop_limit; - struct in6_addr saddr; - struct in6_addr daddr; -}; - -struct ip_options { - __be32 faddr; - __be32 nexthop; - unsigned char optlen; - unsigned char srr; - unsigned char rr; - unsigned char ts; - unsigned char is_strictroute: 1; - unsigned char srr_is_hit: 1; - unsigned char is_changed: 1; - unsigned char rr_needaddr: 1; - unsigned char ts_needtime: 1; - unsigned char ts_needaddr: 1; - unsigned char router_alert; - unsigned char cipso; - unsigned char __pad2; - unsigned char __data[0]; -}; - -struct ip_options_rcu { - struct callback_head rcu; - struct ip_options opt; -}; - -struct ipv6_txoptions { - refcount_t refcnt; - int tot_len; - __u16 opt_flen; - __u16 opt_nflen; - struct ipv6_opt_hdr *hopopt; - struct ipv6_opt_hdr *dst0opt; - struct ipv6_rt_hdr *srcrt; - struct ipv6_opt_hdr *dst1opt; - struct callback_head rcu; -}; - -struct inet_cork { - unsigned int flags; - __be32 addr; - struct ip_options *opt; - unsigned int fragsize; - int length; - struct dst_entry *dst; - u8 tx_flags; - __u8 ttl; - __s16 tos; - char priority; - __u16 gso_size; - u64 transmit_time; - u32 mark; -}; - -struct inet_cork_full { - struct inet_cork base; - struct flowi fl; -}; - -struct ipv6_pinfo; - -struct ip_mc_socklist; - -struct inet_sock { - struct sock sk; - struct ipv6_pinfo *pinet6; - __be32 inet_saddr; - __s16 uc_ttl; - __u16 cmsg_flags; - __be16 inet_sport; - __u16 inet_id; - struct ip_options_rcu *inet_opt; - int rx_dst_ifindex; - __u8 tos; - __u8 min_ttl; - __u8 mc_ttl; - __u8 pmtudisc; - __u8 recverr: 1; - __u8 is_icsk: 1; - __u8 freebind: 1; - __u8 hdrincl: 1; - __u8 mc_loop: 1; - __u8 transparent: 1; - __u8 mc_all: 1; - __u8 nodefrag: 1; - __u8 bind_address_no_port: 1; - __u8 recverr_rfc4884: 1; - __u8 defer_connect: 1; - __u8 rcv_tos; - __u8 convert_csum; - int uc_index; - int mc_index; - __be32 mc_addr; - struct ip_mc_socklist *mc_list; - struct inet_cork_full cork; -}; - -struct inet6_cork { - struct ipv6_txoptions *opt; - u8 hop_limit; - u8 tclass; -}; - -struct ipv6_mc_socklist; - -struct ipv6_ac_socklist; - -struct ipv6_fl_socklist; - -struct ipv6_pinfo { - struct in6_addr saddr; - struct in6_pktinfo sticky_pktinfo; - const struct in6_addr *daddr_cache; - const struct in6_addr *saddr_cache; - __be32 flow_label; - __u32 frag_size; - __u16 __unused_1: 7; - __s16 hop_limit: 9; - __u16 mc_loop: 1; - __u16 __unused_2: 6; - __s16 mcast_hops: 9; - int ucast_oif; - int mcast_oif; - union { - struct { - __u16 srcrt: 1; - __u16 osrcrt: 1; - __u16 rxinfo: 1; - __u16 rxoinfo: 1; - __u16 rxhlim: 1; - __u16 rxohlim: 1; - __u16 hopopts: 1; - __u16 ohopopts: 1; - __u16 dstopts: 1; - __u16 odstopts: 1; - __u16 rxflow: 1; - __u16 rxtclass: 1; - __u16 rxpmtu: 1; - __u16 rxorigdstaddr: 1; - __u16 recvfragsize: 1; - } bits; - __u16 all; - } rxopt; - __u16 recverr: 1; - __u16 sndflow: 1; - __u16 repflow: 1; - __u16 pmtudisc: 3; - __u16 padding: 1; - __u16 srcprefs: 3; - __u16 dontfrag: 1; - __u16 autoflowlabel: 1; - __u16 autoflowlabel_set: 1; - __u16 mc_all: 1; - __u16 recverr_rfc4884: 1; - __u16 rtalert_isolate: 1; - __u8 min_hopcount; - __u8 tclass; - __be32 rcv_flowinfo; - __u32 dst_cookie; - __u32 rx_dst_cookie; - struct ipv6_mc_socklist *ipv6_mc_list; - struct ipv6_ac_socklist *ipv6_ac_list; - struct ipv6_fl_socklist *ipv6_fl_list; - struct ipv6_txoptions *opt; - struct sk_buff *pktoptions; - struct sk_buff *rxpmtu; - struct inet6_cork cork; -}; - -struct tcphdr { - __be16 source; - __be16 dest; - __be32 seq; - __be32 ack_seq; - __u16 res1: 4; - __u16 doff: 4; - __u16 fin: 1; - __u16 syn: 1; - __u16 rst: 1; - __u16 psh: 1; - __u16 ack: 1; - __u16 urg: 1; - __u16 ece: 1; - __u16 cwr: 1; - __be16 window; - __sum16 check; - __be16 urg_ptr; -}; - -struct udphdr { - __be16 source; - __be16 dest; - __be16 len; - __sum16 check; -}; - -struct ip6_sf_socklist; - -struct ipv6_mc_socklist { - struct in6_addr addr; - int ifindex; - unsigned int sfmode; - struct ipv6_mc_socklist *next; - rwlock_t sflock; - struct ip6_sf_socklist *sflist; - struct callback_head rcu; -}; - -struct ipv6_ac_socklist { - struct in6_addr acl_addr; - int acl_ifindex; - struct ipv6_ac_socklist *acl_next; -}; - -struct ip6_flowlabel; - -struct ipv6_fl_socklist { - struct ipv6_fl_socklist *next; - struct ip6_flowlabel *fl; - struct callback_head rcu; -}; - -struct iphdr { - __u8 ihl: 4; - __u8 version: 4; - __u8 tos; - __be16 tot_len; - __be16 id; - __be16 frag_off; - __u8 ttl; - __u8 protocol; - __sum16 check; - __be32 saddr; - __be32 daddr; -}; - -struct ip6_sf_socklist { - unsigned int sl_max; - unsigned int sl_count; - struct in6_addr sl_addr[0]; -}; - -struct ip6_flowlabel { - struct ip6_flowlabel *next; - __be32 label; - atomic_t users; - struct in6_addr dst; - struct ipv6_txoptions *opt; - long unsigned int linger; - struct callback_head rcu; - u8 share; - union { - struct pid *pid; - kuid_t uid; - } owner; - long unsigned int lastuse; - long unsigned int expires; - struct net *fl_net; -}; - -struct dccp_hdr { - __be16 dccph_sport; - __be16 dccph_dport; - __u8 dccph_doff; - __u8 dccph_cscov: 4; - __u8 dccph_ccval: 4; - __sum16 dccph_checksum; - __u8 dccph_x: 1; - __u8 dccph_type: 4; - __u8 dccph_reserved: 3; - __u8 dccph_seq2; - __be16 dccph_seq; -}; - -struct sctphdr { - __be16 source; - __be16 dest; - __be32 vtag; - __le32 checksum; -}; - -struct lsm_network_audit { - int netif; - struct sock *sk; - u16 family; - __be16 dport; - __be16 sport; - union { - struct { - __be32 daddr; - __be32 saddr; - } v4; - struct { - struct in6_addr daddr; - struct in6_addr saddr; - } v6; - } fam; -}; - -struct lsm_ioctlop_audit { - struct path path; - u16 cmd; -}; - -struct lsm_ibpkey_audit { - u64 subnet_prefix; - u16 pkey; -}; - -struct lsm_ibendport_audit { - char dev_name[64]; - u8 port; -}; - -struct apparmor_audit_data; - -struct common_audit_data { - char type; - union { - struct path path; - struct dentry *dentry; - struct inode *inode; - struct lsm_network_audit *net; - int cap; - int ipc_id; - struct task_struct *tsk; - struct { - key_serial_t key; - char *key_desc; - } key_struct; - char *kmod_name; - struct lsm_ioctlop_audit *op; - struct file *file; - struct lsm_ibpkey_audit *ibpkey; - struct lsm_ibendport_audit *ibendport; - int reason; - } u; - union { - struct apparmor_audit_data *apparmor_audit_data; - }; -}; - -typedef unsigned char Byte; - -typedef long unsigned int uLong; - -struct internal_state; - -struct z_stream_s { - const Byte *next_in; - uLong avail_in; - uLong total_in; - Byte *next_out; - uLong avail_out; - uLong total_out; - char *msg; - struct internal_state *state; - void *workspace; - int data_type; - uLong adler; - uLong reserved; -}; - -struct internal_state { - int dummy; -}; - -enum audit_mode { - AUDIT_NORMAL = 0, - AUDIT_QUIET_DENIED = 1, - AUDIT_QUIET = 2, - AUDIT_NOQUIET = 3, - AUDIT_ALL = 4, -}; - -enum aa_sfs_type { - AA_SFS_TYPE_BOOLEAN = 0, - AA_SFS_TYPE_STRING = 1, - AA_SFS_TYPE_U64 = 2, - AA_SFS_TYPE_FOPS = 3, - AA_SFS_TYPE_DIR = 4, -}; - -struct aa_sfs_entry { - const char *name; - struct dentry *dentry; - umode_t mode; - enum aa_sfs_type v_type; - union { - bool boolean; - char *string; - long unsigned int u64; - struct aa_sfs_entry *files; - } v; - const struct file_operations *file_ops; -}; - -enum aafs_ns_type { - AAFS_NS_DIR = 0, - AAFS_NS_PROFS = 1, - AAFS_NS_NS = 2, - AAFS_NS_RAW_DATA = 3, - AAFS_NS_LOAD = 4, - AAFS_NS_REPLACE = 5, - AAFS_NS_REMOVE = 6, - AAFS_NS_REVISION = 7, - AAFS_NS_COUNT = 8, - AAFS_NS_MAX_COUNT = 9, - AAFS_NS_SIZE = 10, - AAFS_NS_MAX_SIZE = 11, - AAFS_NS_OWNER = 12, - AAFS_NS_SIZEOF = 13, -}; - -enum aafs_prof_type { - AAFS_PROF_DIR = 0, - AAFS_PROF_PROFS = 1, - AAFS_PROF_NAME = 2, - AAFS_PROF_MODE = 3, - AAFS_PROF_ATTACH = 4, - AAFS_PROF_HASH = 5, - AAFS_PROF_RAW_DATA = 6, - AAFS_PROF_RAW_HASH = 7, - AAFS_PROF_RAW_ABI = 8, - AAFS_PROF_SIZEOF = 9, -}; - -enum ib_uverbs_write_cmds { - IB_USER_VERBS_CMD_GET_CONTEXT = 0, - IB_USER_VERBS_CMD_QUERY_DEVICE = 1, - IB_USER_VERBS_CMD_QUERY_PORT = 2, - IB_USER_VERBS_CMD_ALLOC_PD = 3, - IB_USER_VERBS_CMD_DEALLOC_PD = 4, - IB_USER_VERBS_CMD_CREATE_AH = 5, - IB_USER_VERBS_CMD_MODIFY_AH = 6, - IB_USER_VERBS_CMD_QUERY_AH = 7, - IB_USER_VERBS_CMD_DESTROY_AH = 8, - IB_USER_VERBS_CMD_REG_MR = 9, - IB_USER_VERBS_CMD_REG_SMR = 10, - IB_USER_VERBS_CMD_REREG_MR = 11, - IB_USER_VERBS_CMD_QUERY_MR = 12, - IB_USER_VERBS_CMD_DEREG_MR = 13, - IB_USER_VERBS_CMD_ALLOC_MW = 14, - IB_USER_VERBS_CMD_BIND_MW = 15, - IB_USER_VERBS_CMD_DEALLOC_MW = 16, - IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL = 17, - IB_USER_VERBS_CMD_CREATE_CQ = 18, - IB_USER_VERBS_CMD_RESIZE_CQ = 19, - IB_USER_VERBS_CMD_DESTROY_CQ = 20, - IB_USER_VERBS_CMD_POLL_CQ = 21, - IB_USER_VERBS_CMD_PEEK_CQ = 22, - IB_USER_VERBS_CMD_REQ_NOTIFY_CQ = 23, - IB_USER_VERBS_CMD_CREATE_QP = 24, - IB_USER_VERBS_CMD_QUERY_QP = 25, - IB_USER_VERBS_CMD_MODIFY_QP = 26, - IB_USER_VERBS_CMD_DESTROY_QP = 27, - IB_USER_VERBS_CMD_POST_SEND = 28, - IB_USER_VERBS_CMD_POST_RECV = 29, - IB_USER_VERBS_CMD_ATTACH_MCAST = 30, - IB_USER_VERBS_CMD_DETACH_MCAST = 31, - IB_USER_VERBS_CMD_CREATE_SRQ = 32, - IB_USER_VERBS_CMD_MODIFY_SRQ = 33, - IB_USER_VERBS_CMD_QUERY_SRQ = 34, - IB_USER_VERBS_CMD_DESTROY_SRQ = 35, - IB_USER_VERBS_CMD_POST_SRQ_RECV = 36, - IB_USER_VERBS_CMD_OPEN_XRCD = 37, - IB_USER_VERBS_CMD_CLOSE_XRCD = 38, - IB_USER_VERBS_CMD_CREATE_XSRQ = 39, - IB_USER_VERBS_CMD_OPEN_QP = 40, -}; - -enum ib_uverbs_wc_opcode { - IB_UVERBS_WC_SEND = 0, - IB_UVERBS_WC_RDMA_WRITE = 1, - IB_UVERBS_WC_RDMA_READ = 2, - IB_UVERBS_WC_COMP_SWAP = 3, - IB_UVERBS_WC_FETCH_ADD = 4, - IB_UVERBS_WC_BIND_MW = 5, - IB_UVERBS_WC_LOCAL_INV = 6, - IB_UVERBS_WC_TSO = 7, -}; - -enum ib_uverbs_create_qp_mask { - IB_UVERBS_CREATE_QP_MASK_IND_TABLE = 1, -}; - -enum ib_uverbs_wr_opcode { - IB_UVERBS_WR_RDMA_WRITE = 0, - IB_UVERBS_WR_RDMA_WRITE_WITH_IMM = 1, - IB_UVERBS_WR_SEND = 2, - IB_UVERBS_WR_SEND_WITH_IMM = 3, - IB_UVERBS_WR_RDMA_READ = 4, - IB_UVERBS_WR_ATOMIC_CMP_AND_SWP = 5, - IB_UVERBS_WR_ATOMIC_FETCH_AND_ADD = 6, - IB_UVERBS_WR_LOCAL_INV = 7, - IB_UVERBS_WR_BIND_MW = 8, - IB_UVERBS_WR_SEND_WITH_INV = 9, - IB_UVERBS_WR_TSO = 10, - IB_UVERBS_WR_RDMA_READ_WITH_INV = 11, - IB_UVERBS_WR_MASKED_ATOMIC_CMP_AND_SWP = 12, - IB_UVERBS_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13, -}; - -enum ib_uverbs_access_flags { - IB_UVERBS_ACCESS_LOCAL_WRITE = 1, - IB_UVERBS_ACCESS_REMOTE_WRITE = 2, - IB_UVERBS_ACCESS_REMOTE_READ = 4, - IB_UVERBS_ACCESS_REMOTE_ATOMIC = 8, - IB_UVERBS_ACCESS_MW_BIND = 16, - IB_UVERBS_ACCESS_ZERO_BASED = 32, - IB_UVERBS_ACCESS_ON_DEMAND = 64, - IB_UVERBS_ACCESS_HUGETLB = 128, - IB_UVERBS_ACCESS_RELAXED_ORDERING = 1048576, - IB_UVERBS_ACCESS_OPTIONAL_RANGE = 1072693248, -}; - -enum ib_uverbs_srq_type { - IB_UVERBS_SRQT_BASIC = 0, - IB_UVERBS_SRQT_XRC = 1, - IB_UVERBS_SRQT_TM = 2, -}; - -enum ib_uverbs_wq_type { - IB_UVERBS_WQT_RQ = 0, -}; - -enum ib_uverbs_wq_flags { - IB_UVERBS_WQ_FLAGS_CVLAN_STRIPPING = 1, - IB_UVERBS_WQ_FLAGS_SCATTER_FCS = 2, - IB_UVERBS_WQ_FLAGS_DELAY_DROP = 4, - IB_UVERBS_WQ_FLAGS_PCI_WRITE_END_PADDING = 8, -}; - -enum ib_uverbs_qp_type { - IB_UVERBS_QPT_RC = 2, - IB_UVERBS_QPT_UC = 3, - IB_UVERBS_QPT_UD = 4, - IB_UVERBS_QPT_RAW_PACKET = 8, - IB_UVERBS_QPT_XRC_INI = 9, - IB_UVERBS_QPT_XRC_TGT = 10, - IB_UVERBS_QPT_DRIVER = 255, -}; - -enum ib_uverbs_qp_create_flags { - IB_UVERBS_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 2, - IB_UVERBS_QP_CREATE_SCATTER_FCS = 256, - IB_UVERBS_QP_CREATE_CVLAN_STRIPPING = 512, - IB_UVERBS_QP_CREATE_PCI_WRITE_END_PADDING = 2048, - IB_UVERBS_QP_CREATE_SQ_SIG_ALL = 4096, -}; - -enum ib_uverbs_gid_type { - IB_UVERBS_GID_TYPE_IB = 0, - IB_UVERBS_GID_TYPE_ROCE_V1 = 1, - IB_UVERBS_GID_TYPE_ROCE_V2 = 2, -}; - -enum ib_poll_context { - IB_POLL_SOFTIRQ = 0, - IB_POLL_WORKQUEUE = 1, - IB_POLL_UNBOUND_WORKQUEUE = 2, - IB_POLL_LAST_POOL_TYPE = 2, - IB_POLL_DIRECT = 3, -}; - -struct table_header { - u16 td_id; - u16 td_flags; - u32 td_hilen; - u32 td_lolen; - char td_data[0]; -}; - -struct aa_dfa { - struct kref count; - u16 flags; - u32 max_oob; - struct table_header *tables[8]; -}; - -struct aa_policy { - const char *name; - char *hname; - struct list_head list; - struct list_head profiles; -}; - -struct aa_labelset { - rwlock_t lock; - struct rb_root root; -}; - -enum label_flags { - FLAG_HAT = 1, - FLAG_UNCONFINED = 2, - FLAG_NULL = 4, - FLAG_IX_ON_NAME_ERROR = 8, - FLAG_IMMUTIBLE = 16, - FLAG_USER_DEFINED = 32, - FLAG_NO_LIST_REF = 64, - FLAG_NS_COUNT = 128, - FLAG_IN_TREE = 256, - FLAG_PROFILE = 512, - FLAG_EXPLICIT = 1024, - FLAG_STALE = 2048, - FLAG_RENAMED = 4096, - FLAG_REVOKED = 8192, -}; - -struct aa_label; - -struct aa_proxy { - struct kref count; - struct aa_label *label; -}; - -struct aa_profile; - -struct aa_label { - struct kref count; - struct rb_node node; - struct callback_head rcu; - struct aa_proxy *proxy; - char *hname; - long int flags; - u32 secid; - int size; - struct aa_profile *vec[0]; -}; - -struct label_it { - int i; - int j; -}; - -struct aa_policydb { - struct aa_dfa *dfa; - unsigned int start[17]; -}; - -struct aa_domain { - int size; - char **table; -}; - -struct aa_file_rules { - unsigned int start; - struct aa_dfa *dfa; - struct aa_domain trans; -}; - -struct aa_caps { - kernel_cap_t allow; - kernel_cap_t audit; - kernel_cap_t denied; - kernel_cap_t quiet; - kernel_cap_t kill; - kernel_cap_t extended; -}; - -struct aa_rlimit { - unsigned int mask; - struct rlimit limits[16]; -}; - -struct aa_ns; - -struct aa_secmark; - -struct aa_loaddata; - -struct aa_profile { - struct aa_policy base; - struct aa_profile *parent; - struct aa_ns *ns; - const char *rename; - const char *attach; - struct aa_dfa *xmatch; - int xmatch_len; - enum audit_mode audit; - long int mode; - u32 path_flags; - const char *disconnected; - int size; - struct aa_policydb policy; - struct aa_file_rules file; - struct aa_caps caps; - int xattr_count; - char **xattrs; - struct aa_rlimit rlimits; - int secmark_count; - struct aa_secmark *secmark; - struct aa_loaddata *rawdata; - unsigned char *hash; - char *dirname; - struct dentry *dents[9]; - struct rhashtable *data; - struct aa_label label; -}; - -struct aa_perms { - u32 allow; - u32 audit; - u32 deny; - u32 quiet; - u32 kill; - u32 stop; - u32 complain; - u32 cond; - u32 hide; - u32 prompt; - u16 xindex; -}; - -struct path_cond { - kuid_t uid; - umode_t mode; -}; - -struct aa_secmark { - u8 audit; - u8 deny; - u32 secid; - char *label; -}; - -enum profile_mode { - APPARMOR_ENFORCE = 0, - APPARMOR_COMPLAIN = 1, - APPARMOR_KILL = 2, - APPARMOR_UNCONFINED = 3, -}; - -struct aa_data { - char *key; - u32 size; - char *data; - struct rhash_head head; -}; - -struct aa_ns_acct { - int max_size; - int max_count; - int size; - int count; -}; - -struct aa_ns { - struct aa_policy base; - struct aa_ns *parent; - struct mutex lock; - struct aa_ns_acct acct; - struct aa_profile *unconfined; - struct list_head sub_ns; - atomic_t uniq_null; - long int uniq_id; - int level; - long int revision; - wait_queue_head_t wait; - struct aa_labelset labels; - struct list_head rawdata_list; - struct dentry *dents[13]; -}; - -struct aa_loaddata { - struct kref count; - struct list_head list; - struct work_struct work; - struct dentry *dents[6]; - struct aa_ns *ns; - char *name; - size_t size; - size_t compressed_size; - long int revision; - int abi; - unsigned char *hash; - char *data; -}; - -enum { - AAFS_LOADDATA_ABI = 0, - AAFS_LOADDATA_REVISION = 1, - AAFS_LOADDATA_HASH = 2, - AAFS_LOADDATA_DATA = 3, - AAFS_LOADDATA_COMPRESSED_SIZE = 4, - AAFS_LOADDATA_DIR = 5, - AAFS_LOADDATA_NDENTS = 6, -}; - -struct rawdata_f_data { - struct aa_loaddata *loaddata; -}; - -struct aa_revision { - struct aa_ns *ns; - long int last_read; -}; - -struct multi_transaction { - struct kref count; - ssize_t size; - char data[0]; -}; - -struct apparmor_audit_data { - int error; - int type; - const char *op; - struct aa_label *label; - const char *name; - const char *info; - u32 request; - u32 denied; - union { - struct { - struct aa_label *peer; - union { - struct { - const char *target; - kuid_t ouid; - } fs; - struct { - int rlim; - long unsigned int max; - } rlim; - struct { - int signal; - int unmappedsig; - }; - struct { - int type; - int protocol; - struct sock *peer_sk; - void *addr; - int addrlen; - } net; - }; - }; - struct { - struct aa_profile *profile; - const char *ns; - long int pos; - } iface; - struct { - const char *src_name; - const char *type; - const char *trans; - const char *data; - long unsigned int flags; - } mnt; - }; -}; - -enum audit_type { - AUDIT_APPARMOR_AUDIT = 0, - AUDIT_APPARMOR_ALLOWED = 1, - AUDIT_APPARMOR_DENIED = 2, - AUDIT_APPARMOR_HINT = 3, - AUDIT_APPARMOR_STATUS = 4, - AUDIT_APPARMOR_ERROR = 5, - AUDIT_APPARMOR_KILL = 6, - AUDIT_APPARMOR_AUTO = 7, -}; - -struct aa_audit_rule { - struct aa_label *label; -}; - -struct audit_cache { - struct aa_profile *profile; - kernel_cap_t caps; -}; - -struct aa_task_ctx { - struct aa_label *nnp; - struct aa_label *onexec; - struct aa_label *previous; - u64 token; -}; - -struct counted_str { - struct kref count; - char name[0]; -}; - -struct match_workbuf { - unsigned int count; - unsigned int pos; - unsigned int len; - unsigned int size; - unsigned int history[24]; -}; - -enum path_flags { - PATH_IS_DIR = 1, - PATH_CONNECT_PATH = 4, - PATH_CHROOT_REL = 8, - PATH_CHROOT_NSCONNECT = 16, - PATH_DELEGATE_DELETED = 32768, - PATH_MEDIATE_DELETED = 65536, -}; - -struct aa_load_ent { - struct list_head list; - struct aa_profile *new; - struct aa_profile *old; - struct aa_profile *rename; - const char *ns_name; -}; - -enum aa_code { - AA_U8 = 0, - AA_U16 = 1, - AA_U32 = 2, - AA_U64 = 3, - AA_NAME = 4, - AA_STRING = 5, - AA_BLOB = 6, - AA_STRUCT = 7, - AA_STRUCTEND = 8, - AA_LIST = 9, - AA_LISTEND = 10, - AA_ARRAY = 11, - AA_ARRAYEND = 12, -}; - -struct aa_ext { - void *start; - void *end; - void *pos; - u32 version; -}; - -struct nf_hook_state; - -typedef unsigned int nf_hookfn(void *, struct sk_buff *, const struct nf_hook_state *); - -struct nf_hook_entry { - nf_hookfn *hook; - void *priv; -}; - -struct nf_hook_entries { - u16 num_hook_entries; - struct nf_hook_entry hooks[0]; -}; - -struct nf_hook_state { - unsigned int hook; - u_int8_t pf; - struct net_device *in; - struct net_device *out; - struct sock *sk; - struct net *net; - int (*okfn)(struct net *, struct sock *, struct sk_buff *); -}; - -struct aa_file_ctx { - spinlock_t lock; - struct aa_label *label; - u32 allow; -}; - -struct aa_sk_ctx { - struct aa_label *label; - struct aa_label *peer; -}; - -union aa_buffer { - struct list_head list; - char buffer[1]; -}; - -struct tty_file_private { - struct tty_struct *tty; - struct file *file; - struct list_head list; -}; - -enum devcg_behavior { - DEVCG_DEFAULT_NONE = 0, - DEVCG_DEFAULT_ALLOW = 1, - DEVCG_DEFAULT_DENY = 2, -}; - -struct dev_exception_item { - u32 major; - u32 minor; - short int type; - short int access; - struct list_head list; - struct callback_head rcu; -}; - -struct dev_cgroup { - struct cgroup_subsys_state css; - struct list_head exceptions; - enum devcg_behavior behavior; -}; - -enum integrity_status { - INTEGRITY_PASS = 0, - INTEGRITY_PASS_IMMUTABLE = 1, - INTEGRITY_FAIL = 2, - INTEGRITY_NOLABEL = 3, - INTEGRITY_NOXATTRS = 4, - INTEGRITY_UNKNOWN = 5, -}; - -struct ima_digest_data { - u8 algo; - u8 length; - union { - struct { - u8 unused; - u8 type; - } sha1; - struct { - u8 type; - u8 algo; - } ng; - u8 data[2]; - } xattr; - u8 digest[0]; -}; - -struct integrity_iint_cache { - struct rb_node rb_node; - struct mutex mutex; - struct inode *inode; - u64 version; - long unsigned int flags; - long unsigned int measured_pcrs; - long unsigned int atomic_flags; - enum integrity_status ima_file_status: 4; - enum integrity_status ima_mmap_status: 4; - enum integrity_status ima_bprm_status: 4; - enum integrity_status ima_read_status: 4; - enum integrity_status ima_creds_status: 4; - enum integrity_status evm_status: 4; - struct ima_digest_data *ima_hash; -}; - -enum { - CRYPTO_MSG_ALG_REQUEST = 0, - CRYPTO_MSG_ALG_REGISTER = 1, - CRYPTO_MSG_ALG_LOADED = 2, -}; - -struct crypto_larval { - struct crypto_alg alg; - struct crypto_alg *adult; - struct completion completion; - u32 mask; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct crypto_cipher { - struct crypto_tfm base; -}; - -enum { - CRYPTOA_UNSPEC = 0, - CRYPTOA_ALG = 1, - CRYPTOA_TYPE = 2, - CRYPTOA_U32 = 3, - __CRYPTOA_MAX = 4, -}; - -struct crypto_attr_alg { - char name[128]; -}; - -struct crypto_attr_type { - u32 type; - u32 mask; -}; - -struct crypto_attr_u32 { - u32 num; -}; - -struct rtattr { - short unsigned int rta_len; - short unsigned int rta_type; -}; - -struct crypto_queue { - struct list_head list; - struct list_head *backlog; - unsigned int qlen; - unsigned int max_qlen; -}; - -enum { - NAPI_STATE_SCHED = 0, - NAPI_STATE_MISSED = 1, - NAPI_STATE_DISABLE = 2, - NAPI_STATE_NPSVC = 3, - NAPI_STATE_LISTED = 4, - NAPI_STATE_NO_BUSY_POLL = 5, - NAPI_STATE_IN_BUSY_POLL = 6, -}; - -enum bpf_xdp_mode { - XDP_MODE_SKB = 0, - XDP_MODE_DRV = 1, - XDP_MODE_HW = 2, - __MAX_XDP_MODE = 3, -}; - -enum { - NETIF_MSG_DRV_BIT = 0, - NETIF_MSG_PROBE_BIT = 1, - NETIF_MSG_LINK_BIT = 2, - NETIF_MSG_TIMER_BIT = 3, - NETIF_MSG_IFDOWN_BIT = 4, - NETIF_MSG_IFUP_BIT = 5, - NETIF_MSG_RX_ERR_BIT = 6, - NETIF_MSG_TX_ERR_BIT = 7, - NETIF_MSG_TX_QUEUED_BIT = 8, - NETIF_MSG_INTR_BIT = 9, - NETIF_MSG_TX_DONE_BIT = 10, - NETIF_MSG_RX_STATUS_BIT = 11, - NETIF_MSG_PKTDATA_BIT = 12, - NETIF_MSG_HW_BIT = 13, - NETIF_MSG_WOL_BIT = 14, - NETIF_MSG_CLASS_COUNT = 15, -}; - -struct scatter_walk { - struct scatterlist *sg; - unsigned int offset; -}; - -struct aead_request { - struct crypto_async_request base; - unsigned int assoclen; - unsigned int cryptlen; - u8 *iv; - struct scatterlist *src; - struct scatterlist *dst; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__ctx[0]; -}; - -struct crypto_aead; - -struct aead_alg { - int (*setkey)(struct crypto_aead *, const u8 *, unsigned int); - int (*setauthsize)(struct crypto_aead *, unsigned int); - int (*encrypt)(struct aead_request *); - int (*decrypt)(struct aead_request *); - int (*init)(struct crypto_aead *); - void (*exit)(struct crypto_aead *); - unsigned int ivsize; - unsigned int maxauthsize; - unsigned int chunksize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct crypto_aead { - unsigned int authsize; - unsigned int reqsize; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_tfm base; -}; - -struct aead_instance { - void (*free)(struct aead_instance *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct { - char head[128]; - struct crypto_instance base; - } s; - struct aead_alg alg; - }; -}; - -struct crypto_aead_spawn { - struct crypto_spawn base; -}; - -enum crypto_attr_type_t { - CRYPTOCFGA_UNSPEC = 0, - CRYPTOCFGA_PRIORITY_VAL = 1, - CRYPTOCFGA_REPORT_LARVAL = 2, - CRYPTOCFGA_REPORT_HASH = 3, - CRYPTOCFGA_REPORT_BLKCIPHER = 4, - CRYPTOCFGA_REPORT_AEAD = 5, - CRYPTOCFGA_REPORT_COMPRESS = 6, - CRYPTOCFGA_REPORT_RNG = 7, - CRYPTOCFGA_REPORT_CIPHER = 8, - CRYPTOCFGA_REPORT_AKCIPHER = 9, - CRYPTOCFGA_REPORT_KPP = 10, - CRYPTOCFGA_REPORT_ACOMP = 11, - CRYPTOCFGA_STAT_LARVAL = 12, - CRYPTOCFGA_STAT_HASH = 13, - CRYPTOCFGA_STAT_BLKCIPHER = 14, - CRYPTOCFGA_STAT_AEAD = 15, - CRYPTOCFGA_STAT_COMPRESS = 16, - CRYPTOCFGA_STAT_RNG = 17, - CRYPTOCFGA_STAT_CIPHER = 18, - CRYPTOCFGA_STAT_AKCIPHER = 19, - CRYPTOCFGA_STAT_KPP = 20, - CRYPTOCFGA_STAT_ACOMP = 21, - __CRYPTOCFGA_MAX = 22, -}; - -struct crypto_report_aead { - char type[64]; - char geniv[64]; - unsigned int blocksize; - unsigned int maxauthsize; - unsigned int ivsize; -}; - -struct crypto_sync_skcipher; - -struct aead_geniv_ctx { - spinlock_t lock; - struct crypto_aead *child; - struct crypto_sync_skcipher *sknull; - u8 salt[0]; -}; - -struct crypto_rng; - -struct rng_alg { - int (*generate)(struct crypto_rng *, const u8 *, unsigned int, u8 *, unsigned int); - int (*seed)(struct crypto_rng *, const u8 *, unsigned int); - void (*set_ent)(struct crypto_rng *, const u8 *, unsigned int); - unsigned int seedsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct crypto_rng { - struct crypto_tfm base; -}; - -struct crypto_cipher_spawn { - struct crypto_spawn base; -}; - -struct crypto_sync_skcipher___2 { - struct crypto_skcipher base; -}; - -struct skcipher_instance { - void (*free)(struct skcipher_instance *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct { - char head[128]; - struct crypto_instance base; - } s; - struct skcipher_alg alg; - }; -}; - -struct crypto_skcipher_spawn { - struct crypto_spawn base; -}; - -struct skcipher_walk { - union { - struct { - struct page *page; - long unsigned int offset; - } phys; - struct { - u8 *page; - void *addr; - } virt; - } src; - union { - struct { - struct page *page; - long unsigned int offset; - } phys; - struct { - u8 *page; - void *addr; - } virt; - } dst; - struct scatter_walk in; - unsigned int nbytes; - struct scatter_walk out; - unsigned int total; - struct list_head buffers; - u8 *page; - u8 *buffer; - u8 *oiv; - void *iv; - unsigned int ivsize; - int flags; - unsigned int blocksize; - unsigned int stride; - unsigned int alignmask; -}; - -struct skcipher_ctx_simple { - struct crypto_cipher *cipher; -}; - -struct crypto_report_blkcipher { - char type[64]; - char geniv[64]; - unsigned int blocksize; - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; -}; - -enum { - SKCIPHER_WALK_PHYS = 1, - SKCIPHER_WALK_SLOW = 2, - SKCIPHER_WALK_COPY = 4, - SKCIPHER_WALK_DIFF = 8, - SKCIPHER_WALK_SLEEP = 16, -}; - -struct skcipher_walk_buffer { - struct list_head entry; - struct scatter_walk dst; - unsigned int len; - u8 *data; - u8 buffer[0]; -}; - -struct hash_alg_common { - unsigned int digestsize; - unsigned int statesize; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct ahash_request { - struct crypto_async_request base; - unsigned int nbytes; - struct scatterlist *src; - u8 *result; - void *priv; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__ctx[0]; -}; - -struct crypto_ahash; - -struct ahash_alg { - int (*init)(struct ahash_request *); - int (*update)(struct ahash_request *); - int (*final)(struct ahash_request *); - int (*finup)(struct ahash_request *); - int (*digest)(struct ahash_request *); - int (*export)(struct ahash_request *, void *); - int (*import)(struct ahash_request *, const void *); - int (*setkey)(struct crypto_ahash *, const u8 *, unsigned int); - int (*init_tfm)(struct crypto_ahash *); - void (*exit_tfm)(struct crypto_ahash *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct hash_alg_common halg; -}; - -struct crypto_ahash { - int (*init)(struct ahash_request *); - int (*update)(struct ahash_request *); - int (*final)(struct ahash_request *); - int (*finup)(struct ahash_request *); - int (*digest)(struct ahash_request *); - int (*export)(struct ahash_request *, void *); - int (*import)(struct ahash_request *, const void *); - int (*setkey)(struct crypto_ahash *, const u8 *, unsigned int); - unsigned int reqsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_tfm base; -}; - -struct crypto_hash_walk { - char *data; - unsigned int offset; - unsigned int alignmask; - struct page *pg; - unsigned int entrylen; - unsigned int total; - struct scatterlist *sg; - unsigned int flags; -}; - -struct ahash_instance { - void (*free)(struct ahash_instance *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct { - char head[256]; - struct crypto_instance base; - } s; - struct ahash_alg alg; - }; -}; - -struct crypto_ahash_spawn { - struct crypto_spawn base; -}; - -struct crypto_report_hash { - char type[64]; - unsigned int blocksize; - unsigned int digestsize; -}; - -struct ahash_request_priv { - crypto_completion_t complete; - void *data; - u8 *result; - u32 flags; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *ubuf[0]; -}; - -struct shash_instance { - void (*free)(struct shash_instance *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct { - char head[256]; - struct crypto_instance base; - } s; - struct shash_alg alg; - }; -}; - -struct crypto_shash_spawn { - struct crypto_spawn base; -}; - -struct crypto_report_akcipher { - char type[64]; -}; - -struct akcipher_request { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int src_len; - unsigned int dst_len; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__ctx[0]; -}; - -struct crypto_akcipher { - struct crypto_tfm base; -}; - -struct akcipher_alg { - int (*sign)(struct akcipher_request *); - int (*verify)(struct akcipher_request *); - int (*encrypt)(struct akcipher_request *); - int (*decrypt)(struct akcipher_request *); - int (*set_pub_key)(struct crypto_akcipher *, const void *, unsigned int); - int (*set_priv_key)(struct crypto_akcipher *, const void *, unsigned int); - unsigned int (*max_size)(struct crypto_akcipher *); - int (*init)(struct crypto_akcipher *); - void (*exit)(struct crypto_akcipher *); - unsigned int reqsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct akcipher_instance { - void (*free)(struct akcipher_instance *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct { - char head[128]; - struct crypto_instance base; - } s; - struct akcipher_alg alg; - }; -}; - -struct crypto_akcipher_spawn { - struct crypto_spawn base; -}; - -struct crypto_report_kpp { - char type[64]; -}; - -struct kpp_request { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int src_len; - unsigned int dst_len; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__ctx[0]; -}; - -struct crypto_kpp { - struct crypto_tfm base; -}; - -struct kpp_alg { - int (*set_secret)(struct crypto_kpp *, const void *, unsigned int); - int (*generate_public_key)(struct kpp_request *); - int (*compute_shared_secret)(struct kpp_request *); - unsigned int (*max_size)(struct crypto_kpp *); - int (*init)(struct crypto_kpp *); - void (*exit)(struct crypto_kpp *); - unsigned int reqsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -enum asn1_class { - ASN1_UNIV = 0, - ASN1_APPL = 1, - ASN1_CONT = 2, - ASN1_PRIV = 3, -}; - -enum asn1_method { - ASN1_PRIM = 0, - ASN1_CONS = 1, -}; - -enum asn1_tag { - ASN1_EOC = 0, - ASN1_BOOL = 1, - ASN1_INT = 2, - ASN1_BTS = 3, - ASN1_OTS = 4, - ASN1_NULL = 5, - ASN1_OID = 6, - ASN1_ODE = 7, - ASN1_EXT = 8, - ASN1_REAL = 9, - ASN1_ENUM = 10, - ASN1_EPDV = 11, - ASN1_UTF8STR = 12, - ASN1_RELOID = 13, - ASN1_SEQ = 16, - ASN1_SET = 17, - ASN1_NUMSTR = 18, - ASN1_PRNSTR = 19, - ASN1_TEXSTR = 20, - ASN1_VIDSTR = 21, - ASN1_IA5STR = 22, - ASN1_UNITIM = 23, - ASN1_GENTIM = 24, - ASN1_GRASTR = 25, - ASN1_VISSTR = 26, - ASN1_GENSTR = 27, - ASN1_UNISTR = 28, - ASN1_CHRSTR = 29, - ASN1_BMPSTR = 30, - ASN1_LONG_TAG = 31, -}; - -typedef int (*asn1_action_t)(void *, size_t, unsigned char, const void *, size_t); - -struct asn1_decoder { - const unsigned char *machine; - size_t machlen; - const asn1_action_t *actions; -}; - -enum asn1_opcode { - ASN1_OP_MATCH = 0, - ASN1_OP_MATCH_OR_SKIP = 1, - ASN1_OP_MATCH_ACT = 2, - ASN1_OP_MATCH_ACT_OR_SKIP = 3, - ASN1_OP_MATCH_JUMP = 4, - ASN1_OP_MATCH_JUMP_OR_SKIP = 5, - ASN1_OP_MATCH_ANY = 8, - ASN1_OP_MATCH_ANY_OR_SKIP = 9, - ASN1_OP_MATCH_ANY_ACT = 10, - ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 11, - ASN1_OP_COND_MATCH_OR_SKIP = 17, - ASN1_OP_COND_MATCH_ACT_OR_SKIP = 19, - ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 21, - ASN1_OP_COND_MATCH_ANY = 24, - ASN1_OP_COND_MATCH_ANY_OR_SKIP = 25, - ASN1_OP_COND_MATCH_ANY_ACT = 26, - ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 27, - ASN1_OP_COND_FAIL = 28, - ASN1_OP_COMPLETE = 29, - ASN1_OP_ACT = 30, - ASN1_OP_MAYBE_ACT = 31, - ASN1_OP_END_SEQ = 32, - ASN1_OP_END_SET = 33, - ASN1_OP_END_SEQ_OF = 34, - ASN1_OP_END_SET_OF = 35, - ASN1_OP_END_SEQ_ACT = 36, - ASN1_OP_END_SET_ACT = 37, - ASN1_OP_END_SEQ_OF_ACT = 38, - ASN1_OP_END_SET_OF_ACT = 39, - ASN1_OP_RETURN = 40, - ASN1_OP__NR = 41, -}; - -enum rsapubkey_actions { - ACT_rsa_get_e = 0, - ACT_rsa_get_n = 1, - NR__rsapubkey_actions = 2, -}; - -enum rsaprivkey_actions { - ACT_rsa_get_d = 0, - ACT_rsa_get_dp = 1, - ACT_rsa_get_dq = 2, - ACT_rsa_get_e___2 = 3, - ACT_rsa_get_n___2 = 4, - ACT_rsa_get_p = 5, - ACT_rsa_get_q = 6, - ACT_rsa_get_qinv = 7, - NR__rsaprivkey_actions = 8, -}; - -typedef long unsigned int mpi_limb_t; - -struct gcry_mpi { - int alloced; - int nlimbs; - int nbits; - int sign; - unsigned int flags; - mpi_limb_t *d; -}; - -typedef struct gcry_mpi *MPI; - -struct rsa_key { - const u8 *n; - const u8 *e; - const u8 *d; - const u8 *p; - const u8 *q; - const u8 *dp; - const u8 *dq; - const u8 *qinv; - size_t n_sz; - size_t e_sz; - size_t d_sz; - size_t p_sz; - size_t q_sz; - size_t dp_sz; - size_t dq_sz; - size_t qinv_sz; -}; - -struct rsa_mpi_key { - MPI n; - MPI e; - MPI d; -}; - -struct asn1_decoder___2; - -struct rsa_asn1_template { - const char *name; - const u8 *data; - size_t size; -}; - -struct pkcs1pad_ctx { - struct crypto_akcipher *child; - unsigned int key_size; -}; - -struct pkcs1pad_inst_ctx { - struct crypto_akcipher_spawn spawn; - const struct rsa_asn1_template *digest_info; -}; - -struct pkcs1pad_request { - struct scatterlist in_sg[2]; - struct scatterlist out_sg[1]; - uint8_t *in_buf; - uint8_t *out_buf; - long: 64; - long: 64; - struct akcipher_request child_req; -}; - -struct crypto_report_acomp { - char type[64]; -}; - -struct acomp_req { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int slen; - unsigned int dlen; - u32 flags; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - void *__ctx[0]; -}; - -struct crypto_acomp { - int (*compress)(struct acomp_req *); - int (*decompress)(struct acomp_req *); - void (*dst_free)(struct scatterlist *); - unsigned int reqsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_tfm base; -}; - -struct acomp_alg { - int (*compress)(struct acomp_req *); - int (*decompress)(struct acomp_req *); - void (*dst_free)(struct scatterlist *); - int (*init)(struct crypto_acomp *); - void (*exit)(struct crypto_acomp *); - unsigned int reqsize; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct crypto_report_comp { - char type[64]; -}; - -struct crypto_scomp { - struct crypto_tfm base; -}; - -struct scomp_alg { - void * (*alloc_ctx)(struct crypto_scomp *); - void (*free_ctx)(struct crypto_scomp *, void *); - int (*compress)(struct crypto_scomp *, const u8 *, unsigned int, u8 *, unsigned int *, void *); - int (*decompress)(struct crypto_scomp *, const u8 *, unsigned int, u8 *, unsigned int *, void *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct crypto_alg base; -}; - -struct scomp_scratch { - spinlock_t lock; - void *src; - void *dst; -}; - -struct cryptomgr_param { - struct rtattr *tb[34]; - struct { - struct rtattr attr; - struct crypto_attr_type data; - } type; - union { - struct rtattr attr; - struct { - struct rtattr attr; - struct crypto_attr_alg data; - } alg; - struct { - struct rtattr attr; - struct crypto_attr_u32 data; - } nu32; - } attrs[32]; - char template[128]; - struct crypto_larval *larval; - u32 otype; - u32 omask; -}; - -struct crypto_test_param { - char driver[128]; - char alg[128]; - u32 type; -}; - -struct hmac_ctx { - struct crypto_shash *hash; -}; - -struct sha1_state { - u32 state[5]; - u64 count; - u8 buffer[64]; -}; - -typedef void sha1_block_fn(struct sha1_state *, const u8 *, int); - -struct sha256_state { - u32 state[8]; - u64 count; - u8 buf[64]; -}; - -struct sha512_state { - u64 state[8]; - u64 count[2]; - u8 buf[128]; -}; - -typedef void sha512_block_fn(struct sha512_state *, const u8 *, int); - -struct crypto_cts_ctx { - struct crypto_skcipher *child; -}; - -struct crypto_cts_reqctx { - struct scatterlist sg[2]; - unsigned int offset; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct skcipher_request subreq; -}; - -typedef struct { - u64 a; - u64 b; -} u128; - -typedef struct { - __le64 b; - __le64 a; -} le128; - -struct xts_tfm_ctx { - struct crypto_skcipher *child; - struct crypto_cipher *tweak; -}; - -struct xts_instance_ctx { - struct crypto_skcipher_spawn spawn; - char name[128]; -}; - -struct xts_request_ctx { - le128 t; - struct scatterlist *tail; - struct scatterlist sg[2]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct skcipher_request subreq; -}; - -struct des_ctx { - u32 expkey[32]; -}; - -struct des3_ede_ctx { - u32 expkey[96]; -}; - -struct crypto_aes_ctx { - u32 key_enc[60]; - u32 key_dec[60]; - u32 key_length; -}; - -struct chksum_ctx { - u32 key; -}; - -struct chksum_desc_ctx { - u32 crc; -}; - -struct lzo_ctx { - void *lzo_comp_mem; -}; - -struct lzorle_ctx { - void *lzorle_comp_mem; -}; - -struct crypto_report_rng { - char type[64]; - unsigned int seedsize; -}; - -enum asymmetric_payload_bits { - asym_crypto = 0, - asym_subtype = 1, - asym_key_ids = 2, - asym_auth = 3, -}; - -struct asymmetric_key_id { - short unsigned int len; - unsigned char data[0]; -}; - -struct asymmetric_key_ids { - void *id[2]; -}; - -struct public_key_signature; - -struct asymmetric_key_subtype { - struct module *owner; - const char *name; - short unsigned int name_len; - void (*describe)(const struct key *, struct seq_file *); - void (*destroy)(void *, void *); - int (*query)(const struct kernel_pkey_params *, struct kernel_pkey_query *); - int (*eds_op)(struct kernel_pkey_params *, const void *, void *); - int (*verify_signature)(const struct key *, const struct public_key_signature *); -}; - -struct public_key_signature { - struct asymmetric_key_id *auth_ids[2]; - u8 *s; - u8 *digest; - u32 s_size; - u32 digest_size; - const char *pkey_algo; - const char *hash_algo; - const char *encoding; - const void *data; - unsigned int data_size; -}; - -struct asymmetric_key_parser { - struct list_head link; - struct module *owner; - const char *name; - int (*parse)(struct key_preparsed_payload *); -}; - -enum OID { - OID_id_dsa_with_sha1 = 0, - OID_id_dsa = 1, - OID_id_ecdsa_with_sha1 = 2, - OID_id_ecPublicKey = 3, - OID_rsaEncryption = 4, - OID_md2WithRSAEncryption = 5, - OID_md3WithRSAEncryption = 6, - OID_md4WithRSAEncryption = 7, - OID_sha1WithRSAEncryption = 8, - OID_sha256WithRSAEncryption = 9, - OID_sha384WithRSAEncryption = 10, - OID_sha512WithRSAEncryption = 11, - OID_sha224WithRSAEncryption = 12, - OID_data = 13, - OID_signed_data = 14, - OID_email_address = 15, - OID_contentType = 16, - OID_messageDigest = 17, - OID_signingTime = 18, - OID_smimeCapabilites = 19, - OID_smimeAuthenticatedAttrs = 20, - OID_md2 = 21, - OID_md4 = 22, - OID_md5 = 23, - OID_msIndirectData = 24, - OID_msStatementType = 25, - OID_msSpOpusInfo = 26, - OID_msPeImageDataObjId = 27, - OID_msIndividualSPKeyPurpose = 28, - OID_msOutlookExpress = 29, - OID_certAuthInfoAccess = 30, - OID_sha1 = 31, - OID_sha256 = 32, - OID_sha384 = 33, - OID_sha512 = 34, - OID_sha224 = 35, - OID_commonName = 36, - OID_surname = 37, - OID_countryName = 38, - OID_locality = 39, - OID_stateOrProvinceName = 40, - OID_organizationName = 41, - OID_organizationUnitName = 42, - OID_title = 43, - OID_description = 44, - OID_name = 45, - OID_givenName = 46, - OID_initials = 47, - OID_generationalQualifier = 48, - OID_subjectKeyIdentifier = 49, - OID_keyUsage = 50, - OID_subjectAltName = 51, - OID_issuerAltName = 52, - OID_basicConstraints = 53, - OID_crlDistributionPoints = 54, - OID_certPolicies = 55, - OID_authorityKeyIdentifier = 56, - OID_extKeyUsage = 57, - OID_gostCPSignA = 58, - OID_gostCPSignB = 59, - OID_gostCPSignC = 60, - OID_gost2012PKey256 = 61, - OID_gost2012PKey512 = 62, - OID_gost2012Digest256 = 63, - OID_gost2012Digest512 = 64, - OID_gost2012Signature256 = 65, - OID_gost2012Signature512 = 66, - OID_gostTC26Sign256A = 67, - OID_gostTC26Sign256B = 68, - OID_gostTC26Sign256C = 69, - OID_gostTC26Sign256D = 70, - OID_gostTC26Sign512A = 71, - OID_gostTC26Sign512B = 72, - OID_gostTC26Sign512C = 73, - OID_sm2 = 74, - OID_sm3 = 75, - OID_SM2_with_SM3 = 76, - OID_sm3WithRSAEncryption = 77, - OID__NR = 78, -}; - -struct public_key { - void *key; - u32 keylen; - enum OID algo; - void *params; - u32 paramlen; - bool key_is_private; - const char *id_type; - const char *pkey_algo; -}; - -enum x509_actions { - ACT_x509_extract_key_data = 0, - ACT_x509_extract_name_segment = 1, - ACT_x509_note_OID = 2, - ACT_x509_note_issuer = 3, - ACT_x509_note_not_after = 4, - ACT_x509_note_not_before = 5, - ACT_x509_note_params = 6, - ACT_x509_note_pkey_algo = 7, - ACT_x509_note_serial = 8, - ACT_x509_note_signature = 9, - ACT_x509_note_subject = 10, - ACT_x509_note_tbs_certificate = 11, - ACT_x509_process_extension = 12, - NR__x509_actions = 13, -}; - -enum x509_akid_actions { - ACT_x509_akid_note_kid = 0, - ACT_x509_akid_note_name = 1, - ACT_x509_akid_note_serial = 2, - ACT_x509_extract_name_segment___2 = 3, - ACT_x509_note_OID___2 = 4, - NR__x509_akid_actions = 5, -}; - -struct x509_certificate { - struct x509_certificate *next; - struct x509_certificate *signer; - struct public_key *pub; - struct public_key_signature *sig; - char *issuer; - char *subject; - struct asymmetric_key_id *id; - struct asymmetric_key_id *skid; - time64_t valid_from; - time64_t valid_to; - const void *tbs; - unsigned int tbs_size; - unsigned int raw_sig_size; - const void *raw_sig; - const void *raw_serial; - unsigned int raw_serial_size; - unsigned int raw_issuer_size; - const void *raw_issuer; - const void *raw_subject; - unsigned int raw_subject_size; - unsigned int raw_skid_size; - const void *raw_skid; - unsigned int index; - bool seen; - bool verified; - bool self_signed; - bool unsupported_key; - bool unsupported_sig; - bool blacklisted; -}; - -struct x509_parse_context { - struct x509_certificate *cert; - long unsigned int data; - const void *cert_start; - const void *key; - size_t key_size; - const void *params; - size_t params_size; - enum OID key_algo; - enum OID last_oid; - enum OID algo_oid; - unsigned char nr_mpi; - u8 o_size; - u8 cn_size; - u8 email_size; - u16 o_offset; - u16 cn_offset; - u16 email_offset; - unsigned int raw_akid_size; - const void *raw_akid; - const void *akid_raw_issuer; - unsigned int akid_raw_issuer_size; -}; - -enum pkcs7_actions { - ACT_pkcs7_check_content_type = 0, - ACT_pkcs7_extract_cert = 1, - ACT_pkcs7_note_OID = 2, - ACT_pkcs7_note_certificate_list = 3, - ACT_pkcs7_note_content = 4, - ACT_pkcs7_note_data = 5, - ACT_pkcs7_note_signed_info = 6, - ACT_pkcs7_note_signeddata_version = 7, - ACT_pkcs7_note_signerinfo_version = 8, - ACT_pkcs7_sig_note_authenticated_attr = 9, - ACT_pkcs7_sig_note_digest_algo = 10, - ACT_pkcs7_sig_note_issuer = 11, - ACT_pkcs7_sig_note_pkey_algo = 12, - ACT_pkcs7_sig_note_serial = 13, - ACT_pkcs7_sig_note_set_of_authattrs = 14, - ACT_pkcs7_sig_note_signature = 15, - ACT_pkcs7_sig_note_skid = 16, - NR__pkcs7_actions = 17, -}; - -struct pkcs7_signed_info { - struct pkcs7_signed_info *next; - struct x509_certificate *signer; - unsigned int index; - bool unsupported_crypto; - bool blacklisted; - const void *msgdigest; - unsigned int msgdigest_len; - unsigned int authattrs_len; - const void *authattrs; - long unsigned int aa_set; - time64_t signing_time; - struct public_key_signature *sig; -}; - -struct pkcs7_message___2 { - struct x509_certificate *certs; - struct x509_certificate *crl; - struct pkcs7_signed_info *signed_infos; - u8 version; - bool have_authattrs; - enum OID data_type; - size_t data_len; - size_t data_hdrlen; - const void *data; -}; - -struct pkcs7_parse_context { - struct pkcs7_message___2 *msg; - struct pkcs7_signed_info *sinfo; - struct pkcs7_signed_info **ppsinfo; - struct x509_certificate *certs; - struct x509_certificate **ppcerts; - long unsigned int data; - enum OID last_oid; - unsigned int x509_index; - unsigned int sinfo_index; - const void *raw_serial; - unsigned int raw_serial_size; - unsigned int raw_issuer_size; - const void *raw_issuer; - const void *raw_skid; - unsigned int raw_skid_size; - bool expect_skid; -}; - -enum hash_algo { - HASH_ALGO_MD4 = 0, - HASH_ALGO_MD5 = 1, - HASH_ALGO_SHA1 = 2, - HASH_ALGO_RIPE_MD_160 = 3, - HASH_ALGO_SHA256 = 4, - HASH_ALGO_SHA384 = 5, - HASH_ALGO_SHA512 = 6, - HASH_ALGO_SHA224 = 7, - HASH_ALGO_RIPE_MD_128 = 8, - HASH_ALGO_RIPE_MD_256 = 9, - HASH_ALGO_RIPE_MD_320 = 10, - HASH_ALGO_WP_256 = 11, - HASH_ALGO_WP_384 = 12, - HASH_ALGO_WP_512 = 13, - HASH_ALGO_TGR_128 = 14, - HASH_ALGO_TGR_160 = 15, - HASH_ALGO_TGR_192 = 16, - HASH_ALGO_SM3_256 = 17, - HASH_ALGO_STREEBOG_256 = 18, - HASH_ALGO_STREEBOG_512 = 19, - HASH_ALGO__LAST = 20, -}; - -struct biovec_slab { - int nr_vecs; - char *name; - struct kmem_cache *slab; -}; - -enum rq_qos_id { - RQ_QOS_WBT = 0, - RQ_QOS_LATENCY = 1, - RQ_QOS_COST = 2, -}; - -struct rq_qos_ops; - -struct rq_qos { - struct rq_qos_ops *ops; - struct request_queue *q; - enum rq_qos_id id; - struct rq_qos *next; - struct dentry *debugfs_dir; -}; - -enum hctx_type { - HCTX_TYPE_DEFAULT = 0, - HCTX_TYPE_READ = 1, - HCTX_TYPE_POLL = 2, - HCTX_MAX_TYPES = 3, -}; - -enum xen_domain_type { - XEN_NATIVE = 0, - XEN_PV_DOMAIN = 1, - XEN_HVM_DOMAIN = 2, -}; - -struct rq_qos_ops { - void (*throttle)(struct rq_qos *, struct bio *); - void (*track)(struct rq_qos *, struct request *, struct bio *); - void (*merge)(struct rq_qos *, struct request *, struct bio *); - void (*issue)(struct rq_qos *, struct request *); - void (*requeue)(struct rq_qos *, struct request *); - void (*done)(struct rq_qos *, struct request *); - void (*done_bio)(struct rq_qos *, struct bio *); - void (*cleanup)(struct rq_qos *, struct bio *); - void (*queue_depth_changed)(struct rq_qos *); - void (*exit)(struct rq_qos *); - const struct blk_mq_debugfs_attr *debugfs_attrs; -}; - -struct bio_slab { - struct kmem_cache *slab; - unsigned int slab_ref; - unsigned int slab_size; - char name[8]; -}; - -enum { - BLK_MQ_F_SHOULD_MERGE = 1, - BLK_MQ_F_TAG_QUEUE_SHARED = 2, - BLK_MQ_F_STACKING = 4, - BLK_MQ_F_TAG_HCTX_SHARED = 8, - BLK_MQ_F_BLOCKING = 32, - BLK_MQ_F_NO_SCHED = 64, - BLK_MQ_F_ALLOC_POLICY_START_BIT = 8, - BLK_MQ_F_ALLOC_POLICY_BITS = 1, - BLK_MQ_S_STOPPED = 0, - BLK_MQ_S_TAG_ACTIVE = 1, - BLK_MQ_S_SCHED_RESTART = 2, - BLK_MQ_S_INACTIVE = 3, - BLK_MQ_MAX_DEPTH = 10240, - BLK_MQ_CPU_WORK_BATCH = 8, -}; - -enum { - WBT_RWQ_BG = 0, - WBT_RWQ_KSWAPD = 1, - WBT_RWQ_DISCARD = 2, - WBT_NUM_RWQ = 3, -}; - -struct req_iterator { - struct bvec_iter iter; - struct bio *bio; -}; - -struct blk_plug_cb; - -typedef void (*blk_plug_cb_fn)(struct blk_plug_cb *, bool); - -struct blk_plug_cb { - struct list_head list; - blk_plug_cb_fn callback; - void *data; -}; - -enum { - BLK_MQ_REQ_NOWAIT = 1, - BLK_MQ_REQ_RESERVED = 2, - BLK_MQ_REQ_PM = 4, -}; - -struct trace_event_raw_block_buffer { - struct trace_entry ent; - dev_t dev; - sector_t sector; - size_t size; - char __data[0]; -}; - -struct trace_event_raw_block_rq_requeue { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - char rwbs[8]; - u32 __data_loc_cmd; - char __data[0]; -}; - -struct trace_event_raw_block_rq_complete { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - int error; - char rwbs[8]; - u32 __data_loc_cmd; - char __data[0]; -}; - -struct trace_event_raw_block_rq { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - unsigned int bytes; - char rwbs[8]; - char comm[16]; - u32 __data_loc_cmd; - char __data[0]; -}; - -struct trace_event_raw_block_bio_bounce { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - char rwbs[8]; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_bio_complete { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - int error; - char rwbs[8]; - char __data[0]; -}; - -struct trace_event_raw_block_bio_merge { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - char rwbs[8]; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_bio_queue { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - char rwbs[8]; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_get_rq { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - char rwbs[8]; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_plug { - struct trace_entry ent; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_unplug { - struct trace_entry ent; - int nr_rq; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_split { - struct trace_entry ent; - dev_t dev; - sector_t sector; - sector_t new_sector; - char rwbs[8]; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_bio_remap { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - dev_t old_dev; - sector_t old_sector; - char rwbs[8]; - char __data[0]; -}; - -struct trace_event_raw_block_rq_remap { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - dev_t old_dev; - sector_t old_sector; - unsigned int nr_bios; - char rwbs[8]; - char __data[0]; -}; - -struct trace_event_data_offsets_block_buffer {}; - -struct trace_event_data_offsets_block_rq_requeue { - u32 cmd; -}; - -struct trace_event_data_offsets_block_rq_complete { - u32 cmd; -}; - -struct trace_event_data_offsets_block_rq { - u32 cmd; -}; - -struct trace_event_data_offsets_block_bio_bounce {}; - -struct trace_event_data_offsets_block_bio_complete {}; - -struct trace_event_data_offsets_block_bio_merge {}; - -struct trace_event_data_offsets_block_bio_queue {}; - -struct trace_event_data_offsets_block_get_rq {}; - -struct trace_event_data_offsets_block_plug {}; - -struct trace_event_data_offsets_block_unplug {}; - -struct trace_event_data_offsets_block_split {}; - -struct trace_event_data_offsets_block_bio_remap {}; - -struct trace_event_data_offsets_block_rq_remap {}; - -typedef void (*btf_trace_block_touch_buffer)(void *, struct buffer_head *); - -typedef void (*btf_trace_block_dirty_buffer)(void *, struct buffer_head *); - -typedef void (*btf_trace_block_rq_requeue)(void *, struct request_queue *, struct request *); - -typedef void (*btf_trace_block_rq_complete)(void *, struct request *, int, unsigned int); - -typedef void (*btf_trace_block_rq_insert)(void *, struct request_queue *, struct request *); - -typedef void (*btf_trace_block_rq_issue)(void *, struct request_queue *, struct request *); - -typedef void (*btf_trace_block_rq_merge)(void *, struct request_queue *, struct request *); - -typedef void (*btf_trace_block_bio_bounce)(void *, struct request_queue *, struct bio *); - -typedef void (*btf_trace_block_bio_complete)(void *, struct request_queue *, struct bio *); - -typedef void (*btf_trace_block_bio_backmerge)(void *, struct request_queue *, struct request *, struct bio *); - -typedef void (*btf_trace_block_bio_frontmerge)(void *, struct request_queue *, struct request *, struct bio *); - -typedef void (*btf_trace_block_bio_queue)(void *, struct request_queue *, struct bio *); - -typedef void (*btf_trace_block_getrq)(void *, struct request_queue *, struct bio *, int); - -typedef void (*btf_trace_block_sleeprq)(void *, struct request_queue *, struct bio *, int); - -typedef void (*btf_trace_block_plug)(void *, struct request_queue *); - -typedef void (*btf_trace_block_unplug)(void *, struct request_queue *, unsigned int, bool); - -typedef void (*btf_trace_block_split)(void *, struct request_queue *, struct bio *, unsigned int); - -typedef void (*btf_trace_block_bio_remap)(void *, struct request_queue *, struct bio *, dev_t, sector_t); - -typedef void (*btf_trace_block_rq_remap)(void *, struct request_queue *, struct request *, dev_t, sector_t); - -enum { - BLK_MQ_NO_TAG = 4294967295, - BLK_MQ_TAG_MIN = 1, - BLK_MQ_TAG_MAX = 4294967294, -}; - -struct queue_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct request_queue *, char *); - ssize_t (*store)(struct request_queue *, const char *, size_t); -}; - -enum { - REQ_FSEQ_PREFLUSH = 1, - REQ_FSEQ_DATA = 2, - REQ_FSEQ_POSTFLUSH = 4, - REQ_FSEQ_DONE = 8, - REQ_FSEQ_ACTIONS = 7, - FLUSH_PENDING_TIMEOUT = 1250, -}; - -enum { - ICQ_EXITED = 4, - ICQ_DESTROYED = 8, -}; - -struct rq_map_data { - struct page **pages; - int page_order; - int nr_entries; - long unsigned int offset; - int null_mapped; - int from_user; -}; - -struct bio_map_data { - bool is_our_pages: 1; - bool is_null_mapped: 1; - struct iov_iter iter; - struct iovec iov[0]; -}; - -enum bio_merge_status { - BIO_MERGE_OK = 0, - BIO_MERGE_NONE = 1, - BIO_MERGE_FAILED = 2, -}; - -typedef bool (*sb_for_each_fn)(struct sbitmap *, unsigned int, void *); - -enum { - BLK_MQ_UNIQUE_TAG_BITS = 16, - BLK_MQ_UNIQUE_TAG_MASK = 65535, -}; - -struct mq_inflight { - struct hd_struct *part; - unsigned int inflight[2]; -}; - -struct flush_busy_ctx_data { - struct blk_mq_hw_ctx *hctx; - struct list_head *list; -}; - -struct dispatch_rq_data { - struct blk_mq_hw_ctx *hctx; - struct request *rq; -}; - -enum prep_dispatch { - PREP_DISPATCH_OK = 0, - PREP_DISPATCH_NO_TAG = 1, - PREP_DISPATCH_NO_BUDGET = 2, -}; - -struct rq_iter_data { - struct blk_mq_hw_ctx *hctx; - bool has_rq; -}; - -struct blk_mq_qe_pair { - struct list_head node; - struct request_queue *q; - struct elevator_type *type; -}; - -struct sbq_wait { - struct sbitmap_queue *sbq; - struct wait_queue_entry wait; -}; - -typedef bool busy_iter_fn(struct blk_mq_hw_ctx *, struct request *, void *, bool); - -typedef bool busy_tag_iter_fn(struct request *, void *, bool); - -struct bt_iter_data { - struct blk_mq_hw_ctx *hctx; - busy_iter_fn *fn; - void *data; - bool reserved; -}; - -struct bt_tags_iter_data { - struct blk_mq_tags *tags; - busy_tag_iter_fn *fn; - void *data; - unsigned int flags; -}; - -struct blk_queue_stats { - struct list_head callbacks; - spinlock_t lock; - bool enable_accounting; -}; - -struct blk_mq_ctx_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_mq_ctx *, char *); - ssize_t (*store)(struct blk_mq_ctx *, const char *, size_t); -}; - -struct blk_mq_hw_ctx_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_mq_hw_ctx *, char *); - ssize_t (*store)(struct blk_mq_hw_ctx *, const char *, size_t); -}; - -typedef u32 compat_caddr_t; - -struct hd_geometry { - unsigned char heads; - unsigned char sectors; - short unsigned int cylinders; - long unsigned int start; -}; - -struct blkpg_ioctl_arg { - int op; - int flags; - int datalen; - void *data; -}; - -struct blkpg_partition { - long long int start; - long long int length; - int pno; - char devname[64]; - char volname[64]; -}; - -struct pr_reservation { - __u64 key; - __u32 type; - __u32 flags; -}; - -struct pr_registration { - __u64 old_key; - __u64 new_key; - __u32 flags; - __u32 __pad; -}; - -struct pr_preempt { - __u64 old_key; - __u64 new_key; - __u32 type; - __u32 flags; -}; - -struct pr_clear { - __u64 key; - __u32 flags; - __u32 __pad; -}; - -struct compat_blkpg_ioctl_arg { - compat_int_t op; - compat_int_t flags; - compat_int_t datalen; - compat_caddr_t data; -}; - -struct compat_hd_geometry { - unsigned char heads; - unsigned char sectors; - short unsigned int cylinders; - u32 start; -}; - -struct klist_node; - -struct klist { - spinlock_t k_lock; - struct list_head k_list; - void (*get)(struct klist_node *); - void (*put)(struct klist_node *); -}; - -struct klist_node { - void *n_klist; - struct list_head n_node; - struct kref n_ref; -}; - -struct klist_iter { - struct klist *i_klist; - struct klist_node *i_cur; -}; - -struct class_dev_iter { - struct klist_iter ki; - const struct device_type *type; -}; - -enum { - DISK_EVENT_FLAG_POLL = 1, - DISK_EVENT_FLAG_UEVENT = 2, -}; - -struct disk_events { - struct list_head node; - struct gendisk *disk; - spinlock_t lock; - struct mutex block_mutex; - int block; - unsigned int pending; - unsigned int clearing; - long int poll_msecs; - struct delayed_work dwork; -}; - -struct badblocks { - struct device *dev; - int count; - int unacked_exist; - int shift; - u64 *page; - int changed; - seqlock_t lock; - sector_t sector; - sector_t size; -}; - -struct disk_part_iter { - struct gendisk *disk; - struct hd_struct *part; - int idx; - unsigned int flags; -}; - -struct blk_major_name { - struct blk_major_name *next; - int major; - char name[16]; -}; - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP = 2, - IOPRIO_WHO_USER = 3, -}; - -struct parsed_partitions { - struct block_device *bdev; - char name[32]; - struct { - sector_t from; - sector_t size; - int flags; - bool has_info; - struct partition_meta_info info; - } *parts; - int next; - int limit; - bool access_beyond_eod; - char *pp_buf; -}; - -typedef struct { - struct page *v; -} Sector; - -struct mac_partition { - __be16 signature; - __be16 res1; - __be32 map_count; - __be32 start_block; - __be32 block_count; - char name[32]; - char type[32]; - __be32 data_start; - __be32 data_count; - __be32 status; - __be32 boot_start; - __be32 boot_size; - __be32 boot_load; - __be32 boot_load2; - __be32 boot_entry; - __be32 boot_entry2; - __be32 boot_cksum; - char processor[16]; -}; - -struct mac_driver_desc { - __be16 signature; - __be16 block_size; - __be32 block_count; -}; - -struct msdos_partition { - u8 boot_ind; - u8 head; - u8 sector; - u8 cyl; - u8 sys_ind; - u8 end_head; - u8 end_sector; - u8 end_cyl; - __le32 start_sect; - __le32 nr_sects; -}; - -enum msdos_sys_ind { - DOS_EXTENDED_PARTITION = 5, - LINUX_EXTENDED_PARTITION = 133, - WIN98_EXTENDED_PARTITION = 15, - LINUX_DATA_PARTITION = 131, - LINUX_LVM_PARTITION = 142, - LINUX_RAID_PARTITION = 253, - SOLARIS_X86_PARTITION = 130, - NEW_SOLARIS_X86_PARTITION = 191, - DM6_AUX1PARTITION = 81, - DM6_AUX3PARTITION = 83, - DM6_PARTITION = 84, - EZD_PARTITION = 85, - FREEBSD_PARTITION = 165, - OPENBSD_PARTITION = 166, - NETBSD_PARTITION = 169, - BSDI_PARTITION = 183, - MINIX_PARTITION = 129, - UNIXWARE_PARTITION = 99, -}; - -struct _gpt_header { - __le64 signature; - __le32 revision; - __le32 header_size; - __le32 header_crc32; - __le32 reserved1; - __le64 my_lba; - __le64 alternate_lba; - __le64 first_usable_lba; - __le64 last_usable_lba; - efi_guid_t disk_guid; - __le64 partition_entry_lba; - __le32 num_partition_entries; - __le32 sizeof_partition_entry; - __le32 partition_entry_array_crc32; -} __attribute__((packed)); - -typedef struct _gpt_header gpt_header; - -struct _gpt_entry_attributes { - u64 required_to_function: 1; - u64 reserved: 47; - u64 type_guid_specific: 16; -}; - -typedef struct _gpt_entry_attributes gpt_entry_attributes; - -struct _gpt_entry { - efi_guid_t partition_type_guid; - efi_guid_t unique_partition_guid; - __le64 starting_lba; - __le64 ending_lba; - gpt_entry_attributes attributes; - __le16 partition_name[36]; -}; - -typedef struct _gpt_entry gpt_entry; - -struct _gpt_mbr_record { - u8 boot_indicator; - u8 start_head; - u8 start_sector; - u8 start_track; - u8 os_type; - u8 end_head; - u8 end_sector; - u8 end_track; - __le32 starting_lba; - __le32 size_in_lba; -}; - -typedef struct _gpt_mbr_record gpt_mbr_record; - -struct _legacy_mbr { - u8 boot_code[440]; - __le32 unique_mbr_signature; - __le16 unknown; - gpt_mbr_record partition_record[4]; - __le16 signature; -} __attribute__((packed)); - -typedef struct _legacy_mbr legacy_mbr; - -struct rq_wait { - wait_queue_head_t wait; - atomic_t inflight; -}; - -struct rq_depth { - unsigned int max_depth; - int scale_step; - bool scaled_max; - unsigned int queue_depth; - unsigned int default_depth; -}; - -typedef bool acquire_inflight_cb_t(struct rq_wait *, void *); - -typedef void cleanup_cb_t(struct rq_wait *, void *); - -struct rq_qos_wait_data { - struct wait_queue_entry wq; - struct task_struct *task; - struct rq_wait *rqw; - acquire_inflight_cb_t *cb; - void *private_data; - bool got_token; -}; - -struct cdrom_device_ops; - -struct cdrom_device_info { - const struct cdrom_device_ops *ops; - struct list_head list; - struct gendisk *disk; - void *handle; - int mask; - int speed; - int capacity; - unsigned int options: 30; - unsigned int mc_flags: 2; - unsigned int vfs_events; - unsigned int ioctl_events; - int use_count; - char name[20]; - __u8 sanyo_slot: 2; - __u8 keeplocked: 1; - __u8 reserved: 5; - int cdda_method; - __u8 last_sense; - __u8 media_written; - short unsigned int mmc3_profile; - int for_data; - int (*exit)(struct cdrom_device_info *); - int mrw_mode_page; -}; - -struct scsi_sense_hdr { - u8 response_code; - u8 sense_key; - u8 asc; - u8 ascq; - u8 byte4; - u8 byte5; - u8 byte6; - u8 additional_length; -}; - -struct cdrom_msf0 { - __u8 minute; - __u8 second; - __u8 frame; -}; - -union cdrom_addr { - struct cdrom_msf0 msf; - int lba; -}; - -struct cdrom_multisession { - union cdrom_addr addr; - __u8 xa_flag; - __u8 addr_format; -}; - -struct cdrom_mcn { - __u8 medium_catalog_number[14]; -}; - -struct request_sense; - -struct cdrom_generic_command { - unsigned char cmd[12]; - unsigned char *buffer; - unsigned int buflen; - int stat; - struct request_sense *sense; - unsigned char data_direction; - int quiet; - int timeout; - union { - void *reserved[1]; - void *unused; - }; -}; - -struct request_sense { - __u8 error_code: 7; - __u8 valid: 1; - __u8 segment_number; - __u8 sense_key: 4; - __u8 reserved2: 1; - __u8 ili: 1; - __u8 reserved1: 2; - __u8 information[4]; - __u8 add_sense_len; - __u8 command_info[4]; - __u8 asc; - __u8 ascq; - __u8 fruc; - __u8 sks[3]; - __u8 asb[46]; -}; - -struct packet_command { - unsigned char cmd[12]; - unsigned char *buffer; - unsigned int buflen; - int stat; - struct scsi_sense_hdr *sshdr; - unsigned char data_direction; - int quiet; - int timeout; - void *reserved[1]; -}; - -struct cdrom_device_ops { - int (*open)(struct cdrom_device_info *, int); - void (*release)(struct cdrom_device_info *); - int (*drive_status)(struct cdrom_device_info *, int); - unsigned int (*check_events)(struct cdrom_device_info *, unsigned int, int); - int (*tray_move)(struct cdrom_device_info *, int); - int (*lock_door)(struct cdrom_device_info *, int); - int (*select_speed)(struct cdrom_device_info *, int); - int (*select_disc)(struct cdrom_device_info *, int); - int (*get_last_session)(struct cdrom_device_info *, struct cdrom_multisession *); - int (*get_mcn)(struct cdrom_device_info *, struct cdrom_mcn *); - int (*reset)(struct cdrom_device_info *); - int (*audio_ioctl)(struct cdrom_device_info *, unsigned int, void *); - const int capability; - int (*generic_packet)(struct cdrom_device_info *, struct packet_command *); -}; - -struct scsi_ioctl_command { - unsigned int inlen; - unsigned int outlen; - unsigned char data[0]; -}; - -enum scsi_device_event { - SDEV_EVT_MEDIA_CHANGE = 1, - SDEV_EVT_INQUIRY_CHANGE_REPORTED = 2, - SDEV_EVT_CAPACITY_CHANGE_REPORTED = 3, - SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED = 4, - SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED = 5, - SDEV_EVT_LUN_CHANGE_REPORTED = 6, - SDEV_EVT_ALUA_STATE_CHANGE_REPORTED = 7, - SDEV_EVT_POWER_ON_RESET_OCCURRED = 8, - SDEV_EVT_FIRST = 1, - SDEV_EVT_LAST = 8, - SDEV_EVT_MAXBITS = 9, -}; - -struct scsi_request { - unsigned char __cmd[16]; - unsigned char *cmd; - short unsigned int cmd_len; - int result; - unsigned int sense_len; - unsigned int resid_len; - int retries; - void *sense; -}; - -struct sg_io_hdr { - int interface_id; - int dxfer_direction; - unsigned char cmd_len; - unsigned char mx_sb_len; - short unsigned int iovec_count; - unsigned int dxfer_len; - void *dxferp; - unsigned char *cmdp; - void *sbp; - unsigned int timeout; - unsigned int flags; - int pack_id; - void *usr_ptr; - unsigned char status; - unsigned char masked_status; - unsigned char msg_status; - unsigned char sb_len_wr; - short unsigned int host_status; - short unsigned int driver_status; - int resid; - unsigned int duration; - unsigned int info; -}; - -struct compat_sg_io_hdr { - compat_int_t interface_id; - compat_int_t dxfer_direction; - unsigned char cmd_len; - unsigned char mx_sb_len; - short unsigned int iovec_count; - compat_uint_t dxfer_len; - compat_uint_t dxferp; - compat_uptr_t cmdp; - compat_uptr_t sbp; - compat_uint_t timeout; - compat_uint_t flags; - compat_int_t pack_id; - compat_uptr_t usr_ptr; - unsigned char status; - unsigned char masked_status; - unsigned char msg_status; - unsigned char sb_len_wr; - short unsigned int host_status; - short unsigned int driver_status; - compat_int_t resid; - compat_uint_t duration; - compat_uint_t info; -}; - -struct blk_cmd_filter { - long unsigned int read_ok[4]; - long unsigned int write_ok[4]; -}; - -struct compat_cdrom_generic_command { - unsigned char cmd[12]; - compat_caddr_t buffer; - compat_uint_t buflen; - compat_int_t stat; - compat_caddr_t sense; - unsigned char data_direction; - unsigned char pad[3]; - compat_int_t quiet; - compat_int_t timeout; - compat_caddr_t unused; -}; - -enum { - OMAX_SB_LEN = 16, -}; - -struct bsg_device { - struct request_queue *queue; - spinlock_t lock; - struct hlist_node dev_list; - refcount_t ref_count; - char name[20]; - int max_queue; -}; - -struct bsg_job; - -typedef int bsg_job_fn(struct bsg_job *); - -struct bsg_buffer { - unsigned int payload_len; - int sg_cnt; - struct scatterlist *sg_list; -}; - -struct bsg_job { - struct device *dev; - struct kref kref; - unsigned int timeout; - void *request; - void *reply; - unsigned int request_len; - unsigned int reply_len; - struct bsg_buffer request_payload; - struct bsg_buffer reply_payload; - int result; - unsigned int reply_payload_rcv_len; - struct request *bidi_rq; - struct bio *bidi_bio; - void *dd_data; -}; - -typedef enum blk_eh_timer_return bsg_timeout_fn(struct request *); - -struct bsg_set { - struct blk_mq_tag_set tag_set; - bsg_job_fn *job_fn; - bsg_timeout_fn *timeout_fn; -}; - -typedef struct blkcg_policy_data *blkcg_pol_alloc_cpd_fn(gfp_t); - -typedef void blkcg_pol_init_cpd_fn(struct blkcg_policy_data *); - -typedef void blkcg_pol_free_cpd_fn(struct blkcg_policy_data *); - -typedef void blkcg_pol_bind_cpd_fn(struct blkcg_policy_data *); - -typedef struct blkg_policy_data *blkcg_pol_alloc_pd_fn(gfp_t, struct request_queue *, struct blkcg *); - -typedef void blkcg_pol_init_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_online_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_offline_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_free_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_reset_pd_stats_fn(struct blkg_policy_data *); - -typedef size_t blkcg_pol_stat_pd_fn(struct blkg_policy_data *, char *, size_t); - -struct blkcg_policy { - int plid; - struct cftype *dfl_cftypes; - struct cftype *legacy_cftypes; - blkcg_pol_alloc_cpd_fn *cpd_alloc_fn; - blkcg_pol_init_cpd_fn *cpd_init_fn; - blkcg_pol_free_cpd_fn *cpd_free_fn; - blkcg_pol_bind_cpd_fn *cpd_bind_fn; - blkcg_pol_alloc_pd_fn *pd_alloc_fn; - blkcg_pol_init_pd_fn *pd_init_fn; - blkcg_pol_online_pd_fn *pd_online_fn; - blkcg_pol_offline_pd_fn *pd_offline_fn; - blkcg_pol_free_pd_fn *pd_free_fn; - blkcg_pol_reset_pd_stats_fn *pd_reset_stats_fn; - blkcg_pol_stat_pd_fn *pd_stat_fn; -}; - -struct blkg_conf_ctx { - struct gendisk *disk; - struct blkcg_gq *blkg; - char *body; -}; - -enum blkg_rwstat_type { - BLKG_RWSTAT_READ = 0, - BLKG_RWSTAT_WRITE = 1, - BLKG_RWSTAT_SYNC = 2, - BLKG_RWSTAT_ASYNC = 3, - BLKG_RWSTAT_DISCARD = 4, - BLKG_RWSTAT_NR = 5, - BLKG_RWSTAT_TOTAL = 5, -}; - -struct blkg_rwstat { - struct percpu_counter cpu_cnt[5]; - atomic64_t aux_cnt[5]; -}; - -struct blkg_rwstat_sample { - u64 cnt[5]; -}; - -struct throtl_service_queue { - struct throtl_service_queue *parent_sq; - struct list_head queued[2]; - unsigned int nr_queued[2]; - struct rb_root_cached pending_tree; - unsigned int nr_pending; - long unsigned int first_pending_disptime; - struct timer_list pending_timer; -}; - -struct latency_bucket { - long unsigned int total_latency; - int samples; -}; - -struct avg_latency_bucket { - long unsigned int latency; - bool valid; -}; - -struct throtl_data { - struct throtl_service_queue service_queue; - struct request_queue *queue; - unsigned int nr_queued[2]; - unsigned int throtl_slice; - struct work_struct dispatch_work; - unsigned int limit_index; - bool limit_valid[2]; - long unsigned int low_upgrade_time; - long unsigned int low_downgrade_time; - unsigned int scale; - struct latency_bucket tmp_buckets[18]; - struct avg_latency_bucket avg_buckets[18]; - struct latency_bucket *latency_buckets[2]; - long unsigned int last_calculate_time; - long unsigned int filtered_latency; - bool track_bio_latency; -}; - -struct throtl_grp; - -struct throtl_qnode { - struct list_head node; - struct bio_list bios; - struct throtl_grp *tg; -}; - -struct throtl_grp { - struct blkg_policy_data pd; - struct rb_node rb_node; - struct throtl_data *td; - struct throtl_service_queue service_queue; - struct throtl_qnode qnode_on_self[2]; - struct throtl_qnode qnode_on_parent[2]; - long unsigned int disptime; - unsigned int flags; - bool has_rules[2]; - uint64_t bps[4]; - uint64_t bps_conf[4]; - unsigned int iops[4]; - unsigned int iops_conf[4]; - uint64_t bytes_disp[2]; - unsigned int io_disp[2]; - long unsigned int last_low_overflow_time[2]; - uint64_t last_bytes_disp[2]; - unsigned int last_io_disp[2]; - long unsigned int last_check_time; - long unsigned int latency_target; - long unsigned int latency_target_conf; - long unsigned int slice_start[2]; - long unsigned int slice_end[2]; - long unsigned int last_finish_time; - long unsigned int checked_last_finish_time; - long unsigned int avg_idletime; - long unsigned int idletime_threshold; - long unsigned int idletime_threshold_conf; - unsigned int bio_cnt; - unsigned int bad_bio_cnt; - long unsigned int bio_cnt_reset_time; - atomic_t io_split_cnt[2]; - atomic_t last_io_split_cnt[2]; - struct blkg_rwstat stat_bytes; - struct blkg_rwstat stat_ios; -}; - -enum tg_state_flags { - THROTL_TG_PENDING = 1, - THROTL_TG_WAS_EMPTY = 2, -}; - -enum { - LIMIT_LOW = 0, - LIMIT_MAX = 1, - LIMIT_CNT = 2, -}; - -struct deadline_data { - struct rb_root sort_list[2]; - struct list_head fifo_list[2]; - struct request *next_rq[2]; - unsigned int batching; - unsigned int starved; - int fifo_expire[2]; - int fifo_batch; - int writes_starved; - int front_merges; - spinlock_t lock; - spinlock_t zone_lock; - struct list_head dispatch; -}; - -struct trace_event_raw_kyber_latency { - struct trace_entry ent; - dev_t dev; - char domain[16]; - char type[8]; - u8 percentile; - u8 numerator; - u8 denominator; - unsigned int samples; - char __data[0]; -}; - -struct trace_event_raw_kyber_adjust { - struct trace_entry ent; - dev_t dev; - char domain[16]; - unsigned int depth; - char __data[0]; -}; - -struct trace_event_raw_kyber_throttled { - struct trace_entry ent; - dev_t dev; - char domain[16]; - char __data[0]; -}; - -struct trace_event_data_offsets_kyber_latency {}; - -struct trace_event_data_offsets_kyber_adjust {}; - -struct trace_event_data_offsets_kyber_throttled {}; - -typedef void (*btf_trace_kyber_latency)(void *, struct request_queue *, const char *, const char *, unsigned int, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_kyber_adjust)(void *, struct request_queue *, const char *, unsigned int); - -typedef void (*btf_trace_kyber_throttled)(void *, struct request_queue *, const char *); - -enum { - KYBER_READ = 0, - KYBER_WRITE = 1, - KYBER_DISCARD = 2, - KYBER_OTHER = 3, - KYBER_NUM_DOMAINS = 4, -}; - -enum { - KYBER_ASYNC_PERCENT = 75, -}; - -enum { - KYBER_LATENCY_SHIFT = 2, - KYBER_GOOD_BUCKETS = 4, - KYBER_LATENCY_BUCKETS = 8, -}; - -enum { - KYBER_TOTAL_LATENCY = 0, - KYBER_IO_LATENCY = 1, -}; - -struct kyber_cpu_latency { - atomic_t buckets[48]; -}; - -struct kyber_ctx_queue { - spinlock_t lock; - struct list_head rq_list[4]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct kyber_queue_data { - struct request_queue *q; - struct sbitmap_queue domain_tokens[4]; - unsigned int async_depth; - struct kyber_cpu_latency *cpu_latency; - struct timer_list timer; - unsigned int latency_buckets[48]; - long unsigned int latency_timeout[3]; - int domain_p99[3]; - u64 latency_targets[3]; -}; - -struct kyber_hctx_data { - spinlock_t lock; - struct list_head rqs[4]; - unsigned int cur_domain; - unsigned int batching; - struct kyber_ctx_queue *kcqs; - struct sbitmap kcq_map[4]; - struct sbq_wait domain_wait[4]; - struct sbq_wait_state *domain_ws[4]; - atomic_t wait_index[4]; -}; - -struct flush_kcq_data { - struct kyber_hctx_data *khd; - unsigned int sched_domain; - struct list_head *list; -}; - -enum { - PCI_STD_RESOURCES = 0, - PCI_STD_RESOURCE_END = 5, - PCI_ROM_RESOURCE = 6, - PCI_BRIDGE_RESOURCES = 7, - PCI_BRIDGE_RESOURCE_END = 10, - PCI_NUM_RESOURCES = 11, - DEVICE_COUNT_RESOURCE = 11, -}; - -typedef unsigned int pcie_reset_state_t; - -struct show_busy_params { - struct seq_file *m; - struct blk_mq_hw_ctx *hctx; -}; - -typedef void (*swap_func_t)(void *, void *, int); - -typedef int (*cmp_r_func_t)(const void *, const void *, const void *); - -struct random_ready_callback { - struct list_head list; - void (*func)(struct random_ready_callback *); - struct module *owner; -}; - -struct siprand_state { - long unsigned int v0; - long unsigned int v1; - long unsigned int v2; - long unsigned int v3; -}; - -typedef __kernel_long_t __kernel_ptrdiff_t; - -typedef __kernel_ptrdiff_t ptrdiff_t; - -struct region { - unsigned int start; - unsigned int off; - unsigned int group_len; - unsigned int end; -}; - -enum { - REG_OP_ISFREE = 0, - REG_OP_ALLOC = 1, - REG_OP_RELEASE = 2, -}; - -typedef struct scatterlist *sg_alloc_fn(unsigned int, gfp_t); - -typedef void sg_free_fn(struct scatterlist *, unsigned int); - -struct sg_page_iter { - struct scatterlist *sg; - unsigned int sg_pgoffset; - unsigned int __nents; - int __pg_advance; -}; - -struct sg_dma_page_iter { - struct sg_page_iter base; -}; - -struct sg_mapping_iter { - struct page *page; - void *addr; - size_t length; - size_t consumed; - struct sg_page_iter piter; - unsigned int __offset; - unsigned int __remaining; - unsigned int __flags; -}; - -typedef int (*list_cmp_func_t)(void *, const struct list_head *, const struct list_head *); - -struct csum_state { - __wsum csum; - size_t off; -}; - -struct __kfifo { - unsigned int in; - unsigned int out; - unsigned int mask; - unsigned int esize; - void *data; -}; - -struct rhltable { - struct rhashtable ht; -}; - -struct rhashtable_walker { - struct list_head list; - struct bucket_table *tbl; -}; - -struct rhashtable_iter { - struct rhashtable *ht; - struct rhash_head *p; - struct rhlist_head *list; - struct rhashtable_walker walker; - unsigned int slot; - unsigned int skip; - bool end_of_table; -}; - -union nested_table { - union nested_table *table; - struct rhash_lock_head *bucket; -}; - -struct once_work { - struct work_struct work; - struct static_key_true *key; - struct module *module; -}; - -struct genradix_iter { - size_t offset; - size_t pos; -}; - -struct genradix_node { - union { - struct genradix_node *children[512]; - u8 data[4096]; - }; -}; - -enum string_size_units { - STRING_UNITS_10 = 0, - STRING_UNITS_2 = 1, -}; - -struct reciprocal_value_adv { - u32 m; - u8 sh; - u8 exp; - bool is_wide_m; -}; - -enum devm_ioremap_type { - DEVM_IOREMAP = 0, - DEVM_IOREMAP_UC = 1, - DEVM_IOREMAP_WC = 2, -}; - -struct pcim_iomap_devres { - void *table[6]; -}; - -enum assoc_array_walk_status { - assoc_array_walk_tree_empty = 0, - assoc_array_walk_found_terminal_node = 1, - assoc_array_walk_found_wrong_shortcut = 2, -}; - -struct assoc_array_walk_result { - struct { - struct assoc_array_node *node; - int level; - int slot; - } terminal_node; - struct { - struct assoc_array_shortcut *shortcut; - int level; - int sc_level; - long unsigned int sc_segments; - long unsigned int dissimilarity; - } wrong_shortcut; -}; - -struct assoc_array_delete_collapse_context { - struct assoc_array_node *node; - const void *skip_leaf; - int slot; -}; - -struct linear_range { - unsigned int min; - unsigned int min_sel; - unsigned int max_sel; - unsigned int step; -}; - -struct xxh32_state { - uint32_t total_len_32; - uint32_t large_len; - uint32_t v1; - uint32_t v2; - uint32_t v3; - uint32_t v4; - uint32_t mem32[4]; - uint32_t memsize; -}; - -struct xxh64_state { - uint64_t total_len; - uint64_t v1; - uint64_t v2; - uint64_t v3; - uint64_t v4; - uint64_t mem64[4]; - uint32_t memsize; -}; - -struct gen_pool_chunk { - struct list_head next_chunk; - atomic_long_t avail; - phys_addr_t phys_addr; - void *owner; - long unsigned int start_addr; - long unsigned int end_addr; - long unsigned int bits[0]; -}; - -struct genpool_data_align { - int align; -}; - -struct genpool_data_fixed { - long unsigned int offset; -}; - -typedef struct z_stream_s z_stream; - -typedef z_stream *z_streamp; - -typedef struct { - unsigned char op; - unsigned char bits; - short unsigned int val; -} code; - -typedef enum { - HEAD = 0, - FLAGS = 1, - TIME = 2, - OS = 3, - EXLEN = 4, - EXTRA = 5, - NAME = 6, - COMMENT = 7, - HCRC = 8, - DICTID = 9, - DICT = 10, - TYPE = 11, - TYPEDO = 12, - STORED = 13, - COPY = 14, - TABLE = 15, - LENLENS = 16, - CODELENS = 17, - LEN = 18, - LENEXT = 19, - DIST = 20, - DISTEXT = 21, - MATCH = 22, - LIT = 23, - CHECK = 24, - LENGTH = 25, - DONE = 26, - BAD = 27, - MEM = 28, - SYNC = 29, -} inflate_mode; - -struct inflate_state { - inflate_mode mode; - int last; - int wrap; - int havedict; - int flags; - unsigned int dmax; - long unsigned int check; - long unsigned int total; - unsigned int wbits; - unsigned int wsize; - unsigned int whave; - unsigned int write; - unsigned char *window; - long unsigned int hold; - unsigned int bits; - unsigned int length; - unsigned int offset; - unsigned int extra; - const code *lencode; - const code *distcode; - unsigned int lenbits; - unsigned int distbits; - unsigned int ncode; - unsigned int nlen; - unsigned int ndist; - unsigned int have; - code *next; - short unsigned int lens[320]; - short unsigned int work[288]; - code codes[2048]; -}; - -union uu { - short unsigned int us; - unsigned char b[2]; -}; - -typedef unsigned int uInt; - -struct inflate_workspace { - struct inflate_state inflate_state; - unsigned char working_window[32768]; -}; - -typedef enum { - CODES = 0, - LENS = 1, - DISTS = 2, -} codetype; - -typedef unsigned char uch; - -typedef short unsigned int ush; - -typedef long unsigned int ulg; - -struct ct_data_s { - union { - ush freq; - ush code; - } fc; - union { - ush dad; - ush len; - } dl; -}; - -typedef struct ct_data_s ct_data; - -struct static_tree_desc_s { - const ct_data *static_tree; - const int *extra_bits; - int extra_base; - int elems; - int max_length; -}; - -typedef struct static_tree_desc_s static_tree_desc; - -struct tree_desc_s { - ct_data *dyn_tree; - int max_code; - static_tree_desc *stat_desc; -}; - -typedef ush Pos; - -typedef unsigned int IPos; - -struct deflate_state { - z_streamp strm; - int status; - Byte *pending_buf; - ulg pending_buf_size; - Byte *pending_out; - int pending; - int noheader; - Byte data_type; - Byte method; - int last_flush; - uInt w_size; - uInt w_bits; - uInt w_mask; - Byte *window; - ulg window_size; - Pos *prev; - Pos *head; - uInt ins_h; - uInt hash_size; - uInt hash_bits; - uInt hash_mask; - uInt hash_shift; - long int block_start; - uInt match_length; - IPos prev_match; - int match_available; - uInt strstart; - uInt match_start; - uInt lookahead; - uInt prev_length; - uInt max_chain_length; - uInt max_lazy_match; - int level; - int strategy; - uInt good_match; - int nice_match; - struct ct_data_s dyn_ltree[573]; - struct ct_data_s dyn_dtree[61]; - struct ct_data_s bl_tree[39]; - struct tree_desc_s l_desc; - struct tree_desc_s d_desc; - struct tree_desc_s bl_desc; - ush bl_count[16]; - int heap[573]; - int heap_len; - int heap_max; - uch depth[573]; - uch *l_buf; - uInt lit_bufsize; - uInt last_lit; - ush *d_buf; - ulg opt_len; - ulg static_len; - ulg compressed_len; - uInt matches; - int last_eob_len; - ush bi_buf; - int bi_valid; -}; - -typedef struct deflate_state deflate_state; - -typedef enum { - need_more = 0, - block_done = 1, - finish_started = 2, - finish_done = 3, -} block_state; - -typedef block_state (*compress_func)(deflate_state *, int); - -struct deflate_workspace { - deflate_state deflate_memory; - Byte *window_memory; - Pos *prev_memory; - Pos *head_memory; - char *overlay_memory; -}; - -typedef struct deflate_workspace deflate_workspace; - -struct config_s { - ush good_length; - ush max_lazy; - ush nice_length; - ush max_chain; - compress_func func; -}; - -typedef struct config_s config; - -typedef struct tree_desc_s tree_desc; - -typedef struct { - const uint8_t *externalDict; - size_t extDictSize; - const uint8_t *prefixEnd; - size_t prefixSize; -} LZ4_streamDecode_t_internal; - -typedef union { - long long unsigned int table[4]; - LZ4_streamDecode_t_internal internal_donotuse; -} LZ4_streamDecode_t; - -typedef uint8_t BYTE; - -typedef uint16_t U16; - -typedef uint32_t U32; - -typedef uint64_t U64; - -typedef uintptr_t uptrval; - -typedef enum { - noDict = 0, - withPrefix64k = 1, - usingExtDict = 2, -} dict_directive; - -typedef enum { - endOnOutputSize = 0, - endOnInputSize = 1, -} endCondition_directive; - -typedef enum { - decode_full_block = 0, - partial_decode = 1, -} earlyEnd_directive; - -typedef struct { - size_t bitContainer; - unsigned int bitsConsumed; - const char *ptr; - const char *start; -} BIT_DStream_t; - -typedef enum { - BIT_DStream_unfinished = 0, - BIT_DStream_endOfBuffer = 1, - BIT_DStream_completed = 2, - BIT_DStream_overflow = 3, -} BIT_DStream_status; - -typedef U32 HUF_DTable; - -typedef struct { - BYTE maxTableLog; - BYTE tableType; - BYTE tableLog; - BYTE reserved; -} DTableDesc; - -typedef struct { - BYTE byte; - BYTE nbBits; -} HUF_DEltX2; - -typedef struct { - U16 sequence; - BYTE nbBits; - BYTE length; -} HUF_DEltX4; - -typedef struct { - BYTE symbol; - BYTE weight; -} sortedSymbol_t; - -typedef U32 rankValCol_t[13]; - -typedef struct { - U32 tableTime; - U32 decode256Time; -} algo_time_t; - -typedef s16 int16_t; - -typedef unsigned int FSE_DTable; - -typedef struct { - FSE_DTable LLTable[513]; - FSE_DTable OFTable[257]; - FSE_DTable MLTable[513]; - HUF_DTable hufTable[4097]; - U64 workspace[384]; - U32 rep[3]; -} ZSTD_entropyTables_t; - -typedef struct { - long long unsigned int frameContentSize; - unsigned int windowSize; - unsigned int dictID; - unsigned int checksumFlag; -} ZSTD_frameParams; - -typedef enum { - bt_raw = 0, - bt_rle = 1, - bt_compressed = 2, - bt_reserved = 3, -} blockType_e; - -typedef enum { - ZSTDds_getFrameHeaderSize = 0, - ZSTDds_decodeFrameHeader = 1, - ZSTDds_decodeBlockHeader = 2, - ZSTDds_decompressBlock = 3, - ZSTDds_decompressLastBlock = 4, - ZSTDds_checkChecksum = 5, - ZSTDds_decodeSkippableHeader = 6, - ZSTDds_skipFrame = 7, -} ZSTD_dStage; - -typedef void * (*ZSTD_allocFunction)(void *, size_t); - -typedef void (*ZSTD_freeFunction)(void *, void *); - -typedef struct { - ZSTD_allocFunction customAlloc; - ZSTD_freeFunction customFree; - void *opaque; -} ZSTD_customMem; - -struct ZSTD_DCtx_s { - const FSE_DTable *LLTptr; - const FSE_DTable *MLTptr; - const FSE_DTable *OFTptr; - const HUF_DTable *HUFptr; - ZSTD_entropyTables_t entropy; - const void *previousDstEnd; - const void *base; - const void *vBase; - const void *dictEnd; - size_t expected; - ZSTD_frameParams fParams; - blockType_e bType; - ZSTD_dStage stage; - U32 litEntropy; - U32 fseEntropy; - struct xxh64_state xxhState; - size_t headerSize; - U32 dictID; - const BYTE *litPtr; - ZSTD_customMem customMem; - size_t litSize; - size_t rleSize; - BYTE litBuffer[131080]; - BYTE headerBuffer[18]; -}; - -typedef struct ZSTD_DCtx_s ZSTD_DCtx; - -struct ZSTD_DDict_s { - void *dictBuffer; - const void *dictContent; - size_t dictSize; - ZSTD_entropyTables_t entropy; - U32 dictID; - U32 entropyPresent; - ZSTD_customMem cMem; -}; - -typedef struct ZSTD_DDict_s ZSTD_DDict; - -struct ZSTD_inBuffer_s { - const void *src; - size_t size; - size_t pos; -}; - -typedef struct ZSTD_inBuffer_s ZSTD_inBuffer; - -struct ZSTD_outBuffer_s { - void *dst; - size_t size; - size_t pos; -}; - -typedef struct ZSTD_outBuffer_s ZSTD_outBuffer; - -typedef enum { - zdss_init = 0, - zdss_loadHeader = 1, - zdss_read = 2, - zdss_load = 3, - zdss_flush = 4, -} ZSTD_dStreamStage; - -struct ZSTD_DStream_s { - ZSTD_DCtx *dctx; - ZSTD_DDict *ddictLocal; - const ZSTD_DDict *ddict; - ZSTD_frameParams fParams; - ZSTD_dStreamStage stage; - char *inBuff; - size_t inBuffSize; - size_t inPos; - size_t maxWindowSize; - char *outBuff; - size_t outBuffSize; - size_t outStart; - size_t outEnd; - size_t blockSize; - BYTE headerBuffer[18]; - size_t lhSize; - ZSTD_customMem customMem; - void *legacyContext; - U32 previousLegacyVersion; - U32 legacyVersion; - U32 hostageByte; -}; - -typedef struct ZSTD_DStream_s ZSTD_DStream; - -typedef enum { - ZSTDnit_frameHeader = 0, - ZSTDnit_blockHeader = 1, - ZSTDnit_block = 2, - ZSTDnit_lastBlock = 3, - ZSTDnit_checksum = 4, - ZSTDnit_skippableFrame = 5, -} ZSTD_nextInputType_e; - -typedef int16_t S16; - -typedef uintptr_t uPtrDiff; - -typedef struct { - size_t state; - const void *table; -} FSE_DState_t; - -typedef struct { - U16 tableLog; - U16 fastMode; -} FSE_DTableHeader; - -typedef struct { - short unsigned int newState; - unsigned char symbol; - unsigned char nbBits; -} FSE_decode_t; - -typedef enum { - set_basic = 0, - set_rle = 1, - set_compressed = 2, - set_repeat = 3, -} symbolEncodingType_e; - -typedef struct { - blockType_e blockType; - U32 lastBlock; - U32 origSize; -} blockProperties_t; - -typedef union { - FSE_decode_t realData; - U32 alignedBy4; -} FSE_decode_t4; - -typedef struct { - size_t litLength; - size_t matchLength; - size_t offset; - const BYTE *match; -} seq_t; - -typedef struct { - BIT_DStream_t DStream; - FSE_DState_t stateLL; - FSE_DState_t stateOffb; - FSE_DState_t stateML; - size_t prevOffset[3]; - const BYTE *base; - size_t pos; - uPtrDiff gotoDict; -} seqState_t; - -typedef struct { - void *ptr; - const void *end; -} ZSTD_stack; - -enum xz_mode { - XZ_SINGLE = 0, - XZ_PREALLOC = 1, - XZ_DYNALLOC = 2, -}; - -enum xz_ret { - XZ_OK = 0, - XZ_STREAM_END = 1, - XZ_UNSUPPORTED_CHECK = 2, - XZ_MEM_ERROR = 3, - XZ_MEMLIMIT_ERROR = 4, - XZ_FORMAT_ERROR = 5, - XZ_OPTIONS_ERROR = 6, - XZ_DATA_ERROR = 7, - XZ_BUF_ERROR = 8, -}; - -struct xz_buf { - const uint8_t *in; - size_t in_pos; - size_t in_size; - uint8_t *out; - size_t out_pos; - size_t out_size; -}; - -typedef uint64_t vli_type; - -enum xz_check { - XZ_CHECK_NONE = 0, - XZ_CHECK_CRC32 = 1, - XZ_CHECK_CRC64 = 4, - XZ_CHECK_SHA256 = 10, -}; - -struct xz_dec_hash { - vli_type unpadded; - vli_type uncompressed; - uint32_t crc32; -}; - -struct xz_dec_lzma2; - -struct xz_dec_bcj; - -struct xz_dec { - enum { - SEQ_STREAM_HEADER = 0, - SEQ_BLOCK_START = 1, - SEQ_BLOCK_HEADER = 2, - SEQ_BLOCK_UNCOMPRESS = 3, - SEQ_BLOCK_PADDING = 4, - SEQ_BLOCK_CHECK = 5, - SEQ_INDEX = 6, - SEQ_INDEX_PADDING = 7, - SEQ_INDEX_CRC32 = 8, - SEQ_STREAM_FOOTER = 9, - } sequence; - uint32_t pos; - vli_type vli; - size_t in_start; - size_t out_start; - uint32_t crc32; - enum xz_check check_type; - enum xz_mode mode; - bool allow_buf_error; - struct { - vli_type compressed; - vli_type uncompressed; - uint32_t size; - } block_header; - struct { - vli_type compressed; - vli_type uncompressed; - vli_type count; - struct xz_dec_hash hash; - } block; - struct { - enum { - SEQ_INDEX_COUNT = 0, - SEQ_INDEX_UNPADDED = 1, - SEQ_INDEX_UNCOMPRESSED = 2, - } sequence; - vli_type size; - vli_type count; - struct xz_dec_hash hash; - } index; - struct { - size_t pos; - size_t size; - uint8_t buf[1024]; - } temp; - struct xz_dec_lzma2 *lzma2; - struct xz_dec_bcj *bcj; - bool bcj_active; -}; - -enum lzma_state { - STATE_LIT_LIT = 0, - STATE_MATCH_LIT_LIT = 1, - STATE_REP_LIT_LIT = 2, - STATE_SHORTREP_LIT_LIT = 3, - STATE_MATCH_LIT = 4, - STATE_REP_LIT = 5, - STATE_SHORTREP_LIT = 6, - STATE_LIT_MATCH = 7, - STATE_LIT_LONGREP = 8, - STATE_LIT_SHORTREP = 9, - STATE_NONLIT_MATCH = 10, - STATE_NONLIT_REP = 11, -}; - -struct dictionary { - uint8_t *buf; - size_t start; - size_t pos; - size_t full; - size_t limit; - size_t end; - uint32_t size; - uint32_t size_max; - uint32_t allocated; - enum xz_mode mode; -}; - -struct rc_dec { - uint32_t range; - uint32_t code; - uint32_t init_bytes_left; - const uint8_t *in; - size_t in_pos; - size_t in_limit; -}; - -struct lzma_len_dec { - uint16_t choice; - uint16_t choice2; - uint16_t low[128]; - uint16_t mid[128]; - uint16_t high[256]; -}; - -struct lzma_dec { - uint32_t rep0; - uint32_t rep1; - uint32_t rep2; - uint32_t rep3; - enum lzma_state state; - uint32_t len; - uint32_t lc; - uint32_t literal_pos_mask; - uint32_t pos_mask; - uint16_t is_match[192]; - uint16_t is_rep[12]; - uint16_t is_rep0[12]; - uint16_t is_rep1[12]; - uint16_t is_rep2[12]; - uint16_t is_rep0_long[192]; - uint16_t dist_slot[256]; - uint16_t dist_special[114]; - uint16_t dist_align[16]; - struct lzma_len_dec match_len_dec; - struct lzma_len_dec rep_len_dec; - uint16_t literal[12288]; -}; - -enum lzma2_seq { - SEQ_CONTROL = 0, - SEQ_UNCOMPRESSED_1 = 1, - SEQ_UNCOMPRESSED_2 = 2, - SEQ_COMPRESSED_0 = 3, - SEQ_COMPRESSED_1 = 4, - SEQ_PROPERTIES = 5, - SEQ_LZMA_PREPARE = 6, - SEQ_LZMA_RUN = 7, - SEQ_COPY = 8, -}; - -struct lzma2_dec { - enum lzma2_seq sequence; - enum lzma2_seq next_sequence; - uint32_t uncompressed; - uint32_t compressed; - bool need_dict_reset; - bool need_props; -}; - -struct xz_dec_lzma2___2 { - struct rc_dec rc; - struct dictionary dict; - struct lzma2_dec lzma2; - struct lzma_dec lzma; - struct { - uint32_t size; - uint8_t buf[63]; - } temp; -}; - -struct xz_dec_bcj___2 { - enum { - BCJ_X86 = 4, - BCJ_POWERPC = 5, - BCJ_IA64 = 6, - BCJ_ARM = 7, - BCJ_ARMTHUMB = 8, - BCJ_SPARC = 9, - } type; - enum xz_ret ret; - bool single_call; - uint32_t pos; - uint32_t x86_prev_mask; - uint8_t *out; - size_t out_pos; - size_t out_size; - struct { - size_t filtered; - size_t size; - uint8_t buf[16]; - } temp; -}; - -struct ts_state { - unsigned int offset; - char cb[40]; -}; - -struct ts_config; - -struct ts_ops { - const char *name; - struct ts_config * (*init)(const void *, unsigned int, gfp_t, int); - unsigned int (*find)(struct ts_config *, struct ts_state *); - void (*destroy)(struct ts_config *); - void * (*get_pattern)(struct ts_config *); - unsigned int (*get_pattern_len)(struct ts_config *); - struct module *owner; - struct list_head list; -}; - -struct ts_config { - struct ts_ops *ops; - int flags; - unsigned int (*get_next_block)(unsigned int, const u8 **, struct ts_config *, struct ts_state *); - void (*finish)(struct ts_config *, struct ts_state *); -}; - -struct ts_linear_state { - unsigned int len; - const void *data; -}; - -struct ei_entry { - struct list_head list; - long unsigned int start_addr; - long unsigned int end_addr; - int etype; - void *priv; -}; - -struct nla_bitfield32 { - __u32 value; - __u32 selector; -}; - -enum nla_policy_validation { - NLA_VALIDATE_NONE = 0, - NLA_VALIDATE_RANGE = 1, - NLA_VALIDATE_RANGE_WARN_TOO_LONG = 2, - NLA_VALIDATE_MIN = 3, - NLA_VALIDATE_MAX = 4, - NLA_VALIDATE_MASK = 5, - NLA_VALIDATE_RANGE_PTR = 6, - NLA_VALIDATE_FUNCTION = 7, -}; - -enum netlink_validation { - NL_VALIDATE_LIBERAL = 0, - NL_VALIDATE_TRAILING = 1, - NL_VALIDATE_MAXTYPE = 2, - NL_VALIDATE_UNSPEC = 4, - NL_VALIDATE_STRICT_ATTRS = 8, - NL_VALIDATE_NESTED = 16, -}; - -struct cpu_rmap { - struct kref refcount; - u16 size; - u16 used; - void **obj; - struct { - u16 index; - u16 dist; - } near[0]; -}; - -struct irq_glue { - struct irq_affinity_notify notify; - struct cpu_rmap *rmap; - u16 index; -}; - -typedef mpi_limb_t *mpi_ptr_t; - -typedef int mpi_size_t; - -typedef mpi_limb_t UWtype; - -typedef unsigned int UHWtype; - -enum gcry_mpi_constants { - MPI_C_ZERO = 0, - MPI_C_ONE = 1, - MPI_C_TWO = 2, - MPI_C_THREE = 3, - MPI_C_FOUR = 4, - MPI_C_EIGHT = 5, -}; - -struct barrett_ctx_s; - -typedef struct barrett_ctx_s *mpi_barrett_t; - -struct gcry_mpi_point { - MPI x; - MPI y; - MPI z; -}; - -typedef struct gcry_mpi_point *MPI_POINT; - -enum gcry_mpi_ec_models { - MPI_EC_WEIERSTRASS = 0, - MPI_EC_MONTGOMERY = 1, - MPI_EC_EDWARDS = 2, -}; - -enum ecc_dialects { - ECC_DIALECT_STANDARD = 0, - ECC_DIALECT_ED25519 = 1, - ECC_DIALECT_SAFECURVE = 2, -}; - -struct mpi_ec_ctx { - enum gcry_mpi_ec_models model; - enum ecc_dialects dialect; - int flags; - unsigned int nbits; - MPI p; - MPI a; - MPI b; - MPI_POINT G; - MPI n; - unsigned int h; - MPI_POINT Q; - MPI d; - const char *name; - struct { - struct { - unsigned int a_is_pminus3: 1; - unsigned int two_inv_p: 1; - } valid; - int a_is_pminus3; - MPI two_inv_p; - mpi_barrett_t p_barrett; - MPI scratch[11]; - } t; - void (*addm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*subm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*mulm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*pow2)(MPI, const MPI, struct mpi_ec_ctx *); - void (*mul2)(MPI, MPI, struct mpi_ec_ctx *); -}; - -struct field_table { - const char *p; - void (*addm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*subm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*mulm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*mul2)(MPI, MPI, struct mpi_ec_ctx *); - void (*pow2)(MPI, const MPI, struct mpi_ec_ctx *); -}; - -enum gcry_mpi_format { - GCRYMPI_FMT_NONE = 0, - GCRYMPI_FMT_STD = 1, - GCRYMPI_FMT_PGP = 2, - GCRYMPI_FMT_SSH = 3, - GCRYMPI_FMT_HEX = 4, - GCRYMPI_FMT_USG = 5, - GCRYMPI_FMT_OPAQUE = 8, -}; - -struct barrett_ctx_s___2; - -typedef struct barrett_ctx_s___2 *mpi_barrett_t___2; - -struct barrett_ctx_s___2 { - MPI m; - int m_copied; - int k; - MPI y; - MPI r1; - MPI r2; - MPI r3; -}; - -struct karatsuba_ctx { - struct karatsuba_ctx *next; - mpi_ptr_t tspace; - mpi_size_t tspace_size; - mpi_ptr_t tp; - mpi_size_t tp_size; -}; - -typedef long int mpi_limb_signed_t; - -struct dim_sample { - ktime_t time; - u32 pkt_ctr; - u32 byte_ctr; - u16 event_ctr; - u32 comp_ctr; -}; - -struct dim_stats { - int ppms; - int bpms; - int epms; - int cpms; - int cpe_ratio; -}; - -struct dim { - u8 state; - struct dim_stats prev_stats; - struct dim_sample start_sample; - struct dim_sample measuring_sample; - struct work_struct work; - void *priv; - u8 profile_ix; - u8 mode; - u8 tune_state; - u8 steps_right; - u8 steps_left; - u8 tired; -}; - -enum dim_tune_state { - DIM_PARKING_ON_TOP = 0, - DIM_PARKING_TIRED = 1, - DIM_GOING_RIGHT = 2, - DIM_GOING_LEFT = 3, -}; - -struct dim_cq_moder { - u16 usec; - u16 pkts; - u16 comps; - u8 cq_period_mode; -}; - -enum dim_cq_period_mode { - DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0, - DIM_CQ_PERIOD_MODE_START_FROM_CQE = 1, - DIM_CQ_PERIOD_NUM_MODES = 2, -}; - -enum dim_state { - DIM_START_MEASURE = 0, - DIM_MEASURE_IN_PROGRESS = 1, - DIM_APPLY_NEW_PROFILE = 2, -}; - -enum dim_stats_state { - DIM_STATS_WORSE = 0, - DIM_STATS_SAME = 1, - DIM_STATS_BETTER = 2, -}; - -enum dim_step_result { - DIM_STEPPED = 0, - DIM_TOO_TIRED = 1, - DIM_ON_EDGE = 2, -}; - -struct sg_pool { - size_t size; - char *name; - struct kmem_cache *slab; - mempool_t *pool; -}; - -struct font_desc { - int idx; - const char *name; - int width; - int height; - const void *data; - int pref; -}; - -struct font_data { - unsigned int extra[4]; - const unsigned char data[0]; -}; - -typedef u16 ucs2_char_t; - -typedef long unsigned int cycles_t; - -struct compress_format { - unsigned char magic[2]; - const char *name; - decompress_fn decompressor; -}; - -struct group_data { - int limit[21]; - int base[20]; - int permute[258]; - int minLen; - int maxLen; -}; - -struct bunzip_data { - int writeCopies; - int writePos; - int writeRunCountdown; - int writeCount; - int writeCurrent; - long int (*fill)(void *, long unsigned int); - long int inbufCount; - long int inbufPos; - unsigned char *inbuf; - unsigned int inbufBitCount; - unsigned int inbufBits; - unsigned int crc32Table[256]; - unsigned int headerCRC; - unsigned int totalCRC; - unsigned int writeCRC; - unsigned int *dbuf; - unsigned int dbufSize; - unsigned char selectors[32768]; - struct group_data groups[6]; - int io_error; - int byteCount[256]; - unsigned char symToByte[256]; - unsigned char mtfSymbol[256]; -}; - -struct rc { - long int (*fill)(void *, long unsigned int); - uint8_t *ptr; - uint8_t *buffer; - uint8_t *buffer_end; - long int buffer_size; - uint32_t code; - uint32_t range; - uint32_t bound; - void (*error)(char *); -}; - -struct lzma_header { - uint8_t pos; - uint32_t dict_size; - uint64_t dst_size; -} __attribute__((packed)); - -struct writer { - uint8_t *buffer; - uint8_t previous_byte; - size_t buffer_pos; - int bufsize; - size_t global_pos; - long int (*flush)(void *, long unsigned int); - struct lzma_header *header; -}; - -struct cstate { - int state; - uint32_t rep0; - uint32_t rep1; - uint32_t rep2; - uint32_t rep3; -}; - -struct xz_dec___2; - -typedef enum { - ZSTD_error_no_error = 0, - ZSTD_error_GENERIC = 1, - ZSTD_error_prefix_unknown = 2, - ZSTD_error_version_unsupported = 3, - ZSTD_error_parameter_unknown = 4, - ZSTD_error_frameParameter_unsupported = 5, - ZSTD_error_frameParameter_unsupportedBy32bits = 6, - ZSTD_error_frameParameter_windowTooLarge = 7, - ZSTD_error_compressionParameter_unsupported = 8, - ZSTD_error_init_missing = 9, - ZSTD_error_memory_allocation = 10, - ZSTD_error_stage_wrong = 11, - ZSTD_error_dstSize_tooSmall = 12, - ZSTD_error_srcSize_wrong = 13, - ZSTD_error_corruption_detected = 14, - ZSTD_error_checksum_wrong = 15, - ZSTD_error_tableLog_tooLarge = 16, - ZSTD_error_maxSymbolValue_tooLarge = 17, - ZSTD_error_maxSymbolValue_tooSmall = 18, - ZSTD_error_dictionary_corrupted = 19, - ZSTD_error_dictionary_wrong = 20, - ZSTD_error_dictionaryCreation_failed = 21, - ZSTD_error_maxCode = 22, -} ZSTD_ErrorCode; - -struct ZSTD_DCtx_s___2; - -typedef struct ZSTD_DCtx_s___2 ZSTD_DCtx___2; - -struct ZSTD_DStream_s___2; - -typedef struct ZSTD_DStream_s___2 ZSTD_DStream___2; - -struct cpio_data { - void *data; - size_t size; - char name[18]; -}; - -enum cpio_fields { - C_MAGIC = 0, - C_INO = 1, - C_MODE = 2, - C_UID = 3, - C_GID = 4, - C_NLINK = 5, - C_MTIME = 6, - C_FILESIZE = 7, - C_MAJ = 8, - C_MIN = 9, - C_RMAJ = 10, - C_RMIN = 11, - C_NAMESIZE = 12, - C_CHKSUM = 13, - C_NFIELDS = 14, -}; - -enum { - ASSUME_PERFECT = 255, - ASSUME_VALID_DTB = 1, - ASSUME_VALID_INPUT = 2, - ASSUME_LATEST = 4, - ASSUME_NO_ROLLBACK = 8, - ASSUME_LIBFDT_ORDER = 16, - ASSUME_LIBFDT_FLAWLESS = 32, -}; - -typedef __be64 fdt64_t; - -struct fdt_reserve_entry { - fdt64_t address; - fdt64_t size; -}; - -struct fdt_node_header { - fdt32_t tag; - char name[0]; -}; - -struct fdt_property { - fdt32_t tag; - fdt32_t len; - fdt32_t nameoff; - char data[0]; -}; - -struct fdt_errtabent { - const char *str; -}; - -struct fprop_local_single { - long unsigned int events; - unsigned int period; - raw_spinlock_t lock; -}; - -struct ida_bitmap { - long unsigned int bitmap[16]; -}; - -struct klist_waiter { - struct list_head list; - struct klist_node *node; - struct task_struct *process; - int woken; -}; - -struct uevent_sock { - struct list_head list; - struct sock *sk; -}; - -enum { - LOGIC_PIO_INDIRECT = 0, - LOGIC_PIO_CPU_MMIO = 1, -}; - -struct logic_pio_host_ops; - -struct logic_pio_hwaddr { - struct list_head list; - struct fwnode_handle *fwnode; - resource_size_t hw_start; - resource_size_t io_start; - resource_size_t size; - long unsigned int flags; - void *hostdata; - const struct logic_pio_host_ops *ops; -}; - -struct logic_pio_host_ops { - u32 (*in)(void *, long unsigned int, size_t); - void (*out)(void *, long unsigned int, u32, size_t); - u32 (*ins)(void *, long unsigned int, void *, size_t, unsigned int); - void (*outs)(void *, long unsigned int, const void *, size_t, unsigned int); -}; - -typedef struct { - long unsigned int key[2]; -} hsiphash_key_t; - -enum format_type { - FORMAT_TYPE_NONE = 0, - FORMAT_TYPE_WIDTH = 1, - FORMAT_TYPE_PRECISION = 2, - FORMAT_TYPE_CHAR = 3, - FORMAT_TYPE_STR = 4, - FORMAT_TYPE_PTR = 5, - FORMAT_TYPE_PERCENT_CHAR = 6, - FORMAT_TYPE_INVALID = 7, - FORMAT_TYPE_LONG_LONG = 8, - FORMAT_TYPE_ULONG = 9, - FORMAT_TYPE_LONG = 10, - FORMAT_TYPE_UBYTE = 11, - FORMAT_TYPE_BYTE = 12, - FORMAT_TYPE_USHORT = 13, - FORMAT_TYPE_SHORT = 14, - FORMAT_TYPE_UINT = 15, - FORMAT_TYPE_INT = 16, - FORMAT_TYPE_SIZE_T = 17, - FORMAT_TYPE_PTRDIFF = 18, -}; - -struct printf_spec { - unsigned int type: 8; - int field_width: 24; - unsigned int flags: 8; - unsigned int base: 8; - int precision: 16; -}; - -struct minmax_sample { - u32 t; - u32 v; -}; - -struct minmax { - struct minmax_sample s[3]; -}; - -typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *); - -typedef int (*of_init_fn_2)(struct device_node *, struct device_node *); - -struct armctrl_ic { - void *base; - void *pending[3]; - void *enable[3]; - void *disable[3]; - struct irq_domain *domain; - void *local_base; -}; - -struct bcm2836_arm_irqchip_intc { - struct irq_domain *domain; - void *base; -}; - -struct gic_quirk { - const char *desc; - const char *compatible; - bool (*init)(void *); - u32 iidr; - u32 mask; -}; - -union gic_base { - void *common_base; - void **percpu_base; -}; - -struct gic_chip_data { - struct irq_chip chip; - union gic_base dist_base; - union gic_base cpu_base; - void *raw_dist_base; - void *raw_cpu_base; - u32 percpu_offset; - u32 saved_spi_enable[32]; - u32 saved_spi_active[32]; - u32 saved_spi_conf[64]; - u32 saved_spi_target[255]; - u32 *saved_ppi_enable; - u32 *saved_ppi_active; - u32 *saved_ppi_conf; - struct irq_domain *domain; - unsigned int gic_irqs; -}; - -struct v2m_data { - struct list_head entry; - struct fwnode_handle *fwnode; - struct resource res; - void *base; - u32 spi_start; - u32 nr_spis; - u32 spi_offset; - long unsigned int *bm; - u32 flags; -}; - -struct rdists { - struct { - raw_spinlock_t rd_lock; - void *rd_base; - struct page *pend_page; - phys_addr_t phys_base; - bool lpi_enabled; - cpumask_t *vpe_table_mask; - void *vpe_l1_base; - } *rdist; - phys_addr_t prop_table_pa; - void *prop_table_va; - u64 flags; - u32 gicd_typer; - u32 gicd_typer2; - bool has_vlpis; - bool has_rvpeid; - bool has_direct_lpi; - bool has_vpend_valid_dirty; -}; - -struct partition_affinity { - cpumask_t mask; - void *partition_id; -}; - -struct redist_region { - void *redist_base; - phys_addr_t phys_base; - bool single_redist; -}; - -struct partition_desc; - -struct gic_chip_data___2 { - struct fwnode_handle *fwnode; - void *dist_base; - struct redist_region *redist_regions; - struct rdists rdists; - struct irq_domain *domain; - u64 redist_stride; - u32 nr_redist_regions; - u64 flags; - bool has_rss; - unsigned int ppi_nr; - struct partition_desc **ppi_descs; -}; - -enum gic_intid_range { - SGI_RANGE = 0, - PPI_RANGE = 1, - SPI_RANGE = 2, - EPPI_RANGE = 3, - ESPI_RANGE = 4, - LPI_RANGE = 5, - __INVALID_RANGE__ = 6, -}; - -struct mbi_range { - u32 spi_start; - u32 nr_spis; - long unsigned int *bm; -}; - -enum its_vcpu_info_cmd_type { - MAP_VLPI = 0, - GET_VLPI = 1, - PROP_UPDATE_VLPI = 2, - PROP_UPDATE_AND_INV_VLPI = 3, - SCHEDULE_VPE = 4, - DESCHEDULE_VPE = 5, - INVALL_VPE = 6, - PROP_UPDATE_VSGI = 7, -}; - -struct its_cmd_info { - enum its_vcpu_info_cmd_type cmd_type; - union { - struct its_vlpi_map *map; - u8 config; - bool req_db; - struct { - bool g0en; - bool g1en; - }; - struct { - u8 priority; - bool group; - }; - }; -}; - -struct its_collection___2 { - u64 target_address; - u16 col_id; -}; - -struct its_baser { - void *base; - u64 val; - u32 order; - u32 psz; -}; - -struct its_cmd_block; - -struct its_device___2; - -struct its_node { - raw_spinlock_t lock; - struct mutex dev_alloc_lock; - struct list_head entry; - void *base; - void *sgir_base; - phys_addr_t phys_base; - struct its_cmd_block *cmd_base; - struct its_cmd_block *cmd_write; - struct its_baser tables[8]; - struct its_collection___2 *collections; - struct fwnode_handle *fwnode_handle; - u64 (*get_msi_base)(struct its_device___2 *); - u64 typer; - u64 cbaser_save; - u32 ctlr_save; - u32 mpidr; - struct list_head its_device_list; - u64 flags; - long unsigned int list_nr; - int numa_node; - unsigned int msi_domain_flags; - u32 pre_its_base; - int vlpi_redist_offset; -}; - -struct its_cmd_block { - union { - u64 raw_cmd[4]; - __le64 raw_cmd_le[4]; - }; -}; - -struct event_lpi_map { - long unsigned int *lpi_map; - u16 *col_map; - irq_hw_number_t lpi_base; - int nr_lpis; - raw_spinlock_t vlpi_lock; - struct its_vm *vm; - struct its_vlpi_map *vlpi_maps; - int nr_vlpis; -}; - -struct its_device___2 { - struct list_head entry; - struct its_node *its; - struct event_lpi_map event_map; - void *itt; - u32 nr_ites; - u32 device_id; - bool shared; -}; - -struct cpu_lpi_count { - atomic_t managed; - atomic_t unmanaged; -}; - -struct its_cmd_desc { - union { - struct { - struct its_device___2 *dev; - u32 event_id; - } its_inv_cmd; - struct { - struct its_device___2 *dev; - u32 event_id; - } its_clear_cmd; - struct { - struct its_device___2 *dev; - u32 event_id; - } its_int_cmd; - struct { - struct its_device___2 *dev; - int valid; - } its_mapd_cmd; - struct { - struct its_collection___2 *col; - int valid; - } its_mapc_cmd; - struct { - struct its_device___2 *dev; - u32 phys_id; - u32 event_id; - } its_mapti_cmd; - struct { - struct its_device___2 *dev; - struct its_collection___2 *col; - u32 event_id; - } its_movi_cmd; - struct { - struct its_device___2 *dev; - u32 event_id; - } its_discard_cmd; - struct { - struct its_collection___2 *col; - } its_invall_cmd; - struct { - struct its_vpe *vpe; - } its_vinvall_cmd; - struct { - struct its_vpe *vpe; - struct its_collection___2 *col; - bool valid; - } its_vmapp_cmd; - struct { - struct its_vpe *vpe; - struct its_device___2 *dev; - u32 virt_id; - u32 event_id; - bool db_enabled; - } its_vmapti_cmd; - struct { - struct its_vpe *vpe; - struct its_device___2 *dev; - u32 event_id; - bool db_enabled; - } its_vmovi_cmd; - struct { - struct its_vpe *vpe; - struct its_collection___2 *col; - u16 seq_num; - u16 its_list; - } its_vmovp_cmd; - struct { - struct its_vpe *vpe; - } its_invdb_cmd; - struct { - struct its_vpe *vpe; - u8 sgi; - u8 priority; - bool enable; - bool group; - bool clear; - } its_vsgi_cmd; - }; -}; - -typedef struct its_collection___2 * (*its_cmd_builder_t)(struct its_node *, struct its_cmd_block *, struct its_cmd_desc *); - -typedef struct its_vpe * (*its_cmd_vbuilder_t)(struct its_node *, struct its_cmd_block *, struct its_cmd_desc *); - -struct lpi_range { - struct list_head entry; - u32 base_id; - u32 span; -}; - -struct msi_controller { - struct module *owner; - struct device *dev; - struct device_node *of_node; - struct list_head list; - int (*setup_irq)(struct msi_controller *, struct pci_dev *, struct msi_desc *); - int (*setup_irqs)(struct msi_controller *, struct pci_dev *, int, int); - void (*teardown_irq)(struct msi_controller *, unsigned int); -}; - -struct partition_desc___2 { - int nr_parts; - struct partition_affinity *parts; - struct irq_domain *domain; - struct irq_desc *chained_desc; - long unsigned int *bitmap; - struct irq_domain_ops ops; -}; - -struct brcmstb_intc_init_params { - irq_flow_handler_t handler; - int cpu_status; - int cpu_clear; - int cpu_mask_status; - int cpu_mask_set; - int cpu_mask_clear; -}; - -struct brcmstb_l2_intc_data { - struct irq_domain *domain; - struct irq_chip_generic *gc; - int status_offset; - int mask_offset; - bool can_wake; - u32 saved_mask; -}; - -enum device_link_state { - DL_STATE_NONE = 4294967295, - DL_STATE_DORMANT = 0, - DL_STATE_AVAILABLE = 1, - DL_STATE_CONSUMER_PROBE = 2, - DL_STATE_ACTIVE = 3, - DL_STATE_SUPPLIER_UNBIND = 4, -}; - -struct device_link { - struct device *supplier; - struct list_head s_node; - struct device *consumer; - struct list_head c_node; - struct device link_dev; - enum device_link_state status; - u32 flags; - refcount_t rpm_active; - struct kref kref; - struct work_struct rm_work; - bool supplier_preactivated; -}; - -struct phy_configure_opts_dp { - unsigned int link_rate; - unsigned int lanes; - unsigned int voltage[4]; - unsigned int pre[4]; - u8 ssc: 1; - u8 set_rate: 1; - u8 set_lanes: 1; - u8 set_voltages: 1; -}; - -struct phy_configure_opts_mipi_dphy { - unsigned int clk_miss; - unsigned int clk_post; - unsigned int clk_pre; - unsigned int clk_prepare; - unsigned int clk_settle; - unsigned int clk_term_en; - unsigned int clk_trail; - unsigned int clk_zero; - unsigned int d_term_en; - unsigned int eot; - unsigned int hs_exit; - unsigned int hs_prepare; - unsigned int hs_settle; - unsigned int hs_skip; - unsigned int hs_trail; - unsigned int hs_zero; - unsigned int init; - unsigned int lpx; - unsigned int ta_get; - unsigned int ta_go; - unsigned int ta_sure; - unsigned int wakeup; - long unsigned int hs_clk_rate; - long unsigned int lp_clk_rate; - unsigned char lanes; -}; - -enum phy_mode { - PHY_MODE_INVALID = 0, - PHY_MODE_USB_HOST = 1, - PHY_MODE_USB_HOST_LS = 2, - PHY_MODE_USB_HOST_FS = 3, - PHY_MODE_USB_HOST_HS = 4, - PHY_MODE_USB_HOST_SS = 5, - PHY_MODE_USB_DEVICE = 6, - PHY_MODE_USB_DEVICE_LS = 7, - PHY_MODE_USB_DEVICE_FS = 8, - PHY_MODE_USB_DEVICE_HS = 9, - PHY_MODE_USB_DEVICE_SS = 10, - PHY_MODE_USB_OTG = 11, - PHY_MODE_UFS_HS_A = 12, - PHY_MODE_UFS_HS_B = 13, - PHY_MODE_PCIE = 14, - PHY_MODE_ETHERNET = 15, - PHY_MODE_MIPI_DPHY = 16, - PHY_MODE_SATA = 17, - PHY_MODE_LVDS = 18, - PHY_MODE_DP = 19, -}; - -union phy_configure_opts { - struct phy_configure_opts_mipi_dphy mipi_dphy; - struct phy_configure_opts_dp dp; -}; - -struct phy; - -struct phy_ops { - int (*init)(struct phy *); - int (*exit)(struct phy *); - int (*power_on)(struct phy *); - int (*power_off)(struct phy *); - int (*set_mode)(struct phy *, enum phy_mode, int); - int (*configure)(struct phy *, union phy_configure_opts *); - int (*validate)(struct phy *, enum phy_mode, int, union phy_configure_opts *); - int (*reset)(struct phy *); - int (*calibrate)(struct phy *); - void (*release)(struct phy *); - struct module *owner; -}; - -struct phy_attrs { - u32 bus_width; - u32 max_link_rate; - enum phy_mode mode; -}; - -struct regulator; - -struct phy { - struct device dev; - int id; - const struct phy_ops *ops; - struct mutex mutex; - int init_count; - int power_count; - struct phy_attrs attrs; - struct regulator *pwr; -}; - -struct phy_provider { - struct device *dev; - struct device_node *children; - struct module *owner; - struct list_head list; - struct phy * (*of_xlate)(struct device *, struct of_phandle_args *); -}; - -struct phy_lookup { - struct list_head node; - const char *dev_id; - const char *con_id; - struct phy *phy; -}; - -struct pinctrl; - -struct pinctrl_state; - -struct dev_pin_info { - struct pinctrl *p; - struct pinctrl_state *default_state; - struct pinctrl_state *init_state; - struct pinctrl_state *sleep_state; - struct pinctrl_state *idle_state; -}; - -struct pinctrl { - struct list_head node; - struct device *dev; - struct list_head states; - struct pinctrl_state *state; - struct list_head dt_maps; - struct kref users; -}; - -struct pinctrl_state { - struct list_head node; - const char *name; - struct list_head settings; -}; - -struct pinctrl_pin_desc { - unsigned int number; - const char *name; - void *drv_data; -}; - -struct gpio_chip; - -struct pinctrl_gpio_range { - struct list_head node; - const char *name; - unsigned int id; - unsigned int base; - unsigned int pin_base; - const unsigned int *pins; - unsigned int npins; - struct gpio_chip *gc; -}; - -struct gpio_irq_chip { - struct irq_chip *chip; - struct irq_domain *domain; - const struct irq_domain_ops *domain_ops; - struct fwnode_handle *fwnode; - struct irq_domain *parent_domain; - int (*child_to_parent_hwirq)(struct gpio_chip *, unsigned int, unsigned int, unsigned int *, unsigned int *); - void * (*populate_parent_alloc_arg)(struct gpio_chip *, unsigned int, unsigned int); - unsigned int (*child_offset_to_irq)(struct gpio_chip *, unsigned int); - struct irq_domain_ops child_irq_domain_ops; - irq_flow_handler_t handler; - unsigned int default_type; - struct lock_class_key *lock_key; - struct lock_class_key *request_key; - irq_flow_handler_t parent_handler; - void *parent_handler_data; - unsigned int num_parents; - unsigned int *parents; - unsigned int *map; - bool threaded; - int (*init_hw)(struct gpio_chip *); - void (*init_valid_mask)(struct gpio_chip *, long unsigned int *, unsigned int); - long unsigned int *valid_mask; - unsigned int first; - void (*irq_enable)(struct irq_data *); - void (*irq_disable)(struct irq_data *); - void (*irq_unmask)(struct irq_data *); - void (*irq_mask)(struct irq_data *); -}; - -struct gpio_device; - -struct gpio_chip { - const char *label; - struct gpio_device *gpiodev; - struct device *parent; - struct module *owner; - int (*request)(struct gpio_chip *, unsigned int); - void (*free)(struct gpio_chip *, unsigned int); - int (*get_direction)(struct gpio_chip *, unsigned int); - int (*direction_input)(struct gpio_chip *, unsigned int); - int (*direction_output)(struct gpio_chip *, unsigned int, int); - int (*get)(struct gpio_chip *, unsigned int); - int (*get_multiple)(struct gpio_chip *, long unsigned int *, long unsigned int *); - void (*set)(struct gpio_chip *, unsigned int, int); - void (*set_multiple)(struct gpio_chip *, long unsigned int *, long unsigned int *); - int (*set_config)(struct gpio_chip *, unsigned int, long unsigned int); - int (*to_irq)(struct gpio_chip *, unsigned int); - void (*dbg_show)(struct seq_file *, struct gpio_chip *); - int (*init_valid_mask)(struct gpio_chip *, long unsigned int *, unsigned int); - int (*add_pin_ranges)(struct gpio_chip *); - int base; - u16 ngpio; - const char * const *names; - bool can_sleep; - struct gpio_irq_chip irq; - long unsigned int *valid_mask; - struct device_node *of_node; - unsigned int of_gpio_n_cells; - int (*of_xlate)(struct gpio_chip *, const struct of_phandle_args *, u32 *); -}; - -struct pinctrl_dev; - -struct pinctrl_map; - -struct pinctrl_ops { - int (*get_groups_count)(struct pinctrl_dev *); - const char * (*get_group_name)(struct pinctrl_dev *, unsigned int); - int (*get_group_pins)(struct pinctrl_dev *, unsigned int, const unsigned int **, unsigned int *); - void (*pin_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int); - int (*dt_node_to_map)(struct pinctrl_dev *, struct device_node *, struct pinctrl_map **, unsigned int *); - void (*dt_free_map)(struct pinctrl_dev *, struct pinctrl_map *, unsigned int); -}; - -struct pinctrl_desc; - -struct pinctrl_dev { - struct list_head node; - struct pinctrl_desc *desc; - struct xarray pin_desc_tree; - struct list_head gpio_ranges; - struct device *dev; - struct module *owner; - void *driver_data; - struct pinctrl *p; - struct pinctrl_state *hog_default; - struct pinctrl_state *hog_sleep; - struct mutex mutex; - struct dentry *device_root; -}; - -enum pinctrl_map_type { - PIN_MAP_TYPE_INVALID = 0, - PIN_MAP_TYPE_DUMMY_STATE = 1, - PIN_MAP_TYPE_MUX_GROUP = 2, - PIN_MAP_TYPE_CONFIGS_PIN = 3, - PIN_MAP_TYPE_CONFIGS_GROUP = 4, -}; - -struct pinctrl_map_mux { - const char *group; - const char *function; -}; - -struct pinctrl_map_configs { - const char *group_or_pin; - long unsigned int *configs; - unsigned int num_configs; -}; - -struct pinctrl_map { - const char *dev_name; - const char *name; - enum pinctrl_map_type type; - const char *ctrl_dev_name; - union { - struct pinctrl_map_mux mux; - struct pinctrl_map_configs configs; - } data; -}; - -struct pinmux_ops; - -struct pinconf_ops; - -struct pinconf_generic_params; - -struct pin_config_item; - -struct pinctrl_desc { - const char *name; - const struct pinctrl_pin_desc *pins; - unsigned int npins; - const struct pinctrl_ops *pctlops; - const struct pinmux_ops *pmxops; - const struct pinconf_ops *confops; - struct module *owner; - unsigned int num_custom_params; - const struct pinconf_generic_params *custom_params; - const struct pin_config_item *custom_conf_items; - bool link_consumers; -}; - -struct pinmux_ops { - int (*request)(struct pinctrl_dev *, unsigned int); - int (*free)(struct pinctrl_dev *, unsigned int); - int (*get_functions_count)(struct pinctrl_dev *); - const char * (*get_function_name)(struct pinctrl_dev *, unsigned int); - int (*get_function_groups)(struct pinctrl_dev *, unsigned int, const char * const **, unsigned int *); - int (*set_mux)(struct pinctrl_dev *, unsigned int, unsigned int); - int (*gpio_request_enable)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int); - void (*gpio_disable_free)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int); - int (*gpio_set_direction)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int, bool); - bool strict; -}; - -struct pinconf_ops { - bool is_generic; - int (*pin_config_get)(struct pinctrl_dev *, unsigned int, long unsigned int *); - int (*pin_config_set)(struct pinctrl_dev *, unsigned int, long unsigned int *, unsigned int); - int (*pin_config_group_get)(struct pinctrl_dev *, unsigned int, long unsigned int *); - int (*pin_config_group_set)(struct pinctrl_dev *, unsigned int, long unsigned int *, unsigned int); - void (*pin_config_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int); - void (*pin_config_group_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int); - void (*pin_config_config_dbg_show)(struct pinctrl_dev *, struct seq_file *, long unsigned int); -}; - -enum pin_config_param { - PIN_CONFIG_BIAS_BUS_HOLD = 0, - PIN_CONFIG_BIAS_DISABLE = 1, - PIN_CONFIG_BIAS_HIGH_IMPEDANCE = 2, - PIN_CONFIG_BIAS_PULL_DOWN = 3, - PIN_CONFIG_BIAS_PULL_PIN_DEFAULT = 4, - PIN_CONFIG_BIAS_PULL_UP = 5, - PIN_CONFIG_DRIVE_OPEN_DRAIN = 6, - PIN_CONFIG_DRIVE_OPEN_SOURCE = 7, - PIN_CONFIG_DRIVE_PUSH_PULL = 8, - PIN_CONFIG_DRIVE_STRENGTH = 9, - PIN_CONFIG_DRIVE_STRENGTH_UA = 10, - PIN_CONFIG_INPUT_DEBOUNCE = 11, - PIN_CONFIG_INPUT_ENABLE = 12, - PIN_CONFIG_INPUT_SCHMITT = 13, - PIN_CONFIG_INPUT_SCHMITT_ENABLE = 14, - PIN_CONFIG_LOW_POWER_MODE = 15, - PIN_CONFIG_OUTPUT_ENABLE = 16, - PIN_CONFIG_OUTPUT = 17, - PIN_CONFIG_POWER_SOURCE = 18, - PIN_CONFIG_SLEEP_HARDWARE_STATE = 19, - PIN_CONFIG_SLEW_RATE = 20, - PIN_CONFIG_SKEW_DELAY = 21, - PIN_CONFIG_PERSIST_STATE = 22, - PIN_CONFIG_END = 127, - PIN_CONFIG_MAX = 255, -}; - -struct pinconf_generic_params { - const char * const property; - enum pin_config_param param; - u32 default_value; -}; - -struct pin_config_item { - const enum pin_config_param param; - const char * const display; - const char * const format; - bool has_arg; -}; - -struct gpio_desc; - -struct gpio_device { - int id; - struct device dev; - struct cdev chrdev; - struct device *mockdev; - struct module *owner; - struct gpio_chip *chip; - struct gpio_desc *descs; - int base; - u16 ngpio; - const char *label; - void *data; - struct list_head list; - struct blocking_notifier_head notifier; - struct list_head pin_ranges; -}; - -struct gpio_desc { - struct gpio_device *gdev; - long unsigned int flags; - const char *label; - const char *name; - struct device_node *hog; - unsigned int debounce_period_us; -}; - -struct pinctrl_setting_mux { - unsigned int group; - unsigned int func; -}; - -struct pinctrl_setting_configs { - unsigned int group_or_pin; - long unsigned int *configs; - unsigned int num_configs; -}; - -struct pinctrl_setting { - struct list_head node; - enum pinctrl_map_type type; - struct pinctrl_dev *pctldev; - const char *dev_name; - union { - struct pinctrl_setting_mux mux; - struct pinctrl_setting_configs configs; - } data; -}; - -struct pin_desc { - struct pinctrl_dev *pctldev; - const char *name; - bool dynamic_name; - void *drv_data; - unsigned int mux_usecount; - const char *mux_owner; - const struct pinctrl_setting_mux *mux_setting; - const char *gpio_owner; -}; - -struct pinctrl_maps { - struct list_head node; - const struct pinctrl_map *maps; - unsigned int num_maps; -}; - -struct pctldev; - -struct pinctrl_dt_map { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_map *map; - unsigned int num_maps; -}; - -struct bcm2835_pinctrl { - struct device *dev; - void *base; - int *wake_irq; - long unsigned int enabled_irq_map[2]; - unsigned int irq_type[58]; - struct pinctrl_dev *pctl_dev; - struct gpio_chip gpio_chip; - struct pinctrl_desc pctl_desc; - struct pinctrl_gpio_range gpio_range; - raw_spinlock_t irq_lock[2]; -}; - -enum bcm2835_fsel { - BCM2835_FSEL_COUNT = 8, - BCM2835_FSEL_MASK = 7, -}; - -struct bcm_plat_data { - const struct gpio_chip *gpio_chip; - const struct pinctrl_desc *pctl_desc; - const struct pinctrl_gpio_range *gpio_range; -}; - -struct gpio_pin_range { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_gpio_range range; -}; - -struct gpio_array; - -struct gpio_descs { - struct gpio_array *info; - unsigned int ndescs; - struct gpio_desc *desc[0]; -}; - -struct gpio_array { - struct gpio_desc **desc; - unsigned int size; - struct gpio_chip *chip; - long unsigned int *get_mask; - long unsigned int *set_mask; - long unsigned int invert_mask[0]; -}; - -enum gpiod_flags { - GPIOD_ASIS = 0, - GPIOD_IN = 1, - GPIOD_OUT_LOW = 3, - GPIOD_OUT_HIGH = 7, - GPIOD_OUT_LOW_OPEN_DRAIN = 11, - GPIOD_OUT_HIGH_OPEN_DRAIN = 15, -}; - -enum gpio_lookup_flags { - GPIO_ACTIVE_HIGH = 0, - GPIO_ACTIVE_LOW = 1, - GPIO_OPEN_DRAIN = 2, - GPIO_OPEN_SOURCE = 4, - GPIO_PERSISTENT = 0, - GPIO_TRANSITORY = 8, - GPIO_PULL_UP = 16, - GPIO_PULL_DOWN = 32, - GPIO_LOOKUP_FLAGS_DEFAULT = 0, -}; - -struct gpiod_lookup { - const char *key; - u16 chip_hwnum; - const char *con_id; - unsigned int idx; - long unsigned int flags; -}; - -struct gpiod_lookup_table { - struct list_head list; - const char *dev_id; - struct gpiod_lookup table[0]; -}; - -struct gpiod_hog { - struct list_head list; - const char *chip_label; - u16 chip_hwnum; - const char *line_name; - long unsigned int lflags; - int dflags; -}; - -enum { - GPIOLINE_CHANGED_REQUESTED = 1, - GPIOLINE_CHANGED_RELEASED = 2, - GPIOLINE_CHANGED_CONFIG = 3, -}; - -struct acpi_device; - -struct acpi_gpio_info { - struct acpi_device *adev; - enum gpiod_flags flags; - bool gpioint; - int pin_config; - int polarity; - int triggering; - unsigned int quirks; -}; - -struct trace_event_raw_gpio_direction { - struct trace_entry ent; - unsigned int gpio; - int in; - int err; - char __data[0]; -}; - -struct trace_event_raw_gpio_value { - struct trace_entry ent; - unsigned int gpio; - int get; - int value; - char __data[0]; -}; - -struct trace_event_data_offsets_gpio_direction {}; - -struct trace_event_data_offsets_gpio_value {}; - -typedef void (*btf_trace_gpio_direction)(void *, unsigned int, int, int); - -typedef void (*btf_trace_gpio_value)(void *, unsigned int, int, int); - -struct devres; - -struct gpio { - unsigned int gpio; - long unsigned int flags; - const char *label; -}; - -struct of_reconfig_data { - struct device_node *dn; - struct property *prop; - struct property *old_prop; -}; - -enum of_reconfig_change { - OF_RECONFIG_NO_CHANGE = 0, - OF_RECONFIG_CHANGE_ADD = 1, - OF_RECONFIG_CHANGE_REMOVE = 2, -}; - -enum of_gpio_flags { - OF_GPIO_ACTIVE_LOW = 1, - OF_GPIO_SINGLE_ENDED = 2, - OF_GPIO_OPEN_DRAIN = 4, - OF_GPIO_TRANSITORY = 8, - OF_GPIO_PULL_UP = 16, - OF_GPIO_PULL_DOWN = 32, -}; - -struct of_mm_gpio_chip { - struct gpio_chip gc; - void (*save_regs)(struct of_mm_gpio_chip *); - void *regs; -}; - -struct gpiochip_info { - char name[32]; - char label[32]; - __u32 lines; -}; - -enum gpio_v2_line_flag { - GPIO_V2_LINE_FLAG_USED = 1, - GPIO_V2_LINE_FLAG_ACTIVE_LOW = 2, - GPIO_V2_LINE_FLAG_INPUT = 4, - GPIO_V2_LINE_FLAG_OUTPUT = 8, - GPIO_V2_LINE_FLAG_EDGE_RISING = 16, - GPIO_V2_LINE_FLAG_EDGE_FALLING = 32, - GPIO_V2_LINE_FLAG_OPEN_DRAIN = 64, - GPIO_V2_LINE_FLAG_OPEN_SOURCE = 128, - GPIO_V2_LINE_FLAG_BIAS_PULL_UP = 256, - GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = 512, - GPIO_V2_LINE_FLAG_BIAS_DISABLED = 1024, -}; - -struct gpio_v2_line_values { - __u64 bits; - __u64 mask; -}; - -enum gpio_v2_line_attr_id { - GPIO_V2_LINE_ATTR_ID_FLAGS = 1, - GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES = 2, - GPIO_V2_LINE_ATTR_ID_DEBOUNCE = 3, -}; - -struct gpio_v2_line_attribute { - __u32 id; - __u32 padding; - union { - __u64 flags; - __u64 values; - __u32 debounce_period_us; - }; -}; - -struct gpio_v2_line_config_attribute { - struct gpio_v2_line_attribute attr; - __u64 mask; -}; - -struct gpio_v2_line_config { - __u64 flags; - __u32 num_attrs; - __u32 padding[5]; - struct gpio_v2_line_config_attribute attrs[10]; -}; - -struct gpio_v2_line_request { - __u32 offsets[64]; - char consumer[32]; - struct gpio_v2_line_config config; - __u32 num_lines; - __u32 event_buffer_size; - __u32 padding[5]; - __s32 fd; -}; - -struct gpio_v2_line_info { - char name[32]; - char consumer[32]; - __u32 offset; - __u32 num_attrs; - __u64 flags; - struct gpio_v2_line_attribute attrs[10]; - __u32 padding[4]; -}; - -enum gpio_v2_line_changed_type { - GPIO_V2_LINE_CHANGED_REQUESTED = 1, - GPIO_V2_LINE_CHANGED_RELEASED = 2, - GPIO_V2_LINE_CHANGED_CONFIG = 3, -}; - -struct gpio_v2_line_info_changed { - struct gpio_v2_line_info info; - __u64 timestamp_ns; - __u32 event_type; - __u32 padding[5]; -}; - -enum gpio_v2_line_event_id { - GPIO_V2_LINE_EVENT_RISING_EDGE = 1, - GPIO_V2_LINE_EVENT_FALLING_EDGE = 2, -}; - -struct gpio_v2_line_event { - __u64 timestamp_ns; - __u32 id; - __u32 offset; - __u32 seqno; - __u32 line_seqno; - __u32 padding[6]; -}; - -struct gpioline_info { - __u32 line_offset; - __u32 flags; - char name[32]; - char consumer[32]; -}; - -struct gpioline_info_changed { - struct gpioline_info info; - __u64 timestamp; - __u32 event_type; - __u32 padding[5]; -}; - -struct gpiohandle_request { - __u32 lineoffsets[64]; - __u32 flags; - __u8 default_values[64]; - char consumer_label[32]; - __u32 lines; - int fd; -}; - -struct gpiohandle_config { - __u32 flags; - __u8 default_values[64]; - __u32 padding[4]; -}; - -struct gpiohandle_data { - __u8 values[64]; -}; - -struct gpioevent_request { - __u32 lineoffset; - __u32 handleflags; - __u32 eventflags; - char consumer_label[32]; - int fd; -}; - -struct gpioevent_data { - __u64 timestamp; - __u32 id; -}; - -struct linehandle_state { - struct gpio_device *gdev; - const char *label; - struct gpio_desc *descs[64]; - u32 num_descs; -}; - -struct linereq; - -struct line { - struct gpio_desc *desc; - struct linereq *req; - unsigned int irq; - u64 eflags; - u64 timestamp_ns; - u32 req_seqno; - u32 line_seqno; - struct delayed_work work; - unsigned int sw_debounced; - unsigned int level; -}; - -struct linereq { - struct gpio_device *gdev; - const char *label; - u32 num_lines; - wait_queue_head_t wait; - u32 event_buffer_size; - struct { - union { - struct __kfifo kfifo; - struct gpio_v2_line_event *type; - const struct gpio_v2_line_event *const_type; - char (*rectype)[0]; - struct gpio_v2_line_event *ptr; - const struct gpio_v2_line_event *ptr_const; - }; - struct gpio_v2_line_event buf[0]; - } events; - atomic_t seqno; - struct mutex config_mutex; - struct line lines[0]; -}; - -struct lineevent_state { - struct gpio_device *gdev; - const char *label; - struct gpio_desc *desc; - u32 eflags; - int irq; - wait_queue_head_t wait; - struct { - union { - struct __kfifo kfifo; - struct gpioevent_data *type; - const struct gpioevent_data *const_type; - char (*rectype)[0]; - struct gpioevent_data *ptr; - const struct gpioevent_data *ptr_const; - }; - struct gpioevent_data buf[16]; - } events; - u64 timestamp; -}; - -struct gpio_chardev_data { - struct gpio_device *gdev; - wait_queue_head_t wait; - struct { - union { - struct __kfifo kfifo; - struct gpio_v2_line_info_changed *type; - const struct gpio_v2_line_info_changed *const_type; - char (*rectype)[0]; - struct gpio_v2_line_info_changed *ptr; - const struct gpio_v2_line_info_changed *ptr_const; - }; - struct gpio_v2_line_info_changed buf[32]; - } events; - struct notifier_block lineinfo_changed_nb; - long unsigned int *watched_lines; - atomic_t watch_abi_version; -}; - -struct class_attribute { - struct attribute attr; - ssize_t (*show)(struct class *, struct class_attribute *, char *); - ssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t); -}; - -struct gpiod_data { - struct gpio_desc *desc; - struct mutex mutex; - struct kernfs_node *value_kn; - int irq; - unsigned char irq_flags; - bool direction_can_change; -}; - -enum rpi_firmware_property_tag { - RPI_FIRMWARE_PROPERTY_END = 0, - RPI_FIRMWARE_GET_FIRMWARE_REVISION = 1, - RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 2, - RPI_FIRMWARE_GET_FIRMWARE_HASH = 3, - RPI_FIRMWARE_SET_CURSOR_INFO = 32784, - RPI_FIRMWARE_SET_CURSOR_STATE = 32785, - RPI_FIRMWARE_GET_BOARD_MODEL = 65537, - RPI_FIRMWARE_GET_BOARD_REVISION = 65538, - RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 65539, - RPI_FIRMWARE_GET_BOARD_SERIAL = 65540, - RPI_FIRMWARE_GET_ARM_MEMORY = 65541, - RPI_FIRMWARE_GET_VC_MEMORY = 65542, - RPI_FIRMWARE_GET_CLOCKS = 65543, - RPI_FIRMWARE_GET_POWER_STATE = 131073, - RPI_FIRMWARE_GET_TIMING = 131074, - RPI_FIRMWARE_SET_POWER_STATE = 163841, - RPI_FIRMWARE_GET_CLOCK_STATE = 196609, - RPI_FIRMWARE_GET_CLOCK_RATE = 196610, - RPI_FIRMWARE_GET_VOLTAGE = 196611, - RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 196612, - RPI_FIRMWARE_GET_MAX_VOLTAGE = 196613, - RPI_FIRMWARE_GET_TEMPERATURE = 196614, - RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 196615, - RPI_FIRMWARE_GET_MIN_VOLTAGE = 196616, - RPI_FIRMWARE_GET_TURBO = 196617, - RPI_FIRMWARE_GET_MAX_TEMPERATURE = 196618, - RPI_FIRMWARE_GET_STC = 196619, - RPI_FIRMWARE_ALLOCATE_MEMORY = 196620, - RPI_FIRMWARE_LOCK_MEMORY = 196621, - RPI_FIRMWARE_UNLOCK_MEMORY = 196622, - RPI_FIRMWARE_RELEASE_MEMORY = 196623, - RPI_FIRMWARE_EXECUTE_CODE = 196624, - RPI_FIRMWARE_EXECUTE_QPU = 196625, - RPI_FIRMWARE_SET_ENABLE_QPU = 196626, - RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 196628, - RPI_FIRMWARE_GET_EDID_BLOCK = 196640, - RPI_FIRMWARE_GET_CUSTOMER_OTP = 196641, - RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 196643, - RPI_FIRMWARE_GET_DOMAIN_STATE = 196656, - RPI_FIRMWARE_GET_THROTTLED = 196678, - RPI_FIRMWARE_GET_CLOCK_MEASURED = 196679, - RPI_FIRMWARE_NOTIFY_REBOOT = 196680, - RPI_FIRMWARE_SET_CLOCK_STATE = 229377, - RPI_FIRMWARE_SET_CLOCK_RATE = 229378, - RPI_FIRMWARE_SET_VOLTAGE = 229379, - RPI_FIRMWARE_SET_TURBO = 229385, - RPI_FIRMWARE_SET_CUSTOMER_OTP = 229409, - RPI_FIRMWARE_SET_DOMAIN_STATE = 229424, - RPI_FIRMWARE_GET_GPIO_STATE = 196673, - RPI_FIRMWARE_SET_GPIO_STATE = 229441, - RPI_FIRMWARE_SET_SDHOST_CLOCK = 229442, - RPI_FIRMWARE_GET_GPIO_CONFIG = 196675, - RPI_FIRMWARE_SET_GPIO_CONFIG = 229443, - RPI_FIRMWARE_GET_PERIPH_REG = 196677, - RPI_FIRMWARE_SET_PERIPH_REG = 229445, - RPI_FIRMWARE_GET_POE_HAT_VAL = 196681, - RPI_FIRMWARE_SET_POE_HAT_VAL = 229449, - RPI_FIRMWARE_SET_POE_HAT_VAL_OLD = 196688, - RPI_FIRMWARE_NOTIFY_XHCI_RESET = 196696, - RPI_FIRMWARE_GET_REBOOT_FLAGS = 196708, - RPI_FIRMWARE_SET_REBOOT_FLAGS = 229476, - RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 196710, - RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 262145, - RPI_FIRMWARE_FRAMEBUFFER_BLANK = 262146, - RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 262147, - RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 262148, - RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 262149, - RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 262150, - RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 262151, - RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 262152, - RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 262153, - RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 262154, - RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 262155, - RPI_FIRMWARE_FRAMEBUFFER_GET_LAYER = 262156, - RPI_FIRMWARE_FRAMEBUFFER_GET_TRANSFORM = 262157, - RPI_FIRMWARE_FRAMEBUFFER_GET_VSYNC = 262158, - RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 262159, - RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 262160, - RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 294913, - RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 262166, - RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 294931, - RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 262163, - RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 262164, - RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 278531, - RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 278532, - RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 278533, - RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 278534, - RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 278535, - RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 278537, - RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 278538, - RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 278539, - RPI_FIRMWARE_FRAMEBUFFER_TEST_LAYER = 278540, - RPI_FIRMWARE_FRAMEBUFFER_TEST_TRANSFORM = 278541, - RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 278542, - RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 294915, - RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 294916, - RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 294917, - RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 294918, - RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 294919, - RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 294920, - RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 294921, - RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 294922, - RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 294923, - RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 294943, - RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 294944, - RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 294926, - RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER = 294924, - RPI_FIRMWARE_FRAMEBUFFER_SET_TRANSFORM = 294925, - RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 294927, - RPI_FIRMWARE_VCHIQ_INIT = 294928, - RPI_FIRMWARE_SET_PLANE = 294933, - RPI_FIRMWARE_GET_DISPLAY_TIMING = 262167, - RPI_FIRMWARE_SET_TIMING = 294935, - RPI_FIRMWARE_GET_DISPLAY_CFG = 262168, - RPI_FIRMWARE_SET_DISPLAY_POWER = 294937, - RPI_FIRMWARE_GET_COMMAND_LINE = 327681, - RPI_FIRMWARE_GET_DMA_CHANNELS = 393217, -}; - -struct brcmvirt_gpio { - struct gpio_chip gc; - u32 *ts_base; - u32 enables_disables[2]; - dma_addr_t bus_addr; -}; - -struct rpi_firmware; - -struct rpi_exp_gpio { - struct gpio_chip gc; - struct rpi_firmware *fw; -}; - -struct gpio_set_config { - u32 gpio; - u32 direction; - u32 polarity; - u32 term_en; - u32 term_pull_up; - u32 state; -}; - -struct gpio_get_config { - u32 gpio; - u32 direction; - u32 polarity; - u32 term_en; - u32 term_pull_up; -}; - -struct gpio_get_set_state { - u32 gpio; - u32 state; -}; - -enum stmpe_block { - STMPE_BLOCK_GPIO = 1, - STMPE_BLOCK_KEYPAD = 2, - STMPE_BLOCK_TOUCHSCREEN = 4, - STMPE_BLOCK_ADC = 8, - STMPE_BLOCK_PWM = 16, - STMPE_BLOCK_ROTATOR = 32, -}; - -enum stmpe_partnum { - STMPE610 = 0, - STMPE801 = 1, - STMPE811 = 2, - STMPE1600 = 3, - STMPE1601 = 4, - STMPE1801 = 5, - STMPE2401 = 6, - STMPE2403 = 7, - STMPE_NBR_PARTS = 8, -}; - -enum { - STMPE_IDX_CHIP_ID = 0, - STMPE_IDX_SYS_CTRL = 1, - STMPE_IDX_SYS_CTRL2 = 2, - STMPE_IDX_ICR_LSB = 3, - STMPE_IDX_IER_LSB = 4, - STMPE_IDX_IER_MSB = 5, - STMPE_IDX_ISR_LSB = 6, - STMPE_IDX_ISR_MSB = 7, - STMPE_IDX_GPMR_LSB = 8, - STMPE_IDX_GPMR_CSB = 9, - STMPE_IDX_GPMR_MSB = 10, - STMPE_IDX_GPSR_LSB = 11, - STMPE_IDX_GPSR_CSB = 12, - STMPE_IDX_GPSR_MSB = 13, - STMPE_IDX_GPCR_LSB = 14, - STMPE_IDX_GPCR_CSB = 15, - STMPE_IDX_GPCR_MSB = 16, - STMPE_IDX_GPDR_LSB = 17, - STMPE_IDX_GPDR_CSB = 18, - STMPE_IDX_GPDR_MSB = 19, - STMPE_IDX_GPEDR_LSB = 20, - STMPE_IDX_GPEDR_CSB = 21, - STMPE_IDX_GPEDR_MSB = 22, - STMPE_IDX_GPRER_LSB = 23, - STMPE_IDX_GPRER_CSB = 24, - STMPE_IDX_GPRER_MSB = 25, - STMPE_IDX_GPFER_LSB = 26, - STMPE_IDX_GPFER_CSB = 27, - STMPE_IDX_GPFER_MSB = 28, - STMPE_IDX_GPPUR_LSB = 29, - STMPE_IDX_GPPDR_LSB = 30, - STMPE_IDX_GPAFR_U_MSB = 31, - STMPE_IDX_IEGPIOR_LSB = 32, - STMPE_IDX_IEGPIOR_CSB = 33, - STMPE_IDX_IEGPIOR_MSB = 34, - STMPE_IDX_ISGPIOR_LSB = 35, - STMPE_IDX_ISGPIOR_CSB = 36, - STMPE_IDX_ISGPIOR_MSB = 37, - STMPE_IDX_MAX = 38, -}; - -struct stmpe_client_info; - -struct stmpe_variant_info; - -struct stmpe_platform_data; - -struct stmpe { - struct regulator *vcc; - struct regulator *vio; - struct mutex lock; - struct mutex irq_lock; - struct device *dev; - struct irq_domain *domain; - void *client; - struct stmpe_client_info *ci; - enum stmpe_partnum partnum; - struct stmpe_variant_info *variant; - const u8 *regs; - int irq; - int num_gpios; - u8 ier[2]; - u8 oldier[2]; - struct stmpe_platform_data *pdata; - u8 sample_time; - u8 mod_12b; - u8 ref_sel; - u8 adc_freq; -}; - -enum { - REG_RE = 0, - REG_FE = 1, - REG_IE = 2, -}; - -enum { - LSB = 0, - CSB = 1, - MSB = 2, -}; - -struct stmpe_gpio { - struct gpio_chip chip; - struct stmpe *stmpe; - struct device *dev; - struct mutex irq_lock; - u32 norequest_mask; - u8 regs[9]; - u8 oldregs[9]; -}; - -enum pwm_polarity { - PWM_POLARITY_NORMAL = 0, - PWM_POLARITY_INVERSED = 1, -}; - -struct pwm_args { - u64 period; - enum pwm_polarity polarity; -}; - -enum { - PWMF_REQUESTED = 1, - PWMF_EXPORTED = 2, -}; - -struct pwm_state { - u64 period; - u64 duty_cycle; - enum pwm_polarity polarity; - bool enabled; -}; - -struct pwm_chip; - -struct pwm_device { - const char *label; - long unsigned int flags; - unsigned int hwpwm; - unsigned int pwm; - struct pwm_chip *chip; - void *chip_data; - struct pwm_args args; - struct pwm_state state; - struct pwm_state last; -}; - -struct pwm_ops; - -struct pwm_chip { - struct device *dev; - const struct pwm_ops *ops; - int base; - unsigned int npwm; - struct pwm_device * (*of_xlate)(struct pwm_chip *, const struct of_phandle_args *); - unsigned int of_pwm_n_cells; - struct list_head list; - struct pwm_device *pwms; -}; - -struct pwm_capture; - -struct pwm_ops { - int (*request)(struct pwm_chip *, struct pwm_device *); - void (*free)(struct pwm_chip *, struct pwm_device *); - int (*capture)(struct pwm_chip *, struct pwm_device *, struct pwm_capture *, long unsigned int); - int (*apply)(struct pwm_chip *, struct pwm_device *, const struct pwm_state *); - void (*get_state)(struct pwm_chip *, struct pwm_device *, struct pwm_state *); - struct module *owner; - int (*config)(struct pwm_chip *, struct pwm_device *, int, int); - int (*set_polarity)(struct pwm_chip *, struct pwm_device *, enum pwm_polarity); - int (*enable)(struct pwm_chip *, struct pwm_device *); - void (*disable)(struct pwm_chip *, struct pwm_device *); -}; - -struct pwm_capture { - unsigned int period; - unsigned int duty_cycle; -}; - -struct pwm_lookup { - struct list_head list; - const char *provider; - unsigned int index; - const char *dev_id; - const char *con_id; - unsigned int period; - enum pwm_polarity polarity; - const char *module; -}; - -struct trace_event_raw_pwm { - struct trace_entry ent; - struct pwm_device *pwm; - u64 period; - u64 duty_cycle; - enum pwm_polarity polarity; - bool enabled; - char __data[0]; -}; - -struct trace_event_data_offsets_pwm {}; - -typedef void (*btf_trace_pwm_apply)(void *, struct pwm_device *, const struct pwm_state *); - -typedef void (*btf_trace_pwm_get)(void *, struct pwm_device *, const struct pwm_state *); - -struct pwm_export { - struct device child; - struct pwm_device *pwm; - struct mutex lock; - struct pwm_state suspend; -}; - -enum { - pci_channel_io_normal = 1, - pci_channel_io_frozen = 2, - pci_channel_io_perm_failure = 3, -}; - -struct pci_bus_resource { - struct list_head list; - struct resource *res; - unsigned int flags; -}; - -typedef u64 pci_bus_addr_t; - -struct pci_bus_region { - pci_bus_addr_t start; - pci_bus_addr_t end; -}; - -enum pci_fixup_pass { - pci_fixup_early = 0, - pci_fixup_header = 1, - pci_fixup_final = 2, - pci_fixup_enable = 3, - pci_fixup_resume = 4, - pci_fixup_suspend = 5, - pci_fixup_resume_early = 6, - pci_fixup_suspend_late = 7, -}; - -struct hotplug_slot_ops; - -struct hotplug_slot { - const struct hotplug_slot_ops *ops; - struct list_head slot_list; - struct pci_slot *pci_slot; - struct module *owner; - const char *mod_name; -}; - -enum pci_dev_flags { - PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = 1, - PCI_DEV_FLAGS_NO_D3 = 2, - PCI_DEV_FLAGS_ASSIGNED = 4, - PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = 8, - PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = 32, - PCI_DEV_FLAGS_NO_BUS_RESET = 64, - PCI_DEV_FLAGS_NO_PM_RESET = 128, - PCI_DEV_FLAGS_VPD_REF_F0 = 256, - PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT = 512, - PCI_DEV_FLAGS_NO_FLR_RESET = 1024, - PCI_DEV_FLAGS_NO_RELAXED_ORDERING = 2048, - PCI_DEV_FLAGS_HAS_MSI_MASKING = 4096, -}; - -enum pci_bus_flags { - PCI_BUS_FLAGS_NO_MSI = 1, - PCI_BUS_FLAGS_NO_MMRBC = 2, - PCI_BUS_FLAGS_NO_AERSID = 4, - PCI_BUS_FLAGS_NO_EXTCFG = 8, -}; - -enum pci_bus_speed { - PCI_SPEED_33MHz = 0, - PCI_SPEED_66MHz = 1, - PCI_SPEED_66MHz_PCIX = 2, - PCI_SPEED_100MHz_PCIX = 3, - PCI_SPEED_133MHz_PCIX = 4, - PCI_SPEED_66MHz_PCIX_ECC = 5, - PCI_SPEED_100MHz_PCIX_ECC = 6, - PCI_SPEED_133MHz_PCIX_ECC = 7, - PCI_SPEED_66MHz_PCIX_266 = 9, - PCI_SPEED_100MHz_PCIX_266 = 10, - PCI_SPEED_133MHz_PCIX_266 = 11, - AGP_UNKNOWN = 12, - AGP_1X = 13, - AGP_2X = 14, - AGP_4X = 15, - AGP_8X = 16, - PCI_SPEED_66MHz_PCIX_533 = 17, - PCI_SPEED_100MHz_PCIX_533 = 18, - PCI_SPEED_133MHz_PCIX_533 = 19, - PCIE_SPEED_2_5GT = 20, - PCIE_SPEED_5_0GT = 21, - PCIE_SPEED_8_0GT = 22, - PCIE_SPEED_16_0GT = 23, - PCIE_SPEED_32_0GT = 24, - PCI_SPEED_UNKNOWN = 255, -}; - -struct pci_host_bridge { - struct device dev; - struct pci_bus *bus; - struct pci_ops *ops; - struct pci_ops *child_ops; - void *sysdata; - int busnr; - struct list_head windows; - struct list_head dma_ranges; - u8 (*swizzle_irq)(struct pci_dev *, u8 *); - int (*map_irq)(const struct pci_dev *, u8, u8); - void (*release_fn)(struct pci_host_bridge *); - void *release_data; - struct msi_controller *msi; - unsigned int ignore_reset_delay: 1; - unsigned int no_ext_tags: 1; - unsigned int native_aer: 1; - unsigned int native_pcie_hotplug: 1; - unsigned int native_shpc_hotplug: 1; - unsigned int native_pme: 1; - unsigned int native_ltr: 1; - unsigned int native_dpc: 1; - unsigned int preserve_config: 1; - unsigned int size_windows: 1; - resource_size_t (*align_resource)(struct pci_dev *, const struct resource *, resource_size_t, resource_size_t, resource_size_t); - long: 64; - long unsigned int private[0]; -}; - -enum { - PCI_REASSIGN_ALL_RSRC = 1, - PCI_REASSIGN_ALL_BUS = 2, - PCI_PROBE_ONLY = 4, - PCI_CAN_SKIP_ISA_ALIGN = 8, - PCI_ENABLE_PROC_DOMAINS = 16, - PCI_COMPAT_DOMAIN_0 = 32, - PCI_SCAN_ALL_PCIE_DEVS = 64, -}; - -enum pcie_bus_config_types { - PCIE_BUS_TUNE_OFF = 0, - PCIE_BUS_DEFAULT = 1, - PCIE_BUS_SAFE = 2, - PCIE_BUS_PERFORMANCE = 3, - PCIE_BUS_PEER2PEER = 4, -}; - -struct hotplug_slot_ops { - int (*enable_slot)(struct hotplug_slot *); - int (*disable_slot)(struct hotplug_slot *); - int (*set_attention_status)(struct hotplug_slot *, u8); - int (*hardware_test)(struct hotplug_slot *, u32); - int (*get_power_status)(struct hotplug_slot *, u8 *); - int (*get_attention_status)(struct hotplug_slot *, u8 *); - int (*get_latch_status)(struct hotplug_slot *, u8 *); - int (*get_adapter_status)(struct hotplug_slot *, u8 *); - int (*reset_slot)(struct hotplug_slot *, int); -}; - -enum pci_bar_type { - pci_bar_unknown = 0, - pci_bar_io = 1, - pci_bar_mem32 = 2, - pci_bar_mem64 = 3, -}; - -struct pci_domain_busn_res { - struct list_head list; - struct resource res; - int domain_nr; -}; - -struct dmi_strmatch { - unsigned char slot: 7; - unsigned char exact_match: 1; - char substr[79]; -}; - -struct dmi_system_id { - int (*callback)(const struct dmi_system_id *); - const char *ident; - struct dmi_strmatch matches[4]; - void *driver_data; -}; - -struct bus_attribute { - struct attribute attr; - ssize_t (*show)(struct bus_type *, char *); - ssize_t (*store)(struct bus_type *, const char *, size_t); -}; - -enum pcie_reset_state { - pcie_deassert_reset = 1, - pcie_warm_reset = 2, - pcie_hot_reset = 3, -}; - -enum pcie_link_width { - PCIE_LNK_WIDTH_RESRV = 0, - PCIE_LNK_X1 = 1, - PCIE_LNK_X2 = 2, - PCIE_LNK_X4 = 4, - PCIE_LNK_X8 = 8, - PCIE_LNK_X12 = 12, - PCIE_LNK_X16 = 16, - PCIE_LNK_X32 = 32, - PCIE_LNK_WIDTH_UNKNOWN = 255, -}; - -struct pci_cap_saved_data { - u16 cap_nr; - bool cap_extended; - unsigned int size; - u32 data[0]; -}; - -struct pci_cap_saved_state { - struct hlist_node next; - struct pci_cap_saved_data cap; -}; - -typedef int (*arch_set_vga_state_t)(struct pci_dev *, bool, unsigned int, u32); - -struct pci_platform_pm_ops { - bool (*bridge_d3)(struct pci_dev *); - bool (*is_manageable)(struct pci_dev *); - int (*set_state)(struct pci_dev *, pci_power_t); - pci_power_t (*get_state)(struct pci_dev *); - void (*refresh_state)(struct pci_dev *); - pci_power_t (*choose_state)(struct pci_dev *); - int (*set_wakeup)(struct pci_dev *, bool); - bool (*need_resume)(struct pci_dev *); -}; - -struct pci_pme_device { - struct list_head list; - struct pci_dev *dev; -}; - -struct pci_saved_state { - u32 config_space[16]; - struct pci_cap_saved_data cap[0]; -}; - -struct pci_devres { - unsigned int enabled: 1; - unsigned int pinned: 1; - unsigned int orig_intx: 1; - unsigned int restore_intx: 1; - unsigned int mwi: 1; - u32 region_mask; -}; - -struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *, char *); - ssize_t (*store)(struct device_driver *, const char *, size_t); -}; - -enum dev_dma_attr { - DEV_DMA_NOT_SUPPORTED = 0, - DEV_DMA_NON_COHERENT = 1, - DEV_DMA_COHERENT = 2, -}; - -struct pci_dynid { - struct list_head node; - struct pci_device_id id; -}; - -struct drv_dev_and_id { - struct pci_driver *drv; - struct pci_dev *dev; - const struct pci_device_id *id; -}; - -enum pci_mmap_state { - pci_mmap_io = 0, - pci_mmap_mem = 1, -}; - -enum pci_mmap_api { - PCI_MMAP_SYSFS = 0, - PCI_MMAP_PROCFS = 1, -}; - -struct pci_vpd_ops; - -struct pci_vpd { - const struct pci_vpd_ops *ops; - struct bin_attribute *attr; - struct mutex lock; - unsigned int len; - u16 flag; - u8 cap; - unsigned int busy: 1; - unsigned int valid: 1; -}; - -struct pci_vpd_ops { - ssize_t (*read)(struct pci_dev *, loff_t, size_t, void *); - ssize_t (*write)(struct pci_dev *, loff_t, size_t, const void *); - int (*set_size)(struct pci_dev *, size_t); -}; - -struct pci_dev_resource { - struct list_head list; - struct resource *res; - struct pci_dev *dev; - resource_size_t start; - resource_size_t end; - resource_size_t add_size; - resource_size_t min_align; - long unsigned int flags; -}; - -enum release_type { - leaf_only = 0, - whole_subtree = 1, -}; - -enum enable_type { - undefined = 4294967295, - user_disabled = 0, - auto_disabled = 1, - user_enabled = 2, - auto_enabled = 3, -}; - -struct aspm_latency { - u32 l0s; - u32 l1; -}; - -struct pcie_link_state { - struct pci_dev *pdev; - struct pci_dev *downstream; - struct pcie_link_state *root; - struct pcie_link_state *parent; - struct list_head sibling; - u32 aspm_support: 7; - u32 aspm_enabled: 7; - u32 aspm_capable: 7; - u32 aspm_default: 7; - char: 4; - u32 aspm_disable: 7; - u32 clkpm_capable: 1; - u32 clkpm_enabled: 1; - u32 clkpm_default: 1; - u32 clkpm_disable: 1; - struct aspm_latency latency_up; - struct aspm_latency latency_dw; - struct aspm_latency acceptable[8]; -}; - -struct pci_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct pci_slot *, char *); - ssize_t (*store)(struct pci_slot *, const char *, size_t); -}; - -struct of_bus; - -struct of_pci_range_parser { - struct device_node *node; - struct of_bus *bus; - const __be32 *range; - const __be32 *end; - int na; - int ns; - int pna; - bool dma; -}; - -struct of_pci_range { - union { - u64 pci_addr; - u64 bus_addr; - }; - u64 cpu_addr; - u64 size; - u32 flags; -}; - -enum dmi_field { - DMI_NONE = 0, - DMI_BIOS_VENDOR = 1, - DMI_BIOS_VERSION = 2, - DMI_BIOS_DATE = 3, - DMI_BIOS_RELEASE = 4, - DMI_EC_FIRMWARE_RELEASE = 5, - DMI_SYS_VENDOR = 6, - DMI_PRODUCT_NAME = 7, - DMI_PRODUCT_VERSION = 8, - DMI_PRODUCT_SERIAL = 9, - DMI_PRODUCT_UUID = 10, - DMI_PRODUCT_SKU = 11, - DMI_PRODUCT_FAMILY = 12, - DMI_BOARD_VENDOR = 13, - DMI_BOARD_NAME = 14, - DMI_BOARD_VERSION = 15, - DMI_BOARD_SERIAL = 16, - DMI_BOARD_ASSET_TAG = 17, - DMI_CHASSIS_VENDOR = 18, - DMI_CHASSIS_TYPE = 19, - DMI_CHASSIS_VERSION = 20, - DMI_CHASSIS_SERIAL = 21, - DMI_CHASSIS_ASSET_TAG = 22, - DMI_STRING_MAX = 23, - DMI_OEM_STRING = 24, -}; - -struct pci_fixup { - u16 vendor; - u16 device; - u32 class; - unsigned int class_shift; - int hook_offset; -}; - -enum { - NVME_REG_CAP = 0, - NVME_REG_VS = 8, - NVME_REG_INTMS = 12, - NVME_REG_INTMC = 16, - NVME_REG_CC = 20, - NVME_REG_CSTS = 28, - NVME_REG_NSSR = 32, - NVME_REG_AQA = 36, - NVME_REG_ASQ = 40, - NVME_REG_ACQ = 48, - NVME_REG_CMBLOC = 56, - NVME_REG_CMBSZ = 60, - NVME_REG_BPINFO = 64, - NVME_REG_BPRSEL = 68, - NVME_REG_BPMBL = 72, - NVME_REG_CMBMSC = 80, - NVME_REG_PMRCAP = 3584, - NVME_REG_PMRCTL = 3588, - NVME_REG_PMRSTS = 3592, - NVME_REG_PMREBS = 3596, - NVME_REG_PMRSWTP = 3600, - NVME_REG_DBS = 4096, -}; - -enum { - NVME_CC_ENABLE = 1, - NVME_CC_EN_SHIFT = 0, - NVME_CC_CSS_SHIFT = 4, - NVME_CC_MPS_SHIFT = 7, - NVME_CC_AMS_SHIFT = 11, - NVME_CC_SHN_SHIFT = 14, - NVME_CC_IOSQES_SHIFT = 16, - NVME_CC_IOCQES_SHIFT = 20, - NVME_CC_CSS_NVM = 0, - NVME_CC_CSS_CSI = 96, - NVME_CC_CSS_MASK = 112, - NVME_CC_AMS_RR = 0, - NVME_CC_AMS_WRRU = 2048, - NVME_CC_AMS_VS = 14336, - NVME_CC_SHN_NONE = 0, - NVME_CC_SHN_NORMAL = 16384, - NVME_CC_SHN_ABRUPT = 32768, - NVME_CC_SHN_MASK = 49152, - NVME_CC_IOSQES = 393216, - NVME_CC_IOCQES = 4194304, - NVME_CAP_CSS_NVM = 1, - NVME_CAP_CSS_CSI = 64, - NVME_CSTS_RDY = 1, - NVME_CSTS_CFS = 2, - NVME_CSTS_NSSRO = 16, - NVME_CSTS_PP = 32, - NVME_CSTS_SHST_NORMAL = 0, - NVME_CSTS_SHST_OCCUR = 4, - NVME_CSTS_SHST_CMPLT = 8, - NVME_CSTS_SHST_MASK = 12, - NVME_CMBMSC_CRE = 1, - NVME_CMBMSC_CMSE = 2, -}; - -enum { - NVME_AEN_BIT_NS_ATTR = 8, - NVME_AEN_BIT_FW_ACT = 9, - NVME_AEN_BIT_ANA_CHANGE = 11, - NVME_AEN_BIT_DISC_CHANGE = 31, -}; - -enum { - SWITCHTEC_GAS_MRPC_OFFSET = 0, - SWITCHTEC_GAS_TOP_CFG_OFFSET = 4096, - SWITCHTEC_GAS_SW_EVENT_OFFSET = 6144, - SWITCHTEC_GAS_SYS_INFO_OFFSET = 8192, - SWITCHTEC_GAS_FLASH_INFO_OFFSET = 8704, - SWITCHTEC_GAS_PART_CFG_OFFSET = 16384, - SWITCHTEC_GAS_NTB_OFFSET = 65536, - SWITCHTEC_GAS_PFF_CSR_OFFSET = 1261568, -}; - -enum { - SWITCHTEC_NTB_REG_INFO_OFFSET = 0, - SWITCHTEC_NTB_REG_CTRL_OFFSET = 16384, - SWITCHTEC_NTB_REG_DBMSG_OFFSET = 409600, -}; - -struct nt_partition_info { - u32 xlink_enabled; - u32 target_part_low; - u32 target_part_high; - u32 reserved; -}; - -struct ntb_info_regs { - u8 partition_count; - u8 partition_id; - u16 reserved1; - u64 ep_map; - u16 requester_id; - u16 reserved2; - u32 reserved3[4]; - struct nt_partition_info ntp_info[48]; -} __attribute__((packed)); - -struct ntb_ctrl_regs { - u32 partition_status; - u32 partition_op; - u32 partition_ctrl; - u32 bar_setup; - u32 bar_error; - u16 lut_table_entries; - u16 lut_table_offset; - u32 lut_error; - u16 req_id_table_size; - u16 req_id_table_offset; - u32 req_id_error; - u32 reserved1[7]; - struct { - u32 ctl; - u32 win_size; - u64 xlate_addr; - } bar_entry[6]; - struct { - u32 win_size; - u32 reserved[3]; - } bar_ext_entry[6]; - u32 reserved2[192]; - u32 req_id_table[512]; - u32 reserved3[256]; - u64 lut_entry[512]; -}; - -struct pci_dev_reset_methods { - u16 vendor; - u16 device; - int (*reset)(struct pci_dev *, int); -}; - -struct pci_dev_acs_enabled { - u16 vendor; - u16 device; - int (*acs_enabled)(struct pci_dev *, u16); -}; - -struct pci_dev_acs_ops { - u16 vendor; - u16 device; - int (*enable_acs)(struct pci_dev *); - int (*disable_acs_redir)(struct pci_dev *); -}; - -struct msix_entry { - u32 vector; - u16 entry; -}; - -enum dmi_device_type { - DMI_DEV_TYPE_ANY = 0, - DMI_DEV_TYPE_OTHER = 1, - DMI_DEV_TYPE_UNKNOWN = 2, - DMI_DEV_TYPE_VIDEO = 3, - DMI_DEV_TYPE_SCSI = 4, - DMI_DEV_TYPE_ETHERNET = 5, - DMI_DEV_TYPE_TOKENRING = 6, - DMI_DEV_TYPE_SOUND = 7, - DMI_DEV_TYPE_PATA = 8, - DMI_DEV_TYPE_SATA = 9, - DMI_DEV_TYPE_SAS = 10, - DMI_DEV_TYPE_IPMI = 4294967295, - DMI_DEV_TYPE_OEM_STRING = 4294967294, - DMI_DEV_TYPE_DEV_ONBOARD = 4294967293, - DMI_DEV_TYPE_DEV_SLOT = 4294967292, -}; - -struct dmi_device { - struct list_head list; - int type; - const char *name; - void *device_data; -}; - -struct dmi_dev_onboard { - struct dmi_device dev; - int instance; - int segment; - int bus; - int devfn; -}; - -enum smbios_attr_enum { - SMBIOS_ATTR_NONE = 0, - SMBIOS_ATTR_LABEL_SHOW = 1, - SMBIOS_ATTR_INSTANCE_SHOW = 2, -}; - -enum { - RGR1_SW_INIT_1 = 0, - EXT_CFG_INDEX = 1, - EXT_CFG_DATA = 2, -}; - -enum pcie_type { - GENERIC = 0, - BCM7278 = 1, - BCM2711 = 2, -}; - -struct brcm_pcie; - -struct pcie_cfg_data { - const int *offsets; - const enum pcie_type type; - void (*perst_set)(struct brcm_pcie *, u32); - void (*bridge_sw_init_set)(struct brcm_pcie *, u32); -}; - -struct reset_control; - -struct brcm_msi; - -struct brcm_pcie { - struct device *dev; - void *base; - struct clk *clk; - struct device_node *np; - bool ssc; - bool l1ss; - int gen; - u64 msi_target_addr; - struct brcm_msi *msi; - const int *reg_offsets; - enum pcie_type type; - struct reset_control *rescal; - int num_memc; - u64 memc_size[3]; - u32 hw_rev; - void (*perst_set)(struct brcm_pcie *, u32); - void (*bridge_sw_init_set)(struct brcm_pcie *, u32); -}; - -struct brcm_msi { - struct device *dev; - void *base; - struct device_node *np; - struct irq_domain *msi_domain; - struct irq_domain *inner_domain; - struct mutex lock; - u64 target_addr; - int irq; - long unsigned int used; - bool legacy; - int legacy_shift; - int nr; - void *intr_base; -}; - -enum hdmi_infoframe_type { - HDMI_INFOFRAME_TYPE_VENDOR = 129, - HDMI_INFOFRAME_TYPE_AVI = 130, - HDMI_INFOFRAME_TYPE_SPD = 131, - HDMI_INFOFRAME_TYPE_AUDIO = 132, - HDMI_INFOFRAME_TYPE_DRM = 135, -}; - -struct hdmi_any_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; -}; - -enum hdmi_colorspace { - HDMI_COLORSPACE_RGB = 0, - HDMI_COLORSPACE_YUV422 = 1, - HDMI_COLORSPACE_YUV444 = 2, - HDMI_COLORSPACE_YUV420 = 3, - HDMI_COLORSPACE_RESERVED4 = 4, - HDMI_COLORSPACE_RESERVED5 = 5, - HDMI_COLORSPACE_RESERVED6 = 6, - HDMI_COLORSPACE_IDO_DEFINED = 7, -}; - -enum hdmi_scan_mode { - HDMI_SCAN_MODE_NONE = 0, - HDMI_SCAN_MODE_OVERSCAN = 1, - HDMI_SCAN_MODE_UNDERSCAN = 2, - HDMI_SCAN_MODE_RESERVED = 3, -}; - -enum hdmi_colorimetry { - HDMI_COLORIMETRY_NONE = 0, - HDMI_COLORIMETRY_ITU_601 = 1, - HDMI_COLORIMETRY_ITU_709 = 2, - HDMI_COLORIMETRY_EXTENDED = 3, -}; - -enum hdmi_picture_aspect { - HDMI_PICTURE_ASPECT_NONE = 0, - HDMI_PICTURE_ASPECT_4_3 = 1, - HDMI_PICTURE_ASPECT_16_9 = 2, - HDMI_PICTURE_ASPECT_64_27 = 3, - HDMI_PICTURE_ASPECT_256_135 = 4, - HDMI_PICTURE_ASPECT_RESERVED = 5, -}; - -enum hdmi_active_aspect { - HDMI_ACTIVE_ASPECT_16_9_TOP = 2, - HDMI_ACTIVE_ASPECT_14_9_TOP = 3, - HDMI_ACTIVE_ASPECT_16_9_CENTER = 4, - HDMI_ACTIVE_ASPECT_PICTURE = 8, - HDMI_ACTIVE_ASPECT_4_3 = 9, - HDMI_ACTIVE_ASPECT_16_9 = 10, - HDMI_ACTIVE_ASPECT_14_9 = 11, - HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13, - HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14, - HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15, -}; - -enum hdmi_extended_colorimetry { - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 = 0, - HDMI_EXTENDED_COLORIMETRY_XV_YCC_709 = 1, - HDMI_EXTENDED_COLORIMETRY_S_YCC_601 = 2, - HDMI_EXTENDED_COLORIMETRY_OPYCC_601 = 3, - HDMI_EXTENDED_COLORIMETRY_OPRGB = 4, - HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM = 5, - HDMI_EXTENDED_COLORIMETRY_BT2020 = 6, - HDMI_EXTENDED_COLORIMETRY_RESERVED = 7, -}; - -enum hdmi_quantization_range { - HDMI_QUANTIZATION_RANGE_DEFAULT = 0, - HDMI_QUANTIZATION_RANGE_LIMITED = 1, - HDMI_QUANTIZATION_RANGE_FULL = 2, - HDMI_QUANTIZATION_RANGE_RESERVED = 3, -}; - -enum hdmi_nups { - HDMI_NUPS_UNKNOWN = 0, - HDMI_NUPS_HORIZONTAL = 1, - HDMI_NUPS_VERTICAL = 2, - HDMI_NUPS_BOTH = 3, -}; - -enum hdmi_ycc_quantization_range { - HDMI_YCC_QUANTIZATION_RANGE_LIMITED = 0, - HDMI_YCC_QUANTIZATION_RANGE_FULL = 1, -}; - -enum hdmi_content_type { - HDMI_CONTENT_TYPE_GRAPHICS = 0, - HDMI_CONTENT_TYPE_PHOTO = 1, - HDMI_CONTENT_TYPE_CINEMA = 2, - HDMI_CONTENT_TYPE_GAME = 3, -}; - -enum hdmi_metadata_type { - HDMI_STATIC_METADATA_TYPE1 = 0, -}; - -enum hdmi_eotf { - HDMI_EOTF_TRADITIONAL_GAMMA_SDR = 0, - HDMI_EOTF_TRADITIONAL_GAMMA_HDR = 1, - HDMI_EOTF_SMPTE_ST2084 = 2, - HDMI_EOTF_BT_2100_HLG = 3, -}; - -struct hdmi_avi_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - enum hdmi_colorspace colorspace; - enum hdmi_scan_mode scan_mode; - enum hdmi_colorimetry colorimetry; - enum hdmi_picture_aspect picture_aspect; - enum hdmi_active_aspect active_aspect; - bool itc; - enum hdmi_extended_colorimetry extended_colorimetry; - enum hdmi_quantization_range quantization_range; - enum hdmi_nups nups; - unsigned char video_code; - enum hdmi_ycc_quantization_range ycc_quantization_range; - enum hdmi_content_type content_type; - unsigned char pixel_repeat; - short unsigned int top_bar; - short unsigned int bottom_bar; - short unsigned int left_bar; - short unsigned int right_bar; -}; - -struct hdmi_drm_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - enum hdmi_eotf eotf; - enum hdmi_metadata_type metadata_type; - struct { - u16 x; - u16 y; - } display_primaries[3]; - struct { - u16 x; - u16 y; - } white_point; - u16 max_display_mastering_luminance; - u16 min_display_mastering_luminance; - u16 max_cll; - u16 max_fall; -}; - -enum hdmi_spd_sdi { - HDMI_SPD_SDI_UNKNOWN = 0, - HDMI_SPD_SDI_DSTB = 1, - HDMI_SPD_SDI_DVDP = 2, - HDMI_SPD_SDI_DVHS = 3, - HDMI_SPD_SDI_HDDVR = 4, - HDMI_SPD_SDI_DVC = 5, - HDMI_SPD_SDI_DSC = 6, - HDMI_SPD_SDI_VCD = 7, - HDMI_SPD_SDI_GAME = 8, - HDMI_SPD_SDI_PC = 9, - HDMI_SPD_SDI_BD = 10, - HDMI_SPD_SDI_SACD = 11, - HDMI_SPD_SDI_HDDVD = 12, - HDMI_SPD_SDI_PMP = 13, -}; - -struct hdmi_spd_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - char vendor[8]; - char product[16]; - enum hdmi_spd_sdi sdi; -}; - -enum hdmi_audio_coding_type { - HDMI_AUDIO_CODING_TYPE_STREAM = 0, - HDMI_AUDIO_CODING_TYPE_PCM = 1, - HDMI_AUDIO_CODING_TYPE_AC3 = 2, - HDMI_AUDIO_CODING_TYPE_MPEG1 = 3, - HDMI_AUDIO_CODING_TYPE_MP3 = 4, - HDMI_AUDIO_CODING_TYPE_MPEG2 = 5, - HDMI_AUDIO_CODING_TYPE_AAC_LC = 6, - HDMI_AUDIO_CODING_TYPE_DTS = 7, - HDMI_AUDIO_CODING_TYPE_ATRAC = 8, - HDMI_AUDIO_CODING_TYPE_DSD = 9, - HDMI_AUDIO_CODING_TYPE_EAC3 = 10, - HDMI_AUDIO_CODING_TYPE_DTS_HD = 11, - HDMI_AUDIO_CODING_TYPE_MLP = 12, - HDMI_AUDIO_CODING_TYPE_DST = 13, - HDMI_AUDIO_CODING_TYPE_WMA_PRO = 14, - HDMI_AUDIO_CODING_TYPE_CXT = 15, -}; - -enum hdmi_audio_sample_size { - HDMI_AUDIO_SAMPLE_SIZE_STREAM = 0, - HDMI_AUDIO_SAMPLE_SIZE_16 = 1, - HDMI_AUDIO_SAMPLE_SIZE_20 = 2, - HDMI_AUDIO_SAMPLE_SIZE_24 = 3, -}; - -enum hdmi_audio_sample_frequency { - HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM = 0, - HDMI_AUDIO_SAMPLE_FREQUENCY_32000 = 1, - HDMI_AUDIO_SAMPLE_FREQUENCY_44100 = 2, - HDMI_AUDIO_SAMPLE_FREQUENCY_48000 = 3, - HDMI_AUDIO_SAMPLE_FREQUENCY_88200 = 4, - HDMI_AUDIO_SAMPLE_FREQUENCY_96000 = 5, - HDMI_AUDIO_SAMPLE_FREQUENCY_176400 = 6, - HDMI_AUDIO_SAMPLE_FREQUENCY_192000 = 7, -}; - -enum hdmi_audio_coding_type_ext { - HDMI_AUDIO_CODING_TYPE_EXT_CT = 0, - HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC = 1, - HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2 = 2, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND = 3, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC = 4, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2 = 5, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC = 6, - HDMI_AUDIO_CODING_TYPE_EXT_DRA = 7, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND = 8, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND = 10, -}; - -struct hdmi_audio_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - unsigned char channels; - enum hdmi_audio_coding_type coding_type; - enum hdmi_audio_sample_size sample_size; - enum hdmi_audio_sample_frequency sample_frequency; - enum hdmi_audio_coding_type_ext coding_type_ext; - unsigned char channel_allocation; - unsigned char level_shift_value; - bool downmix_inhibit; -}; - -enum hdmi_3d_structure { - HDMI_3D_STRUCTURE_INVALID = 4294967295, - HDMI_3D_STRUCTURE_FRAME_PACKING = 0, - HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE = 1, - HDMI_3D_STRUCTURE_LINE_ALTERNATIVE = 2, - HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL = 3, - HDMI_3D_STRUCTURE_L_DEPTH = 4, - HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH = 5, - HDMI_3D_STRUCTURE_TOP_AND_BOTTOM = 6, - HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8, -}; - -struct hdmi_vendor_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - unsigned int oui; - u8 vic; - enum hdmi_3d_structure s3d_struct; - unsigned int s3d_ext_data; -}; - -union hdmi_vendor_any_infoframe { - struct { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - unsigned int oui; - } any; - struct hdmi_vendor_infoframe hdmi; -}; - -union hdmi_infoframe { - struct hdmi_any_infoframe any; - struct hdmi_avi_infoframe avi; - struct hdmi_spd_infoframe spd; - union hdmi_vendor_any_infoframe vendor; - struct hdmi_audio_infoframe audio; - struct hdmi_drm_infoframe drm; -}; - -enum con_scroll { - SM_UP = 0, - SM_DOWN = 1, -}; - -enum vc_intensity { - VCI_HALF_BRIGHT = 0, - VCI_NORMAL = 1, - VCI_BOLD = 2, - VCI_MASK = 3, -}; - -struct vc_data; - -struct console_font; - -struct consw { - struct module *owner; - const char * (*con_startup)(); - void (*con_init)(struct vc_data *, int); - void (*con_deinit)(struct vc_data *); - void (*con_clear)(struct vc_data *, int, int, int, int); - void (*con_putc)(struct vc_data *, int, int, int); - void (*con_putcs)(struct vc_data *, const short unsigned int *, int, int, int); - void (*con_cursor)(struct vc_data *, int); - bool (*con_scroll)(struct vc_data *, unsigned int, unsigned int, enum con_scroll, unsigned int); - int (*con_switch)(struct vc_data *); - int (*con_blank)(struct vc_data *, int, int); - int (*con_font_set)(struct vc_data *, struct console_font *, unsigned int); - int (*con_font_get)(struct vc_data *, struct console_font *); - int (*con_font_default)(struct vc_data *, struct console_font *, char *); - int (*con_font_copy)(struct vc_data *, int); - int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); - void (*con_set_palette)(struct vc_data *, const unsigned char *); - void (*con_scrolldelta)(struct vc_data *, int); - int (*con_set_origin)(struct vc_data *); - void (*con_save_screen)(struct vc_data *); - u8 (*con_build_attr)(struct vc_data *, u8, enum vc_intensity, bool, bool, bool, bool); - void (*con_invert_region)(struct vc_data *, u16 *, int); - u16 * (*con_screen_pos)(const struct vc_data *, int); - long unsigned int (*con_getxy)(struct vc_data *, long unsigned int, int *, int *); - void (*con_flush_scrollback)(struct vc_data *); - int (*con_debug_enter)(struct vc_data *); - int (*con_debug_leave)(struct vc_data *); -}; - -struct vc_state { - unsigned int x; - unsigned int y; - unsigned char color; - unsigned char Gx_charset[2]; - unsigned int charset: 1; - enum vc_intensity intensity; - bool italic; - bool underline; - bool blink; - bool reverse; -}; - -struct console_font { - unsigned int width; - unsigned int height; - unsigned int charcount; - unsigned char *data; -}; - -struct vt_mode { - char mode; - char waitv; - short int relsig; - short int acqsig; - short int frsig; -}; - -struct uni_pagedir; - -struct uni_screen; - -struct vc_data { - struct tty_port port; - struct vc_state state; - struct vc_state saved_state; - short unsigned int vc_num; - unsigned int vc_cols; - unsigned int vc_rows; - unsigned int vc_size_row; - unsigned int vc_scan_lines; - unsigned int vc_cell_height; - long unsigned int vc_origin; - long unsigned int vc_scr_end; - long unsigned int vc_visible_origin; - unsigned int vc_top; - unsigned int vc_bottom; - const struct consw *vc_sw; - short unsigned int *vc_screenbuf; - unsigned int vc_screenbuf_size; - unsigned char vc_mode; - unsigned char vc_attr; - unsigned char vc_def_color; - unsigned char vc_ulcolor; - unsigned char vc_itcolor; - unsigned char vc_halfcolor; - unsigned int vc_cursor_type; - short unsigned int vc_complement_mask; - short unsigned int vc_s_complement_mask; - long unsigned int vc_pos; - short unsigned int vc_hi_font_mask; - struct console_font vc_font; - short unsigned int vc_video_erase_char; - unsigned int vc_state; - unsigned int vc_npar; - unsigned int vc_par[16]; - struct vt_mode vt_mode; - struct pid *vt_pid; - int vt_newvt; - wait_queue_head_t paste_wait; - unsigned int vc_disp_ctrl: 1; - unsigned int vc_toggle_meta: 1; - unsigned int vc_decscnm: 1; - unsigned int vc_decom: 1; - unsigned int vc_decawm: 1; - unsigned int vc_deccm: 1; - unsigned int vc_decim: 1; - unsigned int vc_priv: 3; - unsigned int vc_need_wrap: 1; - unsigned int vc_can_do_color: 1; - unsigned int vc_report_mouse: 2; - unsigned char vc_utf: 1; - unsigned char vc_utf_count; - int vc_utf_char; - long unsigned int vc_tab_stop[4]; - unsigned char vc_palette[48]; - short unsigned int *vc_translate; - unsigned int vc_resize_user; - unsigned int vc_bell_pitch; - unsigned int vc_bell_duration; - short unsigned int vc_cur_blink_ms; - struct vc_data **vc_display_fg; - struct uni_pagedir *vc_uni_pagedir; - struct uni_pagedir **vc_uni_pagedir_loc; - struct uni_screen *vc_uni_screen; -}; - -struct linux_logo { - int type; - unsigned int width; - unsigned int height; - unsigned int clutsize; - const unsigned char *clut; - const unsigned char *data; -}; - -struct fb_fix_screeninfo { - char id[16]; - long unsigned int smem_start; - __u32 smem_len; - __u32 type; - __u32 type_aux; - __u32 visual; - __u16 xpanstep; - __u16 ypanstep; - __u16 ywrapstep; - __u32 line_length; - long unsigned int mmio_start; - __u32 mmio_len; - __u32 accel; - __u16 capabilities; - __u16 reserved[2]; -}; - -struct fb_bitfield { - __u32 offset; - __u32 length; - __u32 msb_right; -}; - -struct fb_var_screeninfo { - __u32 xres; - __u32 yres; - __u32 xres_virtual; - __u32 yres_virtual; - __u32 xoffset; - __u32 yoffset; - __u32 bits_per_pixel; - __u32 grayscale; - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - __u32 nonstd; - __u32 activate; - __u32 height; - __u32 width; - __u32 accel_flags; - __u32 pixclock; - __u32 left_margin; - __u32 right_margin; - __u32 upper_margin; - __u32 lower_margin; - __u32 hsync_len; - __u32 vsync_len; - __u32 sync; - __u32 vmode; - __u32 rotate; - __u32 colorspace; - __u32 reserved[4]; -}; - -struct fb_cmap { - __u32 start; - __u32 len; - __u16 *red; - __u16 *green; - __u16 *blue; - __u16 *transp; -}; - -enum { - FB_BLANK_UNBLANK = 0, - FB_BLANK_NORMAL = 1, - FB_BLANK_VSYNC_SUSPEND = 2, - FB_BLANK_HSYNC_SUSPEND = 3, - FB_BLANK_POWERDOWN = 4, -}; - -struct fb_copyarea { - __u32 dx; - __u32 dy; - __u32 width; - __u32 height; - __u32 sx; - __u32 sy; -}; - -struct fb_fillrect { - __u32 dx; - __u32 dy; - __u32 width; - __u32 height; - __u32 color; - __u32 rop; -}; - -struct fb_image { - __u32 dx; - __u32 dy; - __u32 width; - __u32 height; - __u32 fg_color; - __u32 bg_color; - __u8 depth; - const char *data; - struct fb_cmap cmap; -}; - -struct fbcurpos { - __u16 x; - __u16 y; -}; - -struct fb_cursor { - __u16 set; - __u16 enable; - __u16 rop; - const char *mask; - struct fbcurpos hot; - struct fb_image image; -}; - -enum backlight_type { - BACKLIGHT_RAW = 1, - BACKLIGHT_PLATFORM = 2, - BACKLIGHT_FIRMWARE = 3, - BACKLIGHT_TYPE_MAX = 4, -}; - -enum backlight_scale { - BACKLIGHT_SCALE_UNKNOWN = 0, - BACKLIGHT_SCALE_LINEAR = 1, - BACKLIGHT_SCALE_NON_LINEAR = 2, -}; - -struct backlight_device; - -struct fb_info; - -struct backlight_ops { - unsigned int options; - int (*update_status)(struct backlight_device *); - int (*get_brightness)(struct backlight_device *); - int (*check_fb)(struct backlight_device *, struct fb_info *); -}; - -struct backlight_properties { - int brightness; - int max_brightness; - int power; - int fb_blank; - enum backlight_type type; - unsigned int state; - enum backlight_scale scale; -}; - -struct backlight_device { - struct backlight_properties props; - struct mutex update_lock; - struct mutex ops_lock; - const struct backlight_ops *ops; - struct notifier_block fb_notif; - struct list_head entry; - struct device dev; - bool fb_bl_on[32]; - int use_count; -}; - -struct fb_chroma { - __u32 redx; - __u32 greenx; - __u32 bluex; - __u32 whitex; - __u32 redy; - __u32 greeny; - __u32 bluey; - __u32 whitey; -}; - -struct fb_videomode; - -struct fb_monspecs { - struct fb_chroma chroma; - struct fb_videomode *modedb; - __u8 manufacturer[4]; - __u8 monitor[14]; - __u8 serial_no[14]; - __u8 ascii[14]; - __u32 modedb_len; - __u32 model; - __u32 serial; - __u32 year; - __u32 week; - __u32 hfmin; - __u32 hfmax; - __u32 dclkmin; - __u32 dclkmax; - __u16 input; - __u16 dpms; - __u16 signal; - __u16 vfmin; - __u16 vfmax; - __u16 gamma; - __u16 gtf: 1; - __u16 misc; - __u8 version; - __u8 revision; - __u8 max_x; - __u8 max_y; -}; - -struct fb_pixmap { - u8 *addr; - u32 size; - u32 offset; - u32 buf_align; - u32 scan_align; - u32 access_align; - u32 flags; - u32 blit_x; - u32 blit_y; - void (*writeio)(struct fb_info *, void *, void *, unsigned int); - void (*readio)(struct fb_info *, void *, void *, unsigned int); -}; - -struct fb_deferred_io; - -struct fb_ops; - -struct apertures_struct; - -struct fb_info { - atomic_t count; - int node; - int flags; - int fbcon_rotate_hint; - struct mutex lock; - struct mutex mm_lock; - struct fb_var_screeninfo var; - struct fb_fix_screeninfo fix; - struct fb_monspecs monspecs; - struct work_struct queue; - struct fb_pixmap pixmap; - struct fb_pixmap sprite; - struct fb_cmap cmap; - struct list_head modelist; - struct fb_videomode *mode; - struct backlight_device *bl_dev; - struct mutex bl_curve_mutex; - u8 bl_curve[128]; - struct delayed_work deferred_work; - struct fb_deferred_io *fbdefio; - const struct fb_ops *fbops; - struct device *device; - struct device *dev; - int class_flag; - union { - char *screen_base; - char *screen_buffer; - }; - long unsigned int screen_size; - void *pseudo_palette; - u32 state; - void *fbcon_par; - void *par; - struct apertures_struct *apertures; - bool skip_vt_switch; -}; - -struct fb_videomode { - const char *name; - u32 refresh; - u32 xres; - u32 yres; - u32 pixclock; - u32 left_margin; - u32 right_margin; - u32 upper_margin; - u32 lower_margin; - u32 hsync_len; - u32 vsync_len; - u32 sync; - u32 vmode; - u32 flag; -}; - -struct fb_cmap_user { - __u32 start; - __u32 len; - __u16 *red; - __u16 *green; - __u16 *blue; - __u16 *transp; -}; - -struct fb_event { - struct fb_info *info; - void *data; -}; - -struct fb_blit_caps { - u32 x; - u32 y; - u32 len; - u32 flags; -}; - -struct fb_deferred_io { - long unsigned int delay; - struct mutex lock; - struct list_head pagelist; - void (*first_io)(struct fb_info *); - void (*deferred_io)(struct fb_info *, struct list_head *); -}; - -struct fb_ops { - struct module *owner; - int (*fb_open)(struct fb_info *, int); - int (*fb_release)(struct fb_info *, int); - ssize_t (*fb_read)(struct fb_info *, char *, size_t, loff_t *); - ssize_t (*fb_write)(struct fb_info *, const char *, size_t, loff_t *); - int (*fb_check_var)(struct fb_var_screeninfo *, struct fb_info *); - int (*fb_set_par)(struct fb_info *); - int (*fb_setcolreg)(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, struct fb_info *); - int (*fb_setcmap)(struct fb_cmap *, struct fb_info *); - int (*fb_blank)(int, struct fb_info *); - int (*fb_pan_display)(struct fb_var_screeninfo *, struct fb_info *); - void (*fb_fillrect)(struct fb_info *, const struct fb_fillrect *); - void (*fb_copyarea)(struct fb_info *, const struct fb_copyarea *); - void (*fb_imageblit)(struct fb_info *, const struct fb_image *); - int (*fb_cursor)(struct fb_info *, struct fb_cursor *); - int (*fb_sync)(struct fb_info *); - int (*fb_ioctl)(struct fb_info *, unsigned int, long unsigned int); - int (*fb_compat_ioctl)(struct fb_info *, unsigned int, long unsigned int); - int (*fb_mmap)(struct fb_info *, struct vm_area_struct *); - void (*fb_get_caps)(struct fb_info *, struct fb_blit_caps *, struct fb_var_screeninfo *); - void (*fb_destroy)(struct fb_info *); - int (*fb_debug_enter)(struct fb_info *); - int (*fb_debug_leave)(struct fb_info *); -}; - -struct aperture { - resource_size_t base; - resource_size_t size; -}; - -struct apertures_struct { - unsigned int count; - struct aperture ranges[0]; -}; - -struct fb_modelist { - struct list_head list; - struct fb_videomode mode; -}; - -struct logo_data { - int depth; - int needs_directpalette; - int needs_truepalette; - int needs_cmapreset; - const struct linux_logo *logo; -}; - -struct fb_fix_screeninfo32 { - char id[16]; - compat_caddr_t smem_start; - u32 smem_len; - u32 type; - u32 type_aux; - u32 visual; - u16 xpanstep; - u16 ypanstep; - u16 ywrapstep; - u32 line_length; - compat_caddr_t mmio_start; - u32 mmio_len; - u32 accel; - u16 reserved[3]; -}; - -struct fb_cmap32 { - u32 start; - u32 len; - compat_caddr_t red; - compat_caddr_t green; - compat_caddr_t blue; - compat_caddr_t transp; -}; - -struct dmt_videomode { - u32 dmt_id; - u32 std_2byte_code; - u32 cvt_3byte_code; - const struct fb_videomode *mode; -}; - -enum display_flags { - DISPLAY_FLAGS_HSYNC_LOW = 1, - DISPLAY_FLAGS_HSYNC_HIGH = 2, - DISPLAY_FLAGS_VSYNC_LOW = 4, - DISPLAY_FLAGS_VSYNC_HIGH = 8, - DISPLAY_FLAGS_DE_LOW = 16, - DISPLAY_FLAGS_DE_HIGH = 32, - DISPLAY_FLAGS_PIXDATA_POSEDGE = 64, - DISPLAY_FLAGS_PIXDATA_NEGEDGE = 128, - DISPLAY_FLAGS_INTERLACED = 256, - DISPLAY_FLAGS_DOUBLESCAN = 512, - DISPLAY_FLAGS_DOUBLECLK = 1024, - DISPLAY_FLAGS_SYNC_POSEDGE = 2048, - DISPLAY_FLAGS_SYNC_NEGEDGE = 4096, -}; - -struct videomode { - long unsigned int pixelclock; - u32 hactive; - u32 hfront_porch; - u32 hback_porch; - u32 hsync_len; - u32 vactive; - u32 vfront_porch; - u32 vback_porch; - u32 vsync_len; - enum display_flags flags; -}; - -struct broken_edid { - u8 manufacturer[4]; - u32 model; - u32 fix; -}; - -struct __fb_timings { - u32 dclk; - u32 hfreq; - u32 vfreq; - u32 hactive; - u32 vactive; - u32 hblank; - u32 vblank; - u32 htotal; - u32 vtotal; -}; - -typedef unsigned int u_int; - -struct fb_cvt_data { - u32 xres; - u32 yres; - u32 refresh; - u32 f_refresh; - u32 pixclock; - u32 hperiod; - u32 hblank; - u32 hfreq; - u32 htotal; - u32 vtotal; - u32 vsync; - u32 hsync; - u32 h_front_porch; - u32 h_back_porch; - u32 v_front_porch; - u32 v_back_porch; - u32 h_margin; - u32 v_margin; - u32 interlace; - u32 aspect_ratio; - u32 active_pixels; - u32 flags; - u32 status; -}; - -typedef unsigned char u_char; - -struct fb_con2fbmap { - __u32 console; - __u32 framebuffer; -}; - -struct vc { - struct vc_data *d; - struct work_struct SAK_work; -}; - -struct fbcon_display { - const u_char *fontdata; - int userfont; - u_short scrollmode; - u_short inverse; - short int yscroll; - int vrows; - int cursor_shape; - int con_rotate; - u32 xres_virtual; - u32 yres_virtual; - u32 height; - u32 width; - u32 bits_per_pixel; - u32 grayscale; - u32 nonstd; - u32 accel_flags; - u32 rotate; - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - const struct fb_videomode *mode; -}; - -struct fbcon_ops { - void (*bmove)(struct vc_data *, struct fb_info *, int, int, int, int, int, int); - void (*clear)(struct vc_data *, struct fb_info *, int, int, int, int); - void (*putcs)(struct vc_data *, struct fb_info *, const short unsigned int *, int, int, int, int, int); - void (*clear_margins)(struct vc_data *, struct fb_info *, int, int); - void (*cursor)(struct vc_data *, struct fb_info *, int, int, int); - int (*update_start)(struct fb_info *); - int (*rotate_font)(struct fb_info *, struct vc_data *); - struct fb_var_screeninfo var; - struct timer_list cursor_timer; - struct fb_cursor cursor_state; - struct fbcon_display *p; - struct fb_info *info; - int currcon; - int cur_blink_jiffies; - int cursor_flash; - int cursor_reset; - int blank_state; - int graphics; - int save_graphics; - int flags; - int rotate; - int cur_rotate; - char *cursor_data; - u8 *fontbuffer; - u8 *fontdata; - u8 *cursor_src; - u32 cursor_size; - u32 fd_size; -}; - -enum { - FBCON_LOGO_CANSHOW = 4294967295, - FBCON_LOGO_DRAW = 4294967294, - FBCON_LOGO_DONTSHOW = 4294967293, -}; - -struct fb_dmacopy { - void *dst; - __u32 src; - __u32 length; -}; - -struct bcm2708_dma_cb { - u32 info; - u32 src; - u32 dst; - u32 length; - u32 stride; - u32 next; - u32 pad[2]; -}; - -struct rpi_firmware_property_tag_header { - u32 tag; - u32 buf_size; - u32 req_resp_size; -}; - -struct fb_alloc_tags { - struct rpi_firmware_property_tag_header tag1; - u32 xres; - u32 yres; - struct rpi_firmware_property_tag_header tag2; - u32 xres_virtual; - u32 yres_virtual; - struct rpi_firmware_property_tag_header tag3; - u32 bpp; - struct rpi_firmware_property_tag_header tag4; - u32 xoffset; - u32 yoffset; - struct rpi_firmware_property_tag_header tag5; - u32 base; - u32 screen_size; - struct rpi_firmware_property_tag_header tag6; - u32 pitch; -}; - -struct bcm2708_fb_stats { - struct debugfs_regset32 regset; - u32 dma_copies; - u32 dma_irqs; -}; - -struct vc4_display_settings_t { - u32 display_num; - u32 width; - u32 height; - u32 depth; - u32 pitch; - u32 virtual_width; - u32 virtual_height; - u32 virtual_width_offset; - u32 virtual_height_offset; - long unsigned int fb_bus_address; -}; - -struct bcm2708_fb_dev; - -struct bcm2708_fb { - struct fb_info fb; - struct platform_device *dev; - u32 cmap[16]; - u32 gpu_cmap[256]; - struct dentry *debugfs_dir; - struct dentry *debugfs_subdir; - long unsigned int fb_bus_address; - struct { - u32 base; - u32 length; - } gpu; - struct vc4_display_settings_t display_settings; - struct debugfs_regset32 screeninfo_regset; - struct bcm2708_fb_dev *fbdev; - unsigned int image_size; - dma_addr_t dma_addr; - void *cpuaddr; -}; - -struct bcm2708_fb_dev { - int firmware_supports_multifb; - struct mutex dma_mutex; - int dma_chan; - int dma_irq; - void *dma_chan_base; - wait_queue_head_t dma_waitq; - bool disable_arm_alloc; - struct bcm2708_fb_stats dma_stats; - void *cb_base; - dma_addr_t cb_handle; - int instance_count; - int num_displays; - struct rpi_firmware *fw; - struct bcm2708_fb displays[3]; -}; - -struct fb_dmacopy32 { - compat_uptr_t dst; - __u32 src; - __u32 length; -}; - -struct packet { - u32 offset; - u32 length; - u32 cmap[256]; -}; - -struct simplefb_format { - const char *name; - u32 bits_per_pixel; - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - u32 fourcc; -}; - -struct simplefb_platform_data { - u32 width; - u32 height; - u32 stride; - const char *format; -}; - -struct simplefb_params { - u32 width; - u32 height; - u32 stride; - struct simplefb_format *format; -}; - -struct simplefb_par { - u32 palette[16]; - bool clks_enabled; - unsigned int clk_count; - struct clk **clks; - bool regulators_enabled; - u32 regulator_count; - struct regulator **regulators; -}; - -struct timing_entry { - u32 min; - u32 typ; - u32 max; -}; - -struct display_timing { - struct timing_entry pixelclock; - struct timing_entry hactive; - struct timing_entry hfront_porch; - struct timing_entry hback_porch; - struct timing_entry hsync_len; - struct timing_entry vactive; - struct timing_entry vfront_porch; - struct timing_entry vback_porch; - struct timing_entry vsync_len; - enum display_flags flags; -}; - -struct display_timings { - unsigned int num_timings; - unsigned int native_mode; - struct display_timing **timings; -}; - -struct pm_domain_data { - struct list_head list_node; - struct device *dev; -}; - -struct amba_id { - unsigned int id; - unsigned int mask; - void *data; -}; - -struct amba_cs_uci_id { - unsigned int devarch; - unsigned int devarch_mask; - unsigned int devtype; - void *data; -}; - -struct amba_device { - struct device dev; - struct resource res; - struct clk *pclk; - struct device_dma_parameters dma_parms; - unsigned int periphid; - unsigned int cid; - struct amba_cs_uci_id uci; - unsigned int irq[9]; - char *driver_override; -}; - -struct amba_driver { - struct device_driver drv; - int (*probe)(struct amba_device *, const struct amba_id *); - int (*remove)(struct amba_device *); - void (*shutdown)(struct amba_device *); - const struct amba_id *id_table; -}; - -struct deferred_device { - struct amba_device *dev; - struct resource *parent; - struct list_head node; -}; - -struct find_data { - struct amba_device *dev; - struct device *parent; - const char *busid; - unsigned int id; - unsigned int mask; -}; - -struct clk_bulk_data { - const char *id; - struct clk *clk; -}; - -struct clk_bulk_devres { - struct clk_bulk_data *clks; - int num_clks; -}; - -struct clk_hw; - -struct clk_lookup { - struct list_head node; - const char *dev_id; - const char *con_id; - struct clk *clk; - struct clk_hw *clk_hw; -}; - -struct clk_core; - -struct clk_init_data; - -struct clk_hw { - struct clk_core *core; - struct clk *clk; - const struct clk_init_data *init; -}; - -struct clk_rate_request { - long unsigned int rate; - long unsigned int min_rate; - long unsigned int max_rate; - long unsigned int best_parent_rate; - struct clk_hw *best_parent_hw; -}; - -struct clk_duty { - unsigned int num; - unsigned int den; -}; - -struct clk_ops { - int (*prepare)(struct clk_hw *); - void (*unprepare)(struct clk_hw *); - int (*is_prepared)(struct clk_hw *); - void (*unprepare_unused)(struct clk_hw *); - int (*enable)(struct clk_hw *); - void (*disable)(struct clk_hw *); - int (*is_enabled)(struct clk_hw *); - void (*disable_unused)(struct clk_hw *); - int (*save_context)(struct clk_hw *); - void (*restore_context)(struct clk_hw *); - long unsigned int (*recalc_rate)(struct clk_hw *, long unsigned int); - long int (*round_rate)(struct clk_hw *, long unsigned int, long unsigned int *); - int (*determine_rate)(struct clk_hw *, struct clk_rate_request *); - int (*set_parent)(struct clk_hw *, u8); - u8 (*get_parent)(struct clk_hw *); - int (*set_rate)(struct clk_hw *, long unsigned int, long unsigned int); - int (*set_rate_and_parent)(struct clk_hw *, long unsigned int, long unsigned int, u8); - long unsigned int (*recalc_accuracy)(struct clk_hw *, long unsigned int); - int (*get_phase)(struct clk_hw *); - int (*set_phase)(struct clk_hw *, int); - int (*get_duty_cycle)(struct clk_hw *, struct clk_duty *); - int (*set_duty_cycle)(struct clk_hw *, struct clk_duty *); - int (*init)(struct clk_hw *); - void (*terminate)(struct clk_hw *); - void (*debug_init)(struct clk_hw *, struct dentry *); -}; - -struct clk_parent_data { - const struct clk_hw *hw; - const char *fw_name; - const char *name; - int index; -}; - -struct clk_init_data { - const char *name; - const struct clk_ops *ops; - const char * const *parent_names; - const struct clk_parent_data *parent_data; - const struct clk_hw **parent_hws; - u8 num_parents; - long unsigned int flags; -}; - -struct clk_lookup_alloc { - struct clk_lookup cl; - char dev_id[20]; - char con_id[16]; -}; - -struct clk_notifier { - struct clk *clk; - struct srcu_notifier_head notifier_head; - struct list_head node; -}; - -struct clk { - struct clk_core *core; - struct device *dev; - const char *dev_id; - const char *con_id; - long unsigned int min_rate; - long unsigned int max_rate; - unsigned int exclusive_count; - struct hlist_node clks_node; -}; - -struct clk_notifier_data { - struct clk *clk; - long unsigned int old_rate; - long unsigned int new_rate; -}; - -struct clk_parent_map; - -struct clk_core { - const char *name; - const struct clk_ops *ops; - struct clk_hw *hw; - struct module *owner; - struct device *dev; - struct device_node *of_node; - struct clk_core *parent; - struct clk_parent_map *parents; - u8 num_parents; - u8 new_parent_index; - long unsigned int rate; - long unsigned int req_rate; - long unsigned int new_rate; - struct clk_core *new_parent; - struct clk_core *new_child; - long unsigned int flags; - bool orphan; - bool rpm_enabled; - unsigned int enable_count; - unsigned int prepare_count; - unsigned int protect_count; - long unsigned int min_rate; - long unsigned int max_rate; - long unsigned int default_request_rate; - long unsigned int accuracy; - int phase; - struct clk_duty duty; - struct hlist_head children; - struct hlist_node child_node; - struct hlist_head clks; - struct list_head pending_requests; - unsigned int notifier_count; - struct dentry *dentry; - struct hlist_node debug_node; - struct kref ref; -}; - -struct clk_onecell_data { - struct clk **clks; - unsigned int clk_num; -}; - -struct clk_hw_onecell_data { - unsigned int num; - struct clk_hw *hws[0]; -}; - -struct clk_parent_map { - const struct clk_hw *hw; - struct clk_core *core; - const char *fw_name; - const char *name; - int index; -}; - -struct trace_event_raw_clk { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_clk_rate { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int rate; - char __data[0]; -}; - -struct trace_event_raw_clk_parent { - struct trace_entry ent; - u32 __data_loc_name; - u32 __data_loc_pname; - char __data[0]; -}; - -struct trace_event_raw_clk_phase { - struct trace_entry ent; - u32 __data_loc_name; - int phase; - char __data[0]; -}; - -struct trace_event_raw_clk_duty_cycle { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int num; - unsigned int den; - char __data[0]; -}; - -struct trace_event_data_offsets_clk { - u32 name; -}; - -struct trace_event_data_offsets_clk_rate { - u32 name; -}; - -struct trace_event_data_offsets_clk_parent { - u32 name; - u32 pname; -}; - -struct trace_event_data_offsets_clk_phase { - u32 name; -}; - -struct trace_event_data_offsets_clk_duty_cycle { - u32 name; -}; - -typedef void (*btf_trace_clk_enable)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_enable_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_disable)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_disable_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_prepare)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_prepare_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_unprepare)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_unprepare_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_set_rate)(void *, struct clk_core *, long unsigned int); - -typedef void (*btf_trace_clk_set_rate_complete)(void *, struct clk_core *, long unsigned int); - -typedef void (*btf_trace_clk_set_parent)(void *, struct clk_core *, struct clk_core *); - -typedef void (*btf_trace_clk_set_parent_complete)(void *, struct clk_core *, struct clk_core *); - -typedef void (*btf_trace_clk_set_phase)(void *, struct clk_core *, int); - -typedef void (*btf_trace_clk_set_phase_complete)(void *, struct clk_core *, int); - -typedef void (*btf_trace_clk_set_duty_cycle)(void *, struct clk_core *, struct clk_duty *); - -typedef void (*btf_trace_clk_set_duty_cycle_complete)(void *, struct clk_core *, struct clk_duty *); - -struct clk_request { - struct list_head list; - struct clk *clk; - long unsigned int rate; -}; - -struct of_clk_provider { - struct list_head link; - struct device_node *node; - struct clk * (*get)(struct of_phandle_args *, void *); - struct clk_hw * (*get_hw)(struct of_phandle_args *, void *); - void *data; -}; - -struct clock_provider { - void (*clk_init_cb)(struct device_node *); - struct device_node *np; - struct list_head node; -}; - -struct clk_div_table { - unsigned int val; - unsigned int div; -}; - -struct clk_divider { - struct clk_hw hw; - void *reg; - u8 shift; - u8 width; - u8 flags; - const struct clk_div_table *table; - spinlock_t *lock; -}; - -typedef void (*of_init_fn_1)(struct device_node *); - -struct clk_fixed_factor { - struct clk_hw hw; - unsigned int mult; - unsigned int div; -}; - -struct clk_fixed_rate { - struct clk_hw hw; - long unsigned int fixed_rate; - long unsigned int fixed_accuracy; - long unsigned int flags; -}; - -struct clk_gate { - struct clk_hw hw; - void *reg; - u8 bit_idx; - u8 flags; - spinlock_t *lock; -}; - -struct clk_multiplier { - struct clk_hw hw; - void *reg; - u8 shift; - u8 width; - u8 flags; - spinlock_t *lock; -}; - -struct clk_mux { - struct clk_hw hw; - void *reg; - u32 *table; - u32 mask; - u8 shift; - u8 flags; - spinlock_t *lock; -}; - -struct clk_composite { - struct clk_hw hw; - struct clk_ops ops; - struct clk_hw *mux_hw; - struct clk_hw *rate_hw; - struct clk_hw *gate_hw; - const struct clk_ops *mux_ops; - const struct clk_ops *rate_ops; - const struct clk_ops *gate_ops; -}; - -struct clk_fractional_divider { - struct clk_hw hw; - void *reg; - u8 mshift; - u8 mwidth; - u32 mmask; - u8 nshift; - u8 nwidth; - u32 nmask; - u8 flags; - void (*approximation)(struct clk_hw *, long unsigned int, long unsigned int *, long unsigned int *, long unsigned int *); - spinlock_t *lock; -}; - -struct clk_gpio { - struct clk_hw hw; - struct gpio_desc *gpiod; -}; - -struct reset_controller_dev; - -struct reset_control_ops { - int (*reset)(struct reset_controller_dev *, long unsigned int); - int (*assert)(struct reset_controller_dev *, long unsigned int); - int (*deassert)(struct reset_controller_dev *, long unsigned int); - int (*status)(struct reset_controller_dev *, long unsigned int); -}; - -struct reset_controller_dev { - const struct reset_control_ops *ops; - struct module *owner; - struct list_head list; - struct list_head reset_control_head; - struct device *dev; - struct device_node *of_node; - int of_reset_n_cells; - int (*of_xlate)(struct reset_controller_dev *, const struct of_phandle_args *); - unsigned int nr_resets; -}; - -struct reset_simple_data { - spinlock_t lock; - void *membase; - struct reset_controller_dev rcdev; - bool active_low; - bool status_active_low; - unsigned int reset_us; -}; - -struct clk_dvp { - struct clk_hw_onecell_data *data; - struct reset_simple_data reset; -}; - -struct bcm2835_cprman { - struct device *dev; - void *regs; - struct rpi_firmware *fw; - spinlock_t regs_lock; - unsigned int soc; - const char *real_parent_names[7]; - struct clk_hw_onecell_data onecell; -}; - -struct cprman_plat_data { - unsigned int soc; -}; - -struct bcm2835_pll_ana_bits; - -struct bcm2835_pll_data { - const char *name; - u32 cm_ctrl_reg; - u32 a2w_ctrl_reg; - u32 frac_reg; - u32 ana_reg_base; - u32 reference_enable_mask; - u32 lock_mask; - u32 flags; - const struct bcm2835_pll_ana_bits *ana; - long unsigned int min_rate; - long unsigned int max_rate; - long unsigned int max_fb_rate; -}; - -struct bcm2835_pll_ana_bits { - u32 mask0; - u32 set0; - u32 mask1; - u32 set1; - u32 mask3; - u32 set3; - u32 fb_prediv_mask; -}; - -struct bcm2835_pll_divider_data { - const char *name; - const char *source_pll; - u32 cm_reg; - u32 a2w_reg; - u32 load_mask; - u32 hold_mask; - u32 fixed_divider; - u32 flags; -}; - -struct bcm2835_clock_data { - const char *name; - const char * const *parents; - int num_mux_parents; - unsigned int set_rate_parent; - u32 ctl_reg; - u32 div_reg; - u32 int_bits; - u32 frac_bits; - u32 flags; - bool is_vpu_clock; - bool is_mash_clock; - bool low_jitter; - u32 tcnt_mux; -}; - -struct bcm2835_gate_data { - const char *name; - const char *parent; - u32 ctl_reg; -}; - -struct bcm2835_pll { - struct clk_hw hw; - struct bcm2835_cprman *cprman; - const struct bcm2835_pll_data *data; -}; - -struct bcm2835_pll_divider { - struct clk_divider div; - struct bcm2835_cprman *cprman; - const struct bcm2835_pll_divider_data *data; -}; - -struct bcm2835_clock { - struct clk_hw hw; - struct bcm2835_cprman *cprman; - const struct bcm2835_clock_data *data; -}; - -struct bcm2835_clk_desc { - struct clk_hw * (*clk_register)(struct bcm2835_cprman *, const void *); - unsigned int supported; - const void *data; -}; - -enum rpi_firmware_clk_id { - RPI_FIRMWARE_EMMC_CLK_ID = 1, - RPI_FIRMWARE_UART_CLK_ID = 2, - RPI_FIRMWARE_ARM_CLK_ID = 3, - RPI_FIRMWARE_CORE_CLK_ID = 4, - RPI_FIRMWARE_V3D_CLK_ID = 5, - RPI_FIRMWARE_H264_CLK_ID = 6, - RPI_FIRMWARE_ISP_CLK_ID = 7, - RPI_FIRMWARE_SDRAM_CLK_ID = 8, - RPI_FIRMWARE_PIXEL_CLK_ID = 9, - RPI_FIRMWARE_PWM_CLK_ID = 10, - RPI_FIRMWARE_HEVC_CLK_ID = 11, - RPI_FIRMWARE_EMMC2_CLK_ID = 12, - RPI_FIRMWARE_M2MC_CLK_ID = 13, - RPI_FIRMWARE_PIXEL_BVB_CLK_ID = 14, - RPI_FIRMWARE_VEC_CLK_ID = 15, - RPI_FIRMWARE_NUM_CLK_ID = 16, -}; - -struct raspberrypi_clk { - struct device *dev; - struct rpi_firmware *firmware; - struct platform_device *cpufreq; -}; - -struct raspberrypi_clk_data { - struct clk_hw hw; - unsigned int id; - struct raspberrypi_clk *rpi; -}; - -struct raspberrypi_firmware_prop { - __le32 id; - __le32 val; - __le32 disable_turbo; -}; - -struct rpi_firmware_get_clocks_response { - u32 parent; - u32 id; -}; - -typedef s32 dma_cookie_t; - -enum dma_status { - DMA_COMPLETE = 0, - DMA_IN_PROGRESS = 1, - DMA_PAUSED = 2, - DMA_ERROR = 3, - DMA_OUT_OF_ORDER = 4, -}; - -enum dma_transaction_type { - DMA_MEMCPY = 0, - DMA_XOR = 1, - DMA_PQ = 2, - DMA_XOR_VAL = 3, - DMA_PQ_VAL = 4, - DMA_MEMSET = 5, - DMA_MEMSET_SG = 6, - DMA_INTERRUPT = 7, - DMA_PRIVATE = 8, - DMA_ASYNC_TX = 9, - DMA_SLAVE = 10, - DMA_CYCLIC = 11, - DMA_INTERLEAVE = 12, - DMA_COMPLETION_NO_ORDER = 13, - DMA_REPEAT = 14, - DMA_LOAD_EOT = 15, - DMA_TX_TYPE_END = 16, -}; - -enum dma_transfer_direction { - DMA_MEM_TO_MEM = 0, - DMA_MEM_TO_DEV = 1, - DMA_DEV_TO_MEM = 2, - DMA_DEV_TO_DEV = 3, - DMA_TRANS_NONE = 4, -}; - -struct data_chunk { - size_t size; - size_t icg; - size_t dst_icg; - size_t src_icg; -}; - -struct dma_interleaved_template { - dma_addr_t src_start; - dma_addr_t dst_start; - enum dma_transfer_direction dir; - bool src_inc; - bool dst_inc; - bool src_sgl; - bool dst_sgl; - size_t numf; - size_t frame_size; - struct data_chunk sgl[0]; -}; - -enum dma_ctrl_flags { - DMA_PREP_INTERRUPT = 1, - DMA_CTRL_ACK = 2, - DMA_PREP_PQ_DISABLE_P = 4, - DMA_PREP_PQ_DISABLE_Q = 8, - DMA_PREP_CONTINUE = 16, - DMA_PREP_FENCE = 32, - DMA_CTRL_REUSE = 64, - DMA_PREP_CMD = 128, - DMA_PREP_REPEAT = 256, - DMA_PREP_LOAD_EOT = 512, -}; - -enum sum_check_bits { - SUM_CHECK_P = 0, - SUM_CHECK_Q = 1, -}; - -enum sum_check_flags { - SUM_CHECK_P_RESULT = 1, - SUM_CHECK_Q_RESULT = 2, -}; - -typedef struct { - long unsigned int bits[1]; -} dma_cap_mask_t; - -enum dma_desc_metadata_mode { - DESC_METADATA_NONE = 0, - DESC_METADATA_CLIENT = 1, - DESC_METADATA_ENGINE = 2, -}; - -struct dma_chan_percpu { - long unsigned int memcpy_count; - long unsigned int bytes_transferred; -}; - -struct dma_router { - struct device *dev; - void (*route_free)(struct device *, void *); -}; - -struct dma_device; - -struct dma_chan_dev; - -struct dma_chan { - struct dma_device *device; - struct device *slave; - dma_cookie_t cookie; - dma_cookie_t completed_cookie; - int chan_id; - struct dma_chan_dev *dev; - const char *name; - char *dbg_client_name; - struct list_head device_node; - struct dma_chan_percpu *local; - int client_count; - int table_count; - struct dma_router *router; - void *route_data; - void *private; -}; - -typedef bool (*dma_filter_fn)(struct dma_chan *, void *); - -struct dma_slave_map; - -struct dma_filter { - dma_filter_fn fn; - int mapcnt; - const struct dma_slave_map *map; -}; - -enum dmaengine_alignment { - DMAENGINE_ALIGN_1_BYTE = 0, - DMAENGINE_ALIGN_2_BYTES = 1, - DMAENGINE_ALIGN_4_BYTES = 2, - DMAENGINE_ALIGN_8_BYTES = 3, - DMAENGINE_ALIGN_16_BYTES = 4, - DMAENGINE_ALIGN_32_BYTES = 5, - DMAENGINE_ALIGN_64_BYTES = 6, -}; - -enum dma_residue_granularity { - DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0, - DMA_RESIDUE_GRANULARITY_SEGMENT = 1, - DMA_RESIDUE_GRANULARITY_BURST = 2, -}; - -struct dma_async_tx_descriptor; - -struct dma_slave_caps; - -struct dma_slave_config; - -struct dma_tx_state; - -struct dma_device { - struct kref ref; - unsigned int chancnt; - unsigned int privatecnt; - struct list_head channels; - struct list_head global_node; - struct dma_filter filter; - dma_cap_mask_t cap_mask; - enum dma_desc_metadata_mode desc_metadata_modes; - short unsigned int max_xor; - short unsigned int max_pq; - enum dmaengine_alignment copy_align; - enum dmaengine_alignment xor_align; - enum dmaengine_alignment pq_align; - enum dmaengine_alignment fill_align; - int dev_id; - struct device *dev; - struct module *owner; - struct ida chan_ida; - struct mutex chan_mutex; - u32 src_addr_widths; - u32 dst_addr_widths; - u32 directions; - u32 min_burst; - u32 max_burst; - u32 max_sg_burst; - bool descriptor_reuse; - enum dma_residue_granularity residue_granularity; - int (*device_alloc_chan_resources)(struct dma_chan *); - void (*device_free_chan_resources)(struct dma_chan *); - struct dma_async_tx_descriptor * (*device_prep_dma_memcpy)(struct dma_chan *, dma_addr_t, dma_addr_t, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_xor)(struct dma_chan *, dma_addr_t, dma_addr_t *, unsigned int, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_xor_val)(struct dma_chan *, dma_addr_t *, unsigned int, size_t, enum sum_check_flags *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_pq)(struct dma_chan *, dma_addr_t *, dma_addr_t *, unsigned int, const unsigned char *, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_pq_val)(struct dma_chan *, dma_addr_t *, dma_addr_t *, unsigned int, const unsigned char *, size_t, enum sum_check_flags *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_memset)(struct dma_chan *, dma_addr_t, int, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_memset_sg)(struct dma_chan *, struct scatterlist *, unsigned int, int, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_interrupt)(struct dma_chan *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_slave_sg)(struct dma_chan *, struct scatterlist *, unsigned int, enum dma_transfer_direction, long unsigned int, void *); - struct dma_async_tx_descriptor * (*device_prep_dma_cyclic)(struct dma_chan *, dma_addr_t, size_t, size_t, enum dma_transfer_direction, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_interleaved_dma)(struct dma_chan *, struct dma_interleaved_template *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_imm_data)(struct dma_chan *, dma_addr_t, u64, long unsigned int); - void (*device_caps)(struct dma_chan *, struct dma_slave_caps *); - int (*device_config)(struct dma_chan *, struct dma_slave_config *); - int (*device_pause)(struct dma_chan *); - int (*device_resume)(struct dma_chan *); - int (*device_terminate_all)(struct dma_chan *); - void (*device_synchronize)(struct dma_chan *); - enum dma_status (*device_tx_status)(struct dma_chan *, dma_cookie_t, struct dma_tx_state *); - void (*device_issue_pending)(struct dma_chan *); - void (*device_release)(struct dma_device *); - void (*dbg_summary_show)(struct seq_file *, struct dma_device *); - struct dentry *dbg_dev_root; -}; - -struct dma_chan_dev { - struct dma_chan *chan; - struct device device; - int dev_id; -}; - -enum dma_slave_buswidth { - DMA_SLAVE_BUSWIDTH_UNDEFINED = 0, - DMA_SLAVE_BUSWIDTH_1_BYTE = 1, - DMA_SLAVE_BUSWIDTH_2_BYTES = 2, - DMA_SLAVE_BUSWIDTH_3_BYTES = 3, - DMA_SLAVE_BUSWIDTH_4_BYTES = 4, - DMA_SLAVE_BUSWIDTH_8_BYTES = 8, - DMA_SLAVE_BUSWIDTH_16_BYTES = 16, - DMA_SLAVE_BUSWIDTH_32_BYTES = 32, - DMA_SLAVE_BUSWIDTH_64_BYTES = 64, -}; - -struct dma_slave_config { - enum dma_transfer_direction direction; - phys_addr_t src_addr; - phys_addr_t dst_addr; - enum dma_slave_buswidth src_addr_width; - enum dma_slave_buswidth dst_addr_width; - u32 src_maxburst; - u32 dst_maxburst; - u32 src_port_window_size; - u32 dst_port_window_size; - bool device_fc; - unsigned int slave_id; -}; - -struct dma_slave_caps { - u32 src_addr_widths; - u32 dst_addr_widths; - u32 directions; - u32 min_burst; - u32 max_burst; - u32 max_sg_burst; - bool cmd_pause; - bool cmd_resume; - bool cmd_terminate; - enum dma_residue_granularity residue_granularity; - bool descriptor_reuse; -}; - -typedef void (*dma_async_tx_callback)(void *); - -enum dmaengine_tx_result { - DMA_TRANS_NOERROR = 0, - DMA_TRANS_READ_FAILED = 1, - DMA_TRANS_WRITE_FAILED = 2, - DMA_TRANS_ABORTED = 3, -}; - -struct dmaengine_result { - enum dmaengine_tx_result result; - u32 residue; -}; - -typedef void (*dma_async_tx_callback_result)(void *, const struct dmaengine_result *); - -struct dmaengine_unmap_data { - u8 map_cnt; - u8 to_cnt; - u8 from_cnt; - u8 bidi_cnt; - struct device *dev; - struct kref kref; - size_t len; - dma_addr_t addr[0]; -}; - -struct dma_descriptor_metadata_ops { - int (*attach)(struct dma_async_tx_descriptor *, void *, size_t); - void * (*get_ptr)(struct dma_async_tx_descriptor *, size_t *, size_t *); - int (*set_len)(struct dma_async_tx_descriptor *, size_t); -}; - -struct dma_async_tx_descriptor { - dma_cookie_t cookie; - enum dma_ctrl_flags flags; - dma_addr_t phys; - struct dma_chan *chan; - dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *); - int (*desc_free)(struct dma_async_tx_descriptor *); - dma_async_tx_callback callback; - dma_async_tx_callback_result callback_result; - void *callback_param; - struct dmaengine_unmap_data *unmap; - enum dma_desc_metadata_mode desc_metadata_mode; - struct dma_descriptor_metadata_ops *metadata_ops; -}; - -struct dma_tx_state { - dma_cookie_t last; - dma_cookie_t used; - u32 residue; - u32 in_flight_bytes; -}; - -struct dma_slave_map { - const char *devname; - const char *slave; - void *param; -}; - -struct dma_chan_tbl_ent { - struct dma_chan *chan; -}; - -struct dmaengine_unmap_pool { - struct kmem_cache *cache; - const char *name; - mempool_t *pool; - size_t size; -}; - -struct dmaengine_desc_callback { - dma_async_tx_callback callback; - dma_async_tx_callback_result callback_result; - void *callback_param; -}; - -struct virt_dma_desc { - struct dma_async_tx_descriptor tx; - struct dmaengine_result tx_result; - struct list_head node; -}; - -struct virt_dma_chan { - struct dma_chan chan; - struct tasklet_struct task; - void (*desc_free)(struct virt_dma_desc *); - spinlock_t lock; - struct list_head desc_allocated; - struct list_head desc_submitted; - struct list_head desc_issued; - struct list_head desc_completed; - struct list_head desc_terminated; - struct virt_dma_desc *cyclic; -}; - -struct of_dma { - struct list_head of_dma_controllers; - struct device_node *of_node; - struct dma_chan * (*of_dma_xlate)(struct of_phandle_args *, struct of_dma *); - void * (*of_dma_route_allocate)(struct of_phandle_args *, struct of_dma *); - struct dma_router *dma_router; - void *of_dma_data; -}; - -struct of_dma_filter_info { - dma_cap_mask_t dma_cap; - dma_filter_fn filter_fn; -}; - -struct vc_dmaman { - void *dma_base; - u32 chan_available; - u32 has_feature[4]; - struct mutex lock; -}; - -struct bcm2835_dma_cfg_data { - u64 dma_mask; - u32 chan_40bit_mask; -}; - -struct bcm2835_dmadev { - struct dma_device ddev; - void *base; - dma_addr_t zero_page; - const struct bcm2835_dma_cfg_data *cfg_data; -}; - -struct bcm2835_dma_cb { - uint32_t info; - uint32_t src; - uint32_t dst; - uint32_t length; - uint32_t stride; - uint32_t next; - uint32_t pad[2]; -}; - -struct bcm2711_dma40_scb { - uint32_t ti; - uint32_t src; - uint32_t srci; - uint32_t dst; - uint32_t dsti; - uint32_t len; - uint32_t next_cb; - uint32_t rsvd; -}; - -struct bcm2835_cb_entry { - struct bcm2835_dma_cb *cb; - dma_addr_t paddr; -}; - -struct dma_pool___2; - -struct bcm2835_desc; - -struct bcm2835_chan { - struct virt_dma_chan vc; - struct dma_slave_config cfg; - unsigned int dreq; - int ch; - struct bcm2835_desc *desc; - struct dma_pool___2 *cb_pool; - void *chan_base; - int irq_number; - unsigned int irq_flags; - bool is_lite_channel; - bool is_40bit_channel; -}; - -struct bcm2835_desc { - struct bcm2835_chan *c; - struct virt_dma_desc vd; - enum dma_transfer_direction dir; - unsigned int frames; - size_t size; - bool cyclic; - struct bcm2835_cb_entry cb_list[0]; -}; - -struct bcm2835_pm { - struct device *dev; - void *base; - void *asb; - void *rpivid_asb; -}; - -enum gpd_status { - GENPD_STATE_ON = 0, - GENPD_STATE_OFF = 1, -}; - -struct dev_power_governor { - bool (*power_down_ok)(struct dev_pm_domain *); - bool (*suspend_ok)(struct device *); -}; - -struct gpd_dev_ops { - int (*start)(struct device *); - int (*stop)(struct device *); -}; - -struct genpd_power_state { - s64 power_off_latency_ns; - s64 power_on_latency_ns; - s64 residency_ns; - u64 usage; - u64 rejected; - struct fwnode_handle *fwnode; - ktime_t idle_time; - void *data; -}; - -struct opp_table; - -struct dev_pm_opp; - -struct genpd_lock_ops; - -struct generic_pm_domain { - struct device dev; - struct dev_pm_domain domain; - struct list_head gpd_list_node; - struct list_head parent_links; - struct list_head child_links; - struct list_head dev_list; - struct dev_power_governor *gov; - struct work_struct power_off_work; - struct fwnode_handle *provider; - bool has_provider; - const char *name; - atomic_t sd_count; - enum gpd_status status; - unsigned int device_count; - unsigned int suspended_count; - unsigned int prepared_count; - unsigned int performance_state; - cpumask_var_t cpus; - int (*power_off)(struct generic_pm_domain *); - int (*power_on)(struct generic_pm_domain *); - struct raw_notifier_head power_notifiers; - struct opp_table *opp_table; - unsigned int (*opp_to_performance_state)(struct generic_pm_domain *, struct dev_pm_opp *); - int (*set_performance_state)(struct generic_pm_domain *, unsigned int); - struct gpd_dev_ops dev_ops; - s64 max_off_time_ns; - bool max_off_time_changed; - bool cached_power_down_ok; - bool cached_power_down_state_idx; - int (*attach_dev)(struct generic_pm_domain *, struct device *); - void (*detach_dev)(struct generic_pm_domain *, struct device *); - unsigned int flags; - struct genpd_power_state *states; - void (*free_states)(struct genpd_power_state *, unsigned int); - unsigned int state_count; - unsigned int state_idx; - ktime_t on_time; - ktime_t accounting_time; - const struct genpd_lock_ops *lock_ops; - union { - struct mutex mlock; - struct { - spinlock_t slock; - long unsigned int lock_flags; - }; - }; -}; - -struct genpd_lock_ops { - void (*lock)(struct generic_pm_domain *); - void (*lock_nested)(struct generic_pm_domain *, int); - int (*lock_interruptible)(struct generic_pm_domain *); - void (*unlock)(struct generic_pm_domain *); -}; - -typedef struct generic_pm_domain * (*genpd_xlate_t)(struct of_phandle_args *, void *); - -struct genpd_onecell_data { - struct generic_pm_domain **domains; - unsigned int num_domains; - genpd_xlate_t xlate; -}; - -struct bcm2835_power; - -struct bcm2835_power_domain { - struct generic_pm_domain base; - struct bcm2835_power *power; - u32 domain; - struct clk *clk; -}; - -struct bcm2835_power { - struct device *dev; - void *base; - void *asb; - bool is_2711; - struct genpd_onecell_data pd_xlate; - struct bcm2835_power_domain domains[13]; - struct reset_controller_dev reset; -}; - -struct rpi_power_domain { - u32 domain; - bool enabled; - bool old_interface; - struct generic_pm_domain base; - struct rpi_firmware *fw; -}; - -struct rpi_power_domains { - bool has_new_interface; - struct genpd_onecell_data xlate; - struct rpi_firmware *fw; - struct rpi_power_domain domains[23]; -}; - -struct rpi_power_domain_packet { - u32 domain; - u32 on; -}; - -struct ww_class { - atomic_long_t stamp; - struct lock_class_key acquire_key; - struct lock_class_key mutex_key; - const char *acquire_name; - const char *mutex_name; - unsigned int is_wait_die; -}; - -struct regulator_state { - int uV; - int min_uV; - int max_uV; - unsigned int mode; - int enabled; - bool changeable; -}; - -struct regulation_constraints { - const char *name; - int min_uV; - int max_uV; - int uV_offset; - int min_uA; - int max_uA; - int ilim_uA; - int system_load; - u32 *max_spread; - int max_uV_step; - unsigned int valid_modes_mask; - unsigned int valid_ops_mask; - int input_uV; - struct regulator_state state_disk; - struct regulator_state state_mem; - struct regulator_state state_standby; - suspend_state_t initial_state; - unsigned int initial_mode; - unsigned int ramp_delay; - unsigned int settling_time; - unsigned int settling_time_up; - unsigned int settling_time_down; - unsigned int enable_time; - unsigned int active_discharge; - unsigned int always_on: 1; - unsigned int boot_on: 1; - unsigned int apply_uV: 1; - unsigned int ramp_disable: 1; - unsigned int soft_start: 1; - unsigned int pull_down: 1; - unsigned int over_current_protection: 1; -}; - -struct regulator_consumer_supply; - -struct regulator_init_data { - const char *supply_regulator; - struct regulation_constraints constraints; - int num_consumer_supplies; - struct regulator_consumer_supply *consumer_supplies; - int (*regulator_init)(void *); - void *driver_data; -}; - -enum regulator_type { - REGULATOR_VOLTAGE = 0, - REGULATOR_CURRENT = 1, -}; - -struct regulator_config; - -struct regulator_ops; - -struct regulator_desc { - const char *name; - const char *supply_name; - const char *of_match; - const char *regulators_node; - int (*of_parse_cb)(struct device_node *, const struct regulator_desc *, struct regulator_config *); - int id; - unsigned int continuous_voltage_range: 1; - unsigned int n_voltages; - unsigned int n_current_limits; - const struct regulator_ops *ops; - int irq; - enum regulator_type type; - struct module *owner; - unsigned int min_uV; - unsigned int uV_step; - unsigned int linear_min_sel; - int fixed_uV; - unsigned int ramp_delay; - int min_dropout_uV; - const struct linear_range *linear_ranges; - const unsigned int *linear_range_selectors; - int n_linear_ranges; - const unsigned int *volt_table; - const unsigned int *curr_table; - unsigned int vsel_range_reg; - unsigned int vsel_range_mask; - unsigned int vsel_reg; - unsigned int vsel_mask; - unsigned int vsel_step; - unsigned int csel_reg; - unsigned int csel_mask; - unsigned int apply_reg; - unsigned int apply_bit; - unsigned int enable_reg; - unsigned int enable_mask; - unsigned int enable_val; - unsigned int disable_val; - bool enable_is_inverted; - unsigned int bypass_reg; - unsigned int bypass_mask; - unsigned int bypass_val_on; - unsigned int bypass_val_off; - unsigned int active_discharge_on; - unsigned int active_discharge_off; - unsigned int active_discharge_mask; - unsigned int active_discharge_reg; - unsigned int soft_start_reg; - unsigned int soft_start_mask; - unsigned int soft_start_val_on; - unsigned int pull_down_reg; - unsigned int pull_down_mask; - unsigned int pull_down_val_on; - unsigned int enable_time; - unsigned int off_on_delay; - unsigned int poll_enabled_time; - unsigned int (*of_map_mode)(unsigned int); -}; - -struct pre_voltage_change_data { - long unsigned int old_uV; - long unsigned int min_uV; - long unsigned int max_uV; -}; - -struct regulator_bulk_data { - const char *supply; - struct regulator *consumer; - int ret; -}; - -struct regulator_voltage { - int min_uV; - int max_uV; -}; - -struct regulator_dev; - -struct regulator { - struct device *dev; - struct list_head list; - unsigned int always_on: 1; - unsigned int bypass: 1; - unsigned int device_link: 1; - int uA_load; - unsigned int enable_count; - unsigned int deferred_disables; - struct regulator_voltage voltage[5]; - const char *supply_name; - struct device_attribute dev_attr; - struct regulator_dev *rdev; - struct dentry *debugfs; -}; - -struct regulator_coupler { - struct list_head list; - int (*attach_regulator)(struct regulator_coupler *, struct regulator_dev *); - int (*detach_regulator)(struct regulator_coupler *, struct regulator_dev *); - int (*balance_voltage)(struct regulator_coupler *, struct regulator_dev *, suspend_state_t); -}; - -struct coupling_desc { - struct regulator_dev **coupled_rdevs; - struct regulator_coupler *coupler; - int n_resolved; - int n_coupled; -}; - -struct regmap; - -struct regulator_enable_gpio; - -struct regulator_dev { - const struct regulator_desc *desc; - int exclusive; - u32 use_count; - u32 open_count; - u32 bypass_count; - struct list_head list; - struct list_head consumer_list; - struct coupling_desc coupling_desc; - struct blocking_notifier_head notifier; - struct ww_mutex mutex; - struct task_struct *mutex_owner; - int ref_cnt; - struct module *owner; - struct device dev; - struct regulation_constraints *constraints; - struct regulator *supply; - const char *supply_name; - struct regmap *regmap; - struct delayed_work disable_work; - void *reg_data; - struct dentry *debugfs; - struct regulator_enable_gpio *ena_pin; - unsigned int ena_gpio_state: 1; - unsigned int is_switch: 1; - long unsigned int last_off_jiffy; -}; - -enum regulator_status { - REGULATOR_STATUS_OFF = 0, - REGULATOR_STATUS_ON = 1, - REGULATOR_STATUS_ERROR = 2, - REGULATOR_STATUS_FAST = 3, - REGULATOR_STATUS_NORMAL = 4, - REGULATOR_STATUS_IDLE = 5, - REGULATOR_STATUS_STANDBY = 6, - REGULATOR_STATUS_BYPASS = 7, - REGULATOR_STATUS_UNDEFINED = 8, -}; - -struct regulator_ops { - int (*list_voltage)(struct regulator_dev *, unsigned int); - int (*set_voltage)(struct regulator_dev *, int, int, unsigned int *); - int (*map_voltage)(struct regulator_dev *, int, int); - int (*set_voltage_sel)(struct regulator_dev *, unsigned int); - int (*get_voltage)(struct regulator_dev *); - int (*get_voltage_sel)(struct regulator_dev *); - int (*set_current_limit)(struct regulator_dev *, int, int); - int (*get_current_limit)(struct regulator_dev *); - int (*set_input_current_limit)(struct regulator_dev *, int); - int (*set_over_current_protection)(struct regulator_dev *); - int (*set_active_discharge)(struct regulator_dev *, bool); - int (*enable)(struct regulator_dev *); - int (*disable)(struct regulator_dev *); - int (*is_enabled)(struct regulator_dev *); - int (*set_mode)(struct regulator_dev *, unsigned int); - unsigned int (*get_mode)(struct regulator_dev *); - int (*get_error_flags)(struct regulator_dev *, unsigned int *); - int (*enable_time)(struct regulator_dev *); - int (*set_ramp_delay)(struct regulator_dev *, int); - int (*set_voltage_time)(struct regulator_dev *, int, int); - int (*set_voltage_time_sel)(struct regulator_dev *, unsigned int, unsigned int); - int (*set_soft_start)(struct regulator_dev *); - int (*get_status)(struct regulator_dev *); - unsigned int (*get_optimum_mode)(struct regulator_dev *, int, int, int); - int (*set_load)(struct regulator_dev *, int); - int (*set_bypass)(struct regulator_dev *, bool); - int (*get_bypass)(struct regulator_dev *, bool *); - int (*set_suspend_voltage)(struct regulator_dev *, int); - int (*set_suspend_enable)(struct regulator_dev *); - int (*set_suspend_disable)(struct regulator_dev *); - int (*set_suspend_mode)(struct regulator_dev *, unsigned int); - int (*resume)(struct regulator_dev *); - int (*set_pull_down)(struct regulator_dev *); -}; - -struct regulator_config { - struct device *dev; - const struct regulator_init_data *init_data; - void *driver_data; - struct device_node *of_node; - struct regmap *regmap; - struct gpio_desc *ena_gpiod; -}; - -struct regulator_enable_gpio { - struct list_head list; - struct gpio_desc *gpiod; - u32 enable_count; - u32 request_count; -}; - -enum regulator_active_discharge { - REGULATOR_ACTIVE_DISCHARGE_DEFAULT = 0, - REGULATOR_ACTIVE_DISCHARGE_DISABLE = 1, - REGULATOR_ACTIVE_DISCHARGE_ENABLE = 2, -}; - -struct regulator_consumer_supply { - const char *dev_name; - const char *supply; -}; - -struct trace_event_raw_regulator_basic { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_regulator_range { - struct trace_entry ent; - u32 __data_loc_name; - int min; - int max; - char __data[0]; -}; - -struct trace_event_raw_regulator_value { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int val; - char __data[0]; -}; - -struct trace_event_data_offsets_regulator_basic { - u32 name; -}; - -struct trace_event_data_offsets_regulator_range { - u32 name; -}; - -struct trace_event_data_offsets_regulator_value { - u32 name; -}; - -typedef void (*btf_trace_regulator_enable)(void *, const char *); - -typedef void (*btf_trace_regulator_enable_delay)(void *, const char *); - -typedef void (*btf_trace_regulator_enable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_disable)(void *, const char *); - -typedef void (*btf_trace_regulator_disable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_enable)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_enable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_disable)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_disable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_set_voltage)(void *, const char *, int, int); - -typedef void (*btf_trace_regulator_set_voltage_complete)(void *, const char *, unsigned int); - -enum regulator_get_type { - NORMAL_GET = 0, - EXCLUSIVE_GET = 1, - OPTIONAL_GET = 2, - MAX_GET_TYPE = 3, -}; - -struct regulator_map { - struct list_head list; - const char *dev_name; - const char *supply; - struct regulator_dev *regulator; -}; - -struct regulator_supply_alias { - struct list_head list; - struct device *src_dev; - const char *src_supply; - struct device *alias_dev; - const char *alias_supply; -}; - -struct summary_data { - struct seq_file *s; - struct regulator_dev *parent; - int level; -}; - -struct summary_lock_data { - struct ww_acquire_ctx *ww_ctx; - struct regulator_dev **new_contended_rdev; - struct regulator_dev **old_contended_rdev; -}; - -struct fixed_voltage_config { - const char *supply_name; - const char *input_supply; - int microvolts; - unsigned int startup_delay; - unsigned int off_on_delay; - unsigned int enabled_at_boot: 1; - struct regulator_init_data *init_data; -}; - -struct fixed_regulator_data { - struct fixed_voltage_config cfg; - struct regulator_init_data init_data; - struct platform_device pdev; -}; - -struct regulator_bulk_devres { - struct regulator_bulk_data *consumers; - int num_consumers; -}; - -struct regulator_supply_alias_match { - struct device *dev; - const char *id; -}; - -struct regulator_notifier_match { - struct regulator *regulator; - struct notifier_block *nb; -}; - -struct of_regulator_match { - const char *name; - void *driver_data; - struct regulator_init_data *init_data; - struct device_node *of_node; - const struct regulator_desc *desc; -}; - -struct devm_of_regulator_matches { - struct of_regulator_match *matches; - unsigned int num_matches; -}; - -struct fixed_voltage_data { - struct regulator_desc desc; - struct regulator_dev *dev; - struct clk *enable_clock; - unsigned int clk_enable_counter; -}; - -struct fixed_dev_type { - bool has_enable_clock; -}; - -struct gpio_regulator_state { - int value; - int gpios; -}; - -struct gpio_regulator_config { - const char *supply_name; - unsigned int enabled_at_boot: 1; - unsigned int startup_delay; - enum gpiod_flags *gflags; - int ngpios; - struct gpio_regulator_state *states; - int nr_states; - enum regulator_type type; - struct regulator_init_data *init_data; -}; - -struct gpio_regulator_data { - struct regulator_desc desc; - struct gpio_desc **gpiods; - int nr_gpios; - struct gpio_regulator_state *states; - int nr_states; - int state; -}; - -struct reset_control_lookup { - struct list_head list; - const char *provider; - unsigned int index; - const char *dev_id; - const char *con_id; -}; - -struct reset_control___2 { - struct reset_controller_dev *rcdev; - struct list_head list; - unsigned int id; - struct kref refcnt; - bool acquired; - bool shared; - bool array; - atomic_t deassert_count; - atomic_t triggered_count; -}; - -struct reset_control_array { - struct reset_control___2 base; - unsigned int num_rstcs; - struct reset_control___2 *rstc[0]; -}; - -struct rpi_reset { - struct reset_controller_dev rcdev; - struct rpi_firmware *fw; -}; - -struct reset_simple_devdata { - u32 reg_offset; - u32 nr_resets; - bool active_low; - bool status_active_low; -}; - -struct serial_struct32 { - compat_int_t type; - compat_int_t line; - compat_uint_t port; - compat_int_t irq; - compat_int_t flags; - compat_int_t xmit_fifo_size; - compat_int_t custom_divisor; - compat_int_t baud_base; - short unsigned int close_delay; - char io_type; - char reserved_char; - compat_int_t hub6; - short unsigned int closing_wait; - short unsigned int closing_wait2; - compat_uint_t iomem_base; - short unsigned int iomem_reg_shift; - unsigned int port_high; - compat_int_t reserved; -}; - -struct n_tty_data { - size_t read_head; - size_t commit_head; - size_t canon_head; - size_t echo_head; - size_t echo_commit; - size_t echo_mark; - long unsigned int char_map[4]; - long unsigned int overrun_time; - int num_overrun; - bool no_room; - unsigned char lnext: 1; - unsigned char erasing: 1; - unsigned char raw: 1; - unsigned char real_raw: 1; - unsigned char icanon: 1; - unsigned char push: 1; - char read_buf[4096]; - long unsigned int read_flags[64]; - unsigned char echo_buf[4096]; - size_t read_tail; - size_t line_start; - unsigned int column; - unsigned int canon_column; - size_t echo_tail; - struct mutex atomic_read_lock; - struct mutex output_lock; -}; - -enum { - ERASE = 0, - WERASE = 1, - KILL = 2, -}; - -struct termios { - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[19]; -}; - -struct termios2 { - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[19]; - speed_t c_ispeed; - speed_t c_ospeed; -}; - -struct termio { - short unsigned int c_iflag; - short unsigned int c_oflag; - short unsigned int c_cflag; - short unsigned int c_lflag; - unsigned char c_line; - unsigned char c_cc[8]; -}; - -struct ldsem_waiter { - struct list_head list; - struct task_struct *task; -}; - -struct pts_fs_info___2; - -struct tty_audit_buf { - struct mutex mutex; - dev_t dev; - unsigned int icanon: 1; - size_t valid; - unsigned char *data; -}; - -struct input_id { - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; -}; - -struct input_absinfo { - __s32 value; - __s32 minimum; - __s32 maximum; - __s32 fuzz; - __s32 flat; - __s32 resolution; -}; - -struct input_keymap_entry { - __u8 flags; - __u8 len; - __u16 index; - __u32 keycode; - __u8 scancode[32]; -}; - -struct ff_replay { - __u16 length; - __u16 delay; -}; - -struct ff_trigger { - __u16 button; - __u16 interval; -}; - -struct ff_envelope { - __u16 attack_length; - __u16 attack_level; - __u16 fade_length; - __u16 fade_level; -}; - -struct ff_constant_effect { - __s16 level; - struct ff_envelope envelope; -}; - -struct ff_ramp_effect { - __s16 start_level; - __s16 end_level; - struct ff_envelope envelope; -}; - -struct ff_condition_effect { - __u16 right_saturation; - __u16 left_saturation; - __s16 right_coeff; - __s16 left_coeff; - __u16 deadband; - __s16 center; -}; - -struct ff_periodic_effect { - __u16 waveform; - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; - struct ff_envelope envelope; - __u32 custom_len; - __s16 *custom_data; -}; - -struct ff_rumble_effect { - __u16 strong_magnitude; - __u16 weak_magnitude; -}; - -struct ff_effect { - __u16 type; - __s16 id; - __u16 direction; - struct ff_trigger trigger; - struct ff_replay replay; - union { - struct ff_constant_effect constant; - struct ff_ramp_effect ramp; - struct ff_periodic_effect periodic; - struct ff_condition_effect condition[2]; - struct ff_rumble_effect rumble; - } u; -}; - -struct input_device_id { - kernel_ulong_t flags; - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; - kernel_ulong_t evbit[1]; - kernel_ulong_t keybit[12]; - kernel_ulong_t relbit[1]; - kernel_ulong_t absbit[1]; - kernel_ulong_t mscbit[1]; - kernel_ulong_t ledbit[1]; - kernel_ulong_t sndbit[1]; - kernel_ulong_t ffbit[2]; - kernel_ulong_t swbit[1]; - kernel_ulong_t propbit[1]; - kernel_ulong_t driver_info; -}; - -struct input_value { - __u16 type; - __u16 code; - __s32 value; -}; - -enum input_clock_type { - INPUT_CLK_REAL = 0, - INPUT_CLK_MONO = 1, - INPUT_CLK_BOOT = 2, - INPUT_CLK_MAX = 3, -}; - -struct ff_device; - -struct input_dev_poller; - -struct input_mt; - -struct input_handle; - -struct input_dev { - const char *name; - const char *phys; - const char *uniq; - struct input_id id; - long unsigned int propbit[1]; - long unsigned int evbit[1]; - long unsigned int keybit[12]; - long unsigned int relbit[1]; - long unsigned int absbit[1]; - long unsigned int mscbit[1]; - long unsigned int ledbit[1]; - long unsigned int sndbit[1]; - long unsigned int ffbit[2]; - long unsigned int swbit[1]; - unsigned int hint_events_per_packet; - unsigned int keycodemax; - unsigned int keycodesize; - void *keycode; - int (*setkeycode)(struct input_dev *, const struct input_keymap_entry *, unsigned int *); - int (*getkeycode)(struct input_dev *, struct input_keymap_entry *); - struct ff_device *ff; - struct input_dev_poller *poller; - unsigned int repeat_key; - struct timer_list timer; - int rep[2]; - struct input_mt *mt; - struct input_absinfo *absinfo; - long unsigned int key[12]; - long unsigned int led[1]; - long unsigned int snd[1]; - long unsigned int sw[1]; - int (*open)(struct input_dev *); - void (*close)(struct input_dev *); - int (*flush)(struct input_dev *, struct file *); - int (*event)(struct input_dev *, unsigned int, unsigned int, int); - struct input_handle *grab; - spinlock_t event_lock; - struct mutex mutex; - unsigned int users; - bool going_away; - struct device dev; - struct list_head h_list; - struct list_head node; - unsigned int num_vals; - unsigned int max_vals; - struct input_value *vals; - bool devres_managed; - ktime_t timestamp[3]; -}; - -struct ff_device { - int (*upload)(struct input_dev *, struct ff_effect *, struct ff_effect *); - int (*erase)(struct input_dev *, int); - int (*playback)(struct input_dev *, int, int); - void (*set_gain)(struct input_dev *, u16); - void (*set_autocenter)(struct input_dev *, u16); - void (*destroy)(struct ff_device *); - void *private; - long unsigned int ffbit[2]; - struct mutex mutex; - int max_effects; - struct ff_effect *effects; - struct file *effect_owners[0]; -}; - -struct input_handler; - -struct input_handle { - void *private; - int open; - const char *name; - struct input_dev *dev; - struct input_handler *handler; - struct list_head d_node; - struct list_head h_node; -}; - -struct input_handler { - void *private; - void (*event)(struct input_handle *, unsigned int, unsigned int, int); - void (*events)(struct input_handle *, const struct input_value *, unsigned int); - bool (*filter)(struct input_handle *, unsigned int, unsigned int, int); - bool (*match)(struct input_handler *, struct input_dev *); - int (*connect)(struct input_handler *, struct input_dev *, const struct input_device_id *); - void (*disconnect)(struct input_handle *); - void (*start)(struct input_handle *); - bool legacy_minors; - int minor; - const char *name; - const struct input_device_id *id_table; - struct list_head h_list; - struct list_head node; -}; - -struct sysrq_state { - struct input_handle handle; - struct work_struct reinject_work; - long unsigned int key_down[12]; - unsigned int alt; - unsigned int alt_use; - unsigned int shift; - unsigned int shift_use; - bool active; - bool need_reinject; - bool reinjecting; - bool reset_canceled; - bool reset_requested; - long unsigned int reset_keybit[12]; - int reset_seq_len; - int reset_seq_cnt; - int reset_seq_version; - struct timer_list keyreset_timer; -}; - -struct consolefontdesc { - short unsigned int charcount; - short unsigned int charheight; - char *chardata; -}; - -struct unipair { - short unsigned int unicode; - short unsigned int fontpos; -}; - -struct unimapdesc { - short unsigned int entry_ct; - struct unipair *entries; -}; - -struct kbd_repeat { - int delay; - int period; -}; - -struct console_font_op { - unsigned int op; - unsigned int flags; - unsigned int width; - unsigned int height; - unsigned int charcount; - unsigned char *data; -}; - -struct vt_stat { - short unsigned int v_active; - short unsigned int v_signal; - short unsigned int v_state; -}; - -struct vt_sizes { - short unsigned int v_rows; - short unsigned int v_cols; - short unsigned int v_scrollsize; -}; - -struct vt_consize { - short unsigned int v_rows; - short unsigned int v_cols; - short unsigned int v_vlin; - short unsigned int v_clin; - short unsigned int v_vcol; - short unsigned int v_ccol; -}; - -struct vt_event { - unsigned int event; - unsigned int oldev; - unsigned int newev; - unsigned int pad[4]; -}; - -struct vt_setactivate { - unsigned int console; - struct vt_mode mode; -}; - -struct vt_spawn_console { - spinlock_t lock; - struct pid *pid; - int sig; -}; - -struct vt_event_wait { - struct list_head list; - struct vt_event event; - int done; -}; - -struct compat_consolefontdesc { - short unsigned int charcount; - short unsigned int charheight; - compat_caddr_t chardata; -}; - -struct compat_console_font_op { - compat_uint_t op; - compat_uint_t flags; - compat_uint_t width; - compat_uint_t height; - compat_uint_t charcount; - compat_caddr_t data; -}; - -struct compat_unimapdesc { - short unsigned int entry_ct; - compat_caddr_t entries; -}; - -struct vt_notifier_param { - struct vc_data *vc; - unsigned int c; -}; - -struct vcs_poll_data { - struct notifier_block notifier; - unsigned int cons_num; - int event; - wait_queue_head_t waitq; - struct fasync_struct *fasync; -}; - -struct tiocl_selection { - short unsigned int xs; - short unsigned int ys; - short unsigned int xe; - short unsigned int ye; - short unsigned int sel_mode; -}; - -struct vc_selection { - struct mutex lock; - struct vc_data *cons; - char *buffer; - unsigned int buf_len; - volatile int start; - int end; -}; - -enum led_brightness { - LED_OFF = 0, - LED_ON = 1, - LED_HALF = 127, - LED_FULL = 255, -}; - -struct led_hw_trigger_type { - int dummy; -}; - -struct led_pattern; - -struct led_trigger; - -struct led_classdev { - const char *name; - enum led_brightness brightness; - enum led_brightness max_brightness; - int flags; - long unsigned int work_flags; - void (*brightness_set)(struct led_classdev *, enum led_brightness); - int (*brightness_set_blocking)(struct led_classdev *, enum led_brightness); - enum led_brightness (*brightness_get)(struct led_classdev *); - int (*blink_set)(struct led_classdev *, long unsigned int *, long unsigned int *); - int (*pattern_set)(struct led_classdev *, struct led_pattern *, u32, int); - int (*pattern_clear)(struct led_classdev *); - struct device *dev; - const struct attribute_group **groups; - struct list_head node; - const char *default_trigger; - long unsigned int blink_delay_on; - long unsigned int blink_delay_off; - struct timer_list blink_timer; - int blink_brightness; - int new_blink_brightness; - void (*flash_resume)(struct led_classdev *); - struct work_struct set_brightness_work; - int delayed_set_value; - struct rw_semaphore trigger_lock; - struct led_trigger *trigger; - struct list_head trig_list; - void *trigger_data; - bool activated; - struct led_hw_trigger_type *trigger_type; - struct mutex led_access; -}; - -struct led_pattern { - u32 delta_t; - int brightness; -}; - -struct led_trigger { - const char *name; - int (*activate)(struct led_classdev *); - void (*deactivate)(struct led_classdev *); - struct led_hw_trigger_type *trigger_type; - rwlock_t leddev_list_lock; - struct list_head led_cdevs; - struct list_head next_trig; - const struct attribute_group **groups; -}; - -struct keyboard_notifier_param { - struct vc_data *vc; - int down; - int shift; - int ledstate; - unsigned int value; -}; - -struct kbd_struct { - unsigned char lockstate; - unsigned char slockstate; - unsigned char ledmode: 1; - unsigned char ledflagstate: 4; - char: 3; - unsigned char default_ledflagstate: 4; - unsigned char kbdmode: 3; - char: 1; - unsigned char modeflags: 5; -}; - -struct kbentry { - unsigned char kb_table; - unsigned char kb_index; - short unsigned int kb_value; -}; - -struct kbsentry { - unsigned char kb_func; - unsigned char kb_string[512]; -}; - -struct kbdiacr { - unsigned char diacr; - unsigned char base; - unsigned char result; -}; - -struct kbdiacrs { - unsigned int kb_cnt; - struct kbdiacr kbdiacr[256]; -}; - -struct kbdiacruc { - unsigned int diacr; - unsigned int base; - unsigned int result; -}; - -struct kbdiacrsuc { - unsigned int kb_cnt; - struct kbdiacruc kbdiacruc[256]; -}; - -struct kbkeycode { - unsigned int scancode; - unsigned int keycode; -}; - -typedef void k_handler_fn(struct vc_data *, unsigned char, char); - -typedef void fn_handler_fn(struct vc_data *); - -struct getset_keycode_data { - struct input_keymap_entry ke; - int error; -}; - -struct kbd_led_trigger { - struct led_trigger trigger; - unsigned int mask; -}; - -struct uni_pagedir { - u16 **uni_pgdir[32]; - long unsigned int refcount; - long unsigned int sum; - unsigned char *inverse_translations[4]; - u16 *inverse_trans_unicode; -}; - -typedef uint32_t char32_t; - -struct uni_screen { - char32_t *lines[0]; -}; - -struct con_driver { - const struct consw *con; - const char *desc; - struct device *dev; - int node; - int first; - int last; - int flag; -}; - -enum { - blank_off = 0, - blank_normal_wait = 1, - blank_vesa_wait = 2, -}; - -enum { - EPecma = 0, - EPdec = 1, - EPeq = 2, - EPgt = 3, - EPlt = 4, -}; - -struct rgb { - u8 r; - u8 g; - u8 b; -}; - -enum { - ESnormal = 0, - ESesc = 1, - ESsquare = 2, - ESgetpars = 3, - ESfunckey = 4, - EShash = 5, - ESsetG0 = 6, - ESsetG1 = 7, - ESpercent = 8, - EScsiignore = 9, - ESnonstd = 10, - ESpalette = 11, - ESosc = 12, - ESapc = 13, - ESpm = 14, - ESdcs = 15, -}; - -struct interval { - uint32_t first; - uint32_t last; -}; - -struct vc_draw_region { - long unsigned int from; - long unsigned int to; - int x; -}; - -struct serial_rs485 { - __u32 flags; - __u32 delay_rts_before_send; - __u32 delay_rts_after_send; - __u32 padding[5]; -}; - -struct serial_iso7816 { - __u32 flags; - __u32 tg; - __u32 sc_fi; - __u32 sc_di; - __u32 clk; - __u32 reserved[5]; -}; - -struct circ_buf { - char *buf; - int head; - int tail; -}; - -struct uart_port; - -struct uart_ops { - unsigned int (*tx_empty)(struct uart_port *); - void (*set_mctrl)(struct uart_port *, unsigned int); - unsigned int (*get_mctrl)(struct uart_port *); - void (*stop_tx)(struct uart_port *); - void (*start_tx)(struct uart_port *); - void (*throttle)(struct uart_port *); - void (*unthrottle)(struct uart_port *); - void (*send_xchar)(struct uart_port *, char); - void (*stop_rx)(struct uart_port *); - void (*enable_ms)(struct uart_port *); - void (*break_ctl)(struct uart_port *, int); - int (*startup)(struct uart_port *); - void (*shutdown)(struct uart_port *); - void (*flush_buffer)(struct uart_port *); - void (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *); - void (*set_ldisc)(struct uart_port *, struct ktermios *); - void (*pm)(struct uart_port *, unsigned int, unsigned int); - const char * (*type)(struct uart_port *); - void (*release_port)(struct uart_port *); - int (*request_port)(struct uart_port *); - void (*config_port)(struct uart_port *, int); - int (*verify_port)(struct uart_port *, struct serial_struct *); - int (*ioctl)(struct uart_port *, unsigned int, long unsigned int); - int (*poll_init)(struct uart_port *); - void (*poll_put_char)(struct uart_port *, unsigned char); - int (*poll_get_char)(struct uart_port *); -}; - -struct uart_icount { - __u32 cts; - __u32 dsr; - __u32 rng; - __u32 dcd; - __u32 rx; - __u32 tx; - __u32 frame; - __u32 overrun; - __u32 parity; - __u32 brk; - __u32 buf_overrun; -}; - -typedef unsigned int upf_t; - -typedef unsigned int upstat_t; - -struct uart_state; - -struct uart_port { - spinlock_t lock; - long unsigned int iobase; - unsigned char *membase; - unsigned int (*serial_in)(struct uart_port *, int); - void (*serial_out)(struct uart_port *, int, int); - void (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *); - void (*set_ldisc)(struct uart_port *, struct ktermios *); - unsigned int (*get_mctrl)(struct uart_port *); - void (*set_mctrl)(struct uart_port *, unsigned int); - unsigned int (*get_divisor)(struct uart_port *, unsigned int, unsigned int *); - void (*set_divisor)(struct uart_port *, unsigned int, unsigned int, unsigned int); - int (*startup)(struct uart_port *); - void (*shutdown)(struct uart_port *); - void (*throttle)(struct uart_port *); - void (*unthrottle)(struct uart_port *); - int (*handle_irq)(struct uart_port *); - void (*pm)(struct uart_port *, unsigned int, unsigned int); - void (*handle_break)(struct uart_port *); - int (*rs485_config)(struct uart_port *, struct serial_rs485 *); - int (*iso7816_config)(struct uart_port *, struct serial_iso7816 *); - unsigned int irq; - long unsigned int irqflags; - unsigned int uartclk; - unsigned int fifosize; - unsigned char x_char; - unsigned char regshift; - unsigned char iotype; - unsigned char quirks; - unsigned int read_status_mask; - unsigned int ignore_status_mask; - struct uart_state *state; - struct uart_icount icount; - struct console *cons; - upf_t flags; - upstat_t status; - int hw_stopped; - unsigned int mctrl; - unsigned int timeout; - unsigned int type; - const struct uart_ops *ops; - unsigned int custom_divisor; - unsigned int line; - unsigned int minor; - resource_size_t mapbase; - resource_size_t mapsize; - struct device *dev; - long unsigned int sysrq; - unsigned int sysrq_ch; - unsigned char has_sysrq; - unsigned char sysrq_seq; - unsigned char hub6; - unsigned char suspended; - unsigned char console_reinit; - const char *name; - struct attribute_group *attr_group; - const struct attribute_group **tty_groups; - struct serial_rs485 rs485; - struct gpio_desc *rs485_term_gpio; - struct serial_iso7816 iso7816; - void *private_data; -}; - -enum uart_pm_state { - UART_PM_STATE_ON = 0, - UART_PM_STATE_OFF = 3, - UART_PM_STATE_UNDEFINED = 4, -}; - -struct uart_state { - struct tty_port port; - enum uart_pm_state pm_state; - struct circ_buf xmit; - atomic_t refcount; - wait_queue_head_t remove_wait; - struct uart_port *uart_port; -}; - -struct uart_driver { - struct module *owner; - const char *driver_name; - const char *dev_name; - int major; - int minor; - int nr; - struct console *cons; - struct uart_state *state; - struct tty_driver *tty_driver; -}; - -struct uart_match { - struct uart_port *port; - struct uart_driver *driver; -}; - -struct earlycon_device { - struct console *con; - struct uart_port port; - char options[16]; - unsigned int baud; -}; - -struct earlycon_id { - char name[15]; - char name_term; - char compatible[128]; - int (*setup)(struct earlycon_device *, const char *); -}; - -enum hwparam_type { - hwparam_ioport = 0, - hwparam_iomem = 1, - hwparam_ioport_or_iomem = 2, - hwparam_irq = 3, - hwparam_dma = 4, - hwparam_dma_addr = 5, - hwparam_other = 6, -}; - -struct plat_serial8250_port { - long unsigned int iobase; - void *membase; - resource_size_t mapbase; - unsigned int irq; - long unsigned int irqflags; - unsigned int uartclk; - void *private_data; - unsigned char regshift; - unsigned char iotype; - unsigned char hub6; - unsigned char has_sysrq; - upf_t flags; - unsigned int type; - unsigned int (*serial_in)(struct uart_port *, int); - void (*serial_out)(struct uart_port *, int, int); - void (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *); - void (*set_ldisc)(struct uart_port *, struct ktermios *); - unsigned int (*get_mctrl)(struct uart_port *); - int (*handle_irq)(struct uart_port *); - void (*pm)(struct uart_port *, unsigned int, unsigned int); - void (*handle_break)(struct uart_port *); -}; - -enum { - PLAT8250_DEV_LEGACY = 4294967295, - PLAT8250_DEV_PLATFORM = 0, - PLAT8250_DEV_PLATFORM1 = 1, - PLAT8250_DEV_PLATFORM2 = 2, - PLAT8250_DEV_FOURPORT = 3, - PLAT8250_DEV_ACCENT = 4, - PLAT8250_DEV_BOCA = 5, - PLAT8250_DEV_EXAR_ST16C554 = 6, - PLAT8250_DEV_HUB6 = 7, - PLAT8250_DEV_AU1X00 = 8, - PLAT8250_DEV_SM501 = 9, -}; - -struct uart_8250_port; - -struct uart_8250_ops { - int (*setup_irq)(struct uart_8250_port *); - void (*release_irq)(struct uart_8250_port *); -}; - -struct mctrl_gpios; - -struct uart_8250_dma; - -struct uart_8250_em485; - -struct uart_8250_port { - struct uart_port port; - struct timer_list timer; - struct list_head list; - u32 capabilities; - short unsigned int bugs; - bool fifo_bug; - unsigned int tx_loadsz; - unsigned char acr; - unsigned char fcr; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned char mcr_mask; - unsigned char mcr_force; - unsigned char cur_iotype; - unsigned int rpm_tx_active; - unsigned char canary; - unsigned char probe; - struct mctrl_gpios *gpios; - unsigned char lsr_saved_flags; - unsigned char msr_saved_flags; - struct uart_8250_dma *dma; - const struct uart_8250_ops *ops; - int (*dl_read)(struct uart_8250_port *); - void (*dl_write)(struct uart_8250_port *, int); - struct uart_8250_em485 *em485; - void (*rs485_start_tx)(struct uart_8250_port *); - void (*rs485_stop_tx)(struct uart_8250_port *); - struct delayed_work overrun_backoff; - u32 overrun_backoff_time_ms; -}; - -struct uart_8250_em485 { - struct hrtimer start_tx_timer; - struct hrtimer stop_tx_timer; - struct hrtimer *active_timer; - struct uart_8250_port *port; - unsigned int tx_stopped: 1; -}; - -struct uart_8250_dma { - int (*tx_dma)(struct uart_8250_port *); - int (*rx_dma)(struct uart_8250_port *); - dma_filter_fn fn; - void *rx_param; - void *tx_param; - struct dma_slave_config rxconf; - struct dma_slave_config txconf; - struct dma_chan *rxchan; - struct dma_chan *txchan; - phys_addr_t rx_dma_addr; - phys_addr_t tx_dma_addr; - dma_addr_t rx_addr; - dma_addr_t tx_addr; - dma_cookie_t rx_cookie; - dma_cookie_t tx_cookie; - void *rx_buf; - size_t rx_size; - size_t tx_size; - unsigned char tx_running; - unsigned char tx_err; - unsigned char rx_running; -}; - -struct old_serial_port { - unsigned int uart; - unsigned int baud_base; - unsigned int port; - unsigned int irq; - upf_t flags; - unsigned char io_type; - unsigned char *iomem_base; - short unsigned int iomem_reg_shift; -}; - -struct irq_info { - struct hlist_node node; - int irq; - spinlock_t lock; - struct list_head *head; -}; - -struct serial8250_config { - const char *name; - short unsigned int fifo_size; - short unsigned int tx_loadsz; - unsigned char fcr; - unsigned char rxtrig_bytes[4]; - unsigned int flags; -}; - -enum pci_ers_result { - PCI_ERS_RESULT_NONE = 1, - PCI_ERS_RESULT_CAN_RECOVER = 2, - PCI_ERS_RESULT_NEED_RESET = 3, - PCI_ERS_RESULT_DISCONNECT = 4, - PCI_ERS_RESULT_RECOVERED = 5, - PCI_ERS_RESULT_NO_AER_DRIVER = 6, -}; - -struct pciserial_board { - unsigned int flags; - unsigned int num_ports; - unsigned int base_baud; - unsigned int uart_offset; - unsigned int reg_shift; - unsigned int first_offset; -}; - -struct serial_private; - -struct pci_serial_quirk { - u32 vendor; - u32 device; - u32 subvendor; - u32 subdevice; - int (*probe)(struct pci_dev *); - int (*init)(struct pci_dev *); - int (*setup)(struct serial_private *, const struct pciserial_board *, struct uart_8250_port *, int); - void (*exit)(struct pci_dev *); -}; - -struct serial_private { - struct pci_dev *dev; - unsigned int nr; - struct pci_serial_quirk *quirk; - const struct pciserial_board *board; - int line[0]; -}; - -struct f815xxa_data { - spinlock_t lock; - int idx; -}; - -struct timedia_struct { - int num; - const short unsigned int *ids; -}; - -struct quatech_feature { - u16 devid; - bool amcc; -}; - -enum pci_board_num_t { - pbn_default = 0, - pbn_b0_1_115200 = 1, - pbn_b0_2_115200 = 2, - pbn_b0_4_115200 = 3, - pbn_b0_5_115200 = 4, - pbn_b0_8_115200 = 5, - pbn_b0_1_921600 = 6, - pbn_b0_2_921600 = 7, - pbn_b0_4_921600 = 8, - pbn_b0_2_1130000 = 9, - pbn_b0_4_1152000 = 10, - pbn_b0_4_1250000 = 11, - pbn_b0_2_1843200 = 12, - pbn_b0_4_1843200 = 13, - pbn_b0_1_4000000 = 14, - pbn_b0_bt_1_115200 = 15, - pbn_b0_bt_2_115200 = 16, - pbn_b0_bt_4_115200 = 17, - pbn_b0_bt_8_115200 = 18, - pbn_b0_bt_1_460800 = 19, - pbn_b0_bt_2_460800 = 20, - pbn_b0_bt_4_460800 = 21, - pbn_b0_bt_1_921600 = 22, - pbn_b0_bt_2_921600 = 23, - pbn_b0_bt_4_921600 = 24, - pbn_b0_bt_8_921600 = 25, - pbn_b1_1_115200 = 26, - pbn_b1_2_115200 = 27, - pbn_b1_4_115200 = 28, - pbn_b1_8_115200 = 29, - pbn_b1_16_115200 = 30, - pbn_b1_1_921600 = 31, - pbn_b1_2_921600 = 32, - pbn_b1_4_921600 = 33, - pbn_b1_8_921600 = 34, - pbn_b1_2_1250000 = 35, - pbn_b1_bt_1_115200 = 36, - pbn_b1_bt_2_115200 = 37, - pbn_b1_bt_4_115200 = 38, - pbn_b1_bt_2_921600 = 39, - pbn_b1_1_1382400 = 40, - pbn_b1_2_1382400 = 41, - pbn_b1_4_1382400 = 42, - pbn_b1_8_1382400 = 43, - pbn_b2_1_115200 = 44, - pbn_b2_2_115200 = 45, - pbn_b2_4_115200 = 46, - pbn_b2_8_115200 = 47, - pbn_b2_1_460800 = 48, - pbn_b2_4_460800 = 49, - pbn_b2_8_460800 = 50, - pbn_b2_16_460800 = 51, - pbn_b2_1_921600 = 52, - pbn_b2_4_921600 = 53, - pbn_b2_8_921600 = 54, - pbn_b2_8_1152000 = 55, - pbn_b2_bt_1_115200 = 56, - pbn_b2_bt_2_115200 = 57, - pbn_b2_bt_4_115200 = 58, - pbn_b2_bt_2_921600 = 59, - pbn_b2_bt_4_921600 = 60, - pbn_b3_2_115200 = 61, - pbn_b3_4_115200 = 62, - pbn_b3_8_115200 = 63, - pbn_b4_bt_2_921600 = 64, - pbn_b4_bt_4_921600 = 65, - pbn_b4_bt_8_921600 = 66, - pbn_panacom = 67, - pbn_panacom2 = 68, - pbn_panacom4 = 69, - pbn_plx_romulus = 70, - pbn_endrun_2_4000000 = 71, - pbn_oxsemi = 72, - pbn_oxsemi_1_4000000 = 73, - pbn_oxsemi_2_4000000 = 74, - pbn_oxsemi_4_4000000 = 75, - pbn_oxsemi_8_4000000 = 76, - pbn_intel_i960 = 77, - pbn_sgi_ioc3 = 78, - pbn_computone_4 = 79, - pbn_computone_6 = 80, - pbn_computone_8 = 81, - pbn_sbsxrsio = 82, - pbn_pasemi_1682M = 83, - pbn_ni8430_2 = 84, - pbn_ni8430_4 = 85, - pbn_ni8430_8 = 86, - pbn_ni8430_16 = 87, - pbn_ADDIDATA_PCIe_1_3906250 = 88, - pbn_ADDIDATA_PCIe_2_3906250 = 89, - pbn_ADDIDATA_PCIe_4_3906250 = 90, - pbn_ADDIDATA_PCIe_8_3906250 = 91, - pbn_ce4100_1_115200 = 92, - pbn_omegapci = 93, - pbn_NETMOS9900_2s_115200 = 94, - pbn_brcm_trumanage = 95, - pbn_fintek_4 = 96, - pbn_fintek_8 = 97, - pbn_fintek_12 = 98, - pbn_fintek_F81504A = 99, - pbn_fintek_F81508A = 100, - pbn_fintek_F81512A = 101, - pbn_wch382_2 = 102, - pbn_wch384_4 = 103, - pbn_wch384_8 = 104, - pbn_pericom_PI7C9X7951 = 105, - pbn_pericom_PI7C9X7952 = 106, - pbn_pericom_PI7C9X7954 = 107, - pbn_pericom_PI7C9X7958 = 108, - pbn_sunix_pci_1s = 109, - pbn_sunix_pci_2s = 110, - pbn_sunix_pci_4s = 111, - pbn_sunix_pci_8s = 112, - pbn_sunix_pci_16s = 113, - pbn_moxa8250_2p = 114, - pbn_moxa8250_4p = 115, - pbn_moxa8250_8p = 116, -}; - -struct exar8250_platform { - int (*rs485_config)(struct uart_port *, struct serial_rs485 *); - int (*register_gpio)(struct pci_dev *, struct uart_8250_port *); -}; - -struct exar8250; - -struct exar8250_board { - unsigned int num_ports; - unsigned int reg_shift; - int (*setup)(struct exar8250 *, struct pci_dev *, struct uart_8250_port *, int); - void (*exit)(struct pci_dev *); -}; - -struct exar8250 { - unsigned int nr; - struct exar8250_board *board; - void *virt; - int line[0]; -}; - -struct bcm2835aux_data { - struct clk *clk; - int line; - u32 cntl; -}; - -struct of_serial_info { - struct clk *clk; - struct reset_control *rst; - int type; - int line; -}; - -enum amba_vendor { - AMBA_VENDOR_ARM = 65, - AMBA_VENDOR_ST = 128, - AMBA_VENDOR_QCOM = 81, - AMBA_VENDOR_LSI = 182, - AMBA_VENDOR_LINUX = 254, -}; - -struct amba_pl011_data { - bool (*dma_filter)(struct dma_chan *, void *); - void *dma_rx_param; - void *dma_tx_param; - bool dma_rx_poll_enable; - unsigned int dma_rx_poll_rate; - unsigned int dma_rx_poll_timeout; - void (*init)(); - void (*exit)(); -}; - -enum { - REG_DR = 0, - REG_ST_DMAWM = 1, - REG_ST_TIMEOUT = 2, - REG_FR = 3, - REG_LCRH_RX = 4, - REG_LCRH_TX = 5, - REG_IBRD = 6, - REG_FBRD = 7, - REG_CR = 8, - REG_IFLS = 9, - REG_IMSC = 10, - REG_RIS = 11, - REG_MIS = 12, - REG_ICR = 13, - REG_DMACR = 14, - REG_ST_XFCR = 15, - REG_ST_XON1 = 16, - REG_ST_XON2 = 17, - REG_ST_XOFF1 = 18, - REG_ST_XOFF2 = 19, - REG_ST_ITCR = 20, - REG_ST_ITIP = 21, - REG_ST_ABCR = 22, - REG_ST_ABIMSC = 23, - REG_ARRAY_SIZE = 24, -}; - -struct vendor_data { - const u16 *reg_offset; - unsigned int ifls; - unsigned int fr_busy; - unsigned int fr_dsr; - unsigned int fr_cts; - unsigned int fr_ri; - unsigned int inv_fr; - bool access_32b; - bool oversampling; - bool dma_threshold; - bool cts_event_workaround; - bool always_enabled; - bool fixed_options; - unsigned int (*get_fifosize)(struct amba_device *); -}; - -struct pl011_sgbuf { - struct scatterlist sg; - char *buf; -}; - -struct pl011_dmarx_data { - struct dma_chan *chan; - struct completion complete; - bool use_buf_b; - struct pl011_sgbuf sgbuf_a; - struct pl011_sgbuf sgbuf_b; - dma_cookie_t cookie; - bool running; - struct timer_list timer; - unsigned int last_residue; - long unsigned int last_jiffies; - bool auto_poll_rate; - unsigned int poll_rate; - unsigned int poll_timeout; -}; - -struct pl011_dmatx_data { - struct dma_chan *chan; - struct scatterlist sg; - char *buf; - bool queued; -}; - -struct uart_amba_port { - struct uart_port port; - const u16 *reg_offset; - struct clk *clk; - const struct vendor_data *vendor; - unsigned int dmacr; - unsigned int im; - unsigned int old_status; - unsigned int fifosize; - unsigned int old_cr; - unsigned int fixed_baud; - char type[12]; - bool irq_locked; - bool using_tx_dma; - bool using_rx_dma; - struct pl011_dmarx_data dmarx; - struct pl011_dmatx_data dmatx; - bool dma_probed; -}; - -enum mctrl_gpio_idx { - UART_GPIO_CTS = 0, - UART_GPIO_DSR = 1, - UART_GPIO_DCD = 2, - UART_GPIO_RNG = 3, - UART_GPIO_RI = 3, - UART_GPIO_RTS = 4, - UART_GPIO_DTR = 5, - UART_GPIO_MAX = 6, -}; - -struct mctrl_gpios___2 { - struct uart_port *port; - struct gpio_desc *gpio[6]; - int irq[6]; - unsigned int mctrl_prev; - bool mctrl_on; -}; - -struct serdev_device; - -struct serdev_device_ops { - int (*receive_buf)(struct serdev_device *, const unsigned char *, size_t); - void (*write_wakeup)(struct serdev_device *); -}; - -struct serdev_controller; - -struct serdev_device { - struct device dev; - int nr; - struct serdev_controller *ctrl; - const struct serdev_device_ops *ops; - struct completion write_comp; - struct mutex write_lock; -}; - -struct serdev_controller_ops; - -struct serdev_controller { - struct device dev; - unsigned int nr; - struct serdev_device *serdev; - const struct serdev_controller_ops *ops; -}; - -struct serdev_device_driver { - struct device_driver driver; - int (*probe)(struct serdev_device *); - void (*remove)(struct serdev_device *); -}; - -enum serdev_parity { - SERDEV_PARITY_NONE = 0, - SERDEV_PARITY_EVEN = 1, - SERDEV_PARITY_ODD = 2, -}; - -struct serdev_controller_ops { - int (*write_buf)(struct serdev_controller *, const unsigned char *, size_t); - void (*write_flush)(struct serdev_controller *); - int (*write_room)(struct serdev_controller *); - int (*open)(struct serdev_controller *); - void (*close)(struct serdev_controller *); - void (*set_flow_control)(struct serdev_controller *, bool); - int (*set_parity)(struct serdev_controller *, enum serdev_parity); - unsigned int (*set_baudrate)(struct serdev_controller *, unsigned int); - void (*wait_until_sent)(struct serdev_controller *, long int); - int (*get_tiocm)(struct serdev_controller *); - int (*set_tiocm)(struct serdev_controller *, unsigned int, unsigned int); -}; - -struct serport { - struct tty_port *port; - struct tty_struct *tty; - struct tty_driver *tty_drv; - int tty_idx; - long unsigned int flags; -}; - -struct memdev { - const char *name; - umode_t mode; - const struct file_operations *fops; - fmode_t fmode; -}; - -struct timer_rand_state { - cycles_t last_time; - long int last_delta; - long int last_delta2; -}; - -struct trace_event_raw_add_device_randomness { - struct trace_entry ent; - int bytes; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_random__mix_pool_bytes { - struct trace_entry ent; - const char *pool_name; - int bytes; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_credit_entropy_bits { - struct trace_entry ent; - const char *pool_name; - int bits; - int entropy_count; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_push_to_pool { - struct trace_entry ent; - const char *pool_name; - int pool_bits; - int input_bits; - char __data[0]; -}; - -struct trace_event_raw_debit_entropy { - struct trace_entry ent; - const char *pool_name; - int debit_bits; - char __data[0]; -}; - -struct trace_event_raw_add_input_randomness { - struct trace_entry ent; - int input_bits; - char __data[0]; -}; - -struct trace_event_raw_add_disk_randomness { - struct trace_entry ent; - dev_t dev; - int input_bits; - char __data[0]; -}; - -struct trace_event_raw_xfer_secondary_pool { - struct trace_entry ent; - const char *pool_name; - int xfer_bits; - int request_bits; - int pool_entropy; - int input_entropy; - char __data[0]; -}; - -struct trace_event_raw_random__get_random_bytes { - struct trace_entry ent; - int nbytes; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_random__extract_entropy { - struct trace_entry ent; - const char *pool_name; - int nbytes; - int entropy_count; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_random_read { - struct trace_entry ent; - int got_bits; - int need_bits; - int pool_left; - int input_left; - char __data[0]; -}; - -struct trace_event_raw_urandom_read { - struct trace_entry ent; - int got_bits; - int pool_left; - int input_left; - char __data[0]; -}; - -struct trace_event_raw_prandom_u32 { - struct trace_entry ent; - unsigned int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_add_device_randomness {}; - -struct trace_event_data_offsets_random__mix_pool_bytes {}; - -struct trace_event_data_offsets_credit_entropy_bits {}; - -struct trace_event_data_offsets_push_to_pool {}; - -struct trace_event_data_offsets_debit_entropy {}; - -struct trace_event_data_offsets_add_input_randomness {}; - -struct trace_event_data_offsets_add_disk_randomness {}; - -struct trace_event_data_offsets_xfer_secondary_pool {}; - -struct trace_event_data_offsets_random__get_random_bytes {}; - -struct trace_event_data_offsets_random__extract_entropy {}; - -struct trace_event_data_offsets_random_read {}; - -struct trace_event_data_offsets_urandom_read {}; - -struct trace_event_data_offsets_prandom_u32 {}; - -typedef void (*btf_trace_add_device_randomness)(void *, int, long unsigned int); - -typedef void (*btf_trace_mix_pool_bytes)(void *, const char *, int, long unsigned int); - -typedef void (*btf_trace_mix_pool_bytes_nolock)(void *, const char *, int, long unsigned int); - -typedef void (*btf_trace_credit_entropy_bits)(void *, const char *, int, int, long unsigned int); - -typedef void (*btf_trace_push_to_pool)(void *, const char *, int, int); - -typedef void (*btf_trace_debit_entropy)(void *, const char *, int); - -typedef void (*btf_trace_add_input_randomness)(void *, int); - -typedef void (*btf_trace_add_disk_randomness)(void *, dev_t, int); - -typedef void (*btf_trace_xfer_secondary_pool)(void *, const char *, int, int, int, int); - -typedef void (*btf_trace_get_random_bytes)(void *, int, long unsigned int); - -typedef void (*btf_trace_get_random_bytes_arch)(void *, int, long unsigned int); - -typedef void (*btf_trace_extract_entropy)(void *, const char *, int, int, long unsigned int); - -typedef void (*btf_trace_extract_entropy_user)(void *, const char *, int, int, long unsigned int); - -typedef void (*btf_trace_random_read)(void *, int, int, int, int); - -typedef void (*btf_trace_urandom_read)(void *, int, int, int); - -typedef void (*btf_trace_prandom_u32)(void *, unsigned int); - -struct poolinfo { - int poolbitshift; - int poolwords; - int poolbytes; - int poolfracbits; - int tap1; - int tap2; - int tap3; - int tap4; - int tap5; -}; - -struct crng_state { - __u32 state[16]; - long unsigned int init_time; - spinlock_t lock; -}; - -struct entropy_store { - const struct poolinfo *poolinfo; - __u32 *pool; - const char *name; - spinlock_t lock; - short unsigned int add_ptr; - short unsigned int input_rotate; - int entropy_count; - unsigned int initialized: 1; - unsigned int last_data_init: 1; - __u8 last_data[10]; -}; - -struct fast_pool { - __u32 pool[4]; - long unsigned int last; - short unsigned int reg_idx; - unsigned char count; -}; - -struct batched_entropy { - union { - u64 entropy_u64[8]; - u32 entropy_u32[16]; - }; - unsigned int position; - spinlock_t batch_lock; -}; - -struct ttyprintk_port { - struct tty_port port; - spinlock_t spinlock; -}; - -struct raw_config_request { - int raw_minor; - __u64 block_major; - __u64 block_minor; -}; - -struct raw_device_data { - dev_t binding; - struct block_device *bdev; - int inuse; -}; - -struct raw32_config_request { - compat_int_t raw_minor; - compat_u64 block_major; - compat_u64 block_minor; -}; - -struct hwrng { - const char *name; - int (*init)(struct hwrng *); - void (*cleanup)(struct hwrng *); - int (*data_present)(struct hwrng *, int); - int (*data_read)(struct hwrng *, u32 *); - int (*read)(struct hwrng *, void *, size_t, bool); - long unsigned int priv; - short unsigned int quality; - struct list_head list; - struct kref ref; - struct completion cleanup_done; -}; - -struct bcm2835_rng_priv { - struct hwrng rng; - void *base; - bool mask_interrupts; - struct clk *clk; -}; - -struct bcm2835_rng_of_data { - bool mask_interrupts; -}; - -struct iproc_rng200_dev { - struct hwrng rng; - void *base; -}; - -struct cavium_rng_pf { - void *control_status; -}; - -struct cavium_rng { - struct hwrng ops; - void *result; -}; - -enum rpi_firmware_property_status { - RPI_FIRMWARE_STATUS_REQUEST = 0, - RPI_FIRMWARE_STATUS_SUCCESS = 2147483648, - RPI_FIRMWARE_STATUS_ERROR = 2147483649, -}; - -struct vcio_data { - struct rpi_firmware *fw; - struct miscdevice misc_dev; -}; - -struct bcm2835_gpiomem_instance { - long unsigned int gpio_regs_phys; - struct device *dev; -}; - -struct mipi_dsi_msg { - u8 channel; - u8 type; - u16 flags; - size_t tx_len; - const void *tx_buf; - size_t rx_len; - void *rx_buf; -}; - -struct mipi_dsi_packet { - size_t size; - u8 header[4]; - size_t payload_length; - const u8 *payload; -}; - -struct mipi_dsi_host; - -struct mipi_dsi_device; - -struct mipi_dsi_host_ops { - int (*attach)(struct mipi_dsi_host *, struct mipi_dsi_device *); - int (*detach)(struct mipi_dsi_host *, struct mipi_dsi_device *); - ssize_t (*transfer)(struct mipi_dsi_host *, const struct mipi_dsi_msg *); -}; - -struct mipi_dsi_host { - struct device *dev; - const struct mipi_dsi_host_ops *ops; - struct list_head list; -}; - -enum mipi_dsi_pixel_format { - MIPI_DSI_FMT_RGB888 = 0, - MIPI_DSI_FMT_RGB666 = 1, - MIPI_DSI_FMT_RGB666_PACKED = 2, - MIPI_DSI_FMT_RGB565 = 3, -}; - -struct mipi_dsi_device { - struct mipi_dsi_host *host; - struct device dev; - char name[20]; - unsigned int channel; - unsigned int lanes; - enum mipi_dsi_pixel_format format; - long unsigned int mode_flags; - long unsigned int hs_rate; - long unsigned int lp_rate; -}; - -struct mipi_dsi_device_info { - char type[20]; - u32 channel; - struct device_node *node; -}; - -enum mipi_dsi_dcs_tear_mode { - MIPI_DSI_DCS_TEAR_MODE_VBLANK = 0, - MIPI_DSI_DCS_TEAR_MODE_VHBLANK = 1, -}; - -struct mipi_dsi_driver { - struct device_driver driver; - int (*probe)(struct mipi_dsi_device *); - int (*remove)(struct mipi_dsi_device *); - void (*shutdown)(struct mipi_dsi_device *); -}; - -struct drm_dsc_picture_parameter_set { - u8 dsc_version; - u8 pps_identifier; - u8 pps_reserved; - u8 pps_3; - u8 pps_4; - u8 bits_per_pixel_low; - __be16 pic_height; - __be16 pic_width; - __be16 slice_height; - __be16 slice_width; - __be16 chunk_size; - u8 initial_xmit_delay_high; - u8 initial_xmit_delay_low; - __be16 initial_dec_delay; - u8 pps20_reserved; - u8 initial_scale_value; - __be16 scale_increment_interval; - u8 scale_decrement_interval_high; - u8 scale_decrement_interval_low; - u8 pps26_reserved; - u8 first_line_bpg_offset; - __be16 nfl_bpg_offset; - __be16 slice_bpg_offset; - __be16 initial_offset; - __be16 final_offset; - u8 flatness_min_qp; - u8 flatness_max_qp; - __be16 rc_model_size; - u8 rc_edge_factor; - u8 rc_quant_incr_limit0; - u8 rc_quant_incr_limit1; - u8 rc_tgt_offset; - u8 rc_buf_thresh[14]; - __be16 rc_range_parameters[15]; - u8 native_422_420; - u8 second_line_bpg_offset; - __be16 nsl_bpg_offset; - __be16 second_line_offset_adj; - u32 pps_long_94_reserved; - u32 pps_long_98_reserved; - u32 pps_long_102_reserved; - u32 pps_long_106_reserved; - u32 pps_long_110_reserved; - u32 pps_long_114_reserved; - u32 pps_long_118_reserved; - u32 pps_long_122_reserved; - __be16 pps_short_126_reserved; -} __attribute__((packed)); - -enum { - MIPI_DSI_V_SYNC_START = 1, - MIPI_DSI_V_SYNC_END = 17, - MIPI_DSI_H_SYNC_START = 33, - MIPI_DSI_H_SYNC_END = 49, - MIPI_DSI_COMPRESSION_MODE = 7, - MIPI_DSI_END_OF_TRANSMISSION = 8, - MIPI_DSI_COLOR_MODE_OFF = 2, - MIPI_DSI_COLOR_MODE_ON = 18, - MIPI_DSI_SHUTDOWN_PERIPHERAL = 34, - MIPI_DSI_TURN_ON_PERIPHERAL = 50, - MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 3, - MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 19, - MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 35, - MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 4, - MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 20, - MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 36, - MIPI_DSI_DCS_SHORT_WRITE = 5, - MIPI_DSI_DCS_SHORT_WRITE_PARAM = 21, - MIPI_DSI_DCS_READ = 6, - MIPI_DSI_EXECUTE_QUEUE = 22, - MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 55, - MIPI_DSI_NULL_PACKET = 9, - MIPI_DSI_BLANKING_PACKET = 25, - MIPI_DSI_GENERIC_LONG_WRITE = 41, - MIPI_DSI_DCS_LONG_WRITE = 57, - MIPI_DSI_PICTURE_PARAMETER_SET = 10, - MIPI_DSI_COMPRESSED_PIXEL_STREAM = 11, - MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 12, - MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 28, - MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 44, - MIPI_DSI_PACKED_PIXEL_STREAM_30 = 13, - MIPI_DSI_PACKED_PIXEL_STREAM_36 = 29, - MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 61, - MIPI_DSI_PACKED_PIXEL_STREAM_16 = 14, - MIPI_DSI_PACKED_PIXEL_STREAM_18 = 30, - MIPI_DSI_PIXEL_STREAM_3BYTE_18 = 46, - MIPI_DSI_PACKED_PIXEL_STREAM_24 = 62, -}; - -enum { - MIPI_DCS_NOP = 0, - MIPI_DCS_SOFT_RESET = 1, - MIPI_DCS_GET_COMPRESSION_MODE = 3, - MIPI_DCS_GET_DISPLAY_ID = 4, - MIPI_DCS_GET_ERROR_COUNT_ON_DSI = 5, - MIPI_DCS_GET_RED_CHANNEL = 6, - MIPI_DCS_GET_GREEN_CHANNEL = 7, - MIPI_DCS_GET_BLUE_CHANNEL = 8, - MIPI_DCS_GET_DISPLAY_STATUS = 9, - MIPI_DCS_GET_POWER_MODE = 10, - MIPI_DCS_GET_ADDRESS_MODE = 11, - MIPI_DCS_GET_PIXEL_FORMAT = 12, - MIPI_DCS_GET_DISPLAY_MODE = 13, - MIPI_DCS_GET_SIGNAL_MODE = 14, - MIPI_DCS_GET_DIAGNOSTIC_RESULT = 15, - MIPI_DCS_ENTER_SLEEP_MODE = 16, - MIPI_DCS_EXIT_SLEEP_MODE = 17, - MIPI_DCS_ENTER_PARTIAL_MODE = 18, - MIPI_DCS_ENTER_NORMAL_MODE = 19, - MIPI_DCS_GET_IMAGE_CHECKSUM_RGB = 20, - MIPI_DCS_GET_IMAGE_CHECKSUM_CT = 21, - MIPI_DCS_EXIT_INVERT_MODE = 32, - MIPI_DCS_ENTER_INVERT_MODE = 33, - MIPI_DCS_SET_GAMMA_CURVE = 38, - MIPI_DCS_SET_DISPLAY_OFF = 40, - MIPI_DCS_SET_DISPLAY_ON = 41, - MIPI_DCS_SET_COLUMN_ADDRESS = 42, - MIPI_DCS_SET_PAGE_ADDRESS = 43, - MIPI_DCS_WRITE_MEMORY_START = 44, - MIPI_DCS_WRITE_LUT = 45, - MIPI_DCS_READ_MEMORY_START = 46, - MIPI_DCS_SET_PARTIAL_ROWS = 48, - MIPI_DCS_SET_PARTIAL_COLUMNS = 49, - MIPI_DCS_SET_SCROLL_AREA = 51, - MIPI_DCS_SET_TEAR_OFF = 52, - MIPI_DCS_SET_TEAR_ON = 53, - MIPI_DCS_SET_ADDRESS_MODE = 54, - MIPI_DCS_SET_SCROLL_START = 55, - MIPI_DCS_EXIT_IDLE_MODE = 56, - MIPI_DCS_ENTER_IDLE_MODE = 57, - MIPI_DCS_SET_PIXEL_FORMAT = 58, - MIPI_DCS_WRITE_MEMORY_CONTINUE = 60, - MIPI_DCS_SET_3D_CONTROL = 61, - MIPI_DCS_READ_MEMORY_CONTINUE = 62, - MIPI_DCS_GET_3D_CONTROL = 63, - MIPI_DCS_SET_VSYNC_TIMING = 64, - MIPI_DCS_SET_TEAR_SCANLINE = 68, - MIPI_DCS_GET_SCANLINE = 69, - MIPI_DCS_SET_DISPLAY_BRIGHTNESS = 81, - MIPI_DCS_GET_DISPLAY_BRIGHTNESS = 82, - MIPI_DCS_WRITE_CONTROL_DISPLAY = 83, - MIPI_DCS_GET_CONTROL_DISPLAY = 84, - MIPI_DCS_WRITE_POWER_SAVE = 85, - MIPI_DCS_GET_POWER_SAVE = 86, - MIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 94, - MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 95, - MIPI_DCS_READ_DDB_START = 161, - MIPI_DCS_READ_PPS_START = 162, - MIPI_DCS_READ_DDB_CONTINUE = 168, - MIPI_DCS_READ_PPS_CONTINUE = 169, -}; - -struct vga_device { - struct list_head list; - struct pci_dev *pdev; - unsigned int decodes; - unsigned int owns; - unsigned int locks; - unsigned int io_lock_cnt; - unsigned int mem_lock_cnt; - unsigned int io_norm_cnt; - unsigned int mem_norm_cnt; - bool bridge_has_one_vga; - void *cookie; - void (*irq_set_state)(void *, bool); - unsigned int (*set_vga_decode)(void *, bool); -}; - -struct vga_arb_user_card { - struct pci_dev *pdev; - unsigned int mem_cnt; - unsigned int io_cnt; -}; - -struct vga_arb_private { - struct list_head list; - struct pci_dev *target; - struct vga_arb_user_card cards[16]; - spinlock_t lock; -}; - -struct component_ops { - int (*bind)(struct device *, struct device *, void *); - void (*unbind)(struct device *, struct device *, void *); -}; - -struct component_master_ops { - int (*bind)(struct device *); - void (*unbind)(struct device *); -}; - -struct component; - -struct component_match_array { - void *data; - int (*compare)(struct device *, void *); - int (*compare_typed)(struct device *, int, void *); - void (*release)(struct device *, void *); - struct component *component; - bool duplicate; -}; - -struct master; - -struct component { - struct list_head node; - struct master *master; - bool bound; - const struct component_ops *ops; - int subcomponent; - struct device *dev; -}; - -struct component_match { - size_t alloc; - size_t num; - struct component_match_array *compare; -}; - -struct master { - struct list_head node; - bool bound; - const struct component_master_ops *ops; - struct device *dev; - struct component_match *match; - struct dentry *dentry; -}; - -struct wake_irq { - struct device *dev; - unsigned int status; - int irq; - const char *name; -}; - -enum dpm_order { - DPM_ORDER_NONE = 0, - DPM_ORDER_DEV_AFTER_PARENT = 1, - DPM_ORDER_PARENT_BEFORE_DEV = 2, - DPM_ORDER_DEV_LAST = 3, -}; - -struct subsys_private { - struct kset subsys; - struct kset *devices_kset; - struct list_head interfaces; - struct mutex mutex; - struct kset *drivers_kset; - struct klist klist_devices; - struct klist klist_drivers; - struct blocking_notifier_head bus_notifier; - unsigned int drivers_autoprobe: 1; - struct bus_type *bus; - struct kset glue_dirs; - struct class *class; -}; - -struct driver_private { - struct kobject kobj; - struct klist klist_devices; - struct klist_node knode_bus; - struct module_kobject *mkobj; - struct device_driver *driver; -}; - -struct dev_ext_attribute { - struct device_attribute attr; - void *var; -}; - -struct device_private { - struct klist klist_children; - struct klist_node knode_parent; - struct klist_node knode_driver; - struct klist_node knode_bus; - struct klist_node knode_class; - struct list_head deferred_probe; - struct device_driver *async_driver; - char *deferred_probe_reason; - struct device *device; - u8 dead: 1; -}; - -union device_attr_group_devres { - const struct attribute_group *group; - const struct attribute_group **groups; -}; - -struct class_dir { - struct kobject kobj; - struct class *class; -}; - -struct root_device { - struct device dev; - struct module *owner; -}; - -struct subsys_dev_iter { - struct klist_iter ki; - const struct device_type *type; -}; - -struct subsys_interface { - const char *name; - struct bus_type *subsys; - struct list_head node; - int (*add_dev)(struct device *, struct subsys_interface *); - void (*remove_dev)(struct device *, struct subsys_interface *); -}; - -struct device_attach_data { - struct device *dev; - bool check_async; - bool want_async; - bool have_async; -}; - -struct class_attribute_string { - struct class_attribute attr; - char *str; -}; - -struct class_compat { - struct kobject *kobj; -}; - -typedef void *acpi_handle; - -struct platform_object { - struct platform_device pdev; - char name[0]; -}; - -struct cpu_attr { - struct device_attribute attr; - const struct cpumask * const map; -}; - -typedef struct kobject *kobj_probe_t(dev_t, int *, void *); - -struct probe { - struct probe *next; - dev_t dev; - long unsigned int range; - struct module *owner; - kobj_probe_t *get; - int (*lock)(dev_t, void *); - void *data; -}; - -struct kobj_map___2 { - struct probe *probes[255]; - struct mutex *lock; -}; - -typedef int (*dr_match_t)(struct device *, void *, void *); - -struct devres_node { - struct list_head entry; - dr_release_t release; -}; - -struct devres___2 { - struct devres_node node; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u8 data[0]; -}; - -struct devres_group { - struct devres_node node[2]; - void *id; - int color; -}; - -struct action_devres { - void *data; - void (*action)(void *); -}; - -struct pages_devres { - long unsigned int addr; - unsigned int order; -}; - -struct attribute_container { - struct list_head node; - struct klist containers; - struct class *class; - const struct attribute_group *grp; - struct device_attribute **attrs; - int (*match)(struct attribute_container *, struct device *); - long unsigned int flags; -}; - -struct internal_container { - struct klist_node node; - struct attribute_container *cont; - struct device classdev; -}; - -struct transport_container; - -struct transport_class { - struct class class; - int (*setup)(struct transport_container *, struct device *, struct device *); - int (*configure)(struct transport_container *, struct device *, struct device *); - int (*remove)(struct transport_container *, struct device *, struct device *); -}; - -struct transport_container { - struct attribute_container ac; - const struct attribute_group *statistics; -}; - -struct anon_transport_class { - struct transport_class tclass; - struct attribute_container container; -}; - -struct container_dev { - struct device dev; - int (*offline)(struct container_dev *); -}; - -typedef void * (*devcon_match_fn_t)(struct fwnode_handle *, const char *, void *); - -enum ethtool_link_mode_bit_indices { - ETHTOOL_LINK_MODE_10baseT_Half_BIT = 0, - ETHTOOL_LINK_MODE_10baseT_Full_BIT = 1, - ETHTOOL_LINK_MODE_100baseT_Half_BIT = 2, - ETHTOOL_LINK_MODE_100baseT_Full_BIT = 3, - ETHTOOL_LINK_MODE_1000baseT_Half_BIT = 4, - ETHTOOL_LINK_MODE_1000baseT_Full_BIT = 5, - ETHTOOL_LINK_MODE_Autoneg_BIT = 6, - ETHTOOL_LINK_MODE_TP_BIT = 7, - ETHTOOL_LINK_MODE_AUI_BIT = 8, - ETHTOOL_LINK_MODE_MII_BIT = 9, - ETHTOOL_LINK_MODE_FIBRE_BIT = 10, - ETHTOOL_LINK_MODE_BNC_BIT = 11, - ETHTOOL_LINK_MODE_10000baseT_Full_BIT = 12, - ETHTOOL_LINK_MODE_Pause_BIT = 13, - ETHTOOL_LINK_MODE_Asym_Pause_BIT = 14, - ETHTOOL_LINK_MODE_2500baseX_Full_BIT = 15, - ETHTOOL_LINK_MODE_Backplane_BIT = 16, - ETHTOOL_LINK_MODE_1000baseKX_Full_BIT = 17, - ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT = 18, - ETHTOOL_LINK_MODE_10000baseKR_Full_BIT = 19, - ETHTOOL_LINK_MODE_10000baseR_FEC_BIT = 20, - ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT = 21, - ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT = 22, - ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT = 23, - ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT = 24, - ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT = 25, - ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT = 26, - ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT = 27, - ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT = 28, - ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT = 29, - ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT = 30, - ETHTOOL_LINK_MODE_25000baseCR_Full_BIT = 31, - ETHTOOL_LINK_MODE_25000baseKR_Full_BIT = 32, - ETHTOOL_LINK_MODE_25000baseSR_Full_BIT = 33, - ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT = 34, - ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT = 35, - ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT = 36, - ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT = 37, - ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT = 38, - ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT = 39, - ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT = 40, - ETHTOOL_LINK_MODE_1000baseX_Full_BIT = 41, - ETHTOOL_LINK_MODE_10000baseCR_Full_BIT = 42, - ETHTOOL_LINK_MODE_10000baseSR_Full_BIT = 43, - ETHTOOL_LINK_MODE_10000baseLR_Full_BIT = 44, - ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT = 45, - ETHTOOL_LINK_MODE_10000baseER_Full_BIT = 46, - ETHTOOL_LINK_MODE_2500baseT_Full_BIT = 47, - ETHTOOL_LINK_MODE_5000baseT_Full_BIT = 48, - ETHTOOL_LINK_MODE_FEC_NONE_BIT = 49, - ETHTOOL_LINK_MODE_FEC_RS_BIT = 50, - ETHTOOL_LINK_MODE_FEC_BASER_BIT = 51, - ETHTOOL_LINK_MODE_50000baseKR_Full_BIT = 52, - ETHTOOL_LINK_MODE_50000baseSR_Full_BIT = 53, - ETHTOOL_LINK_MODE_50000baseCR_Full_BIT = 54, - ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT = 55, - ETHTOOL_LINK_MODE_50000baseDR_Full_BIT = 56, - ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT = 57, - ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT = 58, - ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT = 59, - ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT = 60, - ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT = 61, - ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT = 62, - ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT = 63, - ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64, - ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT = 65, - ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT = 66, - ETHTOOL_LINK_MODE_100baseT1_Full_BIT = 67, - ETHTOOL_LINK_MODE_1000baseT1_Full_BIT = 68, - ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT = 69, - ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT = 70, - ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71, - ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72, - ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73, - ETHTOOL_LINK_MODE_FEC_LLRS_BIT = 74, - ETHTOOL_LINK_MODE_100000baseKR_Full_BIT = 75, - ETHTOOL_LINK_MODE_100000baseSR_Full_BIT = 76, - ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT = 77, - ETHTOOL_LINK_MODE_100000baseCR_Full_BIT = 78, - ETHTOOL_LINK_MODE_100000baseDR_Full_BIT = 79, - ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT = 80, - ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT = 81, - ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT = 82, - ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT = 83, - ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT = 84, - ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT = 85, - ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT = 86, - ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87, - ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT = 88, - ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89, - ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90, - ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91, - __ETHTOOL_LINK_MODE_MASK_NBITS = 92, -}; - -struct mii_bus; - -struct mdio_device { - struct device dev; - struct mii_bus *bus; - char modalias[32]; - int (*bus_match)(struct device *, struct device_driver *); - void (*device_free)(struct mdio_device *); - void (*device_remove)(struct mdio_device *); - int addr; - int flags; - struct gpio_desc *reset_gpio; - struct reset_control *reset_ctrl; - unsigned int reset_assert_delay; - unsigned int reset_deassert_delay; -}; - -struct phy_c45_device_ids { - u32 devices_in_package; - u32 mmds_present; - u32 device_ids[32]; -}; - -enum phy_state { - PHY_DOWN = 0, - PHY_READY = 1, - PHY_HALTED = 2, - PHY_UP = 3, - PHY_RUNNING = 4, - PHY_NOLINK = 5, - PHY_CABLETEST = 6, -}; - -typedef enum { - PHY_INTERFACE_MODE_NA = 0, - PHY_INTERFACE_MODE_INTERNAL = 1, - PHY_INTERFACE_MODE_MII = 2, - PHY_INTERFACE_MODE_GMII = 3, - PHY_INTERFACE_MODE_SGMII = 4, - PHY_INTERFACE_MODE_TBI = 5, - PHY_INTERFACE_MODE_REVMII = 6, - PHY_INTERFACE_MODE_RMII = 7, - PHY_INTERFACE_MODE_RGMII = 8, - PHY_INTERFACE_MODE_RGMII_ID = 9, - PHY_INTERFACE_MODE_RGMII_RXID = 10, - PHY_INTERFACE_MODE_RGMII_TXID = 11, - PHY_INTERFACE_MODE_RTBI = 12, - PHY_INTERFACE_MODE_SMII = 13, - PHY_INTERFACE_MODE_XGMII = 14, - PHY_INTERFACE_MODE_XLGMII = 15, - PHY_INTERFACE_MODE_MOCA = 16, - PHY_INTERFACE_MODE_QSGMII = 17, - PHY_INTERFACE_MODE_TRGMII = 18, - PHY_INTERFACE_MODE_1000BASEX = 19, - PHY_INTERFACE_MODE_2500BASEX = 20, - PHY_INTERFACE_MODE_RXAUI = 21, - PHY_INTERFACE_MODE_XAUI = 22, - PHY_INTERFACE_MODE_10GBASER = 23, - PHY_INTERFACE_MODE_USXGMII = 24, - PHY_INTERFACE_MODE_10GKR = 25, - PHY_INTERFACE_MODE_MAX = 26, -} phy_interface_t; - -struct phylink; - -struct phy_driver; - -struct phy_package_shared; - -struct mii_timestamper; - -struct phy_device { - struct mdio_device mdio; - struct phy_driver *drv; - u32 phy_id; - struct phy_c45_device_ids c45_ids; - unsigned int is_c45: 1; - unsigned int is_internal: 1; - unsigned int is_pseudo_fixed_link: 1; - unsigned int is_gigabit_capable: 1; - unsigned int has_fixups: 1; - unsigned int suspended: 1; - unsigned int suspended_by_mdio_bus: 1; - unsigned int sysfs_links: 1; - unsigned int loopback_enabled: 1; - unsigned int downshifted_rate: 1; - unsigned int autoneg: 1; - unsigned int link: 1; - unsigned int autoneg_complete: 1; - unsigned int interrupts: 1; - enum phy_state state; - u32 dev_flags; - phy_interface_t interface; - int speed; - int duplex; - int port; - int pause; - int asym_pause; - u8 master_slave_get; - u8 master_slave_set; - u8 master_slave_state; - long unsigned int supported[2]; - long unsigned int advertising[2]; - long unsigned int lp_advertising[2]; - long unsigned int adv_old[2]; - u32 eee_broken_modes; - int irq; - void *priv; - struct phy_package_shared *shared; - struct sk_buff *skb; - void *ehdr; - struct nlattr *nest; - struct delayed_work state_queue; - struct mutex lock; - bool sfp_bus_attached; - struct sfp_bus *sfp_bus; - struct phylink *phylink; - struct net_device *attached_dev; - struct mii_timestamper *mii_ts; - u8 mdix; - u8 mdix_ctrl; - void (*phy_link_change)(struct phy_device *, bool); - void (*adjust_link)(struct net_device *); -}; - -struct phy_tdr_config { - u32 first; - u32 last; - u32 step; - s8 pair; -}; - -struct mdio_bus_stats { - u64_stats_t transfers; - u64_stats_t errors; - u64_stats_t writes; - u64_stats_t reads; - struct u64_stats_sync syncp; -}; - -struct mii_bus { - struct module *owner; - const char *name; - char id[61]; - void *priv; - int (*read)(struct mii_bus *, int, int); - int (*write)(struct mii_bus *, int, int, u16); - int (*reset)(struct mii_bus *); - struct mdio_bus_stats stats[32]; - struct mutex mdio_lock; - struct device *parent; - enum { - MDIOBUS_ALLOCATED = 1, - MDIOBUS_REGISTERED = 2, - MDIOBUS_UNREGISTERED = 3, - MDIOBUS_RELEASED = 4, - } state; - struct device dev; - struct mdio_device *mdio_map[32]; - u32 phy_mask; - u32 phy_ignore_ta_mask; - int irq[32]; - int reset_delay_us; - int reset_post_delay_us; - struct gpio_desc *reset_gpiod; - enum { - MDIOBUS_NO_CAP = 0, - MDIOBUS_C22 = 1, - MDIOBUS_C45 = 2, - MDIOBUS_C22_C45 = 3, - } probe_capabilities; - struct mutex shared_lock; - struct phy_package_shared *shared[32]; -}; - -struct mdio_driver_common { - struct device_driver driver; - int flags; -}; - -struct mii_timestamper { - bool (*rxtstamp)(struct mii_timestamper *, struct sk_buff *, int); - void (*txtstamp)(struct mii_timestamper *, struct sk_buff *, int); - int (*hwtstamp)(struct mii_timestamper *, struct ifreq *); - void (*link_state)(struct mii_timestamper *, struct phy_device *); - int (*ts_info)(struct mii_timestamper *, struct ethtool_ts_info *); - struct device *device; -}; - -struct phy_package_shared { - int addr; - refcount_t refcnt; - long unsigned int flags; - size_t priv_size; - void *priv; -}; - -struct phy_driver { - struct mdio_driver_common mdiodrv; - u32 phy_id; - char *name; - u32 phy_id_mask; - const long unsigned int * const features; - u32 flags; - const void *driver_data; - int (*soft_reset)(struct phy_device *); - int (*config_init)(struct phy_device *); - int (*probe)(struct phy_device *); - int (*get_features)(struct phy_device *); - int (*suspend)(struct phy_device *); - int (*resume)(struct phy_device *); - int (*config_aneg)(struct phy_device *); - int (*aneg_done)(struct phy_device *); - int (*read_status)(struct phy_device *); - int (*ack_interrupt)(struct phy_device *); - int (*config_intr)(struct phy_device *); - int (*did_interrupt)(struct phy_device *); - irqreturn_t (*handle_interrupt)(struct phy_device *); - void (*remove)(struct phy_device *); - int (*match_phy_device)(struct phy_device *); - int (*set_wol)(struct phy_device *, struct ethtool_wolinfo *); - void (*get_wol)(struct phy_device *, struct ethtool_wolinfo *); - void (*link_change_notify)(struct phy_device *); - int (*read_mmd)(struct phy_device *, int, u16); - int (*write_mmd)(struct phy_device *, int, u16, u16); - int (*read_page)(struct phy_device *); - int (*write_page)(struct phy_device *, int); - int (*module_info)(struct phy_device *, struct ethtool_modinfo *); - int (*module_eeprom)(struct phy_device *, struct ethtool_eeprom *, u8 *); - int (*cable_test_start)(struct phy_device *); - int (*cable_test_tdr_start)(struct phy_device *, const struct phy_tdr_config *); - int (*cable_test_get_status)(struct phy_device *, bool *); - int (*get_sset_count)(struct phy_device *); - void (*get_strings)(struct phy_device *, u8 *); - void (*get_stats)(struct phy_device *, struct ethtool_stats *, u64 *); - int (*get_tunable)(struct phy_device *, struct ethtool_tunable *, void *); - int (*set_tunable)(struct phy_device *, struct ethtool_tunable *, const void *); - int (*set_loopback)(struct phy_device *, bool); - int (*get_sqi)(struct phy_device *); - int (*get_sqi_max)(struct phy_device *); -}; - -struct cache_type_info { - const char *size_prop; - const char *line_size_props[2]; - const char *nr_sets_prop; -}; - -struct software_node; - -struct software_node_ref_args { - const struct software_node *node; - unsigned int nargs; - u64 args[8]; -}; - -struct software_node { - const char *name; - const struct software_node *parent; - const struct property_entry *properties; -}; - -struct swnode { - int id; - struct kobject kobj; - struct fwnode_handle fwnode; - const struct software_node *node; - struct ida child_ids; - struct list_head entry; - struct list_head children; - struct swnode *parent; - unsigned int allocated: 1; -}; - -struct req { - struct req *next; - struct completion done; - int err; - const char *name; - umode_t mode; - kuid_t uid; - kgid_t gid; - struct device *dev; -}; - -enum pm_qos_flags_status { - PM_QOS_FLAGS_UNDEFINED = 4294967295, - PM_QOS_FLAGS_NONE = 0, - PM_QOS_FLAGS_SOME = 1, - PM_QOS_FLAGS_ALL = 2, -}; - -typedef int (*pm_callback_t)(struct device *); - -struct of_phandle_iterator { - const char *cells_name; - int cell_count; - const struct device_node *parent; - const __be32 *list_end; - const __be32 *phandle_end; - const __be32 *cur; - uint32_t cur_count; - phandle phandle; - struct device_node *node; -}; - -enum genpd_notication { - GENPD_NOTIFY_PRE_OFF = 0, - GENPD_NOTIFY_OFF = 1, - GENPD_NOTIFY_PRE_ON = 2, - GENPD_NOTIFY_ON = 3, -}; - -struct gpd_link { - struct generic_pm_domain *parent; - struct list_head parent_node; - struct generic_pm_domain *child; - struct list_head child_node; - unsigned int performance_state; - unsigned int prev_performance_state; -}; - -struct gpd_timing_data { - s64 suspend_latency_ns; - s64 resume_latency_ns; - s64 effective_constraint_ns; - bool constraint_changed; - bool cached_suspend_ok; -}; - -struct generic_pm_domain_data { - struct pm_domain_data base; - struct gpd_timing_data td; - struct notifier_block nb; - struct notifier_block *power_nb; - int cpu; - unsigned int performance_state; - void *data; -}; - -struct of_genpd_provider { - struct list_head link; - struct device_node *node; - genpd_xlate_t xlate; - void *data; -}; - -struct pm_clk_notifier_block { - struct notifier_block nb; - struct dev_pm_domain *pm_domain; - char *con_ids[0]; -}; - -enum pce_status { - PCE_STATUS_NONE = 0, - PCE_STATUS_ACQUIRED = 1, - PCE_STATUS_ENABLED = 2, - PCE_STATUS_ERROR = 3, -}; - -struct pm_clock_entry { - struct list_head node; - char *con_id; - struct clk *clk; - enum pce_status status; -}; - -struct firmware { - size_t size; - const u8 *data; - void *priv; -}; - -struct builtin_fw { - char *name; - void *data; - long unsigned int size; -}; - -enum fw_opt { - FW_OPT_UEVENT = 1, - FW_OPT_NOWAIT = 2, - FW_OPT_USERHELPER = 4, - FW_OPT_NO_WARN = 8, - FW_OPT_NOCACHE = 16, - FW_OPT_NOFALLBACK_SYSFS = 32, - FW_OPT_FALLBACK_PLATFORM = 64, - FW_OPT_PARTIAL = 128, -}; - -enum fw_status { - FW_STATUS_UNKNOWN = 0, - FW_STATUS_LOADING = 1, - FW_STATUS_DONE = 2, - FW_STATUS_ABORTED = 3, -}; - -struct fw_state { - struct completion completion; - enum fw_status status; -}; - -struct firmware_cache; - -struct fw_priv { - struct kref ref; - struct list_head list; - struct firmware_cache *fwc; - struct fw_state fw_st; - void *data; - size_t size; - size_t allocated_size; - size_t offset; - u32 opt_flags; - const char *fw_name; -}; - -struct firmware_cache { - spinlock_t lock; - struct list_head head; - int state; -}; - -struct firmware_work { - struct work_struct work; - struct module *module; - const char *name; - struct device *device; - void *context; - void (*cont)(const struct firmware *, void *); - u32 opt_flags; -}; - -enum regcache_type { - REGCACHE_NONE = 0, - REGCACHE_RBTREE = 1, - REGCACHE_COMPRESSED = 2, - REGCACHE_FLAT = 3, -}; - -struct reg_default { - unsigned int reg; - unsigned int def; -}; - -struct reg_sequence { - unsigned int reg; - unsigned int def; - unsigned int delay_us; -}; - -enum regmap_endian { - REGMAP_ENDIAN_DEFAULT = 0, - REGMAP_ENDIAN_BIG = 1, - REGMAP_ENDIAN_LITTLE = 2, - REGMAP_ENDIAN_NATIVE = 3, -}; - -struct regmap_range { - unsigned int range_min; - unsigned int range_max; -}; - -struct regmap_access_table { - const struct regmap_range *yes_ranges; - unsigned int n_yes_ranges; - const struct regmap_range *no_ranges; - unsigned int n_no_ranges; -}; - -typedef void (*regmap_lock)(void *); - -typedef void (*regmap_unlock)(void *); - -struct regmap_range_cfg; - -struct regmap_config { - const char *name; - int reg_bits; - int reg_stride; - int pad_bits; - int val_bits; - bool (*writeable_reg)(struct device *, unsigned int); - bool (*readable_reg)(struct device *, unsigned int); - bool (*volatile_reg)(struct device *, unsigned int); - bool (*precious_reg)(struct device *, unsigned int); - bool (*writeable_noinc_reg)(struct device *, unsigned int); - bool (*readable_noinc_reg)(struct device *, unsigned int); - bool disable_locking; - regmap_lock lock; - regmap_unlock unlock; - void *lock_arg; - int (*reg_read)(void *, unsigned int, unsigned int *); - int (*reg_write)(void *, unsigned int, unsigned int); - bool fast_io; - unsigned int max_register; - const struct regmap_access_table *wr_table; - const struct regmap_access_table *rd_table; - const struct regmap_access_table *volatile_table; - const struct regmap_access_table *precious_table; - const struct regmap_access_table *wr_noinc_table; - const struct regmap_access_table *rd_noinc_table; - const struct reg_default *reg_defaults; - unsigned int num_reg_defaults; - enum regcache_type cache_type; - const void *reg_defaults_raw; - unsigned int num_reg_defaults_raw; - long unsigned int read_flag_mask; - long unsigned int write_flag_mask; - bool zero_flag_mask; - bool use_single_read; - bool use_single_write; - bool can_multi_write; - enum regmap_endian reg_format_endian; - enum regmap_endian val_format_endian; - const struct regmap_range_cfg *ranges; - unsigned int num_ranges; - bool use_hwlock; - unsigned int hwlock_id; - unsigned int hwlock_mode; - bool can_sleep; -}; - -struct regmap_range_cfg { - const char *name; - unsigned int range_min; - unsigned int range_max; - unsigned int selector_reg; - unsigned int selector_mask; - int selector_shift; - unsigned int window_start; - unsigned int window_len; -}; - -typedef int (*regmap_hw_write)(void *, const void *, size_t); - -typedef int (*regmap_hw_gather_write)(void *, const void *, size_t, const void *, size_t); - -struct regmap_async; - -typedef int (*regmap_hw_async_write)(void *, const void *, size_t, const void *, size_t, struct regmap_async *); - -struct regmap___2; - -struct regmap_async { - struct list_head list; - struct regmap___2 *map; - void *work_buf; -}; - -typedef int (*regmap_hw_read)(void *, const void *, size_t, void *, size_t); - -typedef int (*regmap_hw_reg_read)(void *, unsigned int, unsigned int *); - -typedef int (*regmap_hw_reg_write)(void *, unsigned int, unsigned int); - -typedef int (*regmap_hw_reg_update_bits)(void *, unsigned int, unsigned int, unsigned int); - -typedef struct regmap_async * (*regmap_hw_async_alloc)(); - -typedef void (*regmap_hw_free_context)(void *); - -struct regmap_bus { - bool fast_io; - regmap_hw_write write; - regmap_hw_gather_write gather_write; - regmap_hw_async_write async_write; - regmap_hw_reg_write reg_write; - regmap_hw_reg_update_bits reg_update_bits; - regmap_hw_read read; - regmap_hw_reg_read reg_read; - regmap_hw_free_context free_context; - regmap_hw_async_alloc async_alloc; - u8 read_flag_mask; - enum regmap_endian reg_format_endian_default; - enum regmap_endian val_format_endian_default; - size_t max_raw_read; - size_t max_raw_write; -}; - -struct reg_field { - unsigned int reg; - unsigned int lsb; - unsigned int msb; - unsigned int id_size; - unsigned int id_offset; -}; - -struct regmap_format { - size_t buf_size; - size_t reg_bytes; - size_t pad_bytes; - size_t val_bytes; - void (*format_write)(struct regmap___2 *, unsigned int, unsigned int); - void (*format_reg)(void *, unsigned int, unsigned int); - void (*format_val)(void *, unsigned int, unsigned int); - unsigned int (*parse_val)(const void *); - void (*parse_inplace)(void *); -}; - -struct hwspinlock; - -struct regcache_ops; - -struct regmap___2 { - union { - struct mutex mutex; - struct { - spinlock_t spinlock; - long unsigned int spinlock_flags; - }; - }; - regmap_lock lock; - regmap_unlock unlock; - void *lock_arg; - gfp_t alloc_flags; - struct device *dev; - void *work_buf; - struct regmap_format format; - const struct regmap_bus *bus; - void *bus_context; - const char *name; - bool async; - spinlock_t async_lock; - wait_queue_head_t async_waitq; - struct list_head async_list; - struct list_head async_free; - int async_ret; - bool debugfs_disable; - struct dentry *debugfs; - const char *debugfs_name; - unsigned int debugfs_reg_len; - unsigned int debugfs_val_len; - unsigned int debugfs_tot_len; - struct list_head debugfs_off_cache; - struct mutex cache_lock; - unsigned int max_register; - bool (*writeable_reg)(struct device *, unsigned int); - bool (*readable_reg)(struct device *, unsigned int); - bool (*volatile_reg)(struct device *, unsigned int); - bool (*precious_reg)(struct device *, unsigned int); - bool (*writeable_noinc_reg)(struct device *, unsigned int); - bool (*readable_noinc_reg)(struct device *, unsigned int); - const struct regmap_access_table *wr_table; - const struct regmap_access_table *rd_table; - const struct regmap_access_table *volatile_table; - const struct regmap_access_table *precious_table; - const struct regmap_access_table *wr_noinc_table; - const struct regmap_access_table *rd_noinc_table; - int (*reg_read)(void *, unsigned int, unsigned int *); - int (*reg_write)(void *, unsigned int, unsigned int); - int (*reg_update_bits)(void *, unsigned int, unsigned int, unsigned int); - bool defer_caching; - long unsigned int read_flag_mask; - long unsigned int write_flag_mask; - int reg_shift; - int reg_stride; - int reg_stride_order; - const struct regcache_ops *cache_ops; - enum regcache_type cache_type; - unsigned int cache_size_raw; - unsigned int cache_word_size; - unsigned int num_reg_defaults; - unsigned int num_reg_defaults_raw; - bool cache_only; - bool cache_bypass; - bool cache_free; - struct reg_default *reg_defaults; - const void *reg_defaults_raw; - void *cache; - bool cache_dirty; - bool no_sync_defaults; - struct reg_sequence *patch; - int patch_regs; - bool use_single_read; - bool use_single_write; - bool can_multi_write; - size_t max_raw_read; - size_t max_raw_write; - struct rb_root range_tree; - void *selector_work_buf; - struct hwspinlock *hwlock; - bool can_sleep; -}; - -struct regcache_ops { - const char *name; - enum regcache_type type; - int (*init)(struct regmap___2 *); - int (*exit)(struct regmap___2 *); - void (*debugfs_init)(struct regmap___2 *); - int (*read)(struct regmap___2 *, unsigned int, unsigned int *); - int (*write)(struct regmap___2 *, unsigned int, unsigned int); - int (*sync)(struct regmap___2 *, unsigned int, unsigned int); - int (*drop)(struct regmap___2 *, unsigned int, unsigned int); -}; - -struct regmap_range_node { - struct rb_node node; - const char *name; - struct regmap___2 *map; - unsigned int range_min; - unsigned int range_max; - unsigned int selector_reg; - unsigned int selector_mask; - int selector_shift; - unsigned int window_start; - unsigned int window_len; -}; - -struct regmap_field { - struct regmap___2 *regmap; - unsigned int mask; - unsigned int shift; - unsigned int reg; - unsigned int id_size; - unsigned int id_offset; -}; - -struct trace_event_raw_regmap_reg { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int reg; - unsigned int val; - char __data[0]; -}; - -struct trace_event_raw_regmap_block { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int reg; - int count; - char __data[0]; -}; - -struct trace_event_raw_regcache_sync { - struct trace_entry ent; - u32 __data_loc_name; - u32 __data_loc_status; - u32 __data_loc_type; - int type; - char __data[0]; -}; - -struct trace_event_raw_regmap_bool { - struct trace_entry ent; - u32 __data_loc_name; - int flag; - char __data[0]; -}; - -struct trace_event_raw_regmap_async { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_regcache_drop_region { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int from; - unsigned int to; - char __data[0]; -}; - -struct trace_event_data_offsets_regmap_reg { - u32 name; -}; - -struct trace_event_data_offsets_regmap_block { - u32 name; -}; - -struct trace_event_data_offsets_regcache_sync { - u32 name; - u32 status; - u32 type; -}; - -struct trace_event_data_offsets_regmap_bool { - u32 name; -}; - -struct trace_event_data_offsets_regmap_async { - u32 name; -}; - -struct trace_event_data_offsets_regcache_drop_region { - u32 name; -}; - -typedef void (*btf_trace_regmap_reg_write)(void *, struct regmap___2 *, unsigned int, unsigned int); - -typedef void (*btf_trace_regmap_reg_read)(void *, struct regmap___2 *, unsigned int, unsigned int); - -typedef void (*btf_trace_regmap_reg_read_cache)(void *, struct regmap___2 *, unsigned int, unsigned int); - -typedef void (*btf_trace_regmap_hw_read_start)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_hw_read_done)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_hw_write_start)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_hw_write_done)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regcache_sync)(void *, struct regmap___2 *, const char *, const char *); - -typedef void (*btf_trace_regmap_cache_only)(void *, struct regmap___2 *, bool); - -typedef void (*btf_trace_regmap_cache_bypass)(void *, struct regmap___2 *, bool); - -typedef void (*btf_trace_regmap_async_write_start)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_async_io_complete)(void *, struct regmap___2 *); - -typedef void (*btf_trace_regmap_async_complete_start)(void *, struct regmap___2 *); - -typedef void (*btf_trace_regmap_async_complete_done)(void *, struct regmap___2 *); - -typedef void (*btf_trace_regcache_drop_region)(void *, struct regmap___2 *, unsigned int, unsigned int); - -struct regcache_rbtree_node { - void *block; - long int *cache_present; - unsigned int base_reg; - unsigned int blklen; - struct rb_node node; -}; - -struct regcache_rbtree_ctx { - struct rb_root root; - struct regcache_rbtree_node *cached_rbnode; -}; - -struct regmap_debugfs_off_cache { - struct list_head list; - off_t min; - off_t max; - unsigned int base_reg; - unsigned int max_reg; -}; - -struct regmap_debugfs_node { - struct regmap___2 *map; - struct list_head link; -}; - -struct regmap_mmio_context { - void *regs; - unsigned int val_bytes; - bool attached_clk; - struct clk *clk; - void (*reg_write)(struct regmap_mmio_context *, unsigned int, unsigned int); - unsigned int (*reg_read)(struct regmap_mmio_context *, unsigned int); -}; - -struct regmap_irq_type { - unsigned int type_reg_offset; - unsigned int type_reg_mask; - unsigned int type_rising_val; - unsigned int type_falling_val; - unsigned int type_level_low_val; - unsigned int type_level_high_val; - unsigned int types_supported; -}; - -struct regmap_irq { - unsigned int reg_offset; - unsigned int mask; - struct regmap_irq_type type; -}; - -struct regmap_irq_sub_irq_map { - unsigned int num_regs; - unsigned int *offset; -}; - -struct regmap_irq_chip { - const char *name; - unsigned int main_status; - unsigned int num_main_status_bits; - struct regmap_irq_sub_irq_map *sub_reg_offsets; - int num_main_regs; - unsigned int status_base; - unsigned int mask_base; - unsigned int unmask_base; - unsigned int ack_base; - unsigned int wake_base; - unsigned int type_base; - unsigned int irq_reg_stride; - bool mask_writeonly: 1; - bool init_ack_masked: 1; - bool mask_invert: 1; - bool use_ack: 1; - bool ack_invert: 1; - bool clear_ack: 1; - bool wake_invert: 1; - bool runtime_pm: 1; - bool type_invert: 1; - bool type_in_mask: 1; - bool clear_on_unmask: 1; - int num_regs; - const struct regmap_irq *irqs; - int num_irqs; - int num_type_reg; - unsigned int type_reg_stride; - int (*handle_pre_irq)(void *); - int (*handle_post_irq)(void *); - void *irq_drv_data; -}; - -struct regmap_irq_chip_data { - struct mutex lock; - struct irq_chip irq_chip; - struct regmap___2 *map; - const struct regmap_irq_chip *chip; - int irq_base; - struct irq_domain *domain; - int irq; - int wake_count; - void *status_reg_buf; - unsigned int *main_status_buf; - unsigned int *status_buf; - unsigned int *mask_buf; - unsigned int *mask_buf_def; - unsigned int *wake_buf; - unsigned int *type_buf; - unsigned int *type_buf_def; - unsigned int irq_reg_stride; - unsigned int type_reg_stride; - bool clear_status: 1; -}; - -struct soc_device_attribute { - const char *machine; - const char *family; - const char *revision; - const char *serial_number; - const char *soc_id; - const void *data; - const struct attribute_group *custom_attr_group; -}; - -struct soc_device { - struct device dev; - struct soc_device_attribute *attr; - int soc_dev_num; -}; - -struct devcd_entry { - struct device devcd_dev; - void *data; - size_t datalen; - struct module *owner; - ssize_t (*read)(char *, loff_t, size_t, void *, size_t); - void (*free)(void *); - struct delayed_work del_wk; - struct device *failing_dev; -}; - -typedef void (*irq_write_msi_msg_t)(struct msi_desc *, struct msi_msg *); - -struct platform_msi_priv_data { - struct device *dev; - void *host_data; - msi_alloc_info_t arg; - irq_write_msi_msg_t write_msg; - int devid; -}; - -struct brd_device { - int brd_number; - struct request_queue *brd_queue; - struct gendisk *brd_disk; - struct list_head brd_list; - spinlock_t brd_lock; - struct xarray brd_pages; -}; - -typedef unsigned int __kernel_old_dev_t; - -enum { - LO_FLAGS_READ_ONLY = 1, - LO_FLAGS_AUTOCLEAR = 4, - LO_FLAGS_PARTSCAN = 8, - LO_FLAGS_DIRECT_IO = 16, -}; - -struct loop_info { - int lo_number; - __kernel_old_dev_t lo_device; - long unsigned int lo_inode; - __kernel_old_dev_t lo_rdevice; - int lo_offset; - int lo_encrypt_type; - int lo_encrypt_key_size; - int lo_flags; - char lo_name[64]; - unsigned char lo_encrypt_key[32]; - long unsigned int lo_init[2]; - char reserved[4]; -}; - -struct loop_info64 { - __u64 lo_device; - __u64 lo_inode; - __u64 lo_rdevice; - __u64 lo_offset; - __u64 lo_sizelimit; - __u32 lo_number; - __u32 lo_encrypt_type; - __u32 lo_encrypt_key_size; - __u32 lo_flags; - __u8 lo_file_name[64]; - __u8 lo_crypt_name[64]; - __u8 lo_encrypt_key[32]; - __u64 lo_init[2]; -}; - -struct loop_config { - __u32 fd; - __u32 block_size; - struct loop_info64 info; - __u64 __reserved[8]; -}; - -enum { - Lo_unbound = 0, - Lo_bound = 1, - Lo_rundown = 2, -}; - -struct loop_func_table; - -struct loop_device { - int lo_number; - atomic_t lo_refcnt; - loff_t lo_offset; - loff_t lo_sizelimit; - int lo_flags; - int (*transfer)(struct loop_device *, int, struct page *, unsigned int, struct page *, unsigned int, int, sector_t); - char lo_file_name[64]; - char lo_crypt_name[64]; - char lo_encrypt_key[32]; - int lo_encrypt_key_size; - struct loop_func_table *lo_encryption; - __u32 lo_init[2]; - kuid_t lo_key_owner; - int (*ioctl)(struct loop_device *, int, long unsigned int); - struct file *lo_backing_file; - struct block_device *lo_device; - void *key_data; - gfp_t old_gfp_mask; - spinlock_t lo_lock; - int lo_state; - struct kthread_worker worker; - struct task_struct *worker_task; - bool use_dio; - bool sysfs_inited; - struct request_queue *lo_queue; - struct blk_mq_tag_set tag_set; - struct gendisk *lo_disk; -}; - -struct loop_func_table { - int number; - int (*transfer)(struct loop_device *, int, struct page *, unsigned int, struct page *, unsigned int, int, sector_t); - int (*init)(struct loop_device *, const struct loop_info64 *); - int (*release)(struct loop_device *); - int (*ioctl)(struct loop_device *, int, long unsigned int); - struct module *owner; -}; - -struct loop_cmd { - struct kthread_work work; - bool use_aio; - atomic_t ref; - long int ret; - struct kiocb iocb; - struct bio_vec *bvec; - struct cgroup_subsys_state *css; -}; - -struct compat_loop_info { - compat_int_t lo_number; - compat_dev_t lo_device; - compat_ulong_t lo_inode; - compat_dev_t lo_rdevice; - compat_int_t lo_offset; - compat_int_t lo_encrypt_type; - compat_int_t lo_encrypt_key_size; - compat_int_t lo_flags; - char lo_name[64]; - unsigned char lo_encrypt_key[32]; - compat_ulong_t lo_init[2]; - char reserved[4]; -}; - -struct mfd_cell_acpi_match; - -struct mfd_cell { - const char *name; - int id; - int level; - int (*enable)(struct platform_device *); - int (*disable)(struct platform_device *); - int (*suspend)(struct platform_device *); - int (*resume)(struct platform_device *); - void *platform_data; - size_t pdata_size; - const struct property_entry *properties; - const char *of_compatible; - const u64 of_reg; - bool use_of_reg; - const struct mfd_cell_acpi_match *acpi_match; - int num_resources; - const struct resource *resources; - bool ignore_resource_conflicts; - bool pm_runtime_no_callbacks; - const char * const *parent_supplies; - int num_parent_supplies; -}; - -struct mfd_cell_acpi_match { - const char *pnpid; - const long long unsigned int adr; -}; - -struct stmpe_client_info { - void *data; - int irq; - void *client; - struct device *dev; - int (*read_byte)(struct stmpe *, u8); - int (*write_byte)(struct stmpe *, u8, u8); - int (*read_block)(struct stmpe *, u8, u8, u8 *); - int (*write_block)(struct stmpe *, u8, u8, const u8 *); - void (*init)(struct stmpe *); -}; - -struct stmpe_variant_block; - -struct stmpe_variant_info { - const char *name; - u16 id_val; - u16 id_mask; - int num_gpios; - int af_bits; - const u8 *regs; - struct stmpe_variant_block *blocks; - int num_blocks; - int num_irqs; - int (*enable)(struct stmpe *, unsigned int, bool); - int (*get_altfunc)(struct stmpe *, enum stmpe_block); - int (*enable_autosleep)(struct stmpe *, int); -}; - -struct stmpe_platform_data { - int id; - unsigned int blocks; - unsigned int irq_trigger; - bool autosleep; - bool irq_over_gpio; - int irq_gpio; - int autosleep_timeout; -}; - -struct stmpe_variant_block { - const struct mfd_cell *cell; - int irq; - enum stmpe_block block; -}; - -struct i2c_device_id { - char name[20]; - kernel_ulong_t driver_data; -}; - -struct i2c_msg { - __u16 addr; - __u16 flags; - __u16 len; - __u8 *buf; -}; - -union i2c_smbus_data { - __u8 byte; - __u16 word; - __u8 block[34]; -}; - -struct i2c_adapter; - -struct i2c_client { - short unsigned int flags; - short unsigned int addr; - char name[20]; - struct i2c_adapter *adapter; - struct device dev; - int init_irq; - int irq; - struct list_head detected; -}; - -enum i2c_alert_protocol { - I2C_PROTOCOL_SMBUS_ALERT = 0, - I2C_PROTOCOL_SMBUS_HOST_NOTIFY = 1, -}; - -struct i2c_board_info; - -struct i2c_driver { - unsigned int class; - int (*probe)(struct i2c_client *, const struct i2c_device_id *); - int (*remove)(struct i2c_client *); - int (*probe_new)(struct i2c_client *); - void (*shutdown)(struct i2c_client *); - void (*alert)(struct i2c_client *, enum i2c_alert_protocol, unsigned int); - int (*command)(struct i2c_client *, unsigned int, void *); - struct device_driver driver; - const struct i2c_device_id *id_table; - int (*detect)(struct i2c_client *, struct i2c_board_info *); - const short unsigned int *address_list; - struct list_head clients; -}; - -struct i2c_board_info { - char type[20]; - short unsigned int flags; - short unsigned int addr; - const char *dev_name; - void *platform_data; - struct device_node *of_node; - struct fwnode_handle *fwnode; - const struct property_entry *properties; - const struct resource *resources; - unsigned int num_resources; - int irq; -}; - -struct i2c_algorithm; - -struct i2c_lock_operations; - -struct i2c_bus_recovery_info; - -struct i2c_adapter_quirks; - -struct i2c_adapter { - struct module *owner; - unsigned int class; - const struct i2c_algorithm *algo; - void *algo_data; - const struct i2c_lock_operations *lock_ops; - struct rt_mutex bus_lock; - struct rt_mutex mux_lock; - int timeout; - int retries; - struct device dev; - long unsigned int locked_flags; - int nr; - char name[48]; - struct completion dev_released; - struct mutex userspace_clients_lock; - struct list_head userspace_clients; - struct i2c_bus_recovery_info *bus_recovery_info; - const struct i2c_adapter_quirks *quirks; - struct irq_domain *host_notify_domain; -}; - -struct i2c_algorithm { - int (*master_xfer)(struct i2c_adapter *, struct i2c_msg *, int); - int (*master_xfer_atomic)(struct i2c_adapter *, struct i2c_msg *, int); - int (*smbus_xfer)(struct i2c_adapter *, u16, short unsigned int, char, u8, int, union i2c_smbus_data *); - int (*smbus_xfer_atomic)(struct i2c_adapter *, u16, short unsigned int, char, u8, int, union i2c_smbus_data *); - u32 (*functionality)(struct i2c_adapter *); -}; - -struct i2c_lock_operations { - void (*lock_bus)(struct i2c_adapter *, unsigned int); - int (*trylock_bus)(struct i2c_adapter *, unsigned int); - void (*unlock_bus)(struct i2c_adapter *, unsigned int); -}; - -struct i2c_bus_recovery_info { - int (*recover_bus)(struct i2c_adapter *); - int (*get_scl)(struct i2c_adapter *); - void (*set_scl)(struct i2c_adapter *, int); - int (*get_sda)(struct i2c_adapter *); - void (*set_sda)(struct i2c_adapter *, int); - int (*get_bus_free)(struct i2c_adapter *); - void (*prepare_recovery)(struct i2c_adapter *); - void (*unprepare_recovery)(struct i2c_adapter *); - struct gpio_desc *scl_gpiod; - struct gpio_desc *sda_gpiod; - struct pinctrl *pinctrl; - struct pinctrl_state *pins_default; - struct pinctrl_state *pins_gpio; -}; - -struct i2c_adapter_quirks { - u64 flags; - int max_num_msgs; - u16 max_write_len; - u16 max_read_len; - u16 max_comb_1st_msg_len; - u16 max_comb_2nd_msg_len; -}; - -struct spi_device_id { - char name[32]; - kernel_ulong_t driver_data; -}; - -struct ptp_system_timestamp { - struct timespec64 pre_ts; - struct timespec64 post_ts; -}; - -struct spi_statistics { - spinlock_t lock; - long unsigned int messages; - long unsigned int transfers; - long unsigned int errors; - long unsigned int timedout; - long unsigned int spi_sync; - long unsigned int spi_sync_immediate; - long unsigned int spi_async; - long long unsigned int bytes; - long long unsigned int bytes_rx; - long long unsigned int bytes_tx; - long unsigned int transfer_bytes_histo[17]; - long unsigned int transfers_split_maxsize; -}; - -struct spi_delay { - u16 value; - u8 unit; -}; - -struct spi_controller; - -struct spi_device { - struct device dev; - struct spi_controller *controller; - struct spi_controller *master; - u32 max_speed_hz; - u8 chip_select; - u8 bits_per_word; - bool rt; - u32 mode; - int irq; - void *controller_state; - void *controller_data; - char modalias[32]; - const char *driver_override; - int cs_gpio; - struct gpio_desc *cs_gpiod; - struct spi_delay word_delay; - struct spi_statistics statistics; -}; - -struct spi_message; - -struct spi_transfer; - -struct spi_controller_mem_ops; - -struct spi_controller { - struct device dev; - struct list_head list; - s16 bus_num; - u16 num_chipselect; - u16 dma_alignment; - u32 mode_bits; - u32 buswidth_override_bits; - u32 bits_per_word_mask; - u32 min_speed_hz; - u32 max_speed_hz; - u16 flags; - bool devm_allocated; - bool slave; - size_t (*max_transfer_size)(struct spi_device *); - size_t (*max_message_size)(struct spi_device *); - struct mutex io_mutex; - spinlock_t bus_lock_spinlock; - struct mutex bus_lock_mutex; - bool bus_lock_flag; - int (*setup)(struct spi_device *); - int (*set_cs_timing)(struct spi_device *, struct spi_delay *, struct spi_delay *, struct spi_delay *); - int (*transfer)(struct spi_device *, struct spi_message *); - void (*cleanup)(struct spi_device *); - bool (*can_dma)(struct spi_controller *, struct spi_device *, struct spi_transfer *); - bool queued; - struct kthread_worker *kworker; - struct kthread_work pump_messages; - spinlock_t queue_lock; - struct list_head queue; - struct spi_message *cur_msg; - bool idling; - bool busy; - bool running; - bool rt; - bool auto_runtime_pm; - bool cur_msg_prepared; - bool cur_msg_mapped; - bool last_cs_enable; - bool last_cs_mode_high; - bool fallback; - struct completion xfer_completion; - size_t max_dma_len; - int (*prepare_transfer_hardware)(struct spi_controller *); - int (*transfer_one_message)(struct spi_controller *, struct spi_message *); - int (*unprepare_transfer_hardware)(struct spi_controller *); - int (*prepare_message)(struct spi_controller *, struct spi_message *); - int (*unprepare_message)(struct spi_controller *, struct spi_message *); - int (*slave_abort)(struct spi_controller *); - void (*set_cs)(struct spi_device *, bool); - int (*transfer_one)(struct spi_controller *, struct spi_device *, struct spi_transfer *); - void (*handle_err)(struct spi_controller *, struct spi_message *); - const struct spi_controller_mem_ops *mem_ops; - struct spi_delay cs_setup; - struct spi_delay cs_hold; - struct spi_delay cs_inactive; - int *cs_gpios; - struct gpio_desc **cs_gpiods; - bool use_gpio_descriptors; - s8 unused_native_cs; - s8 max_native_cs; - struct spi_statistics statistics; - struct dma_chan *dma_tx; - struct dma_chan *dma_rx; - void *dummy_rx; - void *dummy_tx; - int (*fw_translate_cs)(struct spi_controller *, unsigned int); - bool ptp_sts_supported; - long unsigned int irq_flags; -}; - -struct spi_driver { - const struct spi_device_id *id_table; - int (*probe)(struct spi_device *); - int (*remove)(struct spi_device *); - void (*shutdown)(struct spi_device *); - struct device_driver driver; -}; - -struct spi_message { - struct list_head transfers; - struct spi_device *spi; - unsigned int is_dma_mapped: 1; - void (*complete)(void *); - void *context; - unsigned int frame_length; - unsigned int actual_length; - int status; - struct list_head queue; - void *state; - struct list_head resources; -}; - -struct spi_transfer { - const void *tx_buf; - void *rx_buf; - unsigned int len; - dma_addr_t tx_dma; - dma_addr_t rx_dma; - struct sg_table tx_sg; - struct sg_table rx_sg; - unsigned int cs_change: 1; - unsigned int tx_nbits: 3; - unsigned int rx_nbits: 3; - u8 bits_per_word; - u16 delay_usecs; - struct spi_delay delay; - struct spi_delay cs_change_delay; - struct spi_delay word_delay; - u32 speed_hz; - u32 effective_speed_hz; - unsigned int ptp_sts_word_pre; - unsigned int ptp_sts_word_post; - struct ptp_system_timestamp *ptp_sts; - bool timestamped; - struct list_head transfer_list; - u16 error; -}; - -struct spi_mem; - -struct spi_mem_op; - -struct spi_mem_dirmap_desc; - -struct spi_controller_mem_ops { - int (*adjust_op_size)(struct spi_mem *, struct spi_mem_op *); - bool (*supports_op)(struct spi_mem *, const struct spi_mem_op *); - int (*exec_op)(struct spi_mem *, const struct spi_mem_op *); - const char * (*get_name)(struct spi_mem *); - int (*dirmap_create)(struct spi_mem_dirmap_desc *); - void (*dirmap_destroy)(struct spi_mem_dirmap_desc *); - ssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *, u64, size_t, void *); - ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *, u64, size_t, const void *); -}; - -struct arizona_ldo1_pdata { - const struct regulator_init_data *init_data; -}; - -struct arizona_micsupp_pdata { - const struct regulator_init_data *init_data; -}; - -struct arizona_micbias { - int mV; - unsigned int ext_cap: 1; - unsigned int discharge: 1; - unsigned int soft_start: 1; - unsigned int bypass: 1; -}; - -struct arizona_micd_config { - unsigned int src; - unsigned int bias; - bool gpio; -}; - -struct arizona_micd_range { - int max; - int key; -}; - -struct arizona_pdata { - struct gpio_desc *reset; - struct arizona_micsupp_pdata micvdd; - struct arizona_ldo1_pdata ldo1; - int clk32k_src; - unsigned int irq_flags; - int gpio_base; - unsigned int gpio_defaults[5]; - unsigned int max_channels_clocked[3]; - bool jd_gpio5; - bool jd_gpio5_nopull; - bool jd_invert; - bool hpdet_acc_id; - bool hpdet_acc_id_line; - int hpdet_id_gpio; - unsigned int hpdet_channel; - bool micd_software_compare; - unsigned int micd_detect_debounce; - int micd_pol_gpio; - unsigned int micd_bias_start_time; - unsigned int micd_rate; - unsigned int micd_dbtime; - unsigned int micd_timeout; - bool micd_force_micbias; - const struct arizona_micd_range *micd_ranges; - int num_micd_ranges; - struct arizona_micd_config *micd_configs; - int num_micd_configs; - int dmic_ref[4]; - struct arizona_micbias micbias[3]; - int inmode[4]; - int out_mono[6]; - unsigned int out_vol_limit[12]; - unsigned int spk_mute[2]; - unsigned int spk_fmt[2]; - unsigned int hap_act; - int irq_gpio; - unsigned int gpsw; -}; - -enum { - ARIZONA_MCLK1 = 0, - ARIZONA_MCLK2 = 1, - ARIZONA_NUM_MCLK = 2, -}; - -enum arizona_type { - WM5102 = 1, - WM5110 = 2, - WM8997 = 3, - WM8280 = 4, - WM8998 = 5, - WM1814 = 6, - WM1831 = 7, - CS47L24 = 8, -}; - -struct regmap_irq_chip_data___2; - -struct snd_soc_dapm_context; - -struct arizona { - struct regmap *regmap; - struct device *dev; - enum arizona_type type; - unsigned int rev; - int num_core_supplies; - struct regulator_bulk_data core_supplies[2]; - struct regulator *dcvdd; - bool has_fully_powered_off; - struct arizona_pdata pdata; - unsigned int external_dcvdd: 1; - int irq; - struct irq_domain *virq; - struct regmap_irq_chip_data___2 *aod_irq_chip; - struct regmap_irq_chip_data___2 *irq_chip; - bool hpdet_clamp; - unsigned int hp_ena; - struct mutex clk_lock; - int clk32k_ref; - struct clk *mclk[2]; - bool ctrlif_error; - struct snd_soc_dapm_context *dapm; - int tdm_width[3]; - int tdm_slots[3]; - uint16_t dac_comp_coeff; - uint8_t dac_comp_enabled; - struct mutex dac_comp_lock; - struct blocking_notifier_head notifier; -}; - -struct arizona_sysclk_state { - unsigned int fll; - unsigned int sysclk; -}; - -struct mfd_of_node_entry { - struct list_head list; - struct device *dev; - struct device_node *np; -}; - -struct syscon_platform_data { - const char *label; -}; - -struct syscon { - struct device_node *np; - struct regmap *regmap; - struct list_head list; -}; - -struct seqcount_ww_mutex { - seqcount_t seqcount; -}; - -typedef struct seqcount_ww_mutex seqcount_ww_mutex_t; - -struct dma_fence_ops; - -struct dma_fence { - spinlock_t *lock; - const struct dma_fence_ops *ops; - union { - struct list_head cb_list; - ktime_t timestamp; - struct callback_head rcu; - }; - u64 context; - u64 seqno; - long unsigned int flags; - struct kref refcount; - int error; -}; - -struct dma_fence_ops { - bool use_64bit_seqno; - const char * (*get_driver_name)(struct dma_fence *); - const char * (*get_timeline_name)(struct dma_fence *); - bool (*enable_signaling)(struct dma_fence *); - bool (*signaled)(struct dma_fence *); - long int (*wait)(struct dma_fence *, bool, long int); - void (*release)(struct dma_fence *); - void (*fence_value_str)(struct dma_fence *, char *, int); - void (*timeline_value_str)(struct dma_fence *, char *, int); -}; - -enum dma_fence_flag_bits { - DMA_FENCE_FLAG_SIGNALED_BIT = 0, - DMA_FENCE_FLAG_TIMESTAMP_BIT = 1, - DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT = 2, - DMA_FENCE_FLAG_USER_BITS = 3, -}; - -struct dma_fence_cb; - -typedef void (*dma_fence_func_t)(struct dma_fence *, struct dma_fence_cb *); - -struct dma_fence_cb { - struct list_head node; - dma_fence_func_t func; -}; - -struct dma_buf; - -struct dma_buf_attachment; - -struct dma_buf_ops { - bool cache_sgt_mapping; - int (*attach)(struct dma_buf *, struct dma_buf_attachment *); - void (*detach)(struct dma_buf *, struct dma_buf_attachment *); - int (*pin)(struct dma_buf_attachment *); - void (*unpin)(struct dma_buf_attachment *); - struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction); - void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *, enum dma_data_direction); - void (*release)(struct dma_buf *); - int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction); - int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); - int (*mmap)(struct dma_buf *, struct vm_area_struct *); - void * (*vmap)(struct dma_buf *); - void (*vunmap)(struct dma_buf *, void *); -}; - -struct dma_buf_poll_cb_t { - struct dma_fence_cb cb; - wait_queue_head_t *poll; - __poll_t active; -}; - -struct dma_resv; - -struct dma_buf { - size_t size; - struct file *file; - struct list_head attachments; - const struct dma_buf_ops *ops; - struct mutex lock; - unsigned int vmapping_counter; - void *vmap_ptr; - const char *exp_name; - const char *name; - spinlock_t name_lock; - struct module *owner; - struct list_head list_node; - void *priv; - struct dma_resv *resv; - wait_queue_head_t poll; - struct dma_buf_poll_cb_t cb_excl; - struct dma_buf_poll_cb_t cb_shared; -}; - -struct dma_buf_attach_ops; - -struct dma_buf_attachment { - struct dma_buf *dmabuf; - struct device *dev; - struct list_head node; - struct sg_table *sgt; - enum dma_data_direction dir; - bool peer2peer; - const struct dma_buf_attach_ops *importer_ops; - void *importer_priv; - void *priv; -}; - -struct dma_resv_list; - -struct dma_resv { - struct ww_mutex lock; - seqcount_ww_mutex_t seq; - struct dma_fence *fence_excl; - struct dma_resv_list *fence; -}; - -struct dma_buf_attach_ops { - bool allow_peer2peer; - void (*move_notify)(struct dma_buf_attachment *); -}; - -struct dma_buf_export_info { - const char *exp_name; - struct module *owner; - const struct dma_buf_ops *ops; - size_t size; - int flags; - struct dma_resv *resv; - void *priv; -}; - -struct dma_resv_list { - struct callback_head rcu; - u32 shared_count; - u32 shared_max; - struct dma_fence *shared[0]; -}; - -struct dma_buf_sync { - __u64 flags; -}; - -struct dma_buf_list { - struct list_head head; - struct mutex lock; -}; - -struct trace_event_raw_dma_fence { - struct trace_entry ent; - u32 __data_loc_driver; - u32 __data_loc_timeline; - unsigned int context; - unsigned int seqno; - char __data[0]; -}; - -struct trace_event_data_offsets_dma_fence { - u32 driver; - u32 timeline; -}; - -typedef void (*btf_trace_dma_fence_emit)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_init)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_destroy)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_enable_signal)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_signaled)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_wait_start)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_wait_end)(void *, struct dma_fence *); - -struct default_wait_cb { - struct dma_fence_cb base; - struct task_struct *task; -}; - -struct dma_fence_array; - -struct dma_fence_array_cb { - struct dma_fence_cb cb; - struct dma_fence_array *array; -}; - -struct dma_fence_array { - struct dma_fence base; - spinlock_t lock; - unsigned int num_fences; - atomic_t num_pending; - struct dma_fence **fences; - struct irq_work work; -}; - -struct dma_fence_chain { - struct dma_fence base; - spinlock_t lock; - struct dma_fence *prev; - u64 prev_seqno; - struct dma_fence *fence; - struct dma_fence_cb cb; - struct irq_work work; -}; - -enum seqno_fence_condition { - SEQNO_FENCE_WAIT_GEQUAL = 0, - SEQNO_FENCE_WAIT_NONZERO = 1, -}; - -struct seqno_fence { - struct dma_fence base; - const struct dma_fence_ops *ops; - struct dma_buf *sync_buf; - uint32_t seqno_ofs; - enum seqno_fence_condition condition; -}; - -struct dma_heap; - -struct dma_heap_ops { - int (*allocate)(struct dma_heap *, long unsigned int, long unsigned int, long unsigned int); -}; - -struct dma_heap { - const char *name; - const struct dma_heap_ops *ops; - void *priv; - dev_t heap_devt; - struct list_head list; - struct cdev heap_cdev; -}; - -struct dma_heap_export_info { - const char *name; - const struct dma_heap_ops *ops; - void *priv; -}; - -struct dma_heap_allocation_data { - __u64 len; - __u32 fd; - __u32 fd_flags; - __u64 heap_flags; -}; - -struct heap_helper_buffer { - struct dma_heap *heap; - struct dma_buf *dmabuf; - size_t size; - void *priv_virt; - struct mutex lock; - int vmap_cnt; - void *vaddr; - long unsigned int pagecount; - struct page **pages; - struct list_head attachments; - void (*free)(struct heap_helper_buffer *); -}; - -struct dma_heaps_attachment { - struct device *dev; - struct sg_table table; - struct list_head list; -}; - -struct cma_heap { - struct dma_heap *heap; - struct cma *cma; -}; - -struct sync_file { - struct file *file; - char user_name[32]; - struct list_head sync_file_list; - wait_queue_head_t wq; - long unsigned int flags; - struct dma_fence *fence; - struct dma_fence_cb cb; -}; - -struct sync_merge_data { - char name[32]; - __s32 fd2; - __s32 fence; - __u32 flags; - __u32 pad; -}; - -struct sync_fence_info { - char obj_name[32]; - char driver_name[32]; - __s32 status; - __u32 flags; - __u64 timestamp_ns; -}; - -struct sync_file_info { - char name[32]; - __s32 status; - __u32 flags; - __u32 num_fences; - __u32 pad; - __u64 sync_fence_info; -}; - -typedef __u64 blist_flags_t; - -enum scsi_device_state { - SDEV_CREATED = 1, - SDEV_RUNNING = 2, - SDEV_CANCEL = 3, - SDEV_DEL = 4, - SDEV_QUIESCE = 5, - SDEV_OFFLINE = 6, - SDEV_TRANSPORT_OFFLINE = 7, - SDEV_BLOCK = 8, - SDEV_CREATED_BLOCK = 9, -}; - -struct scsi_vpd { - struct callback_head rcu; - int len; - unsigned char data[0]; -}; - -struct Scsi_Host; - -struct scsi_target; - -struct scsi_device_handler; - -struct scsi_device { - struct Scsi_Host *host; - struct request_queue *request_queue; - struct list_head siblings; - struct list_head same_target_siblings; - atomic_t device_busy; - atomic_t device_blocked; - atomic_t restarts; - spinlock_t list_lock; - struct list_head starved_entry; - short unsigned int queue_depth; - short unsigned int max_queue_depth; - short unsigned int last_queue_full_depth; - short unsigned int last_queue_full_count; - long unsigned int last_queue_full_time; - long unsigned int queue_ramp_up_period; - long unsigned int last_queue_ramp_up; - unsigned int id; - unsigned int channel; - u64 lun; - unsigned int manufacturer; - unsigned int sector_size; - void *hostdata; - unsigned char type; - char scsi_level; - char inq_periph_qual; - struct mutex inquiry_mutex; - unsigned char inquiry_len; - unsigned char *inquiry; - const char *vendor; - const char *model; - const char *rev; - struct scsi_vpd *vpd_pg0; - struct scsi_vpd *vpd_pg83; - struct scsi_vpd *vpd_pg80; - struct scsi_vpd *vpd_pg89; - unsigned char current_tag; - struct scsi_target *sdev_target; - blist_flags_t sdev_bflags; - unsigned int eh_timeout; - unsigned int removable: 1; - unsigned int changed: 1; - unsigned int busy: 1; - unsigned int lockable: 1; - unsigned int locked: 1; - unsigned int borken: 1; - unsigned int disconnect: 1; - unsigned int soft_reset: 1; - unsigned int sdtr: 1; - unsigned int wdtr: 1; - unsigned int ppr: 1; - unsigned int tagged_supported: 1; - unsigned int simple_tags: 1; - unsigned int was_reset: 1; - unsigned int expecting_cc_ua: 1; - unsigned int use_10_for_rw: 1; - unsigned int use_10_for_ms: 1; - unsigned int set_dbd_for_ms: 1; - unsigned int no_report_opcodes: 1; - unsigned int no_write_same: 1; - unsigned int use_16_for_rw: 1; - unsigned int skip_ms_page_8: 1; - unsigned int skip_ms_page_3f: 1; - unsigned int skip_vpd_pages: 1; - unsigned int try_vpd_pages: 1; - unsigned int use_192_bytes_for_3f: 1; - unsigned int no_start_on_add: 1; - unsigned int allow_restart: 1; - unsigned int manage_start_stop: 1; - unsigned int start_stop_pwr_cond: 1; - unsigned int no_uld_attach: 1; - unsigned int select_no_atn: 1; - unsigned int fix_capacity: 1; - unsigned int guess_capacity: 1; - unsigned int retry_hwerror: 1; - unsigned int last_sector_bug: 1; - unsigned int no_read_disc_info: 1; - unsigned int no_read_capacity_16: 1; - unsigned int try_rc_10_first: 1; - unsigned int security_supported: 1; - unsigned int is_visible: 1; - unsigned int wce_default_on: 1; - unsigned int no_dif: 1; - unsigned int broken_fua: 1; - unsigned int lun_in_cdb: 1; - unsigned int unmap_limit_for_ws: 1; - unsigned int rpm_autosuspend: 1; - bool offline_already; - atomic_t disk_events_disable_depth; - long unsigned int supported_events[1]; - long unsigned int pending_events[1]; - struct list_head event_list; - struct work_struct event_work; - unsigned int max_device_blocked; - atomic_t iorequest_cnt; - atomic_t iodone_cnt; - atomic_t ioerr_cnt; - struct device sdev_gendev; - struct device sdev_dev; - struct execute_work ew; - struct work_struct requeue_work; - struct scsi_device_handler *handler; - void *handler_data; - size_t dma_drain_len; - void *dma_drain_buf; - unsigned char access_state; - struct mutex state_mutex; - enum scsi_device_state sdev_state; - struct task_struct *quiesced_by; - long unsigned int sdev_data[0]; -}; - -enum scsi_host_state { - SHOST_CREATED = 1, - SHOST_RUNNING = 2, - SHOST_CANCEL = 3, - SHOST_DEL = 4, - SHOST_RECOVERY = 5, - SHOST_CANCEL_RECOVERY = 6, - SHOST_DEL_RECOVERY = 7, -}; - -struct scsi_host_template; - -struct scsi_transport_template; - -struct Scsi_Host { - struct list_head __devices; - struct list_head __targets; - struct list_head starved_list; - spinlock_t default_lock; - spinlock_t *host_lock; - struct mutex scan_mutex; - struct list_head eh_cmd_q; - struct task_struct *ehandler; - struct completion *eh_action; - wait_queue_head_t host_wait; - struct scsi_host_template *hostt; - struct scsi_transport_template *transportt; - struct blk_mq_tag_set tag_set; - atomic_t host_blocked; - unsigned int host_failed; - unsigned int host_eh_scheduled; - unsigned int host_no; - int eh_deadline; - long unsigned int last_reset; - unsigned int max_channel; - unsigned int max_id; - u64 max_lun; - unsigned int unique_id; - short unsigned int max_cmd_len; - int this_id; - int can_queue; - short int cmd_per_lun; - short unsigned int sg_tablesize; - short unsigned int sg_prot_tablesize; - unsigned int max_sectors; - unsigned int max_segment_size; - long unsigned int dma_boundary; - long unsigned int virt_boundary_mask; - unsigned int nr_hw_queues; - unsigned int active_mode: 2; - unsigned int unchecked_isa_dma: 1; - unsigned int host_self_blocked: 1; - unsigned int reverse_ordering: 1; - unsigned int tmf_in_progress: 1; - unsigned int async_scan: 1; - unsigned int eh_noresume: 1; - unsigned int no_write_same: 1; - unsigned int host_tagset: 1; - unsigned int short_inquiry: 1; - unsigned int no_scsi2_lun_in_cdb: 1; - char work_q_name[20]; - struct workqueue_struct *work_q; - struct workqueue_struct *tmf_work_q; - unsigned int max_host_blocked; - unsigned int prot_capabilities; - unsigned char prot_guard_type; - long unsigned int base; - long unsigned int io_port; - unsigned char n_io_port; - unsigned char dma_channel; - unsigned int irq; - enum scsi_host_state shost_state; - struct device shost_gendev; - struct device shost_dev; - void *shost_data; - struct device *dma_dev; - long unsigned int hostdata[0]; -}; - -enum scsi_target_state { - STARGET_CREATED = 1, - STARGET_RUNNING = 2, - STARGET_REMOVE = 3, - STARGET_CREATED_REMOVE = 4, - STARGET_DEL = 5, -}; - -struct scsi_target { - struct scsi_device *starget_sdev_user; - struct list_head siblings; - struct list_head devices; - struct device dev; - struct kref reap_ref; - unsigned int channel; - unsigned int id; - unsigned int create: 1; - unsigned int single_lun: 1; - unsigned int pdt_1f_for_no_lun: 1; - unsigned int no_report_luns: 1; - unsigned int expecting_lun_change: 1; - atomic_t target_busy; - atomic_t target_blocked; - unsigned int can_queue; - unsigned int max_target_blocked; - char scsi_level; - enum scsi_target_state state; - void *hostdata; - long unsigned int starget_data[0]; -}; - -struct scsi_data_buffer { - struct sg_table table; - unsigned int length; -}; - -struct scsi_pointer { - char *ptr; - int this_residual; - struct scatterlist *buffer; - int buffers_residual; - dma_addr_t dma_handle; - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; -}; - -struct scsi_cmnd { - struct scsi_request req; - struct scsi_device *device; - struct list_head eh_entry; - struct delayed_work abort_work; - struct callback_head rcu; - int eh_eflags; - long unsigned int jiffies_at_alloc; - int retries; - int allowed; - unsigned char prot_op; - unsigned char prot_type; - unsigned char prot_flags; - short unsigned int cmd_len; - enum dma_data_direction sc_data_direction; - unsigned char *cmnd; - struct scsi_data_buffer sdb; - struct scsi_data_buffer *prot_sdb; - unsigned int underflow; - unsigned int transfersize; - struct request *request; - unsigned char *sense_buffer; - void (*scsi_done)(struct scsi_cmnd *); - struct scsi_pointer SCp; - unsigned char *host_scribble; - int result; - int flags; - long unsigned int state; - unsigned char tag; - unsigned int extra_len; -}; - -enum scsi_prot_operations { - SCSI_PROT_NORMAL = 0, - SCSI_PROT_READ_INSERT = 1, - SCSI_PROT_WRITE_STRIP = 2, - SCSI_PROT_READ_STRIP = 3, - SCSI_PROT_WRITE_INSERT = 4, - SCSI_PROT_READ_PASS = 5, - SCSI_PROT_WRITE_PASS = 6, -}; - -struct scsi_driver { - struct device_driver gendrv; - void (*rescan)(struct device *); - blk_status_t (*init_command)(struct scsi_cmnd *); - void (*uninit_command)(struct scsi_cmnd *); - int (*done)(struct scsi_cmnd *); - int (*eh_action)(struct scsi_cmnd *, int); - void (*eh_reset)(struct scsi_cmnd *); -}; - -struct scsi_host_cmd_pool; - -struct scsi_host_template { - struct module *module; - const char *name; - const char * (*info)(struct Scsi_Host *); - int (*ioctl)(struct scsi_device *, unsigned int, void *); - int (*compat_ioctl)(struct scsi_device *, unsigned int, void *); - int (*init_cmd_priv)(struct Scsi_Host *, struct scsi_cmnd *); - int (*exit_cmd_priv)(struct Scsi_Host *, struct scsi_cmnd *); - int (*queuecommand)(struct Scsi_Host *, struct scsi_cmnd *); - void (*commit_rqs)(struct Scsi_Host *, u16); - int (*eh_abort_handler)(struct scsi_cmnd *); - int (*eh_device_reset_handler)(struct scsi_cmnd *); - int (*eh_target_reset_handler)(struct scsi_cmnd *); - int (*eh_bus_reset_handler)(struct scsi_cmnd *); - int (*eh_host_reset_handler)(struct scsi_cmnd *); - int (*slave_alloc)(struct scsi_device *); - int (*slave_configure)(struct scsi_device *); - void (*slave_destroy)(struct scsi_device *); - int (*target_alloc)(struct scsi_target *); - void (*target_destroy)(struct scsi_target *); - int (*scan_finished)(struct Scsi_Host *, long unsigned int); - void (*scan_start)(struct Scsi_Host *); - int (*change_queue_depth)(struct scsi_device *, int); - int (*map_queues)(struct Scsi_Host *); - bool (*dma_need_drain)(struct request *); - int (*bios_param)(struct scsi_device *, struct block_device *, sector_t, int *); - void (*unlock_native_capacity)(struct scsi_device *); - int (*show_info)(struct seq_file *, struct Scsi_Host *); - int (*write_info)(struct Scsi_Host *, char *, int); - enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); - int (*host_reset)(struct Scsi_Host *, int); - const char *proc_name; - struct proc_dir_entry *proc_dir; - int can_queue; - int this_id; - short unsigned int sg_tablesize; - short unsigned int sg_prot_tablesize; - unsigned int max_sectors; - unsigned int max_segment_size; - long unsigned int dma_boundary; - long unsigned int virt_boundary_mask; - short int cmd_per_lun; - unsigned char present; - int tag_alloc_policy; - unsigned int track_queue_depth: 1; - unsigned int supported_mode: 2; - unsigned int unchecked_isa_dma: 1; - unsigned int emulated: 1; - unsigned int skip_settle_delay: 1; - unsigned int no_write_same: 1; - unsigned int host_tagset: 1; - unsigned int max_host_blocked; - struct device_attribute **shost_attrs; - struct device_attribute **sdev_attrs; - const struct attribute_group **sdev_groups; - u64 vendor_id; - unsigned int cmd_size; - struct scsi_host_cmd_pool *cmd_pool; - int rpm_autosuspend_delay; -}; - -struct trace_event_raw_scsi_dispatch_cmd_start { - struct trace_entry ent; - unsigned int host_no; - unsigned int channel; - unsigned int id; - unsigned int lun; - unsigned int opcode; - unsigned int cmd_len; - unsigned int data_sglen; - unsigned int prot_sglen; - unsigned char prot_op; - u32 __data_loc_cmnd; - char __data[0]; -}; - -struct trace_event_raw_scsi_dispatch_cmd_error { - struct trace_entry ent; - unsigned int host_no; - unsigned int channel; - unsigned int id; - unsigned int lun; - int rtn; - unsigned int opcode; - unsigned int cmd_len; - unsigned int data_sglen; - unsigned int prot_sglen; - unsigned char prot_op; - u32 __data_loc_cmnd; - char __data[0]; -}; - -struct trace_event_raw_scsi_cmd_done_timeout_template { - struct trace_entry ent; - unsigned int host_no; - unsigned int channel; - unsigned int id; - unsigned int lun; - int result; - unsigned int opcode; - unsigned int cmd_len; - unsigned int data_sglen; - unsigned int prot_sglen; - unsigned char prot_op; - u32 __data_loc_cmnd; - char __data[0]; -}; - -struct trace_event_raw_scsi_eh_wakeup { - struct trace_entry ent; - unsigned int host_no; - char __data[0]; -}; - -struct trace_event_data_offsets_scsi_dispatch_cmd_start { - u32 cmnd; -}; - -struct trace_event_data_offsets_scsi_dispatch_cmd_error { - u32 cmnd; -}; - -struct trace_event_data_offsets_scsi_cmd_done_timeout_template { - u32 cmnd; -}; - -struct trace_event_data_offsets_scsi_eh_wakeup {}; - -typedef void (*btf_trace_scsi_dispatch_cmd_start)(void *, struct scsi_cmnd *); - -typedef void (*btf_trace_scsi_dispatch_cmd_error)(void *, struct scsi_cmnd *, int); - -typedef void (*btf_trace_scsi_dispatch_cmd_done)(void *, struct scsi_cmnd *); - -typedef void (*btf_trace_scsi_dispatch_cmd_timeout)(void *, struct scsi_cmnd *); - -typedef void (*btf_trace_scsi_eh_wakeup)(void *, struct Scsi_Host *); - -struct scsi_transport_template { - struct transport_container host_attrs; - struct transport_container target_attrs; - struct transport_container device_attrs; - int (*user_scan)(struct Scsi_Host *, uint, uint, u64); - int device_size; - int device_private_offset; - int target_size; - int target_private_offset; - int host_size; - unsigned int create_work_queue: 1; - void (*eh_strategy_handler)(struct Scsi_Host *); -}; - -struct scsi_host_busy_iter_data { - bool (*fn)(struct scsi_cmnd *, void *, bool); - void *priv; -}; - -struct scsi_idlun { - __u32 dev_id; - __u32 host_unique_id; -}; - -typedef void (*activate_complete)(void *, int); - -struct scsi_device_handler { - struct list_head list; - struct module *module; - const char *name; - int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); - int (*attach)(struct scsi_device *); - void (*detach)(struct scsi_device *); - int (*activate)(struct scsi_device *, activate_complete, void *); - blk_status_t (*prep_fn)(struct scsi_device *, struct request *); - int (*set_params)(struct scsi_device *, const char *); - void (*rescan)(struct scsi_device *); -}; - -struct scsi_eh_save { - int result; - unsigned int resid_len; - int eh_eflags; - enum dma_data_direction data_direction; - unsigned int underflow; - unsigned char cmd_len; - unsigned char prot_op; - unsigned char *cmnd; - struct scsi_data_buffer sdb; - unsigned char eh_cmnd[16]; - struct scatterlist sense_sgl; -}; - -struct scsi_mode_data { - __u32 length; - __u16 block_descriptor_length; - __u8 medium_type; - __u8 device_specific; - __u8 header_length; - __u8 longlba: 1; -}; - -struct scsi_event { - enum scsi_device_event evt_type; - struct list_head node; -}; - -enum scsi_host_prot_capabilities { - SHOST_DIF_TYPE1_PROTECTION = 1, - SHOST_DIF_TYPE2_PROTECTION = 2, - SHOST_DIF_TYPE3_PROTECTION = 4, - SHOST_DIX_TYPE0_PROTECTION = 8, - SHOST_DIX_TYPE1_PROTECTION = 16, - SHOST_DIX_TYPE2_PROTECTION = 32, - SHOST_DIX_TYPE3_PROTECTION = 64, -}; - -enum { - ACTION_FAIL = 0, - ACTION_REPREP = 1, - ACTION_RETRY = 2, - ACTION_DELAYED_RETRY = 3, -}; - -struct scsi_lun { - __u8 scsi_lun[8]; -}; - -enum scsi_timeouts { - SCSI_DEFAULT_EH_TIMEOUT = 2500, -}; - -enum scsi_scan_mode { - SCSI_SCAN_INITIAL = 0, - SCSI_SCAN_RESCAN = 1, - SCSI_SCAN_MANUAL = 2, -}; - -struct async_scan_data { - struct list_head list; - struct Scsi_Host *shost; - struct completion prev_finished; -}; - -enum scsi_devinfo_key { - SCSI_DEVINFO_GLOBAL = 0, - SCSI_DEVINFO_SPI = 1, -}; - -struct scsi_dev_info_list { - struct list_head dev_info_list; - char vendor[8]; - char model[16]; - blist_flags_t flags; - unsigned int compatible; -}; - -struct scsi_dev_info_list_table { - struct list_head node; - struct list_head scsi_dev_info_list; - const char *name; - int key; -}; - -struct scsi_varlen_cdb_hdr { - __u8 opcode; - __u8 control; - __u8 misc[5]; - __u8 additional_cdb_length; - __be16 service_action; -}; - -typedef uint32_t itt_t; - -struct iscsi_hdr { - uint8_t opcode; - uint8_t flags; - uint8_t rsvd2[2]; - uint8_t hlength; - uint8_t dlength[3]; - struct scsi_lun lun; - itt_t itt; - __be32 ttt; - __be32 statsn; - __be32 exp_statsn; - __be32 max_statsn; - uint8_t other[12]; -}; - -enum iscsi_uevent_e { - ISCSI_UEVENT_UNKNOWN = 0, - ISCSI_UEVENT_CREATE_SESSION = 11, - ISCSI_UEVENT_DESTROY_SESSION = 12, - ISCSI_UEVENT_CREATE_CONN = 13, - ISCSI_UEVENT_DESTROY_CONN = 14, - ISCSI_UEVENT_BIND_CONN = 15, - ISCSI_UEVENT_SET_PARAM = 16, - ISCSI_UEVENT_START_CONN = 17, - ISCSI_UEVENT_STOP_CONN = 18, - ISCSI_UEVENT_SEND_PDU = 19, - ISCSI_UEVENT_GET_STATS = 20, - ISCSI_UEVENT_GET_PARAM = 21, - ISCSI_UEVENT_TRANSPORT_EP_CONNECT = 22, - ISCSI_UEVENT_TRANSPORT_EP_POLL = 23, - ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = 24, - ISCSI_UEVENT_TGT_DSCVR = 25, - ISCSI_UEVENT_SET_HOST_PARAM = 26, - ISCSI_UEVENT_UNBIND_SESSION = 27, - ISCSI_UEVENT_CREATE_BOUND_SESSION = 28, - ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST = 29, - ISCSI_UEVENT_PATH_UPDATE = 30, - ISCSI_UEVENT_SET_IFACE_PARAMS = 31, - ISCSI_UEVENT_PING = 32, - ISCSI_UEVENT_GET_CHAP = 33, - ISCSI_UEVENT_DELETE_CHAP = 34, - ISCSI_UEVENT_SET_FLASHNODE_PARAMS = 35, - ISCSI_UEVENT_NEW_FLASHNODE = 36, - ISCSI_UEVENT_DEL_FLASHNODE = 37, - ISCSI_UEVENT_LOGIN_FLASHNODE = 38, - ISCSI_UEVENT_LOGOUT_FLASHNODE = 39, - ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = 40, - ISCSI_UEVENT_SET_CHAP = 41, - ISCSI_UEVENT_GET_HOST_STATS = 42, - ISCSI_UEVENT_DESTROY_SESSION_ASYNC = 43, - ISCSI_KEVENT_RECV_PDU = 101, - ISCSI_KEVENT_CONN_ERROR = 102, - ISCSI_KEVENT_IF_ERROR = 103, - ISCSI_KEVENT_DESTROY_SESSION = 104, - ISCSI_KEVENT_UNBIND_SESSION = 105, - ISCSI_KEVENT_CREATE_SESSION = 106, - ISCSI_KEVENT_PATH_REQ = 107, - ISCSI_KEVENT_IF_DOWN = 108, - ISCSI_KEVENT_CONN_LOGIN_STATE = 109, - ISCSI_KEVENT_HOST_EVENT = 110, - ISCSI_KEVENT_PING_COMP = 111, -}; - -enum iscsi_tgt_dscvr { - ISCSI_TGT_DSCVR_SEND_TARGETS = 1, - ISCSI_TGT_DSCVR_ISNS = 2, - ISCSI_TGT_DSCVR_SLP = 3, -}; - -enum iscsi_host_event_code { - ISCSI_EVENT_LINKUP = 1, - ISCSI_EVENT_LINKDOWN = 2, - ISCSI_EVENT_MAX = 3, -}; - -struct msg_create_session { - uint32_t initial_cmdsn; - uint16_t cmds_max; - uint16_t queue_depth; -}; - -struct msg_create_bound_session { - uint64_t ep_handle; - uint32_t initial_cmdsn; - uint16_t cmds_max; - uint16_t queue_depth; -}; - -struct msg_destroy_session { - uint32_t sid; -}; - -struct msg_create_conn { - uint32_t sid; - uint32_t cid; -}; - -struct msg_bind_conn { - uint32_t sid; - uint32_t cid; - uint64_t transport_eph; - uint32_t is_leading; -}; - -struct msg_destroy_conn { - uint32_t sid; - uint32_t cid; -}; - -struct msg_send_pdu { - uint32_t sid; - uint32_t cid; - uint32_t hdr_size; - uint32_t data_size; -}; - -struct msg_set_param { - uint32_t sid; - uint32_t cid; - uint32_t param; - uint32_t len; -}; - -struct msg_start_conn { - uint32_t sid; - uint32_t cid; -}; - -struct msg_stop_conn { - uint32_t sid; - uint32_t cid; - uint64_t conn_handle; - uint32_t flag; -}; - -struct msg_get_stats { - uint32_t sid; - uint32_t cid; -}; - -struct msg_transport_connect { - uint32_t non_blocking; -}; - -struct msg_transport_connect_through_host { - uint32_t host_no; - uint32_t non_blocking; -}; - -struct msg_transport_poll { - uint64_t ep_handle; - uint32_t timeout_ms; -}; - -struct msg_transport_disconnect { - uint64_t ep_handle; -}; - -struct msg_tgt_dscvr { - enum iscsi_tgt_dscvr type; - uint32_t host_no; - uint32_t enable; -}; - -struct msg_set_host_param { - uint32_t host_no; - uint32_t param; - uint32_t len; -}; - -struct msg_set_path { - uint32_t host_no; -}; - -struct msg_set_iface_params { - uint32_t host_no; - uint32_t count; -}; - -struct msg_iscsi_ping { - uint32_t host_no; - uint32_t iface_num; - uint32_t iface_type; - uint32_t payload_size; - uint32_t pid; -}; - -struct msg_get_chap { - uint32_t host_no; - uint32_t num_entries; - uint16_t chap_tbl_idx; -}; - -struct msg_delete_chap { - uint32_t host_no; - uint16_t chap_tbl_idx; -}; - -struct msg_set_flashnode_param { - uint32_t host_no; - uint32_t flashnode_idx; - uint32_t count; -}; - -struct msg_new_flashnode { - uint32_t host_no; - uint32_t len; -}; - -struct msg_del_flashnode { - uint32_t host_no; - uint32_t flashnode_idx; -}; - -struct msg_login_flashnode { - uint32_t host_no; - uint32_t flashnode_idx; -}; - -struct msg_logout_flashnode { - uint32_t host_no; - uint32_t flashnode_idx; -}; - -struct msg_logout_flashnode_sid { - uint32_t host_no; - uint32_t sid; -}; - -struct msg_get_host_stats { - uint32_t host_no; -}; - -struct msg_create_session_ret { - uint32_t sid; - uint32_t host_no; -}; - -struct msg_create_conn_ret { - uint32_t sid; - uint32_t cid; -}; - -struct msg_unbind_session { - uint32_t sid; - uint32_t host_no; -}; - -struct msg_recv_req { - uint32_t sid; - uint32_t cid; - uint64_t recv_handle; -}; - -struct msg_conn_login { - uint32_t sid; - uint32_t cid; - uint32_t state; -}; - -struct msg_conn_error { - uint32_t sid; - uint32_t cid; - uint32_t error; -}; - -struct msg_session_destroyed { - uint32_t host_no; - uint32_t sid; -}; - -struct msg_transport_connect_ret { - uint64_t handle; -}; - -struct msg_req_path { - uint32_t host_no; -}; - -struct msg_notify_if_down { - uint32_t host_no; -}; - -struct msg_host_event { - uint32_t host_no; - uint32_t data_size; - enum iscsi_host_event_code code; -}; - -struct msg_ping_comp { - uint32_t host_no; - uint32_t status; - uint32_t pid; - uint32_t data_size; -}; - -struct msg_new_flashnode_ret { - uint32_t flashnode_idx; -}; - -struct iscsi_uevent { - uint32_t type; - uint32_t iferror; - uint64_t transport_handle; - union { - struct msg_create_session c_session; - struct msg_create_bound_session c_bound_session; - struct msg_destroy_session d_session; - struct msg_create_conn c_conn; - struct msg_bind_conn b_conn; - struct msg_destroy_conn d_conn; - struct msg_send_pdu send_pdu; - struct msg_set_param set_param; - struct msg_start_conn start_conn; - struct msg_stop_conn stop_conn; - struct msg_get_stats get_stats; - struct msg_transport_connect ep_connect; - struct msg_transport_connect_through_host ep_connect_through_host; - struct msg_transport_poll ep_poll; - struct msg_transport_disconnect ep_disconnect; - struct msg_tgt_dscvr tgt_dscvr; - struct msg_set_host_param set_host_param; - struct msg_set_path set_path; - struct msg_set_iface_params set_iface_params; - struct msg_iscsi_ping iscsi_ping; - struct msg_get_chap get_chap; - struct msg_delete_chap delete_chap; - struct msg_set_flashnode_param set_flashnode; - struct msg_new_flashnode new_flashnode; - struct msg_del_flashnode del_flashnode; - struct msg_login_flashnode login_flashnode; - struct msg_logout_flashnode logout_flashnode; - struct msg_logout_flashnode_sid logout_flashnode_sid; - struct msg_get_host_stats get_host_stats; - } u; - union { - int retcode; - struct msg_create_session_ret c_session_ret; - struct msg_create_conn_ret c_conn_ret; - struct msg_unbind_session unbind_session; - struct msg_recv_req recv_req; - struct msg_conn_login conn_login; - struct msg_conn_error connerror; - struct msg_session_destroyed d_session; - struct msg_transport_connect_ret ep_connect_ret; - struct msg_req_path req_path; - struct msg_notify_if_down notify_if_down; - struct msg_host_event host_event; - struct msg_ping_comp ping_comp; - struct msg_new_flashnode_ret new_flashnode_ret; - } r; -}; - -enum iscsi_param_type { - ISCSI_PARAM = 0, - ISCSI_HOST_PARAM = 1, - ISCSI_NET_PARAM = 2, - ISCSI_FLASHNODE_PARAM = 3, - ISCSI_CHAP_PARAM = 4, - ISCSI_IFACE_PARAM = 5, -}; - -struct iscsi_path { - uint64_t handle; - uint8_t mac_addr[6]; - uint8_t mac_addr_old[6]; - uint32_t ip_addr_len; - union { - struct in_addr v4_addr; - struct in6_addr v6_addr; - } src; - union { - struct in_addr v4_addr; - struct in6_addr v6_addr; - } dst; - uint16_t vlan_id; - uint16_t pmtu; -}; - -enum iscsi_net_param { - ISCSI_NET_PARAM_IPV4_ADDR = 1, - ISCSI_NET_PARAM_IPV4_SUBNET = 2, - ISCSI_NET_PARAM_IPV4_GW = 3, - ISCSI_NET_PARAM_IPV4_BOOTPROTO = 4, - ISCSI_NET_PARAM_MAC = 5, - ISCSI_NET_PARAM_IPV6_LINKLOCAL = 6, - ISCSI_NET_PARAM_IPV6_ADDR = 7, - ISCSI_NET_PARAM_IPV6_ROUTER = 8, - ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG = 9, - ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG = 10, - ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG = 11, - ISCSI_NET_PARAM_IFACE_ENABLE = 12, - ISCSI_NET_PARAM_VLAN_ID = 13, - ISCSI_NET_PARAM_VLAN_PRIORITY = 14, - ISCSI_NET_PARAM_VLAN_ENABLED = 15, - ISCSI_NET_PARAM_VLAN_TAG = 16, - ISCSI_NET_PARAM_IFACE_TYPE = 17, - ISCSI_NET_PARAM_IFACE_NAME = 18, - ISCSI_NET_PARAM_MTU = 19, - ISCSI_NET_PARAM_PORT = 20, - ISCSI_NET_PARAM_IPADDR_STATE = 21, - ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE = 22, - ISCSI_NET_PARAM_IPV6_ROUTER_STATE = 23, - ISCSI_NET_PARAM_DELAYED_ACK_EN = 24, - ISCSI_NET_PARAM_TCP_NAGLE_DISABLE = 25, - ISCSI_NET_PARAM_TCP_WSF_DISABLE = 26, - ISCSI_NET_PARAM_TCP_WSF = 27, - ISCSI_NET_PARAM_TCP_TIMER_SCALE = 28, - ISCSI_NET_PARAM_TCP_TIMESTAMP_EN = 29, - ISCSI_NET_PARAM_CACHE_ID = 30, - ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN = 31, - ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN = 32, - ISCSI_NET_PARAM_IPV4_TOS_EN = 33, - ISCSI_NET_PARAM_IPV4_TOS = 34, - ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN = 35, - ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN = 36, - ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID = 37, - ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN = 38, - ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN = 39, - ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID = 40, - ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN = 41, - ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE = 42, - ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN = 43, - ISCSI_NET_PARAM_IPV4_TTL = 44, - ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN = 45, - ISCSI_NET_PARAM_IPV6_MLD_EN = 46, - ISCSI_NET_PARAM_IPV6_FLOW_LABEL = 47, - ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS = 48, - ISCSI_NET_PARAM_IPV6_HOP_LIMIT = 49, - ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO = 50, - ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME = 51, - ISCSI_NET_PARAM_IPV6_ND_STALE_TMO = 52, - ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT = 53, - ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU = 54, - ISCSI_NET_PARAM_REDIRECT_EN = 55, -}; - -enum iscsi_ipaddress_state { - ISCSI_IPDDRESS_STATE_UNCONFIGURED = 0, - ISCSI_IPDDRESS_STATE_ACQUIRING = 1, - ISCSI_IPDDRESS_STATE_TENTATIVE = 2, - ISCSI_IPDDRESS_STATE_VALID = 3, - ISCSI_IPDDRESS_STATE_DISABLING = 4, - ISCSI_IPDDRESS_STATE_INVALID = 5, - ISCSI_IPDDRESS_STATE_DEPRECATED = 6, -}; - -enum iscsi_router_state { - ISCSI_ROUTER_STATE_UNKNOWN = 0, - ISCSI_ROUTER_STATE_ADVERTISED = 1, - ISCSI_ROUTER_STATE_MANUAL = 2, - ISCSI_ROUTER_STATE_STALE = 3, -}; - -enum iscsi_iface_param { - ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO = 0, - ISCSI_IFACE_PARAM_HDRDGST_EN = 1, - ISCSI_IFACE_PARAM_DATADGST_EN = 2, - ISCSI_IFACE_PARAM_IMM_DATA_EN = 3, - ISCSI_IFACE_PARAM_INITIAL_R2T_EN = 4, - ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN = 5, - ISCSI_IFACE_PARAM_PDU_INORDER_EN = 6, - ISCSI_IFACE_PARAM_ERL = 7, - ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH = 8, - ISCSI_IFACE_PARAM_FIRST_BURST = 9, - ISCSI_IFACE_PARAM_MAX_R2T = 10, - ISCSI_IFACE_PARAM_MAX_BURST = 11, - ISCSI_IFACE_PARAM_CHAP_AUTH_EN = 12, - ISCSI_IFACE_PARAM_BIDI_CHAP_EN = 13, - ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL = 14, - ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN = 15, - ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN = 16, - ISCSI_IFACE_PARAM_INITIATOR_NAME = 17, -}; - -enum iscsi_conn_state { - ISCSI_CONN_STATE_FREE = 0, - ISCSI_CONN_STATE_XPT_WAIT = 1, - ISCSI_CONN_STATE_IN_LOGIN = 2, - ISCSI_CONN_STATE_LOGGED_IN = 3, - ISCSI_CONN_STATE_IN_LOGOUT = 4, - ISCSI_CONN_STATE_LOGOUT_REQUESTED = 5, - ISCSI_CONN_STATE_CLEANUP_WAIT = 6, -}; - -enum iscsi_err { - ISCSI_OK = 0, - ISCSI_ERR_DATASN = 1001, - ISCSI_ERR_DATA_OFFSET = 1002, - ISCSI_ERR_MAX_CMDSN = 1003, - ISCSI_ERR_EXP_CMDSN = 1004, - ISCSI_ERR_BAD_OPCODE = 1005, - ISCSI_ERR_DATALEN = 1006, - ISCSI_ERR_AHSLEN = 1007, - ISCSI_ERR_PROTO = 1008, - ISCSI_ERR_LUN = 1009, - ISCSI_ERR_BAD_ITT = 1010, - ISCSI_ERR_CONN_FAILED = 1011, - ISCSI_ERR_R2TSN = 1012, - ISCSI_ERR_SESSION_FAILED = 1013, - ISCSI_ERR_HDR_DGST = 1014, - ISCSI_ERR_DATA_DGST = 1015, - ISCSI_ERR_PARAM_NOT_FOUND = 1016, - ISCSI_ERR_NO_SCSI_CMD = 1017, - ISCSI_ERR_INVALID_HOST = 1018, - ISCSI_ERR_XMIT_FAILED = 1019, - ISCSI_ERR_TCP_CONN_CLOSE = 1020, - ISCSI_ERR_SCSI_EH_SESSION_RST = 1021, - ISCSI_ERR_NOP_TIMEDOUT = 1022, -}; - -enum iscsi_param { - ISCSI_PARAM_MAX_RECV_DLENGTH = 0, - ISCSI_PARAM_MAX_XMIT_DLENGTH = 1, - ISCSI_PARAM_HDRDGST_EN = 2, - ISCSI_PARAM_DATADGST_EN = 3, - ISCSI_PARAM_INITIAL_R2T_EN = 4, - ISCSI_PARAM_MAX_R2T = 5, - ISCSI_PARAM_IMM_DATA_EN = 6, - ISCSI_PARAM_FIRST_BURST = 7, - ISCSI_PARAM_MAX_BURST = 8, - ISCSI_PARAM_PDU_INORDER_EN = 9, - ISCSI_PARAM_DATASEQ_INORDER_EN = 10, - ISCSI_PARAM_ERL = 11, - ISCSI_PARAM_IFMARKER_EN = 12, - ISCSI_PARAM_OFMARKER_EN = 13, - ISCSI_PARAM_EXP_STATSN = 14, - ISCSI_PARAM_TARGET_NAME = 15, - ISCSI_PARAM_TPGT = 16, - ISCSI_PARAM_PERSISTENT_ADDRESS = 17, - ISCSI_PARAM_PERSISTENT_PORT = 18, - ISCSI_PARAM_SESS_RECOVERY_TMO = 19, - ISCSI_PARAM_CONN_PORT = 20, - ISCSI_PARAM_CONN_ADDRESS = 21, - ISCSI_PARAM_USERNAME = 22, - ISCSI_PARAM_USERNAME_IN = 23, - ISCSI_PARAM_PASSWORD = 24, - ISCSI_PARAM_PASSWORD_IN = 25, - ISCSI_PARAM_FAST_ABORT = 26, - ISCSI_PARAM_ABORT_TMO = 27, - ISCSI_PARAM_LU_RESET_TMO = 28, - ISCSI_PARAM_HOST_RESET_TMO = 29, - ISCSI_PARAM_PING_TMO = 30, - ISCSI_PARAM_RECV_TMO = 31, - ISCSI_PARAM_IFACE_NAME = 32, - ISCSI_PARAM_ISID = 33, - ISCSI_PARAM_INITIATOR_NAME = 34, - ISCSI_PARAM_TGT_RESET_TMO = 35, - ISCSI_PARAM_TARGET_ALIAS = 36, - ISCSI_PARAM_CHAP_IN_IDX = 37, - ISCSI_PARAM_CHAP_OUT_IDX = 38, - ISCSI_PARAM_BOOT_ROOT = 39, - ISCSI_PARAM_BOOT_NIC = 40, - ISCSI_PARAM_BOOT_TARGET = 41, - ISCSI_PARAM_AUTO_SND_TGT_DISABLE = 42, - ISCSI_PARAM_DISCOVERY_SESS = 43, - ISCSI_PARAM_PORTAL_TYPE = 44, - ISCSI_PARAM_CHAP_AUTH_EN = 45, - ISCSI_PARAM_DISCOVERY_LOGOUT_EN = 46, - ISCSI_PARAM_BIDI_CHAP_EN = 47, - ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL = 48, - ISCSI_PARAM_DEF_TIME2WAIT = 49, - ISCSI_PARAM_DEF_TIME2RETAIN = 50, - ISCSI_PARAM_MAX_SEGMENT_SIZE = 51, - ISCSI_PARAM_STATSN = 52, - ISCSI_PARAM_KEEPALIVE_TMO = 53, - ISCSI_PARAM_LOCAL_PORT = 54, - ISCSI_PARAM_TSID = 55, - ISCSI_PARAM_DEF_TASKMGMT_TMO = 56, - ISCSI_PARAM_TCP_TIMESTAMP_STAT = 57, - ISCSI_PARAM_TCP_WSF_DISABLE = 58, - ISCSI_PARAM_TCP_NAGLE_DISABLE = 59, - ISCSI_PARAM_TCP_TIMER_SCALE = 60, - ISCSI_PARAM_TCP_TIMESTAMP_EN = 61, - ISCSI_PARAM_TCP_XMIT_WSF = 62, - ISCSI_PARAM_TCP_RECV_WSF = 63, - ISCSI_PARAM_IP_FRAGMENT_DISABLE = 64, - ISCSI_PARAM_IPV4_TOS = 65, - ISCSI_PARAM_IPV6_TC = 66, - ISCSI_PARAM_IPV6_FLOW_LABEL = 67, - ISCSI_PARAM_IS_FW_ASSIGNED_IPV6 = 68, - ISCSI_PARAM_DISCOVERY_PARENT_IDX = 69, - ISCSI_PARAM_DISCOVERY_PARENT_TYPE = 70, - ISCSI_PARAM_LOCAL_IPADDR = 71, - ISCSI_PARAM_MAX = 72, -}; - -enum iscsi_host_param { - ISCSI_HOST_PARAM_HWADDRESS = 0, - ISCSI_HOST_PARAM_INITIATOR_NAME = 1, - ISCSI_HOST_PARAM_NETDEV_NAME = 2, - ISCSI_HOST_PARAM_IPADDRESS = 3, - ISCSI_HOST_PARAM_PORT_STATE = 4, - ISCSI_HOST_PARAM_PORT_SPEED = 5, - ISCSI_HOST_PARAM_MAX = 6, -}; - -enum iscsi_flashnode_param { - ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6 = 0, - ISCSI_FLASHNODE_PORTAL_TYPE = 1, - ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE = 2, - ISCSI_FLASHNODE_DISCOVERY_SESS = 3, - ISCSI_FLASHNODE_ENTRY_EN = 4, - ISCSI_FLASHNODE_HDR_DGST_EN = 5, - ISCSI_FLASHNODE_DATA_DGST_EN = 6, - ISCSI_FLASHNODE_IMM_DATA_EN = 7, - ISCSI_FLASHNODE_INITIAL_R2T_EN = 8, - ISCSI_FLASHNODE_DATASEQ_INORDER = 9, - ISCSI_FLASHNODE_PDU_INORDER = 10, - ISCSI_FLASHNODE_CHAP_AUTH_EN = 11, - ISCSI_FLASHNODE_SNACK_REQ_EN = 12, - ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN = 13, - ISCSI_FLASHNODE_BIDI_CHAP_EN = 14, - ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL = 15, - ISCSI_FLASHNODE_ERL = 16, - ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT = 17, - ISCSI_FLASHNODE_TCP_NAGLE_DISABLE = 18, - ISCSI_FLASHNODE_TCP_WSF_DISABLE = 19, - ISCSI_FLASHNODE_TCP_TIMER_SCALE = 20, - ISCSI_FLASHNODE_TCP_TIMESTAMP_EN = 21, - ISCSI_FLASHNODE_IP_FRAG_DISABLE = 22, - ISCSI_FLASHNODE_MAX_RECV_DLENGTH = 23, - ISCSI_FLASHNODE_MAX_XMIT_DLENGTH = 24, - ISCSI_FLASHNODE_FIRST_BURST = 25, - ISCSI_FLASHNODE_DEF_TIME2WAIT = 26, - ISCSI_FLASHNODE_DEF_TIME2RETAIN = 27, - ISCSI_FLASHNODE_MAX_R2T = 28, - ISCSI_FLASHNODE_KEEPALIVE_TMO = 29, - ISCSI_FLASHNODE_ISID = 30, - ISCSI_FLASHNODE_TSID = 31, - ISCSI_FLASHNODE_PORT = 32, - ISCSI_FLASHNODE_MAX_BURST = 33, - ISCSI_FLASHNODE_DEF_TASKMGMT_TMO = 34, - ISCSI_FLASHNODE_IPADDR = 35, - ISCSI_FLASHNODE_ALIAS = 36, - ISCSI_FLASHNODE_REDIRECT_IPADDR = 37, - ISCSI_FLASHNODE_MAX_SEGMENT_SIZE = 38, - ISCSI_FLASHNODE_LOCAL_PORT = 39, - ISCSI_FLASHNODE_IPV4_TOS = 40, - ISCSI_FLASHNODE_IPV6_TC = 41, - ISCSI_FLASHNODE_IPV6_FLOW_LABEL = 42, - ISCSI_FLASHNODE_NAME = 43, - ISCSI_FLASHNODE_TPGT = 44, - ISCSI_FLASHNODE_LINK_LOCAL_IPV6 = 45, - ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX = 46, - ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE = 47, - ISCSI_FLASHNODE_TCP_XMIT_WSF = 48, - ISCSI_FLASHNODE_TCP_RECV_WSF = 49, - ISCSI_FLASHNODE_CHAP_IN_IDX = 50, - ISCSI_FLASHNODE_CHAP_OUT_IDX = 51, - ISCSI_FLASHNODE_USERNAME = 52, - ISCSI_FLASHNODE_USERNAME_IN = 53, - ISCSI_FLASHNODE_PASSWORD = 54, - ISCSI_FLASHNODE_PASSWORD_IN = 55, - ISCSI_FLASHNODE_STATSN = 56, - ISCSI_FLASHNODE_EXP_STATSN = 57, - ISCSI_FLASHNODE_IS_BOOT_TGT = 58, - ISCSI_FLASHNODE_MAX = 59, -}; - -enum iscsi_discovery_parent_type { - ISCSI_DISC_PARENT_UNKNOWN = 1, - ISCSI_DISC_PARENT_SENDTGT = 2, - ISCSI_DISC_PARENT_ISNS = 3, -}; - -enum iscsi_port_speed { - ISCSI_PORT_SPEED_UNKNOWN = 1, - ISCSI_PORT_SPEED_10MBPS = 2, - ISCSI_PORT_SPEED_100MBPS = 4, - ISCSI_PORT_SPEED_1GBPS = 8, - ISCSI_PORT_SPEED_10GBPS = 16, - ISCSI_PORT_SPEED_25GBPS = 32, - ISCSI_PORT_SPEED_40GBPS = 64, -}; - -enum iscsi_port_state { - ISCSI_PORT_STATE_DOWN = 1, - ISCSI_PORT_STATE_UP = 2, -}; - -struct iscsi_stats_custom { - char desc[64]; - uint64_t value; -}; - -struct iscsi_stats { - uint64_t txdata_octets; - uint64_t rxdata_octets; - uint32_t noptx_pdus; - uint32_t scsicmd_pdus; - uint32_t tmfcmd_pdus; - uint32_t login_pdus; - uint32_t text_pdus; - uint32_t dataout_pdus; - uint32_t logout_pdus; - uint32_t snack_pdus; - uint32_t noprx_pdus; - uint32_t scsirsp_pdus; - uint32_t tmfrsp_pdus; - uint32_t textrsp_pdus; - uint32_t datain_pdus; - uint32_t logoutrsp_pdus; - uint32_t r2t_pdus; - uint32_t async_pdus; - uint32_t rjt_pdus; - uint32_t digest_err; - uint32_t timeout_err; - uint32_t custom_length; - struct iscsi_stats_custom custom[0]; -}; - -enum chap_type_e { - CHAP_TYPE_OUT = 0, - CHAP_TYPE_IN = 1, -}; - -struct iscsi_chap_rec { - uint16_t chap_tbl_idx; - enum chap_type_e chap_type; - char username[256]; - uint8_t password[256]; - uint8_t password_length; -}; - -struct iscsi_task; - -struct iscsi_conn; - -struct iscsi_cls_session; - -struct iscsi_endpoint; - -struct iscsi_cls_conn; - -struct iscsi_iface; - -struct iscsi_bus_flash_session; - -struct iscsi_bus_flash_conn; - -struct iscsi_transport { - struct module *owner; - char *name; - unsigned int caps; - struct iscsi_cls_session * (*create_session)(struct iscsi_endpoint *, uint16_t, uint16_t, uint32_t); - void (*destroy_session)(struct iscsi_cls_session *); - struct iscsi_cls_conn * (*create_conn)(struct iscsi_cls_session *, uint32_t); - int (*bind_conn)(struct iscsi_cls_session *, struct iscsi_cls_conn *, uint64_t, int); - int (*start_conn)(struct iscsi_cls_conn *); - void (*stop_conn)(struct iscsi_cls_conn *, int); - void (*destroy_conn)(struct iscsi_cls_conn *); - int (*set_param)(struct iscsi_cls_conn *, enum iscsi_param, char *, int); - int (*get_ep_param)(struct iscsi_endpoint *, enum iscsi_param, char *); - int (*get_conn_param)(struct iscsi_cls_conn *, enum iscsi_param, char *); - int (*get_session_param)(struct iscsi_cls_session *, enum iscsi_param, char *); - int (*get_host_param)(struct Scsi_Host *, enum iscsi_host_param, char *); - int (*set_host_param)(struct Scsi_Host *, enum iscsi_host_param, char *, int); - int (*send_pdu)(struct iscsi_cls_conn *, struct iscsi_hdr *, char *, uint32_t); - void (*get_stats)(struct iscsi_cls_conn *, struct iscsi_stats *); - int (*init_task)(struct iscsi_task *); - int (*xmit_task)(struct iscsi_task *); - void (*cleanup_task)(struct iscsi_task *); - int (*alloc_pdu)(struct iscsi_task *, uint8_t); - int (*xmit_pdu)(struct iscsi_task *); - int (*init_pdu)(struct iscsi_task *, unsigned int, unsigned int); - void (*parse_pdu_itt)(struct iscsi_conn *, itt_t, int *, int *); - void (*session_recovery_timedout)(struct iscsi_cls_session *); - struct iscsi_endpoint * (*ep_connect)(struct Scsi_Host *, struct sockaddr *, int); - int (*ep_poll)(struct iscsi_endpoint *, int); - void (*ep_disconnect)(struct iscsi_endpoint *); - int (*tgt_dscvr)(struct Scsi_Host *, enum iscsi_tgt_dscvr, uint32_t, struct sockaddr *); - int (*set_path)(struct Scsi_Host *, struct iscsi_path *); - int (*set_iface_param)(struct Scsi_Host *, void *, uint32_t); - int (*get_iface_param)(struct iscsi_iface *, enum iscsi_param_type, int, char *); - umode_t (*attr_is_visible)(int, int); - int (*bsg_request)(struct bsg_job *); - int (*send_ping)(struct Scsi_Host *, uint32_t, uint32_t, uint32_t, uint32_t, struct sockaddr *); - int (*get_chap)(struct Scsi_Host *, uint16_t, uint32_t *, char *); - int (*delete_chap)(struct Scsi_Host *, uint16_t); - int (*set_chap)(struct Scsi_Host *, void *, int); - int (*get_flashnode_param)(struct iscsi_bus_flash_session *, int, char *); - int (*set_flashnode_param)(struct iscsi_bus_flash_session *, struct iscsi_bus_flash_conn *, void *, int); - int (*new_flashnode)(struct Scsi_Host *, const char *, int); - int (*del_flashnode)(struct iscsi_bus_flash_session *); - int (*login_flashnode)(struct iscsi_bus_flash_session *, struct iscsi_bus_flash_conn *); - int (*logout_flashnode)(struct iscsi_bus_flash_session *, struct iscsi_bus_flash_conn *); - int (*logout_flashnode_sid)(struct iscsi_cls_session *); - int (*get_host_stats)(struct Scsi_Host *, char *, int); - u8 (*check_protection)(struct iscsi_task *, sector_t *); -}; - -struct iscsi_cls_session { - struct list_head sess_list; - struct iscsi_transport *transport; - spinlock_t lock; - struct work_struct block_work; - struct work_struct unblock_work; - struct work_struct scan_work; - struct work_struct unbind_work; - struct work_struct destroy_work; - int recovery_tmo; - bool recovery_tmo_sysfs_override; - struct delayed_work recovery_work; - unsigned int target_id; - bool ida_used; - pid_t creator; - int state; - int sid; - void *dd_data; - struct device dev; -}; - -struct iscsi_endpoint { - void *dd_data; - struct device dev; - uint64_t id; - struct iscsi_cls_conn *conn; -}; - -enum iscsi_connection_state { - ISCSI_CONN_UP = 0, - ISCSI_CONN_DOWN = 1, - ISCSI_CONN_FAILED = 2, - ISCSI_CONN_BOUND = 3, -}; - -struct iscsi_cls_conn { - struct list_head conn_list; - struct list_head conn_list_err; - void *dd_data; - struct iscsi_transport *transport; - uint32_t cid; - struct mutex ep_mutex; - struct iscsi_endpoint *ep; - struct device dev; - enum iscsi_connection_state state; -}; - -struct iscsi_iface { - struct device dev; - struct iscsi_transport *transport; - uint32_t iface_type; - uint32_t iface_num; - void *dd_data; -}; - -struct iscsi_bus_flash_session { - struct list_head sess_list; - struct iscsi_transport *transport; - unsigned int target_id; - int flash_state; - void *dd_data; - struct device dev; - unsigned int first_burst; - unsigned int max_burst; - short unsigned int max_r2t; - int default_taskmgmt_timeout; - int initial_r2t_en; - int imm_data_en; - int time2wait; - int time2retain; - int pdu_inorder_en; - int dataseq_inorder_en; - int erl; - int tpgt; - char *username; - char *username_in; - char *password; - char *password_in; - char *targetname; - char *targetalias; - char *portal_type; - uint16_t tsid; - uint16_t chap_in_idx; - uint16_t chap_out_idx; - uint16_t discovery_parent_idx; - uint16_t discovery_parent_type; - uint8_t auto_snd_tgt_disable; - uint8_t discovery_sess; - uint8_t entry_state; - uint8_t chap_auth_en; - uint8_t discovery_logout_en; - uint8_t bidi_chap_en; - uint8_t discovery_auth_optional; - uint8_t isid[6]; - uint8_t is_boot_target; -}; - -struct iscsi_bus_flash_conn { - struct list_head conn_list; - void *dd_data; - struct iscsi_transport *transport; - struct device dev; - uint32_t exp_statsn; - uint32_t statsn; - unsigned int max_recv_dlength; - unsigned int max_xmit_dlength; - unsigned int max_segment_size; - unsigned int tcp_xmit_wsf; - unsigned int tcp_recv_wsf; - int hdrdgst_en; - int datadgst_en; - int port; - char *ipaddress; - char *link_local_ipv6_addr; - char *redirect_ipaddr; - uint16_t keepalive_timeout; - uint16_t local_port; - uint8_t snack_req_en; - uint8_t tcp_timestamp_stat; - uint8_t tcp_nagle_disable; - uint8_t tcp_wsf_disable; - uint8_t tcp_timer_scale; - uint8_t tcp_timestamp_en; - uint8_t ipv4_tos; - uint8_t ipv6_traffic_class; - uint8_t ipv6_flow_label; - uint8_t fragment_disable; - uint8_t is_fw_assigned_ipv6; -}; - -enum { - ISCSI_SESSION_LOGGED_IN = 0, - ISCSI_SESSION_FAILED = 1, - ISCSI_SESSION_FREE = 2, -}; - -struct iscsi_cls_host { - atomic_t nr_scans; - struct mutex mutex; - struct request_queue *bsg_q; - uint32_t port_speed; - uint32_t port_state; -}; - -struct iscsi_bsg_host_vendor { - uint64_t vendor_id; - uint32_t vendor_cmd[0]; -}; - -struct iscsi_bsg_host_vendor_reply { - uint32_t vendor_rsp[0]; -}; - -struct iscsi_bsg_request { - uint32_t msgcode; - union { - struct iscsi_bsg_host_vendor h_vendor; - } rqst_data; -} __attribute__((packed)); - -struct iscsi_bsg_reply { - uint32_t result; - uint32_t reply_payload_rcv_len; - union { - struct iscsi_bsg_host_vendor_reply vendor_reply; - } reply_data; -}; - -struct trace_event_raw_iscsi_log_msg { - struct trace_entry ent; - u32 __data_loc_dname; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_data_offsets_iscsi_log_msg { - u32 dname; - u32 msg; -}; - -typedef void (*btf_trace_iscsi_dbg_conn)(void *, struct device *, struct va_format *); - -typedef void (*btf_trace_iscsi_dbg_session)(void *, struct device *, struct va_format *); - -typedef void (*btf_trace_iscsi_dbg_eh)(void *, struct device *, struct va_format *); - -typedef void (*btf_trace_iscsi_dbg_tcp)(void *, struct device *, struct va_format *); - -typedef void (*btf_trace_iscsi_dbg_sw_tcp)(void *, struct device *, struct va_format *); - -typedef void (*btf_trace_iscsi_dbg_trans_session)(void *, struct device *, struct va_format *); - -typedef void (*btf_trace_iscsi_dbg_trans_conn)(void *, struct device *, struct va_format *); - -struct iscsi_internal { - struct scsi_transport_template t; - struct iscsi_transport *iscsi_transport; - struct list_head list; - struct device dev; - struct transport_container conn_cont; - struct transport_container session_cont; -}; - -struct iscsi_scan_data { - unsigned int channel; - unsigned int id; - u64 lun; - enum scsi_scan_mode rescan; -}; - -enum bip_flags { - BIP_BLOCK_INTEGRITY = 1, - BIP_MAPPED_INTEGRITY = 2, - BIP_CTRL_NOCHECK = 4, - BIP_DISK_NOCHECK = 8, - BIP_IP_CHECKSUM = 16, -}; - -enum t10_dif_type { - T10_PI_TYPE0_PROTECTION = 0, - T10_PI_TYPE1_PROTECTION = 1, - T10_PI_TYPE2_PROTECTION = 2, - T10_PI_TYPE3_PROTECTION = 3, -}; - -enum scsi_prot_flags { - SCSI_PROT_TRANSFER_PI = 1, - SCSI_PROT_GUARD_CHECK = 2, - SCSI_PROT_REF_CHECK = 4, - SCSI_PROT_REF_INCREMENT = 8, - SCSI_PROT_IP_CHECKSUM = 16, -}; - -enum { - SD_EXT_CDB_SIZE = 32, - SD_MEMPOOL_SIZE = 2, -}; - -enum { - SD_DEF_XFER_BLOCKS = 65535, - SD_MAX_XFER_BLOCKS = 4294967295, - SD_MAX_WS10_BLOCKS = 65535, - SD_MAX_WS16_BLOCKS = 8388607, -}; - -enum { - SD_LBP_FULL = 0, - SD_LBP_UNMAP = 1, - SD_LBP_WS16 = 2, - SD_LBP_WS10 = 3, - SD_LBP_ZERO = 4, - SD_LBP_DISABLE = 5, -}; - -enum { - SD_ZERO_WRITE = 0, - SD_ZERO_WS = 1, - SD_ZERO_WS16_UNMAP = 2, - SD_ZERO_WS10_UNMAP = 3, -}; - -struct opal_dev; - -struct scsi_disk { - struct scsi_driver *driver; - struct scsi_device *device; - struct device dev; - struct gendisk *disk; - struct opal_dev *opal_dev; - atomic_t openers; - sector_t capacity; - int max_retries; - u32 max_xfer_blocks; - u32 opt_xfer_blocks; - u32 max_ws_blocks; - u32 max_unmap_blocks; - u32 unmap_granularity; - u32 unmap_alignment; - u32 index; - unsigned int physical_block_size; - unsigned int max_medium_access_timeouts; - unsigned int medium_access_timed_out; - u8 media_present; - u8 write_prot; - u8 protection_type; - u8 provisioning_mode; - u8 zeroing_mode; - unsigned int ATO: 1; - unsigned int cache_override: 1; - unsigned int WCE: 1; - unsigned int RCD: 1; - unsigned int DPOFUA: 1; - unsigned int first_scan: 1; - unsigned int lbpme: 1; - unsigned int lbprz: 1; - unsigned int lbpu: 1; - unsigned int lbpws: 1; - unsigned int lbpws10: 1; - unsigned int lbpvpd: 1; - unsigned int ws10: 1; - unsigned int ws16: 1; - unsigned int rc_basis: 2; - unsigned int zoned: 2; - unsigned int urswrz: 1; - unsigned int security: 1; - unsigned int ignore_medium_access_errors: 1; -}; - -struct bio_integrity_payload { - struct bio *bip_bio; - struct bvec_iter bip_iter; - short unsigned int bip_slab; - short unsigned int bip_vcnt; - short unsigned int bip_max_vcnt; - short unsigned int bip_flags; - struct bvec_iter bio_iter; - struct work_struct bip_work; - struct bio_vec *bip_vec; - struct bio_vec bip_inline_vecs[0]; -}; - -struct nvme_user_io { - __u8 opcode; - __u8 flags; - __u16 control; - __u16 nblocks; - __u16 rsvd; - __u64 metadata; - __u64 addr; - __u64 slba; - __u32 dsmgmt; - __u32 reftag; - __u16 apptag; - __u16 appmask; -}; - -struct nvme_passthru_cmd { - __u8 opcode; - __u8 flags; - __u16 rsvd1; - __u32 nsid; - __u32 cdw2; - __u32 cdw3; - __u64 metadata; - __u64 addr; - __u32 metadata_len; - __u32 data_len; - __u32 cdw10; - __u32 cdw11; - __u32 cdw12; - __u32 cdw13; - __u32 cdw14; - __u32 cdw15; - __u32 timeout_ms; - __u32 result; -}; - -struct nvme_passthru_cmd64 { - __u8 opcode; - __u8 flags; - __u16 rsvd1; - __u32 nsid; - __u32 cdw2; - __u32 cdw3; - __u64 metadata; - __u64 addr; - __u32 metadata_len; - __u32 data_len; - __u32 cdw10; - __u32 cdw11; - __u32 cdw12; - __u32 cdw13; - __u32 cdw14; - __u32 cdw15; - __u32 timeout_ms; - __u32 rsvd2; - __u64 result; -}; - -struct nvme_id_power_state { - __le16 max_power; - __u8 rsvd2; - __u8 flags; - __le32 entry_lat; - __le32 exit_lat; - __u8 read_tput; - __u8 read_lat; - __u8 write_tput; - __u8 write_lat; - __le16 idle_power; - __u8 idle_scale; - __u8 rsvd19; - __le16 active_power; - __u8 active_work_scale; - __u8 rsvd23[9]; -}; - -enum { - NVME_PS_FLAGS_MAX_POWER_SCALE = 1, - NVME_PS_FLAGS_NON_OP_STATE = 2, -}; - -enum nvme_ctrl_attr { - NVME_CTRL_ATTR_HID_128_BIT = 1, - NVME_CTRL_ATTR_TBKAS = 64, -}; - -struct nvme_id_ctrl { - __le16 vid; - __le16 ssvid; - char sn[20]; - char mn[40]; - char fr[8]; - __u8 rab; - __u8 ieee[3]; - __u8 cmic; - __u8 mdts; - __le16 cntlid; - __le32 ver; - __le32 rtd3r; - __le32 rtd3e; - __le32 oaes; - __le32 ctratt; - __u8 rsvd100[28]; - __le16 crdt1; - __le16 crdt2; - __le16 crdt3; - __u8 rsvd134[122]; - __le16 oacs; - __u8 acl; - __u8 aerl; - __u8 frmw; - __u8 lpa; - __u8 elpe; - __u8 npss; - __u8 avscc; - __u8 apsta; - __le16 wctemp; - __le16 cctemp; - __le16 mtfa; - __le32 hmpre; - __le32 hmmin; - __u8 tnvmcap[16]; - __u8 unvmcap[16]; - __le32 rpmbs; - __le16 edstt; - __u8 dsto; - __u8 fwug; - __le16 kas; - __le16 hctma; - __le16 mntmt; - __le16 mxtmt; - __le32 sanicap; - __le32 hmminds; - __le16 hmmaxd; - __u8 rsvd338[4]; - __u8 anatt; - __u8 anacap; - __le32 anagrpmax; - __le32 nanagrpid; - __u8 rsvd352[160]; - __u8 sqes; - __u8 cqes; - __le16 maxcmd; - __le32 nn; - __le16 oncs; - __le16 fuses; - __u8 fna; - __u8 vwc; - __le16 awun; - __le16 awupf; - __u8 nvscc; - __u8 nwpc; - __le16 acwu; - __u8 rsvd534[2]; - __le32 sgls; - __le32 mnan; - __u8 rsvd544[224]; - char subnqn[256]; - __u8 rsvd1024[768]; - __le32 ioccsz; - __le32 iorcsz; - __le16 icdoff; - __u8 ctrattr; - __u8 msdbd; - __u8 rsvd1804[244]; - struct nvme_id_power_state psd[32]; - __u8 vs[1024]; -}; - -enum { - NVME_CTRL_CMIC_MULTI_CTRL = 2, - NVME_CTRL_CMIC_ANA = 8, - NVME_CTRL_ONCS_COMPARE = 1, - NVME_CTRL_ONCS_WRITE_UNCORRECTABLE = 2, - NVME_CTRL_ONCS_DSM = 4, - NVME_CTRL_ONCS_WRITE_ZEROES = 8, - NVME_CTRL_ONCS_RESERVATIONS = 32, - NVME_CTRL_ONCS_TIMESTAMP = 64, - NVME_CTRL_VWC_PRESENT = 1, - NVME_CTRL_OACS_SEC_SUPP = 1, - NVME_CTRL_OACS_DIRECTIVES = 32, - NVME_CTRL_OACS_DBBUF_SUPP = 256, - NVME_CTRL_LPA_CMD_EFFECTS_LOG = 2, - NVME_CTRL_CTRATT_128_ID = 1, - NVME_CTRL_CTRATT_NON_OP_PSP = 2, - NVME_CTRL_CTRATT_NVM_SETS = 4, - NVME_CTRL_CTRATT_READ_RECV_LVLS = 8, - NVME_CTRL_CTRATT_ENDURANCE_GROUPS = 16, - NVME_CTRL_CTRATT_PREDICTABLE_LAT = 32, - NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY = 128, - NVME_CTRL_CTRATT_UUID_LIST = 512, -}; - -struct nvme_lbaf { - __le16 ms; - __u8 ds; - __u8 rp; -}; - -struct nvme_id_ns { - __le64 nsze; - __le64 ncap; - __le64 nuse; - __u8 nsfeat; - __u8 nlbaf; - __u8 flbas; - __u8 mc; - __u8 dpc; - __u8 dps; - __u8 nmic; - __u8 rescap; - __u8 fpi; - __u8 dlfeat; - __le16 nawun; - __le16 nawupf; - __le16 nacwu; - __le16 nabsn; - __le16 nabo; - __le16 nabspf; - __le16 noiob; - __u8 nvmcap[16]; - __le16 npwg; - __le16 npwa; - __le16 npdg; - __le16 npda; - __le16 nows; - __u8 rsvd74[18]; - __le32 anagrpid; - __u8 rsvd96[3]; - __u8 nsattr; - __le16 nvmsetid; - __le16 endgid; - __u8 nguid[16]; - __u8 eui64[8]; - struct nvme_lbaf lbaf[16]; - __u8 rsvd192[192]; - __u8 vs[3712]; -}; - -enum { - NVME_ID_CNS_NS = 0, - NVME_ID_CNS_CTRL = 1, - NVME_ID_CNS_NS_ACTIVE_LIST = 2, - NVME_ID_CNS_NS_DESC_LIST = 3, - NVME_ID_CNS_CS_NS = 5, - NVME_ID_CNS_CS_CTRL = 6, - NVME_ID_CNS_NS_PRESENT_LIST = 16, - NVME_ID_CNS_NS_PRESENT = 17, - NVME_ID_CNS_CTRL_NS_LIST = 18, - NVME_ID_CNS_CTRL_LIST = 19, - NVME_ID_CNS_SCNDRY_CTRL_LIST = 21, - NVME_ID_CNS_NS_GRANULARITY = 22, - NVME_ID_CNS_UUID_LIST = 23, -}; - -enum { - NVME_CSI_NVM = 0, - NVME_CSI_ZNS = 2, -}; - -enum { - NVME_DIR_IDENTIFY = 0, - NVME_DIR_STREAMS = 1, - NVME_DIR_SND_ID_OP_ENABLE = 1, - NVME_DIR_SND_ST_OP_REL_ID = 1, - NVME_DIR_SND_ST_OP_REL_RSC = 2, - NVME_DIR_RCV_ID_OP_PARAM = 1, - NVME_DIR_RCV_ST_OP_PARAM = 1, - NVME_DIR_RCV_ST_OP_STATUS = 2, - NVME_DIR_RCV_ST_OP_RESOURCE = 3, - NVME_DIR_ENDIR = 1, -}; - -enum { - NVME_NS_FEAT_THIN = 1, - NVME_NS_FEAT_ATOMICS = 2, - NVME_NS_FEAT_IO_OPT = 16, - NVME_NS_ATTR_RO = 1, - NVME_NS_FLBAS_LBA_MASK = 15, - NVME_NS_FLBAS_META_EXT = 16, - NVME_NS_NMIC_SHARED = 1, - NVME_LBAF_RP_BEST = 0, - NVME_LBAF_RP_BETTER = 1, - NVME_LBAF_RP_GOOD = 2, - NVME_LBAF_RP_DEGRADED = 3, - NVME_NS_DPC_PI_LAST = 16, - NVME_NS_DPC_PI_FIRST = 8, - NVME_NS_DPC_PI_TYPE3 = 4, - NVME_NS_DPC_PI_TYPE2 = 2, - NVME_NS_DPC_PI_TYPE1 = 1, - NVME_NS_DPS_PI_FIRST = 8, - NVME_NS_DPS_PI_MASK = 7, - NVME_NS_DPS_PI_TYPE1 = 1, - NVME_NS_DPS_PI_TYPE2 = 2, - NVME_NS_DPS_PI_TYPE3 = 3, -}; - -struct nvme_ns_id_desc { - __u8 nidt; - __u8 nidl; - __le16 reserved; -}; - -enum { - NVME_NIDT_EUI64 = 1, - NVME_NIDT_NGUID = 2, - NVME_NIDT_UUID = 3, - NVME_NIDT_CSI = 4, -}; - -struct nvme_fw_slot_info_log { - __u8 afi; - __u8 rsvd1[7]; - __le64 frs[7]; - __u8 rsvd64[448]; -}; - -enum { - NVME_CMD_EFFECTS_CSUPP = 1, - NVME_CMD_EFFECTS_LBCC = 2, - NVME_CMD_EFFECTS_NCC = 4, - NVME_CMD_EFFECTS_NIC = 8, - NVME_CMD_EFFECTS_CCC = 16, - NVME_CMD_EFFECTS_CSE_MASK = 196608, - NVME_CMD_EFFECTS_UUID_SEL = 524288, -}; - -struct nvme_effects_log { - __le32 acs[256]; - __le32 iocs[256]; - __u8 resv[2048]; -}; - -enum { - NVME_AER_ERROR = 0, - NVME_AER_SMART = 1, - NVME_AER_NOTICE = 2, - NVME_AER_CSS = 6, - NVME_AER_VS = 7, -}; - -enum { - NVME_AER_NOTICE_NS_CHANGED = 0, - NVME_AER_NOTICE_FW_ACT_STARTING = 1, - NVME_AER_NOTICE_ANA = 3, - NVME_AER_NOTICE_DISC_CHANGED = 240, -}; - -enum { - NVME_AEN_CFG_NS_ATTR = 256, - NVME_AEN_CFG_FW_ACT = 512, - NVME_AEN_CFG_ANA_CHANGE = 2048, - NVME_AEN_CFG_DISC_CHANGE = 2147483648, -}; - -enum nvme_opcode { - nvme_cmd_flush = 0, - nvme_cmd_write = 1, - nvme_cmd_read = 2, - nvme_cmd_write_uncor = 4, - nvme_cmd_compare = 5, - nvme_cmd_write_zeroes = 8, - nvme_cmd_dsm = 9, - nvme_cmd_verify = 12, - nvme_cmd_resv_register = 13, - nvme_cmd_resv_report = 14, - nvme_cmd_resv_acquire = 17, - nvme_cmd_resv_release = 21, - nvme_cmd_zone_mgmt_send = 121, - nvme_cmd_zone_mgmt_recv = 122, - nvme_cmd_zone_append = 125, -}; - -struct nvme_sgl_desc { - __le64 addr; - __le32 length; - __u8 rsvd[3]; - __u8 type; -}; - -struct nvme_keyed_sgl_desc { - __le64 addr; - __u8 length[3]; - __u8 key[4]; - __u8 type; -}; - -union nvme_data_ptr { - struct { - __le64 prp1; - __le64 prp2; - }; - struct nvme_sgl_desc sgl; - struct nvme_keyed_sgl_desc ksgl; -}; - -enum { - NVME_CMD_FUSE_FIRST = 1, - NVME_CMD_FUSE_SECOND = 2, - NVME_CMD_SGL_METABUF = 64, - NVME_CMD_SGL_METASEG = 128, - NVME_CMD_SGL_ALL = 192, -}; - -struct nvme_common_command { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __le32 cdw2[2]; - __le64 metadata; - union nvme_data_ptr dptr; - __le32 cdw10; - __le32 cdw11; - __le32 cdw12; - __le32 cdw13; - __le32 cdw14; - __le32 cdw15; -}; - -struct nvme_rw_command { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2; - __le64 metadata; - union nvme_data_ptr dptr; - __le64 slba; - __le16 length; - __le16 control; - __le32 dsmgmt; - __le32 reftag; - __le16 apptag; - __le16 appmask; -}; - -enum { - NVME_RW_LR = 32768, - NVME_RW_FUA = 16384, - NVME_RW_APPEND_PIREMAP = 512, - NVME_RW_DSM_FREQ_UNSPEC = 0, - NVME_RW_DSM_FREQ_TYPICAL = 1, - NVME_RW_DSM_FREQ_RARE = 2, - NVME_RW_DSM_FREQ_READS = 3, - NVME_RW_DSM_FREQ_WRITES = 4, - NVME_RW_DSM_FREQ_RW = 5, - NVME_RW_DSM_FREQ_ONCE = 6, - NVME_RW_DSM_FREQ_PREFETCH = 7, - NVME_RW_DSM_FREQ_TEMP = 8, - NVME_RW_DSM_LATENCY_NONE = 0, - NVME_RW_DSM_LATENCY_IDLE = 16, - NVME_RW_DSM_LATENCY_NORM = 32, - NVME_RW_DSM_LATENCY_LOW = 48, - NVME_RW_DSM_SEQ_REQ = 64, - NVME_RW_DSM_COMPRESSED = 128, - NVME_RW_PRINFO_PRCHK_REF = 1024, - NVME_RW_PRINFO_PRCHK_APP = 2048, - NVME_RW_PRINFO_PRCHK_GUARD = 4096, - NVME_RW_PRINFO_PRACT = 8192, - NVME_RW_DTYPE_STREAMS = 16, -}; - -struct nvme_dsm_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __le32 nr; - __le32 attributes; - __u32 rsvd12[4]; -}; - -enum { - NVME_DSMGMT_IDR = 1, - NVME_DSMGMT_IDW = 2, - NVME_DSMGMT_AD = 4, -}; - -struct nvme_dsm_range { - __le32 cattr; - __le32 nlb; - __le64 slba; -}; - -struct nvme_write_zeroes_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2; - __le64 metadata; - union nvme_data_ptr dptr; - __le64 slba; - __le16 length; - __le16 control; - __le32 dsmgmt; - __le32 reftag; - __le16 apptag; - __le16 appmask; -}; - -enum nvme_zone_mgmt_action { - NVME_ZONE_CLOSE = 1, - NVME_ZONE_FINISH = 2, - NVME_ZONE_OPEN = 3, - NVME_ZONE_RESET = 4, - NVME_ZONE_OFFLINE = 5, - NVME_ZONE_SET_DESC_EXT = 16, -}; - -struct nvme_zone_mgmt_send_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __le32 cdw2[2]; - __le64 metadata; - union nvme_data_ptr dptr; - __le64 slba; - __le32 cdw12; - __u8 zsa; - __u8 select_all; - __u8 rsvd13[2]; - __le32 cdw14[2]; -}; - -struct nvme_zone_mgmt_recv_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __le64 rsvd2[2]; - union nvme_data_ptr dptr; - __le64 slba; - __le32 numd; - __u8 zra; - __u8 zrasf; - __u8 pr; - __u8 rsvd13; - __le32 cdw14[2]; -}; - -struct nvme_feat_auto_pst { - __le64 entries[32]; -}; - -struct nvme_feat_host_behavior { - __u8 acre; - __u8 resv1[511]; -}; - -enum { - NVME_ENABLE_ACRE = 1, -}; - -enum nvme_admin_opcode { - nvme_admin_delete_sq = 0, - nvme_admin_create_sq = 1, - nvme_admin_get_log_page = 2, - nvme_admin_delete_cq = 4, - nvme_admin_create_cq = 5, - nvme_admin_identify = 6, - nvme_admin_abort_cmd = 8, - nvme_admin_set_features = 9, - nvme_admin_get_features = 10, - nvme_admin_async_event = 12, - nvme_admin_ns_mgmt = 13, - nvme_admin_activate_fw = 16, - nvme_admin_download_fw = 17, - nvme_admin_dev_self_test = 20, - nvme_admin_ns_attach = 21, - nvme_admin_keep_alive = 24, - nvme_admin_directive_send = 25, - nvme_admin_directive_recv = 26, - nvme_admin_virtual_mgmt = 28, - nvme_admin_nvme_mi_send = 29, - nvme_admin_nvme_mi_recv = 30, - nvme_admin_dbbuf = 124, - nvme_admin_format_nvm = 128, - nvme_admin_security_send = 129, - nvme_admin_security_recv = 130, - nvme_admin_sanitize_nvm = 132, - nvme_admin_get_lba_status = 134, - nvme_admin_vendor_start = 192, -}; - -enum { - NVME_QUEUE_PHYS_CONTIG = 1, - NVME_CQ_IRQ_ENABLED = 2, - NVME_SQ_PRIO_URGENT = 0, - NVME_SQ_PRIO_HIGH = 2, - NVME_SQ_PRIO_MEDIUM = 4, - NVME_SQ_PRIO_LOW = 6, - NVME_FEAT_ARBITRATION = 1, - NVME_FEAT_POWER_MGMT = 2, - NVME_FEAT_LBA_RANGE = 3, - NVME_FEAT_TEMP_THRESH = 4, - NVME_FEAT_ERR_RECOVERY = 5, - NVME_FEAT_VOLATILE_WC = 6, - NVME_FEAT_NUM_QUEUES = 7, - NVME_FEAT_IRQ_COALESCE = 8, - NVME_FEAT_IRQ_CONFIG = 9, - NVME_FEAT_WRITE_ATOMIC = 10, - NVME_FEAT_ASYNC_EVENT = 11, - NVME_FEAT_AUTO_PST = 12, - NVME_FEAT_HOST_MEM_BUF = 13, - NVME_FEAT_TIMESTAMP = 14, - NVME_FEAT_KATO = 15, - NVME_FEAT_HCTM = 16, - NVME_FEAT_NOPSC = 17, - NVME_FEAT_RRL = 18, - NVME_FEAT_PLM_CONFIG = 19, - NVME_FEAT_PLM_WINDOW = 20, - NVME_FEAT_HOST_BEHAVIOR = 22, - NVME_FEAT_SANITIZE = 23, - NVME_FEAT_SW_PROGRESS = 128, - NVME_FEAT_HOST_ID = 129, - NVME_FEAT_RESV_MASK = 130, - NVME_FEAT_RESV_PERSIST = 131, - NVME_FEAT_WRITE_PROTECT = 132, - NVME_FEAT_VENDOR_START = 192, - NVME_FEAT_VENDOR_END = 255, - NVME_LOG_ERROR = 1, - NVME_LOG_SMART = 2, - NVME_LOG_FW_SLOT = 3, - NVME_LOG_CHANGED_NS = 4, - NVME_LOG_CMD_EFFECTS = 5, - NVME_LOG_DEVICE_SELF_TEST = 6, - NVME_LOG_TELEMETRY_HOST = 7, - NVME_LOG_TELEMETRY_CTRL = 8, - NVME_LOG_ENDURANCE_GROUP = 9, - NVME_LOG_ANA = 12, - NVME_LOG_DISC = 112, - NVME_LOG_RESERVATION = 128, - NVME_FWACT_REPL = 0, - NVME_FWACT_REPL_ACTV = 8, - NVME_FWACT_ACTV = 16, -}; - -struct nvme_identify { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __u8 cns; - __u8 rsvd3; - __le16 ctrlid; - __u8 rsvd11[3]; - __u8 csi; - __u32 rsvd12[4]; -}; - -struct nvme_features { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __le32 fid; - __le32 dword11; - __le32 dword12; - __le32 dword13; - __le32 dword14; - __le32 dword15; -}; - -struct nvme_create_cq { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - __le64 prp1; - __u64 rsvd8; - __le16 cqid; - __le16 qsize; - __le16 cq_flags; - __le16 irq_vector; - __u32 rsvd12[4]; -}; - -struct nvme_create_sq { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - __le64 prp1; - __u64 rsvd8; - __le16 sqid; - __le16 qsize; - __le16 sq_flags; - __le16 cqid; - __u32 rsvd12[4]; -}; - -struct nvme_delete_queue { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[9]; - __le16 qid; - __u16 rsvd10; - __u32 rsvd11[5]; -}; - -struct nvme_abort_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[9]; - __le16 sqid; - __u16 cid; - __u32 rsvd11[5]; -}; - -struct nvme_download_firmware { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - union nvme_data_ptr dptr; - __le32 numd; - __le32 offset; - __u32 rsvd12[4]; -}; - -struct nvme_format_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[4]; - __le32 cdw10; - __u32 rsvd11[5]; -}; - -struct nvme_get_log_page_command { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __u8 lid; - __u8 lsp; - __le16 numdl; - __le16 numdu; - __u16 rsvd11; - union { - struct { - __le32 lpol; - __le32 lpou; - }; - __le64 lpo; - }; - __u8 rsvd14[3]; - __u8 csi; - __u32 rsvd15; -}; - -struct nvme_directive_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __le32 numd; - __u8 doper; - __u8 dtype; - __le16 dspec; - __u8 endir; - __u8 tdtype; - __u16 rsvd15; - __u32 rsvd16[3]; -}; - -enum nvmf_fabrics_opcode { - nvme_fabrics_command = 127, -}; - -enum nvmf_capsule_command { - nvme_fabrics_type_property_set = 0, - nvme_fabrics_type_connect = 1, - nvme_fabrics_type_property_get = 4, -}; - -struct nvmf_common_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[35]; - __u8 ts[24]; -}; - -struct nvmf_connect_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[19]; - union nvme_data_ptr dptr; - __le16 recfmt; - __le16 qid; - __le16 sqsize; - __u8 cattr; - __u8 resv3; - __le32 kato; - __u8 resv4[12]; -}; - -struct nvmf_property_set_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[35]; - __u8 attrib; - __u8 resv3[3]; - __le32 offset; - __le64 value; - __u8 resv4[8]; -}; - -struct nvmf_property_get_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[35]; - __u8 attrib; - __u8 resv3[3]; - __le32 offset; - __u8 resv4[16]; -}; - -struct nvme_dbbuf { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - __le64 prp1; - __le64 prp2; - __u32 rsvd12[6]; -}; - -struct streams_directive_params { - __le16 msl; - __le16 nssa; - __le16 nsso; - __u8 rsvd[10]; - __le32 sws; - __le16 sgs; - __le16 nsa; - __le16 nso; - __u8 rsvd2[6]; -}; - -struct nvme_command { - union { - struct nvme_common_command common; - struct nvme_rw_command rw; - struct nvme_identify identify; - struct nvme_features features; - struct nvme_create_cq create_cq; - struct nvme_create_sq create_sq; - struct nvme_delete_queue delete_queue; - struct nvme_download_firmware dlfw; - struct nvme_format_cmd format; - struct nvme_dsm_cmd dsm; - struct nvme_write_zeroes_cmd write_zeroes; - struct nvme_zone_mgmt_send_cmd zms; - struct nvme_zone_mgmt_recv_cmd zmr; - struct nvme_abort_cmd abort; - struct nvme_get_log_page_command get_log_page; - struct nvmf_common_command fabrics; - struct nvmf_connect_command connect; - struct nvmf_property_set_command prop_set; - struct nvmf_property_get_command prop_get; - struct nvme_dbbuf dbbuf; - struct nvme_directive_cmd directive; - }; -}; - -enum { - NVME_SC_SUCCESS = 0, - NVME_SC_INVALID_OPCODE = 1, - NVME_SC_INVALID_FIELD = 2, - NVME_SC_CMDID_CONFLICT = 3, - NVME_SC_DATA_XFER_ERROR = 4, - NVME_SC_POWER_LOSS = 5, - NVME_SC_INTERNAL = 6, - NVME_SC_ABORT_REQ = 7, - NVME_SC_ABORT_QUEUE = 8, - NVME_SC_FUSED_FAIL = 9, - NVME_SC_FUSED_MISSING = 10, - NVME_SC_INVALID_NS = 11, - NVME_SC_CMD_SEQ_ERROR = 12, - NVME_SC_SGL_INVALID_LAST = 13, - NVME_SC_SGL_INVALID_COUNT = 14, - NVME_SC_SGL_INVALID_DATA = 15, - NVME_SC_SGL_INVALID_METADATA = 16, - NVME_SC_SGL_INVALID_TYPE = 17, - NVME_SC_SGL_INVALID_OFFSET = 22, - NVME_SC_SGL_INVALID_SUBTYPE = 23, - NVME_SC_SANITIZE_FAILED = 28, - NVME_SC_SANITIZE_IN_PROGRESS = 29, - NVME_SC_NS_WRITE_PROTECTED = 32, - NVME_SC_CMD_INTERRUPTED = 33, - NVME_SC_LBA_RANGE = 128, - NVME_SC_CAP_EXCEEDED = 129, - NVME_SC_NS_NOT_READY = 130, - NVME_SC_RESERVATION_CONFLICT = 131, - NVME_SC_CQ_INVALID = 256, - NVME_SC_QID_INVALID = 257, - NVME_SC_QUEUE_SIZE = 258, - NVME_SC_ABORT_LIMIT = 259, - NVME_SC_ABORT_MISSING = 260, - NVME_SC_ASYNC_LIMIT = 261, - NVME_SC_FIRMWARE_SLOT = 262, - NVME_SC_FIRMWARE_IMAGE = 263, - NVME_SC_INVALID_VECTOR = 264, - NVME_SC_INVALID_LOG_PAGE = 265, - NVME_SC_INVALID_FORMAT = 266, - NVME_SC_FW_NEEDS_CONV_RESET = 267, - NVME_SC_INVALID_QUEUE = 268, - NVME_SC_FEATURE_NOT_SAVEABLE = 269, - NVME_SC_FEATURE_NOT_CHANGEABLE = 270, - NVME_SC_FEATURE_NOT_PER_NS = 271, - NVME_SC_FW_NEEDS_SUBSYS_RESET = 272, - NVME_SC_FW_NEEDS_RESET = 273, - NVME_SC_FW_NEEDS_MAX_TIME = 274, - NVME_SC_FW_ACTIVATE_PROHIBITED = 275, - NVME_SC_OVERLAPPING_RANGE = 276, - NVME_SC_NS_INSUFFICIENT_CAP = 277, - NVME_SC_NS_ID_UNAVAILABLE = 278, - NVME_SC_NS_ALREADY_ATTACHED = 280, - NVME_SC_NS_IS_PRIVATE = 281, - NVME_SC_NS_NOT_ATTACHED = 282, - NVME_SC_THIN_PROV_NOT_SUPP = 283, - NVME_SC_CTRL_LIST_INVALID = 284, - NVME_SC_BP_WRITE_PROHIBITED = 286, - NVME_SC_PMR_SAN_PROHIBITED = 291, - NVME_SC_BAD_ATTRIBUTES = 384, - NVME_SC_INVALID_PI = 385, - NVME_SC_READ_ONLY = 386, - NVME_SC_ONCS_NOT_SUPPORTED = 387, - NVME_SC_CONNECT_FORMAT = 384, - NVME_SC_CONNECT_CTRL_BUSY = 385, - NVME_SC_CONNECT_INVALID_PARAM = 386, - NVME_SC_CONNECT_RESTART_DISC = 387, - NVME_SC_CONNECT_INVALID_HOST = 388, - NVME_SC_DISCOVERY_RESTART = 400, - NVME_SC_AUTH_REQUIRED = 401, - NVME_SC_ZONE_BOUNDARY_ERROR = 440, - NVME_SC_ZONE_FULL = 441, - NVME_SC_ZONE_READ_ONLY = 442, - NVME_SC_ZONE_OFFLINE = 443, - NVME_SC_ZONE_INVALID_WRITE = 444, - NVME_SC_ZONE_TOO_MANY_ACTIVE = 445, - NVME_SC_ZONE_TOO_MANY_OPEN = 446, - NVME_SC_ZONE_INVALID_TRANSITION = 447, - NVME_SC_WRITE_FAULT = 640, - NVME_SC_READ_ERROR = 641, - NVME_SC_GUARD_CHECK = 642, - NVME_SC_APPTAG_CHECK = 643, - NVME_SC_REFTAG_CHECK = 644, - NVME_SC_COMPARE_FAILED = 645, - NVME_SC_ACCESS_DENIED = 646, - NVME_SC_UNWRITTEN_BLOCK = 647, - NVME_SC_ANA_PERSISTENT_LOSS = 769, - NVME_SC_ANA_INACCESSIBLE = 770, - NVME_SC_ANA_TRANSITION = 771, - NVME_SC_HOST_PATH_ERROR = 880, - NVME_SC_HOST_ABORTED_CMD = 881, - NVME_SC_CRD = 6144, - NVME_SC_DNR = 16384, -}; - -union nvme_result { - __le16 u16; - __le32 u32; - __le64 u64; -}; - -struct nvm_dev; - -enum nvme_quirks { - NVME_QUIRK_STRIPE_SIZE = 1, - NVME_QUIRK_IDENTIFY_CNS = 2, - NVME_QUIRK_DEALLOCATE_ZEROES = 4, - NVME_QUIRK_DELAY_BEFORE_CHK_RDY = 8, - NVME_QUIRK_NO_APST = 16, - NVME_QUIRK_NO_DEEPEST_PS = 32, - NVME_QUIRK_LIGHTNVM = 64, - NVME_QUIRK_MEDIUM_PRIO_SQ = 128, - NVME_QUIRK_IGNORE_DEV_SUBNQN = 256, - NVME_QUIRK_DISABLE_WRITE_ZEROES = 512, - NVME_QUIRK_SIMPLE_SUSPEND = 1024, - NVME_QUIRK_SINGLE_VECTOR = 2048, - NVME_QUIRK_128_BYTES_SQES = 4096, - NVME_QUIRK_SHARED_TAGS = 8192, - NVME_QUIRK_NO_TEMP_THRESH_CHANGE = 16384, - NVME_QUIRK_NO_NS_DESC_LIST = 32768, - NVME_QUIRK_SKIP_CID_GEN = 131072, -}; - -struct nvme_ctrl; - -struct nvme_request { - struct nvme_command *cmd; - union nvme_result result; - u8 genctr; - u8 retries; - u8 flags; - u16 status; - struct nvme_ctrl *ctrl; -}; - -enum nvme_ctrl_state { - NVME_CTRL_NEW = 0, - NVME_CTRL_LIVE = 1, - NVME_CTRL_RESETTING = 2, - NVME_CTRL_CONNECTING = 3, - NVME_CTRL_DELETING = 4, - NVME_CTRL_DELETING_NOIO = 5, - NVME_CTRL_DEAD = 6, -}; - -struct nvme_fault_inject {}; - -struct nvme_ctrl_ops; - -struct nvme_subsystem; - -struct nvmf_ctrl_options; - -struct nvme_ctrl { - bool comp_seen; - enum nvme_ctrl_state state; - bool identified; - spinlock_t lock; - struct mutex scan_lock; - const struct nvme_ctrl_ops *ops; - struct request_queue *admin_q; - struct request_queue *connect_q; - struct request_queue *fabrics_q; - struct device *dev; - int instance; - int numa_node; - struct blk_mq_tag_set *tagset; - struct blk_mq_tag_set *admin_tagset; - struct list_head namespaces; - struct rw_semaphore namespaces_rwsem; - struct device ctrl_device; - struct device *device; - struct cdev cdev; - struct work_struct reset_work; - struct work_struct delete_work; - wait_queue_head_t state_wq; - struct nvme_subsystem *subsys; - struct list_head subsys_entry; - struct opal_dev *opal_dev; - char name[12]; - u16 cntlid; - u32 ctrl_config; - u16 mtfa; - u32 queue_count; - u64 cap; - u32 max_hw_sectors; - u32 max_segments; - u32 max_integrity_segments; - u16 crdt[3]; - u16 oncs; - u16 oacs; - u16 nssa; - u16 nr_streams; - u16 sqsize; - u32 max_namespaces; - atomic_t abort_limit; - u8 vwc; - u32 vs; - u32 sgls; - u16 kas; - u8 npss; - u8 apsta; - u16 wctemp; - u16 cctemp; - u32 oaes; - u32 aen_result; - u32 ctratt; - unsigned int shutdown_timeout; - unsigned int kato; - bool subsystem; - long unsigned int quirks; - struct nvme_id_power_state psd[32]; - struct nvme_effects_log *effects; - struct xarray cels; - struct work_struct scan_work; - struct work_struct async_event_work; - struct delayed_work ka_work; - struct nvme_command ka_cmd; - struct work_struct fw_act_work; - long unsigned int events; - u64 ps_max_latency_us; - bool apst_enabled; - u32 hmpre; - u32 hmmin; - u32 hmminds; - u16 hmmaxd; - u32 ioccsz; - u32 iorcsz; - u16 icdoff; - u16 maxcmd; - int nr_reconnects; - struct nvmf_ctrl_options *opts; - struct page *discard_page; - long unsigned int discard_page_busy; - struct nvme_fault_inject fault_inject; -}; - -enum { - NVME_REQ_CANCELLED = 1, - NVME_REQ_USERCMD = 2, -}; - -struct nvme_ctrl_ops { - const char *name; - struct module *module; - unsigned int flags; - int (*reg_read32)(struct nvme_ctrl *, u32, u32 *); - int (*reg_write32)(struct nvme_ctrl *, u32, u32); - int (*reg_read64)(struct nvme_ctrl *, u32, u64 *); - void (*free_ctrl)(struct nvme_ctrl *); - void (*submit_async_event)(struct nvme_ctrl *); - void (*delete_ctrl)(struct nvme_ctrl *); - int (*get_address)(struct nvme_ctrl *, char *, int); -}; - -struct nvme_subsystem { - int instance; - struct device dev; - struct kref ref; - struct list_head entry; - struct mutex lock; - struct list_head ctrls; - struct list_head nsheads; - char subnqn[223]; - char serial[20]; - char model[40]; - char firmware_rev[8]; - u8 cmic; - u16 vendor_id; - u16 awupf; - struct ida ns_ida; -}; - -struct nvmf_host; - -struct nvmf_ctrl_options { - unsigned int mask; - char *transport; - char *subsysnqn; - char *traddr; - char *trsvcid; - char *host_traddr; - size_t queue_size; - unsigned int nr_io_queues; - unsigned int reconnect_delay; - bool discovery_nqn; - bool duplicate_connect; - unsigned int kato; - struct nvmf_host *host; - int max_reconnects; - bool disable_sqflow; - bool hdr_digest; - bool data_digest; - unsigned int nr_write_queues; - unsigned int nr_poll_queues; - int tos; -}; - -struct nvme_ns_ids { - u8 eui64[8]; - u8 nguid[16]; - uuid_t uuid; - u8 csi; -}; - -struct nvme_ns_head { - struct list_head list; - struct srcu_struct srcu; - struct nvme_subsystem *subsys; - unsigned int ns_id; - struct nvme_ns_ids ids; - struct list_head entry; - struct kref ref; - bool shared; - int instance; - struct nvme_effects_log *effects; -}; - -enum nvme_ns_features { - NVME_NS_EXT_LBAS = 1, - NVME_NS_METADATA_SUPPORTED = 2, -}; - -struct nvme_ns { - struct list_head list; - struct nvme_ctrl *ctrl; - struct request_queue *queue; - struct gendisk *disk; - struct list_head siblings; - struct nvm_dev *ndev; - struct kref kref; - struct nvme_ns_head *head; - int lba_shift; - u16 ms; - u16 sgs; - u32 sws; - u8 pi_type; - long unsigned int features; - long unsigned int flags; - struct nvme_fault_inject fault_inject; -}; - -struct nvmf_host { - struct kref ref; - struct list_head list; - char nqn[223]; - uuid_t id; -}; - -struct trace_event_raw_nvme_setup_cmd { - struct trace_entry ent; - char disk[32]; - int ctrl_id; - int qid; - u8 opcode; - u8 flags; - u8 fctype; - u16 cid; - u32 nsid; - bool metadata; - u8 cdw10[24]; - char __data[0]; -}; - -struct trace_event_raw_nvme_complete_rq { - struct trace_entry ent; - char disk[32]; - int ctrl_id; - int qid; - int cid; - u64 result; - u8 retries; - u8 flags; - u16 status; - char __data[0]; -}; - -struct trace_event_raw_nvme_async_event { - struct trace_entry ent; - int ctrl_id; - u32 result; - char __data[0]; -}; - -struct trace_event_raw_nvme_sq { - struct trace_entry ent; - int ctrl_id; - char disk[32]; - int qid; - u16 sq_head; - u16 sq_tail; - char __data[0]; -}; - -struct trace_event_data_offsets_nvme_setup_cmd {}; - -struct trace_event_data_offsets_nvme_complete_rq {}; - -struct trace_event_data_offsets_nvme_async_event {}; - -struct trace_event_data_offsets_nvme_sq {}; - -typedef void (*btf_trace_nvme_setup_cmd)(void *, struct request *, struct nvme_command *); - -typedef void (*btf_trace_nvme_complete_rq)(void *, struct request *); - -typedef void (*btf_trace_nvme_async_event)(void *, struct nvme_ctrl *, u32); - -typedef void (*btf_trace_nvme_sq)(void *, struct request *, __le16, int); - -enum nvme_disposition { - COMPLETE = 0, - RETRY = 1, - FAILOVER = 2, -}; - -struct nvme_core_quirk_entry { - u16 vid; - const char *mn; - const char *fr; - long unsigned int quirks; -}; - -enum { - NVME_CMBSZ_SQS = 1, - NVME_CMBSZ_CQS = 2, - NVME_CMBSZ_LISTS = 4, - NVME_CMBSZ_RDS = 8, - NVME_CMBSZ_WDS = 16, - NVME_CMBSZ_SZ_SHIFT = 12, - NVME_CMBSZ_SZ_MASK = 1048575, - NVME_CMBSZ_SZU_SHIFT = 8, - NVME_CMBSZ_SZU_MASK = 15, -}; - -enum { - NVME_SGL_FMT_DATA_DESC = 0, - NVME_SGL_FMT_SEG_DESC = 2, - NVME_SGL_FMT_LAST_SEG_DESC = 3, - NVME_KEY_SGL_FMT_DATA_DESC = 4, - NVME_TRANSPORT_SGL_DATA_DESC = 5, -}; - -enum { - NVME_HOST_MEM_ENABLE = 1, - NVME_HOST_MEM_RETURN = 2, -}; - -struct nvme_host_mem_buf_desc { - __le64 addr; - __le32 size; - __u32 rsvd; -}; - -struct nvme_completion { - union nvme_result result; - __le16 sq_head; - __le16 sq_id; - __u16 command_id; - __le16 status; -}; - -struct nvme_queue; - -struct nvme_dev { - struct nvme_queue *queues; - struct blk_mq_tag_set tagset; - struct blk_mq_tag_set admin_tagset; - u32 *dbs; - struct device *dev; - struct dma_pool___2 *prp_page_pool; - struct dma_pool___2 *prp_small_pool; - unsigned int online_queues; - unsigned int max_qid; - unsigned int io_queues[3]; - unsigned int num_vecs; - u32 q_depth; - int io_sqes; - u32 db_stride; - void *bar; - long unsigned int bar_mapped_size; - struct work_struct remove_work; - struct mutex shutdown_lock; - bool subsystem; - u64 cmb_size; - bool cmb_use_sqes; - u32 cmbsz; - u32 cmbloc; - struct nvme_ctrl ctrl; - u32 last_ps; - mempool_t *iod_mempool; - u32 *dbbuf_dbs; - dma_addr_t dbbuf_dbs_dma_addr; - u32 *dbbuf_eis; - dma_addr_t dbbuf_eis_dma_addr; - u64 host_mem_size; - u32 nr_host_mem_descs; - dma_addr_t host_mem_descs_dma; - struct nvme_host_mem_buf_desc *host_mem_descs; - void **host_mem_desc_bufs; - unsigned int nr_allocated_queues; - unsigned int nr_write_queues; - unsigned int nr_poll_queues; -}; - -struct nvme_queue { - struct nvme_dev *dev; - spinlock_t sq_lock; - void *sq_cmds; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t cq_poll_lock; - struct nvme_completion *cqes; - dma_addr_t sq_dma_addr; - dma_addr_t cq_dma_addr; - u32 *q_db; - u32 q_depth; - u16 cq_vector; - u16 sq_tail; - u16 last_sq_tail; - u16 cq_head; - u16 qid; - u8 cq_phase; - u8 sqes; - long unsigned int flags; - u32 *dbbuf_sq_db; - u32 *dbbuf_cq_db; - u32 *dbbuf_sq_ei; - u32 *dbbuf_cq_ei; - struct completion delete_done; -}; - -struct nvme_iod { - struct nvme_request req; - struct nvme_queue *nvmeq; - bool use_sgl; - int aborted; - int npages; - int nents; - dma_addr_t first_dma; - unsigned int dma_len; - dma_addr_t meta_dma; - struct scatterlist *sg; -}; - -typedef void (*spi_res_release_t)(struct spi_controller *, struct spi_message *, void *); - -struct spi_res { - struct list_head entry; - spi_res_release_t release; - long long unsigned int data[0]; -}; - -struct spi_replaced_transfers; - -typedef void (*spi_replaced_release_t)(struct spi_controller *, struct spi_message *, struct spi_replaced_transfers *); - -struct spi_replaced_transfers { - spi_replaced_release_t release; - void *extradata; - struct list_head replaced_transfers; - struct list_head *replaced_after; - size_t inserted; - struct spi_transfer inserted_transfers[0]; -}; - -struct spi_board_info { - char modalias[32]; - const void *platform_data; - const struct property_entry *properties; - void *controller_data; - int irq; - u32 max_speed_hz; - u16 bus_num; - u16 chip_select; - u32 mode; -}; - -enum spi_mem_data_dir { - SPI_MEM_NO_DATA = 0, - SPI_MEM_DATA_IN = 1, - SPI_MEM_DATA_OUT = 2, -}; - -struct spi_mem_op { - struct { - u8 nbytes; - u8 buswidth; - u8 dtr: 1; - u16 opcode; - } cmd; - struct { - u8 nbytes; - u8 buswidth; - u8 dtr: 1; - u64 val; - } addr; - struct { - u8 nbytes; - u8 buswidth; - u8 dtr: 1; - } dummy; - struct { - u8 buswidth; - u8 dtr: 1; - enum spi_mem_data_dir dir; - unsigned int nbytes; - union { - void *in; - const void *out; - } buf; - } data; -}; - -struct spi_mem_dirmap_info { - struct spi_mem_op op_tmpl; - u64 offset; - u64 length; -}; - -struct spi_mem_dirmap_desc { - struct spi_mem *mem; - struct spi_mem_dirmap_info info; - unsigned int nodirmap; - void *priv; -}; - -struct spi_mem { - struct spi_device *spi; - void *drvpriv; - const char *name; -}; - -struct trace_event_raw_spi_controller { - struct trace_entry ent; - int bus_num; - char __data[0]; -}; - -struct trace_event_raw_spi_message { - struct trace_entry ent; - int bus_num; - int chip_select; - struct spi_message *msg; - char __data[0]; -}; - -struct trace_event_raw_spi_message_done { - struct trace_entry ent; - int bus_num; - int chip_select; - struct spi_message *msg; - unsigned int frame; - unsigned int actual; - char __data[0]; -}; - -struct trace_event_raw_spi_transfer { - struct trace_entry ent; - int bus_num; - int chip_select; - struct spi_transfer *xfer; - int len; - u32 __data_loc_rx_buf; - u32 __data_loc_tx_buf; - char __data[0]; -}; - -struct trace_event_data_offsets_spi_controller {}; - -struct trace_event_data_offsets_spi_message {}; - -struct trace_event_data_offsets_spi_message_done {}; - -struct trace_event_data_offsets_spi_transfer { - u32 rx_buf; - u32 tx_buf; -}; - -typedef void (*btf_trace_spi_controller_idle)(void *, struct spi_controller *); - -typedef void (*btf_trace_spi_controller_busy)(void *, struct spi_controller *); - -typedef void (*btf_trace_spi_message_submit)(void *, struct spi_message *); - -typedef void (*btf_trace_spi_message_start)(void *, struct spi_message *); - -typedef void (*btf_trace_spi_message_done)(void *, struct spi_message *); - -typedef void (*btf_trace_spi_transfer_start)(void *, struct spi_message *, struct spi_transfer *); - -typedef void (*btf_trace_spi_transfer_stop)(void *, struct spi_message *, struct spi_transfer *); - -struct boardinfo { - struct list_head list; - struct spi_board_info board_info; -}; - -struct spi_mem_driver { - struct spi_driver spidrv; - int (*probe)(struct spi_mem *); - int (*remove)(struct spi_mem *); - void (*shutdown)(struct spi_mem *); -}; - -struct ethtool_cmd { - __u32 cmd; - __u32 supported; - __u32 advertising; - __u16 speed; - __u8 duplex; - __u8 port; - __u8 phy_address; - __u8 transceiver; - __u8 autoneg; - __u8 mdio_support; - __u32 maxtxpkt; - __u32 maxrxpkt; - __u16 speed_hi; - __u8 eth_tp_mdix; - __u8 eth_tp_mdix_ctrl; - __u32 lp_advertising; - __u32 reserved[2]; -}; - -enum netdev_state_t { - __LINK_STATE_START = 0, - __LINK_STATE_PRESENT = 1, - __LINK_STATE_NOCARRIER = 2, - __LINK_STATE_LINKWATCH_PENDING = 3, - __LINK_STATE_DORMANT = 4, - __LINK_STATE_TESTING = 5, -}; - -struct mii_ioctl_data { - __u16 phy_id; - __u16 reg_num; - __u16 val_in; - __u16 val_out; -}; - -struct mii_if_info { - int phy_id; - int advertising; - int phy_id_mask; - int reg_num_mask; - unsigned int full_duplex: 1; - unsigned int force_media: 1; - unsigned int supports_gmii: 1; - struct net_device *dev; - int (*mdio_read)(struct net_device *, int, int); - void (*mdio_write)(struct net_device *, int, int, int); -}; - -struct devprobe2 { - struct net_device * (*probe)(int); - int status; -}; - -enum { - NETIF_F_SG_BIT = 0, - NETIF_F_IP_CSUM_BIT = 1, - __UNUSED_NETIF_F_1 = 2, - NETIF_F_HW_CSUM_BIT = 3, - NETIF_F_IPV6_CSUM_BIT = 4, - NETIF_F_HIGHDMA_BIT = 5, - NETIF_F_FRAGLIST_BIT = 6, - NETIF_F_HW_VLAN_CTAG_TX_BIT = 7, - NETIF_F_HW_VLAN_CTAG_RX_BIT = 8, - NETIF_F_HW_VLAN_CTAG_FILTER_BIT = 9, - NETIF_F_VLAN_CHALLENGED_BIT = 10, - NETIF_F_GSO_BIT = 11, - NETIF_F_LLTX_BIT = 12, - NETIF_F_NETNS_LOCAL_BIT = 13, - NETIF_F_GRO_BIT = 14, - NETIF_F_LRO_BIT = 15, - NETIF_F_GSO_SHIFT = 16, - NETIF_F_TSO_BIT = 16, - NETIF_F_GSO_ROBUST_BIT = 17, - NETIF_F_TSO_ECN_BIT = 18, - NETIF_F_TSO_MANGLEID_BIT = 19, - NETIF_F_TSO6_BIT = 20, - NETIF_F_FSO_BIT = 21, - NETIF_F_GSO_GRE_BIT = 22, - NETIF_F_GSO_GRE_CSUM_BIT = 23, - NETIF_F_GSO_IPXIP4_BIT = 24, - NETIF_F_GSO_IPXIP6_BIT = 25, - NETIF_F_GSO_UDP_TUNNEL_BIT = 26, - NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT = 27, - NETIF_F_GSO_PARTIAL_BIT = 28, - NETIF_F_GSO_TUNNEL_REMCSUM_BIT = 29, - NETIF_F_GSO_SCTP_BIT = 30, - NETIF_F_GSO_ESP_BIT = 31, - NETIF_F_GSO_UDP_BIT = 32, - NETIF_F_GSO_UDP_L4_BIT = 33, - NETIF_F_GSO_FRAGLIST_BIT = 34, - NETIF_F_GSO_LAST = 34, - NETIF_F_FCOE_CRC_BIT = 35, - NETIF_F_SCTP_CRC_BIT = 36, - NETIF_F_FCOE_MTU_BIT = 37, - NETIF_F_NTUPLE_BIT = 38, - NETIF_F_RXHASH_BIT = 39, - NETIF_F_RXCSUM_BIT = 40, - NETIF_F_NOCACHE_COPY_BIT = 41, - NETIF_F_LOOPBACK_BIT = 42, - NETIF_F_RXFCS_BIT = 43, - NETIF_F_RXALL_BIT = 44, - NETIF_F_HW_VLAN_STAG_TX_BIT = 45, - NETIF_F_HW_VLAN_STAG_RX_BIT = 46, - NETIF_F_HW_VLAN_STAG_FILTER_BIT = 47, - NETIF_F_HW_L2FW_DOFFLOAD_BIT = 48, - NETIF_F_HW_TC_BIT = 49, - NETIF_F_HW_ESP_BIT = 50, - NETIF_F_HW_ESP_TX_CSUM_BIT = 51, - NETIF_F_RX_UDP_TUNNEL_PORT_BIT = 52, - NETIF_F_HW_TLS_TX_BIT = 53, - NETIF_F_HW_TLS_RX_BIT = 54, - NETIF_F_GRO_HW_BIT = 55, - NETIF_F_HW_TLS_RECORD_BIT = 56, - NETIF_F_GRO_FRAGLIST_BIT = 57, - NETIF_F_HW_MACSEC_BIT = 58, - NETDEV_FEATURE_COUNT = 59, -}; - -enum { - SKBTX_HW_TSTAMP = 1, - SKBTX_SW_TSTAMP = 2, - SKBTX_IN_PROGRESS = 4, - SKBTX_DEV_ZEROCOPY = 8, - SKBTX_WIFI_STATUS = 16, - SKBTX_SHARED_FRAG = 32, - SKBTX_SCHED_TSTAMP = 64, -}; - -enum netdev_priv_flags { - IFF_802_1Q_VLAN = 1, - IFF_EBRIDGE = 2, - IFF_BONDING = 4, - IFF_ISATAP = 8, - IFF_WAN_HDLC = 16, - IFF_XMIT_DST_RELEASE = 32, - IFF_DONT_BRIDGE = 64, - IFF_DISABLE_NETPOLL = 128, - IFF_MACVLAN_PORT = 256, - IFF_BRIDGE_PORT = 512, - IFF_OVS_DATAPATH = 1024, - IFF_TX_SKB_SHARING = 2048, - IFF_UNICAST_FLT = 4096, - IFF_TEAM_PORT = 8192, - IFF_SUPP_NOFCS = 16384, - IFF_LIVE_ADDR_CHANGE = 32768, - IFF_MACVLAN = 65536, - IFF_XMIT_DST_RELEASE_PERM = 131072, - IFF_L3MDEV_MASTER = 262144, - IFF_NO_QUEUE = 524288, - IFF_OPENVSWITCH = 1048576, - IFF_L3MDEV_SLAVE = 2097152, - IFF_TEAM = 4194304, - IFF_RXFH_CONFIGURED = 8388608, - IFF_PHONY_HEADROOM = 16777216, - IFF_MACSEC = 33554432, - IFF_NO_RX_HANDLER = 67108864, - IFF_FAILOVER = 134217728, - IFF_FAILOVER_SLAVE = 268435456, - IFF_L3MDEV_RX_HANDLER = 536870912, - IFF_LIVE_RENAME_OK = 1073741824, -}; - -struct mdio_board_info { - const char *bus_id; - char modalias[32]; - int mdio_addr; - const void *platform_data; -}; - -struct mdio_board_entry { - struct list_head list; - struct mdio_board_info board_info; -}; - -struct mdiobus_devres { - struct mii_bus *mii; -}; - -enum { - ETHTOOL_MSG_KERNEL_NONE = 0, - ETHTOOL_MSG_STRSET_GET_REPLY = 1, - ETHTOOL_MSG_LINKINFO_GET_REPLY = 2, - ETHTOOL_MSG_LINKINFO_NTF = 3, - ETHTOOL_MSG_LINKMODES_GET_REPLY = 4, - ETHTOOL_MSG_LINKMODES_NTF = 5, - ETHTOOL_MSG_LINKSTATE_GET_REPLY = 6, - ETHTOOL_MSG_DEBUG_GET_REPLY = 7, - ETHTOOL_MSG_DEBUG_NTF = 8, - ETHTOOL_MSG_WOL_GET_REPLY = 9, - ETHTOOL_MSG_WOL_NTF = 10, - ETHTOOL_MSG_FEATURES_GET_REPLY = 11, - ETHTOOL_MSG_FEATURES_SET_REPLY = 12, - ETHTOOL_MSG_FEATURES_NTF = 13, - ETHTOOL_MSG_PRIVFLAGS_GET_REPLY = 14, - ETHTOOL_MSG_PRIVFLAGS_NTF = 15, - ETHTOOL_MSG_RINGS_GET_REPLY = 16, - ETHTOOL_MSG_RINGS_NTF = 17, - ETHTOOL_MSG_CHANNELS_GET_REPLY = 18, - ETHTOOL_MSG_CHANNELS_NTF = 19, - ETHTOOL_MSG_COALESCE_GET_REPLY = 20, - ETHTOOL_MSG_COALESCE_NTF = 21, - ETHTOOL_MSG_PAUSE_GET_REPLY = 22, - ETHTOOL_MSG_PAUSE_NTF = 23, - ETHTOOL_MSG_EEE_GET_REPLY = 24, - ETHTOOL_MSG_EEE_NTF = 25, - ETHTOOL_MSG_TSINFO_GET_REPLY = 26, - ETHTOOL_MSG_CABLE_TEST_NTF = 27, - ETHTOOL_MSG_CABLE_TEST_TDR_NTF = 28, - ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY = 29, - __ETHTOOL_MSG_KERNEL_CNT = 30, - ETHTOOL_MSG_KERNEL_MAX = 29, -}; - -struct phy_setting { - u32 speed; - u8 duplex; - u8 bit; -}; - -struct ethtool_phy_ops { - int (*get_sset_count)(struct phy_device *); - int (*get_strings)(struct phy_device *, u8 *); - int (*get_stats)(struct phy_device *, struct ethtool_stats *, u64 *); - int (*start_cable_test)(struct phy_device *, struct netlink_ext_ack *); - int (*start_cable_test_tdr)(struct phy_device *, struct netlink_ext_ack *, const struct phy_tdr_config *); -}; - -struct phy_fixup { - struct list_head list; - char bus_id[64]; - u32 phy_uid; - u32 phy_uid_mask; - int (*run)(struct phy_device *); -}; - -struct sfp_eeprom_base { - u8 phys_id; - u8 phys_ext_id; - u8 connector; - u8 if_1x_copper_passive: 1; - u8 if_1x_copper_active: 1; - u8 if_1x_lx: 1; - u8 if_1x_sx: 1; - u8 e10g_base_sr: 1; - u8 e10g_base_lr: 1; - u8 e10g_base_lrm: 1; - u8 e10g_base_er: 1; - u8 sonet_oc3_short_reach: 1; - u8 sonet_oc3_smf_intermediate_reach: 1; - u8 sonet_oc3_smf_long_reach: 1; - u8 unallocated_5_3: 1; - u8 sonet_oc12_short_reach: 1; - u8 sonet_oc12_smf_intermediate_reach: 1; - u8 sonet_oc12_smf_long_reach: 1; - u8 unallocated_5_7: 1; - u8 sonet_oc48_short_reach: 1; - u8 sonet_oc48_intermediate_reach: 1; - u8 sonet_oc48_long_reach: 1; - u8 sonet_reach_bit2: 1; - u8 sonet_reach_bit1: 1; - u8 sonet_oc192_short_reach: 1; - u8 escon_smf_1310_laser: 1; - u8 escon_mmf_1310_led: 1; - u8 e1000_base_sx: 1; - u8 e1000_base_lx: 1; - u8 e1000_base_cx: 1; - u8 e1000_base_t: 1; - u8 e100_base_lx: 1; - u8 e100_base_fx: 1; - u8 e_base_bx10: 1; - u8 e_base_px: 1; - u8 fc_tech_electrical_inter_enclosure: 1; - u8 fc_tech_lc: 1; - u8 fc_tech_sa: 1; - u8 fc_ll_m: 1; - u8 fc_ll_l: 1; - u8 fc_ll_i: 1; - u8 fc_ll_s: 1; - u8 fc_ll_v: 1; - u8 unallocated_8_0: 1; - u8 unallocated_8_1: 1; - u8 sfp_ct_passive: 1; - u8 sfp_ct_active: 1; - u8 fc_tech_ll: 1; - u8 fc_tech_sl: 1; - u8 fc_tech_sn: 1; - u8 fc_tech_electrical_intra_enclosure: 1; - u8 fc_media_sm: 1; - u8 unallocated_9_1: 1; - u8 fc_media_m5: 1; - u8 fc_media_m6: 1; - u8 fc_media_tv: 1; - u8 fc_media_mi: 1; - u8 fc_media_tp: 1; - u8 fc_media_tw: 1; - u8 fc_speed_100: 1; - u8 unallocated_10_1: 1; - u8 fc_speed_200: 1; - u8 fc_speed_3200: 1; - u8 fc_speed_400: 1; - u8 fc_speed_1600: 1; - u8 fc_speed_800: 1; - u8 fc_speed_1200: 1; - u8 encoding; - u8 br_nominal; - u8 rate_id; - u8 link_len[6]; - char vendor_name[16]; - u8 extended_cc; - char vendor_oui[3]; - char vendor_pn[16]; - char vendor_rev[4]; - union { - __be16 optical_wavelength; - __be16 cable_compliance; - struct { - u8 sff8431_app_e: 1; - u8 fc_pi_4_app_h: 1; - u8 reserved60_2: 6; - u8 reserved61: 8; - } passive; - struct { - u8 sff8431_app_e: 1; - u8 fc_pi_4_app_h: 1; - u8 sff8431_lim: 1; - u8 fc_pi_4_lim: 1; - u8 reserved60_4: 4; - u8 reserved61: 8; - } active; - }; - u8 reserved62; - u8 cc_base; -}; - -struct sfp_eeprom_ext { - __be16 options; - u8 br_max; - u8 br_min; - char vendor_sn[16]; - char datecode[8]; - u8 diagmon; - u8 enhopts; - u8 sff8472_compliance; - u8 cc_ext; -}; - -struct sfp_eeprom_id { - struct sfp_eeprom_base base; - struct sfp_eeprom_ext ext; -}; - -struct sfp_upstream_ops { - void (*attach)(void *, struct sfp_bus *); - void (*detach)(void *, struct sfp_bus *); - int (*module_insert)(void *, const struct sfp_eeprom_id *); - void (*module_remove)(void *); - int (*module_start)(void *); - void (*module_stop)(void *); - void (*link_down)(void *); - void (*link_up)(void *); - int (*connect_phy)(void *, struct phy_device *); - void (*disconnect_phy)(void *); -}; - -struct trace_event_raw_mdio_access { - struct trace_entry ent; - char busid[61]; - char read; - u8 addr; - u16 val; - unsigned int regnum; - char __data[0]; -}; - -struct trace_event_data_offsets_mdio_access {}; - -typedef void (*btf_trace_mdio_access)(void *, struct mii_bus *, char, u8, unsigned int, u16, int); - -struct mdio_bus_stat_attr { - int addr; - unsigned int field_offset; -}; - -struct mdio_driver { - struct mdio_driver_common mdiodrv; - int (*probe)(struct mdio_device *); - void (*remove)(struct mdio_device *); - void (*shutdown)(struct mdio_device *); -}; - -struct fixed_phy_status { - int link; - int speed; - int duplex; - int pause; - int asym_pause; -}; - -struct swmii_regs { - u16 bmsr; - u16 lpa; - u16 lpagb; - u16 estat; -}; - -enum { - SWMII_SPEED_10 = 0, - SWMII_SPEED_100 = 1, - SWMII_SPEED_1000 = 2, - SWMII_DUPLEX_HALF = 0, - SWMII_DUPLEX_FULL = 1, -}; - -enum phy_tunable_id { - ETHTOOL_PHY_ID_UNSPEC = 0, - ETHTOOL_PHY_DOWNSHIFT = 1, - ETHTOOL_PHY_FAST_LINK_DOWN = 2, - ETHTOOL_PHY_EDPD = 3, - __ETHTOOL_PHY_TUNABLE_COUNT = 4, -}; - -struct mdio_device_id { - __u32 phy_id; - __u32 phy_id_mask; -}; - -struct bcm7xxx_phy_priv { - u64 *stats; - struct clk *clk; -}; - -struct bcm7xxx_regs { - int reg; - u16 value; -}; - -enum { - ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC = 0, - ETHTOOL_A_CABLE_RESULT_CODE_OK = 1, - ETHTOOL_A_CABLE_RESULT_CODE_OPEN = 2, - ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT = 3, - ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT = 4, -}; - -enum { - ETHTOOL_A_CABLE_PAIR_A = 0, - ETHTOOL_A_CABLE_PAIR_B = 1, - ETHTOOL_A_CABLE_PAIR_C = 2, - ETHTOOL_A_CABLE_PAIR_D = 3, -}; - -struct bcm_phy_hw_stat { - const char *string; - u8 reg; - u8 shift; - u8 bits; -}; - -struct bcm53xx_phy_priv { - u64 *stats; -}; - -struct fixed_mdio_bus { - struct mii_bus *mii_bus; - struct list_head phys; -}; - -struct fixed_phy { - int addr; - struct phy_device *phydev; - struct fixed_phy_status status; - bool no_carrier; - int (*link_update)(struct net_device *, struct fixed_phy_status *); - struct list_head node; - struct gpio_desc *link_gpiod; -}; - -struct kszphy_hw_stat { - const char *string; - u8 reg; - u8 bits; -}; - -struct kszphy_type { - u32 led_mode_reg; - u16 interrupt_level_mask; - bool has_broadcast_disable; - bool has_nand_tree_disable; - bool has_rmii_ref_clk_sel; -}; - -struct kszphy_priv { - const struct kszphy_type *type; - int led_mode; - bool rmii_ref_clk_sel; - bool rmii_ref_clk_sel_val; - u64 stats[2]; -}; - -struct lan88xx_priv { - int chip_id; - int chip_rev; - __u32 wolopts; -}; - -struct smsc_hw_stat { - const char *string; - u8 reg; - u8 bits; -}; - -struct smsc_phy_priv { - bool energy_enable; - struct clk *refclk; -}; - -struct unimac_mdio_pdata { - u32 phy_mask; - int (*wait_func)(void *); - void *wait_func_data; - const char *bus_name; -}; - -struct unimac_mdio_priv { - struct mii_bus *mii_bus; - void *base; - int (*wait_func)(void *); - void *wait_func_data; - struct clk *clk; - u32 clk_freq; -}; - -enum ethtool_stringset { - ETH_SS_TEST = 0, - ETH_SS_STATS = 1, - ETH_SS_PRIV_FLAGS = 2, - ETH_SS_NTUPLE_FILTERS = 3, - ETH_SS_FEATURES = 4, - ETH_SS_RSS_HASH_FUNCS = 5, - ETH_SS_TUNABLES = 6, - ETH_SS_PHY_STATS = 7, - ETH_SS_PHY_TUNABLES = 8, - ETH_SS_LINK_MODES = 9, - ETH_SS_MSG_CLASSES = 10, - ETH_SS_WOL_MODES = 11, - ETH_SS_SOF_TIMESTAMPING = 12, - ETH_SS_TS_TX_TYPES = 13, - ETH_SS_TS_RX_FILTERS = 14, - ETH_SS_UDP_TUNNEL_TYPES = 15, - ETH_SS_COUNT = 16, -}; - -struct netdev_hw_addr { - struct list_head list; - unsigned char addr[32]; - unsigned char type; - bool global_use; - int sync_cnt; - int refcount; - int synced; - struct callback_head callback_head; -}; - -struct gro_list { - struct list_head list; - int count; -}; - -struct napi_struct { - struct list_head poll_list; - long unsigned int state; - int weight; - int defer_hard_irqs_count; - long unsigned int gro_bitmask; - int (*poll)(struct napi_struct *, int); - int poll_owner; - struct net_device *dev; - struct gro_list gro_hash[8]; - struct sk_buff *skb; - struct list_head rx_list; - int rx_count; - struct hrtimer timer; - struct list_head dev_list; - struct hlist_node napi_hash_node; - unsigned int napi_id; -}; - -enum netdev_queue_state_t { - __QUEUE_STATE_DRV_XOFF = 0, - __QUEUE_STATE_STACK_XOFF = 1, - __QUEUE_STATE_FROZEN = 2, -}; - -struct sd_flow_limit { - u64 count; - unsigned int num_buckets; - unsigned int history_head; - u16 history[128]; - u8 buckets[0]; -}; - -struct softnet_data { - struct list_head poll_list; - struct sk_buff_head process_queue; - unsigned int processed; - unsigned int time_squeeze; - unsigned int received_rps; - struct softnet_data *rps_ipi_list; - struct sd_flow_limit *flow_limit; - struct Qdisc *output_queue; - struct Qdisc **output_queue_tailp; - struct sk_buff *completion_queue; - struct sk_buff_head xfrm_backlog; - struct { - u16 recursion; - u8 more; - } xmit; - int: 32; - unsigned int input_queue_head; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - call_single_data_t csd; - struct softnet_data *rps_ipi_next; - unsigned int cpu; - unsigned int input_queue_tail; - unsigned int dropped; - struct sk_buff_head input_pkt_queue; - struct napi_struct backlog; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum skb_free_reason { - SKB_REASON_CONSUMED = 0, - SKB_REASON_DROPPED = 1, -}; - -struct bcmgenet_platform_data { - bool mdio_enabled; - phy_interface_t phy_interface; - int phy_address; - int phy_speed; - int phy_duplex; - u8 mac_address[6]; - int genet_version; -}; - -struct status_64 { - u32 length_status; - u32 ext_status; - u32 rx_csum; - u32 unused1[9]; - u32 tx_csum_info; - u32 unused2[3]; -}; - -struct bcmgenet_pkt_counters { - u32 cnt_64; - u32 cnt_127; - u32 cnt_255; - u32 cnt_511; - u32 cnt_1023; - u32 cnt_1518; - u32 cnt_mgv; - u32 cnt_2047; - u32 cnt_4095; - u32 cnt_9216; -}; - -struct bcmgenet_rx_counters { - struct bcmgenet_pkt_counters pkt_cnt; - u32 pkt; - u32 bytes; - u32 mca; - u32 bca; - u32 fcs; - u32 cf; - u32 pf; - u32 uo; - u32 aln; - u32 flr; - u32 cde; - u32 fcr; - u32 ovr; - u32 jbr; - u32 mtue; - u32 pok; - u32 uc; - u32 ppp; - u32 rcrc; -}; - -struct bcmgenet_tx_counters { - struct bcmgenet_pkt_counters pkt_cnt; - u32 pkts; - u32 mca; - u32 bca; - u32 pf; - u32 cf; - u32 fcs; - u32 ovr; - u32 drf; - u32 edf; - u32 scl; - u32 mcl; - u32 lcl; - u32 ecl; - u32 frg; - u32 ncl; - u32 jbr; - u32 bytes; - u32 pok; - u32 uc; -}; - -struct bcmgenet_mib_counters { - struct bcmgenet_rx_counters rx; - struct bcmgenet_tx_counters tx; - u32 rx_runt_cnt; - u32 rx_runt_fcs; - u32 rx_runt_fcs_align; - u32 rx_runt_bytes; - u32 rbuf_ovflow_cnt; - u32 rbuf_err_cnt; - u32 mdf_err_cnt; - u32 alloc_rx_buff_failed; - u32 rx_dma_failed; - u32 tx_dma_failed; - u32 tx_realloc_tsb; - u32 tx_realloc_tsb_failed; -}; - -struct enet_cb { - struct sk_buff *skb; - void *bd_addr; - dma_addr_t dma_addr; - __u32 dma_len; -}; - -enum bcmgenet_power_mode { - GENET_POWER_CABLE_SENSE = 0, - GENET_POWER_PASSIVE = 1, - GENET_POWER_WOL_MAGIC = 2, -}; - -enum bcmgenet_version { - GENET_V1 = 1, - GENET_V2 = 2, - GENET_V3 = 3, - GENET_V4 = 4, - GENET_V5 = 5, -}; - -struct bcmgenet_hw_params { - u8 tx_queues; - u8 tx_bds_per_q; - u8 rx_queues; - u8 rx_bds_per_q; - u8 bp_in_en_shift; - u32 bp_in_mask; - u8 hfb_filter_cnt; - u8 hfb_filter_size; - u8 qtag_mask; - u16 tbuf_offset; - u32 hfb_offset; - u32 hfb_reg_offset; - u32 rdma_offset; - u32 tdma_offset; - u32 words_per_bd; - u32 flags; -}; - -struct bcmgenet_skb_cb { - struct enet_cb *first_cb; - struct enet_cb *last_cb; - unsigned int bytes_sent; -}; - -struct bcmgenet_priv; - -struct bcmgenet_tx_ring { - spinlock_t lock; - struct napi_struct napi; - long unsigned int packets; - long unsigned int bytes; - unsigned int index; - unsigned int queue; - struct enet_cb *cbs; - unsigned int size; - unsigned int clean_ptr; - unsigned int c_index; - unsigned int free_bds; - unsigned int write_ptr; - unsigned int prod_index; - unsigned int cb_ptr; - unsigned int end_ptr; - void (*int_enable)(struct bcmgenet_tx_ring *); - void (*int_disable)(struct bcmgenet_tx_ring *); - struct bcmgenet_priv *priv; -}; - -enum bcmgenet_rxnfc_state { - BCMGENET_RXNFC_STATE_UNUSED = 0, - BCMGENET_RXNFC_STATE_DISABLED = 1, - BCMGENET_RXNFC_STATE_ENABLED = 2, -}; - -struct bcmgenet_rxnfc_rule { - struct list_head list; - struct ethtool_rx_flow_spec fs; - enum bcmgenet_rxnfc_state state; -}; - -struct bcmgenet_net_dim { - u16 use_dim; - u16 event_ctr; - long unsigned int packets; - long unsigned int bytes; - struct dim dim; -}; - -struct bcmgenet_rx_ring { - struct napi_struct napi; - long unsigned int bytes; - long unsigned int packets; - long unsigned int errors; - long unsigned int dropped; - unsigned int index; - struct enet_cb *cbs; - unsigned int size; - unsigned int c_index; - unsigned int read_ptr; - unsigned int cb_ptr; - unsigned int end_ptr; - unsigned int old_discards; - struct bcmgenet_net_dim dim; - u32 rx_max_coalesced_frames; - u32 rx_coalesce_usecs; - void (*int_enable)(struct bcmgenet_rx_ring *); - void (*int_disable)(struct bcmgenet_rx_ring *); - struct bcmgenet_priv *priv; -}; - -struct bcmgenet_priv { - void *base; - enum bcmgenet_version version; - struct net_device *dev; - void *tx_bds; - struct enet_cb *tx_cbs; - unsigned int num_tx_bds; - struct bcmgenet_tx_ring tx_rings[17]; - void *rx_bds; - struct enet_cb *rx_cbs; - unsigned int num_rx_bds; - unsigned int rx_buf_len; - struct bcmgenet_rxnfc_rule rxnfc_rules[16]; - struct list_head rxnfc_list; - struct bcmgenet_rx_ring rx_rings[17]; - struct bcmgenet_hw_params *hw_params; - wait_queue_head_t wq; - bool internal_phy; - struct device_node *phy_dn; - struct device_node *mdio_dn; - struct mii_bus *mii_bus; - u16 gphy_rev; - struct clk *clk_eee; - bool clk_eee_enabled; - int old_link; - int old_speed; - int old_duplex; - int old_pause; - phy_interface_t phy_interface; - int phy_addr; - int ext_phy; - struct work_struct bcmgenet_irq_work; - int irq0; - int irq1; - int wol_irq; - bool wol_irq_disabled; - spinlock_t lock; - unsigned int irq0_stat; - bool crc_fwd_en; - u32 dma_max_burst_length; - u32 msg_enable; - struct clk *clk; - struct platform_device *pdev; - struct platform_device *mii_pdev; - struct clk *clk_wol; - u32 wolopts; - u8 sopass[6]; - bool wol_active; - struct bcmgenet_mib_counters mib; - struct ethtool_eee eee; -}; - -enum dma_reg { - DMA_RING_CFG = 0, - DMA_CTRL = 1, - DMA_STATUS = 2, - DMA_SCB_BURST_SIZE = 3, - DMA_ARB_CTRL = 4, - DMA_PRIORITY_0 = 5, - DMA_PRIORITY_1 = 6, - DMA_PRIORITY_2 = 7, - DMA_INDEX2RING_0 = 8, - DMA_INDEX2RING_1 = 9, - DMA_INDEX2RING_2 = 10, - DMA_INDEX2RING_3 = 11, - DMA_INDEX2RING_4 = 12, - DMA_INDEX2RING_5 = 13, - DMA_INDEX2RING_6 = 14, - DMA_INDEX2RING_7 = 15, - DMA_RING0_TIMEOUT = 16, - DMA_RING1_TIMEOUT = 17, - DMA_RING2_TIMEOUT = 18, - DMA_RING3_TIMEOUT = 19, - DMA_RING4_TIMEOUT = 20, - DMA_RING5_TIMEOUT = 21, - DMA_RING6_TIMEOUT = 22, - DMA_RING7_TIMEOUT = 23, - DMA_RING8_TIMEOUT = 24, - DMA_RING9_TIMEOUT = 25, - DMA_RING10_TIMEOUT = 26, - DMA_RING11_TIMEOUT = 27, - DMA_RING12_TIMEOUT = 28, - DMA_RING13_TIMEOUT = 29, - DMA_RING14_TIMEOUT = 30, - DMA_RING15_TIMEOUT = 31, - DMA_RING16_TIMEOUT = 32, -}; - -enum dma_ring_reg { - TDMA_READ_PTR = 0, - RDMA_WRITE_PTR = 0, - TDMA_READ_PTR_HI = 1, - RDMA_WRITE_PTR_HI = 1, - TDMA_CONS_INDEX = 2, - RDMA_PROD_INDEX = 2, - TDMA_PROD_INDEX = 3, - RDMA_CONS_INDEX = 3, - DMA_RING_BUF_SIZE = 4, - DMA_START_ADDR = 5, - DMA_START_ADDR_HI = 6, - DMA_END_ADDR = 7, - DMA_END_ADDR_HI = 8, - DMA_MBUF_DONE_THRESH = 9, - TDMA_FLOW_PERIOD = 10, - RDMA_XON_XOFF_THRESH = 10, - TDMA_WRITE_PTR = 11, - RDMA_READ_PTR = 11, - TDMA_WRITE_PTR_HI = 12, - RDMA_READ_PTR_HI = 12, -}; - -enum bcmgenet_stat_type { - BCMGENET_STAT_NETDEV = 4294967295, - BCMGENET_STAT_MIB_RX = 0, - BCMGENET_STAT_MIB_TX = 1, - BCMGENET_STAT_RUNT = 2, - BCMGENET_STAT_MISC = 3, - BCMGENET_STAT_SOFT = 4, -}; - -struct bcmgenet_stats { - char stat_string[32]; - int stat_sizeof; - int stat_offset; - enum bcmgenet_stat_type type; - u16 reg_offset; -}; - -struct bcmgenet_plat_data { - enum bcmgenet_version version; - u32 dma_max_burst_length; -}; - -enum tunable_id { - ETHTOOL_ID_UNSPEC = 0, - ETHTOOL_RX_COPYBREAK = 1, - ETHTOOL_TX_COPYBREAK = 2, - ETHTOOL_PFC_PREVENTION_TOUT = 3, - __ETHTOOL_TUNABLE_COUNT = 4, -}; - -struct usb_device_id { - __u16 match_flags; - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice_lo; - __u16 bcdDevice_hi; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 bInterfaceNumber; - kernel_ulong_t driver_info; -}; - -struct usb_device_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __le16 idVendor; - __le16 idProduct; - __le16 bcdDevice; - __u8 iManufacturer; - __u8 iProduct; - __u8 iSerialNumber; - __u8 bNumConfigurations; -}; - -struct usb_config_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 wTotalLength; - __u8 bNumInterfaces; - __u8 bConfigurationValue; - __u8 iConfiguration; - __u8 bmAttributes; - __u8 bMaxPower; -} __attribute__((packed)); - -struct usb_interface_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - __u8 bNumEndpoints; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 iInterface; -}; - -struct usb_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bEndpointAddress; - __u8 bmAttributes; - __le16 wMaxPacketSize; - __u8 bInterval; - __u8 bRefresh; - __u8 bSynchAddress; -} __attribute__((packed)); - -struct usb_ssp_isoc_ep_comp_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 wReseved; - __le32 dwBytesPerInterval; -}; - -struct usb_ss_ep_comp_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bMaxBurst; - __u8 bmAttributes; - __le16 wBytesPerInterval; -}; - -struct usb_interface_assoc_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bFirstInterface; - __u8 bInterfaceCount; - __u8 bFunctionClass; - __u8 bFunctionSubClass; - __u8 bFunctionProtocol; - __u8 iFunction; -}; - -struct usb_bos_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 wTotalLength; - __u8 bNumDeviceCaps; -} __attribute__((packed)); - -struct usb_ext_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __le32 bmAttributes; -} __attribute__((packed)); - -struct usb_ss_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __u8 bmAttributes; - __le16 wSpeedSupported; - __u8 bFunctionalitySupport; - __u8 bU1devExitLat; - __le16 bU2DevExitLat; -}; - -struct usb_ss_container_id_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __u8 bReserved; - __u8 ContainerID[16]; -}; - -struct usb_ssp_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __u8 bReserved; - __le32 bmAttributes; - __le16 wFunctionalitySupport; - __le16 wReserved; - __le32 bmSublinkSpeedAttr[1]; -}; - -struct usb_ptm_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; -}; - -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, - USB_SPEED_LOW = 1, - USB_SPEED_FULL = 2, - USB_SPEED_HIGH = 3, - USB_SPEED_WIRELESS = 4, - USB_SPEED_SUPER = 5, - USB_SPEED_SUPER_PLUS = 6, -}; - -enum usb_device_state { - USB_STATE_NOTATTACHED = 0, - USB_STATE_ATTACHED = 1, - USB_STATE_POWERED = 2, - USB_STATE_RECONNECTING = 3, - USB_STATE_UNAUTHENTICATED = 4, - USB_STATE_DEFAULT = 5, - USB_STATE_ADDRESS = 6, - USB_STATE_CONFIGURED = 7, - USB_STATE_SUSPENDED = 8, -}; - -struct ep_device; - -struct usb_host_endpoint { - struct usb_endpoint_descriptor desc; - struct usb_ss_ep_comp_descriptor ss_ep_comp; - struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp; - char: 8; - struct list_head urb_list; - void *hcpriv; - struct ep_device *ep_dev; - unsigned char *extra; - int extralen; - int enabled; - int streams; - int: 32; -} __attribute__((packed)); - -struct usb_host_interface { - struct usb_interface_descriptor desc; - int extralen; - unsigned char *extra; - struct usb_host_endpoint *endpoint; - char *string; -}; - -enum usb_interface_condition { - USB_INTERFACE_UNBOUND = 0, - USB_INTERFACE_BINDING = 1, - USB_INTERFACE_BOUND = 2, - USB_INTERFACE_UNBINDING = 3, -}; - -struct usb_interface { - struct usb_host_interface *altsetting; - struct usb_host_interface *cur_altsetting; - unsigned int num_altsetting; - struct usb_interface_assoc_descriptor *intf_assoc; - int minor; - enum usb_interface_condition condition; - unsigned int sysfs_files_created: 1; - unsigned int ep_devs_created: 1; - unsigned int unregistering: 1; - unsigned int needs_remote_wakeup: 1; - unsigned int needs_altsetting0: 1; - unsigned int needs_binding: 1; - unsigned int resetting_device: 1; - unsigned int authorized: 1; - struct device dev; - struct device *usb_dev; - struct work_struct reset_ws; -}; - -struct usb_interface_cache { - unsigned int num_altsetting; - struct kref ref; - struct usb_host_interface altsetting[0]; -}; - -struct usb_host_config { - struct usb_config_descriptor desc; - char *string; - struct usb_interface_assoc_descriptor *intf_assoc[16]; - struct usb_interface *interface[32]; - struct usb_interface_cache *intf_cache[32]; - unsigned char *extra; - int extralen; -}; - -struct usb_host_bos { - struct usb_bos_descriptor *desc; - struct usb_ext_cap_descriptor *ext_cap; - struct usb_ss_cap_descriptor *ss_cap; - struct usb_ssp_cap_descriptor *ssp_cap; - struct usb_ss_container_id_descriptor *ss_id; - struct usb_ptm_cap_descriptor *ptm_cap; -}; - -struct usb_devmap { - long unsigned int devicemap[2]; -}; - -struct mon_bus; - -struct usb_device; - -struct usb_bus { - struct device *controller; - struct device *sysdev; - int busnum; - const char *bus_name; - u8 uses_pio_for_control; - u8 otg_port; - unsigned int is_b_host: 1; - unsigned int b_hnp_enable: 1; - unsigned int no_stop_on_short: 1; - unsigned int no_sg_constraint: 1; - unsigned int sg_tablesize; - int devnum_next; - struct mutex devnum_next_mutex; - struct usb_devmap devmap; - struct usb_device *root_hub; - struct usb_bus *hs_companion; - int bandwidth_allocated; - int bandwidth_int_reqs; - int bandwidth_isoc_reqs; - unsigned int resuming_ports; - struct mon_bus *mon_bus; - int monitored; -}; - -struct wusb_dev; - -enum usb_device_removable { - USB_DEVICE_REMOVABLE_UNKNOWN = 0, - USB_DEVICE_REMOVABLE = 1, - USB_DEVICE_FIXED = 2, -}; - -struct usb2_lpm_parameters { - unsigned int besl; - int timeout; -}; - -struct usb3_lpm_parameters { - unsigned int mel; - unsigned int pel; - unsigned int sel; - int timeout; -}; - -struct usb_tt; - -struct usb_device { - int devnum; - char devpath[16]; - u32 route; - enum usb_device_state state; - enum usb_device_speed speed; - unsigned int rx_lanes; - unsigned int tx_lanes; - struct usb_tt *tt; - int ttport; - unsigned int toggle[2]; - struct usb_device *parent; - struct usb_bus *bus; - struct usb_host_endpoint ep0; - struct device dev; - struct usb_device_descriptor descriptor; - struct usb_host_bos *bos; - struct usb_host_config *config; - struct usb_host_config *actconfig; - struct usb_host_endpoint *ep_in[16]; - struct usb_host_endpoint *ep_out[16]; - char **rawdescriptors; - short unsigned int bus_mA; - u8 portnum; - u8 level; - u8 devaddr; - unsigned int can_submit: 1; - unsigned int persist_enabled: 1; - unsigned int have_langid: 1; - unsigned int authorized: 1; - unsigned int authenticated: 1; - unsigned int wusb: 1; - unsigned int lpm_capable: 1; - unsigned int usb2_hw_lpm_capable: 1; - unsigned int usb2_hw_lpm_besl_capable: 1; - unsigned int usb2_hw_lpm_enabled: 1; - unsigned int usb2_hw_lpm_allowed: 1; - unsigned int usb3_lpm_u1_enabled: 1; - unsigned int usb3_lpm_u2_enabled: 1; - int string_langid; - char *product; - char *manufacturer; - char *serial; - struct list_head filelist; - int maxchild; - u32 quirks; - atomic_t urbnum; - long unsigned int active_duration; - long unsigned int connect_time; - unsigned int do_remote_wakeup: 1; - unsigned int reset_resume: 1; - unsigned int port_is_suspended: 1; - struct wusb_dev *wusb_dev; - int slot_id; - enum usb_device_removable removable; - struct usb2_lpm_parameters l1_params; - struct usb3_lpm_parameters u1_params; - struct usb3_lpm_parameters u2_params; - unsigned int lpm_disable_count; - u16 hub_delay; - unsigned int use_generic_driver: 1; -}; - -struct usb_dynids { - spinlock_t lock; - struct list_head list; -}; - -struct usbdrv_wrap { - struct device_driver driver; - int for_devices; -}; - -struct usb_driver { - const char *name; - int (*probe)(struct usb_interface *, const struct usb_device_id *); - void (*disconnect)(struct usb_interface *); - int (*unlocked_ioctl)(struct usb_interface *, unsigned int, void *); - int (*suspend)(struct usb_interface *, pm_message_t); - int (*resume)(struct usb_interface *); - int (*reset_resume)(struct usb_interface *); - int (*pre_reset)(struct usb_interface *); - int (*post_reset)(struct usb_interface *); - const struct usb_device_id *id_table; - const struct attribute_group **dev_groups; - struct usb_dynids dynids; - struct usbdrv_wrap drvwrap; - unsigned int no_dynamic_id: 1; - unsigned int supports_autosuspend: 1; - unsigned int disable_hub_initiated_lpm: 1; - unsigned int soft_unbind: 1; -}; - -struct usb_iso_packet_descriptor { - unsigned int offset; - unsigned int length; - unsigned int actual_length; - int status; -}; - -struct usb_anchor { - struct list_head urb_list; - wait_queue_head_t wait; - spinlock_t lock; - atomic_t suspend_wakeups; - unsigned int poisoned: 1; -}; - -struct urb; - -typedef void (*usb_complete_t)(struct urb *); - -struct urb { - struct kref kref; - int unlinked; - void *hcpriv; - atomic_t use_count; - atomic_t reject; - struct list_head urb_list; - struct list_head anchor_list; - struct usb_anchor *anchor; - struct usb_device *dev; - struct usb_host_endpoint *ep; - unsigned int pipe; - unsigned int stream_id; - int status; - unsigned int transfer_flags; - void *transfer_buffer; - dma_addr_t transfer_dma; - struct scatterlist *sg; - int num_mapped_sgs; - int num_sgs; - u32 transfer_buffer_length; - u32 actual_length; - unsigned char *setup_packet; - dma_addr_t setup_dma; - int start_frame; - int number_of_packets; - int interval; - int error_count; - void *context; - usb_complete_t complete; - struct usb_iso_packet_descriptor iso_frame_desc[0]; -}; - -struct vlan_hdr { - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -typedef u64 acpi_size; - -typedef u64 acpi_io_address; - -typedef u32 acpi_status; - -typedef char *acpi_string; - -typedef u32 acpi_object_type; - -union acpi_object { - acpi_object_type type; - struct { - acpi_object_type type; - u64 value; - } integer; - struct { - acpi_object_type type; - u32 length; - char *pointer; - } string; - struct { - acpi_object_type type; - u32 length; - u8 *pointer; - } buffer; - struct { - acpi_object_type type; - u32 count; - union acpi_object *elements; - } package; - struct { - acpi_object_type type; - acpi_object_type actual_type; - acpi_handle handle; - } reference; - struct { - acpi_object_type type; - u32 proc_id; - acpi_io_address pblk_address; - u32 pblk_length; - } processor; - struct { - acpi_object_type type; - u32 system_level; - u32 resource_order; - } power_resource; -}; - -struct acpi_object_list { - u32 count; - union acpi_object *pointer; -}; - -struct acpi_buffer { - acpi_size length; - void *pointer; -}; - -enum spd_duplex { - NWAY_10M_HALF = 0, - NWAY_10M_FULL = 1, - NWAY_100M_HALF = 2, - NWAY_100M_FULL = 3, - NWAY_1000M_FULL = 4, - FORCE_10M_HALF = 5, - FORCE_10M_FULL = 6, - FORCE_100M_HALF = 7, - FORCE_100M_FULL = 8, - FORCE_1000M_FULL = 9, - NWAY_2500M_FULL = 10, -}; - -enum rtl_register_content { - _2500bps = 1024, - _1250bps = 512, - _500bps = 256, - _tx_flow = 64, - _rx_flow = 32, - _1000bps = 16, - _100bps = 8, - _10bps = 4, - LINK_STATUS = 2, - FULL_DUP = 1, -}; - -enum rtl8152_flags { - RTL8152_UNPLUG = 0, - RTL8152_SET_RX_MODE = 1, - WORK_ENABLE = 2, - RTL8152_LINK_CHG = 3, - SELECTIVE_SUSPEND = 4, - PHY_RESET = 5, - SCHEDULE_TASKLET = 6, - GREEN_ETHERNET = 7, - DELL_TB_RX_AGG_BUG = 8, - LENOVO_MACPASSTHRU = 9, -}; - -struct tally_counter { - __le64 tx_packets; - __le64 rx_packets; - __le64 tx_errors; - __le32 rx_errors; - __le16 rx_missed; - __le16 align_errors; - __le32 tx_one_collision; - __le32 tx_multi_collision; - __le64 rx_unicast; - __le64 rx_broadcast; - __le32 rx_multicast; - __le16 tx_aborted; - __le16 tx_underrun; -}; - -struct rx_desc { - __le32 opts1; - __le32 opts2; - __le32 opts3; - __le32 opts4; - __le32 opts5; - __le32 opts6; -}; - -struct tx_desc { - __le32 opts1; - __le32 opts2; -}; - -struct r8152; - -struct rx_agg { - struct list_head list; - struct list_head info_list; - struct urb *urb; - struct r8152 *context; - struct page *page; - void *buffer; -}; - -struct tx_agg { - struct list_head list; - struct urb *urb; - struct r8152 *context; - void *buffer; - void *head; - u32 skb_num; - u32 skb_len; -}; - -struct rtl_ops { - void (*init)(struct r8152 *); - int (*enable)(struct r8152 *); - void (*disable)(struct r8152 *); - void (*up)(struct r8152 *); - void (*down)(struct r8152 *); - void (*unload)(struct r8152 *); - int (*eee_get)(struct r8152 *, struct ethtool_eee *); - int (*eee_set)(struct r8152 *, struct ethtool_eee *); - bool (*in_nway)(struct r8152 *); - void (*hw_phy_cfg)(struct r8152 *); - void (*autosuspend_en)(struct r8152 *, bool); - void (*change_mtu)(struct r8152 *); -}; - -struct ups_info { - u32 r_tune: 1; - u32 _10m_ckdiv: 1; - u32 _250m_ckdiv: 1; - u32 aldps: 1; - u32 lite_mode: 2; - u32 speed_duplex: 4; - u32 eee: 1; - u32 eee_lite: 1; - u32 eee_ckdiv: 1; - u32 eee_plloff_100: 1; - u32 eee_plloff_giga: 1; - u32 eee_cmod_lv: 1; - u32 green: 1; - u32 flow_control: 1; - u32 ctap_short_off: 1; -}; - -struct rtl_fw { - const char *fw_name; - const struct firmware *fw; - char version[32]; - int (*pre_fw)(struct r8152 *); - int (*post_fw)(struct r8152 *); - bool retry; -}; - -struct r8152 { - long unsigned int flags; - struct usb_device *udev; - struct napi_struct napi; - struct usb_interface *intf; - struct net_device *netdev; - struct urb *intr_urb; - struct tx_agg tx_info[4]; - struct list_head rx_info; - struct list_head rx_used; - struct list_head rx_done; - struct list_head tx_free; - struct sk_buff_head tx_queue; - struct sk_buff_head rx_queue; - spinlock_t rx_lock; - spinlock_t tx_lock; - struct delayed_work schedule; - struct delayed_work hw_phy_work; - struct mii_if_info mii; - struct mutex control; - struct tasklet_struct tx_tl; - struct rtl_ops rtl_ops; - struct ups_info ups_info; - struct rtl_fw rtl_fw; - atomic_t rx_count; - bool eee_en; - int intr_interval; - u32 saved_wolopts; - u32 msg_enable; - u32 tx_qlen; - u32 coalesce; - u32 advertising; - u32 rx_buf_sz; - u32 rx_copybreak; - u32 rx_pending; - u32 fc_pause_on; - u32 fc_pause_off; - u32 support_2500full: 1; - u16 ocp_base; - u16 speed; - u16 eee_adv; - u8 *intr_buff; - u8 version; - u8 duplex; - u8 autoneg; -}; - -struct fw_block { - __le32 type; - __le32 length; -}; - -struct fw_header { - u8 checksum[32]; - char version[32]; - struct fw_block blocks[0]; -}; - -enum rtl8152_fw_flags { - FW_FLAGS_USB = 0, - FW_FLAGS_PLA = 1, - FW_FLAGS_START = 2, - FW_FLAGS_STOP = 3, - FW_FLAGS_NC = 4, - FW_FLAGS_NC1 = 5, - FW_FLAGS_NC2 = 6, - FW_FLAGS_UC2 = 7, - FW_FLAGS_UC = 8, - FW_FLAGS_SPEED_UP = 9, - FW_FLAGS_VER = 10, -}; - -enum rtl8152_fw_fixup_cmd { - FW_FIXUP_AND = 0, - FW_FIXUP_OR = 1, - FW_FIXUP_NOT = 2, - FW_FIXUP_XOR = 3, -}; - -struct fw_phy_set { - __le16 addr; - __le16 data; -}; - -struct fw_phy_speed_up { - struct fw_block blk_hdr; - __le16 fw_offset; - __le16 version; - __le16 fw_reg; - __le16 reserved; - char info[0]; -}; - -struct fw_phy_ver { - struct fw_block blk_hdr; - struct fw_phy_set ver; - __le32 reserved; -}; - -struct fw_phy_fixup { - struct fw_block blk_hdr; - struct fw_phy_set setting; - __le16 bit_cmd; - __le16 reserved; -}; - -struct fw_phy_union { - struct fw_block blk_hdr; - __le16 fw_offset; - __le16 fw_reg; - struct fw_phy_set pre_set[2]; - struct fw_phy_set bp[8]; - struct fw_phy_set bp_en; - u8 pre_num; - u8 bp_num; - char info[0]; -} __attribute__((packed)); - -struct fw_mac { - struct fw_block blk_hdr; - __le16 fw_offset; - __le16 fw_reg; - __le16 bp_ba_addr; - __le16 bp_ba_value; - __le16 bp_en_addr; - __le16 bp_en_value; - __le16 bp_start; - __le16 bp_num; - __le16 bp[16]; - __le32 reserved; - __le16 fw_ver_reg; - u8 fw_ver_data; - char info[0]; -} __attribute__((packed)); - -struct fw_phy_patch_key { - struct fw_block blk_hdr; - __le16 key_reg; - __le16 key_data; - __le32 reserved; -}; - -struct fw_phy_nc { - struct fw_block blk_hdr; - __le16 fw_offset; - __le16 fw_reg; - __le16 ba_reg; - __le16 ba_data; - __le16 patch_en_addr; - __le16 patch_en_value; - __le16 mode_reg; - __le16 mode_pre; - __le16 mode_post; - __le16 reserved; - __le16 bp_start; - __le16 bp_num; - __le16 bp[4]; - char info[0]; -}; - -enum rtl_fw_type { - RTL_FW_END = 0, - RTL_FW_PLA = 1, - RTL_FW_USB = 2, - RTL_FW_PHY_START = 3, - RTL_FW_PHY_STOP = 4, - RTL_FW_PHY_NC = 5, - RTL_FW_PHY_FIXUP = 6, - RTL_FW_PHY_UNION_NC = 7, - RTL_FW_PHY_UNION_NC1 = 8, - RTL_FW_PHY_UNION_NC2 = 9, - RTL_FW_PHY_UNION_UC2 = 10, - RTL_FW_PHY_UNION_UC = 11, - RTL_FW_PHY_UNION_MISC = 12, - RTL_FW_PHY_SPEED_UP = 13, - RTL_FW_PHY_VER = 14, -}; - -enum rtl_version { - RTL_VER_UNKNOWN = 0, - RTL_VER_01 = 1, - RTL_VER_02 = 2, - RTL_VER_03 = 3, - RTL_VER_04 = 4, - RTL_VER_05 = 5, - RTL_VER_06 = 6, - RTL_VER_07 = 7, - RTL_VER_08 = 8, - RTL_VER_09 = 9, - RTL_TEST_01 = 10, - RTL_VER_10 = 11, - RTL_VER_11 = 12, - RTL_VER_12 = 13, - RTL_VER_13 = 14, - RTL_VER_14 = 15, - RTL_VER_15 = 16, - RTL_VER_MAX = 17, -}; - -enum tx_csum_stat { - TX_CSUM_SUCCESS = 0, - TX_CSUM_TSO = 1, - TX_CSUM_NONE = 2, -}; - -struct rt6key { - struct in6_addr addr; - int plen; -}; - -struct rtable; - -struct fnhe_hash_bucket; - -struct fib_nh_common { - struct net_device *nhc_dev; - int nhc_oif; - unsigned char nhc_scope; - u8 nhc_family; - u8 nhc_gw_family; - unsigned char nhc_flags; - struct lwtunnel_state *nhc_lwtstate; - union { - __be32 ipv4; - struct in6_addr ipv6; - } nhc_gw; - int nhc_weight; - atomic_t nhc_upper_bound; - struct rtable **nhc_pcpu_rth_output; - struct rtable *nhc_rth_input; - struct fnhe_hash_bucket *nhc_exceptions; -}; - -struct rt6_exception_bucket; - -struct fib6_nh { - struct fib_nh_common nh_common; - long unsigned int last_probe; - struct rt6_info **rt6i_pcpu; - struct rt6_exception_bucket *rt6i_exception_bucket; -}; - -struct fib6_node; - -struct dst_metrics; - -struct nexthop; - -struct fib6_info { - struct fib6_table *fib6_table; - struct fib6_info *fib6_next; - struct fib6_node *fib6_node; - union { - struct list_head fib6_siblings; - struct list_head nh_list; - }; - unsigned int fib6_nsiblings; - refcount_t fib6_ref; - long unsigned int expires; - struct dst_metrics *fib6_metrics; - struct rt6key fib6_dst; - u32 fib6_flags; - struct rt6key fib6_src; - struct rt6key fib6_prefsrc; - u32 fib6_metric; - u8 fib6_protocol; - u8 fib6_type; - u8 should_flush: 1; - u8 dst_nocount: 1; - u8 dst_nopolicy: 1; - u8 fib6_destroying: 1; - u8 offload: 1; - u8 trap: 1; - u8 unused: 2; - struct callback_head rcu; - struct nexthop *nh; - struct fib6_nh fib6_nh[0]; -}; - -struct uncached_list; - -struct rt6_info { - struct dst_entry dst; - struct fib6_info *from; - int sernum; - struct rt6key rt6i_dst; - struct rt6key rt6i_src; - struct in6_addr rt6i_gateway; - struct inet6_dev *rt6i_idev; - u32 rt6i_flags; - struct list_head rt6i_uncached; - struct uncached_list *rt6i_uncached_list; - short unsigned int rt6i_nfheader_len; -}; - -struct rt6_statistics { - __u32 fib_nodes; - __u32 fib_route_nodes; - __u32 fib_rt_entries; - __u32 fib_rt_cache; - __u32 fib_discarded_routes; - atomic_t fib_rt_alloc; - atomic_t fib_rt_uncache; -}; - -struct fib6_node { - struct fib6_node *parent; - struct fib6_node *left; - struct fib6_node *right; - struct fib6_node *subtree; - struct fib6_info *leaf; - __u16 fn_bit; - __u16 fn_flags; - int fn_sernum; - struct fib6_info *rr_ptr; - struct callback_head rcu; -}; - -struct fib6_table { - struct hlist_node tb6_hlist; - u32 tb6_id; - spinlock_t tb6_lock; - struct fib6_node tb6_root; - struct inet_peer_base tb6_peers; - unsigned int flags; - unsigned int fib_seq; -}; - -struct udp_tunnel_info { - short unsigned int type; - sa_family_t sa_family; - __be16 port; - u8 hw_priv; -}; - -struct ip_tunnel_parm { - char name[16]; - int link; - __be16 i_flags; - __be16 o_flags; - __be32 i_key; - __be32 o_key; - struct iphdr iph; -}; - -struct vlan_ethhdr { - unsigned char h_dest[6]; - unsigned char h_source[6]; - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -struct dst_metrics { - u32 metrics[17]; - refcount_t refcnt; -}; - -struct udp_hslot; - -struct udp_table { - struct udp_hslot *hash; - struct udp_hslot *hash2; - unsigned int mask; - unsigned int log; -}; - -struct fib_nh_exception { - struct fib_nh_exception *fnhe_next; - int fnhe_genid; - __be32 fnhe_daddr; - u32 fnhe_pmtu; - bool fnhe_mtu_locked; - __be32 fnhe_gw; - long unsigned int fnhe_expires; - struct rtable *fnhe_rth_input; - struct rtable *fnhe_rth_output; - long unsigned int fnhe_stamp; - struct callback_head rcu; -}; - -struct rtable { - struct dst_entry dst; - int rt_genid; - unsigned int rt_flags; - __u16 rt_type; - __u8 rt_is_input; - __u8 rt_uses_gateway; - int rt_iif; - u8 rt_gw_family; - union { - __be32 rt_gw4; - struct in6_addr rt_gw6; - }; - u32 rt_mtu_locked: 1; - u32 rt_pmtu: 31; - struct list_head rt_uncached; - struct uncached_list *rt_uncached_list; -}; - -struct fnhe_hash_bucket { - struct fib_nh_exception *chain; -}; - -struct fib_info; - -struct fib_nh { - struct fib_nh_common nh_common; - struct hlist_node nh_hash; - struct fib_info *nh_parent; - __u32 nh_tclassid; - __be32 nh_saddr; - int nh_saddr_genid; -}; - -struct fib_info { - struct hlist_node fib_hash; - struct hlist_node fib_lhash; - struct list_head nh_list; - struct net *fib_net; - int fib_treeref; - refcount_t fib_clntref; - unsigned int fib_flags; - unsigned char fib_dead; - unsigned char fib_protocol; - unsigned char fib_scope; - unsigned char fib_type; - __be32 fib_prefsrc; - u32 fib_tb_id; - u32 fib_priority; - struct dst_metrics *fib_metrics; - int fib_nhs; - bool fib_nh_is_v6; - bool nh_updated; - struct nexthop *nh; - struct callback_head rcu; - struct fib_nh fib_nh[0]; -}; - -struct nh_info; - -struct nh_group; - -struct nexthop { - struct rb_node rb_node; - struct list_head fi_list; - struct list_head f6i_list; - struct list_head fdb_list; - struct list_head grp_list; - struct net *net; - u32 id; - u8 protocol; - u8 nh_flags; - bool is_group; - refcount_t refcnt; - struct callback_head rcu; - union { - struct nh_info *nh_info; - struct nh_group *nh_grp; - }; -}; - -struct rt6_exception_bucket { - struct hlist_head chain; - int depth; -}; - -struct nh_info { - struct hlist_node dev_hash; - struct nexthop *nh_parent; - u8 family; - bool reject_nh; - bool fdb_nh; - union { - struct fib_nh_common fib_nhc; - struct fib_nh fib_nh; - struct fib6_nh fib6_nh; - }; -}; - -struct nh_grp_entry { - struct nexthop *nh; - u8 weight; - atomic_t upper_bound; - struct list_head nh_list; - struct nexthop *nh_parent; -}; - -struct nh_group { - struct nh_group *spare; - u16 num_nh; - bool mpath; - bool fdb_nh; - bool has_v4; - struct nh_grp_entry nh_entries[0]; -}; - -struct udp_hslot { - struct hlist_head head; - int count; - spinlock_t lock; -}; - -struct udp_tunnel_nic_shared { - struct udp_tunnel_nic *udp_tunnel_nic_info; - struct list_head devices; -}; - -struct lan78xx_statstage { - u32 rx_fcs_errors; - u32 rx_alignment_errors; - u32 rx_fragment_errors; - u32 rx_jabber_errors; - u32 rx_undersize_frame_errors; - u32 rx_oversize_frame_errors; - u32 rx_dropped_frames; - u32 rx_unicast_byte_count; - u32 rx_broadcast_byte_count; - u32 rx_multicast_byte_count; - u32 rx_unicast_frames; - u32 rx_broadcast_frames; - u32 rx_multicast_frames; - u32 rx_pause_frames; - u32 rx_64_byte_frames; - u32 rx_65_127_byte_frames; - u32 rx_128_255_byte_frames; - u32 rx_256_511_bytes_frames; - u32 rx_512_1023_byte_frames; - u32 rx_1024_1518_byte_frames; - u32 rx_greater_1518_byte_frames; - u32 eee_rx_lpi_transitions; - u32 eee_rx_lpi_time; - u32 tx_fcs_errors; - u32 tx_excess_deferral_errors; - u32 tx_carrier_errors; - u32 tx_bad_byte_count; - u32 tx_single_collisions; - u32 tx_multiple_collisions; - u32 tx_excessive_collision; - u32 tx_late_collisions; - u32 tx_unicast_byte_count; - u32 tx_broadcast_byte_count; - u32 tx_multicast_byte_count; - u32 tx_unicast_frames; - u32 tx_broadcast_frames; - u32 tx_multicast_frames; - u32 tx_pause_frames; - u32 tx_64_byte_frames; - u32 tx_65_127_byte_frames; - u32 tx_128_255_byte_frames; - u32 tx_256_511_bytes_frames; - u32 tx_512_1023_byte_frames; - u32 tx_1024_1518_byte_frames; - u32 tx_greater_1518_byte_frames; - u32 eee_tx_lpi_transitions; - u32 eee_tx_lpi_time; -}; - -struct lan78xx_statstage64 { - u64 rx_fcs_errors; - u64 rx_alignment_errors; - u64 rx_fragment_errors; - u64 rx_jabber_errors; - u64 rx_undersize_frame_errors; - u64 rx_oversize_frame_errors; - u64 rx_dropped_frames; - u64 rx_unicast_byte_count; - u64 rx_broadcast_byte_count; - u64 rx_multicast_byte_count; - u64 rx_unicast_frames; - u64 rx_broadcast_frames; - u64 rx_multicast_frames; - u64 rx_pause_frames; - u64 rx_64_byte_frames; - u64 rx_65_127_byte_frames; - u64 rx_128_255_byte_frames; - u64 rx_256_511_bytes_frames; - u64 rx_512_1023_byte_frames; - u64 rx_1024_1518_byte_frames; - u64 rx_greater_1518_byte_frames; - u64 eee_rx_lpi_transitions; - u64 eee_rx_lpi_time; - u64 tx_fcs_errors; - u64 tx_excess_deferral_errors; - u64 tx_carrier_errors; - u64 tx_bad_byte_count; - u64 tx_single_collisions; - u64 tx_multiple_collisions; - u64 tx_excessive_collision; - u64 tx_late_collisions; - u64 tx_unicast_byte_count; - u64 tx_broadcast_byte_count; - u64 tx_multicast_byte_count; - u64 tx_unicast_frames; - u64 tx_broadcast_frames; - u64 tx_multicast_frames; - u64 tx_pause_frames; - u64 tx_64_byte_frames; - u64 tx_65_127_byte_frames; - u64 tx_128_255_byte_frames; - u64 tx_256_511_bytes_frames; - u64 tx_512_1023_byte_frames; - u64 tx_1024_1518_byte_frames; - u64 tx_greater_1518_byte_frames; - u64 eee_tx_lpi_transitions; - u64 eee_tx_lpi_time; -}; - -struct lan78xx_net; - -struct lan78xx_priv { - struct lan78xx_net *dev; - u32 rfe_ctl; - u32 mchash_table[16]; - u32 pfilter_table[66]; - u32 vlan_table[128]; - struct mutex dataport_mutex; - spinlock_t rfe_ctl_lock; - struct work_struct set_multicast; - struct work_struct set_vlan; - u32 wol; -}; - -struct statstage { - struct mutex access_lock; - struct lan78xx_statstage saved; - struct lan78xx_statstage rollover_count; - struct lan78xx_statstage rollover_max; - struct lan78xx_statstage64 curr_stat; -}; - -struct irq_domain_data { - struct irq_domain *irqdomain; - unsigned int phyirq; - struct irq_chip *irqchip; - irq_flow_handler_t irq_handler; - u32 irqenable; - struct mutex irq_lock; -}; - -struct lan78xx_net { - struct net_device *net; - struct usb_device *udev; - struct usb_interface *intf; - void *driver_priv; - int rx_qlen; - int tx_qlen; - struct sk_buff_head rxq; - struct sk_buff_head txq; - struct sk_buff_head done; - struct sk_buff_head rxq_pause; - struct sk_buff_head txq_pend; - struct tasklet_struct bh; - struct delayed_work wq; - int msg_enable; - struct urb *urb_intr; - struct usb_anchor deferred; - struct mutex phy_mutex; - unsigned int pipe_in; - unsigned int pipe_out; - unsigned int pipe_intr; - u32 hard_mtu; - size_t rx_urb_size; - long unsigned int flags; - wait_queue_head_t *wait; - unsigned char suspend_count; - unsigned int maxpacket; - struct timer_list delay; - struct timer_list stat_monitor; - long unsigned int data[5]; - int link_on; - u8 mdix_ctrl; - u32 chipid; - u32 chiprev; - struct mii_bus *mdiobus; - phy_interface_t interface; - int fc_autoneg; - u8 fc_request_control; - int delta; - struct statstage stats; - struct irq_domain_data domain_data; -}; - -enum skb_state { - illegal = 0, - tx_start = 1, - tx_done = 2, - rx_start = 3, - rx_done = 4, - rx_cleanup = 5, - unlink_start = 6, -}; - -struct skb_data { - struct urb *urb; - struct lan78xx_net *dev; - enum skb_state state; - size_t length; - int num_of_packet; -}; - -struct driver_info; - -struct usbnet { - struct usb_device *udev; - struct usb_interface *intf; - const struct driver_info *driver_info; - const char *driver_name; - void *driver_priv; - wait_queue_head_t wait; - struct mutex phy_mutex; - unsigned char suspend_count; - unsigned char pkt_cnt; - unsigned char pkt_err; - short unsigned int rx_qlen; - short unsigned int tx_qlen; - unsigned int can_dma_sg: 1; - unsigned int in; - unsigned int out; - struct usb_host_endpoint *status; - unsigned int maxpacket; - struct timer_list delay; - const char *padding_pkt; - struct net_device *net; - int msg_enable; - long unsigned int data[5]; - u32 xid; - u32 hard_mtu; - size_t rx_urb_size; - struct mii_if_info mii; - struct sk_buff_head rxq; - struct sk_buff_head txq; - struct sk_buff_head done; - struct sk_buff_head rxq_pause; - struct urb *interrupt; - unsigned int interrupt_count; - struct mutex interrupt_mutex; - struct usb_anchor deferred; - struct tasklet_struct bh; - struct pcpu_sw_netstats *stats64; - struct work_struct kevent; - long unsigned int flags; - u32 rx_speed; - u32 tx_speed; -}; - -struct driver_info { - char *description; - int flags; - int (*bind)(struct usbnet *, struct usb_interface *); - void (*unbind)(struct usbnet *, struct usb_interface *); - int (*reset)(struct usbnet *); - int (*stop)(struct usbnet *); - int (*check_connect)(struct usbnet *); - int (*manage_power)(struct usbnet *, int); - void (*status)(struct usbnet *, struct urb *); - int (*link_reset)(struct usbnet *); - int (*rx_fixup)(struct usbnet *, struct sk_buff *); - struct sk_buff * (*tx_fixup)(struct usbnet *, struct sk_buff *, gfp_t); - void (*recover)(struct usbnet *); - int (*early_init)(struct usbnet *); - void (*indication)(struct usbnet *, void *, int); - void (*set_rx_mode)(struct usbnet *); - int in; - int out; - long unsigned int data; -}; - -struct smsc95xx_priv { - u32 mac_cr; - u32 hash_hi; - u32 hash_lo; - u32 wolopts; - spinlock_t mac_cr_lock; - u8 features; - u8 suspend_flags; - struct mii_bus *mdiobus; - struct phy_device *phydev; -}; - -struct usb_ctrlrequest { - __u8 bRequestType; - __u8 bRequest; - __le16 wValue; - __le16 wIndex; - __le16 wLength; -}; - -struct skb_data___2 { - struct urb *urb; - struct usbnet *dev; - enum skb_state state; - long int length; - long unsigned int packets; -}; - -enum usb_otg_state { - OTG_STATE_UNDEFINED = 0, - OTG_STATE_B_IDLE = 1, - OTG_STATE_B_SRP_INIT = 2, - OTG_STATE_B_PERIPHERAL = 3, - OTG_STATE_B_WAIT_ACON = 4, - OTG_STATE_B_HOST = 5, - OTG_STATE_A_IDLE = 6, - OTG_STATE_A_WAIT_VRISE = 7, - OTG_STATE_A_WAIT_BCON = 8, - OTG_STATE_A_HOST = 9, - OTG_STATE_A_SUSPEND = 10, - OTG_STATE_A_PERIPHERAL = 11, - OTG_STATE_A_WAIT_VFALL = 12, - OTG_STATE_A_VBUS_ERR = 13, -}; - -struct usb_otg_caps { - u16 otg_rev; - bool hnp_support; - bool srp_support; - bool adp_support; -}; - -enum usb_dr_mode { - USB_DR_MODE_UNKNOWN = 0, - USB_DR_MODE_HOST = 1, - USB_DR_MODE_PERIPHERAL = 2, - USB_DR_MODE_OTG = 3, -}; - -struct usb_descriptor_header { - __u8 bLength; - __u8 bDescriptorType; -}; - -enum usb3_link_state { - USB3_LPM_U0 = 0, - USB3_LPM_U1 = 1, - USB3_LPM_U2 = 2, - USB3_LPM_U3 = 3, -}; - -enum usb_port_connect_type { - USB_PORT_CONNECT_TYPE_UNKNOWN = 0, - USB_PORT_CONNECT_TYPE_HOT_PLUG = 1, - USB_PORT_CONNECT_TYPE_HARD_WIRED = 2, - USB_PORT_NOT_USED = 3, -}; - -struct usb_tt { - struct usb_device *hub; - int multi; - unsigned int think_time; - void *hcpriv; - spinlock_t lock; - struct list_head clear_list; - struct work_struct clear_work; -}; - -struct usb_device_driver { - const char *name; - bool (*match)(struct usb_device *); - int (*probe)(struct usb_device *); - void (*disconnect)(struct usb_device *); - int (*suspend)(struct usb_device *, pm_message_t); - int (*resume)(struct usb_device *, pm_message_t); - const struct attribute_group **dev_groups; - struct usbdrv_wrap drvwrap; - const struct usb_device_id *id_table; - unsigned int supports_autosuspend: 1; - unsigned int generic_subclass: 1; -}; - -struct giveback_urb_bh { - bool running; - spinlock_t lock; - struct list_head head; - struct tasklet_struct bh; - struct usb_host_endpoint *completing_ep; -}; - -enum usb_dev_authorize_policy { - USB_DEVICE_AUTHORIZE_NONE = 0, - USB_DEVICE_AUTHORIZE_ALL = 1, - USB_DEVICE_AUTHORIZE_INTERNAL = 2, -}; - -struct usb_phy_roothub; - -struct hc_driver; - -struct usb_phy; - -struct usb_hcd { - struct usb_bus self; - struct kref kref; - const char *product_desc; - int speed; - char irq_descr[24]; - struct timer_list rh_timer; - struct urb *status_urb; - struct work_struct wakeup_work; - struct work_struct died_work; - const struct hc_driver *driver; - struct usb_phy *usb_phy; - struct usb_phy_roothub *phy_roothub; - long unsigned int flags; - enum usb_dev_authorize_policy dev_policy; - unsigned int rh_registered: 1; - unsigned int rh_pollable: 1; - unsigned int msix_enabled: 1; - unsigned int msi_enabled: 1; - unsigned int skip_phy_initialization: 1; - unsigned int uses_new_polling: 1; - unsigned int wireless: 1; - unsigned int has_tt: 1; - unsigned int amd_resume_bug: 1; - unsigned int can_do_streams: 1; - unsigned int tpl_support: 1; - unsigned int cant_recv_wakeups: 1; - unsigned int irq; - void *regs; - resource_size_t rsrc_start; - resource_size_t rsrc_len; - unsigned int power_budget; - struct giveback_urb_bh high_prio_bh; - struct giveback_urb_bh low_prio_bh; - struct mutex *address0_mutex; - struct mutex *bandwidth_mutex; - struct usb_hcd *shared_hcd; - struct usb_hcd *primary_hcd; - struct dma_pool___2 *pool[4]; - int state; - struct gen_pool *localmem_pool; - long unsigned int hcd_priv[0]; -}; - -struct hc_driver { - const char *description; - const char *product_desc; - size_t hcd_priv_size; - irqreturn_t (*irq)(struct usb_hcd *); - int flags; - int (*reset)(struct usb_hcd *); - int (*start)(struct usb_hcd *); - int (*pci_suspend)(struct usb_hcd *, bool); - int (*pci_resume)(struct usb_hcd *, bool); - void (*stop)(struct usb_hcd *); - void (*shutdown)(struct usb_hcd *); - int (*get_frame_number)(struct usb_hcd *); - int (*urb_enqueue)(struct usb_hcd *, struct urb *, gfp_t); - int (*urb_dequeue)(struct usb_hcd *, struct urb *, int); - int (*map_urb_for_dma)(struct usb_hcd *, struct urb *, gfp_t); - void (*unmap_urb_for_dma)(struct usb_hcd *, struct urb *); - void (*endpoint_disable)(struct usb_hcd *, struct usb_host_endpoint *); - void (*endpoint_reset)(struct usb_hcd *, struct usb_host_endpoint *); - int (*hub_status_data)(struct usb_hcd *, char *); - int (*hub_control)(struct usb_hcd *, u16, u16, u16, char *, u16); - int (*bus_suspend)(struct usb_hcd *); - int (*bus_resume)(struct usb_hcd *); - int (*start_port_reset)(struct usb_hcd *, unsigned int); - long unsigned int (*get_resuming_ports)(struct usb_hcd *); - void (*relinquish_port)(struct usb_hcd *, int); - int (*port_handed_over)(struct usb_hcd *, int); - void (*clear_tt_buffer_complete)(struct usb_hcd *, struct usb_host_endpoint *); - int (*alloc_dev)(struct usb_hcd *, struct usb_device *); - void (*free_dev)(struct usb_hcd *, struct usb_device *); - int (*alloc_streams)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint **, unsigned int, unsigned int, gfp_t); - int (*free_streams)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint **, unsigned int, gfp_t); - int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); - int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); - int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); - void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); - void (*fixup_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *, int); - int (*address_device)(struct usb_hcd *, struct usb_device *); - int (*enable_device)(struct usb_hcd *, struct usb_device *); - int (*update_hub_device)(struct usb_hcd *, struct usb_device *, struct usb_tt *, gfp_t); - int (*reset_device)(struct usb_hcd *, struct usb_device *); - int (*update_device)(struct usb_hcd *, struct usb_device *); - int (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int); - int (*enable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state); - int (*disable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state); - int (*find_raw_port_number)(struct usb_hcd *, int); - int (*port_power)(struct usb_hcd *, int, bool); -}; - -enum usb_phy_type { - USB_PHY_TYPE_UNDEFINED = 0, - USB_PHY_TYPE_USB2 = 1, - USB_PHY_TYPE_USB3 = 2, -}; - -enum usb_phy_events { - USB_EVENT_NONE = 0, - USB_EVENT_VBUS = 1, - USB_EVENT_ID = 2, - USB_EVENT_CHARGER = 3, - USB_EVENT_ENUMERATED = 4, -}; - -struct extcon_dev; - -enum usb_charger_type { - UNKNOWN_TYPE = 0, - SDP_TYPE = 1, - DCP_TYPE = 2, - CDP_TYPE = 3, - ACA_TYPE = 4, -}; - -enum usb_charger_state { - USB_CHARGER_DEFAULT = 0, - USB_CHARGER_PRESENT = 1, - USB_CHARGER_ABSENT = 2, -}; - -struct usb_charger_current { - unsigned int sdp_min; - unsigned int sdp_max; - unsigned int dcp_min; - unsigned int dcp_max; - unsigned int cdp_min; - unsigned int cdp_max; - unsigned int aca_min; - unsigned int aca_max; -}; - -struct usb_otg; - -struct usb_phy_io_ops; - -struct usb_phy { - struct device *dev; - const char *label; - unsigned int flags; - enum usb_phy_type type; - enum usb_phy_events last_event; - struct usb_otg *otg; - struct device *io_dev; - struct usb_phy_io_ops *io_ops; - void *io_priv; - struct extcon_dev *edev; - struct extcon_dev *id_edev; - struct notifier_block vbus_nb; - struct notifier_block id_nb; - struct notifier_block type_nb; - enum usb_charger_type chg_type; - enum usb_charger_state chg_state; - struct usb_charger_current chg_cur; - struct work_struct chg_work; - struct atomic_notifier_head notifier; - u16 port_status; - u16 port_change; - struct list_head head; - int (*init)(struct usb_phy *); - void (*shutdown)(struct usb_phy *); - int (*set_vbus)(struct usb_phy *, int); - int (*set_power)(struct usb_phy *, unsigned int); - int (*set_suspend)(struct usb_phy *, int); - int (*set_wakeup)(struct usb_phy *, bool); - int (*notify_connect)(struct usb_phy *, enum usb_device_speed); - int (*notify_disconnect)(struct usb_phy *, enum usb_device_speed); - enum usb_charger_type (*charger_detect)(struct usb_phy *); -}; - -struct usb_port_status { - __le16 wPortStatus; - __le16 wPortChange; - __le32 dwExtPortStatus; -}; - -struct usb_hub_status { - __le16 wHubStatus; - __le16 wHubChange; -}; - -struct usb_hub_descriptor { - __u8 bDescLength; - __u8 bDescriptorType; - __u8 bNbrPorts; - __le16 wHubCharacteristics; - __u8 bPwrOn2PwrGood; - __u8 bHubContrCurrent; - union { - struct { - __u8 DeviceRemovable[4]; - __u8 PortPwrCtrlMask[4]; - } hs; - struct { - __u8 bHubHdrDecLat; - __le16 wHubDelay; - __le16 DeviceRemovable; - } __attribute__((packed)) ss; - } u; -} __attribute__((packed)); - -struct usb_phy_io_ops { - int (*read)(struct usb_phy *, u32); - int (*write)(struct usb_phy *, u32, u32); -}; - -struct usb_gadget; - -struct usb_otg { - u8 default_a; - struct phy *phy; - struct usb_phy *usb_phy; - struct usb_bus *host; - struct usb_gadget *gadget; - enum usb_otg_state state; - int (*set_host)(struct usb_otg *, struct usb_bus *); - int (*set_peripheral)(struct usb_otg *, struct usb_gadget *); - int (*set_vbus)(struct usb_otg *, bool); - int (*start_srp)(struct usb_otg *); - int (*start_hnp)(struct usb_otg *); -}; - -typedef u32 usb_port_location_t; - -struct usb_port; - -struct usb_hub { - struct device *intfdev; - struct usb_device *hdev; - struct kref kref; - struct urb *urb; - u8 (*buffer)[8]; - union { - struct usb_hub_status hub; - struct usb_port_status port; - } *status; - struct mutex status_mutex; - int error; - int nerrors; - long unsigned int event_bits[1]; - long unsigned int change_bits[1]; - long unsigned int removed_bits[1]; - long unsigned int wakeup_bits[1]; - long unsigned int power_bits[1]; - long unsigned int child_usage_bits[1]; - long unsigned int warm_reset_bits[1]; - struct usb_hub_descriptor *descriptor; - struct usb_tt tt; - unsigned int mA_per_port; - unsigned int wakeup_enabled_descendants; - unsigned int limited_power: 1; - unsigned int quiescing: 1; - unsigned int disconnected: 1; - unsigned int in_reset: 1; - unsigned int quirk_disable_autosuspend: 1; - unsigned int quirk_check_port_auto_suspend: 1; - unsigned int has_indicators: 1; - u8 indicator[31]; - struct delayed_work leds; - struct delayed_work init_work; - struct work_struct events; - spinlock_t irq_urb_lock; - struct timer_list irq_urb_retry; - struct usb_port **ports; -}; - -struct usb_dev_state; - -struct usb_port { - struct usb_device *child; - struct device dev; - struct usb_dev_state *port_owner; - struct usb_port *peer; - struct dev_pm_qos_request *req; - enum usb_port_connect_type connect_type; - usb_port_location_t location; - struct mutex status_lock; - u32 over_current_count; - u8 portnum; - u32 quirks; - unsigned int is_superspeed: 1; - unsigned int usb3_lpm_u1_permit: 1; - unsigned int usb3_lpm_u2_permit: 1; -}; - -struct find_interface_arg { - int minor; - struct device_driver *drv; -}; - -struct each_dev_arg { - void *data; - int (*fn)(struct usb_device *, void *); -}; - -struct usb_qualifier_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __u8 bNumConfigurations; - __u8 bRESERVED; -}; - -struct usb_set_sel_req { - __u8 u1_sel; - __u8 u1_pel; - __le16 u2_sel; - __le16 u2_pel; -}; - -struct usbdevfs_hub_portinfo { - char nports; - char port[127]; -}; - -enum hub_led_mode { - INDICATOR_AUTO = 0, - INDICATOR_CYCLE = 1, - INDICATOR_GREEN_BLINK = 2, - INDICATOR_GREEN_BLINK_OFF = 3, - INDICATOR_AMBER_BLINK = 4, - INDICATOR_AMBER_BLINK_OFF = 5, - INDICATOR_ALT_BLINK = 6, - INDICATOR_ALT_BLINK_OFF = 7, -}; - -struct usb_tt_clear { - struct list_head clear_list; - unsigned int tt; - u16 devinfo; - struct usb_hcd *hcd; - struct usb_host_endpoint *ep; -}; - -enum hub_activation_type { - HUB_INIT = 0, - HUB_INIT2 = 1, - HUB_INIT3 = 2, - HUB_POST_RESET = 3, - HUB_RESUME = 4, - HUB_RESET_RESUME = 5, -}; - -enum hub_quiescing_type { - HUB_DISCONNECT = 0, - HUB_PRE_RESET = 1, - HUB_SUSPEND = 2, -}; - -enum usb_led_event { - USB_LED_EVENT_HOST = 0, - USB_LED_EVENT_GADGET = 1, -}; - -struct usb_mon_operations { - void (*urb_submit)(struct usb_bus *, struct urb *); - void (*urb_submit_error)(struct usb_bus *, struct urb *, int); - void (*urb_complete)(struct usb_bus *, struct urb *, int); -}; - -struct usb_sg_request { - int status; - size_t bytes; - spinlock_t lock; - struct usb_device *dev; - int pipe; - int entries; - struct urb **urbs; - int count; - struct completion complete; -}; - -struct usb_cdc_header_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdCDC; -} __attribute__((packed)); - -struct usb_cdc_call_mgmt_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bmCapabilities; - __u8 bDataInterface; -}; - -struct usb_cdc_acm_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bmCapabilities; -}; - -struct usb_cdc_union_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bMasterInterface0; - __u8 bSlaveInterface0; -}; - -struct usb_cdc_country_functional_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 iCountryCodeRelDate; - __le16 wCountyCode0; -}; - -struct usb_cdc_network_terminal_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bEntityId; - __u8 iName; - __u8 bChannelIndex; - __u8 bPhysicalInterface; -}; - -struct usb_cdc_ether_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 iMACAddress; - __le32 bmEthernetStatistics; - __le16 wMaxSegmentSize; - __le16 wNumberMCFilters; - __u8 bNumberPowerFilters; -} __attribute__((packed)); - -struct usb_cdc_dmm_desc { - __u8 bFunctionLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u16 bcdVersion; - __le16 wMaxCommand; -} __attribute__((packed)); - -struct usb_cdc_mdlm_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdVersion; - __u8 bGUID[16]; -} __attribute__((packed)); - -struct usb_cdc_mdlm_detail_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bGuidDescriptorType; - __u8 bDetailData[0]; -}; - -struct usb_cdc_obex_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdVersion; -} __attribute__((packed)); - -struct usb_cdc_ncm_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdNcmVersion; - __u8 bmNetworkCapabilities; -} __attribute__((packed)); - -struct usb_cdc_mbim_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdMBIMVersion; - __le16 wMaxControlMessage; - __u8 bNumberFilters; - __u8 bMaxFilterSize; - __le16 wMaxSegmentSize; - __u8 bmNetworkCapabilities; -} __attribute__((packed)); - -struct usb_cdc_mbim_extended_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdMBIMExtendedVersion; - __u8 bMaxOutstandingCommandMessages; - __le16 wMTU; -} __attribute__((packed)); - -struct usb_cdc_parsed_header { - struct usb_cdc_union_desc *usb_cdc_union_desc; - struct usb_cdc_header_desc *usb_cdc_header_desc; - struct usb_cdc_call_mgmt_descriptor *usb_cdc_call_mgmt_descriptor; - struct usb_cdc_acm_descriptor *usb_cdc_acm_descriptor; - struct usb_cdc_country_functional_desc *usb_cdc_country_functional_desc; - struct usb_cdc_network_terminal_desc *usb_cdc_network_terminal_desc; - struct usb_cdc_ether_desc *usb_cdc_ether_desc; - struct usb_cdc_dmm_desc *usb_cdc_dmm_desc; - struct usb_cdc_mdlm_desc *usb_cdc_mdlm_desc; - struct usb_cdc_mdlm_detail_desc *usb_cdc_mdlm_detail_desc; - struct usb_cdc_obex_desc *usb_cdc_obex_desc; - struct usb_cdc_ncm_desc *usb_cdc_ncm_desc; - struct usb_cdc_mbim_desc *usb_cdc_mbim_desc; - struct usb_cdc_mbim_extended_desc *usb_cdc_mbim_extended_desc; - bool phonet_magic_present; -}; - -struct api_context { - struct completion done; - int status; -}; - -struct set_config_request { - struct usb_device *udev; - int config; - struct work_struct work; - struct list_head node; -}; - -struct usb_dynid { - struct list_head node; - struct usb_device_id id; -}; - -struct usb_dev_cap_header { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; -}; - -struct usb_class_driver { - char *name; - char * (*devnode)(struct device *, umode_t *); - const struct file_operations *fops; - int minor_base; -}; - -struct usb_class { - struct kref kref; - struct class *class; -}; - -struct ep_device { - struct usb_endpoint_descriptor *desc; - struct usb_device *udev; - struct device dev; -}; - -struct usbdevfs_ctrltransfer { - __u8 bRequestType; - __u8 bRequest; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - __u32 timeout; - void *data; -}; - -struct usbdevfs_bulktransfer { - unsigned int ep; - unsigned int len; - unsigned int timeout; - void *data; -}; - -struct usbdevfs_setinterface { - unsigned int interface; - unsigned int altsetting; -}; - -struct usbdevfs_disconnectsignal { - unsigned int signr; - void *context; -}; - -struct usbdevfs_getdriver { - unsigned int interface; - char driver[256]; -}; - -struct usbdevfs_connectinfo { - unsigned int devnum; - unsigned char slow; -}; - -struct usbdevfs_conninfo_ex { - __u32 size; - __u32 busnum; - __u32 devnum; - __u32 speed; - __u8 num_ports; - __u8 ports[7]; -}; - -struct usbdevfs_iso_packet_desc { - unsigned int length; - unsigned int actual_length; - unsigned int status; -}; - -struct usbdevfs_urb { - unsigned char type; - unsigned char endpoint; - int status; - unsigned int flags; - void *buffer; - int buffer_length; - int actual_length; - int start_frame; - union { - int number_of_packets; - unsigned int stream_id; - }; - int error_count; - unsigned int signr; - void *usercontext; - struct usbdevfs_iso_packet_desc iso_frame_desc[0]; -}; - -struct usbdevfs_ioctl { - int ifno; - int ioctl_code; - void *data; -}; - -struct usbdevfs_disconnect_claim { - unsigned int interface; - unsigned int flags; - char driver[256]; -}; - -struct usbdevfs_streams { - unsigned int num_streams; - unsigned int num_eps; - unsigned char eps[0]; -}; - -struct usbdevfs_ctrltransfer32 { - u8 bRequestType; - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; - u32 timeout; - compat_caddr_t data; -}; - -struct usbdevfs_bulktransfer32 { - compat_uint_t ep; - compat_uint_t len; - compat_uint_t timeout; - compat_caddr_t data; -}; - -struct usbdevfs_disconnectsignal32 { - compat_int_t signr; - compat_caddr_t context; -}; - -struct usbdevfs_urb32 { - unsigned char type; - unsigned char endpoint; - compat_int_t status; - compat_uint_t flags; - compat_caddr_t buffer; - compat_int_t buffer_length; - compat_int_t actual_length; - compat_int_t start_frame; - compat_int_t number_of_packets; - compat_int_t error_count; - compat_uint_t signr; - compat_caddr_t usercontext; - struct usbdevfs_iso_packet_desc iso_frame_desc[0]; -}; - -struct usbdevfs_ioctl32 { - s32 ifno; - s32 ioctl_code; - compat_caddr_t data; -}; - -struct usb_dev_state___2 { - struct list_head list; - struct usb_device *dev; - struct file *file; - spinlock_t lock; - struct list_head async_pending; - struct list_head async_completed; - struct list_head memory_list; - wait_queue_head_t wait; - wait_queue_head_t wait_for_resume; - unsigned int discsignr; - struct pid *disc_pid; - const struct cred *cred; - sigval_t disccontext; - long unsigned int ifclaimed; - u32 disabled_bulk_eps; - long unsigned int interface_allowed_mask; - int not_yet_resumed; - bool suspend_allowed; - bool privileges_dropped; -}; - -struct usb_memory { - struct list_head memlist; - int vma_use_count; - int urb_use_count; - u32 size; - void *mem; - dma_addr_t dma_handle; - long unsigned int vm_start; - struct usb_dev_state___2 *ps; -}; - -struct async { - struct list_head asynclist; - struct usb_dev_state___2 *ps; - struct pid *pid; - const struct cred *cred; - unsigned int signr; - unsigned int ifnum; - void *userbuffer; - void *userurb; - sigval_t userurb_sigval; - struct urb *urb; - struct usb_memory *usbm; - unsigned int mem_usage; - int status; - u8 bulk_addr; - u8 bulk_status; -}; - -enum snoop_when { - SUBMIT = 0, - COMPLETE___2 = 1, -}; - -struct quirk_entry { - u16 vid; - u16 pid; - u32 flags; -}; - -struct class_info { - int class; - char *class_name; -}; - -struct usb_phy_roothub___2 { - struct phy *phy; - struct list_head list; -}; - -typedef void (*companion_fn)(struct pci_dev *, struct usb_hcd *, struct pci_dev *, struct usb_hcd *); - -struct phy_devm { - struct usb_phy *phy; - struct notifier_block *nb; -}; - -enum usb_phy_interface { - USBPHY_INTERFACE_MODE_UNKNOWN = 0, - USBPHY_INTERFACE_MODE_UTMI = 1, - USBPHY_INTERFACE_MODE_UTMIW = 2, - USBPHY_INTERFACE_MODE_ULPI = 3, - USBPHY_INTERFACE_MODE_SERIAL = 4, - USBPHY_INTERFACE_MODE_HSIC = 5, -}; - -struct usb_ep; - -struct usb_request { - void *buf; - unsigned int length; - dma_addr_t dma; - struct scatterlist *sg; - unsigned int num_sgs; - unsigned int num_mapped_sgs; - unsigned int stream_id: 16; - unsigned int is_last: 1; - unsigned int no_interrupt: 1; - unsigned int zero: 1; - unsigned int short_not_ok: 1; - unsigned int dma_mapped: 1; - void (*complete)(struct usb_ep *, struct usb_request *); - void *context; - struct list_head list; - unsigned int frame_number; - int status; - unsigned int actual; -}; - -struct usb_ep_caps { - unsigned int type_control: 1; - unsigned int type_iso: 1; - unsigned int type_bulk: 1; - unsigned int type_int: 1; - unsigned int dir_in: 1; - unsigned int dir_out: 1; -}; - -struct usb_ep_ops; - -struct usb_ep { - void *driver_data; - const char *name; - const struct usb_ep_ops *ops; - struct list_head ep_list; - struct usb_ep_caps caps; - bool claimed; - bool enabled; - unsigned int maxpacket: 16; - unsigned int maxpacket_limit: 16; - unsigned int max_streams: 16; - unsigned int mult: 2; - unsigned int maxburst: 5; - u8 address; - const struct usb_endpoint_descriptor *desc; - const struct usb_ss_ep_comp_descriptor *comp_desc; -}; - -struct usb_ep_ops { - int (*enable)(struct usb_ep *, const struct usb_endpoint_descriptor *); - int (*disable)(struct usb_ep *); - void (*dispose)(struct usb_ep *); - struct usb_request * (*alloc_request)(struct usb_ep *, gfp_t); - void (*free_request)(struct usb_ep *, struct usb_request *); - int (*queue)(struct usb_ep *, struct usb_request *, gfp_t); - int (*dequeue)(struct usb_ep *, struct usb_request *); - int (*set_halt)(struct usb_ep *, int); - int (*set_wedge)(struct usb_ep *); - int (*fifo_status)(struct usb_ep *); - void (*fifo_flush)(struct usb_ep *); -}; - -struct usb_dcd_config_params { - __u8 bU1devExitLat; - __le16 bU2DevExitLat; - __u8 besl_baseline; - __u8 besl_deep; -}; - -struct usb_gadget_driver; - -struct usb_gadget_ops { - int (*get_frame)(struct usb_gadget *); - int (*wakeup)(struct usb_gadget *); - int (*set_selfpowered)(struct usb_gadget *, int); - int (*vbus_session)(struct usb_gadget *, int); - int (*vbus_draw)(struct usb_gadget *, unsigned int); - int (*pullup)(struct usb_gadget *, int); - int (*ioctl)(struct usb_gadget *, unsigned int, long unsigned int); - void (*get_config_params)(struct usb_gadget *, struct usb_dcd_config_params *); - int (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); - int (*udc_stop)(struct usb_gadget *); - void (*udc_set_speed)(struct usb_gadget *, enum usb_device_speed); - struct usb_ep * (*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); -}; - -struct usb_udc; - -struct usb_gadget { - struct work_struct work; - struct usb_udc *udc; - const struct usb_gadget_ops *ops; - struct usb_ep *ep0; - struct list_head ep_list; - enum usb_device_speed speed; - enum usb_device_speed max_speed; - enum usb_device_state state; - const char *name; - struct device dev; - unsigned int isoch_delay; - unsigned int out_epnum; - unsigned int in_epnum; - unsigned int mA; - struct usb_otg_caps *otg_caps; - unsigned int sg_supported: 1; - unsigned int is_otg: 1; - unsigned int is_a_peripheral: 1; - unsigned int b_hnp_enable: 1; - unsigned int a_hnp_support: 1; - unsigned int a_alt_hnp_support: 1; - unsigned int hnp_polling_support: 1; - unsigned int host_request_flag: 1; - unsigned int quirk_ep_out_aligned_size: 1; - unsigned int quirk_altset_not_supp: 1; - unsigned int quirk_stall_not_supp: 1; - unsigned int quirk_zlp_not_supp: 1; - unsigned int quirk_avoids_skb_reserve: 1; - unsigned int is_selfpowered: 1; - unsigned int deactivated: 1; - unsigned int connected: 1; - unsigned int lpm_capable: 1; - int irq; -}; - -struct usb_gadget_driver { - char *function; - enum usb_device_speed max_speed; - int (*bind)(struct usb_gadget *, struct usb_gadget_driver *); - void (*unbind)(struct usb_gadget *); - int (*setup)(struct usb_gadget *, const struct usb_ctrlrequest *); - void (*disconnect)(struct usb_gadget *); - void (*suspend)(struct usb_gadget *); - void (*resume)(struct usb_gadget *); - void (*reset)(struct usb_gadget *); - struct device_driver driver; - char *udc_name; - struct list_head pending; - unsigned int match_existing_only: 1; -}; - -struct usb_phy_generic { - struct usb_phy phy; - struct device *dev; - struct clk *clk; - struct regulator *vcc; - struct gpio_desc *gpiod_reset; - struct gpio_desc *gpiod_vbus; - struct regulator *vbus_draw; - bool vbus_draw_enabled; - long unsigned int mA; - unsigned int vbus; -}; - -enum amd_chipset_gen { - NOT_AMD_CHIPSET = 0, - AMD_CHIPSET_SB600 = 1, - AMD_CHIPSET_SB700 = 2, - AMD_CHIPSET_SB800 = 3, - AMD_CHIPSET_HUDSON2 = 4, - AMD_CHIPSET_BOLTON = 5, - AMD_CHIPSET_YANGTZE = 6, - AMD_CHIPSET_TAISHAN = 7, - AMD_CHIPSET_UNKNOWN = 8, -}; - -struct amd_chipset_type { - enum amd_chipset_gen gen; - u8 rev; -}; - -struct amd_chipset_info { - struct pci_dev *nb_dev; - struct pci_dev *smbus_dev; - int nb_type; - struct amd_chipset_type sb_type; - int isoc_reqs; - int probe_count; - bool need_pll_quirk; -}; - -struct xhci_cap_regs { - __le32 hc_capbase; - __le32 hcs_params1; - __le32 hcs_params2; - __le32 hcs_params3; - __le32 hcc_params; - __le32 db_off; - __le32 run_regs_off; - __le32 hcc_params2; -}; - -struct xhci_op_regs { - __le32 command; - __le32 status; - __le32 page_size; - __le32 reserved1; - __le32 reserved2; - __le32 dev_notification; - __le64 cmd_ring; - __le32 reserved3[4]; - __le64 dcbaa_ptr; - __le32 config_reg; - __le32 reserved4[241]; - __le32 port_status_base; - __le32 port_power_base; - __le32 port_link_base; - __le32 reserved5; - __le32 reserved6[1016]; -}; - -struct xhci_intr_reg { - __le32 irq_pending; - __le32 irq_control; - __le32 erst_size; - __le32 rsvd; - __le64 erst_base; - __le64 erst_dequeue; -}; - -struct xhci_run_regs { - __le32 microframe_index; - __le32 rsvd[7]; - struct xhci_intr_reg ir_set[128]; -}; - -struct xhci_doorbell_array { - __le32 doorbell[256]; -}; - -struct xhci_container_ctx { - unsigned int type; - int size; - u8 *bytes; - dma_addr_t dma; -}; - -struct xhci_slot_ctx { - __le32 dev_info; - __le32 dev_info2; - __le32 tt_info; - __le32 dev_state; - __le32 reserved[4]; -}; - -struct xhci_ep_ctx { - __le32 ep_info; - __le32 ep_info2; - __le64 deq; - __le32 tx_info; - __le32 reserved[3]; -}; - -struct xhci_input_control_ctx { - __le32 drop_flags; - __le32 add_flags; - __le32 rsvd2[6]; -}; - -union xhci_trb; - -struct xhci_command { - struct xhci_container_ctx *in_ctx; - u32 status; - int slot_id; - struct completion *completion; - union xhci_trb *command_trb; - struct list_head cmd_list; -}; - -struct xhci_link_trb { - __le64 segment_ptr; - __le32 intr_target; - __le32 control; -}; - -struct xhci_transfer_event { - __le64 buffer; - __le32 transfer_len; - __le32 flags; -}; - -struct xhci_event_cmd { - __le64 cmd_trb; - __le32 status; - __le32 flags; -}; - -struct xhci_generic_trb { - __le32 field[4]; -}; - -union xhci_trb { - struct xhci_link_trb link; - struct xhci_transfer_event trans_event; - struct xhci_event_cmd event_cmd; - struct xhci_generic_trb generic; -}; - -struct xhci_stream_ctx { - __le64 stream_ring; - __le32 reserved[2]; -}; - -struct xhci_ring; - -struct xhci_stream_info { - struct xhci_ring **stream_rings; - unsigned int num_streams; - struct xhci_stream_ctx *stream_ctx_array; - unsigned int num_stream_ctxs; - dma_addr_t ctx_array_dma; - struct xarray trb_address_map; - struct xhci_command *free_streams_command; -}; - -enum xhci_ring_type { - TYPE_CTRL = 0, - TYPE_ISOC = 1, - TYPE_BULK = 2, - TYPE_INTR = 3, - TYPE_STREAM = 4, - TYPE_COMMAND = 5, - TYPE_EVENT = 6, -}; - -struct xhci_segment; - -struct xhci_ring { - struct xhci_segment *first_seg; - struct xhci_segment *last_seg; - union xhci_trb *enqueue; - struct xhci_segment *enq_seg; - union xhci_trb *dequeue; - struct xhci_segment *deq_seg; - struct list_head td_list; - u32 cycle_state; - unsigned int err_count; - unsigned int stream_id; - unsigned int num_segs; - unsigned int num_trbs_free; - unsigned int num_trbs_free_temp; - unsigned int bounce_buf_len; - unsigned int trbs_per_seg; - enum xhci_ring_type type; - bool last_td_was_short; - struct xarray *trb_address_map; -}; - -struct xhci_bw_info { - unsigned int ep_interval; - unsigned int mult; - unsigned int num_packets; - unsigned int max_packet_size; - unsigned int max_esit_payload; - unsigned int type; -}; - -struct xhci_hcd; - -struct xhci_virt_ep { - struct xhci_ring *ring; - struct xhci_stream_info *stream_info; - struct xhci_ring *new_ring; - unsigned int ep_state; - struct list_head cancelled_td_list; - struct timer_list stop_cmd_timer; - struct xhci_hcd *xhci; - struct xhci_segment *queued_deq_seg; - union xhci_trb *queued_deq_ptr; - bool skip; - struct xhci_bw_info bw_info; - struct list_head bw_endpoint_list; - int next_frame_id; - bool use_extended_tbc; -}; - -struct xhci_erst_entry; - -struct xhci_erst { - struct xhci_erst_entry *entries; - unsigned int num_entries; - dma_addr_t erst_dma_addr; - unsigned int erst_size; -}; - -struct s3_save { - u32 command; - u32 dev_nt; - u64 dcbaa_ptr; - u32 config_reg; - u32 irq_pending; - u32 irq_control; - u32 erst_size; - u64 erst_base; - u64 erst_dequeue; -}; - -struct xhci_bus_state { - long unsigned int bus_suspended; - long unsigned int next_statechange; - u32 port_c_suspend; - u32 suspended_ports; - u32 port_remote_wakeup; - long unsigned int resume_done[31]; - long unsigned int resuming_ports; - long unsigned int rexit_ports; - struct completion rexit_done[31]; - struct completion u3exit_done[31]; -}; - -struct xhci_port; - -struct xhci_hub { - struct xhci_port **ports; - unsigned int num_ports; - struct usb_hcd *hcd; - struct xhci_bus_state bus_state; - u8 maj_rev; - u8 min_rev; -}; - -struct xhci_device_context_array; - -struct xhci_scratchpad; - -struct xhci_virt_device; - -struct xhci_root_port_bw_info; - -struct xhci_port_cap; - -struct xhci_hcd { - struct usb_hcd *main_hcd; - struct usb_hcd *shared_hcd; - struct xhci_cap_regs *cap_regs; - struct xhci_op_regs *op_regs; - struct xhci_run_regs *run_regs; - struct xhci_doorbell_array *dba; - struct xhci_intr_reg *ir_set; - __u32 hcs_params1; - __u32 hcs_params2; - __u32 hcs_params3; - __u32 hcc_params; - __u32 hcc_params2; - spinlock_t lock; - u8 sbrn; - u16 hci_version; - u8 max_slots; - u8 max_interrupters; - u8 max_ports; - u8 isoc_threshold; - u32 imod_interval; - int event_ring_max; - int page_size; - int page_shift; - int msix_count; - struct clk *clk; - struct clk *reg_clk; - struct reset_control *reset; - struct xhci_device_context_array *dcbaa; - struct xhci_ring *cmd_ring; - unsigned int cmd_ring_state; - struct list_head cmd_list; - unsigned int cmd_ring_reserved_trbs; - struct delayed_work cmd_timer; - struct completion cmd_ring_stop_completion; - struct xhci_command *current_cmd; - struct xhci_ring *event_ring; - struct xhci_erst erst; - struct xhci_scratchpad *scratchpad; - struct list_head lpm_failed_devs; - struct mutex mutex; - struct xhci_command *lpm_command; - struct xhci_virt_device *devs[256]; - struct xhci_root_port_bw_info *rh_bw; - struct dma_pool___2 *device_pool; - struct dma_pool___2 *segment_pool; - struct dma_pool___2 *small_streams_pool; - struct dma_pool___2 *medium_streams_pool; - unsigned int xhc_state; - u32 command; - struct s3_save s3; - long long unsigned int quirks; - unsigned int num_active_eps; - unsigned int limit_active_eps; - struct xhci_port *hw_ports; - struct xhci_hub usb2_rhub; - struct xhci_hub usb3_rhub; - unsigned int hw_lpm_support: 1; - unsigned int broken_suspend: 1; - u32 *ext_caps; - unsigned int num_ext_caps; - struct xhci_port_cap *port_caps; - unsigned int num_port_caps; - struct timer_list comp_mode_recovery_timer; - u32 port_status_u0; - u16 test_mode; - struct dentry *debugfs_root; - struct dentry *debugfs_slots; - struct list_head regset_list; - void *dbc; - long unsigned int priv[0]; -}; - -struct xhci_segment { - union xhci_trb *trbs; - struct xhci_segment *next; - dma_addr_t dma; - dma_addr_t bounce_dma; - void *bounce_buf; - unsigned int bounce_offs; - unsigned int bounce_len; -}; - -enum xhci_overhead_type { - LS_OVERHEAD_TYPE = 0, - FS_OVERHEAD_TYPE = 1, - HS_OVERHEAD_TYPE = 2, -}; - -struct xhci_interval_bw { - unsigned int num_packets; - struct list_head endpoints; - unsigned int overhead[3]; -}; - -struct xhci_interval_bw_table { - unsigned int interval0_esit_payload; - struct xhci_interval_bw interval_bw[16]; - unsigned int bw_used; - unsigned int ss_bw_in; - unsigned int ss_bw_out; -}; - -struct xhci_tt_bw_info; - -struct xhci_virt_device { - struct usb_device *udev; - struct xhci_container_ctx *out_ctx; - struct xhci_container_ctx *in_ctx; - struct xhci_virt_ep eps[31]; - u8 fake_port; - u8 real_port; - struct xhci_interval_bw_table *bw_table; - struct xhci_tt_bw_info *tt_info; - long unsigned int flags; - u16 current_mel; - void *debugfs_private; -}; - -struct xhci_tt_bw_info { - struct list_head tt_list; - int slot_id; - int ttport; - struct xhci_interval_bw_table bw_table; - int active_eps; -}; - -struct xhci_root_port_bw_info { - struct list_head tts; - unsigned int num_active_tts; - struct xhci_interval_bw_table bw_table; -}; - -struct xhci_device_context_array { - __le64 dev_context_ptrs[256]; - dma_addr_t dma; -}; - -enum xhci_setup_dev { - SETUP_CONTEXT_ONLY = 0, - SETUP_CONTEXT_ADDRESS = 1, -}; - -struct xhci_td { - struct list_head td_list; - struct list_head cancelled_td_list; - struct urb *urb; - struct xhci_segment *start_seg; - union xhci_trb *first_trb; - union xhci_trb *last_trb; - struct xhci_segment *bounce_seg; - bool urb_length_set; -}; - -struct xhci_dequeue_state { - struct xhci_segment *new_deq_seg; - union xhci_trb *new_deq_ptr; - int new_cycle_state; - unsigned int stream_id; -}; - -struct xhci_erst_entry { - __le64 seg_addr; - __le32 seg_size; - __le32 rsvd; -}; - -struct xhci_scratchpad { - u64 *sp_array; - dma_addr_t sp_dma; - void **sp_buffers; -}; - -struct urb_priv { - int num_tds; - int num_tds_done; - struct xhci_td td[0]; -}; - -struct xhci_port_cap { - u32 *psi; - u8 psi_count; - u8 psi_uid_count; - u8 maj_rev; - u8 min_rev; -}; - -struct xhci_port { - __le32 *addr; - int hw_portnum; - int hcd_portnum; - struct xhci_hub *rhub; - struct xhci_port_cap *port_cap; -}; - -struct xhci_driver_overrides { - size_t extra_priv_size; - int (*reset)(struct usb_hcd *); - int (*start)(struct usb_hcd *); - int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); - void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); -}; - -typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); - -enum xhci_ep_reset_type { - EP_HARD_RESET = 0, - EP_SOFT_RESET = 1, -}; - -struct dbc_regs { - __le32 capability; - __le32 doorbell; - __le32 ersts; - __le32 __reserved_0; - __le64 erstba; - __le64 erdp; - __le32 control; - __le32 status; - __le32 portsc; - __le32 __reserved_1; - __le64 dccp; - __le32 devinfo1; - __le32 devinfo2; -}; - -struct dbc_str_descs { - char string0[64]; - char manufacturer[64]; - char product[64]; - char serial[64]; -}; - -enum dbc_state { - DS_DISABLED = 0, - DS_INITIALIZED = 1, - DS_ENABLED = 2, - DS_CONNECTED = 3, - DS_CONFIGURED = 4, - DS_STALLED = 5, -}; - -struct xhci_dbc; - -struct dbc_ep { - struct xhci_dbc *dbc; - struct list_head list_pending; - struct xhci_ring *ring; - unsigned int direction: 1; -}; - -struct dbc_driver; - -struct xhci_dbc { - spinlock_t lock; - struct device *dev; - struct xhci_hcd *xhci; - struct dbc_regs *regs; - struct xhci_ring *ring_evt; - struct xhci_ring *ring_in; - struct xhci_ring *ring_out; - struct xhci_erst erst; - struct xhci_container_ctx *ctx; - struct dbc_str_descs *string; - dma_addr_t string_dma; - size_t string_size; - enum dbc_state state; - struct delayed_work event_work; - unsigned int resume_required: 1; - struct dbc_ep eps[2]; - const struct dbc_driver *driver; - void *priv; -}; - -struct dbc_driver { - int (*configure)(struct xhci_dbc *); - void (*disconnect)(struct xhci_dbc *); -}; - -struct dbc_request { - void *buf; - unsigned int length; - dma_addr_t dma; - void (*complete)(struct xhci_dbc *, struct dbc_request *); - struct list_head list_pool; - int status; - unsigned int actual; - struct xhci_dbc *dbc; - struct list_head list_pending; - dma_addr_t trb_dma; - union xhci_trb *trb; - unsigned int direction: 1; -}; - -struct trace_event_raw_xhci_log_msg { - struct trace_entry ent; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ctx { - struct trace_entry ent; - int ctx_64; - unsigned int ctx_type; - dma_addr_t ctx_dma; - u8 *ctx_va; - unsigned int ctx_ep_num; - int slot_id; - u32 __data_loc_ctx_data; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_trb { - struct trace_entry ent; - u32 type; - u32 field0; - u32 field1; - u32 field2; - u32 field3; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_free_virt_dev { - struct trace_entry ent; - void *vdev; - long long unsigned int out_ctx; - long long unsigned int in_ctx; - u8 fake_port; - u8 real_port; - u16 current_mel; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_virt_dev { - struct trace_entry ent; - void *vdev; - long long unsigned int out_ctx; - long long unsigned int in_ctx; - int devnum; - int state; - int speed; - u8 portnum; - u8 level; - int slot_id; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_urb { - struct trace_entry ent; - void *urb; - unsigned int pipe; - unsigned int stream; - int status; - unsigned int flags; - int num_mapped_sgs; - int num_sgs; - int length; - int actual; - int epnum; - int dir_in; - int type; - int slot_id; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ep_ctx { - struct trace_entry ent; - u32 info; - u32 info2; - u64 deq; - u32 tx_info; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_slot_ctx { - struct trace_entry ent; - u32 info; - u32 info2; - u32 tt_info; - u32 state; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ctrl_ctx { - struct trace_entry ent; - u32 drop; - u32 add; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ring { - struct trace_entry ent; - u32 type; - void *ring; - dma_addr_t enq; - dma_addr_t deq; - dma_addr_t enq_seg; - dma_addr_t deq_seg; - unsigned int num_segs; - unsigned int stream_id; - unsigned int cycle_state; - unsigned int num_trbs_free; - unsigned int bounce_buf_len; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_portsc { - struct trace_entry ent; - u32 portnum; - u32 portsc; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_doorbell { - struct trace_entry ent; - u32 slot; - u32 doorbell; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_dbc_log_request { - struct trace_entry ent; - struct dbc_request *req; - bool dir; - unsigned int actual; - unsigned int length; - int status; - char __data[0]; -}; - -struct trace_event_data_offsets_xhci_log_msg { - u32 msg; -}; - -struct trace_event_data_offsets_xhci_log_ctx { - u32 ctx_data; -}; - -struct trace_event_data_offsets_xhci_log_trb { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_free_virt_dev {}; - -struct trace_event_data_offsets_xhci_log_virt_dev {}; - -struct trace_event_data_offsets_xhci_log_urb {}; - -struct trace_event_data_offsets_xhci_log_ep_ctx { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_slot_ctx { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_ctrl_ctx { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_ring {}; - -struct trace_event_data_offsets_xhci_log_portsc { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_doorbell { - u32 str; -}; - -struct trace_event_data_offsets_xhci_dbc_log_request {}; - -typedef void (*btf_trace_xhci_dbg_address)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_context_change)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_quirks)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_reset_ep)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_cancel_urb)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_init)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_ring_expansion)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_address_ctx)(void *, struct xhci_hcd *, struct xhci_container_ctx *, unsigned int); - -typedef void (*btf_trace_xhci_handle_event)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_handle_command)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_handle_transfer)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_queue_trb)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_dbc_handle_event)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_dbc_handle_transfer)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_dbc_gadget_ep_queue)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_free_virt_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_alloc_virt_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_setup_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_setup_addressable_virt_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_stop_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_urb_enqueue)(void *, struct urb *); - -typedef void (*btf_trace_xhci_urb_giveback)(void *, struct urb *); - -typedef void (*btf_trace_xhci_urb_dequeue)(void *, struct urb *); - -typedef void (*btf_trace_xhci_handle_cmd_stop_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_set_deq_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_reset_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_config_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_add_endpoint)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_alloc_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_free_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_disable_slot)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_discover_or_reset_device)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_setup_device_slot)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_addr_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_reset_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_set_deq)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_configure_endpoint)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_address_ctrl_ctx)(void *, struct xhci_input_control_ctx *); - -typedef void (*btf_trace_xhci_configure_endpoint_ctrl_ctx)(void *, struct xhci_input_control_ctx *); - -typedef void (*btf_trace_xhci_ring_alloc)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_ring_free)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_ring_expansion)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_inc_enq)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_inc_deq)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_handle_port_status)(void *, u32, u32); - -typedef void (*btf_trace_xhci_get_port_status)(void *, u32, u32); - -typedef void (*btf_trace_xhci_hub_status_data)(void *, u32, u32); - -typedef void (*btf_trace_xhci_ring_ep_doorbell)(void *, u32, u32); - -typedef void (*btf_trace_xhci_ring_host_doorbell)(void *, u32, u32); - -typedef void (*btf_trace_xhci_dbc_alloc_request)(void *, struct dbc_request *); - -typedef void (*btf_trace_xhci_dbc_free_request)(void *, struct dbc_request *); - -typedef void (*btf_trace_xhci_dbc_queue_request)(void *, struct dbc_request *); - -typedef void (*btf_trace_xhci_dbc_giveback_request)(void *, struct dbc_request *); - -struct xhci_regset { - char name[32]; - struct debugfs_regset32 regset; - size_t nregs; - struct list_head list; -}; - -struct xhci_file_map { - const char *name; - int (*show)(struct seq_file *, void *); -}; - -struct xhci_ep_priv { - char name[32]; - struct dentry *root; - struct xhci_stream_info *stream_info; - struct xhci_ring *show_ring; - unsigned int stream_id; -}; - -struct xhci_slot_priv { - char name[32]; - struct dentry *root; - struct xhci_ep_priv *eps[31]; - struct xhci_virt_device *dev; -}; - -struct xhci_driver_data { - u64 quirks; - const char *firmware; -}; - -struct xhci_plat_priv { - const char *firmware_name; - long long unsigned int quirks; - int (*plat_setup)(struct usb_hcd *); - void (*plat_start)(struct usb_hcd *); - int (*init_quirk)(struct usb_hcd *); - int (*suspend_quirk)(struct usb_hcd *); - int (*resume_quirk)(struct usb_hcd *); -}; - -struct os_dependent { - void *base; - uint32_t reg_offset; - void *mphi_base; - bool use_swirq; - int irq_num; - int fiq_num; - struct platform_device *platformdev; -}; - -typedef dma_addr_t dwc_dma_t; - -struct dwc_workq; - -typedef struct dwc_workq dwc_workq_t; - -struct dwc_tasklet; - -typedef struct dwc_tasklet dwc_tasklet_t; - -struct dwc_timer; - -typedef struct dwc_timer dwc_timer_t; - -struct dwc_spinlock; - -typedef struct dwc_spinlock dwc_spinlock_t; - -union hwcfg1_data { - uint32_t d32; - struct { - unsigned int ep_dir0: 2; - unsigned int ep_dir1: 2; - unsigned int ep_dir2: 2; - unsigned int ep_dir3: 2; - unsigned int ep_dir4: 2; - unsigned int ep_dir5: 2; - unsigned int ep_dir6: 2; - unsigned int ep_dir7: 2; - unsigned int ep_dir8: 2; - unsigned int ep_dir9: 2; - unsigned int ep_dir10: 2; - unsigned int ep_dir11: 2; - unsigned int ep_dir12: 2; - unsigned int ep_dir13: 2; - unsigned int ep_dir14: 2; - unsigned int ep_dir15: 2; - } b; -}; - -typedef union hwcfg1_data hwcfg1_data_t; - -union hwcfg2_data { - uint32_t d32; - struct { - unsigned int op_mode: 3; - unsigned int architecture: 2; - unsigned int point2point: 1; - unsigned int hs_phy_type: 2; - unsigned int fs_phy_type: 2; - unsigned int num_dev_ep: 4; - unsigned int num_host_chan: 4; - unsigned int perio_ep_supported: 1; - unsigned int dynamic_fifo: 1; - unsigned int multi_proc_int: 1; - unsigned int reserved21: 1; - unsigned int nonperio_tx_q_depth: 2; - unsigned int host_perio_tx_q_depth: 2; - unsigned int dev_token_q_depth: 5; - unsigned int otg_enable_ic_usb: 1; - } b; -}; - -typedef union hwcfg2_data hwcfg2_data_t; - -union hwcfg3_data { - uint32_t d32; - struct { - unsigned int xfer_size_cntr_width: 4; - unsigned int packet_size_cntr_width: 3; - unsigned int otg_func: 1; - unsigned int i2c: 1; - unsigned int vendor_ctrl_if: 1; - unsigned int optional_features: 1; - unsigned int synch_reset_type: 1; - unsigned int adp_supp: 1; - unsigned int otg_enable_hsic: 1; - unsigned int bc_support: 1; - unsigned int otg_lpm_en: 1; - unsigned int dfifo_depth: 16; - } b; -}; - -typedef union hwcfg3_data hwcfg3_data_t; - -union hwcfg4_data { - uint32_t d32; - struct { - unsigned int num_dev_perio_in_ep: 4; - unsigned int power_optimiz: 1; - unsigned int min_ahb_freq: 1; - unsigned int hiber: 1; - unsigned int xhiber: 1; - unsigned int reserved: 6; - unsigned int utmi_phy_data_width: 2; - unsigned int num_dev_mode_ctrl_ep: 4; - unsigned int iddig_filt_en: 1; - unsigned int vbus_valid_filt_en: 1; - unsigned int a_valid_filt_en: 1; - unsigned int b_valid_filt_en: 1; - unsigned int session_end_filt_en: 1; - unsigned int ded_fifo_en: 1; - unsigned int num_in_eps: 4; - unsigned int desc_dma: 1; - unsigned int desc_dma_dyn: 1; - } b; -}; - -typedef union hwcfg4_data hwcfg4_data_t; - -union fifosize_data { - uint32_t d32; - struct { - unsigned int startaddr: 16; - unsigned int depth: 16; - } b; -}; - -typedef union fifosize_data fifosize_data_t; - -union hcfg_data { - uint32_t d32; - struct { - unsigned int fslspclksel: 2; - unsigned int fslssupp: 1; - unsigned int reserved3_6: 4; - unsigned int ena32khzs: 1; - unsigned int resvalid: 8; - unsigned int reserved16_22: 7; - unsigned int descdma: 1; - unsigned int frlisten: 2; - unsigned int perschedena: 1; - unsigned int reserved27_30: 4; - unsigned int modechtimen: 1; - } b; -}; - -typedef union hcfg_data hcfg_data_t; - -union dcfg_data { - uint32_t d32; - struct { - unsigned int devspd: 2; - unsigned int nzstsouthshk: 1; - unsigned int ena32khzs: 1; - unsigned int devaddr: 7; - unsigned int perfrint: 2; - unsigned int endevoutnak: 1; - unsigned int reserved14_17: 4; - unsigned int epmscnt: 5; - unsigned int descdma: 1; - unsigned int perschintvl: 2; - unsigned int resvalid: 6; - } b; -}; - -typedef union dcfg_data dcfg_data_t; - -struct dwc_otg_core_if; - -struct dwc_ep; - -typedef struct dwc_ep dwc_ep_t; - -struct ep_xfer_info { - struct dwc_otg_core_if *core_if; - dwc_ep_t *ep; - uint8_t state; -}; - -typedef struct ep_xfer_info ep_xfer_info_t; - -enum dwc_otg_lx_state { - DWC_OTG_L0 = 0, - DWC_OTG_L1 = 1, - DWC_OTG_L2 = 2, - DWC_OTG_L3 = 3, -}; - -typedef enum dwc_otg_lx_state dwc_otg_lx_state_e; - -struct dwc_otg_adp { - uint32_t adp_started; - uint32_t initial_probe; - int32_t probe_timer_values[2]; - uint32_t probe_enabled; - uint32_t sense_enabled; - dwc_timer_t *sense_timer; - uint32_t sense_timer_started; - dwc_timer_t *vbuson_timer; - uint32_t vbuson_timer_started; - uint32_t attached; - uint32_t probe_counter; - uint32_t gpwrdn; -}; - -typedef struct dwc_otg_adp dwc_otg_adp_t; - -struct dwc_otg_core_params; - -typedef struct dwc_otg_core_params dwc_otg_core_params_t; - -struct dwc_otg_core_global_regs; - -typedef struct dwc_otg_core_global_regs dwc_otg_core_global_regs_t; - -struct dwc_otg_dev_if; - -typedef struct dwc_otg_dev_if dwc_otg_dev_if_t; - -struct dwc_otg_host_if; - -typedef struct dwc_otg_host_if dwc_otg_host_if_t; - -struct dwc_otg_cil_callbacks; - -struct dwc_otg_global_regs_backup; - -struct dwc_otg_host_regs_backup; - -struct dwc_otg_dev_regs_backup; - -struct dwc_otg_core_if { - dwc_otg_core_params_t *core_params; - dwc_otg_core_global_regs_t *core_global_regs; - dwc_otg_dev_if_t *dev_if; - dwc_otg_host_if_t *host_if; - uint32_t snpsid; - uint8_t phy_init_done; - uint8_t srp_success; - uint8_t srp_timer_started; - dwc_timer_t *srp_timer; - volatile uint32_t *pcgcctl; - uint32_t *data_fifo[16]; - uint16_t total_fifo_size; - uint16_t rx_fifo_size; - uint16_t nperio_tx_fifo_size; - uint8_t dma_enable; - uint8_t dma_desc_enable; - uint8_t pti_enh_enable; - uint8_t multiproc_int_enable; - uint8_t en_multiple_tx_fifo; - uint8_t queuing_high_bandwidth; - hwcfg1_data_t hwcfg1; - hwcfg2_data_t hwcfg2; - hwcfg3_data_t hwcfg3; - hwcfg4_data_t hwcfg4; - fifosize_data_t hptxfsiz; - hcfg_data_t hcfg; - dcfg_data_t dcfg; - uint8_t op_state; - uint8_t restart_hcd_on_session_req; - struct dwc_otg_cil_callbacks *hcd_cb; - struct dwc_otg_cil_callbacks *pcd_cb; - uint32_t p_tx_msk; - uint32_t tx_msk; - dwc_workq_t *wq_otg; - dwc_timer_t *wkp_timer; - uint32_t start_doeptsiz_val[16]; - ep_xfer_info_t ep_xfer_info[16]; - dwc_timer_t *ep_xfer_timer[16]; - dwc_otg_lx_state_e lx_state; - struct dwc_otg_global_regs_backup *gr_backup; - struct dwc_otg_host_regs_backup *hr_backup; - struct dwc_otg_dev_regs_backup *dr_backup; - uint32_t power_down; - uint32_t adp_enable; - dwc_otg_adp_t adp; - int hibernation_suspend; - int xhib; - uint32_t otg_ver; - uint8_t otg_sts; - dwc_spinlock_t *lock; - uint8_t start_predict; - uint8_t nextep_seq[16]; - uint8_t first_in_nextep_seq; - uint32_t frame_num; -}; - -typedef struct dwc_otg_core_if dwc_otg_core_if_t; - -struct dwc_otg_pcd; - -struct dwc_otg_hcd; - -struct dwc_otg_device { - struct os_dependent os_dep; - dwc_otg_core_if_t *core_if; - struct dwc_otg_pcd *pcd; - struct dwc_otg_hcd *hcd; - uint8_t common_irq_installed; -}; - -union dwc_otg_hcd_internal_flags { - uint32_t d32; - struct { - unsigned int port_connect_status_change: 1; - unsigned int port_connect_status: 1; - unsigned int port_reset_change: 1; - unsigned int port_enable_change: 1; - unsigned int port_suspend_change: 1; - unsigned int port_over_current_change: 1; - unsigned int port_l1_change: 1; - unsigned int port_speed: 2; - int: 23; - unsigned int reserved: 24; - } b; -}; - -struct dwc_list_link { - struct dwc_list_link *next; - struct dwc_list_link *prev; -}; - -typedef struct dwc_list_link dwc_list_link_t; - -struct dwc_hc; - -struct hc_list { - struct dwc_hc *cqh_first; - struct dwc_hc *cqh_last; -}; - -struct urb_tq_entry; - -struct urb_list { - struct urb_tq_entry *tqh_first; - struct urb_tq_entry **tqh_last; -}; - -struct dwc_otg_hcd_function_ops; - -struct fiq_stack; - -struct fiq_state; - -struct fiq_dma_blob; - -struct dwc_otg_hcd { - struct dwc_otg_device *otg_dev; - dwc_otg_core_if_t *core_if; - struct dwc_otg_hcd_function_ops *fops; - volatile union dwc_otg_hcd_internal_flags flags; - dwc_list_link_t non_periodic_sched_inactive; - dwc_list_link_t non_periodic_sched_active; - dwc_list_link_t *non_periodic_qh_ptr; - dwc_list_link_t periodic_sched_inactive; - dwc_list_link_t periodic_sched_ready; - dwc_list_link_t periodic_sched_assigned; - dwc_list_link_t periodic_sched_queued; - uint16_t periodic_usecs; - uint16_t frame_usecs[8]; - uint16_t frame_number; - uint16_t periodic_qh_count; - struct hc_list free_hc_list; - int periodic_channels; - int non_periodic_channels; - int available_host_channels; - struct dwc_hc *hc_ptr_array[16]; - uint8_t *status_buf; - dma_addr_t status_buf_dma; - dwc_timer_t *conn_timer; - dwc_tasklet_t *reset_tasklet; - dwc_tasklet_t *completion_tasklet; - struct urb_list completed_urb_list; - dwc_spinlock_t *lock; - void *priv; - uint8_t otg_port; - uint32_t *frame_list; - int hub_port[128]; - dma_addr_t frame_list_dma; - struct fiq_stack *fiq_stack; - struct fiq_state *fiq_state; - struct fiq_dma_blob *fiq_dmab; -}; - -typedef struct dwc_otg_device dwc_otg_device_t; - -typedef struct dwc_otg_hcd dwc_otg_hcd_t; - -struct dwc_otg_hcd_pipe_info { - uint8_t dev_addr; - uint8_t ep_num; - uint8_t pipe_type; - uint8_t pipe_dir; - uint16_t mps; -}; - -struct dwc_otg_hcd_iso_packet_desc { - uint32_t offset; - uint32_t length; - uint32_t actual_length; - uint32_t status; -}; - -struct dwc_otg_qtd; - -struct dwc_otg_hcd_urb { - void *priv; - struct dwc_otg_qtd *qtd; - void *buf; - dwc_dma_t dma; - void *setup_packet; - dwc_dma_t setup_dma; - uint32_t length; - uint32_t actual_length; - uint32_t status; - uint32_t error_count; - uint32_t packet_count; - uint32_t flags; - uint16_t interval; - struct dwc_otg_hcd_pipe_info pipe_info; - struct dwc_otg_hcd_iso_packet_desc iso_descs[0]; -}; - -typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t; - -typedef int (*dwc_otg_hcd_start_cb_t)(dwc_otg_hcd_t *); - -typedef int (*dwc_otg_hcd_disconnect_cb_t)(dwc_otg_hcd_t *); - -typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t)(dwc_otg_hcd_t *, void *, uint32_t *, uint32_t *); - -typedef int (*dwc_otg_hcd_speed_from_urb_cb_t)(dwc_otg_hcd_t *, void *); - -typedef int (*dwc_otg_hcd_complete_urb_cb_t)(dwc_otg_hcd_t *, void *, dwc_otg_hcd_urb_t *, int32_t); - -typedef int (*dwc_otg_hcd_get_b_hnp_enable)(dwc_otg_hcd_t *); - -struct dwc_otg_hcd_function_ops { - dwc_otg_hcd_start_cb_t start; - dwc_otg_hcd_disconnect_cb_t disconnect; - dwc_otg_hcd_hub_info_from_urb_cb_t hub_info; - dwc_otg_hcd_speed_from_urb_cb_t speed; - dwc_otg_hcd_complete_urb_cb_t complete; - dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable; -}; - -struct dwc_otg_core_global_regs { - volatile uint32_t gotgctl; - volatile uint32_t gotgint; - volatile uint32_t gahbcfg; - volatile uint32_t gusbcfg; - volatile uint32_t grstctl; - volatile uint32_t gintsts; - volatile uint32_t gintmsk; - volatile uint32_t grxstsr; - volatile uint32_t grxstsp; - volatile uint32_t grxfsiz; - volatile uint32_t gnptxfsiz; - volatile uint32_t gnptxsts; - volatile uint32_t gi2cctl; - volatile uint32_t gpvndctl; - volatile uint32_t ggpio; - volatile uint32_t guid; - volatile uint32_t gsnpsid; - volatile uint32_t ghwcfg1; - volatile uint32_t ghwcfg2; - volatile uint32_t ghwcfg3; - volatile uint32_t ghwcfg4; - volatile uint32_t glpmcfg; - volatile uint32_t gpwrdn; - volatile uint32_t gdfifocfg; - volatile uint32_t adpctl; - volatile uint32_t reserved39[39]; - volatile uint32_t hptxfsiz; - volatile uint32_t dtxfsiz[15]; -}; - -union gintmsk_data { - uint32_t d32; - struct { - unsigned int reserved0: 1; - unsigned int modemismatch: 1; - unsigned int otgintr: 1; - unsigned int sofintr: 1; - unsigned int rxstsqlvl: 1; - unsigned int nptxfempty: 1; - unsigned int ginnakeff: 1; - unsigned int goutnakeff: 1; - unsigned int ulpickint: 1; - unsigned int i2cintr: 1; - unsigned int erlysuspend: 1; - unsigned int usbsuspend: 1; - unsigned int usbreset: 1; - unsigned int enumdone: 1; - unsigned int isooutdrop: 1; - unsigned int eopframe: 1; - unsigned int restoredone: 1; - unsigned int epmismatch: 1; - unsigned int inepintr: 1; - unsigned int outepintr: 1; - unsigned int incomplisoin: 1; - unsigned int incomplisoout: 1; - unsigned int fetsusp: 1; - unsigned int resetdet: 1; - unsigned int portintr: 1; - unsigned int hcintr: 1; - unsigned int ptxfempty: 1; - unsigned int lpmtranrcvd: 1; - unsigned int conidstschng: 1; - unsigned int disconnect: 1; - unsigned int sessreqintr: 1; - unsigned int wkupintr: 1; - } b; -}; - -typedef union gintmsk_data gintmsk_data_t; - -struct dwc_otg_dev_global_regs { - volatile uint32_t dcfg; - volatile uint32_t dctl; - volatile uint32_t dsts; - uint32_t unused; - volatile uint32_t diepmsk; - volatile uint32_t doepmsk; - volatile uint32_t daint; - volatile uint32_t daintmsk; - volatile uint32_t dtknqr1; - volatile uint32_t dtknqr2; - volatile uint32_t dvbusdis; - volatile uint32_t dvbuspulse; - volatile uint32_t dtknqr3_dthrctl; - volatile uint32_t dtknqr4_fifoemptymsk; - volatile uint32_t deachint; - volatile uint32_t deachintmsk; - volatile uint32_t diepeachintmsk[16]; - volatile uint32_t doepeachintmsk[16]; -}; - -typedef struct dwc_otg_dev_global_regs dwc_otg_device_global_regs_t; - -struct dwc_otg_dev_in_ep_regs { - volatile uint32_t diepctl; - uint32_t reserved04; - volatile uint32_t diepint; - uint32_t reserved0C; - volatile uint32_t dieptsiz; - volatile uint32_t diepdma; - volatile uint32_t dtxfsts; - volatile uint32_t diepdmab; -}; - -typedef struct dwc_otg_dev_in_ep_regs dwc_otg_dev_in_ep_regs_t; - -struct dwc_otg_dev_out_ep_regs { - volatile uint32_t doepctl; - uint32_t reserved04; - volatile uint32_t doepint; - uint32_t reserved0C; - volatile uint32_t doeptsiz; - volatile uint32_t doepdma; - uint32_t unused; - uint32_t doepdmab; -}; - -typedef struct dwc_otg_dev_out_ep_regs dwc_otg_dev_out_ep_regs_t; - -union dev_dma_desc_sts { - uint32_t d32; - struct { - unsigned int bytes: 16; - unsigned int nak: 1; - unsigned int reserved17_22: 6; - unsigned int mtrf: 1; - unsigned int sr: 1; - unsigned int ioc: 1; - unsigned int sp: 1; - unsigned int l: 1; - unsigned int sts: 2; - unsigned int bs: 2; - } b; - struct { - unsigned int rxbytes: 11; - unsigned int reserved11: 1; - unsigned int framenum: 11; - unsigned int pid: 2; - unsigned int ioc: 1; - unsigned int sp: 1; - unsigned int l: 1; - unsigned int rxsts: 2; - unsigned int bs: 2; - } b_iso_out; - struct { - unsigned int txbytes: 12; - unsigned int framenum: 11; - unsigned int pid: 2; - unsigned int ioc: 1; - unsigned int sp: 1; - unsigned int l: 1; - unsigned int txsts: 2; - unsigned int bs: 2; - } b_iso_in; -}; - -typedef union dev_dma_desc_sts dev_dma_desc_sts_t; - -struct dwc_otg_dev_dma_desc { - dev_dma_desc_sts_t status; - uint32_t buf; -}; - -typedef struct dwc_otg_dev_dma_desc dwc_otg_dev_dma_desc_t; - -struct dwc_otg_dev_if { - dwc_otg_device_global_regs_t *dev_global_regs; - dwc_otg_dev_in_ep_regs_t *in_ep_regs[16]; - dwc_otg_dev_out_ep_regs_t *out_ep_regs[16]; - uint8_t speed; - uint8_t num_in_eps; - uint8_t num_out_eps; - uint16_t perio_tx_fifo_size[15]; - uint16_t tx_fifo_size[15]; - uint16_t rx_thr_en; - uint16_t iso_tx_thr_en; - uint16_t non_iso_tx_thr_en; - uint16_t rx_thr_length; - uint16_t tx_thr_length; - dwc_dma_t dma_setup_desc_addr[2]; - dwc_otg_dev_dma_desc_t *setup_desc_addr[2]; - dwc_otg_dev_dma_desc_t *psetup; - uint32_t setup_desc_index; - dwc_dma_t dma_in_desc_addr; - dwc_otg_dev_dma_desc_t *in_desc_addr; - dwc_dma_t dma_out_desc_addr; - dwc_otg_dev_dma_desc_t *out_desc_addr; - uint32_t spd; - void *isoc_ep; -}; - -struct dwc_otg_host_global_regs { - volatile uint32_t hcfg; - volatile uint32_t hfir; - volatile uint32_t hfnum; - uint32_t reserved40C; - volatile uint32_t hptxsts; - volatile uint32_t haint; - volatile uint32_t haintmsk; - volatile uint32_t hflbaddr; -}; - -typedef struct dwc_otg_host_global_regs dwc_otg_host_global_regs_t; - -union haintmsk_data { - uint32_t d32; - struct { - unsigned int ch0: 1; - unsigned int ch1: 1; - unsigned int ch2: 1; - unsigned int ch3: 1; - unsigned int ch4: 1; - unsigned int ch5: 1; - unsigned int ch6: 1; - unsigned int ch7: 1; - unsigned int ch8: 1; - unsigned int ch9: 1; - unsigned int ch10: 1; - unsigned int ch11: 1; - unsigned int ch12: 1; - unsigned int ch13: 1; - unsigned int ch14: 1; - unsigned int ch15: 1; - unsigned int reserved: 16; - } b; - struct { - unsigned int chint: 16; - unsigned int reserved: 16; - } b2; -}; - -typedef union haintmsk_data haintmsk_data_t; - -struct dwc_otg_hc_regs { - volatile uint32_t hcchar; - volatile uint32_t hcsplt; - volatile uint32_t hcint; - volatile uint32_t hcintmsk; - volatile uint32_t hctsiz; - volatile uint32_t hcdma; - volatile uint32_t reserved; - volatile uint32_t hcdmab; -}; - -typedef struct dwc_otg_hc_regs dwc_otg_hc_regs_t; - -union hcchar_data { - uint32_t d32; - struct { - unsigned int mps: 11; - unsigned int epnum: 4; - unsigned int epdir: 1; - unsigned int reserved: 1; - unsigned int lspddev: 1; - unsigned int eptype: 2; - unsigned int multicnt: 2; - unsigned int devaddr: 7; - unsigned int oddfrm: 1; - unsigned int chdis: 1; - unsigned int chen: 1; - } b; -}; - -typedef union hcchar_data hcchar_data_t; - -union hcsplt_data { - uint32_t d32; - struct { - unsigned int prtaddr: 7; - unsigned int hubaddr: 7; - unsigned int xactpos: 2; - unsigned int compsplt: 1; - unsigned int reserved: 14; - unsigned int spltena: 1; - } b; -}; - -typedef union hcsplt_data hcsplt_data_t; - -union hcint_data { - uint32_t d32; - struct { - unsigned int xfercomp: 1; - unsigned int chhltd: 1; - unsigned int ahberr: 1; - unsigned int stall: 1; - unsigned int nak: 1; - unsigned int ack: 1; - unsigned int nyet: 1; - unsigned int xacterr: 1; - unsigned int bblerr: 1; - unsigned int frmovrun: 1; - unsigned int datatglerr: 1; - unsigned int bna: 1; - unsigned int xcs_xact: 1; - unsigned int frm_list_roll: 1; - unsigned int reserved14_31: 18; - } b; -}; - -typedef union hcint_data hcint_data_t; - -union hcintmsk_data { - uint32_t d32; - struct { - unsigned int xfercompl: 1; - unsigned int chhltd: 1; - unsigned int ahberr: 1; - unsigned int stall: 1; - unsigned int nak: 1; - unsigned int ack: 1; - unsigned int nyet: 1; - unsigned int xacterr: 1; - unsigned int bblerr: 1; - unsigned int frmovrun: 1; - unsigned int datatglerr: 1; - unsigned int bna: 1; - unsigned int xcs_xact: 1; - unsigned int frm_list_roll: 1; - unsigned int reserved14_31: 18; - } b; -}; - -typedef union hcintmsk_data hcintmsk_data_t; - -union hctsiz_data { - uint32_t d32; - struct { - unsigned int xfersize: 19; - unsigned int pktcnt: 10; - unsigned int pid: 2; - unsigned int dopng: 1; - } b; - struct { - unsigned int schinfo: 8; - unsigned int ntd: 8; - unsigned int reserved16_28: 13; - unsigned int pid: 2; - unsigned int dopng: 1; - } b_ddma; -}; - -typedef union hctsiz_data hctsiz_data_t; - -union hcdma_data { - uint32_t d32; - struct { - unsigned int reserved0_2: 3; - unsigned int ctd: 8; - unsigned int dma_addr: 21; - } b; -}; - -typedef union hcdma_data hcdma_data_t; - -union host_dma_desc_sts { - uint32_t d32; - struct { - unsigned int n_bytes: 17; - unsigned int qtd_offset: 6; - unsigned int a_qtd: 1; - unsigned int sup: 1; - unsigned int ioc: 1; - unsigned int eol: 1; - unsigned int reserved27: 1; - unsigned int sts: 2; - unsigned int reserved30: 1; - unsigned int a: 1; - } b; - struct { - unsigned int n_bytes: 12; - unsigned int reserved12_24: 13; - unsigned int ioc: 1; - unsigned int reserved26_27: 2; - unsigned int sts: 2; - unsigned int reserved30: 1; - unsigned int a: 1; - } b_isoc; -}; - -typedef union host_dma_desc_sts host_dma_desc_sts_t; - -struct dwc_otg_host_dma_desc { - host_dma_desc_sts_t status; - uint32_t buf; -}; - -typedef struct dwc_otg_host_dma_desc dwc_otg_host_dma_desc_t; - -struct dwc_otg_host_if { - dwc_otg_host_global_regs_t *host_global_regs; - volatile uint32_t *hprt0; - dwc_otg_hc_regs_t *hc_regs[16]; - uint8_t num_host_channels; - uint8_t perio_eps_supported; - uint16_t perio_tx_fifo_size; -}; - -struct dwc_ep { - uint8_t num; - unsigned int is_in: 1; - unsigned int active: 1; - unsigned int tx_fifo_num: 4; - unsigned int type: 2; - unsigned int data_pid_start: 1; - unsigned int even_odd_frame: 1; - unsigned int maxpacket: 11; - uint32_t maxxfer; - dwc_dma_t dma_addr; - dwc_dma_t dma_desc_addr; - dwc_otg_dev_dma_desc_t *desc_addr; - uint8_t *start_xfer_buff; - uint8_t *xfer_buff; - unsigned int xfer_len: 19; - short: 13; - unsigned int xfer_count: 19; - unsigned int sent_zlp: 1; - short: 12; - unsigned int total_len: 19; - unsigned int stall_clear_flag: 1; - unsigned int stp_rollover; - uint32_t desc_cnt; - uint32_t bInterval; - uint32_t frame_num; - uint8_t frm_overrun; -}; - -enum dwc_otg_halt_status { - DWC_OTG_HC_XFER_NO_HALT_STATUS = 0, - DWC_OTG_HC_XFER_COMPLETE = 1, - DWC_OTG_HC_XFER_URB_COMPLETE = 2, - DWC_OTG_HC_XFER_ACK = 3, - DWC_OTG_HC_XFER_NAK = 4, - DWC_OTG_HC_XFER_NYET = 5, - DWC_OTG_HC_XFER_STALL = 6, - DWC_OTG_HC_XFER_XACT_ERR = 7, - DWC_OTG_HC_XFER_FRAME_OVERRUN = 8, - DWC_OTG_HC_XFER_BABBLE_ERR = 9, - DWC_OTG_HC_XFER_DATA_TOGGLE_ERR = 10, - DWC_OTG_HC_XFER_AHB_ERR = 11, - DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE = 12, - DWC_OTG_HC_XFER_URB_DEQUEUE = 13, -}; - -typedef enum dwc_otg_halt_status dwc_otg_halt_status_e; - -struct dwc_otg_qh; - -struct dwc_hc { - uint8_t hc_num; - unsigned int dev_addr: 7; - unsigned int ep_num: 4; - unsigned int ep_is_in: 1; - unsigned int speed: 2; - unsigned int ep_type: 2; - char: 8; - unsigned int max_packet: 11; - unsigned int data_pid_start: 2; - unsigned int multi_count: 2; - uint8_t *xfer_buff; - dwc_dma_t align_buff; - uint32_t xfer_len; - uint32_t xfer_count; - uint16_t start_pkt_count; - uint8_t xfer_started; - uint8_t do_ping; - uint8_t error_state; - uint8_t halt_on_queue; - uint8_t halt_pending; - dwc_otg_halt_status_e halt_status; - uint8_t do_split; - uint8_t complete_split; - uint8_t hub_addr; - uint8_t port_addr; - uint8_t xact_pos; - uint8_t short_read; - uint8_t requests; - struct dwc_otg_qh *qh; - struct { - struct dwc_hc *cqe_next; - struct dwc_hc *cqe_prev; - } hc_list_entry; - uint16_t ntd; - dwc_dma_t desc_list_addr; - uint8_t schinfo; -}; - -struct dwc_otg_qtd_list { - struct dwc_otg_qtd *cqh_first; - struct dwc_otg_qtd *cqh_last; -}; - -struct dwc_otg_qh { - uint8_t ep_type; - uint8_t ep_is_in; - uint16_t maxp; - uint8_t dev_speed; - uint8_t data_toggle; - uint8_t ping_state; - struct dwc_otg_qtd_list qtd_list; - struct dwc_hc *channel; - uint8_t do_split; - uint16_t usecs; - uint16_t interval; - uint16_t sched_frame; - uint16_t nak_frame; - uint16_t start_split_frame; - uint8_t *dw_align_buf; - dwc_dma_t dw_align_buf_dma; - dwc_list_link_t qh_list_entry; - dwc_otg_host_dma_desc_t *desc_list; - dwc_dma_t desc_list_dma; - uint32_t *n_bytes; - uint16_t ntd; - uint8_t td_first; - uint8_t td_last; - uint16_t speed; - uint16_t frame_usecs[8]; - uint32_t skip_count; -}; - -struct dwc_otg_core_params { - int32_t opt; - int32_t otg_cap; - int32_t dma_enable; - int32_t dma_desc_enable; - int32_t dma_burst_size; - int32_t speed; - int32_t host_support_fs_ls_low_power; - int32_t host_ls_low_power_phy_clk; - int32_t enable_dynamic_fifo; - int32_t data_fifo_size; - int32_t dev_rx_fifo_size; - int32_t dev_nperio_tx_fifo_size; - uint32_t dev_perio_tx_fifo_size[15]; - int32_t host_rx_fifo_size; - int32_t host_nperio_tx_fifo_size; - int32_t host_perio_tx_fifo_size; - int32_t max_transfer_size; - int32_t max_packet_count; - int32_t host_channels; - int32_t dev_endpoints; - int32_t phy_type; - int32_t phy_utmi_width; - int32_t phy_ulpi_ddr; - int32_t phy_ulpi_ext_vbus; - int32_t i2c_enable; - int32_t ulpi_fs_ls; - int32_t ts_dline; - int32_t en_multiple_tx_fifo; - uint32_t dev_tx_fifo_size[15]; - uint32_t thr_ctl; - uint32_t tx_thr_length; - uint32_t rx_thr_length; - int32_t lpm_enable; - int32_t pti_enable; - int32_t mpi_enable; - int32_t ic_usb_cap; - int32_t ahb_thr_ratio; - int32_t adp_supp_enable; - int32_t reload_ctl; - int32_t dev_out_nak; - int32_t cont_on_bna; - int32_t ahb_single; - int32_t power_down; - int32_t otg_ver; -}; - -struct dwc_otg_global_regs_backup { - uint32_t gotgctl_local; - uint32_t gintmsk_local; - uint32_t gahbcfg_local; - uint32_t gusbcfg_local; - uint32_t grxfsiz_local; - uint32_t gnptxfsiz_local; - uint32_t gi2cctl_local; - uint32_t hptxfsiz_local; - uint32_t pcgcctl_local; - uint32_t gdfifocfg_local; - uint32_t dtxfsiz_local[16]; - uint32_t gpwrdn_local; - uint32_t xhib_pcgcctl; - uint32_t xhib_gpwrdn; -}; - -struct dwc_otg_host_regs_backup { - uint32_t hcfg_local; - uint32_t haintmsk_local; - uint32_t hcintmsk_local[16]; - uint32_t hprt0_local; - uint32_t hfir_local; -}; - -struct dwc_otg_dev_regs_backup { - uint32_t dcfg; - uint32_t dctl; - uint32_t daintmsk; - uint32_t diepmsk; - uint32_t doepmsk; - uint32_t diepctl[16]; - uint32_t dieptsiz[16]; - uint32_t diepdma[16]; -}; - -struct dwc_otg_cil_callbacks { - int (*start)(void *); - int (*stop)(void *); - int (*disconnect)(void *); - int (*resume_wakeup)(void *); - int (*suspend)(void *); - int (*session_start)(void *); - void *p; -}; - -enum dwc_otg_control_phase { - DWC_OTG_CONTROL_SETUP = 0, - DWC_OTG_CONTROL_DATA = 1, - DWC_OTG_CONTROL_STATUS = 2, -}; - -typedef enum dwc_otg_control_phase dwc_otg_control_phase_e; - -struct dwc_otg_qtd { - uint8_t data_toggle; - dwc_otg_control_phase_e control_phase; - uint8_t complete_split; - uint32_t ssplit_out_xfer_count; - uint8_t error_count; - uint16_t isoc_frame_index; - uint8_t isoc_split_pos; - uint16_t isoc_split_offset; - struct dwc_otg_hcd_urb *urb; - struct dwc_otg_qh *qh; - struct { - struct dwc_otg_qtd *cqe_next; - struct dwc_otg_qtd *cqe_prev; - } qtd_list_entry; - uint8_t in_process; - uint8_t n_desc; - uint16_t isoc_frame_index_last; -}; - -struct urb_tq_entry { - struct urb *urb; - struct { - struct urb_tq_entry *tqe_next; - struct urb_tq_entry **tqe_prev; - } urb_tq_entries; -}; - -struct fiq_stack { - int magic1; - uint8_t stack[2048]; - int magic2; -}; - -typedef spinlock_t fiq_lock_t; - -typedef struct { - volatile void *base; - volatile void *ctrl; - volatile void *outdda; - volatile void *outddb; - volatile void *intstat; - volatile void *swirq_set; - volatile void *swirq_clr; -} mphi_regs_t; - -enum fiq_fsm_state { - FIQ_PASSTHROUGH = 0, - FIQ_PASSTHROUGH_ERRORSTATE = 31, - FIQ_NP_SSPLIT_STARTED = 1, - FIQ_NP_SSPLIT_RETRY = 2, - FIQ_NP_SSPLIT_PENDING = 33, - FIQ_NP_OUT_CSPLIT_RETRY = 3, - FIQ_NP_IN_CSPLIT_RETRY = 4, - FIQ_NP_SPLIT_DONE = 5, - FIQ_NP_SPLIT_LS_ABORTED = 6, - FIQ_NP_SPLIT_HS_ABORTED = 7, - FIQ_PER_SSPLIT_QUEUED = 8, - FIQ_PER_SSPLIT_STARTED = 9, - FIQ_PER_SSPLIT_LAST = 10, - FIQ_PER_ISO_OUT_PENDING = 11, - FIQ_PER_ISO_OUT_ACTIVE = 12, - FIQ_PER_ISO_OUT_LAST = 13, - FIQ_PER_ISO_OUT_DONE = 27, - FIQ_PER_CSPLIT_WAIT = 14, - FIQ_PER_CSPLIT_NYET1 = 15, - FIQ_PER_CSPLIT_BROKEN_NYET1 = 28, - FIQ_PER_CSPLIT_NYET_FAFF = 29, - FIQ_PER_CSPLIT_POLL = 16, - FIQ_PER_CSPLIT_LAST = 17, - FIQ_PER_SPLIT_DONE = 18, - FIQ_PER_SPLIT_LS_ABORTED = 19, - FIQ_PER_SPLIT_HS_ABORTED = 20, - FIQ_PER_SPLIT_NYET_ABORTED = 21, - FIQ_PER_SPLIT_TIMEOUT = 22, - FIQ_HS_ISOC_TURBO = 23, - FIQ_HS_ISOC_SLEEPING = 24, - FIQ_HS_ISOC_DONE = 25, - FIQ_HS_ISOC_ABORTED = 26, - FIQ_DEQUEUE_ISSUED = 30, - FIQ_TEST = 32, -}; - -struct fiq_dma_info { - u8 index; - u8 slot_len[6]; -}; - -struct fiq_hs_isoc_info { - struct dwc_otg_hcd_iso_packet_desc *iso_desc; - unsigned int nrframes; - unsigned int index; - unsigned int stride; -}; - -struct fiq_channel_state { - enum fiq_fsm_state fsm; - unsigned int nr_errors; - unsigned int hub_addr; - unsigned int port_addr; - unsigned int expected_uframe; - unsigned int uframe_sleeps; - unsigned int nrpackets; - struct fiq_dma_info dma_info; - struct fiq_hs_isoc_info hs_isoc_info; - hcchar_data_t hcchar_copy; - hcsplt_data_t hcsplt_copy; - hcint_data_t hcint_copy; - hcintmsk_data_t hcintmsk_copy; - hctsiz_data_t hctsiz_copy; - hcdma_data_t hcdma_copy; -}; - -struct fiq_state { - fiq_lock_t lock; - mphi_regs_t mphi_regs; - void *dwc_regs_base; - dma_addr_t dma_base; - struct fiq_dma_blob *fiq_dmab; - void *dummy_send; - dma_addr_t dummy_send_dma; - gintmsk_data_t gintmsk_saved; - haintmsk_data_t haintmsk_saved; - int mphi_int_count; - unsigned int fiq_done; - unsigned int kick_np_queues; - unsigned int next_sched_frame; - struct fiq_channel_state channel[0]; -}; - -struct fiq_split_dma_slot { - u8 buf[188]; -}; - -struct fiq_dma_channel { - struct fiq_split_dma_slot index[6]; -}; - -struct fiq_dma_blob { - struct fiq_dma_channel channel[0]; -}; - -struct dwc_otg_driver_module_params { - int32_t opt; - int32_t otg_cap; - int32_t dma_enable; - int32_t dma_desc_enable; - int32_t dma_burst_size; - int32_t speed; - int32_t host_support_fs_ls_low_power; - int32_t host_ls_low_power_phy_clk; - int32_t enable_dynamic_fifo; - int32_t data_fifo_size; - int32_t dev_rx_fifo_size; - int32_t dev_nperio_tx_fifo_size; - uint32_t dev_perio_tx_fifo_size[15]; - int32_t host_rx_fifo_size; - int32_t host_nperio_tx_fifo_size; - int32_t host_perio_tx_fifo_size; - int32_t max_transfer_size; - int32_t max_packet_count; - int32_t host_channels; - int32_t dev_endpoints; - int32_t phy_type; - int32_t phy_utmi_width; - int32_t phy_ulpi_ddr; - int32_t phy_ulpi_ext_vbus; - int32_t i2c_enable; - int32_t ulpi_fs_ls; - int32_t ts_dline; - int32_t en_multiple_tx_fifo; - uint32_t dev_tx_fifo_size[15]; - uint32_t thr_ctl; - uint32_t tx_thr_length; - uint32_t rx_thr_length; - int32_t pti_enable; - int32_t mpi_enable; - int32_t lpm_enable; - int32_t ic_usb_cap; - int32_t ahb_thr_ratio; - int32_t power_down; - int32_t reload_ctl; - int32_t dev_out_nak; - int32_t cont_on_bna; - int32_t ahb_single; - int32_t otg_ver; - int32_t adp_enable; -}; - -union gotgctl_data { - uint32_t d32; - struct { - unsigned int sesreqscs: 1; - unsigned int sesreq: 1; - unsigned int vbvalidoven: 1; - unsigned int vbvalidovval: 1; - unsigned int avalidoven: 1; - unsigned int avalidovval: 1; - unsigned int bvalidoven: 1; - unsigned int bvalidovval: 1; - unsigned int hstnegscs: 1; - unsigned int hnpreq: 1; - unsigned int hstsethnpen: 1; - unsigned int devhnpen: 1; - unsigned int reserved12_15: 4; - unsigned int conidsts: 1; - unsigned int dbnctime: 1; - unsigned int asesvld: 1; - unsigned int bsesvld: 1; - unsigned int otgver: 1; - unsigned int reserved1: 1; - unsigned int multvalidbc: 5; - unsigned int chirpen: 1; - unsigned int reserved28_31: 4; - } b; -}; - -typedef union gotgctl_data gotgctl_data_t; - -union gahbcfg_data { - uint32_t d32; - struct { - unsigned int glblintrmsk: 1; - unsigned int hburstlen: 4; - unsigned int dmaenable: 1; - unsigned int reserved: 1; - unsigned int nptxfemplvl_txfemplvl: 1; - unsigned int ptxfemplvl: 1; - unsigned int reserved9_20: 12; - unsigned int remmemsupp: 1; - unsigned int notialldmawrit: 1; - unsigned int ahbsingle: 1; - unsigned int reserved24_31: 8; - } b; -}; - -typedef union gahbcfg_data gahbcfg_data_t; - -union gusbcfg_data { - uint32_t d32; - struct { - unsigned int toutcal: 3; - unsigned int phyif: 1; - unsigned int ulpi_utmi_sel: 1; - unsigned int fsintf: 1; - unsigned int physel: 1; - unsigned int ddrsel: 1; - unsigned int srpcap: 1; - unsigned int hnpcap: 1; - unsigned int usbtrdtim: 4; - unsigned int reserved1: 1; - unsigned int phylpwrclksel: 1; - unsigned int otgutmifssel: 1; - unsigned int ulpi_fsls: 1; - unsigned int ulpi_auto_res: 1; - unsigned int ulpi_clk_sus_m: 1; - unsigned int ulpi_ext_vbus_drv: 1; - unsigned int ulpi_int_vbus_indicator: 1; - unsigned int term_sel_dl_pulse: 1; - unsigned int indicator_complement: 1; - unsigned int indicator_pass_through: 1; - unsigned int ulpi_int_prot_dis: 1; - unsigned int ic_usb_cap: 1; - unsigned int ic_traffic_pull_remove: 1; - unsigned int tx_end_delay: 1; - unsigned int force_host_mode: 1; - unsigned int force_dev_mode: 1; - unsigned int reserved31: 1; - } b; -}; - -typedef union gusbcfg_data gusbcfg_data_t; - -union grstctl_data { - uint32_t d32; - struct { - unsigned int csftrst: 1; - unsigned int hsftrst: 1; - unsigned int hstfrm: 1; - unsigned int intknqflsh: 1; - unsigned int rxfflsh: 1; - unsigned int txfflsh: 1; - unsigned int txfnum: 5; - unsigned int reserved11_29: 19; - unsigned int dmareq: 1; - unsigned int ahbidle: 1; - } b; -}; - -typedef union grstctl_data grstctl_t; - -union gintsts_data { - uint32_t d32; - struct { - unsigned int curmode: 1; - unsigned int modemismatch: 1; - unsigned int otgintr: 1; - unsigned int sofintr: 1; - unsigned int rxstsqlvl: 1; - unsigned int nptxfempty: 1; - unsigned int ginnakeff: 1; - unsigned int goutnakeff: 1; - unsigned int ulpickint: 1; - unsigned int i2cintr: 1; - unsigned int erlysuspend: 1; - unsigned int usbsuspend: 1; - unsigned int usbreset: 1; - unsigned int enumdone: 1; - unsigned int isooutdrop: 1; - unsigned int eopframe: 1; - unsigned int restoredone: 1; - unsigned int epmismatch: 1; - unsigned int inepint: 1; - unsigned int outepintr: 1; - unsigned int incomplisoin: 1; - unsigned int incomplisoout: 1; - unsigned int fetsusp: 1; - unsigned int resetdet: 1; - unsigned int portintr: 1; - unsigned int hcintr: 1; - unsigned int ptxfempty: 1; - unsigned int lpmtranrcvd: 1; - unsigned int conidstschng: 1; - unsigned int disconnect: 1; - unsigned int sessreqintr: 1; - unsigned int wkupintr: 1; - } b; -}; - -typedef union gintsts_data gintsts_data_t; - -union device_grxsts_data { - uint32_t d32; - struct { - unsigned int epnum: 4; - unsigned int bcnt: 11; - unsigned int dpid: 2; - unsigned int pktsts: 4; - unsigned int fn: 4; - unsigned int reserved25_31: 7; - } b; -}; - -typedef union device_grxsts_data device_grxsts_data_t; - -union gnptxsts_data { - uint32_t d32; - struct { - unsigned int nptxfspcavail: 16; - unsigned int nptxqspcavail: 8; - unsigned int nptxqtop_terminate: 1; - unsigned int nptxqtop_token: 2; - unsigned int nptxqtop_chnep: 4; - unsigned int reserved: 1; - } b; -}; - -typedef union gnptxsts_data gnptxsts_data_t; - -union dtxfsts_data { - uint32_t d32; - struct { - unsigned int txfspcavail: 16; - unsigned int reserved: 16; - } b; -}; - -typedef union dtxfsts_data dtxfsts_data_t; - -union gi2cctl_data { - uint32_t d32; - struct { - unsigned int rwdata: 8; - unsigned int regaddr: 8; - unsigned int addr: 7; - unsigned int i2cen: 1; - unsigned int ack: 1; - unsigned int i2csuspctl: 1; - unsigned int i2cdevaddr: 2; - unsigned int i2cdatse0: 1; - unsigned int reserved: 1; - unsigned int rw: 1; - unsigned int bsydne: 1; - } b; -}; - -typedef union gi2cctl_data gi2cctl_data_t; - -union glpmctl_data { - uint32_t d32; - struct { - unsigned int lpm_cap_en: 1; - unsigned int appl_resp: 1; - unsigned int hird: 4; - unsigned int rem_wkup_en: 1; - unsigned int en_utmi_sleep: 1; - unsigned int hird_thres: 5; - unsigned int lpm_resp: 2; - unsigned int prt_sleep_sts: 1; - unsigned int sleep_state_resumeok: 1; - unsigned int lpm_chan_index: 4; - unsigned int retry_count: 3; - unsigned int send_lpm: 1; - unsigned int retry_count_sts: 3; - unsigned int reserved28_29: 2; - unsigned int hsic_connect: 1; - unsigned int inv_sel_hsic: 1; - } b; -}; - -typedef union glpmctl_data glpmcfg_data_t; - -union dctl_data { - uint32_t d32; - struct { - unsigned int rmtwkupsig: 1; - unsigned int sftdiscon: 1; - unsigned int gnpinnaksts: 1; - unsigned int goutnaksts: 1; - unsigned int tstctl: 3; - unsigned int sgnpinnak: 1; - unsigned int cgnpinnak: 1; - unsigned int sgoutnak: 1; - unsigned int cgoutnak: 1; - unsigned int pwronprgdone: 1; - unsigned int reserved: 1; - unsigned int gmc: 2; - unsigned int ifrmnum: 1; - unsigned int nakonbble: 1; - unsigned int encontonbna: 1; - unsigned int reserved18_31: 14; - } b; -}; - -typedef union dctl_data dctl_data_t; - -union dsts_data { - uint32_t d32; - struct { - unsigned int suspsts: 1; - unsigned int enumspd: 2; - unsigned int errticerr: 1; - unsigned int reserved4_7: 4; - unsigned int soffn: 14; - unsigned int reserved22_31: 10; - } b; -}; - -typedef union dsts_data dsts_data_t; - -union diepint_data { - uint32_t d32; - struct { - unsigned int xfercompl: 1; - unsigned int epdisabled: 1; - unsigned int ahberr: 1; - unsigned int timeout: 1; - unsigned int intktxfemp: 1; - unsigned int intknepmis: 1; - unsigned int inepnakeff: 1; - unsigned int emptyintr: 1; - unsigned int txfifoundrn: 1; - unsigned int bna: 1; - unsigned int reserved10_12: 3; - unsigned int nak: 1; - unsigned int reserved14_31: 18; - } b; -}; - -typedef union diepint_data diepint_data_t; - -typedef union diepint_data diepmsk_data_t; - -union doepint_data { - uint32_t d32; - struct { - unsigned int xfercompl: 1; - unsigned int epdisabled: 1; - unsigned int ahberr: 1; - unsigned int setup: 1; - unsigned int outtknepdis: 1; - unsigned int stsphsercvd: 1; - unsigned int back2backsetup: 1; - unsigned int reserved7: 1; - unsigned int outpkterr: 1; - unsigned int bna: 1; - unsigned int reserved10: 1; - unsigned int pktdrpsts: 1; - unsigned int babble: 1; - unsigned int nak: 1; - unsigned int nyet: 1; - unsigned int sr: 1; - unsigned int reserved16_31: 16; - } b; -}; - -typedef union doepint_data doepint_data_t; - -typedef union doepint_data doepmsk_data_t; - -union daint_data { - uint32_t d32; - struct { - unsigned int in: 16; - unsigned int out: 16; - } ep; - struct { - unsigned int inep0: 1; - unsigned int inep1: 1; - unsigned int inep2: 1; - unsigned int inep3: 1; - unsigned int inep4: 1; - unsigned int inep5: 1; - unsigned int inep6: 1; - unsigned int inep7: 1; - unsigned int inep8: 1; - unsigned int inep9: 1; - unsigned int inep10: 1; - unsigned int inep11: 1; - unsigned int inep12: 1; - unsigned int inep13: 1; - unsigned int inep14: 1; - unsigned int inep15: 1; - unsigned int outep0: 1; - unsigned int outep1: 1; - unsigned int outep2: 1; - unsigned int outep3: 1; - unsigned int outep4: 1; - unsigned int outep5: 1; - unsigned int outep6: 1; - unsigned int outep7: 1; - unsigned int outep8: 1; - unsigned int outep9: 1; - unsigned int outep10: 1; - unsigned int outep11: 1; - unsigned int outep12: 1; - unsigned int outep13: 1; - unsigned int outep14: 1; - unsigned int outep15: 1; - } b; -}; - -typedef union daint_data daint_data_t; - -union dthrctl_data { - uint32_t d32; - struct { - unsigned int non_iso_thr_en: 1; - unsigned int iso_thr_en: 1; - unsigned int tx_thr_len: 9; - unsigned int ahb_thr_ratio: 2; - unsigned int reserved13_15: 3; - unsigned int rx_thr_en: 1; - unsigned int rx_thr_len: 9; - unsigned int reserved26: 1; - unsigned int arbprken: 1; - unsigned int reserved28_31: 4; - } b; -}; - -typedef union dthrctl_data dthrctl_data_t; - -union depctl_data { - uint32_t d32; - struct { - unsigned int mps: 11; - unsigned int nextep: 4; - unsigned int usbactep: 1; - unsigned int dpid: 1; - unsigned int naksts: 1; - unsigned int eptype: 2; - unsigned int snp: 1; - unsigned int stall: 1; - unsigned int txfnum: 4; - unsigned int cnak: 1; - unsigned int snak: 1; - unsigned int setd0pid: 1; - unsigned int setd1pid: 1; - unsigned int epdis: 1; - unsigned int epena: 1; - } b; -}; - -typedef union depctl_data depctl_data_t; - -union deptsiz_data { - uint32_t d32; - struct { - unsigned int xfersize: 19; - unsigned int pktcnt: 10; - unsigned int mc: 2; - unsigned int reserved: 1; - } b; -}; - -typedef union deptsiz_data deptsiz_data_t; - -union deptsiz0_data { - uint32_t d32; - struct { - unsigned int xfersize: 7; - unsigned int reserved7_18: 12; - unsigned int pktcnt: 2; - unsigned int reserved21_28: 8; - unsigned int supcnt: 2; - unsigned int reserved31; - } b; -}; - -typedef union deptsiz0_data deptsiz0_data_t; - -union hfir_data { - uint32_t d32; - struct { - unsigned int frint: 16; - unsigned int hfirrldctrl: 1; - unsigned int reserved: 15; - } b; -}; - -typedef union hfir_data hfir_data_t; - -union hfnum_data { - uint32_t d32; - struct { - unsigned int frnum: 16; - unsigned int frrem: 16; - } b; -}; - -typedef union hfnum_data hfnum_data_t; - -union hptxsts_data { - uint32_t d32; - struct { - unsigned int ptxfspcavail: 16; - unsigned int ptxqspcavail: 8; - unsigned int ptxqtop_terminate: 1; - unsigned int ptxqtop_token: 2; - unsigned int ptxqtop_chnum: 4; - unsigned int ptxqtop_odd: 1; - } b; -}; - -typedef union hptxsts_data hptxsts_data_t; - -union hprt0_data { - uint32_t d32; - struct { - unsigned int prtconnsts: 1; - unsigned int prtconndet: 1; - unsigned int prtena: 1; - unsigned int prtenchng: 1; - unsigned int prtovrcurract: 1; - unsigned int prtovrcurrchng: 1; - unsigned int prtres: 1; - unsigned int prtsusp: 1; - unsigned int prtrst: 1; - unsigned int reserved9: 1; - unsigned int prtlnsts: 2; - unsigned int prtpwr: 1; - unsigned int prttstctl: 4; - unsigned int prtspd: 2; - unsigned int reserved19_31: 13; - } b; -}; - -typedef union hprt0_data hprt0_data_t; - -union pcgcctl_data { - uint32_t d32; - struct { - unsigned int stoppclk: 1; - unsigned int gatehclk: 1; - unsigned int pwrclmp: 1; - unsigned int rstpdwnmodule: 1; - unsigned int reserved: 1; - unsigned int enbl_sleep_gating: 1; - unsigned int phy_in_sleep: 1; - unsigned int deep_sleep: 1; - unsigned int resetaftsusp: 1; - unsigned int restoremode: 1; - unsigned int enbl_extnd_hiber: 1; - unsigned int extnd_hiber_pwrclmp: 1; - unsigned int extnd_hiber_switch: 1; - unsigned int ess_reg_restored: 1; - unsigned int prt_clk_sel: 2; - unsigned int port_power: 1; - unsigned int max_xcvrselect: 2; - unsigned int max_termsel: 1; - unsigned int mac_dev_addr: 7; - unsigned int p2hd_dev_enum_spd: 2; - unsigned int p2hd_prt_spd: 2; - unsigned int if_dev_mode: 1; - } b; -}; - -typedef union pcgcctl_data pcgcctl_data_t; - -union gdfifocfg_data { - uint32_t d32; - struct { - unsigned int gdfifocfg: 16; - unsigned int epinfobase: 16; - } b; -}; - -typedef union gdfifocfg_data gdfifocfg_data_t; - -union gpwrdn_data { - uint32_t d32; - struct { - unsigned int pmuintsel: 1; - unsigned int pmuactv: 1; - unsigned int restore: 1; - unsigned int pwrdnclmp: 1; - unsigned int pwrdnrstn: 1; - unsigned int pwrdnswtch: 1; - unsigned int dis_vbus: 1; - unsigned int lnstschng: 1; - unsigned int lnstchng_msk: 1; - unsigned int rst_det: 1; - unsigned int rst_det_msk: 1; - unsigned int disconn_det: 1; - unsigned int disconn_det_msk: 1; - unsigned int connect_det: 1; - unsigned int connect_det_msk: 1; - unsigned int srp_det: 1; - unsigned int srp_det_msk: 1; - unsigned int sts_chngint: 1; - unsigned int sts_chngint_msk: 1; - unsigned int linestate: 2; - unsigned int idsts: 1; - unsigned int bsessvld: 1; - unsigned int adp_int: 1; - unsigned int mult_val_id_bc: 5; - unsigned int reserved29_31: 3; - } b; -}; - -typedef union gpwrdn_data gpwrdn_data_t; - -typedef struct dwc_hc dwc_hc_t; - -typedef struct dwc_otg_cil_callbacks dwc_otg_cil_callbacks_t; - -union gotgint_data { - uint32_t d32; - struct { - unsigned int reserved0_1: 2; - unsigned int sesenddet: 1; - unsigned int reserved3_7: 5; - unsigned int sesreqsucstschng: 1; - unsigned int hstnegsucstschng: 1; - unsigned int reserved10_16: 7; - unsigned int hstnegdet: 1; - unsigned int adevtoutchng: 1; - unsigned int debdone: 1; - unsigned int mvic: 1; - unsigned int reserved31_21: 11; - } b; -}; - -typedef union gotgint_data gotgint_data_t; - -enum ep0_state { - EP0_DISCONNECT = 0, - EP0_IDLE = 1, - EP0_IN_DATA_PHASE = 2, - EP0_OUT_DATA_PHASE = 3, - EP0_IN_STATUS_PHASE = 4, - EP0_OUT_STATUS_PHASE = 5, - EP0_STALL = 6, -}; - -typedef enum ep0_state ep0state_e; - -typedef u_int8_t uByte; - -typedef u_int8_t uWord[2]; - -typedef struct { - uByte bmRequestType; - uByte bRequest; - uWord wValue; - uWord wIndex; - uWord wLength; -} usb_device_request_t; - -typedef struct { - uByte bLength; - uByte bDescriptorType; - uByte bEndpointAddress; - uByte bmAttributes; - uWord wMaxPacketSize; - uByte bInterval; -} usb_endpoint_descriptor_t; - -struct dwc_otg_pcd_request; - -struct req_list { - struct dwc_otg_pcd_request *cqh_first; - struct dwc_otg_pcd_request *cqh_last; -}; - -struct dwc_otg_pcd_ep { - const usb_endpoint_descriptor_t *desc; - struct req_list queue; - unsigned int stopped: 1; - unsigned int disabling: 1; - unsigned int dma: 1; - unsigned int queue_sof: 1; - dwc_ep_t dwc_ep; - struct dwc_otg_pcd *pcd; - void *priv; -}; - -typedef struct dwc_otg_pcd_ep dwc_otg_pcd_ep_t; - -struct dwc_otg_pcd_function_ops; - -struct dwc_otg_pcd { - const struct dwc_otg_pcd_function_ops *fops; - struct dwc_otg_device *otg_dev; - dwc_otg_core_if_t *core_if; - ep0state_e ep0state; - unsigned int ep0_pending: 1; - unsigned int request_config: 1; - unsigned int remote_wakeup_enable: 1; - unsigned int b_hnp_enable: 1; - unsigned int a_hnp_support: 1; - unsigned int a_alt_hnp_support: 1; - unsigned int request_pending; - union { - usb_device_request_t req; - uint32_t d32[2]; - } *setup_pkt; - dwc_dma_t setup_pkt_dma_handle; - uint8_t *backup_buf; - unsigned int data_terminated; - uint16_t *status_buf; - dwc_dma_t status_buf_dma_handle; - dwc_otg_pcd_ep_t ep0; - dwc_otg_pcd_ep_t in_ep[15]; - dwc_otg_pcd_ep_t out_ep[15]; - dwc_spinlock_t *lock; - dwc_tasklet_t *test_mode_tasklet; - dwc_tasklet_t *start_xfer_tasklet; - unsigned int test_mode; -}; - -typedef struct dwc_otg_pcd dwc_otg_pcd_t; - -typedef int (*dwc_completion_cb_t)(dwc_otg_pcd_t *, void *, void *, int32_t, uint32_t); - -typedef int (*dwc_isoc_completion_cb_t)(dwc_otg_pcd_t *, void *, void *, int); - -typedef int (*dwc_setup_cb_t)(dwc_otg_pcd_t *, uint8_t *); - -typedef int (*dwc_disconnect_cb_t)(dwc_otg_pcd_t *); - -typedef int (*dwc_connect_cb_t)(dwc_otg_pcd_t *, int); - -typedef int (*dwc_suspend_cb_t)(dwc_otg_pcd_t *); - -typedef int (*dwc_sleep_cb_t)(dwc_otg_pcd_t *); - -typedef int (*dwc_resume_cb_t)(dwc_otg_pcd_t *); - -typedef int (*dwc_hnp_params_changed_cb_t)(dwc_otg_pcd_t *); - -typedef int (*dwc_reset_cb_t)(dwc_otg_pcd_t *); - -typedef int (*cfi_setup_cb_t)(dwc_otg_pcd_t *, void *); - -struct dwc_otg_pcd_function_ops { - dwc_connect_cb_t connect; - dwc_disconnect_cb_t disconnect; - dwc_setup_cb_t setup; - dwc_completion_cb_t complete; - dwc_isoc_completion_cb_t isoc_complete; - dwc_suspend_cb_t suspend; - dwc_sleep_cb_t sleep; - dwc_resume_cb_t resume; - dwc_reset_cb_t reset; - dwc_hnp_params_changed_cb_t hnp_changed; - cfi_setup_cb_t cfi_setup; -}; - -struct dwc_otg_pcd_request { - void *priv; - void *buf; - dwc_dma_t dma; - uint32_t length; - uint32_t actual; - unsigned int sent_zlp: 1; - uint8_t *dw_align_buf; - dwc_dma_t dw_align_buf_dma; - struct { - struct dwc_otg_pcd_request *cqe_next; - struct dwc_otg_pcd_request *cqe_prev; - } queue_entry; -}; - -typedef s8 int8_t; - -typedef struct platform_device dwc_bus_dev_t; - -struct gadget_wrapper { - dwc_otg_pcd_t *pcd; - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct usb_ep ep0; - struct usb_ep in_ep[16]; - struct usb_ep out_ep[16]; -}; - -typedef long unsigned int dwc_irqflags_t; - -typedef struct dwc_otg_pcd_request dwc_otg_pcd_request_t; - -union dtknq1_data { - uint32_t d32; - struct { - unsigned int intknwptr: 5; - unsigned int reserved05_06: 2; - unsigned int wrap_bit: 1; - unsigned int epnums0_5: 24; - } b; -}; - -typedef union dtknq1_data dtknq1_data_t; - -typedef struct { - uByte bDescLength; - uByte bDescriptorType; - uByte bNbrPorts; - uWord wHubCharacteristics; - uByte bPwrOn2PwrGood; - uByte bHubContrCurrent; - uByte DeviceRemovable[32]; - uByte PortPowerCtrlMask[1]; -} usb_hub_descriptor_t; - -union host_grxsts_data { - uint32_t d32; - struct { - unsigned int chnum: 4; - unsigned int bcnt: 11; - unsigned int dpid: 2; - unsigned int pktsts: 4; - unsigned int reserved21_31: 11; - } b; -}; - -typedef union host_grxsts_data host_grxsts_data_t; - -union haint_data { - uint32_t d32; - struct { - unsigned int ch0: 1; - unsigned int ch1: 1; - unsigned int ch2: 1; - unsigned int ch3: 1; - unsigned int ch4: 1; - unsigned int ch5: 1; - unsigned int ch6: 1; - unsigned int ch7: 1; - unsigned int ch8: 1; - unsigned int ch9: 1; - unsigned int ch10: 1; - unsigned int ch11: 1; - unsigned int ch12: 1; - unsigned int ch13: 1; - unsigned int ch14: 1; - unsigned int ch15: 1; - unsigned int reserved: 16; - } b; - struct { - unsigned int chint: 16; - unsigned int reserved: 16; - } b2; -}; - -typedef union haint_data haint_data_t; - -enum dwc_otg_transaction_type { - DWC_OTG_TRANSACTION_NONE = 0, - DWC_OTG_TRANSACTION_PERIODIC = 1, - DWC_OTG_TRANSACTION_NON_PERIODIC = 2, - DWC_OTG_TRANSACTION_ALL = 3, -}; - -typedef enum dwc_otg_transaction_type dwc_otg_transaction_type_e; - -typedef struct dwc_otg_qtd dwc_otg_qtd_t; - -typedef struct dwc_otg_qh dwc_otg_qh_t; - -typedef struct urb_tq_entry urb_tq_entry_t; - -struct wrapper_priv_data { - dwc_otg_hcd_t *dwc_otg_hcd; -}; - -union adpctl_data { - uint32_t d32; - struct { - unsigned int prb_dschg: 2; - unsigned int prb_delta: 2; - unsigned int prb_per: 2; - unsigned int rtim: 11; - unsigned int enaprb: 1; - unsigned int enasns: 1; - unsigned int adpres: 1; - unsigned int adpen: 1; - unsigned int adp_prb_int: 1; - unsigned int adp_sns_int: 1; - unsigned int adp_tmout_int: 1; - unsigned int adp_prb_int_msk: 1; - unsigned int adp_sns_int_msk: 1; - unsigned int adp_tmout_int_msk: 1; - unsigned int ar: 2; - unsigned int reserved29_31: 3; - } b; -}; - -typedef union adpctl_data adpctl_data_t; - -enum fiq_debug_level { - FIQDBG_SCHED = 1, - FIQDBG_INT = 2, - FIQDBG_ERR = 4, - FIQDBG_PORTHUB = 8, -}; - -struct dwc_mutex; - -typedef struct dwc_mutex dwc_mutex_t; - -struct dwc_notifier; - -typedef struct dwc_notifier dwc_notifier_t; - -struct dwc_cc; - -struct context_list { - struct dwc_cc *cqh_first; - struct dwc_cc *cqh_last; -}; - -struct dwc_cc_if { - dwc_mutex_t *mutex; - char *filename; - unsigned int is_host: 1; - dwc_notifier_t *notifier; - struct context_list list; -}; - -typedef struct dwc_cc_if dwc_cc_if_t; - -struct dwc_cc { - uint32_t uid; - uint8_t chid[16]; - uint8_t cdid[16]; - uint8_t ck[16]; - uint8_t *name; - uint8_t length; - struct { - struct dwc_cc *cqe_next; - struct dwc_cc *cqe_prev; - } list_entry; -}; - -typedef struct dwc_cc dwc_cc_t; - -struct dwc_observer; - -struct observer_queue { - struct dwc_observer *cqh_first; - struct dwc_observer *cqh_last; -}; - -struct dwc_notifier___2 { - void *mem_ctx; - void *object; - struct observer_queue observers; - struct { - struct dwc_notifier___2 *cqe_next; - struct dwc_notifier___2 *cqe_prev; - } list_entry; -}; - -typedef struct dwc_notifier___2 dwc_notifier_t___2; - -typedef void (*dwc_notifier_callback_t)(void *, char *, void *, void *, void *); - -struct dwc_observer { - void *observer; - dwc_notifier_callback_t callback; - void *data; - char *notification; - struct { - struct dwc_observer *cqe_next; - struct dwc_observer *cqe_prev; - } list_entry; -}; - -typedef struct dwc_observer observer_t; - -typedef struct dwc_notifier___2 notifier_t; - -struct notifier_queue { - struct dwc_notifier___2 *cqh_first; - struct dwc_notifier___2 *cqh_last; -}; - -struct manager { - void *mem_ctx; - void *wkq_ctx; - dwc_workq_t *wq; - struct notifier_queue notifiers; -}; - -typedef struct manager manager_t; - -struct callback_data { - void *mem_ctx; - dwc_notifier_callback_t cb; - void *observer; - void *data; - void *object; - char *notification; - void *notification_data; -}; - -typedef struct callback_data cb_data_t; - -typedef uint8_t dwc_bool_t; - -struct dwc_waitq { - wait_queue_head_t queue; - int abort; -}; - -typedef struct dwc_waitq dwc_waitq_t; - -typedef int (*dwc_waitq_condition_t)(void *); - -struct dwc_thread; - -typedef struct dwc_thread dwc_thread_t; - -typedef int (*dwc_thread_function_t)(void *); - -struct dwc_workq___2 { - struct workqueue_struct *wq; - dwc_spinlock_t *lock; - dwc_waitq_t *waitq; - int pending; -}; - -typedef struct dwc_workq___2 dwc_workq_t___2; - -typedef void (*dwc_work_callback_t)(void *); - -typedef void (*dwc_tasklet_callback_t)(void *); - -struct dwc_tasklet___2 { - struct tasklet_struct t; - dwc_tasklet_callback_t cb; - void *data; -}; - -typedef struct dwc_tasklet___2 dwc_tasklet_t___2; - -typedef void (*dwc_timer_callback_t)(void *); - -struct dwc_timer___2 { - struct timer_list t; - char *name; - dwc_timer_callback_t cb; - void *data; - uint8_t scheduled; - dwc_spinlock_t *lock; -}; - -typedef struct dwc_timer___2 dwc_timer_t___2; - -struct work_container { - dwc_work_callback_t cb; - void *data; - dwc_workq_t___2 *wq; - char *name; - struct delayed_work work; -}; - -typedef struct work_container work_container_t; - -enum { - US_FL_SINGLE_LUN = 1, - US_FL_NEED_OVERRIDE = 2, - US_FL_SCM_MULT_TARG = 4, - US_FL_FIX_INQUIRY = 8, - US_FL_FIX_CAPACITY = 16, - US_FL_IGNORE_RESIDUE = 32, - US_FL_BULK32 = 64, - US_FL_NOT_LOCKABLE = 128, - US_FL_GO_SLOW = 256, - US_FL_NO_WP_DETECT = 512, - US_FL_MAX_SECTORS_64 = 1024, - US_FL_IGNORE_DEVICE = 2048, - US_FL_CAPACITY_HEURISTICS = 4096, - US_FL_MAX_SECTORS_MIN = 8192, - US_FL_BULK_IGNORE_TAG = 16384, - US_FL_SANE_SENSE = 32768, - US_FL_CAPACITY_OK = 65536, - US_FL_BAD_SENSE = 131072, - US_FL_NO_READ_DISC_INFO = 262144, - US_FL_NO_READ_CAPACITY_16 = 524288, - US_FL_INITIAL_READ10 = 1048576, - US_FL_WRITE_CACHE = 2097152, - US_FL_NEEDS_CAP16 = 4194304, - US_FL_IGNORE_UAS = 8388608, - US_FL_BROKEN_FUA = 16777216, - US_FL_NO_ATA_1X = 33554432, - US_FL_NO_REPORT_OPCODES = 67108864, - US_FL_MAX_SECTORS_240 = 134217728, - US_FL_NO_REPORT_LUNS = 268435456, - US_FL_ALWAYS_SYNC = 536870912, - US_FL_NO_SAME = 1073741824, - US_FL_SENSE_AFTER_SYNC = 2147483648, -}; - -struct iu { - __u8 iu_id; - __u8 rsvd1; - __be16 tag; -}; - -enum { - IU_ID_COMMAND = 1, - IU_ID_STATUS = 3, - IU_ID_RESPONSE = 4, - IU_ID_TASK_MGMT = 5, - IU_ID_READ_READY = 6, - IU_ID_WRITE_READY = 7, -}; - -enum { - RC_TMF_COMPLETE = 0, - RC_INVALID_INFO_UNIT = 2, - RC_TMF_NOT_SUPPORTED = 4, - RC_TMF_FAILED = 5, - RC_TMF_SUCCEEDED = 8, - RC_INCORRECT_LUN = 9, - RC_OVERLAPPED_TAG = 10, -}; - -struct command_iu { - __u8 iu_id; - __u8 rsvd1; - __be16 tag; - __u8 prio_attr; - __u8 rsvd5; - __u8 len; - __u8 rsvd7; - struct scsi_lun lun; - __u8 cdb[16]; -}; - -struct sense_iu { - __u8 iu_id; - __u8 rsvd1; - __be16 tag; - __be16 status_qual; - __u8 status; - __u8 rsvd7[7]; - __be16 len; - __u8 sense[96]; -}; - -struct response_iu { - __u8 iu_id; - __u8 rsvd1; - __be16 tag; - __u8 add_response_info[3]; - __u8 response_code; -}; - -enum { - CMD_PIPE_ID = 1, - STATUS_PIPE_ID = 2, - DATA_IN_PIPE_ID = 3, - DATA_OUT_PIPE_ID = 4, - UAS_SIMPLE_TAG = 0, - UAS_HEAD_TAG = 1, - UAS_ORDERED_TAG = 2, - UAS_ACA = 4, -}; - -struct uas_dev_info { - struct usb_interface *intf; - struct usb_device *udev; - struct usb_anchor cmd_urbs; - struct usb_anchor sense_urbs; - struct usb_anchor data_urbs; - long unsigned int flags; - int qdepth; - int resetting; - unsigned int cmd_pipe; - unsigned int status_pipe; - unsigned int data_in_pipe; - unsigned int data_out_pipe; - unsigned int use_streams: 1; - unsigned int shutdown: 1; - struct scsi_cmnd *cmnd[256]; - spinlock_t lock; - struct work_struct work; - struct work_struct scan_work; -}; - -enum { - SUBMIT_STATUS_URB = 2, - ALLOC_DATA_IN_URB = 4, - SUBMIT_DATA_IN_URB = 8, - ALLOC_DATA_OUT_URB = 16, - SUBMIT_DATA_OUT_URB = 32, - ALLOC_CMD_URB = 64, - SUBMIT_CMD_URB = 128, - COMMAND_INFLIGHT = 256, - DATA_IN_URB_INFLIGHT = 512, - DATA_OUT_URB_INFLIGHT = 1024, - COMMAND_ABORTED = 2048, - IS_IN_WORK_LIST = 4096, -}; - -struct uas_cmd_info { - unsigned int state; - unsigned int uas_tag; - struct urb *cmd_urb; - struct urb *data_in_urb; - struct urb *data_out_urb; -}; - -struct us_data; - -struct us_unusual_dev { - const char *vendorName; - const char *productName; - __u8 useProtocol; - __u8 useTransport; - int (*initFunction)(struct us_data *); -}; - -typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data *); - -typedef int (*trans_reset)(struct us_data *); - -typedef void (*proto_cmnd)(struct scsi_cmnd *, struct us_data *); - -typedef void (*extra_data_destructor)(void *); - -typedef void (*pm_hook)(struct us_data *, int); - -struct us_data { - struct mutex dev_mutex; - struct usb_device *pusb_dev; - struct usb_interface *pusb_intf; - const struct us_unusual_dev *unusual_dev; - long unsigned int fflags; - long unsigned int dflags; - unsigned int send_bulk_pipe; - unsigned int recv_bulk_pipe; - unsigned int send_ctrl_pipe; - unsigned int recv_ctrl_pipe; - unsigned int recv_intr_pipe; - char *transport_name; - char *protocol_name; - __le32 bcs_signature; - u8 subclass; - u8 protocol; - u8 max_lun; - u8 ifnum; - u8 ep_bInterval; - trans_cmnd transport; - trans_reset transport_reset; - proto_cmnd proto_handler; - struct scsi_cmnd *srb; - unsigned int tag; - char scsi_name[32]; - struct urb *current_urb; - struct usb_ctrlrequest *cr; - struct usb_sg_request current_sg; - unsigned char *iobuf; - dma_addr_t iobuf_dma; - struct task_struct *ctl_thread; - struct completion cmnd_ready; - struct completion notify; - wait_queue_head_t delay_wait; - struct delayed_work scan_dwork; - void *extra; - extra_data_destructor extra_destructor; - pm_hook suspend_resume_hook; - int use_last_sector_hacks; - int last_sector_retries; -}; - -enum xfer_buf_dir { - TO_XFER_BUF = 0, - FROM_XFER_BUF = 1, -}; - -struct bulk_cb_wrap { - __le32 Signature; - __u32 Tag; - __le32 DataTransferLength; - __u8 Flags; - __u8 Lun; - __u8 Length; - __u8 CDB[16]; -}; - -struct bulk_cs_wrap { - __le32 Signature; - __u32 Tag; - __le32 Residue; - __u8 Status; -}; - -struct swoc_info { - __u8 rev; - __u8 reserved[8]; - __u16 LinuxSKU; - __u16 LinuxVer; - __u8 reserved2[47]; -} __attribute__((packed)); - -struct ignore_entry { - u16 vid; - u16 pid; - u16 bcdmin; - u16 bcdmax; -}; - -struct usb_udc { - struct usb_gadget_driver *driver; - struct usb_gadget *gadget; - struct device dev; - struct list_head list; - bool vbus; -}; - -struct trace_event_raw_udc_log_gadget { - struct trace_entry ent; - enum usb_device_speed speed; - enum usb_device_speed max_speed; - enum usb_device_state state; - unsigned int mA; - unsigned int sg_supported; - unsigned int is_otg; - unsigned int is_a_peripheral; - unsigned int b_hnp_enable; - unsigned int a_hnp_support; - unsigned int hnp_polling_support; - unsigned int host_request_flag; - unsigned int quirk_ep_out_aligned_size; - unsigned int quirk_altset_not_supp; - unsigned int quirk_stall_not_supp; - unsigned int quirk_zlp_not_supp; - unsigned int is_selfpowered; - unsigned int deactivated; - unsigned int connected; - int ret; - char __data[0]; -}; - -struct trace_event_raw_udc_log_ep { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int maxpacket; - unsigned int maxpacket_limit; - unsigned int max_streams; - unsigned int mult; - unsigned int maxburst; - u8 address; - bool claimed; - bool enabled; - int ret; - char __data[0]; -}; - -struct trace_event_raw_udc_log_req { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int length; - unsigned int actual; - unsigned int num_sgs; - unsigned int num_mapped_sgs; - unsigned int stream_id; - unsigned int no_interrupt; - unsigned int zero; - unsigned int short_not_ok; - int status; - int ret; - struct usb_request *req; - char __data[0]; -}; - -struct trace_event_data_offsets_udc_log_gadget {}; - -struct trace_event_data_offsets_udc_log_ep { - u32 name; -}; - -struct trace_event_data_offsets_udc_log_req { - u32 name; -}; - -typedef void (*btf_trace_usb_gadget_frame_number)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_wakeup)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_set_selfpowered)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_clear_selfpowered)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_vbus_connect)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_vbus_draw)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_vbus_disconnect)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_connect)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_disconnect)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_deactivate)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_gadget_activate)(void *, struct usb_gadget *, int); - -typedef void (*btf_trace_usb_ep_set_maxpacket_limit)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_enable)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_disable)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_set_halt)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_clear_halt)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_set_wedge)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_fifo_status)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_fifo_flush)(void *, struct usb_ep *, int); - -typedef void (*btf_trace_usb_ep_alloc_request)(void *, struct usb_ep *, struct usb_request *, int); - -typedef void (*btf_trace_usb_ep_free_request)(void *, struct usb_ep *, struct usb_request *, int); - -typedef void (*btf_trace_usb_ep_queue)(void *, struct usb_ep *, struct usb_request *, int); - -typedef void (*btf_trace_usb_ep_dequeue)(void *, struct usb_ep *, struct usb_request *, int); - -typedef void (*btf_trace_usb_gadget_giveback_request)(void *, struct usb_ep *, struct usb_request *, int); - -struct input_mt_slot { - int abs[14]; - unsigned int frame; - unsigned int key; -}; - -struct input_mt { - int trkid; - int num_slots; - int slot; - unsigned int flags; - unsigned int frame; - int *red; - struct input_mt_slot slots[0]; -}; - -union input_seq_state { - struct { - short unsigned int pos; - bool mutex_acquired; - }; - void *p; -}; - -struct input_devres { - struct input_dev *input; -}; - -struct input_event { - __kernel_ulong_t __sec; - __kernel_ulong_t __usec; - __u16 type; - __u16 code; - __s32 value; -}; - -struct input_event_compat { - compat_ulong_t sec; - compat_ulong_t usec; - __u16 type; - __u16 code; - __s32 value; -}; - -struct ff_periodic_effect_compat { - __u16 waveform; - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; - struct ff_envelope envelope; - __u32 custom_len; - compat_uptr_t custom_data; -}; - -struct ff_effect_compat { - __u16 type; - __s16 id; - __u16 direction; - struct ff_trigger trigger; - struct ff_replay replay; - union { - struct ff_constant_effect constant; - struct ff_ramp_effect ramp; - struct ff_periodic_effect_compat periodic; - struct ff_condition_effect condition[2]; - struct ff_rumble_effect rumble; - } u; -}; - -struct input_mt_pos { - s16 x; - s16 y; -}; - -struct input_dev_poller { - void (*poll)(struct input_dev *); - unsigned int poll_interval; - unsigned int poll_interval_max; - unsigned int poll_interval_min; - struct input_dev *input; - struct delayed_work work; -}; - -struct input_led { - struct led_classdev cdev; - struct input_handle *handle; - unsigned int code; -}; - -struct input_leds { - struct input_handle handle; - unsigned int num_leds; - struct input_led leds[0]; -}; - -struct mousedev_hw_data { - int dx; - int dy; - int dz; - int x; - int y; - int abs_event; - long unsigned int buttons; -}; - -struct mousedev { - int open; - struct input_handle handle; - wait_queue_head_t wait; - struct list_head client_list; - spinlock_t client_lock; - struct mutex mutex; - struct device dev; - struct cdev cdev; - bool exist; - struct list_head mixdev_node; - bool opened_by_mixdev; - struct mousedev_hw_data packet; - unsigned int pkt_count; - int old_x[4]; - int old_y[4]; - int frac_dx; - int frac_dy; - long unsigned int touch; - int (*open_device)(struct mousedev *); - void (*close_device)(struct mousedev *); -}; - -enum mousedev_emul { - MOUSEDEV_EMUL_PS2 = 0, - MOUSEDEV_EMUL_IMPS = 1, - MOUSEDEV_EMUL_EXPS = 2, -}; - -struct mousedev_motion { - int dx; - int dy; - int dz; - long unsigned int buttons; -}; - -struct mousedev_client { - struct fasync_struct *fasync; - struct mousedev *mousedev; - struct list_head node; - struct mousedev_motion packets[16]; - unsigned int head; - unsigned int tail; - spinlock_t packet_lock; - int pos_x; - int pos_y; - u8 ps2[6]; - unsigned char ready; - unsigned char buffer; - unsigned char bufsiz; - unsigned char imexseq; - unsigned char impsseq; - enum mousedev_emul mode; - long unsigned int last_buttons; -}; - -enum { - FRACTION_DENOM = 128, -}; - -struct input_mask { - __u32 type; - __u32 codes_size; - __u64 codes_ptr; -}; - -struct evdev_client; - -struct evdev { - int open; - struct input_handle handle; - struct evdev_client *grab; - struct list_head client_list; - spinlock_t client_lock; - struct mutex mutex; - struct device dev; - struct cdev cdev; - bool exist; -}; - -struct evdev_client { - unsigned int head; - unsigned int tail; - unsigned int packet_head; - spinlock_t buffer_lock; - wait_queue_head_t wait; - struct fasync_struct *fasync; - struct evdev *evdev; - struct list_head node; - enum input_clock_type clk_type; - bool revoked; - long unsigned int *evmasks[32]; - unsigned int bufsize; - struct input_event buffer[0]; -}; - -struct touchscreen_properties { - unsigned int max_x; - unsigned int max_y; - bool invert_x; - bool invert_y; - bool swap_x_y; -}; - -struct trace_event_raw_rtc_time_alarm_class { - struct trace_entry ent; - time64_t secs; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_irq_set_freq { - struct trace_entry ent; - int freq; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_irq_set_state { - struct trace_entry ent; - int enabled; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_alarm_irq_enable { - struct trace_entry ent; - unsigned int enabled; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_offset_class { - struct trace_entry ent; - long int offset; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_timer_class { - struct trace_entry ent; - struct rtc_timer *timer; - ktime_t expires; - ktime_t period; - char __data[0]; -}; - -struct trace_event_data_offsets_rtc_time_alarm_class {}; - -struct trace_event_data_offsets_rtc_irq_set_freq {}; - -struct trace_event_data_offsets_rtc_irq_set_state {}; - -struct trace_event_data_offsets_rtc_alarm_irq_enable {}; - -struct trace_event_data_offsets_rtc_offset_class {}; - -struct trace_event_data_offsets_rtc_timer_class {}; - -typedef void (*btf_trace_rtc_set_time)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_read_time)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_set_alarm)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_read_alarm)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_irq_set_freq)(void *, int, int); - -typedef void (*btf_trace_rtc_irq_set_state)(void *, int, int); - -typedef void (*btf_trace_rtc_alarm_irq_enable)(void *, unsigned int, int); - -typedef void (*btf_trace_rtc_set_offset)(void *, long int, int); - -typedef void (*btf_trace_rtc_read_offset)(void *, long int, int); - -typedef void (*btf_trace_rtc_timer_enqueue)(void *, struct rtc_timer *); - -typedef void (*btf_trace_rtc_timer_dequeue)(void *, struct rtc_timer *); - -typedef void (*btf_trace_rtc_timer_fired)(void *, struct rtc_timer *); - -enum { - none = 0, - day = 1, - month = 2, - year = 3, -}; - -struct nvmem_cell_info { - const char *name; - unsigned int offset; - unsigned int bytes; - unsigned int bit_offset; - unsigned int nbits; -}; - -typedef int (*nvmem_reg_read_t)(void *, unsigned int, void *, size_t); - -typedef int (*nvmem_reg_write_t)(void *, unsigned int, void *, size_t); - -enum nvmem_type { - NVMEM_TYPE_UNKNOWN = 0, - NVMEM_TYPE_EEPROM = 1, - NVMEM_TYPE_OTP = 2, - NVMEM_TYPE_BATTERY_BACKED = 3, -}; - -struct nvmem_config { - struct device *dev; - const char *name; - int id; - struct module *owner; - struct gpio_desc *wp_gpio; - const struct nvmem_cell_info *cells; - int ncells; - enum nvmem_type type; - bool read_only; - bool root_only; - bool no_of_node; - nvmem_reg_read_t reg_read; - nvmem_reg_write_t reg_write; - int size; - int word_size; - int stride; - void *priv; - bool compat; - struct device *base_dev; -}; - -struct nvmem_device; - -struct i2c_devinfo { - struct list_head list; - int busnum; - struct i2c_board_info board_info; -}; - -struct i2c_device_identity { - u16 manufacturer_id; - u16 part_id; - u8 die_revision; -}; - -struct i2c_timings { - u32 bus_freq_hz; - u32 scl_rise_ns; - u32 scl_fall_ns; - u32 scl_int_delay_ns; - u32 sda_fall_ns; - u32 sda_hold_ns; - u32 digital_filter_width_ns; - u32 analog_filter_cutoff_freq_hz; -}; - -struct trace_event_raw_i2c_write { - struct trace_entry ent; - int adapter_nr; - __u16 msg_nr; - __u16 addr; - __u16 flags; - __u16 len; - u32 __data_loc_buf; - char __data[0]; -}; - -struct trace_event_raw_i2c_read { - struct trace_entry ent; - int adapter_nr; - __u16 msg_nr; - __u16 addr; - __u16 flags; - __u16 len; - char __data[0]; -}; - -struct trace_event_raw_i2c_reply { - struct trace_entry ent; - int adapter_nr; - __u16 msg_nr; - __u16 addr; - __u16 flags; - __u16 len; - u32 __data_loc_buf; - char __data[0]; -}; - -struct trace_event_raw_i2c_result { - struct trace_entry ent; - int adapter_nr; - __u16 nr_msgs; - __s16 ret; - char __data[0]; -}; - -struct trace_event_data_offsets_i2c_write { - u32 buf; -}; - -struct trace_event_data_offsets_i2c_read {}; - -struct trace_event_data_offsets_i2c_reply { - u32 buf; -}; - -struct trace_event_data_offsets_i2c_result {}; - -typedef void (*btf_trace_i2c_write)(void *, const struct i2c_adapter *, const struct i2c_msg *, int); - -typedef void (*btf_trace_i2c_read)(void *, const struct i2c_adapter *, const struct i2c_msg *, int); - -typedef void (*btf_trace_i2c_reply)(void *, const struct i2c_adapter *, const struct i2c_msg *, int); - -typedef void (*btf_trace_i2c_result)(void *, const struct i2c_adapter *, int, int); - -struct i2c_dummy_devres { - struct i2c_client *client; -}; - -struct class_compat___2; - -struct i2c_cmd_arg { - unsigned int cmd; - void *arg; -}; - -struct i2c_smbus_alert_setup { - int irq; -}; - -struct trace_event_raw_smbus_write { - struct trace_entry ent; - int adapter_nr; - __u16 addr; - __u16 flags; - __u8 command; - __u8 len; - __u32 protocol; - __u8 buf[34]; - char __data[0]; -}; - -struct trace_event_raw_smbus_read { - struct trace_entry ent; - int adapter_nr; - __u16 flags; - __u16 addr; - __u8 command; - __u32 protocol; - __u8 buf[34]; - char __data[0]; -}; - -struct trace_event_raw_smbus_reply { - struct trace_entry ent; - int adapter_nr; - __u16 addr; - __u16 flags; - __u8 command; - __u8 len; - __u32 protocol; - __u8 buf[34]; - char __data[0]; -}; - -struct trace_event_raw_smbus_result { - struct trace_entry ent; - int adapter_nr; - __u16 addr; - __u16 flags; - __u8 read_write; - __u8 command; - __s16 res; - __u32 protocol; - char __data[0]; -}; - -struct trace_event_data_offsets_smbus_write {}; - -struct trace_event_data_offsets_smbus_read {}; - -struct trace_event_data_offsets_smbus_reply {}; - -struct trace_event_data_offsets_smbus_result {}; - -typedef void (*btf_trace_smbus_write)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, const union i2c_smbus_data *); - -typedef void (*btf_trace_smbus_read)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int); - -typedef void (*btf_trace_smbus_reply)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, const union i2c_smbus_data *, int); - -typedef void (*btf_trace_smbus_result)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, int); - -enum rc_proto { - RC_PROTO_UNKNOWN = 0, - RC_PROTO_OTHER = 1, - RC_PROTO_RC5 = 2, - RC_PROTO_RC5X_20 = 3, - RC_PROTO_RC5_SZ = 4, - RC_PROTO_JVC = 5, - RC_PROTO_SONY12 = 6, - RC_PROTO_SONY15 = 7, - RC_PROTO_SONY20 = 8, - RC_PROTO_NEC = 9, - RC_PROTO_NECX = 10, - RC_PROTO_NEC32 = 11, - RC_PROTO_SANYO = 12, - RC_PROTO_MCIR2_KBD = 13, - RC_PROTO_MCIR2_MSE = 14, - RC_PROTO_RC6_0 = 15, - RC_PROTO_RC6_6A_20 = 16, - RC_PROTO_RC6_6A_24 = 17, - RC_PROTO_RC6_6A_32 = 18, - RC_PROTO_RC6_MCE = 19, - RC_PROTO_SHARP = 20, - RC_PROTO_XMP = 21, - RC_PROTO_CEC = 22, - RC_PROTO_IMON = 23, - RC_PROTO_RCMM12 = 24, - RC_PROTO_RCMM24 = 25, - RC_PROTO_RCMM32 = 26, - RC_PROTO_XBOX_DVD = 27, -}; - -struct rc_map_table { - u64 scancode; - u32 keycode; -}; - -struct rc_map { - struct rc_map_table *scan; - unsigned int size; - unsigned int len; - unsigned int alloc; - enum rc_proto rc_proto; - const char *name; - spinlock_t lock; -}; - -struct rc_map_list { - struct list_head list; - struct rc_map map; -}; - -struct lirc_scancode { - __u64 timestamp; - __u16 flags; - __u16 rc_proto; - __u32 keycode; - __u64 scancode; -}; - -enum rc_driver_type { - RC_DRIVER_SCANCODE = 0, - RC_DRIVER_IR_RAW = 1, - RC_DRIVER_IR_RAW_TX = 2, -}; - -struct rc_scancode_filter { - u32 data; - u32 mask; -}; - -enum rc_filter_type { - RC_FILTER_NORMAL = 0, - RC_FILTER_WAKEUP = 1, - RC_FILTER_MAX = 2, -}; - -struct ir_raw_event_ctrl; - -struct rc_dev { - struct device dev; - bool managed_alloc; - const struct attribute_group *sysfs_groups[5]; - const char *device_name; - const char *input_phys; - struct input_id input_id; - const char *driver_name; - const char *map_name; - struct rc_map rc_map; - struct mutex lock; - unsigned int minor; - struct ir_raw_event_ctrl *raw; - struct input_dev *input_dev; - enum rc_driver_type driver_type; - bool idle; - bool encode_wakeup; - u64 allowed_protocols; - u64 enabled_protocols; - u64 allowed_wakeup_protocols; - enum rc_proto wakeup_protocol; - struct rc_scancode_filter scancode_filter; - struct rc_scancode_filter scancode_wakeup_filter; - u32 scancode_mask; - u32 users; - void *priv; - spinlock_t keylock; - bool keypressed; - long unsigned int keyup_jiffies; - struct timer_list timer_keyup; - struct timer_list timer_repeat; - u32 last_keycode; - enum rc_proto last_protocol; - u64 last_scancode; - u8 last_toggle; - u32 timeout; - u32 min_timeout; - u32 max_timeout; - u32 rx_resolution; - u32 tx_resolution; - struct device lirc_dev; - struct cdev lirc_cdev; - ktime_t gap_start; - u64 gap_duration; - bool gap; - spinlock_t lirc_fh_lock; - struct list_head lirc_fh; - bool registered; - int (*change_protocol)(struct rc_dev *, u64 *); - int (*open)(struct rc_dev *); - void (*close)(struct rc_dev *); - int (*s_tx_mask)(struct rc_dev *, u32); - int (*s_tx_carrier)(struct rc_dev *, u32); - int (*s_tx_duty_cycle)(struct rc_dev *, u32); - int (*s_rx_carrier_range)(struct rc_dev *, u32, u32); - int (*tx_ir)(struct rc_dev *, unsigned int *, unsigned int); - void (*s_idle)(struct rc_dev *, bool); - int (*s_learning_mode)(struct rc_dev *, int); - int (*s_carrier_report)(struct rc_dev *, int); - int (*s_filter)(struct rc_dev *, struct rc_scancode_filter *); - int (*s_wakeup_filter)(struct rc_dev *, struct rc_scancode_filter *); - int (*s_timeout)(struct rc_dev *, unsigned int); -}; - -struct ir_raw_event { - union { - u32 duration; - u32 carrier; - }; - u8 duty_cycle; - unsigned int pulse: 1; - unsigned int reset: 1; - unsigned int timeout: 1; - unsigned int carrier_report: 1; -}; - -struct nec_dec { - int state; - unsigned int count; - u32 bits; - bool is_nec_x; - bool necx_repeat; -}; - -struct rc5_dec { - int state; - u32 bits; - unsigned int count; - bool is_rc5x; -}; - -struct rc6_dec { - int state; - u8 header; - u32 body; - bool toggle; - unsigned int count; - unsigned int wanted_bits; -}; - -struct sony_dec { - int state; - u32 bits; - unsigned int count; -}; - -struct jvc_dec { - int state; - u16 bits; - u16 old_bits; - unsigned int count; - bool first; - bool toggle; -}; - -struct sanyo_dec { - int state; - unsigned int count; - u64 bits; -}; - -struct sharp_dec { - int state; - unsigned int count; - u32 bits; - unsigned int pulse_len; -}; - -struct mce_kbd_dec { - spinlock_t keylock; - struct timer_list rx_timeout; - int state; - u8 header; - u32 body; - unsigned int count; - unsigned int wanted_bits; -}; - -struct xmp_dec { - int state; - unsigned int count; - u32 durations[16]; -}; - -struct imon_dec { - int state; - int count; - int last_chk; - unsigned int bits; - bool stick_keyboard; -}; - -struct ir_raw_event_ctrl { - struct list_head list; - struct task_struct *thread; - struct { - union { - struct __kfifo kfifo; - struct ir_raw_event *type; - const struct ir_raw_event *const_type; - char (*rectype)[0]; - struct ir_raw_event *ptr; - const struct ir_raw_event *ptr_const; - }; - struct ir_raw_event buf[512]; - } kfifo; - ktime_t last_event; - struct rc_dev *dev; - spinlock_t edge_spinlock; - struct timer_list edge_handle; - struct ir_raw_event prev_ev; - struct ir_raw_event this_ev; - u32 bpf_sample; - struct bpf_prog_array *progs; - struct nec_dec nec; - struct rc5_dec rc5; - struct rc6_dec rc6; - struct sony_dec sony; - struct jvc_dec jvc; - struct sanyo_dec sanyo; - struct sharp_dec sharp; - struct mce_kbd_dec mce_kbd; - struct xmp_dec xmp; - struct imon_dec imon; -}; - -struct rc_filter_attribute { - struct device_attribute attr; - enum rc_filter_type type; - bool mask; -}; - -struct ir_raw_handler { - struct list_head list; - u64 protocols; - int (*decode)(struct rc_dev *, struct ir_raw_event); - int (*encode)(enum rc_proto, u32, struct ir_raw_event *, unsigned int); - u32 carrier; - u32 min_timeout; - int (*raw_register)(struct rc_dev *); - int (*raw_unregister)(struct rc_dev *); -}; - -struct ir_raw_timings_manchester { - unsigned int leader_pulse; - unsigned int leader_space; - unsigned int clock; - unsigned int invert: 1; - unsigned int trailer_space; -}; - -struct ir_raw_timings_pd { - unsigned int header_pulse; - unsigned int header_space; - unsigned int bit_pulse; - unsigned int bit_space[2]; - unsigned int trailer_pulse; - unsigned int trailer_space; - unsigned int msb_first: 1; -}; - -struct ir_raw_timings_pl { - unsigned int header_pulse; - unsigned int bit_space; - unsigned int bit_pulse[2]; - unsigned int trailer_space; - unsigned int msb_first: 1; -}; - -struct lirc_fh { - struct list_head list; - struct rc_dev *rc; - int carrier_low; - bool send_timeout_reports; - struct { - union { - struct __kfifo kfifo; - unsigned int *type; - const unsigned int *const_type; - char (*rectype)[0]; - unsigned int *ptr; - const unsigned int *ptr_const; - }; - unsigned int buf[0]; - } rawir; - struct { - union { - struct __kfifo kfifo; - struct lirc_scancode *type; - const struct lirc_scancode *const_type; - char (*rectype)[0]; - struct lirc_scancode *ptr; - const struct lirc_scancode *ptr_const; - }; - struct lirc_scancode buf[0]; - } scancodes; - wait_queue_head_t wait_poll; - u8 send_mode; - u8 rec_mode; -}; - -typedef u64 (*btf_bpf_rc_repeat)(u32 *); - -typedef u64 (*btf_bpf_rc_keydown)(u32 *, u32, u64, u32); - -typedef u64 (*btf_bpf_rc_pointer_rel)(u32 *, s32, s32); - -enum power_supply_property { - POWER_SUPPLY_PROP_STATUS = 0, - POWER_SUPPLY_PROP_CHARGE_TYPE = 1, - POWER_SUPPLY_PROP_HEALTH = 2, - POWER_SUPPLY_PROP_PRESENT = 3, - POWER_SUPPLY_PROP_ONLINE = 4, - POWER_SUPPLY_PROP_AUTHENTIC = 5, - POWER_SUPPLY_PROP_TECHNOLOGY = 6, - POWER_SUPPLY_PROP_CYCLE_COUNT = 7, - POWER_SUPPLY_PROP_VOLTAGE_MAX = 8, - POWER_SUPPLY_PROP_VOLTAGE_MIN = 9, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN = 10, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN = 11, - POWER_SUPPLY_PROP_VOLTAGE_NOW = 12, - POWER_SUPPLY_PROP_VOLTAGE_AVG = 13, - POWER_SUPPLY_PROP_VOLTAGE_OCV = 14, - POWER_SUPPLY_PROP_VOLTAGE_BOOT = 15, - POWER_SUPPLY_PROP_CURRENT_MAX = 16, - POWER_SUPPLY_PROP_CURRENT_NOW = 17, - POWER_SUPPLY_PROP_CURRENT_AVG = 18, - POWER_SUPPLY_PROP_CURRENT_BOOT = 19, - POWER_SUPPLY_PROP_POWER_NOW = 20, - POWER_SUPPLY_PROP_POWER_AVG = 21, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN = 22, - POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN = 23, - POWER_SUPPLY_PROP_CHARGE_FULL = 24, - POWER_SUPPLY_PROP_CHARGE_EMPTY = 25, - POWER_SUPPLY_PROP_CHARGE_NOW = 26, - POWER_SUPPLY_PROP_CHARGE_AVG = 27, - POWER_SUPPLY_PROP_CHARGE_COUNTER = 28, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT = 29, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX = 30, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE = 31, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX = 32, - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT = 33, - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX = 34, - POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD = 35, - POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD = 36, - POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT = 37, - POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT = 38, - POWER_SUPPLY_PROP_INPUT_POWER_LIMIT = 39, - POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN = 40, - POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN = 41, - POWER_SUPPLY_PROP_ENERGY_FULL = 42, - POWER_SUPPLY_PROP_ENERGY_EMPTY = 43, - POWER_SUPPLY_PROP_ENERGY_NOW = 44, - POWER_SUPPLY_PROP_ENERGY_AVG = 45, - POWER_SUPPLY_PROP_CAPACITY = 46, - POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN = 47, - POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX = 48, - POWER_SUPPLY_PROP_CAPACITY_ERROR_MARGIN = 49, - POWER_SUPPLY_PROP_CAPACITY_LEVEL = 50, - POWER_SUPPLY_PROP_TEMP = 51, - POWER_SUPPLY_PROP_TEMP_MAX = 52, - POWER_SUPPLY_PROP_TEMP_MIN = 53, - POWER_SUPPLY_PROP_TEMP_ALERT_MIN = 54, - POWER_SUPPLY_PROP_TEMP_ALERT_MAX = 55, - POWER_SUPPLY_PROP_TEMP_AMBIENT = 56, - POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN = 57, - POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX = 58, - POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW = 59, - POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG = 60, - POWER_SUPPLY_PROP_TIME_TO_FULL_NOW = 61, - POWER_SUPPLY_PROP_TIME_TO_FULL_AVG = 62, - POWER_SUPPLY_PROP_TYPE = 63, - POWER_SUPPLY_PROP_USB_TYPE = 64, - POWER_SUPPLY_PROP_SCOPE = 65, - POWER_SUPPLY_PROP_PRECHARGE_CURRENT = 66, - POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT = 67, - POWER_SUPPLY_PROP_CALIBRATE = 68, - POWER_SUPPLY_PROP_MANUFACTURE_YEAR = 69, - POWER_SUPPLY_PROP_MANUFACTURE_MONTH = 70, - POWER_SUPPLY_PROP_MANUFACTURE_DAY = 71, - POWER_SUPPLY_PROP_MODEL_NAME = 72, - POWER_SUPPLY_PROP_MANUFACTURER = 73, - POWER_SUPPLY_PROP_SERIAL_NUMBER = 74, -}; - -enum power_supply_type { - POWER_SUPPLY_TYPE_UNKNOWN = 0, - POWER_SUPPLY_TYPE_BATTERY = 1, - POWER_SUPPLY_TYPE_UPS = 2, - POWER_SUPPLY_TYPE_MAINS = 3, - POWER_SUPPLY_TYPE_USB = 4, - POWER_SUPPLY_TYPE_USB_DCP = 5, - POWER_SUPPLY_TYPE_USB_CDP = 6, - POWER_SUPPLY_TYPE_USB_ACA = 7, - POWER_SUPPLY_TYPE_USB_TYPE_C = 8, - POWER_SUPPLY_TYPE_USB_PD = 9, - POWER_SUPPLY_TYPE_USB_PD_DRP = 10, - POWER_SUPPLY_TYPE_APPLE_BRICK_ID = 11, - POWER_SUPPLY_TYPE_WIRELESS = 12, -}; - -enum power_supply_usb_type { - POWER_SUPPLY_USB_TYPE_UNKNOWN = 0, - POWER_SUPPLY_USB_TYPE_SDP = 1, - POWER_SUPPLY_USB_TYPE_DCP = 2, - POWER_SUPPLY_USB_TYPE_CDP = 3, - POWER_SUPPLY_USB_TYPE_ACA = 4, - POWER_SUPPLY_USB_TYPE_C = 5, - POWER_SUPPLY_USB_TYPE_PD = 6, - POWER_SUPPLY_USB_TYPE_PD_DRP = 7, - POWER_SUPPLY_USB_TYPE_PD_PPS = 8, - POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID = 9, -}; - -enum power_supply_notifier_events { - PSY_EVENT_PROP_CHANGED = 0, -}; - -union power_supply_propval { - int intval; - const char *strval; -}; - -struct power_supply_config { - struct device_node *of_node; - struct fwnode_handle *fwnode; - void *drv_data; - const struct attribute_group **attr_grp; - char **supplied_to; - size_t num_supplicants; -}; - -struct power_supply; - -struct power_supply_desc { - const char *name; - enum power_supply_type type; - const enum power_supply_usb_type *usb_types; - size_t num_usb_types; - const enum power_supply_property *properties; - size_t num_properties; - int (*get_property)(struct power_supply *, enum power_supply_property, union power_supply_propval *); - int (*set_property)(struct power_supply *, enum power_supply_property, const union power_supply_propval *); - int (*property_is_writeable)(struct power_supply *, enum power_supply_property); - void (*external_power_changed)(struct power_supply *); - void (*set_charged)(struct power_supply *); - bool no_thermal; - int use_for_apm; -}; - -struct thermal_zone_device; - -struct power_supply { - const struct power_supply_desc *desc; - char **supplied_to; - size_t num_supplicants; - char **supplied_from; - size_t num_supplies; - struct device_node *of_node; - void *drv_data; - struct device dev; - struct work_struct changed_work; - struct delayed_work deferred_register_work; - spinlock_t changed_lock; - bool changed; - bool initialized; - bool removing; - atomic_t use_cnt; - struct thermal_zone_device *tzd; - struct thermal_cooling_device *tcd; - struct led_trigger *charging_full_trig; - char *charging_full_trig_name; - struct led_trigger *charging_trig; - char *charging_trig_name; - struct led_trigger *full_trig; - char *full_trig_name; - struct led_trigger *online_trig; - char *online_trig_name; - struct led_trigger *charging_blink_full_solid_trig; - char *charging_blink_full_solid_trig_name; -}; - -enum thermal_device_mode { - THERMAL_DEVICE_DISABLED = 0, - THERMAL_DEVICE_ENABLED = 1, -}; - -enum thermal_notify_event { - THERMAL_EVENT_UNSPECIFIED = 0, - THERMAL_EVENT_TEMP_SAMPLE = 1, - THERMAL_TRIP_VIOLATED = 2, - THERMAL_TRIP_CHANGED = 3, - THERMAL_DEVICE_DOWN = 4, - THERMAL_DEVICE_UP = 5, - THERMAL_DEVICE_POWER_CAPABILITY_CHANGED = 6, - THERMAL_TABLE_CHANGED = 7, - THERMAL_EVENT_KEEP_ALIVE = 8, -}; - -struct thermal_attr; - -struct thermal_zone_device_ops; - -struct thermal_zone_params; - -struct thermal_governor; - -struct thermal_zone_device { - int id; - char type[20]; - struct device device; - struct attribute_group trips_attribute_group; - struct thermal_attr *trip_temp_attrs; - struct thermal_attr *trip_type_attrs; - struct thermal_attr *trip_hyst_attrs; - enum thermal_device_mode mode; - void *devdata; - int trips; - long unsigned int trips_disabled; - int passive_delay; - int polling_delay; - int temperature; - int last_temperature; - int emul_temperature; - int passive; - int prev_low_trip; - int prev_high_trip; - unsigned int forced_passive; - atomic_t need_update; - struct thermal_zone_device_ops *ops; - struct thermal_zone_params *tzp; - struct thermal_governor *governor; - void *governor_data; - struct list_head thermal_instances; - struct ida ida; - struct mutex lock; - struct list_head node; - struct delayed_work poll_queue; - enum thermal_notify_event notify_event; -}; - -struct thermal_cooling_device_ops; - -struct thermal_cooling_device { - int id; - char type[20]; - struct device device; - struct device_node *np; - void *devdata; - void *stats; - const struct thermal_cooling_device_ops *ops; - bool updated; - struct mutex lock; - struct list_head thermal_instances; - struct list_head node; -}; - -struct power_supply_battery_ocv_table { - int ocv; - int capacity; -}; - -struct power_supply_resistance_temp_table { - int temp; - int resistance; -}; - -struct power_supply_battery_info { - int energy_full_design_uwh; - int charge_full_design_uah; - int voltage_min_design_uv; - int voltage_max_design_uv; - int tricklecharge_current_ua; - int precharge_current_ua; - int precharge_voltage_max_uv; - int charge_term_current_ua; - int charge_restart_voltage_uv; - int overvoltage_limit_uv; - int constant_charge_current_max_ua; - int constant_charge_voltage_max_uv; - int factory_internal_resistance_uohm; - int ocv_temp[20]; - int temp_ambient_alert_min; - int temp_ambient_alert_max; - int temp_alert_min; - int temp_alert_max; - int temp_min; - int temp_max; - struct power_supply_battery_ocv_table *ocv_table[20]; - int ocv_table_size[20]; - struct power_supply_resistance_temp_table *resist_table; - int resist_table_size; -}; - -enum thermal_trip_type { - THERMAL_TRIP_ACTIVE = 0, - THERMAL_TRIP_PASSIVE = 1, - THERMAL_TRIP_HOT = 2, - THERMAL_TRIP_CRITICAL = 3, -}; - -enum thermal_trend { - THERMAL_TREND_STABLE = 0, - THERMAL_TREND_RAISING = 1, - THERMAL_TREND_DROPPING = 2, - THERMAL_TREND_RAISE_FULL = 3, - THERMAL_TREND_DROP_FULL = 4, -}; - -struct thermal_zone_device_ops { - int (*bind)(struct thermal_zone_device *, struct thermal_cooling_device *); - int (*unbind)(struct thermal_zone_device *, struct thermal_cooling_device *); - int (*get_temp)(struct thermal_zone_device *, int *); - int (*set_trips)(struct thermal_zone_device *, int, int); - int (*change_mode)(struct thermal_zone_device *, enum thermal_device_mode); - int (*get_trip_type)(struct thermal_zone_device *, int, enum thermal_trip_type *); - int (*get_trip_temp)(struct thermal_zone_device *, int, int *); - int (*set_trip_temp)(struct thermal_zone_device *, int, int); - int (*get_trip_hyst)(struct thermal_zone_device *, int, int *); - int (*set_trip_hyst)(struct thermal_zone_device *, int, int); - int (*get_crit_temp)(struct thermal_zone_device *, int *); - int (*set_emul_temp)(struct thermal_zone_device *, int); - int (*get_trend)(struct thermal_zone_device *, int, enum thermal_trend *); - int (*notify)(struct thermal_zone_device *, int, enum thermal_trip_type); -}; - -struct thermal_cooling_device_ops { - int (*get_max_state)(struct thermal_cooling_device *, long unsigned int *); - int (*get_cur_state)(struct thermal_cooling_device *, long unsigned int *); - int (*set_cur_state)(struct thermal_cooling_device *, long unsigned int); - int (*get_requested_power)(struct thermal_cooling_device *, u32 *); - int (*state2power)(struct thermal_cooling_device *, long unsigned int, u32 *); - int (*power2state)(struct thermal_cooling_device *, u32, long unsigned int *); -}; - -struct thermal_bind_params; - -struct thermal_zone_params { - char governor_name[20]; - bool no_hwmon; - int num_tbps; - struct thermal_bind_params *tbp; - u32 sustainable_power; - s32 k_po; - s32 k_pu; - s32 k_i; - s32 k_d; - s32 integral_cutoff; - int slope; - int offset; -}; - -struct thermal_governor { - char name[20]; - int (*bind_to_tz)(struct thermal_zone_device *); - void (*unbind_from_tz)(struct thermal_zone_device *); - int (*throttle)(struct thermal_zone_device *, int); - struct list_head governor_list; -}; - -struct thermal_bind_params { - struct thermal_cooling_device *cdev; - int weight; - int trip_mask; - long unsigned int *binding_limits; - int (*match)(struct thermal_zone_device *, struct thermal_cooling_device *); -}; - -struct psy_am_i_supplied_data { - struct power_supply *psy; - unsigned int count; -}; - -enum { - POWER_SUPPLY_STATUS_UNKNOWN = 0, - POWER_SUPPLY_STATUS_CHARGING = 1, - POWER_SUPPLY_STATUS_DISCHARGING = 2, - POWER_SUPPLY_STATUS_NOT_CHARGING = 3, - POWER_SUPPLY_STATUS_FULL = 4, -}; - -enum { - POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0, - POWER_SUPPLY_CHARGE_TYPE_NONE = 1, - POWER_SUPPLY_CHARGE_TYPE_TRICKLE = 2, - POWER_SUPPLY_CHARGE_TYPE_FAST = 3, - POWER_SUPPLY_CHARGE_TYPE_STANDARD = 4, - POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE = 5, - POWER_SUPPLY_CHARGE_TYPE_CUSTOM = 6, - POWER_SUPPLY_CHARGE_TYPE_LONGLIFE = 7, -}; - -enum { - POWER_SUPPLY_HEALTH_UNKNOWN = 0, - POWER_SUPPLY_HEALTH_GOOD = 1, - POWER_SUPPLY_HEALTH_OVERHEAT = 2, - POWER_SUPPLY_HEALTH_DEAD = 3, - POWER_SUPPLY_HEALTH_OVERVOLTAGE = 4, - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5, - POWER_SUPPLY_HEALTH_COLD = 6, - POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7, - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8, - POWER_SUPPLY_HEALTH_OVERCURRENT = 9, - POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED = 10, - POWER_SUPPLY_HEALTH_WARM = 11, - POWER_SUPPLY_HEALTH_COOL = 12, - POWER_SUPPLY_HEALTH_HOT = 13, -}; - -enum { - POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0, - POWER_SUPPLY_TECHNOLOGY_NiMH = 1, - POWER_SUPPLY_TECHNOLOGY_LION = 2, - POWER_SUPPLY_TECHNOLOGY_LIPO = 3, - POWER_SUPPLY_TECHNOLOGY_LiFe = 4, - POWER_SUPPLY_TECHNOLOGY_NiCd = 5, - POWER_SUPPLY_TECHNOLOGY_LiMn = 6, -}; - -enum { - POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0, - POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL = 1, - POWER_SUPPLY_CAPACITY_LEVEL_LOW = 2, - POWER_SUPPLY_CAPACITY_LEVEL_NORMAL = 3, - POWER_SUPPLY_CAPACITY_LEVEL_HIGH = 4, - POWER_SUPPLY_CAPACITY_LEVEL_FULL = 5, -}; - -enum { - POWER_SUPPLY_SCOPE_UNKNOWN = 0, - POWER_SUPPLY_SCOPE_SYSTEM = 1, - POWER_SUPPLY_SCOPE_DEVICE = 2, -}; - -struct power_supply_attr { - const char *prop_name; - char attr_name[31]; - struct device_attribute dev_attr; - const char * const *text_values; - int text_values_len; -}; - -enum hwmon_sensor_types { - hwmon_chip = 0, - hwmon_temp = 1, - hwmon_in = 2, - hwmon_curr = 3, - hwmon_power = 4, - hwmon_energy = 5, - hwmon_humidity = 6, - hwmon_fan = 7, - hwmon_pwm = 8, - hwmon_intrusion = 9, - hwmon_max = 10, -}; - -enum hwmon_temp_attributes { - hwmon_temp_enable = 0, - hwmon_temp_input = 1, - hwmon_temp_type = 2, - hwmon_temp_lcrit = 3, - hwmon_temp_lcrit_hyst = 4, - hwmon_temp_min = 5, - hwmon_temp_min_hyst = 6, - hwmon_temp_max = 7, - hwmon_temp_max_hyst = 8, - hwmon_temp_crit = 9, - hwmon_temp_crit_hyst = 10, - hwmon_temp_emergency = 11, - hwmon_temp_emergency_hyst = 12, - hwmon_temp_alarm = 13, - hwmon_temp_lcrit_alarm = 14, - hwmon_temp_min_alarm = 15, - hwmon_temp_max_alarm = 16, - hwmon_temp_crit_alarm = 17, - hwmon_temp_emergency_alarm = 18, - hwmon_temp_fault = 19, - hwmon_temp_offset = 20, - hwmon_temp_label = 21, - hwmon_temp_lowest = 22, - hwmon_temp_highest = 23, - hwmon_temp_reset_history = 24, - hwmon_temp_rated_min = 25, - hwmon_temp_rated_max = 26, -}; - -enum hwmon_in_attributes { - hwmon_in_enable = 0, - hwmon_in_input = 1, - hwmon_in_min = 2, - hwmon_in_max = 3, - hwmon_in_lcrit = 4, - hwmon_in_crit = 5, - hwmon_in_average = 6, - hwmon_in_lowest = 7, - hwmon_in_highest = 8, - hwmon_in_reset_history = 9, - hwmon_in_label = 10, - hwmon_in_alarm = 11, - hwmon_in_min_alarm = 12, - hwmon_in_max_alarm = 13, - hwmon_in_lcrit_alarm = 14, - hwmon_in_crit_alarm = 15, - hwmon_in_rated_min = 16, - hwmon_in_rated_max = 17, -}; - -enum hwmon_curr_attributes { - hwmon_curr_enable = 0, - hwmon_curr_input = 1, - hwmon_curr_min = 2, - hwmon_curr_max = 3, - hwmon_curr_lcrit = 4, - hwmon_curr_crit = 5, - hwmon_curr_average = 6, - hwmon_curr_lowest = 7, - hwmon_curr_highest = 8, - hwmon_curr_reset_history = 9, - hwmon_curr_label = 10, - hwmon_curr_alarm = 11, - hwmon_curr_min_alarm = 12, - hwmon_curr_max_alarm = 13, - hwmon_curr_lcrit_alarm = 14, - hwmon_curr_crit_alarm = 15, - hwmon_curr_rated_min = 16, - hwmon_curr_rated_max = 17, -}; - -struct hwmon_ops { - umode_t (*is_visible)(const void *, enum hwmon_sensor_types, u32, int); - int (*read)(struct device *, enum hwmon_sensor_types, u32, int, long int *); - int (*read_string)(struct device *, enum hwmon_sensor_types, u32, int, const char **); - int (*write)(struct device *, enum hwmon_sensor_types, u32, int, long int); -}; - -struct hwmon_channel_info { - enum hwmon_sensor_types type; - const u32 *config; -}; - -struct hwmon_chip_info { - const struct hwmon_ops *ops; - const struct hwmon_channel_info **info; -}; - -struct power_supply_hwmon { - struct power_supply *psy; - long unsigned int *props; -}; - -struct hwmon_type_attr_list { - const u32 *attrs; - size_t n_attrs; -}; - -enum hwmon_chip_attributes { - hwmon_chip_temp_reset_history = 0, - hwmon_chip_in_reset_history = 1, - hwmon_chip_curr_reset_history = 2, - hwmon_chip_power_reset_history = 3, - hwmon_chip_register_tz = 4, - hwmon_chip_update_interval = 5, - hwmon_chip_alarms = 6, - hwmon_chip_samples = 7, - hwmon_chip_curr_samples = 8, - hwmon_chip_in_samples = 9, - hwmon_chip_power_samples = 10, - hwmon_chip_temp_samples = 11, -}; - -enum hwmon_power_attributes { - hwmon_power_enable = 0, - hwmon_power_average = 1, - hwmon_power_average_interval = 2, - hwmon_power_average_interval_max = 3, - hwmon_power_average_interval_min = 4, - hwmon_power_average_highest = 5, - hwmon_power_average_lowest = 6, - hwmon_power_average_max = 7, - hwmon_power_average_min = 8, - hwmon_power_input = 9, - hwmon_power_input_highest = 10, - hwmon_power_input_lowest = 11, - hwmon_power_reset_history = 12, - hwmon_power_accuracy = 13, - hwmon_power_cap = 14, - hwmon_power_cap_hyst = 15, - hwmon_power_cap_max = 16, - hwmon_power_cap_min = 17, - hwmon_power_min = 18, - hwmon_power_max = 19, - hwmon_power_crit = 20, - hwmon_power_lcrit = 21, - hwmon_power_label = 22, - hwmon_power_alarm = 23, - hwmon_power_cap_alarm = 24, - hwmon_power_min_alarm = 25, - hwmon_power_max_alarm = 26, - hwmon_power_lcrit_alarm = 27, - hwmon_power_crit_alarm = 28, - hwmon_power_rated_min = 29, - hwmon_power_rated_max = 30, -}; - -enum hwmon_energy_attributes { - hwmon_energy_enable = 0, - hwmon_energy_input = 1, - hwmon_energy_label = 2, -}; - -enum hwmon_humidity_attributes { - hwmon_humidity_enable = 0, - hwmon_humidity_input = 1, - hwmon_humidity_label = 2, - hwmon_humidity_min = 3, - hwmon_humidity_min_hyst = 4, - hwmon_humidity_max = 5, - hwmon_humidity_max_hyst = 6, - hwmon_humidity_alarm = 7, - hwmon_humidity_fault = 8, - hwmon_humidity_rated_min = 9, - hwmon_humidity_rated_max = 10, -}; - -enum hwmon_fan_attributes { - hwmon_fan_enable = 0, - hwmon_fan_input = 1, - hwmon_fan_label = 2, - hwmon_fan_min = 3, - hwmon_fan_max = 4, - hwmon_fan_div = 5, - hwmon_fan_pulses = 6, - hwmon_fan_target = 7, - hwmon_fan_alarm = 8, - hwmon_fan_min_alarm = 9, - hwmon_fan_max_alarm = 10, - hwmon_fan_fault = 11, -}; - -enum hwmon_pwm_attributes { - hwmon_pwm_input = 0, - hwmon_pwm_enable = 1, - hwmon_pwm_mode = 2, - hwmon_pwm_freq = 3, -}; - -enum hwmon_intrusion_attributes { - hwmon_intrusion_alarm = 0, - hwmon_intrusion_beep = 1, -}; - -struct thermal_zone_of_device_ops { - int (*get_temp)(void *, int *); - int (*get_trend)(void *, int, enum thermal_trend *); - int (*set_trips)(void *, int, int); - int (*set_emul_temp)(void *, int); - int (*set_trip_temp)(void *, int, int); -}; - -struct trace_event_raw_hwmon_attr_class { - struct trace_entry ent; - int index; - u32 __data_loc_attr_name; - long int val; - char __data[0]; -}; - -struct trace_event_raw_hwmon_attr_show_string { - struct trace_entry ent; - int index; - u32 __data_loc_attr_name; - u32 __data_loc_label; - char __data[0]; -}; - -struct trace_event_data_offsets_hwmon_attr_class { - u32 attr_name; -}; - -struct trace_event_data_offsets_hwmon_attr_show_string { - u32 attr_name; - u32 label; -}; - -typedef void (*btf_trace_hwmon_attr_show)(void *, int, const char *, long int); - -typedef void (*btf_trace_hwmon_attr_store)(void *, int, const char *, long int); - -typedef void (*btf_trace_hwmon_attr_show_string)(void *, int, const char *, const char *); - -struct hwmon_device { - const char *name; - struct device dev; - const struct hwmon_chip_info *chip; - struct list_head tzdata; - struct attribute_group group; - const struct attribute_group **groups; -}; - -struct hwmon_device_attribute { - struct device_attribute dev_attr; - const struct hwmon_ops *ops; - enum hwmon_sensor_types type; - u32 attr; - int index; - char name[32]; -}; - -struct hwmon_thermal_data { - struct list_head node; - struct device *dev; - int index; - struct thermal_zone_device *tzd; -}; - -struct thermal_attr { - struct device_attribute attr; - char name[20]; -}; - -struct trace_event_raw_thermal_temperature { - struct trace_entry ent; - u32 __data_loc_thermal_zone; - int id; - int temp_prev; - int temp; - char __data[0]; -}; - -struct trace_event_raw_cdev_update { - struct trace_entry ent; - u32 __data_loc_type; - long unsigned int target; - char __data[0]; -}; - -struct trace_event_raw_thermal_zone_trip { - struct trace_entry ent; - u32 __data_loc_thermal_zone; - int id; - int trip; - enum thermal_trip_type trip_type; - char __data[0]; -}; - -struct trace_event_data_offsets_thermal_temperature { - u32 thermal_zone; -}; - -struct trace_event_data_offsets_cdev_update { - u32 type; -}; - -struct trace_event_data_offsets_thermal_zone_trip { - u32 thermal_zone; -}; - -typedef void (*btf_trace_thermal_temperature)(void *, struct thermal_zone_device *); - -typedef void (*btf_trace_cdev_update)(void *, struct thermal_cooling_device *, long unsigned int); - -typedef void (*btf_trace_thermal_zone_trip)(void *, struct thermal_zone_device *, int, enum thermal_trip_type); - -struct thermal_instance { - int id; - char name[20]; - struct thermal_zone_device *tz; - struct thermal_cooling_device *cdev; - int trip; - bool initialized; - long unsigned int upper; - long unsigned int lower; - long unsigned int target; - char attr_name[20]; - struct device_attribute attr; - char weight_attr_name[20]; - struct device_attribute weight_attr; - struct list_head tz_node; - struct list_head cdev_node; - unsigned int weight; -}; - -struct thermal_hwmon_device { - char type[20]; - struct device *device; - int count; - struct list_head tz_list; - struct list_head node; -}; - -struct thermal_hwmon_attr { - struct device_attribute attr; - char name[16]; -}; - -struct thermal_hwmon_temp { - struct list_head hwmon_node; - struct thermal_zone_device *tz; - struct thermal_hwmon_attr temp_input; - struct thermal_hwmon_attr temp_crit; -}; - -struct thermal_trip { - struct device_node *np; - int temperature; - int hysteresis; - enum thermal_trip_type type; -}; - -struct __thermal_cooling_bind_param { - struct device_node *cooling_device; - long unsigned int min; - long unsigned int max; -}; - -struct __thermal_bind_params { - struct __thermal_cooling_bind_param *tcbp; - unsigned int count; - unsigned int trip_id; - unsigned int usage; -}; - -struct __thermal_zone { - int passive_delay; - int polling_delay; - int slope; - int offset; - int ntrips; - struct thermal_trip *trips; - int num_tbps; - struct __thermal_bind_params *tbps; - void *sensor_data; - const struct thermal_zone_of_device_ops *ops; -}; - -struct bcm2711_thermal_priv { - struct regmap *regmap; - struct thermal_zone_device *thermal; -}; - -struct bcm2835_thermal_data { - struct thermal_zone_device *tz; - void *regs; - struct clk *clk; - struct dentry *debugfsdir; -}; - -struct watchdog_info { - __u32 options; - __u32 firmware_version; - __u8 identity[32]; -}; - -struct watchdog_device; - -struct watchdog_ops { - struct module *owner; - int (*start)(struct watchdog_device *); - int (*stop)(struct watchdog_device *); - int (*ping)(struct watchdog_device *); - unsigned int (*status)(struct watchdog_device *); - int (*set_timeout)(struct watchdog_device *, unsigned int); - int (*set_pretimeout)(struct watchdog_device *, unsigned int); - unsigned int (*get_timeleft)(struct watchdog_device *); - int (*restart)(struct watchdog_device *, long unsigned int, void *); - long int (*ioctl)(struct watchdog_device *, unsigned int, long unsigned int); -}; - -struct watchdog_governor; - -struct watchdog_core_data; - -struct watchdog_device { - int id; - struct device *parent; - const struct attribute_group **groups; - const struct watchdog_info *info; - const struct watchdog_ops *ops; - const struct watchdog_governor *gov; - unsigned int bootstatus; - unsigned int timeout; - unsigned int pretimeout; - unsigned int min_timeout; - unsigned int max_timeout; - unsigned int min_hw_heartbeat_ms; - unsigned int max_hw_heartbeat_ms; - struct notifier_block reboot_nb; - struct notifier_block restart_nb; - void *driver_data; - struct watchdog_core_data *wd_data; - long unsigned int status; - struct list_head deferred; -}; - -struct watchdog_governor { - const char name[20]; - void (*pretimeout)(struct watchdog_device *); -}; - -struct watchdog_core_data { - struct device dev; - struct cdev cdev; - struct watchdog_device *wdd; - struct mutex lock; - ktime_t last_keepalive; - ktime_t last_hw_keepalive; - ktime_t open_deadline; - struct hrtimer timer; - struct kthread_work work; - long unsigned int status; -}; - -struct bcm2835_wdt { - void *base; - spinlock_t lock; -}; - -struct dm_kobject_holder { - struct kobject kobj; - struct completion completion; -}; - -enum opp_table_access { - OPP_TABLE_ACCESS_UNKNOWN = 0, - OPP_TABLE_ACCESS_EXCLUSIVE = 1, - OPP_TABLE_ACCESS_SHARED = 2, -}; - -struct icc_path; - -struct dev_pm_opp___2; - -struct dev_pm_set_opp_data; - -struct opp_table___2 { - struct list_head node; - struct blocking_notifier_head head; - struct list_head dev_list; - struct list_head opp_list; - struct kref kref; - struct mutex lock; - struct device_node *np; - long unsigned int clock_latency_ns_max; - unsigned int voltage_tolerance_v1; - unsigned int parsed_static_opps; - enum opp_table_access shared_opp; - struct dev_pm_opp___2 *suspend_opp; - struct mutex genpd_virt_dev_lock; - struct device **genpd_virt_devs; - struct opp_table___2 **required_opp_tables; - unsigned int required_opp_count; - unsigned int *supported_hw; - unsigned int supported_hw_count; - const char *prop_name; - struct clk *clk; - struct regulator **regulators; - int regulator_count; - struct icc_path **paths; - unsigned int path_count; - bool enabled; - bool genpd_performance_state; - bool is_genpd; - int (*set_opp)(struct dev_pm_set_opp_data *); - struct dev_pm_set_opp_data *set_opp_data; - struct dentry *dentry; - char dentry_name[255]; -}; - -struct dev_pm_opp_supply; - -struct dev_pm_opp_icc_bw; - -struct dev_pm_opp___2 { - struct list_head node; - struct kref kref; - bool available; - bool dynamic; - bool turbo; - bool suspend; - unsigned int pstate; - long unsigned int rate; - unsigned int level; - struct dev_pm_opp_supply *supplies; - struct dev_pm_opp_icc_bw *bandwidth; - long unsigned int clock_latency_ns; - struct dev_pm_opp___2 **required_opps; - struct opp_table___2 *opp_table; - struct device_node *np; - struct dentry *dentry; -}; - -enum dev_pm_opp_event { - OPP_EVENT_ADD = 0, - OPP_EVENT_REMOVE = 1, - OPP_EVENT_ENABLE = 2, - OPP_EVENT_DISABLE = 3, - OPP_EVENT_ADJUST_VOLTAGE = 4, -}; - -struct dev_pm_opp_supply { - long unsigned int u_volt; - long unsigned int u_volt_min; - long unsigned int u_volt_max; - long unsigned int u_amp; -}; - -struct dev_pm_opp_icc_bw { - u32 avg; - u32 peak; -}; - -struct dev_pm_opp_info { - long unsigned int rate; - struct dev_pm_opp_supply *supplies; -}; - -struct dev_pm_set_opp_data { - struct dev_pm_opp_info old_opp; - struct dev_pm_opp_info new_opp; - struct regulator **regulators; - unsigned int regulator_count; - struct clk *clk; - struct device *dev; -}; - -struct opp_device { - struct list_head node; - const struct device *dev; - struct dentry *dentry; -}; - -struct em_data_callback {}; - -struct cpufreq_policy_data { - struct cpufreq_cpuinfo cpuinfo; - struct cpufreq_frequency_table *freq_table; - unsigned int cpu; - unsigned int min; - unsigned int max; -}; - -struct cpufreq_freqs { - struct cpufreq_policy *policy; - unsigned int old; - unsigned int new; - u8 flags; -}; - -struct freq_attr { - struct attribute attr; - ssize_t (*show)(struct cpufreq_policy *, char *); - ssize_t (*store)(struct cpufreq_policy *, const char *, size_t); -}; - -struct cpufreq_driver { - char name[16]; - u16 flags; - void *driver_data; - int (*init)(struct cpufreq_policy *); - int (*verify)(struct cpufreq_policy_data *); - int (*setpolicy)(struct cpufreq_policy *); - int (*target)(struct cpufreq_policy *, unsigned int, unsigned int); - int (*target_index)(struct cpufreq_policy *, unsigned int); - unsigned int (*fast_switch)(struct cpufreq_policy *, unsigned int); - unsigned int (*resolve_freq)(struct cpufreq_policy *, unsigned int); - unsigned int (*get_intermediate)(struct cpufreq_policy *, unsigned int); - int (*target_intermediate)(struct cpufreq_policy *, unsigned int); - unsigned int (*get)(unsigned int); - void (*update_limits)(unsigned int); - int (*bios_limit)(int, unsigned int *); - int (*online)(struct cpufreq_policy *); - int (*offline)(struct cpufreq_policy *); - int (*exit)(struct cpufreq_policy *); - void (*stop_cpu)(struct cpufreq_policy *); - int (*suspend)(struct cpufreq_policy *); - int (*resume)(struct cpufreq_policy *); - void (*ready)(struct cpufreq_policy *); - struct freq_attr **attr; - bool boost_enabled; - int (*set_boost)(struct cpufreq_policy *, int); -}; - -struct cpufreq_stats { - unsigned int total_trans; - long long unsigned int last_time; - unsigned int max_state; - unsigned int state_num; - unsigned int last_index; - u64 *time_in_state; - unsigned int *freq_table; - unsigned int *trans_table; - unsigned int reset_pending; - long long unsigned int reset_time; -}; - -enum { - OD_NORMAL_SAMPLE = 0, - OD_SUB_SAMPLE = 1, -}; - -struct dbs_data { - struct gov_attr_set attr_set; - void *tuners; - unsigned int ignore_nice_load; - unsigned int sampling_rate; - unsigned int sampling_down_factor; - unsigned int up_threshold; - unsigned int io_is_busy; -}; - -struct policy_dbs_info { - struct cpufreq_policy *policy; - struct mutex update_mutex; - u64 last_sample_time; - s64 sample_delay_ns; - atomic_t work_count; - struct irq_work irq_work; - struct work_struct work; - struct dbs_data *dbs_data; - struct list_head list; - unsigned int rate_mult; - unsigned int idle_periods; - bool is_shared; - bool work_in_progress; -}; - -struct dbs_governor { - struct cpufreq_governor gov; - struct kobj_type kobj_type; - struct dbs_data *gdbs_data; - unsigned int (*gov_dbs_update)(struct cpufreq_policy *); - struct policy_dbs_info * (*alloc)(); - void (*free)(struct policy_dbs_info *); - int (*init)(struct dbs_data *); - void (*exit)(struct dbs_data *); - void (*start)(struct cpufreq_policy *); -}; - -struct od_ops { - unsigned int (*powersave_bias_target)(struct cpufreq_policy *, unsigned int, unsigned int); -}; - -struct od_policy_dbs_info { - struct policy_dbs_info policy_dbs; - unsigned int freq_lo; - unsigned int freq_lo_delay_us; - unsigned int freq_hi_delay_us; - unsigned int sample_type: 1; -}; - -struct od_dbs_tuners { - unsigned int powersave_bias; -}; - -struct cs_policy_dbs_info { - struct policy_dbs_info policy_dbs; - unsigned int down_skip; - unsigned int requested_freq; -}; - -struct cs_dbs_tuners { - unsigned int down_threshold; - unsigned int freq_step; -}; - -struct cpu_dbs_info { - u64 prev_cpu_idle; - u64 prev_update_time; - u64 prev_cpu_nice; - unsigned int prev_load; - struct update_util_data update_util; - struct policy_dbs_info *policy_dbs; -}; - -struct cpufreq_dt_platform_data { - bool have_governor_per_policy; - unsigned int (*get_intermediate)(struct cpufreq_policy *, unsigned int); - int (*target_intermediate)(struct cpufreq_policy *, unsigned int); - int (*suspend)(struct cpufreq_policy *); - int (*resume)(struct cpufreq_policy *); -}; - -struct private_data { - struct list_head node; - cpumask_var_t cpus; - struct device *cpu_dev; - struct opp_table *opp_table; - struct opp_table *reg_opp_table; - bool have_static_opps; -}; - -struct cpuidle_governor { - char name[16]; - struct list_head governor_list; - unsigned int rating; - int (*enable)(struct cpuidle_driver *, struct cpuidle_device *); - void (*disable)(struct cpuidle_driver *, struct cpuidle_device *); - int (*select)(struct cpuidle_driver *, struct cpuidle_device *, bool *); - void (*reflect)(struct cpuidle_device *, int); -}; - -struct cpuidle_state_kobj { - struct cpuidle_state *state; - struct cpuidle_state_usage *state_usage; - struct completion kobj_unregister; - struct kobject kobj; - struct cpuidle_device *device; -}; - -struct cpuidle_driver_kobj { - struct cpuidle_driver *drv; - struct completion kobj_unregister; - struct kobject kobj; -}; - -struct cpuidle_device_kobj { - struct cpuidle_device *dev; - struct completion kobj_unregister; - struct kobject kobj; -}; - -struct cpuidle_attr { - struct attribute attr; - ssize_t (*show)(struct cpuidle_device *, char *); - ssize_t (*store)(struct cpuidle_device *, const char *, size_t); -}; - -struct cpuidle_state_attr { - struct attribute attr; - ssize_t (*show)(struct cpuidle_state *, struct cpuidle_state_usage *, char *); - ssize_t (*store)(struct cpuidle_state *, struct cpuidle_state_usage *, const char *, size_t); -}; - -struct cpuidle_driver_attr { - struct attribute attr; - ssize_t (*show)(struct cpuidle_driver *, char *); - ssize_t (*store)(struct cpuidle_driver *, const char *, size_t); -}; - -struct menu_device { - int needs_update; - int tick_wakeup; - u64 next_timer_ns; - unsigned int bucket; - unsigned int correction_factor[12]; - unsigned int intervals[8]; - int interval_ptr; -}; - -struct mmc_cid { - unsigned int manfid; - char prod_name[8]; - unsigned char prv; - unsigned int serial; - short unsigned int oemid; - short unsigned int year; - unsigned char hwrev; - unsigned char fwrev; - unsigned char month; -}; - -struct mmc_csd { - unsigned char structure; - unsigned char mmca_vsn; - short unsigned int cmdclass; - short unsigned int taac_clks; - unsigned int taac_ns; - unsigned int c_size; - unsigned int r2w_factor; - unsigned int max_dtr; - unsigned int erase_size; - unsigned int read_blkbits; - unsigned int write_blkbits; - unsigned int capacity; - unsigned int read_partial: 1; - unsigned int read_misalign: 1; - unsigned int write_partial: 1; - unsigned int write_misalign: 1; - unsigned int dsr_imp: 1; -}; - -struct mmc_ext_csd { - u8 rev; - u8 erase_group_def; - u8 sec_feature_support; - u8 rel_sectors; - u8 rel_param; - bool enhanced_rpmb_supported; - u8 part_config; - u8 cache_ctrl; - u8 rst_n_function; - u8 max_packed_writes; - u8 max_packed_reads; - u8 packed_event_en; - unsigned int part_time; - unsigned int sa_timeout; - unsigned int generic_cmd6_time; - unsigned int power_off_longtime; - u8 power_off_notification; - unsigned int hs_max_dtr; - unsigned int hs200_max_dtr; - unsigned int sectors; - unsigned int hc_erase_size; - unsigned int hc_erase_timeout; - unsigned int sec_trim_mult; - unsigned int sec_erase_mult; - unsigned int trim_timeout; - bool partition_setting_completed; - long long unsigned int enhanced_area_offset; - unsigned int enhanced_area_size; - unsigned int cache_size; - bool hpi_en; - bool hpi; - unsigned int hpi_cmd; - bool bkops; - bool man_bkops_en; - bool auto_bkops_en; - unsigned int data_sector_size; - unsigned int data_tag_unit_size; - unsigned int boot_ro_lock; - bool boot_ro_lockable; - bool ffu_capable; - bool cmdq_en; - bool cmdq_support; - unsigned int cmdq_depth; - u8 fwrev[8]; - u8 raw_exception_status; - u8 raw_partition_support; - u8 raw_rpmb_size_mult; - u8 raw_erased_mem_count; - u8 strobe_support; - u8 raw_ext_csd_structure; - u8 raw_card_type; - u8 raw_driver_strength; - u8 out_of_int_time; - u8 raw_pwr_cl_52_195; - u8 raw_pwr_cl_26_195; - u8 raw_pwr_cl_52_360; - u8 raw_pwr_cl_26_360; - u8 raw_s_a_timeout; - u8 raw_hc_erase_gap_size; - u8 raw_erase_timeout_mult; - u8 raw_hc_erase_grp_size; - u8 raw_sec_trim_mult; - u8 raw_sec_erase_mult; - u8 raw_sec_feature_support; - u8 raw_trim_mult; - u8 raw_pwr_cl_200_195; - u8 raw_pwr_cl_200_360; - u8 raw_pwr_cl_ddr_52_195; - u8 raw_pwr_cl_ddr_52_360; - u8 raw_pwr_cl_ddr_200_360; - u8 raw_bkops_status; - u8 raw_sectors[4]; - u8 pre_eol_info; - u8 device_life_time_est_typ_a; - u8 device_life_time_est_typ_b; - unsigned int feature_support; -}; - -struct sd_scr { - unsigned char sda_vsn; - unsigned char sda_spec3; - unsigned char sda_spec4; - unsigned char sda_specx; - unsigned char bus_widths; - unsigned char cmds; -}; - -struct sd_ssr { - unsigned int au; - unsigned int erase_timeout; - unsigned int erase_offset; -}; - -struct sd_switch_caps { - unsigned int hs_max_dtr; - unsigned int uhs_max_dtr; - unsigned int sd3_bus_mode; - unsigned int sd3_drv_type; - unsigned int sd3_curr_limit; -}; - -struct sdio_cccr { - unsigned int sdio_vsn; - unsigned int sd_vsn; - unsigned int multi_block: 1; - unsigned int low_speed: 1; - unsigned int wide_bus: 1; - unsigned int high_power: 1; - unsigned int high_speed: 1; - unsigned int disable_cd: 1; -}; - -struct sdio_cis { - short unsigned int vendor; - short unsigned int device; - short unsigned int blksize; - unsigned int max_dtr; -}; - -struct mmc_part { - u64 size; - unsigned int part_cfg; - char name[20]; - bool force_ro; - unsigned int area_type; -}; - -struct mmc_host; - -struct sdio_func; - -struct sdio_func_tuple; - -struct mmc_card { - struct mmc_host *host; - struct device dev; - u32 ocr; - unsigned int rca; - unsigned int type; - unsigned int state; - unsigned int quirks; - unsigned int quirk_max_rate; - bool reenable_cmdq; - unsigned int erase_size; - unsigned int erase_shift; - unsigned int pref_erase; - unsigned int eg_boundary; - unsigned int erase_arg; - u8 erased_byte; - u32 raw_cid[4]; - u32 raw_csd[4]; - u32 raw_scr[2]; - u32 raw_ssr[16]; - struct mmc_cid cid; - struct mmc_csd csd; - struct mmc_ext_csd ext_csd; - struct sd_scr scr; - struct sd_ssr ssr; - struct sd_switch_caps sw_caps; - unsigned int sdio_funcs; - atomic_t sdio_funcs_probed; - struct sdio_cccr cccr; - struct sdio_cis cis; - struct sdio_func *sdio_func[7]; - struct sdio_func *sdio_single_irq; - u8 major_rev; - u8 minor_rev; - unsigned int num_info; - const char **info; - struct sdio_func_tuple *tuples; - unsigned int sd_bus_speed; - unsigned int mmc_avail_type; - unsigned int drive_strength; - struct dentry *debugfs_root; - struct mmc_part part[7]; - unsigned int nr_parts; - unsigned int bouncesz; - struct workqueue_struct *complete_wq; -}; - -typedef unsigned int mmc_pm_flag_t; - -struct mmc_ios { - unsigned int clock; - short unsigned int vdd; - unsigned int power_delay_ms; - unsigned char bus_mode; - unsigned char chip_select; - unsigned char power_mode; - unsigned char bus_width; - unsigned char timing; - unsigned char signal_voltage; - unsigned char drv_type; - bool enhanced_strobe; -}; - -struct mmc_ctx { - struct task_struct *task; -}; - -struct mmc_slot { - int cd_irq; - bool cd_wake_enabled; - void *handler_priv; -}; - -struct mmc_supply { - struct regulator *vmmc; - struct regulator *vqmmc; -}; - -struct mmc_host_ops; - -struct mmc_pwrseq; - -struct mmc_bus_ops; - -struct mmc_request; - -struct mmc_cqe_ops; - -struct mmc_host { - struct device *parent; - struct device class_dev; - int index; - const struct mmc_host_ops *ops; - struct mmc_pwrseq *pwrseq; - unsigned int f_min; - unsigned int f_max; - unsigned int f_init; - u32 ocr_avail; - u32 ocr_avail_sdio; - u32 ocr_avail_sd; - u32 ocr_avail_mmc; - struct wakeup_source *ws; - u32 max_current_330; - u32 max_current_300; - u32 max_current_180; - u32 caps; - u32 caps2; - int fixed_drv_type; - mmc_pm_flag_t pm_caps; - unsigned int max_seg_size; - short unsigned int max_segs; - short unsigned int unused; - unsigned int max_req_size; - unsigned int max_blk_size; - unsigned int max_blk_count; - unsigned int max_busy_timeout; - spinlock_t lock; - struct mmc_ios ios; - unsigned int use_spi_crc: 1; - unsigned int claimed: 1; - unsigned int bus_dead: 1; - unsigned int doing_init_tune: 1; - unsigned int can_retune: 1; - unsigned int doing_retune: 1; - unsigned int retune_now: 1; - unsigned int retune_paused: 1; - unsigned int use_blk_mq: 1; - unsigned int retune_crc_disable: 1; - unsigned int can_dma_map_merge: 1; - int rescan_disable; - int rescan_entered; - int need_retune; - int hold_retune; - unsigned int retune_period; - struct timer_list retune_timer; - bool trigger_card_event; - struct mmc_card *card; - wait_queue_head_t wq; - struct mmc_ctx *claimer; - int claim_cnt; - struct mmc_ctx default_ctx; - struct delayed_work detect; - int detect_change; - struct mmc_slot slot; - const struct mmc_bus_ops *bus_ops; - unsigned int bus_refs; - unsigned int sdio_irqs; - struct task_struct *sdio_irq_thread; - struct delayed_work sdio_irq_work; - bool sdio_irq_pending; - atomic_t sdio_irq_thread_abort; - mmc_pm_flag_t pm_flags; - struct led_trigger *led; - bool regulator_enabled; - struct mmc_supply supply; - struct dentry *debugfs_root; - struct mmc_request *ongoing_mrq; - unsigned int actual_clock; - unsigned int slotno; - int dsr_req; - u32 dsr; - const struct mmc_cqe_ops *cqe_ops; - void *cqe_private; - int cqe_qdepth; - bool cqe_enabled; - bool cqe_on; - bool hsq_enabled; - long: 8; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int private[0]; -}; - -struct mmc_data; - -struct mmc_command { - u32 opcode; - u32 arg; - u32 resp[4]; - unsigned int flags; - unsigned int retries; - int error; - unsigned int busy_timeout; - struct mmc_data *data; - struct mmc_request *mrq; -}; - -struct mmc_data { - unsigned int timeout_ns; - unsigned int timeout_clks; - unsigned int blksz; - unsigned int blocks; - unsigned int blk_addr; - int error; - unsigned int flags; - unsigned int bytes_xfered; - struct mmc_command *stop; - struct mmc_request *mrq; - unsigned int sg_len; - int sg_count; - struct scatterlist *sg; - s32 host_cookie; -}; - -struct mmc_request { - struct mmc_command *sbc; - struct mmc_command *cmd; - struct mmc_data *data; - struct mmc_command *stop; - struct completion completion; - struct completion cmd_completion; - void (*done)(struct mmc_request *); - void (*recovery_notifier)(struct mmc_request *); - struct mmc_host *host; - bool cap_cmd_during_tfr; - int tag; -}; - -struct mmc_host_ops { - void (*post_req)(struct mmc_host *, struct mmc_request *, int); - void (*pre_req)(struct mmc_host *, struct mmc_request *); - void (*request)(struct mmc_host *, struct mmc_request *); - int (*request_atomic)(struct mmc_host *, struct mmc_request *); - void (*set_ios)(struct mmc_host *, struct mmc_ios *); - int (*get_ro)(struct mmc_host *); - int (*get_cd)(struct mmc_host *); - void (*enable_sdio_irq)(struct mmc_host *, int); - void (*ack_sdio_irq)(struct mmc_host *); - void (*init_card)(struct mmc_host *, struct mmc_card *); - int (*start_signal_voltage_switch)(struct mmc_host *, struct mmc_ios *); - int (*card_busy)(struct mmc_host *); - int (*execute_tuning)(struct mmc_host *, u32); - int (*prepare_hs400_tuning)(struct mmc_host *, struct mmc_ios *); - int (*hs400_prepare_ddr)(struct mmc_host *); - void (*hs400_downgrade)(struct mmc_host *); - void (*hs400_complete)(struct mmc_host *); - void (*hs400_enhanced_strobe)(struct mmc_host *, struct mmc_ios *); - int (*select_drive_strength)(struct mmc_card *, unsigned int, int, int, int *); - void (*hw_reset)(struct mmc_host *); - void (*card_event)(struct mmc_host *); - int (*multi_io_quirk)(struct mmc_card *, unsigned int, int); -}; - -struct mmc_cqe_ops { - int (*cqe_enable)(struct mmc_host *, struct mmc_card *); - void (*cqe_disable)(struct mmc_host *); - int (*cqe_request)(struct mmc_host *, struct mmc_request *); - void (*cqe_post_req)(struct mmc_host *, struct mmc_request *); - void (*cqe_off)(struct mmc_host *); - int (*cqe_wait_for_idle)(struct mmc_host *); - bool (*cqe_timeout)(struct mmc_host *, struct mmc_request *, bool *); - void (*cqe_recovery_start)(struct mmc_host *); - void (*cqe_recovery_finish)(struct mmc_host *); -}; - -struct mmc_pwrseq_ops; - -struct mmc_pwrseq { - const struct mmc_pwrseq_ops *ops; - struct device *dev; - struct list_head pwrseq_node; - struct module *owner; -}; - -struct mmc_bus_ops { - void (*remove)(struct mmc_host *); - void (*detect)(struct mmc_host *); - int (*pre_suspend)(struct mmc_host *); - int (*suspend)(struct mmc_host *); - int (*resume)(struct mmc_host *); - int (*runtime_suspend)(struct mmc_host *); - int (*runtime_resume)(struct mmc_host *); - int (*alive)(struct mmc_host *); - int (*shutdown)(struct mmc_host *); - int (*hw_reset)(struct mmc_host *); - int (*sw_reset)(struct mmc_host *); - bool (*cache_enabled)(struct mmc_host *); -}; - -struct trace_event_raw_mmc_request_start { - struct trace_entry ent; - u32 cmd_opcode; - u32 cmd_arg; - unsigned int cmd_flags; - unsigned int cmd_retries; - u32 stop_opcode; - u32 stop_arg; - unsigned int stop_flags; - unsigned int stop_retries; - u32 sbc_opcode; - u32 sbc_arg; - unsigned int sbc_flags; - unsigned int sbc_retries; - unsigned int blocks; - unsigned int blk_addr; - unsigned int blksz; - unsigned int data_flags; - int tag; - unsigned int can_retune; - unsigned int doing_retune; - unsigned int retune_now; - int need_retune; - int hold_retune; - unsigned int retune_period; - struct mmc_request *mrq; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_mmc_request_done { - struct trace_entry ent; - u32 cmd_opcode; - int cmd_err; - u32 cmd_resp[4]; - unsigned int cmd_retries; - u32 stop_opcode; - int stop_err; - u32 stop_resp[4]; - unsigned int stop_retries; - u32 sbc_opcode; - int sbc_err; - u32 sbc_resp[4]; - unsigned int sbc_retries; - unsigned int bytes_xfered; - int data_err; - int tag; - unsigned int can_retune; - unsigned int doing_retune; - unsigned int retune_now; - int need_retune; - int hold_retune; - unsigned int retune_period; - struct mmc_request *mrq; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_data_offsets_mmc_request_start { - u32 name; -}; - -struct trace_event_data_offsets_mmc_request_done { - u32 name; -}; - -typedef void (*btf_trace_mmc_request_start)(void *, struct mmc_host *, struct mmc_request *); - -typedef void (*btf_trace_mmc_request_done)(void *, struct mmc_host *, struct mmc_request *); - -struct mmc_pwrseq_ops { - void (*pre_power_on)(struct mmc_host *); - void (*post_power_on)(struct mmc_host *); - void (*power_off)(struct mmc_host *); - void (*reset)(struct mmc_host *); -}; - -enum mmc_busy_cmd { - MMC_BUSY_CMD6 = 0, - MMC_BUSY_ERASE = 1, - MMC_BUSY_HPI = 2, -}; - -struct mmc_driver { - struct device_driver drv; - int (*probe)(struct mmc_card *); - void (*remove)(struct mmc_card *); - void (*shutdown)(struct mmc_card *); -}; - -struct mmc_fixup { - const char *name; - u64 rev_start; - u64 rev_end; - unsigned int manfid; - short unsigned int oemid; - u16 cis_vendor; - u16 cis_device; - unsigned int ext_csd_rev; - void (*vendor_fixup)(struct mmc_card *, int); - int data; -}; - -typedef void sdio_irq_handler_t(struct sdio_func *); - -struct sdio_func { - struct mmc_card *card; - struct device dev; - sdio_irq_handler_t *irq_handler; - unsigned int num; - unsigned char class; - short unsigned int vendor; - short unsigned int device; - unsigned int max_blksize; - unsigned int cur_blksize; - unsigned int enable_timeout; - unsigned int state; - u8 *tmpbuf; - u8 major_rev; - u8 minor_rev; - unsigned int num_info; - const char **info; - struct sdio_func_tuple *tuples; -}; - -struct sdio_func_tuple { - struct sdio_func_tuple *next; - unsigned char code; - unsigned char size; - unsigned char data[0]; -}; - -struct sdio_device_id { - __u8 class; - __u16 vendor; - __u16 device; - kernel_ulong_t driver_data; -}; - -struct sdio_driver { - char *name; - const struct sdio_device_id *id_table; - int (*probe)(struct sdio_func *, const struct sdio_device_id *); - void (*remove)(struct sdio_func *); - struct device_driver drv; -}; - -typedef int tpl_parse_t(struct mmc_card *, struct sdio_func *, const unsigned char *, unsigned int); - -struct cis_tpl { - unsigned char code; - unsigned char min_size; - tpl_parse_t *parse; -}; - -struct mmc_gpio { - struct gpio_desc *ro_gpio; - struct gpio_desc *cd_gpio; - irqreturn_t (*cd_gpio_isr)(int, void *); - char *ro_label; - char *cd_label; - u32 cd_debounce_delay_ms; -}; - -struct mmc_pwrseq_simple { - struct mmc_pwrseq pwrseq; - bool clk_enabled; - u32 post_power_on_delay_ms; - u32 power_off_delay_us; - struct clk *ext_clk; - struct gpio_descs *reset_gpios; -}; - -struct mmc_pwrseq_emmc { - struct mmc_pwrseq pwrseq; - struct notifier_block reset_nb; - struct gpio_desc *reset_gpio; -}; - -struct mmc_ioc_cmd { - int write_flag; - int is_acmd; - __u32 opcode; - __u32 arg; - __u32 response[4]; - unsigned int flags; - unsigned int blksz; - unsigned int blocks; - unsigned int postsleep_min_us; - unsigned int postsleep_max_us; - unsigned int data_timeout_ns; - unsigned int cmd_timeout_ms; - __u32 __pad; - __u64 data_ptr; -}; - -struct mmc_ioc_multi_cmd { - __u64 num_of_cmds; - struct mmc_ioc_cmd cmds[0]; -}; - -enum mmc_issued { - MMC_REQ_STARTED = 0, - MMC_REQ_BUSY = 1, - MMC_REQ_FAILED_TO_START = 2, - MMC_REQ_FINISHED = 3, -}; - -enum mmc_issue_type { - MMC_ISSUE_SYNC = 0, - MMC_ISSUE_DCMD = 1, - MMC_ISSUE_ASYNC = 2, - MMC_ISSUE_MAX = 3, -}; - -struct mmc_blk_request { - struct mmc_request mrq; - struct mmc_command sbc; - struct mmc_command cmd; - struct mmc_command stop; - struct mmc_data data; -}; - -enum mmc_drv_op { - MMC_DRV_OP_IOCTL = 0, - MMC_DRV_OP_IOCTL_RPMB = 1, - MMC_DRV_OP_BOOT_WP = 2, - MMC_DRV_OP_GET_CARD_STATUS = 3, - MMC_DRV_OP_GET_EXT_CSD = 4, -}; - -struct mmc_queue_req { - struct mmc_blk_request brq; - struct scatterlist *sg; - enum mmc_drv_op drv_op; - int drv_op_result; - void *drv_op_data; - unsigned int ioc_count; - int retries; -}; - -struct mmc_blk_data; - -struct mmc_queue { - struct mmc_card *card; - struct mmc_ctx ctx; - struct blk_mq_tag_set tag_set; - struct mmc_blk_data *blkdata; - struct request_queue *queue; - spinlock_t lock; - int in_flight[3]; - unsigned int cqe_busy; - bool busy; - bool use_cqe; - bool recovery_needed; - bool in_recovery; - bool rw_wait; - bool waiting; - struct work_struct recovery_work; - wait_queue_head_t wait; - struct request *recovery_req; - struct request *complete_req; - struct mutex complete_lock; - struct work_struct complete_work; -}; - -struct mmc_blk_data { - struct device *parent; - struct gendisk *disk; - struct mmc_queue queue; - struct list_head part; - struct list_head rpmbs; - unsigned int flags; - unsigned int usage; - unsigned int read_only; - unsigned int part_type; - unsigned int reset_done; - unsigned int part_curr; - struct device_attribute force_ro; - struct device_attribute power_ro_lock; - int area_type; - struct dentry *status_dentry; - struct dentry *ext_csd_dentry; -}; - -struct mmc_rpmb_data { - struct device dev; - struct cdev chrdev; - int id; - unsigned int part_index; - struct mmc_blk_data *md; - struct list_head node; -}; - -struct mmc_blk_ioc_data { - struct mmc_ioc_cmd ic; - unsigned char *buf; - u64 buf_bytes; - struct mmc_rpmb_data *rpmb; -}; - -struct sdhci_adma2_64_desc { - __le16 cmd; - __le16 len; - __le32 addr_lo; - __le32 addr_hi; -}; - -enum sdhci_cookie { - COOKIE_UNMAPPED = 0, - COOKIE_PRE_MAPPED = 1, - COOKIE_MAPPED = 2, -}; - -struct sdhci_ops; - -struct sdhci_host { - const char *hw_name; - unsigned int quirks; - unsigned int quirks2; - int irq; - void *ioaddr; - phys_addr_t mapbase; - char *bounce_buffer; - dma_addr_t bounce_addr; - unsigned int bounce_buffer_size; - const struct sdhci_ops *ops; - struct mmc_host *mmc; - struct mmc_host_ops mmc_host_ops; - u64 dma_mask; - struct led_classdev led; - char led_name[32]; - spinlock_t lock; - int flags; - unsigned int version; - unsigned int max_clk; - unsigned int timeout_clk; - unsigned int clk_mul; - unsigned int clock; - u8 pwr; - bool runtime_suspended; - bool bus_on; - bool preset_enabled; - bool pending_reset; - bool irq_wake_enabled; - bool v4_mode; - bool use_external_dma; - bool always_defer_done; - struct mmc_request *mrqs_done[2]; - struct mmc_command *cmd; - struct mmc_command *data_cmd; - struct mmc_command *deferred_cmd; - struct mmc_data *data; - unsigned int data_early: 1; - struct sg_mapping_iter sg_miter; - unsigned int blocks; - int sg_count; - int max_adma; - void *adma_table; - void *align_buffer; - size_t adma_table_sz; - size_t align_buffer_sz; - dma_addr_t adma_addr; - dma_addr_t align_addr; - unsigned int desc_sz; - unsigned int alloc_desc_sz; - struct workqueue_struct *complete_wq; - struct work_struct complete_work; - struct timer_list timer; - struct timer_list data_timer; - u32 caps; - u32 caps1; - bool read_caps; - bool sdhci_core_to_disable_vqmmc; - unsigned int ocr_avail_sdio; - unsigned int ocr_avail_sd; - unsigned int ocr_avail_mmc; - u32 ocr_mask; - unsigned int timing; - u32 thread_isr; - u32 ier; - bool cqe_on; - u32 cqe_ier; - u32 cqe_err_ier; - wait_queue_head_t buf_ready_int; - unsigned int tuning_done; - unsigned int tuning_count; - unsigned int tuning_mode; - unsigned int tuning_err; - int tuning_delay; - int tuning_loop_count; - u32 sdma_boundary; - u32 adma_table_cnt; - u64 data_timeout; - long: 64; - long: 64; - long: 64; - long unsigned int private[0]; -}; - -struct sdhci_ops { - u32 (*read_l)(struct sdhci_host *, int); - u16 (*read_w)(struct sdhci_host *, int); - u8 (*read_b)(struct sdhci_host *, int); - void (*write_l)(struct sdhci_host *, u32, int); - void (*write_w)(struct sdhci_host *, u16, int); - void (*write_b)(struct sdhci_host *, u8, int); - void (*set_clock)(struct sdhci_host *, unsigned int); - void (*set_power)(struct sdhci_host *, unsigned char, short unsigned int); - u32 (*irq)(struct sdhci_host *, u32); - int (*set_dma_mask)(struct sdhci_host *); - int (*enable_dma)(struct sdhci_host *); - unsigned int (*get_max_clock)(struct sdhci_host *); - unsigned int (*get_min_clock)(struct sdhci_host *); - unsigned int (*get_timeout_clock)(struct sdhci_host *); - unsigned int (*get_max_timeout_count)(struct sdhci_host *); - void (*set_timeout)(struct sdhci_host *, struct mmc_command *); - void (*set_bus_width)(struct sdhci_host *, int); - void (*platform_send_init_74_clocks)(struct sdhci_host *, u8); - unsigned int (*get_ro)(struct sdhci_host *); - void (*reset)(struct sdhci_host *, u8); - int (*platform_execute_tuning)(struct sdhci_host *, u32); - void (*set_uhs_signaling)(struct sdhci_host *, unsigned int); - void (*hw_reset)(struct sdhci_host *); - void (*adma_workaround)(struct sdhci_host *, u32); - void (*card_event)(struct sdhci_host *); - void (*voltage_switch)(struct sdhci_host *); - void (*adma_write_desc)(struct sdhci_host *, void **, dma_addr_t, int, unsigned int); - void (*copy_to_bounce_buffer)(struct sdhci_host *, struct mmc_data *, unsigned int); - void (*request_done)(struct sdhci_host *, struct mmc_request *); - void (*dump_vendor_regs)(struct sdhci_host *); -}; - -struct bcm2835_host { - spinlock_t lock; - void *ioaddr; - u32 bus_addr; - struct mmc_host *mmc; - u32 timeout; - int clock; - u8 pwr; - unsigned int max_clk; - unsigned int timeout_clk; - unsigned int clk_mul; - struct tasklet_struct finish_tasklet; - struct timer_list timer; - struct sg_mapping_iter sg_miter; - unsigned int blocks; - int irq; - u32 ier; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - unsigned int data_early: 1; - wait_queue_head_t buf_ready_int; - u32 shadow; - struct dma_chan *dma_chan_rxtx; - struct dma_slave_config dma_cfg_rx; - struct dma_slave_config dma_cfg_tx; - struct dma_async_tx_descriptor *tx_desc; - bool have_dma; - bool use_dma; - bool wait_for_dma; - int max_delay; - int flags; - u32 overclock_50; - u32 max_overclock; -}; - -struct bcm2835_host___2 { - spinlock_t lock; - struct rpi_firmware *fw; - void *ioaddr; - phys_addr_t bus_addr; - struct mmc_host *mmc; - u32 pio_timeout; - int clock; - bool slow_card; - unsigned int max_clk; - struct tasklet_struct finish_tasklet; - struct work_struct cmd_wait_wq; - struct timer_list timer; - struct sg_mapping_iter sg_miter; - unsigned int blocks; - int irq; - u32 cmd_quick_poll_retries; - u32 ns_per_fifo_word; - u32 hcfg; - u32 cdiv; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - unsigned int data_complete: 1; - unsigned int flush_fifo: 1; - unsigned int use_busy: 1; - unsigned int use_sbc: 1; - unsigned int debug: 1; - unsigned int firmware_sets_cdiv: 1; - unsigned int reset_clock: 1; - struct dma_chan *dma_chan_rxtx; - struct dma_chan *dma_chan; - struct dma_slave_config dma_cfg_rx; - struct dma_slave_config dma_cfg_tx; - struct dma_async_tx_descriptor *dma_desc; - u32 dma_dir; - u32 drain_words; - struct page *drain_page; - u32 drain_offset; - bool allow_dma; - bool use_dma; - int max_delay; - struct timespec64 stop_time; - u32 delay_after_stop; - u32 delay_after_this_stop; - u32 user_overclock_50; - u32 overclock_50; - u32 overclock; - u32 pio_limit; - u32 sectors; -}; - -struct log_entry_struct { - char event[4]; - u32 timestamp; - u32 param1; - u32 param2; -}; - -typedef struct log_entry_struct LOG_ENTRY_T; - -struct sdhci_pltfm_data { - const struct sdhci_ops *ops; - unsigned int quirks; - unsigned int quirks2; -}; - -struct sdhci_pltfm_host { - struct clk *clk; - unsigned int clock; - u16 xfer_mode_shadow; - long: 16; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int private[0]; -}; - -struct sdhci_iproc_data { - const struct sdhci_pltfm_data *pdata; - u32 caps; - u32 caps1; - u32 mmc_caps; -}; - -struct sdhci_iproc_host { - const struct sdhci_iproc_data *data; - u32 shadow_cmd; - u32 shadow_blk; - bool is_cmd_shadowed; - bool is_blk_shadowed; -}; - -struct led_init_data { - struct fwnode_handle *fwnode; - const char *default_label; - const char *devicename; - bool devname_mandatory; -}; - -struct led_properties { - u32 color; - bool color_present; - const char *function; - u32 func_enum; - bool func_enum_present; - const char *label; -}; - -typedef int (*gpio_blink_set_t)(struct gpio_desc *, int, long unsigned int *, long unsigned int *); - -struct gpio_led { - const char *name; - const char *default_trigger; - unsigned int gpio; - unsigned int active_low: 1; - unsigned int retain_state_suspended: 1; - unsigned int panic_indicator: 1; - unsigned int default_state: 2; - unsigned int retain_state_shutdown: 1; - struct gpio_desc *gpiod; -}; - -struct gpio_led_platform_data { - int num_leds; - const struct gpio_led *leds; - gpio_blink_set_t gpio_blink_set; -}; - -struct gpio_led_data { - struct led_classdev cdev; - struct gpio_desc *gpiod; - u8 can_sleep; - u8 blinking; - gpio_blink_set_t platform_gpio_blink_set; -}; - -struct gpio_leds_priv { - int num_leds; - struct gpio_led_data leds[0]; -}; - -struct led_pwm { - const char *name; - u8 active_low; - unsigned int max_brightness; -}; - -struct led_pwm_data { - struct led_classdev cdev; - struct pwm_device *pwm; - struct pwm_state pwmstate; - unsigned int active_low; -}; - -struct led_pwm_priv { - int num_leds; - struct led_pwm_data leds[0]; -}; - -struct oneshot_trig_data { - unsigned int invert; -}; - -struct heartbeat_trig_data { - struct led_classdev *led_cdev; - unsigned int phase; - unsigned int period; - struct timer_list timer; - unsigned int invert; -}; - -struct bl_trig_notifier { - struct led_classdev *led; - int brightness; - int old_status; - struct notifier_block notifier; - unsigned int invert; -}; - -struct gpio_trig_data { - struct led_classdev *led; - unsigned int desired_brightness; - unsigned int inverted; - unsigned int gpio; -}; - -enum cpu_led_event { - CPU_LED_IDLE_START = 0, - CPU_LED_IDLE_END = 1, - CPU_LED_START = 2, - CPU_LED_STOP = 3, - CPU_LED_HALTED = 4, -}; - -struct led_trigger_cpu { - bool is_active; - char name[8]; - struct led_trigger *_trig; -}; - -enum { - TRIG_ACT = 0, - TRIG_PWR = 1, - TRIG_COUNT = 2, -}; - -struct actpwr_trig_src { - const char *name; - int interval; - bool invert; -}; - -struct actpwr_trig_data; - -struct actpwr_vled { - struct led_classdev cdev; - struct actpwr_trig_data *parent; - enum led_brightness value; - unsigned int interval; - bool invert; -}; - -struct actpwr_trig_data { - struct led_trigger trig; - struct actpwr_vled virt_leds[2]; - struct actpwr_vled *active; - struct timer_list timer; - int next_active; -}; - -enum dmi_entry_type { - DMI_ENTRY_BIOS = 0, - DMI_ENTRY_SYSTEM = 1, - DMI_ENTRY_BASEBOARD = 2, - DMI_ENTRY_CHASSIS = 3, - DMI_ENTRY_PROCESSOR = 4, - DMI_ENTRY_MEM_CONTROLLER = 5, - DMI_ENTRY_MEM_MODULE = 6, - DMI_ENTRY_CACHE = 7, - DMI_ENTRY_PORT_CONNECTOR = 8, - DMI_ENTRY_SYSTEM_SLOT = 9, - DMI_ENTRY_ONBOARD_DEVICE = 10, - DMI_ENTRY_OEMSTRINGS = 11, - DMI_ENTRY_SYSCONF = 12, - DMI_ENTRY_BIOS_LANG = 13, - DMI_ENTRY_GROUP_ASSOC = 14, - DMI_ENTRY_SYSTEM_EVENT_LOG = 15, - DMI_ENTRY_PHYS_MEM_ARRAY = 16, - DMI_ENTRY_MEM_DEVICE = 17, - DMI_ENTRY_32_MEM_ERROR = 18, - DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR = 19, - DMI_ENTRY_MEM_DEV_MAPPED_ADDR = 20, - DMI_ENTRY_BUILTIN_POINTING_DEV = 21, - DMI_ENTRY_PORTABLE_BATTERY = 22, - DMI_ENTRY_SYSTEM_RESET = 23, - DMI_ENTRY_HW_SECURITY = 24, - DMI_ENTRY_SYSTEM_POWER_CONTROLS = 25, - DMI_ENTRY_VOLTAGE_PROBE = 26, - DMI_ENTRY_COOLING_DEV = 27, - DMI_ENTRY_TEMP_PROBE = 28, - DMI_ENTRY_ELECTRICAL_CURRENT_PROBE = 29, - DMI_ENTRY_OOB_REMOTE_ACCESS = 30, - DMI_ENTRY_BIS_ENTRY = 31, - DMI_ENTRY_SYSTEM_BOOT = 32, - DMI_ENTRY_MGMT_DEV = 33, - DMI_ENTRY_MGMT_DEV_COMPONENT = 34, - DMI_ENTRY_MGMT_DEV_THRES = 35, - DMI_ENTRY_MEM_CHANNEL = 36, - DMI_ENTRY_IPMI_DEV = 37, - DMI_ENTRY_SYS_POWER_SUPPLY = 38, - DMI_ENTRY_ADDITIONAL = 39, - DMI_ENTRY_ONBOARD_DEV_EXT = 40, - DMI_ENTRY_MGMT_CONTROLLER_HOST = 41, - DMI_ENTRY_INACTIVE = 126, - DMI_ENTRY_END_OF_TABLE = 127, -}; - -struct dmi_header { - u8 type; - u8 length; - u16 handle; -}; - -struct dmi_memdev_info { - const char *device; - const char *bank; - u64 size; - u16 handle; - u8 type; -}; - -struct dmi_device_attribute { - struct device_attribute dev_attr; - int field; -}; - -struct mafield { - const char *prefix; - int field; -}; - -struct mbox_client { - struct device *dev; - bool tx_block; - long unsigned int tx_tout; - bool knows_txdone; - void (*rx_callback)(struct mbox_client *, void *); - void (*tx_prepare)(struct mbox_client *, void *); - void (*tx_done)(struct mbox_client *, void *, int); -}; - -struct mbox_chan; - -struct rpi_firmware___2 { - struct mbox_client cl; - struct mbox_chan *chan; - struct completion c; - u32 enabled; - u32 get_throttled; - struct kref consumers; -}; - -typedef efi_status_t efi_query_variable_store_t(u32, long unsigned int, bool); - -typedef struct { - efi_guid_t guid; - u64 table; -} efi_config_table_64_t; - -typedef struct { - efi_guid_t guid; - u32 table; -} efi_config_table_32_t; - -typedef union { - struct { - efi_guid_t guid; - void *table; - }; - efi_config_table_32_t mixed_mode; -} efi_config_table_t; - -typedef struct { - efi_guid_t guid; - long unsigned int *ptr; - const char name[16]; -} efi_config_table_type_t; - -typedef struct { - u16 version; - u16 length; - u32 runtime_services_supported; -} efi_rt_properties_table_t; - -struct efivar_operations { - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_set_variable_t *set_variable_nonblocking; - efi_query_variable_store_t *query_variable_store; -}; - -struct efivars { - struct kset *kset; - struct kobject *kobject; - const struct efivar_operations *ops; -}; - -struct linux_efi_random_seed { - u32 size; - u8 bits[0]; -}; - -struct linux_efi_memreserve { - int size; - atomic_t count; - phys_addr_t next; - struct { - phys_addr_t base; - phys_addr_t size; - } entry[0]; -}; - -struct efi_generic_dev_path { - u8 type; - u8 sub_type; - u16 length; -}; - -struct efi_variable { - efi_char16_t VariableName[512]; - efi_guid_t VendorGuid; - long unsigned int DataSize; - __u8 Data[1024]; - efi_status_t Status; - __u32 Attributes; -} __attribute__((packed)); - -struct efivar_entry { - struct efi_variable var; - struct list_head list; - struct kobject kobj; - bool scanning; - bool deleting; -}; - -struct variable_validate { - efi_guid_t vendor; - char *name; - bool (*validate)(efi_char16_t *, int, u8 *, long unsigned int); -}; - -typedef struct { - u32 version; - u32 num_entries; - u32 desc_size; - u32 reserved; - efi_memory_desc_t entry[0]; -} efi_memory_attributes_table_t; - -typedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *); - -struct linux_efi_tpm_eventlog { - u32 size; - u32 final_events_preboot_size; - u8 version; - u8 log[0]; -}; - -struct efi_tcg2_final_events_table { - u64 version; - u64 nr_events; - u8 events[0]; -}; - -struct tpm_digest { - u16 alg_id; - u8 digest[64]; -}; - -enum tpm_duration { - TPM_SHORT = 0, - TPM_MEDIUM = 1, - TPM_LONG = 2, - TPM_LONG_LONG = 3, - TPM_UNDEFINED = 4, - TPM_NUM_DURATIONS = 4, -}; - -enum tcpa_event_types { - PREBOOT = 0, - POST_CODE = 1, - UNUSED = 2, - NO_ACTION = 3, - SEPARATOR = 4, - ACTION = 5, - EVENT_TAG = 6, - SCRTM_CONTENTS = 7, - SCRTM_VERSION = 8, - CPU_MICROCODE = 9, - PLATFORM_CONFIG_FLAGS = 10, - TABLE_OF_DEVICES = 11, - COMPACT_HASH = 12, - IPL = 13, - IPL_PARTITION_DATA = 14, - NONHOST_CODE = 15, - NONHOST_CONFIG = 16, - NONHOST_INFO = 17, -}; - -struct tcg_efi_specid_event_algs { - u16 alg_id; - u16 digest_size; -}; - -struct tcg_efi_specid_event_head { - u8 signature[16]; - u32 platform_class; - u8 spec_version_minor; - u8 spec_version_major; - u8 spec_errata; - u8 uintnsize; - u32 num_algs; - struct tcg_efi_specid_event_algs digest_sizes[0]; -}; - -struct tcg_pcr_event { - u32 pcr_idx; - u32 event_type; - u8 digest[20]; - u32 event_size; - u8 event[0]; -}; - -struct tcg_event_field { - u32 event_size; - u8 event[0]; -}; - -struct tcg_pcr_event2_head { - u32 pcr_idx; - u32 event_type; - u32 count; - struct tpm_digest digests[0]; -}; - -typedef u64 efi_physical_addr_t; - -typedef struct { - u64 length; - u64 data; -} efi_capsule_block_desc_t; - -struct efi_memory_map_data { - phys_addr_t phys_map; - long unsigned int size; - long unsigned int desc_version; - long unsigned int desc_size; - long unsigned int flags; -}; - -struct efi_mem_range { - struct range range; - u64 attribute; -}; - -enum { - SYSTAB = 0, - MMBASE = 1, - MMSIZE = 2, - DCSIZE = 3, - DCVERS = 4, - PARAMCOUNT = 5, -}; - -struct efi_system_resource_entry_v1 { - efi_guid_t fw_class; - u32 fw_type; - u32 fw_version; - u32 lowest_supported_fw_version; - u32 capsule_flags; - u32 last_attempt_version; - u32 last_attempt_status; -}; - -struct efi_system_resource_table { - u32 fw_resource_count; - u32 fw_resource_count_max; - u64 fw_resource_version; - u8 entries[0]; -}; - -struct esre_entry { - union { - struct efi_system_resource_entry_v1 *esre1; - } esre; - struct kobject kobj; - struct list_head list; -}; - -struct esre_attribute { - struct attribute attr; - ssize_t (*show)(struct esre_entry *, char *); - ssize_t (*store)(struct esre_entry *, const char *, size_t); -}; - -enum efi_rts_ids { - EFI_NONE = 0, - EFI_GET_TIME = 1, - EFI_SET_TIME = 2, - EFI_GET_WAKEUP_TIME = 3, - EFI_SET_WAKEUP_TIME = 4, - EFI_GET_VARIABLE = 5, - EFI_GET_NEXT_VARIABLE = 6, - EFI_SET_VARIABLE = 7, - EFI_QUERY_VARIABLE_INFO = 8, - EFI_GET_NEXT_HIGH_MONO_COUNT = 9, - EFI_RESET_SYSTEM = 10, - EFI_UPDATE_CAPSULE = 11, - EFI_QUERY_CAPSULE_CAPS = 12, -}; - -struct efi_runtime_work { - void *arg1; - void *arg2; - void *arg3; - void *arg4; - void *arg5; - efi_status_t status; - struct work_struct work; - enum efi_rts_ids efi_rts_id; - struct completion efi_rts_comp; -}; - -typedef void *efi_event_t; - -typedef void (*efi_event_notify_t)(efi_event_t, void *); - -typedef enum { - EfiTimerCancel = 0, - EfiTimerPeriodic = 1, - EfiTimerRelative = 2, -} EFI_TIMER_DELAY; - -typedef void *efi_handle_t; - -typedef struct efi_generic_dev_path efi_device_path_protocol_t; - -union efi_boot_services { - struct { - efi_table_hdr_t hdr; - void *raise_tpl; - void *restore_tpl; - efi_status_t (*allocate_pages)(int, int, long unsigned int, efi_physical_addr_t *); - efi_status_t (*free_pages)(efi_physical_addr_t, long unsigned int); - efi_status_t (*get_memory_map)(long unsigned int *, void *, long unsigned int *, long unsigned int *, u32 *); - efi_status_t (*allocate_pool)(int, long unsigned int, void **); - efi_status_t (*free_pool)(void *); - efi_status_t (*create_event)(u32, long unsigned int, efi_event_notify_t, void *, efi_event_t *); - efi_status_t (*set_timer)(efi_event_t, EFI_TIMER_DELAY, u64); - efi_status_t (*wait_for_event)(long unsigned int, efi_event_t *, long unsigned int *); - void *signal_event; - efi_status_t (*close_event)(efi_event_t); - void *check_event; - void *install_protocol_interface; - void *reinstall_protocol_interface; - void *uninstall_protocol_interface; - efi_status_t (*handle_protocol)(efi_handle_t, efi_guid_t *, void **); - void *__reserved; - void *register_protocol_notify; - efi_status_t (*locate_handle)(int, efi_guid_t *, void *, long unsigned int *, efi_handle_t *); - efi_status_t (*locate_device_path)(efi_guid_t *, efi_device_path_protocol_t **, efi_handle_t *); - efi_status_t (*install_configuration_table)(efi_guid_t *, void *); - void *load_image; - void *start_image; - efi_status_t (*exit)(efi_handle_t, efi_status_t, long unsigned int, efi_char16_t *); - void *unload_image; - efi_status_t (*exit_boot_services)(efi_handle_t, long unsigned int); - void *get_next_monotonic_count; - efi_status_t (*stall)(long unsigned int); - void *set_watchdog_timer; - void *connect_controller; - efi_status_t (*disconnect_controller)(efi_handle_t, efi_handle_t, efi_handle_t); - void *open_protocol; - void *close_protocol; - void *open_protocol_information; - void *protocols_per_handle; - void *locate_handle_buffer; - efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **); - void *install_multiple_protocol_interfaces; - void *uninstall_multiple_protocol_interfaces; - void *calculate_crc32; - void *copy_mem; - void *set_mem; - void *create_event_ex; - }; - struct { - efi_table_hdr_t hdr; - u32 raise_tpl; - u32 restore_tpl; - u32 allocate_pages; - u32 free_pages; - u32 get_memory_map; - u32 allocate_pool; - u32 free_pool; - u32 create_event; - u32 set_timer; - u32 wait_for_event; - u32 signal_event; - u32 close_event; - u32 check_event; - u32 install_protocol_interface; - u32 reinstall_protocol_interface; - u32 uninstall_protocol_interface; - u32 handle_protocol; - u32 __reserved; - u32 register_protocol_notify; - u32 locate_handle; - u32 locate_device_path; - u32 install_configuration_table; - u32 load_image; - u32 start_image; - u32 exit; - u32 unload_image; - u32 exit_boot_services; - u32 get_next_monotonic_count; - u32 stall; - u32 set_watchdog_timer; - u32 connect_controller; - u32 disconnect_controller; - u32 open_protocol; - u32 close_protocol; - u32 open_protocol_information; - u32 protocols_per_handle; - u32 locate_handle_buffer; - u32 locate_protocol; - u32 install_multiple_protocol_interfaces; - u32 uninstall_multiple_protocol_interfaces; - u32 calculate_crc32; - u32 copy_mem; - u32 set_mem; - u32 create_event_ex; - } mixed_mode; -}; - -typedef union efi_boot_services efi_boot_services_t; - -typedef struct { - efi_table_hdr_t hdr; - u32 fw_vendor; - u32 fw_revision; - u32 con_in_handle; - u32 con_in; - u32 con_out_handle; - u32 con_out; - u32 stderr_handle; - u32 stderr; - u32 runtime; - u32 boottime; - u32 nr_tables; - u32 tables; -} efi_system_table_32_t; - -typedef struct { - u16 scan_code; - efi_char16_t unicode_char; -} efi_input_key_t; - -union efi_simple_text_input_protocol; - -typedef union efi_simple_text_input_protocol efi_simple_text_input_protocol_t; - -union efi_simple_text_input_protocol { - struct { - void *reset; - efi_status_t (*read_keystroke)(efi_simple_text_input_protocol_t *, efi_input_key_t *); - efi_event_t wait_for_key; - }; - struct { - u32 reset; - u32 read_keystroke; - u32 wait_for_key; - } mixed_mode; -}; - -union efi_simple_text_output_protocol; - -typedef union efi_simple_text_output_protocol efi_simple_text_output_protocol_t; - -union efi_simple_text_output_protocol { - struct { - void *reset; - efi_status_t (*output_string)(efi_simple_text_output_protocol_t *, efi_char16_t *); - void *test_string; - }; - struct { - u32 reset; - u32 output_string; - u32 test_string; - } mixed_mode; -}; - -typedef union { - struct { - efi_table_hdr_t hdr; - long unsigned int fw_vendor; - u32 fw_revision; - long unsigned int con_in_handle; - efi_simple_text_input_protocol_t *con_in; - long unsigned int con_out_handle; - efi_simple_text_output_protocol_t *con_out; - long unsigned int stderr_handle; - long unsigned int stderr; - efi_runtime_services_t *runtime; - efi_boot_services_t *boottime; - long unsigned int nr_tables; - long unsigned int tables; - }; - efi_system_table_32_t mixed_mode; -} efi_system_table_t; - -struct platform_suspend_ops { - int (*valid)(suspend_state_t); - int (*begin)(suspend_state_t); - int (*prepare)(); - int (*prepare_late)(); - int (*enter)(suspend_state_t); - void (*wake)(); - void (*finish)(); - bool (*suspend_again)(); - void (*end)(); - void (*recover)(); -}; - -typedef long unsigned int psci_fn(long unsigned int, long unsigned int, long unsigned int, long unsigned int); - -enum psci_function { - PSCI_FN_CPU_SUSPEND = 0, - PSCI_FN_CPU_ON = 1, - PSCI_FN_CPU_OFF = 2, - PSCI_FN_MIGRATE = 3, - PSCI_FN_MAX = 4, -}; - -typedef int (*psci_initcall_t)(const struct device_node *); - -struct soc_device___2; - -struct of_timer_irq { - int irq; - int index; - int percpu; - const char *name; - long unsigned int flags; - irq_handler_t handler; -}; - -struct of_timer_base { - void *base; - const char *name; - int index; -}; - -struct of_timer_clk { - struct clk *clk; - const char *name; - int index; - long unsigned int rate; - long unsigned int period; -}; - -struct timer_of { - unsigned int flags; - struct device_node *np; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct clock_event_device clkevt; - struct of_timer_base of_base; - struct of_timer_irq of_irq; - struct of_timer_clk of_clk; - void *private_data; - long: 64; - long: 64; -}; - -typedef int (*of_init_fn_1_ret)(struct device_node *); - -struct clocksource_mmio { - void *reg; - struct clocksource clksrc; -}; - -enum arch_timer_reg { - ARCH_TIMER_REG_CTRL = 0, - ARCH_TIMER_REG_TVAL = 1, -}; - -enum arch_timer_ppi_nr { - ARCH_TIMER_PHYS_SECURE_PPI = 0, - ARCH_TIMER_PHYS_NONSECURE_PPI = 1, - ARCH_TIMER_VIRT_PPI = 2, - ARCH_TIMER_HYP_PPI = 3, - ARCH_TIMER_MAX_TIMER_PPI = 4, -}; - -enum arch_timer_spi_nr { - ARCH_TIMER_PHYS_SPI = 0, - ARCH_TIMER_VIRT_SPI = 1, - ARCH_TIMER_MAX_TIMER_SPI = 2, -}; - -struct arch_timer_mem_frame { - bool valid; - phys_addr_t cntbase; - size_t size; - int phys_irq; - int virt_irq; -}; - -struct arch_timer_mem { - phys_addr_t cntctlbase; - size_t size; - struct arch_timer_mem_frame frame[8]; -}; - -enum arch_timer_erratum_match_type { - ate_match_dt = 0, - ate_match_local_cap_id = 1, - ate_match_acpi_oem_info = 2, -}; - -struct arch_timer_erratum_workaround { - enum arch_timer_erratum_match_type match_type; - const void *id; - const char *desc; - u32 (*read_cntp_tval_el0)(); - u32 (*read_cntv_tval_el0)(); - u64 (*read_cntpct_el0)(); - u64 (*read_cntvct_el0)(); - int (*set_next_event_phys)(long unsigned int, struct clock_event_device *); - int (*set_next_event_virt)(long unsigned int, struct clock_event_device *); - bool disable_compat_vdso; -}; - -struct acpi_table_header { - char signature[4]; - u32 length; - u8 revision; - u8 checksum; - char oem_id[6]; - char oem_table_id[8]; - u32 oem_revision; - char asl_compiler_id[4]; - u32 asl_compiler_revision; -}; - -struct arch_timer { - void *base; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct clock_event_device evt; -}; - -struct ate_acpi_oem_info { - char oem_id[7]; - char oem_table_id[9]; - u32 oem_revision; -}; - -typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, const void *); - -struct sp804_timer { - int load; - int load_h; - int value; - int value_h; - int ctrl; - int intclr; - int ris; - int mis; - int bgload; - int bgload_h; - int timer_base[2]; - int width; -}; - -struct sp804_clkevt { - void *base; - void *load; - void *load_h; - void *value; - void *value_h; - void *ctrl; - void *intclr; - void *ris; - void *mis; - void *bgload; - void *bgload_h; - long unsigned int reload; - int width; -}; - -struct hid_device_id { - __u16 bus; - __u16 group; - __u32 vendor; - __u32 product; - kernel_ulong_t driver_data; -}; - -struct hid_item { - unsigned int format; - __u8 size; - __u8 type; - __u8 tag; - union { - __u8 u8; - __s8 s8; - __u16 u16; - __s16 s16; - __u32 u32; - __s32 s32; - __u8 *longdata; - } data; -}; - -struct hid_global { - unsigned int usage_page; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned int unit; - unsigned int report_id; - unsigned int report_size; - unsigned int report_count; -}; - -struct hid_local { - unsigned int usage[12288]; - u8 usage_size[12288]; - unsigned int collection_index[12288]; - unsigned int usage_index; - unsigned int usage_minimum; - unsigned int delimiter_depth; - unsigned int delimiter_branch; -}; - -struct hid_collection { - int parent_idx; - unsigned int type; - unsigned int usage; - unsigned int level; -}; - -struct hid_usage { - unsigned int hid; - unsigned int collection_index; - unsigned int usage_index; - __s8 resolution_multiplier; - __s8 wheel_factor; - __u16 code; - __u8 type; - __s8 hat_min; - __s8 hat_max; - __s8 hat_dir; - __s16 wheel_accumulated; -}; - -struct hid_report; - -struct hid_input; - -struct hid_field { - unsigned int physical; - unsigned int logical; - unsigned int application; - struct hid_usage *usage; - unsigned int maxusage; - unsigned int flags; - unsigned int report_offset; - unsigned int report_size; - unsigned int report_count; - unsigned int report_type; - __s32 *value; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned int unit; - struct hid_report *report; - unsigned int index; - struct hid_input *hidinput; - __u16 dpad; -}; - -struct hid_device; - -struct hid_report { - struct list_head list; - struct list_head hidinput_list; - unsigned int id; - unsigned int type; - unsigned int application; - struct hid_field *field[256]; - unsigned int maxfield; - unsigned int size; - struct hid_device *device; -}; - -struct hid_input { - struct list_head list; - struct hid_report *report; - struct input_dev *input; - const char *name; - bool registered; - struct list_head reports; - unsigned int application; -}; - -enum hid_type { - HID_TYPE_OTHER = 0, - HID_TYPE_USBMOUSE = 1, - HID_TYPE_USBNONE = 2, -}; - -struct hid_report_enum { - unsigned int numbered; - struct list_head report_list; - struct hid_report *report_id_hash[256]; -}; - -enum hid_battery_status { - HID_BATTERY_UNKNOWN = 0, - HID_BATTERY_QUERIED = 1, - HID_BATTERY_REPORTED = 2, -}; - -struct hid_driver; - -struct hid_ll_driver; - -struct hid_device { - __u8 *dev_rdesc; - unsigned int dev_rsize; - __u8 *rdesc; - unsigned int rsize; - struct hid_collection *collection; - unsigned int collection_size; - unsigned int maxcollection; - unsigned int maxapplication; - __u16 bus; - __u16 group; - __u32 vendor; - __u32 product; - __u32 version; - enum hid_type type; - unsigned int country; - struct hid_report_enum report_enum[3]; - struct work_struct led_work; - struct semaphore driver_input_lock; - struct device dev; - struct hid_driver *driver; - struct hid_ll_driver *ll_driver; - struct mutex ll_open_lock; - unsigned int ll_open_count; - struct power_supply *battery; - __s32 battery_capacity; - __s32 battery_min; - __s32 battery_max; - __s32 battery_report_type; - __s32 battery_report_id; - enum hid_battery_status battery_status; - bool battery_avoid_query; - long unsigned int status; - unsigned int claimed; - unsigned int quirks; - bool io_started; - struct list_head inputs; - void *hiddev; - void *hidraw; - char name[128]; - char phys[64]; - char uniq[64]; - void *driver_data; - int (*ff_init)(struct hid_device *); - int (*hiddev_connect)(struct hid_device *, unsigned int); - void (*hiddev_disconnect)(struct hid_device *); - void (*hiddev_hid_event)(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); - void (*hiddev_report_event)(struct hid_device *, struct hid_report *); - short unsigned int debug; - struct dentry *debug_dir; - struct dentry *debug_rdesc; - struct dentry *debug_events; - struct list_head debug_list; - spinlock_t debug_list_lock; - wait_queue_head_t debug_wait; -}; - -struct hid_report_id; - -struct hid_usage_id; - -struct hid_driver { - char *name; - const struct hid_device_id *id_table; - struct list_head dyn_list; - spinlock_t dyn_lock; - bool (*match)(struct hid_device *, bool); - int (*probe)(struct hid_device *, const struct hid_device_id *); - void (*remove)(struct hid_device *); - const struct hid_report_id *report_table; - int (*raw_event)(struct hid_device *, struct hid_report *, u8 *, int); - const struct hid_usage_id *usage_table; - int (*event)(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); - void (*report)(struct hid_device *, struct hid_report *); - __u8 * (*report_fixup)(struct hid_device *, __u8 *, unsigned int *); - int (*input_mapping)(struct hid_device *, struct hid_input *, struct hid_field *, struct hid_usage *, long unsigned int **, int *); - int (*input_mapped)(struct hid_device *, struct hid_input *, struct hid_field *, struct hid_usage *, long unsigned int **, int *); - int (*input_configured)(struct hid_device *, struct hid_input *); - void (*feature_mapping)(struct hid_device *, struct hid_field *, struct hid_usage *); - int (*suspend)(struct hid_device *, pm_message_t); - int (*resume)(struct hid_device *); - int (*reset_resume)(struct hid_device *); - struct device_driver driver; -}; - -struct hid_ll_driver { - int (*start)(struct hid_device *); - void (*stop)(struct hid_device *); - int (*open)(struct hid_device *); - void (*close)(struct hid_device *); - int (*power)(struct hid_device *, int); - int (*parse)(struct hid_device *); - void (*request)(struct hid_device *, struct hid_report *, int); - int (*wait)(struct hid_device *); - int (*raw_request)(struct hid_device *, unsigned char, __u8 *, size_t, unsigned char, int); - int (*output_report)(struct hid_device *, __u8 *, size_t); - int (*idle)(struct hid_device *, int, int, int); -}; - -struct hid_parser { - struct hid_global global; - struct hid_global global_stack[4]; - unsigned int global_stack_ptr; - struct hid_local local; - unsigned int *collection_stack; - unsigned int collection_stack_ptr; - unsigned int collection_stack_size; - struct hid_device *device; - unsigned int scan_flags; -}; - -struct hid_report_id { - __u32 report_type; -}; - -struct hid_usage_id { - __u32 usage_hid; - __u32 usage_type; - __u32 usage_code; -}; - -struct hiddev { - int minor; - int exist; - int open; - struct mutex existancelock; - wait_queue_head_t wait; - struct hid_device *hid; - struct list_head list; - spinlock_t list_lock; - bool initialized; -}; - -struct hidraw { - unsigned int minor; - int exist; - int open; - wait_queue_head_t wait; - struct hid_device *hid; - struct device *dev; - spinlock_t list_lock; - struct list_head list; -}; - -struct hid_dynid { - struct list_head list; - struct hid_device_id id; -}; - -typedef bool (*hid_usage_cmp_t)(struct hid_usage *, unsigned int, unsigned int); - -struct quirks_list_struct { - struct hid_device_id hid_bl_item; - struct list_head node; -}; - -struct hid_debug_list { - struct { - union { - struct __kfifo kfifo; - char *type; - const char *const_type; - char (*rectype)[0]; - char *ptr; - const char *ptr_const; - }; - char buf[0]; - } hid_debug_fifo; - struct fasync_struct *fasync; - struct hid_device *hdev; - struct list_head node; - struct mutex read_mutex; -}; - -struct hid_usage_entry { - unsigned int page; - unsigned int usage; - const char *description; -}; - -struct hidraw_devinfo { - __u32 bustype; - __s16 vendor; - __s16 product; -}; - -struct hidraw_report { - __u8 *value; - int len; -}; - -struct hidraw_list { - struct hidraw_report buffer[64]; - int head; - int tail; - struct fasync_struct *fasync; - struct hidraw *hidraw; - struct list_head node; - struct mutex read_mutex; -}; - -struct hid_control_fifo { - unsigned char dir; - struct hid_report *report; - char *raw_report; -}; - -struct hid_output_fifo { - struct hid_report *report; - char *raw_report; -}; - -struct hid_class_descriptor { - __u8 bDescriptorType; - __le16 wDescriptorLength; -} __attribute__((packed)); - -struct hid_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdHID; - __u8 bCountryCode; - __u8 bNumDescriptors; - struct hid_class_descriptor desc[1]; -} __attribute__((packed)); - -struct usbhid_device { - struct hid_device *hid; - struct usb_interface *intf; - int ifnum; - unsigned int bufsize; - struct urb *urbin; - char *inbuf; - dma_addr_t inbuf_dma; - struct urb *urbctrl; - struct usb_ctrlrequest *cr; - struct hid_control_fifo ctrl[256]; - unsigned char ctrlhead; - unsigned char ctrltail; - char *ctrlbuf; - dma_addr_t ctrlbuf_dma; - long unsigned int last_ctrl; - struct urb *urbout; - struct hid_output_fifo out[256]; - unsigned char outhead; - unsigned char outtail; - char *outbuf; - dma_addr_t outbuf_dma; - long unsigned int last_out; - struct mutex mutex; - spinlock_t lock; - long unsigned int iofl; - struct timer_list io_retry; - long unsigned int stop_retry; - unsigned int retry_delay; - struct work_struct reset_work; - wait_queue_head_t wait; -}; - -struct hiddev_event { - unsigned int hid; - int value; -}; - -struct hiddev_devinfo { - __u32 bustype; - __u32 busnum; - __u32 devnum; - __u32 ifnum; - __s16 vendor; - __s16 product; - __s16 version; - __u32 num_applications; -}; - -struct hiddev_collection_info { - __u32 index; - __u32 type; - __u32 usage; - __u32 level; -}; - -struct hiddev_report_info { - __u32 report_type; - __u32 report_id; - __u32 num_fields; -}; - -struct hiddev_field_info { - __u32 report_type; - __u32 report_id; - __u32 field_index; - __u32 maxusage; - __u32 flags; - __u32 physical; - __u32 logical; - __u32 application; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __u32 unit_exponent; - __u32 unit; -}; - -struct hiddev_usage_ref { - __u32 report_type; - __u32 report_id; - __u32 field_index; - __u32 usage_index; - __u32 usage_code; - __s32 value; -}; - -struct hiddev_usage_ref_multi { - struct hiddev_usage_ref uref; - __u32 num_values; - __s32 values[1024]; -}; - -struct hiddev_list { - struct hiddev_usage_ref buffer[2048]; - int head; - int tail; - unsigned int flags; - struct fasync_struct *fasync; - struct hiddev *hiddev; - struct list_head node; - struct mutex thread_lock; -}; - -struct pidff_usage { - struct hid_field *field; - s32 *value; -}; - -struct pidff_device { - struct hid_device *hid; - struct hid_report *reports[13]; - struct pidff_usage set_effect[7]; - struct pidff_usage set_envelope[5]; - struct pidff_usage set_condition[8]; - struct pidff_usage set_periodic[5]; - struct pidff_usage set_constant[2]; - struct pidff_usage set_ramp[3]; - struct pidff_usage device_gain[1]; - struct pidff_usage block_load[2]; - struct pidff_usage pool[3]; - struct pidff_usage effect_operation[2]; - struct pidff_usage block_free[1]; - struct hid_field *create_new_effect_type; - struct hid_field *set_effect_type; - struct hid_field *effect_direction; - struct hid_field *device_control; - struct hid_field *block_load_status; - struct hid_field *effect_operation_status; - int control_id[2]; - int type_id[11]; - int status_id[2]; - int operation_id[2]; - int pid_id[64]; -}; - -struct alias_prop { - struct list_head link; - const char *alias; - struct device_node *np; - int id; - char stem[0]; -}; - -struct of_dev_auxdata { - char *compatible; - resource_size_t phys_addr; - char *name; - void *platform_data; -}; - -struct of_endpoint { - unsigned int port; - unsigned int id; - const struct device_node *local_node; -}; - -struct supplier_bindings { - struct device_node * (*parse_prop)(struct device_node *, const char *, int); -}; - -struct cfs_overlay_item { - struct config_item item; - char path[4096]; - const struct firmware *fw; - struct device_node *overlay; - int ov_id; - void *dtbo; - int dtbo_size; -}; - -struct of_changeset_entry { - struct list_head node; - long unsigned int action; - struct device_node *np; - struct property *prop; - struct property *old_prop; -}; - -struct of_changeset { - struct list_head entries; -}; - -struct of_bus___2 { - void (*count_cells)(const void *, int, int *, int *); - u64 (*map)(__be32 *, const __be32 *, int, int, int); - int (*translate)(__be32 *, u64, int); -}; - -struct of_bus { - const char *name; - const char *addresses; - int (*match)(struct device_node *); - void (*count_cells)(struct device_node *, int *, int *); - u64 (*map)(__be32 *, const __be32 *, int, int, int); - int (*translate)(__be32 *, u64, int); - bool has_flags; - unsigned int (*get_flags)(const __be32 *); -}; - -struct of_intc_desc { - struct list_head list; - of_irq_init_cb_t irq_init_cb; - struct device_node *dev; - struct device_node *interrupt_parent; -}; - -struct rmem_assigned_device { - struct device *dev; - struct reserved_mem *rmem; - struct list_head list; -}; - -enum of_overlay_notify_action { - OF_OVERLAY_PRE_APPLY = 0, - OF_OVERLAY_POST_APPLY = 1, - OF_OVERLAY_PRE_REMOVE = 2, - OF_OVERLAY_POST_REMOVE = 3, -}; - -struct of_overlay_notify_data { - struct device_node *overlay; - struct device_node *target; -}; - -struct target { - struct device_node *np; - bool in_livetree; -}; - -struct fragment { - struct device_node *overlay; - struct device_node *target; -}; - -struct overlay_changeset { - int id; - struct list_head ovcs_list; - const void *fdt; - struct device_node *overlay_tree; - int count; - struct fragment *fragments; - bool symbols_fragment; - struct of_changeset cset; -}; - -struct ashmem_pin { - __u32 offset; - __u32 len; -}; - -struct ashmem_area { - char name[267]; - struct list_head unpinned_list; - struct file *file; - size_t size; - long unsigned int prot_mask; -}; - -struct ashmem_range { - struct list_head lru; - struct list_head unpinned; - struct ashmem_area *asma; - size_t pgstart; - size_t pgend; - unsigned int purged; -}; - -enum vchiq_reason { - VCHIQ_SERVICE_OPENED = 0, - VCHIQ_SERVICE_CLOSED = 1, - VCHIQ_MESSAGE_AVAILABLE = 2, - VCHIQ_BULK_TRANSMIT_DONE = 3, - VCHIQ_BULK_RECEIVE_DONE = 4, - VCHIQ_BULK_TRANSMIT_ABORTED = 5, - VCHIQ_BULK_RECEIVE_ABORTED = 6, -}; - -enum vchiq_status { - VCHIQ_ERROR = 4294967295, - VCHIQ_SUCCESS = 0, - VCHIQ_RETRY = 1, -}; - -enum vchiq_bulk_mode { - VCHIQ_BULK_MODE_CALLBACK = 0, - VCHIQ_BULK_MODE_BLOCKING = 1, - VCHIQ_BULK_MODE_NOCALLBACK = 2, - VCHIQ_BULK_MODE_WAITING = 3, -}; - -enum vchiq_service_option { - VCHIQ_SERVICE_OPTION_AUTOCLOSE = 0, - VCHIQ_SERVICE_OPTION_SLOT_QUOTA = 1, - VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA = 2, - VCHIQ_SERVICE_OPTION_SYNCHRONOUS = 3, - VCHIQ_SERVICE_OPTION_TRACE = 4, -}; - -struct vchiq_header { - int msgid; - unsigned int size; - char data[0]; -}; - -struct vchiq_service_base { - int fourcc; - enum vchiq_status (*callback)(enum vchiq_reason, struct vchiq_header *, unsigned int, void *); - void *userdata; -}; - -struct vchiq_service_params_kernel { - int fourcc; - enum vchiq_status (*callback)(enum vchiq_reason, struct vchiq_header *, unsigned int, void *); - void *userdata; - short int version; - short int version_min; -}; - -typedef uint32_t BITSET_T; - -enum { - DEBUG_ENTRIES = 0, - DEBUG_SLOT_HANDLER_COUNT = 1, - DEBUG_SLOT_HANDLER_LINE = 2, - DEBUG_PARSE_LINE = 3, - DEBUG_PARSE_HEADER = 4, - DEBUG_PARSE_MSGID = 5, - DEBUG_AWAIT_COMPLETION_LINE = 6, - DEBUG_DEQUEUE_MESSAGE_LINE = 7, - DEBUG_SERVICE_CALLBACK_LINE = 8, - DEBUG_MSG_QUEUE_FULL_COUNT = 9, - DEBUG_COMPLETION_QUEUE_FULL_COUNT = 10, - DEBUG_MAX = 11, -}; - -enum vchiq_connstate { - VCHIQ_CONNSTATE_DISCONNECTED = 0, - VCHIQ_CONNSTATE_CONNECTING = 1, - VCHIQ_CONNSTATE_CONNECTED = 2, - VCHIQ_CONNSTATE_PAUSING = 3, - VCHIQ_CONNSTATE_PAUSE_SENT = 4, - VCHIQ_CONNSTATE_PAUSED = 5, - VCHIQ_CONNSTATE_RESUMING = 6, - VCHIQ_CONNSTATE_PAUSE_TIMEOUT = 7, - VCHIQ_CONNSTATE_RESUME_TIMEOUT = 8, -}; - -enum { - VCHIQ_SRVSTATE_FREE = 0, - VCHIQ_SRVSTATE_HIDDEN = 1, - VCHIQ_SRVSTATE_LISTENING = 2, - VCHIQ_SRVSTATE_OPENING = 3, - VCHIQ_SRVSTATE_OPEN = 4, - VCHIQ_SRVSTATE_OPENSYNC = 5, - VCHIQ_SRVSTATE_CLOSESENT = 6, - VCHIQ_SRVSTATE_CLOSERECVD = 7, - VCHIQ_SRVSTATE_CLOSEWAIT = 8, - VCHIQ_SRVSTATE_CLOSED = 9, -}; - -enum { - VCHIQ_POLL_TERMINATE = 0, - VCHIQ_POLL_REMOVE = 1, - VCHIQ_POLL_TXNOTIFY = 2, - VCHIQ_POLL_RXNOTIFY = 3, - VCHIQ_POLL_COUNT = 4, -}; - -enum vchiq_bulk_dir { - VCHIQ_BULK_TRANSMIT = 0, - VCHIQ_BULK_RECEIVE = 1, -}; - -typedef void (*vchiq_userdata_term)(void *); - -struct vchiq_bulk { - short int mode; - short int dir; - void *userdata; - dma_addr_t data; - int size; - void *remote_data; - int remote_size; - int actual; -}; - -struct vchiq_bulk_queue { - int local_insert; - int remote_insert; - int process; - int remote_notify; - int remove; - struct vchiq_bulk bulks[4]; -}; - -struct remote_event { - int armed; - int fired; - u32 __unused; -}; - -struct vchiq_slot { - char data[4096]; -}; - -struct vchiq_slot_info { - short int use_count; - short int release_count; -}; - -struct service_stats_struct { - int quota_stalls; - int slot_stalls; - int bulk_stalls; - int error_count; - int ctrl_tx_count; - int ctrl_rx_count; - int bulk_tx_count; - int bulk_rx_count; - int bulk_aborted_count; - uint64_t ctrl_tx_bytes; - uint64_t ctrl_rx_bytes; - uint64_t bulk_tx_bytes; - uint64_t bulk_rx_bytes; -}; - -struct vchiq_state; - -struct vchiq_instance; - -struct vchiq_service { - struct vchiq_service_base base; - unsigned int handle; - struct kref ref_count; - struct callback_head rcu; - int srvstate; - vchiq_userdata_term userdata_term; - unsigned int localport; - unsigned int remoteport; - int public_fourcc; - int client_id; - char auto_close; - char sync; - char closing; - char trace; - atomic_t poll_flags; - short int version; - short int version_min; - short int peer_version; - struct vchiq_state *state; - struct vchiq_instance *instance; - int service_use_count; - struct vchiq_bulk_queue bulk_tx; - struct vchiq_bulk_queue bulk_rx; - struct completion remove_event; - struct completion bulk_remove_event; - struct mutex bulk_mutex; - struct service_stats_struct stats; - int msg_queue_read; - int msg_queue_write; - struct completion msg_queue_pop; - struct completion msg_queue_push; - struct vchiq_header *msg_queue[128]; -}; - -struct state_stats_struct { - int slot_stalls; - int data_stalls; - int ctrl_tx_count; - int ctrl_rx_count; - int error_count; -}; - -struct vchiq_service_quota { - short unsigned int slot_quota; - short unsigned int slot_use_count; - short unsigned int message_quota; - short unsigned int message_use_count; - struct completion quota_event; - int previous_tx_index; -}; - -struct opaque_platform_state; - -struct vchiq_shared_state; - -struct vchiq_state { - int id; - int initialised; - enum vchiq_connstate conn_state; - short int version_common; - struct vchiq_shared_state *local; - struct vchiq_shared_state *remote; - struct vchiq_slot *slot_data; - short unsigned int default_slot_quota; - short unsigned int default_message_quota; - struct completion connect; - struct mutex mutex; - struct vchiq_instance **instance; - struct task_struct *slot_handler_thread; - struct task_struct *recycle_thread; - struct task_struct *sync_thread; - wait_queue_head_t trigger_event; - wait_queue_head_t recycle_event; - wait_queue_head_t sync_trigger_event; - wait_queue_head_t sync_release_event; - char *tx_data; - char *rx_data; - struct vchiq_slot_info *rx_info; - struct mutex slot_mutex; - struct mutex recycle_mutex; - struct mutex sync_mutex; - struct mutex bulk_transfer_mutex; - int rx_pos; - int local_tx_pos; - int slot_queue_available; - int poll_needed; - int previous_data_index; - short unsigned int data_use_count; - short unsigned int data_quota; - atomic_t poll_services[128]; - int unused_service; - struct completion slot_available_event; - struct completion slot_remove_event; - struct completion data_quota_event; - struct state_stats_struct stats; - struct vchiq_service *services[4096]; - struct vchiq_service_quota service_quotas[4096]; - struct vchiq_slot_info slot_info[128]; - struct opaque_platform_state *platform_state; -}; - -struct vchiq_shared_state { - int initialised; - int slot_first; - int slot_last; - int slot_sync; - struct remote_event trigger; - int tx_pos; - struct remote_event recycle; - int slot_queue_recycle; - struct remote_event sync_trigger; - struct remote_event sync_release; - int slot_queue[64]; - int debug[11]; -}; - -struct vchiq_slot_zero { - int magic; - short int version; - short int version_min; - int slot_zero_size; - int slot_size; - int max_slots; - int max_slots_per_side; - int platform_data[2]; - struct vchiq_shared_state master; - struct vchiq_shared_state slave; - struct vchiq_slot_info slots[128]; -}; - -struct bulk_waiter { - struct vchiq_bulk *bulk; - struct completion event; - int actual; -}; - -struct vchiq_config { - unsigned int max_msg_size; - unsigned int bulk_threshold; - unsigned int max_outstanding_bulks; - unsigned int max_services; - short int version; - short int version_min; -}; - -struct vchiq_open_payload { - int fourcc; - int client_id; - short int version; - short int version_min; -}; - -struct vchiq_openack_payload { - short int version; -}; - -enum { - QMFLAGS_IS_BLOCKING = 1, - QMFLAGS_NO_MUTEX_LOCK = 2, - QMFLAGS_NO_MUTEX_UNLOCK = 4, -}; - -struct vchiq_element { - const void *data; - unsigned int size; -}; - -struct vchiq_completion_data_kernel { - enum vchiq_reason reason; - struct vchiq_header *header; - void *service_userdata; - void *bulk_userdata; -}; - -struct vchiq_debugfs_node { - struct dentry *dentry; -}; - -struct vchiq_instance { - struct vchiq_state *state; - struct vchiq_completion_data_kernel completions[128]; - int completion_insert; - int completion_remove; - struct completion insert_event; - struct completion remove_event; - struct mutex completion_mutex; - int connected; - int closing; - int pid; - int mark; - int use_close_delivered; - int trace; - struct list_head bulk_waiter_list; - struct mutex bulk_waiter_list_mutex; - struct vchiq_debugfs_node debugfs_node; -}; - -struct vchiq_service_params { - int fourcc; - enum vchiq_status (*callback)(enum vchiq_reason, struct vchiq_header *, unsigned int, void *); - void *userdata; - short int version; - short int version_min; -}; - -struct vchiq_create_service { - struct vchiq_service_params params; - int is_open; - int is_vchi; - unsigned int handle; -}; - -struct vchiq_queue_message { - unsigned int handle; - unsigned int count; - const struct vchiq_element *elements; -}; - -struct vchiq_queue_bulk_transfer { - unsigned int handle; - void *data; - unsigned int size; - void *userdata; - enum vchiq_bulk_mode mode; -}; - -struct vchiq_completion_data { - enum vchiq_reason reason; - struct vchiq_header *header; - void *service_userdata; - void *bulk_userdata; -}; - -struct vchiq_await_completion { - unsigned int count; - struct vchiq_completion_data *buf; - unsigned int msgbufsize; - unsigned int msgbufcount; - void **msgbufs; -}; - -struct vchiq_dequeue_message { - unsigned int handle; - int blocking; - unsigned int bufsize; - void *buf; -}; - -struct vchiq_get_config { - unsigned int config_size; - struct vchiq_config *pconfig; -}; - -struct vchiq_set_service_option { - unsigned int handle; - enum vchiq_service_option option; - int value; -}; - -enum USE_TYPE_E { - USE_TYPE_SERVICE = 0, - USE_TYPE_VCHIQ = 1, -}; - -struct vchiq_arm_state { - struct task_struct *ka_thread; - struct completion ka_evt; - atomic_t ka_use_count; - atomic_t ka_use_ack_count; - atomic_t ka_release_count; - rwlock_t susp_res_lock; - struct vchiq_state *state; - int videocore_use_count; - int peer_use_count; - int first_connect; -}; - -struct vchiq_drvdata { - const unsigned int cache_line_size; - const bool use_36bit_addrs; - struct rpi_firmware *fw; -}; - -struct user_service { - struct vchiq_service *service; - void *userdata; - struct vchiq_instance *instance; - char is_vchi; - char dequeue_pending; - char close_pending; - int message_available_pos; - int msg_insert; - int msg_remove; - struct completion insert_event; - struct completion remove_event; - struct completion close_event; - struct vchiq_header *msg_queue[128]; -}; - -struct bulk_waiter_node { - struct bulk_waiter bulk_waiter; - int pid; - struct list_head list; -}; - -struct dump_context { - char *buf; - size_t actual; - size_t space; - loff_t offset; -}; - -struct vchiq_io_copy_callback_context { - struct vchiq_element *element; - size_t element_offset; - long unsigned int elements_to_go; -}; - -struct vchiq_completion_data32 { - enum vchiq_reason reason; - compat_uptr_t header; - compat_uptr_t service_userdata; - compat_uptr_t bulk_userdata; -}; - -struct vchiq_service_params32 { - int fourcc; - compat_uptr_t callback; - compat_uptr_t userdata; - short int version; - short int version_min; -}; - -struct vchiq_create_service32 { - struct vchiq_service_params32 params; - int is_open; - int is_vchi; - unsigned int handle; -}; - -struct vchiq_element32 { - compat_uptr_t data; - unsigned int size; -}; - -struct vchiq_queue_message32 { - unsigned int handle; - unsigned int count; - compat_uptr_t elements; -}; - -struct vchiq_queue_bulk_transfer32 { - unsigned int handle; - compat_uptr_t data; - unsigned int size; - compat_uptr_t userdata; - enum vchiq_bulk_mode mode; -}; - -struct vchiq_await_completion32 { - unsigned int count; - compat_uptr_t buf; - unsigned int msgbufsize; - unsigned int msgbufcount; - compat_uptr_t msgbufs; -}; - -struct vchiq_dequeue_message32 { - unsigned int handle; - int blocking; - unsigned int bufsize; - compat_uptr_t buf; -}; - -struct vchiq_get_config32 { - unsigned int config_size; - compat_uptr_t pconfig; -}; - -struct service_data_struct { - int fourcc; - int clientid; - int use_count; -}; - -struct pagelist { - u32 length; - u16 type; - u16 offset; - u32 addrs[1]; -}; - -struct vchiq_2835_state { - int inited; - struct vchiq_arm_state arm_state; -}; - -struct vchiq_pagelist_info { - struct pagelist *pagelist; - size_t pagelist_buffer_size; - dma_addr_t dma_addr; - bool is_from_pool; - enum dma_data_direction dma_dir; - unsigned int num_pages; - unsigned int pages_need_release; - struct page **pages; - struct scatterlist *scatterlist; - unsigned int scatterlist_mapped; -}; - -struct vchiq_debugfs_log_entry { - const char *name; - void *plevel; -}; - -typedef void (*VCHIQ_CONNECTED_CALLBACK_T)(); - -struct mbox_chan___2; - -struct mbox_chan_ops { - int (*send_data)(struct mbox_chan___2 *, void *); - int (*flush)(struct mbox_chan___2 *, long unsigned int); - int (*startup)(struct mbox_chan___2 *); - void (*shutdown)(struct mbox_chan___2 *); - bool (*last_tx_done)(struct mbox_chan___2 *); - bool (*peek_data)(struct mbox_chan___2 *); -}; - -struct mbox_controller; - -struct mbox_chan___2 { - struct mbox_controller *mbox; - unsigned int txdone_method; - struct mbox_client *cl; - struct completion tx_complete; - void *active_req; - unsigned int msg_count; - unsigned int msg_free; - void *msg_data[20]; - spinlock_t lock; - void *con_priv; -}; - -struct mbox_controller { - struct device *dev; - const struct mbox_chan_ops *ops; - struct mbox_chan___2 *chans; - int num_chans; - bool txdone_irq; - bool txdone_poll; - unsigned int txpoll_period; - struct mbox_chan___2 * (*of_xlate)(struct mbox_controller *, const struct of_phandle_args *); - struct hrtimer poll_hrt; - struct list_head node; -}; - -struct bcm2835_mbox { - void *regs; - spinlock_t lock; - struct mbox_controller controller; -}; - -union extcon_property_value { - int intval; -}; - -struct extcon_cable; - -struct extcon_dev___2 { - const char *name; - const unsigned int *supported_cable; - const u32 *mutually_exclusive; - struct device dev; - struct raw_notifier_head nh_all; - struct raw_notifier_head *nh; - struct list_head entry; - int max_supported; - spinlock_t lock; - u32 state; - struct device_type extcon_dev_type; - struct extcon_cable *cables; - struct attribute_group attr_g_muex; - struct attribute **attrs_muex; - struct device_attribute *d_attrs_muex; -}; - -struct extcon_cable { - struct extcon_dev___2 *edev; - int cable_index; - struct attribute_group attr_g; - struct device_attribute attr_name; - struct device_attribute attr_state; - struct attribute *attrs[3]; - union extcon_property_value usb_propval[3]; - union extcon_property_value chg_propval[1]; - union extcon_property_value jack_propval[1]; - union extcon_property_value disp_propval[2]; - long unsigned int usb_bits[1]; - long unsigned int chg_bits[1]; - long unsigned int jack_bits[1]; - long unsigned int disp_bits[1]; -}; - -struct __extcon_info { - unsigned int type; - unsigned int id; - const char *name; -}; - -struct extcon_dev_notifier_devres { - struct extcon_dev___2 *edev; - unsigned int id; - struct notifier_block *nb; -}; - -struct pmu_irq_ops { - void (*enable_pmuirq)(unsigned int); - void (*disable_pmuirq)(unsigned int); - void (*free_pmuirq)(unsigned int, int, void *); -}; - -typedef int (*armpmu_init_fn)(struct arm_pmu *); - -struct pmu_probe_info { - unsigned int cpuid; - unsigned int mask; - armpmu_init_fn init; -}; - -struct binderfs_device { - char name[256]; - __u32 major; - __u32 minor; -}; - -struct binder_node; - -struct binder_context { - struct binder_node *binder_context_mgr_node; - struct mutex context_mgr_node_lock; - kuid_t binder_context_mgr_uid; - const char *name; -}; - -struct binder_device { - struct hlist_node hlist; - struct miscdevice miscdev; - struct binder_context context; - struct inode *binderfs_inode; - refcount_t ref; -}; - -struct binderfs_mount_opts { - int max; - int stats_mode; -}; - -struct binderfs_info { - struct ipc_namespace *ipc_ns; - struct dentry *control_dentry; - kuid_t root_uid; - kgid_t root_gid; - struct binderfs_mount_opts mount_opts; - int device_count; - struct dentry *proc_log_dir; -}; - -struct binder_transaction_log_entry { - int debug_id; - int debug_id_done; - int call_type; - int from_proc; - int from_thread; - int target_handle; - int to_proc; - int to_thread; - int to_node; - int data_size; - int offsets_size; - int return_error_line; - uint32_t return_error; - uint32_t return_error_param; - char context_name[256]; -}; - -struct binder_transaction_log { - atomic_t cur; - bool full; - struct binder_transaction_log_entry entry[32]; -}; - -enum binderfs_param { - Opt_max___2 = 0, - Opt_stats_mode = 1, -}; - -enum binderfs_stats_mode { - binderfs_stats_mode_unset = 0, - binderfs_stats_mode_global = 1, -}; - -enum { - BINDER_TYPE_BINDER = 1935813253, - BINDER_TYPE_WEAK_BINDER = 2002922117, - BINDER_TYPE_HANDLE = 1936206469, - BINDER_TYPE_WEAK_HANDLE = 2003315333, - BINDER_TYPE_FD = 1717840517, - BINDER_TYPE_FDA = 1717854597, - BINDER_TYPE_PTR = 1886661253, -}; - -enum { - FLAT_BINDER_FLAG_PRIORITY_MASK = 255, - FLAT_BINDER_FLAG_ACCEPTS_FDS = 256, - FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 4096, -}; - -typedef __u64 binder_size_t; - -typedef __u64 binder_uintptr_t; - -struct binder_object_header { - __u32 type; -}; - -struct flat_binder_object { - struct binder_object_header hdr; - __u32 flags; - union { - binder_uintptr_t binder; - __u32 handle; - }; - binder_uintptr_t cookie; -}; - -struct binder_fd_object { - struct binder_object_header hdr; - __u32 pad_flags; - union { - binder_uintptr_t pad_binder; - __u32 fd; - }; - binder_uintptr_t cookie; -}; - -struct binder_buffer_object { - struct binder_object_header hdr; - __u32 flags; - binder_uintptr_t buffer; - binder_size_t length; - binder_size_t parent; - binder_size_t parent_offset; -}; - -enum { - BINDER_BUFFER_FLAG_HAS_PARENT = 1, -}; - -struct binder_fd_array_object { - struct binder_object_header hdr; - __u32 pad; - binder_size_t num_fds; - binder_size_t parent; - binder_size_t parent_offset; -}; - -struct binder_write_read { - binder_size_t write_size; - binder_size_t write_consumed; - binder_uintptr_t write_buffer; - binder_size_t read_size; - binder_size_t read_consumed; - binder_uintptr_t read_buffer; -}; - -struct binder_version { - __s32 protocol_version; -}; - -struct binder_node_debug_info { - binder_uintptr_t ptr; - binder_uintptr_t cookie; - __u32 has_strong_ref; - __u32 has_weak_ref; -}; - -struct binder_node_info_for_ref { - __u32 handle; - __u32 strong_count; - __u32 weak_count; - __u32 reserved1; - __u32 reserved2; - __u32 reserved3; -}; - -enum transaction_flags { - TF_ONE_WAY = 1, - TF_ROOT_OBJECT = 4, - TF_STATUS_CODE = 8, - TF_ACCEPT_FDS = 16, - TF_CLEAR_BUF = 32, -}; - -struct binder_transaction_data { - union { - __u32 handle; - binder_uintptr_t ptr; - } target; - binder_uintptr_t cookie; - __u32 code; - __u32 flags; - pid_t sender_pid; - uid_t sender_euid; - binder_size_t data_size; - binder_size_t offsets_size; - union { - struct { - binder_uintptr_t buffer; - binder_uintptr_t offsets; - } ptr; - __u8 buf[8]; - } data; -}; - -struct binder_transaction_data_secctx { - struct binder_transaction_data transaction_data; - binder_uintptr_t secctx; -}; - -struct binder_transaction_data_sg { - struct binder_transaction_data transaction_data; - binder_size_t buffers_size; -}; - -enum binder_driver_return_protocol { - BR_ERROR = 2147774976, - BR_OK = 29185, - BR_TRANSACTION_SEC_CTX = 2152231426, - BR_TRANSACTION = 2151707138, - BR_REPLY = 2151707139, - BR_ACQUIRE_RESULT = 2147774980, - BR_DEAD_REPLY = 29189, - BR_TRANSACTION_COMPLETE = 29190, - BR_INCREFS = 2148561415, - BR_ACQUIRE = 2148561416, - BR_RELEASE = 2148561417, - BR_DECREFS = 2148561418, - BR_ATTEMPT_ACQUIRE = 2149085707, - BR_NOOP = 29196, - BR_SPAWN_LOOPER = 29197, - BR_FINISHED = 29198, - BR_DEAD_BINDER = 2148037135, - BR_CLEAR_DEATH_NOTIFICATION_DONE = 2148037136, - BR_FAILED_REPLY = 29201, -}; - -enum binder_driver_command_protocol { - BC_TRANSACTION = 1077961472, - BC_REPLY = 1077961473, - BC_ACQUIRE_RESULT = 1074029314, - BC_FREE_BUFFER = 1074291459, - BC_INCREFS = 1074029316, - BC_ACQUIRE = 1074029317, - BC_RELEASE = 1074029318, - BC_DECREFS = 1074029319, - BC_INCREFS_DONE = 1074815752, - BC_ACQUIRE_DONE = 1074815753, - BC_ATTEMPT_ACQUIRE = 1074291466, - BC_REGISTER_LOOPER = 25355, - BC_ENTER_LOOPER = 25356, - BC_EXIT_LOOPER = 25357, - BC_REQUEST_DEATH_NOTIFICATION = 1074553614, - BC_CLEAR_DEATH_NOTIFICATION = 1074553615, - BC_DEAD_BINDER_DONE = 1074291472, - BC_TRANSACTION_SG = 1078485777, - BC_REPLY_SG = 1078485778, -}; - -struct binder_transaction; - -struct binder_buffer { - struct list_head entry; - struct rb_node rb_node; - unsigned int free: 1; - unsigned int clear_on_free: 1; - unsigned int allow_user_free: 1; - unsigned int async_transaction: 1; - unsigned int debug_id: 28; - struct binder_transaction *transaction; - struct binder_node *target_node; - size_t data_size; - size_t offsets_size; - size_t extra_buffers_size; - void *user_data; - int pid; -}; - -enum binder_work_type { - BINDER_WORK_TRANSACTION = 1, - BINDER_WORK_TRANSACTION_COMPLETE = 2, - BINDER_WORK_RETURN_ERROR = 3, - BINDER_WORK_NODE = 4, - BINDER_WORK_DEAD_BINDER = 5, - BINDER_WORK_DEAD_BINDER_AND_CLEAR = 6, - BINDER_WORK_CLEAR_DEATH_NOTIFICATION = 7, -}; - -struct binder_work { - struct list_head entry; - enum binder_work_type type; -}; - -struct binder_thread; - -struct binder_proc; - -struct binder_transaction { - int debug_id; - struct binder_work work; - struct binder_thread *from; - struct binder_transaction *from_parent; - struct binder_proc *to_proc; - struct binder_thread *to_thread; - struct binder_transaction *to_parent; - unsigned int need_reply: 1; - struct binder_buffer *buffer; - unsigned int code; - unsigned int flags; - long int priority; - long int saved_priority; - kuid_t sender_euid; - struct list_head fd_fixups; - binder_uintptr_t security_ctx; - spinlock_t lock; -}; - -struct binder_node { - int debug_id; - spinlock_t lock; - struct binder_work work; - union { - struct rb_node rb_node; - struct hlist_node dead_node; - }; - struct binder_proc *proc; - struct hlist_head refs; - int internal_strong_refs; - int local_weak_refs; - int local_strong_refs; - int tmp_refs; - binder_uintptr_t ptr; - binder_uintptr_t cookie; - struct { - u8 has_strong_ref: 1; - u8 pending_strong_ref: 1; - u8 has_weak_ref: 1; - u8 pending_weak_ref: 1; - }; - struct { - u8 accept_fds: 1; - u8 txn_security_ctx: 1; - u8 min_priority; - }; - bool has_async_transaction; - struct list_head async_todo; -}; - -struct binder_alloc; - -struct binder_lru_page { - struct list_head lru; - struct page *page_ptr; - struct binder_alloc *alloc; -}; - -struct binder_alloc { - struct mutex mutex; - struct vm_area_struct *vma; - struct mm_struct *vma_vm_mm; - void *buffer; - struct list_head buffers; - struct rb_root free_buffers; - struct rb_root allocated_buffers; - size_t free_async_space; - struct binder_lru_page *pages; - size_t buffer_size; - uint32_t buffer_free; - int pid; - size_t pages_high; -}; - -enum { - BINDER_DEBUG_USER_ERROR = 1, - BINDER_DEBUG_FAILED_TRANSACTION = 2, - BINDER_DEBUG_DEAD_TRANSACTION = 4, - BINDER_DEBUG_OPEN_CLOSE = 8, - BINDER_DEBUG_DEAD_BINDER = 16, - BINDER_DEBUG_DEATH_NOTIFICATION = 32, - BINDER_DEBUG_READ_WRITE = 64, - BINDER_DEBUG_USER_REFS = 128, - BINDER_DEBUG_THREADS = 256, - BINDER_DEBUG_TRANSACTION = 512, - BINDER_DEBUG_TRANSACTION_COMPLETE = 1024, - BINDER_DEBUG_FREE_BUFFER = 2048, - BINDER_DEBUG_INTERNAL_REFS = 4096, - BINDER_DEBUG_PRIORITY_CAP = 8192, - BINDER_DEBUG_SPINLOCKS = 16384, -}; - -enum binder_stat_types { - BINDER_STAT_PROC = 0, - BINDER_STAT_THREAD = 1, - BINDER_STAT_NODE = 2, - BINDER_STAT_REF = 3, - BINDER_STAT_DEATH = 4, - BINDER_STAT_TRANSACTION = 5, - BINDER_STAT_TRANSACTION_COMPLETE = 6, - BINDER_STAT_COUNT = 7, -}; - -struct binder_stats { - atomic_t br[18]; - atomic_t bc[19]; - atomic_t obj_created[7]; - atomic_t obj_deleted[7]; -}; - -struct binder_error { - struct binder_work work; - uint32_t cmd; -}; - -struct binder_proc { - struct hlist_node proc_node; - struct rb_root threads; - struct rb_root nodes; - struct rb_root refs_by_desc; - struct rb_root refs_by_node; - struct list_head waiting_threads; - int pid; - struct task_struct *tsk; - const struct cred *cred; - struct hlist_node deferred_work_node; - int deferred_work; - bool is_dead; - struct list_head todo; - struct binder_stats stats; - struct list_head delivered_death; - int max_threads; - int requested_threads; - int requested_threads_started; - int tmp_ref; - long int default_priority; - struct dentry *debugfs_entry; - struct binder_alloc alloc; - struct binder_context *context; - spinlock_t inner_lock; - spinlock_t outer_lock; - struct dentry *binderfs_entry; -}; - -struct binder_ref_death { - struct binder_work work; - binder_uintptr_t cookie; -}; - -struct binder_ref_data { - int debug_id; - uint32_t desc; - int strong; - int weak; -}; - -struct binder_ref { - struct binder_ref_data data; - struct rb_node rb_node_desc; - struct rb_node rb_node_node; - struct hlist_node node_entry; - struct binder_proc *proc; - struct binder_node *node; - struct binder_ref_death *death; -}; - -enum binder_deferred_state { - BINDER_DEFERRED_FLUSH = 1, - BINDER_DEFERRED_RELEASE = 2, -}; - -enum { - BINDER_LOOPER_STATE_REGISTERED = 1, - BINDER_LOOPER_STATE_ENTERED = 2, - BINDER_LOOPER_STATE_EXITED = 4, - BINDER_LOOPER_STATE_INVALID = 8, - BINDER_LOOPER_STATE_WAITING = 16, - BINDER_LOOPER_STATE_POLL = 32, -}; - -struct binder_thread { - struct binder_proc *proc; - struct rb_node rb_node; - struct list_head waiting_thread_node; - int pid; - int looper; - bool looper_need_return; - struct binder_transaction *transaction_stack; - struct list_head todo; - bool process_todo; - struct binder_error return_error; - struct binder_error reply_error; - wait_queue_head_t wait; - struct binder_stats stats; - atomic_t tmp_ref; - bool is_dead; -}; - -struct binder_txn_fd_fixup { - struct list_head fixup_entry; - struct file *file; - size_t offset; -}; - -struct binder_object { - union { - struct binder_object_header hdr; - struct flat_binder_object fbo; - struct binder_fd_object fdo; - struct binder_buffer_object bbo; - struct binder_fd_array_object fdao; - }; -}; - -struct binder_task_work_cb { - struct callback_head twork; - struct file *file; -}; - -struct trace_event_raw_binder_ioctl { - struct trace_entry ent; - unsigned int cmd; - long unsigned int arg; - char __data[0]; -}; - -struct trace_event_raw_binder_lock_class { - struct trace_entry ent; - const char *tag; - char __data[0]; -}; - -struct trace_event_raw_binder_function_return_class { - struct trace_entry ent; - int ret; - char __data[0]; -}; - -struct trace_event_raw_binder_wait_for_work { - struct trace_entry ent; - bool proc_work; - bool transaction_stack; - bool thread_todo; - char __data[0]; -}; - -struct trace_event_raw_binder_transaction { - struct trace_entry ent; - int debug_id; - int target_node; - int to_proc; - int to_thread; - int reply; - unsigned int code; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_binder_transaction_received { - struct trace_entry ent; - int debug_id; - char __data[0]; -}; - -struct trace_event_raw_binder_transaction_node_to_ref { - struct trace_entry ent; - int debug_id; - int node_debug_id; - binder_uintptr_t node_ptr; - int ref_debug_id; - uint32_t ref_desc; - char __data[0]; -}; - -struct trace_event_raw_binder_transaction_ref_to_node { - struct trace_entry ent; - int debug_id; - int ref_debug_id; - uint32_t ref_desc; - int node_debug_id; - binder_uintptr_t node_ptr; - char __data[0]; -}; - -struct trace_event_raw_binder_transaction_ref_to_ref { - struct trace_entry ent; - int debug_id; - int node_debug_id; - int src_ref_debug_id; - uint32_t src_ref_desc; - int dest_ref_debug_id; - uint32_t dest_ref_desc; - char __data[0]; -}; - -struct trace_event_raw_binder_transaction_fd_send { - struct trace_entry ent; - int debug_id; - int fd; - size_t offset; - char __data[0]; -}; - -struct trace_event_raw_binder_transaction_fd_recv { - struct trace_entry ent; - int debug_id; - int fd; - size_t offset; - char __data[0]; -}; - -struct trace_event_raw_binder_buffer_class { - struct trace_entry ent; - int debug_id; - size_t data_size; - size_t offsets_size; - size_t extra_buffers_size; - char __data[0]; -}; - -struct trace_event_raw_binder_update_page_range { - struct trace_entry ent; - int proc; - bool allocate; - size_t offset; - size_t size; - char __data[0]; -}; - -struct trace_event_raw_binder_lru_page_class { - struct trace_entry ent; - int proc; - size_t page_index; - char __data[0]; -}; - -struct trace_event_raw_binder_command { - struct trace_entry ent; - uint32_t cmd; - char __data[0]; -}; - -struct trace_event_raw_binder_return { - struct trace_entry ent; - uint32_t cmd; - char __data[0]; -}; - -struct trace_event_data_offsets_binder_ioctl {}; - -struct trace_event_data_offsets_binder_lock_class {}; - -struct trace_event_data_offsets_binder_function_return_class {}; - -struct trace_event_data_offsets_binder_wait_for_work {}; - -struct trace_event_data_offsets_binder_transaction {}; - -struct trace_event_data_offsets_binder_transaction_received {}; - -struct trace_event_data_offsets_binder_transaction_node_to_ref {}; - -struct trace_event_data_offsets_binder_transaction_ref_to_node {}; - -struct trace_event_data_offsets_binder_transaction_ref_to_ref {}; - -struct trace_event_data_offsets_binder_transaction_fd_send {}; - -struct trace_event_data_offsets_binder_transaction_fd_recv {}; - -struct trace_event_data_offsets_binder_buffer_class {}; - -struct trace_event_data_offsets_binder_update_page_range {}; - -struct trace_event_data_offsets_binder_lru_page_class {}; - -struct trace_event_data_offsets_binder_command {}; - -struct trace_event_data_offsets_binder_return {}; - -typedef void (*btf_trace_binder_ioctl)(void *, unsigned int, long unsigned int); - -typedef void (*btf_trace_binder_lock)(void *, const char *); - -typedef void (*btf_trace_binder_locked)(void *, const char *); - -typedef void (*btf_trace_binder_unlock)(void *, const char *); - -typedef void (*btf_trace_binder_ioctl_done)(void *, int); - -typedef void (*btf_trace_binder_write_done)(void *, int); - -typedef void (*btf_trace_binder_read_done)(void *, int); - -typedef void (*btf_trace_binder_wait_for_work)(void *, bool, bool, bool); - -typedef void (*btf_trace_binder_transaction)(void *, bool, struct binder_transaction *, struct binder_node *); - -typedef void (*btf_trace_binder_transaction_received)(void *, struct binder_transaction *); - -typedef void (*btf_trace_binder_transaction_node_to_ref)(void *, struct binder_transaction *, struct binder_node *, struct binder_ref_data *); - -typedef void (*btf_trace_binder_transaction_ref_to_node)(void *, struct binder_transaction *, struct binder_node *, struct binder_ref_data *); - -typedef void (*btf_trace_binder_transaction_ref_to_ref)(void *, struct binder_transaction *, struct binder_node *, struct binder_ref_data *, struct binder_ref_data *); - -typedef void (*btf_trace_binder_transaction_fd_send)(void *, struct binder_transaction *, int, size_t); - -typedef void (*btf_trace_binder_transaction_fd_recv)(void *, struct binder_transaction *, int, size_t); - -typedef void (*btf_trace_binder_transaction_alloc_buf)(void *, struct binder_buffer *); - -typedef void (*btf_trace_binder_transaction_buffer_release)(void *, struct binder_buffer *); - -typedef void (*btf_trace_binder_transaction_failed_buffer_release)(void *, struct binder_buffer *); - -typedef void (*btf_trace_binder_update_page_range)(void *, struct binder_alloc *, bool, void *, void *); - -typedef void (*btf_trace_binder_alloc_lru_start)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_alloc_lru_end)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_free_lru_start)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_free_lru_end)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_alloc_page_start)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_alloc_page_end)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_unmap_user_start)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_unmap_user_end)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_unmap_kernel_start)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_unmap_kernel_end)(void *, const struct binder_alloc *, size_t); - -typedef void (*btf_trace_binder_command)(void *, uint32_t); - -typedef void (*btf_trace_binder_return)(void *, uint32_t); - -enum { - BINDER_DEBUG_USER_ERROR___2 = 1, - BINDER_DEBUG_OPEN_CLOSE___2 = 2, - BINDER_DEBUG_BUFFER_ALLOC = 4, - BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 8, -}; - -struct nvmem_cell_lookup { - const char *nvmem_name; - const char *cell_name; - const char *dev_id; - const char *con_id; - struct list_head node; -}; - -enum { - NVMEM_ADD = 1, - NVMEM_REMOVE = 2, - NVMEM_CELL_ADD = 3, - NVMEM_CELL_REMOVE = 4, -}; - -struct nvmem_cell_table { - const char *nvmem_name; - const struct nvmem_cell_info *cells; - size_t ncells; - struct list_head node; -}; - -struct nvmem_device___2 { - struct module *owner; - struct device dev; - int stride; - int word_size; - int id; - struct kref refcnt; - size_t size; - bool read_only; - bool root_only; - int flags; - enum nvmem_type type; - struct bin_attribute eeprom; - struct device *base_dev; - struct list_head cells; - nvmem_reg_read_t reg_read; - nvmem_reg_write_t reg_write; - struct gpio_desc *wp_gpio; - void *priv; -}; - -struct nvmem_cell { - const char *name; - int offset; - int bytes; - int bit_offset; - int nbits; - struct device_node *np; - struct nvmem_device___2 *nvmem; - struct list_head node; -}; - -struct net_device_devres { - struct net_device *ndev; -}; - -struct __kernel_old_timespec { - __kernel_old_time_t tv_sec; - long int tv_nsec; -}; - -struct __kernel_sock_timeval { - __s64 tv_sec; - __s64 tv_usec; -}; - -struct mmsghdr { - struct user_msghdr msg_hdr; - unsigned int msg_len; -}; - -struct scm_timestamping_internal { - struct timespec64 ts[3]; -}; - -enum sock_shutdown_cmd { - SHUT_RD = 0, - SHUT_WR = 1, - SHUT_RDWR = 2, -}; - -struct net_proto_family { - int family; - int (*create)(struct net *, struct socket *, int, int); - struct module *owner; -}; - -enum { - SOCK_WAKE_IO = 0, - SOCK_WAKE_WAITD = 1, - SOCK_WAKE_SPACE = 2, - SOCK_WAKE_URG = 3, -}; - -struct ifconf { - int ifc_len; - union { - char *ifcu_buf; - struct ifreq *ifcu_req; - } ifc_ifcu; -}; - -struct compat_ifmap { - compat_ulong_t mem_start; - compat_ulong_t mem_end; - short unsigned int base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct compat_if_settings { - unsigned int type; - unsigned int size; - compat_uptr_t ifs_ifsu; -}; - -struct compat_ifreq { - union { - char ifrn_name[16]; - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short int ifru_flags; - compat_int_t ifru_ivalue; - compat_int_t ifru_mtu; - struct compat_ifmap ifru_map; - char ifru_slave[16]; - char ifru_newname[16]; - compat_caddr_t ifru_data; - struct compat_if_settings ifru_settings; - } ifr_ifru; -}; - -struct compat_ifconf { - compat_int_t ifc_len; - compat_caddr_t ifcbuf; -}; - -struct libipw_device; - -struct iw_spy_data; - -struct iw_public_data { - struct iw_spy_data *spy_data; - struct libipw_device *libipw; -}; - -struct iw_param { - __s32 value; - __u8 fixed; - __u8 disabled; - __u16 flags; -}; - -struct iw_point { - void *pointer; - __u16 length; - __u16 flags; -}; - -struct iw_freq { - __s32 m; - __s16 e; - __u8 i; - __u8 flags; -}; - -struct iw_quality { - __u8 qual; - __u8 level; - __u8 noise; - __u8 updated; -}; - -struct iw_discarded { - __u32 nwid; - __u32 code; - __u32 fragment; - __u32 retries; - __u32 misc; -}; - -struct iw_missed { - __u32 beacon; -}; - -struct iw_statistics { - __u16 status; - struct iw_quality qual; - struct iw_discarded discard; - struct iw_missed miss; -}; - -union iwreq_data { - char name[16]; - struct iw_point essid; - struct iw_param nwid; - struct iw_freq freq; - struct iw_param sens; - struct iw_param bitrate; - struct iw_param txpower; - struct iw_param rts; - struct iw_param frag; - __u32 mode; - struct iw_param retry; - struct iw_point encoding; - struct iw_param power; - struct iw_quality qual; - struct sockaddr ap_addr; - struct sockaddr addr; - struct iw_param param; - struct iw_point data; -}; - -struct iw_priv_args { - __u32 cmd; - __u16 set_args; - __u16 get_args; - char name[16]; -}; - -struct compat_mmsghdr { - struct compat_msghdr msg_hdr; - compat_uint_t msg_len; -}; - -struct iw_request_info { - __u16 cmd; - __u16 flags; -}; - -struct iw_spy_data { - int spy_number; - u_char spy_address[48]; - struct iw_quality spy_stat[8]; - struct iw_quality spy_thr_low; - struct iw_quality spy_thr_high; - u_char spy_thr_under[8]; -}; - -enum { - SOF_TIMESTAMPING_TX_HARDWARE = 1, - SOF_TIMESTAMPING_TX_SOFTWARE = 2, - SOF_TIMESTAMPING_RX_HARDWARE = 4, - SOF_TIMESTAMPING_RX_SOFTWARE = 8, - SOF_TIMESTAMPING_SOFTWARE = 16, - SOF_TIMESTAMPING_SYS_HARDWARE = 32, - SOF_TIMESTAMPING_RAW_HARDWARE = 64, - SOF_TIMESTAMPING_OPT_ID = 128, - SOF_TIMESTAMPING_TX_SCHED = 256, - SOF_TIMESTAMPING_TX_ACK = 512, - SOF_TIMESTAMPING_OPT_CMSG = 1024, - SOF_TIMESTAMPING_OPT_TSONLY = 2048, - SOF_TIMESTAMPING_OPT_STATS = 4096, - SOF_TIMESTAMPING_OPT_PKTINFO = 8192, - SOF_TIMESTAMPING_OPT_TX_SWHW = 16384, - SOF_TIMESTAMPING_LAST = 16384, - SOF_TIMESTAMPING_MASK = 32767, -}; - -struct scm_ts_pktinfo { - __u32 if_index; - __u32 pkt_length; - __u32 reserved[2]; -}; - -struct socket_alloc { - struct socket socket; - struct inode vfs_inode; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct sock_skb_cb { - u32 dropcount; -}; - -struct inet6_skb_parm { - int iif; - __be16 ra; - __u16 dst0; - __u16 srcrt; - __u16 dst1; - __u16 lastopt; - __u16 nhoff; - __u16 flags; - __u16 frag_max_size; -}; - -struct inet_skb_parm { - int iif; - struct ip_options opt; - u16 flags; - u16 frag_max_size; -}; - -struct sock_ee_data_rfc4884 { - __u16 len; - __u8 flags; - __u8 reserved; -}; - -struct sock_extended_err { - __u32 ee_errno; - __u8 ee_origin; - __u8 ee_type; - __u8 ee_code; - __u8 ee_pad; - __u32 ee_info; - union { - __u32 ee_data; - struct sock_ee_data_rfc4884 ee_rfc4884; - }; -}; - -struct sock_exterr_skb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - struct sock_extended_err ee; - u16 addr_offset; - __be16 port; - u8 opt_stats: 1; - u8 unused: 7; -}; - -struct used_address { - struct __kernel_sockaddr_storage name; - unsigned int name_len; -}; - -struct linger { - int l_onoff; - int l_linger; -}; - -struct cmsghdr { - __kernel_size_t cmsg_len; - int cmsg_level; - int cmsg_type; -}; - -struct ucred { - __u32 pid; - __u32 uid; - __u32 gid; -}; - -struct mmpin { - struct user_struct *user; - unsigned int num_pg; -}; - -struct ubuf_info { - void (*callback)(struct ubuf_info *, bool); - union { - struct { - long unsigned int desc; - void *ctx; - }; - struct { - u32 id; - u16 len; - u16 zerocopy: 1; - u32 bytelen; - }; - }; - refcount_t refcnt; - struct mmpin mmp; -}; - -enum { - SKB_GSO_TCPV4 = 1, - SKB_GSO_DODGY = 2, - SKB_GSO_TCP_ECN = 4, - SKB_GSO_TCP_FIXEDID = 8, - SKB_GSO_TCPV6 = 16, - SKB_GSO_FCOE = 32, - SKB_GSO_GRE = 64, - SKB_GSO_GRE_CSUM = 128, - SKB_GSO_IPXIP4 = 256, - SKB_GSO_IPXIP6 = 512, - SKB_GSO_UDP_TUNNEL = 1024, - SKB_GSO_UDP_TUNNEL_CSUM = 2048, - SKB_GSO_PARTIAL = 4096, - SKB_GSO_TUNNEL_REMCSUM = 8192, - SKB_GSO_SCTP = 16384, - SKB_GSO_ESP = 32768, - SKB_GSO_UDP = 65536, - SKB_GSO_UDP_L4 = 131072, - SKB_GSO_FRAGLIST = 262144, -}; - -struct prot_inuse { - int val[64]; -}; - -typedef union { - __be32 a4; - __be32 a6[4]; - struct in6_addr in6; -} xfrm_address_t; - -struct xfrm_id { - xfrm_address_t daddr; - __be32 spi; - __u8 proto; -}; - -struct xfrm_sec_ctx { - __u8 ctx_doi; - __u8 ctx_alg; - __u16 ctx_len; - __u32 ctx_sid; - char ctx_str[0]; -}; - -struct xfrm_selector { - xfrm_address_t daddr; - xfrm_address_t saddr; - __be16 dport; - __be16 dport_mask; - __be16 sport; - __be16 sport_mask; - __u16 family; - __u8 prefixlen_d; - __u8 prefixlen_s; - __u8 proto; - int ifindex; - __kernel_uid32_t user; -}; - -struct xfrm_lifetime_cfg { - __u64 soft_byte_limit; - __u64 hard_byte_limit; - __u64 soft_packet_limit; - __u64 hard_packet_limit; - __u64 soft_add_expires_seconds; - __u64 hard_add_expires_seconds; - __u64 soft_use_expires_seconds; - __u64 hard_use_expires_seconds; -}; - -struct xfrm_lifetime_cur { - __u64 bytes; - __u64 packets; - __u64 add_time; - __u64 use_time; -}; - -struct xfrm_replay_state { - __u32 oseq; - __u32 seq; - __u32 bitmap; -}; - -struct xfrm_replay_state_esn { - unsigned int bmp_len; - __u32 oseq; - __u32 seq; - __u32 oseq_hi; - __u32 seq_hi; - __u32 replay_window; - __u32 bmp[0]; -}; - -struct xfrm_algo { - char alg_name[64]; - unsigned int alg_key_len; - char alg_key[0]; -}; - -struct xfrm_algo_auth { - char alg_name[64]; - unsigned int alg_key_len; - unsigned int alg_trunc_len; - char alg_key[0]; -}; - -struct xfrm_algo_aead { - char alg_name[64]; - unsigned int alg_key_len; - unsigned int alg_icv_len; - char alg_key[0]; -}; - -struct xfrm_stats { - __u32 replay_window; - __u32 replay; - __u32 integrity_failed; -}; - -enum { - XFRM_POLICY_TYPE_MAIN = 0, - XFRM_POLICY_TYPE_SUB = 1, - XFRM_POLICY_TYPE_MAX = 2, - XFRM_POLICY_TYPE_ANY = 255, -}; - -enum { - XFRM_MSG_BASE = 16, - XFRM_MSG_NEWSA = 16, - XFRM_MSG_DELSA = 17, - XFRM_MSG_GETSA = 18, - XFRM_MSG_NEWPOLICY = 19, - XFRM_MSG_DELPOLICY = 20, - XFRM_MSG_GETPOLICY = 21, - XFRM_MSG_ALLOCSPI = 22, - XFRM_MSG_ACQUIRE = 23, - XFRM_MSG_EXPIRE = 24, - XFRM_MSG_UPDPOLICY = 25, - XFRM_MSG_UPDSA = 26, - XFRM_MSG_POLEXPIRE = 27, - XFRM_MSG_FLUSHSA = 28, - XFRM_MSG_FLUSHPOLICY = 29, - XFRM_MSG_NEWAE = 30, - XFRM_MSG_GETAE = 31, - XFRM_MSG_REPORT = 32, - XFRM_MSG_MIGRATE = 33, - XFRM_MSG_NEWSADINFO = 34, - XFRM_MSG_GETSADINFO = 35, - XFRM_MSG_NEWSPDINFO = 36, - XFRM_MSG_GETSPDINFO = 37, - XFRM_MSG_MAPPING = 38, - __XFRM_MSG_MAX = 39, -}; - -struct xfrm_encap_tmpl { - __u16 encap_type; - __be16 encap_sport; - __be16 encap_dport; - xfrm_address_t encap_oa; -}; - -enum xfrm_attr_type_t { - XFRMA_UNSPEC = 0, - XFRMA_ALG_AUTH = 1, - XFRMA_ALG_CRYPT = 2, - XFRMA_ALG_COMP = 3, - XFRMA_ENCAP = 4, - XFRMA_TMPL = 5, - XFRMA_SA = 6, - XFRMA_POLICY = 7, - XFRMA_SEC_CTX = 8, - XFRMA_LTIME_VAL = 9, - XFRMA_REPLAY_VAL = 10, - XFRMA_REPLAY_THRESH = 11, - XFRMA_ETIMER_THRESH = 12, - XFRMA_SRCADDR = 13, - XFRMA_COADDR = 14, - XFRMA_LASTUSED = 15, - XFRMA_POLICY_TYPE = 16, - XFRMA_MIGRATE = 17, - XFRMA_ALG_AEAD = 18, - XFRMA_KMADDRESS = 19, - XFRMA_ALG_AUTH_TRUNC = 20, - XFRMA_MARK = 21, - XFRMA_TFCPAD = 22, - XFRMA_REPLAY_ESN_VAL = 23, - XFRMA_SA_EXTRA_FLAGS = 24, - XFRMA_PROTO = 25, - XFRMA_ADDRESS_FILTER = 26, - XFRMA_PAD = 27, - XFRMA_OFFLOAD_DEV = 28, - XFRMA_SET_MARK = 29, - XFRMA_SET_MARK_MASK = 30, - XFRMA_IF_ID = 31, - __XFRMA_MAX = 32, -}; - -struct xfrm_mark { - __u32 v; - __u32 m; -}; - -struct xfrm_address_filter { - xfrm_address_t saddr; - xfrm_address_t daddr; - __u16 family; - __u8 splen; - __u8 dplen; -}; - -struct xfrm_state_walk { - struct list_head all; - u8 state; - u8 dying; - u8 proto; - u32 seq; - struct xfrm_address_filter *filter; -}; - -struct xfrm_state_offload { - struct net_device *dev; - struct net_device *real_dev; - long unsigned int offload_handle; - unsigned int num_exthdrs; - u8 flags; -}; - -struct xfrm_mode { - u8 encap; - u8 family; - u8 flags; -}; - -struct xfrm_replay; - -struct xfrm_type; - -struct xfrm_type_offload; - -struct xfrm_state { - possible_net_t xs_net; - union { - struct hlist_node gclist; - struct hlist_node bydst; - }; - struct hlist_node bysrc; - struct hlist_node byspi; - refcount_t refcnt; - spinlock_t lock; - struct xfrm_id id; - struct xfrm_selector sel; - struct xfrm_mark mark; - u32 if_id; - u32 tfcpad; - u32 genid; - struct xfrm_state_walk km; - struct { - u32 reqid; - u8 mode; - u8 replay_window; - u8 aalgo; - u8 ealgo; - u8 calgo; - u8 flags; - u16 family; - xfrm_address_t saddr; - int header_len; - int trailer_len; - u32 extra_flags; - struct xfrm_mark smark; - } props; - struct xfrm_lifetime_cfg lft; - struct xfrm_algo_auth *aalg; - struct xfrm_algo *ealg; - struct xfrm_algo *calg; - struct xfrm_algo_aead *aead; - const char *geniv; - struct xfrm_encap_tmpl *encap; - struct sock *encap_sk; - xfrm_address_t *coaddr; - struct xfrm_state *tunnel; - atomic_t tunnel_users; - struct xfrm_replay_state replay; - struct xfrm_replay_state_esn *replay_esn; - struct xfrm_replay_state preplay; - struct xfrm_replay_state_esn *preplay_esn; - const struct xfrm_replay *repl; - u32 xflags; - u32 replay_maxage; - u32 replay_maxdiff; - struct timer_list rtimer; - struct xfrm_stats stats; - struct xfrm_lifetime_cur curlft; - struct hrtimer mtimer; - struct xfrm_state_offload xso; - long int saved_tmo; - time64_t lastused; - struct page_frag xfrag; - const struct xfrm_type *type; - struct xfrm_mode inner_mode; - struct xfrm_mode inner_mode_iaf; - struct xfrm_mode outer_mode; - const struct xfrm_type_offload *type_offload; - struct xfrm_sec_ctx *security; - void *data; -}; - -enum txtime_flags { - SOF_TXTIME_DEADLINE_MODE = 1, - SOF_TXTIME_REPORT_ERRORS = 2, - SOF_TXTIME_FLAGS_LAST = 2, - SOF_TXTIME_FLAGS_MASK = 3, -}; - -struct sock_txtime { - __kernel_clockid_t clockid; - __u32 flags; -}; - -struct xfrm_policy_walk_entry { - struct list_head all; - u8 dead; -}; - -struct xfrm_policy_queue { - struct sk_buff_head hold_queue; - struct timer_list hold_timer; - long unsigned int timeout; -}; - -struct xfrm_tmpl { - struct xfrm_id id; - xfrm_address_t saddr; - short unsigned int encap_family; - u32 reqid; - u8 mode; - u8 share; - u8 optional; - u8 allalgs; - u32 aalgos; - u32 ealgos; - u32 calgos; -}; - -struct xfrm_policy { - possible_net_t xp_net; - struct hlist_node bydst; - struct hlist_node byidx; - rwlock_t lock; - refcount_t refcnt; - u32 pos; - struct timer_list timer; - atomic_t genid; - u32 priority; - u32 index; - u32 if_id; - struct xfrm_mark mark; - struct xfrm_selector selector; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - struct xfrm_policy_walk_entry walk; - struct xfrm_policy_queue polq; - bool bydst_reinsert; - u8 type; - u8 action; - u8 flags; - u8 xfrm_nr; - u16 family; - struct xfrm_sec_ctx *security; - struct xfrm_tmpl xfrm_vec[6]; - struct hlist_node bydst_inexact_list; - struct callback_head rcu; -}; - -enum sk_pacing { - SK_PACING_NONE = 0, - SK_PACING_NEEDED = 1, - SK_PACING_FQ = 2, -}; - -struct sockcm_cookie { - u64 transmit_time; - u32 mark; - u16 tsflags; -}; - -struct fastopen_queue { - struct request_sock *rskq_rst_head; - struct request_sock *rskq_rst_tail; - spinlock_t lock; - int qlen; - int max_qlen; - struct tcp_fastopen_context *ctx; -}; - -struct request_sock_queue { - spinlock_t rskq_lock; - u8 rskq_defer_accept; - u32 synflood_warned; - atomic_t qlen; - atomic_t young; - struct request_sock *rskq_accept_head; - struct request_sock *rskq_accept_tail; - struct fastopen_queue fastopenq; -}; - -struct inet_connection_sock_af_ops { - int (*queue_xmit)(struct sock *, struct sk_buff *, struct flowi *); - void (*send_check)(struct sock *, struct sk_buff *); - int (*rebuild_header)(struct sock *); - void (*sk_rx_dst_set)(struct sock *, const struct sk_buff *); - int (*conn_request)(struct sock *, struct sk_buff *); - struct sock * (*syn_recv_sock)(const struct sock *, struct sk_buff *, struct request_sock *, struct dst_entry *, struct request_sock *, bool *); - u16 net_header_len; - u16 net_frag_header_len; - u16 sockaddr_len; - int (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int); - int (*getsockopt)(struct sock *, int, int, char *, int *); - void (*addr2sockaddr)(struct sock *, struct sockaddr *); - void (*mtu_reduced)(struct sock *); -}; - -struct inet_bind_bucket; - -struct tcp_ulp_ops; - -struct inet_connection_sock { - struct inet_sock icsk_inet; - struct request_sock_queue icsk_accept_queue; - struct inet_bind_bucket *icsk_bind_hash; - long unsigned int icsk_timeout; - struct timer_list icsk_retransmit_timer; - struct timer_list icsk_delack_timer; - __u32 icsk_rto; - __u32 icsk_rto_min; - __u32 icsk_delack_max; - __u32 icsk_pmtu_cookie; - const struct tcp_congestion_ops *icsk_ca_ops; - const struct inet_connection_sock_af_ops *icsk_af_ops; - const struct tcp_ulp_ops *icsk_ulp_ops; - void *icsk_ulp_data; - void (*icsk_clean_acked)(struct sock *, u32); - struct hlist_node icsk_listen_portaddr_node; - unsigned int (*icsk_sync_mss)(struct sock *, u32); - __u8 icsk_ca_state: 5; - __u8 icsk_ca_initialized: 1; - __u8 icsk_ca_setsockopt: 1; - __u8 icsk_ca_dst_locked: 1; - __u8 icsk_retransmits; - __u8 icsk_pending; - __u8 icsk_backoff; - __u8 icsk_syn_retries; - __u8 icsk_probes_out; - __u16 icsk_ext_hdr_len; - struct { - __u8 pending; - __u8 quick; - __u8 pingpong; - __u8 retry; - __u32 ato; - long unsigned int timeout; - __u32 lrcvtime; - __u16 last_seg_size; - __u16 rcv_mss; - } icsk_ack; - struct { - int enabled; - int search_high; - int search_low; - int probe_size; - u32 probe_timestamp; - } icsk_mtup; - u32 icsk_probes_tstamp; - u32 icsk_user_timeout; - u64 icsk_ca_priv[13]; -}; - -struct inet_bind_bucket { - possible_net_t ib_net; - int l3mdev; - short unsigned int port; - signed char fastreuse; - signed char fastreuseport; - kuid_t fastuid; - struct in6_addr fast_v6_rcv_saddr; - __be32 fast_rcv_saddr; - short unsigned int fast_sk_family; - bool fast_ipv6_only; - struct hlist_node node; - struct hlist_head owners; -}; - -struct tcp_ulp_ops { - struct list_head list; - int (*init)(struct sock *); - void (*update)(struct sock *, struct proto *, void (*)(struct sock *)); - void (*release)(struct sock *); - int (*get_info)(const struct sock *, struct sk_buff *); - size_t (*get_info_size)(const struct sock *); - void (*clone)(const struct request_sock *, struct sock *, const gfp_t); - char name[16]; - struct module *owner; -}; - -struct tcp_fastopen_cookie { - __le64 val[2]; - s8 len; - bool exp; -}; - -struct tcp_sack_block { - u32 start_seq; - u32 end_seq; -}; - -struct tcp_options_received { - int ts_recent_stamp; - u32 ts_recent; - u32 rcv_tsval; - u32 rcv_tsecr; - u16 saw_tstamp: 1; - u16 tstamp_ok: 1; - u16 dsack: 1; - u16 wscale_ok: 1; - u16 sack_ok: 3; - u16 smc_ok: 1; - u16 snd_wscale: 4; - u16 rcv_wscale: 4; - u8 saw_unknown: 1; - u8 unused: 7; - u8 num_sacks; - u16 user_mss; - u16 mss_clamp; -}; - -struct tcp_rack { - u64 mstamp; - u32 rtt_us; - u32 end_seq; - u32 last_delivered; - u8 reo_wnd_steps; - u8 reo_wnd_persist: 5; - u8 dsack_seen: 1; - u8 advanced: 1; -}; - -struct tcp_fastopen_request; - -struct tcp_sock { - struct inet_connection_sock inet_conn; - u16 tcp_header_len; - u16 gso_segs; - __be32 pred_flags; - u64 bytes_received; - u32 segs_in; - u32 data_segs_in; - u32 rcv_nxt; - u32 copied_seq; - u32 rcv_wup; - u32 snd_nxt; - u32 segs_out; - u32 data_segs_out; - u64 bytes_sent; - u64 bytes_acked; - u32 dsack_dups; - u32 snd_una; - u32 snd_sml; - u32 rcv_tstamp; - u32 lsndtime; - u32 last_oow_ack_time; - u32 compressed_ack_rcv_nxt; - u32 tsoffset; - struct list_head tsq_node; - struct list_head tsorted_sent_queue; - u32 snd_wl1; - u32 snd_wnd; - u32 max_window; - u32 mss_cache; - u32 window_clamp; - u32 rcv_ssthresh; - struct tcp_rack rack; - u16 advmss; - u8 compressed_ack; - u8 dup_ack_counter: 2; - u8 tlp_retrans: 1; - u8 unused: 5; - u32 chrono_start; - u32 chrono_stat[3]; - u8 chrono_type: 2; - u8 rate_app_limited: 1; - u8 fastopen_connect: 1; - u8 fastopen_no_cookie: 1; - u8 is_sack_reneg: 1; - u8 fastopen_client_fail: 2; - u8 nonagle: 4; - u8 thin_lto: 1; - u8 recvmsg_inq: 1; - u8 repair: 1; - u8 frto: 1; - u8 repair_queue; - u8 save_syn: 2; - u8 syn_data: 1; - u8 syn_fastopen: 1; - u8 syn_fastopen_exp: 1; - u8 syn_fastopen_ch: 1; - u8 syn_data_acked: 1; - u8 is_cwnd_limited: 1; - u32 tlp_high_seq; - u32 tcp_tx_delay; - u64 tcp_wstamp_ns; - u64 tcp_clock_cache; - u64 tcp_mstamp; - u32 srtt_us; - u32 mdev_us; - u32 mdev_max_us; - u32 rttvar_us; - u32 rtt_seq; - struct minmax rtt_min; - u32 packets_out; - u32 retrans_out; - u32 max_packets_out; - u32 max_packets_seq; - u16 urg_data; - u8 ecn_flags; - u8 keepalive_probes; - u32 reordering; - u32 reord_seen; - u32 snd_up; - struct tcp_options_received rx_opt; - u32 snd_ssthresh; - u32 snd_cwnd; - u32 snd_cwnd_cnt; - u32 snd_cwnd_clamp; - u32 snd_cwnd_used; - u32 snd_cwnd_stamp; - u32 prior_cwnd; - u32 prr_delivered; - u32 prr_out; - u32 delivered; - u32 delivered_ce; - u32 lost; - u32 app_limited; - u64 first_tx_mstamp; - u64 delivered_mstamp; - u32 rate_delivered; - u32 rate_interval_us; - u32 rcv_wnd; - u32 write_seq; - u32 notsent_lowat; - u32 pushed_seq; - u32 lost_out; - u32 sacked_out; - struct hrtimer pacing_timer; - struct hrtimer compressed_ack_timer; - struct sk_buff *lost_skb_hint; - struct sk_buff *retransmit_skb_hint; - struct rb_root out_of_order_queue; - struct sk_buff *ooo_last_skb; - struct tcp_sack_block duplicate_sack[1]; - struct tcp_sack_block selective_acks[4]; - struct tcp_sack_block recv_sack_cache[4]; - struct sk_buff *highest_sack; - int lost_cnt_hint; - u32 prior_ssthresh; - u32 high_seq; - u32 retrans_stamp; - u32 undo_marker; - int undo_retrans; - u64 bytes_retrans; - u32 total_retrans; - u32 urg_seq; - unsigned int keepalive_time; - unsigned int keepalive_intvl; - int linger2; - u8 bpf_sock_ops_cb_flags; - u16 timeout_rehash; - u32 rcv_ooopack; - u32 rcv_rtt_last_tsecr; - struct { - u32 rtt_us; - u32 seq; - u64 time; - } rcv_rtt_est; - struct { - u32 space; - u32 seq; - u64 time; - } rcvq_space; - struct { - u32 probe_seq_start; - u32 probe_seq_end; - } mtu_probe; - u32 mtu_info; - struct tcp_fastopen_request *fastopen_req; - struct request_sock *fastopen_rsk; - struct saved_syn *saved_syn; -}; - -struct tcp_fastopen_request { - struct tcp_fastopen_cookie cookie; - struct msghdr *data; - size_t size; - int copied; - struct ubuf_info *uarg; -}; - -struct net_protocol { - int (*early_demux)(struct sk_buff *); - int (*early_demux_handler)(struct sk_buff *); - int (*handler)(struct sk_buff *); - int (*err_handler)(struct sk_buff *, u32); - unsigned int no_policy: 1; - unsigned int netns_ok: 1; - unsigned int icmp_strict_tag_validation: 1; -}; - -struct xfrm_replay { - void (*advance)(struct xfrm_state *, __be32); - int (*check)(struct xfrm_state *, struct sk_buff *, __be32); - int (*recheck)(struct xfrm_state *, struct sk_buff *, __be32); - void (*notify)(struct xfrm_state *, int); - int (*overflow)(struct xfrm_state *, struct sk_buff *); -}; - -struct xfrm_type { - char *description; - struct module *owner; - u8 proto; - u8 flags; - int (*init_state)(struct xfrm_state *); - void (*destructor)(struct xfrm_state *); - int (*input)(struct xfrm_state *, struct sk_buff *); - int (*output)(struct xfrm_state *, struct sk_buff *); - int (*reject)(struct xfrm_state *, struct sk_buff *, const struct flowi *); - int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **); -}; - -struct xfrm_type_offload { - char *description; - struct module *owner; - u8 proto; - void (*encap)(struct xfrm_state *, struct sk_buff *); - int (*input_tail)(struct xfrm_state *, struct sk_buff *); - int (*xmit)(struct xfrm_state *, struct sk_buff *, netdev_features_t); -}; - -struct xfrm_dst { - union { - struct dst_entry dst; - struct rtable rt; - struct rt6_info rt6; - } u; - struct dst_entry *route; - struct dst_entry *child; - struct dst_entry *path; - struct xfrm_policy *pols[2]; - int num_pols; - int num_xfrms; - u32 xfrm_genid; - u32 policy_genid; - u32 route_mtu_cached; - u32 child_mtu_cached; - u32 route_cookie; - u32 path_cookie; -}; - -struct cgroup_cls_state { - struct cgroup_subsys_state css; - u32 classid; -}; - -enum { - SK_MEMINFO_RMEM_ALLOC = 0, - SK_MEMINFO_RCVBUF = 1, - SK_MEMINFO_WMEM_ALLOC = 2, - SK_MEMINFO_SNDBUF = 3, - SK_MEMINFO_FWD_ALLOC = 4, - SK_MEMINFO_WMEM_QUEUED = 5, - SK_MEMINFO_OPTMEM = 6, - SK_MEMINFO_BACKLOG = 7, - SK_MEMINFO_DROPS = 8, - SK_MEMINFO_VARS = 9, -}; - -enum sknetlink_groups { - SKNLGRP_NONE = 0, - SKNLGRP_INET_TCP_DESTROY = 1, - SKNLGRP_INET_UDP_DESTROY = 2, - SKNLGRP_INET6_TCP_DESTROY = 3, - SKNLGRP_INET6_UDP_DESTROY = 4, - __SKNLGRP_MAX = 5, -}; - -struct inet_request_sock { - struct request_sock req; - u16 snd_wscale: 4; - u16 rcv_wscale: 4; - u16 tstamp_ok: 1; - u16 sack_ok: 1; - u16 wscale_ok: 1; - u16 ecn_ok: 1; - u16 acked: 1; - u16 no_srccheck: 1; - u16 smc_ok: 1; - u32 ir_mark; - union { - struct ip_options_rcu *ireq_opt; - struct { - struct ipv6_txoptions *ipv6_opt; - struct sk_buff *pktopts; - }; - }; -}; - -struct tcp_request_sock_ops; - -struct tcp_request_sock { - struct inet_request_sock req; - const struct tcp_request_sock_ops *af_specific; - u64 snt_synack; - bool tfo_listener; - bool is_mptcp; - u32 txhash; - u32 rcv_isn; - u32 snt_isn; - u32 ts_off; - u32 last_oow_ack_time; - u32 rcv_nxt; - u8 syn_tos; -}; - -enum tcp_synack_type { - TCP_SYNACK_NORMAL = 0, - TCP_SYNACK_FASTOPEN = 1, - TCP_SYNACK_COOKIE = 2, -}; - -struct tcp_request_sock_ops { - u16 mss_clamp; - void (*init_req)(struct request_sock *, const struct sock *, struct sk_buff *); - __u32 (*cookie_init_seq)(const struct sk_buff *, __u16 *); - struct dst_entry * (*route_req)(const struct sock *, struct flowi *, const struct request_sock *); - u32 (*init_seq)(const struct sk_buff *); - u32 (*init_ts_off)(const struct net *, const struct sk_buff *); - int (*send_synack)(const struct sock *, struct dst_entry *, struct flowi *, struct request_sock *, struct tcp_fastopen_cookie *, enum tcp_synack_type, struct sk_buff *); -}; - -struct nf_conntrack { - atomic_t use; -}; - -enum { - SKB_FCLONE_UNAVAILABLE = 0, - SKB_FCLONE_ORIG = 1, - SKB_FCLONE_CLONE = 2, -}; - -struct sk_buff_fclones { - struct sk_buff skb1; - struct sk_buff skb2; - refcount_t fclone_ref; -}; - -struct skb_seq_state { - __u32 lower_offset; - __u32 upper_offset; - __u32 frag_idx; - __u32 stepped_offset; - struct sk_buff *root_skb; - struct sk_buff *cur_skb; - __u8 *frag_data; -}; - -struct skb_checksum_ops { - __wsum (*update)(const void *, int, __wsum); - __wsum (*combine)(__wsum, __wsum, int, int); -}; - -struct skb_gso_cb { - union { - int mac_offset; - int data_offset; - }; - int encap_level; - __wsum csum; - __u16 csum_start; -}; - -struct napi_gro_cb { - void *frag0; - unsigned int frag0_len; - int data_offset; - u16 flush; - u16 flush_id; - u16 count; - u16 gro_remcsum_start; - long unsigned int age; - u16 proto; - u8 same_flow: 1; - u8 encap_mark: 1; - u8 csum_valid: 1; - u8 csum_cnt: 3; - u8 free: 2; - u8 is_ipv6: 1; - u8 is_fou: 1; - u8 is_atomic: 1; - u8 recursion_counter: 4; - u8 is_flist: 1; - __wsum csum; - struct sk_buff *last; -}; - -struct qdisc_walker { - int stop; - int skip; - int count; - int (*fn)(struct Qdisc *, long unsigned int, struct qdisc_walker *); -}; - -enum sctp_msg_flags { - MSG_NOTIFICATION = 32768, -}; - -struct ip_auth_hdr { - __u8 nexthdr; - __u8 hdrlen; - __be16 reserved; - __be32 spi; - __be32 seq_no; - __u8 auth_data[0]; -}; - -struct frag_hdr { - __u8 nexthdr; - __u8 reserved; - __be16 frag_off; - __be32 identification; -}; - -enum { - SCM_TSTAMP_SND = 0, - SCM_TSTAMP_SCHED = 1, - SCM_TSTAMP_ACK = 2, -}; - -struct xfrm_offload { - struct { - __u32 low; - __u32 hi; - } seq; - __u32 flags; - __u32 status; - __u8 proto; -}; - -struct sec_path { - int len; - int olen; - struct xfrm_state *xvec[6]; - struct xfrm_offload ovec[1]; -}; - -struct mpls_shim_hdr { - __be32 label_stack_entry; -}; - -struct napi_alloc_cache { - struct page_frag_cache page; - unsigned int skb_count; - void *skb_cache[64]; -}; - -struct ahash_request___2; - -struct scm_cookie { - struct pid *pid; - struct scm_fp_list *fp; - struct scm_creds creds; - u32 secid; -}; - -struct scm_timestamping { - struct __kernel_old_timespec ts[3]; -}; - -struct scm_timestamping64 { - struct __kernel_timespec ts[3]; -}; - -enum { - TCA_STATS_UNSPEC = 0, - TCA_STATS_BASIC = 1, - TCA_STATS_RATE_EST = 2, - TCA_STATS_QUEUE = 3, - TCA_STATS_APP = 4, - TCA_STATS_RATE_EST64 = 5, - TCA_STATS_PAD = 6, - TCA_STATS_BASIC_HW = 7, - TCA_STATS_PKT64 = 8, - __TCA_STATS_MAX = 9, -}; - -struct gnet_stats_basic { - __u64 bytes; - __u32 packets; -}; - -struct gnet_stats_rate_est { - __u32 bps; - __u32 pps; -}; - -struct gnet_stats_rate_est64 { - __u64 bps; - __u64 pps; -}; - -struct gnet_estimator { - signed char interval; - unsigned char ewma_log; -}; - -struct net_rate_estimator { - struct gnet_stats_basic_packed *bstats; - spinlock_t *stats_lock; - seqcount_t *running; - struct gnet_stats_basic_cpu *cpu_bstats; - u8 ewma_log; - u8 intvl_log; - seqcount_t seq; - u64 last_packets; - u64 last_bytes; - u64 avpps; - u64 avbps; - long unsigned int next_jiffies; - struct timer_list timer; - struct callback_head rcu; -}; - -enum { - RTM_BASE = 16, - RTM_NEWLINK = 16, - RTM_DELLINK = 17, - RTM_GETLINK = 18, - RTM_SETLINK = 19, - RTM_NEWADDR = 20, - RTM_DELADDR = 21, - RTM_GETADDR = 22, - RTM_NEWROUTE = 24, - RTM_DELROUTE = 25, - RTM_GETROUTE = 26, - RTM_NEWNEIGH = 28, - RTM_DELNEIGH = 29, - RTM_GETNEIGH = 30, - RTM_NEWRULE = 32, - RTM_DELRULE = 33, - RTM_GETRULE = 34, - RTM_NEWQDISC = 36, - RTM_DELQDISC = 37, - RTM_GETQDISC = 38, - RTM_NEWTCLASS = 40, - RTM_DELTCLASS = 41, - RTM_GETTCLASS = 42, - RTM_NEWTFILTER = 44, - RTM_DELTFILTER = 45, - RTM_GETTFILTER = 46, - RTM_NEWACTION = 48, - RTM_DELACTION = 49, - RTM_GETACTION = 50, - RTM_NEWPREFIX = 52, - RTM_GETMULTICAST = 58, - RTM_GETANYCAST = 62, - RTM_NEWNEIGHTBL = 64, - RTM_GETNEIGHTBL = 66, - RTM_SETNEIGHTBL = 67, - RTM_NEWNDUSEROPT = 68, - RTM_NEWADDRLABEL = 72, - RTM_DELADDRLABEL = 73, - RTM_GETADDRLABEL = 74, - RTM_GETDCB = 78, - RTM_SETDCB = 79, - RTM_NEWNETCONF = 80, - RTM_DELNETCONF = 81, - RTM_GETNETCONF = 82, - RTM_NEWMDB = 84, - RTM_DELMDB = 85, - RTM_GETMDB = 86, - RTM_NEWNSID = 88, - RTM_DELNSID = 89, - RTM_GETNSID = 90, - RTM_NEWSTATS = 92, - RTM_GETSTATS = 94, - RTM_NEWCACHEREPORT = 96, - RTM_NEWCHAIN = 100, - RTM_DELCHAIN = 101, - RTM_GETCHAIN = 102, - RTM_NEWNEXTHOP = 104, - RTM_DELNEXTHOP = 105, - RTM_GETNEXTHOP = 106, - RTM_NEWLINKPROP = 108, - RTM_DELLINKPROP = 109, - RTM_GETLINKPROP = 110, - RTM_NEWVLAN = 112, - RTM_DELVLAN = 113, - RTM_GETVLAN = 114, - __RTM_MAX = 115, -}; - -struct rtgenmsg { - unsigned char rtgen_family; -}; - -enum rtnetlink_groups { - RTNLGRP_NONE = 0, - RTNLGRP_LINK = 1, - RTNLGRP_NOTIFY = 2, - RTNLGRP_NEIGH = 3, - RTNLGRP_TC = 4, - RTNLGRP_IPV4_IFADDR = 5, - RTNLGRP_IPV4_MROUTE = 6, - RTNLGRP_IPV4_ROUTE = 7, - RTNLGRP_IPV4_RULE = 8, - RTNLGRP_IPV6_IFADDR = 9, - RTNLGRP_IPV6_MROUTE = 10, - RTNLGRP_IPV6_ROUTE = 11, - RTNLGRP_IPV6_IFINFO = 12, - RTNLGRP_DECnet_IFADDR = 13, - RTNLGRP_NOP2 = 14, - RTNLGRP_DECnet_ROUTE = 15, - RTNLGRP_DECnet_RULE = 16, - RTNLGRP_NOP4 = 17, - RTNLGRP_IPV6_PREFIX = 18, - RTNLGRP_IPV6_RULE = 19, - RTNLGRP_ND_USEROPT = 20, - RTNLGRP_PHONET_IFADDR = 21, - RTNLGRP_PHONET_ROUTE = 22, - RTNLGRP_DCB = 23, - RTNLGRP_IPV4_NETCONF = 24, - RTNLGRP_IPV6_NETCONF = 25, - RTNLGRP_MDB = 26, - RTNLGRP_MPLS_ROUTE = 27, - RTNLGRP_NSID = 28, - RTNLGRP_MPLS_NETCONF = 29, - RTNLGRP_IPV4_MROUTE_R = 30, - RTNLGRP_IPV6_MROUTE_R = 31, - RTNLGRP_NEXTHOP = 32, - RTNLGRP_BRVLAN = 33, - __RTNLGRP_MAX = 34, -}; - -enum { - NETNSA_NONE = 0, - NETNSA_NSID = 1, - NETNSA_PID = 2, - NETNSA_FD = 3, - NETNSA_TARGET_NSID = 4, - NETNSA_CURRENT_NSID = 5, - __NETNSA_MAX = 6, -}; - -struct pcpu_gen_cookie { - local_t nesting; - u64 last; -}; - -struct gen_cookie { - struct pcpu_gen_cookie *local; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - atomic64_t forward_last; - atomic64_t reverse_last; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum rtnl_link_flags { - RTNL_FLAG_DOIT_UNLOCKED = 1, -}; - -struct net_fill_args { - u32 portid; - u32 seq; - int flags; - int cmd; - int nsid; - bool add_ref; - int ref_nsid; -}; - -struct rtnl_net_dump_cb { - struct net *tgt_net; - struct net *ref_net; - struct sk_buff *skb; - struct net_fill_args fillargs; - int idx; - int s_idx; -}; - -typedef u16 u_int16_t; - -typedef u32 u_int32_t; - -typedef u64 u_int64_t; - -struct flow_dissector_key_control { - u16 thoff; - u16 addr_type; - u32 flags; -}; - -enum flow_dissect_ret { - FLOW_DISSECT_RET_OUT_GOOD = 0, - FLOW_DISSECT_RET_OUT_BAD = 1, - FLOW_DISSECT_RET_PROTO_AGAIN = 2, - FLOW_DISSECT_RET_IPPROTO_AGAIN = 3, - FLOW_DISSECT_RET_CONTINUE = 4, -}; - -struct flow_dissector_key_basic { - __be16 n_proto; - u8 ip_proto; - u8 padding; -}; - -struct flow_dissector_key_tags { - u32 flow_label; -}; - -struct flow_dissector_key_vlan { - union { - struct { - u16 vlan_id: 12; - u16 vlan_dei: 1; - u16 vlan_priority: 3; - }; - __be16 vlan_tci; - }; - __be16 vlan_tpid; -}; - -struct flow_dissector_mpls_lse { - u32 mpls_ttl: 8; - u32 mpls_bos: 1; - u32 mpls_tc: 3; - u32 mpls_label: 20; -}; - -struct flow_dissector_key_mpls { - struct flow_dissector_mpls_lse ls[7]; - u8 used_lses; -}; - -struct flow_dissector_key_enc_opts { - u8 data[255]; - u8 len; - __be16 dst_opt_type; -}; - -struct flow_dissector_key_keyid { - __be32 keyid; -}; - -struct flow_dissector_key_ipv4_addrs { - __be32 src; - __be32 dst; -}; - -struct flow_dissector_key_ipv6_addrs { - struct in6_addr src; - struct in6_addr dst; -}; - -struct flow_dissector_key_tipc { - __be32 key; -}; - -struct flow_dissector_key_addrs { - union { - struct flow_dissector_key_ipv4_addrs v4addrs; - struct flow_dissector_key_ipv6_addrs v6addrs; - struct flow_dissector_key_tipc tipckey; - }; -}; - -struct flow_dissector_key_arp { - __u32 sip; - __u32 tip; - __u8 op; - unsigned char sha[6]; - unsigned char tha[6]; -}; - -struct flow_dissector_key_ports { - union { - __be32 ports; - struct { - __be16 src; - __be16 dst; - }; - }; -}; - -struct flow_dissector_key_icmp { - struct { - u8 type; - u8 code; - }; - u16 id; -}; - -struct flow_dissector_key_eth_addrs { - unsigned char dst[6]; - unsigned char src[6]; -}; - -struct flow_dissector_key_tcp { - __be16 flags; -}; - -struct flow_dissector_key_ip { - __u8 tos; - __u8 ttl; -}; - -struct flow_dissector_key_meta { - int ingress_ifindex; - u16 ingress_iftype; -}; - -struct flow_dissector_key_ct { - u16 ct_state; - u16 ct_zone; - u32 ct_mark; - u32 ct_labels[4]; -}; - -struct flow_dissector_key_hash { - u32 hash; -}; - -struct flow_dissector_key { - enum flow_dissector_key_id key_id; - size_t offset; -}; - -struct flow_dissector { - unsigned int used_keys; - short unsigned int offset[28]; -}; - -struct flow_keys_basic { - struct flow_dissector_key_control control; - struct flow_dissector_key_basic basic; -}; - -struct flow_keys { - struct flow_dissector_key_control control; - struct flow_dissector_key_basic basic; - struct flow_dissector_key_tags tags; - struct flow_dissector_key_vlan vlan; - struct flow_dissector_key_vlan cvlan; - struct flow_dissector_key_keyid keyid; - struct flow_dissector_key_ports ports; - struct flow_dissector_key_icmp icmp; - struct flow_dissector_key_addrs addrs; - int: 32; -}; - -struct flow_keys_digest { - u8 data[16]; -}; - -enum ip_conntrack_info { - IP_CT_ESTABLISHED = 0, - IP_CT_RELATED = 1, - IP_CT_NEW = 2, - IP_CT_IS_REPLY = 3, - IP_CT_ESTABLISHED_REPLY = 3, - IP_CT_RELATED_REPLY = 4, - IP_CT_NUMBER = 5, - IP_CT_UNTRACKED = 7, -}; - -struct xt_table_info; - -struct xt_table { - struct list_head list; - unsigned int valid_hooks; - struct xt_table_info *private; - struct module *me; - u_int8_t af; - int priority; - int (*table_init)(struct net *); - const char name[32]; -}; - -union nf_inet_addr { - __u32 all[4]; - __be32 ip; - __be32 ip6[4]; - struct in_addr in; - struct in6_addr in6; -}; - -struct ip_ct_tcp_state { - u_int32_t td_end; - u_int32_t td_maxend; - u_int32_t td_maxwin; - u_int32_t td_maxack; - u_int8_t td_scale; - u_int8_t flags; -}; - -struct ip_ct_tcp { - struct ip_ct_tcp_state seen[2]; - u_int8_t state; - u_int8_t last_dir; - u_int8_t retrans; - u_int8_t last_index; - u_int32_t last_seq; - u_int32_t last_ack; - u_int32_t last_end; - u_int16_t last_win; - u_int8_t last_wscale; - u_int8_t last_flags; -}; - -union nf_conntrack_man_proto { - __be16 all; - struct { - __be16 port; - } tcp; - struct { - __be16 port; - } udp; - struct { - __be16 id; - } icmp; - struct { - __be16 port; - } dccp; - struct { - __be16 port; - } sctp; - struct { - __be16 key; - } gre; -}; - -struct nf_ct_dccp { - u_int8_t role[2]; - u_int8_t state; - u_int8_t last_pkt; - u_int8_t last_dir; - u_int64_t handshake_seq; -}; - -struct ip_ct_sctp { - enum sctp_conntrack state; - __be32 vtag[2]; - u8 last_dir; - u8 flags; -}; - -struct nf_ct_event; - -struct nf_ct_event_notifier { - int (*fcn)(unsigned int, struct nf_ct_event *); -}; - -struct nf_exp_event; - -struct nf_exp_event_notifier { - int (*fcn)(unsigned int, struct nf_exp_event *); -}; - -enum bpf_ret_code { - BPF_OK = 0, - BPF_DROP = 2, - BPF_REDIRECT = 7, - BPF_LWT_REROUTE = 128, -}; - -enum { - BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = 1, - BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = 2, - BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = 4, -}; - -enum devlink_port_type { - DEVLINK_PORT_TYPE_NOTSET = 0, - DEVLINK_PORT_TYPE_AUTO = 1, - DEVLINK_PORT_TYPE_ETH = 2, - DEVLINK_PORT_TYPE_IB = 3, -}; - -enum devlink_port_flavour { - DEVLINK_PORT_FLAVOUR_PHYSICAL = 0, - DEVLINK_PORT_FLAVOUR_CPU = 1, - DEVLINK_PORT_FLAVOUR_DSA = 2, - DEVLINK_PORT_FLAVOUR_PCI_PF = 3, - DEVLINK_PORT_FLAVOUR_PCI_VF = 4, - DEVLINK_PORT_FLAVOUR_VIRTUAL = 5, - DEVLINK_PORT_FLAVOUR_UNUSED = 6, -}; - -struct devlink_port_phys_attrs { - u32 port_number; - u32 split_subport_number; -}; - -struct devlink_port_pci_pf_attrs { - u32 controller; - u16 pf; - u8 external: 1; -}; - -struct devlink_port_pci_vf_attrs { - u32 controller; - u16 pf; - u16 vf; - u8 external: 1; -}; - -struct devlink_port_attrs { - u8 split: 1; - u8 splittable: 1; - u32 lanes; - enum devlink_port_flavour flavour; - struct netdev_phys_item_id switch_id; - union { - struct devlink_port_phys_attrs phys; - struct devlink_port_pci_pf_attrs pci_pf; - struct devlink_port_pci_vf_attrs pci_vf; - }; -}; - -struct devlink; - -struct devlink_port { - struct list_head list; - struct list_head param_list; - struct list_head region_list; - struct devlink *devlink; - unsigned int index; - bool registered; - spinlock_t type_lock; - enum devlink_port_type type; - enum devlink_port_type desired_type; - void *type_dev; - struct devlink_port_attrs attrs; - u8 attrs_set: 1; - u8 switch_port: 1; - struct delayed_work type_warn_dw; - struct list_head reporter_list; - struct mutex reporters_lock; -}; - -struct ip_tunnel_key { - __be64 tun_id; - union { - struct { - __be32 src; - __be32 dst; - } ipv4; - struct { - struct in6_addr src; - struct in6_addr dst; - } ipv6; - } u; - __be16 tun_flags; - u8 tos; - u8 ttl; - __be32 label; - __be16 tp_src; - __be16 tp_dst; -}; - -struct dst_cache_pcpu; - -struct dst_cache { - struct dst_cache_pcpu *cache; - long unsigned int reset_ts; -}; - -struct ip_tunnel_info { - struct ip_tunnel_key key; - struct dst_cache dst_cache; - u8 options_len; - u8 mode; -}; - -union tcp_word_hdr { - struct tcphdr hdr; - __be32 words[5]; -}; - -enum devlink_sb_pool_type { - DEVLINK_SB_POOL_TYPE_INGRESS = 0, - DEVLINK_SB_POOL_TYPE_EGRESS = 1, -}; - -enum devlink_sb_threshold_type { - DEVLINK_SB_THRESHOLD_TYPE_STATIC = 0, - DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC = 1, -}; - -enum devlink_eswitch_encap_mode { - DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0, - DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1, -}; - -enum devlink_trap_action { - DEVLINK_TRAP_ACTION_DROP = 0, - DEVLINK_TRAP_ACTION_TRAP = 1, - DEVLINK_TRAP_ACTION_MIRROR = 2, -}; - -enum devlink_trap_type { - DEVLINK_TRAP_TYPE_DROP = 0, - DEVLINK_TRAP_TYPE_EXCEPTION = 1, - DEVLINK_TRAP_TYPE_CONTROL = 2, -}; - -enum devlink_reload_action { - DEVLINK_RELOAD_ACTION_UNSPEC = 0, - DEVLINK_RELOAD_ACTION_DRIVER_REINIT = 1, - DEVLINK_RELOAD_ACTION_FW_ACTIVATE = 2, - __DEVLINK_RELOAD_ACTION_MAX = 3, - DEVLINK_RELOAD_ACTION_MAX = 2, -}; - -enum devlink_reload_limit { - DEVLINK_RELOAD_LIMIT_UNSPEC = 0, - DEVLINK_RELOAD_LIMIT_NO_RESET = 1, - __DEVLINK_RELOAD_LIMIT_MAX = 2, - DEVLINK_RELOAD_LIMIT_MAX = 1, -}; - -enum devlink_dpipe_field_mapping_type { - DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0, - DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 1, -}; - -struct devlink_dev_stats { - u32 reload_stats[6]; - u32 remote_reload_stats[6]; -}; - -struct devlink_dpipe_headers; - -struct devlink_ops; - -struct devlink { - struct list_head list; - struct list_head port_list; - struct list_head sb_list; - struct list_head dpipe_table_list; - struct list_head resource_list; - struct list_head param_list; - struct list_head region_list; - struct list_head reporter_list; - struct mutex reporters_lock; - struct devlink_dpipe_headers *dpipe_headers; - struct list_head trap_list; - struct list_head trap_group_list; - struct list_head trap_policer_list; - const struct devlink_ops *ops; - struct xarray snapshot_ids; - struct devlink_dev_stats stats; - struct device *dev; - possible_net_t _net; - struct mutex lock; - u8 reload_failed: 1; - u8 reload_enabled: 1; - u8 registered: 1; - long: 61; - long: 64; - char priv[0]; -}; - -struct devlink_dpipe_header; - -struct devlink_dpipe_headers { - struct devlink_dpipe_header **headers; - unsigned int headers_count; -}; - -struct devlink_info_req; - -struct devlink_sb_pool_info; - -struct devlink_flash_update_params; - -struct devlink_trap; - -struct devlink_trap_group; - -struct devlink_trap_policer; - -struct devlink_ops { - u32 supported_flash_update_params; - long unsigned int reload_actions; - long unsigned int reload_limits; - int (*reload_down)(struct devlink *, bool, enum devlink_reload_action, enum devlink_reload_limit, struct netlink_ext_ack *); - int (*reload_up)(struct devlink *, enum devlink_reload_action, enum devlink_reload_limit, u32 *, struct netlink_ext_ack *); - int (*port_type_set)(struct devlink_port *, enum devlink_port_type); - int (*port_split)(struct devlink *, unsigned int, unsigned int, struct netlink_ext_ack *); - int (*port_unsplit)(struct devlink *, unsigned int, struct netlink_ext_ack *); - int (*sb_pool_get)(struct devlink *, unsigned int, u16, struct devlink_sb_pool_info *); - int (*sb_pool_set)(struct devlink *, unsigned int, u16, u32, enum devlink_sb_threshold_type, struct netlink_ext_ack *); - int (*sb_port_pool_get)(struct devlink_port *, unsigned int, u16, u32 *); - int (*sb_port_pool_set)(struct devlink_port *, unsigned int, u16, u32, struct netlink_ext_ack *); - int (*sb_tc_pool_bind_get)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u16 *, u32 *); - int (*sb_tc_pool_bind_set)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u16, u32, struct netlink_ext_ack *); - int (*sb_occ_snapshot)(struct devlink *, unsigned int); - int (*sb_occ_max_clear)(struct devlink *, unsigned int); - int (*sb_occ_port_pool_get)(struct devlink_port *, unsigned int, u16, u32 *, u32 *); - int (*sb_occ_tc_port_bind_get)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u32 *, u32 *); - int (*eswitch_mode_get)(struct devlink *, u16 *); - int (*eswitch_mode_set)(struct devlink *, u16, struct netlink_ext_ack *); - int (*eswitch_inline_mode_get)(struct devlink *, u8 *); - int (*eswitch_inline_mode_set)(struct devlink *, u8, struct netlink_ext_ack *); - int (*eswitch_encap_mode_get)(struct devlink *, enum devlink_eswitch_encap_mode *); - int (*eswitch_encap_mode_set)(struct devlink *, enum devlink_eswitch_encap_mode, struct netlink_ext_ack *); - int (*info_get)(struct devlink *, struct devlink_info_req *, struct netlink_ext_ack *); - int (*flash_update)(struct devlink *, struct devlink_flash_update_params *, struct netlink_ext_ack *); - int (*trap_init)(struct devlink *, const struct devlink_trap *, void *); - void (*trap_fini)(struct devlink *, const struct devlink_trap *, void *); - int (*trap_action_set)(struct devlink *, const struct devlink_trap *, enum devlink_trap_action, struct netlink_ext_ack *); - int (*trap_group_init)(struct devlink *, const struct devlink_trap_group *); - int (*trap_group_set)(struct devlink *, const struct devlink_trap_group *, const struct devlink_trap_policer *, struct netlink_ext_ack *); - int (*trap_group_action_set)(struct devlink *, const struct devlink_trap_group *, enum devlink_trap_action, struct netlink_ext_ack *); - int (*trap_policer_init)(struct devlink *, const struct devlink_trap_policer *); - void (*trap_policer_fini)(struct devlink *, const struct devlink_trap_policer *); - int (*trap_policer_set)(struct devlink *, const struct devlink_trap_policer *, u64, u64, struct netlink_ext_ack *); - int (*trap_policer_counter_get)(struct devlink *, const struct devlink_trap_policer *, u64 *); - int (*port_function_hw_addr_get)(struct devlink *, struct devlink_port *, u8 *, int *, struct netlink_ext_ack *); - int (*port_function_hw_addr_set)(struct devlink *, struct devlink_port *, const u8 *, int, struct netlink_ext_ack *); -}; - -struct devlink_sb_pool_info { - enum devlink_sb_pool_type pool_type; - u32 size; - enum devlink_sb_threshold_type threshold_type; - u32 cell_size; -}; - -struct devlink_dpipe_field { - const char *name; - unsigned int id; - unsigned int bitwidth; - enum devlink_dpipe_field_mapping_type mapping_type; -}; - -struct devlink_dpipe_header { - const char *name; - unsigned int id; - struct devlink_dpipe_field *fields; - unsigned int fields_count; - bool global; -}; - -struct devlink_flash_update_params { - const char *file_name; - const char *component; - u32 overwrite_mask; -}; - -struct devlink_trap_policer { - u32 id; - u64 init_rate; - u64 init_burst; - u64 max_rate; - u64 min_rate; - u64 max_burst; - u64 min_burst; -}; - -struct devlink_trap_group { - const char *name; - u16 id; - bool generic; - u32 init_policer_id; -}; - -struct devlink_trap { - enum devlink_trap_type type; - enum devlink_trap_action init_action; - bool generic; - u16 id; - const char *name; - u16 init_group_id; - u32 metadata_cap; -}; - -struct arphdr { - __be16 ar_hrd; - __be16 ar_pro; - unsigned char ar_hln; - unsigned char ar_pln; - __be16 ar_op; -}; - -enum lwtunnel_encap_types { - LWTUNNEL_ENCAP_NONE = 0, - LWTUNNEL_ENCAP_MPLS = 1, - LWTUNNEL_ENCAP_IP = 2, - LWTUNNEL_ENCAP_ILA = 3, - LWTUNNEL_ENCAP_IP6 = 4, - LWTUNNEL_ENCAP_SEG6 = 5, - LWTUNNEL_ENCAP_BPF = 6, - LWTUNNEL_ENCAP_SEG6_LOCAL = 7, - LWTUNNEL_ENCAP_RPL = 8, - __LWTUNNEL_ENCAP_MAX = 9, -}; - -enum metadata_type { - METADATA_IP_TUNNEL = 0, - METADATA_HW_PORT_MUX = 1, -}; - -struct hw_port_info { - struct net_device *lower_dev; - u32 port_id; -}; - -struct metadata_dst { - struct dst_entry dst; - enum metadata_type type; - union { - struct ip_tunnel_info tun_info; - struct hw_port_info port_info; - } u; -}; - -struct gre_base_hdr { - __be16 flags; - __be16 protocol; -}; - -struct gre_full_hdr { - struct gre_base_hdr fixed_header; - __be16 csum; - __be16 reserved1; - __be32 key; - __be32 seq; -}; - -struct pptp_gre_header { - struct gre_base_hdr gre_hd; - __be16 payload_len; - __be16 call_id; - __be32 seq; - __be32 ack; -}; - -struct tipc_basic_hdr { - __be32 w[4]; -}; - -struct icmphdr { - __u8 type; - __u8 code; - __sum16 checksum; - union { - struct { - __be16 id; - __be16 sequence; - } echo; - __be32 gateway; - struct { - __be16 __unused; - __be16 mtu; - } frag; - __u8 reserved[4]; - } un; -}; - -enum dccp_state { - DCCP_OPEN = 1, - DCCP_REQUESTING = 2, - DCCP_LISTEN = 10, - DCCP_RESPOND = 3, - DCCP_ACTIVE_CLOSEREQ = 4, - DCCP_PASSIVE_CLOSE = 8, - DCCP_CLOSING = 11, - DCCP_TIME_WAIT = 6, - DCCP_CLOSED = 7, - DCCP_NEW_SYN_RECV = 12, - DCCP_PARTOPEN = 13, - DCCP_PASSIVE_CLOSEREQ = 14, - DCCP_MAX_STATES = 15, -}; - -enum l2tp_debug_flags { - L2TP_MSG_DEBUG = 1, - L2TP_MSG_CONTROL = 2, - L2TP_MSG_SEQ = 4, - L2TP_MSG_DATA = 8, -}; - -struct pppoe_tag { - __be16 tag_type; - __be16 tag_len; - char tag_data[0]; -}; - -struct pppoe_hdr { - __u8 type: 4; - __u8 ver: 4; - __u8 code; - __be16 sid; - __be16 length; - struct pppoe_tag tag[0]; -}; - -struct mpls_label { - __be32 entry; -}; - -enum batadv_packettype { - BATADV_IV_OGM = 0, - BATADV_BCAST = 1, - BATADV_CODED = 2, - BATADV_ELP = 3, - BATADV_OGM2 = 4, - BATADV_UNICAST = 64, - BATADV_UNICAST_FRAG = 65, - BATADV_UNICAST_4ADDR = 66, - BATADV_ICMP = 67, - BATADV_UNICAST_TVLV = 68, -}; - -struct batadv_unicast_packet { - __u8 packet_type; - __u8 version; - __u8 ttl; - __u8 ttvn; - __u8 dest[6]; -}; - -struct nf_conntrack_zone { - u16 id; - u8 flags; - u8 dir; -}; - -struct nf_conntrack_man { - union nf_inet_addr u3; - union nf_conntrack_man_proto u; - u_int16_t l3num; -}; - -struct nf_conntrack_tuple { - struct nf_conntrack_man src; - struct { - union nf_inet_addr u3; - union { - __be16 all; - struct { - __be16 port; - } tcp; - struct { - __be16 port; - } udp; - struct { - u_int8_t type; - u_int8_t code; - } icmp; - struct { - __be16 port; - } dccp; - struct { - __be16 port; - } sctp; - struct { - __be16 key; - } gre; - } u; - u_int8_t protonum; - u_int8_t dir; - } dst; -}; - -struct nf_conntrack_tuple_hash { - struct hlist_nulls_node hnnode; - struct nf_conntrack_tuple tuple; -}; - -struct nf_ct_udp { - long unsigned int stream_ts; -}; - -struct nf_ct_gre { - unsigned int stream_timeout; - unsigned int timeout; -}; - -union nf_conntrack_proto { - struct nf_ct_dccp dccp; - struct ip_ct_sctp sctp; - struct ip_ct_tcp tcp; - struct nf_ct_udp udp; - struct nf_ct_gre gre; - unsigned int tmpl_padto; -}; - -struct nf_ct_ext; - -struct nf_conn { - struct nf_conntrack ct_general; - spinlock_t lock; - u32 timeout; - struct nf_conntrack_zone zone; - struct nf_conntrack_tuple_hash tuplehash[2]; - long unsigned int status; - u16 cpu; - possible_net_t ct_net; - struct hlist_node nat_bysource; - struct { } __nfct_init_offset; - struct nf_conn *master; - u_int32_t mark; - struct nf_ct_ext *ext; - union nf_conntrack_proto proto; -}; - -struct xt_table_info { - unsigned int size; - unsigned int number; - unsigned int initial_entries; - unsigned int hook_entry[5]; - unsigned int underflow[5]; - unsigned int stacksize; - void ***jumpstack; - unsigned char entries[0]; -}; - -struct nf_conntrack_tuple_mask { - struct { - union nf_inet_addr u3; - union nf_conntrack_man_proto u; - } src; -}; - -struct nf_ct_ext { - u8 offset[8]; - u8 len; - char data[0]; -}; - -struct nf_conntrack_helper; - -struct nf_conntrack_expect { - struct hlist_node lnode; - struct hlist_node hnode; - struct nf_conntrack_tuple tuple; - struct nf_conntrack_tuple_mask mask; - void (*expectfn)(struct nf_conn *, struct nf_conntrack_expect *); - struct nf_conntrack_helper *helper; - struct nf_conn *master; - struct timer_list timeout; - refcount_t use; - unsigned int flags; - unsigned int class; - union nf_inet_addr saved_addr; - union nf_conntrack_man_proto saved_proto; - enum ip_conntrack_dir dir; - struct callback_head rcu; -}; - -enum nf_ct_ext_id { - NF_CT_EXT_HELPER = 0, - NF_CT_EXT_NAT = 1, - NF_CT_EXT_SEQADJ = 2, - NF_CT_EXT_ACCT = 3, - NF_CT_EXT_ECACHE = 4, - NF_CT_EXT_TSTAMP = 5, - NF_CT_EXT_LABELS = 6, - NF_CT_EXT_SYNPROXY = 7, - NF_CT_EXT_NUM = 8, -}; - -struct nf_ct_event { - struct nf_conn *ct; - u32 portid; - int report; -}; - -struct nf_exp_event { - struct nf_conntrack_expect *exp; - u32 portid; - int report; -}; - -struct nf_conn_labels { - long unsigned int bits[2]; -}; - -struct _flow_keys_digest_data { - __be16 n_proto; - u8 ip_proto; - u8 padding; - __be32 ports; - __be32 src; - __be32 dst; -}; - -struct rps_sock_flow_table { - u32 mask; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 ents[0]; -}; - -enum { - IF_OPER_UNKNOWN = 0, - IF_OPER_NOTPRESENT = 1, - IF_OPER_DOWN = 2, - IF_OPER_LOWERLAYERDOWN = 3, - IF_OPER_TESTING = 4, - IF_OPER_DORMANT = 5, - IF_OPER_UP = 6, -}; - -enum nf_dev_hooks { - NF_NETDEV_INGRESS = 0, - NF_NETDEV_NUMHOOKS = 1, -}; - -struct ifbond { - __s32 bond_mode; - __s32 num_slaves; - __s32 miimon; -}; - -typedef struct ifbond ifbond; - -struct ifslave { - __s32 slave_id; - char slave_name[16]; - __s8 link; - __s8 state; - __u32 link_failure_count; -}; - -typedef struct ifslave ifslave; - -struct netdev_boot_setup { - char name[16]; - struct ifmap map; -}; - -enum { - NAPIF_STATE_SCHED = 1, - NAPIF_STATE_MISSED = 2, - NAPIF_STATE_DISABLE = 4, - NAPIF_STATE_NPSVC = 8, - NAPIF_STATE_LISTED = 16, - NAPIF_STATE_NO_BUSY_POLL = 32, - NAPIF_STATE_IN_BUSY_POLL = 64, -}; - -enum gro_result { - GRO_MERGED = 0, - GRO_MERGED_FREE = 1, - GRO_HELD = 2, - GRO_NORMAL = 3, - GRO_DROP = 4, - GRO_CONSUMED = 5, -}; - -typedef enum gro_result gro_result_t; - -struct bpf_xdp_link { - struct bpf_link link; - struct net_device *dev; - int flags; -}; - -struct netdev_net_notifier { - struct list_head list; - struct notifier_block *nb; -}; - -struct netpoll; - -struct netpoll_info { - refcount_t refcnt; - struct semaphore dev_lock; - struct sk_buff_head txq; - struct delayed_work tx_work; - struct netpoll *netpoll; - struct callback_head rcu; -}; - -struct packet_type { - __be16 type; - bool ignore_outgoing; - struct net_device *dev; - int (*func)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); - void (*list_func)(struct list_head *, struct packet_type *, struct net_device *); - bool (*id_match)(struct packet_type *, struct sock *); - void *af_packet_priv; - struct list_head list; -}; - -struct offload_callbacks { - struct sk_buff * (*gso_segment)(struct sk_buff *, netdev_features_t); - struct sk_buff * (*gro_receive)(struct list_head *, struct sk_buff *); - int (*gro_complete)(struct sk_buff *, int); -}; - -struct packet_offload { - __be16 type; - u16 priority; - struct offload_callbacks callbacks; - struct list_head list; -}; - -struct netdev_notifier_info_ext { - struct netdev_notifier_info info; - union { - u32 mtu; - } ext; -}; - -struct netdev_notifier_change_info { - struct netdev_notifier_info info; - unsigned int flags_changed; -}; - -struct netdev_notifier_changeupper_info { - struct netdev_notifier_info info; - struct net_device *upper_dev; - bool master; - bool linking; - void *upper_info; -}; - -struct netdev_notifier_changelowerstate_info { - struct netdev_notifier_info info; - void *lower_state_info; -}; - -struct netdev_notifier_pre_changeaddr_info { - struct netdev_notifier_info info; - const unsigned char *dev_addr; -}; - -typedef int (*bpf_op_t)(struct net_device *, struct netdev_bpf *); - -enum { - NESTED_SYNC_IMM_BIT = 0, - NESTED_SYNC_TODO_BIT = 1, -}; - -struct netdev_nested_priv { - unsigned char flags; - void *data; -}; - -struct netdev_bonding_info { - ifslave slave; - ifbond master; -}; - -struct netdev_notifier_bonding_info { - struct netdev_notifier_info info; - struct netdev_bonding_info bonding_info; -}; - -union inet_addr { - __u32 all[4]; - __be32 ip; - __be32 ip6[4]; - struct in_addr in; - struct in6_addr in6; -}; - -struct netpoll { - struct net_device *dev; - char dev_name[16]; - const char *name; - union inet_addr local_ip; - union inet_addr remote_ip; - bool ipv6; - u16 local_port; - u16 remote_port; - u8 remote_mac[6]; -}; - -enum qdisc_state_t { - __QDISC_STATE_SCHED = 0, - __QDISC_STATE_DEACTIVATED = 1, - __QDISC_STATE_MISSED = 2, -}; - -struct tcf_walker { - int stop; - int skip; - int count; - bool nonempty; - long unsigned int cookie; - int (*fn)(struct tcf_proto *, void *, struct tcf_walker *); -}; - -enum { - IPV4_DEVCONF_FORWARDING = 1, - IPV4_DEVCONF_MC_FORWARDING = 2, - IPV4_DEVCONF_PROXY_ARP = 3, - IPV4_DEVCONF_ACCEPT_REDIRECTS = 4, - IPV4_DEVCONF_SECURE_REDIRECTS = 5, - IPV4_DEVCONF_SEND_REDIRECTS = 6, - IPV4_DEVCONF_SHARED_MEDIA = 7, - IPV4_DEVCONF_RP_FILTER = 8, - IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE = 9, - IPV4_DEVCONF_BOOTP_RELAY = 10, - IPV4_DEVCONF_LOG_MARTIANS = 11, - IPV4_DEVCONF_TAG = 12, - IPV4_DEVCONF_ARPFILTER = 13, - IPV4_DEVCONF_MEDIUM_ID = 14, - IPV4_DEVCONF_NOXFRM = 15, - IPV4_DEVCONF_NOPOLICY = 16, - IPV4_DEVCONF_FORCE_IGMP_VERSION = 17, - IPV4_DEVCONF_ARP_ANNOUNCE = 18, - IPV4_DEVCONF_ARP_IGNORE = 19, - IPV4_DEVCONF_PROMOTE_SECONDARIES = 20, - IPV4_DEVCONF_ARP_ACCEPT = 21, - IPV4_DEVCONF_ARP_NOTIFY = 22, - IPV4_DEVCONF_ACCEPT_LOCAL = 23, - IPV4_DEVCONF_SRC_VMARK = 24, - IPV4_DEVCONF_PROXY_ARP_PVLAN = 25, - IPV4_DEVCONF_ROUTE_LOCALNET = 26, - IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL = 27, - IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL = 28, - IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN = 29, - IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST = 30, - IPV4_DEVCONF_DROP_GRATUITOUS_ARP = 31, - IPV4_DEVCONF_BC_FORWARDING = 32, - __IPV4_DEVCONF_MAX = 33, -}; - -struct dev_kfree_skb_cb { - enum skb_free_reason reason; -}; - -struct netdev_adjacent { - struct net_device *dev; - bool master; - bool ignore; - u16 ref_nr; - void *private; - struct list_head list; - struct callback_head rcu; -}; - -enum { - NDA_UNSPEC = 0, - NDA_DST = 1, - NDA_LLADDR = 2, - NDA_CACHEINFO = 3, - NDA_PROBES = 4, - NDA_VLAN = 5, - NDA_PORT = 6, - NDA_VNI = 7, - NDA_IFINDEX = 8, - NDA_MASTER = 9, - NDA_LINK_NETNSID = 10, - NDA_SRC_VNI = 11, - NDA_PROTOCOL = 12, - NDA_NH_ID = 13, - NDA_FDB_EXT_ATTRS = 14, - __NDA_MAX = 15, -}; - -struct nda_cacheinfo { - __u32 ndm_confirmed; - __u32 ndm_used; - __u32 ndm_updated; - __u32 ndm_refcnt; -}; - -struct ndt_stats { - __u64 ndts_allocs; - __u64 ndts_destroys; - __u64 ndts_hash_grows; - __u64 ndts_res_failed; - __u64 ndts_lookups; - __u64 ndts_hits; - __u64 ndts_rcv_probes_mcast; - __u64 ndts_rcv_probes_ucast; - __u64 ndts_periodic_gc_runs; - __u64 ndts_forced_gc_runs; - __u64 ndts_table_fulls; -}; - -enum { - NDTPA_UNSPEC = 0, - NDTPA_IFINDEX = 1, - NDTPA_REFCNT = 2, - NDTPA_REACHABLE_TIME = 3, - NDTPA_BASE_REACHABLE_TIME = 4, - NDTPA_RETRANS_TIME = 5, - NDTPA_GC_STALETIME = 6, - NDTPA_DELAY_PROBE_TIME = 7, - NDTPA_QUEUE_LEN = 8, - NDTPA_APP_PROBES = 9, - NDTPA_UCAST_PROBES = 10, - NDTPA_MCAST_PROBES = 11, - NDTPA_ANYCAST_DELAY = 12, - NDTPA_PROXY_DELAY = 13, - NDTPA_PROXY_QLEN = 14, - NDTPA_LOCKTIME = 15, - NDTPA_QUEUE_LENBYTES = 16, - NDTPA_MCAST_REPROBES = 17, - NDTPA_PAD = 18, - __NDTPA_MAX = 19, -}; - -struct ndtmsg { - __u8 ndtm_family; - __u8 ndtm_pad1; - __u16 ndtm_pad2; -}; - -struct ndt_config { - __u16 ndtc_key_len; - __u16 ndtc_entry_size; - __u32 ndtc_entries; - __u32 ndtc_last_flush; - __u32 ndtc_last_rand; - __u32 ndtc_hash_rnd; - __u32 ndtc_hash_mask; - __u32 ndtc_hash_chain_gc; - __u32 ndtc_proxy_qlen; -}; - -enum { - NDTA_UNSPEC = 0, - NDTA_NAME = 1, - NDTA_THRESH1 = 2, - NDTA_THRESH2 = 3, - NDTA_THRESH3 = 4, - NDTA_CONFIG = 5, - NDTA_PARMS = 6, - NDTA_STATS = 7, - NDTA_GC_INTERVAL = 8, - NDTA_PAD = 9, - __NDTA_MAX = 10, -}; - -enum { - RTN_UNSPEC = 0, - RTN_UNICAST = 1, - RTN_LOCAL = 2, - RTN_BROADCAST = 3, - RTN_ANYCAST = 4, - RTN_MULTICAST = 5, - RTN_BLACKHOLE = 6, - RTN_UNREACHABLE = 7, - RTN_PROHIBIT = 8, - RTN_THROW = 9, - RTN_NAT = 10, - RTN_XRESOLVE = 11, - __RTN_MAX = 12, -}; - -enum { - NEIGH_ARP_TABLE = 0, - NEIGH_ND_TABLE = 1, - NEIGH_DN_TABLE = 2, - NEIGH_NR_TABLES = 3, - NEIGH_LINK_TABLE = 3, -}; - -struct neigh_seq_state { - struct seq_net_private p; - struct neigh_table *tbl; - struct neigh_hash_table *nht; - void * (*neigh_sub_iter)(struct neigh_seq_state *, struct neighbour *, loff_t *); - unsigned int bucket; - unsigned int flags; -}; - -struct neighbour_cb { - long unsigned int sched_next; - unsigned int flags; -}; - -enum netevent_notif_type { - NETEVENT_NEIGH_UPDATE = 1, - NETEVENT_REDIRECT = 2, - NETEVENT_DELAY_PROBE_TIME_UPDATE = 3, - NETEVENT_IPV4_MPATH_HASH_UPDATE = 4, - NETEVENT_IPV6_MPATH_HASH_UPDATE = 5, - NETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE = 6, -}; - -struct neigh_dump_filter { - int master_idx; - int dev_idx; -}; - -struct neigh_sysctl_table { - struct ctl_table_header *sysctl_header; - struct ctl_table neigh_vars[21]; -}; - -struct netlink_dump_control { - int (*start)(struct netlink_callback *); - int (*dump)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - void *data; - struct module *module; - u32 min_dump_alloc; -}; - -struct rtnl_link_stats { - __u32 rx_packets; - __u32 tx_packets; - __u32 rx_bytes; - __u32 tx_bytes; - __u32 rx_errors; - __u32 tx_errors; - __u32 rx_dropped; - __u32 tx_dropped; - __u32 multicast; - __u32 collisions; - __u32 rx_length_errors; - __u32 rx_over_errors; - __u32 rx_crc_errors; - __u32 rx_frame_errors; - __u32 rx_fifo_errors; - __u32 rx_missed_errors; - __u32 tx_aborted_errors; - __u32 tx_carrier_errors; - __u32 tx_fifo_errors; - __u32 tx_heartbeat_errors; - __u32 tx_window_errors; - __u32 rx_compressed; - __u32 tx_compressed; - __u32 rx_nohandler; -}; - -struct rtnl_link_ifmap { - __u64 mem_start; - __u64 mem_end; - __u64 base_addr; - __u16 irq; - __u8 dma; - __u8 port; -}; - -enum { - IFLA_UNSPEC = 0, - IFLA_ADDRESS = 1, - IFLA_BROADCAST = 2, - IFLA_IFNAME = 3, - IFLA_MTU = 4, - IFLA_LINK = 5, - IFLA_QDISC = 6, - IFLA_STATS = 7, - IFLA_COST = 8, - IFLA_PRIORITY = 9, - IFLA_MASTER = 10, - IFLA_WIRELESS = 11, - IFLA_PROTINFO = 12, - IFLA_TXQLEN = 13, - IFLA_MAP = 14, - IFLA_WEIGHT = 15, - IFLA_OPERSTATE = 16, - IFLA_LINKMODE = 17, - IFLA_LINKINFO = 18, - IFLA_NET_NS_PID = 19, - IFLA_IFALIAS = 20, - IFLA_NUM_VF = 21, - IFLA_VFINFO_LIST = 22, - IFLA_STATS64 = 23, - IFLA_VF_PORTS = 24, - IFLA_PORT_SELF = 25, - IFLA_AF_SPEC = 26, - IFLA_GROUP = 27, - IFLA_NET_NS_FD = 28, - IFLA_EXT_MASK = 29, - IFLA_PROMISCUITY = 30, - IFLA_NUM_TX_QUEUES = 31, - IFLA_NUM_RX_QUEUES = 32, - IFLA_CARRIER = 33, - IFLA_PHYS_PORT_ID = 34, - IFLA_CARRIER_CHANGES = 35, - IFLA_PHYS_SWITCH_ID = 36, - IFLA_LINK_NETNSID = 37, - IFLA_PHYS_PORT_NAME = 38, - IFLA_PROTO_DOWN = 39, - IFLA_GSO_MAX_SEGS = 40, - IFLA_GSO_MAX_SIZE = 41, - IFLA_PAD = 42, - IFLA_XDP = 43, - IFLA_EVENT = 44, - IFLA_NEW_NETNSID = 45, - IFLA_IF_NETNSID = 46, - IFLA_TARGET_NETNSID = 46, - IFLA_CARRIER_UP_COUNT = 47, - IFLA_CARRIER_DOWN_COUNT = 48, - IFLA_NEW_IFINDEX = 49, - IFLA_MIN_MTU = 50, - IFLA_MAX_MTU = 51, - IFLA_PROP_LIST = 52, - IFLA_ALT_IFNAME = 53, - IFLA_PERM_ADDRESS = 54, - IFLA_PROTO_DOWN_REASON = 55, - __IFLA_MAX = 56, -}; - -enum { - IFLA_PROTO_DOWN_REASON_UNSPEC = 0, - IFLA_PROTO_DOWN_REASON_MASK = 1, - IFLA_PROTO_DOWN_REASON_VALUE = 2, - __IFLA_PROTO_DOWN_REASON_CNT = 3, - IFLA_PROTO_DOWN_REASON_MAX = 2, -}; - -enum { - IFLA_BRPORT_UNSPEC = 0, - IFLA_BRPORT_STATE = 1, - IFLA_BRPORT_PRIORITY = 2, - IFLA_BRPORT_COST = 3, - IFLA_BRPORT_MODE = 4, - IFLA_BRPORT_GUARD = 5, - IFLA_BRPORT_PROTECT = 6, - IFLA_BRPORT_FAST_LEAVE = 7, - IFLA_BRPORT_LEARNING = 8, - IFLA_BRPORT_UNICAST_FLOOD = 9, - IFLA_BRPORT_PROXYARP = 10, - IFLA_BRPORT_LEARNING_SYNC = 11, - IFLA_BRPORT_PROXYARP_WIFI = 12, - IFLA_BRPORT_ROOT_ID = 13, - IFLA_BRPORT_BRIDGE_ID = 14, - IFLA_BRPORT_DESIGNATED_PORT = 15, - IFLA_BRPORT_DESIGNATED_COST = 16, - IFLA_BRPORT_ID = 17, - IFLA_BRPORT_NO = 18, - IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19, - IFLA_BRPORT_CONFIG_PENDING = 20, - IFLA_BRPORT_MESSAGE_AGE_TIMER = 21, - IFLA_BRPORT_FORWARD_DELAY_TIMER = 22, - IFLA_BRPORT_HOLD_TIMER = 23, - IFLA_BRPORT_FLUSH = 24, - IFLA_BRPORT_MULTICAST_ROUTER = 25, - IFLA_BRPORT_PAD = 26, - IFLA_BRPORT_MCAST_FLOOD = 27, - IFLA_BRPORT_MCAST_TO_UCAST = 28, - IFLA_BRPORT_VLAN_TUNNEL = 29, - IFLA_BRPORT_BCAST_FLOOD = 30, - IFLA_BRPORT_GROUP_FWD_MASK = 31, - IFLA_BRPORT_NEIGH_SUPPRESS = 32, - IFLA_BRPORT_ISOLATED = 33, - IFLA_BRPORT_BACKUP_PORT = 34, - IFLA_BRPORT_MRP_RING_OPEN = 35, - IFLA_BRPORT_MRP_IN_OPEN = 36, - __IFLA_BRPORT_MAX = 37, -}; - -enum { - IFLA_INFO_UNSPEC = 0, - IFLA_INFO_KIND = 1, - IFLA_INFO_DATA = 2, - IFLA_INFO_XSTATS = 3, - IFLA_INFO_SLAVE_KIND = 4, - IFLA_INFO_SLAVE_DATA = 5, - __IFLA_INFO_MAX = 6, -}; - -enum { - IFLA_VF_INFO_UNSPEC = 0, - IFLA_VF_INFO = 1, - __IFLA_VF_INFO_MAX = 2, -}; - -enum { - IFLA_VF_UNSPEC = 0, - IFLA_VF_MAC = 1, - IFLA_VF_VLAN = 2, - IFLA_VF_TX_RATE = 3, - IFLA_VF_SPOOFCHK = 4, - IFLA_VF_LINK_STATE = 5, - IFLA_VF_RATE = 6, - IFLA_VF_RSS_QUERY_EN = 7, - IFLA_VF_STATS = 8, - IFLA_VF_TRUST = 9, - IFLA_VF_IB_NODE_GUID = 10, - IFLA_VF_IB_PORT_GUID = 11, - IFLA_VF_VLAN_LIST = 12, - IFLA_VF_BROADCAST = 13, - __IFLA_VF_MAX = 14, -}; - -struct ifla_vf_mac { - __u32 vf; - __u8 mac[32]; -}; - -struct ifla_vf_broadcast { - __u8 broadcast[32]; -}; - -struct ifla_vf_vlan { - __u32 vf; - __u32 vlan; - __u32 qos; -}; - -enum { - IFLA_VF_VLAN_INFO_UNSPEC = 0, - IFLA_VF_VLAN_INFO = 1, - __IFLA_VF_VLAN_INFO_MAX = 2, -}; - -struct ifla_vf_vlan_info { - __u32 vf; - __u32 vlan; - __u32 qos; - __be16 vlan_proto; -}; - -struct ifla_vf_tx_rate { - __u32 vf; - __u32 rate; -}; - -struct ifla_vf_rate { - __u32 vf; - __u32 min_tx_rate; - __u32 max_tx_rate; -}; - -struct ifla_vf_spoofchk { - __u32 vf; - __u32 setting; -}; - -struct ifla_vf_link_state { - __u32 vf; - __u32 link_state; -}; - -struct ifla_vf_rss_query_en { - __u32 vf; - __u32 setting; -}; - -enum { - IFLA_VF_STATS_RX_PACKETS = 0, - IFLA_VF_STATS_TX_PACKETS = 1, - IFLA_VF_STATS_RX_BYTES = 2, - IFLA_VF_STATS_TX_BYTES = 3, - IFLA_VF_STATS_BROADCAST = 4, - IFLA_VF_STATS_MULTICAST = 5, - IFLA_VF_STATS_PAD = 6, - IFLA_VF_STATS_RX_DROPPED = 7, - IFLA_VF_STATS_TX_DROPPED = 8, - __IFLA_VF_STATS_MAX = 9, -}; - -struct ifla_vf_trust { - __u32 vf; - __u32 setting; -}; - -enum { - IFLA_VF_PORT_UNSPEC = 0, - IFLA_VF_PORT = 1, - __IFLA_VF_PORT_MAX = 2, -}; - -enum { - IFLA_PORT_UNSPEC = 0, - IFLA_PORT_VF = 1, - IFLA_PORT_PROFILE = 2, - IFLA_PORT_VSI_TYPE = 3, - IFLA_PORT_INSTANCE_UUID = 4, - IFLA_PORT_HOST_UUID = 5, - IFLA_PORT_REQUEST = 6, - IFLA_PORT_RESPONSE = 7, - __IFLA_PORT_MAX = 8, -}; - -struct if_stats_msg { - __u8 family; - __u8 pad1; - __u16 pad2; - __u32 ifindex; - __u32 filter_mask; -}; - -enum { - IFLA_STATS_UNSPEC = 0, - IFLA_STATS_LINK_64 = 1, - IFLA_STATS_LINK_XSTATS = 2, - IFLA_STATS_LINK_XSTATS_SLAVE = 3, - IFLA_STATS_LINK_OFFLOAD_XSTATS = 4, - IFLA_STATS_AF_SPEC = 5, - __IFLA_STATS_MAX = 6, -}; - -enum { - IFLA_OFFLOAD_XSTATS_UNSPEC = 0, - IFLA_OFFLOAD_XSTATS_CPU_HIT = 1, - __IFLA_OFFLOAD_XSTATS_MAX = 2, -}; - -enum { - XDP_ATTACHED_NONE = 0, - XDP_ATTACHED_DRV = 1, - XDP_ATTACHED_SKB = 2, - XDP_ATTACHED_HW = 3, - XDP_ATTACHED_MULTI = 4, -}; - -enum { - IFLA_XDP_UNSPEC = 0, - IFLA_XDP_FD = 1, - IFLA_XDP_ATTACHED = 2, - IFLA_XDP_FLAGS = 3, - IFLA_XDP_PROG_ID = 4, - IFLA_XDP_DRV_PROG_ID = 5, - IFLA_XDP_SKB_PROG_ID = 6, - IFLA_XDP_HW_PROG_ID = 7, - IFLA_XDP_EXPECTED_FD = 8, - __IFLA_XDP_MAX = 9, -}; - -enum { - IFLA_EVENT_NONE = 0, - IFLA_EVENT_REBOOT = 1, - IFLA_EVENT_FEATURES = 2, - IFLA_EVENT_BONDING_FAILOVER = 3, - IFLA_EVENT_NOTIFY_PEERS = 4, - IFLA_EVENT_IGMP_RESEND = 5, - IFLA_EVENT_BONDING_OPTIONS = 6, -}; - -enum { - IFLA_BRIDGE_FLAGS = 0, - IFLA_BRIDGE_MODE = 1, - IFLA_BRIDGE_VLAN_INFO = 2, - IFLA_BRIDGE_VLAN_TUNNEL_INFO = 3, - IFLA_BRIDGE_MRP = 4, - __IFLA_BRIDGE_MAX = 5, -}; - -enum { - BR_MCAST_DIR_RX = 0, - BR_MCAST_DIR_TX = 1, - BR_MCAST_DIR_SIZE = 2, -}; - -enum rtattr_type_t { - RTA_UNSPEC = 0, - RTA_DST = 1, - RTA_SRC = 2, - RTA_IIF = 3, - RTA_OIF = 4, - RTA_GATEWAY = 5, - RTA_PRIORITY = 6, - RTA_PREFSRC = 7, - RTA_METRICS = 8, - RTA_MULTIPATH = 9, - RTA_PROTOINFO = 10, - RTA_FLOW = 11, - RTA_CACHEINFO = 12, - RTA_SESSION = 13, - RTA_MP_ALGO = 14, - RTA_TABLE = 15, - RTA_MARK = 16, - RTA_MFC_STATS = 17, - RTA_VIA = 18, - RTA_NEWDST = 19, - RTA_PREF = 20, - RTA_ENCAP_TYPE = 21, - RTA_ENCAP = 22, - RTA_EXPIRES = 23, - RTA_PAD = 24, - RTA_UID = 25, - RTA_TTL_PROPAGATE = 26, - RTA_IP_PROTO = 27, - RTA_SPORT = 28, - RTA_DPORT = 29, - RTA_NH_ID = 30, - __RTA_MAX = 31, -}; - -struct rta_cacheinfo { - __u32 rta_clntref; - __u32 rta_lastuse; - __s32 rta_expires; - __u32 rta_error; - __u32 rta_used; - __u32 rta_id; - __u32 rta_ts; - __u32 rta_tsage; -}; - -struct ifinfomsg { - unsigned char ifi_family; - unsigned char __ifi_pad; - short unsigned int ifi_type; - int ifi_index; - unsigned int ifi_flags; - unsigned int ifi_change; -}; - -typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, struct netlink_ext_ack *); - -typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *); - -struct rtnl_af_ops { - struct list_head list; - int family; - int (*fill_link_af)(struct sk_buff *, const struct net_device *, u32); - size_t (*get_link_af_size)(const struct net_device *, u32); - int (*validate_link_af)(const struct net_device *, const struct nlattr *); - int (*set_link_af)(struct net_device *, const struct nlattr *); - int (*fill_stats_af)(struct sk_buff *, const struct net_device *); - size_t (*get_stats_af_size)(const struct net_device *); -}; - -struct rtnl_link { - rtnl_doit_func doit; - rtnl_dumpit_func dumpit; - struct module *owner; - unsigned int flags; - struct callback_head rcu; -}; - -enum { - IF_LINK_MODE_DEFAULT = 0, - IF_LINK_MODE_DORMANT = 1, - IF_LINK_MODE_TESTING = 2, -}; - -enum lw_bits { - LW_URGENT = 0, -}; - -struct seg6_pernet_data { - struct mutex lock; - struct in6_addr *tun_src; -}; - -enum { - BPF_F_RECOMPUTE_CSUM = 1, - BPF_F_INVALIDATE_HASH = 2, -}; - -enum { - BPF_F_HDR_FIELD_MASK = 15, -}; - -enum { - BPF_F_PSEUDO_HDR = 16, - BPF_F_MARK_MANGLED_0 = 32, - BPF_F_MARK_ENFORCE = 64, -}; - -enum { - BPF_F_INGRESS = 1, -}; - -enum { - BPF_F_TUNINFO_IPV6 = 1, -}; - -enum { - BPF_F_ZERO_CSUM_TX = 2, - BPF_F_DONT_FRAGMENT = 4, - BPF_F_SEQ_NUMBER = 8, -}; - -enum { - BPF_CSUM_LEVEL_QUERY = 0, - BPF_CSUM_LEVEL_INC = 1, - BPF_CSUM_LEVEL_DEC = 2, - BPF_CSUM_LEVEL_RESET = 3, -}; - -enum { - BPF_F_ADJ_ROOM_FIXED_GSO = 1, - BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = 2, - BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = 4, - BPF_F_ADJ_ROOM_ENCAP_L4_GRE = 8, - BPF_F_ADJ_ROOM_ENCAP_L4_UDP = 16, - BPF_F_ADJ_ROOM_NO_CSUM_RESET = 32, -}; - -enum { - BPF_ADJ_ROOM_ENCAP_L2_MASK = 255, - BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 56, -}; - -enum { - BPF_SK_LOOKUP_F_REPLACE = 1, - BPF_SK_LOOKUP_F_NO_REUSEPORT = 2, -}; - -enum bpf_adj_room_mode { - BPF_ADJ_ROOM_NET = 0, - BPF_ADJ_ROOM_MAC = 1, -}; - -enum bpf_hdr_start_off { - BPF_HDR_START_MAC = 0, - BPF_HDR_START_NET = 1, -}; - -enum bpf_lwt_encap_mode { - BPF_LWT_ENCAP_SEG6 = 0, - BPF_LWT_ENCAP_SEG6_INLINE = 1, - BPF_LWT_ENCAP_IP = 2, -}; - -struct bpf_tunnel_key { - __u32 tunnel_id; - union { - __u32 remote_ipv4; - __u32 remote_ipv6[4]; - }; - __u8 tunnel_tos; - __u8 tunnel_ttl; - __u16 tunnel_ext; - __u32 tunnel_label; -}; - -struct bpf_xfrm_state { - __u32 reqid; - __u32 spi; - __u16 family; - __u16 ext; - union { - __u32 remote_ipv4; - __u32 remote_ipv6[4]; - }; -}; - -struct bpf_tcp_sock { - __u32 snd_cwnd; - __u32 srtt_us; - __u32 rtt_min; - __u32 snd_ssthresh; - __u32 rcv_nxt; - __u32 snd_nxt; - __u32 snd_una; - __u32 mss_cache; - __u32 ecn_flags; - __u32 rate_delivered; - __u32 rate_interval_us; - __u32 packets_out; - __u32 retrans_out; - __u32 total_retrans; - __u32 segs_in; - __u32 data_segs_in; - __u32 segs_out; - __u32 data_segs_out; - __u32 lost_out; - __u32 sacked_out; - __u64 bytes_received; - __u64 bytes_acked; - __u32 dsack_dups; - __u32 delivered; - __u32 delivered_ce; - __u32 icsk_retransmits; -}; - -struct bpf_sock_tuple { - union { - struct { - __be32 saddr; - __be32 daddr; - __be16 sport; - __be16 dport; - } ipv4; - struct { - __be32 saddr[4]; - __be32 daddr[4]; - __be16 sport; - __be16 dport; - } ipv6; - }; -}; - -struct bpf_xdp_sock { - __u32 queue_id; -}; - -enum { - BPF_SOCK_OPS_RTO_CB_FLAG = 1, - BPF_SOCK_OPS_RETRANS_CB_FLAG = 2, - BPF_SOCK_OPS_STATE_CB_FLAG = 4, - BPF_SOCK_OPS_RTT_CB_FLAG = 8, - BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = 16, - BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = 32, - BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = 64, - BPF_SOCK_OPS_ALL_CB_FLAGS = 127, -}; - -enum { - BPF_SOCK_OPS_VOID = 0, - BPF_SOCK_OPS_TIMEOUT_INIT = 1, - BPF_SOCK_OPS_RWND_INIT = 2, - BPF_SOCK_OPS_TCP_CONNECT_CB = 3, - BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB = 4, - BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB = 5, - BPF_SOCK_OPS_NEEDS_ECN = 6, - BPF_SOCK_OPS_BASE_RTT = 7, - BPF_SOCK_OPS_RTO_CB = 8, - BPF_SOCK_OPS_RETRANS_CB = 9, - BPF_SOCK_OPS_STATE_CB = 10, - BPF_SOCK_OPS_TCP_LISTEN_CB = 11, - BPF_SOCK_OPS_RTT_CB = 12, - BPF_SOCK_OPS_PARSE_HDR_OPT_CB = 13, - BPF_SOCK_OPS_HDR_OPT_LEN_CB = 14, - BPF_SOCK_OPS_WRITE_HDR_OPT_CB = 15, -}; - -enum { - TCP_BPF_IW = 1001, - TCP_BPF_SNDCWND_CLAMP = 1002, - TCP_BPF_DELACK_MAX = 1003, - TCP_BPF_RTO_MIN = 1004, - TCP_BPF_SYN = 1005, - TCP_BPF_SYN_IP = 1006, - TCP_BPF_SYN_MAC = 1007, -}; - -enum { - BPF_LOAD_HDR_OPT_TCP_SYN = 1, -}; - -enum { - BPF_FIB_LOOKUP_DIRECT = 1, - BPF_FIB_LOOKUP_OUTPUT = 2, -}; - -enum { - BPF_FIB_LKUP_RET_SUCCESS = 0, - BPF_FIB_LKUP_RET_BLACKHOLE = 1, - BPF_FIB_LKUP_RET_UNREACHABLE = 2, - BPF_FIB_LKUP_RET_PROHIBIT = 3, - BPF_FIB_LKUP_RET_NOT_FWDED = 4, - BPF_FIB_LKUP_RET_FWD_DISABLED = 5, - BPF_FIB_LKUP_RET_UNSUPP_LWT = 6, - BPF_FIB_LKUP_RET_NO_NEIGH = 7, - BPF_FIB_LKUP_RET_FRAG_NEEDED = 8, -}; - -struct bpf_fib_lookup { - __u8 family; - __u8 l4_protocol; - __be16 sport; - __be16 dport; - __u16 tot_len; - __u32 ifindex; - union { - __u8 tos; - __be32 flowinfo; - __u32 rt_metric; - }; - union { - __be32 ipv4_src; - __u32 ipv6_src[4]; - }; - union { - __be32 ipv4_dst; - __u32 ipv6_dst[4]; - }; - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - __u8 smac[6]; - __u8 dmac[6]; -}; - -struct bpf_redir_neigh { - __u32 nh_family; - union { - __be32 ipv4_nh; - __u32 ipv6_nh[4]; - }; -}; - -enum rt_scope_t { - RT_SCOPE_UNIVERSE = 0, - RT_SCOPE_SITE = 200, - RT_SCOPE_LINK = 253, - RT_SCOPE_HOST = 254, - RT_SCOPE_NOWHERE = 255, -}; - -enum rt_class_t { - RT_TABLE_UNSPEC = 0, - RT_TABLE_COMPAT = 252, - RT_TABLE_DEFAULT = 253, - RT_TABLE_MAIN = 254, - RT_TABLE_LOCAL = 255, - RT_TABLE_MAX = 4294967295, -}; - -struct nl_info { - struct nlmsghdr *nlh; - struct net *nl_net; - u32 portid; - u8 skip_notify: 1; - u8 skip_notify_kernel: 1; -}; - -typedef int (*bpf_aux_classic_check_t)(struct sock_filter *, unsigned int); - -struct inet_timewait_sock { - struct sock_common __tw_common; - __u32 tw_mark; - volatile unsigned char tw_substate; - unsigned char tw_rcv_wscale; - __be16 tw_sport; - unsigned int tw_kill: 1; - unsigned int tw_transparent: 1; - unsigned int tw_flowlabel: 20; - unsigned int tw_pad: 2; - unsigned int tw_tos: 8; - u32 tw_txhash; - u32 tw_priority; - struct timer_list tw_timer; - struct inet_bind_bucket *tw_tb; -}; - -struct tcp_timewait_sock { - struct inet_timewait_sock tw_sk; - u32 tw_rcv_wnd; - u32 tw_ts_offset; - u32 tw_ts_recent; - u32 tw_last_oow_ack_time; - int tw_ts_recent_stamp; - u32 tw_tx_delay; -}; - -struct udp_sock { - struct inet_sock inet; - int pending; - unsigned int corkflag; - __u8 encap_type; - unsigned char no_check6_tx: 1; - unsigned char no_check6_rx: 1; - unsigned char encap_enabled: 1; - unsigned char gro_enabled: 1; - unsigned char accept_udp_l4: 1; - unsigned char accept_udp_fraglist: 1; - __u16 len; - __u16 gso_size; - __u16 pcslen; - __u16 pcrlen; - __u8 pcflag; - __u8 unused[3]; - int (*encap_rcv)(struct sock *, struct sk_buff *); - int (*encap_err_lookup)(struct sock *, struct sk_buff *); - void (*encap_destroy)(struct sock *); - struct sk_buff * (*gro_receive)(struct sock *, struct list_head *, struct sk_buff *); - int (*gro_complete)(struct sock *, struct sk_buff *, int); - struct sk_buff_head reader_queue; - int forward_deficit; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct udp6_sock { - struct udp_sock udp; - struct ipv6_pinfo inet6; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct tcp6_sock { - struct tcp_sock tcp; - struct ipv6_pinfo inet6; -}; - -struct fib6_result; - -struct fib6_config; - -struct ipv6_stub { - int (*ipv6_sock_mc_join)(struct sock *, int, const struct in6_addr *); - int (*ipv6_sock_mc_drop)(struct sock *, int, const struct in6_addr *); - struct dst_entry * (*ipv6_dst_lookup_flow)(struct net *, const struct sock *, struct flowi6 *, const struct in6_addr *); - int (*ipv6_route_input)(struct sk_buff *); - struct fib6_table * (*fib6_get_table)(struct net *, u32); - int (*fib6_lookup)(struct net *, int, struct flowi6 *, struct fib6_result *, int); - int (*fib6_table_lookup)(struct net *, struct fib6_table *, int, struct flowi6 *, struct fib6_result *, int); - void (*fib6_select_path)(const struct net *, struct fib6_result *, struct flowi6 *, int, bool, const struct sk_buff *, int); - u32 (*ip6_mtu_from_fib6)(const struct fib6_result *, const struct in6_addr *, const struct in6_addr *); - int (*fib6_nh_init)(struct net *, struct fib6_nh *, struct fib6_config *, gfp_t, struct netlink_ext_ack *); - void (*fib6_nh_release)(struct fib6_nh *); - void (*fib6_nh_release_dsts)(struct fib6_nh *); - void (*fib6_update_sernum)(struct net *, struct fib6_info *); - int (*ip6_del_rt)(struct net *, struct fib6_info *, bool); - void (*fib6_rt_update)(struct net *, struct fib6_info *, struct nl_info *); - void (*udpv6_encap_enable)(); - void (*ndisc_send_na)(struct net_device *, const struct in6_addr *, const struct in6_addr *, bool, bool, bool, bool); - void (*xfrm6_local_rxpmtu)(struct sk_buff *, u32); - int (*xfrm6_udp_encap_rcv)(struct sock *, struct sk_buff *); - int (*xfrm6_rcv_encap)(struct sk_buff *, int, __be32, int); - struct neigh_table *nd_tbl; - int (*ipv6_fragment)(struct net *, struct sock *, struct sk_buff *, int (*)(struct net *, struct sock *, struct sk_buff *)); -}; - -struct fib6_result { - struct fib6_nh *nh; - struct fib6_info *f6i; - u32 fib6_flags; - u8 fib6_type; - struct rt6_info *rt6; -}; - -struct fib6_config { - u32 fc_table; - u32 fc_metric; - int fc_dst_len; - int fc_src_len; - int fc_ifindex; - u32 fc_flags; - u32 fc_protocol; - u16 fc_type; - u16 fc_delete_all_nh: 1; - u16 fc_ignore_dev_down: 1; - u16 __unused: 14; - u32 fc_nh_id; - struct in6_addr fc_dst; - struct in6_addr fc_src; - struct in6_addr fc_prefsrc; - struct in6_addr fc_gateway; - long unsigned int fc_expires; - struct nlattr *fc_mx; - int fc_mx_len; - int fc_mp_len; - struct nlattr *fc_mp; - struct nl_info fc_nlinfo; - struct nlattr *fc_encap; - u16 fc_encap_type; - bool fc_is_fdb; -}; - -struct ipv6_bpf_stub { - int (*inet6_bind)(struct sock *, struct sockaddr *, int, u32); - struct sock * (*udp6_lib_lookup)(struct net *, const struct in6_addr *, __be16, const struct in6_addr *, __be16, int, int, struct udp_table *, struct sk_buff *); -}; - -struct fib_result { - __be32 prefix; - unsigned char prefixlen; - unsigned char nh_sel; - unsigned char type; - unsigned char scope; - u32 tclassid; - struct fib_nh_common *nhc; - struct fib_info *fi; - struct fib_table *table; - struct hlist_head *fa_head; -}; - -enum { - INET_ECN_NOT_ECT = 0, - INET_ECN_ECT_1 = 1, - INET_ECN_ECT_0 = 2, - INET_ECN_CE = 3, - INET_ECN_MASK = 3, -}; - -struct tcp_skb_cb { - __u32 seq; - __u32 end_seq; - union { - __u32 tcp_tw_isn; - struct { - u16 tcp_gso_segs; - u16 tcp_gso_size; - }; - }; - __u8 tcp_flags; - __u8 sacked; - __u8 ip_dsfield; - __u8 txstamp_ack: 1; - __u8 eor: 1; - __u8 has_rxtstamp: 1; - __u8 unused: 5; - __u32 ack_seq; - union { - struct { - __u32 in_flight: 30; - __u32 is_app_limited: 1; - __u32 unused: 1; - __u32 delivered; - u64 first_tx_mstamp; - u64 delivered_mstamp; - } tx; - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - struct { - __u32 flags; - struct sock *sk_redir; - void *data_end; - } bpf; - }; -}; - -struct strp_stats { - long long unsigned int msgs; - long long unsigned int bytes; - unsigned int mem_fail; - unsigned int need_more_hdr; - unsigned int msg_too_big; - unsigned int msg_timeouts; - unsigned int bad_hdr_len; -}; - -struct strparser; - -struct strp_callbacks { - int (*parse_msg)(struct strparser *, struct sk_buff *); - void (*rcv_msg)(struct strparser *, struct sk_buff *); - int (*read_sock_done)(struct strparser *, int); - void (*abort_parser)(struct strparser *, int); - void (*lock)(struct strparser *); - void (*unlock)(struct strparser *); -}; - -struct strparser { - struct sock *sk; - u32 stopped: 1; - u32 paused: 1; - u32 aborted: 1; - u32 interrupted: 1; - u32 unrecov_intr: 1; - struct sk_buff **skb_nextp; - struct sk_buff *skb_head; - unsigned int need_bytes; - struct delayed_work msg_timer_work; - struct work_struct work; - struct strp_stats stats; - struct strp_callbacks cb; -}; - -struct strp_msg { - int full_len; - int offset; -}; - -struct _strp_msg { - struct strp_msg strp; - int accum_len; -}; - -struct sk_skb_cb { - unsigned char data[20]; - struct _strp_msg strp; -}; - -struct xdp_umem { - void *addrs; - u64 size; - u32 headroom; - u32 chunk_size; - u32 chunks; - u32 npgs; - struct user_struct *user; - refcount_t users; - u8 flags; - bool zc; - struct page **pgs; - int id; - struct list_head xsk_dma_list; - struct work_struct work; -}; - -struct xsk_queue; - -struct xdp_sock { - struct sock sk; - long: 64; - long: 64; - struct xsk_queue *rx; - struct net_device *dev; - struct xdp_umem *umem; - struct list_head flush_node; - struct xsk_buff_pool *pool; - u16 queue_id; - bool zc; - enum { - XSK_READY = 0, - XSK_BOUND = 1, - XSK_UNBOUND = 2, - } state; - long: 64; - struct xsk_queue *tx; - struct list_head tx_list; - spinlock_t rx_lock; - u64 rx_dropped; - u64 rx_queue_full; - struct list_head map_list; - spinlock_t map_list_lock; - struct mutex mutex; - struct xsk_queue *fq_tmp; - struct xsk_queue *cq_tmp; - long: 64; -}; - -struct tls_crypto_info { - __u16 version; - __u16 cipher_type; -}; - -struct tls12_crypto_info_aes_gcm_128 { - struct tls_crypto_info info; - unsigned char iv[8]; - unsigned char key[16]; - unsigned char salt[4]; - unsigned char rec_seq[8]; -}; - -struct tls12_crypto_info_aes_gcm_256 { - struct tls_crypto_info info; - unsigned char iv[8]; - unsigned char key[32]; - unsigned char salt[4]; - unsigned char rec_seq[8]; -}; - -struct tls_sw_context_rx { - struct crypto_aead *aead_recv; - struct crypto_wait async_wait; - struct strparser strp; - struct sk_buff_head rx_list; - void (*saved_data_ready)(struct sock *); - struct sk_buff *recv_pkt; - u8 control; - u8 async_capable: 1; - u8 decrypted: 1; - atomic_t decrypt_pending; - spinlock_t decrypt_compl_lock; - bool async_notify; -}; - -struct cipher_context { - char *iv; - char *rec_seq; -}; - -union tls_crypto_context { - struct tls_crypto_info info; - union { - struct tls12_crypto_info_aes_gcm_128 aes_gcm_128; - struct tls12_crypto_info_aes_gcm_256 aes_gcm_256; - }; -}; - -struct tls_prot_info { - u16 version; - u16 cipher_type; - u16 prepend_size; - u16 tag_size; - u16 overhead_size; - u16 iv_size; - u16 salt_size; - u16 rec_seq_size; - u16 aad_size; - u16 tail_size; -}; - -struct tls_context { - struct tls_prot_info prot_info; - u8 tx_conf: 3; - u8 rx_conf: 3; - int (*push_pending_record)(struct sock *, int); - void (*sk_write_space)(struct sock *); - void *priv_ctx_tx; - void *priv_ctx_rx; - struct net_device *netdev; - struct cipher_context tx; - struct cipher_context rx; - struct scatterlist *partially_sent_record; - u16 partially_sent_offset; - bool in_tcp_sendpages; - bool pending_open_record_frags; - struct mutex tx_lock; - long unsigned int flags; - struct proto *sk_proto; - struct sock *sk; - void (*sk_destruct)(struct sock *); - union tls_crypto_context crypto_send; - union tls_crypto_context crypto_recv; - struct list_head list; - refcount_t refcount; - struct callback_head rcu; -}; - -typedef u64 (*btf_bpf_skb_get_pay_offset)(struct sk_buff *); - -typedef u64 (*btf_bpf_skb_get_nlattr)(struct sk_buff *, u32, u32); - -typedef u64 (*btf_bpf_skb_get_nlattr_nest)(struct sk_buff *, u32, u32); - -typedef u64 (*btf_bpf_skb_load_helper_8)(const struct sk_buff *, const void *, int, int); - -typedef u64 (*btf_bpf_skb_load_helper_8_no_cache)(const struct sk_buff *, int); - -typedef u64 (*btf_bpf_skb_load_helper_16)(const struct sk_buff *, const void *, int, int); - -typedef u64 (*btf_bpf_skb_load_helper_16_no_cache)(const struct sk_buff *, int); - -typedef u64 (*btf_bpf_skb_load_helper_32)(const struct sk_buff *, const void *, int, int); - -typedef u64 (*btf_bpf_skb_load_helper_32_no_cache)(const struct sk_buff *, int); - -struct bpf_scratchpad { - union { - __be32 diff[128]; - u8 buff[512]; - }; -}; - -typedef u64 (*btf_bpf_skb_store_bytes)(struct sk_buff *, u32, const void *, u32, u64); - -typedef u64 (*btf_bpf_skb_load_bytes)(const struct sk_buff *, u32, void *, u32); - -typedef u64 (*btf_bpf_flow_dissector_load_bytes)(const struct bpf_flow_dissector *, u32, void *, u32); - -typedef u64 (*btf_bpf_skb_load_bytes_relative)(const struct sk_buff *, u32, void *, u32, u32); - -typedef u64 (*btf_bpf_skb_pull_data)(struct sk_buff *, u32); - -typedef u64 (*btf_bpf_sk_fullsock)(struct sock *); - -typedef u64 (*btf_sk_skb_pull_data)(struct sk_buff *, u32); - -typedef u64 (*btf_bpf_l3_csum_replace)(struct sk_buff *, u32, u64, u64, u64); - -typedef u64 (*btf_bpf_l4_csum_replace)(struct sk_buff *, u32, u64, u64, u64); - -typedef u64 (*btf_bpf_csum_diff)(__be32 *, u32, __be32 *, u32, __wsum); - -typedef u64 (*btf_bpf_csum_update)(struct sk_buff *, __wsum); - -typedef u64 (*btf_bpf_csum_level)(struct sk_buff *, u64); - -enum { - BPF_F_NEIGH = 2, - BPF_F_PEER = 4, - BPF_F_NEXTHOP = 8, -}; - -typedef u64 (*btf_bpf_clone_redirect)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_bpf_redirect)(u32, u64); - -typedef u64 (*btf_bpf_redirect_peer)(u32, u64); - -typedef u64 (*btf_bpf_redirect_neigh)(u32, struct bpf_redir_neigh *, int, u64); - -typedef u64 (*btf_bpf_msg_apply_bytes)(struct sk_msg *, u32); - -typedef u64 (*btf_bpf_msg_cork_bytes)(struct sk_msg *, u32); - -typedef u64 (*btf_bpf_msg_pull_data)(struct sk_msg *, u32, u32, u64); - -typedef u64 (*btf_bpf_msg_push_data)(struct sk_msg *, u32, u32, u64); - -typedef u64 (*btf_bpf_msg_pop_data)(struct sk_msg *, u32, u32, u64); - -typedef u64 (*btf_bpf_get_cgroup_classid_curr)(); - -typedef u64 (*btf_bpf_skb_cgroup_classid)(const struct sk_buff *); - -typedef u64 (*btf_bpf_get_cgroup_classid)(const struct sk_buff *); - -typedef u64 (*btf_bpf_get_route_realm)(const struct sk_buff *); - -typedef u64 (*btf_bpf_get_hash_recalc)(struct sk_buff *); - -typedef u64 (*btf_bpf_set_hash_invalid)(struct sk_buff *); - -typedef u64 (*btf_bpf_set_hash)(struct sk_buff *, u32); - -typedef u64 (*btf_bpf_skb_vlan_push)(struct sk_buff *, __be16, u16); - -typedef u64 (*btf_bpf_skb_vlan_pop)(struct sk_buff *); - -typedef u64 (*btf_bpf_skb_change_proto)(struct sk_buff *, __be16, u64); - -typedef u64 (*btf_bpf_skb_change_type)(struct sk_buff *, u32); - -typedef u64 (*btf_sk_skb_adjust_room)(struct sk_buff *, s32, u32, u64); - -typedef u64 (*btf_bpf_skb_adjust_room)(struct sk_buff *, s32, u32, u64); - -typedef u64 (*btf_bpf_skb_change_tail)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_sk_skb_change_tail)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_bpf_skb_change_head)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_sk_skb_change_head)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_bpf_xdp_adjust_head)(struct xdp_buff *, int); - -typedef u64 (*btf_bpf_xdp_adjust_tail)(struct xdp_buff *, int); - -typedef u64 (*btf_bpf_xdp_adjust_meta)(struct xdp_buff *, int); - -typedef u64 (*btf_bpf_xdp_redirect)(u32, u64); - -typedef u64 (*btf_bpf_xdp_redirect_map)(struct bpf_map *, u32, u64); - -typedef u64 (*btf_bpf_skb_event_output)(struct sk_buff *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_skb_get_tunnel_key)(struct sk_buff *, struct bpf_tunnel_key *, u32, u64); - -typedef u64 (*btf_bpf_skb_get_tunnel_opt)(struct sk_buff *, u8 *, u32); - -typedef u64 (*btf_bpf_skb_set_tunnel_key)(struct sk_buff *, const struct bpf_tunnel_key *, u32, u64); - -typedef u64 (*btf_bpf_skb_set_tunnel_opt)(struct sk_buff *, const u8 *, u32); - -typedef u64 (*btf_bpf_skb_under_cgroup)(struct sk_buff *, struct bpf_map *, u32); - -typedef u64 (*btf_bpf_skb_cgroup_id)(const struct sk_buff *); - -typedef u64 (*btf_bpf_skb_ancestor_cgroup_id)(const struct sk_buff *, int); - -typedef u64 (*btf_bpf_sk_cgroup_id)(struct sock *); - -typedef u64 (*btf_bpf_sk_ancestor_cgroup_id)(struct sock *, int); - -typedef u64 (*btf_bpf_xdp_event_output)(struct xdp_buff *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_get_socket_cookie)(struct sk_buff *); - -typedef u64 (*btf_bpf_get_socket_cookie_sock_addr)(struct bpf_sock_addr_kern *); - -typedef u64 (*btf_bpf_get_socket_cookie_sock)(struct sock *); - -typedef u64 (*btf_bpf_get_socket_cookie_sock_ops)(struct bpf_sock_ops_kern *); - -typedef u64 (*btf_bpf_get_netns_cookie_sock)(struct sock *); - -typedef u64 (*btf_bpf_get_netns_cookie_sock_addr)(struct bpf_sock_addr_kern *); - -typedef u64 (*btf_bpf_get_socket_uid)(struct sk_buff *); - -typedef u64 (*btf_bpf_sock_addr_setsockopt)(struct bpf_sock_addr_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_addr_getsockopt)(struct bpf_sock_addr_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_ops_setsockopt)(struct bpf_sock_ops_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_ops_getsockopt)(struct bpf_sock_ops_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_ops_cb_flags_set)(struct bpf_sock_ops_kern *, int); - -typedef u64 (*btf_bpf_bind)(struct bpf_sock_addr_kern *, struct sockaddr *, int); - -typedef u64 (*btf_bpf_skb_get_xfrm_state)(struct sk_buff *, u32, struct bpf_xfrm_state *, u32, u64); - -typedef u64 (*btf_bpf_xdp_fib_lookup)(struct xdp_buff *, struct bpf_fib_lookup *, int, u32); - -typedef u64 (*btf_bpf_skb_fib_lookup)(struct sk_buff *, struct bpf_fib_lookup *, int, u32); - -typedef u64 (*btf_bpf_lwt_in_push_encap)(struct sk_buff *, u32, void *, u32); - -typedef u64 (*btf_bpf_lwt_xmit_push_encap)(struct sk_buff *, u32, void *, u32); - -typedef u64 (*btf_bpf_skc_lookup_tcp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sk_lookup_tcp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sk_lookup_udp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sk_release)(struct sock *); - -typedef u64 (*btf_bpf_xdp_sk_lookup_udp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64); - -typedef u64 (*btf_bpf_xdp_skc_lookup_tcp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64); - -typedef u64 (*btf_bpf_xdp_sk_lookup_tcp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64); - -typedef u64 (*btf_bpf_sock_addr_skc_lookup_tcp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sock_addr_sk_lookup_tcp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sock_addr_sk_lookup_udp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_tcp_sock)(struct sock *); - -typedef u64 (*btf_bpf_get_listener_sock)(struct sock *); - -typedef u64 (*btf_bpf_skb_ecn_set_ce)(struct sk_buff *); - -typedef u64 (*btf_bpf_tcp_check_syncookie)(struct sock *, void *, u32, struct tcphdr *, u32); - -typedef u64 (*btf_bpf_tcp_gen_syncookie)(struct sock *, void *, u32, struct tcphdr *, u32); - -typedef u64 (*btf_bpf_sk_assign)(struct sk_buff *, struct sock *, u64); - -typedef u64 (*btf_bpf_sock_ops_load_hdr_opt)(struct bpf_sock_ops_kern *, void *, u32, u64); - -typedef u64 (*btf_bpf_sock_ops_store_hdr_opt)(struct bpf_sock_ops_kern *, const void *, u32, u64); - -typedef u64 (*btf_bpf_sock_ops_reserve_hdr_opt)(struct bpf_sock_ops_kern *, u32, u64); - -typedef u64 (*btf_sk_select_reuseport)(struct sk_reuseport_kern *, struct bpf_map *, void *, u32); - -typedef u64 (*btf_sk_reuseport_load_bytes)(const struct sk_reuseport_kern *, u32, void *, u32); - -typedef u64 (*btf_sk_reuseport_load_bytes_relative)(const struct sk_reuseport_kern *, u32, void *, u32, u32); - -typedef u64 (*btf_bpf_sk_lookup_assign)(struct bpf_sk_lookup_kern *, struct sock *, u64); - -typedef u64 (*btf_bpf_skc_to_tcp6_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_tcp_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_tcp_timewait_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_tcp_request_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_udp6_sock)(struct sock *); - -struct bpf_dtab_netdev___2; - -enum { - INET_DIAG_REQ_NONE = 0, - INET_DIAG_REQ_BYTECODE = 1, - INET_DIAG_REQ_SK_BPF_STORAGES = 2, - INET_DIAG_REQ_PROTOCOL = 3, - __INET_DIAG_REQ_MAX = 4, -}; - -struct sock_diag_req { - __u8 sdiag_family; - __u8 sdiag_protocol; -}; - -struct sock_diag_handler { - __u8 family; - int (*dump)(struct sk_buff *, struct nlmsghdr *); - int (*get_info)(struct sk_buff *, struct sock *); - int (*destroy)(struct sk_buff *, struct nlmsghdr *); -}; - -struct broadcast_sk { - struct sock *sk; - struct work_struct work; -}; - -typedef int gifconf_func_t(struct net_device *, char *, int, int); - -struct hwtstamp_config { - int flags; - int tx_type; - int rx_filter; -}; - -enum hwtstamp_tx_types { - HWTSTAMP_TX_OFF = 0, - HWTSTAMP_TX_ON = 1, - HWTSTAMP_TX_ONESTEP_SYNC = 2, - HWTSTAMP_TX_ONESTEP_P2P = 3, - __HWTSTAMP_TX_CNT = 4, -}; - -enum hwtstamp_rx_filters { - HWTSTAMP_FILTER_NONE = 0, - HWTSTAMP_FILTER_ALL = 1, - HWTSTAMP_FILTER_SOME = 2, - HWTSTAMP_FILTER_PTP_V1_L4_EVENT = 3, - HWTSTAMP_FILTER_PTP_V1_L4_SYNC = 4, - HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ = 5, - HWTSTAMP_FILTER_PTP_V2_L4_EVENT = 6, - HWTSTAMP_FILTER_PTP_V2_L4_SYNC = 7, - HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ = 8, - HWTSTAMP_FILTER_PTP_V2_L2_EVENT = 9, - HWTSTAMP_FILTER_PTP_V2_L2_SYNC = 10, - HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ = 11, - HWTSTAMP_FILTER_PTP_V2_EVENT = 12, - HWTSTAMP_FILTER_PTP_V2_SYNC = 13, - HWTSTAMP_FILTER_PTP_V2_DELAY_REQ = 14, - HWTSTAMP_FILTER_NTP_ALL = 15, - __HWTSTAMP_FILTER_CNT = 16, -}; - -struct tso_t { - int next_frag_idx; - int size; - void *data; - u16 ip_id; - u8 tlen; - bool ipv6; - u32 tcp_seq; -}; - -struct fib_notifier_info { - int family; - struct netlink_ext_ack *extack; -}; - -enum fib_event_type { - FIB_EVENT_ENTRY_REPLACE = 0, - FIB_EVENT_ENTRY_APPEND = 1, - FIB_EVENT_ENTRY_ADD = 2, - FIB_EVENT_ENTRY_DEL = 3, - FIB_EVENT_RULE_ADD = 4, - FIB_EVENT_RULE_DEL = 5, - FIB_EVENT_NH_ADD = 6, - FIB_EVENT_NH_DEL = 7, - FIB_EVENT_VIF_ADD = 8, - FIB_EVENT_VIF_DEL = 9, -}; - -struct fib_notifier_net { - struct list_head fib_notifier_ops; - struct atomic_notifier_head fib_chain; -}; - -struct xdp_attachment_info { - struct bpf_prog *prog; - u32 flags; -}; - -struct xdp_buff_xsk; - -struct xsk_buff_pool { - struct device *dev; - struct net_device *netdev; - struct list_head xsk_tx_list; - spinlock_t xsk_tx_list_lock; - refcount_t users; - struct xdp_umem *umem; - struct work_struct work; - struct list_head free_list; - u32 heads_cnt; - u16 queue_id; - long: 16; - long: 64; - long: 64; - long: 64; - struct xsk_queue *fq; - struct xsk_queue *cq; - dma_addr_t *dma_pages; - struct xdp_buff_xsk *heads; - u64 chunk_mask; - u64 addrs_cnt; - u32 free_list_cnt; - u32 dma_pages_cnt; - u32 free_heads_cnt; - u32 headroom; - u32 chunk_size; - u32 frame_len; - u8 cached_need_wakeup; - bool uses_need_wakeup; - bool dma_need_sync; - bool unaligned; - void *addrs; - spinlock_t cq_lock; - struct xdp_buff_xsk *free_heads[0]; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct pp_alloc_cache { - u32 count; - void *cache[128]; -}; - -struct page_pool_params { - unsigned int flags; - unsigned int order; - unsigned int pool_size; - int nid; - struct device *dev; - enum dma_data_direction dma_dir; - unsigned int max_len; - unsigned int offset; -}; - -struct page_pool { - struct page_pool_params p; - struct delayed_work release_dw; - void (*disconnect)(void *); - long unsigned int defer_start; - long unsigned int defer_warn; - u32 pages_state_hold_cnt; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - struct pp_alloc_cache alloc; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct ptr_ring ring; - atomic_t pages_state_release_cnt; - refcount_t user_cnt; - u64 destroy_cnt; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct xdp_buff_xsk { - struct xdp_buff xdp; - dma_addr_t dma; - dma_addr_t frame_dma; - struct xsk_buff_pool *pool; - bool unaligned; - u64 orig_addr; - struct list_head free_list_node; -}; - -struct flow_match { - struct flow_dissector *dissector; - void *mask; - void *key; -}; - -struct flow_match_meta { - struct flow_dissector_key_meta *key; - struct flow_dissector_key_meta *mask; -}; - -struct flow_match_basic { - struct flow_dissector_key_basic *key; - struct flow_dissector_key_basic *mask; -}; - -struct flow_match_control { - struct flow_dissector_key_control *key; - struct flow_dissector_key_control *mask; -}; - -struct flow_match_eth_addrs { - struct flow_dissector_key_eth_addrs *key; - struct flow_dissector_key_eth_addrs *mask; -}; - -struct flow_match_vlan { - struct flow_dissector_key_vlan *key; - struct flow_dissector_key_vlan *mask; -}; - -struct flow_match_ipv4_addrs { - struct flow_dissector_key_ipv4_addrs *key; - struct flow_dissector_key_ipv4_addrs *mask; -}; - -struct flow_match_ipv6_addrs { - struct flow_dissector_key_ipv6_addrs *key; - struct flow_dissector_key_ipv6_addrs *mask; -}; - -struct flow_match_ip { - struct flow_dissector_key_ip *key; - struct flow_dissector_key_ip *mask; -}; - -struct flow_match_ports { - struct flow_dissector_key_ports *key; - struct flow_dissector_key_ports *mask; -}; - -struct flow_match_icmp { - struct flow_dissector_key_icmp *key; - struct flow_dissector_key_icmp *mask; -}; - -struct flow_match_tcp { - struct flow_dissector_key_tcp *key; - struct flow_dissector_key_tcp *mask; -}; - -struct flow_match_mpls { - struct flow_dissector_key_mpls *key; - struct flow_dissector_key_mpls *mask; -}; - -struct flow_match_enc_keyid { - struct flow_dissector_key_keyid *key; - struct flow_dissector_key_keyid *mask; -}; - -struct flow_match_enc_opts { - struct flow_dissector_key_enc_opts *key; - struct flow_dissector_key_enc_opts *mask; -}; - -struct flow_match_ct { - struct flow_dissector_key_ct *key; - struct flow_dissector_key_ct *mask; -}; - -enum flow_action_id { - FLOW_ACTION_ACCEPT = 0, - FLOW_ACTION_DROP = 1, - FLOW_ACTION_TRAP = 2, - FLOW_ACTION_GOTO = 3, - FLOW_ACTION_REDIRECT = 4, - FLOW_ACTION_MIRRED = 5, - FLOW_ACTION_REDIRECT_INGRESS = 6, - FLOW_ACTION_MIRRED_INGRESS = 7, - FLOW_ACTION_VLAN_PUSH = 8, - FLOW_ACTION_VLAN_POP = 9, - FLOW_ACTION_VLAN_MANGLE = 10, - FLOW_ACTION_TUNNEL_ENCAP = 11, - FLOW_ACTION_TUNNEL_DECAP = 12, - FLOW_ACTION_MANGLE = 13, - FLOW_ACTION_ADD = 14, - FLOW_ACTION_CSUM = 15, - FLOW_ACTION_MARK = 16, - FLOW_ACTION_PTYPE = 17, - FLOW_ACTION_PRIORITY = 18, - FLOW_ACTION_WAKE = 19, - FLOW_ACTION_QUEUE = 20, - FLOW_ACTION_SAMPLE = 21, - FLOW_ACTION_POLICE = 22, - FLOW_ACTION_CT = 23, - FLOW_ACTION_CT_METADATA = 24, - FLOW_ACTION_MPLS_PUSH = 25, - FLOW_ACTION_MPLS_POP = 26, - FLOW_ACTION_MPLS_MANGLE = 27, - FLOW_ACTION_GATE = 28, - NUM_FLOW_ACTIONS = 29, -}; - -enum flow_action_mangle_base { - FLOW_ACT_MANGLE_UNSPEC = 0, - FLOW_ACT_MANGLE_HDR_TYPE_ETH = 1, - FLOW_ACT_MANGLE_HDR_TYPE_IP4 = 2, - FLOW_ACT_MANGLE_HDR_TYPE_IP6 = 3, - FLOW_ACT_MANGLE_HDR_TYPE_TCP = 4, - FLOW_ACT_MANGLE_HDR_TYPE_UDP = 5, -}; - -enum flow_action_hw_stats { - FLOW_ACTION_HW_STATS_IMMEDIATE = 1, - FLOW_ACTION_HW_STATS_DELAYED = 2, - FLOW_ACTION_HW_STATS_ANY = 3, - FLOW_ACTION_HW_STATS_DISABLED = 4, - FLOW_ACTION_HW_STATS_DONT_CARE = 7, -}; - -typedef void (*action_destr)(void *); - -struct flow_action_cookie { - u32 cookie_len; - u8 cookie[0]; -}; - -struct nf_flowtable; - -struct psample_group; - -struct action_gate_entry; - -struct flow_action_entry { - enum flow_action_id id; - enum flow_action_hw_stats hw_stats; - action_destr destructor; - void *destructor_priv; - union { - u32 chain_index; - struct net_device *dev; - struct { - u16 vid; - __be16 proto; - u8 prio; - } vlan; - struct { - enum flow_action_mangle_base htype; - u32 offset; - u32 mask; - u32 val; - } mangle; - struct ip_tunnel_info *tunnel; - u32 csum_flags; - u32 mark; - u16 ptype; - u32 priority; - struct { - u32 ctx; - u32 index; - u8 vf; - } queue; - struct { - struct psample_group *psample_group; - u32 rate; - u32 trunc_size; - bool truncate; - } sample; - struct { - u32 index; - u32 burst; - u64 rate_bytes_ps; - u32 mtu; - } police; - struct { - int action; - u16 zone; - struct nf_flowtable *flow_table; - } ct; - struct { - long unsigned int cookie; - u32 mark; - u32 labels[4]; - } ct_metadata; - struct { - u32 label; - __be16 proto; - u8 tc; - u8 bos; - u8 ttl; - } mpls_push; - struct { - __be16 proto; - } mpls_pop; - struct { - u32 label; - u8 tc; - u8 bos; - u8 ttl; - } mpls_mangle; - struct { - u32 index; - s32 prio; - u64 basetime; - u64 cycletime; - u64 cycletimeext; - u32 num_entries; - struct action_gate_entry *entries; - } gate; - }; - struct flow_action_cookie *cookie; -}; - -struct flow_action { - unsigned int num_entries; - struct flow_action_entry entries[0]; -}; - -struct flow_rule { - struct flow_match match; - struct flow_action action; -}; - -enum flow_block_command { - FLOW_BLOCK_BIND = 0, - FLOW_BLOCK_UNBIND = 1, -}; - -enum flow_block_binder_type { - FLOW_BLOCK_BINDER_TYPE_UNSPEC = 0, - FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS = 1, - FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS = 2, - FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP = 3, - FLOW_BLOCK_BINDER_TYPE_RED_MARK = 4, -}; - -struct flow_block_offload { - enum flow_block_command command; - enum flow_block_binder_type binder_type; - bool block_shared; - bool unlocked_driver_cb; - struct net *net; - struct flow_block *block; - struct list_head cb_list; - struct list_head *driver_block_list; - struct netlink_ext_ack *extack; - struct Qdisc *sch; - struct list_head *cb_list_head; -}; - -struct flow_block_cb; - -struct flow_block_indr { - struct list_head list; - struct net_device *dev; - struct Qdisc *sch; - enum flow_block_binder_type binder_type; - void *data; - void *cb_priv; - void (*cleanup)(struct flow_block_cb *); -}; - -struct flow_block_cb { - struct list_head driver_list; - struct list_head list; - flow_setup_cb_t *cb; - void *cb_ident; - void *cb_priv; - void (*release)(void *); - struct flow_block_indr indr; - unsigned int refcnt; -}; - -typedef int flow_indr_block_bind_cb_t(struct net_device *, struct Qdisc *, void *, enum tc_setup_type, void *, void *, void (*)(struct flow_block_cb *)); - -struct flow_indr_dev { - struct list_head list; - flow_indr_block_bind_cb_t *cb; - void *cb_priv; - refcount_t refcnt; - struct callback_head rcu; -}; - -struct flow_indir_dev_info { - void *data; - struct net_device *dev; - struct Qdisc *sch; - enum tc_setup_type type; - void (*cleanup)(struct flow_block_cb *); - struct list_head list; - enum flow_block_command command; - enum flow_block_binder_type binder_type; - struct list_head *cb_list; -}; - -struct rx_queue_attribute { - struct attribute attr; - ssize_t (*show)(struct netdev_rx_queue *, char *); - ssize_t (*store)(struct netdev_rx_queue *, const char *, size_t); -}; - -struct netdev_queue_attribute { - struct attribute attr; - ssize_t (*show)(struct netdev_queue *, char *); - ssize_t (*store)(struct netdev_queue *, const char *, size_t); -}; - -struct fib_rule_uid_range { - __u32 start; - __u32 end; -}; - -enum { - FRA_UNSPEC = 0, - FRA_DST = 1, - FRA_SRC = 2, - FRA_IIFNAME = 3, - FRA_GOTO = 4, - FRA_UNUSED2 = 5, - FRA_PRIORITY = 6, - FRA_UNUSED3 = 7, - FRA_UNUSED4 = 8, - FRA_UNUSED5 = 9, - FRA_FWMARK = 10, - FRA_FLOW = 11, - FRA_TUN_ID = 12, - FRA_SUPPRESS_IFGROUP = 13, - FRA_SUPPRESS_PREFIXLEN = 14, - FRA_TABLE = 15, - FRA_FWMASK = 16, - FRA_OIFNAME = 17, - FRA_PAD = 18, - FRA_L3MDEV = 19, - FRA_UID_RANGE = 20, - FRA_PROTOCOL = 21, - FRA_IP_PROTO = 22, - FRA_SPORT_RANGE = 23, - FRA_DPORT_RANGE = 24, - __FRA_MAX = 25, -}; - -enum { - FR_ACT_UNSPEC = 0, - FR_ACT_TO_TBL = 1, - FR_ACT_GOTO = 2, - FR_ACT_NOP = 3, - FR_ACT_RES3 = 4, - FR_ACT_RES4 = 5, - FR_ACT_BLACKHOLE = 6, - FR_ACT_UNREACHABLE = 7, - FR_ACT_PROHIBIT = 8, - __FR_ACT_MAX = 9, -}; - -struct fib_rule_notifier_info { - struct fib_notifier_info info; - struct fib_rule *rule; -}; - -struct trace_event_raw_kfree_skb { - struct trace_entry ent; - void *skbaddr; - void *location; - short unsigned int protocol; - char __data[0]; -}; - -struct trace_event_raw_consume_skb { - struct trace_entry ent; - void *skbaddr; - char __data[0]; -}; - -struct trace_event_raw_skb_copy_datagram_iovec { - struct trace_entry ent; - const void *skbaddr; - int len; - char __data[0]; -}; - -struct trace_event_data_offsets_kfree_skb {}; - -struct trace_event_data_offsets_consume_skb {}; - -struct trace_event_data_offsets_skb_copy_datagram_iovec {}; - -typedef void (*btf_trace_kfree_skb)(void *, struct sk_buff *, void *); - -typedef void (*btf_trace_consume_skb)(void *, struct sk_buff *); - -typedef void (*btf_trace_skb_copy_datagram_iovec)(void *, const struct sk_buff *, int); - -struct trace_event_raw_net_dev_start_xmit { - struct trace_entry ent; - u32 __data_loc_name; - u16 queue_mapping; - const void *skbaddr; - bool vlan_tagged; - u16 vlan_proto; - u16 vlan_tci; - u16 protocol; - u8 ip_summed; - unsigned int len; - unsigned int data_len; - int network_offset; - bool transport_offset_valid; - int transport_offset; - u8 tx_flags; - u16 gso_size; - u16 gso_segs; - u16 gso_type; - char __data[0]; -}; - -struct trace_event_raw_net_dev_xmit { - struct trace_entry ent; - void *skbaddr; - unsigned int len; - int rc; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_net_dev_xmit_timeout { - struct trace_entry ent; - u32 __data_loc_name; - u32 __data_loc_driver; - int queue_index; - char __data[0]; -}; - -struct trace_event_raw_net_dev_template { - struct trace_entry ent; - void *skbaddr; - unsigned int len; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_net_dev_rx_verbose_template { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int napi_id; - u16 queue_mapping; - const void *skbaddr; - bool vlan_tagged; - u16 vlan_proto; - u16 vlan_tci; - u16 protocol; - u8 ip_summed; - u32 hash; - bool l4_hash; - unsigned int len; - unsigned int data_len; - unsigned int truesize; - bool mac_header_valid; - int mac_header; - unsigned char nr_frags; - u16 gso_size; - u16 gso_type; - char __data[0]; -}; - -struct trace_event_raw_net_dev_rx_exit_template { - struct trace_entry ent; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_net_dev_start_xmit { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_xmit { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_xmit_timeout { - u32 name; - u32 driver; -}; - -struct trace_event_data_offsets_net_dev_template { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_rx_verbose_template { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_rx_exit_template {}; - -typedef void (*btf_trace_net_dev_start_xmit)(void *, const struct sk_buff *, const struct net_device *); - -typedef void (*btf_trace_net_dev_xmit)(void *, struct sk_buff *, int, struct net_device *, unsigned int); - -typedef void (*btf_trace_net_dev_xmit_timeout)(void *, struct net_device *, int); - -typedef void (*btf_trace_net_dev_queue)(void *, struct sk_buff *); - -typedef void (*btf_trace_netif_receive_skb)(void *, struct sk_buff *); - -typedef void (*btf_trace_netif_rx)(void *, struct sk_buff *); - -typedef void (*btf_trace_napi_gro_frags_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_napi_gro_receive_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_receive_skb_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_receive_skb_list_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_rx_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_rx_ni_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_napi_gro_frags_exit)(void *, int); - -typedef void (*btf_trace_napi_gro_receive_exit)(void *, int); - -typedef void (*btf_trace_netif_receive_skb_exit)(void *, int); - -typedef void (*btf_trace_netif_rx_exit)(void *, int); - -typedef void (*btf_trace_netif_rx_ni_exit)(void *, int); - -typedef void (*btf_trace_netif_receive_skb_list_exit)(void *, int); - -struct trace_event_raw_napi_poll { - struct trace_entry ent; - struct napi_struct *napi; - u32 __data_loc_dev_name; - int work; - int budget; - char __data[0]; -}; - -struct trace_event_data_offsets_napi_poll { - u32 dev_name; -}; - -typedef void (*btf_trace_napi_poll)(void *, struct napi_struct *, int, int); - -enum tcp_ca_state { - TCP_CA_Open = 0, - TCP_CA_Disorder = 1, - TCP_CA_CWR = 2, - TCP_CA_Recovery = 3, - TCP_CA_Loss = 4, -}; - -struct trace_event_raw_sock_rcvqueue_full { - struct trace_entry ent; - int rmem_alloc; - unsigned int truesize; - int sk_rcvbuf; - char __data[0]; -}; - -struct trace_event_raw_sock_exceed_buf_limit { - struct trace_entry ent; - char name[32]; - long int *sysctl_mem; - long int allocated; - int sysctl_rmem; - int rmem_alloc; - int sysctl_wmem; - int wmem_alloc; - int wmem_queued; - int kind; - char __data[0]; -}; - -struct trace_event_raw_inet_sock_set_state { - struct trace_entry ent; - const void *skaddr; - int oldstate; - int newstate; - __u16 sport; - __u16 dport; - __u16 family; - __u16 protocol; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - char __data[0]; -}; - -struct trace_event_data_offsets_sock_rcvqueue_full {}; - -struct trace_event_data_offsets_sock_exceed_buf_limit {}; - -struct trace_event_data_offsets_inet_sock_set_state {}; - -typedef void (*btf_trace_sock_rcvqueue_full)(void *, struct sock *, struct sk_buff *); - -typedef void (*btf_trace_sock_exceed_buf_limit)(void *, struct sock *, struct proto *, long int, int); - -typedef void (*btf_trace_inet_sock_set_state)(void *, const struct sock *, const int, const int); - -struct trace_event_raw_udp_fail_queue_rcv_skb { - struct trace_entry ent; - int rc; - __u16 lport; - char __data[0]; -}; - -struct trace_event_data_offsets_udp_fail_queue_rcv_skb {}; - -typedef void (*btf_trace_udp_fail_queue_rcv_skb)(void *, int, struct sock *); - -struct trace_event_raw_tcp_event_sk_skb { - struct trace_entry ent; - const void *skbaddr; - const void *skaddr; - int state; - __u16 sport; - __u16 dport; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - char __data[0]; -}; - -struct trace_event_raw_tcp_event_sk { - struct trace_entry ent; - const void *skaddr; - __u16 sport; - __u16 dport; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - __u64 sock_cookie; - char __data[0]; -}; - -struct trace_event_raw_tcp_retransmit_synack { - struct trace_entry ent; - const void *skaddr; - const void *req; - __u16 sport; - __u16 dport; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - char __data[0]; -}; - -struct trace_event_raw_tcp_probe { - struct trace_entry ent; - __u8 saddr[28]; - __u8 daddr[28]; - __u16 sport; - __u16 dport; - __u32 mark; - __u16 data_len; - __u32 snd_nxt; - __u32 snd_una; - __u32 snd_cwnd; - __u32 ssthresh; - __u32 snd_wnd; - __u32 srtt; - __u32 rcv_wnd; - __u64 sock_cookie; - char __data[0]; -}; - -struct trace_event_data_offsets_tcp_event_sk_skb {}; - -struct trace_event_data_offsets_tcp_event_sk {}; - -struct trace_event_data_offsets_tcp_retransmit_synack {}; - -struct trace_event_data_offsets_tcp_probe {}; - -typedef void (*btf_trace_tcp_retransmit_skb)(void *, const struct sock *, const struct sk_buff *); - -typedef void (*btf_trace_tcp_send_reset)(void *, const struct sock *, const struct sk_buff *); - -typedef void (*btf_trace_tcp_receive_reset)(void *, struct sock *); - -typedef void (*btf_trace_tcp_destroy_sock)(void *, struct sock *); - -typedef void (*btf_trace_tcp_rcv_space_adjust)(void *, struct sock *); - -typedef void (*btf_trace_tcp_retransmit_synack)(void *, const struct sock *, const struct request_sock *); - -typedef void (*btf_trace_tcp_probe)(void *, struct sock *, struct sk_buff *); - -struct trace_event_raw_fib_table_lookup { - struct trace_entry ent; - u32 tb_id; - int err; - int oif; - int iif; - u8 proto; - __u8 tos; - __u8 scope; - __u8 flags; - __u8 src[4]; - __u8 dst[4]; - __u8 gw4[4]; - __u8 gw6[16]; - u16 sport; - u16 dport; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_data_offsets_fib_table_lookup { - u32 name; -}; - -typedef void (*btf_trace_fib_table_lookup)(void *, u32, const struct flowi4 *, const struct fib_nh_common *, int); - -struct trace_event_raw_qdisc_dequeue { - struct trace_entry ent; - struct Qdisc *qdisc; - const struct netdev_queue *txq; - int packets; - void *skbaddr; - int ifindex; - u32 handle; - u32 parent; - long unsigned int txq_state; - char __data[0]; -}; - -struct trace_event_raw_qdisc_reset { - struct trace_entry ent; - u32 __data_loc_dev; - u32 __data_loc_kind; - u32 parent; - u32 handle; - char __data[0]; -}; - -struct trace_event_raw_qdisc_destroy { - struct trace_entry ent; - u32 __data_loc_dev; - u32 __data_loc_kind; - u32 parent; - u32 handle; - char __data[0]; -}; - -struct trace_event_raw_qdisc_create { - struct trace_entry ent; - u32 __data_loc_dev; - u32 __data_loc_kind; - u32 parent; - char __data[0]; -}; - -struct trace_event_data_offsets_qdisc_dequeue {}; - -struct trace_event_data_offsets_qdisc_reset { - u32 dev; - u32 kind; -}; - -struct trace_event_data_offsets_qdisc_destroy { - u32 dev; - u32 kind; -}; - -struct trace_event_data_offsets_qdisc_create { - u32 dev; - u32 kind; -}; - -typedef void (*btf_trace_qdisc_dequeue)(void *, struct Qdisc *, const struct netdev_queue *, int, struct sk_buff *); - -typedef void (*btf_trace_qdisc_reset)(void *, struct Qdisc *); - -typedef void (*btf_trace_qdisc_destroy)(void *, struct Qdisc *); - -typedef void (*btf_trace_qdisc_create)(void *, const struct Qdisc_ops *, struct net_device *, u32); - -struct bridge_stp_xstats { - __u64 transition_blk; - __u64 transition_fwd; - __u64 rx_bpdu; - __u64 tx_bpdu; - __u64 rx_tcn; - __u64 tx_tcn; -}; - -struct br_mcast_stats { - __u64 igmp_v1queries[2]; - __u64 igmp_v2queries[2]; - __u64 igmp_v3queries[2]; - __u64 igmp_leaves[2]; - __u64 igmp_v1reports[2]; - __u64 igmp_v2reports[2]; - __u64 igmp_v3reports[2]; - __u64 igmp_parse_errors; - __u64 mld_v1queries[2]; - __u64 mld_v2queries[2]; - __u64 mld_leaves[2]; - __u64 mld_v1reports[2]; - __u64 mld_v2reports[2]; - __u64 mld_parse_errors; - __u64 mcast_bytes[2]; - __u64 mcast_packets[2]; -}; - -struct br_ip { - union { - __be32 ip4; - struct in6_addr ip6; - } src; - union { - __be32 ip4; - struct in6_addr ip6; - } dst; - __be16 proto; - __u16 vid; -}; - -struct bridge_id { - unsigned char prio[2]; - unsigned char addr[6]; -}; - -typedef struct bridge_id bridge_id; - -struct mac_addr { - unsigned char addr[6]; -}; - -typedef struct mac_addr mac_addr; - -typedef __u16 port_id; - -struct bridge_mcast_own_query { - struct timer_list timer; - u32 startup_sent; -}; - -struct bridge_mcast_other_query { - struct timer_list timer; - long unsigned int delay_time; -}; - -struct net_bridge_port; - -struct bridge_mcast_querier { - struct br_ip addr; - struct net_bridge_port *port; -}; - -struct net_bridge; - -struct bridge_mcast_stats; - -struct net_bridge_port { - struct net_bridge *br; - struct net_device *dev; - struct list_head list; - long unsigned int flags; - struct net_bridge_port *backup_port; - u8 priority; - u8 state; - u16 port_no; - unsigned char topology_change_ack; - unsigned char config_pending; - port_id port_id; - port_id designated_port; - bridge_id designated_root; - bridge_id designated_bridge; - u32 path_cost; - u32 designated_cost; - long unsigned int designated_age; - struct timer_list forward_delay_timer; - struct timer_list hold_timer; - struct timer_list message_age_timer; - struct kobject kobj; - struct callback_head rcu; - struct bridge_mcast_own_query ip4_own_query; - struct bridge_mcast_own_query ip6_own_query; - unsigned char multicast_router; - struct bridge_mcast_stats *mcast_stats; - struct timer_list multicast_router_timer; - struct hlist_head mglist; - struct hlist_node rlist; - char sysfs_name[16]; - struct netpoll *np; - u16 group_fwd_mask; - u16 backup_redirected_cnt; - struct bridge_stp_xstats stp_xstats; -}; - -struct bridge_mcast_stats { - struct br_mcast_stats mstats; - struct u64_stats_sync syncp; -}; - -struct net_bridge { - spinlock_t lock; - spinlock_t hash_lock; - struct list_head port_list; - struct net_device *dev; - struct pcpu_sw_netstats *stats; - long unsigned int options; - struct rhashtable fdb_hash_tbl; - union { - struct rtable fake_rtable; - struct rt6_info fake_rt6_info; - }; - u16 group_fwd_mask; - u16 group_fwd_mask_required; - bridge_id designated_root; - bridge_id bridge_id; - unsigned char topology_change; - unsigned char topology_change_detected; - u16 root_port; - long unsigned int max_age; - long unsigned int hello_time; - long unsigned int forward_delay; - long unsigned int ageing_time; - long unsigned int bridge_max_age; - long unsigned int bridge_hello_time; - long unsigned int bridge_forward_delay; - long unsigned int bridge_ageing_time; - u32 root_path_cost; - u8 group_addr[6]; - enum { - BR_NO_STP = 0, - BR_KERNEL_STP = 1, - BR_USER_STP = 2, - } stp_enabled; - u32 hash_max; - u32 multicast_last_member_count; - u32 multicast_startup_query_count; - u8 multicast_igmp_version; - u8 multicast_router; - u8 multicast_mld_version; - spinlock_t multicast_lock; - long unsigned int multicast_last_member_interval; - long unsigned int multicast_membership_interval; - long unsigned int multicast_querier_interval; - long unsigned int multicast_query_interval; - long unsigned int multicast_query_response_interval; - long unsigned int multicast_startup_query_interval; - struct rhashtable mdb_hash_tbl; - struct rhashtable sg_port_tbl; - struct hlist_head mcast_gc_list; - struct hlist_head mdb_list; - struct hlist_head router_list; - struct timer_list multicast_router_timer; - struct bridge_mcast_other_query ip4_other_query; - struct bridge_mcast_own_query ip4_own_query; - struct bridge_mcast_querier ip4_querier; - struct bridge_mcast_stats *mcast_stats; - struct bridge_mcast_other_query ip6_other_query; - struct bridge_mcast_own_query ip6_own_query; - struct bridge_mcast_querier ip6_querier; - struct work_struct mcast_gc_work; - struct timer_list hello_timer; - struct timer_list tcn_timer; - struct timer_list topology_change_timer; - struct delayed_work gc_work; - struct kobject *ifobj; - u32 auto_cnt; - struct hlist_head fdb_list; -}; - -struct net_bridge_fdb_key { - mac_addr addr; - u16 vlan_id; -}; - -struct net_bridge_fdb_entry { - struct rhash_head rhnode; - struct net_bridge_port *dst; - struct net_bridge_fdb_key key; - struct hlist_node fdb_node; - long unsigned int flags; - long: 64; - long: 64; - long unsigned int updated; - long unsigned int used; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct trace_event_raw_br_fdb_add { - struct trace_entry ent; - u8 ndm_flags; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - u16 nlh_flags; - char __data[0]; -}; - -struct trace_event_raw_br_fdb_external_learn_add { - struct trace_entry ent; - u32 __data_loc_br_dev; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - char __data[0]; -}; - -struct trace_event_raw_fdb_delete { - struct trace_entry ent; - u32 __data_loc_br_dev; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - char __data[0]; -}; - -struct trace_event_raw_br_fdb_update { - struct trace_entry ent; - u32 __data_loc_br_dev; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_data_offsets_br_fdb_add { - u32 dev; -}; - -struct trace_event_data_offsets_br_fdb_external_learn_add { - u32 br_dev; - u32 dev; -}; - -struct trace_event_data_offsets_fdb_delete { - u32 br_dev; - u32 dev; -}; - -struct trace_event_data_offsets_br_fdb_update { - u32 br_dev; - u32 dev; -}; - -typedef void (*btf_trace_br_fdb_add)(void *, struct ndmsg *, struct net_device *, const unsigned char *, u16, u16); - -typedef void (*btf_trace_br_fdb_external_learn_add)(void *, struct net_bridge *, struct net_bridge_port *, const unsigned char *, u16); - -typedef void (*btf_trace_fdb_delete)(void *, struct net_bridge *, struct net_bridge_fdb_entry *); - -typedef void (*btf_trace_br_fdb_update)(void *, struct net_bridge *, struct net_bridge_port *, const unsigned char *, u16, long unsigned int); - -struct trace_event_raw_neigh_create { - struct trace_entry ent; - u32 family; - u32 __data_loc_dev; - int entries; - u8 created; - u8 gc_exempt; - u8 primary_key4[4]; - u8 primary_key6[16]; - char __data[0]; -}; - -struct trace_event_raw_neigh_update { - struct trace_entry ent; - u32 family; - u32 __data_loc_dev; - u8 lladdr[32]; - u8 lladdr_len; - u8 flags; - u8 nud_state; - u8 type; - u8 dead; - int refcnt; - __u8 primary_key4[4]; - __u8 primary_key6[16]; - long unsigned int confirmed; - long unsigned int updated; - long unsigned int used; - u8 new_lladdr[32]; - u8 new_state; - u32 update_flags; - u32 pid; - char __data[0]; -}; - -struct trace_event_raw_neigh__update { - struct trace_entry ent; - u32 family; - u32 __data_loc_dev; - u8 lladdr[32]; - u8 lladdr_len; - u8 flags; - u8 nud_state; - u8 type; - u8 dead; - int refcnt; - __u8 primary_key4[4]; - __u8 primary_key6[16]; - long unsigned int confirmed; - long unsigned int updated; - long unsigned int used; - u32 err; - char __data[0]; -}; - -struct trace_event_data_offsets_neigh_create { - u32 dev; -}; - -struct trace_event_data_offsets_neigh_update { - u32 dev; -}; - -struct trace_event_data_offsets_neigh__update { - u32 dev; -}; - -typedef void (*btf_trace_neigh_create)(void *, struct neigh_table *, struct net_device *, const void *, const struct neighbour *, bool); - -typedef void (*btf_trace_neigh_update)(void *, struct neighbour *, const u8 *, u8, u32, u32); - -typedef void (*btf_trace_neigh_update_done)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_timer_handler)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_event_send_done)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_event_send_dead)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_cleanup_and_release)(void *, struct neighbour *, int); - -struct update_classid_context { - u32 classid; - unsigned int batch; -}; - -struct rtnexthop { - short unsigned int rtnh_len; - unsigned char rtnh_flags; - unsigned char rtnh_hops; - int rtnh_ifindex; -}; - -struct lwtunnel_encap_ops { - int (*build_state)(struct net *, struct nlattr *, unsigned int, const void *, struct lwtunnel_state **, struct netlink_ext_ack *); - void (*destroy_state)(struct lwtunnel_state *); - int (*output)(struct net *, struct sock *, struct sk_buff *); - int (*input)(struct sk_buff *); - int (*fill_encap)(struct sk_buff *, struct lwtunnel_state *); - int (*get_encap_size)(struct lwtunnel_state *); - int (*cmp_encap)(struct lwtunnel_state *, struct lwtunnel_state *); - int (*xmit)(struct sk_buff *); - struct module *owner; -}; - -enum { - LWT_BPF_PROG_UNSPEC = 0, - LWT_BPF_PROG_FD = 1, - LWT_BPF_PROG_NAME = 2, - __LWT_BPF_PROG_MAX = 3, -}; - -enum { - LWT_BPF_UNSPEC = 0, - LWT_BPF_IN = 1, - LWT_BPF_OUT = 2, - LWT_BPF_XMIT = 3, - LWT_BPF_XMIT_HEADROOM = 4, - __LWT_BPF_MAX = 5, -}; - -enum { - LWTUNNEL_XMIT_DONE = 0, - LWTUNNEL_XMIT_CONTINUE = 1, -}; - -struct bpf_lwt_prog { - struct bpf_prog *prog; - char *name; -}; - -struct bpf_lwt { - struct bpf_lwt_prog in; - struct bpf_lwt_prog out; - struct bpf_lwt_prog xmit; - int family; -}; - -struct dst_cache_pcpu { - long unsigned int refresh_ts; - struct dst_entry *dst; - u32 cookie; - union { - struct in_addr in_saddr; - struct in6_addr in6_saddr; - }; -}; - -struct gro_cell; - -struct gro_cells { - struct gro_cell *cells; -}; - -struct gro_cell { - struct sk_buff_head napi_skbs; - struct napi_struct napi; -}; - -enum { - BPF_LOCAL_STORAGE_GET_F_CREATE = 1, - BPF_SK_STORAGE_GET_F_CREATE = 1, -}; - -enum { - SK_DIAG_BPF_STORAGE_REQ_NONE = 0, - SK_DIAG_BPF_STORAGE_REQ_MAP_FD = 1, - __SK_DIAG_BPF_STORAGE_REQ_MAX = 2, -}; - -enum { - SK_DIAG_BPF_STORAGE_REP_NONE = 0, - SK_DIAG_BPF_STORAGE = 1, - __SK_DIAG_BPF_STORAGE_REP_MAX = 2, -}; - -enum { - SK_DIAG_BPF_STORAGE_NONE = 0, - SK_DIAG_BPF_STORAGE_PAD = 1, - SK_DIAG_BPF_STORAGE_MAP_ID = 2, - SK_DIAG_BPF_STORAGE_MAP_VALUE = 3, - __SK_DIAG_BPF_STORAGE_MAX = 4, -}; - -typedef u64 (*btf_bpf_sk_storage_get)(struct bpf_map *, struct sock *, void *, u64); - -typedef u64 (*btf_bpf_sk_storage_delete)(struct bpf_map *, struct sock *); - -struct bpf_sk_storage_diag { - u32 nr_maps; - struct bpf_map *maps[0]; -}; - -struct bpf_iter_seq_sk_storage_map_info { - struct bpf_map *map; - unsigned int bucket_id; - unsigned int skip_elems; -}; - -struct bpf_iter__bpf_sk_storage_map { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_map *map; - }; - union { - struct sock *sk; - }; - union { - void *value; - }; -}; - -struct compat_cmsghdr { - compat_size_t cmsg_len; - compat_int_t cmsg_level; - compat_int_t cmsg_type; -}; - -typedef struct sk_buff * (*gro_receive_t)(struct list_head *, struct sk_buff *); - -struct nvmem_cell___2; - -enum macvlan_mode { - MACVLAN_MODE_PRIVATE = 1, - MACVLAN_MODE_VEPA = 2, - MACVLAN_MODE_BRIDGE = 4, - MACVLAN_MODE_PASSTHRU = 8, - MACVLAN_MODE_SOURCE = 16, -}; - -struct tc_ratespec { - unsigned char cell_log; - __u8 linklayer; - short unsigned int overhead; - short int cell_align; - short unsigned int mpu; - __u32 rate; -}; - -struct tc_prio_qopt { - int bands; - __u8 priomap[16]; -}; - -enum { - TCA_UNSPEC = 0, - TCA_KIND = 1, - TCA_OPTIONS = 2, - TCA_STATS = 3, - TCA_XSTATS = 4, - TCA_RATE = 5, - TCA_FCNT = 6, - TCA_STATS2 = 7, - TCA_STAB = 8, - TCA_PAD = 9, - TCA_DUMP_INVISIBLE = 10, - TCA_CHAIN = 11, - TCA_HW_OFFLOAD = 12, - TCA_INGRESS_BLOCK = 13, - TCA_EGRESS_BLOCK = 14, - TCA_DUMP_FLAGS = 15, - __TCA_MAX = 16, -}; - -struct vlan_pcpu_stats { - u64 rx_packets; - u64 rx_bytes; - u64 rx_multicast; - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; - u32 rx_errors; - u32 tx_dropped; -}; - -struct netpoll___2; - -struct skb_array { - struct ptr_ring ring; -}; - -struct macvlan_port; - -struct macvlan_dev { - struct net_device *dev; - struct list_head list; - struct hlist_node hlist; - struct macvlan_port *port; - struct net_device *lowerdev; - void *accel_priv; - struct vlan_pcpu_stats *pcpu_stats; - long unsigned int mc_filter[4]; - netdev_features_t set_features; - enum macvlan_mode mode; - u16 flags; - unsigned int macaddr_count; - struct netpoll___2 *netpoll; -}; - -struct psched_ratecfg { - u64 rate_bytes_ps; - u32 mult; - u16 overhead; - u8 linklayer; - u8 shift; -}; - -struct mini_Qdisc_pair { - struct mini_Qdisc miniq1; - struct mini_Qdisc miniq2; - struct mini_Qdisc **p_miniq; -}; - -struct pfifo_fast_priv { - struct skb_array q[3]; -}; - -struct tc_qopt_offload_stats { - struct gnet_stats_basic_packed *bstats; - struct gnet_stats_queue *qstats; -}; - -enum tc_mq_command { - TC_MQ_CREATE = 0, - TC_MQ_DESTROY = 1, - TC_MQ_STATS = 2, - TC_MQ_GRAFT = 3, -}; - -struct tc_mq_opt_offload_graft_params { - long unsigned int queue; - u32 child_handle; -}; - -struct tc_mq_qopt_offload { - enum tc_mq_command command; - u32 handle; - union { - struct tc_qopt_offload_stats stats; - struct tc_mq_opt_offload_graft_params graft_params; - }; -}; - -struct mq_sched { - struct Qdisc **qdiscs; -}; - -enum tc_link_layer { - TC_LINKLAYER_UNAWARE = 0, - TC_LINKLAYER_ETHERNET = 1, - TC_LINKLAYER_ATM = 2, -}; - -enum { - TCA_STAB_UNSPEC = 0, - TCA_STAB_BASE = 1, - TCA_STAB_DATA = 2, - __TCA_STAB_MAX = 3, -}; - -struct qdisc_rate_table { - struct tc_ratespec rate; - u32 data[256]; - struct qdisc_rate_table *next; - int refcnt; -}; - -struct Qdisc_class_common { - u32 classid; - struct hlist_node hnode; -}; - -struct Qdisc_class_hash { - struct hlist_head *hash; - unsigned int hashsize; - unsigned int hashmask; - unsigned int hashelems; -}; - -struct qdisc_watchdog { - u64 last_expires; - struct hrtimer timer; - struct Qdisc *qdisc; -}; - -enum tc_root_command { - TC_ROOT_GRAFT = 0, -}; - -struct tc_root_qopt_offload { - enum tc_root_command command; - u32 handle; - bool ingress; -}; - -struct check_loop_arg { - struct qdisc_walker w; - struct Qdisc *p; - int depth; -}; - -struct tcf_bind_args { - struct tcf_walker w; - long unsigned int base; - long unsigned int cl; - u32 classid; -}; - -struct tc_bind_class_args { - struct qdisc_walker w; - long unsigned int new_cl; - u32 portid; - u32 clid; -}; - -struct qdisc_dump_args { - struct qdisc_walker w; - struct sk_buff *skb; - struct netlink_callback *cb; -}; - -enum net_xmit_qdisc_t { - __NET_XMIT_STOLEN = 65536, - __NET_XMIT_BYPASS = 131072, -}; - -enum { - TCA_ACT_UNSPEC = 0, - TCA_ACT_KIND = 1, - TCA_ACT_OPTIONS = 2, - TCA_ACT_INDEX = 3, - TCA_ACT_STATS = 4, - TCA_ACT_PAD = 5, - TCA_ACT_COOKIE = 6, - TCA_ACT_FLAGS = 7, - TCA_ACT_HW_STATS = 8, - TCA_ACT_USED_HW_STATS = 9, - __TCA_ACT_MAX = 10, -}; - -enum tca_id { - TCA_ID_UNSPEC = 0, - TCA_ID_POLICE = 1, - TCA_ID_GACT = 5, - TCA_ID_IPT = 6, - TCA_ID_PEDIT = 7, - TCA_ID_MIRRED = 8, - TCA_ID_NAT = 9, - TCA_ID_XT = 10, - TCA_ID_SKBEDIT = 11, - TCA_ID_VLAN = 12, - TCA_ID_BPF = 13, - TCA_ID_CONNMARK = 14, - TCA_ID_SKBMOD = 15, - TCA_ID_CSUM = 16, - TCA_ID_TUNNEL_KEY = 17, - TCA_ID_SIMP = 22, - TCA_ID_IFE = 25, - TCA_ID_SAMPLE = 26, - TCA_ID_CTINFO = 27, - TCA_ID_MPLS = 28, - TCA_ID_CT = 29, - TCA_ID_GATE = 30, - __TCA_ID_MAX = 255, -}; - -struct tcf_t { - __u64 install; - __u64 lastuse; - __u64 expires; - __u64 firstuse; -}; - -struct psample_group { - struct list_head list; - struct net *net; - u32 group_num; - u32 refcount; - u32 seq; - struct callback_head rcu; -}; - -struct action_gate_entry { - u8 gate_state; - u32 interval; - s32 ipv; - s32 maxoctets; -}; - -enum qdisc_class_ops_flags { - QDISC_CLASS_OPS_DOIT_UNLOCKED = 1, -}; - -enum tcf_proto_ops_flags { - TCF_PROTO_OPS_DOIT_UNLOCKED = 1, -}; - -typedef void tcf_chain_head_change_t(struct tcf_proto *, void *); - -struct tcf_idrinfo { - struct mutex lock; - struct idr action_idr; - struct net *net; -}; - -struct tc_action_ops; - -struct tc_cookie; - -struct tc_action { - const struct tc_action_ops *ops; - __u32 type; - struct tcf_idrinfo *idrinfo; - u32 tcfa_index; - refcount_t tcfa_refcnt; - atomic_t tcfa_bindcnt; - int tcfa_action; - struct tcf_t tcfa_tm; - struct gnet_stats_basic_packed tcfa_bstats; - struct gnet_stats_basic_packed tcfa_bstats_hw; - struct gnet_stats_queue tcfa_qstats; - struct net_rate_estimator *tcfa_rate_est; - spinlock_t tcfa_lock; - struct gnet_stats_basic_cpu *cpu_bstats; - struct gnet_stats_basic_cpu *cpu_bstats_hw; - struct gnet_stats_queue *cpu_qstats; - struct tc_cookie *act_cookie; - struct tcf_chain *goto_chain; - u32 tcfa_flags; - u8 hw_stats; - u8 used_hw_stats; - bool used_hw_stats_valid; -}; - -typedef void (*tc_action_priv_destructor)(void *); - -struct tc_action_ops { - struct list_head head; - char kind[16]; - enum tca_id id; - size_t size; - struct module *owner; - int (*act)(struct sk_buff *, const struct tc_action *, struct tcf_result *); - int (*dump)(struct sk_buff *, struct tc_action *, int, int); - void (*cleanup)(struct tc_action *); - int (*lookup)(struct net *, struct tc_action **, u32); - int (*init)(struct net *, struct nlattr *, struct nlattr *, struct tc_action **, int, int, bool, struct tcf_proto *, u32, struct netlink_ext_ack *); - int (*walk)(struct net *, struct sk_buff *, struct netlink_callback *, int, const struct tc_action_ops *, struct netlink_ext_ack *); - void (*stats_update)(struct tc_action *, u64, u64, u64, u64, bool); - size_t (*get_fill_size)(const struct tc_action *); - struct net_device * (*get_dev)(const struct tc_action *, tc_action_priv_destructor *); - struct psample_group * (*get_psample_group)(const struct tc_action *, tc_action_priv_destructor *); -}; - -struct tc_cookie { - u8 *data; - u32 len; - struct callback_head rcu; -}; - -struct tcf_block_ext_info { - enum flow_block_binder_type binder_type; - tcf_chain_head_change_t *chain_head_change; - void *chain_head_change_priv; - u32 block_index; -}; - -struct tcf_qevent { - struct tcf_block *block; - struct tcf_block_ext_info info; - struct tcf_proto *filter_chain; -}; - -struct tcf_exts { - __u32 type; - int nr_actions; - struct tc_action **actions; - struct net *net; - int action; - int police; -}; - -enum pedit_header_type { - TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK = 0, - TCA_PEDIT_KEY_EX_HDR_TYPE_ETH = 1, - TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 = 2, - TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 = 3, - TCA_PEDIT_KEY_EX_HDR_TYPE_TCP = 4, - TCA_PEDIT_KEY_EX_HDR_TYPE_UDP = 5, - __PEDIT_HDR_TYPE_MAX = 6, -}; - -enum pedit_cmd { - TCA_PEDIT_KEY_EX_CMD_SET = 0, - TCA_PEDIT_KEY_EX_CMD_ADD = 1, - __PEDIT_CMD_MAX = 2, -}; - -struct tc_pedit_key { - __u32 mask; - __u32 val; - __u32 off; - __u32 at; - __u32 offmask; - __u32 shift; -}; - -struct tcf_pedit_key_ex { - enum pedit_header_type htype; - enum pedit_cmd cmd; -}; - -struct tcf_pedit { - struct tc_action common; - unsigned char tcfp_nkeys; - unsigned char tcfp_flags; - struct tc_pedit_key *tcfp_keys; - struct tcf_pedit_key_ex *tcfp_keys_ex; -}; - -struct tcf_mirred { - struct tc_action common; - int tcfm_eaction; - bool tcfm_mac_header_xmit; - struct net_device *tcfm_dev; - struct list_head tcfm_list; -}; - -struct tcf_vlan_params { - int tcfv_action; - unsigned char tcfv_push_dst[6]; - unsigned char tcfv_push_src[6]; - u16 tcfv_push_vid; - __be16 tcfv_push_proto; - u8 tcfv_push_prio; - bool tcfv_push_prio_exists; - struct callback_head rcu; -}; - -struct tcf_vlan { - struct tc_action common; - struct tcf_vlan_params *vlan_p; -}; - -struct tcf_tunnel_key_params { - struct callback_head rcu; - int tcft_action; - struct metadata_dst *tcft_enc_metadata; -}; - -struct tcf_tunnel_key { - struct tc_action common; - struct tcf_tunnel_key_params *params; -}; - -struct tcf_csum_params { - u32 update_flags; - struct callback_head rcu; -}; - -struct tcf_csum { - struct tc_action common; - struct tcf_csum_params *params; -}; - -struct tcf_gact { - struct tc_action common; - u16 tcfg_ptype; - u16 tcfg_pval; - int tcfg_paction; - atomic_t packets; -}; - -struct tcf_police_params { - int tcfp_result; - u32 tcfp_ewma_rate; - s64 tcfp_burst; - u32 tcfp_mtu; - s64 tcfp_mtu_ptoks; - struct psched_ratecfg rate; - bool rate_present; - struct psched_ratecfg peak; - bool peak_present; - struct callback_head rcu; -}; - -struct tcf_police { - struct tc_action common; - struct tcf_police_params *params; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t tcfp_lock; - s64 tcfp_toks; - s64 tcfp_ptoks; - s64 tcfp_t_c; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct tcf_sample { - struct tc_action common; - u32 rate; - bool truncate; - u32 trunc_size; - struct psample_group *psample_group; - u32 psample_group_num; - struct list_head tcfm_list; -}; - -struct tcf_skbedit_params { - u32 flags; - u32 priority; - u32 mark; - u32 mask; - u16 queue_mapping; - u16 ptype; - struct callback_head rcu; -}; - -struct tcf_skbedit { - struct tc_action common; - struct tcf_skbedit_params *params; -}; - -struct nf_nat_range2 { - unsigned int flags; - union nf_inet_addr min_addr; - union nf_inet_addr max_addr; - union nf_conntrack_man_proto min_proto; - union nf_conntrack_man_proto max_proto; - union nf_conntrack_man_proto base_proto; -}; - -struct tcf_ct_flow_table; - -struct tcf_ct_params { - struct nf_conn *tmpl; - u16 zone; - u32 mark; - u32 mark_mask; - u32 labels[4]; - u32 labels_mask[4]; - struct nf_nat_range2 range; - bool ipv4_range; - u16 ct_action; - struct callback_head rcu; - struct tcf_ct_flow_table *ct_ft; - struct nf_flowtable *nf_ft; -}; - -struct tcf_ct { - struct tc_action common; - struct tcf_ct_params *params; -}; - -struct tcf_mpls_params { - int tcfm_action; - u32 tcfm_label; - u8 tcfm_tc; - u8 tcfm_ttl; - u8 tcfm_bos; - __be16 tcfm_proto; - struct callback_head rcu; -}; - -struct tcf_mpls { - struct tc_action common; - struct tcf_mpls_params *mpls_p; -}; - -struct tcfg_gate_entry { - int index; - u8 gate_state; - u32 interval; - s32 ipv; - s32 maxoctets; - struct list_head list; -}; - -struct tcf_gate_params { - s32 tcfg_priority; - u64 tcfg_basetime; - u64 tcfg_cycletime; - u64 tcfg_cycletime_ext; - u32 tcfg_flags; - s32 tcfg_clockid; - size_t num_entries; - struct list_head entries; -}; - -struct tcf_gate { - struct tc_action common; - struct tcf_gate_params param; - u8 current_gate_status; - ktime_t current_close_time; - u32 current_entry_octets; - s32 current_max_octets; - struct tcfg_gate_entry *next_entry; - struct hrtimer hitimer; - enum tk_offsets tk_offset; -}; - -struct tcf_filter_chain_list_item { - struct list_head list; - tcf_chain_head_change_t *chain_head_change; - void *chain_head_change_priv; -}; - -struct tcf_net { - spinlock_t idr_lock; - struct idr idr; -}; - -struct tcf_block_owner_item { - struct list_head list; - struct Qdisc *q; - enum flow_block_binder_type binder_type; -}; - -struct tcf_chain_info { - struct tcf_proto **pprev; - struct tcf_proto *next; -}; - -struct tcf_dump_args { - struct tcf_walker w; - struct sk_buff *skb; - struct netlink_callback *cb; - struct tcf_block *block; - struct Qdisc *q; - u32 parent; - bool terse_dump; -}; - -struct tcamsg { - unsigned char tca_family; - unsigned char tca__pad1; - short unsigned int tca__pad2; -}; - -enum { - TCA_ROOT_UNSPEC = 0, - TCA_ROOT_TAB = 1, - TCA_ROOT_FLAGS = 2, - TCA_ROOT_COUNT = 3, - TCA_ROOT_TIME_DELTA = 4, - __TCA_ROOT_MAX = 5, -}; - -struct tc_action_net { - struct tcf_idrinfo *idrinfo; - const struct tc_action_ops *ops; -}; - -struct tc_fifo_qopt { - __u32 limit; -}; - -enum tc_fifo_command { - TC_FIFO_REPLACE = 0, - TC_FIFO_DESTROY = 1, - TC_FIFO_STATS = 2, -}; - -struct tc_fifo_qopt_offload { - enum tc_fifo_command command; - u32 handle; - u32 parent; - union { - struct tc_qopt_offload_stats stats; - }; -}; - -struct tcf_ematch_tree_hdr { - __u16 nmatches; - __u16 progid; -}; - -enum { - TCA_EMATCH_TREE_UNSPEC = 0, - TCA_EMATCH_TREE_HDR = 1, - TCA_EMATCH_TREE_LIST = 2, - __TCA_EMATCH_TREE_MAX = 3, -}; - -struct tcf_ematch_hdr { - __u16 matchid; - __u16 kind; - __u16 flags; - __u16 pad; -}; - -struct tcf_pkt_info { - unsigned char *ptr; - int nexthdr; -}; - -struct tcf_ematch_ops; - -struct tcf_ematch { - struct tcf_ematch_ops *ops; - long unsigned int data; - unsigned int datalen; - u16 matchid; - u16 flags; - struct net *net; -}; - -struct tcf_ematch_ops { - int kind; - int datalen; - int (*change)(struct net *, void *, int, struct tcf_ematch *); - int (*match)(struct sk_buff *, struct tcf_ematch *, struct tcf_pkt_info *); - void (*destroy)(struct tcf_ematch *); - int (*dump)(struct sk_buff *, struct tcf_ematch *); - struct module *owner; - struct list_head link; -}; - -struct tcf_ematch_tree { - struct tcf_ematch_tree_hdr hdr; - struct tcf_ematch *matches; -}; - -struct sockaddr_nl { - __kernel_sa_family_t nl_family; - short unsigned int nl_pad; - __u32 nl_pid; - __u32 nl_groups; -}; - -struct nlmsgerr { - int error; - struct nlmsghdr msg; -}; - -enum nlmsgerr_attrs { - NLMSGERR_ATTR_UNUSED = 0, - NLMSGERR_ATTR_MSG = 1, - NLMSGERR_ATTR_OFFS = 2, - NLMSGERR_ATTR_COOKIE = 3, - NLMSGERR_ATTR_POLICY = 4, - __NLMSGERR_ATTR_MAX = 5, - NLMSGERR_ATTR_MAX = 4, -}; - -struct nl_pktinfo { - __u32 group; -}; - -enum { - NETLINK_UNCONNECTED = 0, - NETLINK_CONNECTED = 1, -}; - -enum netlink_skb_flags { - NETLINK_SKB_DST = 8, -}; - -struct netlink_notify { - struct net *net; - u32 portid; - int protocol; -}; - -struct netlink_tap { - struct net_device *dev; - struct module *module; - struct list_head list; -}; - -struct netlink_sock { - struct sock sk; - u32 portid; - u32 dst_portid; - u32 dst_group; - u32 flags; - u32 subscriptions; - u32 ngroups; - long unsigned int *groups; - long unsigned int state; - size_t max_recvmsg_len; - wait_queue_head_t wait; - bool bound; - bool cb_running; - int dump_done_errno; - struct netlink_callback cb; - struct mutex *cb_mutex; - struct mutex cb_def_mutex; - void (*netlink_rcv)(struct sk_buff *); - int (*netlink_bind)(struct net *, int); - void (*netlink_unbind)(struct net *, int); - struct module *module; - struct rhash_head node; - struct callback_head rcu; - struct work_struct work; -}; - -struct listeners; - -struct netlink_table { - struct rhashtable hash; - struct hlist_head mc_list; - struct listeners *listeners; - unsigned int flags; - unsigned int groups; - struct mutex *cb_mutex; - struct module *module; - int (*bind)(struct net *, int); - void (*unbind)(struct net *, int); - bool (*compare)(struct net *, struct sock *); - int registered; -}; - -struct listeners { - struct callback_head rcu; - long unsigned int masks[0]; -}; - -struct netlink_tap_net { - struct list_head netlink_tap_all; - struct mutex netlink_tap_lock; -}; - -struct netlink_compare_arg { - possible_net_t pnet; - u32 portid; -}; - -struct netlink_broadcast_data { - struct sock *exclude_sk; - struct net *net; - u32 portid; - u32 group; - int failure; - int delivery_failure; - int congested; - int delivered; - gfp_t allocation; - struct sk_buff *skb; - struct sk_buff *skb2; - int (*tx_filter)(struct sock *, struct sk_buff *, void *); - void *tx_data; -}; - -struct netlink_set_err_data { - struct sock *exclude_sk; - u32 portid; - u32 group; - int code; -}; - -struct nl_seq_iter { - struct seq_net_private p; - struct rhashtable_iter hti; - int link; -}; - -struct bpf_iter__netlink { - union { - struct bpf_iter_meta *meta; - }; - union { - struct netlink_sock *sk; - }; -}; - -enum { - CTRL_CMD_UNSPEC = 0, - CTRL_CMD_NEWFAMILY = 1, - CTRL_CMD_DELFAMILY = 2, - CTRL_CMD_GETFAMILY = 3, - CTRL_CMD_NEWOPS = 4, - CTRL_CMD_DELOPS = 5, - CTRL_CMD_GETOPS = 6, - CTRL_CMD_NEWMCAST_GRP = 7, - CTRL_CMD_DELMCAST_GRP = 8, - CTRL_CMD_GETMCAST_GRP = 9, - CTRL_CMD_GETPOLICY = 10, - __CTRL_CMD_MAX = 11, -}; - -enum { - CTRL_ATTR_UNSPEC = 0, - CTRL_ATTR_FAMILY_ID = 1, - CTRL_ATTR_FAMILY_NAME = 2, - CTRL_ATTR_VERSION = 3, - CTRL_ATTR_HDRSIZE = 4, - CTRL_ATTR_MAXATTR = 5, - CTRL_ATTR_OPS = 6, - CTRL_ATTR_MCAST_GROUPS = 7, - CTRL_ATTR_POLICY = 8, - CTRL_ATTR_OP_POLICY = 9, - CTRL_ATTR_OP = 10, - __CTRL_ATTR_MAX = 11, -}; - -enum { - CTRL_ATTR_OP_UNSPEC = 0, - CTRL_ATTR_OP_ID = 1, - CTRL_ATTR_OP_FLAGS = 2, - __CTRL_ATTR_OP_MAX = 3, -}; - -enum { - CTRL_ATTR_MCAST_GRP_UNSPEC = 0, - CTRL_ATTR_MCAST_GRP_NAME = 1, - CTRL_ATTR_MCAST_GRP_ID = 2, - __CTRL_ATTR_MCAST_GRP_MAX = 3, -}; - -enum { - CTRL_ATTR_POLICY_UNSPEC = 0, - CTRL_ATTR_POLICY_DO = 1, - CTRL_ATTR_POLICY_DUMP = 2, - __CTRL_ATTR_POLICY_DUMP_MAX = 3, - CTRL_ATTR_POLICY_DUMP_MAX = 2, -}; - -struct genl_dumpit_info { - const struct genl_family *family; - struct genl_ops op; - struct nlattr **attrs; -}; - -struct genl_start_context { - const struct genl_family *family; - struct nlmsghdr *nlh; - struct netlink_ext_ack *extack; - const struct genl_ops *ops; - int hdrlen; -}; - -struct netlink_policy_dump_state; - -struct ctrl_dump_policy_ctx { - struct netlink_policy_dump_state *state; - const struct genl_family *rt; - unsigned int opidx; - u32 op; - u16 fam_id; - u8 policies: 1; - u8 single_op: 1; -}; - -enum netlink_attribute_type { - NL_ATTR_TYPE_INVALID = 0, - NL_ATTR_TYPE_FLAG = 1, - NL_ATTR_TYPE_U8 = 2, - NL_ATTR_TYPE_U16 = 3, - NL_ATTR_TYPE_U32 = 4, - NL_ATTR_TYPE_U64 = 5, - NL_ATTR_TYPE_S8 = 6, - NL_ATTR_TYPE_S16 = 7, - NL_ATTR_TYPE_S32 = 8, - NL_ATTR_TYPE_S64 = 9, - NL_ATTR_TYPE_BINARY = 10, - NL_ATTR_TYPE_STRING = 11, - NL_ATTR_TYPE_NUL_STRING = 12, - NL_ATTR_TYPE_NESTED = 13, - NL_ATTR_TYPE_NESTED_ARRAY = 14, - NL_ATTR_TYPE_BITFIELD32 = 15, -}; - -enum netlink_policy_type_attr { - NL_POLICY_TYPE_ATTR_UNSPEC = 0, - NL_POLICY_TYPE_ATTR_TYPE = 1, - NL_POLICY_TYPE_ATTR_MIN_VALUE_S = 2, - NL_POLICY_TYPE_ATTR_MAX_VALUE_S = 3, - NL_POLICY_TYPE_ATTR_MIN_VALUE_U = 4, - NL_POLICY_TYPE_ATTR_MAX_VALUE_U = 5, - NL_POLICY_TYPE_ATTR_MIN_LENGTH = 6, - NL_POLICY_TYPE_ATTR_MAX_LENGTH = 7, - NL_POLICY_TYPE_ATTR_POLICY_IDX = 8, - NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE = 9, - NL_POLICY_TYPE_ATTR_BITFIELD32_MASK = 10, - NL_POLICY_TYPE_ATTR_PAD = 11, - NL_POLICY_TYPE_ATTR_MASK = 12, - __NL_POLICY_TYPE_ATTR_MAX = 13, - NL_POLICY_TYPE_ATTR_MAX = 12, -}; - -struct netlink_policy_dump_state___2 { - unsigned int policy_idx; - unsigned int attr_idx; - unsigned int n_alloc; - struct { - const struct nla_policy *policy; - unsigned int maxtype; - } policies[0]; -}; - -struct trace_event_raw_bpf_test_finish { - struct trace_entry ent; - int err; - char __data[0]; -}; - -struct trace_event_data_offsets_bpf_test_finish {}; - -typedef void (*btf_trace_bpf_test_finish)(void *, int *); - -struct bpf_fentry_test_t { - struct bpf_fentry_test_t *a; -}; - -struct bpf_raw_tp_test_run_info { - struct bpf_prog *prog; - void *ctx; - u32 retval; -}; - -struct ethtool_value { - __u32 cmd; - __u32 data; -}; - -enum tunable_type_id { - ETHTOOL_TUNABLE_UNSPEC = 0, - ETHTOOL_TUNABLE_U8 = 1, - ETHTOOL_TUNABLE_U16 = 2, - ETHTOOL_TUNABLE_U32 = 3, - ETHTOOL_TUNABLE_U64 = 4, - ETHTOOL_TUNABLE_STRING = 5, - ETHTOOL_TUNABLE_S8 = 6, - ETHTOOL_TUNABLE_S16 = 7, - ETHTOOL_TUNABLE_S32 = 8, - ETHTOOL_TUNABLE_S64 = 9, -}; - -struct ethtool_gstrings { - __u32 cmd; - __u32 string_set; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_sset_info { - __u32 cmd; - __u32 reserved; - __u64 sset_mask; - __u32 data[0]; -}; - -struct ethtool_perm_addr { - __u32 cmd; - __u32 size; - __u8 data[0]; -}; - -enum ethtool_flags { - ETH_FLAG_TXVLAN = 128, - ETH_FLAG_RXVLAN = 256, - ETH_FLAG_LRO = 32768, - ETH_FLAG_NTUPLE = 134217728, - ETH_FLAG_RXHASH = 268435456, -}; - -struct ethtool_rxfh { - __u32 cmd; - __u32 rss_context; - __u32 indir_size; - __u32 key_size; - __u8 hfunc; - __u8 rsvd8[3]; - __u32 rsvd32; - __u32 rss_config[0]; -}; - -struct ethtool_get_features_block { - __u32 available; - __u32 requested; - __u32 active; - __u32 never_changed; -}; - -struct ethtool_gfeatures { - __u32 cmd; - __u32 size; - struct ethtool_get_features_block features[0]; -}; - -struct ethtool_set_features_block { - __u32 valid; - __u32 requested; -}; - -struct ethtool_sfeatures { - __u32 cmd; - __u32 size; - struct ethtool_set_features_block features[0]; -}; - -enum ethtool_sfeatures_retval_bits { - ETHTOOL_F_UNSUPPORTED__BIT = 0, - ETHTOOL_F_WISH__BIT = 1, - ETHTOOL_F_COMPAT__BIT = 2, -}; - -struct ethtool_per_queue_op { - __u32 cmd; - __u32 sub_command; - __u32 queue_mask[128]; - char data[0]; -}; - -enum { - ETH_RSS_HASH_TOP_BIT = 0, - ETH_RSS_HASH_XOR_BIT = 1, - ETH_RSS_HASH_CRC32_BIT = 2, - ETH_RSS_HASH_FUNCS_COUNT = 3, -}; - -struct ethtool_rx_flow_rule { - struct flow_rule *rule; - long unsigned int priv[0]; -}; - -struct ethtool_rx_flow_spec_input { - const struct ethtool_rx_flow_spec *fs; - u32 rss_ctx; -}; - -struct ethtool_link_usettings { - struct ethtool_link_settings base; - struct { - __u32 supported[3]; - __u32 advertising[3]; - __u32 lp_advertising[3]; - } link_modes; -}; - -struct ethtool_rx_flow_key { - struct flow_dissector_key_basic basic; - union { - struct flow_dissector_key_ipv4_addrs ipv4; - struct flow_dissector_key_ipv6_addrs ipv6; - }; - struct flow_dissector_key_ports tp; - struct flow_dissector_key_ip ip; - struct flow_dissector_key_vlan vlan; - struct flow_dissector_key_eth_addrs eth_addrs; - long: 48; -}; - -struct ethtool_rx_flow_match { - struct flow_dissector dissector; - int: 32; - struct ethtool_rx_flow_key key; - struct ethtool_rx_flow_key mask; -}; - -enum { - ETHTOOL_UDP_TUNNEL_TYPE_VXLAN = 0, - ETHTOOL_UDP_TUNNEL_TYPE_GENEVE = 1, - ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE = 2, - __ETHTOOL_UDP_TUNNEL_TYPE_CNT = 3, -}; - -enum { - ETHTOOL_MSG_USER_NONE = 0, - ETHTOOL_MSG_STRSET_GET = 1, - ETHTOOL_MSG_LINKINFO_GET = 2, - ETHTOOL_MSG_LINKINFO_SET = 3, - ETHTOOL_MSG_LINKMODES_GET = 4, - ETHTOOL_MSG_LINKMODES_SET = 5, - ETHTOOL_MSG_LINKSTATE_GET = 6, - ETHTOOL_MSG_DEBUG_GET = 7, - ETHTOOL_MSG_DEBUG_SET = 8, - ETHTOOL_MSG_WOL_GET = 9, - ETHTOOL_MSG_WOL_SET = 10, - ETHTOOL_MSG_FEATURES_GET = 11, - ETHTOOL_MSG_FEATURES_SET = 12, - ETHTOOL_MSG_PRIVFLAGS_GET = 13, - ETHTOOL_MSG_PRIVFLAGS_SET = 14, - ETHTOOL_MSG_RINGS_GET = 15, - ETHTOOL_MSG_RINGS_SET = 16, - ETHTOOL_MSG_CHANNELS_GET = 17, - ETHTOOL_MSG_CHANNELS_SET = 18, - ETHTOOL_MSG_COALESCE_GET = 19, - ETHTOOL_MSG_COALESCE_SET = 20, - ETHTOOL_MSG_PAUSE_GET = 21, - ETHTOOL_MSG_PAUSE_SET = 22, - ETHTOOL_MSG_EEE_GET = 23, - ETHTOOL_MSG_EEE_SET = 24, - ETHTOOL_MSG_TSINFO_GET = 25, - ETHTOOL_MSG_CABLE_TEST_ACT = 26, - ETHTOOL_MSG_CABLE_TEST_TDR_ACT = 27, - ETHTOOL_MSG_TUNNEL_INFO_GET = 28, - __ETHTOOL_MSG_USER_CNT = 29, - ETHTOOL_MSG_USER_MAX = 28, -}; - -enum { - ETHTOOL_A_HEADER_UNSPEC = 0, - ETHTOOL_A_HEADER_DEV_INDEX = 1, - ETHTOOL_A_HEADER_DEV_NAME = 2, - ETHTOOL_A_HEADER_FLAGS = 3, - __ETHTOOL_A_HEADER_CNT = 4, - ETHTOOL_A_HEADER_MAX = 3, -}; - -enum { - ETHTOOL_A_STRSET_UNSPEC = 0, - ETHTOOL_A_STRSET_HEADER = 1, - ETHTOOL_A_STRSET_STRINGSETS = 2, - ETHTOOL_A_STRSET_COUNTS_ONLY = 3, - __ETHTOOL_A_STRSET_CNT = 4, - ETHTOOL_A_STRSET_MAX = 3, -}; - -enum { - ETHTOOL_A_LINKINFO_UNSPEC = 0, - ETHTOOL_A_LINKINFO_HEADER = 1, - ETHTOOL_A_LINKINFO_PORT = 2, - ETHTOOL_A_LINKINFO_PHYADDR = 3, - ETHTOOL_A_LINKINFO_TP_MDIX = 4, - ETHTOOL_A_LINKINFO_TP_MDIX_CTRL = 5, - ETHTOOL_A_LINKINFO_TRANSCEIVER = 6, - __ETHTOOL_A_LINKINFO_CNT = 7, - ETHTOOL_A_LINKINFO_MAX = 6, -}; - -enum { - ETHTOOL_A_LINKMODES_UNSPEC = 0, - ETHTOOL_A_LINKMODES_HEADER = 1, - ETHTOOL_A_LINKMODES_AUTONEG = 2, - ETHTOOL_A_LINKMODES_OURS = 3, - ETHTOOL_A_LINKMODES_PEER = 4, - ETHTOOL_A_LINKMODES_SPEED = 5, - ETHTOOL_A_LINKMODES_DUPLEX = 6, - ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG = 7, - ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE = 8, - __ETHTOOL_A_LINKMODES_CNT = 9, - ETHTOOL_A_LINKMODES_MAX = 8, -}; - -enum { - ETHTOOL_A_LINKSTATE_UNSPEC = 0, - ETHTOOL_A_LINKSTATE_HEADER = 1, - ETHTOOL_A_LINKSTATE_LINK = 2, - ETHTOOL_A_LINKSTATE_SQI = 3, - ETHTOOL_A_LINKSTATE_SQI_MAX = 4, - ETHTOOL_A_LINKSTATE_EXT_STATE = 5, - ETHTOOL_A_LINKSTATE_EXT_SUBSTATE = 6, - __ETHTOOL_A_LINKSTATE_CNT = 7, - ETHTOOL_A_LINKSTATE_MAX = 6, -}; - -enum { - ETHTOOL_A_DEBUG_UNSPEC = 0, - ETHTOOL_A_DEBUG_HEADER = 1, - ETHTOOL_A_DEBUG_MSGMASK = 2, - __ETHTOOL_A_DEBUG_CNT = 3, - ETHTOOL_A_DEBUG_MAX = 2, -}; - -enum { - ETHTOOL_A_WOL_UNSPEC = 0, - ETHTOOL_A_WOL_HEADER = 1, - ETHTOOL_A_WOL_MODES = 2, - ETHTOOL_A_WOL_SOPASS = 3, - __ETHTOOL_A_WOL_CNT = 4, - ETHTOOL_A_WOL_MAX = 3, -}; - -enum { - ETHTOOL_A_FEATURES_UNSPEC = 0, - ETHTOOL_A_FEATURES_HEADER = 1, - ETHTOOL_A_FEATURES_HW = 2, - ETHTOOL_A_FEATURES_WANTED = 3, - ETHTOOL_A_FEATURES_ACTIVE = 4, - ETHTOOL_A_FEATURES_NOCHANGE = 5, - __ETHTOOL_A_FEATURES_CNT = 6, - ETHTOOL_A_FEATURES_MAX = 5, -}; - -enum { - ETHTOOL_A_PRIVFLAGS_UNSPEC = 0, - ETHTOOL_A_PRIVFLAGS_HEADER = 1, - ETHTOOL_A_PRIVFLAGS_FLAGS = 2, - __ETHTOOL_A_PRIVFLAGS_CNT = 3, - ETHTOOL_A_PRIVFLAGS_MAX = 2, -}; - -enum { - ETHTOOL_A_RINGS_UNSPEC = 0, - ETHTOOL_A_RINGS_HEADER = 1, - ETHTOOL_A_RINGS_RX_MAX = 2, - ETHTOOL_A_RINGS_RX_MINI_MAX = 3, - ETHTOOL_A_RINGS_RX_JUMBO_MAX = 4, - ETHTOOL_A_RINGS_TX_MAX = 5, - ETHTOOL_A_RINGS_RX = 6, - ETHTOOL_A_RINGS_RX_MINI = 7, - ETHTOOL_A_RINGS_RX_JUMBO = 8, - ETHTOOL_A_RINGS_TX = 9, - __ETHTOOL_A_RINGS_CNT = 10, - ETHTOOL_A_RINGS_MAX = 9, -}; - -enum { - ETHTOOL_A_CHANNELS_UNSPEC = 0, - ETHTOOL_A_CHANNELS_HEADER = 1, - ETHTOOL_A_CHANNELS_RX_MAX = 2, - ETHTOOL_A_CHANNELS_TX_MAX = 3, - ETHTOOL_A_CHANNELS_OTHER_MAX = 4, - ETHTOOL_A_CHANNELS_COMBINED_MAX = 5, - ETHTOOL_A_CHANNELS_RX_COUNT = 6, - ETHTOOL_A_CHANNELS_TX_COUNT = 7, - ETHTOOL_A_CHANNELS_OTHER_COUNT = 8, - ETHTOOL_A_CHANNELS_COMBINED_COUNT = 9, - __ETHTOOL_A_CHANNELS_CNT = 10, - ETHTOOL_A_CHANNELS_MAX = 9, -}; - -enum { - ETHTOOL_A_COALESCE_UNSPEC = 0, - ETHTOOL_A_COALESCE_HEADER = 1, - ETHTOOL_A_COALESCE_RX_USECS = 2, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES = 3, - ETHTOOL_A_COALESCE_RX_USECS_IRQ = 4, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ = 5, - ETHTOOL_A_COALESCE_TX_USECS = 6, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES = 7, - ETHTOOL_A_COALESCE_TX_USECS_IRQ = 8, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ = 9, - ETHTOOL_A_COALESCE_STATS_BLOCK_USECS = 10, - ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX = 11, - ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX = 12, - ETHTOOL_A_COALESCE_PKT_RATE_LOW = 13, - ETHTOOL_A_COALESCE_RX_USECS_LOW = 14, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW = 15, - ETHTOOL_A_COALESCE_TX_USECS_LOW = 16, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW = 17, - ETHTOOL_A_COALESCE_PKT_RATE_HIGH = 18, - ETHTOOL_A_COALESCE_RX_USECS_HIGH = 19, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH = 20, - ETHTOOL_A_COALESCE_TX_USECS_HIGH = 21, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH = 22, - ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 23, - __ETHTOOL_A_COALESCE_CNT = 24, - ETHTOOL_A_COALESCE_MAX = 23, -}; - -enum { - ETHTOOL_A_PAUSE_UNSPEC = 0, - ETHTOOL_A_PAUSE_HEADER = 1, - ETHTOOL_A_PAUSE_AUTONEG = 2, - ETHTOOL_A_PAUSE_RX = 3, - ETHTOOL_A_PAUSE_TX = 4, - ETHTOOL_A_PAUSE_STATS = 5, - __ETHTOOL_A_PAUSE_CNT = 6, - ETHTOOL_A_PAUSE_MAX = 5, -}; - -enum { - ETHTOOL_A_EEE_UNSPEC = 0, - ETHTOOL_A_EEE_HEADER = 1, - ETHTOOL_A_EEE_MODES_OURS = 2, - ETHTOOL_A_EEE_MODES_PEER = 3, - ETHTOOL_A_EEE_ACTIVE = 4, - ETHTOOL_A_EEE_ENABLED = 5, - ETHTOOL_A_EEE_TX_LPI_ENABLED = 6, - ETHTOOL_A_EEE_TX_LPI_TIMER = 7, - __ETHTOOL_A_EEE_CNT = 8, - ETHTOOL_A_EEE_MAX = 7, -}; - -enum { - ETHTOOL_A_TSINFO_UNSPEC = 0, - ETHTOOL_A_TSINFO_HEADER = 1, - ETHTOOL_A_TSINFO_TIMESTAMPING = 2, - ETHTOOL_A_TSINFO_TX_TYPES = 3, - ETHTOOL_A_TSINFO_RX_FILTERS = 4, - ETHTOOL_A_TSINFO_PHC_INDEX = 5, - __ETHTOOL_A_TSINFO_CNT = 6, - ETHTOOL_A_TSINFO_MAX = 5, -}; - -enum { - ETHTOOL_A_CABLE_TEST_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_HEADER = 1, - __ETHTOOL_A_CABLE_TEST_CNT = 2, - ETHTOOL_A_CABLE_TEST_MAX = 1, -}; - -enum { - ETHTOOL_A_CABLE_TEST_TDR_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_TDR_HEADER = 1, - ETHTOOL_A_CABLE_TEST_TDR_CFG = 2, - __ETHTOOL_A_CABLE_TEST_TDR_CNT = 3, - ETHTOOL_A_CABLE_TEST_TDR_MAX = 2, -}; - -enum { - ETHTOOL_A_TUNNEL_INFO_UNSPEC = 0, - ETHTOOL_A_TUNNEL_INFO_HEADER = 1, - ETHTOOL_A_TUNNEL_INFO_UDP_PORTS = 2, - __ETHTOOL_A_TUNNEL_INFO_CNT = 3, - ETHTOOL_A_TUNNEL_INFO_MAX = 2, -}; - -enum ethtool_multicast_groups { - ETHNL_MCGRP_MONITOR = 0, -}; - -struct ethnl_req_info { - struct net_device *dev; - u32 flags; -}; - -struct ethnl_reply_data { - struct net_device *dev; -}; - -struct ethnl_request_ops { - u8 request_cmd; - u8 reply_cmd; - u16 hdr_attr; - unsigned int req_info_size; - unsigned int reply_data_size; - bool allow_nodev_do; - int (*parse_request)(struct ethnl_req_info *, struct nlattr **, struct netlink_ext_ack *); - int (*prepare_data)(const struct ethnl_req_info *, struct ethnl_reply_data *, struct genl_info *); - int (*reply_size)(const struct ethnl_req_info *, const struct ethnl_reply_data *); - int (*fill_reply)(struct sk_buff *, const struct ethnl_req_info *, const struct ethnl_reply_data *); - void (*cleanup_data)(struct ethnl_reply_data *); -}; - -struct ethnl_dump_ctx { - const struct ethnl_request_ops *ops; - struct ethnl_req_info *req_info; - struct ethnl_reply_data *reply_data; - int pos_hash; - int pos_idx; -}; - -typedef void (*ethnl_notify_handler_t)(struct net_device *, unsigned int, const void *); - -enum { - ETHTOOL_A_BITSET_BIT_UNSPEC = 0, - ETHTOOL_A_BITSET_BIT_INDEX = 1, - ETHTOOL_A_BITSET_BIT_NAME = 2, - ETHTOOL_A_BITSET_BIT_VALUE = 3, - __ETHTOOL_A_BITSET_BIT_CNT = 4, - ETHTOOL_A_BITSET_BIT_MAX = 3, -}; - -enum { - ETHTOOL_A_BITSET_BITS_UNSPEC = 0, - ETHTOOL_A_BITSET_BITS_BIT = 1, - __ETHTOOL_A_BITSET_BITS_CNT = 2, - ETHTOOL_A_BITSET_BITS_MAX = 1, -}; - -enum { - ETHTOOL_A_BITSET_UNSPEC = 0, - ETHTOOL_A_BITSET_NOMASK = 1, - ETHTOOL_A_BITSET_SIZE = 2, - ETHTOOL_A_BITSET_BITS = 3, - ETHTOOL_A_BITSET_VALUE = 4, - ETHTOOL_A_BITSET_MASK = 5, - __ETHTOOL_A_BITSET_CNT = 6, - ETHTOOL_A_BITSET_MAX = 5, -}; - -typedef const char (* const ethnl_string_array_t)[32]; - -enum { - ETHTOOL_A_STRING_UNSPEC = 0, - ETHTOOL_A_STRING_INDEX = 1, - ETHTOOL_A_STRING_VALUE = 2, - __ETHTOOL_A_STRING_CNT = 3, - ETHTOOL_A_STRING_MAX = 2, -}; - -enum { - ETHTOOL_A_STRINGS_UNSPEC = 0, - ETHTOOL_A_STRINGS_STRING = 1, - __ETHTOOL_A_STRINGS_CNT = 2, - ETHTOOL_A_STRINGS_MAX = 1, -}; - -enum { - ETHTOOL_A_STRINGSET_UNSPEC = 0, - ETHTOOL_A_STRINGSET_ID = 1, - ETHTOOL_A_STRINGSET_COUNT = 2, - ETHTOOL_A_STRINGSET_STRINGS = 3, - __ETHTOOL_A_STRINGSET_CNT = 4, - ETHTOOL_A_STRINGSET_MAX = 3, -}; - -enum { - ETHTOOL_A_STRINGSETS_UNSPEC = 0, - ETHTOOL_A_STRINGSETS_STRINGSET = 1, - __ETHTOOL_A_STRINGSETS_CNT = 2, - ETHTOOL_A_STRINGSETS_MAX = 1, -}; - -struct strset_info { - bool per_dev; - bool free_strings; - unsigned int count; - const char (*strings)[32]; -}; - -struct strset_req_info { - struct ethnl_req_info base; - u32 req_ids; - bool counts_only; -}; - -struct strset_reply_data { - struct ethnl_reply_data base; - struct strset_info sets[16]; -}; - -struct linkinfo_reply_data { - struct ethnl_reply_data base; - struct ethtool_link_ksettings ksettings; - struct ethtool_link_settings *lsettings; -}; - -struct linkmodes_reply_data { - struct ethnl_reply_data base; - struct ethtool_link_ksettings ksettings; - struct ethtool_link_settings *lsettings; - bool peer_empty; -}; - -struct link_mode_info { - int speed; - u8 duplex; -}; - -struct linkstate_reply_data { - struct ethnl_reply_data base; - int link; - int sqi; - int sqi_max; - bool link_ext_state_provided; - struct ethtool_link_ext_state_info ethtool_link_ext_state_info; -}; - -struct debug_reply_data { - struct ethnl_reply_data base; - u32 msg_mask; -}; - -struct wol_reply_data { - struct ethnl_reply_data base; - struct ethtool_wolinfo wol; - bool show_sopass; -}; - -struct features_reply_data { - struct ethnl_reply_data base; - u32 hw[2]; - u32 wanted[2]; - u32 active[2]; - u32 nochange[2]; - u32 all[2]; -}; - -struct privflags_reply_data { - struct ethnl_reply_data base; - const char (*priv_flag_names)[32]; - unsigned int n_priv_flags; - u32 priv_flags; -}; - -struct rings_reply_data { - struct ethnl_reply_data base; - struct ethtool_ringparam ringparam; -}; - -struct channels_reply_data { - struct ethnl_reply_data base; - struct ethtool_channels channels; -}; - -struct coalesce_reply_data { - struct ethnl_reply_data base; - struct ethtool_coalesce coalesce; - u32 supported_params; -}; - -enum { - ETHTOOL_A_PAUSE_STAT_UNSPEC = 0, - ETHTOOL_A_PAUSE_STAT_PAD = 1, - ETHTOOL_A_PAUSE_STAT_TX_FRAMES = 2, - ETHTOOL_A_PAUSE_STAT_RX_FRAMES = 3, - __ETHTOOL_A_PAUSE_STAT_CNT = 4, - ETHTOOL_A_PAUSE_STAT_MAX = 3, -}; - -struct pause_reply_data { - struct ethnl_reply_data base; - struct ethtool_pauseparam pauseparam; - struct ethtool_pause_stats pausestat; -}; - -struct eee_reply_data { - struct ethnl_reply_data base; - struct ethtool_eee eee; -}; - -struct tsinfo_reply_data { - struct ethnl_reply_data base; - struct ethtool_ts_info ts_info; -}; - -enum { - ETHTOOL_A_CABLE_RESULT_UNSPEC = 0, - ETHTOOL_A_CABLE_RESULT_PAIR = 1, - ETHTOOL_A_CABLE_RESULT_CODE = 2, - __ETHTOOL_A_CABLE_RESULT_CNT = 3, - ETHTOOL_A_CABLE_RESULT_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC = 0, - ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR = 1, - ETHTOOL_A_CABLE_FAULT_LENGTH_CM = 2, - __ETHTOOL_A_CABLE_FAULT_LENGTH_CNT = 3, - ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_TEST_NTF_STATUS_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED = 1, - ETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED = 2, -}; - -enum { - ETHTOOL_A_CABLE_NEST_UNSPEC = 0, - ETHTOOL_A_CABLE_NEST_RESULT = 1, - ETHTOOL_A_CABLE_NEST_FAULT_LENGTH = 2, - __ETHTOOL_A_CABLE_NEST_CNT = 3, - ETHTOOL_A_CABLE_NEST_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_TEST_NTF_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_NTF_HEADER = 1, - ETHTOOL_A_CABLE_TEST_NTF_STATUS = 2, - ETHTOOL_A_CABLE_TEST_NTF_NEST = 3, - __ETHTOOL_A_CABLE_TEST_NTF_CNT = 4, - ETHTOOL_A_CABLE_TEST_NTF_MAX = 3, -}; - -enum { - ETHTOOL_A_CABLE_TEST_TDR_CFG_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST = 1, - ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST = 2, - ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP = 3, - ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR = 4, - __ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT = 5, - ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX = 4, -}; - -enum { - ETHTOOL_A_CABLE_AMPLITUDE_UNSPEC = 0, - ETHTOOL_A_CABLE_AMPLITUDE_PAIR = 1, - ETHTOOL_A_CABLE_AMPLITUDE_mV = 2, - __ETHTOOL_A_CABLE_AMPLITUDE_CNT = 3, - ETHTOOL_A_CABLE_AMPLITUDE_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_PULSE_UNSPEC = 0, - ETHTOOL_A_CABLE_PULSE_mV = 1, - __ETHTOOL_A_CABLE_PULSE_CNT = 2, - ETHTOOL_A_CABLE_PULSE_MAX = 1, -}; - -enum { - ETHTOOL_A_CABLE_STEP_UNSPEC = 0, - ETHTOOL_A_CABLE_STEP_FIRST_DISTANCE = 1, - ETHTOOL_A_CABLE_STEP_LAST_DISTANCE = 2, - ETHTOOL_A_CABLE_STEP_STEP_DISTANCE = 3, - __ETHTOOL_A_CABLE_STEP_CNT = 4, - ETHTOOL_A_CABLE_STEP_MAX = 3, -}; - -enum { - ETHTOOL_A_CABLE_TDR_NEST_UNSPEC = 0, - ETHTOOL_A_CABLE_TDR_NEST_STEP = 1, - ETHTOOL_A_CABLE_TDR_NEST_AMPLITUDE = 2, - ETHTOOL_A_CABLE_TDR_NEST_PULSE = 3, - __ETHTOOL_A_CABLE_TDR_NEST_CNT = 4, - ETHTOOL_A_CABLE_TDR_NEST_MAX = 3, -}; - -enum { - ETHTOOL_A_TUNNEL_UDP_ENTRY_UNSPEC = 0, - ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT = 1, - ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE = 2, - __ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT = 3, - ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX = 2, -}; - -enum { - ETHTOOL_A_TUNNEL_UDP_TABLE_UNSPEC = 0, - ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE = 1, - ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES = 2, - ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY = 3, - __ETHTOOL_A_TUNNEL_UDP_TABLE_CNT = 4, - ETHTOOL_A_TUNNEL_UDP_TABLE_MAX = 3, -}; - -enum { - ETHTOOL_A_TUNNEL_UDP_UNSPEC = 0, - ETHTOOL_A_TUNNEL_UDP_TABLE = 1, - __ETHTOOL_A_TUNNEL_UDP_CNT = 2, - ETHTOOL_A_TUNNEL_UDP_MAX = 1, -}; - -enum udp_parsable_tunnel_type { - UDP_TUNNEL_TYPE_VXLAN = 1, - UDP_TUNNEL_TYPE_GENEVE = 2, - UDP_TUNNEL_TYPE_VXLAN_GPE = 4, -}; - -enum udp_tunnel_nic_info_flags { - UDP_TUNNEL_NIC_INFO_MAY_SLEEP = 1, - UDP_TUNNEL_NIC_INFO_OPEN_ONLY = 2, - UDP_TUNNEL_NIC_INFO_IPV4_ONLY = 4, - UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN = 8, -}; - -struct udp_tunnel_nic_ops { - void (*get_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *); - void (*set_port_priv)(struct net_device *, unsigned int, unsigned int, u8); - void (*add_port)(struct net_device *, struct udp_tunnel_info *); - void (*del_port)(struct net_device *, struct udp_tunnel_info *); - void (*reset_ntf)(struct net_device *); - size_t (*dump_size)(struct net_device *, unsigned int); - int (*dump_write)(struct net_device *, unsigned int, struct sk_buff *); -}; - -struct ethnl_tunnel_info_dump_ctx { - struct ethnl_req_info req_info; - int pos_hash; - int pos_idx; -}; - -struct nf_hook_ops { - nf_hookfn *hook; - struct net_device *dev; - void *priv; - u_int8_t pf; - unsigned int hooknum; - int priority; -}; - -struct nf_hook_entries_rcu_head { - struct callback_head head; - void *allocation; -}; - -struct nf_conn___2; - -enum nf_nat_manip_type; - -struct nf_nat_hook { - int (*parse_nat_setup)(struct nf_conn___2 *, enum nf_nat_manip_type, const struct nlattr *); - void (*decode_session)(struct sk_buff *, struct flowi *); - unsigned int (*manip_pkt)(struct sk_buff *, struct nf_conn___2 *, enum nf_nat_manip_type, enum ip_conntrack_dir); -}; - -struct nf_conntrack_tuple___2; - -struct nf_ct_hook { - int (*update)(struct net *, struct sk_buff *); - void (*destroy)(struct nf_conntrack *); - bool (*get_tuple_skb)(struct nf_conntrack_tuple___2 *, const struct sk_buff *); -}; - -struct nfnl_ct_hook { - struct nf_conn___2 * (*get_ct)(const struct sk_buff *, enum ip_conntrack_info *); - size_t (*build_size)(const struct nf_conn___2 *); - int (*build)(struct sk_buff *, struct nf_conn___2 *, enum ip_conntrack_info, u_int16_t, u_int16_t); - int (*parse)(const struct nlattr *, struct nf_conn___2 *); - int (*attach_expect)(const struct nlattr *, struct nf_conn___2 *, u32, u32); - void (*seq_adjust)(struct sk_buff *, struct nf_conn___2 *, enum ip_conntrack_info, s32); -}; - -struct nf_bridge_frag_data; - -struct nf_ipv6_ops { - int (*chk_addr)(struct net *, const struct in6_addr *, const struct net_device *, int); - int (*route_me_harder)(struct net *, struct sock *, struct sk_buff *); - int (*dev_get_saddr)(struct net *, const struct net_device *, const struct in6_addr *, unsigned int, struct in6_addr *); - int (*route)(struct net *, struct dst_entry **, struct flowi *, bool); - u32 (*cookie_init_sequence)(const struct ipv6hdr *, const struct tcphdr *, u16 *); - int (*cookie_v6_check)(const struct ipv6hdr *, const struct tcphdr *, __u32); - void (*route_input)(struct sk_buff *); - int (*fragment)(struct net *, struct sock *, struct sk_buff *, int (*)(struct net *, struct sock *, struct sk_buff *)); - int (*reroute)(struct sk_buff *, const struct nf_queue_entry *); - int (*br_fragment)(struct net *, struct sock *, struct sk_buff *, struct nf_bridge_frag_data *, int (*)(struct net *, struct sock *, const struct nf_bridge_frag_data *, struct sk_buff *)); -}; - -struct nf_queue_entry { - struct list_head list; - struct sk_buff *skb; - unsigned int id; - unsigned int hook_index; - struct net_device *physin; - struct net_device *physout; - struct nf_hook_state state; - u16 size; -}; - -struct nf_loginfo { - u_int8_t type; - union { - struct { - u_int32_t copy_len; - u_int16_t group; - u_int16_t qthreshold; - u_int16_t flags; - } ulog; - struct { - u_int8_t level; - u_int8_t logflags; - } log; - } u; -}; - -struct nf_log_buf { - unsigned int count; - char buf[1020]; -}; - -struct nf_bridge_info { - enum { - BRNF_PROTO_UNCHANGED = 0, - BRNF_PROTO_8021Q = 1, - BRNF_PROTO_PPPOE = 2, - } orig_proto: 8; - u8 pkt_otherhost: 1; - u8 in_prerouting: 1; - u8 bridged_dnat: 1; - __u16 frag_max_size; - struct net_device *physindev; - struct net_device *physoutdev; - union { - __be32 ipv4_daddr; - struct in6_addr ipv6_daddr; - char neigh_header[8]; - }; -}; - -struct ip_rt_info { - __be32 daddr; - __be32 saddr; - u_int8_t tos; - u_int32_t mark; -}; - -struct ip6_rt_info { - struct in6_addr daddr; - struct in6_addr saddr; - u_int32_t mark; -}; - -struct nf_sockopt_ops { - struct list_head list; - u_int8_t pf; - int set_optmin; - int set_optmax; - int (*set)(struct sock *, int, sockptr_t, unsigned int); - int get_optmin; - int get_optmax; - int (*get)(struct sock *, int, void *, int *); - struct module *owner; -}; - -struct ip_mreqn { - struct in_addr imr_multiaddr; - struct in_addr imr_address; - int imr_ifindex; -}; - -struct rtmsg { - unsigned char rtm_family; - unsigned char rtm_dst_len; - unsigned char rtm_src_len; - unsigned char rtm_tos; - unsigned char rtm_table; - unsigned char rtm_protocol; - unsigned char rtm_scope; - unsigned char rtm_type; - unsigned int rtm_flags; -}; - -struct rtvia { - __kernel_sa_family_t rtvia_family; - __u8 rtvia_addr[0]; -}; - -struct ip_sf_list; - -struct ip_mc_list { - struct in_device *interface; - __be32 multiaddr; - unsigned int sfmode; - struct ip_sf_list *sources; - struct ip_sf_list *tomb; - long unsigned int sfcount[2]; - union { - struct ip_mc_list *next; - struct ip_mc_list *next_rcu; - }; - struct ip_mc_list *next_hash; - struct timer_list timer; - int users; - refcount_t refcnt; - spinlock_t lock; - char tm_running; - char reporter; - char unsolicit_count; - char loaded; - unsigned char gsquery; - unsigned char crcount; - struct callback_head rcu; -}; - -struct ip_sf_socklist { - unsigned int sl_max; - unsigned int sl_count; - struct callback_head rcu; - __be32 sl_addr[0]; -}; - -struct ip_mc_socklist { - struct ip_mc_socklist *next_rcu; - struct ip_mreqn multi; - unsigned int sfmode; - struct ip_sf_socklist *sflist; - struct callback_head rcu; -}; - -struct ip_sf_list { - struct ip_sf_list *sf_next; - long unsigned int sf_count[2]; - __be32 sf_inaddr; - unsigned char sf_gsresp; - unsigned char sf_oldin; - unsigned char sf_crcount; -}; - -struct ipv4_addr_key { - __be32 addr; - int vif; -}; - -struct inetpeer_addr { - union { - struct ipv4_addr_key a4; - struct in6_addr a6; - u32 key[4]; - }; - __u16 family; -}; - -struct inet_peer { - struct rb_node rb_node; - struct inetpeer_addr daddr; - u32 metrics[17]; - u32 rate_tokens; - u32 n_redirects; - long unsigned int rate_last; - union { - struct { - atomic_t rid; - }; - struct callback_head rcu; - }; - __u32 dtime; - refcount_t refcnt; -}; - -struct fib_rt_info { - struct fib_info *fi; - u32 tb_id; - __be32 dst; - int dst_len; - u8 tos; - u8 type; - u8 offload: 1; - u8 trap: 1; - u8 unused: 6; -}; - -struct uncached_list { - spinlock_t lock; - struct list_head head; -}; - -struct ip_rt_acct { - __u32 o_bytes; - __u32 o_packets; - __u32 i_bytes; - __u32 i_packets; -}; - -struct rt_cache_stat { - unsigned int in_slow_tot; - unsigned int in_slow_mc; - unsigned int in_no_route; - unsigned int in_brd; - unsigned int in_martian_dst; - unsigned int in_martian_src; - unsigned int out_slow_tot; - unsigned int out_slow_mc; -}; - -struct fib_alias { - struct hlist_node fa_list; - struct fib_info *fa_info; - u8 fa_tos; - u8 fa_type; - u8 fa_state; - u8 fa_slen; - u32 tb_id; - s16 fa_default; - u8 offload: 1; - u8 trap: 1; - u8 unused: 6; - struct callback_head rcu; -}; - -struct fib_prop { - int error; - u8 scope; -}; - -struct net_offload { - struct offload_callbacks callbacks; - unsigned int flags; -}; - -struct raw_hashinfo { - rwlock_t lock; - struct hlist_head ht[256]; -}; - -enum ip_defrag_users { - IP_DEFRAG_LOCAL_DELIVER = 0, - IP_DEFRAG_CALL_RA_CHAIN = 1, - IP_DEFRAG_CONNTRACK_IN = 2, - __IP_DEFRAG_CONNTRACK_IN_END = 65537, - IP_DEFRAG_CONNTRACK_OUT = 65538, - __IP_DEFRAG_CONNTRACK_OUT_END = 131073, - IP_DEFRAG_CONNTRACK_BRIDGE_IN = 131074, - __IP_DEFRAG_CONNTRACK_BRIDGE_IN = 196609, - IP_DEFRAG_VS_IN = 196610, - IP_DEFRAG_VS_OUT = 196611, - IP_DEFRAG_VS_FWD = 196612, - IP_DEFRAG_AF_PACKET = 196613, - IP_DEFRAG_MACVLAN = 196614, -}; - -enum { - INET_FRAG_FIRST_IN = 1, - INET_FRAG_LAST_IN = 2, - INET_FRAG_COMPLETE = 4, - INET_FRAG_HASH_DEAD = 8, -}; - -struct ipq { - struct inet_frag_queue q; - u8 ecn; - u16 max_df_size; - int iif; - unsigned int rid; - struct inet_peer *peer; -}; - -struct ip_options_data { - struct ip_options_rcu opt; - char data[40]; -}; - -struct ipcm_cookie { - struct sockcm_cookie sockc; - __be32 addr; - int oif; - struct ip_options_rcu *opt; - __u8 ttl; - __s16 tos; - char priority; - __u16 gso_size; -}; - -struct ip_fraglist_iter { - struct sk_buff *frag; - struct iphdr *iph; - int offset; - unsigned int hlen; -}; - -struct ip_frag_state { - bool DF; - unsigned int hlen; - unsigned int ll_rs; - unsigned int mtu; - unsigned int left; - int offset; - int ptr; - __be16 not_last_frag; -}; - -struct ip_reply_arg { - struct kvec iov[1]; - int flags; - __wsum csum; - int csumoffset; - int bound_dev_if; - u8 tos; - kuid_t uid; -}; - -struct ip_mreq_source { - __be32 imr_multiaddr; - __be32 imr_interface; - __be32 imr_sourceaddr; -}; - -struct ip_msfilter { - __be32 imsf_multiaddr; - __be32 imsf_interface; - __u32 imsf_fmode; - __u32 imsf_numsrc; - __be32 imsf_slist[1]; -}; - -struct group_req { - __u32 gr_interface; - struct __kernel_sockaddr_storage gr_group; -}; - -struct group_source_req { - __u32 gsr_interface; - struct __kernel_sockaddr_storage gsr_group; - struct __kernel_sockaddr_storage gsr_source; -}; - -struct group_filter { - __u32 gf_interface; - struct __kernel_sockaddr_storage gf_group; - __u32 gf_fmode; - __u32 gf_numsrc; - struct __kernel_sockaddr_storage gf_slist[1]; -}; - -struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; -}; - -struct compat_group_req { - __u32 gr_interface; - struct __kernel_sockaddr_storage gr_group; -} __attribute__((packed)); - -struct compat_group_source_req { - __u32 gsr_interface; - struct __kernel_sockaddr_storage gsr_group; - struct __kernel_sockaddr_storage gsr_source; -} __attribute__((packed)); - -struct compat_group_filter { - __u32 gf_interface; - struct __kernel_sockaddr_storage gf_group; - __u32 gf_fmode; - __u32 gf_numsrc; - struct __kernel_sockaddr_storage gf_slist[1]; -} __attribute__((packed)); - -struct tcpvegas_info { - __u32 tcpv_enabled; - __u32 tcpv_rttcnt; - __u32 tcpv_rtt; - __u32 tcpv_minrtt; -}; - -struct tcp_dctcp_info { - __u16 dctcp_enabled; - __u16 dctcp_ce_state; - __u32 dctcp_alpha; - __u32 dctcp_ab_ecn; - __u32 dctcp_ab_tot; -}; - -struct tcp_bbr_info { - __u32 bbr_bw_lo; - __u32 bbr_bw_hi; - __u32 bbr_min_rtt; - __u32 bbr_pacing_gain; - __u32 bbr_cwnd_gain; -}; - -union tcp_cc_info { - struct tcpvegas_info vegas; - struct tcp_dctcp_info dctcp; - struct tcp_bbr_info bbr; -}; - -enum { - BPF_TCP_ESTABLISHED = 1, - BPF_TCP_SYN_SENT = 2, - BPF_TCP_SYN_RECV = 3, - BPF_TCP_FIN_WAIT1 = 4, - BPF_TCP_FIN_WAIT2 = 5, - BPF_TCP_TIME_WAIT = 6, - BPF_TCP_CLOSE = 7, - BPF_TCP_CLOSE_WAIT = 8, - BPF_TCP_LAST_ACK = 9, - BPF_TCP_LISTEN = 10, - BPF_TCP_CLOSING = 11, - BPF_TCP_NEW_SYN_RECV = 12, - BPF_TCP_MAX_STATES = 13, -}; - -enum inet_csk_ack_state_t { - ICSK_ACK_SCHED = 1, - ICSK_ACK_TIMER = 2, - ICSK_ACK_PUSHED = 4, - ICSK_ACK_PUSHED2 = 8, - ICSK_ACK_NOW = 16, -}; - -enum { - TCP_FLAG_CWR = 32768, - TCP_FLAG_ECE = 16384, - TCP_FLAG_URG = 8192, - TCP_FLAG_ACK = 4096, - TCP_FLAG_PSH = 2048, - TCP_FLAG_RST = 1024, - TCP_FLAG_SYN = 512, - TCP_FLAG_FIN = 256, - TCP_RESERVED_BITS = 15, - TCP_DATA_OFFSET = 240, -}; - -struct tcp_repair_opt { - __u32 opt_code; - __u32 opt_val; -}; - -struct tcp_repair_window { - __u32 snd_wl1; - __u32 snd_wnd; - __u32 max_window; - __u32 rcv_wnd; - __u32 rcv_wup; -}; - -enum { - TCP_NO_QUEUE = 0, - TCP_RECV_QUEUE = 1, - TCP_SEND_QUEUE = 2, - TCP_QUEUES_NR = 3, -}; - -struct tcp_info { - __u8 tcpi_state; - __u8 tcpi_ca_state; - __u8 tcpi_retransmits; - __u8 tcpi_probes; - __u8 tcpi_backoff; - __u8 tcpi_options; - __u8 tcpi_snd_wscale: 4; - __u8 tcpi_rcv_wscale: 4; - __u8 tcpi_delivery_rate_app_limited: 1; - __u8 tcpi_fastopen_client_fail: 2; - __u32 tcpi_rto; - __u32 tcpi_ato; - __u32 tcpi_snd_mss; - __u32 tcpi_rcv_mss; - __u32 tcpi_unacked; - __u32 tcpi_sacked; - __u32 tcpi_lost; - __u32 tcpi_retrans; - __u32 tcpi_fackets; - __u32 tcpi_last_data_sent; - __u32 tcpi_last_ack_sent; - __u32 tcpi_last_data_recv; - __u32 tcpi_last_ack_recv; - __u32 tcpi_pmtu; - __u32 tcpi_rcv_ssthresh; - __u32 tcpi_rtt; - __u32 tcpi_rttvar; - __u32 tcpi_snd_ssthresh; - __u32 tcpi_snd_cwnd; - __u32 tcpi_advmss; - __u32 tcpi_reordering; - __u32 tcpi_rcv_rtt; - __u32 tcpi_rcv_space; - __u32 tcpi_total_retrans; - __u64 tcpi_pacing_rate; - __u64 tcpi_max_pacing_rate; - __u64 tcpi_bytes_acked; - __u64 tcpi_bytes_received; - __u32 tcpi_segs_out; - __u32 tcpi_segs_in; - __u32 tcpi_notsent_bytes; - __u32 tcpi_min_rtt; - __u32 tcpi_data_segs_in; - __u32 tcpi_data_segs_out; - __u64 tcpi_delivery_rate; - __u64 tcpi_busy_time; - __u64 tcpi_rwnd_limited; - __u64 tcpi_sndbuf_limited; - __u32 tcpi_delivered; - __u32 tcpi_delivered_ce; - __u64 tcpi_bytes_sent; - __u64 tcpi_bytes_retrans; - __u32 tcpi_dsack_dups; - __u32 tcpi_reord_seen; - __u32 tcpi_rcv_ooopack; - __u32 tcpi_snd_wnd; -}; - -enum { - TCP_NLA_PAD = 0, - TCP_NLA_BUSY = 1, - TCP_NLA_RWND_LIMITED = 2, - TCP_NLA_SNDBUF_LIMITED = 3, - TCP_NLA_DATA_SEGS_OUT = 4, - TCP_NLA_TOTAL_RETRANS = 5, - TCP_NLA_PACING_RATE = 6, - TCP_NLA_DELIVERY_RATE = 7, - TCP_NLA_SND_CWND = 8, - TCP_NLA_REORDERING = 9, - TCP_NLA_MIN_RTT = 10, - TCP_NLA_RECUR_RETRANS = 11, - TCP_NLA_DELIVERY_RATE_APP_LMT = 12, - TCP_NLA_SNDQ_SIZE = 13, - TCP_NLA_CA_STATE = 14, - TCP_NLA_SND_SSTHRESH = 15, - TCP_NLA_DELIVERED = 16, - TCP_NLA_DELIVERED_CE = 17, - TCP_NLA_BYTES_SENT = 18, - TCP_NLA_BYTES_RETRANS = 19, - TCP_NLA_DSACK_DUPS = 20, - TCP_NLA_REORD_SEEN = 21, - TCP_NLA_SRTT = 22, - TCP_NLA_TIMEOUT_REHASH = 23, - TCP_NLA_BYTES_NOTSENT = 24, - TCP_NLA_EDT = 25, -}; - -struct tcp_zerocopy_receive { - __u64 address; - __u32 length; - __u32 recv_skip_hint; - __u32 inq; - __s32 err; - __u64 copybuf_address; - __s32 copybuf_len; -}; - -enum tcp_chrono { - TCP_CHRONO_UNSPEC = 0, - TCP_CHRONO_BUSY = 1, - TCP_CHRONO_RWND_LIMITED = 2, - TCP_CHRONO_SNDBUF_LIMITED = 3, - __TCP_CHRONO_MAX = 4, -}; - -struct tcp_splice_state { - struct pipe_inode_info *pipe; - size_t len; - unsigned int flags; -}; - -enum tcp_fastopen_client_fail { - TFO_STATUS_UNSPEC = 0, - TFO_COOKIE_UNAVAILABLE = 1, - TFO_DATA_NOT_ACKED = 2, - TFO_SYN_RETRANSMITTED = 3, -}; - -struct tcp_sack_block_wire { - __be32 start_seq; - __be32 end_seq; -}; - -enum tcp_queue { - TCP_FRAG_IN_WRITE_QUEUE = 0, - TCP_FRAG_IN_RTX_QUEUE = 1, -}; - -enum tcp_ca_ack_event_flags { - CA_ACK_SLOWPATH = 1, - CA_ACK_WIN_UPDATE = 2, - CA_ACK_ECE = 4, -}; - -struct tcp_sacktag_state { - u64 first_sackt; - u64 last_sackt; - u32 reord; - u32 sack_delivered; - int flag; - unsigned int mss_now; - struct rate_sample *rate; -}; - -enum pkt_hash_types { - PKT_HASH_TYPE_NONE = 0, - PKT_HASH_TYPE_L2 = 1, - PKT_HASH_TYPE_L3 = 2, - PKT_HASH_TYPE_L4 = 3, -}; - -enum { - BPF_WRITE_HDR_TCP_CURRENT_MSS = 1, - BPF_WRITE_HDR_TCP_SYNACK_COOKIE = 2, -}; - -enum tsq_flags { - TSQF_THROTTLED = 1, - TSQF_QUEUED = 2, - TCPF_TSQ_DEFERRED = 4, - TCPF_WRITE_TIMER_DEFERRED = 8, - TCPF_DELACK_TIMER_DEFERRED = 16, - TCPF_MTU_REDUCED_DEFERRED = 32, -}; - -struct mptcp_out_options {}; - -union tcp_md5_addr { - struct in_addr a4; - struct in6_addr a6; -}; - -struct tcp_md5sig_key { - struct hlist_node node; - u8 keylen; - u8 family; - u8 prefixlen; - union tcp_md5_addr addr; - int l3index; - u8 key[80]; - struct callback_head rcu; -}; - -struct tcp_out_options { - u16 options; - u16 mss; - u8 ws; - u8 num_sack_blocks; - u8 hash_size; - u8 bpf_opt_len; - __u8 *hash_location; - __u32 tsval; - __u32 tsecr; - struct tcp_fastopen_cookie *fastopen_cookie; - struct mptcp_out_options mptcp; -}; - -struct tsq_tasklet { - struct tasklet_struct tasklet; - struct list_head head; -}; - -struct icmp_err { - int errno; - unsigned int fatal: 1; -}; - -enum tcp_tw_status { - TCP_TW_SUCCESS = 0, - TCP_TW_RST = 1, - TCP_TW_ACK = 2, - TCP_TW_SYN = 3, -}; - -enum tcp_seq_states { - TCP_SEQ_STATE_LISTENING = 0, - TCP_SEQ_STATE_ESTABLISHED = 1, -}; - -struct tcp_seq_afinfo { - sa_family_t family; -}; - -struct tcp_iter_state { - struct seq_net_private p; - enum tcp_seq_states state; - struct sock *syn_wait_sk; - struct tcp_seq_afinfo *bpf_seq_afinfo; - int bucket; - int offset; - int sbucket; - int num; - loff_t last_pos; -}; - -struct bpf_iter__tcp { - union { - struct bpf_iter_meta *meta; - }; - union { - struct sock_common *sk_common; - }; - uid_t uid; -}; - -enum tcp_metric_index { - TCP_METRIC_RTT = 0, - TCP_METRIC_RTTVAR = 1, - TCP_METRIC_SSTHRESH = 2, - TCP_METRIC_CWND = 3, - TCP_METRIC_REORDERING = 4, - TCP_METRIC_RTT_US = 5, - TCP_METRIC_RTTVAR_US = 6, - __TCP_METRIC_MAX = 7, -}; - -enum { - TCP_METRICS_ATTR_UNSPEC = 0, - TCP_METRICS_ATTR_ADDR_IPV4 = 1, - TCP_METRICS_ATTR_ADDR_IPV6 = 2, - TCP_METRICS_ATTR_AGE = 3, - TCP_METRICS_ATTR_TW_TSVAL = 4, - TCP_METRICS_ATTR_TW_TS_STAMP = 5, - TCP_METRICS_ATTR_VALS = 6, - TCP_METRICS_ATTR_FOPEN_MSS = 7, - TCP_METRICS_ATTR_FOPEN_SYN_DROPS = 8, - TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS = 9, - TCP_METRICS_ATTR_FOPEN_COOKIE = 10, - TCP_METRICS_ATTR_SADDR_IPV4 = 11, - TCP_METRICS_ATTR_SADDR_IPV6 = 12, - TCP_METRICS_ATTR_PAD = 13, - __TCP_METRICS_ATTR_MAX = 14, -}; - -enum { - TCP_METRICS_CMD_UNSPEC = 0, - TCP_METRICS_CMD_GET = 1, - TCP_METRICS_CMD_DEL = 2, - __TCP_METRICS_CMD_MAX = 3, -}; - -struct tcp_fastopen_metrics { - u16 mss; - u16 syn_loss: 10; - u16 try_exp: 2; - long unsigned int last_syn_loss; - struct tcp_fastopen_cookie cookie; -}; - -struct tcp_metrics_block { - struct tcp_metrics_block *tcpm_next; - possible_net_t tcpm_net; - struct inetpeer_addr tcpm_saddr; - struct inetpeer_addr tcpm_daddr; - long unsigned int tcpm_stamp; - u32 tcpm_lock; - u32 tcpm_vals[5]; - struct tcp_fastopen_metrics tcpm_fastopen; - struct callback_head callback_head; -}; - -struct tcpm_hash_bucket { - struct tcp_metrics_block *chain; -}; - -struct icmp_filter { - __u32 data; -}; - -struct raw_iter_state { - struct seq_net_private p; - int bucket; -}; - -struct raw_sock { - struct inet_sock inet; - struct icmp_filter filter; - u32 ipmr_table; -}; - -struct raw_frag_vec { - struct msghdr *msg; - union { - struct icmphdr icmph; - char c[1]; - } hdr; - int hlen; -}; - -struct ip_tunnel_encap { - u16 type; - u16 flags; - __be16 sport; - __be16 dport; -}; - -struct ip_tunnel_encap_ops { - size_t (*encap_hlen)(struct ip_tunnel_encap *); - int (*build_header)(struct sk_buff *, struct ip_tunnel_encap *, u8 *, struct flowi4 *); - int (*err_handler)(struct sk_buff *, u32); -}; - -struct udp_skb_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - __u16 cscov; - __u8 partial_cov; -}; - -struct udp_dev_scratch { - u32 _tsize_state; - u16 len; - bool is_linear; - bool csum_unnecessary; -}; - -struct udp_seq_afinfo { - sa_family_t family; - struct udp_table *udp_table; -}; - -struct udp_iter_state { - struct seq_net_private p; - int bucket; - struct udp_seq_afinfo *bpf_seq_afinfo; -}; - -struct bpf_iter__udp { - union { - struct bpf_iter_meta *meta; - }; - union { - struct udp_sock *udp_sk; - }; - uid_t uid; - int: 32; - int bucket; -}; - -struct inet_protosw { - struct list_head list; - short unsigned int type; - short unsigned int protocol; - struct proto *prot; - const struct proto_ops *ops; - unsigned char flags; -}; - -typedef struct sk_buff * (*gro_receive_sk_t)(struct sock *, struct list_head *, struct sk_buff *); - -typedef struct sock * (*udp_lookup_t)(struct sk_buff *, __be16, __be16); - -struct arpreq { - struct sockaddr arp_pa; - struct sockaddr arp_ha; - int arp_flags; - struct sockaddr arp_netmask; - char arp_dev[16]; -}; - -enum { - AX25_VALUES_IPDEFMODE = 0, - AX25_VALUES_AXDEFMODE = 1, - AX25_VALUES_BACKOFF = 2, - AX25_VALUES_CONMODE = 3, - AX25_VALUES_WINDOW = 4, - AX25_VALUES_EWINDOW = 5, - AX25_VALUES_T1 = 6, - AX25_VALUES_T2 = 7, - AX25_VALUES_T3 = 8, - AX25_VALUES_IDLE = 9, - AX25_VALUES_N2 = 10, - AX25_VALUES_PACLEN = 11, - AX25_VALUES_PROTOCOL = 12, - AX25_VALUES_DS_TIMEOUT = 13, - AX25_MAX_VALUES = 14, -}; - -enum ip_conntrack_status { - IPS_EXPECTED_BIT = 0, - IPS_EXPECTED = 1, - IPS_SEEN_REPLY_BIT = 1, - IPS_SEEN_REPLY = 2, - IPS_ASSURED_BIT = 2, - IPS_ASSURED = 4, - IPS_CONFIRMED_BIT = 3, - IPS_CONFIRMED = 8, - IPS_SRC_NAT_BIT = 4, - IPS_SRC_NAT = 16, - IPS_DST_NAT_BIT = 5, - IPS_DST_NAT = 32, - IPS_NAT_MASK = 48, - IPS_SEQ_ADJUST_BIT = 6, - IPS_SEQ_ADJUST = 64, - IPS_SRC_NAT_DONE_BIT = 7, - IPS_SRC_NAT_DONE = 128, - IPS_DST_NAT_DONE_BIT = 8, - IPS_DST_NAT_DONE = 256, - IPS_NAT_DONE_MASK = 384, - IPS_DYING_BIT = 9, - IPS_DYING = 512, - IPS_FIXED_TIMEOUT_BIT = 10, - IPS_FIXED_TIMEOUT = 1024, - IPS_TEMPLATE_BIT = 11, - IPS_TEMPLATE = 2048, - IPS_UNTRACKED_BIT = 12, - IPS_UNTRACKED = 4096, - IPS_NAT_CLASH_BIT = 12, - IPS_NAT_CLASH = 4096, - IPS_HELPER_BIT = 13, - IPS_HELPER = 8192, - IPS_OFFLOAD_BIT = 14, - IPS_OFFLOAD = 16384, - IPS_HW_OFFLOAD_BIT = 15, - IPS_HW_OFFLOAD = 32768, - IPS_UNCHANGEABLE_MASK = 56313, - __IPS_MAX_BIT = 16, -}; - -enum { - XFRM_LOOKUP_ICMP = 1, - XFRM_LOOKUP_QUEUE = 2, - XFRM_LOOKUP_KEEP_DST_REF = 4, -}; - -struct icmp_ext_hdr { - __u8 reserved1: 4; - __u8 version: 4; - __u8 reserved2; - __sum16 checksum; -}; - -struct icmp_extobj_hdr { - __be16 length; - __u8 class_num; - __u8 class_type; -}; - -struct icmp_bxm { - struct sk_buff *skb; - int offset; - int data_len; - struct { - struct icmphdr icmph; - __be32 times[3]; - } data; - int head_len; - struct ip_options_data replyopts; -}; - -struct icmp_control { - bool (*handler)(struct sk_buff *); - short int error; -}; - -struct ifaddrmsg { - __u8 ifa_family; - __u8 ifa_prefixlen; - __u8 ifa_flags; - __u8 ifa_scope; - __u32 ifa_index; -}; - -enum { - IFA_UNSPEC = 0, - IFA_ADDRESS = 1, - IFA_LOCAL = 2, - IFA_LABEL = 3, - IFA_BROADCAST = 4, - IFA_ANYCAST = 5, - IFA_CACHEINFO = 6, - IFA_MULTICAST = 7, - IFA_FLAGS = 8, - IFA_RT_PRIORITY = 9, - IFA_TARGET_NETNSID = 10, - __IFA_MAX = 11, -}; - -struct ifa_cacheinfo { - __u32 ifa_prefered; - __u32 ifa_valid; - __u32 cstamp; - __u32 tstamp; -}; - -enum { - IFLA_INET_UNSPEC = 0, - IFLA_INET_CONF = 1, - __IFLA_INET_MAX = 2, -}; - -struct in_validator_info { - __be32 ivi_addr; - struct in_device *ivi_dev; - struct netlink_ext_ack *extack; -}; - -struct netconfmsg { - __u8 ncm_family; -}; - -enum { - NETCONFA_UNSPEC = 0, - NETCONFA_IFINDEX = 1, - NETCONFA_FORWARDING = 2, - NETCONFA_RP_FILTER = 3, - NETCONFA_MC_FORWARDING = 4, - NETCONFA_PROXY_NEIGH = 5, - NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN = 6, - NETCONFA_INPUT = 7, - NETCONFA_BC_FORWARDING = 8, - __NETCONFA_MAX = 9, -}; - -struct inet_fill_args { - u32 portid; - u32 seq; - int event; - unsigned int flags; - int netnsid; - int ifindex; -}; - -struct devinet_sysctl_table { - struct ctl_table_header *sysctl_header; - struct ctl_table devinet_vars[33]; -}; - -struct rtentry { - long unsigned int rt_pad1; - struct sockaddr rt_dst; - struct sockaddr rt_gateway; - struct sockaddr rt_genmask; - short unsigned int rt_flags; - short int rt_pad2; - long unsigned int rt_pad3; - void *rt_pad4; - short int rt_metric; - char *rt_dev; - long unsigned int rt_mtu; - long unsigned int rt_window; - short unsigned int rt_irtt; -}; - -struct pingv6_ops { - int (*ipv6_recv_error)(struct sock *, struct msghdr *, int, int *); - void (*ip6_datagram_recv_common_ctl)(struct sock *, struct msghdr *, struct sk_buff *); - void (*ip6_datagram_recv_specific_ctl)(struct sock *, struct msghdr *, struct sk_buff *); - int (*icmpv6_err_convert)(u8, u8, int *); - void (*ipv6_icmp_error)(struct sock *, struct sk_buff *, int, __be16, u32, u8 *); - int (*ipv6_chk_addr)(struct net *, const struct in6_addr *, const struct net_device *, int); -}; - -struct compat_rtentry { - u32 rt_pad1; - struct sockaddr rt_dst; - struct sockaddr rt_gateway; - struct sockaddr rt_genmask; - short unsigned int rt_flags; - short int rt_pad2; - u32 rt_pad3; - unsigned char rt_tos; - unsigned char rt_class; - short int rt_pad4; - short int rt_metric; - compat_uptr_t rt_dev; - u32 rt_mtu; - u32 rt_window; - short unsigned int rt_irtt; -}; - -struct igmphdr { - __u8 type; - __u8 code; - __sum16 csum; - __be32 group; -}; - -struct igmpv3_grec { - __u8 grec_type; - __u8 grec_auxwords; - __be16 grec_nsrcs; - __be32 grec_mca; - __be32 grec_src[0]; -}; - -struct igmpv3_report { - __u8 type; - __u8 resv1; - __sum16 csum; - __be16 resv2; - __be16 ngrec; - struct igmpv3_grec grec[0]; -}; - -struct igmpv3_query { - __u8 type; - __u8 code; - __sum16 csum; - __be32 group; - __u8 qrv: 3; - __u8 suppress: 1; - __u8 resv: 4; - __u8 qqic; - __be16 nsrcs; - __be32 srcs[0]; -}; - -struct igmp_mc_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct in_device *in_dev; -}; - -struct igmp_mcf_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct in_device *idev; - struct ip_mc_list *im; -}; - -struct fib_config { - u8 fc_dst_len; - u8 fc_tos; - u8 fc_protocol; - u8 fc_scope; - u8 fc_type; - u8 fc_gw_family; - u32 fc_table; - __be32 fc_dst; - union { - __be32 fc_gw4; - struct in6_addr fc_gw6; - }; - int fc_oif; - u32 fc_flags; - u32 fc_priority; - __be32 fc_prefsrc; - u32 fc_nh_id; - struct nlattr *fc_mx; - struct rtnexthop *fc_mp; - int fc_mx_len; - int fc_mp_len; - u32 fc_flow; - u32 fc_nlflags; - struct nl_info fc_nlinfo; - struct nlattr *fc_encap; - u16 fc_encap_type; -}; - -struct fib_result_nl { - __be32 fl_addr; - u32 fl_mark; - unsigned char fl_tos; - unsigned char fl_scope; - unsigned char tb_id_in; - unsigned char tb_id; - unsigned char prefixlen; - unsigned char nh_sel; - unsigned char type; - unsigned char scope; - int err; -}; - -struct fib_dump_filter { - u32 table_id; - bool filter_set; - bool dump_routes; - bool dump_exceptions; - unsigned char protocol; - unsigned char rt_type; - unsigned int flags; - struct net_device *dev; -}; - -struct fib_nh_notifier_info { - struct fib_notifier_info info; - struct fib_nh *fib_nh; -}; - -struct fib_entry_notifier_info { - struct fib_notifier_info info; - u32 dst; - int dst_len; - struct fib_info *fi; - u8 tos; - u8 type; - u32 tb_id; -}; - -typedef unsigned int t_key; - -struct key_vector { - t_key key; - unsigned char pos; - unsigned char bits; - unsigned char slen; - union { - struct hlist_head leaf; - struct key_vector *tnode[0]; - }; -}; - -struct tnode { - struct callback_head rcu; - t_key empty_children; - t_key full_children; - struct key_vector *parent; - struct key_vector kv[1]; -}; - -struct trie_stat { - unsigned int totdepth; - unsigned int maxdepth; - unsigned int tnodes; - unsigned int leaves; - unsigned int nullpointers; - unsigned int prefixes; - unsigned int nodesizes[32]; -}; - -struct trie { - struct key_vector kv[1]; -}; - -struct fib_trie_iter { - struct seq_net_private p; - struct fib_table *tb; - struct key_vector *tnode; - unsigned int index; - unsigned int depth; -}; - -struct fib_route_iter { - struct seq_net_private p; - struct fib_table *main_tb; - struct key_vector *tnode; - loff_t pos; - t_key key; -}; - -struct ipfrag_skb_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - }; - struct sk_buff *next_frag; - int frag_run_len; -}; - -struct icmpv6_echo { - __be16 identifier; - __be16 sequence; -}; - -struct icmpv6_nd_advt { - __u32 reserved: 5; - __u32 override: 1; - __u32 solicited: 1; - __u32 router: 1; - __u32 reserved2: 24; -}; - -struct icmpv6_nd_ra { - __u8 hop_limit; - __u8 reserved: 3; - __u8 router_pref: 2; - __u8 home_agent: 1; - __u8 other: 1; - __u8 managed: 1; - __be16 rt_lifetime; -}; - -struct icmp6hdr { - __u8 icmp6_type; - __u8 icmp6_code; - __sum16 icmp6_cksum; - union { - __be32 un_data32[1]; - __be16 un_data16[2]; - __u8 un_data8[4]; - struct icmpv6_echo u_echo; - struct icmpv6_nd_advt u_nd_advt; - struct icmpv6_nd_ra u_nd_ra; - } icmp6_dataun; -}; - -struct ping_iter_state { - struct seq_net_private p; - int bucket; - sa_family_t family; -}; - -struct pingfakehdr { - struct icmphdr icmph; - struct msghdr *msg; - sa_family_t family; - __wsum wcheck; -}; - -struct ping_table { - struct hlist_nulls_head hash[64]; - rwlock_t lock; -}; - -enum lwtunnel_ip_t { - LWTUNNEL_IP_UNSPEC = 0, - LWTUNNEL_IP_ID = 1, - LWTUNNEL_IP_DST = 2, - LWTUNNEL_IP_SRC = 3, - LWTUNNEL_IP_TTL = 4, - LWTUNNEL_IP_TOS = 5, - LWTUNNEL_IP_FLAGS = 6, - LWTUNNEL_IP_PAD = 7, - LWTUNNEL_IP_OPTS = 8, - __LWTUNNEL_IP_MAX = 9, -}; - -enum lwtunnel_ip6_t { - LWTUNNEL_IP6_UNSPEC = 0, - LWTUNNEL_IP6_ID = 1, - LWTUNNEL_IP6_DST = 2, - LWTUNNEL_IP6_SRC = 3, - LWTUNNEL_IP6_HOPLIMIT = 4, - LWTUNNEL_IP6_TC = 5, - LWTUNNEL_IP6_FLAGS = 6, - LWTUNNEL_IP6_PAD = 7, - LWTUNNEL_IP6_OPTS = 8, - __LWTUNNEL_IP6_MAX = 9, -}; - -enum { - LWTUNNEL_IP_OPTS_UNSPEC = 0, - LWTUNNEL_IP_OPTS_GENEVE = 1, - LWTUNNEL_IP_OPTS_VXLAN = 2, - LWTUNNEL_IP_OPTS_ERSPAN = 3, - __LWTUNNEL_IP_OPTS_MAX = 4, -}; - -enum { - LWTUNNEL_IP_OPT_GENEVE_UNSPEC = 0, - LWTUNNEL_IP_OPT_GENEVE_CLASS = 1, - LWTUNNEL_IP_OPT_GENEVE_TYPE = 2, - LWTUNNEL_IP_OPT_GENEVE_DATA = 3, - __LWTUNNEL_IP_OPT_GENEVE_MAX = 4, -}; - -enum { - LWTUNNEL_IP_OPT_VXLAN_UNSPEC = 0, - LWTUNNEL_IP_OPT_VXLAN_GBP = 1, - __LWTUNNEL_IP_OPT_VXLAN_MAX = 2, -}; - -enum { - LWTUNNEL_IP_OPT_ERSPAN_UNSPEC = 0, - LWTUNNEL_IP_OPT_ERSPAN_VER = 1, - LWTUNNEL_IP_OPT_ERSPAN_INDEX = 2, - LWTUNNEL_IP_OPT_ERSPAN_DIR = 3, - LWTUNNEL_IP_OPT_ERSPAN_HWID = 4, - __LWTUNNEL_IP_OPT_ERSPAN_MAX = 5, -}; - -struct ip6_tnl_encap_ops { - size_t (*encap_hlen)(struct ip_tunnel_encap *); - int (*build_header)(struct sk_buff *, struct ip_tunnel_encap *, u8 *, struct flowi6 *); - int (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32); -}; - -struct geneve_opt { - __be16 opt_class; - u8 type; - u8 length: 5; - u8 r3: 1; - u8 r2: 1; - u8 r1: 1; - u8 opt_data[0]; -}; - -struct vxlan_metadata { - u32 gbp; -}; - -struct erspan_md2 { - __be32 timestamp; - __be16 sgt; - __u8 hwid_upper: 2; - __u8 ft: 5; - __u8 p: 1; - __u8 o: 1; - __u8 gra: 2; - __u8 dir: 1; - __u8 hwid: 4; -}; - -struct erspan_metadata { - int version; - union { - __be32 index; - struct erspan_md2 md2; - } u; -}; - -struct nhmsg { - unsigned char nh_family; - unsigned char nh_scope; - unsigned char nh_protocol; - unsigned char resvd; - unsigned int nh_flags; -}; - -struct nexthop_grp { - __u32 id; - __u8 weight; - __u8 resvd1; - __u16 resvd2; -}; - -enum { - NEXTHOP_GRP_TYPE_MPATH = 0, - __NEXTHOP_GRP_TYPE_MAX = 1, -}; - -enum { - NHA_UNSPEC = 0, - NHA_ID = 1, - NHA_GROUP = 2, - NHA_GROUP_TYPE = 3, - NHA_BLACKHOLE = 4, - NHA_OIF = 5, - NHA_GATEWAY = 6, - NHA_ENCAP_TYPE = 7, - NHA_ENCAP = 8, - NHA_GROUPS = 9, - NHA_MASTER = 10, - NHA_FDB = 11, - __NHA_MAX = 12, -}; - -struct nh_config { - u32 nh_id; - u8 nh_family; - u8 nh_protocol; - u8 nh_blackhole; - u8 nh_fdb; - u32 nh_flags; - int nh_ifindex; - struct net_device *dev; - union { - __be32 ipv4; - struct in6_addr ipv6; - } gw; - struct nlattr *nh_grp; - u16 nh_grp_type; - struct nlattr *nh_encap; - u16 nh_encap_type; - u32 nlflags; - struct nl_info nlinfo; -}; - -enum nexthop_event_type { - NEXTHOP_EVENT_DEL = 0, -}; - -struct inet6_protocol { - void (*early_demux)(struct sk_buff *); - void (*early_demux_handler)(struct sk_buff *); - int (*handler)(struct sk_buff *); - int (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32); - unsigned int flags; -}; - -struct snmp_mib { - const char *name; - int entry; -}; - -struct fib4_rule { - struct fib_rule common; - u8 dst_len; - u8 src_len; - u8 tos; - __be32 src; - __be32 srcmask; - __be32 dst; - __be32 dstmask; - u32 tclassid; -}; - -enum { - PIM_TYPE_HELLO = 0, - PIM_TYPE_REGISTER = 1, - PIM_TYPE_REGISTER_STOP = 2, - PIM_TYPE_JOIN_PRUNE = 3, - PIM_TYPE_BOOTSTRAP = 4, - PIM_TYPE_ASSERT = 5, - PIM_TYPE_GRAFT = 6, - PIM_TYPE_GRAFT_ACK = 7, - PIM_TYPE_CANDIDATE_RP_ADV = 8, -}; - -struct pimreghdr { - __u8 type; - __u8 reserved; - __be16 csum; - __be32 flags; -}; - -typedef short unsigned int vifi_t; - -struct vifctl { - vifi_t vifc_vifi; - unsigned char vifc_flags; - unsigned char vifc_threshold; - unsigned int vifc_rate_limit; - union { - struct in_addr vifc_lcl_addr; - int vifc_lcl_ifindex; - }; - struct in_addr vifc_rmt_addr; -}; - -struct mfcctl { - struct in_addr mfcc_origin; - struct in_addr mfcc_mcastgrp; - vifi_t mfcc_parent; - unsigned char mfcc_ttls[32]; - unsigned int mfcc_pkt_cnt; - unsigned int mfcc_byte_cnt; - unsigned int mfcc_wrong_if; - int mfcc_expire; -}; - -struct sioc_sg_req { - struct in_addr src; - struct in_addr grp; - long unsigned int pktcnt; - long unsigned int bytecnt; - long unsigned int wrong_if; -}; - -struct sioc_vif_req { - vifi_t vifi; - long unsigned int icount; - long unsigned int ocount; - long unsigned int ibytes; - long unsigned int obytes; -}; - -struct igmpmsg { - __u32 unused1; - __u32 unused2; - unsigned char im_msgtype; - unsigned char im_mbz; - unsigned char im_vif; - unsigned char im_vif_hi; - struct in_addr im_src; - struct in_addr im_dst; -}; - -enum { - IPMRA_TABLE_UNSPEC = 0, - IPMRA_TABLE_ID = 1, - IPMRA_TABLE_CACHE_RES_QUEUE_LEN = 2, - IPMRA_TABLE_MROUTE_REG_VIF_NUM = 3, - IPMRA_TABLE_MROUTE_DO_ASSERT = 4, - IPMRA_TABLE_MROUTE_DO_PIM = 5, - IPMRA_TABLE_VIFS = 6, - IPMRA_TABLE_MROUTE_DO_WRVIFWHOLE = 7, - __IPMRA_TABLE_MAX = 8, -}; - -enum { - IPMRA_VIF_UNSPEC = 0, - IPMRA_VIF = 1, - __IPMRA_VIF_MAX = 2, -}; - -enum { - IPMRA_VIFA_UNSPEC = 0, - IPMRA_VIFA_IFINDEX = 1, - IPMRA_VIFA_VIF_ID = 2, - IPMRA_VIFA_FLAGS = 3, - IPMRA_VIFA_BYTES_IN = 4, - IPMRA_VIFA_BYTES_OUT = 5, - IPMRA_VIFA_PACKETS_IN = 6, - IPMRA_VIFA_PACKETS_OUT = 7, - IPMRA_VIFA_LOCAL_ADDR = 8, - IPMRA_VIFA_REMOTE_ADDR = 9, - IPMRA_VIFA_PAD = 10, - __IPMRA_VIFA_MAX = 11, -}; - -enum { - IPMRA_CREPORT_UNSPEC = 0, - IPMRA_CREPORT_MSGTYPE = 1, - IPMRA_CREPORT_VIF_ID = 2, - IPMRA_CREPORT_SRC_ADDR = 3, - IPMRA_CREPORT_DST_ADDR = 4, - IPMRA_CREPORT_PKT = 5, - IPMRA_CREPORT_TABLE = 6, - __IPMRA_CREPORT_MAX = 7, -}; - -struct vif_device { - struct net_device *dev; - long unsigned int bytes_in; - long unsigned int bytes_out; - long unsigned int pkt_in; - long unsigned int pkt_out; - long unsigned int rate_limit; - unsigned char threshold; - short unsigned int flags; - int link; - struct netdev_phys_item_id dev_parent_id; - __be32 local; - __be32 remote; -}; - -struct vif_entry_notifier_info { - struct fib_notifier_info info; - struct net_device *dev; - short unsigned int vif_index; - short unsigned int vif_flags; - u32 tb_id; -}; - -enum { - MFC_STATIC = 1, - MFC_OFFLOAD = 2, -}; - -struct mr_mfc { - struct rhlist_head mnode; - short unsigned int mfc_parent; - int mfc_flags; - union { - struct { - long unsigned int expires; - struct sk_buff_head unresolved; - } unres; - struct { - long unsigned int last_assert; - int minvif; - int maxvif; - long unsigned int bytes; - long unsigned int pkt; - long unsigned int wrong_if; - long unsigned int lastuse; - unsigned char ttls[32]; - refcount_t refcount; - } res; - } mfc_un; - struct list_head list; - struct callback_head rcu; - void (*free)(struct callback_head *); -}; - -struct mfc_entry_notifier_info { - struct fib_notifier_info info; - struct mr_mfc *mfc; - u32 tb_id; -}; - -struct mr_table_ops { - const struct rhashtable_params *rht_params; - void *cmparg_any; -}; - -struct mr_table { - struct list_head list; - possible_net_t net; - struct mr_table_ops ops; - u32 id; - struct sock *mroute_sk; - struct timer_list ipmr_expire_timer; - struct list_head mfc_unres_queue; - struct vif_device vif_table[32]; - struct rhltable mfc_hash; - struct list_head mfc_cache_list; - int maxvif; - atomic_t cache_resolve_queue_len; - bool mroute_do_assert; - bool mroute_do_pim; - bool mroute_do_wrvifwhole; - int mroute_reg_vif_num; -}; - -struct mr_vif_iter { - struct seq_net_private p; - struct mr_table *mrt; - int ct; -}; - -struct mr_mfc_iter { - struct seq_net_private p; - struct mr_table *mrt; - struct list_head *cache; - spinlock_t *lock; -}; - -struct mfc_cache_cmp_arg { - __be32 mfc_mcastgrp; - __be32 mfc_origin; -}; - -struct mfc_cache { - struct mr_mfc _c; - union { - struct { - __be32 mfc_mcastgrp; - __be32 mfc_origin; - }; - struct mfc_cache_cmp_arg cmparg; - }; -}; - -struct ipmr_result { - struct mr_table *mrt; -}; - -struct compat_sioc_sg_req { - struct in_addr src; - struct in_addr grp; - compat_ulong_t pktcnt; - compat_ulong_t bytecnt; - compat_ulong_t wrong_if; -}; - -struct compat_sioc_vif_req { - vifi_t vifi; - compat_ulong_t icount; - compat_ulong_t ocount; - compat_ulong_t ibytes; - compat_ulong_t obytes; -}; - -struct rta_mfc_stats { - __u64 mfcs_packets; - __u64 mfcs_bytes; - __u64 mfcs_wrong_if; -}; - -struct ic_device { - struct ic_device *next; - struct net_device *dev; - short unsigned int flags; - short int able; - __be32 xid; -}; - -struct bootp_pkt { - struct iphdr iph; - struct udphdr udph; - u8 op; - u8 htype; - u8 hlen; - u8 hops; - __be32 xid; - __be16 secs; - __be16 flags; - __be32 client_ip; - __be32 your_ip; - __be32 server_ip; - __be32 relay_ip; - u8 hw_addr[16]; - u8 serv_name[64]; - u8 boot_file[128]; - u8 exten[312]; -}; - -struct bictcp { - u32 cnt; - u32 last_max_cwnd; - u32 last_cwnd; - u32 last_time; - u32 bic_origin_point; - u32 bic_K; - u32 delay_min; - u32 epoch_start; - u32 ack_cnt; - u32 tcp_cwnd; - u16 unused; - u8 sample_cnt; - u8 found; - u32 round_start; - u32 end_seq; - u32 last_ack; - u32 curr_rtt; -}; - -struct xfrm_policy_afinfo { - struct dst_ops *dst_ops; - struct dst_entry * (*dst_lookup)(struct net *, int, int, const xfrm_address_t *, const xfrm_address_t *, u32); - int (*get_saddr)(struct net *, int, xfrm_address_t *, xfrm_address_t *, u32); - int (*fill_dst)(struct xfrm_dst *, struct net_device *, const struct flowi *); - struct dst_entry * (*blackhole_route)(struct net *, struct dst_entry *); -}; - -struct xfrm_state_afinfo { - u8 family; - u8 proto; - const struct xfrm_type_offload *type_offload_esp; - const struct xfrm_type *type_esp; - const struct xfrm_type *type_ipip; - const struct xfrm_type *type_ipip6; - const struct xfrm_type *type_comp; - const struct xfrm_type *type_ah; - const struct xfrm_type *type_routing; - const struct xfrm_type *type_dstopts; - int (*output)(struct net *, struct sock *, struct sk_buff *); - int (*transport_finish)(struct sk_buff *, int); - void (*local_error)(struct sk_buff *, u32); -}; - -struct ip_tunnel; - -struct ip6_tnl; - -struct xfrm_tunnel_skb_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - union { - struct ip_tunnel *ip4; - struct ip6_tnl *ip6; - } tunnel; -}; - -struct xfrm_mode_skb_cb { - struct xfrm_tunnel_skb_cb header; - __be16 id; - __be16 frag_off; - u8 ihl; - u8 tos; - u8 ttl; - u8 protocol; - u8 optlen; - u8 flow_lbl[3]; -}; - -struct xfrm_spi_skb_cb { - struct xfrm_tunnel_skb_cb header; - unsigned int daddroff; - unsigned int family; - __be32 seq; -}; - -struct xfrm_input_afinfo { - u8 family; - bool is_ipip; - int (*callback)(struct sk_buff *, u8, int); -}; - -struct xfrm4_protocol { - int (*handler)(struct sk_buff *); - int (*input_handler)(struct sk_buff *, int, __be32, int); - int (*cb_handler)(struct sk_buff *, int); - int (*err_handler)(struct sk_buff *, u32); - struct xfrm4_protocol *next; - int priority; -}; - -typedef u64 (*btf_bpf_tcp_send_ack)(struct tcp_sock *, u32); - -enum { - XFRM_STATE_VOID = 0, - XFRM_STATE_ACQ = 1, - XFRM_STATE_VALID = 2, - XFRM_STATE_ERROR = 3, - XFRM_STATE_EXPIRED = 4, - XFRM_STATE_DEAD = 5, -}; - -struct xfrm_if; - -struct xfrm_if_cb { - struct xfrm_if * (*decode_session)(struct sk_buff *, short unsigned int); -}; - -struct xfrm_if_parms { - int link; - u32 if_id; -}; - -struct xfrm_if { - struct xfrm_if *next; - struct net_device *dev; - struct net *net; - struct xfrm_if_parms p; - struct gro_cells gro_cells; -}; - -struct xfrm_policy_walk { - struct xfrm_policy_walk_entry walk; - u8 type; - u32 seq; -}; - -struct xfrmk_spdinfo { - u32 incnt; - u32 outcnt; - u32 fwdcnt; - u32 inscnt; - u32 outscnt; - u32 fwdscnt; - u32 spdhcnt; - u32 spdhmcnt; -}; - -struct xfrm_flo { - struct dst_entry *dst_orig; - u8 flags; -}; - -struct xfrm_pol_inexact_node { - struct rb_node node; - union { - xfrm_address_t addr; - struct callback_head rcu; - }; - u8 prefixlen; - struct rb_root root; - struct hlist_head hhead; -}; - -struct xfrm_pol_inexact_key { - possible_net_t net; - u32 if_id; - u16 family; - u8 dir; - u8 type; -}; - -struct xfrm_pol_inexact_bin { - struct xfrm_pol_inexact_key k; - struct rhash_head head; - struct hlist_head hhead; - seqcount_spinlock_t count; - struct rb_root root_d; - struct rb_root root_s; - struct list_head inexact_bins; - struct callback_head rcu; -}; - -enum xfrm_pol_inexact_candidate_type { - XFRM_POL_CAND_BOTH = 0, - XFRM_POL_CAND_SADDR = 1, - XFRM_POL_CAND_DADDR = 2, - XFRM_POL_CAND_ANY = 3, - XFRM_POL_CAND_MAX = 4, -}; - -struct xfrm_pol_inexact_candidates { - struct hlist_head *res[4]; -}; - -enum xfrm_ae_ftype_t { - XFRM_AE_UNSPEC = 0, - XFRM_AE_RTHR = 1, - XFRM_AE_RVAL = 2, - XFRM_AE_LVAL = 4, - XFRM_AE_ETHR = 8, - XFRM_AE_CR = 16, - XFRM_AE_CE = 32, - XFRM_AE_CU = 64, - __XFRM_AE_MAX = 65, -}; - -enum xfrm_nlgroups { - XFRMNLGRP_NONE = 0, - XFRMNLGRP_ACQUIRE = 1, - XFRMNLGRP_EXPIRE = 2, - XFRMNLGRP_SA = 3, - XFRMNLGRP_POLICY = 4, - XFRMNLGRP_AEVENTS = 5, - XFRMNLGRP_REPORT = 6, - XFRMNLGRP_MIGRATE = 7, - XFRMNLGRP_MAPPING = 8, - __XFRMNLGRP_MAX = 9, -}; - -enum { - XFRM_MODE_FLAG_TUNNEL = 1, -}; - -struct km_event { - union { - u32 hard; - u32 proto; - u32 byid; - u32 aevent; - u32 type; - } data; - u32 seq; - u32 portid; - u32 event; - struct net *net; -}; - -struct xfrm_kmaddress { - xfrm_address_t local; - xfrm_address_t remote; - u32 reserved; - u16 family; -}; - -struct xfrm_migrate { - xfrm_address_t old_daddr; - xfrm_address_t old_saddr; - xfrm_address_t new_daddr; - xfrm_address_t new_saddr; - u8 proto; - u8 mode; - u16 reserved; - u32 reqid; - u16 old_family; - u16 new_family; -}; - -struct xfrm_mgr { - struct list_head list; - int (*notify)(struct xfrm_state *, const struct km_event *); - int (*acquire)(struct xfrm_state *, struct xfrm_tmpl *, struct xfrm_policy *); - struct xfrm_policy * (*compile_policy)(struct sock *, int, u8 *, int, int *); - int (*new_mapping)(struct xfrm_state *, xfrm_address_t *, __be16); - int (*notify_policy)(struct xfrm_policy *, int, const struct km_event *); - int (*report)(struct net *, u8, struct xfrm_selector *, xfrm_address_t *); - int (*migrate)(const struct xfrm_selector *, u8, u8, const struct xfrm_migrate *, int, const struct xfrm_kmaddress *, const struct xfrm_encap_tmpl *); - bool (*is_alive)(const struct km_event *); -}; - -struct xfrmk_sadinfo { - u32 sadhcnt; - u32 sadhmcnt; - u32 sadcnt; -}; - -struct xfrm_translator { - int (*alloc_compat)(struct sk_buff *, const struct nlmsghdr *); - struct nlmsghdr * (*rcv_msg_compat)(const struct nlmsghdr *, int, const struct nla_policy *, struct netlink_ext_ack *); - int (*xlate_user_policy_sockptr)(u8 **, int); - struct module *owner; -}; - -struct ip_beet_phdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 padlen; - __u8 reserved; -}; - -struct ip_tunnel_6rd_parm { - struct in6_addr prefix; - __be32 relay_prefix; - u16 prefixlen; - u16 relay_prefixlen; -}; - -struct ip_tunnel_prl_entry; - -struct ip_tunnel { - struct ip_tunnel *next; - struct hlist_node hash_node; - struct net_device *dev; - struct net *net; - long unsigned int err_time; - int err_count; - u32 i_seqno; - u32 o_seqno; - int tun_hlen; - u32 index; - u8 erspan_ver; - u8 dir; - u16 hwid; - struct dst_cache dst_cache; - struct ip_tunnel_parm parms; - int mlink; - int encap_hlen; - int hlen; - struct ip_tunnel_encap encap; - struct ip_tunnel_6rd_parm ip6rd; - struct ip_tunnel_prl_entry *prl; - unsigned int prl_count; - unsigned int ip_tnl_net_id; - struct gro_cells gro_cells; - __u32 fwmark; - bool collect_md; - bool ignore_df; -}; - -struct __ip6_tnl_parm { - char name[16]; - int link; - __u8 proto; - __u8 encap_limit; - __u8 hop_limit; - bool collect_md; - __be32 flowinfo; - __u32 flags; - struct in6_addr laddr; - struct in6_addr raddr; - __be16 i_flags; - __be16 o_flags; - __be32 i_key; - __be32 o_key; - __u32 fwmark; - __u32 index; - __u8 erspan_ver; - __u8 dir; - __u16 hwid; -}; - -struct ip6_tnl { - struct ip6_tnl *next; - struct net_device *dev; - struct net *net; - struct __ip6_tnl_parm parms; - struct flowi fl; - struct dst_cache dst_cache; - struct gro_cells gro_cells; - int err_count; - long unsigned int err_time; - __u32 i_seqno; - __u32 o_seqno; - int hlen; - int tun_hlen; - int encap_hlen; - struct ip_tunnel_encap encap; - int mlink; -}; - -struct xfrm_skb_cb { - struct xfrm_tunnel_skb_cb header; - union { - struct { - __u32 low; - __u32 hi; - } output; - struct { - __be32 low; - __be32 hi; - } input; - } seq; -}; - -struct ip_tunnel_prl_entry { - struct ip_tunnel_prl_entry *next; - __be32 addr; - u16 flags; - struct callback_head callback_head; -}; - -struct xfrm_trans_tasklet { - struct tasklet_struct tasklet; - struct sk_buff_head queue; -}; - -struct xfrm_trans_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - int (*finish)(struct net *, struct sock *, struct sk_buff *); - struct net *net; -}; - -struct xfrm_user_offload { - int ifindex; - __u8 flags; -}; - -struct sadb_alg { - __u8 sadb_alg_id; - __u8 sadb_alg_ivlen; - __u16 sadb_alg_minbits; - __u16 sadb_alg_maxbits; - __u16 sadb_alg_reserved; -}; - -struct xfrm_algo_aead_info { - char *geniv; - u16 icv_truncbits; -}; - -struct xfrm_algo_auth_info { - u16 icv_truncbits; - u16 icv_fullbits; -}; - -struct xfrm_algo_encr_info { - char *geniv; - u16 blockbits; - u16 defkeybits; -}; - -struct xfrm_algo_comp_info { - u16 threshold; -}; - -struct xfrm_algo_desc { - char *name; - char *compat; - u8 available: 1; - u8 pfkey_supported: 1; - union { - struct xfrm_algo_aead_info aead; - struct xfrm_algo_auth_info auth; - struct xfrm_algo_encr_info encr; - struct xfrm_algo_comp_info comp; - } uinfo; - struct sadb_alg desc; -}; - -struct xfrm_algo_list { - struct xfrm_algo_desc *algs; - int entries; - u32 type; - u32 mask; -}; - -struct xfrm_aead_name { - const char *name; - int icvbits; -}; - -enum { - XFRM_SHARE_ANY = 0, - XFRM_SHARE_SESSION = 1, - XFRM_SHARE_USER = 2, - XFRM_SHARE_UNIQUE = 3, -}; - -struct xfrm_user_sec_ctx { - __u16 len; - __u16 exttype; - __u8 ctx_alg; - __u8 ctx_doi; - __u16 ctx_len; -}; - -struct xfrm_user_tmpl { - struct xfrm_id id; - __u16 family; - xfrm_address_t saddr; - __u32 reqid; - __u8 mode; - __u8 share; - __u8 optional; - __u32 aalgos; - __u32 ealgos; - __u32 calgos; -}; - -struct xfrm_userpolicy_type { - __u8 type; - __u16 reserved1; - __u8 reserved2; -}; - -enum xfrm_sadattr_type_t { - XFRMA_SAD_UNSPEC = 0, - XFRMA_SAD_CNT = 1, - XFRMA_SAD_HINFO = 2, - __XFRMA_SAD_MAX = 3, -}; - -struct xfrmu_sadhinfo { - __u32 sadhcnt; - __u32 sadhmcnt; -}; - -enum xfrm_spdattr_type_t { - XFRMA_SPD_UNSPEC = 0, - XFRMA_SPD_INFO = 1, - XFRMA_SPD_HINFO = 2, - XFRMA_SPD_IPV4_HTHRESH = 3, - XFRMA_SPD_IPV6_HTHRESH = 4, - __XFRMA_SPD_MAX = 5, -}; - -struct xfrmu_spdinfo { - __u32 incnt; - __u32 outcnt; - __u32 fwdcnt; - __u32 inscnt; - __u32 outscnt; - __u32 fwdscnt; -}; - -struct xfrmu_spdhinfo { - __u32 spdhcnt; - __u32 spdhmcnt; -}; - -struct xfrmu_spdhthresh { - __u8 lbits; - __u8 rbits; -}; - -struct xfrm_usersa_info { - struct xfrm_selector sel; - struct xfrm_id id; - xfrm_address_t saddr; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - struct xfrm_stats stats; - __u32 seq; - __u32 reqid; - __u16 family; - __u8 mode; - __u8 replay_window; - __u8 flags; -}; - -struct xfrm_usersa_id { - xfrm_address_t daddr; - __be32 spi; - __u16 family; - __u8 proto; -}; - -struct xfrm_aevent_id { - struct xfrm_usersa_id sa_id; - xfrm_address_t saddr; - __u32 flags; - __u32 reqid; -}; - -struct xfrm_userspi_info { - struct xfrm_usersa_info info; - __u32 min; - __u32 max; -}; - -struct xfrm_userpolicy_info { - struct xfrm_selector sel; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - __u32 priority; - __u32 index; - __u8 dir; - __u8 action; - __u8 flags; - __u8 share; -}; - -struct xfrm_userpolicy_id { - struct xfrm_selector sel; - __u32 index; - __u8 dir; -}; - -struct xfrm_user_acquire { - struct xfrm_id id; - xfrm_address_t saddr; - struct xfrm_selector sel; - struct xfrm_userpolicy_info policy; - __u32 aalgos; - __u32 ealgos; - __u32 calgos; - __u32 seq; -}; - -struct xfrm_user_expire { - struct xfrm_usersa_info state; - __u8 hard; -}; - -struct xfrm_user_polexpire { - struct xfrm_userpolicy_info pol; - __u8 hard; -}; - -struct xfrm_usersa_flush { - __u8 proto; -}; - -struct xfrm_user_report { - __u8 proto; - struct xfrm_selector sel; -}; - -struct xfrm_user_mapping { - struct xfrm_usersa_id id; - __u32 reqid; - xfrm_address_t old_saddr; - xfrm_address_t new_saddr; - __be16 old_sport; - __be16 new_sport; -}; - -struct xfrm_dump_info { - struct sk_buff *in_skb; - struct sk_buff *out_skb; - u32 nlmsg_seq; - u16 nlmsg_flags; -}; - -struct xfrm_link { - int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); - int (*start)(struct netlink_callback *); - int (*dump)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - const struct nla_policy *nla_pol; - int nla_max; -}; - -struct unix_stream_read_state { - int (*recv_actor)(struct sk_buff *, int, int, struct unix_stream_read_state *); - struct socket *socket; - struct msghdr *msg; - struct pipe_inode_info *pipe; - size_t size; - int flags; - unsigned int splice_flags; -}; - -enum { - IP6_FH_F_FRAG = 1, - IP6_FH_F_AUTH = 2, - IP6_FH_F_SKIP_RH = 4, -}; - -typedef void ip6_icmp_send_t(struct sk_buff *, u8, u8, __u32, const struct in6_addr *, const struct inet6_skb_parm *); - -struct mld_msg { - struct icmp6hdr mld_hdr; - struct in6_addr mld_mca; -}; - -struct sockaddr_pkt { - short unsigned int spkt_family; - unsigned char spkt_device[14]; - __be16 spkt_protocol; -}; - -struct sockaddr_ll { - short unsigned int sll_family; - __be16 sll_protocol; - int sll_ifindex; - short unsigned int sll_hatype; - unsigned char sll_pkttype; - unsigned char sll_halen; - unsigned char sll_addr[8]; -}; - -struct tpacket_stats { - unsigned int tp_packets; - unsigned int tp_drops; -}; - -struct tpacket_stats_v3 { - unsigned int tp_packets; - unsigned int tp_drops; - unsigned int tp_freeze_q_cnt; -}; - -struct tpacket_rollover_stats { - __u64 tp_all; - __u64 tp_huge; - __u64 tp_failed; -}; - -union tpacket_stats_u { - struct tpacket_stats stats1; - struct tpacket_stats_v3 stats3; -}; - -struct tpacket_auxdata { - __u32 tp_status; - __u32 tp_len; - __u32 tp_snaplen; - __u16 tp_mac; - __u16 tp_net; - __u16 tp_vlan_tci; - __u16 tp_vlan_tpid; -}; - -struct tpacket_hdr { - long unsigned int tp_status; - unsigned int tp_len; - unsigned int tp_snaplen; - short unsigned int tp_mac; - short unsigned int tp_net; - unsigned int tp_sec; - unsigned int tp_usec; -}; - -struct tpacket2_hdr { - __u32 tp_status; - __u32 tp_len; - __u32 tp_snaplen; - __u16 tp_mac; - __u16 tp_net; - __u32 tp_sec; - __u32 tp_nsec; - __u16 tp_vlan_tci; - __u16 tp_vlan_tpid; - __u8 tp_padding[4]; -}; - -struct tpacket_hdr_variant1 { - __u32 tp_rxhash; - __u32 tp_vlan_tci; - __u16 tp_vlan_tpid; - __u16 tp_padding; -}; - -struct tpacket3_hdr { - __u32 tp_next_offset; - __u32 tp_sec; - __u32 tp_nsec; - __u32 tp_snaplen; - __u32 tp_len; - __u32 tp_status; - __u16 tp_mac; - __u16 tp_net; - union { - struct tpacket_hdr_variant1 hv1; - }; - __u8 tp_padding[8]; -}; - -struct tpacket_bd_ts { - unsigned int ts_sec; - union { - unsigned int ts_usec; - unsigned int ts_nsec; - }; -}; - -struct tpacket_hdr_v1 { - __u32 block_status; - __u32 num_pkts; - __u32 offset_to_first_pkt; - __u32 blk_len; - __u64 seq_num; - struct tpacket_bd_ts ts_first_pkt; - struct tpacket_bd_ts ts_last_pkt; -}; - -union tpacket_bd_header_u { - struct tpacket_hdr_v1 bh1; -}; - -struct tpacket_block_desc { - __u32 version; - __u32 offset_to_priv; - union tpacket_bd_header_u hdr; -}; - -enum tpacket_versions { - TPACKET_V1 = 0, - TPACKET_V2 = 1, - TPACKET_V3 = 2, -}; - -struct tpacket_req { - unsigned int tp_block_size; - unsigned int tp_block_nr; - unsigned int tp_frame_size; - unsigned int tp_frame_nr; -}; - -struct tpacket_req3 { - unsigned int tp_block_size; - unsigned int tp_block_nr; - unsigned int tp_frame_size; - unsigned int tp_frame_nr; - unsigned int tp_retire_blk_tov; - unsigned int tp_sizeof_priv; - unsigned int tp_feature_req_word; -}; - -union tpacket_req_u { - struct tpacket_req req; - struct tpacket_req3 req3; -}; - -struct fanout_args { - __u16 id; - __u16 type_flags; - __u32 max_num_members; -}; - -typedef __u16 __virtio16; - -struct virtio_net_hdr { - __u8 flags; - __u8 gso_type; - __virtio16 hdr_len; - __virtio16 gso_size; - __virtio16 csum_start; - __virtio16 csum_offset; -}; - -struct packet_mclist { - struct packet_mclist *next; - int ifindex; - int count; - short unsigned int type; - short unsigned int alen; - unsigned char addr[32]; -}; - -struct pgv; - -struct tpacket_kbdq_core { - struct pgv *pkbdq; - unsigned int feature_req_word; - unsigned int hdrlen; - unsigned char reset_pending_on_curr_blk; - unsigned char delete_blk_timer; - short unsigned int kactive_blk_num; - short unsigned int blk_sizeof_priv; - short unsigned int last_kactive_blk_num; - char *pkblk_start; - char *pkblk_end; - int kblk_size; - unsigned int max_frame_len; - unsigned int knum_blocks; - uint64_t knxt_seq_num; - char *prev; - char *nxt_offset; - struct sk_buff *skb; - rwlock_t blk_fill_in_prog_lock; - short unsigned int retire_blk_tov; - short unsigned int version; - long unsigned int tov_in_jiffies; - struct timer_list retire_blk_timer; -}; - -struct pgv { - char *buffer; -}; - -struct packet_ring_buffer { - struct pgv *pg_vec; - unsigned int head; - unsigned int frames_per_block; - unsigned int frame_size; - unsigned int frame_max; - unsigned int pg_vec_order; - unsigned int pg_vec_pages; - unsigned int pg_vec_len; - unsigned int *pending_refcnt; - union { - long unsigned int *rx_owner_map; - struct tpacket_kbdq_core prb_bdqc; - }; -}; - -struct packet_fanout { - possible_net_t net; - unsigned int num_members; - u32 max_num_members; - u16 id; - u8 type; - u8 flags; - union { - atomic_t rr_cur; - struct bpf_prog *bpf_prog; - }; - struct list_head list; - spinlock_t lock; - refcount_t sk_ref; - long: 64; - struct packet_type prot_hook; - struct sock *arr[0]; -}; - -struct packet_rollover { - int sock; - atomic_long_t num; - atomic_long_t num_huge; - atomic_long_t num_failed; - long: 64; - long: 64; - long: 64; - long: 64; - u32 history[16]; -}; - -struct packet_sock { - struct sock sk; - struct packet_fanout *fanout; - union tpacket_stats_u stats; - struct packet_ring_buffer rx_ring; - struct packet_ring_buffer tx_ring; - int copy_thresh; - spinlock_t bind_lock; - struct mutex pg_vec_lock; - unsigned int running; - unsigned int auxdata: 1; - unsigned int origdev: 1; - unsigned int has_vnet_hdr: 1; - unsigned int tp_loss: 1; - unsigned int tp_tx_has_off: 1; - int pressure; - int ifindex; - __be16 num; - struct packet_rollover *rollover; - struct packet_mclist *mclist; - atomic_t mapped; - enum tpacket_versions tp_version; - unsigned int tp_hdrlen; - unsigned int tp_reserve; - unsigned int tp_tstamp; - struct completion skb_completion; - struct net_device *cached_dev; - int (*xmit)(struct sk_buff *); - long: 64; - long: 64; - struct packet_type prot_hook; - atomic_t tp_drops; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct packet_mreq_max { - int mr_ifindex; - short unsigned int mr_type; - short unsigned int mr_alen; - unsigned char mr_address[32]; -}; - -union tpacket_uhdr { - struct tpacket_hdr *h1; - struct tpacket2_hdr *h2; - struct tpacket3_hdr *h3; - void *raw; -}; - -struct packet_skb_cb { - union { - struct sockaddr_pkt pkt; - union { - unsigned int origlen; - struct sockaddr_ll ll; - }; - } sa; -}; - -enum rpc_msg_type { - RPC_CALL = 0, - RPC_REPLY = 1, -}; - -enum rpc_reply_stat { - RPC_MSG_ACCEPTED = 0, - RPC_MSG_DENIED = 1, -}; - -enum rpc_reject_stat { - RPC_MISMATCH = 0, - RPC_AUTH_ERROR = 1, -}; - -enum { - SUNRPC_PIPEFS_NFS_PRIO = 0, - SUNRPC_PIPEFS_RPC_PRIO = 1, -}; - -enum { - RPC_PIPEFS_MOUNT = 0, - RPC_PIPEFS_UMOUNT = 1, -}; - -struct sunrpc_net { - struct proc_dir_entry *proc_net_rpc; - struct cache_detail *ip_map_cache; - struct cache_detail *unix_gid_cache; - struct cache_detail *rsc_cache; - struct cache_detail *rsi_cache; - struct super_block *pipefs_sb; - struct rpc_pipe *gssd_dummy; - struct mutex pipefs_sb_lock; - struct list_head all_clients; - spinlock_t rpc_client_lock; - struct rpc_clnt *rpcb_local_clnt; - struct rpc_clnt *rpcb_local_clnt4; - spinlock_t rpcb_clnt_lock; - unsigned int rpcb_users; - unsigned int rpcb_is_af_local: 1; - struct mutex gssp_lock; - struct rpc_clnt *gssp_clnt; - int use_gss_proxy; - int pipe_version; - atomic_t pipe_users; - struct proc_dir_entry *use_gssp_proc; -}; - -struct rpc_cb_add_xprt_calldata { - struct rpc_xprt_switch *xps; - struct rpc_xprt *xprt; -}; - -struct connect_timeout_data { - long unsigned int connect_timeout; - long unsigned int reconnect_timeout; -}; - -struct xprt_class { - struct list_head list; - int ident; - struct rpc_xprt * (*setup)(struct xprt_create *); - struct module *owner; - char name[32]; - const char *netid[0]; -}; - -enum xprt_xid_rb_cmp { - XID_RB_EQUAL = 0, - XID_RB_LEFT = 1, - XID_RB_RIGHT = 2, -}; - -typedef __be32 rpc_fraghdr; - -struct xdr_skb_reader { - struct sk_buff *skb; - unsigned int offset; - size_t count; - __wsum csum; -}; - -typedef size_t (*xdr_skb_read_actor)(struct xdr_skb_reader *, void *, size_t); - -struct svc_sock { - struct svc_xprt sk_xprt; - struct socket *sk_sock; - struct sock *sk_sk; - void (*sk_ostate)(struct sock *); - void (*sk_odata)(struct sock *); - void (*sk_owspace)(struct sock *); - __be32 sk_marker; - u32 sk_tcplen; - u32 sk_datalen; - struct page *sk_pages[259]; -}; - -struct sock_xprt { - struct rpc_xprt xprt; - struct socket *sock; - struct sock *inet; - struct file *file; - struct { - struct { - __be32 fraghdr; - __be32 xid; - __be32 calldir; - }; - u32 offset; - u32 len; - long unsigned int copied; - } recv; - struct { - u32 offset; - } xmit; - long unsigned int sock_state; - struct delayed_work connect_worker; - struct work_struct error_worker; - struct work_struct recv_worker; - struct mutex recv_mutex; - struct __kernel_sockaddr_storage srcaddr; - short unsigned int srcport; - int xprt_err; - size_t rcvsize; - size_t sndsize; - struct rpc_timeout tcp_timeout; - void (*old_data_ready)(struct sock *); - void (*old_state_change)(struct sock *); - void (*old_write_space)(struct sock *); - void (*old_error_report)(struct sock *); -}; - -struct rpc_buffer { - size_t len; - char data[0]; -}; - -typedef void (*rpc_action)(struct rpc_task *); - -struct trace_event_raw_rpc_xdr_buf_class { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - const void *head_base; - size_t head_len; - const void *tail_base; - size_t tail_len; - unsigned int page_len; - unsigned int msg_len; - char __data[0]; -}; - -struct trace_event_raw_rpc_clnt_class { - struct trace_entry ent; - unsigned int client_id; - char __data[0]; -}; - -struct trace_event_raw_rpc_clnt_new { - struct trace_entry ent; - unsigned int client_id; - u32 __data_loc_addr; - u32 __data_loc_port; - u32 __data_loc_program; - u32 __data_loc_server; - char __data[0]; -}; - -struct trace_event_raw_rpc_clnt_new_err { - struct trace_entry ent; - int error; - u32 __data_loc_program; - u32 __data_loc_server; - char __data[0]; -}; - -struct trace_event_raw_rpc_clnt_clone_err { - struct trace_entry ent; - unsigned int client_id; - int error; - char __data[0]; -}; - -struct trace_event_raw_rpc_task_status { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - int status; - char __data[0]; -}; - -struct trace_event_raw_rpc_request { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - int version; - bool async; - u32 __data_loc_progname; - u32 __data_loc_procname; - char __data[0]; -}; - -struct trace_event_raw_rpc_task_running { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - const void *action; - long unsigned int runstate; - int status; - short unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_rpc_task_queued { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - long unsigned int timeout; - long unsigned int runstate; - int status; - short unsigned int flags; - u32 __data_loc_q_name; - char __data[0]; -}; - -struct trace_event_raw_rpc_failure { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - char __data[0]; -}; - -struct trace_event_raw_rpc_reply_event { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - u32 __data_loc_progname; - u32 version; - u32 __data_loc_procname; - u32 __data_loc_servername; - char __data[0]; -}; - -struct trace_event_raw_rpc_buf_alloc { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - size_t callsize; - size_t recvsize; - int status; - char __data[0]; -}; - -struct trace_event_raw_rpc_call_rpcerror { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - int tk_status; - int rpc_status; - char __data[0]; -}; - -struct trace_event_raw_rpc_stats_latency { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - int version; - u32 __data_loc_progname; - u32 __data_loc_procname; - long unsigned int backlog; - long unsigned int rtt; - long unsigned int execute; - char __data[0]; -}; - -struct trace_event_raw_rpc_xdr_overflow { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - int version; - size_t requested; - const void *end; - const void *p; - const void *head_base; - size_t head_len; - const void *tail_base; - size_t tail_len; - unsigned int page_len; - unsigned int len; - u32 __data_loc_progname; - u32 __data_loc_procedure; - char __data[0]; -}; - -struct trace_event_raw_rpc_xdr_alignment { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - int version; - size_t offset; - unsigned int copied; - const void *head_base; - size_t head_len; - const void *tail_base; - size_t tail_len; - unsigned int page_len; - unsigned int len; - u32 __data_loc_progname; - u32 __data_loc_procedure; - char __data[0]; -}; - -struct trace_event_raw_xs_socket_event { - struct trace_entry ent; - unsigned int socket_state; - unsigned int sock_state; - long long unsigned int ino; - u32 __data_loc_dstaddr; - u32 __data_loc_dstport; - char __data[0]; -}; - -struct trace_event_raw_xs_socket_event_done { - struct trace_entry ent; - int error; - unsigned int socket_state; - unsigned int sock_state; - long long unsigned int ino; - u32 __data_loc_dstaddr; - u32 __data_loc_dstport; - char __data[0]; -}; - -struct trace_event_raw_rpc_socket_nospace { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - unsigned int total; - unsigned int remaining; - char __data[0]; -}; - -struct trace_event_raw_rpc_xprt_lifetime_class { - struct trace_entry ent; - long unsigned int state; - u32 __data_loc_addr; - u32 __data_loc_port; - char __data[0]; -}; - -struct trace_event_raw_rpc_xprt_event { - struct trace_entry ent; - u32 xid; - int status; - u32 __data_loc_addr; - u32 __data_loc_port; - char __data[0]; -}; - -struct trace_event_raw_xprt_transmit { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - u32 seqno; - int status; - char __data[0]; -}; - -struct trace_event_raw_xprt_ping { - struct trace_entry ent; - int status; - u32 __data_loc_addr; - u32 __data_loc_port; - char __data[0]; -}; - -struct trace_event_raw_xprt_writelock_event { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - unsigned int snd_task_id; - char __data[0]; -}; - -struct trace_event_raw_xprt_cong_event { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - unsigned int snd_task_id; - long unsigned int cong; - long unsigned int cwnd; - bool wait; - char __data[0]; -}; - -struct trace_event_raw_xprt_reserve { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - char __data[0]; -}; - -struct trace_event_raw_xs_stream_read_data { - struct trace_entry ent; - ssize_t err; - size_t total; - u32 __data_loc_addr; - u32 __data_loc_port; - char __data[0]; -}; - -struct trace_event_raw_xs_stream_read_request { - struct trace_entry ent; - u32 __data_loc_addr; - u32 __data_loc_port; - u32 xid; - long unsigned int copied; - unsigned int reclen; - unsigned int offset; - char __data[0]; -}; - -struct trace_event_raw_rpcb_getport { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - unsigned int program; - unsigned int version; - int protocol; - unsigned int bind_version; - u32 __data_loc_servername; - char __data[0]; -}; - -struct trace_event_raw_rpcb_setport { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - int status; - short unsigned int port; - char __data[0]; -}; - -struct trace_event_raw_pmap_register { - struct trace_entry ent; - unsigned int program; - unsigned int version; - int protocol; - unsigned int port; - char __data[0]; -}; - -struct trace_event_raw_rpcb_register { - struct trace_entry ent; - unsigned int program; - unsigned int version; - u32 __data_loc_addr; - u32 __data_loc_netid; - char __data[0]; -}; - -struct trace_event_raw_rpcb_unregister { - struct trace_entry ent; - unsigned int program; - unsigned int version; - u32 __data_loc_netid; - char __data[0]; -}; - -struct trace_event_raw_svc_xdr_buf_class { - struct trace_entry ent; - u32 xid; - const void *head_base; - size_t head_len; - const void *tail_base; - size_t tail_len; - unsigned int page_len; - unsigned int msg_len; - char __data[0]; -}; - -struct trace_event_raw_svc_recv { - struct trace_entry ent; - u32 xid; - int len; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_authenticate { - struct trace_entry ent; - u32 xid; - long unsigned int svc_status; - long unsigned int auth_stat; - char __data[0]; -}; - -struct trace_event_raw_svc_process { - struct trace_entry ent; - u32 xid; - u32 vers; - u32 proc; - u32 __data_loc_service; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_rqst_event { - struct trace_entry ent; - u32 xid; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_rqst_status { - struct trace_entry ent; - u32 xid; - int status; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_xprt_create_err { - struct trace_entry ent; - long int error; - u32 __data_loc_program; - u32 __data_loc_protocol; - unsigned char addr[28]; - char __data[0]; -}; - -struct trace_event_raw_svc_xprt_do_enqueue { - struct trace_entry ent; - int pid; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_xprt_event { - struct trace_entry ent; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_xprt_accept { - struct trace_entry ent; - u32 __data_loc_addr; - u32 __data_loc_protocol; - u32 __data_loc_service; - char __data[0]; -}; - -struct trace_event_raw_svc_xprt_dequeue { - struct trace_entry ent; - long unsigned int flags; - long unsigned int wakeup; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_wake_up { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_svc_handle_xprt { - struct trace_entry ent; - int len; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_stats_latency { - struct trace_entry ent; - u32 xid; - long unsigned int execute; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svc_deferred_event { - struct trace_entry ent; - const void *dr; - u32 xid; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svcsock_new_socket { - struct trace_entry ent; - long unsigned int type; - long unsigned int family; - bool listener; - char __data[0]; -}; - -struct trace_event_raw_svcsock_marker { - struct trace_entry ent; - unsigned int length; - bool last; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svcsock_class { - struct trace_entry ent; - ssize_t result; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svcsock_tcp_recv_short { - struct trace_entry ent; - u32 expected; - u32 received; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svcsock_tcp_state { - struct trace_entry ent; - long unsigned int socket_state; - long unsigned int sock_state; - long unsigned int flags; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_svcsock_accept_class { - struct trace_entry ent; - long int status; - u32 __data_loc_service; - unsigned char addr[28]; - char __data[0]; -}; - -struct trace_event_raw_cache_event { - struct trace_entry ent; - const struct cache_head *h; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_register_class { - struct trace_entry ent; - u32 version; - long unsigned int family; - short unsigned int protocol; - short unsigned int port; - int error; - u32 __data_loc_program; - char __data[0]; -}; - -struct trace_event_raw_svc_unregister { - struct trace_entry ent; - u32 version; - int error; - u32 __data_loc_program; - char __data[0]; -}; - -struct trace_event_data_offsets_rpc_xdr_buf_class {}; - -struct trace_event_data_offsets_rpc_clnt_class {}; - -struct trace_event_data_offsets_rpc_clnt_new { - u32 addr; - u32 port; - u32 program; - u32 server; -}; - -struct trace_event_data_offsets_rpc_clnt_new_err { - u32 program; - u32 server; -}; - -struct trace_event_data_offsets_rpc_clnt_clone_err {}; - -struct trace_event_data_offsets_rpc_task_status {}; - -struct trace_event_data_offsets_rpc_request { - u32 progname; - u32 procname; -}; - -struct trace_event_data_offsets_rpc_task_running {}; - -struct trace_event_data_offsets_rpc_task_queued { - u32 q_name; -}; - -struct trace_event_data_offsets_rpc_failure {}; - -struct trace_event_data_offsets_rpc_reply_event { - u32 progname; - u32 procname; - u32 servername; -}; - -struct trace_event_data_offsets_rpc_buf_alloc {}; - -struct trace_event_data_offsets_rpc_call_rpcerror {}; - -struct trace_event_data_offsets_rpc_stats_latency { - u32 progname; - u32 procname; -}; - -struct trace_event_data_offsets_rpc_xdr_overflow { - u32 progname; - u32 procedure; -}; - -struct trace_event_data_offsets_rpc_xdr_alignment { - u32 progname; - u32 procedure; -}; - -struct trace_event_data_offsets_xs_socket_event { - u32 dstaddr; - u32 dstport; -}; - -struct trace_event_data_offsets_xs_socket_event_done { - u32 dstaddr; - u32 dstport; -}; - -struct trace_event_data_offsets_rpc_socket_nospace {}; - -struct trace_event_data_offsets_rpc_xprt_lifetime_class { - u32 addr; - u32 port; -}; - -struct trace_event_data_offsets_rpc_xprt_event { - u32 addr; - u32 port; -}; - -struct trace_event_data_offsets_xprt_transmit {}; - -struct trace_event_data_offsets_xprt_ping { - u32 addr; - u32 port; -}; - -struct trace_event_data_offsets_xprt_writelock_event {}; - -struct trace_event_data_offsets_xprt_cong_event {}; - -struct trace_event_data_offsets_xprt_reserve {}; - -struct trace_event_data_offsets_xs_stream_read_data { - u32 addr; - u32 port; -}; - -struct trace_event_data_offsets_xs_stream_read_request { - u32 addr; - u32 port; -}; - -struct trace_event_data_offsets_rpcb_getport { - u32 servername; -}; - -struct trace_event_data_offsets_rpcb_setport {}; - -struct trace_event_data_offsets_pmap_register {}; - -struct trace_event_data_offsets_rpcb_register { - u32 addr; - u32 netid; -}; - -struct trace_event_data_offsets_rpcb_unregister { - u32 netid; -}; - -struct trace_event_data_offsets_svc_xdr_buf_class {}; - -struct trace_event_data_offsets_svc_recv { - u32 addr; -}; - -struct trace_event_data_offsets_svc_authenticate {}; - -struct trace_event_data_offsets_svc_process { - u32 service; - u32 addr; -}; - -struct trace_event_data_offsets_svc_rqst_event { - u32 addr; -}; - -struct trace_event_data_offsets_svc_rqst_status { - u32 addr; -}; - -struct trace_event_data_offsets_svc_xprt_create_err { - u32 program; - u32 protocol; -}; - -struct trace_event_data_offsets_svc_xprt_do_enqueue { - u32 addr; -}; - -struct trace_event_data_offsets_svc_xprt_event { - u32 addr; -}; - -struct trace_event_data_offsets_svc_xprt_accept { - u32 addr; - u32 protocol; - u32 service; -}; - -struct trace_event_data_offsets_svc_xprt_dequeue { - u32 addr; -}; - -struct trace_event_data_offsets_svc_wake_up {}; - -struct trace_event_data_offsets_svc_handle_xprt { - u32 addr; -}; - -struct trace_event_data_offsets_svc_stats_latency { - u32 addr; -}; - -struct trace_event_data_offsets_svc_deferred_event { - u32 addr; -}; - -struct trace_event_data_offsets_svcsock_new_socket {}; - -struct trace_event_data_offsets_svcsock_marker { - u32 addr; -}; - -struct trace_event_data_offsets_svcsock_class { - u32 addr; -}; - -struct trace_event_data_offsets_svcsock_tcp_recv_short { - u32 addr; -}; - -struct trace_event_data_offsets_svcsock_tcp_state { - u32 addr; -}; - -struct trace_event_data_offsets_svcsock_accept_class { - u32 service; -}; - -struct trace_event_data_offsets_cache_event { - u32 name; -}; - -struct trace_event_data_offsets_register_class { - u32 program; -}; - -struct trace_event_data_offsets_svc_unregister { - u32 program; -}; - -typedef void (*btf_trace_rpc_xdr_sendto)(void *, const struct rpc_task *, const struct xdr_buf *); - -typedef void (*btf_trace_rpc_xdr_recvfrom)(void *, const struct rpc_task *, const struct xdr_buf *); - -typedef void (*btf_trace_rpc_xdr_reply_pages)(void *, const struct rpc_task *, const struct xdr_buf *); - -typedef void (*btf_trace_rpc_clnt_free)(void *, const struct rpc_clnt *); - -typedef void (*btf_trace_rpc_clnt_killall)(void *, const struct rpc_clnt *); - -typedef void (*btf_trace_rpc_clnt_shutdown)(void *, const struct rpc_clnt *); - -typedef void (*btf_trace_rpc_clnt_release)(void *, const struct rpc_clnt *); - -typedef void (*btf_trace_rpc_clnt_replace_xprt)(void *, const struct rpc_clnt *); - -typedef void (*btf_trace_rpc_clnt_replace_xprt_err)(void *, const struct rpc_clnt *); - -typedef void (*btf_trace_rpc_clnt_new)(void *, const struct rpc_clnt *, const struct rpc_xprt *, const char *, const char *); - -typedef void (*btf_trace_rpc_clnt_new_err)(void *, const char *, const char *, int); - -typedef void (*btf_trace_rpc_clnt_clone_err)(void *, const struct rpc_clnt *, int); - -typedef void (*btf_trace_rpc_call_status)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_connect_status)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_timeout_status)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_retry_refresh_status)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_refresh_status)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_request)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_task_begin)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_run_action)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_sync_sleep)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_sync_wake)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_complete)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_timeout)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_signalled)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_end)(void *, const struct rpc_task *, const void *); - -typedef void (*btf_trace_rpc_task_sleep)(void *, const struct rpc_task *, const struct rpc_wait_queue *); - -typedef void (*btf_trace_rpc_task_wakeup)(void *, const struct rpc_task *, const struct rpc_wait_queue *); - -typedef void (*btf_trace_rpc_bad_callhdr)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_bad_verifier)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__prog_unavail)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__prog_mismatch)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__proc_unavail)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__garbage_args)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__unparsable)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__mismatch)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__stale_creds)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__bad_creds)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc__auth_tooweak)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpcb_prog_unavail_err)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpcb_timeout_err)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpcb_bind_version_err)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpcb_unreachable_err)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpcb_unrecognized_err)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpc_buf_alloc)(void *, const struct rpc_task *, int); - -typedef void (*btf_trace_rpc_call_rpcerror)(void *, const struct rpc_task *, int, int); - -typedef void (*btf_trace_rpc_stats_latency)(void *, const struct rpc_task *, ktime_t, ktime_t, ktime_t); - -typedef void (*btf_trace_rpc_xdr_overflow)(void *, const struct xdr_stream *, size_t); - -typedef void (*btf_trace_rpc_xdr_alignment)(void *, const struct xdr_stream *, size_t, unsigned int); - -typedef void (*btf_trace_rpc_socket_state_change)(void *, struct rpc_xprt *, struct socket *); - -typedef void (*btf_trace_rpc_socket_connect)(void *, struct rpc_xprt *, struct socket *, int); - -typedef void (*btf_trace_rpc_socket_error)(void *, struct rpc_xprt *, struct socket *, int); - -typedef void (*btf_trace_rpc_socket_reset_connection)(void *, struct rpc_xprt *, struct socket *, int); - -typedef void (*btf_trace_rpc_socket_close)(void *, struct rpc_xprt *, struct socket *); - -typedef void (*btf_trace_rpc_socket_shutdown)(void *, struct rpc_xprt *, struct socket *); - -typedef void (*btf_trace_rpc_socket_nospace)(void *, const struct rpc_rqst *, const struct sock_xprt *); - -typedef void (*btf_trace_xprt_create)(void *, const struct rpc_xprt *); - -typedef void (*btf_trace_xprt_connect)(void *, const struct rpc_xprt *); - -typedef void (*btf_trace_xprt_disconnect_auto)(void *, const struct rpc_xprt *); - -typedef void (*btf_trace_xprt_disconnect_done)(void *, const struct rpc_xprt *); - -typedef void (*btf_trace_xprt_disconnect_force)(void *, const struct rpc_xprt *); - -typedef void (*btf_trace_xprt_disconnect_cleanup)(void *, const struct rpc_xprt *); - -typedef void (*btf_trace_xprt_destroy)(void *, const struct rpc_xprt *); - -typedef void (*btf_trace_xprt_timer)(void *, const struct rpc_xprt *, __be32, int); - -typedef void (*btf_trace_xprt_lookup_rqst)(void *, const struct rpc_xprt *, __be32, int); - -typedef void (*btf_trace_xprt_transmit)(void *, const struct rpc_rqst *, int); - -typedef void (*btf_trace_xprt_ping)(void *, const struct rpc_xprt *, int); - -typedef void (*btf_trace_xprt_reserve_xprt)(void *, const struct rpc_xprt *, const struct rpc_task *); - -typedef void (*btf_trace_xprt_release_xprt)(void *, const struct rpc_xprt *, const struct rpc_task *); - -typedef void (*btf_trace_xprt_reserve_cong)(void *, const struct rpc_xprt *, const struct rpc_task *); - -typedef void (*btf_trace_xprt_release_cong)(void *, const struct rpc_xprt *, const struct rpc_task *); - -typedef void (*btf_trace_xprt_get_cong)(void *, const struct rpc_xprt *, const struct rpc_task *); - -typedef void (*btf_trace_xprt_put_cong)(void *, const struct rpc_xprt *, const struct rpc_task *); - -typedef void (*btf_trace_xprt_reserve)(void *, const struct rpc_rqst *); - -typedef void (*btf_trace_xs_stream_read_data)(void *, struct rpc_xprt *, ssize_t, size_t); - -typedef void (*btf_trace_xs_stream_read_request)(void *, struct sock_xprt *); - -typedef void (*btf_trace_rpcb_getport)(void *, const struct rpc_clnt *, const struct rpc_task *, unsigned int); - -typedef void (*btf_trace_rpcb_setport)(void *, const struct rpc_task *, int, short unsigned int); - -typedef void (*btf_trace_pmap_register)(void *, u32, u32, int, short unsigned int); - -typedef void (*btf_trace_rpcb_register)(void *, u32, u32, const char *, const char *); - -typedef void (*btf_trace_rpcb_unregister)(void *, u32, u32, const char *); - -typedef void (*btf_trace_svc_xdr_recvfrom)(void *, const struct svc_rqst *, const struct xdr_buf *); - -typedef void (*btf_trace_svc_xdr_sendto)(void *, const struct svc_rqst *, const struct xdr_buf *); - -typedef void (*btf_trace_svc_recv)(void *, struct svc_rqst *, int); - -typedef void (*btf_trace_svc_authenticate)(void *, const struct svc_rqst *, int, __be32); - -typedef void (*btf_trace_svc_process)(void *, const struct svc_rqst *, const char *); - -typedef void (*btf_trace_svc_defer)(void *, const struct svc_rqst *); - -typedef void (*btf_trace_svc_drop)(void *, const struct svc_rqst *); - -typedef void (*btf_trace_svc_send)(void *, struct svc_rqst *, int); - -typedef void (*btf_trace_svc_xprt_create_err)(void *, const char *, const char *, struct sockaddr *, const struct svc_xprt *); - -typedef void (*btf_trace_svc_xprt_do_enqueue)(void *, struct svc_xprt *, struct svc_rqst *); - -typedef void (*btf_trace_svc_xprt_no_write_space)(void *, struct svc_xprt *); - -typedef void (*btf_trace_svc_xprt_close)(void *, struct svc_xprt *); - -typedef void (*btf_trace_svc_xprt_detach)(void *, struct svc_xprt *); - -typedef void (*btf_trace_svc_xprt_free)(void *, struct svc_xprt *); - -typedef void (*btf_trace_svc_xprt_accept)(void *, const struct svc_xprt *, const char *); - -typedef void (*btf_trace_svc_xprt_dequeue)(void *, struct svc_rqst *); - -typedef void (*btf_trace_svc_wake_up)(void *, int); - -typedef void (*btf_trace_svc_handle_xprt)(void *, struct svc_xprt *, int); - -typedef void (*btf_trace_svc_stats_latency)(void *, const struct svc_rqst *); - -typedef void (*btf_trace_svc_defer_drop)(void *, const struct svc_deferred_req *); - -typedef void (*btf_trace_svc_defer_queue)(void *, const struct svc_deferred_req *); - -typedef void (*btf_trace_svc_defer_recv)(void *, const struct svc_deferred_req *); - -typedef void (*btf_trace_svcsock_new_socket)(void *, const struct socket *); - -typedef void (*btf_trace_svcsock_marker)(void *, const struct svc_xprt *, __be32); - -typedef void (*btf_trace_svcsock_udp_send)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_udp_recv)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_udp_recv_err)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_tcp_send)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_tcp_recv)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_tcp_recv_eagain)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_tcp_recv_err)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_data_ready)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_write_space)(void *, const struct svc_xprt *, ssize_t); - -typedef void (*btf_trace_svcsock_tcp_recv_short)(void *, const struct svc_xprt *, u32, u32); - -typedef void (*btf_trace_svcsock_tcp_state)(void *, const struct svc_xprt *, const struct socket *); - -typedef void (*btf_trace_svcsock_accept_err)(void *, const struct svc_xprt *, const char *, long int); - -typedef void (*btf_trace_svcsock_getpeername_err)(void *, const struct svc_xprt *, const char *, long int); - -typedef void (*btf_trace_cache_entry_expired)(void *, const struct cache_detail *, const struct cache_head *); - -typedef void (*btf_trace_cache_entry_upcall)(void *, const struct cache_detail *, const struct cache_head *); - -typedef void (*btf_trace_cache_entry_update)(void *, const struct cache_detail *, const struct cache_head *); - -typedef void (*btf_trace_cache_entry_make_negative)(void *, const struct cache_detail *, const struct cache_head *); - -typedef void (*btf_trace_cache_entry_no_listener)(void *, const struct cache_detail *, const struct cache_head *); - -typedef void (*btf_trace_svc_register)(void *, const char *, const u32, const int, const short unsigned int, const short unsigned int, int); - -typedef void (*btf_trace_svc_noregister)(void *, const char *, const u32, const int, const short unsigned int, const short unsigned int, int); - -typedef void (*btf_trace_svc_unregister)(void *, const char *, const u32, int); - -struct rpc_cred_cache { - struct hlist_head *hashtable; - unsigned int hashbits; - spinlock_t lock; -}; - -enum { - SVC_POOL_AUTO = 4294967295, - SVC_POOL_GLOBAL = 0, - SVC_POOL_PERCPU = 1, - SVC_POOL_PERNODE = 2, -}; - -struct svc_pool_map { - int count; - int mode; - unsigned int npools; - unsigned int *pool_to; - unsigned int *to_pool; -}; - -struct unix_domain { - struct auth_domain h; -}; - -struct ip_map { - struct cache_head h; - char m_class[8]; - struct in6_addr m_addr; - struct unix_domain *m_client; - struct callback_head m_rcu; -}; - -struct unix_gid { - struct cache_head h; - kuid_t uid; - struct group_info *gi; - struct callback_head rcu; -}; - -enum { - RPCBPROC_NULL = 0, - RPCBPROC_SET = 1, - RPCBPROC_UNSET = 2, - RPCBPROC_GETPORT = 3, - RPCBPROC_GETADDR = 3, - RPCBPROC_DUMP = 4, - RPCBPROC_CALLIT = 5, - RPCBPROC_BCAST = 5, - RPCBPROC_GETTIME = 6, - RPCBPROC_UADDR2TADDR = 7, - RPCBPROC_TADDR2UADDR = 8, - RPCBPROC_GETVERSADDR = 9, - RPCBPROC_INDIRECT = 10, - RPCBPROC_GETADDRLIST = 11, - RPCBPROC_GETSTAT = 12, -}; - -struct rpcbind_args { - struct rpc_xprt *r_xprt; - u32 r_prog; - u32 r_vers; - u32 r_prot; - short unsigned int r_port; - const char *r_netid; - const char *r_addr; - const char *r_owner; - int r_status; -}; - -struct rpcb_info { - u32 rpc_vers; - const struct rpc_procinfo *rpc_proc; -}; - -struct thread_deferred_req { - struct cache_deferred_req handle; - struct completion completion; -}; - -struct cache_queue { - struct list_head list; - int reader; -}; - -struct cache_request { - struct cache_queue q; - struct cache_head *item; - char *buf; - int len; - int readers; -}; - -struct cache_reader { - struct cache_queue q; - int offset; -}; - -struct rpc_filelist { - const char *name; - const struct file_operations *i_fop; - umode_t mode; -}; - -enum { - RPCAUTH_info = 0, - RPCAUTH_EOF = 1, -}; - -enum { - RPCAUTH_lockd = 0, - RPCAUTH_mount = 1, - RPCAUTH_nfs = 2, - RPCAUTH_portmap = 3, - RPCAUTH_statd = 4, - RPCAUTH_nfsd4_cb = 5, - RPCAUTH_cache = 6, - RPCAUTH_nfsd = 7, - RPCAUTH_gssd = 8, - RPCAUTH_RootEOF = 9, -}; - -struct svc_xpt_user { - struct list_head list; - void (*callback)(struct svc_xpt_user *); -}; - -typedef struct rpc_xprt * (*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *, const struct rpc_xprt *); - -enum rpc_gss_proc { - RPC_GSS_PROC_DATA = 0, - RPC_GSS_PROC_INIT = 1, - RPC_GSS_PROC_CONTINUE_INIT = 2, - RPC_GSS_PROC_DESTROY = 3, -}; - -enum rpc_gss_svc { - RPC_GSS_SVC_NONE = 1, - RPC_GSS_SVC_INTEGRITY = 2, - RPC_GSS_SVC_PRIVACY = 3, -}; - -struct gss_cl_ctx { - refcount_t count; - enum rpc_gss_proc gc_proc; - u32 gc_seq; - u32 gc_seq_xmit; - spinlock_t gc_seq_lock; - struct gss_ctx *gc_gss_ctx; - struct xdr_netobj gc_wire_ctx; - struct xdr_netobj gc_acceptor; - u32 gc_win; - long unsigned int gc_expiry; - struct callback_head gc_rcu; -}; - -struct gss_upcall_msg; - -struct gss_cred { - struct rpc_cred gc_base; - enum rpc_gss_svc gc_service; - struct gss_cl_ctx *gc_ctx; - struct gss_upcall_msg *gc_upcall; - const char *gc_principal; - long unsigned int gc_upcall_timestamp; -}; - -struct gss_auth; - -struct gss_upcall_msg { - refcount_t count; - kuid_t uid; - const char *service_name; - struct rpc_pipe_msg msg; - struct list_head list; - struct gss_auth *auth; - struct rpc_pipe *pipe; - struct rpc_wait_queue rpc_waitqueue; - wait_queue_head_t waitqueue; - struct gss_cl_ctx *ctx; - char databuf[256]; -}; - -typedef unsigned int OM_uint32; - -struct gss_pipe { - struct rpc_pipe_dir_object pdo; - struct rpc_pipe *pipe; - struct rpc_clnt *clnt; - const char *name; - struct kref kref; -}; - -struct gss_auth { - struct kref kref; - struct hlist_node hash; - struct rpc_auth rpc_auth; - struct gss_api_mech *mech; - enum rpc_gss_svc service; - struct rpc_clnt *client; - struct net *net; - struct gss_pipe *gss_pipe[2]; - const char *target_name; -}; - -struct gss_alloc_pdo { - struct rpc_clnt *clnt; - const char *name; - const struct rpc_pipe_ops *upcall_ops; -}; - -struct rpc_gss_wire_cred { - u32 gc_v; - u32 gc_proc; - u32 gc_seq; - u32 gc_svc; - struct xdr_netobj gc_ctx; -}; - -struct gssp_in_token { - struct page **pages; - unsigned int page_base; - unsigned int page_len; -}; - -struct gssp_upcall_data { - struct xdr_netobj in_handle; - struct gssp_in_token in_token; - struct xdr_netobj out_handle; - struct xdr_netobj out_token; - struct rpcsec_gss_oid mech_oid; - struct svc_cred creds; - int found_creds; - int major_status; - int minor_status; -}; - -struct rsi { - struct cache_head h; - struct xdr_netobj in_handle; - struct xdr_netobj in_token; - struct xdr_netobj out_handle; - struct xdr_netobj out_token; - int major_status; - int minor_status; - struct callback_head callback_head; -}; - -struct gss_svc_seq_data { - u32 sd_max; - long unsigned int sd_win[2]; - spinlock_t sd_lock; -}; - -struct rsc { - struct cache_head h; - struct xdr_netobj handle; - struct svc_cred cred; - struct gss_svc_seq_data seqdata; - struct gss_ctx *mechctx; - struct callback_head callback_head; -}; - -struct gss_domain { - struct auth_domain h; - u32 pseudoflavor; -}; - -struct gss_svc_data { - struct rpc_gss_wire_cred clcred; - __be32 *verf_start; - struct rsc *rsci; -}; - -typedef struct xdr_netobj gssx_buffer; - -typedef struct xdr_netobj utf8string; - -typedef struct xdr_netobj gssx_OID; - -struct gssx_option { - gssx_buffer option; - gssx_buffer value; -}; - -struct gssx_option_array { - u32 count; - struct gssx_option *data; -}; - -struct gssx_status { - u64 major_status; - gssx_OID mech; - u64 minor_status; - utf8string major_status_string; - utf8string minor_status_string; - gssx_buffer server_ctx; - struct gssx_option_array options; -}; - -struct gssx_call_ctx { - utf8string locale; - gssx_buffer server_ctx; - struct gssx_option_array options; -}; - -struct gssx_name { - gssx_buffer display_name; -}; - -typedef struct gssx_name gssx_name; - -struct gssx_cred_element { - gssx_name MN; - gssx_OID mech; - u32 cred_usage; - u64 initiator_time_rec; - u64 acceptor_time_rec; - struct gssx_option_array options; -}; - -struct gssx_cred_element_array { - u32 count; - struct gssx_cred_element *data; -}; - -struct gssx_cred { - gssx_name desired_name; - struct gssx_cred_element_array elements; - gssx_buffer cred_handle_reference; - u32 needs_release; -}; - -struct gssx_ctx { - gssx_buffer exported_context_token; - gssx_buffer state; - u32 need_release; - gssx_OID mech; - gssx_name src_name; - gssx_name targ_name; - u64 lifetime; - u64 ctx_flags; - u32 locally_initiated; - u32 open; - struct gssx_option_array options; -}; - -struct gssx_cb { - u64 initiator_addrtype; - gssx_buffer initiator_address; - u64 acceptor_addrtype; - gssx_buffer acceptor_address; - gssx_buffer application_data; -}; - -struct gssx_arg_accept_sec_context { - struct gssx_call_ctx call_ctx; - struct gssx_ctx *context_handle; - struct gssx_cred *cred_handle; - struct gssp_in_token input_token; - struct gssx_cb *input_cb; - u32 ret_deleg_cred; - struct gssx_option_array options; - struct page **pages; - unsigned int npages; -}; - -struct gssx_res_accept_sec_context { - struct gssx_status status; - struct gssx_ctx *context_handle; - gssx_buffer *output_token; - struct gssx_option_array options; -}; - -enum { - GSSX_NULL = 0, - GSSX_INDICATE_MECHS = 1, - GSSX_GET_CALL_CONTEXT = 2, - GSSX_IMPORT_AND_CANON_NAME = 3, - GSSX_EXPORT_CRED = 4, - GSSX_IMPORT_CRED = 5, - GSSX_ACQUIRE_CRED = 6, - GSSX_STORE_CRED = 7, - GSSX_INIT_SEC_CONTEXT = 8, - GSSX_ACCEPT_SEC_CONTEXT = 9, - GSSX_RELEASE_HANDLE = 10, - GSSX_GET_MIC = 11, - GSSX_VERIFY = 12, - GSSX_WRAP = 13, - GSSX_UNWRAP = 14, - GSSX_WRAP_SIZE_LIMIT = 15, -}; - -struct gssx_name_attr { - gssx_buffer attr; - gssx_buffer value; - struct gssx_option_array extensions; -}; - -struct gssx_name_attr_array { - u32 count; - struct gssx_name_attr *data; -}; - -struct trace_event_raw_rpcgss_gssapi_event { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 maj_stat; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_import_ctx { - struct trace_entry ent; - int status; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_ctx_class { - struct trace_entry ent; - const void *cred; - long unsigned int service; - u32 __data_loc_principal; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_svc_gssapi_class { - struct trace_entry ent; - u32 xid; - u32 maj_stat; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_svc_unwrap_failed { - struct trace_entry ent; - u32 xid; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_svc_seqno_bad { - struct trace_entry ent; - u32 expected; - u32 received; - u32 xid; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_svc_accept_upcall { - struct trace_entry ent; - u32 minor_status; - long unsigned int major_status; - u32 xid; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_svc_authenticate { - struct trace_entry ent; - u32 seqno; - u32 xid; - u32 __data_loc_addr; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_unwrap_failed { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_bad_seqno { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 expected; - u32 received; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_seqno { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - u32 seqno; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_need_reencode { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - u32 seq_xmit; - u32 seqno; - bool ret; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_update_slack { - struct trace_entry ent; - unsigned int task_id; - unsigned int client_id; - u32 xid; - const void *auth; - unsigned int rslack; - unsigned int ralign; - unsigned int verfsize; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_svc_seqno_class { - struct trace_entry ent; - u32 xid; - u32 seqno; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_svc_seqno_low { - struct trace_entry ent; - u32 xid; - u32 seqno; - u32 min; - u32 max; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_upcall_msg { - struct trace_entry ent; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_upcall_result { - struct trace_entry ent; - u32 uid; - int result; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_context { - struct trace_entry ent; - long unsigned int expiry; - long unsigned int now; - unsigned int timeout; - u32 window_size; - int len; - u32 __data_loc_acceptor; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_createauth { - struct trace_entry ent; - unsigned int flavor; - int error; - char __data[0]; -}; - -struct trace_event_raw_rpcgss_oid_to_mech { - struct trace_entry ent; - u32 __data_loc_oid; - char __data[0]; -}; - -struct trace_event_data_offsets_rpcgss_gssapi_event {}; - -struct trace_event_data_offsets_rpcgss_import_ctx {}; - -struct trace_event_data_offsets_rpcgss_ctx_class { - u32 principal; -}; - -struct trace_event_data_offsets_rpcgss_svc_gssapi_class { - u32 addr; -}; - -struct trace_event_data_offsets_rpcgss_svc_unwrap_failed { - u32 addr; -}; - -struct trace_event_data_offsets_rpcgss_svc_seqno_bad { - u32 addr; -}; - -struct trace_event_data_offsets_rpcgss_svc_accept_upcall { - u32 addr; -}; - -struct trace_event_data_offsets_rpcgss_svc_authenticate { - u32 addr; -}; - -struct trace_event_data_offsets_rpcgss_unwrap_failed {}; - -struct trace_event_data_offsets_rpcgss_bad_seqno {}; - -struct trace_event_data_offsets_rpcgss_seqno {}; - -struct trace_event_data_offsets_rpcgss_need_reencode {}; - -struct trace_event_data_offsets_rpcgss_update_slack {}; - -struct trace_event_data_offsets_rpcgss_svc_seqno_class {}; - -struct trace_event_data_offsets_rpcgss_svc_seqno_low {}; - -struct trace_event_data_offsets_rpcgss_upcall_msg { - u32 msg; -}; - -struct trace_event_data_offsets_rpcgss_upcall_result {}; - -struct trace_event_data_offsets_rpcgss_context { - u32 acceptor; -}; - -struct trace_event_data_offsets_rpcgss_createauth {}; - -struct trace_event_data_offsets_rpcgss_oid_to_mech { - u32 oid; -}; - -typedef void (*btf_trace_rpcgss_import_ctx)(void *, int); - -typedef void (*btf_trace_rpcgss_get_mic)(void *, const struct rpc_task *, u32); - -typedef void (*btf_trace_rpcgss_verify_mic)(void *, const struct rpc_task *, u32); - -typedef void (*btf_trace_rpcgss_wrap)(void *, const struct rpc_task *, u32); - -typedef void (*btf_trace_rpcgss_unwrap)(void *, const struct rpc_task *, u32); - -typedef void (*btf_trace_rpcgss_ctx_init)(void *, const struct gss_cred *); - -typedef void (*btf_trace_rpcgss_ctx_destroy)(void *, const struct gss_cred *); - -typedef void (*btf_trace_rpcgss_svc_unwrap)(void *, const struct svc_rqst *, u32); - -typedef void (*btf_trace_rpcgss_svc_mic)(void *, const struct svc_rqst *, u32); - -typedef void (*btf_trace_rpcgss_svc_unwrap_failed)(void *, const struct svc_rqst *); - -typedef void (*btf_trace_rpcgss_svc_seqno_bad)(void *, const struct svc_rqst *, u32, u32); - -typedef void (*btf_trace_rpcgss_svc_accept_upcall)(void *, const struct svc_rqst *, u32, u32); - -typedef void (*btf_trace_rpcgss_svc_authenticate)(void *, const struct svc_rqst *, const struct rpc_gss_wire_cred *); - -typedef void (*btf_trace_rpcgss_unwrap_failed)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpcgss_bad_seqno)(void *, const struct rpc_task *, u32, u32); - -typedef void (*btf_trace_rpcgss_seqno)(void *, const struct rpc_task *); - -typedef void (*btf_trace_rpcgss_need_reencode)(void *, const struct rpc_task *, u32, bool); - -typedef void (*btf_trace_rpcgss_update_slack)(void *, const struct rpc_task *, const struct rpc_auth *); - -typedef void (*btf_trace_rpcgss_svc_seqno_large)(void *, const struct svc_rqst *, u32); - -typedef void (*btf_trace_rpcgss_svc_seqno_seen)(void *, const struct svc_rqst *, u32); - -typedef void (*btf_trace_rpcgss_svc_seqno_low)(void *, const struct svc_rqst *, u32, u32, u32); - -typedef void (*btf_trace_rpcgss_upcall_msg)(void *, const char *); - -typedef void (*btf_trace_rpcgss_upcall_result)(void *, u32, int); - -typedef void (*btf_trace_rpcgss_context)(void *, u32, long unsigned int, long unsigned int, unsigned int, unsigned int, const u8 *); - -typedef void (*btf_trace_rpcgss_createauth)(void *, unsigned int, int); - -typedef void (*btf_trace_rpcgss_oid_to_mech)(void *, const char *); - -struct vlan_group { - unsigned int nr_vlan_devs; - struct hlist_node hlist; - struct net_device **vlan_devices_arrays[16]; -}; - -struct vlan_info { - struct net_device *real_dev; - struct vlan_group grp; - struct list_head vid_list; - unsigned int nr_vids; - struct callback_head rcu; -}; - -enum vlan_flags { - VLAN_FLAG_REORDER_HDR = 1, - VLAN_FLAG_GVRP = 2, - VLAN_FLAG_LOOSE_BINDING = 4, - VLAN_FLAG_MVRP = 8, - VLAN_FLAG_BRIDGE_BINDING = 16, -}; - -struct vlan_priority_tci_mapping { - u32 priority; - u16 vlan_qos; - struct vlan_priority_tci_mapping *next; -}; - -struct vlan_dev_priv { - unsigned int nr_ingress_mappings; - u32 ingress_priority_map[8]; - unsigned int nr_egress_mappings; - struct vlan_priority_tci_mapping *egress_priority_map[16]; - __be16 vlan_proto; - u16 vlan_id; - u16 flags; - struct net_device *real_dev; - unsigned char real_dev_addr[6]; - struct proc_dir_entry *dent; - struct vlan_pcpu_stats *vlan_pcpu_stats; - struct netpoll *netpoll; -}; - -enum vlan_protos { - VLAN_PROTO_8021Q = 0, - VLAN_PROTO_8021AD = 1, - VLAN_PROTO_NUM = 2, -}; - -struct vlan_vid_info { - struct list_head list; - __be16 proto; - u16 vid; - int refcount; -}; - -enum nl80211_iftype { - NL80211_IFTYPE_UNSPECIFIED = 0, - NL80211_IFTYPE_ADHOC = 1, - NL80211_IFTYPE_STATION = 2, - NL80211_IFTYPE_AP = 3, - NL80211_IFTYPE_AP_VLAN = 4, - NL80211_IFTYPE_WDS = 5, - NL80211_IFTYPE_MONITOR = 6, - NL80211_IFTYPE_MESH_POINT = 7, - NL80211_IFTYPE_P2P_CLIENT = 8, - NL80211_IFTYPE_P2P_GO = 9, - NL80211_IFTYPE_P2P_DEVICE = 10, - NL80211_IFTYPE_OCB = 11, - NL80211_IFTYPE_NAN = 12, - NUM_NL80211_IFTYPES = 13, - NL80211_IFTYPE_MAX = 12, -}; - -struct cfg80211_conn; - -struct cfg80211_cached_keys; - -enum ieee80211_bss_type { - IEEE80211_BSS_TYPE_ESS = 0, - IEEE80211_BSS_TYPE_PBSS = 1, - IEEE80211_BSS_TYPE_IBSS = 2, - IEEE80211_BSS_TYPE_MBSS = 3, - IEEE80211_BSS_TYPE_ANY = 4, -}; - -struct cfg80211_internal_bss; - -enum nl80211_chan_width { - NL80211_CHAN_WIDTH_20_NOHT = 0, - NL80211_CHAN_WIDTH_20 = 1, - NL80211_CHAN_WIDTH_40 = 2, - NL80211_CHAN_WIDTH_80 = 3, - NL80211_CHAN_WIDTH_80P80 = 4, - NL80211_CHAN_WIDTH_160 = 5, - NL80211_CHAN_WIDTH_5 = 6, - NL80211_CHAN_WIDTH_10 = 7, - NL80211_CHAN_WIDTH_1 = 8, - NL80211_CHAN_WIDTH_2 = 9, - NL80211_CHAN_WIDTH_4 = 10, - NL80211_CHAN_WIDTH_8 = 11, - NL80211_CHAN_WIDTH_16 = 12, -}; - -enum ieee80211_edmg_bw_config { - IEEE80211_EDMG_BW_CONFIG_4 = 4, - IEEE80211_EDMG_BW_CONFIG_5 = 5, - IEEE80211_EDMG_BW_CONFIG_6 = 6, - IEEE80211_EDMG_BW_CONFIG_7 = 7, - IEEE80211_EDMG_BW_CONFIG_8 = 8, - IEEE80211_EDMG_BW_CONFIG_9 = 9, - IEEE80211_EDMG_BW_CONFIG_10 = 10, - IEEE80211_EDMG_BW_CONFIG_11 = 11, - IEEE80211_EDMG_BW_CONFIG_12 = 12, - IEEE80211_EDMG_BW_CONFIG_13 = 13, - IEEE80211_EDMG_BW_CONFIG_14 = 14, - IEEE80211_EDMG_BW_CONFIG_15 = 15, -}; - -struct ieee80211_edmg { - u8 channels; - enum ieee80211_edmg_bw_config bw_config; -}; - -struct ieee80211_channel; - -struct cfg80211_chan_def { - struct ieee80211_channel *chan; - enum nl80211_chan_width width; - u32 center_freq1; - u32 center_freq2; - struct ieee80211_edmg edmg; - u16 freq1_offset; -}; - -struct ieee80211_mcs_info { - u8 rx_mask[10]; - __le16 rx_highest; - u8 tx_params; - u8 reserved[3]; -}; - -struct ieee80211_ht_cap { - __le16 cap_info; - u8 ampdu_params_info; - struct ieee80211_mcs_info mcs; - __le16 extended_ht_cap_info; - __le32 tx_BF_cap_info; - u8 antenna_selection_info; -} __attribute__((packed)); - -struct key_params; - -struct cfg80211_ibss_params { - const u8 *ssid; - const u8 *bssid; - struct cfg80211_chan_def chandef; - const u8 *ie; - u8 ssid_len; - u8 ie_len; - u16 beacon_interval; - u32 basic_rates; - bool channel_fixed; - bool privacy; - bool control_port; - bool control_port_over_nl80211; - bool userspace_handles_dfs; - int: 24; - int mcast_rate[5]; - struct ieee80211_ht_cap ht_capa; - struct ieee80211_ht_cap ht_capa_mask; - struct key_params *wep_keys; - int wep_tx_key; - int: 32; -} __attribute__((packed)); - -enum nl80211_auth_type { - NL80211_AUTHTYPE_OPEN_SYSTEM = 0, - NL80211_AUTHTYPE_SHARED_KEY = 1, - NL80211_AUTHTYPE_FT = 2, - NL80211_AUTHTYPE_NETWORK_EAP = 3, - NL80211_AUTHTYPE_SAE = 4, - NL80211_AUTHTYPE_FILS_SK = 5, - NL80211_AUTHTYPE_FILS_SK_PFS = 6, - NL80211_AUTHTYPE_FILS_PK = 7, - __NL80211_AUTHTYPE_NUM = 8, - NL80211_AUTHTYPE_MAX = 7, - NL80211_AUTHTYPE_AUTOMATIC = 8, -}; - -enum nl80211_mfp { - NL80211_MFP_NO = 0, - NL80211_MFP_REQUIRED = 1, - NL80211_MFP_OPTIONAL = 2, -}; - -struct cfg80211_crypto_settings { - u32 wpa_versions; - u32 cipher_group; - int n_ciphers_pairwise; - u32 ciphers_pairwise[5]; - int n_akm_suites; - u32 akm_suites[2]; - bool control_port; - __be16 control_port_ethertype; - bool control_port_no_encrypt; - bool control_port_over_nl80211; - bool control_port_no_preauth; - struct key_params *wep_keys; - int wep_tx_key; - const u8 *psk; - const u8 *sae_pwd; - u8 sae_pwd_len; -}; - -struct ieee80211_vht_mcs_info { - __le16 rx_mcs_map; - __le16 rx_highest; - __le16 tx_mcs_map; - __le16 tx_highest; -}; - -struct ieee80211_vht_cap { - __le32 vht_cap_info; - struct ieee80211_vht_mcs_info supp_mcs; -}; - -enum nl80211_bss_select_attr { - __NL80211_BSS_SELECT_ATTR_INVALID = 0, - NL80211_BSS_SELECT_ATTR_RSSI = 1, - NL80211_BSS_SELECT_ATTR_BAND_PREF = 2, - NL80211_BSS_SELECT_ATTR_RSSI_ADJUST = 3, - __NL80211_BSS_SELECT_ATTR_AFTER_LAST = 4, - NL80211_BSS_SELECT_ATTR_MAX = 3, -}; - -enum nl80211_band { - NL80211_BAND_2GHZ = 0, - NL80211_BAND_5GHZ = 1, - NL80211_BAND_60GHZ = 2, - NL80211_BAND_6GHZ = 3, - NL80211_BAND_S1GHZ = 4, - NUM_NL80211_BANDS = 5, -}; - -struct cfg80211_bss_select_adjust { - enum nl80211_band band; - s8 delta; -}; - -struct cfg80211_bss_selection { - enum nl80211_bss_select_attr behaviour; - union { - enum nl80211_band band_pref; - struct cfg80211_bss_select_adjust adjust; - } param; -}; - -struct cfg80211_connect_params { - struct ieee80211_channel *channel; - struct ieee80211_channel *channel_hint; - const u8 *bssid; - const u8 *bssid_hint; - const u8 *ssid; - size_t ssid_len; - enum nl80211_auth_type auth_type; - int: 32; - const u8 *ie; - size_t ie_len; - bool privacy; - int: 24; - enum nl80211_mfp mfp; - struct cfg80211_crypto_settings crypto; - const u8 *key; - u8 key_len; - u8 key_idx; - short: 16; - u32 flags; - int bg_scan_period; - struct ieee80211_ht_cap ht_capa; - struct ieee80211_ht_cap ht_capa_mask; - struct ieee80211_vht_cap vht_capa; - struct ieee80211_vht_cap vht_capa_mask; - bool pbss; - int: 24; - struct cfg80211_bss_selection bss_select; - const u8 *prev_bssid; - const u8 *fils_erp_username; - size_t fils_erp_username_len; - const u8 *fils_erp_realm; - size_t fils_erp_realm_len; - u16 fils_erp_next_seq_num; - long: 48; - const u8 *fils_erp_rrk; - size_t fils_erp_rrk_len; - bool want_1x; - int: 24; - struct ieee80211_edmg edmg; - int: 32; -} __attribute__((packed)); - -struct cfg80211_cqm_config; - -struct wiphy; - -struct wireless_dev { - struct wiphy *wiphy; - enum nl80211_iftype iftype; - struct list_head list; - struct net_device *netdev; - u32 identifier; - struct list_head mgmt_registrations; - u8 mgmt_registrations_need_update: 1; - struct mutex mtx; - bool use_4addr; - bool is_running; - u8 address[6]; - u8 ssid[32]; - u8 ssid_len; - u8 mesh_id_len; - u8 mesh_id_up_len; - struct cfg80211_conn *conn; - struct cfg80211_cached_keys *connect_keys; - enum ieee80211_bss_type conn_bss_type; - u32 conn_owner_nlportid; - struct work_struct disconnect_wk; - u8 disconnect_bssid[6]; - struct list_head event_list; - spinlock_t event_lock; - struct cfg80211_internal_bss *current_bss; - struct cfg80211_chan_def preset_chandef; - struct cfg80211_chan_def chandef; - bool ibss_fixed; - bool ibss_dfs_possible; - bool ps; - int ps_timeout; - int beacon_interval; - u32 ap_unexpected_nlportid; - u32 owner_nlportid; - bool nl_owner_dead; - bool cac_started; - long unsigned int cac_start_time; - unsigned int cac_time_ms; - struct { - struct cfg80211_ibss_params ibss; - struct cfg80211_connect_params connect; - struct cfg80211_cached_keys *keys; - const u8 *ie; - size_t ie_len; - u8 bssid[6]; - u8 prev_bssid[6]; - u8 ssid[32]; - s8 default_key; - s8 default_mgmt_key; - bool prev_bssid_valid; - } wext; - struct cfg80211_cqm_config *cqm_config; - struct list_head pmsr_list; - spinlock_t pmsr_lock; - struct work_struct pmsr_free_wk; - long unsigned int unprot_beacon_reported; -}; - -struct iw_encode_ext { - __u32 ext_flags; - __u8 tx_seq[8]; - __u8 rx_seq[8]; - struct sockaddr addr; - __u16 alg; - __u16 key_len; - __u8 key[0]; -}; - -struct iwreq { - union { - char ifrn_name[16]; - } ifr_ifrn; - union iwreq_data u; -}; - -struct iw_event { - __u16 len; - __u16 cmd; - union iwreq_data u; -}; - -struct compat_iw_point { - compat_caddr_t pointer; - __u16 length; - __u16 flags; -}; - -struct __compat_iw_event { - __u16 len; - __u16 cmd; - compat_caddr_t pointer; -}; - -enum nl80211_reg_initiator { - NL80211_REGDOM_SET_BY_CORE = 0, - NL80211_REGDOM_SET_BY_USER = 1, - NL80211_REGDOM_SET_BY_DRIVER = 2, - NL80211_REGDOM_SET_BY_COUNTRY_IE = 3, -}; - -enum nl80211_dfs_regions { - NL80211_DFS_UNSET = 0, - NL80211_DFS_FCC = 1, - NL80211_DFS_ETSI = 2, - NL80211_DFS_JP = 3, -}; - -enum nl80211_user_reg_hint_type { - NL80211_USER_REG_HINT_USER = 0, - NL80211_USER_REG_HINT_CELL_BASE = 1, - NL80211_USER_REG_HINT_INDOOR = 2, -}; - -enum nl80211_mntr_flags { - __NL80211_MNTR_FLAG_INVALID = 0, - NL80211_MNTR_FLAG_FCSFAIL = 1, - NL80211_MNTR_FLAG_PLCPFAIL = 2, - NL80211_MNTR_FLAG_CONTROL = 3, - NL80211_MNTR_FLAG_OTHER_BSS = 4, - NL80211_MNTR_FLAG_COOK_FRAMES = 5, - NL80211_MNTR_FLAG_ACTIVE = 6, - __NL80211_MNTR_FLAG_AFTER_LAST = 7, - NL80211_MNTR_FLAG_MAX = 6, -}; - -enum nl80211_key_mode { - NL80211_KEY_RX_TX = 0, - NL80211_KEY_NO_TX = 1, - NL80211_KEY_SET_TX = 2, -}; - -enum nl80211_bss_scan_width { - NL80211_BSS_CHAN_WIDTH_20 = 0, - NL80211_BSS_CHAN_WIDTH_10 = 1, - NL80211_BSS_CHAN_WIDTH_5 = 2, - NL80211_BSS_CHAN_WIDTH_1 = 3, - NL80211_BSS_CHAN_WIDTH_2 = 4, -}; - -struct nl80211_wowlan_tcp_data_seq { - __u32 start; - __u32 offset; - __u32 len; -}; - -struct nl80211_wowlan_tcp_data_token { - __u32 offset; - __u32 len; - __u8 token_stream[0]; -}; - -struct nl80211_wowlan_tcp_data_token_feature { - __u32 min_len; - __u32 max_len; - __u32 bufsize; -}; - -enum nl80211_ext_feature_index { - NL80211_EXT_FEATURE_VHT_IBSS = 0, - NL80211_EXT_FEATURE_RRM = 1, - NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER = 2, - NL80211_EXT_FEATURE_SCAN_START_TIME = 3, - NL80211_EXT_FEATURE_BSS_PARENT_TSF = 4, - NL80211_EXT_FEATURE_SET_SCAN_DWELL = 5, - NL80211_EXT_FEATURE_BEACON_RATE_LEGACY = 6, - NL80211_EXT_FEATURE_BEACON_RATE_HT = 7, - NL80211_EXT_FEATURE_BEACON_RATE_VHT = 8, - NL80211_EXT_FEATURE_FILS_STA = 9, - NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA = 10, - NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED = 11, - NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI = 12, - NL80211_EXT_FEATURE_CQM_RSSI_LIST = 13, - NL80211_EXT_FEATURE_FILS_SK_OFFLOAD = 14, - NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK = 15, - NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X = 16, - NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME = 17, - NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP = 18, - NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE = 19, - NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 20, - NL80211_EXT_FEATURE_MFP_OPTIONAL = 21, - NL80211_EXT_FEATURE_LOW_SPAN_SCAN = 22, - NL80211_EXT_FEATURE_LOW_POWER_SCAN = 23, - NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN = 24, - NL80211_EXT_FEATURE_DFS_OFFLOAD = 25, - NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211 = 26, - NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT = 27, - NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = 27, - NL80211_EXT_FEATURE_TXQS = 28, - NL80211_EXT_FEATURE_SCAN_RANDOM_SN = 29, - NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT = 30, - NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 = 31, - NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER = 32, - NL80211_EXT_FEATURE_AIRTIME_FAIRNESS = 33, - NL80211_EXT_FEATURE_AP_PMKSA_CACHING = 34, - NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD = 35, - NL80211_EXT_FEATURE_EXT_KEY_ID = 36, - NL80211_EXT_FEATURE_STA_TX_PWR = 37, - NL80211_EXT_FEATURE_SAE_OFFLOAD = 38, - NL80211_EXT_FEATURE_VLAN_OFFLOAD = 39, - NL80211_EXT_FEATURE_AQL = 40, - NL80211_EXT_FEATURE_BEACON_PROTECTION = 41, - NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH = 42, - NL80211_EXT_FEATURE_PROTECTED_TWT = 43, - NL80211_EXT_FEATURE_DEL_IBSS_STA = 44, - NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS = 45, - NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT = 46, - NL80211_EXT_FEATURE_SCAN_FREQ_KHZ = 47, - NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS = 48, - NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION = 49, - NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK = 50, - NL80211_EXT_FEATURE_SAE_OFFLOAD_AP = 51, - NL80211_EXT_FEATURE_FILS_DISCOVERY = 52, - NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP = 53, - NUM_NL80211_EXT_FEATURES = 54, - MAX_NL80211_EXT_FEATURES = 53, -}; - -enum nl80211_dfs_state { - NL80211_DFS_USABLE = 0, - NL80211_DFS_UNAVAILABLE = 1, - NL80211_DFS_AVAILABLE = 2, -}; - -struct nl80211_vendor_cmd_info { - __u32 vendor_id; - __u32 subcmd; -}; - -struct ieee80211_he_cap_elem { - u8 mac_cap_info[6]; - u8 phy_cap_info[11]; -}; - -struct ieee80211_he_mcs_nss_supp { - __le16 rx_mcs_80; - __le16 tx_mcs_80; - __le16 rx_mcs_160; - __le16 tx_mcs_160; - __le16 rx_mcs_80p80; - __le16 tx_mcs_80p80; -}; - -struct ieee80211_he_6ghz_capa { - __le16 capa; -}; - -enum environment_cap { - ENVIRON_ANY = 0, - ENVIRON_INDOOR = 1, - ENVIRON_OUTDOOR = 2, -}; - -struct regulatory_request { - struct callback_head callback_head; - int wiphy_idx; - enum nl80211_reg_initiator initiator; - enum nl80211_user_reg_hint_type user_reg_hint_type; - char alpha2[3]; - enum nl80211_dfs_regions dfs_region; - bool intersect; - bool processed; - enum environment_cap country_ie_env; - struct list_head list; -}; - -struct ieee80211_freq_range { - u32 start_freq_khz; - u32 end_freq_khz; - u32 max_bandwidth_khz; -}; - -struct ieee80211_power_rule { - u32 max_antenna_gain; - u32 max_eirp; -}; - -struct ieee80211_wmm_ac { - u16 cw_min; - u16 cw_max; - u16 cot; - u8 aifsn; -}; - -struct ieee80211_wmm_rule { - struct ieee80211_wmm_ac client[4]; - struct ieee80211_wmm_ac ap[4]; -}; - -struct ieee80211_reg_rule { - struct ieee80211_freq_range freq_range; - struct ieee80211_power_rule power_rule; - struct ieee80211_wmm_rule wmm_rule; - u32 flags; - u32 dfs_cac_ms; - bool has_wmm; -}; - -struct ieee80211_regdomain { - struct callback_head callback_head; - u32 n_reg_rules; - char alpha2[3]; - enum nl80211_dfs_regions dfs_region; - struct ieee80211_reg_rule reg_rules[0]; -}; - -struct ieee80211_channel { - enum nl80211_band band; - u32 center_freq; - u16 freq_offset; - u16 hw_value; - u32 flags; - int max_antenna_gain; - int max_power; - int max_reg_power; - bool beacon_found; - u32 orig_flags; - int orig_mag; - int orig_mpwr; - enum nl80211_dfs_state dfs_state; - long unsigned int dfs_state_entered; - unsigned int dfs_cac_ms; -}; - -struct ieee80211_rate { - u32 flags; - u16 bitrate; - u16 hw_value; - u16 hw_value_short; -}; - -struct ieee80211_sta_ht_cap { - u16 cap; - bool ht_supported; - u8 ampdu_factor; - u8 ampdu_density; - struct ieee80211_mcs_info mcs; - char: 8; -} __attribute__((packed)); - -struct ieee80211_sta_vht_cap { - bool vht_supported; - u32 cap; - struct ieee80211_vht_mcs_info vht_mcs; -}; - -struct ieee80211_sta_he_cap { - bool has_he; - struct ieee80211_he_cap_elem he_cap_elem; - struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp; - u8 ppe_thres[25]; -} __attribute__((packed)); - -struct ieee80211_sband_iftype_data { - u16 types_mask; - struct ieee80211_sta_he_cap he_cap; - struct ieee80211_he_6ghz_capa he_6ghz_capa; - char: 8; -} __attribute__((packed)); - -struct ieee80211_sta_s1g_cap { - bool s1g; - u8 cap[10]; - u8 nss_mcs[5]; -}; - -struct ieee80211_supported_band { - struct ieee80211_channel *channels; - struct ieee80211_rate *bitrates; - enum nl80211_band band; - int n_channels; - int n_bitrates; - struct ieee80211_sta_ht_cap ht_cap; - struct ieee80211_sta_vht_cap vht_cap; - struct ieee80211_sta_s1g_cap s1g_cap; - struct ieee80211_edmg edmg_cap; - u16 n_iftype_data; - const struct ieee80211_sband_iftype_data *iftype_data; -}; - -struct key_params { - const u8 *key; - const u8 *seq; - int key_len; - int seq_len; - u16 vlan_id; - u32 cipher; - enum nl80211_key_mode mode; -}; - -struct mac_address { - u8 addr[6]; -}; - -struct cfg80211_ssid { - u8 ssid[32]; - u8 ssid_len; -}; - -enum cfg80211_signal_type { - CFG80211_SIGNAL_TYPE_NONE = 0, - CFG80211_SIGNAL_TYPE_MBM = 1, - CFG80211_SIGNAL_TYPE_UNSPEC = 2, -}; - -struct ieee80211_txrx_stypes; - -struct ieee80211_iface_combination; - -struct wiphy_iftype_akm_suites; - -struct wiphy_wowlan_support; - -struct cfg80211_wowlan; - -struct wiphy_iftype_ext_capab; - -struct wiphy_coalesce_support; - -struct wiphy_vendor_command; - -struct cfg80211_pmsr_capabilities; - -struct wiphy { - u8 perm_addr[6]; - u8 addr_mask[6]; - struct mac_address *addresses; - const struct ieee80211_txrx_stypes *mgmt_stypes; - const struct ieee80211_iface_combination *iface_combinations; - int n_iface_combinations; - u16 software_iftypes; - u16 n_addresses; - u16 interface_modes; - u16 max_acl_mac_addrs; - u32 flags; - u32 regulatory_flags; - u32 features; - u8 ext_features[7]; - u32 ap_sme_capa; - enum cfg80211_signal_type signal_type; - int bss_priv_size; - u8 max_scan_ssids; - u8 max_sched_scan_reqs; - u8 max_sched_scan_ssids; - u8 max_match_sets; - u16 max_scan_ie_len; - u16 max_sched_scan_ie_len; - u32 max_sched_scan_plans; - u32 max_sched_scan_plan_interval; - u32 max_sched_scan_plan_iterations; - int n_cipher_suites; - const u32 *cipher_suites; - int n_akm_suites; - const u32 *akm_suites; - const struct wiphy_iftype_akm_suites *iftype_akm_suites; - unsigned int num_iftype_akm_suites; - u8 retry_short; - u8 retry_long; - u32 frag_threshold; - u32 rts_threshold; - u8 coverage_class; - char fw_version[32]; - u32 hw_version; - const struct wiphy_wowlan_support *wowlan; - struct cfg80211_wowlan *wowlan_config; - u16 max_remain_on_channel_duration; - u8 max_num_pmkids; - u32 available_antennas_tx; - u32 available_antennas_rx; - u32 probe_resp_offload; - const u8 *extended_capabilities; - const u8 *extended_capabilities_mask; - u8 extended_capabilities_len; - const struct wiphy_iftype_ext_capab *iftype_ext_capab; - unsigned int num_iftype_ext_capab; - const void *privid; - struct ieee80211_supported_band *bands[5]; - void (*reg_notifier)(struct wiphy *, struct regulatory_request *); - const struct ieee80211_regdomain *regd; - struct device dev; - bool registered; - struct dentry *debugfsdir; - const struct ieee80211_ht_cap *ht_capa_mod_mask; - const struct ieee80211_vht_cap *vht_capa_mod_mask; - struct list_head wdev_list; - possible_net_t _net; - const struct iw_handler_def *wext; - const struct wiphy_coalesce_support *coalesce; - const struct wiphy_vendor_command *vendor_commands; - const struct nl80211_vendor_cmd_info *vendor_events; - int n_vendor_commands; - int n_vendor_events; - u16 max_ap_assoc_sta; - u8 max_num_csa_counters; - u32 bss_select_support; - u8 nan_supported_bands; - u32 txq_limit; - u32 txq_memory_limit; - u32 txq_quantum; - long unsigned int tx_queue_len; - u8 support_mbssid: 1; - u8 support_only_he_mbssid: 1; - const struct cfg80211_pmsr_capabilities *pmsr_capa; - struct { - u64 peer; - u64 vif; - u8 max_retry; - } tid_config_support; - u8 max_data_retry_count; - long: 56; - long: 64; - char priv[0]; -}; - -struct cfg80211_match_set { - struct cfg80211_ssid ssid; - u8 bssid[6]; - s32 rssi_thold; - s32 per_band_rssi_thold[5]; -}; - -struct cfg80211_sched_scan_plan { - u32 interval; - u32 iterations; -}; - -struct cfg80211_sched_scan_request { - u64 reqid; - struct cfg80211_ssid *ssids; - int n_ssids; - u32 n_channels; - enum nl80211_bss_scan_width scan_width; - const u8 *ie; - size_t ie_len; - u32 flags; - struct cfg80211_match_set *match_sets; - int n_match_sets; - s32 min_rssi_thold; - u32 delay; - struct cfg80211_sched_scan_plan *scan_plans; - int n_scan_plans; - u8 mac_addr[6]; - u8 mac_addr_mask[6]; - bool relative_rssi_set; - s8 relative_rssi; - struct cfg80211_bss_select_adjust rssi_adjust; - struct wiphy *wiphy; - struct net_device *dev; - long unsigned int scan_start; - bool report_results; - struct callback_head callback_head; - u32 owner_nlportid; - bool nl_owner_dead; - struct list_head list; - struct ieee80211_channel *channels[0]; -}; - -struct cfg80211_pkt_pattern { - const u8 *mask; - const u8 *pattern; - int pattern_len; - int pkt_offset; -}; - -struct cfg80211_wowlan_tcp { - struct socket *sock; - __be32 src; - __be32 dst; - u16 src_port; - u16 dst_port; - u8 dst_mac[6]; - int payload_len; - const u8 *payload; - struct nl80211_wowlan_tcp_data_seq payload_seq; - u32 data_interval; - u32 wake_len; - const u8 *wake_data; - const u8 *wake_mask; - u32 tokens_size; - struct nl80211_wowlan_tcp_data_token payload_tok; -}; - -struct cfg80211_wowlan { - bool any; - bool disconnect; - bool magic_pkt; - bool gtk_rekey_failure; - bool eap_identity_req; - bool four_way_handshake; - bool rfkill_release; - struct cfg80211_pkt_pattern *patterns; - struct cfg80211_wowlan_tcp *tcp; - int n_patterns; - struct cfg80211_sched_scan_request *nd_config; -}; - -struct ieee80211_iface_limit { - u16 max; - u16 types; -}; - -struct ieee80211_iface_combination { - const struct ieee80211_iface_limit *limits; - u32 num_different_channels; - u16 max_interfaces; - u8 n_limits; - bool beacon_int_infra_match; - u8 radar_detect_widths; - u8 radar_detect_regions; - u32 beacon_int_min_gcd; -}; - -struct ieee80211_txrx_stypes { - u16 tx; - u16 rx; -}; - -struct wiphy_wowlan_tcp_support { - const struct nl80211_wowlan_tcp_data_token_feature *tok; - u32 data_payload_max; - u32 data_interval_max; - u32 wake_payload_max; - bool seq; -}; - -struct wiphy_wowlan_support { - u32 flags; - int n_patterns; - int pattern_max_len; - int pattern_min_len; - int max_pkt_offset; - int max_nd_match_sets; - const struct wiphy_wowlan_tcp_support *tcp; -}; - -struct wiphy_coalesce_support { - int n_rules; - int max_delay; - int n_patterns; - int pattern_max_len; - int pattern_min_len; - int max_pkt_offset; -}; - -struct wiphy_vendor_command { - struct nl80211_vendor_cmd_info info; - u32 flags; - int (*doit)(struct wiphy *, struct wireless_dev *, const void *, int); - int (*dumpit)(struct wiphy *, struct wireless_dev *, struct sk_buff *, const void *, int, long unsigned int *); - const struct nla_policy *policy; - unsigned int maxattr; -}; - -struct wiphy_iftype_ext_capab { - enum nl80211_iftype iftype; - const u8 *extended_capabilities; - const u8 *extended_capabilities_mask; - u8 extended_capabilities_len; -}; - -struct cfg80211_pmsr_capabilities { - unsigned int max_peers; - u8 report_ap_tsf: 1; - u8 randomize_mac_addr: 1; - struct { - u32 preambles; - u32 bandwidths; - s8 max_bursts_exponent; - u8 max_ftms_per_burst; - u8 supported: 1; - u8 asap: 1; - u8 non_asap: 1; - u8 request_lci: 1; - u8 request_civicloc: 1; - u8 trigger_based: 1; - u8 non_trigger_based: 1; - } ftm; -}; - -struct wiphy_iftype_akm_suites { - u16 iftypes_mask; - const u32 *akm_suites; - int n_akm_suites; -}; - -struct iw_ioctl_description { - __u8 header_type; - __u8 token_type; - __u16 token_size; - __u16 min_tokens; - __u16 max_tokens; - __u32 flags; -}; - -typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, unsigned int, struct iw_request_info *, iw_handler); - -struct iw_thrspy { - struct sockaddr addr; - struct iw_quality qual; - struct iw_quality low; - struct iw_quality high; -}; - -enum dns_payload_content_type { - DNS_PAYLOAD_IS_SERVER_LIST = 0, -}; - -struct dns_payload_header { - __u8 zero; - __u8 content; - __u8 version; -}; - -enum { - dns_key_data = 0, - dns_key_error = 1, -}; - -enum l3mdev_type { - L3MDEV_TYPE_UNSPEC = 0, - L3MDEV_TYPE_VRF = 1, - __L3MDEV_TYPE_MAX = 2, -}; - -typedef int (*lookup_by_table_id_t)(struct net *, u32); - -struct l3mdev_handler { - lookup_by_table_id_t dev_lookup; -}; - -typedef struct { - u32 version; - u32 length; - u64 memory_protection_attribute; -} efi_properties_table_t; - -enum efi_secureboot_mode { - efi_secureboot_mode_unset = 0, - efi_secureboot_mode_unknown = 1, - efi_secureboot_mode_disabled = 2, - efi_secureboot_mode_enabled = 3, -}; - -typedef union { - struct { - u32 revision; - efi_handle_t parent_handle; - efi_system_table_t *system_table; - efi_handle_t device_handle; - void *file_path; - void *reserved; - u32 load_options_size; - void *load_options; - void *image_base; - __u64 image_size; - unsigned int image_code_type; - unsigned int image_data_type; - efi_status_t (*unload)(efi_handle_t); - }; - struct { - u32 revision; - u32 parent_handle; - u32 system_table; - u32 device_handle; - u32 file_path; - u32 reserved; - u32 load_options_size; - u32 load_options; - u32 image_base; - __u64 image_size; - u32 image_code_type; - u32 image_data_type; - u32 unload; - } mixed_mode; -} efi_loaded_image_t; - -struct efi_boot_memmap { - efi_memory_desc_t **map; - long unsigned int *map_size; - long unsigned int *desc_size; - u32 *desc_ver; - long unsigned int *key_ptr; - long unsigned int *buff_size; -}; - -struct exit_boot_struct { - efi_memory_desc_t *runtime_map; - int *runtime_entry_count; - void *new_fdt_addr; -}; - -typedef struct { - u64 size; - u64 file_size; - u64 phys_size; - efi_time_t create_time; - efi_time_t last_access_time; - efi_time_t modification_time; - __u64 attribute; - efi_char16_t filename[0]; -} efi_file_info_t; - -struct efi_file_protocol; - -typedef struct efi_file_protocol efi_file_protocol_t; - -struct efi_file_protocol { - u64 revision; - efi_status_t (*open)(efi_file_protocol_t *, efi_file_protocol_t **, efi_char16_t *, u64, u64); - efi_status_t (*close)(efi_file_protocol_t *); - efi_status_t (*delete)(efi_file_protocol_t *); - efi_status_t (*read)(efi_file_protocol_t *, long unsigned int *, void *); - efi_status_t (*write)(efi_file_protocol_t *, long unsigned int, void *); - efi_status_t (*get_position)(efi_file_protocol_t *, u64 *); - efi_status_t (*set_position)(efi_file_protocol_t *, u64); - efi_status_t (*get_info)(efi_file_protocol_t *, efi_guid_t *, long unsigned int *, void *); - efi_status_t (*set_info)(efi_file_protocol_t *, efi_guid_t *, long unsigned int, void *); - efi_status_t (*flush)(efi_file_protocol_t *); -}; - -struct efi_simple_file_system_protocol; - -typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t; - -struct efi_simple_file_system_protocol { - u64 revision; - int (*open_volume)(efi_simple_file_system_protocol_t *, efi_file_protocol_t **); -}; - -struct finfo { - efi_file_info_t info; - efi_char16_t filename[256]; -}; - -typedef struct { - u32 red_mask; - u32 green_mask; - u32 blue_mask; - u32 reserved_mask; -} efi_pixel_bitmask_t; - -typedef struct { - u32 version; - u32 horizontal_resolution; - u32 vertical_resolution; - int pixel_format; - efi_pixel_bitmask_t pixel_information; - u32 pixels_per_scan_line; -} efi_graphics_output_mode_info_t; - -union efi_graphics_output_protocol_mode { - struct { - u32 max_mode; - u32 mode; - efi_graphics_output_mode_info_t *info; - long unsigned int size_of_info; - efi_physical_addr_t frame_buffer_base; - long unsigned int frame_buffer_size; - }; - struct { - u32 max_mode; - u32 mode; - u32 info; - u32 size_of_info; - u64 frame_buffer_base; - u32 frame_buffer_size; - } mixed_mode; -}; - -typedef union efi_graphics_output_protocol_mode efi_graphics_output_protocol_mode_t; - -union efi_graphics_output_protocol; - -typedef union efi_graphics_output_protocol efi_graphics_output_protocol_t; - -union efi_graphics_output_protocol { - struct { - efi_status_t (*query_mode)(efi_graphics_output_protocol_t *, u32, long unsigned int *, efi_graphics_output_mode_info_t **); - efi_status_t (*set_mode)(efi_graphics_output_protocol_t *, u32); - void *blt; - efi_graphics_output_protocol_mode_t *mode; - }; - struct { - u32 query_mode; - u32 set_mode; - u32 blt; - u32 mode; - } mixed_mode; -}; - -enum efi_cmdline_option { - EFI_CMDLINE_NONE = 0, - EFI_CMDLINE_MODE_NUM = 1, - EFI_CMDLINE_RES = 2, - EFI_CMDLINE_AUTO = 3, - EFI_CMDLINE_LIST = 4, -}; - -union efi_rng_protocol; - -typedef union efi_rng_protocol efi_rng_protocol_t; - -union efi_rng_protocol { - struct { - efi_status_t (*get_info)(efi_rng_protocol_t *, long unsigned int *, efi_guid_t *); - efi_status_t (*get_rng)(efi_rng_protocol_t *, efi_guid_t *, long unsigned int, u8 *); - }; - struct { - u32 get_info; - u32 get_rng; - } mixed_mode; -}; - -struct tcpa_event { - u32 pcr_index; - u32 event_type; - u8 pcr_value[20]; - u32 event_size; - u8 event_data[0]; -}; - -typedef u32 efi_tcg2_event_log_format; - -union efi_tcg2_protocol { - struct { - void *get_capability; - efi_status_t (*get_event_log)(efi_handle_t, efi_tcg2_event_log_format, efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *); - void *hash_log_extend_event; - void *submit_command; - void *get_active_pcr_banks; - void *set_active_pcr_banks; - void *get_result_of_set_active_pcr_banks; - }; - struct { - u32 get_capability; - u32 get_event_log; - u32 hash_log_extend_event; - u32 submit_command; - u32 get_active_pcr_banks; - u32 set_active_pcr_banks; - u32 get_result_of_set_active_pcr_banks; - } mixed_mode; -}; - -typedef union efi_tcg2_protocol efi_tcg2_protocol_t; - -struct efi_vendor_dev_path { - struct efi_generic_dev_path header; - efi_guid_t vendorguid; - u8 vendordata[0]; -}; - -union efi_load_file_protocol; - -typedef union efi_load_file_protocol efi_load_file_protocol_t; - -union efi_load_file_protocol { - struct { - efi_status_t (*load_file)(efi_load_file_protocol_t *, efi_device_path_protocol_t *, bool, long unsigned int *, void *); - }; - struct { - u32 load_file; - } mixed_mode; -}; - -typedef union efi_load_file_protocol efi_load_file2_protocol_t; - -typedef struct { - u32 attributes; - u16 file_path_list_length; - u8 variable_data[0]; -} __attribute__((packed)) efi_load_option_t; - -typedef struct { - u32 attributes; - u16 file_path_list_length; - const efi_char16_t *description; - const efi_device_path_protocol_t *file_path_list; - size_t optional_data_size; - const void *optional_data; -} efi_load_option_unpacked_t; - -typedef efi_status_t (*efi_exit_boot_map_processing)(struct efi_boot_memmap *, void *); - -typedef enum { - EfiPciIoWidthUint8 = 0, - EfiPciIoWidthUint16 = 1, - EfiPciIoWidthUint32 = 2, - EfiPciIoWidthUint64 = 3, - EfiPciIoWidthFifoUint8 = 4, - EfiPciIoWidthFifoUint16 = 5, - EfiPciIoWidthFifoUint32 = 6, - EfiPciIoWidthFifoUint64 = 7, - EfiPciIoWidthFillUint8 = 8, - EfiPciIoWidthFillUint16 = 9, - EfiPciIoWidthFillUint32 = 10, - EfiPciIoWidthFillUint64 = 11, - EfiPciIoWidthMaximum = 12, -} EFI_PCI_IO_PROTOCOL_WIDTH; - -typedef struct { - u32 read; - u32 write; -} efi_pci_io_protocol_access_32_t; - -typedef struct { - void *read; - void *write; -} efi_pci_io_protocol_access_t; - -union efi_pci_io_protocol; - -typedef union efi_pci_io_protocol efi_pci_io_protocol_t; - -typedef efi_status_t (*efi_pci_io_protocol_cfg_t)(efi_pci_io_protocol_t *, EFI_PCI_IO_PROTOCOL_WIDTH, u32, long unsigned int, void *); - -typedef struct { - efi_pci_io_protocol_cfg_t read; - efi_pci_io_protocol_cfg_t write; -} efi_pci_io_protocol_config_access_t; - -union efi_pci_io_protocol { - struct { - void *poll_mem; - void *poll_io; - efi_pci_io_protocol_access_t mem; - efi_pci_io_protocol_access_t io; - efi_pci_io_protocol_config_access_t pci; - void *copy_mem; - void *map; - void *unmap; - void *allocate_buffer; - void *free_buffer; - void *flush; - efi_status_t (*get_location)(efi_pci_io_protocol_t *, long unsigned int *, long unsigned int *, long unsigned int *, long unsigned int *); - void *attributes; - void *get_bar_attributes; - void *set_bar_attributes; - uint64_t romsize; - void *romimage; - }; - struct { - u32 poll_mem; - u32 poll_io; - efi_pci_io_protocol_access_32_t mem; - efi_pci_io_protocol_access_32_t io; - efi_pci_io_protocol_access_32_t pci; - u32 copy_mem; - u32 map; - u32 unmap; - u32 allocate_buffer; - u32 free_buffer; - u32 flush; - u32 get_location; - u32 attributes; - u32 get_bar_attributes; - u32 set_bar_attributes; - u64 romsize; - u32 romimage; - } mixed_mode; -}; - -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute pop -#endif - -#endif /* __VMLINUX_H__ */ \ No newline at end of file diff --git a/ebpf/bpf/vmlinux/vmlinux-x86.h b/ebpf/bpf/vmlinux/vmlinux-x86.h deleted file mode 100644 index 8a68e45a13..0000000000 --- a/ebpf/bpf/vmlinux/vmlinux-x86.h +++ /dev/null @@ -1,120348 +0,0 @@ -#ifndef __VMLINUX_H__ -#define __VMLINUX_H__ - -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) -#endif - -typedef unsigned char __u8; - -typedef short int __s16; - -typedef short unsigned int __u16; - -typedef int __s32; - -typedef unsigned int __u32; - -typedef long long int __s64; - -typedef long long unsigned int __u64; - -typedef __u8 u8; - -typedef __s16 s16; - -typedef __u16 u16; - -typedef __s32 s32; - -typedef __u32 u32; - -typedef __s64 s64; - -typedef __u64 u64; - -enum { - false = 0, - true = 1, -}; - -typedef long int __kernel_long_t; - -typedef long unsigned int __kernel_ulong_t; - -typedef int __kernel_pid_t; - -typedef unsigned int __kernel_uid32_t; - -typedef unsigned int __kernel_gid32_t; - -typedef __kernel_ulong_t __kernel_size_t; - -typedef __kernel_long_t __kernel_ssize_t; - -typedef long long int __kernel_loff_t; - -typedef long long int __kernel_time64_t; - -typedef __kernel_long_t __kernel_clock_t; - -typedef int __kernel_timer_t; - -typedef int __kernel_clockid_t; - -typedef unsigned int __poll_t; - -typedef u32 __kernel_dev_t; - -typedef __kernel_dev_t dev_t; - -typedef short unsigned int umode_t; - -typedef __kernel_pid_t pid_t; - -typedef __kernel_clockid_t clockid_t; - -typedef _Bool bool; - -typedef __kernel_uid32_t uid_t; - -typedef __kernel_gid32_t gid_t; - -typedef __kernel_loff_t loff_t; - -typedef __kernel_size_t size_t; - -typedef __kernel_ssize_t ssize_t; - -typedef s32 int32_t; - -typedef u32 uint32_t; - -typedef u64 sector_t; - -typedef u64 blkcnt_t; - -typedef unsigned int gfp_t; - -typedef unsigned int fmode_t; - -typedef u64 phys_addr_t; - -typedef struct { - int counter; -} atomic_t; - -typedef struct { - s64 counter; -} atomic64_t; - -struct list_head { - struct list_head *next; - struct list_head *prev; -}; - -struct hlist_node; - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next; - struct hlist_node **pprev; -}; - -struct callback_head { - struct callback_head *next; - void (*func)(struct callback_head *); -}; - -struct lock_class_key {}; - -struct fs_context; - -struct fs_parameter_spec; - -struct dentry; - -struct super_block; - -struct module; - -struct file_system_type { - const char *name; - int fs_flags; - int (*init_fs_context)(struct fs_context *); - const struct fs_parameter_spec *parameters; - struct dentry * (*mount)(struct file_system_type *, int, const char *, void *); - void (*kill_sb)(struct super_block *); - struct module *owner; - struct file_system_type *next; - struct hlist_head fs_supers; - struct lock_class_key s_lock_key; - struct lock_class_key s_umount_key; - struct lock_class_key s_vfs_rename_key; - struct lock_class_key s_writers_key[3]; - struct lock_class_key i_lock_key; - struct lock_class_key i_mutex_key; - struct lock_class_key i_mutex_dir_key; -}; - -struct qspinlock { - union { - atomic_t val; - struct { - u8 locked; - u8 pending; - }; - struct { - u16 locked_pending; - u16 tail; - }; - }; -}; - -typedef struct qspinlock arch_spinlock_t; - -struct qrwlock { - union { - atomic_t cnts; - struct { - u8 wlocked; - u8 __lstate[3]; - }; - }; - arch_spinlock_t wait_lock; -}; - -typedef struct qrwlock arch_rwlock_t; - -struct raw_spinlock { - arch_spinlock_t raw_lock; -}; - -typedef struct raw_spinlock raw_spinlock_t; - -struct spinlock { - union { - struct raw_spinlock rlock; - }; -}; - -typedef struct spinlock spinlock_t; - -typedef struct { - arch_rwlock_t raw_lock; -} rwlock_t; - -struct ratelimit_state { - raw_spinlock_t lock; - int interval; - int burst; - int printed; - int missed; - long unsigned int begin; - long unsigned int flags; -}; - -typedef void *fl_owner_t; - -struct file; - -struct kiocb; - -struct iov_iter; - -struct dir_context; - -struct poll_table_struct; - -struct vm_area_struct; - -struct inode; - -struct file_lock; - -struct page; - -struct pipe_inode_info; - -struct seq_file; - -struct file_operations { - struct module *owner; - loff_t (*llseek)(struct file *, loff_t, int); - ssize_t (*read)(struct file *, char *, size_t, loff_t *); - ssize_t (*write)(struct file *, const char *, size_t, loff_t *); - ssize_t (*read_iter)(struct kiocb *, struct iov_iter *); - ssize_t (*write_iter)(struct kiocb *, struct iov_iter *); - int (*iopoll)(struct kiocb *, bool); - int (*iterate)(struct file *, struct dir_context *); - int (*iterate_shared)(struct file *, struct dir_context *); - __poll_t (*poll)(struct file *, struct poll_table_struct *); - long int (*unlocked_ioctl)(struct file *, unsigned int, long unsigned int); - long int (*compat_ioctl)(struct file *, unsigned int, long unsigned int); - int (*mmap)(struct file *, struct vm_area_struct *); - long unsigned int mmap_supported_flags; - int (*open)(struct inode *, struct file *); - int (*flush)(struct file *, fl_owner_t); - int (*release)(struct inode *, struct file *); - int (*fsync)(struct file *, loff_t, loff_t, int); - int (*fasync)(int, struct file *, int); - int (*lock)(struct file *, int, struct file_lock *); - ssize_t (*sendpage)(struct file *, struct page *, int, size_t, loff_t *, int); - long unsigned int (*get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - int (*check_flags)(int); - int (*flock)(struct file *, int, struct file_lock *); - ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); - ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); - int (*setlease)(struct file *, long int, struct file_lock **, void **); - long int (*fallocate)(struct file *, int, loff_t, loff_t); - void (*show_fdinfo)(struct seq_file *, struct file *); - ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); - loff_t (*remap_file_range)(struct file *, loff_t, struct file *, loff_t, loff_t, unsigned int); - int (*fadvise)(struct file *, loff_t, loff_t, int); -}; - -typedef __s64 time64_t; - -struct __kernel_timespec { - __kernel_time64_t tv_sec; - long long int tv_nsec; -}; - -struct timespec64 { - time64_t tv_sec; - long int tv_nsec; -}; - -enum timespec_type { - TT_NONE = 0, - TT_NATIVE = 1, - TT_COMPAT = 2, -}; - -typedef s32 old_time32_t; - -struct old_timespec32 { - old_time32_t tv_sec; - s32 tv_nsec; -}; - -struct pollfd; - -struct restart_block { - long unsigned int arch_data; - long int (*fn)(struct restart_block *); - union { - struct { - u32 *uaddr; - u32 val; - u32 flags; - u32 bitset; - u64 time; - u32 *uaddr2; - } futex; - struct { - clockid_t clockid; - enum timespec_type type; - union { - struct __kernel_timespec *rmtp; - struct old_timespec32 *compat_rmtp; - }; - u64 expires; - } nanosleep; - struct { - struct pollfd *ufds; - int nfds; - int has_timeout; - long unsigned int tv_sec; - long unsigned int tv_nsec; - } poll; - }; -}; - -struct thread_info { - long unsigned int flags; - long unsigned int syscall_work; - u32 status; -}; - -struct refcount_struct { - atomic_t refs; -}; - -typedef struct refcount_struct refcount_t; - -struct llist_node { - struct llist_node *next; -}; - -struct __call_single_node { - struct llist_node llist; - union { - unsigned int u_flags; - atomic_t a_flags; - }; - u16 src; - u16 dst; -}; - -struct load_weight { - long unsigned int weight; - u32 inv_weight; -}; - -struct rb_node { - long unsigned int __rb_parent_color; - struct rb_node *rb_right; - struct rb_node *rb_left; -}; - -struct sched_statistics { - u64 wait_start; - u64 wait_max; - u64 wait_count; - u64 wait_sum; - u64 iowait_count; - u64 iowait_sum; - u64 sleep_start; - u64 sleep_max; - s64 sum_sleep_runtime; - u64 block_start; - u64 block_max; - u64 exec_max; - u64 slice_max; - u64 nr_migrations_cold; - u64 nr_failed_migrations_affine; - u64 nr_failed_migrations_running; - u64 nr_failed_migrations_hot; - u64 nr_forced_migrations; - u64 nr_wakeups; - u64 nr_wakeups_sync; - u64 nr_wakeups_migrate; - u64 nr_wakeups_local; - u64 nr_wakeups_remote; - u64 nr_wakeups_affine; - u64 nr_wakeups_affine_attempts; - u64 nr_wakeups_passive; - u64 nr_wakeups_idle; -}; - -struct util_est { - unsigned int enqueued; - unsigned int ewma; -}; - -struct sched_avg { - u64 last_update_time; - u64 load_sum; - u64 runnable_sum; - u32 util_sum; - u32 period_contrib; - long unsigned int load_avg; - long unsigned int runnable_avg; - long unsigned int util_avg; - struct util_est util_est; -}; - -struct cfs_rq; - -struct sched_entity { - struct load_weight load; - struct rb_node run_node; - struct list_head group_node; - unsigned int on_rq; - u64 exec_start; - u64 sum_exec_runtime; - u64 vruntime; - u64 prev_sum_exec_runtime; - u64 nr_migrations; - struct sched_statistics statistics; - int depth; - struct sched_entity *parent; - struct cfs_rq *cfs_rq; - struct cfs_rq *my_q; - long unsigned int runnable_weight; - long: 64; - long: 64; - long: 64; - struct sched_avg avg; -}; - -struct sched_rt_entity { - struct list_head run_list; - long unsigned int timeout; - long unsigned int watchdog_stamp; - unsigned int time_slice; - short unsigned int on_rq; - short unsigned int on_list; - struct sched_rt_entity *back; -}; - -typedef s64 ktime_t; - -struct timerqueue_node { - struct rb_node node; - ktime_t expires; -}; - -enum hrtimer_restart { - HRTIMER_NORESTART = 0, - HRTIMER_RESTART = 1, -}; - -struct hrtimer_clock_base; - -struct hrtimer { - struct timerqueue_node node; - ktime_t _softexpires; - enum hrtimer_restart (*function)(struct hrtimer *); - struct hrtimer_clock_base *base; - u8 state; - u8 is_rel; - u8 is_soft; - u8 is_hard; -}; - -struct sched_dl_entity { - struct rb_node rb_node; - u64 dl_runtime; - u64 dl_deadline; - u64 dl_period; - u64 dl_bw; - u64 dl_density; - s64 runtime; - u64 deadline; - unsigned int flags; - unsigned int dl_throttled: 1; - unsigned int dl_yielded: 1; - unsigned int dl_non_contending: 1; - unsigned int dl_overrun: 1; - struct hrtimer dl_timer; - struct hrtimer inactive_timer; - struct sched_dl_entity *pi_se; -}; - -struct uclamp_se { - unsigned int value: 11; - unsigned int bucket_id: 3; - unsigned int active: 1; - unsigned int user_defined: 1; -}; - -struct cpumask { - long unsigned int bits[5]; -}; - -typedef struct cpumask cpumask_t; - -union rcu_special { - struct { - u8 blocked; - u8 need_qs; - u8 exp_hint; - u8 need_mb; - } b; - u32 s; -}; - -struct sched_info { - long unsigned int pcount; - long long unsigned int run_delay; - long long unsigned int last_arrival; - long long unsigned int last_queued; -}; - -struct plist_node { - int prio; - struct list_head prio_list; - struct list_head node_list; -}; - -struct vmacache { - u64 seqnum; - struct vm_area_struct *vmas[4]; -}; - -struct task_rss_stat { - int events; - int count[4]; -}; - -struct prev_cputime { - u64 utime; - u64 stime; - raw_spinlock_t lock; -}; - -struct rb_root { - struct rb_node *rb_node; -}; - -struct rb_root_cached { - struct rb_root rb_root; - struct rb_node *rb_leftmost; -}; - -struct timerqueue_head { - struct rb_root_cached rb_root; -}; - -struct posix_cputimer_base { - u64 nextevt; - struct timerqueue_head tqhead; -}; - -struct posix_cputimers { - struct posix_cputimer_base bases[3]; - unsigned int timers_active; - unsigned int expiry_active; -}; - -struct posix_cputimers_work { - struct callback_head work; - unsigned int scheduled; -}; - -struct sem_undo_list; - -struct sysv_sem { - struct sem_undo_list *undo_list; -}; - -struct sysv_shm { - struct list_head shm_clist; -}; - -typedef struct { - long unsigned int sig[1]; -} sigset_t; - -struct sigpending { - struct list_head list; - sigset_t signal; -}; - -typedef struct { - uid_t val; -} kuid_t; - -struct seccomp_filter; - -struct seccomp { - int mode; - atomic_t filter_count; - struct seccomp_filter *filter; -}; - -struct syscall_user_dispatch { - char *selector; - long unsigned int offset; - long unsigned int len; - bool on_dispatch; -}; - -struct wake_q_node { - struct wake_q_node *next; -}; - -struct task_io_accounting { - u64 rchar; - u64 wchar; - u64 syscr; - u64 syscw; - u64 read_bytes; - u64 write_bytes; - u64 cancelled_write_bytes; -}; - -typedef struct { - long unsigned int bits[1]; -} nodemask_t; - -struct seqcount { - unsigned int sequence; -}; - -typedef struct seqcount seqcount_t; - -struct seqcount_spinlock { - seqcount_t seqcount; -}; - -typedef struct seqcount_spinlock seqcount_spinlock_t; - -typedef atomic64_t atomic_long_t; - -struct optimistic_spin_queue { - atomic_t tail; -}; - -struct mutex { - atomic_long_t owner; - spinlock_t wait_lock; - struct optimistic_spin_queue osq; - struct list_head wait_list; -}; - -struct arch_tlbflush_unmap_batch { - struct cpumask cpumask; -}; - -struct tlbflush_unmap_batch { - struct arch_tlbflush_unmap_batch arch; - bool flush_required; - bool writable; -}; - -struct page_frag { - struct page *page; - __u32 offset; - __u32 size; -}; - -struct latency_record { - long unsigned int backtrace[12]; - unsigned int count; - long unsigned int time; - long unsigned int max; -}; - -struct kmap_ctrl {}; - -struct llist_head { - struct llist_node *first; -}; - -struct desc_struct { - u16 limit0; - u16 base0; - u16 base1: 8; - u16 type: 4; - u16 s: 1; - u16 dpl: 2; - u16 p: 1; - u16 limit1: 4; - u16 avl: 1; - u16 l: 1; - u16 d: 1; - u16 g: 1; - u16 base2: 8; -}; - -struct fregs_state { - u32 cwd; - u32 swd; - u32 twd; - u32 fip; - u32 fcs; - u32 foo; - u32 fos; - u32 st_space[20]; - u32 status; -}; - -struct fxregs_state { - u16 cwd; - u16 swd; - u16 twd; - u16 fop; - union { - struct { - u64 rip; - u64 rdp; - }; - struct { - u32 fip; - u32 fcs; - u32 foo; - u32 fos; - }; - }; - u32 mxcsr; - u32 mxcsr_mask; - u32 st_space[32]; - u32 xmm_space[64]; - u32 padding[12]; - union { - u32 padding1[12]; - u32 sw_reserved[12]; - }; -}; - -struct math_emu_info; - -struct swregs_state { - u32 cwd; - u32 swd; - u32 twd; - u32 fip; - u32 fcs; - u32 foo; - u32 fos; - u32 st_space[20]; - u8 ftop; - u8 changed; - u8 lookahead; - u8 no_update; - u8 rm; - u8 alimit; - struct math_emu_info *info; - u32 entry_eip; -}; - -struct xstate_header { - u64 xfeatures; - u64 xcomp_bv; - u64 reserved[6]; -}; - -struct xregs_state { - struct fxregs_state i387; - struct xstate_header header; - u8 extended_state_area[0]; -}; - -union fpregs_state { - struct fregs_state fsave; - struct fxregs_state fxsave; - struct swregs_state soft; - struct xregs_state xsave; - u8 __padding[4096]; -}; - -struct fpu { - unsigned int last_cpu; - long unsigned int avx512_timestamp; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union fpregs_state state; -}; - -struct perf_event; - -struct io_bitmap; - -struct thread_struct { - struct desc_struct tls_array[3]; - long unsigned int sp; - short unsigned int es; - short unsigned int ds; - short unsigned int fsindex; - short unsigned int gsindex; - long unsigned int fsbase; - long unsigned int gsbase; - struct perf_event *ptrace_bps[4]; - long unsigned int virtual_dr6; - long unsigned int ptrace_dr7; - long unsigned int cr2; - long unsigned int trap_nr; - long unsigned int error_code; - struct io_bitmap *io_bitmap; - long unsigned int iopl_emul; - unsigned int sig_on_uaccess_err: 1; - u32 pkru; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct fpu fpu; -}; - -struct sched_class; - -struct task_group; - -struct rcu_node; - -struct mm_struct; - -struct pid; - -struct completion; - -struct cred; - -struct key; - -struct nameidata; - -struct fs_struct; - -struct files_struct; - -struct io_uring_task; - -struct nsproxy; - -struct signal_struct; - -struct sighand_struct; - -struct audit_context; - -struct rt_mutex_waiter; - -struct bio_list; - -struct blk_plug; - -struct reclaim_state; - -struct backing_dev_info; - -struct io_context; - -struct capture_control; - -struct kernel_siginfo; - -typedef struct kernel_siginfo kernel_siginfo_t; - -struct css_set; - -struct robust_list_head; - -struct compat_robust_list_head; - -struct futex_pi_state; - -struct perf_event_context; - -struct mempolicy; - -struct numa_group; - -struct rseq; - -struct task_delay_info; - -struct ftrace_ret_stack; - -struct mem_cgroup; - -struct request_queue; - -struct uprobe_task; - -struct vm_struct; - -struct bpf_local_storage; - -struct task_struct { - struct thread_info thread_info; - unsigned int __state; - void *stack; - refcount_t usage; - unsigned int flags; - unsigned int ptrace; - int on_cpu; - struct __call_single_node wake_entry; - unsigned int cpu; - unsigned int wakee_flips; - long unsigned int wakee_flip_decay_ts; - struct task_struct *last_wakee; - int recent_used_cpu; - int wake_cpu; - int on_rq; - int prio; - int static_prio; - int normal_prio; - unsigned int rt_priority; - const struct sched_class *sched_class; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct sched_entity se; - struct sched_rt_entity rt; - struct sched_dl_entity dl; - struct rb_node core_node; - long unsigned int core_cookie; - unsigned int core_occupation; - struct task_group *sched_task_group; - struct uclamp_se uclamp_req[2]; - struct uclamp_se uclamp[2]; - struct hlist_head preempt_notifiers; - unsigned int btrace_seq; - unsigned int policy; - int nr_cpus_allowed; - const cpumask_t *cpus_ptr; - cpumask_t cpus_mask; - void *migration_pending; - short unsigned int migration_disabled; - short unsigned int migration_flags; - int rcu_read_lock_nesting; - union rcu_special rcu_read_unlock_special; - struct list_head rcu_node_entry; - struct rcu_node *rcu_blocked_node; - long unsigned int rcu_tasks_nvcsw; - u8 rcu_tasks_holdout; - u8 rcu_tasks_idx; - int rcu_tasks_idle_cpu; - struct list_head rcu_tasks_holdout_list; - int trc_reader_nesting; - int trc_ipi_to_cpu; - union rcu_special trc_reader_special; - bool trc_reader_checked; - struct list_head trc_holdout_list; - struct sched_info sched_info; - struct list_head tasks; - struct plist_node pushable_tasks; - struct rb_node pushable_dl_tasks; - struct mm_struct *mm; - struct mm_struct *active_mm; - struct vmacache vmacache; - struct task_rss_stat rss_stat; - int exit_state; - int exit_code; - int exit_signal; - int pdeath_signal; - long unsigned int jobctl; - unsigned int personality; - unsigned int sched_reset_on_fork: 1; - unsigned int sched_contributes_to_load: 1; - unsigned int sched_migrated: 1; - unsigned int sched_psi_wake_requeue: 1; - int: 28; - unsigned int sched_remote_wakeup: 1; - unsigned int in_execve: 1; - unsigned int in_iowait: 1; - unsigned int restore_sigmask: 1; - unsigned int in_user_fault: 1; - unsigned int no_cgroup_migration: 1; - unsigned int frozen: 1; - unsigned int use_memdelay: 1; - unsigned int in_memstall: 1; - long unsigned int atomic_flags; - struct restart_block restart_block; - pid_t pid; - pid_t tgid; - long unsigned int stack_canary; - struct task_struct *real_parent; - struct task_struct *parent; - struct list_head children; - struct list_head sibling; - struct task_struct *group_leader; - struct list_head ptraced; - struct list_head ptrace_entry; - struct pid *thread_pid; - struct hlist_node pid_links[4]; - struct list_head thread_group; - struct list_head thread_node; - struct completion *vfork_done; - int *set_child_tid; - int *clear_child_tid; - void *pf_io_worker; - u64 utime; - u64 stime; - u64 gtime; - struct prev_cputime prev_cputime; - long unsigned int nvcsw; - long unsigned int nivcsw; - u64 start_time; - u64 start_boottime; - long unsigned int min_flt; - long unsigned int maj_flt; - struct posix_cputimers posix_cputimers; - struct posix_cputimers_work posix_cputimers_work; - const struct cred *ptracer_cred; - const struct cred *real_cred; - const struct cred *cred; - struct key *cached_requested_key; - char comm[16]; - struct nameidata *nameidata; - struct sysv_sem sysvsem; - struct sysv_shm sysvshm; - long unsigned int last_switch_count; - long unsigned int last_switch_time; - struct fs_struct *fs; - struct files_struct *files; - struct io_uring_task *io_uring; - struct nsproxy *nsproxy; - struct signal_struct *signal; - struct sighand_struct *sighand; - sigset_t blocked; - sigset_t real_blocked; - sigset_t saved_sigmask; - struct sigpending pending; - long unsigned int sas_ss_sp; - size_t sas_ss_size; - unsigned int sas_ss_flags; - struct callback_head *task_works; - struct audit_context *audit_context; - kuid_t loginuid; - unsigned int sessionid; - struct seccomp seccomp; - struct syscall_user_dispatch syscall_dispatch; - u64 parent_exec_id; - u64 self_exec_id; - spinlock_t alloc_lock; - raw_spinlock_t pi_lock; - struct wake_q_node wake_q; - struct rb_root_cached pi_waiters; - struct task_struct *pi_top_task; - struct rt_mutex_waiter *pi_blocked_on; - void *journal_info; - struct bio_list *bio_list; - struct blk_plug *plug; - struct reclaim_state *reclaim_state; - struct backing_dev_info *backing_dev_info; - struct io_context *io_context; - struct capture_control *capture_control; - long unsigned int ptrace_message; - kernel_siginfo_t *last_siginfo; - struct task_io_accounting ioac; - unsigned int psi_flags; - u64 acct_rss_mem1; - u64 acct_vm_mem1; - u64 acct_timexpd; - nodemask_t mems_allowed; - seqcount_spinlock_t mems_allowed_seq; - int cpuset_mem_spread_rotor; - int cpuset_slab_spread_rotor; - struct css_set *cgroups; - struct list_head cg_list; - u32 closid; - u32 rmid; - struct robust_list_head *robust_list; - struct compat_robust_list_head *compat_robust_list; - struct list_head pi_state_list; - struct futex_pi_state *pi_state_cache; - struct mutex futex_exit_mutex; - unsigned int futex_state; - struct perf_event_context *perf_event_ctxp[2]; - struct mutex perf_event_mutex; - struct list_head perf_event_list; - struct mempolicy *mempolicy; - short int il_prev; - short int pref_node_fork; - int numa_scan_seq; - unsigned int numa_scan_period; - unsigned int numa_scan_period_max; - int numa_preferred_nid; - long unsigned int numa_migrate_retry; - u64 node_stamp; - u64 last_task_numa_placement; - u64 last_sum_exec_runtime; - struct callback_head numa_work; - struct numa_group *numa_group; - long unsigned int *numa_faults; - long unsigned int total_numa_faults; - long unsigned int numa_faults_locality[3]; - long unsigned int numa_pages_migrated; - struct rseq *rseq; - u32 rseq_sig; - long unsigned int rseq_event_mask; - struct tlbflush_unmap_batch tlb_ubc; - union { - refcount_t rcu_users; - struct callback_head rcu; - }; - struct pipe_inode_info *splice_pipe; - struct page_frag task_frag; - struct task_delay_info *delays; - int nr_dirtied; - int nr_dirtied_pause; - long unsigned int dirty_paused_when; - int latency_record_count; - struct latency_record latency_record[32]; - u64 timer_slack_ns; - u64 default_timer_slack_ns; - int curr_ret_stack; - int curr_ret_depth; - struct ftrace_ret_stack *ret_stack; - long long unsigned int ftrace_timestamp; - atomic_t trace_overrun; - atomic_t tracing_graph_pause; - long unsigned int trace; - long unsigned int trace_recursion; - struct mem_cgroup *memcg_in_oom; - gfp_t memcg_oom_gfp_mask; - int memcg_oom_order; - unsigned int memcg_nr_pages_over_high; - struct mem_cgroup *active_memcg; - struct request_queue *throttle_queue; - struct uprobe_task *utask; - unsigned int sequential_io; - unsigned int sequential_io_avg; - struct kmap_ctrl kmap_ctrl; - int pagefault_disabled; - struct task_struct *oom_reaper_list; - struct vm_struct *stack_vm_area; - refcount_t stack_refcount; - void *security; - struct bpf_local_storage *bpf_storage; - void *mce_vaddr; - __u64 mce_kflags; - u64 mce_addr; - __u64 mce_ripv: 1; - __u64 mce_whole_page: 1; - __u64 __mce_reserved: 62; - struct callback_head mce_kill_me; - struct llist_head kretprobe_instances; - long: 64; - long: 64; - long: 64; - struct thread_struct thread; -}; - -struct screen_info { - __u8 orig_x; - __u8 orig_y; - __u16 ext_mem_k; - __u16 orig_video_page; - __u8 orig_video_mode; - __u8 orig_video_cols; - __u8 flags; - __u8 unused2; - __u16 orig_video_ega_bx; - __u16 unused3; - __u8 orig_video_lines; - __u8 orig_video_isVGA; - __u16 orig_video_points; - __u16 lfb_width; - __u16 lfb_height; - __u16 lfb_depth; - __u32 lfb_base; - __u32 lfb_size; - __u16 cl_magic; - __u16 cl_offset; - __u16 lfb_linelength; - __u8 red_size; - __u8 red_pos; - __u8 green_size; - __u8 green_pos; - __u8 blue_size; - __u8 blue_pos; - __u8 rsvd_size; - __u8 rsvd_pos; - __u16 vesapm_seg; - __u16 vesapm_off; - __u16 pages; - __u16 vesa_attributes; - __u32 capabilities; - __u32 ext_lfb_base; - __u8 _reserved[2]; -} __attribute__((packed)); - -struct apm_bios_info { - __u16 version; - __u16 cseg; - __u32 offset; - __u16 cseg_16; - __u16 dseg; - __u16 flags; - __u16 cseg_len; - __u16 cseg_16_len; - __u16 dseg_len; -}; - -struct edd_device_params { - __u16 length; - __u16 info_flags; - __u32 num_default_cylinders; - __u32 num_default_heads; - __u32 sectors_per_track; - __u64 number_of_sectors; - __u16 bytes_per_sector; - __u32 dpte_ptr; - __u16 key; - __u8 device_path_info_length; - __u8 reserved2; - __u16 reserved3; - __u8 host_bus_type[4]; - __u8 interface_type[8]; - union { - struct { - __u16 base_address; - __u16 reserved1; - __u32 reserved2; - } isa; - struct { - __u8 bus; - __u8 slot; - __u8 function; - __u8 channel; - __u32 reserved; - } pci; - struct { - __u64 reserved; - } ibnd; - struct { - __u64 reserved; - } xprs; - struct { - __u64 reserved; - } htpt; - struct { - __u64 reserved; - } unknown; - } interface_path; - union { - struct { - __u8 device; - __u8 reserved1; - __u16 reserved2; - __u32 reserved3; - __u64 reserved4; - } ata; - struct { - __u8 device; - __u8 lun; - __u8 reserved1; - __u8 reserved2; - __u32 reserved3; - __u64 reserved4; - } atapi; - struct { - __u16 id; - __u64 lun; - __u16 reserved1; - __u32 reserved2; - } __attribute__((packed)) scsi; - struct { - __u64 serial_number; - __u64 reserved; - } usb; - struct { - __u64 eui; - __u64 reserved; - } i1394; - struct { - __u64 wwid; - __u64 lun; - } fibre; - struct { - __u64 identity_tag; - __u64 reserved; - } i2o; - struct { - __u32 array_number; - __u32 reserved1; - __u64 reserved2; - } raid; - struct { - __u8 device; - __u8 reserved1; - __u16 reserved2; - __u32 reserved3; - __u64 reserved4; - } sata; - struct { - __u64 reserved1; - __u64 reserved2; - } unknown; - } device_path; - __u8 reserved4; - __u8 checksum; -} __attribute__((packed)); - -struct edd_info { - __u8 device; - __u8 version; - __u16 interface_support; - __u16 legacy_max_cylinder; - __u8 legacy_max_head; - __u8 legacy_sectors_per_track; - struct edd_device_params params; -} __attribute__((packed)); - -struct ist_info { - __u32 signature; - __u32 command; - __u32 event; - __u32 perf_level; -}; - -struct edid_info { - unsigned char dummy[128]; -}; - -struct setup_header { - __u8 setup_sects; - __u16 root_flags; - __u32 syssize; - __u16 ram_size; - __u16 vid_mode; - __u16 root_dev; - __u16 boot_flag; - __u16 jump; - __u32 header; - __u16 version; - __u32 realmode_swtch; - __u16 start_sys_seg; - __u16 kernel_version; - __u8 type_of_loader; - __u8 loadflags; - __u16 setup_move_size; - __u32 code32_start; - __u32 ramdisk_image; - __u32 ramdisk_size; - __u32 bootsect_kludge; - __u16 heap_end_ptr; - __u8 ext_loader_ver; - __u8 ext_loader_type; - __u32 cmd_line_ptr; - __u32 initrd_addr_max; - __u32 kernel_alignment; - __u8 relocatable_kernel; - __u8 min_alignment; - __u16 xloadflags; - __u32 cmdline_size; - __u32 hardware_subarch; - __u64 hardware_subarch_data; - __u32 payload_offset; - __u32 payload_length; - __u64 setup_data; - __u64 pref_address; - __u32 init_size; - __u32 handover_offset; - __u32 kernel_info_offset; -} __attribute__((packed)); - -struct sys_desc_table { - __u16 length; - __u8 table[14]; -}; - -struct olpc_ofw_header { - __u32 ofw_magic; - __u32 ofw_version; - __u32 cif_handler; - __u32 irq_desc_table; -}; - -struct efi_info { - __u32 efi_loader_signature; - __u32 efi_systab; - __u32 efi_memdesc_size; - __u32 efi_memdesc_version; - __u32 efi_memmap; - __u32 efi_memmap_size; - __u32 efi_systab_hi; - __u32 efi_memmap_hi; -}; - -struct boot_e820_entry { - __u64 addr; - __u64 size; - __u32 type; -} __attribute__((packed)); - -struct boot_params { - struct screen_info screen_info; - struct apm_bios_info apm_bios_info; - __u8 _pad2[4]; - __u64 tboot_addr; - struct ist_info ist_info; - __u64 acpi_rsdp_addr; - __u8 _pad3[8]; - __u8 hd0_info[16]; - __u8 hd1_info[16]; - struct sys_desc_table sys_desc_table; - struct olpc_ofw_header olpc_ofw_header; - __u32 ext_ramdisk_image; - __u32 ext_ramdisk_size; - __u32 ext_cmd_line_ptr; - __u8 _pad4[116]; - struct edid_info edid_info; - struct efi_info efi_info; - __u32 alt_mem_k; - __u32 scratch; - __u8 e820_entries; - __u8 eddbuf_entries; - __u8 edd_mbr_sig_buf_entries; - __u8 kbd_status; - __u8 secure_boot; - __u8 _pad5[2]; - __u8 sentinel; - __u8 _pad6[1]; - struct setup_header hdr; - __u8 _pad7[36]; - __u32 edd_mbr_sig_buffer[16]; - struct boot_e820_entry e820_table[128]; - __u8 _pad8[48]; - struct edd_info eddbuf[6]; - __u8 _pad9[276]; -} __attribute__((packed)); - -enum x86_hardware_subarch { - X86_SUBARCH_PC = 0, - X86_SUBARCH_LGUEST = 1, - X86_SUBARCH_XEN = 2, - X86_SUBARCH_INTEL_MID = 3, - X86_SUBARCH_CE4100 = 4, - X86_NR_SUBARCHS = 5, -}; - -struct range { - u64 start; - u64 end; -}; - -struct pt_regs { - long unsigned int r15; - long unsigned int r14; - long unsigned int r13; - long unsigned int r12; - long unsigned int bp; - long unsigned int bx; - long unsigned int r11; - long unsigned int r10; - long unsigned int r9; - long unsigned int r8; - long unsigned int ax; - long unsigned int cx; - long unsigned int dx; - long unsigned int si; - long unsigned int di; - long unsigned int orig_ax; - long unsigned int ip; - long unsigned int cs; - long unsigned int flags; - long unsigned int sp; - long unsigned int ss; -}; - -enum { - GATE_INTERRUPT = 14, - GATE_TRAP = 15, - GATE_CALL = 12, - GATE_TASK = 5, -}; - -struct idt_bits { - u16 ist: 3; - u16 zero: 5; - u16 type: 5; - u16 dpl: 2; - u16 p: 1; -}; - -struct idt_data { - unsigned int vector; - unsigned int segment; - struct idt_bits bits; - const void *addr; -}; - -struct gate_struct { - u16 offset_low; - u16 segment; - struct idt_bits bits; - u16 offset_middle; - u32 offset_high; - u32 reserved; -}; - -typedef struct gate_struct gate_desc; - -struct desc_ptr { - short unsigned int size; - long unsigned int address; -} __attribute__((packed)); - -typedef long unsigned int pteval_t; - -typedef long unsigned int pmdval_t; - -typedef long unsigned int pudval_t; - -typedef long unsigned int p4dval_t; - -typedef long unsigned int pgdval_t; - -typedef long unsigned int pgprotval_t; - -typedef struct { - pteval_t pte; -} pte_t; - -struct pgprot { - pgprotval_t pgprot; -}; - -typedef struct pgprot pgprot_t; - -typedef struct { - pgdval_t pgd; -} pgd_t; - -typedef struct { - p4dval_t p4d; -} p4d_t; - -typedef struct { - pudval_t pud; -} pud_t; - -typedef struct { - pmdval_t pmd; -} pmd_t; - -typedef struct page *pgtable_t; - -struct address_space; - -struct page_pool; - -struct kmem_cache; - -struct dev_pagemap; - -struct page { - long unsigned int flags; - union { - struct { - struct list_head lru; - struct address_space *mapping; - long unsigned int index; - long unsigned int private; - }; - struct { - long unsigned int pp_magic; - struct page_pool *pp; - long unsigned int _pp_mapping_pad; - long unsigned int dma_addr[2]; - }; - struct { - union { - struct list_head slab_list; - struct { - struct page *next; - int pages; - int pobjects; - }; - }; - struct kmem_cache *slab_cache; - void *freelist; - union { - void *s_mem; - long unsigned int counters; - struct { - unsigned int inuse: 16; - unsigned int objects: 15; - unsigned int frozen: 1; - }; - }; - }; - struct { - long unsigned int compound_head; - unsigned char compound_dtor; - unsigned char compound_order; - atomic_t compound_mapcount; - unsigned int compound_nr; - }; - struct { - long unsigned int _compound_pad_1; - atomic_t hpage_pinned_refcount; - struct list_head deferred_list; - }; - struct { - long unsigned int _pt_pad_1; - pgtable_t pmd_huge_pte; - long unsigned int _pt_pad_2; - union { - struct mm_struct *pt_mm; - atomic_t pt_frag_refcount; - }; - spinlock_t ptl; - }; - struct { - struct dev_pagemap *pgmap; - void *zone_device_data; - }; - struct callback_head callback_head; - }; - union { - atomic_t _mapcount; - unsigned int page_type; - unsigned int active; - int units; - }; - atomic_t _refcount; - long unsigned int memcg_data; -}; - -struct paravirt_callee_save { - void *func; -}; - -struct pv_lazy_ops { - void (*enter)(); - void (*leave)(); - void (*flush)(); -}; - -struct pv_cpu_ops { - void (*io_delay)(); - long unsigned int (*get_debugreg)(int); - void (*set_debugreg)(int, long unsigned int); - long unsigned int (*read_cr0)(); - void (*write_cr0)(long unsigned int); - void (*write_cr4)(long unsigned int); - void (*load_tr_desc)(); - void (*load_gdt)(const struct desc_ptr *); - void (*load_idt)(const struct desc_ptr *); - void (*set_ldt)(const void *, unsigned int); - long unsigned int (*store_tr)(); - void (*load_tls)(struct thread_struct *, unsigned int); - void (*load_gs_index)(unsigned int); - void (*write_ldt_entry)(struct desc_struct *, int, const void *); - void (*write_gdt_entry)(struct desc_struct *, int, const void *, int); - void (*write_idt_entry)(gate_desc *, int, const gate_desc *); - void (*alloc_ldt)(struct desc_struct *, unsigned int); - void (*free_ldt)(struct desc_struct *, unsigned int); - void (*load_sp0)(long unsigned int); - void (*invalidate_io_bitmap)(); - void (*update_io_bitmap)(); - void (*wbinvd)(); - void (*cpuid)(unsigned int *, unsigned int *, unsigned int *, unsigned int *); - u64 (*read_msr)(unsigned int); - void (*write_msr)(unsigned int, unsigned int, unsigned int); - u64 (*read_msr_safe)(unsigned int, int *); - int (*write_msr_safe)(unsigned int, unsigned int, unsigned int); - u64 (*read_pmc)(int); - void (*start_context_switch)(struct task_struct *); - void (*end_context_switch)(struct task_struct *); -}; - -struct pv_irq_ops { - struct paravirt_callee_save save_fl; - struct paravirt_callee_save irq_disable; - struct paravirt_callee_save irq_enable; - void (*safe_halt)(); - void (*halt)(); -}; - -struct flush_tlb_info; - -struct mmu_gather; - -struct pv_mmu_ops { - void (*flush_tlb_user)(); - void (*flush_tlb_kernel)(); - void (*flush_tlb_one_user)(long unsigned int); - void (*flush_tlb_multi)(const struct cpumask *, const struct flush_tlb_info *); - void (*tlb_remove_table)(struct mmu_gather *, void *); - void (*exit_mmap)(struct mm_struct *); - struct paravirt_callee_save read_cr2; - void (*write_cr2)(long unsigned int); - long unsigned int (*read_cr3)(); - void (*write_cr3)(long unsigned int); - void (*activate_mm)(struct mm_struct *, struct mm_struct *); - void (*dup_mmap)(struct mm_struct *, struct mm_struct *); - int (*pgd_alloc)(struct mm_struct *); - void (*pgd_free)(struct mm_struct *, pgd_t *); - void (*alloc_pte)(struct mm_struct *, long unsigned int); - void (*alloc_pmd)(struct mm_struct *, long unsigned int); - void (*alloc_pud)(struct mm_struct *, long unsigned int); - void (*alloc_p4d)(struct mm_struct *, long unsigned int); - void (*release_pte)(long unsigned int); - void (*release_pmd)(long unsigned int); - void (*release_pud)(long unsigned int); - void (*release_p4d)(long unsigned int); - void (*set_pte)(pte_t *, pte_t); - void (*set_pmd)(pmd_t *, pmd_t); - pte_t (*ptep_modify_prot_start)(struct vm_area_struct *, long unsigned int, pte_t *); - void (*ptep_modify_prot_commit)(struct vm_area_struct *, long unsigned int, pte_t *, pte_t); - struct paravirt_callee_save pte_val; - struct paravirt_callee_save make_pte; - struct paravirt_callee_save pgd_val; - struct paravirt_callee_save make_pgd; - void (*set_pud)(pud_t *, pud_t); - struct paravirt_callee_save pmd_val; - struct paravirt_callee_save make_pmd; - struct paravirt_callee_save pud_val; - struct paravirt_callee_save make_pud; - void (*set_p4d)(p4d_t *, p4d_t); - struct paravirt_callee_save p4d_val; - struct paravirt_callee_save make_p4d; - void (*set_pgd)(pgd_t *, pgd_t); - struct pv_lazy_ops lazy_mode; - void (*set_fixmap)(unsigned int, phys_addr_t, pgprot_t); -}; - -struct flush_tlb_info { - struct mm_struct *mm; - long unsigned int start; - long unsigned int end; - u64 new_tlb_gen; - unsigned int initiating_cpu; - u8 stride_shift; - u8 freed_tables; -}; - -struct rw_semaphore { - atomic_long_t count; - atomic_long_t owner; - struct optimistic_spin_queue osq; - raw_spinlock_t wait_lock; - struct list_head wait_list; -}; - -struct mm_rss_stat { - atomic_long_t count[4]; -}; - -struct ldt_struct; - -struct vdso_image; - -typedef struct { - u64 ctx_id; - atomic64_t tlb_gen; - struct rw_semaphore ldt_usr_sem; - struct ldt_struct *ldt; - short unsigned int flags; - struct mutex lock; - void *vdso; - const struct vdso_image *vdso_image; - atomic_t perf_rdpmc_allowed; - u16 pkey_allocation_map; - s16 execute_only_pkey; -} mm_context_t; - -struct xol_area; - -struct uprobes_state { - struct xol_area *xol_area; -}; - -struct work_struct; - -typedef void (*work_func_t)(struct work_struct *); - -struct work_struct { - atomic_long_t data; - struct list_head entry; - work_func_t func; -}; - -struct linux_binfmt; - -struct core_state; - -struct kioctx_table; - -struct user_namespace; - -struct mmu_notifier_subscriptions; - -struct mm_struct { - struct { - struct vm_area_struct *mmap; - struct rb_root mm_rb; - u64 vmacache_seqnum; - long unsigned int (*get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - long unsigned int mmap_base; - long unsigned int mmap_legacy_base; - long unsigned int mmap_compat_base; - long unsigned int mmap_compat_legacy_base; - long unsigned int task_size; - long unsigned int highest_vm_end; - pgd_t *pgd; - atomic_t membarrier_state; - atomic_t mm_users; - atomic_t mm_count; - atomic_long_t pgtables_bytes; - int map_count; - spinlock_t page_table_lock; - struct rw_semaphore mmap_lock; - struct list_head mmlist; - long unsigned int hiwater_rss; - long unsigned int hiwater_vm; - long unsigned int total_vm; - long unsigned int locked_vm; - atomic64_t pinned_vm; - long unsigned int data_vm; - long unsigned int exec_vm; - long unsigned int stack_vm; - long unsigned int def_flags; - seqcount_t write_protect_seq; - spinlock_t arg_lock; - long unsigned int start_code; - long unsigned int end_code; - long unsigned int start_data; - long unsigned int end_data; - long unsigned int start_brk; - long unsigned int brk; - long unsigned int start_stack; - long unsigned int arg_start; - long unsigned int arg_end; - long unsigned int env_start; - long unsigned int env_end; - long unsigned int saved_auxv[48]; - struct mm_rss_stat rss_stat; - struct linux_binfmt *binfmt; - mm_context_t context; - long unsigned int flags; - struct core_state *core_state; - spinlock_t ioctx_lock; - struct kioctx_table *ioctx_table; - struct task_struct *owner; - struct user_namespace *user_ns; - struct file *exe_file; - struct mmu_notifier_subscriptions *notifier_subscriptions; - long unsigned int numa_next_scan; - long unsigned int numa_scan_offset; - int numa_scan_seq; - atomic_t tlb_flush_pending; - bool tlb_flush_batched; - struct uprobes_state uprobes_state; - atomic_long_t hugetlb_usage; - struct work_struct async_put_work; - u32 pasid; - }; - long unsigned int cpu_bitmap[0]; -}; - -struct userfaultfd_ctx; - -struct vm_userfaultfd_ctx { - struct userfaultfd_ctx *ctx; -}; - -struct anon_vma; - -struct vm_operations_struct; - -struct vm_area_struct { - long unsigned int vm_start; - long unsigned int vm_end; - struct vm_area_struct *vm_next; - struct vm_area_struct *vm_prev; - struct rb_node vm_rb; - long unsigned int rb_subtree_gap; - struct mm_struct *vm_mm; - pgprot_t vm_page_prot; - long unsigned int vm_flags; - struct { - struct rb_node rb; - long unsigned int rb_subtree_last; - } shared; - struct list_head anon_vma_chain; - struct anon_vma *anon_vma; - const struct vm_operations_struct *vm_ops; - long unsigned int vm_pgoff; - struct file *vm_file; - void *vm_private_data; - atomic_long_t swap_readahead_info; - struct mempolicy *vm_policy; - struct vm_userfaultfd_ctx vm_userfaultfd_ctx; -}; - -struct pv_lock_ops { - void (*queued_spin_lock_slowpath)(struct qspinlock *, u32); - struct paravirt_callee_save queued_spin_unlock; - void (*wait)(u8 *, u8); - void (*kick)(int); - struct paravirt_callee_save vcpu_is_preempted; -}; - -struct paravirt_patch_template { - struct pv_cpu_ops cpu; - struct pv_irq_ops irq; - struct pv_mmu_ops mmu; - struct pv_lock_ops lock; -}; - -struct math_emu_info { - long int ___orig_eip; - struct pt_regs *regs; -}; - -enum { - UNAME26 = 131072, - ADDR_NO_RANDOMIZE = 262144, - FDPIC_FUNCPTRS = 524288, - MMAP_PAGE_ZERO = 1048576, - ADDR_COMPAT_LAYOUT = 2097152, - READ_IMPLIES_EXEC = 4194304, - ADDR_LIMIT_32BIT = 8388608, - SHORT_INODE = 16777216, - WHOLE_SECONDS = 33554432, - STICKY_TIMEOUTS = 67108864, - ADDR_LIMIT_3GB = 134217728, -}; - -enum tlb_infos { - ENTRIES = 0, - NR_INFO = 1, -}; - -enum pcpu_fc { - PCPU_FC_AUTO = 0, - PCPU_FC_EMBED = 1, - PCPU_FC_PAGE = 2, - PCPU_FC_NR = 3, -}; - -struct vm_struct { - struct vm_struct *next; - void *addr; - long unsigned int size; - long unsigned int flags; - struct page **pages; - unsigned int nr_pages; - phys_addr_t phys_addr; - const void *caller; -}; - -struct wait_queue_head { - spinlock_t lock; - struct list_head head; -}; - -typedef struct wait_queue_head wait_queue_head_t; - -struct seqcount_raw_spinlock { - seqcount_t seqcount; -}; - -typedef struct seqcount_raw_spinlock seqcount_raw_spinlock_t; - -typedef struct { - seqcount_spinlock_t seqcount; - spinlock_t lock; -} seqlock_t; - -enum node_states { - N_POSSIBLE = 0, - N_ONLINE = 1, - N_NORMAL_MEMORY = 2, - N_HIGH_MEMORY = 2, - N_MEMORY = 3, - N_CPU = 4, - N_GENERIC_INITIATOR = 5, - NR_NODE_STATES = 6, -}; - -enum { - MM_FILEPAGES = 0, - MM_ANONPAGES = 1, - MM_SWAPENTS = 2, - MM_SHMEMPAGES = 3, - NR_MM_COUNTERS = 4, -}; - -struct swait_queue_head { - raw_spinlock_t lock; - struct list_head task_list; -}; - -struct completion { - unsigned int done; - struct swait_queue_head wait; -}; - -struct arch_uprobe_task { - long unsigned int saved_scratch_register; - unsigned int saved_trap_nr; - unsigned int saved_tf; -}; - -enum uprobe_task_state { - UTASK_RUNNING = 0, - UTASK_SSTEP = 1, - UTASK_SSTEP_ACK = 2, - UTASK_SSTEP_TRAPPED = 3, -}; - -struct uprobe; - -struct return_instance; - -struct uprobe_task { - enum uprobe_task_state state; - union { - struct { - struct arch_uprobe_task autask; - long unsigned int vaddr; - }; - struct { - struct callback_head dup_xol_work; - long unsigned int dup_xol_addr; - }; - }; - struct uprobe *active_uprobe; - long unsigned int xol_vaddr; - struct return_instance *return_instances; - unsigned int depth; -}; - -struct return_instance { - struct uprobe *uprobe; - long unsigned int func; - long unsigned int stack; - long unsigned int orig_ret_vaddr; - bool chained; - struct return_instance *next; -}; - -struct vdso_image { - void *data; - long unsigned int size; - long unsigned int alt; - long unsigned int alt_len; - long unsigned int extable_base; - long unsigned int extable_len; - const void *extable; - long int sym_vvar_start; - long int sym_vvar_page; - long int sym_pvclock_page; - long int sym_hvclock_page; - long int sym_timens_page; - long int sym_VDSO32_NOTE_MASK; - long int sym___kernel_sigreturn; - long int sym___kernel_rt_sigreturn; - long int sym___kernel_vsyscall; - long int sym_int80_landing_pad; - long int sym_vdso32_sigreturn_landing_pad; - long int sym_vdso32_rt_sigreturn_landing_pad; -}; - -struct xarray { - spinlock_t xa_lock; - gfp_t xa_flags; - void *xa_head; -}; - -typedef u32 errseq_t; - -struct address_space_operations; - -struct address_space { - struct inode *host; - struct xarray i_pages; - gfp_t gfp_mask; - atomic_t i_mmap_writable; - atomic_t nr_thps; - struct rb_root_cached i_mmap; - struct rw_semaphore i_mmap_rwsem; - long unsigned int nrpages; - long unsigned int writeback_index; - const struct address_space_operations *a_ops; - long unsigned int flags; - errseq_t wb_err; - spinlock_t private_lock; - struct list_head private_list; - void *private_data; -}; - -struct vmem_altmap { - long unsigned int base_pfn; - const long unsigned int end_pfn; - const long unsigned int reserve; - long unsigned int free; - long unsigned int align; - long unsigned int alloc; -}; - -struct percpu_ref_data; - -struct percpu_ref { - long unsigned int percpu_count_ptr; - struct percpu_ref_data *data; -}; - -enum memory_type { - MEMORY_DEVICE_PRIVATE = 1, - MEMORY_DEVICE_FS_DAX = 2, - MEMORY_DEVICE_GENERIC = 3, - MEMORY_DEVICE_PCI_P2PDMA = 4, -}; - -struct dev_pagemap_ops; - -struct dev_pagemap { - struct vmem_altmap altmap; - struct percpu_ref *ref; - struct percpu_ref internal_ref; - struct completion done; - enum memory_type type; - unsigned int flags; - const struct dev_pagemap_ops *ops; - void *owner; - int nr_range; - union { - struct range range; - struct range ranges[0]; - }; -}; - -struct vfsmount; - -struct path { - struct vfsmount *mnt; - struct dentry *dentry; -}; - -enum rw_hint { - WRITE_LIFE_NOT_SET = 0, - WRITE_LIFE_NONE = 1, - WRITE_LIFE_SHORT = 2, - WRITE_LIFE_MEDIUM = 3, - WRITE_LIFE_LONG = 4, - WRITE_LIFE_EXTREME = 5, -}; - -enum pid_type { - PIDTYPE_PID = 0, - PIDTYPE_TGID = 1, - PIDTYPE_PGID = 2, - PIDTYPE_SID = 3, - PIDTYPE_MAX = 4, -}; - -struct fown_struct { - rwlock_t lock; - struct pid *pid; - enum pid_type pid_type; - kuid_t uid; - kuid_t euid; - int signum; -}; - -struct file_ra_state { - long unsigned int start; - unsigned int size; - unsigned int async_size; - unsigned int ra_pages; - unsigned int mmap_miss; - loff_t prev_pos; -}; - -struct file { - union { - struct llist_node fu_llist; - struct callback_head fu_rcuhead; - } f_u; - struct path f_path; - struct inode *f_inode; - const struct file_operations *f_op; - spinlock_t f_lock; - enum rw_hint f_write_hint; - atomic_long_t f_count; - unsigned int f_flags; - fmode_t f_mode; - struct mutex f_pos_lock; - loff_t f_pos; - struct fown_struct f_owner; - const struct cred *f_cred; - struct file_ra_state f_ra; - u64 f_version; - void *f_security; - void *private_data; - struct hlist_head *f_ep; - struct address_space *f_mapping; - errseq_t f_wb_err; - errseq_t f_sb_err; -}; - -typedef unsigned int vm_fault_t; - -enum page_entry_size { - PE_SIZE_PTE = 0, - PE_SIZE_PMD = 1, - PE_SIZE_PUD = 2, -}; - -struct vm_fault; - -struct vm_operations_struct { - void (*open)(struct vm_area_struct *); - void (*close)(struct vm_area_struct *); - int (*may_split)(struct vm_area_struct *, long unsigned int); - int (*mremap)(struct vm_area_struct *); - int (*mprotect)(struct vm_area_struct *, long unsigned int, long unsigned int, long unsigned int); - vm_fault_t (*fault)(struct vm_fault *); - vm_fault_t (*huge_fault)(struct vm_fault *, enum page_entry_size); - vm_fault_t (*map_pages)(struct vm_fault *, long unsigned int, long unsigned int); - long unsigned int (*pagesize)(struct vm_area_struct *); - vm_fault_t (*page_mkwrite)(struct vm_fault *); - vm_fault_t (*pfn_mkwrite)(struct vm_fault *); - int (*access)(struct vm_area_struct *, long unsigned int, void *, int, int); - const char * (*name)(struct vm_area_struct *); - int (*set_policy)(struct vm_area_struct *, struct mempolicy *); - struct mempolicy * (*get_policy)(struct vm_area_struct *, long unsigned int); - struct page * (*find_special_page)(struct vm_area_struct *, long unsigned int); -}; - -struct core_thread { - struct task_struct *task; - struct core_thread *next; -}; - -struct core_state { - atomic_t nr_threads; - struct core_thread dumper; - struct completion startup; -}; - -enum fault_flag { - FAULT_FLAG_WRITE = 1, - FAULT_FLAG_MKWRITE = 2, - FAULT_FLAG_ALLOW_RETRY = 4, - FAULT_FLAG_RETRY_NOWAIT = 8, - FAULT_FLAG_KILLABLE = 16, - FAULT_FLAG_TRIED = 32, - FAULT_FLAG_USER = 64, - FAULT_FLAG_REMOTE = 128, - FAULT_FLAG_INSTRUCTION = 256, - FAULT_FLAG_INTERRUPTIBLE = 512, -}; - -struct vm_fault { - const struct { - struct vm_area_struct *vma; - gfp_t gfp_mask; - long unsigned int pgoff; - long unsigned int address; - }; - enum fault_flag flags; - pmd_t *pmd; - pud_t *pud; - union { - pte_t orig_pte; - pmd_t orig_pmd; - }; - struct page *cow_page; - struct page *page; - pte_t *pte; - spinlock_t *ptl; - pgtable_t prealloc_pte; -}; - -enum migratetype { - MIGRATE_UNMOVABLE = 0, - MIGRATE_MOVABLE = 1, - MIGRATE_RECLAIMABLE = 2, - MIGRATE_PCPTYPES = 3, - MIGRATE_HIGHATOMIC = 3, - MIGRATE_CMA = 4, - MIGRATE_ISOLATE = 5, - MIGRATE_TYPES = 6, -}; - -enum numa_stat_item { - NUMA_HIT = 0, - NUMA_MISS = 1, - NUMA_FOREIGN = 2, - NUMA_INTERLEAVE_HIT = 3, - NUMA_LOCAL = 4, - NUMA_OTHER = 5, - NR_VM_NUMA_EVENT_ITEMS = 6, -}; - -enum zone_stat_item { - NR_FREE_PAGES = 0, - NR_ZONE_LRU_BASE = 1, - NR_ZONE_INACTIVE_ANON = 1, - NR_ZONE_ACTIVE_ANON = 2, - NR_ZONE_INACTIVE_FILE = 3, - NR_ZONE_ACTIVE_FILE = 4, - NR_ZONE_UNEVICTABLE = 5, - NR_ZONE_WRITE_PENDING = 6, - NR_MLOCK = 7, - NR_BOUNCE = 8, - NR_ZSPAGES = 9, - NR_FREE_CMA_PAGES = 10, - NR_VM_ZONE_STAT_ITEMS = 11, -}; - -enum node_stat_item { - NR_LRU_BASE = 0, - NR_INACTIVE_ANON = 0, - NR_ACTIVE_ANON = 1, - NR_INACTIVE_FILE = 2, - NR_ACTIVE_FILE = 3, - NR_UNEVICTABLE = 4, - NR_SLAB_RECLAIMABLE_B = 5, - NR_SLAB_UNRECLAIMABLE_B = 6, - NR_ISOLATED_ANON = 7, - NR_ISOLATED_FILE = 8, - WORKINGSET_NODES = 9, - WORKINGSET_REFAULT_BASE = 10, - WORKINGSET_REFAULT_ANON = 10, - WORKINGSET_REFAULT_FILE = 11, - WORKINGSET_ACTIVATE_BASE = 12, - WORKINGSET_ACTIVATE_ANON = 12, - WORKINGSET_ACTIVATE_FILE = 13, - WORKINGSET_RESTORE_BASE = 14, - WORKINGSET_RESTORE_ANON = 14, - WORKINGSET_RESTORE_FILE = 15, - WORKINGSET_NODERECLAIM = 16, - NR_ANON_MAPPED = 17, - NR_FILE_MAPPED = 18, - NR_FILE_PAGES = 19, - NR_FILE_DIRTY = 20, - NR_WRITEBACK = 21, - NR_WRITEBACK_TEMP = 22, - NR_SHMEM = 23, - NR_SHMEM_THPS = 24, - NR_SHMEM_PMDMAPPED = 25, - NR_FILE_THPS = 26, - NR_FILE_PMDMAPPED = 27, - NR_ANON_THPS = 28, - NR_VMSCAN_WRITE = 29, - NR_VMSCAN_IMMEDIATE = 30, - NR_DIRTIED = 31, - NR_WRITTEN = 32, - NR_KERNEL_MISC_RECLAIMABLE = 33, - NR_FOLL_PIN_ACQUIRED = 34, - NR_FOLL_PIN_RELEASED = 35, - NR_KERNEL_STACK_KB = 36, - NR_PAGETABLE = 37, - NR_SWAPCACHE = 38, - NR_VM_NODE_STAT_ITEMS = 39, -}; - -enum lru_list { - LRU_INACTIVE_ANON = 0, - LRU_ACTIVE_ANON = 1, - LRU_INACTIVE_FILE = 2, - LRU_ACTIVE_FILE = 3, - LRU_UNEVICTABLE = 4, - NR_LRU_LISTS = 5, -}; - -typedef unsigned int isolate_mode_t; - -enum zone_watermarks { - WMARK_MIN = 0, - WMARK_LOW = 1, - WMARK_HIGH = 2, - NR_WMARK = 3, -}; - -enum { - ZONELIST_FALLBACK = 0, - ZONELIST_NOFALLBACK = 1, - MAX_ZONELISTS = 2, -}; - -typedef void percpu_ref_func_t(struct percpu_ref *); - -struct percpu_ref_data { - atomic_long_t count; - percpu_ref_func_t *release; - percpu_ref_func_t *confirm_switch; - bool force_atomic: 1; - bool allow_reinit: 1; - struct callback_head rcu; - struct percpu_ref *ref; -}; - -struct shrink_control { - gfp_t gfp_mask; - int nid; - long unsigned int nr_to_scan; - long unsigned int nr_scanned; - struct mem_cgroup *memcg; -}; - -struct shrinker { - long unsigned int (*count_objects)(struct shrinker *, struct shrink_control *); - long unsigned int (*scan_objects)(struct shrinker *, struct shrink_control *); - long int batch; - int seeks; - unsigned int flags; - struct list_head list; - int id; - atomic_long_t *nr_deferred; -}; - -struct rlimit { - __kernel_ulong_t rlim_cur; - __kernel_ulong_t rlim_max; -}; - -struct dev_pagemap_ops { - void (*page_free)(struct page *); - void (*kill)(struct dev_pagemap *); - void (*cleanup)(struct dev_pagemap *); - vm_fault_t (*migrate_to_ram)(struct vm_fault *); -}; - -struct pid_namespace; - -struct upid { - int nr; - struct pid_namespace *ns; -}; - -struct pid { - refcount_t count; - unsigned int level; - spinlock_t lock; - struct hlist_head tasks[4]; - struct hlist_head inodes; - wait_queue_head_t wait_pidfd; - struct callback_head rcu; - struct upid numbers[1]; -}; - -typedef struct { - gid_t val; -} kgid_t; - -struct hrtimer_cpu_base; - -struct hrtimer_clock_base { - struct hrtimer_cpu_base *cpu_base; - unsigned int index; - clockid_t clockid; - seqcount_raw_spinlock_t seq; - struct hrtimer *running; - struct timerqueue_head active; - ktime_t (*get_time)(); - ktime_t offset; -}; - -struct hrtimer_cpu_base { - raw_spinlock_t lock; - unsigned int cpu; - unsigned int active_bases; - unsigned int clock_was_set_seq; - unsigned int hres_active: 1; - unsigned int in_hrtirq: 1; - unsigned int hang_detected: 1; - unsigned int softirq_activated: 1; - unsigned int nr_events; - short unsigned int nr_retries; - short unsigned int nr_hangs; - unsigned int max_hang_time; - ktime_t expires_next; - struct hrtimer *next_timer; - ktime_t softirq_expires_next; - struct hrtimer *softirq_next_timer; - struct hrtimer_clock_base clock_base[8]; -}; - -enum hrtimer_base_type { - HRTIMER_BASE_MONOTONIC = 0, - HRTIMER_BASE_REALTIME = 1, - HRTIMER_BASE_BOOTTIME = 2, - HRTIMER_BASE_TAI = 3, - HRTIMER_BASE_MONOTONIC_SOFT = 4, - HRTIMER_BASE_REALTIME_SOFT = 5, - HRTIMER_BASE_BOOTTIME_SOFT = 6, - HRTIMER_BASE_TAI_SOFT = 7, - HRTIMER_MAX_CLOCK_BASES = 8, -}; - -typedef void __signalfn_t(int); - -typedef __signalfn_t *__sighandler_t; - -typedef void __restorefn_t(); - -typedef __restorefn_t *__sigrestore_t; - -union sigval { - int sival_int; - void *sival_ptr; -}; - -typedef union sigval sigval_t; - -union __sifields { - struct { - __kernel_pid_t _pid; - __kernel_uid32_t _uid; - } _kill; - struct { - __kernel_timer_t _tid; - int _overrun; - sigval_t _sigval; - int _sys_private; - } _timer; - struct { - __kernel_pid_t _pid; - __kernel_uid32_t _uid; - sigval_t _sigval; - } _rt; - struct { - __kernel_pid_t _pid; - __kernel_uid32_t _uid; - int _status; - __kernel_clock_t _utime; - __kernel_clock_t _stime; - } _sigchld; - struct { - void *_addr; - union { - int _trapno; - short int _addr_lsb; - struct { - char _dummy_bnd[8]; - void *_lower; - void *_upper; - } _addr_bnd; - struct { - char _dummy_pkey[8]; - __u32 _pkey; - } _addr_pkey; - struct { - long unsigned int _data; - __u32 _type; - } _perf; - }; - } _sigfault; - struct { - long int _band; - int _fd; - } _sigpoll; - struct { - void *_call_addr; - int _syscall; - unsigned int _arch; - } _sigsys; -}; - -struct kernel_siginfo { - struct { - int si_signo; - int si_errno; - int si_code; - union __sifields _sifields; - }; -}; - -struct sigaction { - __sighandler_t sa_handler; - long unsigned int sa_flags; - __sigrestore_t sa_restorer; - sigset_t sa_mask; -}; - -struct k_sigaction { - struct sigaction sa; -}; - -struct cpu_itimer { - u64 expires; - u64 incr; -}; - -struct task_cputime_atomic { - atomic64_t utime; - atomic64_t stime; - atomic64_t sum_exec_runtime; -}; - -struct thread_group_cputimer { - struct task_cputime_atomic cputime_atomic; -}; - -struct pacct_struct { - int ac_flag; - long int ac_exitcode; - long unsigned int ac_mem; - u64 ac_utime; - u64 ac_stime; - long unsigned int ac_minflt; - long unsigned int ac_majflt; -}; - -struct tty_struct; - -struct autogroup; - -struct taskstats; - -struct tty_audit_buf; - -struct signal_struct { - refcount_t sigcnt; - atomic_t live; - int nr_threads; - struct list_head thread_head; - wait_queue_head_t wait_chldexit; - struct task_struct *curr_target; - struct sigpending shared_pending; - struct hlist_head multiprocess; - int group_exit_code; - int notify_count; - struct task_struct *group_exit_task; - int group_stop_count; - unsigned int flags; - unsigned int is_child_subreaper: 1; - unsigned int has_child_subreaper: 1; - int posix_timer_id; - struct list_head posix_timers; - struct hrtimer real_timer; - ktime_t it_real_incr; - struct cpu_itimer it[2]; - struct thread_group_cputimer cputimer; - struct posix_cputimers posix_cputimers; - struct pid *pids[4]; - struct pid *tty_old_pgrp; - int leader; - struct tty_struct *tty; - struct autogroup *autogroup; - seqlock_t stats_lock; - u64 utime; - u64 stime; - u64 cutime; - u64 cstime; - u64 gtime; - u64 cgtime; - struct prev_cputime prev_cputime; - long unsigned int nvcsw; - long unsigned int nivcsw; - long unsigned int cnvcsw; - long unsigned int cnivcsw; - long unsigned int min_flt; - long unsigned int maj_flt; - long unsigned int cmin_flt; - long unsigned int cmaj_flt; - long unsigned int inblock; - long unsigned int oublock; - long unsigned int cinblock; - long unsigned int coublock; - long unsigned int maxrss; - long unsigned int cmaxrss; - struct task_io_accounting ioac; - long long unsigned int sum_sched_runtime; - struct rlimit rlim[16]; - struct pacct_struct pacct; - struct taskstats *stats; - unsigned int audit_tty; - struct tty_audit_buf *tty_audit_buf; - bool oom_flag_origin; - short int oom_score_adj; - short int oom_score_adj_min; - struct mm_struct *oom_mm; - struct mutex cred_guard_mutex; - struct rw_semaphore exec_update_lock; -}; - -enum rseq_cs_flags_bit { - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, -}; - -struct rseq { - __u32 cpu_id_start; - __u32 cpu_id; - union { - __u64 ptr64; - __u64 ptr; - } rseq_cs; - __u32 flags; - long: 32; - long: 64; -}; - -enum uclamp_id { - UCLAMP_MIN = 0, - UCLAMP_MAX = 1, - UCLAMP_CNT = 2, -}; - -enum perf_event_task_context { - perf_invalid_context = 4294967295, - perf_hw_context = 0, - perf_sw_context = 1, - perf_nr_task_contexts = 2, -}; - -struct rq; - -struct rq_flags; - -struct sched_class { - int uclamp_enabled; - void (*enqueue_task)(struct rq *, struct task_struct *, int); - void (*dequeue_task)(struct rq *, struct task_struct *, int); - void (*yield_task)(struct rq *); - bool (*yield_to_task)(struct rq *, struct task_struct *); - void (*check_preempt_curr)(struct rq *, struct task_struct *, int); - struct task_struct * (*pick_next_task)(struct rq *); - void (*put_prev_task)(struct rq *, struct task_struct *); - void (*set_next_task)(struct rq *, struct task_struct *, bool); - int (*balance)(struct rq *, struct task_struct *, struct rq_flags *); - int (*select_task_rq)(struct task_struct *, int, int); - struct task_struct * (*pick_task)(struct rq *); - void (*migrate_task_rq)(struct task_struct *, int); - void (*task_woken)(struct rq *, struct task_struct *); - void (*set_cpus_allowed)(struct task_struct *, const struct cpumask *, u32); - void (*rq_online)(struct rq *); - void (*rq_offline)(struct rq *); - struct rq * (*find_lock_rq)(struct task_struct *, struct rq *); - void (*task_tick)(struct rq *, struct task_struct *, int); - void (*task_fork)(struct task_struct *); - void (*task_dead)(struct task_struct *); - void (*switched_from)(struct rq *, struct task_struct *); - void (*switched_to)(struct rq *, struct task_struct *); - void (*prio_changed)(struct rq *, struct task_struct *, int); - unsigned int (*get_rr_interval)(struct rq *, struct task_struct *); - void (*update_curr)(struct rq *); - void (*task_change_group)(struct task_struct *, int); -}; - -struct kernel_cap_struct { - __u32 cap[2]; -}; - -typedef struct kernel_cap_struct kernel_cap_t; - -struct user_struct; - -struct ucounts; - -struct group_info; - -struct cred { - atomic_t usage; - kuid_t uid; - kgid_t gid; - kuid_t suid; - kgid_t sgid; - kuid_t euid; - kgid_t egid; - kuid_t fsuid; - kgid_t fsgid; - unsigned int securebits; - kernel_cap_t cap_inheritable; - kernel_cap_t cap_permitted; - kernel_cap_t cap_effective; - kernel_cap_t cap_bset; - kernel_cap_t cap_ambient; - unsigned char jit_keyring; - struct key *session_keyring; - struct key *process_keyring; - struct key *thread_keyring; - struct key *request_key_auth; - void *security; - struct user_struct *user; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct group_info *group_info; - union { - int non_rcu; - struct callback_head rcu; - }; -}; - -typedef int32_t key_serial_t; - -typedef uint32_t key_perm_t; - -struct key_type; - -struct key_tag; - -struct keyring_index_key { - long unsigned int hash; - union { - struct { - u16 desc_len; - char desc[6]; - }; - long unsigned int x; - }; - struct key_type *type; - struct key_tag *domain_tag; - const char *description; -}; - -union key_payload { - void *rcu_data0; - void *data[4]; -}; - -struct assoc_array_ptr; - -struct assoc_array { - struct assoc_array_ptr *root; - long unsigned int nr_leaves_on_tree; -}; - -struct watch_list; - -struct key_user; - -struct key_restriction; - -struct key { - refcount_t usage; - key_serial_t serial; - union { - struct list_head graveyard_link; - struct rb_node serial_node; - }; - struct watch_list *watchers; - struct rw_semaphore sem; - struct key_user *user; - void *security; - union { - time64_t expiry; - time64_t revoked_at; - }; - time64_t last_used_at; - kuid_t uid; - kgid_t gid; - key_perm_t perm; - short unsigned int quotalen; - short unsigned int datalen; - short int state; - long unsigned int flags; - union { - struct keyring_index_key index_key; - struct { - long unsigned int hash; - long unsigned int len_desc; - struct key_type *type; - struct key_tag *domain_tag; - char *description; - }; - }; - union { - union key_payload payload; - struct { - struct list_head name_link; - struct assoc_array keys; - }; - }; - struct key_restriction *restrict_link; -}; - -struct sighand_struct { - spinlock_t siglock; - refcount_t count; - wait_queue_head_t signalfd_wqh; - struct k_sigaction action[64]; -}; - -struct io_cq; - -struct io_context { - atomic_long_t refcount; - atomic_t active_ref; - atomic_t nr_tasks; - spinlock_t lock; - short unsigned int ioprio; - struct xarray icq_tree; - struct io_cq *icq_hint; - struct hlist_head icq_list; - struct work_struct release_work; -}; - -enum rseq_event_mask_bits { - RSEQ_EVENT_PREEMPT_BIT = 0, - RSEQ_EVENT_SIGNAL_BIT = 1, - RSEQ_EVENT_MIGRATE_BIT = 2, -}; - -enum fixed_addresses { - VSYSCALL_PAGE = 511, - FIX_DBGP_BASE = 512, - FIX_EARLYCON_MEM_BASE = 513, - FIX_APIC_BASE = 514, - FIX_IO_APIC_BASE_0 = 515, - FIX_IO_APIC_BASE_END = 642, - FIX_PARAVIRT_BOOTMAP = 643, - FIX_APEI_GHES_IRQ = 644, - FIX_APEI_GHES_NMI = 645, - __end_of_permanent_fixed_addresses = 646, - FIX_BTMAP_END = 1024, - FIX_BTMAP_BEGIN = 1535, - __end_of_fixed_addresses = 1536, -}; - -struct hlist_bl_node; - -struct hlist_bl_head { - struct hlist_bl_node *first; -}; - -struct hlist_bl_node { - struct hlist_bl_node *next; - struct hlist_bl_node **pprev; -}; - -struct lockref { - union { - __u64 lock_count; - struct { - spinlock_t lock; - int count; - }; - }; -}; - -struct qstr { - union { - struct { - u32 hash; - u32 len; - }; - u64 hash_len; - }; - const unsigned char *name; -}; - -struct dentry_operations; - -struct dentry { - unsigned int d_flags; - seqcount_spinlock_t d_seq; - struct hlist_bl_node d_hash; - struct dentry *d_parent; - struct qstr d_name; - struct inode *d_inode; - unsigned char d_iname[32]; - struct lockref d_lockref; - const struct dentry_operations *d_op; - struct super_block *d_sb; - long unsigned int d_time; - void *d_fsdata; - union { - struct list_head d_lru; - wait_queue_head_t *d_wait; - }; - struct list_head d_child; - struct list_head d_subdirs; - union { - struct hlist_node d_alias; - struct hlist_bl_node d_in_lookup_hash; - struct callback_head d_rcu; - } d_u; -}; - -struct posix_acl; - -struct inode_operations; - -struct bdi_writeback; - -struct file_lock_context; - -struct cdev; - -struct fsnotify_mark_connector; - -struct fscrypt_info; - -struct fsverity_info; - -struct inode { - umode_t i_mode; - short unsigned int i_opflags; - kuid_t i_uid; - kgid_t i_gid; - unsigned int i_flags; - struct posix_acl *i_acl; - struct posix_acl *i_default_acl; - const struct inode_operations *i_op; - struct super_block *i_sb; - struct address_space *i_mapping; - void *i_security; - long unsigned int i_ino; - union { - const unsigned int i_nlink; - unsigned int __i_nlink; - }; - dev_t i_rdev; - loff_t i_size; - struct timespec64 i_atime; - struct timespec64 i_mtime; - struct timespec64 i_ctime; - spinlock_t i_lock; - short unsigned int i_bytes; - u8 i_blkbits; - u8 i_write_hint; - blkcnt_t i_blocks; - long unsigned int i_state; - struct rw_semaphore i_rwsem; - long unsigned int dirtied_when; - long unsigned int dirtied_time_when; - struct hlist_node i_hash; - struct list_head i_io_list; - struct bdi_writeback *i_wb; - int i_wb_frn_winner; - u16 i_wb_frn_avg_time; - u16 i_wb_frn_history; - struct list_head i_lru; - struct list_head i_sb_list; - struct list_head i_wb_list; - union { - struct hlist_head i_dentry; - struct callback_head i_rcu; - }; - atomic64_t i_version; - atomic64_t i_sequence; - atomic_t i_count; - atomic_t i_dio_count; - atomic_t i_writecount; - atomic_t i_readcount; - union { - const struct file_operations *i_fop; - void (*free_inode)(struct inode *); - }; - struct file_lock_context *i_flctx; - struct address_space i_data; - struct list_head i_devices; - union { - struct pipe_inode_info *i_pipe; - struct cdev *i_cdev; - char *i_link; - unsigned int i_dir_seq; - }; - __u32 i_generation; - __u32 i_fsnotify_mask; - struct fsnotify_mark_connector *i_fsnotify_marks; - struct fscrypt_info *i_crypt_info; - struct fsverity_info *i_verity_info; - void *i_private; -}; - -struct dentry_operations { - int (*d_revalidate)(struct dentry *, unsigned int); - int (*d_weak_revalidate)(struct dentry *, unsigned int); - int (*d_hash)(const struct dentry *, struct qstr *); - int (*d_compare)(const struct dentry *, unsigned int, const char *, const struct qstr *); - int (*d_delete)(const struct dentry *); - int (*d_init)(struct dentry *); - void (*d_release)(struct dentry *); - void (*d_prune)(struct dentry *); - void (*d_iput)(struct dentry *, struct inode *); - char * (*d_dname)(struct dentry *, char *, int); - struct vfsmount * (*d_automount)(struct path *); - int (*d_manage)(const struct path *, bool); - struct dentry * (*d_real)(struct dentry *, const struct inode *); - long: 64; - long: 64; - long: 64; -}; - -struct mtd_info; - -typedef long long int qsize_t; - -struct quota_format_type; - -struct mem_dqinfo { - struct quota_format_type *dqi_format; - int dqi_fmt_id; - struct list_head dqi_dirty_list; - long unsigned int dqi_flags; - unsigned int dqi_bgrace; - unsigned int dqi_igrace; - qsize_t dqi_max_spc_limit; - qsize_t dqi_max_ino_limit; - void *dqi_priv; -}; - -struct quota_format_ops; - -struct quota_info { - unsigned int flags; - struct rw_semaphore dqio_sem; - struct inode *files[3]; - struct mem_dqinfo info[3]; - const struct quota_format_ops *ops[3]; -}; - -struct rcu_sync { - int gp_state; - int gp_count; - wait_queue_head_t gp_wait; - struct callback_head cb_head; -}; - -struct rcuwait { - struct task_struct *task; -}; - -struct percpu_rw_semaphore { - struct rcu_sync rss; - unsigned int *read_count; - struct rcuwait writer; - wait_queue_head_t waiters; - atomic_t block; -}; - -struct sb_writers { - int frozen; - wait_queue_head_t wait_unfrozen; - struct percpu_rw_semaphore rw_sem[3]; -}; - -typedef struct { - __u8 b[16]; -} uuid_t; - -struct list_lru_node; - -struct list_lru { - struct list_lru_node *node; - struct list_head list; - int shrinker_id; - bool memcg_aware; -}; - -struct super_operations; - -struct dquot_operations; - -struct quotactl_ops; - -struct export_operations; - -struct xattr_handler; - -struct fscrypt_operations; - -struct fsverity_operations; - -struct unicode_map; - -struct block_device; - -struct workqueue_struct; - -struct super_block { - struct list_head s_list; - dev_t s_dev; - unsigned char s_blocksize_bits; - long unsigned int s_blocksize; - loff_t s_maxbytes; - struct file_system_type *s_type; - const struct super_operations *s_op; - const struct dquot_operations *dq_op; - const struct quotactl_ops *s_qcop; - const struct export_operations *s_export_op; - long unsigned int s_flags; - long unsigned int s_iflags; - long unsigned int s_magic; - struct dentry *s_root; - struct rw_semaphore s_umount; - int s_count; - atomic_t s_active; - void *s_security; - const struct xattr_handler **s_xattr; - const struct fscrypt_operations *s_cop; - struct key *s_master_keys; - const struct fsverity_operations *s_vop; - struct unicode_map *s_encoding; - __u16 s_encoding_flags; - struct hlist_bl_head s_roots; - struct list_head s_mounts; - struct block_device *s_bdev; - struct backing_dev_info *s_bdi; - struct mtd_info *s_mtd; - struct hlist_node s_instances; - unsigned int s_quota_types; - struct quota_info s_dquot; - struct sb_writers s_writers; - void *s_fs_info; - u32 s_time_gran; - time64_t s_time_min; - time64_t s_time_max; - __u32 s_fsnotify_mask; - struct fsnotify_mark_connector *s_fsnotify_marks; - char s_id[32]; - uuid_t s_uuid; - unsigned int s_max_links; - fmode_t s_mode; - struct mutex s_vfs_rename_mutex; - const char *s_subtype; - const struct dentry_operations *s_d_op; - int cleancache_poolid; - struct shrinker s_shrink; - atomic_long_t s_remove_count; - atomic_long_t s_fsnotify_inode_refs; - int s_readonly_remount; - errseq_t s_wb_err; - struct workqueue_struct *s_dio_done_wq; - struct hlist_head s_pins; - struct user_namespace *s_user_ns; - struct list_lru s_dentry_lru; - struct list_lru s_inode_lru; - struct callback_head rcu; - struct work_struct destroy_work; - struct mutex s_sync_lock; - int s_stack_depth; - int: 32; - spinlock_t s_inode_list_lock; - struct list_head s_inodes; - spinlock_t s_inode_wblist_lock; - struct list_head s_inodes_wb; - long: 64; - long: 64; -}; - -struct vfsmount { - struct dentry *mnt_root; - struct super_block *mnt_sb; - int mnt_flags; - struct user_namespace *mnt_userns; -}; - -struct kstat { - u32 result_mask; - umode_t mode; - unsigned int nlink; - uint32_t blksize; - u64 attributes; - u64 attributes_mask; - u64 ino; - dev_t dev; - dev_t rdev; - kuid_t uid; - kgid_t gid; - loff_t size; - struct timespec64 atime; - struct timespec64 mtime; - struct timespec64 ctime; - struct timespec64 btime; - u64 blocks; - u64 mnt_id; -}; - -struct list_lru_one { - struct list_head list; - long int nr_items; -}; - -struct list_lru_memcg { - struct callback_head rcu; - struct list_lru_one *lru[0]; -}; - -struct list_lru_node { - spinlock_t lock; - struct list_lru_one lru; - struct list_lru_memcg *memcg_lrus; - long int nr_items; - long: 64; - long: 64; -}; - -enum migrate_mode { - MIGRATE_ASYNC = 0, - MIGRATE_SYNC_LIGHT = 1, - MIGRATE_SYNC = 2, - MIGRATE_SYNC_NO_COPY = 3, -}; - -struct key_tag { - struct callback_head rcu; - refcount_t usage; - bool removed; -}; - -typedef int (*request_key_actor_t)(struct key *, void *); - -struct key_preparsed_payload; - -struct key_match_data; - -struct kernel_pkey_params; - -struct kernel_pkey_query; - -struct key_type { - const char *name; - size_t def_datalen; - unsigned int flags; - int (*vet_description)(const char *); - int (*preparse)(struct key_preparsed_payload *); - void (*free_preparse)(struct key_preparsed_payload *); - int (*instantiate)(struct key *, struct key_preparsed_payload *); - int (*update)(struct key *, struct key_preparsed_payload *); - int (*match_preparse)(struct key_match_data *); - void (*match_free)(struct key_match_data *); - void (*revoke)(struct key *); - void (*destroy)(struct key *); - void (*describe)(const struct key *, struct seq_file *); - long int (*read)(const struct key *, char *, size_t); - request_key_actor_t request_key; - struct key_restriction * (*lookup_restriction)(const char *); - int (*asym_query)(const struct kernel_pkey_params *, struct kernel_pkey_query *); - int (*asym_eds_op)(struct kernel_pkey_params *, const void *, void *); - int (*asym_verify_signature)(struct kernel_pkey_params *, const void *, const void *); - struct list_head link; - struct lock_class_key lock_class; -}; - -typedef int (*key_restrict_link_func_t)(struct key *, const struct key_type *, const union key_payload *, struct key *); - -struct key_restriction { - key_restrict_link_func_t check; - struct key *key; - struct key_type *keytype; -}; - -struct user_struct { - refcount_t __count; - atomic_long_t epoll_watches; - long unsigned int unix_inflight; - atomic_long_t pipe_bufs; - struct hlist_node uidhash_node; - kuid_t uid; - atomic_long_t locked_vm; - atomic_t nr_watches; - struct ratelimit_state ratelimit; -}; - -struct group_info { - atomic_t usage; - int ngroups; - kgid_t gid[0]; -}; - -struct delayed_call { - void (*fn)(void *); - void *arg; -}; - -struct io_cq { - struct request_queue *q; - struct io_context *ioc; - union { - struct list_head q_node; - struct kmem_cache *__rcu_icq_cache; - }; - union { - struct hlist_node ioc_node; - struct callback_head __rcu_head; - }; - unsigned int flags; -}; - -struct wait_page_queue; - -struct kiocb { - struct file *ki_filp; - loff_t ki_pos; - void (*ki_complete)(struct kiocb *, long int, long int); - void *private; - int ki_flags; - u16 ki_hint; - u16 ki_ioprio; - union { - unsigned int ki_cookie; - struct wait_page_queue *ki_waitq; - }; -}; - -struct iattr { - unsigned int ia_valid; - umode_t ia_mode; - kuid_t ia_uid; - kgid_t ia_gid; - loff_t ia_size; - struct timespec64 ia_atime; - struct timespec64 ia_mtime; - struct timespec64 ia_ctime; - struct file *ia_file; -}; - -typedef __kernel_uid32_t projid_t; - -typedef struct { - projid_t val; -} kprojid_t; - -enum quota_type { - USRQUOTA = 0, - GRPQUOTA = 1, - PRJQUOTA = 2, -}; - -struct kqid { - union { - kuid_t uid; - kgid_t gid; - kprojid_t projid; - }; - enum quota_type type; -}; - -struct mem_dqblk { - qsize_t dqb_bhardlimit; - qsize_t dqb_bsoftlimit; - qsize_t dqb_curspace; - qsize_t dqb_rsvspace; - qsize_t dqb_ihardlimit; - qsize_t dqb_isoftlimit; - qsize_t dqb_curinodes; - time64_t dqb_btime; - time64_t dqb_itime; -}; - -struct dquot { - struct hlist_node dq_hash; - struct list_head dq_inuse; - struct list_head dq_free; - struct list_head dq_dirty; - struct mutex dq_lock; - spinlock_t dq_dqb_lock; - atomic_t dq_count; - struct super_block *dq_sb; - struct kqid dq_id; - loff_t dq_off; - long unsigned int dq_flags; - struct mem_dqblk dq_dqb; -}; - -enum { - DQF_ROOT_SQUASH_B = 0, - DQF_SYS_FILE_B = 16, - DQF_PRIVATE = 17, -}; - -struct quota_format_type { - int qf_fmt_id; - const struct quota_format_ops *qf_ops; - struct module *qf_owner; - struct quota_format_type *qf_next; -}; - -enum { - DQST_LOOKUPS = 0, - DQST_DROPS = 1, - DQST_READS = 2, - DQST_WRITES = 3, - DQST_CACHE_HITS = 4, - DQST_ALLOC_DQUOTS = 5, - DQST_FREE_DQUOTS = 6, - DQST_SYNCS = 7, - _DQST_DQSTAT_LAST = 8, -}; - -struct quota_format_ops { - int (*check_quota_file)(struct super_block *, int); - int (*read_file_info)(struct super_block *, int); - int (*write_file_info)(struct super_block *, int); - int (*free_file_info)(struct super_block *, int); - int (*read_dqblk)(struct dquot *); - int (*commit_dqblk)(struct dquot *); - int (*release_dqblk)(struct dquot *); - int (*get_next_id)(struct super_block *, struct kqid *); -}; - -struct dquot_operations { - int (*write_dquot)(struct dquot *); - struct dquot * (*alloc_dquot)(struct super_block *, int); - void (*destroy_dquot)(struct dquot *); - int (*acquire_dquot)(struct dquot *); - int (*release_dquot)(struct dquot *); - int (*mark_dirty)(struct dquot *); - int (*write_info)(struct super_block *, int); - qsize_t * (*get_reserved_space)(struct inode *); - int (*get_projid)(struct inode *, kprojid_t *); - int (*get_inode_usage)(struct inode *, qsize_t *); - int (*get_next_id)(struct super_block *, struct kqid *); -}; - -struct qc_dqblk { - int d_fieldmask; - u64 d_spc_hardlimit; - u64 d_spc_softlimit; - u64 d_ino_hardlimit; - u64 d_ino_softlimit; - u64 d_space; - u64 d_ino_count; - s64 d_ino_timer; - s64 d_spc_timer; - int d_ino_warns; - int d_spc_warns; - u64 d_rt_spc_hardlimit; - u64 d_rt_spc_softlimit; - u64 d_rt_space; - s64 d_rt_spc_timer; - int d_rt_spc_warns; -}; - -struct qc_type_state { - unsigned int flags; - unsigned int spc_timelimit; - unsigned int ino_timelimit; - unsigned int rt_spc_timelimit; - unsigned int spc_warnlimit; - unsigned int ino_warnlimit; - unsigned int rt_spc_warnlimit; - long long unsigned int ino; - blkcnt_t blocks; - blkcnt_t nextents; -}; - -struct qc_state { - unsigned int s_incoredqs; - struct qc_type_state s_state[3]; -}; - -struct qc_info { - int i_fieldmask; - unsigned int i_flags; - unsigned int i_spc_timelimit; - unsigned int i_ino_timelimit; - unsigned int i_rt_spc_timelimit; - unsigned int i_spc_warnlimit; - unsigned int i_ino_warnlimit; - unsigned int i_rt_spc_warnlimit; -}; - -struct quotactl_ops { - int (*quota_on)(struct super_block *, int, int, const struct path *); - int (*quota_off)(struct super_block *, int); - int (*quota_enable)(struct super_block *, unsigned int); - int (*quota_disable)(struct super_block *, unsigned int); - int (*quota_sync)(struct super_block *, int); - int (*set_info)(struct super_block *, int, struct qc_info *); - int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); - int (*get_nextdqblk)(struct super_block *, struct kqid *, struct qc_dqblk *); - int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); - int (*get_state)(struct super_block *, struct qc_state *); - int (*rm_xquota)(struct super_block *, unsigned int); -}; - -struct writeback_control; - -struct readahead_control; - -struct swap_info_struct; - -struct address_space_operations { - int (*writepage)(struct page *, struct writeback_control *); - int (*readpage)(struct file *, struct page *); - int (*writepages)(struct address_space *, struct writeback_control *); - int (*set_page_dirty)(struct page *); - int (*readpages)(struct file *, struct address_space *, struct list_head *, unsigned int); - void (*readahead)(struct readahead_control *); - int (*write_begin)(struct file *, struct address_space *, loff_t, unsigned int, unsigned int, struct page **, void **); - int (*write_end)(struct file *, struct address_space *, loff_t, unsigned int, unsigned int, struct page *, void *); - sector_t (*bmap)(struct address_space *, sector_t); - void (*invalidatepage)(struct page *, unsigned int, unsigned int); - int (*releasepage)(struct page *, gfp_t); - void (*freepage)(struct page *); - ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *); - int (*migratepage)(struct address_space *, struct page *, struct page *, enum migrate_mode); - bool (*isolate_page)(struct page *, isolate_mode_t); - void (*putback_page)(struct page *); - int (*launder_page)(struct page *); - int (*is_partially_uptodate)(struct page *, long unsigned int, long unsigned int); - void (*is_dirty_writeback)(struct page *, bool *, bool *); - int (*error_remove_page)(struct address_space *, struct page *); - int (*swap_activate)(struct swap_info_struct *, struct file *, sector_t *); - void (*swap_deactivate)(struct file *); -}; - -struct fiemap_extent_info; - -struct fileattr; - -struct inode_operations { - struct dentry * (*lookup)(struct inode *, struct dentry *, unsigned int); - const char * (*get_link)(struct dentry *, struct inode *, struct delayed_call *); - int (*permission)(struct user_namespace *, struct inode *, int); - struct posix_acl * (*get_acl)(struct inode *, int); - int (*readlink)(struct dentry *, char *, int); - int (*create)(struct user_namespace *, struct inode *, struct dentry *, umode_t, bool); - int (*link)(struct dentry *, struct inode *, struct dentry *); - int (*unlink)(struct inode *, struct dentry *); - int (*symlink)(struct user_namespace *, struct inode *, struct dentry *, const char *); - int (*mkdir)(struct user_namespace *, struct inode *, struct dentry *, umode_t); - int (*rmdir)(struct inode *, struct dentry *); - int (*mknod)(struct user_namespace *, struct inode *, struct dentry *, umode_t, dev_t); - int (*rename)(struct user_namespace *, struct inode *, struct dentry *, struct inode *, struct dentry *, unsigned int); - int (*setattr)(struct user_namespace *, struct dentry *, struct iattr *); - int (*getattr)(struct user_namespace *, const struct path *, struct kstat *, u32, unsigned int); - ssize_t (*listxattr)(struct dentry *, char *, size_t); - int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64, u64); - int (*update_time)(struct inode *, struct timespec64 *, int); - int (*atomic_open)(struct inode *, struct dentry *, struct file *, unsigned int, umode_t); - int (*tmpfile)(struct user_namespace *, struct inode *, struct dentry *, umode_t); - int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int); - int (*fileattr_set)(struct user_namespace *, struct dentry *, struct fileattr *); - int (*fileattr_get)(struct dentry *, struct fileattr *); - long: 64; -}; - -struct file_lock_context { - spinlock_t flc_lock; - struct list_head flc_flock; - struct list_head flc_posix; - struct list_head flc_lease; -}; - -struct file_lock_operations { - void (*fl_copy_lock)(struct file_lock *, struct file_lock *); - void (*fl_release_private)(struct file_lock *); -}; - -struct nlm_lockowner; - -struct nfs_lock_info { - u32 state; - struct nlm_lockowner *owner; - struct list_head list; -}; - -struct nfs4_lock_state; - -struct nfs4_lock_info { - struct nfs4_lock_state *owner; -}; - -struct fasync_struct; - -struct lock_manager_operations; - -struct file_lock { - struct file_lock *fl_blocker; - struct list_head fl_list; - struct hlist_node fl_link; - struct list_head fl_blocked_requests; - struct list_head fl_blocked_member; - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - unsigned int fl_pid; - int fl_link_cpu; - wait_queue_head_t fl_wait; - struct file *fl_file; - loff_t fl_start; - loff_t fl_end; - struct fasync_struct *fl_fasync; - long unsigned int fl_break_time; - long unsigned int fl_downgrade_time; - const struct file_lock_operations *fl_ops; - const struct lock_manager_operations *fl_lmops; - union { - struct nfs_lock_info nfs_fl; - struct nfs4_lock_info nfs4_fl; - struct { - struct list_head link; - int state; - unsigned int debug_id; - } afs; - } fl_u; -}; - -struct lock_manager_operations { - fl_owner_t (*lm_get_owner)(fl_owner_t); - void (*lm_put_owner)(fl_owner_t); - void (*lm_notify)(struct file_lock *); - int (*lm_grant)(struct file_lock *, int); - bool (*lm_break)(struct file_lock *); - int (*lm_change)(struct file_lock *, int, struct list_head *); - void (*lm_setup)(struct file_lock *, void **); - bool (*lm_breaker_owns_lease)(struct file_lock *); -}; - -struct fasync_struct { - rwlock_t fa_lock; - int magic; - int fa_fd; - struct fasync_struct *fa_next; - struct file *fa_file; - struct callback_head fa_rcu; -}; - -enum { - SB_UNFROZEN = 0, - SB_FREEZE_WRITE = 1, - SB_FREEZE_PAGEFAULT = 2, - SB_FREEZE_FS = 3, - SB_FREEZE_COMPLETE = 4, -}; - -struct kstatfs; - -struct super_operations { - struct inode * (*alloc_inode)(struct super_block *); - void (*destroy_inode)(struct inode *); - void (*free_inode)(struct inode *); - void (*dirty_inode)(struct inode *, int); - int (*write_inode)(struct inode *, struct writeback_control *); - int (*drop_inode)(struct inode *); - void (*evict_inode)(struct inode *); - void (*put_super)(struct super_block *); - int (*sync_fs)(struct super_block *, int); - int (*freeze_super)(struct super_block *); - int (*freeze_fs)(struct super_block *); - int (*thaw_super)(struct super_block *); - int (*unfreeze_fs)(struct super_block *); - int (*statfs)(struct dentry *, struct kstatfs *); - int (*remount_fs)(struct super_block *, int *, char *); - void (*umount_begin)(struct super_block *); - int (*show_options)(struct seq_file *, struct dentry *); - int (*show_devname)(struct seq_file *, struct dentry *); - int (*show_path)(struct seq_file *, struct dentry *); - int (*show_stats)(struct seq_file *, struct dentry *); - ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); - ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); - struct dquot ** (*get_dquots)(struct inode *); - long int (*nr_cached_objects)(struct super_block *, struct shrink_control *); - long int (*free_cached_objects)(struct super_block *, struct shrink_control *); -}; - -struct iomap; - -struct fid; - -struct export_operations { - int (*encode_fh)(struct inode *, __u32 *, int *, struct inode *); - struct dentry * (*fh_to_dentry)(struct super_block *, struct fid *, int, int); - struct dentry * (*fh_to_parent)(struct super_block *, struct fid *, int, int); - int (*get_name)(struct dentry *, char *, struct dentry *); - struct dentry * (*get_parent)(struct dentry *); - int (*commit_metadata)(struct inode *); - int (*get_uuid)(struct super_block *, u8 *, u32 *, u64 *); - int (*map_blocks)(struct inode *, loff_t, u64, struct iomap *, bool, u32 *); - int (*commit_blocks)(struct inode *, struct iomap *, int, struct iattr *); - u64 (*fetch_iversion)(struct inode *); - long unsigned int flags; -}; - -struct xattr_handler { - const char *name; - const char *prefix; - int flags; - bool (*list)(struct dentry *); - int (*get)(const struct xattr_handler *, struct dentry *, struct inode *, const char *, void *, size_t); - int (*set)(const struct xattr_handler *, struct user_namespace *, struct dentry *, struct inode *, const char *, const void *, size_t, int); -}; - -union fscrypt_policy; - -struct fscrypt_operations { - unsigned int flags; - const char *key_prefix; - int (*get_context)(struct inode *, void *, size_t); - int (*set_context)(struct inode *, const void *, size_t, void *); - const union fscrypt_policy * (*get_dummy_policy)(struct super_block *); - bool (*empty_dir)(struct inode *); - unsigned int max_namelen; - bool (*has_stable_inodes)(struct super_block *); - void (*get_ino_and_lblk_bits)(struct super_block *, int *, int *); - int (*get_num_devices)(struct super_block *); - void (*get_devices)(struct super_block *, struct request_queue **); -}; - -struct fsverity_operations { - int (*begin_enable_verity)(struct file *); - int (*end_enable_verity)(struct file *, const void *, size_t, u64); - int (*get_verity_descriptor)(struct inode *, void *, size_t); - struct page * (*read_merkle_tree_page)(struct inode *, long unsigned int, long unsigned int); - int (*write_merkle_tree_block)(struct inode *, const void *, u64, int); -}; - -typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64, unsigned int); - -struct dir_context { - filldir_t actor; - loff_t pos; -}; - -struct p_log; - -struct fs_parameter; - -struct fs_parse_result; - -typedef int fs_param_type(struct p_log *, const struct fs_parameter_spec *, struct fs_parameter *, struct fs_parse_result *); - -struct fs_parameter_spec { - const char *name; - fs_param_type *type; - u8 opt; - short unsigned int flags; - const void *data; -}; - -enum compound_dtor_id { - NULL_COMPOUND_DTOR = 0, - COMPOUND_PAGE_DTOR = 1, - HUGETLB_PAGE_DTOR = 2, - TRANSHUGE_PAGE_DTOR = 3, - NR_COMPOUND_DTORS = 4, -}; - -enum vm_event_item { - PGPGIN = 0, - PGPGOUT = 1, - PSWPIN = 2, - PSWPOUT = 3, - PGALLOC_DMA = 4, - PGALLOC_DMA32 = 5, - PGALLOC_NORMAL = 6, - PGALLOC_MOVABLE = 7, - ALLOCSTALL_DMA = 8, - ALLOCSTALL_DMA32 = 9, - ALLOCSTALL_NORMAL = 10, - ALLOCSTALL_MOVABLE = 11, - PGSCAN_SKIP_DMA = 12, - PGSCAN_SKIP_DMA32 = 13, - PGSCAN_SKIP_NORMAL = 14, - PGSCAN_SKIP_MOVABLE = 15, - PGFREE = 16, - PGACTIVATE = 17, - PGDEACTIVATE = 18, - PGLAZYFREE = 19, - PGFAULT = 20, - PGMAJFAULT = 21, - PGLAZYFREED = 22, - PGREFILL = 23, - PGREUSE = 24, - PGSTEAL_KSWAPD = 25, - PGSTEAL_DIRECT = 26, - PGSCAN_KSWAPD = 27, - PGSCAN_DIRECT = 28, - PGSCAN_DIRECT_THROTTLE = 29, - PGSCAN_ANON = 30, - PGSCAN_FILE = 31, - PGSTEAL_ANON = 32, - PGSTEAL_FILE = 33, - PGSCAN_ZONE_RECLAIM_FAILED = 34, - PGINODESTEAL = 35, - SLABS_SCANNED = 36, - KSWAPD_INODESTEAL = 37, - KSWAPD_LOW_WMARK_HIT_QUICKLY = 38, - KSWAPD_HIGH_WMARK_HIT_QUICKLY = 39, - PAGEOUTRUN = 40, - PGROTATED = 41, - DROP_PAGECACHE = 42, - DROP_SLAB = 43, - OOM_KILL = 44, - NUMA_PTE_UPDATES = 45, - NUMA_HUGE_PTE_UPDATES = 46, - NUMA_HINT_FAULTS = 47, - NUMA_HINT_FAULTS_LOCAL = 48, - NUMA_PAGE_MIGRATE = 49, - PGMIGRATE_SUCCESS = 50, - PGMIGRATE_FAIL = 51, - THP_MIGRATION_SUCCESS = 52, - THP_MIGRATION_FAIL = 53, - THP_MIGRATION_SPLIT = 54, - COMPACTMIGRATE_SCANNED = 55, - COMPACTFREE_SCANNED = 56, - COMPACTISOLATED = 57, - COMPACTSTALL = 58, - COMPACTFAIL = 59, - COMPACTSUCCESS = 60, - KCOMPACTD_WAKE = 61, - KCOMPACTD_MIGRATE_SCANNED = 62, - KCOMPACTD_FREE_SCANNED = 63, - HTLB_BUDDY_PGALLOC = 64, - HTLB_BUDDY_PGALLOC_FAIL = 65, - CMA_ALLOC_SUCCESS = 66, - CMA_ALLOC_FAIL = 67, - UNEVICTABLE_PGCULLED = 68, - UNEVICTABLE_PGSCANNED = 69, - UNEVICTABLE_PGRESCUED = 70, - UNEVICTABLE_PGMLOCKED = 71, - UNEVICTABLE_PGMUNLOCKED = 72, - UNEVICTABLE_PGCLEARED = 73, - UNEVICTABLE_PGSTRANDED = 74, - THP_FAULT_ALLOC = 75, - THP_FAULT_FALLBACK = 76, - THP_FAULT_FALLBACK_CHARGE = 77, - THP_COLLAPSE_ALLOC = 78, - THP_COLLAPSE_ALLOC_FAILED = 79, - THP_FILE_ALLOC = 80, - THP_FILE_FALLBACK = 81, - THP_FILE_FALLBACK_CHARGE = 82, - THP_FILE_MAPPED = 83, - THP_SPLIT_PAGE = 84, - THP_SPLIT_PAGE_FAILED = 85, - THP_DEFERRED_SPLIT_PAGE = 86, - THP_SPLIT_PMD = 87, - THP_SPLIT_PUD = 88, - THP_ZERO_PAGE_ALLOC = 89, - THP_ZERO_PAGE_ALLOC_FAILED = 90, - THP_SWPOUT = 91, - THP_SWPOUT_FALLBACK = 92, - BALLOON_INFLATE = 93, - BALLOON_DEFLATE = 94, - BALLOON_MIGRATE = 95, - SWAP_RA = 96, - SWAP_RA_HIT = 97, - DIRECT_MAP_LEVEL2_SPLIT = 98, - DIRECT_MAP_LEVEL3_SPLIT = 99, - NR_VM_EVENT_ITEMS = 100, -}; - -struct tlb_context { - u64 ctx_id; - u64 tlb_gen; -}; - -struct tlb_state { - struct mm_struct *loaded_mm; - union { - struct mm_struct *last_user_mm; - long unsigned int last_user_mm_ibpb; - }; - u16 loaded_mm_asid; - u16 next_asid; - bool invalidate_other; - short unsigned int user_pcid_flush_mask; - long unsigned int cr4; - struct tlb_context ctxs[6]; -}; - -struct boot_params_to_save { - unsigned int start; - unsigned int len; -}; - -enum cpu_idle_type { - CPU_IDLE = 0, - CPU_NOT_IDLE = 1, - CPU_NEWLY_IDLE = 2, - CPU_MAX_IDLE_TYPES = 3, -}; - -enum { - __SD_BALANCE_NEWIDLE = 0, - __SD_BALANCE_EXEC = 1, - __SD_BALANCE_FORK = 2, - __SD_BALANCE_WAKE = 3, - __SD_WAKE_AFFINE = 4, - __SD_ASYM_CPUCAPACITY = 5, - __SD_ASYM_CPUCAPACITY_FULL = 6, - __SD_SHARE_CPUCAPACITY = 7, - __SD_SHARE_PKG_RESOURCES = 8, - __SD_SERIALIZE = 9, - __SD_ASYM_PACKING = 10, - __SD_PREFER_SIBLING = 11, - __SD_OVERLAP = 12, - __SD_NUMA = 13, - __SD_FLAG_CNT = 14, -}; - -struct x86_legacy_devices { - int pnpbios; -}; - -enum x86_legacy_i8042_state { - X86_LEGACY_I8042_PLATFORM_ABSENT = 0, - X86_LEGACY_I8042_FIRMWARE_ABSENT = 1, - X86_LEGACY_I8042_EXPECTED_PRESENT = 2, -}; - -struct x86_legacy_features { - enum x86_legacy_i8042_state i8042; - int rtc; - int warm_reset; - int no_vga; - int reserve_bios_regions; - struct x86_legacy_devices devices; -}; - -struct ghcb; - -struct x86_hyper_runtime { - void (*pin_vcpu)(int); - void (*sev_es_hcall_prepare)(struct ghcb *, struct pt_regs *); - bool (*sev_es_hcall_finish)(struct ghcb *, struct pt_regs *); -}; - -struct x86_platform_ops { - long unsigned int (*calibrate_cpu)(); - long unsigned int (*calibrate_tsc)(); - void (*get_wallclock)(struct timespec64 *); - int (*set_wallclock)(const struct timespec64 *); - void (*iommu_shutdown)(); - bool (*is_untracked_pat_range)(u64, u64); - void (*nmi_init)(); - unsigned char (*get_nmi_reason)(); - void (*save_sched_clock_state)(); - void (*restore_sched_clock_state)(); - void (*apic_post_init)(); - struct x86_legacy_features legacy; - void (*set_legacy_features)(); - struct x86_hyper_runtime hyper; -}; - -typedef signed char __s8; - -typedef __s8 s8; - -typedef __u32 __le32; - -typedef long unsigned int irq_hw_number_t; - -struct kernel_symbol { - int value_offset; - int name_offset; - int namespace_offset; -}; - -typedef int (*initcall_t)(); - -typedef int initcall_entry_t; - -struct obs_kernel_param { - const char *str; - int (*setup_func)(char *); - int early; -}; - -struct lockdep_map {}; - -struct jump_entry { - s32 code; - s32 target; - long int key; -}; - -struct static_key_mod; - -struct static_key { - atomic_t enabled; - union { - long unsigned int type; - struct jump_entry *entries; - struct static_key_mod *next; - }; -}; - -struct static_key_true { - struct static_key key; -}; - -struct static_key_false { - struct static_key key; -}; - -struct _ddebug { - const char *modname; - const char *function; - const char *filename; - const char *format; - unsigned int lineno: 18; - unsigned int flags: 8; - union { - struct static_key_true dd_key_true; - struct static_key_false dd_key_false; - } key; -}; - -struct static_call_site { - s32 addr; - s32 key; -}; - -struct static_call_mod { - struct static_call_mod *next; - struct module *mod; - struct static_call_site *sites; -}; - -struct static_call_key { - void *func; - union { - long unsigned int type; - struct static_call_mod *mods; - struct static_call_site *sites; - }; -}; - -enum system_states { - SYSTEM_BOOTING = 0, - SYSTEM_SCHEDULING = 1, - SYSTEM_RUNNING = 2, - SYSTEM_HALT = 3, - SYSTEM_POWER_OFF = 4, - SYSTEM_RESTART = 5, - SYSTEM_SUSPEND = 6, -}; - -struct orc_entry { - s16 sp_offset; - s16 bp_offset; - unsigned int sp_reg: 4; - unsigned int bp_reg: 4; - unsigned int type: 2; - unsigned int end: 1; -} __attribute__((packed)); - -struct bug_entry { - int bug_addr_disp; - int file_disp; - short unsigned int line; - short unsigned int flags; -}; - -typedef struct cpumask cpumask_var_t[1]; - -struct tracepoint_func { - void *func; - void *data; - int prio; -}; - -struct tracepoint { - const char *name; - struct static_key key; - struct static_call_key *static_call_key; - void *static_call_tramp; - void *iterator; - int (*regfunc)(); - void (*unregfunc)(); - struct tracepoint_func *funcs; -}; - -typedef const int tracepoint_ptr_t; - -struct bpf_raw_event_map { - struct tracepoint *tp; - void *bpf_func; - u32 num_args; - u32 writable_size; - long: 64; -}; - -struct seq_operations { - void * (*start)(struct seq_file *, loff_t *); - void (*stop)(struct seq_file *, void *); - void * (*next)(struct seq_file *, void *, loff_t *); - int (*show)(struct seq_file *, void *); -}; - -struct fixed_percpu_data { - char gs_base[40]; - long unsigned int stack_canary; -}; - -enum perf_event_state { - PERF_EVENT_STATE_DEAD = 4294967292, - PERF_EVENT_STATE_EXIT = 4294967293, - PERF_EVENT_STATE_ERROR = 4294967294, - PERF_EVENT_STATE_OFF = 4294967295, - PERF_EVENT_STATE_INACTIVE = 0, - PERF_EVENT_STATE_ACTIVE = 1, -}; - -typedef struct { - atomic_long_t a; -} local_t; - -typedef struct { - local_t a; -} local64_t; - -struct perf_event_attr { - __u32 type; - __u32 size; - __u64 config; - union { - __u64 sample_period; - __u64 sample_freq; - }; - __u64 sample_type; - __u64 read_format; - __u64 disabled: 1; - __u64 inherit: 1; - __u64 pinned: 1; - __u64 exclusive: 1; - __u64 exclude_user: 1; - __u64 exclude_kernel: 1; - __u64 exclude_hv: 1; - __u64 exclude_idle: 1; - __u64 mmap: 1; - __u64 comm: 1; - __u64 freq: 1; - __u64 inherit_stat: 1; - __u64 enable_on_exec: 1; - __u64 task: 1; - __u64 watermark: 1; - __u64 precise_ip: 2; - __u64 mmap_data: 1; - __u64 sample_id_all: 1; - __u64 exclude_host: 1; - __u64 exclude_guest: 1; - __u64 exclude_callchain_kernel: 1; - __u64 exclude_callchain_user: 1; - __u64 mmap2: 1; - __u64 comm_exec: 1; - __u64 use_clockid: 1; - __u64 context_switch: 1; - __u64 write_backward: 1; - __u64 namespaces: 1; - __u64 ksymbol: 1; - __u64 bpf_event: 1; - __u64 aux_output: 1; - __u64 cgroup: 1; - __u64 text_poke: 1; - __u64 build_id: 1; - __u64 inherit_thread: 1; - __u64 remove_on_exec: 1; - __u64 sigtrap: 1; - __u64 __reserved_1: 26; - union { - __u32 wakeup_events; - __u32 wakeup_watermark; - }; - __u32 bp_type; - union { - __u64 bp_addr; - __u64 kprobe_func; - __u64 uprobe_path; - __u64 config1; - }; - union { - __u64 bp_len; - __u64 kprobe_addr; - __u64 probe_offset; - __u64 config2; - }; - __u64 branch_sample_type; - __u64 sample_regs_user; - __u32 sample_stack_user; - __s32 clockid; - __u64 sample_regs_intr; - __u32 aux_watermark; - __u16 sample_max_stack; - __u16 __reserved_2; - __u32 aux_sample_size; - __u32 __reserved_3; - __u64 sig_data; -}; - -struct hw_perf_event_extra { - u64 config; - unsigned int reg; - int alloc; - int idx; -}; - -struct arch_hw_breakpoint { - long unsigned int address; - long unsigned int mask; - u8 len; - u8 type; -}; - -struct hw_perf_event { - union { - struct { - u64 config; - u64 last_tag; - long unsigned int config_base; - long unsigned int event_base; - int event_base_rdpmc; - int idx; - int last_cpu; - int flags; - struct hw_perf_event_extra extra_reg; - struct hw_perf_event_extra branch_reg; - }; - struct { - struct hrtimer hrtimer; - }; - struct { - struct list_head tp_list; - }; - struct { - u64 pwr_acc; - u64 ptsc; - }; - struct { - struct arch_hw_breakpoint info; - struct list_head bp_list; - }; - struct { - u8 iommu_bank; - u8 iommu_cntr; - u16 padding; - u64 conf; - u64 conf1; - }; - }; - struct task_struct *target; - void *addr_filters; - long unsigned int addr_filters_gen; - int state; - local64_t prev_count; - u64 sample_period; - union { - struct { - u64 last_period; - local64_t period_left; - }; - struct { - u64 saved_metric; - u64 saved_slots; - }; - }; - u64 interrupts_seq; - u64 interrupts; - u64 freq_time_stamp; - u64 freq_count_stamp; -}; - -struct irq_work { - struct __call_single_node node; - void (*func)(struct irq_work *); -}; - -struct perf_addr_filters_head { - struct list_head list; - raw_spinlock_t lock; - unsigned int nr_file_filters; -}; - -struct perf_sample_data; - -typedef void (*perf_overflow_handler_t)(struct perf_event *, struct perf_sample_data *, struct pt_regs *); - -struct ftrace_ops; - -struct ftrace_regs; - -typedef void (*ftrace_func_t)(long unsigned int, long unsigned int, struct ftrace_ops *, struct ftrace_regs *); - -struct ftrace_hash; - -struct ftrace_ops_hash { - struct ftrace_hash *notrace_hash; - struct ftrace_hash *filter_hash; - struct mutex regex_lock; -}; - -struct ftrace_ops { - ftrace_func_t func; - struct ftrace_ops *next; - long unsigned int flags; - void *private; - ftrace_func_t saved_func; - struct ftrace_ops_hash local_hash; - struct ftrace_ops_hash *func_hash; - struct ftrace_ops_hash old_hash; - long unsigned int trampoline; - long unsigned int trampoline_size; - struct list_head list; -}; - -struct pmu; - -struct perf_buffer; - -struct perf_addr_filter_range; - -struct bpf_prog; - -struct trace_event_call; - -struct event_filter; - -struct perf_cgroup; - -struct perf_event { - struct list_head event_entry; - struct list_head sibling_list; - struct list_head active_list; - struct rb_node group_node; - u64 group_index; - struct list_head migrate_entry; - struct hlist_node hlist_entry; - struct list_head active_entry; - int nr_siblings; - int event_caps; - int group_caps; - struct perf_event *group_leader; - struct pmu *pmu; - void *pmu_private; - enum perf_event_state state; - unsigned int attach_state; - local64_t count; - atomic64_t child_count; - u64 total_time_enabled; - u64 total_time_running; - u64 tstamp; - u64 shadow_ctx_time; - struct perf_event_attr attr; - u16 header_size; - u16 id_header_size; - u16 read_size; - struct hw_perf_event hw; - struct perf_event_context *ctx; - atomic_long_t refcount; - atomic64_t child_total_time_enabled; - atomic64_t child_total_time_running; - struct mutex child_mutex; - struct list_head child_list; - struct perf_event *parent; - int oncpu; - int cpu; - struct list_head owner_entry; - struct task_struct *owner; - struct mutex mmap_mutex; - atomic_t mmap_count; - struct perf_buffer *rb; - struct list_head rb_entry; - long unsigned int rcu_batches; - int rcu_pending; - wait_queue_head_t waitq; - struct fasync_struct *fasync; - int pending_wakeup; - int pending_kill; - int pending_disable; - long unsigned int pending_addr; - struct irq_work pending; - atomic_t event_limit; - struct perf_addr_filters_head addr_filters; - struct perf_addr_filter_range *addr_filter_ranges; - long unsigned int addr_filters_gen; - struct perf_event *aux_event; - void (*destroy)(struct perf_event *); - struct callback_head callback_head; - struct pid_namespace *ns; - u64 id; - u64 (*clock)(); - perf_overflow_handler_t overflow_handler; - void *overflow_handler_context; - perf_overflow_handler_t orig_overflow_handler; - struct bpf_prog *prog; - struct trace_event_call *tp_event; - struct event_filter *filter; - struct ftrace_ops ftrace_ops; - struct perf_cgroup *cgrp; - void *security; - struct list_head sb_list; -}; - -struct uid_gid_extent { - u32 first; - u32 lower_first; - u32 count; -}; - -struct uid_gid_map { - u32 nr_extents; - union { - struct uid_gid_extent extent[5]; - struct { - struct uid_gid_extent *forward; - struct uid_gid_extent *reverse; - }; - }; -}; - -struct proc_ns_operations; - -struct ns_common { - atomic_long_t stashed; - const struct proc_ns_operations *ops; - unsigned int inum; - refcount_t count; -}; - -struct ctl_table; - -struct ctl_table_root; - -struct ctl_table_set; - -struct ctl_dir; - -struct ctl_node; - -struct ctl_table_header { - union { - struct { - struct ctl_table *ctl_table; - int used; - int count; - int nreg; - }; - struct callback_head rcu; - }; - struct completion *unregistering; - struct ctl_table *ctl_table_arg; - struct ctl_table_root *root; - struct ctl_table_set *set; - struct ctl_dir *parent; - struct ctl_node *node; - struct hlist_head inodes; -}; - -struct ctl_dir { - struct ctl_table_header header; - struct rb_root root; -}; - -struct ctl_table_set { - int (*is_seen)(struct ctl_table_set *); - struct ctl_dir dir; -}; - -struct user_namespace { - struct uid_gid_map uid_map; - struct uid_gid_map gid_map; - struct uid_gid_map projid_map; - struct user_namespace *parent; - int level; - kuid_t owner; - kgid_t group; - struct ns_common ns; - long unsigned int flags; - bool parent_could_setfcap; - struct list_head keyring_name_list; - struct key *user_keyring_register; - struct rw_semaphore keyring_sem; - struct key *persistent_keyring_register; - struct work_struct work; - struct ctl_table_set set; - struct ctl_table_header *sysctls; - struct ucounts *ucounts; - long int ucount_max[16]; -}; - -struct pollfd { - int fd; - short int events; - short int revents; -}; - -typedef void (*smp_call_func_t)(void *); - -struct __call_single_data { - struct __call_single_node node; - smp_call_func_t func; - void *info; -}; - -struct smp_ops { - void (*smp_prepare_boot_cpu)(); - void (*smp_prepare_cpus)(unsigned int); - void (*smp_cpus_done)(unsigned int); - void (*stop_other_cpus)(int); - void (*crash_stop_other_cpus)(); - void (*smp_send_reschedule)(int); - int (*cpu_up)(unsigned int, struct task_struct *); - int (*cpu_disable)(); - void (*cpu_die)(unsigned int); - void (*play_dead)(); - void (*send_call_func_ipi)(const struct cpumask *); - void (*send_call_func_single_ipi)(int); -}; - -struct wait_queue_entry; - -typedef int (*wait_queue_func_t)(struct wait_queue_entry *, unsigned int, int, void *); - -struct wait_queue_entry { - unsigned int flags; - void *private; - wait_queue_func_t func; - struct list_head entry; -}; - -typedef struct wait_queue_entry wait_queue_entry_t; - -struct timer_list { - struct hlist_node entry; - long unsigned int expires; - void (*function)(struct timer_list *); - u32 flags; -}; - -struct delayed_work { - struct work_struct work; - struct timer_list timer; - struct workqueue_struct *wq; - int cpu; -}; - -struct rcu_work { - struct work_struct work; - struct callback_head rcu; - struct workqueue_struct *wq; -}; - -struct rcu_segcblist { - struct callback_head *head; - struct callback_head **tails[4]; - long unsigned int gp_seq[4]; - long int len; - long int seglen[4]; - u8 flags; -}; - -struct srcu_node; - -struct srcu_struct; - -struct srcu_data { - long unsigned int srcu_lock_count[2]; - long unsigned int srcu_unlock_count[2]; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t lock; - struct rcu_segcblist srcu_cblist; - long unsigned int srcu_gp_seq_needed; - long unsigned int srcu_gp_seq_needed_exp; - bool srcu_cblist_invoking; - struct timer_list delay_work; - struct work_struct work; - struct callback_head srcu_barrier_head; - struct srcu_node *mynode; - long unsigned int grpmask; - int cpu; - struct srcu_struct *ssp; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct srcu_node { - spinlock_t lock; - long unsigned int srcu_have_cbs[4]; - long unsigned int srcu_data_have_cbs[4]; - long unsigned int srcu_gp_seq_needed_exp; - struct srcu_node *srcu_parent; - int grplo; - int grphi; -}; - -struct srcu_struct { - struct srcu_node node[21]; - struct srcu_node *level[3]; - struct mutex srcu_cb_mutex; - spinlock_t lock; - struct mutex srcu_gp_mutex; - unsigned int srcu_idx; - long unsigned int srcu_gp_seq; - long unsigned int srcu_gp_seq_needed; - long unsigned int srcu_gp_seq_needed_exp; - long unsigned int srcu_last_gp_end; - struct srcu_data *sda; - long unsigned int srcu_barrier_seq; - struct mutex srcu_barrier_mutex; - struct completion srcu_barrier_completion; - atomic_t srcu_barrier_cpu_cnt; - struct delayed_work work; - struct lockdep_map dep_map; -}; - -struct anon_vma { - struct anon_vma *root; - struct rw_semaphore rwsem; - atomic_t refcount; - unsigned int degree; - struct anon_vma *parent; - struct rb_root_cached rb_root; -}; - -struct mempolicy { - atomic_t refcnt; - short unsigned int mode; - short unsigned int flags; - nodemask_t nodes; - union { - nodemask_t cpuset_mems_allowed; - nodemask_t user_nodemask; - } w; -}; - -struct linux_binprm; - -struct coredump_params; - -struct linux_binfmt { - struct list_head lh; - struct module *module; - int (*load_binary)(struct linux_binprm *); - int (*load_shlib)(struct file *); - int (*core_dump)(struct coredump_params *); - long unsigned int min_coredump; -}; - -struct free_area { - struct list_head free_list[6]; - long unsigned int nr_free; -}; - -struct zone_padding { - char x[0]; -}; - -struct pglist_data; - -struct lruvec { - struct list_head lists[5]; - spinlock_t lru_lock; - long unsigned int anon_cost; - long unsigned int file_cost; - atomic_long_t nonresident_age; - long unsigned int refaults[2]; - long unsigned int flags; - struct pglist_data *pgdat; -}; - -struct per_cpu_pages; - -struct per_cpu_zonestat; - -struct zone { - long unsigned int _watermark[3]; - long unsigned int watermark_boost; - long unsigned int nr_reserved_highatomic; - long int lowmem_reserve[5]; - int node; - struct pglist_data *zone_pgdat; - struct per_cpu_pages *per_cpu_pageset; - struct per_cpu_zonestat *per_cpu_zonestats; - int pageset_high; - int pageset_batch; - long unsigned int zone_start_pfn; - atomic_long_t managed_pages; - long unsigned int spanned_pages; - long unsigned int present_pages; - long unsigned int cma_pages; - const char *name; - long unsigned int nr_isolate_pageblock; - seqlock_t span_seqlock; - int initialized; - int: 32; - struct zone_padding _pad1_; - struct free_area free_area[11]; - long unsigned int flags; - spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct zone_padding _pad2_; - long unsigned int percpu_drift_mark; - long unsigned int compact_cached_free_pfn; - long unsigned int compact_cached_migrate_pfn[2]; - long unsigned int compact_init_migrate_pfn; - long unsigned int compact_init_free_pfn; - unsigned int compact_considered; - unsigned int compact_defer_shift; - int compact_order_failed; - bool compact_blockskip_flush; - bool contiguous; - short: 16; - struct zone_padding _pad3_; - atomic_long_t vm_stat[11]; - atomic_long_t vm_numa_event[6]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct zoneref { - struct zone *zone; - int zone_idx; -}; - -struct zonelist { - struct zoneref _zonerefs[161]; -}; - -enum zone_type { - ZONE_DMA = 0, - ZONE_DMA32 = 1, - ZONE_NORMAL = 2, - ZONE_MOVABLE = 3, - ZONE_DEVICE = 4, - __MAX_NR_ZONES = 5, -}; - -struct deferred_split { - spinlock_t split_queue_lock; - struct list_head split_queue; - long unsigned int split_queue_len; -}; - -struct per_cpu_nodestat; - -struct pglist_data { - struct zone node_zones[5]; - struct zonelist node_zonelists[2]; - int nr_zones; - spinlock_t node_size_lock; - long unsigned int node_start_pfn; - long unsigned int node_present_pages; - long unsigned int node_spanned_pages; - int node_id; - wait_queue_head_t kswapd_wait; - wait_queue_head_t pfmemalloc_wait; - struct task_struct *kswapd; - int kswapd_order; - enum zone_type kswapd_highest_zoneidx; - int kswapd_failures; - int kcompactd_max_order; - enum zone_type kcompactd_highest_zoneidx; - wait_queue_head_t kcompactd_wait; - struct task_struct *kcompactd; - long unsigned int totalreserve_pages; - long unsigned int min_unmapped_pages; - long unsigned int min_slab_pages; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct zone_padding _pad1_; - struct deferred_split deferred_split_queue; - struct lruvec __lruvec; - long unsigned int flags; - long: 64; - struct zone_padding _pad2_; - struct per_cpu_nodestat *per_cpu_nodestats; - atomic_long_t vm_stat[39]; -}; - -struct per_cpu_pages { - int count; - int high; - int batch; - short int free_factor; - short int expire; - struct list_head lists[15]; -}; - -struct per_cpu_zonestat { - s8 vm_stat_diff[11]; - s8 stat_threshold; - long unsigned int vm_numa_event[6]; -}; - -struct per_cpu_nodestat { - s8 stat_threshold; - s8 vm_node_stat_diff[39]; -}; - -typedef struct pglist_data pg_data_t; - -enum irq_domain_bus_token { - DOMAIN_BUS_ANY = 0, - DOMAIN_BUS_WIRED = 1, - DOMAIN_BUS_GENERIC_MSI = 2, - DOMAIN_BUS_PCI_MSI = 3, - DOMAIN_BUS_PLATFORM_MSI = 4, - DOMAIN_BUS_NEXUS = 5, - DOMAIN_BUS_IPI = 6, - DOMAIN_BUS_FSL_MC_MSI = 7, - DOMAIN_BUS_TI_SCI_INTA_MSI = 8, - DOMAIN_BUS_WAKEUP = 9, - DOMAIN_BUS_VMD_MSI = 10, -}; - -struct irq_domain_ops; - -struct fwnode_handle; - -struct irq_domain_chip_generic; - -struct irq_data; - -struct irq_domain { - struct list_head link; - const char *name; - const struct irq_domain_ops *ops; - void *host_data; - unsigned int flags; - unsigned int mapcount; - struct fwnode_handle *fwnode; - enum irq_domain_bus_token bus_token; - struct irq_domain_chip_generic *gc; - struct irq_domain *parent; - irq_hw_number_t hwirq_max; - unsigned int revmap_size; - struct xarray revmap_tree; - struct mutex revmap_mutex; - struct irq_data *revmap[0]; -}; - -typedef int proc_handler(struct ctl_table *, int, void *, size_t *, loff_t *); - -struct ctl_table_poll; - -struct ctl_table { - const char *procname; - void *data; - int maxlen; - umode_t mode; - struct ctl_table *child; - proc_handler *proc_handler; - struct ctl_table_poll *poll; - void *extra1; - void *extra2; -}; - -struct ctl_table_poll { - atomic_t event; - wait_queue_head_t wait; -}; - -struct ctl_node { - struct rb_node node; - struct ctl_table_header *header; -}; - -struct ctl_table_root { - struct ctl_table_set default_set; - struct ctl_table_set * (*lookup)(struct ctl_table_root *); - void (*set_ownership)(struct ctl_table_header *, struct ctl_table *, kuid_t *, kgid_t *); - int (*permissions)(struct ctl_table_header *, struct ctl_table *); -}; - -enum umh_disable_depth { - UMH_ENABLED = 0, - UMH_FREEZING = 1, - UMH_DISABLED = 2, -}; - -typedef __u64 Elf64_Addr; - -typedef __u16 Elf64_Half; - -typedef __u32 Elf64_Word; - -typedef __u64 Elf64_Xword; - -struct elf64_sym { - Elf64_Word st_name; - unsigned char st_info; - unsigned char st_other; - Elf64_Half st_shndx; - Elf64_Addr st_value; - Elf64_Xword st_size; -}; - -typedef struct elf64_sym Elf64_Sym; - -struct idr { - struct xarray idr_rt; - unsigned int idr_base; - unsigned int idr_next; -}; - -struct kernfs_root; - -struct kernfs_elem_dir { - long unsigned int subdirs; - struct rb_root children; - struct kernfs_root *root; -}; - -struct kernfs_node; - -struct kernfs_syscall_ops; - -struct kernfs_root { - struct kernfs_node *kn; - unsigned int flags; - struct idr ino_idr; - u32 last_id_lowbits; - u32 id_highbits; - struct kernfs_syscall_ops *syscall_ops; - struct list_head supers; - wait_queue_head_t deactivate_waitq; -}; - -struct kernfs_elem_symlink { - struct kernfs_node *target_kn; -}; - -struct kernfs_ops; - -struct kernfs_open_node; - -struct kernfs_elem_attr { - const struct kernfs_ops *ops; - struct kernfs_open_node *open; - loff_t size; - struct kernfs_node *notify_next; -}; - -struct kernfs_iattrs; - -struct kernfs_node { - atomic_t count; - atomic_t active; - struct kernfs_node *parent; - const char *name; - struct rb_node rb; - const void *ns; - unsigned int hash; - union { - struct kernfs_elem_dir dir; - struct kernfs_elem_symlink symlink; - struct kernfs_elem_attr attr; - }; - void *priv; - u64 id; - short unsigned int flags; - umode_t mode; - struct kernfs_iattrs *iattr; -}; - -struct kernfs_open_file; - -struct kernfs_ops { - int (*open)(struct kernfs_open_file *); - void (*release)(struct kernfs_open_file *); - int (*seq_show)(struct seq_file *, void *); - void * (*seq_start)(struct seq_file *, loff_t *); - void * (*seq_next)(struct seq_file *, void *, loff_t *); - void (*seq_stop)(struct seq_file *, void *); - ssize_t (*read)(struct kernfs_open_file *, char *, size_t, loff_t); - size_t atomic_write_len; - bool prealloc; - ssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t); - __poll_t (*poll)(struct kernfs_open_file *, struct poll_table_struct *); - int (*mmap)(struct kernfs_open_file *, struct vm_area_struct *); -}; - -struct kernfs_syscall_ops { - int (*show_options)(struct seq_file *, struct kernfs_root *); - int (*mkdir)(struct kernfs_node *, const char *, umode_t); - int (*rmdir)(struct kernfs_node *); - int (*rename)(struct kernfs_node *, struct kernfs_node *, const char *); - int (*show_path)(struct seq_file *, struct kernfs_node *, struct kernfs_root *); -}; - -struct seq_file { - char *buf; - size_t size; - size_t from; - size_t count; - size_t pad_until; - loff_t index; - loff_t read_pos; - struct mutex lock; - const struct seq_operations *op; - int poll_event; - const struct file *file; - void *private; -}; - -struct kernfs_open_file { - struct kernfs_node *kn; - struct file *file; - struct seq_file *seq_file; - void *priv; - struct mutex mutex; - struct mutex prealloc_mutex; - int event; - struct list_head list; - char *prealloc_buf; - size_t atomic_write_len; - bool mmapped: 1; - bool released: 1; - const struct vm_operations_struct *vm_ops; -}; - -typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); - -struct poll_table_struct { - poll_queue_proc _qproc; - __poll_t _key; -}; - -enum kobj_ns_type { - KOBJ_NS_TYPE_NONE = 0, - KOBJ_NS_TYPE_NET = 1, - KOBJ_NS_TYPES = 2, -}; - -struct sock; - -struct kobj_ns_type_operations { - enum kobj_ns_type type; - bool (*current_may_mount)(); - void * (*grab_current_ns)(); - const void * (*netlink_ns)(struct sock *); - const void * (*initial_ns)(); - void (*drop_ns)(void *); -}; - -struct attribute { - const char *name; - umode_t mode; -}; - -struct kobject; - -struct bin_attribute; - -struct attribute_group { - const char *name; - umode_t (*is_visible)(struct kobject *, struct attribute *, int); - umode_t (*is_bin_visible)(struct kobject *, struct bin_attribute *, int); - struct attribute **attrs; - struct bin_attribute **bin_attrs; -}; - -struct kref { - refcount_t refcount; -}; - -struct kset; - -struct kobj_type; - -struct kobject { - const char *name; - struct list_head entry; - struct kobject *parent; - struct kset *kset; - struct kobj_type *ktype; - struct kernfs_node *sd; - struct kref kref; - unsigned int state_initialized: 1; - unsigned int state_in_sysfs: 1; - unsigned int state_add_uevent_sent: 1; - unsigned int state_remove_uevent_sent: 1; - unsigned int uevent_suppress: 1; -}; - -struct bin_attribute { - struct attribute attr; - size_t size; - void *private; - struct address_space *mapping; - ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t); - ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t); - int (*mmap)(struct file *, struct kobject *, struct bin_attribute *, struct vm_area_struct *); -}; - -struct sysfs_ops { - ssize_t (*show)(struct kobject *, struct attribute *, char *); - ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); -}; - -enum refcount_saturation_type { - REFCOUNT_ADD_NOT_ZERO_OVF = 0, - REFCOUNT_ADD_OVF = 1, - REFCOUNT_ADD_UAF = 2, - REFCOUNT_SUB_UAF = 3, - REFCOUNT_DEC_LEAK = 4, -}; - -struct kset_uevent_ops; - -struct kset { - struct list_head list; - spinlock_t list_lock; - struct kobject kobj; - const struct kset_uevent_ops *uevent_ops; -}; - -struct kobj_type { - void (*release)(struct kobject *); - const struct sysfs_ops *sysfs_ops; - struct attribute **default_attrs; - const struct attribute_group **default_groups; - const struct kobj_ns_type_operations * (*child_ns_type)(struct kobject *); - const void * (*namespace)(struct kobject *); - void (*get_ownership)(struct kobject *, kuid_t *, kgid_t *); -}; - -struct kobj_uevent_env { - char *argv[3]; - char *envp[64]; - int envp_idx; - char buf[2048]; - int buflen; -}; - -struct kset_uevent_ops { - int (* const filter)(struct kset *, struct kobject *); - const char * (* const name)(struct kset *, struct kobject *); - int (* const uevent)(struct kset *, struct kobject *, struct kobj_uevent_env *); -}; - -struct kernel_param; - -struct kernel_param_ops { - unsigned int flags; - int (*set)(const char *, const struct kernel_param *); - int (*get)(char *, const struct kernel_param *); - void (*free)(void *); -}; - -struct kparam_string; - -struct kparam_array; - -struct kernel_param { - const char *name; - struct module *mod; - const struct kernel_param_ops *ops; - const u16 perm; - s8 level; - u8 flags; - union { - void *arg; - const struct kparam_string *str; - const struct kparam_array *arr; - }; -}; - -struct kparam_string { - unsigned int maxlen; - char *string; -}; - -struct kparam_array { - unsigned int max; - unsigned int elemsize; - unsigned int *num; - const struct kernel_param_ops *ops; - void *elem; -}; - -enum module_state { - MODULE_STATE_LIVE = 0, - MODULE_STATE_COMING = 1, - MODULE_STATE_GOING = 2, - MODULE_STATE_UNFORMED = 3, -}; - -struct module_param_attrs; - -struct module_kobject { - struct kobject kobj; - struct module *mod; - struct kobject *drivers_dir; - struct module_param_attrs *mp; - struct completion *kobj_completion; -}; - -struct latch_tree_node { - struct rb_node node[2]; -}; - -struct mod_tree_node { - struct module *mod; - struct latch_tree_node node; -}; - -struct module_layout { - void *base; - unsigned int size; - unsigned int text_size; - unsigned int ro_size; - unsigned int ro_after_init_size; - struct mod_tree_node mtn; -}; - -struct mod_arch_specific { - unsigned int num_orcs; - int *orc_unwind_ip; - struct orc_entry *orc_unwind; -}; - -struct mod_kallsyms { - Elf64_Sym *symtab; - unsigned int num_symtab; - char *strtab; - char *typetab; -}; - -struct module_attribute; - -struct exception_table_entry; - -struct module_sect_attrs; - -struct module_notes_attrs; - -struct trace_eval_map; - -struct error_injection_entry; - -struct module { - enum module_state state; - struct list_head list; - char name[56]; - unsigned char build_id[20]; - struct module_kobject mkobj; - struct module_attribute *modinfo_attrs; - const char *version; - const char *srcversion; - struct kobject *holders_dir; - const struct kernel_symbol *syms; - const s32 *crcs; - unsigned int num_syms; - struct mutex param_lock; - struct kernel_param *kp; - unsigned int num_kp; - unsigned int num_gpl_syms; - const struct kernel_symbol *gpl_syms; - const s32 *gpl_crcs; - bool using_gplonly_symbols; - bool sig_ok; - bool async_probe_requested; - unsigned int num_exentries; - struct exception_table_entry *extable; - int (*init)(); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct module_layout core_layout; - struct module_layout init_layout; - struct mod_arch_specific arch; - long unsigned int taints; - unsigned int num_bugs; - struct list_head bug_list; - struct bug_entry *bug_table; - struct mod_kallsyms *kallsyms; - struct mod_kallsyms core_kallsyms; - struct module_sect_attrs *sect_attrs; - struct module_notes_attrs *notes_attrs; - char *args; - void *percpu; - unsigned int percpu_size; - void *noinstr_text_start; - unsigned int noinstr_text_size; - unsigned int num_tracepoints; - tracepoint_ptr_t *tracepoints_ptrs; - unsigned int num_srcu_structs; - struct srcu_struct **srcu_struct_ptrs; - unsigned int num_bpf_raw_events; - struct bpf_raw_event_map *bpf_raw_events; - unsigned int btf_data_size; - void *btf_data; - struct jump_entry *jump_entries; - unsigned int num_jump_entries; - unsigned int num_trace_bprintk_fmt; - const char **trace_bprintk_fmt_start; - struct trace_event_call **trace_events; - unsigned int num_trace_events; - struct trace_eval_map **trace_evals; - unsigned int num_trace_evals; - unsigned int num_ftrace_callsites; - long unsigned int *ftrace_callsites; - void *kprobes_text_start; - unsigned int kprobes_text_size; - long unsigned int *kprobe_blacklist; - unsigned int num_kprobe_blacklist; - int num_static_call_sites; - struct static_call_site *static_call_sites; - struct list_head source_list; - struct list_head target_list; - void (*exit)(); - atomic_t refcnt; - struct error_injection_entry *ei_funcs; - unsigned int num_ei_funcs; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct error_injection_entry { - long unsigned int addr; - int etype; -}; - -struct module_attribute { - struct attribute attr; - ssize_t (*show)(struct module_attribute *, struct module_kobject *, char *); - ssize_t (*store)(struct module_attribute *, struct module_kobject *, const char *, size_t); - void (*setup)(struct module *, const char *); - int (*test)(struct module *); - void (*free)(struct module *); -}; - -struct exception_table_entry { - int insn; - int fixup; - int handler; -}; - -struct trace_event_functions; - -struct trace_event { - struct hlist_node node; - struct list_head list; - int type; - struct trace_event_functions *funcs; -}; - -struct trace_event_class; - -struct bpf_prog_array; - -struct trace_event_call { - struct list_head list; - struct trace_event_class *class; - union { - char *name; - struct tracepoint *tp; - }; - struct trace_event event; - char *print_fmt; - struct event_filter *filter; - void *mod; - void *data; - int flags; - int perf_refcount; - struct hlist_head *perf_events; - struct bpf_prog_array *prog_array; - int (*perf_perm)(struct trace_event_call *, struct perf_event *); -}; - -struct trace_eval_map { - const char *system; - const char *eval_string; - long unsigned int eval_value; -}; - -struct cgroup; - -struct cgroup_subsys; - -struct cgroup_subsys_state { - struct cgroup *cgroup; - struct cgroup_subsys *ss; - struct percpu_ref refcnt; - struct list_head sibling; - struct list_head children; - struct list_head rstat_css_node; - int id; - unsigned int flags; - u64 serial_nr; - atomic_t online_cnt; - struct work_struct destroy_work; - struct rcu_work destroy_rwork; - struct cgroup_subsys_state *parent; -}; - -struct mem_cgroup_id { - int id; - refcount_t ref; -}; - -struct page_counter { - atomic_long_t usage; - long unsigned int min; - long unsigned int low; - long unsigned int high; - long unsigned int max; - long unsigned int emin; - atomic_long_t min_usage; - atomic_long_t children_min_usage; - long unsigned int elow; - atomic_long_t low_usage; - atomic_long_t children_low_usage; - long unsigned int watermark; - long unsigned int failcnt; - struct page_counter *parent; -}; - -struct vmpressure { - long unsigned int scanned; - long unsigned int reclaimed; - long unsigned int tree_scanned; - long unsigned int tree_reclaimed; - spinlock_t sr_lock; - struct list_head events; - struct mutex events_lock; - struct work_struct work; -}; - -struct cgroup_file { - struct kernfs_node *kn; - long unsigned int notified_at; - struct timer_list notify_timer; -}; - -struct mem_cgroup_threshold_ary; - -struct mem_cgroup_thresholds { - struct mem_cgroup_threshold_ary *primary; - struct mem_cgroup_threshold_ary *spare; -}; - -struct memcg_padding { - char x[0]; -}; - -struct memcg_vmstats { - long int state[42]; - long unsigned int events[100]; - long int state_pending[42]; - long unsigned int events_pending[100]; -}; - -enum memcg_kmem_state { - KMEM_NONE = 0, - KMEM_ALLOCATED = 1, - KMEM_ONLINE = 2, -}; - -struct percpu_counter { - raw_spinlock_t lock; - s64 count; - struct list_head list; - s32 *counters; -}; - -struct fprop_global { - struct percpu_counter events; - unsigned int period; - seqcount_t sequence; -}; - -struct wb_domain { - spinlock_t lock; - struct fprop_global completions; - struct timer_list period_timer; - long unsigned int period_time; - long unsigned int dirty_limit_tstamp; - long unsigned int dirty_limit; -}; - -struct wb_completion { - atomic_t cnt; - wait_queue_head_t *waitq; -}; - -struct memcg_cgwb_frn { - u64 bdi_id; - int memcg_id; - u64 at; - struct wb_completion done; -}; - -struct obj_cgroup; - -struct memcg_vmstats_percpu; - -struct mem_cgroup_per_node; - -struct mem_cgroup { - struct cgroup_subsys_state css; - struct mem_cgroup_id id; - struct page_counter memory; - union { - struct page_counter swap; - struct page_counter memsw; - }; - struct page_counter kmem; - struct page_counter tcpmem; - struct work_struct high_work; - long unsigned int soft_limit; - struct vmpressure vmpressure; - bool oom_group; - bool oom_lock; - int under_oom; - int swappiness; - int oom_kill_disable; - struct cgroup_file events_file; - struct cgroup_file events_local_file; - struct cgroup_file swap_events_file; - struct mutex thresholds_lock; - struct mem_cgroup_thresholds thresholds; - struct mem_cgroup_thresholds memsw_thresholds; - struct list_head oom_notify; - long unsigned int move_charge_at_immigrate; - spinlock_t move_lock; - long unsigned int move_lock_flags; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct memcg_padding _pad1_; - struct memcg_vmstats vmstats; - atomic_long_t memory_events[8]; - atomic_long_t memory_events_local[8]; - long unsigned int socket_pressure; - bool tcpmem_active; - int tcpmem_pressure; - int kmemcg_id; - enum memcg_kmem_state kmem_state; - struct obj_cgroup *objcg; - struct list_head objcg_list; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct memcg_padding _pad2_; - atomic_t moving_account; - struct task_struct *move_lock_task; - struct memcg_vmstats_percpu *vmstats_percpu; - struct list_head cgwb_list; - struct wb_domain cgwb_domain; - struct memcg_cgwb_frn cgwb_frn[4]; - struct list_head event_list; - spinlock_t event_list_lock; - struct deferred_split deferred_split_queue; - struct mem_cgroup_per_node *nodeinfo[0]; - long: 64; -}; - -struct fs_pin; - -struct pid_namespace { - struct idr idr; - struct callback_head rcu; - unsigned int pid_allocated; - struct task_struct *child_reaper; - struct kmem_cache *pid_cachep; - unsigned int level; - struct pid_namespace *parent; - struct fs_pin *bacct; - struct user_namespace *user_ns; - struct ucounts *ucounts; - int reboot; - struct ns_common ns; -}; - -struct ucounts { - struct hlist_node node; - struct user_namespace *ns; - kuid_t uid; - atomic_t count; - atomic_long_t ucount[16]; -}; - -struct task_cputime { - u64 stime; - u64 utime; - long long unsigned int sum_exec_runtime; -}; - -struct uts_namespace; - -struct ipc_namespace; - -struct mnt_namespace; - -struct net; - -struct time_namespace; - -struct cgroup_namespace; - -struct nsproxy { - atomic_t count; - struct uts_namespace *uts_ns; - struct ipc_namespace *ipc_ns; - struct mnt_namespace *mnt_ns; - struct pid_namespace *pid_ns_for_children; - struct net *net_ns; - struct time_namespace *time_ns; - struct time_namespace *time_ns_for_children; - struct cgroup_namespace *cgroup_ns; -}; - -struct bio; - -struct bio_list { - struct bio *head; - struct bio *tail; -}; - -struct blk_plug { - struct list_head mq_list; - struct list_head cb_list; - short unsigned int rq_count; - bool multiple_queues; - bool nowait; -}; - -struct reclaim_state { - long unsigned int reclaimed_slab; -}; - -struct fprop_local_percpu { - struct percpu_counter events; - unsigned int period; - raw_spinlock_t lock; -}; - -enum wb_reason { - WB_REASON_BACKGROUND = 0, - WB_REASON_VMSCAN = 1, - WB_REASON_SYNC = 2, - WB_REASON_PERIODIC = 3, - WB_REASON_LAPTOP_TIMER = 4, - WB_REASON_FS_FREE_SPACE = 5, - WB_REASON_FORKER_THREAD = 6, - WB_REASON_FOREIGN_FLUSH = 7, - WB_REASON_MAX = 8, -}; - -struct bdi_writeback { - struct backing_dev_info *bdi; - long unsigned int state; - long unsigned int last_old_flush; - struct list_head b_dirty; - struct list_head b_io; - struct list_head b_more_io; - struct list_head b_dirty_time; - spinlock_t list_lock; - struct percpu_counter stat[4]; - long unsigned int congested; - long unsigned int bw_time_stamp; - long unsigned int dirtied_stamp; - long unsigned int written_stamp; - long unsigned int write_bandwidth; - long unsigned int avg_write_bandwidth; - long unsigned int dirty_ratelimit; - long unsigned int balanced_dirty_ratelimit; - struct fprop_local_percpu completions; - int dirty_exceeded; - enum wb_reason start_all_reason; - spinlock_t work_lock; - struct list_head work_list; - struct delayed_work dwork; - long unsigned int dirty_sleep; - struct list_head bdi_node; - struct percpu_ref refcnt; - struct fprop_local_percpu memcg_completions; - struct cgroup_subsys_state *memcg_css; - struct cgroup_subsys_state *blkcg_css; - struct list_head memcg_node; - struct list_head blkcg_node; - struct list_head b_attached; - struct list_head offline_node; - union { - struct work_struct release_work; - struct callback_head rcu; - }; -}; - -struct device; - -struct backing_dev_info { - u64 id; - struct rb_node rb_node; - struct list_head bdi_list; - long unsigned int ra_pages; - long unsigned int io_pages; - struct kref refcnt; - unsigned int capabilities; - unsigned int min_ratio; - unsigned int max_ratio; - unsigned int max_prop_frac; - atomic_long_t tot_write_bandwidth; - struct bdi_writeback wb; - struct list_head wb_list; - struct xarray cgwb_tree; - struct mutex cgwb_release_mutex; - struct rw_semaphore wb_switch_rwsem; - wait_queue_head_t wb_waitq; - struct device *dev; - char dev_name[64]; - struct device *owner; - struct timer_list laptop_mode_wb_timer; - struct dentry *debug_dir; -}; - -struct css_set { - struct cgroup_subsys_state *subsys[14]; - refcount_t refcount; - struct css_set *dom_cset; - struct cgroup *dfl_cgrp; - int nr_tasks; - struct list_head tasks; - struct list_head mg_tasks; - struct list_head dying_tasks; - struct list_head task_iters; - struct list_head e_cset_node[14]; - struct list_head threaded_csets; - struct list_head threaded_csets_node; - struct hlist_node hlist; - struct list_head cgrp_links; - struct list_head mg_preload_node; - struct list_head mg_node; - struct cgroup *mg_src_cgrp; - struct cgroup *mg_dst_cgrp; - struct css_set *mg_dst_cset; - bool dead; - struct callback_head callback_head; -}; - -typedef u32 compat_uptr_t; - -struct compat_robust_list { - compat_uptr_t next; -}; - -typedef s32 compat_long_t; - -struct compat_robust_list_head { - struct compat_robust_list list; - compat_long_t futex_offset; - compat_uptr_t list_op_pending; -}; - -struct perf_event_groups { - struct rb_root tree; - u64 index; -}; - -struct perf_event_context { - struct pmu *pmu; - raw_spinlock_t lock; - struct mutex mutex; - struct list_head active_ctx_list; - struct perf_event_groups pinned_groups; - struct perf_event_groups flexible_groups; - struct list_head event_list; - struct list_head pinned_active; - struct list_head flexible_active; - int nr_events; - int nr_active; - int is_active; - int nr_stat; - int nr_freq; - int rotate_disable; - int rotate_necessary; - refcount_t refcount; - struct task_struct *task; - u64 time; - u64 timestamp; - struct perf_event_context *parent_ctx; - u64 parent_gen; - u64 generation; - int pin_count; - int nr_cgroups; - void *task_ctx_data; - struct callback_head callback_head; -}; - -struct task_delay_info { - raw_spinlock_t lock; - unsigned int flags; - u64 blkio_start; - u64 blkio_delay; - u64 swapin_delay; - u32 blkio_count; - u32 swapin_count; - u64 freepages_start; - u64 freepages_delay; - u64 thrashing_start; - u64 thrashing_delay; - u32 freepages_count; - u32 thrashing_count; -}; - -struct ftrace_ret_stack { - long unsigned int ret; - long unsigned int func; - long long unsigned int calltime; - long long unsigned int subtime; - long unsigned int *retp; -}; - -struct blk_integrity_profile; - -struct blk_integrity { - const struct blk_integrity_profile *profile; - unsigned char flags; - unsigned char tuple_size; - unsigned char interval_exp; - unsigned char tag_size; -}; - -enum rpm_status { - RPM_ACTIVE = 0, - RPM_RESUMING = 1, - RPM_SUSPENDED = 2, - RPM_SUSPENDING = 3, -}; - -struct blk_rq_stat { - u64 mean; - u64 min; - u64 max; - u32 nr_samples; - u64 batch; -}; - -struct sbitmap_word; - -struct sbitmap { - unsigned int depth; - unsigned int shift; - unsigned int map_nr; - bool round_robin; - struct sbitmap_word *map; - unsigned int *alloc_hint; -}; - -struct sbq_wait_state; - -struct sbitmap_queue { - struct sbitmap sb; - unsigned int wake_batch; - atomic_t wake_index; - struct sbq_wait_state *ws; - atomic_t ws_active; - unsigned int min_shallow_depth; -}; - -enum blk_bounce { - BLK_BOUNCE_NONE = 0, - BLK_BOUNCE_HIGH = 1, -}; - -enum blk_zoned_model { - BLK_ZONED_NONE = 0, - BLK_ZONED_HA = 1, - BLK_ZONED_HM = 2, -}; - -struct queue_limits { - enum blk_bounce bounce; - long unsigned int seg_boundary_mask; - long unsigned int virt_boundary_mask; - unsigned int max_hw_sectors; - unsigned int max_dev_sectors; - unsigned int chunk_sectors; - unsigned int max_sectors; - unsigned int max_segment_size; - unsigned int physical_block_size; - unsigned int logical_block_size; - unsigned int alignment_offset; - unsigned int io_min; - unsigned int io_opt; - unsigned int max_discard_sectors; - unsigned int max_hw_discard_sectors; - unsigned int max_write_same_sectors; - unsigned int max_write_zeroes_sectors; - unsigned int max_zone_append_sectors; - unsigned int discard_granularity; - unsigned int discard_alignment; - unsigned int zone_write_granularity; - short unsigned int max_segments; - short unsigned int max_integrity_segments; - short unsigned int max_discard_segments; - unsigned char misaligned; - unsigned char discard_misaligned; - unsigned char raid_partial_stripes_expensive; - enum blk_zoned_model zoned; -}; - -struct bsg_ops; - -struct bsg_class_device { - struct device *class_dev; - int minor; - struct request_queue *queue; - const struct bsg_ops *ops; -}; - -typedef void *mempool_alloc_t(gfp_t, void *); - -typedef void mempool_free_t(void *, void *); - -struct mempool_s { - spinlock_t lock; - int min_nr; - int curr_nr; - void **elements; - void *pool_data; - mempool_alloc_t *alloc; - mempool_free_t *free; - wait_queue_head_t wait; -}; - -typedef struct mempool_s mempool_t; - -struct bio_set { - struct kmem_cache *bio_slab; - unsigned int front_pad; - mempool_t bio_pool; - mempool_t bvec_pool; - mempool_t bio_integrity_pool; - mempool_t bvec_integrity_pool; - unsigned int back_pad; - spinlock_t rescue_lock; - struct bio_list rescue_list; - struct work_struct rescue_work; - struct workqueue_struct *rescue_workqueue; -}; - -struct request; - -struct elevator_queue; - -struct blk_queue_stats; - -struct rq_qos; - -struct blk_mq_ops; - -struct blk_mq_ctx; - -struct blk_mq_hw_ctx; - -struct blk_keyslot_manager; - -struct blk_stat_callback; - -struct blkcg_gq; - -struct blk_trace; - -struct blk_flush_queue; - -struct throtl_data; - -struct blk_mq_tag_set; - -struct request_queue { - struct request *last_merge; - struct elevator_queue *elevator; - struct percpu_ref q_usage_counter; - struct blk_queue_stats *stats; - struct rq_qos *rq_qos; - const struct blk_mq_ops *mq_ops; - struct blk_mq_ctx *queue_ctx; - unsigned int queue_depth; - struct blk_mq_hw_ctx **queue_hw_ctx; - unsigned int nr_hw_queues; - struct backing_dev_info *backing_dev_info; - void *queuedata; - long unsigned int queue_flags; - atomic_t pm_only; - int id; - spinlock_t queue_lock; - struct kobject kobj; - struct kobject *mq_kobj; - struct blk_integrity integrity; - struct device *dev; - enum rpm_status rpm_status; - long unsigned int nr_requests; - unsigned int dma_pad_mask; - unsigned int dma_alignment; - struct blk_keyslot_manager *ksm; - unsigned int rq_timeout; - int poll_nsec; - struct blk_stat_callback *poll_cb; - struct blk_rq_stat poll_stat[16]; - struct timer_list timeout; - struct work_struct timeout_work; - atomic_t nr_active_requests_shared_sbitmap; - struct sbitmap_queue sched_bitmap_tags; - struct sbitmap_queue sched_breserved_tags; - struct list_head icq_list; - long unsigned int blkcg_pols[1]; - struct blkcg_gq *root_blkg; - struct list_head blkg_list; - struct queue_limits limits; - unsigned int required_elevator_features; - unsigned int nr_zones; - long unsigned int *conv_zones_bitmap; - long unsigned int *seq_zones_wlock; - unsigned int max_open_zones; - unsigned int max_active_zones; - unsigned int sg_timeout; - unsigned int sg_reserved_size; - int node; - struct mutex debugfs_mutex; - struct blk_trace *blk_trace; - struct blk_flush_queue *fq; - struct list_head requeue_list; - spinlock_t requeue_lock; - struct delayed_work requeue_work; - struct mutex sysfs_lock; - struct mutex sysfs_dir_lock; - struct list_head unused_hctx_list; - spinlock_t unused_hctx_lock; - int mq_freeze_depth; - struct bsg_class_device bsg_dev; - struct throtl_data *td; - struct callback_head callback_head; - wait_queue_head_t mq_freeze_wq; - struct mutex mq_freeze_lock; - struct blk_mq_tag_set *tag_set; - struct list_head tag_set_list; - struct bio_set bio_split; - struct dentry *debugfs_dir; - struct dentry *sched_debugfs_dir; - struct dentry *rqos_debugfs_dir; - bool mq_sysfs_init_done; - size_t cmd_size; - u64 write_hints[5]; -}; - -struct cgroup_base_stat { - struct task_cputime cputime; -}; - -struct psi_group_cpu; - -struct psi_group { - struct mutex avgs_lock; - struct psi_group_cpu *pcpu; - u64 avg_total[6]; - u64 avg_last_update; - u64 avg_next_update; - struct delayed_work avgs_work; - u64 total[12]; - long unsigned int avg[18]; - struct task_struct *poll_task; - struct timer_list poll_timer; - wait_queue_head_t poll_wait; - atomic_t poll_wakeup; - struct mutex trigger_lock; - struct list_head triggers; - u32 nr_triggers[6]; - u32 poll_states; - u64 poll_min_period; - u64 polling_total[6]; - u64 polling_next_update; - u64 polling_until; -}; - -struct cgroup_bpf { - struct bpf_prog_array *effective[41]; - struct list_head progs[41]; - u32 flags[41]; - struct list_head storages; - struct bpf_prog_array *inactive; - struct percpu_ref refcnt; - struct work_struct release_work; -}; - -struct cgroup_freezer_state { - bool freeze; - int e_freeze; - int nr_frozen_descendants; - int nr_frozen_tasks; -}; - -struct cgroup_root; - -struct cgroup_rstat_cpu; - -struct cgroup { - struct cgroup_subsys_state self; - long unsigned int flags; - int level; - int max_depth; - int nr_descendants; - int nr_dying_descendants; - int max_descendants; - int nr_populated_csets; - int nr_populated_domain_children; - int nr_populated_threaded_children; - int nr_threaded_children; - struct kernfs_node *kn; - struct cgroup_file procs_file; - struct cgroup_file events_file; - u16 subtree_control; - u16 subtree_ss_mask; - u16 old_subtree_control; - u16 old_subtree_ss_mask; - struct cgroup_subsys_state *subsys[14]; - struct cgroup_root *root; - struct list_head cset_links; - struct list_head e_csets[14]; - struct cgroup *dom_cgrp; - struct cgroup *old_dom_cgrp; - struct cgroup_rstat_cpu *rstat_cpu; - struct list_head rstat_css_list; - struct cgroup_base_stat last_bstat; - struct cgroup_base_stat bstat; - struct prev_cputime prev_cputime; - struct list_head pidlists; - struct mutex pidlist_mutex; - wait_queue_head_t offline_waitq; - struct work_struct release_agent_work; - struct psi_group psi; - struct cgroup_bpf bpf; - atomic_t congestion_count; - struct cgroup_freezer_state freezer; - u64 ancestor_ids[0]; -}; - -struct taskstats { - __u16 version; - __u32 ac_exitcode; - __u8 ac_flag; - __u8 ac_nice; - __u64 cpu_count; - __u64 cpu_delay_total; - __u64 blkio_count; - __u64 blkio_delay_total; - __u64 swapin_count; - __u64 swapin_delay_total; - __u64 cpu_run_real_total; - __u64 cpu_run_virtual_total; - char ac_comm[32]; - __u8 ac_sched; - __u8 ac_pad[3]; - int: 32; - __u32 ac_uid; - __u32 ac_gid; - __u32 ac_pid; - __u32 ac_ppid; - __u32 ac_btime; - __u64 ac_etime; - __u64 ac_utime; - __u64 ac_stime; - __u64 ac_minflt; - __u64 ac_majflt; - __u64 coremem; - __u64 virtmem; - __u64 hiwater_rss; - __u64 hiwater_vm; - __u64 read_char; - __u64 write_char; - __u64 read_syscalls; - __u64 write_syscalls; - __u64 read_bytes; - __u64 write_bytes; - __u64 cancelled_write_bytes; - __u64 nvcsw; - __u64 nivcsw; - __u64 ac_utimescaled; - __u64 ac_stimescaled; - __u64 cpu_scaled_run_real_total; - __u64 freepages_count; - __u64 freepages_delay_total; - __u64 thrashing_count; - __u64 thrashing_delay_total; - __u64 ac_btime64; -}; - -typedef struct { - __u8 b[16]; -} guid_t; - -struct wait_page_queue { - struct page *page; - int bit_nr; - wait_queue_entry_t wait; -}; - -enum writeback_sync_modes { - WB_SYNC_NONE = 0, - WB_SYNC_ALL = 1, -}; - -struct writeback_control { - long int nr_to_write; - long int pages_skipped; - loff_t range_start; - loff_t range_end; - enum writeback_sync_modes sync_mode; - unsigned int for_kupdate: 1; - unsigned int for_background: 1; - unsigned int tagged_writepages: 1; - unsigned int for_reclaim: 1; - unsigned int range_cyclic: 1; - unsigned int for_sync: 1; - unsigned int no_cgroup_owner: 1; - unsigned int punt_to_cgroup: 1; - struct bdi_writeback *wb; - struct inode *inode; - int wb_id; - int wb_lcand_id; - int wb_tcand_id; - size_t wb_bytes; - size_t wb_lcand_bytes; - size_t wb_tcand_bytes; -}; - -struct readahead_control { - struct file *file; - struct address_space *mapping; - struct file_ra_state *ra; - long unsigned int _index; - unsigned int _nr_pages; - unsigned int _batch_count; -}; - -struct iovec; - -struct kvec; - -struct bio_vec; - -struct iov_iter { - u8 iter_type; - bool data_source; - size_t iov_offset; - size_t count; - union { - const struct iovec *iov; - const struct kvec *kvec; - const struct bio_vec *bvec; - struct xarray *xarray; - struct pipe_inode_info *pipe; - }; - union { - long unsigned int nr_segs; - struct { - unsigned int head; - unsigned int start_head; - }; - loff_t xarray_start; - }; -}; - -struct swap_cluster_info { - spinlock_t lock; - unsigned int data: 24; - unsigned int flags: 8; -}; - -struct swap_cluster_list { - struct swap_cluster_info head; - struct swap_cluster_info tail; -}; - -struct percpu_cluster; - -struct swap_info_struct { - struct percpu_ref users; - long unsigned int flags; - short int prio; - struct plist_node list; - signed char type; - unsigned int max; - unsigned char *swap_map; - struct swap_cluster_info *cluster_info; - struct swap_cluster_list free_clusters; - unsigned int lowest_bit; - unsigned int highest_bit; - unsigned int pages; - unsigned int inuse_pages; - unsigned int cluster_next; - unsigned int cluster_nr; - unsigned int *cluster_next_cpu; - struct percpu_cluster *percpu_cluster; - struct rb_root swap_extent_root; - struct block_device *bdev; - struct file *swap_file; - unsigned int old_block_size; - struct completion comp; - long unsigned int *frontswap_map; - atomic_t frontswap_pages; - spinlock_t lock; - spinlock_t cont_lock; - struct work_struct discard_work; - struct swap_cluster_list discard_clusters; - struct plist_node avail_lists[0]; -}; - -struct cdev { - struct kobject kobj; - struct module *owner; - const struct file_operations *ops; - struct list_head list; - dev_t dev; - unsigned int count; -}; - -enum dl_dev_state { - DL_DEV_NO_DRIVER = 0, - DL_DEV_PROBING = 1, - DL_DEV_DRIVER_BOUND = 2, - DL_DEV_UNBINDING = 3, -}; - -struct dev_links_info { - struct list_head suppliers; - struct list_head consumers; - struct list_head defer_sync; - enum dl_dev_state status; -}; - -struct pm_message { - int event; -}; - -typedef struct pm_message pm_message_t; - -enum rpm_request { - RPM_REQ_NONE = 0, - RPM_REQ_IDLE = 1, - RPM_REQ_SUSPEND = 2, - RPM_REQ_AUTOSUSPEND = 3, - RPM_REQ_RESUME = 4, -}; - -struct wakeup_source; - -struct wake_irq; - -struct pm_subsys_data; - -struct dev_pm_qos; - -struct dev_pm_info { - pm_message_t power_state; - unsigned int can_wakeup: 1; - unsigned int async_suspend: 1; - bool in_dpm_list: 1; - bool is_prepared: 1; - bool is_suspended: 1; - bool is_noirq_suspended: 1; - bool is_late_suspended: 1; - bool no_pm: 1; - bool early_init: 1; - bool direct_complete: 1; - u32 driver_flags; - spinlock_t lock; - struct list_head entry; - struct completion completion; - struct wakeup_source *wakeup; - bool wakeup_path: 1; - bool syscore: 1; - bool no_pm_callbacks: 1; - unsigned int must_resume: 1; - unsigned int may_skip_resume: 1; - struct hrtimer suspend_timer; - u64 timer_expires; - struct work_struct work; - wait_queue_head_t wait_queue; - struct wake_irq *wakeirq; - atomic_t usage_count; - atomic_t child_count; - unsigned int disable_depth: 3; - unsigned int idle_notification: 1; - unsigned int request_pending: 1; - unsigned int deferred_resume: 1; - unsigned int needs_force_resume: 1; - unsigned int runtime_auto: 1; - bool ignore_children: 1; - unsigned int no_callbacks: 1; - unsigned int irq_safe: 1; - unsigned int use_autosuspend: 1; - unsigned int timer_autosuspends: 1; - unsigned int memalloc_noio: 1; - unsigned int links_count; - enum rpm_request request; - enum rpm_status runtime_status; - int runtime_error; - int autosuspend_delay; - u64 last_busy; - u64 active_time; - u64 suspended_time; - u64 accounting_timestamp; - struct pm_subsys_data *subsys_data; - void (*set_latency_tolerance)(struct device *, s32); - struct dev_pm_qos *qos; -}; - -struct dev_archdata {}; - -enum device_removable { - DEVICE_REMOVABLE_NOT_SUPPORTED = 0, - DEVICE_REMOVABLE_UNKNOWN = 1, - DEVICE_FIXED = 2, - DEVICE_REMOVABLE = 3, -}; - -struct device_private; - -struct device_type; - -struct bus_type; - -struct device_driver; - -struct dev_pm_domain; - -struct em_perf_domain; - -struct dev_pin_info; - -struct dma_map_ops; - -struct bus_dma_region; - -struct device_dma_parameters; - -struct cma; - -struct device_node; - -struct class; - -struct iommu_group; - -struct dev_iommu; - -struct device { - struct kobject kobj; - struct device *parent; - struct device_private *p; - const char *init_name; - const struct device_type *type; - struct bus_type *bus; - struct device_driver *driver; - void *platform_data; - void *driver_data; - struct mutex mutex; - struct dev_links_info links; - struct dev_pm_info power; - struct dev_pm_domain *pm_domain; - struct em_perf_domain *em_pd; - struct irq_domain *msi_domain; - struct dev_pin_info *pins; - raw_spinlock_t msi_lock; - struct list_head msi_list; - const struct dma_map_ops *dma_ops; - u64 *dma_mask; - u64 coherent_dma_mask; - u64 bus_dma_limit; - const struct bus_dma_region *dma_range_map; - struct device_dma_parameters *dma_parms; - struct list_head dma_pools; - struct cma *cma_area; - struct dev_archdata archdata; - struct device_node *of_node; - struct fwnode_handle *fwnode; - int numa_node; - dev_t devt; - u32 id; - spinlock_t devres_lock; - struct list_head devres_head; - struct class *class; - const struct attribute_group **groups; - void (*release)(struct device *); - struct iommu_group *iommu_group; - struct dev_iommu *iommu; - enum device_removable removable; - bool offline_disabled: 1; - bool offline: 1; - bool of_node_reused: 1; - bool state_synced: 1; - bool can_match: 1; -}; - -struct disk_stats; - -struct gendisk; - -struct partition_meta_info; - -struct block_device { - sector_t bd_start_sect; - struct disk_stats *bd_stats; - long unsigned int bd_stamp; - bool bd_read_only; - dev_t bd_dev; - int bd_openers; - struct inode *bd_inode; - struct super_block *bd_super; - void *bd_claiming; - struct device bd_device; - void *bd_holder; - int bd_holders; - bool bd_write_holder; - struct list_head bd_holder_disks; - struct kobject *bd_holder_dir; - u8 bd_partno; - spinlock_t bd_size_lock; - struct gendisk *bd_disk; - struct backing_dev_info *bd_bdi; - int bd_fsfreeze_count; - struct mutex bd_fsfreeze_mutex; - struct super_block *bd_fsfreeze_sb; - struct partition_meta_info *bd_meta_info; -}; - -struct fc_log; - -struct p_log { - const char *prefix; - struct fc_log *log; -}; - -enum fs_context_purpose { - FS_CONTEXT_FOR_MOUNT = 0, - FS_CONTEXT_FOR_SUBMOUNT = 1, - FS_CONTEXT_FOR_RECONFIGURE = 2, -}; - -enum fs_context_phase { - FS_CONTEXT_CREATE_PARAMS = 0, - FS_CONTEXT_CREATING = 1, - FS_CONTEXT_AWAITING_MOUNT = 2, - FS_CONTEXT_AWAITING_RECONF = 3, - FS_CONTEXT_RECONF_PARAMS = 4, - FS_CONTEXT_RECONFIGURING = 5, - FS_CONTEXT_FAILED = 6, -}; - -struct fs_context_operations; - -struct fs_context { - const struct fs_context_operations *ops; - struct mutex uapi_mutex; - struct file_system_type *fs_type; - void *fs_private; - void *sget_key; - struct dentry *root; - struct user_namespace *user_ns; - struct net *net_ns; - const struct cred *cred; - struct p_log log; - const char *source; - void *security; - void *s_fs_info; - unsigned int sb_flags; - unsigned int sb_flags_mask; - unsigned int s_iflags; - unsigned int lsm_flags; - enum fs_context_purpose purpose: 8; - enum fs_context_phase phase: 8; - bool need_free: 1; - bool global: 1; - bool oldapi: 1; -}; - -struct audit_names; - -struct filename { - const char *name; - const char *uptr; - int refcnt; - struct audit_names *aname; - const char iname[0]; -}; - -typedef u8 blk_status_t; - -struct bvec_iter { - sector_t bi_sector; - unsigned int bi_size; - unsigned int bi_idx; - unsigned int bi_bvec_done; -}; - -typedef void bio_end_io_t(struct bio *); - -struct bio_issue { - u64 value; -}; - -struct bio_vec { - struct page *bv_page; - unsigned int bv_len; - unsigned int bv_offset; -}; - -struct bio_crypt_ctx; - -struct bio_integrity_payload; - -struct bio { - struct bio *bi_next; - struct block_device *bi_bdev; - unsigned int bi_opf; - short unsigned int bi_flags; - short unsigned int bi_ioprio; - short unsigned int bi_write_hint; - blk_status_t bi_status; - atomic_t __bi_remaining; - struct bvec_iter bi_iter; - bio_end_io_t *bi_end_io; - void *bi_private; - struct blkcg_gq *bi_blkg; - struct bio_issue bi_issue; - u64 bi_iocost_cost; - struct bio_crypt_ctx *bi_crypt_context; - union { - struct bio_integrity_payload *bi_integrity; - }; - short unsigned int bi_vcnt; - short unsigned int bi_max_vecs; - atomic_t __bi_cnt; - struct bio_vec *bi_io_vec; - struct bio_set *bi_pool; - struct bio_vec bi_inline_vecs[0]; -}; - -struct linux_binprm { - struct vm_area_struct *vma; - long unsigned int vma_pages; - struct mm_struct *mm; - long unsigned int p; - long unsigned int argmin; - unsigned int have_execfd: 1; - unsigned int execfd_creds: 1; - unsigned int secureexec: 1; - unsigned int point_of_no_return: 1; - struct file *executable; - struct file *interpreter; - struct file *file; - struct cred *cred; - int unsafe; - unsigned int per_clear; - int argc; - int envc; - const char *filename; - const char *interp; - const char *fdpath; - unsigned int interp_flags; - int execfd; - long unsigned int loader; - long unsigned int exec; - struct rlimit rlim_stack; - char buf[256]; -}; - -struct coredump_params { - const kernel_siginfo_t *siginfo; - struct pt_regs *regs; - struct file *file; - long unsigned int limit; - long unsigned int mm_flags; - loff_t written; - loff_t pos; - loff_t to_skip; -}; - -struct em_perf_state { - long unsigned int frequency; - long unsigned int power; - long unsigned int cost; -}; - -struct em_perf_domain { - struct em_perf_state *table; - int nr_perf_states; - int milliwatts; - long unsigned int cpus[0]; -}; - -struct dev_pm_ops { - int (*prepare)(struct device *); - void (*complete)(struct device *); - int (*suspend)(struct device *); - int (*resume)(struct device *); - int (*freeze)(struct device *); - int (*thaw)(struct device *); - int (*poweroff)(struct device *); - int (*restore)(struct device *); - int (*suspend_late)(struct device *); - int (*resume_early)(struct device *); - int (*freeze_late)(struct device *); - int (*thaw_early)(struct device *); - int (*poweroff_late)(struct device *); - int (*restore_early)(struct device *); - int (*suspend_noirq)(struct device *); - int (*resume_noirq)(struct device *); - int (*freeze_noirq)(struct device *); - int (*thaw_noirq)(struct device *); - int (*poweroff_noirq)(struct device *); - int (*restore_noirq)(struct device *); - int (*runtime_suspend)(struct device *); - int (*runtime_resume)(struct device *); - int (*runtime_idle)(struct device *); -}; - -struct pm_domain_data; - -struct pm_subsys_data { - spinlock_t lock; - unsigned int refcount; - unsigned int clock_op_might_sleep; - struct mutex clock_mutex; - struct list_head clock_list; - struct pm_domain_data *domain_data; -}; - -struct wakeup_source { - const char *name; - int id; - struct list_head entry; - spinlock_t lock; - struct wake_irq *wakeirq; - struct timer_list timer; - long unsigned int timer_expires; - ktime_t total_time; - ktime_t max_time; - ktime_t last_time; - ktime_t start_prevent_time; - ktime_t prevent_sleep_time; - long unsigned int event_count; - long unsigned int active_count; - long unsigned int relax_count; - long unsigned int expire_count; - long unsigned int wakeup_count; - struct device *dev; - bool active: 1; - bool autosleep_enabled: 1; -}; - -struct dev_pm_domain { - struct dev_pm_ops ops; - int (*start)(struct device *); - void (*detach)(struct device *, bool); - int (*activate)(struct device *); - void (*sync)(struct device *); - void (*dismiss)(struct device *); -}; - -struct iommu_ops; - -struct subsys_private; - -struct bus_type { - const char *name; - const char *dev_name; - struct device *dev_root; - const struct attribute_group **bus_groups; - const struct attribute_group **dev_groups; - const struct attribute_group **drv_groups; - int (*match)(struct device *, struct device_driver *); - int (*uevent)(struct device *, struct kobj_uevent_env *); - int (*probe)(struct device *); - void (*sync_state)(struct device *); - int (*remove)(struct device *); - void (*shutdown)(struct device *); - int (*online)(struct device *); - int (*offline)(struct device *); - int (*suspend)(struct device *, pm_message_t); - int (*resume)(struct device *); - int (*num_vf)(struct device *); - int (*dma_configure)(struct device *); - const struct dev_pm_ops *pm; - const struct iommu_ops *iommu_ops; - struct subsys_private *p; - struct lock_class_key lock_key; - bool need_parent_lock; -}; - -enum probe_type { - PROBE_DEFAULT_STRATEGY = 0, - PROBE_PREFER_ASYNCHRONOUS = 1, - PROBE_FORCE_SYNCHRONOUS = 2, -}; - -struct of_device_id; - -struct acpi_device_id; - -struct driver_private; - -struct device_driver { - const char *name; - struct bus_type *bus; - struct module *owner; - const char *mod_name; - bool suppress_bind_attrs; - enum probe_type probe_type; - const struct of_device_id *of_match_table; - const struct acpi_device_id *acpi_match_table; - int (*probe)(struct device *); - void (*sync_state)(struct device *); - int (*remove)(struct device *); - void (*shutdown)(struct device *); - int (*suspend)(struct device *, pm_message_t); - int (*resume)(struct device *); - const struct attribute_group **groups; - const struct attribute_group **dev_groups; - const struct dev_pm_ops *pm; - void (*coredump)(struct device *); - struct driver_private *p; -}; - -enum iommu_cap { - IOMMU_CAP_CACHE_COHERENCY = 0, - IOMMU_CAP_INTR_REMAP = 1, - IOMMU_CAP_NOEXEC = 2, -}; - -typedef u64 dma_addr_t; - -enum iommu_dev_features { - IOMMU_DEV_FEAT_AUX = 0, - IOMMU_DEV_FEAT_SVA = 1, - IOMMU_DEV_FEAT_IOPF = 2, -}; - -struct iommu_domain; - -struct iommu_iotlb_gather; - -struct iommu_device; - -struct iommu_resv_region; - -struct of_phandle_args; - -struct iommu_sva; - -struct iommu_fault_event; - -struct iommu_page_response; - -struct iommu_cache_invalidate_info; - -struct iommu_gpasid_bind_data; - -struct iommu_ops { - bool (*capable)(enum iommu_cap); - struct iommu_domain * (*domain_alloc)(unsigned int); - void (*domain_free)(struct iommu_domain *); - int (*attach_dev)(struct iommu_domain *, struct device *); - void (*detach_dev)(struct iommu_domain *, struct device *); - int (*map)(struct iommu_domain *, long unsigned int, phys_addr_t, size_t, int, gfp_t); - size_t (*unmap)(struct iommu_domain *, long unsigned int, size_t, struct iommu_iotlb_gather *); - void (*flush_iotlb_all)(struct iommu_domain *); - void (*iotlb_sync_map)(struct iommu_domain *, long unsigned int, size_t); - void (*iotlb_sync)(struct iommu_domain *, struct iommu_iotlb_gather *); - phys_addr_t (*iova_to_phys)(struct iommu_domain *, dma_addr_t); - struct iommu_device * (*probe_device)(struct device *); - void (*release_device)(struct device *); - void (*probe_finalize)(struct device *); - struct iommu_group * (*device_group)(struct device *); - int (*enable_nesting)(struct iommu_domain *); - int (*set_pgtable_quirks)(struct iommu_domain *, long unsigned int); - void (*get_resv_regions)(struct device *, struct list_head *); - void (*put_resv_regions)(struct device *, struct list_head *); - void (*apply_resv_region)(struct device *, struct iommu_domain *, struct iommu_resv_region *); - int (*of_xlate)(struct device *, struct of_phandle_args *); - bool (*is_attach_deferred)(struct iommu_domain *, struct device *); - bool (*dev_has_feat)(struct device *, enum iommu_dev_features); - bool (*dev_feat_enabled)(struct device *, enum iommu_dev_features); - int (*dev_enable_feat)(struct device *, enum iommu_dev_features); - int (*dev_disable_feat)(struct device *, enum iommu_dev_features); - int (*aux_attach_dev)(struct iommu_domain *, struct device *); - void (*aux_detach_dev)(struct iommu_domain *, struct device *); - int (*aux_get_pasid)(struct iommu_domain *, struct device *); - struct iommu_sva * (*sva_bind)(struct device *, struct mm_struct *, void *); - void (*sva_unbind)(struct iommu_sva *); - u32 (*sva_get_pasid)(struct iommu_sva *); - int (*page_response)(struct device *, struct iommu_fault_event *, struct iommu_page_response *); - int (*cache_invalidate)(struct iommu_domain *, struct device *, struct iommu_cache_invalidate_info *); - int (*sva_bind_gpasid)(struct iommu_domain *, struct device *, struct iommu_gpasid_bind_data *); - int (*sva_unbind_gpasid)(struct device *, u32); - int (*def_domain_type)(struct device *); - long unsigned int pgsize_bitmap; - struct module *owner; -}; - -struct device_type { - const char *name; - const struct attribute_group **groups; - int (*uevent)(struct device *, struct kobj_uevent_env *); - char * (*devnode)(struct device *, umode_t *, kuid_t *, kgid_t *); - void (*release)(struct device *); - const struct dev_pm_ops *pm; -}; - -struct class { - const char *name; - struct module *owner; - const struct attribute_group **class_groups; - const struct attribute_group **dev_groups; - struct kobject *dev_kobj; - int (*dev_uevent)(struct device *, struct kobj_uevent_env *); - char * (*devnode)(struct device *, umode_t *); - void (*class_release)(struct class *); - void (*dev_release)(struct device *); - int (*shutdown_pre)(struct device *); - const struct kobj_ns_type_operations *ns_type; - const void * (*namespace)(struct device *); - void (*get_ownership)(struct device *, kuid_t *, kgid_t *); - const struct dev_pm_ops *pm; - struct subsys_private *p; -}; - -struct of_device_id { - char name[32]; - char type[32]; - char compatible[128]; - const void *data; -}; - -typedef long unsigned int kernel_ulong_t; - -struct acpi_device_id { - __u8 id[9]; - kernel_ulong_t driver_data; - __u32 cls; - __u32 cls_msk; -}; - -struct device_dma_parameters { - unsigned int max_segment_size; - unsigned int min_align_mask; - long unsigned int segment_boundary_mask; -}; - -enum dma_data_direction { - DMA_BIDIRECTIONAL = 0, - DMA_TO_DEVICE = 1, - DMA_FROM_DEVICE = 2, - DMA_NONE = 3, -}; - -struct sg_table; - -struct scatterlist; - -struct dma_map_ops { - void * (*alloc)(struct device *, size_t, dma_addr_t *, gfp_t, long unsigned int); - void (*free)(struct device *, size_t, void *, dma_addr_t, long unsigned int); - struct page * (*alloc_pages)(struct device *, size_t, dma_addr_t *, enum dma_data_direction, gfp_t); - void (*free_pages)(struct device *, size_t, struct page *, dma_addr_t, enum dma_data_direction); - struct sg_table * (*alloc_noncontiguous)(struct device *, size_t, enum dma_data_direction, gfp_t, long unsigned int); - void (*free_noncontiguous)(struct device *, size_t, struct sg_table *, enum dma_data_direction); - int (*mmap)(struct device *, struct vm_area_struct *, void *, dma_addr_t, size_t, long unsigned int); - int (*get_sgtable)(struct device *, struct sg_table *, void *, dma_addr_t, size_t, long unsigned int); - dma_addr_t (*map_page)(struct device *, struct page *, long unsigned int, size_t, enum dma_data_direction, long unsigned int); - void (*unmap_page)(struct device *, dma_addr_t, size_t, enum dma_data_direction, long unsigned int); - int (*map_sg)(struct device *, struct scatterlist *, int, enum dma_data_direction, long unsigned int); - void (*unmap_sg)(struct device *, struct scatterlist *, int, enum dma_data_direction, long unsigned int); - dma_addr_t (*map_resource)(struct device *, phys_addr_t, size_t, enum dma_data_direction, long unsigned int); - void (*unmap_resource)(struct device *, dma_addr_t, size_t, enum dma_data_direction, long unsigned int); - void (*sync_single_for_cpu)(struct device *, dma_addr_t, size_t, enum dma_data_direction); - void (*sync_single_for_device)(struct device *, dma_addr_t, size_t, enum dma_data_direction); - void (*sync_sg_for_cpu)(struct device *, struct scatterlist *, int, enum dma_data_direction); - void (*sync_sg_for_device)(struct device *, struct scatterlist *, int, enum dma_data_direction); - void (*cache_sync)(struct device *, void *, size_t, enum dma_data_direction); - int (*dma_supported)(struct device *, u64); - u64 (*get_required_mask)(struct device *); - size_t (*max_mapping_size)(struct device *); - long unsigned int (*get_merge_boundary)(struct device *); -}; - -struct bus_dma_region { - phys_addr_t cpu_start; - dma_addr_t dma_start; - u64 size; - u64 offset; -}; - -typedef u32 phandle; - -struct fwnode_operations; - -struct fwnode_handle { - struct fwnode_handle *secondary; - const struct fwnode_operations *ops; - struct device *dev; - struct list_head suppliers; - struct list_head consumers; - u8 flags; -}; - -struct property; - -struct device_node { - const char *name; - phandle phandle; - const char *full_name; - struct fwnode_handle fwnode; - struct property *properties; - struct property *deadprops; - struct device_node *parent; - struct device_node *child; - struct device_node *sibling; - long unsigned int _flags; - void *data; -}; - -enum cpuhp_state { - CPUHP_INVALID = 4294967295, - CPUHP_OFFLINE = 0, - CPUHP_CREATE_THREADS = 1, - CPUHP_PERF_PREPARE = 2, - CPUHP_PERF_X86_PREPARE = 3, - CPUHP_PERF_X86_AMD_UNCORE_PREP = 4, - CPUHP_PERF_POWER = 5, - CPUHP_PERF_SUPERH = 6, - CPUHP_X86_HPET_DEAD = 7, - CPUHP_X86_APB_DEAD = 8, - CPUHP_X86_MCE_DEAD = 9, - CPUHP_VIRT_NET_DEAD = 10, - CPUHP_SLUB_DEAD = 11, - CPUHP_DEBUG_OBJ_DEAD = 12, - CPUHP_MM_WRITEBACK_DEAD = 13, - CPUHP_MM_VMSTAT_DEAD = 14, - CPUHP_SOFTIRQ_DEAD = 15, - CPUHP_NET_MVNETA_DEAD = 16, - CPUHP_CPUIDLE_DEAD = 17, - CPUHP_ARM64_FPSIMD_DEAD = 18, - CPUHP_ARM_OMAP_WAKE_DEAD = 19, - CPUHP_IRQ_POLL_DEAD = 20, - CPUHP_BLOCK_SOFTIRQ_DEAD = 21, - CPUHP_ACPI_CPUDRV_DEAD = 22, - CPUHP_S390_PFAULT_DEAD = 23, - CPUHP_BLK_MQ_DEAD = 24, - CPUHP_FS_BUFF_DEAD = 25, - CPUHP_PRINTK_DEAD = 26, - CPUHP_MM_MEMCQ_DEAD = 27, - CPUHP_PERCPU_CNT_DEAD = 28, - CPUHP_RADIX_DEAD = 29, - CPUHP_PAGE_ALLOC = 30, - CPUHP_NET_DEV_DEAD = 31, - CPUHP_PCI_XGENE_DEAD = 32, - CPUHP_IOMMU_IOVA_DEAD = 33, - CPUHP_LUSTRE_CFS_DEAD = 34, - CPUHP_AP_ARM_CACHE_B15_RAC_DEAD = 35, - CPUHP_PADATA_DEAD = 36, - CPUHP_WORKQUEUE_PREP = 37, - CPUHP_POWER_NUMA_PREPARE = 38, - CPUHP_HRTIMERS_PREPARE = 39, - CPUHP_PROFILE_PREPARE = 40, - CPUHP_X2APIC_PREPARE = 41, - CPUHP_SMPCFD_PREPARE = 42, - CPUHP_RELAY_PREPARE = 43, - CPUHP_SLAB_PREPARE = 44, - CPUHP_MD_RAID5_PREPARE = 45, - CPUHP_RCUTREE_PREP = 46, - CPUHP_CPUIDLE_COUPLED_PREPARE = 47, - CPUHP_POWERPC_PMAC_PREPARE = 48, - CPUHP_POWERPC_MMU_CTX_PREPARE = 49, - CPUHP_XEN_PREPARE = 50, - CPUHP_XEN_EVTCHN_PREPARE = 51, - CPUHP_ARM_SHMOBILE_SCU_PREPARE = 52, - CPUHP_SH_SH3X_PREPARE = 53, - CPUHP_NET_FLOW_PREPARE = 54, - CPUHP_TOPOLOGY_PREPARE = 55, - CPUHP_NET_IUCV_PREPARE = 56, - CPUHP_ARM_BL_PREPARE = 57, - CPUHP_TRACE_RB_PREPARE = 58, - CPUHP_MM_ZS_PREPARE = 59, - CPUHP_MM_ZSWP_MEM_PREPARE = 60, - CPUHP_MM_ZSWP_POOL_PREPARE = 61, - CPUHP_KVM_PPC_BOOK3S_PREPARE = 62, - CPUHP_ZCOMP_PREPARE = 63, - CPUHP_TIMERS_PREPARE = 64, - CPUHP_MIPS_SOC_PREPARE = 65, - CPUHP_BP_PREPARE_DYN = 66, - CPUHP_BP_PREPARE_DYN_END = 86, - CPUHP_BRINGUP_CPU = 87, - CPUHP_AP_IDLE_DEAD = 88, - CPUHP_AP_OFFLINE = 89, - CPUHP_AP_SCHED_STARTING = 90, - CPUHP_AP_RCUTREE_DYING = 91, - CPUHP_AP_CPU_PM_STARTING = 92, - CPUHP_AP_IRQ_GIC_STARTING = 93, - CPUHP_AP_IRQ_HIP04_STARTING = 94, - CPUHP_AP_IRQ_APPLE_AIC_STARTING = 95, - CPUHP_AP_IRQ_ARMADA_XP_STARTING = 96, - CPUHP_AP_IRQ_BCM2836_STARTING = 97, - CPUHP_AP_IRQ_MIPS_GIC_STARTING = 98, - CPUHP_AP_IRQ_RISCV_STARTING = 99, - CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING = 100, - CPUHP_AP_ARM_MVEBU_COHERENCY = 101, - CPUHP_AP_MICROCODE_LOADER = 102, - CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING = 103, - CPUHP_AP_PERF_X86_STARTING = 104, - CPUHP_AP_PERF_X86_AMD_IBS_STARTING = 105, - CPUHP_AP_PERF_X86_CQM_STARTING = 106, - CPUHP_AP_PERF_X86_CSTATE_STARTING = 107, - CPUHP_AP_PERF_XTENSA_STARTING = 108, - CPUHP_AP_MIPS_OP_LOONGSON3_STARTING = 109, - CPUHP_AP_ARM_SDEI_STARTING = 110, - CPUHP_AP_ARM_VFP_STARTING = 111, - CPUHP_AP_ARM64_DEBUG_MONITORS_STARTING = 112, - CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING = 113, - CPUHP_AP_PERF_ARM_ACPI_STARTING = 114, - CPUHP_AP_PERF_ARM_STARTING = 115, - CPUHP_AP_ARM_L2X0_STARTING = 116, - CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING = 117, - CPUHP_AP_ARM_ARCH_TIMER_STARTING = 118, - CPUHP_AP_ARM_GLOBAL_TIMER_STARTING = 119, - CPUHP_AP_JCORE_TIMER_STARTING = 120, - CPUHP_AP_ARM_TWD_STARTING = 121, - CPUHP_AP_QCOM_TIMER_STARTING = 122, - CPUHP_AP_TEGRA_TIMER_STARTING = 123, - CPUHP_AP_ARMADA_TIMER_STARTING = 124, - CPUHP_AP_MARCO_TIMER_STARTING = 125, - CPUHP_AP_MIPS_GIC_TIMER_STARTING = 126, - CPUHP_AP_ARC_TIMER_STARTING = 127, - CPUHP_AP_RISCV_TIMER_STARTING = 128, - CPUHP_AP_CLINT_TIMER_STARTING = 129, - CPUHP_AP_CSKY_TIMER_STARTING = 130, - CPUHP_AP_TI_GP_TIMER_STARTING = 131, - CPUHP_AP_HYPERV_TIMER_STARTING = 132, - CPUHP_AP_KVM_STARTING = 133, - CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING = 134, - CPUHP_AP_KVM_ARM_VGIC_STARTING = 135, - CPUHP_AP_KVM_ARM_TIMER_STARTING = 136, - CPUHP_AP_DUMMY_TIMER_STARTING = 137, - CPUHP_AP_ARM_XEN_STARTING = 138, - CPUHP_AP_ARM_CORESIGHT_STARTING = 139, - CPUHP_AP_ARM_CORESIGHT_CTI_STARTING = 140, - CPUHP_AP_ARM64_ISNDEP_STARTING = 141, - CPUHP_AP_SMPCFD_DYING = 142, - CPUHP_AP_X86_TBOOT_DYING = 143, - CPUHP_AP_ARM_CACHE_B15_RAC_DYING = 144, - CPUHP_AP_ONLINE = 145, - CPUHP_TEARDOWN_CPU = 146, - CPUHP_AP_ONLINE_IDLE = 147, - CPUHP_AP_SCHED_WAIT_EMPTY = 148, - CPUHP_AP_SMPBOOT_THREADS = 149, - CPUHP_AP_X86_VDSO_VMA_ONLINE = 150, - CPUHP_AP_IRQ_AFFINITY_ONLINE = 151, - CPUHP_AP_BLK_MQ_ONLINE = 152, - CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS = 153, - CPUHP_AP_X86_INTEL_EPB_ONLINE = 154, - CPUHP_AP_PERF_ONLINE = 155, - CPUHP_AP_PERF_X86_ONLINE = 156, - CPUHP_AP_PERF_X86_UNCORE_ONLINE = 157, - CPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE = 158, - CPUHP_AP_PERF_X86_AMD_POWER_ONLINE = 159, - CPUHP_AP_PERF_X86_RAPL_ONLINE = 160, - CPUHP_AP_PERF_X86_CQM_ONLINE = 161, - CPUHP_AP_PERF_X86_CSTATE_ONLINE = 162, - CPUHP_AP_PERF_X86_IDXD_ONLINE = 163, - CPUHP_AP_PERF_S390_CF_ONLINE = 164, - CPUHP_AP_PERF_S390_SF_ONLINE = 165, - CPUHP_AP_PERF_ARM_CCI_ONLINE = 166, - CPUHP_AP_PERF_ARM_CCN_ONLINE = 167, - CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE = 168, - CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE = 169, - CPUHP_AP_PERF_ARM_HISI_L3_ONLINE = 170, - CPUHP_AP_PERF_ARM_HISI_PA_ONLINE = 171, - CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE = 172, - CPUHP_AP_PERF_ARM_L2X0_ONLINE = 173, - CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE = 174, - CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE = 175, - CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE = 176, - CPUHP_AP_PERF_ARM_CAVIUM_TX2_UNCORE_ONLINE = 177, - CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE = 178, - CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE = 179, - CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE = 180, - CPUHP_AP_PERF_POWERPC_TRACE_IMC_ONLINE = 181, - CPUHP_AP_PERF_POWERPC_HV_24x7_ONLINE = 182, - CPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE = 183, - CPUHP_AP_PERF_CSKY_ONLINE = 184, - CPUHP_AP_WATCHDOG_ONLINE = 185, - CPUHP_AP_WORKQUEUE_ONLINE = 186, - CPUHP_AP_RCUTREE_ONLINE = 187, - CPUHP_AP_BASE_CACHEINFO_ONLINE = 188, - CPUHP_AP_ONLINE_DYN = 189, - CPUHP_AP_ONLINE_DYN_END = 219, - CPUHP_AP_X86_HPET_ONLINE = 220, - CPUHP_AP_X86_KVM_CLK_ONLINE = 221, - CPUHP_AP_DTPM_CPU_ONLINE = 222, - CPUHP_AP_ACTIVE = 223, - CPUHP_ONLINE = 224, -}; - -struct ring_buffer_event { - u32 type_len: 5; - u32 time_delta: 27; - u32 array[0]; -}; - -struct seq_buf { - char *buffer; - size_t size; - size_t len; - loff_t readpos; -}; - -struct trace_seq { - char buffer[4096]; - struct seq_buf seq; - int full; -}; - -enum perf_sw_ids { - PERF_COUNT_SW_CPU_CLOCK = 0, - PERF_COUNT_SW_TASK_CLOCK = 1, - PERF_COUNT_SW_PAGE_FAULTS = 2, - PERF_COUNT_SW_CONTEXT_SWITCHES = 3, - PERF_COUNT_SW_CPU_MIGRATIONS = 4, - PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, - PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, - PERF_COUNT_SW_ALIGNMENT_FAULTS = 7, - PERF_COUNT_SW_EMULATION_FAULTS = 8, - PERF_COUNT_SW_DUMMY = 9, - PERF_COUNT_SW_BPF_OUTPUT = 10, - PERF_COUNT_SW_CGROUP_SWITCHES = 11, - PERF_COUNT_SW_MAX = 12, -}; - -union perf_mem_data_src { - __u64 val; - struct { - __u64 mem_op: 5; - __u64 mem_lvl: 14; - __u64 mem_snoop: 5; - __u64 mem_lock: 2; - __u64 mem_dtlb: 7; - __u64 mem_lvl_num: 4; - __u64 mem_remote: 1; - __u64 mem_snoopx: 2; - __u64 mem_blk: 3; - __u64 mem_rsvd: 21; - }; -}; - -struct perf_branch_entry { - __u64 from; - __u64 to; - __u64 mispred: 1; - __u64 predicted: 1; - __u64 in_tx: 1; - __u64 abort: 1; - __u64 cycles: 16; - __u64 type: 4; - __u64 reserved: 40; -}; - -union perf_sample_weight { - __u64 full; - struct { - __u32 var1_dw; - __u16 var2_w; - __u16 var3_w; - }; -}; - -struct new_utsname { - char sysname[65]; - char nodename[65]; - char release[65]; - char version[65]; - char machine[65]; - char domainname[65]; -}; - -struct uts_namespace { - struct new_utsname name; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct ns_common ns; -}; - -struct cgroup_namespace { - struct ns_common ns; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct css_set *root_cset; -}; - -struct nsset { - unsigned int flags; - struct nsproxy *nsproxy; - struct fs_struct *fs; - const struct cred *cred; -}; - -struct proc_ns_operations { - const char *name; - const char *real_ns_name; - int type; - struct ns_common * (*get)(struct task_struct *); - void (*put)(struct ns_common *); - int (*install)(struct nsset *, struct ns_common *); - struct user_namespace * (*owner)(struct ns_common *); - struct ns_common * (*get_parent)(struct ns_common *); -}; - -struct perf_cpu_context; - -struct perf_output_handle; - -struct pmu { - struct list_head entry; - struct module *module; - struct device *dev; - const struct attribute_group **attr_groups; - const struct attribute_group **attr_update; - const char *name; - int type; - int capabilities; - int *pmu_disable_count; - struct perf_cpu_context *pmu_cpu_context; - atomic_t exclusive_cnt; - int task_ctx_nr; - int hrtimer_interval_ms; - unsigned int nr_addr_filters; - void (*pmu_enable)(struct pmu *); - void (*pmu_disable)(struct pmu *); - int (*event_init)(struct perf_event *); - void (*event_mapped)(struct perf_event *, struct mm_struct *); - void (*event_unmapped)(struct perf_event *, struct mm_struct *); - int (*add)(struct perf_event *, int); - void (*del)(struct perf_event *, int); - void (*start)(struct perf_event *, int); - void (*stop)(struct perf_event *, int); - void (*read)(struct perf_event *); - void (*start_txn)(struct pmu *, unsigned int); - int (*commit_txn)(struct pmu *); - void (*cancel_txn)(struct pmu *); - int (*event_idx)(struct perf_event *); - void (*sched_task)(struct perf_event_context *, bool); - struct kmem_cache *task_ctx_cache; - void (*swap_task_ctx)(struct perf_event_context *, struct perf_event_context *); - void * (*setup_aux)(struct perf_event *, void **, int, bool); - void (*free_aux)(void *); - long int (*snapshot_aux)(struct perf_event *, struct perf_output_handle *, long unsigned int); - int (*addr_filters_validate)(struct list_head *); - void (*addr_filters_sync)(struct perf_event *); - int (*aux_output_match)(struct perf_event *); - int (*filter_match)(struct perf_event *); - int (*check_period)(struct perf_event *, u64); -}; - -struct ftrace_regs { - struct pt_regs regs; -}; - -struct iovec { - void *iov_base; - __kernel_size_t iov_len; -}; - -struct kvec { - void *iov_base; - size_t iov_len; -}; - -struct perf_regs { - __u64 abi; - struct pt_regs *regs; -}; - -struct u64_stats_sync {}; - -struct bpf_cgroup_storage_key { - __u64 cgroup_inode_id; - __u32 attach_type; -}; - -enum kmalloc_cache_type { - KMALLOC_NORMAL = 0, - KMALLOC_CGROUP = 1, - KMALLOC_RECLAIM = 2, - KMALLOC_DMA = 3, - NR_KMALLOC_TYPES = 4, -}; - -struct bpf_cgroup_storage; - -struct bpf_prog_array_item { - struct bpf_prog *prog; - struct bpf_cgroup_storage *cgroup_storage[2]; -}; - -struct bpf_storage_buffer; - -struct bpf_cgroup_storage_map; - -struct bpf_cgroup_storage { - union { - struct bpf_storage_buffer *buf; - void *percpu_buf; - }; - struct bpf_cgroup_storage_map *map; - struct bpf_cgroup_storage_key key; - struct list_head list_map; - struct list_head list_cg; - struct rb_node node; - struct callback_head rcu; -}; - -struct bpf_prog_array { - struct callback_head rcu; - struct bpf_prog_array_item items[0]; -}; - -struct bpf_storage_buffer { - struct callback_head rcu; - char data[0]; -}; - -struct psi_group_cpu { - seqcount_t seq; - unsigned int tasks[4]; - u32 state_mask; - u32 times[7]; - u64 state_start; - u32 times_prev[14]; - long: 64; -}; - -struct cgroup_taskset; - -struct cftype; - -struct cgroup_subsys { - struct cgroup_subsys_state * (*css_alloc)(struct cgroup_subsys_state *); - int (*css_online)(struct cgroup_subsys_state *); - void (*css_offline)(struct cgroup_subsys_state *); - void (*css_released)(struct cgroup_subsys_state *); - void (*css_free)(struct cgroup_subsys_state *); - void (*css_reset)(struct cgroup_subsys_state *); - void (*css_rstat_flush)(struct cgroup_subsys_state *, int); - int (*css_extra_stat_show)(struct seq_file *, struct cgroup_subsys_state *); - int (*can_attach)(struct cgroup_taskset *); - void (*cancel_attach)(struct cgroup_taskset *); - void (*attach)(struct cgroup_taskset *); - void (*post_attach)(); - int (*can_fork)(struct task_struct *, struct css_set *); - void (*cancel_fork)(struct task_struct *, struct css_set *); - void (*fork)(struct task_struct *); - void (*exit)(struct task_struct *); - void (*release)(struct task_struct *); - void (*bind)(struct cgroup_subsys_state *); - bool early_init: 1; - bool implicit_on_dfl: 1; - bool threaded: 1; - int id; - const char *name; - const char *legacy_name; - struct cgroup_root *root; - struct idr css_idr; - struct list_head cfts; - struct cftype *dfl_cftypes; - struct cftype *legacy_cftypes; - unsigned int depends_on; -}; - -struct cgroup_rstat_cpu { - struct u64_stats_sync bsync; - struct cgroup_base_stat bstat; - struct cgroup_base_stat last_bstat; - struct cgroup *updated_children; - struct cgroup *updated_next; -}; - -struct cgroup_root { - struct kernfs_root *kf_root; - unsigned int subsys_mask; - int hierarchy_id; - struct cgroup cgrp; - u64 cgrp_ancestor_id_storage; - atomic_t nr_cgrps; - struct list_head root_list; - unsigned int flags; - char release_agent_path[4096]; - char name[64]; -}; - -struct cftype { - char name[64]; - long unsigned int private; - size_t max_write_len; - unsigned int flags; - unsigned int file_offset; - struct cgroup_subsys *ss; - struct list_head node; - struct kernfs_ops *kf_ops; - int (*open)(struct kernfs_open_file *); - void (*release)(struct kernfs_open_file *); - u64 (*read_u64)(struct cgroup_subsys_state *, struct cftype *); - s64 (*read_s64)(struct cgroup_subsys_state *, struct cftype *); - int (*seq_show)(struct seq_file *, void *); - void * (*seq_start)(struct seq_file *, loff_t *); - void * (*seq_next)(struct seq_file *, void *, loff_t *); - void (*seq_stop)(struct seq_file *, void *); - int (*write_u64)(struct cgroup_subsys_state *, struct cftype *, u64); - int (*write_s64)(struct cgroup_subsys_state *, struct cftype *, s64); - ssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t); - __poll_t (*poll)(struct kernfs_open_file *, struct poll_table_struct *); -}; - -struct perf_callchain_entry { - __u64 nr; - __u64 ip[0]; -}; - -typedef long unsigned int (*perf_copy_f)(void *, const void *, long unsigned int, long unsigned int); - -struct perf_raw_frag { - union { - struct perf_raw_frag *next; - long unsigned int pad; - }; - perf_copy_f copy; - void *data; - u32 size; -} __attribute__((packed)); - -struct perf_raw_record { - struct perf_raw_frag frag; - u32 size; -}; - -struct perf_branch_stack { - __u64 nr; - __u64 hw_idx; - struct perf_branch_entry entries[0]; -}; - -struct perf_cpu_context { - struct perf_event_context ctx; - struct perf_event_context *task_ctx; - int active_oncpu; - int exclusive; - raw_spinlock_t hrtimer_lock; - struct hrtimer hrtimer; - ktime_t hrtimer_interval; - unsigned int hrtimer_active; - struct perf_cgroup *cgrp; - struct list_head cgrp_cpuctx_entry; - struct list_head sched_cb_entry; - int sched_cb_usage; - int online; - int heap_size; - struct perf_event **heap; - struct perf_event *heap_default[2]; -}; - -struct perf_output_handle { - struct perf_event *event; - struct perf_buffer *rb; - long unsigned int wakeup; - long unsigned int size; - u64 aux_flags; - union { - void *addr; - long unsigned int head; - }; - int page; -}; - -struct perf_addr_filter_range { - long unsigned int start; - long unsigned int size; -}; - -struct perf_sample_data { - u64 addr; - struct perf_raw_record *raw; - struct perf_branch_stack *br_stack; - u64 period; - union perf_sample_weight weight; - u64 txn; - union perf_mem_data_src data_src; - u64 type; - u64 ip; - struct { - u32 pid; - u32 tid; - } tid_entry; - u64 time; - u64 id; - u64 stream_id; - struct { - u32 cpu; - u32 reserved; - } cpu_entry; - struct perf_callchain_entry *callchain; - u64 aux_size; - struct perf_regs regs_user; - struct perf_regs regs_intr; - u64 stack_user_size; - u64 phys_addr; - u64 cgroup; - u64 data_page_size; - u64 code_page_size; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct perf_cgroup_info; - -struct perf_cgroup { - struct cgroup_subsys_state css; - struct perf_cgroup_info *info; -}; - -struct perf_cgroup_info { - u64 time; - u64 timestamp; -}; - -struct trace_entry { - short unsigned int type; - unsigned char flags; - unsigned char preempt_count; - int pid; -}; - -struct trace_array; - -struct tracer; - -struct array_buffer; - -struct ring_buffer_iter; - -struct trace_iterator { - struct trace_array *tr; - struct tracer *trace; - struct array_buffer *array_buffer; - void *private; - int cpu_file; - struct mutex mutex; - struct ring_buffer_iter **buffer_iter; - long unsigned int iter_flags; - void *temp; - unsigned int temp_size; - char *fmt; - unsigned int fmt_size; - struct trace_seq tmp_seq; - cpumask_var_t started; - bool snapshot; - struct trace_seq seq; - struct trace_entry *ent; - long unsigned int lost_events; - int leftover; - int ent_size; - int cpu; - u64 ts; - loff_t pos; - long int idx; -}; - -enum print_line_t { - TRACE_TYPE_PARTIAL_LINE = 0, - TRACE_TYPE_HANDLED = 1, - TRACE_TYPE_UNHANDLED = 2, - TRACE_TYPE_NO_CONSUME = 3, -}; - -typedef enum print_line_t (*trace_print_func)(struct trace_iterator *, int, struct trace_event *); - -struct trace_event_functions { - trace_print_func trace; - trace_print_func raw; - trace_print_func hex; - trace_print_func binary; -}; - -enum trace_reg { - TRACE_REG_REGISTER = 0, - TRACE_REG_UNREGISTER = 1, - TRACE_REG_PERF_REGISTER = 2, - TRACE_REG_PERF_UNREGISTER = 3, - TRACE_REG_PERF_OPEN = 4, - TRACE_REG_PERF_CLOSE = 5, - TRACE_REG_PERF_ADD = 6, - TRACE_REG_PERF_DEL = 7, -}; - -struct trace_event_fields { - const char *type; - union { - struct { - const char *name; - const int size; - const int align; - const int is_signed; - const int filter_type; - }; - int (*define_fields)(struct trace_event_call *); - }; -}; - -struct trace_event_class { - const char *system; - void *probe; - void *perf_probe; - int (*reg)(struct trace_event_call *, enum trace_reg, void *); - struct trace_event_fields *fields_array; - struct list_head * (*get_fields)(struct trace_event_call *); - struct list_head fields; - int (*raw_init)(struct trace_event_call *); -}; - -struct trace_buffer; - -struct trace_event_file; - -struct trace_event_buffer { - struct trace_buffer *buffer; - struct ring_buffer_event *event; - struct trace_event_file *trace_file; - void *entry; - unsigned int trace_ctx; - struct pt_regs *regs; -}; - -struct trace_subsystem_dir; - -struct trace_event_file { - struct list_head list; - struct trace_event_call *event_call; - struct event_filter *filter; - struct dentry *dir; - struct trace_array *tr; - struct trace_subsystem_dir *system; - struct list_head triggers; - long unsigned int flags; - atomic_t sm_ref; - atomic_t tm_ref; -}; - -enum { - TRACE_EVENT_FL_FILTERED_BIT = 0, - TRACE_EVENT_FL_CAP_ANY_BIT = 1, - TRACE_EVENT_FL_NO_SET_FILTER_BIT = 2, - TRACE_EVENT_FL_IGNORE_ENABLE_BIT = 3, - TRACE_EVENT_FL_TRACEPOINT_BIT = 4, - TRACE_EVENT_FL_KPROBE_BIT = 5, - TRACE_EVENT_FL_UPROBE_BIT = 6, -}; - -enum { - TRACE_EVENT_FL_FILTERED = 1, - TRACE_EVENT_FL_CAP_ANY = 2, - TRACE_EVENT_FL_NO_SET_FILTER = 4, - TRACE_EVENT_FL_IGNORE_ENABLE = 8, - TRACE_EVENT_FL_TRACEPOINT = 16, - TRACE_EVENT_FL_KPROBE = 32, - TRACE_EVENT_FL_UPROBE = 64, -}; - -enum { - EVENT_FILE_FL_ENABLED_BIT = 0, - EVENT_FILE_FL_RECORDED_CMD_BIT = 1, - EVENT_FILE_FL_RECORDED_TGID_BIT = 2, - EVENT_FILE_FL_FILTERED_BIT = 3, - EVENT_FILE_FL_NO_SET_FILTER_BIT = 4, - EVENT_FILE_FL_SOFT_MODE_BIT = 5, - EVENT_FILE_FL_SOFT_DISABLED_BIT = 6, - EVENT_FILE_FL_TRIGGER_MODE_BIT = 7, - EVENT_FILE_FL_TRIGGER_COND_BIT = 8, - EVENT_FILE_FL_PID_FILTER_BIT = 9, - EVENT_FILE_FL_WAS_ENABLED_BIT = 10, -}; - -enum { - EVENT_FILE_FL_ENABLED = 1, - EVENT_FILE_FL_RECORDED_CMD = 2, - EVENT_FILE_FL_RECORDED_TGID = 4, - EVENT_FILE_FL_FILTERED = 8, - EVENT_FILE_FL_NO_SET_FILTER = 16, - EVENT_FILE_FL_SOFT_MODE = 32, - EVENT_FILE_FL_SOFT_DISABLED = 64, - EVENT_FILE_FL_TRIGGER_MODE = 128, - EVENT_FILE_FL_TRIGGER_COND = 256, - EVENT_FILE_FL_PID_FILTER = 512, - EVENT_FILE_FL_WAS_ENABLED = 1024, -}; - -enum event_trigger_type { - ETT_NONE = 0, - ETT_TRACE_ONOFF = 1, - ETT_SNAPSHOT = 2, - ETT_STACKTRACE = 4, - ETT_EVENT_ENABLE = 8, - ETT_EVENT_HIST = 16, - ETT_HIST_ENABLE = 32, -}; - -enum { - FILTER_OTHER = 0, - FILTER_STATIC_STRING = 1, - FILTER_DYN_STRING = 2, - FILTER_PTR_STRING = 3, - FILTER_TRACE_FN = 4, - FILTER_COMM = 5, - FILTER_CPU = 6, -}; - -struct fwnode_reference_args; - -struct fwnode_endpoint; - -struct fwnode_operations { - struct fwnode_handle * (*get)(struct fwnode_handle *); - void (*put)(struct fwnode_handle *); - bool (*device_is_available)(const struct fwnode_handle *); - const void * (*device_get_match_data)(const struct fwnode_handle *, const struct device *); - bool (*property_present)(const struct fwnode_handle *, const char *); - int (*property_read_int_array)(const struct fwnode_handle *, const char *, unsigned int, void *, size_t); - int (*property_read_string_array)(const struct fwnode_handle *, const char *, const char **, size_t); - const char * (*get_name)(const struct fwnode_handle *); - const char * (*get_name_prefix)(const struct fwnode_handle *); - struct fwnode_handle * (*get_parent)(const struct fwnode_handle *); - struct fwnode_handle * (*get_next_child_node)(const struct fwnode_handle *, struct fwnode_handle *); - struct fwnode_handle * (*get_named_child_node)(const struct fwnode_handle *, const char *); - int (*get_reference_args)(const struct fwnode_handle *, const char *, const char *, unsigned int, unsigned int, struct fwnode_reference_args *); - struct fwnode_handle * (*graph_get_next_endpoint)(const struct fwnode_handle *, struct fwnode_handle *); - struct fwnode_handle * (*graph_get_remote_endpoint)(const struct fwnode_handle *); - struct fwnode_handle * (*graph_get_port_parent)(struct fwnode_handle *); - int (*graph_parse_endpoint)(const struct fwnode_handle *, struct fwnode_endpoint *); - int (*add_links)(struct fwnode_handle *); -}; - -struct fwnode_endpoint { - unsigned int port; - unsigned int id; - const struct fwnode_handle *local_fwnode; -}; - -struct fwnode_reference_args { - struct fwnode_handle *fwnode; - unsigned int nargs; - u64 args[8]; -}; - -struct property { - char *name; - int length; - void *value; - struct property *next; -}; - -struct irq_fwspec { - struct fwnode_handle *fwnode; - int param_count; - u32 param[16]; -}; - -struct irq_domain_ops { - int (*match)(struct irq_domain *, struct device_node *, enum irq_domain_bus_token); - int (*select)(struct irq_domain *, struct irq_fwspec *, enum irq_domain_bus_token); - int (*map)(struct irq_domain *, unsigned int, irq_hw_number_t); - void (*unmap)(struct irq_domain *, unsigned int); - int (*xlate)(struct irq_domain *, struct device_node *, const u32 *, unsigned int, long unsigned int *, unsigned int *); - int (*alloc)(struct irq_domain *, unsigned int, unsigned int, void *); - void (*free)(struct irq_domain *, unsigned int, unsigned int); - int (*activate)(struct irq_domain *, struct irq_data *, bool); - void (*deactivate)(struct irq_domain *, struct irq_data *); - int (*translate)(struct irq_domain *, struct irq_fwspec *, long unsigned int *, unsigned int *); -}; - -struct xbc_node { - u16 next; - u16 child; - u16 parent; - u16 data; -}; - -enum wb_stat_item { - WB_RECLAIMABLE = 0, - WB_WRITEBACK = 1, - WB_DIRTIED = 2, - WB_WRITTEN = 3, - NR_WB_STAT_ITEMS = 4, -}; - -struct block_device_operations; - -struct timer_rand_state; - -struct disk_events; - -struct cdrom_device_info; - -struct badblocks; - -struct gendisk { - int major; - int first_minor; - int minors; - char disk_name[32]; - short unsigned int events; - short unsigned int event_flags; - struct xarray part_tbl; - struct block_device *part0; - const struct block_device_operations *fops; - struct request_queue *queue; - void *private_data; - int flags; - long unsigned int state; - struct mutex open_mutex; - unsigned int open_partitions; - struct kobject *slave_dir; - struct timer_rand_state *random; - atomic_t sync_io; - struct disk_events *ev; - struct kobject integrity_kobj; - struct cdrom_device_info *cdi; - int node_id; - struct badblocks *bb; - struct lockdep_map lockdep_map; -}; - -struct partition_meta_info { - char uuid[37]; - u8 volname[64]; -}; - -struct bio_integrity_payload { - struct bio *bip_bio; - struct bvec_iter bip_iter; - short unsigned int bip_vcnt; - short unsigned int bip_max_vcnt; - short unsigned int bip_flags; - struct bvec_iter bio_iter; - struct work_struct bip_work; - struct bio_vec *bip_vec; - struct bio_vec bip_inline_vecs[0]; -}; - -struct blkg_iostat { - u64 bytes[3]; - u64 ios[3]; -}; - -struct blkg_iostat_set { - struct u64_stats_sync sync; - struct blkg_iostat cur; - struct blkg_iostat last; -}; - -struct blkcg; - -struct blkg_policy_data; - -struct blkcg_gq { - struct request_queue *q; - struct list_head q_node; - struct hlist_node blkcg_node; - struct blkcg *blkcg; - struct blkcg_gq *parent; - struct percpu_ref refcnt; - bool online; - struct blkg_iostat_set *iostat_cpu; - struct blkg_iostat_set iostat; - struct blkg_policy_data *pd[6]; - spinlock_t async_bio_lock; - struct bio_list async_bios; - struct work_struct async_bio_work; - atomic_t use_delay; - atomic64_t delay_nsec; - atomic64_t delay_start; - u64 last_delay; - int last_use; - struct callback_head callback_head; -}; - -typedef unsigned int blk_qc_t; - -struct blk_integrity_iter; - -typedef blk_status_t integrity_processing_fn(struct blk_integrity_iter *); - -typedef void integrity_prepare_fn(struct request *); - -typedef void integrity_complete_fn(struct request *, unsigned int); - -struct blk_integrity_profile { - integrity_processing_fn *generate_fn; - integrity_processing_fn *verify_fn; - integrity_prepare_fn *prepare_fn; - integrity_complete_fn *complete_fn; - const char *name; -}; - -struct blk_zone; - -typedef int (*report_zones_cb)(struct blk_zone *, unsigned int, void *); - -struct hd_geometry; - -struct pr_ops; - -struct block_device_operations { - blk_qc_t (*submit_bio)(struct bio *); - int (*open)(struct block_device *, fmode_t); - void (*release)(struct gendisk *, fmode_t); - int (*rw_page)(struct block_device *, sector_t, struct page *, unsigned int); - int (*ioctl)(struct block_device *, fmode_t, unsigned int, long unsigned int); - int (*compat_ioctl)(struct block_device *, fmode_t, unsigned int, long unsigned int); - unsigned int (*check_events)(struct gendisk *, unsigned int); - void (*unlock_native_capacity)(struct gendisk *); - int (*getgeo)(struct block_device *, struct hd_geometry *); - int (*set_read_only)(struct block_device *, bool); - void (*swap_slot_free_notify)(struct block_device *, long unsigned int); - int (*report_zones)(struct gendisk *, sector_t, unsigned int, report_zones_cb, void *); - char * (*devnode)(struct gendisk *, umode_t *); - struct module *owner; - const struct pr_ops *pr_ops; -}; - -struct sg_io_v4 { - __s32 guard; - __u32 protocol; - __u32 subprotocol; - __u32 request_len; - __u64 request; - __u64 request_tag; - __u32 request_attr; - __u32 request_priority; - __u32 request_extra; - __u32 max_response_len; - __u64 response; - __u32 dout_iovec_count; - __u32 dout_xfer_len; - __u32 din_iovec_count; - __u32 din_xfer_len; - __u64 dout_xferp; - __u64 din_xferp; - __u32 timeout; - __u32 flags; - __u64 usr_ptr; - __u32 spare_in; - __u32 driver_status; - __u32 transport_status; - __u32 device_status; - __u32 retry_delay; - __u32 info; - __u32 duration; - __u32 response_len; - __s32 din_resid; - __s32 dout_resid; - __u64 generated_tag; - __u32 spare_out; - __u32 padding; -}; - -struct bsg_ops { - int (*check_proto)(struct sg_io_v4 *); - int (*fill_hdr)(struct request *, struct sg_io_v4 *, fmode_t); - int (*complete_rq)(struct request *, struct sg_io_v4 *); - void (*free_rq)(struct request *); -}; - -typedef __u32 req_flags_t; - -typedef void rq_end_io_fn(struct request *, blk_status_t); - -enum mq_rq_state { - MQ_RQ_IDLE = 0, - MQ_RQ_IN_FLIGHT = 1, - MQ_RQ_COMPLETE = 2, -}; - -struct blk_ksm_keyslot; - -struct request { - struct request_queue *q; - struct blk_mq_ctx *mq_ctx; - struct blk_mq_hw_ctx *mq_hctx; - unsigned int cmd_flags; - req_flags_t rq_flags; - int tag; - int internal_tag; - unsigned int __data_len; - sector_t __sector; - struct bio *bio; - struct bio *biotail; - struct list_head queuelist; - union { - struct hlist_node hash; - struct llist_node ipi_list; - }; - union { - struct rb_node rb_node; - struct bio_vec special_vec; - void *completion_data; - int error_count; - }; - union { - struct { - struct io_cq *icq; - void *priv[2]; - } elv; - struct { - unsigned int seq; - struct list_head list; - rq_end_io_fn *saved_end_io; - } flush; - }; - struct gendisk *rq_disk; - struct block_device *part; - u64 alloc_time_ns; - u64 start_time_ns; - u64 io_start_time_ns; - short unsigned int wbt_flags; - short unsigned int stats_sectors; - short unsigned int nr_phys_segments; - short unsigned int nr_integrity_segments; - struct bio_crypt_ctx *crypt_ctx; - struct blk_ksm_keyslot *crypt_keyslot; - short unsigned int write_hint; - short unsigned int ioprio; - enum mq_rq_state state; - refcount_t ref; - unsigned int timeout; - long unsigned int deadline; - union { - struct __call_single_data csd; - u64 fifo_time; - }; - rq_end_io_fn *end_io; - void *end_io_data; -}; - -struct blk_zone { - __u64 start; - __u64 len; - __u64 wp; - __u8 type; - __u8 cond; - __u8 non_seq; - __u8 reset; - __u8 resv[4]; - __u64 capacity; - __u8 reserved[24]; -}; - -struct sbitmap_word { - long unsigned int depth; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int word; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int cleared; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct sbq_wait_state { - atomic_t wait_cnt; - wait_queue_head_t wait; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum elv_merge { - ELEVATOR_NO_MERGE = 0, - ELEVATOR_FRONT_MERGE = 1, - ELEVATOR_BACK_MERGE = 2, - ELEVATOR_DISCARD_MERGE = 3, -}; - -struct elevator_type; - -struct blk_mq_alloc_data; - -struct elevator_mq_ops { - int (*init_sched)(struct request_queue *, struct elevator_type *); - void (*exit_sched)(struct elevator_queue *); - int (*init_hctx)(struct blk_mq_hw_ctx *, unsigned int); - void (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int); - void (*depth_updated)(struct blk_mq_hw_ctx *); - bool (*allow_merge)(struct request_queue *, struct request *, struct bio *); - bool (*bio_merge)(struct request_queue *, struct bio *, unsigned int); - int (*request_merge)(struct request_queue *, struct request **, struct bio *); - void (*request_merged)(struct request_queue *, struct request *, enum elv_merge); - void (*requests_merged)(struct request_queue *, struct request *, struct request *); - void (*limit_depth)(unsigned int, struct blk_mq_alloc_data *); - void (*prepare_request)(struct request *); - void (*finish_request)(struct request *); - void (*insert_requests)(struct blk_mq_hw_ctx *, struct list_head *, bool); - struct request * (*dispatch_request)(struct blk_mq_hw_ctx *); - bool (*has_work)(struct blk_mq_hw_ctx *); - void (*completed_request)(struct request *, u64); - void (*requeue_request)(struct request *); - struct request * (*former_request)(struct request_queue *, struct request *); - struct request * (*next_request)(struct request_queue *, struct request *); - void (*init_icq)(struct io_cq *); - void (*exit_icq)(struct io_cq *); -}; - -struct elv_fs_entry; - -struct blk_mq_debugfs_attr; - -struct elevator_type { - struct kmem_cache *icq_cache; - struct elevator_mq_ops ops; - size_t icq_size; - size_t icq_align; - struct elv_fs_entry *elevator_attrs; - const char *elevator_name; - const char *elevator_alias; - const unsigned int elevator_features; - struct module *elevator_owner; - const struct blk_mq_debugfs_attr *queue_debugfs_attrs; - const struct blk_mq_debugfs_attr *hctx_debugfs_attrs; - char icq_cache_name[22]; - struct list_head list; -}; - -struct elevator_queue { - struct elevator_type *type; - void *elevator_data; - struct kobject kobj; - struct mutex sysfs_lock; - unsigned int registered: 1; - struct hlist_head hash[64]; -}; - -struct elv_fs_entry { - struct attribute attr; - ssize_t (*show)(struct elevator_queue *, char *); - ssize_t (*store)(struct elevator_queue *, const char *, size_t); -}; - -struct blk_mq_debugfs_attr { - const char *name; - umode_t mode; - int (*show)(void *, struct seq_file *); - ssize_t (*write)(void *, const char *, size_t, loff_t *); - const struct seq_operations *seq_ops; -}; - -enum blk_eh_timer_return { - BLK_EH_DONE = 0, - BLK_EH_RESET_TIMER = 1, -}; - -struct blk_mq_queue_data; - -struct blk_mq_ops { - blk_status_t (*queue_rq)(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *); - void (*commit_rqs)(struct blk_mq_hw_ctx *); - int (*get_budget)(struct request_queue *); - void (*put_budget)(struct request_queue *, int); - void (*set_rq_budget_token)(struct request *, int); - int (*get_rq_budget_token)(struct request *); - enum blk_eh_timer_return (*timeout)(struct request *, bool); - int (*poll)(struct blk_mq_hw_ctx *); - void (*complete)(struct request *); - int (*init_hctx)(struct blk_mq_hw_ctx *, void *, unsigned int); - void (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int); - int (*init_request)(struct blk_mq_tag_set *, struct request *, unsigned int, unsigned int); - void (*exit_request)(struct blk_mq_tag_set *, struct request *, unsigned int); - void (*initialize_rq_fn)(struct request *); - void (*cleanup_rq)(struct request *); - bool (*busy)(struct request_queue *); - int (*map_queues)(struct blk_mq_tag_set *); - void (*show_rq)(struct seq_file *, struct request *); -}; - -struct blk_integrity_iter { - void *prot_buf; - void *data_buf; - sector_t seed; - unsigned int data_size; - short unsigned int interval; - const char *disk_name; -}; - -enum pr_type { - PR_WRITE_EXCLUSIVE = 1, - PR_EXCLUSIVE_ACCESS = 2, - PR_WRITE_EXCLUSIVE_REG_ONLY = 3, - PR_EXCLUSIVE_ACCESS_REG_ONLY = 4, - PR_WRITE_EXCLUSIVE_ALL_REGS = 5, - PR_EXCLUSIVE_ACCESS_ALL_REGS = 6, -}; - -struct pr_ops { - int (*pr_register)(struct block_device *, u64, u64, u32); - int (*pr_reserve)(struct block_device *, u64, enum pr_type, u32); - int (*pr_release)(struct block_device *, u64, enum pr_type); - int (*pr_preempt)(struct block_device *, u64, u64, enum pr_type, bool); - int (*pr_clear)(struct block_device *, u64); -}; - -enum blkg_iostat_type { - BLKG_IOSTAT_READ = 0, - BLKG_IOSTAT_WRITE = 1, - BLKG_IOSTAT_DISCARD = 2, - BLKG_IOSTAT_NR = 3, -}; - -struct blkcg_policy_data; - -struct blkcg { - struct cgroup_subsys_state css; - spinlock_t lock; - refcount_t online_pin; - struct xarray blkg_tree; - struct blkcg_gq *blkg_hint; - struct hlist_head blkg_list; - struct blkcg_policy_data *cpd[6]; - struct list_head all_blkcgs_node; - char fc_app_id[129]; - struct list_head cgwb_list; -}; - -struct blkcg_policy_data { - struct blkcg *blkcg; - int plid; -}; - -struct blkg_policy_data { - struct blkcg_gq *blkg; - int plid; -}; - -typedef long unsigned int efi_status_t; - -typedef u8 efi_bool_t; - -typedef u16 efi_char16_t; - -typedef guid_t efi_guid_t; - -typedef struct { - u64 signature; - u32 revision; - u32 headersize; - u32 crc32; - u32 reserved; -} efi_table_hdr_t; - -typedef struct { - u32 type; - u32 pad; - u64 phys_addr; - u64 virt_addr; - u64 num_pages; - u64 attribute; -} efi_memory_desc_t; - -typedef struct { - efi_guid_t guid; - u32 headersize; - u32 flags; - u32 imagesize; -} efi_capsule_header_t; - -typedef struct { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 minute; - u8 second; - u8 pad1; - u32 nanosecond; - s16 timezone; - u8 daylight; - u8 pad2; -} efi_time_t; - -typedef struct { - u32 resolution; - u32 accuracy; - u8 sets_to_zero; -} efi_time_cap_t; - -typedef struct { - efi_table_hdr_t hdr; - u32 get_time; - u32 set_time; - u32 get_wakeup_time; - u32 set_wakeup_time; - u32 set_virtual_address_map; - u32 convert_pointer; - u32 get_variable; - u32 get_next_variable; - u32 set_variable; - u32 get_next_high_mono_count; - u32 reset_system; - u32 update_capsule; - u32 query_capsule_caps; - u32 query_variable_info; -} efi_runtime_services_32_t; - -typedef efi_status_t efi_get_time_t(efi_time_t *, efi_time_cap_t *); - -typedef efi_status_t efi_set_time_t(efi_time_t *); - -typedef efi_status_t efi_get_wakeup_time_t(efi_bool_t *, efi_bool_t *, efi_time_t *); - -typedef efi_status_t efi_set_wakeup_time_t(efi_bool_t, efi_time_t *); - -typedef efi_status_t efi_get_variable_t(efi_char16_t *, efi_guid_t *, u32 *, long unsigned int *, void *); - -typedef efi_status_t efi_get_next_variable_t(long unsigned int *, efi_char16_t *, efi_guid_t *); - -typedef efi_status_t efi_set_variable_t(efi_char16_t *, efi_guid_t *, u32, long unsigned int, void *); - -typedef efi_status_t efi_get_next_high_mono_count_t(u32 *); - -typedef void efi_reset_system_t(int, efi_status_t, long unsigned int, efi_char16_t *); - -typedef efi_status_t efi_query_variable_info_t(u32, u64 *, u64 *, u64 *); - -typedef efi_status_t efi_update_capsule_t(efi_capsule_header_t **, long unsigned int, long unsigned int); - -typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **, long unsigned int, u64 *, int *); - -typedef union { - struct { - efi_table_hdr_t hdr; - efi_status_t (*get_time)(efi_time_t *, efi_time_cap_t *); - efi_status_t (*set_time)(efi_time_t *); - efi_status_t (*get_wakeup_time)(efi_bool_t *, efi_bool_t *, efi_time_t *); - efi_status_t (*set_wakeup_time)(efi_bool_t, efi_time_t *); - efi_status_t (*set_virtual_address_map)(long unsigned int, long unsigned int, u32, efi_memory_desc_t *); - void *convert_pointer; - efi_status_t (*get_variable)(efi_char16_t *, efi_guid_t *, u32 *, long unsigned int *, void *); - efi_status_t (*get_next_variable)(long unsigned int *, efi_char16_t *, efi_guid_t *); - efi_status_t (*set_variable)(efi_char16_t *, efi_guid_t *, u32, long unsigned int, void *); - efi_status_t (*get_next_high_mono_count)(u32 *); - void (*reset_system)(int, efi_status_t, long unsigned int, efi_char16_t *); - efi_status_t (*update_capsule)(efi_capsule_header_t **, long unsigned int, long unsigned int); - efi_status_t (*query_capsule_caps)(efi_capsule_header_t **, long unsigned int, u64 *, int *); - efi_status_t (*query_variable_info)(u32, u64 *, u64 *, u64 *); - }; - efi_runtime_services_32_t mixed_mode; -} efi_runtime_services_t; - -struct efi_memory_map { - phys_addr_t phys_map; - void *map; - void *map_end; - int nr_map; - long unsigned int desc_version; - long unsigned int desc_size; - long unsigned int flags; -}; - -struct efi { - const efi_runtime_services_t *runtime; - unsigned int runtime_version; - unsigned int runtime_supported_mask; - long unsigned int acpi; - long unsigned int acpi20; - long unsigned int smbios; - long unsigned int smbios3; - long unsigned int esrt; - long unsigned int tpm_log; - long unsigned int tpm_final_log; - long unsigned int mokvar_table; - efi_get_time_t *get_time; - efi_set_time_t *set_time; - efi_get_wakeup_time_t *get_wakeup_time; - efi_set_wakeup_time_t *set_wakeup_time; - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_set_variable_t *set_variable_nonblocking; - efi_query_variable_info_t *query_variable_info; - efi_query_variable_info_t *query_variable_info_nonblocking; - efi_update_capsule_t *update_capsule; - efi_query_capsule_caps_t *query_capsule_caps; - efi_get_next_high_mono_count_t *get_next_high_mono_count; - efi_reset_system_t *reset_system; - struct efi_memory_map memmap; - long unsigned int flags; -}; - -enum memcg_stat_item { - MEMCG_SWAP = 39, - MEMCG_SOCK = 40, - MEMCG_PERCPU_B = 41, - MEMCG_NR_STAT = 42, -}; - -enum memcg_memory_event { - MEMCG_LOW = 0, - MEMCG_HIGH = 1, - MEMCG_MAX = 2, - MEMCG_OOM = 3, - MEMCG_OOM_KILL = 4, - MEMCG_SWAP_HIGH = 5, - MEMCG_SWAP_MAX = 6, - MEMCG_SWAP_FAIL = 7, - MEMCG_NR_MEMORY_EVENTS = 8, -}; - -enum mem_cgroup_events_target { - MEM_CGROUP_TARGET_THRESH = 0, - MEM_CGROUP_TARGET_SOFTLIMIT = 1, - MEM_CGROUP_NTARGETS = 2, -}; - -struct memcg_vmstats_percpu { - long int state[42]; - long unsigned int events[100]; - long int state_prev[42]; - long unsigned int events_prev[100]; - long unsigned int nr_page_events; - long unsigned int targets[2]; -}; - -struct mem_cgroup_reclaim_iter { - struct mem_cgroup *position; - unsigned int generation; -}; - -struct lruvec_stat { - long int count[39]; -}; - -struct batched_lruvec_stat { - s32 count[39]; -}; - -struct shrinker_info { - struct callback_head rcu; - atomic_long_t *nr_deferred; - long unsigned int *map; -}; - -struct mem_cgroup_per_node { - struct lruvec lruvec; - struct lruvec_stat *lruvec_stat_local; - struct batched_lruvec_stat *lruvec_stat_cpu; - atomic_long_t lruvec_stat[39]; - long unsigned int lru_zone_size[25]; - struct mem_cgroup_reclaim_iter iter; - struct shrinker_info *shrinker_info; - struct rb_node tree_node; - long unsigned int usage_in_excess; - bool on_tree; - struct mem_cgroup *memcg; -}; - -struct eventfd_ctx; - -struct mem_cgroup_threshold { - struct eventfd_ctx *eventfd; - long unsigned int threshold; -}; - -struct mem_cgroup_threshold_ary { - int current_threshold; - unsigned int size; - struct mem_cgroup_threshold entries[0]; -}; - -struct obj_cgroup { - struct percpu_ref refcnt; - struct mem_cgroup *memcg; - atomic_t nr_charged_bytes; - union { - struct list_head list; - struct callback_head rcu; - }; -}; - -struct percpu_cluster { - struct swap_cluster_info index; - unsigned int next; -}; - -enum fs_value_type { - fs_value_is_undefined = 0, - fs_value_is_flag = 1, - fs_value_is_string = 2, - fs_value_is_blob = 3, - fs_value_is_filename = 4, - fs_value_is_file = 5, -}; - -struct fs_parameter { - const char *key; - enum fs_value_type type: 8; - union { - char *string; - void *blob; - struct filename *name; - struct file *file; - }; - size_t size; - int dirfd; -}; - -struct fc_log { - refcount_t usage; - u8 head; - u8 tail; - u8 need_free; - struct module *owner; - char *buffer[8]; -}; - -struct fs_context_operations { - void (*free)(struct fs_context *); - int (*dup)(struct fs_context *, struct fs_context *); - int (*parse_param)(struct fs_context *, struct fs_parameter *); - int (*parse_monolithic)(struct fs_context *, void *); - int (*get_tree)(struct fs_context *); - int (*reconfigure)(struct fs_context *); -}; - -struct fs_parse_result { - bool negated; - union { - bool boolean; - int int_32; - unsigned int uint_32; - u64 uint_64; - }; -}; - -struct trace_event_raw_initcall_level { - struct trace_entry ent; - u32 __data_loc_level; - char __data[0]; -}; - -struct trace_event_raw_initcall_start { - struct trace_entry ent; - initcall_t func; - char __data[0]; -}; - -struct trace_event_raw_initcall_finish { - struct trace_entry ent; - initcall_t func; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_initcall_level { - u32 level; -}; - -struct trace_event_data_offsets_initcall_start {}; - -struct trace_event_data_offsets_initcall_finish {}; - -typedef void (*btf_trace_initcall_level)(void *, const char *); - -typedef void (*btf_trace_initcall_start)(void *, initcall_t); - -typedef void (*btf_trace_initcall_finish)(void *, initcall_t, int); - -struct blacklist_entry { - struct list_head next; - char *buf; -}; - -typedef __u32 Elf32_Word; - -struct elf32_note { - Elf32_Word n_namesz; - Elf32_Word n_descsz; - Elf32_Word n_type; -}; - -enum { - PROC_ROOT_INO = 1, - PROC_IPC_INIT_INO = 4026531839, - PROC_UTS_INIT_INO = 4026531838, - PROC_USER_INIT_INO = 4026531837, - PROC_PID_INIT_INO = 4026531836, - PROC_CGROUP_INIT_INO = 4026531835, - PROC_TIME_INIT_INO = 4026531834, -}; - -typedef __u16 __le16; - -typedef __u16 __be16; - -typedef __u32 __be32; - -typedef __u64 __be64; - -typedef __u32 __wsum; - -typedef unsigned int slab_flags_t; - -struct notifier_block; - -typedef int (*notifier_fn_t)(struct notifier_block *, long unsigned int, void *); - -struct notifier_block { - notifier_fn_t notifier_call; - struct notifier_block *next; - int priority; -}; - -struct blocking_notifier_head { - struct rw_semaphore rwsem; - struct notifier_block *head; -}; - -struct raw_notifier_head { - struct notifier_block *head; -}; - -struct page_pool_params { - unsigned int flags; - unsigned int order; - unsigned int pool_size; - int nid; - struct device *dev; - enum dma_data_direction dma_dir; - unsigned int max_len; - unsigned int offset; -}; - -struct pp_alloc_cache { - u32 count; - struct page *cache[128]; -}; - -struct ptr_ring { - int producer; - spinlock_t producer_lock; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - int consumer_head; - int consumer_tail; - spinlock_t consumer_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - int size; - int batch; - void **queue; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct page_pool { - struct page_pool_params p; - struct delayed_work release_dw; - void (*disconnect)(void *); - long unsigned int defer_start; - long unsigned int defer_warn; - u32 pages_state_hold_cnt; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - struct pp_alloc_cache alloc; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct ptr_ring ring; - atomic_t pages_state_release_cnt; - refcount_t user_cnt; - u64 destroy_cnt; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef __u64 __addrpair; - -typedef __u32 __portpair; - -typedef struct { - struct net *net; -} possible_net_t; - -struct in6_addr { - union { - __u8 u6_addr8[16]; - __be16 u6_addr16[8]; - __be32 u6_addr32[4]; - } in6_u; -}; - -struct hlist_nulls_node { - struct hlist_nulls_node *next; - struct hlist_nulls_node **pprev; -}; - -struct proto; - -struct inet_timewait_death_row; - -struct sock_common { - union { - __addrpair skc_addrpair; - struct { - __be32 skc_daddr; - __be32 skc_rcv_saddr; - }; - }; - union { - unsigned int skc_hash; - __u16 skc_u16hashes[2]; - }; - union { - __portpair skc_portpair; - struct { - __be16 skc_dport; - __u16 skc_num; - }; - }; - short unsigned int skc_family; - volatile unsigned char skc_state; - unsigned char skc_reuse: 4; - unsigned char skc_reuseport: 1; - unsigned char skc_ipv6only: 1; - unsigned char skc_net_refcnt: 1; - int skc_bound_dev_if; - union { - struct hlist_node skc_bind_node; - struct hlist_node skc_portaddr_node; - }; - struct proto *skc_prot; - possible_net_t skc_net; - struct in6_addr skc_v6_daddr; - struct in6_addr skc_v6_rcv_saddr; - atomic64_t skc_cookie; - union { - long unsigned int skc_flags; - struct sock *skc_listener; - struct inet_timewait_death_row *skc_tw_dr; - }; - int skc_dontcopy_begin[0]; - union { - struct hlist_node skc_node; - struct hlist_nulls_node skc_nulls_node; - }; - short unsigned int skc_tx_queue_mapping; - short unsigned int skc_rx_queue_mapping; - union { - int skc_incoming_cpu; - u32 skc_rcv_wnd; - u32 skc_tw_rcv_nxt; - }; - refcount_t skc_refcnt; - int skc_dontcopy_end[0]; - union { - u32 skc_rxhash; - u32 skc_window_clamp; - u32 skc_tw_snd_nxt; - }; -}; - -typedef struct { - spinlock_t slock; - int owned; - wait_queue_head_t wq; -} socket_lock_t; - -struct sk_buff; - -struct sk_buff_head { - struct sk_buff *next; - struct sk_buff *prev; - __u32 qlen; - spinlock_t lock; -}; - -typedef u64 netdev_features_t; - -struct sock_cgroup_data { - union { - struct { - u8 is_data: 1; - u8 no_refcnt: 1; - u8 unused: 6; - u8 padding; - u16 prioidx; - u32 classid; - }; - u64 val; - }; -}; - -struct sk_filter; - -struct socket_wq; - -struct xfrm_policy; - -struct dst_entry; - -struct socket; - -struct net_device; - -struct sock_reuseport; - -struct sock { - struct sock_common __sk_common; - socket_lock_t sk_lock; - atomic_t sk_drops; - int sk_rcvlowat; - struct sk_buff_head sk_error_queue; - struct sk_buff *sk_rx_skb_cache; - struct sk_buff_head sk_receive_queue; - struct { - atomic_t rmem_alloc; - int len; - struct sk_buff *head; - struct sk_buff *tail; - } sk_backlog; - int sk_forward_alloc; - unsigned int sk_ll_usec; - unsigned int sk_napi_id; - int sk_rcvbuf; - struct sk_filter *sk_filter; - union { - struct socket_wq *sk_wq; - struct socket_wq *sk_wq_raw; - }; - struct xfrm_policy *sk_policy[2]; - struct dst_entry *sk_rx_dst; - struct dst_entry *sk_dst_cache; - atomic_t sk_omem_alloc; - int sk_sndbuf; - int sk_wmem_queued; - refcount_t sk_wmem_alloc; - long unsigned int sk_tsq_flags; - union { - struct sk_buff *sk_send_head; - struct rb_root tcp_rtx_queue; - }; - struct sk_buff *sk_tx_skb_cache; - struct sk_buff_head sk_write_queue; - __s32 sk_peek_off; - int sk_write_pending; - __u32 sk_dst_pending_confirm; - u32 sk_pacing_status; - long int sk_sndtimeo; - struct timer_list sk_timer; - __u32 sk_priority; - __u32 sk_mark; - long unsigned int sk_pacing_rate; - long unsigned int sk_max_pacing_rate; - struct page_frag sk_frag; - netdev_features_t sk_route_caps; - netdev_features_t sk_route_nocaps; - netdev_features_t sk_route_forced_caps; - int sk_gso_type; - unsigned int sk_gso_max_size; - gfp_t sk_allocation; - __u32 sk_txhash; - u8 sk_padding: 1; - u8 sk_kern_sock: 1; - u8 sk_no_check_tx: 1; - u8 sk_no_check_rx: 1; - u8 sk_userlocks: 4; - u8 sk_pacing_shift; - u16 sk_type; - u16 sk_protocol; - u16 sk_gso_max_segs; - long unsigned int sk_lingertime; - struct proto *sk_prot_creator; - rwlock_t sk_callback_lock; - int sk_err; - int sk_err_soft; - u32 sk_ack_backlog; - u32 sk_max_ack_backlog; - kuid_t sk_uid; - u8 sk_prefer_busy_poll; - u16 sk_busy_poll_budget; - struct pid *sk_peer_pid; - const struct cred *sk_peer_cred; - long int sk_rcvtimeo; - ktime_t sk_stamp; - u16 sk_tsflags; - int sk_bind_phc; - u8 sk_shutdown; - u32 sk_tskey; - atomic_t sk_zckey; - u8 sk_clockid; - u8 sk_txtime_deadline_mode: 1; - u8 sk_txtime_report_errors: 1; - u8 sk_txtime_unused: 6; - struct socket *sk_socket; - void *sk_user_data; - void *sk_security; - struct sock_cgroup_data sk_cgrp_data; - struct mem_cgroup *sk_memcg; - void (*sk_state_change)(struct sock *); - void (*sk_data_ready)(struct sock *); - void (*sk_write_space)(struct sock *); - void (*sk_error_report)(struct sock *); - int (*sk_backlog_rcv)(struct sock *, struct sk_buff *); - struct sk_buff * (*sk_validate_xmit_skb)(struct sock *, struct net_device *, struct sk_buff *); - void (*sk_destruct)(struct sock *); - struct sock_reuseport *sk_reuseport_cb; - struct bpf_local_storage *sk_bpf_storage; - struct callback_head sk_rcu; -}; - -struct rhash_head { - struct rhash_head *next; -}; - -struct rhashtable; - -struct rhashtable_compare_arg { - struct rhashtable *ht; - const void *key; -}; - -typedef u32 (*rht_hashfn_t)(const void *, u32, u32); - -typedef u32 (*rht_obj_hashfn_t)(const void *, u32, u32); - -typedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *, const void *); - -struct rhashtable_params { - u16 nelem_hint; - u16 key_len; - u16 key_offset; - u16 head_offset; - unsigned int max_size; - u16 min_size; - bool automatic_shrinking; - rht_hashfn_t hashfn; - rht_obj_hashfn_t obj_hashfn; - rht_obj_cmpfn_t obj_cmpfn; -}; - -struct bucket_table; - -struct rhashtable { - struct bucket_table *tbl; - unsigned int key_len; - unsigned int max_elems; - struct rhashtable_params p; - bool rhlist; - struct work_struct run_work; - struct mutex mutex; - spinlock_t lock; - atomic_t nelems; -}; - -struct fs_struct { - int users; - spinlock_t lock; - seqcount_spinlock_t seq; - int umask; - int in_exec; - struct path root; - struct path pwd; -}; - -struct pipe_buffer; - -struct watch_queue; - -struct pipe_inode_info { - struct mutex mutex; - wait_queue_head_t rd_wait; - wait_queue_head_t wr_wait; - unsigned int head; - unsigned int tail; - unsigned int max_usage; - unsigned int ring_size; - bool note_loss; - unsigned int nr_accounted; - unsigned int readers; - unsigned int writers; - unsigned int files; - unsigned int r_counter; - unsigned int w_counter; - unsigned int poll_usage; - struct page *tmp_page; - struct fasync_struct *fasync_readers; - struct fasync_struct *fasync_writers; - struct pipe_buffer *bufs; - struct user_struct *user; - struct watch_queue *watch_queue; -}; - -typedef short unsigned int __kernel_sa_family_t; - -typedef __kernel_sa_family_t sa_family_t; - -struct sockaddr { - sa_family_t sa_family; - char sa_data[14]; -}; - -struct msghdr { - void *msg_name; - int msg_namelen; - struct iov_iter msg_iter; - union { - void *msg_control; - void *msg_control_user; - }; - bool msg_control_is_user: 1; - __kernel_size_t msg_controllen; - unsigned int msg_flags; - struct kiocb *msg_iocb; -}; - -typedef struct { - unsigned int clock_rate; - unsigned int clock_type; - short unsigned int loopback; -} sync_serial_settings; - -typedef struct { - unsigned int clock_rate; - unsigned int clock_type; - short unsigned int loopback; - unsigned int slot_map; -} te1_settings; - -typedef struct { - short unsigned int encoding; - short unsigned int parity; -} raw_hdlc_proto; - -typedef struct { - unsigned int t391; - unsigned int t392; - unsigned int n391; - unsigned int n392; - unsigned int n393; - short unsigned int lmi; - short unsigned int dce; -} fr_proto; - -typedef struct { - unsigned int dlci; -} fr_proto_pvc; - -typedef struct { - unsigned int dlci; - char master[16]; -} fr_proto_pvc_info; - -typedef struct { - unsigned int interval; - unsigned int timeout; -} cisco_proto; - -typedef struct { - short unsigned int dce; - unsigned int modulo; - unsigned int window; - unsigned int t1; - unsigned int t2; - unsigned int n2; -} x25_hdlc_proto; - -struct ifmap { - long unsigned int mem_start; - long unsigned int mem_end; - short unsigned int base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct if_settings { - unsigned int type; - unsigned int size; - union { - raw_hdlc_proto *raw_hdlc; - cisco_proto *cisco; - fr_proto *fr; - fr_proto_pvc *fr_pvc; - fr_proto_pvc_info *fr_pvc_info; - x25_hdlc_proto *x25; - sync_serial_settings *sync; - te1_settings *te1; - } ifs_ifsu; -}; - -struct ifreq { - union { - char ifrn_name[16]; - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short int ifru_flags; - int ifru_ivalue; - int ifru_mtu; - struct ifmap ifru_map; - char ifru_slave[16]; - char ifru_newname[16]; - void *ifru_data; - struct if_settings ifru_settings; - } ifr_ifru; -}; - -struct ld_semaphore { - atomic_long_t count; - raw_spinlock_t wait_lock; - unsigned int wait_readers; - struct list_head read_wait; - struct list_head write_wait; -}; - -typedef unsigned int tcflag_t; - -typedef unsigned char cc_t; - -typedef unsigned int speed_t; - -struct ktermios { - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[19]; - speed_t c_ispeed; - speed_t c_ospeed; -}; - -struct winsize { - short unsigned int ws_row; - short unsigned int ws_col; - short unsigned int ws_xpixel; - short unsigned int ws_ypixel; -}; - -struct tty_driver; - -struct tty_operations; - -struct tty_ldisc; - -struct tty_port; - -struct tty_struct { - int magic; - struct kref kref; - struct device *dev; - struct tty_driver *driver; - const struct tty_operations *ops; - int index; - struct ld_semaphore ldisc_sem; - struct tty_ldisc *ldisc; - struct mutex atomic_write_lock; - struct mutex legacy_mutex; - struct mutex throttle_mutex; - struct rw_semaphore termios_rwsem; - struct mutex winsize_mutex; - struct ktermios termios; - struct ktermios termios_locked; - char name[64]; - long unsigned int flags; - int count; - struct winsize winsize; - struct { - spinlock_t lock; - bool stopped; - bool tco_stopped; - long unsigned int unused[0]; - } flow; - struct { - spinlock_t lock; - struct pid *pgrp; - struct pid *session; - unsigned char pktstatus; - bool packet; - long unsigned int unused[0]; - } ctrl; - int hw_stopped; - unsigned int receive_room; - int flow_change; - struct tty_struct *link; - struct fasync_struct *fasync; - wait_queue_head_t write_wait; - wait_queue_head_t read_wait; - struct work_struct hangup_work; - void *disc_data; - void *driver_data; - spinlock_t files_lock; - struct list_head tty_files; - int closing; - unsigned char *write_buf; - int write_cnt; - struct work_struct SAK_work; - struct tty_port *port; -}; - -typedef struct { - size_t written; - size_t count; - union { - char *buf; - void *data; - } arg; - int error; -} read_descriptor_t; - -struct posix_acl_entry { - short int e_tag; - short unsigned int e_perm; - union { - kuid_t e_uid; - kgid_t e_gid; - }; -}; - -struct posix_acl { - refcount_t a_refcount; - struct callback_head a_rcu; - unsigned int a_count; - struct posix_acl_entry a_entries[0]; -}; - -struct serial_icounter_struct; - -struct serial_struct; - -struct tty_operations { - struct tty_struct * (*lookup)(struct tty_driver *, struct file *, int); - int (*install)(struct tty_driver *, struct tty_struct *); - void (*remove)(struct tty_driver *, struct tty_struct *); - int (*open)(struct tty_struct *, struct file *); - void (*close)(struct tty_struct *, struct file *); - void (*shutdown)(struct tty_struct *); - void (*cleanup)(struct tty_struct *); - int (*write)(struct tty_struct *, const unsigned char *, int); - int (*put_char)(struct tty_struct *, unsigned char); - void (*flush_chars)(struct tty_struct *); - unsigned int (*write_room)(struct tty_struct *); - unsigned int (*chars_in_buffer)(struct tty_struct *); - int (*ioctl)(struct tty_struct *, unsigned int, long unsigned int); - long int (*compat_ioctl)(struct tty_struct *, unsigned int, long unsigned int); - void (*set_termios)(struct tty_struct *, struct ktermios *); - void (*throttle)(struct tty_struct *); - void (*unthrottle)(struct tty_struct *); - void (*stop)(struct tty_struct *); - void (*start)(struct tty_struct *); - void (*hangup)(struct tty_struct *); - int (*break_ctl)(struct tty_struct *, int); - void (*flush_buffer)(struct tty_struct *); - void (*set_ldisc)(struct tty_struct *); - void (*wait_until_sent)(struct tty_struct *, int); - void (*send_xchar)(struct tty_struct *, char); - int (*tiocmget)(struct tty_struct *); - int (*tiocmset)(struct tty_struct *, unsigned int, unsigned int); - int (*resize)(struct tty_struct *, struct winsize *); - int (*get_icount)(struct tty_struct *, struct serial_icounter_struct *); - int (*get_serial)(struct tty_struct *, struct serial_struct *); - int (*set_serial)(struct tty_struct *, struct serial_struct *); - void (*show_fdinfo)(struct tty_struct *, struct seq_file *); - int (*proc_show)(struct seq_file *, void *); -}; - -struct proc_dir_entry; - -struct tty_driver { - int magic; - struct kref kref; - struct cdev **cdevs; - struct module *owner; - const char *driver_name; - const char *name; - int name_base; - int major; - int minor_start; - unsigned int num; - short int type; - short int subtype; - struct ktermios init_termios; - long unsigned int flags; - struct proc_dir_entry *proc_entry; - struct tty_driver *other; - struct tty_struct **ttys; - struct tty_port **ports; - struct ktermios **termios; - void *driver_state; - const struct tty_operations *ops; - struct list_head tty_drivers; -}; - -struct tty_buffer { - union { - struct tty_buffer *next; - struct llist_node free; - }; - int used; - int size; - int commit; - int read; - int flags; - long unsigned int data[0]; -}; - -struct tty_bufhead { - struct tty_buffer *head; - struct work_struct work; - struct mutex lock; - atomic_t priority; - struct tty_buffer sentinel; - struct llist_head free; - atomic_t mem_used; - int mem_limit; - struct tty_buffer *tail; -}; - -struct tty_port_operations; - -struct tty_port_client_operations; - -struct tty_port { - struct tty_bufhead buf; - struct tty_struct *tty; - struct tty_struct *itty; - const struct tty_port_operations *ops; - const struct tty_port_client_operations *client_ops; - spinlock_t lock; - int blocked_open; - int count; - wait_queue_head_t open_wait; - wait_queue_head_t delta_msr_wait; - long unsigned int flags; - long unsigned int iflags; - unsigned char console: 1; - struct mutex mutex; - struct mutex buf_mutex; - unsigned char *xmit_buf; - unsigned int close_delay; - unsigned int closing_wait; - int drain_delay; - struct kref kref; - void *client_data; -}; - -struct tty_ldisc_ops { - char *name; - int num; - int flags; - int (*open)(struct tty_struct *); - void (*close)(struct tty_struct *); - void (*flush_buffer)(struct tty_struct *); - ssize_t (*read)(struct tty_struct *, struct file *, unsigned char *, size_t, void **, long unsigned int); - ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t); - int (*ioctl)(struct tty_struct *, struct file *, unsigned int, long unsigned int); - int (*compat_ioctl)(struct tty_struct *, struct file *, unsigned int, long unsigned int); - void (*set_termios)(struct tty_struct *, struct ktermios *); - __poll_t (*poll)(struct tty_struct *, struct file *, struct poll_table_struct *); - int (*hangup)(struct tty_struct *); - void (*receive_buf)(struct tty_struct *, const unsigned char *, const char *, int); - void (*write_wakeup)(struct tty_struct *); - void (*dcd_change)(struct tty_struct *, unsigned int); - int (*receive_buf2)(struct tty_struct *, const unsigned char *, const char *, int); - struct module *owner; -}; - -struct tty_ldisc { - struct tty_ldisc_ops *ops; - struct tty_struct *tty; -}; - -struct tty_port_operations { - int (*carrier_raised)(struct tty_port *); - void (*dtr_rts)(struct tty_port *, int); - void (*shutdown)(struct tty_port *); - int (*activate)(struct tty_port *, struct tty_struct *); - void (*destruct)(struct tty_port *); -}; - -struct tty_port_client_operations { - int (*receive_buf)(struct tty_port *, const unsigned char *, const unsigned char *, size_t); - void (*write_wakeup)(struct tty_port *); -}; - -struct prot_inuse; - -struct netns_core { - struct ctl_table_header *sysctl_hdr; - int sysctl_somaxconn; - int *sock_inuse; - struct prot_inuse *prot_inuse; -}; - -struct ipstats_mib; - -struct tcp_mib; - -struct linux_mib; - -struct udp_mib; - -struct linux_xfrm_mib; - -struct linux_tls_mib; - -struct mptcp_mib; - -struct icmp_mib; - -struct icmpmsg_mib; - -struct icmpv6_mib; - -struct icmpv6msg_mib; - -struct netns_mib { - struct ipstats_mib *ip_statistics; - struct ipstats_mib *ipv6_statistics; - struct tcp_mib *tcp_statistics; - struct linux_mib *net_statistics; - struct udp_mib *udp_statistics; - struct udp_mib *udp_stats_in6; - struct linux_xfrm_mib *xfrm_statistics; - struct linux_tls_mib *tls_statistics; - struct mptcp_mib *mptcp_statistics; - struct udp_mib *udplite_statistics; - struct udp_mib *udplite_stats_in6; - struct icmp_mib *icmp_statistics; - struct icmpmsg_mib *icmpmsg_statistics; - struct icmpv6_mib *icmpv6_statistics; - struct icmpv6msg_mib *icmpv6msg_statistics; - struct proc_dir_entry *proc_net_devsnmp6; -}; - -struct netns_packet { - struct mutex sklist_lock; - struct hlist_head sklist; -}; - -struct netns_unix { - int sysctl_max_dgram_qlen; - struct ctl_table_header *ctl; -}; - -struct netns_nexthop { - struct rb_root rb_root; - struct hlist_head *devhash; - unsigned int seq; - u32 last_id_allocated; - struct blocking_notifier_head notifier_chain; -}; - -struct inet_hashinfo; - -struct inet_timewait_death_row { - atomic_t tw_count; - char tw_pad[60]; - struct inet_hashinfo *hashinfo; - int sysctl_max_tw_buckets; -}; - -struct local_ports { - seqlock_t lock; - int range[2]; - bool warned; -}; - -struct ping_group_range { - seqlock_t lock; - kgid_t range[2]; -}; - -typedef struct { - u64 key[2]; -} siphash_key_t; - -struct ipv4_devconf; - -struct ip_ra_chain; - -struct fib_rules_ops; - -struct fib_table; - -struct inet_peer_base; - -struct fqdir; - -struct tcp_congestion_ops; - -struct tcp_fastopen_context; - -struct fib_notifier_ops; - -struct netns_ipv4 { - struct inet_timewait_death_row tcp_death_row; - struct ctl_table_header *forw_hdr; - struct ctl_table_header *frags_hdr; - struct ctl_table_header *ipv4_hdr; - struct ctl_table_header *route_hdr; - struct ctl_table_header *xfrm4_hdr; - struct ipv4_devconf *devconf_all; - struct ipv4_devconf *devconf_dflt; - struct ip_ra_chain *ra_chain; - struct mutex ra_mutex; - struct fib_rules_ops *rules_ops; - struct fib_table *fib_main; - struct fib_table *fib_default; - unsigned int fib_rules_require_fldissect; - bool fib_has_custom_rules; - bool fib_has_custom_local_routes; - bool fib_offload_disabled; - int fib_num_tclassid_users; - struct hlist_head *fib_table_hash; - struct sock *fibnl; - struct sock **icmp_sk; - struct sock *mc_autojoin_sk; - struct inet_peer_base *peers; - struct sock **tcp_sk; - struct fqdir *fqdir; - u8 sysctl_icmp_echo_ignore_all; - u8 sysctl_icmp_echo_enable_probe; - u8 sysctl_icmp_echo_ignore_broadcasts; - u8 sysctl_icmp_ignore_bogus_error_responses; - u8 sysctl_icmp_errors_use_inbound_ifaddr; - int sysctl_icmp_ratelimit; - int sysctl_icmp_ratemask; - struct local_ports ip_local_ports; - u8 sysctl_tcp_ecn; - u8 sysctl_tcp_ecn_fallback; - u8 sysctl_ip_default_ttl; - u8 sysctl_ip_no_pmtu_disc; - u8 sysctl_ip_fwd_use_pmtu; - u8 sysctl_ip_fwd_update_priority; - u8 sysctl_ip_nonlocal_bind; - u8 sysctl_ip_autobind_reuse; - u8 sysctl_ip_dynaddr; - u8 sysctl_ip_early_demux; - u8 sysctl_raw_l3mdev_accept; - u8 sysctl_tcp_early_demux; - u8 sysctl_udp_early_demux; - u8 sysctl_nexthop_compat_mode; - u8 sysctl_fwmark_reflect; - u8 sysctl_tcp_fwmark_accept; - u8 sysctl_tcp_l3mdev_accept; - u8 sysctl_tcp_mtu_probing; - int sysctl_tcp_mtu_probe_floor; - int sysctl_tcp_base_mss; - int sysctl_tcp_min_snd_mss; - int sysctl_tcp_probe_threshold; - u32 sysctl_tcp_probe_interval; - int sysctl_tcp_keepalive_time; - int sysctl_tcp_keepalive_intvl; - u8 sysctl_tcp_keepalive_probes; - u8 sysctl_tcp_syn_retries; - u8 sysctl_tcp_synack_retries; - u8 sysctl_tcp_syncookies; - u8 sysctl_tcp_migrate_req; - int sysctl_tcp_reordering; - u8 sysctl_tcp_retries1; - u8 sysctl_tcp_retries2; - u8 sysctl_tcp_orphan_retries; - u8 sysctl_tcp_tw_reuse; - int sysctl_tcp_fin_timeout; - unsigned int sysctl_tcp_notsent_lowat; - u8 sysctl_tcp_sack; - u8 sysctl_tcp_window_scaling; - u8 sysctl_tcp_timestamps; - u8 sysctl_tcp_early_retrans; - u8 sysctl_tcp_recovery; - u8 sysctl_tcp_thin_linear_timeouts; - u8 sysctl_tcp_slow_start_after_idle; - u8 sysctl_tcp_retrans_collapse; - u8 sysctl_tcp_stdurg; - u8 sysctl_tcp_rfc1337; - u8 sysctl_tcp_abort_on_overflow; - u8 sysctl_tcp_fack; - int sysctl_tcp_max_reordering; - int sysctl_tcp_adv_win_scale; - u8 sysctl_tcp_dsack; - u8 sysctl_tcp_app_win; - u8 sysctl_tcp_frto; - u8 sysctl_tcp_nometrics_save; - u8 sysctl_tcp_no_ssthresh_metrics_save; - u8 sysctl_tcp_moderate_rcvbuf; - u8 sysctl_tcp_tso_win_divisor; - u8 sysctl_tcp_workaround_signed_windows; - int sysctl_tcp_limit_output_bytes; - int sysctl_tcp_challenge_ack_limit; - int sysctl_tcp_min_rtt_wlen; - u8 sysctl_tcp_min_tso_segs; - u8 sysctl_tcp_autocorking; - u8 sysctl_tcp_reflect_tos; - u8 sysctl_tcp_comp_sack_nr; - int sysctl_tcp_invalid_ratelimit; - int sysctl_tcp_pacing_ss_ratio; - int sysctl_tcp_pacing_ca_ratio; - int sysctl_tcp_wmem[3]; - int sysctl_tcp_rmem[3]; - long unsigned int sysctl_tcp_comp_sack_delay_ns; - long unsigned int sysctl_tcp_comp_sack_slack_ns; - int sysctl_max_syn_backlog; - int sysctl_tcp_fastopen; - const struct tcp_congestion_ops *tcp_congestion_control; - struct tcp_fastopen_context *tcp_fastopen_ctx; - spinlock_t tcp_fastopen_ctx_lock; - unsigned int sysctl_tcp_fastopen_blackhole_timeout; - atomic_t tfo_active_disable_times; - long unsigned int tfo_active_disable_stamp; - int sysctl_udp_wmem_min; - int sysctl_udp_rmem_min; - u8 sysctl_fib_notify_on_flag_change; - u8 sysctl_udp_l3mdev_accept; - u8 sysctl_igmp_llm_reports; - int sysctl_igmp_max_memberships; - int sysctl_igmp_max_msf; - int sysctl_igmp_qrv; - struct ping_group_range ping_group_range; - atomic_t dev_addr_genid; - long unsigned int *sysctl_local_reserved_ports; - int sysctl_ip_prot_sock; - struct list_head mr_tables; - struct fib_rules_ops *mr_rules_ops; - u32 sysctl_fib_multipath_hash_fields; - u8 sysctl_fib_multipath_use_neigh; - u8 sysctl_fib_multipath_hash_policy; - struct fib_notifier_ops *notifier_ops; - unsigned int fib_seq; - struct fib_notifier_ops *ipmr_notifier_ops; - unsigned int ipmr_seq; - atomic_t rt_genid; - siphash_key_t ip_id_key; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct neighbour; - -struct dst_ops { - short unsigned int family; - unsigned int gc_thresh; - int (*gc)(struct dst_ops *); - struct dst_entry * (*check)(struct dst_entry *, __u32); - unsigned int (*default_advmss)(const struct dst_entry *); - unsigned int (*mtu)(const struct dst_entry *); - u32 * (*cow_metrics)(struct dst_entry *, long unsigned int); - void (*destroy)(struct dst_entry *); - void (*ifdown)(struct dst_entry *, struct net_device *, int); - struct dst_entry * (*negative_advice)(struct dst_entry *); - void (*link_failure)(struct sk_buff *); - void (*update_pmtu)(struct dst_entry *, struct sock *, struct sk_buff *, u32, bool); - void (*redirect)(struct dst_entry *, struct sock *, struct sk_buff *); - int (*local_out)(struct net *, struct sock *, struct sk_buff *); - struct neighbour * (*neigh_lookup)(const struct dst_entry *, struct sk_buff *, const void *); - void (*confirm_neigh)(const struct dst_entry *, const void *); - struct kmem_cache *kmem_cachep; - struct percpu_counter pcpuc_entries; - long: 64; - long: 64; - long: 64; -}; - -struct netns_sysctl_ipv6 { - struct ctl_table_header *hdr; - struct ctl_table_header *route_hdr; - struct ctl_table_header *icmp_hdr; - struct ctl_table_header *frags_hdr; - struct ctl_table_header *xfrm6_hdr; - int flush_delay; - int ip6_rt_max_size; - int ip6_rt_gc_min_interval; - int ip6_rt_gc_timeout; - int ip6_rt_gc_interval; - int ip6_rt_gc_elasticity; - int ip6_rt_mtu_expires; - int ip6_rt_min_advmss; - u32 multipath_hash_fields; - u8 multipath_hash_policy; - u8 bindv6only; - u8 flowlabel_consistency; - u8 auto_flowlabels; - int icmpv6_time; - u8 icmpv6_echo_ignore_all; - u8 icmpv6_echo_ignore_multicast; - u8 icmpv6_echo_ignore_anycast; - long unsigned int icmpv6_ratemask[4]; - long unsigned int *icmpv6_ratemask_ptr; - u8 anycast_src_echo_reply; - u8 ip_nonlocal_bind; - u8 fwmark_reflect; - u8 flowlabel_state_ranges; - int idgen_retries; - int idgen_delay; - int flowlabel_reflect; - int max_dst_opts_cnt; - int max_hbh_opts_cnt; - int max_dst_opts_len; - int max_hbh_opts_len; - int seg6_flowlabel; - bool skip_notify_on_dev_down; - u8 fib_notify_on_flag_change; -}; - -struct ipv6_devconf; - -struct fib6_info; - -struct rt6_info; - -struct rt6_statistics; - -struct fib6_table; - -struct seg6_pernet_data; - -struct netns_ipv6 { - struct dst_ops ip6_dst_ops; - struct netns_sysctl_ipv6 sysctl; - struct ipv6_devconf *devconf_all; - struct ipv6_devconf *devconf_dflt; - struct inet_peer_base *peers; - struct fqdir *fqdir; - struct fib6_info *fib6_null_entry; - struct rt6_info *ip6_null_entry; - struct rt6_statistics *rt6_stats; - struct timer_list ip6_fib_timer; - struct hlist_head *fib_table_hash; - struct fib6_table *fib6_main_tbl; - struct list_head fib6_walkers; - rwlock_t fib6_walker_lock; - spinlock_t fib6_gc_lock; - unsigned int ip6_rt_gc_expire; - long unsigned int ip6_rt_last_gc; - unsigned int fib6_rules_require_fldissect; - bool fib6_has_custom_rules; - unsigned int fib6_routes_require_src; - struct rt6_info *ip6_prohibit_entry; - struct rt6_info *ip6_blk_hole_entry; - struct fib6_table *fib6_local_tbl; - struct fib_rules_ops *fib6_rules_ops; - struct sock **icmp_sk; - struct sock *ndisc_sk; - struct sock *tcp_sk; - struct sock *igmp_sk; - struct sock *mc_autojoin_sk; - struct list_head mr6_tables; - struct fib_rules_ops *mr6_rules_ops; - atomic_t dev_addr_genid; - atomic_t fib6_sernum; - struct seg6_pernet_data *seg6_data; - struct fib_notifier_ops *notifier_ops; - struct fib_notifier_ops *ip6mr_notifier_ops; - unsigned int ipmr_seq; - struct { - struct hlist_head head; - spinlock_t lock; - u32 seq; - } ip6addrlbl_table; - long: 64; - long: 64; - long: 64; -}; - -struct netns_sysctl_lowpan { - struct ctl_table_header *frags_hdr; -}; - -struct netns_ieee802154_lowpan { - struct netns_sysctl_lowpan sysctl; - struct fqdir *fqdir; -}; - -struct sctp_mib; - -struct netns_sctp { - struct sctp_mib *sctp_statistics; - struct proc_dir_entry *proc_net_sctp; - struct ctl_table_header *sysctl_header; - struct sock *ctl_sock; - struct sock *udp4_sock; - struct sock *udp6_sock; - int udp_port; - int encap_port; - struct list_head local_addr_list; - struct list_head addr_waitq; - struct timer_list addr_wq_timer; - struct list_head auto_asconf_splist; - spinlock_t addr_wq_lock; - spinlock_t local_addr_lock; - unsigned int rto_initial; - unsigned int rto_min; - unsigned int rto_max; - int rto_alpha; - int rto_beta; - int max_burst; - int cookie_preserve_enable; - char *sctp_hmac_alg; - unsigned int valid_cookie_life; - unsigned int sack_timeout; - unsigned int hb_interval; - unsigned int probe_interval; - int max_retrans_association; - int max_retrans_path; - int max_retrans_init; - int pf_retrans; - int ps_retrans; - int pf_enable; - int pf_expose; - int sndbuf_policy; - int rcvbuf_policy; - int default_auto_asconf; - int addip_enable; - int addip_noauth; - int prsctp_enable; - int reconf_enable; - int auth_enable; - int intl_enable; - int ecn_enable; - int scope_policy; - int rwnd_upd_shift; - long unsigned int max_autoclose; -}; - -struct nf_queue_handler; - -struct nf_logger; - -struct nf_hook_entries; - -struct netns_nf { - struct proc_dir_entry *proc_netfilter; - const struct nf_queue_handler *queue_handler; - const struct nf_logger *nf_loggers[13]; - struct ctl_table_header *nf_log_dir_header; - struct nf_hook_entries *hooks_ipv4[5]; - struct nf_hook_entries *hooks_ipv6[5]; - struct nf_hook_entries *hooks_arp[3]; - struct nf_hook_entries *hooks_bridge[5]; -}; - -struct netns_xt { - bool notrack_deprecated_warning; - bool clusterip_deprecated_warning; -}; - -struct nf_generic_net { - unsigned int timeout; -}; - -struct nf_tcp_net { - unsigned int timeouts[14]; - u8 tcp_loose; - u8 tcp_be_liberal; - u8 tcp_max_retrans; - u8 tcp_ignore_invalid_rst; - unsigned int offload_timeout; -}; - -struct nf_udp_net { - unsigned int timeouts[2]; - unsigned int offload_timeout; -}; - -struct nf_icmp_net { - unsigned int timeout; -}; - -struct nf_dccp_net { - u8 dccp_loose; - unsigned int dccp_timeout[10]; -}; - -struct nf_sctp_net { - unsigned int timeouts[10]; -}; - -struct nf_gre_net { - struct list_head keymap_list; - unsigned int timeouts[2]; -}; - -struct nf_ip_net { - struct nf_generic_net generic; - struct nf_tcp_net tcp; - struct nf_udp_net udp; - struct nf_icmp_net icmp; - struct nf_icmp_net icmpv6; - struct nf_dccp_net dccp; - struct nf_sctp_net sctp; - struct nf_gre_net gre; -}; - -struct ct_pcpu; - -struct ip_conntrack_stat; - -struct nf_ct_event_notifier; - -struct nf_exp_event_notifier; - -struct netns_ct { - bool ecache_dwork_pending; - u8 sysctl_log_invalid; - u8 sysctl_events; - u8 sysctl_acct; - u8 sysctl_auto_assign_helper; - u8 sysctl_tstamp; - u8 sysctl_checksum; - struct ct_pcpu *pcpu_lists; - struct ip_conntrack_stat *stat; - struct nf_ct_event_notifier *nf_conntrack_event_cb; - struct nf_exp_event_notifier *nf_expect_event_cb; - struct nf_ip_net nf_ct_proto; - unsigned int labels_used; -}; - -struct netns_nftables { - u8 gencursor; -}; - -struct netns_bpf { - struct bpf_prog_array *run_array[2]; - struct bpf_prog *progs[2]; - struct list_head links[2]; -}; - -struct xfrm_policy_hash { - struct hlist_head *table; - unsigned int hmask; - u8 dbits4; - u8 sbits4; - u8 dbits6; - u8 sbits6; -}; - -struct xfrm_policy_hthresh { - struct work_struct work; - seqlock_t lock; - u8 lbits4; - u8 rbits4; - u8 lbits6; - u8 rbits6; -}; - -struct netns_xfrm { - struct list_head state_all; - struct hlist_head *state_bydst; - struct hlist_head *state_bysrc; - struct hlist_head *state_byspi; - struct hlist_head *state_byseq; - unsigned int state_hmask; - unsigned int state_num; - struct work_struct state_hash_work; - struct list_head policy_all; - struct hlist_head *policy_byidx; - unsigned int policy_idx_hmask; - struct hlist_head policy_inexact[3]; - struct xfrm_policy_hash policy_bydst[3]; - unsigned int policy_count[6]; - struct work_struct policy_hash_work; - struct xfrm_policy_hthresh policy_hthresh; - struct list_head inexact_bins; - struct sock *nlsk; - struct sock *nlsk_stash; - u32 sysctl_aevent_etime; - u32 sysctl_aevent_rseqth; - int sysctl_larval_drop; - u32 sysctl_acq_expires; - struct ctl_table_header *sysctl_hdr; - long: 64; - long: 64; - long: 64; - long: 64; - struct dst_ops xfrm4_dst_ops; - struct dst_ops xfrm6_dst_ops; - spinlock_t xfrm_state_lock; - seqcount_spinlock_t xfrm_state_hash_generation; - seqcount_spinlock_t xfrm_policy_hash_generation; - spinlock_t xfrm_policy_lock; - struct mutex xfrm_cfg_mutex; - long: 64; - long: 64; -}; - -struct netns_ipvs; - -struct mpls_route; - -struct netns_mpls { - int ip_ttl_propagate; - int default_ttl; - size_t platform_labels; - struct mpls_route **platform_label; - struct ctl_table_header *ctl; -}; - -struct can_dev_rcv_lists; - -struct can_pkg_stats; - -struct can_rcv_lists_stats; - -struct netns_can { - struct proc_dir_entry *proc_dir; - struct proc_dir_entry *pde_stats; - struct proc_dir_entry *pde_reset_stats; - struct proc_dir_entry *pde_rcvlist_all; - struct proc_dir_entry *pde_rcvlist_fil; - struct proc_dir_entry *pde_rcvlist_inv; - struct proc_dir_entry *pde_rcvlist_sff; - struct proc_dir_entry *pde_rcvlist_eff; - struct proc_dir_entry *pde_rcvlist_err; - struct proc_dir_entry *bcmproc_dir; - struct can_dev_rcv_lists *rx_alldev_list; - spinlock_t rcvlists_lock; - struct timer_list stattimer; - struct can_pkg_stats *pkg_stats; - struct can_rcv_lists_stats *rcv_lists_stats; - struct hlist_head cgw_list; -}; - -struct netns_xdp { - struct mutex lock; - struct hlist_head list; -}; - -struct smc_stats; - -struct smc_stats_rsn; - -struct netns_smc { - struct smc_stats *smc_stats; - struct mutex mutex_fback_rsn; - struct smc_stats_rsn *fback_rsn; -}; - -struct uevent_sock; - -struct net_generic; - -struct net { - refcount_t passive; - spinlock_t rules_mod_lock; - unsigned int dev_unreg_count; - unsigned int dev_base_seq; - int ifindex; - spinlock_t nsid_lock; - atomic_t fnhe_genid; - struct list_head list; - struct list_head exit_list; - struct llist_node cleanup_list; - struct key_tag *key_domain; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct idr netns_ids; - struct ns_common ns; - struct list_head dev_base_head; - struct proc_dir_entry *proc_net; - struct proc_dir_entry *proc_net_stat; - struct ctl_table_set sysctls; - struct sock *rtnl; - struct sock *genl_sock; - struct uevent_sock *uevent_sock; - struct hlist_head *dev_name_head; - struct hlist_head *dev_index_head; - struct raw_notifier_head netdev_chain; - u32 hash_mix; - struct net_device *loopback_dev; - struct list_head rules_ops; - struct netns_core core; - struct netns_mib mib; - struct netns_packet packet; - struct netns_unix unx; - struct netns_nexthop nexthop; - struct netns_ipv4 ipv4; - struct netns_ipv6 ipv6; - struct netns_ieee802154_lowpan ieee802154_lowpan; - struct netns_sctp sctp; - struct netns_nf nf; - struct netns_xt xt; - struct netns_ct ct; - struct netns_nftables nft; - struct sk_buff_head wext_nlevents; - struct net_generic *gen; - struct netns_bpf bpf; - long: 64; - long: 64; - struct netns_xfrm xfrm; - u64 net_cookie; - struct netns_ipvs *ipvs; - struct netns_mpls mpls; - struct netns_can can; - struct netns_xdp xdp; - struct sock *crypto_nlsk; - struct sock *diag_nlsk; - struct netns_smc smc; - long: 64; -}; - -typedef struct { - local64_t v; -} u64_stats_t; - -struct bpf_insn { - __u8 code; - __u8 dst_reg: 4; - __u8 src_reg: 4; - __s16 off; - __s32 imm; -}; - -enum bpf_map_type { - BPF_MAP_TYPE_UNSPEC = 0, - BPF_MAP_TYPE_HASH = 1, - BPF_MAP_TYPE_ARRAY = 2, - BPF_MAP_TYPE_PROG_ARRAY = 3, - BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4, - BPF_MAP_TYPE_PERCPU_HASH = 5, - BPF_MAP_TYPE_PERCPU_ARRAY = 6, - BPF_MAP_TYPE_STACK_TRACE = 7, - BPF_MAP_TYPE_CGROUP_ARRAY = 8, - BPF_MAP_TYPE_LRU_HASH = 9, - BPF_MAP_TYPE_LRU_PERCPU_HASH = 10, - BPF_MAP_TYPE_LPM_TRIE = 11, - BPF_MAP_TYPE_ARRAY_OF_MAPS = 12, - BPF_MAP_TYPE_HASH_OF_MAPS = 13, - BPF_MAP_TYPE_DEVMAP = 14, - BPF_MAP_TYPE_SOCKMAP = 15, - BPF_MAP_TYPE_CPUMAP = 16, - BPF_MAP_TYPE_XSKMAP = 17, - BPF_MAP_TYPE_SOCKHASH = 18, - BPF_MAP_TYPE_CGROUP_STORAGE = 19, - BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20, - BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21, - BPF_MAP_TYPE_QUEUE = 22, - BPF_MAP_TYPE_STACK = 23, - BPF_MAP_TYPE_SK_STORAGE = 24, - BPF_MAP_TYPE_DEVMAP_HASH = 25, - BPF_MAP_TYPE_STRUCT_OPS = 26, - BPF_MAP_TYPE_RINGBUF = 27, - BPF_MAP_TYPE_INODE_STORAGE = 28, - BPF_MAP_TYPE_TASK_STORAGE = 29, -}; - -enum bpf_prog_type { - BPF_PROG_TYPE_UNSPEC = 0, - BPF_PROG_TYPE_SOCKET_FILTER = 1, - BPF_PROG_TYPE_KPROBE = 2, - BPF_PROG_TYPE_SCHED_CLS = 3, - BPF_PROG_TYPE_SCHED_ACT = 4, - BPF_PROG_TYPE_TRACEPOINT = 5, - BPF_PROG_TYPE_XDP = 6, - BPF_PROG_TYPE_PERF_EVENT = 7, - BPF_PROG_TYPE_CGROUP_SKB = 8, - BPF_PROG_TYPE_CGROUP_SOCK = 9, - BPF_PROG_TYPE_LWT_IN = 10, - BPF_PROG_TYPE_LWT_OUT = 11, - BPF_PROG_TYPE_LWT_XMIT = 12, - BPF_PROG_TYPE_SOCK_OPS = 13, - BPF_PROG_TYPE_SK_SKB = 14, - BPF_PROG_TYPE_CGROUP_DEVICE = 15, - BPF_PROG_TYPE_SK_MSG = 16, - BPF_PROG_TYPE_RAW_TRACEPOINT = 17, - BPF_PROG_TYPE_CGROUP_SOCK_ADDR = 18, - BPF_PROG_TYPE_LWT_SEG6LOCAL = 19, - BPF_PROG_TYPE_LIRC_MODE2 = 20, - BPF_PROG_TYPE_SK_REUSEPORT = 21, - BPF_PROG_TYPE_FLOW_DISSECTOR = 22, - BPF_PROG_TYPE_CGROUP_SYSCTL = 23, - BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 24, - BPF_PROG_TYPE_CGROUP_SOCKOPT = 25, - BPF_PROG_TYPE_TRACING = 26, - BPF_PROG_TYPE_STRUCT_OPS = 27, - BPF_PROG_TYPE_EXT = 28, - BPF_PROG_TYPE_LSM = 29, - BPF_PROG_TYPE_SK_LOOKUP = 30, - BPF_PROG_TYPE_SYSCALL = 31, -}; - -enum bpf_attach_type { - BPF_CGROUP_INET_INGRESS = 0, - BPF_CGROUP_INET_EGRESS = 1, - BPF_CGROUP_INET_SOCK_CREATE = 2, - BPF_CGROUP_SOCK_OPS = 3, - BPF_SK_SKB_STREAM_PARSER = 4, - BPF_SK_SKB_STREAM_VERDICT = 5, - BPF_CGROUP_DEVICE = 6, - BPF_SK_MSG_VERDICT = 7, - BPF_CGROUP_INET4_BIND = 8, - BPF_CGROUP_INET6_BIND = 9, - BPF_CGROUP_INET4_CONNECT = 10, - BPF_CGROUP_INET6_CONNECT = 11, - BPF_CGROUP_INET4_POST_BIND = 12, - BPF_CGROUP_INET6_POST_BIND = 13, - BPF_CGROUP_UDP4_SENDMSG = 14, - BPF_CGROUP_UDP6_SENDMSG = 15, - BPF_LIRC_MODE2 = 16, - BPF_FLOW_DISSECTOR = 17, - BPF_CGROUP_SYSCTL = 18, - BPF_CGROUP_UDP4_RECVMSG = 19, - BPF_CGROUP_UDP6_RECVMSG = 20, - BPF_CGROUP_GETSOCKOPT = 21, - BPF_CGROUP_SETSOCKOPT = 22, - BPF_TRACE_RAW_TP = 23, - BPF_TRACE_FENTRY = 24, - BPF_TRACE_FEXIT = 25, - BPF_MODIFY_RETURN = 26, - BPF_LSM_MAC = 27, - BPF_TRACE_ITER = 28, - BPF_CGROUP_INET4_GETPEERNAME = 29, - BPF_CGROUP_INET6_GETPEERNAME = 30, - BPF_CGROUP_INET4_GETSOCKNAME = 31, - BPF_CGROUP_INET6_GETSOCKNAME = 32, - BPF_XDP_DEVMAP = 33, - BPF_CGROUP_INET_SOCK_RELEASE = 34, - BPF_XDP_CPUMAP = 35, - BPF_SK_LOOKUP = 36, - BPF_XDP = 37, - BPF_SK_SKB_VERDICT = 38, - BPF_SK_REUSEPORT_SELECT = 39, - BPF_SK_REUSEPORT_SELECT_OR_MIGRATE = 40, - __MAX_BPF_ATTACH_TYPE = 41, -}; - -union bpf_attr { - struct { - __u32 map_type; - __u32 key_size; - __u32 value_size; - __u32 max_entries; - __u32 map_flags; - __u32 inner_map_fd; - __u32 numa_node; - char map_name[16]; - __u32 map_ifindex; - __u32 btf_fd; - __u32 btf_key_type_id; - __u32 btf_value_type_id; - __u32 btf_vmlinux_value_type_id; - }; - struct { - __u32 map_fd; - __u64 key; - union { - __u64 value; - __u64 next_key; - }; - __u64 flags; - }; - struct { - __u64 in_batch; - __u64 out_batch; - __u64 keys; - __u64 values; - __u32 count; - __u32 map_fd; - __u64 elem_flags; - __u64 flags; - } batch; - struct { - __u32 prog_type; - __u32 insn_cnt; - __u64 insns; - __u64 license; - __u32 log_level; - __u32 log_size; - __u64 log_buf; - __u32 kern_version; - __u32 prog_flags; - char prog_name[16]; - __u32 prog_ifindex; - __u32 expected_attach_type; - __u32 prog_btf_fd; - __u32 func_info_rec_size; - __u64 func_info; - __u32 func_info_cnt; - __u32 line_info_rec_size; - __u64 line_info; - __u32 line_info_cnt; - __u32 attach_btf_id; - union { - __u32 attach_prog_fd; - __u32 attach_btf_obj_fd; - }; - __u64 fd_array; - }; - struct { - __u64 pathname; - __u32 bpf_fd; - __u32 file_flags; - }; - struct { - __u32 target_fd; - __u32 attach_bpf_fd; - __u32 attach_type; - __u32 attach_flags; - __u32 replace_bpf_fd; - }; - struct { - __u32 prog_fd; - __u32 retval; - __u32 data_size_in; - __u32 data_size_out; - __u64 data_in; - __u64 data_out; - __u32 repeat; - __u32 duration; - __u32 ctx_size_in; - __u32 ctx_size_out; - __u64 ctx_in; - __u64 ctx_out; - __u32 flags; - __u32 cpu; - } test; - struct { - union { - __u32 start_id; - __u32 prog_id; - __u32 map_id; - __u32 btf_id; - __u32 link_id; - }; - __u32 next_id; - __u32 open_flags; - }; - struct { - __u32 bpf_fd; - __u32 info_len; - __u64 info; - } info; - struct { - __u32 target_fd; - __u32 attach_type; - __u32 query_flags; - __u32 attach_flags; - __u64 prog_ids; - __u32 prog_cnt; - } query; - struct { - __u64 name; - __u32 prog_fd; - } raw_tracepoint; - struct { - __u64 btf; - __u64 btf_log_buf; - __u32 btf_size; - __u32 btf_log_size; - __u32 btf_log_level; - }; - struct { - __u32 pid; - __u32 fd; - __u32 flags; - __u32 buf_len; - __u64 buf; - __u32 prog_id; - __u32 fd_type; - __u64 probe_offset; - __u64 probe_addr; - } task_fd_query; - struct { - __u32 prog_fd; - union { - __u32 target_fd; - __u32 target_ifindex; - }; - __u32 attach_type; - __u32 flags; - union { - __u32 target_btf_id; - struct { - __u64 iter_info; - __u32 iter_info_len; - }; - }; - } link_create; - struct { - __u32 link_fd; - __u32 new_prog_fd; - __u32 flags; - __u32 old_prog_fd; - } link_update; - struct { - __u32 link_fd; - } link_detach; - struct { - __u32 type; - } enable_stats; - struct { - __u32 link_fd; - __u32 flags; - } iter_create; - struct { - __u32 prog_fd; - __u32 map_fd; - __u32 flags; - } prog_bind_map; -}; - -struct bpf_func_info { - __u32 insn_off; - __u32 type_id; -}; - -struct bpf_line_info { - __u32 insn_off; - __u32 file_name_off; - __u32 line_off; - __u32 line_col; -}; - -typedef struct { - union { - void *kernel; - void *user; - }; - bool is_kernel: 1; -} sockptr_t; - -struct bpf_iter_aux_info; - -typedef int (*bpf_iter_init_seq_priv_t)(void *, struct bpf_iter_aux_info *); - -struct bpf_map; - -struct bpf_iter_aux_info { - struct bpf_map *map; -}; - -typedef void (*bpf_iter_fini_seq_priv_t)(void *); - -struct bpf_iter_seq_info { - const struct seq_operations *seq_ops; - bpf_iter_init_seq_priv_t init_seq_private; - bpf_iter_fini_seq_priv_t fini_seq_private; - u32 seq_priv_size; -}; - -struct btf; - -struct btf_type; - -struct bpf_prog_aux; - -struct bpf_local_storage_map; - -struct bpf_verifier_env; - -struct bpf_func_state; - -struct bpf_map_ops { - int (*map_alloc_check)(union bpf_attr *); - struct bpf_map * (*map_alloc)(union bpf_attr *); - void (*map_release)(struct bpf_map *, struct file *); - void (*map_free)(struct bpf_map *); - int (*map_get_next_key)(struct bpf_map *, void *, void *); - void (*map_release_uref)(struct bpf_map *); - void * (*map_lookup_elem_sys_only)(struct bpf_map *, void *); - int (*map_lookup_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - int (*map_lookup_and_delete_elem)(struct bpf_map *, void *, void *, u64); - int (*map_lookup_and_delete_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - int (*map_update_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - int (*map_delete_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *); - void * (*map_lookup_elem)(struct bpf_map *, void *); - int (*map_update_elem)(struct bpf_map *, void *, void *, u64); - int (*map_delete_elem)(struct bpf_map *, void *); - int (*map_push_elem)(struct bpf_map *, void *, u64); - int (*map_pop_elem)(struct bpf_map *, void *); - int (*map_peek_elem)(struct bpf_map *, void *); - void * (*map_fd_get_ptr)(struct bpf_map *, struct file *, int); - void (*map_fd_put_ptr)(void *); - int (*map_gen_lookup)(struct bpf_map *, struct bpf_insn *); - u32 (*map_fd_sys_lookup_elem)(void *); - void (*map_seq_show_elem)(struct bpf_map *, void *, struct seq_file *); - int (*map_check_btf)(const struct bpf_map *, const struct btf *, const struct btf_type *, const struct btf_type *); - int (*map_poke_track)(struct bpf_map *, struct bpf_prog_aux *); - void (*map_poke_untrack)(struct bpf_map *, struct bpf_prog_aux *); - void (*map_poke_run)(struct bpf_map *, u32, struct bpf_prog *, struct bpf_prog *); - int (*map_direct_value_addr)(const struct bpf_map *, u64 *, u32); - int (*map_direct_value_meta)(const struct bpf_map *, u64, u32 *); - int (*map_mmap)(struct bpf_map *, struct vm_area_struct *); - __poll_t (*map_poll)(struct bpf_map *, struct file *, struct poll_table_struct *); - int (*map_local_storage_charge)(struct bpf_local_storage_map *, void *, u32); - void (*map_local_storage_uncharge)(struct bpf_local_storage_map *, void *, u32); - struct bpf_local_storage ** (*map_owner_storage_ptr)(void *); - int (*map_redirect)(struct bpf_map *, u32, u64); - bool (*map_meta_equal)(const struct bpf_map *, const struct bpf_map *); - int (*map_set_for_each_callback_args)(struct bpf_verifier_env *, struct bpf_func_state *, struct bpf_func_state *); - int (*map_for_each_callback)(struct bpf_map *, void *, void *, u64); - const char * const map_btf_name; - int *map_btf_id; - const struct bpf_iter_seq_info *iter_seq_info; -}; - -struct bpf_map { - const struct bpf_map_ops *ops; - struct bpf_map *inner_map_meta; - void *security; - enum bpf_map_type map_type; - u32 key_size; - u32 value_size; - u32 max_entries; - u32 map_flags; - int spin_lock_off; - u32 id; - int numa_node; - u32 btf_key_type_id; - u32 btf_value_type_id; - struct btf *btf; - struct mem_cgroup *memcg; - char name[16]; - u32 btf_vmlinux_value_type_id; - bool bypass_spec_v1; - bool frozen; - long: 16; - long: 64; - long: 64; - long: 64; - atomic64_t refcnt; - atomic64_t usercnt; - struct work_struct work; - struct mutex freeze_mutex; - u64 writecnt; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct btf_header { - __u16 magic; - __u8 version; - __u8 flags; - __u32 hdr_len; - __u32 type_off; - __u32 type_len; - __u32 str_off; - __u32 str_len; -}; - -struct btf { - void *data; - struct btf_type **types; - u32 *resolved_ids; - u32 *resolved_sizes; - const char *strings; - void *nohdr_data; - struct btf_header hdr; - u32 nr_types; - u32 types_size; - u32 data_size; - refcount_t refcnt; - u32 id; - struct callback_head rcu; - struct btf *base_btf; - u32 start_id; - u32 start_str_off; - char name[56]; - bool kernel_btf; -}; - -struct btf_type { - __u32 name_off; - __u32 info; - union { - __u32 size; - __u32 type; - }; -}; - -struct bpf_ksym { - long unsigned int start; - long unsigned int end; - char name[128]; - struct list_head lnode; - struct latch_tree_node tnode; - bool prog; -}; - -struct bpf_ctx_arg_aux; - -struct bpf_trampoline; - -struct bpf_jit_poke_descriptor; - -struct bpf_kfunc_desc_tab; - -struct bpf_prog_ops; - -struct btf_mod_pair; - -struct bpf_prog_offload; - -struct bpf_func_info_aux; - -struct bpf_prog_aux { - atomic64_t refcnt; - u32 used_map_cnt; - u32 used_btf_cnt; - u32 max_ctx_offset; - u32 max_pkt_offset; - u32 max_tp_access; - u32 stack_depth; - u32 id; - u32 func_cnt; - u32 func_idx; - u32 attach_btf_id; - u32 ctx_arg_info_size; - u32 max_rdonly_access; - u32 max_rdwr_access; - struct btf *attach_btf; - const struct bpf_ctx_arg_aux *ctx_arg_info; - struct mutex dst_mutex; - struct bpf_prog *dst_prog; - struct bpf_trampoline *dst_trampoline; - enum bpf_prog_type saved_dst_prog_type; - enum bpf_attach_type saved_dst_attach_type; - bool verifier_zext; - bool offload_requested; - bool attach_btf_trace; - bool func_proto_unreliable; - bool sleepable; - bool tail_call_reachable; - struct hlist_node tramp_hlist; - const struct btf_type *attach_func_proto; - const char *attach_func_name; - struct bpf_prog **func; - void *jit_data; - struct bpf_jit_poke_descriptor *poke_tab; - struct bpf_kfunc_desc_tab *kfunc_tab; - u32 size_poke_tab; - struct bpf_ksym ksym; - const struct bpf_prog_ops *ops; - struct bpf_map **used_maps; - struct mutex used_maps_mutex; - struct btf_mod_pair *used_btfs; - struct bpf_prog *prog; - struct user_struct *user; - u64 load_time; - struct bpf_map *cgroup_storage[2]; - char name[16]; - void *security; - struct bpf_prog_offload *offload; - struct btf *btf; - struct bpf_func_info *func_info; - struct bpf_func_info_aux *func_info_aux; - struct bpf_line_info *linfo; - void **jited_linfo; - u32 func_info_cnt; - u32 nr_linfo; - u32 linfo_idx; - u32 num_exentries; - struct exception_table_entry *extable; - union { - struct work_struct work; - struct callback_head rcu; - }; -}; - -struct sock_filter { - __u16 code; - __u8 jt; - __u8 jf; - __u32 k; -}; - -struct bpf_prog_stats; - -struct sock_fprog_kern; - -struct bpf_prog { - u16 pages; - u16 jited: 1; - u16 jit_requested: 1; - u16 gpl_compatible: 1; - u16 cb_access: 1; - u16 dst_needed: 1; - u16 blinded: 1; - u16 is_func: 1; - u16 kprobe_override: 1; - u16 has_callchain_buf: 1; - u16 enforce_expected_attach_type: 1; - u16 call_get_stack: 1; - enum bpf_prog_type type; - enum bpf_attach_type expected_attach_type; - u32 len; - u32 jited_len; - u8 tag[8]; - struct bpf_prog_stats *stats; - int *active; - unsigned int (*bpf_func)(const void *, const struct bpf_insn *); - struct bpf_prog_aux *aux; - struct sock_fprog_kern *orig_prog; - struct sock_filter insns[0]; - struct bpf_insn insnsi[0]; -}; - -struct bpf_offloaded_map; - -struct bpf_map_dev_ops { - int (*map_get_next_key)(struct bpf_offloaded_map *, void *, void *); - int (*map_lookup_elem)(struct bpf_offloaded_map *, void *, void *); - int (*map_update_elem)(struct bpf_offloaded_map *, void *, void *, u64); - int (*map_delete_elem)(struct bpf_offloaded_map *, void *); -}; - -struct bpf_offloaded_map { - struct bpf_map map; - struct net_device *netdev; - const struct bpf_map_dev_ops *dev_ops; - void *dev_priv; - struct list_head offloads; - long: 64; - long: 64; - long: 64; -}; - -struct net_device_stats { - long unsigned int rx_packets; - long unsigned int tx_packets; - long unsigned int rx_bytes; - long unsigned int tx_bytes; - long unsigned int rx_errors; - long unsigned int tx_errors; - long unsigned int rx_dropped; - long unsigned int tx_dropped; - long unsigned int multicast; - long unsigned int collisions; - long unsigned int rx_length_errors; - long unsigned int rx_over_errors; - long unsigned int rx_crc_errors; - long unsigned int rx_frame_errors; - long unsigned int rx_fifo_errors; - long unsigned int rx_missed_errors; - long unsigned int tx_aborted_errors; - long unsigned int tx_carrier_errors; - long unsigned int tx_fifo_errors; - long unsigned int tx_heartbeat_errors; - long unsigned int tx_window_errors; - long unsigned int rx_compressed; - long unsigned int tx_compressed; -}; - -struct netdev_hw_addr_list { - struct list_head list; - int count; -}; - -struct tipc_bearer; - -struct mpls_dev; - -enum rx_handler_result { - RX_HANDLER_CONSUMED = 0, - RX_HANDLER_ANOTHER = 1, - RX_HANDLER_EXACT = 2, - RX_HANDLER_PASS = 3, -}; - -typedef enum rx_handler_result rx_handler_result_t; - -typedef rx_handler_result_t rx_handler_func_t(struct sk_buff **); - -enum netdev_ml_priv_type { - ML_PRIV_NONE = 0, - ML_PRIV_CAN = 1, -}; - -struct pcpu_dstats; - -struct garp_port; - -struct mrp_port; - -struct netdev_tc_txq { - u16 count; - u16 offset; -}; - -struct macsec_ops; - -struct udp_tunnel_nic; - -struct bpf_xdp_link; - -struct bpf_xdp_entity { - struct bpf_prog *prog; - struct bpf_xdp_link *link; -}; - -struct netdev_name_node; - -struct dev_ifalias; - -struct net_device_ops; - -struct iw_handler_def; - -struct iw_public_data; - -struct ethtool_ops; - -struct l3mdev_ops; - -struct ndisc_ops; - -struct xfrmdev_ops; - -struct tlsdev_ops; - -struct header_ops; - -struct vlan_info; - -struct dsa_port; - -struct in_device; - -struct inet6_dev; - -struct wireless_dev; - -struct wpan_dev; - -struct netdev_rx_queue; - -struct mini_Qdisc; - -struct netdev_queue; - -struct cpu_rmap; - -struct Qdisc; - -struct xdp_dev_bulk_queue; - -struct xps_dev_maps; - -struct netpoll_info; - -struct pcpu_lstats; - -struct pcpu_sw_netstats; - -struct rtnl_link_ops; - -struct dcbnl_rtnl_ops; - -struct netprio_map; - -struct phy_device; - -struct sfp_bus; - -struct udp_tunnel_nic_info; - -struct net_device { - char name[16]; - struct netdev_name_node *name_node; - struct dev_ifalias *ifalias; - long unsigned int mem_end; - long unsigned int mem_start; - long unsigned int base_addr; - long unsigned int state; - struct list_head dev_list; - struct list_head napi_list; - struct list_head unreg_list; - struct list_head close_list; - struct list_head ptype_all; - struct list_head ptype_specific; - struct { - struct list_head upper; - struct list_head lower; - } adj_list; - unsigned int flags; - unsigned int priv_flags; - const struct net_device_ops *netdev_ops; - int ifindex; - short unsigned int gflags; - short unsigned int hard_header_len; - unsigned int mtu; - short unsigned int needed_headroom; - short unsigned int needed_tailroom; - netdev_features_t features; - netdev_features_t hw_features; - netdev_features_t wanted_features; - netdev_features_t vlan_features; - netdev_features_t hw_enc_features; - netdev_features_t mpls_features; - netdev_features_t gso_partial_features; - unsigned int min_mtu; - unsigned int max_mtu; - short unsigned int type; - unsigned char min_header_len; - unsigned char name_assign_type; - int group; - struct net_device_stats stats; - atomic_long_t rx_dropped; - atomic_long_t tx_dropped; - atomic_long_t rx_nohandler; - atomic_t carrier_up_count; - atomic_t carrier_down_count; - const struct iw_handler_def *wireless_handlers; - struct iw_public_data *wireless_data; - const struct ethtool_ops *ethtool_ops; - const struct l3mdev_ops *l3mdev_ops; - const struct ndisc_ops *ndisc_ops; - const struct xfrmdev_ops *xfrmdev_ops; - const struct tlsdev_ops *tlsdev_ops; - const struct header_ops *header_ops; - unsigned char operstate; - unsigned char link_mode; - unsigned char if_port; - unsigned char dma; - unsigned char perm_addr[32]; - unsigned char addr_assign_type; - unsigned char addr_len; - unsigned char upper_level; - unsigned char lower_level; - short unsigned int neigh_priv_len; - short unsigned int dev_id; - short unsigned int dev_port; - short unsigned int padded; - spinlock_t addr_list_lock; - int irq; - struct netdev_hw_addr_list uc; - struct netdev_hw_addr_list mc; - struct netdev_hw_addr_list dev_addrs; - struct kset *queues_kset; - unsigned int promiscuity; - unsigned int allmulti; - bool uc_promisc; - struct vlan_info *vlan_info; - struct dsa_port *dsa_ptr; - struct tipc_bearer *tipc_ptr; - void *atalk_ptr; - struct in_device *ip_ptr; - struct inet6_dev *ip6_ptr; - void *ax25_ptr; - struct wireless_dev *ieee80211_ptr; - struct wpan_dev *ieee802154_ptr; - struct mpls_dev *mpls_ptr; - unsigned char *dev_addr; - struct netdev_rx_queue *_rx; - unsigned int num_rx_queues; - unsigned int real_num_rx_queues; - struct bpf_prog *xdp_prog; - long unsigned int gro_flush_timeout; - int napi_defer_hard_irqs; - rx_handler_func_t *rx_handler; - void *rx_handler_data; - struct mini_Qdisc *miniq_ingress; - struct netdev_queue *ingress_queue; - struct nf_hook_entries *nf_hooks_ingress; - unsigned char broadcast[32]; - struct cpu_rmap *rx_cpu_rmap; - struct hlist_node index_hlist; - long: 64; - struct netdev_queue *_tx; - unsigned int num_tx_queues; - unsigned int real_num_tx_queues; - struct Qdisc *qdisc; - unsigned int tx_queue_len; - spinlock_t tx_global_lock; - struct xdp_dev_bulk_queue *xdp_bulkq; - struct xps_dev_maps *xps_maps[2]; - struct mini_Qdisc *miniq_egress; - struct hlist_head qdisc_hash[16]; - struct timer_list watchdog_timer; - int watchdog_timeo; - u32 proto_down_reason; - struct list_head todo_list; - int *pcpu_refcnt; - struct list_head link_watch_list; - enum { - NETREG_UNINITIALIZED = 0, - NETREG_REGISTERED = 1, - NETREG_UNREGISTERING = 2, - NETREG_UNREGISTERED = 3, - NETREG_RELEASED = 4, - NETREG_DUMMY = 5, - } reg_state: 8; - bool dismantle; - enum { - RTNL_LINK_INITIALIZED = 0, - RTNL_LINK_INITIALIZING = 1, - } rtnl_link_state: 16; - bool needs_free_netdev; - void (*priv_destructor)(struct net_device *); - struct netpoll_info *npinfo; - possible_net_t nd_net; - void *ml_priv; - enum netdev_ml_priv_type ml_priv_type; - union { - struct pcpu_lstats *lstats; - struct pcpu_sw_netstats *tstats; - struct pcpu_dstats *dstats; - }; - struct garp_port *garp_port; - struct mrp_port *mrp_port; - struct device dev; - const struct attribute_group *sysfs_groups[4]; - const struct attribute_group *sysfs_rx_queue_group; - const struct rtnl_link_ops *rtnl_link_ops; - unsigned int gso_max_size; - u16 gso_max_segs; - const struct dcbnl_rtnl_ops *dcbnl_ops; - s16 num_tc; - struct netdev_tc_txq tc_to_txq[16]; - u8 prio_tc_map[16]; - unsigned int fcoe_ddp_xid; - struct netprio_map *priomap; - struct phy_device *phydev; - struct sfp_bus *sfp_bus; - struct lock_class_key *qdisc_tx_busylock; - struct lock_class_key *qdisc_running_key; - bool proto_down; - unsigned int wol_enabled: 1; - unsigned int threaded: 1; - struct list_head net_notifier_list; - const struct macsec_ops *macsec_ops; - const struct udp_tunnel_nic_info *udp_tunnel_nic_info; - struct udp_tunnel_nic *udp_tunnel_nic; - struct bpf_xdp_entity xdp_state[3]; - long: 64; - long: 64; - long: 64; -}; - -enum bpf_reg_type { - NOT_INIT = 0, - SCALAR_VALUE = 1, - PTR_TO_CTX = 2, - CONST_PTR_TO_MAP = 3, - PTR_TO_MAP_VALUE = 4, - PTR_TO_MAP_VALUE_OR_NULL = 5, - PTR_TO_STACK = 6, - PTR_TO_PACKET_META = 7, - PTR_TO_PACKET = 8, - PTR_TO_PACKET_END = 9, - PTR_TO_FLOW_KEYS = 10, - PTR_TO_SOCKET = 11, - PTR_TO_SOCKET_OR_NULL = 12, - PTR_TO_SOCK_COMMON = 13, - PTR_TO_SOCK_COMMON_OR_NULL = 14, - PTR_TO_TCP_SOCK = 15, - PTR_TO_TCP_SOCK_OR_NULL = 16, - PTR_TO_TP_BUFFER = 17, - PTR_TO_XDP_SOCK = 18, - PTR_TO_BTF_ID = 19, - PTR_TO_BTF_ID_OR_NULL = 20, - PTR_TO_MEM = 21, - PTR_TO_MEM_OR_NULL = 22, - PTR_TO_RDONLY_BUF = 23, - PTR_TO_RDONLY_BUF_OR_NULL = 24, - PTR_TO_RDWR_BUF = 25, - PTR_TO_RDWR_BUF_OR_NULL = 26, - PTR_TO_PERCPU_BTF_ID = 27, - PTR_TO_FUNC = 28, - PTR_TO_MAP_KEY = 29, - __BPF_REG_TYPE_MAX = 30, -}; - -struct bpf_prog_ops { - int (*test_run)(struct bpf_prog *, const union bpf_attr *, union bpf_attr *); -}; - -struct bpf_offload_dev; - -struct bpf_prog_offload { - struct bpf_prog *prog; - struct net_device *netdev; - struct bpf_offload_dev *offdev; - void *dev_priv; - struct list_head offloads; - bool dev_state; - bool opt_failed; - void *jited_image; - u32 jited_len; -}; - -struct btf_func_model { - u8 ret_size; - u8 nr_args; - u8 arg_size[12]; -}; - -struct bpf_tramp_image { - void *image; - struct bpf_ksym ksym; - struct percpu_ref pcref; - void *ip_after_call; - void *ip_epilogue; - union { - struct callback_head rcu; - struct work_struct work; - }; -}; - -struct bpf_trampoline { - struct hlist_node hlist; - struct mutex mutex; - refcount_t refcnt; - u64 key; - struct { - struct btf_func_model model; - void *addr; - bool ftrace_managed; - } func; - struct bpf_prog *extension_prog; - struct hlist_head progs_hlist[3]; - int progs_cnt[3]; - struct bpf_tramp_image *cur_image; - u64 selector; - struct module *mod; -}; - -struct bpf_func_info_aux { - u16 linkage; - bool unreliable; -}; - -struct bpf_jit_poke_descriptor { - void *tailcall_target; - void *tailcall_bypass; - void *bypass_addr; - void *aux; - union { - struct { - struct bpf_map *map; - u32 key; - } tail_call; - }; - bool tailcall_target_stable; - u8 adj_off; - u16 reason; - u32 insn_idx; -}; - -struct bpf_ctx_arg_aux { - u32 offset; - enum bpf_reg_type reg_type; - u32 btf_id; -}; - -struct btf_mod_pair { - struct btf *btf; - struct module *module; -}; - -typedef unsigned int sk_buff_data_t; - -struct skb_ext; - -struct sk_buff { - union { - struct { - struct sk_buff *next; - struct sk_buff *prev; - union { - struct net_device *dev; - long unsigned int dev_scratch; - }; - }; - struct rb_node rbnode; - struct list_head list; - }; - union { - struct sock *sk; - int ip_defrag_offset; - }; - union { - ktime_t tstamp; - u64 skb_mstamp_ns; - }; - char cb[48]; - union { - struct { - long unsigned int _skb_refdst; - void (*destructor)(struct sk_buff *); - }; - struct list_head tcp_tsorted_anchor; - long unsigned int _sk_redir; - }; - long unsigned int _nfct; - unsigned int len; - unsigned int data_len; - __u16 mac_len; - __u16 hdr_len; - __u16 queue_mapping; - __u8 __cloned_offset[0]; - __u8 cloned: 1; - __u8 nohdr: 1; - __u8 fclone: 2; - __u8 peeked: 1; - __u8 head_frag: 1; - __u8 pfmemalloc: 1; - __u8 pp_recycle: 1; - __u8 active_extensions; - __u32 headers_start[0]; - __u8 __pkt_type_offset[0]; - __u8 pkt_type: 3; - __u8 ignore_df: 1; - __u8 nf_trace: 1; - __u8 ip_summed: 2; - __u8 ooo_okay: 1; - __u8 l4_hash: 1; - __u8 sw_hash: 1; - __u8 wifi_acked_valid: 1; - __u8 wifi_acked: 1; - __u8 no_fcs: 1; - __u8 encapsulation: 1; - __u8 encap_hdr_csum: 1; - __u8 csum_valid: 1; - __u8 __pkt_vlan_present_offset[0]; - __u8 vlan_present: 1; - __u8 csum_complete_sw: 1; - __u8 csum_level: 2; - __u8 csum_not_inet: 1; - __u8 dst_pending_confirm: 1; - __u8 ndisc_nodetype: 2; - __u8 ipvs_property: 1; - __u8 inner_protocol_type: 1; - __u8 remcsum_offload: 1; - __u8 offload_fwd_mark: 1; - __u8 offload_l3_fwd_mark: 1; - __u8 tc_skip_classify: 1; - __u8 tc_at_ingress: 1; - __u8 redirected: 1; - __u8 from_ingress: 1; - __u8 decrypted: 1; - __u16 tc_index; - union { - __wsum csum; - struct { - __u16 csum_start; - __u16 csum_offset; - }; - }; - __u32 priority; - int skb_iif; - __u32 hash; - __be16 vlan_proto; - __u16 vlan_tci; - union { - unsigned int napi_id; - unsigned int sender_cpu; - }; - __u32 secmark; - union { - __u32 mark; - __u32 reserved_tailroom; - }; - union { - __be16 inner_protocol; - __u8 inner_ipproto; - }; - __u16 inner_transport_header; - __u16 inner_network_header; - __u16 inner_mac_header; - __be16 protocol; - __u16 transport_header; - __u16 network_header; - __u16 mac_header; - __u32 headers_end[0]; - sk_buff_data_t tail; - sk_buff_data_t end; - unsigned char *head; - unsigned char *data; - unsigned int truesize; - refcount_t users; - struct skb_ext *extensions; -}; - -struct scatterlist { - long unsigned int page_link; - unsigned int offset; - unsigned int length; - dma_addr_t dma_address; - unsigned int dma_length; -}; - -enum { - Root_NFS = 255, - Root_CIFS = 254, - Root_RAM0 = 1048576, - Root_RAM1 = 1048577, - Root_FD0 = 2097152, - Root_HDA1 = 3145729, - Root_HDA2 = 3145730, - Root_SDA1 = 8388609, - Root_SDA2 = 8388610, - Root_HDC1 = 23068673, - Root_SR0 = 11534336, -}; - -struct flowi_tunnel { - __be64 tun_id; -}; - -struct flowi_common { - int flowic_oif; - int flowic_iif; - __u32 flowic_mark; - __u8 flowic_tos; - __u8 flowic_scope; - __u8 flowic_proto; - __u8 flowic_flags; - __u32 flowic_secid; - kuid_t flowic_uid; - struct flowi_tunnel flowic_tun_key; - __u32 flowic_multipath_hash; -}; - -union flowi_uli { - struct { - __be16 dport; - __be16 sport; - } ports; - struct { - __u8 type; - __u8 code; - } icmpt; - struct { - __le16 dport; - __le16 sport; - } dnports; - __be32 gre_key; - struct { - __u8 type; - } mht; -}; - -struct flowi4 { - struct flowi_common __fl_common; - __be32 saddr; - __be32 daddr; - union flowi_uli uli; -}; - -struct flowi6 { - struct flowi_common __fl_common; - struct in6_addr daddr; - struct in6_addr saddr; - __be32 flowlabel; - union flowi_uli uli; - __u32 mp_hash; -}; - -struct flowidn { - struct flowi_common __fl_common; - __le16 daddr; - __le16 saddr; - union flowi_uli uli; -}; - -struct flowi { - union { - struct flowi_common __fl_common; - struct flowi4 ip4; - struct flowi6 ip6; - struct flowidn dn; - } u; -}; - -struct ipstats_mib { - u64 mibs[37]; - struct u64_stats_sync syncp; -}; - -struct icmp_mib { - long unsigned int mibs[28]; -}; - -struct icmpmsg_mib { - atomic_long_t mibs[512]; -}; - -struct icmpv6_mib { - long unsigned int mibs[6]; -}; - -struct icmpv6_mib_device { - atomic_long_t mibs[6]; -}; - -struct icmpv6msg_mib { - atomic_long_t mibs[512]; -}; - -struct icmpv6msg_mib_device { - atomic_long_t mibs[512]; -}; - -struct tcp_mib { - long unsigned int mibs[16]; -}; - -struct udp_mib { - long unsigned int mibs[10]; -}; - -struct linux_mib { - long unsigned int mibs[126]; -}; - -struct linux_xfrm_mib { - long unsigned int mibs[29]; -}; - -struct linux_tls_mib { - long unsigned int mibs[11]; -}; - -struct inet_frags; - -struct fqdir { - long int high_thresh; - long int low_thresh; - int timeout; - int max_dist; - struct inet_frags *f; - struct net *net; - bool dead; - long: 56; - long: 64; - long: 64; - struct rhashtable rhashtable; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - atomic_long_t mem; - struct work_struct destroy_work; - struct llist_node free_list; - long: 64; - long: 64; -}; - -struct inet_frag_queue; - -struct inet_frags { - unsigned int qsize; - void (*constructor)(struct inet_frag_queue *, const void *); - void (*destructor)(struct inet_frag_queue *); - void (*frag_expire)(struct timer_list *); - struct kmem_cache *frags_cachep; - const char *frags_cache_name; - struct rhashtable_params rhash_params; - refcount_t refcnt; - struct completion completion; -}; - -struct frag_v4_compare_key { - __be32 saddr; - __be32 daddr; - u32 user; - u32 vif; - __be16 id; - u16 protocol; -}; - -struct frag_v6_compare_key { - struct in6_addr saddr; - struct in6_addr daddr; - u32 user; - __be32 id; - u32 iif; -}; - -struct inet_frag_queue { - struct rhash_head node; - union { - struct frag_v4_compare_key v4; - struct frag_v6_compare_key v6; - } key; - struct timer_list timer; - spinlock_t lock; - refcount_t refcnt; - struct rb_root rb_fragments; - struct sk_buff *fragments_tail; - struct sk_buff *last_run_head; - ktime_t stamp; - int len; - int meat; - __u8 flags; - u16 max_size; - struct fqdir *fqdir; - struct callback_head rcu; -}; - -struct fib_rule; - -struct fib_lookup_arg; - -struct fib_rule_hdr; - -struct nlattr; - -struct netlink_ext_ack; - -struct nla_policy; - -struct fib_rules_ops { - int family; - struct list_head list; - int rule_size; - int addr_size; - int unresolved_rules; - int nr_goto_rules; - unsigned int fib_rules_seq; - int (*action)(struct fib_rule *, struct flowi *, int, struct fib_lookup_arg *); - bool (*suppress)(struct fib_rule *, struct fib_lookup_arg *); - int (*match)(struct fib_rule *, struct flowi *, int); - int (*configure)(struct fib_rule *, struct sk_buff *, struct fib_rule_hdr *, struct nlattr **, struct netlink_ext_ack *); - int (*delete)(struct fib_rule *); - int (*compare)(struct fib_rule *, struct fib_rule_hdr *, struct nlattr **); - int (*fill)(struct fib_rule *, struct sk_buff *, struct fib_rule_hdr *); - size_t (*nlmsg_payload)(struct fib_rule *); - void (*flush_cache)(struct fib_rules_ops *); - int nlgroup; - const struct nla_policy *policy; - struct list_head rules_list; - struct module *owner; - struct net *fro_net; - struct callback_head rcu; -}; - -enum tcp_ca_event { - CA_EVENT_TX_START = 0, - CA_EVENT_CWND_RESTART = 1, - CA_EVENT_COMPLETE_CWR = 2, - CA_EVENT_LOSS = 3, - CA_EVENT_ECN_NO_CE = 4, - CA_EVENT_ECN_IS_CE = 5, -}; - -struct ack_sample; - -struct rate_sample; - -union tcp_cc_info; - -struct tcp_congestion_ops { - u32 (*ssthresh)(struct sock *); - void (*cong_avoid)(struct sock *, u32, u32); - void (*set_state)(struct sock *, u8); - void (*cwnd_event)(struct sock *, enum tcp_ca_event); - void (*in_ack_event)(struct sock *, u32); - void (*pkts_acked)(struct sock *, const struct ack_sample *); - u32 (*min_tso_segs)(struct sock *); - void (*cong_control)(struct sock *, const struct rate_sample *); - u32 (*undo_cwnd)(struct sock *); - u32 (*sndbuf_expand)(struct sock *); - size_t (*get_info)(struct sock *, u32, int *, union tcp_cc_info *); - char name[16]; - struct module *owner; - struct list_head list; - u32 key; - u32 flags; - void (*init)(struct sock *); - void (*release)(struct sock *); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct fib_notifier_ops { - int family; - struct list_head list; - unsigned int (*fib_seq_read)(struct net *); - int (*fib_dump)(struct net *, struct notifier_block *, struct netlink_ext_ack *); - struct module *owner; - struct callback_head rcu; -}; - -struct xfrm_state; - -struct lwtunnel_state; - -struct dst_entry { - struct net_device *dev; - struct dst_ops *ops; - long unsigned int _metrics; - long unsigned int expires; - struct xfrm_state *xfrm; - int (*input)(struct sk_buff *); - int (*output)(struct net *, struct sock *, struct sk_buff *); - short unsigned int flags; - short int obsolete; - short unsigned int header_len; - short unsigned int trailer_len; - atomic_t __refcnt; - int __use; - long unsigned int lastuse; - struct lwtunnel_state *lwtstate; - struct callback_head callback_head; - short int error; - short int __pad; - __u32 tclassid; -}; - -struct hh_cache { - unsigned int hh_len; - seqlock_t hh_lock; - long unsigned int hh_data[16]; -}; - -struct neigh_table; - -struct neigh_parms; - -struct neigh_ops; - -struct neighbour { - struct neighbour *next; - struct neigh_table *tbl; - struct neigh_parms *parms; - long unsigned int confirmed; - long unsigned int updated; - rwlock_t lock; - refcount_t refcnt; - unsigned int arp_queue_len_bytes; - struct sk_buff_head arp_queue; - struct timer_list timer; - long unsigned int used; - atomic_t probes; - __u8 flags; - __u8 nud_state; - __u8 type; - __u8 dead; - u8 protocol; - seqlock_t ha_lock; - int: 32; - unsigned char ha[32]; - struct hh_cache hh; - int (*output)(struct neighbour *, struct sk_buff *); - const struct neigh_ops *ops; - struct list_head gc_list; - struct callback_head rcu; - struct net_device *dev; - u8 primary_key[0]; -}; - -struct ipv6_stable_secret { - bool initialized; - struct in6_addr secret; -}; - -struct ipv6_devconf { - __s32 forwarding; - __s32 hop_limit; - __s32 mtu6; - __s32 accept_ra; - __s32 accept_redirects; - __s32 autoconf; - __s32 dad_transmits; - __s32 rtr_solicits; - __s32 rtr_solicit_interval; - __s32 rtr_solicit_max_interval; - __s32 rtr_solicit_delay; - __s32 force_mld_version; - __s32 mldv1_unsolicited_report_interval; - __s32 mldv2_unsolicited_report_interval; - __s32 use_tempaddr; - __s32 temp_valid_lft; - __s32 temp_prefered_lft; - __s32 regen_max_retry; - __s32 max_desync_factor; - __s32 max_addresses; - __s32 accept_ra_defrtr; - __u32 ra_defrtr_metric; - __s32 accept_ra_min_hop_limit; - __s32 accept_ra_pinfo; - __s32 ignore_routes_with_linkdown; - __s32 accept_ra_rtr_pref; - __s32 rtr_probe_interval; - __s32 accept_ra_rt_info_min_plen; - __s32 accept_ra_rt_info_max_plen; - __s32 proxy_ndp; - __s32 accept_source_route; - __s32 accept_ra_from_local; - __s32 optimistic_dad; - __s32 use_optimistic; - __s32 mc_forwarding; - __s32 disable_ipv6; - __s32 drop_unicast_in_l2_multicast; - __s32 accept_dad; - __s32 force_tllao; - __s32 ndisc_notify; - __s32 suppress_frag_ndisc; - __s32 accept_ra_mtu; - __s32 drop_unsolicited_na; - struct ipv6_stable_secret stable_secret; - __s32 use_oif_addrs_only; - __s32 keep_addr_on_down; - __s32 seg6_enabled; - __s32 seg6_require_hmac; - __u32 enhanced_dad; - __u32 addr_gen_mode; - __s32 disable_policy; - __s32 ndisc_tclass; - __s32 rpl_seg_enabled; - struct ctl_table_header *sysctl_header; -}; - -struct nf_queue_entry; - -struct nf_queue_handler { - int (*outfn)(struct nf_queue_entry *, unsigned int); - void (*nf_hook_drop)(struct net *); -}; - -enum nf_log_type { - NF_LOG_TYPE_LOG = 0, - NF_LOG_TYPE_ULOG = 1, - NF_LOG_TYPE_MAX = 2, -}; - -typedef u8 u_int8_t; - -struct nf_loginfo; - -typedef void nf_logfn(struct net *, u_int8_t, unsigned int, const struct sk_buff *, const struct net_device *, const struct net_device *, const struct nf_loginfo *, const char *); - -struct nf_logger { - char *name; - enum nf_log_type type; - nf_logfn *logfn; - struct module *me; -}; - -struct hlist_nulls_head { - struct hlist_nulls_node *first; -}; - -struct ip_conntrack_stat { - unsigned int found; - unsigned int invalid; - unsigned int insert; - unsigned int insert_failed; - unsigned int clash_resolve; - unsigned int drop; - unsigned int early_drop; - unsigned int error; - unsigned int expect_new; - unsigned int expect_create; - unsigned int expect_delete; - unsigned int search_restart; -}; - -struct ct_pcpu { - spinlock_t lock; - struct hlist_nulls_head unconfirmed; - struct hlist_nulls_head dying; -}; - -typedef enum { - SS_FREE = 0, - SS_UNCONNECTED = 1, - SS_CONNECTING = 2, - SS_CONNECTED = 3, - SS_DISCONNECTING = 4, -} socket_state; - -struct socket_wq { - wait_queue_head_t wait; - struct fasync_struct *fasync_list; - long unsigned int flags; - struct callback_head rcu; - long: 64; -}; - -struct proto_ops; - -struct socket { - socket_state state; - short int type; - long unsigned int flags; - struct file *file; - struct sock *sk; - const struct proto_ops *ops; - long: 64; - long: 64; - long: 64; - struct socket_wq wq; -}; - -typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, unsigned int, size_t); - -struct proto_ops { - int family; - struct module *owner; - int (*release)(struct socket *); - int (*bind)(struct socket *, struct sockaddr *, int); - int (*connect)(struct socket *, struct sockaddr *, int, int); - int (*socketpair)(struct socket *, struct socket *); - int (*accept)(struct socket *, struct socket *, int, bool); - int (*getname)(struct socket *, struct sockaddr *, int); - __poll_t (*poll)(struct file *, struct socket *, struct poll_table_struct *); - int (*ioctl)(struct socket *, unsigned int, long unsigned int); - int (*compat_ioctl)(struct socket *, unsigned int, long unsigned int); - int (*gettstamp)(struct socket *, void *, bool, bool); - int (*listen)(struct socket *, int); - int (*shutdown)(struct socket *, int); - int (*setsockopt)(struct socket *, int, int, sockptr_t, unsigned int); - int (*getsockopt)(struct socket *, int, int, char *, int *); - void (*show_fdinfo)(struct seq_file *, struct socket *); - int (*sendmsg)(struct socket *, struct msghdr *, size_t); - int (*recvmsg)(struct socket *, struct msghdr *, size_t, int); - int (*mmap)(struct file *, struct socket *, struct vm_area_struct *); - ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); - ssize_t (*splice_read)(struct socket *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); - int (*set_peek_off)(struct sock *, int); - int (*peek_len)(struct socket *); - int (*read_sock)(struct sock *, read_descriptor_t *, sk_read_actor_t); - int (*sendpage_locked)(struct sock *, struct page *, int, size_t, int); - int (*sendmsg_locked)(struct sock *, struct msghdr *, size_t); - int (*set_rcvlowat)(struct sock *, int); -}; - -struct pipe_buf_operations; - -struct pipe_buffer { - struct page *page; - unsigned int offset; - unsigned int len; - const struct pipe_buf_operations *ops; - unsigned int flags; - long unsigned int private; -}; - -struct pipe_buf_operations { - int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *); - void (*release)(struct pipe_inode_info *, struct pipe_buffer *); - bool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *); - bool (*get)(struct pipe_inode_info *, struct pipe_buffer *); -}; - -struct skb_ext { - refcount_t refcnt; - u8 offset[4]; - u8 chunks; - long: 56; - char data[0]; -}; - -struct dql { - unsigned int num_queued; - unsigned int adj_limit; - unsigned int last_obj_cnt; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - unsigned int limit; - unsigned int num_completed; - unsigned int prev_ovlimit; - unsigned int prev_num_queued; - unsigned int prev_last_obj_cnt; - unsigned int lowest_slack; - long unsigned int slack_start_time; - unsigned int max_limit; - unsigned int min_limit; - unsigned int slack_hold_time; - long: 32; - long: 64; - long: 64; -}; - -struct ieee_ets { - __u8 willing; - __u8 ets_cap; - __u8 cbs; - __u8 tc_tx_bw[8]; - __u8 tc_rx_bw[8]; - __u8 tc_tsa[8]; - __u8 prio_tc[8]; - __u8 tc_reco_bw[8]; - __u8 tc_reco_tsa[8]; - __u8 reco_prio_tc[8]; -}; - -struct ieee_maxrate { - __u64 tc_maxrate[8]; -}; - -struct ieee_qcn { - __u8 rpg_enable[8]; - __u32 rppp_max_rps[8]; - __u32 rpg_time_reset[8]; - __u32 rpg_byte_reset[8]; - __u32 rpg_threshold[8]; - __u32 rpg_max_rate[8]; - __u32 rpg_ai_rate[8]; - __u32 rpg_hai_rate[8]; - __u32 rpg_gd[8]; - __u32 rpg_min_dec_fac[8]; - __u32 rpg_min_rate[8]; - __u32 cndd_state_machine[8]; -}; - -struct ieee_qcn_stats { - __u64 rppp_rp_centiseconds[8]; - __u32 rppp_created_rps[8]; -}; - -struct ieee_pfc { - __u8 pfc_cap; - __u8 pfc_en; - __u8 mbc; - __u16 delay; - __u64 requests[8]; - __u64 indications[8]; -}; - -struct dcbnl_buffer { - __u8 prio2buffer[8]; - __u32 buffer_size[8]; - __u32 total_size; -}; - -struct cee_pg { - __u8 willing; - __u8 error; - __u8 pg_en; - __u8 tcs_supported; - __u8 pg_bw[8]; - __u8 prio_pg[8]; -}; - -struct cee_pfc { - __u8 willing; - __u8 error; - __u8 pfc_en; - __u8 tcs_supported; -}; - -struct dcb_app { - __u8 selector; - __u8 priority; - __u16 protocol; -}; - -struct dcb_peer_app_info { - __u8 willing; - __u8 error; -}; - -struct dcbnl_rtnl_ops { - int (*ieee_getets)(struct net_device *, struct ieee_ets *); - int (*ieee_setets)(struct net_device *, struct ieee_ets *); - int (*ieee_getmaxrate)(struct net_device *, struct ieee_maxrate *); - int (*ieee_setmaxrate)(struct net_device *, struct ieee_maxrate *); - int (*ieee_getqcn)(struct net_device *, struct ieee_qcn *); - int (*ieee_setqcn)(struct net_device *, struct ieee_qcn *); - int (*ieee_getqcnstats)(struct net_device *, struct ieee_qcn_stats *); - int (*ieee_getpfc)(struct net_device *, struct ieee_pfc *); - int (*ieee_setpfc)(struct net_device *, struct ieee_pfc *); - int (*ieee_getapp)(struct net_device *, struct dcb_app *); - int (*ieee_setapp)(struct net_device *, struct dcb_app *); - int (*ieee_delapp)(struct net_device *, struct dcb_app *); - int (*ieee_peer_getets)(struct net_device *, struct ieee_ets *); - int (*ieee_peer_getpfc)(struct net_device *, struct ieee_pfc *); - u8 (*getstate)(struct net_device *); - u8 (*setstate)(struct net_device *, u8); - void (*getpermhwaddr)(struct net_device *, u8 *); - void (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8); - void (*setpgbwgcfgtx)(struct net_device *, int, u8); - void (*setpgtccfgrx)(struct net_device *, int, u8, u8, u8, u8); - void (*setpgbwgcfgrx)(struct net_device *, int, u8); - void (*getpgtccfgtx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); - void (*getpgbwgcfgtx)(struct net_device *, int, u8 *); - void (*getpgtccfgrx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); - void (*getpgbwgcfgrx)(struct net_device *, int, u8 *); - void (*setpfccfg)(struct net_device *, int, u8); - void (*getpfccfg)(struct net_device *, int, u8 *); - u8 (*setall)(struct net_device *); - u8 (*getcap)(struct net_device *, int, u8 *); - int (*getnumtcs)(struct net_device *, int, u8 *); - int (*setnumtcs)(struct net_device *, int, u8); - u8 (*getpfcstate)(struct net_device *); - void (*setpfcstate)(struct net_device *, u8); - void (*getbcncfg)(struct net_device *, int, u32 *); - void (*setbcncfg)(struct net_device *, int, u32); - void (*getbcnrp)(struct net_device *, int, u8 *); - void (*setbcnrp)(struct net_device *, int, u8); - int (*setapp)(struct net_device *, u8, u16, u8); - int (*getapp)(struct net_device *, u8, u16); - u8 (*getfeatcfg)(struct net_device *, int, u8 *); - u8 (*setfeatcfg)(struct net_device *, int, u8); - u8 (*getdcbx)(struct net_device *); - u8 (*setdcbx)(struct net_device *, u8); - int (*peer_getappinfo)(struct net_device *, struct dcb_peer_app_info *, u16 *); - int (*peer_getapptable)(struct net_device *, struct dcb_app *); - int (*cee_peer_getpg)(struct net_device *, struct cee_pg *); - int (*cee_peer_getpfc)(struct net_device *, struct cee_pfc *); - int (*dcbnl_getbuffer)(struct net_device *, struct dcbnl_buffer *); - int (*dcbnl_setbuffer)(struct net_device *, struct dcbnl_buffer *); -}; - -struct netprio_map { - struct callback_head rcu; - u32 priomap_len; - u32 priomap[0]; -}; - -struct xdp_mem_info { - u32 type; - u32 id; -}; - -struct xdp_rxq_info { - struct net_device *dev; - u32 queue_index; - u32 reg_state; - struct xdp_mem_info mem; - unsigned int napi_id; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct xdp_frame { - void *data; - u16 len; - u16 headroom; - u32 metasize: 8; - u32 frame_sz: 24; - struct xdp_mem_info mem; - struct net_device *dev_rx; -}; - -struct nlmsghdr { - __u32 nlmsg_len; - __u16 nlmsg_type; - __u16 nlmsg_flags; - __u32 nlmsg_seq; - __u32 nlmsg_pid; -}; - -struct nlattr { - __u16 nla_len; - __u16 nla_type; -}; - -struct netlink_ext_ack { - const char *_msg; - const struct nlattr *bad_attr; - const struct nla_policy *policy; - u8 cookie[20]; - u8 cookie_len; -}; - -struct netlink_range_validation; - -struct netlink_range_validation_signed; - -struct nla_policy { - u8 type; - u8 validation_type; - u16 len; - union { - const u32 bitfield32_valid; - const u32 mask; - const char *reject_message; - const struct nla_policy *nested_policy; - struct netlink_range_validation *range; - struct netlink_range_validation_signed *range_signed; - struct { - s16 min; - s16 max; - }; - int (*validate)(const struct nlattr *, struct netlink_ext_ack *); - u16 strict_start_type; - }; -}; - -struct netlink_callback { - struct sk_buff *skb; - const struct nlmsghdr *nlh; - int (*dump)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - void *data; - struct module *module; - struct netlink_ext_ack *extack; - u16 family; - u16 answer_flags; - u32 min_dump_alloc; - unsigned int prev_seq; - unsigned int seq; - bool strict_check; - union { - u8 ctx[48]; - long int args[6]; - }; -}; - -struct ndmsg { - __u8 ndm_family; - __u8 ndm_pad1; - __u16 ndm_pad2; - __s32 ndm_ifindex; - __u16 ndm_state; - __u8 ndm_flags; - __u8 ndm_type; -}; - -struct rtnl_link_stats64 { - __u64 rx_packets; - __u64 tx_packets; - __u64 rx_bytes; - __u64 tx_bytes; - __u64 rx_errors; - __u64 tx_errors; - __u64 rx_dropped; - __u64 tx_dropped; - __u64 multicast; - __u64 collisions; - __u64 rx_length_errors; - __u64 rx_over_errors; - __u64 rx_crc_errors; - __u64 rx_frame_errors; - __u64 rx_fifo_errors; - __u64 rx_missed_errors; - __u64 tx_aborted_errors; - __u64 tx_carrier_errors; - __u64 tx_fifo_errors; - __u64 tx_heartbeat_errors; - __u64 tx_window_errors; - __u64 rx_compressed; - __u64 tx_compressed; - __u64 rx_nohandler; -}; - -struct ifla_vf_guid { - __u32 vf; - __u64 guid; -}; - -struct ifla_vf_stats { - __u64 rx_packets; - __u64 tx_packets; - __u64 rx_bytes; - __u64 tx_bytes; - __u64 broadcast; - __u64 multicast; - __u64 rx_dropped; - __u64 tx_dropped; -}; - -struct ifla_vf_info { - __u32 vf; - __u8 mac[32]; - __u32 vlan; - __u32 qos; - __u32 spoofchk; - __u32 linkstate; - __u32 min_tx_rate; - __u32 max_tx_rate; - __u32 rss_query_en; - __u32 trusted; - __be16 vlan_proto; -}; - -struct tc_stats { - __u64 bytes; - __u32 packets; - __u32 drops; - __u32 overlimits; - __u32 bps; - __u32 pps; - __u32 qlen; - __u32 backlog; -}; - -struct tc_sizespec { - unsigned char cell_log; - unsigned char size_log; - short int cell_align; - int overhead; - unsigned int linklayer; - unsigned int mpu; - unsigned int mtu; - unsigned int tsize; -}; - -enum netdev_tx { - __NETDEV_TX_MIN = 2147483648, - NETDEV_TX_OK = 0, - NETDEV_TX_BUSY = 16, -}; - -typedef enum netdev_tx netdev_tx_t; - -struct header_ops { - int (*create)(struct sk_buff *, struct net_device *, short unsigned int, const void *, const void *, unsigned int); - int (*parse)(const struct sk_buff *, unsigned char *); - int (*cache)(const struct neighbour *, struct hh_cache *, __be16); - void (*cache_update)(struct hh_cache *, const struct net_device *, const unsigned char *); - bool (*validate)(const char *, unsigned int); - __be16 (*parse_protocol)(const struct sk_buff *); -}; - -struct xsk_buff_pool; - -struct netdev_queue { - struct net_device *dev; - struct Qdisc *qdisc; - struct Qdisc *qdisc_sleeping; - struct kobject kobj; - int numa_node; - long unsigned int tx_maxrate; - long unsigned int trans_timeout; - struct net_device *sb_dev; - struct xsk_buff_pool *pool; - spinlock_t _xmit_lock; - int xmit_lock_owner; - long unsigned int trans_start; - long unsigned int state; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct dql dql; -}; - -struct net_rate_estimator; - -struct qdisc_skb_head { - struct sk_buff *head; - struct sk_buff *tail; - __u32 qlen; - spinlock_t lock; -}; - -struct gnet_stats_basic_packed { - __u64 bytes; - __u64 packets; -}; - -struct gnet_stats_queue { - __u32 qlen; - __u32 backlog; - __u32 drops; - __u32 requeues; - __u32 overlimits; -}; - -struct Qdisc_ops; - -struct qdisc_size_table; - -struct gnet_stats_basic_cpu; - -struct Qdisc { - int (*enqueue)(struct sk_buff *, struct Qdisc *, struct sk_buff **); - struct sk_buff * (*dequeue)(struct Qdisc *); - unsigned int flags; - u32 limit; - const struct Qdisc_ops *ops; - struct qdisc_size_table *stab; - struct hlist_node hash; - u32 handle; - u32 parent; - struct netdev_queue *dev_queue; - struct net_rate_estimator *rate_est; - struct gnet_stats_basic_cpu *cpu_bstats; - struct gnet_stats_queue *cpu_qstats; - int pad; - refcount_t refcnt; - long: 64; - long: 64; - long: 64; - struct sk_buff_head gso_skb; - struct qdisc_skb_head q; - struct gnet_stats_basic_packed bstats; - seqcount_t running; - struct gnet_stats_queue qstats; - long unsigned int state; - struct Qdisc *next_sched; - struct sk_buff_head skb_bad_txq; - spinlock_t busylock; - spinlock_t seqlock; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long int privdata[0]; -}; - -struct rps_map { - unsigned int len; - struct callback_head rcu; - u16 cpus[0]; -}; - -struct rps_dev_flow { - u16 cpu; - u16 filter; - unsigned int last_qtail; -}; - -struct rps_dev_flow_table { - unsigned int mask; - struct callback_head rcu; - struct rps_dev_flow flows[0]; -}; - -struct netdev_rx_queue { - struct rps_map *rps_map; - struct rps_dev_flow_table *rps_flow_table; - struct kobject kobj; - struct net_device *dev; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct xdp_rxq_info xdp_rxq; - struct xsk_buff_pool *pool; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct xps_map { - unsigned int len; - unsigned int alloc_len; - struct callback_head rcu; - u16 queues[0]; -}; - -struct xps_dev_maps { - struct callback_head rcu; - unsigned int nr_ids; - s16 num_tc; - struct xps_map *attr_map[0]; -}; - -struct netdev_fcoe_hbainfo { - char manufacturer[64]; - char serial_number[64]; - char hardware_version[64]; - char driver_version[64]; - char optionrom_version[64]; - char firmware_version[64]; - char model[256]; - char model_description[256]; -}; - -struct netdev_phys_item_id { - unsigned char id[32]; - unsigned char id_len; -}; - -enum net_device_path_type { - DEV_PATH_ETHERNET = 0, - DEV_PATH_VLAN = 1, - DEV_PATH_BRIDGE = 2, - DEV_PATH_PPPOE = 3, - DEV_PATH_DSA = 4, -}; - -struct net_device_path { - enum net_device_path_type type; - const struct net_device *dev; - union { - struct { - u16 id; - __be16 proto; - u8 h_dest[6]; - } encap; - struct { - enum { - DEV_PATH_BR_VLAN_KEEP = 0, - DEV_PATH_BR_VLAN_TAG = 1, - DEV_PATH_BR_VLAN_UNTAG = 2, - DEV_PATH_BR_VLAN_UNTAG_HW = 3, - } vlan_mode; - u16 vlan_id; - __be16 vlan_proto; - } bridge; - struct { - int port; - u16 proto; - } dsa; - }; -}; - -struct net_device_path_ctx { - const struct net_device *dev; - const u8 *daddr; - int num_vlans; - struct { - u16 id; - __be16 proto; - } vlan[2]; -}; - -enum tc_setup_type { - TC_SETUP_QDISC_MQPRIO = 0, - TC_SETUP_CLSU32 = 1, - TC_SETUP_CLSFLOWER = 2, - TC_SETUP_CLSMATCHALL = 3, - TC_SETUP_CLSBPF = 4, - TC_SETUP_BLOCK = 5, - TC_SETUP_QDISC_CBS = 6, - TC_SETUP_QDISC_RED = 7, - TC_SETUP_QDISC_PRIO = 8, - TC_SETUP_QDISC_MQ = 9, - TC_SETUP_QDISC_ETF = 10, - TC_SETUP_ROOT_QDISC = 11, - TC_SETUP_QDISC_GRED = 12, - TC_SETUP_QDISC_TAPRIO = 13, - TC_SETUP_FT = 14, - TC_SETUP_QDISC_ETS = 15, - TC_SETUP_QDISC_TBF = 16, - TC_SETUP_QDISC_FIFO = 17, - TC_SETUP_QDISC_HTB = 18, -}; - -enum bpf_netdev_command { - XDP_SETUP_PROG = 0, - XDP_SETUP_PROG_HW = 1, - BPF_OFFLOAD_MAP_ALLOC = 2, - BPF_OFFLOAD_MAP_FREE = 3, - XDP_SETUP_XSK_POOL = 4, -}; - -struct netdev_bpf { - enum bpf_netdev_command command; - union { - struct { - u32 flags; - struct bpf_prog *prog; - struct netlink_ext_ack *extack; - }; - struct { - struct bpf_offloaded_map *offmap; - }; - struct { - struct xsk_buff_pool *pool; - u16 queue_id; - } xsk; - }; -}; - -struct xfrmdev_ops { - int (*xdo_dev_state_add)(struct xfrm_state *); - void (*xdo_dev_state_delete)(struct xfrm_state *); - void (*xdo_dev_state_free)(struct xfrm_state *); - bool (*xdo_dev_offload_ok)(struct sk_buff *, struct xfrm_state *); - void (*xdo_dev_state_advance_esn)(struct xfrm_state *); -}; - -struct dev_ifalias { - struct callback_head rcuhead; - char ifalias[0]; -}; - -struct netdev_name_node { - struct hlist_node hlist; - struct list_head list; - struct net_device *dev; - const char *name; -}; - -struct devlink_port; - -struct ip_tunnel_parm; - -struct net_device_ops { - int (*ndo_init)(struct net_device *); - void (*ndo_uninit)(struct net_device *); - int (*ndo_open)(struct net_device *); - int (*ndo_stop)(struct net_device *); - netdev_tx_t (*ndo_start_xmit)(struct sk_buff *, struct net_device *); - netdev_features_t (*ndo_features_check)(struct sk_buff *, struct net_device *, netdev_features_t); - u16 (*ndo_select_queue)(struct net_device *, struct sk_buff *, struct net_device *); - void (*ndo_change_rx_flags)(struct net_device *, int); - void (*ndo_set_rx_mode)(struct net_device *); - int (*ndo_set_mac_address)(struct net_device *, void *); - int (*ndo_validate_addr)(struct net_device *); - int (*ndo_do_ioctl)(struct net_device *, struct ifreq *, int); - int (*ndo_set_config)(struct net_device *, struct ifmap *); - int (*ndo_change_mtu)(struct net_device *, int); - int (*ndo_neigh_setup)(struct net_device *, struct neigh_parms *); - void (*ndo_tx_timeout)(struct net_device *, unsigned int); - void (*ndo_get_stats64)(struct net_device *, struct rtnl_link_stats64 *); - bool (*ndo_has_offload_stats)(const struct net_device *, int); - int (*ndo_get_offload_stats)(int, const struct net_device *, void *); - struct net_device_stats * (*ndo_get_stats)(struct net_device *); - int (*ndo_vlan_rx_add_vid)(struct net_device *, __be16, u16); - int (*ndo_vlan_rx_kill_vid)(struct net_device *, __be16, u16); - void (*ndo_poll_controller)(struct net_device *); - int (*ndo_netpoll_setup)(struct net_device *, struct netpoll_info *); - void (*ndo_netpoll_cleanup)(struct net_device *); - int (*ndo_set_vf_mac)(struct net_device *, int, u8 *); - int (*ndo_set_vf_vlan)(struct net_device *, int, u16, u8, __be16); - int (*ndo_set_vf_rate)(struct net_device *, int, int, int); - int (*ndo_set_vf_spoofchk)(struct net_device *, int, bool); - int (*ndo_set_vf_trust)(struct net_device *, int, bool); - int (*ndo_get_vf_config)(struct net_device *, int, struct ifla_vf_info *); - int (*ndo_set_vf_link_state)(struct net_device *, int, int); - int (*ndo_get_vf_stats)(struct net_device *, int, struct ifla_vf_stats *); - int (*ndo_set_vf_port)(struct net_device *, int, struct nlattr **); - int (*ndo_get_vf_port)(struct net_device *, int, struct sk_buff *); - int (*ndo_get_vf_guid)(struct net_device *, int, struct ifla_vf_guid *, struct ifla_vf_guid *); - int (*ndo_set_vf_guid)(struct net_device *, int, u64, int); - int (*ndo_set_vf_rss_query_en)(struct net_device *, int, bool); - int (*ndo_setup_tc)(struct net_device *, enum tc_setup_type, void *); - int (*ndo_fcoe_enable)(struct net_device *); - int (*ndo_fcoe_disable)(struct net_device *); - int (*ndo_fcoe_ddp_setup)(struct net_device *, u16, struct scatterlist *, unsigned int); - int (*ndo_fcoe_ddp_done)(struct net_device *, u16); - int (*ndo_fcoe_ddp_target)(struct net_device *, u16, struct scatterlist *, unsigned int); - int (*ndo_fcoe_get_hbainfo)(struct net_device *, struct netdev_fcoe_hbainfo *); - int (*ndo_fcoe_get_wwn)(struct net_device *, u64 *, int); - int (*ndo_rx_flow_steer)(struct net_device *, const struct sk_buff *, u16, u32); - int (*ndo_add_slave)(struct net_device *, struct net_device *, struct netlink_ext_ack *); - int (*ndo_del_slave)(struct net_device *, struct net_device *); - struct net_device * (*ndo_get_xmit_slave)(struct net_device *, struct sk_buff *, bool); - struct net_device * (*ndo_sk_get_lower_dev)(struct net_device *, struct sock *); - netdev_features_t (*ndo_fix_features)(struct net_device *, netdev_features_t); - int (*ndo_set_features)(struct net_device *, netdev_features_t); - int (*ndo_neigh_construct)(struct net_device *, struct neighbour *); - void (*ndo_neigh_destroy)(struct net_device *, struct neighbour *); - int (*ndo_fdb_add)(struct ndmsg *, struct nlattr **, struct net_device *, const unsigned char *, u16, u16, struct netlink_ext_ack *); - int (*ndo_fdb_del)(struct ndmsg *, struct nlattr **, struct net_device *, const unsigned char *, u16); - int (*ndo_fdb_dump)(struct sk_buff *, struct netlink_callback *, struct net_device *, struct net_device *, int *); - int (*ndo_fdb_get)(struct sk_buff *, struct nlattr **, struct net_device *, const unsigned char *, u16, u32, u32, struct netlink_ext_ack *); - int (*ndo_bridge_setlink)(struct net_device *, struct nlmsghdr *, u16, struct netlink_ext_ack *); - int (*ndo_bridge_getlink)(struct sk_buff *, u32, u32, struct net_device *, u32, int); - int (*ndo_bridge_dellink)(struct net_device *, struct nlmsghdr *, u16); - int (*ndo_change_carrier)(struct net_device *, bool); - int (*ndo_get_phys_port_id)(struct net_device *, struct netdev_phys_item_id *); - int (*ndo_get_port_parent_id)(struct net_device *, struct netdev_phys_item_id *); - int (*ndo_get_phys_port_name)(struct net_device *, char *, size_t); - void * (*ndo_dfwd_add_station)(struct net_device *, struct net_device *); - void (*ndo_dfwd_del_station)(struct net_device *, void *); - int (*ndo_set_tx_maxrate)(struct net_device *, int, u32); - int (*ndo_get_iflink)(const struct net_device *); - int (*ndo_change_proto_down)(struct net_device *, bool); - int (*ndo_fill_metadata_dst)(struct net_device *, struct sk_buff *); - void (*ndo_set_rx_headroom)(struct net_device *, int); - int (*ndo_bpf)(struct net_device *, struct netdev_bpf *); - int (*ndo_xdp_xmit)(struct net_device *, int, struct xdp_frame **, u32); - int (*ndo_xsk_wakeup)(struct net_device *, u32, u32); - struct devlink_port * (*ndo_get_devlink_port)(struct net_device *); - int (*ndo_tunnel_ctl)(struct net_device *, struct ip_tunnel_parm *, int); - struct net_device * (*ndo_get_peer_dev)(struct net_device *); - int (*ndo_fill_forward_path)(struct net_device_path_ctx *, struct net_device_path *); -}; - -struct neigh_parms { - possible_net_t net; - struct net_device *dev; - struct list_head list; - int (*neigh_setup)(struct neighbour *); - struct neigh_table *tbl; - void *sysctl_table; - int dead; - refcount_t refcnt; - struct callback_head callback_head; - int reachable_time; - int data[13]; - long unsigned int data_state[1]; -}; - -struct pcpu_lstats { - u64_stats_t packets; - u64_stats_t bytes; - struct u64_stats_sync syncp; -}; - -struct pcpu_sw_netstats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; -}; - -struct iw_request_info; - -union iwreq_data; - -typedef int (*iw_handler)(struct net_device *, struct iw_request_info *, union iwreq_data *, char *); - -struct iw_priv_args; - -struct iw_statistics; - -struct iw_handler_def { - const iw_handler *standard; - __u16 num_standard; - __u16 num_private; - __u16 num_private_args; - const iw_handler *private; - const struct iw_priv_args *private_args; - struct iw_statistics * (*get_wireless_stats)(struct net_device *); -}; - -enum ethtool_phys_id_state { - ETHTOOL_ID_INACTIVE = 0, - ETHTOOL_ID_ACTIVE = 1, - ETHTOOL_ID_ON = 2, - ETHTOOL_ID_OFF = 3, -}; - -struct ethtool_drvinfo; - -struct ethtool_regs; - -struct ethtool_wolinfo; - -struct ethtool_link_ext_state_info; - -struct ethtool_eeprom; - -struct ethtool_coalesce; - -struct ethtool_ringparam; - -struct ethtool_pause_stats; - -struct ethtool_pauseparam; - -struct ethtool_test; - -struct ethtool_stats; - -struct ethtool_rxnfc; - -struct ethtool_flash; - -struct ethtool_channels; - -struct ethtool_dump; - -struct ethtool_ts_info; - -struct ethtool_modinfo; - -struct ethtool_eee; - -struct ethtool_tunable; - -struct ethtool_link_ksettings; - -struct ethtool_fec_stats; - -struct ethtool_fecparam; - -struct ethtool_module_eeprom; - -struct ethtool_eth_phy_stats; - -struct ethtool_eth_mac_stats; - -struct ethtool_eth_ctrl_stats; - -struct ethtool_rmon_stats; - -struct ethtool_rmon_hist_range; - -struct ethtool_ops { - u32 cap_link_lanes_supported: 1; - u32 supported_coalesce_params; - void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); - int (*get_regs_len)(struct net_device *); - void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); - void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); - int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); - u32 (*get_msglevel)(struct net_device *); - void (*set_msglevel)(struct net_device *, u32); - int (*nway_reset)(struct net_device *); - u32 (*get_link)(struct net_device *); - int (*get_link_ext_state)(struct net_device *, struct ethtool_link_ext_state_info *); - int (*get_eeprom_len)(struct net_device *); - int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); - int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); - int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); - int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); - void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *); - int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *); - void (*get_pause_stats)(struct net_device *, struct ethtool_pause_stats *); - void (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam *); - int (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam *); - void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); - void (*get_strings)(struct net_device *, u32, u8 *); - int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state); - void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); - int (*begin)(struct net_device *); - void (*complete)(struct net_device *); - u32 (*get_priv_flags)(struct net_device *); - int (*set_priv_flags)(struct net_device *, u32); - int (*get_sset_count)(struct net_device *, int); - int (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, u32 *); - int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); - int (*flash_device)(struct net_device *, struct ethtool_flash *); - int (*reset)(struct net_device *, u32 *); - u32 (*get_rxfh_key_size)(struct net_device *); - u32 (*get_rxfh_indir_size)(struct net_device *); - int (*get_rxfh)(struct net_device *, u32 *, u8 *, u8 *); - int (*set_rxfh)(struct net_device *, const u32 *, const u8 *, const u8); - int (*get_rxfh_context)(struct net_device *, u32 *, u8 *, u8 *, u32); - int (*set_rxfh_context)(struct net_device *, const u32 *, const u8 *, const u8, u32 *, bool); - void (*get_channels)(struct net_device *, struct ethtool_channels *); - int (*set_channels)(struct net_device *, struct ethtool_channels *); - int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); - int (*get_dump_data)(struct net_device *, struct ethtool_dump *, void *); - int (*set_dump)(struct net_device *, struct ethtool_dump *); - int (*get_ts_info)(struct net_device *, struct ethtool_ts_info *); - int (*get_module_info)(struct net_device *, struct ethtool_modinfo *); - int (*get_module_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); - int (*get_eee)(struct net_device *, struct ethtool_eee *); - int (*set_eee)(struct net_device *, struct ethtool_eee *); - int (*get_tunable)(struct net_device *, const struct ethtool_tunable *, void *); - int (*set_tunable)(struct net_device *, const struct ethtool_tunable *, const void *); - int (*get_per_queue_coalesce)(struct net_device *, u32, struct ethtool_coalesce *); - int (*set_per_queue_coalesce)(struct net_device *, u32, struct ethtool_coalesce *); - int (*get_link_ksettings)(struct net_device *, struct ethtool_link_ksettings *); - int (*set_link_ksettings)(struct net_device *, const struct ethtool_link_ksettings *); - void (*get_fec_stats)(struct net_device *, struct ethtool_fec_stats *); - int (*get_fecparam)(struct net_device *, struct ethtool_fecparam *); - int (*set_fecparam)(struct net_device *, struct ethtool_fecparam *); - void (*get_ethtool_phy_stats)(struct net_device *, struct ethtool_stats *, u64 *); - int (*get_phy_tunable)(struct net_device *, const struct ethtool_tunable *, void *); - int (*set_phy_tunable)(struct net_device *, const struct ethtool_tunable *, const void *); - int (*get_module_eeprom_by_page)(struct net_device *, const struct ethtool_module_eeprom *, struct netlink_ext_ack *); - void (*get_eth_phy_stats)(struct net_device *, struct ethtool_eth_phy_stats *); - void (*get_eth_mac_stats)(struct net_device *, struct ethtool_eth_mac_stats *); - void (*get_eth_ctrl_stats)(struct net_device *, struct ethtool_eth_ctrl_stats *); - void (*get_rmon_stats)(struct net_device *, struct ethtool_rmon_stats *, const struct ethtool_rmon_hist_range **); -}; - -struct l3mdev_ops { - u32 (*l3mdev_fib_table)(const struct net_device *); - struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *, struct sk_buff *, u16); - struct sk_buff * (*l3mdev_l3_out)(struct net_device *, struct sock *, struct sk_buff *, u16); - struct dst_entry * (*l3mdev_link_scope_lookup)(const struct net_device *, struct flowi6 *); -}; - -struct nd_opt_hdr; - -struct ndisc_options; - -struct prefix_info; - -struct ndisc_ops { - int (*is_useropt)(u8); - int (*parse_options)(const struct net_device *, struct nd_opt_hdr *, struct ndisc_options *); - void (*update)(const struct net_device *, struct neighbour *, u32, u8, const struct ndisc_options *); - int (*opt_addr_space)(const struct net_device *, u8, struct neighbour *, u8 *, u8 **); - void (*fill_addr_option)(const struct net_device *, struct sk_buff *, u8, const u8 *); - void (*prefix_rcv_add_addr)(struct net *, struct net_device *, const struct prefix_info *, struct inet6_dev *, struct in6_addr *, int, u32, bool, bool, __u32, u32, bool); -}; - -enum tls_offload_ctx_dir { - TLS_OFFLOAD_CTX_DIR_RX = 0, - TLS_OFFLOAD_CTX_DIR_TX = 1, -}; - -struct tls_crypto_info; - -struct tls_context; - -struct tlsdev_ops { - int (*tls_dev_add)(struct net_device *, struct sock *, enum tls_offload_ctx_dir, struct tls_crypto_info *, u32); - void (*tls_dev_del)(struct net_device *, struct tls_context *, enum tls_offload_ctx_dir); - int (*tls_dev_resync)(struct net_device *, struct sock *, u32, u8 *, enum tls_offload_ctx_dir); -}; - -struct ipv6_devstat { - struct proc_dir_entry *proc_dir_entry; - struct ipstats_mib *ipv6; - struct icmpv6_mib_device *icmpv6dev; - struct icmpv6msg_mib_device *icmpv6msgdev; -}; - -struct ifmcaddr6; - -struct ifacaddr6; - -struct inet6_dev { - struct net_device *dev; - struct list_head addr_list; - struct ifmcaddr6 *mc_list; - struct ifmcaddr6 *mc_tomb; - unsigned char mc_qrv; - unsigned char mc_gq_running; - unsigned char mc_ifc_count; - unsigned char mc_dad_count; - long unsigned int mc_v1_seen; - long unsigned int mc_qi; - long unsigned int mc_qri; - long unsigned int mc_maxdelay; - struct delayed_work mc_gq_work; - struct delayed_work mc_ifc_work; - struct delayed_work mc_dad_work; - struct delayed_work mc_query_work; - struct delayed_work mc_report_work; - struct sk_buff_head mc_query_queue; - struct sk_buff_head mc_report_queue; - spinlock_t mc_query_lock; - spinlock_t mc_report_lock; - struct mutex mc_lock; - struct ifacaddr6 *ac_list; - rwlock_t lock; - refcount_t refcnt; - __u32 if_flags; - int dead; - u32 desync_factor; - struct list_head tempaddr_list; - struct in6_addr token; - struct neigh_parms *nd_parms; - struct ipv6_devconf cnf; - struct ipv6_devstat stats; - struct timer_list rs_timer; - __s32 rs_interval; - __u8 rs_probes; - long unsigned int tstamp; - struct callback_head rcu; -}; - -struct tcf_proto; - -struct tcf_block; - -struct mini_Qdisc { - struct tcf_proto *filter_list; - struct tcf_block *block; - struct gnet_stats_basic_cpu *cpu_bstats; - struct gnet_stats_queue *cpu_qstats; - struct callback_head rcu; -}; - -struct rtnl_link_ops { - struct list_head list; - const char *kind; - size_t priv_size; - struct net_device * (*alloc)(struct nlattr **, const char *, unsigned char, unsigned int, unsigned int); - void (*setup)(struct net_device *); - bool netns_refund; - unsigned int maxtype; - const struct nla_policy *policy; - int (*validate)(struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - int (*newlink)(struct net *, struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - int (*changelink)(struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - void (*dellink)(struct net_device *, struct list_head *); - size_t (*get_size)(const struct net_device *); - int (*fill_info)(struct sk_buff *, const struct net_device *); - size_t (*get_xstats_size)(const struct net_device *); - int (*fill_xstats)(struct sk_buff *, const struct net_device *); - unsigned int (*get_num_tx_queues)(); - unsigned int (*get_num_rx_queues)(); - unsigned int slave_maxtype; - const struct nla_policy *slave_policy; - int (*slave_changelink)(struct net_device *, struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *); - size_t (*get_slave_size)(const struct net_device *, const struct net_device *); - int (*fill_slave_info)(struct sk_buff *, const struct net_device *, const struct net_device *); - struct net * (*get_link_net)(const struct net_device *); - size_t (*get_linkxstats_size)(const struct net_device *, int); - int (*fill_linkxstats)(struct sk_buff *, const struct net_device *, int *, int); -}; - -struct udp_tunnel_nic_table_info { - unsigned int n_entries; - unsigned int tunnel_types; -}; - -struct udp_tunnel_info; - -struct udp_tunnel_nic_shared; - -struct udp_tunnel_nic_info { - int (*set_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *); - int (*unset_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *); - int (*sync_table)(struct net_device *, unsigned int); - struct udp_tunnel_nic_shared *shared; - unsigned int flags; - struct udp_tunnel_nic_table_info tables[4]; -}; - -enum { - RTAX_UNSPEC = 0, - RTAX_LOCK = 1, - RTAX_MTU = 2, - RTAX_WINDOW = 3, - RTAX_RTT = 4, - RTAX_RTTVAR = 5, - RTAX_SSTHRESH = 6, - RTAX_CWND = 7, - RTAX_ADVMSS = 8, - RTAX_REORDERING = 9, - RTAX_HOPLIMIT = 10, - RTAX_INITCWND = 11, - RTAX_FEATURES = 12, - RTAX_RTO_MIN = 13, - RTAX_INITRWND = 14, - RTAX_QUICKACK = 15, - RTAX_CC_ALGO = 16, - RTAX_FASTOPEN_NO_COOKIE = 17, - __RTAX_MAX = 18, -}; - -struct tcmsg { - unsigned char tcm_family; - unsigned char tcm__pad1; - short unsigned int tcm__pad2; - int tcm_ifindex; - __u32 tcm_handle; - __u32 tcm_parent; - __u32 tcm_info; -}; - -struct gnet_stats_basic_cpu { - struct gnet_stats_basic_packed bstats; - struct u64_stats_sync syncp; -}; - -struct gnet_dump { - spinlock_t *lock; - struct sk_buff *skb; - struct nlattr *tail; - int compat_tc_stats; - int compat_xstats; - int padattr; - void *xstats; - int xstats_len; - struct tc_stats tc_stats; -}; - -struct netlink_range_validation { - u64 min; - u64 max; -}; - -struct netlink_range_validation_signed { - s64 min; - s64 max; -}; - -enum flow_action_hw_stats_bit { - FLOW_ACTION_HW_STATS_IMMEDIATE_BIT = 0, - FLOW_ACTION_HW_STATS_DELAYED_BIT = 1, - FLOW_ACTION_HW_STATS_DISABLED_BIT = 2, - FLOW_ACTION_HW_STATS_NUM_BITS = 3, -}; - -struct flow_block { - struct list_head cb_list; -}; - -typedef int flow_setup_cb_t(enum tc_setup_type, void *, void *); - -struct qdisc_size_table { - struct callback_head rcu; - struct list_head list; - struct tc_sizespec szopts; - int refcnt; - u16 data[0]; -}; - -struct Qdisc_class_ops; - -struct Qdisc_ops { - struct Qdisc_ops *next; - const struct Qdisc_class_ops *cl_ops; - char id[16]; - int priv_size; - unsigned int static_flags; - int (*enqueue)(struct sk_buff *, struct Qdisc *, struct sk_buff **); - struct sk_buff * (*dequeue)(struct Qdisc *); - struct sk_buff * (*peek)(struct Qdisc *); - int (*init)(struct Qdisc *, struct nlattr *, struct netlink_ext_ack *); - void (*reset)(struct Qdisc *); - void (*destroy)(struct Qdisc *); - int (*change)(struct Qdisc *, struct nlattr *, struct netlink_ext_ack *); - void (*attach)(struct Qdisc *); - int (*change_tx_queue_len)(struct Qdisc *, unsigned int); - int (*dump)(struct Qdisc *, struct sk_buff *); - int (*dump_stats)(struct Qdisc *, struct gnet_dump *); - void (*ingress_block_set)(struct Qdisc *, u32); - void (*egress_block_set)(struct Qdisc *, u32); - u32 (*ingress_block_get)(struct Qdisc *); - u32 (*egress_block_get)(struct Qdisc *); - struct module *owner; -}; - -struct qdisc_walker; - -struct Qdisc_class_ops { - unsigned int flags; - struct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *); - int (*graft)(struct Qdisc *, long unsigned int, struct Qdisc *, struct Qdisc **, struct netlink_ext_ack *); - struct Qdisc * (*leaf)(struct Qdisc *, long unsigned int); - void (*qlen_notify)(struct Qdisc *, long unsigned int); - long unsigned int (*find)(struct Qdisc *, u32); - int (*change)(struct Qdisc *, u32, u32, struct nlattr **, long unsigned int *, struct netlink_ext_ack *); - int (*delete)(struct Qdisc *, long unsigned int, struct netlink_ext_ack *); - void (*walk)(struct Qdisc *, struct qdisc_walker *); - struct tcf_block * (*tcf_block)(struct Qdisc *, long unsigned int, struct netlink_ext_ack *); - long unsigned int (*bind_tcf)(struct Qdisc *, long unsigned int, u32); - void (*unbind_tcf)(struct Qdisc *, long unsigned int); - int (*dump)(struct Qdisc *, long unsigned int, struct sk_buff *, struct tcmsg *); - int (*dump_stats)(struct Qdisc *, long unsigned int, struct gnet_dump *); -}; - -struct tcf_chain; - -struct tcf_block { - struct mutex lock; - struct list_head chain_list; - u32 index; - u32 classid; - refcount_t refcnt; - struct net *net; - struct Qdisc *q; - struct rw_semaphore cb_lock; - struct flow_block flow_block; - struct list_head owner_list; - bool keep_dst; - atomic_t offloadcnt; - unsigned int nooffloaddevcnt; - unsigned int lockeddevcnt; - struct { - struct tcf_chain *chain; - struct list_head filter_chain_list; - } chain0; - struct callback_head rcu; - struct hlist_head proto_destroy_ht[128]; - struct mutex proto_destroy_lock; -}; - -struct tcf_result; - -struct tcf_proto_ops; - -struct tcf_proto { - struct tcf_proto *next; - void *root; - int (*classify)(struct sk_buff *, const struct tcf_proto *, struct tcf_result *); - __be16 protocol; - u32 prio; - void *data; - const struct tcf_proto_ops *ops; - struct tcf_chain *chain; - spinlock_t lock; - bool deleting; - refcount_t refcnt; - struct callback_head rcu; - struct hlist_node destroy_ht_node; -}; - -struct tcf_result { - union { - struct { - long unsigned int class; - u32 classid; - }; - const struct tcf_proto *goto_tp; - struct { - bool ingress; - struct gnet_stats_queue *qstats; - }; - }; -}; - -struct tcf_walker; - -struct tcf_proto_ops { - struct list_head head; - char kind[16]; - int (*classify)(struct sk_buff *, const struct tcf_proto *, struct tcf_result *); - int (*init)(struct tcf_proto *); - void (*destroy)(struct tcf_proto *, bool, struct netlink_ext_ack *); - void * (*get)(struct tcf_proto *, u32); - void (*put)(struct tcf_proto *, void *); - int (*change)(struct net *, struct sk_buff *, struct tcf_proto *, long unsigned int, u32, struct nlattr **, void **, bool, bool, struct netlink_ext_ack *); - int (*delete)(struct tcf_proto *, void *, bool *, bool, struct netlink_ext_ack *); - bool (*delete_empty)(struct tcf_proto *); - void (*walk)(struct tcf_proto *, struct tcf_walker *, bool); - int (*reoffload)(struct tcf_proto *, bool, flow_setup_cb_t *, void *, struct netlink_ext_ack *); - void (*hw_add)(struct tcf_proto *, void *); - void (*hw_del)(struct tcf_proto *, void *); - void (*bind_class)(void *, u32, long unsigned int, void *, long unsigned int); - void * (*tmplt_create)(struct net *, struct tcf_chain *, struct nlattr **, struct netlink_ext_ack *); - void (*tmplt_destroy)(void *); - int (*dump)(struct net *, struct tcf_proto *, void *, struct sk_buff *, struct tcmsg *, bool); - int (*terse_dump)(struct net *, struct tcf_proto *, void *, struct sk_buff *, struct tcmsg *, bool); - int (*tmplt_dump)(struct sk_buff *, struct net *, void *); - struct module *owner; - int flags; -}; - -struct tcf_chain { - struct mutex filter_chain_lock; - struct tcf_proto *filter_chain; - struct list_head list; - struct tcf_block *block; - u32 index; - unsigned int refcnt; - unsigned int action_refcnt; - bool explicitly_created; - bool flushing; - const struct tcf_proto_ops *tmplt_ops; - void *tmplt_priv; - struct callback_head rcu; -}; - -struct sock_fprog_kern { - u16 len; - struct sock_filter *filter; -}; - -struct bpf_prog_stats { - u64 cnt; - u64 nsecs; - u64 misses; - struct u64_stats_sync syncp; - long: 64; -}; - -struct sk_filter { - refcount_t refcnt; - struct callback_head rcu; - struct bpf_prog *prog; -}; - -enum { - NEIGH_VAR_MCAST_PROBES = 0, - NEIGH_VAR_UCAST_PROBES = 1, - NEIGH_VAR_APP_PROBES = 2, - NEIGH_VAR_MCAST_REPROBES = 3, - NEIGH_VAR_RETRANS_TIME = 4, - NEIGH_VAR_BASE_REACHABLE_TIME = 5, - NEIGH_VAR_DELAY_PROBE_TIME = 6, - NEIGH_VAR_GC_STALETIME = 7, - NEIGH_VAR_QUEUE_LEN_BYTES = 8, - NEIGH_VAR_PROXY_QLEN = 9, - NEIGH_VAR_ANYCAST_DELAY = 10, - NEIGH_VAR_PROXY_DELAY = 11, - NEIGH_VAR_LOCKTIME = 12, - NEIGH_VAR_QUEUE_LEN = 13, - NEIGH_VAR_RETRANS_TIME_MS = 14, - NEIGH_VAR_BASE_REACHABLE_TIME_MS = 15, - NEIGH_VAR_GC_INTERVAL = 16, - NEIGH_VAR_GC_THRESH1 = 17, - NEIGH_VAR_GC_THRESH2 = 18, - NEIGH_VAR_GC_THRESH3 = 19, - NEIGH_VAR_MAX = 20, -}; - -struct pneigh_entry; - -struct neigh_statistics; - -struct neigh_hash_table; - -struct neigh_table { - int family; - unsigned int entry_size; - unsigned int key_len; - __be16 protocol; - __u32 (*hash)(const void *, const struct net_device *, __u32 *); - bool (*key_eq)(const struct neighbour *, const void *); - int (*constructor)(struct neighbour *); - int (*pconstructor)(struct pneigh_entry *); - void (*pdestructor)(struct pneigh_entry *); - void (*proxy_redo)(struct sk_buff *); - int (*is_multicast)(const void *); - bool (*allow_add)(const struct net_device *, struct netlink_ext_ack *); - char *id; - struct neigh_parms parms; - struct list_head parms_list; - int gc_interval; - int gc_thresh1; - int gc_thresh2; - int gc_thresh3; - long unsigned int last_flush; - struct delayed_work gc_work; - struct timer_list proxy_timer; - struct sk_buff_head proxy_queue; - atomic_t entries; - atomic_t gc_entries; - struct list_head gc_list; - rwlock_t lock; - long unsigned int last_rand; - struct neigh_statistics *stats; - struct neigh_hash_table *nht; - struct pneigh_entry **phash_buckets; -}; - -struct neigh_statistics { - long unsigned int allocs; - long unsigned int destroys; - long unsigned int hash_grows; - long unsigned int res_failed; - long unsigned int lookups; - long unsigned int hits; - long unsigned int rcv_probes_mcast; - long unsigned int rcv_probes_ucast; - long unsigned int periodic_gc_runs; - long unsigned int forced_gc_runs; - long unsigned int unres_discards; - long unsigned int table_fulls; -}; - -struct neigh_ops { - int family; - void (*solicit)(struct neighbour *, struct sk_buff *); - void (*error_report)(struct neighbour *, struct sk_buff *); - int (*output)(struct neighbour *, struct sk_buff *); - int (*connected_output)(struct neighbour *, struct sk_buff *); -}; - -struct pneigh_entry { - struct pneigh_entry *next; - possible_net_t net; - struct net_device *dev; - u8 flags; - u8 protocol; - u8 key[0]; -}; - -struct neigh_hash_table { - struct neighbour **hash_buckets; - unsigned int hash_shift; - __u32 hash_rnd[4]; - struct callback_head rcu; -}; - -enum { - TCP_ESTABLISHED = 1, - TCP_SYN_SENT = 2, - TCP_SYN_RECV = 3, - TCP_FIN_WAIT1 = 4, - TCP_FIN_WAIT2 = 5, - TCP_TIME_WAIT = 6, - TCP_CLOSE = 7, - TCP_CLOSE_WAIT = 8, - TCP_LAST_ACK = 9, - TCP_LISTEN = 10, - TCP_CLOSING = 11, - TCP_NEW_SYN_RECV = 12, - TCP_MAX_STATES = 13, -}; - -struct fib_rule_hdr { - __u8 family; - __u8 dst_len; - __u8 src_len; - __u8 tos; - __u8 table; - __u8 res1; - __u8 res2; - __u8 action; - __u32 flags; -}; - -struct fib_rule_port_range { - __u16 start; - __u16 end; -}; - -struct fib_kuid_range { - kuid_t start; - kuid_t end; -}; - -struct fib_rule { - struct list_head list; - int iifindex; - int oifindex; - u32 mark; - u32 mark_mask; - u32 flags; - u32 table; - u8 action; - u8 l3mdev; - u8 proto; - u8 ip_proto; - u32 target; - __be64 tun_id; - struct fib_rule *ctarget; - struct net *fr_net; - refcount_t refcnt; - u32 pref; - int suppress_ifgroup; - int suppress_prefixlen; - char iifname[16]; - char oifname[16]; - struct fib_kuid_range uid_range; - struct fib_rule_port_range sport_range; - struct fib_rule_port_range dport_range; - struct callback_head rcu; -}; - -struct fib_lookup_arg { - void *lookup_ptr; - const void *lookup_data; - void *result; - struct fib_rule *rule; - u32 table; - int flags; -}; - -struct smc_hashinfo; - -struct sk_psock; - -struct request_sock_ops; - -struct timewait_sock_ops; - -struct udp_table; - -struct raw_hashinfo; - -struct proto { - void (*close)(struct sock *, long int); - int (*pre_connect)(struct sock *, struct sockaddr *, int); - int (*connect)(struct sock *, struct sockaddr *, int); - int (*disconnect)(struct sock *, int); - struct sock * (*accept)(struct sock *, int, int *, bool); - int (*ioctl)(struct sock *, int, long unsigned int); - int (*init)(struct sock *); - void (*destroy)(struct sock *); - void (*shutdown)(struct sock *, int); - int (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int); - int (*getsockopt)(struct sock *, int, int, char *, int *); - void (*keepalive)(struct sock *, int); - int (*compat_ioctl)(struct sock *, unsigned int, long unsigned int); - int (*sendmsg)(struct sock *, struct msghdr *, size_t); - int (*recvmsg)(struct sock *, struct msghdr *, size_t, int, int, int *); - int (*sendpage)(struct sock *, struct page *, int, size_t, int); - int (*bind)(struct sock *, struct sockaddr *, int); - int (*bind_add)(struct sock *, struct sockaddr *, int); - int (*backlog_rcv)(struct sock *, struct sk_buff *); - bool (*bpf_bypass_getsockopt)(int, int); - void (*release_cb)(struct sock *); - int (*hash)(struct sock *); - void (*unhash)(struct sock *); - void (*rehash)(struct sock *); - int (*get_port)(struct sock *, short unsigned int); - int (*psock_update_sk_prot)(struct sock *, struct sk_psock *, bool); - unsigned int inuse_idx; - bool (*stream_memory_free)(const struct sock *, int); - bool (*stream_memory_read)(const struct sock *); - void (*enter_memory_pressure)(struct sock *); - void (*leave_memory_pressure)(struct sock *); - atomic_long_t *memory_allocated; - struct percpu_counter *sockets_allocated; - long unsigned int *memory_pressure; - long int *sysctl_mem; - int *sysctl_wmem; - int *sysctl_rmem; - u32 sysctl_wmem_offset; - u32 sysctl_rmem_offset; - int max_header; - bool no_autobind; - struct kmem_cache *slab; - unsigned int obj_size; - slab_flags_t slab_flags; - unsigned int useroffset; - unsigned int usersize; - struct percpu_counter *orphan_count; - struct request_sock_ops *rsk_prot; - struct timewait_sock_ops *twsk_prot; - union { - struct inet_hashinfo *hashinfo; - struct udp_table *udp_table; - struct raw_hashinfo *raw_hash; - struct smc_hashinfo *smc_hash; - } h; - struct module *owner; - char name[32]; - struct list_head node; - int (*diag_destroy)(struct sock *, int); -}; - -struct request_sock; - -struct request_sock_ops { - int family; - unsigned int obj_size; - struct kmem_cache *slab; - char *slab_name; - int (*rtx_syn_ack)(const struct sock *, struct request_sock *); - void (*send_ack)(const struct sock *, struct sk_buff *, struct request_sock *); - void (*send_reset)(const struct sock *, struct sk_buff *); - void (*destructor)(struct request_sock *); - void (*syn_ack_timeout)(const struct request_sock *); -}; - -struct timewait_sock_ops { - struct kmem_cache *twsk_slab; - char *twsk_slab_name; - unsigned int twsk_obj_size; - int (*twsk_unique)(struct sock *, struct sock *, void *); - void (*twsk_destructor)(struct sock *); -}; - -struct saved_syn; - -struct request_sock { - struct sock_common __req_common; - struct request_sock *dl_next; - u16 mss; - u8 num_retrans; - u8 syncookie: 1; - u8 num_timeout: 7; - u32 ts_recent; - struct timer_list rsk_timer; - const struct request_sock_ops *rsk_ops; - struct sock *sk; - struct saved_syn *saved_syn; - u32 secid; - u32 peer_secid; -}; - -struct saved_syn { - u32 mac_hdrlen; - u32 network_hdrlen; - u32 tcp_hdrlen; - u8 data[0]; -}; - -enum tsq_enum { - TSQ_THROTTLED = 0, - TSQ_QUEUED = 1, - TCP_TSQ_DEFERRED = 2, - TCP_WRITE_TIMER_DEFERRED = 3, - TCP_DELACK_TIMER_DEFERRED = 4, - TCP_MTU_REDUCED_DEFERRED = 5, -}; - -struct ip6_sf_list { - struct ip6_sf_list *sf_next; - struct in6_addr sf_addr; - long unsigned int sf_count[2]; - unsigned char sf_gsresp; - unsigned char sf_oldin; - unsigned char sf_crcount; - struct callback_head rcu; -}; - -struct ifmcaddr6 { - struct in6_addr mca_addr; - struct inet6_dev *idev; - struct ifmcaddr6 *next; - struct ip6_sf_list *mca_sources; - struct ip6_sf_list *mca_tomb; - unsigned int mca_sfmode; - unsigned char mca_crcount; - long unsigned int mca_sfcount[2]; - struct delayed_work mca_work; - unsigned int mca_flags; - int mca_users; - refcount_t mca_refcnt; - long unsigned int mca_cstamp; - long unsigned int mca_tstamp; - struct callback_head rcu; -}; - -struct ifacaddr6 { - struct in6_addr aca_addr; - struct fib6_info *aca_rt; - struct ifacaddr6 *aca_next; - struct hlist_node aca_addr_lst; - int aca_users; - refcount_t aca_refcnt; - long unsigned int aca_cstamp; - long unsigned int aca_tstamp; - struct callback_head rcu; -}; - -enum { - __ND_OPT_PREFIX_INFO_END = 0, - ND_OPT_SOURCE_LL_ADDR = 1, - ND_OPT_TARGET_LL_ADDR = 2, - ND_OPT_PREFIX_INFO = 3, - ND_OPT_REDIRECT_HDR = 4, - ND_OPT_MTU = 5, - ND_OPT_NONCE = 14, - __ND_OPT_ARRAY_MAX = 15, - ND_OPT_ROUTE_INFO = 24, - ND_OPT_RDNSS = 25, - ND_OPT_DNSSL = 31, - ND_OPT_6CO = 34, - ND_OPT_CAPTIVE_PORTAL = 37, - ND_OPT_PREF64 = 38, - __ND_OPT_MAX = 39, -}; - -struct nd_opt_hdr { - __u8 nd_opt_type; - __u8 nd_opt_len; -}; - -struct ndisc_options { - struct nd_opt_hdr *nd_opt_array[15]; - struct nd_opt_hdr *nd_opts_ri; - struct nd_opt_hdr *nd_opts_ri_end; - struct nd_opt_hdr *nd_useropts; - struct nd_opt_hdr *nd_useropts_end; - struct nd_opt_hdr *nd_802154_opt_array[3]; -}; - -struct prefix_info { - __u8 type; - __u8 length; - __u8 prefix_len; - __u8 reserved: 6; - __u8 autoconf: 1; - __u8 onlink: 1; - __be32 valid; - __be32 prefered; - __be32 reserved2; - struct in6_addr prefix; -}; - -enum nfs_opnum4 { - OP_ACCESS = 3, - OP_CLOSE = 4, - OP_COMMIT = 5, - OP_CREATE = 6, - OP_DELEGPURGE = 7, - OP_DELEGRETURN = 8, - OP_GETATTR = 9, - OP_GETFH = 10, - OP_LINK = 11, - OP_LOCK = 12, - OP_LOCKT = 13, - OP_LOCKU = 14, - OP_LOOKUP = 15, - OP_LOOKUPP = 16, - OP_NVERIFY = 17, - OP_OPEN = 18, - OP_OPENATTR = 19, - OP_OPEN_CONFIRM = 20, - OP_OPEN_DOWNGRADE = 21, - OP_PUTFH = 22, - OP_PUTPUBFH = 23, - OP_PUTROOTFH = 24, - OP_READ = 25, - OP_READDIR = 26, - OP_READLINK = 27, - OP_REMOVE = 28, - OP_RENAME = 29, - OP_RENEW = 30, - OP_RESTOREFH = 31, - OP_SAVEFH = 32, - OP_SECINFO = 33, - OP_SETATTR = 34, - OP_SETCLIENTID = 35, - OP_SETCLIENTID_CONFIRM = 36, - OP_VERIFY = 37, - OP_WRITE = 38, - OP_RELEASE_LOCKOWNER = 39, - OP_BACKCHANNEL_CTL = 40, - OP_BIND_CONN_TO_SESSION = 41, - OP_EXCHANGE_ID = 42, - OP_CREATE_SESSION = 43, - OP_DESTROY_SESSION = 44, - OP_FREE_STATEID = 45, - OP_GET_DIR_DELEGATION = 46, - OP_GETDEVICEINFO = 47, - OP_GETDEVICELIST = 48, - OP_LAYOUTCOMMIT = 49, - OP_LAYOUTGET = 50, - OP_LAYOUTRETURN = 51, - OP_SECINFO_NO_NAME = 52, - OP_SEQUENCE = 53, - OP_SET_SSV = 54, - OP_TEST_STATEID = 55, - OP_WANT_DELEGATION = 56, - OP_DESTROY_CLIENTID = 57, - OP_RECLAIM_COMPLETE = 58, - OP_ALLOCATE = 59, - OP_COPY = 60, - OP_COPY_NOTIFY = 61, - OP_DEALLOCATE = 62, - OP_IO_ADVISE = 63, - OP_LAYOUTERROR = 64, - OP_LAYOUTSTATS = 65, - OP_OFFLOAD_CANCEL = 66, - OP_OFFLOAD_STATUS = 67, - OP_READ_PLUS = 68, - OP_SEEK = 69, - OP_WRITE_SAME = 70, - OP_CLONE = 71, - OP_GETXATTR = 72, - OP_SETXATTR = 73, - OP_LISTXATTRS = 74, - OP_REMOVEXATTR = 75, - OP_ILLEGAL = 10044, -}; - -enum perf_branch_sample_type_shift { - PERF_SAMPLE_BRANCH_USER_SHIFT = 0, - PERF_SAMPLE_BRANCH_KERNEL_SHIFT = 1, - PERF_SAMPLE_BRANCH_HV_SHIFT = 2, - PERF_SAMPLE_BRANCH_ANY_SHIFT = 3, - PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT = 4, - PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT = 5, - PERF_SAMPLE_BRANCH_IND_CALL_SHIFT = 6, - PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT = 7, - PERF_SAMPLE_BRANCH_IN_TX_SHIFT = 8, - PERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9, - PERF_SAMPLE_BRANCH_COND_SHIFT = 10, - PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11, - PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12, - PERF_SAMPLE_BRANCH_CALL_SHIFT = 13, - PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT = 14, - PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT = 15, - PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT = 16, - PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT = 17, - PERF_SAMPLE_BRANCH_MAX_SHIFT = 18, -}; - -enum exception_stack_ordering { - ESTACK_DF = 0, - ESTACK_NMI = 1, - ESTACK_DB = 2, - ESTACK_MCE = 3, - ESTACK_VC = 4, - ESTACK_VC2 = 5, - N_EXCEPTION_STACKS = 6, -}; - -enum { - TSK_TRACE_FL_TRACE_BIT = 0, - TSK_TRACE_FL_GRAPH_BIT = 1, -}; - -struct uuidcmp { - const char *uuid; - int len; -}; - -struct subprocess_info { - struct work_struct work; - struct completion *complete; - const char *path; - char **argv; - char **envp; - int wait; - int retval; - int (*init)(struct subprocess_info *, struct cred *); - void (*cleanup)(struct subprocess_info *); - void *data; -}; - -typedef phys_addr_t resource_size_t; - -struct __va_list_tag { - unsigned int gp_offset; - unsigned int fp_offset; - void *overflow_arg_area; - void *reg_save_area; -}; - -typedef __builtin_va_list __gnuc_va_list; - -typedef __gnuc_va_list va_list; - -struct resource { - resource_size_t start; - resource_size_t end; - const char *name; - long unsigned int flags; - long unsigned int desc; - struct resource *parent; - struct resource *sibling; - struct resource *child; -}; - -typedef u64 async_cookie_t; - -typedef void (*async_func_t)(void *, async_cookie_t); - -struct async_domain { - struct list_head pending; - unsigned int registered: 1; -}; - -struct hash { - int ino; - int minor; - int major; - umode_t mode; - struct hash *next; - char name[4098]; -}; - -struct dir_entry { - struct list_head list; - char *name; - time64_t mtime; -}; - -enum state { - Start = 0, - Collect = 1, - GotHeader = 2, - SkipIt = 3, - GotName = 4, - CopyFile = 5, - GotSymlink = 6, - Reset = 7, -}; - -typedef int (*decompress_fn)(unsigned char *, long int, long int (*)(void *, long unsigned int), long int (*)(void *, long unsigned int), unsigned char *, long int *, void (*)(char *)); - -enum { - HI_SOFTIRQ = 0, - TIMER_SOFTIRQ = 1, - NET_TX_SOFTIRQ = 2, - NET_RX_SOFTIRQ = 3, - BLOCK_SOFTIRQ = 4, - IRQ_POLL_SOFTIRQ = 5, - TASKLET_SOFTIRQ = 6, - SCHED_SOFTIRQ = 7, - HRTIMER_SOFTIRQ = 8, - RCU_SOFTIRQ = 9, - NR_SOFTIRQS = 10, -}; - -enum ucount_type { - UCOUNT_USER_NAMESPACES = 0, - UCOUNT_PID_NAMESPACES = 1, - UCOUNT_UTS_NAMESPACES = 2, - UCOUNT_IPC_NAMESPACES = 3, - UCOUNT_NET_NAMESPACES = 4, - UCOUNT_MNT_NAMESPACES = 5, - UCOUNT_CGROUP_NAMESPACES = 6, - UCOUNT_TIME_NAMESPACES = 7, - UCOUNT_INOTIFY_INSTANCES = 8, - UCOUNT_INOTIFY_WATCHES = 9, - UCOUNT_FANOTIFY_GROUPS = 10, - UCOUNT_FANOTIFY_MARKS = 11, - UCOUNT_RLIMIT_NPROC = 12, - UCOUNT_RLIMIT_MSGQUEUE = 13, - UCOUNT_RLIMIT_SIGPENDING = 14, - UCOUNT_RLIMIT_MEMLOCK = 15, - UCOUNT_COUNTS = 16, -}; - -enum flow_dissector_key_id { - FLOW_DISSECTOR_KEY_CONTROL = 0, - FLOW_DISSECTOR_KEY_BASIC = 1, - FLOW_DISSECTOR_KEY_IPV4_ADDRS = 2, - FLOW_DISSECTOR_KEY_IPV6_ADDRS = 3, - FLOW_DISSECTOR_KEY_PORTS = 4, - FLOW_DISSECTOR_KEY_PORTS_RANGE = 5, - FLOW_DISSECTOR_KEY_ICMP = 6, - FLOW_DISSECTOR_KEY_ETH_ADDRS = 7, - FLOW_DISSECTOR_KEY_TIPC = 8, - FLOW_DISSECTOR_KEY_ARP = 9, - FLOW_DISSECTOR_KEY_VLAN = 10, - FLOW_DISSECTOR_KEY_FLOW_LABEL = 11, - FLOW_DISSECTOR_KEY_GRE_KEYID = 12, - FLOW_DISSECTOR_KEY_MPLS_ENTROPY = 13, - FLOW_DISSECTOR_KEY_ENC_KEYID = 14, - FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS = 15, - FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS = 16, - FLOW_DISSECTOR_KEY_ENC_CONTROL = 17, - FLOW_DISSECTOR_KEY_ENC_PORTS = 18, - FLOW_DISSECTOR_KEY_MPLS = 19, - FLOW_DISSECTOR_KEY_TCP = 20, - FLOW_DISSECTOR_KEY_IP = 21, - FLOW_DISSECTOR_KEY_CVLAN = 22, - FLOW_DISSECTOR_KEY_ENC_IP = 23, - FLOW_DISSECTOR_KEY_ENC_OPTS = 24, - FLOW_DISSECTOR_KEY_META = 25, - FLOW_DISSECTOR_KEY_CT = 26, - FLOW_DISSECTOR_KEY_HASH = 27, - FLOW_DISSECTOR_KEY_MAX = 28, -}; - -enum { - IPSTATS_MIB_NUM = 0, - IPSTATS_MIB_INPKTS = 1, - IPSTATS_MIB_INOCTETS = 2, - IPSTATS_MIB_INDELIVERS = 3, - IPSTATS_MIB_OUTFORWDATAGRAMS = 4, - IPSTATS_MIB_OUTPKTS = 5, - IPSTATS_MIB_OUTOCTETS = 6, - IPSTATS_MIB_INHDRERRORS = 7, - IPSTATS_MIB_INTOOBIGERRORS = 8, - IPSTATS_MIB_INNOROUTES = 9, - IPSTATS_MIB_INADDRERRORS = 10, - IPSTATS_MIB_INUNKNOWNPROTOS = 11, - IPSTATS_MIB_INTRUNCATEDPKTS = 12, - IPSTATS_MIB_INDISCARDS = 13, - IPSTATS_MIB_OUTDISCARDS = 14, - IPSTATS_MIB_OUTNOROUTES = 15, - IPSTATS_MIB_REASMTIMEOUT = 16, - IPSTATS_MIB_REASMREQDS = 17, - IPSTATS_MIB_REASMOKS = 18, - IPSTATS_MIB_REASMFAILS = 19, - IPSTATS_MIB_FRAGOKS = 20, - IPSTATS_MIB_FRAGFAILS = 21, - IPSTATS_MIB_FRAGCREATES = 22, - IPSTATS_MIB_INMCASTPKTS = 23, - IPSTATS_MIB_OUTMCASTPKTS = 24, - IPSTATS_MIB_INBCASTPKTS = 25, - IPSTATS_MIB_OUTBCASTPKTS = 26, - IPSTATS_MIB_INMCASTOCTETS = 27, - IPSTATS_MIB_OUTMCASTOCTETS = 28, - IPSTATS_MIB_INBCASTOCTETS = 29, - IPSTATS_MIB_OUTBCASTOCTETS = 30, - IPSTATS_MIB_CSUMERRORS = 31, - IPSTATS_MIB_NOECTPKTS = 32, - IPSTATS_MIB_ECT1PKTS = 33, - IPSTATS_MIB_ECT0PKTS = 34, - IPSTATS_MIB_CEPKTS = 35, - IPSTATS_MIB_REASM_OVERLAPS = 36, - __IPSTATS_MIB_MAX = 37, -}; - -enum { - ICMP_MIB_NUM = 0, - ICMP_MIB_INMSGS = 1, - ICMP_MIB_INERRORS = 2, - ICMP_MIB_INDESTUNREACHS = 3, - ICMP_MIB_INTIMEEXCDS = 4, - ICMP_MIB_INPARMPROBS = 5, - ICMP_MIB_INSRCQUENCHS = 6, - ICMP_MIB_INREDIRECTS = 7, - ICMP_MIB_INECHOS = 8, - ICMP_MIB_INECHOREPS = 9, - ICMP_MIB_INTIMESTAMPS = 10, - ICMP_MIB_INTIMESTAMPREPS = 11, - ICMP_MIB_INADDRMASKS = 12, - ICMP_MIB_INADDRMASKREPS = 13, - ICMP_MIB_OUTMSGS = 14, - ICMP_MIB_OUTERRORS = 15, - ICMP_MIB_OUTDESTUNREACHS = 16, - ICMP_MIB_OUTTIMEEXCDS = 17, - ICMP_MIB_OUTPARMPROBS = 18, - ICMP_MIB_OUTSRCQUENCHS = 19, - ICMP_MIB_OUTREDIRECTS = 20, - ICMP_MIB_OUTECHOS = 21, - ICMP_MIB_OUTECHOREPS = 22, - ICMP_MIB_OUTTIMESTAMPS = 23, - ICMP_MIB_OUTTIMESTAMPREPS = 24, - ICMP_MIB_OUTADDRMASKS = 25, - ICMP_MIB_OUTADDRMASKREPS = 26, - ICMP_MIB_CSUMERRORS = 27, - __ICMP_MIB_MAX = 28, -}; - -enum { - ICMP6_MIB_NUM = 0, - ICMP6_MIB_INMSGS = 1, - ICMP6_MIB_INERRORS = 2, - ICMP6_MIB_OUTMSGS = 3, - ICMP6_MIB_OUTERRORS = 4, - ICMP6_MIB_CSUMERRORS = 5, - __ICMP6_MIB_MAX = 6, -}; - -enum { - TCP_MIB_NUM = 0, - TCP_MIB_RTOALGORITHM = 1, - TCP_MIB_RTOMIN = 2, - TCP_MIB_RTOMAX = 3, - TCP_MIB_MAXCONN = 4, - TCP_MIB_ACTIVEOPENS = 5, - TCP_MIB_PASSIVEOPENS = 6, - TCP_MIB_ATTEMPTFAILS = 7, - TCP_MIB_ESTABRESETS = 8, - TCP_MIB_CURRESTAB = 9, - TCP_MIB_INSEGS = 10, - TCP_MIB_OUTSEGS = 11, - TCP_MIB_RETRANSSEGS = 12, - TCP_MIB_INERRS = 13, - TCP_MIB_OUTRSTS = 14, - TCP_MIB_CSUMERRORS = 15, - __TCP_MIB_MAX = 16, -}; - -enum { - UDP_MIB_NUM = 0, - UDP_MIB_INDATAGRAMS = 1, - UDP_MIB_NOPORTS = 2, - UDP_MIB_INERRORS = 3, - UDP_MIB_OUTDATAGRAMS = 4, - UDP_MIB_RCVBUFERRORS = 5, - UDP_MIB_SNDBUFERRORS = 6, - UDP_MIB_CSUMERRORS = 7, - UDP_MIB_IGNOREDMULTI = 8, - UDP_MIB_MEMERRORS = 9, - __UDP_MIB_MAX = 10, -}; - -enum { - LINUX_MIB_NUM = 0, - LINUX_MIB_SYNCOOKIESSENT = 1, - LINUX_MIB_SYNCOOKIESRECV = 2, - LINUX_MIB_SYNCOOKIESFAILED = 3, - LINUX_MIB_EMBRYONICRSTS = 4, - LINUX_MIB_PRUNECALLED = 5, - LINUX_MIB_RCVPRUNED = 6, - LINUX_MIB_OFOPRUNED = 7, - LINUX_MIB_OUTOFWINDOWICMPS = 8, - LINUX_MIB_LOCKDROPPEDICMPS = 9, - LINUX_MIB_ARPFILTER = 10, - LINUX_MIB_TIMEWAITED = 11, - LINUX_MIB_TIMEWAITRECYCLED = 12, - LINUX_MIB_TIMEWAITKILLED = 13, - LINUX_MIB_PAWSACTIVEREJECTED = 14, - LINUX_MIB_PAWSESTABREJECTED = 15, - LINUX_MIB_DELAYEDACKS = 16, - LINUX_MIB_DELAYEDACKLOCKED = 17, - LINUX_MIB_DELAYEDACKLOST = 18, - LINUX_MIB_LISTENOVERFLOWS = 19, - LINUX_MIB_LISTENDROPS = 20, - LINUX_MIB_TCPHPHITS = 21, - LINUX_MIB_TCPPUREACKS = 22, - LINUX_MIB_TCPHPACKS = 23, - LINUX_MIB_TCPRENORECOVERY = 24, - LINUX_MIB_TCPSACKRECOVERY = 25, - LINUX_MIB_TCPSACKRENEGING = 26, - LINUX_MIB_TCPSACKREORDER = 27, - LINUX_MIB_TCPRENOREORDER = 28, - LINUX_MIB_TCPTSREORDER = 29, - LINUX_MIB_TCPFULLUNDO = 30, - LINUX_MIB_TCPPARTIALUNDO = 31, - LINUX_MIB_TCPDSACKUNDO = 32, - LINUX_MIB_TCPLOSSUNDO = 33, - LINUX_MIB_TCPLOSTRETRANSMIT = 34, - LINUX_MIB_TCPRENOFAILURES = 35, - LINUX_MIB_TCPSACKFAILURES = 36, - LINUX_MIB_TCPLOSSFAILURES = 37, - LINUX_MIB_TCPFASTRETRANS = 38, - LINUX_MIB_TCPSLOWSTARTRETRANS = 39, - LINUX_MIB_TCPTIMEOUTS = 40, - LINUX_MIB_TCPLOSSPROBES = 41, - LINUX_MIB_TCPLOSSPROBERECOVERY = 42, - LINUX_MIB_TCPRENORECOVERYFAIL = 43, - LINUX_MIB_TCPSACKRECOVERYFAIL = 44, - LINUX_MIB_TCPRCVCOLLAPSED = 45, - LINUX_MIB_TCPDSACKOLDSENT = 46, - LINUX_MIB_TCPDSACKOFOSENT = 47, - LINUX_MIB_TCPDSACKRECV = 48, - LINUX_MIB_TCPDSACKOFORECV = 49, - LINUX_MIB_TCPABORTONDATA = 50, - LINUX_MIB_TCPABORTONCLOSE = 51, - LINUX_MIB_TCPABORTONMEMORY = 52, - LINUX_MIB_TCPABORTONTIMEOUT = 53, - LINUX_MIB_TCPABORTONLINGER = 54, - LINUX_MIB_TCPABORTFAILED = 55, - LINUX_MIB_TCPMEMORYPRESSURES = 56, - LINUX_MIB_TCPMEMORYPRESSURESCHRONO = 57, - LINUX_MIB_TCPSACKDISCARD = 58, - LINUX_MIB_TCPDSACKIGNOREDOLD = 59, - LINUX_MIB_TCPDSACKIGNOREDNOUNDO = 60, - LINUX_MIB_TCPSPURIOUSRTOS = 61, - LINUX_MIB_TCPMD5NOTFOUND = 62, - LINUX_MIB_TCPMD5UNEXPECTED = 63, - LINUX_MIB_TCPMD5FAILURE = 64, - LINUX_MIB_SACKSHIFTED = 65, - LINUX_MIB_SACKMERGED = 66, - LINUX_MIB_SACKSHIFTFALLBACK = 67, - LINUX_MIB_TCPBACKLOGDROP = 68, - LINUX_MIB_PFMEMALLOCDROP = 69, - LINUX_MIB_TCPMINTTLDROP = 70, - LINUX_MIB_TCPDEFERACCEPTDROP = 71, - LINUX_MIB_IPRPFILTER = 72, - LINUX_MIB_TCPTIMEWAITOVERFLOW = 73, - LINUX_MIB_TCPREQQFULLDOCOOKIES = 74, - LINUX_MIB_TCPREQQFULLDROP = 75, - LINUX_MIB_TCPRETRANSFAIL = 76, - LINUX_MIB_TCPRCVCOALESCE = 77, - LINUX_MIB_TCPBACKLOGCOALESCE = 78, - LINUX_MIB_TCPOFOQUEUE = 79, - LINUX_MIB_TCPOFODROP = 80, - LINUX_MIB_TCPOFOMERGE = 81, - LINUX_MIB_TCPCHALLENGEACK = 82, - LINUX_MIB_TCPSYNCHALLENGE = 83, - LINUX_MIB_TCPFASTOPENACTIVE = 84, - LINUX_MIB_TCPFASTOPENACTIVEFAIL = 85, - LINUX_MIB_TCPFASTOPENPASSIVE = 86, - LINUX_MIB_TCPFASTOPENPASSIVEFAIL = 87, - LINUX_MIB_TCPFASTOPENLISTENOVERFLOW = 88, - LINUX_MIB_TCPFASTOPENCOOKIEREQD = 89, - LINUX_MIB_TCPFASTOPENBLACKHOLE = 90, - LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES = 91, - LINUX_MIB_BUSYPOLLRXPACKETS = 92, - LINUX_MIB_TCPAUTOCORKING = 93, - LINUX_MIB_TCPFROMZEROWINDOWADV = 94, - LINUX_MIB_TCPTOZEROWINDOWADV = 95, - LINUX_MIB_TCPWANTZEROWINDOWADV = 96, - LINUX_MIB_TCPSYNRETRANS = 97, - LINUX_MIB_TCPORIGDATASENT = 98, - LINUX_MIB_TCPHYSTARTTRAINDETECT = 99, - LINUX_MIB_TCPHYSTARTTRAINCWND = 100, - LINUX_MIB_TCPHYSTARTDELAYDETECT = 101, - LINUX_MIB_TCPHYSTARTDELAYCWND = 102, - LINUX_MIB_TCPACKSKIPPEDSYNRECV = 103, - LINUX_MIB_TCPACKSKIPPEDPAWS = 104, - LINUX_MIB_TCPACKSKIPPEDSEQ = 105, - LINUX_MIB_TCPACKSKIPPEDFINWAIT2 = 106, - LINUX_MIB_TCPACKSKIPPEDTIMEWAIT = 107, - LINUX_MIB_TCPACKSKIPPEDCHALLENGE = 108, - LINUX_MIB_TCPWINPROBE = 109, - LINUX_MIB_TCPKEEPALIVE = 110, - LINUX_MIB_TCPMTUPFAIL = 111, - LINUX_MIB_TCPMTUPSUCCESS = 112, - LINUX_MIB_TCPDELIVERED = 113, - LINUX_MIB_TCPDELIVEREDCE = 114, - LINUX_MIB_TCPACKCOMPRESSED = 115, - LINUX_MIB_TCPZEROWINDOWDROP = 116, - LINUX_MIB_TCPRCVQDROP = 117, - LINUX_MIB_TCPWQUEUETOOBIG = 118, - LINUX_MIB_TCPFASTOPENPASSIVEALTKEY = 119, - LINUX_MIB_TCPTIMEOUTREHASH = 120, - LINUX_MIB_TCPDUPLICATEDATAREHASH = 121, - LINUX_MIB_TCPDSACKRECVSEGS = 122, - LINUX_MIB_TCPDSACKIGNOREDDUBIOUS = 123, - LINUX_MIB_TCPMIGRATEREQSUCCESS = 124, - LINUX_MIB_TCPMIGRATEREQFAILURE = 125, - __LINUX_MIB_MAX = 126, -}; - -enum { - LINUX_MIB_XFRMNUM = 0, - LINUX_MIB_XFRMINERROR = 1, - LINUX_MIB_XFRMINBUFFERERROR = 2, - LINUX_MIB_XFRMINHDRERROR = 3, - LINUX_MIB_XFRMINNOSTATES = 4, - LINUX_MIB_XFRMINSTATEPROTOERROR = 5, - LINUX_MIB_XFRMINSTATEMODEERROR = 6, - LINUX_MIB_XFRMINSTATESEQERROR = 7, - LINUX_MIB_XFRMINSTATEEXPIRED = 8, - LINUX_MIB_XFRMINSTATEMISMATCH = 9, - LINUX_MIB_XFRMINSTATEINVALID = 10, - LINUX_MIB_XFRMINTMPLMISMATCH = 11, - LINUX_MIB_XFRMINNOPOLS = 12, - LINUX_MIB_XFRMINPOLBLOCK = 13, - LINUX_MIB_XFRMINPOLERROR = 14, - LINUX_MIB_XFRMOUTERROR = 15, - LINUX_MIB_XFRMOUTBUNDLEGENERROR = 16, - LINUX_MIB_XFRMOUTBUNDLECHECKERROR = 17, - LINUX_MIB_XFRMOUTNOSTATES = 18, - LINUX_MIB_XFRMOUTSTATEPROTOERROR = 19, - LINUX_MIB_XFRMOUTSTATEMODEERROR = 20, - LINUX_MIB_XFRMOUTSTATESEQERROR = 21, - LINUX_MIB_XFRMOUTSTATEEXPIRED = 22, - LINUX_MIB_XFRMOUTPOLBLOCK = 23, - LINUX_MIB_XFRMOUTPOLDEAD = 24, - LINUX_MIB_XFRMOUTPOLERROR = 25, - LINUX_MIB_XFRMFWDHDRERROR = 26, - LINUX_MIB_XFRMOUTSTATEINVALID = 27, - LINUX_MIB_XFRMACQUIREERROR = 28, - __LINUX_MIB_XFRMMAX = 29, -}; - -enum { - LINUX_MIB_TLSNUM = 0, - LINUX_MIB_TLSCURRTXSW = 1, - LINUX_MIB_TLSCURRRXSW = 2, - LINUX_MIB_TLSCURRTXDEVICE = 3, - LINUX_MIB_TLSCURRRXDEVICE = 4, - LINUX_MIB_TLSTXSW = 5, - LINUX_MIB_TLSRXSW = 6, - LINUX_MIB_TLSTXDEVICE = 7, - LINUX_MIB_TLSRXDEVICE = 8, - LINUX_MIB_TLSDECRYPTERROR = 9, - LINUX_MIB_TLSRXDEVICERESYNC = 10, - __LINUX_MIB_TLSMAX = 11, -}; - -enum nf_inet_hooks { - NF_INET_PRE_ROUTING = 0, - NF_INET_LOCAL_IN = 1, - NF_INET_FORWARD = 2, - NF_INET_LOCAL_OUT = 3, - NF_INET_POST_ROUTING = 4, - NF_INET_NUMHOOKS = 5, - NF_INET_INGRESS = 5, -}; - -enum { - NFPROTO_UNSPEC = 0, - NFPROTO_INET = 1, - NFPROTO_IPV4 = 2, - NFPROTO_ARP = 3, - NFPROTO_NETDEV = 5, - NFPROTO_BRIDGE = 7, - NFPROTO_IPV6 = 10, - NFPROTO_DECNET = 12, - NFPROTO_NUMPROTO = 13, -}; - -enum tcp_conntrack { - TCP_CONNTRACK_NONE = 0, - TCP_CONNTRACK_SYN_SENT = 1, - TCP_CONNTRACK_SYN_RECV = 2, - TCP_CONNTRACK_ESTABLISHED = 3, - TCP_CONNTRACK_FIN_WAIT = 4, - TCP_CONNTRACK_CLOSE_WAIT = 5, - TCP_CONNTRACK_LAST_ACK = 6, - TCP_CONNTRACK_TIME_WAIT = 7, - TCP_CONNTRACK_CLOSE = 8, - TCP_CONNTRACK_LISTEN = 9, - TCP_CONNTRACK_MAX = 10, - TCP_CONNTRACK_IGNORE = 11, - TCP_CONNTRACK_RETRANS = 12, - TCP_CONNTRACK_UNACK = 13, - TCP_CONNTRACK_TIMEOUT_MAX = 14, -}; - -enum ct_dccp_states { - CT_DCCP_NONE = 0, - CT_DCCP_REQUEST = 1, - CT_DCCP_RESPOND = 2, - CT_DCCP_PARTOPEN = 3, - CT_DCCP_OPEN = 4, - CT_DCCP_CLOSEREQ = 5, - CT_DCCP_CLOSING = 6, - CT_DCCP_TIMEWAIT = 7, - CT_DCCP_IGNORE = 8, - CT_DCCP_INVALID = 9, - __CT_DCCP_MAX = 10, -}; - -enum ip_conntrack_dir { - IP_CT_DIR_ORIGINAL = 0, - IP_CT_DIR_REPLY = 1, - IP_CT_DIR_MAX = 2, -}; - -enum sctp_conntrack { - SCTP_CONNTRACK_NONE = 0, - SCTP_CONNTRACK_CLOSED = 1, - SCTP_CONNTRACK_COOKIE_WAIT = 2, - SCTP_CONNTRACK_COOKIE_ECHOED = 3, - SCTP_CONNTRACK_ESTABLISHED = 4, - SCTP_CONNTRACK_SHUTDOWN_SENT = 5, - SCTP_CONNTRACK_SHUTDOWN_RECD = 6, - SCTP_CONNTRACK_SHUTDOWN_ACK_SENT = 7, - SCTP_CONNTRACK_HEARTBEAT_SENT = 8, - SCTP_CONNTRACK_HEARTBEAT_ACKED = 9, - SCTP_CONNTRACK_MAX = 10, -}; - -enum udp_conntrack { - UDP_CT_UNREPLIED = 0, - UDP_CT_REPLIED = 1, - UDP_CT_MAX = 2, -}; - -enum gre_conntrack { - GRE_CT_UNREPLIED = 0, - GRE_CT_REPLIED = 1, - GRE_CT_MAX = 2, -}; - -enum { - XFRM_POLICY_IN = 0, - XFRM_POLICY_OUT = 1, - XFRM_POLICY_FWD = 2, - XFRM_POLICY_MASK = 3, - XFRM_POLICY_MAX = 3, -}; - -enum netns_bpf_attach_type { - NETNS_BPF_INVALID = 4294967295, - NETNS_BPF_FLOW_DISSECTOR = 0, - NETNS_BPF_SK_LOOKUP = 1, - MAX_NETNS_BPF_ATTACH_TYPE = 2, -}; - -enum skb_ext_id { - SKB_EXT_BRIDGE_NF = 0, - SKB_EXT_SEC_PATH = 1, - TC_SKB_EXT = 2, - SKB_EXT_MPTCP = 3, - SKB_EXT_NUM = 4, -}; - -enum audit_ntp_type { - AUDIT_NTP_OFFSET = 0, - AUDIT_NTP_FREQ = 1, - AUDIT_NTP_STATUS = 2, - AUDIT_NTP_TAI = 3, - AUDIT_NTP_TICK = 4, - AUDIT_NTP_ADJUST = 5, - AUDIT_NTP_NVALS = 6, -}; - -typedef long int (*sys_call_ptr_t)(const struct pt_regs *); - -struct io_bitmap { - u64 sequence; - refcount_t refcnt; - unsigned int max; - long unsigned int bitmap[1024]; -}; - -enum irqreturn { - IRQ_NONE = 0, - IRQ_HANDLED = 1, - IRQ_WAKE_THREAD = 2, -}; - -typedef enum irqreturn irqreturn_t; - -typedef struct { - u16 __softirq_pending; - u8 kvm_cpu_l1tf_flush_l1d; - unsigned int __nmi_count; - unsigned int apic_timer_irqs; - unsigned int irq_spurious_count; - unsigned int icr_read_retry_count; - unsigned int kvm_posted_intr_ipis; - unsigned int kvm_posted_intr_wakeup_ipis; - unsigned int kvm_posted_intr_nested_ipis; - unsigned int x86_platform_ipis; - unsigned int apic_perf_irqs; - unsigned int apic_irq_work_irqs; - unsigned int irq_resched_count; - unsigned int irq_call_count; - unsigned int irq_tlb_count; - unsigned int irq_thermal_count; - unsigned int irq_threshold_count; - unsigned int irq_deferred_error_count; - unsigned int irq_hv_callback_count; - unsigned int irq_hv_reenlightenment_count; - unsigned int hyperv_stimer0_count; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -} irq_cpustat_t; - -typedef irqreturn_t (*irq_handler_t)(int, void *); - -struct irqaction { - irq_handler_t handler; - void *dev_id; - void *percpu_dev_id; - struct irqaction *next; - irq_handler_t thread_fn; - struct task_struct *thread; - struct irqaction *secondary; - unsigned int irq; - unsigned int flags; - long unsigned int thread_flags; - long unsigned int thread_mask; - const char *name; - struct proc_dir_entry *dir; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct irq_affinity_notify { - unsigned int irq; - struct kref kref; - struct work_struct work; - void (*notify)(struct irq_affinity_notify *, const cpumask_t *); - void (*release)(struct kref *); -}; - -struct irq_affinity_desc { - struct cpumask mask; - unsigned int is_managed: 1; -}; - -enum irqchip_irq_state { - IRQCHIP_STATE_PENDING = 0, - IRQCHIP_STATE_ACTIVE = 1, - IRQCHIP_STATE_MASKED = 2, - IRQCHIP_STATE_LINE_LEVEL = 3, -}; - -enum { - EI_ETYPE_NONE = 0, - EI_ETYPE_NULL = 1, - EI_ETYPE_ERRNO = 2, - EI_ETYPE_ERRNO_NULL = 3, - EI_ETYPE_TRUE = 4, -}; - -struct syscall_metadata { - const char *name; - int syscall_nr; - int nb_args; - const char **types; - const char **args; - struct list_head enter_fields; - struct trace_event_call *enter_event; - struct trace_event_call *exit_event; -}; - -struct irqentry_state { - union { - bool exit_rcu; - bool lockdep; - }; -}; - -typedef struct irqentry_state irqentry_state_t; - -struct irq_desc; - -typedef void (*irq_flow_handler_t)(struct irq_desc *); - -struct msi_desc; - -struct irq_common_data { - unsigned int state_use_accessors; - unsigned int node; - void *handler_data; - struct msi_desc *msi_desc; - cpumask_var_t affinity; - cpumask_var_t effective_affinity; -}; - -struct irq_chip; - -struct irq_data { - u32 mask; - unsigned int irq; - long unsigned int hwirq; - struct irq_common_data *common; - struct irq_chip *chip; - struct irq_domain *domain; - struct irq_data *parent_data; - void *chip_data; -}; - -struct irq_desc { - struct irq_common_data irq_common_data; - struct irq_data irq_data; - unsigned int *kstat_irqs; - irq_flow_handler_t handle_irq; - struct irqaction *action; - unsigned int status_use_accessors; - unsigned int core_internal_state__do_not_mess_with_it; - unsigned int depth; - unsigned int wake_depth; - unsigned int tot_count; - unsigned int irq_count; - long unsigned int last_unhandled; - unsigned int irqs_unhandled; - atomic_t threads_handled; - int threads_handled_last; - raw_spinlock_t lock; - struct cpumask *percpu_enabled; - const struct cpumask *percpu_affinity; - const struct cpumask *affinity_hint; - struct irq_affinity_notify *affinity_notify; - cpumask_var_t pending_mask; - long unsigned int threads_oneshot; - atomic_t threads_active; - wait_queue_head_t wait_for_threads; - unsigned int nr_actions; - unsigned int no_suspend_depth; - unsigned int cond_suspend_depth; - unsigned int force_resume_depth; - struct proc_dir_entry *dir; - struct callback_head rcu; - struct kobject kobj; - struct mutex request_mutex; - int parent_irq; - struct module *owner; - const char *name; - long: 64; -}; - -struct x86_msi_addr_lo { - union { - struct { - u32 reserved_0: 2; - u32 dest_mode_logical: 1; - u32 redirect_hint: 1; - u32 reserved_1: 1; - u32 virt_destid_8_14: 7; - u32 destid_0_7: 8; - u32 base_address: 12; - }; - struct { - u32 dmar_reserved_0: 2; - u32 dmar_index_15: 1; - u32 dmar_subhandle_valid: 1; - u32 dmar_format: 1; - u32 dmar_index_0_14: 15; - u32 dmar_base_address: 12; - }; - }; -}; - -typedef struct x86_msi_addr_lo arch_msi_msg_addr_lo_t; - -struct x86_msi_addr_hi { - u32 reserved: 8; - u32 destid_8_31: 24; -}; - -typedef struct x86_msi_addr_hi arch_msi_msg_addr_hi_t; - -struct x86_msi_data { - u32 vector: 8; - u32 delivery_mode: 3; - u32 dest_mode_logical: 1; - u32 reserved: 2; - u32 active_low: 1; - u32 is_level: 1; - u32 dmar_subhandle; -} __attribute__((packed)); - -typedef struct x86_msi_data arch_msi_msg_data_t; - -struct msi_msg { - union { - u32 address_lo; - arch_msi_msg_addr_lo_t arch_addr_lo; - }; - union { - u32 address_hi; - arch_msi_msg_addr_hi_t arch_addr_hi; - }; - union { - u32 data; - arch_msi_msg_data_t arch_data; - }; -}; - -struct platform_msi_priv_data; - -struct platform_msi_desc { - struct platform_msi_priv_data *msi_priv_data; - u16 msi_index; -}; - -struct fsl_mc_msi_desc { - u16 msi_index; -}; - -struct ti_sci_inta_msi_desc { - u16 dev_index; -}; - -struct msi_desc { - struct list_head list; - unsigned int irq; - unsigned int nvec_used; - struct device *dev; - struct msi_msg msg; - struct irq_affinity_desc *affinity; - const void *iommu_cookie; - void (*write_msi_msg)(struct msi_desc *, void *); - void *write_msi_msg_data; - union { - struct { - u32 masked; - struct { - u8 is_msix: 1; - u8 multiple: 3; - u8 multi_cap: 3; - u8 maskbit: 1; - u8 is_64: 1; - u8 is_virtual: 1; - u16 entry_nr; - unsigned int default_irq; - } msi_attrib; - union { - u8 mask_pos; - void *mask_base; - }; - }; - struct platform_msi_desc platform; - struct fsl_mc_msi_desc fsl_mc; - struct ti_sci_inta_msi_desc inta; - }; -}; - -struct irq_chip { - struct device *parent_device; - const char *name; - unsigned int (*irq_startup)(struct irq_data *); - void (*irq_shutdown)(struct irq_data *); - void (*irq_enable)(struct irq_data *); - void (*irq_disable)(struct irq_data *); - void (*irq_ack)(struct irq_data *); - void (*irq_mask)(struct irq_data *); - void (*irq_mask_ack)(struct irq_data *); - void (*irq_unmask)(struct irq_data *); - void (*irq_eoi)(struct irq_data *); - int (*irq_set_affinity)(struct irq_data *, const struct cpumask *, bool); - int (*irq_retrigger)(struct irq_data *); - int (*irq_set_type)(struct irq_data *, unsigned int); - int (*irq_set_wake)(struct irq_data *, unsigned int); - void (*irq_bus_lock)(struct irq_data *); - void (*irq_bus_sync_unlock)(struct irq_data *); - void (*irq_cpu_online)(struct irq_data *); - void (*irq_cpu_offline)(struct irq_data *); - void (*irq_suspend)(struct irq_data *); - void (*irq_resume)(struct irq_data *); - void (*irq_pm_shutdown)(struct irq_data *); - void (*irq_calc_mask)(struct irq_data *); - void (*irq_print_chip)(struct irq_data *, struct seq_file *); - int (*irq_request_resources)(struct irq_data *); - void (*irq_release_resources)(struct irq_data *); - void (*irq_compose_msi_msg)(struct irq_data *, struct msi_msg *); - void (*irq_write_msi_msg)(struct irq_data *, struct msi_msg *); - int (*irq_get_irqchip_state)(struct irq_data *, enum irqchip_irq_state, bool *); - int (*irq_set_irqchip_state)(struct irq_data *, enum irqchip_irq_state, bool); - int (*irq_set_vcpu_affinity)(struct irq_data *, void *); - void (*ipi_send_single)(struct irq_data *, unsigned int); - void (*ipi_send_mask)(struct irq_data *, const struct cpumask *); - int (*irq_nmi_setup)(struct irq_data *); - void (*irq_nmi_teardown)(struct irq_data *); - long unsigned int flags; -}; - -struct irq_chip_regs { - long unsigned int enable; - long unsigned int disable; - long unsigned int mask; - long unsigned int ack; - long unsigned int eoi; - long unsigned int type; - long unsigned int polarity; -}; - -struct irq_chip_type { - struct irq_chip chip; - struct irq_chip_regs regs; - irq_flow_handler_t handler; - u32 type; - u32 mask_cache_priv; - u32 *mask_cache; -}; - -struct irq_chip_generic { - raw_spinlock_t lock; - void *reg_base; - u32 (*reg_readl)(void *); - void (*reg_writel)(u32, void *); - void (*suspend)(struct irq_chip_generic *); - void (*resume)(struct irq_chip_generic *); - unsigned int irq_base; - unsigned int irq_cnt; - u32 mask_cache; - u32 type_cache; - u32 polarity_cache; - u32 wake_enabled; - u32 wake_active; - unsigned int num_ct; - void *private; - long unsigned int installed; - long unsigned int unused; - struct irq_domain *domain; - struct list_head list; - struct irq_chip_type chip_types[0]; -}; - -enum irq_gc_flags { - IRQ_GC_INIT_MASK_CACHE = 1, - IRQ_GC_INIT_NESTED_LOCK = 2, - IRQ_GC_MASK_CACHE_PER_TYPE = 4, - IRQ_GC_NO_MASK = 8, - IRQ_GC_BE_IO = 16, -}; - -struct irq_domain_chip_generic { - unsigned int irqs_per_chip; - unsigned int num_chips; - unsigned int irq_flags_to_clear; - unsigned int irq_flags_to_set; - enum irq_gc_flags gc_flags; - struct irq_chip_generic *gc[0]; -}; - -struct alt_instr { - s32 instr_offset; - s32 repl_offset; - u16 cpuid; - u8 instrlen; - u8 replacementlen; -}; - -struct timens_offset { - s64 sec; - u64 nsec; -}; - -enum vm_fault_reason { - VM_FAULT_OOM = 1, - VM_FAULT_SIGBUS = 2, - VM_FAULT_MAJOR = 4, - VM_FAULT_WRITE = 8, - VM_FAULT_HWPOISON = 16, - VM_FAULT_HWPOISON_LARGE = 32, - VM_FAULT_SIGSEGV = 64, - VM_FAULT_NOPAGE = 256, - VM_FAULT_LOCKED = 512, - VM_FAULT_RETRY = 1024, - VM_FAULT_FALLBACK = 2048, - VM_FAULT_DONE_COW = 4096, - VM_FAULT_NEEDDSYNC = 8192, - VM_FAULT_HINDEX_MASK = 983040, -}; - -struct vm_special_mapping { - const char *name; - struct page **pages; - vm_fault_t (*fault)(const struct vm_special_mapping *, struct vm_area_struct *, struct vm_fault *); - int (*mremap)(const struct vm_special_mapping *, struct vm_area_struct *); -}; - -struct timens_offsets { - struct timespec64 monotonic; - struct timespec64 boottime; -}; - -struct time_namespace { - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct ns_common ns; - struct timens_offsets offsets; - struct page *vvar_page; - bool frozen_offsets; -}; - -struct pvclock_vcpu_time_info { - u32 version; - u32 pad0; - u64 tsc_timestamp; - u64 system_time; - u32 tsc_to_system_mul; - s8 tsc_shift; - u8 flags; - u8 pad[2]; -}; - -struct pvclock_vsyscall_time_info { - struct pvclock_vcpu_time_info pvti; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum vdso_clock_mode { - VDSO_CLOCKMODE_NONE = 0, - VDSO_CLOCKMODE_TSC = 1, - VDSO_CLOCKMODE_PVCLOCK = 2, - VDSO_CLOCKMODE_HVCLOCK = 3, - VDSO_CLOCKMODE_MAX = 4, - VDSO_CLOCKMODE_TIMENS = 2147483647, -}; - -struct arch_vdso_data {}; - -struct vdso_timestamp { - u64 sec; - u64 nsec; -}; - -struct vdso_data { - u32 seq; - s32 clock_mode; - u64 cycle_last; - u64 mask; - u32 mult; - u32 shift; - union { - struct vdso_timestamp basetime[12]; - struct timens_offset offset[12]; - }; - s32 tz_minuteswest; - s32 tz_dsttime; - u32 hrtimer_res; - u32 __unused; - struct arch_vdso_data arch_data; -}; - -struct ms_hyperv_tsc_page { - volatile u32 tsc_sequence; - u32 reserved1; - volatile u64 tsc_scale; - volatile s64 tsc_offset; -}; - -enum { - TASKSTATS_CMD_UNSPEC = 0, - TASKSTATS_CMD_GET = 1, - TASKSTATS_CMD_NEW = 2, - __TASKSTATS_CMD_MAX = 3, -}; - -enum cpu_usage_stat { - CPUTIME_USER = 0, - CPUTIME_NICE = 1, - CPUTIME_SYSTEM = 2, - CPUTIME_SOFTIRQ = 3, - CPUTIME_IRQ = 4, - CPUTIME_IDLE = 5, - CPUTIME_IOWAIT = 6, - CPUTIME_STEAL = 7, - CPUTIME_GUEST = 8, - CPUTIME_GUEST_NICE = 9, - NR_STATS = 10, -}; - -enum bpf_cgroup_storage_type { - BPF_CGROUP_STORAGE_SHARED = 0, - BPF_CGROUP_STORAGE_PERCPU = 1, - __BPF_CGROUP_STORAGE_MAX = 2, -}; - -enum bpf_tramp_prog_type { - BPF_TRAMP_FENTRY = 0, - BPF_TRAMP_FEXIT = 1, - BPF_TRAMP_MODIFY_RETURN = 2, - BPF_TRAMP_MAX = 3, - BPF_TRAMP_REPLACE = 4, -}; - -enum psi_task_count { - NR_IOWAIT = 0, - NR_MEMSTALL = 1, - NR_RUNNING = 2, - NR_ONCPU = 3, - NR_PSI_TASK_COUNTS = 4, -}; - -enum psi_states { - PSI_IO_SOME = 0, - PSI_IO_FULL = 1, - PSI_MEM_SOME = 2, - PSI_MEM_FULL = 3, - PSI_CPU_SOME = 4, - PSI_CPU_FULL = 5, - PSI_NONIDLE = 6, - NR_PSI_STATES = 7, -}; - -enum psi_aggregators { - PSI_AVGS = 0, - PSI_POLL = 1, - NR_PSI_AGGREGATORS = 2, -}; - -enum cgroup_subsys_id { - cpuset_cgrp_id = 0, - cpu_cgrp_id = 1, - cpuacct_cgrp_id = 2, - io_cgrp_id = 3, - memory_cgrp_id = 4, - devices_cgrp_id = 5, - freezer_cgrp_id = 6, - net_cls_cgrp_id = 7, - perf_event_cgrp_id = 8, - net_prio_cgrp_id = 9, - hugetlb_cgrp_id = 10, - pids_cgrp_id = 11, - rdma_cgrp_id = 12, - misc_cgrp_id = 13, - CGROUP_SUBSYS_COUNT = 14, -}; - -struct vdso_exception_table_entry { - int insn; - int fixup; -}; - -struct cpuinfo_x86 { - __u8 x86; - __u8 x86_vendor; - __u8 x86_model; - __u8 x86_stepping; - int x86_tlbsize; - __u32 vmx_capability[3]; - __u8 x86_virt_bits; - __u8 x86_phys_bits; - __u8 x86_coreid_bits; - __u8 cu_id; - __u32 extended_cpuid_level; - int cpuid_level; - union { - __u32 x86_capability[21]; - long unsigned int x86_capability_alignment; - }; - char x86_vendor_id[16]; - char x86_model_id[64]; - unsigned int x86_cache_size; - int x86_cache_alignment; - int x86_cache_max_rmid; - int x86_cache_occ_scale; - int x86_cache_mbm_width_offset; - int x86_power; - long unsigned int loops_per_jiffy; - u16 x86_max_cores; - u16 apicid; - u16 initial_apicid; - u16 x86_clflush_size; - u16 booted_cores; - u16 phys_proc_id; - u16 logical_proc_id; - u16 cpu_core_id; - u16 cpu_die_id; - u16 logical_die_id; - u16 cpu_index; - u32 microcode; - u8 x86_cache_bits; - unsigned int initialized: 1; -}; - -enum syscall_work_bit { - SYSCALL_WORK_BIT_SECCOMP = 0, - SYSCALL_WORK_BIT_SYSCALL_TRACEPOINT = 1, - SYSCALL_WORK_BIT_SYSCALL_TRACE = 2, - SYSCALL_WORK_BIT_SYSCALL_EMU = 3, - SYSCALL_WORK_BIT_SYSCALL_AUDIT = 4, - SYSCALL_WORK_BIT_SYSCALL_USER_DISPATCH = 5, - SYSCALL_WORK_BIT_SYSCALL_EXIT_TRAP = 6, -}; - -struct seccomp_data { - int nr; - __u32 arch; - __u64 instruction_pointer; - __u64 args[6]; -}; - -enum x86_pf_error_code { - X86_PF_PROT = 1, - X86_PF_WRITE = 2, - X86_PF_USER = 4, - X86_PF_RSVD = 8, - X86_PF_INSTR = 16, - X86_PF_PK = 32, - X86_PF_SGX = 32768, -}; - -struct trace_event_raw_emulate_vsyscall { - struct trace_entry ent; - int nr; - char __data[0]; -}; - -struct trace_event_data_offsets_emulate_vsyscall {}; - -typedef void (*btf_trace_emulate_vsyscall)(void *, int); - -enum { - EMULATE = 0, - XONLY = 1, - NONE = 2, -}; - -enum perf_type_id { - PERF_TYPE_HARDWARE = 0, - PERF_TYPE_SOFTWARE = 1, - PERF_TYPE_TRACEPOINT = 2, - PERF_TYPE_HW_CACHE = 3, - PERF_TYPE_RAW = 4, - PERF_TYPE_BREAKPOINT = 5, - PERF_TYPE_MAX = 6, -}; - -enum perf_hw_id { - PERF_COUNT_HW_CPU_CYCLES = 0, - PERF_COUNT_HW_INSTRUCTIONS = 1, - PERF_COUNT_HW_CACHE_REFERENCES = 2, - PERF_COUNT_HW_CACHE_MISSES = 3, - PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, - PERF_COUNT_HW_BRANCH_MISSES = 5, - PERF_COUNT_HW_BUS_CYCLES = 6, - PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7, - PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8, - PERF_COUNT_HW_REF_CPU_CYCLES = 9, - PERF_COUNT_HW_MAX = 10, -}; - -enum perf_hw_cache_id { - PERF_COUNT_HW_CACHE_L1D = 0, - PERF_COUNT_HW_CACHE_L1I = 1, - PERF_COUNT_HW_CACHE_LL = 2, - PERF_COUNT_HW_CACHE_DTLB = 3, - PERF_COUNT_HW_CACHE_ITLB = 4, - PERF_COUNT_HW_CACHE_BPU = 5, - PERF_COUNT_HW_CACHE_NODE = 6, - PERF_COUNT_HW_CACHE_MAX = 7, -}; - -enum perf_hw_cache_op_id { - PERF_COUNT_HW_CACHE_OP_READ = 0, - PERF_COUNT_HW_CACHE_OP_WRITE = 1, - PERF_COUNT_HW_CACHE_OP_PREFETCH = 2, - PERF_COUNT_HW_CACHE_OP_MAX = 3, -}; - -enum perf_hw_cache_op_result_id { - PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0, - PERF_COUNT_HW_CACHE_RESULT_MISS = 1, - PERF_COUNT_HW_CACHE_RESULT_MAX = 2, -}; - -enum perf_event_sample_format { - PERF_SAMPLE_IP = 1, - PERF_SAMPLE_TID = 2, - PERF_SAMPLE_TIME = 4, - PERF_SAMPLE_ADDR = 8, - PERF_SAMPLE_READ = 16, - PERF_SAMPLE_CALLCHAIN = 32, - PERF_SAMPLE_ID = 64, - PERF_SAMPLE_CPU = 128, - PERF_SAMPLE_PERIOD = 256, - PERF_SAMPLE_STREAM_ID = 512, - PERF_SAMPLE_RAW = 1024, - PERF_SAMPLE_BRANCH_STACK = 2048, - PERF_SAMPLE_REGS_USER = 4096, - PERF_SAMPLE_STACK_USER = 8192, - PERF_SAMPLE_WEIGHT = 16384, - PERF_SAMPLE_DATA_SRC = 32768, - PERF_SAMPLE_IDENTIFIER = 65536, - PERF_SAMPLE_TRANSACTION = 131072, - PERF_SAMPLE_REGS_INTR = 262144, - PERF_SAMPLE_PHYS_ADDR = 524288, - PERF_SAMPLE_AUX = 1048576, - PERF_SAMPLE_CGROUP = 2097152, - PERF_SAMPLE_DATA_PAGE_SIZE = 4194304, - PERF_SAMPLE_CODE_PAGE_SIZE = 8388608, - PERF_SAMPLE_WEIGHT_STRUCT = 16777216, - PERF_SAMPLE_MAX = 33554432, - __PERF_SAMPLE_CALLCHAIN_EARLY = 0, -}; - -enum perf_branch_sample_type { - PERF_SAMPLE_BRANCH_USER = 1, - PERF_SAMPLE_BRANCH_KERNEL = 2, - PERF_SAMPLE_BRANCH_HV = 4, - PERF_SAMPLE_BRANCH_ANY = 8, - PERF_SAMPLE_BRANCH_ANY_CALL = 16, - PERF_SAMPLE_BRANCH_ANY_RETURN = 32, - PERF_SAMPLE_BRANCH_IND_CALL = 64, - PERF_SAMPLE_BRANCH_ABORT_TX = 128, - PERF_SAMPLE_BRANCH_IN_TX = 256, - PERF_SAMPLE_BRANCH_NO_TX = 512, - PERF_SAMPLE_BRANCH_COND = 1024, - PERF_SAMPLE_BRANCH_CALL_STACK = 2048, - PERF_SAMPLE_BRANCH_IND_JUMP = 4096, - PERF_SAMPLE_BRANCH_CALL = 8192, - PERF_SAMPLE_BRANCH_NO_FLAGS = 16384, - PERF_SAMPLE_BRANCH_NO_CYCLES = 32768, - PERF_SAMPLE_BRANCH_TYPE_SAVE = 65536, - PERF_SAMPLE_BRANCH_HW_INDEX = 131072, - PERF_SAMPLE_BRANCH_MAX = 262144, -}; - -struct perf_event_mmap_page { - __u32 version; - __u32 compat_version; - __u32 lock; - __u32 index; - __s64 offset; - __u64 time_enabled; - __u64 time_running; - union { - __u64 capabilities; - struct { - __u64 cap_bit0: 1; - __u64 cap_bit0_is_deprecated: 1; - __u64 cap_user_rdpmc: 1; - __u64 cap_user_time: 1; - __u64 cap_user_time_zero: 1; - __u64 cap_user_time_short: 1; - __u64 cap_____res: 58; - }; - }; - __u16 pmc_width; - __u16 time_shift; - __u32 time_mult; - __u64 time_offset; - __u64 time_zero; - __u32 size; - __u32 __reserved_1; - __u64 time_cycles; - __u64 time_mask; - __u8 __reserved[928]; - __u64 data_head; - __u64 data_tail; - __u64 data_offset; - __u64 data_size; - __u64 aux_head; - __u64 aux_tail; - __u64 aux_offset; - __u64 aux_size; -}; - -struct pv_info { - u16 extra_user_64bit_cs; - const char *name; -}; - -typedef bool (*smp_cond_func_t)(int, void *); - -struct ldt_struct { - struct desc_struct *entries; - unsigned int nr_entries; - int slot; -}; - -enum apic_delivery_modes { - APIC_DELIVERY_MODE_FIXED = 0, - APIC_DELIVERY_MODE_LOWESTPRIO = 1, - APIC_DELIVERY_MODE_SMI = 2, - APIC_DELIVERY_MODE_NMI = 4, - APIC_DELIVERY_MODE_INIT = 5, - APIC_DELIVERY_MODE_EXTINT = 7, -}; - -struct physid_mask { - long unsigned int mask[512]; -}; - -typedef struct physid_mask physid_mask_t; - -struct x86_pmu_capability { - int version; - int num_counters_gp; - int num_counters_fixed; - int bit_width_gp; - int bit_width_fixed; - unsigned int events_mask; - int events_mask_len; -}; - -struct debug_store { - u64 bts_buffer_base; - u64 bts_index; - u64 bts_absolute_maximum; - u64 bts_interrupt_threshold; - u64 pebs_buffer_base; - u64 pebs_index; - u64 pebs_absolute_maximum; - u64 pebs_interrupt_threshold; - u64 pebs_event_reset[12]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum stack_type { - STACK_TYPE_UNKNOWN = 0, - STACK_TYPE_TASK = 1, - STACK_TYPE_IRQ = 2, - STACK_TYPE_SOFTIRQ = 3, - STACK_TYPE_ENTRY = 4, - STACK_TYPE_EXCEPTION = 5, - STACK_TYPE_EXCEPTION_LAST = 10, -}; - -struct stack_info { - enum stack_type type; - long unsigned int *begin; - long unsigned int *end; - long unsigned int *next_sp; -}; - -struct stack_frame { - struct stack_frame *next_frame; - long unsigned int return_address; -}; - -struct stack_frame_ia32 { - u32 next_frame; - u32 return_address; -}; - -struct perf_guest_switch_msr { - unsigned int msr; - u64 host; - u64 guest; -}; - -struct perf_guest_info_callbacks { - int (*is_in_guest)(); - int (*is_user_mode)(); - long unsigned int (*get_guest_ip)(); - void (*handle_intel_pt_intr)(); -}; - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device *, struct device_attribute *, char *); - ssize_t (*store)(struct device *, struct device_attribute *, const char *, size_t); -}; - -enum perf_event_x86_regs { - PERF_REG_X86_AX = 0, - PERF_REG_X86_BX = 1, - PERF_REG_X86_CX = 2, - PERF_REG_X86_DX = 3, - PERF_REG_X86_SI = 4, - PERF_REG_X86_DI = 5, - PERF_REG_X86_BP = 6, - PERF_REG_X86_SP = 7, - PERF_REG_X86_IP = 8, - PERF_REG_X86_FLAGS = 9, - PERF_REG_X86_CS = 10, - PERF_REG_X86_SS = 11, - PERF_REG_X86_DS = 12, - PERF_REG_X86_ES = 13, - PERF_REG_X86_FS = 14, - PERF_REG_X86_GS = 15, - PERF_REG_X86_R8 = 16, - PERF_REG_X86_R9 = 17, - PERF_REG_X86_R10 = 18, - PERF_REG_X86_R11 = 19, - PERF_REG_X86_R12 = 20, - PERF_REG_X86_R13 = 21, - PERF_REG_X86_R14 = 22, - PERF_REG_X86_R15 = 23, - PERF_REG_X86_32_MAX = 16, - PERF_REG_X86_64_MAX = 24, - PERF_REG_X86_XMM0 = 32, - PERF_REG_X86_XMM1 = 34, - PERF_REG_X86_XMM2 = 36, - PERF_REG_X86_XMM3 = 38, - PERF_REG_X86_XMM4 = 40, - PERF_REG_X86_XMM5 = 42, - PERF_REG_X86_XMM6 = 44, - PERF_REG_X86_XMM7 = 46, - PERF_REG_X86_XMM8 = 48, - PERF_REG_X86_XMM9 = 50, - PERF_REG_X86_XMM10 = 52, - PERF_REG_X86_XMM11 = 54, - PERF_REG_X86_XMM12 = 56, - PERF_REG_X86_XMM13 = 58, - PERF_REG_X86_XMM14 = 60, - PERF_REG_X86_XMM15 = 62, - PERF_REG_X86_XMM_MAX = 64, -}; - -struct perf_callchain_entry_ctx { - struct perf_callchain_entry *entry; - u32 max_stack; - u32 nr; - short int contexts; - bool contexts_maxed; -}; - -struct perf_pmu_events_attr { - struct device_attribute attr; - u64 id; - const char *event_str; -}; - -struct perf_pmu_events_ht_attr { - struct device_attribute attr; - u64 id; - const char *event_str_ht; - const char *event_str_noht; -}; - -struct perf_pmu_events_hybrid_attr { - struct device_attribute attr; - u64 id; - const char *event_str; - u64 pmu_type; -}; - -struct apic { - void (*eoi_write)(u32, u32); - void (*native_eoi_write)(u32, u32); - void (*write)(u32, u32); - u32 (*read)(u32); - void (*wait_icr_idle)(); - u32 (*safe_wait_icr_idle)(); - void (*send_IPI)(int, int); - void (*send_IPI_mask)(const struct cpumask *, int); - void (*send_IPI_mask_allbutself)(const struct cpumask *, int); - void (*send_IPI_allbutself)(int); - void (*send_IPI_all)(int); - void (*send_IPI_self)(int); - u32 disable_esr; - enum apic_delivery_modes delivery_mode; - bool dest_mode_logical; - u32 (*calc_dest_apicid)(unsigned int); - u64 (*icr_read)(); - void (*icr_write)(u32, u32); - int (*probe)(); - int (*acpi_madt_oem_check)(char *, char *); - int (*apic_id_valid)(u32); - int (*apic_id_registered)(); - bool (*check_apicid_used)(physid_mask_t *, int); - void (*init_apic_ldr)(); - void (*ioapic_phys_id_map)(physid_mask_t *, physid_mask_t *); - void (*setup_apic_routing)(); - int (*cpu_present_to_apicid)(int); - void (*apicid_to_cpu_present)(int, physid_mask_t *); - int (*check_phys_apicid_present)(int); - int (*phys_pkg_id)(int, int); - u32 (*get_apic_id)(long unsigned int); - u32 (*set_apic_id)(unsigned int); - int (*wakeup_secondary_cpu)(int, long unsigned int); - void (*inquire_remote_apic)(int); - char *name; -}; - -enum { - NMI_LOCAL = 0, - NMI_UNKNOWN = 1, - NMI_SERR = 2, - NMI_IO_CHECK = 3, - NMI_MAX = 4, -}; - -typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *); - -struct nmiaction { - struct list_head list; - nmi_handler_t handler; - u64 max_duration; - long unsigned int flags; - const char *name; -}; - -struct gdt_page { - struct desc_struct gdt[16]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct cyc2ns_data { - u32 cyc2ns_mul; - u32 cyc2ns_shift; - u64 cyc2ns_offset; -}; - -struct unwind_state { - struct stack_info stack_info; - long unsigned int stack_mask; - struct task_struct *task; - int graph_idx; - bool error; - bool signal; - bool full_regs; - long unsigned int sp; - long unsigned int bp; - long unsigned int ip; - struct pt_regs *regs; - struct pt_regs *prev_regs; -}; - -enum extra_reg_type { - EXTRA_REG_NONE = 4294967295, - EXTRA_REG_RSP_0 = 0, - EXTRA_REG_RSP_1 = 1, - EXTRA_REG_LBR = 2, - EXTRA_REG_LDLAT = 3, - EXTRA_REG_FE = 4, - EXTRA_REG_MAX = 5, -}; - -struct event_constraint { - union { - long unsigned int idxmsk[1]; - u64 idxmsk64; - }; - u64 code; - u64 cmask; - int weight; - int overlap; - int flags; - unsigned int size; -}; - -struct amd_nb { - int nb_id; - int refcnt; - struct perf_event *owners[64]; - struct event_constraint event_constraints[64]; -}; - -struct er_account { - raw_spinlock_t lock; - u64 config; - u64 reg; - atomic_t ref; -}; - -struct intel_shared_regs { - struct er_account regs[5]; - int refcnt; - unsigned int core_id; -}; - -enum intel_excl_state_type { - INTEL_EXCL_UNUSED = 0, - INTEL_EXCL_SHARED = 1, - INTEL_EXCL_EXCLUSIVE = 2, -}; - -struct intel_excl_states { - enum intel_excl_state_type state[64]; - bool sched_started; -}; - -struct intel_excl_cntrs { - raw_spinlock_t lock; - struct intel_excl_states states[2]; - union { - u16 has_exclusive[2]; - u32 exclusive_present; - }; - int refcnt; - unsigned int core_id; -}; - -enum { - X86_PERF_KFREE_SHARED = 0, - X86_PERF_KFREE_EXCL = 1, - X86_PERF_KFREE_MAX = 2, -}; - -struct cpu_hw_events { - struct perf_event *events[64]; - long unsigned int active_mask[1]; - long unsigned int dirty[1]; - int enabled; - int n_events; - int n_added; - int n_txn; - int n_txn_pair; - int n_txn_metric; - int assign[64]; - u64 tags[64]; - struct perf_event *event_list[64]; - struct event_constraint *event_constraint[64]; - int n_excl; - unsigned int txn_flags; - int is_fake; - struct debug_store *ds; - void *ds_pebs_vaddr; - void *ds_bts_vaddr; - u64 pebs_enabled; - int n_pebs; - int n_large_pebs; - int n_pebs_via_pt; - int pebs_output; - u64 pebs_data_cfg; - u64 active_pebs_data_cfg; - int pebs_record_size; - int lbr_users; - int lbr_pebs_users; - struct perf_branch_stack lbr_stack; - struct perf_branch_entry lbr_entries[32]; - union { - struct er_account *lbr_sel; - struct er_account *lbr_ctl; - }; - u64 br_sel; - void *last_task_ctx; - int last_log_id; - int lbr_select; - void *lbr_xsave; - u64 intel_ctrl_guest_mask; - u64 intel_ctrl_host_mask; - struct perf_guest_switch_msr guest_switch_msrs[64]; - u64 intel_cp_status; - struct intel_shared_regs *shared_regs; - struct event_constraint *constraint_list; - struct intel_excl_cntrs *excl_cntrs; - int excl_thread_id; - u64 tfa_shadow; - int n_metric; - struct amd_nb *amd_nb; - u64 perf_ctr_virt_mask; - int n_pair; - void *kfree_on_online[2]; - struct pmu *pmu; -}; - -struct extra_reg { - unsigned int event; - unsigned int msr; - u64 config_mask; - u64 valid_mask; - int idx; - bool extra_msr_access; -}; - -union perf_capabilities { - struct { - u64 lbr_format: 6; - u64 pebs_trap: 1; - u64 pebs_arch_reg: 1; - u64 pebs_format: 4; - u64 smm_freeze: 1; - u64 full_width_write: 1; - u64 pebs_baseline: 1; - u64 perf_metrics: 1; - u64 pebs_output_pt_available: 1; - u64 anythread_deprecated: 1; - }; - u64 capabilities; -}; - -struct x86_pmu_quirk { - struct x86_pmu_quirk *next; - void (*func)(); -}; - -enum { - x86_lbr_exclusive_lbr = 0, - x86_lbr_exclusive_bts = 1, - x86_lbr_exclusive_pt = 2, - x86_lbr_exclusive_max = 3, -}; - -struct x86_hybrid_pmu { - struct pmu pmu; - const char *name; - u8 cpu_type; - cpumask_t supported_cpus; - union perf_capabilities intel_cap; - u64 intel_ctrl; - int max_pebs_events; - int num_counters; - int num_counters_fixed; - struct event_constraint unconstrained; - u64 hw_cache_event_ids[42]; - u64 hw_cache_extra_regs[42]; - struct event_constraint *event_constraints; - struct event_constraint *pebs_constraints; - struct extra_reg *extra_regs; - unsigned int late_ack: 1; - unsigned int mid_ack: 1; - unsigned int enabled_ack: 1; -}; - -enum hybrid_pmu_type { - hybrid_big = 64, - hybrid_small = 32, - hybrid_big_small = 96, -}; - -struct x86_pmu { - const char *name; - int version; - int (*handle_irq)(struct pt_regs *); - void (*disable_all)(); - void (*enable_all)(int); - void (*enable)(struct perf_event *); - void (*disable)(struct perf_event *); - void (*add)(struct perf_event *); - void (*del)(struct perf_event *); - void (*read)(struct perf_event *); - int (*hw_config)(struct perf_event *); - int (*schedule_events)(struct cpu_hw_events *, int, int *); - unsigned int eventsel; - unsigned int perfctr; - int (*addr_offset)(int, bool); - int (*rdpmc_index)(int); - u64 (*event_map)(int); - int max_events; - int num_counters; - int num_counters_fixed; - int cntval_bits; - u64 cntval_mask; - union { - long unsigned int events_maskl; - long unsigned int events_mask[1]; - }; - int events_mask_len; - int apic; - u64 max_period; - struct event_constraint * (*get_event_constraints)(struct cpu_hw_events *, int, struct perf_event *); - void (*put_event_constraints)(struct cpu_hw_events *, struct perf_event *); - void (*start_scheduling)(struct cpu_hw_events *); - void (*commit_scheduling)(struct cpu_hw_events *, int, int); - void (*stop_scheduling)(struct cpu_hw_events *); - struct event_constraint *event_constraints; - struct x86_pmu_quirk *quirks; - int perfctr_second_write; - u64 (*limit_period)(struct perf_event *, u64); - unsigned int late_ack: 1; - unsigned int mid_ack: 1; - unsigned int enabled_ack: 1; - int attr_rdpmc_broken; - int attr_rdpmc; - struct attribute **format_attrs; - ssize_t (*events_sysfs_show)(char *, u64); - const struct attribute_group **attr_update; - long unsigned int attr_freeze_on_smi; - int (*cpu_prepare)(int); - void (*cpu_starting)(int); - void (*cpu_dying)(int); - void (*cpu_dead)(int); - void (*check_microcode)(); - void (*sched_task)(struct perf_event_context *, bool); - u64 intel_ctrl; - union perf_capabilities intel_cap; - unsigned int bts: 1; - unsigned int bts_active: 1; - unsigned int pebs: 1; - unsigned int pebs_active: 1; - unsigned int pebs_broken: 1; - unsigned int pebs_prec_dist: 1; - unsigned int pebs_no_tlb: 1; - unsigned int pebs_no_isolation: 1; - unsigned int pebs_block: 1; - int pebs_record_size; - int pebs_buffer_size; - int max_pebs_events; - void (*drain_pebs)(struct pt_regs *, struct perf_sample_data *); - struct event_constraint *pebs_constraints; - void (*pebs_aliases)(struct perf_event *); - long unsigned int large_pebs_flags; - u64 rtm_abort_event; - unsigned int lbr_tos; - unsigned int lbr_from; - unsigned int lbr_to; - unsigned int lbr_info; - unsigned int lbr_nr; - union { - u64 lbr_sel_mask; - u64 lbr_ctl_mask; - }; - union { - const int *lbr_sel_map; - int *lbr_ctl_map; - }; - bool lbr_double_abort; - bool lbr_pt_coexist; - unsigned int lbr_depth_mask: 8; - unsigned int lbr_deep_c_reset: 1; - unsigned int lbr_lip: 1; - unsigned int lbr_cpl: 1; - unsigned int lbr_filter: 1; - unsigned int lbr_call_stack: 1; - unsigned int lbr_mispred: 1; - unsigned int lbr_timed_lbr: 1; - unsigned int lbr_br_type: 1; - void (*lbr_reset)(); - void (*lbr_read)(struct cpu_hw_events *); - void (*lbr_save)(void *); - void (*lbr_restore)(void *); - atomic_t lbr_exclusive[3]; - int num_topdown_events; - u64 (*update_topdown_event)(struct perf_event *); - int (*set_topdown_event_period)(struct perf_event *); - void (*swap_task_ctx)(struct perf_event_context *, struct perf_event_context *); - unsigned int amd_nb_constraints: 1; - u64 perf_ctr_pair_en; - struct extra_reg *extra_regs; - unsigned int flags; - struct perf_guest_switch_msr * (*guest_get_msrs)(int *); - int (*check_period)(struct perf_event *, u64); - int (*aux_output_match)(struct perf_event *); - int (*filter_match)(struct perf_event *); - int num_hybrid_pmus; - struct x86_hybrid_pmu *hybrid_pmu; - u8 (*get_hybrid_cpu_type)(); -}; - -struct sched_state { - int weight; - int event; - int counter; - int unassigned; - int nr_gp; - u64 used; -}; - -struct perf_sched { - int max_weight; - int max_events; - int max_gp; - int saved_states; - struct event_constraint **constraints; - struct sched_state state; - struct sched_state saved[2]; -}; - -struct perf_msr { - u64 msr; - struct attribute_group *grp; - bool (*test)(int, void *); - bool no_check; - u64 mask; -}; - -struct amd_uncore { - int id; - int refcnt; - int cpu; - int num_counters; - int rdpmc_base; - u32 msr_base; - cpumask_t *active_mask; - struct pmu *pmu; - struct perf_event *events[6]; - struct hlist_node node; -}; - -typedef int pci_power_t; - -typedef unsigned int pci_channel_state_t; - -typedef short unsigned int pci_dev_flags_t; - -struct pci_bus; - -struct pci_slot; - -struct aer_stats; - -struct rcec_ea; - -struct pci_driver; - -struct pcie_link_state; - -struct pci_vpd; - -struct pci_sriov; - -struct pci_p2pdma; - -struct pci_dev { - struct list_head bus_list; - struct pci_bus *bus; - struct pci_bus *subordinate; - void *sysdata; - struct proc_dir_entry *procent; - struct pci_slot *slot; - unsigned int devfn; - short unsigned int vendor; - short unsigned int device; - short unsigned int subsystem_vendor; - short unsigned int subsystem_device; - unsigned int class; - u8 revision; - u8 hdr_type; - u16 aer_cap; - struct aer_stats *aer_stats; - struct rcec_ea *rcec_ea; - struct pci_dev *rcec; - u8 pcie_cap; - u8 msi_cap; - u8 msix_cap; - u8 pcie_mpss: 3; - u8 rom_base_reg; - u8 pin; - u16 pcie_flags_reg; - long unsigned int *dma_alias_mask; - struct pci_driver *driver; - u64 dma_mask; - struct device_dma_parameters dma_parms; - pci_power_t current_state; - unsigned int imm_ready: 1; - u8 pm_cap; - unsigned int pme_support: 5; - unsigned int pme_poll: 1; - unsigned int d1_support: 1; - unsigned int d2_support: 1; - unsigned int no_d1d2: 1; - unsigned int no_d3cold: 1; - unsigned int bridge_d3: 1; - unsigned int d3cold_allowed: 1; - unsigned int mmio_always_on: 1; - unsigned int wakeup_prepared: 1; - unsigned int runtime_d3cold: 1; - unsigned int skip_bus_pm: 1; - unsigned int ignore_hotplug: 1; - unsigned int hotplug_user_indicators: 1; - unsigned int clear_retrain_link: 1; - unsigned int d3hot_delay; - unsigned int d3cold_delay; - struct pcie_link_state *link_state; - unsigned int ltr_path: 1; - u16 l1ss; - unsigned int eetlp_prefix_path: 1; - pci_channel_state_t error_state; - struct device dev; - int cfg_size; - unsigned int irq; - struct resource resource[17]; - bool match_driver; - unsigned int transparent: 1; - unsigned int io_window: 1; - unsigned int pref_window: 1; - unsigned int pref_64_window: 1; - unsigned int multifunction: 1; - unsigned int is_busmaster: 1; - unsigned int no_msi: 1; - unsigned int no_64bit_msi: 1; - unsigned int block_cfg_access: 1; - unsigned int broken_parity_status: 1; - unsigned int irq_reroute_variant: 2; - unsigned int msi_enabled: 1; - unsigned int msix_enabled: 1; - unsigned int ari_enabled: 1; - unsigned int ats_enabled: 1; - unsigned int pasid_enabled: 1; - unsigned int pri_enabled: 1; - unsigned int is_managed: 1; - unsigned int needs_freset: 1; - unsigned int state_saved: 1; - unsigned int is_physfn: 1; - unsigned int is_virtfn: 1; - unsigned int reset_fn: 1; - unsigned int is_hotplug_bridge: 1; - unsigned int shpc_managed: 1; - unsigned int is_thunderbolt: 1; - unsigned int untrusted: 1; - unsigned int external_facing: 1; - unsigned int broken_intx_masking: 1; - unsigned int io_window_1k: 1; - unsigned int irq_managed: 1; - unsigned int non_compliant_bars: 1; - unsigned int is_probed: 1; - unsigned int link_active_reporting: 1; - unsigned int no_vf_scan: 1; - unsigned int no_command_memory: 1; - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; - u32 saved_config_space[16]; - struct hlist_head saved_cap_space; - int rom_attr_enabled; - struct bin_attribute *res_attr[17]; - struct bin_attribute *res_attr_wc[17]; - unsigned int broken_cmd_compl: 1; - unsigned int ptm_root: 1; - unsigned int ptm_enabled: 1; - u8 ptm_granularity; - const struct attribute_group **msi_irq_groups; - struct pci_vpd *vpd; - u16 dpc_cap; - unsigned int dpc_rp_extensions: 1; - u8 dpc_rp_log_size; - union { - struct pci_sriov *sriov; - struct pci_dev *physfn; - }; - u16 ats_cap; - u8 ats_stu; - u16 pri_cap; - u32 pri_reqs_alloc; - unsigned int pasid_required: 1; - u16 pasid_cap; - u16 pasid_features; - struct pci_p2pdma *p2pdma; - u16 acs_cap; - phys_addr_t rom; - size_t romlen; - char *driver_override; - long unsigned int priv_flags; -}; - -struct pci_device_id { - __u32 vendor; - __u32 device; - __u32 subvendor; - __u32 subdevice; - __u32 class; - __u32 class_mask; - kernel_ulong_t driver_data; -}; - -struct hotplug_slot; - -struct pci_slot { - struct pci_bus *bus; - struct list_head list; - struct hotplug_slot *hotplug; - unsigned char number; - struct kobject kobj; -}; - -typedef short unsigned int pci_bus_flags_t; - -struct pci_ops; - -struct pci_bus { - struct list_head node; - struct pci_bus *parent; - struct list_head children; - struct list_head devices; - struct pci_dev *self; - struct list_head slots; - struct resource *resource[4]; - struct list_head resources; - struct resource busn_res; - struct pci_ops *ops; - void *sysdata; - struct proc_dir_entry *procdir; - unsigned char number; - unsigned char primary; - unsigned char max_bus_speed; - unsigned char cur_bus_speed; - char name[48]; - short unsigned int bridge_ctl; - pci_bus_flags_t bus_flags; - struct device *bridge; - struct device dev; - struct bin_attribute *legacy_io; - struct bin_attribute *legacy_mem; - unsigned int is_added: 1; -}; - -enum { - PCI_STD_RESOURCES = 0, - PCI_STD_RESOURCE_END = 5, - PCI_ROM_RESOURCE = 6, - PCI_IOV_RESOURCES = 7, - PCI_IOV_RESOURCE_END = 12, - PCI_BRIDGE_RESOURCES = 13, - PCI_BRIDGE_RESOURCE_END = 16, - PCI_NUM_RESOURCES = 17, - DEVICE_COUNT_RESOURCE = 17, -}; - -typedef unsigned int pcie_reset_state_t; - -struct pci_dynids { - spinlock_t lock; - struct list_head list; -}; - -struct pci_error_handlers; - -struct pci_driver { - struct list_head node; - const char *name; - const struct pci_device_id *id_table; - int (*probe)(struct pci_dev *, const struct pci_device_id *); - void (*remove)(struct pci_dev *); - int (*suspend)(struct pci_dev *, pm_message_t); - int (*resume)(struct pci_dev *); - void (*shutdown)(struct pci_dev *); - int (*sriov_configure)(struct pci_dev *, int); - int (*sriov_set_msix_vec_count)(struct pci_dev *, int); - u32 (*sriov_get_vf_total_msix)(struct pci_dev *); - const struct pci_error_handlers *err_handler; - const struct attribute_group **groups; - const struct attribute_group **dev_groups; - struct device_driver driver; - struct pci_dynids dynids; -}; - -struct pci_ops { - int (*add_bus)(struct pci_bus *); - void (*remove_bus)(struct pci_bus *); - void * (*map_bus)(struct pci_bus *, unsigned int, int); - int (*read)(struct pci_bus *, unsigned int, int, int, u32 *); - int (*write)(struct pci_bus *, unsigned int, int, int, u32); -}; - -typedef unsigned int pci_ers_result_t; - -struct pci_error_handlers { - pci_ers_result_t (*error_detected)(struct pci_dev *, pci_channel_state_t); - pci_ers_result_t (*mmio_enabled)(struct pci_dev *); - pci_ers_result_t (*slot_reset)(struct pci_dev *); - void (*reset_prepare)(struct pci_dev *); - void (*reset_done)(struct pci_dev *); - void (*resume)(struct pci_dev *); -}; - -struct syscore_ops { - struct list_head node; - int (*suspend)(); - void (*resume)(); - void (*shutdown)(); -}; - -enum ibs_states { - IBS_ENABLED = 0, - IBS_STARTED = 1, - IBS_STOPPING = 2, - IBS_STOPPED = 3, - IBS_MAX_STATES = 4, -}; - -struct cpu_perf_ibs { - struct perf_event *event; - long unsigned int state[1]; -}; - -struct perf_ibs { - struct pmu pmu; - unsigned int msr; - u64 config_mask; - u64 cnt_mask; - u64 enable_mask; - u64 valid_mask; - u64 max_period; - long unsigned int offset_mask[1]; - int offset_max; - unsigned int fetch_count_reset_broken: 1; - unsigned int fetch_ignore_if_zero_rip: 1; - struct cpu_perf_ibs *pcpu; - struct attribute **format_attrs; - struct attribute_group format_group; - const struct attribute_group *attr_groups[2]; - u64 (*get_count)(u64); -}; - -struct perf_ibs_data { - u32 size; - union { - u32 data[0]; - u32 caps; - }; - u64 regs[8]; -}; - -struct amd_iommu; - -struct perf_amd_iommu { - struct list_head list; - struct pmu pmu; - struct amd_iommu *iommu; - char name[16]; - u8 max_banks; - u8 max_counters; - u64 cntr_assign_mask; - raw_spinlock_t lock; -}; - -struct amd_iommu_event_desc { - struct device_attribute attr; - const char *event; -}; - -enum perf_msr_id { - PERF_MSR_TSC = 0, - PERF_MSR_APERF = 1, - PERF_MSR_MPERF = 2, - PERF_MSR_PPERF = 3, - PERF_MSR_SMI = 4, - PERF_MSR_PTSC = 5, - PERF_MSR_IRPERF = 6, - PERF_MSR_THERM = 7, - PERF_MSR_EVENT_MAX = 8, -}; - -struct x86_cpu_desc { - u8 x86_family; - u8 x86_vendor; - u8 x86_model; - u8 x86_stepping; - u32 x86_microcode_rev; -}; - -union cpuid10_eax { - struct { - unsigned int version_id: 8; - unsigned int num_counters: 8; - unsigned int bit_width: 8; - unsigned int mask_length: 8; - } split; - unsigned int full; -}; - -union cpuid10_ebx { - struct { - unsigned int no_unhalted_core_cycles: 1; - unsigned int no_instructions_retired: 1; - unsigned int no_unhalted_reference_cycles: 1; - unsigned int no_llc_reference: 1; - unsigned int no_llc_misses: 1; - unsigned int no_branch_instruction_retired: 1; - unsigned int no_branch_misses_retired: 1; - } split; - unsigned int full; -}; - -union cpuid10_edx { - struct { - unsigned int num_counters_fixed: 5; - unsigned int bit_width_fixed: 8; - unsigned int reserved1: 2; - unsigned int anythread_deprecated: 1; - unsigned int reserved2: 16; - } split; - unsigned int full; -}; - -struct perf_pmu_format_hybrid_attr { - struct device_attribute attr; - u64 pmu_type; -}; - -enum { - LBR_FORMAT_32 = 0, - LBR_FORMAT_LIP = 1, - LBR_FORMAT_EIP = 2, - LBR_FORMAT_EIP_FLAGS = 3, - LBR_FORMAT_EIP_FLAGS2 = 4, - LBR_FORMAT_INFO = 5, - LBR_FORMAT_TIME = 6, - LBR_FORMAT_MAX_KNOWN = 6, -}; - -union x86_pmu_config { - struct { - u64 event: 8; - u64 umask: 8; - u64 usr: 1; - u64 os: 1; - u64 edge: 1; - u64 pc: 1; - u64 interrupt: 1; - u64 __reserved1: 1; - u64 en: 1; - u64 inv: 1; - u64 cmask: 8; - u64 event2: 4; - u64 __reserved2: 4; - u64 go: 1; - u64 ho: 1; - } bits; - u64 value; -}; - -enum pageflags { - PG_locked = 0, - PG_referenced = 1, - PG_uptodate = 2, - PG_dirty = 3, - PG_lru = 4, - PG_active = 5, - PG_workingset = 6, - PG_waiters = 7, - PG_error = 8, - PG_slab = 9, - PG_owner_priv_1 = 10, - PG_arch_1 = 11, - PG_reserved = 12, - PG_private = 13, - PG_private_2 = 14, - PG_writeback = 15, - PG_head = 16, - PG_mappedtodisk = 17, - PG_reclaim = 18, - PG_swapbacked = 19, - PG_unevictable = 20, - PG_mlocked = 21, - PG_uncached = 22, - PG_hwpoison = 23, - PG_young = 24, - PG_idle = 25, - PG_arch_2 = 26, - __NR_PAGEFLAGS = 27, - PG_checked = 10, - PG_swapcache = 10, - PG_fscache = 14, - PG_pinned = 10, - PG_savepinned = 3, - PG_foreign = 10, - PG_xen_remapped = 10, - PG_slob_free = 13, - PG_double_map = 6, - PG_isolated = 18, - PG_reported = 2, -}; - -struct bts_ctx { - struct perf_output_handle handle; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct debug_store ds_back; - int state; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum { - BTS_STATE_STOPPED = 0, - BTS_STATE_INACTIVE = 1, - BTS_STATE_ACTIVE = 2, -}; - -struct bts_phys { - struct page *page; - long unsigned int size; - long unsigned int offset; - long unsigned int displacement; -}; - -struct bts_buffer { - size_t real_size; - unsigned int nr_pages; - unsigned int nr_bufs; - unsigned int cur_buf; - bool snapshot; - local_t data_size; - local_t head; - long unsigned int end; - void **data_pages; - struct bts_phys buf[0]; -}; - -struct lbr_entry { - u64 from; - u64 to; - u64 info; -}; - -struct x86_hw_tss { - u32 reserved1; - u64 sp0; - u64 sp1; - u64 sp2; - u64 reserved2; - u64 ist[7]; - u32 reserved3; - u32 reserved4; - u16 reserved5; - u16 io_bitmap_base; -} __attribute__((packed)); - -struct entry_stack { - char stack[4096]; -}; - -struct entry_stack_page { - struct entry_stack stack; -}; - -struct x86_io_bitmap { - u64 prev_sequence; - unsigned int prev_max; - long unsigned int bitmap[1025]; - long unsigned int mapall[1025]; -}; - -struct tss_struct { - struct x86_hw_tss x86_tss; - struct x86_io_bitmap io_bitmap; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct debug_store_buffers { - char bts_buffer[65536]; - char pebs_buffer[65536]; -}; - -struct cea_exception_stacks { - char DF_stack_guard[4096]; - char DF_stack[4096]; - char NMI_stack_guard[4096]; - char NMI_stack[4096]; - char DB_stack_guard[4096]; - char DB_stack[4096]; - char MCE_stack_guard[4096]; - char MCE_stack[4096]; - char VC_stack_guard[4096]; - char VC_stack[4096]; - char VC2_stack_guard[4096]; - char VC2_stack[4096]; - char IST_top_guard[4096]; -}; - -struct cpu_entry_area { - char gdt[4096]; - struct entry_stack_page entry_stack_page; - struct tss_struct tss; - struct cea_exception_stacks estacks; - struct debug_store cpu_debug_store; - struct debug_store_buffers cpu_debug_buffers; -}; - -struct pebs_basic { - u64 format_size; - u64 ip; - u64 applicable_counters; - u64 tsc; -}; - -struct pebs_meminfo { - u64 address; - u64 aux; - u64 latency; - u64 tsx_tuning; -}; - -struct pebs_gprs { - u64 flags; - u64 ip; - u64 ax; - u64 cx; - u64 dx; - u64 bx; - u64 sp; - u64 bp; - u64 si; - u64 di; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; -}; - -struct pebs_xmm { - u64 xmm[32]; -}; - -struct x86_perf_regs { - struct pt_regs regs; - u64 *xmm_regs; -}; - -typedef unsigned int insn_attr_t; - -typedef unsigned char insn_byte_t; - -typedef int insn_value_t; - -struct insn_field { - union { - insn_value_t value; - insn_byte_t bytes[4]; - }; - unsigned char got; - unsigned char nbytes; -}; - -struct insn { - struct insn_field prefixes; - struct insn_field rex_prefix; - struct insn_field vex_prefix; - struct insn_field opcode; - struct insn_field modrm; - struct insn_field sib; - struct insn_field displacement; - union { - struct insn_field immediate; - struct insn_field moffset1; - struct insn_field immediate1; - }; - union { - struct insn_field moffset2; - struct insn_field immediate2; - }; - int emulate_prefix_size; - insn_attr_t attr; - unsigned char opnd_bytes; - unsigned char addr_bytes; - unsigned char length; - unsigned char x86_64; - const insn_byte_t *kaddr; - const insn_byte_t *end_kaddr; - const insn_byte_t *next_byte; -}; - -enum { - PERF_TXN_ELISION = 1, - PERF_TXN_TRANSACTION = 2, - PERF_TXN_SYNC = 4, - PERF_TXN_ASYNC = 8, - PERF_TXN_RETRY = 16, - PERF_TXN_CONFLICT = 32, - PERF_TXN_CAPACITY_WRITE = 64, - PERF_TXN_CAPACITY_READ = 128, - PERF_TXN_MAX = 256, - PERF_TXN_ABORT_MASK = 0, - PERF_TXN_ABORT_SHIFT = 32, -}; - -struct perf_event_header { - __u32 type; - __u16 misc; - __u16 size; -}; - -union intel_x86_pebs_dse { - u64 val; - struct { - unsigned int ld_dse: 4; - unsigned int ld_stlb_miss: 1; - unsigned int ld_locked: 1; - unsigned int ld_data_blk: 1; - unsigned int ld_addr_blk: 1; - unsigned int ld_reserved: 24; - }; - struct { - unsigned int st_l1d_hit: 1; - unsigned int st_reserved1: 3; - unsigned int st_stlb_miss: 1; - unsigned int st_locked: 1; - unsigned int st_reserved2: 26; - }; - struct { - unsigned int st_lat_dse: 4; - unsigned int st_lat_stlb_miss: 1; - unsigned int st_lat_locked: 1; - unsigned int ld_reserved3: 26; - }; -}; - -struct pebs_record_core { - u64 flags; - u64 ip; - u64 ax; - u64 bx; - u64 cx; - u64 dx; - u64 si; - u64 di; - u64 bp; - u64 sp; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; -}; - -struct pebs_record_nhm { - u64 flags; - u64 ip; - u64 ax; - u64 bx; - u64 cx; - u64 dx; - u64 si; - u64 di; - u64 bp; - u64 sp; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; - u64 status; - u64 dla; - u64 dse; - u64 lat; -}; - -union hsw_tsx_tuning { - struct { - u32 cycles_last_block: 32; - u32 hle_abort: 1; - u32 rtm_abort: 1; - u32 instruction_abort: 1; - u32 non_instruction_abort: 1; - u32 retry: 1; - u32 data_conflict: 1; - u32 capacity_writes: 1; - u32 capacity_reads: 1; - }; - u64 value; -}; - -struct pebs_record_skl { - u64 flags; - u64 ip; - u64 ax; - u64 bx; - u64 cx; - u64 dx; - u64 si; - u64 di; - u64 bp; - u64 sp; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; - u64 status; - u64 dla; - u64 dse; - u64 lat; - u64 real_ip; - u64 tsx_tuning; - u64 tsc; -}; - -struct bts_record { - u64 from; - u64 to; - u64 flags; -}; - -enum { - PERF_BR_UNKNOWN = 0, - PERF_BR_COND = 1, - PERF_BR_UNCOND = 2, - PERF_BR_IND = 3, - PERF_BR_CALL = 4, - PERF_BR_IND_CALL = 5, - PERF_BR_RET = 6, - PERF_BR_SYSCALL = 7, - PERF_BR_SYSRET = 8, - PERF_BR_COND_CALL = 9, - PERF_BR_COND_RET = 10, - PERF_BR_MAX = 11, -}; - -enum xfeature { - XFEATURE_FP = 0, - XFEATURE_SSE = 1, - XFEATURE_YMM = 2, - XFEATURE_BNDREGS = 3, - XFEATURE_BNDCSR = 4, - XFEATURE_OPMASK = 5, - XFEATURE_ZMM_Hi256 = 6, - XFEATURE_Hi16_ZMM = 7, - XFEATURE_PT_UNIMPLEMENTED_SO_FAR = 8, - XFEATURE_PKRU = 9, - XFEATURE_PASID = 10, - XFEATURE_RSRVD_COMP_11 = 11, - XFEATURE_RSRVD_COMP_12 = 12, - XFEATURE_RSRVD_COMP_13 = 13, - XFEATURE_RSRVD_COMP_14 = 14, - XFEATURE_LBR = 15, - XFEATURE_MAX = 16, -}; - -struct arch_lbr_state { - u64 lbr_ctl; - u64 lbr_depth; - u64 ler_from; - u64 ler_to; - u64 ler_info; - struct lbr_entry entries[0]; -}; - -union cpuid28_eax { - struct { - unsigned int lbr_depth_mask: 8; - unsigned int reserved: 22; - unsigned int lbr_deep_c_reset: 1; - unsigned int lbr_lip: 1; - } split; - unsigned int full; -}; - -union cpuid28_ebx { - struct { - unsigned int lbr_cpl: 1; - unsigned int lbr_filter: 1; - unsigned int lbr_call_stack: 1; - } split; - unsigned int full; -}; - -union cpuid28_ecx { - struct { - unsigned int lbr_mispred: 1; - unsigned int lbr_timed_lbr: 1; - unsigned int lbr_br_type: 1; - } split; - unsigned int full; -}; - -struct x86_pmu_lbr { - unsigned int nr; - unsigned int from; - unsigned int to; - unsigned int info; -}; - -struct x86_perf_task_context_opt { - int lbr_callstack_users; - int lbr_stack_state; - int log_id; -}; - -struct x86_perf_task_context { - u64 lbr_sel; - int tos; - int valid_lbrs; - struct x86_perf_task_context_opt opt; - struct lbr_entry lbr[32]; -}; - -struct x86_perf_task_context_arch_lbr { - struct x86_perf_task_context_opt opt; - struct lbr_entry entries[0]; -}; - -struct x86_perf_task_context_arch_lbr_xsave { - struct x86_perf_task_context_opt opt; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct xregs_state xsave; - struct { - struct fxregs_state i387; - struct xstate_header header; - struct arch_lbr_state lbr; - long: 64; - long: 64; - long: 64; - }; - }; -}; - -enum { - X86_BR_NONE = 0, - X86_BR_USER = 1, - X86_BR_KERNEL = 2, - X86_BR_CALL = 4, - X86_BR_RET = 8, - X86_BR_SYSCALL = 16, - X86_BR_SYSRET = 32, - X86_BR_INT = 64, - X86_BR_IRET = 128, - X86_BR_JCC = 256, - X86_BR_JMP = 512, - X86_BR_IRQ = 1024, - X86_BR_IND_CALL = 2048, - X86_BR_ABORT = 4096, - X86_BR_IN_TX = 8192, - X86_BR_NO_TX = 16384, - X86_BR_ZERO_CALL = 32768, - X86_BR_CALL_STACK = 65536, - X86_BR_IND_JMP = 131072, - X86_BR_TYPE_SAVE = 262144, -}; - -enum { - LBR_NONE = 0, - LBR_VALID = 1, -}; - -enum { - ARCH_LBR_BR_TYPE_JCC = 0, - ARCH_LBR_BR_TYPE_NEAR_IND_JMP = 1, - ARCH_LBR_BR_TYPE_NEAR_REL_JMP = 2, - ARCH_LBR_BR_TYPE_NEAR_IND_CALL = 3, - ARCH_LBR_BR_TYPE_NEAR_REL_CALL = 4, - ARCH_LBR_BR_TYPE_NEAR_RET = 5, - ARCH_LBR_BR_TYPE_KNOWN_MAX = 5, - ARCH_LBR_BR_TYPE_MAP_MAX = 16, -}; - -enum P4_EVENTS { - P4_EVENT_TC_DELIVER_MODE = 0, - P4_EVENT_BPU_FETCH_REQUEST = 1, - P4_EVENT_ITLB_REFERENCE = 2, - P4_EVENT_MEMORY_CANCEL = 3, - P4_EVENT_MEMORY_COMPLETE = 4, - P4_EVENT_LOAD_PORT_REPLAY = 5, - P4_EVENT_STORE_PORT_REPLAY = 6, - P4_EVENT_MOB_LOAD_REPLAY = 7, - P4_EVENT_PAGE_WALK_TYPE = 8, - P4_EVENT_BSQ_CACHE_REFERENCE = 9, - P4_EVENT_IOQ_ALLOCATION = 10, - P4_EVENT_IOQ_ACTIVE_ENTRIES = 11, - P4_EVENT_FSB_DATA_ACTIVITY = 12, - P4_EVENT_BSQ_ALLOCATION = 13, - P4_EVENT_BSQ_ACTIVE_ENTRIES = 14, - P4_EVENT_SSE_INPUT_ASSIST = 15, - P4_EVENT_PACKED_SP_UOP = 16, - P4_EVENT_PACKED_DP_UOP = 17, - P4_EVENT_SCALAR_SP_UOP = 18, - P4_EVENT_SCALAR_DP_UOP = 19, - P4_EVENT_64BIT_MMX_UOP = 20, - P4_EVENT_128BIT_MMX_UOP = 21, - P4_EVENT_X87_FP_UOP = 22, - P4_EVENT_TC_MISC = 23, - P4_EVENT_GLOBAL_POWER_EVENTS = 24, - P4_EVENT_TC_MS_XFER = 25, - P4_EVENT_UOP_QUEUE_WRITES = 26, - P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE = 27, - P4_EVENT_RETIRED_BRANCH_TYPE = 28, - P4_EVENT_RESOURCE_STALL = 29, - P4_EVENT_WC_BUFFER = 30, - P4_EVENT_B2B_CYCLES = 31, - P4_EVENT_BNR = 32, - P4_EVENT_SNOOP = 33, - P4_EVENT_RESPONSE = 34, - P4_EVENT_FRONT_END_EVENT = 35, - P4_EVENT_EXECUTION_EVENT = 36, - P4_EVENT_REPLAY_EVENT = 37, - P4_EVENT_INSTR_RETIRED = 38, - P4_EVENT_UOPS_RETIRED = 39, - P4_EVENT_UOP_TYPE = 40, - P4_EVENT_BRANCH_RETIRED = 41, - P4_EVENT_MISPRED_BRANCH_RETIRED = 42, - P4_EVENT_X87_ASSIST = 43, - P4_EVENT_MACHINE_CLEAR = 44, - P4_EVENT_INSTR_COMPLETED = 45, -}; - -enum P4_EVENT_OPCODES { - P4_EVENT_TC_DELIVER_MODE_OPCODE = 257, - P4_EVENT_BPU_FETCH_REQUEST_OPCODE = 768, - P4_EVENT_ITLB_REFERENCE_OPCODE = 6147, - P4_EVENT_MEMORY_CANCEL_OPCODE = 517, - P4_EVENT_MEMORY_COMPLETE_OPCODE = 2050, - P4_EVENT_LOAD_PORT_REPLAY_OPCODE = 1026, - P4_EVENT_STORE_PORT_REPLAY_OPCODE = 1282, - P4_EVENT_MOB_LOAD_REPLAY_OPCODE = 770, - P4_EVENT_PAGE_WALK_TYPE_OPCODE = 260, - P4_EVENT_BSQ_CACHE_REFERENCE_OPCODE = 3079, - P4_EVENT_IOQ_ALLOCATION_OPCODE = 774, - P4_EVENT_IOQ_ACTIVE_ENTRIES_OPCODE = 6662, - P4_EVENT_FSB_DATA_ACTIVITY_OPCODE = 5894, - P4_EVENT_BSQ_ALLOCATION_OPCODE = 1287, - P4_EVENT_BSQ_ACTIVE_ENTRIES_OPCODE = 1543, - P4_EVENT_SSE_INPUT_ASSIST_OPCODE = 13313, - P4_EVENT_PACKED_SP_UOP_OPCODE = 2049, - P4_EVENT_PACKED_DP_UOP_OPCODE = 3073, - P4_EVENT_SCALAR_SP_UOP_OPCODE = 2561, - P4_EVENT_SCALAR_DP_UOP_OPCODE = 3585, - P4_EVENT_64BIT_MMX_UOP_OPCODE = 513, - P4_EVENT_128BIT_MMX_UOP_OPCODE = 6657, - P4_EVENT_X87_FP_UOP_OPCODE = 1025, - P4_EVENT_TC_MISC_OPCODE = 1537, - P4_EVENT_GLOBAL_POWER_EVENTS_OPCODE = 4870, - P4_EVENT_TC_MS_XFER_OPCODE = 1280, - P4_EVENT_UOP_QUEUE_WRITES_OPCODE = 2304, - P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE_OPCODE = 1282, - P4_EVENT_RETIRED_BRANCH_TYPE_OPCODE = 1026, - P4_EVENT_RESOURCE_STALL_OPCODE = 257, - P4_EVENT_WC_BUFFER_OPCODE = 1285, - P4_EVENT_B2B_CYCLES_OPCODE = 5635, - P4_EVENT_BNR_OPCODE = 2051, - P4_EVENT_SNOOP_OPCODE = 1539, - P4_EVENT_RESPONSE_OPCODE = 1027, - P4_EVENT_FRONT_END_EVENT_OPCODE = 2053, - P4_EVENT_EXECUTION_EVENT_OPCODE = 3077, - P4_EVENT_REPLAY_EVENT_OPCODE = 2309, - P4_EVENT_INSTR_RETIRED_OPCODE = 516, - P4_EVENT_UOPS_RETIRED_OPCODE = 260, - P4_EVENT_UOP_TYPE_OPCODE = 514, - P4_EVENT_BRANCH_RETIRED_OPCODE = 1541, - P4_EVENT_MISPRED_BRANCH_RETIRED_OPCODE = 772, - P4_EVENT_X87_ASSIST_OPCODE = 773, - P4_EVENT_MACHINE_CLEAR_OPCODE = 517, - P4_EVENT_INSTR_COMPLETED_OPCODE = 1796, -}; - -enum P4_ESCR_EMASKS { - P4_EVENT_TC_DELIVER_MODE__DD = 512, - P4_EVENT_TC_DELIVER_MODE__DB = 1024, - P4_EVENT_TC_DELIVER_MODE__DI = 2048, - P4_EVENT_TC_DELIVER_MODE__BD = 4096, - P4_EVENT_TC_DELIVER_MODE__BB = 8192, - P4_EVENT_TC_DELIVER_MODE__BI = 16384, - P4_EVENT_TC_DELIVER_MODE__ID = 32768, - P4_EVENT_BPU_FETCH_REQUEST__TCMISS = 512, - P4_EVENT_ITLB_REFERENCE__HIT = 512, - P4_EVENT_ITLB_REFERENCE__MISS = 1024, - P4_EVENT_ITLB_REFERENCE__HIT_UK = 2048, - P4_EVENT_MEMORY_CANCEL__ST_RB_FULL = 2048, - P4_EVENT_MEMORY_CANCEL__64K_CONF = 4096, - P4_EVENT_MEMORY_COMPLETE__LSC = 512, - P4_EVENT_MEMORY_COMPLETE__SSC = 1024, - P4_EVENT_LOAD_PORT_REPLAY__SPLIT_LD = 1024, - P4_EVENT_STORE_PORT_REPLAY__SPLIT_ST = 1024, - P4_EVENT_MOB_LOAD_REPLAY__NO_STA = 1024, - P4_EVENT_MOB_LOAD_REPLAY__NO_STD = 4096, - P4_EVENT_MOB_LOAD_REPLAY__PARTIAL_DATA = 8192, - P4_EVENT_MOB_LOAD_REPLAY__UNALGN_ADDR = 16384, - P4_EVENT_PAGE_WALK_TYPE__DTMISS = 512, - P4_EVENT_PAGE_WALK_TYPE__ITMISS = 1024, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_HITS = 512, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_HITE = 1024, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_HITM = 2048, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_HITS = 4096, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_HITE = 8192, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_HITM = 16384, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_MISS = 131072, - P4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_MISS = 262144, - P4_EVENT_BSQ_CACHE_REFERENCE__WR_2ndL_MISS = 524288, - P4_EVENT_IOQ_ALLOCATION__DEFAULT = 512, - P4_EVENT_IOQ_ALLOCATION__ALL_READ = 16384, - P4_EVENT_IOQ_ALLOCATION__ALL_WRITE = 32768, - P4_EVENT_IOQ_ALLOCATION__MEM_UC = 65536, - P4_EVENT_IOQ_ALLOCATION__MEM_WC = 131072, - P4_EVENT_IOQ_ALLOCATION__MEM_WT = 262144, - P4_EVENT_IOQ_ALLOCATION__MEM_WP = 524288, - P4_EVENT_IOQ_ALLOCATION__MEM_WB = 1048576, - P4_EVENT_IOQ_ALLOCATION__OWN = 4194304, - P4_EVENT_IOQ_ALLOCATION__OTHER = 8388608, - P4_EVENT_IOQ_ALLOCATION__PREFETCH = 16777216, - P4_EVENT_IOQ_ACTIVE_ENTRIES__DEFAULT = 512, - P4_EVENT_IOQ_ACTIVE_ENTRIES__ALL_READ = 16384, - P4_EVENT_IOQ_ACTIVE_ENTRIES__ALL_WRITE = 32768, - P4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_UC = 65536, - P4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WC = 131072, - P4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WT = 262144, - P4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WP = 524288, - P4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WB = 1048576, - P4_EVENT_IOQ_ACTIVE_ENTRIES__OWN = 4194304, - P4_EVENT_IOQ_ACTIVE_ENTRIES__OTHER = 8388608, - P4_EVENT_IOQ_ACTIVE_ENTRIES__PREFETCH = 16777216, - P4_EVENT_FSB_DATA_ACTIVITY__DRDY_DRV = 512, - P4_EVENT_FSB_DATA_ACTIVITY__DRDY_OWN = 1024, - P4_EVENT_FSB_DATA_ACTIVITY__DRDY_OTHER = 2048, - P4_EVENT_FSB_DATA_ACTIVITY__DBSY_DRV = 4096, - P4_EVENT_FSB_DATA_ACTIVITY__DBSY_OWN = 8192, - P4_EVENT_FSB_DATA_ACTIVITY__DBSY_OTHER = 16384, - P4_EVENT_BSQ_ALLOCATION__REQ_TYPE0 = 512, - P4_EVENT_BSQ_ALLOCATION__REQ_TYPE1 = 1024, - P4_EVENT_BSQ_ALLOCATION__REQ_LEN0 = 2048, - P4_EVENT_BSQ_ALLOCATION__REQ_LEN1 = 4096, - P4_EVENT_BSQ_ALLOCATION__REQ_IO_TYPE = 16384, - P4_EVENT_BSQ_ALLOCATION__REQ_LOCK_TYPE = 32768, - P4_EVENT_BSQ_ALLOCATION__REQ_CACHE_TYPE = 65536, - P4_EVENT_BSQ_ALLOCATION__REQ_SPLIT_TYPE = 131072, - P4_EVENT_BSQ_ALLOCATION__REQ_DEM_TYPE = 262144, - P4_EVENT_BSQ_ALLOCATION__REQ_ORD_TYPE = 524288, - P4_EVENT_BSQ_ALLOCATION__MEM_TYPE0 = 1048576, - P4_EVENT_BSQ_ALLOCATION__MEM_TYPE1 = 2097152, - P4_EVENT_BSQ_ALLOCATION__MEM_TYPE2 = 4194304, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_TYPE0 = 512, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_TYPE1 = 1024, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_LEN0 = 2048, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_LEN1 = 4096, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_IO_TYPE = 16384, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_LOCK_TYPE = 32768, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_CACHE_TYPE = 65536, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_SPLIT_TYPE = 131072, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_DEM_TYPE = 262144, - P4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_ORD_TYPE = 524288, - P4_EVENT_BSQ_ACTIVE_ENTRIES__MEM_TYPE0 = 1048576, - P4_EVENT_BSQ_ACTIVE_ENTRIES__MEM_TYPE1 = 2097152, - P4_EVENT_BSQ_ACTIVE_ENTRIES__MEM_TYPE2 = 4194304, - P4_EVENT_SSE_INPUT_ASSIST__ALL = 16777216, - P4_EVENT_PACKED_SP_UOP__ALL = 16777216, - P4_EVENT_PACKED_DP_UOP__ALL = 16777216, - P4_EVENT_SCALAR_SP_UOP__ALL = 16777216, - P4_EVENT_SCALAR_DP_UOP__ALL = 16777216, - P4_EVENT_64BIT_MMX_UOP__ALL = 16777216, - P4_EVENT_128BIT_MMX_UOP__ALL = 16777216, - P4_EVENT_X87_FP_UOP__ALL = 16777216, - P4_EVENT_TC_MISC__FLUSH = 8192, - P4_EVENT_GLOBAL_POWER_EVENTS__RUNNING = 512, - P4_EVENT_TC_MS_XFER__CISC = 512, - P4_EVENT_UOP_QUEUE_WRITES__FROM_TC_BUILD = 512, - P4_EVENT_UOP_QUEUE_WRITES__FROM_TC_DELIVER = 1024, - P4_EVENT_UOP_QUEUE_WRITES__FROM_ROM = 2048, - P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__CONDITIONAL = 1024, - P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__CALL = 2048, - P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__RETURN = 4096, - P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__INDIRECT = 8192, - P4_EVENT_RETIRED_BRANCH_TYPE__CONDITIONAL = 1024, - P4_EVENT_RETIRED_BRANCH_TYPE__CALL = 2048, - P4_EVENT_RETIRED_BRANCH_TYPE__RETURN = 4096, - P4_EVENT_RETIRED_BRANCH_TYPE__INDIRECT = 8192, - P4_EVENT_RESOURCE_STALL__SBFULL = 16384, - P4_EVENT_WC_BUFFER__WCB_EVICTS = 512, - P4_EVENT_WC_BUFFER__WCB_FULL_EVICTS = 1024, - P4_EVENT_FRONT_END_EVENT__NBOGUS = 512, - P4_EVENT_FRONT_END_EVENT__BOGUS = 1024, - P4_EVENT_EXECUTION_EVENT__NBOGUS0 = 512, - P4_EVENT_EXECUTION_EVENT__NBOGUS1 = 1024, - P4_EVENT_EXECUTION_EVENT__NBOGUS2 = 2048, - P4_EVENT_EXECUTION_EVENT__NBOGUS3 = 4096, - P4_EVENT_EXECUTION_EVENT__BOGUS0 = 8192, - P4_EVENT_EXECUTION_EVENT__BOGUS1 = 16384, - P4_EVENT_EXECUTION_EVENT__BOGUS2 = 32768, - P4_EVENT_EXECUTION_EVENT__BOGUS3 = 65536, - P4_EVENT_REPLAY_EVENT__NBOGUS = 512, - P4_EVENT_REPLAY_EVENT__BOGUS = 1024, - P4_EVENT_INSTR_RETIRED__NBOGUSNTAG = 512, - P4_EVENT_INSTR_RETIRED__NBOGUSTAG = 1024, - P4_EVENT_INSTR_RETIRED__BOGUSNTAG = 2048, - P4_EVENT_INSTR_RETIRED__BOGUSTAG = 4096, - P4_EVENT_UOPS_RETIRED__NBOGUS = 512, - P4_EVENT_UOPS_RETIRED__BOGUS = 1024, - P4_EVENT_UOP_TYPE__TAGLOADS = 1024, - P4_EVENT_UOP_TYPE__TAGSTORES = 2048, - P4_EVENT_BRANCH_RETIRED__MMNP = 512, - P4_EVENT_BRANCH_RETIRED__MMNM = 1024, - P4_EVENT_BRANCH_RETIRED__MMTP = 2048, - P4_EVENT_BRANCH_RETIRED__MMTM = 4096, - P4_EVENT_MISPRED_BRANCH_RETIRED__NBOGUS = 512, - P4_EVENT_X87_ASSIST__FPSU = 512, - P4_EVENT_X87_ASSIST__FPSO = 1024, - P4_EVENT_X87_ASSIST__POAO = 2048, - P4_EVENT_X87_ASSIST__POAU = 4096, - P4_EVENT_X87_ASSIST__PREA = 8192, - P4_EVENT_MACHINE_CLEAR__CLEAR = 512, - P4_EVENT_MACHINE_CLEAR__MOCLEAR = 1024, - P4_EVENT_MACHINE_CLEAR__SMCLEAR = 2048, - P4_EVENT_INSTR_COMPLETED__NBOGUS = 512, - P4_EVENT_INSTR_COMPLETED__BOGUS = 1024, -}; - -enum P4_PEBS_METRIC { - P4_PEBS_METRIC__none = 0, - P4_PEBS_METRIC__1stl_cache_load_miss_retired = 1, - P4_PEBS_METRIC__2ndl_cache_load_miss_retired = 2, - P4_PEBS_METRIC__dtlb_load_miss_retired = 3, - P4_PEBS_METRIC__dtlb_store_miss_retired = 4, - P4_PEBS_METRIC__dtlb_all_miss_retired = 5, - P4_PEBS_METRIC__tagged_mispred_branch = 6, - P4_PEBS_METRIC__mob_load_replay_retired = 7, - P4_PEBS_METRIC__split_load_retired = 8, - P4_PEBS_METRIC__split_store_retired = 9, - P4_PEBS_METRIC__max = 10, -}; - -struct p4_event_bind { - unsigned int opcode; - unsigned int escr_msr[2]; - unsigned int escr_emask; - unsigned int shared; - char cntr[6]; -}; - -struct p4_pebs_bind { - unsigned int metric_pebs; - unsigned int metric_vert; -}; - -struct p4_event_alias { - u64 original; - u64 alternative; -}; - -enum cpuid_regs_idx { - CPUID_EAX = 0, - CPUID_EBX = 1, - CPUID_ECX = 2, - CPUID_EDX = 3, -}; - -struct dev_ext_attribute { - struct device_attribute attr; - void *var; -}; - -enum pt_capabilities { - PT_CAP_max_subleaf = 0, - PT_CAP_cr3_filtering = 1, - PT_CAP_psb_cyc = 2, - PT_CAP_ip_filtering = 3, - PT_CAP_mtc = 4, - PT_CAP_ptwrite = 5, - PT_CAP_power_event_trace = 6, - PT_CAP_topa_output = 7, - PT_CAP_topa_multiple_entries = 8, - PT_CAP_single_range_output = 9, - PT_CAP_output_subsys = 10, - PT_CAP_payloads_lip = 11, - PT_CAP_num_address_ranges = 12, - PT_CAP_mtc_periods = 13, - PT_CAP_cycle_thresholds = 14, - PT_CAP_psb_periods = 15, -}; - -enum perf_addr_filter_action_t { - PERF_ADDR_FILTER_ACTION_STOP = 0, - PERF_ADDR_FILTER_ACTION_START = 1, - PERF_ADDR_FILTER_ACTION_FILTER = 2, -}; - -struct perf_addr_filter { - struct list_head entry; - struct path path; - long unsigned int offset; - long unsigned int size; - enum perf_addr_filter_action_t action; -}; - -struct topa_entry { - u64 end: 1; - u64 rsvd0: 1; - u64 intr: 1; - u64 rsvd1: 1; - u64 stop: 1; - u64 rsvd2: 1; - u64 size: 4; - u64 rsvd3: 2; - u64 base: 36; - u64 rsvd4: 16; -}; - -struct pt_pmu { - struct pmu pmu; - u32 caps[8]; - bool vmx; - bool branch_en_always_on; - long unsigned int max_nonturbo_ratio; - unsigned int tsc_art_num; - unsigned int tsc_art_den; -}; - -struct topa; - -struct pt_buffer { - struct list_head tables; - struct topa *first; - struct topa *last; - struct topa *cur; - unsigned int cur_idx; - size_t output_off; - long unsigned int nr_pages; - local_t data_size; - local64_t head; - bool snapshot; - bool single; - long int stop_pos; - long int intr_pos; - struct topa_entry *stop_te; - struct topa_entry *intr_te; - void **data_pages; -}; - -struct topa { - struct list_head list; - u64 offset; - size_t size; - int last; - unsigned int z_count; -}; - -struct pt_filter { - long unsigned int msr_a; - long unsigned int msr_b; - long unsigned int config; -}; - -struct pt_filters { - struct pt_filter filter[4]; - unsigned int nr_filters; -}; - -struct pt { - struct perf_output_handle handle; - struct pt_filters filters; - int handle_nmi; - int vmx_on; - u64 output_base; - u64 output_mask; -}; - -struct pt_cap_desc { - const char *name; - u32 leaf; - u8 reg; - u32 mask; -}; - -struct pt_address_range { - long unsigned int msr_a; - long unsigned int msr_b; - unsigned int reg_off; -}; - -struct topa_page { - struct topa_entry table[507]; - struct topa topa; -}; - -typedef s8 int8_t; - -typedef u8 uint8_t; - -typedef u64 uint64_t; - -struct atomic_notifier_head { - spinlock_t lock; - struct notifier_block *head; -}; - -enum xen_domain_type { - XEN_NATIVE = 0, - XEN_PV_DOMAIN = 1, - XEN_HVM_DOMAIN = 2, -}; - -typedef long unsigned int xen_pfn_t; - -typedef long unsigned int xen_ulong_t; - -struct arch_shared_info { - long unsigned int max_pfn; - xen_pfn_t pfn_to_mfn_frame_list_list; - long unsigned int nmi_reason; - long unsigned int p2m_cr3; - long unsigned int p2m_vaddr; - long unsigned int p2m_generation; -}; - -struct arch_vcpu_info { - long unsigned int cr2; - long unsigned int pad; -}; - -struct pvclock_wall_clock { - u32 version; - u32 sec; - u32 nsec; -}; - -struct vcpu_info { - uint8_t evtchn_upcall_pending; - uint8_t evtchn_upcall_mask; - xen_ulong_t evtchn_pending_sel; - struct arch_vcpu_info arch; - struct pvclock_vcpu_time_info time; -}; - -struct shared_info { - struct vcpu_info vcpu_info[32]; - xen_ulong_t evtchn_pending[64]; - xen_ulong_t evtchn_mask[64]; - struct pvclock_wall_clock wc; - uint32_t wc_sec_hi; - struct arch_shared_info arch; -}; - -struct start_info { - char magic[32]; - long unsigned int nr_pages; - long unsigned int shared_info; - uint32_t flags; - xen_pfn_t store_mfn; - uint32_t store_evtchn; - union { - struct { - xen_pfn_t mfn; - uint32_t evtchn; - } domU; - struct { - uint32_t info_off; - uint32_t info_size; - } dom0; - } console; - long unsigned int pt_base; - long unsigned int nr_pt_frames; - long unsigned int mfn_list; - long unsigned int mod_start; - long unsigned int mod_len; - int8_t cmd_line[1024]; - long unsigned int first_p2m_pfn; - long unsigned int nr_p2m_frames; -}; - -struct sched_shutdown { - unsigned int reason; -}; - -struct sched_pin_override { - int32_t pcpu; -}; - -struct vcpu_register_vcpu_info { - uint64_t mfn; - uint32_t offset; - uint32_t rsvd; -}; - -struct xmaddr { - phys_addr_t maddr; -}; - -typedef struct xmaddr xmaddr_t; - -struct xpaddr { - phys_addr_t paddr; -}; - -typedef struct xpaddr xpaddr_t; - -typedef s16 int16_t; - -typedef u16 uint16_t; - -enum clocksource_ids { - CSID_GENERIC = 0, - CSID_ARM_ARCH_COUNTER = 1, - CSID_MAX = 2, -}; - -struct clocksource { - u64 (*read)(struct clocksource *); - u64 mask; - u32 mult; - u32 shift; - u64 max_idle_ns; - u32 maxadj; - u32 uncertainty_margin; - u64 max_cycles; - const char *name; - struct list_head list; - int rating; - enum clocksource_ids id; - enum vdso_clock_mode vdso_clock_mode; - long unsigned int flags; - int (*enable)(struct clocksource *); - void (*disable)(struct clocksource *); - void (*suspend)(struct clocksource *); - void (*resume)(struct clocksource *); - void (*mark_unstable)(struct clocksource *); - void (*tick_stable)(struct clocksource *); - struct list_head wd_list; - u64 cs_last; - u64 wd_last; - struct module *owner; -}; - -struct x86_init_mpparse { - void (*setup_ioapic_ids)(); - void (*find_smp_config)(); - void (*get_smp_config)(unsigned int); -}; - -struct x86_init_resources { - void (*probe_roms)(); - void (*reserve_resources)(); - char * (*memory_setup)(); -}; - -struct x86_init_irqs { - void (*pre_vector_init)(); - void (*intr_init)(); - void (*intr_mode_select)(); - void (*intr_mode_init)(); - struct irq_domain * (*create_pci_msi_domain)(); -}; - -struct x86_init_oem { - void (*arch_setup)(); - void (*banner)(); -}; - -struct x86_init_paging { - void (*pagetable_init)(); -}; - -struct x86_init_timers { - void (*setup_percpu_clockev)(); - void (*timer_init)(); - void (*wallclock_init)(); -}; - -struct x86_init_iommu { - int (*iommu_init)(); -}; - -struct x86_init_pci { - int (*arch_init)(); - int (*init)(); - void (*init_irq)(); - void (*fixup_irqs)(); -}; - -struct x86_hyper_init { - void (*init_platform)(); - void (*guest_late_init)(); - bool (*x2apic_available)(); - bool (*msi_ext_dest_id)(); - void (*init_mem_mapping)(); - void (*init_after_bootmem)(); -}; - -struct x86_init_acpi { - void (*set_root_pointer)(u64); - u64 (*get_root_pointer)(); - void (*reduced_hw_early_init)(); -}; - -struct x86_init_ops { - struct x86_init_resources resources; - struct x86_init_mpparse mpparse; - struct x86_init_irqs irqs; - struct x86_init_oem oem; - struct x86_init_paging paging; - struct x86_init_timers timers; - struct x86_init_iommu iommu; - struct x86_init_pci pci; - struct x86_hyper_init hyper; - struct x86_init_acpi acpi; -}; - -struct x86_cpuinit_ops { - void (*setup_percpu_clockev)(); - void (*early_percpu_clock_init)(); - void (*fixup_cpu_id)(struct cpuinfo_x86 *, int); -}; - -enum clock_event_state { - CLOCK_EVT_STATE_DETACHED = 0, - CLOCK_EVT_STATE_SHUTDOWN = 1, - CLOCK_EVT_STATE_PERIODIC = 2, - CLOCK_EVT_STATE_ONESHOT = 3, - CLOCK_EVT_STATE_ONESHOT_STOPPED = 4, -}; - -struct clock_event_device { - void (*event_handler)(struct clock_event_device *); - int (*set_next_event)(long unsigned int, struct clock_event_device *); - int (*set_next_ktime)(ktime_t, struct clock_event_device *); - ktime_t next_event; - u64 max_delta_ns; - u64 min_delta_ns; - u32 mult; - u32 shift; - enum clock_event_state state_use_accessors; - unsigned int features; - long unsigned int retries; - int (*set_state_periodic)(struct clock_event_device *); - int (*set_state_oneshot)(struct clock_event_device *); - int (*set_state_oneshot_stopped)(struct clock_event_device *); - int (*set_state_shutdown)(struct clock_event_device *); - int (*tick_resume)(struct clock_event_device *); - void (*broadcast)(const struct cpumask *); - void (*suspend)(struct clock_event_device *); - void (*resume)(struct clock_event_device *); - long unsigned int min_delta_ticks; - long unsigned int max_delta_ticks; - const char *name; - int rating; - int irq; - int bound_on; - const struct cpumask *cpumask; - struct list_head list; - struct module *owner; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct tk_read_base { - struct clocksource *clock; - u64 mask; - u64 cycle_last; - u32 mult; - u32 shift; - u64 xtime_nsec; - ktime_t base; - u64 base_real; -}; - -struct timekeeper { - struct tk_read_base tkr_mono; - struct tk_read_base tkr_raw; - u64 xtime_sec; - long unsigned int ktime_sec; - struct timespec64 wall_to_monotonic; - ktime_t offs_real; - ktime_t offs_boot; - ktime_t offs_tai; - s32 tai_offset; - unsigned int clock_was_set_seq; - u8 cs_was_changed_seq; - ktime_t next_leap_ktime; - u64 raw_sec; - struct timespec64 monotonic_to_boot; - u64 cycle_interval; - u64 xtime_interval; - s64 xtime_remainder; - u64 raw_interval; - u64 ntp_tick; - s64 ntp_error; - u32 ntp_error_shift; - u32 ntp_err_mult; - u32 skip_second_overflow; -}; - -typedef unsigned char *__guest_handle_uchar; - -typedef char *__guest_handle_char; - -typedef void *__guest_handle_void; - -typedef uint64_t *__guest_handle_uint64_t; - -typedef uint32_t *__guest_handle_uint32_t; - -struct vcpu_time_info { - uint32_t version; - uint32_t pad0; - uint64_t tsc_timestamp; - uint64_t system_time; - uint32_t tsc_to_system_mul; - int8_t tsc_shift; - int8_t pad1[3]; -}; - -struct xenpf_settime32 { - uint32_t secs; - uint32_t nsecs; - uint64_t system_time; -}; - -struct xenpf_settime64 { - uint64_t secs; - uint32_t nsecs; - uint32_t mbz; - uint64_t system_time; -}; - -struct xenpf_add_memtype { - xen_pfn_t mfn; - uint64_t nr_mfns; - uint32_t type; - uint32_t handle; - uint32_t reg; -}; - -struct xenpf_del_memtype { - uint32_t handle; - uint32_t reg; -}; - -struct xenpf_read_memtype { - uint32_t reg; - xen_pfn_t mfn; - uint64_t nr_mfns; - uint32_t type; -}; - -struct xenpf_microcode_update { - __guest_handle_void data; - uint32_t length; -}; - -struct xenpf_platform_quirk { - uint32_t quirk_id; -}; - -struct xenpf_efi_time { - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t min; - uint8_t sec; - uint32_t ns; - int16_t tz; - uint8_t daylight; -}; - -struct xenpf_efi_guid { - uint32_t data1; - uint16_t data2; - uint16_t data3; - uint8_t data4[8]; -}; - -struct xenpf_efi_runtime_call { - uint32_t function; - uint32_t misc; - xen_ulong_t status; - union { - struct { - struct xenpf_efi_time time; - uint32_t resolution; - uint32_t accuracy; - } get_time; - struct xenpf_efi_time set_time; - struct xenpf_efi_time get_wakeup_time; - struct xenpf_efi_time set_wakeup_time; - struct { - __guest_handle_void name; - xen_ulong_t size; - __guest_handle_void data; - struct xenpf_efi_guid vendor_guid; - } get_variable; - struct { - __guest_handle_void name; - xen_ulong_t size; - __guest_handle_void data; - struct xenpf_efi_guid vendor_guid; - } set_variable; - struct { - xen_ulong_t size; - __guest_handle_void name; - struct xenpf_efi_guid vendor_guid; - } get_next_variable_name; - struct { - uint32_t attr; - uint64_t max_store_size; - uint64_t remain_store_size; - uint64_t max_size; - } query_variable_info; - struct { - __guest_handle_void capsule_header_array; - xen_ulong_t capsule_count; - uint64_t max_capsule_size; - uint32_t reset_type; - } query_capsule_capabilities; - struct { - __guest_handle_void capsule_header_array; - xen_ulong_t capsule_count; - uint64_t sg_list; - } update_capsule; - } u; -}; - -union xenpf_efi_info { - uint32_t version; - struct { - uint64_t addr; - uint32_t nent; - } cfg; - struct { - uint32_t revision; - uint32_t bufsz; - __guest_handle_void name; - } vendor; - struct { - uint64_t addr; - uint64_t size; - uint64_t attr; - uint32_t type; - } mem; -}; - -struct xenpf_firmware_info { - uint32_t type; - uint32_t index; - union { - struct { - uint8_t device; - uint8_t version; - uint16_t interface_support; - uint16_t legacy_max_cylinder; - uint8_t legacy_max_head; - uint8_t legacy_sectors_per_track; - __guest_handle_void edd_params; - } disk_info; - struct { - uint8_t device; - uint32_t mbr_signature; - } disk_mbr_signature; - struct { - uint8_t capabilities; - uint8_t edid_transfer_time; - __guest_handle_uchar edid; - } vbeddc_info; - union xenpf_efi_info efi_info; - uint8_t kbd_shift_flags; - } u; -}; - -struct xenpf_enter_acpi_sleep { - uint16_t val_a; - uint16_t val_b; - uint32_t sleep_state; - uint32_t flags; -}; - -struct xenpf_change_freq { - uint32_t flags; - uint32_t cpu; - uint64_t freq; -}; - -struct xenpf_getidletime { - __guest_handle_uchar cpumap_bitmap; - uint32_t cpumap_nr_cpus; - __guest_handle_uint64_t idletime; - uint64_t now; -}; - -struct xen_power_register { - uint32_t space_id; - uint32_t bit_width; - uint32_t bit_offset; - uint32_t access_size; - uint64_t address; -}; - -struct xen_processor_csd { - uint32_t domain; - uint32_t coord_type; - uint32_t num; -}; - -typedef struct xen_processor_csd *__guest_handle_xen_processor_csd; - -struct xen_processor_cx { - struct xen_power_register reg; - uint8_t type; - uint32_t latency; - uint32_t power; - uint32_t dpcnt; - __guest_handle_xen_processor_csd dp; -}; - -typedef struct xen_processor_cx *__guest_handle_xen_processor_cx; - -struct xen_processor_flags { - uint32_t bm_control: 1; - uint32_t bm_check: 1; - uint32_t has_cst: 1; - uint32_t power_setup_done: 1; - uint32_t bm_rld_set: 1; -}; - -struct xen_processor_power { - uint32_t count; - struct xen_processor_flags flags; - __guest_handle_xen_processor_cx states; -}; - -struct xen_pct_register { - uint8_t descriptor; - uint16_t length; - uint8_t space_id; - uint8_t bit_width; - uint8_t bit_offset; - uint8_t reserved; - uint64_t address; -}; - -struct xen_processor_px { - uint64_t core_frequency; - uint64_t power; - uint64_t transition_latency; - uint64_t bus_master_latency; - uint64_t control; - uint64_t status; -}; - -typedef struct xen_processor_px *__guest_handle_xen_processor_px; - -struct xen_psd_package { - uint64_t num_entries; - uint64_t revision; - uint64_t domain; - uint64_t coord_type; - uint64_t num_processors; -}; - -struct xen_processor_performance { - uint32_t flags; - uint32_t platform_limit; - struct xen_pct_register control_register; - struct xen_pct_register status_register; - uint32_t state_count; - __guest_handle_xen_processor_px states; - struct xen_psd_package domain_info; - uint32_t shared_type; -}; - -struct xenpf_set_processor_pminfo { - uint32_t id; - uint32_t type; - union { - struct xen_processor_power power; - struct xen_processor_performance perf; - __guest_handle_uint32_t pdc; - }; -}; - -struct xenpf_pcpuinfo { - uint32_t xen_cpuid; - uint32_t max_present; - uint32_t flags; - uint32_t apic_id; - uint32_t acpi_id; -}; - -struct xenpf_cpu_ol { - uint32_t cpuid; -}; - -struct xenpf_cpu_hotadd { - uint32_t apic_id; - uint32_t acpi_id; - uint32_t pxm; -}; - -struct xenpf_mem_hotadd { - uint64_t spfn; - uint64_t epfn; - uint32_t pxm; - uint32_t flags; -}; - -struct xenpf_core_parking { - uint32_t type; - uint32_t idle_nums; -}; - -struct xenpf_symdata { - uint32_t namelen; - uint32_t symnum; - __guest_handle_char name; - uint64_t address; - char type; -}; - -struct xen_platform_op { - uint32_t cmd; - uint32_t interface_version; - union { - struct xenpf_settime32 settime32; - struct xenpf_settime64 settime64; - struct xenpf_add_memtype add_memtype; - struct xenpf_del_memtype del_memtype; - struct xenpf_read_memtype read_memtype; - struct xenpf_microcode_update microcode; - struct xenpf_platform_quirk platform_quirk; - struct xenpf_efi_runtime_call efi_runtime_call; - struct xenpf_firmware_info firmware_info; - struct xenpf_enter_acpi_sleep enter_acpi_sleep; - struct xenpf_change_freq change_freq; - struct xenpf_getidletime getidletime; - struct xenpf_set_processor_pminfo set_pminfo; - struct xenpf_pcpuinfo pcpu_info; - struct xenpf_cpu_ol cpu_ol; - struct xenpf_cpu_hotadd cpu_add; - struct xenpf_mem_hotadd mem_add; - struct xenpf_core_parking core_parking; - struct xenpf_symdata symdata; - uint8_t pad[128]; - } u; -}; - -struct vcpu_set_singleshot_timer { - uint64_t timeout_abs_ns; - uint32_t flags; -}; - -typedef struct vcpu_time_info *__guest_handle_vcpu_time_info; - -struct vcpu_register_time_memory_area { - union { - __guest_handle_vcpu_time_info h; - struct pvclock_vcpu_time_info *v; - uint64_t p; - } addr; -}; - -struct xen_clock_event_device { - struct clock_event_device evt; - char name[16]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef int (*pte_fn_t)(pte_t *, long unsigned int, void *); - -typedef uint16_t grant_status_t; - -struct grant_frames { - xen_pfn_t *pfn; - unsigned int count; - void *vaddr; -}; - -struct gnttab_vm_area { - struct vm_struct *area; - pte_t **ptes; - int idx; -}; - -enum acpi_irq_model_id { - ACPI_IRQ_MODEL_PIC = 0, - ACPI_IRQ_MODEL_IOAPIC = 1, - ACPI_IRQ_MODEL_IOSAPIC = 2, - ACPI_IRQ_MODEL_PLATFORM = 3, - ACPI_IRQ_MODEL_GIC = 4, - ACPI_IRQ_MODEL_COUNT = 5, -}; - -typedef uint16_t domid_t; - -struct xen_add_to_physmap { - domid_t domid; - uint16_t size; - unsigned int space; - xen_ulong_t idx; - xen_pfn_t gpfn; -}; - -struct machine_ops { - void (*restart)(char *); - void (*halt)(); - void (*power_off)(); - void (*shutdown)(); - void (*crash_shutdown)(struct pt_regs *); - void (*emergency_restart)(); -}; - -enum x86_hypervisor_type { - X86_HYPER_NATIVE = 0, - X86_HYPER_VMWARE = 1, - X86_HYPER_MS_HYPERV = 2, - X86_HYPER_XEN_PV = 3, - X86_HYPER_XEN_HVM = 4, - X86_HYPER_KVM = 5, - X86_HYPER_JAILHOUSE = 6, - X86_HYPER_ACRN = 7, -}; - -struct hypervisor_x86 { - const char *name; - uint32_t (*detect)(); - enum x86_hypervisor_type type; - struct x86_hyper_init init; - struct x86_hyper_runtime runtime; - bool ignore_nopv; -}; - -enum e820_type { - E820_TYPE_RAM = 1, - E820_TYPE_RESERVED = 2, - E820_TYPE_ACPI = 3, - E820_TYPE_NVS = 4, - E820_TYPE_UNUSABLE = 5, - E820_TYPE_PMEM = 7, - E820_TYPE_PRAM = 12, - E820_TYPE_SOFT_RESERVED = 4026531839, - E820_TYPE_RESERVED_KERN = 128, -}; - -struct xen_hvm_pagetable_dying { - domid_t domid; - __u64 gpa; -}; - -enum hvmmem_type_t { - HVMMEM_ram_rw = 0, - HVMMEM_ram_ro = 1, - HVMMEM_mmio_dm = 2, -}; - -struct xen_hvm_get_mem_type { - domid_t domid; - uint16_t mem_type; - uint16_t pad[2]; - uint64_t pfn; -}; - -struct e820_entry { - u64 addr; - u64 size; - enum e820_type type; -} __attribute__((packed)); - -struct e820_table { - __u32 nr_entries; - struct e820_entry entries[224]; -} __attribute__((packed)); - -typedef xen_pfn_t *__guest_handle_xen_pfn_t; - -typedef long unsigned int xen_callback_t; - -struct mmu_update { - uint64_t ptr; - uint64_t val; -}; - -struct xen_memory_region { - long unsigned int start_pfn; - long unsigned int n_pfns; -}; - -struct callback_register { - uint16_t type; - uint16_t flags; - xen_callback_t address; -}; - -struct xen_memory_reservation { - __guest_handle_xen_pfn_t extent_start; - xen_ulong_t nr_extents; - unsigned int extent_order; - unsigned int address_bits; - domid_t domid; -}; - -struct xen_memory_map { - unsigned int nr_entries; - __guest_handle_void buffer; -}; - -struct x86_apic_ops { - unsigned int (*io_apic_read)(unsigned int, unsigned int); - void (*restore)(); -}; - -struct physdev_apic { - long unsigned int apic_physbase; - uint32_t reg; - uint32_t value; -}; - -typedef long unsigned int uintptr_t; - -struct xen_pmu_amd_ctxt { - uint32_t counters; - uint32_t ctrls; - uint64_t regs[0]; -}; - -struct xen_pmu_cntr_pair { - uint64_t counter; - uint64_t control; -}; - -struct xen_pmu_intel_ctxt { - uint32_t fixed_counters; - uint32_t arch_counters; - uint64_t global_ctrl; - uint64_t global_ovf_ctrl; - uint64_t global_status; - uint64_t fixed_ctrl; - uint64_t ds_area; - uint64_t pebs_enable; - uint64_t debugctl; - uint64_t regs[0]; -}; - -struct xen_pmu_regs { - uint64_t ip; - uint64_t sp; - uint64_t flags; - uint16_t cs; - uint16_t ss; - uint8_t cpl; - uint8_t pad[3]; -}; - -struct xen_pmu_arch { - union { - struct xen_pmu_regs regs; - uint8_t pad[64]; - } r; - uint64_t pmu_flags; - union { - uint32_t lapic_lvtpc; - uint64_t pad; - } l; - union { - struct xen_pmu_amd_ctxt amd; - struct xen_pmu_intel_ctxt intel; - uint8_t pad[128]; - } c; -}; - -struct xen_pmu_params { - struct { - uint32_t maj; - uint32_t min; - } version; - uint64_t val; - uint32_t vcpu; - uint32_t pad; -}; - -struct xen_pmu_data { - uint32_t vcpu_id; - uint32_t pcpu_id; - domid_t domain_id; - uint8_t pad[6]; - struct xen_pmu_arch pmu; -}; - -struct xenpmu { - struct xen_pmu_data *xenpmu_data; - uint8_t flags; -}; - -enum pg_level { - PG_LEVEL_NONE = 0, - PG_LEVEL_4K = 1, - PG_LEVEL_2M = 2, - PG_LEVEL_1G = 3, - PG_LEVEL_512G = 4, - PG_LEVEL_NUM = 5, -}; - -typedef uint32_t grant_ref_t; - -typedef uint32_t grant_handle_t; - -struct gnttab_map_grant_ref { - uint64_t host_addr; - uint32_t flags; - grant_ref_t ref; - domid_t dom; - int16_t status; - grant_handle_t handle; - uint64_t dev_bus_addr; -}; - -struct gnttab_unmap_grant_ref { - uint64_t host_addr; - uint64_t dev_bus_addr; - grant_handle_t handle; - int16_t status; -}; - -enum { - DESC_TSS = 9, - DESC_LDT = 2, - DESCTYPE_S = 16, -}; - -enum paravirt_lazy_mode { - PARAVIRT_LAZY_NONE = 0, - PARAVIRT_LAZY_MMU = 1, - PARAVIRT_LAZY_CPU = 2, -}; - -struct plist_head { - struct list_head node_list; -}; - -enum pm_qos_type { - PM_QOS_UNITIALIZED = 0, - PM_QOS_MAX = 1, - PM_QOS_MIN = 2, -}; - -struct pm_qos_constraints { - struct plist_head list; - s32 target_value; - s32 default_value; - s32 no_constraint_value; - enum pm_qos_type type; - struct blocking_notifier_head *notifiers; -}; - -struct freq_constraints { - struct pm_qos_constraints min_freq; - struct blocking_notifier_head min_freq_notifiers; - struct pm_qos_constraints max_freq; - struct blocking_notifier_head max_freq_notifiers; -}; - -struct pm_qos_flags { - struct list_head list; - s32 effective_flags; -}; - -struct dev_pm_qos_request; - -struct dev_pm_qos { - struct pm_qos_constraints resume_latency; - struct pm_qos_constraints latency_tolerance; - struct freq_constraints freq; - struct pm_qos_flags flags; - struct dev_pm_qos_request *resume_latency_req; - struct dev_pm_qos_request *latency_tolerance_req; - struct dev_pm_qos_request *flags_req; -}; - -typedef long int xen_long_t; - -struct trap_info { - uint8_t vector; - uint8_t flags; - uint16_t cs; - long unsigned int address; -}; - -struct mmuext_op { - unsigned int cmd; - union { - xen_pfn_t mfn; - long unsigned int linear_addr; - } arg1; - union { - unsigned int nr_ents; - void *vcpumask; - xen_pfn_t src_mfn; - } arg2; -}; - -struct multicall_entry { - xen_ulong_t op; - xen_long_t result; - xen_ulong_t args[6]; -}; - -struct dom0_vga_console_info { - uint8_t video_type; - union { - struct { - uint16_t font_height; - uint16_t cursor_x; - uint16_t cursor_y; - uint16_t rows; - uint16_t columns; - } text_mode_3; - struct { - uint16_t width; - uint16_t height; - uint16_t bytes_per_line; - uint16_t bits_per_pixel; - uint32_t lfb_base; - uint32_t lfb_size; - uint8_t red_pos; - uint8_t red_size; - uint8_t green_pos; - uint8_t green_size; - uint8_t blue_pos; - uint8_t blue_size; - uint8_t rsvd_pos; - uint8_t rsvd_size; - uint32_t gbl_caps; - uint16_t mode_attrs; - } vesa_lfb; - } u; -}; - -struct physdev_set_iopl { - uint32_t iopl; -}; - -struct physdev_set_iobitmap { - uint8_t *bitmap; - uint32_t nr_ports; -}; - -struct xen_extraversion { - char extraversion[16]; -}; - -typedef u32 acpi_status; - -struct pm_qos_flags_request { - struct list_head node; - s32 flags; -}; - -enum freq_qos_req_type { - FREQ_QOS_MIN = 1, - FREQ_QOS_MAX = 2, -}; - -struct freq_qos_request { - enum freq_qos_req_type type; - struct plist_node pnode; - struct freq_constraints *qos; -}; - -enum dev_pm_qos_req_type { - DEV_PM_QOS_RESUME_LATENCY = 1, - DEV_PM_QOS_LATENCY_TOLERANCE = 2, - DEV_PM_QOS_MIN_FREQUENCY = 3, - DEV_PM_QOS_MAX_FREQUENCY = 4, - DEV_PM_QOS_FLAGS = 5, -}; - -struct dev_pm_qos_request { - enum dev_pm_qos_req_type type; - union { - struct plist_node pnode; - struct pm_qos_flags_request flr; - struct freq_qos_request freq; - } data; - struct device *dev; -}; - -struct multicall_space { - struct multicall_entry *mc; - void *args; -}; - -struct tls_descs { - struct desc_struct desc[3]; -}; - -struct trap_array_entry { - void (*orig)(); - void (*xen)(); - bool ist_okay; -}; - -struct mmu_gather_batch { - struct mmu_gather_batch *next; - unsigned int nr; - unsigned int max; - struct page *pages[0]; -}; - -struct mmu_table_batch; - -struct mmu_gather { - struct mm_struct *mm; - struct mmu_table_batch *batch; - long unsigned int start; - long unsigned int end; - unsigned int fullmm: 1; - unsigned int need_flush_all: 1; - unsigned int freed_tables: 1; - unsigned int cleared_ptes: 1; - unsigned int cleared_pmds: 1; - unsigned int cleared_puds: 1; - unsigned int cleared_p4ds: 1; - unsigned int vma_exec: 1; - unsigned int vma_huge: 1; - unsigned int batch_count; - struct mmu_gather_batch *active; - struct mmu_gather_batch local; - struct page *__pages[8]; -}; - -struct mmu_table_batch { - struct callback_head rcu; - unsigned int nr; - void *tables[0]; -}; - -struct xen_memory_exchange { - struct xen_memory_reservation in; - struct xen_memory_reservation out; - xen_ulong_t nr_exchanged; -}; - -struct xen_machphys_mapping { - xen_ulong_t v_start; - xen_ulong_t v_end; - xen_ulong_t max_mfn; -}; - -enum pt_level { - PT_PGD = 0, - PT_P4D = 1, - PT_PUD = 2, - PT_PMD = 3, - PT_PTE = 4, -}; - -struct remap_data { - xen_pfn_t *pfn; - bool contiguous; - bool no_translate; - pgprot_t prot; - struct mmu_update *mmu_update; -}; - -enum xen_mc_flush_reason { - XEN_MC_FL_NONE = 0, - XEN_MC_FL_BATCH = 1, - XEN_MC_FL_ARGS = 2, - XEN_MC_FL_CALLBACK = 3, -}; - -enum xen_mc_extend_args { - XEN_MC_XE_OK = 0, - XEN_MC_XE_BAD_OP = 1, - XEN_MC_XE_NO_SPACE = 2, -}; - -typedef void (*xen_mc_callback_fn_t)(void *); - -struct callback { - void (*fn)(void *); - void *data; -}; - -struct mc_buffer { - unsigned int mcidx; - unsigned int argidx; - unsigned int cbidx; - struct multicall_entry entries[32]; - unsigned char args[512]; - struct callback callbacks[32]; -}; - -struct hvm_start_info { - uint32_t magic; - uint32_t version; - uint32_t flags; - uint32_t nr_modules; - uint64_t modlist_paddr; - uint64_t cmdline_paddr; - uint64_t rsdp_paddr; - uint64_t memmap_paddr; - uint32_t memmap_entries; - uint32_t reserved; -}; - -struct trace_event_raw_xen_mc__batch { - struct trace_entry ent; - enum paravirt_lazy_mode mode; - char __data[0]; -}; - -struct trace_event_raw_xen_mc_entry { - struct trace_entry ent; - unsigned int op; - unsigned int nargs; - long unsigned int args[6]; - char __data[0]; -}; - -struct trace_event_raw_xen_mc_entry_alloc { - struct trace_entry ent; - size_t args; - char __data[0]; -}; - -struct trace_event_raw_xen_mc_callback { - struct trace_entry ent; - xen_mc_callback_fn_t fn; - void *data; - char __data[0]; -}; - -struct trace_event_raw_xen_mc_flush_reason { - struct trace_entry ent; - enum xen_mc_flush_reason reason; - char __data[0]; -}; - -struct trace_event_raw_xen_mc_flush { - struct trace_entry ent; - unsigned int mcidx; - unsigned int argidx; - unsigned int cbidx; - char __data[0]; -}; - -struct trace_event_raw_xen_mc_extend_args { - struct trace_entry ent; - unsigned int op; - size_t args; - enum xen_mc_extend_args res; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu__set_pte { - struct trace_entry ent; - pte_t *ptep; - pteval_t pteval; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_set_pmd { - struct trace_entry ent; - pmd_t *pmdp; - pmdval_t pmdval; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_set_pud { - struct trace_entry ent; - pud_t *pudp; - pudval_t pudval; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_set_p4d { - struct trace_entry ent; - p4d_t *p4dp; - p4d_t *user_p4dp; - p4dval_t p4dval; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_ptep_modify_prot { - struct trace_entry ent; - struct mm_struct *mm; - long unsigned int addr; - pte_t *ptep; - pteval_t pteval; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_alloc_ptpage { - struct trace_entry ent; - struct mm_struct *mm; - long unsigned int pfn; - unsigned int level; - bool pinned; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_release_ptpage { - struct trace_entry ent; - long unsigned int pfn; - unsigned int level; - bool pinned; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_pgd { - struct trace_entry ent; - struct mm_struct *mm; - pgd_t *pgd; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_flush_tlb_one_user { - struct trace_entry ent; - long unsigned int addr; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_flush_tlb_multi { - struct trace_entry ent; - unsigned int ncpus; - struct mm_struct *mm; - long unsigned int addr; - long unsigned int end; - char __data[0]; -}; - -struct trace_event_raw_xen_mmu_write_cr3 { - struct trace_entry ent; - bool kernel; - long unsigned int cr3; - char __data[0]; -}; - -struct trace_event_raw_xen_cpu_write_ldt_entry { - struct trace_entry ent; - struct desc_struct *dt; - int entrynum; - u64 desc; - char __data[0]; -}; - -struct trace_event_raw_xen_cpu_write_idt_entry { - struct trace_entry ent; - gate_desc *dt; - int entrynum; - char __data[0]; -}; - -struct trace_event_raw_xen_cpu_load_idt { - struct trace_entry ent; - long unsigned int addr; - char __data[0]; -}; - -struct trace_event_raw_xen_cpu_write_gdt_entry { - struct trace_entry ent; - u64 desc; - struct desc_struct *dt; - int entrynum; - int type; - char __data[0]; -}; - -struct trace_event_raw_xen_cpu_set_ldt { - struct trace_entry ent; - const void *addr; - unsigned int entries; - char __data[0]; -}; - -struct trace_event_data_offsets_xen_mc__batch {}; - -struct trace_event_data_offsets_xen_mc_entry {}; - -struct trace_event_data_offsets_xen_mc_entry_alloc {}; - -struct trace_event_data_offsets_xen_mc_callback {}; - -struct trace_event_data_offsets_xen_mc_flush_reason {}; - -struct trace_event_data_offsets_xen_mc_flush {}; - -struct trace_event_data_offsets_xen_mc_extend_args {}; - -struct trace_event_data_offsets_xen_mmu__set_pte {}; - -struct trace_event_data_offsets_xen_mmu_set_pmd {}; - -struct trace_event_data_offsets_xen_mmu_set_pud {}; - -struct trace_event_data_offsets_xen_mmu_set_p4d {}; - -struct trace_event_data_offsets_xen_mmu_ptep_modify_prot {}; - -struct trace_event_data_offsets_xen_mmu_alloc_ptpage {}; - -struct trace_event_data_offsets_xen_mmu_release_ptpage {}; - -struct trace_event_data_offsets_xen_mmu_pgd {}; - -struct trace_event_data_offsets_xen_mmu_flush_tlb_one_user {}; - -struct trace_event_data_offsets_xen_mmu_flush_tlb_multi {}; - -struct trace_event_data_offsets_xen_mmu_write_cr3 {}; - -struct trace_event_data_offsets_xen_cpu_write_ldt_entry {}; - -struct trace_event_data_offsets_xen_cpu_write_idt_entry {}; - -struct trace_event_data_offsets_xen_cpu_load_idt {}; - -struct trace_event_data_offsets_xen_cpu_write_gdt_entry {}; - -struct trace_event_data_offsets_xen_cpu_set_ldt {}; - -typedef void (*btf_trace_xen_mc_batch)(void *, enum paravirt_lazy_mode); - -typedef void (*btf_trace_xen_mc_issue)(void *, enum paravirt_lazy_mode); - -typedef void (*btf_trace_xen_mc_entry)(void *, struct multicall_entry *, unsigned int); - -typedef void (*btf_trace_xen_mc_entry_alloc)(void *, size_t); - -typedef void (*btf_trace_xen_mc_callback)(void *, xen_mc_callback_fn_t, void *); - -typedef void (*btf_trace_xen_mc_flush_reason)(void *, enum xen_mc_flush_reason); - -typedef void (*btf_trace_xen_mc_flush)(void *, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_xen_mc_extend_args)(void *, long unsigned int, size_t, enum xen_mc_extend_args); - -typedef void (*btf_trace_xen_mmu_set_pte)(void *, pte_t *, pte_t); - -typedef void (*btf_trace_xen_mmu_set_pmd)(void *, pmd_t *, pmd_t); - -typedef void (*btf_trace_xen_mmu_set_pud)(void *, pud_t *, pud_t); - -typedef void (*btf_trace_xen_mmu_set_p4d)(void *, p4d_t *, p4d_t *, p4d_t); - -typedef void (*btf_trace_xen_mmu_ptep_modify_prot_start)(void *, struct mm_struct *, long unsigned int, pte_t *, pte_t); - -typedef void (*btf_trace_xen_mmu_ptep_modify_prot_commit)(void *, struct mm_struct *, long unsigned int, pte_t *, pte_t); - -typedef void (*btf_trace_xen_mmu_alloc_ptpage)(void *, struct mm_struct *, long unsigned int, unsigned int, bool); - -typedef void (*btf_trace_xen_mmu_release_ptpage)(void *, long unsigned int, unsigned int, bool); - -typedef void (*btf_trace_xen_mmu_pgd_pin)(void *, struct mm_struct *, pgd_t *); - -typedef void (*btf_trace_xen_mmu_pgd_unpin)(void *, struct mm_struct *, pgd_t *); - -typedef void (*btf_trace_xen_mmu_flush_tlb_one_user)(void *, long unsigned int); - -typedef void (*btf_trace_xen_mmu_flush_tlb_multi)(void *, const struct cpumask *, struct mm_struct *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_xen_mmu_write_cr3)(void *, bool, long unsigned int); - -typedef void (*btf_trace_xen_cpu_write_ldt_entry)(void *, struct desc_struct *, int, u64); - -typedef void (*btf_trace_xen_cpu_write_idt_entry)(void *, gate_desc *, int, const gate_desc *); - -typedef void (*btf_trace_xen_cpu_load_idt)(void *, const struct desc_ptr *); - -typedef void (*btf_trace_xen_cpu_write_gdt_entry)(void *, struct desc_struct *, int, const void *, int); - -typedef void (*btf_trace_xen_cpu_set_ldt)(void *, const void *, unsigned int); - -enum ipi_vector { - XEN_RESCHEDULE_VECTOR = 0, - XEN_CALL_FUNCTION_VECTOR = 1, - XEN_CALL_FUNCTION_SINGLE_VECTOR = 2, - XEN_SPIN_UNLOCK_VECTOR = 3, - XEN_IRQ_WORK_VECTOR = 4, - XEN_NMI_VECTOR = 5, - XEN_NR_IPIS = 6, -}; - -struct xen_common_irq { - int irq; - char *name; -}; - -struct cpu_user_regs { - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - union { - uint64_t rbp; - uint64_t ebp; - uint32_t _ebp; - }; - union { - uint64_t rbx; - uint64_t ebx; - uint32_t _ebx; - }; - uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - union { - uint64_t rax; - uint64_t eax; - uint32_t _eax; - }; - union { - uint64_t rcx; - uint64_t ecx; - uint32_t _ecx; - }; - union { - uint64_t rdx; - uint64_t edx; - uint32_t _edx; - }; - union { - uint64_t rsi; - uint64_t esi; - uint32_t _esi; - }; - union { - uint64_t rdi; - uint64_t edi; - uint32_t _edi; - }; - uint32_t error_code; - uint32_t entry_vector; - union { - uint64_t rip; - uint64_t eip; - uint32_t _eip; - }; - uint16_t cs; - uint16_t _pad0[1]; - uint8_t saved_upcall_mask; - uint8_t _pad1[3]; - union { - uint64_t rflags; - uint64_t eflags; - uint32_t _eflags; - }; - union { - uint64_t rsp; - uint64_t esp; - uint32_t _esp; - }; - uint16_t ss; - uint16_t _pad2[3]; - uint16_t es; - uint16_t _pad3[3]; - uint16_t ds; - uint16_t _pad4[3]; - uint16_t fs; - uint16_t _pad5[3]; - uint16_t gs; - uint16_t _pad6[3]; -}; - -struct vcpu_guest_context { - struct { - char x[512]; - } fpu_ctxt; - long unsigned int flags; - struct cpu_user_regs user_regs; - struct trap_info trap_ctxt[256]; - long unsigned int ldt_base; - long unsigned int ldt_ents; - long unsigned int gdt_frames[16]; - long unsigned int gdt_ents; - long unsigned int kernel_ss; - long unsigned int kernel_sp; - long unsigned int ctrlreg[8]; - long unsigned int debugreg[8]; - long unsigned int event_callback_eip; - long unsigned int failsafe_callback_eip; - long unsigned int syscall_callback_eip; - long unsigned int vm_assist; - uint64_t fs_base; - uint64_t gs_base_kernel; - uint64_t gs_base_user; -}; - -struct sg_table { - struct scatterlist *sgl; - unsigned int nents; - unsigned int orig_nents; -}; - -enum swiotlb_force { - SWIOTLB_NORMAL = 0, - SWIOTLB_FORCE = 1, - SWIOTLB_NO_FORCE = 2, -}; - -struct iommu_table_entry { - initcall_t detect; - initcall_t depend; - void (*early_init)(); - void (*late_init)(); - int flags; -}; - -union efi_boot_services; - -typedef union efi_boot_services efi_boot_services_t; - -typedef struct { - efi_table_hdr_t hdr; - u32 fw_vendor; - u32 fw_revision; - u32 con_in_handle; - u32 con_in; - u32 con_out_handle; - u32 con_out; - u32 stderr_handle; - u32 stderr; - u32 runtime; - u32 boottime; - u32 nr_tables; - u32 tables; -} efi_system_table_32_t; - -union efi_simple_text_input_protocol; - -typedef union efi_simple_text_input_protocol efi_simple_text_input_protocol_t; - -union efi_simple_text_output_protocol; - -typedef union efi_simple_text_output_protocol efi_simple_text_output_protocol_t; - -typedef union { - struct { - efi_table_hdr_t hdr; - long unsigned int fw_vendor; - u32 fw_revision; - long unsigned int con_in_handle; - efi_simple_text_input_protocol_t *con_in; - long unsigned int con_out_handle; - efi_simple_text_output_protocol_t *con_out; - long unsigned int stderr_handle; - long unsigned int stderr; - efi_runtime_services_t *runtime; - efi_boot_services_t *boottime; - long unsigned int nr_tables; - long unsigned int tables; - }; - efi_system_table_32_t mixed_mode; -} efi_system_table_t; - -enum efi_secureboot_mode { - efi_secureboot_mode_unset = 0, - efi_secureboot_mode_unknown = 1, - efi_secureboot_mode_disabled = 2, - efi_secureboot_mode_enabled = 3, -}; - -struct hvm_modlist_entry { - uint64_t paddr; - uint64_t size; - uint64_t cmdline_paddr; - uint64_t reserved; -}; - -struct hvm_memmap_table_entry { - uint64_t addr; - uint64_t size; - uint32_t type; - uint32_t reserved; -}; - -enum { - WORK_STRUCT_PENDING_BIT = 0, - WORK_STRUCT_DELAYED_BIT = 1, - WORK_STRUCT_PWQ_BIT = 2, - WORK_STRUCT_LINKED_BIT = 3, - WORK_STRUCT_COLOR_SHIFT = 4, - WORK_STRUCT_COLOR_BITS = 4, - WORK_STRUCT_PENDING = 1, - WORK_STRUCT_DELAYED = 2, - WORK_STRUCT_PWQ = 4, - WORK_STRUCT_LINKED = 8, - WORK_STRUCT_STATIC = 0, - WORK_NR_COLORS = 15, - WORK_NO_COLOR = 15, - WORK_CPU_UNBOUND = 320, - WORK_STRUCT_FLAG_BITS = 8, - WORK_OFFQ_FLAG_BASE = 4, - __WORK_OFFQ_CANCELING = 4, - WORK_OFFQ_CANCELING = 16, - WORK_OFFQ_FLAG_BITS = 1, - WORK_OFFQ_POOL_SHIFT = 5, - WORK_OFFQ_LEFT = 59, - WORK_OFFQ_POOL_BITS = 31, - WORK_OFFQ_POOL_NONE = 2147483647, - WORK_STRUCT_FLAG_MASK = 255, - WORK_STRUCT_WQ_DATA_MASK = 4294967040, - WORK_STRUCT_NO_POOL = 4294967264, - WORK_BUSY_PENDING = 1, - WORK_BUSY_RUNNING = 2, - WORKER_DESC_LEN = 24, -}; - -enum { - MEMREMAP_WB = 1, - MEMREMAP_WT = 2, - MEMREMAP_WC = 4, - MEMREMAP_ENC = 8, - MEMREMAP_DEC = 16, -}; - -enum hv_isolation_type { - HV_ISOLATION_TYPE_NONE = 0, - HV_ISOLATION_TYPE_VBS = 1, - HV_ISOLATION_TYPE_SNP = 2, -}; - -union hv_x64_msr_hypercall_contents { - u64 as_uint64; - struct { - u64 enable: 1; - u64 reserved: 11; - u64 guest_physical_address: 52; - }; -}; - -struct hv_reenlightenment_control { - __u64 vector: 8; - __u64 reserved1: 8; - __u64 enabled: 1; - __u64 reserved2: 15; - __u64 target_vp: 32; -}; - -struct hv_tsc_emulation_control { - __u64 enabled: 1; - __u64 reserved: 63; -}; - -struct hv_tsc_emulation_status { - __u64 inprogress: 1; - __u64 reserved: 63; -}; - -struct hv_nested_enlightenments_control { - struct { - __u32 directhypercall: 1; - __u32 reserved: 31; - } features; - struct { - __u32 reserved; - } hypercallControls; -}; - -struct hv_vp_assist_page { - __u32 apic_assist; - __u32 reserved1; - __u64 vtl_control[3]; - struct hv_nested_enlightenments_control nested_control; - __u8 enlighten_vmentry; - __u8 reserved2[7]; - __u64 current_nested_vmcs; -}; - -struct hv_get_partition_id { - u64 partition_id; -}; - -struct ms_hyperv_info { - u32 features; - u32 priv_high; - u32 misc_features; - u32 hints; - u32 nested_features; - u32 max_vp_index; - u32 max_lp_index; - u32 isolation_config_a; - u32 isolation_config_b; -}; - -enum HV_GENERIC_SET_FORMAT { - HV_GENERIC_SET_SPARSE_4K = 0, - HV_GENERIC_SET_ALL = 1, -}; - -struct hv_vpset { - u64 format; - u64 valid_bank_mask; - u64 bank_contents[0]; -}; - -struct hv_tlb_flush { - u64 address_space; - u64 flags; - u64 processor_mask; - u64 gva_list[0]; -}; - -struct hv_tlb_flush_ex { - u64 address_space; - u64 flags; - struct hv_vpset hv_vp_set; - u64 gva_list[0]; -}; - -struct trace_event_raw_hyperv_mmu_flush_tlb_multi { - struct trace_entry ent; - unsigned int ncpus; - struct mm_struct *mm; - long unsigned int addr; - long unsigned int end; - char __data[0]; -}; - -struct trace_event_raw_hyperv_nested_flush_guest_mapping { - struct trace_entry ent; - u64 as; - int ret; - char __data[0]; -}; - -struct trace_event_raw_hyperv_nested_flush_guest_mapping_range { - struct trace_entry ent; - u64 as; - int ret; - char __data[0]; -}; - -struct trace_event_raw_hyperv_send_ipi_mask { - struct trace_entry ent; - unsigned int ncpus; - int vector; - char __data[0]; -}; - -struct trace_event_raw_hyperv_send_ipi_one { - struct trace_entry ent; - int cpu; - int vector; - char __data[0]; -}; - -struct trace_event_data_offsets_hyperv_mmu_flush_tlb_multi {}; - -struct trace_event_data_offsets_hyperv_nested_flush_guest_mapping {}; - -struct trace_event_data_offsets_hyperv_nested_flush_guest_mapping_range {}; - -struct trace_event_data_offsets_hyperv_send_ipi_mask {}; - -struct trace_event_data_offsets_hyperv_send_ipi_one {}; - -typedef void (*btf_trace_hyperv_mmu_flush_tlb_multi)(void *, const struct cpumask *, const struct flush_tlb_info *); - -typedef void (*btf_trace_hyperv_nested_flush_guest_mapping)(void *, u64, int); - -typedef void (*btf_trace_hyperv_nested_flush_guest_mapping_range)(void *, u64, int); - -typedef void (*btf_trace_hyperv_send_ipi_mask)(void *, const struct cpumask *, int); - -typedef void (*btf_trace_hyperv_send_ipi_one)(void *, int, int); - -struct hv_guest_mapping_flush { - u64 address_space; - u64 flags; -}; - -union hv_gpa_page_range { - u64 address_space; - struct { - u64 additional_pages: 11; - u64 largepage: 1; - u64 basepfn: 52; - } page; - struct { - u64 reserved: 12; - u64 page_size: 1; - u64 reserved1: 8; - u64 base_large_pfn: 43; - }; -}; - -struct hv_guest_mapping_flush_list { - u64 address_space; - u64 flags; - union hv_gpa_page_range gpa_list[510]; -}; - -typedef int (*hyperv_fill_flush_list_func)(struct hv_guest_mapping_flush_list *, void *); - -struct acpi_device; - -struct pci_sysdata { - int domain; - int node; - struct acpi_device *companion; - void *iommu; - void *fwnode; - struct pci_dev *vmd_dev; -}; - -enum { - IRQCHIP_SET_TYPE_MASKED = 1, - IRQCHIP_EOI_IF_HANDLED = 2, - IRQCHIP_MASK_ON_SUSPEND = 4, - IRQCHIP_ONOFFLINE_ENABLED = 8, - IRQCHIP_SKIP_SET_WAKE = 16, - IRQCHIP_ONESHOT_SAFE = 32, - IRQCHIP_EOI_THREADED = 64, - IRQCHIP_SUPPORTS_LEVEL_MSI = 128, - IRQCHIP_SUPPORTS_NMI = 256, - IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = 512, - IRQCHIP_AFFINITY_PRE_STARTUP = 1024, -}; - -enum irq_alloc_type { - X86_IRQ_ALLOC_TYPE_IOAPIC = 1, - X86_IRQ_ALLOC_TYPE_HPET = 2, - X86_IRQ_ALLOC_TYPE_PCI_MSI = 3, - X86_IRQ_ALLOC_TYPE_PCI_MSIX = 4, - X86_IRQ_ALLOC_TYPE_DMAR = 5, - X86_IRQ_ALLOC_TYPE_AMDVI = 6, - X86_IRQ_ALLOC_TYPE_UV = 7, -}; - -struct ioapic_alloc_info { - int pin; - int node; - u32 is_level: 1; - u32 active_low: 1; - u32 valid: 1; -}; - -struct uv_alloc_info { - int limit; - int blade; - long unsigned int offset; - char *name; -}; - -struct irq_alloc_info { - enum irq_alloc_type type; - u32 flags; - u32 devid; - irq_hw_number_t hwirq; - const struct cpumask *mask; - struct msi_desc *desc; - void *data; - union { - struct ioapic_alloc_info ioapic; - struct uv_alloc_info uv; - }; -}; - -struct irq_cfg { - unsigned int dest_apicid; - unsigned int vector; -}; - -enum { - IRQCHIP_FWNODE_REAL = 0, - IRQCHIP_FWNODE_NAMED = 1, - IRQCHIP_FWNODE_NAMED_ID = 2, -}; - -typedef struct irq_alloc_info msi_alloc_info_t; - -struct msi_domain_info; - -struct msi_domain_ops { - irq_hw_number_t (*get_hwirq)(struct msi_domain_info *, msi_alloc_info_t *); - int (*msi_init)(struct irq_domain *, struct msi_domain_info *, unsigned int, irq_hw_number_t, msi_alloc_info_t *); - void (*msi_free)(struct irq_domain *, struct msi_domain_info *, unsigned int); - int (*msi_check)(struct irq_domain *, struct msi_domain_info *, struct device *); - int (*msi_prepare)(struct irq_domain *, struct device *, int, msi_alloc_info_t *); - void (*msi_finish)(msi_alloc_info_t *, int); - void (*set_desc)(msi_alloc_info_t *, struct msi_desc *); - int (*handle_error)(struct irq_domain *, struct msi_desc *, int); - int (*domain_alloc_irqs)(struct irq_domain *, struct device *, int); - void (*domain_free_irqs)(struct irq_domain *, struct device *); -}; - -struct msi_domain_info { - u32 flags; - struct msi_domain_ops *ops; - struct irq_chip *chip; - void *chip_data; - irq_flow_handler_t handler; - void *handler_data; - const char *handler_name; - void *data; -}; - -enum { - MSI_FLAG_USE_DEF_DOM_OPS = 1, - MSI_FLAG_USE_DEF_CHIP_OPS = 2, - MSI_FLAG_MULTI_PCI_MSI = 4, - MSI_FLAG_PCI_MSIX = 8, - MSI_FLAG_ACTIVATE_EARLY = 16, - MSI_FLAG_MUST_REACTIVATE = 32, - MSI_FLAG_LEVEL_CAPABLE = 64, -}; - -enum hv_interrupt_type { - HV_X64_INTERRUPT_TYPE_FIXED = 0, - HV_X64_INTERRUPT_TYPE_LOWESTPRIORITY = 1, - HV_X64_INTERRUPT_TYPE_SMI = 2, - HV_X64_INTERRUPT_TYPE_REMOTEREAD = 3, - HV_X64_INTERRUPT_TYPE_NMI = 4, - HV_X64_INTERRUPT_TYPE_INIT = 5, - HV_X64_INTERRUPT_TYPE_SIPI = 6, - HV_X64_INTERRUPT_TYPE_EXTINT = 7, - HV_X64_INTERRUPT_TYPE_LOCALINT0 = 8, - HV_X64_INTERRUPT_TYPE_LOCALINT1 = 9, - HV_X64_INTERRUPT_TYPE_MAXIMUM = 10, -}; - -union hv_msi_address_register { - u32 as_uint32; - struct { - u32 reserved1: 2; - u32 destination_mode: 1; - u32 redirection_hint: 1; - u32 reserved2: 8; - u32 destination_id: 8; - u32 msi_base: 12; - }; -}; - -union hv_msi_data_register { - u32 as_uint32; - struct { - u32 vector: 8; - u32 delivery_mode: 3; - u32 reserved1: 3; - u32 level_assert: 1; - u32 trigger_mode: 1; - u32 reserved2: 16; - }; -}; - -union hv_msi_entry { - u64 as_uint64; - struct { - union hv_msi_address_register address; - union hv_msi_data_register data; - }; -}; - -union hv_ioapic_rte { - u64 as_uint64; - struct { - u32 vector: 8; - u32 delivery_mode: 3; - u32 destination_mode: 1; - u32 delivery_status: 1; - u32 interrupt_polarity: 1; - u32 remote_irr: 1; - u32 trigger_mode: 1; - u32 interrupt_mask: 1; - u32 reserved1: 15; - u32 reserved2: 24; - u32 destination_id: 8; - }; - struct { - u32 low_uint32; - u32 high_uint32; - }; -}; - -struct hv_interrupt_entry { - u32 source; - u32 reserved1; - union { - union hv_msi_entry msi_entry; - union hv_ioapic_rte ioapic_rte; - }; -}; - -struct hv_device_interrupt_target { - u32 vector; - u32 flags; - union { - u64 vp_mask; - struct hv_vpset vp_set; - }; -}; - -enum hv_device_type { - HV_DEVICE_TYPE_LOGICAL = 0, - HV_DEVICE_TYPE_PCI = 1, - HV_DEVICE_TYPE_IOAPIC = 2, - HV_DEVICE_TYPE_ACPI = 3, -}; - -typedef u16 hv_pci_rid; - -typedef u16 hv_pci_segment; - -union hv_pci_bdf { - u16 as_uint16; - struct { - u8 function: 3; - u8 device: 5; - u8 bus; - }; -}; - -union hv_pci_bus_range { - u16 as_uint16; - struct { - u8 subordinate_bus; - u8 secondary_bus; - }; -}; - -union hv_device_id { - u64 as_uint64; - struct { - u64 reserved0: 62; - u64 device_type: 2; - }; - struct { - u64 id: 62; - u64 device_type: 2; - } logical; - struct { - union { - hv_pci_rid rid; - union hv_pci_bdf bdf; - }; - hv_pci_segment segment; - union hv_pci_bus_range shadow_bus_range; - u16 phantom_function_bits: 2; - u16 source_shadow: 1; - u16 rsvdz0: 11; - u16 device_type: 2; - } pci; - struct { - u8 ioapic_id; - u8 rsvdz0; - u16 rsvdz1; - u16 rsvdz2; - u16 rsvdz3: 14; - u16 device_type: 2; - } ioapic; - struct { - u32 input_mapping_base; - u32 input_mapping_count: 30; - u32 device_type: 2; - } acpi; -}; - -enum hv_interrupt_trigger_mode { - HV_INTERRUPT_TRIGGER_MODE_EDGE = 0, - HV_INTERRUPT_TRIGGER_MODE_LEVEL = 1, -}; - -struct hv_device_interrupt_descriptor { - u32 interrupt_type; - u32 trigger_mode; - u32 vector_count; - u32 reserved; - struct hv_device_interrupt_target target; -}; - -struct hv_input_map_device_interrupt { - u64 partition_id; - u64 device_id; - u64 flags; - struct hv_interrupt_entry logical_interrupt_entry; - struct hv_device_interrupt_descriptor interrupt_descriptor; -}; - -struct hv_output_map_device_interrupt { - struct hv_interrupt_entry interrupt_entry; -}; - -struct hv_input_unmap_device_interrupt { - u64 partition_id; - u64 device_id; - struct hv_interrupt_entry interrupt_entry; -}; - -struct rid_data { - struct pci_dev *bridge; - u32 rid; -}; - -struct hv_send_ipi { - u32 vector; - u32 reserved; - u64 cpu_mask; -}; - -struct hv_send_ipi_ex { - u32 vector; - u32 reserved; - struct hv_vpset vp_set; -}; - -struct hv_deposit_memory { - u64 partition_id; - u64 gpa_page_list[0]; -}; - -struct hv_proximity_domain_flags { - u32 proximity_preferred: 1; - u32 reserved: 30; - u32 proximity_info_valid: 1; -}; - -union hv_proximity_domain_info { - struct { - u32 domain_id; - struct hv_proximity_domain_flags flags; - }; - u64 as_uint64; -}; - -struct hv_lp_startup_status { - u64 hv_status; - u64 substatus1; - u64 substatus2; - u64 substatus3; - u64 substatus4; - u64 substatus5; - u64 substatus6; -}; - -struct hv_add_logical_processor_in { - u32 lp_index; - u32 apic_id; - union hv_proximity_domain_info proximity_domain_info; - u64 flags; -}; - -struct hv_add_logical_processor_out { - struct hv_lp_startup_status startup_status; -}; - -enum HV_SUBNODE_TYPE { - HvSubnodeAny = 0, - HvSubnodeSocket = 1, - HvSubnodeAmdNode = 2, - HvSubnodeL3 = 3, - HvSubnodeCount = 4, - HvSubnodeInvalid = 4294967295, -}; - -struct hv_create_vp { - u64 partition_id; - u32 vp_index; - u8 padding[3]; - u8 subnode_type; - u64 subnode_id; - union hv_proximity_domain_info proximity_domain_info; - u64 flags; -}; - -struct real_mode_header { - u32 text_start; - u32 ro_end; - u32 trampoline_start; - u32 trampoline_header; - u32 sev_es_trampoline_start; - u32 trampoline_pgd; - u32 wakeup_start; - u32 wakeup_header; - u32 machine_real_restart_asm; - u32 machine_real_restart_seg; -}; - -struct trampoline_header { - u64 start; - u64 efer; - u32 cr4; - u32 flags; -}; - -enum show_regs_mode { - SHOW_REGS_SHORT = 0, - SHOW_REGS_USER = 1, - SHOW_REGS_ALL = 2, -}; - -struct resctrl_pqr_state { - u32 cur_rmid; - u32 cur_closid; - u32 default_rmid; - u32 default_closid; -}; - -enum which_selector { - FS = 0, - GS = 1, -}; - -struct sigcontext_64 { - __u64 r8; - __u64 r9; - __u64 r10; - __u64 r11; - __u64 r12; - __u64 r13; - __u64 r14; - __u64 r15; - __u64 di; - __u64 si; - __u64 bp; - __u64 bx; - __u64 dx; - __u64 ax; - __u64 cx; - __u64 sp; - __u64 ip; - __u64 flags; - __u16 cs; - __u16 gs; - __u16 fs; - __u16 ss; - __u64 err; - __u64 trapno; - __u64 oldmask; - __u64 cr2; - __u64 fpstate; - __u64 reserved1[8]; -}; - -struct sigaltstack { - void *ss_sp; - int ss_flags; - size_t ss_size; -}; - -typedef struct sigaltstack stack_t; - -struct siginfo { - union { - struct { - int si_signo; - int si_errno; - int si_code; - union __sifields _sifields; - }; - int _si_pad[32]; - }; -}; - -typedef struct siginfo siginfo_t; - -struct ksignal { - struct k_sigaction ka; - kernel_siginfo_t info; - int sig; -}; - -struct __large_struct { - long unsigned int buf[100]; -}; - -typedef u32 compat_sigset_word; - -typedef struct { - compat_sigset_word sig[2]; -} compat_sigset_t; - -struct ucontext { - long unsigned int uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - struct sigcontext_64 uc_mcontext; - sigset_t uc_sigmask; -}; - -struct kernel_vm86_regs { - struct pt_regs pt; - short unsigned int es; - short unsigned int __esh; - short unsigned int ds; - short unsigned int __dsh; - short unsigned int fs; - short unsigned int __fsh; - short unsigned int gs; - short unsigned int __gsh; -}; - -struct rt_sigframe { - char *pretcode; - struct ucontext uc; - struct siginfo info; -}; - -typedef s32 compat_clock_t; - -typedef s32 compat_pid_t; - -typedef s32 compat_timer_t; - -typedef s32 compat_int_t; - -typedef u32 compat_ulong_t; - -typedef u32 __compat_uid32_t; - -union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -}; - -typedef union compat_sigval compat_sigval_t; - -struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - union { - int _pad[29]; - struct { - compat_pid_t _pid; - __compat_uid32_t _uid; - } _kill; - struct { - compat_timer_t _tid; - int _overrun; - compat_sigval_t _sigval; - } _timer; - struct { - compat_pid_t _pid; - __compat_uid32_t _uid; - compat_sigval_t _sigval; - } _rt; - struct { - compat_pid_t _pid; - __compat_uid32_t _uid; - int _status; - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - struct { - compat_uptr_t _addr; - union { - int _trapno; - short int _addr_lsb; - struct { - char _dummy_bnd[4]; - compat_uptr_t _lower; - compat_uptr_t _upper; - } _addr_bnd; - struct { - char _dummy_pkey[4]; - u32 _pkey; - } _addr_pkey; - struct { - compat_ulong_t _data; - u32 _type; - } _perf; - }; - } _sigfault; - struct { - compat_long_t _band; - int _fd; - } _sigpoll; - struct { - compat_uptr_t _call_addr; - int _syscall; - unsigned int _arch; - } _sigsys; - } _sifields; -}; - -typedef struct compat_siginfo compat_siginfo_t; - -enum bug_trap_type { - BUG_TRAP_TYPE_NONE = 0, - BUG_TRAP_TYPE_WARN = 1, - BUG_TRAP_TYPE_BUG = 2, -}; - -enum insn_mode { - INSN_MODE_32 = 0, - INSN_MODE_64 = 1, - INSN_MODE_KERN = 2, - INSN_NUM_MODES = 3, -}; - -typedef u8 kprobe_opcode_t; - -struct kprobe; - -struct arch_specific_insn { - kprobe_opcode_t *insn; - unsigned int boostable: 1; - unsigned char size; - union { - unsigned char opcode; - struct { - unsigned char type; - } jcc; - struct { - unsigned char type; - unsigned char asize; - } loop; - struct { - unsigned char reg; - } indirect; - }; - s32 rel32; - void (*emulate_op)(struct kprobe *, struct pt_regs *); - int tp_len; -}; - -typedef int (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *); - -typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *, long unsigned int); - -struct kprobe { - struct hlist_node hlist; - struct list_head list; - long unsigned int nmissed; - kprobe_opcode_t *addr; - const char *symbol_name; - unsigned int offset; - kprobe_pre_handler_t pre_handler; - kprobe_post_handler_t post_handler; - kprobe_opcode_t opcode; - struct arch_specific_insn ainsn; - u32 flags; -}; - -enum die_val { - DIE_OOPS = 1, - DIE_INT3 = 2, - DIE_DEBUG = 3, - DIE_PANIC = 4, - DIE_NMI = 5, - DIE_DIE = 6, - DIE_KERNELDEBUG = 7, - DIE_TRAP = 8, - DIE_GPF = 9, - DIE_CALL = 10, - DIE_PAGE_FAULT = 11, - DIE_NMIUNKNOWN = 12, -}; - -enum kernel_gp_hint { - GP_NO_HINT = 0, - GP_NON_CANONICAL = 1, - GP_CANONICAL = 2, -}; - -struct bad_iret_stack { - void *error_entry_ret; - struct pt_regs regs; -}; - -typedef struct irq_desc *vector_irq_t[256]; - -struct trace_event_raw_x86_irq_vector { - struct trace_entry ent; - int vector; - char __data[0]; -}; - -struct trace_event_raw_vector_config { - struct trace_entry ent; - unsigned int irq; - unsigned int vector; - unsigned int cpu; - unsigned int apicdest; - char __data[0]; -}; - -struct trace_event_raw_vector_mod { - struct trace_entry ent; - unsigned int irq; - unsigned int vector; - unsigned int cpu; - unsigned int prev_vector; - unsigned int prev_cpu; - char __data[0]; -}; - -struct trace_event_raw_vector_reserve { - struct trace_entry ent; - unsigned int irq; - int ret; - char __data[0]; -}; - -struct trace_event_raw_vector_alloc { - struct trace_entry ent; - unsigned int irq; - unsigned int vector; - bool reserved; - int ret; - char __data[0]; -}; - -struct trace_event_raw_vector_alloc_managed { - struct trace_entry ent; - unsigned int irq; - unsigned int vector; - int ret; - char __data[0]; -}; - -struct trace_event_raw_vector_activate { - struct trace_entry ent; - unsigned int irq; - bool is_managed; - bool can_reserve; - bool reserve; - char __data[0]; -}; - -struct trace_event_raw_vector_teardown { - struct trace_entry ent; - unsigned int irq; - bool is_managed; - bool has_reserved; - char __data[0]; -}; - -struct trace_event_raw_vector_setup { - struct trace_entry ent; - unsigned int irq; - bool is_legacy; - int ret; - char __data[0]; -}; - -struct trace_event_raw_vector_free_moved { - struct trace_entry ent; - unsigned int irq; - unsigned int cpu; - unsigned int vector; - bool is_managed; - char __data[0]; -}; - -struct trace_event_data_offsets_x86_irq_vector {}; - -struct trace_event_data_offsets_vector_config {}; - -struct trace_event_data_offsets_vector_mod {}; - -struct trace_event_data_offsets_vector_reserve {}; - -struct trace_event_data_offsets_vector_alloc {}; - -struct trace_event_data_offsets_vector_alloc_managed {}; - -struct trace_event_data_offsets_vector_activate {}; - -struct trace_event_data_offsets_vector_teardown {}; - -struct trace_event_data_offsets_vector_setup {}; - -struct trace_event_data_offsets_vector_free_moved {}; - -typedef void (*btf_trace_local_timer_entry)(void *, int); - -typedef void (*btf_trace_local_timer_exit)(void *, int); - -typedef void (*btf_trace_spurious_apic_entry)(void *, int); - -typedef void (*btf_trace_spurious_apic_exit)(void *, int); - -typedef void (*btf_trace_error_apic_entry)(void *, int); - -typedef void (*btf_trace_error_apic_exit)(void *, int); - -typedef void (*btf_trace_x86_platform_ipi_entry)(void *, int); - -typedef void (*btf_trace_x86_platform_ipi_exit)(void *, int); - -typedef void (*btf_trace_irq_work_entry)(void *, int); - -typedef void (*btf_trace_irq_work_exit)(void *, int); - -typedef void (*btf_trace_reschedule_entry)(void *, int); - -typedef void (*btf_trace_reschedule_exit)(void *, int); - -typedef void (*btf_trace_call_function_entry)(void *, int); - -typedef void (*btf_trace_call_function_exit)(void *, int); - -typedef void (*btf_trace_call_function_single_entry)(void *, int); - -typedef void (*btf_trace_call_function_single_exit)(void *, int); - -typedef void (*btf_trace_threshold_apic_entry)(void *, int); - -typedef void (*btf_trace_threshold_apic_exit)(void *, int); - -typedef void (*btf_trace_deferred_error_apic_entry)(void *, int); - -typedef void (*btf_trace_deferred_error_apic_exit)(void *, int); - -typedef void (*btf_trace_thermal_apic_entry)(void *, int); - -typedef void (*btf_trace_thermal_apic_exit)(void *, int); - -typedef void (*btf_trace_vector_config)(void *, unsigned int, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_vector_update)(void *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_vector_clear)(void *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_vector_reserve_managed)(void *, unsigned int, int); - -typedef void (*btf_trace_vector_reserve)(void *, unsigned int, int); - -typedef void (*btf_trace_vector_alloc)(void *, unsigned int, unsigned int, bool, int); - -typedef void (*btf_trace_vector_alloc_managed)(void *, unsigned int, unsigned int, int); - -typedef void (*btf_trace_vector_activate)(void *, unsigned int, bool, bool, bool); - -typedef void (*btf_trace_vector_deactivate)(void *, unsigned int, bool, bool, bool); - -typedef void (*btf_trace_vector_teardown)(void *, unsigned int, bool, bool); - -typedef void (*btf_trace_vector_setup)(void *, unsigned int, bool, int); - -typedef void (*btf_trace_vector_free_moved)(void *, unsigned int, unsigned int, unsigned int, bool); - -struct irq_stack { - char stack[16384]; -}; - -struct estack_pages { - u32 offs; - u16 size; - u16 type; -}; - -enum lockdown_reason { - LOCKDOWN_NONE = 0, - LOCKDOWN_MODULE_SIGNATURE = 1, - LOCKDOWN_DEV_MEM = 2, - LOCKDOWN_EFI_TEST = 3, - LOCKDOWN_KEXEC = 4, - LOCKDOWN_HIBERNATION = 5, - LOCKDOWN_PCI_ACCESS = 6, - LOCKDOWN_IOPORT = 7, - LOCKDOWN_MSR = 8, - LOCKDOWN_ACPI_TABLES = 9, - LOCKDOWN_PCMCIA_CIS = 10, - LOCKDOWN_TIOCSSERIAL = 11, - LOCKDOWN_MODULE_PARAMETERS = 12, - LOCKDOWN_MMIOTRACE = 13, - LOCKDOWN_DEBUGFS = 14, - LOCKDOWN_XMON_WR = 15, - LOCKDOWN_BPF_WRITE_USER = 16, - LOCKDOWN_INTEGRITY_MAX = 17, - LOCKDOWN_KCORE = 18, - LOCKDOWN_KPROBES = 19, - LOCKDOWN_BPF_READ_KERNEL = 20, - LOCKDOWN_PERF = 21, - LOCKDOWN_TRACEFS = 22, - LOCKDOWN_XMON_RW = 23, - LOCKDOWN_XFRM_SECRET = 24, - LOCKDOWN_CONFIDENTIALITY_MAX = 25, -}; - -enum lockdep_ok { - LOCKDEP_STILL_OK = 0, - LOCKDEP_NOW_UNRELIABLE = 1, -}; - -struct trace_event_raw_nmi_handler { - struct trace_entry ent; - void *handler; - s64 delta_ns; - int handled; - char __data[0]; -}; - -struct trace_event_data_offsets_nmi_handler {}; - -typedef void (*btf_trace_nmi_handler)(void *, void *, s64, int); - -struct nmi_desc { - raw_spinlock_t lock; - struct list_head head; -}; - -struct nmi_stats { - unsigned int normal; - unsigned int unknown; - unsigned int external; - unsigned int swallow; -}; - -enum nmi_states { - NMI_NOT_RUNNING = 0, - NMI_EXECUTING = 1, - NMI_LATCHED = 2, -}; - -struct user_desc { - unsigned int entry_number; - unsigned int base_addr; - unsigned int limit; - unsigned int seg_32bit: 1; - unsigned int contents: 2; - unsigned int read_exec_only: 1; - unsigned int limit_in_pages: 1; - unsigned int seg_not_present: 1; - unsigned int useable: 1; - unsigned int lm: 1; -}; - -enum con_scroll { - SM_UP = 0, - SM_DOWN = 1, -}; - -enum vc_intensity { - VCI_HALF_BRIGHT = 0, - VCI_NORMAL = 1, - VCI_BOLD = 2, - VCI_MASK = 3, -}; - -struct vc_data; - -struct console_font; - -struct consw { - struct module *owner; - const char * (*con_startup)(); - void (*con_init)(struct vc_data *, int); - void (*con_deinit)(struct vc_data *); - void (*con_clear)(struct vc_data *, int, int, int, int); - void (*con_putc)(struct vc_data *, int, int, int); - void (*con_putcs)(struct vc_data *, const short unsigned int *, int, int, int); - void (*con_cursor)(struct vc_data *, int); - bool (*con_scroll)(struct vc_data *, unsigned int, unsigned int, enum con_scroll, unsigned int); - int (*con_switch)(struct vc_data *); - int (*con_blank)(struct vc_data *, int, int); - int (*con_font_set)(struct vc_data *, struct console_font *, unsigned int); - int (*con_font_get)(struct vc_data *, struct console_font *); - int (*con_font_default)(struct vc_data *, struct console_font *, char *); - int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); - void (*con_set_palette)(struct vc_data *, const unsigned char *); - void (*con_scrolldelta)(struct vc_data *, int); - int (*con_set_origin)(struct vc_data *); - void (*con_save_screen)(struct vc_data *); - u8 (*con_build_attr)(struct vc_data *, u8, enum vc_intensity, bool, bool, bool, bool); - void (*con_invert_region)(struct vc_data *, u16 *, int); - u16 * (*con_screen_pos)(const struct vc_data *, int); - long unsigned int (*con_getxy)(struct vc_data *, long unsigned int, int *, int *); - void (*con_flush_scrollback)(struct vc_data *); - int (*con_debug_enter)(struct vc_data *); - int (*con_debug_leave)(struct vc_data *); -}; - -struct vc_state { - unsigned int x; - unsigned int y; - unsigned char color; - unsigned char Gx_charset[2]; - unsigned int charset: 1; - enum vc_intensity intensity; - bool italic; - bool underline; - bool blink; - bool reverse; -}; - -struct console_font { - unsigned int width; - unsigned int height; - unsigned int charcount; - unsigned char *data; -}; - -struct vt_mode { - char mode; - char waitv; - short int relsig; - short int acqsig; - short int frsig; -}; - -struct uni_pagedir; - -struct uni_screen; - -struct vc_data { - struct tty_port port; - struct vc_state state; - struct vc_state saved_state; - short unsigned int vc_num; - unsigned int vc_cols; - unsigned int vc_rows; - unsigned int vc_size_row; - unsigned int vc_scan_lines; - unsigned int vc_cell_height; - long unsigned int vc_origin; - long unsigned int vc_scr_end; - long unsigned int vc_visible_origin; - unsigned int vc_top; - unsigned int vc_bottom; - const struct consw *vc_sw; - short unsigned int *vc_screenbuf; - unsigned int vc_screenbuf_size; - unsigned char vc_mode; - unsigned char vc_attr; - unsigned char vc_def_color; - unsigned char vc_ulcolor; - unsigned char vc_itcolor; - unsigned char vc_halfcolor; - unsigned int vc_cursor_type; - short unsigned int vc_complement_mask; - short unsigned int vc_s_complement_mask; - long unsigned int vc_pos; - short unsigned int vc_hi_font_mask; - struct console_font vc_font; - short unsigned int vc_video_erase_char; - unsigned int vc_state; - unsigned int vc_npar; - unsigned int vc_par[16]; - struct vt_mode vt_mode; - struct pid *vt_pid; - int vt_newvt; - wait_queue_head_t paste_wait; - unsigned int vc_disp_ctrl: 1; - unsigned int vc_toggle_meta: 1; - unsigned int vc_decscnm: 1; - unsigned int vc_decom: 1; - unsigned int vc_decawm: 1; - unsigned int vc_deccm: 1; - unsigned int vc_decim: 1; - unsigned int vc_priv: 3; - unsigned int vc_need_wrap: 1; - unsigned int vc_can_do_color: 1; - unsigned int vc_report_mouse: 2; - unsigned char vc_utf: 1; - unsigned char vc_utf_count; - int vc_utf_char; - long unsigned int vc_tab_stop[4]; - unsigned char vc_palette[48]; - short unsigned int *vc_translate; - unsigned int vc_resize_user; - unsigned int vc_bell_pitch; - unsigned int vc_bell_duration; - short unsigned int vc_cur_blink_ms; - struct vc_data **vc_display_fg; - struct uni_pagedir *vc_uni_pagedir; - struct uni_pagedir **vc_uni_pagedir_loc; - struct uni_screen *vc_uni_screen; -}; - -struct edd { - unsigned int mbr_signature[16]; - struct edd_info edd_info[6]; - unsigned char mbr_signature_nr; - unsigned char edd_info_nr; -}; - -struct setup_data { - __u64 next; - __u32 type; - __u32 len; - __u8 data[0]; -}; - -struct setup_indirect { - __u32 type; - __u32 reserved; - __u64 len; - __u64 addr; -}; - -enum memblock_flags { - MEMBLOCK_NONE = 0, - MEMBLOCK_HOTPLUG = 1, - MEMBLOCK_MIRROR = 2, - MEMBLOCK_NOMAP = 4, -}; - -struct memblock_region { - phys_addr_t base; - phys_addr_t size; - enum memblock_flags flags; - int nid; -}; - -struct memblock_type { - long unsigned int cnt; - long unsigned int max; - phys_addr_t total_size; - struct memblock_region *regions; - char *name; -}; - -struct memblock { - bool bottom_up; - phys_addr_t current_limit; - struct memblock_type memory; - struct memblock_type reserved; -}; - -struct x86_msi_ops { - void (*restore_msi_irqs)(struct pci_dev *); -}; - -struct legacy_pic { - int nr_legacy_irqs; - struct irq_chip *chip; - void (*mask)(unsigned int); - void (*unmask)(unsigned int); - void (*mask_all)(); - void (*restore_mask)(); - void (*init)(int); - int (*probe)(); - int (*irq_pending)(unsigned int); - void (*make_irq)(unsigned int); -}; - -enum jump_label_type { - JUMP_LABEL_NOP = 0, - JUMP_LABEL_JMP = 1, -}; - -union text_poke_insn { - u8 text[5]; - struct { - u8 opcode; - s32 disp; - } __attribute__((packed)); -}; - -struct jump_label_patch { - const void *code; - int size; -}; - -enum { - JL_STATE_START = 0, - JL_STATE_NO_UPDATE = 1, - JL_STATE_UPDATE = 2, -}; - -typedef short unsigned int __kernel_old_uid_t; - -typedef short unsigned int __kernel_old_gid_t; - -typedef struct { - int val[2]; -} __kernel_fsid_t; - -typedef __kernel_old_uid_t old_uid_t; - -typedef __kernel_old_gid_t old_gid_t; - -struct kernel_clone_args { - u64 flags; - int *pidfd; - int *child_tid; - int *parent_tid; - int exit_signal; - long unsigned int stack; - long unsigned int stack_size; - long unsigned int tls; - pid_t *set_tid; - size_t set_tid_size; - int cgroup; - int io_thread; - struct cgroup *cgrp; - struct css_set *cset; -}; - -struct kstatfs { - long int f_type; - long int f_bsize; - u64 f_blocks; - u64 f_bfree; - u64 f_bavail; - u64 f_files; - u64 f_ffree; - __kernel_fsid_t f_fsid; - long int f_namelen; - long int f_frsize; - long int f_flags; - long int f_spare[4]; -}; - -struct stat64 { - long long unsigned int st_dev; - unsigned char __pad0[4]; - unsigned int __st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - long long unsigned int st_rdev; - unsigned char __pad3[4]; - long long int st_size; - unsigned int st_blksize; - long long int st_blocks; - unsigned int st_atime; - unsigned int st_atime_nsec; - unsigned int st_mtime; - unsigned int st_mtime_nsec; - unsigned int st_ctime; - unsigned int st_ctime_nsec; - long long unsigned int st_ino; -} __attribute__((packed)); - -struct mmap_arg_struct32 { - unsigned int addr; - unsigned int len; - unsigned int prot; - unsigned int flags; - unsigned int fd; - unsigned int offset; -}; - -struct vm_unmapped_area_info { - long unsigned int flags; - long unsigned int length; - long unsigned int low_limit; - long unsigned int high_limit; - long unsigned int align_mask; - long unsigned int align_offset; -}; - -enum align_flags { - ALIGN_VA_32 = 1, - ALIGN_VA_64 = 2, -}; - -struct va_alignment { - int flags; - long unsigned int mask; - long unsigned int bits; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct kobj_attribute { - struct attribute attr; - ssize_t (*show)(struct kobject *, struct kobj_attribute *, char *); - ssize_t (*store)(struct kobject *, struct kobj_attribute *, const char *, size_t); -}; - -typedef void (*swap_func_t)(void *, void *, int); - -typedef int (*cmp_func_t)(const void *, const void *); - -enum { - IORES_DESC_NONE = 0, - IORES_DESC_CRASH_KERNEL = 1, - IORES_DESC_ACPI_TABLES = 2, - IORES_DESC_ACPI_NV_STORAGE = 3, - IORES_DESC_PERSISTENT_MEMORY = 4, - IORES_DESC_PERSISTENT_MEMORY_LEGACY = 5, - IORES_DESC_DEVICE_PRIVATE_MEMORY = 6, - IORES_DESC_RESERVED = 7, - IORES_DESC_SOFT_RESERVED = 8, -}; - -struct change_member { - struct e820_entry *entry; - long long unsigned int addr; -}; - -struct iommu_fault_param; - -struct iopf_device_param; - -struct iommu_fwspec; - -struct dev_iommu { - struct mutex lock; - struct iommu_fault_param *fault_param; - struct iopf_device_param *iopf_param; - struct iommu_fwspec *fwspec; - struct iommu_device *iommu_dev; - void *priv; -}; - -struct of_phandle_args { - struct device_node *np; - int args_count; - uint32_t args[16]; -}; - -struct iommu_fault_unrecoverable { - __u32 reason; - __u32 flags; - __u32 pasid; - __u32 perm; - __u64 addr; - __u64 fetch_addr; -}; - -struct iommu_fault_page_request { - __u32 flags; - __u32 pasid; - __u32 grpid; - __u32 perm; - __u64 addr; - __u64 private_data[2]; -}; - -struct iommu_fault { - __u32 type; - __u32 padding; - union { - struct iommu_fault_unrecoverable event; - struct iommu_fault_page_request prm; - __u8 padding2[56]; - }; -}; - -struct iommu_page_response { - __u32 argsz; - __u32 version; - __u32 flags; - __u32 pasid; - __u32 grpid; - __u32 code; -}; - -struct iommu_inv_addr_info { - __u32 flags; - __u32 archid; - __u64 pasid; - __u64 addr; - __u64 granule_size; - __u64 nb_granules; -}; - -struct iommu_inv_pasid_info { - __u32 flags; - __u32 archid; - __u64 pasid; -}; - -struct iommu_cache_invalidate_info { - __u32 argsz; - __u32 version; - __u8 cache; - __u8 granularity; - __u8 padding[6]; - union { - struct iommu_inv_pasid_info pasid_info; - struct iommu_inv_addr_info addr_info; - } granu; -}; - -struct iommu_gpasid_bind_data_vtd { - __u64 flags; - __u32 pat; - __u32 emt; -}; - -struct iommu_gpasid_bind_data { - __u32 argsz; - __u32 version; - __u32 format; - __u32 addr_width; - __u64 flags; - __u64 gpgd; - __u64 hpasid; - __u64 gpasid; - __u8 padding[8]; - union { - struct iommu_gpasid_bind_data_vtd vtd; - } vendor; -}; - -typedef int (*iommu_fault_handler_t)(struct iommu_domain *, struct device *, long unsigned int, int, void *); - -struct iommu_domain_geometry { - dma_addr_t aperture_start; - dma_addr_t aperture_end; - bool force_aperture; -}; - -struct iommu_domain { - unsigned int type; - const struct iommu_ops *ops; - long unsigned int pgsize_bitmap; - iommu_fault_handler_t handler; - void *handler_token; - struct iommu_domain_geometry geometry; - void *iova_cookie; -}; - -typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *); - -enum iommu_resv_type { - IOMMU_RESV_DIRECT = 0, - IOMMU_RESV_DIRECT_RELAXABLE = 1, - IOMMU_RESV_RESERVED = 2, - IOMMU_RESV_MSI = 3, - IOMMU_RESV_SW_MSI = 4, -}; - -struct iommu_resv_region { - struct list_head list; - phys_addr_t start; - size_t length; - int prot; - enum iommu_resv_type type; -}; - -struct iommu_iotlb_gather { - long unsigned int start; - long unsigned int end; - size_t pgsize; - struct page *freelist; -}; - -struct iommu_device { - struct list_head list; - const struct iommu_ops *ops; - struct fwnode_handle *fwnode; - struct device *dev; -}; - -struct iommu_sva { - struct device *dev; -}; - -struct iommu_fault_event { - struct iommu_fault fault; - struct list_head list; -}; - -struct iommu_fault_param { - iommu_dev_fault_handler_t handler; - void *data; - struct list_head faults; - struct mutex lock; -}; - -struct iommu_fwspec { - const struct iommu_ops *ops; - struct fwnode_handle *iommu_fwnode; - u32 flags; - unsigned int num_ids; - u32 ids[0]; -}; - -enum dmi_field { - DMI_NONE = 0, - DMI_BIOS_VENDOR = 1, - DMI_BIOS_VERSION = 2, - DMI_BIOS_DATE = 3, - DMI_BIOS_RELEASE = 4, - DMI_EC_FIRMWARE_RELEASE = 5, - DMI_SYS_VENDOR = 6, - DMI_PRODUCT_NAME = 7, - DMI_PRODUCT_VERSION = 8, - DMI_PRODUCT_SERIAL = 9, - DMI_PRODUCT_UUID = 10, - DMI_PRODUCT_SKU = 11, - DMI_PRODUCT_FAMILY = 12, - DMI_BOARD_VENDOR = 13, - DMI_BOARD_NAME = 14, - DMI_BOARD_VERSION = 15, - DMI_BOARD_SERIAL = 16, - DMI_BOARD_ASSET_TAG = 17, - DMI_CHASSIS_VENDOR = 18, - DMI_CHASSIS_TYPE = 19, - DMI_CHASSIS_VERSION = 20, - DMI_CHASSIS_SERIAL = 21, - DMI_CHASSIS_ASSET_TAG = 22, - DMI_STRING_MAX = 23, - DMI_OEM_STRING = 24, -}; - -enum { - NONE_FORCE_HPET_RESUME = 0, - OLD_ICH_FORCE_HPET_RESUME = 1, - ICH_FORCE_HPET_RESUME = 2, - VT8237_FORCE_HPET_RESUME = 3, - NVIDIA_FORCE_HPET_RESUME = 4, - ATI_FORCE_HPET_RESUME = 5, -}; - -enum meminit_context { - MEMINIT_EARLY = 0, - MEMINIT_HOTPLUG = 1, -}; - -struct cpu { - int node_id; - int hotpluggable; - struct device dev; -}; - -struct x86_cpu { - struct cpu cpu; -}; - -struct debugfs_blob_wrapper { - void *data; - long unsigned int size; -}; - -struct setup_data_node { - u64 paddr; - u32 type; - u32 len; -}; - -struct paravirt_patch_site { - u8 *instr; - u8 type; - u8 len; -}; - -struct die_args { - struct pt_regs *regs; - const char *str; - long int err; - int trapnr; - int signr; -}; - -struct tlb_state_shared { - bool is_lazy; -}; - -struct smp_alt_module { - struct module *mod; - char *name; - const s32 *locks; - const s32 *locks_end; - u8 *text; - u8 *text_end; - struct list_head next; -}; - -typedef struct { - struct mm_struct *mm; -} temp_mm_state_t; - -struct text_poke_loc { - s32 rel_addr; - s32 rel32; - u8 opcode; - const u8 text[5]; - u8 old; -}; - -struct bp_patching_desc { - struct text_poke_loc *vec; - int nr_entries; - atomic_t refs; -}; - -enum { - HW_BREAKPOINT_LEN_1 = 1, - HW_BREAKPOINT_LEN_2 = 2, - HW_BREAKPOINT_LEN_3 = 3, - HW_BREAKPOINT_LEN_4 = 4, - HW_BREAKPOINT_LEN_5 = 5, - HW_BREAKPOINT_LEN_6 = 6, - HW_BREAKPOINT_LEN_7 = 7, - HW_BREAKPOINT_LEN_8 = 8, -}; - -enum { - HW_BREAKPOINT_EMPTY = 0, - HW_BREAKPOINT_R = 1, - HW_BREAKPOINT_W = 2, - HW_BREAKPOINT_RW = 3, - HW_BREAKPOINT_X = 4, - HW_BREAKPOINT_INVALID = 7, -}; - -typedef unsigned int u_int; - -typedef long long unsigned int cycles_t; - -struct system_counterval_t { - u64 cycles; - struct clocksource *cs; -}; - -typedef struct { - seqcount_t seqcount; -} seqcount_latch_t; - -enum cpufreq_table_sorting { - CPUFREQ_TABLE_UNSORTED = 0, - CPUFREQ_TABLE_SORTED_ASCENDING = 1, - CPUFREQ_TABLE_SORTED_DESCENDING = 2, -}; - -struct cpufreq_cpuinfo { - unsigned int max_freq; - unsigned int min_freq; - unsigned int transition_latency; -}; - -struct clk; - -struct cpufreq_governor; - -struct cpufreq_frequency_table; - -struct cpufreq_stats; - -struct thermal_cooling_device; - -struct cpufreq_policy { - cpumask_var_t cpus; - cpumask_var_t related_cpus; - cpumask_var_t real_cpus; - unsigned int shared_type; - unsigned int cpu; - struct clk *clk; - struct cpufreq_cpuinfo cpuinfo; - unsigned int min; - unsigned int max; - unsigned int cur; - unsigned int suspend_freq; - unsigned int policy; - unsigned int last_policy; - struct cpufreq_governor *governor; - void *governor_data; - char last_governor[16]; - struct work_struct update; - struct freq_constraints constraints; - struct freq_qos_request *min_freq_req; - struct freq_qos_request *max_freq_req; - struct cpufreq_frequency_table *freq_table; - enum cpufreq_table_sorting freq_table_sorted; - struct list_head policy_list; - struct kobject kobj; - struct completion kobj_unregister; - struct rw_semaphore rwsem; - bool fast_switch_possible; - bool fast_switch_enabled; - bool strict_target; - unsigned int transition_delay_us; - bool dvfs_possible_from_any_cpu; - unsigned int cached_target_freq; - unsigned int cached_resolved_idx; - bool transition_ongoing; - spinlock_t transition_lock; - wait_queue_head_t transition_wait; - struct task_struct *transition_task; - struct cpufreq_stats *stats; - void *driver_data; - struct thermal_cooling_device *cdev; - struct notifier_block nb_min; - struct notifier_block nb_max; -}; - -struct cpufreq_governor { - char name[16]; - int (*init)(struct cpufreq_policy *); - void (*exit)(struct cpufreq_policy *); - int (*start)(struct cpufreq_policy *); - void (*stop)(struct cpufreq_policy *); - void (*limits)(struct cpufreq_policy *); - ssize_t (*show_setspeed)(struct cpufreq_policy *, char *); - int (*store_setspeed)(struct cpufreq_policy *, unsigned int); - struct list_head governor_list; - struct module *owner; - u8 flags; -}; - -struct cpufreq_frequency_table { - unsigned int flags; - unsigned int driver_data; - unsigned int frequency; -}; - -struct cpufreq_freqs { - struct cpufreq_policy *policy; - unsigned int old; - unsigned int new; - u8 flags; -}; - -struct cyc2ns { - struct cyc2ns_data data[2]; - seqcount_latch_t seq; -}; - -struct x86_cpu_id { - __u16 vendor; - __u16 family; - __u16 model; - __u16 steppings; - __u16 feature; - kernel_ulong_t driver_data; -}; - -struct muldiv { - u32 multiplier; - u32 divider; -}; - -struct freq_desc { - bool use_msr_plat; - struct muldiv muldiv[16]; - u32 freqs[16]; - u32 mask; -}; - -struct dmi_strmatch { - unsigned char slot: 7; - unsigned char exact_match: 1; - char substr[79]; -}; - -struct dmi_system_id { - int (*callback)(const struct dmi_system_id *); - const char *ident; - struct dmi_strmatch matches[4]; - void *driver_data; -}; - -struct pdev_archdata {}; - -struct platform_device_id; - -struct mfd_cell; - -struct platform_device { - const char *name; - int id; - bool id_auto; - struct device dev; - u64 platform_dma_mask; - struct device_dma_parameters dma_parms; - u32 num_resources; - struct resource *resource; - const struct platform_device_id *id_entry; - char *driver_override; - struct mfd_cell *mfd_cell; - struct pdev_archdata archdata; -}; - -struct platform_device_id { - char name[20]; - kernel_ulong_t driver_data; -}; - -struct rtc_time { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -struct pnp_device_id { - __u8 id[8]; - kernel_ulong_t driver_data; -}; - -struct pnp_card_device_id { - __u8 id[8]; - kernel_ulong_t driver_data; - struct { - __u8 id[8]; - } devs[8]; -}; - -struct acpi_table_header { - char signature[4]; - u32 length; - u8 revision; - u8 checksum; - char oem_id[6]; - char oem_table_id[8]; - u32 oem_revision; - char asl_compiler_id[4]; - u32 asl_compiler_revision; -}; - -struct acpi_generic_address { - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 access_width; - u64 address; -} __attribute__((packed)); - -struct acpi_table_fadt { - struct acpi_table_header header; - u32 facs; - u32 dsdt; - u8 model; - u8 preferred_profile; - u16 sci_interrupt; - u32 smi_command; - u8 acpi_enable; - u8 acpi_disable; - u8 s4_bios_request; - u8 pstate_control; - u32 pm1a_event_block; - u32 pm1b_event_block; - u32 pm1a_control_block; - u32 pm1b_control_block; - u32 pm2_control_block; - u32 pm_timer_block; - u32 gpe0_block; - u32 gpe1_block; - u8 pm1_event_length; - u8 pm1_control_length; - u8 pm2_control_length; - u8 pm_timer_length; - u8 gpe0_block_length; - u8 gpe1_block_length; - u8 gpe1_base; - u8 cst_control; - u16 c2_latency; - u16 c3_latency; - u16 flush_size; - u16 flush_stride; - u8 duty_offset; - u8 duty_width; - u8 day_alarm; - u8 month_alarm; - u8 century; - u16 boot_flags; - u8 reserved; - u32 flags; - struct acpi_generic_address reset_register; - u8 reset_value; - u16 arm_boot_flags; - u8 minor_revision; - u64 Xfacs; - u64 Xdsdt; - struct acpi_generic_address xpm1a_event_block; - struct acpi_generic_address xpm1b_event_block; - struct acpi_generic_address xpm1a_control_block; - struct acpi_generic_address xpm1b_control_block; - struct acpi_generic_address xpm2_control_block; - struct acpi_generic_address xpm_timer_block; - struct acpi_generic_address xgpe0_block; - struct acpi_generic_address xgpe1_block; - struct acpi_generic_address sleep_control; - struct acpi_generic_address sleep_status; - u64 hypervisor_id; -} __attribute__((packed)); - -struct pnp_protocol; - -struct pnp_id; - -struct pnp_card { - struct device dev; - unsigned char number; - struct list_head global_list; - struct list_head protocol_list; - struct list_head devices; - struct pnp_protocol *protocol; - struct pnp_id *id; - char name[50]; - unsigned char pnpver; - unsigned char productver; - unsigned int serial; - unsigned char checksum; - struct proc_dir_entry *procdir; -}; - -struct pnp_dev; - -struct pnp_protocol { - struct list_head protocol_list; - char *name; - int (*get)(struct pnp_dev *); - int (*set)(struct pnp_dev *); - int (*disable)(struct pnp_dev *); - bool (*can_wakeup)(struct pnp_dev *); - int (*suspend)(struct pnp_dev *, pm_message_t); - int (*resume)(struct pnp_dev *); - unsigned char number; - struct device dev; - struct list_head cards; - struct list_head devices; -}; - -struct pnp_id { - char id[8]; - struct pnp_id *next; -}; - -struct pnp_card_driver; - -struct pnp_card_link { - struct pnp_card *card; - struct pnp_card_driver *driver; - void *driver_data; - pm_message_t pm_state; -}; - -struct pnp_driver { - const char *name; - const struct pnp_device_id *id_table; - unsigned int flags; - int (*probe)(struct pnp_dev *, const struct pnp_device_id *); - void (*remove)(struct pnp_dev *); - void (*shutdown)(struct pnp_dev *); - int (*suspend)(struct pnp_dev *, pm_message_t); - int (*resume)(struct pnp_dev *); - struct device_driver driver; -}; - -struct pnp_card_driver { - struct list_head global_list; - char *name; - const struct pnp_card_device_id *id_table; - unsigned int flags; - int (*probe)(struct pnp_card_link *, const struct pnp_card_device_id *); - void (*remove)(struct pnp_card_link *); - int (*suspend)(struct pnp_card_link *, pm_message_t); - int (*resume)(struct pnp_card_link *); - struct pnp_driver link; -}; - -struct pnp_dev { - struct device dev; - u64 dma_mask; - unsigned int number; - int status; - struct list_head global_list; - struct list_head protocol_list; - struct list_head card_list; - struct list_head rdev_list; - struct pnp_protocol *protocol; - struct pnp_card *card; - struct pnp_driver *driver; - struct pnp_card_link *card_link; - struct pnp_id *id; - int active; - int capabilities; - unsigned int num_dependent_sets; - struct list_head resources; - struct list_head options; - char name[50]; - int flags; - struct proc_dir_entry *procent; - void *data; -}; - -enum insn_type { - CALL = 0, - NOP = 1, - JMP = 2, - RET = 3, -}; - -struct ldttss_desc { - u16 limit0; - u16 base0; - u16 base1: 8; - u16 type: 5; - u16 dpl: 2; - u16 p: 1; - u16 limit1: 4; - u16 zero0: 3; - u16 g: 1; - u16 base2: 8; - u32 base3; - u32 zero1; -}; - -typedef struct ldttss_desc tss_desc; - -enum idle_boot_override { - IDLE_NO_OVERRIDE = 0, - IDLE_HALT = 1, - IDLE_NOMWAIT = 2, - IDLE_POLL = 3, -}; - -enum tick_broadcast_mode { - TICK_BROADCAST_OFF = 0, - TICK_BROADCAST_ON = 1, - TICK_BROADCAST_FORCE = 2, -}; - -enum tick_broadcast_state { - TICK_BROADCAST_EXIT = 0, - TICK_BROADCAST_ENTER = 1, -}; - -struct inactive_task_frame { - long unsigned int r15; - long unsigned int r14; - long unsigned int r13; - long unsigned int r12; - long unsigned int bx; - long unsigned int bp; - long unsigned int ret_addr; -}; - -struct fork_frame { - struct inactive_task_frame frame; - struct pt_regs regs; -}; - -struct ssb_state { - struct ssb_state *shared_state; - raw_spinlock_t lock; - unsigned int disable_state; - long unsigned int local_state; -}; - -struct trace_event_raw_x86_fpu { - struct trace_entry ent; - struct fpu *fpu; - bool load_fpu; - u64 xfeatures; - u64 xcomp_bv; - char __data[0]; -}; - -struct trace_event_data_offsets_x86_fpu {}; - -typedef void (*btf_trace_x86_fpu_before_save)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_after_save)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_before_restore)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_after_restore)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_regs_activated)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_regs_deactivated)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_init_state)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_dropped)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_copy_src)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_copy_dst)(void *, struct fpu *); - -typedef void (*btf_trace_x86_fpu_xstate_check_failed)(void *, struct fpu *); - -struct _fpreg { - __u16 significand[4]; - __u16 exponent; -}; - -struct _fpxreg { - __u16 significand[4]; - __u16 exponent; - __u16 padding[3]; -}; - -struct user_i387_ia32_struct { - u32 cwd; - u32 swd; - u32 twd; - u32 fip; - u32 fcs; - u32 foo; - u32 fos; - u32 st_space[20]; -}; - -struct user32_fxsr_struct { - short unsigned int cwd; - short unsigned int swd; - short unsigned int twd; - short unsigned int fop; - int fip; - int fcs; - int foo; - int fos; - int mxcsr; - int reserved; - int st_space[32]; - int xmm_space[32]; - int padding[56]; -}; - -enum xstate_copy_mode { - XSTATE_COPY_FP = 0, - XSTATE_COPY_FX = 1, - XSTATE_COPY_XSAVE = 2, -}; - -struct membuf { - void *p; - size_t left; -}; - -struct user_regset; - -typedef int user_regset_active_fn(struct task_struct *, const struct user_regset *); - -typedef int user_regset_get2_fn(struct task_struct *, const struct user_regset *, struct membuf); - -typedef int user_regset_set_fn(struct task_struct *, const struct user_regset *, unsigned int, unsigned int, const void *, const void *); - -typedef int user_regset_writeback_fn(struct task_struct *, const struct user_regset *, int); - -struct user_regset { - user_regset_get2_fn *regset_get; - user_regset_set_fn *set; - user_regset_active_fn *active; - user_regset_writeback_fn *writeback; - unsigned int n; - unsigned int size; - unsigned int align; - unsigned int bias; - unsigned int core_note_type; -}; - -struct _fpx_sw_bytes { - __u32 magic1; - __u32 extended_size; - __u64 xfeatures; - __u32 xstate_size; - __u32 padding[7]; -}; - -struct _xmmreg { - __u32 element[4]; -}; - -struct _fpstate_32 { - __u32 cw; - __u32 sw; - __u32 tag; - __u32 ipoff; - __u32 cssel; - __u32 dataoff; - __u32 datasel; - struct _fpreg _st[8]; - __u16 status; - __u16 magic; - __u32 _fxsr_env[6]; - __u32 mxcsr; - __u32 reserved; - struct _fpxreg _fxsr_st[8]; - struct _xmmreg _xmm[8]; - union { - __u32 padding1[44]; - __u32 padding[44]; - }; - union { - __u32 padding2[12]; - struct _fpx_sw_bytes sw_reserved; - }; -}; - -struct pkru_state { - u32 pkru; - u32 pad; -}; - -struct user_regset_view { - const char *name; - const struct user_regset *regsets; - unsigned int n; - u32 e_flags; - u16 e_machine; - u8 ei_osabi; -}; - -enum x86_regset { - REGSET_GENERAL = 0, - REGSET_FP = 1, - REGSET_XFP = 2, - REGSET_IOPERM64 = 2, - REGSET_XSTATE = 3, - REGSET_TLS = 4, - REGSET_IOPERM32 = 5, -}; - -struct pt_regs_offset { - const char *name; - int offset; -}; - -typedef bool (*stack_trace_consume_fn)(void *, long unsigned int); - -struct stack_frame_user { - const void *next_fp; - long unsigned int ret_addr; -}; - -enum cache_type { - CACHE_TYPE_NOCACHE = 0, - CACHE_TYPE_INST = 1, - CACHE_TYPE_DATA = 2, - CACHE_TYPE_SEPARATE = 3, - CACHE_TYPE_UNIFIED = 4, -}; - -struct cacheinfo { - unsigned int id; - enum cache_type type; - unsigned int level; - unsigned int coherency_line_size; - unsigned int number_of_sets; - unsigned int ways_of_associativity; - unsigned int physical_line_partition; - unsigned int size; - cpumask_t shared_cpu_map; - unsigned int attributes; - void *fw_token; - bool disable_sysfs; - void *priv; -}; - -struct cpu_cacheinfo { - struct cacheinfo *info_list; - unsigned int num_levels; - unsigned int num_leaves; - bool cpu_map_populated; -}; - -struct amd_l3_cache { - unsigned int indices; - u8 subcaches[4]; -}; - -struct threshold_block { - unsigned int block; - unsigned int bank; - unsigned int cpu; - u32 address; - u16 interrupt_enable; - bool interrupt_capable; - u16 threshold_limit; - struct kobject kobj; - struct list_head miscj; -}; - -struct threshold_bank { - struct kobject *kobj; - struct threshold_block *blocks; - refcount_t cpus; - unsigned int shared; -}; - -struct amd_northbridge { - struct pci_dev *root; - struct pci_dev *misc; - struct pci_dev *link; - struct amd_l3_cache l3_cache; - struct threshold_bank *bank4; -}; - -struct _cache_table { - unsigned char descriptor; - char cache_type; - short int size; -}; - -enum _cache_type { - CTYPE_NULL = 0, - CTYPE_DATA = 1, - CTYPE_INST = 2, - CTYPE_UNIFIED = 3, -}; - -union _cpuid4_leaf_eax { - struct { - enum _cache_type type: 5; - unsigned int level: 3; - unsigned int is_self_initializing: 1; - unsigned int is_fully_associative: 1; - unsigned int reserved: 4; - unsigned int num_threads_sharing: 12; - unsigned int num_cores_on_die: 6; - } split; - u32 full; -}; - -union _cpuid4_leaf_ebx { - struct { - unsigned int coherency_line_size: 12; - unsigned int physical_line_partition: 10; - unsigned int ways_of_associativity: 10; - } split; - u32 full; -}; - -union _cpuid4_leaf_ecx { - struct { - unsigned int number_of_sets: 32; - } split; - u32 full; -}; - -struct _cpuid4_info_regs { - union _cpuid4_leaf_eax eax; - union _cpuid4_leaf_ebx ebx; - union _cpuid4_leaf_ecx ecx; - unsigned int id; - long unsigned int size; - struct amd_northbridge *nb; -}; - -union l1_cache { - struct { - unsigned int line_size: 8; - unsigned int lines_per_tag: 8; - unsigned int assoc: 8; - unsigned int size_in_kb: 8; - }; - unsigned int val; -}; - -union l2_cache { - struct { - unsigned int line_size: 8; - unsigned int lines_per_tag: 4; - unsigned int assoc: 4; - unsigned int size_in_kb: 16; - }; - unsigned int val; -}; - -union l3_cache { - struct { - unsigned int line_size: 8; - unsigned int lines_per_tag: 4; - unsigned int assoc: 4; - unsigned int res: 2; - unsigned int size_encoded: 14; - }; - unsigned int val; -}; - -struct cpuid_bit { - u16 feature; - u8 reg; - u8 bit; - u32 level; - u32 sub_leaf; -}; - -enum cpuid_leafs { - CPUID_1_EDX = 0, - CPUID_8000_0001_EDX = 1, - CPUID_8086_0001_EDX = 2, - CPUID_LNX_1 = 3, - CPUID_1_ECX = 4, - CPUID_C000_0001_EDX = 5, - CPUID_8000_0001_ECX = 6, - CPUID_LNX_2 = 7, - CPUID_LNX_3 = 8, - CPUID_7_0_EBX = 9, - CPUID_D_1_EAX = 10, - CPUID_LNX_4 = 11, - CPUID_7_1_EAX = 12, - CPUID_8000_0008_EBX = 13, - CPUID_6_EAX = 14, - CPUID_8000_000A_EDX = 15, - CPUID_7_ECX = 16, - CPUID_8000_0007_EBX = 17, - CPUID_7_EDX = 18, - CPUID_8000_001F_EAX = 19, -}; - -struct cpu_dev { - const char *c_vendor; - const char *c_ident[2]; - void (*c_early_init)(struct cpuinfo_x86 *); - void (*c_bsp_init)(struct cpuinfo_x86 *); - void (*c_init)(struct cpuinfo_x86 *); - void (*c_identify)(struct cpuinfo_x86 *); - void (*c_detect_tlb)(struct cpuinfo_x86 *); - int c_x86_vendor; -}; - -struct cpuid_dependent_feature { - u32 feature; - u32 level; -}; - -enum spectre_v2_mitigation { - SPECTRE_V2_NONE = 0, - SPECTRE_V2_RETPOLINE_GENERIC = 1, - SPECTRE_V2_RETPOLINE_AMD = 2, - SPECTRE_V2_IBRS_ENHANCED = 3, -}; - -enum spectre_v2_user_mitigation { - SPECTRE_V2_USER_NONE = 0, - SPECTRE_V2_USER_STRICT = 1, - SPECTRE_V2_USER_STRICT_PREFERRED = 2, - SPECTRE_V2_USER_PRCTL = 3, - SPECTRE_V2_USER_SECCOMP = 4, -}; - -enum ssb_mitigation { - SPEC_STORE_BYPASS_NONE = 0, - SPEC_STORE_BYPASS_DISABLE = 1, - SPEC_STORE_BYPASS_PRCTL = 2, - SPEC_STORE_BYPASS_SECCOMP = 3, -}; - -enum l1tf_mitigations { - L1TF_MITIGATION_OFF = 0, - L1TF_MITIGATION_FLUSH_NOWARN = 1, - L1TF_MITIGATION_FLUSH = 2, - L1TF_MITIGATION_FLUSH_NOSMT = 3, - L1TF_MITIGATION_FULL = 4, - L1TF_MITIGATION_FULL_FORCE = 5, -}; - -enum mds_mitigations { - MDS_MITIGATION_OFF = 0, - MDS_MITIGATION_FULL = 1, - MDS_MITIGATION_VMWERV = 2, -}; - -enum cpuhp_smt_control { - CPU_SMT_ENABLED = 0, - CPU_SMT_DISABLED = 1, - CPU_SMT_FORCE_DISABLED = 2, - CPU_SMT_NOT_SUPPORTED = 3, - CPU_SMT_NOT_IMPLEMENTED = 4, -}; - -enum vmx_l1d_flush_state { - VMENTER_L1D_FLUSH_AUTO = 0, - VMENTER_L1D_FLUSH_NEVER = 1, - VMENTER_L1D_FLUSH_COND = 2, - VMENTER_L1D_FLUSH_ALWAYS = 3, - VMENTER_L1D_FLUSH_EPT_DISABLED = 4, - VMENTER_L1D_FLUSH_NOT_REQUIRED = 5, -}; - -enum taa_mitigations { - TAA_MITIGATION_OFF = 0, - TAA_MITIGATION_UCODE_NEEDED = 1, - TAA_MITIGATION_VERW = 2, - TAA_MITIGATION_TSX_DISABLED = 3, -}; - -enum srbds_mitigations { - SRBDS_MITIGATION_OFF = 0, - SRBDS_MITIGATION_UCODE_NEEDED = 1, - SRBDS_MITIGATION_FULL = 2, - SRBDS_MITIGATION_TSX_OFF = 3, - SRBDS_MITIGATION_HYPERVISOR = 4, -}; - -enum spectre_v1_mitigation { - SPECTRE_V1_MITIGATION_NONE = 0, - SPECTRE_V1_MITIGATION_AUTO = 1, -}; - -enum spectre_v2_mitigation_cmd { - SPECTRE_V2_CMD_NONE = 0, - SPECTRE_V2_CMD_AUTO = 1, - SPECTRE_V2_CMD_FORCE = 2, - SPECTRE_V2_CMD_RETPOLINE = 3, - SPECTRE_V2_CMD_RETPOLINE_GENERIC = 4, - SPECTRE_V2_CMD_RETPOLINE_AMD = 5, -}; - -enum spectre_v2_user_cmd { - SPECTRE_V2_USER_CMD_NONE = 0, - SPECTRE_V2_USER_CMD_AUTO = 1, - SPECTRE_V2_USER_CMD_FORCE = 2, - SPECTRE_V2_USER_CMD_PRCTL = 3, - SPECTRE_V2_USER_CMD_PRCTL_IBPB = 4, - SPECTRE_V2_USER_CMD_SECCOMP = 5, - SPECTRE_V2_USER_CMD_SECCOMP_IBPB = 6, -}; - -enum ssb_mitigation_cmd { - SPEC_STORE_BYPASS_CMD_NONE = 0, - SPEC_STORE_BYPASS_CMD_AUTO = 1, - SPEC_STORE_BYPASS_CMD_ON = 2, - SPEC_STORE_BYPASS_CMD_PRCTL = 3, - SPEC_STORE_BYPASS_CMD_SECCOMP = 4, -}; - -enum hk_flags { - HK_FLAG_TIMER = 1, - HK_FLAG_RCU = 2, - HK_FLAG_MISC = 4, - HK_FLAG_SCHED = 8, - HK_FLAG_TICK = 16, - HK_FLAG_DOMAIN = 32, - HK_FLAG_WQ = 64, - HK_FLAG_MANAGED_IRQ = 128, - HK_FLAG_KTHREAD = 256, -}; - -struct aperfmperf_sample { - unsigned int khz; - atomic_t scfpending; - ktime_t time; - u64 aperf; - u64 mperf; -}; - -struct cpuid_dep { - unsigned int feature; - unsigned int depends; -}; - -enum vmx_feature_leafs { - MISC_FEATURES = 0, - PRIMARY_CTLS = 1, - SECONDARY_CTLS = 2, - NR_VMX_FEATURE_WORDS = 3, -}; - -struct _tlb_table { - unsigned char descriptor; - char tlb_type; - unsigned int entries; - char info[128]; -}; - -enum tsx_ctrl_states { - TSX_CTRL_ENABLE = 0, - TSX_CTRL_DISABLE = 1, - TSX_CTRL_RTM_ALWAYS_ABORT = 2, - TSX_CTRL_NOT_SUPPORTED = 3, -}; - -enum split_lock_detect_state { - sld_off = 0, - sld_warn = 1, - sld_fatal = 2, - sld_ratelimit = 3, -}; - -struct sku_microcode { - u8 model; - u8 stepping; - u32 microcode; -}; - -struct cpuid_regs { - u32 eax; - u32 ebx; - u32 ecx; - u32 edx; -}; - -enum pconfig_target { - INVALID_TARGET = 0, - MKTME_TARGET = 1, - PCONFIG_TARGET_NR = 2, -}; - -enum { - PCONFIG_CPUID_SUBLEAF_INVALID = 0, - PCONFIG_CPUID_SUBLEAF_TARGETID = 1, -}; - -enum task_work_notify_mode { - TWA_NONE = 0, - TWA_RESUME = 1, - TWA_SIGNAL = 2, -}; - -enum mf_flags { - MF_COUNT_INCREASED = 1, - MF_ACTION_REQUIRED = 2, - MF_MUST_KILL = 4, - MF_SOFT_OFFLINE = 8, -}; - -struct mce { - __u64 status; - __u64 misc; - __u64 addr; - __u64 mcgstatus; - __u64 ip; - __u64 tsc; - __u64 time; - __u8 cpuvendor; - __u8 inject_flags; - __u8 severity; - __u8 pad; - __u32 cpuid; - __u8 cs; - __u8 bank; - __u8 cpu; - __u8 finished; - __u32 extcpu; - __u32 socketid; - __u32 apicid; - __u64 mcgcap; - __u64 synd; - __u64 ipid; - __u64 ppin; - __u32 microcode; - __u64 kflags; -}; - -enum mce_notifier_prios { - MCE_PRIO_LOWEST = 0, - MCE_PRIO_MCELOG = 1, - MCE_PRIO_EDAC = 2, - MCE_PRIO_NFIT = 3, - MCE_PRIO_EXTLOG = 4, - MCE_PRIO_UC = 5, - MCE_PRIO_EARLY = 6, - MCE_PRIO_CEC = 7, - MCE_PRIO_HIGHEST = 7, -}; - -typedef long unsigned int mce_banks_t[1]; - -enum mcp_flags { - MCP_TIMESTAMP = 1, - MCP_UC = 2, - MCP_DONTLOG = 4, -}; - -enum severity_level { - MCE_NO_SEVERITY = 0, - MCE_DEFERRED_SEVERITY = 1, - MCE_UCNA_SEVERITY = 1, - MCE_KEEP_SEVERITY = 2, - MCE_SOME_SEVERITY = 3, - MCE_AO_SEVERITY = 4, - MCE_UC_SEVERITY = 5, - MCE_AR_SEVERITY = 6, - MCE_PANIC_SEVERITY = 7, -}; - -struct mce_evt_llist { - struct llist_node llnode; - struct mce mce; -}; - -struct mca_config { - bool dont_log_ce; - bool cmci_disabled; - bool ignore_ce; - bool print_all; - __u64 lmce_disabled: 1; - __u64 disabled: 1; - __u64 ser: 1; - __u64 recovery: 1; - __u64 bios_cmci_threshold: 1; - int: 27; - __u64 __reserved: 59; - s8 bootlog; - int tolerant; - int monarch_timeout; - int panic_timeout; - u32 rip_msr; -}; - -struct mce_vendor_flags { - __u64 overflow_recov: 1; - __u64 succor: 1; - __u64 smca: 1; - __u64 amd_threshold: 1; - __u64 __reserved_0: 60; -}; - -struct mca_msr_regs { - u32 (*ctl)(int); - u32 (*status)(int); - u32 (*addr)(int); - u32 (*misc)(int); -}; - -struct trace_event_raw_mce_record { - struct trace_entry ent; - u64 mcgcap; - u64 mcgstatus; - u64 status; - u64 addr; - u64 misc; - u64 synd; - u64 ipid; - u64 ip; - u64 tsc; - u64 walltime; - u32 cpu; - u32 cpuid; - u32 apicid; - u32 socketid; - u8 cs; - u8 bank; - u8 cpuvendor; - char __data[0]; -}; - -struct trace_event_data_offsets_mce_record {}; - -typedef void (*btf_trace_mce_record)(void *, struct mce *); - -struct mce_bank { - u64 ctl; - bool init; -}; - -struct mce_bank_dev { - struct device_attribute attr; - char attrname[16]; - u8 bank; -}; - -enum handler_type { - EX_HANDLER_NONE = 0, - EX_HANDLER_FAULT = 1, - EX_HANDLER_UACCESS = 2, - EX_HANDLER_OTHER = 3, -}; - -enum context { - IN_KERNEL = 1, - IN_USER = 2, - IN_KERNEL_RECOV = 3, -}; - -enum ser { - SER_REQUIRED = 1, - NO_SER = 2, -}; - -enum exception { - EXCP_CONTEXT = 1, - NO_EXCP = 2, -}; - -struct severity { - u64 mask; - u64 result; - unsigned char sev; - unsigned char mcgmask; - unsigned char mcgres; - unsigned char ser; - unsigned char context; - unsigned char excp; - unsigned char covered; - unsigned char cpu_model; - unsigned char cpu_minstepping; - unsigned char bank_lo; - unsigned char bank_hi; - char *msg; -}; - -struct gen_pool; - -typedef long unsigned int (*genpool_algo_t)(long unsigned int *, long unsigned int, long unsigned int, unsigned int, void *, struct gen_pool *, long unsigned int); - -struct gen_pool { - spinlock_t lock; - struct list_head chunks; - int min_alloc_order; - genpool_algo_t algo; - void *data; - const char *name; -}; - -enum { - CMCI_STORM_NONE = 0, - CMCI_STORM_ACTIVE = 1, - CMCI_STORM_SUBSIDED = 2, -}; - -enum kobject_action { - KOBJ_ADD = 0, - KOBJ_REMOVE = 1, - KOBJ_CHANGE = 2, - KOBJ_MOVE = 3, - KOBJ_ONLINE = 4, - KOBJ_OFFLINE = 5, - KOBJ_BIND = 6, - KOBJ_UNBIND = 7, -}; - -enum smca_bank_types { - SMCA_LS = 0, - SMCA_LS_V2 = 1, - SMCA_IF = 2, - SMCA_L2_CACHE = 3, - SMCA_DE = 4, - SMCA_RESERVED = 5, - SMCA_EX = 6, - SMCA_FP = 7, - SMCA_L3_CACHE = 8, - SMCA_CS = 9, - SMCA_CS_V2 = 10, - SMCA_PIE = 11, - SMCA_UMC = 12, - SMCA_UMC_V2 = 13, - SMCA_PB = 14, - SMCA_PSP = 15, - SMCA_PSP_V2 = 16, - SMCA_SMU = 17, - SMCA_SMU_V2 = 18, - SMCA_MP5 = 19, - SMCA_NBIO = 20, - SMCA_PCIE = 21, - SMCA_PCIE_V2 = 22, - SMCA_XGMI_PCS = 23, - SMCA_XGMI_PHY = 24, - SMCA_WAFL_PHY = 25, - N_SMCA_BANK_TYPES = 26, -}; - -struct smca_hwid { - unsigned int bank_type; - u32 hwid_mcatype; - u8 count; -}; - -struct smca_bank { - struct smca_hwid *hwid; - u32 id; - u8 sysfs_id; -}; - -struct smca_bank_name { - const char *name; - const char *long_name; -}; - -struct thresh_restart { - struct threshold_block *b; - int reset; - int set_lvt_off; - int lvt_off; - u16 old_limit; -}; - -struct threshold_attr { - struct attribute attr; - ssize_t (*show)(struct threshold_block *, char *); - ssize_t (*store)(struct threshold_block *, const char *, size_t); -}; - -enum { - CPER_SEV_RECOVERABLE = 0, - CPER_SEV_FATAL = 1, - CPER_SEV_CORRECTED = 2, - CPER_SEV_INFORMATIONAL = 3, -}; - -struct cper_record_header { - char signature[4]; - u16 revision; - u32 signature_end; - u16 section_count; - u32 error_severity; - u32 validation_bits; - u32 record_length; - u64 timestamp; - guid_t platform_id; - guid_t partition_id; - guid_t creator_id; - guid_t notification_type; - u64 record_id; - u32 flags; - u64 persistence_information; - u8 reserved[12]; -} __attribute__((packed)); - -struct cper_section_descriptor { - u32 section_offset; - u32 section_length; - u16 revision; - u8 validation_bits; - u8 reserved; - u32 flags; - guid_t section_type; - guid_t fru_id; - u32 section_severity; - u8 fru_text[20]; -}; - -struct cper_ia_proc_ctx { - u16 reg_ctx_type; - u16 reg_arr_size; - u32 msr_addr; - u64 mm_reg_addr; -}; - -struct cper_sec_mem_err { - u64 validation_bits; - u64 error_status; - u64 physical_addr; - u64 physical_addr_mask; - u16 node; - u16 card; - u16 module; - u16 bank; - u16 device; - u16 row; - u16 column; - u16 bit_pos; - u64 requestor_id; - u64 responder_id; - u64 target_id; - u8 error_type; - u8 extended; - u16 rank; - u16 mem_array_handle; - u16 mem_dev_handle; -}; - -enum { - GHES_SEV_NO = 0, - GHES_SEV_CORRECTED = 1, - GHES_SEV_RECOVERABLE = 2, - GHES_SEV_PANIC = 3, -}; - -struct cper_mce_record { - struct cper_record_header hdr; - struct cper_section_descriptor sec_hdr; - struct mce mce; -}; - -typedef int (*cpu_stop_fn_t)(void *); - -typedef __u8 mtrr_type; - -struct mtrr_ops { - u32 vendor; - u32 use_intel_if; - void (*set)(unsigned int, long unsigned int, long unsigned int, mtrr_type); - void (*set_all)(); - void (*get)(unsigned int, long unsigned int *, long unsigned int *, mtrr_type *); - int (*get_free_region)(long unsigned int, long unsigned int, int); - int (*validate_add_page)(long unsigned int, long unsigned int, unsigned int); - int (*have_wrcomb)(); -}; - -struct set_mtrr_data { - long unsigned int smp_base; - long unsigned int smp_size; - unsigned int smp_reg; - mtrr_type smp_type; -}; - -struct mtrr_value { - mtrr_type ltype; - long unsigned int lbase; - long unsigned int lsize; -}; - -struct proc_ops { - unsigned int proc_flags; - int (*proc_open)(struct inode *, struct file *); - ssize_t (*proc_read)(struct file *, char *, size_t, loff_t *); - ssize_t (*proc_read_iter)(struct kiocb *, struct iov_iter *); - ssize_t (*proc_write)(struct file *, const char *, size_t, loff_t *); - loff_t (*proc_lseek)(struct file *, loff_t, int); - int (*proc_release)(struct inode *, struct file *); - __poll_t (*proc_poll)(struct file *, struct poll_table_struct *); - long int (*proc_ioctl)(struct file *, unsigned int, long unsigned int); - long int (*proc_compat_ioctl)(struct file *, unsigned int, long unsigned int); - int (*proc_mmap)(struct file *, struct vm_area_struct *); - long unsigned int (*proc_get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); -}; - -struct mtrr_sentry { - __u64 base; - __u32 size; - __u32 type; -}; - -struct mtrr_gentry { - __u64 base; - __u32 size; - __u32 regnum; - __u32 type; - __u32 _pad; -}; - -typedef u32 compat_uint_t; - -struct mtrr_sentry32 { - compat_ulong_t base; - compat_uint_t size; - compat_uint_t type; -}; - -struct mtrr_gentry32 { - compat_ulong_t regnum; - compat_uint_t base; - compat_uint_t size; - compat_uint_t type; -}; - -struct mtrr_var_range { - __u32 base_lo; - __u32 base_hi; - __u32 mask_lo; - __u32 mask_hi; -}; - -struct mtrr_state_type { - struct mtrr_var_range var_ranges[256]; - mtrr_type fixed_ranges[88]; - unsigned char enabled; - unsigned char have_fixed; - mtrr_type def_type; -}; - -struct fixed_range_block { - int base_msr; - int ranges; -}; - -struct var_mtrr_range_state { - long unsigned int base_pfn; - long unsigned int size_pfn; - mtrr_type type; -}; - -struct var_mtrr_state { - long unsigned int range_startk; - long unsigned int range_sizek; - long unsigned int chunk_sizek; - long unsigned int gran_sizek; - unsigned int reg; -}; - -struct mtrr_cleanup_result { - long unsigned int gran_sizek; - long unsigned int chunk_sizek; - long unsigned int lose_cover_sizek; - unsigned int num_reg; - int bad; -}; - -struct subsys_interface { - const char *name; - struct bus_type *subsys; - struct list_head node; - int (*add_dev)(struct device *, struct subsys_interface *); - void (*remove_dev)(struct device *, struct subsys_interface *); -}; - -struct property_entry; - -struct platform_device_info { - struct device *parent; - struct fwnode_handle *fwnode; - bool of_node_reused; - const char *name; - int id; - const struct resource *res; - unsigned int num_res; - const void *data; - size_t size_data; - u64 dma_mask; - const struct property_entry *properties; -}; - -enum dev_prop_type { - DEV_PROP_U8 = 0, - DEV_PROP_U16 = 1, - DEV_PROP_U32 = 2, - DEV_PROP_U64 = 3, - DEV_PROP_STRING = 4, - DEV_PROP_REF = 5, -}; - -struct property_entry { - const char *name; - size_t length; - bool is_inline; - enum dev_prop_type type; - union { - const void *pointer; - union { - u8 u8_data[8]; - u16 u16_data[4]; - u32 u32_data[2]; - u64 u64_data[1]; - const char *str[1]; - } value; - }; -}; - -struct builtin_fw { - char *name; - void *data; - long unsigned int size; -}; - -struct cpio_data { - void *data; - size_t size; - char name[18]; -}; - -struct cpu_signature { - unsigned int sig; - unsigned int pf; - unsigned int rev; -}; - -enum ucode_state { - UCODE_OK = 0, - UCODE_NEW = 1, - UCODE_UPDATED = 2, - UCODE_NFOUND = 3, - UCODE_ERROR = 4, -}; - -struct microcode_ops { - enum ucode_state (*request_microcode_user)(int, const void *, size_t); - enum ucode_state (*request_microcode_fw)(int, struct device *, bool); - void (*microcode_fini_cpu)(int); - enum ucode_state (*apply_microcode)(int); - int (*collect_cpu_info)(int, struct cpu_signature *); -}; - -struct ucode_cpu_info { - struct cpu_signature cpu_sig; - int valid; - void *mc; -}; - -struct cpu_info_ctx { - struct cpu_signature *cpu_sig; - int err; -}; - -struct firmware { - size_t size; - const u8 *data; - void *priv; -}; - -struct ucode_patch { - struct list_head plist; - void *data; - u32 patch_id; - u16 equiv_cpu; -}; - -struct microcode_header_intel { - unsigned int hdrver; - unsigned int rev; - unsigned int date; - unsigned int sig; - unsigned int cksum; - unsigned int ldrver; - unsigned int pf; - unsigned int datasize; - unsigned int totalsize; - unsigned int reserved[3]; -}; - -struct microcode_intel { - struct microcode_header_intel hdr; - unsigned int bits[0]; -}; - -struct extended_signature { - unsigned int sig; - unsigned int pf; - unsigned int cksum; -}; - -struct extended_sigtable { - unsigned int count; - unsigned int cksum; - unsigned int reserved[3]; - struct extended_signature sigs[0]; -}; - -struct equiv_cpu_entry { - u32 installed_cpu; - u32 fixed_errata_mask; - u32 fixed_errata_compare; - u16 equiv_cpu; - u16 res; -}; - -struct microcode_header_amd { - u32 data_code; - u32 patch_id; - u16 mc_patch_data_id; - u8 mc_patch_data_len; - u8 init_flag; - u32 mc_patch_data_checksum; - u32 nb_dev_id; - u32 sb_dev_id; - u16 processor_rev_id; - u8 nb_rev_id; - u8 sb_rev_id; - u8 bios_api_rev; - u8 reserved1[3]; - u32 match_reg[8]; -}; - -struct microcode_amd { - struct microcode_header_amd hdr; - unsigned int mpb[0]; -}; - -struct equiv_cpu_table { - unsigned int num_entries; - struct equiv_cpu_entry *entry; -}; - -struct cont_desc { - struct microcode_amd *mc; - u32 cpuid_1_eax; - u32 psize; - u8 *data; - size_t size; -}; - -typedef void (*exitcall_t)(); - -enum rdt_group_type { - RDTCTRL_GROUP = 0, - RDTMON_GROUP = 1, - RDT_NUM_GROUP = 2, -}; - -struct rdtgroup; - -struct mongroup { - struct kernfs_node *mon_data_kn; - struct rdtgroup *parent; - struct list_head crdtgrp_list; - u32 rmid; -}; - -enum rdtgrp_mode { - RDT_MODE_SHAREABLE = 0, - RDT_MODE_EXCLUSIVE = 1, - RDT_MODE_PSEUDO_LOCKSETUP = 2, - RDT_MODE_PSEUDO_LOCKED = 3, - RDT_NUM_MODES = 4, -}; - -struct pseudo_lock_region; - -struct rdtgroup { - struct kernfs_node *kn; - struct list_head rdtgroup_list; - u32 closid; - struct cpumask cpu_mask; - int flags; - atomic_t waitcount; - enum rdt_group_type type; - struct mongroup mon; - enum rdtgrp_mode mode; - struct pseudo_lock_region *plr; -}; - -struct rdt_cache { - unsigned int cbm_len; - unsigned int min_cbm_bits; - unsigned int cbm_idx_mult; - unsigned int cbm_idx_offset; - unsigned int shareable_bits; - bool arch_has_sparse_bitmaps; - bool arch_has_empty_bitmaps; - bool arch_has_per_cpu_cfg; -}; - -enum membw_throttle_mode { - THREAD_THROTTLE_UNDEFINED = 0, - THREAD_THROTTLE_MAX = 1, - THREAD_THROTTLE_PER_THREAD = 2, -}; - -struct rdt_membw { - u32 min_bw; - u32 bw_gran; - u32 delay_linear; - bool arch_needs_linear; - enum membw_throttle_mode throttle_mode; - bool mba_sc; - u32 *mb_map; -}; - -struct rdt_domain; - -struct msr_param; - -struct rdt_parse_data; - -struct rdt_resource { - int rid; - bool alloc_enabled; - bool mon_enabled; - bool alloc_capable; - bool mon_capable; - char *name; - int num_closid; - int cache_level; - u32 default_ctrl; - unsigned int msr_base; - void (*msr_update)(struct rdt_domain *, struct msr_param *, struct rdt_resource *); - int data_width; - struct list_head domains; - struct rdt_cache cache; - struct rdt_membw membw; - const char *format_str; - int (*parse_ctrlval)(struct rdt_parse_data *, struct rdt_resource *, struct rdt_domain *); - struct list_head evt_list; - int num_rmid; - unsigned int mon_scale; - unsigned int mbm_width; - long unsigned int fflags; -}; - -struct mbm_state; - -struct rdt_domain { - struct list_head list; - int id; - struct cpumask cpu_mask; - long unsigned int *rmid_busy_llc; - struct mbm_state *mbm_total; - struct mbm_state *mbm_local; - struct delayed_work mbm_over; - struct delayed_work cqm_limbo; - int mbm_work_cpu; - int cqm_work_cpu; - u32 *ctrl_val; - u32 *mbps_val; - u32 new_ctrl; - bool have_new_ctrl; - struct pseudo_lock_region *plr; -}; - -struct pseudo_lock_region { - struct rdt_resource *r; - struct rdt_domain *d; - u32 cbm; - wait_queue_head_t lock_thread_wq; - int thread_done; - int cpu; - unsigned int line_size; - unsigned int size; - void *kmem; - unsigned int minor; - struct dentry *debugfs_dir; - struct list_head pm_reqs; -}; - -struct mbm_state { - u64 chunks; - u64 prev_msr; - u64 prev_bw_msr; - u32 prev_bw; - u32 delta_bw; - bool delta_comp; -}; - -struct msr_param { - struct rdt_resource *res; - int low; - int high; -}; - -struct rdt_parse_data { - struct rdtgroup *rdtgrp; - char *buf; -}; - -enum { - RDT_RESOURCE_L3 = 0, - RDT_RESOURCE_L3DATA = 1, - RDT_RESOURCE_L3CODE = 2, - RDT_RESOURCE_L2 = 3, - RDT_RESOURCE_L2DATA = 4, - RDT_RESOURCE_L2CODE = 5, - RDT_RESOURCE_MBA = 6, - RDT_NUM_RESOURCES = 7, -}; - -union cpuid_0x10_1_eax { - struct { - unsigned int cbm_len: 5; - } split; - unsigned int full; -}; - -union cpuid_0x10_3_eax { - struct { - unsigned int max_delay: 12; - } split; - unsigned int full; -}; - -union cpuid_0x10_x_edx { - struct { - unsigned int cos_max: 16; - } split; - unsigned int full; -}; - -enum { - RDT_FLAG_CMT = 0, - RDT_FLAG_MBM_TOTAL = 1, - RDT_FLAG_MBM_LOCAL = 2, - RDT_FLAG_L3_CAT = 3, - RDT_FLAG_L3_CDP = 4, - RDT_FLAG_L2_CAT = 5, - RDT_FLAG_L2_CDP = 6, - RDT_FLAG_MBA = 7, -}; - -struct rdt_options { - char *name; - int flag; - bool force_off; - bool force_on; -}; - -typedef unsigned int uint; - -enum kernfs_node_type { - KERNFS_DIR = 1, - KERNFS_FILE = 2, - KERNFS_LINK = 4, -}; - -enum kernfs_root_flag { - KERNFS_ROOT_CREATE_DEACTIVATED = 1, - KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK = 2, - KERNFS_ROOT_SUPPORT_EXPORTOP = 4, - KERNFS_ROOT_SUPPORT_USER_XATTR = 8, -}; - -struct kernfs_fs_context { - struct kernfs_root *root; - void *ns_tag; - long unsigned int magic; - bool new_sb_created; -}; - -struct rdt_fs_context { - struct kernfs_fs_context kfc; - bool enable_cdpl2; - bool enable_cdpl3; - bool enable_mba_mbps; -}; - -struct mon_evt { - u32 evtid; - char *name; - struct list_head list; -}; - -union mon_data_bits { - void *priv; - struct { - unsigned int rid: 10; - unsigned int evtid: 8; - unsigned int domid: 14; - } u; -}; - -struct rmid_read { - struct rdtgroup *rgrp; - struct rdt_resource *r; - struct rdt_domain *d; - int evtid; - bool first; - u64 val; -}; - -struct rftype { - char *name; - umode_t mode; - const struct kernfs_ops *kf_ops; - long unsigned int flags; - long unsigned int fflags; - int (*seq_show)(struct kernfs_open_file *, struct seq_file *, void *); - ssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t); -}; - -enum rdt_param { - Opt_cdp = 0, - Opt_cdpl2 = 1, - Opt_mba_mbps = 2, - nr__rdt_params = 3, -}; - -struct rmid_entry { - u32 rmid; - int busy; - struct list_head list; -}; - -struct mbm_correction_factor_table { - u32 rmidthreshold; - u64 cf; -}; - -struct trace_event_raw_pseudo_lock_mem_latency { - struct trace_entry ent; - u32 latency; - char __data[0]; -}; - -struct trace_event_raw_pseudo_lock_l2 { - struct trace_entry ent; - u64 l2_hits; - u64 l2_miss; - char __data[0]; -}; - -struct trace_event_raw_pseudo_lock_l3 { - struct trace_entry ent; - u64 l3_hits; - u64 l3_miss; - char __data[0]; -}; - -struct trace_event_data_offsets_pseudo_lock_mem_latency {}; - -struct trace_event_data_offsets_pseudo_lock_l2 {}; - -struct trace_event_data_offsets_pseudo_lock_l3 {}; - -typedef void (*btf_trace_pseudo_lock_mem_latency)(void *, u32); - -typedef void (*btf_trace_pseudo_lock_l2)(void *, u64, u64); - -typedef void (*btf_trace_pseudo_lock_l3)(void *, u64, u64); - -struct pseudo_lock_pm_req { - struct list_head list; - struct dev_pm_qos_request req; -}; - -struct residency_counts { - u64 miss_before; - u64 hits_before; - u64 miss_after; - u64 hits_after; -}; - -struct miscdevice { - int minor; - const char *name; - const struct file_operations *fops; - struct list_head list; - struct device *parent; - struct device *this_device; - const struct attribute_group **groups; - const char *nodename; - umode_t mode; -}; - -enum mmu_notifier_event { - MMU_NOTIFY_UNMAP = 0, - MMU_NOTIFY_CLEAR = 1, - MMU_NOTIFY_PROTECTION_VMA = 2, - MMU_NOTIFY_PROTECTION_PAGE = 3, - MMU_NOTIFY_SOFT_DIRTY = 4, - MMU_NOTIFY_RELEASE = 5, - MMU_NOTIFY_MIGRATE = 6, - MMU_NOTIFY_EXCLUSIVE = 7, -}; - -struct mmu_notifier; - -struct mmu_notifier_range; - -struct mmu_notifier_ops { - void (*release)(struct mmu_notifier *, struct mm_struct *); - int (*clear_flush_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int); - int (*clear_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int); - int (*test_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int); - void (*change_pte)(struct mmu_notifier *, struct mm_struct *, long unsigned int, pte_t); - int (*invalidate_range_start)(struct mmu_notifier *, const struct mmu_notifier_range *); - void (*invalidate_range_end)(struct mmu_notifier *, const struct mmu_notifier_range *); - void (*invalidate_range)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int); - struct mmu_notifier * (*alloc_notifier)(struct mm_struct *); - void (*free_notifier)(struct mmu_notifier *); -}; - -struct mmu_notifier { - struct hlist_node hlist; - const struct mmu_notifier_ops *ops; - struct mm_struct *mm; - struct callback_head rcu; - unsigned int users; -}; - -struct mmu_notifier_range { - struct vm_area_struct *vma; - struct mm_struct *mm; - long unsigned int start; - long unsigned int end; - unsigned int flags; - enum mmu_notifier_event event; - void *owner; -}; - -enum sgx_page_type { - SGX_PAGE_TYPE_SECS = 0, - SGX_PAGE_TYPE_TCS = 1, - SGX_PAGE_TYPE_REG = 2, - SGX_PAGE_TYPE_VA = 3, - SGX_PAGE_TYPE_TRIM = 4, -}; - -struct sgx_encl_page; - -struct sgx_epc_page { - unsigned int section; - unsigned int flags; - struct sgx_encl_page *owner; - struct list_head list; -}; - -struct sgx_encl; - -struct sgx_va_page; - -struct sgx_encl_page { - long unsigned int desc; - long unsigned int vm_max_prot_bits; - struct sgx_epc_page *epc_page; - struct sgx_encl *encl; - struct sgx_va_page *va_page; -}; - -struct sgx_encl { - long unsigned int base; - long unsigned int size; - long unsigned int flags; - unsigned int page_cnt; - unsigned int secs_child_cnt; - struct mutex lock; - struct xarray page_array; - struct sgx_encl_page secs; - long unsigned int attributes; - long unsigned int attributes_mask; - cpumask_t cpumask; - struct file *backing; - struct kref refcount; - struct list_head va_pages; - long unsigned int mm_list_version; - struct list_head mm_list; - spinlock_t mm_lock; - struct srcu_struct srcu; -}; - -struct sgx_va_page { - struct sgx_epc_page *epc_page; - long unsigned int slots[8]; - struct list_head list; -}; - -struct sgx_encl_mm { - struct sgx_encl *encl; - struct mm_struct *mm; - struct list_head list; - struct mmu_notifier mmu_notifier; -}; - -typedef unsigned int xa_mark_t; - -struct xa_node { - unsigned char shift; - unsigned char offset; - unsigned char count; - unsigned char nr_values; - struct xa_node *parent; - struct xarray *array; - union { - struct list_head private_list; - struct callback_head callback_head; - }; - void *slots[64]; - union { - long unsigned int tags[3]; - long unsigned int marks[3]; - }; -}; - -typedef void (*xa_update_node_t)(struct xa_node *); - -struct xa_state { - struct xarray *xa; - long unsigned int xa_index; - unsigned char xa_shift; - unsigned char xa_sibs; - unsigned char xa_offset; - unsigned char xa_pad; - struct xa_node *xa_node; - struct xa_node *xa_alloc; - xa_update_node_t xa_update; -}; - -enum { - XA_CHECK_SCHED = 4096, -}; - -enum sgx_encls_function { - ECREATE = 0, - EADD = 1, - EINIT = 2, - EREMOVE = 3, - EDGBRD = 4, - EDGBWR = 5, - EEXTEND = 6, - ELDU = 8, - EBLOCK = 9, - EPA = 10, - EWB = 11, - ETRACK = 12, - EAUG = 13, - EMODPR = 14, - EMODT = 15, -}; - -struct sgx_pageinfo { - u64 addr; - u64 contents; - u64 metadata; - u64 secs; -}; - -struct sgx_numa_node { - struct list_head free_page_list; - spinlock_t lock; -}; - -struct sgx_epc_section { - long unsigned int phys_addr; - void *virt_addr; - struct sgx_epc_page *pages; - struct sgx_numa_node *node; -}; - -enum sgx_encl_flags { - SGX_ENCL_IOCTL = 1, - SGX_ENCL_DEBUG = 2, - SGX_ENCL_CREATED = 4, - SGX_ENCL_INITIALIZED = 8, -}; - -struct sgx_backing { - long unsigned int page_index; - struct page *contents; - struct page *pcmd; - long unsigned int pcmd_offset; -}; - -enum sgx_return_code { - SGX_NOT_TRACKED = 11, - SGX_CHILD_PRESENT = 13, - SGX_INVALID_EINITTOKEN = 16, - SGX_UNMASKED_EVENT = 128, -}; - -enum sgx_attribute { - SGX_ATTR_INIT = 1, - SGX_ATTR_DEBUG = 2, - SGX_ATTR_MODE64BIT = 4, - SGX_ATTR_PROVISIONKEY = 16, - SGX_ATTR_EINITTOKENKEY = 32, - SGX_ATTR_KSS = 128, -}; - -struct sgx_secs { - u64 size; - u64 base; - u32 ssa_frame_size; - u32 miscselect; - u8 reserved1[24]; - u64 attributes; - u64 xfrm; - u32 mrenclave[8]; - u8 reserved2[32]; - u32 mrsigner[8]; - u8 reserved3[32]; - u32 config_id[16]; - u16 isv_prod_id; - u16 isv_svn; - u16 config_svn; - u8 reserved4[3834]; -}; - -enum sgx_secinfo_flags { - SGX_SECINFO_R = 1, - SGX_SECINFO_W = 2, - SGX_SECINFO_X = 4, - SGX_SECINFO_SECS = 0, - SGX_SECINFO_TCS = 256, - SGX_SECINFO_REG = 512, - SGX_SECINFO_VA = 768, - SGX_SECINFO_TRIM = 1024, -}; - -struct sgx_secinfo { - u64 flags; - u8 reserved[56]; -}; - -struct sgx_sigstruct_header { - u64 header1[2]; - u32 vendor; - u32 date; - u64 header2[2]; - u32 swdefined; - u8 reserved1[84]; -}; - -struct sgx_sigstruct_body { - u32 miscselect; - u32 misc_mask; - u8 reserved2[20]; - u64 attributes; - u64 xfrm; - u64 attributes_mask; - u64 xfrm_mask; - u8 mrenclave[32]; - u8 reserved3[32]; - u16 isvprodid; - u16 isvsvn; -} __attribute__((packed)); - -struct sgx_sigstruct { - struct sgx_sigstruct_header header; - u8 modulus[384]; - u32 exponent; - u8 signature[384]; - struct sgx_sigstruct_body body; - u8 reserved4[12]; - u8 q1[384]; - u8 q2[384]; -} __attribute__((packed)); - -struct crypto_alg; - -struct crypto_tfm { - u32 crt_flags; - int node; - void (*exit)(struct crypto_tfm *); - struct crypto_alg *__crt_alg; - void *__crt_ctx[0]; -}; - -struct cipher_alg { - unsigned int cia_min_keysize; - unsigned int cia_max_keysize; - int (*cia_setkey)(struct crypto_tfm *, const u8 *, unsigned int); - void (*cia_encrypt)(struct crypto_tfm *, u8 *, const u8 *); - void (*cia_decrypt)(struct crypto_tfm *, u8 *, const u8 *); -}; - -struct compress_alg { - int (*coa_compress)(struct crypto_tfm *, const u8 *, unsigned int, u8 *, unsigned int *); - int (*coa_decompress)(struct crypto_tfm *, const u8 *, unsigned int, u8 *, unsigned int *); -}; - -struct crypto_istat_aead { - atomic64_t encrypt_cnt; - atomic64_t encrypt_tlen; - atomic64_t decrypt_cnt; - atomic64_t decrypt_tlen; - atomic64_t err_cnt; -}; - -struct crypto_istat_akcipher { - atomic64_t encrypt_cnt; - atomic64_t encrypt_tlen; - atomic64_t decrypt_cnt; - atomic64_t decrypt_tlen; - atomic64_t verify_cnt; - atomic64_t sign_cnt; - atomic64_t err_cnt; -}; - -struct crypto_istat_cipher { - atomic64_t encrypt_cnt; - atomic64_t encrypt_tlen; - atomic64_t decrypt_cnt; - atomic64_t decrypt_tlen; - atomic64_t err_cnt; -}; - -struct crypto_istat_compress { - atomic64_t compress_cnt; - atomic64_t compress_tlen; - atomic64_t decompress_cnt; - atomic64_t decompress_tlen; - atomic64_t err_cnt; -}; - -struct crypto_istat_hash { - atomic64_t hash_cnt; - atomic64_t hash_tlen; - atomic64_t err_cnt; -}; - -struct crypto_istat_kpp { - atomic64_t setsecret_cnt; - atomic64_t generate_public_key_cnt; - atomic64_t compute_shared_secret_cnt; - atomic64_t err_cnt; -}; - -struct crypto_istat_rng { - atomic64_t generate_cnt; - atomic64_t generate_tlen; - atomic64_t seed_cnt; - atomic64_t err_cnt; -}; - -struct crypto_type; - -struct crypto_alg { - struct list_head cra_list; - struct list_head cra_users; - u32 cra_flags; - unsigned int cra_blocksize; - unsigned int cra_ctxsize; - unsigned int cra_alignmask; - int cra_priority; - refcount_t cra_refcnt; - char cra_name[128]; - char cra_driver_name[128]; - const struct crypto_type *cra_type; - union { - struct cipher_alg cipher; - struct compress_alg compress; - } cra_u; - int (*cra_init)(struct crypto_tfm *); - void (*cra_exit)(struct crypto_tfm *); - void (*cra_destroy)(struct crypto_alg *); - struct module *cra_module; - union { - struct crypto_istat_aead aead; - struct crypto_istat_akcipher akcipher; - struct crypto_istat_cipher cipher; - struct crypto_istat_compress compress; - struct crypto_istat_hash hash; - struct crypto_istat_rng rng; - struct crypto_istat_kpp kpp; - } stats; -}; - -struct crypto_instance; - -struct crypto_type { - unsigned int (*ctxsize)(struct crypto_alg *, u32, u32); - unsigned int (*extsize)(struct crypto_alg *); - int (*init)(struct crypto_tfm *, u32, u32); - int (*init_tfm)(struct crypto_tfm *); - void (*show)(struct seq_file *, struct crypto_alg *); - int (*report)(struct sk_buff *, struct crypto_alg *); - void (*free)(struct crypto_instance *); - unsigned int type; - unsigned int maskclear; - unsigned int maskset; - unsigned int tfmsize; -}; - -struct crypto_shash; - -struct shash_desc { - struct crypto_shash *tfm; - void *__ctx[0]; -}; - -struct crypto_shash { - unsigned int descsize; - struct crypto_tfm base; -}; - -enum sgx_page_flags { - SGX_PAGE_MEASURE = 1, -}; - -struct sgx_enclave_create { - __u64 src; -}; - -struct sgx_enclave_add_pages { - __u64 src; - __u64 offset; - __u64 length; - __u64 secinfo; - __u64 flags; - __u64 count; -}; - -struct sgx_enclave_init { - __u64 sigstruct; -}; - -struct sgx_enclave_provision { - __u64 fd; -}; - -struct sgx_vepc { - struct xarray page_array; - struct mutex lock; -}; - -struct vmcb_seg { - u16 selector; - u16 attrib; - u32 limit; - u64 base; -}; - -struct vmcb_save_area { - struct vmcb_seg es; - struct vmcb_seg cs; - struct vmcb_seg ss; - struct vmcb_seg ds; - struct vmcb_seg fs; - struct vmcb_seg gs; - struct vmcb_seg gdtr; - struct vmcb_seg ldtr; - struct vmcb_seg idtr; - struct vmcb_seg tr; - u8 reserved_1[43]; - u8 cpl; - u8 reserved_2[4]; - u64 efer; - u8 reserved_3[104]; - u64 xss; - u64 cr4; - u64 cr3; - u64 cr0; - u64 dr7; - u64 dr6; - u64 rflags; - u64 rip; - u8 reserved_4[88]; - u64 rsp; - u8 reserved_5[24]; - u64 rax; - u64 star; - u64 lstar; - u64 cstar; - u64 sfmask; - u64 kernel_gs_base; - u64 sysenter_cs; - u64 sysenter_esp; - u64 sysenter_eip; - u64 cr2; - u8 reserved_6[32]; - u64 g_pat; - u64 dbgctl; - u64 br_from; - u64 br_to; - u64 last_excp_from; - u64 last_excp_to; - u8 reserved_7[72]; - u32 spec_ctrl; - u8 reserved_7b[4]; - u32 pkru; - u8 reserved_7a[20]; - u64 reserved_8; - u64 rcx; - u64 rdx; - u64 rbx; - u64 reserved_9; - u64 rbp; - u64 rsi; - u64 rdi; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; - u8 reserved_10[16]; - u64 sw_exit_code; - u64 sw_exit_info_1; - u64 sw_exit_info_2; - u64 sw_scratch; - u8 reserved_11[56]; - u64 xcr0; - u8 valid_bitmap[16]; - u64 x87_state_gpa; -}; - -struct ghcb { - struct vmcb_save_area save; - u8 reserved_save[1016]; - u8 shared_buffer[2032]; - u8 reserved_1[10]; - u16 protocol_version; - u32 ghcb_usage; -}; - -enum intercept_words { - INTERCEPT_CR = 0, - INTERCEPT_DR = 1, - INTERCEPT_EXCEPTION = 2, - INTERCEPT_WORD3 = 3, - INTERCEPT_WORD4 = 4, - INTERCEPT_WORD5 = 5, - MAX_INTERCEPT = 6, -}; - -struct vmware_steal_time { - union { - uint64_t clock; - struct { - uint32_t clock_low; - uint32_t clock_high; - }; - }; - uint64_t reserved[7]; -}; - -struct mpc_intsrc { - unsigned char type; - unsigned char irqtype; - short unsigned int irqflag; - unsigned char srcbus; - unsigned char srcbusirq; - unsigned char dstapic; - unsigned char dstirq; -}; - -enum mp_irq_source_types { - mp_INT = 0, - mp_NMI = 1, - mp_SMI = 2, - mp_ExtINT = 3, -}; - -typedef u64 acpi_io_address; - -typedef u64 acpi_physical_address; - -typedef char *acpi_string; - -typedef void *acpi_handle; - -typedef u32 acpi_object_type; - -typedef u8 acpi_adr_space_type; - -union acpi_object { - acpi_object_type type; - struct { - acpi_object_type type; - u64 value; - } integer; - struct { - acpi_object_type type; - u32 length; - char *pointer; - } string; - struct { - acpi_object_type type; - u32 length; - u8 *pointer; - } buffer; - struct { - acpi_object_type type; - u32 count; - union acpi_object *elements; - } package; - struct { - acpi_object_type type; - acpi_object_type actual_type; - acpi_handle handle; - } reference; - struct { - acpi_object_type type; - u32 proc_id; - acpi_io_address pblk_address; - u32 pblk_length; - } processor; - struct { - acpi_object_type type; - u32 system_level; - u32 resource_order; - } power_resource; -}; - -struct acpi_object_list { - u32 count; - union acpi_object *pointer; -}; - -struct acpi_subtable_header { - u8 type; - u8 length; -}; - -struct acpi_table_boot { - struct acpi_table_header header; - u8 cmos_index; - u8 reserved[3]; -}; - -struct acpi_hmat_structure { - u16 type; - u16 reserved; - u32 length; -}; - -struct acpi_table_hpet { - struct acpi_table_header header; - u32 id; - struct acpi_generic_address address; - u8 sequence; - u16 minimum_tick; - u8 flags; -} __attribute__((packed)); - -struct acpi_table_madt { - struct acpi_table_header header; - u32 address; - u32 flags; -}; - -enum acpi_madt_type { - ACPI_MADT_TYPE_LOCAL_APIC = 0, - ACPI_MADT_TYPE_IO_APIC = 1, - ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2, - ACPI_MADT_TYPE_NMI_SOURCE = 3, - ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4, - ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5, - ACPI_MADT_TYPE_IO_SAPIC = 6, - ACPI_MADT_TYPE_LOCAL_SAPIC = 7, - ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, - ACPI_MADT_TYPE_LOCAL_X2APIC = 9, - ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, - ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11, - ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12, - ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13, - ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14, - ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15, - ACPI_MADT_TYPE_MULTIPROC_WAKEUP = 16, - ACPI_MADT_TYPE_RESERVED = 17, -}; - -struct acpi_madt_local_apic { - struct acpi_subtable_header header; - u8 processor_id; - u8 id; - u32 lapic_flags; -}; - -struct acpi_madt_io_apic { - struct acpi_subtable_header header; - u8 id; - u8 reserved; - u32 address; - u32 global_irq_base; -}; - -struct acpi_madt_interrupt_override { - struct acpi_subtable_header header; - u8 bus; - u8 source_irq; - u32 global_irq; - u16 inti_flags; -} __attribute__((packed)); - -struct acpi_madt_nmi_source { - struct acpi_subtable_header header; - u16 inti_flags; - u32 global_irq; -}; - -struct acpi_madt_local_apic_nmi { - struct acpi_subtable_header header; - u8 processor_id; - u16 inti_flags; - u8 lint; -} __attribute__((packed)); - -struct acpi_madt_local_apic_override { - struct acpi_subtable_header header; - u16 reserved; - u64 address; -} __attribute__((packed)); - -struct acpi_madt_local_sapic { - struct acpi_subtable_header header; - u8 processor_id; - u8 id; - u8 eid; - u8 reserved[3]; - u32 lapic_flags; - u32 uid; - char uid_string[1]; -} __attribute__((packed)); - -struct acpi_madt_local_x2apic { - struct acpi_subtable_header header; - u16 reserved; - u32 local_apic_id; - u32 lapic_flags; - u32 uid; -}; - -struct acpi_madt_local_x2apic_nmi { - struct acpi_subtable_header header; - u16 inti_flags; - u32 uid; - u8 lint; - u8 reserved[3]; -}; - -struct acpi_prmt_module_header { - u16 revision; - u16 length; -}; - -union acpi_subtable_headers { - struct acpi_subtable_header common; - struct acpi_hmat_structure hmat; - struct acpi_prmt_module_header prmt; -}; - -typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *); - -typedef int (*acpi_tbl_entry_handler)(union acpi_subtable_headers *, const long unsigned int); - -struct acpi_subtable_proc { - int id; - acpi_tbl_entry_handler handler; - int count; -}; - -typedef u32 phys_cpuid_t; - -struct serial_icounter_struct { - int cts; - int dsr; - int rng; - int dcd; - int rx; - int tx; - int frame; - int overrun; - int parity; - int brk; - int buf_overrun; - int reserved[9]; -}; - -struct serial_struct { - int type; - int line; - unsigned int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - short unsigned int close_delay; - char io_type; - char reserved_char[1]; - int hub6; - short unsigned int closing_wait; - short unsigned int closing_wait2; - unsigned char *iomem_base; - short unsigned int iomem_reg_shift; - unsigned int port_high; - long unsigned int iomap_base; -}; - -enum ioapic_domain_type { - IOAPIC_DOMAIN_INVALID = 0, - IOAPIC_DOMAIN_LEGACY = 1, - IOAPIC_DOMAIN_STRICT = 2, - IOAPIC_DOMAIN_DYNAMIC = 3, -}; - -struct ioapic_domain_cfg { - enum ioapic_domain_type type; - const struct irq_domain_ops *ops; - struct device_node *dev; -}; - -struct wakeup_header { - u16 video_mode; - u32 pmode_entry; - u16 pmode_cs; - u32 pmode_cr0; - u32 pmode_cr3; - u32 pmode_cr4; - u32 pmode_efer_low; - u32 pmode_efer_high; - u64 pmode_gdt; - u32 pmode_misc_en_low; - u32 pmode_misc_en_high; - u32 pmode_behavior; - u32 realmode_flags; - u32 real_magic; - u32 signature; -} __attribute__((packed)); - -struct acpi_hest_header { - u16 type; - u16 source_id; -}; - -struct acpi_hest_ia_error_bank { - u8 bank_number; - u8 clear_status_on_init; - u8 status_format; - u8 reserved; - u32 control_register; - u64 control_data; - u32 status_register; - u32 address_register; - u32 misc_register; -} __attribute__((packed)); - -struct acpi_hest_notify { - u8 type; - u8 length; - u16 config_write_enable; - u32 poll_interval; - u32 vector; - u32 polling_threshold_value; - u32 polling_threshold_window; - u32 error_threshold_value; - u32 error_threshold_window; -}; - -struct acpi_hest_ia_corrected { - struct acpi_hest_header header; - u16 reserved1; - u8 flags; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - struct acpi_hest_notify notify; - u8 num_hardware_banks; - u8 reserved2[3]; -}; - -struct cpc_reg { - u8 descriptor; - u16 length; - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 access_width; - u64 address; -} __attribute__((packed)); - -struct acpi_power_register { - u8 descriptor; - u16 length; - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 access_size; - u64 address; -} __attribute__((packed)); - -struct acpi_processor_cx { - u8 valid; - u8 type; - u32 address; - u8 entry_method; - u8 index; - u32 latency; - u8 bm_sts_skip; - char desc[32]; -}; - -struct acpi_processor_flags { - u8 power: 1; - u8 performance: 1; - u8 throttling: 1; - u8 limit: 1; - u8 bm_control: 1; - u8 bm_check: 1; - u8 has_cst: 1; - u8 has_lpi: 1; - u8 power_setup_done: 1; - u8 bm_rld_set: 1; - u8 need_hotplug_init: 1; -}; - -struct cstate_entry { - struct { - unsigned int eax; - unsigned int ecx; - } states[8]; -}; - -enum reboot_mode { - REBOOT_UNDEFINED = 4294967295, - REBOOT_COLD = 0, - REBOOT_WARM = 1, - REBOOT_HARD = 2, - REBOOT_SOFT = 3, - REBOOT_GPIO = 4, -}; - -enum reboot_type { - BOOT_TRIPLE = 116, - BOOT_KBD = 107, - BOOT_BIOS = 98, - BOOT_ACPI = 97, - BOOT_EFI = 101, - BOOT_CF9_FORCE = 112, - BOOT_CF9_SAFE = 113, -}; - -typedef void (*nmi_shootdown_cb)(int, struct pt_regs *); - -enum allow_write_msrs { - MSR_WRITES_ON = 0, - MSR_WRITES_OFF = 1, - MSR_WRITES_DEFAULT = 2, -}; - -typedef struct __call_single_data call_single_data_t; - -struct cpuid_regs_done { - struct cpuid_regs regs; - struct completion done; -}; - -struct intel_early_ops { - resource_size_t (*stolen_size)(int, int, int); - resource_size_t (*stolen_base)(int, int, int, resource_size_t); -}; - -struct chipset { - u32 vendor; - u32 device; - u32 class; - u32 class_mask; - u32 flags; - void (*f)(int, int, int); -}; - -enum { - SD_BALANCE_NEWIDLE = 1, - SD_BALANCE_EXEC = 2, - SD_BALANCE_FORK = 4, - SD_BALANCE_WAKE = 8, - SD_WAKE_AFFINE = 16, - SD_ASYM_CPUCAPACITY = 32, - SD_ASYM_CPUCAPACITY_FULL = 64, - SD_SHARE_CPUCAPACITY = 128, - SD_SHARE_PKG_RESOURCES = 256, - SD_SERIALIZE = 512, - SD_ASYM_PACKING = 1024, - SD_PREFER_SIBLING = 2048, - SD_OVERLAP = 4096, - SD_NUMA = 8192, -}; - -struct sched_domain_shared { - atomic_t ref; - atomic_t nr_busy_cpus; - int has_idle_cores; -}; - -struct sched_group; - -struct sched_domain { - struct sched_domain *parent; - struct sched_domain *child; - struct sched_group *groups; - long unsigned int min_interval; - long unsigned int max_interval; - unsigned int busy_factor; - unsigned int imbalance_pct; - unsigned int cache_nice_tries; - int nohz_idle; - int flags; - int level; - long unsigned int last_balance; - unsigned int balance_interval; - unsigned int nr_balance_failed; - u64 max_newidle_lb_cost; - long unsigned int next_decay_max_lb_cost; - u64 avg_scan_cost; - unsigned int lb_count[3]; - unsigned int lb_failed[3]; - unsigned int lb_balanced[3]; - unsigned int lb_imbalance[3]; - unsigned int lb_gained[3]; - unsigned int lb_hot_gained[3]; - unsigned int lb_nobusyg[3]; - unsigned int lb_nobusyq[3]; - unsigned int alb_count; - unsigned int alb_failed; - unsigned int alb_pushed; - unsigned int sbe_count; - unsigned int sbe_balanced; - unsigned int sbe_pushed; - unsigned int sbf_count; - unsigned int sbf_balanced; - unsigned int sbf_pushed; - unsigned int ttwu_wake_remote; - unsigned int ttwu_move_affine; - unsigned int ttwu_move_balance; - char *name; - union { - void *private; - struct callback_head rcu; - }; - struct sched_domain_shared *shared; - unsigned int span_weight; - long unsigned int span[0]; -}; - -typedef const struct cpumask * (*sched_domain_mask_f)(int); - -typedef int (*sched_domain_flags_f)(); - -struct sched_group_capacity; - -struct sd_data { - struct sched_domain **sd; - struct sched_domain_shared **sds; - struct sched_group **sg; - struct sched_group_capacity **sgc; -}; - -struct sched_domain_topology_level { - sched_domain_mask_f mask; - sched_domain_flags_f sd_flags; - int flags; - int numa_level; - struct sd_data data; - char *name; -}; - -enum apic_intr_mode_id { - APIC_PIC = 0, - APIC_VIRTUAL_WIRE = 1, - APIC_VIRTUAL_WIRE_NO_CONFIG = 2, - APIC_SYMMETRIC_IO = 3, - APIC_SYMMETRIC_IO_NO_ROUTING = 4, -}; - -struct cppc_perf_caps { - u32 guaranteed_perf; - u32 highest_perf; - u32 nominal_perf; - u32 lowest_perf; - u32 lowest_nonlinear_perf; - u32 lowest_freq; - u32 nominal_freq; -}; - -struct tsc_adjust { - s64 bootval; - s64 adjusted; - long unsigned int nextcheck; - bool warned; -}; - -typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int, size_t, size_t); - -typedef void (*pcpu_fc_free_fn_t)(void *, size_t); - -typedef void (*pcpu_fc_populate_pte_fn_t)(long unsigned int); - -typedef int pcpu_fc_cpu_distance_fn_t(unsigned int, unsigned int); - -enum { - DUMP_PREFIX_NONE = 0, - DUMP_PREFIX_ADDRESS = 1, - DUMP_PREFIX_OFFSET = 2, -}; - -struct mpf_intel { - char signature[4]; - unsigned int physptr; - unsigned char length; - unsigned char specification; - unsigned char checksum; - unsigned char feature1; - unsigned char feature2; - unsigned char feature3; - unsigned char feature4; - unsigned char feature5; -}; - -struct mpc_table { - char signature[4]; - short unsigned int length; - char spec; - char checksum; - char oem[8]; - char productid[12]; - unsigned int oemptr; - short unsigned int oemsize; - short unsigned int oemcount; - unsigned int lapic; - unsigned int reserved; -}; - -struct mpc_cpu { - unsigned char type; - unsigned char apicid; - unsigned char apicver; - unsigned char cpuflag; - unsigned int cpufeature; - unsigned int featureflag; - unsigned int reserved[2]; -}; - -struct mpc_bus { - unsigned char type; - unsigned char busid; - unsigned char bustype[6]; -}; - -struct mpc_ioapic { - unsigned char type; - unsigned char apicid; - unsigned char apicver; - unsigned char flags; - unsigned int apicaddr; -}; - -struct mpc_lintsrc { - unsigned char type; - unsigned char irqtype; - short unsigned int irqflag; - unsigned char srcbusid; - unsigned char srcbusirq; - unsigned char destapic; - unsigned char destapiclint; -}; - -enum page_cache_mode { - _PAGE_CACHE_MODE_WB = 0, - _PAGE_CACHE_MODE_WC = 1, - _PAGE_CACHE_MODE_UC_MINUS = 2, - _PAGE_CACHE_MODE_UC = 3, - _PAGE_CACHE_MODE_WT = 4, - _PAGE_CACHE_MODE_WP = 5, - _PAGE_CACHE_MODE_NUM = 8, -}; - -enum { - IRQ_REMAP_XAPIC_MODE = 0, - IRQ_REMAP_X2APIC_MODE = 1, -}; - -union apic_ir { - long unsigned int map[4]; - u32 regs[8]; -}; - -enum { - X2APIC_OFF = 0, - X2APIC_ON = 1, - X2APIC_DISABLED = 2, -}; - -enum { - IRQ_SET_MASK_OK = 0, - IRQ_SET_MASK_OK_NOCOPY = 1, - IRQ_SET_MASK_OK_DONE = 2, -}; - -enum { - IRQD_TRIGGER_MASK = 15, - IRQD_SETAFFINITY_PENDING = 256, - IRQD_ACTIVATED = 512, - IRQD_NO_BALANCING = 1024, - IRQD_PER_CPU = 2048, - IRQD_AFFINITY_SET = 4096, - IRQD_LEVEL = 8192, - IRQD_WAKEUP_STATE = 16384, - IRQD_MOVE_PCNTXT = 32768, - IRQD_IRQ_DISABLED = 65536, - IRQD_IRQ_MASKED = 131072, - IRQD_IRQ_INPROGRESS = 262144, - IRQD_WAKEUP_ARMED = 524288, - IRQD_FORWARDED_TO_VCPU = 1048576, - IRQD_AFFINITY_MANAGED = 2097152, - IRQD_IRQ_STARTED = 4194304, - IRQD_MANAGED_SHUTDOWN = 8388608, - IRQD_SINGLE_TARGET = 16777216, - IRQD_DEFAULT_TRIGGER_SET = 33554432, - IRQD_CAN_RESERVE = 67108864, - IRQD_MSI_NOMASK_QUIRK = 134217728, - IRQD_HANDLE_ENFORCE_IRQCTX = 268435456, - IRQD_AFFINITY_ON_ACTIVATE = 536870912, - IRQD_IRQ_ENABLED_ON_SUSPEND = 1073741824, -}; - -enum { - X86_IRQ_ALLOC_CONTIGUOUS_VECTORS = 1, - X86_IRQ_ALLOC_LEGACY = 2, -}; - -struct apic_chip_data { - struct irq_cfg hw_irq_cfg; - unsigned int vector; - unsigned int prev_vector; - unsigned int cpu; - unsigned int prev_cpu; - unsigned int irq; - struct hlist_node clist; - unsigned int move_in_progress: 1; - unsigned int is_managed: 1; - unsigned int can_reserve: 1; - unsigned int has_reserved: 1; -}; - -struct irq_matrix; - -enum { - IRQ_TYPE_NONE = 0, - IRQ_TYPE_EDGE_RISING = 1, - IRQ_TYPE_EDGE_FALLING = 2, - IRQ_TYPE_EDGE_BOTH = 3, - IRQ_TYPE_LEVEL_HIGH = 4, - IRQ_TYPE_LEVEL_LOW = 8, - IRQ_TYPE_LEVEL_MASK = 12, - IRQ_TYPE_SENSE_MASK = 15, - IRQ_TYPE_DEFAULT = 15, - IRQ_TYPE_PROBE = 16, - IRQ_LEVEL = 256, - IRQ_PER_CPU = 512, - IRQ_NOPROBE = 1024, - IRQ_NOREQUEST = 2048, - IRQ_NOAUTOEN = 4096, - IRQ_NO_BALANCING = 8192, - IRQ_MOVE_PCNTXT = 16384, - IRQ_NESTED_THREAD = 32768, - IRQ_NOTHREAD = 65536, - IRQ_PER_CPU_DEVID = 131072, - IRQ_IS_POLLED = 262144, - IRQ_DISABLE_UNLAZY = 524288, - IRQ_HIDDEN = 1048576, - IRQ_NO_DEBUG = 2097152, -}; - -struct clock_event_device___2; - -union IO_APIC_reg_00 { - u32 raw; - struct { - u32 __reserved_2: 14; - u32 LTS: 1; - u32 delivery_type: 1; - u32 __reserved_1: 8; - u32 ID: 8; - } bits; -}; - -union IO_APIC_reg_01 { - u32 raw; - struct { - u32 version: 8; - u32 __reserved_2: 7; - u32 PRQ: 1; - u32 entries: 8; - u32 __reserved_1: 8; - } bits; -}; - -union IO_APIC_reg_02 { - u32 raw; - struct { - u32 __reserved_2: 24; - u32 arbitration: 4; - u32 __reserved_1: 4; - } bits; -}; - -union IO_APIC_reg_03 { - u32 raw; - struct { - u32 boot_DT: 1; - u32 __reserved_1: 31; - } bits; -}; - -struct IO_APIC_route_entry { - union { - struct { - u64 vector: 8; - u64 delivery_mode: 3; - u64 dest_mode_logical: 1; - u64 delivery_status: 1; - u64 active_low: 1; - u64 irr: 1; - u64 is_level: 1; - u64 masked: 1; - u64 reserved_0: 15; - u64 reserved_1: 17; - u64 virt_destid_8_14: 7; - u64 destid_0_7: 8; - }; - struct { - u64 ir_shared_0: 8; - u64 ir_zero: 3; - u64 ir_index_15: 1; - u64 ir_shared_1: 5; - u64 ir_reserved_0: 31; - u64 ir_format: 1; - u64 ir_index_0_14: 15; - }; - struct { - u64 w1: 32; - u64 w2: 32; - }; - }; -}; - -struct irq_pin_list { - struct list_head list; - int apic; - int pin; -}; - -struct mp_chip_data { - struct list_head irq_2_pin; - struct IO_APIC_route_entry entry; - bool is_level; - bool active_low; - bool isa_irq; - u32 count; -}; - -struct mp_ioapic_gsi { - u32 gsi_base; - u32 gsi_end; -}; - -struct ioapic { - int nr_registers; - struct IO_APIC_route_entry *saved_registers; - struct mpc_ioapic mp_config; - struct mp_ioapic_gsi gsi_config; - struct ioapic_domain_cfg irqdomain_cfg; - struct irq_domain *irqdomain; - struct resource *iomem_res; -}; - -struct io_apic { - unsigned int index; - unsigned int unused[3]; - unsigned int data; - unsigned int unused2[11]; - unsigned int eoi; -}; - -enum { - IRQ_DOMAIN_FLAG_HIERARCHY = 1, - IRQ_DOMAIN_NAME_ALLOCATED = 2, - IRQ_DOMAIN_FLAG_IPI_PER_CPU = 4, - IRQ_DOMAIN_FLAG_IPI_SINGLE = 8, - IRQ_DOMAIN_FLAG_MSI = 16, - IRQ_DOMAIN_FLAG_MSI_REMAP = 32, - IRQ_DOMAIN_MSI_NOMASK_QUIRK = 64, - IRQ_DOMAIN_FLAG_NO_MAP = 128, - IRQ_DOMAIN_FLAG_NONCORE = 65536, -}; - -struct cluster_mask { - unsigned int clusterid; - int node; - struct cpumask mask; -}; - -struct dyn_arch_ftrace {}; - -enum { - FTRACE_OPS_FL_ENABLED = 1, - FTRACE_OPS_FL_DYNAMIC = 2, - FTRACE_OPS_FL_SAVE_REGS = 4, - FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 8, - FTRACE_OPS_FL_RECURSION = 16, - FTRACE_OPS_FL_STUB = 32, - FTRACE_OPS_FL_INITIALIZED = 64, - FTRACE_OPS_FL_DELETED = 128, - FTRACE_OPS_FL_ADDING = 256, - FTRACE_OPS_FL_REMOVING = 512, - FTRACE_OPS_FL_MODIFYING = 1024, - FTRACE_OPS_FL_ALLOC_TRAMP = 2048, - FTRACE_OPS_FL_IPMODIFY = 4096, - FTRACE_OPS_FL_PID = 8192, - FTRACE_OPS_FL_RCU = 16384, - FTRACE_OPS_FL_TRACE_ARRAY = 32768, - FTRACE_OPS_FL_PERMANENT = 65536, - FTRACE_OPS_FL_DIRECT = 131072, -}; - -enum { - FTRACE_FL_ENABLED = 2147483648, - FTRACE_FL_REGS = 1073741824, - FTRACE_FL_REGS_EN = 536870912, - FTRACE_FL_TRAMP = 268435456, - FTRACE_FL_TRAMP_EN = 134217728, - FTRACE_FL_IPMODIFY = 67108864, - FTRACE_FL_DISABLED = 33554432, - FTRACE_FL_DIRECT = 16777216, - FTRACE_FL_DIRECT_EN = 8388608, -}; - -struct dyn_ftrace { - long unsigned int ip; - long unsigned int flags; - struct dyn_arch_ftrace arch; -}; - -enum { - FTRACE_UPDATE_IGNORE = 0, - FTRACE_UPDATE_MAKE_CALL = 1, - FTRACE_UPDATE_MODIFY_CALL = 2, - FTRACE_UPDATE_MAKE_NOP = 3, -}; - -union ftrace_op_code_union { - char code[7]; - struct { - char op[3]; - int offset; - } __attribute__((packed)); -}; - -struct ftrace_rec_iter; - -typedef __u64 Elf64_Off; - -typedef __s64 Elf64_Sxword; - -struct elf64_rela { - Elf64_Addr r_offset; - Elf64_Xword r_info; - Elf64_Sxword r_addend; -}; - -typedef struct elf64_rela Elf64_Rela; - -struct elf64_hdr { - unsigned char e_ident[16]; - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; - Elf64_Off e_phoff; - Elf64_Off e_shoff; - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -}; - -typedef struct elf64_hdr Elf64_Ehdr; - -struct elf64_shdr { - Elf64_Word sh_name; - Elf64_Word sh_type; - Elf64_Xword sh_flags; - Elf64_Addr sh_addr; - Elf64_Off sh_offset; - Elf64_Xword sh_size; - Elf64_Word sh_link; - Elf64_Word sh_info; - Elf64_Xword sh_addralign; - Elf64_Xword sh_entsize; -}; - -typedef struct elf64_shdr Elf64_Shdr; - -struct kimage_arch { - p4d_t *p4d; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; -}; - -typedef long unsigned int kimage_entry_t; - -struct kexec_segment { - union { - void *buf; - void *kbuf; - }; - size_t bufsz; - long unsigned int mem; - size_t memsz; -}; - -struct purgatory_info { - const Elf64_Ehdr *ehdr; - Elf64_Shdr *sechdrs; - void *purgatory_buf; -}; - -typedef int kexec_probe_t(const char *, long unsigned int); - -struct kimage; - -typedef void *kexec_load_t(struct kimage *, char *, long unsigned int, char *, long unsigned int, char *, long unsigned int); - -struct kexec_file_ops; - -struct kimage { - kimage_entry_t head; - kimage_entry_t *entry; - kimage_entry_t *last_entry; - long unsigned int start; - struct page *control_code_page; - struct page *swap_page; - void *vmcoreinfo_data_copy; - long unsigned int nr_segments; - struct kexec_segment segment[16]; - struct list_head control_pages; - struct list_head dest_pages; - struct list_head unusable_pages; - long unsigned int control_page; - unsigned int type: 1; - unsigned int preserve_context: 1; - unsigned int file_mode: 1; - struct kimage_arch arch; - void *kernel_buf; - long unsigned int kernel_buf_len; - void *initrd_buf; - long unsigned int initrd_buf_len; - char *cmdline_buf; - long unsigned int cmdline_buf_len; - const struct kexec_file_ops *fops; - void *image_loader_data; - struct purgatory_info purgatory_info; - void *elf_headers; - long unsigned int elf_headers_sz; - long unsigned int elf_load_addr; -}; - -typedef int kexec_cleanup_t(void *); - -struct kexec_file_ops { - kexec_probe_t *probe; - kexec_load_t *load; - kexec_cleanup_t *cleanup; -}; - -struct x86_mapping_info { - void * (*alloc_pgt_page)(void *); - void *context; - long unsigned int page_flag; - long unsigned int offset; - bool direct_gbpages; - long unsigned int kernpg_flag; -}; - -struct init_pgtable_data { - struct x86_mapping_info *info; - pgd_t *level4p; -}; - -typedef void crash_vmclear_fn(); - -struct kexec_buf { - struct kimage *image; - void *buffer; - long unsigned int bufsz; - long unsigned int mem; - long unsigned int memsz; - long unsigned int buf_align; - long unsigned int buf_min; - long unsigned int buf_max; - bool top_down; -}; - -struct crash_mem_range { - u64 start; - u64 end; -}; - -struct crash_mem { - unsigned int max_nr_ranges; - unsigned int nr_ranges; - struct crash_mem_range ranges[0]; -}; - -struct crash_memmap_data { - struct boot_params *params; - unsigned int type; -}; - -struct kexec_entry64_regs { - uint64_t rax; - uint64_t rcx; - uint64_t rdx; - uint64_t rbx; - uint64_t rsp; - uint64_t rbp; - uint64_t rsi; - uint64_t rdi; - uint64_t r8; - uint64_t r9; - uint64_t r10; - uint64_t r11; - uint64_t r12; - uint64_t r13; - uint64_t r14; - uint64_t r15; - uint64_t rip; -}; - -enum key_being_used_for { - VERIFYING_MODULE_SIGNATURE = 0, - VERIFYING_FIRMWARE_SIGNATURE = 1, - VERIFYING_KEXEC_PE_SIGNATURE = 2, - VERIFYING_KEY_SIGNATURE = 3, - VERIFYING_KEY_SELF_SIGNATURE = 4, - VERIFYING_UNSPECIFIED_SIGNATURE = 5, - NR__KEY_BEING_USED_FOR = 6, -}; - -struct efi_setup_data { - u64 fw_vendor; - u64 __unused; - u64 tables; - u64 smbios; - u64 reserved[8]; -}; - -struct bzimage64_data { - void *bootparams_buf; -}; - -struct freelist_node { - atomic_t refs; - struct freelist_node *next; -}; - -struct freelist_head { - struct freelist_node *head; -}; - -struct prev_kprobe { - struct kprobe *kp; - long unsigned int status; - long unsigned int old_flags; - long unsigned int saved_flags; -}; - -struct kprobe_ctlblk { - long unsigned int kprobe_status; - long unsigned int kprobe_old_flags; - long unsigned int kprobe_saved_flags; - struct prev_kprobe prev_kprobe; -}; - -struct kretprobe_instance; - -typedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *); - -struct kretprobe_holder; - -struct kretprobe_instance { - union { - struct freelist_node freelist; - struct callback_head rcu; - }; - struct llist_node llist; - struct kretprobe_holder *rph; - kprobe_opcode_t *ret_addr; - void *fp; - char data[0]; -}; - -struct kretprobe; - -struct kretprobe_holder { - struct kretprobe *rp; - refcount_t ref; -}; - -struct kretprobe { - struct kprobe kp; - kretprobe_handler_t handler; - kretprobe_handler_t entry_handler; - int maxactive; - int nmissed; - size_t data_size; - struct freelist_head freelist; - struct kretprobe_holder *rph; -}; - -struct kretprobe_blackpoint { - const char *name; - void *addr; -}; - -struct kprobe_insn_cache { - struct mutex mutex; - void * (*alloc)(); - void (*free)(void *); - const char *sym; - struct list_head pages; - size_t insn_size; - int nr_garbage; -}; - -struct __arch_relative_insn { - u8 op; - s32 raddr; -} __attribute__((packed)); - -struct arch_optimized_insn { - kprobe_opcode_t copied_insn[4]; - kprobe_opcode_t *insn; - size_t size; -}; - -struct optimized_kprobe { - struct kprobe kp; - struct list_head list; - struct arch_optimized_insn optinsn; -}; - -enum { - TRACE_FTRACE_BIT = 0, - TRACE_FTRACE_NMI_BIT = 1, - TRACE_FTRACE_IRQ_BIT = 2, - TRACE_FTRACE_SIRQ_BIT = 3, - TRACE_INTERNAL_BIT = 4, - TRACE_INTERNAL_NMI_BIT = 5, - TRACE_INTERNAL_IRQ_BIT = 6, - TRACE_INTERNAL_SIRQ_BIT = 7, - TRACE_BRANCH_BIT = 8, - TRACE_IRQ_BIT = 9, - TRACE_GRAPH_BIT = 10, - TRACE_GRAPH_DEPTH_START_BIT = 11, - TRACE_GRAPH_DEPTH_END_BIT = 12, - TRACE_GRAPH_NOTRACE_BIT = 13, - TRACE_TRANSITION_BIT = 14, - TRACE_RECORD_RECURSION_BIT = 15, -}; - -enum { - TRACE_CTX_NMI = 0, - TRACE_CTX_IRQ = 1, - TRACE_CTX_SOFTIRQ = 2, - TRACE_CTX_NORMAL = 3, -}; - -struct console { - char name[16]; - void (*write)(struct console *, const char *, unsigned int); - int (*read)(struct console *, char *, unsigned int); - struct tty_driver * (*device)(struct console *, int *); - void (*unblank)(); - int (*setup)(struct console *, char *); - int (*exit)(struct console *); - int (*match)(struct console *, char *, int, char *); - short int flags; - short int index; - int cflag; - void *data; - struct console *next; -}; - -struct hpet_data { - long unsigned int hd_phys_address; - void *hd_address; - short unsigned int hd_nirqs; - unsigned int hd_state; - unsigned int hd_irq[32]; -}; - -typedef irqreturn_t (*rtc_irq_handler)(int, void *); - -enum hpet_mode { - HPET_MODE_UNUSED = 0, - HPET_MODE_LEGACY = 1, - HPET_MODE_CLOCKEVT = 2, - HPET_MODE_DEVICE = 3, -}; - -struct hpet_channel { - struct clock_event_device evt; - unsigned int num; - unsigned int cpu; - unsigned int irq; - unsigned int in_use; - enum hpet_mode mode; - unsigned int boot_cfg; - char name[10]; - long: 48; - long: 64; - long: 64; - long: 64; -}; - -struct hpet_base { - unsigned int nr_channels; - unsigned int nr_clockevents; - unsigned int boot_cfg; - struct hpet_channel *channels; -}; - -union hpet_lock { - struct { - arch_spinlock_t lock; - u32 value; - }; - u64 lockval; -}; - -struct amd_nb_bus_dev_range { - u8 bus; - u8 dev_base; - u8 dev_limit; -}; - -struct amd_northbridge_info { - u16 num; - u64 flags; - struct amd_northbridge *nb; -}; - -struct swait_queue { - struct task_struct *task; - struct list_head task_list; -}; - -struct kvm_steal_time { - __u64 steal; - __u32 version; - __u32 flags; - __u8 preempted; - __u8 u8_pad[3]; - __u32 pad[11]; -}; - -struct kvm_vcpu_pv_apf_data { - __u32 flags; - __u32 token; - __u8 pad[56]; - __u32 enabled; -}; - -struct kvm_task_sleep_node { - struct hlist_node link; - struct swait_queue_head wq; - u32 token; - int cpu; -}; - -struct kvm_task_sleep_head { - raw_spinlock_t lock; - struct hlist_head list; -}; - -typedef struct ldttss_desc ldt_desc; - -struct branch { - unsigned char opcode; - u32 delta; -} __attribute__((packed)); - -typedef long unsigned int ulong; - -struct jailhouse_setup_data { - struct { - __u16 version; - __u16 compatible_version; - } hdr; - struct { - __u16 pm_timer_address; - __u16 num_cpus; - __u64 pci_mmconfig_base; - __u32 tsc_khz; - __u32 apic_khz; - __u8 standard_ioapic; - __u8 cpu_ids[255]; - } __attribute__((packed)) v1; - struct { - __u32 flags; - } v2; -} __attribute__((packed)); - -struct circ_buf { - char *buf; - int head; - int tail; -}; - -struct serial_rs485 { - __u32 flags; - __u32 delay_rts_before_send; - __u32 delay_rts_after_send; - __u32 padding[5]; -}; - -struct serial_iso7816 { - __u32 flags; - __u32 tg; - __u32 sc_fi; - __u32 sc_di; - __u32 clk; - __u32 reserved[5]; -}; - -struct uart_port; - -struct uart_ops { - unsigned int (*tx_empty)(struct uart_port *); - void (*set_mctrl)(struct uart_port *, unsigned int); - unsigned int (*get_mctrl)(struct uart_port *); - void (*stop_tx)(struct uart_port *); - void (*start_tx)(struct uart_port *); - void (*throttle)(struct uart_port *); - void (*unthrottle)(struct uart_port *); - void (*send_xchar)(struct uart_port *, char); - void (*stop_rx)(struct uart_port *); - void (*enable_ms)(struct uart_port *); - void (*break_ctl)(struct uart_port *, int); - int (*startup)(struct uart_port *); - void (*shutdown)(struct uart_port *); - void (*flush_buffer)(struct uart_port *); - void (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *); - void (*set_ldisc)(struct uart_port *, struct ktermios *); - void (*pm)(struct uart_port *, unsigned int, unsigned int); - const char * (*type)(struct uart_port *); - void (*release_port)(struct uart_port *); - int (*request_port)(struct uart_port *); - void (*config_port)(struct uart_port *, int); - int (*verify_port)(struct uart_port *, struct serial_struct *); - int (*ioctl)(struct uart_port *, unsigned int, long unsigned int); -}; - -struct uart_icount { - __u32 cts; - __u32 dsr; - __u32 rng; - __u32 dcd; - __u32 rx; - __u32 tx; - __u32 frame; - __u32 overrun; - __u32 parity; - __u32 brk; - __u32 buf_overrun; -}; - -typedef unsigned int upf_t; - -typedef unsigned int upstat_t; - -struct gpio_desc; - -struct uart_state; - -struct uart_port { - spinlock_t lock; - long unsigned int iobase; - unsigned char *membase; - unsigned int (*serial_in)(struct uart_port *, int); - void (*serial_out)(struct uart_port *, int, int); - void (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *); - void (*set_ldisc)(struct uart_port *, struct ktermios *); - unsigned int (*get_mctrl)(struct uart_port *); - void (*set_mctrl)(struct uart_port *, unsigned int); - unsigned int (*get_divisor)(struct uart_port *, unsigned int, unsigned int *); - void (*set_divisor)(struct uart_port *, unsigned int, unsigned int, unsigned int); - int (*startup)(struct uart_port *); - void (*shutdown)(struct uart_port *); - void (*throttle)(struct uart_port *); - void (*unthrottle)(struct uart_port *); - int (*handle_irq)(struct uart_port *); - void (*pm)(struct uart_port *, unsigned int, unsigned int); - void (*handle_break)(struct uart_port *); - int (*rs485_config)(struct uart_port *, struct serial_rs485 *); - int (*iso7816_config)(struct uart_port *, struct serial_iso7816 *); - unsigned int irq; - long unsigned int irqflags; - unsigned int uartclk; - unsigned int fifosize; - unsigned char x_char; - unsigned char regshift; - unsigned char iotype; - unsigned char quirks; - unsigned int read_status_mask; - unsigned int ignore_status_mask; - struct uart_state *state; - struct uart_icount icount; - struct console *cons; - upf_t flags; - upstat_t status; - int hw_stopped; - unsigned int mctrl; - unsigned int timeout; - unsigned int type; - const struct uart_ops *ops; - unsigned int custom_divisor; - unsigned int line; - unsigned int minor; - resource_size_t mapbase; - resource_size_t mapsize; - struct device *dev; - long unsigned int sysrq; - unsigned int sysrq_ch; - unsigned char has_sysrq; - unsigned char sysrq_seq; - unsigned char hub6; - unsigned char suspended; - unsigned char console_reinit; - const char *name; - struct attribute_group *attr_group; - const struct attribute_group **tty_groups; - struct serial_rs485 rs485; - struct gpio_desc *rs485_term_gpio; - struct serial_iso7816 iso7816; - void *private_data; -}; - -enum uart_pm_state { - UART_PM_STATE_ON = 0, - UART_PM_STATE_OFF = 3, - UART_PM_STATE_UNDEFINED = 4, -}; - -struct uart_state { - struct tty_port port; - enum uart_pm_state pm_state; - struct circ_buf xmit; - atomic_t refcount; - wait_queue_head_t remove_wait; - struct uart_port *uart_port; -}; - -struct pci_mmcfg_region { - struct list_head list; - struct resource res; - u64 address; - char *virt; - u16 segment; - u8 start_bus; - u8 end_bus; - char name[30]; -}; - -struct scan_area { - u64 addr; - u64 size; -}; - -struct uprobe_xol_ops; - -struct arch_uprobe { - union { - u8 insn[16]; - u8 ixol[16]; - }; - const struct uprobe_xol_ops *ops; - union { - struct { - s32 offs; - u8 ilen; - u8 opc1; - } branch; - struct { - u8 fixups; - u8 ilen; - } defparam; - struct { - u8 reg_offset; - u8 ilen; - } push; - }; -}; - -struct uprobe_xol_ops { - bool (*emulate)(struct arch_uprobe *, struct pt_regs *); - int (*pre_xol)(struct arch_uprobe *, struct pt_regs *); - int (*post_xol)(struct arch_uprobe *, struct pt_regs *); - void (*abort)(struct arch_uprobe *, struct pt_regs *); -}; - -enum rp_check { - RP_CHECK_CALL = 0, - RP_CHECK_CHAIN_CALL = 1, - RP_CHECK_RET = 2, -}; - -struct simplefb_platform_data { - u32 width; - u32 height; - u32 stride; - const char *format; -}; - -enum { - M_I17 = 0, - M_I20 = 1, - M_I20_SR = 2, - M_I24 = 3, - M_I24_8_1 = 4, - M_I24_10_1 = 5, - M_I27_11_1 = 6, - M_MINI = 7, - M_MINI_3_1 = 8, - M_MINI_4_1 = 9, - M_MB = 10, - M_MB_2 = 11, - M_MB_3 = 12, - M_MB_5_1 = 13, - M_MB_6_1 = 14, - M_MB_7_1 = 15, - M_MB_SR = 16, - M_MBA = 17, - M_MBA_3 = 18, - M_MBP = 19, - M_MBP_2 = 20, - M_MBP_2_2 = 21, - M_MBP_SR = 22, - M_MBP_4 = 23, - M_MBP_5_1 = 24, - M_MBP_5_2 = 25, - M_MBP_5_3 = 26, - M_MBP_6_1 = 27, - M_MBP_6_2 = 28, - M_MBP_7_1 = 29, - M_MBP_8_2 = 30, - M_UNKNOWN = 31, -}; - -struct efifb_dmi_info { - char *optname; - long unsigned int base; - int stride; - int width; - int height; - int flags; -}; - -enum { - OVERRIDE_NONE = 0, - OVERRIDE_BASE = 1, - OVERRIDE_STRIDE = 2, - OVERRIDE_HEIGHT = 4, - OVERRIDE_WIDTH = 8, -}; - -enum perf_sample_regs_abi { - PERF_SAMPLE_REGS_ABI_NONE = 0, - PERF_SAMPLE_REGS_ABI_32 = 1, - PERF_SAMPLE_REGS_ABI_64 = 2, -}; - -struct va_format { - const char *fmt; - va_list *va; -}; - -enum es_result { - ES_OK = 0, - ES_UNSUPPORTED = 1, - ES_VMM_ERROR = 2, - ES_DECODE_FAILED = 3, - ES_EXCEPTION = 4, - ES_RETRY = 5, -}; - -struct es_fault_info { - long unsigned int vector; - long unsigned int error_code; - long unsigned int cr2; -}; - -struct es_em_ctxt { - struct pt_regs *regs; - struct insn insn; - struct es_fault_info fi; -}; - -struct sev_es_runtime_data { - struct ghcb ghcb_page; - char ist_stack[4096]; - char fallback_stack[4096]; - struct ghcb backup_ghcb; - bool ghcb_active; - bool backup_ghcb_active; - long unsigned int dr7; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct ghcb_state { - struct ghcb *ghcb; -}; - -struct pci_hostbridge_probe { - u32 bus; - u32 slot; - u32 vendor; - u32 device; -}; - -struct trace_print_flags { - long unsigned int mask; - const char *name; -}; - -enum tlb_flush_reason { - TLB_FLUSH_ON_TASK_SWITCH = 0, - TLB_REMOTE_SHOOTDOWN = 1, - TLB_LOCAL_SHOOTDOWN = 2, - TLB_LOCAL_MM_SHOOTDOWN = 3, - TLB_REMOTE_SEND_IPI = 4, - NR_TLB_FLUSH_REASONS = 5, -}; - -enum { - REGION_INTERSECTS = 0, - REGION_DISJOINT = 1, - REGION_MIXED = 2, -}; - -struct trace_event_raw_tlb_flush { - struct trace_entry ent; - int reason; - long unsigned int pages; - char __data[0]; -}; - -struct trace_event_data_offsets_tlb_flush {}; - -typedef void (*btf_trace_tlb_flush)(void *, int, long unsigned int); - -struct map_range { - long unsigned int start; - long unsigned int end; - unsigned int page_size_mask; -}; - -struct mhp_params { - struct vmem_altmap *altmap; - pgprot_t pgprot; -}; - -struct mem_section_usage { - long unsigned int subsection_map[1]; - long unsigned int pageblock_flags[0]; -}; - -struct mem_section { - long unsigned int section_mem_map; - struct mem_section_usage *usage; -}; - -enum kcore_type { - KCORE_TEXT = 0, - KCORE_VMALLOC = 1, - KCORE_RAM = 2, - KCORE_VMEMMAP = 3, - KCORE_USER = 4, -}; - -struct kcore_list { - struct list_head list; - long unsigned int addr; - size_t size; - int type; -}; - -enum { - MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE = 12, - SECTION_INFO = 12, - MIX_SECTION_INFO = 13, - NODE_INFO = 14, - MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE = 14, -}; - -struct hstate { - struct mutex resize_lock; - int next_nid_to_alloc; - int next_nid_to_free; - unsigned int order; - long unsigned int mask; - long unsigned int max_huge_pages; - long unsigned int nr_huge_pages; - long unsigned int free_huge_pages; - long unsigned int resv_huge_pages; - long unsigned int surplus_huge_pages; - long unsigned int nr_overcommit_huge_pages; - struct list_head hugepage_activelist; - struct list_head hugepage_freelists[32]; - unsigned int nr_huge_pages_node[32]; - unsigned int free_huge_pages_node[32]; - unsigned int surplus_huge_pages_node[32]; - unsigned int nr_free_vmemmap_pages; - struct cftype cgroup_files_dfl[7]; - struct cftype cgroup_files_legacy[9]; - char name[32]; -}; - -struct trace_event_raw_x86_exceptions { - struct trace_entry ent; - long unsigned int address; - long unsigned int ip; - long unsigned int error_code; - char __data[0]; -}; - -struct trace_event_data_offsets_x86_exceptions {}; - -typedef void (*btf_trace_page_fault_user)(void *, long unsigned int, struct pt_regs *, long unsigned int); - -typedef void (*btf_trace_page_fault_kernel)(void *, long unsigned int, struct pt_regs *, long unsigned int); - -enum { - IORES_MAP_SYSTEM_RAM = 1, - IORES_MAP_ENCRYPTED = 2, -}; - -struct ioremap_desc { - unsigned int flags; -}; - -typedef bool (*ex_handler_t)(const struct exception_table_entry *, struct pt_regs *, int, long unsigned int, long unsigned int); - -struct hugepage_subpool { - spinlock_t lock; - long int count; - long int max_hpages; - long int used_hpages; - struct hstate *hstate; - long int min_hpages; - long int rsv_hpages; -}; - -struct hugetlbfs_sb_info { - long int max_inodes; - long int free_inodes; - spinlock_t stat_lock; - struct hstate *hstate; - struct hugepage_subpool *spool; - kuid_t uid; - kgid_t gid; - umode_t mode; -}; - -struct exception_stacks { - char DF_stack_guard[0]; - char DF_stack[4096]; - char NMI_stack_guard[0]; - char NMI_stack[4096]; - char DB_stack_guard[0]; - char DB_stack[4096]; - char MCE_stack_guard[0]; - char MCE_stack[4096]; - char VC_stack_guard[0]; - char VC_stack[0]; - char VC2_stack_guard[0]; - char VC2_stack[0]; - char IST_top_guard[0]; -}; - -struct vm_event_state { - long unsigned int event[100]; -}; - -struct cpa_data { - long unsigned int *vaddr; - pgd_t *pgd; - pgprot_t mask_set; - pgprot_t mask_clr; - long unsigned int numpages; - long unsigned int curpage; - long unsigned int pfn; - unsigned int flags; - unsigned int force_split: 1; - unsigned int force_static_prot: 1; - unsigned int force_flush_all: 1; - struct page **pages; -}; - -enum cpa_warn { - CPA_CONFLICT = 0, - CPA_PROTECT = 1, - CPA_DETECT = 2, -}; - -typedef struct { - u64 val; -} pfn_t; - -struct memtype { - u64 start; - u64 end; - u64 subtree_max_end; - enum page_cache_mode type; - struct rb_node rb; -}; - -enum { - PAT_UC = 0, - PAT_WC = 1, - PAT_WT = 4, - PAT_WP = 5, - PAT_WB = 6, - PAT_UC_MINUS = 7, -}; - -struct pagerange_state { - long unsigned int cur_pfn; - int ram; - int not_ram; -}; - -struct rb_augment_callbacks { - void (*propagate)(struct rb_node *, struct rb_node *); - void (*copy)(struct rb_node *, struct rb_node *); - void (*rotate)(struct rb_node *, struct rb_node *); -}; - -enum { - MEMTYPE_EXACT_MATCH = 0, - MEMTYPE_END_MATCH = 1, -}; - -struct ptdump_range { - long unsigned int start; - long unsigned int end; -}; - -struct ptdump_state { - void (*note_page)(struct ptdump_state *, long unsigned int, int, u64); - void (*effective_prot)(struct ptdump_state *, int, u64); - const struct ptdump_range *range; -}; - -struct addr_marker; - -struct pg_state { - struct ptdump_state ptdump; - int level; - pgprotval_t current_prot; - pgprotval_t effective_prot; - pgprotval_t prot_levels[5]; - long unsigned int start_address; - const struct addr_marker *marker; - long unsigned int lines; - bool to_dmesg; - bool check_wx; - long unsigned int wx_pages; - struct seq_file *seq; -}; - -struct addr_marker { - long unsigned int start_address; - const char *name; - long unsigned int max_lines; -}; - -enum address_markers_idx { - USER_SPACE_NR = 0, - KERNEL_SPACE_NR = 1, - LDT_NR = 2, - LOW_KERNEL_NR = 3, - VMALLOC_START_NR = 4, - VMEMMAP_START_NR = 5, - CPU_ENTRY_AREA_NR = 6, - ESPFIX_START_NR = 7, - EFI_END_NR = 8, - HIGH_KERNEL_NR = 9, - MODULES_VADDR_NR = 10, - MODULES_END_NR = 11, - FIXADDR_START_NR = 12, - END_OF_SPACE_NR = 13, -}; - -typedef void (*rcu_callback_t)(struct callback_head *); - -struct kmmio_probe; - -typedef void (*kmmio_pre_handler_t)(struct kmmio_probe *, struct pt_regs *, long unsigned int); - -typedef void (*kmmio_post_handler_t)(struct kmmio_probe *, long unsigned int, struct pt_regs *); - -struct kmmio_probe { - struct list_head list; - long unsigned int addr; - long unsigned int len; - kmmio_pre_handler_t pre_handler; - kmmio_post_handler_t post_handler; - void *private; -}; - -struct kmmio_fault_page { - struct list_head list; - struct kmmio_fault_page *release_next; - long unsigned int addr; - pteval_t old_presence; - bool armed; - int count; - bool scheduled_for_release; -}; - -struct kmmio_delayed_release { - struct callback_head rcu; - struct kmmio_fault_page *release_list; -}; - -struct kmmio_context { - struct kmmio_fault_page *fpage; - struct kmmio_probe *probe; - long unsigned int saved_flags; - long unsigned int addr; - int active; -}; - -enum reason_type { - NOT_ME = 0, - NOTHING = 1, - REG_READ = 2, - REG_WRITE = 3, - IMM_WRITE = 4, - OTHERS = 5, -}; - -struct prefix_bits { - unsigned int shorted: 1; - unsigned int enlarged: 1; - unsigned int rexr: 1; - unsigned int rex: 1; -}; - -enum { - arg_AL = 0, - arg_CL = 1, - arg_DL = 2, - arg_BL = 3, - arg_AH = 4, - arg_CH = 5, - arg_DH = 6, - arg_BH = 7, - arg_AX = 0, - arg_CX = 1, - arg_DX = 2, - arg_BX = 3, - arg_SP = 4, - arg_BP = 5, - arg_SI = 6, - arg_DI = 7, - arg_R8 = 8, - arg_R9 = 9, - arg_R10 = 10, - arg_R11 = 11, - arg_R12 = 12, - arg_R13 = 13, - arg_R14 = 14, - arg_R15 = 15, -}; - -enum mm_io_opcode { - MMIO_READ = 1, - MMIO_WRITE = 2, - MMIO_PROBE = 3, - MMIO_UNPROBE = 4, - MMIO_UNKNOWN_OP = 5, -}; - -struct mmiotrace_rw { - resource_size_t phys; - long unsigned int value; - long unsigned int pc; - int map_id; - unsigned char opcode; - unsigned char width; -}; - -struct mmiotrace_map { - resource_size_t phys; - long unsigned int virt; - long unsigned int len; - int map_id; - unsigned char opcode; -}; - -struct trap_reason { - long unsigned int addr; - long unsigned int ip; - enum reason_type type; - int active_traces; -}; - -struct remap_trace { - struct list_head list; - struct kmmio_probe probe; - resource_size_t phys; - long unsigned int id; -}; - -struct numa_memblk { - u64 start; - u64 end; - int nid; -}; - -struct numa_meminfo { - int nr_blks; - struct numa_memblk blk[64]; -}; - -struct acpi_srat_cpu_affinity { - struct acpi_subtable_header header; - u8 proximity_domain_lo; - u8 apic_id; - u32 flags; - u8 local_sapic_eid; - u8 proximity_domain_hi[3]; - u32 clock_domain; -}; - -struct acpi_srat_x2apic_cpu_affinity { - struct acpi_subtable_header header; - u16 reserved; - u32 proximity_domain; - u32 apic_id; - u32 flags; - u32 clock_domain; - u32 reserved2; -}; - -enum uv_system_type { - UV_NONE = 0, - UV_LEGACY_APIC = 1, - UV_X2APIC = 2, -}; - -struct rnd_state { - __u32 s1; - __u32 s2; - __u32 s3; - __u32 s4; -}; - -struct kaslr_memory_region { - long unsigned int *base; - long unsigned int size_tb; -}; - -enum pti_mode { - PTI_AUTO = 0, - PTI_FORCE_OFF = 1, - PTI_FORCE_ON = 2, -}; - -enum pti_clone_level { - PTI_CLONE_PMD = 0, - PTI_CLONE_PTE = 1, -}; - -struct sme_populate_pgd_data { - void *pgtable_area; - pgd_t *pgd; - pmdval_t pmd_flags; - pteval_t pte_flags; - long unsigned int paddr; - long unsigned int vaddr; - long unsigned int vaddr_end; -}; - -struct sigcontext_32 { - __u16 gs; - __u16 __gsh; - __u16 fs; - __u16 __fsh; - __u16 es; - __u16 __esh; - __u16 ds; - __u16 __dsh; - __u32 di; - __u32 si; - __u32 bp; - __u32 sp; - __u32 bx; - __u32 dx; - __u32 cx; - __u32 ax; - __u32 trapno; - __u32 err; - __u32 ip; - __u16 cs; - __u16 __csh; - __u32 flags; - __u32 sp_at_signal; - __u16 ss; - __u16 __ssh; - __u32 fpstate; - __u32 oldmask; - __u32 cr2; -}; - -typedef u32 compat_size_t; - -struct compat_sigaltstack { - compat_uptr_t ss_sp; - int ss_flags; - compat_size_t ss_size; -}; - -typedef struct compat_sigaltstack compat_stack_t; - -struct ucontext_ia32 { - unsigned int uc_flags; - unsigned int uc_link; - compat_stack_t uc_stack; - struct sigcontext_32 uc_mcontext; - compat_sigset_t uc_sigmask; -}; - -struct sigframe_ia32 { - u32 pretcode; - int sig; - struct sigcontext_32 sc; - struct _fpstate_32 fpstate_unused; - unsigned int extramask[1]; - char retcode[8]; -}; - -struct rt_sigframe_ia32 { - u32 pretcode; - int sig; - u32 pinfo; - u32 puc; - compat_siginfo_t info; - struct ucontext_ia32 uc; - char retcode[8]; -}; - -typedef struct { - efi_guid_t guid; - u64 table; -} efi_config_table_64_t; - -struct efi_memory_map_data { - phys_addr_t phys_map; - long unsigned int size; - long unsigned int desc_version; - long unsigned int desc_size; - long unsigned int flags; -}; - -struct efi_mem_range { - struct range range; - u64 attribute; -}; - -enum efi_rts_ids { - EFI_NONE = 0, - EFI_GET_TIME = 1, - EFI_SET_TIME = 2, - EFI_GET_WAKEUP_TIME = 3, - EFI_SET_WAKEUP_TIME = 4, - EFI_GET_VARIABLE = 5, - EFI_GET_NEXT_VARIABLE = 6, - EFI_SET_VARIABLE = 7, - EFI_QUERY_VARIABLE_INFO = 8, - EFI_GET_NEXT_HIGH_MONO_COUNT = 9, - EFI_RESET_SYSTEM = 10, - EFI_UPDATE_CAPSULE = 11, - EFI_QUERY_CAPSULE_CAPS = 12, -}; - -struct efi_runtime_work { - void *arg1; - void *arg2; - void *arg3; - void *arg4; - void *arg5; - efi_status_t status; - struct work_struct work; - enum efi_rts_ids efi_rts_id; - struct completion efi_rts_comp; -}; - -typedef struct { - efi_guid_t guid; - u32 table; -} efi_config_table_32_t; - -typedef union { - struct { - efi_guid_t guid; - void *table; - }; - efi_config_table_32_t mixed_mode; -} efi_config_table_t; - -typedef struct { - efi_guid_t guid; - long unsigned int *ptr; - const char name[16]; -} efi_config_table_type_t; - -typedef struct { - efi_table_hdr_t hdr; - u64 fw_vendor; - u32 fw_revision; - u32 __pad1; - u64 con_in_handle; - u64 con_in; - u64 con_out_handle; - u64 con_out; - u64 stderr_handle; - u64 stderr; - u64 runtime; - u64 boottime; - u32 nr_tables; - u32 __pad2; - u64 tables; -} efi_system_table_64_t; - -typedef struct { - u32 version; - u32 length; - u64 memory_protection_attribute; -} efi_properties_table_t; - -typedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *); - -typedef u16 ucs2_char_t; - -struct pm_qos_request { - struct plist_node node; - struct pm_qos_constraints *qos; -}; - -enum { - BPF_REG_0 = 0, - BPF_REG_1 = 1, - BPF_REG_2 = 2, - BPF_REG_3 = 3, - BPF_REG_4 = 4, - BPF_REG_5 = 5, - BPF_REG_6 = 6, - BPF_REG_7 = 7, - BPF_REG_8 = 8, - BPF_REG_9 = 9, - BPF_REG_10 = 10, - __MAX_BPF_REG = 11, -}; - -struct bpf_tramp_progs { - struct bpf_prog *progs[38]; - int nr_progs; -}; - -enum bpf_jit_poke_reason { - BPF_POKE_REASON_TAIL_CALL = 0, -}; - -struct bpf_array_aux { - enum bpf_prog_type type; - bool jited; - struct list_head poke_progs; - struct bpf_map *map; - struct mutex poke_mutex; - struct work_struct work; -}; - -struct bpf_array { - struct bpf_map map; - u32 elem_size; - u32 index_mask; - struct bpf_array_aux *aux; - union { - char value[0]; - void *ptrs[0]; - void *pptrs[0]; - }; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum bpf_text_poke_type { - BPF_MOD_CALL = 0, - BPF_MOD_JUMP = 1, -}; - -struct bpf_binary_header { - u32 pages; - int: 32; - u8 image[0]; -}; - -typedef void (*bpf_jit_fill_hole_t)(void *, unsigned int); - -struct jit_context { - int cleanup_addr; -}; - -struct x64_jit_data { - struct bpf_binary_header *header; - int *addrs; - u8 *image; - int proglen; - struct jit_context ctx; -}; - -enum tk_offsets { - TK_OFFS_REAL = 0, - TK_OFFS_BOOT = 1, - TK_OFFS_TAI = 2, - TK_OFFS_MAX = 3, -}; - -typedef long unsigned int vm_flags_t; - -struct clone_args { - __u64 flags; - __u64 pidfd; - __u64 child_tid; - __u64 parent_tid; - __u64 exit_signal; - __u64 stack; - __u64 stack_size; - __u64 tls; - __u64 set_tid; - __u64 set_tid_size; - __u64 cgroup; -}; - -enum hrtimer_mode { - HRTIMER_MODE_ABS = 0, - HRTIMER_MODE_REL = 1, - HRTIMER_MODE_PINNED = 2, - HRTIMER_MODE_SOFT = 4, - HRTIMER_MODE_HARD = 8, - HRTIMER_MODE_ABS_PINNED = 2, - HRTIMER_MODE_REL_PINNED = 3, - HRTIMER_MODE_ABS_SOFT = 4, - HRTIMER_MODE_REL_SOFT = 5, - HRTIMER_MODE_ABS_PINNED_SOFT = 6, - HRTIMER_MODE_REL_PINNED_SOFT = 7, - HRTIMER_MODE_ABS_HARD = 8, - HRTIMER_MODE_REL_HARD = 9, - HRTIMER_MODE_ABS_PINNED_HARD = 10, - HRTIMER_MODE_REL_PINNED_HARD = 11, -}; - -struct fdtable { - unsigned int max_fds; - struct file **fd; - long unsigned int *close_on_exec; - long unsigned int *open_fds; - long unsigned int *full_fds_bits; - struct callback_head rcu; -}; - -struct files_struct { - atomic_t count; - bool resize_in_progress; - wait_queue_head_t resize_wait; - struct fdtable *fdt; - struct fdtable fdtab; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t file_lock; - unsigned int next_fd; - long unsigned int close_on_exec_init[1]; - long unsigned int open_fds_init[1]; - long unsigned int full_fds_bits_init[1]; - struct file *fd_array[64]; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct robust_list { - struct robust_list *next; -}; - -struct robust_list_head { - struct robust_list list; - long int futex_offset; - struct robust_list *list_op_pending; -}; - -struct multiprocess_signals { - sigset_t signal; - struct hlist_node node; -}; - -typedef int (*proc_visitor)(struct task_struct *, void *); - -enum { - IOPRIO_CLASS_NONE = 0, - IOPRIO_CLASS_RT = 1, - IOPRIO_CLASS_BE = 2, - IOPRIO_CLASS_IDLE = 3, -}; - -typedef struct poll_table_struct poll_table; - -enum { - FUTEX_STATE_OK = 0, - FUTEX_STATE_EXITING = 1, - FUTEX_STATE_DEAD = 2, -}; - -enum proc_hidepid { - HIDEPID_OFF = 0, - HIDEPID_NO_ACCESS = 1, - HIDEPID_INVISIBLE = 2, - HIDEPID_NOT_PTRACEABLE = 4, -}; - -enum proc_pidonly { - PROC_PIDONLY_OFF = 0, - PROC_PIDONLY_ON = 1, -}; - -struct proc_fs_info { - struct pid_namespace *pid_ns; - struct dentry *proc_self; - struct dentry *proc_thread_self; - kgid_t pid_gid; - enum proc_hidepid hide_pid; - enum proc_pidonly pidonly; -}; - -struct trace_event_raw_task_newtask { - struct trace_entry ent; - pid_t pid; - char comm[16]; - long unsigned int clone_flags; - short int oom_score_adj; - char __data[0]; -}; - -struct trace_event_raw_task_rename { - struct trace_entry ent; - pid_t pid; - char oldcomm[16]; - char newcomm[16]; - short int oom_score_adj; - char __data[0]; -}; - -struct trace_event_data_offsets_task_newtask {}; - -struct trace_event_data_offsets_task_rename {}; - -typedef void (*btf_trace_task_newtask)(void *, struct task_struct *, long unsigned int); - -typedef void (*btf_trace_task_rename)(void *, struct task_struct *, const char *); - -struct taint_flag { - char c_true; - char c_false; - bool module; -}; - -enum ftrace_dump_mode { - DUMP_NONE = 0, - DUMP_ALL = 1, - DUMP_ORIG = 2, -}; - -enum kmsg_dump_reason { - KMSG_DUMP_UNDEF = 0, - KMSG_DUMP_PANIC = 1, - KMSG_DUMP_OOPS = 2, - KMSG_DUMP_EMERG = 3, - KMSG_DUMP_SHUTDOWN = 4, - KMSG_DUMP_MAX = 5, -}; - -enum con_flush_mode { - CONSOLE_FLUSH_PENDING = 0, - CONSOLE_REPLAY_ALL = 1, -}; - -struct warn_args { - const char *fmt; - va_list args; -}; - -struct smp_hotplug_thread { - struct task_struct **store; - struct list_head list; - int (*thread_should_run)(unsigned int); - void (*thread_fn)(unsigned int); - void (*create)(unsigned int); - void (*setup)(unsigned int); - void (*cleanup)(unsigned int, bool); - void (*park)(unsigned int); - void (*unpark)(unsigned int); - bool selfparking; - const char *thread_comm; -}; - -struct trace_event_raw_cpuhp_enter { - struct trace_entry ent; - unsigned int cpu; - int target; - int idx; - void *fun; - char __data[0]; -}; - -struct trace_event_raw_cpuhp_multi_enter { - struct trace_entry ent; - unsigned int cpu; - int target; - int idx; - void *fun; - char __data[0]; -}; - -struct trace_event_raw_cpuhp_exit { - struct trace_entry ent; - unsigned int cpu; - int state; - int idx; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_cpuhp_enter {}; - -struct trace_event_data_offsets_cpuhp_multi_enter {}; - -struct trace_event_data_offsets_cpuhp_exit {}; - -typedef void (*btf_trace_cpuhp_enter)(void *, unsigned int, int, int, int (*)(unsigned int)); - -typedef void (*btf_trace_cpuhp_multi_enter)(void *, unsigned int, int, int, int (*)(unsigned int, struct hlist_node *), struct hlist_node *); - -typedef void (*btf_trace_cpuhp_exit)(void *, unsigned int, int, int, int); - -struct cpuhp_cpu_state { - enum cpuhp_state state; - enum cpuhp_state target; - enum cpuhp_state fail; - struct task_struct *thread; - bool should_run; - bool rollback; - bool single; - bool bringup; - int cpu; - struct hlist_node *node; - struct hlist_node *last; - enum cpuhp_state cb_state; - int result; - struct completion done_up; - struct completion done_down; -}; - -struct cpuhp_step { - const char *name; - union { - int (*single)(unsigned int); - int (*multi)(unsigned int, struct hlist_node *); - } startup; - union { - int (*single)(unsigned int); - int (*multi)(unsigned int, struct hlist_node *); - } teardown; - struct hlist_head list; - bool cant_stop; - bool multi_instance; -}; - -enum cpu_mitigations { - CPU_MITIGATIONS_OFF = 0, - CPU_MITIGATIONS_AUTO = 1, - CPU_MITIGATIONS_AUTO_NOSMT = 2, -}; - -struct __kernel_old_timeval { - __kernel_long_t tv_sec; - __kernel_long_t tv_usec; -}; - -struct old_timeval32 { - old_time32_t tv_sec; - s32 tv_usec; -}; - -struct rusage { - struct __kernel_old_timeval ru_utime; - struct __kernel_old_timeval ru_stime; - __kernel_long_t ru_maxrss; - __kernel_long_t ru_ixrss; - __kernel_long_t ru_idrss; - __kernel_long_t ru_isrss; - __kernel_long_t ru_minflt; - __kernel_long_t ru_majflt; - __kernel_long_t ru_nswap; - __kernel_long_t ru_inblock; - __kernel_long_t ru_oublock; - __kernel_long_t ru_msgsnd; - __kernel_long_t ru_msgrcv; - __kernel_long_t ru_nsignals; - __kernel_long_t ru_nvcsw; - __kernel_long_t ru_nivcsw; -}; - -typedef struct {} mm_segment_t; - -struct compat_rusage { - struct old_timeval32 ru_utime; - struct old_timeval32 ru_stime; - compat_long_t ru_maxrss; - compat_long_t ru_ixrss; - compat_long_t ru_idrss; - compat_long_t ru_isrss; - compat_long_t ru_minflt; - compat_long_t ru_majflt; - compat_long_t ru_nswap; - compat_long_t ru_inblock; - compat_long_t ru_oublock; - compat_long_t ru_msgsnd; - compat_long_t ru_msgrcv; - compat_long_t ru_nsignals; - compat_long_t ru_nvcsw; - compat_long_t ru_nivcsw; -}; - -struct waitid_info { - pid_t pid; - uid_t uid; - int status; - int cause; -}; - -struct wait_opts { - enum pid_type wo_type; - int wo_flags; - struct pid *wo_pid; - struct waitid_info *wo_info; - int wo_stat; - struct rusage *wo_rusage; - wait_queue_entry_t child_wait; - int notask_error; -}; - -struct softirq_action { - void (*action)(struct softirq_action *); -}; - -struct tasklet_struct { - struct tasklet_struct *next; - long unsigned int state; - atomic_t count; - bool use_callback; - union { - void (*func)(long unsigned int); - void (*callback)(struct tasklet_struct *); - }; - long unsigned int data; -}; - -enum { - TASKLET_STATE_SCHED = 0, - TASKLET_STATE_RUN = 1, -}; - -struct kernel_stat { - long unsigned int irqs_sum; - unsigned int softirqs[10]; -}; - -struct wait_bit_key { - void *flags; - int bit_nr; - long unsigned int timeout; -}; - -struct wait_bit_queue_entry { - struct wait_bit_key key; - struct wait_queue_entry wq_entry; -}; - -struct trace_event_raw_irq_handler_entry { - struct trace_entry ent; - int irq; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_irq_handler_exit { - struct trace_entry ent; - int irq; - int ret; - char __data[0]; -}; - -struct trace_event_raw_softirq { - struct trace_entry ent; - unsigned int vec; - char __data[0]; -}; - -struct trace_event_data_offsets_irq_handler_entry { - u32 name; -}; - -struct trace_event_data_offsets_irq_handler_exit {}; - -struct trace_event_data_offsets_softirq {}; - -typedef void (*btf_trace_irq_handler_entry)(void *, int, struct irqaction *); - -typedef void (*btf_trace_irq_handler_exit)(void *, int, struct irqaction *, int); - -typedef void (*btf_trace_softirq_entry)(void *, unsigned int); - -typedef void (*btf_trace_softirq_exit)(void *, unsigned int); - -typedef void (*btf_trace_softirq_raise)(void *, unsigned int); - -struct tasklet_head { - struct tasklet_struct *head; - struct tasklet_struct **tail; -}; - -struct pseudo_fs_context { - const struct super_operations *ops; - const struct xattr_handler **xattr; - const struct dentry_operations *dops; - long unsigned int magic; -}; - -typedef void (*dr_release_t)(struct device *, void *); - -typedef int (*dr_match_t)(struct device *, void *, void *); - -struct resource_entry { - struct list_head node; - struct resource *res; - resource_size_t offset; - struct resource __res; -}; - -struct resource_constraint { - resource_size_t min; - resource_size_t max; - resource_size_t align; - resource_size_t (*alignf)(void *, const struct resource *, resource_size_t, resource_size_t); - void *alignf_data; -}; - -enum { - MAX_IORES_LEVEL = 5, -}; - -struct region_devres { - struct resource *parent; - resource_size_t start; - resource_size_t n; -}; - -typedef __kernel_clock_t clock_t; - -struct dentry_stat_t { - long int nr_dentry; - long int nr_unused; - long int age_limit; - long int want_pages; - long int nr_negative; - long int dummy; -}; - -struct files_stat_struct { - long unsigned int nr_files; - long unsigned int nr_free_files; - long unsigned int max_files; -}; - -struct inodes_stat_t { - long int nr_inodes; - long int nr_unused; - long int dummy[5]; -}; - -enum sysctl_writes_mode { - SYSCTL_WRITES_LEGACY = 4294967295, - SYSCTL_WRITES_WARN = 0, - SYSCTL_WRITES_STRICT = 1, -}; - -struct do_proc_dointvec_minmax_conv_param { - int *min; - int *max; -}; - -struct do_proc_douintvec_minmax_conv_param { - unsigned int *min; - unsigned int *max; -}; - -struct __user_cap_header_struct { - __u32 version; - int pid; -}; - -typedef struct __user_cap_header_struct *cap_user_header_t; - -struct __user_cap_data_struct { - __u32 effective; - __u32 permitted; - __u32 inheritable; -}; - -typedef struct __user_cap_data_struct *cap_user_data_t; - -struct sigqueue { - struct list_head list; - int flags; - kernel_siginfo_t info; - struct ucounts *ucounts; -}; - -typedef int wait_bit_action_f(struct wait_bit_key *, int); - -struct ptrace_peeksiginfo_args { - __u64 off; - __u32 flags; - __s32 nr; -}; - -struct ptrace_syscall_info { - __u8 op; - __u8 pad[3]; - __u32 arch; - __u64 instruction_pointer; - __u64 stack_pointer; - union { - struct { - __u64 nr; - __u64 args[6]; - } entry; - struct { - __s64 rval; - __u8 is_error; - } exit; - struct { - __u64 nr; - __u64 args[6]; - __u32 ret_data; - } seccomp; - }; -}; - -struct ptrace_rseq_configuration { - __u64 rseq_abi_pointer; - __u32 rseq_abi_size; - __u32 signature; - __u32 flags; - __u32 pad; -}; - -struct compat_iovec { - compat_uptr_t iov_base; - compat_size_t iov_len; -}; - -typedef long unsigned int old_sigset_t; - -enum siginfo_layout { - SIL_KILL = 0, - SIL_TIMER = 1, - SIL_POLL = 2, - SIL_FAULT = 3, - SIL_FAULT_TRAPNO = 4, - SIL_FAULT_MCEERR = 5, - SIL_FAULT_BNDERR = 6, - SIL_FAULT_PKUERR = 7, - SIL_PERF_EVENT = 8, - SIL_CHLD = 9, - SIL_RT = 10, - SIL_SYS = 11, -}; - -struct fd { - struct file *file; - unsigned int flags; -}; - -typedef u32 compat_old_sigset_t; - -struct compat_sigaction { - compat_uptr_t sa_handler; - compat_ulong_t sa_flags; - compat_uptr_t sa_restorer; - compat_sigset_t sa_mask; -}; - -struct compat_old_sigaction { - compat_uptr_t sa_handler; - compat_old_sigset_t sa_mask; - compat_ulong_t sa_flags; - compat_uptr_t sa_restorer; -}; - -enum { - TRACE_SIGNAL_DELIVERED = 0, - TRACE_SIGNAL_IGNORED = 1, - TRACE_SIGNAL_ALREADY_PENDING = 2, - TRACE_SIGNAL_OVERFLOW_FAIL = 3, - TRACE_SIGNAL_LOSE_INFO = 4, -}; - -struct trace_event_raw_signal_generate { - struct trace_entry ent; - int sig; - int errno; - int code; - char comm[16]; - pid_t pid; - int group; - int result; - char __data[0]; -}; - -struct trace_event_raw_signal_deliver { - struct trace_entry ent; - int sig; - int errno; - int code; - long unsigned int sa_handler; - long unsigned int sa_flags; - char __data[0]; -}; - -struct trace_event_data_offsets_signal_generate {}; - -struct trace_event_data_offsets_signal_deliver {}; - -typedef void (*btf_trace_signal_generate)(void *, int, struct kernel_siginfo *, struct task_struct *, int, int); - -typedef void (*btf_trace_signal_deliver)(void *, int, struct kernel_siginfo *, struct k_sigaction *); - -struct sysinfo { - __kernel_long_t uptime; - __kernel_ulong_t loads[3]; - __kernel_ulong_t totalram; - __kernel_ulong_t freeram; - __kernel_ulong_t sharedram; - __kernel_ulong_t bufferram; - __kernel_ulong_t totalswap; - __kernel_ulong_t freeswap; - __u16 procs; - __u16 pad; - __kernel_ulong_t totalhigh; - __kernel_ulong_t freehigh; - __u32 mem_unit; - char _f[0]; -}; - -enum { - PER_LINUX = 0, - PER_LINUX_32BIT = 8388608, - PER_LINUX_FDPIC = 524288, - PER_SVR4 = 68157441, - PER_SVR3 = 83886082, - PER_SCOSVR3 = 117440515, - PER_OSR5 = 100663299, - PER_WYSEV386 = 83886084, - PER_ISCR4 = 67108869, - PER_BSD = 6, - PER_SUNOS = 67108870, - PER_XENIX = 83886087, - PER_LINUX32 = 8, - PER_LINUX32_3GB = 134217736, - PER_IRIX32 = 67108873, - PER_IRIXN32 = 67108874, - PER_IRIX64 = 67108875, - PER_RISCOS = 12, - PER_SOLARIS = 67108877, - PER_UW7 = 68157454, - PER_OSF4 = 15, - PER_HPUX = 16, - PER_MASK = 255, -}; - -struct rlimit64 { - __u64 rlim_cur; - __u64 rlim_max; -}; - -struct oldold_utsname { - char sysname[9]; - char nodename[9]; - char release[9]; - char version[9]; - char machine[9]; -}; - -struct old_utsname { - char sysname[65]; - char nodename[65]; - char release[65]; - char version[65]; - char machine[65]; -}; - -enum uts_proc { - UTS_PROC_OSTYPE = 0, - UTS_PROC_OSRELEASE = 1, - UTS_PROC_VERSION = 2, - UTS_PROC_HOSTNAME = 3, - UTS_PROC_DOMAINNAME = 4, -}; - -struct prctl_mm_map { - __u64 start_code; - __u64 end_code; - __u64 start_data; - __u64 end_data; - __u64 start_brk; - __u64 brk; - __u64 start_stack; - __u64 arg_start; - __u64 arg_end; - __u64 env_start; - __u64 env_end; - __u64 *auxv; - __u32 auxv_size; - __u32 exe_fd; -}; - -struct compat_tms { - compat_clock_t tms_utime; - compat_clock_t tms_stime; - compat_clock_t tms_cutime; - compat_clock_t tms_cstime; -}; - -struct compat_rlimit { - compat_ulong_t rlim_cur; - compat_ulong_t rlim_max; -}; - -struct tms { - __kernel_clock_t tms_utime; - __kernel_clock_t tms_stime; - __kernel_clock_t tms_cutime; - __kernel_clock_t tms_cstime; -}; - -struct getcpu_cache { - long unsigned int blob[16]; -}; - -struct compat_sysinfo { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - u16 procs; - u16 pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[8]; -}; - -struct wq_flusher; - -struct worker; - -struct workqueue_attrs; - -struct pool_workqueue; - -struct wq_device; - -struct workqueue_struct { - struct list_head pwqs; - struct list_head list; - struct mutex mutex; - int work_color; - int flush_color; - atomic_t nr_pwqs_to_flush; - struct wq_flusher *first_flusher; - struct list_head flusher_queue; - struct list_head flusher_overflow; - struct list_head maydays; - struct worker *rescuer; - int nr_drainers; - int saved_max_active; - struct workqueue_attrs *unbound_attrs; - struct pool_workqueue *dfl_pwq; - struct wq_device *wq_dev; - char name[24]; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - unsigned int flags; - struct pool_workqueue *cpu_pwqs; - struct pool_workqueue *numa_pwq_tbl[0]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct workqueue_attrs { - int nice; - cpumask_var_t cpumask; - bool no_numa; -}; - -struct execute_work { - struct work_struct work; -}; - -enum { - WQ_UNBOUND = 2, - WQ_FREEZABLE = 4, - WQ_MEM_RECLAIM = 8, - WQ_HIGHPRI = 16, - WQ_CPU_INTENSIVE = 32, - WQ_SYSFS = 64, - WQ_POWER_EFFICIENT = 128, - __WQ_DRAINING = 65536, - __WQ_ORDERED = 131072, - __WQ_LEGACY = 262144, - __WQ_ORDERED_EXPLICIT = 524288, - WQ_MAX_ACTIVE = 512, - WQ_MAX_UNBOUND_PER_CPU = 4, - WQ_DFL_ACTIVE = 256, -}; - -enum xa_lock_type { - XA_LOCK_IRQ = 1, - XA_LOCK_BH = 2, -}; - -struct ida { - struct xarray xa; -}; - -struct __una_u32 { - u32 x; -}; - -struct worker_pool; - -struct worker { - union { - struct list_head entry; - struct hlist_node hentry; - }; - struct work_struct *current_work; - work_func_t current_func; - struct pool_workqueue *current_pwq; - struct list_head scheduled; - struct task_struct *task; - struct worker_pool *pool; - struct list_head node; - long unsigned int last_active; - unsigned int flags; - int id; - int sleeping; - char desc[24]; - struct workqueue_struct *rescue_wq; - work_func_t last_func; -}; - -struct pool_workqueue { - struct worker_pool *pool; - struct workqueue_struct *wq; - int work_color; - int flush_color; - int refcnt; - int nr_in_flight[15]; - int nr_active; - int max_active; - struct list_head delayed_works; - struct list_head pwqs_node; - struct list_head mayday_node; - struct work_struct unbound_release_work; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct worker_pool { - raw_spinlock_t lock; - int cpu; - int node; - int id; - unsigned int flags; - long unsigned int watchdog_ts; - struct list_head worklist; - int nr_workers; - int nr_idle; - struct list_head idle_list; - struct timer_list idle_timer; - struct timer_list mayday_timer; - struct hlist_head busy_hash[64]; - struct worker *manager; - struct list_head workers; - struct completion *detach_completion; - struct ida worker_ida; - struct workqueue_attrs *attrs; - struct hlist_node hash_node; - int refcnt; - long: 32; - long: 64; - long: 64; - long: 64; - atomic_t nr_running; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum { - POOL_MANAGER_ACTIVE = 1, - POOL_DISASSOCIATED = 4, - WORKER_DIE = 2, - WORKER_IDLE = 4, - WORKER_PREP = 8, - WORKER_CPU_INTENSIVE = 64, - WORKER_UNBOUND = 128, - WORKER_REBOUND = 256, - WORKER_NOT_RUNNING = 456, - NR_STD_WORKER_POOLS = 2, - UNBOUND_POOL_HASH_ORDER = 6, - BUSY_WORKER_HASH_ORDER = 6, - MAX_IDLE_WORKERS_RATIO = 4, - IDLE_WORKER_TIMEOUT = 90000, - MAYDAY_INITIAL_TIMEOUT = 3, - MAYDAY_INTERVAL = 30, - CREATE_COOLDOWN = 300, - RESCUER_NICE_LEVEL = 4294967276, - HIGHPRI_NICE_LEVEL = 4294967276, - WQ_NAME_LEN = 24, -}; - -struct wq_flusher { - struct list_head list; - int flush_color; - struct completion done; -}; - -struct wq_device { - struct workqueue_struct *wq; - struct device dev; -}; - -struct trace_event_raw_workqueue_queue_work { - struct trace_entry ent; - void *work; - void *function; - u32 __data_loc_workqueue; - unsigned int req_cpu; - unsigned int cpu; - char __data[0]; -}; - -struct trace_event_raw_workqueue_activate_work { - struct trace_entry ent; - void *work; - char __data[0]; -}; - -struct trace_event_raw_workqueue_execute_start { - struct trace_entry ent; - void *work; - void *function; - char __data[0]; -}; - -struct trace_event_raw_workqueue_execute_end { - struct trace_entry ent; - void *work; - void *function; - char __data[0]; -}; - -struct trace_event_data_offsets_workqueue_queue_work { - u32 workqueue; -}; - -struct trace_event_data_offsets_workqueue_activate_work {}; - -struct trace_event_data_offsets_workqueue_execute_start {}; - -struct trace_event_data_offsets_workqueue_execute_end {}; - -typedef void (*btf_trace_workqueue_queue_work)(void *, unsigned int, struct pool_workqueue *, struct work_struct *); - -typedef void (*btf_trace_workqueue_activate_work)(void *, struct work_struct *); - -typedef void (*btf_trace_workqueue_execute_start)(void *, struct work_struct *); - -typedef void (*btf_trace_workqueue_execute_end)(void *, struct work_struct *, work_func_t); - -struct wq_barrier { - struct work_struct work; - struct completion done; - struct task_struct *task; -}; - -struct cwt_wait { - wait_queue_entry_t wait; - struct work_struct *work; -}; - -struct apply_wqattrs_ctx { - struct workqueue_struct *wq; - struct workqueue_attrs *attrs; - struct list_head list; - struct pool_workqueue *dfl_pwq; - struct pool_workqueue *pwq_tbl[0]; -}; - -struct work_for_cpu { - struct work_struct work; - long int (*fn)(void *); - void *arg; - long int ret; -}; - -typedef struct {} local_lock_t; - -struct radix_tree_preload { - local_lock_t lock; - unsigned int nr; - struct xa_node *nodes; -}; - -typedef void (*task_work_func_t)(struct callback_head *); - -enum { - KERNEL_PARAM_OPS_FL_NOARG = 1, -}; - -enum { - KERNEL_PARAM_FL_UNSAFE = 1, - KERNEL_PARAM_FL_HWPARAM = 2, -}; - -struct param_attribute { - struct module_attribute mattr; - const struct kernel_param *param; -}; - -struct module_param_attrs { - unsigned int num; - struct attribute_group grp; - struct param_attribute attrs[0]; -}; - -struct module_version_attribute { - struct module_attribute mattr; - const char *module_name; - const char *version; -}; - -struct kmalloced_param { - struct list_head list; - char val[0]; -}; - -struct sched_param { - int sched_priority; -}; - -enum { - __PERCPU_REF_ATOMIC = 1, - __PERCPU_REF_DEAD = 2, - __PERCPU_REF_ATOMIC_DEAD = 3, - __PERCPU_REF_FLAG_BITS = 2, -}; - -struct kthread_work; - -typedef void (*kthread_work_func_t)(struct kthread_work *); - -struct kthread_worker; - -struct kthread_work { - struct list_head node; - kthread_work_func_t func; - struct kthread_worker *worker; - int canceling; -}; - -enum { - KTW_FREEZABLE = 1, -}; - -struct kthread_worker { - unsigned int flags; - raw_spinlock_t lock; - struct list_head work_list; - struct list_head delayed_work_list; - struct task_struct *task; - struct kthread_work *current_work; -}; - -struct kthread_delayed_work { - struct kthread_work work; - struct timer_list timer; -}; - -enum { - CSS_NO_REF = 1, - CSS_ONLINE = 2, - CSS_RELEASED = 4, - CSS_VISIBLE = 8, - CSS_DYING = 16, -}; - -struct kthread_create_info { - int (*threadfn)(void *); - void *data; - int node; - struct task_struct *result; - struct completion *done; - struct list_head list; -}; - -struct kthread { - long unsigned int flags; - unsigned int cpu; - int (*threadfn)(void *); - void *data; - mm_segment_t oldfs; - struct completion parked; - struct completion exited; - struct cgroup_subsys_state *blkcg_css; -}; - -enum KTHREAD_BITS { - KTHREAD_IS_PER_CPU = 0, - KTHREAD_SHOULD_STOP = 1, - KTHREAD_SHOULD_PARK = 2, -}; - -struct kthread_flush_work { - struct kthread_work work; - struct completion done; -}; - -struct pt_regs___2; - -struct ipc_ids { - int in_use; - short unsigned int seq; - struct rw_semaphore rwsem; - struct idr ipcs_idr; - int max_idx; - int last_idx; - int next_id; - struct rhashtable key_ht; -}; - -struct ipc_namespace { - struct ipc_ids ids[3]; - int sem_ctls[4]; - int used_sems; - unsigned int msg_ctlmax; - unsigned int msg_ctlmnb; - unsigned int msg_ctlmni; - atomic_t msg_bytes; - atomic_t msg_hdrs; - size_t shm_ctlmax; - size_t shm_ctlall; - long unsigned int shm_tot; - int shm_ctlmni; - int shm_rmid_forced; - struct notifier_block ipcns_nb; - struct vfsmount *mq_mnt; - unsigned int mq_queues_count; - unsigned int mq_queues_max; - unsigned int mq_msg_max; - unsigned int mq_msgsize_max; - unsigned int mq_msg_default; - unsigned int mq_msgsize_default; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct llist_node mnt_llist; - struct ns_common ns; -}; - -struct srcu_notifier_head { - struct mutex mutex; - struct srcu_struct srcu; - struct notifier_block *head; -}; - -enum what { - PROC_EVENT_NONE = 0, - PROC_EVENT_FORK = 1, - PROC_EVENT_EXEC = 2, - PROC_EVENT_UID = 4, - PROC_EVENT_GID = 64, - PROC_EVENT_SID = 128, - PROC_EVENT_PTRACE = 256, - PROC_EVENT_COMM = 512, - PROC_EVENT_COREDUMP = 1073741824, - PROC_EVENT_EXIT = 2147483648, -}; - -struct async_entry { - struct list_head domain_list; - struct list_head global_list; - struct work_struct work; - async_cookie_t cookie; - async_func_t func; - void *data; - struct async_domain *domain; -}; - -struct smpboot_thread_data { - unsigned int cpu; - unsigned int status; - struct smp_hotplug_thread *ht; -}; - -enum { - HP_THREAD_NONE = 0, - HP_THREAD_ACTIVE = 1, - HP_THREAD_PARKED = 2, -}; - -struct umd_info { - const char *driver_name; - struct file *pipe_to_umh; - struct file *pipe_from_umh; - struct path wd; - struct pid *tgid; -}; - -struct pin_cookie {}; - -struct preempt_notifier; - -struct preempt_ops { - void (*sched_in)(struct preempt_notifier *, int); - void (*sched_out)(struct preempt_notifier *, struct task_struct *); -}; - -struct preempt_notifier { - struct hlist_node link; - struct preempt_ops *ops; -}; - -enum { - CSD_FLAG_LOCK = 1, - IRQ_WORK_PENDING = 1, - IRQ_WORK_BUSY = 2, - IRQ_WORK_LAZY = 4, - IRQ_WORK_HARD_IRQ = 8, - IRQ_WORK_CLAIMED = 3, - CSD_TYPE_ASYNC = 0, - CSD_TYPE_SYNC = 16, - CSD_TYPE_IRQ_WORK = 32, - CSD_TYPE_TTWU = 48, - CSD_FLAG_TYPE_MASK = 240, -}; - -struct dl_bw { - raw_spinlock_t lock; - u64 bw; - u64 total_bw; -}; - -struct cpudl_item; - -struct cpudl { - raw_spinlock_t lock; - int size; - cpumask_var_t free_cpus; - struct cpudl_item *elements; -}; - -struct cpupri_vec { - atomic_t count; - cpumask_var_t mask; -}; - -struct cpupri { - struct cpupri_vec pri_to_cpu[101]; - int *cpu_to_pri; -}; - -struct perf_domain; - -struct root_domain { - atomic_t refcount; - atomic_t rto_count; - struct callback_head rcu; - cpumask_var_t span; - cpumask_var_t online; - int overload; - int overutilized; - cpumask_var_t dlo_mask; - atomic_t dlo_count; - struct dl_bw dl_bw; - struct cpudl cpudl; - u64 visit_gen; - struct irq_work rto_push_work; - raw_spinlock_t rto_lock; - int rto_loop; - int rto_cpu; - atomic_t rto_loop_next; - atomic_t rto_loop_start; - cpumask_var_t rto_mask; - struct cpupri cpupri; - long unsigned int max_cpu_capacity; - struct perf_domain *pd; -}; - -struct cfs_rq { - struct load_weight load; - unsigned int nr_running; - unsigned int h_nr_running; - unsigned int idle_h_nr_running; - u64 exec_clock; - u64 min_vruntime; - unsigned int forceidle_seq; - u64 min_vruntime_fi; - struct rb_root_cached tasks_timeline; - struct sched_entity *curr; - struct sched_entity *next; - struct sched_entity *last; - struct sched_entity *skip; - unsigned int nr_spread_over; - long: 32; - long: 64; - struct sched_avg avg; - struct { - raw_spinlock_t lock; - int nr; - long unsigned int load_avg; - long unsigned int util_avg; - long unsigned int runnable_avg; - long: 64; - long: 64; - long: 64; - long: 64; - } removed; - long unsigned int tg_load_avg_contrib; - long int propagate; - long int prop_runnable_sum; - long unsigned int h_load; - u64 last_h_load_update; - struct sched_entity *h_load_next; - struct rq *rq; - int on_list; - struct list_head leaf_cfs_rq_list; - struct task_group *tg; - int runtime_enabled; - s64 runtime_remaining; - u64 throttled_clock; - u64 throttled_clock_task; - u64 throttled_clock_task_time; - int throttled; - int throttle_count; - struct list_head throttled_list; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct cfs_bandwidth { - raw_spinlock_t lock; - ktime_t period; - u64 quota; - u64 runtime; - u64 burst; - s64 hierarchical_quota; - u8 idle; - u8 period_active; - u8 slack_started; - struct hrtimer period_timer; - struct hrtimer slack_timer; - struct list_head throttled_cfs_rq; - int nr_periods; - int nr_throttled; - u64 throttled_time; -}; - -struct task_group { - struct cgroup_subsys_state css; - struct sched_entity **se; - struct cfs_rq **cfs_rq; - long unsigned int shares; - long: 64; - long: 64; - long: 64; - long: 64; - atomic_long_t load_avg; - struct callback_head rcu; - struct list_head list; - struct task_group *parent; - struct list_head siblings; - struct list_head children; - struct autogroup *autogroup; - struct cfs_bandwidth cfs_bandwidth; - unsigned int uclamp_pct[2]; - struct uclamp_se uclamp_req[2]; - struct uclamp_se uclamp[2]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct sched_domain_attr { - int relax_domain_level; -}; - -struct sched_group { - struct sched_group *next; - atomic_t ref; - unsigned int group_weight; - struct sched_group_capacity *sgc; - int asym_prefer_cpu; - long unsigned int cpumask[0]; -}; - -struct sched_group_capacity { - atomic_t ref; - long unsigned int capacity; - long unsigned int min_capacity; - long unsigned int max_capacity; - long unsigned int next_update; - int imbalance; - int id; - long unsigned int cpumask[0]; -}; - -struct autogroup { - struct kref kref; - struct task_group *tg; - struct rw_semaphore lock; - long unsigned int id; - int nice; -}; - -enum ctx_state { - CONTEXT_DISABLED = 4294967295, - CONTEXT_KERNEL = 0, - CONTEXT_USER = 1, - CONTEXT_GUEST = 2, -}; - -struct kernel_cpustat { - u64 cpustat[10]; -}; - -enum { - MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY = 1, - MEMBARRIER_STATE_PRIVATE_EXPEDITED = 2, - MEMBARRIER_STATE_GLOBAL_EXPEDITED_READY = 4, - MEMBARRIER_STATE_GLOBAL_EXPEDITED = 8, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY = 16, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE = 32, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ_READY = 64, - MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ = 128, -}; - -enum { - CFTYPE_ONLY_ON_ROOT = 1, - CFTYPE_NOT_ON_ROOT = 2, - CFTYPE_NS_DELEGATABLE = 4, - CFTYPE_NO_PREFIX = 8, - CFTYPE_WORLD_WRITABLE = 16, - CFTYPE_DEBUG = 32, - CFTYPE_PRESSURE = 64, - __CFTYPE_ONLY_ON_DFL = 65536, - __CFTYPE_NOT_ON_DFL = 131072, -}; - -struct css_task_iter { - struct cgroup_subsys *ss; - unsigned int flags; - struct list_head *cset_pos; - struct list_head *cset_head; - struct list_head *tcset_pos; - struct list_head *tcset_head; - struct list_head *task_pos; - struct list_head *cur_tasks_head; - struct css_set *cur_cset; - struct css_set *cur_dcset; - struct task_struct *cur_task; - struct list_head iters_node; -}; - -struct trace_event_raw_sched_kthread_stop { - struct trace_entry ent; - char comm[16]; - pid_t pid; - char __data[0]; -}; - -struct trace_event_raw_sched_kthread_stop_ret { - struct trace_entry ent; - int ret; - char __data[0]; -}; - -struct trace_event_raw_sched_kthread_work_queue_work { - struct trace_entry ent; - void *work; - void *function; - void *worker; - char __data[0]; -}; - -struct trace_event_raw_sched_kthread_work_execute_start { - struct trace_entry ent; - void *work; - void *function; - char __data[0]; -}; - -struct trace_event_raw_sched_kthread_work_execute_end { - struct trace_entry ent; - void *work; - void *function; - char __data[0]; -}; - -struct trace_event_raw_sched_wakeup_template { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - int target_cpu; - char __data[0]; -}; - -struct trace_event_raw_sched_switch { - struct trace_entry ent; - char prev_comm[16]; - pid_t prev_pid; - int prev_prio; - long int prev_state; - char next_comm[16]; - pid_t next_pid; - int next_prio; - char __data[0]; -}; - -struct trace_event_raw_sched_migrate_task { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - int orig_cpu; - int dest_cpu; - char __data[0]; -}; - -struct trace_event_raw_sched_process_template { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - char __data[0]; -}; - -struct trace_event_raw_sched_process_wait { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int prio; - char __data[0]; -}; - -struct trace_event_raw_sched_process_fork { - struct trace_entry ent; - char parent_comm[16]; - pid_t parent_pid; - char child_comm[16]; - pid_t child_pid; - char __data[0]; -}; - -struct trace_event_raw_sched_process_exec { - struct trace_entry ent; - u32 __data_loc_filename; - pid_t pid; - pid_t old_pid; - char __data[0]; -}; - -struct trace_event_raw_sched_stat_template { - struct trace_entry ent; - char comm[16]; - pid_t pid; - u64 delay; - char __data[0]; -}; - -struct trace_event_raw_sched_stat_runtime { - struct trace_entry ent; - char comm[16]; - pid_t pid; - u64 runtime; - u64 vruntime; - char __data[0]; -}; - -struct trace_event_raw_sched_pi_setprio { - struct trace_entry ent; - char comm[16]; - pid_t pid; - int oldprio; - int newprio; - char __data[0]; -}; - -struct trace_event_raw_sched_process_hang { - struct trace_entry ent; - char comm[16]; - pid_t pid; - char __data[0]; -}; - -struct trace_event_raw_sched_move_numa { - struct trace_entry ent; - pid_t pid; - pid_t tgid; - pid_t ngid; - int src_cpu; - int src_nid; - int dst_cpu; - int dst_nid; - char __data[0]; -}; - -struct trace_event_raw_sched_numa_pair_template { - struct trace_entry ent; - pid_t src_pid; - pid_t src_tgid; - pid_t src_ngid; - int src_cpu; - int src_nid; - pid_t dst_pid; - pid_t dst_tgid; - pid_t dst_ngid; - int dst_cpu; - int dst_nid; - char __data[0]; -}; - -struct trace_event_raw_sched_wake_idle_without_ipi { - struct trace_entry ent; - int cpu; - char __data[0]; -}; - -struct trace_event_data_offsets_sched_kthread_stop {}; - -struct trace_event_data_offsets_sched_kthread_stop_ret {}; - -struct trace_event_data_offsets_sched_kthread_work_queue_work {}; - -struct trace_event_data_offsets_sched_kthread_work_execute_start {}; - -struct trace_event_data_offsets_sched_kthread_work_execute_end {}; - -struct trace_event_data_offsets_sched_wakeup_template {}; - -struct trace_event_data_offsets_sched_switch {}; - -struct trace_event_data_offsets_sched_migrate_task {}; - -struct trace_event_data_offsets_sched_process_template {}; - -struct trace_event_data_offsets_sched_process_wait {}; - -struct trace_event_data_offsets_sched_process_fork {}; - -struct trace_event_data_offsets_sched_process_exec { - u32 filename; -}; - -struct trace_event_data_offsets_sched_stat_template {}; - -struct trace_event_data_offsets_sched_stat_runtime {}; - -struct trace_event_data_offsets_sched_pi_setprio {}; - -struct trace_event_data_offsets_sched_process_hang {}; - -struct trace_event_data_offsets_sched_move_numa {}; - -struct trace_event_data_offsets_sched_numa_pair_template {}; - -struct trace_event_data_offsets_sched_wake_idle_without_ipi {}; - -typedef void (*btf_trace_sched_kthread_stop)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_kthread_stop_ret)(void *, int); - -typedef void (*btf_trace_sched_kthread_work_queue_work)(void *, struct kthread_worker *, struct kthread_work *); - -typedef void (*btf_trace_sched_kthread_work_execute_start)(void *, struct kthread_work *); - -typedef void (*btf_trace_sched_kthread_work_execute_end)(void *, struct kthread_work *, kthread_work_func_t); - -typedef void (*btf_trace_sched_waking)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_wakeup)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_wakeup_new)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_switch)(void *, bool, struct task_struct *, struct task_struct *); - -typedef void (*btf_trace_sched_migrate_task)(void *, struct task_struct *, int); - -typedef void (*btf_trace_sched_process_free)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_process_exit)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_wait_task)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_process_wait)(void *, struct pid *); - -typedef void (*btf_trace_sched_process_fork)(void *, struct task_struct *, struct task_struct *); - -typedef void (*btf_trace_sched_process_exec)(void *, struct task_struct *, pid_t, struct linux_binprm *); - -typedef void (*btf_trace_sched_stat_wait)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_sleep)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_iowait)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_blocked)(void *, struct task_struct *, u64); - -typedef void (*btf_trace_sched_stat_runtime)(void *, struct task_struct *, u64, u64); - -typedef void (*btf_trace_sched_pi_setprio)(void *, struct task_struct *, struct task_struct *); - -typedef void (*btf_trace_sched_process_hang)(void *, struct task_struct *); - -typedef void (*btf_trace_sched_move_numa)(void *, struct task_struct *, int, int); - -typedef void (*btf_trace_sched_stick_numa)(void *, struct task_struct *, int, struct task_struct *, int); - -typedef void (*btf_trace_sched_swap_numa)(void *, struct task_struct *, int, struct task_struct *, int); - -typedef void (*btf_trace_sched_wake_idle_without_ipi)(void *, int); - -typedef void (*btf_trace_pelt_cfs_tp)(void *, struct cfs_rq *); - -typedef void (*btf_trace_pelt_rt_tp)(void *, struct rq *); - -struct uclamp_bucket { - long unsigned int value: 11; - long unsigned int tasks: 53; -}; - -struct uclamp_rq { - unsigned int value; - struct uclamp_bucket bucket[5]; -}; - -struct rt_prio_array { - long unsigned int bitmap[2]; - struct list_head queue[100]; -}; - -struct rt_rq { - struct rt_prio_array active; - unsigned int rt_nr_running; - unsigned int rr_nr_running; - struct { - int curr; - int next; - } highest_prio; - unsigned int rt_nr_migratory; - unsigned int rt_nr_total; - int overloaded; - struct plist_head pushable_tasks; - int rt_queued; - int rt_throttled; - u64 rt_time; - u64 rt_runtime; - raw_spinlock_t rt_runtime_lock; -}; - -struct dl_rq { - struct rb_root_cached root; - unsigned int dl_nr_running; - struct { - u64 curr; - u64 next; - } earliest_dl; - unsigned int dl_nr_migratory; - int overloaded; - struct rb_root_cached pushable_dl_tasks_root; - u64 running_bw; - u64 this_bw; - u64 extra_bw; - u64 bw_ratio; -}; - -struct cpu_stop_done; - -struct cpu_stop_work { - struct list_head list; - cpu_stop_fn_t fn; - long unsigned int caller; - void *arg; - struct cpu_stop_done *done; -}; - -struct cpuidle_state; - -struct rq { - raw_spinlock_t __lock; - unsigned int nr_running; - unsigned int nr_numa_running; - unsigned int nr_preferred_running; - unsigned int numa_migrate_on; - long unsigned int last_blocked_load_update_tick; - unsigned int has_blocked_load; - long: 32; - long: 64; - long: 64; - long: 64; - call_single_data_t nohz_csd; - unsigned int nohz_tick_stopped; - atomic_t nohz_flags; - unsigned int ttwu_pending; - u64 nr_switches; - long: 64; - struct uclamp_rq uclamp[2]; - unsigned int uclamp_flags; - long: 32; - long: 64; - long: 64; - long: 64; - struct cfs_rq cfs; - struct rt_rq rt; - struct dl_rq dl; - struct list_head leaf_cfs_rq_list; - struct list_head *tmp_alone_branch; - unsigned int nr_uninterruptible; - struct task_struct *curr; - struct task_struct *idle; - struct task_struct *stop; - long unsigned int next_balance; - struct mm_struct *prev_mm; - unsigned int clock_update_flags; - u64 clock; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u64 clock_task; - u64 clock_pelt; - long unsigned int lost_idle_time; - atomic_t nr_iowait; - u64 last_seen_need_resched_ns; - int ticks_without_resched; - int membarrier_state; - struct root_domain *rd; - struct sched_domain *sd; - long unsigned int cpu_capacity; - long unsigned int cpu_capacity_orig; - struct callback_head *balance_callback; - unsigned char nohz_idle_balance; - unsigned char idle_balance; - long unsigned int misfit_task_load; - int active_balance; - int push_cpu; - struct cpu_stop_work active_balance_work; - int cpu; - int online; - struct list_head cfs_tasks; - long: 64; - struct sched_avg avg_rt; - struct sched_avg avg_dl; - struct sched_avg avg_irq; - u64 idle_stamp; - u64 avg_idle; - long unsigned int wake_stamp; - u64 wake_avg_idle; - u64 max_idle_balance_cost; - struct rcuwait hotplug_wait; - u64 prev_irq_time; - u64 prev_steal_time; - u64 prev_steal_time_rq; - long unsigned int calc_load_update; - long int calc_load_active; - long: 64; - call_single_data_t hrtick_csd; - struct hrtimer hrtick_timer; - ktime_t hrtick_time; - struct sched_info rq_sched_info; - long long unsigned int rq_cpu_time; - unsigned int yld_count; - unsigned int sched_count; - unsigned int sched_goidle; - unsigned int ttwu_count; - unsigned int ttwu_local; - struct cpuidle_state *idle_state; - unsigned int nr_pinned; - unsigned int push_busy; - struct cpu_stop_work push_work; - struct rq *core; - struct task_struct *core_pick; - unsigned int core_enabled; - unsigned int core_sched_seq; - struct rb_root core_tree; - unsigned int core_task_seq; - unsigned int core_pick_seq; - long unsigned int core_cookie; - unsigned char core_forceidle; - unsigned int core_forceidle_seq; -}; - -typedef void (*btf_trace_pelt_dl_tp)(void *, struct rq *); - -typedef void (*btf_trace_pelt_thermal_tp)(void *, struct rq *); - -typedef void (*btf_trace_pelt_irq_tp)(void *, struct rq *); - -typedef void (*btf_trace_pelt_se_tp)(void *, struct sched_entity *); - -typedef void (*btf_trace_sched_cpu_capacity_tp)(void *, struct rq *); - -typedef void (*btf_trace_sched_overutilized_tp)(void *, struct root_domain *, bool); - -typedef void (*btf_trace_sched_util_est_cfs_tp)(void *, struct cfs_rq *); - -typedef void (*btf_trace_sched_util_est_se_tp)(void *, struct sched_entity *); - -typedef void (*btf_trace_sched_update_nr_running_tp)(void *, struct rq *, int); - -struct wake_q_head { - struct wake_q_node *first; - struct wake_q_node **lastp; -}; - -struct sched_attr { - __u32 size; - __u32 sched_policy; - __u64 sched_flags; - __s32 sched_nice; - __u32 sched_priority; - __u64 sched_runtime; - __u64 sched_deadline; - __u64 sched_period; - __u32 sched_util_min; - __u32 sched_util_max; -}; - -struct cpuidle_state_usage { - long long unsigned int disable; - long long unsigned int usage; - u64 time_ns; - long long unsigned int above; - long long unsigned int below; - long long unsigned int rejected; - long long unsigned int s2idle_usage; - long long unsigned int s2idle_time; -}; - -struct cpuidle_device; - -struct cpuidle_driver; - -struct cpuidle_state { - char name[16]; - char desc[32]; - s64 exit_latency_ns; - s64 target_residency_ns; - unsigned int flags; - unsigned int exit_latency; - int power_usage; - unsigned int target_residency; - int (*enter)(struct cpuidle_device *, struct cpuidle_driver *, int); - int (*enter_dead)(struct cpuidle_device *, int); - int (*enter_s2idle)(struct cpuidle_device *, struct cpuidle_driver *, int); -}; - -struct cpuidle_driver_kobj; - -struct cpuidle_state_kobj; - -struct cpuidle_device_kobj; - -struct cpuidle_device { - unsigned int registered: 1; - unsigned int enabled: 1; - unsigned int poll_time_limit: 1; - unsigned int cpu; - ktime_t next_hrtimer; - int last_state_idx; - u64 last_residency_ns; - u64 poll_limit_ns; - u64 forced_idle_latency_limit_ns; - struct cpuidle_state_usage states_usage[10]; - struct cpuidle_state_kobj *kobjs[10]; - struct cpuidle_driver_kobj *kobj_driver; - struct cpuidle_device_kobj *kobj_dev; - struct list_head device_list; -}; - -struct cpuidle_driver { - const char *name; - struct module *owner; - unsigned int bctimer: 1; - struct cpuidle_state states[10]; - int state_count; - int safe_state_index; - struct cpumask *cpumask; - const char *governor; -}; - -struct cpudl_item { - u64 dl; - int cpu; - int idx; -}; - -struct rt_bandwidth { - raw_spinlock_t rt_runtime_lock; - ktime_t rt_period; - u64 rt_runtime; - struct hrtimer rt_period_timer; - unsigned int rt_period_active; -}; - -struct dl_bandwidth { - raw_spinlock_t dl_runtime_lock; - u64 dl_runtime; - u64 dl_period; -}; - -typedef int (*tg_visitor)(struct task_group *, void *); - -struct perf_domain { - struct em_perf_domain *em_pd; - struct perf_domain *next; - struct callback_head rcu; -}; - -struct rq_flags { - long unsigned int flags; - struct pin_cookie cookie; - unsigned int clock_update_flags; -}; - -enum { - __SCHED_FEAT_GENTLE_FAIR_SLEEPERS = 0, - __SCHED_FEAT_START_DEBIT = 1, - __SCHED_FEAT_NEXT_BUDDY = 2, - __SCHED_FEAT_LAST_BUDDY = 3, - __SCHED_FEAT_CACHE_HOT_BUDDY = 4, - __SCHED_FEAT_WAKEUP_PREEMPTION = 5, - __SCHED_FEAT_HRTICK = 6, - __SCHED_FEAT_HRTICK_DL = 7, - __SCHED_FEAT_DOUBLE_TICK = 8, - __SCHED_FEAT_NONTASK_CAPACITY = 9, - __SCHED_FEAT_TTWU_QUEUE = 10, - __SCHED_FEAT_SIS_PROP = 11, - __SCHED_FEAT_WARN_DOUBLE_CLOCK = 12, - __SCHED_FEAT_RT_PUSH_IPI = 13, - __SCHED_FEAT_RT_RUNTIME_SHARE = 14, - __SCHED_FEAT_LB_MIN = 15, - __SCHED_FEAT_ATTACH_AGE_LOAD = 16, - __SCHED_FEAT_WA_IDLE = 17, - __SCHED_FEAT_WA_WEIGHT = 18, - __SCHED_FEAT_WA_BIAS = 19, - __SCHED_FEAT_UTIL_EST = 20, - __SCHED_FEAT_UTIL_EST_FASTUP = 21, - __SCHED_FEAT_LATENCY_WARN = 22, - __SCHED_FEAT_ALT_PERIOD = 23, - __SCHED_FEAT_BASE_SLICE = 24, - __SCHED_FEAT_NR = 25, -}; - -struct irqtime { - u64 total; - u64 tick_delta; - u64 irq_start_time; - struct u64_stats_sync sync; -}; - -enum cpu_util_type { - FREQUENCY_UTIL = 0, - ENERGY_UTIL = 1, -}; - -struct set_affinity_pending; - -struct migration_arg { - struct task_struct *task; - int dest_cpu; - struct set_affinity_pending *pending; -}; - -struct set_affinity_pending { - refcount_t refs; - unsigned int stop_pending; - struct completion done; - struct cpu_stop_work stop_work; - struct migration_arg arg; -}; - -struct migration_swap_arg { - struct task_struct *src_task; - struct task_struct *dst_task; - int src_cpu; - int dst_cpu; -}; - -enum { - preempt_dynamic_none = 0, - preempt_dynamic_voluntary = 1, - preempt_dynamic_full = 2, -}; - -struct uclamp_request { - s64 percent; - u64 util; - int ret; -}; - -struct cfs_schedulable_data { - struct task_group *tg; - u64 period; - u64 quota; -}; - -enum { - cpuset = 0, - possible = 1, - fail = 2, -}; - -enum tick_dep_bits { - TICK_DEP_BIT_POSIX_TIMER = 0, - TICK_DEP_BIT_PERF_EVENTS = 1, - TICK_DEP_BIT_SCHED = 2, - TICK_DEP_BIT_CLOCK_UNSTABLE = 3, - TICK_DEP_BIT_RCU = 4, - TICK_DEP_BIT_RCU_EXP = 5, -}; - -struct sched_clock_data { - u64 tick_raw; - u64 tick_gtod; - u64 clock; -}; - -enum s2idle_states { - S2IDLE_STATE_NONE = 0, - S2IDLE_STATE_ENTER = 1, - S2IDLE_STATE_WAKE = 2, -}; - -struct idle_timer { - struct hrtimer timer; - int done; -}; - -struct numa_group { - refcount_t refcount; - spinlock_t lock; - int nr_tasks; - pid_t gid; - int active_nodes; - struct callback_head rcu; - long unsigned int total_faults; - long unsigned int max_faults_cpu; - long unsigned int *faults_cpu; - long unsigned int faults[0]; -}; - -struct update_util_data { - void (*func)(struct update_util_data *, u64, unsigned int); -}; - -enum sched_tunable_scaling { - SCHED_TUNABLESCALING_NONE = 0, - SCHED_TUNABLESCALING_LOG = 1, - SCHED_TUNABLESCALING_LINEAR = 2, - SCHED_TUNABLESCALING_END = 3, -}; - -enum numa_topology_type { - NUMA_DIRECT = 0, - NUMA_GLUELESS_MESH = 1, - NUMA_BACKPLANE = 2, -}; - -enum numa_faults_stats { - NUMA_MEM = 0, - NUMA_CPU = 1, - NUMA_MEMBUF = 2, - NUMA_CPUBUF = 3, -}; - -enum numa_type { - node_has_spare = 0, - node_fully_busy = 1, - node_overloaded = 2, -}; - -struct numa_stats { - long unsigned int load; - long unsigned int runnable; - long unsigned int util; - long unsigned int compute_capacity; - unsigned int nr_running; - unsigned int weight; - enum numa_type node_type; - int idle_cpu; -}; - -struct task_numa_env { - struct task_struct *p; - int src_cpu; - int src_nid; - int dst_cpu; - int dst_nid; - struct numa_stats src_stats; - struct numa_stats dst_stats; - int imbalance_pct; - int dist; - struct task_struct *best_task; - long int best_imp; - int best_cpu; -}; - -enum fbq_type { - regular = 0, - remote = 1, - all = 2, -}; - -enum group_type { - group_has_spare = 0, - group_fully_busy = 1, - group_misfit_task = 2, - group_asym_packing = 3, - group_imbalanced = 4, - group_overloaded = 5, -}; - -enum migration_type { - migrate_load = 0, - migrate_util = 1, - migrate_task = 2, - migrate_misfit = 3, -}; - -struct lb_env { - struct sched_domain *sd; - struct rq *src_rq; - int src_cpu; - int dst_cpu; - struct rq *dst_rq; - struct cpumask *dst_grpmask; - int new_dst_cpu; - enum cpu_idle_type idle; - long int imbalance; - struct cpumask *cpus; - unsigned int flags; - unsigned int loop; - unsigned int loop_break; - unsigned int loop_max; - enum fbq_type fbq_type; - enum migration_type migration_type; - struct list_head tasks; -}; - -struct sg_lb_stats { - long unsigned int avg_load; - long unsigned int group_load; - long unsigned int group_capacity; - long unsigned int group_util; - long unsigned int group_runnable; - unsigned int sum_nr_running; - unsigned int sum_h_nr_running; - unsigned int idle_cpus; - unsigned int group_weight; - enum group_type group_type; - unsigned int group_asym_packing; - long unsigned int group_misfit_task_load; - unsigned int nr_numa_running; - unsigned int nr_preferred_running; -}; - -struct sd_lb_stats { - struct sched_group *busiest; - struct sched_group *local; - long unsigned int total_load; - long unsigned int total_capacity; - long unsigned int avg_load; - unsigned int prefer_sibling; - struct sg_lb_stats busiest_stat; - struct sg_lb_stats local_stat; -}; - -typedef struct rt_rq *rt_rq_iter_t; - -struct sd_flag_debug { - unsigned int meta_flags; - char *name; -}; - -struct s_data { - struct sched_domain **sd; - struct root_domain *rd; -}; - -enum s_alloc { - sa_rootdomain = 0, - sa_sd = 1, - sa_sd_storage = 2, - sa_none = 3, -}; - -struct asym_cap_data { - struct list_head link; - long unsigned int capacity; - long unsigned int cpus[0]; -}; - -enum cpuacct_stat_index { - CPUACCT_STAT_USER = 0, - CPUACCT_STAT_SYSTEM = 1, - CPUACCT_STAT_NSTATS = 2, -}; - -struct cpuacct_usage { - u64 usages[2]; -}; - -struct cpuacct { - struct cgroup_subsys_state css; - struct cpuacct_usage *cpuusage; - struct kernel_cpustat *cpustat; -}; - -struct gov_attr_set { - struct kobject kobj; - struct list_head policy_list; - struct mutex update_lock; - int usage_count; -}; - -struct governor_attr { - struct attribute attr; - ssize_t (*show)(struct gov_attr_set *, char *); - ssize_t (*store)(struct gov_attr_set *, const char *, size_t); -}; - -struct sugov_tunables { - struct gov_attr_set attr_set; - unsigned int rate_limit_us; -}; - -struct sugov_policy { - struct cpufreq_policy *policy; - struct sugov_tunables *tunables; - struct list_head tunables_hook; - raw_spinlock_t update_lock; - u64 last_freq_update_time; - s64 freq_update_delay_ns; - unsigned int next_freq; - unsigned int cached_raw_freq; - struct irq_work irq_work; - struct kthread_work work; - struct mutex work_lock; - struct kthread_worker worker; - struct task_struct *thread; - bool work_in_progress; - bool limits_changed; - bool need_freq_update; -}; - -struct sugov_cpu { - struct update_util_data update_util; - struct sugov_policy *sg_policy; - unsigned int cpu; - bool iowait_boost_pending; - unsigned int iowait_boost; - u64 last_update; - long unsigned int util; - long unsigned int bw_dl; - long unsigned int max; - long unsigned int saved_idle_calls; -}; - -enum { - MEMBARRIER_FLAG_SYNC_CORE = 1, - MEMBARRIER_FLAG_RSEQ = 2, -}; - -enum membarrier_cmd { - MEMBARRIER_CMD_QUERY = 0, - MEMBARRIER_CMD_GLOBAL = 1, - MEMBARRIER_CMD_GLOBAL_EXPEDITED = 2, - MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = 4, - MEMBARRIER_CMD_PRIVATE_EXPEDITED = 8, - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = 16, - MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = 32, - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = 64, - MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ = 128, - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ = 256, - MEMBARRIER_CMD_SHARED = 1, -}; - -enum membarrier_cmd_flag { - MEMBARRIER_CMD_FLAG_CPU = 1, -}; - -enum psi_res { - PSI_IO = 0, - PSI_MEM = 1, - PSI_CPU = 2, - NR_PSI_RESOURCES = 3, -}; - -struct psi_window { - u64 size; - u64 start_time; - u64 start_value; - u64 prev_growth; -}; - -struct psi_trigger { - enum psi_states state; - u64 threshold; - struct list_head node; - struct psi_group *group; - wait_queue_head_t event_wait; - int event; - struct psi_window win; - u64 last_event_time; - struct kref refcount; -}; - -struct sched_core_cookie { - refcount_t refcnt; -}; - -struct ww_acquire_ctx; - -struct ww_mutex { - struct mutex base; - struct ww_acquire_ctx *ctx; -}; - -struct ww_acquire_ctx { - struct task_struct *task; - long unsigned int stamp; - unsigned int acquired; - short unsigned int wounded; - short unsigned int is_wait_die; -}; - -struct mutex_waiter { - struct list_head list; - struct task_struct *task; - struct ww_acquire_ctx *ww_ctx; -}; - -struct semaphore { - raw_spinlock_t lock; - unsigned int count; - struct list_head wait_list; -}; - -struct semaphore_waiter { - struct list_head list; - struct task_struct *task; - bool up; -}; - -enum lock_events { - LOCKEVENT_pv_hash_hops = 0, - LOCKEVENT_pv_kick_unlock = 1, - LOCKEVENT_pv_kick_wake = 2, - LOCKEVENT_pv_latency_kick = 3, - LOCKEVENT_pv_latency_wake = 4, - LOCKEVENT_pv_lock_stealing = 5, - LOCKEVENT_pv_spurious_wakeup = 6, - LOCKEVENT_pv_wait_again = 7, - LOCKEVENT_pv_wait_early = 8, - LOCKEVENT_pv_wait_head = 9, - LOCKEVENT_pv_wait_node = 10, - LOCKEVENT_lock_pending = 11, - LOCKEVENT_lock_slowpath = 12, - LOCKEVENT_lock_use_node2 = 13, - LOCKEVENT_lock_use_node3 = 14, - LOCKEVENT_lock_use_node4 = 15, - LOCKEVENT_lock_no_node = 16, - LOCKEVENT_rwsem_sleep_reader = 17, - LOCKEVENT_rwsem_sleep_writer = 18, - LOCKEVENT_rwsem_wake_reader = 19, - LOCKEVENT_rwsem_wake_writer = 20, - LOCKEVENT_rwsem_opt_lock = 21, - LOCKEVENT_rwsem_opt_fail = 22, - LOCKEVENT_rwsem_opt_nospin = 23, - LOCKEVENT_rwsem_rlock = 24, - LOCKEVENT_rwsem_rlock_steal = 25, - LOCKEVENT_rwsem_rlock_fast = 26, - LOCKEVENT_rwsem_rlock_fail = 27, - LOCKEVENT_rwsem_rlock_handoff = 28, - LOCKEVENT_rwsem_wlock = 29, - LOCKEVENT_rwsem_wlock_fail = 30, - LOCKEVENT_rwsem_wlock_handoff = 31, - lockevent_num = 32, - LOCKEVENT_reset_cnts = 32, -}; - -enum rwsem_waiter_type { - RWSEM_WAITING_FOR_WRITE = 0, - RWSEM_WAITING_FOR_READ = 1, -}; - -struct rwsem_waiter { - struct list_head list; - struct task_struct *task; - enum rwsem_waiter_type type; - long unsigned int timeout; -}; - -enum rwsem_wake_type { - RWSEM_WAKE_ANY = 0, - RWSEM_WAKE_READERS = 1, - RWSEM_WAKE_READ_OWNED = 2, -}; - -enum writer_wait_state { - WRITER_NOT_FIRST = 0, - WRITER_FIRST = 1, - WRITER_HANDOFF = 2, -}; - -enum owner_state { - OWNER_NULL = 1, - OWNER_WRITER = 2, - OWNER_READER = 4, - OWNER_NONSPINNABLE = 8, -}; - -struct optimistic_spin_node { - struct optimistic_spin_node *next; - struct optimistic_spin_node *prev; - int locked; - int cpu; -}; - -struct mcs_spinlock { - struct mcs_spinlock *next; - int locked; - int count; -}; - -struct qnode { - struct mcs_spinlock mcs; - long int reserved[2]; -}; - -enum vcpu_state { - vcpu_running = 0, - vcpu_halted = 1, - vcpu_hashed = 2, -}; - -struct pv_node { - struct mcs_spinlock mcs; - int cpu; - u8 state; -}; - -struct pv_hash_entry { - struct qspinlock *lock; - struct pv_node *node; -}; - -struct hrtimer_sleeper { - struct hrtimer timer; - struct task_struct *task; -}; - -struct rt_mutex; - -struct rt_mutex_waiter { - struct rb_node tree_entry; - struct rb_node pi_tree_entry; - struct task_struct *task; - struct rt_mutex *lock; - int prio; - u64 deadline; -}; - -struct rt_mutex { - raw_spinlock_t wait_lock; - struct rb_root_cached waiters; - struct task_struct *owner; -}; - -enum rtmutex_chainwalk { - RT_MUTEX_MIN_CHAINWALK = 0, - RT_MUTEX_FULL_CHAINWALK = 1, -}; - -enum pm_qos_req_action { - PM_QOS_ADD_REQ = 0, - PM_QOS_UPDATE_REQ = 1, - PM_QOS_REMOVE_REQ = 2, -}; - -typedef int suspend_state_t; - -enum suspend_stat_step { - SUSPEND_FREEZE = 1, - SUSPEND_PREPARE = 2, - SUSPEND_SUSPEND = 3, - SUSPEND_SUSPEND_LATE = 4, - SUSPEND_SUSPEND_NOIRQ = 5, - SUSPEND_RESUME_NOIRQ = 6, - SUSPEND_RESUME_EARLY = 7, - SUSPEND_RESUME = 8, -}; - -struct suspend_stats { - int success; - int fail; - int failed_freeze; - int failed_prepare; - int failed_suspend; - int failed_suspend_late; - int failed_suspend_noirq; - int failed_resume; - int failed_resume_early; - int failed_resume_noirq; - int last_failed_dev; - char failed_devs[80]; - int last_failed_errno; - int errno[2]; - int last_failed_step; - enum suspend_stat_step failed_steps[2]; -}; - -enum { - TEST_NONE = 0, - TEST_CORE = 1, - TEST_CPUS = 2, - TEST_PLATFORM = 3, - TEST_DEVICES = 4, - TEST_FREEZER = 5, - __TEST_AFTER_LAST = 6, -}; - -struct pm_vt_switch { - struct list_head head; - struct device *dev; - bool required; -}; - -struct platform_suspend_ops { - int (*valid)(suspend_state_t); - int (*begin)(suspend_state_t); - int (*prepare)(); - int (*prepare_late)(); - int (*enter)(suspend_state_t); - void (*wake)(); - void (*finish)(); - bool (*suspend_again)(); - void (*end)(); - void (*recover)(); -}; - -struct platform_s2idle_ops { - int (*begin)(); - int (*prepare)(); - int (*prepare_late)(); - bool (*wake)(); - void (*restore_early)(); - void (*restore)(); - void (*end)(); -}; - -struct platform_hibernation_ops { - int (*begin)(pm_message_t); - void (*end)(); - int (*pre_snapshot)(); - void (*finish)(); - int (*prepare)(); - int (*enter)(); - void (*leave)(); - int (*pre_restore)(); - void (*restore_cleanup)(); - void (*recover)(); -}; - -enum { - HIBERNATION_INVALID = 0, - HIBERNATION_PLATFORM = 1, - HIBERNATION_SHUTDOWN = 2, - HIBERNATION_REBOOT = 3, - HIBERNATION_SUSPEND = 4, - HIBERNATION_TEST_RESUME = 5, - __HIBERNATION_AFTER_LAST = 6, -}; - -struct pbe { - void *address; - void *orig_address; - struct pbe *next; -}; - -struct swsusp_info { - struct new_utsname uts; - u32 version_code; - long unsigned int num_physpages; - int cpus; - long unsigned int image_pages; - long unsigned int pages; - long unsigned int size; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct snapshot_handle { - unsigned int cur; - void *buffer; - int sync_read; -}; - -struct linked_page { - struct linked_page *next; - char data[4088]; -}; - -struct chain_allocator { - struct linked_page *chain; - unsigned int used_space; - gfp_t gfp_mask; - int safe_needed; -}; - -struct rtree_node { - struct list_head list; - long unsigned int *data; -}; - -struct mem_zone_bm_rtree { - struct list_head list; - struct list_head nodes; - struct list_head leaves; - long unsigned int start_pfn; - long unsigned int end_pfn; - struct rtree_node *rtree; - int levels; - unsigned int blocks; -}; - -struct bm_position { - struct mem_zone_bm_rtree *zone; - struct rtree_node *node; - long unsigned int node_pfn; - int node_bit; -}; - -struct memory_bitmap { - struct list_head zones; - struct linked_page *p_list; - struct bm_position cur; -}; - -struct mem_extent { - struct list_head hook; - long unsigned int start; - long unsigned int end; -}; - -struct nosave_region { - struct list_head list; - long unsigned int start_pfn; - long unsigned int end_pfn; -}; - -typedef struct { - long unsigned int val; -} swp_entry_t; - -enum { - BIO_NO_PAGE_REF = 0, - BIO_CLONED = 1, - BIO_BOUNCED = 2, - BIO_WORKINGSET = 3, - BIO_QUIET = 4, - BIO_CHAIN = 5, - BIO_REFFED = 6, - BIO_THROTTLED = 7, - BIO_TRACE_COMPLETION = 8, - BIO_CGROUP_ACCT = 9, - BIO_TRACKED = 10, - BIO_REMAPPED = 11, - BIO_ZONE_WRITE_LOCKED = 12, - BIO_FLAG_LAST = 13, -}; - -enum req_opf { - REQ_OP_READ = 0, - REQ_OP_WRITE = 1, - REQ_OP_FLUSH = 2, - REQ_OP_DISCARD = 3, - REQ_OP_SECURE_ERASE = 5, - REQ_OP_WRITE_SAME = 7, - REQ_OP_WRITE_ZEROES = 9, - REQ_OP_ZONE_OPEN = 10, - REQ_OP_ZONE_CLOSE = 11, - REQ_OP_ZONE_FINISH = 12, - REQ_OP_ZONE_APPEND = 13, - REQ_OP_ZONE_RESET = 15, - REQ_OP_ZONE_RESET_ALL = 17, - REQ_OP_DRV_IN = 34, - REQ_OP_DRV_OUT = 35, - REQ_OP_LAST = 36, -}; - -enum req_flag_bits { - __REQ_FAILFAST_DEV = 8, - __REQ_FAILFAST_TRANSPORT = 9, - __REQ_FAILFAST_DRIVER = 10, - __REQ_SYNC = 11, - __REQ_META = 12, - __REQ_PRIO = 13, - __REQ_NOMERGE = 14, - __REQ_IDLE = 15, - __REQ_INTEGRITY = 16, - __REQ_FUA = 17, - __REQ_PREFLUSH = 18, - __REQ_RAHEAD = 19, - __REQ_BACKGROUND = 20, - __REQ_NOWAIT = 21, - __REQ_CGROUP_PUNT = 22, - __REQ_NOUNMAP = 23, - __REQ_HIPRI = 24, - __REQ_DRV = 25, - __REQ_SWAP = 26, - __REQ_NR_BITS = 27, -}; - -struct swap_map_page { - sector_t entries[511]; - sector_t next_swap; -}; - -struct swap_map_page_list { - struct swap_map_page *map; - struct swap_map_page_list *next; -}; - -struct swap_map_handle { - struct swap_map_page *cur; - struct swap_map_page_list *maps; - sector_t cur_swap; - sector_t first_sector; - unsigned int k; - long unsigned int reqd_free_pages; - u32 crc32; -}; - -struct swsusp_header { - char reserved[4060]; - u32 crc32; - sector_t image; - unsigned int flags; - char orig_sig[10]; - char sig[10]; -}; - -struct swsusp_extent { - struct rb_node node; - long unsigned int start; - long unsigned int end; -}; - -struct hib_bio_batch { - atomic_t count; - wait_queue_head_t wait; - blk_status_t error; - struct blk_plug plug; -}; - -struct crc_data { - struct task_struct *thr; - atomic_t ready; - atomic_t stop; - unsigned int run_threads; - wait_queue_head_t go; - wait_queue_head_t done; - u32 *crc32; - size_t *unc_len[3]; - unsigned char *unc[3]; -}; - -struct cmp_data { - struct task_struct *thr; - atomic_t ready; - atomic_t stop; - int ret; - wait_queue_head_t go; - wait_queue_head_t done; - size_t unc_len; - size_t cmp_len; - unsigned char unc[131072]; - unsigned char cmp[143360]; - unsigned char wrk[16384]; -}; - -struct dec_data { - struct task_struct *thr; - atomic_t ready; - atomic_t stop; - int ret; - wait_queue_head_t go; - wait_queue_head_t done; - size_t unc_len; - size_t cmp_len; - unsigned char unc[131072]; - unsigned char cmp[143360]; -}; - -typedef s64 compat_loff_t; - -struct resume_swap_area { - __kernel_loff_t offset; - __u32 dev; -} __attribute__((packed)); - -struct snapshot_data { - struct snapshot_handle handle; - int swap; - int mode; - bool frozen; - bool ready; - bool platform_support; - bool free_bitmaps; - dev_t dev; -}; - -struct compat_resume_swap_area { - compat_loff_t offset; - u32 dev; -} __attribute__((packed)); - -struct sysrq_key_op { - void (* const handler)(int); - const char * const help_msg; - const char * const action_msg; - const int enable_mask; -}; - -struct em_data_callback { - int (*active_power)(long unsigned int *, long unsigned int *, struct device *); -}; - -struct dev_printk_info { - char subsystem[16]; - char device[48]; -}; - -struct kmsg_dump_iter { - u64 cur_seq; - u64 next_seq; -}; - -struct kmsg_dumper { - struct list_head list; - void (*dump)(struct kmsg_dumper *, enum kmsg_dump_reason); - enum kmsg_dump_reason max_reason; - bool registered; -}; - -struct trace_event_raw_console { - struct trace_entry ent; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_data_offsets_console { - u32 msg; -}; - -typedef void (*btf_trace_console)(void *, const char *, size_t); - -struct printk_info { - u64 seq; - u64 ts_nsec; - u16 text_len; - u8 facility; - u8 flags: 5; - u8 level: 3; - u32 caller_id; - struct dev_printk_info dev_info; -}; - -struct printk_record { - struct printk_info *info; - char *text_buf; - unsigned int text_buf_size; -}; - -struct prb_data_blk_lpos { - long unsigned int begin; - long unsigned int next; -}; - -struct prb_desc { - atomic_long_t state_var; - struct prb_data_blk_lpos text_blk_lpos; -}; - -struct prb_data_ring { - unsigned int size_bits; - char *data; - atomic_long_t head_lpos; - atomic_long_t tail_lpos; -}; - -struct prb_desc_ring { - unsigned int count_bits; - struct prb_desc *descs; - struct printk_info *infos; - atomic_long_t head_id; - atomic_long_t tail_id; -}; - -struct printk_ringbuffer { - struct prb_desc_ring desc_ring; - struct prb_data_ring text_data_ring; - atomic_long_t fail; -}; - -struct prb_reserved_entry { - struct printk_ringbuffer *rb; - long unsigned int irqflags; - long unsigned int id; - unsigned int text_space; -}; - -enum desc_state { - desc_miss = 4294967295, - desc_reserved = 0, - desc_committed = 1, - desc_finalized = 2, - desc_reusable = 3, -}; - -struct console_cmdline { - char name[16]; - int index; - bool user_specified; - char *options; - char *brl_options; -}; - -enum devkmsg_log_bits { - __DEVKMSG_LOG_BIT_ON = 0, - __DEVKMSG_LOG_BIT_OFF = 1, - __DEVKMSG_LOG_BIT_LOCK = 2, -}; - -enum devkmsg_log_masks { - DEVKMSG_LOG_MASK_ON = 1, - DEVKMSG_LOG_MASK_OFF = 2, - DEVKMSG_LOG_MASK_LOCK = 4, -}; - -enum con_msg_format_flags { - MSG_FORMAT_DEFAULT = 0, - MSG_FORMAT_SYSLOG = 1, -}; - -enum log_flags { - LOG_NEWLINE = 2, - LOG_CONT = 8, -}; - -struct latched_seq { - seqcount_latch_t latch; - u64 val[2]; -}; - -struct devkmsg_user { - atomic64_t seq; - struct ratelimit_state rs; - struct mutex lock; - char buf[8192]; - struct printk_info info; - char text_buf[8192]; - struct printk_record record; -}; - -struct printk_safe_seq_buf { - atomic_t len; - atomic_t message_lost; - struct irq_work work; - unsigned char buffer[8160]; -}; - -struct dev_printk_info___2; - -struct prb_data_block { - long unsigned int id; - char data[0]; -}; - -enum { - IRQS_AUTODETECT = 1, - IRQS_SPURIOUS_DISABLED = 2, - IRQS_POLL_INPROGRESS = 8, - IRQS_ONESHOT = 32, - IRQS_REPLAY = 64, - IRQS_WAITING = 128, - IRQS_PENDING = 512, - IRQS_SUSPENDED = 2048, - IRQS_TIMINGS = 4096, - IRQS_NMI = 8192, -}; - -enum { - _IRQ_DEFAULT_INIT_FLAGS = 0, - _IRQ_PER_CPU = 512, - _IRQ_LEVEL = 256, - _IRQ_NOPROBE = 1024, - _IRQ_NOREQUEST = 2048, - _IRQ_NOTHREAD = 65536, - _IRQ_NOAUTOEN = 4096, - _IRQ_MOVE_PCNTXT = 16384, - _IRQ_NO_BALANCING = 8192, - _IRQ_NESTED_THREAD = 32768, - _IRQ_PER_CPU_DEVID = 131072, - _IRQ_IS_POLLED = 262144, - _IRQ_DISABLE_UNLAZY = 524288, - _IRQ_HIDDEN = 1048576, - _IRQ_NO_DEBUG = 2097152, - _IRQF_MODIFY_MASK = 2096911, -}; - -enum { - IRQTF_RUNTHREAD = 0, - IRQTF_WARNED = 1, - IRQTF_AFFINITY = 2, - IRQTF_FORCED_THREAD = 3, -}; - -enum { - IRQC_IS_HARDIRQ = 0, - IRQC_IS_NESTED = 1, -}; - -enum { - IRQ_STARTUP_NORMAL = 0, - IRQ_STARTUP_MANAGED = 1, - IRQ_STARTUP_ABORT = 2, -}; - -struct irq_devres { - unsigned int irq; - void *dev_id; -}; - -struct irq_desc_devres { - unsigned int from; - unsigned int cnt; -}; - -struct irq_generic_chip_devres { - struct irq_chip_generic *gc; - u32 msk; - unsigned int clr; - unsigned int set; -}; - -struct irqchip_fwid { - struct fwnode_handle fwnode; - unsigned int type; - char *name; - phys_addr_t *pa; -}; - -struct irq_sim_work_ctx { - struct irq_work work; - int irq_base; - unsigned int irq_count; - long unsigned int *pending; - struct irq_domain *domain; -}; - -struct irq_sim_irq_ctx { - int irqnum; - bool enabled; - struct irq_sim_work_ctx *work_ctx; -}; - -enum { - AFFINITY = 0, - AFFINITY_LIST = 1, - EFFECTIVE = 2, - EFFECTIVE_LIST = 3, -}; - -struct irq_affinity { - unsigned int pre_vectors; - unsigned int post_vectors; - unsigned int nr_sets; - unsigned int set_size[4]; - void (*calc_sets)(struct irq_affinity *, unsigned int); - void *priv; -}; - -struct node_vectors { - unsigned int id; - union { - unsigned int nvectors; - unsigned int ncpus; - }; -}; - -struct cpumap { - unsigned int available; - unsigned int allocated; - unsigned int managed; - unsigned int managed_allocated; - bool initialized; - bool online; - long unsigned int alloc_map[4]; - long unsigned int managed_map[4]; -}; - -struct irq_matrix___2 { - unsigned int matrix_bits; - unsigned int alloc_start; - unsigned int alloc_end; - unsigned int alloc_size; - unsigned int global_available; - unsigned int global_reserved; - unsigned int systembits_inalloc; - unsigned int total_allocated; - unsigned int online_maps; - struct cpumap *maps; - long unsigned int scratch_map[4]; - long unsigned int system_map[4]; -}; - -struct trace_event_raw_irq_matrix_global { - struct trace_entry ent; - unsigned int online_maps; - unsigned int global_available; - unsigned int global_reserved; - unsigned int total_allocated; - char __data[0]; -}; - -struct trace_event_raw_irq_matrix_global_update { - struct trace_entry ent; - int bit; - unsigned int online_maps; - unsigned int global_available; - unsigned int global_reserved; - unsigned int total_allocated; - char __data[0]; -}; - -struct trace_event_raw_irq_matrix_cpu { - struct trace_entry ent; - int bit; - unsigned int cpu; - bool online; - unsigned int available; - unsigned int allocated; - unsigned int managed; - unsigned int online_maps; - unsigned int global_available; - unsigned int global_reserved; - unsigned int total_allocated; - char __data[0]; -}; - -struct trace_event_data_offsets_irq_matrix_global {}; - -struct trace_event_data_offsets_irq_matrix_global_update {}; - -struct trace_event_data_offsets_irq_matrix_cpu {}; - -typedef void (*btf_trace_irq_matrix_online)(void *, struct irq_matrix___2 *); - -typedef void (*btf_trace_irq_matrix_offline)(void *, struct irq_matrix___2 *); - -typedef void (*btf_trace_irq_matrix_reserve)(void *, struct irq_matrix___2 *); - -typedef void (*btf_trace_irq_matrix_remove_reserved)(void *, struct irq_matrix___2 *); - -typedef void (*btf_trace_irq_matrix_assign_system)(void *, int, struct irq_matrix___2 *); - -typedef void (*btf_trace_irq_matrix_alloc_reserved)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *); - -typedef void (*btf_trace_irq_matrix_reserve_managed)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *); - -typedef void (*btf_trace_irq_matrix_remove_managed)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *); - -typedef void (*btf_trace_irq_matrix_alloc_managed)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *); - -typedef void (*btf_trace_irq_matrix_assign)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *); - -typedef void (*btf_trace_irq_matrix_alloc)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *); - -typedef void (*btf_trace_irq_matrix_free)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *); - -typedef void (*call_rcu_func_t)(struct callback_head *, rcu_callback_t); - -struct rcu_synchronize { - struct callback_head head; - struct completion completion; -}; - -struct trace_event_raw_rcu_utilization { - struct trace_entry ent; - const char *s; - char __data[0]; -}; - -struct trace_event_raw_rcu_stall_warning { - struct trace_entry ent; - const char *rcuname; - const char *msg; - char __data[0]; -}; - -struct trace_event_data_offsets_rcu_utilization {}; - -struct trace_event_data_offsets_rcu_stall_warning {}; - -typedef void (*btf_trace_rcu_utilization)(void *, const char *); - -typedef void (*btf_trace_rcu_stall_warning)(void *, const char *, const char *); - -struct rcu_tasks; - -typedef void (*rcu_tasks_gp_func_t)(struct rcu_tasks *); - -typedef void (*pregp_func_t)(); - -typedef void (*pertask_func_t)(struct task_struct *, struct list_head *); - -typedef void (*postscan_func_t)(struct list_head *); - -typedef void (*holdouts_func_t)(struct list_head *, bool, bool *); - -typedef void (*postgp_func_t)(struct rcu_tasks *); - -struct rcu_tasks { - struct callback_head *cbs_head; - struct callback_head **cbs_tail; - struct wait_queue_head cbs_wq; - raw_spinlock_t cbs_lock; - int gp_state; - int gp_sleep; - int init_fract; - long unsigned int gp_jiffies; - long unsigned int gp_start; - long unsigned int n_gps; - long unsigned int n_ipis; - long unsigned int n_ipis_fails; - struct task_struct *kthread_ptr; - rcu_tasks_gp_func_t gp_func; - pregp_func_t pregp_func; - pertask_func_t pertask_func; - postscan_func_t postscan_func; - holdouts_func_t holdouts_func; - postgp_func_t postgp_func; - call_rcu_func_t call_func; - char *name; - char *kname; -}; - -enum { - GP_IDLE = 0, - GP_ENTER = 1, - GP_PASSED = 2, - GP_EXIT = 3, - GP_REPLAY = 4, -}; - -struct rcu_cblist { - struct callback_head *head; - struct callback_head **tail; - long int len; -}; - -enum rcutorture_type { - RCU_FLAVOR = 0, - RCU_TASKS_FLAVOR = 1, - RCU_TASKS_RUDE_FLAVOR = 2, - RCU_TASKS_TRACING_FLAVOR = 3, - RCU_TRIVIAL_FLAVOR = 4, - SRCU_FLAVOR = 5, - INVALID_RCU_FLAVOR = 6, -}; - -struct rcu_exp_work { - long unsigned int rew_s; - struct work_struct rew_work; -}; - -struct rcu_node { - raw_spinlock_t lock; - long unsigned int gp_seq; - long unsigned int gp_seq_needed; - long unsigned int completedqs; - long unsigned int qsmask; - long unsigned int rcu_gp_init_mask; - long unsigned int qsmaskinit; - long unsigned int qsmaskinitnext; - long unsigned int ofl_seq; - long unsigned int expmask; - long unsigned int expmaskinit; - long unsigned int expmaskinitnext; - long unsigned int cbovldmask; - long unsigned int ffmask; - long unsigned int grpmask; - int grplo; - int grphi; - u8 grpnum; - u8 level; - bool wait_blkd_tasks; - struct rcu_node *parent; - struct list_head blkd_tasks; - struct list_head *gp_tasks; - struct list_head *exp_tasks; - struct list_head *boost_tasks; - struct rt_mutex boost_mtx; - long unsigned int boost_time; - struct task_struct *boost_kthread_task; - unsigned int boost_kthread_status; - long unsigned int n_boosts; - long: 64; - raw_spinlock_t fqslock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t exp_lock; - long unsigned int exp_seq_rq; - wait_queue_head_t exp_wq[4]; - struct rcu_exp_work rew; - bool exp_need_flush; - long: 56; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -union rcu_noqs { - struct { - u8 norm; - u8 exp; - } b; - u16 s; -}; - -struct rcu_data { - long unsigned int gp_seq; - long unsigned int gp_seq_needed; - union rcu_noqs cpu_no_qs; - bool core_needs_qs; - bool beenonline; - bool gpwrap; - bool exp_deferred_qs; - bool cpu_started; - struct rcu_node *mynode; - long unsigned int grpmask; - long unsigned int ticks_this_gp; - struct irq_work defer_qs_iw; - bool defer_qs_iw_pending; - struct work_struct strict_work; - struct rcu_segcblist cblist; - long int qlen_last_fqs_check; - long unsigned int n_cbs_invoked; - long unsigned int n_force_qs_snap; - long int blimit; - int dynticks_snap; - long int dynticks_nesting; - long int dynticks_nmi_nesting; - atomic_t dynticks; - bool rcu_need_heavy_qs; - bool rcu_urgent_qs; - bool rcu_forced_tick; - bool rcu_forced_tick_exp; - long unsigned int last_accelerate; - long unsigned int last_advance_all; - int tick_nohz_enabled_snap; - struct callback_head barrier_head; - int exp_dynticks_snap; - struct task_struct *rcu_cpu_kthread_task; - unsigned int rcu_cpu_kthread_status; - char rcu_cpu_has_work; - unsigned int softirq_snap; - struct irq_work rcu_iw; - bool rcu_iw_pending; - long unsigned int rcu_iw_gp_seq; - long unsigned int rcu_ofl_gp_seq; - short int rcu_ofl_gp_flags; - long unsigned int rcu_onl_gp_seq; - short int rcu_onl_gp_flags; - long unsigned int last_fqs_resched; - int cpu; -}; - -struct rcu_state { - struct rcu_node node[21]; - struct rcu_node *level[3]; - int ncpus; - int n_online_cpus; - long: 64; - long: 64; - long: 64; - long: 64; - u8 boost; - long unsigned int gp_seq; - long unsigned int gp_max; - struct task_struct *gp_kthread; - struct swait_queue_head gp_wq; - short int gp_flags; - short int gp_state; - long unsigned int gp_wake_time; - long unsigned int gp_wake_seq; - struct mutex barrier_mutex; - atomic_t barrier_cpu_count; - struct completion barrier_completion; - long unsigned int barrier_sequence; - struct mutex exp_mutex; - struct mutex exp_wake_mutex; - long unsigned int expedited_sequence; - atomic_t expedited_need_qs; - struct swait_queue_head expedited_wq; - int ncpus_snap; - u8 cbovld; - u8 cbovldnext; - long unsigned int jiffies_force_qs; - long unsigned int jiffies_kick_kthreads; - long unsigned int n_force_qs; - long unsigned int gp_start; - long unsigned int gp_end; - long unsigned int gp_activity; - long unsigned int gp_req_activity; - long unsigned int jiffies_stall; - long unsigned int jiffies_resched; - long unsigned int n_force_qs_gpstart; - const char *name; - char abbr; - long: 56; - long: 64; - long: 64; - raw_spinlock_t ofl_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct kvfree_rcu_bulk_data { - long unsigned int nr_records; - struct kvfree_rcu_bulk_data *next; - void *records[0]; -}; - -struct kfree_rcu_cpu; - -struct kfree_rcu_cpu_work { - struct rcu_work rcu_work; - struct callback_head *head_free; - struct kvfree_rcu_bulk_data *bkvhead_free[2]; - struct kfree_rcu_cpu *krcp; -}; - -struct kfree_rcu_cpu { - struct callback_head *head; - struct kvfree_rcu_bulk_data *bkvhead[2]; - struct kfree_rcu_cpu_work krw_arr[2]; - raw_spinlock_t lock; - struct delayed_work monitor_work; - bool monitor_todo; - bool initialized; - int count; - struct delayed_work page_cache_work; - atomic_t backoff_page_cache_fill; - atomic_t work_in_progress; - struct hrtimer hrtimer; - struct llist_head bkvcache; - int nr_bkv_objs; -}; - -struct rcu_stall_chk_rdr { - int nesting; - union rcu_special rs; - bool on_blkd_list; -}; - -struct io_tlb_slot { - phys_addr_t orig_addr; - size_t alloc_size; - unsigned int list; -}; - -struct io_tlb_mem { - phys_addr_t start; - phys_addr_t end; - long unsigned int nslabs; - long unsigned int used; - unsigned int index; - spinlock_t lock; - struct dentry *debugfs; - bool late_alloc; - struct io_tlb_slot slots[0]; -}; - -struct dma_sgt_handle { - struct sg_table sgt; - struct page **pages; -}; - -struct dma_devres { - size_t size; - void *vaddr; - dma_addr_t dma_handle; - long unsigned int attrs; -}; - -struct debugfs_u32_array { - u32 *array; - u32 n_elements; -}; - -struct cma_kobject; - -struct cma { - long unsigned int base_pfn; - long unsigned int count; - long unsigned int *bitmap; - unsigned int order_per_bit; - spinlock_t lock; - struct hlist_head mem_head; - spinlock_t mem_head_lock; - struct debugfs_u32_array dfs_bitmap; - char name[64]; - atomic64_t nr_pages_succeeded; - atomic64_t nr_pages_failed; - struct cma_kobject *cma_kobj; -}; - -struct trace_event_raw_swiotlb_bounced { - struct trace_entry ent; - u32 __data_loc_dev_name; - u64 dma_mask; - dma_addr_t dev_addr; - size_t size; - enum swiotlb_force swiotlb_force; - char __data[0]; -}; - -struct trace_event_data_offsets_swiotlb_bounced { - u32 dev_name; -}; - -typedef void (*btf_trace_swiotlb_bounced)(void *, struct device *, dma_addr_t, size_t, enum swiotlb_force); - -struct trace_event_raw_sys_enter { - struct trace_entry ent; - long int id; - long unsigned int args[6]; - char __data[0]; -}; - -struct trace_event_raw_sys_exit { - struct trace_entry ent; - long int id; - long int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_sys_enter {}; - -struct trace_event_data_offsets_sys_exit {}; - -typedef void (*btf_trace_sys_enter)(void *, struct pt_regs *, long int); - -typedef void (*btf_trace_sys_exit)(void *, struct pt_regs *, long int); - -struct kvm_regs { - __u64 rax; - __u64 rbx; - __u64 rcx; - __u64 rdx; - __u64 rsi; - __u64 rdi; - __u64 rsp; - __u64 rbp; - __u64 r8; - __u64 r9; - __u64 r10; - __u64 r11; - __u64 r12; - __u64 r13; - __u64 r14; - __u64 r15; - __u64 rip; - __u64 rflags; -}; - -struct kvm_segment { - __u64 base; - __u32 limit; - __u16 selector; - __u8 type; - __u8 present; - __u8 dpl; - __u8 db; - __u8 s; - __u8 l; - __u8 g; - __u8 avl; - __u8 unusable; - __u8 padding; -}; - -struct kvm_dtable { - __u64 base; - __u16 limit; - __u16 padding[3]; -}; - -struct kvm_sregs { - struct kvm_segment cs; - struct kvm_segment ds; - struct kvm_segment es; - struct kvm_segment fs; - struct kvm_segment gs; - struct kvm_segment ss; - struct kvm_segment tr; - struct kvm_segment ldt; - struct kvm_dtable gdt; - struct kvm_dtable idt; - __u64 cr0; - __u64 cr2; - __u64 cr3; - __u64 cr4; - __u64 cr8; - __u64 efer; - __u64 apic_base; - __u64 interrupt_bitmap[4]; -}; - -struct kvm_msr_entry { - __u32 index; - __u32 reserved; - __u64 data; -}; - -struct kvm_cpuid_entry2 { - __u32 function; - __u32 index; - __u32 flags; - __u32 eax; - __u32 ebx; - __u32 ecx; - __u32 edx; - __u32 padding[3]; -}; - -struct kvm_debug_exit_arch { - __u32 exception; - __u32 pad; - __u64 pc; - __u64 dr6; - __u64 dr7; -}; - -struct kvm_vcpu_events { - struct { - __u8 injected; - __u8 nr; - __u8 has_error_code; - __u8 pending; - __u32 error_code; - } exception; - struct { - __u8 injected; - __u8 nr; - __u8 soft; - __u8 shadow; - } interrupt; - struct { - __u8 injected; - __u8 pending; - __u8 masked; - __u8 pad; - } nmi; - __u32 sipi_vector; - __u32 flags; - struct { - __u8 smm; - __u8 pending; - __u8 smm_inside_nmi; - __u8 latched_init; - } smi; - __u8 reserved[27]; - __u8 exception_has_payload; - __u64 exception_payload; -}; - -struct kvm_sync_regs { - struct kvm_regs regs; - struct kvm_sregs sregs; - struct kvm_vcpu_events events; -}; - -struct kvm_vmx_nested_state_data { - __u8 vmcs12[4096]; - __u8 shadow_vmcs12[4096]; -}; - -struct kvm_vmx_nested_state_hdr { - __u64 vmxon_pa; - __u64 vmcs12_pa; - struct { - __u16 flags; - } smm; - __u16 pad; - __u32 flags; - __u64 preemption_timer_deadline; -}; - -struct kvm_svm_nested_state_data { - __u8 vmcb12[4096]; -}; - -struct kvm_svm_nested_state_hdr { - __u64 vmcb_pa; -}; - -struct kvm_nested_state { - __u16 flags; - __u16 format; - __u32 size; - union { - struct kvm_vmx_nested_state_hdr vmx; - struct kvm_svm_nested_state_hdr svm; - __u8 pad[120]; - } hdr; - union { - struct kvm_vmx_nested_state_data vmx[0]; - struct kvm_svm_nested_state_data svm[0]; - } data; -}; - -struct kvm_pmu_event_filter { - __u32 action; - __u32 nevents; - __u32 fixed_counter_bitmap; - __u32 flags; - __u32 pad[4]; - __u64 events[0]; -}; - -struct kvm_hyperv_exit { - __u32 type; - __u32 pad1; - union { - struct { - __u32 msr; - __u32 pad2; - __u64 control; - __u64 evt_page; - __u64 msg_page; - } synic; - struct { - __u64 input; - __u64 result; - __u64 params[2]; - } hcall; - struct { - __u32 msr; - __u32 pad2; - __u64 control; - __u64 status; - __u64 send_page; - __u64 recv_page; - __u64 pending_page; - } syndbg; - } u; -}; - -struct kvm_xen_exit { - __u32 type; - union { - struct { - __u32 longmode; - __u32 cpl; - __u64 input; - __u64 result; - __u64 params[6]; - } hcall; - } u; -}; - -struct kvm_run { - __u8 request_interrupt_window; - __u8 immediate_exit; - __u8 padding1[6]; - __u32 exit_reason; - __u8 ready_for_interrupt_injection; - __u8 if_flag; - __u16 flags; - __u64 cr8; - __u64 apic_base; - union { - struct { - __u64 hardware_exit_reason; - } hw; - struct { - __u64 hardware_entry_failure_reason; - __u32 cpu; - } fail_entry; - struct { - __u32 exception; - __u32 error_code; - } ex; - struct { - __u8 direction; - __u8 size; - __u16 port; - __u32 count; - __u64 data_offset; - } io; - struct { - struct kvm_debug_exit_arch arch; - } debug; - struct { - __u64 phys_addr; - __u8 data[8]; - __u32 len; - __u8 is_write; - } mmio; - struct { - __u64 nr; - __u64 args[6]; - __u64 ret; - __u32 longmode; - __u32 pad; - } hypercall; - struct { - __u64 rip; - __u32 is_write; - __u32 pad; - } tpr_access; - struct { - __u8 icptcode; - __u16 ipa; - __u32 ipb; - } s390_sieic; - __u64 s390_reset_flags; - struct { - __u64 trans_exc_code; - __u32 pgm_code; - } s390_ucontrol; - struct { - __u32 dcrn; - __u32 data; - __u8 is_write; - } dcr; - struct { - __u32 suberror; - __u32 ndata; - __u64 data[16]; - } internal; - struct { - __u32 suberror; - __u32 ndata; - __u64 flags; - __u8 insn_size; - __u8 insn_bytes[15]; - } emulation_failure; - struct { - __u64 gprs[32]; - } osi; - struct { - __u64 nr; - __u64 ret; - __u64 args[9]; - } papr_hcall; - struct { - __u16 subchannel_id; - __u16 subchannel_nr; - __u32 io_int_parm; - __u32 io_int_word; - __u32 ipb; - __u8 dequeued; - } s390_tsch; - struct { - __u32 epr; - } epr; - struct { - __u32 type; - __u64 flags; - } system_event; - struct { - __u64 addr; - __u8 ar; - __u8 reserved; - __u8 fc; - __u8 sel1; - __u16 sel2; - } s390_stsi; - struct { - __u8 vector; - } eoi; - struct kvm_hyperv_exit hyperv; - struct { - __u64 esr_iss; - __u64 fault_ipa; - } arm_nisv; - struct { - __u8 error; - __u8 pad[7]; - __u32 reason; - __u32 index; - __u64 data; - } msr; - struct kvm_xen_exit xen; - char padding[256]; - }; - __u64 kvm_valid_regs; - __u64 kvm_dirty_regs; - union { - struct kvm_sync_regs regs; - char padding[2048]; - } s; -}; - -struct kvm_coalesced_mmio { - __u64 phys_addr; - __u32 len; - union { - __u32 pad; - __u32 pio; - }; - __u8 data[8]; -}; - -struct kvm_coalesced_mmio_ring { - __u32 first; - __u32 last; - struct kvm_coalesced_mmio coalesced_mmio[0]; -}; - -struct kvm_xen_hvm_config { - __u32 flags; - __u32 msr; - __u64 blob_addr_32; - __u64 blob_addr_64; - __u8 blob_size_32; - __u8 blob_size_64; - __u8 pad2[30]; -}; - -struct kvm_enc_region { - __u64 addr; - __u64 size; -}; - -struct kvm_dirty_gfn { - __u32 flags; - __u32 slot; - __u64 offset; -}; - -struct kvm_stats_desc { - __u32 flags; - __s16 exponent; - __u16 size; - __u32 offset; - __u32 unused; - char name[0]; -}; - -typedef long unsigned int gva_t; - -typedef u64 gpa_t; - -typedef u64 gfn_t; - -typedef u64 hpa_t; - -typedef u64 hfn_t; - -typedef hfn_t kvm_pfn_t; - -struct kvm_memory_slot; - -struct gfn_to_hva_cache { - u64 generation; - gpa_t gpa; - long unsigned int hva; - long unsigned int len; - struct kvm_memory_slot *memslot; -}; - -struct kvm_rmap_head; - -struct kvm_lpage_info; - -struct kvm_arch_memory_slot { - struct kvm_rmap_head *rmap[3]; - struct kvm_lpage_info *lpage_info[2]; - short unsigned int *gfn_track[1]; -}; - -struct kvm_memory_slot { - gfn_t base_gfn; - long unsigned int npages; - long unsigned int *dirty_bitmap; - struct kvm_arch_memory_slot arch; - long unsigned int userspace_addr; - u32 flags; - short int id; - u16 as_id; -}; - -struct gfn_to_pfn_cache { - u64 generation; - gfn_t gfn; - kvm_pfn_t pfn; - bool dirty; -}; - -struct kvm_mmu_memory_cache { - int nobjs; - gfp_t gfp_zero; - struct kmem_cache *kmem_cache; - void *objects[40]; -}; - -struct kvm_vm_stat_generic { - u64 remote_tlb_flush; -}; - -struct kvm_vcpu_stat_generic { - u64 halt_successful_poll; - u64 halt_attempted_poll; - u64 halt_poll_invalid; - u64 halt_wakeup; - u64 halt_poll_success_ns; - u64 halt_poll_fail_ns; -}; - -struct hv_partition_assist_pg { - u32 tlb_lock_count; -}; - -union hv_message_flags { - __u8 asu8; - struct { - __u8 msg_pending: 1; - __u8 reserved: 7; - }; -}; - -union hv_port_id { - __u32 asu32; - struct { - __u32 id: 24; - __u32 reserved: 8; - } u; -}; - -struct hv_message_header { - __u32 message_type; - __u8 payload_size; - union hv_message_flags message_flags; - __u8 reserved[2]; - union { - __u64 sender; - union hv_port_id port; - }; -}; - -struct hv_message { - struct hv_message_header header; - union { - __u64 payload[30]; - } u; -}; - -union hv_stimer_config { - u64 as_uint64; - struct { - u64 enable: 1; - u64 periodic: 1; - u64 lazy: 1; - u64 auto_enable: 1; - u64 apic_vector: 8; - u64 direct_mode: 1; - u64 reserved_z0: 3; - u64 sintx: 4; - u64 reserved_z1: 44; - }; -}; - -enum kvm_page_track_mode { - KVM_PAGE_TRACK_WRITE = 0, - KVM_PAGE_TRACK_MAX = 1, -}; - -struct kvm_page_track_notifier_head { - struct srcu_struct track_srcu; - struct hlist_head track_notifier_list; -}; - -struct kvm_vcpu; - -struct kvm; - -struct kvm_page_track_notifier_node { - struct hlist_node node; - void (*track_write)(struct kvm_vcpu *, gpa_t, const u8 *, int, struct kvm_page_track_notifier_node *); - void (*track_flush_slot)(struct kvm *, struct kvm_memory_slot *, struct kvm_page_track_notifier_node *); -}; - -struct kvm_mmio_fragment { - gpa_t gpa; - void *data; - unsigned int len; -}; - -struct kvm_lapic; - -struct x86_exception; - -struct kvm_mmu_page; - -union kvm_mmu_page_role { - u32 word; - struct { - unsigned int level: 4; - unsigned int gpte_is_8_bytes: 1; - unsigned int quadrant: 2; - unsigned int direct: 1; - unsigned int access: 3; - unsigned int invalid: 1; - unsigned int efer_nx: 1; - unsigned int cr0_wp: 1; - unsigned int smep_andnot_wp: 1; - unsigned int smap_andnot_wp: 1; - unsigned int ad_disabled: 1; - unsigned int guest_mode: 1; - char: 6; - unsigned int smm: 8; - }; -}; - -union kvm_mmu_extended_role { - u32 word; - struct { - unsigned int valid: 1; - unsigned int execonly: 1; - unsigned int cr0_pg: 1; - unsigned int cr4_pae: 1; - unsigned int cr4_pse: 1; - unsigned int cr4_pke: 1; - unsigned int cr4_smap: 1; - unsigned int cr4_smep: 1; - unsigned int cr4_la57: 1; - }; -}; - -union kvm_mmu_role { - u64 as_u64; - struct { - union kvm_mmu_page_role base; - union kvm_mmu_extended_role ext; - }; -}; - -struct kvm_mmu_root_info { - gpa_t pgd; - hpa_t hpa; -}; - -struct rsvd_bits_validate { - u64 rsvd_bits_mask[10]; - u64 bad_mt_xwr; -}; - -struct kvm_mmu { - long unsigned int (*get_guest_pgd)(struct kvm_vcpu *); - u64 (*get_pdptr)(struct kvm_vcpu *, int); - int (*page_fault)(struct kvm_vcpu *, gpa_t, u32, bool); - void (*inject_page_fault)(struct kvm_vcpu *, struct x86_exception *); - gpa_t (*gva_to_gpa)(struct kvm_vcpu *, gpa_t, u32, struct x86_exception *); - gpa_t (*translate_gpa)(struct kvm_vcpu *, gpa_t, u32, struct x86_exception *); - int (*sync_page)(struct kvm_vcpu *, struct kvm_mmu_page *); - void (*invlpg)(struct kvm_vcpu *, gva_t, hpa_t); - hpa_t root_hpa; - gpa_t root_pgd; - union kvm_mmu_role mmu_role; - u8 root_level; - u8 shadow_root_level; - u8 ept_ad; - bool direct_map; - struct kvm_mmu_root_info prev_roots[3]; - u8 permissions[16]; - u32 pkru_mask; - u64 *pae_root; - u64 *pml4_root; - struct rsvd_bits_validate shadow_zero_check; - struct rsvd_bits_validate guest_rsvd_check; - u64 pdptrs[4]; -}; - -struct kvm_pio_request { - long unsigned int linear_rip; - long unsigned int count; - int in; - int port; - int size; -}; - -struct kvm_queued_exception { - bool pending; - bool injected; - bool has_error_code; - u8 nr; - u32 error_code; - long unsigned int payload; - bool has_payload; - u8 nested_apf; -}; - -struct kvm_queued_interrupt { - bool injected; - bool soft; - u8 nr; -}; - -struct x86_emulate_ctxt; - -struct kvm_mtrr_range { - u64 base; - u64 mask; - struct list_head node; -}; - -struct kvm_mtrr { - struct kvm_mtrr_range var_ranges[8]; - mtrr_type fixed_ranges[88]; - u64 deftype; - struct list_head head; -}; - -enum pmc_type { - KVM_PMC_GP = 0, - KVM_PMC_FIXED = 1, -}; - -struct kvm_pmc { - enum pmc_type type; - u8 idx; - u64 counter; - u64 eventsel; - struct perf_event *perf_event; - struct kvm_vcpu *vcpu; - u64 current_config; -}; - -struct kvm_pmu { - unsigned int nr_arch_gp_counters; - unsigned int nr_arch_fixed_counters; - unsigned int available_event_types; - u64 fixed_ctr_ctrl; - u64 global_ctrl; - u64 global_status; - u64 global_ovf_ctrl; - u64 counter_bitmask[2]; - u64 global_ctrl_mask; - u64 global_ovf_ctrl_mask; - u64 reserved_bits; - u8 version; - struct kvm_pmc gp_counters[32]; - struct kvm_pmc fixed_counters[4]; - struct irq_work irq_work; - long unsigned int reprogram_pmi[1]; - long unsigned int all_valid_pmc_idx[1]; - long unsigned int pmc_in_use[1]; - bool need_cleanup; - u8 event_count; -}; - -struct kvm_vcpu_xen { - u64 hypercall_rip; - u32 current_runstate; - bool vcpu_info_set; - bool vcpu_time_info_set; - bool runstate_set; - struct gfn_to_hva_cache vcpu_info_cache; - struct gfn_to_hva_cache vcpu_time_info_cache; - struct gfn_to_hva_cache runstate_cache; - u64 last_steal; - u64 runstate_entry_time; - u64 runstate_times[4]; -}; - -struct kvm_vcpu_hv; - -struct kvm_vcpu_arch { - long unsigned int regs[17]; - u32 regs_avail; - u32 regs_dirty; - long unsigned int cr0; - long unsigned int cr0_guest_owned_bits; - long unsigned int cr2; - long unsigned int cr3; - long unsigned int cr4; - long unsigned int cr4_guest_owned_bits; - long unsigned int cr4_guest_rsvd_bits; - long unsigned int cr8; - u32 host_pkru; - u32 pkru; - u32 hflags; - u64 efer; - u64 apic_base; - struct kvm_lapic *apic; - bool apicv_active; - bool load_eoi_exitmap_pending; - long unsigned int ioapic_handled_vectors[4]; - long unsigned int apic_attention; - int32_t apic_arb_prio; - int mp_state; - u64 ia32_misc_enable_msr; - u64 smbase; - u64 smi_count; - bool tpr_access_reporting; - bool xsaves_enabled; - u64 ia32_xss; - u64 microcode_version; - u64 arch_capabilities; - u64 perf_capabilities; - struct kvm_mmu *mmu; - struct kvm_mmu root_mmu; - struct kvm_mmu guest_mmu; - struct kvm_mmu nested_mmu; - struct kvm_mmu *walk_mmu; - struct kvm_mmu_memory_cache mmu_pte_list_desc_cache; - struct kvm_mmu_memory_cache mmu_shadow_page_cache; - struct kvm_mmu_memory_cache mmu_gfn_array_cache; - struct kvm_mmu_memory_cache mmu_page_header_cache; - struct fpu *user_fpu; - struct fpu *guest_fpu; - u64 xcr0; - u64 guest_supported_xcr0; - struct kvm_pio_request pio; - void *pio_data; - void *guest_ins_data; - u8 event_exit_inst_len; - struct kvm_queued_exception exception; - struct kvm_queued_interrupt interrupt; - int halt_request; - int cpuid_nent; - struct kvm_cpuid_entry2 *cpuid_entries; - u64 reserved_gpa_bits; - int maxphyaddr; - int max_tdp_level; - struct x86_emulate_ctxt *emulate_ctxt; - bool emulate_regs_need_sync_to_vcpu; - bool emulate_regs_need_sync_from_vcpu; - int (*complete_userspace_io)(struct kvm_vcpu *); - gpa_t time; - struct pvclock_vcpu_time_info hv_clock; - unsigned int hw_tsc_khz; - struct gfn_to_hva_cache pv_time; - bool pv_time_enabled; - bool pvclock_set_guest_stopped_request; - struct { - u8 preempted; - u64 msr_val; - u64 last_steal; - struct gfn_to_pfn_cache cache; - } st; - u64 l1_tsc_offset; - u64 tsc_offset; - u64 last_guest_tsc; - u64 last_host_tsc; - u64 tsc_offset_adjustment; - u64 this_tsc_nsec; - u64 this_tsc_write; - u64 this_tsc_generation; - bool tsc_catchup; - bool tsc_always_catchup; - s8 virtual_tsc_shift; - u32 virtual_tsc_mult; - u32 virtual_tsc_khz; - s64 ia32_tsc_adjust_msr; - u64 msr_ia32_power_ctl; - u64 l1_tsc_scaling_ratio; - u64 tsc_scaling_ratio; - atomic_t nmi_queued; - unsigned int nmi_pending; - bool nmi_injected; - bool smi_pending; - struct kvm_mtrr mtrr_state; - u64 pat; - unsigned int switch_db_regs; - long unsigned int db[4]; - long unsigned int dr6; - long unsigned int dr7; - long unsigned int eff_db[4]; - long unsigned int guest_debug_dr7; - u64 msr_platform_info; - u64 msr_misc_features_enables; - u64 mcg_cap; - u64 mcg_status; - u64 mcg_ctl; - u64 mcg_ext_ctl; - u64 *mce_banks; - u64 mmio_gva; - unsigned int mmio_access; - gfn_t mmio_gfn; - u64 mmio_gen; - struct kvm_pmu pmu; - long unsigned int singlestep_rip; - bool hyperv_enabled; - struct kvm_vcpu_hv *hyperv; - struct kvm_vcpu_xen xen; - cpumask_var_t wbinvd_dirty_mask; - long unsigned int last_retry_eip; - long unsigned int last_retry_addr; - struct { - bool halted; - gfn_t gfns[64]; - struct gfn_to_hva_cache data; - u64 msr_en_val; - u64 msr_int_val; - u16 vec; - u32 id; - bool send_user_only; - u32 host_apf_flags; - long unsigned int nested_apf_token; - bool delivery_as_pf_vmexit; - bool pageready_pending; - } apf; - struct { - u64 length; - u64 status; - } osvw; - struct { - u64 msr_val; - struct gfn_to_hva_cache data; - } pv_eoi; - u64 msr_kvm_poll_control; - bool write_fault_to_shadow_pgtable; - long unsigned int exit_qualification; - struct { - bool pv_unhalted; - } pv; - int pending_ioapic_eoi; - int pending_external_vector; - bool preempted_in_kernel; - bool l1tf_flush_l1d; - int last_vmentry_cpu; - u64 msr_hwcr; - struct { - u32 features; - bool enforce; - } pv_cpuid; - bool guest_state_protected; - bool pdptrs_from_userspace; - hpa_t hv_root_tdp; -}; - -struct kvm_vcpu_stat { - struct kvm_vcpu_stat_generic generic; - u64 pf_fixed; - u64 pf_guest; - u64 tlb_flush; - u64 invlpg; - u64 exits; - u64 io_exits; - u64 mmio_exits; - u64 signal_exits; - u64 irq_window_exits; - u64 nmi_window_exits; - u64 l1d_flush; - u64 halt_exits; - u64 request_irq_exits; - u64 irq_exits; - u64 host_state_reload; - u64 fpu_reload; - u64 insn_emulation; - u64 insn_emulation_fail; - u64 hypercalls; - u64 irq_injections; - u64 nmi_injections; - u64 req_event; - u64 nested_run; - u64 directed_yield_attempted; - u64 directed_yield_successful; - u64 guest_mode; -}; - -struct kvm_dirty_ring { - u32 dirty_index; - u32 reset_index; - u32 size; - u32 soft_limit; - struct kvm_dirty_gfn *dirty_gfns; - int index; -}; - -struct kvm_vcpu { - struct kvm *kvm; - struct preempt_notifier preempt_notifier; - int cpu; - int vcpu_id; - int vcpu_idx; - int srcu_idx; - int mode; - u64 requests; - long unsigned int guest_debug; - int pre_pcpu; - struct list_head blocked_vcpu_list; - struct mutex mutex; - struct kvm_run *run; - struct rcuwait wait; - struct pid *pid; - int sigset_active; - sigset_t sigset; - unsigned int halt_poll_ns; - bool valid_wakeup; - int mmio_needed; - int mmio_read_completed; - int mmio_is_write; - int mmio_cur_fragment; - int mmio_nr_fragments; - struct kvm_mmio_fragment mmio_fragments[2]; - struct { - u32 queued; - struct list_head queue; - struct list_head done; - spinlock_t lock; - } async_pf; - struct { - bool in_spin_loop; - bool dy_eligible; - } spin_loop; - bool preempted; - bool ready; - struct kvm_vcpu_arch arch; - struct kvm_vcpu_stat stat; - char stats_id[48]; - struct kvm_dirty_ring dirty_ring; -}; - -struct kvm_vm_stat { - struct kvm_vm_stat_generic generic; - u64 mmu_shadow_zapped; - u64 mmu_pte_write; - u64 mmu_pde_zapped; - u64 mmu_flooded; - u64 mmu_recycled; - u64 mmu_cache_miss; - u64 mmu_unsync; - u64 lpages; - u64 nx_lpage_splits; - u64 max_mmu_page_hash_collisions; -}; - -struct kvm_pic; - -struct kvm_ioapic; - -struct kvm_pit; - -enum hv_tsc_page_status { - HV_TSC_PAGE_UNSET = 0, - HV_TSC_PAGE_GUEST_CHANGED = 1, - HV_TSC_PAGE_HOST_CHANGED = 2, - HV_TSC_PAGE_SET = 3, - HV_TSC_PAGE_UPDATING = 4, - HV_TSC_PAGE_BROKEN = 5, -}; - -struct kvm_hv_syndbg { - struct { - u64 control; - u64 status; - u64 send_page; - u64 recv_page; - u64 pending_page; - } control; - u64 options; -}; - -struct kvm_hv { - struct mutex hv_lock; - u64 hv_guest_os_id; - u64 hv_hypercall; - u64 hv_tsc_page; - enum hv_tsc_page_status hv_tsc_page_status; - u64 hv_crash_param[5]; - u64 hv_crash_ctl; - struct ms_hyperv_tsc_page tsc_ref; - struct idr conn_to_evt; - u64 hv_reenlightenment_control; - u64 hv_tsc_emulation_control; - u64 hv_tsc_emulation_status; - atomic_t num_mismatched_vp_indexes; - struct hv_partition_assist_pg *hv_pa_pg; - struct kvm_hv_syndbg hv_syndbg; -}; - -struct kvm_xen { - bool long_mode; - bool shinfo_set; - u8 upcall_vector; - struct gfn_to_hva_cache shinfo_cache; -}; - -enum kvm_irqchip_mode { - KVM_IRQCHIP_NONE = 0, - KVM_IRQCHIP_KERNEL = 1, - KVM_IRQCHIP_SPLIT = 2, -}; - -struct kvm_apic_map; - -struct kvm_x86_msr_filter; - -struct kvm_arch { - long unsigned int n_used_mmu_pages; - long unsigned int n_requested_mmu_pages; - long unsigned int n_max_mmu_pages; - unsigned int indirect_shadow_pages; - u8 mmu_valid_gen; - struct hlist_head mmu_page_hash[4096]; - struct list_head active_mmu_pages; - struct list_head zapped_obsolete_pages; - struct list_head lpage_disallowed_mmu_pages; - struct kvm_page_track_notifier_node mmu_sp_tracker; - struct kvm_page_track_notifier_head track_notifier_head; - spinlock_t mmu_unsync_pages_lock; - struct list_head assigned_dev_head; - struct iommu_domain *iommu_domain; - bool iommu_noncoherent; - atomic_t noncoherent_dma_count; - atomic_t assigned_device_count; - struct kvm_pic *vpic; - struct kvm_ioapic *vioapic; - struct kvm_pit *vpit; - atomic_t vapics_in_nmi_mode; - struct mutex apic_map_lock; - struct kvm_apic_map *apic_map; - atomic_t apic_map_dirty; - bool apic_access_memslot_enabled; - long unsigned int apicv_inhibit_reasons; - gpa_t wall_clock; - bool mwait_in_guest; - bool hlt_in_guest; - bool pause_in_guest; - bool cstate_in_guest; - long unsigned int irq_sources_bitmap; - s64 kvmclock_offset; - raw_spinlock_t tsc_write_lock; - u64 last_tsc_nsec; - u64 last_tsc_write; - u32 last_tsc_khz; - u64 cur_tsc_nsec; - u64 cur_tsc_write; - u64 cur_tsc_offset; - u64 cur_tsc_generation; - int nr_vcpus_matched_tsc; - spinlock_t pvclock_gtod_sync_lock; - bool use_master_clock; - u64 master_kernel_ns; - u64 master_cycle_now; - struct delayed_work kvmclock_update_work; - struct delayed_work kvmclock_sync_work; - struct kvm_xen_hvm_config xen_hvm_config; - struct hlist_head mask_notifier_list; - struct kvm_hv hyperv; - struct kvm_xen xen; - int audit_point; - bool backwards_tsc_observed; - bool boot_vcpu_runs_old_kvmclock; - u32 bsp_vcpu_id; - u64 disabled_quirks; - int cpu_dirty_logging_count; - enum kvm_irqchip_mode irqchip_mode; - u8 nr_reserved_ioapic_pins; - bool disabled_lapic_found; - bool x2apic_format; - bool x2apic_broadcast_quirk_disabled; - bool guest_can_read_msr_platform_info; - bool exception_payload_enabled; - bool bus_lock_detection_enabled; - bool exit_on_emulation_error; - u32 user_space_msr_mask; - struct kvm_x86_msr_filter *msr_filter; - u32 hypercall_exit_enabled; - bool sgx_provisioning_allowed; - struct kvm_pmu_event_filter *pmu_event_filter; - struct task_struct *nx_lpage_recovery_thread; - bool tdp_mmu_enabled; - struct list_head tdp_mmu_roots; - struct list_head tdp_mmu_pages; - spinlock_t tdp_mmu_pages_lock; - bool memslots_have_rmaps; - hpa_t hv_root_tdp; - spinlock_t hv_root_tdp_lock; -}; - -struct kvm_memslots; - -struct kvm_io_bus; - -struct kvm_irq_routing_table; - -struct kvm_stat_data; - -struct kvm { - rwlock_t mmu_lock; - struct mutex slots_lock; - struct mutex slots_arch_lock; - struct mm_struct *mm; - struct kvm_memslots *memslots[2]; - struct kvm_vcpu *vcpus[288]; - atomic_t online_vcpus; - int created_vcpus; - int last_boosted_vcpu; - struct list_head vm_list; - struct mutex lock; - struct kvm_io_bus *buses[4]; - struct { - spinlock_t lock; - struct list_head items; - struct list_head resampler_list; - struct mutex resampler_lock; - } irqfds; - struct list_head ioeventfds; - struct kvm_vm_stat stat; - struct kvm_arch arch; - refcount_t users_count; - struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; - spinlock_t ring_lock; - struct list_head coalesced_zones; - struct mutex irq_lock; - struct kvm_irq_routing_table *irq_routing; - struct hlist_head irq_ack_notifier_list; - struct mmu_notifier mmu_notifier; - long unsigned int mmu_notifier_seq; - long int mmu_notifier_count; - long unsigned int mmu_notifier_range_start; - long unsigned int mmu_notifier_range_end; - long int tlbs_dirty; - struct list_head devices; - u64 manual_dirty_log_protect; - struct dentry *debugfs_dentry; - struct kvm_stat_data **debugfs_stat_data; - struct srcu_struct srcu; - struct srcu_struct irq_srcu; - pid_t userspace_pid; - unsigned int max_halt_poll_ns; - u32 dirty_ring_size; - struct notifier_block pm_notifier; - char stats_id[48]; -}; - -enum kvm_reg { - VCPU_REGS_RAX = 0, - VCPU_REGS_RCX = 1, - VCPU_REGS_RDX = 2, - VCPU_REGS_RBX = 3, - VCPU_REGS_RSP = 4, - VCPU_REGS_RBP = 5, - VCPU_REGS_RSI = 6, - VCPU_REGS_RDI = 7, - VCPU_REGS_R8 = 8, - VCPU_REGS_R9 = 9, - VCPU_REGS_R10 = 10, - VCPU_REGS_R11 = 11, - VCPU_REGS_R12 = 12, - VCPU_REGS_R13 = 13, - VCPU_REGS_R14 = 14, - VCPU_REGS_R15 = 15, - VCPU_REGS_RIP = 16, - NR_VCPU_REGS = 17, - VCPU_EXREG_PDPTR = 17, - VCPU_EXREG_CR0 = 18, - VCPU_EXREG_CR3 = 19, - VCPU_EXREG_CR4 = 20, - VCPU_EXREG_RFLAGS = 21, - VCPU_EXREG_SEGMENTS = 22, - VCPU_EXREG_EXIT_INFO_1 = 23, - VCPU_EXREG_EXIT_INFO_2 = 24, -}; - -enum exit_fastpath_completion { - EXIT_FASTPATH_NONE = 0, - EXIT_FASTPATH_REENTER_GUEST = 1, - EXIT_FASTPATH_EXIT_HANDLED = 2, -}; - -struct kvm_rmap_head { - long unsigned int val; -}; - -struct kvm_tlb_range { - u64 start_gfn; - u64 pages; -}; - -struct kvm_vcpu_hv_stimer { - struct hrtimer timer; - int index; - union hv_stimer_config config; - u64 count; - u64 exp_time; - struct hv_message msg; - bool msg_pending; -}; - -struct kvm_vcpu_hv_synic { - u64 version; - u64 control; - u64 msg_page; - u64 evt_page; - atomic64_t sint[16]; - atomic_t sint_to_gsi[16]; - long unsigned int auto_eoi_bitmap[4]; - long unsigned int vec_bitmap[4]; - bool active; - bool dont_zero_synic_pages; -}; - -struct kvm_vcpu_hv { - struct kvm_vcpu *vcpu; - u32 vp_index; - u64 hv_vapic; - s64 runtime_offset; - struct kvm_vcpu_hv_synic synic; - struct kvm_hyperv_exit exit; - struct kvm_vcpu_hv_stimer stimer[4]; - long unsigned int stimer_pending_bitmap[1]; - cpumask_t tlb_flush; - bool enforce_cpuid; - struct { - u32 features_eax; - u32 features_ebx; - u32 features_edx; - u32 enlightenments_eax; - u32 enlightenments_ebx; - u32 syndbg_cap_eax; - } cpuid_cache; -}; - -struct kvm_lpage_info { - int disallow_lpage; -}; - -struct kvm_apic_map { - struct callback_head rcu; - u8 mode; - u32 max_apic_id; - union { - struct kvm_lapic *xapic_flat_map[8]; - struct kvm_lapic *xapic_cluster_map[64]; - }; - struct kvm_lapic *phys_map[0]; -}; - -struct msr_bitmap_range { - u32 flags; - u32 nmsrs; - u32 base; - long unsigned int *bitmap; -}; - -struct kvm_x86_msr_filter { - u8 count; - bool default_allow: 1; - struct msr_bitmap_range ranges[16]; -}; - -struct msr_data { - bool host_initiated; - u32 index; - u64 data; -}; - -struct x86_instruction_info; - -enum x86_intercept_stage; - -struct kvm_pmu_ops; - -struct kvm_x86_nested_ops; - -struct kvm_x86_ops { - int (*hardware_enable)(); - void (*hardware_disable)(); - void (*hardware_unsetup)(); - bool (*cpu_has_accelerated_tpr)(); - bool (*has_emulated_msr)(struct kvm *, u32); - void (*vcpu_after_set_cpuid)(struct kvm_vcpu *); - unsigned int vm_size; - int (*vm_init)(struct kvm *); - void (*vm_destroy)(struct kvm *); - int (*vcpu_create)(struct kvm_vcpu *); - void (*vcpu_free)(struct kvm_vcpu *); - void (*vcpu_reset)(struct kvm_vcpu *, bool); - void (*prepare_guest_switch)(struct kvm_vcpu *); - void (*vcpu_load)(struct kvm_vcpu *, int); - void (*vcpu_put)(struct kvm_vcpu *); - void (*update_exception_bitmap)(struct kvm_vcpu *); - int (*get_msr)(struct kvm_vcpu *, struct msr_data *); - int (*set_msr)(struct kvm_vcpu *, struct msr_data *); - u64 (*get_segment_base)(struct kvm_vcpu *, int); - void (*get_segment)(struct kvm_vcpu *, struct kvm_segment *, int); - int (*get_cpl)(struct kvm_vcpu *); - void (*set_segment)(struct kvm_vcpu *, struct kvm_segment *, int); - void (*get_cs_db_l_bits)(struct kvm_vcpu *, int *, int *); - void (*set_cr0)(struct kvm_vcpu *, long unsigned int); - bool (*is_valid_cr4)(struct kvm_vcpu *, long unsigned int); - void (*set_cr4)(struct kvm_vcpu *, long unsigned int); - int (*set_efer)(struct kvm_vcpu *, u64); - void (*get_idt)(struct kvm_vcpu *, struct desc_ptr *); - void (*set_idt)(struct kvm_vcpu *, struct desc_ptr *); - void (*get_gdt)(struct kvm_vcpu *, struct desc_ptr *); - void (*set_gdt)(struct kvm_vcpu *, struct desc_ptr *); - void (*sync_dirty_debug_regs)(struct kvm_vcpu *); - void (*set_dr7)(struct kvm_vcpu *, long unsigned int); - void (*cache_reg)(struct kvm_vcpu *, enum kvm_reg); - long unsigned int (*get_rflags)(struct kvm_vcpu *); - void (*set_rflags)(struct kvm_vcpu *, long unsigned int); - void (*tlb_flush_all)(struct kvm_vcpu *); - void (*tlb_flush_current)(struct kvm_vcpu *); - int (*tlb_remote_flush)(struct kvm *); - int (*tlb_remote_flush_with_range)(struct kvm *, struct kvm_tlb_range *); - void (*tlb_flush_gva)(struct kvm_vcpu *, gva_t); - void (*tlb_flush_guest)(struct kvm_vcpu *); - enum exit_fastpath_completion (*run)(struct kvm_vcpu *); - int (*handle_exit)(struct kvm_vcpu *, enum exit_fastpath_completion); - int (*skip_emulated_instruction)(struct kvm_vcpu *); - void (*update_emulated_instruction)(struct kvm_vcpu *); - void (*set_interrupt_shadow)(struct kvm_vcpu *, int); - u32 (*get_interrupt_shadow)(struct kvm_vcpu *); - void (*patch_hypercall)(struct kvm_vcpu *, unsigned char *); - void (*set_irq)(struct kvm_vcpu *); - void (*set_nmi)(struct kvm_vcpu *); - void (*queue_exception)(struct kvm_vcpu *); - void (*cancel_injection)(struct kvm_vcpu *); - int (*interrupt_allowed)(struct kvm_vcpu *, bool); - int (*nmi_allowed)(struct kvm_vcpu *, bool); - bool (*get_nmi_mask)(struct kvm_vcpu *); - void (*set_nmi_mask)(struct kvm_vcpu *, bool); - void (*enable_nmi_window)(struct kvm_vcpu *); - void (*enable_irq_window)(struct kvm_vcpu *); - void (*update_cr8_intercept)(struct kvm_vcpu *, int, int); - bool (*check_apicv_inhibit_reasons)(ulong); - void (*pre_update_apicv_exec_ctrl)(struct kvm *, bool); - void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *); - void (*hwapic_irr_update)(struct kvm_vcpu *, int); - void (*hwapic_isr_update)(struct kvm_vcpu *, int); - bool (*guest_apic_has_interrupt)(struct kvm_vcpu *); - void (*load_eoi_exitmap)(struct kvm_vcpu *, u64 *); - void (*set_virtual_apic_mode)(struct kvm_vcpu *); - void (*set_apic_access_page_addr)(struct kvm_vcpu *); - int (*deliver_posted_interrupt)(struct kvm_vcpu *, int); - int (*sync_pir_to_irr)(struct kvm_vcpu *); - int (*set_tss_addr)(struct kvm *, unsigned int); - int (*set_identity_map_addr)(struct kvm *, u64); - u64 (*get_mt_mask)(struct kvm_vcpu *, gfn_t, bool); - void (*load_mmu_pgd)(struct kvm_vcpu *, hpa_t, int); - bool (*has_wbinvd_exit)(); - u64 (*get_l2_tsc_offset)(struct kvm_vcpu *); - u64 (*get_l2_tsc_multiplier)(struct kvm_vcpu *); - void (*write_tsc_offset)(struct kvm_vcpu *, u64); - void (*write_tsc_multiplier)(struct kvm_vcpu *, u64); - void (*get_exit_info)(struct kvm_vcpu *, u64 *, u64 *, u32 *, u32 *); - int (*check_intercept)(struct kvm_vcpu *, struct x86_instruction_info *, enum x86_intercept_stage, struct x86_exception *); - void (*handle_exit_irqoff)(struct kvm_vcpu *); - void (*request_immediate_exit)(struct kvm_vcpu *); - void (*sched_in)(struct kvm_vcpu *, int); - int cpu_dirty_log_size; - void (*update_cpu_dirty_logging)(struct kvm_vcpu *); - const struct kvm_pmu_ops *pmu_ops; - const struct kvm_x86_nested_ops *nested_ops; - int (*pre_block)(struct kvm_vcpu *); - void (*post_block)(struct kvm_vcpu *); - void (*vcpu_blocking)(struct kvm_vcpu *); - void (*vcpu_unblocking)(struct kvm_vcpu *); - int (*update_pi_irte)(struct kvm *, unsigned int, uint32_t, bool); - void (*start_assignment)(struct kvm *); - void (*apicv_post_state_restore)(struct kvm_vcpu *); - bool (*dy_apicv_has_pending_interrupt)(struct kvm_vcpu *); - int (*set_hv_timer)(struct kvm_vcpu *, u64, bool *); - void (*cancel_hv_timer)(struct kvm_vcpu *); - void (*setup_mce)(struct kvm_vcpu *); - int (*smi_allowed)(struct kvm_vcpu *, bool); - int (*enter_smm)(struct kvm_vcpu *, char *); - int (*leave_smm)(struct kvm_vcpu *, const char *); - void (*enable_smi_window)(struct kvm_vcpu *); - int (*mem_enc_op)(struct kvm *, void *); - int (*mem_enc_reg_region)(struct kvm *, struct kvm_enc_region *); - int (*mem_enc_unreg_region)(struct kvm *, struct kvm_enc_region *); - int (*vm_copy_enc_context_from)(struct kvm *, unsigned int); - int (*get_msr_feature)(struct kvm_msr_entry *); - bool (*can_emulate_instruction)(struct kvm_vcpu *, void *, int); - bool (*apic_init_signal_blocked)(struct kvm_vcpu *); - int (*enable_direct_tlbflush)(struct kvm_vcpu *); - void (*migrate_timers)(struct kvm_vcpu *); - void (*msr_filter_changed)(struct kvm_vcpu *); - int (*complete_emulated_msr)(struct kvm_vcpu *, int); - void (*vcpu_deliver_sipi_vector)(struct kvm_vcpu *, u8); -}; - -struct kvm_x86_nested_ops { - int (*check_events)(struct kvm_vcpu *); - bool (*hv_timer_pending)(struct kvm_vcpu *); - void (*triple_fault)(struct kvm_vcpu *); - int (*get_state)(struct kvm_vcpu *, struct kvm_nested_state *, unsigned int); - int (*set_state)(struct kvm_vcpu *, struct kvm_nested_state *, struct kvm_nested_state *); - bool (*get_nested_state_pages)(struct kvm_vcpu *); - int (*write_log_dirty)(struct kvm_vcpu *, gpa_t); - int (*enable_evmcs)(struct kvm_vcpu *, uint16_t *); - uint16_t (*get_evmcs_version)(struct kvm_vcpu *); -}; - -struct kvm_io_device; - -struct kvm_io_range { - gpa_t addr; - int len; - struct kvm_io_device *dev; -}; - -struct kvm_io_bus { - int dev_count; - int ioeventfd_count; - struct kvm_io_range range[0]; -}; - -enum kvm_bus { - KVM_MMIO_BUS = 0, - KVM_PIO_BUS = 1, - KVM_VIRTIO_CCW_NOTIFY_BUS = 2, - KVM_FAST_MMIO_BUS = 3, - KVM_NR_BUSES = 4, -}; - -struct kvm_irq_routing_table { - int chip[72]; - u32 nr_rt_entries; - struct hlist_head map[0]; -}; - -struct kvm_memslots { - u64 generation; - short int id_to_index[32767]; - atomic_t lru_slot; - int used_slots; - struct kvm_memory_slot memslots[0]; -}; - -enum kvm_stat_kind { - KVM_STAT_VM = 0, - KVM_STAT_VCPU = 1, -}; - -struct _kvm_stats_desc; - -struct kvm_stat_data { - struct kvm *kvm; - const struct _kvm_stats_desc *desc; - enum kvm_stat_kind kind; -}; - -struct _kvm_stats_desc { - struct kvm_stats_desc desc; - char name[48]; -}; - -enum kcmp_type { - KCMP_FILE = 0, - KCMP_VM = 1, - KCMP_FILES = 2, - KCMP_FS = 3, - KCMP_SIGHAND = 4, - KCMP_IO = 5, - KCMP_SYSVSEM = 6, - KCMP_EPOLL_TFD = 7, - KCMP_TYPES = 8, -}; - -struct kcmp_epoll_slot { - __u32 efd; - __u32 tfd; - __u32 toff; -}; - -enum profile_type { - PROFILE_TASK_EXIT = 0, - PROFILE_MUNMAP = 1, -}; - -struct profile_hit { - u32 pc; - u32 hits; -}; - -struct stacktrace_cookie { - long unsigned int *store; - unsigned int size; - unsigned int skip; - unsigned int len; -}; - -typedef __kernel_long_t __kernel_suseconds_t; - -typedef __kernel_long_t __kernel_old_time_t; - -typedef __kernel_suseconds_t suseconds_t; - -typedef __u64 timeu64_t; - -struct __kernel_itimerspec { - struct __kernel_timespec it_interval; - struct __kernel_timespec it_value; -}; - -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - -struct itimerspec64 { - struct timespec64 it_interval; - struct timespec64 it_value; -}; - -struct old_itimerspec32 { - struct old_timespec32 it_interval; - struct old_timespec32 it_value; -}; - -struct old_timex32 { - u32 modes; - s32 offset; - s32 freq; - s32 maxerror; - s32 esterror; - s32 status; - s32 constant; - s32 precision; - s32 tolerance; - struct old_timeval32 time; - s32 tick; - s32 ppsfreq; - s32 jitter; - s32 shift; - s32 stabil; - s32 jitcnt; - s32 calcnt; - s32 errcnt; - s32 stbcnt; - s32 tai; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct __kernel_timex_timeval { - __kernel_time64_t tv_sec; - long long int tv_usec; -}; - -struct __kernel_timex { - unsigned int modes; - long long int offset; - long long int freq; - long long int maxerror; - long long int esterror; - int status; - long long int constant; - long long int precision; - long long int tolerance; - struct __kernel_timex_timeval time; - long long int tick; - long long int ppsfreq; - long long int jitter; - int shift; - long long int stabil; - long long int jitcnt; - long long int calcnt; - long long int errcnt; - long long int stbcnt; - int tai; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct trace_event_raw_timer_class { - struct trace_entry ent; - void *timer; - char __data[0]; -}; - -struct trace_event_raw_timer_start { - struct trace_entry ent; - void *timer; - void *function; - long unsigned int expires; - long unsigned int now; - unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_timer_expire_entry { - struct trace_entry ent; - void *timer; - long unsigned int now; - void *function; - long unsigned int baseclk; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_init { - struct trace_entry ent; - void *hrtimer; - clockid_t clockid; - enum hrtimer_mode mode; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_start { - struct trace_entry ent; - void *hrtimer; - void *function; - s64 expires; - s64 softexpires; - enum hrtimer_mode mode; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_expire_entry { - struct trace_entry ent; - void *hrtimer; - s64 now; - void *function; - char __data[0]; -}; - -struct trace_event_raw_hrtimer_class { - struct trace_entry ent; - void *hrtimer; - char __data[0]; -}; - -struct trace_event_raw_itimer_state { - struct trace_entry ent; - int which; - long long unsigned int expires; - long int value_sec; - long int value_nsec; - long int interval_sec; - long int interval_nsec; - char __data[0]; -}; - -struct trace_event_raw_itimer_expire { - struct trace_entry ent; - int which; - pid_t pid; - long long unsigned int now; - char __data[0]; -}; - -struct trace_event_raw_tick_stop { - struct trace_entry ent; - int success; - int dependency; - char __data[0]; -}; - -struct trace_event_data_offsets_timer_class {}; - -struct trace_event_data_offsets_timer_start {}; - -struct trace_event_data_offsets_timer_expire_entry {}; - -struct trace_event_data_offsets_hrtimer_init {}; - -struct trace_event_data_offsets_hrtimer_start {}; - -struct trace_event_data_offsets_hrtimer_expire_entry {}; - -struct trace_event_data_offsets_hrtimer_class {}; - -struct trace_event_data_offsets_itimer_state {}; - -struct trace_event_data_offsets_itimer_expire {}; - -struct trace_event_data_offsets_tick_stop {}; - -typedef void (*btf_trace_timer_init)(void *, struct timer_list *); - -typedef void (*btf_trace_timer_start)(void *, struct timer_list *, long unsigned int, unsigned int); - -typedef void (*btf_trace_timer_expire_entry)(void *, struct timer_list *, long unsigned int); - -typedef void (*btf_trace_timer_expire_exit)(void *, struct timer_list *); - -typedef void (*btf_trace_timer_cancel)(void *, struct timer_list *); - -typedef void (*btf_trace_hrtimer_init)(void *, struct hrtimer *, clockid_t, enum hrtimer_mode); - -typedef void (*btf_trace_hrtimer_start)(void *, struct hrtimer *, enum hrtimer_mode); - -typedef void (*btf_trace_hrtimer_expire_entry)(void *, struct hrtimer *, ktime_t *); - -typedef void (*btf_trace_hrtimer_expire_exit)(void *, struct hrtimer *); - -typedef void (*btf_trace_hrtimer_cancel)(void *, struct hrtimer *); - -typedef void (*btf_trace_itimer_state)(void *, int, const struct itimerspec64 * const, long long unsigned int); - -typedef void (*btf_trace_itimer_expire)(void *, int, struct pid *, long long unsigned int); - -typedef void (*btf_trace_tick_stop)(void *, int, int); - -struct timer_base { - raw_spinlock_t lock; - struct timer_list *running_timer; - long unsigned int clk; - long unsigned int next_expiry; - unsigned int cpu; - bool next_expiry_recalc; - bool is_idle; - bool timers_pending; - long unsigned int pending_map[9]; - struct hlist_head vectors[576]; - long: 64; - long: 64; -}; - -struct process_timer { - struct timer_list timer; - struct task_struct *task; -}; - -enum tick_device_mode { - TICKDEV_MODE_PERIODIC = 0, - TICKDEV_MODE_ONESHOT = 1, -}; - -struct tick_device { - struct clock_event_device *evtdev; - enum tick_device_mode mode; -}; - -struct ktime_timestamps { - u64 mono; - u64 boot; - u64 real; -}; - -struct system_time_snapshot { - u64 cycles; - ktime_t real; - ktime_t raw; - enum clocksource_ids cs_id; - unsigned int clock_was_set_seq; - u8 cs_was_changed_seq; -}; - -struct system_device_crosststamp { - ktime_t device; - ktime_t sys_realtime; - ktime_t sys_monoraw; -}; - -struct audit_ntp_val { - long long int oldval; - long long int newval; -}; - -struct audit_ntp_data { - struct audit_ntp_val vals[6]; -}; - -enum timekeeping_adv_mode { - TK_ADV_TICK = 0, - TK_ADV_FREQ = 1, -}; - -struct tk_fast { - seqcount_latch_t seq; - struct tk_read_base base[2]; -}; - -struct rtc_wkalrm { - unsigned char enabled; - unsigned char pending; - struct rtc_time time; -}; - -struct rtc_class_ops { - int (*ioctl)(struct device *, unsigned int, long unsigned int); - int (*read_time)(struct device *, struct rtc_time *); - int (*set_time)(struct device *, struct rtc_time *); - int (*read_alarm)(struct device *, struct rtc_wkalrm *); - int (*set_alarm)(struct device *, struct rtc_wkalrm *); - int (*proc)(struct device *, struct seq_file *); - int (*alarm_irq_enable)(struct device *, unsigned int); - int (*read_offset)(struct device *, long int *); - int (*set_offset)(struct device *, long int); -}; - -struct rtc_device; - -struct rtc_timer { - struct timerqueue_node node; - ktime_t period; - void (*func)(struct rtc_device *); - struct rtc_device *rtc; - int enabled; -}; - -struct rtc_device { - struct device dev; - struct module *owner; - int id; - const struct rtc_class_ops *ops; - struct mutex ops_lock; - struct cdev char_dev; - long unsigned int flags; - long unsigned int irq_data; - spinlock_t irq_lock; - wait_queue_head_t irq_queue; - struct fasync_struct *async_queue; - int irq_freq; - int max_user_freq; - struct timerqueue_head timerqueue; - struct rtc_timer aie_timer; - struct rtc_timer uie_rtctimer; - struct hrtimer pie_timer; - int pie_enabled; - struct work_struct irqwork; - int uie_unsupported; - long unsigned int set_offset_nsec; - long unsigned int features[1]; - time64_t range_min; - timeu64_t range_max; - time64_t start_secs; - time64_t offset_secs; - bool set_start_time; - struct work_struct uie_task; - struct timer_list uie_timer; - unsigned int oldsecs; - unsigned int uie_irq_active: 1; - unsigned int stop_uie_polling: 1; - unsigned int uie_task_active: 1; - unsigned int uie_timer_active: 1; -}; - -typedef s64 int64_t; - -enum tick_nohz_mode { - NOHZ_MODE_INACTIVE = 0, - NOHZ_MODE_LOWRES = 1, - NOHZ_MODE_HIGHRES = 2, -}; - -struct tick_sched { - struct hrtimer sched_timer; - long unsigned int check_clocks; - enum tick_nohz_mode nohz_mode; - unsigned int inidle: 1; - unsigned int tick_stopped: 1; - unsigned int idle_active: 1; - unsigned int do_timer_last: 1; - unsigned int got_idle_tick: 1; - ktime_t last_tick; - ktime_t next_tick; - long unsigned int idle_jiffies; - long unsigned int idle_calls; - long unsigned int idle_sleeps; - ktime_t idle_entrytime; - ktime_t idle_waketime; - ktime_t idle_exittime; - ktime_t idle_sleeptime; - ktime_t iowait_sleeptime; - long unsigned int last_jiffies; - u64 timer_expires; - u64 timer_expires_base; - u64 next_timer; - ktime_t idle_expires; - atomic_t tick_dep_mask; -}; - -struct timer_list_iter { - int cpu; - bool second_pass; - u64 now; -}; - -struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - long int tm_year; - int tm_wday; - int tm_yday; -}; - -struct cyclecounter { - u64 (*read)(const struct cyclecounter *); - u64 mask; - u32 mult; - u32 shift; -}; - -struct timecounter { - const struct cyclecounter *cc; - u64 cycle_last; - u64 nsec; - u64 mask; - u64 frac; -}; - -typedef __kernel_timer_t timer_t; - -enum alarmtimer_type { - ALARM_REALTIME = 0, - ALARM_BOOTTIME = 1, - ALARM_NUMTYPE = 2, - ALARM_REALTIME_FREEZER = 3, - ALARM_BOOTTIME_FREEZER = 4, -}; - -enum alarmtimer_restart { - ALARMTIMER_NORESTART = 0, - ALARMTIMER_RESTART = 1, -}; - -struct alarm { - struct timerqueue_node node; - struct hrtimer timer; - enum alarmtimer_restart (*function)(struct alarm *, ktime_t); - enum alarmtimer_type type; - int state; - void *data; -}; - -struct cpu_timer { - struct timerqueue_node node; - struct timerqueue_head *head; - struct pid *pid; - struct list_head elist; - int firing; -}; - -struct k_clock; - -struct k_itimer { - struct list_head list; - struct hlist_node t_hash; - spinlock_t it_lock; - const struct k_clock *kclock; - clockid_t it_clock; - timer_t it_id; - int it_active; - s64 it_overrun; - s64 it_overrun_last; - int it_requeue_pending; - int it_sigev_notify; - ktime_t it_interval; - struct signal_struct *it_signal; - union { - struct pid *it_pid; - struct task_struct *it_process; - }; - struct sigqueue *sigq; - union { - struct { - struct hrtimer timer; - } real; - struct cpu_timer cpu; - struct { - struct alarm alarmtimer; - } alarm; - } it; - struct callback_head rcu; -}; - -struct k_clock { - int (*clock_getres)(const clockid_t, struct timespec64 *); - int (*clock_set)(const clockid_t, const struct timespec64 *); - int (*clock_get_timespec)(const clockid_t, struct timespec64 *); - ktime_t (*clock_get_ktime)(const clockid_t); - int (*clock_adj)(const clockid_t, struct __kernel_timex *); - int (*timer_create)(struct k_itimer *); - int (*nsleep)(const clockid_t, int, const struct timespec64 *); - int (*timer_set)(struct k_itimer *, int, struct itimerspec64 *, struct itimerspec64 *); - int (*timer_del)(struct k_itimer *); - void (*timer_get)(struct k_itimer *, struct itimerspec64 *); - void (*timer_rearm)(struct k_itimer *); - s64 (*timer_forward)(struct k_itimer *, ktime_t); - ktime_t (*timer_remaining)(struct k_itimer *, ktime_t); - int (*timer_try_to_cancel)(struct k_itimer *); - void (*timer_arm)(struct k_itimer *, ktime_t, bool, bool); - void (*timer_wait_running)(struct k_itimer *); -}; - -struct class_interface { - struct list_head node; - struct class *class; - int (*add_dev)(struct device *, struct class_interface *); - void (*remove_dev)(struct device *, struct class_interface *); -}; - -struct platform_driver { - int (*probe)(struct platform_device *); - int (*remove)(struct platform_device *); - void (*shutdown)(struct platform_device *); - int (*suspend)(struct platform_device *, pm_message_t); - int (*resume)(struct platform_device *); - struct device_driver driver; - const struct platform_device_id *id_table; - bool prevent_deferred_probe; -}; - -struct trace_event_raw_alarmtimer_suspend { - struct trace_entry ent; - s64 expires; - unsigned char alarm_type; - char __data[0]; -}; - -struct trace_event_raw_alarm_class { - struct trace_entry ent; - void *alarm; - unsigned char alarm_type; - s64 expires; - s64 now; - char __data[0]; -}; - -struct trace_event_data_offsets_alarmtimer_suspend {}; - -struct trace_event_data_offsets_alarm_class {}; - -typedef void (*btf_trace_alarmtimer_suspend)(void *, ktime_t, int); - -typedef void (*btf_trace_alarmtimer_fired)(void *, struct alarm *, ktime_t); - -typedef void (*btf_trace_alarmtimer_start)(void *, struct alarm *, ktime_t); - -typedef void (*btf_trace_alarmtimer_cancel)(void *, struct alarm *, ktime_t); - -struct alarm_base { - spinlock_t lock; - struct timerqueue_head timerqueue; - ktime_t (*get_ktime)(); - void (*get_timespec)(struct timespec64 *); - clockid_t base_clockid; -}; - -struct sigevent { - sigval_t sigev_value; - int sigev_signo; - int sigev_notify; - union { - int _pad[12]; - int _tid; - struct { - void (*_function)(sigval_t); - void *_attribute; - } _sigev_thread; - } _sigev_un; -}; - -typedef struct sigevent sigevent_t; - -struct compat_sigevent { - compat_sigval_t sigev_value; - compat_int_t sigev_signo; - compat_int_t sigev_notify; - union { - compat_int_t _pad[13]; - compat_int_t _tid; - struct { - compat_uptr_t _function; - compat_uptr_t _attribute; - } _sigev_thread; - } _sigev_un; -}; - -struct posix_clock; - -struct posix_clock_operations { - struct module *owner; - int (*clock_adjtime)(struct posix_clock *, struct __kernel_timex *); - int (*clock_gettime)(struct posix_clock *, struct timespec64 *); - int (*clock_getres)(struct posix_clock *, struct timespec64 *); - int (*clock_settime)(struct posix_clock *, const struct timespec64 *); - long int (*ioctl)(struct posix_clock *, unsigned int, long unsigned int); - int (*open)(struct posix_clock *, fmode_t); - __poll_t (*poll)(struct posix_clock *, struct file *, poll_table *); - int (*release)(struct posix_clock *); - ssize_t (*read)(struct posix_clock *, uint, char *, size_t); -}; - -struct posix_clock { - struct posix_clock_operations ops; - struct cdev cdev; - struct device *dev; - struct rw_semaphore rwsem; - bool zombie; -}; - -struct posix_clock_desc { - struct file *fp; - struct posix_clock *clk; -}; - -struct __kernel_old_itimerval { - struct __kernel_old_timeval it_interval; - struct __kernel_old_timeval it_value; -}; - -struct old_itimerval32 { - struct old_timeval32 it_interval; - struct old_timeval32 it_value; -}; - -struct ce_unbind { - struct clock_event_device *ce; - int res; -}; - -struct proc_timens_offset { - int clockid; - struct timespec64 val; -}; - -union futex_key { - struct { - u64 i_seq; - long unsigned int pgoff; - unsigned int offset; - } shared; - struct { - union { - struct mm_struct *mm; - u64 __tmp; - }; - long unsigned int address; - unsigned int offset; - } private; - struct { - u64 ptr; - long unsigned int word; - unsigned int offset; - } both; -}; - -struct futex_pi_state { - struct list_head list; - struct rt_mutex pi_mutex; - struct task_struct *owner; - refcount_t refcount; - union futex_key key; -}; - -struct futex_q { - struct plist_node list; - struct task_struct *task; - spinlock_t *lock_ptr; - union futex_key key; - struct futex_pi_state *pi_state; - struct rt_mutex_waiter *rt_waiter; - union futex_key *requeue_pi_key; - u32 bitset; -}; - -struct futex_hash_bucket { - atomic_t waiters; - spinlock_t lock; - struct plist_head chain; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum futex_access { - FUTEX_READ = 0, - FUTEX_WRITE = 1, -}; - -struct dma_chan { - int lock; - const char *device_id; -}; - -struct cfd_percpu { - call_single_data_t csd; -}; - -struct call_function_data { - struct cfd_percpu *pcpu; - cpumask_var_t cpumask; - cpumask_var_t cpumask_ipi; -}; - -struct smp_call_on_cpu_struct { - struct work_struct work; - struct completion done; - int (*func)(void *); - void *data; - int ret; - int cpu; -}; - -struct latch_tree_root { - seqcount_latch_t seq; - struct rb_root tree[2]; -}; - -struct latch_tree_ops { - bool (*less)(struct latch_tree_node *, struct latch_tree_node *); - int (*comp)(void *, struct latch_tree_node *); -}; - -struct module_use { - struct list_head source_list; - struct list_head target_list; - struct module *source; - struct module *target; -}; - -struct module_sect_attr { - struct bin_attribute battr; - long unsigned int address; -}; - -struct module_sect_attrs { - struct attribute_group grp; - unsigned int nsections; - struct module_sect_attr attrs[0]; -}; - -struct module_notes_attrs { - struct kobject *dir; - unsigned int notes; - struct bin_attribute attrs[0]; -}; - -enum kernel_read_file_id { - READING_UNKNOWN = 0, - READING_FIRMWARE = 1, - READING_MODULE = 2, - READING_KEXEC_IMAGE = 3, - READING_KEXEC_INITRAMFS = 4, - READING_POLICY = 5, - READING_X509_CERTIFICATE = 6, - READING_MAX_ID = 7, -}; - -enum kernel_load_data_id { - LOADING_UNKNOWN = 0, - LOADING_FIRMWARE = 1, - LOADING_MODULE = 2, - LOADING_KEXEC_IMAGE = 3, - LOADING_KEXEC_INITRAMFS = 4, - LOADING_POLICY = 5, - LOADING_X509_CERTIFICATE = 6, - LOADING_MAX_ID = 7, -}; - -enum { - PROC_ENTRY_PERMANENT = 1, -}; - -struct load_info { - const char *name; - struct module *mod; - Elf64_Ehdr *hdr; - long unsigned int len; - Elf64_Shdr *sechdrs; - char *secstrings; - char *strtab; - long unsigned int symoffs; - long unsigned int stroffs; - long unsigned int init_typeoffs; - long unsigned int core_typeoffs; - struct _ddebug *debug; - unsigned int num_debug; - bool sig_ok; - long unsigned int mod_kallsyms_init_off; - struct { - unsigned int sym; - unsigned int str; - unsigned int mod; - unsigned int vers; - unsigned int info; - unsigned int pcpu; - } index; -}; - -struct trace_event_raw_module_load { - struct trace_entry ent; - unsigned int taints; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_module_free { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_module_refcnt { - struct trace_entry ent; - long unsigned int ip; - int refcnt; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_module_request { - struct trace_entry ent; - long unsigned int ip; - bool wait; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_data_offsets_module_load { - u32 name; -}; - -struct trace_event_data_offsets_module_free { - u32 name; -}; - -struct trace_event_data_offsets_module_refcnt { - u32 name; -}; - -struct trace_event_data_offsets_module_request { - u32 name; -}; - -typedef void (*btf_trace_module_load)(void *, struct module *); - -typedef void (*btf_trace_module_free)(void *, struct module *); - -typedef void (*btf_trace_module_get)(void *, struct module *, long unsigned int); - -typedef void (*btf_trace_module_put)(void *, struct module *, long unsigned int); - -typedef void (*btf_trace_module_request)(void *, char *, bool, long unsigned int); - -struct mod_tree_root { - struct latch_tree_root root; - long unsigned int addr_min; - long unsigned int addr_max; -}; - -enum mod_license { - NOT_GPL_ONLY = 0, - GPL_ONLY = 1, -}; - -struct symsearch { - const struct kernel_symbol *start; - const struct kernel_symbol *stop; - const s32 *crcs; - enum mod_license license; -}; - -struct find_symbol_arg { - const char *name; - bool gplok; - bool warn; - struct module *owner; - const s32 *crc; - const struct kernel_symbol *sym; - enum mod_license license; -}; - -struct mod_initfree { - struct llist_node node; - void *module_init; -}; - -struct module_signature { - u8 algo; - u8 hash; - u8 id_type; - u8 signer_len; - u8 key_id_len; - u8 __pad[3]; - __be32 sig_len; -}; - -enum pkey_id_type { - PKEY_ID_PGP = 0, - PKEY_ID_X509 = 1, - PKEY_ID_PKCS7 = 2, -}; - -struct kallsym_iter { - loff_t pos; - loff_t pos_arch_end; - loff_t pos_mod_end; - loff_t pos_ftrace_mod_end; - loff_t pos_bpf_end; - long unsigned int value; - unsigned int nameoff; - char type; - char name[128]; - char module_name[56]; - int exported; - int show_value; -}; - -typedef __u16 comp_t; - -struct acct_v3 { - char ac_flag; - char ac_version; - __u16 ac_tty; - __u32 ac_exitcode; - __u32 ac_uid; - __u32 ac_gid; - __u32 ac_pid; - __u32 ac_ppid; - __u32 ac_btime; - __u32 ac_etime; - comp_t ac_utime; - comp_t ac_stime; - comp_t ac_mem; - comp_t ac_io; - comp_t ac_rw; - comp_t ac_minflt; - comp_t ac_majflt; - comp_t ac_swaps; - char ac_comm[16]; -}; - -typedef struct acct_v3 acct_t; - -struct fs_pin { - wait_queue_head_t wait; - int done; - struct hlist_node s_list; - struct hlist_node m_list; - void (*kill)(struct fs_pin *); -}; - -struct bsd_acct_struct { - struct fs_pin pin; - atomic_long_t count; - struct callback_head rcu; - struct mutex lock; - int active; - long unsigned int needcheck; - struct file *file; - struct pid_namespace *ns; - struct work_struct work; - struct completion done; -}; - -struct elf64_note { - Elf64_Word n_namesz; - Elf64_Word n_descsz; - Elf64_Word n_type; -}; - -typedef long unsigned int elf_greg_t; - -typedef elf_greg_t elf_gregset_t[27]; - -struct elf_siginfo { - int si_signo; - int si_code; - int si_errno; -}; - -struct elf_prstatus_common { - struct elf_siginfo pr_info; - short int pr_cursig; - long unsigned int pr_sigpend; - long unsigned int pr_sighold; - pid_t pr_pid; - pid_t pr_ppid; - pid_t pr_pgrp; - pid_t pr_sid; - struct __kernel_old_timeval pr_utime; - struct __kernel_old_timeval pr_stime; - struct __kernel_old_timeval pr_cutime; - struct __kernel_old_timeval pr_cstime; -}; - -struct elf_prstatus { - struct elf_prstatus_common common; - elf_gregset_t pr_reg; - int pr_fpvalid; -}; - -typedef u32 note_buf_t[92]; - -struct compat_kexec_segment { - compat_uptr_t buf; - compat_size_t bufsz; - compat_ulong_t mem; - compat_size_t memsz; -}; - -struct elf64_phdr { - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; - Elf64_Addr p_vaddr; - Elf64_Addr p_paddr; - Elf64_Xword p_filesz; - Elf64_Xword p_memsz; - Elf64_Xword p_align; -}; - -typedef struct elf64_phdr Elf64_Phdr; - -struct shash_alg { - int (*init)(struct shash_desc *); - int (*update)(struct shash_desc *, const u8 *, unsigned int); - int (*final)(struct shash_desc *, u8 *); - int (*finup)(struct shash_desc *, const u8 *, unsigned int, u8 *); - int (*digest)(struct shash_desc *, const u8 *, unsigned int, u8 *); - int (*export)(struct shash_desc *, void *); - int (*import)(struct shash_desc *, const void *); - int (*setkey)(struct crypto_shash *, const u8 *, unsigned int); - int (*init_tfm)(struct crypto_shash *); - void (*exit_tfm)(struct crypto_shash *); - unsigned int descsize; - int: 32; - unsigned int digestsize; - unsigned int statesize; - struct crypto_alg base; -}; - -struct kexec_sha_region { - long unsigned int start; - long unsigned int len; -}; - -enum migrate_reason { - MR_COMPACTION = 0, - MR_MEMORY_FAILURE = 1, - MR_MEMORY_HOTPLUG = 2, - MR_SYSCALL = 3, - MR_MEMPOLICY_MBIND = 4, - MR_NUMA_MISPLACED = 5, - MR_CONTIG_RANGE = 6, - MR_LONGTERM_PIN = 7, - MR_TYPES = 8, -}; - -typedef __kernel_ulong_t ino_t; - -enum bpf_link_type { - BPF_LINK_TYPE_UNSPEC = 0, - BPF_LINK_TYPE_RAW_TRACEPOINT = 1, - BPF_LINK_TYPE_TRACING = 2, - BPF_LINK_TYPE_CGROUP = 3, - BPF_LINK_TYPE_ITER = 4, - BPF_LINK_TYPE_NETNS = 5, - BPF_LINK_TYPE_XDP = 6, - MAX_BPF_LINK_TYPE = 7, -}; - -struct bpf_link_info { - __u32 type; - __u32 id; - __u32 prog_id; - union { - struct { - __u64 tp_name; - __u32 tp_name_len; - } raw_tracepoint; - struct { - __u32 attach_type; - __u32 target_obj_id; - __u32 target_btf_id; - } tracing; - struct { - __u64 cgroup_id; - __u32 attach_type; - } cgroup; - struct { - __u64 target_name; - __u32 target_name_len; - union { - struct { - __u32 map_id; - } map; - }; - } iter; - struct { - __u32 netns_ino; - __u32 attach_type; - } netns; - struct { - __u32 ifindex; - } xdp; - }; -}; - -struct bpf_link_ops; - -struct bpf_link { - atomic64_t refcnt; - u32 id; - enum bpf_link_type type; - const struct bpf_link_ops *ops; - struct bpf_prog *prog; - struct work_struct work; -}; - -struct bpf_link_ops { - void (*release)(struct bpf_link *); - void (*dealloc)(struct bpf_link *); - int (*detach)(struct bpf_link *); - int (*update_prog)(struct bpf_link *, struct bpf_prog *, struct bpf_prog *); - void (*show_fdinfo)(const struct bpf_link *, struct seq_file *); - int (*fill_link_info)(const struct bpf_link *, struct bpf_link_info *); -}; - -struct bpf_cgroup_link { - struct bpf_link link; - struct cgroup *cgroup; - enum bpf_attach_type type; -}; - -enum { - CGRP_NOTIFY_ON_RELEASE = 0, - CGRP_CPUSET_CLONE_CHILDREN = 1, - CGRP_FREEZE = 2, - CGRP_FROZEN = 3, - CGRP_KILL = 4, -}; - -enum { - CGRP_ROOT_NOPREFIX = 2, - CGRP_ROOT_XATTR = 4, - CGRP_ROOT_NS_DELEGATE = 8, - CGRP_ROOT_CPUSET_V2_MODE = 16, - CGRP_ROOT_MEMORY_LOCAL_EVENTS = 32, - CGRP_ROOT_MEMORY_RECURSIVE_PROT = 64, -}; - -struct cgroup_taskset { - struct list_head src_csets; - struct list_head dst_csets; - int nr_tasks; - int ssid; - struct list_head *csets; - struct css_set *cur_cset; - struct task_struct *cur_task; -}; - -struct cgroup_fs_context { - struct kernfs_fs_context kfc; - struct cgroup_root *root; - struct cgroup_namespace *ns; - unsigned int flags; - bool cpuset_clone_children; - bool none; - bool all_ss; - u16 subsys_mask; - char *name; - char *release_agent; -}; - -struct cgrp_cset_link { - struct cgroup *cgrp; - struct css_set *cset; - struct list_head cset_link; - struct list_head cgrp_link; -}; - -struct cgroup_mgctx { - struct list_head preloaded_src_csets; - struct list_head preloaded_dst_csets; - struct cgroup_taskset tset; - u16 ss_mask; -}; - -struct trace_event_raw_cgroup_root { - struct trace_entry ent; - int root; - u16 ss_mask; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_cgroup { - struct trace_entry ent; - int root; - int id; - int level; - u32 __data_loc_path; - char __data[0]; -}; - -struct trace_event_raw_cgroup_migrate { - struct trace_entry ent; - int dst_root; - int dst_id; - int dst_level; - int pid; - u32 __data_loc_dst_path; - u32 __data_loc_comm; - char __data[0]; -}; - -struct trace_event_raw_cgroup_event { - struct trace_entry ent; - int root; - int id; - int level; - u32 __data_loc_path; - int val; - char __data[0]; -}; - -struct trace_event_data_offsets_cgroup_root { - u32 name; -}; - -struct trace_event_data_offsets_cgroup { - u32 path; -}; - -struct trace_event_data_offsets_cgroup_migrate { - u32 dst_path; - u32 comm; -}; - -struct trace_event_data_offsets_cgroup_event { - u32 path; -}; - -typedef void (*btf_trace_cgroup_setup_root)(void *, struct cgroup_root *); - -typedef void (*btf_trace_cgroup_destroy_root)(void *, struct cgroup_root *); - -typedef void (*btf_trace_cgroup_remount)(void *, struct cgroup_root *); - -typedef void (*btf_trace_cgroup_mkdir)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_rmdir)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_release)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_rename)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_freeze)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_unfreeze)(void *, struct cgroup *, const char *); - -typedef void (*btf_trace_cgroup_attach_task)(void *, struct cgroup *, const char *, struct task_struct *, bool); - -typedef void (*btf_trace_cgroup_transfer_tasks)(void *, struct cgroup *, const char *, struct task_struct *, bool); - -typedef void (*btf_trace_cgroup_notify_populated)(void *, struct cgroup *, const char *, int); - -typedef void (*btf_trace_cgroup_notify_frozen)(void *, struct cgroup *, const char *, int); - -enum cgroup_opt_features { - OPT_FEATURE_PRESSURE = 0, - OPT_FEATURE_COUNT = 1, -}; - -enum cgroup2_param { - Opt_nsdelegate = 0, - Opt_memory_localevents = 1, - Opt_memory_recursiveprot = 2, - nr__cgroup2_params = 3, -}; - -struct cgroupstats { - __u64 nr_sleeping; - __u64 nr_running; - __u64 nr_stopped; - __u64 nr_uninterruptible; - __u64 nr_io_wait; -}; - -enum cgroup_filetype { - CGROUP_FILE_PROCS = 0, - CGROUP_FILE_TASKS = 1, -}; - -struct cgroup_pidlist { - struct { - enum cgroup_filetype type; - struct pid_namespace *ns; - } key; - pid_t *list; - int length; - struct list_head links; - struct cgroup *owner; - struct delayed_work destroy_dwork; -}; - -enum cgroup1_param { - Opt_all = 0, - Opt_clone_children = 1, - Opt_cpuset_v2_mode = 2, - Opt_name = 3, - Opt_none = 4, - Opt_noprefix = 5, - Opt_release_agent = 6, - Opt_xattr = 7, -}; - -enum freezer_state_flags { - CGROUP_FREEZER_ONLINE = 1, - CGROUP_FREEZING_SELF = 2, - CGROUP_FREEZING_PARENT = 4, - CGROUP_FROZEN = 8, - CGROUP_FREEZING = 6, -}; - -struct freezer { - struct cgroup_subsys_state css; - unsigned int state; -}; - -struct pids_cgroup { - struct cgroup_subsys_state css; - atomic64_t counter; - atomic64_t limit; - struct cgroup_file events_file; - atomic64_t events_limit; -}; - -typedef struct { - char *from; - char *to; -} substring_t; - -enum rdmacg_resource_type { - RDMACG_RESOURCE_HCA_HANDLE = 0, - RDMACG_RESOURCE_HCA_OBJECT = 1, - RDMACG_RESOURCE_MAX = 2, -}; - -struct rdma_cgroup { - struct cgroup_subsys_state css; - struct list_head rpools; -}; - -struct rdmacg_device { - struct list_head dev_node; - struct list_head rpools; - char *name; -}; - -enum rdmacg_file_type { - RDMACG_RESOURCE_TYPE_MAX = 0, - RDMACG_RESOURCE_TYPE_STAT = 1, -}; - -struct rdmacg_resource { - int max; - int usage; -}; - -struct rdmacg_resource_pool { - struct rdmacg_device *device; - struct rdmacg_resource resources[2]; - struct list_head cg_node; - struct list_head dev_node; - u64 usage_sum; - int num_max_cnt; -}; - -struct root_domain___2; - -struct fmeter { - int cnt; - int val; - time64_t time; - spinlock_t lock; -}; - -struct cpuset { - struct cgroup_subsys_state css; - long unsigned int flags; - cpumask_var_t cpus_allowed; - nodemask_t mems_allowed; - cpumask_var_t effective_cpus; - nodemask_t effective_mems; - cpumask_var_t subparts_cpus; - nodemask_t old_mems_allowed; - struct fmeter fmeter; - int attach_in_progress; - int pn; - int relax_domain_level; - int nr_subparts_cpus; - int partition_root_state; - int use_parent_ecpus; - int child_ecpus_count; -}; - -struct tmpmasks { - cpumask_var_t addmask; - cpumask_var_t delmask; - cpumask_var_t new_cpus; -}; - -typedef enum { - CS_ONLINE = 0, - CS_CPU_EXCLUSIVE = 1, - CS_MEM_EXCLUSIVE = 2, - CS_MEM_HARDWALL = 3, - CS_MEMORY_MIGRATE = 4, - CS_SCHED_LOAD_BALANCE = 5, - CS_SPREAD_PAGE = 6, - CS_SPREAD_SLAB = 7, -} cpuset_flagbits_t; - -enum subparts_cmd { - partcmd_enable = 0, - partcmd_disable = 1, - partcmd_update = 2, -}; - -struct cpuset_migrate_mm_work { - struct work_struct work; - struct mm_struct *mm; - nodemask_t from; - nodemask_t to; -}; - -typedef enum { - FILE_MEMORY_MIGRATE = 0, - FILE_CPULIST = 1, - FILE_MEMLIST = 2, - FILE_EFFECTIVE_CPULIST = 3, - FILE_EFFECTIVE_MEMLIST = 4, - FILE_SUBPARTS_CPULIST = 5, - FILE_CPU_EXCLUSIVE = 6, - FILE_MEM_EXCLUSIVE = 7, - FILE_MEM_HARDWALL = 8, - FILE_SCHED_LOAD_BALANCE = 9, - FILE_PARTITION_ROOT = 10, - FILE_SCHED_RELAX_DOMAIN_LEVEL = 11, - FILE_MEMORY_PRESSURE_ENABLED = 12, - FILE_MEMORY_PRESSURE = 13, - FILE_SPREAD_PAGE = 14, - FILE_SPREAD_SLAB = 15, -} cpuset_filetype_t; - -enum misc_res_type { - MISC_CG_RES_SEV = 0, - MISC_CG_RES_SEV_ES = 1, - MISC_CG_RES_TYPES = 2, -}; - -struct misc_res { - long unsigned int max; - atomic_long_t usage; - bool failed; -}; - -struct misc_cg { - struct cgroup_subsys_state css; - struct misc_res res[2]; -}; - -struct kernel_pkey_query { - __u32 supported_ops; - __u32 key_size; - __u16 max_data_size; - __u16 max_sig_size; - __u16 max_enc_size; - __u16 max_dec_size; -}; - -enum kernel_pkey_operation { - kernel_pkey_encrypt = 0, - kernel_pkey_decrypt = 1, - kernel_pkey_sign = 2, - kernel_pkey_verify = 3, -}; - -struct kernel_pkey_params { - struct key *key; - const char *encoding; - const char *hash_algo; - char *info; - __u32 in_len; - union { - __u32 out_len; - __u32 in2_len; - }; - enum kernel_pkey_operation op: 8; -}; - -struct key_preparsed_payload { - const char *orig_description; - char *description; - union key_payload payload; - const void *data; - size_t datalen; - size_t quotalen; - time64_t expiry; -}; - -struct key_match_data { - bool (*cmp)(const struct key *, const struct key_match_data *); - const void *raw_data; - void *preparsed; - unsigned int lookup_type; -}; - -struct idmap_key { - bool map_up; - u32 id; - u32 count; -}; - -struct ctl_path { - const char *procname; -}; - -struct cpu_stop_done { - atomic_t nr_todo; - int ret; - struct completion completion; -}; - -struct cpu_stopper { - struct task_struct *thread; - raw_spinlock_t lock; - bool enabled; - struct list_head works; - struct cpu_stop_work stop_work; - long unsigned int caller; - cpu_stop_fn_t fn; -}; - -enum multi_stop_state { - MULTI_STOP_NONE = 0, - MULTI_STOP_PREPARE = 1, - MULTI_STOP_DISABLE_IRQ = 2, - MULTI_STOP_RUN = 3, - MULTI_STOP_EXIT = 4, -}; - -struct multi_stop_data { - cpu_stop_fn_t fn; - void *data; - unsigned int num_threads; - const struct cpumask *active_cpus; - enum multi_stop_state state; - atomic_t thread_ack; -}; - -typedef int __kernel_mqd_t; - -typedef __kernel_mqd_t mqd_t; - -enum audit_state { - AUDIT_STATE_DISABLED = 0, - AUDIT_STATE_BUILD = 1, - AUDIT_STATE_RECORD = 2, -}; - -struct audit_cap_data { - kernel_cap_t permitted; - kernel_cap_t inheritable; - union { - unsigned int fE; - kernel_cap_t effective; - }; - kernel_cap_t ambient; - kuid_t rootid; -}; - -struct audit_names { - struct list_head list; - struct filename *name; - int name_len; - bool hidden; - long unsigned int ino; - dev_t dev; - umode_t mode; - kuid_t uid; - kgid_t gid; - dev_t rdev; - u32 osid; - struct audit_cap_data fcap; - unsigned int fcap_ver; - unsigned char type; - bool should_free; -}; - -struct mq_attr { - __kernel_long_t mq_flags; - __kernel_long_t mq_maxmsg; - __kernel_long_t mq_msgsize; - __kernel_long_t mq_curmsgs; - __kernel_long_t __reserved[4]; -}; - -struct audit_proctitle { - int len; - char *value; -}; - -struct audit_aux_data; - -struct __kernel_sockaddr_storage; - -struct audit_tree_refs; - -struct audit_context { - int dummy; - int in_syscall; - enum audit_state state; - enum audit_state current_state; - unsigned int serial; - int major; - struct timespec64 ctime; - long unsigned int argv[4]; - long int return_code; - u64 prio; - int return_valid; - struct audit_names preallocated_names[5]; - int name_count; - struct list_head names_list; - char *filterkey; - struct path pwd; - struct audit_aux_data *aux; - struct audit_aux_data *aux_pids; - struct __kernel_sockaddr_storage *sockaddr; - size_t sockaddr_len; - pid_t pid; - pid_t ppid; - kuid_t uid; - kuid_t euid; - kuid_t suid; - kuid_t fsuid; - kgid_t gid; - kgid_t egid; - kgid_t sgid; - kgid_t fsgid; - long unsigned int personality; - int arch; - pid_t target_pid; - kuid_t target_auid; - kuid_t target_uid; - unsigned int target_sessionid; - u32 target_sid; - char target_comm[16]; - struct audit_tree_refs *trees; - struct audit_tree_refs *first_trees; - struct list_head killed_trees; - int tree_count; - int type; - union { - struct { - int nargs; - long int args[6]; - } socketcall; - struct { - kuid_t uid; - kgid_t gid; - umode_t mode; - u32 osid; - int has_perm; - uid_t perm_uid; - gid_t perm_gid; - umode_t perm_mode; - long unsigned int qbytes; - } ipc; - struct { - mqd_t mqdes; - struct mq_attr mqstat; - } mq_getsetattr; - struct { - mqd_t mqdes; - int sigev_signo; - } mq_notify; - struct { - mqd_t mqdes; - size_t msg_len; - unsigned int msg_prio; - struct timespec64 abs_timeout; - } mq_sendrecv; - struct { - int oflag; - umode_t mode; - struct mq_attr attr; - } mq_open; - struct { - pid_t pid; - struct audit_cap_data cap; - } capset; - struct { - int fd; - int flags; - } mmap; - struct { - int argc; - } execve; - struct { - char *name; - } module; - }; - int fds[2]; - struct audit_proctitle proctitle; -}; - -struct __kernel_sockaddr_storage { - union { - struct { - __kernel_sa_family_t ss_family; - char __data[126]; - }; - void *__align; - }; -}; - -enum audit_nlgrps { - AUDIT_NLGRP_NONE = 0, - AUDIT_NLGRP_READLOG = 1, - __AUDIT_NLGRP_MAX = 2, -}; - -struct audit_status { - __u32 mask; - __u32 enabled; - __u32 failure; - __u32 pid; - __u32 rate_limit; - __u32 backlog_limit; - __u32 lost; - __u32 backlog; - union { - __u32 version; - __u32 feature_bitmap; - }; - __u32 backlog_wait_time; - __u32 backlog_wait_time_actual; -}; - -struct audit_features { - __u32 vers; - __u32 mask; - __u32 features; - __u32 lock; -}; - -struct audit_tty_status { - __u32 enabled; - __u32 log_passwd; -}; - -struct audit_sig_info { - uid_t uid; - pid_t pid; - char ctx[0]; -}; - -struct net_generic { - union { - struct { - unsigned int len; - struct callback_head rcu; - } s; - void *ptr[0]; - }; -}; - -struct pernet_operations { - struct list_head list; - int (*init)(struct net *); - void (*pre_exit)(struct net *); - void (*exit)(struct net *); - void (*exit_batch)(struct list_head *); - unsigned int *id; - size_t size; -}; - -struct scm_creds { - u32 pid; - kuid_t uid; - kgid_t gid; -}; - -struct netlink_skb_parms { - struct scm_creds creds; - __u32 portid; - __u32 dst_group; - __u32 flags; - struct sock *sk; - bool nsid_is_set; - int nsid; -}; - -struct netlink_kernel_cfg { - unsigned int groups; - unsigned int flags; - void (*input)(struct sk_buff *); - struct mutex *cb_mutex; - int (*bind)(struct net *, int); - void (*unbind)(struct net *, int); - bool (*compare)(struct net *, struct sock *); -}; - -struct audit_netlink_list { - __u32 portid; - struct net *net; - struct sk_buff_head q; -}; - -struct audit_net { - struct sock *sk; -}; - -struct auditd_connection { - struct pid *pid; - u32 portid; - struct net *net; - struct callback_head rcu; -}; - -struct audit_ctl_mutex { - struct mutex lock; - void *owner; -}; - -struct audit_buffer { - struct sk_buff *skb; - struct audit_context *ctx; - gfp_t gfp_mask; -}; - -struct audit_reply { - __u32 portid; - struct net *net; - struct sk_buff *skb; -}; - -enum { - Audit_equal = 0, - Audit_not_equal = 1, - Audit_bitmask = 2, - Audit_bittest = 3, - Audit_lt = 4, - Audit_gt = 5, - Audit_le = 6, - Audit_ge = 7, - Audit_bad = 8, -}; - -struct audit_rule_data { - __u32 flags; - __u32 action; - __u32 field_count; - __u32 mask[64]; - __u32 fields[64]; - __u32 values[64]; - __u32 fieldflags[64]; - __u32 buflen; - char buf[0]; -}; - -struct audit_field; - -struct audit_watch; - -struct audit_tree; - -struct audit_fsnotify_mark; - -struct audit_krule { - u32 pflags; - u32 flags; - u32 listnr; - u32 action; - u32 mask[64]; - u32 buflen; - u32 field_count; - char *filterkey; - struct audit_field *fields; - struct audit_field *arch_f; - struct audit_field *inode_f; - struct audit_watch *watch; - struct audit_tree *tree; - struct audit_fsnotify_mark *exe; - struct list_head rlist; - struct list_head list; - u64 prio; -}; - -struct audit_field { - u32 type; - union { - u32 val; - kuid_t uid; - kgid_t gid; - struct { - char *lsm_str; - void *lsm_rule; - }; - }; - u32 op; -}; - -struct audit_entry { - struct list_head list; - struct callback_head rcu; - struct audit_krule rule; -}; - -struct audit_buffer___2; - -typedef int __kernel_key_t; - -typedef __kernel_key_t key_t; - -struct cpu_vfs_cap_data { - __u32 magic_etc; - kernel_cap_t permitted; - kernel_cap_t inheritable; - kuid_t rootid; -}; - -struct kern_ipc_perm { - spinlock_t lock; - bool deleted; - int id; - key_t key; - kuid_t uid; - kgid_t gid; - kuid_t cuid; - kgid_t cgid; - umode_t mode; - long unsigned int seq; - void *security; - struct rhash_head khtnode; - struct callback_head rcu; - refcount_t refcount; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef struct fsnotify_mark_connector *fsnotify_connp_t; - -struct fsnotify_mark_connector { - spinlock_t lock; - short unsigned int type; - short unsigned int flags; - __kernel_fsid_t fsid; - union { - fsnotify_connp_t *obj; - struct fsnotify_mark_connector *destroy_next; - }; - struct hlist_head list; -}; - -enum audit_nfcfgop { - AUDIT_XT_OP_REGISTER = 0, - AUDIT_XT_OP_REPLACE = 1, - AUDIT_XT_OP_UNREGISTER = 2, - AUDIT_NFT_OP_TABLE_REGISTER = 3, - AUDIT_NFT_OP_TABLE_UNREGISTER = 4, - AUDIT_NFT_OP_CHAIN_REGISTER = 5, - AUDIT_NFT_OP_CHAIN_UNREGISTER = 6, - AUDIT_NFT_OP_RULE_REGISTER = 7, - AUDIT_NFT_OP_RULE_UNREGISTER = 8, - AUDIT_NFT_OP_SET_REGISTER = 9, - AUDIT_NFT_OP_SET_UNREGISTER = 10, - AUDIT_NFT_OP_SETELEM_REGISTER = 11, - AUDIT_NFT_OP_SETELEM_UNREGISTER = 12, - AUDIT_NFT_OP_GEN_REGISTER = 13, - AUDIT_NFT_OP_OBJ_REGISTER = 14, - AUDIT_NFT_OP_OBJ_UNREGISTER = 15, - AUDIT_NFT_OP_OBJ_RESET = 16, - AUDIT_NFT_OP_FLOWTABLE_REGISTER = 17, - AUDIT_NFT_OP_FLOWTABLE_UNREGISTER = 18, - AUDIT_NFT_OP_INVALID = 19, -}; - -enum fsnotify_obj_type { - FSNOTIFY_OBJ_TYPE_INODE = 0, - FSNOTIFY_OBJ_TYPE_PARENT = 1, - FSNOTIFY_OBJ_TYPE_VFSMOUNT = 2, - FSNOTIFY_OBJ_TYPE_SB = 3, - FSNOTIFY_OBJ_TYPE_COUNT = 4, - FSNOTIFY_OBJ_TYPE_DETACHED = 4, -}; - -struct audit_aux_data { - struct audit_aux_data *next; - int type; -}; - -struct audit_chunk; - -struct audit_tree_refs { - struct audit_tree_refs *next; - struct audit_chunk *c[31]; -}; - -struct audit_aux_data_pids { - struct audit_aux_data d; - pid_t target_pid[16]; - kuid_t target_auid[16]; - kuid_t target_uid[16]; - unsigned int target_sessionid[16]; - u32 target_sid[16]; - char target_comm[256]; - int pid_count; -}; - -struct audit_aux_data_bprm_fcaps { - struct audit_aux_data d; - struct audit_cap_data fcap; - unsigned int fcap_ver; - struct audit_cap_data old_pcap; - struct audit_cap_data new_pcap; -}; - -struct audit_nfcfgop_tab { - enum audit_nfcfgop op; - const char *s; -}; - -struct audit_parent; - -struct audit_watch { - refcount_t count; - dev_t dev; - char *path; - long unsigned int ino; - struct audit_parent *parent; - struct list_head wlist; - struct list_head rules; -}; - -struct fsnotify_group; - -struct fsnotify_iter_info; - -struct fsnotify_mark; - -struct fsnotify_event; - -struct fsnotify_ops { - int (*handle_event)(struct fsnotify_group *, u32, const void *, int, struct inode *, const struct qstr *, u32, struct fsnotify_iter_info *); - int (*handle_inode_event)(struct fsnotify_mark *, u32, struct inode *, struct inode *, const struct qstr *, u32); - void (*free_group_priv)(struct fsnotify_group *); - void (*freeing_mark)(struct fsnotify_mark *, struct fsnotify_group *); - void (*free_event)(struct fsnotify_event *); - void (*free_mark)(struct fsnotify_mark *); -}; - -struct inotify_group_private_data { - spinlock_t idr_lock; - struct idr idr; - struct ucounts *ucounts; -}; - -struct fanotify_group_private_data { - struct hlist_head *merge_hash; - struct list_head access_list; - wait_queue_head_t access_waitq; - int flags; - int f_flags; - struct ucounts *ucounts; -}; - -struct fsnotify_group { - const struct fsnotify_ops *ops; - refcount_t refcnt; - spinlock_t notification_lock; - struct list_head notification_list; - wait_queue_head_t notification_waitq; - unsigned int q_len; - unsigned int max_events; - unsigned int priority; - bool shutdown; - struct mutex mark_mutex; - atomic_t user_waits; - struct list_head marks_list; - struct fasync_struct *fsn_fa; - struct fsnotify_event *overflow_event; - struct mem_cgroup *memcg; - union { - void *private; - struct inotify_group_private_data inotify_data; - struct fanotify_group_private_data fanotify_data; - }; -}; - -struct fsnotify_iter_info { - struct fsnotify_mark *marks[4]; - unsigned int report_mask; - int srcu_idx; -}; - -struct fsnotify_mark { - __u32 mask; - refcount_t refcnt; - struct fsnotify_group *group; - struct list_head g_list; - spinlock_t lock; - struct hlist_node obj_list; - struct fsnotify_mark_connector *connector; - __u32 ignored_mask; - unsigned int flags; -}; - -struct fsnotify_event { - struct list_head list; -}; - -struct audit_parent { - struct list_head watches; - struct fsnotify_mark mark; -}; - -struct audit_fsnotify_mark { - dev_t dev; - long unsigned int ino; - char *path; - struct fsnotify_mark mark; - struct audit_krule *rule; -}; - -struct audit_chunk___2; - -struct audit_tree { - refcount_t count; - int goner; - struct audit_chunk___2 *root; - struct list_head chunks; - struct list_head rules; - struct list_head list; - struct list_head same_root; - struct callback_head head; - char pathname[0]; -}; - -struct node { - struct list_head list; - struct audit_tree *owner; - unsigned int index; -}; - -struct audit_chunk___2 { - struct list_head hash; - long unsigned int key; - struct fsnotify_mark *mark; - struct list_head trees; - int count; - atomic_long_t refs; - struct callback_head head; - struct node owners[0]; -}; - -struct audit_tree_mark { - struct fsnotify_mark mark; - struct audit_chunk___2 *chunk; -}; - -enum { - HASH_SIZE = 128, -}; - -struct kprobe_blacklist_entry { - struct list_head list; - long unsigned int start_addr; - long unsigned int end_addr; -}; - -enum perf_record_ksymbol_type { - PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0, - PERF_RECORD_KSYMBOL_TYPE_BPF = 1, - PERF_RECORD_KSYMBOL_TYPE_OOL = 2, - PERF_RECORD_KSYMBOL_TYPE_MAX = 3, -}; - -struct kprobe_insn_page { - struct list_head list; - kprobe_opcode_t *insns; - struct kprobe_insn_cache *cache; - int nused; - int ngarbage; - char slot_used[0]; -}; - -enum kprobe_slot_state { - SLOT_CLEAN = 0, - SLOT_DIRTY = 1, - SLOT_USED = 2, -}; - -struct seccomp_notif_sizes { - __u16 seccomp_notif; - __u16 seccomp_notif_resp; - __u16 seccomp_data; -}; - -struct seccomp_notif { - __u64 id; - __u32 pid; - __u32 flags; - struct seccomp_data data; -}; - -struct seccomp_notif_resp { - __u64 id; - __s64 val; - __s32 error; - __u32 flags; -}; - -struct seccomp_notif_addfd { - __u64 id; - __u32 flags; - __u32 srcfd; - __u32 newfd; - __u32 newfd_flags; -}; - -struct action_cache { - long unsigned int allow_native[7]; - long unsigned int allow_compat[7]; -}; - -struct notification; - -struct seccomp_filter { - refcount_t refs; - refcount_t users; - bool log; - struct action_cache cache; - struct seccomp_filter *prev; - struct bpf_prog *prog; - struct notification *notif; - struct mutex notify_lock; - wait_queue_head_t wqh; -}; - -struct seccomp_metadata { - __u64 filter_off; - __u64 flags; -}; - -struct sock_fprog { - short unsigned int len; - struct sock_filter *filter; -}; - -struct compat_sock_fprog { - u16 len; - compat_uptr_t filter; -}; - -typedef int (*bpf_aux_classic_check_t)(struct sock_filter *, unsigned int); - -enum notify_state { - SECCOMP_NOTIFY_INIT = 0, - SECCOMP_NOTIFY_SENT = 1, - SECCOMP_NOTIFY_REPLIED = 2, -}; - -struct seccomp_knotif { - struct task_struct *task; - u64 id; - const struct seccomp_data *data; - enum notify_state state; - int error; - long int val; - u32 flags; - struct completion ready; - struct list_head list; - struct list_head addfd; -}; - -struct seccomp_kaddfd { - struct file *file; - int fd; - unsigned int flags; - __u32 ioctl_flags; - union { - bool setfd; - int ret; - }; - struct completion completion; - struct list_head list; -}; - -struct notification { - struct semaphore request; - u64 next_id; - struct list_head notifications; -}; - -struct seccomp_log_name { - u32 log; - const char *name; -}; - -struct rchan; - -struct rchan_buf { - void *start; - void *data; - size_t offset; - size_t subbufs_produced; - size_t subbufs_consumed; - struct rchan *chan; - wait_queue_head_t read_wait; - struct irq_work wakeup_work; - struct dentry *dentry; - struct kref kref; - struct page **page_array; - unsigned int page_count; - unsigned int finalized; - size_t *padding; - size_t prev_padding; - size_t bytes_consumed; - size_t early_bytes; - unsigned int cpu; - long: 32; - long: 64; - long: 64; - long: 64; -}; - -struct rchan_callbacks; - -struct rchan { - u32 version; - size_t subbuf_size; - size_t n_subbufs; - size_t alloc_size; - const struct rchan_callbacks *cb; - struct kref kref; - void *private_data; - size_t last_toobig; - struct rchan_buf **buf; - int is_global; - struct list_head list; - struct dentry *parent; - int has_base_filename; - char base_filename[255]; -}; - -struct rchan_callbacks { - int (*subbuf_start)(struct rchan_buf *, void *, void *, size_t); - struct dentry * (*create_buf_file)(const char *, struct dentry *, umode_t, struct rchan_buf *, int *); - int (*remove_buf_file)(struct dentry *); -}; - -struct partial_page { - unsigned int offset; - unsigned int len; - long unsigned int private; -}; - -struct splice_pipe_desc { - struct page **pages; - struct partial_page *partial; - int nr_pages; - unsigned int nr_pages_max; - const struct pipe_buf_operations *ops; - void (*spd_release)(struct splice_pipe_desc *, unsigned int); -}; - -struct rchan_percpu_buf_dispatcher { - struct rchan_buf *buf; - struct dentry *dentry; -}; - -enum { - TASKSTATS_TYPE_UNSPEC = 0, - TASKSTATS_TYPE_PID = 1, - TASKSTATS_TYPE_TGID = 2, - TASKSTATS_TYPE_STATS = 3, - TASKSTATS_TYPE_AGGR_PID = 4, - TASKSTATS_TYPE_AGGR_TGID = 5, - TASKSTATS_TYPE_NULL = 6, - __TASKSTATS_TYPE_MAX = 7, -}; - -enum { - TASKSTATS_CMD_ATTR_UNSPEC = 0, - TASKSTATS_CMD_ATTR_PID = 1, - TASKSTATS_CMD_ATTR_TGID = 2, - TASKSTATS_CMD_ATTR_REGISTER_CPUMASK = 3, - TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 4, - __TASKSTATS_CMD_ATTR_MAX = 5, -}; - -enum { - CGROUPSTATS_CMD_UNSPEC = 3, - CGROUPSTATS_CMD_GET = 4, - CGROUPSTATS_CMD_NEW = 5, - __CGROUPSTATS_CMD_MAX = 6, -}; - -enum { - CGROUPSTATS_TYPE_UNSPEC = 0, - CGROUPSTATS_TYPE_CGROUP_STATS = 1, - __CGROUPSTATS_TYPE_MAX = 2, -}; - -enum { - CGROUPSTATS_CMD_ATTR_UNSPEC = 0, - CGROUPSTATS_CMD_ATTR_FD = 1, - __CGROUPSTATS_CMD_ATTR_MAX = 2, -}; - -struct genlmsghdr { - __u8 cmd; - __u8 version; - __u16 reserved; -}; - -enum { - NLA_UNSPEC = 0, - NLA_U8 = 1, - NLA_U16 = 2, - NLA_U32 = 3, - NLA_U64 = 4, - NLA_STRING = 5, - NLA_FLAG = 6, - NLA_MSECS = 7, - NLA_NESTED = 8, - NLA_NESTED_ARRAY = 9, - NLA_NUL_STRING = 10, - NLA_BINARY = 11, - NLA_S8 = 12, - NLA_S16 = 13, - NLA_S32 = 14, - NLA_S64 = 15, - NLA_BITFIELD32 = 16, - NLA_REJECT = 17, - __NLA_TYPE_MAX = 18, -}; - -struct genl_multicast_group { - char name[16]; - u8 flags; -}; - -struct genl_ops; - -struct genl_info; - -struct genl_small_ops; - -struct genl_family { - int id; - unsigned int hdrsize; - char name[16]; - unsigned int version; - unsigned int maxattr; - unsigned int mcgrp_offset; - u8 netnsok: 1; - u8 parallel_ops: 1; - u8 n_ops; - u8 n_small_ops; - u8 n_mcgrps; - const struct nla_policy *policy; - int (*pre_doit)(const struct genl_ops *, struct sk_buff *, struct genl_info *); - void (*post_doit)(const struct genl_ops *, struct sk_buff *, struct genl_info *); - const struct genl_ops *ops; - const struct genl_small_ops *small_ops; - const struct genl_multicast_group *mcgrps; - struct module *module; -}; - -struct genl_ops { - int (*doit)(struct sk_buff *, struct genl_info *); - int (*start)(struct netlink_callback *); - int (*dumpit)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - const struct nla_policy *policy; - unsigned int maxattr; - u8 cmd; - u8 internal_flags; - u8 flags; - u8 validate; -}; - -struct genl_info { - u32 snd_seq; - u32 snd_portid; - struct nlmsghdr *nlhdr; - struct genlmsghdr *genlhdr; - void *userhdr; - struct nlattr **attrs; - possible_net_t _net; - void *user_ptr[2]; - struct netlink_ext_ack *extack; -}; - -struct genl_small_ops { - int (*doit)(struct sk_buff *, struct genl_info *); - int (*dumpit)(struct sk_buff *, struct netlink_callback *); - u8 cmd; - u8 internal_flags; - u8 flags; - u8 validate; -}; - -enum genl_validate_flags { - GENL_DONT_VALIDATE_STRICT = 1, - GENL_DONT_VALIDATE_DUMP = 2, - GENL_DONT_VALIDATE_DUMP_STRICT = 4, -}; - -struct listener { - struct list_head list; - pid_t pid; - char valid; -}; - -struct listener_list { - struct rw_semaphore sem; - struct list_head list; -}; - -enum actions { - REGISTER = 0, - DEREGISTER = 1, - CPU_DONT_CARE = 2, -}; - -struct tp_module { - struct list_head list; - struct module *mod; -}; - -enum tp_func_state { - TP_FUNC_0 = 0, - TP_FUNC_1 = 1, - TP_FUNC_2 = 2, - TP_FUNC_N = 3, -}; - -enum tp_transition_sync { - TP_TRANSITION_SYNC_1_0_1 = 0, - TP_TRANSITION_SYNC_N_2_1 = 1, - _NR_TP_TRANSITION_SYNC = 2, -}; - -struct tp_transition_snapshot { - long unsigned int rcu; - long unsigned int srcu; - bool ongoing; -}; - -struct tp_probes { - struct callback_head rcu; - struct tracepoint_func probes[0]; -}; - -struct ftrace_hash { - long unsigned int size_bits; - struct hlist_head *buckets; - long unsigned int count; - long unsigned int flags; - struct callback_head rcu; -}; - -struct ftrace_func_entry { - struct hlist_node hlist; - long unsigned int ip; - long unsigned int direct; -}; - -enum ftrace_bug_type { - FTRACE_BUG_UNKNOWN = 0, - FTRACE_BUG_INIT = 1, - FTRACE_BUG_NOP = 2, - FTRACE_BUG_CALL = 3, - FTRACE_BUG_UPDATE = 4, -}; - -enum { - FTRACE_UPDATE_CALLS = 1, - FTRACE_DISABLE_CALLS = 2, - FTRACE_UPDATE_TRACE_FUNC = 4, - FTRACE_START_FUNC_RET = 8, - FTRACE_STOP_FUNC_RET = 16, - FTRACE_MAY_SLEEP = 32, -}; - -enum { - FTRACE_ITER_FILTER = 1, - FTRACE_ITER_NOTRACE = 2, - FTRACE_ITER_PRINTALL = 4, - FTRACE_ITER_DO_PROBES = 8, - FTRACE_ITER_PROBE = 16, - FTRACE_ITER_MOD = 32, - FTRACE_ITER_ENABLED = 64, -}; - -struct ftrace_graph_ent { - long unsigned int func; - int depth; -} __attribute__((packed)); - -struct ftrace_graph_ret { - long unsigned int func; - int depth; - unsigned int overrun; - long long unsigned int calltime; - long long unsigned int rettime; -}; - -typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); - -typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); - -struct fgraph_ops { - trace_func_graph_ent_t entryfunc; - trace_func_graph_ret_t retfunc; -}; - -struct prog_entry; - -struct event_filter { - struct prog_entry *prog; - char *filter_string; -}; - -struct trace_array_cpu; - -struct array_buffer { - struct trace_array *tr; - struct trace_buffer *buffer; - struct trace_array_cpu *data; - u64 time_start; - int cpu; -}; - -struct trace_pid_list; - -struct trace_options; - -struct cond_snapshot; - -struct trace_func_repeats; - -struct trace_array { - struct list_head list; - char *name; - struct array_buffer array_buffer; - struct array_buffer max_buffer; - bool allocated_snapshot; - long unsigned int max_latency; - struct dentry *d_max_latency; - struct work_struct fsnotify_work; - struct irq_work fsnotify_irqwork; - struct trace_pid_list *filtered_pids; - struct trace_pid_list *filtered_no_pids; - arch_spinlock_t max_lock; - int buffer_disabled; - int sys_refcount_enter; - int sys_refcount_exit; - struct trace_event_file *enter_syscall_files[448]; - struct trace_event_file *exit_syscall_files[448]; - int stop_count; - int clock_id; - int nr_topts; - bool clear_trace; - int buffer_percent; - unsigned int n_err_log_entries; - struct tracer *current_trace; - unsigned int trace_flags; - unsigned char trace_flags_index[32]; - unsigned int flags; - raw_spinlock_t start_lock; - struct list_head err_log; - struct dentry *dir; - struct dentry *options; - struct dentry *percpu_dir; - struct dentry *event_dir; - struct trace_options *topts; - struct list_head systems; - struct list_head events; - struct trace_event_file *trace_marker_file; - cpumask_var_t tracing_cpumask; - int ref; - int trace_ref; - struct ftrace_ops *ops; - struct trace_pid_list *function_pids; - struct trace_pid_list *function_no_pids; - struct list_head func_probes; - struct list_head mod_trace; - struct list_head mod_notrace; - int function_enabled; - int no_filter_buffering_ref; - struct list_head hist_vars; - struct cond_snapshot *cond_snapshot; - struct trace_func_repeats *last_func_repeats; -}; - -struct tracer_flags; - -struct tracer { - const char *name; - int (*init)(struct trace_array *); - void (*reset)(struct trace_array *); - void (*start)(struct trace_array *); - void (*stop)(struct trace_array *); - int (*update_thresh)(struct trace_array *); - void (*open)(struct trace_iterator *); - void (*pipe_open)(struct trace_iterator *); - void (*close)(struct trace_iterator *); - void (*pipe_close)(struct trace_iterator *); - ssize_t (*read)(struct trace_iterator *, struct file *, char *, size_t, loff_t *); - ssize_t (*splice_read)(struct trace_iterator *, struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); - void (*print_header)(struct seq_file *); - enum print_line_t (*print_line)(struct trace_iterator *); - int (*set_flag)(struct trace_array *, u32, u32, int); - int (*flag_changed)(struct trace_array *, u32, int); - struct tracer *next; - struct tracer_flags *flags; - int enabled; - bool print_max; - bool allow_instances; - bool use_max_tr; - bool noboot; -}; - -struct event_subsystem; - -struct trace_subsystem_dir { - struct list_head list; - struct event_subsystem *subsystem; - struct trace_array *tr; - struct dentry *entry; - int ref_count; - int nr_events; -}; - -struct trace_array_cpu { - atomic_t disabled; - void *buffer_page; - long unsigned int entries; - long unsigned int saved_latency; - long unsigned int critical_start; - long unsigned int critical_end; - long unsigned int critical_sequence; - long unsigned int nice; - long unsigned int policy; - long unsigned int rt_priority; - long unsigned int skipped_entries; - u64 preempt_timestamp; - pid_t pid; - kuid_t uid; - char comm[16]; - int ftrace_ignore_pid; - bool ignore_pid; -}; - -struct trace_option_dentry; - -struct trace_options { - struct tracer *tracer; - struct trace_option_dentry *topts; -}; - -struct tracer_opt; - -struct trace_option_dentry { - struct tracer_opt *opt; - struct tracer_flags *flags; - struct trace_array *tr; - struct dentry *entry; -}; - -struct trace_pid_list { - int pid_max; - long unsigned int *pids; -}; - -enum { - TRACE_PIDS = 1, - TRACE_NO_PIDS = 2, -}; - -typedef bool (*cond_update_fn_t)(struct trace_array *, void *); - -struct cond_snapshot { - void *cond_data; - cond_update_fn_t update; -}; - -struct trace_func_repeats { - long unsigned int ip; - long unsigned int parent_ip; - long unsigned int count; - u64 ts_last_call; -}; - -enum { - TRACE_ARRAY_FL_GLOBAL = 1, -}; - -struct tracer_opt { - const char *name; - u32 bit; -}; - -struct tracer_flags { - u32 val; - struct tracer_opt *opts; - struct tracer *trace; -}; - -struct ftrace_mod_load { - struct list_head list; - char *func; - char *module; - int enable; -}; - -enum { - FTRACE_HASH_FL_MOD = 1, -}; - -struct ftrace_func_command { - struct list_head list; - char *name; - int (*func)(struct trace_array *, struct ftrace_hash *, char *, char *, char *, int); -}; - -struct ftrace_probe_ops { - void (*func)(long unsigned int, long unsigned int, struct trace_array *, struct ftrace_probe_ops *, void *); - int (*init)(struct ftrace_probe_ops *, struct trace_array *, long unsigned int, void *, void **); - void (*free)(struct ftrace_probe_ops *, struct trace_array *, long unsigned int, void *); - int (*print)(struct seq_file *, long unsigned int, struct ftrace_probe_ops *, void *); -}; - -typedef int (*ftrace_mapper_func)(void *); - -struct trace_parser { - bool cont; - char *buffer; - unsigned int idx; - unsigned int size; -}; - -enum trace_iterator_bits { - TRACE_ITER_PRINT_PARENT_BIT = 0, - TRACE_ITER_SYM_OFFSET_BIT = 1, - TRACE_ITER_SYM_ADDR_BIT = 2, - TRACE_ITER_VERBOSE_BIT = 3, - TRACE_ITER_RAW_BIT = 4, - TRACE_ITER_HEX_BIT = 5, - TRACE_ITER_BIN_BIT = 6, - TRACE_ITER_BLOCK_BIT = 7, - TRACE_ITER_PRINTK_BIT = 8, - TRACE_ITER_ANNOTATE_BIT = 9, - TRACE_ITER_USERSTACKTRACE_BIT = 10, - TRACE_ITER_SYM_USEROBJ_BIT = 11, - TRACE_ITER_PRINTK_MSGONLY_BIT = 12, - TRACE_ITER_CONTEXT_INFO_BIT = 13, - TRACE_ITER_LATENCY_FMT_BIT = 14, - TRACE_ITER_RECORD_CMD_BIT = 15, - TRACE_ITER_RECORD_TGID_BIT = 16, - TRACE_ITER_OVERWRITE_BIT = 17, - TRACE_ITER_STOP_ON_FREE_BIT = 18, - TRACE_ITER_IRQ_INFO_BIT = 19, - TRACE_ITER_MARKERS_BIT = 20, - TRACE_ITER_EVENT_FORK_BIT = 21, - TRACE_ITER_PAUSE_ON_TRACE_BIT = 22, - TRACE_ITER_HASH_PTR_BIT = 23, - TRACE_ITER_FUNCTION_BIT = 24, - TRACE_ITER_FUNC_FORK_BIT = 25, - TRACE_ITER_DISPLAY_GRAPH_BIT = 26, - TRACE_ITER_STACKTRACE_BIT = 27, - TRACE_ITER_LAST_BIT = 28, -}; - -struct event_subsystem { - struct list_head list; - const char *name; - struct event_filter *filter; - int ref_count; -}; - -enum regex_type { - MATCH_FULL = 0, - MATCH_FRONT_ONLY = 1, - MATCH_MIDDLE_ONLY = 2, - MATCH_END_ONLY = 3, - MATCH_GLOB = 4, - MATCH_INDEX = 5, -}; - -struct tracer_stat { - const char *name; - void * (*stat_start)(struct tracer_stat *); - void * (*stat_next)(void *, int); - cmp_func_t stat_cmp; - int (*stat_show)(struct seq_file *, void *); - void (*stat_release)(void *); - int (*stat_headers)(struct seq_file *); -}; - -enum { - FTRACE_MODIFY_ENABLE_FL = 1, - FTRACE_MODIFY_MAY_SLEEP_FL = 2, -}; - -struct ftrace_profile { - struct hlist_node node; - long unsigned int ip; - long unsigned int counter; - long long unsigned int time; - long long unsigned int time_squared; -}; - -struct ftrace_profile_page { - struct ftrace_profile_page *next; - long unsigned int index; - struct ftrace_profile records[0]; -}; - -struct ftrace_profile_stat { - atomic_t disabled; - struct hlist_head *hash; - struct ftrace_profile_page *pages; - struct ftrace_profile_page *start; - struct tracer_stat stat; -}; - -struct ftrace_func_probe { - struct ftrace_probe_ops *probe_ops; - struct ftrace_ops ops; - struct trace_array *tr; - struct list_head list; - void *data; - int ref; -}; - -struct ftrace_page { - struct ftrace_page *next; - struct dyn_ftrace *records; - int index; - int order; -}; - -struct ftrace_rec_iter___2 { - struct ftrace_page *pg; - int index; -}; - -struct ftrace_iterator { - loff_t pos; - loff_t func_pos; - loff_t mod_pos; - struct ftrace_page *pg; - struct dyn_ftrace *func; - struct ftrace_func_probe *probe; - struct ftrace_func_entry *probe_entry; - struct trace_parser parser; - struct ftrace_hash *hash; - struct ftrace_ops *ops; - struct trace_array *tr; - struct list_head *mod_list; - int pidx; - int idx; - unsigned int flags; -}; - -struct ftrace_glob { - char *search; - unsigned int len; - int type; -}; - -struct ftrace_func_map { - struct ftrace_func_entry entry; - void *data; -}; - -struct ftrace_func_mapper { - struct ftrace_hash hash; -}; - -struct ftrace_direct_func { - struct list_head next; - long unsigned int addr; - int count; -}; - -enum graph_filter_type { - GRAPH_FILTER_NOTRACE = 0, - GRAPH_FILTER_FUNCTION = 1, -}; - -struct ftrace_graph_data { - struct ftrace_hash *hash; - struct ftrace_func_entry *entry; - int idx; - enum graph_filter_type type; - struct ftrace_hash *new_hash; - const struct seq_operations *seq_ops; - struct trace_parser parser; -}; - -struct ftrace_mod_func { - struct list_head list; - char *name; - long unsigned int ip; - unsigned int size; -}; - -struct ftrace_mod_map { - struct callback_head rcu; - struct list_head list; - struct module *mod; - long unsigned int start_addr; - long unsigned int end_addr; - struct list_head funcs; - unsigned int num_funcs; -}; - -struct ftrace_init_func { - struct list_head list; - long unsigned int ip; -}; - -enum ring_buffer_type { - RINGBUF_TYPE_DATA_TYPE_LEN_MAX = 28, - RINGBUF_TYPE_PADDING = 29, - RINGBUF_TYPE_TIME_EXTEND = 30, - RINGBUF_TYPE_TIME_STAMP = 31, -}; - -enum ring_buffer_flags { - RB_FL_OVERWRITE = 1, -}; - -struct ring_buffer_per_cpu; - -struct buffer_page; - -struct ring_buffer_iter { - struct ring_buffer_per_cpu *cpu_buffer; - long unsigned int head; - long unsigned int next_event; - struct buffer_page *head_page; - struct buffer_page *cache_reader_page; - long unsigned int cache_read; - u64 read_stamp; - u64 page_stamp; - struct ring_buffer_event *event; - int missed_events; -}; - -struct rb_irq_work { - struct irq_work work; - wait_queue_head_t waiters; - wait_queue_head_t full_waiters; - bool waiters_pending; - bool full_waiters_pending; - bool wakeup_full; -}; - -struct trace_buffer___2 { - unsigned int flags; - int cpus; - atomic_t record_disabled; - cpumask_var_t cpumask; - struct lock_class_key *reader_lock_key; - struct mutex mutex; - struct ring_buffer_per_cpu **buffers; - struct hlist_node node; - u64 (*clock)(); - struct rb_irq_work irq_work; - bool time_stamp_abs; -}; - -enum { - RB_LEN_TIME_EXTEND = 8, - RB_LEN_TIME_STAMP = 8, -}; - -struct buffer_data_page { - u64 time_stamp; - local_t commit; - unsigned char data[0]; -}; - -struct buffer_page { - struct list_head list; - local_t write; - unsigned int read; - local_t entries; - long unsigned int real_end; - struct buffer_data_page *page; -}; - -struct rb_event_info { - u64 ts; - u64 delta; - u64 before; - u64 after; - long unsigned int length; - struct buffer_page *tail_page; - int add_timestamp; -}; - -enum { - RB_ADD_STAMP_NONE = 0, - RB_ADD_STAMP_EXTEND = 2, - RB_ADD_STAMP_ABSOLUTE = 4, - RB_ADD_STAMP_FORCE = 8, -}; - -enum { - RB_CTX_TRANSITION = 0, - RB_CTX_NMI = 1, - RB_CTX_IRQ = 2, - RB_CTX_SOFTIRQ = 3, - RB_CTX_NORMAL = 4, - RB_CTX_MAX = 5, -}; - -struct rb_time_struct { - local64_t time; -}; - -typedef struct rb_time_struct rb_time_t; - -struct ring_buffer_per_cpu { - int cpu; - atomic_t record_disabled; - atomic_t resize_disabled; - struct trace_buffer___2 *buffer; - raw_spinlock_t reader_lock; - arch_spinlock_t lock; - struct lock_class_key lock_key; - struct buffer_data_page *free_page; - long unsigned int nr_pages; - unsigned int current_context; - struct list_head *pages; - struct buffer_page *head_page; - struct buffer_page *tail_page; - struct buffer_page *commit_page; - struct buffer_page *reader_page; - long unsigned int lost_events; - long unsigned int last_overrun; - long unsigned int nest; - local_t entries_bytes; - local_t entries; - local_t overrun; - local_t commit_overrun; - local_t dropped_events; - local_t committing; - local_t commits; - local_t pages_touched; - local_t pages_read; - long int last_pages_touch; - size_t shortest_full; - long unsigned int read; - long unsigned int read_bytes; - rb_time_t write_stamp; - rb_time_t before_stamp; - u64 event_stamp[5]; - u64 read_stamp; - long int nr_pages_to_update; - struct list_head new_pages; - struct work_struct update_pages_work; - struct completion update_done; - struct rb_irq_work irq_work; -}; - -typedef struct vfsmount * (*debugfs_automount_t)(struct dentry *, void *); - -struct trace_export { - struct trace_export *next; - void (*write)(struct trace_export *, const void *, unsigned int); - int flags; -}; - -enum fsnotify_data_type { - FSNOTIFY_EVENT_NONE = 0, - FSNOTIFY_EVENT_PATH = 1, - FSNOTIFY_EVENT_INODE = 2, -}; - -enum trace_iter_flags { - TRACE_FILE_LAT_FMT = 1, - TRACE_FILE_ANNOTATE = 2, - TRACE_FILE_TIME_IN_NS = 4, -}; - -enum trace_flag_type { - TRACE_FLAG_IRQS_OFF = 1, - TRACE_FLAG_IRQS_NOSUPPORT = 2, - TRACE_FLAG_NEED_RESCHED = 4, - TRACE_FLAG_HARDIRQ = 8, - TRACE_FLAG_SOFTIRQ = 16, - TRACE_FLAG_PREEMPT_RESCHED = 32, - TRACE_FLAG_NMI = 64, -}; - -enum trace_type { - __TRACE_FIRST_TYPE = 0, - TRACE_FN = 1, - TRACE_CTX = 2, - TRACE_WAKE = 3, - TRACE_STACK = 4, - TRACE_PRINT = 5, - TRACE_BPRINT = 6, - TRACE_MMIO_RW = 7, - TRACE_MMIO_MAP = 8, - TRACE_BRANCH = 9, - TRACE_GRAPH_RET = 10, - TRACE_GRAPH_ENT = 11, - TRACE_USER_STACK = 12, - TRACE_BLK = 13, - TRACE_BPUTS = 14, - TRACE_HWLAT = 15, - TRACE_OSNOISE = 16, - TRACE_TIMERLAT = 17, - TRACE_RAW_DATA = 18, - TRACE_FUNC_REPEATS = 19, - __TRACE_LAST_TYPE = 20, -}; - -struct ftrace_entry { - struct trace_entry ent; - long unsigned int ip; - long unsigned int parent_ip; -}; - -struct stack_entry { - struct trace_entry ent; - int size; - long unsigned int caller[8]; -}; - -struct userstack_entry { - struct trace_entry ent; - unsigned int tgid; - long unsigned int caller[8]; -}; - -struct bprint_entry { - struct trace_entry ent; - long unsigned int ip; - const char *fmt; - u32 buf[0]; -}; - -struct print_entry { - struct trace_entry ent; - long unsigned int ip; - char buf[0]; -}; - -struct raw_data_entry { - struct trace_entry ent; - unsigned int id; - char buf[0]; -}; - -struct bputs_entry { - struct trace_entry ent; - long unsigned int ip; - const char *str; -}; - -struct func_repeats_entry { - struct trace_entry ent; - long unsigned int ip; - long unsigned int parent_ip; - u16 count; - u16 top_delta_ts; - u32 bottom_delta_ts; -}; - -enum trace_iterator_flags { - TRACE_ITER_PRINT_PARENT = 1, - TRACE_ITER_SYM_OFFSET = 2, - TRACE_ITER_SYM_ADDR = 4, - TRACE_ITER_VERBOSE = 8, - TRACE_ITER_RAW = 16, - TRACE_ITER_HEX = 32, - TRACE_ITER_BIN = 64, - TRACE_ITER_BLOCK = 128, - TRACE_ITER_PRINTK = 256, - TRACE_ITER_ANNOTATE = 512, - TRACE_ITER_USERSTACKTRACE = 1024, - TRACE_ITER_SYM_USEROBJ = 2048, - TRACE_ITER_PRINTK_MSGONLY = 4096, - TRACE_ITER_CONTEXT_INFO = 8192, - TRACE_ITER_LATENCY_FMT = 16384, - TRACE_ITER_RECORD_CMD = 32768, - TRACE_ITER_RECORD_TGID = 65536, - TRACE_ITER_OVERWRITE = 131072, - TRACE_ITER_STOP_ON_FREE = 262144, - TRACE_ITER_IRQ_INFO = 524288, - TRACE_ITER_MARKERS = 1048576, - TRACE_ITER_EVENT_FORK = 2097152, - TRACE_ITER_PAUSE_ON_TRACE = 4194304, - TRACE_ITER_HASH_PTR = 8388608, - TRACE_ITER_FUNCTION = 16777216, - TRACE_ITER_FUNC_FORK = 33554432, - TRACE_ITER_DISPLAY_GRAPH = 67108864, - TRACE_ITER_STACKTRACE = 134217728, -}; - -struct trace_min_max_param { - struct mutex *lock; - u64 *val; - u64 *min; - u64 *max; -}; - -struct saved_cmdlines_buffer { - unsigned int map_pid_to_cmdline[32769]; - unsigned int *map_cmdline_to_pid; - unsigned int cmdline_num; - int cmdline_idx; - char *saved_cmdlines; -}; - -struct ftrace_stack { - long unsigned int calls[1024]; -}; - -struct ftrace_stacks { - struct ftrace_stack stacks[4]; -}; - -struct trace_buffer_struct { - int nesting; - char buffer[4096]; -}; - -struct ftrace_buffer_info { - struct trace_iterator iter; - void *spare; - unsigned int spare_cpu; - unsigned int read; -}; - -struct err_info { - const char **errs; - u8 type; - u8 pos; - u64 ts; -}; - -struct tracing_log_err { - struct list_head list; - struct err_info info; - char loc[128]; - char cmd[256]; -}; - -struct buffer_ref { - struct trace_buffer *buffer; - void *page; - int cpu; - refcount_t refcount; -}; - -struct ftrace_func_mapper___2; - -struct ctx_switch_entry { - struct trace_entry ent; - unsigned int prev_pid; - unsigned int next_pid; - unsigned int next_cpu; - unsigned char prev_prio; - unsigned char prev_state; - unsigned char next_prio; - unsigned char next_state; -}; - -struct hwlat_entry { - struct trace_entry ent; - u64 duration; - u64 outer_duration; - u64 nmi_total_ts; - struct timespec64 timestamp; - unsigned int nmi_count; - unsigned int seqnum; - unsigned int count; -}; - -struct osnoise_entry { - struct trace_entry ent; - u64 noise; - u64 runtime; - u64 max_sample; - unsigned int hw_count; - unsigned int nmi_count; - unsigned int irq_count; - unsigned int softirq_count; - unsigned int thread_count; -}; - -struct timerlat_entry { - struct trace_entry ent; - unsigned int seqnum; - int context; - u64 timer_latency; -}; - -struct trace_mark { - long long unsigned int val; - char sym; -}; - -struct stat_node { - struct rb_node node; - void *stat; -}; - -struct stat_session { - struct list_head session_list; - struct tracer_stat *ts; - struct rb_root stat_root; - struct mutex stat_mutex; - struct dentry *file; -}; - -struct trace_bprintk_fmt { - struct list_head list; - const char *fmt; -}; - -typedef int (*tracing_map_cmp_fn_t)(void *, void *); - -struct tracing_map_field { - tracing_map_cmp_fn_t cmp_fn; - union { - atomic64_t sum; - unsigned int offset; - }; -}; - -struct tracing_map; - -struct tracing_map_elt { - struct tracing_map *map; - struct tracing_map_field *fields; - atomic64_t *vars; - bool *var_set; - void *key; - void *private_data; -}; - -struct tracing_map_sort_key { - unsigned int field_idx; - bool descending; -}; - -struct tracing_map_array; - -struct tracing_map_ops; - -struct tracing_map { - unsigned int key_size; - unsigned int map_bits; - unsigned int map_size; - unsigned int max_elts; - atomic_t next_elt; - struct tracing_map_array *elts; - struct tracing_map_array *map; - const struct tracing_map_ops *ops; - void *private_data; - struct tracing_map_field fields[6]; - unsigned int n_fields; - int key_idx[3]; - unsigned int n_keys; - struct tracing_map_sort_key sort_key; - unsigned int n_vars; - atomic64_t hits; - atomic64_t drops; -}; - -struct tracing_map_entry { - u32 key; - struct tracing_map_elt *val; -}; - -struct tracing_map_sort_entry { - void *key; - struct tracing_map_elt *elt; - bool elt_copied; - bool dup; -}; - -struct tracing_map_array { - unsigned int entries_per_page; - unsigned int entry_size_shift; - unsigned int entry_shift; - unsigned int entry_mask; - unsigned int n_pages; - void **pages; -}; - -struct tracing_map_ops { - int (*elt_alloc)(struct tracing_map_elt *); - void (*elt_free)(struct tracing_map_elt *); - void (*elt_clear)(struct tracing_map_elt *); - void (*elt_init)(struct tracing_map_elt *); -}; - -enum { - TRACE_FUNC_NO_OPTS = 0, - TRACE_FUNC_OPT_STACK = 1, - TRACE_FUNC_OPT_NO_REPEATS = 2, - TRACE_FUNC_OPT_HIGHEST_BIT = 4, -}; - -enum { - MODE_NONE = 0, - MODE_ROUND_ROBIN = 1, - MODE_PER_CPU = 2, - MODE_MAX = 3, -}; - -struct hwlat_kthread_data { - struct task_struct *kthread; - u64 nmi_ts_start; - u64 nmi_total_ts; - int nmi_count; - int nmi_cpu; -}; - -struct hwlat_sample { - u64 seqnum; - u64 duration; - u64 outer_duration; - u64 nmi_total_ts; - struct timespec64 timestamp; - int nmi_count; - int count; -}; - -struct hwlat_data { - struct mutex lock; - u64 count; - u64 sample_window; - u64 sample_width; - int thread_mode; -}; - -struct trace_event_raw_thread_noise { - struct trace_entry ent; - char comm[16]; - u64 start; - u64 duration; - pid_t pid; - char __data[0]; -}; - -struct trace_event_raw_softirq_noise { - struct trace_entry ent; - u64 start; - u64 duration; - int vector; - char __data[0]; -}; - -struct trace_event_raw_irq_noise { - struct trace_entry ent; - u64 start; - u64 duration; - u32 __data_loc_desc; - int vector; - char __data[0]; -}; - -struct trace_event_raw_nmi_noise { - struct trace_entry ent; - u64 start; - u64 duration; - char __data[0]; -}; - -struct trace_event_raw_sample_threshold { - struct trace_entry ent; - u64 start; - u64 duration; - u64 interference; - char __data[0]; -}; - -struct trace_event_data_offsets_thread_noise {}; - -struct trace_event_data_offsets_softirq_noise {}; - -struct trace_event_data_offsets_irq_noise { - u32 desc; -}; - -struct trace_event_data_offsets_nmi_noise {}; - -struct trace_event_data_offsets_sample_threshold {}; - -typedef void (*btf_trace_thread_noise)(void *, struct task_struct *, u64, u64); - -typedef void (*btf_trace_softirq_noise)(void *, int, u64, u64); - -typedef void (*btf_trace_irq_noise)(void *, int, const char *, u64, u64); - -typedef void (*btf_trace_nmi_noise)(void *, u64, u64); - -typedef void (*btf_trace_sample_threshold)(void *, u64, u64, u64); - -struct osn_nmi { - u64 count; - u64 delta_start; -}; - -struct osn_irq { - u64 count; - u64 arrival_time; - u64 delta_start; -}; - -struct osn_softirq { - u64 count; - u64 arrival_time; - u64 delta_start; -}; - -struct osn_thread { - u64 count; - u64 arrival_time; - u64 delta_start; -}; - -struct osnoise_variables { - struct task_struct *kthread; - bool sampling; - pid_t pid; - struct osn_nmi nmi; - struct osn_irq irq; - struct osn_softirq softirq; - struct osn_thread thread; - local_t int_counter; -}; - -struct timerlat_variables { - struct task_struct *kthread; - struct hrtimer timer; - u64 rel_period; - u64 abs_period; - bool tracing_thread; - u64 count; -}; - -struct osnoise_sample { - u64 runtime; - u64 noise; - u64 max_sample; - int hw_count; - int nmi_count; - int irq_count; - int softirq_count; - int thread_count; -}; - -struct timerlat_sample { - u64 timer_latency; - unsigned int seqnum; - int context; -}; - -struct osnoise_data { - u64 sample_period; - u64 sample_runtime; - u64 stop_tracing; - u64 stop_tracing_total; - u64 timerlat_period; - u64 print_stack; - int timerlat_tracer; - bool tainted; -}; - -struct trace_stack { - int stack_size; - int nr_entries; - long unsigned int calls[256]; -}; - -enum { - TRACE_NOP_OPT_ACCEPT = 1, - TRACE_NOP_OPT_REFUSE = 2, -}; - -struct trace_mmiotrace_rw { - struct trace_entry ent; - struct mmiotrace_rw rw; -}; - -struct trace_mmiotrace_map { - struct trace_entry ent; - struct mmiotrace_map map; -}; - -struct header_iter { - struct pci_dev *dev; -}; - -struct ftrace_graph_ent_entry { - struct trace_entry ent; - struct ftrace_graph_ent graph_ent; -} __attribute__((packed)); - -struct ftrace_graph_ret_entry { - struct trace_entry ent; - struct ftrace_graph_ret ret; -}; - -struct fgraph_cpu_data { - pid_t last_pid; - int depth; - int depth_irq; - int ignore; - long unsigned int enter_funcs[50]; -}; - -struct fgraph_data { - struct fgraph_cpu_data *cpu_data; - struct ftrace_graph_ent_entry ent; - struct ftrace_graph_ret_entry ret; - int failed; - int cpu; - int: 32; -} __attribute__((packed)); - -enum { - FLAGS_FILL_FULL = 268435456, - FLAGS_FILL_START = 536870912, - FLAGS_FILL_END = 805306368, -}; - -struct disk_stats { - u64 nsecs[4]; - long unsigned int sectors[4]; - long unsigned int ios[4]; - long unsigned int merges[4]; - long unsigned int io_ticks; - local_t in_flight[2]; -}; - -struct blk_crypto_key; - -struct bio_crypt_ctx { - const struct blk_crypto_key *bc_key; - u64 bc_dun[4]; -}; - -typedef __u32 blk_mq_req_flags_t; - -struct blk_mq_ctxs; - -struct blk_mq_ctx { - struct { - spinlock_t lock; - struct list_head rq_lists[3]; - long: 64; - }; - unsigned int cpu; - short unsigned int index_hw[3]; - struct blk_mq_hw_ctx *hctxs[3]; - long unsigned int rq_dispatched[2]; - long unsigned int rq_merged; - long unsigned int rq_completed[2]; - struct request_queue *queue; - struct blk_mq_ctxs *ctxs; - struct kobject kobj; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct blk_mq_tags; - -struct blk_mq_hw_ctx { - struct { - spinlock_t lock; - struct list_head dispatch; - long unsigned int state; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct delayed_work run_work; - cpumask_var_t cpumask; - int next_cpu; - int next_cpu_batch; - long unsigned int flags; - void *sched_data; - struct request_queue *queue; - struct blk_flush_queue *fq; - void *driver_data; - struct sbitmap ctx_map; - struct blk_mq_ctx *dispatch_from; - unsigned int dispatch_busy; - short unsigned int type; - short unsigned int nr_ctx; - struct blk_mq_ctx **ctxs; - spinlock_t dispatch_wait_lock; - wait_queue_entry_t dispatch_wait; - atomic_t wait_index; - struct blk_mq_tags *tags; - struct blk_mq_tags *sched_tags; - long unsigned int queued; - long unsigned int run; - long unsigned int dispatched[7]; - unsigned int numa_node; - unsigned int queue_num; - atomic_t nr_active; - struct hlist_node cpuhp_online; - struct hlist_node cpuhp_dead; - struct kobject kobj; - long unsigned int poll_considered; - long unsigned int poll_invoked; - long unsigned int poll_success; - struct dentry *debugfs_dir; - struct dentry *sched_debugfs_dir; - struct list_head hctx_list; - struct srcu_struct srcu[0]; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct blk_mq_alloc_data { - struct request_queue *q; - blk_mq_req_flags_t flags; - unsigned int shallow_depth; - unsigned int cmd_flags; - struct blk_mq_ctx *ctx; - struct blk_mq_hw_ctx *hctx; -}; - -struct blk_stat_callback { - struct list_head list; - struct timer_list timer; - struct blk_rq_stat *cpu_stat; - int (*bucket_fn)(const struct request *); - unsigned int buckets; - struct blk_rq_stat *stat; - void (*timer_fn)(struct blk_stat_callback *); - void *data; - struct callback_head rcu; -}; - -struct blk_trace { - int trace_state; - struct rchan *rchan; - long unsigned int *sequence; - unsigned char *msg_data; - u16 act_mask; - u64 start_lba; - u64 end_lba; - u32 pid; - u32 dev; - struct dentry *dir; - struct list_head running_list; - atomic_t dropped; -}; - -struct blk_flush_queue { - unsigned int flush_pending_idx: 1; - unsigned int flush_running_idx: 1; - blk_status_t rq_status; - long unsigned int flush_pending_since; - struct list_head flush_queue[2]; - struct list_head flush_data_in_flight; - struct request *flush_rq; - spinlock_t mq_flush_lock; -}; - -struct blk_mq_queue_map { - unsigned int *mq_map; - unsigned int nr_queues; - unsigned int queue_offset; -}; - -struct blk_mq_tag_set { - struct blk_mq_queue_map map[3]; - unsigned int nr_maps; - const struct blk_mq_ops *ops; - unsigned int nr_hw_queues; - unsigned int queue_depth; - unsigned int reserved_tags; - unsigned int cmd_size; - int numa_node; - unsigned int timeout; - unsigned int flags; - void *driver_data; - atomic_t active_queues_shared_sbitmap; - struct sbitmap_queue __bitmap_tags; - struct sbitmap_queue __breserved_tags; - struct blk_mq_tags **tags; - struct mutex tag_list_lock; - struct list_head tag_list; -}; - -typedef u64 compat_u64; - -enum blktrace_cat { - BLK_TC_READ = 1, - BLK_TC_WRITE = 2, - BLK_TC_FLUSH = 4, - BLK_TC_SYNC = 8, - BLK_TC_SYNCIO = 8, - BLK_TC_QUEUE = 16, - BLK_TC_REQUEUE = 32, - BLK_TC_ISSUE = 64, - BLK_TC_COMPLETE = 128, - BLK_TC_FS = 256, - BLK_TC_PC = 512, - BLK_TC_NOTIFY = 1024, - BLK_TC_AHEAD = 2048, - BLK_TC_META = 4096, - BLK_TC_DISCARD = 8192, - BLK_TC_DRV_DATA = 16384, - BLK_TC_FUA = 32768, - BLK_TC_END = 32768, -}; - -enum blktrace_act { - __BLK_TA_QUEUE = 1, - __BLK_TA_BACKMERGE = 2, - __BLK_TA_FRONTMERGE = 3, - __BLK_TA_GETRQ = 4, - __BLK_TA_SLEEPRQ = 5, - __BLK_TA_REQUEUE = 6, - __BLK_TA_ISSUE = 7, - __BLK_TA_COMPLETE = 8, - __BLK_TA_PLUG = 9, - __BLK_TA_UNPLUG_IO = 10, - __BLK_TA_UNPLUG_TIMER = 11, - __BLK_TA_INSERT = 12, - __BLK_TA_SPLIT = 13, - __BLK_TA_BOUNCE = 14, - __BLK_TA_REMAP = 15, - __BLK_TA_ABORT = 16, - __BLK_TA_DRV_DATA = 17, - __BLK_TA_CGROUP = 256, -}; - -enum blktrace_notify { - __BLK_TN_PROCESS = 0, - __BLK_TN_TIMESTAMP = 1, - __BLK_TN_MESSAGE = 2, - __BLK_TN_CGROUP = 256, -}; - -struct blk_io_trace { - __u32 magic; - __u32 sequence; - __u64 time; - __u64 sector; - __u32 bytes; - __u32 action; - __u32 pid; - __u32 device; - __u32 cpu; - __u16 error; - __u16 pdu_len; -}; - -struct blk_io_trace_remap { - __be32 device_from; - __be32 device_to; - __be64 sector_from; -}; - -enum { - Blktrace_setup = 1, - Blktrace_running = 2, - Blktrace_stopped = 3, -}; - -struct blk_user_trace_setup { - char name[32]; - __u16 act_mask; - __u32 buf_size; - __u32 buf_nr; - __u64 start_lba; - __u64 end_lba; - __u32 pid; -}; - -struct compat_blk_user_trace_setup { - char name[32]; - u16 act_mask; - short: 16; - u32 buf_size; - u32 buf_nr; - compat_u64 start_lba; - compat_u64 end_lba; - u32 pid; -} __attribute__((packed)); - -struct blk_mq_tags { - unsigned int nr_tags; - unsigned int nr_reserved_tags; - atomic_t active_queues; - struct sbitmap_queue *bitmap_tags; - struct sbitmap_queue *breserved_tags; - struct sbitmap_queue __bitmap_tags; - struct sbitmap_queue __breserved_tags; - struct request **rqs; - struct request **static_rqs; - struct list_head page_list; - spinlock_t lock; -}; - -struct blk_mq_queue_data { - struct request *rq; - bool last; -}; - -enum blk_crypto_mode_num { - BLK_ENCRYPTION_MODE_INVALID = 0, - BLK_ENCRYPTION_MODE_AES_256_XTS = 1, - BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV = 2, - BLK_ENCRYPTION_MODE_ADIANTUM = 3, - BLK_ENCRYPTION_MODE_MAX = 4, -}; - -struct blk_crypto_config { - enum blk_crypto_mode_num crypto_mode; - unsigned int data_unit_size; - unsigned int dun_bytes; -}; - -struct blk_crypto_key { - struct blk_crypto_config crypto_cfg; - unsigned int data_unit_size_bits; - unsigned int size; - u8 raw[64]; -}; - -struct blk_mq_ctxs { - struct kobject kobj; - struct blk_mq_ctx *queue_ctx; -}; - -typedef void blk_log_action_t(struct trace_iterator *, const char *, bool); - -struct ftrace_event_field { - struct list_head link; - const char *name; - const char *type; - int filter_type; - int offset; - int size; - int is_signed; -}; - -enum { - FORMAT_HEADER = 1, - FORMAT_FIELD_SEPERATOR = 2, - FORMAT_PRINTFMT = 3, -}; - -struct event_probe_data { - struct trace_event_file *file; - long unsigned int count; - int ref; - bool enable; -}; - -struct syscall_trace_enter { - struct trace_entry ent; - int nr; - long unsigned int args[0]; -}; - -struct syscall_trace_exit { - struct trace_entry ent; - int nr; - long int ret; -}; - -struct syscall_tp_t { - long long unsigned int regs; - long unsigned int syscall_nr; - long unsigned int ret; -}; - -struct syscall_tp_t___2 { - long long unsigned int regs; - long unsigned int syscall_nr; - long unsigned int args[6]; -}; - -typedef long unsigned int perf_trace_t[256]; - -struct filter_pred; - -struct prog_entry { - int target; - int when_to_branch; - struct filter_pred *pred; -}; - -typedef int (*filter_pred_fn_t)(struct filter_pred *, void *); - -struct regex; - -typedef int (*regex_match_func)(char *, struct regex *, int); - -struct regex { - char pattern[256]; - int len; - int field_len; - regex_match_func match; -}; - -struct filter_pred { - filter_pred_fn_t fn; - u64 val; - struct regex regex; - short unsigned int *ops; - struct ftrace_event_field *field; - int offset; - int not; - int op; -}; - -enum filter_op_ids { - OP_GLOB = 0, - OP_NE = 1, - OP_EQ = 2, - OP_LE = 3, - OP_LT = 4, - OP_GE = 5, - OP_GT = 6, - OP_BAND = 7, - OP_MAX = 8, -}; - -enum { - FILT_ERR_NONE = 0, - FILT_ERR_INVALID_OP = 1, - FILT_ERR_TOO_MANY_OPEN = 2, - FILT_ERR_TOO_MANY_CLOSE = 3, - FILT_ERR_MISSING_QUOTE = 4, - FILT_ERR_OPERAND_TOO_LONG = 5, - FILT_ERR_EXPECT_STRING = 6, - FILT_ERR_EXPECT_DIGIT = 7, - FILT_ERR_ILLEGAL_FIELD_OP = 8, - FILT_ERR_FIELD_NOT_FOUND = 9, - FILT_ERR_ILLEGAL_INTVAL = 10, - FILT_ERR_BAD_SUBSYS_FILTER = 11, - FILT_ERR_TOO_MANY_PREDS = 12, - FILT_ERR_INVALID_FILTER = 13, - FILT_ERR_IP_FIELD_ONLY = 14, - FILT_ERR_INVALID_VALUE = 15, - FILT_ERR_ERRNO = 16, - FILT_ERR_NO_FILTER = 17, -}; - -struct filter_parse_error { - int lasterr; - int lasterr_pos; -}; - -typedef int (*parse_pred_fn)(const char *, void *, int, struct filter_parse_error *, struct filter_pred **); - -enum { - INVERT = 1, - PROCESS_AND = 2, - PROCESS_OR = 4, -}; - -enum { - TOO_MANY_CLOSE = 4294967295, - TOO_MANY_OPEN = 4294967294, - MISSING_QUOTE = 4294967293, -}; - -struct filter_list { - struct list_head list; - struct event_filter *filter; -}; - -struct function_filter_data { - struct ftrace_ops *ops; - int first_filter; - int first_notrace; -}; - -struct event_trigger_ops; - -struct event_command; - -struct event_trigger_data { - long unsigned int count; - int ref; - struct event_trigger_ops *ops; - struct event_command *cmd_ops; - struct event_filter *filter; - char *filter_str; - void *private_data; - bool paused; - bool paused_tmp; - struct list_head list; - char *name; - struct list_head named_list; - struct event_trigger_data *named_data; -}; - -struct event_trigger_ops { - void (*func)(struct event_trigger_data *, struct trace_buffer *, void *, struct ring_buffer_event *); - int (*init)(struct event_trigger_ops *, struct event_trigger_data *); - void (*free)(struct event_trigger_ops *, struct event_trigger_data *); - int (*print)(struct seq_file *, struct event_trigger_ops *, struct event_trigger_data *); -}; - -struct event_command { - struct list_head list; - char *name; - enum event_trigger_type trigger_type; - int flags; - int (*func)(struct event_command *, struct trace_event_file *, char *, char *, char *); - int (*reg)(char *, struct event_trigger_ops *, struct event_trigger_data *, struct trace_event_file *); - void (*unreg)(char *, struct event_trigger_ops *, struct event_trigger_data *, struct trace_event_file *); - void (*unreg_all)(struct trace_event_file *); - int (*set_filter)(char *, struct event_trigger_data *, struct trace_event_file *); - struct event_trigger_ops * (*get_trigger_ops)(char *, char *); -}; - -struct enable_trigger_data { - struct trace_event_file *file; - bool enable; - bool hist; -}; - -enum event_command_flags { - EVENT_CMD_FL_POST_TRIGGER = 1, - EVENT_CMD_FL_NEEDS_REC = 2, -}; - -enum dynevent_type { - DYNEVENT_TYPE_SYNTH = 1, - DYNEVENT_TYPE_KPROBE = 2, - DYNEVENT_TYPE_NONE = 3, -}; - -struct dynevent_cmd; - -typedef int (*dynevent_create_fn_t)(struct dynevent_cmd *); - -struct dynevent_cmd { - struct seq_buf seq; - const char *event_name; - unsigned int n_fields; - enum dynevent_type type; - dynevent_create_fn_t run_command; - void *private_data; -}; - -struct synth_field_desc { - const char *type; - const char *name; -}; - -struct synth_trace_event; - -struct synth_event; - -struct synth_event_trace_state { - struct trace_event_buffer fbuffer; - struct synth_trace_event *entry; - struct trace_buffer *buffer; - struct synth_event *event; - unsigned int cur_field; - unsigned int n_u64; - bool disabled; - bool add_next; - bool add_name; -}; - -struct synth_trace_event { - struct trace_entry ent; - u64 fields[0]; -}; - -struct dyn_event_operations; - -struct dyn_event { - struct list_head list; - struct dyn_event_operations *ops; -}; - -struct synth_field; - -struct synth_event { - struct dyn_event devent; - int ref; - char *name; - struct synth_field **fields; - unsigned int n_fields; - struct synth_field **dynamic_fields; - unsigned int n_dynamic_fields; - unsigned int n_u64; - struct trace_event_class class; - struct trace_event_call call; - struct tracepoint *tp; - struct module *mod; -}; - -struct dyn_event_operations { - struct list_head list; - int (*create)(const char *); - int (*show)(struct seq_file *, struct dyn_event *); - bool (*is_busy)(struct dyn_event *); - int (*free)(struct dyn_event *); - bool (*match)(const char *, const char *, int, const char **, struct dyn_event *); -}; - -typedef int (*dynevent_check_arg_fn_t)(void *); - -struct dynevent_arg { - const char *str; - char separator; -}; - -struct dynevent_arg_pair { - const char *lhs; - const char *rhs; - char operator; - char separator; -}; - -struct synth_field { - char *type; - char *name; - size_t size; - unsigned int offset; - unsigned int field_pos; - bool is_signed; - bool is_string; - bool is_dynamic; -}; - -enum { - SYNTH_ERR_BAD_NAME = 0, - SYNTH_ERR_INVALID_CMD = 1, - SYNTH_ERR_INVALID_DYN_CMD = 2, - SYNTH_ERR_EVENT_EXISTS = 3, - SYNTH_ERR_TOO_MANY_FIELDS = 4, - SYNTH_ERR_INCOMPLETE_TYPE = 5, - SYNTH_ERR_INVALID_TYPE = 6, - SYNTH_ERR_INVALID_FIELD = 7, - SYNTH_ERR_INVALID_ARRAY_SPEC = 8, -}; - -enum { - HIST_ERR_NONE = 0, - HIST_ERR_DUPLICATE_VAR = 1, - HIST_ERR_VAR_NOT_UNIQUE = 2, - HIST_ERR_TOO_MANY_VARS = 3, - HIST_ERR_MALFORMED_ASSIGNMENT = 4, - HIST_ERR_NAMED_MISMATCH = 5, - HIST_ERR_TRIGGER_EEXIST = 6, - HIST_ERR_TRIGGER_ENOENT_CLEAR = 7, - HIST_ERR_SET_CLOCK_FAIL = 8, - HIST_ERR_BAD_FIELD_MODIFIER = 9, - HIST_ERR_TOO_MANY_SUBEXPR = 10, - HIST_ERR_TIMESTAMP_MISMATCH = 11, - HIST_ERR_TOO_MANY_FIELD_VARS = 12, - HIST_ERR_EVENT_FILE_NOT_FOUND = 13, - HIST_ERR_HIST_NOT_FOUND = 14, - HIST_ERR_HIST_CREATE_FAIL = 15, - HIST_ERR_SYNTH_VAR_NOT_FOUND = 16, - HIST_ERR_SYNTH_EVENT_NOT_FOUND = 17, - HIST_ERR_SYNTH_TYPE_MISMATCH = 18, - HIST_ERR_SYNTH_COUNT_MISMATCH = 19, - HIST_ERR_FIELD_VAR_PARSE_FAIL = 20, - HIST_ERR_VAR_CREATE_FIND_FAIL = 21, - HIST_ERR_ONX_NOT_VAR = 22, - HIST_ERR_ONX_VAR_NOT_FOUND = 23, - HIST_ERR_ONX_VAR_CREATE_FAIL = 24, - HIST_ERR_FIELD_VAR_CREATE_FAIL = 25, - HIST_ERR_TOO_MANY_PARAMS = 26, - HIST_ERR_PARAM_NOT_FOUND = 27, - HIST_ERR_INVALID_PARAM = 28, - HIST_ERR_ACTION_NOT_FOUND = 29, - HIST_ERR_NO_SAVE_PARAMS = 30, - HIST_ERR_TOO_MANY_SAVE_ACTIONS = 31, - HIST_ERR_ACTION_MISMATCH = 32, - HIST_ERR_NO_CLOSING_PAREN = 33, - HIST_ERR_SUBSYS_NOT_FOUND = 34, - HIST_ERR_INVALID_SUBSYS_EVENT = 35, - HIST_ERR_INVALID_REF_KEY = 36, - HIST_ERR_VAR_NOT_FOUND = 37, - HIST_ERR_FIELD_NOT_FOUND = 38, - HIST_ERR_EMPTY_ASSIGNMENT = 39, - HIST_ERR_INVALID_SORT_MODIFIER = 40, - HIST_ERR_EMPTY_SORT_FIELD = 41, - HIST_ERR_TOO_MANY_SORT_FIELDS = 42, - HIST_ERR_INVALID_SORT_FIELD = 43, - HIST_ERR_INVALID_STR_OPERAND = 44, -}; - -struct hist_field; - -typedef u64 (*hist_field_fn_t)(struct hist_field *, struct tracing_map_elt *, struct trace_buffer *, struct ring_buffer_event *, void *); - -struct hist_trigger_data; - -struct hist_var { - char *name; - struct hist_trigger_data *hist_data; - unsigned int idx; -}; - -enum field_op_id { - FIELD_OP_NONE = 0, - FIELD_OP_PLUS = 1, - FIELD_OP_MINUS = 2, - FIELD_OP_UNARY_MINUS = 3, -}; - -struct hist_field { - struct ftrace_event_field *field; - long unsigned int flags; - hist_field_fn_t fn; - unsigned int ref; - unsigned int size; - unsigned int offset; - unsigned int is_signed; - const char *type; - struct hist_field *operands[2]; - struct hist_trigger_data *hist_data; - struct hist_var var; - enum field_op_id operator; - char *system; - char *event_name; - char *name; - unsigned int var_ref_idx; - bool read_once; - unsigned int var_str_idx; -}; - -struct hist_trigger_attrs; - -struct action_data; - -struct field_var; - -struct field_var_hist; - -struct hist_trigger_data { - struct hist_field *fields[22]; - unsigned int n_vals; - unsigned int n_keys; - unsigned int n_fields; - unsigned int n_vars; - unsigned int n_var_str; - unsigned int key_size; - struct tracing_map_sort_key sort_keys[2]; - unsigned int n_sort_keys; - struct trace_event_file *event_file; - struct hist_trigger_attrs *attrs; - struct tracing_map *map; - bool enable_timestamps; - bool remove; - struct hist_field *var_refs[16]; - unsigned int n_var_refs; - struct action_data *actions[8]; - unsigned int n_actions; - struct field_var *field_vars[32]; - unsigned int n_field_vars; - unsigned int n_field_var_str; - struct field_var_hist *field_var_hists[32]; - unsigned int n_field_var_hists; - struct field_var *save_vars[32]; - unsigned int n_save_vars; - unsigned int n_save_var_str; -}; - -enum hist_field_flags { - HIST_FIELD_FL_HITCOUNT = 1, - HIST_FIELD_FL_KEY = 2, - HIST_FIELD_FL_STRING = 4, - HIST_FIELD_FL_HEX = 8, - HIST_FIELD_FL_SYM = 16, - HIST_FIELD_FL_SYM_OFFSET = 32, - HIST_FIELD_FL_EXECNAME = 64, - HIST_FIELD_FL_SYSCALL = 128, - HIST_FIELD_FL_STACKTRACE = 256, - HIST_FIELD_FL_LOG2 = 512, - HIST_FIELD_FL_TIMESTAMP = 1024, - HIST_FIELD_FL_TIMESTAMP_USECS = 2048, - HIST_FIELD_FL_VAR = 4096, - HIST_FIELD_FL_EXPR = 8192, - HIST_FIELD_FL_VAR_REF = 16384, - HIST_FIELD_FL_CPU = 32768, - HIST_FIELD_FL_ALIAS = 65536, -}; - -struct var_defs { - unsigned int n_vars; - char *name[16]; - char *expr[16]; -}; - -struct hist_trigger_attrs { - char *keys_str; - char *vals_str; - char *sort_key_str; - char *name; - char *clock; - bool pause; - bool cont; - bool clear; - bool ts_in_usecs; - unsigned int map_bits; - char *assignment_str[16]; - unsigned int n_assignments; - char *action_str[8]; - unsigned int n_actions; - struct var_defs var_defs; -}; - -struct field_var { - struct hist_field *var; - struct hist_field *val; -}; - -struct field_var_hist { - struct hist_trigger_data *hist_data; - char *cmd; -}; - -enum handler_id { - HANDLER_ONMATCH = 1, - HANDLER_ONMAX = 2, - HANDLER_ONCHANGE = 3, -}; - -enum action_id { - ACTION_SAVE = 1, - ACTION_TRACE = 2, - ACTION_SNAPSHOT = 3, -}; - -typedef void (*action_fn_t)(struct hist_trigger_data *, struct tracing_map_elt *, struct trace_buffer *, void *, struct ring_buffer_event *, void *, struct action_data *, u64 *); - -typedef bool (*check_track_val_fn_t)(u64, u64); - -struct action_data { - enum handler_id handler; - enum action_id action; - char *action_name; - action_fn_t fn; - unsigned int n_params; - char *params[32]; - unsigned int var_ref_idx[16]; - struct synth_event *synth_event; - bool use_trace_keyword; - char *synth_event_name; - union { - struct { - char *event; - char *event_system; - } match_data; - struct { - char *var_str; - struct hist_field *var_ref; - struct hist_field *track_var; - check_track_val_fn_t check_val; - action_fn_t save_data; - } track_data; - }; -}; - -struct track_data { - u64 track_val; - bool updated; - unsigned int key_len; - void *key; - struct tracing_map_elt elt; - struct action_data *action_data; - struct hist_trigger_data *hist_data; -}; - -struct hist_elt_data { - char *comm; - u64 *var_ref_vals; - char *field_var_str[32]; -}; - -struct snapshot_context { - struct tracing_map_elt *elt; - void *key; -}; - -typedef void (*synth_probe_func_t)(void *, u64 *, unsigned int *); - -struct hist_var_data { - struct list_head list; - struct hist_trigger_data *hist_data; -}; - -enum bpf_func_id { - BPF_FUNC_unspec = 0, - BPF_FUNC_map_lookup_elem = 1, - BPF_FUNC_map_update_elem = 2, - BPF_FUNC_map_delete_elem = 3, - BPF_FUNC_probe_read = 4, - BPF_FUNC_ktime_get_ns = 5, - BPF_FUNC_trace_printk = 6, - BPF_FUNC_get_prandom_u32 = 7, - BPF_FUNC_get_smp_processor_id = 8, - BPF_FUNC_skb_store_bytes = 9, - BPF_FUNC_l3_csum_replace = 10, - BPF_FUNC_l4_csum_replace = 11, - BPF_FUNC_tail_call = 12, - BPF_FUNC_clone_redirect = 13, - BPF_FUNC_get_current_pid_tgid = 14, - BPF_FUNC_get_current_uid_gid = 15, - BPF_FUNC_get_current_comm = 16, - BPF_FUNC_get_cgroup_classid = 17, - BPF_FUNC_skb_vlan_push = 18, - BPF_FUNC_skb_vlan_pop = 19, - BPF_FUNC_skb_get_tunnel_key = 20, - BPF_FUNC_skb_set_tunnel_key = 21, - BPF_FUNC_perf_event_read = 22, - BPF_FUNC_redirect = 23, - BPF_FUNC_get_route_realm = 24, - BPF_FUNC_perf_event_output = 25, - BPF_FUNC_skb_load_bytes = 26, - BPF_FUNC_get_stackid = 27, - BPF_FUNC_csum_diff = 28, - BPF_FUNC_skb_get_tunnel_opt = 29, - BPF_FUNC_skb_set_tunnel_opt = 30, - BPF_FUNC_skb_change_proto = 31, - BPF_FUNC_skb_change_type = 32, - BPF_FUNC_skb_under_cgroup = 33, - BPF_FUNC_get_hash_recalc = 34, - BPF_FUNC_get_current_task = 35, - BPF_FUNC_probe_write_user = 36, - BPF_FUNC_current_task_under_cgroup = 37, - BPF_FUNC_skb_change_tail = 38, - BPF_FUNC_skb_pull_data = 39, - BPF_FUNC_csum_update = 40, - BPF_FUNC_set_hash_invalid = 41, - BPF_FUNC_get_numa_node_id = 42, - BPF_FUNC_skb_change_head = 43, - BPF_FUNC_xdp_adjust_head = 44, - BPF_FUNC_probe_read_str = 45, - BPF_FUNC_get_socket_cookie = 46, - BPF_FUNC_get_socket_uid = 47, - BPF_FUNC_set_hash = 48, - BPF_FUNC_setsockopt = 49, - BPF_FUNC_skb_adjust_room = 50, - BPF_FUNC_redirect_map = 51, - BPF_FUNC_sk_redirect_map = 52, - BPF_FUNC_sock_map_update = 53, - BPF_FUNC_xdp_adjust_meta = 54, - BPF_FUNC_perf_event_read_value = 55, - BPF_FUNC_perf_prog_read_value = 56, - BPF_FUNC_getsockopt = 57, - BPF_FUNC_override_return = 58, - BPF_FUNC_sock_ops_cb_flags_set = 59, - BPF_FUNC_msg_redirect_map = 60, - BPF_FUNC_msg_apply_bytes = 61, - BPF_FUNC_msg_cork_bytes = 62, - BPF_FUNC_msg_pull_data = 63, - BPF_FUNC_bind = 64, - BPF_FUNC_xdp_adjust_tail = 65, - BPF_FUNC_skb_get_xfrm_state = 66, - BPF_FUNC_get_stack = 67, - BPF_FUNC_skb_load_bytes_relative = 68, - BPF_FUNC_fib_lookup = 69, - BPF_FUNC_sock_hash_update = 70, - BPF_FUNC_msg_redirect_hash = 71, - BPF_FUNC_sk_redirect_hash = 72, - BPF_FUNC_lwt_push_encap = 73, - BPF_FUNC_lwt_seg6_store_bytes = 74, - BPF_FUNC_lwt_seg6_adjust_srh = 75, - BPF_FUNC_lwt_seg6_action = 76, - BPF_FUNC_rc_repeat = 77, - BPF_FUNC_rc_keydown = 78, - BPF_FUNC_skb_cgroup_id = 79, - BPF_FUNC_get_current_cgroup_id = 80, - BPF_FUNC_get_local_storage = 81, - BPF_FUNC_sk_select_reuseport = 82, - BPF_FUNC_skb_ancestor_cgroup_id = 83, - BPF_FUNC_sk_lookup_tcp = 84, - BPF_FUNC_sk_lookup_udp = 85, - BPF_FUNC_sk_release = 86, - BPF_FUNC_map_push_elem = 87, - BPF_FUNC_map_pop_elem = 88, - BPF_FUNC_map_peek_elem = 89, - BPF_FUNC_msg_push_data = 90, - BPF_FUNC_msg_pop_data = 91, - BPF_FUNC_rc_pointer_rel = 92, - BPF_FUNC_spin_lock = 93, - BPF_FUNC_spin_unlock = 94, - BPF_FUNC_sk_fullsock = 95, - BPF_FUNC_tcp_sock = 96, - BPF_FUNC_skb_ecn_set_ce = 97, - BPF_FUNC_get_listener_sock = 98, - BPF_FUNC_skc_lookup_tcp = 99, - BPF_FUNC_tcp_check_syncookie = 100, - BPF_FUNC_sysctl_get_name = 101, - BPF_FUNC_sysctl_get_current_value = 102, - BPF_FUNC_sysctl_get_new_value = 103, - BPF_FUNC_sysctl_set_new_value = 104, - BPF_FUNC_strtol = 105, - BPF_FUNC_strtoul = 106, - BPF_FUNC_sk_storage_get = 107, - BPF_FUNC_sk_storage_delete = 108, - BPF_FUNC_send_signal = 109, - BPF_FUNC_tcp_gen_syncookie = 110, - BPF_FUNC_skb_output = 111, - BPF_FUNC_probe_read_user = 112, - BPF_FUNC_probe_read_kernel = 113, - BPF_FUNC_probe_read_user_str = 114, - BPF_FUNC_probe_read_kernel_str = 115, - BPF_FUNC_tcp_send_ack = 116, - BPF_FUNC_send_signal_thread = 117, - BPF_FUNC_jiffies64 = 118, - BPF_FUNC_read_branch_records = 119, - BPF_FUNC_get_ns_current_pid_tgid = 120, - BPF_FUNC_xdp_output = 121, - BPF_FUNC_get_netns_cookie = 122, - BPF_FUNC_get_current_ancestor_cgroup_id = 123, - BPF_FUNC_sk_assign = 124, - BPF_FUNC_ktime_get_boot_ns = 125, - BPF_FUNC_seq_printf = 126, - BPF_FUNC_seq_write = 127, - BPF_FUNC_sk_cgroup_id = 128, - BPF_FUNC_sk_ancestor_cgroup_id = 129, - BPF_FUNC_ringbuf_output = 130, - BPF_FUNC_ringbuf_reserve = 131, - BPF_FUNC_ringbuf_submit = 132, - BPF_FUNC_ringbuf_discard = 133, - BPF_FUNC_ringbuf_query = 134, - BPF_FUNC_csum_level = 135, - BPF_FUNC_skc_to_tcp6_sock = 136, - BPF_FUNC_skc_to_tcp_sock = 137, - BPF_FUNC_skc_to_tcp_timewait_sock = 138, - BPF_FUNC_skc_to_tcp_request_sock = 139, - BPF_FUNC_skc_to_udp6_sock = 140, - BPF_FUNC_get_task_stack = 141, - BPF_FUNC_load_hdr_opt = 142, - BPF_FUNC_store_hdr_opt = 143, - BPF_FUNC_reserve_hdr_opt = 144, - BPF_FUNC_inode_storage_get = 145, - BPF_FUNC_inode_storage_delete = 146, - BPF_FUNC_d_path = 147, - BPF_FUNC_copy_from_user = 148, - BPF_FUNC_snprintf_btf = 149, - BPF_FUNC_seq_printf_btf = 150, - BPF_FUNC_skb_cgroup_classid = 151, - BPF_FUNC_redirect_neigh = 152, - BPF_FUNC_per_cpu_ptr = 153, - BPF_FUNC_this_cpu_ptr = 154, - BPF_FUNC_redirect_peer = 155, - BPF_FUNC_task_storage_get = 156, - BPF_FUNC_task_storage_delete = 157, - BPF_FUNC_get_current_task_btf = 158, - BPF_FUNC_bprm_opts_set = 159, - BPF_FUNC_ktime_get_coarse_ns = 160, - BPF_FUNC_ima_inode_hash = 161, - BPF_FUNC_sock_from_file = 162, - BPF_FUNC_check_mtu = 163, - BPF_FUNC_for_each_map_elem = 164, - BPF_FUNC_snprintf = 165, - BPF_FUNC_sys_bpf = 166, - BPF_FUNC_btf_find_by_name_kind = 167, - BPF_FUNC_sys_close = 168, - __BPF_FUNC_MAX_ID = 169, -}; - -enum { - BPF_F_INDEX_MASK = 4294967295, - BPF_F_CURRENT_CPU = 4294967295, - BPF_F_CTXLEN_MASK = 0, -}; - -enum { - BPF_F_GET_BRANCH_RECORDS_SIZE = 1, -}; - -struct bpf_perf_event_value { - __u64 counter; - __u64 enabled; - __u64 running; -}; - -struct bpf_raw_tracepoint_args { - __u64 args[0]; -}; - -enum bpf_task_fd_type { - BPF_FD_TYPE_RAW_TRACEPOINT = 0, - BPF_FD_TYPE_TRACEPOINT = 1, - BPF_FD_TYPE_KPROBE = 2, - BPF_FD_TYPE_KRETPROBE = 3, - BPF_FD_TYPE_UPROBE = 4, - BPF_FD_TYPE_URETPROBE = 5, -}; - -struct btf_ptr { - void *ptr; - __u32 type_id; - __u32 flags; -}; - -enum { - BTF_F_COMPACT = 1, - BTF_F_NONAME = 2, - BTF_F_PTR_RAW = 4, - BTF_F_ZERO = 8, -}; - -struct bpf_local_storage_data; - -struct bpf_local_storage { - struct bpf_local_storage_data *cache[16]; - struct hlist_head list; - void *owner; - struct callback_head rcu; - raw_spinlock_t lock; -}; - -struct bpf_local_storage_map_bucket; - -struct bpf_local_storage_map { - struct bpf_map map; - struct bpf_local_storage_map_bucket *buckets; - u32 bucket_log; - u16 elem_size; - u16 cache_idx; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum bpf_arg_type { - ARG_DONTCARE = 0, - ARG_CONST_MAP_PTR = 1, - ARG_PTR_TO_MAP_KEY = 2, - ARG_PTR_TO_MAP_VALUE = 3, - ARG_PTR_TO_UNINIT_MAP_VALUE = 4, - ARG_PTR_TO_MAP_VALUE_OR_NULL = 5, - ARG_PTR_TO_MEM = 6, - ARG_PTR_TO_MEM_OR_NULL = 7, - ARG_PTR_TO_UNINIT_MEM = 8, - ARG_CONST_SIZE = 9, - ARG_CONST_SIZE_OR_ZERO = 10, - ARG_PTR_TO_CTX = 11, - ARG_PTR_TO_CTX_OR_NULL = 12, - ARG_ANYTHING = 13, - ARG_PTR_TO_SPIN_LOCK = 14, - ARG_PTR_TO_SOCK_COMMON = 15, - ARG_PTR_TO_INT = 16, - ARG_PTR_TO_LONG = 17, - ARG_PTR_TO_SOCKET = 18, - ARG_PTR_TO_SOCKET_OR_NULL = 19, - ARG_PTR_TO_BTF_ID = 20, - ARG_PTR_TO_ALLOC_MEM = 21, - ARG_PTR_TO_ALLOC_MEM_OR_NULL = 22, - ARG_CONST_ALLOC_SIZE_OR_ZERO = 23, - ARG_PTR_TO_BTF_ID_SOCK_COMMON = 24, - ARG_PTR_TO_PERCPU_BTF_ID = 25, - ARG_PTR_TO_FUNC = 26, - ARG_PTR_TO_STACK_OR_NULL = 27, - ARG_PTR_TO_CONST_STR = 28, - __BPF_ARG_TYPE_MAX = 29, -}; - -enum bpf_return_type { - RET_INTEGER = 0, - RET_VOID = 1, - RET_PTR_TO_MAP_VALUE = 2, - RET_PTR_TO_MAP_VALUE_OR_NULL = 3, - RET_PTR_TO_SOCKET_OR_NULL = 4, - RET_PTR_TO_TCP_SOCK_OR_NULL = 5, - RET_PTR_TO_SOCK_COMMON_OR_NULL = 6, - RET_PTR_TO_ALLOC_MEM_OR_NULL = 7, - RET_PTR_TO_BTF_ID_OR_NULL = 8, - RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL = 9, - RET_PTR_TO_MEM_OR_BTF_ID = 10, - RET_PTR_TO_BTF_ID = 11, -}; - -struct bpf_func_proto { - u64 (*func)(u64, u64, u64, u64, u64); - bool gpl_only; - bool pkt_access; - enum bpf_return_type ret_type; - union { - struct { - enum bpf_arg_type arg1_type; - enum bpf_arg_type arg2_type; - enum bpf_arg_type arg3_type; - enum bpf_arg_type arg4_type; - enum bpf_arg_type arg5_type; - }; - enum bpf_arg_type arg_type[5]; - }; - union { - struct { - u32 *arg1_btf_id; - u32 *arg2_btf_id; - u32 *arg3_btf_id; - u32 *arg4_btf_id; - u32 *arg5_btf_id; - }; - u32 *arg_btf_id[5]; - }; - int *ret_btf_id; - bool (*allowed)(const struct bpf_prog *); -}; - -enum bpf_access_type { - BPF_READ = 1, - BPF_WRITE = 2, -}; - -struct bpf_verifier_log; - -struct bpf_insn_access_aux { - enum bpf_reg_type reg_type; - union { - int ctx_field_size; - struct { - struct btf *btf; - u32 btf_id; - }; - }; - struct bpf_verifier_log *log; -}; - -struct bpf_verifier_ops { - const struct bpf_func_proto * (*get_func_proto)(enum bpf_func_id, const struct bpf_prog *); - bool (*is_valid_access)(int, int, enum bpf_access_type, const struct bpf_prog *, struct bpf_insn_access_aux *); - int (*gen_prologue)(struct bpf_insn *, bool, const struct bpf_prog *); - int (*gen_ld_abs)(const struct bpf_insn *, struct bpf_insn *); - u32 (*convert_ctx_access)(enum bpf_access_type, const struct bpf_insn *, struct bpf_insn *, struct bpf_prog *, u32 *); - int (*btf_struct_access)(struct bpf_verifier_log *, const struct btf *, const struct btf_type *, int, int, enum bpf_access_type, u32 *); - bool (*check_kfunc_call)(u32); -}; - -struct bpf_event_entry { - struct perf_event *event; - struct file *perf_file; - struct file *map_file; - struct callback_head rcu; -}; - -typedef long unsigned int (*bpf_ctx_copy_t)(void *, const void *, long unsigned int, long unsigned int); - -typedef struct pt_regs bpf_user_pt_regs_t; - -struct bpf_perf_event_data { - bpf_user_pt_regs_t regs; - __u64 sample_period; - __u64 addr; -}; - -struct perf_event_query_bpf { - __u32 ids_len; - __u32 prog_cnt; - __u32 ids[0]; -}; - -struct bpf_perf_event_data_kern { - bpf_user_pt_regs_t *regs; - struct perf_sample_data *data; - struct perf_event *event; -}; - -struct btf_id_set { - u32 cnt; - u32 ids[0]; -}; - -struct bpf_local_storage_map_bucket { - struct hlist_head list; - raw_spinlock_t lock; -}; - -struct bpf_local_storage_data { - struct bpf_local_storage_map *smap; - u8 data[0]; -}; - -struct trace_event_raw_bpf_trace_printk { - struct trace_entry ent; - u32 __data_loc_bpf_string; - char __data[0]; -}; - -struct trace_event_data_offsets_bpf_trace_printk { - u32 bpf_string; -}; - -typedef void (*btf_trace_bpf_trace_printk)(void *, const char *); - -struct bpf_trace_module { - struct module *module; - struct list_head list; -}; - -typedef u64 (*btf_bpf_override_return)(struct pt_regs *, long unsigned int); - -typedef u64 (*btf_bpf_probe_read_user)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_user_str)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_kernel)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_kernel_str)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_compat)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_read_compat_str)(void *, u32, const void *); - -typedef u64 (*btf_bpf_probe_write_user)(void *, const void *, u32); - -typedef u64 (*btf_bpf_trace_printk)(char *, u32, u64, u64, u64); - -typedef u64 (*btf_bpf_seq_printf)(struct seq_file *, char *, u32, const void *, u32); - -typedef u64 (*btf_bpf_seq_write)(struct seq_file *, const void *, u32); - -typedef u64 (*btf_bpf_seq_printf_btf)(struct seq_file *, struct btf_ptr *, u32, u64); - -typedef u64 (*btf_bpf_perf_event_read)(struct bpf_map *, u64); - -typedef u64 (*btf_bpf_perf_event_read_value)(struct bpf_map *, u64, struct bpf_perf_event_value *, u32); - -struct bpf_trace_sample_data { - struct perf_sample_data sds[3]; -}; - -typedef u64 (*btf_bpf_perf_event_output)(struct pt_regs *, struct bpf_map *, u64, void *, u64); - -struct bpf_nested_pt_regs { - struct pt_regs regs[3]; -}; - -typedef u64 (*btf_bpf_get_current_task)(); - -typedef u64 (*btf_bpf_get_current_task_btf)(); - -typedef u64 (*btf_bpf_current_task_under_cgroup)(struct bpf_map *, u32); - -struct send_signal_irq_work { - struct irq_work irq_work; - struct task_struct *task; - u32 sig; - enum pid_type type; -}; - -typedef u64 (*btf_bpf_send_signal)(u32); - -typedef u64 (*btf_bpf_send_signal_thread)(u32); - -typedef u64 (*btf_bpf_d_path)(struct path *, char *, u32); - -typedef u64 (*btf_bpf_snprintf_btf)(char *, u32, struct btf_ptr *, u32, u64); - -typedef u64 (*btf_bpf_perf_event_output_tp)(void *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_get_stackid_tp)(void *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stack_tp)(void *, void *, u32, u64); - -typedef u64 (*btf_bpf_perf_prog_read_value)(struct bpf_perf_event_data_kern *, struct bpf_perf_event_value *, u32); - -typedef u64 (*btf_bpf_read_branch_records)(struct bpf_perf_event_data_kern *, void *, u32, u64); - -struct bpf_raw_tp_regs { - struct pt_regs regs[3]; -}; - -typedef u64 (*btf_bpf_perf_event_output_raw_tp)(struct bpf_raw_tracepoint_args *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_get_stackid_raw_tp)(struct bpf_raw_tracepoint_args *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stack_raw_tp)(struct bpf_raw_tracepoint_args *, void *, u32, u64); - -struct kprobe_trace_entry_head { - struct trace_entry ent; - long unsigned int ip; -}; - -struct kretprobe_trace_entry_head { - struct trace_entry ent; - long unsigned int func; - long unsigned int ret_ip; -}; - -typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); - -enum fetch_op { - FETCH_OP_NOP = 0, - FETCH_OP_REG = 1, - FETCH_OP_STACK = 2, - FETCH_OP_STACKP = 3, - FETCH_OP_RETVAL = 4, - FETCH_OP_IMM = 5, - FETCH_OP_COMM = 6, - FETCH_OP_ARG = 7, - FETCH_OP_FOFFS = 8, - FETCH_OP_DATA = 9, - FETCH_OP_DEREF = 10, - FETCH_OP_UDEREF = 11, - FETCH_OP_ST_RAW = 12, - FETCH_OP_ST_MEM = 13, - FETCH_OP_ST_UMEM = 14, - FETCH_OP_ST_STRING = 15, - FETCH_OP_ST_USTRING = 16, - FETCH_OP_MOD_BF = 17, - FETCH_OP_LP_ARRAY = 18, - FETCH_OP_END = 19, - FETCH_NOP_SYMBOL = 20, -}; - -struct fetch_insn { - enum fetch_op op; - union { - unsigned int param; - struct { - unsigned int size; - int offset; - }; - struct { - unsigned char basesize; - unsigned char lshift; - unsigned char rshift; - }; - long unsigned int immediate; - void *data; - }; -}; - -struct fetch_type { - const char *name; - size_t size; - int is_signed; - print_type_func_t print; - const char *fmt; - const char *fmttype; -}; - -struct probe_arg { - struct fetch_insn *code; - bool dynamic; - unsigned int offset; - unsigned int count; - const char *name; - const char *comm; - char *fmt; - const struct fetch_type *type; -}; - -struct trace_uprobe_filter { - rwlock_t rwlock; - int nr_systemwide; - struct list_head perf_events; -}; - -struct trace_probe_event { - unsigned int flags; - struct trace_event_class class; - struct trace_event_call call; - struct list_head files; - struct list_head probes; - struct trace_uprobe_filter filter[0]; -}; - -struct trace_probe { - struct list_head list; - struct trace_probe_event *event; - ssize_t size; - unsigned int nr_args; - struct probe_arg args[0]; -}; - -struct event_file_link { - struct trace_event_file *file; - struct list_head list; -}; - -enum { - TP_ERR_FILE_NOT_FOUND = 0, - TP_ERR_NO_REGULAR_FILE = 1, - TP_ERR_BAD_REFCNT = 2, - TP_ERR_REFCNT_OPEN_BRACE = 3, - TP_ERR_BAD_REFCNT_SUFFIX = 4, - TP_ERR_BAD_UPROBE_OFFS = 5, - TP_ERR_MAXACT_NO_KPROBE = 6, - TP_ERR_BAD_MAXACT = 7, - TP_ERR_MAXACT_TOO_BIG = 8, - TP_ERR_BAD_PROBE_ADDR = 9, - TP_ERR_BAD_RETPROBE = 10, - TP_ERR_BAD_ADDR_SUFFIX = 11, - TP_ERR_NO_GROUP_NAME = 12, - TP_ERR_GROUP_TOO_LONG = 13, - TP_ERR_BAD_GROUP_NAME = 14, - TP_ERR_NO_EVENT_NAME = 15, - TP_ERR_EVENT_TOO_LONG = 16, - TP_ERR_BAD_EVENT_NAME = 17, - TP_ERR_RETVAL_ON_PROBE = 18, - TP_ERR_BAD_STACK_NUM = 19, - TP_ERR_BAD_ARG_NUM = 20, - TP_ERR_BAD_VAR = 21, - TP_ERR_BAD_REG_NAME = 22, - TP_ERR_BAD_MEM_ADDR = 23, - TP_ERR_BAD_IMM = 24, - TP_ERR_IMMSTR_NO_CLOSE = 25, - TP_ERR_FILE_ON_KPROBE = 26, - TP_ERR_BAD_FILE_OFFS = 27, - TP_ERR_SYM_ON_UPROBE = 28, - TP_ERR_TOO_MANY_OPS = 29, - TP_ERR_DEREF_NEED_BRACE = 30, - TP_ERR_BAD_DEREF_OFFS = 31, - TP_ERR_DEREF_OPEN_BRACE = 32, - TP_ERR_COMM_CANT_DEREF = 33, - TP_ERR_BAD_FETCH_ARG = 34, - TP_ERR_ARRAY_NO_CLOSE = 35, - TP_ERR_BAD_ARRAY_SUFFIX = 36, - TP_ERR_BAD_ARRAY_NUM = 37, - TP_ERR_ARRAY_TOO_BIG = 38, - TP_ERR_BAD_TYPE = 39, - TP_ERR_BAD_STRING = 40, - TP_ERR_BAD_BITFIELD = 41, - TP_ERR_ARG_NAME_TOO_LONG = 42, - TP_ERR_NO_ARG_NAME = 43, - TP_ERR_BAD_ARG_NAME = 44, - TP_ERR_USED_ARG_NAME = 45, - TP_ERR_ARG_TOO_LONG = 46, - TP_ERR_NO_ARG_BODY = 47, - TP_ERR_BAD_INSN_BNDRY = 48, - TP_ERR_FAIL_REG_PROBE = 49, - TP_ERR_DIFF_PROBE_TYPE = 50, - TP_ERR_DIFF_ARG_TYPE = 51, - TP_ERR_SAME_PROBE = 52, -}; - -struct trace_kprobe { - struct dyn_event devent; - struct kretprobe rp; - long unsigned int *nhit; - const char *symbol; - struct trace_probe tp; -}; - -enum error_detector { - ERROR_DETECTOR_KFENCE = 0, - ERROR_DETECTOR_KASAN = 1, -}; - -struct trace_event_raw_error_report_template { - struct trace_entry ent; - enum error_detector error_detector; - long unsigned int id; - char __data[0]; -}; - -struct trace_event_data_offsets_error_report_template {}; - -typedef void (*btf_trace_error_report_end)(void *, enum error_detector, long unsigned int); - -struct trace_event_raw_cpu { - struct trace_entry ent; - u32 state; - u32 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_powernv_throttle { - struct trace_entry ent; - int chip_id; - u32 __data_loc_reason; - int pmax; - char __data[0]; -}; - -struct trace_event_raw_pstate_sample { - struct trace_entry ent; - u32 core_busy; - u32 scaled_busy; - u32 from; - u32 to; - u64 mperf; - u64 aperf; - u64 tsc; - u32 freq; - u32 io_boost; - char __data[0]; -}; - -struct trace_event_raw_cpu_frequency_limits { - struct trace_entry ent; - u32 min_freq; - u32 max_freq; - u32 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_device_pm_callback_start { - struct trace_entry ent; - u32 __data_loc_device; - u32 __data_loc_driver; - u32 __data_loc_parent; - u32 __data_loc_pm_ops; - int event; - char __data[0]; -}; - -struct trace_event_raw_device_pm_callback_end { - struct trace_entry ent; - u32 __data_loc_device; - u32 __data_loc_driver; - int error; - char __data[0]; -}; - -struct trace_event_raw_suspend_resume { - struct trace_entry ent; - const char *action; - int val; - bool start; - char __data[0]; -}; - -struct trace_event_raw_wakeup_source { - struct trace_entry ent; - u32 __data_loc_name; - u64 state; - char __data[0]; -}; - -struct trace_event_raw_clock { - struct trace_entry ent; - u32 __data_loc_name; - u64 state; - u64 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_power_domain { - struct trace_entry ent; - u32 __data_loc_name; - u64 state; - u64 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_cpu_latency_qos_request { - struct trace_entry ent; - s32 value; - char __data[0]; -}; - -struct trace_event_raw_pm_qos_update { - struct trace_entry ent; - enum pm_qos_req_action action; - int prev_value; - int curr_value; - char __data[0]; -}; - -struct trace_event_raw_dev_pm_qos_request { - struct trace_entry ent; - u32 __data_loc_name; - enum dev_pm_qos_req_type type; - s32 new_value; - char __data[0]; -}; - -struct trace_event_data_offsets_cpu {}; - -struct trace_event_data_offsets_powernv_throttle { - u32 reason; -}; - -struct trace_event_data_offsets_pstate_sample {}; - -struct trace_event_data_offsets_cpu_frequency_limits {}; - -struct trace_event_data_offsets_device_pm_callback_start { - u32 device; - u32 driver; - u32 parent; - u32 pm_ops; -}; - -struct trace_event_data_offsets_device_pm_callback_end { - u32 device; - u32 driver; -}; - -struct trace_event_data_offsets_suspend_resume {}; - -struct trace_event_data_offsets_wakeup_source { - u32 name; -}; - -struct trace_event_data_offsets_clock { - u32 name; -}; - -struct trace_event_data_offsets_power_domain { - u32 name; -}; - -struct trace_event_data_offsets_cpu_latency_qos_request {}; - -struct trace_event_data_offsets_pm_qos_update {}; - -struct trace_event_data_offsets_dev_pm_qos_request { - u32 name; -}; - -typedef void (*btf_trace_cpu_idle)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_powernv_throttle)(void *, int, const char *, int); - -typedef void (*btf_trace_pstate_sample)(void *, u32, u32, u32, u32, u64, u64, u64, u32, u32); - -typedef void (*btf_trace_cpu_frequency)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_cpu_frequency_limits)(void *, struct cpufreq_policy *); - -typedef void (*btf_trace_device_pm_callback_start)(void *, struct device *, const char *, int); - -typedef void (*btf_trace_device_pm_callback_end)(void *, struct device *, int); - -typedef void (*btf_trace_suspend_resume)(void *, const char *, int, bool); - -typedef void (*btf_trace_wakeup_source_activate)(void *, const char *, unsigned int); - -typedef void (*btf_trace_wakeup_source_deactivate)(void *, const char *, unsigned int); - -typedef void (*btf_trace_clock_enable)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_clock_disable)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_clock_set_rate)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_power_domain_target)(void *, const char *, unsigned int, unsigned int); - -typedef void (*btf_trace_pm_qos_add_request)(void *, s32); - -typedef void (*btf_trace_pm_qos_update_request)(void *, s32); - -typedef void (*btf_trace_pm_qos_remove_request)(void *, s32); - -typedef void (*btf_trace_pm_qos_update_target)(void *, enum pm_qos_req_action, int, int); - -typedef void (*btf_trace_pm_qos_update_flags)(void *, enum pm_qos_req_action, int, int); - -typedef void (*btf_trace_dev_pm_qos_add_request)(void *, const char *, enum dev_pm_qos_req_type, s32); - -typedef void (*btf_trace_dev_pm_qos_update_request)(void *, const char *, enum dev_pm_qos_req_type, s32); - -typedef void (*btf_trace_dev_pm_qos_remove_request)(void *, const char *, enum dev_pm_qos_req_type, s32); - -struct trace_event_raw_rpm_internal { - struct trace_entry ent; - u32 __data_loc_name; - int flags; - int usage_count; - int disable_depth; - int runtime_auto; - int request_pending; - int irq_safe; - int child_count; - char __data[0]; -}; - -struct trace_event_raw_rpm_return_int { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int ip; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_rpm_internal { - u32 name; -}; - -struct trace_event_data_offsets_rpm_return_int { - u32 name; -}; - -typedef void (*btf_trace_rpm_suspend)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_resume)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_idle)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_usage)(void *, struct device *, int); - -typedef void (*btf_trace_rpm_return_int)(void *, struct device *, long unsigned int, int); - -struct trace_probe_log { - const char *subsystem; - const char **argv; - int argc; - int index; -}; - -enum uprobe_filter_ctx { - UPROBE_FILTER_REGISTER = 0, - UPROBE_FILTER_UNREGISTER = 1, - UPROBE_FILTER_MMAP = 2, -}; - -struct uprobe_consumer { - int (*handler)(struct uprobe_consumer *, struct pt_regs *); - int (*ret_handler)(struct uprobe_consumer *, long unsigned int, struct pt_regs *); - bool (*filter)(struct uprobe_consumer *, enum uprobe_filter_ctx, struct mm_struct *); - struct uprobe_consumer *next; -}; - -struct uprobe_trace_entry_head { - struct trace_entry ent; - long unsigned int vaddr[0]; -}; - -struct trace_uprobe { - struct dyn_event devent; - struct uprobe_consumer consumer; - struct path path; - struct inode *inode; - char *filename; - long unsigned int offset; - long unsigned int ref_ctr_offset; - long unsigned int nhit; - struct trace_probe tp; -}; - -struct uprobe_dispatch_data { - struct trace_uprobe *tu; - long unsigned int bp_addr; -}; - -struct uprobe_cpu_buffer { - struct mutex mutex; - void *buf; -}; - -typedef bool (*filter_func_t)(struct uprobe_consumer *, enum uprobe_filter_ctx, struct mm_struct *); - -struct rhash_lock_head; - -struct bucket_table { - unsigned int size; - unsigned int nest; - u32 hash_rnd; - struct list_head walkers; - struct callback_head rcu; - struct bucket_table *future_tbl; - struct lockdep_map dep_map; - long: 64; - struct rhash_lock_head *buckets[0]; -}; - -enum xdp_action { - XDP_ABORTED = 0, - XDP_DROP = 1, - XDP_PASS = 2, - XDP_TX = 3, - XDP_REDIRECT = 4, -}; - -enum xdp_mem_type { - MEM_TYPE_PAGE_SHARED = 0, - MEM_TYPE_PAGE_ORDER0 = 1, - MEM_TYPE_PAGE_POOL = 2, - MEM_TYPE_XSK_BUFF_POOL = 3, - MEM_TYPE_MAX = 4, -}; - -struct xdp_cpumap_stats { - unsigned int redirect; - unsigned int pass; - unsigned int drop; -}; - -struct bpf_prog_dummy { - struct bpf_prog prog; -}; - -typedef u64 (*btf_bpf_user_rnd_u32)(); - -typedef u64 (*btf_bpf_get_raw_cpu_id)(); - -struct _bpf_dtab_netdev { - struct net_device *dev; -}; - -struct rhash_lock_head {}; - -struct zero_copy_allocator; - -struct xdp_mem_allocator { - struct xdp_mem_info mem; - union { - void *allocator; - struct page_pool *page_pool; - struct zero_copy_allocator *zc_alloc; - }; - struct rhash_head node; - struct callback_head rcu; -}; - -struct trace_event_raw_xdp_exception { - struct trace_entry ent; - int prog_id; - u32 act; - int ifindex; - char __data[0]; -}; - -struct trace_event_raw_xdp_bulk_tx { - struct trace_entry ent; - int ifindex; - u32 act; - int drops; - int sent; - int err; - char __data[0]; -}; - -struct trace_event_raw_xdp_redirect_template { - struct trace_entry ent; - int prog_id; - u32 act; - int ifindex; - int err; - int to_ifindex; - u32 map_id; - int map_index; - char __data[0]; -}; - -struct trace_event_raw_xdp_cpumap_kthread { - struct trace_entry ent; - int map_id; - u32 act; - int cpu; - unsigned int drops; - unsigned int processed; - int sched; - unsigned int xdp_pass; - unsigned int xdp_drop; - unsigned int xdp_redirect; - char __data[0]; -}; - -struct trace_event_raw_xdp_cpumap_enqueue { - struct trace_entry ent; - int map_id; - u32 act; - int cpu; - unsigned int drops; - unsigned int processed; - int to_cpu; - char __data[0]; -}; - -struct trace_event_raw_xdp_devmap_xmit { - struct trace_entry ent; - int from_ifindex; - u32 act; - int to_ifindex; - int drops; - int sent; - int err; - char __data[0]; -}; - -struct trace_event_raw_mem_disconnect { - struct trace_entry ent; - const struct xdp_mem_allocator *xa; - u32 mem_id; - u32 mem_type; - const void *allocator; - char __data[0]; -}; - -struct trace_event_raw_mem_connect { - struct trace_entry ent; - const struct xdp_mem_allocator *xa; - u32 mem_id; - u32 mem_type; - const void *allocator; - const struct xdp_rxq_info *rxq; - int ifindex; - char __data[0]; -}; - -struct trace_event_raw_mem_return_failed { - struct trace_entry ent; - const struct page *page; - u32 mem_id; - u32 mem_type; - char __data[0]; -}; - -struct trace_event_data_offsets_xdp_exception {}; - -struct trace_event_data_offsets_xdp_bulk_tx {}; - -struct trace_event_data_offsets_xdp_redirect_template {}; - -struct trace_event_data_offsets_xdp_cpumap_kthread {}; - -struct trace_event_data_offsets_xdp_cpumap_enqueue {}; - -struct trace_event_data_offsets_xdp_devmap_xmit {}; - -struct trace_event_data_offsets_mem_disconnect {}; - -struct trace_event_data_offsets_mem_connect {}; - -struct trace_event_data_offsets_mem_return_failed {}; - -typedef void (*btf_trace_xdp_exception)(void *, const struct net_device *, const struct bpf_prog *, u32); - -typedef void (*btf_trace_xdp_bulk_tx)(void *, const struct net_device *, int, int, int); - -typedef void (*btf_trace_xdp_redirect)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32); - -typedef void (*btf_trace_xdp_redirect_err)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32); - -typedef void (*btf_trace_xdp_redirect_map)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32); - -typedef void (*btf_trace_xdp_redirect_map_err)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32); - -typedef void (*btf_trace_xdp_cpumap_kthread)(void *, int, unsigned int, unsigned int, int, struct xdp_cpumap_stats *); - -typedef void (*btf_trace_xdp_cpumap_enqueue)(void *, int, unsigned int, unsigned int, int); - -typedef void (*btf_trace_xdp_devmap_xmit)(void *, const struct net_device *, const struct net_device *, int, int, int); - -typedef void (*btf_trace_mem_disconnect)(void *, const struct xdp_mem_allocator *); - -typedef void (*btf_trace_mem_connect)(void *, const struct xdp_mem_allocator *, const struct xdp_rxq_info *); - -typedef void (*btf_trace_mem_return_failed)(void *, const struct xdp_mem_info *, const struct page *); - -enum bpf_cmd { - BPF_MAP_CREATE = 0, - BPF_MAP_LOOKUP_ELEM = 1, - BPF_MAP_UPDATE_ELEM = 2, - BPF_MAP_DELETE_ELEM = 3, - BPF_MAP_GET_NEXT_KEY = 4, - BPF_PROG_LOAD = 5, - BPF_OBJ_PIN = 6, - BPF_OBJ_GET = 7, - BPF_PROG_ATTACH = 8, - BPF_PROG_DETACH = 9, - BPF_PROG_TEST_RUN = 10, - BPF_PROG_RUN = 10, - BPF_PROG_GET_NEXT_ID = 11, - BPF_MAP_GET_NEXT_ID = 12, - BPF_PROG_GET_FD_BY_ID = 13, - BPF_MAP_GET_FD_BY_ID = 14, - BPF_OBJ_GET_INFO_BY_FD = 15, - BPF_PROG_QUERY = 16, - BPF_RAW_TRACEPOINT_OPEN = 17, - BPF_BTF_LOAD = 18, - BPF_BTF_GET_FD_BY_ID = 19, - BPF_TASK_FD_QUERY = 20, - BPF_MAP_LOOKUP_AND_DELETE_ELEM = 21, - BPF_MAP_FREEZE = 22, - BPF_BTF_GET_NEXT_ID = 23, - BPF_MAP_LOOKUP_BATCH = 24, - BPF_MAP_LOOKUP_AND_DELETE_BATCH = 25, - BPF_MAP_UPDATE_BATCH = 26, - BPF_MAP_DELETE_BATCH = 27, - BPF_LINK_CREATE = 28, - BPF_LINK_UPDATE = 29, - BPF_LINK_GET_FD_BY_ID = 30, - BPF_LINK_GET_NEXT_ID = 31, - BPF_ENABLE_STATS = 32, - BPF_ITER_CREATE = 33, - BPF_LINK_DETACH = 34, - BPF_PROG_BIND_MAP = 35, -}; - -enum { - BPF_ANY = 0, - BPF_NOEXIST = 1, - BPF_EXIST = 2, - BPF_F_LOCK = 4, -}; - -enum { - BPF_F_NO_PREALLOC = 1, - BPF_F_NO_COMMON_LRU = 2, - BPF_F_NUMA_NODE = 4, - BPF_F_RDONLY = 8, - BPF_F_WRONLY = 16, - BPF_F_STACK_BUILD_ID = 32, - BPF_F_ZERO_SEED = 64, - BPF_F_RDONLY_PROG = 128, - BPF_F_WRONLY_PROG = 256, - BPF_F_CLONE = 512, - BPF_F_MMAPABLE = 1024, - BPF_F_PRESERVE_ELEMS = 2048, - BPF_F_INNER_MAP = 4096, -}; - -enum bpf_stats_type { - BPF_STATS_RUN_TIME = 0, -}; - -struct bpf_prog_info { - __u32 type; - __u32 id; - __u8 tag[8]; - __u32 jited_prog_len; - __u32 xlated_prog_len; - __u64 jited_prog_insns; - __u64 xlated_prog_insns; - __u64 load_time; - __u32 created_by_uid; - __u32 nr_map_ids; - __u64 map_ids; - char name[16]; - __u32 ifindex; - __u32 gpl_compatible: 1; - __u64 netns_dev; - __u64 netns_ino; - __u32 nr_jited_ksyms; - __u32 nr_jited_func_lens; - __u64 jited_ksyms; - __u64 jited_func_lens; - __u32 btf_id; - __u32 func_info_rec_size; - __u64 func_info; - __u32 nr_func_info; - __u32 nr_line_info; - __u64 line_info; - __u64 jited_line_info; - __u32 nr_jited_line_info; - __u32 line_info_rec_size; - __u32 jited_line_info_rec_size; - __u32 nr_prog_tags; - __u64 prog_tags; - __u64 run_time_ns; - __u64 run_cnt; - __u64 recursion_misses; -}; - -struct bpf_map_info { - __u32 type; - __u32 id; - __u32 key_size; - __u32 value_size; - __u32 max_entries; - __u32 map_flags; - char name[16]; - __u32 ifindex; - __u32 btf_vmlinux_value_type_id; - __u64 netns_dev; - __u64 netns_ino; - __u32 btf_id; - __u32 btf_key_type_id; - __u32 btf_value_type_id; -}; - -struct bpf_btf_info { - __u64 btf; - __u32 btf_size; - __u32 id; - __u64 name; - __u32 name_len; - __u32 kernel_btf; -}; - -struct bpf_spin_lock { - __u32 val; -}; - -typedef sockptr_t bpfptr_t; - -struct bpf_verifier_log { - u32 level; - char kbuf[1024]; - char *ubuf; - u32 len_used; - u32 len_total; -}; - -struct bpf_subprog_info { - u32 start; - u32 linfo_idx; - u16 stack_depth; - bool has_tail_call; - bool tail_call_reachable; - bool has_ld_abs; -}; - -struct bpf_id_pair { - u32 old; - u32 cur; -}; - -struct bpf_verifier_stack_elem; - -struct bpf_verifier_state; - -struct bpf_verifier_state_list; - -struct bpf_insn_aux_data; - -struct bpf_verifier_env { - u32 insn_idx; - u32 prev_insn_idx; - struct bpf_prog *prog; - const struct bpf_verifier_ops *ops; - struct bpf_verifier_stack_elem *head; - int stack_size; - bool strict_alignment; - bool test_state_freq; - struct bpf_verifier_state *cur_state; - struct bpf_verifier_state_list **explored_states; - struct bpf_verifier_state_list *free_list; - struct bpf_map *used_maps[64]; - struct btf_mod_pair used_btfs[64]; - u32 used_map_cnt; - u32 used_btf_cnt; - u32 id_gen; - bool explore_alu_limits; - bool allow_ptr_leaks; - bool allow_uninit_stack; - bool allow_ptr_to_map_access; - bool bpf_capable; - bool bypass_spec_v1; - bool bypass_spec_v4; - bool seen_direct_write; - struct bpf_insn_aux_data *insn_aux_data; - const struct bpf_line_info *prev_linfo; - struct bpf_verifier_log log; - struct bpf_subprog_info subprog_info[257]; - struct bpf_id_pair idmap_scratch[75]; - struct { - int *insn_state; - int *insn_stack; - int cur_stack; - } cfg; - u32 pass_cnt; - u32 subprog_cnt; - u32 prev_insn_processed; - u32 insn_processed; - u32 prev_jmps_processed; - u32 jmps_processed; - u64 verification_time; - u32 max_states_per_insn; - u32 total_states; - u32 peak_states; - u32 longest_mark_read_walk; - bpfptr_t fd_array; -}; - -struct tnum { - u64 value; - u64 mask; -}; - -enum bpf_reg_liveness { - REG_LIVE_NONE = 0, - REG_LIVE_READ32 = 1, - REG_LIVE_READ64 = 2, - REG_LIVE_READ = 3, - REG_LIVE_WRITTEN = 4, - REG_LIVE_DONE = 8, -}; - -struct bpf_reg_state { - enum bpf_reg_type type; - s32 off; - union { - int range; - struct bpf_map *map_ptr; - struct { - struct btf *btf; - u32 btf_id; - }; - u32 mem_size; - struct { - long unsigned int raw1; - long unsigned int raw2; - } raw; - u32 subprogno; - }; - u32 id; - u32 ref_obj_id; - struct tnum var_off; - s64 smin_value; - s64 smax_value; - u64 umin_value; - u64 umax_value; - s32 s32_min_value; - s32 s32_max_value; - u32 u32_min_value; - u32 u32_max_value; - struct bpf_reg_state *parent; - u32 frameno; - s32 subreg_def; - enum bpf_reg_liveness live; - bool precise; -}; - -struct bpf_reference_state; - -struct bpf_stack_state; - -struct bpf_func_state { - struct bpf_reg_state regs[11]; - int callsite; - u32 frameno; - u32 subprogno; - int acquired_refs; - struct bpf_reference_state *refs; - int allocated_stack; - bool in_callback_fn; - struct bpf_stack_state *stack; -}; - -struct bpf_attach_target_info { - struct btf_func_model fmodel; - long int tgt_addr; - const char *tgt_name; - const struct btf_type *tgt_type; -}; - -struct bpf_link_primer { - struct bpf_link *link; - struct file *file; - int fd; - u32 id; -}; - -struct bpf_stack_state { - struct bpf_reg_state spilled_ptr; - u8 slot_type[8]; -}; - -struct bpf_reference_state { - int id; - int insn_idx; -}; - -struct bpf_idx_pair { - u32 prev_idx; - u32 idx; -}; - -struct bpf_verifier_state { - struct bpf_func_state *frame[8]; - struct bpf_verifier_state *parent; - u32 branches; - u32 insn_idx; - u32 curframe; - u32 active_spin_lock; - bool speculative; - u32 first_insn_idx; - u32 last_insn_idx; - struct bpf_idx_pair *jmp_history; - u32 jmp_history_cnt; -}; - -struct bpf_verifier_state_list { - struct bpf_verifier_state state; - struct bpf_verifier_state_list *next; - int miss_cnt; - int hit_cnt; -}; - -struct bpf_insn_aux_data { - union { - enum bpf_reg_type ptr_type; - long unsigned int map_ptr_state; - s32 call_imm; - u32 alu_limit; - struct { - u32 map_index; - u32 map_off; - }; - struct { - enum bpf_reg_type reg_type; - union { - struct { - struct btf *btf; - u32 btf_id; - }; - u32 mem_size; - }; - } btf_var; - }; - u64 map_key_state; - int ctx_field_size; - u32 seen; - bool sanitize_stack_spill; - bool zext_dst; - u8 alu_state; - unsigned int orig_idx; - bool prune_point; -}; - -enum perf_bpf_event_type { - PERF_BPF_EVENT_UNKNOWN = 0, - PERF_BPF_EVENT_PROG_LOAD = 1, - PERF_BPF_EVENT_PROG_UNLOAD = 2, - PERF_BPF_EVENT_MAX = 3, -}; - -enum bpf_audit { - BPF_AUDIT_LOAD = 0, - BPF_AUDIT_UNLOAD = 1, - BPF_AUDIT_MAX = 2, -}; - -struct bpf_tracing_link { - struct bpf_link link; - enum bpf_attach_type attach_type; - struct bpf_trampoline *trampoline; - struct bpf_prog *tgt_prog; -}; - -struct bpf_raw_tp_link { - struct bpf_link link; - struct bpf_raw_event_map *btp; -}; - -typedef u64 (*btf_bpf_sys_bpf)(int, void *, u32); - -typedef u64 (*btf_bpf_sys_close)(u32); - -struct btf_member { - __u32 name_off; - __u32 type; - __u32 offset; -}; - -struct btf_param { - __u32 name_off; - __u32 type; -}; - -enum btf_func_linkage { - BTF_FUNC_STATIC = 0, - BTF_FUNC_GLOBAL = 1, - BTF_FUNC_EXTERN = 2, -}; - -struct btf_var_secinfo { - __u32 type; - __u32 offset; - __u32 size; -}; - -enum sk_action { - SK_DROP = 0, - SK_PASS = 1, -}; - -struct bpf_kfunc_desc { - struct btf_func_model func_model; - u32 func_id; - s32 imm; -}; - -struct bpf_kfunc_desc_tab { - struct bpf_kfunc_desc descs[256]; - u32 nr_descs; -}; - -struct bpf_struct_ops { - const struct bpf_verifier_ops *verifier_ops; - int (*init)(struct btf *); - int (*check_member)(const struct btf_type *, const struct btf_member *); - int (*init_member)(const struct btf_type *, const struct btf_member *, void *, const void *); - int (*reg)(void *); - void (*unreg)(void *); - const struct btf_type *type; - const struct btf_type *value_type; - const char *name; - struct btf_func_model func_models[64]; - u32 type_id; - u32 value_id; -}; - -typedef u32 (*bpf_convert_ctx_access_t)(enum bpf_access_type, const struct bpf_insn *, struct bpf_insn *, struct bpf_prog *, u32 *); - -enum bpf_stack_slot_type { - STACK_INVALID = 0, - STACK_SPILL = 1, - STACK_MISC = 2, - STACK_ZERO = 3, -}; - -struct bpf_verifier_stack_elem { - struct bpf_verifier_state st; - int insn_idx; - int prev_insn_idx; - struct bpf_verifier_stack_elem *next; - u32 log_pos; -}; - -enum { - BTF_SOCK_TYPE_INET = 0, - BTF_SOCK_TYPE_INET_CONN = 1, - BTF_SOCK_TYPE_INET_REQ = 2, - BTF_SOCK_TYPE_INET_TW = 3, - BTF_SOCK_TYPE_REQ = 4, - BTF_SOCK_TYPE_SOCK = 5, - BTF_SOCK_TYPE_SOCK_COMMON = 6, - BTF_SOCK_TYPE_TCP = 7, - BTF_SOCK_TYPE_TCP_REQ = 8, - BTF_SOCK_TYPE_TCP_TW = 9, - BTF_SOCK_TYPE_TCP6 = 10, - BTF_SOCK_TYPE_UDP = 11, - BTF_SOCK_TYPE_UDP6 = 12, - MAX_BTF_SOCK_TYPE = 13, -}; - -typedef void (*bpf_insn_print_t)(void *, const char *, ...); - -typedef const char * (*bpf_insn_revmap_call_t)(void *, const struct bpf_insn *); - -typedef const char * (*bpf_insn_print_imm_t)(void *, const struct bpf_insn *, __u64); - -struct bpf_insn_cbs { - bpf_insn_print_t cb_print; - bpf_insn_revmap_call_t cb_call; - bpf_insn_print_imm_t cb_imm; - void *private_data; -}; - -struct bpf_call_arg_meta { - struct bpf_map *map_ptr; - bool raw_mode; - bool pkt_access; - int regno; - int access_size; - int mem_size; - u64 msize_max_value; - int ref_obj_id; - int func_id; - struct btf *btf; - u32 btf_id; - struct btf *ret_btf; - u32 ret_btf_id; - u32 subprogno; -}; - -enum reg_arg_type { - SRC_OP = 0, - DST_OP = 1, - DST_OP_NO_MARK = 2, -}; - -enum stack_access_src { - ACCESS_DIRECT = 1, - ACCESS_HELPER = 2, -}; - -struct bpf_reg_types { - const enum bpf_reg_type types[10]; - u32 *btf_id; -}; - -enum { - AT_PKT_END = 4294967295, - BEYOND_PKT_END = 4294967294, -}; - -typedef int (*set_callee_state_fn)(struct bpf_verifier_env *, struct bpf_func_state *, struct bpf_func_state *, int); - -enum { - REASON_BOUNDS = 4294967295, - REASON_TYPE = 4294967294, - REASON_PATHS = 4294967293, - REASON_LIMIT = 4294967292, - REASON_STACK = 4294967291, -}; - -struct bpf_sanitize_info { - struct bpf_insn_aux_data aux; - bool mask_to_left; -}; - -enum { - DISCOVERED = 16, - EXPLORED = 32, - FALLTHROUGH = 1, - BRANCH = 2, -}; - -enum { - DONE_EXPLORING = 0, - KEEP_EXPLORING = 1, -}; - -struct tree_descr { - const char *name; - const struct file_operations *ops; - int mode; -}; - -struct bpf_preload_info { - char link_name[16]; - int link_id; -}; - -struct bpf_preload_ops { - struct umd_info info; - int (*preload)(struct bpf_preload_info *); - int (*finish)(); - struct module *owner; -}; - -enum bpf_type { - BPF_TYPE_UNSPEC = 0, - BPF_TYPE_PROG = 1, - BPF_TYPE_MAP = 2, - BPF_TYPE_LINK = 3, -}; - -struct map_iter { - void *key; - bool done; -}; - -enum { - OPT_MODE = 0, -}; - -struct bpf_mount_opts { - umode_t mode; -}; - -struct bpf_pidns_info { - __u32 pid; - __u32 tgid; -}; - -struct bpf_cgroup_storage_info { - struct task_struct *task; - struct bpf_cgroup_storage *storage[2]; -}; - -typedef u64 (*btf_bpf_map_lookup_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_map_update_elem)(struct bpf_map *, void *, void *, u64); - -typedef u64 (*btf_bpf_map_delete_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_map_push_elem)(struct bpf_map *, void *, u64); - -typedef u64 (*btf_bpf_map_pop_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_map_peek_elem)(struct bpf_map *, void *); - -typedef u64 (*btf_bpf_get_smp_processor_id)(); - -typedef u64 (*btf_bpf_get_numa_node_id)(); - -typedef u64 (*btf_bpf_ktime_get_ns)(); - -typedef u64 (*btf_bpf_ktime_get_boot_ns)(); - -typedef u64 (*btf_bpf_ktime_get_coarse_ns)(); - -typedef u64 (*btf_bpf_get_current_pid_tgid)(); - -typedef u64 (*btf_bpf_get_current_uid_gid)(); - -typedef u64 (*btf_bpf_get_current_comm)(char *, u32); - -typedef u64 (*btf_bpf_spin_lock)(struct bpf_spin_lock *); - -typedef u64 (*btf_bpf_spin_unlock)(struct bpf_spin_lock *); - -typedef u64 (*btf_bpf_jiffies64)(); - -typedef u64 (*btf_bpf_get_current_cgroup_id)(); - -typedef u64 (*btf_bpf_get_current_ancestor_cgroup_id)(int); - -typedef u64 (*btf_bpf_get_local_storage)(struct bpf_map *, u64); - -typedef u64 (*btf_bpf_strtol)(const char *, size_t, u64, long int *); - -typedef u64 (*btf_bpf_strtoul)(const char *, size_t, u64, long unsigned int *); - -typedef u64 (*btf_bpf_get_ns_current_pid_tgid)(u64, u64, struct bpf_pidns_info *, u32); - -typedef u64 (*btf_bpf_event_output_data)(void *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_copy_from_user)(void *, u32, const void *); - -typedef u64 (*btf_bpf_per_cpu_ptr)(const void *, u32); - -typedef u64 (*btf_bpf_this_cpu_ptr)(const void *); - -struct bpf_bprintf_buffers { - char tmp_bufs[1536]; -}; - -typedef u64 (*btf_bpf_snprintf)(char *, u32, char *, const void *, u32); - -union bpf_iter_link_info { - struct { - __u32 map_fd; - } map; -}; - -typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *, union bpf_iter_link_info *, struct bpf_iter_aux_info *); - -typedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *); - -typedef void (*bpf_iter_show_fdinfo_t)(const struct bpf_iter_aux_info *, struct seq_file *); - -typedef int (*bpf_iter_fill_link_info_t)(const struct bpf_iter_aux_info *, struct bpf_link_info *); - -enum bpf_iter_feature { - BPF_ITER_RESCHED = 1, -}; - -struct bpf_iter_reg { - const char *target; - bpf_iter_attach_target_t attach_target; - bpf_iter_detach_target_t detach_target; - bpf_iter_show_fdinfo_t show_fdinfo; - bpf_iter_fill_link_info_t fill_link_info; - u32 ctx_arg_info_size; - u32 feature; - struct bpf_ctx_arg_aux ctx_arg_info[2]; - const struct bpf_iter_seq_info *seq_info; -}; - -struct bpf_iter_meta { - union { - struct seq_file *seq; - }; - u64 session_id; - u64 seq_num; -}; - -struct bpf_iter_target_info { - struct list_head list; - const struct bpf_iter_reg *reg_info; - u32 btf_id; -}; - -struct bpf_iter_link { - struct bpf_link link; - struct bpf_iter_aux_info aux; - struct bpf_iter_target_info *tinfo; -}; - -struct bpf_iter_priv_data { - struct bpf_iter_target_info *tinfo; - const struct bpf_iter_seq_info *seq_info; - struct bpf_prog *prog; - u64 session_id; - u64 seq_num; - bool done_stop; - long: 56; - u8 target_private[0]; -}; - -typedef u64 (*btf_bpf_for_each_map_elem)(struct bpf_map *, void *, void *, u64); - -struct bpf_iter_seq_map_info { - u32 map_id; -}; - -struct bpf_iter__bpf_map { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_map *map; - }; -}; - -struct bpf_iter_seq_task_common { - struct pid_namespace *ns; -}; - -struct bpf_iter_seq_task_info { - struct bpf_iter_seq_task_common common; - u32 tid; -}; - -struct bpf_iter__task { - union { - struct bpf_iter_meta *meta; - }; - union { - struct task_struct *task; - }; -}; - -struct bpf_iter_seq_task_file_info { - struct bpf_iter_seq_task_common common; - struct task_struct *task; - u32 tid; - u32 fd; -}; - -struct bpf_iter__task_file { - union { - struct bpf_iter_meta *meta; - }; - union { - struct task_struct *task; - }; - u32 fd; - union { - struct file *file; - }; -}; - -struct bpf_iter_seq_task_vma_info { - struct bpf_iter_seq_task_common common; - struct task_struct *task; - struct vm_area_struct *vma; - u32 tid; - long unsigned int prev_vm_start; - long unsigned int prev_vm_end; -}; - -enum bpf_task_vma_iter_find_op { - task_vma_iter_first_vma = 0, - task_vma_iter_next_vma = 1, - task_vma_iter_find_vma = 2, -}; - -struct bpf_iter__task_vma { - union { - struct bpf_iter_meta *meta; - }; - union { - struct task_struct *task; - }; - union { - struct vm_area_struct *vma; - }; -}; - -struct bpf_iter_seq_prog_info { - u32 prog_id; -}; - -struct bpf_iter__bpf_prog { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_prog *prog; - }; -}; - -struct bpf_iter__bpf_map_elem { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_map *map; - }; - union { - void *key; - }; - union { - void *value; - }; -}; - -struct pcpu_freelist_node; - -struct pcpu_freelist_head { - struct pcpu_freelist_node *first; - raw_spinlock_t lock; -}; - -struct pcpu_freelist_node { - struct pcpu_freelist_node *next; -}; - -struct pcpu_freelist { - struct pcpu_freelist_head *freelist; - struct pcpu_freelist_head extralist; -}; - -struct bpf_lru_node { - struct list_head list; - u16 cpu; - u8 type; - u8 ref; -}; - -struct bpf_lru_list { - struct list_head lists[3]; - unsigned int counts[2]; - struct list_head *next_inactive_rotation; - raw_spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_lru_locallist { - struct list_head lists[2]; - u16 next_steal; - raw_spinlock_t lock; -}; - -struct bpf_common_lru { - struct bpf_lru_list lru_list; - struct bpf_lru_locallist *local_list; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef bool (*del_from_htab_func)(void *, struct bpf_lru_node *); - -struct bpf_lru { - union { - struct bpf_common_lru common_lru; - struct bpf_lru_list *percpu_lru; - }; - del_from_htab_func del_from_htab; - void *del_arg; - unsigned int hash_offset; - unsigned int nr_scans; - bool percpu; - long: 56; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bucket { - struct hlist_nulls_head head; - union { - raw_spinlock_t raw_lock; - spinlock_t lock; - }; -}; - -struct htab_elem; - -struct bpf_htab { - struct bpf_map map; - struct bucket *buckets; - void *elems; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - union { - struct pcpu_freelist freelist; - struct bpf_lru lru; - }; - struct htab_elem **extra_elems; - atomic_t count; - u32 n_buckets; - u32 elem_size; - u32 hashrnd; - struct lock_class_key lockdep_key; - int *map_locked[8]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct htab_elem { - union { - struct hlist_nulls_node hash_node; - struct { - void *padding; - union { - struct bpf_htab *htab; - struct pcpu_freelist_node fnode; - struct htab_elem *batch_flink; - }; - }; - }; - union { - struct callback_head rcu; - struct bpf_lru_node lru_node; - }; - u32 hash; - int: 32; - char key[0]; -}; - -struct bpf_iter_seq_hash_map_info { - struct bpf_map *map; - struct bpf_htab *htab; - void *percpu_value_buf; - u32 bucket_id; - u32 skip_elems; -}; - -struct bpf_iter_seq_array_map_info { - struct bpf_map *map; - void *percpu_value_buf; - u32 index; -}; - -struct prog_poke_elem { - struct list_head list; - struct bpf_prog_aux *aux; -}; - -enum bpf_lru_list_type { - BPF_LRU_LIST_T_ACTIVE = 0, - BPF_LRU_LIST_T_INACTIVE = 1, - BPF_LRU_LIST_T_FREE = 2, - BPF_LRU_LOCAL_LIST_T_FREE = 3, - BPF_LRU_LOCAL_LIST_T_PENDING = 4, -}; - -struct bpf_lpm_trie_key { - __u32 prefixlen; - __u8 data[0]; -}; - -struct lpm_trie_node { - struct callback_head rcu; - struct lpm_trie_node *child[2]; - u32 prefixlen; - u32 flags; - u8 data[0]; -}; - -struct lpm_trie { - struct bpf_map map; - struct lpm_trie_node *root; - size_t n_entries; - size_t max_prefixlen; - size_t data_size; - spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_cgroup_storage_map { - struct bpf_map map; - spinlock_t lock; - struct rb_root root; - struct list_head list; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_queue_stack { - struct bpf_map map; - raw_spinlock_t lock; - u32 head; - u32 tail; - u32 size; - char elements[0]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum { - BPF_RB_NO_WAKEUP = 1, - BPF_RB_FORCE_WAKEUP = 2, -}; - -enum { - BPF_RB_AVAIL_DATA = 0, - BPF_RB_RING_SIZE = 1, - BPF_RB_CONS_POS = 2, - BPF_RB_PROD_POS = 3, -}; - -enum { - BPF_RINGBUF_BUSY_BIT = 2147483648, - BPF_RINGBUF_DISCARD_BIT = 1073741824, - BPF_RINGBUF_HDR_SZ = 8, -}; - -struct bpf_ringbuf { - wait_queue_head_t waitq; - struct irq_work work; - u64 mask; - struct page **pages; - int nr_pages; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t spinlock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int consumer_pos; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int producer_pos; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - char data[0]; -}; - -struct bpf_ringbuf_map { - struct bpf_map map; - struct bpf_ringbuf *rb; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_ringbuf_hdr { - u32 len; - u32 pg_off; -}; - -typedef u64 (*btf_bpf_ringbuf_reserve)(struct bpf_map *, u64, u64); - -typedef u64 (*btf_bpf_ringbuf_submit)(void *, u64); - -typedef u64 (*btf_bpf_ringbuf_discard)(void *, u64); - -typedef u64 (*btf_bpf_ringbuf_output)(struct bpf_map *, void *, u64, u64); - -typedef u64 (*btf_bpf_ringbuf_query)(struct bpf_map *, u64); - -struct bpf_local_storage_elem { - struct hlist_node map_node; - struct hlist_node snode; - struct bpf_local_storage *local_storage; - struct callback_head rcu; - long: 64; - struct bpf_local_storage_data sdata; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct bpf_local_storage_cache { - spinlock_t idx_lock; - u64 idx_usage_counts[16]; -}; - -enum { - BPF_LOCAL_STORAGE_GET_F_CREATE = 1, - BPF_SK_STORAGE_GET_F_CREATE = 1, -}; - -typedef u64 (*btf_bpf_task_storage_get)(struct bpf_map *, struct task_struct *, void *, u64); - -typedef u64 (*btf_bpf_task_storage_delete)(struct bpf_map *, struct task_struct *); - -struct lsm_blob_sizes { - int lbs_cred; - int lbs_file; - int lbs_inode; - int lbs_superblock; - int lbs_ipc; - int lbs_msg_msg; - int lbs_task; -}; - -struct bpf_storage_blob { - struct bpf_local_storage *storage; -}; - -typedef u64 (*btf_bpf_inode_storage_get)(struct bpf_map *, struct inode *, void *, u64); - -typedef u64 (*btf_bpf_inode_storage_delete)(struct bpf_map *, struct inode *); - -struct btf_enum { - __u32 name_off; - __s32 val; -}; - -struct btf_array { - __u32 type; - __u32 index_type; - __u32 nelems; -}; - -enum { - BTF_VAR_STATIC = 0, - BTF_VAR_GLOBAL_ALLOCATED = 1, - BTF_VAR_GLOBAL_EXTERN = 2, -}; - -struct btf_var { - __u32 linkage; -}; - -struct bpf_flow_keys { - __u16 nhoff; - __u16 thoff; - __u16 addr_proto; - __u8 is_frag; - __u8 is_first_frag; - __u8 is_encap; - __u8 ip_proto; - __be16 n_proto; - __be16 sport; - __be16 dport; - union { - struct { - __be32 ipv4_src; - __be32 ipv4_dst; - }; - struct { - __u32 ipv6_src[4]; - __u32 ipv6_dst[4]; - }; - }; - __u32 flags; - __be32 flow_label; -}; - -struct bpf_sock { - __u32 bound_dev_if; - __u32 family; - __u32 type; - __u32 protocol; - __u32 mark; - __u32 priority; - __u32 src_ip4; - __u32 src_ip6[4]; - __u32 src_port; - __u32 dst_port; - __u32 dst_ip4; - __u32 dst_ip6[4]; - __u32 state; - __s32 rx_queue_mapping; -}; - -struct __sk_buff { - __u32 len; - __u32 pkt_type; - __u32 mark; - __u32 queue_mapping; - __u32 protocol; - __u32 vlan_present; - __u32 vlan_tci; - __u32 vlan_proto; - __u32 priority; - __u32 ingress_ifindex; - __u32 ifindex; - __u32 tc_index; - __u32 cb[5]; - __u32 hash; - __u32 tc_classid; - __u32 data; - __u32 data_end; - __u32 napi_id; - __u32 family; - __u32 remote_ip4; - __u32 local_ip4; - __u32 remote_ip6[4]; - __u32 local_ip6[4]; - __u32 remote_port; - __u32 local_port; - __u32 data_meta; - union { - struct bpf_flow_keys *flow_keys; - }; - __u64 tstamp; - __u32 wire_len; - __u32 gso_segs; - union { - struct bpf_sock *sk; - }; - __u32 gso_size; -}; - -struct xdp_md { - __u32 data; - __u32 data_end; - __u32 data_meta; - __u32 ingress_ifindex; - __u32 rx_queue_index; - __u32 egress_ifindex; -}; - -struct sk_msg_md { - union { - void *data; - }; - union { - void *data_end; - }; - __u32 family; - __u32 remote_ip4; - __u32 local_ip4; - __u32 remote_ip6[4]; - __u32 local_ip6[4]; - __u32 remote_port; - __u32 local_port; - __u32 size; - union { - struct bpf_sock *sk; - }; -}; - -struct sk_reuseport_md { - union { - void *data; - }; - union { - void *data_end; - }; - __u32 len; - __u32 eth_protocol; - __u32 ip_protocol; - __u32 bind_inany; - __u32 hash; - union { - struct bpf_sock *sk; - }; - union { - struct bpf_sock *migrating_sk; - }; -}; - -struct bpf_sock_addr { - __u32 user_family; - __u32 user_ip4; - __u32 user_ip6[4]; - __u32 user_port; - __u32 family; - __u32 type; - __u32 protocol; - __u32 msg_src_ip4; - __u32 msg_src_ip6[4]; - union { - struct bpf_sock *sk; - }; -}; - -struct bpf_sock_ops { - __u32 op; - union { - __u32 args[4]; - __u32 reply; - __u32 replylong[4]; - }; - __u32 family; - __u32 remote_ip4; - __u32 local_ip4; - __u32 remote_ip6[4]; - __u32 local_ip6[4]; - __u32 remote_port; - __u32 local_port; - __u32 is_fullsock; - __u32 snd_cwnd; - __u32 srtt_us; - __u32 bpf_sock_ops_cb_flags; - __u32 state; - __u32 rtt_min; - __u32 snd_ssthresh; - __u32 rcv_nxt; - __u32 snd_nxt; - __u32 snd_una; - __u32 mss_cache; - __u32 ecn_flags; - __u32 rate_delivered; - __u32 rate_interval_us; - __u32 packets_out; - __u32 retrans_out; - __u32 total_retrans; - __u32 segs_in; - __u32 data_segs_in; - __u32 segs_out; - __u32 data_segs_out; - __u32 lost_out; - __u32 sacked_out; - __u32 sk_txhash; - __u64 bytes_received; - __u64 bytes_acked; - union { - struct bpf_sock *sk; - }; - union { - void *skb_data; - }; - union { - void *skb_data_end; - }; - __u32 skb_len; - __u32 skb_tcp_flags; -}; - -struct bpf_cgroup_dev_ctx { - __u32 access_type; - __u32 major; - __u32 minor; -}; - -struct bpf_sysctl { - __u32 write; - __u32 file_pos; -}; - -struct bpf_sockopt { - union { - struct bpf_sock *sk; - }; - union { - void *optval; - }; - union { - void *optval_end; - }; - __s32 level; - __s32 optname; - __s32 optlen; - __s32 retval; -}; - -struct bpf_sk_lookup { - union { - union { - struct bpf_sock *sk; - }; - __u64 cookie; - }; - __u32 family; - __u32 protocol; - __u32 remote_ip4; - __u32 remote_ip6[4]; - __u32 remote_port; - __u32 local_ip4; - __u32 local_ip6[4]; - __u32 local_port; -}; - -struct sk_reuseport_kern { - struct sk_buff *skb; - struct sock *sk; - struct sock *selected_sk; - struct sock *migrating_sk; - void *data_end; - u32 hash; - u32 reuseport_id; - bool bind_inany; -}; - -struct bpf_flow_dissector { - struct bpf_flow_keys *flow_keys; - const struct sk_buff *skb; - const void *data; - const void *data_end; -}; - -struct inet_listen_hashbucket { - spinlock_t lock; - unsigned int count; - union { - struct hlist_head head; - struct hlist_nulls_head nulls_head; - }; -}; - -struct inet_ehash_bucket; - -struct inet_bind_hashbucket; - -struct inet_hashinfo { - struct inet_ehash_bucket *ehash; - spinlock_t *ehash_locks; - unsigned int ehash_mask; - unsigned int ehash_locks_mask; - struct kmem_cache *bind_bucket_cachep; - struct inet_bind_hashbucket *bhash; - unsigned int bhash_size; - unsigned int lhash2_mask; - struct inet_listen_hashbucket *lhash2; - long: 64; - struct inet_listen_hashbucket listening_hash[32]; -}; - -struct ip_ra_chain { - struct ip_ra_chain *next; - struct sock *sk; - union { - void (*destructor)(struct sock *); - struct sock *saved_sk; - }; - struct callback_head rcu; -}; - -struct fib_table { - struct hlist_node tb_hlist; - u32 tb_id; - int tb_num_default; - struct callback_head rcu; - long unsigned int *tb_data; - long unsigned int __data[0]; -}; - -struct inet_peer_base { - struct rb_root rb_root; - seqlock_t lock; - int total; -}; - -struct tcp_fastopen_context { - siphash_key_t key[2]; - int num; - struct callback_head rcu; -}; - -struct xdp_txq_info { - struct net_device *dev; -}; - -struct xdp_buff { - void *data; - void *data_end; - void *data_meta; - void *data_hard_start; - struct xdp_rxq_info *rxq; - struct xdp_txq_info *txq; - u32 frame_sz; -}; - -struct bpf_sock_addr_kern { - struct sock *sk; - struct sockaddr *uaddr; - u64 tmp_reg; - void *t_ctx; -}; - -struct bpf_sock_ops_kern { - struct sock *sk; - union { - u32 args[4]; - u32 reply; - u32 replylong[4]; - }; - struct sk_buff *syn_skb; - struct sk_buff *skb; - void *skb_data_end; - u8 op; - u8 is_fullsock; - u8 remaining_opt_len; - u64 temp; -}; - -struct bpf_sysctl_kern { - struct ctl_table_header *head; - struct ctl_table *table; - void *cur_val; - size_t cur_len; - void *new_val; - size_t new_len; - int new_updated; - int write; - loff_t *ppos; - u64 tmp_reg; -}; - -struct bpf_sockopt_kern { - struct sock *sk; - u8 *optval; - u8 *optval_end; - s32 level; - s32 optname; - s32 optlen; - s32 retval; -}; - -struct bpf_sk_lookup_kern { - u16 family; - u16 protocol; - __be16 sport; - u16 dport; - struct { - __be32 saddr; - __be32 daddr; - } v4; - struct { - const struct in6_addr *saddr; - const struct in6_addr *daddr; - } v6; - struct sock *selected_sk; - bool no_reuseport; -}; - -struct lwtunnel_state { - __u16 type; - __u16 flags; - __u16 headroom; - atomic_t refcnt; - int (*orig_output)(struct net *, struct sock *, struct sk_buff *); - int (*orig_input)(struct sk_buff *); - struct callback_head rcu; - __u8 data[0]; -}; - -struct sock_reuseport { - struct callback_head rcu; - u16 max_socks; - u16 num_socks; - u16 num_closed_socks; - unsigned int synq_overflow_ts; - unsigned int reuseport_id; - unsigned int bind_inany: 1; - unsigned int has_conns: 1; - struct bpf_prog *prog; - struct sock *socks[0]; -}; - -struct sk_psock_progs { - struct bpf_prog *msg_parser; - struct bpf_prog *stream_parser; - struct bpf_prog *stream_verdict; - struct bpf_prog *skb_verdict; -}; - -struct strp_stats { - long long unsigned int msgs; - long long unsigned int bytes; - unsigned int mem_fail; - unsigned int need_more_hdr; - unsigned int msg_too_big; - unsigned int msg_timeouts; - unsigned int bad_hdr_len; -}; - -struct strparser; - -struct strp_callbacks { - int (*parse_msg)(struct strparser *, struct sk_buff *); - void (*rcv_msg)(struct strparser *, struct sk_buff *); - int (*read_sock_done)(struct strparser *, int); - void (*abort_parser)(struct strparser *, int); - void (*lock)(struct strparser *); - void (*unlock)(struct strparser *); -}; - -struct strparser { - struct sock *sk; - u32 stopped: 1; - u32 paused: 1; - u32 aborted: 1; - u32 interrupted: 1; - u32 unrecov_intr: 1; - struct sk_buff **skb_nextp; - struct sk_buff *skb_head; - unsigned int need_bytes; - struct delayed_work msg_timer_work; - struct work_struct work; - struct strp_stats stats; - struct strp_callbacks cb; -}; - -struct sk_psock_work_state { - struct sk_buff *skb; - u32 len; - u32 off; -}; - -struct sk_msg; - -struct sk_psock { - struct sock *sk; - struct sock *sk_redir; - u32 apply_bytes; - u32 cork_bytes; - u32 eval; - struct sk_msg *cork; - struct sk_psock_progs progs; - struct strparser strp; - struct sk_buff_head ingress_skb; - struct list_head ingress_msg; - spinlock_t ingress_lock; - long unsigned int state; - struct list_head link; - spinlock_t link_lock; - refcount_t refcnt; - void (*saved_unhash)(struct sock *); - void (*saved_close)(struct sock *, long int); - void (*saved_write_space)(struct sock *); - void (*saved_data_ready)(struct sock *); - int (*psock_update_sk_prot)(struct sock *, struct sk_psock *, bool); - struct proto *sk_proto; - struct mutex work_mutex; - struct sk_psock_work_state work_state; - struct work_struct work; - struct rcu_work rwork; -}; - -struct inet_ehash_bucket { - struct hlist_nulls_head chain; -}; - -struct inet_bind_hashbucket { - spinlock_t lock; - struct hlist_head chain; -}; - -struct ack_sample { - u32 pkts_acked; - s32 rtt_us; - u32 in_flight; -}; - -struct rate_sample { - u64 prior_mstamp; - u32 prior_delivered; - s32 delivered; - long int interval_us; - u32 snd_interval_us; - u32 rcv_interval_us; - long int rtt_us; - int losses; - u32 acked_sacked; - u32 prior_in_flight; - bool is_app_limited; - bool is_retrans; - bool is_ack_delayed; -}; - -struct sk_msg_sg { - u32 start; - u32 curr; - u32 end; - u32 size; - u32 copybreak; - long unsigned int copy; - struct scatterlist data[19]; -}; - -struct sk_msg { - struct sk_msg_sg sg; - void *data; - void *data_end; - u32 apply_bytes; - u32 cork_bytes; - u32 flags; - struct sk_buff *skb; - struct sock *sk_redir; - struct sock *sk; - struct list_head list; -}; - -enum verifier_phase { - CHECK_META = 0, - CHECK_TYPE = 1, -}; - -struct resolve_vertex { - const struct btf_type *t; - u32 type_id; - u16 next_member; -}; - -enum visit_state { - NOT_VISITED = 0, - VISITED = 1, - RESOLVED = 2, -}; - -enum resolve_mode { - RESOLVE_TBD = 0, - RESOLVE_PTR = 1, - RESOLVE_STRUCT_OR_ARRAY = 2, -}; - -struct btf_sec_info { - u32 off; - u32 len; -}; - -struct btf_verifier_env { - struct btf *btf; - u8 *visit_states; - struct resolve_vertex stack[32]; - struct bpf_verifier_log log; - u32 log_type_id; - u32 top_stack; - enum verifier_phase phase; - enum resolve_mode resolve_mode; -}; - -struct btf_show { - u64 flags; - void *target; - void (*showfn)(struct btf_show *, const char *, struct __va_list_tag *); - const struct btf *btf; - struct { - u8 depth; - u8 depth_to_show; - u8 depth_check; - u8 array_member: 1; - u8 array_terminated: 1; - u16 array_encoding; - u32 type_id; - int status; - const struct btf_type *type; - const struct btf_member *member; - char name[80]; - } state; - struct { - u32 size; - void *head; - void *data; - u8 safe[32]; - } obj; -}; - -struct btf_kind_operations { - s32 (*check_meta)(struct btf_verifier_env *, const struct btf_type *, u32); - int (*resolve)(struct btf_verifier_env *, const struct resolve_vertex *); - int (*check_member)(struct btf_verifier_env *, const struct btf_type *, const struct btf_member *, const struct btf_type *); - int (*check_kflag_member)(struct btf_verifier_env *, const struct btf_type *, const struct btf_member *, const struct btf_type *); - void (*log_details)(struct btf_verifier_env *, const struct btf_type *); - void (*show)(const struct btf *, const struct btf_type *, u32, void *, u8, struct btf_show *); -}; - -struct bpf_ctx_convert { - struct __sk_buff BPF_PROG_TYPE_SOCKET_FILTER_prog; - struct sk_buff BPF_PROG_TYPE_SOCKET_FILTER_kern; - struct __sk_buff BPF_PROG_TYPE_SCHED_CLS_prog; - struct sk_buff BPF_PROG_TYPE_SCHED_CLS_kern; - struct __sk_buff BPF_PROG_TYPE_SCHED_ACT_prog; - struct sk_buff BPF_PROG_TYPE_SCHED_ACT_kern; - struct xdp_md BPF_PROG_TYPE_XDP_prog; - struct xdp_buff BPF_PROG_TYPE_XDP_kern; - struct __sk_buff BPF_PROG_TYPE_CGROUP_SKB_prog; - struct sk_buff BPF_PROG_TYPE_CGROUP_SKB_kern; - struct bpf_sock BPF_PROG_TYPE_CGROUP_SOCK_prog; - struct sock BPF_PROG_TYPE_CGROUP_SOCK_kern; - struct bpf_sock_addr BPF_PROG_TYPE_CGROUP_SOCK_ADDR_prog; - struct bpf_sock_addr_kern BPF_PROG_TYPE_CGROUP_SOCK_ADDR_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_IN_prog; - struct sk_buff BPF_PROG_TYPE_LWT_IN_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_OUT_prog; - struct sk_buff BPF_PROG_TYPE_LWT_OUT_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_XMIT_prog; - struct sk_buff BPF_PROG_TYPE_LWT_XMIT_kern; - struct __sk_buff BPF_PROG_TYPE_LWT_SEG6LOCAL_prog; - struct sk_buff BPF_PROG_TYPE_LWT_SEG6LOCAL_kern; - struct bpf_sock_ops BPF_PROG_TYPE_SOCK_OPS_prog; - struct bpf_sock_ops_kern BPF_PROG_TYPE_SOCK_OPS_kern; - struct __sk_buff BPF_PROG_TYPE_SK_SKB_prog; - struct sk_buff BPF_PROG_TYPE_SK_SKB_kern; - struct sk_msg_md BPF_PROG_TYPE_SK_MSG_prog; - struct sk_msg BPF_PROG_TYPE_SK_MSG_kern; - struct __sk_buff BPF_PROG_TYPE_FLOW_DISSECTOR_prog; - struct bpf_flow_dissector BPF_PROG_TYPE_FLOW_DISSECTOR_kern; - bpf_user_pt_regs_t BPF_PROG_TYPE_KPROBE_prog; - struct pt_regs BPF_PROG_TYPE_KPROBE_kern; - __u64 BPF_PROG_TYPE_TRACEPOINT_prog; - u64 BPF_PROG_TYPE_TRACEPOINT_kern; - struct bpf_perf_event_data BPF_PROG_TYPE_PERF_EVENT_prog; - struct bpf_perf_event_data_kern BPF_PROG_TYPE_PERF_EVENT_kern; - struct bpf_raw_tracepoint_args BPF_PROG_TYPE_RAW_TRACEPOINT_prog; - u64 BPF_PROG_TYPE_RAW_TRACEPOINT_kern; - struct bpf_raw_tracepoint_args BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE_prog; - u64 BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE_kern; - void *BPF_PROG_TYPE_TRACING_prog; - void *BPF_PROG_TYPE_TRACING_kern; - struct bpf_cgroup_dev_ctx BPF_PROG_TYPE_CGROUP_DEVICE_prog; - struct bpf_cgroup_dev_ctx BPF_PROG_TYPE_CGROUP_DEVICE_kern; - struct bpf_sysctl BPF_PROG_TYPE_CGROUP_SYSCTL_prog; - struct bpf_sysctl_kern BPF_PROG_TYPE_CGROUP_SYSCTL_kern; - struct bpf_sockopt BPF_PROG_TYPE_CGROUP_SOCKOPT_prog; - struct bpf_sockopt_kern BPF_PROG_TYPE_CGROUP_SOCKOPT_kern; - __u32 BPF_PROG_TYPE_LIRC_MODE2_prog; - u32 BPF_PROG_TYPE_LIRC_MODE2_kern; - struct sk_reuseport_md BPF_PROG_TYPE_SK_REUSEPORT_prog; - struct sk_reuseport_kern BPF_PROG_TYPE_SK_REUSEPORT_kern; - struct bpf_sk_lookup BPF_PROG_TYPE_SK_LOOKUP_prog; - struct bpf_sk_lookup_kern BPF_PROG_TYPE_SK_LOOKUP_kern; - void *BPF_PROG_TYPE_STRUCT_OPS_prog; - void *BPF_PROG_TYPE_STRUCT_OPS_kern; - void *BPF_PROG_TYPE_EXT_prog; - void *BPF_PROG_TYPE_EXT_kern; - void *BPF_PROG_TYPE_LSM_prog; - void *BPF_PROG_TYPE_LSM_kern; - void *BPF_PROG_TYPE_SYSCALL_prog; - void *BPF_PROG_TYPE_SYSCALL_kern; -}; - -enum { - __ctx_convertBPF_PROG_TYPE_SOCKET_FILTER = 0, - __ctx_convertBPF_PROG_TYPE_SCHED_CLS = 1, - __ctx_convertBPF_PROG_TYPE_SCHED_ACT = 2, - __ctx_convertBPF_PROG_TYPE_XDP = 3, - __ctx_convertBPF_PROG_TYPE_CGROUP_SKB = 4, - __ctx_convertBPF_PROG_TYPE_CGROUP_SOCK = 5, - __ctx_convertBPF_PROG_TYPE_CGROUP_SOCK_ADDR = 6, - __ctx_convertBPF_PROG_TYPE_LWT_IN = 7, - __ctx_convertBPF_PROG_TYPE_LWT_OUT = 8, - __ctx_convertBPF_PROG_TYPE_LWT_XMIT = 9, - __ctx_convertBPF_PROG_TYPE_LWT_SEG6LOCAL = 10, - __ctx_convertBPF_PROG_TYPE_SOCK_OPS = 11, - __ctx_convertBPF_PROG_TYPE_SK_SKB = 12, - __ctx_convertBPF_PROG_TYPE_SK_MSG = 13, - __ctx_convertBPF_PROG_TYPE_FLOW_DISSECTOR = 14, - __ctx_convertBPF_PROG_TYPE_KPROBE = 15, - __ctx_convertBPF_PROG_TYPE_TRACEPOINT = 16, - __ctx_convertBPF_PROG_TYPE_PERF_EVENT = 17, - __ctx_convertBPF_PROG_TYPE_RAW_TRACEPOINT = 18, - __ctx_convertBPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 19, - __ctx_convertBPF_PROG_TYPE_TRACING = 20, - __ctx_convertBPF_PROG_TYPE_CGROUP_DEVICE = 21, - __ctx_convertBPF_PROG_TYPE_CGROUP_SYSCTL = 22, - __ctx_convertBPF_PROG_TYPE_CGROUP_SOCKOPT = 23, - __ctx_convertBPF_PROG_TYPE_LIRC_MODE2 = 24, - __ctx_convertBPF_PROG_TYPE_SK_REUSEPORT = 25, - __ctx_convertBPF_PROG_TYPE_SK_LOOKUP = 26, - __ctx_convertBPF_PROG_TYPE_STRUCT_OPS = 27, - __ctx_convertBPF_PROG_TYPE_EXT = 28, - __ctx_convertBPF_PROG_TYPE_LSM = 29, - __ctx_convertBPF_PROG_TYPE_SYSCALL = 30, - __ctx_convert_unused = 31, -}; - -enum bpf_struct_walk_result { - WALK_SCALAR = 0, - WALK_PTR = 1, - WALK_STRUCT = 2, -}; - -struct btf_show_snprintf { - struct btf_show show; - int len_left; - int len; -}; - -struct btf_module { - struct list_head list; - struct module *module; - struct btf *btf; - struct bin_attribute *sysfs_attr; -}; - -typedef u64 (*btf_bpf_btf_find_by_name_kind)(char *, int, u32, int); - -struct bpf_dispatcher_prog { - struct bpf_prog *prog; - refcount_t users; -}; - -struct bpf_dispatcher { - struct mutex mutex; - void *func; - struct bpf_dispatcher_prog progs[48]; - int num_progs; - void *image; - u32 image_off; - struct bpf_ksym ksym; -}; - -enum { - BPF_F_BROADCAST = 8, - BPF_F_EXCLUDE_INGRESS = 16, -}; - -struct bpf_devmap_val { - __u32 ifindex; - union { - int fd; - __u32 id; - } bpf_prog; -}; - -enum net_device_flags { - IFF_UP = 1, - IFF_BROADCAST = 2, - IFF_DEBUG = 4, - IFF_LOOPBACK = 8, - IFF_POINTOPOINT = 16, - IFF_NOTRAILERS = 32, - IFF_RUNNING = 64, - IFF_NOARP = 128, - IFF_PROMISC = 256, - IFF_ALLMULTI = 512, - IFF_MASTER = 1024, - IFF_SLAVE = 2048, - IFF_MULTICAST = 4096, - IFF_PORTSEL = 8192, - IFF_AUTOMEDIA = 16384, - IFF_DYNAMIC = 32768, - IFF_LOWER_UP = 65536, - IFF_DORMANT = 131072, - IFF_ECHO = 262144, -}; - -struct xdp_dev_bulk_queue { - struct xdp_frame *q[16]; - struct list_head flush_node; - struct net_device *dev; - struct net_device *dev_rx; - struct bpf_prog *xdp_prog; - unsigned int count; -}; - -enum netdev_cmd { - NETDEV_UP = 1, - NETDEV_DOWN = 2, - NETDEV_REBOOT = 3, - NETDEV_CHANGE = 4, - NETDEV_REGISTER = 5, - NETDEV_UNREGISTER = 6, - NETDEV_CHANGEMTU = 7, - NETDEV_CHANGEADDR = 8, - NETDEV_PRE_CHANGEADDR = 9, - NETDEV_GOING_DOWN = 10, - NETDEV_CHANGENAME = 11, - NETDEV_FEAT_CHANGE = 12, - NETDEV_BONDING_FAILOVER = 13, - NETDEV_PRE_UP = 14, - NETDEV_PRE_TYPE_CHANGE = 15, - NETDEV_POST_TYPE_CHANGE = 16, - NETDEV_POST_INIT = 17, - NETDEV_RELEASE = 18, - NETDEV_NOTIFY_PEERS = 19, - NETDEV_JOIN = 20, - NETDEV_CHANGEUPPER = 21, - NETDEV_RESEND_IGMP = 22, - NETDEV_PRECHANGEMTU = 23, - NETDEV_CHANGEINFODATA = 24, - NETDEV_BONDING_INFO = 25, - NETDEV_PRECHANGEUPPER = 26, - NETDEV_CHANGELOWERSTATE = 27, - NETDEV_UDP_TUNNEL_PUSH_INFO = 28, - NETDEV_UDP_TUNNEL_DROP_INFO = 29, - NETDEV_CHANGE_TX_QUEUE_LEN = 30, - NETDEV_CVLAN_FILTER_PUSH_INFO = 31, - NETDEV_CVLAN_FILTER_DROP_INFO = 32, - NETDEV_SVLAN_FILTER_PUSH_INFO = 33, - NETDEV_SVLAN_FILTER_DROP_INFO = 34, -}; - -struct netdev_notifier_info { - struct net_device *dev; - struct netlink_ext_ack *extack; -}; - -struct bpf_nh_params { - u32 nh_family; - union { - u32 ipv4_nh; - struct in6_addr ipv6_nh; - }; -}; - -struct bpf_redirect_info { - u32 flags; - u32 tgt_index; - void *tgt_value; - struct bpf_map *map; - u32 map_id; - enum bpf_map_type map_type; - u32 kern_flags; - struct bpf_nh_params nh; -}; - -struct bpf_dtab; - -struct bpf_dtab_netdev { - struct net_device *dev; - struct hlist_node index_hlist; - struct bpf_dtab *dtab; - struct bpf_prog *xdp_prog; - struct callback_head rcu; - unsigned int idx; - struct bpf_devmap_val val; -}; - -struct bpf_dtab { - struct bpf_map map; - struct bpf_dtab_netdev **netdev_map; - struct list_head list; - struct hlist_head *dev_index_head; - spinlock_t index_lock; - unsigned int items; - u32 n_buckets; - long: 32; - long: 64; - long: 64; -}; - -struct bpf_cpumap_val { - __u32 qsize; - union { - int fd; - __u32 id; - } bpf_prog; -}; - -struct bpf_cpu_map_entry; - -struct xdp_bulk_queue { - void *q[8]; - struct list_head flush_node; - struct bpf_cpu_map_entry *obj; - unsigned int count; -}; - -struct bpf_cpu_map; - -struct bpf_cpu_map_entry { - u32 cpu; - int map_id; - struct xdp_bulk_queue *bulkq; - struct bpf_cpu_map *cmap; - struct ptr_ring *queue; - struct task_struct *kthread; - struct bpf_cpumap_val value; - struct bpf_prog *prog; - atomic_t refcnt; - struct callback_head rcu; - struct work_struct kthread_stop_wq; -}; - -struct bpf_cpu_map { - struct bpf_map map; - struct bpf_cpu_map_entry **cpu_map; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct rhlist_head { - struct rhash_head rhead; - struct rhlist_head *next; -}; - -struct bpf_prog_offload_ops { - int (*insn_hook)(struct bpf_verifier_env *, int, int); - int (*finalize)(struct bpf_verifier_env *); - int (*replace_insn)(struct bpf_verifier_env *, u32, struct bpf_insn *); - int (*remove_insns)(struct bpf_verifier_env *, u32, u32); - int (*prepare)(struct bpf_prog *); - int (*translate)(struct bpf_prog *); - void (*destroy)(struct bpf_prog *); -}; - -struct bpf_offload_dev { - const struct bpf_prog_offload_ops *ops; - struct list_head netdevs; - void *priv; -}; - -typedef struct ns_common *ns_get_path_helper_t(void *); - -struct bpf_offload_netdev { - struct rhash_head l; - struct net_device *netdev; - struct bpf_offload_dev *offdev; - struct list_head progs; - struct list_head maps; - struct list_head offdev_netdevs; -}; - -struct ns_get_path_bpf_prog_args { - struct bpf_prog *prog; - struct bpf_prog_info *info; -}; - -struct ns_get_path_bpf_map_args { - struct bpf_offloaded_map *offmap; - struct bpf_map_info *info; -}; - -struct bpf_netns_link { - struct bpf_link link; - enum bpf_attach_type type; - enum netns_bpf_attach_type netns_type; - struct net *net; - struct list_head node; -}; - -enum bpf_stack_build_id_status { - BPF_STACK_BUILD_ID_EMPTY = 0, - BPF_STACK_BUILD_ID_VALID = 1, - BPF_STACK_BUILD_ID_IP = 2, -}; - -struct bpf_stack_build_id { - __s32 status; - unsigned char build_id[20]; - union { - __u64 offset; - __u64 ip; - }; -}; - -enum { - BPF_F_SKIP_FIELD_MASK = 255, - BPF_F_USER_STACK = 256, - BPF_F_FAST_STACK_CMP = 512, - BPF_F_REUSE_STACKID = 1024, - BPF_F_USER_BUILD_ID = 2048, -}; - -enum perf_callchain_context { - PERF_CONTEXT_HV = 4294967264, - PERF_CONTEXT_KERNEL = 4294967168, - PERF_CONTEXT_USER = 4294966784, - PERF_CONTEXT_GUEST = 4294965248, - PERF_CONTEXT_GUEST_KERNEL = 4294965120, - PERF_CONTEXT_GUEST_USER = 4294964736, - PERF_CONTEXT_MAX = 4294963201, -}; - -struct stack_map_bucket { - struct pcpu_freelist_node fnode; - u32 hash; - u32 nr; - u64 data[0]; -}; - -struct bpf_stack_map { - struct bpf_map map; - void *elems; - struct pcpu_freelist freelist; - u32 n_buckets; - struct stack_map_bucket *buckets[0]; - long: 64; - long: 64; - long: 64; -}; - -struct stack_map_irq_work { - struct irq_work irq_work; - struct mm_struct *mm; -}; - -typedef u64 (*btf_bpf_get_stackid)(struct pt_regs *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stackid_pe)(struct bpf_perf_event_data_kern *, struct bpf_map *, u64); - -typedef u64 (*btf_bpf_get_stack)(struct pt_regs *, void *, u32, u64); - -typedef u64 (*btf_bpf_get_task_stack)(struct task_struct *, void *, u32, u64); - -typedef u64 (*btf_bpf_get_stack_pe)(struct bpf_perf_event_data_kern *, void *, u32, u64); - -enum { - BPF_F_SYSCTL_BASE_NAME = 1, -}; - -struct bpf_prog_list { - struct list_head node; - struct bpf_prog *prog; - struct bpf_cgroup_link *link; - struct bpf_cgroup_storage *storage[2]; -}; - -struct qdisc_skb_cb { - struct { - unsigned int pkt_len; - u16 slave_dev_queue_mapping; - u16 tc_classid; - }; - unsigned char data[20]; - u16 mru; - bool post_ct; -}; - -struct bpf_skb_data_end { - struct qdisc_skb_cb qdisc_cb; - void *data_meta; - void *data_end; -}; - -struct bpf_sockopt_buf { - u8 data[32]; -}; - -enum { - TCPF_ESTABLISHED = 2, - TCPF_SYN_SENT = 4, - TCPF_SYN_RECV = 8, - TCPF_FIN_WAIT1 = 16, - TCPF_FIN_WAIT2 = 32, - TCPF_TIME_WAIT = 64, - TCPF_CLOSE = 128, - TCPF_CLOSE_WAIT = 256, - TCPF_LAST_ACK = 512, - TCPF_LISTEN = 1024, - TCPF_CLOSING = 2048, - TCPF_NEW_SYN_RECV = 4096, -}; - -typedef u64 (*btf_bpf_sysctl_get_name)(struct bpf_sysctl_kern *, char *, size_t, u64); - -typedef u64 (*btf_bpf_sysctl_get_current_value)(struct bpf_sysctl_kern *, char *, size_t); - -typedef u64 (*btf_bpf_sysctl_get_new_value)(struct bpf_sysctl_kern *, char *, size_t); - -typedef u64 (*btf_bpf_sysctl_set_new_value)(struct bpf_sysctl_kern *, const char *, size_t); - -enum sock_type { - SOCK_STREAM = 1, - SOCK_DGRAM = 2, - SOCK_RAW = 3, - SOCK_RDM = 4, - SOCK_SEQPACKET = 5, - SOCK_DCCP = 6, - SOCK_PACKET = 10, -}; - -enum { - IPPROTO_IP = 0, - IPPROTO_ICMP = 1, - IPPROTO_IGMP = 2, - IPPROTO_IPIP = 4, - IPPROTO_TCP = 6, - IPPROTO_EGP = 8, - IPPROTO_PUP = 12, - IPPROTO_UDP = 17, - IPPROTO_IDP = 22, - IPPROTO_TP = 29, - IPPROTO_DCCP = 33, - IPPROTO_IPV6 = 41, - IPPROTO_RSVP = 46, - IPPROTO_GRE = 47, - IPPROTO_ESP = 50, - IPPROTO_AH = 51, - IPPROTO_MTP = 92, - IPPROTO_BEETPH = 94, - IPPROTO_ENCAP = 98, - IPPROTO_PIM = 103, - IPPROTO_COMP = 108, - IPPROTO_SCTP = 132, - IPPROTO_UDPLITE = 136, - IPPROTO_MPLS = 137, - IPPROTO_ETHERNET = 143, - IPPROTO_RAW = 255, - IPPROTO_MPTCP = 262, - IPPROTO_MAX = 263, -}; - -enum sock_flags { - SOCK_DEAD = 0, - SOCK_DONE = 1, - SOCK_URGINLINE = 2, - SOCK_KEEPOPEN = 3, - SOCK_LINGER = 4, - SOCK_DESTROY = 5, - SOCK_BROADCAST = 6, - SOCK_TIMESTAMP = 7, - SOCK_ZAPPED = 8, - SOCK_USE_WRITE_QUEUE = 9, - SOCK_DBG = 10, - SOCK_RCVTSTAMP = 11, - SOCK_RCVTSTAMPNS = 12, - SOCK_LOCALROUTE = 13, - SOCK_MEMALLOC = 14, - SOCK_TIMESTAMPING_RX_SOFTWARE = 15, - SOCK_FASYNC = 16, - SOCK_RXQ_OVFL = 17, - SOCK_ZEROCOPY = 18, - SOCK_WIFI_STATUS = 19, - SOCK_NOFCS = 20, - SOCK_FILTER_LOCKED = 21, - SOCK_SELECT_ERR_QUEUE = 22, - SOCK_RCU_FREE = 23, - SOCK_TXTIME = 24, - SOCK_XDP = 25, - SOCK_TSTAMP_NEW = 26, -}; - -struct reuseport_array { - struct bpf_map map; - struct sock *ptrs[0]; -}; - -enum bpf_struct_ops_state { - BPF_STRUCT_OPS_STATE_INIT = 0, - BPF_STRUCT_OPS_STATE_INUSE = 1, - BPF_STRUCT_OPS_STATE_TOBEFREE = 2, -}; - -struct bpf_struct_ops_value { - refcount_t refcnt; - enum bpf_struct_ops_state state; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - char data[0]; -}; - -struct bpf_struct_ops_map { - struct bpf_map map; - const struct bpf_struct_ops *st_ops; - struct mutex lock; - struct bpf_prog **progs; - void *image; - struct bpf_struct_ops_value *uvalue; - struct bpf_struct_ops_value kvalue; -}; - -struct bpf_struct_ops_tcp_congestion_ops { - refcount_t refcnt; - enum bpf_struct_ops_state state; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct tcp_congestion_ops data; -}; - -struct sembuf { - short unsigned int sem_num; - short int sem_op; - short int sem_flg; -}; - -enum key_need_perm { - KEY_NEED_UNSPECIFIED = 0, - KEY_NEED_VIEW = 1, - KEY_NEED_READ = 2, - KEY_NEED_WRITE = 3, - KEY_NEED_SEARCH = 4, - KEY_NEED_LINK = 5, - KEY_NEED_SETATTR = 6, - KEY_NEED_UNLINK = 7, - KEY_SYSADMIN_OVERRIDE = 8, - KEY_AUTHTOKEN_OVERRIDE = 9, - KEY_DEFER_PERM_CHECK = 10, -}; - -struct __key_reference_with_attributes; - -typedef struct __key_reference_with_attributes *key_ref_t; - -struct xfrm_sec_ctx { - __u8 ctx_doi; - __u8 ctx_alg; - __u16 ctx_len; - __u32 ctx_sid; - char ctx_str[0]; -}; - -struct xfrm_user_sec_ctx { - __u16 len; - __u16 exttype; - __u8 ctx_alg; - __u8 ctx_doi; - __u16 ctx_len; -}; - -enum { - BPF_F_BPRM_SECUREEXEC = 1, -}; - -typedef u64 (*btf_bpf_bprm_opts_set)(struct linux_binprm *, u64); - -typedef u64 (*btf_bpf_ima_inode_hash)(struct inode *, void *, u32); - -struct static_call_tramp_key { - s32 tramp; - s32 key; -}; - -enum perf_event_read_format { - PERF_FORMAT_TOTAL_TIME_ENABLED = 1, - PERF_FORMAT_TOTAL_TIME_RUNNING = 2, - PERF_FORMAT_ID = 4, - PERF_FORMAT_GROUP = 8, - PERF_FORMAT_MAX = 16, -}; - -enum perf_event_ioc_flags { - PERF_IOC_FLAG_GROUP = 1, -}; - -struct perf_ns_link_info { - __u64 dev; - __u64 ino; -}; - -enum { - NET_NS_INDEX = 0, - UTS_NS_INDEX = 1, - IPC_NS_INDEX = 2, - PID_NS_INDEX = 3, - USER_NS_INDEX = 4, - MNT_NS_INDEX = 5, - CGROUP_NS_INDEX = 6, - NR_NAMESPACES = 7, -}; - -enum perf_event_type { - PERF_RECORD_MMAP = 1, - PERF_RECORD_LOST = 2, - PERF_RECORD_COMM = 3, - PERF_RECORD_EXIT = 4, - PERF_RECORD_THROTTLE = 5, - PERF_RECORD_UNTHROTTLE = 6, - PERF_RECORD_FORK = 7, - PERF_RECORD_READ = 8, - PERF_RECORD_SAMPLE = 9, - PERF_RECORD_MMAP2 = 10, - PERF_RECORD_AUX = 11, - PERF_RECORD_ITRACE_START = 12, - PERF_RECORD_LOST_SAMPLES = 13, - PERF_RECORD_SWITCH = 14, - PERF_RECORD_SWITCH_CPU_WIDE = 15, - PERF_RECORD_NAMESPACES = 16, - PERF_RECORD_KSYMBOL = 17, - PERF_RECORD_BPF_EVENT = 18, - PERF_RECORD_CGROUP = 19, - PERF_RECORD_TEXT_POKE = 20, - PERF_RECORD_MAX = 21, -}; - -struct swevent_hlist { - struct hlist_head heads[256]; - struct callback_head callback_head; -}; - -struct pmu_event_list { - raw_spinlock_t lock; - struct list_head list; -}; - -struct perf_buffer { - refcount_t refcount; - struct callback_head callback_head; - int nr_pages; - int overwrite; - int paused; - atomic_t poll; - local_t head; - unsigned int nest; - local_t events; - local_t wakeup; - local_t lost; - long int watermark; - long int aux_watermark; - spinlock_t event_lock; - struct list_head event_list; - atomic_t mmap_count; - long unsigned int mmap_locked; - struct user_struct *mmap_user; - long int aux_head; - unsigned int aux_nest; - long int aux_wakeup; - long unsigned int aux_pgoff; - int aux_nr_pages; - int aux_overwrite; - atomic_t aux_mmap_count; - long unsigned int aux_mmap_locked; - void (*free_aux)(void *); - refcount_t aux_refcount; - int aux_in_sampling; - void **aux_pages; - void *aux_priv; - struct perf_event_mmap_page *user_page; - void *data_pages[0]; -}; - -struct match_token { - int token; - const char *pattern; -}; - -enum { - MAX_OPT_ARGS = 3, -}; - -struct min_heap { - void *data; - int nr; - int size; -}; - -struct min_heap_callbacks { - int elem_size; - bool (*less)(const void *, const void *); - void (*swp)(void *, void *); -}; - -typedef int (*remote_function_f)(void *); - -struct remote_function_call { - struct task_struct *p; - remote_function_f func; - void *info; - int ret; -}; - -typedef void (*event_f)(struct perf_event *, struct perf_cpu_context *, struct perf_event_context *, void *); - -struct event_function_struct { - struct perf_event *event; - event_f func; - void *data; -}; - -enum event_type_t { - EVENT_FLEXIBLE = 1, - EVENT_PINNED = 2, - EVENT_TIME = 4, - EVENT_CPU = 8, - EVENT_ALL = 3, -}; - -struct __group_key { - int cpu; - struct cgroup *cgroup; -}; - -struct stop_event_data { - struct perf_event *event; - unsigned int restart; -}; - -struct perf_read_data { - struct perf_event *event; - bool group; - int ret; -}; - -struct perf_read_event { - struct perf_event_header header; - u32 pid; - u32 tid; -}; - -typedef void perf_iterate_f(struct perf_event *, void *); - -struct remote_output { - struct perf_buffer *rb; - int err; -}; - -struct perf_task_event { - struct task_struct *task; - struct perf_event_context *task_ctx; - struct { - struct perf_event_header header; - u32 pid; - u32 ppid; - u32 tid; - u32 ptid; - u64 time; - } event_id; -}; - -struct perf_comm_event { - struct task_struct *task; - char *comm; - int comm_size; - struct { - struct perf_event_header header; - u32 pid; - u32 tid; - } event_id; -}; - -struct perf_namespaces_event { - struct task_struct *task; - struct { - struct perf_event_header header; - u32 pid; - u32 tid; - u64 nr_namespaces; - struct perf_ns_link_info link_info[7]; - } event_id; -}; - -struct perf_cgroup_event { - char *path; - int path_size; - struct { - struct perf_event_header header; - u64 id; - char path[0]; - } event_id; -}; - -struct perf_mmap_event { - struct vm_area_struct *vma; - const char *file_name; - int file_size; - int maj; - int min; - u64 ino; - u64 ino_generation; - u32 prot; - u32 flags; - u8 build_id[20]; - u32 build_id_size; - struct { - struct perf_event_header header; - u32 pid; - u32 tid; - u64 start; - u64 len; - u64 pgoff; - } event_id; -}; - -struct perf_switch_event { - struct task_struct *task; - struct task_struct *next_prev; - struct { - struct perf_event_header header; - u32 next_prev_pid; - u32 next_prev_tid; - } event_id; -}; - -struct perf_ksymbol_event { - const char *name; - int name_len; - struct { - struct perf_event_header header; - u64 addr; - u32 len; - u16 ksym_type; - u16 flags; - } event_id; -}; - -struct perf_bpf_event { - struct bpf_prog *prog; - struct { - struct perf_event_header header; - u16 type; - u16 flags; - u32 id; - u8 tag[8]; - } event_id; -}; - -struct perf_text_poke_event { - const void *old_bytes; - const void *new_bytes; - size_t pad; - u16 old_len; - u16 new_len; - struct { - struct perf_event_header header; - u64 addr; - } event_id; -}; - -struct swevent_htable { - struct swevent_hlist *swevent_hlist; - struct mutex hlist_mutex; - int hlist_refcount; - int recursion[4]; -}; - -enum perf_probe_config { - PERF_PROBE_CONFIG_IS_RETPROBE = 1, - PERF_UPROBE_REF_CTR_OFFSET_BITS = 32, - PERF_UPROBE_REF_CTR_OFFSET_SHIFT = 32, -}; - -enum { - IF_ACT_NONE = 4294967295, - IF_ACT_FILTER = 0, - IF_ACT_START = 1, - IF_ACT_STOP = 2, - IF_SRC_FILE = 3, - IF_SRC_KERNEL = 4, - IF_SRC_FILEADDR = 5, - IF_SRC_KERNELADDR = 6, -}; - -enum { - IF_STATE_ACTION = 0, - IF_STATE_SOURCE = 1, - IF_STATE_END = 2, -}; - -struct perf_aux_event { - struct perf_event_header header; - u32 pid; - u32 tid; -}; - -struct perf_aux_event___2 { - struct perf_event_header header; - u64 offset; - u64 size; - u64 flags; -}; - -struct callchain_cpus_entries { - struct callback_head callback_head; - struct perf_callchain_entry *cpu_entries[0]; -}; - -enum bp_type_idx { - TYPE_INST = 0, - TYPE_DATA = 0, - TYPE_MAX = 1, -}; - -struct bp_cpuinfo { - unsigned int cpu_pinned; - unsigned int *tsk_pinned; - unsigned int flexible; -}; - -struct bp_busy_slots { - unsigned int pinned; - unsigned int flexible; -}; - -typedef u8 uprobe_opcode_t; - -struct uprobe { - struct rb_node rb_node; - refcount_t ref; - struct rw_semaphore register_rwsem; - struct rw_semaphore consumer_rwsem; - struct list_head pending_list; - struct uprobe_consumer *consumers; - struct inode *inode; - loff_t offset; - loff_t ref_ctr_offset; - long unsigned int flags; - struct arch_uprobe arch; -}; - -struct xol_area { - wait_queue_head_t wq; - atomic_t slot_count; - long unsigned int *bitmap; - struct vm_special_mapping xol_mapping; - struct page *pages[2]; - long unsigned int vaddr; -}; - -struct compact_control; - -struct capture_control { - struct compact_control *cc; - struct page *page; -}; - -typedef int filler_t(void *, struct page *); - -struct page_vma_mapped_walk { - struct page *page; - struct vm_area_struct *vma; - long unsigned int address; - pmd_t *pmd; - pte_t *pte; - spinlock_t *ptl; - unsigned int flags; -}; - -struct compact_control { - struct list_head freepages; - struct list_head migratepages; - unsigned int nr_freepages; - unsigned int nr_migratepages; - long unsigned int free_pfn; - long unsigned int migrate_pfn; - long unsigned int fast_start_pfn; - struct zone *zone; - long unsigned int total_migrate_scanned; - long unsigned int total_free_scanned; - short unsigned int fast_search_fail; - short int search_order; - const gfp_t gfp_mask; - int order; - int migratetype; - const unsigned int alloc_flags; - const int highest_zoneidx; - enum migrate_mode mode; - bool ignore_skip_hint; - bool no_set_skip_hint; - bool ignore_block_suitable; - bool direct_compaction; - bool proactive_compaction; - bool whole_zone; - bool contended; - bool rescan; - bool alloc_contig; -}; - -struct delayed_uprobe { - struct list_head list; - struct uprobe *uprobe; - struct mm_struct *mm; -}; - -struct __uprobe_key { - struct inode *inode; - loff_t offset; -}; - -struct map_info { - struct map_info *next; - struct mm_struct *mm; - long unsigned int vaddr; -}; - -struct user_return_notifier { - void (*on_user_return)(struct user_return_notifier *); - struct hlist_node link; -}; - -struct parallel_data; - -struct padata_priv { - struct list_head list; - struct parallel_data *pd; - int cb_cpu; - unsigned int seq_nr; - int info; - void (*parallel)(struct padata_priv *); - void (*serial)(struct padata_priv *); -}; - -struct padata_cpumask { - cpumask_var_t pcpu; - cpumask_var_t cbcpu; -}; - -struct padata_shell; - -struct padata_list; - -struct padata_serial_queue; - -struct parallel_data { - struct padata_shell *ps; - struct padata_list *reorder_list; - struct padata_serial_queue *squeue; - atomic_t refcnt; - unsigned int seq_nr; - unsigned int processed; - int cpu; - struct padata_cpumask cpumask; - struct work_struct reorder_work; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct padata_list { - struct list_head list; - spinlock_t lock; -}; - -struct padata_serial_queue { - struct padata_list serial; - struct work_struct work; - struct parallel_data *pd; -}; - -struct padata_instance; - -struct padata_shell { - struct padata_instance *pinst; - struct parallel_data *pd; - struct parallel_data *opd; - struct list_head list; -}; - -struct padata_instance { - struct hlist_node cpu_online_node; - struct hlist_node cpu_dead_node; - struct workqueue_struct *parallel_wq; - struct workqueue_struct *serial_wq; - struct list_head pslist; - struct padata_cpumask cpumask; - struct kobject kobj; - struct mutex lock; - u8 flags; -}; - -struct padata_mt_job { - void (*thread_fn)(long unsigned int, long unsigned int, void *); - void *fn_arg; - long unsigned int start; - long unsigned int size; - long unsigned int align; - long unsigned int min_chunk; - int max_threads; -}; - -struct padata_work { - struct work_struct pw_work; - struct list_head pw_list; - void *pw_data; -}; - -struct padata_mt_job_state { - spinlock_t lock; - struct completion completion; - struct padata_mt_job *job; - int nworks; - int nworks_fini; - long unsigned int chunk_size; -}; - -struct padata_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct padata_instance *, struct attribute *, char *); - ssize_t (*store)(struct padata_instance *, struct attribute *, const char *, size_t); -}; - -struct static_key_mod { - struct static_key_mod *next; - struct jump_entry *entries; - struct module *mod; -}; - -struct static_key_deferred { - struct static_key key; - long unsigned int timeout; - struct delayed_work work; -}; - -enum rseq_cpu_id_state { - RSEQ_CPU_ID_UNINITIALIZED = 4294967295, - RSEQ_CPU_ID_REGISTRATION_FAILED = 4294967294, -}; - -enum rseq_flags { - RSEQ_FLAG_UNREGISTER = 1, -}; - -enum rseq_cs_flags { - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = 1, - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = 2, - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = 4, -}; - -struct rseq_cs { - __u32 version; - __u32 flags; - __u64 start_ip; - __u64 post_commit_offset; - __u64 abort_ip; -}; - -struct trace_event_raw_rseq_update { - struct trace_entry ent; - s32 cpu_id; - char __data[0]; -}; - -struct trace_event_raw_rseq_ip_fixup { - struct trace_entry ent; - long unsigned int regs_ip; - long unsigned int start_ip; - long unsigned int post_commit_offset; - long unsigned int abort_ip; - char __data[0]; -}; - -struct trace_event_data_offsets_rseq_update {}; - -struct trace_event_data_offsets_rseq_ip_fixup {}; - -typedef void (*btf_trace_rseq_update)(void *, struct task_struct *); - -typedef void (*btf_trace_rseq_ip_fixup)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - -struct watch; - -struct watch_list { - struct callback_head rcu; - struct hlist_head watchers; - void (*release_watch)(struct watch *); - spinlock_t lock; -}; - -enum watch_notification_type { - WATCH_TYPE_META = 0, - WATCH_TYPE_KEY_NOTIFY = 1, - WATCH_TYPE__NR = 2, -}; - -enum watch_meta_notification_subtype { - WATCH_META_REMOVAL_NOTIFICATION = 0, - WATCH_META_LOSS_NOTIFICATION = 1, -}; - -struct watch_notification { - __u32 type: 24; - __u32 subtype: 8; - __u32 info; -}; - -struct watch_notification_type_filter { - __u32 type; - __u32 info_filter; - __u32 info_mask; - __u32 subtype_filter[8]; -}; - -struct watch_notification_filter { - __u32 nr_filters; - __u32 __reserved; - struct watch_notification_type_filter filters[0]; -}; - -struct watch_notification_removal { - struct watch_notification watch; - __u64 id; -}; - -struct watch_type_filter { - enum watch_notification_type type; - __u32 subtype_filter[1]; - __u32 info_filter; - __u32 info_mask; -}; - -struct watch_filter { - union { - struct callback_head rcu; - long unsigned int type_filter[2]; - }; - u32 nr_filters; - struct watch_type_filter filters[0]; -}; - -struct watch_queue { - struct callback_head rcu; - struct watch_filter *filter; - struct pipe_inode_info *pipe; - struct hlist_head watches; - struct page **notes; - long unsigned int *notes_bitmap; - struct kref usage; - spinlock_t lock; - unsigned int nr_notes; - unsigned int nr_pages; - bool defunct; -}; - -struct watch { - union { - struct callback_head rcu; - u32 info_id; - }; - struct watch_queue *queue; - struct hlist_node queue_node; - struct watch_list *watch_list; - struct hlist_node list_node; - const struct cred *cred; - void *private; - u64 id; - struct kref usage; -}; - -struct pkcs7_message; - -typedef int __kernel_rwf_t; - -enum positive_aop_returns { - AOP_WRITEPAGE_ACTIVATE = 524288, - AOP_TRUNCATED_PAGE = 524289, -}; - -enum iter_type { - ITER_IOVEC = 0, - ITER_KVEC = 1, - ITER_BVEC = 2, - ITER_PIPE = 3, - ITER_XARRAY = 4, - ITER_DISCARD = 5, -}; - -enum mapping_flags { - AS_EIO = 0, - AS_ENOSPC = 1, - AS_MM_ALL_LOCKS = 2, - AS_UNEVICTABLE = 3, - AS_EXITING = 4, - AS_NO_WRITEBACK_TAGS = 5, - AS_THP_SUPPORT = 6, -}; - -struct wait_page_key { - struct page *page; - int bit_nr; - int page_match; -}; - -struct pagevec { - unsigned char nr; - bool percpu_pvec_drained; - struct page *pages[15]; -}; - -struct fid { - union { - struct { - u32 ino; - u32 gen; - u32 parent_ino; - u32 parent_gen; - } i32; - struct { - u32 block; - u16 partref; - u16 parent_partref; - u32 generation; - u32 parent_block; - u32 parent_generation; - } udf; - __u32 raw[0]; - }; -}; - -struct trace_event_raw_mm_filemap_op_page_cache { - struct trace_entry ent; - long unsigned int pfn; - long unsigned int i_ino; - long unsigned int index; - dev_t s_dev; - char __data[0]; -}; - -struct trace_event_raw_filemap_set_wb_err { - struct trace_entry ent; - long unsigned int i_ino; - dev_t s_dev; - errseq_t errseq; - char __data[0]; -}; - -struct trace_event_raw_file_check_and_advance_wb_err { - struct trace_entry ent; - struct file *file; - long unsigned int i_ino; - dev_t s_dev; - errseq_t old; - errseq_t new; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_filemap_op_page_cache {}; - -struct trace_event_data_offsets_filemap_set_wb_err {}; - -struct trace_event_data_offsets_file_check_and_advance_wb_err {}; - -typedef void (*btf_trace_mm_filemap_delete_from_page_cache)(void *, struct page *); - -typedef void (*btf_trace_mm_filemap_add_to_page_cache)(void *, struct page *); - -typedef void (*btf_trace_filemap_set_wb_err)(void *, struct address_space *, errseq_t); - -typedef void (*btf_trace_file_check_and_advance_wb_err)(void *, struct file *, errseq_t); - -enum behavior { - EXCLUSIVE = 0, - SHARED = 1, - DROP = 2, -}; - -struct reciprocal_value { - u32 m; - u8 sh1; - u8 sh2; -}; - -struct kmem_cache_order_objects { - unsigned int x; -}; - -struct kmem_cache_cpu; - -struct kmem_cache_node; - -struct kmem_cache { - struct kmem_cache_cpu *cpu_slab; - slab_flags_t flags; - long unsigned int min_partial; - unsigned int size; - unsigned int object_size; - struct reciprocal_value reciprocal_size; - unsigned int offset; - unsigned int cpu_partial; - struct kmem_cache_order_objects oo; - struct kmem_cache_order_objects max; - struct kmem_cache_order_objects min; - gfp_t allocflags; - int refcount; - void (*ctor)(void *); - unsigned int inuse; - unsigned int align; - unsigned int red_left_pad; - const char *name; - struct list_head list; - struct kobject kobj; - long unsigned int random; - unsigned int remote_node_defrag_ratio; - unsigned int *random_seq; - unsigned int useroffset; - unsigned int usersize; - struct kmem_cache_node *node[32]; -}; - -struct kmem_cache_cpu { - void **freelist; - long unsigned int tid; - struct page *page; - struct page *partial; -}; - -struct kmem_cache_node { - spinlock_t list_lock; - long unsigned int nr_partial; - struct list_head partial; - atomic_long_t nr_slabs; - atomic_long_t total_objects; - struct list_head full; -}; - -struct zap_details { - struct address_space *check_mapping; - long unsigned int first_index; - long unsigned int last_index; - struct page *single_page; -}; - -enum oom_constraint { - CONSTRAINT_NONE = 0, - CONSTRAINT_CPUSET = 1, - CONSTRAINT_MEMORY_POLICY = 2, - CONSTRAINT_MEMCG = 3, -}; - -struct oom_control { - struct zonelist *zonelist; - nodemask_t *nodemask; - struct mem_cgroup *memcg; - const gfp_t gfp_mask; - const int order; - long unsigned int totalpages; - struct task_struct *chosen; - long int chosen_points; - enum oom_constraint constraint; -}; - -enum compact_priority { - COMPACT_PRIO_SYNC_FULL = 0, - MIN_COMPACT_PRIORITY = 0, - COMPACT_PRIO_SYNC_LIGHT = 1, - MIN_COMPACT_COSTLY_PRIORITY = 1, - DEF_COMPACT_PRIORITY = 1, - COMPACT_PRIO_ASYNC = 2, - INIT_COMPACT_PRIORITY = 2, -}; - -enum compact_result { - COMPACT_NOT_SUITABLE_ZONE = 0, - COMPACT_SKIPPED = 1, - COMPACT_DEFERRED = 2, - COMPACT_NO_SUITABLE_PAGE = 3, - COMPACT_CONTINUE = 4, - COMPACT_COMPLETE = 5, - COMPACT_PARTIAL_SKIPPED = 6, - COMPACT_CONTENDED = 7, - COMPACT_SUCCESS = 8, -}; - -struct trace_event_raw_oom_score_adj_update { - struct trace_entry ent; - pid_t pid; - char comm[16]; - short int oom_score_adj; - char __data[0]; -}; - -struct trace_event_raw_reclaim_retry_zone { - struct trace_entry ent; - int node; - int zone_idx; - int order; - long unsigned int reclaimable; - long unsigned int available; - long unsigned int min_wmark; - int no_progress_loops; - bool wmark_check; - char __data[0]; -}; - -struct trace_event_raw_mark_victim { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_wake_reaper { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_start_task_reaping { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_finish_task_reaping { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_skip_task_reaping { - struct trace_entry ent; - int pid; - char __data[0]; -}; - -struct trace_event_raw_compact_retry { - struct trace_entry ent; - int order; - int priority; - int result; - int retries; - int max_retries; - bool ret; - char __data[0]; -}; - -struct trace_event_data_offsets_oom_score_adj_update {}; - -struct trace_event_data_offsets_reclaim_retry_zone {}; - -struct trace_event_data_offsets_mark_victim {}; - -struct trace_event_data_offsets_wake_reaper {}; - -struct trace_event_data_offsets_start_task_reaping {}; - -struct trace_event_data_offsets_finish_task_reaping {}; - -struct trace_event_data_offsets_skip_task_reaping {}; - -struct trace_event_data_offsets_compact_retry {}; - -typedef void (*btf_trace_oom_score_adj_update)(void *, struct task_struct *); - -typedef void (*btf_trace_reclaim_retry_zone)(void *, struct zoneref *, int, long unsigned int, long unsigned int, long unsigned int, int, bool); - -typedef void (*btf_trace_mark_victim)(void *, int); - -typedef void (*btf_trace_wake_reaper)(void *, int); - -typedef void (*btf_trace_start_task_reaping)(void *, int); - -typedef void (*btf_trace_finish_task_reaping)(void *, int); - -typedef void (*btf_trace_skip_task_reaping)(void *, int); - -typedef void (*btf_trace_compact_retry)(void *, int, enum compact_priority, enum compact_result, int, int, bool); - -enum wb_congested_state { - WB_async_congested = 0, - WB_sync_congested = 1, -}; - -enum wb_state { - WB_registered = 0, - WB_writeback_running = 1, - WB_has_dirty_io = 2, - WB_start_all = 3, -}; - -enum { - BLK_RW_ASYNC = 0, - BLK_RW_SYNC = 1, -}; - -struct wb_lock_cookie { - bool locked; - long unsigned int flags; -}; - -typedef int (*writepage_t)(struct page *, struct writeback_control *, void *); - -enum page_memcg_data_flags { - MEMCG_DATA_OBJCGS = 1, - MEMCG_DATA_KMEM = 2, - __NR_MEMCG_DATA_FLAGS = 4, -}; - -struct dirty_throttle_control { - struct wb_domain *dom; - struct dirty_throttle_control *gdtc; - struct bdi_writeback *wb; - struct fprop_local_percpu *wb_completions; - long unsigned int avail; - long unsigned int dirty; - long unsigned int thresh; - long unsigned int bg_thresh; - long unsigned int wb_dirty; - long unsigned int wb_thresh; - long unsigned int wb_bg_thresh; - long unsigned int pos_ratio; -}; - -typedef void compound_page_dtor(struct page *); - -struct trace_event_raw_mm_lru_insertion { - struct trace_entry ent; - struct page *page; - long unsigned int pfn; - enum lru_list lru; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_mm_lru_activate { - struct trace_entry ent; - struct page *page; - long unsigned int pfn; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_lru_insertion {}; - -struct trace_event_data_offsets_mm_lru_activate {}; - -typedef void (*btf_trace_mm_lru_insertion)(void *, struct page *); - -typedef void (*btf_trace_mm_lru_activate)(void *, struct page *); - -struct lru_rotate { - local_lock_t lock; - struct pagevec pvec; -}; - -struct lru_pvecs { - local_lock_t lock; - struct pagevec lru_add; - struct pagevec lru_deactivate_file; - struct pagevec lru_deactivate; - struct pagevec lru_lazyfree; - struct pagevec activate_page; -}; - -enum lruvec_flags { - LRUVEC_CONGESTED = 0, -}; - -enum pgdat_flags { - PGDAT_DIRTY = 0, - PGDAT_WRITEBACK = 1, - PGDAT_RECLAIM_LOCKED = 2, -}; - -enum zone_flags { - ZONE_BOOSTED_WATERMARK = 0, - ZONE_RECLAIM_ACTIVE = 1, -}; - -struct reclaim_stat { - unsigned int nr_dirty; - unsigned int nr_unqueued_dirty; - unsigned int nr_congested; - unsigned int nr_writeback; - unsigned int nr_immediate; - unsigned int nr_pageout; - unsigned int nr_activate[2]; - unsigned int nr_ref_keep; - unsigned int nr_unmap_fail; - unsigned int nr_lazyfree_fail; -}; - -struct mem_cgroup_reclaim_cookie { - pg_data_t *pgdat; - unsigned int generation; -}; - -enum ttu_flags { - TTU_SPLIT_HUGE_PMD = 4, - TTU_IGNORE_MLOCK = 8, - TTU_SYNC = 16, - TTU_IGNORE_HWPOISON = 32, - TTU_BATCH_FLUSH = 64, - TTU_RMAP_LOCKED = 128, -}; - -struct trace_event_raw_mm_vmscan_kswapd_sleep { - struct trace_entry ent; - int nid; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_kswapd_wake { - struct trace_entry ent; - int nid; - int zid; - int order; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_wakeup_kswapd { - struct trace_entry ent; - int nid; - int zid; - int order; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_direct_reclaim_begin_template { - struct trace_entry ent; - int order; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_direct_reclaim_end_template { - struct trace_entry ent; - long unsigned int nr_reclaimed; - char __data[0]; -}; - -struct trace_event_raw_mm_shrink_slab_start { - struct trace_entry ent; - struct shrinker *shr; - void *shrink; - int nid; - long int nr_objects_to_shrink; - gfp_t gfp_flags; - long unsigned int cache_items; - long long unsigned int delta; - long unsigned int total_scan; - int priority; - char __data[0]; -}; - -struct trace_event_raw_mm_shrink_slab_end { - struct trace_entry ent; - struct shrinker *shr; - int nid; - void *shrink; - long int unused_scan; - long int new_scan; - int retval; - long int total_scan; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_lru_isolate { - struct trace_entry ent; - int highest_zoneidx; - int order; - long unsigned int nr_requested; - long unsigned int nr_scanned; - long unsigned int nr_skipped; - long unsigned int nr_taken; - isolate_mode_t isolate_mode; - int lru; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_writepage { - struct trace_entry ent; - long unsigned int pfn; - int reclaim_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_lru_shrink_inactive { - struct trace_entry ent; - int nid; - long unsigned int nr_scanned; - long unsigned int nr_reclaimed; - long unsigned int nr_dirty; - long unsigned int nr_writeback; - long unsigned int nr_congested; - long unsigned int nr_immediate; - unsigned int nr_activate0; - unsigned int nr_activate1; - long unsigned int nr_ref_keep; - long unsigned int nr_unmap_fail; - int priority; - int reclaim_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_lru_shrink_active { - struct trace_entry ent; - int nid; - long unsigned int nr_taken; - long unsigned int nr_active; - long unsigned int nr_deactivated; - long unsigned int nr_referenced; - int priority; - int reclaim_flags; - char __data[0]; -}; - -struct trace_event_raw_mm_vmscan_node_reclaim_begin { - struct trace_entry ent; - int nid; - int order; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_vmscan_kswapd_sleep {}; - -struct trace_event_data_offsets_mm_vmscan_kswapd_wake {}; - -struct trace_event_data_offsets_mm_vmscan_wakeup_kswapd {}; - -struct trace_event_data_offsets_mm_vmscan_direct_reclaim_begin_template {}; - -struct trace_event_data_offsets_mm_vmscan_direct_reclaim_end_template {}; - -struct trace_event_data_offsets_mm_shrink_slab_start {}; - -struct trace_event_data_offsets_mm_shrink_slab_end {}; - -struct trace_event_data_offsets_mm_vmscan_lru_isolate {}; - -struct trace_event_data_offsets_mm_vmscan_writepage {}; - -struct trace_event_data_offsets_mm_vmscan_lru_shrink_inactive {}; - -struct trace_event_data_offsets_mm_vmscan_lru_shrink_active {}; - -struct trace_event_data_offsets_mm_vmscan_node_reclaim_begin {}; - -typedef void (*btf_trace_mm_vmscan_kswapd_sleep)(void *, int); - -typedef void (*btf_trace_mm_vmscan_kswapd_wake)(void *, int, int, int); - -typedef void (*btf_trace_mm_vmscan_wakeup_kswapd)(void *, int, int, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_direct_reclaim_begin)(void *, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_memcg_reclaim_begin)(void *, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_memcg_softlimit_reclaim_begin)(void *, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_direct_reclaim_end)(void *, long unsigned int); - -typedef void (*btf_trace_mm_vmscan_memcg_reclaim_end)(void *, long unsigned int); - -typedef void (*btf_trace_mm_vmscan_memcg_softlimit_reclaim_end)(void *, long unsigned int); - -typedef void (*btf_trace_mm_shrink_slab_start)(void *, struct shrinker *, struct shrink_control *, long int, long unsigned int, long long unsigned int, long unsigned int, int); - -typedef void (*btf_trace_mm_shrink_slab_end)(void *, struct shrinker *, int, int, long int, long int, long int); - -typedef void (*btf_trace_mm_vmscan_lru_isolate)(void *, int, int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, isolate_mode_t, int); - -typedef void (*btf_trace_mm_vmscan_writepage)(void *, struct page *); - -typedef void (*btf_trace_mm_vmscan_lru_shrink_inactive)(void *, int, long unsigned int, long unsigned int, struct reclaim_stat *, int, int); - -typedef void (*btf_trace_mm_vmscan_lru_shrink_active)(void *, int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, int, int); - -typedef void (*btf_trace_mm_vmscan_node_reclaim_begin)(void *, int, int, gfp_t); - -typedef void (*btf_trace_mm_vmscan_node_reclaim_end)(void *, long unsigned int); - -struct scan_control { - long unsigned int nr_to_reclaim; - nodemask_t *nodemask; - struct mem_cgroup *target_mem_cgroup; - long unsigned int anon_cost; - long unsigned int file_cost; - unsigned int may_deactivate: 2; - unsigned int force_deactivate: 1; - unsigned int skipped_deactivate: 1; - unsigned int may_writepage: 1; - unsigned int may_unmap: 1; - unsigned int may_swap: 1; - unsigned int memcg_low_reclaim: 1; - unsigned int memcg_low_skipped: 1; - unsigned int hibernation_mode: 1; - unsigned int compaction_ready: 1; - unsigned int cache_trim_mode: 1; - unsigned int file_is_tiny: 1; - s8 order; - s8 priority; - s8 reclaim_idx; - gfp_t gfp_mask; - long unsigned int nr_scanned; - long unsigned int nr_reclaimed; - struct { - unsigned int dirty; - unsigned int unqueued_dirty; - unsigned int congested; - unsigned int writeback; - unsigned int immediate; - unsigned int file_taken; - unsigned int taken; - } nr; - struct reclaim_state reclaim_state; -}; - -typedef enum { - PAGE_KEEP = 0, - PAGE_ACTIVATE = 1, - PAGE_SUCCESS = 2, - PAGE_CLEAN = 3, -} pageout_t; - -enum page_references { - PAGEREF_RECLAIM = 0, - PAGEREF_RECLAIM_CLEAN = 1, - PAGEREF_KEEP = 2, - PAGEREF_ACTIVATE = 3, -}; - -enum scan_balance { - SCAN_EQUAL = 0, - SCAN_FRACT = 1, - SCAN_ANON = 2, - SCAN_FILE = 3, -}; - -typedef __u64 __le64; - -enum transparent_hugepage_flag { - TRANSPARENT_HUGEPAGE_NEVER_DAX = 0, - TRANSPARENT_HUGEPAGE_FLAG = 1, - TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG = 2, - TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG = 3, - TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG = 4, - TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG = 5, - TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG = 6, - TRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG = 7, - TRANSPARENT_HUGEPAGE_USE_ZERO_PAGE_FLAG = 8, -}; - -struct xattr; - -typedef int (*initxattrs)(struct inode *, const struct xattr *, void *); - -struct xattr { - const char *name; - void *value; - size_t value_len; -}; - -struct constant_table { - const char *name; - int value; -}; - -enum { - MPOL_DEFAULT = 0, - MPOL_PREFERRED = 1, - MPOL_BIND = 2, - MPOL_INTERLEAVE = 3, - MPOL_LOCAL = 4, - MPOL_MAX = 5, -}; - -struct shared_policy { - struct rb_root root; - rwlock_t lock; -}; - -struct simple_xattrs { - struct list_head head; - spinlock_t lock; -}; - -struct simple_xattr { - struct list_head list; - char *name; - size_t size; - char value[0]; -}; - -struct shmem_inode_info { - spinlock_t lock; - unsigned int seals; - long unsigned int flags; - long unsigned int alloced; - long unsigned int swapped; - struct list_head shrinklist; - struct list_head swaplist; - struct shared_policy policy; - struct simple_xattrs xattrs; - atomic_t stop_eviction; - struct inode vfs_inode; -}; - -struct shmem_sb_info { - long unsigned int max_blocks; - struct percpu_counter used_blocks; - long unsigned int max_inodes; - long unsigned int free_inodes; - spinlock_t stat_lock; - umode_t mode; - unsigned char huge; - kuid_t uid; - kgid_t gid; - bool full_inums; - ino_t next_ino; - ino_t *ino_batch; - struct mempolicy *mpol; - spinlock_t shrinklist_lock; - struct list_head shrinklist; - long unsigned int shrinklist_len; -}; - -enum sgp_type { - SGP_READ = 0, - SGP_CACHE = 1, - SGP_NOHUGE = 2, - SGP_HUGE = 3, - SGP_WRITE = 4, - SGP_FALLOC = 5, -}; - -enum fid_type { - FILEID_ROOT = 0, - FILEID_INO32_GEN = 1, - FILEID_INO32_GEN_PARENT = 2, - FILEID_BTRFS_WITHOUT_PARENT = 77, - FILEID_BTRFS_WITH_PARENT = 78, - FILEID_BTRFS_WITH_PARENT_ROOT = 79, - FILEID_UDF_WITHOUT_PARENT = 81, - FILEID_UDF_WITH_PARENT = 82, - FILEID_NILFS_WITHOUT_PARENT = 97, - FILEID_NILFS_WITH_PARENT = 98, - FILEID_FAT_WITHOUT_PARENT = 113, - FILEID_FAT_WITH_PARENT = 114, - FILEID_LUSTRE = 151, - FILEID_KERNFS = 254, - FILEID_INVALID = 255, -}; - -struct shmem_falloc { - wait_queue_head_t *waitq; - long unsigned int start; - long unsigned int next; - long unsigned int nr_falloced; - long unsigned int nr_unswapped; -}; - -struct shmem_options { - long long unsigned int blocks; - long long unsigned int inodes; - struct mempolicy *mpol; - kuid_t uid; - kgid_t gid; - umode_t mode; - bool full_inums; - int huge; - int seen; -}; - -enum shmem_param { - Opt_gid = 0, - Opt_huge = 1, - Opt_mode = 2, - Opt_mpol = 3, - Opt_nr_blocks = 4, - Opt_nr_inodes = 5, - Opt_size = 6, - Opt_uid = 7, - Opt_inode32 = 8, - Opt_inode64 = 9, -}; - -enum writeback_stat_item { - NR_DIRTY_THRESHOLD = 0, - NR_DIRTY_BG_THRESHOLD = 1, - NR_VM_WRITEBACK_STAT_ITEMS = 2, -}; - -struct contig_page_info { - long unsigned int free_pages; - long unsigned int free_blocks_total; - long unsigned int free_blocks_suitable; -}; - -struct radix_tree_iter { - long unsigned int index; - long unsigned int next_index; - long unsigned int tags; - struct xa_node *node; -}; - -enum { - RADIX_TREE_ITER_TAG_MASK = 15, - RADIX_TREE_ITER_TAGGED = 16, - RADIX_TREE_ITER_CONTIG = 32, -}; - -enum mminit_level { - MMINIT_WARNING = 0, - MMINIT_VERIFY = 1, - MMINIT_TRACE = 2, -}; - -struct pcpu_group_info { - int nr_units; - long unsigned int base_offset; - unsigned int *cpu_map; -}; - -struct pcpu_alloc_info { - size_t static_size; - size_t reserved_size; - size_t dyn_size; - size_t unit_size; - size_t atom_size; - size_t alloc_size; - size_t __ai_size; - int nr_groups; - struct pcpu_group_info groups[0]; -}; - -struct trace_event_raw_percpu_alloc_percpu { - struct trace_entry ent; - bool reserved; - bool is_atomic; - size_t size; - size_t align; - void *base_addr; - int off; - void *ptr; - char __data[0]; -}; - -struct trace_event_raw_percpu_free_percpu { - struct trace_entry ent; - void *base_addr; - int off; - void *ptr; - char __data[0]; -}; - -struct trace_event_raw_percpu_alloc_percpu_fail { - struct trace_entry ent; - bool reserved; - bool is_atomic; - size_t size; - size_t align; - char __data[0]; -}; - -struct trace_event_raw_percpu_create_chunk { - struct trace_entry ent; - void *base_addr; - char __data[0]; -}; - -struct trace_event_raw_percpu_destroy_chunk { - struct trace_entry ent; - void *base_addr; - char __data[0]; -}; - -struct trace_event_data_offsets_percpu_alloc_percpu {}; - -struct trace_event_data_offsets_percpu_free_percpu {}; - -struct trace_event_data_offsets_percpu_alloc_percpu_fail {}; - -struct trace_event_data_offsets_percpu_create_chunk {}; - -struct trace_event_data_offsets_percpu_destroy_chunk {}; - -typedef void (*btf_trace_percpu_alloc_percpu)(void *, bool, bool, size_t, size_t, void *, int, void *); - -typedef void (*btf_trace_percpu_free_percpu)(void *, void *, int, void *); - -typedef void (*btf_trace_percpu_alloc_percpu_fail)(void *, bool, bool, size_t, size_t); - -typedef void (*btf_trace_percpu_create_chunk)(void *, void *); - -typedef void (*btf_trace_percpu_destroy_chunk)(void *, void *); - -struct pcpu_block_md { - int scan_hint; - int scan_hint_start; - int contig_hint; - int contig_hint_start; - int left_free; - int right_free; - int first_free; - int nr_bits; -}; - -struct pcpu_chunk { - struct list_head list; - int free_bytes; - struct pcpu_block_md chunk_md; - void *base_addr; - long unsigned int *alloc_map; - long unsigned int *bound_map; - struct pcpu_block_md *md_blocks; - void *data; - bool immutable; - bool isolated; - int start_offset; - int end_offset; - struct obj_cgroup **obj_cgroups; - int nr_pages; - int nr_populated; - int nr_empty_pop_pages; - long unsigned int populated[0]; -}; - -struct trace_event_raw_kmem_alloc { - struct trace_entry ent; - long unsigned int call_site; - const void *ptr; - size_t bytes_req; - size_t bytes_alloc; - gfp_t gfp_flags; - char __data[0]; -}; - -struct trace_event_raw_kmem_alloc_node { - struct trace_entry ent; - long unsigned int call_site; - const void *ptr; - size_t bytes_req; - size_t bytes_alloc; - gfp_t gfp_flags; - int node; - char __data[0]; -}; - -struct trace_event_raw_kfree { - struct trace_entry ent; - long unsigned int call_site; - const void *ptr; - char __data[0]; -}; - -struct trace_event_raw_kmem_cache_free { - struct trace_entry ent; - long unsigned int call_site; - const void *ptr; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_mm_page_free { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - char __data[0]; -}; - -struct trace_event_raw_mm_page_free_batched { - struct trace_entry ent; - long unsigned int pfn; - char __data[0]; -}; - -struct trace_event_raw_mm_page_alloc { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - gfp_t gfp_flags; - int migratetype; - char __data[0]; -}; - -struct trace_event_raw_mm_page { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - int migratetype; - char __data[0]; -}; - -struct trace_event_raw_mm_page_pcpu_drain { - struct trace_entry ent; - long unsigned int pfn; - unsigned int order; - int migratetype; - char __data[0]; -}; - -struct trace_event_raw_mm_page_alloc_extfrag { - struct trace_entry ent; - long unsigned int pfn; - int alloc_order; - int fallback_order; - int alloc_migratetype; - int fallback_migratetype; - int change_ownership; - char __data[0]; -}; - -struct trace_event_raw_rss_stat { - struct trace_entry ent; - unsigned int mm_id; - unsigned int curr; - int member; - long int size; - char __data[0]; -}; - -struct trace_event_data_offsets_kmem_alloc {}; - -struct trace_event_data_offsets_kmem_alloc_node {}; - -struct trace_event_data_offsets_kfree {}; - -struct trace_event_data_offsets_kmem_cache_free { - u32 name; -}; - -struct trace_event_data_offsets_mm_page_free {}; - -struct trace_event_data_offsets_mm_page_free_batched {}; - -struct trace_event_data_offsets_mm_page_alloc {}; - -struct trace_event_data_offsets_mm_page {}; - -struct trace_event_data_offsets_mm_page_pcpu_drain {}; - -struct trace_event_data_offsets_mm_page_alloc_extfrag {}; - -struct trace_event_data_offsets_rss_stat {}; - -typedef void (*btf_trace_kmalloc)(void *, long unsigned int, const void *, size_t, size_t, gfp_t); - -typedef void (*btf_trace_kmem_cache_alloc)(void *, long unsigned int, const void *, size_t, size_t, gfp_t); - -typedef void (*btf_trace_kmalloc_node)(void *, long unsigned int, const void *, size_t, size_t, gfp_t, int); - -typedef void (*btf_trace_kmem_cache_alloc_node)(void *, long unsigned int, const void *, size_t, size_t, gfp_t, int); - -typedef void (*btf_trace_kfree)(void *, long unsigned int, const void *); - -typedef void (*btf_trace_kmem_cache_free)(void *, long unsigned int, const void *, const char *); - -typedef void (*btf_trace_mm_page_free)(void *, struct page *, unsigned int); - -typedef void (*btf_trace_mm_page_free_batched)(void *, struct page *); - -typedef void (*btf_trace_mm_page_alloc)(void *, struct page *, unsigned int, gfp_t, int); - -typedef void (*btf_trace_mm_page_alloc_zone_locked)(void *, struct page *, unsigned int, int); - -typedef void (*btf_trace_mm_page_pcpu_drain)(void *, struct page *, unsigned int, int); - -typedef void (*btf_trace_mm_page_alloc_extfrag)(void *, struct page *, int, int, int, int); - -typedef void (*btf_trace_rss_stat)(void *, struct mm_struct *, int, long int); - -enum slab_state { - DOWN = 0, - PARTIAL = 1, - PARTIAL_NODE = 2, - UP = 3, - FULL = 4, -}; - -struct kmalloc_info_struct { - const char *name[4]; - unsigned int size; -}; - -struct slabinfo { - long unsigned int active_objs; - long unsigned int num_objs; - long unsigned int active_slabs; - long unsigned int num_slabs; - long unsigned int shared_avail; - unsigned int limit; - unsigned int batchcount; - unsigned int shared; - unsigned int objects_per_slab; - unsigned int cache_order; -}; - -struct kmem_obj_info { - void *kp_ptr; - struct page *kp_page; - void *kp_objp; - long unsigned int kp_data_offset; - struct kmem_cache *kp_slab_cache; - void *kp_ret; - void *kp_stack[16]; - void *kp_free_stack[16]; -}; - -enum pageblock_bits { - PB_migrate = 0, - PB_migrate_end = 2, - PB_migrate_skip = 3, - NR_PAGEBLOCK_BITS = 4, -}; - -struct node___2 { - struct device dev; - struct list_head access_list; - struct work_struct node_work; - struct list_head cache_attrs; - struct device *cache_dev; -}; - -typedef struct page *new_page_t(struct page *, long unsigned int); - -typedef void free_page_t(struct page *, long unsigned int); - -struct alloc_context { - struct zonelist *zonelist; - nodemask_t *nodemask; - struct zoneref *preferred_zoneref; - int migratetype; - enum zone_type highest_zoneidx; - bool spread_dirty_pages; -}; - -struct trace_event_raw_mm_compaction_isolate_template { - struct trace_entry ent; - long unsigned int start_pfn; - long unsigned int end_pfn; - long unsigned int nr_scanned; - long unsigned int nr_taken; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_migratepages { - struct trace_entry ent; - long unsigned int nr_migrated; - long unsigned int nr_failed; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_begin { - struct trace_entry ent; - long unsigned int zone_start; - long unsigned int migrate_pfn; - long unsigned int free_pfn; - long unsigned int zone_end; - bool sync; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_end { - struct trace_entry ent; - long unsigned int zone_start; - long unsigned int migrate_pfn; - long unsigned int free_pfn; - long unsigned int zone_end; - bool sync; - int status; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_try_to_compact_pages { - struct trace_entry ent; - int order; - gfp_t gfp_mask; - int prio; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_suitable_template { - struct trace_entry ent; - int nid; - enum zone_type idx; - int order; - int ret; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_defer_template { - struct trace_entry ent; - int nid; - enum zone_type idx; - int order; - unsigned int considered; - unsigned int defer_shift; - int order_failed; - char __data[0]; -}; - -struct trace_event_raw_mm_compaction_kcompactd_sleep { - struct trace_entry ent; - int nid; - char __data[0]; -}; - -struct trace_event_raw_kcompactd_wake_template { - struct trace_entry ent; - int nid; - int order; - enum zone_type highest_zoneidx; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_compaction_isolate_template {}; - -struct trace_event_data_offsets_mm_compaction_migratepages {}; - -struct trace_event_data_offsets_mm_compaction_begin {}; - -struct trace_event_data_offsets_mm_compaction_end {}; - -struct trace_event_data_offsets_mm_compaction_try_to_compact_pages {}; - -struct trace_event_data_offsets_mm_compaction_suitable_template {}; - -struct trace_event_data_offsets_mm_compaction_defer_template {}; - -struct trace_event_data_offsets_mm_compaction_kcompactd_sleep {}; - -struct trace_event_data_offsets_kcompactd_wake_template {}; - -typedef void (*btf_trace_mm_compaction_isolate_migratepages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - -typedef void (*btf_trace_mm_compaction_isolate_freepages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - -typedef void (*btf_trace_mm_compaction_migratepages)(void *, long unsigned int, int, struct list_head *); - -typedef void (*btf_trace_mm_compaction_begin)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, bool); - -typedef void (*btf_trace_mm_compaction_end)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, bool, int); - -typedef void (*btf_trace_mm_compaction_try_to_compact_pages)(void *, int, gfp_t, int); - -typedef void (*btf_trace_mm_compaction_finished)(void *, struct zone *, int, int); - -typedef void (*btf_trace_mm_compaction_suitable)(void *, struct zone *, int, int); - -typedef void (*btf_trace_mm_compaction_deferred)(void *, struct zone *, int); - -typedef void (*btf_trace_mm_compaction_defer_compaction)(void *, struct zone *, int); - -typedef void (*btf_trace_mm_compaction_defer_reset)(void *, struct zone *, int); - -typedef void (*btf_trace_mm_compaction_kcompactd_sleep)(void *, int); - -typedef void (*btf_trace_mm_compaction_wakeup_kcompactd)(void *, int, int, enum zone_type); - -typedef void (*btf_trace_mm_compaction_kcompactd_wake)(void *, int, int, enum zone_type); - -typedef enum { - ISOLATE_ABORT = 0, - ISOLATE_NONE = 1, - ISOLATE_SUCCESS = 2, -} isolate_migrate_t; - -struct anon_vma_chain { - struct vm_area_struct *vma; - struct anon_vma *anon_vma; - struct list_head same_vma; - struct rb_node rb; - long unsigned int rb_subtree_last; -}; - -enum lru_status { - LRU_REMOVED = 0, - LRU_REMOVED_RETRY = 1, - LRU_ROTATE = 2, - LRU_SKIP = 3, - LRU_RETRY = 4, -}; - -typedef enum lru_status (*list_lru_walk_cb)(struct list_head *, struct list_lru_one *, spinlock_t *, void *); - -typedef struct { - long unsigned int pd; -} hugepd_t; - -struct migration_target_control { - int nid; - nodemask_t *nmask; - gfp_t gfp_mask; -}; - -struct follow_page_context { - struct dev_pagemap *pgmap; - unsigned int page_mask; -}; - -struct trace_event_raw_mmap_lock_start_locking { - struct trace_entry ent; - struct mm_struct *mm; - u32 __data_loc_memcg_path; - bool write; - char __data[0]; -}; - -struct trace_event_raw_mmap_lock_acquire_returned { - struct trace_entry ent; - struct mm_struct *mm; - u32 __data_loc_memcg_path; - bool write; - bool success; - char __data[0]; -}; - -struct trace_event_raw_mmap_lock_released { - struct trace_entry ent; - struct mm_struct *mm; - u32 __data_loc_memcg_path; - bool write; - char __data[0]; -}; - -struct trace_event_data_offsets_mmap_lock_start_locking { - u32 memcg_path; -}; - -struct trace_event_data_offsets_mmap_lock_acquire_returned { - u32 memcg_path; -}; - -struct trace_event_data_offsets_mmap_lock_released { - u32 memcg_path; -}; - -typedef void (*btf_trace_mmap_lock_start_locking)(void *, struct mm_struct *, const char *, bool); - -typedef void (*btf_trace_mmap_lock_acquire_returned)(void *, struct mm_struct *, const char *, bool, bool); - -typedef void (*btf_trace_mmap_lock_released)(void *, struct mm_struct *, const char *, bool); - -struct memcg_path { - local_lock_t lock; - char *buf; - local_t buf_idx; -}; - -typedef unsigned int pgtbl_mod_mask; - -enum { - SWP_USED = 1, - SWP_WRITEOK = 2, - SWP_DISCARDABLE = 4, - SWP_DISCARDING = 8, - SWP_SOLIDSTATE = 16, - SWP_CONTINUED = 32, - SWP_BLKDEV = 64, - SWP_ACTIVATED = 128, - SWP_FS_OPS = 256, - SWP_AREA_DISCARD = 512, - SWP_PAGE_DISCARD = 1024, - SWP_STABLE_WRITES = 2048, - SWP_SYNCHRONOUS_IO = 4096, - SWP_SCANNING = 16384, -}; - -struct copy_subpage_arg { - struct page *dst; - struct page *src; - struct vm_area_struct *vma; -}; - -struct mm_walk; - -struct mm_walk_ops { - int (*pgd_entry)(pgd_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*p4d_entry)(p4d_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pud_entry)(pud_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pmd_entry)(pmd_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pte_entry)(pte_t *, long unsigned int, long unsigned int, struct mm_walk *); - int (*pte_hole)(long unsigned int, long unsigned int, int, struct mm_walk *); - int (*hugetlb_entry)(pte_t *, long unsigned int, long unsigned int, long unsigned int, struct mm_walk *); - int (*test_walk)(long unsigned int, long unsigned int, struct mm_walk *); - int (*pre_vma)(long unsigned int, long unsigned int, struct mm_walk *); - void (*post_vma)(struct mm_walk *); -}; - -enum page_walk_action { - ACTION_SUBTREE = 0, - ACTION_CONTINUE = 1, - ACTION_AGAIN = 2, -}; - -struct mm_walk { - const struct mm_walk_ops *ops; - struct mm_struct *mm; - pgd_t *pgd; - struct vm_area_struct *vma; - enum page_walk_action action; - bool no_vma; - void *private; -}; - -enum { - HUGETLB_SHMFS_INODE = 1, - HUGETLB_ANONHUGE_INODE = 2, -}; - -struct trace_event_raw_vm_unmapped_area { - struct trace_entry ent; - long unsigned int addr; - long unsigned int total_vm; - long unsigned int flags; - long unsigned int length; - long unsigned int low_limit; - long unsigned int high_limit; - long unsigned int align_mask; - long unsigned int align_offset; - char __data[0]; -}; - -struct trace_event_data_offsets_vm_unmapped_area {}; - -typedef void (*btf_trace_vm_unmapped_area)(void *, long unsigned int, struct vm_unmapped_area_info *); - -enum pgt_entry { - NORMAL_PMD = 0, - HPAGE_PMD = 1, - NORMAL_PUD = 2, - HPAGE_PUD = 3, -}; - -struct rmap_walk_control { - void *arg; - bool (*rmap_one)(struct page *, struct vm_area_struct *, long unsigned int, void *); - int (*done)(struct page *); - struct anon_vma * (*anon_lock)(struct page *); - bool (*invalid_vma)(struct vm_area_struct *, void *); -}; - -struct page_referenced_arg { - int mapcount; - int referenced; - long unsigned int vm_flags; - struct mem_cgroup *memcg; -}; - -struct make_exclusive_args { - struct mm_struct *mm; - long unsigned int address; - void *owner; - bool valid; -}; - -struct vmap_area { - long unsigned int va_start; - long unsigned int va_end; - struct rb_node rb_node; - struct list_head list; - union { - long unsigned int subtree_max_size; - struct vm_struct *vm; - }; -}; - -struct vfree_deferred { - struct llist_head list; - struct work_struct wq; -}; - -enum fit_type { - NOTHING_FIT = 0, - FL_FIT_TYPE = 1, - LE_FIT_TYPE = 2, - RE_FIT_TYPE = 3, - NE_FIT_TYPE = 4, -}; - -struct vmap_block_queue { - spinlock_t lock; - struct list_head free; -}; - -struct vmap_block { - spinlock_t lock; - struct vmap_area *va; - long unsigned int free; - long unsigned int dirty; - long unsigned int dirty_min; - long unsigned int dirty_max; - struct list_head free_list; - struct callback_head callback_head; - struct list_head purge; -}; - -struct vmap_pfn_data { - long unsigned int *pfns; - pgprot_t prot; - unsigned int idx; -}; - -struct page_frag_cache { - void *va; - __u16 offset; - __u16 size; - unsigned int pagecnt_bias; - bool pfmemalloc; -}; - -typedef int fpi_t; - -struct pagesets { - local_lock_t lock; -}; - -struct pcpu_drain { - struct zone *zone; - struct work_struct work; -}; - -struct mminit_pfnnid_cache { - long unsigned int last_start; - long unsigned int last_end; - int last_nid; -}; - -enum { - MMOP_OFFLINE = 0, - MMOP_ONLINE = 1, - MMOP_ONLINE_KERNEL = 2, - MMOP_ONLINE_MOVABLE = 3, -}; - -typedef int mhp_t; - -typedef void (*online_page_callback_t)(struct page *, unsigned int); - -struct memory_block { - long unsigned int start_section_nr; - long unsigned int state; - int online_type; - int nid; - struct device dev; - long unsigned int nr_vmemmap_pages; -}; - -struct memory_notify { - long unsigned int start_pfn; - long unsigned int nr_pages; - int status_change_nid_normal; - int status_change_nid_high; - int status_change_nid; -}; - -typedef int (*walk_memory_blocks_func_t)(struct memory_block *, void *); - -enum hugetlb_page_flags { - HPG_restore_reserve = 0, - HPG_migratable = 1, - HPG_temporary = 2, - HPG_freed = 3, - HPG_vmemmap_optimized = 4, - __NR_HPAGEFLAGS = 5, -}; - -struct madvise_walk_private { - struct mmu_gather *tlb; - bool pageout; -}; - -struct vma_swap_readahead { - short unsigned int win; - short unsigned int offset; - short unsigned int nr_pte; - pte_t *ptes; -}; - -enum { - PERCPU_REF_INIT_ATOMIC = 1, - PERCPU_REF_INIT_DEAD = 2, - PERCPU_REF_ALLOW_REINIT = 4, -}; - -union swap_header { - struct { - char reserved[4086]; - char magic[10]; - } magic; - struct { - char bootbits[1024]; - __u32 version; - __u32 last_page; - __u32 nr_badpages; - unsigned char sws_uuid[16]; - unsigned char sws_volume[16]; - __u32 padding[117]; - __u32 badpages[1]; - } info; -}; - -struct swap_extent { - struct rb_node rb_node; - long unsigned int start_page; - long unsigned int nr_pages; - sector_t start_block; -}; - -struct swap_slots_cache { - bool lock_initialized; - struct mutex alloc_lock; - swp_entry_t *slots; - int nr; - int cur; - spinlock_t free_lock; - swp_entry_t *slots_ret; - int n_ret; -}; - -struct frontswap_ops { - void (*init)(unsigned int); - int (*store)(unsigned int, long unsigned int, struct page *); - int (*load)(unsigned int, long unsigned int, struct page *); - void (*invalidate_page)(unsigned int, long unsigned int); - void (*invalidate_area)(unsigned int); - struct frontswap_ops *next; -}; - -struct crypto_async_request; - -typedef void (*crypto_completion_t)(struct crypto_async_request *, int); - -struct crypto_async_request { - struct list_head list; - crypto_completion_t complete; - void *data; - struct crypto_tfm *tfm; - u32 flags; -}; - -struct crypto_wait { - struct completion completion; - int err; -}; - -struct zpool; - -struct zpool_ops { - int (*evict)(struct zpool *, long unsigned int); -}; - -enum zpool_mapmode { - ZPOOL_MM_RW = 0, - ZPOOL_MM_RO = 1, - ZPOOL_MM_WO = 2, - ZPOOL_MM_DEFAULT = 0, -}; - -struct acomp_req { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int slen; - unsigned int dlen; - u32 flags; - void *__ctx[0]; -}; - -struct crypto_acomp { - int (*compress)(struct acomp_req *); - int (*decompress)(struct acomp_req *); - void (*dst_free)(struct scatterlist *); - unsigned int reqsize; - struct crypto_tfm base; -}; - -struct crypto_acomp_ctx { - struct crypto_acomp *acomp; - struct acomp_req *req; - struct crypto_wait wait; - u8 *dstmem; - struct mutex *mutex; -}; - -struct zswap_pool { - struct zpool *zpool; - struct crypto_acomp_ctx *acomp_ctx; - struct kref kref; - struct list_head list; - struct work_struct release_work; - struct work_struct shrink_work; - struct hlist_node node; - char tfm_name[128]; -}; - -struct zswap_entry { - struct rb_node rbnode; - long unsigned int offset; - int refcount; - unsigned int length; - struct zswap_pool *pool; - union { - long unsigned int handle; - long unsigned int value; - }; -}; - -struct zswap_header { - swp_entry_t swpentry; -}; - -struct zswap_tree { - struct rb_root rbroot; - spinlock_t lock; -}; - -enum zswap_get_swap_ret { - ZSWAP_SWAPCACHE_NEW = 0, - ZSWAP_SWAPCACHE_EXIST = 1, - ZSWAP_SWAPCACHE_FAIL = 2, -}; - -struct dma_pool { - struct list_head page_list; - spinlock_t lock; - size_t size; - struct device *dev; - size_t allocation; - size_t boundary; - char name[32]; - struct list_head pools; -}; - -struct dma_page { - struct list_head page_list; - void *vaddr; - dma_addr_t dma; - unsigned int in_use; - unsigned int offset; -}; - -enum string_size_units { - STRING_UNITS_10 = 0, - STRING_UNITS_2 = 1, -}; - -typedef void (*node_registration_func_t)(struct node___2 *); - -enum mcopy_atomic_mode { - MCOPY_ATOMIC_NORMAL = 0, - MCOPY_ATOMIC_ZEROPAGE = 1, - MCOPY_ATOMIC_CONTINUE = 2, -}; - -enum { - SUBPAGE_INDEX_SUBPOOL = 1, - SUBPAGE_INDEX_CGROUP = 2, - SUBPAGE_INDEX_CGROUP_RSVD = 3, - __MAX_CGROUP_SUBPAGE_INDEX = 3, - __NR_USED_SUBPAGE = 4, -}; - -struct resv_map { - struct kref refs; - spinlock_t lock; - struct list_head regions; - long int adds_in_progress; - struct list_head region_cache; - long int region_cache_count; - struct page_counter *reservation_counter; - long unsigned int pages_per_hpage; - struct cgroup_subsys_state *css; -}; - -struct file_region { - struct list_head link; - long int from; - long int to; - struct page_counter *reservation_counter; - struct cgroup_subsys_state *css; -}; - -struct huge_bootmem_page { - struct list_head list; - struct hstate *hstate; -}; - -enum hugetlb_memory_event { - HUGETLB_MAX = 0, - HUGETLB_NR_MEMORY_EVENTS = 1, -}; - -struct hugetlb_cgroup { - struct cgroup_subsys_state css; - struct page_counter hugepage[2]; - struct page_counter rsvd_hugepage[2]; - atomic_long_t events[2]; - atomic_long_t events_local[2]; - struct cgroup_file events_file[2]; - struct cgroup_file events_local_file[2]; -}; - -enum vma_resv_mode { - VMA_NEEDS_RESV = 0, - VMA_COMMIT_RESV = 1, - VMA_END_RESV = 2, - VMA_ADD_RESV = 3, - VMA_DEL_RESV = 4, -}; - -struct node_hstate { - struct kobject *hugepages_kobj; - struct kobject *hstate_kobjs[2]; -}; - -struct nodemask_scratch { - nodemask_t mask1; - nodemask_t mask2; -}; - -struct sp_node { - struct rb_node nd; - long unsigned int start; - long unsigned int end; - struct mempolicy *policy; -}; - -struct mempolicy_operations { - int (*create)(struct mempolicy *, const nodemask_t *); - void (*rebind)(struct mempolicy *, const nodemask_t *); -}; - -struct queue_pages { - struct list_head *pagelist; - long unsigned int flags; - nodemask_t *nmask; - long unsigned int start; - long unsigned int end; - struct vm_area_struct *first; -}; - -struct vmemmap_remap_walk { - void (*remap_pte)(pte_t *, long unsigned int, struct vmemmap_remap_walk *); - long unsigned int nr_walked; - struct page *reuse_page; - long unsigned int reuse_addr; - struct list_head *vmemmap_pages; -}; - -struct mmu_notifier_subscriptions { - struct hlist_head list; - bool has_itree; - spinlock_t lock; - long unsigned int invalidate_seq; - long unsigned int active_invalidate_ranges; - struct rb_root_cached itree; - wait_queue_head_t wq; - struct hlist_head deferred_list; -}; - -struct interval_tree_node { - struct rb_node rb; - long unsigned int start; - long unsigned int last; - long unsigned int __subtree_last; -}; - -struct mmu_interval_notifier; - -struct mmu_interval_notifier_ops { - bool (*invalidate)(struct mmu_interval_notifier *, const struct mmu_notifier_range *, long unsigned int); -}; - -struct mmu_interval_notifier { - struct interval_tree_node interval_tree; - const struct mmu_interval_notifier_ops *ops; - struct mm_struct *mm; - struct hlist_node deferred_item; - long unsigned int invalidate_seq; -}; - -struct rmap_item; - -struct mm_slot { - struct hlist_node link; - struct list_head mm_list; - struct rmap_item *rmap_list; - struct mm_struct *mm; -}; - -struct stable_node; - -struct rmap_item { - struct rmap_item *rmap_list; - union { - struct anon_vma *anon_vma; - int nid; - }; - struct mm_struct *mm; - long unsigned int address; - unsigned int oldchecksum; - union { - struct rb_node node; - struct { - struct stable_node *head; - struct hlist_node hlist; - }; - }; -}; - -struct ksm_scan { - struct mm_slot *mm_slot; - long unsigned int address; - struct rmap_item **rmap_list; - long unsigned int seqnr; -}; - -struct stable_node { - union { - struct rb_node node; - struct { - struct list_head *head; - struct { - struct hlist_node hlist_dup; - struct list_head list; - }; - }; - }; - struct hlist_head hlist; - union { - long unsigned int kpfn; - long unsigned int chain_prune_time; - }; - int rmap_hlist_len; - int nid; -}; - -enum get_ksm_page_flags { - GET_KSM_PAGE_NOLOCK = 0, - GET_KSM_PAGE_LOCK = 1, - GET_KSM_PAGE_TRYLOCK = 2, -}; - -enum stat_item { - ALLOC_FASTPATH = 0, - ALLOC_SLOWPATH = 1, - FREE_FASTPATH = 2, - FREE_SLOWPATH = 3, - FREE_FROZEN = 4, - FREE_ADD_PARTIAL = 5, - FREE_REMOVE_PARTIAL = 6, - ALLOC_FROM_PARTIAL = 7, - ALLOC_SLAB = 8, - ALLOC_REFILL = 9, - ALLOC_NODE_MISMATCH = 10, - FREE_SLAB = 11, - CPUSLAB_FLUSH = 12, - DEACTIVATE_FULL = 13, - DEACTIVATE_EMPTY = 14, - DEACTIVATE_TO_HEAD = 15, - DEACTIVATE_TO_TAIL = 16, - DEACTIVATE_REMOTE_FREES = 17, - DEACTIVATE_BYPASS = 18, - ORDER_FALLBACK = 19, - CMPXCHG_DOUBLE_CPU_FAIL = 20, - CMPXCHG_DOUBLE_FAIL = 21, - CPU_PARTIAL_ALLOC = 22, - CPU_PARTIAL_FREE = 23, - CPU_PARTIAL_NODE = 24, - CPU_PARTIAL_DRAIN = 25, - NR_SLUB_STAT_ITEMS = 26, -}; - -struct track { - long unsigned int addr; - long unsigned int addrs[16]; - int cpu; - int pid; - long unsigned int when; -}; - -enum track_item { - TRACK_ALLOC = 0, - TRACK_FREE = 1, -}; - -struct detached_freelist { - struct page *page; - void *tail; - void *freelist; - int cnt; - struct kmem_cache *s; -}; - -struct location { - long unsigned int count; - long unsigned int addr; - long long int sum_time; - long int min_time; - long int max_time; - long int min_pid; - long int max_pid; - long unsigned int cpus[5]; - nodemask_t nodes; -}; - -struct loc_track { - long unsigned int max; - long unsigned int count; - struct location *loc; -}; - -enum slab_stat_type { - SL_ALL = 0, - SL_PARTIAL = 1, - SL_CPU = 2, - SL_OBJECTS = 3, - SL_TOTAL = 4, -}; - -struct slab_attribute { - struct attribute attr; - ssize_t (*show)(struct kmem_cache *, char *); - ssize_t (*store)(struct kmem_cache *, const char *, size_t); -}; - -struct saved_alias { - struct kmem_cache *s; - const char *name; - struct saved_alias *next; -}; - -enum slab_modes { - M_NONE = 0, - M_PARTIAL = 1, - M_FULL = 2, - M_FREE = 3, -}; - -struct kcsan_scoped_access {}; - -enum kfence_object_state { - KFENCE_OBJECT_UNUSED = 0, - KFENCE_OBJECT_ALLOCATED = 1, - KFENCE_OBJECT_FREED = 2, -}; - -struct kfence_track { - pid_t pid; - int num_stack_entries; - long unsigned int stack_entries[64]; -}; - -struct kfence_metadata { - struct list_head list; - struct callback_head callback_head; - raw_spinlock_t lock; - enum kfence_object_state state; - long unsigned int addr; - size_t size; - struct kmem_cache *cache; - long unsigned int unprotected_page; - struct kfence_track alloc_track; - struct kfence_track free_track; -}; - -enum kfence_error_type { - KFENCE_ERROR_OOB = 0, - KFENCE_ERROR_UAF = 1, - KFENCE_ERROR_CORRUPTION = 2, - KFENCE_ERROR_INVALID = 3, - KFENCE_ERROR_INVALID_FREE = 4, -}; - -enum kfence_counter_id { - KFENCE_COUNTER_ALLOCATED = 0, - KFENCE_COUNTER_ALLOCS = 1, - KFENCE_COUNTER_FREES = 2, - KFENCE_COUNTER_ZOMBIES = 3, - KFENCE_COUNTER_BUGS = 4, - KFENCE_COUNTER_COUNT = 5, -}; - -typedef __kernel_long_t __kernel_ptrdiff_t; - -typedef __kernel_ptrdiff_t ptrdiff_t; - -struct buffer_head; - -typedef void bh_end_io_t(struct buffer_head *, int); - -struct buffer_head { - long unsigned int b_state; - struct buffer_head *b_this_page; - struct page *b_page; - sector_t b_blocknr; - size_t b_size; - char *b_data; - struct block_device *b_bdev; - bh_end_io_t *b_end_io; - void *b_private; - struct list_head b_assoc_buffers; - struct address_space *b_assoc_map; - atomic_t b_count; - spinlock_t b_uptodate_lock; -}; - -enum migrate_vma_direction { - MIGRATE_VMA_SELECT_SYSTEM = 1, - MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 2, -}; - -struct migrate_vma { - struct vm_area_struct *vma; - long unsigned int *dst; - long unsigned int *src; - long unsigned int cpages; - long unsigned int npages; - long unsigned int start; - long unsigned int end; - void *pgmap_owner; - long unsigned int flags; -}; - -enum bh_state_bits { - BH_Uptodate = 0, - BH_Dirty = 1, - BH_Lock = 2, - BH_Req = 3, - BH_Mapped = 4, - BH_New = 5, - BH_Async_Read = 6, - BH_Async_Write = 7, - BH_Delay = 8, - BH_Boundary = 9, - BH_Write_EIO = 10, - BH_Unwritten = 11, - BH_Quiet = 12, - BH_Meta = 13, - BH_Prio = 14, - BH_Defer_Completion = 15, - BH_PrivateStart = 16, -}; - -struct trace_event_raw_mm_migrate_pages { - struct trace_entry ent; - long unsigned int succeeded; - long unsigned int failed; - long unsigned int thp_succeeded; - long unsigned int thp_failed; - long unsigned int thp_split; - enum migrate_mode mode; - int reason; - char __data[0]; -}; - -struct trace_event_raw_mm_migrate_pages_start { - struct trace_entry ent; - enum migrate_mode mode; - int reason; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_migrate_pages {}; - -struct trace_event_data_offsets_mm_migrate_pages_start {}; - -typedef void (*btf_trace_mm_migrate_pages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, enum migrate_mode, int); - -typedef void (*btf_trace_mm_migrate_pages_start)(void *, enum migrate_mode, int); - -enum scan_result { - SCAN_FAIL = 0, - SCAN_SUCCEED = 1, - SCAN_PMD_NULL = 2, - SCAN_EXCEED_NONE_PTE = 3, - SCAN_EXCEED_SWAP_PTE = 4, - SCAN_EXCEED_SHARED_PTE = 5, - SCAN_PTE_NON_PRESENT = 6, - SCAN_PTE_UFFD_WP = 7, - SCAN_PAGE_RO = 8, - SCAN_LACK_REFERENCED_PAGE = 9, - SCAN_PAGE_NULL = 10, - SCAN_SCAN_ABORT = 11, - SCAN_PAGE_COUNT = 12, - SCAN_PAGE_LRU = 13, - SCAN_PAGE_LOCK = 14, - SCAN_PAGE_ANON = 15, - SCAN_PAGE_COMPOUND = 16, - SCAN_ANY_PROCESS = 17, - SCAN_VMA_NULL = 18, - SCAN_VMA_CHECK = 19, - SCAN_ADDRESS_RANGE = 20, - SCAN_SWAP_CACHE_PAGE = 21, - SCAN_DEL_PAGE_LRU = 22, - SCAN_ALLOC_HUGE_PAGE_FAIL = 23, - SCAN_CGROUP_CHARGE_FAIL = 24, - SCAN_TRUNCATED = 25, - SCAN_PAGE_HAS_PRIVATE = 26, -}; - -struct trace_event_raw_mm_khugepaged_scan_pmd { - struct trace_entry ent; - struct mm_struct *mm; - long unsigned int pfn; - bool writable; - int referenced; - int none_or_zero; - int status; - int unmapped; - char __data[0]; -}; - -struct trace_event_raw_mm_collapse_huge_page { - struct trace_entry ent; - struct mm_struct *mm; - int isolated; - int status; - char __data[0]; -}; - -struct trace_event_raw_mm_collapse_huge_page_isolate { - struct trace_entry ent; - long unsigned int pfn; - int none_or_zero; - int referenced; - bool writable; - int status; - char __data[0]; -}; - -struct trace_event_raw_mm_collapse_huge_page_swapin { - struct trace_entry ent; - struct mm_struct *mm; - int swapped_in; - int referenced; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_mm_khugepaged_scan_pmd {}; - -struct trace_event_data_offsets_mm_collapse_huge_page {}; - -struct trace_event_data_offsets_mm_collapse_huge_page_isolate {}; - -struct trace_event_data_offsets_mm_collapse_huge_page_swapin {}; - -typedef void (*btf_trace_mm_khugepaged_scan_pmd)(void *, struct mm_struct *, struct page *, bool, int, int, int, int); - -typedef void (*btf_trace_mm_collapse_huge_page)(void *, struct mm_struct *, int, int); - -typedef void (*btf_trace_mm_collapse_huge_page_isolate)(void *, struct page *, int, int, bool, int); - -typedef void (*btf_trace_mm_collapse_huge_page_swapin)(void *, struct mm_struct *, int, int, int); - -struct mm_slot___2 { - struct hlist_node hash; - struct list_head mm_node; - struct mm_struct *mm; - int nr_pte_mapped_thp; - long unsigned int pte_mapped_thp[8]; -}; - -struct khugepaged_scan { - struct list_head mm_head; - struct mm_slot___2 *mm_slot; - long unsigned int address; -}; - -struct mem_cgroup_tree_per_node { - struct rb_root rb_root; - struct rb_node *rb_rightmost; - spinlock_t lock; -}; - -struct mem_cgroup_tree { - struct mem_cgroup_tree_per_node *rb_tree_per_node[32]; -}; - -struct mem_cgroup_eventfd_list { - struct list_head list; - struct eventfd_ctx *eventfd; -}; - -struct mem_cgroup_event { - struct mem_cgroup *memcg; - struct eventfd_ctx *eventfd; - struct list_head list; - int (*register_event)(struct mem_cgroup *, struct eventfd_ctx *, const char *); - void (*unregister_event)(struct mem_cgroup *, struct eventfd_ctx *); - poll_table pt; - wait_queue_head_t *wqh; - wait_queue_entry_t wait; - struct work_struct remove; -}; - -struct move_charge_struct { - spinlock_t lock; - struct mm_struct *mm; - struct mem_cgroup *from; - struct mem_cgroup *to; - long unsigned int flags; - long unsigned int precharge; - long unsigned int moved_charge; - long unsigned int moved_swap; - struct task_struct *moving_task; - wait_queue_head_t waitq; -}; - -enum res_type { - _MEM = 0, - _MEMSWAP = 1, - _OOM_TYPE = 2, - _KMEM = 3, - _TCP = 4, -}; - -struct memory_stat { - const char *name; - unsigned int idx; -}; - -struct oom_wait_info { - struct mem_cgroup *memcg; - wait_queue_entry_t wait; -}; - -enum oom_status { - OOM_SUCCESS = 0, - OOM_FAILED = 1, - OOM_ASYNC = 2, - OOM_SKIPPED = 3, -}; - -struct obj_stock { - struct obj_cgroup *cached_objcg; - struct pglist_data *cached_pgdat; - unsigned int nr_bytes; - int nr_slab_reclaimable_b; - int nr_slab_unreclaimable_b; -}; - -struct memcg_stock_pcp { - struct mem_cgroup *cached; - unsigned int nr_pages; - struct obj_stock task_obj; - struct obj_stock irq_obj; - struct work_struct work; - long unsigned int flags; -}; - -enum { - RES_USAGE = 0, - RES_LIMIT = 1, - RES_MAX_USAGE = 2, - RES_FAILCNT = 3, - RES_SOFT_LIMIT = 4, -}; - -union mc_target { - struct page *page; - swp_entry_t ent; -}; - -enum mc_target_type { - MC_TARGET_NONE = 0, - MC_TARGET_PAGE = 1, - MC_TARGET_SWAP = 2, - MC_TARGET_DEVICE = 3, -}; - -struct uncharge_gather { - struct mem_cgroup *memcg; - long unsigned int nr_memory; - long unsigned int pgpgout; - long unsigned int nr_kmem; - struct page *dummy_page; -}; - -struct numa_stat { - const char *name; - unsigned int lru_mask; -}; - -enum vmpressure_levels { - VMPRESSURE_LOW = 0, - VMPRESSURE_MEDIUM = 1, - VMPRESSURE_CRITICAL = 2, - VMPRESSURE_NUM_LEVELS = 3, -}; - -enum vmpressure_modes { - VMPRESSURE_NO_PASSTHROUGH = 0, - VMPRESSURE_HIERARCHY = 1, - VMPRESSURE_LOCAL = 2, - VMPRESSURE_NUM_MODES = 3, -}; - -struct vmpressure_event { - struct eventfd_ctx *efd; - enum vmpressure_levels level; - enum vmpressure_modes mode; - struct list_head node; -}; - -struct swap_cgroup_ctrl { - struct page **map; - long unsigned int length; - spinlock_t lock; -}; - -struct swap_cgroup { - short unsigned int id; -}; - -enum { - RES_USAGE___2 = 0, - RES_RSVD_USAGE = 1, - RES_LIMIT___2 = 2, - RES_RSVD_LIMIT = 3, - RES_MAX_USAGE___2 = 4, - RES_RSVD_MAX_USAGE = 5, - RES_FAILCNT___2 = 6, - RES_RSVD_FAILCNT = 7, -}; - -enum mf_result { - MF_IGNORED = 0, - MF_FAILED = 1, - MF_DELAYED = 2, - MF_RECOVERED = 3, -}; - -enum mf_action_page_type { - MF_MSG_KERNEL = 0, - MF_MSG_KERNEL_HIGH_ORDER = 1, - MF_MSG_SLAB = 2, - MF_MSG_DIFFERENT_COMPOUND = 3, - MF_MSG_POISONED_HUGE = 4, - MF_MSG_HUGE = 5, - MF_MSG_FREE_HUGE = 6, - MF_MSG_NON_PMD_HUGE = 7, - MF_MSG_UNMAP_FAILED = 8, - MF_MSG_DIRTY_SWAPCACHE = 9, - MF_MSG_CLEAN_SWAPCACHE = 10, - MF_MSG_DIRTY_MLOCKED_LRU = 11, - MF_MSG_CLEAN_MLOCKED_LRU = 12, - MF_MSG_DIRTY_UNEVICTABLE_LRU = 13, - MF_MSG_CLEAN_UNEVICTABLE_LRU = 14, - MF_MSG_DIRTY_LRU = 15, - MF_MSG_CLEAN_LRU = 16, - MF_MSG_TRUNCATED_LRU = 17, - MF_MSG_BUDDY = 18, - MF_MSG_BUDDY_2ND = 19, - MF_MSG_DAX = 20, - MF_MSG_UNSPLIT_THP = 21, - MF_MSG_UNKNOWN = 22, -}; - -typedef long unsigned int dax_entry_t; - -struct __kfifo { - unsigned int in; - unsigned int out; - unsigned int mask; - unsigned int esize; - void *data; -}; - -struct to_kill { - struct list_head nd; - struct task_struct *tsk; - long unsigned int addr; - short int size_shift; -}; - -struct hwp_walk { - struct to_kill tk; - long unsigned int pfn; - int flags; -}; - -struct page_state { - long unsigned int mask; - long unsigned int res; - enum mf_action_page_type type; - int (*action)(struct page *, long unsigned int); -}; - -struct memory_failure_entry { - long unsigned int pfn; - int flags; -}; - -struct memory_failure_cpu { - struct { - union { - struct __kfifo kfifo; - struct memory_failure_entry *type; - const struct memory_failure_entry *const_type; - char (*rectype)[0]; - struct memory_failure_entry *ptr; - const struct memory_failure_entry *ptr_const; - }; - struct memory_failure_entry buf[16]; - } fifo; - spinlock_t lock; - struct work_struct work; -}; - -struct cleancache_filekey { - union { - ino_t ino; - __u32 fh[6]; - u32 key[6]; - } u; -}; - -struct cleancache_ops { - int (*init_fs)(size_t); - int (*init_shared_fs)(uuid_t *, size_t); - int (*get_page)(int, struct cleancache_filekey, long unsigned int, struct page *); - void (*put_page)(int, struct cleancache_filekey, long unsigned int, struct page *); - void (*invalidate_page)(int, struct cleancache_filekey, long unsigned int); - void (*invalidate_inode)(int, struct cleancache_filekey); - void (*invalidate_fs)(int); -}; - -struct trace_event_raw_test_pages_isolated { - struct trace_entry ent; - long unsigned int start_pfn; - long unsigned int end_pfn; - long unsigned int fin_pfn; - char __data[0]; -}; - -struct trace_event_data_offsets_test_pages_isolated {}; - -typedef void (*btf_trace_test_pages_isolated)(void *, long unsigned int, long unsigned int, long unsigned int); - -struct zpool_driver; - -struct zpool { - struct zpool_driver *driver; - void *pool; - const struct zpool_ops *ops; - bool evictable; - bool can_sleep_mapped; - struct list_head list; -}; - -struct zpool_driver { - char *type; - struct module *owner; - atomic_t refcount; - struct list_head list; - void * (*create)(const char *, gfp_t, const struct zpool_ops *, struct zpool *); - void (*destroy)(void *); - bool malloc_support_movable; - int (*malloc)(void *, size_t, gfp_t, long unsigned int *); - void (*free)(void *, long unsigned int); - int (*shrink)(void *, unsigned int, unsigned int *); - bool sleep_mapped; - void * (*map)(void *, long unsigned int, enum zpool_mapmode); - void (*unmap)(void *, long unsigned int); - u64 (*total_size)(void *); -}; - -struct zbud_pool; - -struct zbud_ops { - int (*evict)(struct zbud_pool *, long unsigned int); -}; - -struct zbud_pool { - spinlock_t lock; - union { - struct list_head buddied; - struct list_head unbuddied[63]; - }; - struct list_head lru; - u64 pages_nr; - const struct zbud_ops *ops; - struct zpool *zpool; - const struct zpool_ops *zpool_ops; -}; - -struct zbud_header { - struct list_head buddy; - struct list_head lru; - unsigned int first_chunks; - unsigned int last_chunks; - bool under_reclaim; -}; - -enum buddy { - FIRST = 0, - LAST = 1, -}; - -enum zs_mapmode { - ZS_MM_RW = 0, - ZS_MM_RO = 1, - ZS_MM_WO = 2, -}; - -struct zs_pool_stats { - atomic_long_t pages_compacted; -}; - -enum fullness_group { - ZS_EMPTY = 0, - ZS_ALMOST_EMPTY = 1, - ZS_ALMOST_FULL = 2, - ZS_FULL = 3, - NR_ZS_FULLNESS = 4, -}; - -enum zs_stat_type { - CLASS_EMPTY = 0, - CLASS_ALMOST_EMPTY = 1, - CLASS_ALMOST_FULL = 2, - CLASS_FULL = 3, - OBJ_ALLOCATED = 4, - OBJ_USED = 5, - NR_ZS_STAT_TYPE = 6, -}; - -struct zs_size_stat { - long unsigned int objs[6]; -}; - -struct size_class { - spinlock_t lock; - struct list_head fullness_list[4]; - int size; - int objs_per_zspage; - int pages_per_zspage; - unsigned int index; - struct zs_size_stat stats; -}; - -struct link_free { - union { - long unsigned int next; - long unsigned int handle; - }; -}; - -struct zs_pool { - const char *name; - struct size_class *size_class[255]; - struct kmem_cache *handle_cachep; - struct kmem_cache *zspage_cachep; - atomic_long_t pages_allocated; - struct zs_pool_stats stats; - struct shrinker shrinker; - struct inode *inode; - struct work_struct free_work; - struct wait_queue_head migration_wait; - atomic_long_t isolated_pages; - bool destroying; -}; - -struct zspage { - struct { - unsigned int fullness: 2; - unsigned int class: 9; - unsigned int isolated: 3; - unsigned int magic: 8; - }; - unsigned int inuse; - unsigned int freeobj; - struct page *first_page; - struct list_head list; - rwlock_t lock; -}; - -struct mapping_area { - char *vm_buf; - char *vm_addr; - enum zs_mapmode vm_mm; -}; - -struct zs_compact_control { - struct page *s_page; - struct page *d_page; - int obj_idx; -}; - -struct z3fold_pool; - -struct z3fold_ops { - int (*evict)(struct z3fold_pool *, long unsigned int); -}; - -struct z3fold_pool { - const char *name; - spinlock_t lock; - spinlock_t stale_lock; - struct list_head *unbuddied; - struct list_head lru; - struct list_head stale; - atomic64_t pages_nr; - struct kmem_cache *c_handle; - const struct z3fold_ops *ops; - struct zpool *zpool; - const struct zpool_ops *zpool_ops; - struct workqueue_struct *compact_wq; - struct workqueue_struct *release_wq; - struct work_struct work; - struct inode *inode; -}; - -enum buddy___2 { - HEADLESS = 0, - FIRST___2 = 1, - MIDDLE = 2, - LAST___2 = 3, - BUDDIES_MAX = 3, -}; - -struct z3fold_buddy_slots { - long unsigned int slot[4]; - long unsigned int pool; - rwlock_t lock; -}; - -struct z3fold_header { - struct list_head buddy; - spinlock_t page_lock; - struct kref refcount; - struct work_struct work; - struct z3fold_buddy_slots *slots; - struct z3fold_pool *pool; - short int cpu; - short unsigned int first_chunks; - short unsigned int middle_chunks; - short unsigned int last_chunks; - short unsigned int start_middle; - short unsigned int first_num: 2; - short unsigned int mapped_count: 2; - short unsigned int foreign_handles: 2; -}; - -enum z3fold_page_flags { - PAGE_HEADLESS = 0, - MIDDLE_CHUNK_MAPPED = 1, - NEEDS_COMPACTING = 2, - PAGE_STALE = 3, - PAGE_CLAIMED = 4, -}; - -enum z3fold_handle_flags { - HANDLES_NOFREE = 0, -}; - -struct trace_event_raw_cma_alloc_class { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int pfn; - const struct page *page; - long unsigned int count; - unsigned int align; - char __data[0]; -}; - -struct trace_event_raw_cma_release { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int pfn; - const struct page *page; - long unsigned int count; - char __data[0]; -}; - -struct trace_event_raw_cma_alloc_start { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int count; - unsigned int align; - char __data[0]; -}; - -struct trace_event_data_offsets_cma_alloc_class { - u32 name; -}; - -struct trace_event_data_offsets_cma_release { - u32 name; -}; - -struct trace_event_data_offsets_cma_alloc_start { - u32 name; -}; - -typedef void (*btf_trace_cma_release)(void *, const char *, long unsigned int, const struct page *, long unsigned int); - -typedef void (*btf_trace_cma_alloc_start)(void *, const char *, long unsigned int, unsigned int); - -typedef void (*btf_trace_cma_alloc_finish)(void *, const char *, long unsigned int, const struct page *, long unsigned int, unsigned int); - -typedef void (*btf_trace_cma_alloc_busy_retry)(void *, const char *, long unsigned int, const struct page *, long unsigned int, unsigned int); - -struct cma_kobject { - struct kobject kobj; - struct cma *cma; -}; - -struct balloon_dev_info { - long unsigned int isolated_pages; - spinlock_t pages_lock; - struct list_head pages; - int (*migratepage)(struct balloon_dev_info *, struct page *, struct page *, enum migrate_mode); - struct inode *inode; -}; - -struct cma_mem { - struct hlist_node node; - struct page *p; - long unsigned int n; -}; - -enum { - BAD_STACK = 4294967295, - NOT_STACK = 0, - GOOD_FRAME = 1, - GOOD_STACK = 2, -}; - -enum hmm_pfn_flags { - HMM_PFN_VALID = 0, - HMM_PFN_WRITE = 0, - HMM_PFN_ERROR = 0, - HMM_PFN_ORDER_SHIFT = 56, - HMM_PFN_REQ_FAULT = 0, - HMM_PFN_REQ_WRITE = 0, - HMM_PFN_FLAGS = 0, -}; - -struct hmm_range { - struct mmu_interval_notifier *notifier; - long unsigned int notifier_seq; - long unsigned int start; - long unsigned int end; - long unsigned int *hmm_pfns; - long unsigned int default_flags; - long unsigned int pfn_flags_mask; - void *dev_private_owner; -}; - -struct hmm_vma_walk { - struct hmm_range *range; - long unsigned int last; -}; - -enum { - HMM_NEED_FAULT = 1, - HMM_NEED_WRITE_FAULT = 2, - HMM_NEED_ALL_BITS = 3, -}; - -struct hugetlbfs_inode_info { - struct shared_policy policy; - struct inode vfs_inode; - unsigned int seals; -}; - -struct wp_walk { - struct mmu_notifier_range range; - long unsigned int tlbflush_start; - long unsigned int tlbflush_end; - long unsigned int total; -}; - -struct clean_walk { - struct wp_walk base; - long unsigned int bitmap_pgoff; - long unsigned int *bitmap; - long unsigned int start; - long unsigned int end; -}; - -struct page_reporting_dev_info { - int (*report)(struct page_reporting_dev_info *, struct scatterlist *, unsigned int); - struct delayed_work work; - atomic_t state; - unsigned int order; -}; - -enum { - PAGE_REPORTING_IDLE = 0, - PAGE_REPORTING_REQUESTED = 1, - PAGE_REPORTING_ACTIVE = 2, -}; - -struct open_how { - __u64 flags; - __u64 mode; - __u64 resolve; -}; - -typedef s32 compat_off_t; - -struct open_flags { - int open_flag; - umode_t mode; - int acc_mode; - int intent; - int lookup_flags; -}; - -typedef __kernel_long_t __kernel_off_t; - -typedef __kernel_off_t off_t; - -typedef __kernel_rwf_t rwf_t; - -struct fscrypt_policy_v1 { - __u8 version; - __u8 contents_encryption_mode; - __u8 filenames_encryption_mode; - __u8 flags; - __u8 master_key_descriptor[8]; -}; - -struct fscrypt_policy_v2 { - __u8 version; - __u8 contents_encryption_mode; - __u8 filenames_encryption_mode; - __u8 flags; - __u8 __reserved[4]; - __u8 master_key_identifier[16]; -}; - -union fscrypt_policy { - u8 version; - struct fscrypt_policy_v1 v1; - struct fscrypt_policy_v2 v2; -}; - -enum vfs_get_super_keying { - vfs_get_single_super = 0, - vfs_get_single_reconf_super = 1, - vfs_get_keyed_super = 2, - vfs_get_independent_super = 3, -}; - -typedef struct kobject *kobj_probe_t(dev_t, int *, void *); - -struct kobj_map; - -struct char_device_struct { - struct char_device_struct *next; - unsigned int major; - unsigned int baseminor; - int minorct; - char name[64]; - struct cdev *cdev; -}; - -struct stat { - __kernel_ulong_t st_dev; - __kernel_ulong_t st_ino; - __kernel_ulong_t st_nlink; - unsigned int st_mode; - unsigned int st_uid; - unsigned int st_gid; - unsigned int __pad0; - __kernel_ulong_t st_rdev; - __kernel_long_t st_size; - __kernel_long_t st_blksize; - __kernel_long_t st_blocks; - __kernel_ulong_t st_atime; - __kernel_ulong_t st_atime_nsec; - __kernel_ulong_t st_mtime; - __kernel_ulong_t st_mtime_nsec; - __kernel_ulong_t st_ctime; - __kernel_ulong_t st_ctime_nsec; - __kernel_long_t __unused[3]; -}; - -struct __old_kernel_stat { - short unsigned int st_dev; - short unsigned int st_ino; - short unsigned int st_mode; - short unsigned int st_nlink; - short unsigned int st_uid; - short unsigned int st_gid; - short unsigned int st_rdev; - unsigned int st_size; - unsigned int st_atime; - unsigned int st_mtime; - unsigned int st_ctime; -}; - -struct statx_timestamp { - __s64 tv_sec; - __u32 tv_nsec; - __s32 __reserved; -}; - -struct statx { - __u32 stx_mask; - __u32 stx_blksize; - __u64 stx_attributes; - __u32 stx_nlink; - __u32 stx_uid; - __u32 stx_gid; - __u16 stx_mode; - __u16 __spare0[1]; - __u64 stx_ino; - __u64 stx_size; - __u64 stx_blocks; - __u64 stx_attributes_mask; - struct statx_timestamp stx_atime; - struct statx_timestamp stx_btime; - struct statx_timestamp stx_ctime; - struct statx_timestamp stx_mtime; - __u32 stx_rdev_major; - __u32 stx_rdev_minor; - __u32 stx_dev_major; - __u32 stx_dev_minor; - __u64 stx_mnt_id; - __u64 __spare2; - __u64 __spare3[12]; -}; - -struct mount; - -struct mnt_namespace { - struct ns_common ns; - struct mount *root; - struct list_head list; - spinlock_t ns_lock; - struct user_namespace *user_ns; - struct ucounts *ucounts; - u64 seq; - wait_queue_head_t poll; - u64 event; - unsigned int mounts; - unsigned int pending_mounts; -}; - -typedef u32 compat_ino_t; - -typedef u16 __compat_uid_t; - -typedef u16 __compat_gid_t; - -typedef u16 compat_mode_t; - -typedef u16 compat_dev_t; - -typedef u16 compat_nlink_t; - -struct compat_stat { - compat_dev_t st_dev; - u16 __pad1; - compat_ino_t st_ino; - compat_mode_t st_mode; - compat_nlink_t st_nlink; - __compat_uid_t st_uid; - __compat_gid_t st_gid; - compat_dev_t st_rdev; - u16 __pad2; - u32 st_size; - u32 st_blksize; - u32 st_blocks; - u32 st_atime; - u32 st_atime_nsec; - u32 st_mtime; - u32 st_mtime_nsec; - u32 st_ctime; - u32 st_ctime_nsec; - u32 __unused4; - u32 __unused5; -}; - -struct mnt_pcp; - -struct mountpoint; - -struct mount { - struct hlist_node mnt_hash; - struct mount *mnt_parent; - struct dentry *mnt_mountpoint; - struct vfsmount mnt; - union { - struct callback_head mnt_rcu; - struct llist_node mnt_llist; - }; - struct mnt_pcp *mnt_pcp; - struct list_head mnt_mounts; - struct list_head mnt_child; - struct list_head mnt_instance; - const char *mnt_devname; - struct list_head mnt_list; - struct list_head mnt_expire; - struct list_head mnt_share; - struct list_head mnt_slave_list; - struct list_head mnt_slave; - struct mount *mnt_master; - struct mnt_namespace *mnt_ns; - struct mountpoint *mnt_mp; - union { - struct hlist_node mnt_mp_list; - struct hlist_node mnt_umount; - }; - struct list_head mnt_umounting; - struct fsnotify_mark_connector *mnt_fsnotify_marks; - __u32 mnt_fsnotify_mask; - int mnt_id; - int mnt_group_id; - int mnt_expiry_mark; - struct hlist_head mnt_pins; - struct hlist_head mnt_stuck_children; -}; - -struct mnt_pcp { - int mnt_count; - int mnt_writers; -}; - -struct mountpoint { - struct hlist_node m_hash; - struct dentry *m_dentry; - struct hlist_head m_list; - int m_count; -}; - -typedef short unsigned int ushort; - -struct user_arg_ptr { - bool is_compat; - union { - const char * const *native; - const compat_uptr_t *compat; - } ptr; -}; - -enum inode_i_mutex_lock_class { - I_MUTEX_NORMAL = 0, - I_MUTEX_PARENT = 1, - I_MUTEX_CHILD = 2, - I_MUTEX_XATTR = 3, - I_MUTEX_NONDIR2 = 4, - I_MUTEX_PARENT2 = 5, -}; - -struct name_snapshot { - struct qstr name; - unsigned char inline_name[32]; -}; - -struct saved { - struct path link; - struct delayed_call done; - const char *name; - unsigned int seq; -}; - -struct nameidata { - struct path path; - struct qstr last; - struct path root; - struct inode *inode; - unsigned int flags; - unsigned int state; - unsigned int seq; - unsigned int m_seq; - unsigned int r_seq; - int last_type; - unsigned int depth; - int total_link_count; - struct saved *stack; - struct saved internal[2]; - struct filename *name; - struct nameidata *saved; - unsigned int root_seq; - int dfd; - kuid_t dir_uid; - umode_t dir_mode; -}; - -struct renamedata { - struct user_namespace *old_mnt_userns; - struct inode *old_dir; - struct dentry *old_dentry; - struct user_namespace *new_mnt_userns; - struct inode *new_dir; - struct dentry *new_dentry; - struct inode **delegated_inode; - unsigned int flags; -}; - -enum { - LAST_NORM = 0, - LAST_ROOT = 1, - LAST_DOT = 2, - LAST_DOTDOT = 3, -}; - -enum { - WALK_TRAILING = 1, - WALK_MORE = 2, - WALK_NOFOLLOW = 4, -}; - -struct word_at_a_time { - const long unsigned int one_bits; - const long unsigned int high_bits; -}; - -struct f_owner_ex { - int type; - __kernel_pid_t pid; -}; - -struct flock { - short int l_type; - short int l_whence; - __kernel_off_t l_start; - __kernel_off_t l_len; - __kernel_pid_t l_pid; -}; - -struct compat_flock { - short int l_type; - short int l_whence; - compat_off_t l_start; - compat_off_t l_len; - compat_pid_t l_pid; -}; - -struct compat_flock64 { - short int l_type; - short int l_whence; - compat_loff_t l_start; - compat_loff_t l_len; - compat_pid_t l_pid; -} __attribute__((packed)); - -struct file_clone_range { - __s64 src_fd; - __u64 src_offset; - __u64 src_length; - __u64 dest_offset; -}; - -struct file_dedupe_range_info { - __s64 dest_fd; - __u64 dest_offset; - __u64 bytes_deduped; - __s32 status; - __u32 reserved; -}; - -struct file_dedupe_range { - __u64 src_offset; - __u64 src_length; - __u16 dest_count; - __u16 reserved1; - __u32 reserved2; - struct file_dedupe_range_info info[0]; -}; - -struct fsxattr { - __u32 fsx_xflags; - __u32 fsx_extsize; - __u32 fsx_nextents; - __u32 fsx_projid; - __u32 fsx_cowextsize; - unsigned char fsx_pad[8]; -}; - -typedef int get_block_t(struct inode *, sector_t, struct buffer_head *, int); - -struct fiemap_extent; - -struct fiemap_extent_info { - unsigned int fi_flags; - unsigned int fi_extents_mapped; - unsigned int fi_extents_max; - struct fiemap_extent *fi_extents_start; -}; - -struct fileattr { - u32 flags; - u32 fsx_xflags; - u32 fsx_extsize; - u32 fsx_nextents; - u32 fsx_projid; - u32 fsx_cowextsize; - bool flags_valid: 1; - bool fsx_valid: 1; -}; - -struct space_resv { - __s16 l_type; - __s16 l_whence; - __s64 l_start; - __s64 l_len; - __s32 l_sysid; - __u32 l_pid; - __s32 l_pad[4]; -}; - -struct space_resv_32 { - __s16 l_type; - __s16 l_whence; - __s64 l_start; - __s64 l_len; - __s32 l_sysid; - __u32 l_pid; - __s32 l_pad[4]; -} __attribute__((packed)); - -struct fiemap_extent { - __u64 fe_logical; - __u64 fe_physical; - __u64 fe_length; - __u64 fe_reserved64[2]; - __u32 fe_flags; - __u32 fe_reserved[3]; -}; - -struct fiemap { - __u64 fm_start; - __u64 fm_length; - __u32 fm_flags; - __u32 fm_mapped_extents; - __u32 fm_extent_count; - __u32 fm_reserved; - struct fiemap_extent fm_extents[0]; -}; - -struct linux_dirent64 { - u64 d_ino; - s64 d_off; - short unsigned int d_reclen; - unsigned char d_type; - char d_name[0]; -}; - -struct old_linux_dirent { - long unsigned int d_ino; - long unsigned int d_offset; - short unsigned int d_namlen; - char d_name[1]; -}; - -struct readdir_callback { - struct dir_context ctx; - struct old_linux_dirent *dirent; - int result; -}; - -struct linux_dirent { - long unsigned int d_ino; - long unsigned int d_off; - short unsigned int d_reclen; - char d_name[1]; -}; - -struct getdents_callback { - struct dir_context ctx; - struct linux_dirent *current_dir; - int prev_reclen; - int count; - int error; -}; - -struct getdents_callback64 { - struct dir_context ctx; - struct linux_dirent64 *current_dir; - int prev_reclen; - int count; - int error; -}; - -struct compat_old_linux_dirent { - compat_ulong_t d_ino; - compat_ulong_t d_offset; - short unsigned int d_namlen; - char d_name[1]; -}; - -struct compat_readdir_callback { - struct dir_context ctx; - struct compat_old_linux_dirent *dirent; - int result; -}; - -struct compat_linux_dirent { - compat_ulong_t d_ino; - compat_ulong_t d_off; - short unsigned int d_reclen; - char d_name[1]; -}; - -struct compat_getdents_callback { - struct dir_context ctx; - struct compat_linux_dirent *current_dir; - int prev_reclen; - int count; - int error; -}; - -typedef struct { - long unsigned int fds_bits[16]; -} __kernel_fd_set; - -typedef __kernel_fd_set fd_set; - -struct poll_table_entry { - struct file *filp; - __poll_t key; - wait_queue_entry_t wait; - wait_queue_head_t *wait_address; -}; - -struct poll_table_page; - -struct poll_wqueues { - poll_table pt; - struct poll_table_page *table; - struct task_struct *polling_task; - int triggered; - int error; - int inline_index; - struct poll_table_entry inline_entries[9]; -}; - -struct poll_table_page { - struct poll_table_page *next; - struct poll_table_entry *entry; - struct poll_table_entry entries[0]; -}; - -enum poll_time_type { - PT_TIMEVAL = 0, - PT_OLD_TIMEVAL = 1, - PT_TIMESPEC = 2, - PT_OLD_TIMESPEC = 3, -}; - -typedef struct { - long unsigned int *in; - long unsigned int *out; - long unsigned int *ex; - long unsigned int *res_in; - long unsigned int *res_out; - long unsigned int *res_ex; -} fd_set_bits; - -struct sigset_argpack { - sigset_t *p; - size_t size; -}; - -struct poll_list { - struct poll_list *next; - int len; - struct pollfd entries[0]; -}; - -struct compat_sel_arg_struct { - compat_ulong_t n; - compat_uptr_t inp; - compat_uptr_t outp; - compat_uptr_t exp; - compat_uptr_t tvp; -}; - -struct compat_sigset_argpack { - compat_uptr_t p; - compat_size_t size; -}; - -enum dentry_d_lock_class { - DENTRY_D_LOCK_NORMAL = 0, - DENTRY_D_LOCK_NESTED = 1, -}; - -struct external_name { - union { - atomic_t count; - struct callback_head head; - } u; - unsigned char name[0]; -}; - -enum d_walk_ret { - D_WALK_CONTINUE = 0, - D_WALK_QUIT = 1, - D_WALK_NORETRY = 2, - D_WALK_SKIP = 3, -}; - -struct check_mount { - struct vfsmount *mnt; - unsigned int mounted; -}; - -struct select_data { - struct dentry *start; - union { - long int found; - struct dentry *victim; - }; - struct list_head dispose; -}; - -enum file_time_flags { - S_ATIME = 1, - S_MTIME = 2, - S_CTIME = 4, - S_VERSION = 8, -}; - -struct mount_attr { - __u64 attr_set; - __u64 attr_clr; - __u64 propagation; - __u64 userns_fd; -}; - -struct proc_mounts { - struct mnt_namespace *ns; - struct path root; - int (*show)(struct seq_file *, struct vfsmount *); - struct mount cursor; -}; - -struct mount_kattr { - unsigned int attr_set; - unsigned int attr_clr; - unsigned int propagation; - unsigned int lookup_flags; - bool recurse; - struct user_namespace *mnt_userns; -}; - -enum umount_tree_flags { - UMOUNT_SYNC = 1, - UMOUNT_PROPAGATE = 2, - UMOUNT_CONNECTED = 4, -}; - -struct unicode_map { - const char *charset; - int version; -}; - -struct simple_transaction_argresp { - ssize_t size; - char data[0]; -}; - -struct simple_attr { - int (*get)(void *, u64 *); - int (*set)(void *, u64); - char get_buf[24]; - char set_buf[24]; - void *data; - const char *fmt; - struct mutex mutex; -}; - -struct wb_writeback_work { - long int nr_pages; - struct super_block *sb; - enum writeback_sync_modes sync_mode; - unsigned int tagged_writepages: 1; - unsigned int for_kupdate: 1; - unsigned int range_cyclic: 1; - unsigned int for_background: 1; - unsigned int for_sync: 1; - unsigned int auto_free: 1; - enum wb_reason reason; - struct list_head list; - struct wb_completion *done; -}; - -struct trace_event_raw_writeback_page_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int index; - char __data[0]; -}; - -struct trace_event_raw_writeback_dirty_inode_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int state; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_inode_foreign_history { - struct trace_entry ent; - char name[32]; - ino_t ino; - ino_t cgroup_ino; - unsigned int history; - char __data[0]; -}; - -struct trace_event_raw_inode_switch_wbs { - struct trace_entry ent; - char name[32]; - ino_t ino; - ino_t old_cgroup_ino; - ino_t new_cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_track_foreign_dirty { - struct trace_entry ent; - char name[32]; - u64 bdi_id; - ino_t ino; - unsigned int memcg_id; - ino_t cgroup_ino; - ino_t page_cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_flush_foreign { - struct trace_entry ent; - char name[32]; - ino_t cgroup_ino; - unsigned int frn_bdi_id; - unsigned int frn_memcg_id; - char __data[0]; -}; - -struct trace_event_raw_writeback_write_inode_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - int sync_mode; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_work_class { - struct trace_entry ent; - char name[32]; - long int nr_pages; - dev_t sb_dev; - int sync_mode; - int for_kupdate; - int range_cyclic; - int for_background; - int reason; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_pages_written { - struct trace_entry ent; - long int pages; - char __data[0]; -}; - -struct trace_event_raw_writeback_class { - struct trace_entry ent; - char name[32]; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_bdi_register { - struct trace_entry ent; - char name[32]; - char __data[0]; -}; - -struct trace_event_raw_wbc_class { - struct trace_entry ent; - char name[32]; - long int nr_to_write; - long int pages_skipped; - int sync_mode; - int for_kupdate; - int for_background; - int for_reclaim; - int range_cyclic; - long int range_start; - long int range_end; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_queue_io { - struct trace_entry ent; - char name[32]; - long unsigned int older; - long int age; - int moved; - int reason; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_global_dirty_state { - struct trace_entry ent; - long unsigned int nr_dirty; - long unsigned int nr_writeback; - long unsigned int background_thresh; - long unsigned int dirty_thresh; - long unsigned int dirty_limit; - long unsigned int nr_dirtied; - long unsigned int nr_written; - char __data[0]; -}; - -struct trace_event_raw_bdi_dirty_ratelimit { - struct trace_entry ent; - char bdi[32]; - long unsigned int write_bw; - long unsigned int avg_write_bw; - long unsigned int dirty_rate; - long unsigned int dirty_ratelimit; - long unsigned int task_ratelimit; - long unsigned int balanced_dirty_ratelimit; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_balance_dirty_pages { - struct trace_entry ent; - char bdi[32]; - long unsigned int limit; - long unsigned int setpoint; - long unsigned int dirty; - long unsigned int bdi_setpoint; - long unsigned int bdi_dirty; - long unsigned int dirty_ratelimit; - long unsigned int task_ratelimit; - unsigned int dirtied; - unsigned int dirtied_pause; - long unsigned int paused; - long int pause; - long unsigned int period; - long int think; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_sb_inodes_requeue { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int state; - long unsigned int dirtied_when; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_congest_waited_template { - struct trace_entry ent; - unsigned int usec_timeout; - unsigned int usec_delayed; - char __data[0]; -}; - -struct trace_event_raw_writeback_single_inode_template { - struct trace_entry ent; - char name[32]; - ino_t ino; - long unsigned int state; - long unsigned int dirtied_when; - long unsigned int writeback_index; - long int nr_to_write; - long unsigned int wrote; - ino_t cgroup_ino; - char __data[0]; -}; - -struct trace_event_raw_writeback_inode_template { - struct trace_entry ent; - dev_t dev; - ino_t ino; - long unsigned int state; - __u16 mode; - long unsigned int dirtied_when; - char __data[0]; -}; - -struct trace_event_data_offsets_writeback_page_template {}; - -struct trace_event_data_offsets_writeback_dirty_inode_template {}; - -struct trace_event_data_offsets_inode_foreign_history {}; - -struct trace_event_data_offsets_inode_switch_wbs {}; - -struct trace_event_data_offsets_track_foreign_dirty {}; - -struct trace_event_data_offsets_flush_foreign {}; - -struct trace_event_data_offsets_writeback_write_inode_template {}; - -struct trace_event_data_offsets_writeback_work_class {}; - -struct trace_event_data_offsets_writeback_pages_written {}; - -struct trace_event_data_offsets_writeback_class {}; - -struct trace_event_data_offsets_writeback_bdi_register {}; - -struct trace_event_data_offsets_wbc_class {}; - -struct trace_event_data_offsets_writeback_queue_io {}; - -struct trace_event_data_offsets_global_dirty_state {}; - -struct trace_event_data_offsets_bdi_dirty_ratelimit {}; - -struct trace_event_data_offsets_balance_dirty_pages {}; - -struct trace_event_data_offsets_writeback_sb_inodes_requeue {}; - -struct trace_event_data_offsets_writeback_congest_waited_template {}; - -struct trace_event_data_offsets_writeback_single_inode_template {}; - -struct trace_event_data_offsets_writeback_inode_template {}; - -typedef void (*btf_trace_writeback_dirty_page)(void *, struct page *, struct address_space *); - -typedef void (*btf_trace_wait_on_page_writeback)(void *, struct page *, struct address_space *); - -typedef void (*btf_trace_writeback_mark_inode_dirty)(void *, struct inode *, int); - -typedef void (*btf_trace_writeback_dirty_inode_start)(void *, struct inode *, int); - -typedef void (*btf_trace_writeback_dirty_inode)(void *, struct inode *, int); - -typedef void (*btf_trace_inode_foreign_history)(void *, struct inode *, struct writeback_control *, unsigned int); - -typedef void (*btf_trace_inode_switch_wbs)(void *, struct inode *, struct bdi_writeback *, struct bdi_writeback *); - -typedef void (*btf_trace_track_foreign_dirty)(void *, struct page *, struct bdi_writeback *); - -typedef void (*btf_trace_flush_foreign)(void *, struct bdi_writeback *, unsigned int, unsigned int); - -typedef void (*btf_trace_writeback_write_inode_start)(void *, struct inode *, struct writeback_control *); - -typedef void (*btf_trace_writeback_write_inode)(void *, struct inode *, struct writeback_control *); - -typedef void (*btf_trace_writeback_queue)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_exec)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_start)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_written)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_wait)(void *, struct bdi_writeback *, struct wb_writeback_work *); - -typedef void (*btf_trace_writeback_pages_written)(void *, long int); - -typedef void (*btf_trace_writeback_wake_background)(void *, struct bdi_writeback *); - -typedef void (*btf_trace_writeback_bdi_register)(void *, struct backing_dev_info *); - -typedef void (*btf_trace_wbc_writepage)(void *, struct writeback_control *, struct backing_dev_info *); - -typedef void (*btf_trace_writeback_queue_io)(void *, struct bdi_writeback *, struct wb_writeback_work *, long unsigned int, int); - -typedef void (*btf_trace_global_dirty_state)(void *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_bdi_dirty_ratelimit)(void *, struct bdi_writeback *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_balance_dirty_pages)(void *, struct bdi_writeback *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long int, long unsigned int); - -typedef void (*btf_trace_writeback_sb_inodes_requeue)(void *, struct inode *); - -typedef void (*btf_trace_writeback_congestion_wait)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_writeback_wait_iff_congested)(void *, unsigned int, unsigned int); - -typedef void (*btf_trace_writeback_single_inode_start)(void *, struct inode *, struct writeback_control *, long unsigned int); - -typedef void (*btf_trace_writeback_single_inode)(void *, struct inode *, struct writeback_control *, long unsigned int); - -typedef void (*btf_trace_writeback_lazytime)(void *, struct inode *); - -typedef void (*btf_trace_writeback_lazytime_iput)(void *, struct inode *); - -typedef void (*btf_trace_writeback_dirty_inode_enqueue)(void *, struct inode *); - -typedef void (*btf_trace_sb_mark_inode_writeback)(void *, struct inode *); - -typedef void (*btf_trace_sb_clear_inode_writeback)(void *, struct inode *); - -struct inode_switch_wbs_context { - struct rcu_work work; - struct bdi_writeback *new_wb; - struct inode *inodes[0]; -}; - -struct splice_desc { - size_t total_len; - unsigned int len; - unsigned int flags; - union { - void *userptr; - struct file *file; - void *data; - } u; - loff_t pos; - loff_t *opos; - size_t num_spliced; - bool need_wakeup; -}; - -typedef int splice_actor(struct pipe_inode_info *, struct pipe_buffer *, struct splice_desc *); - -typedef int splice_direct_actor(struct pipe_inode_info *, struct splice_desc *); - -struct old_utimbuf32 { - old_time32_t actime; - old_time32_t modtime; -}; - -struct utimbuf { - __kernel_old_time_t actime; - __kernel_old_time_t modtime; -}; - -struct prepend_buffer { - char *buf; - int len; -}; - -typedef int __kernel_daddr_t; - -struct ustat { - __kernel_daddr_t f_tfree; - long unsigned int f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -typedef s32 compat_daddr_t; - -typedef __kernel_fsid_t compat_fsid_t; - -struct compat_statfs { - int f_type; - int f_bsize; - int f_blocks; - int f_bfree; - int f_bavail; - int f_files; - int f_ffree; - compat_fsid_t f_fsid; - int f_namelen; - int f_frsize; - int f_flags; - int f_spare[4]; -}; - -struct compat_ustat { - compat_daddr_t f_tfree; - compat_ino_t f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -struct statfs { - __kernel_long_t f_type; - __kernel_long_t f_bsize; - __kernel_long_t f_blocks; - __kernel_long_t f_bfree; - __kernel_long_t f_bavail; - __kernel_long_t f_files; - __kernel_long_t f_ffree; - __kernel_fsid_t f_fsid; - __kernel_long_t f_namelen; - __kernel_long_t f_frsize; - __kernel_long_t f_flags; - __kernel_long_t f_spare[4]; -}; - -struct statfs64 { - __kernel_long_t f_type; - __kernel_long_t f_bsize; - __u64 f_blocks; - __u64 f_bfree; - __u64 f_bavail; - __u64 f_files; - __u64 f_ffree; - __kernel_fsid_t f_fsid; - __kernel_long_t f_namelen; - __kernel_long_t f_frsize; - __kernel_long_t f_flags; - __kernel_long_t f_spare[4]; -}; - -struct compat_statfs64 { - __u32 f_type; - __u32 f_bsize; - __u64 f_blocks; - __u64 f_bfree; - __u64 f_bavail; - __u64 f_files; - __u64 f_ffree; - __kernel_fsid_t f_fsid; - __u32 f_namelen; - __u32 f_frsize; - __u32 f_flags; - __u32 f_spare[4]; -} __attribute__((packed)); - -struct ns_get_path_task_args { - const struct proc_ns_operations *ns_ops; - struct task_struct *task; -}; - -enum legacy_fs_param { - LEGACY_FS_UNSET_PARAMS = 0, - LEGACY_FS_MONOLITHIC_PARAMS = 1, - LEGACY_FS_INDIVIDUAL_PARAMS = 2, -}; - -struct legacy_fs_context { - char *legacy_data; - size_t data_size; - enum legacy_fs_param param_type; -}; - -enum fsconfig_command { - FSCONFIG_SET_FLAG = 0, - FSCONFIG_SET_STRING = 1, - FSCONFIG_SET_BINARY = 2, - FSCONFIG_SET_PATH = 3, - FSCONFIG_SET_PATH_EMPTY = 4, - FSCONFIG_SET_FD = 5, - FSCONFIG_CMD_CREATE = 6, - FSCONFIG_CMD_RECONFIGURE = 7, -}; - -struct dax_device; - -struct iomap_page_ops; - -struct iomap___2 { - u64 addr; - loff_t offset; - u64 length; - u16 type; - u16 flags; - struct block_device *bdev; - struct dax_device *dax_dev; - void *inline_data; - void *private; - const struct iomap_page_ops *page_ops; -}; - -struct iomap_page_ops { - int (*page_prepare)(struct inode *, loff_t, unsigned int, struct iomap___2 *); - void (*page_done)(struct inode *, loff_t, unsigned int, struct page *, struct iomap___2 *); -}; - -struct decrypt_bh_ctx { - struct work_struct work; - struct buffer_head *bh; -}; - -struct bh_lru { - struct buffer_head *bhs[16]; -}; - -struct bh_accounting { - int nr; - int ratelimit; -}; - -enum stat_group { - STAT_READ = 0, - STAT_WRITE = 1, - STAT_DISCARD = 2, - STAT_FLUSH = 3, - NR_STAT_GROUPS = 4, -}; - -enum { - DISK_EVENT_MEDIA_CHANGE = 1, - DISK_EVENT_EJECT_REQUEST = 2, -}; - -enum { - BIOSET_NEED_BVECS = 1, - BIOSET_NEED_RESCUER = 2, -}; - -struct bdev_inode { - struct block_device bdev; - struct inode vfs_inode; -}; - -struct blkdev_dio { - union { - struct kiocb *iocb; - struct task_struct *waiter; - }; - size_t size; - atomic_t ref; - bool multi_bio: 1; - bool should_dirty: 1; - bool is_sync: 1; - struct bio bio; -}; - -struct bd_holder_disk { - struct list_head list; - struct gendisk *disk; - int refcnt; -}; - -typedef int dio_iodone_t(struct kiocb *, loff_t, ssize_t, void *); - -typedef void dio_submit_t(struct bio *, struct inode *, loff_t); - -enum { - DIO_LOCKING = 1, - DIO_SKIP_HOLES = 2, -}; - -struct dio_submit { - struct bio *bio; - unsigned int blkbits; - unsigned int blkfactor; - unsigned int start_zero_done; - int pages_in_io; - sector_t block_in_file; - unsigned int blocks_available; - int reap_counter; - sector_t final_block_in_request; - int boundary; - get_block_t *get_block; - dio_submit_t *submit_io; - loff_t logical_offset_in_bio; - sector_t final_block_in_bio; - sector_t next_block_for_io; - struct page *cur_page; - unsigned int cur_page_offset; - unsigned int cur_page_len; - sector_t cur_page_block; - loff_t cur_page_fs_offset; - struct iov_iter *iter; - unsigned int head; - unsigned int tail; - size_t from; - size_t to; -}; - -struct dio { - int flags; - int op; - int op_flags; - blk_qc_t bio_cookie; - struct gendisk *bio_disk; - struct inode *inode; - loff_t i_size; - dio_iodone_t *end_io; - void *private; - spinlock_t bio_lock; - int page_errors; - int is_async; - bool defer_completion; - bool should_dirty; - int io_error; - long unsigned int refcount; - struct bio *bio_list; - struct task_struct *waiter; - struct kiocb *iocb; - ssize_t result; - union { - struct page *pages[64]; - struct work_struct complete_work; - }; - long: 64; -}; - -struct bvec_iter_all { - struct bio_vec bv; - int idx; - unsigned int done; -}; - -struct mpage_readpage_args { - struct bio *bio; - struct page *page; - unsigned int nr_pages; - bool is_readahead; - sector_t last_block_in_bio; - struct buffer_head map_bh; - long unsigned int first_logical_block; - get_block_t *get_block; -}; - -struct mpage_data { - struct bio *bio; - sector_t last_block_in_bio; - get_block_t *get_block; - unsigned int use_writepage; -}; - -typedef u32 nlink_t; - -typedef int (*proc_write_t)(struct file *, char *, size_t); - -struct proc_dir_entry { - atomic_t in_use; - refcount_t refcnt; - struct list_head pde_openers; - spinlock_t pde_unload_lock; - struct completion *pde_unload_completion; - const struct inode_operations *proc_iops; - union { - const struct proc_ops *proc_ops; - const struct file_operations *proc_dir_ops; - }; - const struct dentry_operations *proc_dops; - union { - const struct seq_operations *seq_ops; - int (*single_show)(struct seq_file *, void *); - }; - proc_write_t write; - void *data; - unsigned int state_size; - unsigned int low_ino; - nlink_t nlink; - kuid_t uid; - kgid_t gid; - loff_t size; - struct proc_dir_entry *parent; - struct rb_root subdir; - struct rb_node subdir_node; - char *name; - umode_t mode; - u8 flags; - u8 namelen; - char inline_name[0]; -}; - -union proc_op { - int (*proc_get_link)(struct dentry *, struct path *); - int (*proc_show)(struct seq_file *, struct pid_namespace *, struct pid *, struct task_struct *); - const char *lsm; -}; - -struct proc_inode { - struct pid *pid; - unsigned int fd; - union proc_op op; - struct proc_dir_entry *pde; - struct ctl_table_header *sysctl; - struct ctl_table *sysctl_entry; - struct hlist_node sibling_inodes; - const struct proc_ns_operations *ns_ops; - struct inode vfs_inode; -}; - -struct proc_fs_opts { - int flag; - const char *str; -}; - -struct file_handle { - __u32 handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -struct inotify_inode_mark { - struct fsnotify_mark fsn_mark; - int wd; -}; - -struct dnotify_struct { - struct dnotify_struct *dn_next; - __u32 dn_mask; - int dn_fd; - struct file *dn_filp; - fl_owner_t dn_owner; -}; - -struct dnotify_mark { - struct fsnotify_mark fsn_mark; - struct dnotify_struct *dn; -}; - -struct inotify_event_info { - struct fsnotify_event fse; - u32 mask; - int wd; - u32 sync_cookie; - int name_len; - char name[0]; -}; - -struct inotify_event { - __s32 wd; - __u32 mask; - __u32 cookie; - __u32 len; - char name[0]; -}; - -enum { - FAN_EVENT_INIT = 0, - FAN_EVENT_REPORTED = 1, - FAN_EVENT_ANSWERED = 2, - FAN_EVENT_CANCELED = 3, -}; - -struct fanotify_fh { - u8 type; - u8 len; - u8 flags; - u8 pad; - unsigned char buf[0]; -}; - -struct fanotify_info { - u8 dir_fh_totlen; - u8 file_fh_totlen; - u8 name_len; - u8 pad; - unsigned char buf[0]; -}; - -enum fanotify_event_type { - FANOTIFY_EVENT_TYPE_FID = 0, - FANOTIFY_EVENT_TYPE_FID_NAME = 1, - FANOTIFY_EVENT_TYPE_PATH = 2, - FANOTIFY_EVENT_TYPE_PATH_PERM = 3, - FANOTIFY_EVENT_TYPE_OVERFLOW = 4, - __FANOTIFY_EVENT_TYPE_NUM = 5, -}; - -struct fanotify_event { - struct fsnotify_event fse; - struct hlist_node merge_list; - u32 mask; - struct { - unsigned int type: 3; - unsigned int hash: 29; - }; - struct pid *pid; -}; - -struct fanotify_fid_event { - struct fanotify_event fae; - __kernel_fsid_t fsid; - struct fanotify_fh object_fh; - unsigned char _inline_fh_buf[12]; -}; - -struct fanotify_name_event { - struct fanotify_event fae; - __kernel_fsid_t fsid; - struct fanotify_info info; -}; - -struct fanotify_path_event { - struct fanotify_event fae; - struct path path; -}; - -struct fanotify_perm_event { - struct fanotify_event fae; - struct path path; - short unsigned int response; - short unsigned int state; - int fd; -}; - -struct fanotify_event_metadata { - __u32 event_len; - __u8 vers; - __u8 reserved; - __u16 metadata_len; - __u64 mask; - __s32 fd; - __s32 pid; -}; - -struct fanotify_event_info_header { - __u8 info_type; - __u8 pad; - __u16 len; -}; - -struct fanotify_event_info_fid { - struct fanotify_event_info_header hdr; - __kernel_fsid_t fsid; - unsigned char handle[0]; -}; - -struct fanotify_response { - __s32 fd; - __u32 response; -}; - -struct epoll_event { - __poll_t events; - __u64 data; -} __attribute__((packed)); - -struct epoll_filefd { - struct file *file; - int fd; -} __attribute__((packed)); - -struct epitem; - -struct eppoll_entry { - struct eppoll_entry *next; - struct epitem *base; - wait_queue_entry_t wait; - wait_queue_head_t *whead; -}; - -struct eventpoll; - -struct epitem { - union { - struct rb_node rbn; - struct callback_head rcu; - }; - struct list_head rdllink; - struct epitem *next; - struct epoll_filefd ffd; - struct eppoll_entry *pwqlist; - struct eventpoll *ep; - struct hlist_node fllink; - struct wakeup_source *ws; - struct epoll_event event; -}; - -struct eventpoll { - struct mutex mtx; - wait_queue_head_t wq; - wait_queue_head_t poll_wait; - struct list_head rdllist; - rwlock_t lock; - struct rb_root_cached rbr; - struct epitem *ovflist; - struct wakeup_source *ws; - struct user_struct *user; - struct file *file; - u64 gen; - struct hlist_head refs; - unsigned int napi_id; -}; - -struct ep_pqueue { - poll_table pt; - struct epitem *epi; -}; - -struct epitems_head { - struct hlist_head epitems; - struct epitems_head *next; -}; - -struct signalfd_siginfo { - __u32 ssi_signo; - __s32 ssi_errno; - __s32 ssi_code; - __u32 ssi_pid; - __u32 ssi_uid; - __s32 ssi_fd; - __u32 ssi_tid; - __u32 ssi_band; - __u32 ssi_overrun; - __u32 ssi_trapno; - __s32 ssi_status; - __s32 ssi_int; - __u64 ssi_ptr; - __u64 ssi_utime; - __u64 ssi_stime; - __u64 ssi_addr; - __u16 ssi_addr_lsb; - __u16 __pad2; - __s32 ssi_syscall; - __u64 ssi_call_addr; - __u32 ssi_arch; - __u8 __pad[28]; -}; - -struct signalfd_ctx { - sigset_t sigmask; -}; - -struct timerfd_ctx { - union { - struct hrtimer tmr; - struct alarm alarm; - } t; - ktime_t tintv; - ktime_t moffs; - wait_queue_head_t wqh; - u64 ticks; - int clockid; - short unsigned int expired; - short unsigned int settime_flags; - struct callback_head rcu; - struct list_head clist; - spinlock_t cancel_lock; - bool might_cancel; -}; - -struct eventfd_ctx___2 { - struct kref kref; - wait_queue_head_t wqh; - __u64 count; - unsigned int flags; - int id; -}; - -enum userfaultfd_state { - UFFD_STATE_WAIT_API = 0, - UFFD_STATE_RUNNING = 1, -}; - -struct userfaultfd_ctx { - wait_queue_head_t fault_pending_wqh; - wait_queue_head_t fault_wqh; - wait_queue_head_t fd_wqh; - wait_queue_head_t event_wqh; - seqcount_spinlock_t refile_seq; - refcount_t refcount; - unsigned int flags; - unsigned int features; - enum userfaultfd_state state; - bool released; - bool mmap_changing; - struct mm_struct *mm; -}; - -struct uffd_msg { - __u8 event; - __u8 reserved1; - __u16 reserved2; - __u32 reserved3; - union { - struct { - __u64 flags; - __u64 address; - union { - __u32 ptid; - } feat; - } pagefault; - struct { - __u32 ufd; - } fork; - struct { - __u64 from; - __u64 to; - __u64 len; - } remap; - struct { - __u64 start; - __u64 end; - } remove; - struct { - __u64 reserved1; - __u64 reserved2; - __u64 reserved3; - } reserved; - } arg; -}; - -struct uffdio_api { - __u64 api; - __u64 features; - __u64 ioctls; -}; - -struct uffdio_range { - __u64 start; - __u64 len; -}; - -struct uffdio_register { - struct uffdio_range range; - __u64 mode; - __u64 ioctls; -}; - -struct uffdio_copy { - __u64 dst; - __u64 src; - __u64 len; - __u64 mode; - __s64 copy; -}; - -struct uffdio_zeropage { - struct uffdio_range range; - __u64 mode; - __s64 zeropage; -}; - -struct uffdio_writeprotect { - struct uffdio_range range; - __u64 mode; -}; - -struct uffdio_continue { - struct uffdio_range range; - __u64 mode; - __s64 mapped; -}; - -struct userfaultfd_fork_ctx { - struct userfaultfd_ctx *orig; - struct userfaultfd_ctx *new; - struct list_head list; -}; - -struct userfaultfd_unmap_ctx { - struct userfaultfd_ctx *ctx; - long unsigned int start; - long unsigned int end; - struct list_head list; -}; - -struct userfaultfd_wait_queue { - struct uffd_msg msg; - wait_queue_entry_t wq; - struct userfaultfd_ctx *ctx; - bool waken; -}; - -struct userfaultfd_wake_range { - long unsigned int start; - long unsigned int len; -}; - -struct kioctx; - -struct kioctx_table { - struct callback_head rcu; - unsigned int nr; - struct kioctx *table[0]; -}; - -typedef __kernel_ulong_t aio_context_t; - -enum { - IOCB_CMD_PREAD = 0, - IOCB_CMD_PWRITE = 1, - IOCB_CMD_FSYNC = 2, - IOCB_CMD_FDSYNC = 3, - IOCB_CMD_POLL = 5, - IOCB_CMD_NOOP = 6, - IOCB_CMD_PREADV = 7, - IOCB_CMD_PWRITEV = 8, -}; - -struct io_event { - __u64 data; - __u64 obj; - __s64 res; - __s64 res2; -}; - -struct iocb { - __u64 aio_data; - __u32 aio_key; - __kernel_rwf_t aio_rw_flags; - __u16 aio_lio_opcode; - __s16 aio_reqprio; - __u32 aio_fildes; - __u64 aio_buf; - __u64 aio_nbytes; - __s64 aio_offset; - __u64 aio_reserved2; - __u32 aio_flags; - __u32 aio_resfd; -}; - -typedef u32 compat_aio_context_t; - -typedef int kiocb_cancel_fn(struct kiocb *); - -struct aio_ring { - unsigned int id; - unsigned int nr; - unsigned int head; - unsigned int tail; - unsigned int magic; - unsigned int compat_features; - unsigned int incompat_features; - unsigned int header_length; - struct io_event io_events[0]; -}; - -struct kioctx_cpu; - -struct ctx_rq_wait; - -struct kioctx { - struct percpu_ref users; - atomic_t dead; - struct percpu_ref reqs; - long unsigned int user_id; - struct kioctx_cpu *cpu; - unsigned int req_batch; - unsigned int max_reqs; - unsigned int nr_events; - long unsigned int mmap_base; - long unsigned int mmap_size; - struct page **ring_pages; - long int nr_pages; - struct rcu_work free_rwork; - struct ctx_rq_wait *rq_wait; - long: 64; - long: 64; - long: 64; - struct { - atomic_t reqs_available; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - spinlock_t ctx_lock; - struct list_head active_reqs; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - struct mutex ring_lock; - wait_queue_head_t wait; - long: 64; - }; - struct { - unsigned int tail; - unsigned int completed_events; - spinlock_t completion_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct page *internal_pages[8]; - struct file *aio_ring_file; - unsigned int id; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct kioctx_cpu { - unsigned int reqs_available; -}; - -struct ctx_rq_wait { - struct completion comp; - atomic_t count; -}; - -struct fsync_iocb { - struct file *file; - struct work_struct work; - bool datasync; - struct cred *creds; -}; - -struct poll_iocb { - struct file *file; - struct wait_queue_head *head; - __poll_t events; - bool done; - bool cancelled; - struct wait_queue_entry wait; - struct work_struct work; -}; - -struct aio_kiocb { - union { - struct file *ki_filp; - struct kiocb rw; - struct fsync_iocb fsync; - struct poll_iocb poll; - }; - struct kioctx *ki_ctx; - kiocb_cancel_fn *ki_cancel; - struct io_event ki_res; - struct list_head ki_list; - refcount_t ki_refcnt; - struct eventfd_ctx *ki_eventfd; -}; - -struct aio_poll_table { - struct poll_table_struct pt; - struct aio_kiocb *iocb; - int error; -}; - -struct __aio_sigset { - const sigset_t *sigmask; - size_t sigsetsize; -}; - -struct __compat_aio_sigset { - compat_uptr_t sigmask; - compat_size_t sigsetsize; -}; - -struct xa_limit { - u32 max; - u32 min; -}; - -struct io_wq; - -struct io_wq_work_node; - -struct io_wq_work_list { - struct io_wq_work_node *first; - struct io_wq_work_node *last; -}; - -struct io_ring_ctx; - -struct io_uring_task { - int cached_refs; - struct xarray xa; - struct wait_queue_head wait; - const struct io_ring_ctx *last; - struct io_wq *io_wq; - struct percpu_counter inflight; - atomic_t inflight_tracked; - atomic_t in_idle; - spinlock_t task_lock; - struct io_wq_work_list task_list; - long unsigned int task_state; - struct callback_head task_work; -}; - -struct user_msghdr { - void *msg_name; - int msg_namelen; - struct iovec *msg_iov; - __kernel_size_t msg_iovlen; - void *msg_control; - __kernel_size_t msg_controllen; - unsigned int msg_flags; -}; - -typedef s32 compat_ssize_t; - -struct compat_msghdr { - compat_uptr_t msg_name; - compat_int_t msg_namelen; - compat_uptr_t msg_iov; - compat_size_t msg_iovlen; - compat_uptr_t msg_control; - compat_size_t msg_controllen; - compat_uint_t msg_flags; -}; - -struct scm_fp_list { - short int count; - short int max; - struct user_struct *user; - struct file *fp[253]; -}; - -struct unix_skb_parms { - struct pid *pid; - kuid_t uid; - kgid_t gid; - struct scm_fp_list *fp; - u32 secid; - u32 consumed; -}; - -struct trace_event_raw_io_uring_create { - struct trace_entry ent; - int fd; - void *ctx; - u32 sq_entries; - u32 cq_entries; - u32 flags; - char __data[0]; -}; - -struct trace_event_raw_io_uring_register { - struct trace_entry ent; - void *ctx; - unsigned int opcode; - unsigned int nr_files; - unsigned int nr_bufs; - bool eventfd; - long int ret; - char __data[0]; -}; - -struct trace_event_raw_io_uring_file_get { - struct trace_entry ent; - void *ctx; - int fd; - char __data[0]; -}; - -struct io_wq_work; - -struct trace_event_raw_io_uring_queue_async_work { - struct trace_entry ent; - void *ctx; - int rw; - void *req; - struct io_wq_work *work; - unsigned int flags; - char __data[0]; -}; - -struct io_wq_work_node { - struct io_wq_work_node *next; -}; - -struct io_wq_work { - struct io_wq_work_node list; - unsigned int flags; -}; - -struct trace_event_raw_io_uring_defer { - struct trace_entry ent; - void *ctx; - void *req; - long long unsigned int data; - char __data[0]; -}; - -struct trace_event_raw_io_uring_link { - struct trace_entry ent; - void *ctx; - void *req; - void *target_req; - char __data[0]; -}; - -struct trace_event_raw_io_uring_cqring_wait { - struct trace_entry ent; - void *ctx; - int min_events; - char __data[0]; -}; - -struct trace_event_raw_io_uring_fail_link { - struct trace_entry ent; - void *req; - void *link; - char __data[0]; -}; - -struct trace_event_raw_io_uring_complete { - struct trace_entry ent; - void *ctx; - u64 user_data; - long int res; - unsigned int cflags; - char __data[0]; -}; - -struct trace_event_raw_io_uring_submit_sqe { - struct trace_entry ent; - void *ctx; - void *req; - u8 opcode; - u64 user_data; - u32 flags; - bool force_nonblock; - bool sq_thread; - char __data[0]; -}; - -struct trace_event_raw_io_uring_poll_arm { - struct trace_entry ent; - void *ctx; - void *req; - u8 opcode; - u64 user_data; - int mask; - int events; - char __data[0]; -}; - -struct trace_event_raw_io_uring_poll_wake { - struct trace_entry ent; - void *ctx; - u8 opcode; - u64 user_data; - int mask; - char __data[0]; -}; - -struct trace_event_raw_io_uring_task_add { - struct trace_entry ent; - void *ctx; - u8 opcode; - u64 user_data; - int mask; - char __data[0]; -}; - -struct trace_event_raw_io_uring_task_run { - struct trace_entry ent; - void *ctx; - void *req; - u8 opcode; - u64 user_data; - char __data[0]; -}; - -struct trace_event_data_offsets_io_uring_create {}; - -struct trace_event_data_offsets_io_uring_register {}; - -struct trace_event_data_offsets_io_uring_file_get {}; - -struct trace_event_data_offsets_io_uring_queue_async_work {}; - -struct trace_event_data_offsets_io_uring_defer {}; - -struct trace_event_data_offsets_io_uring_link {}; - -struct trace_event_data_offsets_io_uring_cqring_wait {}; - -struct trace_event_data_offsets_io_uring_fail_link {}; - -struct trace_event_data_offsets_io_uring_complete {}; - -struct trace_event_data_offsets_io_uring_submit_sqe {}; - -struct trace_event_data_offsets_io_uring_poll_arm {}; - -struct trace_event_data_offsets_io_uring_poll_wake {}; - -struct trace_event_data_offsets_io_uring_task_add {}; - -struct trace_event_data_offsets_io_uring_task_run {}; - -typedef void (*btf_trace_io_uring_create)(void *, int, void *, u32, u32, u32); - -typedef void (*btf_trace_io_uring_register)(void *, void *, unsigned int, unsigned int, unsigned int, bool, long int); - -typedef void (*btf_trace_io_uring_file_get)(void *, void *, int); - -typedef void (*btf_trace_io_uring_queue_async_work)(void *, void *, int, void *, struct io_wq_work *, unsigned int); - -typedef void (*btf_trace_io_uring_defer)(void *, void *, void *, long long unsigned int); - -typedef void (*btf_trace_io_uring_link)(void *, void *, void *, void *); - -typedef void (*btf_trace_io_uring_cqring_wait)(void *, void *, int); - -typedef void (*btf_trace_io_uring_fail_link)(void *, void *, void *); - -typedef void (*btf_trace_io_uring_complete)(void *, void *, u64, long int, unsigned int); - -typedef void (*btf_trace_io_uring_submit_sqe)(void *, void *, void *, u8, u64, u32, bool, bool); - -typedef void (*btf_trace_io_uring_poll_arm)(void *, void *, void *, u8, u64, int, int); - -typedef void (*btf_trace_io_uring_poll_wake)(void *, void *, u8, u64, int); - -typedef void (*btf_trace_io_uring_task_add)(void *, void *, u8, u64, int); - -typedef void (*btf_trace_io_uring_task_run)(void *, void *, void *, u8, u64); - -struct io_uring_sqe { - __u8 opcode; - __u8 flags; - __u16 ioprio; - __s32 fd; - union { - __u64 off; - __u64 addr2; - }; - union { - __u64 addr; - __u64 splice_off_in; - }; - __u32 len; - union { - __kernel_rwf_t rw_flags; - __u32 fsync_flags; - __u16 poll_events; - __u32 poll32_events; - __u32 sync_range_flags; - __u32 msg_flags; - __u32 timeout_flags; - __u32 accept_flags; - __u32 cancel_flags; - __u32 open_flags; - __u32 statx_flags; - __u32 fadvise_advice; - __u32 splice_flags; - __u32 rename_flags; - __u32 unlink_flags; - }; - __u64 user_data; - union { - __u16 buf_index; - __u16 buf_group; - }; - __u16 personality; - __s32 splice_fd_in; - __u64 __pad2[2]; -}; - -enum { - IOSQE_FIXED_FILE_BIT = 0, - IOSQE_IO_DRAIN_BIT = 1, - IOSQE_IO_LINK_BIT = 2, - IOSQE_IO_HARDLINK_BIT = 3, - IOSQE_ASYNC_BIT = 4, - IOSQE_BUFFER_SELECT_BIT = 5, -}; - -enum { - IORING_OP_NOP = 0, - IORING_OP_READV = 1, - IORING_OP_WRITEV = 2, - IORING_OP_FSYNC = 3, - IORING_OP_READ_FIXED = 4, - IORING_OP_WRITE_FIXED = 5, - IORING_OP_POLL_ADD = 6, - IORING_OP_POLL_REMOVE = 7, - IORING_OP_SYNC_FILE_RANGE = 8, - IORING_OP_SENDMSG = 9, - IORING_OP_RECVMSG = 10, - IORING_OP_TIMEOUT = 11, - IORING_OP_TIMEOUT_REMOVE = 12, - IORING_OP_ACCEPT = 13, - IORING_OP_ASYNC_CANCEL = 14, - IORING_OP_LINK_TIMEOUT = 15, - IORING_OP_CONNECT = 16, - IORING_OP_FALLOCATE = 17, - IORING_OP_OPENAT = 18, - IORING_OP_CLOSE = 19, - IORING_OP_FILES_UPDATE = 20, - IORING_OP_STATX = 21, - IORING_OP_READ = 22, - IORING_OP_WRITE = 23, - IORING_OP_FADVISE = 24, - IORING_OP_MADVISE = 25, - IORING_OP_SEND = 26, - IORING_OP_RECV = 27, - IORING_OP_OPENAT2 = 28, - IORING_OP_EPOLL_CTL = 29, - IORING_OP_SPLICE = 30, - IORING_OP_PROVIDE_BUFFERS = 31, - IORING_OP_REMOVE_BUFFERS = 32, - IORING_OP_TEE = 33, - IORING_OP_SHUTDOWN = 34, - IORING_OP_RENAMEAT = 35, - IORING_OP_UNLINKAT = 36, - IORING_OP_LAST = 37, -}; - -struct io_uring_cqe { - __u64 user_data; - __s32 res; - __u32 flags; -}; - -enum { - IORING_CQE_BUFFER_SHIFT = 16, -}; - -struct io_sqring_offsets { - __u32 head; - __u32 tail; - __u32 ring_mask; - __u32 ring_entries; - __u32 flags; - __u32 dropped; - __u32 array; - __u32 resv1; - __u64 resv2; -}; - -struct io_cqring_offsets { - __u32 head; - __u32 tail; - __u32 ring_mask; - __u32 ring_entries; - __u32 overflow; - __u32 cqes; - __u32 flags; - __u32 resv1; - __u64 resv2; -}; - -struct io_uring_params { - __u32 sq_entries; - __u32 cq_entries; - __u32 flags; - __u32 sq_thread_cpu; - __u32 sq_thread_idle; - __u32 features; - __u32 wq_fd; - __u32 resv[3]; - struct io_sqring_offsets sq_off; - struct io_cqring_offsets cq_off; -}; - -enum { - IORING_REGISTER_BUFFERS = 0, - IORING_UNREGISTER_BUFFERS = 1, - IORING_REGISTER_FILES = 2, - IORING_UNREGISTER_FILES = 3, - IORING_REGISTER_EVENTFD = 4, - IORING_UNREGISTER_EVENTFD = 5, - IORING_REGISTER_FILES_UPDATE = 6, - IORING_REGISTER_EVENTFD_ASYNC = 7, - IORING_REGISTER_PROBE = 8, - IORING_REGISTER_PERSONALITY = 9, - IORING_UNREGISTER_PERSONALITY = 10, - IORING_REGISTER_RESTRICTIONS = 11, - IORING_REGISTER_ENABLE_RINGS = 12, - IORING_REGISTER_FILES2 = 13, - IORING_REGISTER_FILES_UPDATE2 = 14, - IORING_REGISTER_BUFFERS2 = 15, - IORING_REGISTER_BUFFERS_UPDATE = 16, - IORING_REGISTER_IOWQ_AFF = 17, - IORING_UNREGISTER_IOWQ_AFF = 18, - IORING_REGISTER_LAST = 19, -}; - -struct io_uring_rsrc_register { - __u32 nr; - __u32 resv; - __u64 resv2; - __u64 data; - __u64 tags; -}; - -struct io_uring_rsrc_update2 { - __u32 offset; - __u32 resv; - __u64 data; - __u64 tags; - __u32 nr; - __u32 resv2; -}; - -struct io_uring_probe_op { - __u8 op; - __u8 resv; - __u16 flags; - __u32 resv2; -}; - -struct io_uring_probe { - __u8 last_op; - __u8 ops_len; - __u16 resv; - __u32 resv2[3]; - struct io_uring_probe_op ops[0]; -}; - -struct io_uring_restriction { - __u16 opcode; - union { - __u8 register_op; - __u8 sqe_op; - __u8 sqe_flags; - }; - __u8 resv; - __u32 resv2[3]; -}; - -enum { - IORING_RESTRICTION_REGISTER_OP = 0, - IORING_RESTRICTION_SQE_OP = 1, - IORING_RESTRICTION_SQE_FLAGS_ALLOWED = 2, - IORING_RESTRICTION_SQE_FLAGS_REQUIRED = 3, - IORING_RESTRICTION_LAST = 4, -}; - -struct io_uring_getevents_arg { - __u64 sigmask; - __u32 sigmask_sz; - __u32 pad; - __u64 ts; -}; - -enum { - IO_WQ_WORK_CANCEL = 1, - IO_WQ_WORK_HASHED = 2, - IO_WQ_WORK_UNBOUND = 4, - IO_WQ_WORK_CONCURRENT = 16, - IO_WQ_HASH_SHIFT = 24, -}; - -enum io_wq_cancel { - IO_WQ_CANCEL_OK = 0, - IO_WQ_CANCEL_RUNNING = 1, - IO_WQ_CANCEL_NOTFOUND = 2, -}; - -typedef struct io_wq_work *free_work_fn(struct io_wq_work *); - -typedef void io_wq_work_fn(struct io_wq_work *); - -struct io_wq_hash { - refcount_t refs; - long unsigned int map; - struct wait_queue_head wait; -}; - -struct io_wq_data { - struct io_wq_hash *hash; - struct task_struct *task; - io_wq_work_fn *do_work; - free_work_fn *free_work; -}; - -typedef bool work_cancel_fn(struct io_wq_work *, void *); - -struct io_uring { - u32 head; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 tail; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct io_rings { - struct io_uring sq; - struct io_uring cq; - u32 sq_ring_mask; - u32 cq_ring_mask; - u32 sq_ring_entries; - u32 cq_ring_entries; - u32 sq_dropped; - u32 sq_flags; - u32 cq_flags; - u32 cq_overflow; - long: 64; - long: 64; - long: 64; - long: 64; - struct io_uring_cqe cqes[0]; -}; - -enum io_uring_cmd_flags { - IO_URING_F_NONBLOCK = 1, - IO_URING_F_COMPLETE_DEFER = 2, -}; - -struct io_mapped_ubuf { - u64 ubuf; - u64 ubuf_end; - unsigned int nr_bvecs; - long unsigned int acct_pages; - struct bio_vec bvec[0]; -}; - -struct io_overflow_cqe { - struct io_uring_cqe cqe; - struct list_head list; -}; - -struct io_fixed_file { - long unsigned int file_ptr; -}; - -struct io_rsrc_put { - struct list_head list; - u64 tag; - union { - void *rsrc; - struct file *file; - struct io_mapped_ubuf *buf; - }; -}; - -struct io_file_table { - struct io_fixed_file **files; -}; - -struct io_rsrc_data; - -struct io_rsrc_node { - struct percpu_ref refs; - struct list_head node; - struct list_head rsrc_list; - struct io_rsrc_data *rsrc_data; - struct llist_node llist; - bool done; -}; - -typedef void rsrc_put_fn(struct io_ring_ctx *, struct io_rsrc_put *); - -struct io_rsrc_data { - struct io_ring_ctx *ctx; - u64 **tags; - unsigned int nr; - rsrc_put_fn *do_put; - atomic_t refs; - struct completion done; - bool quiesce; -}; - -struct io_kiocb; - -struct io_submit_link { - struct io_kiocb *head; - struct io_kiocb *last; -}; - -struct io_comp_state { - struct io_kiocb *reqs[32]; - unsigned int nr; - struct list_head free_list; -}; - -struct io_submit_state { - struct blk_plug plug; - struct io_submit_link link; - void *reqs[32]; - unsigned int free_reqs; - bool plug_started; - struct io_comp_state comp; - struct file *file; - unsigned int fd; - unsigned int file_refs; - unsigned int ios_left; -}; - -struct io_restriction { - long unsigned int register_op[1]; - long unsigned int sqe_op[1]; - u8 sqe_flags_allowed; - u8 sqe_flags_required; - bool registered; -}; - -struct io_sq_data; - -struct io_ring_ctx { - struct { - struct percpu_ref refs; - struct io_rings *rings; - unsigned int flags; - unsigned int compat: 1; - unsigned int drain_next: 1; - unsigned int eventfd_async: 1; - unsigned int restricted: 1; - unsigned int off_timeout_used: 1; - unsigned int drain_active: 1; - long: 26; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - struct mutex uring_lock; - u32 *sq_array; - struct io_uring_sqe *sq_sqes; - unsigned int cached_sq_head; - unsigned int sq_entries; - struct list_head defer_list; - struct io_rsrc_node *rsrc_node; - struct io_file_table file_table; - unsigned int nr_user_files; - unsigned int nr_user_bufs; - struct io_mapped_ubuf **user_bufs; - struct io_submit_state submit_state; - struct list_head timeout_list; - struct list_head cq_overflow_list; - struct xarray io_buffers; - struct xarray personalities; - u32 pers_next; - unsigned int sq_thread_idle; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct list_head locked_free_list; - unsigned int locked_free_nr; - const struct cred *sq_creds; - struct io_sq_data *sq_data; - struct wait_queue_head sqo_sq_wait; - struct list_head sqd_list; - long unsigned int check_cq_overflow; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct { - unsigned int cached_cq_tail; - unsigned int cq_entries; - struct eventfd_ctx *cq_ev_fd; - struct wait_queue_head poll_wait; - struct wait_queue_head cq_wait; - unsigned int cq_extra; - atomic_t cq_timeouts; - struct fasync_struct *cq_fasync; - unsigned int cq_last_tm_flush; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - }; - struct { - spinlock_t completion_lock; - struct list_head iopoll_list; - struct hlist_head *cancel_hash; - unsigned int cancel_hash_bits; - bool poll_multi_queue; - long: 24; - long: 64; - long: 64; - long: 64; - }; - struct io_restriction restrictions; - struct { - struct io_rsrc_node *rsrc_backup_node; - struct io_mapped_ubuf *dummy_ubuf; - struct io_rsrc_data *file_data; - struct io_rsrc_data *buf_data; - struct delayed_work rsrc_put_work; - struct llist_head rsrc_put_llist; - struct list_head rsrc_ref_list; - spinlock_t rsrc_ref_lock; - }; - struct { - struct socket *ring_sock; - struct io_wq_hash *hash_map; - struct user_struct *user; - struct mm_struct *mm_account; - struct llist_head fallback_llist; - struct delayed_work fallback_work; - struct work_struct exit_work; - struct list_head tctx_list; - struct completion ref_comp; - }; -}; - -struct io_buffer { - struct list_head list; - __u64 addr; - __u32 len; - __u16 bid; -}; - -enum { - IO_SQ_THREAD_SHOULD_STOP = 0, - IO_SQ_THREAD_SHOULD_PARK = 1, -}; - -struct io_sq_data { - refcount_t refs; - atomic_t park_pending; - struct mutex lock; - struct list_head ctx_list; - struct task_struct *thread; - struct wait_queue_head wait; - unsigned int sq_thread_idle; - int sq_cpu; - pid_t task_pid; - pid_t task_tgid; - long unsigned int state; - struct completion exited; -}; - -struct io_rw { - struct kiocb kiocb; - u64 addr; - u64 len; -}; - -struct io_poll_iocb { - struct file *file; - struct wait_queue_head *head; - __poll_t events; - bool done; - bool canceled; - struct wait_queue_entry wait; -}; - -struct io_poll_update { - struct file *file; - u64 old_user_data; - u64 new_user_data; - __poll_t events; - bool update_events; - bool update_user_data; -}; - -struct io_accept { - struct file *file; - struct sockaddr *addr; - int *addr_len; - int flags; - long unsigned int nofile; -}; - -struct io_sync { - struct file *file; - loff_t len; - loff_t off; - int flags; - int mode; -}; - -struct io_cancel { - struct file *file; - u64 addr; -}; - -struct io_timeout { - struct file *file; - u32 off; - u32 target_seq; - struct list_head list; - struct io_kiocb *head; -}; - -struct io_timeout_rem { - struct file *file; - u64 addr; - struct timespec64 ts; - u32 flags; -}; - -struct io_connect { - struct file *file; - struct sockaddr *addr; - int addr_len; -}; - -struct io_sr_msg { - struct file *file; - union { - struct compat_msghdr *umsg_compat; - struct user_msghdr *umsg; - void *buf; - }; - int msg_flags; - int bgid; - size_t len; - struct io_buffer *kbuf; -}; - -struct io_open { - struct file *file; - int dfd; - struct filename *filename; - struct open_how how; - long unsigned int nofile; -}; - -struct io_close { - struct file *file; - int fd; -}; - -struct io_rsrc_update { - struct file *file; - u64 arg; - u32 nr_args; - u32 offset; -}; - -struct io_fadvise { - struct file *file; - u64 offset; - u32 len; - u32 advice; -}; - -struct io_madvise { - struct file *file; - u64 addr; - u32 len; - u32 advice; -}; - -struct io_epoll { - struct file *file; - int epfd; - int op; - int fd; - struct epoll_event event; -} __attribute__((packed)); - -struct io_splice { - struct file *file_out; - struct file *file_in; - loff_t off_out; - loff_t off_in; - u64 len; - unsigned int flags; -}; - -struct io_provide_buf { - struct file *file; - __u64 addr; - __u32 len; - __u32 bgid; - __u16 nbufs; - __u16 bid; -}; - -struct io_statx { - struct file *file; - int dfd; - unsigned int mask; - unsigned int flags; - const char *filename; - struct statx *buffer; -}; - -struct io_shutdown { - struct file *file; - int how; -}; - -struct io_rename { - struct file *file; - int old_dfd; - int new_dfd; - struct filename *oldpath; - struct filename *newpath; - int flags; -}; - -struct io_unlink { - struct file *file; - int dfd; - int flags; - struct filename *filename; -}; - -struct io_completion { - struct file *file; - struct list_head list; - u32 cflags; -}; - -typedef void (*io_req_tw_func_t)(struct io_kiocb *); - -struct io_task_work { - union { - struct io_wq_work_node node; - struct llist_node fallback_node; - }; - io_req_tw_func_t func; -}; - -struct async_poll; - -struct io_kiocb { - union { - struct file *file; - struct io_rw rw; - struct io_poll_iocb poll; - struct io_poll_update poll_update; - struct io_accept accept; - struct io_sync sync; - struct io_cancel cancel; - struct io_timeout timeout; - struct io_timeout_rem timeout_rem; - struct io_connect connect; - struct io_sr_msg sr_msg; - struct io_open open; - struct io_close close; - struct io_rsrc_update rsrc_update; - struct io_fadvise fadvise; - struct io_madvise madvise; - struct io_epoll epoll; - struct io_splice splice; - struct io_provide_buf pbuf; - struct io_statx statx; - struct io_shutdown shutdown; - struct io_rename rename; - struct io_unlink unlink; - struct io_completion compl; - }; - void *async_data; - u8 opcode; - u8 iopoll_completed; - u16 buf_index; - u32 result; - struct io_ring_ctx *ctx; - unsigned int flags; - atomic_t refs; - struct task_struct *task; - u64 user_data; - struct io_kiocb *link; - struct percpu_ref *fixed_rsrc_refs; - struct list_head inflight_entry; - struct io_task_work io_task_work; - struct hlist_node hash_node; - struct async_poll *apoll; - struct io_wq_work work; - const struct cred *creds; - struct io_mapped_ubuf *imu; -}; - -struct io_timeout_data { - struct io_kiocb *req; - struct hrtimer timer; - struct timespec64 ts; - enum hrtimer_mode mode; -}; - -struct io_async_connect { - struct __kernel_sockaddr_storage address; -}; - -struct io_async_msghdr { - struct iovec fast_iov[8]; - struct iovec *free_iov; - struct sockaddr *uaddr; - struct msghdr msg; - struct __kernel_sockaddr_storage addr; -}; - -struct io_async_rw { - struct iovec fast_iov[8]; - const struct iovec *free_iovec; - struct iov_iter iter; - size_t bytes_done; - struct wait_page_queue wpq; -}; - -enum { - REQ_F_FIXED_FILE_BIT = 0, - REQ_F_IO_DRAIN_BIT = 1, - REQ_F_LINK_BIT = 2, - REQ_F_HARDLINK_BIT = 3, - REQ_F_FORCE_ASYNC_BIT = 4, - REQ_F_BUFFER_SELECT_BIT = 5, - REQ_F_FAIL_BIT = 8, - REQ_F_INFLIGHT_BIT = 9, - REQ_F_CUR_POS_BIT = 10, - REQ_F_NOWAIT_BIT = 11, - REQ_F_LINK_TIMEOUT_BIT = 12, - REQ_F_NEED_CLEANUP_BIT = 13, - REQ_F_POLLED_BIT = 14, - REQ_F_BUFFER_SELECTED_BIT = 15, - REQ_F_LTIMEOUT_ACTIVE_BIT = 16, - REQ_F_COMPLETE_INLINE_BIT = 17, - REQ_F_REISSUE_BIT = 18, - REQ_F_DONT_REISSUE_BIT = 19, - REQ_F_CREDS_BIT = 20, - REQ_F_ASYNC_READ_BIT = 21, - REQ_F_ASYNC_WRITE_BIT = 22, - REQ_F_ISREG_BIT = 23, - __REQ_F_LAST_BIT = 24, -}; - -enum { - REQ_F_FIXED_FILE = 1, - REQ_F_IO_DRAIN = 2, - REQ_F_LINK = 4, - REQ_F_HARDLINK = 8, - REQ_F_FORCE_ASYNC = 16, - REQ_F_BUFFER_SELECT = 32, - REQ_F_FAIL = 256, - REQ_F_INFLIGHT = 512, - REQ_F_CUR_POS = 1024, - REQ_F_NOWAIT = 2048, - REQ_F_LINK_TIMEOUT = 4096, - REQ_F_NEED_CLEANUP = 8192, - REQ_F_POLLED = 16384, - REQ_F_BUFFER_SELECTED = 32768, - REQ_F_LTIMEOUT_ACTIVE = 65536, - REQ_F_COMPLETE_INLINE = 131072, - REQ_F_REISSUE = 262144, - REQ_F_DONT_REISSUE = 524288, - REQ_F_ASYNC_READ = 2097152, - REQ_F_ASYNC_WRITE = 4194304, - REQ_F_ISREG = 8388608, - REQ_F_CREDS = 1048576, -}; - -struct async_poll { - struct io_poll_iocb poll; - struct io_poll_iocb *double_poll; -}; - -enum { - IORING_RSRC_FILE = 0, - IORING_RSRC_BUFFER = 1, -}; - -struct io_tctx_node { - struct list_head ctx_node; - struct task_struct *task; - struct io_ring_ctx *ctx; -}; - -struct io_defer_entry { - struct list_head list; - struct io_kiocb *req; - u32 seq; -}; - -struct io_op_def { - unsigned int needs_file: 1; - unsigned int hash_reg_file: 1; - unsigned int unbound_nonreg_file: 1; - unsigned int not_supported: 1; - unsigned int pollin: 1; - unsigned int pollout: 1; - unsigned int buffer_select: 1; - unsigned int needs_async_setup: 1; - unsigned int plug: 1; - short unsigned int async_size; -}; - -struct req_batch { - struct task_struct *task; - int task_refs; - int ctx_refs; -}; - -struct io_poll_table { - struct poll_table_struct pt; - struct io_kiocb *req; - int nr_entries; - int error; -}; - -enum { - IO_APOLL_OK = 0, - IO_APOLL_ABORTED = 1, - IO_APOLL_READY = 2, -}; - -struct io_cancel_data { - struct io_ring_ctx *ctx; - u64 user_data; -}; - -struct io_wait_queue { - struct wait_queue_entry wq; - struct io_ring_ctx *ctx; - unsigned int to_wait; - unsigned int nr_timeouts; -}; - -struct io_tctx_exit { - struct callback_head task_work; - struct completion completion; - struct io_ring_ctx *ctx; -}; - -struct io_task_cancel { - struct task_struct *task; - bool all; -}; - -struct creds; - -enum { - IO_WORKER_F_UP = 1, - IO_WORKER_F_RUNNING = 2, - IO_WORKER_F_FREE = 4, - IO_WORKER_F_FIXED = 8, - IO_WORKER_F_BOUND = 16, -}; - -enum { - IO_WQ_BIT_EXIT = 0, -}; - -enum { - IO_WQE_FLAG_STALLED = 1, -}; - -struct io_wqe; - -struct io_worker { - refcount_t ref; - unsigned int flags; - struct hlist_nulls_node nulls_node; - struct list_head all_list; - struct task_struct *task; - struct io_wqe *wqe; - struct io_wq_work *cur_work; - spinlock_t lock; - struct completion ref_done; - struct callback_head rcu; -}; - -struct io_wqe_acct { - unsigned int nr_workers; - unsigned int max_workers; - int index; - atomic_t nr_running; -}; - -struct io_wq___2; - -struct io_wqe { - struct { - raw_spinlock_t lock; - struct io_wq_work_list work_list; - unsigned int flags; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - }; - int node; - struct io_wqe_acct acct[2]; - struct hlist_nulls_head free_list; - struct list_head all_list; - struct wait_queue_entry wait; - struct io_wq___2 *wq; - struct io_wq_work *hash_tail[64]; - cpumask_var_t cpu_mask; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -enum { - IO_WQ_ACCT_BOUND = 0, - IO_WQ_ACCT_UNBOUND = 1, -}; - -struct io_wq___2 { - long unsigned int state; - free_work_fn *free_work; - io_wq_work_fn *do_work; - struct io_wq_hash *hash; - atomic_t worker_refs; - struct completion worker_done; - struct hlist_node cpuhp_node; - struct task_struct *task; - struct io_wqe *wqes[0]; -}; - -struct io_cb_cancel_data { - work_cancel_fn *fn; - void *data; - int nr_running; - int nr_pending; - bool cancel_all; -}; - -struct create_worker_data { - struct callback_head work; - struct io_wqe *wqe; - int index; -}; - -struct online_data { - unsigned int cpu; - bool online; -}; - -struct iomap_ops { - int (*iomap_begin)(struct inode *, loff_t, loff_t, unsigned int, struct iomap___2 *, struct iomap___2 *); - int (*iomap_end)(struct inode *, loff_t, loff_t, ssize_t, unsigned int, struct iomap___2 *); -}; - -typedef loff_t (*iomap_actor_t)(struct inode *, loff_t, loff_t, void *, struct iomap___2 *, struct iomap___2 *); - -struct trace_event_raw_dax_pmd_fault_class { - struct trace_entry ent; - long unsigned int ino; - long unsigned int vm_start; - long unsigned int vm_end; - long unsigned int vm_flags; - long unsigned int address; - long unsigned int pgoff; - long unsigned int max_pgoff; - dev_t dev; - unsigned int flags; - int result; - char __data[0]; -}; - -struct trace_event_raw_dax_pmd_load_hole_class { - struct trace_entry ent; - long unsigned int ino; - long unsigned int vm_flags; - long unsigned int address; - struct page *zero_page; - void *radix_entry; - dev_t dev; - char __data[0]; -}; - -struct trace_event_raw_dax_pmd_insert_mapping_class { - struct trace_entry ent; - long unsigned int ino; - long unsigned int vm_flags; - long unsigned int address; - long int length; - u64 pfn_val; - void *radix_entry; - dev_t dev; - int write; - char __data[0]; -}; - -struct trace_event_raw_dax_pte_fault_class { - struct trace_entry ent; - long unsigned int ino; - long unsigned int vm_flags; - long unsigned int address; - long unsigned int pgoff; - dev_t dev; - unsigned int flags; - int result; - char __data[0]; -}; - -struct trace_event_raw_dax_insert_mapping { - struct trace_entry ent; - long unsigned int ino; - long unsigned int vm_flags; - long unsigned int address; - void *radix_entry; - dev_t dev; - int write; - char __data[0]; -}; - -struct trace_event_raw_dax_writeback_range_class { - struct trace_entry ent; - long unsigned int ino; - long unsigned int start_index; - long unsigned int end_index; - dev_t dev; - char __data[0]; -}; - -struct trace_event_raw_dax_writeback_one { - struct trace_entry ent; - long unsigned int ino; - long unsigned int pgoff; - long unsigned int pglen; - dev_t dev; - char __data[0]; -}; - -struct trace_event_data_offsets_dax_pmd_fault_class {}; - -struct trace_event_data_offsets_dax_pmd_load_hole_class {}; - -struct trace_event_data_offsets_dax_pmd_insert_mapping_class {}; - -struct trace_event_data_offsets_dax_pte_fault_class {}; - -struct trace_event_data_offsets_dax_insert_mapping {}; - -struct trace_event_data_offsets_dax_writeback_range_class {}; - -struct trace_event_data_offsets_dax_writeback_one {}; - -typedef void (*btf_trace_dax_pmd_fault)(void *, struct inode *, struct vm_fault *, long unsigned int, int); - -typedef void (*btf_trace_dax_pmd_fault_done)(void *, struct inode *, struct vm_fault *, long unsigned int, int); - -typedef void (*btf_trace_dax_pmd_load_hole)(void *, struct inode *, struct vm_fault *, struct page *, void *); - -typedef void (*btf_trace_dax_pmd_load_hole_fallback)(void *, struct inode *, struct vm_fault *, struct page *, void *); - -typedef void (*btf_trace_dax_pmd_insert_mapping)(void *, struct inode *, struct vm_fault *, long int, pfn_t, void *); - -typedef void (*btf_trace_dax_pte_fault)(void *, struct inode *, struct vm_fault *, int); - -typedef void (*btf_trace_dax_pte_fault_done)(void *, struct inode *, struct vm_fault *, int); - -typedef void (*btf_trace_dax_load_hole)(void *, struct inode *, struct vm_fault *, int); - -typedef void (*btf_trace_dax_insert_pfn_mkwrite_no_entry)(void *, struct inode *, struct vm_fault *, int); - -typedef void (*btf_trace_dax_insert_pfn_mkwrite)(void *, struct inode *, struct vm_fault *, int); - -typedef void (*btf_trace_dax_insert_mapping)(void *, struct inode *, struct vm_fault *, void *); - -typedef void (*btf_trace_dax_writeback_range)(void *, struct inode *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_dax_writeback_range_done)(void *, struct inode *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_dax_writeback_one)(void *, struct inode *, long unsigned int, long unsigned int); - -struct exceptional_entry_key { - struct xarray *xa; - long unsigned int entry_start; -}; - -struct wait_exceptional_entry_queue { - wait_queue_entry_t wait; - struct exceptional_entry_key key; -}; - -enum dax_wake_mode { - WAKE_ALL = 0, - WAKE_NEXT = 1, -}; - -struct crypto_skcipher; - -struct fscrypt_blk_crypto_key; - -struct fscrypt_prepared_key { - struct crypto_skcipher *tfm; - struct fscrypt_blk_crypto_key *blk_key; -}; - -struct fscrypt_mode; - -struct fscrypt_direct_key; - -struct fscrypt_info { - struct fscrypt_prepared_key ci_enc_key; - bool ci_owns_key; - bool ci_inlinecrypt; - struct fscrypt_mode *ci_mode; - struct inode *ci_inode; - struct key *ci_master_key; - struct list_head ci_master_key_link; - struct fscrypt_direct_key *ci_direct_key; - siphash_key_t ci_dirhash_key; - bool ci_dirhash_key_initialized; - union fscrypt_policy ci_policy; - u8 ci_nonce[16]; - u32 ci_hashed_ino; -}; - -struct skcipher_request { - unsigned int cryptlen; - u8 *iv; - struct scatterlist *src; - struct scatterlist *dst; - struct crypto_async_request base; - void *__ctx[0]; -}; - -struct crypto_skcipher { - unsigned int reqsize; - struct crypto_tfm base; -}; - -struct fscrypt_mode { - const char *friendly_name; - const char *cipher_str; - int keysize; - int ivsize; - int logged_impl_name; - enum blk_crypto_mode_num blk_crypto_mode; -}; - -typedef enum { - FS_DECRYPT = 0, - FS_ENCRYPT = 1, -} fscrypt_direction_t; - -union fscrypt_iv { - struct { - __le64 lblk_num; - u8 nonce[16]; - }; - u8 raw[32]; - __le64 dun[4]; -}; - -struct fscrypt_str { - unsigned char *name; - u32 len; -}; - -struct fscrypt_name { - const struct qstr *usr_fname; - struct fscrypt_str disk_name; - u32 hash; - u32 minor_hash; - struct fscrypt_str crypto_buf; - bool is_nokey_name; -}; - -struct fscrypt_nokey_name { - u32 dirhash[2]; - u8 bytes[149]; - u8 sha256[32]; -}; - -struct fscrypt_hkdf { - struct crypto_shash *hmac_tfm; -}; - -struct fscrypt_key_specifier { - __u32 type; - __u32 __reserved; - union { - __u8 __reserved[32]; - __u8 descriptor[8]; - __u8 identifier[16]; - } u; -}; - -struct fscrypt_symlink_data { - __le16 len; - char encrypted_path[1]; -} __attribute__((packed)); - -struct fscrypt_master_key_secret { - struct fscrypt_hkdf hkdf; - u32 size; - u8 raw[64]; -}; - -struct fscrypt_master_key { - struct fscrypt_master_key_secret mk_secret; - struct fscrypt_key_specifier mk_spec; - struct key *mk_users; - refcount_t mk_refcount; - struct list_head mk_decrypted_inodes; - spinlock_t mk_decrypted_inodes_lock; - struct fscrypt_prepared_key mk_direct_keys[10]; - struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[10]; - struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[10]; - siphash_key_t mk_ino_hash_key; - bool mk_ino_hash_key_initialized; -}; - -enum key_state { - KEY_IS_UNINSTANTIATED = 0, - KEY_IS_POSITIVE = 1, -}; - -struct fscrypt_provisioning_key_payload { - __u32 type; - __u32 __reserved; - __u8 raw[0]; -}; - -struct fscrypt_add_key_arg { - struct fscrypt_key_specifier key_spec; - __u32 raw_size; - __u32 key_id; - __u32 __reserved[8]; - __u8 raw[0]; -}; - -struct fscrypt_remove_key_arg { - struct fscrypt_key_specifier key_spec; - __u32 removal_status_flags; - __u32 __reserved[5]; -}; - -struct fscrypt_get_key_status_arg { - struct fscrypt_key_specifier key_spec; - __u32 __reserved[6]; - __u32 status; - __u32 status_flags; - __u32 user_count; - __u32 __out_reserved[13]; -}; - -struct skcipher_alg { - int (*setkey)(struct crypto_skcipher *, const u8 *, unsigned int); - int (*encrypt)(struct skcipher_request *); - int (*decrypt)(struct skcipher_request *); - int (*init)(struct crypto_skcipher *); - void (*exit)(struct crypto_skcipher *); - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; - unsigned int chunksize; - unsigned int walksize; - struct crypto_alg base; -}; - -struct fscrypt_context_v1 { - u8 version; - u8 contents_encryption_mode; - u8 filenames_encryption_mode; - u8 flags; - u8 master_key_descriptor[8]; - u8 nonce[16]; -}; - -struct fscrypt_context_v2 { - u8 version; - u8 contents_encryption_mode; - u8 filenames_encryption_mode; - u8 flags; - u8 __reserved[4]; - u8 master_key_identifier[16]; - u8 nonce[16]; -}; - -union fscrypt_context { - u8 version; - struct fscrypt_context_v1 v1; - struct fscrypt_context_v2 v2; -}; - -struct crypto_template; - -struct crypto_spawn; - -struct crypto_instance { - struct crypto_alg alg; - struct crypto_template *tmpl; - union { - struct hlist_node list; - struct crypto_spawn *spawns; - }; - void *__ctx[0]; -}; - -struct crypto_spawn { - struct list_head list; - struct crypto_alg *alg; - union { - struct crypto_instance *inst; - struct crypto_spawn *next; - }; - const struct crypto_type *frontend; - u32 mask; - bool dead; - bool registered; -}; - -struct rtattr; - -struct crypto_template { - struct list_head list; - struct hlist_head instances; - struct module *module; - int (*create)(struct crypto_template *, struct rtattr **); - char name[128]; -}; - -struct user_key_payload { - struct callback_head rcu; - short unsigned int datalen; - long: 48; - char data[0]; -}; - -struct fscrypt_key { - __u32 mode; - __u8 raw[64]; - __u32 size; -}; - -struct fscrypt_direct_key { - struct hlist_node dk_node; - refcount_t dk_refcount; - const struct fscrypt_mode *dk_mode; - struct fscrypt_prepared_key dk_key; - u8 dk_descriptor[8]; - u8 dk_raw[64]; -}; - -struct fscrypt_get_policy_ex_arg { - __u64 policy_size; - union { - __u8 version; - struct fscrypt_policy_v1 v1; - struct fscrypt_policy_v2 v2; - } policy; -}; - -struct fscrypt_dummy_policy { - const union fscrypt_policy *policy; -}; - -struct fscrypt_blk_crypto_key { - struct blk_crypto_key base; - int num_devs; - struct request_queue *devs[0]; -}; - -struct fsverity_hash_alg; - -struct merkle_tree_params { - struct fsverity_hash_alg *hash_alg; - const u8 *hashstate; - unsigned int digest_size; - unsigned int block_size; - unsigned int hashes_per_block; - unsigned int log_blocksize; - unsigned int log_arity; - unsigned int num_levels; - u64 tree_size; - long unsigned int level0_blocks; - u64 level_start[8]; -}; - -struct fsverity_info { - struct merkle_tree_params tree_params; - u8 root_hash[64]; - u8 file_digest[64]; - const struct inode *inode; -}; - -struct fsverity_enable_arg { - __u32 version; - __u32 hash_algorithm; - __u32 block_size; - __u32 salt_size; - __u64 salt_ptr; - __u32 sig_size; - __u32 __reserved1; - __u64 sig_ptr; - __u64 __reserved2[11]; -}; - -struct fsverity_descriptor { - __u8 version; - __u8 hash_algorithm; - __u8 log_blocksize; - __u8 salt_size; - __le32 sig_size; - __le64 data_size; - __u8 root_hash[64]; - __u8 salt[32]; - __u8 __reserved[144]; - __u8 signature[0]; -}; - -struct crypto_ahash; - -struct fsverity_hash_alg { - struct crypto_ahash *tfm; - const char *name; - unsigned int digest_size; - unsigned int block_size; - mempool_t req_pool; -}; - -struct ahash_request; - -struct crypto_ahash { - int (*init)(struct ahash_request *); - int (*update)(struct ahash_request *); - int (*final)(struct ahash_request *); - int (*finup)(struct ahash_request *); - int (*digest)(struct ahash_request *); - int (*export)(struct ahash_request *, void *); - int (*import)(struct ahash_request *, const void *); - int (*setkey)(struct crypto_ahash *, const u8 *, unsigned int); - unsigned int reqsize; - struct crypto_tfm base; -}; - -struct ahash_request { - struct crypto_async_request base; - unsigned int nbytes; - struct scatterlist *src; - u8 *result; - void *priv; - void *__ctx[0]; -}; - -struct hash_alg_common { - unsigned int digestsize; - unsigned int statesize; - struct crypto_alg base; -}; - -struct fsverity_digest { - __u16 digest_algorithm; - __u16 digest_size; - __u8 digest[0]; -}; - -struct fsverity_read_metadata_arg { - __u64 metadata_type; - __u64 offset; - __u64 length; - __u64 buf_ptr; - __u64 __reserved; -}; - -struct fsverity_formatted_digest { - char magic[8]; - __le16 digest_algorithm; - __le16 digest_size; - __u8 digest[0]; -}; - -struct flock64 { - short int l_type; - short int l_whence; - __kernel_loff_t l_start; - __kernel_loff_t l_len; - __kernel_pid_t l_pid; -}; - -struct trace_event_raw_locks_get_lock_context { - struct trace_entry ent; - long unsigned int i_ino; - dev_t s_dev; - unsigned char type; - struct file_lock_context *ctx; - char __data[0]; -}; - -struct trace_event_raw_filelock_lock { - struct trace_entry ent; - struct file_lock *fl; - long unsigned int i_ino; - dev_t s_dev; - struct file_lock *fl_blocker; - fl_owner_t fl_owner; - unsigned int fl_pid; - unsigned int fl_flags; - unsigned char fl_type; - loff_t fl_start; - loff_t fl_end; - int ret; - char __data[0]; -}; - -struct trace_event_raw_filelock_lease { - struct trace_entry ent; - struct file_lock *fl; - long unsigned int i_ino; - dev_t s_dev; - struct file_lock *fl_blocker; - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - long unsigned int fl_break_time; - long unsigned int fl_downgrade_time; - char __data[0]; -}; - -struct trace_event_raw_generic_add_lease { - struct trace_entry ent; - long unsigned int i_ino; - int wcount; - int rcount; - int icount; - dev_t s_dev; - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - char __data[0]; -}; - -struct trace_event_raw_leases_conflict { - struct trace_entry ent; - void *lease; - void *breaker; - unsigned int l_fl_flags; - unsigned int b_fl_flags; - unsigned char l_fl_type; - unsigned char b_fl_type; - bool conflict; - char __data[0]; -}; - -struct trace_event_data_offsets_locks_get_lock_context {}; - -struct trace_event_data_offsets_filelock_lock {}; - -struct trace_event_data_offsets_filelock_lease {}; - -struct trace_event_data_offsets_generic_add_lease {}; - -struct trace_event_data_offsets_leases_conflict {}; - -typedef void (*btf_trace_locks_get_lock_context)(void *, struct inode *, int, struct file_lock_context *); - -typedef void (*btf_trace_posix_lock_inode)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_fcntl_setlk)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_locks_remove_posix)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_flock_lock_inode)(void *, struct inode *, struct file_lock *, int); - -typedef void (*btf_trace_break_lease_noblock)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_break_lease_block)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_break_lease_unblock)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_generic_delete_lease)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_time_out_leases)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_generic_add_lease)(void *, struct inode *, struct file_lock *); - -typedef void (*btf_trace_leases_conflict)(void *, bool, struct file_lock *, struct file_lock *); - -struct file_lock_list_struct { - spinlock_t lock; - struct hlist_head hlist; -}; - -struct locks_iterator { - int li_cpu; - loff_t li_pos; -}; - -enum { - VERBOSE_STATUS = 1, -}; - -enum { - Enabled = 0, - Magic = 1, -}; - -typedef struct { - struct list_head list; - long unsigned int flags; - int offset; - int size; - char *magic; - char *mask; - const char *interpreter; - char *name; - struct dentry *dentry; - struct file *interp_file; -} Node; - -typedef unsigned int __kernel_uid_t; - -typedef unsigned int __kernel_gid_t; - -struct elf_prpsinfo { - char pr_state; - char pr_sname; - char pr_zomb; - char pr_nice; - long unsigned int pr_flag; - __kernel_uid_t pr_uid; - __kernel_gid_t pr_gid; - pid_t pr_pid; - pid_t pr_ppid; - pid_t pr_pgrp; - pid_t pr_sid; - char pr_fname[16]; - char pr_psargs[80]; -}; - -struct core_vma_metadata { - long unsigned int start; - long unsigned int end; - long unsigned int flags; - long unsigned int dump_size; -}; - -struct arch_elf_state {}; - -struct memelfnote { - const char *name; - int type; - unsigned int datasz; - void *data; -}; - -struct elf_thread_core_info { - struct elf_thread_core_info *next; - struct task_struct *task; - struct elf_prstatus prstatus; - struct memelfnote notes[0]; -}; - -struct elf_note_info { - struct elf_thread_core_info *thread; - struct memelfnote psinfo; - struct memelfnote signote; - struct memelfnote auxv; - struct memelfnote files; - siginfo_t csigdata; - size_t size; - int thread_notes; -}; - -struct user_regs_struct { - long unsigned int r15; - long unsigned int r14; - long unsigned int r13; - long unsigned int r12; - long unsigned int bp; - long unsigned int bx; - long unsigned int r11; - long unsigned int r10; - long unsigned int r9; - long unsigned int r8; - long unsigned int ax; - long unsigned int cx; - long unsigned int dx; - long unsigned int si; - long unsigned int di; - long unsigned int orig_ax; - long unsigned int ip; - long unsigned int cs; - long unsigned int flags; - long unsigned int sp; - long unsigned int ss; - long unsigned int fs_base; - long unsigned int gs_base; - long unsigned int ds; - long unsigned int es; - long unsigned int fs; - long unsigned int gs; -}; - -typedef __u32 Elf32_Addr; - -typedef __u16 Elf32_Half; - -typedef __u32 Elf32_Off; - -struct elf32_hdr { - unsigned char e_ident[16]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -}; - -struct elf32_phdr { - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -}; - -struct elf32_shdr { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -}; - -struct user_regs_struct32 { - __u32 ebx; - __u32 ecx; - __u32 edx; - __u32 esi; - __u32 edi; - __u32 ebp; - __u32 eax; - short unsigned int ds; - short unsigned int __ds; - short unsigned int es; - short unsigned int __es; - short unsigned int fs; - short unsigned int __fs; - short unsigned int gs; - short unsigned int __gs; - __u32 orig_eax; - __u32 eip; - short unsigned int cs; - short unsigned int __cs; - __u32 eflags; - __u32 esp; - short unsigned int ss; - short unsigned int __ss; -}; - -struct compat_elf_siginfo { - compat_int_t si_signo; - compat_int_t si_code; - compat_int_t si_errno; -}; - -struct compat_elf_prstatus_common { - struct compat_elf_siginfo pr_info; - short int pr_cursig; - compat_ulong_t pr_sigpend; - compat_ulong_t pr_sighold; - compat_pid_t pr_pid; - compat_pid_t pr_ppid; - compat_pid_t pr_pgrp; - compat_pid_t pr_sid; - struct old_timeval32 pr_utime; - struct old_timeval32 pr_stime; - struct old_timeval32 pr_cutime; - struct old_timeval32 pr_cstime; -}; - -struct compat_elf_prpsinfo { - char pr_state; - char pr_sname; - char pr_zomb; - char pr_nice; - compat_ulong_t pr_flag; - __compat_uid_t pr_uid; - __compat_gid_t pr_gid; - compat_pid_t pr_pid; - compat_pid_t pr_ppid; - compat_pid_t pr_pgrp; - compat_pid_t pr_sid; - char pr_fname[16]; - char pr_psargs[80]; -}; - -typedef struct user_regs_struct compat_elf_gregset_t; - -struct i386_elf_prstatus { - struct compat_elf_prstatus_common common; - struct user_regs_struct32 pr_reg; - compat_int_t pr_fpvalid; -}; - -struct compat_elf_prstatus { - struct compat_elf_prstatus_common common; - compat_elf_gregset_t pr_reg; - compat_int_t pr_fpvalid; -}; - -struct elf_thread_core_info___2 { - struct elf_thread_core_info___2 *next; - struct task_struct *task; - struct compat_elf_prstatus prstatus; - struct memelfnote notes[0]; -}; - -struct elf_note_info___2 { - struct elf_thread_core_info___2 *thread; - struct memelfnote psinfo; - struct memelfnote signote; - struct memelfnote auxv; - struct memelfnote files; - compat_siginfo_t csigdata; - size_t size; - int thread_notes; -}; - -struct posix_acl_xattr_entry { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -}; - -struct posix_acl_xattr_header { - __le32 a_version; -}; - -struct rpc_timer { - struct list_head list; - long unsigned int expires; - struct delayed_work dwork; -}; - -struct rpc_wait_queue { - spinlock_t lock; - struct list_head tasks[4]; - unsigned char maxpriority; - unsigned char priority; - unsigned char nr; - short unsigned int qlen; - struct rpc_timer timer_list; - const char *name; -}; - -struct nfs_seqid_counter { - ktime_t create_time; - int owner_id; - int flags; - u32 counter; - spinlock_t lock; - struct list_head list; - struct rpc_wait_queue wait; -}; - -struct nfs4_stateid_struct { - union { - char data[16]; - struct { - __be32 seqid; - char other[12]; - }; - }; - enum { - NFS4_INVALID_STATEID_TYPE = 0, - NFS4_SPECIAL_STATEID_TYPE = 1, - NFS4_OPEN_STATEID_TYPE = 2, - NFS4_LOCK_STATEID_TYPE = 3, - NFS4_DELEGATION_STATEID_TYPE = 4, - NFS4_LAYOUT_STATEID_TYPE = 5, - NFS4_PNFS_DS_STATEID_TYPE = 6, - NFS4_REVOKED_STATEID_TYPE = 7, - } type; -}; - -typedef struct nfs4_stateid_struct nfs4_stateid; - -struct nfs4_state; - -struct nfs4_lock_state { - struct list_head ls_locks; - struct nfs4_state *ls_state; - long unsigned int ls_flags; - struct nfs_seqid_counter ls_seqid; - nfs4_stateid ls_stateid; - refcount_t ls_count; - fl_owner_t ls_owner; -}; - -struct xdr_netobj { - unsigned int len; - u8 *data; -}; - -struct xdr_buf { - struct kvec head[1]; - struct kvec tail[1]; - struct bio_vec *bvec; - struct page **pages; - unsigned int page_base; - unsigned int page_len; - unsigned int flags; - unsigned int buflen; - unsigned int len; -}; - -struct rpc_rqst; - -struct xdr_stream { - __be32 *p; - struct xdr_buf *buf; - __be32 *end; - struct kvec *iov; - struct kvec scratch; - struct page **page_ptr; - unsigned int nwords; - struct rpc_rqst *rqst; -}; - -struct rpc_xprt; - -struct rpc_task; - -struct rpc_cred; - -struct rpc_rqst { - struct rpc_xprt *rq_xprt; - struct xdr_buf rq_snd_buf; - struct xdr_buf rq_rcv_buf; - struct rpc_task *rq_task; - struct rpc_cred *rq_cred; - __be32 rq_xid; - int rq_cong; - u32 rq_seqno; - int rq_enc_pages_num; - struct page **rq_enc_pages; - void (*rq_release_snd_buf)(struct rpc_rqst *); - union { - struct list_head rq_list; - struct rb_node rq_recv; - }; - struct list_head rq_xmit; - struct list_head rq_xmit2; - void *rq_buffer; - size_t rq_callsize; - void *rq_rbuffer; - size_t rq_rcvsize; - size_t rq_xmit_bytes_sent; - size_t rq_reply_bytes_recvd; - struct xdr_buf rq_private_buf; - long unsigned int rq_majortimeo; - long unsigned int rq_minortimeo; - long unsigned int rq_timeout; - ktime_t rq_rtt; - unsigned int rq_retries; - unsigned int rq_connect_cookie; - atomic_t rq_pin; - u32 rq_bytes_sent; - ktime_t rq_xtime; - int rq_ntrans; - struct list_head rq_bc_list; - long unsigned int rq_bc_pa_state; - struct list_head rq_bc_pa_list; -}; - -typedef void (*kxdreproc_t)(struct rpc_rqst *, struct xdr_stream *, const void *); - -typedef int (*kxdrdproc_t)(struct rpc_rqst *, struct xdr_stream *, void *); - -struct rpc_procinfo; - -struct rpc_message { - const struct rpc_procinfo *rpc_proc; - void *rpc_argp; - void *rpc_resp; - const struct cred *rpc_cred; -}; - -struct rpc_procinfo { - u32 p_proc; - kxdreproc_t p_encode; - kxdrdproc_t p_decode; - unsigned int p_arglen; - unsigned int p_replen; - unsigned int p_timer; - u32 p_statidx; - const char *p_name; -}; - -struct rpc_wait { - struct list_head list; - struct list_head links; - struct list_head timer_list; -}; - -struct rpc_call_ops; - -struct rpc_clnt; - -struct rpc_task { - atomic_t tk_count; - int tk_status; - struct list_head tk_task; - void (*tk_callback)(struct rpc_task *); - void (*tk_action)(struct rpc_task *); - long unsigned int tk_timeout; - long unsigned int tk_runstate; - struct rpc_wait_queue *tk_waitqueue; - union { - struct work_struct tk_work; - struct rpc_wait tk_wait; - } u; - int tk_rpc_status; - struct rpc_message tk_msg; - void *tk_calldata; - const struct rpc_call_ops *tk_ops; - struct rpc_clnt *tk_client; - struct rpc_xprt *tk_xprt; - struct rpc_cred *tk_op_cred; - struct rpc_rqst *tk_rqstp; - struct workqueue_struct *tk_workqueue; - ktime_t tk_start; - pid_t tk_owner; - short unsigned int tk_flags; - short unsigned int tk_timeouts; - short unsigned int tk_pid; - unsigned char tk_priority: 2; - unsigned char tk_garb_retry: 2; - unsigned char tk_cred_retry: 2; - unsigned char tk_rebind_retry: 2; -}; - -struct rpc_call_ops { - void (*rpc_call_prepare)(struct rpc_task *, void *); - void (*rpc_call_done)(struct rpc_task *, void *); - void (*rpc_count_stats)(struct rpc_task *, void *); - void (*rpc_release)(void *); -}; - -struct rpc_iostats; - -struct rpc_pipe_dir_head { - struct list_head pdh_entries; - struct dentry *pdh_dentry; -}; - -struct rpc_rtt { - long unsigned int timeo; - long unsigned int srtt[5]; - long unsigned int sdrtt[5]; - int ntimeouts[5]; -}; - -struct rpc_timeout { - long unsigned int to_initval; - long unsigned int to_maxval; - long unsigned int to_increment; - unsigned int to_retries; - unsigned char to_exponential; -}; - -struct rpc_sysfs_client; - -struct rpc_xprt_switch; - -struct rpc_xprt_iter_ops; - -struct rpc_xprt_iter { - struct rpc_xprt_switch *xpi_xpswitch; - struct rpc_xprt *xpi_cursor; - const struct rpc_xprt_iter_ops *xpi_ops; -}; - -struct rpc_auth; - -struct rpc_stat; - -struct rpc_program; - -struct rpc_clnt { - atomic_t cl_count; - unsigned int cl_clid; - struct list_head cl_clients; - struct list_head cl_tasks; - spinlock_t cl_lock; - struct rpc_xprt *cl_xprt; - const struct rpc_procinfo *cl_procinfo; - u32 cl_prog; - u32 cl_vers; - u32 cl_maxproc; - struct rpc_auth *cl_auth; - struct rpc_stat *cl_stats; - struct rpc_iostats *cl_metrics; - unsigned int cl_softrtry: 1; - unsigned int cl_softerr: 1; - unsigned int cl_discrtry: 1; - unsigned int cl_noretranstimeo: 1; - unsigned int cl_autobind: 1; - unsigned int cl_chatty: 1; - struct rpc_rtt *cl_rtt; - const struct rpc_timeout *cl_timeout; - atomic_t cl_swapper; - int cl_nodelen; - char cl_nodename[65]; - struct rpc_pipe_dir_head cl_pipedir_objects; - struct rpc_clnt *cl_parent; - struct rpc_rtt cl_rtt_default; - struct rpc_timeout cl_timeout_default; - const struct rpc_program *cl_program; - const char *cl_principal; - struct dentry *cl_debugfs; - struct rpc_sysfs_client *cl_sysfs; - union { - struct rpc_xprt_iter cl_xpi; - struct work_struct cl_work; - }; - const struct cred *cl_cred; -}; - -struct svc_xprt; - -struct rpc_sysfs_xprt; - -struct rpc_xprt_ops; - -struct svc_serv; - -struct xprt_class; - -struct rpc_xprt { - struct kref kref; - const struct rpc_xprt_ops *ops; - unsigned int id; - const struct rpc_timeout *timeout; - struct __kernel_sockaddr_storage addr; - size_t addrlen; - int prot; - long unsigned int cong; - long unsigned int cwnd; - size_t max_payload; - struct rpc_wait_queue binding; - struct rpc_wait_queue sending; - struct rpc_wait_queue pending; - struct rpc_wait_queue backlog; - struct list_head free; - unsigned int max_reqs; - unsigned int min_reqs; - unsigned int num_reqs; - long unsigned int state; - unsigned char resvport: 1; - unsigned char reuseport: 1; - atomic_t swapper; - unsigned int bind_index; - struct list_head xprt_switch; - long unsigned int bind_timeout; - long unsigned int reestablish_timeout; - unsigned int connect_cookie; - struct work_struct task_cleanup; - struct timer_list timer; - long unsigned int last_used; - long unsigned int idle_timeout; - long unsigned int connect_timeout; - long unsigned int max_reconnect_timeout; - atomic_long_t queuelen; - spinlock_t transport_lock; - spinlock_t reserve_lock; - spinlock_t queue_lock; - u32 xid; - struct rpc_task *snd_task; - struct list_head xmit_queue; - atomic_long_t xmit_queuelen; - struct svc_xprt *bc_xprt; - struct svc_serv *bc_serv; - unsigned int bc_alloc_max; - unsigned int bc_alloc_count; - atomic_t bc_slot_count; - spinlock_t bc_pa_lock; - struct list_head bc_pa_list; - struct rb_root recv_queue; - struct { - long unsigned int bind_count; - long unsigned int connect_count; - long unsigned int connect_start; - long unsigned int connect_time; - long unsigned int sends; - long unsigned int recvs; - long unsigned int bad_xids; - long unsigned int max_slots; - long long unsigned int req_u; - long long unsigned int bklog_u; - long long unsigned int sending_u; - long long unsigned int pending_u; - } stat; - struct net *xprt_net; - const char *servername; - const char *address_strings[6]; - struct dentry *debugfs; - atomic_t inject_disconnect; - struct callback_head rcu; - const struct xprt_class *xprt_class; - struct rpc_sysfs_xprt *xprt_sysfs; - bool main; -}; - -struct rpc_credops; - -struct rpc_cred { - struct hlist_node cr_hash; - struct list_head cr_lru; - struct callback_head cr_rcu; - struct rpc_auth *cr_auth; - const struct rpc_credops *cr_ops; - long unsigned int cr_expire; - long unsigned int cr_flags; - refcount_t cr_count; - const struct cred *cr_cred; -}; - -typedef u32 rpc_authflavor_t; - -struct auth_cred { - const struct cred *cred; - const char *principal; -}; - -struct rpc_cred_cache; - -struct rpc_authops; - -struct rpc_auth { - unsigned int au_cslack; - unsigned int au_rslack; - unsigned int au_verfsize; - unsigned int au_ralign; - long unsigned int au_flags; - const struct rpc_authops *au_ops; - rpc_authflavor_t au_flavor; - refcount_t au_count; - struct rpc_cred_cache *au_credcache; -}; - -struct rpc_credops { - const char *cr_name; - int (*cr_init)(struct rpc_auth *, struct rpc_cred *); - void (*crdestroy)(struct rpc_cred *); - int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); - int (*crmarshal)(struct rpc_task *, struct xdr_stream *); - int (*crrefresh)(struct rpc_task *); - int (*crvalidate)(struct rpc_task *, struct xdr_stream *); - int (*crwrap_req)(struct rpc_task *, struct xdr_stream *); - int (*crunwrap_resp)(struct rpc_task *, struct xdr_stream *); - int (*crkey_timeout)(struct rpc_cred *); - char * (*crstringify_acceptor)(struct rpc_cred *); - bool (*crneed_reencode)(struct rpc_task *); -}; - -struct rpc_auth_create_args; - -struct rpcsec_gss_info; - -struct rpc_authops { - struct module *owner; - rpc_authflavor_t au_flavor; - char *au_name; - struct rpc_auth * (*create)(const struct rpc_auth_create_args *, struct rpc_clnt *); - void (*destroy)(struct rpc_auth *); - int (*hash_cred)(struct auth_cred *, unsigned int); - struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); - struct rpc_cred * (*crcreate)(struct rpc_auth *, struct auth_cred *, int, gfp_t); - rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *); - int (*flavor2info)(rpc_authflavor_t, struct rpcsec_gss_info *); - int (*key_timeout)(struct rpc_auth *, struct rpc_cred *); -}; - -struct rpc_auth_create_args { - rpc_authflavor_t pseudoflavor; - const char *target_name; -}; - -struct rpcsec_gss_oid { - unsigned int len; - u8 data[32]; -}; - -struct rpcsec_gss_info { - struct rpcsec_gss_oid oid; - u32 qop; - u32 service; -}; - -struct rpc_xprt_ops { - void (*set_buffer_size)(struct rpc_xprt *, size_t, size_t); - int (*reserve_xprt)(struct rpc_xprt *, struct rpc_task *); - void (*release_xprt)(struct rpc_xprt *, struct rpc_task *); - void (*alloc_slot)(struct rpc_xprt *, struct rpc_task *); - void (*free_slot)(struct rpc_xprt *, struct rpc_rqst *); - void (*rpcbind)(struct rpc_task *); - void (*set_port)(struct rpc_xprt *, short unsigned int); - void (*connect)(struct rpc_xprt *, struct rpc_task *); - int (*buf_alloc)(struct rpc_task *); - void (*buf_free)(struct rpc_task *); - void (*prepare_request)(struct rpc_rqst *); - int (*send_request)(struct rpc_rqst *); - void (*wait_for_reply_request)(struct rpc_task *); - void (*timer)(struct rpc_xprt *, struct rpc_task *); - void (*release_request)(struct rpc_task *); - void (*close)(struct rpc_xprt *); - void (*destroy)(struct rpc_xprt *); - void (*set_connect_timeout)(struct rpc_xprt *, long unsigned int, long unsigned int); - void (*print_stats)(struct rpc_xprt *, struct seq_file *); - int (*enable_swap)(struct rpc_xprt *); - void (*disable_swap)(struct rpc_xprt *); - void (*inject_disconnect)(struct rpc_xprt *); - int (*bc_setup)(struct rpc_xprt *, unsigned int); - size_t (*bc_maxpayload)(struct rpc_xprt *); - unsigned int (*bc_num_slots)(struct rpc_xprt *); - void (*bc_free_rqst)(struct rpc_rqst *); - void (*bc_destroy)(struct rpc_xprt *, unsigned int); -}; - -struct svc_program; - -struct svc_stat; - -struct svc_pool; - -struct svc_serv_ops; - -struct svc_serv { - struct svc_program *sv_program; - struct svc_stat *sv_stats; - spinlock_t sv_lock; - unsigned int sv_nrthreads; - unsigned int sv_maxconn; - unsigned int sv_max_payload; - unsigned int sv_max_mesg; - unsigned int sv_xdrsize; - struct list_head sv_permsocks; - struct list_head sv_tempsocks; - int sv_tmpcnt; - struct timer_list sv_temptimer; - char *sv_name; - unsigned int sv_nrpools; - struct svc_pool *sv_pools; - const struct svc_serv_ops *sv_ops; - struct list_head sv_cb_list; - spinlock_t sv_cb_lock; - wait_queue_head_t sv_cb_waitq; - bool sv_bc_enabled; -}; - -struct xprt_create; - -struct xprt_class { - struct list_head list; - int ident; - struct rpc_xprt * (*setup)(struct xprt_create *); - struct module *owner; - char name[32]; - const char *netid[0]; -}; - -struct xprt_create { - int ident; - struct net *net; - struct sockaddr *srcaddr; - struct sockaddr *dstaddr; - size_t addrlen; - const char *servername; - struct svc_xprt *bc_xprt; - struct rpc_xprt_switch *bc_xps; - unsigned int flags; -}; - -struct rpc_sysfs_xprt_switch; - -struct rpc_xprt_switch { - spinlock_t xps_lock; - struct kref xps_kref; - unsigned int xps_id; - unsigned int xps_nxprts; - unsigned int xps_nactive; - atomic_long_t xps_queuelen; - struct list_head xps_xprt_list; - struct net *xps_net; - const struct rpc_xprt_iter_ops *xps_iter_ops; - struct rpc_sysfs_xprt_switch *xps_sysfs; - struct callback_head xps_rcu; -}; - -struct rpc_stat { - const struct rpc_program *program; - unsigned int netcnt; - unsigned int netudpcnt; - unsigned int nettcpcnt; - unsigned int nettcpconn; - unsigned int netreconn; - unsigned int rpccnt; - unsigned int rpcretrans; - unsigned int rpcauthrefresh; - unsigned int rpcgarbage; -}; - -struct rpc_version; - -struct rpc_program { - const char *name; - u32 number; - unsigned int nrvers; - const struct rpc_version **version; - struct rpc_stat *stats; - const char *pipe_dir_name; -}; - -struct svc_stat { - struct svc_program *program; - unsigned int netcnt; - unsigned int netudpcnt; - unsigned int nettcpcnt; - unsigned int nettcpconn; - unsigned int rpccnt; - unsigned int rpcbadfmt; - unsigned int rpcbadauth; - unsigned int rpcbadclnt; -}; - -struct svc_version; - -struct svc_rqst; - -struct svc_process_info; - -struct svc_program { - struct svc_program *pg_next; - u32 pg_prog; - unsigned int pg_lovers; - unsigned int pg_hivers; - unsigned int pg_nvers; - const struct svc_version **pg_vers; - char *pg_name; - char *pg_class; - struct svc_stat *pg_stats; - int (*pg_authenticate)(struct svc_rqst *); - __be32 (*pg_init_request)(struct svc_rqst *, const struct svc_program *, struct svc_process_info *); - int (*pg_rpcbind_set)(struct net *, const struct svc_program *, u32, int, short unsigned int, short unsigned int); -}; - -struct rpc_xprt_iter_ops { - void (*xpi_rewind)(struct rpc_xprt_iter *); - struct rpc_xprt * (*xpi_xprt)(struct rpc_xprt_iter *); - struct rpc_xprt * (*xpi_next)(struct rpc_xprt_iter *); -}; - -struct rpc_version { - u32 number; - unsigned int nrprocs; - const struct rpc_procinfo *procs; - unsigned int *counts; -}; - -struct nfs_fh { - short unsigned int size; - unsigned char data[128]; -}; - -enum nfs3_stable_how { - NFS_UNSTABLE = 0, - NFS_DATA_SYNC = 1, - NFS_FILE_SYNC = 2, - NFS_INVALID_STABLE_HOW = 4294967295, -}; - -struct nfs4_label { - uint32_t lfs; - uint32_t pi; - u32 len; - char *label; -}; - -typedef struct { - char data[8]; -} nfs4_verifier; - -enum nfs4_change_attr_type { - NFS4_CHANGE_TYPE_IS_MONOTONIC_INCR = 0, - NFS4_CHANGE_TYPE_IS_VERSION_COUNTER = 1, - NFS4_CHANGE_TYPE_IS_VERSION_COUNTER_NOPNFS = 2, - NFS4_CHANGE_TYPE_IS_TIME_METADATA = 3, - NFS4_CHANGE_TYPE_IS_UNDEFINED = 4, -}; - -struct gss_api_mech; - -struct gss_ctx { - struct gss_api_mech *mech_type; - void *internal_ctx_id; - unsigned int slack; - unsigned int align; -}; - -struct gss_api_ops; - -struct pf_desc; - -struct gss_api_mech { - struct list_head gm_list; - struct module *gm_owner; - struct rpcsec_gss_oid gm_oid; - char *gm_name; - const struct gss_api_ops *gm_ops; - int gm_pf_num; - struct pf_desc *gm_pfs; - const char *gm_upcall_enctypes; -}; - -struct auth_domain; - -struct pf_desc { - u32 pseudoflavor; - u32 qop; - u32 service; - char *name; - char *auth_domain_name; - struct auth_domain *domain; - bool datatouch; -}; - -struct auth_ops; - -struct auth_domain { - struct kref ref; - struct hlist_node hash; - char *name; - struct auth_ops *flavour; - struct callback_head callback_head; -}; - -struct gss_api_ops { - int (*gss_import_sec_context)(const void *, size_t, struct gss_ctx *, time64_t *, gfp_t); - u32 (*gss_get_mic)(struct gss_ctx *, struct xdr_buf *, struct xdr_netobj *); - u32 (*gss_verify_mic)(struct gss_ctx *, struct xdr_buf *, struct xdr_netobj *); - u32 (*gss_wrap)(struct gss_ctx *, int, struct xdr_buf *, struct page **); - u32 (*gss_unwrap)(struct gss_ctx *, int, int, struct xdr_buf *); - void (*gss_delete_sec_context)(void *); -}; - -struct nfs4_string { - unsigned int len; - char *data; -}; - -struct nfs_fsid { - uint64_t major; - uint64_t minor; -}; - -struct nfs4_threshold { - __u32 bm; - __u32 l_type; - __u64 rd_sz; - __u64 wr_sz; - __u64 rd_io_sz; - __u64 wr_io_sz; -}; - -struct nfs_fattr { - unsigned int valid; - umode_t mode; - __u32 nlink; - kuid_t uid; - kgid_t gid; - dev_t rdev; - __u64 size; - union { - struct { - __u32 blocksize; - __u32 blocks; - } nfs2; - struct { - __u64 used; - } nfs3; - } du; - struct nfs_fsid fsid; - __u64 fileid; - __u64 mounted_on_fileid; - struct timespec64 atime; - struct timespec64 mtime; - struct timespec64 ctime; - __u64 change_attr; - __u64 pre_change_attr; - __u64 pre_size; - struct timespec64 pre_mtime; - struct timespec64 pre_ctime; - long unsigned int time_start; - long unsigned int gencount; - struct nfs4_string *owner_name; - struct nfs4_string *group_name; - struct nfs4_threshold *mdsthreshold; - struct nfs4_label *label; -}; - -struct nfs_fsinfo { - struct nfs_fattr *fattr; - __u32 rtmax; - __u32 rtpref; - __u32 rtmult; - __u32 wtmax; - __u32 wtpref; - __u32 wtmult; - __u32 dtpref; - __u64 maxfilesize; - struct timespec64 time_delta; - __u32 lease_time; - __u32 nlayouttypes; - __u32 layouttype[8]; - __u32 blksize; - __u32 clone_blksize; - enum nfs4_change_attr_type change_attr_type; - __u32 xattr_support; -}; - -struct nfs_fsstat { - struct nfs_fattr *fattr; - __u64 tbytes; - __u64 fbytes; - __u64 abytes; - __u64 tfiles; - __u64 ffiles; - __u64 afiles; -}; - -struct nfs_pathconf { - struct nfs_fattr *fattr; - __u32 max_link; - __u32 max_namelen; -}; - -struct nfs4_change_info { - u32 atomic; - u64 before; - u64 after; -}; - -struct nfs4_slot; - -struct nfs4_sequence_args { - struct nfs4_slot *sa_slot; - u8 sa_cache_this: 1; - u8 sa_privileged: 1; -}; - -struct nfs4_sequence_res { - struct nfs4_slot *sr_slot; - long unsigned int sr_timestamp; - int sr_status; - u32 sr_status_flags; - u32 sr_highest_slotid; - u32 sr_target_highest_slotid; -}; - -struct nfs_open_context; - -struct nfs_lock_context { - refcount_t count; - struct list_head list; - struct nfs_open_context *open_context; - fl_owner_t lockowner; - atomic_t io_count; - struct callback_head callback_head; -}; - -struct nfs_open_context { - struct nfs_lock_context lock_context; - fl_owner_t flock_owner; - struct dentry *dentry; - const struct cred *cred; - struct rpc_cred *ll_cred; - struct nfs4_state *state; - fmode_t mode; - long unsigned int flags; - int error; - struct list_head list; - struct nfs4_threshold *mdsthreshold; - struct callback_head callback_head; -}; - -struct nlm_host; - -struct nfs_iostats; - -struct nfs_auth_info { - unsigned int flavor_len; - rpc_authflavor_t flavors[12]; -}; - -struct nfs_fscache_key; - -struct fscache_cookie; - -struct pnfs_layoutdriver_type; - -struct nfs_client; - -struct nfs_server { - struct nfs_client *nfs_client; - struct list_head client_link; - struct list_head master_link; - struct rpc_clnt *client; - struct rpc_clnt *client_acl; - struct nlm_host *nlm_host; - struct nfs_iostats *io_stats; - atomic_long_t writeback; - unsigned int flags; - unsigned int fattr_valid; - unsigned int caps; - unsigned int rsize; - unsigned int rpages; - unsigned int wsize; - unsigned int wpages; - unsigned int wtmult; - unsigned int dtsize; - short unsigned int port; - unsigned int bsize; - unsigned int gxasize; - unsigned int sxasize; - unsigned int lxasize; - unsigned int acregmin; - unsigned int acregmax; - unsigned int acdirmin; - unsigned int acdirmax; - unsigned int namelen; - unsigned int options; - unsigned int clone_blksize; - enum nfs4_change_attr_type change_attr_type; - struct nfs_fsid fsid; - __u64 maxfilesize; - struct timespec64 time_delta; - long unsigned int mount_time; - struct super_block *super; - dev_t s_dev; - struct nfs_auth_info auth_info; - struct nfs_fscache_key *fscache_key; - struct fscache_cookie *fscache; - u32 pnfs_blksize; - u32 attr_bitmask[3]; - u32 attr_bitmask_nl[3]; - u32 exclcreat_bitmask[3]; - u32 cache_consistency_bitmask[3]; - u32 acl_bitmask; - u32 fh_expire_type; - struct pnfs_layoutdriver_type *pnfs_curr_ld; - struct rpc_wait_queue roc_rpcwaitq; - void *pnfs_ld_data; - struct rb_root state_owners; - struct ida openowner_id; - struct ida lockowner_id; - struct list_head state_owners_lru; - struct list_head layouts; - struct list_head delegations; - struct list_head ss_copies; - long unsigned int mig_gen; - long unsigned int mig_status; - void (*destroy)(struct nfs_server *); - atomic_t active; - struct __kernel_sockaddr_storage mountd_address; - size_t mountd_addrlen; - u32 mountd_version; - short unsigned int mountd_port; - short unsigned int mountd_protocol; - struct rpc_wait_queue uoc_rpcwaitq; - unsigned int read_hdrsize; - const struct cred *cred; - bool has_sec_mnt_opts; -}; - -struct nfs_subversion; - -struct idmap; - -struct nfs4_slot_table; - -struct nfs4_session; - -struct nfs_rpc_ops; - -struct nfs4_minor_version_ops; - -struct nfs41_server_owner; - -struct nfs41_server_scope; - -struct nfs41_impl_id; - -struct nfs_client { - refcount_t cl_count; - atomic_t cl_mds_count; - int cl_cons_state; - long unsigned int cl_res_state; - long unsigned int cl_flags; - struct __kernel_sockaddr_storage cl_addr; - size_t cl_addrlen; - char *cl_hostname; - char *cl_acceptor; - struct list_head cl_share_link; - struct list_head cl_superblocks; - struct rpc_clnt *cl_rpcclient; - const struct nfs_rpc_ops *rpc_ops; - int cl_proto; - struct nfs_subversion *cl_nfs_mod; - u32 cl_minorversion; - unsigned int cl_nconnect; - const char *cl_principal; - struct list_head cl_ds_clients; - u64 cl_clientid; - nfs4_verifier cl_confirm; - long unsigned int cl_state; - spinlock_t cl_lock; - long unsigned int cl_lease_time; - long unsigned int cl_last_renewal; - struct delayed_work cl_renewd; - struct rpc_wait_queue cl_rpcwaitq; - struct idmap *cl_idmap; - const char *cl_owner_id; - u32 cl_cb_ident; - const struct nfs4_minor_version_ops *cl_mvops; - long unsigned int cl_mig_gen; - struct nfs4_slot_table *cl_slot_tbl; - u32 cl_seqid; - u32 cl_exchange_flags; - struct nfs4_session *cl_session; - bool cl_preserve_clid; - struct nfs41_server_owner *cl_serverowner; - struct nfs41_server_scope *cl_serverscope; - struct nfs41_impl_id *cl_implid; - long unsigned int cl_sp4_flags; - wait_queue_head_t cl_lock_waitq; - char cl_ipaddr[48]; - struct fscache_cookie *fscache; - struct net *cl_net; - struct list_head pending_cb_stateids; -}; - -struct pnfs_layout_segment; - -struct nfs_seqid { - struct nfs_seqid_counter *sequence; - struct list_head list; - struct rpc_task *task; -}; - -struct nfs_write_verifier { - char data[8]; -}; - -struct nfs_writeverf { - struct nfs_write_verifier verifier; - enum nfs3_stable_how committed; -}; - -struct nfs_pgio_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - struct nfs_open_context *context; - struct nfs_lock_context *lock_context; - nfs4_stateid stateid; - __u64 offset; - __u32 count; - unsigned int pgbase; - struct page **pages; - union { - unsigned int replen; - struct { - const u32 *bitmask; - u32 bitmask_store[3]; - enum nfs3_stable_how stable; - }; - }; -}; - -struct nfs_pgio_res { - struct nfs4_sequence_res seq_res; - struct nfs_fattr *fattr; - __u64 count; - __u32 op_status; - union { - struct { - unsigned int replen; - int eof; - }; - struct { - struct nfs_writeverf *verf; - const struct nfs_server *server; - }; - }; -}; - -struct nfs_commitargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - __u64 offset; - __u32 count; - const u32 *bitmask; -}; - -struct nfs_commitres { - struct nfs4_sequence_res seq_res; - __u32 op_status; - struct nfs_fattr *fattr; - struct nfs_writeverf *verf; - const struct nfs_server *server; -}; - -struct nfs_removeargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - struct qstr name; -}; - -struct nfs_removeres { - struct nfs4_sequence_res seq_res; - struct nfs_server *server; - struct nfs_fattr *dir_attr; - struct nfs4_change_info cinfo; -}; - -struct nfs_renameargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *old_dir; - const struct nfs_fh *new_dir; - const struct qstr *old_name; - const struct qstr *new_name; -}; - -struct nfs_renameres { - struct nfs4_sequence_res seq_res; - struct nfs_server *server; - struct nfs4_change_info old_cinfo; - struct nfs_fattr *old_fattr; - struct nfs4_change_info new_cinfo; - struct nfs_fattr *new_fattr; -}; - -struct nfs_entry { - __u64 ino; - __u64 cookie; - __u64 prev_cookie; - const char *name; - unsigned int len; - int eof; - struct nfs_fh *fh; - struct nfs_fattr *fattr; - struct nfs4_label *label; - unsigned char d_type; - struct nfs_server *server; -}; - -struct nfs_readdir_arg { - struct dentry *dentry; - const struct cred *cred; - __be32 *verf; - u64 cookie; - struct page **pages; - unsigned int page_len; - bool plus; -}; - -struct nfs_readdir_res { - __be32 *verf; -}; - -struct nfs4_pathname { - unsigned int ncomponents; - struct nfs4_string components[512]; -}; - -struct nfs4_fs_location { - unsigned int nservers; - struct nfs4_string servers[10]; - struct nfs4_pathname rootpath; -}; - -struct nfs4_fs_locations { - struct nfs_fattr fattr; - const struct nfs_server *server; - struct nfs4_pathname fs_path; - int nlocations; - struct nfs4_fs_location locations[10]; -}; - -struct nfstime4 { - u64 seconds; - u32 nseconds; -}; - -struct pnfs_commit_ops; - -struct pnfs_ds_commit_info { - struct list_head commits; - unsigned int nwritten; - unsigned int ncommitting; - const struct pnfs_commit_ops *ops; -}; - -struct nfs41_server_owner { - uint64_t minor_id; - uint32_t major_id_sz; - char major_id[1024]; -}; - -struct nfs41_server_scope { - uint32_t server_scope_sz; - char server_scope[1024]; -}; - -struct nfs41_impl_id { - char domain[1025]; - char name[1025]; - struct nfstime4 date; -}; - -struct nfs_page_array { - struct page **pagevec; - unsigned int npages; - struct page *page_array[8]; -}; - -struct nfs_page; - -struct nfs_rw_ops; - -struct nfs_io_completion; - -struct nfs_direct_req; - -struct nfs_pgio_completion_ops; - -struct nfs_pgio_header { - struct inode *inode; - const struct cred *cred; - struct list_head pages; - struct nfs_page *req; - struct nfs_writeverf verf; - fmode_t rw_mode; - struct pnfs_layout_segment *lseg; - loff_t io_start; - const struct rpc_call_ops *mds_ops; - void (*release)(struct nfs_pgio_header *); - const struct nfs_pgio_completion_ops *completion_ops; - const struct nfs_rw_ops *rw_ops; - struct nfs_io_completion *io_completion; - struct nfs_direct_req *dreq; - int pnfs_error; - int error; - unsigned int good_bytes; - long unsigned int flags; - struct rpc_task task; - struct nfs_fattr fattr; - struct nfs_pgio_args args; - struct nfs_pgio_res res; - long unsigned int timestamp; - int (*pgio_done_cb)(struct rpc_task *, struct nfs_pgio_header *); - __u64 mds_offset; - struct nfs_page_array page_array; - struct nfs_client *ds_clp; - u32 ds_commit_idx; - u32 pgio_mirror_idx; -}; - -struct nfs_pgio_completion_ops { - void (*error_cleanup)(struct list_head *, int); - void (*init_hdr)(struct nfs_pgio_header *); - void (*completion)(struct nfs_pgio_header *); - void (*reschedule_io)(struct nfs_pgio_header *); -}; - -struct nfs_mds_commit_info { - atomic_t rpcs_out; - atomic_long_t ncommit; - struct list_head list; -}; - -struct nfs_commit_data; - -struct nfs_commit_info; - -struct nfs_commit_completion_ops { - void (*completion)(struct nfs_commit_data *); - void (*resched_write)(struct nfs_commit_info *, struct nfs_page *); -}; - -struct nfs_commit_data { - struct rpc_task task; - struct inode *inode; - const struct cred *cred; - struct nfs_fattr fattr; - struct nfs_writeverf verf; - struct list_head pages; - struct list_head list; - struct nfs_direct_req *dreq; - struct nfs_commitargs args; - struct nfs_commitres res; - struct nfs_open_context *context; - struct pnfs_layout_segment *lseg; - struct nfs_client *ds_clp; - int ds_commit_index; - loff_t lwb; - const struct rpc_call_ops *mds_ops; - const struct nfs_commit_completion_ops *completion_ops; - int (*commit_done_cb)(struct rpc_task *, struct nfs_commit_data *); - long unsigned int flags; -}; - -struct nfs_commit_info { - struct inode *inode; - struct nfs_mds_commit_info *mds; - struct pnfs_ds_commit_info *ds; - struct nfs_direct_req *dreq; - const struct nfs_commit_completion_ops *completion_ops; -}; - -struct nfs_unlinkdata { - struct nfs_removeargs args; - struct nfs_removeres res; - struct dentry *dentry; - wait_queue_head_t wq; - const struct cred *cred; - struct nfs_fattr dir_attr; - long int timeout; -}; - -struct nfs_renamedata { - struct nfs_renameargs args; - struct nfs_renameres res; - const struct cred *cred; - struct inode *old_dir; - struct dentry *old_dentry; - struct nfs_fattr old_fattr; - struct inode *new_dir; - struct dentry *new_dentry; - struct nfs_fattr new_fattr; - void (*complete)(struct rpc_task *, struct nfs_renamedata *); - long int timeout; - bool cancelled; -}; - -struct nlmclnt_operations; - -struct nfs_client_initdata; - -struct nfs_access_entry; - -struct nfs_rpc_ops { - u32 version; - const struct dentry_operations *dentry_ops; - const struct inode_operations *dir_inode_ops; - const struct inode_operations *file_inode_ops; - const struct file_operations *file_ops; - const struct nlmclnt_operations *nlmclnt_ops; - int (*getroot)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); - int (*submount)(struct fs_context *, struct nfs_server *); - int (*try_get_tree)(struct fs_context *); - int (*getattr)(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *, struct inode *); - int (*setattr)(struct dentry *, struct nfs_fattr *, struct iattr *); - int (*lookup)(struct inode *, struct dentry *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *); - int (*lookupp)(struct inode *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *); - int (*access)(struct inode *, struct nfs_access_entry *); - int (*readlink)(struct inode *, struct page *, unsigned int, unsigned int); - int (*create)(struct inode *, struct dentry *, struct iattr *, int); - int (*remove)(struct inode *, struct dentry *); - void (*unlink_setup)(struct rpc_message *, struct dentry *, struct inode *); - void (*unlink_rpc_prepare)(struct rpc_task *, struct nfs_unlinkdata *); - int (*unlink_done)(struct rpc_task *, struct inode *); - void (*rename_setup)(struct rpc_message *, struct dentry *, struct dentry *); - void (*rename_rpc_prepare)(struct rpc_task *, struct nfs_renamedata *); - int (*rename_done)(struct rpc_task *, struct inode *, struct inode *); - int (*link)(struct inode *, struct inode *, const struct qstr *); - int (*symlink)(struct inode *, struct dentry *, struct page *, unsigned int, struct iattr *); - int (*mkdir)(struct inode *, struct dentry *, struct iattr *); - int (*rmdir)(struct inode *, const struct qstr *); - int (*readdir)(struct nfs_readdir_arg *, struct nfs_readdir_res *); - int (*mknod)(struct inode *, struct dentry *, struct iattr *, dev_t); - int (*statfs)(struct nfs_server *, struct nfs_fh *, struct nfs_fsstat *); - int (*fsinfo)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); - int (*pathconf)(struct nfs_server *, struct nfs_fh *, struct nfs_pathconf *); - int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); - int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, bool); - int (*pgio_rpc_prepare)(struct rpc_task *, struct nfs_pgio_header *); - void (*read_setup)(struct nfs_pgio_header *, struct rpc_message *); - int (*read_done)(struct rpc_task *, struct nfs_pgio_header *); - void (*write_setup)(struct nfs_pgio_header *, struct rpc_message *, struct rpc_clnt **); - int (*write_done)(struct rpc_task *, struct nfs_pgio_header *); - void (*commit_setup)(struct nfs_commit_data *, struct rpc_message *, struct rpc_clnt **); - void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *); - int (*commit_done)(struct rpc_task *, struct nfs_commit_data *); - int (*lock)(struct file *, int, struct file_lock *); - int (*lock_check_bounds)(const struct file_lock *); - void (*clear_acl_cache)(struct inode *); - void (*close_context)(struct nfs_open_context *, int); - struct inode * (*open_context)(struct inode *, struct nfs_open_context *, int, struct iattr *, int *); - int (*have_delegation)(struct inode *, fmode_t); - struct nfs_client * (*alloc_client)(const struct nfs_client_initdata *); - struct nfs_client * (*init_client)(struct nfs_client *, const struct nfs_client_initdata *); - void (*free_client)(struct nfs_client *); - struct nfs_server * (*create_server)(struct fs_context *); - struct nfs_server * (*clone_server)(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, rpc_authflavor_t); -}; - -struct nfs_access_entry { - struct rb_node rb_node; - struct list_head lru; - const struct cred *cred; - __u32 mask; - struct callback_head callback_head; -}; - -struct nfs4_state_recovery_ops; - -struct nfs4_state_maintenance_ops; - -struct nfs4_mig_recovery_ops; - -struct nfs4_minor_version_ops { - u32 minor_version; - unsigned int init_caps; - int (*init_client)(struct nfs_client *); - void (*shutdown_client)(struct nfs_client *); - bool (*match_stateid)(const nfs4_stateid *, const nfs4_stateid *); - int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); - void (*free_lock_state)(struct nfs_server *, struct nfs4_lock_state *); - int (*test_and_free_expired)(struct nfs_server *, nfs4_stateid *, const struct cred *); - struct nfs_seqid * (*alloc_seqid)(struct nfs_seqid_counter *, gfp_t); - void (*session_trunk)(struct rpc_clnt *, struct rpc_xprt *, void *); - const struct rpc_call_ops *call_sync_ops; - const struct nfs4_state_recovery_ops *reboot_recovery_ops; - const struct nfs4_state_recovery_ops *nograce_recovery_ops; - const struct nfs4_state_maintenance_ops *state_renewal_ops; - const struct nfs4_mig_recovery_ops *mig_recovery_ops; -}; - -struct nfs4_state_owner; - -struct nfs4_state { - struct list_head open_states; - struct list_head inode_states; - struct list_head lock_states; - struct nfs4_state_owner *owner; - struct inode *inode; - long unsigned int flags; - spinlock_t state_lock; - seqlock_t seqlock; - nfs4_stateid stateid; - nfs4_stateid open_stateid; - unsigned int n_rdonly; - unsigned int n_wronly; - unsigned int n_rdwr; - fmode_t state; - refcount_t count; - wait_queue_head_t waitq; - struct callback_head callback_head; -}; - -struct cache_head { - struct hlist_node cache_list; - time64_t expiry_time; - time64_t last_refresh; - struct kref ref; - long unsigned int flags; -}; - -struct cache_deferred_req; - -struct cache_req { - struct cache_deferred_req * (*defer)(struct cache_req *); - int thread_wait; -}; - -struct cache_deferred_req { - struct hlist_node hash; - struct list_head recent; - struct cache_head *item; - void *owner; - void (*revisit)(struct cache_deferred_req *, int); -}; - -struct svc_cred { - kuid_t cr_uid; - kgid_t cr_gid; - struct group_info *cr_group_info; - u32 cr_flavor; - char *cr_raw_principal; - char *cr_principal; - char *cr_targ_princ; - struct gss_api_mech *cr_gss_mech; -}; - -struct auth_ops { - char *name; - struct module *owner; - int flavour; - int (*accept)(struct svc_rqst *, __be32 *); - int (*release)(struct svc_rqst *); - void (*domain_release)(struct auth_domain *); - int (*set_client)(struct svc_rqst *); -}; - -struct svc_cacherep; - -struct svc_procedure; - -struct svc_deferred_req; - -struct svc_rqst { - struct list_head rq_all; - struct callback_head rq_rcu_head; - struct svc_xprt *rq_xprt; - struct __kernel_sockaddr_storage rq_addr; - size_t rq_addrlen; - struct __kernel_sockaddr_storage rq_daddr; - size_t rq_daddrlen; - struct svc_serv *rq_server; - struct svc_pool *rq_pool; - const struct svc_procedure *rq_procinfo; - struct auth_ops *rq_authop; - struct svc_cred rq_cred; - void *rq_xprt_ctxt; - struct svc_deferred_req *rq_deferred; - size_t rq_xprt_hlen; - struct xdr_buf rq_arg; - struct xdr_stream rq_arg_stream; - struct xdr_stream rq_res_stream; - struct page *rq_scratch_page; - struct xdr_buf rq_res; - struct page *rq_pages[260]; - struct page **rq_respages; - struct page **rq_next_page; - struct page **rq_page_end; - struct kvec rq_vec[259]; - struct bio_vec rq_bvec[259]; - __be32 rq_xid; - u32 rq_prog; - u32 rq_vers; - u32 rq_proc; - u32 rq_prot; - int rq_cachetype; - long unsigned int rq_flags; - ktime_t rq_qtime; - void *rq_argp; - void *rq_resp; - void *rq_auth_data; - int rq_auth_slack; - int rq_reserved; - ktime_t rq_stime; - struct cache_req rq_chandle; - struct auth_domain *rq_client; - struct auth_domain *rq_gssclient; - struct svc_cacherep *rq_cacherep; - struct task_struct *rq_task; - spinlock_t rq_lock; - struct net *rq_bc_net; - void **rq_lease_breaker; -}; - -struct svc_pool_stats { - atomic_long_t packets; - long unsigned int sockets_queued; - atomic_long_t threads_woken; - atomic_long_t threads_timedout; -}; - -struct svc_pool { - unsigned int sp_id; - spinlock_t sp_lock; - struct list_head sp_sockets; - unsigned int sp_nrthreads; - struct list_head sp_all_threads; - struct svc_pool_stats sp_stats; - long unsigned int sp_flags; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct svc_serv_ops { - void (*svo_shutdown)(struct svc_serv *, struct net *); - int (*svo_function)(void *); - void (*svo_enqueue_xprt)(struct svc_xprt *); - int (*svo_setup)(struct svc_serv *, struct svc_pool *, int); - struct module *svo_module; -}; - -struct svc_procedure { - __be32 (*pc_func)(struct svc_rqst *); - int (*pc_decode)(struct svc_rqst *, __be32 *); - int (*pc_encode)(struct svc_rqst *, __be32 *); - void (*pc_release)(struct svc_rqst *); - unsigned int pc_argsize; - unsigned int pc_ressize; - unsigned int pc_cachetype; - unsigned int pc_xdrressize; - const char *pc_name; -}; - -struct svc_deferred_req { - u32 prot; - struct svc_xprt *xprt; - struct __kernel_sockaddr_storage addr; - size_t addrlen; - struct __kernel_sockaddr_storage daddr; - size_t daddrlen; - struct cache_deferred_req handle; - size_t xprt_hlen; - int argslen; - __be32 args[0]; -}; - -struct svc_process_info { - union { - int (*dispatch)(struct svc_rqst *, __be32 *); - struct { - unsigned int lovers; - unsigned int hivers; - } mismatch; - }; -}; - -struct svc_version { - u32 vs_vers; - u32 vs_nproc; - const struct svc_procedure *vs_proc; - unsigned int *vs_count; - u32 vs_xdrsize; - bool vs_hidden; - bool vs_rpcb_optnl; - bool vs_need_cong_ctrl; - int (*vs_dispatch)(struct svc_rqst *, __be32 *); -}; - -struct nfs4_ssc_client_ops; - -struct nfs_ssc_client_ops; - -struct nfs_ssc_client_ops_tbl { - const struct nfs4_ssc_client_ops *ssc_nfs4_ops; - const struct nfs_ssc_client_ops *ssc_nfs_ops; -}; - -struct nfs4_ssc_client_ops { - struct file * (*sco_open)(struct vfsmount *, struct nfs_fh *, nfs4_stateid *); - void (*sco_close)(struct file *); -}; - -struct nfs_ssc_client_ops { - void (*sco_sb_deactive)(struct super_block *); -}; - -struct nfs4_state_recovery_ops { - int owner_flag_bit; - int state_flag_bit; - int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); - int (*recover_lock)(struct nfs4_state *, struct file_lock *); - int (*establish_clid)(struct nfs_client *, const struct cred *); - int (*reclaim_complete)(struct nfs_client *, const struct cred *); - int (*detect_trunking)(struct nfs_client *, struct nfs_client **, const struct cred *); -}; - -struct nfs4_state_maintenance_ops { - int (*sched_state_renewal)(struct nfs_client *, const struct cred *, unsigned int); - const struct cred * (*get_state_renewal_cred)(struct nfs_client *); - int (*renew_lease)(struct nfs_client *, const struct cred *); -}; - -struct nfs4_mig_recovery_ops { - int (*get_locations)(struct inode *, struct nfs4_fs_locations *, struct page *, const struct cred *); - int (*fsid_present)(struct inode *, const struct cred *); -}; - -struct nfs4_state_owner { - struct nfs_server *so_server; - struct list_head so_lru; - long unsigned int so_expires; - struct rb_node so_server_node; - const struct cred *so_cred; - spinlock_t so_lock; - atomic_t so_count; - long unsigned int so_flags; - struct list_head so_states; - struct nfs_seqid_counter so_seqid; - seqcount_spinlock_t so_reclaim_seqcount; - struct mutex so_delegreturn_mutex; -}; - -struct core_name { - char *corename; - int used; - int size; -}; - -struct trace_event_raw_iomap_readpage_class { - struct trace_entry ent; - dev_t dev; - u64 ino; - int nr_pages; - char __data[0]; -}; - -struct trace_event_raw_iomap_range_class { - struct trace_entry ent; - dev_t dev; - u64 ino; - loff_t size; - long unsigned int offset; - unsigned int length; - char __data[0]; -}; - -struct trace_event_raw_iomap_class { - struct trace_entry ent; - dev_t dev; - u64 ino; - u64 addr; - loff_t offset; - u64 length; - u16 type; - u16 flags; - dev_t bdev; - char __data[0]; -}; - -struct trace_event_raw_iomap_apply { - struct trace_entry ent; - dev_t dev; - u64 ino; - loff_t pos; - loff_t length; - unsigned int flags; - const void *ops; - void *actor; - long unsigned int caller; - char __data[0]; -}; - -struct trace_event_data_offsets_iomap_readpage_class {}; - -struct trace_event_data_offsets_iomap_range_class {}; - -struct trace_event_data_offsets_iomap_class {}; - -struct trace_event_data_offsets_iomap_apply {}; - -typedef void (*btf_trace_iomap_readpage)(void *, struct inode *, int); - -typedef void (*btf_trace_iomap_readahead)(void *, struct inode *, int); - -typedef void (*btf_trace_iomap_writepage)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_releasepage)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_invalidatepage)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_dio_invalidate_fail)(void *, struct inode *, long unsigned int, unsigned int); - -typedef void (*btf_trace_iomap_apply_dstmap)(void *, struct inode *, struct iomap___2 *); - -typedef void (*btf_trace_iomap_apply_srcmap)(void *, struct inode *, struct iomap___2 *); - -typedef void (*btf_trace_iomap_apply)(void *, struct inode *, loff_t, loff_t, unsigned int, const void *, void *, long unsigned int); - -struct iomap_ioend { - struct list_head io_list; - u16 io_type; - u16 io_flags; - struct inode *io_inode; - size_t io_size; - loff_t io_offset; - struct bio *io_bio; - struct bio io_inline_bio; -}; - -struct iomap_writepage_ctx; - -struct iomap_writeback_ops { - int (*map_blocks)(struct iomap_writepage_ctx *, struct inode *, loff_t); - int (*prepare_ioend)(struct iomap_ioend *, int); - void (*discard_page)(struct page *, loff_t); -}; - -struct iomap_writepage_ctx { - struct iomap___2 iomap; - struct iomap_ioend *ioend; - const struct iomap_writeback_ops *ops; -}; - -typedef int (*list_cmp_func_t)(void *, const struct list_head *, const struct list_head *); - -struct iomap_page { - atomic_t read_bytes_pending; - atomic_t write_bytes_pending; - spinlock_t uptodate_lock; - long unsigned int uptodate[0]; -}; - -struct iomap_readpage_ctx { - struct page *cur_page; - bool cur_page_in_bio; - struct bio *bio; - struct readahead_control *rac; -}; - -enum { - IOMAP_WRITE_F_UNSHARE = 1, -}; - -struct iomap_dio_ops { - int (*end_io)(struct kiocb *, ssize_t, int, unsigned int); - blk_qc_t (*submit_io)(struct inode *, struct iomap___2 *, struct bio *, loff_t); -}; - -struct iomap_dio { - struct kiocb *iocb; - const struct iomap_dio_ops *dops; - loff_t i_size; - loff_t size; - atomic_t ref; - unsigned int flags; - int error; - bool wait_for_completion; - union { - struct { - struct iov_iter *iter; - struct task_struct *waiter; - struct request_queue *last_queue; - blk_qc_t cookie; - } submit; - struct { - struct work_struct work; - } aio; - }; -}; - -struct fiemap_ctx { - struct fiemap_extent_info *fi; - struct iomap___2 prev; -}; - -struct iomap_swapfile_info { - struct iomap___2 iomap; - struct swap_info_struct *sis; - uint64_t lowest_ppage; - uint64_t highest_ppage; - long unsigned int nr_pages; - int nr_extents; - struct file *file; -}; - -enum { - QIF_BLIMITS_B = 0, - QIF_SPACE_B = 1, - QIF_ILIMITS_B = 2, - QIF_INODES_B = 3, - QIF_BTIME_B = 4, - QIF_ITIME_B = 5, -}; - -typedef __kernel_uid32_t qid_t; - -enum { - DQF_INFO_DIRTY_B = 17, -}; - -struct dqstats { - long unsigned int stat[8]; - struct percpu_counter counter[8]; -}; - -enum { - _DQUOT_USAGE_ENABLED = 0, - _DQUOT_LIMITS_ENABLED = 1, - _DQUOT_SUSPENDED = 2, - _DQUOT_STATE_FLAGS = 3, -}; - -struct quota_module_name { - int qm_fmt_id; - char *qm_mod_name; -}; - -struct dquot_warn { - struct super_block *w_sb; - struct kqid w_dq_id; - short int w_type; -}; - -struct fs_disk_quota { - __s8 d_version; - __s8 d_flags; - __u16 d_fieldmask; - __u32 d_id; - __u64 d_blk_hardlimit; - __u64 d_blk_softlimit; - __u64 d_ino_hardlimit; - __u64 d_ino_softlimit; - __u64 d_bcount; - __u64 d_icount; - __s32 d_itimer; - __s32 d_btimer; - __u16 d_iwarns; - __u16 d_bwarns; - __s8 d_itimer_hi; - __s8 d_btimer_hi; - __s8 d_rtbtimer_hi; - __s8 d_padding2; - __u64 d_rtb_hardlimit; - __u64 d_rtb_softlimit; - __u64 d_rtbcount; - __s32 d_rtbtimer; - __u16 d_rtbwarns; - __s16 d_padding3; - char d_padding4[8]; -}; - -struct fs_qfilestat { - __u64 qfs_ino; - __u64 qfs_nblks; - __u32 qfs_nextents; -}; - -typedef struct fs_qfilestat fs_qfilestat_t; - -struct fs_quota_stat { - __s8 qs_version; - __u16 qs_flags; - __s8 qs_pad; - fs_qfilestat_t qs_uquota; - fs_qfilestat_t qs_gquota; - __u32 qs_incoredqs; - __s32 qs_btimelimit; - __s32 qs_itimelimit; - __s32 qs_rtbtimelimit; - __u16 qs_bwarnlimit; - __u16 qs_iwarnlimit; -}; - -struct fs_qfilestatv { - __u64 qfs_ino; - __u64 qfs_nblks; - __u32 qfs_nextents; - __u32 qfs_pad; -}; - -struct fs_quota_statv { - __s8 qs_version; - __u8 qs_pad1; - __u16 qs_flags; - __u32 qs_incoredqs; - struct fs_qfilestatv qs_uquota; - struct fs_qfilestatv qs_gquota; - struct fs_qfilestatv qs_pquota; - __s32 qs_btimelimit; - __s32 qs_itimelimit; - __s32 qs_rtbtimelimit; - __u16 qs_bwarnlimit; - __u16 qs_iwarnlimit; - __u16 qs_rtbwarnlimit; - __u16 qs_pad3; - __u32 qs_pad4; - __u64 qs_pad2[7]; -}; - -struct if_dqblk { - __u64 dqb_bhardlimit; - __u64 dqb_bsoftlimit; - __u64 dqb_curspace; - __u64 dqb_ihardlimit; - __u64 dqb_isoftlimit; - __u64 dqb_curinodes; - __u64 dqb_btime; - __u64 dqb_itime; - __u32 dqb_valid; -}; - -struct if_nextdqblk { - __u64 dqb_bhardlimit; - __u64 dqb_bsoftlimit; - __u64 dqb_curspace; - __u64 dqb_ihardlimit; - __u64 dqb_isoftlimit; - __u64 dqb_curinodes; - __u64 dqb_btime; - __u64 dqb_itime; - __u32 dqb_valid; - __u32 dqb_id; -}; - -struct if_dqinfo { - __u64 dqi_bgrace; - __u64 dqi_igrace; - __u32 dqi_flags; - __u32 dqi_valid; -}; - -struct compat_if_dqblk { - compat_u64 dqb_bhardlimit; - compat_u64 dqb_bsoftlimit; - compat_u64 dqb_curspace; - compat_u64 dqb_ihardlimit; - compat_u64 dqb_isoftlimit; - compat_u64 dqb_curinodes; - compat_u64 dqb_btime; - compat_u64 dqb_itime; - compat_uint_t dqb_valid; -} __attribute__((packed)); - -struct compat_fs_qfilestat { - compat_u64 dqb_bhardlimit; - compat_u64 qfs_nblks; - compat_uint_t qfs_nextents; -} __attribute__((packed)); - -struct compat_fs_quota_stat { - __s8 qs_version; - char: 8; - __u16 qs_flags; - __s8 qs_pad; - int: 24; - struct compat_fs_qfilestat qs_uquota; - struct compat_fs_qfilestat qs_gquota; - compat_uint_t qs_incoredqs; - compat_int_t qs_btimelimit; - compat_int_t qs_itimelimit; - compat_int_t qs_rtbtimelimit; - __u16 qs_bwarnlimit; - __u16 qs_iwarnlimit; -} __attribute__((packed)); - -enum { - QUOTA_NL_C_UNSPEC = 0, - QUOTA_NL_C_WARNING = 1, - __QUOTA_NL_C_MAX = 2, -}; - -enum { - QUOTA_NL_A_UNSPEC = 0, - QUOTA_NL_A_QTYPE = 1, - QUOTA_NL_A_EXCESS_ID = 2, - QUOTA_NL_A_WARNING = 3, - QUOTA_NL_A_DEV_MAJOR = 4, - QUOTA_NL_A_DEV_MINOR = 5, - QUOTA_NL_A_CAUSED_ID = 6, - QUOTA_NL_A_PAD = 7, - __QUOTA_NL_A_MAX = 8, -}; - -struct proc_maps_private { - struct inode *inode; - struct task_struct *task; - struct mm_struct *mm; - struct vm_area_struct *tail_vma; - struct mempolicy *task_mempolicy; -}; - -struct mem_size_stats { - long unsigned int resident; - long unsigned int shared_clean; - long unsigned int shared_dirty; - long unsigned int private_clean; - long unsigned int private_dirty; - long unsigned int referenced; - long unsigned int anonymous; - long unsigned int lazyfree; - long unsigned int anonymous_thp; - long unsigned int shmem_thp; - long unsigned int file_thp; - long unsigned int swap; - long unsigned int shared_hugetlb; - long unsigned int private_hugetlb; - u64 pss; - u64 pss_anon; - u64 pss_file; - u64 pss_shmem; - u64 pss_locked; - u64 swap_pss; - bool check_shmem_swap; -}; - -enum clear_refs_types { - CLEAR_REFS_ALL = 1, - CLEAR_REFS_ANON = 2, - CLEAR_REFS_MAPPED = 3, - CLEAR_REFS_SOFT_DIRTY = 4, - CLEAR_REFS_MM_HIWATER_RSS = 5, - CLEAR_REFS_LAST = 6, -}; - -struct clear_refs_private { - enum clear_refs_types type; -}; - -typedef struct { - u64 pme; -} pagemap_entry_t; - -struct pagemapread { - int pos; - int len; - pagemap_entry_t *buffer; - bool show_pfn; -}; - -struct numa_maps { - long unsigned int pages; - long unsigned int anon; - long unsigned int active; - long unsigned int writeback; - long unsigned int mapcount_max; - long unsigned int dirty; - long unsigned int swapcache; - long unsigned int node[32]; -}; - -struct numa_maps_private { - struct proc_maps_private proc_maps; - struct numa_maps md; -}; - -struct pde_opener { - struct list_head lh; - struct file *file; - bool closing; - struct completion *c; -}; - -enum { - BIAS = 2147483648, -}; - -struct proc_fs_context { - struct pid_namespace *pid_ns; - unsigned int mask; - enum proc_hidepid hidepid; - int gid; - enum proc_pidonly pidonly; -}; - -enum proc_param { - Opt_gid___2 = 0, - Opt_hidepid = 1, - Opt_subset = 2, -}; - -struct genradix_root; - -struct __genradix { - struct genradix_root *root; -}; - -struct syscall_info { - __u64 sp; - struct seccomp_data data; -}; - -typedef struct dentry *instantiate_t(struct dentry *, struct task_struct *, const void *); - -struct pid_entry { - const char *name; - unsigned int len; - umode_t mode; - const struct inode_operations *iop; - const struct file_operations *fop; - union proc_op op; -}; - -struct limit_names { - const char *name; - const char *unit; -}; - -struct map_files_info { - long unsigned int start; - long unsigned int end; - fmode_t mode; -}; - -struct timers_private { - struct pid *pid; - struct task_struct *task; - struct sighand_struct *sighand; - struct pid_namespace *ns; - long unsigned int flags; -}; - -struct tgid_iter { - unsigned int tgid; - struct task_struct *task; -}; - -struct fd_data { - fmode_t mode; - unsigned int fd; -}; - -struct sysctl_alias { - const char *kernel_param; - const char *sysctl_param; -}; - -struct seq_net_private { - struct net *net; -}; - -struct bpf_iter_aux_info___2; - -struct vmcore { - struct list_head list; - long long unsigned int paddr; - long long unsigned int size; - loff_t offset; -}; - -struct vmcoredd_node { - struct list_head list; - void *buf; - unsigned int size; -}; - -typedef struct elf32_hdr Elf32_Ehdr; - -typedef struct elf32_phdr Elf32_Phdr; - -typedef struct elf32_note Elf32_Nhdr; - -typedef struct elf64_note Elf64_Nhdr; - -struct vmcoredd_header { - __u32 n_namesz; - __u32 n_descsz; - __u32 n_type; - __u8 name[8]; - __u8 dump_name[44]; -}; - -struct vmcoredd_data { - char dump_name[44]; - unsigned int size; - int (*vmcoredd_callback)(struct vmcoredd_data *, void *); -}; - -struct kernfs_iattrs { - kuid_t ia_uid; - kgid_t ia_gid; - struct timespec64 ia_atime; - struct timespec64 ia_mtime; - struct timespec64 ia_ctime; - struct simple_xattrs xattrs; - atomic_t nr_user_xattrs; - atomic_t user_xattr_size; -}; - -struct kernfs_super_info { - struct super_block *sb; - struct kernfs_root *root; - const void *ns; - struct list_head node; -}; - -enum kernfs_node_flag { - KERNFS_ACTIVATED = 16, - KERNFS_NS = 32, - KERNFS_HAS_SEQ_SHOW = 64, - KERNFS_HAS_MMAP = 128, - KERNFS_LOCKDEP = 256, - KERNFS_SUICIDAL = 1024, - KERNFS_SUICIDED = 2048, - KERNFS_EMPTY_DIR = 4096, - KERNFS_HAS_RELEASE = 8192, -}; - -struct kernfs_open_node { - atomic_t refcnt; - atomic_t event; - wait_queue_head_t poll; - struct list_head files; -}; - -struct config_group; - -struct config_item_type; - -struct config_item { - char *ci_name; - char ci_namebuf[20]; - struct kref ci_kref; - struct list_head ci_entry; - struct config_item *ci_parent; - struct config_group *ci_group; - const struct config_item_type *ci_type; - struct dentry *ci_dentry; -}; - -struct configfs_subsystem; - -struct config_group { - struct config_item cg_item; - struct list_head cg_children; - struct configfs_subsystem *cg_subsys; - struct list_head default_groups; - struct list_head group_entry; -}; - -struct configfs_item_operations; - -struct configfs_group_operations; - -struct configfs_attribute; - -struct configfs_bin_attribute; - -struct config_item_type { - struct module *ct_owner; - struct configfs_item_operations *ct_item_ops; - struct configfs_group_operations *ct_group_ops; - struct configfs_attribute **ct_attrs; - struct configfs_bin_attribute **ct_bin_attrs; -}; - -struct configfs_item_operations { - void (*release)(struct config_item *); - int (*allow_link)(struct config_item *, struct config_item *); - void (*drop_link)(struct config_item *, struct config_item *); -}; - -struct configfs_group_operations { - struct config_item * (*make_item)(struct config_group *, const char *); - struct config_group * (*make_group)(struct config_group *, const char *); - int (*commit_item)(struct config_item *); - void (*disconnect_notify)(struct config_group *, struct config_item *); - void (*drop_item)(struct config_group *, struct config_item *); -}; - -struct configfs_attribute { - const char *ca_name; - struct module *ca_owner; - umode_t ca_mode; - ssize_t (*show)(struct config_item *, char *); - ssize_t (*store)(struct config_item *, const char *, size_t); -}; - -struct configfs_bin_attribute { - struct configfs_attribute cb_attr; - void *cb_private; - size_t cb_max_size; - ssize_t (*read)(struct config_item *, void *, size_t); - ssize_t (*write)(struct config_item *, const void *, size_t); -}; - -struct configfs_subsystem { - struct config_group su_group; - struct mutex su_mutex; -}; - -struct configfs_fragment { - atomic_t frag_count; - struct rw_semaphore frag_sem; - bool frag_dead; -}; - -struct configfs_dirent { - atomic_t s_count; - int s_dependent_count; - struct list_head s_sibling; - struct list_head s_children; - int s_links; - void *s_element; - int s_type; - umode_t s_mode; - struct dentry *s_dentry; - struct iattr *s_iattr; - struct configfs_fragment *s_frag; -}; - -struct configfs_buffer { - size_t count; - loff_t pos; - char *page; - struct configfs_item_operations *ops; - struct mutex mutex; - int needs_read_fill; - bool read_in_progress; - bool write_in_progress; - char *bin_buffer; - int bin_buffer_size; - int cb_max_size; - struct config_item *item; - struct module *owner; - union { - struct configfs_attribute *attr; - struct configfs_bin_attribute *bin_attr; - }; -}; - -struct pts_mount_opts { - int setuid; - int setgid; - kuid_t uid; - kgid_t gid; - umode_t mode; - umode_t ptmxmode; - int reserve; - int max; -}; - -enum { - Opt_uid___2 = 0, - Opt_gid___3 = 1, - Opt_mode___2 = 2, - Opt_ptmxmode = 3, - Opt_newinstance = 4, - Opt_max = 5, - Opt_err = 6, -}; - -struct pts_fs_info { - struct ida allocated_ptys; - struct pts_mount_opts mount_opts; - struct super_block *sb; - struct dentry *ptmx_dentry; -}; - -struct ramfs_mount_opts { - umode_t mode; -}; - -struct ramfs_fs_info { - struct ramfs_mount_opts mount_opts; -}; - -enum ramfs_param { - Opt_mode___3 = 0, -}; - -enum hugetlbfs_size_type { - NO_SIZE = 0, - SIZE_STD = 1, - SIZE_PERCENT = 2, -}; - -struct hugetlbfs_fs_context { - struct hstate *hstate; - long long unsigned int max_size_opt; - long long unsigned int min_size_opt; - long int max_hpages; - long int nr_inodes; - long int min_hpages; - enum hugetlbfs_size_type max_val_type; - enum hugetlbfs_size_type min_val_type; - kuid_t uid; - kgid_t gid; - umode_t mode; -}; - -enum hugetlb_param { - Opt_gid___4 = 0, - Opt_min_size = 1, - Opt_mode___4 = 2, - Opt_nr_inodes___2 = 3, - Opt_pagesize = 4, - Opt_size___2 = 5, - Opt_uid___3 = 6, -}; - -struct getdents_callback___2 { - struct dir_context ctx; - char *name; - u64 ino; - int found; - int sequence; -}; - -typedef u16 wchar_t; - -typedef u32 unicode_t; - -struct nls_table { - const char *charset; - const char *alias; - int (*uni2char)(wchar_t, unsigned char *, int); - int (*char2uni)(const unsigned char *, int, wchar_t *); - const unsigned char *charset2lower; - const unsigned char *charset2upper; - struct module *owner; - struct nls_table *next; -}; - -enum utf16_endian { - UTF16_HOST_ENDIAN = 0, - UTF16_LITTLE_ENDIAN = 1, - UTF16_BIG_ENDIAN = 2, -}; - -struct utf8_table { - int cmask; - int cval; - int shift; - long int lmask; - long int lval; -}; - -struct utf8data; - -struct utf8cursor { - const struct utf8data *data; - const char *s; - const char *p; - const char *ss; - const char *sp; - unsigned int len; - unsigned int slen; - short int ccc; - short int nccc; - unsigned char hangul[12]; -}; - -struct utf8data { - unsigned int maxage; - unsigned int offset; -}; - -typedef const unsigned char utf8trie_t; - -typedef const unsigned char utf8leaf_t; - -typedef unsigned int autofs_wqt_t; - -struct autofs_sb_info; - -struct autofs_info { - struct dentry *dentry; - struct inode *inode; - int flags; - struct completion expire_complete; - struct list_head active; - struct list_head expiring; - struct autofs_sb_info *sbi; - long unsigned int last_used; - int count; - kuid_t uid; - kgid_t gid; - struct callback_head rcu; -}; - -struct autofs_wait_queue; - -struct autofs_sb_info { - u32 magic; - int pipefd; - struct file *pipe; - struct pid *oz_pgrp; - int version; - int sub_version; - int min_proto; - int max_proto; - unsigned int flags; - long unsigned int exp_timeout; - unsigned int type; - struct super_block *sb; - struct mutex wq_mutex; - struct mutex pipe_mutex; - spinlock_t fs_lock; - struct autofs_wait_queue *queues; - spinlock_t lookup_lock; - struct list_head active_list; - struct list_head expiring_list; - struct callback_head rcu; -}; - -struct autofs_wait_queue { - wait_queue_head_t queue; - struct autofs_wait_queue *next; - autofs_wqt_t wait_queue_token; - struct qstr name; - u32 offset; - u32 dev; - u64 ino; - kuid_t uid; - kgid_t gid; - pid_t pid; - pid_t tgid; - int status; - unsigned int wait_ctr; -}; - -enum { - Opt_err___2 = 0, - Opt_fd = 1, - Opt_uid___4 = 2, - Opt_gid___5 = 3, - Opt_pgrp = 4, - Opt_minproto = 5, - Opt_maxproto = 6, - Opt_indirect = 7, - Opt_direct = 8, - Opt_offset = 9, - Opt_strictexpire = 10, - Opt_ignore = 11, -}; - -struct autofs_packet_hdr { - int proto_version; - int type; -}; - -struct autofs_packet_expire { - struct autofs_packet_hdr hdr; - int len; - char name[256]; -}; - -enum { - AUTOFS_IOC_READY_CMD = 96, - AUTOFS_IOC_FAIL_CMD = 97, - AUTOFS_IOC_CATATONIC_CMD = 98, - AUTOFS_IOC_PROTOVER_CMD = 99, - AUTOFS_IOC_SETTIMEOUT_CMD = 100, - AUTOFS_IOC_EXPIRE_CMD = 101, -}; - -enum autofs_notify { - NFY_NONE = 0, - NFY_MOUNT = 1, - NFY_EXPIRE = 2, -}; - -enum { - AUTOFS_IOC_EXPIRE_MULTI_CMD = 102, - AUTOFS_IOC_PROTOSUBVER_CMD = 103, - AUTOFS_IOC_ASKUMOUNT_CMD = 112, -}; - -struct autofs_packet_missing { - struct autofs_packet_hdr hdr; - autofs_wqt_t wait_queue_token; - int len; - char name[256]; -}; - -struct autofs_packet_expire_multi { - struct autofs_packet_hdr hdr; - autofs_wqt_t wait_queue_token; - int len; - char name[256]; -}; - -union autofs_packet_union { - struct autofs_packet_hdr hdr; - struct autofs_packet_missing missing; - struct autofs_packet_expire expire; - struct autofs_packet_expire_multi expire_multi; -}; - -struct autofs_v5_packet { - struct autofs_packet_hdr hdr; - autofs_wqt_t wait_queue_token; - __u32 dev; - __u64 ino; - __u32 uid; - __u32 gid; - __u32 pid; - __u32 tgid; - __u32 len; - char name[256]; -}; - -typedef struct autofs_v5_packet autofs_packet_missing_indirect_t; - -typedef struct autofs_v5_packet autofs_packet_expire_indirect_t; - -typedef struct autofs_v5_packet autofs_packet_missing_direct_t; - -typedef struct autofs_v5_packet autofs_packet_expire_direct_t; - -union autofs_v5_packet_union { - struct autofs_packet_hdr hdr; - struct autofs_v5_packet v5_packet; - autofs_packet_missing_indirect_t missing_indirect; - autofs_packet_expire_indirect_t expire_indirect; - autofs_packet_missing_direct_t missing_direct; - autofs_packet_expire_direct_t expire_direct; -}; - -struct args_protover { - __u32 version; -}; - -struct args_protosubver { - __u32 sub_version; -}; - -struct args_openmount { - __u32 devid; -}; - -struct args_ready { - __u32 token; -}; - -struct args_fail { - __u32 token; - __s32 status; -}; - -struct args_setpipefd { - __s32 pipefd; -}; - -struct args_timeout { - __u64 timeout; -}; - -struct args_requester { - __u32 uid; - __u32 gid; -}; - -struct args_expire { - __u32 how; -}; - -struct args_askumount { - __u32 may_umount; -}; - -struct args_in { - __u32 type; -}; - -struct args_out { - __u32 devid; - __u32 magic; -}; - -struct args_ismountpoint { - union { - struct args_in in; - struct args_out out; - }; -}; - -struct autofs_dev_ioctl { - __u32 ver_major; - __u32 ver_minor; - __u32 size; - __s32 ioctlfd; - union { - struct args_protover protover; - struct args_protosubver protosubver; - struct args_openmount openmount; - struct args_ready ready; - struct args_fail fail; - struct args_setpipefd setpipefd; - struct args_timeout timeout; - struct args_requester requester; - struct args_expire expire; - struct args_askumount askumount; - struct args_ismountpoint ismountpoint; - }; - char path[0]; -}; - -enum { - AUTOFS_DEV_IOCTL_VERSION_CMD = 113, - AUTOFS_DEV_IOCTL_PROTOVER_CMD = 114, - AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD = 115, - AUTOFS_DEV_IOCTL_OPENMOUNT_CMD = 116, - AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD = 117, - AUTOFS_DEV_IOCTL_READY_CMD = 118, - AUTOFS_DEV_IOCTL_FAIL_CMD = 119, - AUTOFS_DEV_IOCTL_SETPIPEFD_CMD = 120, - AUTOFS_DEV_IOCTL_CATATONIC_CMD = 121, - AUTOFS_DEV_IOCTL_TIMEOUT_CMD = 122, - AUTOFS_DEV_IOCTL_REQUESTER_CMD = 123, - AUTOFS_DEV_IOCTL_EXPIRE_CMD = 124, - AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD = 125, - AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD = 126, -}; - -typedef int (*ioctl_fn)(struct file *, struct autofs_sb_info *, struct autofs_dev_ioctl *); - -struct debugfs_fsdata { - const struct file_operations *real_fops; - refcount_t active_users; - struct completion active_users_drained; -}; - -struct debugfs_mount_opts { - kuid_t uid; - kgid_t gid; - umode_t mode; -}; - -enum { - Opt_uid___5 = 0, - Opt_gid___6 = 1, - Opt_mode___5 = 2, - Opt_err___3 = 3, -}; - -struct debugfs_fs_info { - struct debugfs_mount_opts mount_opts; -}; - -struct debugfs_reg32 { - char *name; - long unsigned int offset; -}; - -struct debugfs_regset32 { - const struct debugfs_reg32 *regs; - int nregs; - void *base; - struct device *dev; -}; - -struct debugfs_devm_entry { - int (*read)(struct seq_file *, void *); - struct device *dev; -}; - -struct tracefs_dir_ops { - int (*mkdir)(const char *); - int (*rmdir)(const char *); -}; - -struct tracefs_mount_opts { - kuid_t uid; - kgid_t gid; - umode_t mode; -}; - -struct tracefs_fs_info { - struct tracefs_mount_opts mount_opts; -}; - -enum pstore_type_id { - PSTORE_TYPE_DMESG = 0, - PSTORE_TYPE_MCE = 1, - PSTORE_TYPE_CONSOLE = 2, - PSTORE_TYPE_FTRACE = 3, - PSTORE_TYPE_PPC_RTAS = 4, - PSTORE_TYPE_PPC_OF = 5, - PSTORE_TYPE_PPC_COMMON = 6, - PSTORE_TYPE_PMSG = 7, - PSTORE_TYPE_PPC_OPAL = 8, - PSTORE_TYPE_MAX = 9, -}; - -struct pstore_info; - -struct pstore_record { - struct pstore_info *psi; - enum pstore_type_id type; - u64 id; - struct timespec64 time; - char *buf; - ssize_t size; - ssize_t ecc_notice_size; - int count; - enum kmsg_dump_reason reason; - unsigned int part; - bool compressed; -}; - -struct pstore_info { - struct module *owner; - const char *name; - struct semaphore buf_lock; - char *buf; - size_t bufsize; - struct mutex read_mutex; - int flags; - int max_reason; - void *data; - int (*open)(struct pstore_info *); - int (*close)(struct pstore_info *); - ssize_t (*read)(struct pstore_record *); - int (*write)(struct pstore_record *); - int (*write_user)(struct pstore_record *, const char *); - int (*erase)(struct pstore_record *); -}; - -struct pstore_ftrace_record { - long unsigned int ip; - long unsigned int parent_ip; - u64 ts; -}; - -struct pstore_private { - struct list_head list; - struct dentry *dentry; - struct pstore_record *record; - size_t total_size; -}; - -struct pstore_ftrace_seq_data { - const void *ptr; - size_t off; - size_t size; -}; - -enum { - Opt_kmsg_bytes = 0, - Opt_err___4 = 1, -}; - -struct crypto_comp { - struct crypto_tfm base; -}; - -struct pstore_zbackend { - int (*zbufsize)(size_t); - const char *name; -}; - -struct efi_variable { - efi_char16_t VariableName[512]; - efi_guid_t VendorGuid; - long unsigned int DataSize; - __u8 Data[1024]; - efi_status_t Status; - __u32 Attributes; -} __attribute__((packed)); - -struct efivar_entry { - struct efi_variable var; - struct list_head list; - struct kobject kobj; - bool scanning; - bool deleting; -}; - -typedef unsigned int __kernel_mode_t; - -struct ipc64_perm { - __kernel_key_t key; - __kernel_uid32_t uid; - __kernel_gid32_t gid; - __kernel_uid32_t cuid; - __kernel_gid32_t cgid; - __kernel_mode_t mode; - unsigned char __pad1[0]; - short unsigned int seq; - short unsigned int __pad2; - __kernel_ulong_t __unused1; - __kernel_ulong_t __unused2; -}; - -typedef s32 compat_key_t; - -typedef u32 __compat_gid32_t; - -struct compat_ipc64_perm { - compat_key_t key; - __compat_uid32_t uid; - __compat_gid32_t gid; - __compat_uid32_t cuid; - __compat_gid32_t cgid; - short unsigned int mode; - short unsigned int __pad1; - short unsigned int seq; - short unsigned int __pad2; - compat_ulong_t unused1; - compat_ulong_t unused2; -}; - -struct compat_ipc_perm { - key_t key; - __compat_uid_t uid; - __compat_gid_t gid; - __compat_uid_t cuid; - __compat_gid_t cgid; - compat_mode_t mode; - short unsigned int seq; -}; - -struct ipc_perm { - __kernel_key_t key; - __kernel_uid_t uid; - __kernel_gid_t gid; - __kernel_uid_t cuid; - __kernel_gid_t cgid; - __kernel_mode_t mode; - short unsigned int seq; -}; - -struct ipc_params { - key_t key; - int flg; - union { - size_t size; - int nsems; - } u; -}; - -struct ipc_ops { - int (*getnew)(struct ipc_namespace *, struct ipc_params *); - int (*associate)(struct kern_ipc_perm *, int); - int (*more_checks)(struct kern_ipc_perm *, struct ipc_params *); -}; - -struct ipc_proc_iface { - const char *path; - const char *header; - int ids; - int (*show)(struct seq_file *, void *); -}; - -struct ipc_proc_iter { - struct ipc_namespace *ns; - struct pid_namespace *pid_ns; - struct ipc_proc_iface *iface; -}; - -struct msg_msgseg; - -struct msg_msg { - struct list_head m_list; - long int m_type; - size_t m_ts; - struct msg_msgseg *next; - void *security; -}; - -struct msg_msgseg { - struct msg_msgseg *next; -}; - -typedef int __kernel_ipc_pid_t; - -struct msgbuf { - __kernel_long_t mtype; - char mtext[1]; -}; - -struct msg; - -struct msqid_ds { - struct ipc_perm msg_perm; - struct msg *msg_first; - struct msg *msg_last; - __kernel_old_time_t msg_stime; - __kernel_old_time_t msg_rtime; - __kernel_old_time_t msg_ctime; - long unsigned int msg_lcbytes; - long unsigned int msg_lqbytes; - short unsigned int msg_cbytes; - short unsigned int msg_qnum; - short unsigned int msg_qbytes; - __kernel_ipc_pid_t msg_lspid; - __kernel_ipc_pid_t msg_lrpid; -}; - -struct msqid64_ds { - struct ipc64_perm msg_perm; - long int msg_stime; - long int msg_rtime; - long int msg_ctime; - long unsigned int msg_cbytes; - long unsigned int msg_qnum; - long unsigned int msg_qbytes; - __kernel_pid_t msg_lspid; - __kernel_pid_t msg_lrpid; - long unsigned int __unused4; - long unsigned int __unused5; -}; - -struct msginfo { - int msgpool; - int msgmap; - int msgmax; - int msgmnb; - int msgmni; - int msgssz; - int msgtql; - short unsigned int msgseg; -}; - -typedef u16 compat_ipc_pid_t; - -struct compat_msqid64_ds { - struct compat_ipc64_perm msg_perm; - compat_ulong_t msg_stime; - compat_ulong_t msg_stime_high; - compat_ulong_t msg_rtime; - compat_ulong_t msg_rtime_high; - compat_ulong_t msg_ctime; - compat_ulong_t msg_ctime_high; - compat_ulong_t msg_cbytes; - compat_ulong_t msg_qnum; - compat_ulong_t msg_qbytes; - compat_pid_t msg_lspid; - compat_pid_t msg_lrpid; - compat_ulong_t __unused4; - compat_ulong_t __unused5; -}; - -struct msg_queue { - struct kern_ipc_perm q_perm; - time64_t q_stime; - time64_t q_rtime; - time64_t q_ctime; - long unsigned int q_cbytes; - long unsigned int q_qnum; - long unsigned int q_qbytes; - struct pid *q_lspid; - struct pid *q_lrpid; - struct list_head q_messages; - struct list_head q_receivers; - struct list_head q_senders; - long: 64; - long: 64; -}; - -struct msg_receiver { - struct list_head r_list; - struct task_struct *r_tsk; - int r_mode; - long int r_msgtype; - long int r_maxsize; - struct msg_msg *r_msg; -}; - -struct msg_sender { - struct list_head list; - struct task_struct *tsk; - size_t msgsz; -}; - -struct compat_msqid_ds { - struct compat_ipc_perm msg_perm; - compat_uptr_t msg_first; - compat_uptr_t msg_last; - old_time32_t msg_stime; - old_time32_t msg_rtime; - old_time32_t msg_ctime; - compat_ulong_t msg_lcbytes; - compat_ulong_t msg_lqbytes; - short unsigned int msg_cbytes; - short unsigned int msg_qnum; - short unsigned int msg_qbytes; - compat_ipc_pid_t msg_lspid; - compat_ipc_pid_t msg_lrpid; -}; - -struct compat_msgbuf { - compat_long_t mtype; - char mtext[1]; -}; - -struct sem; - -struct sem_queue; - -struct sem_undo; - -struct semid_ds { - struct ipc_perm sem_perm; - __kernel_old_time_t sem_otime; - __kernel_old_time_t sem_ctime; - struct sem *sem_base; - struct sem_queue *sem_pending; - struct sem_queue **sem_pending_last; - struct sem_undo *undo; - short unsigned int sem_nsems; -}; - -struct sem { - int semval; - struct pid *sempid; - spinlock_t lock; - struct list_head pending_alter; - struct list_head pending_const; - time64_t sem_otime; -}; - -struct sem_queue { - struct list_head list; - struct task_struct *sleeper; - struct sem_undo *undo; - struct pid *pid; - int status; - struct sembuf *sops; - struct sembuf *blocking; - int nsops; - bool alter; - bool dupsop; -}; - -struct sem_undo { - struct list_head list_proc; - struct callback_head rcu; - struct sem_undo_list *ulp; - struct list_head list_id; - int semid; - short int *semadj; -}; - -struct semid64_ds { - struct ipc64_perm sem_perm; - __kernel_long_t sem_otime; - __kernel_ulong_t __unused1; - __kernel_long_t sem_ctime; - __kernel_ulong_t __unused2; - __kernel_ulong_t sem_nsems; - __kernel_ulong_t __unused3; - __kernel_ulong_t __unused4; -}; - -struct seminfo { - int semmap; - int semmni; - int semmns; - int semmnu; - int semmsl; - int semopm; - int semume; - int semusz; - int semvmx; - int semaem; -}; - -struct sem_undo_list { - refcount_t refcnt; - spinlock_t lock; - struct list_head list_proc; -}; - -struct compat_semid64_ds { - struct compat_ipc64_perm sem_perm; - compat_ulong_t sem_otime; - compat_ulong_t sem_otime_high; - compat_ulong_t sem_ctime; - compat_ulong_t sem_ctime_high; - compat_ulong_t sem_nsems; - compat_ulong_t __unused3; - compat_ulong_t __unused4; -}; - -struct sem_array { - struct kern_ipc_perm sem_perm; - time64_t sem_ctime; - struct list_head pending_alter; - struct list_head pending_const; - struct list_head list_id; - int sem_nsems; - int complex_count; - unsigned int use_global_lock; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct sem sems[0]; -}; - -struct compat_semid_ds { - struct compat_ipc_perm sem_perm; - old_time32_t sem_otime; - old_time32_t sem_ctime; - compat_uptr_t sem_base; - compat_uptr_t sem_pending; - compat_uptr_t sem_pending_last; - compat_uptr_t undo; - short unsigned int sem_nsems; -}; - -struct shmid_ds { - struct ipc_perm shm_perm; - int shm_segsz; - __kernel_old_time_t shm_atime; - __kernel_old_time_t shm_dtime; - __kernel_old_time_t shm_ctime; - __kernel_ipc_pid_t shm_cpid; - __kernel_ipc_pid_t shm_lpid; - short unsigned int shm_nattch; - short unsigned int shm_unused; - void *shm_unused2; - void *shm_unused3; -}; - -struct shmid64_ds { - struct ipc64_perm shm_perm; - size_t shm_segsz; - long int shm_atime; - long int shm_dtime; - long int shm_ctime; - __kernel_pid_t shm_cpid; - __kernel_pid_t shm_lpid; - long unsigned int shm_nattch; - long unsigned int __unused4; - long unsigned int __unused5; -}; - -struct shminfo64 { - long unsigned int shmmax; - long unsigned int shmmin; - long unsigned int shmmni; - long unsigned int shmseg; - long unsigned int shmall; - long unsigned int __unused1; - long unsigned int __unused2; - long unsigned int __unused3; - long unsigned int __unused4; -}; - -struct shminfo { - int shmmax; - int shmmin; - int shmmni; - int shmseg; - int shmall; -}; - -struct shm_info { - int used_ids; - __kernel_ulong_t shm_tot; - __kernel_ulong_t shm_rss; - __kernel_ulong_t shm_swp; - __kernel_ulong_t swap_attempts; - __kernel_ulong_t swap_successes; -}; - -struct compat_shmid64_ds { - struct compat_ipc64_perm shm_perm; - compat_size_t shm_segsz; - compat_ulong_t shm_atime; - compat_ulong_t shm_atime_high; - compat_ulong_t shm_dtime; - compat_ulong_t shm_dtime_high; - compat_ulong_t shm_ctime; - compat_ulong_t shm_ctime_high; - compat_pid_t shm_cpid; - compat_pid_t shm_lpid; - compat_ulong_t shm_nattch; - compat_ulong_t __unused4; - compat_ulong_t __unused5; -}; - -struct shmid_kernel { - struct kern_ipc_perm shm_perm; - struct file *shm_file; - long unsigned int shm_nattch; - long unsigned int shm_segsz; - time64_t shm_atim; - time64_t shm_dtim; - time64_t shm_ctim; - struct pid *shm_cprid; - struct pid *shm_lprid; - struct ucounts *mlock_ucounts; - struct task_struct *shm_creator; - struct list_head shm_clist; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct shm_file_data { - int id; - struct ipc_namespace *ns; - struct file *file; - const struct vm_operations_struct *vm_ops; -}; - -struct compat_shmid_ds { - struct compat_ipc_perm shm_perm; - int shm_segsz; - old_time32_t shm_atime; - old_time32_t shm_dtime; - old_time32_t shm_ctime; - compat_ipc_pid_t shm_cpid; - compat_ipc_pid_t shm_lpid; - short unsigned int shm_nattch; - short unsigned int shm_unused; - compat_uptr_t shm_unused2; - compat_uptr_t shm_unused3; -}; - -struct compat_shminfo64 { - compat_ulong_t shmmax; - compat_ulong_t shmmin; - compat_ulong_t shmmni; - compat_ulong_t shmseg; - compat_ulong_t shmall; - compat_ulong_t __unused1; - compat_ulong_t __unused2; - compat_ulong_t __unused3; - compat_ulong_t __unused4; -}; - -struct compat_shm_info { - compat_int_t used_ids; - compat_ulong_t shm_tot; - compat_ulong_t shm_rss; - compat_ulong_t shm_swp; - compat_ulong_t swap_attempts; - compat_ulong_t swap_successes; -}; - -struct compat_ipc_kludge { - compat_uptr_t msgp; - compat_long_t msgtyp; -}; - -struct mqueue_fs_context { - struct ipc_namespace *ipc_ns; -}; - -struct posix_msg_tree_node { - struct rb_node rb_node; - struct list_head msg_list; - int priority; -}; - -struct ext_wait_queue { - struct task_struct *task; - struct list_head list; - struct msg_msg *msg; - int state; -}; - -struct mqueue_inode_info { - spinlock_t lock; - struct inode vfs_inode; - wait_queue_head_t wait_q; - struct rb_root msg_tree; - struct rb_node *msg_tree_rightmost; - struct posix_msg_tree_node *node_cache; - struct mq_attr attr; - struct sigevent notify; - struct pid *notify_owner; - u32 notify_self_exec_id; - struct user_namespace *notify_user_ns; - struct ucounts *ucounts; - struct sock *notify_sock; - struct sk_buff *notify_cookie; - struct ext_wait_queue e_wait_q[2]; - long unsigned int qsize; -}; - -struct compat_mq_attr { - compat_long_t mq_flags; - compat_long_t mq_maxmsg; - compat_long_t mq_msgsize; - compat_long_t mq_curmsgs; - compat_long_t __reserved[4]; -}; - -struct key_user { - struct rb_node node; - struct mutex cons_lock; - spinlock_t lock; - refcount_t usage; - atomic_t nkeys; - atomic_t nikeys; - kuid_t uid; - int qnkeys; - int qnbytes; -}; - -enum key_notification_subtype { - NOTIFY_KEY_INSTANTIATED = 0, - NOTIFY_KEY_UPDATED = 1, - NOTIFY_KEY_LINKED = 2, - NOTIFY_KEY_UNLINKED = 3, - NOTIFY_KEY_CLEARED = 4, - NOTIFY_KEY_REVOKED = 5, - NOTIFY_KEY_INVALIDATED = 6, - NOTIFY_KEY_SETATTR = 7, -}; - -struct key_notification { - struct watch_notification watch; - __u32 key_id; - __u32 aux; -}; - -struct assoc_array_edit; - -struct assoc_array_ops { - long unsigned int (*get_key_chunk)(const void *, int); - long unsigned int (*get_object_key_chunk)(const void *, int); - bool (*compare_object)(const void *, const void *); - int (*diff_objects)(const void *, const void *); - void (*free_object)(void *); -}; - -struct assoc_array_node { - struct assoc_array_ptr *back_pointer; - u8 parent_slot; - struct assoc_array_ptr *slots[16]; - long unsigned int nr_leaves_on_branch; -}; - -struct assoc_array_shortcut { - struct assoc_array_ptr *back_pointer; - int parent_slot; - int skip_to_level; - struct assoc_array_ptr *next_node; - long unsigned int index_key[0]; -}; - -struct assoc_array_edit___2 { - struct callback_head rcu; - struct assoc_array *array; - const struct assoc_array_ops *ops; - const struct assoc_array_ops *ops_for_excised_subtree; - struct assoc_array_ptr *leaf; - struct assoc_array_ptr **leaf_p; - struct assoc_array_ptr *dead_leaf; - struct assoc_array_ptr *new_meta[3]; - struct assoc_array_ptr *excised_meta[1]; - struct assoc_array_ptr *excised_subtree; - struct assoc_array_ptr **set_backpointers[16]; - struct assoc_array_ptr *set_backpointers_to; - struct assoc_array_node *adjust_count_on; - long int adjust_count_by; - struct { - struct assoc_array_ptr **ptr; - struct assoc_array_ptr *to; - } set[2]; - struct { - u8 *p; - u8 to; - } set_parent_slot[1]; - u8 segment_cache[17]; -}; - -struct keyring_search_context { - struct keyring_index_key index_key; - const struct cred *cred; - struct key_match_data match_data; - unsigned int flags; - int (*iterator)(const void *, void *); - int skipped_ret; - bool possessed; - key_ref_t result; - time64_t now; -}; - -struct keyring_read_iterator_context { - size_t buflen; - size_t count; - key_serial_t *buffer; -}; - -struct keyctl_dh_params { - union { - __s32 private; - __s32 priv; - }; - __s32 prime; - __s32 base; -}; - -struct keyctl_kdf_params { - char *hashname; - char *otherinfo; - __u32 otherinfolen; - __u32 __spare[8]; -}; - -struct keyctl_pkey_query { - __u32 supported_ops; - __u32 key_size; - __u16 max_data_size; - __u16 max_sig_size; - __u16 max_enc_size; - __u16 max_dec_size; - __u32 __spare[10]; -}; - -struct keyctl_pkey_params { - __s32 key_id; - __u32 in_len; - union { - __u32 out_len; - __u32 in2_len; - }; - __u32 __spare[7]; -}; - -struct request_key_auth { - struct callback_head rcu; - struct key *target_key; - struct key *dest_keyring; - const struct cred *cred; - void *callout_info; - size_t callout_len; - pid_t pid; - char op[8]; -}; - -struct compat_keyctl_kdf_params { - compat_uptr_t hashname; - compat_uptr_t otherinfo; - __u32 otherinfolen; - __u32 __spare[8]; -}; - -struct kpp_request { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int src_len; - unsigned int dst_len; - void *__ctx[0]; -}; - -struct crypto_kpp { - struct crypto_tfm base; -}; - -struct kpp_alg { - int (*set_secret)(struct crypto_kpp *, const void *, unsigned int); - int (*generate_public_key)(struct kpp_request *); - int (*compute_shared_secret)(struct kpp_request *); - unsigned int (*max_size)(struct crypto_kpp *); - int (*init)(struct crypto_kpp *); - void (*exit)(struct crypto_kpp *); - unsigned int reqsize; - struct crypto_alg base; -}; - -struct dh { - void *key; - void *p; - void *q; - void *g; - unsigned int key_size; - unsigned int p_size; - unsigned int q_size; - unsigned int g_size; -}; - -struct dh_completion { - struct completion completion; - int err; -}; - -struct kdf_sdesc { - struct shash_desc shash; - char ctx[0]; -}; - -enum { - Opt_err___5 = 0, - Opt_enc = 1, - Opt_hash = 2, -}; - -struct vfs_cap_data { - __le32 magic_etc; - struct { - __le32 permitted; - __le32 inheritable; - } data[2]; -}; - -struct vfs_ns_cap_data { - __le32 magic_etc; - struct { - __le32 permitted; - __le32 inheritable; - } data[2]; - __le32 rootid; -}; - -struct sctp_endpoint; - -union security_list_options { - int (*binder_set_context_mgr)(struct task_struct *); - int (*binder_transaction)(struct task_struct *, struct task_struct *); - int (*binder_transfer_binder)(struct task_struct *, struct task_struct *); - int (*binder_transfer_file)(struct task_struct *, struct task_struct *, struct file *); - int (*ptrace_access_check)(struct task_struct *, unsigned int); - int (*ptrace_traceme)(struct task_struct *); - int (*capget)(struct task_struct *, kernel_cap_t *, kernel_cap_t *, kernel_cap_t *); - int (*capset)(struct cred *, const struct cred *, const kernel_cap_t *, const kernel_cap_t *, const kernel_cap_t *); - int (*capable)(const struct cred *, struct user_namespace *, int, unsigned int); - int (*quotactl)(int, int, int, struct super_block *); - int (*quota_on)(struct dentry *); - int (*syslog)(int); - int (*settime)(const struct timespec64 *, const struct timezone *); - int (*vm_enough_memory)(struct mm_struct *, long int); - int (*bprm_creds_for_exec)(struct linux_binprm *); - int (*bprm_creds_from_file)(struct linux_binprm *, struct file *); - int (*bprm_check_security)(struct linux_binprm *); - void (*bprm_committing_creds)(struct linux_binprm *); - void (*bprm_committed_creds)(struct linux_binprm *); - int (*fs_context_dup)(struct fs_context *, struct fs_context *); - int (*fs_context_parse_param)(struct fs_context *, struct fs_parameter *); - int (*sb_alloc_security)(struct super_block *); - void (*sb_delete)(struct super_block *); - void (*sb_free_security)(struct super_block *); - void (*sb_free_mnt_opts)(void *); - int (*sb_eat_lsm_opts)(char *, void **); - int (*sb_mnt_opts_compat)(struct super_block *, void *); - int (*sb_remount)(struct super_block *, void *); - int (*sb_kern_mount)(struct super_block *); - int (*sb_show_options)(struct seq_file *, struct super_block *); - int (*sb_statfs)(struct dentry *); - int (*sb_mount)(const char *, const struct path *, const char *, long unsigned int, void *); - int (*sb_umount)(struct vfsmount *, int); - int (*sb_pivotroot)(const struct path *, const struct path *); - int (*sb_set_mnt_opts)(struct super_block *, void *, long unsigned int, long unsigned int *); - int (*sb_clone_mnt_opts)(const struct super_block *, struct super_block *, long unsigned int, long unsigned int *); - int (*sb_add_mnt_opt)(const char *, const char *, int, void **); - int (*move_mount)(const struct path *, const struct path *); - int (*dentry_init_security)(struct dentry *, int, const struct qstr *, void **, u32 *); - int (*dentry_create_files_as)(struct dentry *, int, struct qstr *, const struct cred *, struct cred *); - int (*path_unlink)(const struct path *, struct dentry *); - int (*path_mkdir)(const struct path *, struct dentry *, umode_t); - int (*path_rmdir)(const struct path *, struct dentry *); - int (*path_mknod)(const struct path *, struct dentry *, umode_t, unsigned int); - int (*path_truncate)(const struct path *); - int (*path_symlink)(const struct path *, struct dentry *, const char *); - int (*path_link)(struct dentry *, const struct path *, struct dentry *); - int (*path_rename)(const struct path *, struct dentry *, const struct path *, struct dentry *); - int (*path_chmod)(const struct path *, umode_t); - int (*path_chown)(const struct path *, kuid_t, kgid_t); - int (*path_chroot)(const struct path *); - int (*path_notify)(const struct path *, u64, unsigned int); - int (*inode_alloc_security)(struct inode *); - void (*inode_free_security)(struct inode *); - int (*inode_init_security)(struct inode *, struct inode *, const struct qstr *, const char **, void **, size_t *); - int (*inode_init_security_anon)(struct inode *, const struct qstr *, const struct inode *); - int (*inode_create)(struct inode *, struct dentry *, umode_t); - int (*inode_link)(struct dentry *, struct inode *, struct dentry *); - int (*inode_unlink)(struct inode *, struct dentry *); - int (*inode_symlink)(struct inode *, struct dentry *, const char *); - int (*inode_mkdir)(struct inode *, struct dentry *, umode_t); - int (*inode_rmdir)(struct inode *, struct dentry *); - int (*inode_mknod)(struct inode *, struct dentry *, umode_t, dev_t); - int (*inode_rename)(struct inode *, struct dentry *, struct inode *, struct dentry *); - int (*inode_readlink)(struct dentry *); - int (*inode_follow_link)(struct dentry *, struct inode *, bool); - int (*inode_permission)(struct inode *, int); - int (*inode_setattr)(struct dentry *, struct iattr *); - int (*inode_getattr)(const struct path *); - int (*inode_setxattr)(struct user_namespace *, struct dentry *, const char *, const void *, size_t, int); - void (*inode_post_setxattr)(struct dentry *, const char *, const void *, size_t, int); - int (*inode_getxattr)(struct dentry *, const char *); - int (*inode_listxattr)(struct dentry *); - int (*inode_removexattr)(struct user_namespace *, struct dentry *, const char *); - int (*inode_need_killpriv)(struct dentry *); - int (*inode_killpriv)(struct user_namespace *, struct dentry *); - int (*inode_getsecurity)(struct user_namespace *, struct inode *, const char *, void **, bool); - int (*inode_setsecurity)(struct inode *, const char *, const void *, size_t, int); - int (*inode_listsecurity)(struct inode *, char *, size_t); - void (*inode_getsecid)(struct inode *, u32 *); - int (*inode_copy_up)(struct dentry *, struct cred **); - int (*inode_copy_up_xattr)(const char *); - int (*kernfs_init_security)(struct kernfs_node *, struct kernfs_node *); - int (*file_permission)(struct file *, int); - int (*file_alloc_security)(struct file *); - void (*file_free_security)(struct file *); - int (*file_ioctl)(struct file *, unsigned int, long unsigned int); - int (*mmap_addr)(long unsigned int); - int (*mmap_file)(struct file *, long unsigned int, long unsigned int, long unsigned int); - int (*file_mprotect)(struct vm_area_struct *, long unsigned int, long unsigned int); - int (*file_lock)(struct file *, unsigned int); - int (*file_fcntl)(struct file *, unsigned int, long unsigned int); - void (*file_set_fowner)(struct file *); - int (*file_send_sigiotask)(struct task_struct *, struct fown_struct *, int); - int (*file_receive)(struct file *); - int (*file_open)(struct file *); - int (*task_alloc)(struct task_struct *, long unsigned int); - void (*task_free)(struct task_struct *); - int (*cred_alloc_blank)(struct cred *, gfp_t); - void (*cred_free)(struct cred *); - int (*cred_prepare)(struct cred *, const struct cred *, gfp_t); - void (*cred_transfer)(struct cred *, const struct cred *); - void (*cred_getsecid)(const struct cred *, u32 *); - int (*kernel_act_as)(struct cred *, u32); - int (*kernel_create_files_as)(struct cred *, struct inode *); - int (*kernel_module_request)(char *); - int (*kernel_load_data)(enum kernel_load_data_id, bool); - int (*kernel_post_load_data)(char *, loff_t, enum kernel_load_data_id, char *); - int (*kernel_read_file)(struct file *, enum kernel_read_file_id, bool); - int (*kernel_post_read_file)(struct file *, char *, loff_t, enum kernel_read_file_id); - int (*task_fix_setuid)(struct cred *, const struct cred *, int); - int (*task_fix_setgid)(struct cred *, const struct cred *, int); - int (*task_setpgid)(struct task_struct *, pid_t); - int (*task_getpgid)(struct task_struct *); - int (*task_getsid)(struct task_struct *); - void (*task_getsecid_subj)(struct task_struct *, u32 *); - void (*task_getsecid_obj)(struct task_struct *, u32 *); - int (*task_setnice)(struct task_struct *, int); - int (*task_setioprio)(struct task_struct *, int); - int (*task_getioprio)(struct task_struct *); - int (*task_prlimit)(const struct cred *, const struct cred *, unsigned int); - int (*task_setrlimit)(struct task_struct *, unsigned int, struct rlimit *); - int (*task_setscheduler)(struct task_struct *); - int (*task_getscheduler)(struct task_struct *); - int (*task_movememory)(struct task_struct *); - int (*task_kill)(struct task_struct *, struct kernel_siginfo *, int, const struct cred *); - int (*task_prctl)(int, long unsigned int, long unsigned int, long unsigned int, long unsigned int); - void (*task_to_inode)(struct task_struct *, struct inode *); - int (*ipc_permission)(struct kern_ipc_perm *, short int); - void (*ipc_getsecid)(struct kern_ipc_perm *, u32 *); - int (*msg_msg_alloc_security)(struct msg_msg *); - void (*msg_msg_free_security)(struct msg_msg *); - int (*msg_queue_alloc_security)(struct kern_ipc_perm *); - void (*msg_queue_free_security)(struct kern_ipc_perm *); - int (*msg_queue_associate)(struct kern_ipc_perm *, int); - int (*msg_queue_msgctl)(struct kern_ipc_perm *, int); - int (*msg_queue_msgsnd)(struct kern_ipc_perm *, struct msg_msg *, int); - int (*msg_queue_msgrcv)(struct kern_ipc_perm *, struct msg_msg *, struct task_struct *, long int, int); - int (*shm_alloc_security)(struct kern_ipc_perm *); - void (*shm_free_security)(struct kern_ipc_perm *); - int (*shm_associate)(struct kern_ipc_perm *, int); - int (*shm_shmctl)(struct kern_ipc_perm *, int); - int (*shm_shmat)(struct kern_ipc_perm *, char *, int); - int (*sem_alloc_security)(struct kern_ipc_perm *); - void (*sem_free_security)(struct kern_ipc_perm *); - int (*sem_associate)(struct kern_ipc_perm *, int); - int (*sem_semctl)(struct kern_ipc_perm *, int); - int (*sem_semop)(struct kern_ipc_perm *, struct sembuf *, unsigned int, int); - int (*netlink_send)(struct sock *, struct sk_buff *); - void (*d_instantiate)(struct dentry *, struct inode *); - int (*getprocattr)(struct task_struct *, char *, char **); - int (*setprocattr)(const char *, void *, size_t); - int (*ismaclabel)(const char *); - int (*secid_to_secctx)(u32, char **, u32 *); - int (*secctx_to_secid)(const char *, u32, u32 *); - void (*release_secctx)(char *, u32); - void (*inode_invalidate_secctx)(struct inode *); - int (*inode_notifysecctx)(struct inode *, void *, u32); - int (*inode_setsecctx)(struct dentry *, void *, u32); - int (*inode_getsecctx)(struct inode *, void **, u32 *); - int (*post_notification)(const struct cred *, const struct cred *, struct watch_notification *); - int (*watch_key)(struct key *); - int (*unix_stream_connect)(struct sock *, struct sock *, struct sock *); - int (*unix_may_send)(struct socket *, struct socket *); - int (*socket_create)(int, int, int, int); - int (*socket_post_create)(struct socket *, int, int, int, int); - int (*socket_socketpair)(struct socket *, struct socket *); - int (*socket_bind)(struct socket *, struct sockaddr *, int); - int (*socket_connect)(struct socket *, struct sockaddr *, int); - int (*socket_listen)(struct socket *, int); - int (*socket_accept)(struct socket *, struct socket *); - int (*socket_sendmsg)(struct socket *, struct msghdr *, int); - int (*socket_recvmsg)(struct socket *, struct msghdr *, int, int); - int (*socket_getsockname)(struct socket *); - int (*socket_getpeername)(struct socket *); - int (*socket_getsockopt)(struct socket *, int, int); - int (*socket_setsockopt)(struct socket *, int, int); - int (*socket_shutdown)(struct socket *, int); - int (*socket_sock_rcv_skb)(struct sock *, struct sk_buff *); - int (*socket_getpeersec_stream)(struct socket *, char *, int *, unsigned int); - int (*socket_getpeersec_dgram)(struct socket *, struct sk_buff *, u32 *); - int (*sk_alloc_security)(struct sock *, int, gfp_t); - void (*sk_free_security)(struct sock *); - void (*sk_clone_security)(const struct sock *, struct sock *); - void (*sk_getsecid)(struct sock *, u32 *); - void (*sock_graft)(struct sock *, struct socket *); - int (*inet_conn_request)(const struct sock *, struct sk_buff *, struct request_sock *); - void (*inet_csk_clone)(struct sock *, const struct request_sock *); - void (*inet_conn_established)(struct sock *, struct sk_buff *); - int (*secmark_relabel_packet)(u32); - void (*secmark_refcount_inc)(); - void (*secmark_refcount_dec)(); - void (*req_classify_flow)(const struct request_sock *, struct flowi_common *); - int (*tun_dev_alloc_security)(void **); - void (*tun_dev_free_security)(void *); - int (*tun_dev_create)(); - int (*tun_dev_attach_queue)(void *); - int (*tun_dev_attach)(struct sock *, void *); - int (*tun_dev_open)(void *); - int (*sctp_assoc_request)(struct sctp_endpoint *, struct sk_buff *); - int (*sctp_bind_connect)(struct sock *, int, struct sockaddr *, int); - void (*sctp_sk_clone)(struct sctp_endpoint *, struct sock *, struct sock *); - int (*ib_pkey_access)(void *, u64, u16); - int (*ib_endport_manage_subnet)(void *, const char *, u8); - int (*ib_alloc_security)(void **); - void (*ib_free_security)(void *); - int (*xfrm_policy_alloc_security)(struct xfrm_sec_ctx **, struct xfrm_user_sec_ctx *, gfp_t); - int (*xfrm_policy_clone_security)(struct xfrm_sec_ctx *, struct xfrm_sec_ctx **); - void (*xfrm_policy_free_security)(struct xfrm_sec_ctx *); - int (*xfrm_policy_delete_security)(struct xfrm_sec_ctx *); - int (*xfrm_state_alloc)(struct xfrm_state *, struct xfrm_user_sec_ctx *); - int (*xfrm_state_alloc_acquire)(struct xfrm_state *, struct xfrm_sec_ctx *, u32); - void (*xfrm_state_free_security)(struct xfrm_state *); - int (*xfrm_state_delete_security)(struct xfrm_state *); - int (*xfrm_policy_lookup)(struct xfrm_sec_ctx *, u32); - int (*xfrm_state_pol_flow_match)(struct xfrm_state *, struct xfrm_policy *, const struct flowi_common *); - int (*xfrm_decode_session)(struct sk_buff *, u32 *, int); - int (*key_alloc)(struct key *, const struct cred *, long unsigned int); - void (*key_free)(struct key *); - int (*key_permission)(key_ref_t, const struct cred *, enum key_need_perm); - int (*key_getsecurity)(struct key *, char **); - int (*audit_rule_init)(u32, u32, char *, void **); - int (*audit_rule_known)(struct audit_krule *); - int (*audit_rule_match)(u32, u32, u32, void *); - void (*audit_rule_free)(void *); - int (*bpf)(int, union bpf_attr *, unsigned int); - int (*bpf_map)(struct bpf_map *, fmode_t); - int (*bpf_prog)(struct bpf_prog *); - int (*bpf_map_alloc_security)(struct bpf_map *); - void (*bpf_map_free_security)(struct bpf_map *); - int (*bpf_prog_alloc_security)(struct bpf_prog_aux *); - void (*bpf_prog_free_security)(struct bpf_prog_aux *); - int (*locked_down)(enum lockdown_reason); - int (*perf_event_open)(struct perf_event_attr *, int); - int (*perf_event_alloc)(struct perf_event *); - void (*perf_event_free)(struct perf_event *); - int (*perf_event_read)(struct perf_event *); - int (*perf_event_write)(struct perf_event *); -}; - -struct security_hook_heads { - struct hlist_head binder_set_context_mgr; - struct hlist_head binder_transaction; - struct hlist_head binder_transfer_binder; - struct hlist_head binder_transfer_file; - struct hlist_head ptrace_access_check; - struct hlist_head ptrace_traceme; - struct hlist_head capget; - struct hlist_head capset; - struct hlist_head capable; - struct hlist_head quotactl; - struct hlist_head quota_on; - struct hlist_head syslog; - struct hlist_head settime; - struct hlist_head vm_enough_memory; - struct hlist_head bprm_creds_for_exec; - struct hlist_head bprm_creds_from_file; - struct hlist_head bprm_check_security; - struct hlist_head bprm_committing_creds; - struct hlist_head bprm_committed_creds; - struct hlist_head fs_context_dup; - struct hlist_head fs_context_parse_param; - struct hlist_head sb_alloc_security; - struct hlist_head sb_delete; - struct hlist_head sb_free_security; - struct hlist_head sb_free_mnt_opts; - struct hlist_head sb_eat_lsm_opts; - struct hlist_head sb_mnt_opts_compat; - struct hlist_head sb_remount; - struct hlist_head sb_kern_mount; - struct hlist_head sb_show_options; - struct hlist_head sb_statfs; - struct hlist_head sb_mount; - struct hlist_head sb_umount; - struct hlist_head sb_pivotroot; - struct hlist_head sb_set_mnt_opts; - struct hlist_head sb_clone_mnt_opts; - struct hlist_head sb_add_mnt_opt; - struct hlist_head move_mount; - struct hlist_head dentry_init_security; - struct hlist_head dentry_create_files_as; - struct hlist_head path_unlink; - struct hlist_head path_mkdir; - struct hlist_head path_rmdir; - struct hlist_head path_mknod; - struct hlist_head path_truncate; - struct hlist_head path_symlink; - struct hlist_head path_link; - struct hlist_head path_rename; - struct hlist_head path_chmod; - struct hlist_head path_chown; - struct hlist_head path_chroot; - struct hlist_head path_notify; - struct hlist_head inode_alloc_security; - struct hlist_head inode_free_security; - struct hlist_head inode_init_security; - struct hlist_head inode_init_security_anon; - struct hlist_head inode_create; - struct hlist_head inode_link; - struct hlist_head inode_unlink; - struct hlist_head inode_symlink; - struct hlist_head inode_mkdir; - struct hlist_head inode_rmdir; - struct hlist_head inode_mknod; - struct hlist_head inode_rename; - struct hlist_head inode_readlink; - struct hlist_head inode_follow_link; - struct hlist_head inode_permission; - struct hlist_head inode_setattr; - struct hlist_head inode_getattr; - struct hlist_head inode_setxattr; - struct hlist_head inode_post_setxattr; - struct hlist_head inode_getxattr; - struct hlist_head inode_listxattr; - struct hlist_head inode_removexattr; - struct hlist_head inode_need_killpriv; - struct hlist_head inode_killpriv; - struct hlist_head inode_getsecurity; - struct hlist_head inode_setsecurity; - struct hlist_head inode_listsecurity; - struct hlist_head inode_getsecid; - struct hlist_head inode_copy_up; - struct hlist_head inode_copy_up_xattr; - struct hlist_head kernfs_init_security; - struct hlist_head file_permission; - struct hlist_head file_alloc_security; - struct hlist_head file_free_security; - struct hlist_head file_ioctl; - struct hlist_head mmap_addr; - struct hlist_head mmap_file; - struct hlist_head file_mprotect; - struct hlist_head file_lock; - struct hlist_head file_fcntl; - struct hlist_head file_set_fowner; - struct hlist_head file_send_sigiotask; - struct hlist_head file_receive; - struct hlist_head file_open; - struct hlist_head task_alloc; - struct hlist_head task_free; - struct hlist_head cred_alloc_blank; - struct hlist_head cred_free; - struct hlist_head cred_prepare; - struct hlist_head cred_transfer; - struct hlist_head cred_getsecid; - struct hlist_head kernel_act_as; - struct hlist_head kernel_create_files_as; - struct hlist_head kernel_module_request; - struct hlist_head kernel_load_data; - struct hlist_head kernel_post_load_data; - struct hlist_head kernel_read_file; - struct hlist_head kernel_post_read_file; - struct hlist_head task_fix_setuid; - struct hlist_head task_fix_setgid; - struct hlist_head task_setpgid; - struct hlist_head task_getpgid; - struct hlist_head task_getsid; - struct hlist_head task_getsecid_subj; - struct hlist_head task_getsecid_obj; - struct hlist_head task_setnice; - struct hlist_head task_setioprio; - struct hlist_head task_getioprio; - struct hlist_head task_prlimit; - struct hlist_head task_setrlimit; - struct hlist_head task_setscheduler; - struct hlist_head task_getscheduler; - struct hlist_head task_movememory; - struct hlist_head task_kill; - struct hlist_head task_prctl; - struct hlist_head task_to_inode; - struct hlist_head ipc_permission; - struct hlist_head ipc_getsecid; - struct hlist_head msg_msg_alloc_security; - struct hlist_head msg_msg_free_security; - struct hlist_head msg_queue_alloc_security; - struct hlist_head msg_queue_free_security; - struct hlist_head msg_queue_associate; - struct hlist_head msg_queue_msgctl; - struct hlist_head msg_queue_msgsnd; - struct hlist_head msg_queue_msgrcv; - struct hlist_head shm_alloc_security; - struct hlist_head shm_free_security; - struct hlist_head shm_associate; - struct hlist_head shm_shmctl; - struct hlist_head shm_shmat; - struct hlist_head sem_alloc_security; - struct hlist_head sem_free_security; - struct hlist_head sem_associate; - struct hlist_head sem_semctl; - struct hlist_head sem_semop; - struct hlist_head netlink_send; - struct hlist_head d_instantiate; - struct hlist_head getprocattr; - struct hlist_head setprocattr; - struct hlist_head ismaclabel; - struct hlist_head secid_to_secctx; - struct hlist_head secctx_to_secid; - struct hlist_head release_secctx; - struct hlist_head inode_invalidate_secctx; - struct hlist_head inode_notifysecctx; - struct hlist_head inode_setsecctx; - struct hlist_head inode_getsecctx; - struct hlist_head post_notification; - struct hlist_head watch_key; - struct hlist_head unix_stream_connect; - struct hlist_head unix_may_send; - struct hlist_head socket_create; - struct hlist_head socket_post_create; - struct hlist_head socket_socketpair; - struct hlist_head socket_bind; - struct hlist_head socket_connect; - struct hlist_head socket_listen; - struct hlist_head socket_accept; - struct hlist_head socket_sendmsg; - struct hlist_head socket_recvmsg; - struct hlist_head socket_getsockname; - struct hlist_head socket_getpeername; - struct hlist_head socket_getsockopt; - struct hlist_head socket_setsockopt; - struct hlist_head socket_shutdown; - struct hlist_head socket_sock_rcv_skb; - struct hlist_head socket_getpeersec_stream; - struct hlist_head socket_getpeersec_dgram; - struct hlist_head sk_alloc_security; - struct hlist_head sk_free_security; - struct hlist_head sk_clone_security; - struct hlist_head sk_getsecid; - struct hlist_head sock_graft; - struct hlist_head inet_conn_request; - struct hlist_head inet_csk_clone; - struct hlist_head inet_conn_established; - struct hlist_head secmark_relabel_packet; - struct hlist_head secmark_refcount_inc; - struct hlist_head secmark_refcount_dec; - struct hlist_head req_classify_flow; - struct hlist_head tun_dev_alloc_security; - struct hlist_head tun_dev_free_security; - struct hlist_head tun_dev_create; - struct hlist_head tun_dev_attach_queue; - struct hlist_head tun_dev_attach; - struct hlist_head tun_dev_open; - struct hlist_head sctp_assoc_request; - struct hlist_head sctp_bind_connect; - struct hlist_head sctp_sk_clone; - struct hlist_head ib_pkey_access; - struct hlist_head ib_endport_manage_subnet; - struct hlist_head ib_alloc_security; - struct hlist_head ib_free_security; - struct hlist_head xfrm_policy_alloc_security; - struct hlist_head xfrm_policy_clone_security; - struct hlist_head xfrm_policy_free_security; - struct hlist_head xfrm_policy_delete_security; - struct hlist_head xfrm_state_alloc; - struct hlist_head xfrm_state_alloc_acquire; - struct hlist_head xfrm_state_free_security; - struct hlist_head xfrm_state_delete_security; - struct hlist_head xfrm_policy_lookup; - struct hlist_head xfrm_state_pol_flow_match; - struct hlist_head xfrm_decode_session; - struct hlist_head key_alloc; - struct hlist_head key_free; - struct hlist_head key_permission; - struct hlist_head key_getsecurity; - struct hlist_head audit_rule_init; - struct hlist_head audit_rule_known; - struct hlist_head audit_rule_match; - struct hlist_head audit_rule_free; - struct hlist_head bpf; - struct hlist_head bpf_map; - struct hlist_head bpf_prog; - struct hlist_head bpf_map_alloc_security; - struct hlist_head bpf_map_free_security; - struct hlist_head bpf_prog_alloc_security; - struct hlist_head bpf_prog_free_security; - struct hlist_head locked_down; - struct hlist_head perf_event_open; - struct hlist_head perf_event_alloc; - struct hlist_head perf_event_free; - struct hlist_head perf_event_read; - struct hlist_head perf_event_write; -}; - -struct security_hook_list { - struct hlist_node list; - struct hlist_head *head; - union security_list_options hook; - char *lsm; -}; - -enum lsm_order { - LSM_ORDER_FIRST = 4294967295, - LSM_ORDER_MUTABLE = 0, -}; - -struct lsm_info { - const char *name; - enum lsm_order order; - long unsigned int flags; - int *enabled; - int (*init)(); - struct lsm_blob_sizes *blobs; -}; - -enum lsm_event { - LSM_POLICY_CHANGE = 0, -}; - -struct ethhdr { - unsigned char h_dest[6]; - unsigned char h_source[6]; - __be16 h_proto; -}; - -struct ethtool_drvinfo { - __u32 cmd; - char driver[32]; - char version[32]; - char fw_version[32]; - char bus_info[32]; - char erom_version[32]; - char reserved2[12]; - __u32 n_priv_flags; - __u32 n_stats; - __u32 testinfo_len; - __u32 eedump_len; - __u32 regdump_len; -}; - -struct ethtool_wolinfo { - __u32 cmd; - __u32 supported; - __u32 wolopts; - __u8 sopass[6]; -}; - -struct ethtool_tunable { - __u32 cmd; - __u32 id; - __u32 type_id; - __u32 len; - void *data[0]; -}; - -struct ethtool_regs { - __u32 cmd; - __u32 version; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_eeprom { - __u32 cmd; - __u32 magic; - __u32 offset; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_eee { - __u32 cmd; - __u32 supported; - __u32 advertised; - __u32 lp_advertised; - __u32 eee_active; - __u32 eee_enabled; - __u32 tx_lpi_enabled; - __u32 tx_lpi_timer; - __u32 reserved[2]; -}; - -struct ethtool_modinfo { - __u32 cmd; - __u32 type; - __u32 eeprom_len; - __u32 reserved[8]; -}; - -struct ethtool_coalesce { - __u32 cmd; - __u32 rx_coalesce_usecs; - __u32 rx_max_coalesced_frames; - __u32 rx_coalesce_usecs_irq; - __u32 rx_max_coalesced_frames_irq; - __u32 tx_coalesce_usecs; - __u32 tx_max_coalesced_frames; - __u32 tx_coalesce_usecs_irq; - __u32 tx_max_coalesced_frames_irq; - __u32 stats_block_coalesce_usecs; - __u32 use_adaptive_rx_coalesce; - __u32 use_adaptive_tx_coalesce; - __u32 pkt_rate_low; - __u32 rx_coalesce_usecs_low; - __u32 rx_max_coalesced_frames_low; - __u32 tx_coalesce_usecs_low; - __u32 tx_max_coalesced_frames_low; - __u32 pkt_rate_high; - __u32 rx_coalesce_usecs_high; - __u32 rx_max_coalesced_frames_high; - __u32 tx_coalesce_usecs_high; - __u32 tx_max_coalesced_frames_high; - __u32 rate_sample_interval; -}; - -struct ethtool_ringparam { - __u32 cmd; - __u32 rx_max_pending; - __u32 rx_mini_max_pending; - __u32 rx_jumbo_max_pending; - __u32 tx_max_pending; - __u32 rx_pending; - __u32 rx_mini_pending; - __u32 rx_jumbo_pending; - __u32 tx_pending; -}; - -struct ethtool_channels { - __u32 cmd; - __u32 max_rx; - __u32 max_tx; - __u32 max_other; - __u32 max_combined; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -struct ethtool_pauseparam { - __u32 cmd; - __u32 autoneg; - __u32 rx_pause; - __u32 tx_pause; -}; - -enum ethtool_link_ext_state { - ETHTOOL_LINK_EXT_STATE_AUTONEG = 0, - ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE = 1, - ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH = 2, - ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY = 3, - ETHTOOL_LINK_EXT_STATE_NO_CABLE = 4, - ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE = 5, - ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE = 6, - ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE = 7, - ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED = 8, - ETHTOOL_LINK_EXT_STATE_OVERHEAT = 9, -}; - -enum ethtool_link_ext_substate_autoneg { - ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED = 1, - ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED = 2, - ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED = 3, - ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE = 4, - ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE = 5, - ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD = 6, -}; - -enum ethtool_link_ext_substate_link_training { - ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED = 1, - ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT = 2, - ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY = 3, - ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT = 4, -}; - -enum ethtool_link_ext_substate_link_logical_mismatch { - ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK = 1, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK = 2, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS = 3, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED = 4, - ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED = 5, -}; - -enum ethtool_link_ext_substate_bad_signal_integrity { - ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS = 1, - ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE = 2, -}; - -enum ethtool_link_ext_substate_cable_issue { - ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE = 1, - ETHTOOL_LINK_EXT_SUBSTATE_CI_CABLE_TEST_FAILURE = 2, -}; - -struct ethtool_test { - __u32 cmd; - __u32 flags; - __u32 reserved; - __u32 len; - __u64 data[0]; -}; - -struct ethtool_stats { - __u32 cmd; - __u32 n_stats; - __u64 data[0]; -}; - -struct ethtool_tcpip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be16 psrc; - __be16 pdst; - __u8 tos; -}; - -struct ethtool_ah_espip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be32 spi; - __u8 tos; -}; - -struct ethtool_usrip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be32 l4_4_bytes; - __u8 tos; - __u8 ip_ver; - __u8 proto; -}; - -struct ethtool_tcpip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be16 psrc; - __be16 pdst; - __u8 tclass; -}; - -struct ethtool_ah_espip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be32 spi; - __u8 tclass; -}; - -struct ethtool_usrip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be32 l4_4_bytes; - __u8 tclass; - __u8 l4_proto; -}; - -union ethtool_flow_union { - struct ethtool_tcpip4_spec tcp_ip4_spec; - struct ethtool_tcpip4_spec udp_ip4_spec; - struct ethtool_tcpip4_spec sctp_ip4_spec; - struct ethtool_ah_espip4_spec ah_ip4_spec; - struct ethtool_ah_espip4_spec esp_ip4_spec; - struct ethtool_usrip4_spec usr_ip4_spec; - struct ethtool_tcpip6_spec tcp_ip6_spec; - struct ethtool_tcpip6_spec udp_ip6_spec; - struct ethtool_tcpip6_spec sctp_ip6_spec; - struct ethtool_ah_espip6_spec ah_ip6_spec; - struct ethtool_ah_espip6_spec esp_ip6_spec; - struct ethtool_usrip6_spec usr_ip6_spec; - struct ethhdr ether_spec; - __u8 hdata[52]; -}; - -struct ethtool_flow_ext { - __u8 padding[2]; - unsigned char h_dest[6]; - __be16 vlan_etype; - __be16 vlan_tci; - __be32 data[2]; -}; - -struct ethtool_rx_flow_spec { - __u32 flow_type; - union ethtool_flow_union h_u; - struct ethtool_flow_ext h_ext; - union ethtool_flow_union m_u; - struct ethtool_flow_ext m_ext; - __u64 ring_cookie; - __u32 location; -}; - -struct ethtool_rxnfc { - __u32 cmd; - __u32 flow_type; - __u64 data; - struct ethtool_rx_flow_spec fs; - union { - __u32 rule_cnt; - __u32 rss_context; - }; - __u32 rule_locs[0]; -}; - -struct ethtool_flash { - __u32 cmd; - __u32 region; - char data[128]; -}; - -struct ethtool_dump { - __u32 cmd; - __u32 version; - __u32 flag; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_ts_info { - __u32 cmd; - __u32 so_timestamping; - __s32 phc_index; - __u32 tx_types; - __u32 tx_reserved[3]; - __u32 rx_filters; - __u32 rx_reserved[3]; -}; - -struct ethtool_fecparam { - __u32 cmd; - __u32 active_fec; - __u32 fec; - __u32 reserved; -}; - -enum ethtool_link_mode_bit_indices { - ETHTOOL_LINK_MODE_10baseT_Half_BIT = 0, - ETHTOOL_LINK_MODE_10baseT_Full_BIT = 1, - ETHTOOL_LINK_MODE_100baseT_Half_BIT = 2, - ETHTOOL_LINK_MODE_100baseT_Full_BIT = 3, - ETHTOOL_LINK_MODE_1000baseT_Half_BIT = 4, - ETHTOOL_LINK_MODE_1000baseT_Full_BIT = 5, - ETHTOOL_LINK_MODE_Autoneg_BIT = 6, - ETHTOOL_LINK_MODE_TP_BIT = 7, - ETHTOOL_LINK_MODE_AUI_BIT = 8, - ETHTOOL_LINK_MODE_MII_BIT = 9, - ETHTOOL_LINK_MODE_FIBRE_BIT = 10, - ETHTOOL_LINK_MODE_BNC_BIT = 11, - ETHTOOL_LINK_MODE_10000baseT_Full_BIT = 12, - ETHTOOL_LINK_MODE_Pause_BIT = 13, - ETHTOOL_LINK_MODE_Asym_Pause_BIT = 14, - ETHTOOL_LINK_MODE_2500baseX_Full_BIT = 15, - ETHTOOL_LINK_MODE_Backplane_BIT = 16, - ETHTOOL_LINK_MODE_1000baseKX_Full_BIT = 17, - ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT = 18, - ETHTOOL_LINK_MODE_10000baseKR_Full_BIT = 19, - ETHTOOL_LINK_MODE_10000baseR_FEC_BIT = 20, - ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT = 21, - ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT = 22, - ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT = 23, - ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT = 24, - ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT = 25, - ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT = 26, - ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT = 27, - ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT = 28, - ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT = 29, - ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT = 30, - ETHTOOL_LINK_MODE_25000baseCR_Full_BIT = 31, - ETHTOOL_LINK_MODE_25000baseKR_Full_BIT = 32, - ETHTOOL_LINK_MODE_25000baseSR_Full_BIT = 33, - ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT = 34, - ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT = 35, - ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT = 36, - ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT = 37, - ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT = 38, - ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT = 39, - ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT = 40, - ETHTOOL_LINK_MODE_1000baseX_Full_BIT = 41, - ETHTOOL_LINK_MODE_10000baseCR_Full_BIT = 42, - ETHTOOL_LINK_MODE_10000baseSR_Full_BIT = 43, - ETHTOOL_LINK_MODE_10000baseLR_Full_BIT = 44, - ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT = 45, - ETHTOOL_LINK_MODE_10000baseER_Full_BIT = 46, - ETHTOOL_LINK_MODE_2500baseT_Full_BIT = 47, - ETHTOOL_LINK_MODE_5000baseT_Full_BIT = 48, - ETHTOOL_LINK_MODE_FEC_NONE_BIT = 49, - ETHTOOL_LINK_MODE_FEC_RS_BIT = 50, - ETHTOOL_LINK_MODE_FEC_BASER_BIT = 51, - ETHTOOL_LINK_MODE_50000baseKR_Full_BIT = 52, - ETHTOOL_LINK_MODE_50000baseSR_Full_BIT = 53, - ETHTOOL_LINK_MODE_50000baseCR_Full_BIT = 54, - ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT = 55, - ETHTOOL_LINK_MODE_50000baseDR_Full_BIT = 56, - ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT = 57, - ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT = 58, - ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT = 59, - ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT = 60, - ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT = 61, - ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT = 62, - ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT = 63, - ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64, - ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT = 65, - ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT = 66, - ETHTOOL_LINK_MODE_100baseT1_Full_BIT = 67, - ETHTOOL_LINK_MODE_1000baseT1_Full_BIT = 68, - ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT = 69, - ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT = 70, - ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71, - ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72, - ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73, - ETHTOOL_LINK_MODE_FEC_LLRS_BIT = 74, - ETHTOOL_LINK_MODE_100000baseKR_Full_BIT = 75, - ETHTOOL_LINK_MODE_100000baseSR_Full_BIT = 76, - ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT = 77, - ETHTOOL_LINK_MODE_100000baseCR_Full_BIT = 78, - ETHTOOL_LINK_MODE_100000baseDR_Full_BIT = 79, - ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT = 80, - ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT = 81, - ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT = 82, - ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT = 83, - ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT = 84, - ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT = 85, - ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT = 86, - ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87, - ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT = 88, - ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89, - ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90, - ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91, - __ETHTOOL_LINK_MODE_MASK_NBITS = 92, -}; - -struct ethtool_link_settings { - __u32 cmd; - __u32 speed; - __u8 duplex; - __u8 port; - __u8 phy_address; - __u8 autoneg; - __u8 mdio_support; - __u8 eth_tp_mdix; - __u8 eth_tp_mdix_ctrl; - __s8 link_mode_masks_nwords; - __u8 transceiver; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u8 reserved1[1]; - __u32 reserved[7]; - __u32 link_mode_masks[0]; -}; - -struct ethtool_link_ext_state_info { - enum ethtool_link_ext_state link_ext_state; - union { - enum ethtool_link_ext_substate_autoneg autoneg; - enum ethtool_link_ext_substate_link_training link_training; - enum ethtool_link_ext_substate_link_logical_mismatch link_logical_mismatch; - enum ethtool_link_ext_substate_bad_signal_integrity bad_signal_integrity; - enum ethtool_link_ext_substate_cable_issue cable_issue; - u8 __link_ext_substate; - }; -}; - -struct ethtool_link_ksettings { - struct ethtool_link_settings base; - struct { - long unsigned int supported[2]; - long unsigned int advertising[2]; - long unsigned int lp_advertising[2]; - } link_modes; - u32 lanes; -}; - -struct ethtool_eth_mac_stats { - u64 FramesTransmittedOK; - u64 SingleCollisionFrames; - u64 MultipleCollisionFrames; - u64 FramesReceivedOK; - u64 FrameCheckSequenceErrors; - u64 AlignmentErrors; - u64 OctetsTransmittedOK; - u64 FramesWithDeferredXmissions; - u64 LateCollisions; - u64 FramesAbortedDueToXSColls; - u64 FramesLostDueToIntMACXmitError; - u64 CarrierSenseErrors; - u64 OctetsReceivedOK; - u64 FramesLostDueToIntMACRcvError; - u64 MulticastFramesXmittedOK; - u64 BroadcastFramesXmittedOK; - u64 FramesWithExcessiveDeferral; - u64 MulticastFramesReceivedOK; - u64 BroadcastFramesReceivedOK; - u64 InRangeLengthErrors; - u64 OutOfRangeLengthField; - u64 FrameTooLongErrors; -}; - -struct ethtool_eth_phy_stats { - u64 SymbolErrorDuringCarrier; -}; - -struct ethtool_eth_ctrl_stats { - u64 MACControlFramesTransmitted; - u64 MACControlFramesReceived; - u64 UnsupportedOpcodesReceived; -}; - -struct ethtool_pause_stats { - u64 tx_pause_frames; - u64 rx_pause_frames; -}; - -struct ethtool_fec_stat { - u64 total; - u64 lanes[8]; -}; - -struct ethtool_fec_stats { - struct ethtool_fec_stat corrected_blocks; - struct ethtool_fec_stat uncorrectable_blocks; - struct ethtool_fec_stat corrected_bits; -}; - -struct ethtool_rmon_hist_range { - u16 low; - u16 high; -}; - -struct ethtool_rmon_stats { - u64 undersize_pkts; - u64 oversize_pkts; - u64 fragments; - u64 jabbers; - u64 hist[10]; - u64 hist_tx[10]; -}; - -struct ethtool_module_eeprom { - u32 offset; - u32 length; - u8 page; - u8 bank; - u8 i2c_address; - u8 *data; -}; - -enum ib_uverbs_write_cmds { - IB_USER_VERBS_CMD_GET_CONTEXT = 0, - IB_USER_VERBS_CMD_QUERY_DEVICE = 1, - IB_USER_VERBS_CMD_QUERY_PORT = 2, - IB_USER_VERBS_CMD_ALLOC_PD = 3, - IB_USER_VERBS_CMD_DEALLOC_PD = 4, - IB_USER_VERBS_CMD_CREATE_AH = 5, - IB_USER_VERBS_CMD_MODIFY_AH = 6, - IB_USER_VERBS_CMD_QUERY_AH = 7, - IB_USER_VERBS_CMD_DESTROY_AH = 8, - IB_USER_VERBS_CMD_REG_MR = 9, - IB_USER_VERBS_CMD_REG_SMR = 10, - IB_USER_VERBS_CMD_REREG_MR = 11, - IB_USER_VERBS_CMD_QUERY_MR = 12, - IB_USER_VERBS_CMD_DEREG_MR = 13, - IB_USER_VERBS_CMD_ALLOC_MW = 14, - IB_USER_VERBS_CMD_BIND_MW = 15, - IB_USER_VERBS_CMD_DEALLOC_MW = 16, - IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL = 17, - IB_USER_VERBS_CMD_CREATE_CQ = 18, - IB_USER_VERBS_CMD_RESIZE_CQ = 19, - IB_USER_VERBS_CMD_DESTROY_CQ = 20, - IB_USER_VERBS_CMD_POLL_CQ = 21, - IB_USER_VERBS_CMD_PEEK_CQ = 22, - IB_USER_VERBS_CMD_REQ_NOTIFY_CQ = 23, - IB_USER_VERBS_CMD_CREATE_QP = 24, - IB_USER_VERBS_CMD_QUERY_QP = 25, - IB_USER_VERBS_CMD_MODIFY_QP = 26, - IB_USER_VERBS_CMD_DESTROY_QP = 27, - IB_USER_VERBS_CMD_POST_SEND = 28, - IB_USER_VERBS_CMD_POST_RECV = 29, - IB_USER_VERBS_CMD_ATTACH_MCAST = 30, - IB_USER_VERBS_CMD_DETACH_MCAST = 31, - IB_USER_VERBS_CMD_CREATE_SRQ = 32, - IB_USER_VERBS_CMD_MODIFY_SRQ = 33, - IB_USER_VERBS_CMD_QUERY_SRQ = 34, - IB_USER_VERBS_CMD_DESTROY_SRQ = 35, - IB_USER_VERBS_CMD_POST_SRQ_RECV = 36, - IB_USER_VERBS_CMD_OPEN_XRCD = 37, - IB_USER_VERBS_CMD_CLOSE_XRCD = 38, - IB_USER_VERBS_CMD_CREATE_XSRQ = 39, - IB_USER_VERBS_CMD_OPEN_QP = 40, -}; - -enum ib_uverbs_wc_opcode { - IB_UVERBS_WC_SEND = 0, - IB_UVERBS_WC_RDMA_WRITE = 1, - IB_UVERBS_WC_RDMA_READ = 2, - IB_UVERBS_WC_COMP_SWAP = 3, - IB_UVERBS_WC_FETCH_ADD = 4, - IB_UVERBS_WC_BIND_MW = 5, - IB_UVERBS_WC_LOCAL_INV = 6, - IB_UVERBS_WC_TSO = 7, -}; - -enum ib_uverbs_create_qp_mask { - IB_UVERBS_CREATE_QP_MASK_IND_TABLE = 1, -}; - -enum ib_uverbs_wr_opcode { - IB_UVERBS_WR_RDMA_WRITE = 0, - IB_UVERBS_WR_RDMA_WRITE_WITH_IMM = 1, - IB_UVERBS_WR_SEND = 2, - IB_UVERBS_WR_SEND_WITH_IMM = 3, - IB_UVERBS_WR_RDMA_READ = 4, - IB_UVERBS_WR_ATOMIC_CMP_AND_SWP = 5, - IB_UVERBS_WR_ATOMIC_FETCH_AND_ADD = 6, - IB_UVERBS_WR_LOCAL_INV = 7, - IB_UVERBS_WR_BIND_MW = 8, - IB_UVERBS_WR_SEND_WITH_INV = 9, - IB_UVERBS_WR_TSO = 10, - IB_UVERBS_WR_RDMA_READ_WITH_INV = 11, - IB_UVERBS_WR_MASKED_ATOMIC_CMP_AND_SWP = 12, - IB_UVERBS_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13, -}; - -enum ib_uverbs_access_flags { - IB_UVERBS_ACCESS_LOCAL_WRITE = 1, - IB_UVERBS_ACCESS_REMOTE_WRITE = 2, - IB_UVERBS_ACCESS_REMOTE_READ = 4, - IB_UVERBS_ACCESS_REMOTE_ATOMIC = 8, - IB_UVERBS_ACCESS_MW_BIND = 16, - IB_UVERBS_ACCESS_ZERO_BASED = 32, - IB_UVERBS_ACCESS_ON_DEMAND = 64, - IB_UVERBS_ACCESS_HUGETLB = 128, - IB_UVERBS_ACCESS_RELAXED_ORDERING = 1048576, - IB_UVERBS_ACCESS_OPTIONAL_RANGE = 1072693248, -}; - -enum ib_uverbs_srq_type { - IB_UVERBS_SRQT_BASIC = 0, - IB_UVERBS_SRQT_XRC = 1, - IB_UVERBS_SRQT_TM = 2, -}; - -enum ib_uverbs_wq_type { - IB_UVERBS_WQT_RQ = 0, -}; - -enum ib_uverbs_wq_flags { - IB_UVERBS_WQ_FLAGS_CVLAN_STRIPPING = 1, - IB_UVERBS_WQ_FLAGS_SCATTER_FCS = 2, - IB_UVERBS_WQ_FLAGS_DELAY_DROP = 4, - IB_UVERBS_WQ_FLAGS_PCI_WRITE_END_PADDING = 8, -}; - -enum ib_uverbs_qp_type { - IB_UVERBS_QPT_RC = 2, - IB_UVERBS_QPT_UC = 3, - IB_UVERBS_QPT_UD = 4, - IB_UVERBS_QPT_RAW_PACKET = 8, - IB_UVERBS_QPT_XRC_INI = 9, - IB_UVERBS_QPT_XRC_TGT = 10, - IB_UVERBS_QPT_DRIVER = 255, -}; - -enum ib_uverbs_qp_create_flags { - IB_UVERBS_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 2, - IB_UVERBS_QP_CREATE_SCATTER_FCS = 256, - IB_UVERBS_QP_CREATE_CVLAN_STRIPPING = 512, - IB_UVERBS_QP_CREATE_PCI_WRITE_END_PADDING = 2048, - IB_UVERBS_QP_CREATE_SQ_SIG_ALL = 4096, -}; - -enum ib_uverbs_gid_type { - IB_UVERBS_GID_TYPE_IB = 0, - IB_UVERBS_GID_TYPE_ROCE_V1 = 1, - IB_UVERBS_GID_TYPE_ROCE_V2 = 2, -}; - -enum ib_poll_context { - IB_POLL_SOFTIRQ = 0, - IB_POLL_WORKQUEUE = 1, - IB_POLL_UNBOUND_WORKQUEUE = 2, - IB_POLL_LAST_POOL_TYPE = 2, - IB_POLL_DIRECT = 3, -}; - -struct lsm_network_audit { - int netif; - const struct sock *sk; - u16 family; - __be16 dport; - __be16 sport; - union { - struct { - __be32 daddr; - __be32 saddr; - } v4; - struct { - struct in6_addr daddr; - struct in6_addr saddr; - } v6; - } fam; -}; - -struct lsm_ioctlop_audit { - struct path path; - u16 cmd; -}; - -struct lsm_ibpkey_audit { - u64 subnet_prefix; - u16 pkey; -}; - -struct lsm_ibendport_audit { - const char *dev_name; - u8 port; -}; - -struct selinux_state; - -struct selinux_audit_data { - u32 ssid; - u32 tsid; - u16 tclass; - u32 requested; - u32 audited; - u32 denied; - int result; - struct selinux_state *state; -}; - -struct smack_audit_data; - -struct apparmor_audit_data; - -struct common_audit_data { - char type; - union { - struct path path; - struct dentry *dentry; - struct inode *inode; - struct lsm_network_audit *net; - int cap; - int ipc_id; - struct task_struct *tsk; - struct { - key_serial_t key; - char *key_desc; - } key_struct; - char *kmod_name; - struct lsm_ioctlop_audit *op; - struct file *file; - struct lsm_ibpkey_audit *ibpkey; - struct lsm_ibendport_audit *ibendport; - int reason; - } u; - union { - struct smack_audit_data *smack_audit_data; - struct selinux_audit_data *selinux_audit_data; - struct apparmor_audit_data *apparmor_audit_data; - }; -}; - -enum { - POLICYDB_CAPABILITY_NETPEER = 0, - POLICYDB_CAPABILITY_OPENPERM = 1, - POLICYDB_CAPABILITY_EXTSOCKCLASS = 2, - POLICYDB_CAPABILITY_ALWAYSNETWORK = 3, - POLICYDB_CAPABILITY_CGROUPSECLABEL = 4, - POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION = 5, - POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS = 6, - __POLICYDB_CAPABILITY_MAX = 7, -}; - -struct selinux_avc; - -struct selinux_policy; - -struct selinux_state { - bool enforcing; - bool checkreqprot; - bool initialized; - bool policycap[7]; - struct page *status_page; - struct mutex status_lock; - struct selinux_avc *avc; - struct selinux_policy *policy; - struct mutex policy_mutex; -}; - -struct avc_cache { - struct hlist_head slots[512]; - spinlock_t slots_lock[512]; - atomic_t lru_hint; - atomic_t active_nodes; - u32 latest_notif; -}; - -struct selinux_avc { - unsigned int avc_cache_threshold; - struct avc_cache avc_cache; -}; - -struct av_decision { - u32 allowed; - u32 auditallow; - u32 auditdeny; - u32 seqno; - u32 flags; -}; - -struct extended_perms_data { - u32 p[8]; -}; - -struct extended_perms_decision { - u8 used; - u8 driver; - struct extended_perms_data *allowed; - struct extended_perms_data *auditallow; - struct extended_perms_data *dontaudit; -}; - -struct extended_perms { - u16 len; - struct extended_perms_data drivers; -}; - -struct avc_cache_stats { - unsigned int lookups; - unsigned int misses; - unsigned int allocations; - unsigned int reclaims; - unsigned int frees; -}; - -struct security_class_mapping { - const char *name; - const char *perms[33]; -}; - -struct trace_event_raw_selinux_audited { - struct trace_entry ent; - u32 requested; - u32 denied; - u32 audited; - int result; - u32 __data_loc_scontext; - u32 __data_loc_tcontext; - u32 __data_loc_tclass; - char __data[0]; -}; - -struct trace_event_data_offsets_selinux_audited { - u32 scontext; - u32 tcontext; - u32 tclass; -}; - -typedef void (*btf_trace_selinux_audited)(void *, struct selinux_audit_data *, char *, char *, const char *); - -struct avc_xperms_node; - -struct avc_entry { - u32 ssid; - u32 tsid; - u16 tclass; - struct av_decision avd; - struct avc_xperms_node *xp_node; -}; - -struct avc_xperms_node { - struct extended_perms xp; - struct list_head xpd_head; -}; - -struct avc_node { - struct avc_entry ae; - struct hlist_node list; - struct callback_head rhead; -}; - -struct avc_xperms_decision_node { - struct extended_perms_decision xpd; - struct list_head xpd_list; -}; - -struct avc_callback_node { - int (*callback)(u32); - u32 events; - struct avc_callback_node *next; -}; - -typedef __u16 __sum16; - -enum sctp_endpoint_type { - SCTP_EP_TYPE_SOCKET = 0, - SCTP_EP_TYPE_ASSOCIATION = 1, -}; - -struct sctp_chunk; - -struct sctp_inq { - struct list_head in_chunk_list; - struct sctp_chunk *in_progress; - struct work_struct immediate; -}; - -struct sctp_bind_addr { - __u16 port; - struct list_head address_list; -}; - -struct sctp_ep_common { - struct hlist_node node; - int hashent; - enum sctp_endpoint_type type; - refcount_t refcnt; - bool dead; - struct sock *sk; - struct net *net; - struct sctp_inq inqueue; - struct sctp_bind_addr bind_addr; -}; - -struct crypto_shash___2; - -struct sctp_hmac_algo_param; - -struct sctp_chunks_param; - -struct sctp_endpoint { - struct sctp_ep_common base; - struct list_head asocs; - __u8 secret_key[32]; - __u8 *digest; - __u32 sndbuf_policy; - __u32 rcvbuf_policy; - struct crypto_shash___2 **auth_hmacs; - struct sctp_hmac_algo_param *auth_hmacs_list; - struct sctp_chunks_param *auth_chunk_list; - struct list_head endpoint_shared_keys; - __u16 active_key_id; - __u8 ecn_enable: 1; - __u8 auth_enable: 1; - __u8 intl_enable: 1; - __u8 prsctp_enable: 1; - __u8 asconf_enable: 1; - __u8 reconf_enable: 1; - __u8 strreset_enable; - u32 secid; - u32 peer_secid; -}; - -struct sockaddr_in6 { - short unsigned int sin6_family; - __be16 sin6_port; - __be32 sin6_flowinfo; - struct in6_addr sin6_addr; - __u32 sin6_scope_id; -}; - -struct in_addr { - __be32 s_addr; -}; - -struct sockaddr_in { - __kernel_sa_family_t sin_family; - __be16 sin_port; - struct in_addr sin_addr; - unsigned char __pad[8]; -}; - -struct nf_hook_state; - -typedef unsigned int nf_hookfn(void *, struct sk_buff *, const struct nf_hook_state *); - -struct nf_hook_entry { - nf_hookfn *hook; - void *priv; -}; - -struct nf_hook_entries { - u16 num_hook_entries; - struct nf_hook_entry hooks[0]; -}; - -struct nf_hook_state { - u8 hook; - u8 pf; - struct net_device *in; - struct net_device *out; - struct sock *sk; - struct net *net; - int (*okfn)(struct net *, struct sock *, struct sk_buff *); -}; - -enum nf_hook_ops_type { - NF_HOOK_OP_UNDEFINED = 0, - NF_HOOK_OP_NF_TABLES = 1, -}; - -struct nf_hook_ops { - nf_hookfn *hook; - struct net_device *dev; - void *priv; - u8 pf; - enum nf_hook_ops_type hook_ops_type: 8; - unsigned int hooknum; - int priority; -}; - -enum nf_ip_hook_priorities { - NF_IP_PRI_FIRST = 2147483648, - NF_IP_PRI_RAW_BEFORE_DEFRAG = 4294966846, - NF_IP_PRI_CONNTRACK_DEFRAG = 4294966896, - NF_IP_PRI_RAW = 4294966996, - NF_IP_PRI_SELINUX_FIRST = 4294967071, - NF_IP_PRI_CONNTRACK = 4294967096, - NF_IP_PRI_MANGLE = 4294967146, - NF_IP_PRI_NAT_DST = 4294967196, - NF_IP_PRI_FILTER = 0, - NF_IP_PRI_SECURITY = 50, - NF_IP_PRI_NAT_SRC = 100, - NF_IP_PRI_SELINUX_LAST = 225, - NF_IP_PRI_CONNTRACK_HELPER = 300, - NF_IP_PRI_CONNTRACK_CONFIRM = 2147483647, - NF_IP_PRI_LAST = 2147483647, -}; - -enum nf_ip6_hook_priorities { - NF_IP6_PRI_FIRST = 2147483648, - NF_IP6_PRI_RAW_BEFORE_DEFRAG = 4294966846, - NF_IP6_PRI_CONNTRACK_DEFRAG = 4294966896, - NF_IP6_PRI_RAW = 4294966996, - NF_IP6_PRI_SELINUX_FIRST = 4294967071, - NF_IP6_PRI_CONNTRACK = 4294967096, - NF_IP6_PRI_MANGLE = 4294967146, - NF_IP6_PRI_NAT_DST = 4294967196, - NF_IP6_PRI_FILTER = 0, - NF_IP6_PRI_SECURITY = 50, - NF_IP6_PRI_NAT_SRC = 100, - NF_IP6_PRI_SELINUX_LAST = 225, - NF_IP6_PRI_CONNTRACK_HELPER = 300, - NF_IP6_PRI_LAST = 2147483647, -}; - -struct socket_alloc { - struct socket socket; - struct inode vfs_inode; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct ip_options { - __be32 faddr; - __be32 nexthop; - unsigned char optlen; - unsigned char srr; - unsigned char rr; - unsigned char ts; - unsigned char is_strictroute: 1; - unsigned char srr_is_hit: 1; - unsigned char is_changed: 1; - unsigned char rr_needaddr: 1; - unsigned char ts_needtime: 1; - unsigned char ts_needaddr: 1; - unsigned char router_alert; - unsigned char cipso; - unsigned char __pad2; - unsigned char __data[0]; -}; - -struct ip_options_rcu { - struct callback_head rcu; - struct ip_options opt; -}; - -struct ipv6_opt_hdr; - -struct ipv6_rt_hdr; - -struct ipv6_txoptions { - refcount_t refcnt; - int tot_len; - __u16 opt_flen; - __u16 opt_nflen; - struct ipv6_opt_hdr *hopopt; - struct ipv6_opt_hdr *dst0opt; - struct ipv6_rt_hdr *srcrt; - struct ipv6_opt_hdr *dst1opt; - struct callback_head rcu; -}; - -struct inet_cork { - unsigned int flags; - __be32 addr; - struct ip_options *opt; - unsigned int fragsize; - int length; - struct dst_entry *dst; - u8 tx_flags; - __u8 ttl; - __s16 tos; - char priority; - __u16 gso_size; - u64 transmit_time; - u32 mark; -}; - -struct inet_cork_full { - struct inet_cork base; - struct flowi fl; -}; - -struct ipv6_pinfo; - -struct ip_mc_socklist; - -struct inet_sock { - struct sock sk; - struct ipv6_pinfo *pinet6; - __be32 inet_saddr; - __s16 uc_ttl; - __u16 cmsg_flags; - __be16 inet_sport; - __u16 inet_id; - struct ip_options_rcu *inet_opt; - int rx_dst_ifindex; - __u8 tos; - __u8 min_ttl; - __u8 mc_ttl; - __u8 pmtudisc; - __u8 recverr: 1; - __u8 is_icsk: 1; - __u8 freebind: 1; - __u8 hdrincl: 1; - __u8 mc_loop: 1; - __u8 transparent: 1; - __u8 mc_all: 1; - __u8 nodefrag: 1; - __u8 bind_address_no_port: 1; - __u8 recverr_rfc4884: 1; - __u8 defer_connect: 1; - __u8 rcv_tos; - __u8 convert_csum; - int uc_index; - int mc_index; - __be32 mc_addr; - struct ip_mc_socklist *mc_list; - struct inet_cork_full cork; -}; - -struct in6_pktinfo { - struct in6_addr ipi6_addr; - int ipi6_ifindex; -}; - -struct inet6_cork { - struct ipv6_txoptions *opt; - u8 hop_limit; - u8 tclass; -}; - -struct ipv6_mc_socklist; - -struct ipv6_ac_socklist; - -struct ipv6_fl_socklist; - -struct ipv6_pinfo { - struct in6_addr saddr; - struct in6_pktinfo sticky_pktinfo; - const struct in6_addr *daddr_cache; - const struct in6_addr *saddr_cache; - __be32 flow_label; - __u32 frag_size; - __u16 __unused_1: 7; - __s16 hop_limit: 9; - __u16 mc_loop: 1; - __u16 __unused_2: 6; - __s16 mcast_hops: 9; - int ucast_oif; - int mcast_oif; - union { - struct { - __u16 srcrt: 1; - __u16 osrcrt: 1; - __u16 rxinfo: 1; - __u16 rxoinfo: 1; - __u16 rxhlim: 1; - __u16 rxohlim: 1; - __u16 hopopts: 1; - __u16 ohopopts: 1; - __u16 dstopts: 1; - __u16 odstopts: 1; - __u16 rxflow: 1; - __u16 rxtclass: 1; - __u16 rxpmtu: 1; - __u16 rxorigdstaddr: 1; - __u16 recvfragsize: 1; - } bits; - __u16 all; - } rxopt; - __u16 recverr: 1; - __u16 sndflow: 1; - __u16 repflow: 1; - __u16 pmtudisc: 3; - __u16 padding: 1; - __u16 srcprefs: 3; - __u16 dontfrag: 1; - __u16 autoflowlabel: 1; - __u16 autoflowlabel_set: 1; - __u16 mc_all: 1; - __u16 recverr_rfc4884: 1; - __u16 rtalert_isolate: 1; - __u8 min_hopcount; - __u8 tclass; - __be32 rcv_flowinfo; - __u32 dst_cookie; - __u32 rx_dst_cookie; - struct ipv6_mc_socklist *ipv6_mc_list; - struct ipv6_ac_socklist *ipv6_ac_list; - struct ipv6_fl_socklist *ipv6_fl_list; - struct ipv6_txoptions *opt; - struct sk_buff *pktoptions; - struct sk_buff *rxpmtu; - struct inet6_cork cork; -}; - -struct tcphdr { - __be16 source; - __be16 dest; - __be32 seq; - __be32 ack_seq; - __u16 res1: 4; - __u16 doff: 4; - __u16 fin: 1; - __u16 syn: 1; - __u16 rst: 1; - __u16 psh: 1; - __u16 ack: 1; - __u16 urg: 1; - __u16 ece: 1; - __u16 cwr: 1; - __be16 window; - __sum16 check; - __be16 urg_ptr; -}; - -struct iphdr { - __u8 ihl: 4; - __u8 version: 4; - __u8 tos; - __be16 tot_len; - __be16 id; - __be16 frag_off; - __u8 ttl; - __u8 protocol; - __sum16 check; - __be32 saddr; - __be32 daddr; -}; - -struct ipv6_rt_hdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 type; - __u8 segments_left; -}; - -struct ipv6_opt_hdr { - __u8 nexthdr; - __u8 hdrlen; -}; - -struct ipv6hdr { - __u8 priority: 4; - __u8 version: 4; - __u8 flow_lbl[3]; - __be16 payload_len; - __u8 nexthdr; - __u8 hop_limit; - struct in6_addr saddr; - struct in6_addr daddr; -}; - -struct udphdr { - __be16 source; - __be16 dest; - __be16 len; - __sum16 check; -}; - -struct inet6_skb_parm { - int iif; - __be16 ra; - __u16 dst0; - __u16 srcrt; - __u16 dst1; - __u16 lastopt; - __u16 nhoff; - __u16 flags; - __u16 dsthao; - __u16 frag_max_size; -}; - -struct ip6_sf_socklist; - -struct ipv6_mc_socklist { - struct in6_addr addr; - int ifindex; - unsigned int sfmode; - struct ipv6_mc_socklist *next; - struct ip6_sf_socklist *sflist; - struct callback_head rcu; -}; - -struct ipv6_ac_socklist { - struct in6_addr acl_addr; - int acl_ifindex; - struct ipv6_ac_socklist *acl_next; -}; - -struct ip6_flowlabel; - -struct ipv6_fl_socklist { - struct ipv6_fl_socklist *next; - struct ip6_flowlabel *fl; - struct callback_head rcu; -}; - -struct ip6_sf_socklist { - unsigned int sl_max; - unsigned int sl_count; - struct callback_head rcu; - struct in6_addr sl_addr[0]; -}; - -struct ip6_flowlabel { - struct ip6_flowlabel *next; - __be32 label; - atomic_t users; - struct in6_addr dst; - struct ipv6_txoptions *opt; - long unsigned int linger; - struct callback_head rcu; - u8 share; - union { - struct pid *pid; - kuid_t uid; - } owner; - long unsigned int lastuse; - long unsigned int expires; - struct net *fl_net; -}; - -struct inet_skb_parm { - int iif; - struct ip_options opt; - u16 flags; - u16 frag_max_size; -}; - -struct tty_file_private { - struct tty_struct *tty; - struct file *file; - struct list_head list; -}; - -struct netlbl_lsm_cache { - refcount_t refcount; - void (*free)(const void *); - void *data; -}; - -struct netlbl_lsm_catmap { - u32 startbit; - u64 bitmap[4]; - struct netlbl_lsm_catmap *next; -}; - -struct netlbl_lsm_secattr { - u32 flags; - u32 type; - char *domain; - struct netlbl_lsm_cache *cache; - struct { - struct { - struct netlbl_lsm_catmap *cat; - u32 lvl; - } mls; - u32 secid; - } attr; -}; - -struct dccp_hdr { - __be16 dccph_sport; - __be16 dccph_dport; - __u8 dccph_doff; - __u8 dccph_cscov: 4; - __u8 dccph_ccval: 4; - __sum16 dccph_checksum; - __u8 dccph_x: 1; - __u8 dccph_type: 4; - __u8 dccph_reserved: 3; - __u8 dccph_seq2; - __be16 dccph_seq; -}; - -enum dccp_state { - DCCP_OPEN = 1, - DCCP_REQUESTING = 2, - DCCP_LISTEN = 10, - DCCP_RESPOND = 3, - DCCP_ACTIVE_CLOSEREQ = 4, - DCCP_PASSIVE_CLOSE = 8, - DCCP_CLOSING = 11, - DCCP_TIME_WAIT = 6, - DCCP_CLOSED = 7, - DCCP_NEW_SYN_RECV = 12, - DCCP_PARTOPEN = 13, - DCCP_PASSIVE_CLOSEREQ = 14, - DCCP_MAX_STATES = 15, -}; - -typedef __s32 sctp_assoc_t; - -enum sctp_msg_flags { - MSG_NOTIFICATION = 32768, -}; - -struct sctp_initmsg { - __u16 sinit_num_ostreams; - __u16 sinit_max_instreams; - __u16 sinit_max_attempts; - __u16 sinit_max_init_timeo; -}; - -struct sctp_sndrcvinfo { - __u16 sinfo_stream; - __u16 sinfo_ssn; - __u16 sinfo_flags; - __u32 sinfo_ppid; - __u32 sinfo_context; - __u32 sinfo_timetolive; - __u32 sinfo_tsn; - __u32 sinfo_cumtsn; - sctp_assoc_t sinfo_assoc_id; -}; - -struct sctp_rtoinfo { - sctp_assoc_t srto_assoc_id; - __u32 srto_initial; - __u32 srto_max; - __u32 srto_min; -}; - -struct sctp_assocparams { - sctp_assoc_t sasoc_assoc_id; - __u16 sasoc_asocmaxrxt; - __u16 sasoc_number_peer_destinations; - __u32 sasoc_peer_rwnd; - __u32 sasoc_local_rwnd; - __u32 sasoc_cookie_life; -}; - -struct sctp_paddrparams { - sctp_assoc_t spp_assoc_id; - struct __kernel_sockaddr_storage spp_address; - __u32 spp_hbinterval; - __u16 spp_pathmaxrxt; - __u32 spp_pathmtu; - __u32 spp_sackdelay; - __u32 spp_flags; - __u32 spp_ipv6_flowlabel; - __u8 spp_dscp; - char: 8; -} __attribute__((packed)); - -struct sctphdr { - __be16 source; - __be16 dest; - __be32 vtag; - __le32 checksum; -}; - -struct sctp_chunkhdr { - __u8 type; - __u8 flags; - __be16 length; -}; - -enum sctp_cid { - SCTP_CID_DATA = 0, - SCTP_CID_INIT = 1, - SCTP_CID_INIT_ACK = 2, - SCTP_CID_SACK = 3, - SCTP_CID_HEARTBEAT = 4, - SCTP_CID_HEARTBEAT_ACK = 5, - SCTP_CID_ABORT = 6, - SCTP_CID_SHUTDOWN = 7, - SCTP_CID_SHUTDOWN_ACK = 8, - SCTP_CID_ERROR = 9, - SCTP_CID_COOKIE_ECHO = 10, - SCTP_CID_COOKIE_ACK = 11, - SCTP_CID_ECN_ECNE = 12, - SCTP_CID_ECN_CWR = 13, - SCTP_CID_SHUTDOWN_COMPLETE = 14, - SCTP_CID_AUTH = 15, - SCTP_CID_I_DATA = 64, - SCTP_CID_FWD_TSN = 192, - SCTP_CID_ASCONF = 193, - SCTP_CID_I_FWD_TSN = 194, - SCTP_CID_ASCONF_ACK = 128, - SCTP_CID_RECONF = 130, - SCTP_CID_PAD = 132, -}; - -struct sctp_paramhdr { - __be16 type; - __be16 length; -}; - -enum sctp_param { - SCTP_PARAM_HEARTBEAT_INFO = 256, - SCTP_PARAM_IPV4_ADDRESS = 1280, - SCTP_PARAM_IPV6_ADDRESS = 1536, - SCTP_PARAM_STATE_COOKIE = 1792, - SCTP_PARAM_UNRECOGNIZED_PARAMETERS = 2048, - SCTP_PARAM_COOKIE_PRESERVATIVE = 2304, - SCTP_PARAM_HOST_NAME_ADDRESS = 2816, - SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = 3072, - SCTP_PARAM_ECN_CAPABLE = 128, - SCTP_PARAM_RANDOM = 640, - SCTP_PARAM_CHUNKS = 896, - SCTP_PARAM_HMAC_ALGO = 1152, - SCTP_PARAM_SUPPORTED_EXT = 2176, - SCTP_PARAM_FWD_TSN_SUPPORT = 192, - SCTP_PARAM_ADD_IP = 448, - SCTP_PARAM_DEL_IP = 704, - SCTP_PARAM_ERR_CAUSE = 960, - SCTP_PARAM_SET_PRIMARY = 1216, - SCTP_PARAM_SUCCESS_REPORT = 1472, - SCTP_PARAM_ADAPTATION_LAYER_IND = 1728, - SCTP_PARAM_RESET_OUT_REQUEST = 3328, - SCTP_PARAM_RESET_IN_REQUEST = 3584, - SCTP_PARAM_RESET_TSN_REQUEST = 3840, - SCTP_PARAM_RESET_RESPONSE = 4096, - SCTP_PARAM_RESET_ADD_OUT_STREAMS = 4352, - SCTP_PARAM_RESET_ADD_IN_STREAMS = 4608, -}; - -struct sctp_datahdr { - __be32 tsn; - __be16 stream; - __be16 ssn; - __u32 ppid; - __u8 payload[0]; -}; - -struct sctp_idatahdr { - __be32 tsn; - __be16 stream; - __be16 reserved; - __be32 mid; - union { - __u32 ppid; - __be32 fsn; - }; - __u8 payload[0]; -}; - -struct sctp_inithdr { - __be32 init_tag; - __be32 a_rwnd; - __be16 num_outbound_streams; - __be16 num_inbound_streams; - __be32 initial_tsn; - __u8 params[0]; -}; - -struct sctp_init_chunk { - struct sctp_chunkhdr chunk_hdr; - struct sctp_inithdr init_hdr; -}; - -struct sctp_ipv4addr_param { - struct sctp_paramhdr param_hdr; - struct in_addr addr; -}; - -struct sctp_ipv6addr_param { - struct sctp_paramhdr param_hdr; - struct in6_addr addr; -}; - -struct sctp_cookie_preserve_param { - struct sctp_paramhdr param_hdr; - __be32 lifespan_increment; -}; - -struct sctp_hostname_param { - struct sctp_paramhdr param_hdr; - uint8_t hostname[0]; -}; - -struct sctp_supported_addrs_param { - struct sctp_paramhdr param_hdr; - __be16 types[0]; -}; - -struct sctp_adaptation_ind_param { - struct sctp_paramhdr param_hdr; - __be32 adaptation_ind; -}; - -struct sctp_supported_ext_param { - struct sctp_paramhdr param_hdr; - __u8 chunks[0]; -}; - -struct sctp_random_param { - struct sctp_paramhdr param_hdr; - __u8 random_val[0]; -}; - -struct sctp_chunks_param { - struct sctp_paramhdr param_hdr; - __u8 chunks[0]; -}; - -struct sctp_hmac_algo_param { - struct sctp_paramhdr param_hdr; - __be16 hmac_ids[0]; -}; - -struct sctp_cookie_param { - struct sctp_paramhdr p; - __u8 body[0]; -}; - -struct sctp_gap_ack_block { - __be16 start; - __be16 end; -}; - -union sctp_sack_variable { - struct sctp_gap_ack_block gab; - __be32 dup; -}; - -struct sctp_sackhdr { - __be32 cum_tsn_ack; - __be32 a_rwnd; - __be16 num_gap_ack_blocks; - __be16 num_dup_tsns; - union sctp_sack_variable variable[0]; -}; - -struct sctp_heartbeathdr { - struct sctp_paramhdr info; -}; - -struct sctp_shutdownhdr { - __be32 cum_tsn_ack; -}; - -struct sctp_errhdr { - __be16 cause; - __be16 length; - __u8 variable[0]; -}; - -struct sctp_ecnehdr { - __be32 lowest_tsn; -}; - -struct sctp_cwrhdr { - __be32 lowest_tsn; -}; - -struct sctp_fwdtsn_skip { - __be16 stream; - __be16 ssn; -}; - -struct sctp_fwdtsn_hdr { - __be32 new_cum_tsn; - struct sctp_fwdtsn_skip skip[0]; -}; - -struct sctp_ifwdtsn_skip { - __be16 stream; - __u8 reserved; - __u8 flags; - __be32 mid; -}; - -struct sctp_ifwdtsn_hdr { - __be32 new_cum_tsn; - struct sctp_ifwdtsn_skip skip[0]; -}; - -struct sctp_addip_param { - struct sctp_paramhdr param_hdr; - __be32 crr_id; -}; - -struct sctp_addiphdr { - __be32 serial; - __u8 params[0]; -}; - -struct sctp_authhdr { - __be16 shkey_id; - __be16 hmac_id; - __u8 hmac[0]; -}; - -union sctp_addr { - struct sockaddr_in v4; - struct sockaddr_in6 v6; - struct sockaddr sa; -}; - -struct sctp_cookie { - __u32 my_vtag; - __u32 peer_vtag; - __u32 my_ttag; - __u32 peer_ttag; - ktime_t expiration; - __u16 sinit_num_ostreams; - __u16 sinit_max_instreams; - __u32 initial_tsn; - union sctp_addr peer_addr; - __u16 my_port; - __u8 prsctp_capable; - __u8 padding; - __u32 adaptation_ind; - __u8 auth_random[36]; - __u8 auth_hmacs[10]; - __u8 auth_chunks[20]; - __u32 raw_addr_list_len; - struct sctp_init_chunk peer_init[0]; -}; - -struct sctp_tsnmap { - long unsigned int *tsn_map; - __u32 base_tsn; - __u32 cumulative_tsn_ack_point; - __u32 max_tsn_seen; - __u16 len; - __u16 pending_data; - __u16 num_dup_tsns; - __be32 dup_tsns[16]; -}; - -struct sctp_inithdr_host { - __u32 init_tag; - __u32 a_rwnd; - __u16 num_outbound_streams; - __u16 num_inbound_streams; - __u32 initial_tsn; -}; - -enum sctp_state { - SCTP_STATE_CLOSED = 0, - SCTP_STATE_COOKIE_WAIT = 1, - SCTP_STATE_COOKIE_ECHOED = 2, - SCTP_STATE_ESTABLISHED = 3, - SCTP_STATE_SHUTDOWN_PENDING = 4, - SCTP_STATE_SHUTDOWN_SENT = 5, - SCTP_STATE_SHUTDOWN_RECEIVED = 6, - SCTP_STATE_SHUTDOWN_ACK_SENT = 7, -}; - -struct sctp_stream_out_ext; - -struct sctp_stream_out { - union { - __u32 mid; - __u16 ssn; - }; - __u32 mid_uo; - struct sctp_stream_out_ext *ext; - __u8 state; -}; - -struct sctp_stream_in { - union { - __u32 mid; - __u16 ssn; - }; - __u32 mid_uo; - __u32 fsn; - __u32 fsn_uo; - char pd_mode; - char pd_mode_uo; -}; - -struct sctp_stream_interleave; - -struct sctp_stream { - struct { - struct __genradix tree; - struct sctp_stream_out type[0]; - } out; - struct { - struct __genradix tree; - struct sctp_stream_in type[0]; - } in; - __u16 outcnt; - __u16 incnt; - struct sctp_stream_out *out_curr; - union { - struct { - struct list_head prio_list; - }; - struct { - struct list_head rr_list; - struct sctp_stream_out_ext *rr_next; - }; - }; - struct sctp_stream_interleave *si; -}; - -struct sctp_sched_ops; - -struct sctp_association; - -struct sctp_outq { - struct sctp_association *asoc; - struct list_head out_chunk_list; - struct sctp_sched_ops *sched; - unsigned int out_qlen; - unsigned int error; - struct list_head control_chunk_list; - struct list_head sacked; - struct list_head retransmit; - struct list_head abandoned; - __u32 outstanding_bytes; - char fast_rtx; - char cork; -}; - -struct sctp_ulpq { - char pd_mode; - struct sctp_association *asoc; - struct sk_buff_head reasm; - struct sk_buff_head reasm_uo; - struct sk_buff_head lobby; -}; - -struct sctp_priv_assoc_stats { - struct __kernel_sockaddr_storage obs_rto_ipaddr; - __u64 max_obs_rto; - __u64 isacks; - __u64 osacks; - __u64 opackets; - __u64 ipackets; - __u64 rtxchunks; - __u64 outofseqtsns; - __u64 idupchunks; - __u64 gapcnt; - __u64 ouodchunks; - __u64 iuodchunks; - __u64 oodchunks; - __u64 iodchunks; - __u64 octrlchunks; - __u64 ictrlchunks; -}; - -struct sctp_transport; - -struct sctp_auth_bytes; - -struct sctp_shared_key; - -struct sctp_association { - struct sctp_ep_common base; - struct list_head asocs; - sctp_assoc_t assoc_id; - struct sctp_endpoint *ep; - struct sctp_cookie c; - struct { - struct list_head transport_addr_list; - __u32 rwnd; - __u16 transport_count; - __u16 port; - struct sctp_transport *primary_path; - union sctp_addr primary_addr; - struct sctp_transport *active_path; - struct sctp_transport *retran_path; - struct sctp_transport *last_sent_to; - struct sctp_transport *last_data_from; - struct sctp_tsnmap tsn_map; - __be16 addip_disabled_mask; - __u16 ecn_capable: 1; - __u16 ipv4_address: 1; - __u16 ipv6_address: 1; - __u16 hostname_address: 1; - __u16 asconf_capable: 1; - __u16 prsctp_capable: 1; - __u16 reconf_capable: 1; - __u16 intl_capable: 1; - __u16 auth_capable: 1; - __u16 sack_needed: 1; - __u16 sack_generation: 1; - __u16 zero_window_announced: 1; - __u32 sack_cnt; - __u32 adaptation_ind; - struct sctp_inithdr_host i; - void *cookie; - int cookie_len; - __u32 addip_serial; - struct sctp_random_param *peer_random; - struct sctp_chunks_param *peer_chunks; - struct sctp_hmac_algo_param *peer_hmacs; - } peer; - enum sctp_state state; - int overall_error_count; - ktime_t cookie_life; - long unsigned int rto_initial; - long unsigned int rto_max; - long unsigned int rto_min; - int max_burst; - int max_retrans; - __u16 pf_retrans; - __u16 ps_retrans; - __u16 max_init_attempts; - __u16 init_retries; - long unsigned int max_init_timeo; - long unsigned int hbinterval; - long unsigned int probe_interval; - __be16 encap_port; - __u16 pathmaxrxt; - __u32 flowlabel; - __u8 dscp; - __u8 pmtu_pending; - __u32 pathmtu; - __u32 param_flags; - __u32 sackfreq; - long unsigned int sackdelay; - long unsigned int timeouts[12]; - struct timer_list timers[12]; - struct sctp_transport *shutdown_last_sent_to; - struct sctp_transport *init_last_sent_to; - int shutdown_retries; - __u32 next_tsn; - __u32 ctsn_ack_point; - __u32 adv_peer_ack_point; - __u32 highest_sacked; - __u32 fast_recovery_exit; - __u8 fast_recovery; - __u16 unack_data; - __u32 rtx_data_chunks; - __u32 rwnd; - __u32 a_rwnd; - __u32 rwnd_over; - __u32 rwnd_press; - int sndbuf_used; - atomic_t rmem_alloc; - wait_queue_head_t wait; - __u32 frag_point; - __u32 user_frag; - int init_err_counter; - int init_cycle; - __u16 default_stream; - __u16 default_flags; - __u32 default_ppid; - __u32 default_context; - __u32 default_timetolive; - __u32 default_rcv_context; - struct sctp_stream stream; - struct sctp_outq outqueue; - struct sctp_ulpq ulpq; - __u32 last_ecne_tsn; - __u32 last_cwr_tsn; - int numduptsns; - struct sctp_chunk *addip_last_asconf; - struct list_head asconf_ack_list; - struct list_head addip_chunk_list; - __u32 addip_serial; - int src_out_of_asoc_ok; - union sctp_addr *asconf_addr_del_pending; - struct sctp_transport *new_transport; - struct list_head endpoint_shared_keys; - struct sctp_auth_bytes *asoc_shared_key; - struct sctp_shared_key *shkey; - __u16 default_hmac_id; - __u16 active_key_id; - __u8 need_ecne: 1; - __u8 temp: 1; - __u8 pf_expose: 2; - __u8 force_delay: 1; - __u8 strreset_enable; - __u8 strreset_outstanding; - __u32 strreset_outseq; - __u32 strreset_inseq; - __u32 strreset_result[2]; - struct sctp_chunk *strreset_chunk; - struct sctp_priv_assoc_stats stats; - int sent_cnt_removable; - __u16 subscribe; - __u64 abandoned_unsent[3]; - __u64 abandoned_sent[3]; - struct callback_head rcu; -}; - -struct sctp_auth_bytes { - refcount_t refcnt; - __u32 len; - __u8 data[0]; -}; - -struct sctp_shared_key { - struct list_head key_list; - struct sctp_auth_bytes *key; - refcount_t refcnt; - __u16 key_id; - __u8 deactivated; -}; - -enum { - SCTP_MAX_STREAM = 65535, -}; - -enum sctp_event_timeout { - SCTP_EVENT_TIMEOUT_NONE = 0, - SCTP_EVENT_TIMEOUT_T1_COOKIE = 1, - SCTP_EVENT_TIMEOUT_T1_INIT = 2, - SCTP_EVENT_TIMEOUT_T2_SHUTDOWN = 3, - SCTP_EVENT_TIMEOUT_T3_RTX = 4, - SCTP_EVENT_TIMEOUT_T4_RTO = 5, - SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD = 6, - SCTP_EVENT_TIMEOUT_HEARTBEAT = 7, - SCTP_EVENT_TIMEOUT_RECONF = 8, - SCTP_EVENT_TIMEOUT_PROBE = 9, - SCTP_EVENT_TIMEOUT_SACK = 10, - SCTP_EVENT_TIMEOUT_AUTOCLOSE = 11, -}; - -enum { - SCTP_MAX_DUP_TSNS = 16, -}; - -enum sctp_scope { - SCTP_SCOPE_GLOBAL = 0, - SCTP_SCOPE_PRIVATE = 1, - SCTP_SCOPE_LINK = 2, - SCTP_SCOPE_LOOPBACK = 3, - SCTP_SCOPE_UNUSABLE = 4, -}; - -enum { - SCTP_AUTH_HMAC_ID_RESERVED_0 = 0, - SCTP_AUTH_HMAC_ID_SHA1 = 1, - SCTP_AUTH_HMAC_ID_RESERVED_2 = 2, - SCTP_AUTH_HMAC_ID_SHA256 = 3, - __SCTP_AUTH_HMAC_MAX = 4, -}; - -struct sctp_ulpevent { - struct sctp_association *asoc; - struct sctp_chunk *chunk; - unsigned int rmem_len; - union { - __u32 mid; - __u16 ssn; - }; - union { - __u32 ppid; - __u32 fsn; - }; - __u32 tsn; - __u32 cumtsn; - __u16 stream; - __u16 flags; - __u16 msg_flags; -} __attribute__((packed)); - -union sctp_addr_param; - -union sctp_params { - void *v; - struct sctp_paramhdr *p; - struct sctp_cookie_preserve_param *life; - struct sctp_hostname_param *dns; - struct sctp_cookie_param *cookie; - struct sctp_supported_addrs_param *sat; - struct sctp_ipv4addr_param *v4; - struct sctp_ipv6addr_param *v6; - union sctp_addr_param *addr; - struct sctp_adaptation_ind_param *aind; - struct sctp_supported_ext_param *ext; - struct sctp_random_param *random; - struct sctp_chunks_param *chunks; - struct sctp_hmac_algo_param *hmac_algo; - struct sctp_addip_param *addip; -}; - -struct sctp_sender_hb_info; - -struct sctp_signed_cookie; - -struct sctp_datamsg; - -struct sctp_chunk { - struct list_head list; - refcount_t refcnt; - int sent_count; - union { - struct list_head transmitted_list; - struct list_head stream_list; - }; - struct list_head frag_list; - struct sk_buff *skb; - union { - struct sk_buff *head_skb; - struct sctp_shared_key *shkey; - }; - union sctp_params param_hdr; - union { - __u8 *v; - struct sctp_datahdr *data_hdr; - struct sctp_inithdr *init_hdr; - struct sctp_sackhdr *sack_hdr; - struct sctp_heartbeathdr *hb_hdr; - struct sctp_sender_hb_info *hbs_hdr; - struct sctp_shutdownhdr *shutdown_hdr; - struct sctp_signed_cookie *cookie_hdr; - struct sctp_ecnehdr *ecne_hdr; - struct sctp_cwrhdr *ecn_cwr_hdr; - struct sctp_errhdr *err_hdr; - struct sctp_addiphdr *addip_hdr; - struct sctp_fwdtsn_hdr *fwdtsn_hdr; - struct sctp_authhdr *auth_hdr; - struct sctp_idatahdr *idata_hdr; - struct sctp_ifwdtsn_hdr *ifwdtsn_hdr; - } subh; - __u8 *chunk_end; - struct sctp_chunkhdr *chunk_hdr; - struct sctphdr *sctp_hdr; - struct sctp_sndrcvinfo sinfo; - struct sctp_association *asoc; - struct sctp_ep_common *rcvr; - long unsigned int sent_at; - union sctp_addr source; - union sctp_addr dest; - struct sctp_datamsg *msg; - struct sctp_transport *transport; - struct sk_buff *auth_chunk; - __u16 rtt_in_progress: 1; - __u16 has_tsn: 1; - __u16 has_ssn: 1; - __u16 singleton: 1; - __u16 end_of_packet: 1; - __u16 ecn_ce_done: 1; - __u16 pdiscard: 1; - __u16 tsn_gap_acked: 1; - __u16 data_accepted: 1; - __u16 auth: 1; - __u16 has_asconf: 1; - __u16 pmtu_probe: 1; - __u16 tsn_missing_report: 2; - __u16 fast_retransmit: 2; -}; - -struct sctp_stream_interleave { - __u16 data_chunk_len; - __u16 ftsn_chunk_len; - struct sctp_chunk * (*make_datafrag)(const struct sctp_association *, const struct sctp_sndrcvinfo *, int, __u8, gfp_t); - void (*assign_number)(struct sctp_chunk *); - bool (*validate_data)(struct sctp_chunk *); - int (*ulpevent_data)(struct sctp_ulpq *, struct sctp_chunk *, gfp_t); - int (*enqueue_event)(struct sctp_ulpq *, struct sctp_ulpevent *); - void (*renege_events)(struct sctp_ulpq *, struct sctp_chunk *, gfp_t); - void (*start_pd)(struct sctp_ulpq *, gfp_t); - void (*abort_pd)(struct sctp_ulpq *, gfp_t); - void (*generate_ftsn)(struct sctp_outq *, __u32); - bool (*validate_ftsn)(struct sctp_chunk *); - void (*report_ftsn)(struct sctp_ulpq *, __u32); - void (*handle_ftsn)(struct sctp_ulpq *, struct sctp_chunk *); -}; - -struct sctp_bind_bucket { - short unsigned int port; - signed char fastreuse; - signed char fastreuseport; - kuid_t fastuid; - struct hlist_node node; - struct hlist_head owner; - struct net *net; -}; - -enum sctp_socket_type { - SCTP_SOCKET_UDP = 0, - SCTP_SOCKET_UDP_HIGH_BANDWIDTH = 1, - SCTP_SOCKET_TCP = 2, -}; - -struct sctp_pf; - -struct sctp_sock { - struct inet_sock inet; - enum sctp_socket_type type; - int: 32; - struct sctp_pf *pf; - struct crypto_shash___2 *hmac; - char *sctp_hmac_alg; - struct sctp_endpoint *ep; - struct sctp_bind_bucket *bind_hash; - __u16 default_stream; - short: 16; - __u32 default_ppid; - __u16 default_flags; - short: 16; - __u32 default_context; - __u32 default_timetolive; - __u32 default_rcv_context; - int max_burst; - __u32 hbinterval; - __u32 probe_interval; - __be16 udp_port; - __be16 encap_port; - __u16 pathmaxrxt; - short: 16; - __u32 flowlabel; - __u8 dscp; - char: 8; - __u16 pf_retrans; - __u16 ps_retrans; - short: 16; - __u32 pathmtu; - __u32 sackdelay; - __u32 sackfreq; - __u32 param_flags; - __u32 default_ss; - struct sctp_rtoinfo rtoinfo; - struct sctp_paddrparams paddrparam; - struct sctp_assocparams assocparams; - __u16 subscribe; - struct sctp_initmsg initmsg; - short: 16; - int user_frag; - __u32 autoclose; - __u32 adaptation_ind; - __u32 pd_point; - __u16 nodelay: 1; - __u16 pf_expose: 2; - __u16 reuse: 1; - __u16 disable_fragments: 1; - __u16 v4mapped: 1; - __u16 frag_interleave: 1; - __u16 recvrcvinfo: 1; - __u16 recvnxtinfo: 1; - __u16 data_ready_signalled: 1; - int: 22; - atomic_t pd_mode; - struct sk_buff_head pd_lobby; - struct list_head auto_asconf_list; - int do_auto_asconf; - int: 32; -} __attribute__((packed)); - -struct sctp_af; - -struct sctp_pf { - void (*event_msgname)(struct sctp_ulpevent *, char *, int *); - void (*skb_msgname)(struct sk_buff *, char *, int *); - int (*af_supported)(sa_family_t, struct sctp_sock *); - int (*cmp_addr)(const union sctp_addr *, const union sctp_addr *, struct sctp_sock *); - int (*bind_verify)(struct sctp_sock *, union sctp_addr *); - int (*send_verify)(struct sctp_sock *, union sctp_addr *); - int (*supported_addrs)(const struct sctp_sock *, __be16 *); - struct sock * (*create_accept_sk)(struct sock *, struct sctp_association *, bool); - int (*addr_to_user)(struct sctp_sock *, union sctp_addr *); - void (*to_sk_saddr)(union sctp_addr *, struct sock *); - void (*to_sk_daddr)(union sctp_addr *, struct sock *); - void (*copy_ip_options)(struct sock *, struct sock *); - struct sctp_af *af; -}; - -struct sctp_signed_cookie { - __u8 signature[32]; - __u32 __pad; - struct sctp_cookie c; -} __attribute__((packed)); - -union sctp_addr_param { - struct sctp_paramhdr p; - struct sctp_ipv4addr_param v4; - struct sctp_ipv6addr_param v6; -}; - -struct sctp_sender_hb_info { - struct sctp_paramhdr param_hdr; - union sctp_addr daddr; - long unsigned int sent_at; - __u64 hb_nonce; - __u32 probe_size; -}; - -struct sctp_af { - int (*sctp_xmit)(struct sk_buff *, struct sctp_transport *); - int (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int); - int (*getsockopt)(struct sock *, int, int, char *, int *); - void (*get_dst)(struct sctp_transport *, union sctp_addr *, struct flowi *, struct sock *); - void (*get_saddr)(struct sctp_sock *, struct sctp_transport *, struct flowi *); - void (*copy_addrlist)(struct list_head *, struct net_device *); - int (*cmp_addr)(const union sctp_addr *, const union sctp_addr *); - void (*addr_copy)(union sctp_addr *, union sctp_addr *); - void (*from_skb)(union sctp_addr *, struct sk_buff *, int); - void (*from_sk)(union sctp_addr *, struct sock *); - bool (*from_addr_param)(union sctp_addr *, union sctp_addr_param *, __be16, int); - int (*to_addr_param)(const union sctp_addr *, union sctp_addr_param *); - int (*addr_valid)(union sctp_addr *, struct sctp_sock *, const struct sk_buff *); - enum sctp_scope (*scope)(union sctp_addr *); - void (*inaddr_any)(union sctp_addr *, __be16); - int (*is_any)(const union sctp_addr *); - int (*available)(union sctp_addr *, struct sctp_sock *); - int (*skb_iif)(const struct sk_buff *); - int (*is_ce)(const struct sk_buff *); - void (*seq_dump_addr)(struct seq_file *, union sctp_addr *); - void (*ecn_capable)(struct sock *); - __u16 net_header_len; - int sockaddr_len; - int (*ip_options_len)(struct sock *); - sa_family_t sa_family; - struct list_head list; -}; - -struct sctp_packet { - __u16 source_port; - __u16 destination_port; - __u32 vtag; - struct list_head chunk_list; - size_t overhead; - size_t size; - size_t max_size; - struct sctp_transport *transport; - struct sctp_chunk *auth; - u8 has_cookie_echo: 1; - u8 has_sack: 1; - u8 has_auth: 1; - u8 has_data: 1; - u8 ipfragok: 1; -}; - -struct sctp_transport { - struct list_head transports; - struct rhlist_head node; - refcount_t refcnt; - __u32 rto_pending: 1; - __u32 hb_sent: 1; - __u32 pmtu_pending: 1; - __u32 dst_pending_confirm: 1; - __u32 sack_generation: 1; - u32 dst_cookie; - struct flowi fl; - union sctp_addr ipaddr; - struct sctp_af *af_specific; - struct sctp_association *asoc; - long unsigned int rto; - __u32 rtt; - __u32 rttvar; - __u32 srtt; - __u32 cwnd; - __u32 ssthresh; - __u32 partial_bytes_acked; - __u32 flight_size; - __u32 burst_limited; - struct dst_entry *dst; - union sctp_addr saddr; - long unsigned int hbinterval; - long unsigned int probe_interval; - long unsigned int sackdelay; - __u32 sackfreq; - atomic_t mtu_info; - ktime_t last_time_heard; - long unsigned int last_time_sent; - long unsigned int last_time_ecne_reduced; - __be16 encap_port; - __u16 pathmaxrxt; - __u32 flowlabel; - __u8 dscp; - __u16 pf_retrans; - __u16 ps_retrans; - __u32 pathmtu; - __u32 param_flags; - int init_sent_count; - int state; - short unsigned int error_count; - struct timer_list T3_rtx_timer; - struct timer_list hb_timer; - struct timer_list proto_unreach_timer; - struct timer_list reconf_timer; - struct timer_list probe_timer; - struct list_head transmitted; - struct sctp_packet packet; - struct list_head send_ready; - struct { - __u32 next_tsn_at_change; - char changeover_active; - char cycling_changeover; - char cacc_saw_newack; - } cacc; - struct { - __u32 last_rtx_chunks; - __u16 pmtu; - __u16 probe_size; - __u16 probe_high; - __u8 probe_count: 3; - __u8 raise_count: 5; - __u8 state; - } pl; - __u64 hb_nonce; - struct callback_head rcu; -}; - -struct sctp_datamsg { - struct list_head chunks; - refcount_t refcnt; - long unsigned int expires_at; - int send_error; - u8 send_failed: 1; - u8 can_delay: 1; - u8 abandoned: 1; -}; - -struct sctp_stream_priorities { - struct list_head prio_sched; - struct list_head active; - struct sctp_stream_out_ext *next; - __u16 prio; -}; - -struct sctp_stream_out_ext { - __u64 abandoned_unsent[3]; - __u64 abandoned_sent[3]; - struct list_head outq; - union { - struct { - struct list_head prio_list; - struct sctp_stream_priorities *prio_head; - }; - struct { - struct list_head rr_list; - }; - }; -}; - -struct task_security_struct { - u32 osid; - u32 sid; - u32 exec_sid; - u32 create_sid; - u32 keycreate_sid; - u32 sockcreate_sid; -}; - -enum label_initialized { - LABEL_INVALID = 0, - LABEL_INITIALIZED = 1, - LABEL_PENDING = 2, -}; - -struct inode_security_struct { - struct inode *inode; - struct list_head list; - u32 task_sid; - u32 sid; - u16 sclass; - unsigned char initialized; - spinlock_t lock; -}; - -struct file_security_struct { - u32 sid; - u32 fown_sid; - u32 isid; - u32 pseqno; -}; - -struct superblock_security_struct { - u32 sid; - u32 def_sid; - u32 mntpoint_sid; - short unsigned int behavior; - short unsigned int flags; - struct mutex lock; - struct list_head isec_head; - spinlock_t isec_lock; -}; - -struct msg_security_struct { - u32 sid; -}; - -struct ipc_security_struct { - u16 sclass; - u32 sid; -}; - -struct sk_security_struct { - enum { - NLBL_UNSET = 0, - NLBL_REQUIRE = 1, - NLBL_LABELED = 2, - NLBL_REQSKB = 3, - NLBL_CONNLABELED = 4, - } nlbl_state; - struct netlbl_lsm_secattr *nlbl_secattr; - u32 sid; - u32 peer_sid; - u16 sclass; - enum { - SCTP_ASSOC_UNSET = 0, - SCTP_ASSOC_SET = 1, - } sctp_assoc_state; -}; - -struct tun_security_struct { - u32 sid; -}; - -struct key_security_struct { - u32 sid; -}; - -struct ib_security_struct { - u32 sid; -}; - -struct bpf_security_struct { - u32 sid; -}; - -struct perf_event_security_struct { - u32 sid; -}; - -struct selinux_mnt_opts { - const char *fscontext; - const char *context; - const char *rootcontext; - const char *defcontext; -}; - -enum { - Opt_error = 4294967295, - Opt_context = 0, - Opt_defcontext = 1, - Opt_fscontext = 2, - Opt_rootcontext = 3, - Opt_seclabel = 4, -}; - -struct selinux_policy_convert_data; - -struct selinux_load_state { - struct selinux_policy *policy; - struct selinux_policy_convert_data *convert_data; -}; - -enum sel_inos { - SEL_ROOT_INO = 2, - SEL_LOAD = 3, - SEL_ENFORCE = 4, - SEL_CONTEXT = 5, - SEL_ACCESS = 6, - SEL_CREATE = 7, - SEL_RELABEL = 8, - SEL_USER = 9, - SEL_POLICYVERS = 10, - SEL_COMMIT_BOOLS = 11, - SEL_MLS = 12, - SEL_DISABLE = 13, - SEL_MEMBER = 14, - SEL_CHECKREQPROT = 15, - SEL_COMPAT_NET = 16, - SEL_REJECT_UNKNOWN = 17, - SEL_DENY_UNKNOWN = 18, - SEL_STATUS = 19, - SEL_POLICY = 20, - SEL_VALIDATE_TRANS = 21, - SEL_INO_NEXT = 22, -}; - -struct selinux_fs_info { - struct dentry *bool_dir; - unsigned int bool_num; - char **bool_pending_names; - unsigned int *bool_pending_values; - struct dentry *class_dir; - long unsigned int last_class_ino; - bool policy_opened; - struct dentry *policycap_dir; - long unsigned int last_ino; - struct selinux_state *state; - struct super_block *sb; -}; - -struct policy_load_memory { - size_t len; - void *data; -}; - -enum { - SELNL_MSG_SETENFORCE = 16, - SELNL_MSG_POLICYLOAD = 17, - SELNL_MSG_MAX = 18, -}; - -enum selinux_nlgroups { - SELNLGRP_NONE = 0, - SELNLGRP_AVC = 1, - __SELNLGRP_MAX = 2, -}; - -struct selnl_msg_setenforce { - __s32 val; -}; - -struct selnl_msg_policyload { - __u32 seqno; -}; - -enum { - XFRM_MSG_BASE = 16, - XFRM_MSG_NEWSA = 16, - XFRM_MSG_DELSA = 17, - XFRM_MSG_GETSA = 18, - XFRM_MSG_NEWPOLICY = 19, - XFRM_MSG_DELPOLICY = 20, - XFRM_MSG_GETPOLICY = 21, - XFRM_MSG_ALLOCSPI = 22, - XFRM_MSG_ACQUIRE = 23, - XFRM_MSG_EXPIRE = 24, - XFRM_MSG_UPDPOLICY = 25, - XFRM_MSG_UPDSA = 26, - XFRM_MSG_POLEXPIRE = 27, - XFRM_MSG_FLUSHSA = 28, - XFRM_MSG_FLUSHPOLICY = 29, - XFRM_MSG_NEWAE = 30, - XFRM_MSG_GETAE = 31, - XFRM_MSG_REPORT = 32, - XFRM_MSG_MIGRATE = 33, - XFRM_MSG_NEWSADINFO = 34, - XFRM_MSG_GETSADINFO = 35, - XFRM_MSG_NEWSPDINFO = 36, - XFRM_MSG_GETSPDINFO = 37, - XFRM_MSG_MAPPING = 38, - __XFRM_MSG_MAX = 39, -}; - -enum { - RTM_BASE = 16, - RTM_NEWLINK = 16, - RTM_DELLINK = 17, - RTM_GETLINK = 18, - RTM_SETLINK = 19, - RTM_NEWADDR = 20, - RTM_DELADDR = 21, - RTM_GETADDR = 22, - RTM_NEWROUTE = 24, - RTM_DELROUTE = 25, - RTM_GETROUTE = 26, - RTM_NEWNEIGH = 28, - RTM_DELNEIGH = 29, - RTM_GETNEIGH = 30, - RTM_NEWRULE = 32, - RTM_DELRULE = 33, - RTM_GETRULE = 34, - RTM_NEWQDISC = 36, - RTM_DELQDISC = 37, - RTM_GETQDISC = 38, - RTM_NEWTCLASS = 40, - RTM_DELTCLASS = 41, - RTM_GETTCLASS = 42, - RTM_NEWTFILTER = 44, - RTM_DELTFILTER = 45, - RTM_GETTFILTER = 46, - RTM_NEWACTION = 48, - RTM_DELACTION = 49, - RTM_GETACTION = 50, - RTM_NEWPREFIX = 52, - RTM_GETMULTICAST = 58, - RTM_GETANYCAST = 62, - RTM_NEWNEIGHTBL = 64, - RTM_GETNEIGHTBL = 66, - RTM_SETNEIGHTBL = 67, - RTM_NEWNDUSEROPT = 68, - RTM_NEWADDRLABEL = 72, - RTM_DELADDRLABEL = 73, - RTM_GETADDRLABEL = 74, - RTM_GETDCB = 78, - RTM_SETDCB = 79, - RTM_NEWNETCONF = 80, - RTM_DELNETCONF = 81, - RTM_GETNETCONF = 82, - RTM_NEWMDB = 84, - RTM_DELMDB = 85, - RTM_GETMDB = 86, - RTM_NEWNSID = 88, - RTM_DELNSID = 89, - RTM_GETNSID = 90, - RTM_NEWSTATS = 92, - RTM_GETSTATS = 94, - RTM_NEWCACHEREPORT = 96, - RTM_NEWCHAIN = 100, - RTM_DELCHAIN = 101, - RTM_GETCHAIN = 102, - RTM_NEWNEXTHOP = 104, - RTM_DELNEXTHOP = 105, - RTM_GETNEXTHOP = 106, - RTM_NEWLINKPROP = 108, - RTM_DELLINKPROP = 109, - RTM_GETLINKPROP = 110, - RTM_NEWVLAN = 112, - RTM_DELVLAN = 113, - RTM_GETVLAN = 114, - RTM_NEWNEXTHOPBUCKET = 116, - RTM_DELNEXTHOPBUCKET = 117, - RTM_GETNEXTHOPBUCKET = 118, - __RTM_MAX = 119, -}; - -struct nlmsg_perm { - u16 nlmsg_type; - u32 perm; -}; - -struct netif_security_struct { - struct net *ns; - int ifindex; - u32 sid; -}; - -struct sel_netif { - struct list_head list; - struct netif_security_struct nsec; - struct callback_head callback_head; -}; - -struct netnode_security_struct { - union { - __be32 ipv4; - struct in6_addr ipv6; - } addr; - u32 sid; - u16 family; -}; - -struct sel_netnode_bkt { - unsigned int size; - struct list_head list; -}; - -struct sel_netnode { - struct netnode_security_struct nsec; - struct list_head list; - struct callback_head rcu; -}; - -struct netport_security_struct { - u32 sid; - u16 port; - u8 protocol; -}; - -struct sel_netport_bkt { - int size; - struct list_head list; -}; - -struct sel_netport { - struct netport_security_struct psec; - struct list_head list; - struct callback_head rcu; -}; - -struct selinux_kernel_status { - u32 version; - u32 sequence; - u32 enforcing; - u32 policyload; - u32 deny_unknown; -}; - -struct ebitmap_node { - struct ebitmap_node *next; - long unsigned int maps[6]; - u32 startbit; -}; - -struct ebitmap { - struct ebitmap_node *node; - u32 highbit; -}; - -struct policy_file { - char *data; - size_t len; -}; - -struct hashtab_node { - void *key; - void *datum; - struct hashtab_node *next; -}; - -struct hashtab { - struct hashtab_node **htable; - u32 size; - u32 nel; -}; - -struct hashtab_info { - u32 slots_used; - u32 max_chain_len; -}; - -struct hashtab_key_params { - u32 (*hash)(const void *); - int (*cmp)(const void *, const void *); -}; - -struct symtab { - struct hashtab table; - u32 nprim; -}; - -struct mls_level { - u32 sens; - struct ebitmap cat; -}; - -struct mls_range { - struct mls_level level[2]; -}; - -struct context___2 { - u32 user; - u32 role; - u32 type; - u32 len; - struct mls_range range; - char *str; -}; - -struct sidtab_str_cache; - -struct sidtab_entry { - u32 sid; - u32 hash; - struct context___2 context; - struct sidtab_str_cache *cache; - struct hlist_node list; -}; - -struct sidtab_str_cache { - struct callback_head rcu_member; - struct list_head lru_member; - struct sidtab_entry *parent; - u32 len; - char str[0]; -}; - -struct sidtab_node_inner; - -struct sidtab_node_leaf; - -union sidtab_entry_inner { - struct sidtab_node_inner *ptr_inner; - struct sidtab_node_leaf *ptr_leaf; -}; - -struct sidtab_node_inner { - union sidtab_entry_inner entries[512]; -}; - -struct sidtab_node_leaf { - struct sidtab_entry entries[39]; -}; - -struct sidtab_isid_entry { - int set; - struct sidtab_entry entry; -}; - -struct sidtab; - -struct sidtab_convert_params { - int (*func)(struct context___2 *, struct context___2 *, void *); - void *args; - struct sidtab *target; -}; - -struct sidtab { - union sidtab_entry_inner roots[4]; - u32 count; - struct sidtab_convert_params *convert; - bool frozen; - spinlock_t lock; - u32 cache_free_slots; - struct list_head cache_lru_list; - spinlock_t cache_lock; - struct sidtab_isid_entry isids[27]; - struct hlist_head context_to_sid[512]; -}; - -struct avtab_key { - u16 source_type; - u16 target_type; - u16 target_class; - u16 specified; -}; - -struct avtab_extended_perms { - u8 specified; - u8 driver; - struct extended_perms_data perms; -}; - -struct avtab_datum { - union { - u32 data; - struct avtab_extended_perms *xperms; - } u; -}; - -struct avtab_node { - struct avtab_key key; - struct avtab_datum datum; - struct avtab_node *next; -}; - -struct avtab { - struct avtab_node **htable; - u32 nel; - u32 nslot; - u32 mask; -}; - -struct type_set; - -struct constraint_expr { - u32 expr_type; - u32 attr; - u32 op; - struct ebitmap names; - struct type_set *type_names; - struct constraint_expr *next; -}; - -struct type_set { - struct ebitmap types; - struct ebitmap negset; - u32 flags; -}; - -struct constraint_node { - u32 permissions; - struct constraint_expr *expr; - struct constraint_node *next; -}; - -struct common_datum { - u32 value; - struct symtab permissions; -}; - -struct class_datum { - u32 value; - char *comkey; - struct common_datum *comdatum; - struct symtab permissions; - struct constraint_node *constraints; - struct constraint_node *validatetrans; - char default_user; - char default_role; - char default_type; - char default_range; -}; - -struct role_datum { - u32 value; - u32 bounds; - struct ebitmap dominates; - struct ebitmap types; -}; - -struct role_allow { - u32 role; - u32 new_role; - struct role_allow *next; -}; - -struct type_datum { - u32 value; - u32 bounds; - unsigned char primary; - unsigned char attribute; -}; - -struct user_datum { - u32 value; - u32 bounds; - struct ebitmap roles; - struct mls_range range; - struct mls_level dfltlevel; -}; - -struct cond_bool_datum { - __u32 value; - int state; -}; - -struct ocontext { - union { - char *name; - struct { - u8 protocol; - u16 low_port; - u16 high_port; - } port; - struct { - u32 addr; - u32 mask; - } node; - struct { - u32 addr[4]; - u32 mask[4]; - } node6; - struct { - u64 subnet_prefix; - u16 low_pkey; - u16 high_pkey; - } ibpkey; - struct { - char *dev_name; - u8 port; - } ibendport; - } u; - union { - u32 sclass; - u32 behavior; - } v; - struct context___2 context[2]; - u32 sid[2]; - struct ocontext *next; -}; - -struct genfs { - char *fstype; - struct ocontext *head; - struct genfs *next; -}; - -struct cond_node; - -struct policydb { - int mls_enabled; - struct symtab symtab[8]; - char **sym_val_to_name[8]; - struct class_datum **class_val_to_struct; - struct role_datum **role_val_to_struct; - struct user_datum **user_val_to_struct; - struct type_datum **type_val_to_struct; - struct avtab te_avtab; - struct hashtab role_tr; - struct ebitmap filename_trans_ttypes; - struct hashtab filename_trans; - u32 compat_filename_trans_count; - struct cond_bool_datum **bool_val_to_struct; - struct avtab te_cond_avtab; - struct cond_node *cond_list; - u32 cond_list_len; - struct role_allow *role_allow; - struct ocontext *ocontexts[9]; - struct genfs *genfs; - struct hashtab range_tr; - struct ebitmap *type_attr_map_array; - struct ebitmap policycaps; - struct ebitmap permissive_map; - size_t len; - unsigned int policyvers; - unsigned int reject_unknown: 1; - unsigned int allow_unknown: 1; - u16 process_class; - u32 process_trans_perms; -}; - -struct perm_datum { - u32 value; -}; - -struct role_trans_key { - u32 role; - u32 type; - u32 tclass; -}; - -struct role_trans_datum { - u32 new_role; -}; - -struct filename_trans_key { - u32 ttype; - u16 tclass; - const char *name; -}; - -struct filename_trans_datum { - struct ebitmap stypes; - u32 otype; - struct filename_trans_datum *next; -}; - -struct level_datum { - struct mls_level *level; - unsigned char isalias; -}; - -struct cat_datum { - u32 value; - unsigned char isalias; -}; - -struct range_trans { - u32 source_type; - u32 target_type; - u32 target_class; -}; - -struct cond_expr_node; - -struct cond_expr { - struct cond_expr_node *nodes; - u32 len; -}; - -struct cond_av_list { - struct avtab_node **nodes; - u32 len; -}; - -struct cond_node { - int cur_state; - struct cond_expr expr; - struct cond_av_list true_list; - struct cond_av_list false_list; -}; - -struct policy_data { - struct policydb *p; - void *fp; -}; - -struct cond_expr_node { - u32 expr_type; - u32 bool; -}; - -struct policydb_compat_info { - int version; - int sym_num; - int ocon_num; -}; - -struct selinux_mapping; - -struct selinux_map { - struct selinux_mapping *mapping; - u16 size; -}; - -struct selinux_policy { - struct sidtab *sidtab; - struct policydb policydb; - struct selinux_map map; - u32 latest_granting; -}; - -struct convert_context_args { - struct selinux_state *state; - struct policydb *oldp; - struct policydb *newp; -}; - -struct selinux_policy_convert_data { - struct convert_context_args args; - struct sidtab_convert_params sidtab_params; -}; - -struct selinux_mapping { - u16 value; - unsigned int num_perms; - u32 perms[32]; -}; - -struct selinux_audit_rule { - u32 au_seqno; - struct context___2 au_ctxt; -}; - -struct cond_insertf_data { - struct policydb *p; - struct avtab_node **dst; - struct cond_av_list *other; -}; - -struct rt6key { - struct in6_addr addr; - int plen; -}; - -struct rtable; - -struct fnhe_hash_bucket; - -struct fib_nh_common { - struct net_device *nhc_dev; - int nhc_oif; - unsigned char nhc_scope; - u8 nhc_family; - u8 nhc_gw_family; - unsigned char nhc_flags; - struct lwtunnel_state *nhc_lwtstate; - union { - __be32 ipv4; - struct in6_addr ipv6; - } nhc_gw; - int nhc_weight; - atomic_t nhc_upper_bound; - struct rtable **nhc_pcpu_rth_output; - struct rtable *nhc_rth_input; - struct fnhe_hash_bucket *nhc_exceptions; -}; - -struct rt6_exception_bucket; - -struct fib6_nh { - struct fib_nh_common nh_common; - long unsigned int last_probe; - struct rt6_info **rt6i_pcpu; - struct rt6_exception_bucket *rt6i_exception_bucket; -}; - -struct fib6_node; - -struct dst_metrics; - -struct nexthop; - -struct fib6_info { - struct fib6_table *fib6_table; - struct fib6_info *fib6_next; - struct fib6_node *fib6_node; - union { - struct list_head fib6_siblings; - struct list_head nh_list; - }; - unsigned int fib6_nsiblings; - refcount_t fib6_ref; - long unsigned int expires; - struct dst_metrics *fib6_metrics; - struct rt6key fib6_dst; - u32 fib6_flags; - struct rt6key fib6_src; - struct rt6key fib6_prefsrc; - u32 fib6_metric; - u8 fib6_protocol; - u8 fib6_type; - u8 should_flush: 1; - u8 dst_nocount: 1; - u8 dst_nopolicy: 1; - u8 fib6_destroying: 1; - u8 offload: 1; - u8 trap: 1; - u8 offload_failed: 1; - u8 unused: 1; - struct callback_head rcu; - struct nexthop *nh; - struct fib6_nh fib6_nh[0]; -}; - -struct uncached_list; - -struct rt6_info { - struct dst_entry dst; - struct fib6_info *from; - int sernum; - struct rt6key rt6i_dst; - struct rt6key rt6i_src; - struct in6_addr rt6i_gateway; - struct inet6_dev *rt6i_idev; - u32 rt6i_flags; - struct list_head rt6i_uncached; - struct uncached_list *rt6i_uncached_list; - short unsigned int rt6i_nfheader_len; -}; - -struct rt6_statistics { - __u32 fib_nodes; - __u32 fib_route_nodes; - __u32 fib_rt_entries; - __u32 fib_rt_cache; - __u32 fib_discarded_routes; - atomic_t fib_rt_alloc; - atomic_t fib_rt_uncache; -}; - -struct fib6_node { - struct fib6_node *parent; - struct fib6_node *left; - struct fib6_node *right; - struct fib6_node *subtree; - struct fib6_info *leaf; - __u16 fn_bit; - __u16 fn_flags; - int fn_sernum; - struct fib6_info *rr_ptr; - struct callback_head rcu; -}; - -struct fib6_table { - struct hlist_node tb6_hlist; - u32 tb6_id; - spinlock_t tb6_lock; - struct fib6_node tb6_root; - struct inet_peer_base tb6_peers; - unsigned int flags; - unsigned int fib_seq; -}; - -typedef union { - __be32 a4; - __be32 a6[4]; - struct in6_addr in6; -} xfrm_address_t; - -struct xfrm_id { - xfrm_address_t daddr; - __be32 spi; - __u8 proto; -}; - -struct xfrm_selector { - xfrm_address_t daddr; - xfrm_address_t saddr; - __be16 dport; - __be16 dport_mask; - __be16 sport; - __be16 sport_mask; - __u16 family; - __u8 prefixlen_d; - __u8 prefixlen_s; - __u8 proto; - int ifindex; - __kernel_uid32_t user; -}; - -struct xfrm_lifetime_cfg { - __u64 soft_byte_limit; - __u64 hard_byte_limit; - __u64 soft_packet_limit; - __u64 hard_packet_limit; - __u64 soft_add_expires_seconds; - __u64 hard_add_expires_seconds; - __u64 soft_use_expires_seconds; - __u64 hard_use_expires_seconds; -}; - -struct xfrm_lifetime_cur { - __u64 bytes; - __u64 packets; - __u64 add_time; - __u64 use_time; -}; - -struct xfrm_replay_state { - __u32 oseq; - __u32 seq; - __u32 bitmap; -}; - -struct xfrm_replay_state_esn { - unsigned int bmp_len; - __u32 oseq; - __u32 seq; - __u32 oseq_hi; - __u32 seq_hi; - __u32 replay_window; - __u32 bmp[0]; -}; - -struct xfrm_algo { - char alg_name[64]; - unsigned int alg_key_len; - char alg_key[0]; -}; - -struct xfrm_algo_auth { - char alg_name[64]; - unsigned int alg_key_len; - unsigned int alg_trunc_len; - char alg_key[0]; -}; - -struct xfrm_algo_aead { - char alg_name[64]; - unsigned int alg_key_len; - unsigned int alg_icv_len; - char alg_key[0]; -}; - -struct xfrm_stats { - __u32 replay_window; - __u32 replay; - __u32 integrity_failed; -}; - -enum { - XFRM_POLICY_TYPE_MAIN = 0, - XFRM_POLICY_TYPE_SUB = 1, - XFRM_POLICY_TYPE_MAX = 2, - XFRM_POLICY_TYPE_ANY = 255, -}; - -struct xfrm_encap_tmpl { - __u16 encap_type; - __be16 encap_sport; - __be16 encap_dport; - xfrm_address_t encap_oa; -}; - -enum xfrm_attr_type_t { - XFRMA_UNSPEC = 0, - XFRMA_ALG_AUTH = 1, - XFRMA_ALG_CRYPT = 2, - XFRMA_ALG_COMP = 3, - XFRMA_ENCAP = 4, - XFRMA_TMPL = 5, - XFRMA_SA = 6, - XFRMA_POLICY = 7, - XFRMA_SEC_CTX = 8, - XFRMA_LTIME_VAL = 9, - XFRMA_REPLAY_VAL = 10, - XFRMA_REPLAY_THRESH = 11, - XFRMA_ETIMER_THRESH = 12, - XFRMA_SRCADDR = 13, - XFRMA_COADDR = 14, - XFRMA_LASTUSED = 15, - XFRMA_POLICY_TYPE = 16, - XFRMA_MIGRATE = 17, - XFRMA_ALG_AEAD = 18, - XFRMA_KMADDRESS = 19, - XFRMA_ALG_AUTH_TRUNC = 20, - XFRMA_MARK = 21, - XFRMA_TFCPAD = 22, - XFRMA_REPLAY_ESN_VAL = 23, - XFRMA_SA_EXTRA_FLAGS = 24, - XFRMA_PROTO = 25, - XFRMA_ADDRESS_FILTER = 26, - XFRMA_PAD = 27, - XFRMA_OFFLOAD_DEV = 28, - XFRMA_SET_MARK = 29, - XFRMA_SET_MARK_MASK = 30, - XFRMA_IF_ID = 31, - __XFRMA_MAX = 32, -}; - -struct xfrm_mark { - __u32 v; - __u32 m; -}; - -struct xfrm_address_filter { - xfrm_address_t saddr; - xfrm_address_t daddr; - __u16 family; - __u8 splen; - __u8 dplen; -}; - -struct xfrm_state_walk { - struct list_head all; - u8 state; - u8 dying; - u8 proto; - u32 seq; - struct xfrm_address_filter *filter; -}; - -enum xfrm_replay_mode { - XFRM_REPLAY_MODE_LEGACY = 0, - XFRM_REPLAY_MODE_BMP = 1, - XFRM_REPLAY_MODE_ESN = 2, -}; - -struct xfrm_state_offload { - struct net_device *dev; - struct net_device *real_dev; - long unsigned int offload_handle; - unsigned int num_exthdrs; - u8 flags; -}; - -struct xfrm_mode { - u8 encap; - u8 family; - u8 flags; -}; - -struct xfrm_type; - -struct xfrm_type_offload; - -struct xfrm_state { - possible_net_t xs_net; - union { - struct hlist_node gclist; - struct hlist_node bydst; - }; - struct hlist_node bysrc; - struct hlist_node byspi; - struct hlist_node byseq; - refcount_t refcnt; - spinlock_t lock; - struct xfrm_id id; - struct xfrm_selector sel; - struct xfrm_mark mark; - u32 if_id; - u32 tfcpad; - u32 genid; - struct xfrm_state_walk km; - struct { - u32 reqid; - u8 mode; - u8 replay_window; - u8 aalgo; - u8 ealgo; - u8 calgo; - u8 flags; - u16 family; - xfrm_address_t saddr; - int header_len; - int trailer_len; - u32 extra_flags; - struct xfrm_mark smark; - } props; - struct xfrm_lifetime_cfg lft; - struct xfrm_algo_auth *aalg; - struct xfrm_algo *ealg; - struct xfrm_algo *calg; - struct xfrm_algo_aead *aead; - const char *geniv; - struct xfrm_encap_tmpl *encap; - struct sock *encap_sk; - xfrm_address_t *coaddr; - struct xfrm_state *tunnel; - atomic_t tunnel_users; - struct xfrm_replay_state replay; - struct xfrm_replay_state_esn *replay_esn; - struct xfrm_replay_state preplay; - struct xfrm_replay_state_esn *preplay_esn; - enum xfrm_replay_mode repl_mode; - u32 xflags; - u32 replay_maxage; - u32 replay_maxdiff; - struct timer_list rtimer; - struct xfrm_stats stats; - struct xfrm_lifetime_cur curlft; - struct hrtimer mtimer; - struct xfrm_state_offload xso; - long int saved_tmo; - time64_t lastused; - struct page_frag xfrag; - const struct xfrm_type *type; - struct xfrm_mode inner_mode; - struct xfrm_mode inner_mode_iaf; - struct xfrm_mode outer_mode; - const struct xfrm_type_offload *type_offload; - struct xfrm_sec_ctx *security; - void *data; -}; - -struct dst_metrics { - u32 metrics[17]; - refcount_t refcnt; -}; - -struct xfrm_policy_walk_entry { - struct list_head all; - u8 dead; -}; - -struct xfrm_policy_queue { - struct sk_buff_head hold_queue; - struct timer_list hold_timer; - long unsigned int timeout; -}; - -struct xfrm_tmpl { - struct xfrm_id id; - xfrm_address_t saddr; - short unsigned int encap_family; - u32 reqid; - u8 mode; - u8 share; - u8 optional; - u8 allalgs; - u32 aalgos; - u32 ealgos; - u32 calgos; -}; - -struct xfrm_policy { - possible_net_t xp_net; - struct hlist_node bydst; - struct hlist_node byidx; - rwlock_t lock; - refcount_t refcnt; - u32 pos; - struct timer_list timer; - atomic_t genid; - u32 priority; - u32 index; - u32 if_id; - struct xfrm_mark mark; - struct xfrm_selector selector; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - struct xfrm_policy_walk_entry walk; - struct xfrm_policy_queue polq; - bool bydst_reinsert; - u8 type; - u8 action; - u8 flags; - u8 xfrm_nr; - u16 family; - struct xfrm_sec_ctx *security; - struct xfrm_tmpl xfrm_vec[6]; - struct hlist_node bydst_inexact_list; - struct callback_head rcu; -}; - -struct udp_hslot; - -struct udp_table { - struct udp_hslot *hash; - struct udp_hslot *hash2; - unsigned int mask; - unsigned int log; -}; - -struct fib_nh_exception { - struct fib_nh_exception *fnhe_next; - int fnhe_genid; - __be32 fnhe_daddr; - u32 fnhe_pmtu; - bool fnhe_mtu_locked; - __be32 fnhe_gw; - long unsigned int fnhe_expires; - struct rtable *fnhe_rth_input; - struct rtable *fnhe_rth_output; - long unsigned int fnhe_stamp; - struct callback_head rcu; -}; - -struct rtable { - struct dst_entry dst; - int rt_genid; - unsigned int rt_flags; - __u16 rt_type; - __u8 rt_is_input; - __u8 rt_uses_gateway; - int rt_iif; - u8 rt_gw_family; - union { - __be32 rt_gw4; - struct in6_addr rt_gw6; - }; - u32 rt_mtu_locked: 1; - u32 rt_pmtu: 31; - struct list_head rt_uncached; - struct uncached_list *rt_uncached_list; -}; - -struct fnhe_hash_bucket { - struct fib_nh_exception *chain; -}; - -struct rt6_exception_bucket { - struct hlist_head chain; - int depth; -}; - -struct xfrm_type { - struct module *owner; - u8 proto; - u8 flags; - int (*init_state)(struct xfrm_state *); - void (*destructor)(struct xfrm_state *); - int (*input)(struct xfrm_state *, struct sk_buff *); - int (*output)(struct xfrm_state *, struct sk_buff *); - int (*reject)(struct xfrm_state *, struct sk_buff *, const struct flowi *); -}; - -struct xfrm_type_offload { - struct module *owner; - u8 proto; - void (*encap)(struct xfrm_state *, struct sk_buff *); - int (*input_tail)(struct xfrm_state *, struct sk_buff *); - int (*xmit)(struct xfrm_state *, struct sk_buff *, netdev_features_t); -}; - -struct xfrm_dst { - union { - struct dst_entry dst; - struct rtable rt; - struct rt6_info rt6; - } u; - struct dst_entry *route; - struct dst_entry *child; - struct dst_entry *path; - struct xfrm_policy *pols[2]; - int num_pols; - int num_xfrms; - u32 xfrm_genid; - u32 policy_genid; - u32 route_mtu_cached; - u32 child_mtu_cached; - u32 route_cookie; - u32 path_cookie; -}; - -struct xfrm_offload { - struct { - __u32 low; - __u32 hi; - } seq; - __u32 flags; - __u32 status; - __u8 proto; - __u8 inner_ipproto; -}; - -struct sec_path { - int len; - int olen; - struct xfrm_state *xvec[6]; - struct xfrm_offload ovec[1]; -}; - -struct udp_hslot { - struct hlist_head head; - int count; - spinlock_t lock; -}; - -struct pkey_security_struct { - u64 subnet_prefix; - u16 pkey; - u32 sid; -}; - -struct sel_ib_pkey_bkt { - int size; - struct list_head list; -}; - -struct sel_ib_pkey { - struct pkey_security_struct psec; - struct list_head list; - struct callback_head rcu; -}; - -struct smack_audit_data { - const char *function; - char *subject; - char *object; - char *request; - int result; -}; - -struct smack_known { - struct list_head list; - struct hlist_node smk_hashed; - char *smk_known; - u32 smk_secid; - struct netlbl_lsm_secattr smk_netlabel; - struct list_head smk_rules; - struct mutex smk_rules_lock; -}; - -struct superblock_smack { - struct smack_known *smk_root; - struct smack_known *smk_floor; - struct smack_known *smk_hat; - struct smack_known *smk_default; - int smk_flags; -}; - -struct socket_smack { - struct smack_known *smk_out; - struct smack_known *smk_in; - struct smack_known *smk_packet; - int smk_state; -}; - -struct inode_smack { - struct smack_known *smk_inode; - struct smack_known *smk_task; - struct smack_known *smk_mmap; - int smk_flags; -}; - -struct task_smack { - struct smack_known *smk_task; - struct smack_known *smk_forked; - struct list_head smk_rules; - struct mutex smk_rules_lock; - struct list_head smk_relabel; -}; - -struct smack_rule { - struct list_head list; - struct smack_known *smk_subject; - struct smack_known *smk_object; - int smk_access; -}; - -struct smk_net4addr { - struct list_head list; - struct in_addr smk_host; - struct in_addr smk_mask; - int smk_masks; - struct smack_known *smk_label; -}; - -struct smk_net6addr { - struct list_head list; - struct in6_addr smk_host; - struct in6_addr smk_mask; - int smk_masks; - struct smack_known *smk_label; -}; - -struct smack_known_list_elem { - struct list_head list; - struct smack_known *smk_label; -}; - -enum { - Opt_error___2 = 4294967295, - Opt_fsdefault = 0, - Opt_fsfloor = 1, - Opt_fshat = 2, - Opt_fsroot = 3, - Opt_fstransmute = 4, -}; - -struct smk_audit_info { - struct common_audit_data a; - struct smack_audit_data sad; -}; - -struct smack_mnt_opts { - const char *fsdefault; - const char *fsfloor; - const char *fshat; - const char *fsroot; - const char *fstransmute; -}; - -struct netlbl_audit { - u32 secid; - kuid_t loginuid; - unsigned int sessionid; -}; - -struct cipso_v4_std_map_tbl { - struct { - u32 *cipso; - u32 *local; - u32 cipso_size; - u32 local_size; - } lvl; - struct { - u32 *cipso; - u32 *local; - u32 cipso_size; - u32 local_size; - } cat; -}; - -struct cipso_v4_doi { - u32 doi; - u32 type; - union { - struct cipso_v4_std_map_tbl *std; - } map; - u8 tags[5]; - refcount_t refcount; - struct list_head list; - struct callback_head rcu; -}; - -enum smk_inos { - SMK_ROOT_INO = 2, - SMK_LOAD = 3, - SMK_CIPSO = 4, - SMK_DOI = 5, - SMK_DIRECT = 6, - SMK_AMBIENT = 7, - SMK_NET4ADDR = 8, - SMK_ONLYCAP = 9, - SMK_LOGGING = 10, - SMK_LOAD_SELF = 11, - SMK_ACCESSES = 12, - SMK_MAPPED = 13, - SMK_LOAD2 = 14, - SMK_LOAD_SELF2 = 15, - SMK_ACCESS2 = 16, - SMK_CIPSO2 = 17, - SMK_REVOKE_SUBJ = 18, - SMK_CHANGE_RULE = 19, - SMK_SYSLOG = 20, - SMK_PTRACE = 21, - SMK_UNCONFINED = 22, - SMK_NET6ADDR = 23, - SMK_RELABEL_SELF = 24, -}; - -struct smack_parsed_rule { - struct smack_known *smk_subject; - struct smack_known *smk_object; - int smk_access1; - int smk_access2; -}; - -struct sockaddr_un { - __kernel_sa_family_t sun_family; - char sun_path[108]; -}; - -struct unix_address { - refcount_t refcnt; - int len; - unsigned int hash; - struct sockaddr_un name[0]; -}; - -struct scm_stat { - atomic_t nr_fds; -}; - -struct unix_sock { - struct sock sk; - struct unix_address *addr; - struct path path; - struct mutex iolock; - struct mutex bindlock; - struct sock *peer; - struct list_head link; - atomic_long_t inflight; - spinlock_t lock; - long unsigned int gc_flags; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct socket_wq peer_wq; - wait_queue_entry_t peer_wake; - struct scm_stat scm_stat; - long: 32; - long: 64; - long: 64; -}; - -enum tomoyo_conditions_index { - TOMOYO_TASK_UID = 0, - TOMOYO_TASK_EUID = 1, - TOMOYO_TASK_SUID = 2, - TOMOYO_TASK_FSUID = 3, - TOMOYO_TASK_GID = 4, - TOMOYO_TASK_EGID = 5, - TOMOYO_TASK_SGID = 6, - TOMOYO_TASK_FSGID = 7, - TOMOYO_TASK_PID = 8, - TOMOYO_TASK_PPID = 9, - TOMOYO_EXEC_ARGC = 10, - TOMOYO_EXEC_ENVC = 11, - TOMOYO_TYPE_IS_SOCKET = 12, - TOMOYO_TYPE_IS_SYMLINK = 13, - TOMOYO_TYPE_IS_FILE = 14, - TOMOYO_TYPE_IS_BLOCK_DEV = 15, - TOMOYO_TYPE_IS_DIRECTORY = 16, - TOMOYO_TYPE_IS_CHAR_DEV = 17, - TOMOYO_TYPE_IS_FIFO = 18, - TOMOYO_MODE_SETUID = 19, - TOMOYO_MODE_SETGID = 20, - TOMOYO_MODE_STICKY = 21, - TOMOYO_MODE_OWNER_READ = 22, - TOMOYO_MODE_OWNER_WRITE = 23, - TOMOYO_MODE_OWNER_EXECUTE = 24, - TOMOYO_MODE_GROUP_READ = 25, - TOMOYO_MODE_GROUP_WRITE = 26, - TOMOYO_MODE_GROUP_EXECUTE = 27, - TOMOYO_MODE_OTHERS_READ = 28, - TOMOYO_MODE_OTHERS_WRITE = 29, - TOMOYO_MODE_OTHERS_EXECUTE = 30, - TOMOYO_EXEC_REALPATH = 31, - TOMOYO_SYMLINK_TARGET = 32, - TOMOYO_PATH1_UID = 33, - TOMOYO_PATH1_GID = 34, - TOMOYO_PATH1_INO = 35, - TOMOYO_PATH1_MAJOR = 36, - TOMOYO_PATH1_MINOR = 37, - TOMOYO_PATH1_PERM = 38, - TOMOYO_PATH1_TYPE = 39, - TOMOYO_PATH1_DEV_MAJOR = 40, - TOMOYO_PATH1_DEV_MINOR = 41, - TOMOYO_PATH2_UID = 42, - TOMOYO_PATH2_GID = 43, - TOMOYO_PATH2_INO = 44, - TOMOYO_PATH2_MAJOR = 45, - TOMOYO_PATH2_MINOR = 46, - TOMOYO_PATH2_PERM = 47, - TOMOYO_PATH2_TYPE = 48, - TOMOYO_PATH2_DEV_MAJOR = 49, - TOMOYO_PATH2_DEV_MINOR = 50, - TOMOYO_PATH1_PARENT_UID = 51, - TOMOYO_PATH1_PARENT_GID = 52, - TOMOYO_PATH1_PARENT_INO = 53, - TOMOYO_PATH1_PARENT_PERM = 54, - TOMOYO_PATH2_PARENT_UID = 55, - TOMOYO_PATH2_PARENT_GID = 56, - TOMOYO_PATH2_PARENT_INO = 57, - TOMOYO_PATH2_PARENT_PERM = 58, - TOMOYO_MAX_CONDITION_KEYWORD = 59, - TOMOYO_NUMBER_UNION = 60, - TOMOYO_NAME_UNION = 61, - TOMOYO_ARGV_ENTRY = 62, - TOMOYO_ENVP_ENTRY = 63, -}; - -enum tomoyo_path_stat_index { - TOMOYO_PATH1 = 0, - TOMOYO_PATH1_PARENT = 1, - TOMOYO_PATH2 = 2, - TOMOYO_PATH2_PARENT = 3, - TOMOYO_MAX_PATH_STAT = 4, -}; - -enum tomoyo_mode_index { - TOMOYO_CONFIG_DISABLED = 0, - TOMOYO_CONFIG_LEARNING = 1, - TOMOYO_CONFIG_PERMISSIVE = 2, - TOMOYO_CONFIG_ENFORCING = 3, - TOMOYO_CONFIG_MAX_MODE = 4, - TOMOYO_CONFIG_WANT_REJECT_LOG = 64, - TOMOYO_CONFIG_WANT_GRANT_LOG = 128, - TOMOYO_CONFIG_USE_DEFAULT = 255, -}; - -enum tomoyo_policy_id { - TOMOYO_ID_GROUP = 0, - TOMOYO_ID_ADDRESS_GROUP = 1, - TOMOYO_ID_PATH_GROUP = 2, - TOMOYO_ID_NUMBER_GROUP = 3, - TOMOYO_ID_TRANSITION_CONTROL = 4, - TOMOYO_ID_AGGREGATOR = 5, - TOMOYO_ID_MANAGER = 6, - TOMOYO_ID_CONDITION = 7, - TOMOYO_ID_NAME = 8, - TOMOYO_ID_ACL = 9, - TOMOYO_ID_DOMAIN = 10, - TOMOYO_MAX_POLICY = 11, -}; - -enum tomoyo_domain_info_flags_index { - TOMOYO_DIF_QUOTA_WARNED = 0, - TOMOYO_DIF_TRANSITION_FAILED = 1, - TOMOYO_MAX_DOMAIN_INFO_FLAGS = 2, -}; - -enum tomoyo_grant_log { - TOMOYO_GRANTLOG_AUTO = 0, - TOMOYO_GRANTLOG_NO = 1, - TOMOYO_GRANTLOG_YES = 2, -}; - -enum tomoyo_group_id { - TOMOYO_PATH_GROUP = 0, - TOMOYO_NUMBER_GROUP = 1, - TOMOYO_ADDRESS_GROUP = 2, - TOMOYO_MAX_GROUP = 3, -}; - -enum tomoyo_path_acl_index { - TOMOYO_TYPE_EXECUTE = 0, - TOMOYO_TYPE_READ = 1, - TOMOYO_TYPE_WRITE = 2, - TOMOYO_TYPE_APPEND = 3, - TOMOYO_TYPE_UNLINK = 4, - TOMOYO_TYPE_GETATTR = 5, - TOMOYO_TYPE_RMDIR = 6, - TOMOYO_TYPE_TRUNCATE = 7, - TOMOYO_TYPE_SYMLINK = 8, - TOMOYO_TYPE_CHROOT = 9, - TOMOYO_TYPE_UMOUNT = 10, - TOMOYO_MAX_PATH_OPERATION = 11, -}; - -enum tomoyo_memory_stat_type { - TOMOYO_MEMORY_POLICY = 0, - TOMOYO_MEMORY_AUDIT = 1, - TOMOYO_MEMORY_QUERY = 2, - TOMOYO_MAX_MEMORY_STAT = 3, -}; - -enum tomoyo_mkdev_acl_index { - TOMOYO_TYPE_MKBLOCK = 0, - TOMOYO_TYPE_MKCHAR = 1, - TOMOYO_MAX_MKDEV_OPERATION = 2, -}; - -enum tomoyo_network_acl_index { - TOMOYO_NETWORK_BIND = 0, - TOMOYO_NETWORK_LISTEN = 1, - TOMOYO_NETWORK_CONNECT = 2, - TOMOYO_NETWORK_SEND = 3, - TOMOYO_MAX_NETWORK_OPERATION = 4, -}; - -enum tomoyo_path2_acl_index { - TOMOYO_TYPE_LINK = 0, - TOMOYO_TYPE_RENAME = 1, - TOMOYO_TYPE_PIVOT_ROOT = 2, - TOMOYO_MAX_PATH2_OPERATION = 3, -}; - -enum tomoyo_path_number_acl_index { - TOMOYO_TYPE_CREATE = 0, - TOMOYO_TYPE_MKDIR = 1, - TOMOYO_TYPE_MKFIFO = 2, - TOMOYO_TYPE_MKSOCK = 3, - TOMOYO_TYPE_IOCTL = 4, - TOMOYO_TYPE_CHMOD = 5, - TOMOYO_TYPE_CHOWN = 6, - TOMOYO_TYPE_CHGRP = 7, - TOMOYO_MAX_PATH_NUMBER_OPERATION = 8, -}; - -enum tomoyo_securityfs_interface_index { - TOMOYO_DOMAINPOLICY = 0, - TOMOYO_EXCEPTIONPOLICY = 1, - TOMOYO_PROCESS_STATUS = 2, - TOMOYO_STAT = 3, - TOMOYO_AUDIT = 4, - TOMOYO_VERSION = 5, - TOMOYO_PROFILE = 6, - TOMOYO_QUERY = 7, - TOMOYO_MANAGER = 8, -}; - -enum tomoyo_mac_index { - TOMOYO_MAC_FILE_EXECUTE = 0, - TOMOYO_MAC_FILE_OPEN = 1, - TOMOYO_MAC_FILE_CREATE = 2, - TOMOYO_MAC_FILE_UNLINK = 3, - TOMOYO_MAC_FILE_GETATTR = 4, - TOMOYO_MAC_FILE_MKDIR = 5, - TOMOYO_MAC_FILE_RMDIR = 6, - TOMOYO_MAC_FILE_MKFIFO = 7, - TOMOYO_MAC_FILE_MKSOCK = 8, - TOMOYO_MAC_FILE_TRUNCATE = 9, - TOMOYO_MAC_FILE_SYMLINK = 10, - TOMOYO_MAC_FILE_MKBLOCK = 11, - TOMOYO_MAC_FILE_MKCHAR = 12, - TOMOYO_MAC_FILE_LINK = 13, - TOMOYO_MAC_FILE_RENAME = 14, - TOMOYO_MAC_FILE_CHMOD = 15, - TOMOYO_MAC_FILE_CHOWN = 16, - TOMOYO_MAC_FILE_CHGRP = 17, - TOMOYO_MAC_FILE_IOCTL = 18, - TOMOYO_MAC_FILE_CHROOT = 19, - TOMOYO_MAC_FILE_MOUNT = 20, - TOMOYO_MAC_FILE_UMOUNT = 21, - TOMOYO_MAC_FILE_PIVOT_ROOT = 22, - TOMOYO_MAC_NETWORK_INET_STREAM_BIND = 23, - TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN = 24, - TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT = 25, - TOMOYO_MAC_NETWORK_INET_DGRAM_BIND = 26, - TOMOYO_MAC_NETWORK_INET_DGRAM_SEND = 27, - TOMOYO_MAC_NETWORK_INET_RAW_BIND = 28, - TOMOYO_MAC_NETWORK_INET_RAW_SEND = 29, - TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND = 30, - TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN = 31, - TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT = 32, - TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND = 33, - TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND = 34, - TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND = 35, - TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN = 36, - TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT = 37, - TOMOYO_MAC_ENVIRON = 38, - TOMOYO_MAX_MAC_INDEX = 39, -}; - -enum tomoyo_mac_category_index { - TOMOYO_MAC_CATEGORY_FILE = 0, - TOMOYO_MAC_CATEGORY_NETWORK = 1, - TOMOYO_MAC_CATEGORY_MISC = 2, - TOMOYO_MAX_MAC_CATEGORY_INDEX = 3, -}; - -enum tomoyo_pref_index { - TOMOYO_PREF_MAX_AUDIT_LOG = 0, - TOMOYO_PREF_MAX_LEARNING_ENTRY = 1, - TOMOYO_MAX_PREF = 2, -}; - -struct tomoyo_shared_acl_head { - struct list_head list; - atomic_t users; -} __attribute__((packed)); - -struct tomoyo_path_info { - const char *name; - u32 hash; - u16 const_len; - bool is_dir; - bool is_patterned; -}; - -struct tomoyo_obj_info; - -struct tomoyo_execve; - -struct tomoyo_domain_info; - -struct tomoyo_acl_info; - -struct tomoyo_request_info { - struct tomoyo_obj_info *obj; - struct tomoyo_execve *ee; - struct tomoyo_domain_info *domain; - union { - struct { - const struct tomoyo_path_info *filename; - const struct tomoyo_path_info *matched_path; - u8 operation; - } path; - struct { - const struct tomoyo_path_info *filename1; - const struct tomoyo_path_info *filename2; - u8 operation; - } path2; - struct { - const struct tomoyo_path_info *filename; - unsigned int mode; - unsigned int major; - unsigned int minor; - u8 operation; - } mkdev; - struct { - const struct tomoyo_path_info *filename; - long unsigned int number; - u8 operation; - } path_number; - struct { - const struct tomoyo_path_info *name; - } environ; - struct { - const __be32 *address; - u16 port; - u8 protocol; - u8 operation; - bool is_ipv6; - } inet_network; - struct { - const struct tomoyo_path_info *address; - u8 protocol; - u8 operation; - } unix_network; - struct { - const struct tomoyo_path_info *type; - const struct tomoyo_path_info *dir; - const struct tomoyo_path_info *dev; - long unsigned int flags; - int need_dev; - } mount; - struct { - const struct tomoyo_path_info *domainname; - } task; - } param; - struct tomoyo_acl_info *matched_acl; - u8 param_type; - bool granted; - u8 retry; - u8 profile; - u8 mode; - u8 type; -}; - -struct tomoyo_mini_stat { - kuid_t uid; - kgid_t gid; - ino_t ino; - umode_t mode; - dev_t dev; - dev_t rdev; -}; - -struct tomoyo_obj_info { - bool validate_done; - bool stat_valid[4]; - struct path path1; - struct path path2; - struct tomoyo_mini_stat stat[4]; - struct tomoyo_path_info *symlink_target; -}; - -struct tomoyo_page_dump { - struct page *page; - char *data; -}; - -struct tomoyo_execve { - struct tomoyo_request_info r; - struct tomoyo_obj_info obj; - struct linux_binprm *bprm; - const struct tomoyo_path_info *transition; - struct tomoyo_page_dump dump; - char *tmp; -}; - -struct tomoyo_policy_namespace; - -struct tomoyo_domain_info { - struct list_head list; - struct list_head acl_info_list; - const struct tomoyo_path_info *domainname; - struct tomoyo_policy_namespace *ns; - long unsigned int group[4]; - u8 profile; - bool is_deleted; - bool flags[2]; - atomic_t users; -}; - -struct tomoyo_condition; - -struct tomoyo_acl_info { - struct list_head list; - struct tomoyo_condition *cond; - s8 is_deleted; - u8 type; -} __attribute__((packed)); - -struct tomoyo_condition { - struct tomoyo_shared_acl_head head; - u32 size; - u16 condc; - u16 numbers_count; - u16 names_count; - u16 argc; - u16 envc; - u8 grant_log; - const struct tomoyo_path_info *transit; -}; - -struct tomoyo_profile; - -struct tomoyo_policy_namespace { - struct tomoyo_profile *profile_ptr[256]; - struct list_head group_list[3]; - struct list_head policy_list[11]; - struct list_head acl_group[256]; - struct list_head namespace_list; - unsigned int profile_version; - const char *name; -}; - -struct tomoyo_io_buffer { - void (*read)(struct tomoyo_io_buffer *); - int (*write)(struct tomoyo_io_buffer *); - __poll_t (*poll)(struct file *, poll_table *); - struct mutex io_sem; - char *read_user_buf; - size_t read_user_buf_avail; - struct { - struct list_head *ns; - struct list_head *domain; - struct list_head *group; - struct list_head *acl; - size_t avail; - unsigned int step; - unsigned int query_index; - u16 index; - u16 cond_index; - u8 acl_group_index; - u8 cond_step; - u8 bit; - u8 w_pos; - bool eof; - bool print_this_domain_only; - bool print_transition_related_only; - bool print_cond_part; - const char *w[64]; - } r; - struct { - struct tomoyo_policy_namespace *ns; - struct tomoyo_domain_info *domain; - size_t avail; - bool is_delete; - } w; - char *read_buf; - size_t readbuf_size; - char *write_buf; - size_t writebuf_size; - enum tomoyo_securityfs_interface_index type; - u8 users; - struct list_head list; -}; - -struct tomoyo_preference { - unsigned int learning_max_entry; - bool enforcing_verbose; - bool learning_verbose; - bool permissive_verbose; -}; - -struct tomoyo_profile { - const struct tomoyo_path_info *comment; - struct tomoyo_preference *learning; - struct tomoyo_preference *permissive; - struct tomoyo_preference *enforcing; - struct tomoyo_preference preference; - u8 default_config; - u8 config[42]; - unsigned int pref[2]; -}; - -struct tomoyo_time { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 min; - u8 sec; -}; - -struct tomoyo_log { - struct list_head list; - char *log; - int size; -}; - -enum tomoyo_value_type { - TOMOYO_VALUE_TYPE_INVALID = 0, - TOMOYO_VALUE_TYPE_DECIMAL = 1, - TOMOYO_VALUE_TYPE_OCTAL = 2, - TOMOYO_VALUE_TYPE_HEXADECIMAL = 3, -}; - -enum tomoyo_transition_type { - TOMOYO_TRANSITION_CONTROL_NO_RESET = 0, - TOMOYO_TRANSITION_CONTROL_RESET = 1, - TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE = 2, - TOMOYO_TRANSITION_CONTROL_INITIALIZE = 3, - TOMOYO_TRANSITION_CONTROL_NO_KEEP = 4, - TOMOYO_TRANSITION_CONTROL_KEEP = 5, - TOMOYO_MAX_TRANSITION_TYPE = 6, -}; - -enum tomoyo_acl_entry_type_index { - TOMOYO_TYPE_PATH_ACL = 0, - TOMOYO_TYPE_PATH2_ACL = 1, - TOMOYO_TYPE_PATH_NUMBER_ACL = 2, - TOMOYO_TYPE_MKDEV_ACL = 3, - TOMOYO_TYPE_MOUNT_ACL = 4, - TOMOYO_TYPE_INET_ACL = 5, - TOMOYO_TYPE_UNIX_ACL = 6, - TOMOYO_TYPE_ENV_ACL = 7, - TOMOYO_TYPE_MANUAL_TASK_ACL = 8, -}; - -enum tomoyo_policy_stat_type { - TOMOYO_STAT_POLICY_UPDATES = 0, - TOMOYO_STAT_POLICY_LEARNING = 1, - TOMOYO_STAT_POLICY_PERMISSIVE = 2, - TOMOYO_STAT_POLICY_ENFORCING = 3, - TOMOYO_MAX_POLICY_STAT = 4, -}; - -struct tomoyo_acl_head { - struct list_head list; - s8 is_deleted; -} __attribute__((packed)); - -struct tomoyo_name { - struct tomoyo_shared_acl_head head; - struct tomoyo_path_info entry; -}; - -struct tomoyo_group; - -struct tomoyo_name_union { - const struct tomoyo_path_info *filename; - struct tomoyo_group *group; -}; - -struct tomoyo_group { - struct tomoyo_shared_acl_head head; - const struct tomoyo_path_info *group_name; - struct list_head member_list; -}; - -struct tomoyo_number_union { - long unsigned int values[2]; - struct tomoyo_group *group; - u8 value_type[2]; -}; - -struct tomoyo_ipaddr_union { - struct in6_addr ip[2]; - struct tomoyo_group *group; - bool is_ipv6; -}; - -struct tomoyo_path_group { - struct tomoyo_acl_head head; - const struct tomoyo_path_info *member_name; -}; - -struct tomoyo_number_group { - struct tomoyo_acl_head head; - struct tomoyo_number_union number; -}; - -struct tomoyo_address_group { - struct tomoyo_acl_head head; - struct tomoyo_ipaddr_union address; -}; - -struct tomoyo_argv { - long unsigned int index; - const struct tomoyo_path_info *value; - bool is_not; -}; - -struct tomoyo_envp { - const struct tomoyo_path_info *name; - const struct tomoyo_path_info *value; - bool is_not; -}; - -struct tomoyo_condition_element { - u8 left; - u8 right; - bool equals; -}; - -struct tomoyo_task_acl { - struct tomoyo_acl_info head; - const struct tomoyo_path_info *domainname; -}; - -struct tomoyo_path_acl { - struct tomoyo_acl_info head; - u16 perm; - struct tomoyo_name_union name; -}; - -struct tomoyo_path_number_acl { - struct tomoyo_acl_info head; - u8 perm; - struct tomoyo_name_union name; - struct tomoyo_number_union number; -}; - -struct tomoyo_mkdev_acl { - struct tomoyo_acl_info head; - u8 perm; - struct tomoyo_name_union name; - struct tomoyo_number_union mode; - struct tomoyo_number_union major; - struct tomoyo_number_union minor; -}; - -struct tomoyo_path2_acl { - struct tomoyo_acl_info head; - u8 perm; - struct tomoyo_name_union name1; - struct tomoyo_name_union name2; -}; - -struct tomoyo_mount_acl { - struct tomoyo_acl_info head; - struct tomoyo_name_union dev_name; - struct tomoyo_name_union dir_name; - struct tomoyo_name_union fs_type; - struct tomoyo_number_union flags; -}; - -struct tomoyo_env_acl { - struct tomoyo_acl_info head; - const struct tomoyo_path_info *env; -}; - -struct tomoyo_inet_acl { - struct tomoyo_acl_info head; - u8 protocol; - u8 perm; - struct tomoyo_ipaddr_union address; - struct tomoyo_number_union port; -}; - -struct tomoyo_unix_acl { - struct tomoyo_acl_info head; - u8 protocol; - u8 perm; - struct tomoyo_name_union name; -}; - -struct tomoyo_acl_param { - char *data; - struct list_head *list; - struct tomoyo_policy_namespace *ns; - bool is_delete; -}; - -struct tomoyo_transition_control { - struct tomoyo_acl_head head; - u8 type; - bool is_last_name; - const struct tomoyo_path_info *domainname; - const struct tomoyo_path_info *program; -}; - -struct tomoyo_aggregator { - struct tomoyo_acl_head head; - const struct tomoyo_path_info *original_name; - const struct tomoyo_path_info *aggregated_name; -}; - -struct tomoyo_manager { - struct tomoyo_acl_head head; - const struct tomoyo_path_info *manager; -}; - -struct tomoyo_task { - struct tomoyo_domain_info *domain_info; - struct tomoyo_domain_info *old_domain_info; -}; - -struct tomoyo_query { - struct list_head list; - struct tomoyo_domain_info *domain; - char *query; - size_t query_len; - unsigned int serial; - u8 timer; - u8 answer; - u8 retry; -}; - -enum tomoyo_special_mount { - TOMOYO_MOUNT_BIND = 0, - TOMOYO_MOUNT_MOVE = 1, - TOMOYO_MOUNT_REMOUNT = 2, - TOMOYO_MOUNT_MAKE_UNBINDABLE = 3, - TOMOYO_MOUNT_MAKE_PRIVATE = 4, - TOMOYO_MOUNT_MAKE_SLAVE = 5, - TOMOYO_MOUNT_MAKE_SHARED = 6, - TOMOYO_MAX_SPECIAL_MOUNT = 7, -}; - -struct tomoyo_inet_addr_info { - __be16 port; - const __be32 *address; - bool is_ipv6; -}; - -struct tomoyo_unix_addr_info { - u8 *addr; - unsigned int addr_len; -}; - -struct tomoyo_addr_info { - u8 protocol; - u8 operation; - struct tomoyo_inet_addr_info inet; - struct tomoyo_unix_addr_info unix0; -}; - -typedef unsigned char Byte; - -typedef long unsigned int uLong; - -struct internal_state; - -struct z_stream_s { - const Byte *next_in; - uLong avail_in; - uLong total_in; - Byte *next_out; - uLong avail_out; - uLong total_out; - char *msg; - struct internal_state *state; - void *workspace; - int data_type; - uLong adler; - uLong reserved; -}; - -struct internal_state { - int dummy; -}; - -typedef struct z_stream_s z_stream; - -typedef z_stream *z_streamp; - -enum audit_mode { - AUDIT_NORMAL = 0, - AUDIT_QUIET_DENIED = 1, - AUDIT_QUIET = 2, - AUDIT_NOQUIET = 3, - AUDIT_ALL = 4, -}; - -enum aa_sfs_type { - AA_SFS_TYPE_BOOLEAN = 0, - AA_SFS_TYPE_STRING = 1, - AA_SFS_TYPE_U64 = 2, - AA_SFS_TYPE_FOPS = 3, - AA_SFS_TYPE_DIR = 4, -}; - -struct aa_sfs_entry { - const char *name; - struct dentry *dentry; - umode_t mode; - enum aa_sfs_type v_type; - union { - bool boolean; - char *string; - long unsigned int u64; - struct aa_sfs_entry *files; - } v; - const struct file_operations *file_ops; -}; - -enum aafs_ns_type { - AAFS_NS_DIR = 0, - AAFS_NS_PROFS = 1, - AAFS_NS_NS = 2, - AAFS_NS_RAW_DATA = 3, - AAFS_NS_LOAD = 4, - AAFS_NS_REPLACE = 5, - AAFS_NS_REMOVE = 6, - AAFS_NS_REVISION = 7, - AAFS_NS_COUNT = 8, - AAFS_NS_MAX_COUNT = 9, - AAFS_NS_SIZE = 10, - AAFS_NS_MAX_SIZE = 11, - AAFS_NS_OWNER = 12, - AAFS_NS_SIZEOF = 13, -}; - -enum aafs_prof_type { - AAFS_PROF_DIR = 0, - AAFS_PROF_PROFS = 1, - AAFS_PROF_NAME = 2, - AAFS_PROF_MODE = 3, - AAFS_PROF_ATTACH = 4, - AAFS_PROF_HASH = 5, - AAFS_PROF_RAW_DATA = 6, - AAFS_PROF_RAW_HASH = 7, - AAFS_PROF_RAW_ABI = 8, - AAFS_PROF_SIZEOF = 9, -}; - -struct table_header { - u16 td_id; - u16 td_flags; - u32 td_hilen; - u32 td_lolen; - char td_data[0]; -}; - -struct aa_dfa { - struct kref count; - u16 flags; - u32 max_oob; - struct table_header *tables[8]; -}; - -struct aa_policy { - const char *name; - char *hname; - struct list_head list; - struct list_head profiles; -}; - -struct aa_labelset { - rwlock_t lock; - struct rb_root root; -}; - -enum label_flags { - FLAG_HAT = 1, - FLAG_UNCONFINED = 2, - FLAG_NULL = 4, - FLAG_IX_ON_NAME_ERROR = 8, - FLAG_IMMUTIBLE = 16, - FLAG_USER_DEFINED = 32, - FLAG_NO_LIST_REF = 64, - FLAG_NS_COUNT = 128, - FLAG_IN_TREE = 256, - FLAG_PROFILE = 512, - FLAG_EXPLICIT = 1024, - FLAG_STALE = 2048, - FLAG_RENAMED = 4096, - FLAG_REVOKED = 8192, -}; - -struct aa_label; - -struct aa_proxy { - struct kref count; - struct aa_label *label; -}; - -struct aa_profile; - -struct aa_label { - struct kref count; - struct rb_node node; - struct callback_head rcu; - struct aa_proxy *proxy; - char *hname; - long int flags; - u32 secid; - int size; - struct aa_profile *vec[0]; -}; - -struct label_it { - int i; - int j; -}; - -struct aa_policydb { - struct aa_dfa *dfa; - unsigned int start[17]; -}; - -struct aa_domain { - int size; - char **table; -}; - -struct aa_file_rules { - unsigned int start; - struct aa_dfa *dfa; - struct aa_domain trans; -}; - -struct aa_caps { - kernel_cap_t allow; - kernel_cap_t audit; - kernel_cap_t denied; - kernel_cap_t quiet; - kernel_cap_t kill; - kernel_cap_t extended; -}; - -struct aa_rlimit { - unsigned int mask; - struct rlimit limits[16]; -}; - -struct aa_ns; - -struct aa_secmark; - -struct aa_loaddata; - -struct aa_profile { - struct aa_policy base; - struct aa_profile *parent; - struct aa_ns *ns; - const char *rename; - const char *attach; - struct aa_dfa *xmatch; - int xmatch_len; - enum audit_mode audit; - long int mode; - u32 path_flags; - const char *disconnected; - int size; - struct aa_policydb policy; - struct aa_file_rules file; - struct aa_caps caps; - int xattr_count; - char **xattrs; - struct aa_rlimit rlimits; - int secmark_count; - struct aa_secmark *secmark; - struct aa_loaddata *rawdata; - unsigned char *hash; - char *dirname; - struct dentry *dents[9]; - struct rhashtable *data; - struct aa_label label; -}; - -struct aa_perms { - u32 allow; - u32 audit; - u32 deny; - u32 quiet; - u32 kill; - u32 stop; - u32 complain; - u32 cond; - u32 hide; - u32 prompt; - u16 xindex; -}; - -struct path_cond { - kuid_t uid; - umode_t mode; -}; - -struct aa_secmark { - u8 audit; - u8 deny; - u32 secid; - char *label; -}; - -enum profile_mode { - APPARMOR_ENFORCE = 0, - APPARMOR_COMPLAIN = 1, - APPARMOR_KILL = 2, - APPARMOR_UNCONFINED = 3, -}; - -struct aa_data { - char *key; - u32 size; - char *data; - struct rhash_head head; -}; - -struct aa_ns_acct { - int max_size; - int max_count; - int size; - int count; -}; - -struct aa_ns { - struct aa_policy base; - struct aa_ns *parent; - struct mutex lock; - struct aa_ns_acct acct; - struct aa_profile *unconfined; - struct list_head sub_ns; - atomic_t uniq_null; - long int uniq_id; - int level; - long int revision; - wait_queue_head_t wait; - struct aa_labelset labels; - struct list_head rawdata_list; - struct dentry *dents[13]; -}; - -struct aa_loaddata { - struct kref count; - struct list_head list; - struct work_struct work; - struct dentry *dents[6]; - struct aa_ns *ns; - char *name; - size_t size; - size_t compressed_size; - long int revision; - int abi; - unsigned char *hash; - char *data; -}; - -enum { - AAFS_LOADDATA_ABI = 0, - AAFS_LOADDATA_REVISION = 1, - AAFS_LOADDATA_HASH = 2, - AAFS_LOADDATA_DATA = 3, - AAFS_LOADDATA_COMPRESSED_SIZE = 4, - AAFS_LOADDATA_DIR = 5, - AAFS_LOADDATA_NDENTS = 6, -}; - -struct rawdata_f_data { - struct aa_loaddata *loaddata; -}; - -struct aa_revision { - struct aa_ns *ns; - long int last_read; -}; - -struct multi_transaction { - struct kref count; - ssize_t size; - char data[0]; -}; - -struct apparmor_audit_data { - int error; - int type; - const char *op; - struct aa_label *label; - const char *name; - const char *info; - u32 request; - u32 denied; - union { - struct { - struct aa_label *peer; - union { - struct { - const char *target; - kuid_t ouid; - } fs; - struct { - int rlim; - long unsigned int max; - } rlim; - struct { - int signal; - int unmappedsig; - }; - struct { - int type; - int protocol; - struct sock *peer_sk; - void *addr; - int addrlen; - } net; - }; - }; - struct { - struct aa_profile *profile; - const char *ns; - long int pos; - } iface; - struct { - const char *src_name; - const char *type; - const char *trans; - const char *data; - long unsigned int flags; - } mnt; - }; -}; - -enum audit_type { - AUDIT_APPARMOR_AUDIT = 0, - AUDIT_APPARMOR_ALLOWED = 1, - AUDIT_APPARMOR_DENIED = 2, - AUDIT_APPARMOR_HINT = 3, - AUDIT_APPARMOR_STATUS = 4, - AUDIT_APPARMOR_ERROR = 5, - AUDIT_APPARMOR_KILL = 6, - AUDIT_APPARMOR_AUTO = 7, -}; - -struct aa_audit_rule { - struct aa_label *label; -}; - -struct audit_cache { - struct aa_profile *profile; - kernel_cap_t caps; -}; - -struct aa_task_ctx { - struct aa_label *nnp; - struct aa_label *onexec; - struct aa_label *previous; - u64 token; -}; - -struct counted_str { - struct kref count; - char name[0]; -}; - -struct match_workbuf { - unsigned int count; - unsigned int pos; - unsigned int len; - unsigned int size; - unsigned int history[24]; -}; - -enum path_flags { - PATH_IS_DIR = 1, - PATH_CONNECT_PATH = 4, - PATH_CHROOT_REL = 8, - PATH_CHROOT_NSCONNECT = 16, - PATH_DELEGATE_DELETED = 32768, - PATH_MEDIATE_DELETED = 65536, -}; - -struct aa_load_ent { - struct list_head list; - struct aa_profile *new; - struct aa_profile *old; - struct aa_profile *rename; - const char *ns_name; -}; - -enum aa_code { - AA_U8 = 0, - AA_U16 = 1, - AA_U32 = 2, - AA_U64 = 3, - AA_NAME = 4, - AA_STRING = 5, - AA_BLOB = 6, - AA_STRUCT = 7, - AA_STRUCTEND = 8, - AA_LIST = 9, - AA_LISTEND = 10, - AA_ARRAY = 11, - AA_ARRAYEND = 12, -}; - -struct aa_ext { - void *start; - void *end; - void *pos; - u32 version; -}; - -struct aa_file_ctx { - spinlock_t lock; - struct aa_label *label; - u32 allow; -}; - -struct aa_sk_ctx { - struct aa_label *label; - struct aa_label *peer; -}; - -union aa_buffer { - struct list_head list; - char buffer[1]; -}; - -struct ptrace_relation { - struct task_struct *tracer; - struct task_struct *tracee; - bool invalid; - struct list_head node; - struct callback_head rcu; -}; - -struct access_report_info { - struct callback_head work; - const char *access; - struct task_struct *target; - struct task_struct *agent; -}; - -enum sid_policy_type { - SIDPOL_DEFAULT = 0, - SIDPOL_CONSTRAINED = 1, - SIDPOL_ALLOWED = 2, -}; - -typedef union { - kuid_t uid; - kgid_t gid; -} kid_t; - -enum setid_type { - UID = 0, - GID = 1, -}; - -struct setid_rule { - struct hlist_node next; - kid_t src_id; - kid_t dst_id; - enum setid_type type; -}; - -struct setid_ruleset { - struct hlist_head rules[256]; - char *policy_str; - struct callback_head rcu; - enum setid_type type; -}; - -enum devcg_behavior { - DEVCG_DEFAULT_NONE = 0, - DEVCG_DEFAULT_ALLOW = 1, - DEVCG_DEFAULT_DENY = 2, -}; - -struct dev_exception_item { - u32 major; - u32 minor; - short int type; - short int access; - struct list_head list; - struct callback_head rcu; -}; - -struct dev_cgroup { - struct cgroup_subsys_state css; - struct list_head exceptions; - enum devcg_behavior behavior; -}; - -struct landlock_ruleset_attr { - __u64 handled_access_fs; -}; - -enum landlock_rule_type { - LANDLOCK_RULE_PATH_BENEATH = 1, -}; - -struct landlock_path_beneath_attr { - __u64 allowed_access; - __s32 parent_fd; -} __attribute__((packed)); - -struct landlock_hierarchy { - struct landlock_hierarchy *parent; - refcount_t usage; -}; - -struct landlock_ruleset { - struct rb_root root; - struct landlock_hierarchy *hierarchy; - union { - struct work_struct work_free; - struct { - struct mutex lock; - refcount_t usage; - u32 num_rules; - u32 num_layers; - u16 fs_access_masks[0]; - }; - }; -}; - -struct landlock_cred_security { - struct landlock_ruleset *domain; -}; - -struct landlock_object; - -struct landlock_object_underops { - void (*release)(struct landlock_object * const); -}; - -struct landlock_object { - refcount_t usage; - spinlock_t lock; - void *underobj; - union { - struct callback_head rcu_free; - const struct landlock_object_underops *underops; - }; -}; - -struct landlock_layer { - u16 level; - u16 access; -}; - -struct landlock_rule { - struct rb_node node; - struct landlock_object *object; - u32 num_layers; - struct landlock_layer layers[0]; -}; - -struct landlock_inode_security { - struct landlock_object *object; -}; - -struct landlock_superblock_security { - atomic_long_t inode_refs; -}; - -enum { - CRYPTO_MSG_ALG_REQUEST = 0, - CRYPTO_MSG_ALG_REGISTER = 1, - CRYPTO_MSG_ALG_LOADED = 2, -}; - -struct crypto_larval { - struct crypto_alg alg; - struct crypto_alg *adult; - struct completion completion; - u32 mask; -}; - -struct crypto_cipher { - struct crypto_tfm base; -}; - -struct rtattr { - short unsigned int rta_len; - short unsigned int rta_type; -}; - -struct crypto_queue { - struct list_head list; - struct list_head *backlog; - unsigned int qlen; - unsigned int max_qlen; -}; - -struct crypto_attr_alg { - char name[128]; -}; - -struct crypto_attr_type { - u32 type; - u32 mask; -}; - -enum { - NAPI_STATE_SCHED = 0, - NAPI_STATE_MISSED = 1, - NAPI_STATE_DISABLE = 2, - NAPI_STATE_NPSVC = 3, - NAPI_STATE_LISTED = 4, - NAPI_STATE_NO_BUSY_POLL = 5, - NAPI_STATE_IN_BUSY_POLL = 6, - NAPI_STATE_PREFER_BUSY_POLL = 7, - NAPI_STATE_THREADED = 8, - NAPI_STATE_SCHED_THREADED = 9, -}; - -enum xps_map_type { - XPS_CPUS = 0, - XPS_RXQS = 1, - XPS_MAPS_MAX = 2, -}; - -enum bpf_xdp_mode { - XDP_MODE_SKB = 0, - XDP_MODE_DRV = 1, - XDP_MODE_HW = 2, - __MAX_XDP_MODE = 3, -}; - -enum { - NETIF_MSG_DRV_BIT = 0, - NETIF_MSG_PROBE_BIT = 1, - NETIF_MSG_LINK_BIT = 2, - NETIF_MSG_TIMER_BIT = 3, - NETIF_MSG_IFDOWN_BIT = 4, - NETIF_MSG_IFUP_BIT = 5, - NETIF_MSG_RX_ERR_BIT = 6, - NETIF_MSG_TX_ERR_BIT = 7, - NETIF_MSG_TX_QUEUED_BIT = 8, - NETIF_MSG_INTR_BIT = 9, - NETIF_MSG_TX_DONE_BIT = 10, - NETIF_MSG_RX_STATUS_BIT = 11, - NETIF_MSG_PKTDATA_BIT = 12, - NETIF_MSG_HW_BIT = 13, - NETIF_MSG_WOL_BIT = 14, - NETIF_MSG_CLASS_COUNT = 15, -}; - -enum { - CRYPTOA_UNSPEC = 0, - CRYPTOA_ALG = 1, - CRYPTOA_TYPE = 2, - __CRYPTOA_MAX = 3, -}; - -struct scatter_walk { - struct scatterlist *sg; - unsigned int offset; -}; - -struct aead_request { - struct crypto_async_request base; - unsigned int assoclen; - unsigned int cryptlen; - u8 *iv; - struct scatterlist *src; - struct scatterlist *dst; - void *__ctx[0]; -}; - -struct crypto_aead; - -struct aead_alg { - int (*setkey)(struct crypto_aead *, const u8 *, unsigned int); - int (*setauthsize)(struct crypto_aead *, unsigned int); - int (*encrypt)(struct aead_request *); - int (*decrypt)(struct aead_request *); - int (*init)(struct crypto_aead *); - void (*exit)(struct crypto_aead *); - unsigned int ivsize; - unsigned int maxauthsize; - unsigned int chunksize; - struct crypto_alg base; -}; - -struct crypto_aead { - unsigned int authsize; - unsigned int reqsize; - struct crypto_tfm base; -}; - -struct aead_instance { - void (*free)(struct aead_instance *); - union { - struct { - char head[64]; - struct crypto_instance base; - } s; - struct aead_alg alg; - }; -}; - -struct crypto_aead_spawn { - struct crypto_spawn base; -}; - -enum crypto_attr_type_t { - CRYPTOCFGA_UNSPEC = 0, - CRYPTOCFGA_PRIORITY_VAL = 1, - CRYPTOCFGA_REPORT_LARVAL = 2, - CRYPTOCFGA_REPORT_HASH = 3, - CRYPTOCFGA_REPORT_BLKCIPHER = 4, - CRYPTOCFGA_REPORT_AEAD = 5, - CRYPTOCFGA_REPORT_COMPRESS = 6, - CRYPTOCFGA_REPORT_RNG = 7, - CRYPTOCFGA_REPORT_CIPHER = 8, - CRYPTOCFGA_REPORT_AKCIPHER = 9, - CRYPTOCFGA_REPORT_KPP = 10, - CRYPTOCFGA_REPORT_ACOMP = 11, - CRYPTOCFGA_STAT_LARVAL = 12, - CRYPTOCFGA_STAT_HASH = 13, - CRYPTOCFGA_STAT_BLKCIPHER = 14, - CRYPTOCFGA_STAT_AEAD = 15, - CRYPTOCFGA_STAT_COMPRESS = 16, - CRYPTOCFGA_STAT_RNG = 17, - CRYPTOCFGA_STAT_CIPHER = 18, - CRYPTOCFGA_STAT_AKCIPHER = 19, - CRYPTOCFGA_STAT_KPP = 20, - CRYPTOCFGA_STAT_ACOMP = 21, - __CRYPTOCFGA_MAX = 22, -}; - -struct crypto_report_aead { - char type[64]; - char geniv[64]; - unsigned int blocksize; - unsigned int maxauthsize; - unsigned int ivsize; -}; - -struct crypto_sync_skcipher; - -struct aead_geniv_ctx { - spinlock_t lock; - struct crypto_aead *child; - struct crypto_sync_skcipher *sknull; - u8 salt[0]; -}; - -struct crypto_rng; - -struct rng_alg { - int (*generate)(struct crypto_rng *, const u8 *, unsigned int, u8 *, unsigned int); - int (*seed)(struct crypto_rng *, const u8 *, unsigned int); - void (*set_ent)(struct crypto_rng *, const u8 *, unsigned int); - unsigned int seedsize; - struct crypto_alg base; -}; - -struct crypto_rng { - struct crypto_tfm base; -}; - -struct crypto_cipher_spawn { - struct crypto_spawn base; -}; - -struct crypto_sync_skcipher___2 { - struct crypto_skcipher base; -}; - -struct skcipher_instance { - void (*free)(struct skcipher_instance *); - union { - struct { - char head[64]; - struct crypto_instance base; - } s; - struct skcipher_alg alg; - }; -}; - -struct crypto_skcipher_spawn { - struct crypto_spawn base; -}; - -struct skcipher_walk { - union { - struct { - struct page *page; - long unsigned int offset; - } phys; - struct { - u8 *page; - void *addr; - } virt; - } src; - union { - struct { - struct page *page; - long unsigned int offset; - } phys; - struct { - u8 *page; - void *addr; - } virt; - } dst; - struct scatter_walk in; - unsigned int nbytes; - struct scatter_walk out; - unsigned int total; - struct list_head buffers; - u8 *page; - u8 *buffer; - u8 *oiv; - void *iv; - unsigned int ivsize; - int flags; - unsigned int blocksize; - unsigned int stride; - unsigned int alignmask; -}; - -struct skcipher_ctx_simple { - struct crypto_cipher *cipher; -}; - -struct crypto_report_blkcipher { - char type[64]; - char geniv[64]; - unsigned int blocksize; - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; -}; - -enum { - SKCIPHER_WALK_PHYS = 1, - SKCIPHER_WALK_SLOW = 2, - SKCIPHER_WALK_COPY = 4, - SKCIPHER_WALK_DIFF = 8, - SKCIPHER_WALK_SLEEP = 16, -}; - -struct skcipher_walk_buffer { - struct list_head entry; - struct scatter_walk dst; - unsigned int len; - u8 *data; - u8 buffer[0]; -}; - -struct ahash_alg { - int (*init)(struct ahash_request *); - int (*update)(struct ahash_request *); - int (*final)(struct ahash_request *); - int (*finup)(struct ahash_request *); - int (*digest)(struct ahash_request *); - int (*export)(struct ahash_request *, void *); - int (*import)(struct ahash_request *, const void *); - int (*setkey)(struct crypto_ahash *, const u8 *, unsigned int); - int (*init_tfm)(struct crypto_ahash *); - void (*exit_tfm)(struct crypto_ahash *); - struct hash_alg_common halg; -}; - -struct crypto_hash_walk { - char *data; - unsigned int offset; - unsigned int alignmask; - struct page *pg; - unsigned int entrylen; - unsigned int total; - struct scatterlist *sg; - unsigned int flags; -}; - -struct ahash_instance { - void (*free)(struct ahash_instance *); - union { - struct { - char head[88]; - struct crypto_instance base; - } s; - struct ahash_alg alg; - }; -}; - -struct crypto_ahash_spawn { - struct crypto_spawn base; -}; - -struct crypto_report_hash { - char type[64]; - unsigned int blocksize; - unsigned int digestsize; -}; - -struct ahash_request_priv { - crypto_completion_t complete; - void *data; - u8 *result; - u32 flags; - void *ubuf[0]; -}; - -struct shash_instance { - void (*free)(struct shash_instance *); - union { - struct { - char head[96]; - struct crypto_instance base; - } s; - struct shash_alg alg; - }; -}; - -struct crypto_shash_spawn { - struct crypto_spawn base; -}; - -struct crypto_report_akcipher { - char type[64]; -}; - -struct akcipher_request { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int src_len; - unsigned int dst_len; - void *__ctx[0]; -}; - -struct crypto_akcipher { - struct crypto_tfm base; -}; - -struct akcipher_alg { - int (*sign)(struct akcipher_request *); - int (*verify)(struct akcipher_request *); - int (*encrypt)(struct akcipher_request *); - int (*decrypt)(struct akcipher_request *); - int (*set_pub_key)(struct crypto_akcipher *, const void *, unsigned int); - int (*set_priv_key)(struct crypto_akcipher *, const void *, unsigned int); - unsigned int (*max_size)(struct crypto_akcipher *); - int (*init)(struct crypto_akcipher *); - void (*exit)(struct crypto_akcipher *); - unsigned int reqsize; - struct crypto_alg base; -}; - -struct akcipher_instance { - void (*free)(struct akcipher_instance *); - union { - struct { - char head[80]; - struct crypto_instance base; - } s; - struct akcipher_alg alg; - }; -}; - -struct crypto_akcipher_spawn { - struct crypto_spawn base; -}; - -struct crypto_report_kpp { - char type[64]; -}; - -typedef long unsigned int mpi_limb_t; - -struct gcry_mpi { - int alloced; - int nlimbs; - int nbits; - int sign; - unsigned int flags; - mpi_limb_t *d; -}; - -typedef struct gcry_mpi *MPI; - -struct dh_ctx { - MPI p; - MPI q; - MPI g; - MPI xa; -}; - -enum { - CRYPTO_KPP_SECRET_TYPE_UNKNOWN = 0, - CRYPTO_KPP_SECRET_TYPE_DH = 1, - CRYPTO_KPP_SECRET_TYPE_ECDH = 2, -}; - -struct kpp_secret { - short unsigned int type; - short unsigned int len; -}; - -enum asn1_class { - ASN1_UNIV = 0, - ASN1_APPL = 1, - ASN1_CONT = 2, - ASN1_PRIV = 3, -}; - -enum asn1_method { - ASN1_PRIM = 0, - ASN1_CONS = 1, -}; - -enum asn1_tag { - ASN1_EOC = 0, - ASN1_BOOL = 1, - ASN1_INT = 2, - ASN1_BTS = 3, - ASN1_OTS = 4, - ASN1_NULL = 5, - ASN1_OID = 6, - ASN1_ODE = 7, - ASN1_EXT = 8, - ASN1_REAL = 9, - ASN1_ENUM = 10, - ASN1_EPDV = 11, - ASN1_UTF8STR = 12, - ASN1_RELOID = 13, - ASN1_SEQ = 16, - ASN1_SET = 17, - ASN1_NUMSTR = 18, - ASN1_PRNSTR = 19, - ASN1_TEXSTR = 20, - ASN1_VIDSTR = 21, - ASN1_IA5STR = 22, - ASN1_UNITIM = 23, - ASN1_GENTIM = 24, - ASN1_GRASTR = 25, - ASN1_VISSTR = 26, - ASN1_GENSTR = 27, - ASN1_UNISTR = 28, - ASN1_CHRSTR = 29, - ASN1_BMPSTR = 30, - ASN1_LONG_TAG = 31, -}; - -typedef int (*asn1_action_t)(void *, size_t, unsigned char, const void *, size_t); - -struct asn1_decoder { - const unsigned char *machine; - size_t machlen; - const asn1_action_t *actions; -}; - -enum asn1_opcode { - ASN1_OP_MATCH = 0, - ASN1_OP_MATCH_OR_SKIP = 1, - ASN1_OP_MATCH_ACT = 2, - ASN1_OP_MATCH_ACT_OR_SKIP = 3, - ASN1_OP_MATCH_JUMP = 4, - ASN1_OP_MATCH_JUMP_OR_SKIP = 5, - ASN1_OP_MATCH_ANY = 8, - ASN1_OP_MATCH_ANY_OR_SKIP = 9, - ASN1_OP_MATCH_ANY_ACT = 10, - ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 11, - ASN1_OP_COND_MATCH_OR_SKIP = 17, - ASN1_OP_COND_MATCH_ACT_OR_SKIP = 19, - ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 21, - ASN1_OP_COND_MATCH_ANY = 24, - ASN1_OP_COND_MATCH_ANY_OR_SKIP = 25, - ASN1_OP_COND_MATCH_ANY_ACT = 26, - ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 27, - ASN1_OP_COND_FAIL = 28, - ASN1_OP_COMPLETE = 29, - ASN1_OP_ACT = 30, - ASN1_OP_MAYBE_ACT = 31, - ASN1_OP_END_SEQ = 32, - ASN1_OP_END_SET = 33, - ASN1_OP_END_SEQ_OF = 34, - ASN1_OP_END_SET_OF = 35, - ASN1_OP_END_SEQ_ACT = 36, - ASN1_OP_END_SET_ACT = 37, - ASN1_OP_END_SEQ_OF_ACT = 38, - ASN1_OP_END_SET_OF_ACT = 39, - ASN1_OP_RETURN = 40, - ASN1_OP__NR = 41, -}; - -enum rsapubkey_actions { - ACT_rsa_get_e = 0, - ACT_rsa_get_n = 1, - NR__rsapubkey_actions = 2, -}; - -enum rsaprivkey_actions { - ACT_rsa_get_d = 0, - ACT_rsa_get_dp = 1, - ACT_rsa_get_dq = 2, - ACT_rsa_get_e___2 = 3, - ACT_rsa_get_n___2 = 4, - ACT_rsa_get_p = 5, - ACT_rsa_get_q = 6, - ACT_rsa_get_qinv = 7, - NR__rsaprivkey_actions = 8, -}; - -struct rsa_key { - const u8 *n; - const u8 *e; - const u8 *d; - const u8 *p; - const u8 *q; - const u8 *dp; - const u8 *dq; - const u8 *qinv; - size_t n_sz; - size_t e_sz; - size_t d_sz; - size_t p_sz; - size_t q_sz; - size_t dp_sz; - size_t dq_sz; - size_t qinv_sz; -}; - -struct rsa_mpi_key { - MPI n; - MPI e; - MPI d; -}; - -struct asn1_decoder___2; - -struct rsa_asn1_template { - const char *name; - const u8 *data; - size_t size; -}; - -struct pkcs1pad_ctx { - struct crypto_akcipher *child; - unsigned int key_size; -}; - -struct pkcs1pad_inst_ctx { - struct crypto_akcipher_spawn spawn; - const struct rsa_asn1_template *digest_info; -}; - -struct pkcs1pad_request { - struct scatterlist in_sg[2]; - struct scatterlist out_sg[1]; - uint8_t *in_buf; - uint8_t *out_buf; - struct akcipher_request child_req; -}; - -struct crypto_report_acomp { - char type[64]; -}; - -struct acomp_alg { - int (*compress)(struct acomp_req *); - int (*decompress)(struct acomp_req *); - void (*dst_free)(struct scatterlist *); - int (*init)(struct crypto_acomp *); - void (*exit)(struct crypto_acomp *); - unsigned int reqsize; - struct crypto_alg base; -}; - -struct crypto_report_comp { - char type[64]; -}; - -struct crypto_scomp { - struct crypto_tfm base; -}; - -struct scomp_alg { - void * (*alloc_ctx)(struct crypto_scomp *); - void (*free_ctx)(struct crypto_scomp *, void *); - int (*compress)(struct crypto_scomp *, const u8 *, unsigned int, u8 *, unsigned int *, void *); - int (*decompress)(struct crypto_scomp *, const u8 *, unsigned int, u8 *, unsigned int *, void *); - struct crypto_alg base; -}; - -struct scomp_scratch { - spinlock_t lock; - void *src; - void *dst; -}; - -struct cryptomgr_param { - struct rtattr *tb[34]; - struct { - struct rtattr attr; - struct crypto_attr_type data; - } type; - struct { - struct rtattr attr; - struct crypto_attr_alg data; - } attrs[32]; - char template[128]; - struct crypto_larval *larval; - u32 otype; - u32 omask; -}; - -struct crypto_test_param { - char driver[128]; - char alg[128]; - u32 type; -}; - -struct hmac_ctx { - struct crypto_shash *hash; -}; - -struct md5_state { - u32 hash[4]; - u32 block[16]; - u64 byte_count; -}; - -struct sha1_state { - u32 state[5]; - u64 count; - u8 buffer[64]; -}; - -typedef void sha1_block_fn(struct sha1_state *, const u8 *, int); - -struct sha256_state { - u32 state[8]; - u64 count; - u8 buf[64]; -}; - -struct sha512_state { - u64 state[8]; - u64 count[2]; - u8 buf[128]; -}; - -typedef void sha512_block_fn(struct sha512_state *, const u8 *, int); - -struct crypto_rfc3686_ctx { - struct crypto_skcipher *child; - u8 nonce[4]; -}; - -struct crypto_rfc3686_req_ctx { - u8 iv[16]; - struct skcipher_request subreq; -}; - -struct crypto_aes_ctx { - u32 key_enc[60]; - u32 key_dec[60]; - u32 key_length; -}; - -struct chksum_desc_ctx { - __u16 crc; -}; - -struct lz4_ctx { - void *lz4_comp_mem; -}; - -struct crypto_report_rng { - char type[64]; - unsigned int seedsize; -}; - -struct rand_data { - __u64 data; - __u64 old_data; - __u64 prev_time; - __u64 last_delta; - __s64 last_delta2; - unsigned int osr; - unsigned char *mem; - unsigned int memlocation; - unsigned int memblocks; - unsigned int memblocksize; - unsigned int memaccessloops; - int rct_count; - unsigned int apt_observations; - unsigned int apt_count; - unsigned int apt_base; - unsigned int apt_base_set: 1; - unsigned int health_failure: 1; -}; - -struct rand_data___2; - -struct jitterentropy { - spinlock_t jent_lock; - struct rand_data___2 *entropy_collector; - unsigned int reset_cnt; -}; - -typedef enum { - ZSTD_fast = 0, - ZSTD_dfast = 1, - ZSTD_greedy = 2, - ZSTD_lazy = 3, - ZSTD_lazy2 = 4, - ZSTD_btlazy2 = 5, - ZSTD_btopt = 6, - ZSTD_btopt2 = 7, -} ZSTD_strategy; - -typedef struct { - unsigned int windowLog; - unsigned int chainLog; - unsigned int hashLog; - unsigned int searchLog; - unsigned int searchLength; - unsigned int targetLength; - ZSTD_strategy strategy; -} ZSTD_compressionParameters; - -typedef struct { - unsigned int contentSizeFlag; - unsigned int checksumFlag; - unsigned int noDictIDFlag; -} ZSTD_frameParameters; - -typedef struct { - ZSTD_compressionParameters cParams; - ZSTD_frameParameters fParams; -} ZSTD_parameters; - -struct ZSTD_CCtx_s; - -typedef struct ZSTD_CCtx_s ZSTD_CCtx; - -struct ZSTD_DCtx_s; - -typedef struct ZSTD_DCtx_s ZSTD_DCtx; - -struct zstd_ctx { - ZSTD_CCtx *cctx; - ZSTD_DCtx *dctx; - void *cwksp; - void *dwksp; -}; - -enum asymmetric_payload_bits { - asym_crypto = 0, - asym_subtype = 1, - asym_key_ids = 2, - asym_auth = 3, -}; - -struct asymmetric_key_id { - short unsigned int len; - unsigned char data[0]; -}; - -struct asymmetric_key_ids { - void *id[2]; -}; - -struct public_key_signature; - -struct asymmetric_key_subtype { - struct module *owner; - const char *name; - short unsigned int name_len; - void (*describe)(const struct key *, struct seq_file *); - void (*destroy)(void *, void *); - int (*query)(const struct kernel_pkey_params *, struct kernel_pkey_query *); - int (*eds_op)(struct kernel_pkey_params *, const void *, void *); - int (*verify_signature)(const struct key *, const struct public_key_signature *); -}; - -struct public_key_signature { - struct asymmetric_key_id *auth_ids[2]; - u8 *s; - u32 s_size; - u8 *digest; - u8 digest_size; - const char *pkey_algo; - const char *hash_algo; - const char *encoding; - const void *data; - unsigned int data_size; -}; - -struct asymmetric_key_parser { - struct list_head link; - struct module *owner; - const char *name; - int (*parse)(struct key_preparsed_payload *); -}; - -enum OID { - OID_id_dsa_with_sha1 = 0, - OID_id_dsa = 1, - OID_id_ecPublicKey = 2, - OID_id_prime192v1 = 3, - OID_id_prime256v1 = 4, - OID_id_ecdsa_with_sha1 = 5, - OID_id_ecdsa_with_sha224 = 6, - OID_id_ecdsa_with_sha256 = 7, - OID_id_ecdsa_with_sha384 = 8, - OID_id_ecdsa_with_sha512 = 9, - OID_rsaEncryption = 10, - OID_md2WithRSAEncryption = 11, - OID_md3WithRSAEncryption = 12, - OID_md4WithRSAEncryption = 13, - OID_sha1WithRSAEncryption = 14, - OID_sha256WithRSAEncryption = 15, - OID_sha384WithRSAEncryption = 16, - OID_sha512WithRSAEncryption = 17, - OID_sha224WithRSAEncryption = 18, - OID_data = 19, - OID_signed_data = 20, - OID_email_address = 21, - OID_contentType = 22, - OID_messageDigest = 23, - OID_signingTime = 24, - OID_smimeCapabilites = 25, - OID_smimeAuthenticatedAttrs = 26, - OID_md2 = 27, - OID_md4 = 28, - OID_md5 = 29, - OID_mskrb5 = 30, - OID_krb5 = 31, - OID_krb5u2u = 32, - OID_msIndirectData = 33, - OID_msStatementType = 34, - OID_msSpOpusInfo = 35, - OID_msPeImageDataObjId = 36, - OID_msIndividualSPKeyPurpose = 37, - OID_msOutlookExpress = 38, - OID_ntlmssp = 39, - OID_spnego = 40, - OID_certAuthInfoAccess = 41, - OID_sha1 = 42, - OID_id_ansip384r1 = 43, - OID_sha256 = 44, - OID_sha384 = 45, - OID_sha512 = 46, - OID_sha224 = 47, - OID_commonName = 48, - OID_surname = 49, - OID_countryName = 50, - OID_locality = 51, - OID_stateOrProvinceName = 52, - OID_organizationName = 53, - OID_organizationUnitName = 54, - OID_title = 55, - OID_description = 56, - OID_name = 57, - OID_givenName = 58, - OID_initials = 59, - OID_generationalQualifier = 60, - OID_subjectKeyIdentifier = 61, - OID_keyUsage = 62, - OID_subjectAltName = 63, - OID_issuerAltName = 64, - OID_basicConstraints = 65, - OID_crlDistributionPoints = 66, - OID_certPolicies = 67, - OID_authorityKeyIdentifier = 68, - OID_extKeyUsage = 69, - OID_gostCPSignA = 70, - OID_gostCPSignB = 71, - OID_gostCPSignC = 72, - OID_gost2012PKey256 = 73, - OID_gost2012PKey512 = 74, - OID_gost2012Digest256 = 75, - OID_gost2012Digest512 = 76, - OID_gost2012Signature256 = 77, - OID_gost2012Signature512 = 78, - OID_gostTC26Sign256A = 79, - OID_gostTC26Sign256B = 80, - OID_gostTC26Sign256C = 81, - OID_gostTC26Sign256D = 82, - OID_gostTC26Sign512A = 83, - OID_gostTC26Sign512B = 84, - OID_gostTC26Sign512C = 85, - OID_sm2 = 86, - OID_sm3 = 87, - OID_SM2_with_SM3 = 88, - OID_sm3WithRSAEncryption = 89, - OID_TPMLoadableKey = 90, - OID_TPMImportableKey = 91, - OID_TPMSealedData = 92, - OID__NR = 93, -}; - -struct public_key { - void *key; - u32 keylen; - enum OID algo; - void *params; - u32 paramlen; - bool key_is_private; - const char *id_type; - const char *pkey_algo; -}; - -enum x509_actions { - ACT_x509_extract_key_data = 0, - ACT_x509_extract_name_segment = 1, - ACT_x509_note_OID = 2, - ACT_x509_note_issuer = 3, - ACT_x509_note_not_after = 4, - ACT_x509_note_not_before = 5, - ACT_x509_note_params = 6, - ACT_x509_note_pkey_algo = 7, - ACT_x509_note_serial = 8, - ACT_x509_note_signature = 9, - ACT_x509_note_subject = 10, - ACT_x509_note_tbs_certificate = 11, - ACT_x509_process_extension = 12, - NR__x509_actions = 13, -}; - -enum x509_akid_actions { - ACT_x509_akid_note_kid = 0, - ACT_x509_akid_note_name = 1, - ACT_x509_akid_note_serial = 2, - ACT_x509_extract_name_segment___2 = 3, - ACT_x509_note_OID___2 = 4, - NR__x509_akid_actions = 5, -}; - -struct x509_certificate { - struct x509_certificate *next; - struct x509_certificate *signer; - struct public_key *pub; - struct public_key_signature *sig; - char *issuer; - char *subject; - struct asymmetric_key_id *id; - struct asymmetric_key_id *skid; - time64_t valid_from; - time64_t valid_to; - const void *tbs; - unsigned int tbs_size; - unsigned int raw_sig_size; - const void *raw_sig; - const void *raw_serial; - unsigned int raw_serial_size; - unsigned int raw_issuer_size; - const void *raw_issuer; - const void *raw_subject; - unsigned int raw_subject_size; - unsigned int raw_skid_size; - const void *raw_skid; - unsigned int index; - bool seen; - bool verified; - bool self_signed; - bool unsupported_key; - bool unsupported_sig; - bool blacklisted; -}; - -struct x509_parse_context { - struct x509_certificate *cert; - long unsigned int data; - const void *cert_start; - const void *key; - size_t key_size; - const void *params; - size_t params_size; - enum OID key_algo; - enum OID last_oid; - enum OID algo_oid; - unsigned char nr_mpi; - u8 o_size; - u8 cn_size; - u8 email_size; - u16 o_offset; - u16 cn_offset; - u16 email_offset; - unsigned int raw_akid_size; - const void *raw_akid; - const void *akid_raw_issuer; - unsigned int akid_raw_issuer_size; -}; - -enum pkcs7_actions { - ACT_pkcs7_check_content_type = 0, - ACT_pkcs7_extract_cert = 1, - ACT_pkcs7_note_OID = 2, - ACT_pkcs7_note_certificate_list = 3, - ACT_pkcs7_note_content = 4, - ACT_pkcs7_note_data = 5, - ACT_pkcs7_note_signed_info = 6, - ACT_pkcs7_note_signeddata_version = 7, - ACT_pkcs7_note_signerinfo_version = 8, - ACT_pkcs7_sig_note_authenticated_attr = 9, - ACT_pkcs7_sig_note_digest_algo = 10, - ACT_pkcs7_sig_note_issuer = 11, - ACT_pkcs7_sig_note_pkey_algo = 12, - ACT_pkcs7_sig_note_serial = 13, - ACT_pkcs7_sig_note_set_of_authattrs = 14, - ACT_pkcs7_sig_note_signature = 15, - ACT_pkcs7_sig_note_skid = 16, - NR__pkcs7_actions = 17, -}; - -struct pkcs7_signed_info { - struct pkcs7_signed_info *next; - struct x509_certificate *signer; - unsigned int index; - bool unsupported_crypto; - bool blacklisted; - const void *msgdigest; - unsigned int msgdigest_len; - unsigned int authattrs_len; - const void *authattrs; - long unsigned int aa_set; - time64_t signing_time; - struct public_key_signature *sig; -}; - -struct pkcs7_message___2 { - struct x509_certificate *certs; - struct x509_certificate *crl; - struct pkcs7_signed_info *signed_infos; - u8 version; - bool have_authattrs; - enum OID data_type; - size_t data_len; - size_t data_hdrlen; - const void *data; -}; - -struct pkcs7_parse_context { - struct pkcs7_message___2 *msg; - struct pkcs7_signed_info *sinfo; - struct pkcs7_signed_info **ppsinfo; - struct x509_certificate *certs; - struct x509_certificate **ppcerts; - long unsigned int data; - enum OID last_oid; - unsigned int x509_index; - unsigned int sinfo_index; - const void *raw_serial; - unsigned int raw_serial_size; - unsigned int raw_issuer_size; - const void *raw_issuer; - const void *raw_skid; - unsigned int raw_skid_size; - bool expect_skid; -}; - -enum hash_algo { - HASH_ALGO_MD4 = 0, - HASH_ALGO_MD5 = 1, - HASH_ALGO_SHA1 = 2, - HASH_ALGO_RIPE_MD_160 = 3, - HASH_ALGO_SHA256 = 4, - HASH_ALGO_SHA384 = 5, - HASH_ALGO_SHA512 = 6, - HASH_ALGO_SHA224 = 7, - HASH_ALGO_RIPE_MD_128 = 8, - HASH_ALGO_RIPE_MD_256 = 9, - HASH_ALGO_RIPE_MD_320 = 10, - HASH_ALGO_WP_256 = 11, - HASH_ALGO_WP_384 = 12, - HASH_ALGO_WP_512 = 13, - HASH_ALGO_TGR_128 = 14, - HASH_ALGO_TGR_160 = 15, - HASH_ALGO_TGR_192 = 16, - HASH_ALGO_SM3_256 = 17, - HASH_ALGO_STREEBOG_256 = 18, - HASH_ALGO_STREEBOG_512 = 19, - HASH_ALGO__LAST = 20, -}; - -struct mz_hdr { - uint16_t magic; - uint16_t lbsize; - uint16_t blocks; - uint16_t relocs; - uint16_t hdrsize; - uint16_t min_extra_pps; - uint16_t max_extra_pps; - uint16_t ss; - uint16_t sp; - uint16_t checksum; - uint16_t ip; - uint16_t cs; - uint16_t reloc_table_offset; - uint16_t overlay_num; - uint16_t reserved0[4]; - uint16_t oem_id; - uint16_t oem_info; - uint16_t reserved1[10]; - uint32_t peaddr; - char message[0]; -}; - -struct pe_hdr { - uint32_t magic; - uint16_t machine; - uint16_t sections; - uint32_t timestamp; - uint32_t symbol_table; - uint32_t symbols; - uint16_t opt_hdr_size; - uint16_t flags; -}; - -struct pe32_opt_hdr { - uint16_t magic; - uint8_t ld_major; - uint8_t ld_minor; - uint32_t text_size; - uint32_t data_size; - uint32_t bss_size; - uint32_t entry_point; - uint32_t code_base; - uint32_t data_base; - uint32_t image_base; - uint32_t section_align; - uint32_t file_align; - uint16_t os_major; - uint16_t os_minor; - uint16_t image_major; - uint16_t image_minor; - uint16_t subsys_major; - uint16_t subsys_minor; - uint32_t win32_version; - uint32_t image_size; - uint32_t header_size; - uint32_t csum; - uint16_t subsys; - uint16_t dll_flags; - uint32_t stack_size_req; - uint32_t stack_size; - uint32_t heap_size_req; - uint32_t heap_size; - uint32_t loader_flags; - uint32_t data_dirs; -}; - -struct pe32plus_opt_hdr { - uint16_t magic; - uint8_t ld_major; - uint8_t ld_minor; - uint32_t text_size; - uint32_t data_size; - uint32_t bss_size; - uint32_t entry_point; - uint32_t code_base; - uint64_t image_base; - uint32_t section_align; - uint32_t file_align; - uint16_t os_major; - uint16_t os_minor; - uint16_t image_major; - uint16_t image_minor; - uint16_t subsys_major; - uint16_t subsys_minor; - uint32_t win32_version; - uint32_t image_size; - uint32_t header_size; - uint32_t csum; - uint16_t subsys; - uint16_t dll_flags; - uint64_t stack_size_req; - uint64_t stack_size; - uint64_t heap_size_req; - uint64_t heap_size; - uint32_t loader_flags; - uint32_t data_dirs; -}; - -struct data_dirent { - uint32_t virtual_address; - uint32_t size; -}; - -struct data_directory { - struct data_dirent exports; - struct data_dirent imports; - struct data_dirent resources; - struct data_dirent exceptions; - struct data_dirent certs; - struct data_dirent base_relocations; - struct data_dirent debug; - struct data_dirent arch; - struct data_dirent global_ptr; - struct data_dirent tls; - struct data_dirent load_config; - struct data_dirent bound_imports; - struct data_dirent import_addrs; - struct data_dirent delay_imports; - struct data_dirent clr_runtime_hdr; - struct data_dirent reserved; -}; - -struct section_header { - char name[8]; - uint32_t virtual_size; - uint32_t virtual_address; - uint32_t raw_data_size; - uint32_t data_addr; - uint32_t relocs; - uint32_t line_numbers; - uint16_t num_relocs; - uint16_t num_lin_numbers; - uint32_t flags; -}; - -struct win_certificate { - uint32_t length; - uint16_t revision; - uint16_t cert_type; -}; - -struct pefile_context { - unsigned int header_size; - unsigned int image_checksum_offset; - unsigned int cert_dirent_offset; - unsigned int n_data_dirents; - unsigned int n_sections; - unsigned int certs_size; - unsigned int sig_offset; - unsigned int sig_len; - const struct section_header *secs; - const void *digest; - unsigned int digest_len; - const char *digest_algo; -}; - -enum mscode_actions { - ACT_mscode_note_content_type = 0, - ACT_mscode_note_digest = 1, - ACT_mscode_note_digest_algo = 2, - NR__mscode_actions = 3, -}; - -enum rq_qos_id { - RQ_QOS_WBT = 0, - RQ_QOS_LATENCY = 1, - RQ_QOS_COST = 2, - RQ_QOS_IOPRIO = 3, -}; - -struct rq_qos_ops; - -struct rq_qos { - struct rq_qos_ops *ops; - struct request_queue *q; - enum rq_qos_id id; - struct rq_qos *next; - struct dentry *debugfs_dir; -}; - -enum hctx_type { - HCTX_TYPE_DEFAULT = 0, - HCTX_TYPE_READ = 1, - HCTX_TYPE_POLL = 2, - HCTX_MAX_TYPES = 3, -}; - -struct rq_qos_ops { - void (*throttle)(struct rq_qos *, struct bio *); - void (*track)(struct rq_qos *, struct request *, struct bio *); - void (*merge)(struct rq_qos *, struct request *, struct bio *); - void (*issue)(struct rq_qos *, struct request *); - void (*requeue)(struct rq_qos *, struct request *); - void (*done)(struct rq_qos *, struct request *); - void (*done_bio)(struct rq_qos *, struct bio *); - void (*cleanup)(struct rq_qos *, struct bio *); - void (*queue_depth_changed)(struct rq_qos *); - void (*exit)(struct rq_qos *); - const struct blk_mq_debugfs_attr *debugfs_attrs; -}; - -struct biovec_slab { - int nr_vecs; - char *name; - struct kmem_cache *slab; -}; - -struct bio_slab { - struct kmem_cache *slab; - unsigned int slab_ref; - unsigned int slab_size; - char name[8]; -}; - -enum { - BLK_MQ_F_SHOULD_MERGE = 1, - BLK_MQ_F_TAG_QUEUE_SHARED = 2, - BLK_MQ_F_STACKING = 4, - BLK_MQ_F_TAG_HCTX_SHARED = 8, - BLK_MQ_F_BLOCKING = 32, - BLK_MQ_F_NO_SCHED = 64, - BLK_MQ_F_ALLOC_POLICY_START_BIT = 8, - BLK_MQ_F_ALLOC_POLICY_BITS = 1, - BLK_MQ_S_STOPPED = 0, - BLK_MQ_S_TAG_ACTIVE = 1, - BLK_MQ_S_SCHED_RESTART = 2, - BLK_MQ_S_INACTIVE = 3, - BLK_MQ_MAX_DEPTH = 10240, - BLK_MQ_CPU_WORK_BATCH = 8, -}; - -enum { - WBT_RWQ_BG = 0, - WBT_RWQ_KSWAPD = 1, - WBT_RWQ_DISCARD = 2, - WBT_NUM_RWQ = 3, -}; - -struct blk_plug_cb; - -typedef void (*blk_plug_cb_fn)(struct blk_plug_cb *, bool); - -struct blk_plug_cb { - struct list_head list; - blk_plug_cb_fn callback; - void *data; -}; - -enum { - BLK_MQ_REQ_NOWAIT = 1, - BLK_MQ_REQ_RESERVED = 2, - BLK_MQ_REQ_PM = 4, -}; - -struct trace_event_raw_block_buffer { - struct trace_entry ent; - dev_t dev; - sector_t sector; - size_t size; - char __data[0]; -}; - -struct trace_event_raw_block_rq_requeue { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - char rwbs[8]; - u32 __data_loc_cmd; - char __data[0]; -}; - -struct trace_event_raw_block_rq_complete { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - int error; - char rwbs[8]; - u32 __data_loc_cmd; - char __data[0]; -}; - -struct trace_event_raw_block_rq { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - unsigned int bytes; - char rwbs[8]; - char comm[16]; - u32 __data_loc_cmd; - char __data[0]; -}; - -struct trace_event_raw_block_bio_complete { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - int error; - char rwbs[8]; - char __data[0]; -}; - -struct trace_event_raw_block_bio { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - char rwbs[8]; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_plug { - struct trace_entry ent; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_unplug { - struct trace_entry ent; - int nr_rq; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_split { - struct trace_entry ent; - dev_t dev; - sector_t sector; - sector_t new_sector; - char rwbs[8]; - char comm[16]; - char __data[0]; -}; - -struct trace_event_raw_block_bio_remap { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - dev_t old_dev; - sector_t old_sector; - char rwbs[8]; - char __data[0]; -}; - -struct trace_event_raw_block_rq_remap { - struct trace_entry ent; - dev_t dev; - sector_t sector; - unsigned int nr_sector; - dev_t old_dev; - sector_t old_sector; - unsigned int nr_bios; - char rwbs[8]; - char __data[0]; -}; - -struct trace_event_data_offsets_block_buffer {}; - -struct trace_event_data_offsets_block_rq_requeue { - u32 cmd; -}; - -struct trace_event_data_offsets_block_rq_complete { - u32 cmd; -}; - -struct trace_event_data_offsets_block_rq { - u32 cmd; -}; - -struct trace_event_data_offsets_block_bio_complete {}; - -struct trace_event_data_offsets_block_bio {}; - -struct trace_event_data_offsets_block_plug {}; - -struct trace_event_data_offsets_block_unplug {}; - -struct trace_event_data_offsets_block_split {}; - -struct trace_event_data_offsets_block_bio_remap {}; - -struct trace_event_data_offsets_block_rq_remap {}; - -typedef void (*btf_trace_block_touch_buffer)(void *, struct buffer_head *); - -typedef void (*btf_trace_block_dirty_buffer)(void *, struct buffer_head *); - -typedef void (*btf_trace_block_rq_requeue)(void *, struct request *); - -typedef void (*btf_trace_block_rq_complete)(void *, struct request *, int, unsigned int); - -typedef void (*btf_trace_block_rq_insert)(void *, struct request *); - -typedef void (*btf_trace_block_rq_issue)(void *, struct request *); - -typedef void (*btf_trace_block_rq_merge)(void *, struct request *); - -typedef void (*btf_trace_block_bio_complete)(void *, struct request_queue *, struct bio *); - -typedef void (*btf_trace_block_bio_bounce)(void *, struct bio *); - -typedef void (*btf_trace_block_bio_backmerge)(void *, struct bio *); - -typedef void (*btf_trace_block_bio_frontmerge)(void *, struct bio *); - -typedef void (*btf_trace_block_bio_queue)(void *, struct bio *); - -typedef void (*btf_trace_block_getrq)(void *, struct bio *); - -typedef void (*btf_trace_block_plug)(void *, struct request_queue *); - -typedef void (*btf_trace_block_unplug)(void *, struct request_queue *, unsigned int, bool); - -typedef void (*btf_trace_block_split)(void *, struct bio *, unsigned int); - -typedef void (*btf_trace_block_bio_remap)(void *, struct bio *, dev_t, sector_t); - -typedef void (*btf_trace_block_rq_remap)(void *, struct request *, dev_t, sector_t); - -enum { - BLK_MQ_NO_TAG = 4294967295, - BLK_MQ_TAG_MIN = 1, - BLK_MQ_TAG_MAX = 4294967294, -}; - -struct queue_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct request_queue *, char *); - ssize_t (*store)(struct request_queue *, const char *, size_t); -}; - -enum { - REQ_FSEQ_PREFLUSH = 1, - REQ_FSEQ_DATA = 2, - REQ_FSEQ_POSTFLUSH = 4, - REQ_FSEQ_DONE = 8, - REQ_FSEQ_ACTIONS = 7, - FLUSH_PENDING_TIMEOUT = 1500, -}; - -enum blk_default_limits { - BLK_MAX_SEGMENTS = 128, - BLK_SAFE_MAX_SECTORS = 255, - BLK_DEF_MAX_SECTORS = 2560, - BLK_MAX_SEGMENT_SIZE = 65536, - BLK_SEG_BOUNDARY_MASK = 4294967295, -}; - -enum { - ICQ_EXITED = 4, - ICQ_DESTROYED = 8, -}; - -struct rq_map_data { - struct page **pages; - int page_order; - int nr_entries; - long unsigned int offset; - int null_mapped; - int from_user; -}; - -struct bio_map_data { - bool is_our_pages: 1; - bool is_null_mapped: 1; - struct iov_iter iter; - struct iovec iov[0]; -}; - -struct req_iterator { - struct bvec_iter iter; - struct bio *bio; -}; - -enum bio_merge_status { - BIO_MERGE_OK = 0, - BIO_MERGE_NONE = 1, - BIO_MERGE_FAILED = 2, -}; - -typedef bool (*sb_for_each_fn)(struct sbitmap *, unsigned int, void *); - -typedef bool busy_iter_fn(struct blk_mq_hw_ctx *, struct request *, void *, bool); - -typedef bool busy_tag_iter_fn(struct request *, void *, bool); - -enum { - BLK_MQ_UNIQUE_TAG_BITS = 16, - BLK_MQ_UNIQUE_TAG_MASK = 65535, -}; - -struct mq_inflight { - struct block_device *part; - unsigned int inflight[2]; -}; - -struct flush_busy_ctx_data { - struct blk_mq_hw_ctx *hctx; - struct list_head *list; -}; - -struct dispatch_rq_data { - struct blk_mq_hw_ctx *hctx; - struct request *rq; -}; - -enum prep_dispatch { - PREP_DISPATCH_OK = 0, - PREP_DISPATCH_NO_TAG = 1, - PREP_DISPATCH_NO_BUDGET = 2, -}; - -struct rq_iter_data { - struct blk_mq_hw_ctx *hctx; - bool has_rq; -}; - -struct blk_mq_qe_pair { - struct list_head node; - struct request_queue *q; - struct elevator_type *type; -}; - -struct sbq_wait { - struct sbitmap_queue *sbq; - struct wait_queue_entry wait; -}; - -struct bt_iter_data { - struct blk_mq_hw_ctx *hctx; - busy_iter_fn *fn; - void *data; - bool reserved; -}; - -struct bt_tags_iter_data { - struct blk_mq_tags *tags; - busy_tag_iter_fn *fn; - void *data; - unsigned int flags; -}; - -struct blk_queue_stats { - struct list_head callbacks; - spinlock_t lock; - bool enable_accounting; -}; - -struct blk_mq_ctx_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_mq_ctx *, char *); - ssize_t (*store)(struct blk_mq_ctx *, const char *, size_t); -}; - -struct blk_mq_hw_ctx_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_mq_hw_ctx *, char *); - ssize_t (*store)(struct blk_mq_hw_ctx *, const char *, size_t); -}; - -typedef u32 compat_caddr_t; - -struct hd_geometry { - unsigned char heads; - unsigned char sectors; - short unsigned int cylinders; - long unsigned int start; -}; - -struct blkpg_ioctl_arg { - int op; - int flags; - int datalen; - void *data; -}; - -struct blkpg_partition { - long long int start; - long long int length; - int pno; - char devname[64]; - char volname[64]; -}; - -struct pr_reservation { - __u64 key; - __u32 type; - __u32 flags; -}; - -struct pr_registration { - __u64 old_key; - __u64 new_key; - __u32 flags; - __u32 __pad; -}; - -struct pr_preempt { - __u64 old_key; - __u64 new_key; - __u32 type; - __u32 flags; -}; - -struct pr_clear { - __u64 key; - __u32 flags; - __u32 __pad; -}; - -struct compat_blkpg_ioctl_arg { - compat_int_t op; - compat_int_t flags; - compat_int_t datalen; - compat_caddr_t data; -}; - -struct compat_hd_geometry { - unsigned char heads; - unsigned char sectors; - short unsigned int cylinders; - u32 start; -}; - -struct klist_node; - -struct klist { - spinlock_t k_lock; - struct list_head k_list; - void (*get)(struct klist_node *); - void (*put)(struct klist_node *); -}; - -struct klist_node { - void *n_klist; - struct list_head n_node; - struct kref n_ref; -}; - -struct klist_iter { - struct klist *i_klist; - struct klist_node *i_cur; -}; - -struct class_dev_iter { - struct klist_iter ki; - const struct device_type *type; -}; - -struct badblocks { - struct device *dev; - int count; - int unacked_exist; - int shift; - u64 *page; - int changed; - seqlock_t lock; - sector_t sector; - sector_t size; -}; - -struct blk_major_name { - struct blk_major_name *next; - int major; - char name[16]; - void (*probe)(dev_t); -}; - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP = 2, - IOPRIO_WHO_USER = 3, -}; - -struct parsed_partitions { - struct block_device *bdev; - char name[32]; - struct { - sector_t from; - sector_t size; - int flags; - bool has_info; - struct partition_meta_info info; - } *parts; - int next; - int limit; - bool access_beyond_eod; - char *pp_buf; -}; - -typedef struct { - struct page *v; -} Sector; - -struct lvm_rec { - char lvm_id[4]; - char reserved4[16]; - __be32 lvmarea_len; - __be32 vgda_len; - __be32 vgda_psn[2]; - char reserved36[10]; - __be16 pp_size; - char reserved46[12]; - __be16 version; -}; - -struct vgda { - __be32 secs; - __be32 usec; - char reserved8[16]; - __be16 numlvs; - __be16 maxlvs; - __be16 pp_size; - __be16 numpvs; - __be16 total_vgdas; - __be16 vgda_size; -}; - -struct lvd { - __be16 lv_ix; - __be16 res2; - __be16 res4; - __be16 maxsize; - __be16 lv_state; - __be16 mirror; - __be16 mirror_policy; - __be16 num_lps; - __be16 res10[8]; -}; - -struct lvname { - char name[64]; -}; - -struct ppe { - __be16 lv_ix; - short unsigned int res2; - short unsigned int res4; - __be16 lp_ix; - short unsigned int res8[12]; -}; - -struct pvd { - char reserved0[16]; - __be16 pp_count; - char reserved18[2]; - __be32 psn_part1; - char reserved24[8]; - struct ppe ppe[1016]; -}; - -struct lv_info { - short unsigned int pps_per_lv; - short unsigned int pps_found; - unsigned char lv_is_contiguous; -}; - -struct mac_partition { - __be16 signature; - __be16 res1; - __be32 map_count; - __be32 start_block; - __be32 block_count; - char name[32]; - char type[32]; - __be32 data_start; - __be32 data_count; - __be32 status; - __be32 boot_start; - __be32 boot_size; - __be32 boot_load; - __be32 boot_load2; - __be32 boot_entry; - __be32 boot_entry2; - __be32 boot_cksum; - char processor[16]; -}; - -struct mac_driver_desc { - __be16 signature; - __be16 block_size; - __be32 block_count; -}; - -struct msdos_partition { - u8 boot_ind; - u8 head; - u8 sector; - u8 cyl; - u8 sys_ind; - u8 end_head; - u8 end_sector; - u8 end_cyl; - __le32 start_sect; - __le32 nr_sects; -}; - -struct frag { - struct list_head list; - u32 group; - u8 num; - u8 rec; - u8 map; - u8 data[0]; -}; - -struct privhead { - u16 ver_major; - u16 ver_minor; - u64 logical_disk_start; - u64 logical_disk_size; - u64 config_start; - u64 config_size; - uuid_t disk_id; -}; - -struct tocblock { - u8 bitmap1_name[16]; - u64 bitmap1_start; - u64 bitmap1_size; - u8 bitmap2_name[16]; - u64 bitmap2_start; - u64 bitmap2_size; -}; - -struct vmdb { - u16 ver_major; - u16 ver_minor; - u32 vblk_size; - u32 vblk_offset; - u32 last_vblk_seq; -}; - -struct vblk_comp { - u8 state[16]; - u64 parent_id; - u8 type; - u8 children; - u16 chunksize; -}; - -struct vblk_dgrp { - u8 disk_id[64]; -}; - -struct vblk_disk { - uuid_t disk_id; - u8 alt_name[128]; -}; - -struct vblk_part { - u64 start; - u64 size; - u64 volume_offset; - u64 parent_id; - u64 disk_id; - u8 partnum; -}; - -struct vblk_volu { - u8 volume_type[16]; - u8 volume_state[16]; - u8 guid[16]; - u8 drive_hint[4]; - u64 size; - u8 partition_type; -}; - -struct vblk { - u8 name[64]; - u64 obj_id; - u32 sequence; - u8 flags; - u8 type; - union { - struct vblk_comp comp; - struct vblk_dgrp dgrp; - struct vblk_disk disk; - struct vblk_part part; - struct vblk_volu volu; - } vblk; - struct list_head list; -}; - -struct ldmdb { - struct privhead ph; - struct tocblock toc; - struct vmdb vm; - struct list_head v_dgrp; - struct list_head v_disk; - struct list_head v_volu; - struct list_head v_comp; - struct list_head v_part; -}; - -struct fat_boot_sector { - __u8 ignored[3]; - __u8 system_id[8]; - __u8 sector_size[2]; - __u8 sec_per_clus; - __le16 reserved; - __u8 fats; - __u8 dir_entries[2]; - __u8 sectors[2]; - __u8 media; - __le16 fat_length; - __le16 secs_track; - __le16 heads; - __le32 hidden; - __le32 total_sect; - union { - struct { - __u8 drive_number; - __u8 state; - __u8 signature; - __u8 vol_id[4]; - __u8 vol_label[11]; - __u8 fs_type[8]; - } fat16; - struct { - __le32 length; - __le16 flags; - __u8 version[2]; - __le32 root_cluster; - __le16 info_sector; - __le16 backup_boot; - __le16 reserved2[6]; - __u8 drive_number; - __u8 state; - __u8 signature; - __u8 vol_id[4]; - __u8 vol_label[11]; - __u8 fs_type[8]; - } fat32; - }; -}; - -enum msdos_sys_ind { - DOS_EXTENDED_PARTITION = 5, - LINUX_EXTENDED_PARTITION = 133, - WIN98_EXTENDED_PARTITION = 15, - LINUX_DATA_PARTITION = 131, - LINUX_LVM_PARTITION = 142, - LINUX_RAID_PARTITION = 253, - SOLARIS_X86_PARTITION = 130, - NEW_SOLARIS_X86_PARTITION = 191, - DM6_AUX1PARTITION = 81, - DM6_AUX3PARTITION = 83, - DM6_PARTITION = 84, - EZD_PARTITION = 85, - FREEBSD_PARTITION = 165, - OPENBSD_PARTITION = 166, - NETBSD_PARTITION = 169, - BSDI_PARTITION = 183, - MINIX_PARTITION = 129, - UNIXWARE_PARTITION = 99, -}; - -struct solaris_x86_slice { - __le16 s_tag; - __le16 s_flag; - __le32 s_start; - __le32 s_size; -}; - -struct solaris_x86_vtoc { - unsigned int v_bootinfo[3]; - __le32 v_sanity; - __le32 v_version; - char v_volume[8]; - __le16 v_sectorsz; - __le16 v_nparts; - unsigned int v_reserved[10]; - struct solaris_x86_slice v_slice[16]; - unsigned int timestamp[16]; - char v_asciilabel[128]; -}; - -struct bsd_partition { - __le32 p_size; - __le32 p_offset; - __le32 p_fsize; - __u8 p_fstype; - __u8 p_frag; - __le16 p_cpg; -}; - -struct bsd_disklabel { - __le32 d_magic; - __s16 d_type; - __s16 d_subtype; - char d_typename[16]; - char d_packname[16]; - __u32 d_secsize; - __u32 d_nsectors; - __u32 d_ntracks; - __u32 d_ncylinders; - __u32 d_secpercyl; - __u32 d_secperunit; - __u16 d_sparespertrack; - __u16 d_sparespercyl; - __u32 d_acylinders; - __u16 d_rpm; - __u16 d_interleave; - __u16 d_trackskew; - __u16 d_cylskew; - __u32 d_headswitch; - __u32 d_trkseek; - __u32 d_flags; - __u32 d_drivedata[5]; - __u32 d_spare[5]; - __le32 d_magic2; - __le16 d_checksum; - __le16 d_npartitions; - __le32 d_bbsize; - __le32 d_sbsize; - struct bsd_partition d_partitions[16]; -}; - -struct _gpt_header { - __le64 signature; - __le32 revision; - __le32 header_size; - __le32 header_crc32; - __le32 reserved1; - __le64 my_lba; - __le64 alternate_lba; - __le64 first_usable_lba; - __le64 last_usable_lba; - efi_guid_t disk_guid; - __le64 partition_entry_lba; - __le32 num_partition_entries; - __le32 sizeof_partition_entry; - __le32 partition_entry_array_crc32; -} __attribute__((packed)); - -typedef struct _gpt_header gpt_header; - -struct _gpt_entry_attributes { - u64 required_to_function: 1; - u64 reserved: 47; - u64 type_guid_specific: 16; -}; - -typedef struct _gpt_entry_attributes gpt_entry_attributes; - -struct _gpt_entry { - efi_guid_t partition_type_guid; - efi_guid_t unique_partition_guid; - __le64 starting_lba; - __le64 ending_lba; - gpt_entry_attributes attributes; - __le16 partition_name[36]; -}; - -typedef struct _gpt_entry gpt_entry; - -struct _gpt_mbr_record { - u8 boot_indicator; - u8 start_head; - u8 start_sector; - u8 start_track; - u8 os_type; - u8 end_head; - u8 end_sector; - u8 end_track; - __le32 starting_lba; - __le32 size_in_lba; -}; - -typedef struct _gpt_mbr_record gpt_mbr_record; - -struct _legacy_mbr { - u8 boot_code[440]; - __le32 unique_mbr_signature; - __le16 unknown; - gpt_mbr_record partition_record[4]; - __le16 signature; -} __attribute__((packed)); - -typedef struct _legacy_mbr legacy_mbr; - -struct d_partition { - __le32 p_res; - u8 p_fstype; - u8 p_res2[3]; - __le32 p_offset; - __le32 p_size; -}; - -struct disklabel { - u8 d_reserved[270]; - struct d_partition d_partitions[2]; - u8 d_blank[208]; - __le16 d_magic; -} __attribute__((packed)); - -struct rq_wait { - wait_queue_head_t wait; - atomic_t inflight; -}; - -struct rq_depth { - unsigned int max_depth; - int scale_step; - bool scaled_max; - unsigned int queue_depth; - unsigned int default_depth; -}; - -typedef bool acquire_inflight_cb_t(struct rq_wait *, void *); - -typedef void cleanup_cb_t(struct rq_wait *, void *); - -struct rq_qos_wait_data { - struct wait_queue_entry wq; - struct task_struct *task; - struct rq_wait *rqw; - acquire_inflight_cb_t *cb; - void *private_data; - bool got_token; -}; - -enum { - DISK_EVENT_FLAG_POLL = 1, - DISK_EVENT_FLAG_UEVENT = 2, -}; - -struct disk_events { - struct list_head node; - struct gendisk *disk; - spinlock_t lock; - struct mutex block_mutex; - int block; - unsigned int pending; - unsigned int clearing; - long int poll_msecs; - struct delayed_work dwork; -}; - -struct cdrom_device_ops; - -struct cdrom_device_info { - const struct cdrom_device_ops *ops; - struct list_head list; - struct gendisk *disk; - void *handle; - int mask; - int speed; - int capacity; - unsigned int options: 30; - unsigned int mc_flags: 2; - unsigned int vfs_events; - unsigned int ioctl_events; - int use_count; - char name[20]; - __u8 sanyo_slot: 2; - __u8 keeplocked: 1; - __u8 reserved: 5; - int cdda_method; - __u8 last_sense; - __u8 media_written; - short unsigned int mmc3_profile; - int for_data; - int (*exit)(struct cdrom_device_info *); - int mrw_mode_page; -}; - -enum sam_status { - SAM_STAT_GOOD = 0, - SAM_STAT_CHECK_CONDITION = 2, - SAM_STAT_CONDITION_MET = 4, - SAM_STAT_BUSY = 8, - SAM_STAT_INTERMEDIATE = 16, - SAM_STAT_INTERMEDIATE_CONDITION_MET = 20, - SAM_STAT_RESERVATION_CONFLICT = 24, - SAM_STAT_COMMAND_TERMINATED = 34, - SAM_STAT_TASK_SET_FULL = 40, - SAM_STAT_ACA_ACTIVE = 48, - SAM_STAT_TASK_ABORTED = 64, -}; - -struct scsi_sense_hdr { - u8 response_code; - u8 sense_key; - u8 asc; - u8 ascq; - u8 byte4; - u8 byte5; - u8 byte6; - u8 additional_length; -}; - -struct cdrom_msf0 { - __u8 minute; - __u8 second; - __u8 frame; -}; - -union cdrom_addr { - struct cdrom_msf0 msf; - int lba; -}; - -struct cdrom_multisession { - union cdrom_addr addr; - __u8 xa_flag; - __u8 addr_format; -}; - -struct cdrom_mcn { - __u8 medium_catalog_number[14]; -}; - -struct request_sense; - -struct cdrom_generic_command { - unsigned char cmd[12]; - unsigned char *buffer; - unsigned int buflen; - int stat; - struct request_sense *sense; - unsigned char data_direction; - int quiet; - int timeout; - union { - void *reserved[1]; - void *unused; - }; -}; - -struct request_sense { - __u8 error_code: 7; - __u8 valid: 1; - __u8 segment_number; - __u8 sense_key: 4; - __u8 reserved2: 1; - __u8 ili: 1; - __u8 reserved1: 2; - __u8 information[4]; - __u8 add_sense_len; - __u8 command_info[4]; - __u8 asc; - __u8 ascq; - __u8 fruc; - __u8 sks[3]; - __u8 asb[46]; -}; - -struct packet_command { - unsigned char cmd[12]; - unsigned char *buffer; - unsigned int buflen; - int stat; - struct scsi_sense_hdr *sshdr; - unsigned char data_direction; - int quiet; - int timeout; - void *reserved[1]; -}; - -struct cdrom_device_ops { - int (*open)(struct cdrom_device_info *, int); - void (*release)(struct cdrom_device_info *); - int (*drive_status)(struct cdrom_device_info *, int); - unsigned int (*check_events)(struct cdrom_device_info *, unsigned int, int); - int (*tray_move)(struct cdrom_device_info *, int); - int (*lock_door)(struct cdrom_device_info *, int); - int (*select_speed)(struct cdrom_device_info *, int); - int (*select_disc)(struct cdrom_device_info *, int); - int (*get_last_session)(struct cdrom_device_info *, struct cdrom_multisession *); - int (*get_mcn)(struct cdrom_device_info *, struct cdrom_mcn *); - int (*reset)(struct cdrom_device_info *); - int (*audio_ioctl)(struct cdrom_device_info *, unsigned int, void *); - const int capability; - int (*generic_packet)(struct cdrom_device_info *, struct packet_command *); -}; - -enum scsi_msg_byte { - COMMAND_COMPLETE = 0, - EXTENDED_MESSAGE = 1, - SAVE_POINTERS = 2, - RESTORE_POINTERS = 3, - DISCONNECT = 4, - INITIATOR_ERROR = 5, - ABORT_TASK_SET = 6, - MESSAGE_REJECT = 7, - NOP___2 = 8, - MSG_PARITY_ERROR = 9, - LINKED_CMD_COMPLETE = 10, - LINKED_FLG_CMD_COMPLETE = 11, - TARGET_RESET = 12, - ABORT_TASK = 13, - CLEAR_TASK_SET = 14, - INITIATE_RECOVERY = 15, - RELEASE_RECOVERY = 16, - TERMINATE_IO_PROC = 17, - CLEAR_ACA = 22, - LOGICAL_UNIT_RESET = 23, - SIMPLE_QUEUE_TAG = 32, - HEAD_OF_QUEUE_TAG = 33, - ORDERED_QUEUE_TAG = 34, - IGNORE_WIDE_RESIDUE = 35, - ACA = 36, - QAS_REQUEST = 85, - BUS_DEVICE_RESET = 12, - ABORT = 6, -}; - -struct scsi_ioctl_command { - unsigned int inlen; - unsigned int outlen; - unsigned char data[0]; -}; - -enum scsi_device_event { - SDEV_EVT_MEDIA_CHANGE = 1, - SDEV_EVT_INQUIRY_CHANGE_REPORTED = 2, - SDEV_EVT_CAPACITY_CHANGE_REPORTED = 3, - SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED = 4, - SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED = 5, - SDEV_EVT_LUN_CHANGE_REPORTED = 6, - SDEV_EVT_ALUA_STATE_CHANGE_REPORTED = 7, - SDEV_EVT_POWER_ON_RESET_OCCURRED = 8, - SDEV_EVT_FIRST = 1, - SDEV_EVT_LAST = 8, - SDEV_EVT_MAXBITS = 9, -}; - -struct scsi_request { - unsigned char __cmd[16]; - unsigned char *cmd; - short unsigned int cmd_len; - int result; - unsigned int sense_len; - unsigned int resid_len; - int retries; - void *sense; -}; - -struct sg_io_hdr { - int interface_id; - int dxfer_direction; - unsigned char cmd_len; - unsigned char mx_sb_len; - short unsigned int iovec_count; - unsigned int dxfer_len; - void *dxferp; - unsigned char *cmdp; - void *sbp; - unsigned int timeout; - unsigned int flags; - int pack_id; - void *usr_ptr; - unsigned char status; - unsigned char masked_status; - unsigned char msg_status; - unsigned char sb_len_wr; - short unsigned int host_status; - short unsigned int driver_status; - int resid; - unsigned int duration; - unsigned int info; -}; - -struct compat_sg_io_hdr { - compat_int_t interface_id; - compat_int_t dxfer_direction; - unsigned char cmd_len; - unsigned char mx_sb_len; - short unsigned int iovec_count; - compat_uint_t dxfer_len; - compat_uint_t dxferp; - compat_uptr_t cmdp; - compat_uptr_t sbp; - compat_uint_t timeout; - compat_uint_t flags; - compat_int_t pack_id; - compat_uptr_t usr_ptr; - unsigned char status; - unsigned char masked_status; - unsigned char msg_status; - unsigned char sb_len_wr; - short unsigned int host_status; - short unsigned int driver_status; - compat_int_t resid; - compat_uint_t duration; - compat_uint_t info; -}; - -struct blk_cmd_filter { - long unsigned int read_ok[4]; - long unsigned int write_ok[4]; -}; - -struct compat_cdrom_generic_command { - unsigned char cmd[12]; - compat_caddr_t buffer; - compat_uint_t buflen; - compat_int_t stat; - compat_caddr_t sense; - unsigned char data_direction; - unsigned char pad[3]; - compat_int_t quiet; - compat_int_t timeout; - compat_caddr_t unused; -}; - -enum { - OMAX_SB_LEN = 16, -}; - -struct bsg_device { - struct request_queue *queue; - spinlock_t lock; - struct hlist_node dev_list; - refcount_t ref_count; - char name[20]; - int max_queue; -}; - -struct bsg_job; - -typedef int bsg_job_fn(struct bsg_job *); - -struct bsg_buffer { - unsigned int payload_len; - int sg_cnt; - struct scatterlist *sg_list; -}; - -struct bsg_job { - struct device *dev; - struct kref kref; - unsigned int timeout; - void *request; - void *reply; - unsigned int request_len; - unsigned int reply_len; - struct bsg_buffer request_payload; - struct bsg_buffer reply_payload; - int result; - unsigned int reply_payload_rcv_len; - struct request *bidi_rq; - struct bio *bidi_bio; - void *dd_data; -}; - -typedef enum blk_eh_timer_return bsg_timeout_fn(struct request *); - -struct bsg_set { - struct blk_mq_tag_set tag_set; - bsg_job_fn *job_fn; - bsg_timeout_fn *timeout_fn; -}; - -typedef struct blkcg_policy_data *blkcg_pol_alloc_cpd_fn(gfp_t); - -typedef void blkcg_pol_init_cpd_fn(struct blkcg_policy_data *); - -typedef void blkcg_pol_free_cpd_fn(struct blkcg_policy_data *); - -typedef void blkcg_pol_bind_cpd_fn(struct blkcg_policy_data *); - -typedef struct blkg_policy_data *blkcg_pol_alloc_pd_fn(gfp_t, struct request_queue *, struct blkcg *); - -typedef void blkcg_pol_init_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_online_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_offline_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_free_pd_fn(struct blkg_policy_data *); - -typedef void blkcg_pol_reset_pd_stats_fn(struct blkg_policy_data *); - -typedef size_t blkcg_pol_stat_pd_fn(struct blkg_policy_data *, char *, size_t); - -struct blkcg_policy { - int plid; - struct cftype *dfl_cftypes; - struct cftype *legacy_cftypes; - blkcg_pol_alloc_cpd_fn *cpd_alloc_fn; - blkcg_pol_init_cpd_fn *cpd_init_fn; - blkcg_pol_free_cpd_fn *cpd_free_fn; - blkcg_pol_bind_cpd_fn *cpd_bind_fn; - blkcg_pol_alloc_pd_fn *pd_alloc_fn; - blkcg_pol_init_pd_fn *pd_init_fn; - blkcg_pol_online_pd_fn *pd_online_fn; - blkcg_pol_offline_pd_fn *pd_offline_fn; - blkcg_pol_free_pd_fn *pd_free_fn; - blkcg_pol_reset_pd_stats_fn *pd_reset_stats_fn; - blkcg_pol_stat_pd_fn *pd_stat_fn; -}; - -struct blkg_conf_ctx { - struct block_device *bdev; - struct blkcg_gq *blkg; - char *body; -}; - -enum blkg_rwstat_type { - BLKG_RWSTAT_READ = 0, - BLKG_RWSTAT_WRITE = 1, - BLKG_RWSTAT_SYNC = 2, - BLKG_RWSTAT_ASYNC = 3, - BLKG_RWSTAT_DISCARD = 4, - BLKG_RWSTAT_NR = 5, - BLKG_RWSTAT_TOTAL = 5, -}; - -struct blkg_rwstat { - struct percpu_counter cpu_cnt[5]; - atomic64_t aux_cnt[5]; -}; - -struct blkg_rwstat_sample { - u64 cnt[5]; -}; - -struct throtl_service_queue { - struct throtl_service_queue *parent_sq; - struct list_head queued[2]; - unsigned int nr_queued[2]; - struct rb_root_cached pending_tree; - unsigned int nr_pending; - long unsigned int first_pending_disptime; - struct timer_list pending_timer; -}; - -struct latency_bucket { - long unsigned int total_latency; - int samples; -}; - -struct avg_latency_bucket { - long unsigned int latency; - bool valid; -}; - -struct throtl_data { - struct throtl_service_queue service_queue; - struct request_queue *queue; - unsigned int nr_queued[2]; - unsigned int throtl_slice; - struct work_struct dispatch_work; - unsigned int limit_index; - bool limit_valid[2]; - long unsigned int low_upgrade_time; - long unsigned int low_downgrade_time; - unsigned int scale; - struct latency_bucket tmp_buckets[18]; - struct avg_latency_bucket avg_buckets[18]; - struct latency_bucket *latency_buckets[2]; - long unsigned int last_calculate_time; - long unsigned int filtered_latency; - bool track_bio_latency; -}; - -struct throtl_grp; - -struct throtl_qnode { - struct list_head node; - struct bio_list bios; - struct throtl_grp *tg; -}; - -struct throtl_grp { - struct blkg_policy_data pd; - struct rb_node rb_node; - struct throtl_data *td; - struct throtl_service_queue service_queue; - struct throtl_qnode qnode_on_self[2]; - struct throtl_qnode qnode_on_parent[2]; - long unsigned int disptime; - unsigned int flags; - bool has_rules[2]; - uint64_t bps[4]; - uint64_t bps_conf[4]; - unsigned int iops[4]; - unsigned int iops_conf[4]; - uint64_t bytes_disp[2]; - unsigned int io_disp[2]; - long unsigned int last_low_overflow_time[2]; - uint64_t last_bytes_disp[2]; - unsigned int last_io_disp[2]; - long unsigned int last_check_time; - long unsigned int latency_target; - long unsigned int latency_target_conf; - long unsigned int slice_start[2]; - long unsigned int slice_end[2]; - long unsigned int last_finish_time; - long unsigned int checked_last_finish_time; - long unsigned int avg_idletime; - long unsigned int idletime_threshold; - long unsigned int idletime_threshold_conf; - unsigned int bio_cnt; - unsigned int bad_bio_cnt; - long unsigned int bio_cnt_reset_time; - struct blkg_rwstat stat_bytes; - struct blkg_rwstat stat_ios; -}; - -enum tg_state_flags { - THROTL_TG_PENDING = 1, - THROTL_TG_WAS_EMPTY = 2, -}; - -enum { - LIMIT_LOW = 0, - LIMIT_MAX = 1, - LIMIT_CNT = 2, -}; - -enum prio_policy { - POLICY_NO_CHANGE = 0, - POLICY_NONE_TO_RT = 1, - POLICY_RESTRICT_TO_BE = 2, - POLICY_ALL_TO_IDLE = 3, -}; - -struct ioprio_blkg { - struct blkg_policy_data pd; -}; - -struct ioprio_blkcg { - struct blkcg_policy_data cpd; - enum prio_policy prio_policy; -}; - -struct blk_ioprio { - struct rq_qos rqos; -}; - -struct blk_iolatency { - struct rq_qos rqos; - struct timer_list timer; - atomic_t enabled; -}; - -struct iolatency_grp; - -struct child_latency_info { - spinlock_t lock; - u64 last_scale_event; - u64 scale_lat; - u64 nr_samples; - struct iolatency_grp *scale_grp; - atomic_t scale_cookie; -}; - -struct percentile_stats { - u64 total; - u64 missed; -}; - -struct latency_stat { - union { - struct percentile_stats ps; - struct blk_rq_stat rqs; - }; -}; - -struct iolatency_grp { - struct blkg_policy_data pd; - struct latency_stat *stats; - struct latency_stat cur_stat; - struct blk_iolatency *blkiolat; - struct rq_depth rq_depth; - struct rq_wait rq_wait; - atomic64_t window_start; - atomic_t scale_cookie; - u64 min_lat_nsec; - u64 cur_win_nsec; - u64 lat_avg; - u64 nr_samples; - bool ssd; - struct child_latency_info child_lat; -}; - -enum { - MILLION = 1000000, - MIN_PERIOD = 1000, - MAX_PERIOD = 1000000, - MARGIN_MIN_PCT = 10, - MARGIN_LOW_PCT = 20, - MARGIN_TARGET_PCT = 50, - INUSE_ADJ_STEP_PCT = 25, - TIMER_SLACK_PCT = 1, - WEIGHT_ONE = 65536, - VTIME_PER_SEC_SHIFT = 37, - VTIME_PER_SEC = 0, - VTIME_PER_USEC = 137438, - VTIME_PER_NSEC = 137, - VRATE_MIN_PPM = 10000, - VRATE_MAX_PPM = 100000000, - VRATE_MIN = 1374, - VRATE_CLAMP_ADJ_PCT = 4, - RQ_WAIT_BUSY_PCT = 5, - UNBUSY_THR_PCT = 75, - MIN_DELAY_THR_PCT = 500, - MAX_DELAY_THR_PCT = 25000, - MIN_DELAY = 250, - MAX_DELAY = 250000, - DFGV_USAGE_PCT = 50, - DFGV_PERIOD = 100000, - MAX_LAGGING_PERIODS = 10, - AUTOP_CYCLE_NSEC = 1410065408, - IOC_PAGE_SHIFT = 12, - IOC_PAGE_SIZE = 4096, - IOC_SECT_TO_PAGE_SHIFT = 3, - LCOEF_RANDIO_PAGES = 4096, -}; - -enum ioc_running { - IOC_IDLE = 0, - IOC_RUNNING = 1, - IOC_STOP = 2, -}; - -enum { - QOS_ENABLE = 0, - QOS_CTRL = 1, - NR_QOS_CTRL_PARAMS = 2, -}; - -enum { - QOS_RPPM = 0, - QOS_RLAT = 1, - QOS_WPPM = 2, - QOS_WLAT = 3, - QOS_MIN = 4, - QOS_MAX = 5, - NR_QOS_PARAMS = 6, -}; - -enum { - COST_CTRL = 0, - COST_MODEL = 1, - NR_COST_CTRL_PARAMS = 2, -}; - -enum { - I_LCOEF_RBPS = 0, - I_LCOEF_RSEQIOPS = 1, - I_LCOEF_RRANDIOPS = 2, - I_LCOEF_WBPS = 3, - I_LCOEF_WSEQIOPS = 4, - I_LCOEF_WRANDIOPS = 5, - NR_I_LCOEFS = 6, -}; - -enum { - LCOEF_RPAGE = 0, - LCOEF_RSEQIO = 1, - LCOEF_RRANDIO = 2, - LCOEF_WPAGE = 3, - LCOEF_WSEQIO = 4, - LCOEF_WRANDIO = 5, - NR_LCOEFS = 6, -}; - -enum { - AUTOP_INVALID = 0, - AUTOP_HDD = 1, - AUTOP_SSD_QD1 = 2, - AUTOP_SSD_DFL = 3, - AUTOP_SSD_FAST = 4, -}; - -struct ioc_params { - u32 qos[6]; - u64 i_lcoefs[6]; - u64 lcoefs[6]; - u32 too_fast_vrate_pct; - u32 too_slow_vrate_pct; -}; - -struct ioc_margins { - s64 min; - s64 low; - s64 target; -}; - -struct ioc_missed { - local_t nr_met; - local_t nr_missed; - u32 last_met; - u32 last_missed; -}; - -struct ioc_pcpu_stat { - struct ioc_missed missed[2]; - local64_t rq_wait_ns; - u64 last_rq_wait_ns; -}; - -struct ioc { - struct rq_qos rqos; - bool enabled; - struct ioc_params params; - struct ioc_margins margins; - u32 period_us; - u32 timer_slack_ns; - u64 vrate_min; - u64 vrate_max; - spinlock_t lock; - struct timer_list timer; - struct list_head active_iocgs; - struct ioc_pcpu_stat *pcpu_stat; - enum ioc_running running; - atomic64_t vtime_rate; - u64 vtime_base_rate; - s64 vtime_err; - seqcount_spinlock_t period_seqcount; - u64 period_at; - u64 period_at_vtime; - atomic64_t cur_period; - int busy_level; - bool weights_updated; - atomic_t hweight_gen; - u64 dfgv_period_at; - u64 dfgv_period_rem; - u64 dfgv_usage_us_sum; - u64 autop_too_fast_at; - u64 autop_too_slow_at; - int autop_idx; - bool user_qos_params: 1; - bool user_cost_model: 1; -}; - -struct iocg_pcpu_stat { - local64_t abs_vusage; -}; - -struct iocg_stat { - u64 usage_us; - u64 wait_us; - u64 indebt_us; - u64 indelay_us; -}; - -struct ioc_gq { - struct blkg_policy_data pd; - struct ioc *ioc; - u32 cfg_weight; - u32 weight; - u32 active; - u32 inuse; - u32 last_inuse; - s64 saved_margin; - sector_t cursor; - atomic64_t vtime; - atomic64_t done_vtime; - u64 abs_vdebt; - u64 delay; - u64 delay_at; - atomic64_t active_period; - struct list_head active_list; - u64 child_active_sum; - u64 child_inuse_sum; - u64 child_adjusted_sum; - int hweight_gen; - u32 hweight_active; - u32 hweight_inuse; - u32 hweight_donating; - u32 hweight_after_donation; - struct list_head walk_list; - struct list_head surplus_list; - struct wait_queue_head waitq; - struct hrtimer waitq_timer; - u64 activated_at; - struct iocg_pcpu_stat *pcpu_stat; - struct iocg_stat local_stat; - struct iocg_stat desc_stat; - struct iocg_stat last_stat; - u64 last_stat_abs_vusage; - u64 usage_delta_us; - u64 wait_since; - u64 indebt_since; - u64 indelay_since; - int level; - struct ioc_gq *ancestors[0]; -}; - -struct ioc_cgrp { - struct blkcg_policy_data cpd; - unsigned int dfl_weight; -}; - -struct ioc_now { - u64 now_ns; - u64 now; - u64 vnow; - u64 vrate; -}; - -struct iocg_wait { - struct wait_queue_entry wait; - struct bio *bio; - u64 abs_cost; - bool committed; -}; - -struct iocg_wake_ctx { - struct ioc_gq *iocg; - u32 hw_inuse; - s64 vbudget; -}; - -struct trace_event_raw_iocost_iocg_state { - struct trace_entry ent; - u32 __data_loc_devname; - u32 __data_loc_cgroup; - u64 now; - u64 vnow; - u64 vrate; - u64 last_period; - u64 cur_period; - u64 vtime; - u32 weight; - u32 inuse; - u64 hweight_active; - u64 hweight_inuse; - char __data[0]; -}; - -struct trace_event_raw_iocg_inuse_update { - struct trace_entry ent; - u32 __data_loc_devname; - u32 __data_loc_cgroup; - u64 now; - u32 old_inuse; - u32 new_inuse; - u64 old_hweight_inuse; - u64 new_hweight_inuse; - char __data[0]; -}; - -struct trace_event_raw_iocost_ioc_vrate_adj { - struct trace_entry ent; - u32 __data_loc_devname; - u64 old_vrate; - u64 new_vrate; - int busy_level; - u32 read_missed_ppm; - u32 write_missed_ppm; - u32 rq_wait_pct; - int nr_lagging; - int nr_shortages; - char __data[0]; -}; - -struct trace_event_raw_iocost_iocg_forgive_debt { - struct trace_entry ent; - u32 __data_loc_devname; - u32 __data_loc_cgroup; - u64 now; - u64 vnow; - u32 usage_pct; - u64 old_debt; - u64 new_debt; - u64 old_delay; - u64 new_delay; - char __data[0]; -}; - -struct trace_event_data_offsets_iocost_iocg_state { - u32 devname; - u32 cgroup; -}; - -struct trace_event_data_offsets_iocg_inuse_update { - u32 devname; - u32 cgroup; -}; - -struct trace_event_data_offsets_iocost_ioc_vrate_adj { - u32 devname; -}; - -struct trace_event_data_offsets_iocost_iocg_forgive_debt { - u32 devname; - u32 cgroup; -}; - -typedef void (*btf_trace_iocost_iocg_activate)(void *, struct ioc_gq *, const char *, struct ioc_now *, u64, u64, u64); - -typedef void (*btf_trace_iocost_iocg_idle)(void *, struct ioc_gq *, const char *, struct ioc_now *, u64, u64, u64); - -typedef void (*btf_trace_iocost_inuse_shortage)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u32, u64, u64); - -typedef void (*btf_trace_iocost_inuse_transfer)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u32, u64, u64); - -typedef void (*btf_trace_iocost_inuse_adjust)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u32, u64, u64); - -typedef void (*btf_trace_iocost_ioc_vrate_adj)(void *, struct ioc *, u64, u32 *, u32, int, int); - -typedef void (*btf_trace_iocost_iocg_forgive_debt)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u64, u64, u64, u64); - -enum dd_data_dir { - DD_READ = 0, - DD_WRITE = 1, -}; - -enum { - DD_DIR_COUNT = 2, -}; - -enum dd_prio { - DD_RT_PRIO = 0, - DD_BE_PRIO = 1, - DD_IDLE_PRIO = 2, - DD_PRIO_MAX = 2, -}; - -enum { - DD_PRIO_COUNT = 3, -}; - -struct io_stats_per_prio { - local_t inserted; - local_t merged; - local_t dispatched; - local_t completed; -}; - -struct io_stats { - struct io_stats_per_prio stats[3]; -}; - -struct dd_per_prio { - struct list_head dispatch; - struct rb_root sort_list[2]; - struct list_head fifo_list[2]; - struct request *next_rq[2]; -}; - -struct deadline_data { - struct dd_per_prio per_prio[3]; - enum dd_data_dir last_dir; - unsigned int batching; - unsigned int starved; - struct io_stats *stats; - int fifo_expire[2]; - int fifo_batch; - int writes_starved; - int front_merges; - u32 async_depth; - spinlock_t lock; - spinlock_t zone_lock; -}; - -struct trace_event_raw_kyber_latency { - struct trace_entry ent; - dev_t dev; - char domain[16]; - char type[8]; - u8 percentile; - u8 numerator; - u8 denominator; - unsigned int samples; - char __data[0]; -}; - -struct trace_event_raw_kyber_adjust { - struct trace_entry ent; - dev_t dev; - char domain[16]; - unsigned int depth; - char __data[0]; -}; - -struct trace_event_raw_kyber_throttled { - struct trace_entry ent; - dev_t dev; - char domain[16]; - char __data[0]; -}; - -struct trace_event_data_offsets_kyber_latency {}; - -struct trace_event_data_offsets_kyber_adjust {}; - -struct trace_event_data_offsets_kyber_throttled {}; - -typedef void (*btf_trace_kyber_latency)(void *, struct request_queue *, const char *, const char *, unsigned int, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_kyber_adjust)(void *, struct request_queue *, const char *, unsigned int); - -typedef void (*btf_trace_kyber_throttled)(void *, struct request_queue *, const char *); - -enum { - KYBER_READ = 0, - KYBER_WRITE = 1, - KYBER_DISCARD = 2, - KYBER_OTHER = 3, - KYBER_NUM_DOMAINS = 4, -}; - -enum { - KYBER_ASYNC_PERCENT = 75, -}; - -enum { - KYBER_LATENCY_SHIFT = 2, - KYBER_GOOD_BUCKETS = 4, - KYBER_LATENCY_BUCKETS = 8, -}; - -enum { - KYBER_TOTAL_LATENCY = 0, - KYBER_IO_LATENCY = 1, -}; - -struct kyber_cpu_latency { - atomic_t buckets[48]; -}; - -struct kyber_ctx_queue { - spinlock_t lock; - struct list_head rq_list[4]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct kyber_queue_data { - struct request_queue *q; - struct sbitmap_queue domain_tokens[4]; - unsigned int async_depth; - struct kyber_cpu_latency *cpu_latency; - struct timer_list timer; - unsigned int latency_buckets[48]; - long unsigned int latency_timeout[3]; - int domain_p99[3]; - u64 latency_targets[3]; -}; - -struct kyber_hctx_data { - spinlock_t lock; - struct list_head rqs[4]; - unsigned int cur_domain; - unsigned int batching; - struct kyber_ctx_queue *kcqs; - struct sbitmap kcq_map[4]; - struct sbq_wait domain_wait[4]; - struct sbq_wait_state *domain_ws[4]; - atomic_t wait_index[4]; -}; - -struct flush_kcq_data { - struct kyber_hctx_data *khd; - unsigned int sched_domain; - struct list_head *list; -}; - -struct bfq_entity; - -struct bfq_service_tree { - struct rb_root active; - struct rb_root idle; - struct bfq_entity *first_idle; - struct bfq_entity *last_idle; - u64 vtime; - long unsigned int wsum; -}; - -struct bfq_sched_data; - -struct bfq_queue; - -struct bfq_entity { - struct rb_node rb_node; - bool on_st_or_in_serv; - u64 start; - u64 finish; - struct rb_root *tree; - u64 min_start; - int service; - int budget; - int dev_weight; - int weight; - int new_weight; - int orig_weight; - struct bfq_entity *parent; - struct bfq_sched_data *my_sched_data; - struct bfq_sched_data *sched_data; - int prio_changed; - bool in_groups_with_pending_reqs; - struct bfq_queue *last_bfqq_created; -}; - -struct bfq_sched_data { - struct bfq_entity *in_service_entity; - struct bfq_entity *next_in_service; - struct bfq_service_tree service_tree[3]; - long unsigned int bfq_class_idle_last_service; -}; - -struct bfq_weight_counter { - unsigned int weight; - unsigned int num_active; - struct rb_node weights_node; -}; - -struct bfq_ttime { - u64 last_end_request; - u64 ttime_total; - long unsigned int ttime_samples; - u64 ttime_mean; -}; - -struct bfq_data; - -struct bfq_io_cq; - -struct bfq_queue { - int ref; - int stable_ref; - struct bfq_data *bfqd; - short unsigned int ioprio; - short unsigned int ioprio_class; - short unsigned int new_ioprio; - short unsigned int new_ioprio_class; - u64 last_serv_time_ns; - unsigned int inject_limit; - long unsigned int decrease_time_jif; - struct bfq_queue *new_bfqq; - struct rb_node pos_node; - struct rb_root *pos_root; - struct rb_root sort_list; - struct request *next_rq; - int queued[2]; - int allocated; - int meta_pending; - struct list_head fifo; - struct bfq_entity entity; - struct bfq_weight_counter *weight_counter; - int max_budget; - long unsigned int budget_timeout; - int dispatched; - long unsigned int flags; - struct list_head bfqq_list; - struct bfq_ttime ttime; - u64 io_start_time; - u64 tot_idle_time; - u32 seek_history; - struct hlist_node burst_list_node; - sector_t last_request_pos; - unsigned int requests_within_timer; - pid_t pid; - struct bfq_io_cq *bic; - long unsigned int wr_cur_max_time; - long unsigned int soft_rt_next_start; - long unsigned int last_wr_start_finish; - unsigned int wr_coeff; - long unsigned int last_idle_bklogged; - long unsigned int service_from_backlogged; - long unsigned int service_from_wr; - long unsigned int wr_start_at_switch_to_srt; - long unsigned int split_time; - long unsigned int first_IO_time; - long unsigned int creation_time; - u32 max_service_rate; - struct bfq_queue *waker_bfqq; - struct bfq_queue *tentative_waker_bfqq; - unsigned int num_waker_detections; - struct hlist_node woken_list_node; - struct hlist_head woken_list; -}; - -struct bfq_group; - -struct bfq_data { - struct request_queue *queue; - struct list_head dispatch; - struct bfq_group *root_group; - struct rb_root_cached queue_weights_tree; - unsigned int num_groups_with_pending_reqs; - unsigned int busy_queues[3]; - int wr_busy_queues; - int queued; - int rq_in_driver; - bool nonrot_with_queueing; - int max_rq_in_driver; - int hw_tag_samples; - int hw_tag; - int budgets_assigned; - struct hrtimer idle_slice_timer; - struct bfq_queue *in_service_queue; - sector_t last_position; - sector_t in_serv_last_pos; - u64 last_completion; - struct bfq_queue *last_completed_rq_bfqq; - struct bfq_queue *last_bfqq_created; - u64 last_empty_occupied_ns; - bool wait_dispatch; - struct request *waited_rq; - bool rqs_injected; - u64 first_dispatch; - u64 last_dispatch; - ktime_t last_budget_start; - ktime_t last_idling_start; - long unsigned int last_idling_start_jiffies; - int peak_rate_samples; - u32 sequential_samples; - u64 tot_sectors_dispatched; - u32 last_rq_max_size; - u64 delta_from_first; - u32 peak_rate; - int bfq_max_budget; - struct list_head active_list; - struct list_head idle_list; - u64 bfq_fifo_expire[2]; - unsigned int bfq_back_penalty; - unsigned int bfq_back_max; - u32 bfq_slice_idle; - int bfq_user_max_budget; - unsigned int bfq_timeout; - bool strict_guarantees; - long unsigned int last_ins_in_burst; - long unsigned int bfq_burst_interval; - int burst_size; - struct bfq_entity *burst_parent_entity; - long unsigned int bfq_large_burst_thresh; - bool large_burst; - struct hlist_head burst_list; - bool low_latency; - unsigned int bfq_wr_coeff; - unsigned int bfq_wr_max_time; - unsigned int bfq_wr_rt_max_time; - unsigned int bfq_wr_min_idle_time; - long unsigned int bfq_wr_min_inter_arr_async; - unsigned int bfq_wr_max_softrt_rate; - u64 rate_dur_prod; - struct bfq_queue oom_bfqq; - spinlock_t lock; - struct bfq_io_cq *bio_bic; - struct bfq_queue *bio_bfqq; - unsigned int word_depths[4]; -}; - -struct bfq_io_cq { - struct io_cq icq; - struct bfq_queue *bfqq[2]; - int ioprio; - uint64_t blkcg_serial_nr; - bool saved_has_short_ttime; - bool saved_IO_bound; - u64 saved_io_start_time; - u64 saved_tot_idle_time; - bool saved_in_large_burst; - bool was_in_burst_list; - unsigned int saved_weight; - long unsigned int saved_wr_coeff; - long unsigned int saved_last_wr_start_finish; - long unsigned int saved_service_from_wr; - long unsigned int saved_wr_start_at_switch_to_srt; - unsigned int saved_wr_cur_max_time; - struct bfq_ttime saved_ttime; - u64 saved_last_serv_time_ns; - unsigned int saved_inject_limit; - long unsigned int saved_decrease_time_jif; - struct bfq_queue *stable_merge_bfqq; - bool stably_merged; -}; - -struct bfqg_stats { - struct blkg_rwstat bytes; - struct blkg_rwstat ios; -}; - -struct bfq_group { - struct blkg_policy_data pd; - char blkg_path[128]; - int ref; - struct bfq_entity entity; - struct bfq_sched_data sched_data; - void *bfqd; - struct bfq_queue *async_bfqq[16]; - struct bfq_queue *async_idle_bfqq; - struct bfq_entity *my_entity; - int active_entities; - struct rb_root rq_pos_tree; - struct bfqg_stats stats; -}; - -enum bfqq_state_flags { - BFQQF_just_created = 0, - BFQQF_busy = 1, - BFQQF_wait_request = 2, - BFQQF_non_blocking_wait_rq = 3, - BFQQF_fifo_expire = 4, - BFQQF_has_short_ttime = 5, - BFQQF_sync = 6, - BFQQF_IO_bound = 7, - BFQQF_in_large_burst = 8, - BFQQF_softrt_update = 9, - BFQQF_coop = 10, - BFQQF_split_coop = 11, -}; - -enum bfqq_expiration { - BFQQE_TOO_IDLE = 0, - BFQQE_BUDGET_TIMEOUT = 1, - BFQQE_BUDGET_EXHAUSTED = 2, - BFQQE_NO_MORE_REQUESTS = 3, - BFQQE_PREEMPTED = 4, -}; - -struct bfq_group_data { - struct blkcg_policy_data pd; - unsigned int weight; -}; - -enum bip_flags { - BIP_BLOCK_INTEGRITY = 1, - BIP_MAPPED_INTEGRITY = 2, - BIP_CTRL_NOCHECK = 4, - BIP_DISK_NOCHECK = 8, - BIP_IP_CHECKSUM = 16, -}; - -enum blk_integrity_flags { - BLK_INTEGRITY_VERIFY = 1, - BLK_INTEGRITY_GENERATE = 2, - BLK_INTEGRITY_DEVICE_CAPABLE = 4, - BLK_INTEGRITY_IP_CHECKSUM = 8, -}; - -struct integrity_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_integrity *, char *); - ssize_t (*store)(struct blk_integrity *, const char *, size_t); -}; - -enum t10_dif_type { - T10_PI_TYPE0_PROTECTION = 0, - T10_PI_TYPE1_PROTECTION = 1, - T10_PI_TYPE2_PROTECTION = 2, - T10_PI_TYPE3_PROTECTION = 3, -}; - -struct t10_pi_tuple { - __be16 guard_tag; - __be16 app_tag; - __be32 ref_tag; -}; - -typedef __be16 csum_fn(void *, unsigned int); - -struct virtio_device_id { - __u32 device; - __u32 vendor; -}; - -struct virtio_device; - -struct virtqueue { - struct list_head list; - void (*callback)(struct virtqueue *); - const char *name; - struct virtio_device *vdev; - unsigned int index; - unsigned int num_free; - void *priv; -}; - -struct vringh_config_ops; - -struct virtio_config_ops; - -struct virtio_device { - int index; - bool failed; - bool config_enabled; - bool config_change_pending; - spinlock_t config_lock; - spinlock_t vqs_list_lock; - struct device dev; - struct virtio_device_id id; - const struct virtio_config_ops *config; - const struct vringh_config_ops *vringh_config; - struct list_head vqs; - u64 features; - void *priv; -}; - -typedef void vq_callback_t(struct virtqueue *); - -struct irq_affinity___2; - -struct virtio_shm_region; - -struct virtio_config_ops { - void (*get)(struct virtio_device *, unsigned int, void *, unsigned int); - void (*set)(struct virtio_device *, unsigned int, const void *, unsigned int); - u32 (*generation)(struct virtio_device *); - u8 (*get_status)(struct virtio_device *); - void (*set_status)(struct virtio_device *, u8); - void (*reset)(struct virtio_device *); - int (*find_vqs)(struct virtio_device *, unsigned int, struct virtqueue **, vq_callback_t **, const char * const *, const bool *, struct irq_affinity___2 *); - void (*del_vqs)(struct virtio_device *); - u64 (*get_features)(struct virtio_device *); - int (*finalize_features)(struct virtio_device *); - const char * (*bus_name)(struct virtio_device *); - int (*set_vq_affinity)(struct virtqueue *, const struct cpumask *); - const struct cpumask * (*get_vq_affinity)(struct virtio_device *, int); - bool (*get_shm_region)(struct virtio_device *, struct virtio_shm_region *, u8); -}; - -struct virtio_shm_region { - u64 addr; - u64 len; -}; - -struct irq_poll; - -typedef int irq_poll_fn(struct irq_poll *, int); - -struct irq_poll { - struct list_head list; - long unsigned int state; - int weight; - irq_poll_fn *poll; -}; - -struct dim_sample { - ktime_t time; - u32 pkt_ctr; - u32 byte_ctr; - u16 event_ctr; - u32 comp_ctr; -}; - -struct dim_stats { - int ppms; - int bpms; - int epms; - int cpms; - int cpe_ratio; -}; - -struct dim { - u8 state; - struct dim_stats prev_stats; - struct dim_sample start_sample; - struct dim_sample measuring_sample; - struct work_struct work; - void *priv; - u8 profile_ix; - u8 mode; - u8 tune_state; - u8 steps_right; - u8 steps_left; - u8 tired; -}; - -enum rdma_nl_counter_mode { - RDMA_COUNTER_MODE_NONE = 0, - RDMA_COUNTER_MODE_AUTO = 1, - RDMA_COUNTER_MODE_MANUAL = 2, - RDMA_COUNTER_MODE_MAX = 3, -}; - -enum rdma_nl_counter_mask { - RDMA_COUNTER_MASK_QP_TYPE = 1, - RDMA_COUNTER_MASK_PID = 2, -}; - -enum rdma_restrack_type { - RDMA_RESTRACK_PD = 0, - RDMA_RESTRACK_CQ = 1, - RDMA_RESTRACK_QP = 2, - RDMA_RESTRACK_CM_ID = 3, - RDMA_RESTRACK_MR = 4, - RDMA_RESTRACK_CTX = 5, - RDMA_RESTRACK_COUNTER = 6, - RDMA_RESTRACK_SRQ = 7, - RDMA_RESTRACK_MAX = 8, -}; - -struct rdma_restrack_entry { - bool valid; - u8 no_track: 1; - struct kref kref; - struct completion comp; - struct task_struct *task; - const char *kern_name; - enum rdma_restrack_type type; - bool user; - u32 id; -}; - -struct rdma_link_ops { - struct list_head list; - const char *type; - int (*newlink)(const char *, struct net_device *); -}; - -struct auto_mode_param { - int qp_type; -}; - -struct rdma_counter_mode { - enum rdma_nl_counter_mode mode; - enum rdma_nl_counter_mask mask; - struct auto_mode_param param; -}; - -struct rdma_hw_stats; - -struct rdma_port_counter { - struct rdma_counter_mode mode; - struct rdma_hw_stats *hstats; - unsigned int num_counters; - struct mutex lock; -}; - -struct rdma_hw_stats { - struct mutex lock; - long unsigned int timestamp; - long unsigned int lifespan; - const char * const *names; - int num_counters; - u64 value[0]; -}; - -struct ib_device; - -struct rdma_counter { - struct rdma_restrack_entry res; - struct ib_device *device; - uint32_t id; - struct kref kref; - struct rdma_counter_mode mode; - struct mutex lock; - struct rdma_hw_stats *stats; - u32 port; -}; - -enum rdma_driver_id { - RDMA_DRIVER_UNKNOWN = 0, - RDMA_DRIVER_MLX5 = 1, - RDMA_DRIVER_MLX4 = 2, - RDMA_DRIVER_CXGB3 = 3, - RDMA_DRIVER_CXGB4 = 4, - RDMA_DRIVER_MTHCA = 5, - RDMA_DRIVER_BNXT_RE = 6, - RDMA_DRIVER_OCRDMA = 7, - RDMA_DRIVER_NES = 8, - RDMA_DRIVER_I40IW = 9, - RDMA_DRIVER_IRDMA = 9, - RDMA_DRIVER_VMW_PVRDMA = 10, - RDMA_DRIVER_QEDR = 11, - RDMA_DRIVER_HNS = 12, - RDMA_DRIVER_USNIC = 13, - RDMA_DRIVER_RXE = 14, - RDMA_DRIVER_HFI1 = 15, - RDMA_DRIVER_QIB = 16, - RDMA_DRIVER_EFA = 17, - RDMA_DRIVER_SIW = 18, -}; - -enum ib_cq_notify_flags { - IB_CQ_SOLICITED = 1, - IB_CQ_NEXT_COMP = 2, - IB_CQ_SOLICITED_MASK = 3, - IB_CQ_REPORT_MISSED_EVENTS = 4, -}; - -struct ib_mad; - -enum rdma_link_layer { - IB_LINK_LAYER_UNSPECIFIED = 0, - IB_LINK_LAYER_INFINIBAND = 1, - IB_LINK_LAYER_ETHERNET = 2, -}; - -enum rdma_netdev_t { - RDMA_NETDEV_OPA_VNIC = 0, - RDMA_NETDEV_IPOIB = 1, -}; - -enum ib_srq_attr_mask { - IB_SRQ_MAX_WR = 1, - IB_SRQ_LIMIT = 2, -}; - -enum ib_mr_type { - IB_MR_TYPE_MEM_REG = 0, - IB_MR_TYPE_SG_GAPS = 1, - IB_MR_TYPE_DM = 2, - IB_MR_TYPE_USER = 3, - IB_MR_TYPE_DMA = 4, - IB_MR_TYPE_INTEGRITY = 5, -}; - -enum ib_uverbs_advise_mr_advice { - IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH = 0, - IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_WRITE = 1, - IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_NO_FAULT = 2, -}; - -struct uverbs_attr_bundle; - -struct rdma_cm_id; - -struct iw_cm_id; - -struct iw_cm_conn_param; - -struct ib_qp; - -struct ib_send_wr; - -struct ib_recv_wr; - -struct ib_cq; - -struct ib_wc; - -struct ib_srq; - -struct ib_grh; - -struct ib_device_attr; - -struct ib_udata; - -struct ib_device_modify; - -struct ib_port_attr; - -struct ib_port_modify; - -struct ib_port_immutable; - -struct rdma_netdev_alloc_params; - -union ib_gid; - -struct ib_gid_attr; - -struct ib_ucontext; - -struct rdma_user_mmap_entry; - -struct ib_pd; - -struct ib_ah; - -struct rdma_ah_init_attr; - -struct rdma_ah_attr; - -struct ib_srq_init_attr; - -struct ib_srq_attr; - -struct ib_qp_init_attr; - -struct ib_qp_attr; - -struct ib_cq_init_attr; - -struct ib_mr; - -struct ib_sge; - -struct ib_mr_status; - -struct ib_mw; - -struct ib_xrcd; - -struct ib_flow; - -struct ib_flow_attr; - -struct ib_flow_action; - -struct ib_flow_action_attrs_esp; - -struct ib_wq; - -struct ib_wq_init_attr; - -struct ib_wq_attr; - -struct ib_rwq_ind_table; - -struct ib_rwq_ind_table_init_attr; - -struct ib_dm; - -struct ib_dm_alloc_attr; - -struct ib_dm_mr_attr; - -struct ib_counters; - -struct ib_counters_read_attr; - -struct ib_device_ops { - struct module *owner; - enum rdma_driver_id driver_id; - u32 uverbs_abi_ver; - unsigned int uverbs_no_driver_id_binding: 1; - const struct attribute_group *device_group; - const struct attribute_group **port_groups; - int (*post_send)(struct ib_qp *, const struct ib_send_wr *, const struct ib_send_wr **); - int (*post_recv)(struct ib_qp *, const struct ib_recv_wr *, const struct ib_recv_wr **); - void (*drain_rq)(struct ib_qp *); - void (*drain_sq)(struct ib_qp *); - int (*poll_cq)(struct ib_cq *, int, struct ib_wc *); - int (*peek_cq)(struct ib_cq *, int); - int (*req_notify_cq)(struct ib_cq *, enum ib_cq_notify_flags); - int (*post_srq_recv)(struct ib_srq *, const struct ib_recv_wr *, const struct ib_recv_wr **); - int (*process_mad)(struct ib_device *, int, u32, const struct ib_wc *, const struct ib_grh *, const struct ib_mad *, struct ib_mad *, size_t *, u16 *); - int (*query_device)(struct ib_device *, struct ib_device_attr *, struct ib_udata *); - int (*modify_device)(struct ib_device *, int, struct ib_device_modify *); - void (*get_dev_fw_str)(struct ib_device *, char *); - const struct cpumask * (*get_vector_affinity)(struct ib_device *, int); - int (*query_port)(struct ib_device *, u32, struct ib_port_attr *); - int (*modify_port)(struct ib_device *, u32, int, struct ib_port_modify *); - int (*get_port_immutable)(struct ib_device *, u32, struct ib_port_immutable *); - enum rdma_link_layer (*get_link_layer)(struct ib_device *, u32); - struct net_device * (*get_netdev)(struct ib_device *, u32); - struct net_device * (*alloc_rdma_netdev)(struct ib_device *, u32, enum rdma_netdev_t, const char *, unsigned char, void (*)(struct net_device *)); - int (*rdma_netdev_get_params)(struct ib_device *, u32, enum rdma_netdev_t, struct rdma_netdev_alloc_params *); - int (*query_gid)(struct ib_device *, u32, int, union ib_gid *); - int (*add_gid)(const struct ib_gid_attr *, void **); - int (*del_gid)(const struct ib_gid_attr *, void **); - int (*query_pkey)(struct ib_device *, u32, u16, u16 *); - int (*alloc_ucontext)(struct ib_ucontext *, struct ib_udata *); - void (*dealloc_ucontext)(struct ib_ucontext *); - int (*mmap)(struct ib_ucontext *, struct vm_area_struct *); - void (*mmap_free)(struct rdma_user_mmap_entry *); - void (*disassociate_ucontext)(struct ib_ucontext *); - int (*alloc_pd)(struct ib_pd *, struct ib_udata *); - int (*dealloc_pd)(struct ib_pd *, struct ib_udata *); - int (*create_ah)(struct ib_ah *, struct rdma_ah_init_attr *, struct ib_udata *); - int (*create_user_ah)(struct ib_ah *, struct rdma_ah_init_attr *, struct ib_udata *); - int (*modify_ah)(struct ib_ah *, struct rdma_ah_attr *); - int (*query_ah)(struct ib_ah *, struct rdma_ah_attr *); - int (*destroy_ah)(struct ib_ah *, u32); - int (*create_srq)(struct ib_srq *, struct ib_srq_init_attr *, struct ib_udata *); - int (*modify_srq)(struct ib_srq *, struct ib_srq_attr *, enum ib_srq_attr_mask, struct ib_udata *); - int (*query_srq)(struct ib_srq *, struct ib_srq_attr *); - int (*destroy_srq)(struct ib_srq *, struct ib_udata *); - struct ib_qp * (*create_qp)(struct ib_pd *, struct ib_qp_init_attr *, struct ib_udata *); - int (*modify_qp)(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *); - int (*query_qp)(struct ib_qp *, struct ib_qp_attr *, int, struct ib_qp_init_attr *); - int (*destroy_qp)(struct ib_qp *, struct ib_udata *); - int (*create_cq)(struct ib_cq *, const struct ib_cq_init_attr *, struct ib_udata *); - int (*modify_cq)(struct ib_cq *, u16, u16); - int (*destroy_cq)(struct ib_cq *, struct ib_udata *); - int (*resize_cq)(struct ib_cq *, int, struct ib_udata *); - struct ib_mr * (*get_dma_mr)(struct ib_pd *, int); - struct ib_mr * (*reg_user_mr)(struct ib_pd *, u64, u64, u64, int, struct ib_udata *); - struct ib_mr * (*reg_user_mr_dmabuf)(struct ib_pd *, u64, u64, u64, int, int, struct ib_udata *); - struct ib_mr * (*rereg_user_mr)(struct ib_mr *, int, u64, u64, u64, int, struct ib_pd *, struct ib_udata *); - int (*dereg_mr)(struct ib_mr *, struct ib_udata *); - struct ib_mr * (*alloc_mr)(struct ib_pd *, enum ib_mr_type, u32); - struct ib_mr * (*alloc_mr_integrity)(struct ib_pd *, u32, u32); - int (*advise_mr)(struct ib_pd *, enum ib_uverbs_advise_mr_advice, u32, struct ib_sge *, u32, struct uverbs_attr_bundle *); - int (*map_mr_sg)(struct ib_mr *, struct scatterlist *, int, unsigned int *); - int (*check_mr_status)(struct ib_mr *, u32, struct ib_mr_status *); - int (*alloc_mw)(struct ib_mw *, struct ib_udata *); - int (*dealloc_mw)(struct ib_mw *); - int (*attach_mcast)(struct ib_qp *, union ib_gid *, u16); - int (*detach_mcast)(struct ib_qp *, union ib_gid *, u16); - int (*alloc_xrcd)(struct ib_xrcd *, struct ib_udata *); - int (*dealloc_xrcd)(struct ib_xrcd *, struct ib_udata *); - struct ib_flow * (*create_flow)(struct ib_qp *, struct ib_flow_attr *, struct ib_udata *); - int (*destroy_flow)(struct ib_flow *); - struct ib_flow_action * (*create_flow_action_esp)(struct ib_device *, const struct ib_flow_action_attrs_esp *, struct uverbs_attr_bundle *); - int (*destroy_flow_action)(struct ib_flow_action *); - int (*modify_flow_action_esp)(struct ib_flow_action *, const struct ib_flow_action_attrs_esp *, struct uverbs_attr_bundle *); - int (*set_vf_link_state)(struct ib_device *, int, u32, int); - int (*get_vf_config)(struct ib_device *, int, u32, struct ifla_vf_info *); - int (*get_vf_stats)(struct ib_device *, int, u32, struct ifla_vf_stats *); - int (*get_vf_guid)(struct ib_device *, int, u32, struct ifla_vf_guid *, struct ifla_vf_guid *); - int (*set_vf_guid)(struct ib_device *, int, u32, u64, int); - struct ib_wq * (*create_wq)(struct ib_pd *, struct ib_wq_init_attr *, struct ib_udata *); - int (*destroy_wq)(struct ib_wq *, struct ib_udata *); - int (*modify_wq)(struct ib_wq *, struct ib_wq_attr *, u32, struct ib_udata *); - int (*create_rwq_ind_table)(struct ib_rwq_ind_table *, struct ib_rwq_ind_table_init_attr *, struct ib_udata *); - int (*destroy_rwq_ind_table)(struct ib_rwq_ind_table *); - struct ib_dm * (*alloc_dm)(struct ib_device *, struct ib_ucontext *, struct ib_dm_alloc_attr *, struct uverbs_attr_bundle *); - int (*dealloc_dm)(struct ib_dm *, struct uverbs_attr_bundle *); - struct ib_mr * (*reg_dm_mr)(struct ib_pd *, struct ib_dm *, struct ib_dm_mr_attr *, struct uverbs_attr_bundle *); - int (*create_counters)(struct ib_counters *, struct uverbs_attr_bundle *); - int (*destroy_counters)(struct ib_counters *); - int (*read_counters)(struct ib_counters *, struct ib_counters_read_attr *, struct uverbs_attr_bundle *); - int (*map_mr_sg_pi)(struct ib_mr *, struct scatterlist *, int, unsigned int *, struct scatterlist *, int, unsigned int *); - struct rdma_hw_stats * (*alloc_hw_device_stats)(struct ib_device *); - struct rdma_hw_stats * (*alloc_hw_port_stats)(struct ib_device *, u32); - int (*get_hw_stats)(struct ib_device *, struct rdma_hw_stats *, u32, int); - int (*fill_res_mr_entry)(struct sk_buff *, struct ib_mr *); - int (*fill_res_mr_entry_raw)(struct sk_buff *, struct ib_mr *); - int (*fill_res_cq_entry)(struct sk_buff *, struct ib_cq *); - int (*fill_res_cq_entry_raw)(struct sk_buff *, struct ib_cq *); - int (*fill_res_qp_entry)(struct sk_buff *, struct ib_qp *); - int (*fill_res_qp_entry_raw)(struct sk_buff *, struct ib_qp *); - int (*fill_res_cm_id_entry)(struct sk_buff *, struct rdma_cm_id *); - int (*enable_driver)(struct ib_device *); - void (*dealloc_driver)(struct ib_device *); - void (*iw_add_ref)(struct ib_qp *); - void (*iw_rem_ref)(struct ib_qp *); - struct ib_qp * (*iw_get_qp)(struct ib_device *, int); - int (*iw_connect)(struct iw_cm_id *, struct iw_cm_conn_param *); - int (*iw_accept)(struct iw_cm_id *, struct iw_cm_conn_param *); - int (*iw_reject)(struct iw_cm_id *, const void *, u8); - int (*iw_create_listen)(struct iw_cm_id *, int); - int (*iw_destroy_listen)(struct iw_cm_id *); - int (*counter_bind_qp)(struct rdma_counter *, struct ib_qp *); - int (*counter_unbind_qp)(struct ib_qp *); - int (*counter_dealloc)(struct rdma_counter *); - struct rdma_hw_stats * (*counter_alloc_stats)(struct rdma_counter *); - int (*counter_update_stats)(struct rdma_counter *); - int (*fill_stat_mr_entry)(struct sk_buff *, struct ib_mr *); - int (*query_ucontext)(struct ib_ucontext *, struct uverbs_attr_bundle *); - size_t size_ib_ah; - size_t size_ib_counters; - size_t size_ib_cq; - size_t size_ib_mw; - size_t size_ib_pd; - size_t size_ib_rwq_ind_table; - size_t size_ib_srq; - size_t size_ib_ucontext; - size_t size_ib_xrcd; -}; - -struct ib_core_device { - struct device dev; - possible_net_t rdma_net; - struct kobject *ports_kobj; - struct list_head port_list; - struct ib_device *owner; -}; - -enum ib_atomic_cap { - IB_ATOMIC_NONE = 0, - IB_ATOMIC_HCA = 1, - IB_ATOMIC_GLOB = 2, -}; - -struct ib_odp_caps { - uint64_t general_caps; - struct { - uint32_t rc_odp_caps; - uint32_t uc_odp_caps; - uint32_t ud_odp_caps; - uint32_t xrc_odp_caps; - } per_transport_caps; -}; - -struct ib_rss_caps { - u32 supported_qpts; - u32 max_rwq_indirection_tables; - u32 max_rwq_indirection_table_size; -}; - -struct ib_tm_caps { - u32 max_rndv_hdr_size; - u32 max_num_tags; - u32 flags; - u32 max_ops; - u32 max_sge; -}; - -struct ib_cq_caps { - u16 max_cq_moderation_count; - u16 max_cq_moderation_period; -}; - -struct ib_device_attr { - u64 fw_ver; - __be64 sys_image_guid; - u64 max_mr_size; - u64 page_size_cap; - u32 vendor_id; - u32 vendor_part_id; - u32 hw_ver; - int max_qp; - int max_qp_wr; - u64 device_cap_flags; - int max_send_sge; - int max_recv_sge; - int max_sge_rd; - int max_cq; - int max_cqe; - int max_mr; - int max_pd; - int max_qp_rd_atom; - int max_ee_rd_atom; - int max_res_rd_atom; - int max_qp_init_rd_atom; - int max_ee_init_rd_atom; - enum ib_atomic_cap atomic_cap; - enum ib_atomic_cap masked_atomic_cap; - int max_ee; - int max_rdd; - int max_mw; - int max_raw_ipv6_qp; - int max_raw_ethy_qp; - int max_mcast_grp; - int max_mcast_qp_attach; - int max_total_mcast_qp_attach; - int max_ah; - int max_srq; - int max_srq_wr; - int max_srq_sge; - unsigned int max_fast_reg_page_list_len; - unsigned int max_pi_fast_reg_page_list_len; - u16 max_pkeys; - u8 local_ca_ack_delay; - int sig_prot_cap; - int sig_guard_cap; - struct ib_odp_caps odp_caps; - uint64_t timestamp_mask; - uint64_t hca_core_clock; - struct ib_rss_caps rss_caps; - u32 max_wq_type_rq; - u32 raw_packet_caps; - struct ib_tm_caps tm_caps; - struct ib_cq_caps cq_caps; - u64 max_dm_size; - u32 max_sgl_rd; -}; - -struct hw_stats_device_data; - -struct rdma_restrack_root; - -struct uapi_definition; - -struct ib_port_data; - -struct ib_device { - struct device *dma_device; - struct ib_device_ops ops; - char name[64]; - struct callback_head callback_head; - struct list_head event_handler_list; - struct rw_semaphore event_handler_rwsem; - spinlock_t qp_open_list_lock; - struct rw_semaphore client_data_rwsem; - struct xarray client_data; - struct mutex unregistration_lock; - rwlock_t cache_lock; - struct ib_port_data *port_data; - int num_comp_vectors; - union { - struct device dev; - struct ib_core_device coredev; - }; - const struct attribute_group *groups[4]; - u64 uverbs_cmd_mask; - char node_desc[64]; - __be64 node_guid; - u32 local_dma_lkey; - u16 is_switch: 1; - u16 kverbs_provider: 1; - u16 use_cq_dim: 1; - u8 node_type; - u32 phys_port_cnt; - struct ib_device_attr attrs; - struct hw_stats_device_data *hw_stats_data; - struct rdmacg_device cg_device; - u32 index; - spinlock_t cq_pools_lock; - struct list_head cq_pools[3]; - struct rdma_restrack_root *res; - const struct uapi_definition *driver_def; - refcount_t refcount; - struct completion unreg_completion; - struct work_struct unregistration_work; - const struct rdma_link_ops *link_ops; - struct mutex compat_devs_mutex; - struct xarray compat_devs; - char iw_ifname[16]; - u32 iw_driver_flags; - u32 lag_flags; -}; - -enum ib_signature_type { - IB_SIG_TYPE_NONE = 0, - IB_SIG_TYPE_T10_DIF = 1, -}; - -enum ib_t10_dif_bg_type { - IB_T10DIF_CRC = 0, - IB_T10DIF_CSUM = 1, -}; - -struct ib_t10_dif_domain { - enum ib_t10_dif_bg_type bg_type; - u16 pi_interval; - u16 bg; - u16 app_tag; - u32 ref_tag; - bool ref_remap; - bool app_escape; - bool ref_escape; - u16 apptag_check_mask; -}; - -struct ib_sig_domain { - enum ib_signature_type sig_type; - union { - struct ib_t10_dif_domain dif; - } sig; -}; - -struct ib_sig_attrs { - u8 check_mask; - struct ib_sig_domain mem; - struct ib_sig_domain wire; - int meta_length; -}; - -enum ib_sig_err_type { - IB_SIG_BAD_GUARD = 0, - IB_SIG_BAD_REFTAG = 1, - IB_SIG_BAD_APPTAG = 2, -}; - -struct ib_sig_err { - enum ib_sig_err_type err_type; - u32 expected; - u32 actual; - u64 sig_err_offset; - u32 key; -}; - -enum ib_uverbs_flow_action_esp_keymat { - IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM = 0, -}; - -struct ib_uverbs_flow_action_esp_keymat_aes_gcm { - __u64 iv; - __u32 iv_algo; - __u32 salt; - __u32 icv_len; - __u32 key_len; - __u32 aes_key[8]; -}; - -enum ib_uverbs_flow_action_esp_replay { - IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE = 0, - IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP = 1, -}; - -struct ib_uverbs_flow_action_esp_replay_bmp { - __u32 size; -}; - -union ib_gid { - u8 raw[16]; - struct { - __be64 subnet_prefix; - __be64 interface_id; - } global; -}; - -enum ib_gid_type { - IB_GID_TYPE_IB = 0, - IB_GID_TYPE_ROCE = 1, - IB_GID_TYPE_ROCE_UDP_ENCAP = 2, - IB_GID_TYPE_SIZE = 3, -}; - -struct ib_gid_attr { - struct net_device *ndev; - struct ib_device *device; - union ib_gid gid; - enum ib_gid_type gid_type; - u16 index; - u32 port_num; -}; - -struct ib_cq_init_attr { - unsigned int cqe; - u32 comp_vector; - u32 flags; -}; - -struct ib_dm_mr_attr { - u64 length; - u64 offset; - u32 access_flags; -}; - -struct ib_dm_alloc_attr { - u64 length; - u32 alignment; - u32 flags; -}; - -enum ib_mtu { - IB_MTU_256 = 1, - IB_MTU_512 = 2, - IB_MTU_1024 = 3, - IB_MTU_2048 = 4, - IB_MTU_4096 = 5, -}; - -enum ib_port_state { - IB_PORT_NOP = 0, - IB_PORT_DOWN = 1, - IB_PORT_INIT = 2, - IB_PORT_ARMED = 3, - IB_PORT_ACTIVE = 4, - IB_PORT_ACTIVE_DEFER = 5, -}; - -struct ib_port_attr { - u64 subnet_prefix; - enum ib_port_state state; - enum ib_mtu max_mtu; - enum ib_mtu active_mtu; - u32 phys_mtu; - int gid_tbl_len; - unsigned int ip_gids: 1; - u32 port_cap_flags; - u32 max_msg_sz; - u32 bad_pkey_cntr; - u32 qkey_viol_cntr; - u16 pkey_tbl_len; - u32 sm_lid; - u32 lid; - u8 lmc; - u8 max_vl_num; - u8 sm_sl; - u8 subnet_timeout; - u8 init_type_reply; - u8 active_width; - u16 active_speed; - u8 phys_state; - u16 port_cap_flags2; -}; - -struct ib_device_modify { - u64 sys_image_guid; - char node_desc[64]; -}; - -struct ib_port_modify { - u32 set_port_cap_mask; - u32 clr_port_cap_mask; - u8 init_type; -}; - -enum ib_event_type { - IB_EVENT_CQ_ERR = 0, - IB_EVENT_QP_FATAL = 1, - IB_EVENT_QP_REQ_ERR = 2, - IB_EVENT_QP_ACCESS_ERR = 3, - IB_EVENT_COMM_EST = 4, - IB_EVENT_SQ_DRAINED = 5, - IB_EVENT_PATH_MIG = 6, - IB_EVENT_PATH_MIG_ERR = 7, - IB_EVENT_DEVICE_FATAL = 8, - IB_EVENT_PORT_ACTIVE = 9, - IB_EVENT_PORT_ERR = 10, - IB_EVENT_LID_CHANGE = 11, - IB_EVENT_PKEY_CHANGE = 12, - IB_EVENT_SM_CHANGE = 13, - IB_EVENT_SRQ_ERR = 14, - IB_EVENT_SRQ_LIMIT_REACHED = 15, - IB_EVENT_QP_LAST_WQE_REACHED = 16, - IB_EVENT_CLIENT_REREGISTER = 17, - IB_EVENT_GID_CHANGE = 18, - IB_EVENT_WQ_FATAL = 19, -}; - -struct ib_ucq_object; - -typedef void (*ib_comp_handler)(struct ib_cq *, void *); - -struct ib_event; - -struct ib_cq { - struct ib_device *device; - struct ib_ucq_object *uobject; - ib_comp_handler comp_handler; - void (*event_handler)(struct ib_event *, void *); - void *cq_context; - int cqe; - unsigned int cqe_used; - atomic_t usecnt; - enum ib_poll_context poll_ctx; - struct ib_wc *wc; - struct list_head pool_entry; - union { - struct irq_poll iop; - struct work_struct work; - }; - struct workqueue_struct *comp_wq; - struct dim *dim; - ktime_t timestamp; - u8 interrupt: 1; - u8 shared: 1; - unsigned int comp_vector; - struct rdma_restrack_entry res; -}; - -struct ib_uqp_object; - -enum ib_qp_type { - IB_QPT_SMI = 0, - IB_QPT_GSI = 1, - IB_QPT_RC = 2, - IB_QPT_UC = 3, - IB_QPT_UD = 4, - IB_QPT_RAW_IPV6 = 5, - IB_QPT_RAW_ETHERTYPE = 6, - IB_QPT_RAW_PACKET = 8, - IB_QPT_XRC_INI = 9, - IB_QPT_XRC_TGT = 10, - IB_QPT_MAX = 11, - IB_QPT_DRIVER = 255, - IB_QPT_RESERVED1 = 4096, - IB_QPT_RESERVED2 = 4097, - IB_QPT_RESERVED3 = 4098, - IB_QPT_RESERVED4 = 4099, - IB_QPT_RESERVED5 = 4100, - IB_QPT_RESERVED6 = 4101, - IB_QPT_RESERVED7 = 4102, - IB_QPT_RESERVED8 = 4103, - IB_QPT_RESERVED9 = 4104, - IB_QPT_RESERVED10 = 4105, -}; - -struct ib_qp_security; - -struct ib_qp { - struct ib_device *device; - struct ib_pd *pd; - struct ib_cq *send_cq; - struct ib_cq *recv_cq; - spinlock_t mr_lock; - int mrs_used; - struct list_head rdma_mrs; - struct list_head sig_mrs; - struct ib_srq *srq; - struct ib_xrcd *xrcd; - struct list_head xrcd_list; - atomic_t usecnt; - struct list_head open_list; - struct ib_qp *real_qp; - struct ib_uqp_object *uobject; - void (*event_handler)(struct ib_event *, void *); - void *qp_context; - const struct ib_gid_attr *av_sgid_attr; - const struct ib_gid_attr *alt_path_sgid_attr; - u32 qp_num; - u32 max_write_sge; - u32 max_read_sge; - enum ib_qp_type qp_type; - struct ib_rwq_ind_table *rwq_ind_tbl; - struct ib_qp_security *qp_sec; - u32 port; - bool integrity_en; - struct rdma_restrack_entry res; - struct rdma_counter *counter; -}; - -struct ib_usrq_object; - -enum ib_srq_type { - IB_SRQT_BASIC = 0, - IB_SRQT_XRC = 1, - IB_SRQT_TM = 2, -}; - -struct ib_srq { - struct ib_device *device; - struct ib_pd *pd; - struct ib_usrq_object *uobject; - void (*event_handler)(struct ib_event *, void *); - void *srq_context; - enum ib_srq_type srq_type; - atomic_t usecnt; - struct { - struct ib_cq *cq; - union { - struct { - struct ib_xrcd *xrcd; - u32 srq_num; - } xrc; - }; - } ext; - struct rdma_restrack_entry res; -}; - -struct ib_uwq_object; - -enum ib_wq_state { - IB_WQS_RESET = 0, - IB_WQS_RDY = 1, - IB_WQS_ERR = 2, -}; - -enum ib_wq_type { - IB_WQT_RQ = 0, -}; - -struct ib_wq { - struct ib_device *device; - struct ib_uwq_object *uobject; - void *wq_context; - void (*event_handler)(struct ib_event *, void *); - struct ib_pd *pd; - struct ib_cq *cq; - u32 wq_num; - enum ib_wq_state state; - enum ib_wq_type wq_type; - atomic_t usecnt; -}; - -struct ib_event { - struct ib_device *device; - union { - struct ib_cq *cq; - struct ib_qp *qp; - struct ib_srq *srq; - struct ib_wq *wq; - u32 port_num; - } element; - enum ib_event_type event; -}; - -struct ib_global_route { - const struct ib_gid_attr *sgid_attr; - union ib_gid dgid; - u32 flow_label; - u8 sgid_index; - u8 hop_limit; - u8 traffic_class; -}; - -struct ib_grh { - __be32 version_tclass_flow; - __be16 paylen; - u8 next_hdr; - u8 hop_limit; - union ib_gid sgid; - union ib_gid dgid; -}; - -struct ib_mr_status { - u32 fail_status; - struct ib_sig_err sig_err; -}; - -struct rdma_ah_init_attr { - struct rdma_ah_attr *ah_attr; - u32 flags; - struct net_device *xmit_slave; -}; - -enum rdma_ah_attr_type { - RDMA_AH_ATTR_TYPE_UNDEFINED = 0, - RDMA_AH_ATTR_TYPE_IB = 1, - RDMA_AH_ATTR_TYPE_ROCE = 2, - RDMA_AH_ATTR_TYPE_OPA = 3, -}; - -struct ib_ah_attr { - u16 dlid; - u8 src_path_bits; -}; - -struct roce_ah_attr { - u8 dmac[6]; -}; - -struct opa_ah_attr { - u32 dlid; - u8 src_path_bits; - bool make_grd; -}; - -struct rdma_ah_attr { - struct ib_global_route grh; - u8 sl; - u8 static_rate; - u32 port_num; - u8 ah_flags; - enum rdma_ah_attr_type type; - union { - struct ib_ah_attr ib; - struct roce_ah_attr roce; - struct opa_ah_attr opa; - }; -}; - -enum ib_wc_status { - IB_WC_SUCCESS = 0, - IB_WC_LOC_LEN_ERR = 1, - IB_WC_LOC_QP_OP_ERR = 2, - IB_WC_LOC_EEC_OP_ERR = 3, - IB_WC_LOC_PROT_ERR = 4, - IB_WC_WR_FLUSH_ERR = 5, - IB_WC_MW_BIND_ERR = 6, - IB_WC_BAD_RESP_ERR = 7, - IB_WC_LOC_ACCESS_ERR = 8, - IB_WC_REM_INV_REQ_ERR = 9, - IB_WC_REM_ACCESS_ERR = 10, - IB_WC_REM_OP_ERR = 11, - IB_WC_RETRY_EXC_ERR = 12, - IB_WC_RNR_RETRY_EXC_ERR = 13, - IB_WC_LOC_RDD_VIOL_ERR = 14, - IB_WC_REM_INV_RD_REQ_ERR = 15, - IB_WC_REM_ABORT_ERR = 16, - IB_WC_INV_EECN_ERR = 17, - IB_WC_INV_EEC_STATE_ERR = 18, - IB_WC_FATAL_ERR = 19, - IB_WC_RESP_TIMEOUT_ERR = 20, - IB_WC_GENERAL_ERR = 21, -}; - -enum ib_wc_opcode { - IB_WC_SEND = 0, - IB_WC_RDMA_WRITE = 1, - IB_WC_RDMA_READ = 2, - IB_WC_COMP_SWAP = 3, - IB_WC_FETCH_ADD = 4, - IB_WC_BIND_MW = 5, - IB_WC_LOCAL_INV = 6, - IB_WC_LSO = 7, - IB_WC_REG_MR = 8, - IB_WC_MASKED_COMP_SWAP = 9, - IB_WC_MASKED_FETCH_ADD = 10, - IB_WC_RECV = 128, - IB_WC_RECV_RDMA_WITH_IMM = 129, -}; - -struct ib_cqe { - void (*done)(struct ib_cq *, struct ib_wc *); -}; - -struct ib_wc { - union { - u64 wr_id; - struct ib_cqe *wr_cqe; - }; - enum ib_wc_status status; - enum ib_wc_opcode opcode; - u32 vendor_err; - u32 byte_len; - struct ib_qp *qp; - union { - __be32 imm_data; - u32 invalidate_rkey; - } ex; - u32 src_qp; - u32 slid; - int wc_flags; - u16 pkey_index; - u8 sl; - u8 dlid_path_bits; - u32 port_num; - u8 smac[6]; - u16 vlan_id; - u8 network_hdr_type; -}; - -struct ib_srq_attr { - u32 max_wr; - u32 max_sge; - u32 srq_limit; -}; - -struct ib_xrcd { - struct ib_device *device; - atomic_t usecnt; - struct inode *inode; - struct rw_semaphore tgt_qps_rwsem; - struct xarray tgt_qps; -}; - -struct ib_srq_init_attr { - void (*event_handler)(struct ib_event *, void *); - void *srq_context; - struct ib_srq_attr attr; - enum ib_srq_type srq_type; - struct { - struct ib_cq *cq; - union { - struct { - struct ib_xrcd *xrcd; - } xrc; - struct { - u32 max_num_tags; - } tag_matching; - }; - } ext; -}; - -struct ib_qp_cap { - u32 max_send_wr; - u32 max_recv_wr; - u32 max_send_sge; - u32 max_recv_sge; - u32 max_inline_data; - u32 max_rdma_ctxs; -}; - -enum ib_sig_type { - IB_SIGNAL_ALL_WR = 0, - IB_SIGNAL_REQ_WR = 1, -}; - -struct ib_qp_init_attr { - void (*event_handler)(struct ib_event *, void *); - void *qp_context; - struct ib_cq *send_cq; - struct ib_cq *recv_cq; - struct ib_srq *srq; - struct ib_xrcd *xrcd; - struct ib_qp_cap cap; - enum ib_sig_type sq_sig_type; - enum ib_qp_type qp_type; - u32 create_flags; - u32 port_num; - struct ib_rwq_ind_table *rwq_ind_tbl; - u32 source_qpn; -}; - -struct ib_uobject; - -struct ib_rwq_ind_table { - struct ib_device *device; - struct ib_uobject *uobject; - atomic_t usecnt; - u32 ind_tbl_num; - u32 log_ind_tbl_size; - struct ib_wq **ind_tbl; -}; - -enum ib_qp_state { - IB_QPS_RESET = 0, - IB_QPS_INIT = 1, - IB_QPS_RTR = 2, - IB_QPS_RTS = 3, - IB_QPS_SQD = 4, - IB_QPS_SQE = 5, - IB_QPS_ERR = 6, -}; - -enum ib_mig_state { - IB_MIG_MIGRATED = 0, - IB_MIG_REARM = 1, - IB_MIG_ARMED = 2, -}; - -enum ib_mw_type { - IB_MW_TYPE_1 = 1, - IB_MW_TYPE_2 = 2, -}; - -struct ib_qp_attr { - enum ib_qp_state qp_state; - enum ib_qp_state cur_qp_state; - enum ib_mtu path_mtu; - enum ib_mig_state path_mig_state; - u32 qkey; - u32 rq_psn; - u32 sq_psn; - u32 dest_qp_num; - int qp_access_flags; - struct ib_qp_cap cap; - struct rdma_ah_attr ah_attr; - struct rdma_ah_attr alt_ah_attr; - u16 pkey_index; - u16 alt_pkey_index; - u8 en_sqd_async_notify; - u8 sq_draining; - u8 max_rd_atomic; - u8 max_dest_rd_atomic; - u8 min_rnr_timer; - u32 port_num; - u8 timeout; - u8 retry_cnt; - u8 rnr_retry; - u32 alt_port_num; - u8 alt_timeout; - u32 rate_limit; - struct net_device *xmit_slave; -}; - -enum ib_wr_opcode { - IB_WR_RDMA_WRITE = 0, - IB_WR_RDMA_WRITE_WITH_IMM = 1, - IB_WR_SEND = 2, - IB_WR_SEND_WITH_IMM = 3, - IB_WR_RDMA_READ = 4, - IB_WR_ATOMIC_CMP_AND_SWP = 5, - IB_WR_ATOMIC_FETCH_AND_ADD = 6, - IB_WR_BIND_MW = 8, - IB_WR_LSO = 10, - IB_WR_SEND_WITH_INV = 9, - IB_WR_RDMA_READ_WITH_INV = 11, - IB_WR_LOCAL_INV = 7, - IB_WR_MASKED_ATOMIC_CMP_AND_SWP = 12, - IB_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13, - IB_WR_REG_MR = 32, - IB_WR_REG_MR_INTEGRITY = 33, - IB_WR_RESERVED1 = 240, - IB_WR_RESERVED2 = 241, - IB_WR_RESERVED3 = 242, - IB_WR_RESERVED4 = 243, - IB_WR_RESERVED5 = 244, - IB_WR_RESERVED6 = 245, - IB_WR_RESERVED7 = 246, - IB_WR_RESERVED8 = 247, - IB_WR_RESERVED9 = 248, - IB_WR_RESERVED10 = 249, -}; - -struct ib_sge { - u64 addr; - u32 length; - u32 lkey; -}; - -struct ib_send_wr { - struct ib_send_wr *next; - union { - u64 wr_id; - struct ib_cqe *wr_cqe; - }; - struct ib_sge *sg_list; - int num_sge; - enum ib_wr_opcode opcode; - int send_flags; - union { - __be32 imm_data; - u32 invalidate_rkey; - } ex; -}; - -struct ib_ah { - struct ib_device *device; - struct ib_pd *pd; - struct ib_uobject *uobject; - const struct ib_gid_attr *sgid_attr; - enum rdma_ah_attr_type type; -}; - -struct ib_mr { - struct ib_device *device; - struct ib_pd *pd; - u32 lkey; - u32 rkey; - u64 iova; - u64 length; - unsigned int page_size; - enum ib_mr_type type; - bool need_inval; - union { - struct ib_uobject *uobject; - struct list_head qp_entry; - }; - struct ib_dm *dm; - struct ib_sig_attrs *sig_attrs; - struct rdma_restrack_entry res; -}; - -struct ib_recv_wr { - struct ib_recv_wr *next; - union { - u64 wr_id; - struct ib_cqe *wr_cqe; - }; - struct ib_sge *sg_list; - int num_sge; -}; - -struct ib_rdmacg_object { - struct rdma_cgroup *cg; -}; - -struct ib_uverbs_file; - -struct ib_ucontext { - struct ib_device *device; - struct ib_uverbs_file *ufile; - struct ib_rdmacg_object cg_obj; - struct rdma_restrack_entry res; - struct xarray mmap_xa; -}; - -struct uverbs_api_object; - -struct ib_uobject { - u64 user_handle; - struct ib_uverbs_file *ufile; - struct ib_ucontext *context; - void *object; - struct list_head list; - struct ib_rdmacg_object cg_obj; - int id; - struct kref ref; - atomic_t usecnt; - struct callback_head rcu; - const struct uverbs_api_object *uapi_object; -}; - -struct ib_udata { - const void *inbuf; - void *outbuf; - size_t inlen; - size_t outlen; -}; - -struct ib_pd { - u32 local_dma_lkey; - u32 flags; - struct ib_device *device; - struct ib_uobject *uobject; - atomic_t usecnt; - u32 unsafe_global_rkey; - struct ib_mr *__internal_mr; - struct rdma_restrack_entry res; -}; - -struct ib_wq_init_attr { - void *wq_context; - enum ib_wq_type wq_type; - u32 max_wr; - u32 max_sge; - struct ib_cq *cq; - void (*event_handler)(struct ib_event *, void *); - u32 create_flags; -}; - -struct ib_wq_attr { - enum ib_wq_state wq_state; - enum ib_wq_state curr_wq_state; - u32 flags; - u32 flags_mask; -}; - -struct ib_rwq_ind_table_init_attr { - u32 log_ind_tbl_size; - struct ib_wq **ind_tbl; -}; - -enum port_pkey_state { - IB_PORT_PKEY_NOT_VALID = 0, - IB_PORT_PKEY_VALID = 1, - IB_PORT_PKEY_LISTED = 2, -}; - -struct ib_port_pkey { - enum port_pkey_state state; - u16 pkey_index; - u32 port_num; - struct list_head qp_list; - struct list_head to_error_list; - struct ib_qp_security *sec; -}; - -struct ib_ports_pkeys; - -struct ib_qp_security { - struct ib_qp *qp; - struct ib_device *dev; - struct mutex mutex; - struct ib_ports_pkeys *ports_pkeys; - struct list_head shared_qp_list; - void *security; - bool destroying; - atomic_t error_list_count; - struct completion error_complete; - int error_comps_pending; -}; - -struct ib_ports_pkeys { - struct ib_port_pkey main; - struct ib_port_pkey alt; -}; - -struct ib_dm { - struct ib_device *device; - u32 length; - u32 flags; - struct ib_uobject *uobject; - atomic_t usecnt; -}; - -struct ib_mw { - struct ib_device *device; - struct ib_pd *pd; - struct ib_uobject *uobject; - u32 rkey; - enum ib_mw_type type; -}; - -enum ib_flow_attr_type { - IB_FLOW_ATTR_NORMAL = 0, - IB_FLOW_ATTR_ALL_DEFAULT = 1, - IB_FLOW_ATTR_MC_DEFAULT = 2, - IB_FLOW_ATTR_SNIFFER = 3, -}; - -enum ib_flow_spec_type { - IB_FLOW_SPEC_ETH = 32, - IB_FLOW_SPEC_IB = 34, - IB_FLOW_SPEC_IPV4 = 48, - IB_FLOW_SPEC_IPV6 = 49, - IB_FLOW_SPEC_ESP = 52, - IB_FLOW_SPEC_TCP = 64, - IB_FLOW_SPEC_UDP = 65, - IB_FLOW_SPEC_VXLAN_TUNNEL = 80, - IB_FLOW_SPEC_GRE = 81, - IB_FLOW_SPEC_MPLS = 96, - IB_FLOW_SPEC_INNER = 256, - IB_FLOW_SPEC_ACTION_TAG = 4096, - IB_FLOW_SPEC_ACTION_DROP = 4097, - IB_FLOW_SPEC_ACTION_HANDLE = 4098, - IB_FLOW_SPEC_ACTION_COUNT = 4099, -}; - -struct ib_flow_eth_filter { - u8 dst_mac[6]; - u8 src_mac[6]; - __be16 ether_type; - __be16 vlan_tag; - u8 real_sz[0]; -}; - -struct ib_flow_spec_eth { - u32 type; - u16 size; - struct ib_flow_eth_filter val; - struct ib_flow_eth_filter mask; -}; - -struct ib_flow_ib_filter { - __be16 dlid; - __u8 sl; - u8 real_sz[0]; -}; - -struct ib_flow_spec_ib { - u32 type; - u16 size; - struct ib_flow_ib_filter val; - struct ib_flow_ib_filter mask; -}; - -struct ib_flow_ipv4_filter { - __be32 src_ip; - __be32 dst_ip; - u8 proto; - u8 tos; - u8 ttl; - u8 flags; - u8 real_sz[0]; -}; - -struct ib_flow_spec_ipv4 { - u32 type; - u16 size; - struct ib_flow_ipv4_filter val; - struct ib_flow_ipv4_filter mask; -}; - -struct ib_flow_ipv6_filter { - u8 src_ip[16]; - u8 dst_ip[16]; - __be32 flow_label; - u8 next_hdr; - u8 traffic_class; - u8 hop_limit; - u8 real_sz[0]; -}; - -struct ib_flow_spec_ipv6 { - u32 type; - u16 size; - struct ib_flow_ipv6_filter val; - struct ib_flow_ipv6_filter mask; -}; - -struct ib_flow_tcp_udp_filter { - __be16 dst_port; - __be16 src_port; - u8 real_sz[0]; -}; - -struct ib_flow_spec_tcp_udp { - u32 type; - u16 size; - struct ib_flow_tcp_udp_filter val; - struct ib_flow_tcp_udp_filter mask; -}; - -struct ib_flow_tunnel_filter { - __be32 tunnel_id; - u8 real_sz[0]; -}; - -struct ib_flow_spec_tunnel { - u32 type; - u16 size; - struct ib_flow_tunnel_filter val; - struct ib_flow_tunnel_filter mask; -}; - -struct ib_flow_esp_filter { - __be32 spi; - __be32 seq; - u8 real_sz[0]; -}; - -struct ib_flow_spec_esp { - u32 type; - u16 size; - struct ib_flow_esp_filter val; - struct ib_flow_esp_filter mask; -}; - -struct ib_flow_gre_filter { - __be16 c_ks_res0_ver; - __be16 protocol; - __be32 key; - u8 real_sz[0]; -}; - -struct ib_flow_spec_gre { - u32 type; - u16 size; - struct ib_flow_gre_filter val; - struct ib_flow_gre_filter mask; -}; - -struct ib_flow_mpls_filter { - __be32 tag; - u8 real_sz[0]; -}; - -struct ib_flow_spec_mpls { - u32 type; - u16 size; - struct ib_flow_mpls_filter val; - struct ib_flow_mpls_filter mask; -}; - -struct ib_flow_spec_action_tag { - enum ib_flow_spec_type type; - u16 size; - u32 tag_id; -}; - -struct ib_flow_spec_action_drop { - enum ib_flow_spec_type type; - u16 size; -}; - -struct ib_flow_spec_action_handle { - enum ib_flow_spec_type type; - u16 size; - struct ib_flow_action *act; -}; - -enum ib_flow_action_type { - IB_FLOW_ACTION_UNSPECIFIED = 0, - IB_FLOW_ACTION_ESP = 1, -}; - -struct ib_flow_action { - struct ib_device *device; - struct ib_uobject *uobject; - enum ib_flow_action_type type; - atomic_t usecnt; -}; - -struct ib_flow_spec_action_count { - enum ib_flow_spec_type type; - u16 size; - struct ib_counters *counters; -}; - -struct ib_counters { - struct ib_device *device; - struct ib_uobject *uobject; - atomic_t usecnt; -}; - -union ib_flow_spec { - struct { - u32 type; - u16 size; - }; - struct ib_flow_spec_eth eth; - struct ib_flow_spec_ib ib; - struct ib_flow_spec_ipv4 ipv4; - struct ib_flow_spec_tcp_udp tcp_udp; - struct ib_flow_spec_ipv6 ipv6; - struct ib_flow_spec_tunnel tunnel; - struct ib_flow_spec_esp esp; - struct ib_flow_spec_gre gre; - struct ib_flow_spec_mpls mpls; - struct ib_flow_spec_action_tag flow_tag; - struct ib_flow_spec_action_drop drop; - struct ib_flow_spec_action_handle action; - struct ib_flow_spec_action_count flow_count; -}; - -struct ib_flow_attr { - enum ib_flow_attr_type type; - u16 size; - u16 priority; - u32 flags; - u8 num_of_specs; - u32 port; - union ib_flow_spec flows[0]; -}; - -struct ib_flow { - struct ib_qp *qp; - struct ib_device *device; - struct ib_uobject *uobject; -}; - -struct ib_flow_action_attrs_esp_keymats { - enum ib_uverbs_flow_action_esp_keymat protocol; - union { - struct ib_uverbs_flow_action_esp_keymat_aes_gcm aes_gcm; - } keymat; -}; - -struct ib_flow_action_attrs_esp_replays { - enum ib_uverbs_flow_action_esp_replay protocol; - union { - struct ib_uverbs_flow_action_esp_replay_bmp bmp; - } replay; -}; - -struct ib_flow_spec_list { - struct ib_flow_spec_list *next; - union ib_flow_spec spec; -}; - -struct ib_flow_action_attrs_esp { - struct ib_flow_action_attrs_esp_keymats *keymat; - struct ib_flow_action_attrs_esp_replays *replay; - struct ib_flow_spec_list *encap; - u32 esn; - u32 spi; - u32 seq; - u32 tfc_pad; - u64 flags; - u64 hard_limit_pkts; -}; - -struct ib_pkey_cache; - -struct ib_gid_table; - -struct ib_port_cache { - u64 subnet_prefix; - struct ib_pkey_cache *pkey; - struct ib_gid_table *gid; - u8 lmc; - enum ib_port_state port_state; -}; - -struct ib_port_immutable { - int pkey_tbl_len; - int gid_tbl_len; - u32 core_cap_flags; - u32 max_mad_size; -}; - -struct ib_port; - -struct ib_port_data { - struct ib_device *ib_dev; - struct ib_port_immutable immutable; - spinlock_t pkey_list_lock; - spinlock_t netdev_lock; - struct list_head pkey_list; - struct ib_port_cache cache; - struct net_device *netdev; - struct hlist_node ndev_hash_link; - struct rdma_port_counter port_counter; - struct ib_port *sysfs; -}; - -struct rdma_netdev_alloc_params { - size_t sizeof_priv; - unsigned int txqs; - unsigned int rxqs; - void *param; - int (*initialize_rdma_netdev)(struct ib_device *, u32, struct net_device *, void *); -}; - -struct ib_counters_read_attr { - u64 *counters_buff; - u32 ncounters; - u32 flags; -}; - -struct rdma_user_mmap_entry { - struct kref ref; - struct ib_ucontext *ucontext; - long unsigned int start_pgoff; - size_t npages; - bool driver_removed; -}; - -enum blk_zone_type { - BLK_ZONE_TYPE_CONVENTIONAL = 1, - BLK_ZONE_TYPE_SEQWRITE_REQ = 2, - BLK_ZONE_TYPE_SEQWRITE_PREF = 3, -}; - -enum blk_zone_cond { - BLK_ZONE_COND_NOT_WP = 0, - BLK_ZONE_COND_EMPTY = 1, - BLK_ZONE_COND_IMP_OPEN = 2, - BLK_ZONE_COND_EXP_OPEN = 3, - BLK_ZONE_COND_CLOSED = 4, - BLK_ZONE_COND_READONLY = 13, - BLK_ZONE_COND_FULL = 14, - BLK_ZONE_COND_OFFLINE = 15, -}; - -enum blk_zone_report_flags { - BLK_ZONE_REP_CAPACITY = 1, -}; - -struct blk_zone_report { - __u64 sector; - __u32 nr_zones; - __u32 flags; - struct blk_zone zones[0]; -}; - -struct blk_zone_range { - __u64 sector; - __u64 nr_sectors; -}; - -struct zone_report_args { - struct blk_zone *zones; -}; - -struct blk_revalidate_zone_args { - struct gendisk *disk; - long unsigned int *conv_zones_bitmap; - long unsigned int *seq_zones_wlock; - unsigned int nr_zones; - sector_t zone_sectors; - sector_t sector; -}; - -enum wbt_flags { - WBT_TRACKED = 1, - WBT_READ = 2, - WBT_KSWAPD = 4, - WBT_DISCARD = 8, - WBT_NR_BITS = 4, -}; - -enum { - WBT_STATE_ON_DEFAULT = 1, - WBT_STATE_ON_MANUAL = 2, - WBT_STATE_OFF_DEFAULT = 3, -}; - -struct rq_wb { - unsigned int wb_background; - unsigned int wb_normal; - short int enable_state; - unsigned int unknown_cnt; - u64 win_nsec; - u64 cur_win_nsec; - struct blk_stat_callback *cb; - u64 sync_issue; - void *sync_cookie; - unsigned int wc; - long unsigned int last_issue; - long unsigned int last_comp; - long unsigned int min_lat_nsec; - struct rq_qos rqos; - struct rq_wait rq_wait[3]; - struct rq_depth rq_depth; -}; - -struct trace_event_raw_wbt_stat { - struct trace_entry ent; - char name[32]; - s64 rmean; - u64 rmin; - u64 rmax; - s64 rnr_samples; - s64 rtime; - s64 wmean; - u64 wmin; - u64 wmax; - s64 wnr_samples; - s64 wtime; - char __data[0]; -}; - -struct trace_event_raw_wbt_lat { - struct trace_entry ent; - char name[32]; - long unsigned int lat; - char __data[0]; -}; - -struct trace_event_raw_wbt_step { - struct trace_entry ent; - char name[32]; - const char *msg; - int step; - long unsigned int window; - unsigned int bg; - unsigned int normal; - unsigned int max; - char __data[0]; -}; - -struct trace_event_raw_wbt_timer { - struct trace_entry ent; - char name[32]; - unsigned int status; - int step; - unsigned int inflight; - char __data[0]; -}; - -struct trace_event_data_offsets_wbt_stat {}; - -struct trace_event_data_offsets_wbt_lat {}; - -struct trace_event_data_offsets_wbt_step {}; - -struct trace_event_data_offsets_wbt_timer {}; - -typedef void (*btf_trace_wbt_stat)(void *, struct backing_dev_info *, struct blk_rq_stat *); - -typedef void (*btf_trace_wbt_lat)(void *, struct backing_dev_info *, long unsigned int); - -typedef void (*btf_trace_wbt_step)(void *, struct backing_dev_info *, const char *, int, long unsigned int, unsigned int, unsigned int, unsigned int); - -typedef void (*btf_trace_wbt_timer)(void *, struct backing_dev_info *, unsigned int, int, unsigned int); - -enum { - RWB_DEF_DEPTH = 16, - RWB_WINDOW_NSEC = 100000000, - RWB_MIN_WRITE_SAMPLES = 3, - RWB_UNKNOWN_BUMP = 5, -}; - -enum { - LAT_OK = 1, - LAT_UNKNOWN = 2, - LAT_UNKNOWN_WRITES = 3, - LAT_EXCEEDED = 4, -}; - -struct wbt_wait_data { - struct rq_wb *rwb; - enum wbt_flags wb_acct; - long unsigned int rw; -}; - -struct show_busy_params { - struct seq_file *m; - struct blk_mq_hw_ctx *hctx; -}; - -enum opal_mbr { - OPAL_MBR_ENABLE = 0, - OPAL_MBR_DISABLE = 1, -}; - -enum opal_mbr_done_flag { - OPAL_MBR_NOT_DONE = 0, - OPAL_MBR_DONE = 1, -}; - -enum opal_user { - OPAL_ADMIN1 = 0, - OPAL_USER1 = 1, - OPAL_USER2 = 2, - OPAL_USER3 = 3, - OPAL_USER4 = 4, - OPAL_USER5 = 5, - OPAL_USER6 = 6, - OPAL_USER7 = 7, - OPAL_USER8 = 8, - OPAL_USER9 = 9, -}; - -enum opal_lock_state { - OPAL_RO = 1, - OPAL_RW = 2, - OPAL_LK = 4, -}; - -struct opal_key { - __u8 lr; - __u8 key_len; - __u8 __align[6]; - __u8 key[256]; -}; - -struct opal_lr_act { - struct opal_key key; - __u32 sum; - __u8 num_lrs; - __u8 lr[9]; - __u8 align[2]; -}; - -struct opal_session_info { - __u32 sum; - __u32 who; - struct opal_key opal_key; -}; - -struct opal_user_lr_setup { - __u64 range_start; - __u64 range_length; - __u32 RLE; - __u32 WLE; - struct opal_session_info session; -}; - -struct opal_lock_unlock { - struct opal_session_info session; - __u32 l_state; - __u8 __align[4]; -}; - -struct opal_new_pw { - struct opal_session_info session; - struct opal_session_info new_user_pw; -}; - -struct opal_mbr_data { - struct opal_key key; - __u8 enable_disable; - __u8 __align[7]; -}; - -struct opal_mbr_done { - struct opal_key key; - __u8 done_flag; - __u8 __align[7]; -}; - -struct opal_shadow_mbr { - struct opal_key key; - const __u64 data; - __u64 offset; - __u64 size; -}; - -enum opal_table_ops { - OPAL_READ_TABLE = 0, - OPAL_WRITE_TABLE = 1, -}; - -struct opal_read_write_table { - struct opal_key key; - const __u64 data; - const __u8 table_uid[8]; - __u64 offset; - __u64 size; - __u64 flags; - __u64 priv; -}; - -typedef int sec_send_recv(void *, u16, u8, void *, size_t, bool); - -enum { - TCG_SECP_00 = 0, - TCG_SECP_01 = 1, -}; - -enum opal_response_token { - OPAL_DTA_TOKENID_BYTESTRING = 224, - OPAL_DTA_TOKENID_SINT = 225, - OPAL_DTA_TOKENID_UINT = 226, - OPAL_DTA_TOKENID_TOKEN = 227, - OPAL_DTA_TOKENID_INVALID = 0, -}; - -enum opal_uid { - OPAL_SMUID_UID = 0, - OPAL_THISSP_UID = 1, - OPAL_ADMINSP_UID = 2, - OPAL_LOCKINGSP_UID = 3, - OPAL_ENTERPRISE_LOCKINGSP_UID = 4, - OPAL_ANYBODY_UID = 5, - OPAL_SID_UID = 6, - OPAL_ADMIN1_UID = 7, - OPAL_USER1_UID = 8, - OPAL_USER2_UID = 9, - OPAL_PSID_UID = 10, - OPAL_ENTERPRISE_BANDMASTER0_UID = 11, - OPAL_ENTERPRISE_ERASEMASTER_UID = 12, - OPAL_TABLE_TABLE = 13, - OPAL_LOCKINGRANGE_GLOBAL = 14, - OPAL_LOCKINGRANGE_ACE_RDLOCKED = 15, - OPAL_LOCKINGRANGE_ACE_WRLOCKED = 16, - OPAL_MBRCONTROL = 17, - OPAL_MBR = 18, - OPAL_AUTHORITY_TABLE = 19, - OPAL_C_PIN_TABLE = 20, - OPAL_LOCKING_INFO_TABLE = 21, - OPAL_ENTERPRISE_LOCKING_INFO_TABLE = 22, - OPAL_DATASTORE = 23, - OPAL_C_PIN_MSID = 24, - OPAL_C_PIN_SID = 25, - OPAL_C_PIN_ADMIN1 = 26, - OPAL_HALF_UID_AUTHORITY_OBJ_REF = 27, - OPAL_HALF_UID_BOOLEAN_ACE = 28, - OPAL_UID_HEXFF = 29, -}; - -enum opal_method { - OPAL_PROPERTIES = 0, - OPAL_STARTSESSION = 1, - OPAL_REVERT = 2, - OPAL_ACTIVATE = 3, - OPAL_EGET = 4, - OPAL_ESET = 5, - OPAL_NEXT = 6, - OPAL_EAUTHENTICATE = 7, - OPAL_GETACL = 8, - OPAL_GENKEY = 9, - OPAL_REVERTSP = 10, - OPAL_GET = 11, - OPAL_SET = 12, - OPAL_AUTHENTICATE = 13, - OPAL_RANDOM = 14, - OPAL_ERASE = 15, -}; - -enum opal_token { - OPAL_TRUE = 1, - OPAL_FALSE = 0, - OPAL_BOOLEAN_EXPR = 3, - OPAL_TABLE = 0, - OPAL_STARTROW = 1, - OPAL_ENDROW = 2, - OPAL_STARTCOLUMN = 3, - OPAL_ENDCOLUMN = 4, - OPAL_VALUES = 1, - OPAL_TABLE_UID = 0, - OPAL_TABLE_NAME = 1, - OPAL_TABLE_COMMON = 2, - OPAL_TABLE_TEMPLATE = 3, - OPAL_TABLE_KIND = 4, - OPAL_TABLE_COLUMN = 5, - OPAL_TABLE_COLUMNS = 6, - OPAL_TABLE_ROWS = 7, - OPAL_TABLE_ROWS_FREE = 8, - OPAL_TABLE_ROW_BYTES = 9, - OPAL_TABLE_LASTID = 10, - OPAL_TABLE_MIN = 11, - OPAL_TABLE_MAX = 12, - OPAL_PIN = 3, - OPAL_RANGESTART = 3, - OPAL_RANGELENGTH = 4, - OPAL_READLOCKENABLED = 5, - OPAL_WRITELOCKENABLED = 6, - OPAL_READLOCKED = 7, - OPAL_WRITELOCKED = 8, - OPAL_ACTIVEKEY = 10, - OPAL_LIFECYCLE = 6, - OPAL_MAXRANGES = 4, - OPAL_MBRENABLE = 1, - OPAL_MBRDONE = 2, - OPAL_HOSTPROPERTIES = 0, - OPAL_STARTLIST = 240, - OPAL_ENDLIST = 241, - OPAL_STARTNAME = 242, - OPAL_ENDNAME = 243, - OPAL_CALL = 248, - OPAL_ENDOFDATA = 249, - OPAL_ENDOFSESSION = 250, - OPAL_STARTTRANSACTON = 251, - OPAL_ENDTRANSACTON = 252, - OPAL_EMPTYATOM = 255, - OPAL_WHERE = 0, -}; - -enum opal_parameter { - OPAL_SUM_SET_LIST = 393216, -}; - -struct opal_compacket { - __be32 reserved0; - u8 extendedComID[4]; - __be32 outstandingData; - __be32 minTransfer; - __be32 length; -}; - -struct opal_packet { - __be32 tsn; - __be32 hsn; - __be32 seq_number; - __be16 reserved0; - __be16 ack_type; - __be32 acknowledgment; - __be32 length; -}; - -struct opal_data_subpacket { - u8 reserved0[6]; - __be16 kind; - __be32 length; -}; - -struct opal_header { - struct opal_compacket cp; - struct opal_packet pkt; - struct opal_data_subpacket subpkt; -}; - -struct d0_header { - __be32 length; - __be32 revision; - __be32 reserved01; - __be32 reserved02; - u8 ignored[32]; -}; - -struct d0_tper_features { - u8 supported_features; - u8 reserved01[3]; - __be32 reserved02; - __be32 reserved03; -}; - -struct d0_locking_features { - u8 supported_features; - u8 reserved01[3]; - __be32 reserved02; - __be32 reserved03; -}; - -struct d0_geometry_features { - u8 header[4]; - u8 reserved01; - u8 reserved02[7]; - __be32 logical_block_size; - __be64 alignment_granularity; - __be64 lowest_aligned_lba; -}; - -struct d0_opal_v100 { - __be16 baseComID; - __be16 numComIDs; -}; - -struct d0_single_user_mode { - __be32 num_locking_objects; - u8 reserved01; - u8 reserved02; - __be16 reserved03; - __be32 reserved04; -}; - -struct d0_opal_v200 { - __be16 baseComID; - __be16 numComIDs; - u8 range_crossing; - u8 num_locking_admin_auth[2]; - u8 num_locking_user_auth[2]; - u8 initialPIN; - u8 revertedPIN; - u8 reserved01; - __be32 reserved02; -}; - -struct d0_features { - __be16 code; - u8 r_version; - u8 length; - u8 features[0]; -}; - -struct opal_dev; - -struct opal_step { - int (*fn)(struct opal_dev *, void *); - void *data; -}; - -enum opal_atom_width { - OPAL_WIDTH_TINY = 0, - OPAL_WIDTH_SHORT = 1, - OPAL_WIDTH_MEDIUM = 2, - OPAL_WIDTH_LONG = 3, - OPAL_WIDTH_TOKEN = 4, -}; - -struct opal_resp_tok { - const u8 *pos; - size_t len; - enum opal_response_token type; - enum opal_atom_width width; - union { - u64 u; - s64 s; - } stored; -}; - -struct parsed_resp { - int num; - struct opal_resp_tok toks[64]; -}; - -struct opal_dev { - bool supported; - bool mbr_enabled; - void *data; - sec_send_recv *send_recv; - struct mutex dev_lock; - u16 comid; - u32 hsn; - u32 tsn; - u64 align; - u64 lowest_lba; - size_t pos; - u8 cmd[2048]; - u8 resp[2048]; - struct parsed_resp parsed; - size_t prev_d_len; - void *prev_data; - struct list_head unlk_lst; -}; - -typedef int cont_fn(struct opal_dev *); - -struct opal_suspend_data { - struct opal_lock_unlock unlk; - u8 lr; - struct list_head node; -}; - -struct blk_ksm_keyslot { - atomic_t slot_refs; - struct list_head idle_slot_node; - struct hlist_node hash_node; - const struct blk_crypto_key *key; - struct blk_keyslot_manager *ksm; -}; - -struct blk_ksm_ll_ops { - int (*keyslot_program)(struct blk_keyslot_manager *, const struct blk_crypto_key *, unsigned int); - int (*keyslot_evict)(struct blk_keyslot_manager *, const struct blk_crypto_key *, unsigned int); -}; - -struct blk_keyslot_manager { - struct blk_ksm_ll_ops ksm_ll_ops; - unsigned int max_dun_bytes_supported; - unsigned int crypto_modes_supported[4]; - struct device *dev; - unsigned int num_slots; - struct rw_semaphore lock; - wait_queue_head_t idle_slots_wait_queue; - struct list_head idle_slots; - spinlock_t idle_slots_lock; - struct hlist_head *slot_hashtable; - unsigned int log_slot_ht_size; - struct blk_ksm_keyslot *slots; -}; - -struct blk_crypto_mode { - const char *cipher_str; - unsigned int keysize; - unsigned int ivsize; -}; - -struct bio_fallback_crypt_ctx { - struct bio_crypt_ctx crypt_ctx; - struct bvec_iter crypt_iter; - union { - struct { - struct work_struct work; - struct bio *bio; - }; - struct { - void *bi_private_orig; - bio_end_io_t *bi_end_io_orig; - }; - }; -}; - -struct blk_crypto_keyslot { - enum blk_crypto_mode_num crypto_mode; - struct crypto_skcipher *tfms[4]; -}; - -union blk_crypto_iv { - __le64 dun[4]; - u8 bytes[32]; -}; - -typedef int (*cmp_r_func_t)(const void *, const void *, const void *); - -struct random_ready_callback { - struct list_head list; - void (*func)(struct random_ready_callback *); - struct module *owner; -}; - -struct siprand_state { - long unsigned int v0; - long unsigned int v1; - long unsigned int v2; - long unsigned int v3; -}; - -struct region { - unsigned int start; - unsigned int off; - unsigned int group_len; - unsigned int end; - unsigned int nbits; -}; - -enum { - REG_OP_ISFREE = 0, - REG_OP_ALLOC = 1, - REG_OP_RELEASE = 2, -}; - -typedef struct scatterlist *sg_alloc_fn(unsigned int, gfp_t); - -typedef void sg_free_fn(struct scatterlist *, unsigned int); - -struct sg_page_iter { - struct scatterlist *sg; - unsigned int sg_pgoffset; - unsigned int __nents; - int __pg_advance; -}; - -struct sg_dma_page_iter { - struct sg_page_iter base; -}; - -struct sg_mapping_iter { - struct page *page; - void *addr; - size_t length; - size_t consumed; - struct sg_page_iter piter; - unsigned int __offset; - unsigned int __remaining; - unsigned int __flags; -}; - -struct csum_state { - __wsum csum; - size_t off; -}; - -struct rhltable { - struct rhashtable ht; -}; - -struct rhashtable_walker { - struct list_head list; - struct bucket_table *tbl; -}; - -struct rhashtable_iter { - struct rhashtable *ht; - struct rhash_head *p; - struct rhlist_head *list; - struct rhashtable_walker walker; - unsigned int slot; - unsigned int skip; - bool end_of_table; -}; - -union nested_table { - union nested_table *table; - struct rhash_lock_head *bucket; -}; - -struct once_work { - struct work_struct work; - struct static_key_true *key; - struct module *module; -}; - -struct genradix_iter { - size_t offset; - size_t pos; -}; - -struct genradix_node { - union { - struct genradix_node *children[512]; - u8 data[4096]; - }; -}; - -struct reciprocal_value_adv { - u32 m; - u8 sh; - u8 exp; - bool is_wide_m; -}; - -enum devm_ioremap_type { - DEVM_IOREMAP = 0, - DEVM_IOREMAP_UC = 1, - DEVM_IOREMAP_WC = 2, - DEVM_IOREMAP_NP = 3, -}; - -struct pcim_iomap_devres { - void *table[6]; -}; - -struct btree_head { - long unsigned int *node; - mempool_t *mempool; - int height; -}; - -struct btree_geo { - int keylen; - int no_pairs; - int no_longs; -}; - -typedef void (*visitor128_t)(void *, long unsigned int, u64, u64, size_t); - -typedef void (*visitorl_t)(void *, long unsigned int, long unsigned int, size_t); - -typedef void (*visitor32_t)(void *, long unsigned int, u32, size_t); - -typedef void (*visitor64_t)(void *, long unsigned int, u64, size_t); - -enum assoc_array_walk_status { - assoc_array_walk_tree_empty = 0, - assoc_array_walk_found_terminal_node = 1, - assoc_array_walk_found_wrong_shortcut = 2, -}; - -struct assoc_array_walk_result { - struct { - struct assoc_array_node *node; - int level; - int slot; - } terminal_node; - struct { - struct assoc_array_shortcut *shortcut; - int level; - int sc_level; - long unsigned int sc_segments; - long unsigned int dissimilarity; - } wrong_shortcut; -}; - -struct assoc_array_delete_collapse_context { - struct assoc_array_node *node; - const void *skip_leaf; - int slot; -}; - -struct linear_range { - unsigned int min; - unsigned int min_sel; - unsigned int max_sel; - unsigned int step; -}; - -enum packing_op { - PACK = 0, - UNPACK = 1, -}; - -struct xxh32_state { - uint32_t total_len_32; - uint32_t large_len; - uint32_t v1; - uint32_t v2; - uint32_t v3; - uint32_t v4; - uint32_t mem32[4]; - uint32_t memsize; -}; - -struct xxh64_state { - uint64_t total_len; - uint64_t v1; - uint64_t v2; - uint64_t v3; - uint64_t v4; - uint64_t mem64[4]; - uint32_t memsize; -}; - -struct gen_pool_chunk { - struct list_head next_chunk; - atomic_long_t avail; - phys_addr_t phys_addr; - void *owner; - long unsigned int start_addr; - long unsigned int end_addr; - long unsigned int bits[0]; -}; - -struct genpool_data_align { - int align; -}; - -struct genpool_data_fixed { - long unsigned int offset; -}; - -typedef struct { - unsigned char op; - unsigned char bits; - short unsigned int val; -} code; - -typedef enum { - HEAD = 0, - FLAGS = 1, - TIME = 2, - OS = 3, - EXLEN = 4, - EXTRA = 5, - NAME = 6, - COMMENT = 7, - HCRC = 8, - DICTID = 9, - DICT = 10, - TYPE = 11, - TYPEDO = 12, - STORED = 13, - COPY = 14, - TABLE = 15, - LENLENS = 16, - CODELENS = 17, - LEN = 18, - LENEXT = 19, - DIST = 20, - DISTEXT = 21, - MATCH = 22, - LIT = 23, - CHECK = 24, - LENGTH = 25, - DONE = 26, - BAD = 27, - MEM = 28, - SYNC = 29, -} inflate_mode; - -struct inflate_state { - inflate_mode mode; - int last; - int wrap; - int havedict; - int flags; - unsigned int dmax; - long unsigned int check; - long unsigned int total; - unsigned int wbits; - unsigned int wsize; - unsigned int whave; - unsigned int write; - unsigned char *window; - long unsigned int hold; - unsigned int bits; - unsigned int length; - unsigned int offset; - unsigned int extra; - const code *lencode; - const code *distcode; - unsigned int lenbits; - unsigned int distbits; - unsigned int ncode; - unsigned int nlen; - unsigned int ndist; - unsigned int have; - code *next; - short unsigned int lens[320]; - short unsigned int work[288]; - code codes[2048]; -}; - -union uu { - short unsigned int us; - unsigned char b[2]; -}; - -typedef unsigned int uInt; - -typedef enum { - CODES = 0, - LENS = 1, - DISTS = 2, -} codetype; - -struct inflate_workspace { - struct inflate_state inflate_state; - unsigned char working_window[32768]; -}; - -typedef unsigned char uch; - -typedef short unsigned int ush; - -typedef long unsigned int ulg; - -struct ct_data_s { - union { - ush freq; - ush code; - } fc; - union { - ush dad; - ush len; - } dl; -}; - -typedef struct ct_data_s ct_data; - -struct static_tree_desc_s { - const ct_data *static_tree; - const int *extra_bits; - int extra_base; - int elems; - int max_length; -}; - -typedef struct static_tree_desc_s static_tree_desc; - -struct tree_desc_s { - ct_data *dyn_tree; - int max_code; - static_tree_desc *stat_desc; -}; - -typedef ush Pos; - -typedef unsigned int IPos; - -struct deflate_state { - z_streamp strm; - int status; - Byte *pending_buf; - ulg pending_buf_size; - Byte *pending_out; - int pending; - int noheader; - Byte data_type; - Byte method; - int last_flush; - uInt w_size; - uInt w_bits; - uInt w_mask; - Byte *window; - ulg window_size; - Pos *prev; - Pos *head; - uInt ins_h; - uInt hash_size; - uInt hash_bits; - uInt hash_mask; - uInt hash_shift; - long int block_start; - uInt match_length; - IPos prev_match; - int match_available; - uInt strstart; - uInt match_start; - uInt lookahead; - uInt prev_length; - uInt max_chain_length; - uInt max_lazy_match; - int level; - int strategy; - uInt good_match; - int nice_match; - struct ct_data_s dyn_ltree[573]; - struct ct_data_s dyn_dtree[61]; - struct ct_data_s bl_tree[39]; - struct tree_desc_s l_desc; - struct tree_desc_s d_desc; - struct tree_desc_s bl_desc; - ush bl_count[16]; - int heap[573]; - int heap_len; - int heap_max; - uch depth[573]; - uch *l_buf; - uInt lit_bufsize; - uInt last_lit; - ush *d_buf; - ulg opt_len; - ulg static_len; - ulg compressed_len; - uInt matches; - int last_eob_len; - ush bi_buf; - int bi_valid; -}; - -typedef struct deflate_state deflate_state; - -typedef enum { - need_more = 0, - block_done = 1, - finish_started = 2, - finish_done = 3, -} block_state; - -typedef block_state (*compress_func)(deflate_state *, int); - -struct deflate_workspace { - deflate_state deflate_memory; - Byte *window_memory; - Pos *prev_memory; - Pos *head_memory; - char *overlay_memory; -}; - -typedef struct deflate_workspace deflate_workspace; - -struct config_s { - ush good_length; - ush max_lazy; - ush nice_length; - ush max_chain; - compress_func func; -}; - -typedef struct config_s config; - -typedef struct tree_desc_s tree_desc; - -typedef struct { - uint32_t hashTable[4096]; - uint32_t currentOffset; - uint32_t initCheck; - const uint8_t *dictionary; - uint8_t *bufferStart; - uint32_t dictSize; -} LZ4_stream_t_internal; - -typedef union { - long long unsigned int table[2052]; - LZ4_stream_t_internal internal_donotuse; -} LZ4_stream_t; - -typedef uint8_t BYTE; - -typedef uint16_t U16; - -typedef uint32_t U32; - -typedef uint64_t U64; - -typedef uintptr_t uptrval; - -typedef enum { - noLimit = 0, - limitedOutput = 1, -} limitedOutput_directive; - -typedef enum { - byPtr = 0, - byU32 = 1, - byU16 = 2, -} tableType_t; - -typedef enum { - noDict = 0, - withPrefix64k = 1, - usingExtDict = 2, -} dict_directive; - -typedef enum { - noDictIssue = 0, - dictSmall = 1, -} dictIssue_directive; - -typedef struct { - const uint8_t *externalDict; - size_t extDictSize; - const uint8_t *prefixEnd; - size_t prefixSize; -} LZ4_streamDecode_t_internal; - -typedef union { - long long unsigned int table[4]; - LZ4_streamDecode_t_internal internal_donotuse; -} LZ4_streamDecode_t; - -typedef enum { - endOnOutputSize = 0, - endOnInputSize = 1, -} endCondition_directive; - -typedef enum { - decode_full_block = 0, - partial_decode = 1, -} earlyEnd_directive; - -typedef struct { - size_t bitContainer; - int bitPos; - char *startPtr; - char *ptr; - char *endPtr; -} BIT_CStream_t; - -typedef unsigned int FSE_CTable; - -typedef struct { - ptrdiff_t value; - const void *stateTable; - const void *symbolTT; - unsigned int stateLog; -} FSE_CState_t; - -typedef struct { - int deltaFindState; - U32 deltaNbBits; -} FSE_symbolCompressionTransform; - -typedef int16_t S16; - -struct HUF_CElt_s { - U16 val; - BYTE nbBits; -}; - -typedef struct HUF_CElt_s HUF_CElt; - -typedef enum { - HUF_repeat_none = 0, - HUF_repeat_check = 1, - HUF_repeat_valid = 2, -} HUF_repeat; - -struct nodeElt_s { - U32 count; - U16 parent; - BYTE byte; - BYTE nbBits; -}; - -typedef struct nodeElt_s nodeElt; - -typedef struct { - U32 base; - U32 curr; -} rankPos; - -typedef enum { - ZSTDcs_created = 0, - ZSTDcs_init = 1, - ZSTDcs_ongoing = 2, - ZSTDcs_ending = 3, -} ZSTD_compressionStage_e; - -typedef void * (*ZSTD_allocFunction)(void *, size_t); - -typedef void (*ZSTD_freeFunction)(void *, void *); - -typedef struct { - ZSTD_allocFunction customAlloc; - ZSTD_freeFunction customFree; - void *opaque; -} ZSTD_customMem; - -typedef struct { - U32 price; - U32 off; - U32 mlen; - U32 litlen; - U32 rep[3]; -} ZSTD_optimal_t; - -typedef struct { - U32 off; - U32 len; -} ZSTD_match_t; - -struct seqDef_s; - -typedef struct seqDef_s seqDef; - -typedef struct { - seqDef *sequencesStart; - seqDef *sequences; - BYTE *litStart; - BYTE *lit; - BYTE *llCode; - BYTE *mlCode; - BYTE *ofCode; - U32 longLengthID; - U32 longLengthPos; - ZSTD_optimal_t *priceTable; - ZSTD_match_t *matchTable; - U32 *matchLengthFreq; - U32 *litLengthFreq; - U32 *litFreq; - U32 *offCodeFreq; - U32 matchLengthSum; - U32 matchSum; - U32 litLengthSum; - U32 litSum; - U32 offCodeSum; - U32 log2matchLengthSum; - U32 log2matchSum; - U32 log2litLengthSum; - U32 log2litSum; - U32 log2offCodeSum; - U32 factor; - U32 staticPrices; - U32 cachedPrice; - U32 cachedLitLength; - const BYTE *cachedLiterals; -} seqStore_t; - -struct HUF_CElt_s___2; - -typedef struct HUF_CElt_s___2 HUF_CElt___2; - -struct ZSTD_CCtx_s___2 { - const BYTE *nextSrc; - const BYTE *base; - const BYTE *dictBase; - U32 dictLimit; - U32 lowLimit; - U32 nextToUpdate; - U32 nextToUpdate3; - U32 hashLog3; - U32 loadedDictEnd; - U32 forceWindow; - U32 forceRawDict; - ZSTD_compressionStage_e stage; - U32 rep[3]; - U32 repToConfirm[3]; - U32 dictID; - ZSTD_parameters params; - void *workSpace; - size_t workSpaceSize; - size_t blockSize; - U64 frameContentSize; - struct xxh64_state xxhState; - ZSTD_customMem customMem; - seqStore_t seqStore; - U32 *hashTable; - U32 *hashTable3; - U32 *chainTable; - HUF_CElt___2 *hufTable; - U32 flagStaticTables; - HUF_repeat flagStaticHufTable; - FSE_CTable offcodeCTable[187]; - FSE_CTable matchlengthCTable[363]; - FSE_CTable litlengthCTable[329]; - unsigned int tmpCounters[1536]; -}; - -typedef struct ZSTD_CCtx_s___2 ZSTD_CCtx___2; - -struct ZSTD_CDict_s { - void *dictBuffer; - const void *dictContent; - size_t dictContentSize; - ZSTD_CCtx___2 *refContext; -}; - -typedef struct ZSTD_CDict_s ZSTD_CDict; - -struct ZSTD_inBuffer_s { - const void *src; - size_t size; - size_t pos; -}; - -typedef struct ZSTD_inBuffer_s ZSTD_inBuffer; - -struct ZSTD_outBuffer_s { - void *dst; - size_t size; - size_t pos; -}; - -typedef struct ZSTD_outBuffer_s ZSTD_outBuffer; - -typedef enum { - zcss_init = 0, - zcss_load = 1, - zcss_flush = 2, - zcss_final = 3, -} ZSTD_cStreamStage; - -struct ZSTD_CStream_s { - ZSTD_CCtx___2 *cctx; - ZSTD_CDict *cdictLocal; - const ZSTD_CDict *cdict; - char *inBuff; - size_t inBuffSize; - size_t inToCompress; - size_t inBuffPos; - size_t inBuffTarget; - size_t blockSize; - char *outBuff; - size_t outBuffSize; - size_t outBuffContentSize; - size_t outBuffFlushedSize; - ZSTD_cStreamStage stage; - U32 checksum; - U32 frameEnded; - U64 pledgedSrcSize; - U64 inputProcessed; - ZSTD_parameters params; - ZSTD_customMem customMem; -}; - -typedef struct ZSTD_CStream_s ZSTD_CStream; - -typedef int32_t S32; - -typedef enum { - set_basic = 0, - set_rle = 1, - set_compressed = 2, - set_repeat = 3, -} symbolEncodingType_e; - -struct seqDef_s { - U32 offset; - U16 litLength; - U16 matchLength; -}; - -typedef enum { - ZSTDcrp_continue = 0, - ZSTDcrp_noMemset = 1, - ZSTDcrp_fullReset = 2, -} ZSTD_compResetPolicy_e; - -typedef void (*ZSTD_blockCompressor)(ZSTD_CCtx___2 *, const void *, size_t); - -typedef enum { - zsf_gather = 0, - zsf_flush = 1, - zsf_end = 2, -} ZSTD_flush_e; - -typedef size_t (*searchMax_f)(ZSTD_CCtx___2 *, const BYTE *, const BYTE *, size_t *, U32, U32); - -typedef struct { - size_t bitContainer; - unsigned int bitsConsumed; - const char *ptr; - const char *start; -} BIT_DStream_t; - -typedef enum { - BIT_DStream_unfinished = 0, - BIT_DStream_endOfBuffer = 1, - BIT_DStream_completed = 2, - BIT_DStream_overflow = 3, -} BIT_DStream_status; - -typedef unsigned int FSE_DTable; - -typedef struct { - size_t state; - const void *table; -} FSE_DState_t; - -typedef struct { - U16 tableLog; - U16 fastMode; -} FSE_DTableHeader; - -typedef struct { - short unsigned int newState; - unsigned char symbol; - unsigned char nbBits; -} FSE_decode_t; - -typedef struct { - void *ptr; - const void *end; -} ZSTD_stack; - -typedef U32 HUF_DTable; - -typedef struct { - BYTE maxTableLog; - BYTE tableType; - BYTE tableLog; - BYTE reserved; -} DTableDesc; - -typedef struct { - BYTE byte; - BYTE nbBits; -} HUF_DEltX2; - -typedef struct { - U16 sequence; - BYTE nbBits; - BYTE length; -} HUF_DEltX4; - -typedef struct { - BYTE symbol; - BYTE weight; -} sortedSymbol_t; - -typedef U32 rankValCol_t[13]; - -typedef struct { - U32 tableTime; - U32 decode256Time; -} algo_time_t; - -typedef struct { - FSE_DTable LLTable[513]; - FSE_DTable OFTable[257]; - FSE_DTable MLTable[513]; - HUF_DTable hufTable[4097]; - U64 workspace[384]; - U32 rep[3]; -} ZSTD_entropyTables_t; - -typedef struct { - long long unsigned int frameContentSize; - unsigned int windowSize; - unsigned int dictID; - unsigned int checksumFlag; -} ZSTD_frameParams; - -typedef enum { - bt_raw = 0, - bt_rle = 1, - bt_compressed = 2, - bt_reserved = 3, -} blockType_e; - -typedef enum { - ZSTDds_getFrameHeaderSize = 0, - ZSTDds_decodeFrameHeader = 1, - ZSTDds_decodeBlockHeader = 2, - ZSTDds_decompressBlock = 3, - ZSTDds_decompressLastBlock = 4, - ZSTDds_checkChecksum = 5, - ZSTDds_decodeSkippableHeader = 6, - ZSTDds_skipFrame = 7, -} ZSTD_dStage; - -struct ZSTD_DCtx_s___2 { - const FSE_DTable *LLTptr; - const FSE_DTable *MLTptr; - const FSE_DTable *OFTptr; - const HUF_DTable *HUFptr; - ZSTD_entropyTables_t entropy; - const void *previousDstEnd; - const void *base; - const void *vBase; - const void *dictEnd; - size_t expected; - ZSTD_frameParams fParams; - blockType_e bType; - ZSTD_dStage stage; - U32 litEntropy; - U32 fseEntropy; - struct xxh64_state xxhState; - size_t headerSize; - U32 dictID; - const BYTE *litPtr; - ZSTD_customMem customMem; - size_t litSize; - size_t rleSize; - BYTE litBuffer[131080]; - BYTE headerBuffer[18]; -}; - -typedef struct ZSTD_DCtx_s___2 ZSTD_DCtx___2; - -struct ZSTD_DDict_s { - void *dictBuffer; - const void *dictContent; - size_t dictSize; - ZSTD_entropyTables_t entropy; - U32 dictID; - U32 entropyPresent; - ZSTD_customMem cMem; -}; - -typedef struct ZSTD_DDict_s ZSTD_DDict; - -typedef enum { - zdss_init = 0, - zdss_loadHeader = 1, - zdss_read = 2, - zdss_load = 3, - zdss_flush = 4, -} ZSTD_dStreamStage; - -struct ZSTD_DStream_s { - ZSTD_DCtx___2 *dctx; - ZSTD_DDict *ddictLocal; - const ZSTD_DDict *ddict; - ZSTD_frameParams fParams; - ZSTD_dStreamStage stage; - char *inBuff; - size_t inBuffSize; - size_t inPos; - size_t maxWindowSize; - char *outBuff; - size_t outBuffSize; - size_t outStart; - size_t outEnd; - size_t blockSize; - BYTE headerBuffer[18]; - size_t lhSize; - ZSTD_customMem customMem; - void *legacyContext; - U32 previousLegacyVersion; - U32 legacyVersion; - U32 hostageByte; -}; - -typedef struct ZSTD_DStream_s ZSTD_DStream; - -typedef enum { - ZSTDnit_frameHeader = 0, - ZSTDnit_blockHeader = 1, - ZSTDnit_block = 2, - ZSTDnit_lastBlock = 3, - ZSTDnit_checksum = 4, - ZSTDnit_skippableFrame = 5, -} ZSTD_nextInputType_e; - -typedef uintptr_t uPtrDiff; - -typedef struct { - blockType_e blockType; - U32 lastBlock; - U32 origSize; -} blockProperties_t; - -typedef union { - FSE_decode_t realData; - U32 alignedBy4; -} FSE_decode_t4; - -typedef struct { - size_t litLength; - size_t matchLength; - size_t offset; - const BYTE *match; -} seq_t; - -typedef struct { - BIT_DStream_t DStream; - FSE_DState_t stateLL; - FSE_DState_t stateOffb; - FSE_DState_t stateML; - size_t prevOffset[3]; - const BYTE *base; - size_t pos; - uPtrDiff gotoDict; -} seqState_t; - -enum xz_mode { - XZ_SINGLE = 0, - XZ_PREALLOC = 1, - XZ_DYNALLOC = 2, -}; - -enum xz_ret { - XZ_OK = 0, - XZ_STREAM_END = 1, - XZ_UNSUPPORTED_CHECK = 2, - XZ_MEM_ERROR = 3, - XZ_MEMLIMIT_ERROR = 4, - XZ_FORMAT_ERROR = 5, - XZ_OPTIONS_ERROR = 6, - XZ_DATA_ERROR = 7, - XZ_BUF_ERROR = 8, -}; - -struct xz_buf { - const uint8_t *in; - size_t in_pos; - size_t in_size; - uint8_t *out; - size_t out_pos; - size_t out_size; -}; - -struct xz_dec; - -typedef uint64_t vli_type; - -enum xz_check { - XZ_CHECK_NONE = 0, - XZ_CHECK_CRC32 = 1, - XZ_CHECK_CRC64 = 4, - XZ_CHECK_SHA256 = 10, -}; - -struct xz_dec_hash { - vli_type unpadded; - vli_type uncompressed; - uint32_t crc32; -}; - -struct xz_dec_lzma2; - -struct xz_dec_bcj; - -struct xz_dec___2 { - enum { - SEQ_STREAM_HEADER = 0, - SEQ_BLOCK_START = 1, - SEQ_BLOCK_HEADER = 2, - SEQ_BLOCK_UNCOMPRESS = 3, - SEQ_BLOCK_PADDING = 4, - SEQ_BLOCK_CHECK = 5, - SEQ_INDEX = 6, - SEQ_INDEX_PADDING = 7, - SEQ_INDEX_CRC32 = 8, - SEQ_STREAM_FOOTER = 9, - } sequence; - uint32_t pos; - vli_type vli; - size_t in_start; - size_t out_start; - uint32_t crc32; - enum xz_check check_type; - enum xz_mode mode; - bool allow_buf_error; - struct { - vli_type compressed; - vli_type uncompressed; - uint32_t size; - } block_header; - struct { - vli_type compressed; - vli_type uncompressed; - vli_type count; - struct xz_dec_hash hash; - } block; - struct { - enum { - SEQ_INDEX_COUNT = 0, - SEQ_INDEX_UNPADDED = 1, - SEQ_INDEX_UNCOMPRESSED = 2, - } sequence; - vli_type size; - vli_type count; - struct xz_dec_hash hash; - } index; - struct { - size_t pos; - size_t size; - uint8_t buf[1024]; - } temp; - struct xz_dec_lzma2 *lzma2; - struct xz_dec_bcj *bcj; - bool bcj_active; -}; - -enum lzma_state { - STATE_LIT_LIT = 0, - STATE_MATCH_LIT_LIT = 1, - STATE_REP_LIT_LIT = 2, - STATE_SHORTREP_LIT_LIT = 3, - STATE_MATCH_LIT = 4, - STATE_REP_LIT = 5, - STATE_SHORTREP_LIT = 6, - STATE_LIT_MATCH = 7, - STATE_LIT_LONGREP = 8, - STATE_LIT_SHORTREP = 9, - STATE_NONLIT_MATCH = 10, - STATE_NONLIT_REP = 11, -}; - -struct dictionary { - uint8_t *buf; - size_t start; - size_t pos; - size_t full; - size_t limit; - size_t end; - uint32_t size; - uint32_t size_max; - uint32_t allocated; - enum xz_mode mode; -}; - -struct rc_dec { - uint32_t range; - uint32_t code; - uint32_t init_bytes_left; - const uint8_t *in; - size_t in_pos; - size_t in_limit; -}; - -struct lzma_len_dec { - uint16_t choice; - uint16_t choice2; - uint16_t low[128]; - uint16_t mid[128]; - uint16_t high[256]; -}; - -struct lzma_dec { - uint32_t rep0; - uint32_t rep1; - uint32_t rep2; - uint32_t rep3; - enum lzma_state state; - uint32_t len; - uint32_t lc; - uint32_t literal_pos_mask; - uint32_t pos_mask; - uint16_t is_match[192]; - uint16_t is_rep[12]; - uint16_t is_rep0[12]; - uint16_t is_rep1[12]; - uint16_t is_rep2[12]; - uint16_t is_rep0_long[192]; - uint16_t dist_slot[256]; - uint16_t dist_special[114]; - uint16_t dist_align[16]; - struct lzma_len_dec match_len_dec; - struct lzma_len_dec rep_len_dec; - uint16_t literal[12288]; -}; - -enum lzma2_seq { - SEQ_CONTROL = 0, - SEQ_UNCOMPRESSED_1 = 1, - SEQ_UNCOMPRESSED_2 = 2, - SEQ_COMPRESSED_0 = 3, - SEQ_COMPRESSED_1 = 4, - SEQ_PROPERTIES = 5, - SEQ_LZMA_PREPARE = 6, - SEQ_LZMA_RUN = 7, - SEQ_COPY = 8, -}; - -struct lzma2_dec { - enum lzma2_seq sequence; - enum lzma2_seq next_sequence; - uint32_t uncompressed; - uint32_t compressed; - bool need_dict_reset; - bool need_props; -}; - -struct xz_dec_lzma2___2 { - struct rc_dec rc; - struct dictionary dict; - struct lzma2_dec lzma2; - struct lzma_dec lzma; - struct { - uint32_t size; - uint8_t buf[63]; - } temp; -}; - -struct xz_dec_bcj___2 { - enum { - BCJ_X86 = 4, - BCJ_POWERPC = 5, - BCJ_IA64 = 6, - BCJ_ARM = 7, - BCJ_ARMTHUMB = 8, - BCJ_SPARC = 9, - } type; - enum xz_ret ret; - bool single_call; - uint32_t pos; - uint32_t x86_prev_mask; - uint8_t *out; - size_t out_pos; - size_t out_size; - struct { - size_t filtered; - size_t size; - uint8_t buf[16]; - } temp; -}; - -struct ts_state { - unsigned int offset; - char cb[48]; -}; - -struct ts_config; - -struct ts_ops { - const char *name; - struct ts_config * (*init)(const void *, unsigned int, gfp_t, int); - unsigned int (*find)(struct ts_config *, struct ts_state *); - void (*destroy)(struct ts_config *); - void * (*get_pattern)(struct ts_config *); - unsigned int (*get_pattern_len)(struct ts_config *); - struct module *owner; - struct list_head list; -}; - -struct ts_config { - struct ts_ops *ops; - int flags; - unsigned int (*get_next_block)(unsigned int, const u8 **, struct ts_config *, struct ts_state *); - void (*finish)(struct ts_config *, struct ts_state *); -}; - -struct ts_linear_state { - unsigned int len; - const void *data; -}; - -struct ei_entry { - struct list_head list; - long unsigned int start_addr; - long unsigned int end_addr; - int etype; - void *priv; -}; - -struct ddebug_table { - struct list_head link; - const char *mod_name; - unsigned int num_ddebugs; - struct _ddebug *ddebugs; -}; - -struct ddebug_query { - const char *filename; - const char *module; - const char *function; - const char *format; - unsigned int first_lineno; - unsigned int last_lineno; -}; - -struct ddebug_iter { - struct ddebug_table *table; - unsigned int idx; -}; - -struct flag_settings { - unsigned int flags; - unsigned int mask; -}; - -struct flagsbuf { - char buf[7]; -}; - -struct nla_bitfield32 { - __u32 value; - __u32 selector; -}; - -enum nla_policy_validation { - NLA_VALIDATE_NONE = 0, - NLA_VALIDATE_RANGE = 1, - NLA_VALIDATE_RANGE_WARN_TOO_LONG = 2, - NLA_VALIDATE_MIN = 3, - NLA_VALIDATE_MAX = 4, - NLA_VALIDATE_MASK = 5, - NLA_VALIDATE_RANGE_PTR = 6, - NLA_VALIDATE_FUNCTION = 7, -}; - -enum netlink_validation { - NL_VALIDATE_LIBERAL = 0, - NL_VALIDATE_TRAILING = 1, - NL_VALIDATE_MAXTYPE = 2, - NL_VALIDATE_UNSPEC = 4, - NL_VALIDATE_STRICT_ATTRS = 8, - NL_VALIDATE_NESTED = 16, -}; - -struct cpu_rmap { - struct kref refcount; - u16 size; - u16 used; - void **obj; - struct { - u16 index; - u16 dist; - } near[0]; -}; - -struct irq_glue { - struct irq_affinity_notify notify; - struct cpu_rmap *rmap; - u16 index; -}; - -typedef mpi_limb_t *mpi_ptr_t; - -typedef int mpi_size_t; - -typedef mpi_limb_t UWtype; - -typedef unsigned int UHWtype; - -enum gcry_mpi_constants { - MPI_C_ZERO = 0, - MPI_C_ONE = 1, - MPI_C_TWO = 2, - MPI_C_THREE = 3, - MPI_C_FOUR = 4, - MPI_C_EIGHT = 5, -}; - -struct barrett_ctx_s; - -typedef struct barrett_ctx_s *mpi_barrett_t; - -struct gcry_mpi_point { - MPI x; - MPI y; - MPI z; -}; - -typedef struct gcry_mpi_point *MPI_POINT; - -enum gcry_mpi_ec_models { - MPI_EC_WEIERSTRASS = 0, - MPI_EC_MONTGOMERY = 1, - MPI_EC_EDWARDS = 2, -}; - -enum ecc_dialects { - ECC_DIALECT_STANDARD = 0, - ECC_DIALECT_ED25519 = 1, - ECC_DIALECT_SAFECURVE = 2, -}; - -struct mpi_ec_ctx { - enum gcry_mpi_ec_models model; - enum ecc_dialects dialect; - int flags; - unsigned int nbits; - MPI p; - MPI a; - MPI b; - MPI_POINT G; - MPI n; - unsigned int h; - MPI_POINT Q; - MPI d; - const char *name; - struct { - struct { - unsigned int a_is_pminus3: 1; - unsigned int two_inv_p: 1; - } valid; - int a_is_pminus3; - MPI two_inv_p; - mpi_barrett_t p_barrett; - MPI scratch[11]; - } t; - void (*addm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*subm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*mulm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*pow2)(MPI, const MPI, struct mpi_ec_ctx *); - void (*mul2)(MPI, MPI, struct mpi_ec_ctx *); -}; - -struct field_table { - const char *p; - void (*addm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*subm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*mulm)(MPI, MPI, MPI, struct mpi_ec_ctx *); - void (*mul2)(MPI, MPI, struct mpi_ec_ctx *); - void (*pow2)(MPI, const MPI, struct mpi_ec_ctx *); -}; - -enum gcry_mpi_format { - GCRYMPI_FMT_NONE = 0, - GCRYMPI_FMT_STD = 1, - GCRYMPI_FMT_PGP = 2, - GCRYMPI_FMT_SSH = 3, - GCRYMPI_FMT_HEX = 4, - GCRYMPI_FMT_USG = 5, - GCRYMPI_FMT_OPAQUE = 8, -}; - -struct barrett_ctx_s___2; - -typedef struct barrett_ctx_s___2 *mpi_barrett_t___2; - -struct barrett_ctx_s___2 { - MPI m; - int m_copied; - int k; - MPI y; - MPI r1; - MPI r2; - MPI r3; -}; - -struct karatsuba_ctx { - struct karatsuba_ctx *next; - mpi_ptr_t tspace; - mpi_size_t tspace_size; - mpi_ptr_t tp; - mpi_size_t tp_size; -}; - -typedef long int mpi_limb_signed_t; - -enum dim_tune_state { - DIM_PARKING_ON_TOP = 0, - DIM_PARKING_TIRED = 1, - DIM_GOING_RIGHT = 2, - DIM_GOING_LEFT = 3, -}; - -struct dim_cq_moder { - u16 usec; - u16 pkts; - u16 comps; - u8 cq_period_mode; -}; - -enum dim_cq_period_mode { - DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0, - DIM_CQ_PERIOD_MODE_START_FROM_CQE = 1, - DIM_CQ_PERIOD_NUM_MODES = 2, -}; - -enum dim_state { - DIM_START_MEASURE = 0, - DIM_MEASURE_IN_PROGRESS = 1, - DIM_APPLY_NEW_PROFILE = 2, -}; - -enum dim_stats_state { - DIM_STATS_WORSE = 0, - DIM_STATS_SAME = 1, - DIM_STATS_BETTER = 2, -}; - -enum dim_step_result { - DIM_STEPPED = 0, - DIM_TOO_TIRED = 1, - DIM_ON_EDGE = 2, -}; - -struct sg_pool { - size_t size; - char *name; - struct kmem_cache *slab; - mempool_t *pool; -}; - -enum { - IRQ_POLL_F_SCHED = 0, - IRQ_POLL_F_DISABLE = 1, -}; - -struct font_desc { - int idx; - const char *name; - unsigned int width; - unsigned int height; - unsigned int charcount; - const void *data; - int pref; -}; - -struct font_data { - unsigned int extra[4]; - const unsigned char data[0]; -}; - -struct pldmfw_record { - struct list_head entry; - struct list_head descs; - const u8 *version_string; - u8 version_type; - u8 version_len; - u16 package_data_len; - u32 device_update_flags; - const u8 *package_data; - long unsigned int *component_bitmap; - u16 component_bitmap_len; -}; - -struct pldmfw_desc_tlv { - struct list_head entry; - const u8 *data; - u16 type; - u16 size; -}; - -struct pldmfw_component { - struct list_head entry; - u16 classification; - u16 identifier; - u16 options; - u16 activation_method; - u32 comparison_stamp; - u32 component_size; - const u8 *component_data; - const u8 *version_string; - u8 version_type; - u8 version_len; - u8 index; -}; - -struct pldmfw_ops; - -struct pldmfw { - const struct pldmfw_ops *ops; - struct device *dev; -}; - -struct pldmfw_ops { - bool (*match_record)(struct pldmfw *, struct pldmfw_record *); - int (*send_package_data)(struct pldmfw *, const u8 *, u16); - int (*send_component_table)(struct pldmfw *, struct pldmfw_component *, u8); - int (*flash_component)(struct pldmfw *, struct pldmfw_component *); - int (*finalize_update)(struct pldmfw *); -}; - -struct __pldm_timestamp { - u8 b[13]; -}; - -struct __pldm_header { - uuid_t id; - u8 revision; - __le16 size; - struct __pldm_timestamp release_date; - __le16 component_bitmap_len; - u8 version_type; - u8 version_len; - u8 version_string[0]; -} __attribute__((packed)); - -struct __pldmfw_record_info { - __le16 record_len; - u8 descriptor_count; - __le32 device_update_flags; - u8 version_type; - u8 version_len; - __le16 package_data_len; - u8 variable_record_data[0]; -} __attribute__((packed)); - -struct __pldmfw_desc_tlv { - __le16 type; - __le16 size; - u8 data[0]; -}; - -struct __pldmfw_record_area { - u8 record_count; - u8 records[0]; -}; - -struct __pldmfw_component_info { - __le16 classification; - __le16 identifier; - __le32 comparison_stamp; - __le16 options; - __le16 activation_method; - __le32 location_offset; - __le32 size; - u8 version_type; - u8 version_len; - u8 version_string[0]; -} __attribute__((packed)); - -struct __pldmfw_component_area { - __le16 component_image_count; - u8 components[0]; -}; - -struct pldmfw_priv { - struct pldmfw *context; - const struct firmware *fw; - size_t offset; - struct list_head records; - struct list_head components; - const struct __pldm_header *header; - u16 total_header_size; - u16 component_bitmap_len; - u16 bitmap_size; - u16 component_count; - const u8 *component_start; - const u8 *record_start; - u8 record_count; - u32 header_crc; - struct pldmfw_record *matching_record; -}; - -struct pldm_pci_record_id { - int vendor; - int device; - int subsystem_vendor; - int subsystem_device; -}; - -struct msr { - union { - struct { - u32 l; - u32 h; - }; - u64 q; - }; -}; - -struct msr_info { - u32 msr_no; - struct msr reg; - struct msr *msrs; - int err; -}; - -struct msr_regs_info { - u32 *regs; - int err; -}; - -struct msr_info_completion { - struct msr_info msr; - struct completion done; -}; - -struct trace_event_raw_msr_trace_class { - struct trace_entry ent; - unsigned int msr; - u64 val; - int failed; - char __data[0]; -}; - -struct trace_event_data_offsets_msr_trace_class {}; - -typedef void (*btf_trace_read_msr)(void *, unsigned int, u64, int); - -typedef void (*btf_trace_write_msr)(void *, unsigned int, u64, int); - -typedef void (*btf_trace_rdpmc)(void *, unsigned int, u64, int); - -struct warn_args___2; - -struct compress_format { - unsigned char magic[2]; - const char *name; - decompress_fn decompressor; -}; - -struct group_data { - int limit[21]; - int base[20]; - int permute[258]; - int minLen; - int maxLen; -}; - -struct bunzip_data { - int writeCopies; - int writePos; - int writeRunCountdown; - int writeCount; - int writeCurrent; - long int (*fill)(void *, long unsigned int); - long int inbufCount; - long int inbufPos; - unsigned char *inbuf; - unsigned int inbufBitCount; - unsigned int inbufBits; - unsigned int crc32Table[256]; - unsigned int headerCRC; - unsigned int totalCRC; - unsigned int writeCRC; - unsigned int *dbuf; - unsigned int dbufSize; - unsigned char selectors[32768]; - struct group_data groups[6]; - int io_error; - int byteCount[256]; - unsigned char symToByte[256]; - unsigned char mtfSymbol[256]; -}; - -struct rc { - long int (*fill)(void *, long unsigned int); - uint8_t *ptr; - uint8_t *buffer; - uint8_t *buffer_end; - long int buffer_size; - uint32_t code; - uint32_t range; - uint32_t bound; - void (*error)(char *); -}; - -struct lzma_header { - uint8_t pos; - uint32_t dict_size; - uint64_t dst_size; -} __attribute__((packed)); - -struct writer { - uint8_t *buffer; - uint8_t previous_byte; - size_t buffer_pos; - int bufsize; - size_t global_pos; - long int (*flush)(void *, long unsigned int); - struct lzma_header *header; -}; - -struct cstate { - int state; - uint32_t rep0; - uint32_t rep1; - uint32_t rep2; - uint32_t rep3; -}; - -typedef enum { - ZSTD_error_no_error = 0, - ZSTD_error_GENERIC = 1, - ZSTD_error_prefix_unknown = 2, - ZSTD_error_version_unsupported = 3, - ZSTD_error_parameter_unknown = 4, - ZSTD_error_frameParameter_unsupported = 5, - ZSTD_error_frameParameter_unsupportedBy32bits = 6, - ZSTD_error_frameParameter_windowTooLarge = 7, - ZSTD_error_compressionParameter_unsupported = 8, - ZSTD_error_init_missing = 9, - ZSTD_error_memory_allocation = 10, - ZSTD_error_stage_wrong = 11, - ZSTD_error_dstSize_tooSmall = 12, - ZSTD_error_srcSize_wrong = 13, - ZSTD_error_corruption_detected = 14, - ZSTD_error_checksum_wrong = 15, - ZSTD_error_tableLog_tooLarge = 16, - ZSTD_error_maxSymbolValue_tooLarge = 17, - ZSTD_error_maxSymbolValue_tooSmall = 18, - ZSTD_error_dictionary_corrupted = 19, - ZSTD_error_dictionary_wrong = 20, - ZSTD_error_dictionaryCreation_failed = 21, - ZSTD_error_maxCode = 22, -} ZSTD_ErrorCode; - -struct ZSTD_DStream_s___2; - -typedef struct ZSTD_DStream_s___2 ZSTD_DStream___2; - -enum cpio_fields { - C_MAGIC = 0, - C_INO = 1, - C_MODE = 2, - C_UID = 3, - C_GID = 4, - C_NLINK = 5, - C_MTIME = 6, - C_FILESIZE = 7, - C_MAJ = 8, - C_MIN = 9, - C_RMAJ = 10, - C_RMIN = 11, - C_NAMESIZE = 12, - C_CHKSUM = 13, - C_NFIELDS = 14, -}; - -struct fprop_local_single { - long unsigned int events; - unsigned int period; - raw_spinlock_t lock; -}; - -struct ida_bitmap { - long unsigned int bitmap[16]; -}; - -struct klist_waiter { - struct list_head list; - struct klist_node *node; - struct task_struct *process; - int woken; -}; - -struct uevent_sock { - struct list_head list; - struct sock *sk; -}; - -enum { - LOGIC_PIO_INDIRECT = 0, - LOGIC_PIO_CPU_MMIO = 1, -}; - -struct logic_pio_host_ops; - -struct logic_pio_hwaddr { - struct list_head list; - struct fwnode_handle *fwnode; - resource_size_t hw_start; - resource_size_t io_start; - resource_size_t size; - long unsigned int flags; - void *hostdata; - const struct logic_pio_host_ops *ops; -}; - -struct logic_pio_host_ops { - u32 (*in)(void *, long unsigned int, size_t); - void (*out)(void *, long unsigned int, u32, size_t); - u32 (*ins)(void *, long unsigned int, void *, size_t, unsigned int); - void (*outs)(void *, long unsigned int, const void *, size_t, unsigned int); -}; - -typedef struct { - long unsigned int key[2]; -} hsiphash_key_t; - -struct clk_core; - -struct clk { - struct clk_core *core; - struct device *dev; - const char *dev_id; - const char *con_id; - long unsigned int min_rate; - long unsigned int max_rate; - unsigned int exclusive_count; - struct hlist_node clks_node; -}; - -enum format_type { - FORMAT_TYPE_NONE = 0, - FORMAT_TYPE_WIDTH = 1, - FORMAT_TYPE_PRECISION = 2, - FORMAT_TYPE_CHAR = 3, - FORMAT_TYPE_STR = 4, - FORMAT_TYPE_PTR = 5, - FORMAT_TYPE_PERCENT_CHAR = 6, - FORMAT_TYPE_INVALID = 7, - FORMAT_TYPE_LONG_LONG = 8, - FORMAT_TYPE_ULONG = 9, - FORMAT_TYPE_LONG = 10, - FORMAT_TYPE_UBYTE = 11, - FORMAT_TYPE_BYTE = 12, - FORMAT_TYPE_USHORT = 13, - FORMAT_TYPE_SHORT = 14, - FORMAT_TYPE_UINT = 15, - FORMAT_TYPE_INT = 16, - FORMAT_TYPE_SIZE_T = 17, - FORMAT_TYPE_PTRDIFF = 18, -}; - -struct printf_spec { - unsigned int type: 8; - int field_width: 24; - unsigned int flags: 8; - unsigned int base: 8; - int precision: 16; -}; - -struct page_flags_fields { - int width; - int shift; - int mask; - const struct printf_spec *spec; - const char *name; -}; - -struct minmax_sample { - u32 t; - u32 v; -}; - -struct minmax { - struct minmax_sample s[3]; -}; - -enum { - st_wordstart = 0, - st_wordcmp = 1, - st_wordskip = 2, - st_bufcpy = 3, -}; - -enum { - st_wordstart___2 = 0, - st_wordcmp___2 = 1, - st_wordskip___2 = 2, -}; - -struct in6_addr___2; - -enum reg_type { - REG_TYPE_RM = 0, - REG_TYPE_REG = 1, - REG_TYPE_INDEX = 2, - REG_TYPE_BASE = 3, -}; - -enum device_link_state { - DL_STATE_NONE = 4294967295, - DL_STATE_DORMANT = 0, - DL_STATE_AVAILABLE = 1, - DL_STATE_CONSUMER_PROBE = 2, - DL_STATE_ACTIVE = 3, - DL_STATE_SUPPLIER_UNBIND = 4, -}; - -struct device_link { - struct device *supplier; - struct list_head s_node; - struct device *consumer; - struct list_head c_node; - struct device link_dev; - enum device_link_state status; - u32 flags; - refcount_t rpm_active; - struct kref kref; - struct work_struct rm_work; - bool supplier_preactivated; -}; - -struct phy_configure_opts_dp { - unsigned int link_rate; - unsigned int lanes; - unsigned int voltage[4]; - unsigned int pre[4]; - u8 ssc: 1; - u8 set_rate: 1; - u8 set_lanes: 1; - u8 set_voltages: 1; -}; - -struct phy_configure_opts_mipi_dphy { - unsigned int clk_miss; - unsigned int clk_post; - unsigned int clk_pre; - unsigned int clk_prepare; - unsigned int clk_settle; - unsigned int clk_term_en; - unsigned int clk_trail; - unsigned int clk_zero; - unsigned int d_term_en; - unsigned int eot; - unsigned int hs_exit; - unsigned int hs_prepare; - unsigned int hs_settle; - unsigned int hs_skip; - unsigned int hs_trail; - unsigned int hs_zero; - unsigned int init; - unsigned int lpx; - unsigned int ta_get; - unsigned int ta_go; - unsigned int ta_sure; - unsigned int wakeup; - long unsigned int hs_clk_rate; - long unsigned int lp_clk_rate; - unsigned char lanes; -}; - -enum phy_mode { - PHY_MODE_INVALID = 0, - PHY_MODE_USB_HOST = 1, - PHY_MODE_USB_HOST_LS = 2, - PHY_MODE_USB_HOST_FS = 3, - PHY_MODE_USB_HOST_HS = 4, - PHY_MODE_USB_HOST_SS = 5, - PHY_MODE_USB_DEVICE = 6, - PHY_MODE_USB_DEVICE_LS = 7, - PHY_MODE_USB_DEVICE_FS = 8, - PHY_MODE_USB_DEVICE_HS = 9, - PHY_MODE_USB_DEVICE_SS = 10, - PHY_MODE_USB_OTG = 11, - PHY_MODE_UFS_HS_A = 12, - PHY_MODE_UFS_HS_B = 13, - PHY_MODE_PCIE = 14, - PHY_MODE_ETHERNET = 15, - PHY_MODE_MIPI_DPHY = 16, - PHY_MODE_SATA = 17, - PHY_MODE_LVDS = 18, - PHY_MODE_DP = 19, -}; - -enum phy_media { - PHY_MEDIA_DEFAULT = 0, - PHY_MEDIA_SR = 1, - PHY_MEDIA_DAC = 2, -}; - -union phy_configure_opts { - struct phy_configure_opts_mipi_dphy mipi_dphy; - struct phy_configure_opts_dp dp; -}; - -struct phy; - -struct phy_ops { - int (*init)(struct phy *); - int (*exit)(struct phy *); - int (*power_on)(struct phy *); - int (*power_off)(struct phy *); - int (*set_mode)(struct phy *, enum phy_mode, int); - int (*set_media)(struct phy *, enum phy_media); - int (*set_speed)(struct phy *, int); - int (*configure)(struct phy *, union phy_configure_opts *); - int (*validate)(struct phy *, enum phy_mode, int, union phy_configure_opts *); - int (*reset)(struct phy *); - int (*calibrate)(struct phy *); - void (*release)(struct phy *); - struct module *owner; -}; - -struct phy_attrs { - u32 bus_width; - u32 max_link_rate; - enum phy_mode mode; -}; - -struct regulator; - -struct phy { - struct device dev; - int id; - const struct phy_ops *ops; - struct mutex mutex; - int init_count; - int power_count; - struct phy_attrs attrs; - struct regulator *pwr; -}; - -struct phy_provider { - struct device *dev; - struct device_node *children; - struct module *owner; - struct list_head list; - struct phy * (*of_xlate)(struct device *, struct of_phandle_args *); -}; - -struct phy_lookup { - struct list_head node; - const char *dev_id; - const char *con_id; - struct phy *phy; -}; - -struct pinctrl; - -struct pinctrl_state; - -struct dev_pin_info { - struct pinctrl *p; - struct pinctrl_state *default_state; - struct pinctrl_state *init_state; - struct pinctrl_state *sleep_state; - struct pinctrl_state *idle_state; -}; - -struct pinctrl { - struct list_head node; - struct device *dev; - struct list_head states; - struct pinctrl_state *state; - struct list_head dt_maps; - struct kref users; -}; - -struct pinctrl_state { - struct list_head node; - const char *name; - struct list_head settings; -}; - -struct pinctrl_pin_desc { - unsigned int number; - const char *name; - void *drv_data; -}; - -struct gpio_chip; - -struct pinctrl_gpio_range { - struct list_head node; - const char *name; - unsigned int id; - unsigned int base; - unsigned int pin_base; - unsigned int npins; - const unsigned int *pins; - struct gpio_chip *gc; -}; - -struct gpio_irq_chip { - struct irq_chip *chip; - struct irq_domain *domain; - const struct irq_domain_ops *domain_ops; - struct fwnode_handle *fwnode; - struct irq_domain *parent_domain; - int (*child_to_parent_hwirq)(struct gpio_chip *, unsigned int, unsigned int, unsigned int *, unsigned int *); - void * (*populate_parent_alloc_arg)(struct gpio_chip *, unsigned int, unsigned int); - unsigned int (*child_offset_to_irq)(struct gpio_chip *, unsigned int); - struct irq_domain_ops child_irq_domain_ops; - irq_flow_handler_t handler; - unsigned int default_type; - struct lock_class_key *lock_key; - struct lock_class_key *request_key; - irq_flow_handler_t parent_handler; - void *parent_handler_data; - unsigned int num_parents; - unsigned int *parents; - unsigned int *map; - bool threaded; - int (*init_hw)(struct gpio_chip *); - void (*init_valid_mask)(struct gpio_chip *, long unsigned int *, unsigned int); - long unsigned int *valid_mask; - unsigned int first; - void (*irq_enable)(struct irq_data *); - void (*irq_disable)(struct irq_data *); - void (*irq_unmask)(struct irq_data *); - void (*irq_mask)(struct irq_data *); -}; - -struct gpio_device; - -struct gpio_chip { - const char *label; - struct gpio_device *gpiodev; - struct device *parent; - struct module *owner; - int (*request)(struct gpio_chip *, unsigned int); - void (*free)(struct gpio_chip *, unsigned int); - int (*get_direction)(struct gpio_chip *, unsigned int); - int (*direction_input)(struct gpio_chip *, unsigned int); - int (*direction_output)(struct gpio_chip *, unsigned int, int); - int (*get)(struct gpio_chip *, unsigned int); - int (*get_multiple)(struct gpio_chip *, long unsigned int *, long unsigned int *); - void (*set)(struct gpio_chip *, unsigned int, int); - void (*set_multiple)(struct gpio_chip *, long unsigned int *, long unsigned int *); - int (*set_config)(struct gpio_chip *, unsigned int, long unsigned int); - int (*to_irq)(struct gpio_chip *, unsigned int); - void (*dbg_show)(struct seq_file *, struct gpio_chip *); - int (*init_valid_mask)(struct gpio_chip *, long unsigned int *, unsigned int); - int (*add_pin_ranges)(struct gpio_chip *); - int base; - u16 ngpio; - const char * const *names; - bool can_sleep; - long unsigned int (*read_reg)(void *); - void (*write_reg)(void *, long unsigned int); - bool be_bits; - void *reg_dat; - void *reg_set; - void *reg_clr; - void *reg_dir_out; - void *reg_dir_in; - bool bgpio_dir_unreadable; - int bgpio_bits; - spinlock_t bgpio_lock; - long unsigned int bgpio_data; - long unsigned int bgpio_dir; - struct gpio_irq_chip irq; - long unsigned int *valid_mask; -}; - -struct pinctrl_dev; - -struct pinctrl_map; - -struct pinctrl_ops { - int (*get_groups_count)(struct pinctrl_dev *); - const char * (*get_group_name)(struct pinctrl_dev *, unsigned int); - int (*get_group_pins)(struct pinctrl_dev *, unsigned int, const unsigned int **, unsigned int *); - void (*pin_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int); - int (*dt_node_to_map)(struct pinctrl_dev *, struct device_node *, struct pinctrl_map **, unsigned int *); - void (*dt_free_map)(struct pinctrl_dev *, struct pinctrl_map *, unsigned int); -}; - -struct pinctrl_desc; - -struct pinctrl_dev { - struct list_head node; - struct pinctrl_desc *desc; - struct xarray pin_desc_tree; - struct list_head gpio_ranges; - struct device *dev; - struct module *owner; - void *driver_data; - struct pinctrl *p; - struct pinctrl_state *hog_default; - struct pinctrl_state *hog_sleep; - struct mutex mutex; - struct dentry *device_root; -}; - -enum pinctrl_map_type { - PIN_MAP_TYPE_INVALID = 0, - PIN_MAP_TYPE_DUMMY_STATE = 1, - PIN_MAP_TYPE_MUX_GROUP = 2, - PIN_MAP_TYPE_CONFIGS_PIN = 3, - PIN_MAP_TYPE_CONFIGS_GROUP = 4, -}; - -struct pinctrl_map_mux { - const char *group; - const char *function; -}; - -struct pinctrl_map_configs { - const char *group_or_pin; - long unsigned int *configs; - unsigned int num_configs; -}; - -struct pinctrl_map { - const char *dev_name; - const char *name; - enum pinctrl_map_type type; - const char *ctrl_dev_name; - union { - struct pinctrl_map_mux mux; - struct pinctrl_map_configs configs; - } data; -}; - -struct pinmux_ops; - -struct pinconf_ops; - -struct pinconf_generic_params; - -struct pin_config_item; - -struct pinctrl_desc { - const char *name; - const struct pinctrl_pin_desc *pins; - unsigned int npins; - const struct pinctrl_ops *pctlops; - const struct pinmux_ops *pmxops; - const struct pinconf_ops *confops; - struct module *owner; - unsigned int num_custom_params; - const struct pinconf_generic_params *custom_params; - const struct pin_config_item *custom_conf_items; - bool link_consumers; -}; - -struct pinmux_ops { - int (*request)(struct pinctrl_dev *, unsigned int); - int (*free)(struct pinctrl_dev *, unsigned int); - int (*get_functions_count)(struct pinctrl_dev *); - const char * (*get_function_name)(struct pinctrl_dev *, unsigned int); - int (*get_function_groups)(struct pinctrl_dev *, unsigned int, const char * const **, unsigned int *); - int (*set_mux)(struct pinctrl_dev *, unsigned int, unsigned int); - int (*gpio_request_enable)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int); - void (*gpio_disable_free)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int); - int (*gpio_set_direction)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int, bool); - bool strict; -}; - -struct pinconf_ops { - bool is_generic; - int (*pin_config_get)(struct pinctrl_dev *, unsigned int, long unsigned int *); - int (*pin_config_set)(struct pinctrl_dev *, unsigned int, long unsigned int *, unsigned int); - int (*pin_config_group_get)(struct pinctrl_dev *, unsigned int, long unsigned int *); - int (*pin_config_group_set)(struct pinctrl_dev *, unsigned int, long unsigned int *, unsigned int); - void (*pin_config_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int); - void (*pin_config_group_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int); - void (*pin_config_config_dbg_show)(struct pinctrl_dev *, struct seq_file *, long unsigned int); -}; - -enum pin_config_param { - PIN_CONFIG_BIAS_BUS_HOLD = 0, - PIN_CONFIG_BIAS_DISABLE = 1, - PIN_CONFIG_BIAS_HIGH_IMPEDANCE = 2, - PIN_CONFIG_BIAS_PULL_DOWN = 3, - PIN_CONFIG_BIAS_PULL_PIN_DEFAULT = 4, - PIN_CONFIG_BIAS_PULL_UP = 5, - PIN_CONFIG_DRIVE_OPEN_DRAIN = 6, - PIN_CONFIG_DRIVE_OPEN_SOURCE = 7, - PIN_CONFIG_DRIVE_PUSH_PULL = 8, - PIN_CONFIG_DRIVE_STRENGTH = 9, - PIN_CONFIG_DRIVE_STRENGTH_UA = 10, - PIN_CONFIG_INPUT_DEBOUNCE = 11, - PIN_CONFIG_INPUT_ENABLE = 12, - PIN_CONFIG_INPUT_SCHMITT = 13, - PIN_CONFIG_INPUT_SCHMITT_ENABLE = 14, - PIN_CONFIG_MODE_LOW_POWER = 15, - PIN_CONFIG_MODE_PWM = 16, - PIN_CONFIG_OUTPUT = 17, - PIN_CONFIG_OUTPUT_ENABLE = 18, - PIN_CONFIG_PERSIST_STATE = 19, - PIN_CONFIG_POWER_SOURCE = 20, - PIN_CONFIG_SKEW_DELAY = 21, - PIN_CONFIG_SLEEP_HARDWARE_STATE = 22, - PIN_CONFIG_SLEW_RATE = 23, - PIN_CONFIG_END = 127, - PIN_CONFIG_MAX = 255, -}; - -struct pinconf_generic_params { - const char * const property; - enum pin_config_param param; - u32 default_value; -}; - -struct pin_config_item { - const enum pin_config_param param; - const char * const display; - const char * const format; - bool has_arg; -}; - -struct gpio_desc___2; - -struct gpio_device { - int id; - struct device dev; - struct cdev chrdev; - struct device *mockdev; - struct module *owner; - struct gpio_chip *chip; - struct gpio_desc___2 *descs; - int base; - u16 ngpio; - const char *label; - void *data; - struct list_head list; - struct blocking_notifier_head notifier; - struct list_head pin_ranges; -}; - -struct gpio_desc___2 { - struct gpio_device *gdev; - long unsigned int flags; - const char *label; - const char *name; - unsigned int debounce_period_us; -}; - -struct pinctrl_setting_mux { - unsigned int group; - unsigned int func; -}; - -struct pinctrl_setting_configs { - unsigned int group_or_pin; - long unsigned int *configs; - unsigned int num_configs; -}; - -struct pinctrl_setting { - struct list_head node; - enum pinctrl_map_type type; - struct pinctrl_dev *pctldev; - const char *dev_name; - union { - struct pinctrl_setting_mux mux; - struct pinctrl_setting_configs configs; - } data; -}; - -struct pin_desc { - struct pinctrl_dev *pctldev; - const char *name; - bool dynamic_name; - void *drv_data; - unsigned int mux_usecount; - const char *mux_owner; - const struct pinctrl_setting_mux *mux_setting; - const char *gpio_owner; -}; - -struct pinctrl_maps { - struct list_head node; - const struct pinctrl_map *maps; - unsigned int num_maps; -}; - -struct pctldev; - -enum regcache_type { - REGCACHE_NONE = 0, - REGCACHE_RBTREE = 1, - REGCACHE_COMPRESSED = 2, - REGCACHE_FLAT = 3, -}; - -struct reg_default { - unsigned int reg; - unsigned int def; -}; - -enum regmap_endian { - REGMAP_ENDIAN_DEFAULT = 0, - REGMAP_ENDIAN_BIG = 1, - REGMAP_ENDIAN_LITTLE = 2, - REGMAP_ENDIAN_NATIVE = 3, -}; - -struct regmap_range { - unsigned int range_min; - unsigned int range_max; -}; - -struct regmap_access_table { - const struct regmap_range *yes_ranges; - unsigned int n_yes_ranges; - const struct regmap_range *no_ranges; - unsigned int n_no_ranges; -}; - -typedef void (*regmap_lock)(void *); - -typedef void (*regmap_unlock)(void *); - -struct regmap_range_cfg; - -struct regmap_config { - const char *name; - int reg_bits; - int reg_stride; - int pad_bits; - int val_bits; - bool (*writeable_reg)(struct device *, unsigned int); - bool (*readable_reg)(struct device *, unsigned int); - bool (*volatile_reg)(struct device *, unsigned int); - bool (*precious_reg)(struct device *, unsigned int); - bool (*writeable_noinc_reg)(struct device *, unsigned int); - bool (*readable_noinc_reg)(struct device *, unsigned int); - bool disable_locking; - regmap_lock lock; - regmap_unlock unlock; - void *lock_arg; - int (*reg_read)(void *, unsigned int, unsigned int *); - int (*reg_write)(void *, unsigned int, unsigned int); - bool fast_io; - unsigned int max_register; - const struct regmap_access_table *wr_table; - const struct regmap_access_table *rd_table; - const struct regmap_access_table *volatile_table; - const struct regmap_access_table *precious_table; - const struct regmap_access_table *wr_noinc_table; - const struct regmap_access_table *rd_noinc_table; - const struct reg_default *reg_defaults; - unsigned int num_reg_defaults; - enum regcache_type cache_type; - const void *reg_defaults_raw; - unsigned int num_reg_defaults_raw; - long unsigned int read_flag_mask; - long unsigned int write_flag_mask; - bool zero_flag_mask; - bool use_single_read; - bool use_single_write; - bool use_relaxed_mmio; - bool can_multi_write; - enum regmap_endian reg_format_endian; - enum regmap_endian val_format_endian; - const struct regmap_range_cfg *ranges; - unsigned int num_ranges; - bool use_hwlock; - unsigned int hwlock_id; - unsigned int hwlock_mode; - bool can_sleep; -}; - -struct regmap_range_cfg { - const char *name; - unsigned int range_min; - unsigned int range_max; - unsigned int selector_reg; - unsigned int selector_mask; - int selector_shift; - unsigned int window_start; - unsigned int window_len; -}; - -typedef int (*regmap_hw_write)(void *, const void *, size_t); - -typedef int (*regmap_hw_gather_write)(void *, const void *, size_t, const void *, size_t); - -struct regmap_async; - -typedef int (*regmap_hw_async_write)(void *, const void *, size_t, const void *, size_t, struct regmap_async *); - -typedef int (*regmap_hw_read)(void *, const void *, size_t, void *, size_t); - -typedef int (*regmap_hw_reg_read)(void *, unsigned int, unsigned int *); - -typedef int (*regmap_hw_reg_write)(void *, unsigned int, unsigned int); - -typedef int (*regmap_hw_reg_update_bits)(void *, unsigned int, unsigned int, unsigned int); - -typedef struct regmap_async * (*regmap_hw_async_alloc)(); - -typedef void (*regmap_hw_free_context)(void *); - -struct regmap_bus { - bool fast_io; - regmap_hw_write write; - regmap_hw_gather_write gather_write; - regmap_hw_async_write async_write; - regmap_hw_reg_write reg_write; - regmap_hw_reg_update_bits reg_update_bits; - regmap_hw_read read; - regmap_hw_reg_read reg_read; - regmap_hw_free_context free_context; - regmap_hw_async_alloc async_alloc; - u8 read_flag_mask; - enum regmap_endian reg_format_endian_default; - enum regmap_endian val_format_endian_default; - size_t max_raw_read; - size_t max_raw_write; - bool free_on_exit; -}; - -struct i2c_device_id { - char name[20]; - kernel_ulong_t driver_data; -}; - -struct software_node { - const char *name; - const struct software_node *parent; - const struct property_entry *properties; -}; - -struct i2c_msg { - __u16 addr; - __u16 flags; - __u16 len; - __u8 *buf; -}; - -union i2c_smbus_data { - __u8 byte; - __u16 word; - __u8 block[34]; -}; - -enum i2c_slave_event { - I2C_SLAVE_READ_REQUESTED = 0, - I2C_SLAVE_WRITE_REQUESTED = 1, - I2C_SLAVE_READ_PROCESSED = 2, - I2C_SLAVE_WRITE_RECEIVED = 3, - I2C_SLAVE_STOP = 4, -}; - -struct i2c_client; - -typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *); - -struct i2c_adapter; - -struct i2c_client { - short unsigned int flags; - short unsigned int addr; - char name[20]; - struct i2c_adapter *adapter; - struct device dev; - int init_irq; - int irq; - struct list_head detected; - i2c_slave_cb_t slave_cb; - void *devres_group_id; -}; - -enum i2c_alert_protocol { - I2C_PROTOCOL_SMBUS_ALERT = 0, - I2C_PROTOCOL_SMBUS_HOST_NOTIFY = 1, -}; - -struct i2c_board_info; - -struct i2c_driver { - unsigned int class; - int (*probe)(struct i2c_client *, const struct i2c_device_id *); - int (*remove)(struct i2c_client *); - int (*probe_new)(struct i2c_client *); - void (*shutdown)(struct i2c_client *); - void (*alert)(struct i2c_client *, enum i2c_alert_protocol, unsigned int); - int (*command)(struct i2c_client *, unsigned int, void *); - struct device_driver driver; - const struct i2c_device_id *id_table; - int (*detect)(struct i2c_client *, struct i2c_board_info *); - const short unsigned int *address_list; - struct list_head clients; -}; - -struct i2c_board_info { - char type[20]; - short unsigned int flags; - short unsigned int addr; - const char *dev_name; - void *platform_data; - struct device_node *of_node; - struct fwnode_handle *fwnode; - const struct software_node *swnode; - const struct resource *resources; - unsigned int num_resources; - int irq; -}; - -struct i2c_algorithm; - -struct i2c_lock_operations; - -struct i2c_bus_recovery_info; - -struct i2c_adapter_quirks; - -struct i2c_adapter { - struct module *owner; - unsigned int class; - const struct i2c_algorithm *algo; - void *algo_data; - const struct i2c_lock_operations *lock_ops; - struct rt_mutex bus_lock; - struct rt_mutex mux_lock; - int timeout; - int retries; - struct device dev; - long unsigned int locked_flags; - int nr; - char name[48]; - struct completion dev_released; - struct mutex userspace_clients_lock; - struct list_head userspace_clients; - struct i2c_bus_recovery_info *bus_recovery_info; - const struct i2c_adapter_quirks *quirks; - struct irq_domain *host_notify_domain; - struct regulator *bus_regulator; -}; - -struct i2c_algorithm { - int (*master_xfer)(struct i2c_adapter *, struct i2c_msg *, int); - int (*master_xfer_atomic)(struct i2c_adapter *, struct i2c_msg *, int); - int (*smbus_xfer)(struct i2c_adapter *, u16, short unsigned int, char, u8, int, union i2c_smbus_data *); - int (*smbus_xfer_atomic)(struct i2c_adapter *, u16, short unsigned int, char, u8, int, union i2c_smbus_data *); - u32 (*functionality)(struct i2c_adapter *); - int (*reg_slave)(struct i2c_client *); - int (*unreg_slave)(struct i2c_client *); -}; - -struct i2c_lock_operations { - void (*lock_bus)(struct i2c_adapter *, unsigned int); - int (*trylock_bus)(struct i2c_adapter *, unsigned int); - void (*unlock_bus)(struct i2c_adapter *, unsigned int); -}; - -struct i2c_bus_recovery_info { - int (*recover_bus)(struct i2c_adapter *); - int (*get_scl)(struct i2c_adapter *); - void (*set_scl)(struct i2c_adapter *, int); - int (*get_sda)(struct i2c_adapter *); - void (*set_sda)(struct i2c_adapter *, int); - int (*get_bus_free)(struct i2c_adapter *); - void (*prepare_recovery)(struct i2c_adapter *); - void (*unprepare_recovery)(struct i2c_adapter *); - struct gpio_desc *scl_gpiod; - struct gpio_desc *sda_gpiod; - struct pinctrl *pinctrl; - struct pinctrl_state *pins_default; - struct pinctrl_state *pins_gpio; -}; - -struct i2c_adapter_quirks { - u64 flags; - int max_num_msgs; - u16 max_write_len; - u16 max_read_len; - u16 max_comb_1st_msg_len; - u16 max_comb_2nd_msg_len; -}; - -enum { - SX150X_123 = 0, - SX150X_456 = 1, - SX150X_789 = 2, -}; - -enum { - SX150X_789_REG_MISC_AUTOCLEAR_OFF = 1, - SX150X_MAX_REGISTER = 173, - SX150X_IRQ_TYPE_EDGE_RISING = 1, - SX150X_IRQ_TYPE_EDGE_FALLING = 2, - SX150X_789_RESET_KEY1 = 18, - SX150X_789_RESET_KEY2 = 52, -}; - -struct sx150x_123_pri { - u8 reg_pld_mode; - u8 reg_pld_table0; - u8 reg_pld_table1; - u8 reg_pld_table2; - u8 reg_pld_table3; - u8 reg_pld_table4; - u8 reg_advanced; -}; - -struct sx150x_456_pri { - u8 reg_pld_mode; - u8 reg_pld_table0; - u8 reg_pld_table1; - u8 reg_pld_table2; - u8 reg_pld_table3; - u8 reg_pld_table4; - u8 reg_advanced; -}; - -struct sx150x_789_pri { - u8 reg_drain; - u8 reg_polarity; - u8 reg_clock; - u8 reg_misc; - u8 reg_reset; - u8 ngpios; -}; - -struct sx150x_device_data { - u8 model; - u8 reg_pullup; - u8 reg_pulldn; - u8 reg_dir; - u8 reg_data; - u8 reg_irq_mask; - u8 reg_irq_src; - u8 reg_sense; - u8 ngpios; - union { - struct sx150x_123_pri x123; - struct sx150x_456_pri x456; - struct sx150x_789_pri x789; - } pri; - const struct pinctrl_pin_desc *pins; - unsigned int npins; -}; - -struct regmap; - -struct sx150x_pinctrl { - struct device *dev; - struct i2c_client *client; - struct pinctrl_dev *pctldev; - struct pinctrl_desc pinctrl_desc; - struct gpio_chip gpio; - struct irq_chip irq_chip; - struct regmap *regmap; - struct { - u32 sense; - u32 masked; - } irq; - struct mutex lock; - const struct sx150x_device_data *data; -}; - -struct intel_pingroup { - const char *name; - const unsigned int *pins; - size_t npins; - short unsigned int mode; - const unsigned int *modes; -}; - -struct intel_function { - const char *name; - const char * const *groups; - size_t ngroups; -}; - -struct intel_padgroup { - unsigned int reg_num; - unsigned int base; - unsigned int size; - int gpio_base; - unsigned int padown_num; -}; - -struct intel_community { - unsigned int barno; - unsigned int padown_offset; - unsigned int padcfglock_offset; - unsigned int hostown_offset; - unsigned int is_offset; - unsigned int ie_offset; - unsigned int features; - unsigned int pin_base; - size_t npins; - unsigned int gpp_size; - unsigned int gpp_num_padown_regs; - const struct intel_padgroup *gpps; - size_t ngpps; - const unsigned int *pad_map; - short unsigned int nirqs; - short unsigned int acpi_space_id; - void *regs; - void *pad_regs; -}; - -struct intel_pinctrl_soc_data { - const char *uid; - const struct pinctrl_pin_desc *pins; - size_t npins; - const struct intel_pingroup *groups; - size_t ngroups; - const struct intel_function *functions; - size_t nfunctions; - const struct intel_community *communities; - size_t ncommunities; -}; - -struct intel_pad_context; - -struct intel_community_context; - -struct intel_pinctrl_context { - struct intel_pad_context *pads; - struct intel_community_context *communities; -}; - -struct intel_pad_context { - u32 conf0; - u32 val; -}; - -struct intel_pinctrl { - struct device *dev; - raw_spinlock_t lock; - struct pinctrl_desc pctldesc; - struct pinctrl_dev *pctldev; - struct gpio_chip chip; - struct irq_chip irqchip; - const struct intel_pinctrl_soc_data *soc; - struct intel_community *communities; - size_t ncommunities; - struct intel_pinctrl_context context; - int irq; -}; - -typedef acpi_status (*acpi_adr_space_handler)(u32, acpi_physical_address, u32, u64 *, void *, void *); - -typedef acpi_status (*acpi_adr_space_setup)(acpi_handle, u32, void *, void **); - -struct acpi_hotplug_profile { - struct kobject kobj; - int (*scan_dependent)(struct acpi_device *); - void (*notify_online)(struct acpi_device *); - bool enabled: 1; - bool demand_offline: 1; -}; - -struct acpi_device_status { - u32 present: 1; - u32 enabled: 1; - u32 show_in_ui: 1; - u32 functional: 1; - u32 battery_present: 1; - u32 reserved: 27; -}; - -struct acpi_device_flags { - u32 dynamic_status: 1; - u32 removable: 1; - u32 ejectable: 1; - u32 power_manageable: 1; - u32 match_driver: 1; - u32 initialized: 1; - u32 visited: 1; - u32 hotplug_notify: 1; - u32 is_dock_station: 1; - u32 of_compatible_ok: 1; - u32 coherent_dma: 1; - u32 cca_seen: 1; - u32 enumeration_by_parent: 1; - u32 reserved: 19; -}; - -typedef char acpi_bus_id[8]; - -struct acpi_pnp_type { - u32 hardware_id: 1; - u32 bus_address: 1; - u32 platform_id: 1; - u32 reserved: 29; -}; - -typedef u64 acpi_bus_address; - -typedef char acpi_device_name[40]; - -typedef char acpi_device_class[20]; - -struct acpi_device_pnp { - acpi_bus_id bus_id; - int instance_no; - struct acpi_pnp_type type; - acpi_bus_address bus_address; - char *unique_id; - struct list_head ids; - acpi_device_name device_name; - acpi_device_class device_class; - union acpi_object *str_obj; -}; - -struct acpi_device_power_flags { - u32 explicit_get: 1; - u32 power_resources: 1; - u32 inrush_current: 1; - u32 power_removed: 1; - u32 ignore_parent: 1; - u32 dsw_present: 1; - u32 reserved: 26; -}; - -struct acpi_device_power_state { - struct { - u8 valid: 1; - u8 explicit_set: 1; - u8 reserved: 6; - } flags; - int power; - int latency; - struct list_head resources; -}; - -struct acpi_device_power { - int state; - struct acpi_device_power_flags flags; - struct acpi_device_power_state states[5]; -}; - -struct acpi_device_wakeup_flags { - u8 valid: 1; - u8 notifier_present: 1; -}; - -struct acpi_device_wakeup_context { - void (*func)(struct acpi_device_wakeup_context *); - struct device *dev; -}; - -struct acpi_device_wakeup { - acpi_handle gpe_device; - u64 gpe_number; - u64 sleep_state; - struct list_head resources; - struct acpi_device_wakeup_flags flags; - struct acpi_device_wakeup_context context; - struct wakeup_source *ws; - int prepare_count; - int enable_count; -}; - -struct acpi_device_perf_flags { - u8 reserved: 8; -}; - -struct acpi_device_perf_state; - -struct acpi_device_perf { - int state; - struct acpi_device_perf_flags flags; - int state_count; - struct acpi_device_perf_state *states; -}; - -struct acpi_device_dir { - struct proc_dir_entry *entry; -}; - -struct acpi_device_data { - const union acpi_object *pointer; - struct list_head properties; - const union acpi_object *of_compatible; - struct list_head subnodes; -}; - -struct acpi_scan_handler; - -struct acpi_hotplug_context; - -struct acpi_driver; - -struct acpi_gpio_mapping; - -struct acpi_device { - int device_type; - acpi_handle handle; - struct fwnode_handle fwnode; - struct acpi_device *parent; - struct list_head children; - struct list_head node; - struct list_head wakeup_list; - struct list_head del_list; - struct acpi_device_status status; - struct acpi_device_flags flags; - struct acpi_device_pnp pnp; - struct acpi_device_power power; - struct acpi_device_wakeup wakeup; - struct acpi_device_perf performance; - struct acpi_device_dir dir; - struct acpi_device_data data; - struct acpi_scan_handler *handler; - struct acpi_hotplug_context *hp; - struct acpi_driver *driver; - const struct acpi_gpio_mapping *driver_gpios; - void *driver_data; - struct device dev; - unsigned int physical_node_count; - unsigned int dep_unmet; - struct list_head physical_node_list; - struct mutex physical_node_lock; - void (*remove)(struct acpi_device *); -}; - -struct acpi_scan_handler { - const struct acpi_device_id *ids; - struct list_head list_node; - bool (*match)(const char *, const struct acpi_device_id **); - int (*attach)(struct acpi_device *, const struct acpi_device_id *); - void (*detach)(struct acpi_device *); - void (*bind)(struct device *); - void (*unbind)(struct device *); - struct acpi_hotplug_profile hotplug; -}; - -struct acpi_hotplug_context { - struct acpi_device *self; - int (*notify)(struct acpi_device *, u32); - void (*uevent)(struct acpi_device *, u32); - void (*fixup)(struct acpi_device *); -}; - -typedef int (*acpi_op_add)(struct acpi_device *); - -typedef int (*acpi_op_remove)(struct acpi_device *); - -typedef void (*acpi_op_notify)(struct acpi_device *, u32); - -struct acpi_device_ops { - acpi_op_add add; - acpi_op_remove remove; - acpi_op_notify notify; -}; - -struct acpi_driver { - char name[80]; - char class[80]; - const struct acpi_device_id *ids; - unsigned int flags; - struct acpi_device_ops ops; - struct device_driver drv; - struct module *owner; -}; - -struct acpi_device_perf_state { - struct { - u8 valid: 1; - u8 reserved: 7; - } flags; - u8 power; - u8 performance; - int latency; -}; - -struct acpi_gpio_params; - -struct acpi_gpio_mapping { - const char *name; - const struct acpi_gpio_params *data; - unsigned int size; - unsigned int quirks; -}; - -struct intel_pad_context___2; - -struct intel_pinctrl_context___2 { - struct intel_pad_context___2 *pads; - struct intel_community_context *communities; -}; - -struct intel_pad_context___2 { - u32 padctrl0; - u32 padctrl1; -}; - -struct intel_community_context { - unsigned int intr_lines[16]; - u32 saved_intmask; -}; - -struct intel_pinctrl___2 { - struct device *dev; - raw_spinlock_t lock; - struct pinctrl_desc pctldesc; - struct pinctrl_dev *pctldev; - struct gpio_chip chip; - struct irq_chip irqchip; - const struct intel_pinctrl_soc_data *soc; - struct intel_community *communities; - size_t ncommunities; - struct intel_pinctrl_context___2 context; - int irq; -}; - -enum { - INTEL_GPIO_BASE_ZERO = 4294967294, - INTEL_GPIO_BASE_NOMAP = 4294967295, - INTEL_GPIO_BASE_MATCH = 0, -}; - -struct intel_pad_context___3; - -struct intel_community_context___2; - -struct intel_pinctrl_context___3 { - struct intel_pad_context___3 *pads; - struct intel_community_context___2 *communities; -}; - -struct intel_pad_context___3 { - u32 padcfg0; - u32 padcfg1; - u32 padcfg2; -}; - -struct intel_community_context___2 { - u32 *intmask; - u32 *hostown; -}; - -struct intel_pinctrl___3 { - struct device *dev; - raw_spinlock_t lock; - struct pinctrl_desc pctldesc; - struct pinctrl_dev *pctldev; - struct gpio_chip chip; - struct irq_chip irqchip; - const struct intel_pinctrl_soc_data *soc; - struct intel_community *communities; - size_t ncommunities; - struct intel_pinctrl_context___3 context; - int irq; -}; - -enum { - PAD_UNLOCKED = 0, - PAD_LOCKED = 1, - PAD_LOCKED_TX = 2, - PAD_LOCKED_FULL = 3, -}; - -struct gpio_pin_range { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_gpio_range range; -}; - -struct gpio_array; - -struct gpio_descs { - struct gpio_array *info; - unsigned int ndescs; - struct gpio_desc___2 *desc[0]; -}; - -struct gpio_array { - struct gpio_desc___2 **desc; - unsigned int size; - struct gpio_chip *chip; - long unsigned int *get_mask; - long unsigned int *set_mask; - long unsigned int invert_mask[0]; -}; - -enum gpiod_flags { - GPIOD_ASIS = 0, - GPIOD_IN = 1, - GPIOD_OUT_LOW = 3, - GPIOD_OUT_HIGH = 7, - GPIOD_OUT_LOW_OPEN_DRAIN = 11, - GPIOD_OUT_HIGH_OPEN_DRAIN = 15, -}; - -struct acpi_gpio_params { - unsigned int crs_entry_index; - unsigned int line_index; - bool active_low; -}; - -enum gpio_lookup_flags { - GPIO_ACTIVE_HIGH = 0, - GPIO_ACTIVE_LOW = 1, - GPIO_OPEN_DRAIN = 2, - GPIO_OPEN_SOURCE = 4, - GPIO_PERSISTENT = 0, - GPIO_TRANSITORY = 8, - GPIO_PULL_UP = 16, - GPIO_PULL_DOWN = 32, - GPIO_LOOKUP_FLAGS_DEFAULT = 0, -}; - -struct gpiod_lookup { - const char *key; - u16 chip_hwnum; - const char *con_id; - unsigned int idx; - long unsigned int flags; -}; - -struct gpiod_lookup_table { - struct list_head list; - const char *dev_id; - struct gpiod_lookup table[0]; -}; - -struct gpiod_hog { - struct list_head list; - const char *chip_label; - u16 chip_hwnum; - const char *line_name; - long unsigned int lflags; - int dflags; -}; - -enum { - GPIOLINE_CHANGED_REQUESTED = 1, - GPIOLINE_CHANGED_RELEASED = 2, - GPIOLINE_CHANGED_CONFIG = 3, -}; - -struct acpi_gpio_info { - struct acpi_device *adev; - enum gpiod_flags flags; - bool gpioint; - int pin_config; - int polarity; - int triggering; - unsigned int debounce; - unsigned int quirks; -}; - -struct trace_event_raw_gpio_direction { - struct trace_entry ent; - unsigned int gpio; - int in; - int err; - char __data[0]; -}; - -struct trace_event_raw_gpio_value { - struct trace_entry ent; - unsigned int gpio; - int get; - int value; - char __data[0]; -}; - -struct trace_event_data_offsets_gpio_direction {}; - -struct trace_event_data_offsets_gpio_value {}; - -typedef void (*btf_trace_gpio_direction)(void *, unsigned int, int, int); - -typedef void (*btf_trace_gpio_value)(void *, unsigned int, int, int); - -struct devres; - -struct gpio { - unsigned int gpio; - long unsigned int flags; - const char *label; -}; - -struct gpiochip_info { - char name[32]; - char label[32]; - __u32 lines; -}; - -enum gpio_v2_line_flag { - GPIO_V2_LINE_FLAG_USED = 1, - GPIO_V2_LINE_FLAG_ACTIVE_LOW = 2, - GPIO_V2_LINE_FLAG_INPUT = 4, - GPIO_V2_LINE_FLAG_OUTPUT = 8, - GPIO_V2_LINE_FLAG_EDGE_RISING = 16, - GPIO_V2_LINE_FLAG_EDGE_FALLING = 32, - GPIO_V2_LINE_FLAG_OPEN_DRAIN = 64, - GPIO_V2_LINE_FLAG_OPEN_SOURCE = 128, - GPIO_V2_LINE_FLAG_BIAS_PULL_UP = 256, - GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = 512, - GPIO_V2_LINE_FLAG_BIAS_DISABLED = 1024, - GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME = 2048, -}; - -struct gpio_v2_line_values { - __u64 bits; - __u64 mask; -}; - -enum gpio_v2_line_attr_id { - GPIO_V2_LINE_ATTR_ID_FLAGS = 1, - GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES = 2, - GPIO_V2_LINE_ATTR_ID_DEBOUNCE = 3, -}; - -struct gpio_v2_line_attribute { - __u32 id; - __u32 padding; - union { - __u64 flags; - __u64 values; - __u32 debounce_period_us; - }; -}; - -struct gpio_v2_line_config_attribute { - struct gpio_v2_line_attribute attr; - __u64 mask; -}; - -struct gpio_v2_line_config { - __u64 flags; - __u32 num_attrs; - __u32 padding[5]; - struct gpio_v2_line_config_attribute attrs[10]; -}; - -struct gpio_v2_line_request { - __u32 offsets[64]; - char consumer[32]; - struct gpio_v2_line_config config; - __u32 num_lines; - __u32 event_buffer_size; - __u32 padding[5]; - __s32 fd; -}; - -struct gpio_v2_line_info { - char name[32]; - char consumer[32]; - __u32 offset; - __u32 num_attrs; - __u64 flags; - struct gpio_v2_line_attribute attrs[10]; - __u32 padding[4]; -}; - -enum gpio_v2_line_changed_type { - GPIO_V2_LINE_CHANGED_REQUESTED = 1, - GPIO_V2_LINE_CHANGED_RELEASED = 2, - GPIO_V2_LINE_CHANGED_CONFIG = 3, -}; - -struct gpio_v2_line_info_changed { - struct gpio_v2_line_info info; - __u64 timestamp_ns; - __u32 event_type; - __u32 padding[5]; -}; - -enum gpio_v2_line_event_id { - GPIO_V2_LINE_EVENT_RISING_EDGE = 1, - GPIO_V2_LINE_EVENT_FALLING_EDGE = 2, -}; - -struct gpio_v2_line_event { - __u64 timestamp_ns; - __u32 id; - __u32 offset; - __u32 seqno; - __u32 line_seqno; - __u32 padding[6]; -}; - -struct gpioline_info { - __u32 line_offset; - __u32 flags; - char name[32]; - char consumer[32]; -}; - -struct gpioline_info_changed { - struct gpioline_info info; - __u64 timestamp; - __u32 event_type; - __u32 padding[5]; -}; - -struct gpiohandle_request { - __u32 lineoffsets[64]; - __u32 flags; - __u8 default_values[64]; - char consumer_label[32]; - __u32 lines; - int fd; -}; - -struct gpiohandle_config { - __u32 flags; - __u8 default_values[64]; - __u32 padding[4]; -}; - -struct gpiohandle_data { - __u8 values[64]; -}; - -struct gpioevent_request { - __u32 lineoffset; - __u32 handleflags; - __u32 eventflags; - char consumer_label[32]; - int fd; -}; - -struct gpioevent_data { - __u64 timestamp; - __u32 id; -}; - -struct linehandle_state { - struct gpio_device *gdev; - const char *label; - struct gpio_desc___2 *descs[64]; - u32 num_descs; -}; - -struct linereq; - -struct line { - struct gpio_desc___2 *desc; - struct linereq *req; - unsigned int irq; - u64 eflags; - u64 timestamp_ns; - u32 req_seqno; - u32 line_seqno; - struct delayed_work work; - unsigned int sw_debounced; - unsigned int level; -}; - -struct linereq { - struct gpio_device *gdev; - const char *label; - u32 num_lines; - wait_queue_head_t wait; - u32 event_buffer_size; - struct { - union { - struct __kfifo kfifo; - struct gpio_v2_line_event *type; - const struct gpio_v2_line_event *const_type; - char (*rectype)[0]; - struct gpio_v2_line_event *ptr; - const struct gpio_v2_line_event *ptr_const; - }; - struct gpio_v2_line_event buf[0]; - } events; - atomic_t seqno; - struct mutex config_mutex; - struct line lines[0]; -}; - -struct lineevent_state { - struct gpio_device *gdev; - const char *label; - struct gpio_desc___2 *desc; - u32 eflags; - int irq; - wait_queue_head_t wait; - struct { - union { - struct __kfifo kfifo; - struct gpioevent_data *type; - const struct gpioevent_data *const_type; - char (*rectype)[0]; - struct gpioevent_data *ptr; - const struct gpioevent_data *ptr_const; - }; - struct gpioevent_data buf[16]; - } events; - u64 timestamp; -}; - -struct gpio_chardev_data { - struct gpio_device *gdev; - wait_queue_head_t wait; - struct { - union { - struct __kfifo kfifo; - struct gpio_v2_line_info_changed *type; - const struct gpio_v2_line_info_changed *const_type; - char (*rectype)[0]; - struct gpio_v2_line_info_changed *ptr; - const struct gpio_v2_line_info_changed *ptr_const; - }; - struct gpio_v2_line_info_changed buf[32]; - } events; - struct notifier_block lineinfo_changed_nb; - long unsigned int *watched_lines; - atomic_t watch_abi_version; -}; - -typedef u64 acpi_size; - -struct acpi_buffer { - acpi_size length; - void *pointer; -}; - -typedef void (*acpi_object_handler)(acpi_handle, void *); - -struct acpi_connection_info { - u8 *connection; - u16 length; - u8 access_length; -}; - -struct acpi_resource_irq { - u8 descriptor_length; - u8 triggering; - u8 polarity; - u8 shareable; - u8 wake_capable; - u8 interrupt_count; - u8 interrupts[1]; -}; - -struct acpi_resource_dma { - u8 type; - u8 bus_master; - u8 transfer; - u8 channel_count; - u8 channels[1]; -}; - -struct acpi_resource_start_dependent { - u8 descriptor_length; - u8 compatibility_priority; - u8 performance_robustness; -}; - -struct acpi_resource_io { - u8 io_decode; - u8 alignment; - u8 address_length; - u16 minimum; - u16 maximum; -} __attribute__((packed)); - -struct acpi_resource_fixed_io { - u16 address; - u8 address_length; -} __attribute__((packed)); - -struct acpi_resource_fixed_dma { - u16 request_lines; - u16 channels; - u8 width; -} __attribute__((packed)); - -struct acpi_resource_vendor { - u16 byte_length; - u8 byte_data[1]; -} __attribute__((packed)); - -struct acpi_resource_vendor_typed { - u16 byte_length; - u8 uuid_subtype; - u8 uuid[16]; - u8 byte_data[1]; -}; - -struct acpi_resource_end_tag { - u8 checksum; -}; - -struct acpi_resource_memory24 { - u8 write_protect; - u16 minimum; - u16 maximum; - u16 alignment; - u16 address_length; -} __attribute__((packed)); - -struct acpi_resource_memory32 { - u8 write_protect; - u32 minimum; - u32 maximum; - u32 alignment; - u32 address_length; -} __attribute__((packed)); - -struct acpi_resource_fixed_memory32 { - u8 write_protect; - u32 address; - u32 address_length; -} __attribute__((packed)); - -struct acpi_memory_attribute { - u8 write_protect; - u8 caching; - u8 range_type; - u8 translation; -}; - -struct acpi_io_attribute { - u8 range_type; - u8 translation; - u8 translation_type; - u8 reserved1; -}; - -union acpi_resource_attribute { - struct acpi_memory_attribute mem; - struct acpi_io_attribute io; - u8 type_specific; -}; - -struct acpi_resource_label { - u16 string_length; - char *string_ptr; -} __attribute__((packed)); - -struct acpi_resource_source { - u8 index; - u16 string_length; - char *string_ptr; -} __attribute__((packed)); - -struct acpi_address16_attribute { - u16 granularity; - u16 minimum; - u16 maximum; - u16 translation_offset; - u16 address_length; -}; - -struct acpi_address32_attribute { - u32 granularity; - u32 minimum; - u32 maximum; - u32 translation_offset; - u32 address_length; -}; - -struct acpi_address64_attribute { - u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; -}; - -struct acpi_resource_address { - u8 resource_type; - u8 producer_consumer; - u8 decode; - u8 min_address_fixed; - u8 max_address_fixed; - union acpi_resource_attribute info; -}; - -struct acpi_resource_address16 { - u8 resource_type; - u8 producer_consumer; - u8 decode; - u8 min_address_fixed; - u8 max_address_fixed; - union acpi_resource_attribute info; - struct acpi_address16_attribute address; - struct acpi_resource_source resource_source; -} __attribute__((packed)); - -struct acpi_resource_address32 { - u8 resource_type; - u8 producer_consumer; - u8 decode; - u8 min_address_fixed; - u8 max_address_fixed; - union acpi_resource_attribute info; - struct acpi_address32_attribute address; - struct acpi_resource_source resource_source; -} __attribute__((packed)); - -struct acpi_resource_address64 { - u8 resource_type; - u8 producer_consumer; - u8 decode; - u8 min_address_fixed; - u8 max_address_fixed; - union acpi_resource_attribute info; - struct acpi_address64_attribute address; - struct acpi_resource_source resource_source; -} __attribute__((packed)); - -struct acpi_resource_extended_address64 { - u8 resource_type; - u8 producer_consumer; - u8 decode; - u8 min_address_fixed; - u8 max_address_fixed; - union acpi_resource_attribute info; - u8 revision_ID; - struct acpi_address64_attribute address; - u64 type_specific; -} __attribute__((packed)); - -struct acpi_resource_extended_irq { - u8 producer_consumer; - u8 triggering; - u8 polarity; - u8 shareable; - u8 wake_capable; - u8 interrupt_count; - struct acpi_resource_source resource_source; - u32 interrupts[1]; -} __attribute__((packed)); - -struct acpi_resource_generic_register { - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 access_size; - u64 address; -} __attribute__((packed)); - -struct acpi_resource_gpio { - u8 revision_id; - u8 connection_type; - u8 producer_consumer; - u8 pin_config; - u8 shareable; - u8 wake_capable; - u8 io_restriction; - u8 triggering; - u8 polarity; - u16 drive_strength; - u16 debounce_timeout; - u16 pin_table_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u16 *pin_table; - u8 *vendor_data; -} __attribute__((packed)); - -struct acpi_resource_common_serialbus { - u8 revision_id; - u8 type; - u8 producer_consumer; - u8 slave_mode; - u8 connection_sharing; - u8 type_revision_id; - u16 type_data_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u8 *vendor_data; -} __attribute__((packed)); - -struct acpi_resource_i2c_serialbus { - u8 revision_id; - u8 type; - u8 producer_consumer; - u8 slave_mode; - u8 connection_sharing; - u8 type_revision_id; - u16 type_data_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u8 *vendor_data; - u8 access_mode; - u16 slave_address; - u32 connection_speed; -} __attribute__((packed)); - -struct acpi_resource_spi_serialbus { - u8 revision_id; - u8 type; - u8 producer_consumer; - u8 slave_mode; - u8 connection_sharing; - u8 type_revision_id; - u16 type_data_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u8 *vendor_data; - u8 wire_mode; - u8 device_polarity; - u8 data_bit_length; - u8 clock_phase; - u8 clock_polarity; - u16 device_selection; - u32 connection_speed; -} __attribute__((packed)); - -struct acpi_resource_uart_serialbus { - u8 revision_id; - u8 type; - u8 producer_consumer; - u8 slave_mode; - u8 connection_sharing; - u8 type_revision_id; - u16 type_data_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u8 *vendor_data; - u8 endian; - u8 data_bits; - u8 stop_bits; - u8 flow_control; - u8 parity; - u8 lines_enabled; - u16 rx_fifo_size; - u16 tx_fifo_size; - u32 default_baud_rate; -} __attribute__((packed)); - -struct acpi_resource_csi2_serialbus { - u8 revision_id; - u8 type; - u8 producer_consumer; - u8 slave_mode; - u8 connection_sharing; - u8 type_revision_id; - u16 type_data_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u8 *vendor_data; - u8 local_port_instance; - u8 phy_type; -} __attribute__((packed)); - -struct acpi_resource_pin_function { - u8 revision_id; - u8 pin_config; - u8 shareable; - u16 function_number; - u16 pin_table_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u16 *pin_table; - u8 *vendor_data; -} __attribute__((packed)); - -struct acpi_resource_pin_config { - u8 revision_id; - u8 producer_consumer; - u8 shareable; - u8 pin_config_type; - u32 pin_config_value; - u16 pin_table_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u16 *pin_table; - u8 *vendor_data; -} __attribute__((packed)); - -struct acpi_resource_pin_group { - u8 revision_id; - u8 producer_consumer; - u16 pin_table_length; - u16 vendor_length; - u16 *pin_table; - struct acpi_resource_label resource_label; - u8 *vendor_data; -} __attribute__((packed)); - -struct acpi_resource_pin_group_function { - u8 revision_id; - u8 producer_consumer; - u8 shareable; - u16 function_number; - u16 vendor_length; - struct acpi_resource_source resource_source; - struct acpi_resource_label resource_source_label; - u8 *vendor_data; -} __attribute__((packed)); - -struct acpi_resource_pin_group_config { - u8 revision_id; - u8 producer_consumer; - u8 shareable; - u8 pin_config_type; - u32 pin_config_value; - u16 vendor_length; - struct acpi_resource_source resource_source; - struct acpi_resource_label resource_source_label; - u8 *vendor_data; -} __attribute__((packed)); - -union acpi_resource_data { - struct acpi_resource_irq irq; - struct acpi_resource_dma dma; - struct acpi_resource_start_dependent start_dpf; - struct acpi_resource_io io; - struct acpi_resource_fixed_io fixed_io; - struct acpi_resource_fixed_dma fixed_dma; - struct acpi_resource_vendor vendor; - struct acpi_resource_vendor_typed vendor_typed; - struct acpi_resource_end_tag end_tag; - struct acpi_resource_memory24 memory24; - struct acpi_resource_memory32 memory32; - struct acpi_resource_fixed_memory32 fixed_memory32; - struct acpi_resource_address16 address16; - struct acpi_resource_address32 address32; - struct acpi_resource_address64 address64; - struct acpi_resource_extended_address64 ext_address64; - struct acpi_resource_extended_irq extended_irq; - struct acpi_resource_generic_register generic_reg; - struct acpi_resource_gpio gpio; - struct acpi_resource_i2c_serialbus i2c_serial_bus; - struct acpi_resource_spi_serialbus spi_serial_bus; - struct acpi_resource_uart_serialbus uart_serial_bus; - struct acpi_resource_csi2_serialbus csi2_serial_bus; - struct acpi_resource_common_serialbus common_serial_bus; - struct acpi_resource_pin_function pin_function; - struct acpi_resource_pin_config pin_config; - struct acpi_resource_pin_group pin_group; - struct acpi_resource_pin_group_function pin_group_function; - struct acpi_resource_pin_group_config pin_group_config; - struct acpi_resource_address address; -}; - -struct acpi_resource { - u32 type; - u32 length; - union acpi_resource_data data; -} __attribute__((packed)); - -typedef acpi_status (*acpi_walk_resource_callback)(struct acpi_resource *, void *); - -struct acpi_gpiolib_dmi_quirk { - bool no_edge_events_on_boot; - char *ignore_wake; -}; - -struct acpi_gpio_event { - struct list_head node; - acpi_handle handle; - irq_handler_t handler; - unsigned int pin; - unsigned int irq; - long unsigned int irqflags; - bool irq_is_wake; - bool irq_requested; - struct gpio_desc___2 *desc; -}; - -struct acpi_gpio_connection { - struct list_head node; - unsigned int pin; - struct gpio_desc___2 *desc; -}; - -struct acpi_gpio_chip { - struct acpi_connection_info conn_info; - struct list_head conns; - struct mutex conn_lock; - struct gpio_chip *chip; - struct list_head events; - struct list_head deferred_req_irqs_list_entry; -}; - -struct acpi_gpio_lookup { - struct acpi_gpio_info info; - int index; - u16 pin_index; - bool active_low; - struct gpio_desc___2 *desc; - int n; -}; - -struct extcon_dev; - -struct regulator_dev; - -struct regulator_ops { - int (*list_voltage)(struct regulator_dev *, unsigned int); - int (*set_voltage)(struct regulator_dev *, int, int, unsigned int *); - int (*map_voltage)(struct regulator_dev *, int, int); - int (*set_voltage_sel)(struct regulator_dev *, unsigned int); - int (*get_voltage)(struct regulator_dev *); - int (*get_voltage_sel)(struct regulator_dev *); - int (*set_current_limit)(struct regulator_dev *, int, int); - int (*get_current_limit)(struct regulator_dev *); - int (*set_input_current_limit)(struct regulator_dev *, int); - int (*set_over_current_protection)(struct regulator_dev *, int, int, bool); - int (*set_over_voltage_protection)(struct regulator_dev *, int, int, bool); - int (*set_under_voltage_protection)(struct regulator_dev *, int, int, bool); - int (*set_thermal_protection)(struct regulator_dev *, int, int, bool); - int (*set_active_discharge)(struct regulator_dev *, bool); - int (*enable)(struct regulator_dev *); - int (*disable)(struct regulator_dev *); - int (*is_enabled)(struct regulator_dev *); - int (*set_mode)(struct regulator_dev *, unsigned int); - unsigned int (*get_mode)(struct regulator_dev *); - int (*get_error_flags)(struct regulator_dev *, unsigned int *); - int (*enable_time)(struct regulator_dev *); - int (*set_ramp_delay)(struct regulator_dev *, int); - int (*set_voltage_time)(struct regulator_dev *, int, int); - int (*set_voltage_time_sel)(struct regulator_dev *, unsigned int, unsigned int); - int (*set_soft_start)(struct regulator_dev *); - int (*get_status)(struct regulator_dev *); - unsigned int (*get_optimum_mode)(struct regulator_dev *, int, int, int); - int (*set_load)(struct regulator_dev *, int); - int (*set_bypass)(struct regulator_dev *, bool); - int (*get_bypass)(struct regulator_dev *, bool *); - int (*set_suspend_voltage)(struct regulator_dev *, int); - int (*set_suspend_enable)(struct regulator_dev *); - int (*set_suspend_disable)(struct regulator_dev *); - int (*set_suspend_mode)(struct regulator_dev *, unsigned int); - int (*resume)(struct regulator_dev *); - int (*set_pull_down)(struct regulator_dev *); -}; - -struct regulator_coupler; - -struct coupling_desc { - struct regulator_dev **coupled_rdevs; - struct regulator_coupler *coupler; - int n_resolved; - int n_coupled; -}; - -struct regulator_desc; - -struct regulation_constraints; - -struct regulator_enable_gpio; - -struct regulator_dev { - const struct regulator_desc *desc; - int exclusive; - u32 use_count; - u32 open_count; - u32 bypass_count; - struct list_head list; - struct list_head consumer_list; - struct coupling_desc coupling_desc; - struct blocking_notifier_head notifier; - struct ww_mutex mutex; - struct task_struct *mutex_owner; - int ref_cnt; - struct module *owner; - struct device dev; - struct regulation_constraints *constraints; - struct regulator *supply; - const char *supply_name; - struct regmap *regmap; - struct delayed_work disable_work; - void *reg_data; - struct dentry *debugfs; - struct regulator_enable_gpio *ena_pin; - unsigned int ena_gpio_state: 1; - unsigned int is_switch: 1; - ktime_t last_off; - int cached_err; - bool use_cached_err; - spinlock_t err_lock; -}; - -enum regulator_type { - REGULATOR_VOLTAGE = 0, - REGULATOR_CURRENT = 1, -}; - -struct regulator_config; - -struct regulator_desc { - const char *name; - const char *supply_name; - const char *of_match; - bool of_match_full_name; - const char *regulators_node; - int (*of_parse_cb)(struct device_node *, const struct regulator_desc *, struct regulator_config *); - int id; - unsigned int continuous_voltage_range: 1; - unsigned int n_voltages; - unsigned int n_current_limits; - const struct regulator_ops *ops; - int irq; - enum regulator_type type; - struct module *owner; - unsigned int min_uV; - unsigned int uV_step; - unsigned int linear_min_sel; - int fixed_uV; - unsigned int ramp_delay; - int min_dropout_uV; - const struct linear_range *linear_ranges; - const unsigned int *linear_range_selectors; - int n_linear_ranges; - const unsigned int *volt_table; - const unsigned int *curr_table; - unsigned int vsel_range_reg; - unsigned int vsel_range_mask; - unsigned int vsel_reg; - unsigned int vsel_mask; - unsigned int vsel_step; - unsigned int csel_reg; - unsigned int csel_mask; - unsigned int apply_reg; - unsigned int apply_bit; - unsigned int enable_reg; - unsigned int enable_mask; - unsigned int enable_val; - unsigned int disable_val; - bool enable_is_inverted; - unsigned int bypass_reg; - unsigned int bypass_mask; - unsigned int bypass_val_on; - unsigned int bypass_val_off; - unsigned int active_discharge_on; - unsigned int active_discharge_off; - unsigned int active_discharge_mask; - unsigned int active_discharge_reg; - unsigned int soft_start_reg; - unsigned int soft_start_mask; - unsigned int soft_start_val_on; - unsigned int pull_down_reg; - unsigned int pull_down_mask; - unsigned int pull_down_val_on; - unsigned int ramp_reg; - unsigned int ramp_mask; - const unsigned int *ramp_delay_table; - unsigned int n_ramp_values; - unsigned int enable_time; - unsigned int off_on_delay; - unsigned int poll_enabled_time; - unsigned int (*of_map_mode)(unsigned int); -}; - -struct regulator_init_data; - -struct regulator_config { - struct device *dev; - const struct regulator_init_data *init_data; - void *driver_data; - struct device_node *of_node; - struct regmap *regmap; - struct gpio_desc *ena_gpiod; -}; - -struct regulator_state { - int uV; - int min_uV; - int max_uV; - unsigned int mode; - int enabled; - bool changeable; -}; - -struct notification_limit { - int prot; - int err; - int warn; -}; - -struct regulation_constraints { - const char *name; - int min_uV; - int max_uV; - int uV_offset; - int min_uA; - int max_uA; - int ilim_uA; - int system_load; - u32 *max_spread; - int max_uV_step; - unsigned int valid_modes_mask; - unsigned int valid_ops_mask; - int input_uV; - struct regulator_state state_disk; - struct regulator_state state_mem; - struct regulator_state state_standby; - struct notification_limit over_curr_limits; - struct notification_limit over_voltage_limits; - struct notification_limit under_voltage_limits; - struct notification_limit temp_limits; - suspend_state_t initial_state; - unsigned int initial_mode; - unsigned int ramp_delay; - unsigned int settling_time; - unsigned int settling_time_up; - unsigned int settling_time_down; - unsigned int enable_time; - unsigned int active_discharge; - unsigned int always_on: 1; - unsigned int boot_on: 1; - unsigned int apply_uV: 1; - unsigned int ramp_disable: 1; - unsigned int soft_start: 1; - unsigned int pull_down: 1; - unsigned int over_current_protection: 1; - unsigned int over_current_detection: 1; - unsigned int over_voltage_detection: 1; - unsigned int under_voltage_detection: 1; - unsigned int over_temp_detection: 1; -}; - -struct regulator_consumer_supply; - -struct regulator_init_data { - const char *supply_regulator; - struct regulation_constraints constraints; - int num_consumer_supplies; - struct regulator_consumer_supply *consumer_supplies; - int (*regulator_init)(void *); - void *driver_data; -}; - -enum palmas_usb_state { - PALMAS_USB_STATE_DISCONNECT = 0, - PALMAS_USB_STATE_VBUS = 1, - PALMAS_USB_STATE_ID = 2, -}; - -struct regmap_irq_chip_data; - -struct palmas_gpadc; - -struct palmas_pmic_driver_data; - -struct palmas_pmic; - -struct palmas_resource; - -struct palmas_usb; - -struct palmas { - struct device *dev; - struct i2c_client *i2c_clients[3]; - struct regmap *regmap[3]; - int id; - unsigned int features; - int irq; - u32 irq_mask; - struct mutex irq_lock; - struct regmap_irq_chip_data *irq_data; - struct palmas_pmic_driver_data *pmic_ddata; - struct palmas_pmic *pmic; - struct palmas_gpadc *gpadc; - struct palmas_resource *resource; - struct palmas_usb *usb; - u8 gpio_muxed; - u8 led_muxed; - u8 pwm_muxed; -}; - -struct of_regulator_match; - -struct palmas_regs_info; - -struct palmas_sleep_requestor_info; - -struct palmas_pmic_platform_data; - -struct palmas_pmic_driver_data { - int smps_start; - int smps_end; - int ldo_begin; - int ldo_end; - int max_reg; - bool has_regen3; - struct palmas_regs_info *palmas_regs_info; - struct of_regulator_match *palmas_matches; - struct palmas_sleep_requestor_info *sleep_req_info; - int (*smps_register)(struct palmas_pmic *, struct palmas_pmic_driver_data *, struct palmas_pmic_platform_data *, const char *, struct regulator_config); - int (*ldo_register)(struct palmas_pmic *, struct palmas_pmic_driver_data *, struct palmas_pmic_platform_data *, const char *, struct regulator_config); -}; - -struct palmas_pmic { - struct palmas *palmas; - struct device *dev; - struct regulator_desc desc[27]; - struct mutex mutex; - int smps123; - int smps457; - int smps12; - int range[10]; - unsigned int ramp_delay[10]; - unsigned int current_reg_mode[10]; -}; - -struct palmas_resource { - struct palmas *palmas; - struct device *dev; -}; - -struct palmas_usb { - struct palmas *palmas; - struct device *dev; - struct extcon_dev *edev; - int id_otg_irq; - int id_irq; - int vbus_otg_irq; - int vbus_irq; - int gpio_id_irq; - int gpio_vbus_irq; - struct gpio_desc *id_gpiod; - struct gpio_desc *vbus_gpiod; - long unsigned int sw_debounce_jiffies; - struct delayed_work wq_detectid; - enum palmas_usb_state linkstat; - int wakeup; - bool enable_vbus_detection; - bool enable_id_detection; - bool enable_gpio_id_detection; - bool enable_gpio_vbus_detection; -}; - -struct palmas_sleep_requestor_info { - int id; - int reg_offset; - int bit_pos; -}; - -struct palmas_regs_info { - char *name; - char *sname; - u8 vsel_addr; - u8 ctrl_addr; - u8 tstep_addr; - int sleep_id; -}; - -struct palmas_reg_init; - -struct palmas_pmic_platform_data { - struct regulator_init_data *reg_data[27]; - struct palmas_reg_init *reg_init[27]; - int ldo6_vibrator; - bool enable_ldo8_tracking; -}; - -struct palmas_adc_wakeup_property { - int adc_channel_number; - int adc_high_threshold; - int adc_low_threshold; -}; - -struct palmas_gpadc_platform_data { - int ch3_current; - int ch0_current; - bool extended_delay; - int bat_removal; - int start_polarity; - int auto_conversion_period_ms; - struct palmas_adc_wakeup_property *adc_wakeup1_data; - struct palmas_adc_wakeup_property *adc_wakeup2_data; -}; - -struct palmas_reg_init { - int warm_reset; - int roof_floor; - int mode_sleep; - u8 vsel; -}; - -enum palmas_regulators { - PALMAS_REG_SMPS12 = 0, - PALMAS_REG_SMPS123 = 1, - PALMAS_REG_SMPS3 = 2, - PALMAS_REG_SMPS45 = 3, - PALMAS_REG_SMPS457 = 4, - PALMAS_REG_SMPS6 = 5, - PALMAS_REG_SMPS7 = 6, - PALMAS_REG_SMPS8 = 7, - PALMAS_REG_SMPS9 = 8, - PALMAS_REG_SMPS10_OUT2 = 9, - PALMAS_REG_SMPS10_OUT1 = 10, - PALMAS_REG_LDO1 = 11, - PALMAS_REG_LDO2 = 12, - PALMAS_REG_LDO3 = 13, - PALMAS_REG_LDO4 = 14, - PALMAS_REG_LDO5 = 15, - PALMAS_REG_LDO6 = 16, - PALMAS_REG_LDO7 = 17, - PALMAS_REG_LDO8 = 18, - PALMAS_REG_LDO9 = 19, - PALMAS_REG_LDOLN = 20, - PALMAS_REG_LDOUSB = 21, - PALMAS_REG_REGEN1 = 22, - PALMAS_REG_REGEN2 = 23, - PALMAS_REG_REGEN3 = 24, - PALMAS_REG_SYSEN1 = 25, - PALMAS_REG_SYSEN2 = 26, - PALMAS_NUM_REGS = 27, -}; - -struct palmas_usb_platform_data { - int wakeup; -}; - -struct palmas_resource_platform_data { - int regen1_mode_sleep; - int regen2_mode_sleep; - int sysen1_mode_sleep; - int sysen2_mode_sleep; - u8 nsleep_res; - u8 nsleep_smps; - u8 nsleep_ldo1; - u8 nsleep_ldo2; - u8 enable1_res; - u8 enable1_smps; - u8 enable1_ldo1; - u8 enable1_ldo2; - u8 enable2_res; - u8 enable2_smps; - u8 enable2_ldo1; - u8 enable2_ldo2; -}; - -struct palmas_clk_platform_data { - int clk32kg_mode_sleep; - int clk32kgaudio_mode_sleep; -}; - -struct palmas_platform_data { - int irq_flags; - int gpio_base; - u8 power_ctrl; - int mux_from_pdata; - u8 pad1; - u8 pad2; - bool pm_off; - struct palmas_pmic_platform_data *pmic_pdata; - struct palmas_gpadc_platform_data *gpadc_pdata; - struct palmas_usb_platform_data *usb_pdata; - struct palmas_resource_platform_data *resource_pdata; - struct palmas_clk_platform_data *clk_pdata; -}; - -enum palmas_irqs { - PALMAS_CHARG_DET_N_VBUS_OVV_IRQ = 0, - PALMAS_PWRON_IRQ = 1, - PALMAS_LONG_PRESS_KEY_IRQ = 2, - PALMAS_RPWRON_IRQ = 3, - PALMAS_PWRDOWN_IRQ = 4, - PALMAS_HOTDIE_IRQ = 5, - PALMAS_VSYS_MON_IRQ = 6, - PALMAS_VBAT_MON_IRQ = 7, - PALMAS_RTC_ALARM_IRQ = 8, - PALMAS_RTC_TIMER_IRQ = 9, - PALMAS_WDT_IRQ = 10, - PALMAS_BATREMOVAL_IRQ = 11, - PALMAS_RESET_IN_IRQ = 12, - PALMAS_FBI_BB_IRQ = 13, - PALMAS_SHORT_IRQ = 14, - PALMAS_VAC_ACOK_IRQ = 15, - PALMAS_GPADC_AUTO_0_IRQ = 16, - PALMAS_GPADC_AUTO_1_IRQ = 17, - PALMAS_GPADC_EOC_SW_IRQ = 18, - PALMAS_GPADC_EOC_RT_IRQ = 19, - PALMAS_ID_OTG_IRQ = 20, - PALMAS_ID_IRQ = 21, - PALMAS_VBUS_OTG_IRQ = 22, - PALMAS_VBUS_IRQ = 23, - PALMAS_GPIO_0_IRQ = 24, - PALMAS_GPIO_1_IRQ = 25, - PALMAS_GPIO_2_IRQ = 26, - PALMAS_GPIO_3_IRQ = 27, - PALMAS_GPIO_4_IRQ = 28, - PALMAS_GPIO_5_IRQ = 29, - PALMAS_GPIO_6_IRQ = 30, - PALMAS_GPIO_7_IRQ = 31, - PALMAS_NUM_IRQ = 32, -}; - -struct palmas_gpio { - struct gpio_chip gpio_chip; - struct palmas *palmas; -}; - -struct palmas_device_data { - int ngpio; -}; - -enum { - RC5T583_IRQ_ONKEY = 0, - RC5T583_IRQ_ACOK = 1, - RC5T583_IRQ_LIDOPEN = 2, - RC5T583_IRQ_PREOT = 3, - RC5T583_IRQ_CLKSTP = 4, - RC5T583_IRQ_ONKEY_OFF = 5, - RC5T583_IRQ_WD = 6, - RC5T583_IRQ_EN_PWRREQ1 = 7, - RC5T583_IRQ_EN_PWRREQ2 = 8, - RC5T583_IRQ_PRE_VINDET = 9, - RC5T583_IRQ_DC0LIM = 10, - RC5T583_IRQ_DC1LIM = 11, - RC5T583_IRQ_DC2LIM = 12, - RC5T583_IRQ_DC3LIM = 13, - RC5T583_IRQ_CTC = 14, - RC5T583_IRQ_YALE = 15, - RC5T583_IRQ_DALE = 16, - RC5T583_IRQ_WALE = 17, - RC5T583_IRQ_AIN1L = 18, - RC5T583_IRQ_AIN2L = 19, - RC5T583_IRQ_AIN3L = 20, - RC5T583_IRQ_VBATL = 21, - RC5T583_IRQ_VIN3L = 22, - RC5T583_IRQ_VIN8L = 23, - RC5T583_IRQ_AIN1H = 24, - RC5T583_IRQ_AIN2H = 25, - RC5T583_IRQ_AIN3H = 26, - RC5T583_IRQ_VBATH = 27, - RC5T583_IRQ_VIN3H = 28, - RC5T583_IRQ_VIN8H = 29, - RC5T583_IRQ_ADCEND = 30, - RC5T583_IRQ_GPIO0 = 31, - RC5T583_IRQ_GPIO1 = 32, - RC5T583_IRQ_GPIO2 = 33, - RC5T583_IRQ_GPIO3 = 34, - RC5T583_IRQ_GPIO4 = 35, - RC5T583_IRQ_GPIO5 = 36, - RC5T583_IRQ_GPIO6 = 37, - RC5T583_IRQ_GPIO7 = 38, - RC5T583_MAX_IRQS = 39, -}; - -enum { - RC5T583_GPIO0 = 0, - RC5T583_GPIO1 = 1, - RC5T583_GPIO2 = 2, - RC5T583_GPIO3 = 3, - RC5T583_GPIO4 = 4, - RC5T583_GPIO5 = 5, - RC5T583_GPIO6 = 6, - RC5T583_GPIO7 = 7, - RC5T583_MAX_GPIO = 8, -}; - -enum { - RC5T583_REGULATOR_DC0 = 0, - RC5T583_REGULATOR_DC1 = 1, - RC5T583_REGULATOR_DC2 = 2, - RC5T583_REGULATOR_DC3 = 3, - RC5T583_REGULATOR_LDO0 = 4, - RC5T583_REGULATOR_LDO1 = 5, - RC5T583_REGULATOR_LDO2 = 6, - RC5T583_REGULATOR_LDO3 = 7, - RC5T583_REGULATOR_LDO4 = 8, - RC5T583_REGULATOR_LDO5 = 9, - RC5T583_REGULATOR_LDO6 = 10, - RC5T583_REGULATOR_LDO7 = 11, - RC5T583_REGULATOR_LDO8 = 12, - RC5T583_REGULATOR_LDO9 = 13, - RC5T583_REGULATOR_MAX = 14, -}; - -struct rc5t583 { - struct device *dev; - struct regmap *regmap; - int chip_irq; - int irq_base; - struct mutex irq_lock; - long unsigned int group_irq_en[5]; - uint8_t intc_inten_reg; - uint8_t irq_en_reg[8]; - uint8_t gpedge_reg[2]; -}; - -struct rc5t583_platform_data { - int irq_base; - int gpio_base; - bool enable_shutdown; - int regulator_deepsleep_slot[14]; - long unsigned int regulator_ext_pwr_control[14]; - struct regulator_init_data *reg_init_data[14]; -}; - -struct rc5t583_gpio { - struct gpio_chip gpio_chip; - struct rc5t583 *rc5t583; -}; - -enum { - TPS6586X_ID_SYS = 0, - TPS6586X_ID_SM_0 = 1, - TPS6586X_ID_SM_1 = 2, - TPS6586X_ID_SM_2 = 3, - TPS6586X_ID_LDO_0 = 4, - TPS6586X_ID_LDO_1 = 5, - TPS6586X_ID_LDO_2 = 6, - TPS6586X_ID_LDO_3 = 7, - TPS6586X_ID_LDO_4 = 8, - TPS6586X_ID_LDO_5 = 9, - TPS6586X_ID_LDO_6 = 10, - TPS6586X_ID_LDO_7 = 11, - TPS6586X_ID_LDO_8 = 12, - TPS6586X_ID_LDO_9 = 13, - TPS6586X_ID_LDO_RTC = 14, - TPS6586X_ID_MAX_REGULATOR = 15, -}; - -enum { - TPS6586X_INT_PLDO_0 = 0, - TPS6586X_INT_PLDO_1 = 1, - TPS6586X_INT_PLDO_2 = 2, - TPS6586X_INT_PLDO_3 = 3, - TPS6586X_INT_PLDO_4 = 4, - TPS6586X_INT_PLDO_5 = 5, - TPS6586X_INT_PLDO_6 = 6, - TPS6586X_INT_PLDO_7 = 7, - TPS6586X_INT_COMP_DET = 8, - TPS6586X_INT_ADC = 9, - TPS6586X_INT_PLDO_8 = 10, - TPS6586X_INT_PLDO_9 = 11, - TPS6586X_INT_PSM_0 = 12, - TPS6586X_INT_PSM_1 = 13, - TPS6586X_INT_PSM_2 = 14, - TPS6586X_INT_PSM_3 = 15, - TPS6586X_INT_RTC_ALM1 = 16, - TPS6586X_INT_ACUSB_OVP = 17, - TPS6586X_INT_USB_DET = 18, - TPS6586X_INT_AC_DET = 19, - TPS6586X_INT_BAT_DET = 20, - TPS6586X_INT_CHG_STAT = 21, - TPS6586X_INT_CHG_TEMP = 22, - TPS6586X_INT_PP = 23, - TPS6586X_INT_RESUME = 24, - TPS6586X_INT_LOW_SYS = 25, - TPS6586X_INT_RTC_ALM2 = 26, -}; - -struct tps6586x_subdev_info { - int id; - const char *name; - void *platform_data; - struct device_node *of_node; -}; - -struct tps6586x_platform_data { - int num_subdevs; - struct tps6586x_subdev_info *subdevs; - int gpio_base; - int irq_base; - bool pm_off; - struct regulator_init_data *reg_init_data[15]; -}; - -struct tps6586x_gpio { - struct gpio_chip gpio_chip; - struct device *parent; -}; - -struct tps65910_sleep_keepon_data { - unsigned int therm_keepon: 1; - unsigned int clkout32k_keepon: 1; - unsigned int i2chs_keepon: 1; -}; - -struct tps65910_board { - int gpio_base; - int irq; - int irq_base; - int vmbch_threshold; - int vmbch2_threshold; - bool en_ck32k_xtal; - bool en_dev_slp; - bool pm_off; - struct tps65910_sleep_keepon_data slp_keepon; - bool en_gpio_sleep[9]; - long unsigned int regulator_ext_sleep_control[14]; - struct regulator_init_data *tps65910_pmic_init_data[14]; -}; - -struct tps65910 { - struct device *dev; - struct i2c_client *i2c_client; - struct regmap *regmap; - long unsigned int id; - struct tps65910_board *of_plat_data; - int chip_irq; - struct regmap_irq_chip_data *irq_data; -}; - -struct tps65910_gpio { - struct gpio_chip gpio_chip; - struct tps65910 *tps65910; -}; - -struct tps68470_gpio_data { - struct regmap *tps68470_regmap; - struct gpio_chip gc; -}; - -enum pwm_polarity { - PWM_POLARITY_NORMAL = 0, - PWM_POLARITY_INVERSED = 1, -}; - -struct pwm_args { - u64 period; - enum pwm_polarity polarity; -}; - -enum { - PWMF_REQUESTED = 1, - PWMF_EXPORTED = 2, -}; - -struct pwm_state { - u64 period; - u64 duty_cycle; - enum pwm_polarity polarity; - bool enabled; - bool usage_power; -}; - -struct pwm_chip; - -struct pwm_device { - const char *label; - long unsigned int flags; - unsigned int hwpwm; - unsigned int pwm; - struct pwm_chip *chip; - void *chip_data; - struct pwm_args args; - struct pwm_state state; - struct pwm_state last; -}; - -struct pwm_ops; - -struct pwm_chip { - struct device *dev; - const struct pwm_ops *ops; - int base; - unsigned int npwm; - struct pwm_device * (*of_xlate)(struct pwm_chip *, const struct of_phandle_args *); - unsigned int of_pwm_n_cells; - struct list_head list; - struct pwm_device *pwms; -}; - -struct pwm_capture; - -struct pwm_ops { - int (*request)(struct pwm_chip *, struct pwm_device *); - void (*free)(struct pwm_chip *, struct pwm_device *); - int (*capture)(struct pwm_chip *, struct pwm_device *, struct pwm_capture *, long unsigned int); - int (*apply)(struct pwm_chip *, struct pwm_device *, const struct pwm_state *); - void (*get_state)(struct pwm_chip *, struct pwm_device *, struct pwm_state *); - struct module *owner; - int (*config)(struct pwm_chip *, struct pwm_device *, int, int); - int (*set_polarity)(struct pwm_chip *, struct pwm_device *, enum pwm_polarity); - int (*enable)(struct pwm_chip *, struct pwm_device *); - void (*disable)(struct pwm_chip *, struct pwm_device *); -}; - -struct pwm_capture { - unsigned int period; - unsigned int duty_cycle; -}; - -struct pwm_lookup { - struct list_head list; - const char *provider; - unsigned int index; - const char *dev_id; - const char *con_id; - unsigned int period; - enum pwm_polarity polarity; - const char *module; -}; - -struct trace_event_raw_pwm { - struct trace_entry ent; - struct pwm_device *pwm; - u64 period; - u64 duty_cycle; - enum pwm_polarity polarity; - bool enabled; - char __data[0]; -}; - -struct trace_event_data_offsets_pwm {}; - -typedef void (*btf_trace_pwm_apply)(void *, struct pwm_device *, const struct pwm_state *); - -typedef void (*btf_trace_pwm_get)(void *, struct pwm_device *, const struct pwm_state *); - -struct pwm_export { - struct device child; - struct pwm_device *pwm; - struct mutex lock; - struct pwm_state suspend; -}; - -struct intel_scu_ipc_dev; - -struct intel_soc_pmic { - int irq; - struct regmap *regmap; - struct regmap_irq_chip_data *irq_chip_data; - struct regmap_irq_chip_data *irq_chip_data_pwrbtn; - struct regmap_irq_chip_data *irq_chip_data_tmu; - struct regmap_irq_chip_data *irq_chip_data_bcu; - struct regmap_irq_chip_data *irq_chip_data_adc; - struct regmap_irq_chip_data *irq_chip_data_chgr; - struct regmap_irq_chip_data *irq_chip_data_crit; - struct device *dev; - struct intel_scu_ipc_dev *scu; -}; - -struct crystalcove_pwm { - struct pwm_chip chip; - struct regmap *regmap; -}; - -enum { - pci_channel_io_normal = 1, - pci_channel_io_frozen = 2, - pci_channel_io_perm_failure = 3, -}; - -struct pci_sriov { - int pos; - int nres; - u32 cap; - u16 ctrl; - u16 total_VFs; - u16 initial_VFs; - u16 num_VFs; - u16 offset; - u16 stride; - u16 vf_device; - u32 pgsz; - u8 link; - u8 max_VF_buses; - u16 driver_max_VFs; - struct pci_dev *dev; - struct pci_dev *self; - u32 class; - u8 hdr_type; - u16 subsystem_vendor; - u16 subsystem_device; - resource_size_t barsz[6]; - bool drivers_autoprobe; -}; - -struct rcec_ea { - u8 nextbusn; - u8 lastbusn; - u32 bitmap; -}; - -struct pci_bus_resource { - struct list_head list; - struct resource *res; - unsigned int flags; -}; - -typedef u64 pci_bus_addr_t; - -struct pci_bus_region { - pci_bus_addr_t start; - pci_bus_addr_t end; -}; - -enum pci_fixup_pass { - pci_fixup_early = 0, - pci_fixup_header = 1, - pci_fixup_final = 2, - pci_fixup_enable = 3, - pci_fixup_resume = 4, - pci_fixup_suspend = 5, - pci_fixup_resume_early = 6, - pci_fixup_suspend_late = 7, -}; - -struct hotplug_slot_ops; - -struct hotplug_slot { - const struct hotplug_slot_ops *ops; - struct list_head slot_list; - struct pci_slot *pci_slot; - struct module *owner; - const char *mod_name; -}; - -enum pci_dev_flags { - PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = 1, - PCI_DEV_FLAGS_NO_D3 = 2, - PCI_DEV_FLAGS_ASSIGNED = 4, - PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = 8, - PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = 32, - PCI_DEV_FLAGS_NO_BUS_RESET = 64, - PCI_DEV_FLAGS_NO_PM_RESET = 128, - PCI_DEV_FLAGS_VPD_REF_F0 = 256, - PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT = 512, - PCI_DEV_FLAGS_NO_FLR_RESET = 1024, - PCI_DEV_FLAGS_NO_RELAXED_ORDERING = 2048, -}; - -enum pci_bus_flags { - PCI_BUS_FLAGS_NO_MSI = 1, - PCI_BUS_FLAGS_NO_MMRBC = 2, - PCI_BUS_FLAGS_NO_AERSID = 4, - PCI_BUS_FLAGS_NO_EXTCFG = 8, -}; - -enum pci_bus_speed { - PCI_SPEED_33MHz = 0, - PCI_SPEED_66MHz = 1, - PCI_SPEED_66MHz_PCIX = 2, - PCI_SPEED_100MHz_PCIX = 3, - PCI_SPEED_133MHz_PCIX = 4, - PCI_SPEED_66MHz_PCIX_ECC = 5, - PCI_SPEED_100MHz_PCIX_ECC = 6, - PCI_SPEED_133MHz_PCIX_ECC = 7, - PCI_SPEED_66MHz_PCIX_266 = 9, - PCI_SPEED_100MHz_PCIX_266 = 10, - PCI_SPEED_133MHz_PCIX_266 = 11, - AGP_UNKNOWN = 12, - AGP_1X = 13, - AGP_2X = 14, - AGP_4X = 15, - AGP_8X = 16, - PCI_SPEED_66MHz_PCIX_533 = 17, - PCI_SPEED_100MHz_PCIX_533 = 18, - PCI_SPEED_133MHz_PCIX_533 = 19, - PCIE_SPEED_2_5GT = 20, - PCIE_SPEED_5_0GT = 21, - PCIE_SPEED_8_0GT = 22, - PCIE_SPEED_16_0GT = 23, - PCIE_SPEED_32_0GT = 24, - PCIE_SPEED_64_0GT = 25, - PCI_SPEED_UNKNOWN = 255, -}; - -struct pci_host_bridge { - struct device dev; - struct pci_bus *bus; - struct pci_ops *ops; - struct pci_ops *child_ops; - void *sysdata; - int busnr; - struct list_head windows; - struct list_head dma_ranges; - u8 (*swizzle_irq)(struct pci_dev *, u8 *); - int (*map_irq)(const struct pci_dev *, u8, u8); - void (*release_fn)(struct pci_host_bridge *); - void *release_data; - unsigned int ignore_reset_delay: 1; - unsigned int no_ext_tags: 1; - unsigned int native_aer: 1; - unsigned int native_pcie_hotplug: 1; - unsigned int native_shpc_hotplug: 1; - unsigned int native_pme: 1; - unsigned int native_ltr: 1; - unsigned int native_dpc: 1; - unsigned int preserve_config: 1; - unsigned int size_windows: 1; - unsigned int msi_domain: 1; - resource_size_t (*align_resource)(struct pci_dev *, const struct resource *, resource_size_t, resource_size_t, resource_size_t); - long: 64; - long: 64; - long: 64; - long: 64; - long unsigned int private[0]; -}; - -enum { - PCI_REASSIGN_ALL_RSRC = 1, - PCI_REASSIGN_ALL_BUS = 2, - PCI_PROBE_ONLY = 4, - PCI_CAN_SKIP_ISA_ALIGN = 8, - PCI_ENABLE_PROC_DOMAINS = 16, - PCI_COMPAT_DOMAIN_0 = 32, - PCI_SCAN_ALL_PCIE_DEVS = 64, -}; - -enum pcie_bus_config_types { - PCIE_BUS_TUNE_OFF = 0, - PCIE_BUS_DEFAULT = 1, - PCIE_BUS_SAFE = 2, - PCIE_BUS_PERFORMANCE = 3, - PCIE_BUS_PEER2PEER = 4, -}; - -struct hotplug_slot_ops { - int (*enable_slot)(struct hotplug_slot *); - int (*disable_slot)(struct hotplug_slot *); - int (*set_attention_status)(struct hotplug_slot *, u8); - int (*hardware_test)(struct hotplug_slot *, u32); - int (*get_power_status)(struct hotplug_slot *, u8 *); - int (*get_attention_status)(struct hotplug_slot *, u8 *); - int (*get_latch_status)(struct hotplug_slot *, u8 *); - int (*get_adapter_status)(struct hotplug_slot *, u8 *); - int (*reset_slot)(struct hotplug_slot *, int); -}; - -enum pci_bar_type { - pci_bar_unknown = 0, - pci_bar_io = 1, - pci_bar_mem32 = 2, - pci_bar_mem64 = 3, -}; - -struct pci_domain_busn_res { - struct list_head list; - struct resource res; - int domain_nr; -}; - -struct bus_attribute { - struct attribute attr; - ssize_t (*show)(struct bus_type *, char *); - ssize_t (*store)(struct bus_type *, const char *, size_t); -}; - -enum pcie_reset_state { - pcie_deassert_reset = 1, - pcie_warm_reset = 2, - pcie_hot_reset = 3, -}; - -enum pcie_link_width { - PCIE_LNK_WIDTH_RESRV = 0, - PCIE_LNK_X1 = 1, - PCIE_LNK_X2 = 2, - PCIE_LNK_X4 = 4, - PCIE_LNK_X8 = 8, - PCIE_LNK_X12 = 12, - PCIE_LNK_X16 = 16, - PCIE_LNK_X32 = 32, - PCIE_LNK_WIDTH_UNKNOWN = 255, -}; - -struct pci_cap_saved_data { - u16 cap_nr; - bool cap_extended; - unsigned int size; - u32 data[0]; -}; - -struct pci_cap_saved_state { - struct hlist_node next; - struct pci_cap_saved_data cap; -}; - -typedef int (*arch_set_vga_state_t)(struct pci_dev *, bool, unsigned int, u32); - -struct pci_platform_pm_ops { - bool (*bridge_d3)(struct pci_dev *); - bool (*is_manageable)(struct pci_dev *); - int (*set_state)(struct pci_dev *, pci_power_t); - pci_power_t (*get_state)(struct pci_dev *); - void (*refresh_state)(struct pci_dev *); - pci_power_t (*choose_state)(struct pci_dev *); - int (*set_wakeup)(struct pci_dev *, bool); - bool (*need_resume)(struct pci_dev *); -}; - -struct pci_pme_device { - struct list_head list; - struct pci_dev *dev; -}; - -struct pci_saved_state { - u32 config_space[16]; - struct pci_cap_saved_data cap[0]; -}; - -struct pci_devres { - unsigned int enabled: 1; - unsigned int pinned: 1; - unsigned int orig_intx: 1; - unsigned int restore_intx: 1; - unsigned int mwi: 1; - u32 region_mask; -}; - -struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *, char *); - ssize_t (*store)(struct device_driver *, const char *, size_t); -}; - -enum pci_ers_result { - PCI_ERS_RESULT_NONE = 1, - PCI_ERS_RESULT_CAN_RECOVER = 2, - PCI_ERS_RESULT_NEED_RESET = 3, - PCI_ERS_RESULT_DISCONNECT = 4, - PCI_ERS_RESULT_RECOVERED = 5, - PCI_ERS_RESULT_NO_AER_DRIVER = 6, -}; - -enum dev_dma_attr { - DEV_DMA_NOT_SUPPORTED = 0, - DEV_DMA_NON_COHERENT = 1, - DEV_DMA_COHERENT = 2, -}; - -struct pcie_device { - int irq; - struct pci_dev *port; - u32 service; - void *priv_data; - struct device device; -}; - -struct pcie_port_service_driver { - const char *name; - int (*probe)(struct pcie_device *); - void (*remove)(struct pcie_device *); - int (*suspend)(struct pcie_device *); - int (*resume_noirq)(struct pcie_device *); - int (*resume)(struct pcie_device *); - int (*runtime_suspend)(struct pcie_device *); - int (*runtime_resume)(struct pcie_device *); - void (*error_resume)(struct pci_dev *); - int port_type; - u32 service; - struct device_driver driver; -}; - -struct pci_dynid { - struct list_head node; - struct pci_device_id id; -}; - -struct drv_dev_and_id { - struct pci_driver *drv; - struct pci_dev *dev; - const struct pci_device_id *id; -}; - -enum pci_mmap_state { - pci_mmap_io = 0, - pci_mmap_mem = 1, -}; - -enum pci_mmap_api { - PCI_MMAP_SYSFS = 0, - PCI_MMAP_PROCFS = 1, -}; - -struct pci_vpd_ops; - -struct pci_vpd { - const struct pci_vpd_ops *ops; - struct mutex lock; - unsigned int len; - u16 flag; - u8 cap; - unsigned int busy: 1; - unsigned int valid: 1; -}; - -struct pci_vpd_ops { - ssize_t (*read)(struct pci_dev *, loff_t, size_t, void *); - ssize_t (*write)(struct pci_dev *, loff_t, size_t, const void *); -}; - -struct pci_dev_resource { - struct list_head list; - struct resource *res; - struct pci_dev *dev; - resource_size_t start; - resource_size_t end; - resource_size_t add_size; - resource_size_t min_align; - long unsigned int flags; -}; - -enum release_type { - leaf_only = 0, - whole_subtree = 1, -}; - -enum enable_type { - undefined = 4294967295, - user_disabled = 0, - auto_disabled = 1, - user_enabled = 2, - auto_enabled = 3, -}; - -struct msix_entry { - u32 vector; - u16 entry; -}; - -struct portdrv_service_data { - struct pcie_port_service_driver *drv; - struct device *dev; - u32 service; -}; - -typedef int (*pcie_pm_callback_t)(struct pcie_device *); - -struct walk_rcec_data { - struct pci_dev *rcec; - int (*user_callback)(struct pci_dev *, void *); - void *user_data; -}; - -struct aspm_latency { - u32 l0s; - u32 l1; -}; - -struct pcie_link_state { - struct pci_dev *pdev; - struct pci_dev *downstream; - struct pcie_link_state *root; - struct pcie_link_state *parent; - struct list_head sibling; - u32 aspm_support: 7; - u32 aspm_enabled: 7; - u32 aspm_capable: 7; - u32 aspm_default: 7; - char: 4; - u32 aspm_disable: 7; - u32 clkpm_capable: 1; - u32 clkpm_enabled: 1; - u32 clkpm_default: 1; - u32 clkpm_disable: 1; - struct aspm_latency latency_up; - struct aspm_latency latency_dw; - struct aspm_latency acceptable[8]; -}; - -struct aer_stats { - u64 dev_cor_errs[16]; - u64 dev_fatal_errs[27]; - u64 dev_nonfatal_errs[27]; - u64 dev_total_cor_errs; - u64 dev_total_fatal_errs; - u64 dev_total_nonfatal_errs; - u64 rootport_total_cor_errs; - u64 rootport_total_fatal_errs; - u64 rootport_total_nonfatal_errs; -}; - -struct aer_header_log_regs { - unsigned int dw0; - unsigned int dw1; - unsigned int dw2; - unsigned int dw3; -}; - -struct aer_capability_regs { - u32 header; - u32 uncor_status; - u32 uncor_mask; - u32 uncor_severity; - u32 cor_status; - u32 cor_mask; - u32 cap_control; - struct aer_header_log_regs header_log; - u32 root_command; - u32 root_status; - u16 cor_err_source; - u16 uncor_err_source; -}; - -struct aer_err_info { - struct pci_dev *dev[5]; - int error_dev_num; - unsigned int id: 16; - unsigned int severity: 2; - unsigned int __pad1: 5; - unsigned int multi_error_valid: 1; - unsigned int first_error: 5; - unsigned int __pad2: 2; - unsigned int tlp_header_valid: 1; - unsigned int status; - unsigned int mask; - struct aer_header_log_regs tlp; -}; - -struct aer_err_source { - unsigned int status; - unsigned int id; -}; - -struct aer_rpc { - struct pci_dev *rpd; - struct { - union { - struct __kfifo kfifo; - struct aer_err_source *type; - const struct aer_err_source *const_type; - char (*rectype)[0]; - struct aer_err_source *ptr; - const struct aer_err_source *ptr_const; - }; - struct aer_err_source buf[128]; - } aer_fifo; -}; - -struct aer_recover_entry { - u8 bus; - u8 devfn; - u16 domain; - int severity; - struct aer_capability_regs *regs; -}; - -struct pcie_pme_service_data { - spinlock_t lock; - struct pcie_device *srv; - struct work_struct work; - bool noirq; -}; - -typedef void (*acpi_notify_handler)(acpi_handle, u32, void *); - -struct pci_filp_private { - enum pci_mmap_state mmap_state; - int write_combine; -}; - -struct pci_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct pci_slot *, char *); - ssize_t (*store)(struct pci_slot *, const char *, size_t); -}; - -struct acpi_bus_type { - struct list_head list; - const char *name; - bool (*match)(struct device *); - struct acpi_device * (*find_companion)(struct device *); - void (*setup)(struct device *); - void (*cleanup)(struct device *); -}; - -struct acpi_pci_root { - struct acpi_device *device; - struct pci_bus *bus; - u16 segment; - struct resource secondary; - u32 osc_support_set; - u32 osc_control_set; - phys_addr_t mcfg_addr; -}; - -enum pm_qos_flags_status { - PM_QOS_FLAGS_UNDEFINED = 4294967295, - PM_QOS_FLAGS_NONE = 0, - PM_QOS_FLAGS_SOME = 1, - PM_QOS_FLAGS_ALL = 2, -}; - -struct hpx_type0 { - u32 revision; - u8 cache_line_size; - u8 latency_timer; - u8 enable_serr; - u8 enable_perr; -}; - -struct hpx_type1 { - u32 revision; - u8 max_mem_read; - u8 avg_max_split; - u16 tot_max_split; -}; - -struct hpx_type2 { - u32 revision; - u32 unc_err_mask_and; - u32 unc_err_mask_or; - u32 unc_err_sever_and; - u32 unc_err_sever_or; - u32 cor_err_mask_and; - u32 cor_err_mask_or; - u32 adv_err_cap_and; - u32 adv_err_cap_or; - u16 pci_exp_devctl_and; - u16 pci_exp_devctl_or; - u16 pci_exp_lnkctl_and; - u16 pci_exp_lnkctl_or; - u32 sec_unc_err_sever_and; - u32 sec_unc_err_sever_or; - u32 sec_unc_err_mask_and; - u32 sec_unc_err_mask_or; -}; - -struct hpx_type3 { - u16 device_type; - u16 function_type; - u16 config_space_location; - u16 pci_exp_cap_id; - u16 pci_exp_cap_ver; - u16 pci_exp_vendor_id; - u16 dvsec_id; - u16 dvsec_rev; - u16 match_offset; - u32 match_mask_and; - u32 match_value; - u16 reg_offset; - u32 reg_mask_and; - u32 reg_mask_or; -}; - -enum hpx_type3_dev_type { - HPX_TYPE_ENDPOINT = 1, - HPX_TYPE_LEG_END = 2, - HPX_TYPE_RC_END = 4, - HPX_TYPE_RC_EC = 8, - HPX_TYPE_ROOT_PORT = 16, - HPX_TYPE_UPSTREAM = 32, - HPX_TYPE_DOWNSTREAM = 64, - HPX_TYPE_PCI_BRIDGE = 128, - HPX_TYPE_PCIE_BRIDGE = 256, -}; - -enum hpx_type3_fn_type { - HPX_FN_NORMAL = 1, - HPX_FN_SRIOV_PHYS = 2, - HPX_FN_SRIOV_VIRT = 4, -}; - -enum hpx_type3_cfg_loc { - HPX_CFG_PCICFG = 0, - HPX_CFG_PCIE_CAP = 1, - HPX_CFG_PCIE_CAP_EXT = 2, - HPX_CFG_VEND_CAP = 3, - HPX_CFG_DVSEC = 4, - HPX_CFG_MAX = 5, -}; - -enum pci_irq_reroute_variant { - INTEL_IRQ_REROUTE_VARIANT = 1, - MAX_IRQ_REROUTE_VARIANTS = 3, -}; - -struct pci_fixup { - u16 vendor; - u16 device; - u32 class; - unsigned int class_shift; - int hook_offset; -}; - -enum { - NVME_REG_CAP = 0, - NVME_REG_VS = 8, - NVME_REG_INTMS = 12, - NVME_REG_INTMC = 16, - NVME_REG_CC = 20, - NVME_REG_CSTS = 28, - NVME_REG_NSSR = 32, - NVME_REG_AQA = 36, - NVME_REG_ASQ = 40, - NVME_REG_ACQ = 48, - NVME_REG_CMBLOC = 56, - NVME_REG_CMBSZ = 60, - NVME_REG_BPINFO = 64, - NVME_REG_BPRSEL = 68, - NVME_REG_BPMBL = 72, - NVME_REG_CMBMSC = 80, - NVME_REG_PMRCAP = 3584, - NVME_REG_PMRCTL = 3588, - NVME_REG_PMRSTS = 3592, - NVME_REG_PMREBS = 3596, - NVME_REG_PMRSWTP = 3600, - NVME_REG_DBS = 4096, -}; - -enum { - NVME_CC_ENABLE = 1, - NVME_CC_EN_SHIFT = 0, - NVME_CC_CSS_SHIFT = 4, - NVME_CC_MPS_SHIFT = 7, - NVME_CC_AMS_SHIFT = 11, - NVME_CC_SHN_SHIFT = 14, - NVME_CC_IOSQES_SHIFT = 16, - NVME_CC_IOCQES_SHIFT = 20, - NVME_CC_CSS_NVM = 0, - NVME_CC_CSS_CSI = 96, - NVME_CC_CSS_MASK = 112, - NVME_CC_AMS_RR = 0, - NVME_CC_AMS_WRRU = 2048, - NVME_CC_AMS_VS = 14336, - NVME_CC_SHN_NONE = 0, - NVME_CC_SHN_NORMAL = 16384, - NVME_CC_SHN_ABRUPT = 32768, - NVME_CC_SHN_MASK = 49152, - NVME_CC_IOSQES = 393216, - NVME_CC_IOCQES = 4194304, - NVME_CAP_CSS_NVM = 1, - NVME_CAP_CSS_CSI = 64, - NVME_CSTS_RDY = 1, - NVME_CSTS_CFS = 2, - NVME_CSTS_NSSRO = 16, - NVME_CSTS_PP = 32, - NVME_CSTS_SHST_NORMAL = 0, - NVME_CSTS_SHST_OCCUR = 4, - NVME_CSTS_SHST_CMPLT = 8, - NVME_CSTS_SHST_MASK = 12, - NVME_CMBMSC_CRE = 1, - NVME_CMBMSC_CMSE = 2, -}; - -enum { - NVME_AEN_BIT_NS_ATTR = 8, - NVME_AEN_BIT_FW_ACT = 9, - NVME_AEN_BIT_ANA_CHANGE = 11, - NVME_AEN_BIT_DISC_CHANGE = 31, -}; - -enum { - SWITCHTEC_GAS_MRPC_OFFSET = 0, - SWITCHTEC_GAS_TOP_CFG_OFFSET = 4096, - SWITCHTEC_GAS_SW_EVENT_OFFSET = 6144, - SWITCHTEC_GAS_SYS_INFO_OFFSET = 8192, - SWITCHTEC_GAS_FLASH_INFO_OFFSET = 8704, - SWITCHTEC_GAS_PART_CFG_OFFSET = 16384, - SWITCHTEC_GAS_NTB_OFFSET = 65536, - SWITCHTEC_GAS_PFF_CSR_OFFSET = 1261568, -}; - -enum { - SWITCHTEC_NTB_REG_INFO_OFFSET = 0, - SWITCHTEC_NTB_REG_CTRL_OFFSET = 16384, - SWITCHTEC_NTB_REG_DBMSG_OFFSET = 409600, -}; - -struct nt_partition_info { - u32 xlink_enabled; - u32 target_part_low; - u32 target_part_high; - u32 reserved; -}; - -struct ntb_info_regs { - u8 partition_count; - u8 partition_id; - u16 reserved1; - u64 ep_map; - u16 requester_id; - u16 reserved2; - u32 reserved3[4]; - struct nt_partition_info ntp_info[48]; -} __attribute__((packed)); - -struct ntb_ctrl_regs { - u32 partition_status; - u32 partition_op; - u32 partition_ctrl; - u32 bar_setup; - u32 bar_error; - u16 lut_table_entries; - u16 lut_table_offset; - u32 lut_error; - u16 req_id_table_size; - u16 req_id_table_offset; - u32 req_id_error; - u32 reserved1[7]; - struct { - u32 ctl; - u32 win_size; - u64 xlate_addr; - } bar_entry[6]; - struct { - u32 win_size; - u32 reserved[3]; - } bar_ext_entry[6]; - u32 reserved2[192]; - u32 req_id_table[512]; - u32 reserved3[256]; - u64 lut_entry[512]; -}; - -struct pci_dev_reset_methods { - u16 vendor; - u16 device; - int (*reset)(struct pci_dev *, int); -}; - -struct pci_dev_acs_enabled { - u16 vendor; - u16 device; - int (*acs_enabled)(struct pci_dev *, u16); -}; - -struct pci_dev_acs_ops { - u16 vendor; - u16 device; - int (*enable_acs)(struct pci_dev *); - int (*disable_acs_redir)(struct pci_dev *); -}; - -struct slot { - u8 number; - unsigned int devfn; - struct pci_bus *bus; - struct pci_dev *dev; - unsigned int latch_status: 1; - unsigned int adapter_status: 1; - unsigned int extracting; - struct hotplug_slot hotplug_slot; - struct list_head slot_list; -}; - -struct cpci_hp_controller_ops { - int (*query_enum)(); - int (*enable_irq)(); - int (*disable_irq)(); - int (*check_irq)(void *); - int (*hardware_test)(struct slot *, u32); - u8 (*get_power)(struct slot *); - int (*set_power)(struct slot *, int); -}; - -struct cpci_hp_controller { - unsigned int irq; - long unsigned int irq_flags; - char *devname; - void *dev_id; - char *name; - struct cpci_hp_controller_ops *ops; -}; - -typedef acpi_status (*acpi_walk_callback)(acpi_handle, u32, void *, void **); - -struct controller { - struct pcie_device *pcie; - u32 slot_cap; - unsigned int inband_presence_disabled: 1; - u16 slot_ctrl; - struct mutex ctrl_lock; - long unsigned int cmd_started; - unsigned int cmd_busy: 1; - wait_queue_head_t queue; - atomic_t pending_events; - unsigned int notification_enabled: 1; - unsigned int power_fault_detected; - struct task_struct *poll_thread; - u8 state; - struct mutex state_lock; - struct delayed_work button_work; - struct hotplug_slot hotplug_slot; - struct rw_semaphore reset_lock; - unsigned int ist_running; - int request_result; - wait_queue_head_t requester; -}; - -struct controller___2; - -struct hpc_ops; - -struct slot___2 { - u8 bus; - u8 device; - u16 status; - u32 number; - u8 is_a_board; - u8 state; - u8 attention_save; - u8 presence_save; - u8 latch_save; - u8 pwr_save; - struct controller___2 *ctrl; - const struct hpc_ops *hpc_ops; - struct hotplug_slot hotplug_slot; - struct list_head slot_list; - struct delayed_work work; - struct mutex lock; - struct workqueue_struct *wq; - u8 hp_slot; -}; - -struct controller___2 { - struct mutex crit_sect; - struct mutex cmd_lock; - int num_slots; - int slot_num_inc; - struct pci_dev *pci_dev; - struct list_head slot_list; - const struct hpc_ops *hpc_ops; - wait_queue_head_t queue; - u8 slot_device_offset; - u32 pcix_misc2_reg; - u32 first_slot; - u32 cap_offset; - long unsigned int mmio_base; - long unsigned int mmio_size; - void *creg; - struct timer_list poll_timer; -}; - -struct hpc_ops { - int (*power_on_slot)(struct slot___2 *); - int (*slot_enable)(struct slot___2 *); - int (*slot_disable)(struct slot___2 *); - int (*set_bus_speed_mode)(struct slot___2 *, enum pci_bus_speed); - int (*get_power_status)(struct slot___2 *, u8 *); - int (*get_attention_status)(struct slot___2 *, u8 *); - int (*set_attention_status)(struct slot___2 *, u8); - int (*get_latch_status)(struct slot___2 *, u8 *); - int (*get_adapter_status)(struct slot___2 *, u8 *); - int (*get_adapter_speed)(struct slot___2 *, enum pci_bus_speed *); - int (*get_mode1_ECC_cap)(struct slot___2 *, u8 *); - int (*get_prog_int)(struct slot___2 *, u8 *); - int (*query_power_fault)(struct slot___2 *); - void (*green_led_on)(struct slot___2 *); - void (*green_led_off)(struct slot___2 *); - void (*green_led_blink)(struct slot___2 *); - void (*release_ctlr)(struct controller___2 *); - int (*check_cmd_status)(struct controller___2 *); -}; - -struct event_info { - u32 event_type; - struct slot___2 *p_slot; - struct work_struct work; -}; - -struct pushbutton_work_info { - struct slot___2 *p_slot; - struct work_struct work; -}; - -enum ctrl_offsets { - BASE_OFFSET = 0, - SLOT_AVAIL1 = 4, - SLOT_AVAIL2 = 8, - SLOT_CONFIG = 12, - SEC_BUS_CONFIG = 16, - MSI_CTRL = 18, - PROG_INTERFACE = 19, - CMD = 20, - CMD_STATUS = 22, - INTR_LOC = 24, - SERR_LOC = 28, - SERR_INTR_ENABLE = 32, - SLOT1 = 36, -}; - -struct acpiphp_slot; - -struct slot___3 { - struct hotplug_slot hotplug_slot; - struct acpiphp_slot *acpi_slot; - unsigned int sun; -}; - -struct acpiphp_slot { - struct list_head node; - struct pci_bus *bus; - struct list_head funcs; - struct slot___3 *slot; - u8 device; - u32 flags; -}; - -struct acpiphp_attention_info { - int (*set_attn)(struct hotplug_slot *, u8); - int (*get_attn)(struct hotplug_slot *, u8 *); - struct module *owner; -}; - -struct acpiphp_context; - -struct acpiphp_bridge { - struct list_head list; - struct list_head slots; - struct kref ref; - struct acpiphp_context *context; - int nr_slots; - struct pci_bus *pci_bus; - struct pci_dev *pci_dev; - bool is_going_away; -}; - -struct acpiphp_func { - struct acpiphp_bridge *parent; - struct acpiphp_slot *slot; - struct list_head sibling; - u8 function; - u32 flags; -}; - -struct acpiphp_context { - struct acpi_hotplug_context hp; - struct acpiphp_func func; - struct acpiphp_bridge *bridge; - unsigned int refcount; -}; - -struct acpiphp_root_context { - struct acpi_hotplug_context hp; - struct acpiphp_bridge *root_bridge; -}; - -enum dmi_device_type { - DMI_DEV_TYPE_ANY = 0, - DMI_DEV_TYPE_OTHER = 1, - DMI_DEV_TYPE_UNKNOWN = 2, - DMI_DEV_TYPE_VIDEO = 3, - DMI_DEV_TYPE_SCSI = 4, - DMI_DEV_TYPE_ETHERNET = 5, - DMI_DEV_TYPE_TOKENRING = 6, - DMI_DEV_TYPE_SOUND = 7, - DMI_DEV_TYPE_PATA = 8, - DMI_DEV_TYPE_SATA = 9, - DMI_DEV_TYPE_SAS = 10, - DMI_DEV_TYPE_IPMI = 4294967295, - DMI_DEV_TYPE_OEM_STRING = 4294967294, - DMI_DEV_TYPE_DEV_ONBOARD = 4294967293, - DMI_DEV_TYPE_DEV_SLOT = 4294967292, -}; - -struct dmi_device { - struct list_head list; - int type; - const char *name; - void *device_data; -}; - -struct dmi_dev_onboard { - struct dmi_device dev; - int instance; - int segment; - int bus; - int devfn; -}; - -enum smbios_attr_enum { - SMBIOS_ATTR_NONE = 0, - SMBIOS_ATTR_LABEL_SHOW = 1, - SMBIOS_ATTR_INSTANCE_SHOW = 2, -}; - -enum acpi_attr_enum { - ACPI_ATTR_LABEL_SHOW = 0, - ACPI_ATTR_INDEX_SHOW = 1, -}; - -struct pci_p2pdma { - struct gen_pool *pool; - bool p2pmem_published; - struct xarray map_types; -}; - -enum pci_p2pdma_map_type { - PCI_P2PDMA_MAP_UNKNOWN = 0, - PCI_P2PDMA_MAP_NOT_SUPPORTED = 1, - PCI_P2PDMA_MAP_BUS_ADDR = 2, - PCI_P2PDMA_MAP_THRU_HOST_BRIDGE = 3, -}; - -struct pci_p2pdma_pagemap { - struct dev_pagemap pgmap; - struct pci_dev *provider; - u64 bus_offset; -}; - -struct pci_p2pdma_whitelist_entry { - short unsigned int vendor; - short unsigned int device; - enum { - REQ_SAME_HOST_BRIDGE = 1, - } flags; -}; - -enum pci_interrupt_pin { - PCI_INTERRUPT_UNKNOWN = 0, - PCI_INTERRUPT_INTA = 1, - PCI_INTERRUPT_INTB = 2, - PCI_INTERRUPT_INTC = 3, - PCI_INTERRUPT_INTD = 4, -}; - -enum pci_barno { - NO_BAR = 4294967295, - BAR_0 = 0, - BAR_1 = 1, - BAR_2 = 2, - BAR_3 = 3, - BAR_4 = 4, - BAR_5 = 5, -}; - -struct pci_epf_header { - u16 vendorid; - u16 deviceid; - u8 revid; - u8 progif_code; - u8 subclass_code; - u8 baseclass_code; - u8 cache_line_size; - u16 subsys_vendor_id; - u16 subsys_id; - enum pci_interrupt_pin interrupt_pin; -}; - -struct pci_epf_bar { - dma_addr_t phys_addr; - void *addr; - size_t size; - enum pci_barno barno; - int flags; -}; - -struct pci_epc_ops; - -struct pci_epc_mem; - -struct pci_epc { - struct device dev; - struct list_head pci_epf; - const struct pci_epc_ops *ops; - struct pci_epc_mem **windows; - struct pci_epc_mem *mem; - unsigned int num_windows; - u8 max_functions; - struct config_group *group; - struct mutex lock; - long unsigned int function_num_map; - struct atomic_notifier_head notifier; -}; - -enum pci_epc_irq_type { - PCI_EPC_IRQ_UNKNOWN = 0, - PCI_EPC_IRQ_LEGACY = 1, - PCI_EPC_IRQ_MSI = 2, - PCI_EPC_IRQ_MSIX = 3, -}; - -struct pci_epc_features; - -struct pci_epc_ops { - int (*write_header)(struct pci_epc *, u8, struct pci_epf_header *); - int (*set_bar)(struct pci_epc *, u8, struct pci_epf_bar *); - void (*clear_bar)(struct pci_epc *, u8, struct pci_epf_bar *); - int (*map_addr)(struct pci_epc *, u8, phys_addr_t, u64, size_t); - void (*unmap_addr)(struct pci_epc *, u8, phys_addr_t); - int (*set_msi)(struct pci_epc *, u8, u8); - int (*get_msi)(struct pci_epc *, u8); - int (*set_msix)(struct pci_epc *, u8, u16, enum pci_barno, u32); - int (*get_msix)(struct pci_epc *, u8); - int (*raise_irq)(struct pci_epc *, u8, enum pci_epc_irq_type, u16); - int (*map_msi_irq)(struct pci_epc *, u8, phys_addr_t, u8, u32, u32 *, u32 *); - int (*start)(struct pci_epc *); - void (*stop)(struct pci_epc *); - const struct pci_epc_features * (*get_features)(struct pci_epc *, u8); - struct module *owner; -}; - -struct pci_epc_features { - unsigned int linkup_notifier: 1; - unsigned int core_init_notifier: 1; - unsigned int msi_capable: 1; - unsigned int msix_capable: 1; - u8 reserved_bar; - u8 bar_fixed_64bit; - u64 bar_fixed_size[6]; - size_t align; -}; - -struct pci_epc_mem_window { - phys_addr_t phys_base; - size_t size; - size_t page_size; -}; - -struct pci_epc_mem { - struct pci_epc_mem_window window; - long unsigned int *bitmap; - int pages; - struct mutex lock; -}; - -enum dw_pcie_region_type { - DW_PCIE_REGION_UNKNOWN = 0, - DW_PCIE_REGION_INBOUND = 1, - DW_PCIE_REGION_OUTBOUND = 2, -}; - -struct pcie_port; - -struct dw_pcie_host_ops { - int (*host_init)(struct pcie_port *); - int (*msi_host_init)(struct pcie_port *); -}; - -struct pcie_port { - bool has_msi_ctrl: 1; - u64 cfg0_base; - void *va_cfg0_base; - u32 cfg0_size; - resource_size_t io_base; - phys_addr_t io_bus_addr; - u32 io_size; - int irq; - const struct dw_pcie_host_ops *ops; - int msi_irq; - struct irq_domain *irq_domain; - struct irq_domain *msi_domain; - u16 msi_msg; - dma_addr_t msi_data; - struct irq_chip *msi_irq_chip; - u32 num_vectors; - u32 irq_mask[8]; - struct pci_host_bridge *bridge; - raw_spinlock_t lock; - long unsigned int msi_irq_in_use[4]; -}; - -enum dw_pcie_as_type { - DW_PCIE_AS_UNKNOWN = 0, - DW_PCIE_AS_MEM = 1, - DW_PCIE_AS_IO = 2, -}; - -struct dw_pcie_ep; - -struct dw_pcie_ep_ops { - void (*ep_init)(struct dw_pcie_ep *); - int (*raise_irq)(struct dw_pcie_ep *, u8, enum pci_epc_irq_type, u16); - const struct pci_epc_features * (*get_features)(struct dw_pcie_ep *); - unsigned int (*func_conf_select)(struct dw_pcie_ep *, u8); -}; - -struct dw_pcie_ep { - struct pci_epc *epc; - struct list_head func_list; - const struct dw_pcie_ep_ops *ops; - phys_addr_t phys_base; - size_t addr_size; - size_t page_size; - u8 bar_to_atu[6]; - phys_addr_t *outbound_addr; - long unsigned int *ib_window_map; - long unsigned int *ob_window_map; - void *msi_mem; - phys_addr_t msi_mem_phys; - struct pci_epf_bar *epf_bar[6]; -}; - -struct dw_pcie; - -struct dw_pcie_ops { - u64 (*cpu_addr_fixup)(struct dw_pcie *, u64); - u32 (*read_dbi)(struct dw_pcie *, void *, u32, size_t); - void (*write_dbi)(struct dw_pcie *, void *, u32, size_t, u32); - void (*write_dbi2)(struct dw_pcie *, void *, u32, size_t, u32); - int (*link_up)(struct dw_pcie *); - int (*start_link)(struct dw_pcie *); - void (*stop_link)(struct dw_pcie *); -}; - -struct dw_pcie { - struct device *dev; - void *dbi_base; - void *dbi_base2; - void *atu_base; - size_t atu_size; - u32 num_ib_windows; - u32 num_ob_windows; - struct pcie_port pp; - struct dw_pcie_ep ep; - const struct dw_pcie_ops *ops; - unsigned int version; - int num_lanes; - int link_gen; - u8 n_fts[2]; - bool iatu_unroll_enabled: 1; - bool io_cfg_atu_shared: 1; -}; - -enum dw_pcie_device_mode { - DW_PCIE_UNKNOWN_TYPE = 0, - DW_PCIE_EP_TYPE = 1, - DW_PCIE_LEG_EP_TYPE = 2, - DW_PCIE_RC_TYPE = 3, -}; - -struct dw_plat_pcie { - struct dw_pcie *pci; - struct regmap *regmap; - enum dw_pcie_device_mode mode; -}; - -struct dw_plat_pcie_of_data { - enum dw_pcie_device_mode mode; -}; - -struct reset_control; - -enum pcie_data_rate { - PCIE_GEN1 = 0, - PCIE_GEN2 = 1, - PCIE_GEN3 = 2, - PCIE_GEN4 = 3, -}; - -struct meson_pcie_clk_res { - struct clk *clk; - struct clk *port_clk; - struct clk *general_clk; -}; - -struct meson_pcie_rc_reset { - struct reset_control *port; - struct reset_control *apb; -}; - -struct meson_pcie { - struct dw_pcie pci; - void *cfg_base; - struct meson_pcie_clk_res clk_res; - struct meson_pcie_rc_reset mrst; - struct gpio_desc *reset_gpio; - struct phy *phy; -}; - -enum hdmi_infoframe_type { - HDMI_INFOFRAME_TYPE_VENDOR = 129, - HDMI_INFOFRAME_TYPE_AVI = 130, - HDMI_INFOFRAME_TYPE_SPD = 131, - HDMI_INFOFRAME_TYPE_AUDIO = 132, - HDMI_INFOFRAME_TYPE_DRM = 135, -}; - -struct hdmi_any_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; -}; - -enum hdmi_colorspace { - HDMI_COLORSPACE_RGB = 0, - HDMI_COLORSPACE_YUV422 = 1, - HDMI_COLORSPACE_YUV444 = 2, - HDMI_COLORSPACE_YUV420 = 3, - HDMI_COLORSPACE_RESERVED4 = 4, - HDMI_COLORSPACE_RESERVED5 = 5, - HDMI_COLORSPACE_RESERVED6 = 6, - HDMI_COLORSPACE_IDO_DEFINED = 7, -}; - -enum hdmi_scan_mode { - HDMI_SCAN_MODE_NONE = 0, - HDMI_SCAN_MODE_OVERSCAN = 1, - HDMI_SCAN_MODE_UNDERSCAN = 2, - HDMI_SCAN_MODE_RESERVED = 3, -}; - -enum hdmi_colorimetry { - HDMI_COLORIMETRY_NONE = 0, - HDMI_COLORIMETRY_ITU_601 = 1, - HDMI_COLORIMETRY_ITU_709 = 2, - HDMI_COLORIMETRY_EXTENDED = 3, -}; - -enum hdmi_picture_aspect { - HDMI_PICTURE_ASPECT_NONE = 0, - HDMI_PICTURE_ASPECT_4_3 = 1, - HDMI_PICTURE_ASPECT_16_9 = 2, - HDMI_PICTURE_ASPECT_64_27 = 3, - HDMI_PICTURE_ASPECT_256_135 = 4, - HDMI_PICTURE_ASPECT_RESERVED = 5, -}; - -enum hdmi_active_aspect { - HDMI_ACTIVE_ASPECT_16_9_TOP = 2, - HDMI_ACTIVE_ASPECT_14_9_TOP = 3, - HDMI_ACTIVE_ASPECT_16_9_CENTER = 4, - HDMI_ACTIVE_ASPECT_PICTURE = 8, - HDMI_ACTIVE_ASPECT_4_3 = 9, - HDMI_ACTIVE_ASPECT_16_9 = 10, - HDMI_ACTIVE_ASPECT_14_9 = 11, - HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13, - HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14, - HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15, -}; - -enum hdmi_extended_colorimetry { - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 = 0, - HDMI_EXTENDED_COLORIMETRY_XV_YCC_709 = 1, - HDMI_EXTENDED_COLORIMETRY_S_YCC_601 = 2, - HDMI_EXTENDED_COLORIMETRY_OPYCC_601 = 3, - HDMI_EXTENDED_COLORIMETRY_OPRGB = 4, - HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM = 5, - HDMI_EXTENDED_COLORIMETRY_BT2020 = 6, - HDMI_EXTENDED_COLORIMETRY_RESERVED = 7, -}; - -enum hdmi_quantization_range { - HDMI_QUANTIZATION_RANGE_DEFAULT = 0, - HDMI_QUANTIZATION_RANGE_LIMITED = 1, - HDMI_QUANTIZATION_RANGE_FULL = 2, - HDMI_QUANTIZATION_RANGE_RESERVED = 3, -}; - -enum hdmi_nups { - HDMI_NUPS_UNKNOWN = 0, - HDMI_NUPS_HORIZONTAL = 1, - HDMI_NUPS_VERTICAL = 2, - HDMI_NUPS_BOTH = 3, -}; - -enum hdmi_ycc_quantization_range { - HDMI_YCC_QUANTIZATION_RANGE_LIMITED = 0, - HDMI_YCC_QUANTIZATION_RANGE_FULL = 1, -}; - -enum hdmi_content_type { - HDMI_CONTENT_TYPE_GRAPHICS = 0, - HDMI_CONTENT_TYPE_PHOTO = 1, - HDMI_CONTENT_TYPE_CINEMA = 2, - HDMI_CONTENT_TYPE_GAME = 3, -}; - -enum hdmi_metadata_type { - HDMI_STATIC_METADATA_TYPE1 = 0, -}; - -enum hdmi_eotf { - HDMI_EOTF_TRADITIONAL_GAMMA_SDR = 0, - HDMI_EOTF_TRADITIONAL_GAMMA_HDR = 1, - HDMI_EOTF_SMPTE_ST2084 = 2, - HDMI_EOTF_BT_2100_HLG = 3, -}; - -struct hdmi_avi_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - enum hdmi_colorspace colorspace; - enum hdmi_scan_mode scan_mode; - enum hdmi_colorimetry colorimetry; - enum hdmi_picture_aspect picture_aspect; - enum hdmi_active_aspect active_aspect; - bool itc; - enum hdmi_extended_colorimetry extended_colorimetry; - enum hdmi_quantization_range quantization_range; - enum hdmi_nups nups; - unsigned char video_code; - enum hdmi_ycc_quantization_range ycc_quantization_range; - enum hdmi_content_type content_type; - unsigned char pixel_repeat; - short unsigned int top_bar; - short unsigned int bottom_bar; - short unsigned int left_bar; - short unsigned int right_bar; -}; - -struct hdmi_drm_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - enum hdmi_eotf eotf; - enum hdmi_metadata_type metadata_type; - struct { - u16 x; - u16 y; - } display_primaries[3]; - struct { - u16 x; - u16 y; - } white_point; - u16 max_display_mastering_luminance; - u16 min_display_mastering_luminance; - u16 max_cll; - u16 max_fall; -}; - -enum hdmi_spd_sdi { - HDMI_SPD_SDI_UNKNOWN = 0, - HDMI_SPD_SDI_DSTB = 1, - HDMI_SPD_SDI_DVDP = 2, - HDMI_SPD_SDI_DVHS = 3, - HDMI_SPD_SDI_HDDVR = 4, - HDMI_SPD_SDI_DVC = 5, - HDMI_SPD_SDI_DSC = 6, - HDMI_SPD_SDI_VCD = 7, - HDMI_SPD_SDI_GAME = 8, - HDMI_SPD_SDI_PC = 9, - HDMI_SPD_SDI_BD = 10, - HDMI_SPD_SDI_SACD = 11, - HDMI_SPD_SDI_HDDVD = 12, - HDMI_SPD_SDI_PMP = 13, -}; - -struct hdmi_spd_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - char vendor[8]; - char product[16]; - enum hdmi_spd_sdi sdi; -}; - -enum hdmi_audio_coding_type { - HDMI_AUDIO_CODING_TYPE_STREAM = 0, - HDMI_AUDIO_CODING_TYPE_PCM = 1, - HDMI_AUDIO_CODING_TYPE_AC3 = 2, - HDMI_AUDIO_CODING_TYPE_MPEG1 = 3, - HDMI_AUDIO_CODING_TYPE_MP3 = 4, - HDMI_AUDIO_CODING_TYPE_MPEG2 = 5, - HDMI_AUDIO_CODING_TYPE_AAC_LC = 6, - HDMI_AUDIO_CODING_TYPE_DTS = 7, - HDMI_AUDIO_CODING_TYPE_ATRAC = 8, - HDMI_AUDIO_CODING_TYPE_DSD = 9, - HDMI_AUDIO_CODING_TYPE_EAC3 = 10, - HDMI_AUDIO_CODING_TYPE_DTS_HD = 11, - HDMI_AUDIO_CODING_TYPE_MLP = 12, - HDMI_AUDIO_CODING_TYPE_DST = 13, - HDMI_AUDIO_CODING_TYPE_WMA_PRO = 14, - HDMI_AUDIO_CODING_TYPE_CXT = 15, -}; - -enum hdmi_audio_sample_size { - HDMI_AUDIO_SAMPLE_SIZE_STREAM = 0, - HDMI_AUDIO_SAMPLE_SIZE_16 = 1, - HDMI_AUDIO_SAMPLE_SIZE_20 = 2, - HDMI_AUDIO_SAMPLE_SIZE_24 = 3, -}; - -enum hdmi_audio_sample_frequency { - HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM = 0, - HDMI_AUDIO_SAMPLE_FREQUENCY_32000 = 1, - HDMI_AUDIO_SAMPLE_FREQUENCY_44100 = 2, - HDMI_AUDIO_SAMPLE_FREQUENCY_48000 = 3, - HDMI_AUDIO_SAMPLE_FREQUENCY_88200 = 4, - HDMI_AUDIO_SAMPLE_FREQUENCY_96000 = 5, - HDMI_AUDIO_SAMPLE_FREQUENCY_176400 = 6, - HDMI_AUDIO_SAMPLE_FREQUENCY_192000 = 7, -}; - -enum hdmi_audio_coding_type_ext { - HDMI_AUDIO_CODING_TYPE_EXT_CT = 0, - HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC = 1, - HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2 = 2, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND = 3, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC = 4, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2 = 5, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC = 6, - HDMI_AUDIO_CODING_TYPE_EXT_DRA = 7, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND = 8, - HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND = 10, -}; - -struct hdmi_audio_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - unsigned char channels; - enum hdmi_audio_coding_type coding_type; - enum hdmi_audio_sample_size sample_size; - enum hdmi_audio_sample_frequency sample_frequency; - enum hdmi_audio_coding_type_ext coding_type_ext; - unsigned char channel_allocation; - unsigned char level_shift_value; - bool downmix_inhibit; -}; - -enum hdmi_3d_structure { - HDMI_3D_STRUCTURE_INVALID = 4294967295, - HDMI_3D_STRUCTURE_FRAME_PACKING = 0, - HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE = 1, - HDMI_3D_STRUCTURE_LINE_ALTERNATIVE = 2, - HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL = 3, - HDMI_3D_STRUCTURE_L_DEPTH = 4, - HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH = 5, - HDMI_3D_STRUCTURE_TOP_AND_BOTTOM = 6, - HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8, -}; - -struct hdmi_vendor_infoframe { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - unsigned int oui; - u8 vic; - enum hdmi_3d_structure s3d_struct; - unsigned int s3d_ext_data; -}; - -union hdmi_vendor_any_infoframe { - struct { - enum hdmi_infoframe_type type; - unsigned char version; - unsigned char length; - unsigned int oui; - } any; - struct hdmi_vendor_infoframe hdmi; -}; - -union hdmi_infoframe { - struct hdmi_any_infoframe any; - struct hdmi_avi_infoframe avi; - struct hdmi_spd_infoframe spd; - union hdmi_vendor_any_infoframe vendor; - struct hdmi_audio_infoframe audio; - struct hdmi_drm_infoframe drm; -}; - -struct vc { - struct vc_data *d; - struct work_struct SAK_work; -}; - -struct vgastate { - void *vgabase; - long unsigned int membase; - __u32 memsize; - __u32 flags; - __u32 depth; - __u32 num_attr; - __u32 num_crtc; - __u32 num_gfx; - __u32 num_seq; - void *vidstate; -}; - -struct fb_fix_screeninfo { - char id[16]; - long unsigned int smem_start; - __u32 smem_len; - __u32 type; - __u32 type_aux; - __u32 visual; - __u16 xpanstep; - __u16 ypanstep; - __u16 ywrapstep; - __u32 line_length; - long unsigned int mmio_start; - __u32 mmio_len; - __u32 accel; - __u16 capabilities; - __u16 reserved[2]; -}; - -struct fb_bitfield { - __u32 offset; - __u32 length; - __u32 msb_right; -}; - -struct fb_var_screeninfo { - __u32 xres; - __u32 yres; - __u32 xres_virtual; - __u32 yres_virtual; - __u32 xoffset; - __u32 yoffset; - __u32 bits_per_pixel; - __u32 grayscale; - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - __u32 nonstd; - __u32 activate; - __u32 height; - __u32 width; - __u32 accel_flags; - __u32 pixclock; - __u32 left_margin; - __u32 right_margin; - __u32 upper_margin; - __u32 lower_margin; - __u32 hsync_len; - __u32 vsync_len; - __u32 sync; - __u32 vmode; - __u32 rotate; - __u32 colorspace; - __u32 reserved[4]; -}; - -struct fb_cmap { - __u32 start; - __u32 len; - __u16 *red; - __u16 *green; - __u16 *blue; - __u16 *transp; -}; - -enum { - FB_BLANK_UNBLANK = 0, - FB_BLANK_NORMAL = 1, - FB_BLANK_VSYNC_SUSPEND = 2, - FB_BLANK_HSYNC_SUSPEND = 3, - FB_BLANK_POWERDOWN = 4, -}; - -struct fb_copyarea { - __u32 dx; - __u32 dy; - __u32 width; - __u32 height; - __u32 sx; - __u32 sy; -}; - -struct fb_fillrect { - __u32 dx; - __u32 dy; - __u32 width; - __u32 height; - __u32 color; - __u32 rop; -}; - -struct fb_image { - __u32 dx; - __u32 dy; - __u32 width; - __u32 height; - __u32 fg_color; - __u32 bg_color; - __u8 depth; - const char *data; - struct fb_cmap cmap; -}; - -struct fbcurpos { - __u16 x; - __u16 y; -}; - -struct fb_cursor { - __u16 set; - __u16 enable; - __u16 rop; - const char *mask; - struct fbcurpos hot; - struct fb_image image; -}; - -struct fb_chroma { - __u32 redx; - __u32 greenx; - __u32 bluex; - __u32 whitex; - __u32 redy; - __u32 greeny; - __u32 bluey; - __u32 whitey; -}; - -struct fb_videomode; - -struct fb_monspecs { - struct fb_chroma chroma; - struct fb_videomode *modedb; - __u8 manufacturer[4]; - __u8 monitor[14]; - __u8 serial_no[14]; - __u8 ascii[14]; - __u32 modedb_len; - __u32 model; - __u32 serial; - __u32 year; - __u32 week; - __u32 hfmin; - __u32 hfmax; - __u32 dclkmin; - __u32 dclkmax; - __u16 input; - __u16 dpms; - __u16 signal; - __u16 vfmin; - __u16 vfmax; - __u16 gamma; - __u16 gtf: 1; - __u16 misc; - __u8 version; - __u8 revision; - __u8 max_x; - __u8 max_y; -}; - -struct fb_videomode { - const char *name; - u32 refresh; - u32 xres; - u32 yres; - u32 pixclock; - u32 left_margin; - u32 right_margin; - u32 upper_margin; - u32 lower_margin; - u32 hsync_len; - u32 vsync_len; - u32 sync; - u32 vmode; - u32 flag; -}; - -struct fb_info; - -struct fb_event { - struct fb_info *info; - void *data; -}; - -struct fb_pixmap { - u8 *addr; - u32 size; - u32 offset; - u32 buf_align; - u32 scan_align; - u32 access_align; - u32 flags; - u32 blit_x; - u32 blit_y; - void (*writeio)(struct fb_info *, void *, void *, unsigned int); - void (*readio)(struct fb_info *, void *, void *, unsigned int); -}; - -struct fb_deferred_io; - -struct fb_ops; - -struct fb_tile_ops; - -struct apertures_struct; - -struct fb_info { - atomic_t count; - int node; - int flags; - int fbcon_rotate_hint; - struct mutex lock; - struct mutex mm_lock; - struct fb_var_screeninfo var; - struct fb_fix_screeninfo fix; - struct fb_monspecs monspecs; - struct work_struct queue; - struct fb_pixmap pixmap; - struct fb_pixmap sprite; - struct fb_cmap cmap; - struct list_head modelist; - struct fb_videomode *mode; - struct delayed_work deferred_work; - struct fb_deferred_io *fbdefio; - const struct fb_ops *fbops; - struct device *device; - struct device *dev; - int class_flag; - struct fb_tile_ops *tileops; - union { - char *screen_base; - char *screen_buffer; - }; - long unsigned int screen_size; - void *pseudo_palette; - u32 state; - void *fbcon_par; - void *par; - struct apertures_struct *apertures; - bool skip_vt_switch; -}; - -struct fb_blit_caps { - u32 x; - u32 y; - u32 len; - u32 flags; -}; - -struct fb_deferred_io { - long unsigned int delay; - struct mutex lock; - struct list_head pagelist; - void (*first_io)(struct fb_info *); - void (*deferred_io)(struct fb_info *, struct list_head *); -}; - -struct fb_ops { - struct module *owner; - int (*fb_open)(struct fb_info *, int); - int (*fb_release)(struct fb_info *, int); - ssize_t (*fb_read)(struct fb_info *, char *, size_t, loff_t *); - ssize_t (*fb_write)(struct fb_info *, const char *, size_t, loff_t *); - int (*fb_check_var)(struct fb_var_screeninfo *, struct fb_info *); - int (*fb_set_par)(struct fb_info *); - int (*fb_setcolreg)(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, struct fb_info *); - int (*fb_setcmap)(struct fb_cmap *, struct fb_info *); - int (*fb_blank)(int, struct fb_info *); - int (*fb_pan_display)(struct fb_var_screeninfo *, struct fb_info *); - void (*fb_fillrect)(struct fb_info *, const struct fb_fillrect *); - void (*fb_copyarea)(struct fb_info *, const struct fb_copyarea *); - void (*fb_imageblit)(struct fb_info *, const struct fb_image *); - int (*fb_cursor)(struct fb_info *, struct fb_cursor *); - int (*fb_sync)(struct fb_info *); - int (*fb_ioctl)(struct fb_info *, unsigned int, long unsigned int); - int (*fb_compat_ioctl)(struct fb_info *, unsigned int, long unsigned int); - int (*fb_mmap)(struct fb_info *, struct vm_area_struct *); - void (*fb_get_caps)(struct fb_info *, struct fb_blit_caps *, struct fb_var_screeninfo *); - void (*fb_destroy)(struct fb_info *); - int (*fb_debug_enter)(struct fb_info *); - int (*fb_debug_leave)(struct fb_info *); -}; - -struct fb_tilemap { - __u32 width; - __u32 height; - __u32 depth; - __u32 length; - const __u8 *data; -}; - -struct fb_tilerect { - __u32 sx; - __u32 sy; - __u32 width; - __u32 height; - __u32 index; - __u32 fg; - __u32 bg; - __u32 rop; -}; - -struct fb_tilearea { - __u32 sx; - __u32 sy; - __u32 dx; - __u32 dy; - __u32 width; - __u32 height; -}; - -struct fb_tileblit { - __u32 sx; - __u32 sy; - __u32 width; - __u32 height; - __u32 fg; - __u32 bg; - __u32 length; - __u32 *indices; -}; - -struct fb_tilecursor { - __u32 sx; - __u32 sy; - __u32 mode; - __u32 shape; - __u32 fg; - __u32 bg; -}; - -struct fb_tile_ops { - void (*fb_settile)(struct fb_info *, struct fb_tilemap *); - void (*fb_tilecopy)(struct fb_info *, struct fb_tilearea *); - void (*fb_tilefill)(struct fb_info *, struct fb_tilerect *); - void (*fb_tileblit)(struct fb_info *, struct fb_tileblit *); - void (*fb_tilecursor)(struct fb_info *, struct fb_tilecursor *); - int (*fb_get_tilemax)(struct fb_info *); -}; - -struct aperture { - resource_size_t base; - resource_size_t size; -}; - -struct apertures_struct { - unsigned int count; - struct aperture ranges[0]; -}; - -enum backlight_update_reason { - BACKLIGHT_UPDATE_HOTKEY = 0, - BACKLIGHT_UPDATE_SYSFS = 1, -}; - -enum backlight_type { - BACKLIGHT_RAW = 1, - BACKLIGHT_PLATFORM = 2, - BACKLIGHT_FIRMWARE = 3, - BACKLIGHT_TYPE_MAX = 4, -}; - -enum backlight_notification { - BACKLIGHT_REGISTERED = 0, - BACKLIGHT_UNREGISTERED = 1, -}; - -enum backlight_scale { - BACKLIGHT_SCALE_UNKNOWN = 0, - BACKLIGHT_SCALE_LINEAR = 1, - BACKLIGHT_SCALE_NON_LINEAR = 2, -}; - -struct backlight_device; - -struct backlight_ops { - unsigned int options; - int (*update_status)(struct backlight_device *); - int (*get_brightness)(struct backlight_device *); - int (*check_fb)(struct backlight_device *, struct fb_info *); -}; - -struct backlight_properties { - int brightness; - int max_brightness; - int power; - int fb_blank; - enum backlight_type type; - unsigned int state; - enum backlight_scale scale; -}; - -struct backlight_device { - struct backlight_properties props; - struct mutex update_lock; - struct mutex ops_lock; - const struct backlight_ops *ops; - struct notifier_block fb_notif; - struct list_head entry; - struct device dev; - bool fb_bl_on[32]; - int use_count; -}; - -struct fb_cmap_user { - __u32 start; - __u32 len; - __u16 *red; - __u16 *green; - __u16 *blue; - __u16 *transp; -}; - -struct fb_modelist { - struct list_head list; - struct fb_videomode mode; -}; - -struct fb_fix_screeninfo32 { - char id[16]; - compat_caddr_t smem_start; - u32 smem_len; - u32 type; - u32 type_aux; - u32 visual; - u16 xpanstep; - u16 ypanstep; - u16 ywrapstep; - u32 line_length; - compat_caddr_t mmio_start; - u32 mmio_len; - u32 accel; - u16 reserved[3]; -}; - -struct fb_cmap32 { - u32 start; - u32 len; - compat_caddr_t red; - compat_caddr_t green; - compat_caddr_t blue; - compat_caddr_t transp; -}; - -struct dmt_videomode { - u32 dmt_id; - u32 std_2byte_code; - u32 cvt_3byte_code; - const struct fb_videomode *mode; -}; - -enum display_flags { - DISPLAY_FLAGS_HSYNC_LOW = 1, - DISPLAY_FLAGS_HSYNC_HIGH = 2, - DISPLAY_FLAGS_VSYNC_LOW = 4, - DISPLAY_FLAGS_VSYNC_HIGH = 8, - DISPLAY_FLAGS_DE_LOW = 16, - DISPLAY_FLAGS_DE_HIGH = 32, - DISPLAY_FLAGS_PIXDATA_POSEDGE = 64, - DISPLAY_FLAGS_PIXDATA_NEGEDGE = 128, - DISPLAY_FLAGS_INTERLACED = 256, - DISPLAY_FLAGS_DOUBLESCAN = 512, - DISPLAY_FLAGS_DOUBLECLK = 1024, - DISPLAY_FLAGS_SYNC_POSEDGE = 2048, - DISPLAY_FLAGS_SYNC_NEGEDGE = 4096, -}; - -struct videomode { - long unsigned int pixelclock; - u32 hactive; - u32 hfront_porch; - u32 hback_porch; - u32 hsync_len; - u32 vactive; - u32 vfront_porch; - u32 vback_porch; - u32 vsync_len; - enum display_flags flags; -}; - -struct broken_edid { - u8 manufacturer[4]; - u32 model; - u32 fix; -}; - -struct __fb_timings { - u32 dclk; - u32 hfreq; - u32 vfreq; - u32 hactive; - u32 vactive; - u32 hblank; - u32 vblank; - u32 htotal; - u32 vtotal; -}; - -struct fb_cvt_data { - u32 xres; - u32 yres; - u32 refresh; - u32 f_refresh; - u32 pixclock; - u32 hperiod; - u32 hblank; - u32 hfreq; - u32 htotal; - u32 vtotal; - u32 vsync; - u32 hsync; - u32 h_front_porch; - u32 h_back_porch; - u32 v_front_porch; - u32 v_back_porch; - u32 h_margin; - u32 v_margin; - u32 interlace; - u32 aspect_ratio; - u32 active_pixels; - u32 flags; - u32 status; -}; - -typedef unsigned char u_char; - -typedef short unsigned int u_short; - -struct fb_con2fbmap { - __u32 console; - __u32 framebuffer; -}; - -struct fbcon_display { - const u_char *fontdata; - int userfont; - u_short scrollmode; - u_short inverse; - short int yscroll; - int vrows; - int cursor_shape; - int con_rotate; - u32 xres_virtual; - u32 yres_virtual; - u32 height; - u32 width; - u32 bits_per_pixel; - u32 grayscale; - u32 nonstd; - u32 accel_flags; - u32 rotate; - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - const struct fb_videomode *mode; -}; - -struct fbcon_ops { - void (*bmove)(struct vc_data *, struct fb_info *, int, int, int, int, int, int); - void (*clear)(struct vc_data *, struct fb_info *, int, int, int, int); - void (*putcs)(struct vc_data *, struct fb_info *, const short unsigned int *, int, int, int, int, int); - void (*clear_margins)(struct vc_data *, struct fb_info *, int, int); - void (*cursor)(struct vc_data *, struct fb_info *, int, int, int); - int (*update_start)(struct fb_info *); - int (*rotate_font)(struct fb_info *, struct vc_data *); - struct fb_var_screeninfo var; - struct timer_list cursor_timer; - struct fb_cursor cursor_state; - struct fbcon_display *p; - struct fb_info *info; - int currcon; - int cur_blink_jiffies; - int cursor_flash; - int cursor_reset; - int blank_state; - int graphics; - int save_graphics; - int flags; - int rotate; - int cur_rotate; - char *cursor_data; - u8 *fontbuffer; - u8 *fontdata; - u8 *cursor_src; - u32 cursor_size; - u32 fd_size; -}; - -enum { - FBCON_LOGO_CANSHOW = 4294967295, - FBCON_LOGO_DRAW = 4294967294, - FBCON_LOGO_DONTSHOW = 4294967293, -}; - -struct vesafb_par { - u32 pseudo_palette[256]; - int wc_cookie; - struct resource *region; -}; - -struct acpi_table_bgrt { - struct acpi_table_header header; - u16 version; - u8 status; - u8 image_type; - u64 image_address; - u32 image_offset_x; - u32 image_offset_y; -}; - -enum drm_panel_orientation { - DRM_MODE_PANEL_ORIENTATION_UNKNOWN = 4294967295, - DRM_MODE_PANEL_ORIENTATION_NORMAL = 0, - DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP = 1, - DRM_MODE_PANEL_ORIENTATION_LEFT_UP = 2, - DRM_MODE_PANEL_ORIENTATION_RIGHT_UP = 3, -}; - -struct bmp_file_header { - u16 id; - u32 file_size; - u32 reserved; - u32 bitmap_offset; -} __attribute__((packed)); - -struct bmp_dib_header { - u32 dib_header_size; - s32 width; - s32 height; - u16 planes; - u16 bpp; - u32 compression; - u32 bitmap_size; - u32 horz_resolution; - u32 vert_resolution; - u32 colors_used; - u32 colors_important; -}; - -struct simplefb_format { - const char *name; - u32 bits_per_pixel; - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - u32 fourcc; -}; - -struct simplefb_params { - u32 width; - u32 height; - u32 stride; - struct simplefb_format *format; -}; - -struct simplefb_par { - u32 palette[16]; -}; - -struct timing_entry { - u32 min; - u32 typ; - u32 max; -}; - -struct display_timing { - struct timing_entry pixelclock; - struct timing_entry hactive; - struct timing_entry hfront_porch; - struct timing_entry hback_porch; - struct timing_entry hsync_len; - struct timing_entry vactive; - struct timing_entry vfront_porch; - struct timing_entry vback_porch; - struct timing_entry vsync_len; - enum display_flags flags; -}; - -struct display_timings { - unsigned int num_timings; - unsigned int native_mode; - struct display_timing **timings; -}; - -struct thermal_cooling_device_ops; - -struct thermal_cooling_device { - int id; - char *type; - struct device device; - struct device_node *np; - void *devdata; - void *stats; - const struct thermal_cooling_device_ops *ops; - bool updated; - struct mutex lock; - struct list_head thermal_instances; - struct list_head node; -}; - -struct idle_cpu { - struct cpuidle_state *state_table; - long unsigned int auto_demotion_disable_flags; - bool byt_auto_demotion_disable_flag; - bool disable_promotion_to_c1e; - bool use_acpi; -}; - -struct thermal_cooling_device_ops { - int (*get_max_state)(struct thermal_cooling_device *, long unsigned int *); - int (*get_cur_state)(struct thermal_cooling_device *, long unsigned int *); - int (*set_cur_state)(struct thermal_cooling_device *, long unsigned int); - int (*get_requested_power)(struct thermal_cooling_device *, u32 *); - int (*state2power)(struct thermal_cooling_device *, long unsigned int, u32 *); - int (*power2state)(struct thermal_cooling_device *, u32, long unsigned int *); -}; - -struct acpi_lpi_state { - u32 min_residency; - u32 wake_latency; - u32 flags; - u32 arch_flags; - u32 res_cnt_freq; - u32 enable_parent_state; - u64 address; - u8 index; - u8 entry_method; - char desc[32]; -}; - -struct acpi_processor_power { - int count; - union { - struct acpi_processor_cx states[8]; - struct acpi_lpi_state lpi_states[8]; - }; - int timer_broadcast_on_state; -}; - -struct acpi_psd_package { - u64 num_entries; - u64 revision; - u64 domain; - u64 coord_type; - u64 num_processors; -}; - -struct acpi_pct_register { - u8 descriptor; - u16 length; - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 reserved; - u64 address; -} __attribute__((packed)); - -struct acpi_processor_px { - u64 core_frequency; - u64 power; - u64 transition_latency; - u64 bus_master_latency; - u64 control; - u64 status; -}; - -struct acpi_processor_performance { - unsigned int state; - unsigned int platform_limit; - struct acpi_pct_register control_register; - struct acpi_pct_register status_register; - short: 16; - unsigned int state_count; - int: 32; - struct acpi_processor_px *states; - struct acpi_psd_package domain_info; - cpumask_var_t shared_cpu_map; - unsigned int shared_type; - int: 32; -} __attribute__((packed)); - -struct acpi_tsd_package { - u64 num_entries; - u64 revision; - u64 domain; - u64 coord_type; - u64 num_processors; -}; - -struct acpi_processor_tx_tss { - u64 freqpercentage; - u64 power; - u64 transition_latency; - u64 control; - u64 status; -}; - -struct acpi_processor_tx { - u16 power; - u16 performance; -}; - -struct acpi_processor; - -struct acpi_processor_throttling { - unsigned int state; - unsigned int platform_limit; - struct acpi_pct_register control_register; - struct acpi_pct_register status_register; - short: 16; - unsigned int state_count; - int: 32; - struct acpi_processor_tx_tss *states_tss; - struct acpi_tsd_package domain_info; - cpumask_var_t shared_cpu_map; - int (*acpi_processor_get_throttling)(struct acpi_processor *); - int (*acpi_processor_set_throttling)(struct acpi_processor *, int, bool); - u32 address; - u8 duty_offset; - u8 duty_width; - u8 tsd_valid_flag; - char: 8; - unsigned int shared_type; - struct acpi_processor_tx states[16]; - int: 32; -} __attribute__((packed)); - -struct acpi_processor_lx { - int px; - int tx; -}; - -struct acpi_processor_limit { - struct acpi_processor_lx state; - struct acpi_processor_lx thermal; - struct acpi_processor_lx user; -}; - -struct acpi_processor { - acpi_handle handle; - u32 acpi_id; - phys_cpuid_t phys_id; - u32 id; - u32 pblk; - int performance_platform_limit; - int throttling_platform_limit; - struct acpi_processor_flags flags; - struct acpi_processor_power power; - struct acpi_processor_performance *performance; - struct acpi_processor_throttling throttling; - struct acpi_processor_limit limit; - struct thermal_cooling_device *cdev; - struct device *dev; - struct freq_qos_request perflib_req; - struct freq_qos_request thermal_req; -}; - -enum ipmi_addr_src { - SI_INVALID = 0, - SI_HOTMOD = 1, - SI_HARDCODED = 2, - SI_SPMI = 3, - SI_ACPI = 4, - SI_SMBIOS = 5, - SI_PCI = 6, - SI_DEVICETREE = 7, - SI_PLATFORM = 8, - SI_LAST = 9, -}; - -struct dmi_header { - u8 type; - u8 length; - u16 handle; -}; - -enum si_type { - SI_TYPE_INVALID = 0, - SI_KCS = 1, - SI_SMIC = 2, - SI_BT = 3, - SI_TYPE_MAX = 4, -}; - -enum ipmi_addr_space { - IPMI_IO_ADDR_SPACE = 0, - IPMI_MEM_ADDR_SPACE = 1, -}; - -enum ipmi_plat_interface_type { - IPMI_PLAT_IF_SI = 0, - IPMI_PLAT_IF_SSIF = 1, -}; - -struct ipmi_plat_data { - enum ipmi_plat_interface_type iftype; - unsigned int type; - unsigned int space; - long unsigned int addr; - unsigned int regspacing; - unsigned int regsize; - unsigned int regshift; - unsigned int irq; - unsigned int slave_addr; - enum ipmi_addr_src addr_source; -}; - -struct ipmi_dmi_info { - enum si_type si_type; - unsigned int space; - long unsigned int addr; - u8 slave_addr; - struct ipmi_dmi_info *next; -}; - -typedef u16 acpi_owner_id; - -union acpi_name_union { - u32 integer; - char ascii[4]; -}; - -struct acpi_table_desc { - acpi_physical_address address; - struct acpi_table_header *pointer; - u32 length; - union acpi_name_union signature; - acpi_owner_id owner_id; - u8 flags; - u16 validation_count; -}; - -struct acpi_madt_io_sapic { - struct acpi_subtable_header header; - u8 id; - u8 reserved; - u32 global_irq_base; - u64 address; -}; - -struct acpi_madt_interrupt_source { - struct acpi_subtable_header header; - u16 inti_flags; - u8 type; - u8 id; - u8 eid; - u8 io_sapic_vector; - u32 global_irq; - u32 flags; -}; - -struct acpi_madt_generic_interrupt { - struct acpi_subtable_header header; - u16 reserved; - u32 cpu_interface_number; - u32 uid; - u32 flags; - u32 parking_version; - u32 performance_interrupt; - u64 parked_address; - u64 base_address; - u64 gicv_base_address; - u64 gich_base_address; - u32 vgic_interrupt; - u64 gicr_base_address; - u64 arm_mpidr; - u8 efficiency_class; - u8 reserved2[1]; - u16 spe_interrupt; -} __attribute__((packed)); - -struct acpi_madt_generic_distributor { - struct acpi_subtable_header header; - u16 reserved; - u32 gic_id; - u64 base_address; - u32 global_irq_base; - u8 version; - u8 reserved2[3]; -}; - -enum acpi_subtable_type { - ACPI_SUBTABLE_COMMON = 0, - ACPI_SUBTABLE_HMAT = 1, - ACPI_SUBTABLE_PRMT = 2, -}; - -struct acpi_subtable_entry { - union acpi_subtable_headers *hdr; - enum acpi_subtable_type type; -}; - -enum acpi_predicate { - all_versions = 0, - less_than_or_equal = 1, - equal = 2, - greater_than_or_equal = 3, -}; - -struct acpi_platform_list { - char oem_id[7]; - char oem_table_id[9]; - u32 oem_revision; - char *table; - enum acpi_predicate pred; - char *reason; - u32 data; -}; - -typedef u32 (*acpi_interface_handler)(acpi_string, u32); - -struct acpi_osi_entry { - char string[64]; - bool enable; -}; - -struct acpi_osi_config { - u8 default_disabling; - unsigned int linux_enable: 1; - unsigned int linux_dmi: 1; - unsigned int linux_cmdline: 1; - unsigned int darwin_enable: 1; - unsigned int darwin_dmi: 1; - unsigned int darwin_cmdline: 1; -}; - -struct acpi_predefined_names { - const char *name; - u8 type; - char *val; -}; - -typedef u32 (*acpi_osd_handler)(void *); - -typedef void (*acpi_osd_exec_callback)(void *); - -typedef u32 (*acpi_gpe_handler)(acpi_handle, u32, void *); - -struct acpi_pci_id { - u16 segment; - u16 bus; - u16 device; - u16 function; -}; - -struct acpi_mem_mapping { - acpi_physical_address physical_address; - u8 *logical_address; - acpi_size length; - struct acpi_mem_mapping *next_mm; -}; - -struct acpi_mem_space_context { - u32 length; - acpi_physical_address address; - struct acpi_mem_mapping *cur_mm; - struct acpi_mem_mapping *first_mm; -}; - -typedef enum { - OSL_GLOBAL_LOCK_HANDLER = 0, - OSL_NOTIFY_HANDLER = 1, - OSL_GPE_HANDLER = 2, - OSL_DEBUGGER_MAIN_THREAD = 3, - OSL_DEBUGGER_EXEC_THREAD = 4, - OSL_EC_POLL_HANDLER = 5, - OSL_EC_BURST_HANDLER = 6, -} acpi_execute_type; - -union acpi_operand_object; - -struct acpi_namespace_node { - union acpi_operand_object *object; - u8 descriptor_type; - u8 type; - u16 flags; - union acpi_name_union name; - struct acpi_namespace_node *parent; - struct acpi_namespace_node *child; - struct acpi_namespace_node *peer; - acpi_owner_id owner_id; -}; - -struct acpi_object_common { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; -}; - -struct acpi_object_integer { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 fill[3]; - u64 value; -}; - -struct acpi_object_string { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - char *pointer; - u32 length; -}; - -struct acpi_object_buffer { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 *pointer; - u32 length; - u32 aml_length; - u8 *aml_start; - struct acpi_namespace_node *node; -}; - -struct acpi_object_package { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - struct acpi_namespace_node *node; - union acpi_operand_object **elements; - u8 *aml_start; - u32 aml_length; - u32 count; -}; - -struct acpi_object_event { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - void *os_semaphore; -}; - -struct acpi_walk_state; - -typedef acpi_status (*acpi_internal_method)(struct acpi_walk_state *); - -struct acpi_object_method { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 info_flags; - u8 param_count; - u8 sync_level; - union acpi_operand_object *mutex; - union acpi_operand_object *node; - u8 *aml_start; - union { - acpi_internal_method implementation; - union acpi_operand_object *handler; - } dispatch; - u32 aml_length; - acpi_owner_id owner_id; - u8 thread_count; -}; - -struct acpi_thread_state; - -struct acpi_object_mutex { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 sync_level; - u16 acquisition_depth; - void *os_mutex; - u64 thread_id; - struct acpi_thread_state *owner_thread; - union acpi_operand_object *prev; - union acpi_operand_object *next; - struct acpi_namespace_node *node; - u8 original_sync_level; -}; - -struct acpi_object_region { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 space_id; - struct acpi_namespace_node *node; - union acpi_operand_object *handler; - union acpi_operand_object *next; - acpi_physical_address address; - u32 length; -}; - -struct acpi_object_notify_common { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - union acpi_operand_object *notify_list[2]; - union acpi_operand_object *handler; -}; - -struct acpi_gpe_block_info; - -struct acpi_object_device { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - union acpi_operand_object *notify_list[2]; - union acpi_operand_object *handler; - struct acpi_gpe_block_info *gpe_block; -}; - -struct acpi_object_power_resource { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - union acpi_operand_object *notify_list[2]; - union acpi_operand_object *handler; - u32 system_level; - u32 resource_order; -}; - -struct acpi_object_processor { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 proc_id; - u8 length; - union acpi_operand_object *notify_list[2]; - union acpi_operand_object *handler; - acpi_io_address address; -}; - -struct acpi_object_thermal_zone { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - union acpi_operand_object *notify_list[2]; - union acpi_operand_object *handler; -}; - -struct acpi_object_field_common { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 field_flags; - u8 attribute; - u8 access_byte_width; - struct acpi_namespace_node *node; - u32 bit_length; - u32 base_byte_offset; - u32 value; - u8 start_field_bit_offset; - u8 access_length; - union acpi_operand_object *region_obj; -}; - -struct acpi_object_region_field { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 field_flags; - u8 attribute; - u8 access_byte_width; - struct acpi_namespace_node *node; - u32 bit_length; - u32 base_byte_offset; - u32 value; - u8 start_field_bit_offset; - u8 access_length; - u16 resource_length; - union acpi_operand_object *region_obj; - u8 *resource_buffer; - u16 pin_number_index; - u8 *internal_pcc_buffer; -}; - -struct acpi_object_buffer_field { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 field_flags; - u8 attribute; - u8 access_byte_width; - struct acpi_namespace_node *node; - u32 bit_length; - u32 base_byte_offset; - u32 value; - u8 start_field_bit_offset; - u8 access_length; - u8 is_create_field; - union acpi_operand_object *buffer_obj; -}; - -struct acpi_object_bank_field { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 field_flags; - u8 attribute; - u8 access_byte_width; - struct acpi_namespace_node *node; - u32 bit_length; - u32 base_byte_offset; - u32 value; - u8 start_field_bit_offset; - u8 access_length; - union acpi_operand_object *region_obj; - union acpi_operand_object *bank_obj; -}; - -struct acpi_object_index_field { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 field_flags; - u8 attribute; - u8 access_byte_width; - struct acpi_namespace_node *node; - u32 bit_length; - u32 base_byte_offset; - u32 value; - u8 start_field_bit_offset; - u8 access_length; - union acpi_operand_object *index_obj; - union acpi_operand_object *data_obj; -}; - -struct acpi_object_notify_handler { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - struct acpi_namespace_node *node; - u32 handler_type; - acpi_notify_handler handler; - void *context; - union acpi_operand_object *next[2]; -}; - -struct acpi_object_addr_handler { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 space_id; - u8 handler_flags; - acpi_adr_space_handler handler; - struct acpi_namespace_node *node; - void *context; - void *context_mutex; - acpi_adr_space_setup setup; - union acpi_operand_object *region_list; - union acpi_operand_object *next; -}; - -struct acpi_object_reference { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - u8 class; - u8 target_type; - u8 resolved; - void *object; - struct acpi_namespace_node *node; - union acpi_operand_object **where; - u8 *index_pointer; - u8 *aml; - u32 value; -}; - -struct acpi_object_extra { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - struct acpi_namespace_node *method_REG; - struct acpi_namespace_node *scope_node; - void *region_context; - u8 *aml_start; - u32 aml_length; -}; - -struct acpi_object_data { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - acpi_object_handler handler; - void *pointer; -}; - -struct acpi_object_cache_list { - union acpi_operand_object *next_object; - u8 descriptor_type; - u8 type; - u16 reference_count; - u8 flags; - union acpi_operand_object *next; -}; - -union acpi_operand_object { - struct acpi_object_common common; - struct acpi_object_integer integer; - struct acpi_object_string string; - struct acpi_object_buffer buffer; - struct acpi_object_package package; - struct acpi_object_event event; - struct acpi_object_method method; - struct acpi_object_mutex mutex; - struct acpi_object_region region; - struct acpi_object_notify_common common_notify; - struct acpi_object_device device; - struct acpi_object_power_resource power_resource; - struct acpi_object_processor processor; - struct acpi_object_thermal_zone thermal_zone; - struct acpi_object_field_common common_field; - struct acpi_object_region_field field; - struct acpi_object_buffer_field buffer_field; - struct acpi_object_bank_field bank_field; - struct acpi_object_index_field index_field; - struct acpi_object_notify_handler notify; - struct acpi_object_addr_handler address_space; - struct acpi_object_reference reference; - struct acpi_object_extra extra; - struct acpi_object_data data; - struct acpi_object_cache_list cache; - struct acpi_namespace_node node; -}; - -union acpi_parse_object; - -union acpi_generic_state; - -struct acpi_parse_state { - u8 *aml_start; - u8 *aml; - u8 *aml_end; - u8 *pkg_start; - u8 *pkg_end; - union acpi_parse_object *start_op; - struct acpi_namespace_node *start_node; - union acpi_generic_state *scope; - union acpi_parse_object *start_scope; - u32 aml_size; -}; - -typedef acpi_status (*acpi_parse_downwards)(struct acpi_walk_state *, union acpi_parse_object **); - -typedef acpi_status (*acpi_parse_upwards)(struct acpi_walk_state *); - -struct acpi_opcode_info; - -struct acpi_walk_state { - struct acpi_walk_state *next; - u8 descriptor_type; - u8 walk_type; - u16 opcode; - u8 next_op_info; - u8 num_operands; - u8 operand_index; - acpi_owner_id owner_id; - u8 last_predicate; - u8 current_result; - u8 return_used; - u8 scope_depth; - u8 pass_number; - u8 namespace_override; - u8 result_size; - u8 result_count; - u8 *aml; - u32 arg_types; - u32 method_breakpoint; - u32 user_breakpoint; - u32 parse_flags; - struct acpi_parse_state parser_state; - u32 prev_arg_types; - u32 arg_count; - u16 method_nesting_depth; - u8 method_is_nested; - struct acpi_namespace_node arguments[7]; - struct acpi_namespace_node local_variables[8]; - union acpi_operand_object *operands[9]; - union acpi_operand_object **params; - u8 *aml_last_while; - union acpi_operand_object **caller_return_desc; - union acpi_generic_state *control_state; - struct acpi_namespace_node *deferred_node; - union acpi_operand_object *implicit_return_obj; - struct acpi_namespace_node *method_call_node; - union acpi_parse_object *method_call_op; - union acpi_operand_object *method_desc; - struct acpi_namespace_node *method_node; - char *method_pathname; - union acpi_parse_object *op; - const struct acpi_opcode_info *op_info; - union acpi_parse_object *origin; - union acpi_operand_object *result_obj; - union acpi_generic_state *results; - union acpi_operand_object *return_desc; - union acpi_generic_state *scope_info; - union acpi_parse_object *prev_op; - union acpi_parse_object *next_op; - struct acpi_thread_state *thread; - acpi_parse_downwards descending_callback; - acpi_parse_upwards ascending_callback; -}; - -struct acpi_gpe_handler_info { - acpi_gpe_handler address; - void *context; - struct acpi_namespace_node *method_node; - u8 original_flags; - u8 originally_enabled; -}; - -struct acpi_gpe_notify_info { - struct acpi_namespace_node *device_node; - struct acpi_gpe_notify_info *next; -}; - -union acpi_gpe_dispatch_info { - struct acpi_namespace_node *method_node; - struct acpi_gpe_handler_info *handler; - struct acpi_gpe_notify_info *notify_list; -}; - -struct acpi_gpe_register_info; - -struct acpi_gpe_event_info { - union acpi_gpe_dispatch_info dispatch; - struct acpi_gpe_register_info *register_info; - u8 flags; - u8 gpe_number; - u8 runtime_count; - u8 disable_for_dispatch; -}; - -struct acpi_gpe_address { - u8 space_id; - u64 address; -}; - -struct acpi_gpe_register_info { - struct acpi_gpe_address status_address; - struct acpi_gpe_address enable_address; - u16 base_gpe_number; - u8 enable_for_wake; - u8 enable_for_run; - u8 mask_for_run; - u8 enable_mask; -}; - -struct acpi_gpe_xrupt_info; - -struct acpi_gpe_block_info { - struct acpi_namespace_node *node; - struct acpi_gpe_block_info *previous; - struct acpi_gpe_block_info *next; - struct acpi_gpe_xrupt_info *xrupt_block; - struct acpi_gpe_register_info *register_info; - struct acpi_gpe_event_info *event_info; - u64 address; - u32 register_count; - u16 gpe_count; - u16 block_base_number; - u8 space_id; - u8 initialized; -}; - -struct acpi_gpe_xrupt_info { - struct acpi_gpe_xrupt_info *previous; - struct acpi_gpe_xrupt_info *next; - struct acpi_gpe_block_info *gpe_block_list_head; - u32 interrupt_number; -}; - -struct acpi_common_state { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; -}; - -struct acpi_update_state { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - union acpi_operand_object *object; -}; - -struct acpi_pkg_state { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - u32 index; - union acpi_operand_object *source_object; - union acpi_operand_object *dest_object; - struct acpi_walk_state *walk_state; - void *this_target_obj; - u32 num_packages; -}; - -struct acpi_control_state { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - u16 opcode; - union acpi_parse_object *predicate_op; - u8 *aml_predicate_start; - u8 *package_end; - u64 loop_timeout; -}; - -union acpi_parse_value { - u64 integer; - u32 size; - char *string; - u8 *buffer; - char *name; - union acpi_parse_object *arg; -}; - -struct acpi_parse_obj_common { - union acpi_parse_object *parent; - u8 descriptor_type; - u8 flags; - u16 aml_opcode; - u8 *aml; - union acpi_parse_object *next; - struct acpi_namespace_node *node; - union acpi_parse_value value; - u8 arg_list_length; - u16 disasm_flags; - u8 disasm_opcode; - char *operator_symbol; - char aml_op_name[16]; -}; - -struct acpi_parse_obj_named { - union acpi_parse_object *parent; - u8 descriptor_type; - u8 flags; - u16 aml_opcode; - u8 *aml; - union acpi_parse_object *next; - struct acpi_namespace_node *node; - union acpi_parse_value value; - u8 arg_list_length; - u16 disasm_flags; - u8 disasm_opcode; - char *operator_symbol; - char aml_op_name[16]; - char *path; - u8 *data; - u32 length; - u32 name; -}; - -struct acpi_parse_obj_asl { - union acpi_parse_object *parent; - u8 descriptor_type; - u8 flags; - u16 aml_opcode; - u8 *aml; - union acpi_parse_object *next; - struct acpi_namespace_node *node; - union acpi_parse_value value; - u8 arg_list_length; - u16 disasm_flags; - u8 disasm_opcode; - char *operator_symbol; - char aml_op_name[16]; - union acpi_parse_object *child; - union acpi_parse_object *parent_method; - char *filename; - u8 file_changed; - char *parent_filename; - char *external_name; - char *namepath; - char name_seg[4]; - u32 extra_value; - u32 column; - u32 line_number; - u32 logical_line_number; - u32 logical_byte_offset; - u32 end_line; - u32 end_logical_line; - u32 acpi_btype; - u32 aml_length; - u32 aml_subtree_length; - u32 final_aml_length; - u32 final_aml_offset; - u32 compile_flags; - u16 parse_opcode; - u8 aml_opcode_length; - u8 aml_pkg_len_bytes; - u8 extra; - char parse_op_name[20]; -}; - -union acpi_parse_object { - struct acpi_parse_obj_common common; - struct acpi_parse_obj_named named; - struct acpi_parse_obj_asl asl; -}; - -struct acpi_scope_state { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - struct acpi_namespace_node *node; -}; - -struct acpi_pscope_state { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - u32 arg_count; - union acpi_parse_object *op; - u8 *arg_end; - u8 *pkg_end; - u32 arg_list; -}; - -struct acpi_thread_state { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - u8 current_sync_level; - struct acpi_walk_state *walk_state_list; - union acpi_operand_object *acquired_mutex_list; - u64 thread_id; -}; - -struct acpi_result_values { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - union acpi_operand_object *obj_desc[8]; -}; - -struct acpi_global_notify_handler { - acpi_notify_handler handler; - void *context; -}; - -struct acpi_notify_info { - void *next; - u8 descriptor_type; - u8 flags; - u16 value; - u16 state; - u8 handler_list_id; - struct acpi_namespace_node *node; - union acpi_operand_object *handler_list_head; - struct acpi_global_notify_handler *global; -}; - -union acpi_generic_state { - struct acpi_common_state common; - struct acpi_control_state control; - struct acpi_update_state update; - struct acpi_scope_state scope; - struct acpi_pscope_state parse_scope; - struct acpi_pkg_state pkg; - struct acpi_thread_state thread; - struct acpi_result_values results; - struct acpi_notify_info notify; -}; - -struct acpi_opcode_info { - char *name; - u32 parse_args; - u32 runtime_args; - u16 flags; - u8 object_type; - u8 class; - u8 type; -}; - -struct acpi_os_dpc { - acpi_osd_exec_callback function; - void *context; - struct work_struct work; -}; - -struct acpi_ioremap { - struct list_head list; - void *virt; - acpi_physical_address phys; - acpi_size size; - union { - long unsigned int refcount; - struct rcu_work rwork; - } track; -}; - -struct acpi_hp_work { - struct work_struct work; - struct acpi_device *adev; - u32 src; -}; - -struct acpi_pld_info { - u8 revision; - u8 ignore_color; - u8 red; - u8 green; - u8 blue; - u16 width; - u16 height; - u8 user_visible; - u8 dock; - u8 lid; - u8 panel; - u8 vertical_position; - u8 horizontal_position; - u8 shape; - u8 group_orientation; - u8 group_token; - u8 group_position; - u8 bay; - u8 ejectable; - u8 ospm_eject_required; - u8 cabinet_number; - u8 card_cage_number; - u8 reference; - u8 rotation; - u8 order; - u8 reserved; - u16 vertical_offset; - u16 horizontal_offset; -}; - -struct acpi_handle_list { - u32 count; - acpi_handle handles[10]; -}; - -struct acpi_device_bus_id { - const char *bus_id; - struct ida instance_ida; - struct list_head node; -}; - -struct acpi_dev_match_info { - struct acpi_device_id hid[2]; - const char *uid; - s64 hrv; -}; - -struct nvs_region { - __u64 phys_start; - __u64 size; - struct list_head node; -}; - -struct nvs_page { - long unsigned int phys_start; - unsigned int size; - void *kaddr; - void *data; - bool unmap; - struct list_head node; -}; - -struct acpi_wakeup_handler { - struct list_head list_node; - bool (*wakeup)(void *); - void *context; -}; - -typedef u32 acpi_event_status; - -struct acpi_table_facs { - char signature[4]; - u32 length; - u32 hardware_signature; - u32 firmware_waking_vector; - u32 global_lock; - u32 flags; - u64 xfirmware_waking_vector; - u8 version; - u8 reserved[3]; - u32 ospm_flags; - u8 reserved1[24]; -}; - -struct acpi_hardware_id { - struct list_head list; - const char *id; -}; - -struct acpi_data_node { - const char *name; - acpi_handle handle; - struct fwnode_handle fwnode; - struct fwnode_handle *parent; - struct acpi_device_data data; - struct list_head sibling; - struct kobject kobj; - struct completion kobj_done; -}; - -struct acpi_data_node_attr { - struct attribute attr; - ssize_t (*show)(struct acpi_data_node *, char *); - ssize_t (*store)(struct acpi_data_node *, const char *, size_t); -}; - -struct pm_domain_data { - struct list_head list_node; - struct device *dev; -}; - -struct acpi_device_physical_node { - unsigned int node_id; - struct list_head node; - struct device *dev; - bool put_online: 1; -}; - -typedef u32 (*acpi_event_handler)(void *); - -typedef acpi_status (*acpi_table_handler)(u32, void *, void *); - -enum acpi_bus_device_type { - ACPI_BUS_TYPE_DEVICE = 0, - ACPI_BUS_TYPE_POWER = 1, - ACPI_BUS_TYPE_PROCESSOR = 2, - ACPI_BUS_TYPE_THERMAL = 3, - ACPI_BUS_TYPE_POWER_BUTTON = 4, - ACPI_BUS_TYPE_SLEEP_BUTTON = 5, - ACPI_BUS_TYPE_ECDT_EC = 6, - ACPI_BUS_DEVICE_TYPE_COUNT = 7, -}; - -struct acpi_osc_context { - char *uuid_str; - int rev; - struct acpi_buffer cap; - struct acpi_buffer ret; -}; - -struct acpi_pnp_device_id { - u32 length; - char *string; -}; - -struct acpi_pnp_device_id_list { - u32 count; - u32 list_size; - struct acpi_pnp_device_id ids[0]; -}; - -struct acpi_device_info { - u32 info_size; - u32 name; - acpi_object_type type; - u8 param_count; - u16 valid; - u8 flags; - u8 highest_dstates[4]; - u8 lowest_dstates[5]; - u64 address; - struct acpi_pnp_device_id hardware_id; - struct acpi_pnp_device_id unique_id; - struct acpi_pnp_device_id class_code; - struct acpi_pnp_device_id_list compatible_id_list; -}; - -struct acpi_table_spcr { - struct acpi_table_header header; - u8 interface_type; - u8 reserved[3]; - struct acpi_generic_address serial_port; - u8 interrupt_type; - u8 pc_interrupt; - u32 interrupt; - u8 baud_rate; - u8 parity; - u8 stop_bits; - u8 flow_control; - u8 terminal_type; - u8 reserved1; - u16 pci_device_id; - u16 pci_vendor_id; - u8 pci_bus; - u8 pci_device; - u8 pci_function; - u32 pci_flags; - u8 pci_segment; - u32 reserved2; -} __attribute__((packed)); - -struct acpi_table_stao { - struct acpi_table_header header; - u8 ignore_uart; -} __attribute__((packed)); - -struct acpi_dep_data { - struct list_head node; - acpi_handle supplier; - acpi_handle consumer; -}; - -enum acpi_reconfig_event { - ACPI_RECONFIG_DEVICE_ADD = 0, - ACPI_RECONFIG_DEVICE_REMOVE = 1, -}; - -struct acpi_probe_entry; - -typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *, struct acpi_probe_entry *); - -struct acpi_probe_entry { - __u8 id[5]; - __u8 type; - acpi_probe_entry_validate_subtbl subtable_valid; - union { - acpi_tbl_table_handler probe_table; - acpi_tbl_entry_handler probe_subtbl; - }; - kernel_ulong_t driver_data; -}; - -struct acpi_scan_clear_dep_work { - struct work_struct work; - struct acpi_device *adev; -}; - -struct resource_win { - struct resource res; - resource_size_t offset; -}; - -struct res_proc_context { - struct list_head *list; - int (*preproc)(struct acpi_resource *, void *); - void *preproc_data; - int count; - int error; -}; - -struct acpi_processor_errata { - u8 smp; - struct { - u8 throttle: 1; - u8 fdma: 1; - u8 reserved: 6; - u32 bmisx; - } piix4; -}; - -struct acpi_table_ecdt { - struct acpi_table_header header; - struct acpi_generic_address control; - struct acpi_generic_address data; - u32 uid; - u8 gpe; - u8 id[1]; -} __attribute__((packed)); - -struct transaction; - -struct acpi_ec { - acpi_handle handle; - int gpe; - int irq; - long unsigned int command_addr; - long unsigned int data_addr; - bool global_lock; - long unsigned int flags; - long unsigned int reference_count; - struct mutex mutex; - wait_queue_head_t wait; - struct list_head list; - struct transaction *curr; - spinlock_t lock; - struct work_struct work; - long unsigned int timestamp; - long unsigned int nr_pending_queries; - bool busy_polling; - unsigned int polling_guard; -}; - -struct transaction { - const u8 *wdata; - u8 *rdata; - short unsigned int irq_count; - u8 command; - u8 wi; - u8 ri; - u8 wlen; - u8 rlen; - u8 flags; -}; - -typedef int (*acpi_ec_query_func)(void *); - -enum ec_command { - ACPI_EC_COMMAND_READ = 128, - ACPI_EC_COMMAND_WRITE = 129, - ACPI_EC_BURST_ENABLE = 130, - ACPI_EC_BURST_DISABLE = 131, - ACPI_EC_COMMAND_QUERY = 132, -}; - -enum { - EC_FLAGS_QUERY_ENABLED = 0, - EC_FLAGS_QUERY_PENDING = 1, - EC_FLAGS_QUERY_GUARDING = 2, - EC_FLAGS_EVENT_HANDLER_INSTALLED = 3, - EC_FLAGS_EC_HANDLER_INSTALLED = 4, - EC_FLAGS_QUERY_METHODS_INSTALLED = 5, - EC_FLAGS_STARTED = 6, - EC_FLAGS_STOPPED = 7, - EC_FLAGS_EVENTS_MASKED = 8, -}; - -struct acpi_ec_query_handler { - struct list_head node; - acpi_ec_query_func func; - acpi_handle handle; - void *data; - u8 query_bit; - struct kref kref; -}; - -struct acpi_ec_query { - struct transaction transaction; - struct work_struct work; - struct acpi_ec_query_handler *handler; -}; - -struct dock_station { - acpi_handle handle; - long unsigned int last_dock_time; - u32 flags; - struct list_head dependent_devices; - struct list_head sibling; - struct platform_device *dock_device; -}; - -struct dock_dependent_device { - struct list_head list; - struct acpi_device *adev; -}; - -enum dock_callback_type { - DOCK_CALL_HANDLER = 0, - DOCK_CALL_FIXUP = 1, - DOCK_CALL_UEVENT = 2, -}; - -struct acpi_pci_root_ops; - -struct acpi_pci_root_info { - struct acpi_pci_root *root; - struct acpi_device *bridge; - struct acpi_pci_root_ops *ops; - struct list_head resources; - char name[16]; -}; - -struct acpi_pci_root_ops { - struct pci_ops *pci_ops; - int (*init_info)(struct acpi_pci_root_info *); - void (*release_info)(struct acpi_pci_root_info *); - int (*prepare_resources)(struct acpi_pci_root_info *); -}; - -struct pci_osc_bit_struct { - u32 bit; - char *desc; -}; - -struct acpi_handle_node { - struct list_head node; - acpi_handle handle; -}; - -struct acpi_pci_link_irq { - u32 active; - u8 triggering; - u8 polarity; - u8 resource_type; - u8 possible_count; - u32 possible[16]; - u8 initialized: 1; - u8 reserved: 7; -}; - -struct acpi_pci_link { - struct list_head list; - struct acpi_device *device; - struct acpi_pci_link_irq irq; - int refcnt; -}; - -struct acpi_pci_routing_table { - u32 length; - u32 pin; - u64 address; - u32 source_index; - char source[4]; -}; - -struct acpi_prt_entry { - struct acpi_pci_id id; - u8 pin; - acpi_handle link; - u32 index; -}; - -struct prt_quirk { - const struct dmi_system_id *system; - unsigned int segment; - unsigned int bus; - unsigned int device; - unsigned char pin; - const char *source; - const char *actual_source; -}; - -struct lpss_clk_data { - const char *name; - struct clk *clk; -}; - -struct lpss_private_data; - -struct lpss_device_desc { - unsigned int flags; - const char *clk_con_id; - unsigned int prv_offset; - size_t prv_size_override; - struct property_entry *properties; - void (*setup)(struct lpss_private_data *); - bool resume_from_noirq; -}; - -struct lpss_private_data { - struct acpi_device *adev; - void *mmio_base; - resource_size_t mmio_size; - unsigned int fixed_clk_rate; - struct clk *clk; - const struct lpss_device_desc *dev_desc; - u32 prv_reg_ctx[9]; -}; - -struct lpss_device_links { - const char *supplier_hid; - const char *supplier_uid; - const char *consumer_hid; - const char *consumer_uid; - u32 flags; - const struct dmi_system_id *dep_missing_ids; -}; - -struct hid_uid { - const char *hid; - const char *uid; -}; - -struct fch_clk_data { - void *base; - u32 is_rv; -}; - -struct apd_private_data; - -struct apd_device_desc { - unsigned int fixed_clk_rate; - struct property_entry *properties; - int (*setup)(struct apd_private_data *); -}; - -struct apd_private_data { - struct clk *clk; - struct acpi_device *adev; - const struct apd_device_desc *dev_desc; -}; - -struct acpi_power_dependent_device { - struct device *dev; - struct list_head node; -}; - -struct acpi_power_resource { - struct acpi_device device; - struct list_head list_node; - char *name; - u32 system_level; - u32 order; - unsigned int ref_count; - u8 state; - bool wakeup_enabled; - struct mutex resource_lock; - struct list_head dependents; -}; - -struct acpi_power_resource_entry { - struct list_head node; - struct acpi_power_resource *resource; -}; - -struct acpi_bus_event { - struct list_head node; - acpi_device_class device_class; - acpi_bus_id bus_id; - u32 type; - u32 data; -}; - -struct acpi_genl_event { - acpi_device_class device_class; - char bus_id[15]; - u32 type; - u32 data; -}; - -enum { - ACPI_GENL_ATTR_UNSPEC = 0, - ACPI_GENL_ATTR_EVENT = 1, - __ACPI_GENL_ATTR_MAX = 2, -}; - -enum { - ACPI_GENL_CMD_UNSPEC = 0, - ACPI_GENL_CMD_EVENT = 1, - __ACPI_GENL_CMD_MAX = 2, -}; - -struct acpi_ged_device { - struct device *dev; - struct list_head event_list; -}; - -struct acpi_ged_event { - struct list_head node; - struct device *dev; - unsigned int gsi; - unsigned int irq; - acpi_handle handle; -}; - -typedef void (*acpi_gbl_event_handler)(u32, acpi_handle, u32, void *); - -struct acpi_table_bert { - struct acpi_table_header header; - u32 region_length; - u64 address; -}; - -struct acpi_dlayer { - const char *name; - long unsigned int value; -}; - -struct acpi_dlevel { - const char *name; - long unsigned int value; -}; - -struct acpi_table_attr { - struct bin_attribute attr; - char name[4]; - int instance; - char filename[8]; - struct list_head node; -}; - -struct acpi_data_attr { - struct bin_attribute attr; - u64 addr; -}; - -struct acpi_data_obj { - char *name; - int (*fn)(void *, struct acpi_data_attr *); -}; - -struct event_counter { - u32 count; - u32 flags; -}; - -struct acpi_device_properties { - const guid_t *guid; - const union acpi_object *properties; - struct list_head list; -}; - -struct always_present_id { - struct acpi_device_id hid[2]; - struct x86_cpu_id cpu_ids[2]; - struct dmi_system_id dmi_ids[2]; - const char *uid; -}; - -struct lpi_device_info { - char *name; - int enabled; - union acpi_object *package; -}; - -struct lpi_device_constraint { - int uid; - int min_dstate; - int function_states; -}; - -struct lpi_constraints { - acpi_handle handle; - int min_dstate; -}; - -struct lpi_device_constraint_amd { - char *name; - int enabled; - int function_states; - int min_dstate; -}; - -struct acpi_lpat { - int temp; - int raw; -}; - -struct acpi_lpat_conversion_table { - struct acpi_lpat *lpat; - int lpat_count; -}; - -enum fpdt_subtable_type { - SUBTABLE_FBPT = 0, - SUBTABLE_S3PT = 1, -}; - -struct fpdt_subtable_entry { - u16 type; - u8 length; - u8 revision; - u32 reserved; - u64 address; -}; - -struct fpdt_subtable_header { - u32 signature; - u32 length; -}; - -enum fpdt_record_type { - RECORD_S3_RESUME = 0, - RECORD_S3_SUSPEND = 1, - RECORD_BOOT = 2, -}; - -struct fpdt_record_header { - u16 type; - u8 length; - u8 revision; -}; - -struct resume_performance_record { - struct fpdt_record_header header; - u32 resume_count; - u64 resume_prev; - u64 resume_avg; -}; - -struct boot_performance_record { - struct fpdt_record_header header; - u32 reserved; - u64 firmware_start; - u64 bootloader_load; - u64 bootloader_launch; - u64 exitbootservice_start; - u64 exitbootservice_end; -}; - -struct suspend_performance_record { - struct fpdt_record_header header; - u64 suspend_start; - u64 suspend_end; -} __attribute__((packed)); - -struct acpi_table_lpit { - struct acpi_table_header header; -}; - -struct acpi_lpit_header { - u32 type; - u32 length; - u16 unique_id; - u16 reserved; - u32 flags; -}; - -struct acpi_lpit_native { - struct acpi_lpit_header header; - struct acpi_generic_address entry_trigger; - u32 residency; - u32 latency; - struct acpi_generic_address residency_counter; - u64 counter_frequency; -} __attribute__((packed)); - -struct lpit_residency_info { - struct acpi_generic_address gaddr; - u64 frequency; - void *iomem_addr; -}; - -struct acpi_table_wdat { - struct acpi_table_header header; - u32 header_length; - u16 pci_segment; - u8 pci_bus; - u8 pci_device; - u8 pci_function; - u8 reserved[3]; - u32 timer_period; - u32 max_count; - u32 min_count; - u8 flags; - u8 reserved2[3]; - u32 entries; -}; - -struct acpi_wdat_entry { - u8 action; - u8 instruction; - u16 reserved; - struct acpi_generic_address register_region; - u32 value; - u32 mask; -} __attribute__((packed)); - -typedef u64 acpi_integer; - -struct acpi_prmt_module_info { - u16 revision; - u16 length; - u8 module_guid[16]; - u16 major_rev; - u16 minor_rev; - u16 handler_info_count; - u32 handler_info_offset; - u64 mmio_list_pointer; -} __attribute__((packed)); - -struct acpi_prmt_handler_info { - u16 revision; - u16 length; - u8 handler_guid[16]; - u64 handler_address; - u64 static_data_buffer_address; - u64 acpi_param_buffer_address; -} __attribute__((packed)); - -struct prm_mmio_addr_range { - u64 phys_addr; - u64 virt_addr; - u32 length; -} __attribute__((packed)); - -struct prm_mmio_info { - u64 mmio_count; - struct prm_mmio_addr_range addr_ranges[0]; -}; - -struct prm_buffer { - u8 prm_status; - u64 efi_status; - u8 prm_cmd; - guid_t handler_guid; -} __attribute__((packed)); - -struct prm_context_buffer { - char signature[4]; - u16 revision; - u16 reserved; - guid_t identifier; - u64 static_data_buffer; - struct prm_mmio_info *mmio_ranges; -}; - -struct prm_handler_info { - guid_t guid; - u64 handler_addr; - u64 static_data_buffer_addr; - u64 acpi_param_buffer_addr; - struct list_head handler_list; -}; - -struct prm_module_info { - guid_t guid; - u16 major_rev; - u16 minor_rev; - u16 handler_count; - struct prm_mmio_info *mmio_info; - bool updatable; - struct list_head module_list; - struct prm_handler_info handlers[0]; -}; - -struct acpi_name_info { - char name[4]; - u16 argument_list; - u8 expected_btypes; -} __attribute__((packed)); - -struct acpi_package_info { - u8 type; - u8 object_type1; - u8 count1; - u8 object_type2; - u8 count2; - u16 reserved; -} __attribute__((packed)); - -struct acpi_package_info2 { - u8 type; - u8 count; - u8 object_type[4]; - u8 reserved; -}; - -struct acpi_package_info3 { - u8 type; - u8 count; - u8 object_type[2]; - u8 tail_object_type; - u16 reserved; -} __attribute__((packed)); - -struct acpi_package_info4 { - u8 type; - u8 object_type1; - u8 count1; - u8 sub_object_types; - u8 pkg_count; - u16 reserved; -} __attribute__((packed)); - -union acpi_predefined_info { - struct acpi_name_info info; - struct acpi_package_info ret_info; - struct acpi_package_info2 ret_info2; - struct acpi_package_info3 ret_info3; - struct acpi_package_info4 ret_info4; -}; - -struct acpi_evaluate_info { - struct acpi_namespace_node *prefix_node; - const char *relative_pathname; - union acpi_operand_object **parameters; - struct acpi_namespace_node *node; - union acpi_operand_object *obj_desc; - char *full_pathname; - const union acpi_predefined_info *predefined; - union acpi_operand_object *return_object; - union acpi_operand_object *parent_package; - u32 return_flags; - u32 return_btype; - u16 param_count; - u16 node_flags; - u8 pass_number; - u8 return_object_type; - u8 flags; -}; - -enum { - ACPI_REFCLASS_LOCAL = 0, - ACPI_REFCLASS_ARG = 1, - ACPI_REFCLASS_REFOF = 2, - ACPI_REFCLASS_INDEX = 3, - ACPI_REFCLASS_TABLE = 4, - ACPI_REFCLASS_NAME = 5, - ACPI_REFCLASS_DEBUG = 6, - ACPI_REFCLASS_MAX = 6, -}; - -struct acpi_common_descriptor { - void *common_pointer; - u8 descriptor_type; -}; - -union acpi_descriptor { - struct acpi_common_descriptor common; - union acpi_operand_object object; - struct acpi_namespace_node node; - union acpi_parse_object op; -}; - -typedef enum { - ACPI_IMODE_LOAD_PASS1 = 1, - ACPI_IMODE_LOAD_PASS2 = 2, - ACPI_IMODE_EXECUTE = 3, -} acpi_interpreter_mode; - -struct acpi_create_field_info { - struct acpi_namespace_node *region_node; - struct acpi_namespace_node *field_node; - struct acpi_namespace_node *register_node; - struct acpi_namespace_node *data_register_node; - struct acpi_namespace_node *connection_node; - u8 *resource_buffer; - u32 bank_value; - u32 field_bit_position; - u32 field_bit_length; - u16 resource_length; - u16 pin_number_index; - u8 field_flags; - u8 attribute; - u8 field_type; - u8 access_length; -}; - -struct acpi_init_walk_info { - u32 table_index; - u32 object_count; - u32 method_count; - u32 serial_method_count; - u32 non_serial_method_count; - u32 serialized_method_count; - u32 device_count; - u32 op_region_count; - u32 field_count; - u32 buffer_count; - u32 package_count; - u32 op_region_init; - u32 field_init; - u32 buffer_init; - u32 package_init; - acpi_owner_id owner_id; -}; - -typedef u32 acpi_name; - -typedef acpi_status (*acpi_exception_handler)(acpi_status, acpi_name, u16, u32, void *); - -enum { - AML_FIELD_ACCESS_ANY = 0, - AML_FIELD_ACCESS_BYTE = 1, - AML_FIELD_ACCESS_WORD = 2, - AML_FIELD_ACCESS_DWORD = 3, - AML_FIELD_ACCESS_QWORD = 4, - AML_FIELD_ACCESS_BUFFER = 5, -}; - -typedef acpi_status (*acpi_execute_op)(struct acpi_walk_state *); - -struct acpi_fixed_event_handler { - acpi_event_handler handler; - void *context; -}; - -struct acpi_fixed_event_info { - u8 status_register_id; - u8 enable_register_id; - u16 status_bit_mask; - u16 enable_bit_mask; -}; - -typedef u32 acpi_mutex_handle; - -struct acpi_gpe_walk_info { - struct acpi_namespace_node *gpe_device; - struct acpi_gpe_block_info *gpe_block; - u16 count; - acpi_owner_id owner_id; - u8 execute_by_owner_id; -}; - -struct acpi_gpe_device_info { - u32 index; - u32 next_block_base_index; - acpi_status status; - struct acpi_namespace_node *gpe_device; -}; - -typedef acpi_status (*acpi_gpe_callback)(struct acpi_gpe_xrupt_info *, struct acpi_gpe_block_info *, void *); - -struct acpi_reg_walk_info { - u32 function; - u32 reg_run_count; - acpi_adr_space_type space_id; -}; - -typedef u32 (*acpi_sci_handler)(void *); - -struct acpi_sci_handler_info { - struct acpi_sci_handler_info *next; - acpi_sci_handler address; - void *context; -}; - -struct acpi_exdump_info { - u8 opcode; - u8 offset; - const char *name; -} __attribute__((packed)); - -enum { - AML_FIELD_UPDATE_PRESERVE = 0, - AML_FIELD_UPDATE_WRITE_AS_ONES = 32, - AML_FIELD_UPDATE_WRITE_AS_ZEROS = 64, -}; - -struct acpi_signal_fatal_info { - u32 type; - u32 code; - u32 argument; -}; - -enum { - MATCH_MTR = 0, - MATCH_MEQ = 1, - MATCH_MLE = 2, - MATCH_MLT = 3, - MATCH_MGE = 4, - MATCH_MGT = 5, -}; - -enum { - AML_FIELD_ATTRIB_QUICK = 2, - AML_FIELD_ATTRIB_SEND_RECEIVE = 4, - AML_FIELD_ATTRIB_BYTE = 6, - AML_FIELD_ATTRIB_WORD = 8, - AML_FIELD_ATTRIB_BLOCK = 10, - AML_FIELD_ATTRIB_BYTES = 11, - AML_FIELD_ATTRIB_PROCESS_CALL = 12, - AML_FIELD_ATTRIB_BLOCK_PROCESS_CALL = 13, - AML_FIELD_ATTRIB_RAW_BYTES = 14, - AML_FIELD_ATTRIB_RAW_PROCESS_BYTES = 15, -}; - -typedef enum { - ACPI_TRACE_AML_METHOD = 0, - ACPI_TRACE_AML_OPCODE = 1, - ACPI_TRACE_AML_REGION = 2, -} acpi_trace_event_type; - -struct acpi_gpe_block_status_context { - struct acpi_gpe_register_info *gpe_skip_register_info; - u8 gpe_skip_mask; - u8 retval; -}; - -struct acpi_bit_register_info { - u8 parent_register; - u8 bit_position; - u16 access_bit_mask; -}; - -struct acpi_port_info { - char *name; - u16 start; - u16 end; - u8 osi_dependency; -}; - -struct acpi_pci_device { - acpi_handle device; - struct acpi_pci_device *next; -}; - -struct acpi_walk_info { - u32 debug_level; - u32 count; - acpi_owner_id owner_id; - u8 display_type; -}; - -typedef acpi_status (*acpi_init_handler)(acpi_handle, u32); - -struct acpi_device_walk_info { - struct acpi_table_desc *table_desc; - struct acpi_evaluate_info *evaluate_info; - u32 device_count; - u32 num_STA; - u32 num_INI; -}; - -typedef acpi_status (*acpi_pkg_callback)(u8, union acpi_operand_object *, union acpi_generic_state *, void *); - -struct acpi_table_list { - struct acpi_table_desc *tables; - u32 current_table_count; - u32 max_table_count; - u8 flags; -}; - -enum acpi_return_package_types { - ACPI_PTYPE1_FIXED = 1, - ACPI_PTYPE1_VAR = 2, - ACPI_PTYPE1_OPTION = 3, - ACPI_PTYPE2 = 4, - ACPI_PTYPE2_COUNT = 5, - ACPI_PTYPE2_PKG_COUNT = 6, - ACPI_PTYPE2_FIXED = 7, - ACPI_PTYPE2_MIN = 8, - ACPI_PTYPE2_REV_FIXED = 9, - ACPI_PTYPE2_FIX_VAR = 10, - ACPI_PTYPE2_VAR_VAR = 11, - ACPI_PTYPE2_UUID_PAIR = 12, - ACPI_PTYPE_CUSTOM = 13, -}; - -typedef acpi_status (*acpi_object_converter)(struct acpi_namespace_node *, union acpi_operand_object *, union acpi_operand_object **); - -struct acpi_simple_repair_info { - char name[4]; - u32 unexpected_btypes; - u32 package_index; - acpi_object_converter object_converter; -}; - -typedef acpi_status (*acpi_repair_function)(struct acpi_evaluate_info *, union acpi_operand_object **); - -struct acpi_repair_info { - char name[4]; - acpi_repair_function repair_function; -}; - -struct acpi_namestring_info { - const char *external_name; - const char *next_external_char; - char *internal_name; - u32 length; - u32 num_segments; - u32 num_carats; - u8 fully_qualified; -}; - -struct acpi_rw_lock { - void *writer_mutex; - void *reader_mutex; - u32 num_readers; -}; - -struct acpi_get_devices_info { - acpi_walk_callback user_function; - void *context; - const char *hid; -}; - -struct aml_resource_small_header { - u8 descriptor_type; -}; - -struct aml_resource_irq { - u8 descriptor_type; - u16 irq_mask; - u8 flags; -} __attribute__((packed)); - -struct aml_resource_dma { - u8 descriptor_type; - u8 dma_channel_mask; - u8 flags; -}; - -struct aml_resource_start_dependent { - u8 descriptor_type; - u8 flags; -}; - -struct aml_resource_end_dependent { - u8 descriptor_type; -}; - -struct aml_resource_io { - u8 descriptor_type; - u8 flags; - u16 minimum; - u16 maximum; - u8 alignment; - u8 address_length; -}; - -struct aml_resource_fixed_io { - u8 descriptor_type; - u16 address; - u8 address_length; -} __attribute__((packed)); - -struct aml_resource_vendor_small { - u8 descriptor_type; -}; - -struct aml_resource_end_tag { - u8 descriptor_type; - u8 checksum; -}; - -struct aml_resource_fixed_dma { - u8 descriptor_type; - u16 request_lines; - u16 channels; - u8 width; -} __attribute__((packed)); - -struct aml_resource_large_header { - u8 descriptor_type; - u16 resource_length; -} __attribute__((packed)); - -struct aml_resource_memory24 { - u8 descriptor_type; - u16 resource_length; - u8 flags; - u16 minimum; - u16 maximum; - u16 alignment; - u16 address_length; -} __attribute__((packed)); - -struct aml_resource_vendor_large { - u8 descriptor_type; - u16 resource_length; -} __attribute__((packed)); - -struct aml_resource_memory32 { - u8 descriptor_type; - u16 resource_length; - u8 flags; - u32 minimum; - u32 maximum; - u32 alignment; - u32 address_length; -} __attribute__((packed)); - -struct aml_resource_fixed_memory32 { - u8 descriptor_type; - u16 resource_length; - u8 flags; - u32 address; - u32 address_length; -} __attribute__((packed)); - -struct aml_resource_address { - u8 descriptor_type; - u16 resource_length; - u8 resource_type; - u8 flags; - u8 specific_flags; -} __attribute__((packed)); - -struct aml_resource_extended_address64 { - u8 descriptor_type; - u16 resource_length; - u8 resource_type; - u8 flags; - u8 specific_flags; - u8 revision_ID; - u8 reserved; - u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; - u64 type_specific; -} __attribute__((packed)); - -struct aml_resource_address64 { - u8 descriptor_type; - u16 resource_length; - u8 resource_type; - u8 flags; - u8 specific_flags; - u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; -} __attribute__((packed)); - -struct aml_resource_address32 { - u8 descriptor_type; - u16 resource_length; - u8 resource_type; - u8 flags; - u8 specific_flags; - u32 granularity; - u32 minimum; - u32 maximum; - u32 translation_offset; - u32 address_length; -} __attribute__((packed)); - -struct aml_resource_address16 { - u8 descriptor_type; - u16 resource_length; - u8 resource_type; - u8 flags; - u8 specific_flags; - u16 granularity; - u16 minimum; - u16 maximum; - u16 translation_offset; - u16 address_length; -} __attribute__((packed)); - -struct aml_resource_extended_irq { - u8 descriptor_type; - u16 resource_length; - u8 flags; - u8 interrupt_count; - u32 interrupts[1]; -} __attribute__((packed)); - -struct aml_resource_generic_register { - u8 descriptor_type; - u16 resource_length; - u8 address_space_id; - u8 bit_width; - u8 bit_offset; - u8 access_size; - u64 address; -} __attribute__((packed)); - -struct aml_resource_gpio { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u8 connection_type; - u16 flags; - u16 int_flags; - u8 pin_config; - u16 drive_strength; - u16 debounce_timeout; - u16 pin_table_offset; - u8 res_source_index; - u16 res_source_offset; - u16 vendor_offset; - u16 vendor_length; -} __attribute__((packed)); - -struct aml_resource_common_serialbus { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u8 res_source_index; - u8 type; - u8 flags; - u16 type_specific_flags; - u8 type_revision_id; - u16 type_data_length; -} __attribute__((packed)); - -struct aml_resource_csi2_serialbus { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u8 res_source_index; - u8 type; - u8 flags; - u16 type_specific_flags; - u8 type_revision_id; - u16 type_data_length; -} __attribute__((packed)); - -struct aml_resource_i2c_serialbus { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u8 res_source_index; - u8 type; - u8 flags; - u16 type_specific_flags; - u8 type_revision_id; - u16 type_data_length; - u32 connection_speed; - u16 slave_address; -} __attribute__((packed)); - -struct aml_resource_spi_serialbus { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u8 res_source_index; - u8 type; - u8 flags; - u16 type_specific_flags; - u8 type_revision_id; - u16 type_data_length; - u32 connection_speed; - u8 data_bit_length; - u8 clock_phase; - u8 clock_polarity; - u16 device_selection; -} __attribute__((packed)); - -struct aml_resource_uart_serialbus { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u8 res_source_index; - u8 type; - u8 flags; - u16 type_specific_flags; - u8 type_revision_id; - u16 type_data_length; - u32 default_baud_rate; - u16 rx_fifo_size; - u16 tx_fifo_size; - u8 parity; - u8 lines_enabled; -} __attribute__((packed)); - -struct aml_resource_pin_function { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u16 flags; - u8 pin_config; - u16 function_number; - u16 pin_table_offset; - u8 res_source_index; - u16 res_source_offset; - u16 vendor_offset; - u16 vendor_length; -} __attribute__((packed)); - -struct aml_resource_pin_config { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u16 flags; - u8 pin_config_type; - u32 pin_config_value; - u16 pin_table_offset; - u8 res_source_index; - u16 res_source_offset; - u16 vendor_offset; - u16 vendor_length; -} __attribute__((packed)); - -struct aml_resource_pin_group { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u16 flags; - u16 pin_table_offset; - u16 label_offset; - u16 vendor_offset; - u16 vendor_length; -} __attribute__((packed)); - -struct aml_resource_pin_group_function { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u16 flags; - u16 function_number; - u8 res_source_index; - u16 res_source_offset; - u16 res_source_label_offset; - u16 vendor_offset; - u16 vendor_length; -} __attribute__((packed)); - -struct aml_resource_pin_group_config { - u8 descriptor_type; - u16 resource_length; - u8 revision_id; - u16 flags; - u8 pin_config_type; - u32 pin_config_value; - u8 res_source_index; - u16 res_source_offset; - u16 res_source_label_offset; - u16 vendor_offset; - u16 vendor_length; -} __attribute__((packed)); - -union aml_resource { - u8 descriptor_type; - struct aml_resource_small_header small_header; - struct aml_resource_large_header large_header; - struct aml_resource_irq irq; - struct aml_resource_dma dma; - struct aml_resource_start_dependent start_dpf; - struct aml_resource_end_dependent end_dpf; - struct aml_resource_io io; - struct aml_resource_fixed_io fixed_io; - struct aml_resource_fixed_dma fixed_dma; - struct aml_resource_vendor_small vendor_small; - struct aml_resource_end_tag end_tag; - struct aml_resource_memory24 memory24; - struct aml_resource_generic_register generic_reg; - struct aml_resource_vendor_large vendor_large; - struct aml_resource_memory32 memory32; - struct aml_resource_fixed_memory32 fixed_memory32; - struct aml_resource_address16 address16; - struct aml_resource_address32 address32; - struct aml_resource_address64 address64; - struct aml_resource_extended_address64 ext_address64; - struct aml_resource_extended_irq extended_irq; - struct aml_resource_gpio gpio; - struct aml_resource_i2c_serialbus i2c_serial_bus; - struct aml_resource_spi_serialbus spi_serial_bus; - struct aml_resource_uart_serialbus uart_serial_bus; - struct aml_resource_csi2_serialbus csi2_serial_bus; - struct aml_resource_common_serialbus common_serial_bus; - struct aml_resource_pin_function pin_function; - struct aml_resource_pin_config pin_config; - struct aml_resource_pin_group pin_group; - struct aml_resource_pin_group_function pin_group_function; - struct aml_resource_pin_group_config pin_group_config; - struct aml_resource_address address; - u32 dword_item; - u16 word_item; - u8 byte_item; -}; - -struct acpi_rsconvert_info { - u8 opcode; - u8 resource_offset; - u8 aml_offset; - u8 value; -}; - -enum { - ACPI_RSC_INITGET = 0, - ACPI_RSC_INITSET = 1, - ACPI_RSC_FLAGINIT = 2, - ACPI_RSC_1BITFLAG = 3, - ACPI_RSC_2BITFLAG = 4, - ACPI_RSC_3BITFLAG = 5, - ACPI_RSC_6BITFLAG = 6, - ACPI_RSC_ADDRESS = 7, - ACPI_RSC_BITMASK = 8, - ACPI_RSC_BITMASK16 = 9, - ACPI_RSC_COUNT = 10, - ACPI_RSC_COUNT16 = 11, - ACPI_RSC_COUNT_GPIO_PIN = 12, - ACPI_RSC_COUNT_GPIO_RES = 13, - ACPI_RSC_COUNT_GPIO_VEN = 14, - ACPI_RSC_COUNT_SERIAL_RES = 15, - ACPI_RSC_COUNT_SERIAL_VEN = 16, - ACPI_RSC_DATA8 = 17, - ACPI_RSC_EXIT_EQ = 18, - ACPI_RSC_EXIT_LE = 19, - ACPI_RSC_EXIT_NE = 20, - ACPI_RSC_LENGTH = 21, - ACPI_RSC_MOVE_GPIO_PIN = 22, - ACPI_RSC_MOVE_GPIO_RES = 23, - ACPI_RSC_MOVE_SERIAL_RES = 24, - ACPI_RSC_MOVE_SERIAL_VEN = 25, - ACPI_RSC_MOVE8 = 26, - ACPI_RSC_MOVE16 = 27, - ACPI_RSC_MOVE32 = 28, - ACPI_RSC_MOVE64 = 29, - ACPI_RSC_SET8 = 30, - ACPI_RSC_SOURCE = 31, - ACPI_RSC_SOURCEX = 32, -}; - -typedef u16 acpi_rs_length; - -typedef acpi_status (*acpi_walk_aml_callback)(u8 *, u32, u32, u8, void **); - -struct acpi_rsdump_info { - u8 opcode; - u8 offset; - const char *name; - const char **pointer; -} __attribute__((packed)); - -enum { - ACPI_RSD_TITLE = 0, - ACPI_RSD_1BITFLAG = 1, - ACPI_RSD_2BITFLAG = 2, - ACPI_RSD_3BITFLAG = 3, - ACPI_RSD_6BITFLAG = 4, - ACPI_RSD_ADDRESS = 5, - ACPI_RSD_DWORDLIST = 6, - ACPI_RSD_LITERAL = 7, - ACPI_RSD_LONGLIST = 8, - ACPI_RSD_SHORTLIST = 9, - ACPI_RSD_SHORTLISTX = 10, - ACPI_RSD_SOURCE = 11, - ACPI_RSD_STRING = 12, - ACPI_RSD_UINT8 = 13, - ACPI_RSD_UINT16 = 14, - ACPI_RSD_UINT32 = 15, - ACPI_RSD_UINT64 = 16, - ACPI_RSD_WORDLIST = 17, - ACPI_RSD_LABEL = 18, - ACPI_RSD_SOURCE_LABEL = 19, -}; - -typedef u32 acpi_rsdesc_size; - -struct acpi_vendor_uuid { - u8 subtype; - u8 data[16]; -}; - -struct acpi_vendor_walk_info { - struct acpi_vendor_uuid *uuid; - struct acpi_buffer *buffer; - acpi_status status; -}; - -struct acpi_fadt_info { - const char *name; - u16 address64; - u16 address32; - u16 length; - u8 default_length; - u8 flags; -}; - -struct acpi_fadt_pm_info { - struct acpi_generic_address *target; - u16 source; - u8 register_num; -}; - -struct acpi_table_rsdp { - char signature[8]; - u8 checksum; - char oem_id[6]; - u8 revision; - u32 rsdt_physical_address; - u32 length; - u64 xsdt_physical_address; - u8 extended_checksum; - u8 reserved[3]; -} __attribute__((packed)); - -struct acpi_address_range { - struct acpi_address_range *next; - struct acpi_namespace_node *region_node; - acpi_physical_address start_address; - acpi_physical_address end_address; -}; - -struct acpi_pkg_info { - u8 *free_space; - acpi_size length; - u32 object_space; - u32 num_packages; -}; - -struct acpi_exception_info { - char *name; -}; - -struct acpi_mutex_info { - void *mutex; - u32 use_count; - u64 thread_id; -}; - -struct acpi_comment_node { - char *comment; - struct acpi_comment_node *next; -}; - -struct acpi_interface_info { - char *name; - struct acpi_interface_info *next; - u8 flags; - u8 value; -}; - -enum led_brightness { - LED_OFF = 0, - LED_ON = 1, - LED_HALF = 127, - LED_FULL = 255, -}; - -struct led_hw_trigger_type { - int dummy; -}; - -struct led_pattern; - -struct led_trigger; - -struct led_classdev { - const char *name; - unsigned int brightness; - unsigned int max_brightness; - int flags; - long unsigned int work_flags; - void (*brightness_set)(struct led_classdev *, enum led_brightness); - int (*brightness_set_blocking)(struct led_classdev *, enum led_brightness); - enum led_brightness (*brightness_get)(struct led_classdev *); - int (*blink_set)(struct led_classdev *, long unsigned int *, long unsigned int *); - int (*pattern_set)(struct led_classdev *, struct led_pattern *, u32, int); - int (*pattern_clear)(struct led_classdev *); - struct device *dev; - const struct attribute_group **groups; - struct list_head node; - const char *default_trigger; - long unsigned int blink_delay_on; - long unsigned int blink_delay_off; - struct timer_list blink_timer; - int blink_brightness; - int new_blink_brightness; - void (*flash_resume)(struct led_classdev *); - struct work_struct set_brightness_work; - int delayed_set_value; - struct rw_semaphore trigger_lock; - struct led_trigger *trigger; - struct list_head trig_list; - void *trigger_data; - bool activated; - struct led_hw_trigger_type *trigger_type; - int brightness_hw_changed; - struct kernfs_node *brightness_hw_changed_kn; - struct mutex led_access; -}; - -struct led_pattern { - u32 delta_t; - int brightness; -}; - -struct led_trigger { - const char *name; - int (*activate)(struct led_classdev *); - void (*deactivate)(struct led_classdev *); - struct led_hw_trigger_type *trigger_type; - rwlock_t leddev_list_lock; - struct list_head led_cdevs; - struct list_head next_trig; - const struct attribute_group **groups; -}; - -enum power_supply_property { - POWER_SUPPLY_PROP_STATUS = 0, - POWER_SUPPLY_PROP_CHARGE_TYPE = 1, - POWER_SUPPLY_PROP_HEALTH = 2, - POWER_SUPPLY_PROP_PRESENT = 3, - POWER_SUPPLY_PROP_ONLINE = 4, - POWER_SUPPLY_PROP_AUTHENTIC = 5, - POWER_SUPPLY_PROP_TECHNOLOGY = 6, - POWER_SUPPLY_PROP_CYCLE_COUNT = 7, - POWER_SUPPLY_PROP_VOLTAGE_MAX = 8, - POWER_SUPPLY_PROP_VOLTAGE_MIN = 9, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN = 10, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN = 11, - POWER_SUPPLY_PROP_VOLTAGE_NOW = 12, - POWER_SUPPLY_PROP_VOLTAGE_AVG = 13, - POWER_SUPPLY_PROP_VOLTAGE_OCV = 14, - POWER_SUPPLY_PROP_VOLTAGE_BOOT = 15, - POWER_SUPPLY_PROP_CURRENT_MAX = 16, - POWER_SUPPLY_PROP_CURRENT_NOW = 17, - POWER_SUPPLY_PROP_CURRENT_AVG = 18, - POWER_SUPPLY_PROP_CURRENT_BOOT = 19, - POWER_SUPPLY_PROP_POWER_NOW = 20, - POWER_SUPPLY_PROP_POWER_AVG = 21, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN = 22, - POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN = 23, - POWER_SUPPLY_PROP_CHARGE_FULL = 24, - POWER_SUPPLY_PROP_CHARGE_EMPTY = 25, - POWER_SUPPLY_PROP_CHARGE_NOW = 26, - POWER_SUPPLY_PROP_CHARGE_AVG = 27, - POWER_SUPPLY_PROP_CHARGE_COUNTER = 28, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT = 29, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX = 30, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE = 31, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX = 32, - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT = 33, - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX = 34, - POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD = 35, - POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD = 36, - POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT = 37, - POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT = 38, - POWER_SUPPLY_PROP_INPUT_POWER_LIMIT = 39, - POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN = 40, - POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN = 41, - POWER_SUPPLY_PROP_ENERGY_FULL = 42, - POWER_SUPPLY_PROP_ENERGY_EMPTY = 43, - POWER_SUPPLY_PROP_ENERGY_NOW = 44, - POWER_SUPPLY_PROP_ENERGY_AVG = 45, - POWER_SUPPLY_PROP_CAPACITY = 46, - POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN = 47, - POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX = 48, - POWER_SUPPLY_PROP_CAPACITY_ERROR_MARGIN = 49, - POWER_SUPPLY_PROP_CAPACITY_LEVEL = 50, - POWER_SUPPLY_PROP_TEMP = 51, - POWER_SUPPLY_PROP_TEMP_MAX = 52, - POWER_SUPPLY_PROP_TEMP_MIN = 53, - POWER_SUPPLY_PROP_TEMP_ALERT_MIN = 54, - POWER_SUPPLY_PROP_TEMP_ALERT_MAX = 55, - POWER_SUPPLY_PROP_TEMP_AMBIENT = 56, - POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN = 57, - POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX = 58, - POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW = 59, - POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG = 60, - POWER_SUPPLY_PROP_TIME_TO_FULL_NOW = 61, - POWER_SUPPLY_PROP_TIME_TO_FULL_AVG = 62, - POWER_SUPPLY_PROP_TYPE = 63, - POWER_SUPPLY_PROP_USB_TYPE = 64, - POWER_SUPPLY_PROP_SCOPE = 65, - POWER_SUPPLY_PROP_PRECHARGE_CURRENT = 66, - POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT = 67, - POWER_SUPPLY_PROP_CALIBRATE = 68, - POWER_SUPPLY_PROP_MANUFACTURE_YEAR = 69, - POWER_SUPPLY_PROP_MANUFACTURE_MONTH = 70, - POWER_SUPPLY_PROP_MANUFACTURE_DAY = 71, - POWER_SUPPLY_PROP_MODEL_NAME = 72, - POWER_SUPPLY_PROP_MANUFACTURER = 73, - POWER_SUPPLY_PROP_SERIAL_NUMBER = 74, -}; - -enum power_supply_type { - POWER_SUPPLY_TYPE_UNKNOWN = 0, - POWER_SUPPLY_TYPE_BATTERY = 1, - POWER_SUPPLY_TYPE_UPS = 2, - POWER_SUPPLY_TYPE_MAINS = 3, - POWER_SUPPLY_TYPE_USB = 4, - POWER_SUPPLY_TYPE_USB_DCP = 5, - POWER_SUPPLY_TYPE_USB_CDP = 6, - POWER_SUPPLY_TYPE_USB_ACA = 7, - POWER_SUPPLY_TYPE_USB_TYPE_C = 8, - POWER_SUPPLY_TYPE_USB_PD = 9, - POWER_SUPPLY_TYPE_USB_PD_DRP = 10, - POWER_SUPPLY_TYPE_APPLE_BRICK_ID = 11, - POWER_SUPPLY_TYPE_WIRELESS = 12, -}; - -enum power_supply_usb_type { - POWER_SUPPLY_USB_TYPE_UNKNOWN = 0, - POWER_SUPPLY_USB_TYPE_SDP = 1, - POWER_SUPPLY_USB_TYPE_DCP = 2, - POWER_SUPPLY_USB_TYPE_CDP = 3, - POWER_SUPPLY_USB_TYPE_ACA = 4, - POWER_SUPPLY_USB_TYPE_C = 5, - POWER_SUPPLY_USB_TYPE_PD = 6, - POWER_SUPPLY_USB_TYPE_PD_DRP = 7, - POWER_SUPPLY_USB_TYPE_PD_PPS = 8, - POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID = 9, -}; - -union power_supply_propval { - int intval; - const char *strval; -}; - -struct power_supply_config { - struct device_node *of_node; - struct fwnode_handle *fwnode; - void *drv_data; - const struct attribute_group **attr_grp; - char **supplied_to; - size_t num_supplicants; -}; - -struct power_supply; - -struct power_supply_desc { - const char *name; - enum power_supply_type type; - const enum power_supply_usb_type *usb_types; - size_t num_usb_types; - const enum power_supply_property *properties; - size_t num_properties; - int (*get_property)(struct power_supply *, enum power_supply_property, union power_supply_propval *); - int (*set_property)(struct power_supply *, enum power_supply_property, const union power_supply_propval *); - int (*property_is_writeable)(struct power_supply *, enum power_supply_property); - void (*external_power_changed)(struct power_supply *); - void (*set_charged)(struct power_supply *); - bool no_thermal; - int use_for_apm; -}; - -struct thermal_zone_device; - -struct power_supply { - const struct power_supply_desc *desc; - char **supplied_to; - size_t num_supplicants; - char **supplied_from; - size_t num_supplies; - struct device_node *of_node; - void *drv_data; - struct device dev; - struct work_struct changed_work; - struct delayed_work deferred_register_work; - spinlock_t changed_lock; - bool changed; - bool initialized; - bool removing; - atomic_t use_cnt; - struct thermal_zone_device *tzd; - struct thermal_cooling_device *tcd; - struct led_trigger *charging_full_trig; - char *charging_full_trig_name; - struct led_trigger *charging_trig; - char *charging_trig_name; - struct led_trigger *full_trig; - char *full_trig_name; - struct led_trigger *online_trig; - char *online_trig_name; - struct led_trigger *charging_blink_full_solid_trig; - char *charging_blink_full_solid_trig_name; -}; - -struct acpi_ac_bl { - const char *hid; - int hrv; -}; - -struct acpi_ac { - struct power_supply *charger; - struct power_supply_desc charger_desc; - struct acpi_device *device; - long long unsigned int state; - struct notifier_block battery_nb; -}; - -struct input_id { - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; -}; - -struct input_absinfo { - __s32 value; - __s32 minimum; - __s32 maximum; - __s32 fuzz; - __s32 flat; - __s32 resolution; -}; - -struct input_keymap_entry { - __u8 flags; - __u8 len; - __u16 index; - __u32 keycode; - __u8 scancode[32]; -}; - -struct ff_replay { - __u16 length; - __u16 delay; -}; - -struct ff_trigger { - __u16 button; - __u16 interval; -}; - -struct ff_envelope { - __u16 attack_length; - __u16 attack_level; - __u16 fade_length; - __u16 fade_level; -}; - -struct ff_constant_effect { - __s16 level; - struct ff_envelope envelope; -}; - -struct ff_ramp_effect { - __s16 start_level; - __s16 end_level; - struct ff_envelope envelope; -}; - -struct ff_condition_effect { - __u16 right_saturation; - __u16 left_saturation; - __s16 right_coeff; - __s16 left_coeff; - __u16 deadband; - __s16 center; -}; - -struct ff_periodic_effect { - __u16 waveform; - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; - struct ff_envelope envelope; - __u32 custom_len; - __s16 *custom_data; -}; - -struct ff_rumble_effect { - __u16 strong_magnitude; - __u16 weak_magnitude; -}; - -struct ff_effect { - __u16 type; - __s16 id; - __u16 direction; - struct ff_trigger trigger; - struct ff_replay replay; - union { - struct ff_constant_effect constant; - struct ff_ramp_effect ramp; - struct ff_periodic_effect periodic; - struct ff_condition_effect condition[2]; - struct ff_rumble_effect rumble; - } u; -}; - -struct input_device_id { - kernel_ulong_t flags; - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; - kernel_ulong_t evbit[1]; - kernel_ulong_t keybit[12]; - kernel_ulong_t relbit[1]; - kernel_ulong_t absbit[1]; - kernel_ulong_t mscbit[1]; - kernel_ulong_t ledbit[1]; - kernel_ulong_t sndbit[1]; - kernel_ulong_t ffbit[2]; - kernel_ulong_t swbit[1]; - kernel_ulong_t propbit[1]; - kernel_ulong_t driver_info; -}; - -struct input_value { - __u16 type; - __u16 code; - __s32 value; -}; - -enum input_clock_type { - INPUT_CLK_REAL = 0, - INPUT_CLK_MONO = 1, - INPUT_CLK_BOOT = 2, - INPUT_CLK_MAX = 3, -}; - -struct ff_device; - -struct input_dev_poller; - -struct input_mt; - -struct input_handle; - -struct input_dev { - const char *name; - const char *phys; - const char *uniq; - struct input_id id; - long unsigned int propbit[1]; - long unsigned int evbit[1]; - long unsigned int keybit[12]; - long unsigned int relbit[1]; - long unsigned int absbit[1]; - long unsigned int mscbit[1]; - long unsigned int ledbit[1]; - long unsigned int sndbit[1]; - long unsigned int ffbit[2]; - long unsigned int swbit[1]; - unsigned int hint_events_per_packet; - unsigned int keycodemax; - unsigned int keycodesize; - void *keycode; - int (*setkeycode)(struct input_dev *, const struct input_keymap_entry *, unsigned int *); - int (*getkeycode)(struct input_dev *, struct input_keymap_entry *); - struct ff_device *ff; - struct input_dev_poller *poller; - unsigned int repeat_key; - struct timer_list timer; - int rep[2]; - struct input_mt *mt; - struct input_absinfo *absinfo; - long unsigned int key[12]; - long unsigned int led[1]; - long unsigned int snd[1]; - long unsigned int sw[1]; - int (*open)(struct input_dev *); - void (*close)(struct input_dev *); - int (*flush)(struct input_dev *, struct file *); - int (*event)(struct input_dev *, unsigned int, unsigned int, int); - struct input_handle *grab; - spinlock_t event_lock; - struct mutex mutex; - unsigned int users; - bool going_away; - struct device dev; - struct list_head h_list; - struct list_head node; - unsigned int num_vals; - unsigned int max_vals; - struct input_value *vals; - bool devres_managed; - ktime_t timestamp[3]; - bool inhibited; -}; - -struct ff_device { - int (*upload)(struct input_dev *, struct ff_effect *, struct ff_effect *); - int (*erase)(struct input_dev *, int); - int (*playback)(struct input_dev *, int, int); - void (*set_gain)(struct input_dev *, u16); - void (*set_autocenter)(struct input_dev *, u16); - void (*destroy)(struct ff_device *); - void *private; - long unsigned int ffbit[2]; - struct mutex mutex; - int max_effects; - struct ff_effect *effects; - struct file *effect_owners[0]; -}; - -struct input_handler; - -struct input_handle { - void *private; - int open; - const char *name; - struct input_dev *dev; - struct input_handler *handler; - struct list_head d_node; - struct list_head h_node; -}; - -struct input_handler { - void *private; - void (*event)(struct input_handle *, unsigned int, unsigned int, int); - void (*events)(struct input_handle *, const struct input_value *, unsigned int); - bool (*filter)(struct input_handle *, unsigned int, unsigned int, int); - bool (*match)(struct input_handler *, struct input_dev *); - int (*connect)(struct input_handler *, struct input_dev *, const struct input_device_id *); - void (*disconnect)(struct input_handle *); - void (*start)(struct input_handle *); - bool legacy_minors; - int minor; - const char *name; - const struct input_device_id *id_table; - struct list_head h_list; - struct list_head node; -}; - -enum { - ACPI_BUTTON_LID_INIT_IGNORE = 0, - ACPI_BUTTON_LID_INIT_OPEN = 1, - ACPI_BUTTON_LID_INIT_METHOD = 2, - ACPI_BUTTON_LID_INIT_DISABLED = 3, -}; - -struct acpi_button { - unsigned int type; - struct input_dev *input; - char phys[32]; - long unsigned int pushed; - int last_state; - ktime_t last_time; - bool suspended; - bool lid_state_initialized; -}; - -struct acpi_fan_fps { - u64 control; - u64 trip_point; - u64 speed; - u64 noise_level; - u64 power; - char name[20]; - struct device_attribute dev_attr; -}; - -struct acpi_fan_fif { - u64 revision; - u64 fine_grain_ctrl; - u64 step_size; - u64 low_speed_notification; -}; - -struct acpi_fan { - bool acpi4; - struct acpi_fan_fif fif; - struct acpi_fan_fps *fps; - int fps_count; - struct thermal_cooling_device *cdev; -}; - -struct acpi_pci_slot { - struct pci_slot *pci_slot; - struct list_head list; -}; - -struct acpi_lpi_states_array { - unsigned int size; - unsigned int composite_states_size; - struct acpi_lpi_state *entries; - struct acpi_lpi_state *composite_states[8]; -}; - -struct throttling_tstate { - unsigned int cpu; - int target_state; -}; - -struct acpi_processor_throttling_arg { - struct acpi_processor *pr; - int target_state; - bool force; -}; - -struct container_dev { - struct device dev; - int (*offline)(struct container_dev *); -}; - -enum thermal_device_mode { - THERMAL_DEVICE_DISABLED = 0, - THERMAL_DEVICE_ENABLED = 1, -}; - -enum thermal_trip_type { - THERMAL_TRIP_ACTIVE = 0, - THERMAL_TRIP_PASSIVE = 1, - THERMAL_TRIP_HOT = 2, - THERMAL_TRIP_CRITICAL = 3, -}; - -enum thermal_trend { - THERMAL_TREND_STABLE = 0, - THERMAL_TREND_RAISING = 1, - THERMAL_TREND_DROPPING = 2, - THERMAL_TREND_RAISE_FULL = 3, - THERMAL_TREND_DROP_FULL = 4, -}; - -enum thermal_notify_event { - THERMAL_EVENT_UNSPECIFIED = 0, - THERMAL_EVENT_TEMP_SAMPLE = 1, - THERMAL_TRIP_VIOLATED = 2, - THERMAL_TRIP_CHANGED = 3, - THERMAL_DEVICE_DOWN = 4, - THERMAL_DEVICE_UP = 5, - THERMAL_DEVICE_POWER_CAPABILITY_CHANGED = 6, - THERMAL_TABLE_CHANGED = 7, - THERMAL_EVENT_KEEP_ALIVE = 8, -}; - -struct thermal_zone_device_ops { - int (*bind)(struct thermal_zone_device *, struct thermal_cooling_device *); - int (*unbind)(struct thermal_zone_device *, struct thermal_cooling_device *); - int (*get_temp)(struct thermal_zone_device *, int *); - int (*set_trips)(struct thermal_zone_device *, int, int); - int (*change_mode)(struct thermal_zone_device *, enum thermal_device_mode); - int (*get_trip_type)(struct thermal_zone_device *, int, enum thermal_trip_type *); - int (*get_trip_temp)(struct thermal_zone_device *, int, int *); - int (*set_trip_temp)(struct thermal_zone_device *, int, int); - int (*get_trip_hyst)(struct thermal_zone_device *, int, int *); - int (*set_trip_hyst)(struct thermal_zone_device *, int, int); - int (*get_crit_temp)(struct thermal_zone_device *, int *); - int (*set_emul_temp)(struct thermal_zone_device *, int); - int (*get_trend)(struct thermal_zone_device *, int, enum thermal_trend *); - void (*hot)(struct thermal_zone_device *); - void (*critical)(struct thermal_zone_device *); -}; - -struct thermal_attr; - -struct thermal_zone_params; - -struct thermal_governor; - -struct thermal_zone_device { - int id; - char type[20]; - struct device device; - struct attribute_group trips_attribute_group; - struct thermal_attr *trip_temp_attrs; - struct thermal_attr *trip_type_attrs; - struct thermal_attr *trip_hyst_attrs; - enum thermal_device_mode mode; - void *devdata; - int trips; - long unsigned int trips_disabled; - long unsigned int passive_delay_jiffies; - long unsigned int polling_delay_jiffies; - int temperature; - int last_temperature; - int emul_temperature; - int passive; - int prev_low_trip; - int prev_high_trip; - atomic_t need_update; - struct thermal_zone_device_ops *ops; - struct thermal_zone_params *tzp; - struct thermal_governor *governor; - void *governor_data; - struct list_head thermal_instances; - struct ida ida; - struct mutex lock; - struct list_head node; - struct delayed_work poll_queue; - enum thermal_notify_event notify_event; -}; - -struct thermal_bind_params; - -struct thermal_zone_params { - char governor_name[20]; - bool no_hwmon; - int num_tbps; - struct thermal_bind_params *tbp; - u32 sustainable_power; - s32 k_po; - s32 k_pu; - s32 k_i; - s32 k_d; - s32 integral_cutoff; - int slope; - int offset; -}; - -struct thermal_governor { - char name[20]; - int (*bind_to_tz)(struct thermal_zone_device *); - void (*unbind_from_tz)(struct thermal_zone_device *); - int (*throttle)(struct thermal_zone_device *, int); - struct list_head governor_list; -}; - -struct thermal_bind_params { - struct thermal_cooling_device *cdev; - int weight; - int trip_mask; - long unsigned int *binding_limits; - int (*match)(struct thermal_zone_device *, struct thermal_cooling_device *); -}; - -struct acpi_thermal_state { - u8 critical: 1; - u8 hot: 1; - u8 passive: 1; - u8 active: 1; - u8 reserved: 4; - int active_index; -}; - -struct acpi_thermal_state_flags { - u8 valid: 1; - u8 enabled: 1; - u8 reserved: 6; -}; - -struct acpi_thermal_critical { - struct acpi_thermal_state_flags flags; - long unsigned int temperature; -}; - -struct acpi_thermal_hot { - struct acpi_thermal_state_flags flags; - long unsigned int temperature; -}; - -struct acpi_thermal_passive { - struct acpi_thermal_state_flags flags; - long unsigned int temperature; - long unsigned int tc1; - long unsigned int tc2; - long unsigned int tsp; - struct acpi_handle_list devices; -}; - -struct acpi_thermal_active { - struct acpi_thermal_state_flags flags; - long unsigned int temperature; - struct acpi_handle_list devices; -}; - -struct acpi_thermal_trips { - struct acpi_thermal_critical critical; - struct acpi_thermal_hot hot; - struct acpi_thermal_passive passive; - struct acpi_thermal_active active[10]; -}; - -struct acpi_thermal_flags { - u8 cooling_mode: 1; - u8 devices: 1; - u8 reserved: 6; -}; - -struct acpi_thermal { - struct acpi_device *device; - acpi_bus_id name; - long unsigned int temperature; - long unsigned int last_temperature; - long unsigned int polling_frequency; - volatile u8 zombie; - struct acpi_thermal_flags flags; - struct acpi_thermal_state state; - struct acpi_thermal_trips trips; - struct acpi_handle_list devices; - struct thermal_zone_device *thermal_zone; - int kelvin_offset; - struct work_struct thermal_check_work; - struct mutex thermal_check_lock; - refcount_t thermal_check_count; -}; - -struct acpi_table_slit { - struct acpi_table_header header; - u64 locality_count; - u8 entry[1]; -} __attribute__((packed)); - -struct acpi_table_srat { - struct acpi_table_header header; - u32 table_revision; - u64 reserved; -}; - -enum acpi_srat_type { - ACPI_SRAT_TYPE_CPU_AFFINITY = 0, - ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1, - ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2, - ACPI_SRAT_TYPE_GICC_AFFINITY = 3, - ACPI_SRAT_TYPE_GIC_ITS_AFFINITY = 4, - ACPI_SRAT_TYPE_GENERIC_AFFINITY = 5, - ACPI_SRAT_TYPE_RESERVED = 6, -}; - -struct acpi_srat_mem_affinity { - struct acpi_subtable_header header; - u32 proximity_domain; - u16 reserved; - u64 base_address; - u64 length; - u32 reserved1; - u32 flags; - u64 reserved2; -} __attribute__((packed)); - -struct acpi_srat_gicc_affinity { - struct acpi_subtable_header header; - u32 proximity_domain; - u32 acpi_processor_uid; - u32 flags; - u32 clock_domain; -} __attribute__((packed)); - -struct acpi_srat_generic_affinity { - struct acpi_subtable_header header; - u8 reserved; - u8 device_handle_type; - u32 proximity_domain; - u8 device_handle[16]; - u32 flags; - u32 reserved1; -}; - -enum acpi_hmat_type { - ACPI_HMAT_TYPE_PROXIMITY = 0, - ACPI_HMAT_TYPE_LOCALITY = 1, - ACPI_HMAT_TYPE_CACHE = 2, - ACPI_HMAT_TYPE_RESERVED = 3, -}; - -struct acpi_hmat_proximity_domain { - struct acpi_hmat_structure header; - u16 flags; - u16 reserved1; - u32 processor_PD; - u32 memory_PD; - u32 reserved2; - u64 reserved3; - u64 reserved4; -}; - -struct acpi_hmat_locality { - struct acpi_hmat_structure header; - u8 flags; - u8 data_type; - u8 min_transfer_size; - u8 reserved1; - u32 number_of_initiator_Pds; - u32 number_of_target_Pds; - u32 reserved2; - u64 entry_base_unit; -}; - -struct acpi_hmat_cache { - struct acpi_hmat_structure header; - u32 memory_PD; - u32 reserved1; - u64 cache_size; - u32 cache_attributes; - u16 reserved2; - u16 number_of_SMBIOShandles; -}; - -struct node_hmem_attrs { - unsigned int read_bandwidth; - unsigned int write_bandwidth; - unsigned int read_latency; - unsigned int write_latency; -}; - -enum cache_indexing { - NODE_CACHE_DIRECT_MAP = 0, - NODE_CACHE_INDEXED = 1, - NODE_CACHE_OTHER = 2, -}; - -enum cache_write_policy { - NODE_CACHE_WRITE_BACK = 0, - NODE_CACHE_WRITE_THROUGH = 1, - NODE_CACHE_WRITE_OTHER = 2, -}; - -struct node_cache_attrs { - enum cache_indexing indexing; - enum cache_write_policy write_policy; - u64 size; - u16 line_size; - u8 level; -}; - -enum locality_types { - WRITE_LATENCY = 0, - READ_LATENCY = 1, - WRITE_BANDWIDTH = 2, - READ_BANDWIDTH = 3, -}; - -struct memory_locality { - struct list_head node; - struct acpi_hmat_locality *hmat_loc; -}; - -struct target_cache { - struct list_head node; - struct node_cache_attrs cache_attrs; -}; - -struct memory_target { - struct list_head node; - unsigned int memory_pxm; - unsigned int processor_pxm; - struct resource memregions; - struct node_hmem_attrs hmem_attrs[2]; - struct list_head caches; - struct node_cache_attrs cache_attrs; - bool registered; -}; - -struct memory_initiator { - struct list_head node; - unsigned int processor_pxm; - bool has_cpu; -}; - -struct acpi_memory_info { - struct list_head list; - u64 start_addr; - u64 length; - short unsigned int caching; - short unsigned int write_protect; - unsigned int enabled: 1; -}; - -struct acpi_memory_device { - struct acpi_device *device; - struct list_head res_list; -}; - -struct acpi_pci_ioapic { - acpi_handle root_handle; - acpi_handle handle; - u32 gsi_base; - struct resource res; - struct pci_dev *pdev; - struct list_head list; -}; - -enum dmi_entry_type { - DMI_ENTRY_BIOS = 0, - DMI_ENTRY_SYSTEM = 1, - DMI_ENTRY_BASEBOARD = 2, - DMI_ENTRY_CHASSIS = 3, - DMI_ENTRY_PROCESSOR = 4, - DMI_ENTRY_MEM_CONTROLLER = 5, - DMI_ENTRY_MEM_MODULE = 6, - DMI_ENTRY_CACHE = 7, - DMI_ENTRY_PORT_CONNECTOR = 8, - DMI_ENTRY_SYSTEM_SLOT = 9, - DMI_ENTRY_ONBOARD_DEVICE = 10, - DMI_ENTRY_OEMSTRINGS = 11, - DMI_ENTRY_SYSCONF = 12, - DMI_ENTRY_BIOS_LANG = 13, - DMI_ENTRY_GROUP_ASSOC = 14, - DMI_ENTRY_SYSTEM_EVENT_LOG = 15, - DMI_ENTRY_PHYS_MEM_ARRAY = 16, - DMI_ENTRY_MEM_DEVICE = 17, - DMI_ENTRY_32_MEM_ERROR = 18, - DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR = 19, - DMI_ENTRY_MEM_DEV_MAPPED_ADDR = 20, - DMI_ENTRY_BUILTIN_POINTING_DEV = 21, - DMI_ENTRY_PORTABLE_BATTERY = 22, - DMI_ENTRY_SYSTEM_RESET = 23, - DMI_ENTRY_HW_SECURITY = 24, - DMI_ENTRY_SYSTEM_POWER_CONTROLS = 25, - DMI_ENTRY_VOLTAGE_PROBE = 26, - DMI_ENTRY_COOLING_DEV = 27, - DMI_ENTRY_TEMP_PROBE = 28, - DMI_ENTRY_ELECTRICAL_CURRENT_PROBE = 29, - DMI_ENTRY_OOB_REMOTE_ACCESS = 30, - DMI_ENTRY_BIS_ENTRY = 31, - DMI_ENTRY_SYSTEM_BOOT = 32, - DMI_ENTRY_MGMT_DEV = 33, - DMI_ENTRY_MGMT_DEV_COMPONENT = 34, - DMI_ENTRY_MGMT_DEV_THRES = 35, - DMI_ENTRY_MEM_CHANNEL = 36, - DMI_ENTRY_IPMI_DEV = 37, - DMI_ENTRY_SYS_POWER_SUPPLY = 38, - DMI_ENTRY_ADDITIONAL = 39, - DMI_ENTRY_ONBOARD_DEV_EXT = 40, - DMI_ENTRY_MGMT_CONTROLLER_HOST = 41, - DMI_ENTRY_INACTIVE = 126, - DMI_ENTRY_END_OF_TABLE = 127, -}; - -enum { - POWER_SUPPLY_STATUS_UNKNOWN = 0, - POWER_SUPPLY_STATUS_CHARGING = 1, - POWER_SUPPLY_STATUS_DISCHARGING = 2, - POWER_SUPPLY_STATUS_NOT_CHARGING = 3, - POWER_SUPPLY_STATUS_FULL = 4, -}; - -enum { - POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0, - POWER_SUPPLY_TECHNOLOGY_NiMH = 1, - POWER_SUPPLY_TECHNOLOGY_LION = 2, - POWER_SUPPLY_TECHNOLOGY_LIPO = 3, - POWER_SUPPLY_TECHNOLOGY_LiFe = 4, - POWER_SUPPLY_TECHNOLOGY_NiCd = 5, - POWER_SUPPLY_TECHNOLOGY_LiMn = 6, -}; - -enum { - POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0, - POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL = 1, - POWER_SUPPLY_CAPACITY_LEVEL_LOW = 2, - POWER_SUPPLY_CAPACITY_LEVEL_NORMAL = 3, - POWER_SUPPLY_CAPACITY_LEVEL_HIGH = 4, - POWER_SUPPLY_CAPACITY_LEVEL_FULL = 5, -}; - -struct acpi_battery_hook { - const char *name; - int (*add_battery)(struct power_supply *); - int (*remove_battery)(struct power_supply *); - struct list_head list; -}; - -enum { - ACPI_BATTERY_ALARM_PRESENT = 0, - ACPI_BATTERY_XINFO_PRESENT = 1, - ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY = 2, - ACPI_BATTERY_QUIRK_THINKPAD_MAH = 3, - ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE = 4, -}; - -struct acpi_battery { - struct mutex lock; - struct mutex sysfs_lock; - struct power_supply *bat; - struct power_supply_desc bat_desc; - struct acpi_device *device; - struct notifier_block pm_nb; - struct list_head list; - long unsigned int update_time; - int revision; - int rate_now; - int capacity_now; - int voltage_now; - int design_capacity; - int full_charge_capacity; - int technology; - int design_voltage; - int design_capacity_warning; - int design_capacity_low; - int cycle_count; - int measurement_accuracy; - int max_sampling_time; - int min_sampling_time; - int max_averaging_interval; - int min_averaging_interval; - int capacity_granularity_1; - int capacity_granularity_2; - int alarm; - char model_number[32]; - char serial_number[32]; - char type[32]; - char oem_info[32]; - int state; - int power_unit; - long unsigned int flags; -}; - -struct acpi_offsets { - size_t offset; - u8 mode; -}; - -struct acpi_pcct_hw_reduced { - struct acpi_subtable_header header; - u32 platform_interrupt; - u8 flags; - u8 reserved; - u64 base_address; - u64 length; - struct acpi_generic_address doorbell_register; - u64 preserve_mask; - u64 write_mask; - u32 latency; - u32 max_access_rate; - u16 min_turnaround_time; -} __attribute__((packed)); - -struct acpi_pcct_shared_memory { - u32 signature; - u16 command; - u16 status; -}; - -struct mbox_chan; - -struct mbox_chan_ops { - int (*send_data)(struct mbox_chan *, void *); - int (*flush)(struct mbox_chan *, long unsigned int); - int (*startup)(struct mbox_chan *); - void (*shutdown)(struct mbox_chan *); - bool (*last_tx_done)(struct mbox_chan *); - bool (*peek_data)(struct mbox_chan *); -}; - -struct mbox_controller; - -struct mbox_client; - -struct mbox_chan { - struct mbox_controller *mbox; - unsigned int txdone_method; - struct mbox_client *cl; - struct completion tx_complete; - void *active_req; - unsigned int msg_count; - unsigned int msg_free; - void *msg_data[20]; - spinlock_t lock; - void *con_priv; -}; - -struct mbox_controller { - struct device *dev; - const struct mbox_chan_ops *ops; - struct mbox_chan *chans; - int num_chans; - bool txdone_irq; - bool txdone_poll; - unsigned int txpoll_period; - struct mbox_chan * (*of_xlate)(struct mbox_controller *, const struct of_phandle_args *); - struct hrtimer poll_hrt; - struct list_head node; -}; - -struct mbox_client { - struct device *dev; - bool tx_block; - long unsigned int tx_tout; - bool knows_txdone; - void (*rx_callback)(struct mbox_client *, void *); - void (*tx_prepare)(struct mbox_client *, void *); - void (*tx_done)(struct mbox_client *, void *, int); -}; - -struct cpc_register_resource { - acpi_object_type type; - u64 *sys_mem_vaddr; - union { - struct cpc_reg reg; - u64 int_value; - } cpc_entry; -}; - -struct cpc_desc { - int num_entries; - int version; - int cpu_id; - int write_cmd_status; - int write_cmd_id; - struct cpc_register_resource cpc_regs[21]; - struct acpi_psd_package domain_info; - struct kobject kobj; -}; - -enum cppc_regs { - HIGHEST_PERF = 0, - NOMINAL_PERF = 1, - LOW_NON_LINEAR_PERF = 2, - LOWEST_PERF = 3, - GUARANTEED_PERF = 4, - DESIRED_PERF = 5, - MIN_PERF = 6, - MAX_PERF = 7, - PERF_REDUC_TOLERANCE = 8, - TIME_WINDOW = 9, - CTR_WRAP_TIME = 10, - REFERENCE_CTR = 11, - DELIVERED_CTR = 12, - PERF_LIMITED = 13, - ENABLE = 14, - AUTO_SEL_ENABLE = 15, - AUTO_ACT_WINDOW = 16, - ENERGY_PERF = 17, - REFERENCE_PERF = 18, - LOWEST_FREQ = 19, - NOMINAL_FREQ = 20, -}; - -struct cppc_perf_ctrls { - u32 max_perf; - u32 min_perf; - u32 desired_perf; -}; - -struct cppc_perf_fb_ctrs { - u64 reference; - u64 delivered; - u64 reference_perf; - u64 wraparound_time; -}; - -struct cppc_cpudata { - struct list_head node; - struct cppc_perf_caps perf_caps; - struct cppc_perf_ctrls perf_ctrls; - struct cppc_perf_fb_ctrs perf_fb_ctrs; - unsigned int shared_type; - cpumask_var_t shared_cpu_map; -}; - -struct cppc_pcc_data { - struct mbox_chan *pcc_channel; - void *pcc_comm_addr; - bool pcc_channel_acquired; - unsigned int deadline_us; - unsigned int pcc_mpar; - unsigned int pcc_mrtt; - unsigned int pcc_nominal; - bool pending_pcc_write_cmd; - bool platform_owns_pcc; - unsigned int pcc_write_cnt; - struct rw_semaphore pcc_lock; - wait_queue_head_t pcc_write_wait_q; - ktime_t last_cmd_cmpl_time; - ktime_t last_mpar_reset; - int mpar_count; - int refcount; -}; - -struct acpi_whea_header { - u8 action; - u8 instruction; - u8 flags; - u8 reserved; - struct acpi_generic_address register_region; - u64 value; - u64 mask; -} __attribute__((packed)); - -struct apei_exec_context; - -typedef int (*apei_exec_ins_func_t)(struct apei_exec_context *, struct acpi_whea_header *); - -struct apei_exec_ins_type; - -struct apei_exec_context { - u32 ip; - u64 value; - u64 var1; - u64 var2; - u64 src_base; - u64 dst_base; - struct apei_exec_ins_type *ins_table; - u32 instructions; - struct acpi_whea_header *action_table; - u32 entries; -}; - -struct apei_exec_ins_type { - u32 flags; - apei_exec_ins_func_t run; -}; - -struct apei_resources { - struct list_head iomem; - struct list_head ioport; -}; - -typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *, struct acpi_whea_header *, void *); - -struct apei_res { - struct list_head list; - long unsigned int start; - long unsigned int end; -}; - -struct acpi_table_hest { - struct acpi_table_header header; - u32 error_source_count; -}; - -enum acpi_hest_types { - ACPI_HEST_TYPE_IA32_CHECK = 0, - ACPI_HEST_TYPE_IA32_CORRECTED_CHECK = 1, - ACPI_HEST_TYPE_IA32_NMI = 2, - ACPI_HEST_TYPE_NOT_USED3 = 3, - ACPI_HEST_TYPE_NOT_USED4 = 4, - ACPI_HEST_TYPE_NOT_USED5 = 5, - ACPI_HEST_TYPE_AER_ROOT_PORT = 6, - ACPI_HEST_TYPE_AER_ENDPOINT = 7, - ACPI_HEST_TYPE_AER_BRIDGE = 8, - ACPI_HEST_TYPE_GENERIC_ERROR = 9, - ACPI_HEST_TYPE_GENERIC_ERROR_V2 = 10, - ACPI_HEST_TYPE_IA32_DEFERRED_CHECK = 11, - ACPI_HEST_TYPE_RESERVED = 12, -}; - -struct acpi_hest_ia_machine_check { - struct acpi_hest_header header; - u16 reserved1; - u8 flags; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - u64 global_capability_data; - u64 global_control_data; - u8 num_hardware_banks; - u8 reserved3[7]; -}; - -struct acpi_hest_generic { - struct acpi_hest_header header; - u16 related_source_id; - u8 reserved; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - u32 max_raw_data_length; - struct acpi_generic_address error_status_address; - struct acpi_hest_notify notify; - u32 error_block_length; -} __attribute__((packed)); - -struct acpi_hest_ia_deferred_check { - struct acpi_hest_header header; - u16 reserved1; - u8 flags; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - struct acpi_hest_notify notify; - u8 num_hardware_banks; - u8 reserved2[3]; -}; - -enum hest_status { - HEST_ENABLED = 0, - HEST_DISABLED = 1, - HEST_NOT_FOUND = 2, -}; - -typedef int (*apei_hest_func_t)(struct acpi_hest_header *, void *); - -struct ghes_arr { - struct platform_device **ghes_devs; - unsigned int count; -}; - -struct acpi_table_erst { - struct acpi_table_header header; - u32 header_length; - u32 reserved; - u32 entries; -}; - -enum acpi_erst_actions { - ACPI_ERST_BEGIN_WRITE = 0, - ACPI_ERST_BEGIN_READ = 1, - ACPI_ERST_BEGIN_CLEAR = 2, - ACPI_ERST_END = 3, - ACPI_ERST_SET_RECORD_OFFSET = 4, - ACPI_ERST_EXECUTE_OPERATION = 5, - ACPI_ERST_CHECK_BUSY_STATUS = 6, - ACPI_ERST_GET_COMMAND_STATUS = 7, - ACPI_ERST_GET_RECORD_ID = 8, - ACPI_ERST_SET_RECORD_ID = 9, - ACPI_ERST_GET_RECORD_COUNT = 10, - ACPI_ERST_BEGIN_DUMMY_WRIITE = 11, - ACPI_ERST_NOT_USED = 12, - ACPI_ERST_GET_ERROR_RANGE = 13, - ACPI_ERST_GET_ERROR_LENGTH = 14, - ACPI_ERST_GET_ERROR_ATTRIBUTES = 15, - ACPI_ERST_EXECUTE_TIMINGS = 16, - ACPI_ERST_ACTION_RESERVED = 17, -}; - -enum acpi_erst_instructions { - ACPI_ERST_READ_REGISTER = 0, - ACPI_ERST_READ_REGISTER_VALUE = 1, - ACPI_ERST_WRITE_REGISTER = 2, - ACPI_ERST_WRITE_REGISTER_VALUE = 3, - ACPI_ERST_NOOP = 4, - ACPI_ERST_LOAD_VAR1 = 5, - ACPI_ERST_LOAD_VAR2 = 6, - ACPI_ERST_STORE_VAR1 = 7, - ACPI_ERST_ADD = 8, - ACPI_ERST_SUBTRACT = 9, - ACPI_ERST_ADD_VALUE = 10, - ACPI_ERST_SUBTRACT_VALUE = 11, - ACPI_ERST_STALL = 12, - ACPI_ERST_STALL_WHILE_TRUE = 13, - ACPI_ERST_SKIP_NEXT_IF_TRUE = 14, - ACPI_ERST_GOTO = 15, - ACPI_ERST_SET_SRC_ADDRESS_BASE = 16, - ACPI_ERST_SET_DST_ADDRESS_BASE = 17, - ACPI_ERST_MOVE_DATA = 18, - ACPI_ERST_INSTRUCTION_RESERVED = 19, -}; - -struct erst_erange { - u64 base; - u64 size; - void *vaddr; - u32 attr; -}; - -struct erst_record_id_cache { - struct mutex lock; - u64 *entries; - int len; - int size; - int refcount; -}; - -struct cper_pstore_record { - struct cper_record_header hdr; - struct cper_section_descriptor sec_hdr; - char data[0]; -}; - -struct acpi_bert_region { - u32 block_status; - u32 raw_data_offset; - u32 raw_data_length; - u32 data_length; - u32 error_severity; -}; - -struct acpi_hest_generic_status { - u32 block_status; - u32 raw_data_offset; - u32 raw_data_length; - u32 data_length; - u32 error_severity; -}; - -enum acpi_hest_notify_types { - ACPI_HEST_NOTIFY_POLLED = 0, - ACPI_HEST_NOTIFY_EXTERNAL = 1, - ACPI_HEST_NOTIFY_LOCAL = 2, - ACPI_HEST_NOTIFY_SCI = 3, - ACPI_HEST_NOTIFY_NMI = 4, - ACPI_HEST_NOTIFY_CMCI = 5, - ACPI_HEST_NOTIFY_MCE = 6, - ACPI_HEST_NOTIFY_GPIO = 7, - ACPI_HEST_NOTIFY_SEA = 8, - ACPI_HEST_NOTIFY_SEI = 9, - ACPI_HEST_NOTIFY_GSIV = 10, - ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED = 11, - ACPI_HEST_NOTIFY_RESERVED = 12, -}; - -struct acpi_hest_generic_v2 { - struct acpi_hest_header header; - u16 related_source_id; - u8 reserved; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - u32 max_raw_data_length; - struct acpi_generic_address error_status_address; - struct acpi_hest_notify notify; - u32 error_block_length; - struct acpi_generic_address read_ack_register; - u64 read_ack_preserve; - u64 read_ack_write; -} __attribute__((packed)); - -struct acpi_hest_generic_data { - u8 section_type[16]; - u32 error_severity; - u16 revision; - u8 validation_bits; - u8 flags; - u32 error_data_length; - u8 fru_id[16]; - u8 fru_text[20]; -}; - -struct acpi_hest_generic_data_v300 { - u8 section_type[16]; - u32 error_severity; - u16 revision; - u8 validation_bits; - u8 flags; - u32 error_data_length; - u8 fru_id[16]; - u8 fru_text[20]; - u64 time_stamp; -}; - -struct cper_sec_proc_arm { - u32 validation_bits; - u16 err_info_num; - u16 context_info_num; - u32 section_length; - u8 affinity_level; - u8 reserved[3]; - u64 mpidr; - u64 midr; - u32 running_state; - u32 psci_state; -}; - -struct cper_arm_err_info { - u8 version; - u8 length; - u16 validation_bits; - u8 type; - u16 multiple_error; - u8 flags; - u64 error_info; - u64 virt_fault_addr; - u64 physical_fault_addr; -} __attribute__((packed)); - -struct cper_sec_pcie { - u64 validation_bits; - u32 port_type; - struct { - u8 minor; - u8 major; - u8 reserved[2]; - } version; - u16 command; - u16 status; - u32 reserved; - struct { - u16 vendor_id; - u16 device_id; - u8 class_code[3]; - u8 function; - u8 device; - u16 segment; - u8 bus; - u8 secondary_bus; - u16 slot; - u8 reserved; - } __attribute__((packed)) device_id; - struct { - u32 lower; - u32 upper; - } serial_number; - struct { - u16 secondary_status; - u16 control; - } bridge; - u8 capability[60]; - u8 aer_info[96]; -}; - -struct ghes { - union { - struct acpi_hest_generic *generic; - struct acpi_hest_generic_v2 *generic_v2; - }; - struct acpi_hest_generic_status *estatus; - long unsigned int flags; - union { - struct list_head list; - struct timer_list timer; - unsigned int irq; - }; -}; - -struct ghes_estatus_node { - struct llist_node llnode; - struct acpi_hest_generic *generic; - struct ghes *ghes; - int task_work_cpu; - struct callback_head task_work; -}; - -struct ghes_estatus_cache { - u32 estatus_len; - atomic_t count; - struct acpi_hest_generic *generic; - long long unsigned int time_in; - struct callback_head rcu; -}; - -struct ghes_vendor_record_entry { - struct work_struct work; - int error_severity; - char vendor_record[0]; -}; - -struct pmic_table { - int address; - int reg; - int bit; -}; - -struct intel_pmic_opregion_data { - int (*get_power)(struct regmap *, int, int, u64 *); - int (*update_power)(struct regmap *, int, int, bool); - int (*get_raw_temp)(struct regmap *, int); - int (*update_aux)(struct regmap *, int, int); - int (*get_policy)(struct regmap *, int, int, u64 *); - int (*update_policy)(struct regmap *, int, int, int); - int (*exec_mipi_pmic_seq_element)(struct regmap *, u16, u32, u32, u32); - struct pmic_table *power_table; - int power_table_count; - struct pmic_table *thermal_table; - int thermal_table_count; - int pmic_i2c_address; -}; - -struct intel_pmic_regs_handler_ctx { - unsigned int val; - u16 addr; -}; - -struct intel_pmic_opregion { - struct mutex lock; - struct acpi_lpat_conversion_table *lpat_table; - struct regmap *regmap; - struct intel_pmic_opregion_data *data; - struct intel_pmic_regs_handler_ctx ctx; -}; - -struct regmap_irq_type { - unsigned int type_reg_offset; - unsigned int type_reg_mask; - unsigned int type_rising_val; - unsigned int type_falling_val; - unsigned int type_level_low_val; - unsigned int type_level_high_val; - unsigned int types_supported; -}; - -struct regmap_irq { - unsigned int reg_offset; - unsigned int mask; - struct regmap_irq_type type; -}; - -struct regmap_irq_sub_irq_map { - unsigned int num_regs; - unsigned int *offset; -}; - -struct regmap_irq_chip { - const char *name; - unsigned int main_status; - unsigned int num_main_status_bits; - struct regmap_irq_sub_irq_map *sub_reg_offsets; - int num_main_regs; - unsigned int status_base; - unsigned int mask_base; - unsigned int unmask_base; - unsigned int ack_base; - unsigned int wake_base; - unsigned int type_base; - unsigned int *virt_reg_base; - unsigned int irq_reg_stride; - bool mask_writeonly: 1; - bool init_ack_masked: 1; - bool mask_invert: 1; - bool use_ack: 1; - bool ack_invert: 1; - bool clear_ack: 1; - bool wake_invert: 1; - bool runtime_pm: 1; - bool type_invert: 1; - bool type_in_mask: 1; - bool clear_on_unmask: 1; - bool not_fixed_stride: 1; - bool status_invert: 1; - int num_regs; - const struct regmap_irq *irqs; - int num_irqs; - int num_type_reg; - int num_virt_regs; - unsigned int type_reg_stride; - int (*handle_pre_irq)(void *); - int (*handle_post_irq)(void *); - int (*set_type_virt)(unsigned int **, unsigned int, long unsigned int, int); - void *irq_drv_data; -}; - -struct axp20x_dev { - struct device *dev; - int irq; - long unsigned int irq_flags; - struct regmap *regmap; - struct regmap_irq_chip_data *regmap_irqc; - long int variant; - int nr_cells; - const struct mfd_cell *cells; - const struct regmap_config *regmap_cfg; - const struct regmap_irq_chip *regmap_irq_chip; -}; - -struct mfd_cell_acpi_match; - -struct mfd_cell { - const char *name; - int id; - int level; - int (*enable)(struct platform_device *); - int (*disable)(struct platform_device *); - int (*suspend)(struct platform_device *); - int (*resume)(struct platform_device *); - void *platform_data; - size_t pdata_size; - const struct software_node *swnode; - const char *of_compatible; - const u64 of_reg; - bool use_of_reg; - const struct mfd_cell_acpi_match *acpi_match; - int num_resources; - const struct resource *resources; - bool ignore_resource_conflicts; - bool pm_runtime_no_callbacks; - const char * const *parent_supplies; - int num_parent_supplies; -}; - -struct tps68470_pmic_table { - u32 address; - u32 reg; - u32 bitmask; -}; - -struct tps68470_pmic_opregion { - struct mutex lock; - struct regmap *regmap; -}; - -struct acpi_table_viot { - struct acpi_table_header header; - u16 node_count; - u16 node_offset; - u8 reserved[8]; -}; - -struct acpi_viot_header { - u8 type; - u8 reserved; - u16 length; -}; - -enum acpi_viot_node_type { - ACPI_VIOT_NODE_PCI_RANGE = 1, - ACPI_VIOT_NODE_MMIO = 2, - ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI = 3, - ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO = 4, - ACPI_VIOT_RESERVED = 5, -}; - -struct acpi_viot_pci_range { - struct acpi_viot_header header; - u32 endpoint_start; - u16 segment_start; - u16 segment_end; - u16 bdf_start; - u16 bdf_end; - u16 output_node; - u8 reserved[6]; -}; - -struct acpi_viot_mmio { - struct acpi_viot_header header; - u32 endpoint; - u64 base_address; - u16 output_node; - u8 reserved[6]; -}; - -struct acpi_viot_virtio_iommu_pci { - struct acpi_viot_header header; - u16 segment; - u16 bdf; - u8 reserved[8]; -}; - -struct acpi_viot_virtio_iommu_mmio { - struct acpi_viot_header header; - u8 reserved[4]; - u64 base_address; -}; - -struct viot_iommu { - unsigned int offset; - struct fwnode_handle *fwnode; - struct list_head list; -}; - -struct viot_endpoint { - union { - struct { - u16 segment_start; - u16 segment_end; - u16 bdf_start; - u16 bdf_end; - }; - u64 address; - }; - u32 endpoint_id; - struct viot_iommu *viommu; - struct list_head list; -}; - -struct pnp_resource { - struct list_head list; - struct resource res; -}; - -struct pnp_port { - resource_size_t min; - resource_size_t max; - resource_size_t align; - resource_size_t size; - unsigned char flags; -}; - -typedef struct { - long unsigned int bits[4]; -} pnp_irq_mask_t; - -struct pnp_irq { - pnp_irq_mask_t map; - unsigned char flags; -}; - -struct pnp_dma { - unsigned char map; - unsigned char flags; -}; - -struct pnp_mem { - resource_size_t min; - resource_size_t max; - resource_size_t align; - resource_size_t size; - unsigned char flags; -}; - -struct pnp_option { - struct list_head list; - unsigned int flags; - long unsigned int type; - union { - struct pnp_port port; - struct pnp_irq irq; - struct pnp_dma dma; - struct pnp_mem mem; - } u; -}; - -struct pnp_info_buffer { - char *buffer; - char *curr; - long unsigned int size; - long unsigned int len; - int stop; - int error; -}; - -typedef struct pnp_info_buffer pnp_info_buffer_t; - -struct pnp_fixup { - char id[7]; - void (*quirk_function)(struct pnp_dev *); -}; - -struct acpipnp_parse_option_s { - struct pnp_dev *dev; - unsigned int option_flags; -}; - -struct clk_bulk_data { - const char *id; - struct clk *clk; -}; - -struct clk_bulk_devres { - struct clk_bulk_data *clks; - int num_clks; -}; - -struct clk_hw; - -struct clk_lookup { - struct list_head node; - const char *dev_id; - const char *con_id; - struct clk *clk; - struct clk_hw *clk_hw; -}; - -struct clk_init_data; - -struct clk_hw { - struct clk_core *core; - struct clk *clk; - const struct clk_init_data *init; -}; - -struct clk_rate_request { - long unsigned int rate; - long unsigned int min_rate; - long unsigned int max_rate; - long unsigned int best_parent_rate; - struct clk_hw *best_parent_hw; -}; - -struct clk_duty { - unsigned int num; - unsigned int den; -}; - -struct clk_ops { - int (*prepare)(struct clk_hw *); - void (*unprepare)(struct clk_hw *); - int (*is_prepared)(struct clk_hw *); - void (*unprepare_unused)(struct clk_hw *); - int (*enable)(struct clk_hw *); - void (*disable)(struct clk_hw *); - int (*is_enabled)(struct clk_hw *); - void (*disable_unused)(struct clk_hw *); - int (*save_context)(struct clk_hw *); - void (*restore_context)(struct clk_hw *); - long unsigned int (*recalc_rate)(struct clk_hw *, long unsigned int); - long int (*round_rate)(struct clk_hw *, long unsigned int, long unsigned int *); - int (*determine_rate)(struct clk_hw *, struct clk_rate_request *); - int (*set_parent)(struct clk_hw *, u8); - u8 (*get_parent)(struct clk_hw *); - int (*set_rate)(struct clk_hw *, long unsigned int, long unsigned int); - int (*set_rate_and_parent)(struct clk_hw *, long unsigned int, long unsigned int, u8); - long unsigned int (*recalc_accuracy)(struct clk_hw *, long unsigned int); - int (*get_phase)(struct clk_hw *); - int (*set_phase)(struct clk_hw *, int); - int (*get_duty_cycle)(struct clk_hw *, struct clk_duty *); - int (*set_duty_cycle)(struct clk_hw *, struct clk_duty *); - int (*init)(struct clk_hw *); - void (*terminate)(struct clk_hw *); - void (*debug_init)(struct clk_hw *, struct dentry *); -}; - -struct clk_parent_data { - const struct clk_hw *hw; - const char *fw_name; - const char *name; - int index; -}; - -struct clk_init_data { - const char *name; - const struct clk_ops *ops; - const char * const *parent_names; - const struct clk_parent_data *parent_data; - const struct clk_hw **parent_hws; - u8 num_parents; - long unsigned int flags; -}; - -struct clk_lookup_alloc { - struct clk_lookup cl; - char dev_id[20]; - char con_id[16]; -}; - -struct clk_notifier { - struct clk *clk; - struct srcu_notifier_head notifier_head; - struct list_head node; -}; - -struct clk_notifier_data { - struct clk *clk; - long unsigned int old_rate; - long unsigned int new_rate; -}; - -struct clk_parent_map; - -struct clk_core { - const char *name; - const struct clk_ops *ops; - struct clk_hw *hw; - struct module *owner; - struct device *dev; - struct device_node *of_node; - struct clk_core *parent; - struct clk_parent_map *parents; - u8 num_parents; - u8 new_parent_index; - long unsigned int rate; - long unsigned int req_rate; - long unsigned int new_rate; - struct clk_core *new_parent; - struct clk_core *new_child; - long unsigned int flags; - bool orphan; - bool rpm_enabled; - unsigned int enable_count; - unsigned int prepare_count; - unsigned int protect_count; - long unsigned int min_rate; - long unsigned int max_rate; - long unsigned int accuracy; - int phase; - struct clk_duty duty; - struct hlist_head children; - struct hlist_node child_node; - struct hlist_head clks; - unsigned int notifier_count; - struct dentry *dentry; - struct hlist_node debug_node; - struct kref ref; -}; - -struct clk_parent_map { - const struct clk_hw *hw; - struct clk_core *core; - const char *fw_name; - const char *name; - int index; -}; - -struct trace_event_raw_clk { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_clk_rate { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int rate; - char __data[0]; -}; - -struct trace_event_raw_clk_rate_range { - struct trace_entry ent; - u32 __data_loc_name; - long unsigned int min; - long unsigned int max; - char __data[0]; -}; - -struct trace_event_raw_clk_parent { - struct trace_entry ent; - u32 __data_loc_name; - u32 __data_loc_pname; - char __data[0]; -}; - -struct trace_event_raw_clk_phase { - struct trace_entry ent; - u32 __data_loc_name; - int phase; - char __data[0]; -}; - -struct trace_event_raw_clk_duty_cycle { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int num; - unsigned int den; - char __data[0]; -}; - -struct trace_event_data_offsets_clk { - u32 name; -}; - -struct trace_event_data_offsets_clk_rate { - u32 name; -}; - -struct trace_event_data_offsets_clk_rate_range { - u32 name; -}; - -struct trace_event_data_offsets_clk_parent { - u32 name; - u32 pname; -}; - -struct trace_event_data_offsets_clk_phase { - u32 name; -}; - -struct trace_event_data_offsets_clk_duty_cycle { - u32 name; -}; - -typedef void (*btf_trace_clk_enable)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_enable_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_disable)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_disable_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_prepare)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_prepare_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_unprepare)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_unprepare_complete)(void *, struct clk_core *); - -typedef void (*btf_trace_clk_set_rate)(void *, struct clk_core *, long unsigned int); - -typedef void (*btf_trace_clk_set_rate_complete)(void *, struct clk_core *, long unsigned int); - -typedef void (*btf_trace_clk_set_min_rate)(void *, struct clk_core *, long unsigned int); - -typedef void (*btf_trace_clk_set_max_rate)(void *, struct clk_core *, long unsigned int); - -typedef void (*btf_trace_clk_set_rate_range)(void *, struct clk_core *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_clk_set_parent)(void *, struct clk_core *, struct clk_core *); - -typedef void (*btf_trace_clk_set_parent_complete)(void *, struct clk_core *, struct clk_core *); - -typedef void (*btf_trace_clk_set_phase)(void *, struct clk_core *, int); - -typedef void (*btf_trace_clk_set_phase_complete)(void *, struct clk_core *, int); - -typedef void (*btf_trace_clk_set_duty_cycle)(void *, struct clk_core *, struct clk_duty *); - -typedef void (*btf_trace_clk_set_duty_cycle_complete)(void *, struct clk_core *, struct clk_duty *); - -struct clk_notifier_devres { - struct clk *clk; - struct notifier_block *nb; -}; - -struct clk_div_table { - unsigned int val; - unsigned int div; -}; - -struct clk_divider { - struct clk_hw hw; - void *reg; - u8 shift; - u8 width; - u8 flags; - const struct clk_div_table *table; - spinlock_t *lock; -}; - -struct clk_fixed_factor { - struct clk_hw hw; - unsigned int mult; - unsigned int div; -}; - -struct clk_fixed_rate { - struct clk_hw hw; - long unsigned int fixed_rate; - long unsigned int fixed_accuracy; - long unsigned int flags; -}; - -struct clk_gate { - struct clk_hw hw; - void *reg; - u8 bit_idx; - u8 flags; - spinlock_t *lock; -}; - -struct clk_multiplier { - struct clk_hw hw; - void *reg; - u8 shift; - u8 width; - u8 flags; - spinlock_t *lock; -}; - -struct clk_mux { - struct clk_hw hw; - void *reg; - u32 *table; - u32 mask; - u8 shift; - u8 flags; - spinlock_t *lock; -}; - -struct clk_composite { - struct clk_hw hw; - struct clk_ops ops; - struct clk_hw *mux_hw; - struct clk_hw *rate_hw; - struct clk_hw *gate_hw; - const struct clk_ops *mux_ops; - const struct clk_ops *rate_ops; - const struct clk_ops *gate_ops; -}; - -struct clk_fractional_divider { - struct clk_hw hw; - void *reg; - u8 mshift; - u8 mwidth; - u32 mmask; - u8 nshift; - u8 nwidth; - u32 nmask; - u8 flags; - void (*approximation)(struct clk_hw *, long unsigned int, long unsigned int *, long unsigned int *, long unsigned int *); - spinlock_t *lock; -}; - -struct clk_gpio { - struct clk_hw hw; - struct gpio_desc *gpiod; -}; - -struct pmc_clk { - const char *name; - long unsigned int freq; - const char *parent_name; -}; - -struct pmc_clk_data { - void *base; - const struct pmc_clk *clks; - bool critical; -}; - -struct clk_plt_fixed { - struct clk_hw *clk; - struct clk_lookup *lookup; -}; - -struct clk_plt { - struct clk_hw hw; - void *reg; - struct clk_lookup *lookup; - spinlock_t lock; -}; - -struct clk_plt_data { - struct clk_plt_fixed **parents; - u8 nparents; - struct clk_plt *clks[6]; - struct clk_lookup *mclk_lookup; - struct clk_lookup *ether_clk_lookup; -}; - -typedef s32 dma_cookie_t; - -enum dma_status { - DMA_COMPLETE = 0, - DMA_IN_PROGRESS = 1, - DMA_PAUSED = 2, - DMA_ERROR = 3, - DMA_OUT_OF_ORDER = 4, -}; - -enum dma_transaction_type { - DMA_MEMCPY = 0, - DMA_XOR = 1, - DMA_PQ = 2, - DMA_XOR_VAL = 3, - DMA_PQ_VAL = 4, - DMA_MEMSET = 5, - DMA_MEMSET_SG = 6, - DMA_INTERRUPT = 7, - DMA_PRIVATE = 8, - DMA_ASYNC_TX = 9, - DMA_SLAVE = 10, - DMA_CYCLIC = 11, - DMA_INTERLEAVE = 12, - DMA_COMPLETION_NO_ORDER = 13, - DMA_REPEAT = 14, - DMA_LOAD_EOT = 15, - DMA_TX_TYPE_END = 16, -}; - -enum dma_transfer_direction { - DMA_MEM_TO_MEM = 0, - DMA_MEM_TO_DEV = 1, - DMA_DEV_TO_MEM = 2, - DMA_DEV_TO_DEV = 3, - DMA_TRANS_NONE = 4, -}; - -struct data_chunk { - size_t size; - size_t icg; - size_t dst_icg; - size_t src_icg; -}; - -struct dma_interleaved_template { - dma_addr_t src_start; - dma_addr_t dst_start; - enum dma_transfer_direction dir; - bool src_inc; - bool dst_inc; - bool src_sgl; - bool dst_sgl; - size_t numf; - size_t frame_size; - struct data_chunk sgl[0]; -}; - -enum dma_ctrl_flags { - DMA_PREP_INTERRUPT = 1, - DMA_CTRL_ACK = 2, - DMA_PREP_PQ_DISABLE_P = 4, - DMA_PREP_PQ_DISABLE_Q = 8, - DMA_PREP_CONTINUE = 16, - DMA_PREP_FENCE = 32, - DMA_CTRL_REUSE = 64, - DMA_PREP_CMD = 128, - DMA_PREP_REPEAT = 256, - DMA_PREP_LOAD_EOT = 512, -}; - -enum sum_check_bits { - SUM_CHECK_P = 0, - SUM_CHECK_Q = 1, -}; - -enum sum_check_flags { - SUM_CHECK_P_RESULT = 1, - SUM_CHECK_Q_RESULT = 2, -}; - -typedef struct { - long unsigned int bits[1]; -} dma_cap_mask_t; - -enum dma_desc_metadata_mode { - DESC_METADATA_NONE = 0, - DESC_METADATA_CLIENT = 1, - DESC_METADATA_ENGINE = 2, -}; - -struct dma_chan_percpu { - long unsigned int memcpy_count; - long unsigned int bytes_transferred; -}; - -struct dma_router { - struct device *dev; - void (*route_free)(struct device *, void *); -}; - -struct dma_device; - -struct dma_chan_dev; - -struct dma_chan___2 { - struct dma_device *device; - struct device *slave; - dma_cookie_t cookie; - dma_cookie_t completed_cookie; - int chan_id; - struct dma_chan_dev *dev; - const char *name; - char *dbg_client_name; - struct list_head device_node; - struct dma_chan_percpu *local; - int client_count; - int table_count; - struct dma_router *router; - void *route_data; - void *private; -}; - -typedef bool (*dma_filter_fn)(struct dma_chan___2 *, void *); - -struct dma_slave_map; - -struct dma_filter { - dma_filter_fn fn; - int mapcnt; - const struct dma_slave_map *map; -}; - -enum dmaengine_alignment { - DMAENGINE_ALIGN_1_BYTE = 0, - DMAENGINE_ALIGN_2_BYTES = 1, - DMAENGINE_ALIGN_4_BYTES = 2, - DMAENGINE_ALIGN_8_BYTES = 3, - DMAENGINE_ALIGN_16_BYTES = 4, - DMAENGINE_ALIGN_32_BYTES = 5, - DMAENGINE_ALIGN_64_BYTES = 6, - DMAENGINE_ALIGN_128_BYTES = 7, - DMAENGINE_ALIGN_256_BYTES = 8, -}; - -enum dma_residue_granularity { - DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0, - DMA_RESIDUE_GRANULARITY_SEGMENT = 1, - DMA_RESIDUE_GRANULARITY_BURST = 2, -}; - -struct dma_async_tx_descriptor; - -struct dma_slave_caps; - -struct dma_slave_config; - -struct dma_tx_state; - -struct dma_device { - struct kref ref; - unsigned int chancnt; - unsigned int privatecnt; - struct list_head channels; - struct list_head global_node; - struct dma_filter filter; - dma_cap_mask_t cap_mask; - enum dma_desc_metadata_mode desc_metadata_modes; - short unsigned int max_xor; - short unsigned int max_pq; - enum dmaengine_alignment copy_align; - enum dmaengine_alignment xor_align; - enum dmaengine_alignment pq_align; - enum dmaengine_alignment fill_align; - int dev_id; - struct device *dev; - struct module *owner; - struct ida chan_ida; - struct mutex chan_mutex; - u32 src_addr_widths; - u32 dst_addr_widths; - u32 directions; - u32 min_burst; - u32 max_burst; - u32 max_sg_burst; - bool descriptor_reuse; - enum dma_residue_granularity residue_granularity; - int (*device_alloc_chan_resources)(struct dma_chan___2 *); - int (*device_router_config)(struct dma_chan___2 *); - void (*device_free_chan_resources)(struct dma_chan___2 *); - struct dma_async_tx_descriptor * (*device_prep_dma_memcpy)(struct dma_chan___2 *, dma_addr_t, dma_addr_t, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_xor)(struct dma_chan___2 *, dma_addr_t, dma_addr_t *, unsigned int, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_xor_val)(struct dma_chan___2 *, dma_addr_t *, unsigned int, size_t, enum sum_check_flags *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_pq)(struct dma_chan___2 *, dma_addr_t *, dma_addr_t *, unsigned int, const unsigned char *, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_pq_val)(struct dma_chan___2 *, dma_addr_t *, dma_addr_t *, unsigned int, const unsigned char *, size_t, enum sum_check_flags *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_memset)(struct dma_chan___2 *, dma_addr_t, int, size_t, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_memset_sg)(struct dma_chan___2 *, struct scatterlist *, unsigned int, int, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_interrupt)(struct dma_chan___2 *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_slave_sg)(struct dma_chan___2 *, struct scatterlist *, unsigned int, enum dma_transfer_direction, long unsigned int, void *); - struct dma_async_tx_descriptor * (*device_prep_dma_cyclic)(struct dma_chan___2 *, dma_addr_t, size_t, size_t, enum dma_transfer_direction, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_interleaved_dma)(struct dma_chan___2 *, struct dma_interleaved_template *, long unsigned int); - struct dma_async_tx_descriptor * (*device_prep_dma_imm_data)(struct dma_chan___2 *, dma_addr_t, u64, long unsigned int); - void (*device_caps)(struct dma_chan___2 *, struct dma_slave_caps *); - int (*device_config)(struct dma_chan___2 *, struct dma_slave_config *); - int (*device_pause)(struct dma_chan___2 *); - int (*device_resume)(struct dma_chan___2 *); - int (*device_terminate_all)(struct dma_chan___2 *); - void (*device_synchronize)(struct dma_chan___2 *); - enum dma_status (*device_tx_status)(struct dma_chan___2 *, dma_cookie_t, struct dma_tx_state *); - void (*device_issue_pending)(struct dma_chan___2 *); - void (*device_release)(struct dma_device *); - void (*dbg_summary_show)(struct seq_file *, struct dma_device *); - struct dentry *dbg_dev_root; -}; - -struct dma_chan_dev { - struct dma_chan___2 *chan; - struct device device; - int dev_id; - bool chan_dma_dev; -}; - -enum dma_slave_buswidth { - DMA_SLAVE_BUSWIDTH_UNDEFINED = 0, - DMA_SLAVE_BUSWIDTH_1_BYTE = 1, - DMA_SLAVE_BUSWIDTH_2_BYTES = 2, - DMA_SLAVE_BUSWIDTH_3_BYTES = 3, - DMA_SLAVE_BUSWIDTH_4_BYTES = 4, - DMA_SLAVE_BUSWIDTH_8_BYTES = 8, - DMA_SLAVE_BUSWIDTH_16_BYTES = 16, - DMA_SLAVE_BUSWIDTH_32_BYTES = 32, - DMA_SLAVE_BUSWIDTH_64_BYTES = 64, -}; - -struct dma_slave_config { - enum dma_transfer_direction direction; - phys_addr_t src_addr; - phys_addr_t dst_addr; - enum dma_slave_buswidth src_addr_width; - enum dma_slave_buswidth dst_addr_width; - u32 src_maxburst; - u32 dst_maxburst; - u32 src_port_window_size; - u32 dst_port_window_size; - bool device_fc; - unsigned int slave_id; - void *peripheral_config; - size_t peripheral_size; -}; - -struct dma_slave_caps { - u32 src_addr_widths; - u32 dst_addr_widths; - u32 directions; - u32 min_burst; - u32 max_burst; - u32 max_sg_burst; - bool cmd_pause; - bool cmd_resume; - bool cmd_terminate; - enum dma_residue_granularity residue_granularity; - bool descriptor_reuse; -}; - -typedef void (*dma_async_tx_callback)(void *); - -enum dmaengine_tx_result { - DMA_TRANS_NOERROR = 0, - DMA_TRANS_READ_FAILED = 1, - DMA_TRANS_WRITE_FAILED = 2, - DMA_TRANS_ABORTED = 3, -}; - -struct dmaengine_result { - enum dmaengine_tx_result result; - u32 residue; -}; - -typedef void (*dma_async_tx_callback_result)(void *, const struct dmaengine_result *); - -struct dmaengine_unmap_data { - u16 map_cnt; - u8 to_cnt; - u8 from_cnt; - u8 bidi_cnt; - struct device *dev; - struct kref kref; - size_t len; - dma_addr_t addr[0]; -}; - -struct dma_descriptor_metadata_ops { - int (*attach)(struct dma_async_tx_descriptor *, void *, size_t); - void * (*get_ptr)(struct dma_async_tx_descriptor *, size_t *, size_t *); - int (*set_len)(struct dma_async_tx_descriptor *, size_t); -}; - -struct dma_async_tx_descriptor { - dma_cookie_t cookie; - enum dma_ctrl_flags flags; - dma_addr_t phys; - struct dma_chan___2 *chan; - dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *); - int (*desc_free)(struct dma_async_tx_descriptor *); - dma_async_tx_callback callback; - dma_async_tx_callback_result callback_result; - void *callback_param; - struct dmaengine_unmap_data *unmap; - enum dma_desc_metadata_mode desc_metadata_mode; - struct dma_descriptor_metadata_ops *metadata_ops; -}; - -struct dma_tx_state { - dma_cookie_t last; - dma_cookie_t used; - u32 residue; - u32 in_flight_bytes; -}; - -struct dma_slave_map { - const char *devname; - const char *slave; - void *param; -}; - -struct dma_chan_tbl_ent { - struct dma_chan___2 *chan; -}; - -struct dmaengine_unmap_pool { - struct kmem_cache *cache; - const char *name; - mempool_t *pool; - size_t size; -}; - -struct dmaengine_desc_callback { - dma_async_tx_callback callback; - dma_async_tx_callback_result callback_result; - void *callback_param; -}; - -struct virt_dma_desc { - struct dma_async_tx_descriptor tx; - struct dmaengine_result tx_result; - struct list_head node; -}; - -struct virt_dma_chan { - struct dma_chan___2 chan; - struct tasklet_struct task; - void (*desc_free)(struct virt_dma_desc *); - spinlock_t lock; - struct list_head desc_allocated; - struct list_head desc_submitted; - struct list_head desc_issued; - struct list_head desc_completed; - struct list_head desc_terminated; - struct virt_dma_desc *cyclic; -}; - -struct acpi_table_csrt { - struct acpi_table_header header; -}; - -struct acpi_csrt_group { - u32 length; - u32 vendor_id; - u32 subvendor_id; - u16 device_id; - u16 subdevice_id; - u16 revision; - u16 reserved; - u32 shared_info_length; -}; - -struct acpi_csrt_shared_info { - u16 major_version; - u16 minor_version; - u32 mmio_base_low; - u32 mmio_base_high; - u32 gsi_interrupt; - u8 interrupt_polarity; - u8 interrupt_mode; - u8 num_channels; - u8 dma_address_width; - u16 base_request_line; - u16 num_handshake_signals; - u32 max_block_size; -}; - -struct acpi_dma_spec { - int chan_id; - int slave_id; - struct device *dev; -}; - -struct acpi_dma { - struct list_head dma_controllers; - struct device *dev; - struct dma_chan___2 * (*acpi_dma_xlate)(struct acpi_dma_spec *, struct acpi_dma *); - void *data; - short unsigned int base_request_line; - short unsigned int end_request_line; -}; - -struct acpi_dma_filter_info { - dma_cap_mask_t dma_cap; - dma_filter_fn filter_fn; -}; - -struct acpi_dma_parser_data { - struct acpi_dma_spec dma_spec; - size_t index; - size_t n; -}; - -struct dw_dma_slave { - struct device *dma_dev; - u8 src_id; - u8 dst_id; - u8 m_master; - u8 p_master; - u8 channels; - bool hs_polarity; -}; - -struct dw_dma_platform_data { - unsigned int nr_channels; - unsigned char chan_allocation_order; - unsigned char chan_priority; - unsigned int block_size; - unsigned char nr_masters; - unsigned char data_width[4]; - unsigned char multi_block[8]; - u32 max_burst[8]; - unsigned char protctl; -}; - -struct dw_dma; - -struct dw_dma_chip { - struct device *dev; - int id; - int irq; - void *regs; - struct clk *clk; - struct dw_dma *dw; - const struct dw_dma_platform_data *pdata; -}; - -struct dma_pool___2; - -struct dw_dma_chan; - -struct dw_dma { - struct dma_device dma; - char name[20]; - void *regs; - struct dma_pool___2 *desc_pool; - struct tasklet_struct tasklet; - struct dw_dma_chan *chan; - u8 all_chan_mask; - u8 in_use; - void (*initialize_chan)(struct dw_dma_chan *); - void (*suspend_chan)(struct dw_dma_chan *, bool); - void (*resume_chan)(struct dw_dma_chan *, bool); - u32 (*prepare_ctllo)(struct dw_dma_chan *); - void (*encode_maxburst)(struct dw_dma_chan *, u32 *); - u32 (*bytes2block)(struct dw_dma_chan *, size_t, unsigned int, size_t *); - size_t (*block2bytes)(struct dw_dma_chan *, u32, u32); - void (*set_device_name)(struct dw_dma *, int); - void (*disable)(struct dw_dma *); - void (*enable)(struct dw_dma *); - struct dw_dma_platform_data *pdata; -}; - -enum dw_dma_fc { - DW_DMA_FC_D_M2M = 0, - DW_DMA_FC_D_M2P = 1, - DW_DMA_FC_D_P2M = 2, - DW_DMA_FC_D_P2P = 3, - DW_DMA_FC_P_P2M = 4, - DW_DMA_FC_SP_P2P = 5, - DW_DMA_FC_P_M2P = 6, - DW_DMA_FC_DP_P2P = 7, -}; - -struct dw_dma_chan_regs { - u32 SAR; - u32 __pad_SAR; - u32 DAR; - u32 __pad_DAR; - u32 LLP; - u32 __pad_LLP; - u32 CTL_LO; - u32 CTL_HI; - u32 SSTAT; - u32 __pad_SSTAT; - u32 DSTAT; - u32 __pad_DSTAT; - u32 SSTATAR; - u32 __pad_SSTATAR; - u32 DSTATAR; - u32 __pad_DSTATAR; - u32 CFG_LO; - u32 CFG_HI; - u32 SGR; - u32 __pad_SGR; - u32 DSR; - u32 __pad_DSR; -}; - -struct dw_dma_irq_regs { - u32 XFER; - u32 __pad_XFER; - u32 BLOCK; - u32 __pad_BLOCK; - u32 SRC_TRAN; - u32 __pad_SRC_TRAN; - u32 DST_TRAN; - u32 __pad_DST_TRAN; - u32 ERROR; - u32 __pad_ERROR; -}; - -struct dw_dma_regs { - struct dw_dma_chan_regs CHAN[8]; - struct dw_dma_irq_regs RAW; - struct dw_dma_irq_regs STATUS; - struct dw_dma_irq_regs MASK; - struct dw_dma_irq_regs CLEAR; - u32 STATUS_INT; - u32 __pad_STATUS_INT; - u32 REQ_SRC; - u32 __pad_REQ_SRC; - u32 REQ_DST; - u32 __pad_REQ_DST; - u32 SGL_REQ_SRC; - u32 __pad_SGL_REQ_SRC; - u32 SGL_REQ_DST; - u32 __pad_SGL_REQ_DST; - u32 LAST_SRC; - u32 __pad_LAST_SRC; - u32 LAST_DST; - u32 __pad_LAST_DST; - u32 CFG; - u32 __pad_CFG; - u32 CH_EN; - u32 __pad_CH_EN; - u32 ID; - u32 __pad_ID; - u32 TEST; - u32 __pad_TEST; - u32 CLASS_PRIORITY0; - u32 __pad_CLASS_PRIORITY0; - u32 CLASS_PRIORITY1; - u32 __pad_CLASS_PRIORITY1; - u32 __reserved; - u32 DWC_PARAMS[8]; - u32 MULTI_BLK_TYPE; - u32 MAX_BLK_SIZE; - u32 DW_PARAMS; - u32 COMP_TYPE; - u32 COMP_VERSION; - u32 FIFO_PARTITION0; - u32 __pad_FIFO_PARTITION0; - u32 FIFO_PARTITION1; - u32 __pad_FIFO_PARTITION1; - u32 SAI_ERR; - u32 __pad_SAI_ERR; - u32 GLOBAL_CFG; - u32 __pad_GLOBAL_CFG; -}; - -enum dw_dmac_flags { - DW_DMA_IS_CYCLIC = 0, - DW_DMA_IS_SOFT_LLP = 1, - DW_DMA_IS_PAUSED = 2, - DW_DMA_IS_INITIALIZED = 3, -}; - -struct dw_dma_chan { - struct dma_chan___2 chan; - void *ch_regs; - u8 mask; - u8 priority; - enum dma_transfer_direction direction; - struct list_head *tx_node_active; - spinlock_t lock; - long unsigned int flags; - struct list_head active_list; - struct list_head queue; - unsigned int descs_allocated; - unsigned int block_size; - bool nollp; - u32 max_burst; - struct dw_dma_slave dws; - struct dma_slave_config dma_sconfig; -}; - -struct dw_lli { - __le32 sar; - __le32 dar; - __le32 llp; - __le32 ctllo; - __le32 ctlhi; - __le32 sstat; - __le32 dstat; -}; - -struct dw_desc { - struct dw_lli lli; - struct list_head desc_node; - struct list_head tx_list; - struct dma_async_tx_descriptor txd; - size_t len; - size_t total_len; - u32 residue; -}; - -struct dw_dma_chip_pdata { - const struct dw_dma_platform_data *pdata; - int (*probe)(struct dw_dma_chip *); - int (*remove)(struct dw_dma_chip *); - struct dw_dma_chip *chip; -}; - -struct hsu_dma; - -struct hsu_dma_chip { - struct device *dev; - int irq; - void *regs; - unsigned int length; - unsigned int offset; - struct hsu_dma *hsu; -}; - -struct hsu_dma_chan; - -struct hsu_dma { - struct dma_device dma; - struct hsu_dma_chan *chan; - short unsigned int nr_channels; -}; - -struct hsu_dma_sg { - dma_addr_t addr; - unsigned int len; -}; - -struct hsu_dma_desc { - struct virt_dma_desc vdesc; - enum dma_transfer_direction direction; - struct hsu_dma_sg *sg; - unsigned int nents; - size_t length; - unsigned int active; - enum dma_status status; -}; - -struct hsu_dma_chan { - struct virt_dma_chan vchan; - void *reg; - enum dma_transfer_direction direction; - struct dma_slave_config config; - struct hsu_dma_desc *desc; -}; - -struct of_dma { - struct list_head of_dma_controllers; - struct device_node *of_node; - struct dma_chan___2 * (*of_dma_xlate)(struct of_phandle_args *, struct of_dma *); - void * (*of_dma_route_allocate)(struct of_phandle_args *, struct of_dma *); - struct dma_router *dma_router; - void *of_dma_data; -}; - -enum ldma_chan_on_off { - DMA_CH_OFF = 0, - DMA_CH_ON = 1, -}; - -enum { - DMA_TYPE_TX = 0, - DMA_TYPE_RX = 1, - DMA_TYPE_MCPY = 2, -}; - -struct ldma_port; - -struct dw2_desc_sw; - -struct ldma_chan { - struct virt_dma_chan vchan; - struct ldma_port *port; - char name[8]; - int nr; - u32 flags; - enum ldma_chan_on_off onoff; - dma_addr_t desc_phys; - void *desc_base; - u32 desc_cnt; - int rst; - u32 hdrm_len; - bool hdrm_csum; - u32 boff_len; - u32 data_endian; - u32 desc_endian; - bool pden; - bool desc_rx_np; - bool data_endian_en; - bool desc_endian_en; - bool abc_en; - bool desc_init; - struct dma_pool___2 *desc_pool; - u32 desc_num; - struct dw2_desc_sw *ds; - struct work_struct work; - struct dma_slave_config config; -}; - -struct ldma_dev; - -struct ldma_port { - struct ldma_dev *ldev; - u32 portid; - u32 rxbl; - u32 txbl; - u32 rxendi; - u32 txendi; - u32 pkt_drop; -}; - -struct dw2_desc; - -struct dw2_desc_sw { - struct virt_dma_desc vdesc; - struct ldma_chan *chan; - dma_addr_t desc_phys; - size_t desc_cnt; - size_t size; - struct dw2_desc *desc_hw; -}; - -struct ldma_inst_data; - -struct ldma_dev { - struct device *dev; - void *base; - struct reset_control *rst; - struct clk *core_clk; - struct dma_device dma_dev; - u32 ver; - int irq; - struct ldma_port *ports; - struct ldma_chan *chans; - spinlock_t dev_lock; - u32 chan_nrs; - u32 port_nrs; - u32 channels_mask; - u32 flags; - u32 pollcnt; - const struct ldma_inst_data *inst; - struct workqueue_struct *wq; -}; - -struct ldma_inst_data { - bool desc_in_sram; - bool chan_fc; - bool desc_fod; - bool valid_desc_fetch_ack; - u32 orrc; - const char *name; - u32 type; -}; - -struct dw2_desc { - u32 field; - u32 addr; -}; - -struct virtio_driver { - struct device_driver driver; - const struct virtio_device_id *id_table; - const unsigned int *feature_table; - unsigned int feature_table_size; - const unsigned int *feature_table_legacy; - unsigned int feature_table_size_legacy; - int (*validate)(struct virtio_device *); - int (*probe)(struct virtio_device *); - void (*scan)(struct virtio_device *); - void (*remove)(struct virtio_device *); - void (*config_changed)(struct virtio_device *); - int (*freeze)(struct virtio_device *); - int (*restore)(struct virtio_device *); -}; - -typedef __u16 __virtio16; - -typedef __u32 __virtio32; - -typedef __u64 __virtio64; - -struct vring_desc { - __virtio64 addr; - __virtio32 len; - __virtio16 flags; - __virtio16 next; -}; - -struct vring_avail { - __virtio16 flags; - __virtio16 idx; - __virtio16 ring[0]; -}; - -struct vring_used_elem { - __virtio32 id; - __virtio32 len; -}; - -typedef struct vring_used_elem vring_used_elem_t; - -struct vring_used { - __virtio16 flags; - __virtio16 idx; - vring_used_elem_t ring[0]; -}; - -typedef struct vring_desc vring_desc_t; - -typedef struct vring_avail vring_avail_t; - -typedef struct vring_used vring_used_t; - -struct vring { - unsigned int num; - vring_desc_t *desc; - vring_avail_t *avail; - vring_used_t *used; -}; - -struct vring_packed_desc_event { - __le16 off_wrap; - __le16 flags; -}; - -struct vring_packed_desc { - __le64 addr; - __le32 len; - __le16 id; - __le16 flags; -}; - -struct vring_desc_state_split { - void *data; - struct vring_desc *indir_desc; -}; - -struct vring_desc_state_packed { - void *data; - struct vring_packed_desc *indir_desc; - u16 num; - u16 last; -}; - -struct vring_desc_extra { - dma_addr_t addr; - u32 len; - u16 flags; - u16 next; -}; - -struct vring_virtqueue { - struct virtqueue vq; - bool packed_ring; - bool use_dma_api; - bool weak_barriers; - bool broken; - bool indirect; - bool event; - unsigned int free_head; - unsigned int num_added; - u16 last_used_idx; - bool event_triggered; - union { - struct { - struct vring vring; - u16 avail_flags_shadow; - u16 avail_idx_shadow; - struct vring_desc_state_split *desc_state; - struct vring_desc_extra *desc_extra; - dma_addr_t queue_dma_addr; - size_t queue_size_in_bytes; - } split; - struct { - struct { - unsigned int num; - struct vring_packed_desc *desc; - struct vring_packed_desc_event *driver; - struct vring_packed_desc_event *device; - } vring; - bool avail_wrap_counter; - bool used_wrap_counter; - u16 avail_used_flags; - u16 next_avail_idx; - u16 event_flags_shadow; - struct vring_desc_state_packed *desc_state; - struct vring_desc_extra *desc_extra; - dma_addr_t ring_dma_addr; - dma_addr_t driver_event_dma_addr; - dma_addr_t device_event_dma_addr; - size_t ring_size_in_bytes; - size_t event_size_in_bytes; - } packed; - }; - bool (*notify)(struct virtqueue *); - bool we_own_ring; -}; - -struct xsd_errors { - int errnum; - const char *errstring; -}; - -struct xenbus_watch { - struct list_head list; - const char *node; - unsigned int nr_pending; - bool (*will_handle)(struct xenbus_watch *, const char *, const char *); - void (*callback)(struct xenbus_watch *, const char *, const char *); -}; - -struct xenbus_transaction { - u32 id; -}; - -struct grant_entry_v1 { - uint16_t flags; - domid_t domid; - uint32_t frame; -}; - -struct grant_entry_header { - uint16_t flags; - domid_t domid; -}; - -union grant_entry_v2 { - struct grant_entry_header hdr; - struct { - struct grant_entry_header hdr; - uint32_t pad0; - uint64_t frame; - } full_page; - struct { - struct grant_entry_header hdr; - uint16_t page_off; - uint16_t length; - uint64_t frame; - } sub_page; - struct { - struct grant_entry_header hdr; - domid_t trans_domid; - uint16_t pad0; - grant_ref_t gref; - } transitive; - uint32_t __spacer[4]; -}; - -struct gnttab_setup_table { - domid_t dom; - uint32_t nr_frames; - int16_t status; - __guest_handle_xen_pfn_t frame_list; -}; - -struct gnttab_copy { - struct { - union { - grant_ref_t ref; - xen_pfn_t gmfn; - } u; - domid_t domid; - uint16_t offset; - } source; - struct { - union { - grant_ref_t ref; - xen_pfn_t gmfn; - } u; - domid_t domid; - uint16_t offset; - } dest; - uint16_t len; - uint16_t flags; - int16_t status; -}; - -struct gnttab_query_size { - domid_t dom; - uint32_t nr_frames; - uint32_t max_nr_frames; - int16_t status; -}; - -struct gnttab_set_version { - uint32_t version; -}; - -struct gnttab_get_status_frames { - uint32_t nr_frames; - domid_t dom; - int16_t status; - __guest_handle_uint64_t frame_list; -}; - -struct gnttab_free_callback { - struct gnttab_free_callback *next; - void (*fn)(void *); - void *arg; - u16 count; -}; - -struct gntab_unmap_queue_data; - -typedef void (*gnttab_unmap_refs_done)(int, struct gntab_unmap_queue_data *); - -struct gntab_unmap_queue_data { - struct delayed_work gnttab_work; - void *data; - gnttab_unmap_refs_done done; - struct gnttab_unmap_grant_ref *unmap_ops; - struct gnttab_unmap_grant_ref *kunmap_ops; - struct page **pages; - unsigned int count; - unsigned int age; -}; - -struct gnttab_page_cache { - spinlock_t lock; - struct page *pages; - unsigned int num_pages; -}; - -struct gnttab_dma_alloc_args { - struct device *dev; - bool coherent; - int nr_pages; - struct page **pages; - xen_pfn_t *frames; - void *vaddr; - dma_addr_t dev_bus_addr; -}; - -struct xen_page_foreign { - domid_t domid; - grant_ref_t gref; -}; - -typedef void (*xen_grant_fn_t)(long unsigned int, unsigned int, unsigned int, void *); - -struct gnttab_ops { - unsigned int version; - unsigned int grefs_per_grant_frame; - int (*map_frames)(xen_pfn_t *, unsigned int); - void (*unmap_frames)(); - void (*update_entry)(grant_ref_t, domid_t, long unsigned int, unsigned int); - int (*end_foreign_access_ref)(grant_ref_t, int); - long unsigned int (*end_foreign_transfer_ref)(grant_ref_t); - int (*query_foreign_access)(grant_ref_t); -}; - -struct unmap_refs_callback_data { - struct completion completion; - int result; -}; - -struct deferred_entry { - struct list_head list; - grant_ref_t ref; - bool ro; - uint16_t warn_delay; - struct page *page; -}; - -struct xen_feature_info { - unsigned int submap_idx; - uint32_t submap; -}; - -struct balloon_stats { - long unsigned int current_pages; - long unsigned int target_pages; - long unsigned int target_unpopulated; - long unsigned int balloon_low; - long unsigned int balloon_high; - long unsigned int total_pages; - long unsigned int schedule_delay; - long unsigned int max_schedule_delay; - long unsigned int retry_count; - long unsigned int max_retry_count; -}; - -enum bp_state { - BP_DONE = 0, - BP_WAIT = 1, - BP_EAGAIN = 2, - BP_ECANCELED = 3, -}; - -enum shutdown_state { - SHUTDOWN_INVALID = 4294967295, - SHUTDOWN_POWEROFF = 0, - SHUTDOWN_SUSPEND = 2, - SHUTDOWN_HALT = 4, -}; - -struct suspend_info { - int cancelled; -}; - -struct shutdown_handler { - const char command[11]; - bool flag; - void (*cb)(); -}; - -struct vcpu_runstate_info { - int state; - uint64_t state_entry_time; - uint64_t time[4]; -}; - -typedef struct vcpu_runstate_info *__guest_handle_vcpu_runstate_info; - -struct vcpu_register_runstate_memory_area { - union { - __guest_handle_vcpu_runstate_info h; - struct vcpu_runstate_info *v; - uint64_t p; - } addr; -}; - -typedef uint32_t evtchn_port_t; - -typedef evtchn_port_t *__guest_handle_evtchn_port_t; - -struct evtchn_bind_interdomain { - domid_t remote_dom; - evtchn_port_t remote_port; - evtchn_port_t local_port; -}; - -struct evtchn_bind_virq { - uint32_t virq; - uint32_t vcpu; - evtchn_port_t port; -}; - -struct evtchn_bind_pirq { - uint32_t pirq; - uint32_t flags; - evtchn_port_t port; -}; - -struct evtchn_bind_ipi { - uint32_t vcpu; - evtchn_port_t port; -}; - -struct evtchn_close { - evtchn_port_t port; -}; - -struct evtchn_send { - evtchn_port_t port; -}; - -struct evtchn_status { - domid_t dom; - evtchn_port_t port; - uint32_t status; - uint32_t vcpu; - union { - struct { - domid_t dom; - } unbound; - struct { - domid_t dom; - evtchn_port_t port; - } interdomain; - uint32_t pirq; - uint32_t virq; - } u; -}; - -struct evtchn_bind_vcpu { - evtchn_port_t port; - uint32_t vcpu; -}; - -struct evtchn_set_priority { - evtchn_port_t port; - uint32_t priority; -}; - -struct sched_poll { - __guest_handle_evtchn_port_t ports; - unsigned int nr_ports; - uint64_t timeout; -}; - -struct physdev_eoi { - uint32_t irq; -}; - -struct physdev_pirq_eoi_gmfn { - xen_ulong_t gmfn; -}; - -struct physdev_irq_status_query { - uint32_t irq; - uint32_t flags; -}; - -struct physdev_irq { - uint32_t irq; - uint32_t vector; -}; - -struct physdev_map_pirq { - domid_t domid; - int type; - int index; - int pirq; - int bus; - int devfn; - int entry_nr; - uint64_t table_base; -}; - -struct physdev_unmap_pirq { - domid_t domid; - int pirq; -}; - -struct physdev_get_free_pirq { - int type; - uint32_t pirq; -}; - -enum xenbus_state { - XenbusStateUnknown = 0, - XenbusStateInitialising = 1, - XenbusStateInitWait = 2, - XenbusStateInitialised = 3, - XenbusStateConnected = 4, - XenbusStateClosing = 5, - XenbusStateClosed = 6, - XenbusStateReconfiguring = 7, - XenbusStateReconfigured = 8, -}; - -struct xenbus_device { - const char *devicetype; - const char *nodename; - const char *otherend; - int otherend_id; - struct xenbus_watch otherend_watch; - struct device dev; - enum xenbus_state state; - struct completion down; - struct work_struct work; - struct semaphore reclaim_sem; - atomic_t event_channels; - atomic_t events; - atomic_t spurious_events; - atomic_t jiffies_eoi_delayed; - unsigned int spurious_threshold; -}; - -struct evtchn_loop_ctrl; - -struct evtchn_ops { - unsigned int (*max_channels)(); - unsigned int (*nr_channels)(); - int (*setup)(evtchn_port_t); - void (*remove)(evtchn_port_t, unsigned int); - void (*bind_to_cpu)(evtchn_port_t, unsigned int, unsigned int); - void (*clear_pending)(evtchn_port_t); - void (*set_pending)(evtchn_port_t); - bool (*is_pending)(evtchn_port_t); - void (*mask)(evtchn_port_t); - void (*unmask)(evtchn_port_t); - void (*handle_events)(unsigned int, struct evtchn_loop_ctrl *); - void (*resume)(); - int (*percpu_init)(unsigned int); - int (*percpu_deinit)(unsigned int); -}; - -struct evtchn_loop_ctrl { - ktime_t timeout; - unsigned int count; - bool defer_eoi; -}; - -enum xen_irq_type { - IRQT_UNBOUND = 0, - IRQT_PIRQ = 1, - IRQT_VIRQ = 2, - IRQT_IPI = 3, - IRQT_EVTCHN = 4, -}; - -struct irq_info { - struct list_head list; - struct list_head eoi_list; - short int refcnt; - u8 spurious_cnt; - u8 is_accounted; - short int type; - u8 mask_reason; - u8 is_active; - unsigned int irq; - evtchn_port_t evtchn; - short unsigned int cpu; - short unsigned int eoi_cpu; - unsigned int irq_epoch; - u64 eoi_time; - raw_spinlock_t lock; - union { - short unsigned int virq; - enum ipi_vector ipi; - struct { - short unsigned int pirq; - short unsigned int gsi; - unsigned char vector; - unsigned char flags; - uint16_t domid; - } pirq; - struct xenbus_device *interdomain; - } u; -}; - -struct lateeoi_work { - struct delayed_work delayed; - spinlock_t eoi_list_lock; - struct list_head eoi_list; -}; - -struct evtchn_unmask { - evtchn_port_t port; -}; - -struct evtchn_init_control { - uint64_t control_gfn; - uint32_t offset; - uint32_t vcpu; - uint8_t link_bits; - uint8_t _pad[7]; -}; - -struct evtchn_expand_array { - uint64_t array_gfn; -}; - -typedef uint32_t event_word_t; - -struct evtchn_fifo_control_block { - uint32_t ready; - uint32_t _rsvd; - event_word_t head[16]; -}; - -struct evtchn_fifo_queue { - uint32_t head[16]; -}; - -struct evtchn_alloc_unbound { - domid_t dom; - domid_t remote_dom; - evtchn_port_t port; -}; - -struct xenbus_map_node { - struct list_head next; - union { - struct { - struct vm_struct *area; - } pv; - struct { - struct page *pages[16]; - long unsigned int addrs[16]; - void *addr; - } hvm; - }; - grant_handle_t handles[16]; - unsigned int nr_handles; -}; - -struct map_ring_valloc { - struct xenbus_map_node *node; - long unsigned int addrs[16]; - phys_addr_t phys_addrs[16]; - struct gnttab_map_grant_ref map[16]; - struct gnttab_unmap_grant_ref unmap[16]; - unsigned int idx; -}; - -struct xenbus_ring_ops { - int (*map)(struct xenbus_device *, struct map_ring_valloc *, grant_ref_t *, unsigned int, void **); - int (*unmap)(struct xenbus_device *, void *); -}; - -struct unmap_ring_hvm { - unsigned int idx; - long unsigned int addrs[16]; -}; - -enum xsd_sockmsg_type { - XS_DEBUG = 0, - XS_DIRECTORY = 1, - XS_READ = 2, - XS_GET_PERMS = 3, - XS_WATCH = 4, - XS_UNWATCH = 5, - XS_TRANSACTION_START = 6, - XS_TRANSACTION_END = 7, - XS_INTRODUCE = 8, - XS_RELEASE = 9, - XS_GET_DOMAIN_PATH = 10, - XS_WRITE = 11, - XS_MKDIR = 12, - XS_RM = 13, - XS_SET_PERMS = 14, - XS_WATCH_EVENT = 15, - XS_ERROR = 16, - XS_IS_DOMAIN_INTRODUCED = 17, - XS_RESUME = 18, - XS_SET_TARGET = 19, - XS_RESTRICT = 20, - XS_RESET_WATCHES = 21, -}; - -struct xsd_sockmsg { - uint32_t type; - uint32_t req_id; - uint32_t tx_id; - uint32_t len; -}; - -typedef uint32_t XENSTORE_RING_IDX; - -struct xenstore_domain_interface { - char req[1024]; - char rsp[1024]; - XENSTORE_RING_IDX req_cons; - XENSTORE_RING_IDX req_prod; - XENSTORE_RING_IDX rsp_cons; - XENSTORE_RING_IDX rsp_prod; -}; - -struct xs_watch_event { - struct list_head list; - unsigned int len; - struct xenbus_watch *handle; - const char *path; - const char *token; - char body[0]; -}; - -enum xb_req_state { - xb_req_state_queued = 0, - xb_req_state_wait_reply = 1, - xb_req_state_got_reply = 2, - xb_req_state_aborted = 3, -}; - -struct xb_req_data { - struct list_head list; - wait_queue_head_t wq; - struct xsd_sockmsg msg; - uint32_t caller_req_id; - enum xsd_sockmsg_type type; - char *body; - const struct kvec *vec; - int num_vecs; - int err; - enum xb_req_state state; - bool user_req; - void (*cb)(struct xb_req_data *); - void *par; -}; - -enum xenstore_init { - XS_UNKNOWN = 0, - XS_PV = 1, - XS_HVM = 2, - XS_LOCAL = 3, -}; - -struct xenbus_device_id { - char devicetype[32]; -}; - -struct xenbus_driver { - const char *name; - const struct xenbus_device_id *ids; - bool allow_rebind; - int (*probe)(struct xenbus_device *, const struct xenbus_device_id *); - void (*otherend_changed)(struct xenbus_device *, enum xenbus_state); - int (*remove)(struct xenbus_device *); - int (*suspend)(struct xenbus_device *); - int (*resume)(struct xenbus_device *); - int (*uevent)(struct xenbus_device *, struct kobj_uevent_env *); - struct device_driver driver; - int (*read_otherend_details)(struct xenbus_device *); - int (*is_ready)(struct xenbus_device *); - void (*reclaim_memory)(struct xenbus_device *); -}; - -struct xen_hvm_param { - domid_t domid; - uint32_t index; - uint64_t value; -}; - -struct xen_bus_type { - char *root; - unsigned int levels; - int (*get_bus_id)(char *, const char *); - int (*probe)(struct xen_bus_type *, const char *, const char *); - bool (*otherend_will_handle)(struct xenbus_watch *, const char *, const char *); - void (*otherend_changed)(struct xenbus_watch *, const char *, const char *); - struct bus_type bus; -}; - -struct xb_find_info { - struct xenbus_device *dev; - const char *nodename; -}; - -struct xenbus_transaction_holder { - struct list_head list; - struct xenbus_transaction handle; - unsigned int generation_id; -}; - -struct read_buffer { - struct list_head list; - unsigned int cons; - unsigned int len; - char msg[0]; -}; - -struct xenbus_file_priv { - struct mutex msgbuffer_mutex; - struct list_head transactions; - struct list_head watches; - unsigned int len; - union { - struct xsd_sockmsg msg; - char buffer[4096]; - } u; - struct mutex reply_mutex; - struct list_head read_buffers; - wait_queue_head_t read_waitq; - struct kref kref; - struct work_struct wq; -}; - -struct watch_adapter { - struct list_head list; - struct xenbus_watch watch; - struct xenbus_file_priv *dev_data; - char *token; -}; - -struct physdev_manage_pci { - uint8_t bus; - uint8_t devfn; -}; - -struct physdev_manage_pci_ext { - uint8_t bus; - uint8_t devfn; - unsigned int is_extfn; - unsigned int is_virtfn; - struct { - uint8_t bus; - uint8_t devfn; - } physfn; -}; - -struct physdev_pci_mmcfg_reserved { - uint64_t address; - uint16_t segment; - uint8_t start_bus; - uint8_t end_bus; - uint32_t flags; -}; - -struct physdev_pci_device_add { - uint16_t seg; - uint8_t bus; - uint8_t devfn; - uint32_t flags; - struct { - uint8_t bus; - uint8_t devfn; - } physfn; - uint32_t optarr[0]; -}; - -struct physdev_pci_device { - uint16_t seg; - uint8_t bus; - uint8_t devfn; -}; - -struct usb_device_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __le16 idVendor; - __le16 idProduct; - __le16 bcdDevice; - __u8 iManufacturer; - __u8 iProduct; - __u8 iSerialNumber; - __u8 bNumConfigurations; -}; - -struct usb_config_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 wTotalLength; - __u8 bNumInterfaces; - __u8 bConfigurationValue; - __u8 iConfiguration; - __u8 bmAttributes; - __u8 bMaxPower; -} __attribute__((packed)); - -struct usb_interface_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - __u8 bNumEndpoints; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 iInterface; -}; - -struct usb_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bEndpointAddress; - __u8 bmAttributes; - __le16 wMaxPacketSize; - __u8 bInterval; - __u8 bRefresh; - __u8 bSynchAddress; -} __attribute__((packed)); - -struct usb_ssp_isoc_ep_comp_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 wReseved; - __le32 dwBytesPerInterval; -}; - -struct usb_ss_ep_comp_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bMaxBurst; - __u8 bmAttributes; - __le16 wBytesPerInterval; -}; - -struct usb_interface_assoc_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bFirstInterface; - __u8 bInterfaceCount; - __u8 bFunctionClass; - __u8 bFunctionSubClass; - __u8 bFunctionProtocol; - __u8 iFunction; -}; - -struct usb_bos_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 wTotalLength; - __u8 bNumDeviceCaps; -} __attribute__((packed)); - -struct usb_ext_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __le32 bmAttributes; -} __attribute__((packed)); - -struct usb_ss_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __u8 bmAttributes; - __le16 wSpeedSupported; - __u8 bFunctionalitySupport; - __u8 bU1devExitLat; - __le16 bU2DevExitLat; -}; - -struct usb_ss_container_id_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __u8 bReserved; - __u8 ContainerID[16]; -}; - -struct usb_ssp_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - __u8 bReserved; - __le32 bmAttributes; - __le16 wFunctionalitySupport; - __le16 wReserved; - __le32 bmSublinkSpeedAttr[1]; -}; - -struct usb_ptm_cap_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; -}; - -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, - USB_SPEED_LOW = 1, - USB_SPEED_FULL = 2, - USB_SPEED_HIGH = 3, - USB_SPEED_WIRELESS = 4, - USB_SPEED_SUPER = 5, - USB_SPEED_SUPER_PLUS = 6, -}; - -enum usb_device_state { - USB_STATE_NOTATTACHED = 0, - USB_STATE_ATTACHED = 1, - USB_STATE_POWERED = 2, - USB_STATE_RECONNECTING = 3, - USB_STATE_UNAUTHENTICATED = 4, - USB_STATE_DEFAULT = 5, - USB_STATE_ADDRESS = 6, - USB_STATE_CONFIGURED = 7, - USB_STATE_SUSPENDED = 8, -}; - -enum usb3_link_state { - USB3_LPM_U0 = 0, - USB3_LPM_U1 = 1, - USB3_LPM_U2 = 2, - USB3_LPM_U3 = 3, -}; - -enum usb_ssp_rate { - USB_SSP_GEN_UNKNOWN = 0, - USB_SSP_GEN_2x1 = 1, - USB_SSP_GEN_1x2 = 2, - USB_SSP_GEN_2x2 = 3, -}; - -struct ep_device; - -struct usb_host_endpoint { - struct usb_endpoint_descriptor desc; - struct usb_ss_ep_comp_descriptor ss_ep_comp; - struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp; - char: 8; - struct list_head urb_list; - void *hcpriv; - struct ep_device *ep_dev; - unsigned char *extra; - int extralen; - int enabled; - int streams; - int: 32; -} __attribute__((packed)); - -struct usb_host_interface { - struct usb_interface_descriptor desc; - int extralen; - unsigned char *extra; - struct usb_host_endpoint *endpoint; - char *string; -}; - -enum usb_interface_condition { - USB_INTERFACE_UNBOUND = 0, - USB_INTERFACE_BINDING = 1, - USB_INTERFACE_BOUND = 2, - USB_INTERFACE_UNBINDING = 3, -}; - -struct usb_interface { - struct usb_host_interface *altsetting; - struct usb_host_interface *cur_altsetting; - unsigned int num_altsetting; - struct usb_interface_assoc_descriptor *intf_assoc; - int minor; - enum usb_interface_condition condition; - unsigned int sysfs_files_created: 1; - unsigned int ep_devs_created: 1; - unsigned int unregistering: 1; - unsigned int needs_remote_wakeup: 1; - unsigned int needs_altsetting0: 1; - unsigned int needs_binding: 1; - unsigned int resetting_device: 1; - unsigned int authorized: 1; - struct device dev; - struct device *usb_dev; - struct work_struct reset_ws; -}; - -struct usb_interface_cache { - unsigned int num_altsetting; - struct kref ref; - struct usb_host_interface altsetting[0]; -}; - -struct usb_host_config { - struct usb_config_descriptor desc; - char *string; - struct usb_interface_assoc_descriptor *intf_assoc[16]; - struct usb_interface *interface[32]; - struct usb_interface_cache *intf_cache[32]; - unsigned char *extra; - int extralen; -}; - -struct usb_host_bos { - struct usb_bos_descriptor *desc; - struct usb_ext_cap_descriptor *ext_cap; - struct usb_ss_cap_descriptor *ss_cap; - struct usb_ssp_cap_descriptor *ssp_cap; - struct usb_ss_container_id_descriptor *ss_id; - struct usb_ptm_cap_descriptor *ptm_cap; -}; - -struct usb_devmap { - long unsigned int devicemap[2]; -}; - -struct mon_bus; - -struct usb_device; - -struct usb_bus { - struct device *controller; - struct device *sysdev; - int busnum; - const char *bus_name; - u8 uses_pio_for_control; - u8 otg_port; - unsigned int is_b_host: 1; - unsigned int b_hnp_enable: 1; - unsigned int no_stop_on_short: 1; - unsigned int no_sg_constraint: 1; - unsigned int sg_tablesize; - int devnum_next; - struct mutex devnum_next_mutex; - struct usb_devmap devmap; - struct usb_device *root_hub; - struct usb_bus *hs_companion; - int bandwidth_allocated; - int bandwidth_int_reqs; - int bandwidth_isoc_reqs; - unsigned int resuming_ports; - struct mon_bus *mon_bus; - int monitored; -}; - -struct wusb_dev; - -struct usb2_lpm_parameters { - unsigned int besl; - int timeout; -}; - -struct usb3_lpm_parameters { - unsigned int mel; - unsigned int pel; - unsigned int sel; - int timeout; -}; - -struct usb_tt; - -struct usb_device { - int devnum; - char devpath[16]; - u32 route; - enum usb_device_state state; - enum usb_device_speed speed; - unsigned int rx_lanes; - unsigned int tx_lanes; - enum usb_ssp_rate ssp_rate; - struct usb_tt *tt; - int ttport; - unsigned int toggle[2]; - struct usb_device *parent; - struct usb_bus *bus; - struct usb_host_endpoint ep0; - struct device dev; - struct usb_device_descriptor descriptor; - struct usb_host_bos *bos; - struct usb_host_config *config; - struct usb_host_config *actconfig; - struct usb_host_endpoint *ep_in[16]; - struct usb_host_endpoint *ep_out[16]; - char **rawdescriptors; - short unsigned int bus_mA; - u8 portnum; - u8 level; - u8 devaddr; - unsigned int can_submit: 1; - unsigned int persist_enabled: 1; - unsigned int have_langid: 1; - unsigned int authorized: 1; - unsigned int authenticated: 1; - unsigned int wusb: 1; - unsigned int lpm_capable: 1; - unsigned int usb2_hw_lpm_capable: 1; - unsigned int usb2_hw_lpm_besl_capable: 1; - unsigned int usb2_hw_lpm_enabled: 1; - unsigned int usb2_hw_lpm_allowed: 1; - unsigned int usb3_lpm_u1_enabled: 1; - unsigned int usb3_lpm_u2_enabled: 1; - int string_langid; - char *product; - char *manufacturer; - char *serial; - struct list_head filelist; - int maxchild; - u32 quirks; - atomic_t urbnum; - long unsigned int active_duration; - long unsigned int connect_time; - unsigned int do_remote_wakeup: 1; - unsigned int reset_resume: 1; - unsigned int port_is_suspended: 1; - struct wusb_dev *wusb_dev; - int slot_id; - struct usb2_lpm_parameters l1_params; - struct usb3_lpm_parameters u1_params; - struct usb3_lpm_parameters u2_params; - unsigned int lpm_disable_count; - u16 hub_delay; - unsigned int use_generic_driver: 1; -}; - -struct usb_tt { - struct usb_device *hub; - int multi; - unsigned int think_time; - void *hcpriv; - spinlock_t lock; - struct list_head clear_list; - struct work_struct clear_work; -}; - -struct usb_iso_packet_descriptor { - unsigned int offset; - unsigned int length; - unsigned int actual_length; - int status; -}; - -struct usb_anchor { - struct list_head urb_list; - wait_queue_head_t wait; - spinlock_t lock; - atomic_t suspend_wakeups; - unsigned int poisoned: 1; -}; - -struct urb; - -typedef void (*usb_complete_t)(struct urb *); - -struct urb { - struct kref kref; - int unlinked; - void *hcpriv; - atomic_t use_count; - atomic_t reject; - struct list_head urb_list; - struct list_head anchor_list; - struct usb_anchor *anchor; - struct usb_device *dev; - struct usb_host_endpoint *ep; - unsigned int pipe; - unsigned int stream_id; - int status; - unsigned int transfer_flags; - void *transfer_buffer; - dma_addr_t transfer_dma; - struct scatterlist *sg; - int num_mapped_sgs; - int num_sgs; - u32 transfer_buffer_length; - u32 actual_length; - unsigned char *setup_packet; - dma_addr_t setup_dma; - int start_frame; - int number_of_packets; - int interval; - int error_count; - void *context; - usb_complete_t complete; - struct usb_iso_packet_descriptor iso_frame_desc[0]; -}; - -struct giveback_urb_bh { - bool running; - spinlock_t lock; - struct list_head head; - struct tasklet_struct bh; - struct usb_host_endpoint *completing_ep; -}; - -enum usb_dev_authorize_policy { - USB_DEVICE_AUTHORIZE_NONE = 0, - USB_DEVICE_AUTHORIZE_ALL = 1, - USB_DEVICE_AUTHORIZE_INTERNAL = 2, -}; - -struct usb_phy_roothub; - -struct hc_driver; - -struct usb_phy; - -struct usb_hcd { - struct usb_bus self; - struct kref kref; - const char *product_desc; - int speed; - char irq_descr[24]; - struct timer_list rh_timer; - struct urb *status_urb; - struct work_struct wakeup_work; - struct work_struct died_work; - const struct hc_driver *driver; - struct usb_phy *usb_phy; - struct usb_phy_roothub *phy_roothub; - long unsigned int flags; - enum usb_dev_authorize_policy dev_policy; - unsigned int rh_registered: 1; - unsigned int rh_pollable: 1; - unsigned int msix_enabled: 1; - unsigned int msi_enabled: 1; - unsigned int skip_phy_initialization: 1; - unsigned int uses_new_polling: 1; - unsigned int wireless: 1; - unsigned int has_tt: 1; - unsigned int amd_resume_bug: 1; - unsigned int can_do_streams: 1; - unsigned int tpl_support: 1; - unsigned int cant_recv_wakeups: 1; - unsigned int irq; - void *regs; - resource_size_t rsrc_start; - resource_size_t rsrc_len; - unsigned int power_budget; - struct giveback_urb_bh high_prio_bh; - struct giveback_urb_bh low_prio_bh; - struct mutex *address0_mutex; - struct mutex *bandwidth_mutex; - struct usb_hcd *shared_hcd; - struct usb_hcd *primary_hcd; - struct dma_pool___2 *pool[4]; - int state; - struct gen_pool *localmem_pool; - long unsigned int hcd_priv[0]; -}; - -struct hc_driver { - const char *description; - const char *product_desc; - size_t hcd_priv_size; - irqreturn_t (*irq)(struct usb_hcd *); - int flags; - int (*reset)(struct usb_hcd *); - int (*start)(struct usb_hcd *); - int (*pci_suspend)(struct usb_hcd *, bool); - int (*pci_resume)(struct usb_hcd *, bool); - void (*stop)(struct usb_hcd *); - void (*shutdown)(struct usb_hcd *); - int (*get_frame_number)(struct usb_hcd *); - int (*urb_enqueue)(struct usb_hcd *, struct urb *, gfp_t); - int (*urb_dequeue)(struct usb_hcd *, struct urb *, int); - int (*map_urb_for_dma)(struct usb_hcd *, struct urb *, gfp_t); - void (*unmap_urb_for_dma)(struct usb_hcd *, struct urb *); - void (*endpoint_disable)(struct usb_hcd *, struct usb_host_endpoint *); - void (*endpoint_reset)(struct usb_hcd *, struct usb_host_endpoint *); - int (*hub_status_data)(struct usb_hcd *, char *); - int (*hub_control)(struct usb_hcd *, u16, u16, u16, char *, u16); - int (*bus_suspend)(struct usb_hcd *); - int (*bus_resume)(struct usb_hcd *); - int (*start_port_reset)(struct usb_hcd *, unsigned int); - long unsigned int (*get_resuming_ports)(struct usb_hcd *); - void (*relinquish_port)(struct usb_hcd *, int); - int (*port_handed_over)(struct usb_hcd *, int); - void (*clear_tt_buffer_complete)(struct usb_hcd *, struct usb_host_endpoint *); - int (*alloc_dev)(struct usb_hcd *, struct usb_device *); - void (*free_dev)(struct usb_hcd *, struct usb_device *); - int (*alloc_streams)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint **, unsigned int, unsigned int, gfp_t); - int (*free_streams)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint **, unsigned int, gfp_t); - int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); - int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); - int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); - void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); - int (*address_device)(struct usb_hcd *, struct usb_device *); - int (*enable_device)(struct usb_hcd *, struct usb_device *); - int (*update_hub_device)(struct usb_hcd *, struct usb_device *, struct usb_tt *, gfp_t); - int (*reset_device)(struct usb_hcd *, struct usb_device *); - int (*update_device)(struct usb_hcd *, struct usb_device *); - int (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int); - int (*enable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state); - int (*disable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state); - int (*find_raw_port_number)(struct usb_hcd *, int); - int (*port_power)(struct usb_hcd *, int, bool); - int (*submit_single_step_set_feature)(struct usb_hcd *, struct urb *, int); -}; - -struct physdev_dbgp_op { - uint8_t op; - uint8_t bus; - union { - struct physdev_pci_device pci; - } u; -}; - -struct pcpu { - struct list_head list; - struct device dev; - uint32_t cpu_id; - uint32_t flags; -}; - -typedef uint8_t xen_domain_handle_t[16]; - -struct xen_compile_info { - char compiler[64]; - char compile_by[16]; - char compile_domain[32]; - char compile_date[32]; -}; - -struct xen_platform_parameters { - xen_ulong_t virt_start; -}; - -struct xen_build_id { - uint32_t len; - unsigned char buf[0]; -}; - -struct hyp_sysfs_attr { - struct attribute attr; - ssize_t (*show)(struct hyp_sysfs_attr *, char *); - ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t); - void *hyp_attr_data; -}; - -struct pmu_mode { - const char *name; - uint32_t mode; -}; - -enum xen_swiotlb_err { - XEN_SWIOTLB_UNKNOWN = 0, - XEN_SWIOTLB_ENOMEM = 1, - XEN_SWIOTLB_EFIXUP = 2, -}; - -struct mcinfo_common { - uint16_t type; - uint16_t size; -}; - -struct mcinfo_global { - struct mcinfo_common common; - uint16_t mc_domid; - uint16_t mc_vcpuid; - uint32_t mc_socketid; - uint16_t mc_coreid; - uint16_t mc_core_threadid; - uint32_t mc_apicid; - uint32_t mc_flags; - uint64_t mc_gstatus; -}; - -struct mcinfo_bank { - struct mcinfo_common common; - uint16_t mc_bank; - uint16_t mc_domid; - uint64_t mc_status; - uint64_t mc_addr; - uint64_t mc_misc; - uint64_t mc_ctrl2; - uint64_t mc_tsc; -}; - -struct mcinfo_msr { - uint64_t reg; - uint64_t value; -}; - -struct mc_info { - uint32_t mi_nentries; - uint32_t flags; - uint64_t mi_data[95]; -}; - -typedef struct mc_info *__guest_handle_mc_info; - -struct mcinfo_logical_cpu { - uint32_t mc_cpunr; - uint32_t mc_chipid; - uint16_t mc_coreid; - uint16_t mc_threadid; - uint32_t mc_apicid; - uint32_t mc_clusterid; - uint32_t mc_ncores; - uint32_t mc_ncores_active; - uint32_t mc_nthreads; - uint32_t mc_cpuid_level; - uint32_t mc_family; - uint32_t mc_vendor; - uint32_t mc_model; - uint32_t mc_step; - char mc_vendorid[16]; - char mc_brandid[64]; - uint32_t mc_cpu_caps[7]; - uint32_t mc_cache_size; - uint32_t mc_cache_alignment; - uint32_t mc_nmsrvals; - struct mcinfo_msr mc_msrvalues[8]; -}; - -typedef struct mcinfo_logical_cpu *__guest_handle_mcinfo_logical_cpu; - -struct xen_mc_fetch { - uint32_t flags; - uint32_t _pad0; - uint64_t fetch_id; - __guest_handle_mc_info data; -}; - -struct xen_mc_notifydomain { - uint16_t mc_domid; - uint16_t mc_vcpuid; - uint32_t flags; -}; - -struct xen_mc_physcpuinfo { - uint32_t ncpus; - uint32_t _pad0; - __guest_handle_mcinfo_logical_cpu info; -}; - -struct xen_mc_msrinject { - uint32_t mcinj_cpunr; - uint32_t mcinj_flags; - uint32_t mcinj_count; - uint32_t _pad0; - struct mcinfo_msr mcinj_msr[8]; -}; - -struct xen_mc_mceinject { - unsigned int mceinj_cpunr; -}; - -struct xen_mc { - uint32_t cmd; - uint32_t interface_version; - union { - struct xen_mc_fetch mc_fetch; - struct xen_mc_notifydomain mc_notifydomain; - struct xen_mc_physcpuinfo mc_physcpuinfo; - struct xen_mc_msrinject mc_msrinject; - struct xen_mc_mceinject mc_mceinject; - } u; -}; - -struct xen_mce { - __u64 status; - __u64 misc; - __u64 addr; - __u64 mcgstatus; - __u64 ip; - __u64 tsc; - __u64 time; - __u8 cpuvendor; - __u8 inject_flags; - __u16 pad; - __u32 cpuid; - __u8 cs; - __u8 bank; - __u8 cpu; - __u8 finished; - __u32 extcpu; - __u32 socketid; - __u32 apicid; - __u64 mcgcap; - __u64 synd; - __u64 ipid; - __u64 ppin; -}; - -struct xen_mce_log { - char signature[12]; - unsigned int len; - unsigned int next; - unsigned int flags; - unsigned int recordlen; - struct xen_mce entry[32]; -}; - -typedef int *__guest_handle_int; - -typedef xen_ulong_t *__guest_handle_xen_ulong_t; - -struct xen_add_to_physmap_range { - domid_t domid; - uint16_t space; - uint16_t size; - domid_t foreign_domid; - __guest_handle_xen_ulong_t idxs; - __guest_handle_xen_pfn_t gpfns; - __guest_handle_int errs; -}; - -struct xen_remove_from_physmap { - domid_t domid; - xen_pfn_t gpfn; -}; - -typedef void (*xen_gfn_fn_t)(long unsigned int, void *); - -struct xen_remap_gfn_info; - -struct remap_data___2 { - xen_pfn_t *fgfn; - int nr_fgfn; - pgprot_t prot; - domid_t domid; - struct vm_area_struct *vma; - int index; - struct page **pages; - struct xen_remap_gfn_info *info; - int *err_ptr; - int mapped; - int h_errs[1]; - xen_ulong_t h_idxs[1]; - xen_pfn_t h_gpfns[1]; - int h_iter; -}; - -struct map_balloon_pages { - xen_pfn_t *pfns; - unsigned int idx; -}; - -struct remap_pfn { - struct mm_struct *mm; - struct page **pages; - pgprot_t prot; - long unsigned int i; -}; - -struct fastopen_queue { - struct request_sock *rskq_rst_head; - struct request_sock *rskq_rst_tail; - spinlock_t lock; - int qlen; - int max_qlen; - struct tcp_fastopen_context *ctx; -}; - -struct request_sock_queue { - spinlock_t rskq_lock; - u8 rskq_defer_accept; - u32 synflood_warned; - atomic_t qlen; - atomic_t young; - struct request_sock *rskq_accept_head; - struct request_sock *rskq_accept_tail; - struct fastopen_queue fastopenq; -}; - -struct inet_connection_sock_af_ops { - int (*queue_xmit)(struct sock *, struct sk_buff *, struct flowi *); - void (*send_check)(struct sock *, struct sk_buff *); - int (*rebuild_header)(struct sock *); - void (*sk_rx_dst_set)(struct sock *, const struct sk_buff *); - int (*conn_request)(struct sock *, struct sk_buff *); - struct sock * (*syn_recv_sock)(const struct sock *, struct sk_buff *, struct request_sock *, struct dst_entry *, struct request_sock *, bool *); - u16 net_header_len; - u16 net_frag_header_len; - u16 sockaddr_len; - int (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int); - int (*getsockopt)(struct sock *, int, int, char *, int *); - void (*addr2sockaddr)(struct sock *, struct sockaddr *); - void (*mtu_reduced)(struct sock *); -}; - -struct inet_bind_bucket; - -struct tcp_ulp_ops; - -struct inet_connection_sock { - struct inet_sock icsk_inet; - struct request_sock_queue icsk_accept_queue; - struct inet_bind_bucket *icsk_bind_hash; - long unsigned int icsk_timeout; - struct timer_list icsk_retransmit_timer; - struct timer_list icsk_delack_timer; - __u32 icsk_rto; - __u32 icsk_rto_min; - __u32 icsk_delack_max; - __u32 icsk_pmtu_cookie; - const struct tcp_congestion_ops *icsk_ca_ops; - const struct inet_connection_sock_af_ops *icsk_af_ops; - const struct tcp_ulp_ops *icsk_ulp_ops; - void *icsk_ulp_data; - void (*icsk_clean_acked)(struct sock *, u32); - struct hlist_node icsk_listen_portaddr_node; - unsigned int (*icsk_sync_mss)(struct sock *, u32); - __u8 icsk_ca_state: 5; - __u8 icsk_ca_initialized: 1; - __u8 icsk_ca_setsockopt: 1; - __u8 icsk_ca_dst_locked: 1; - __u8 icsk_retransmits; - __u8 icsk_pending; - __u8 icsk_backoff; - __u8 icsk_syn_retries; - __u8 icsk_probes_out; - __u16 icsk_ext_hdr_len; - struct { - __u8 pending; - __u8 quick; - __u8 pingpong; - __u8 retry; - __u32 ato; - long unsigned int timeout; - __u32 lrcvtime; - __u16 last_seg_size; - __u16 rcv_mss; - } icsk_ack; - struct { - int search_high; - int search_low; - u32 probe_size: 31; - u32 enabled: 1; - u32 probe_timestamp; - } icsk_mtup; - u32 icsk_probes_tstamp; - u32 icsk_user_timeout; - u64 icsk_ca_priv[13]; -}; - -struct tcp_ulp_ops { - struct list_head list; - int (*init)(struct sock *); - void (*update)(struct sock *, struct proto *, void (*)(struct sock *)); - void (*release)(struct sock *); - int (*get_info)(const struct sock *, struct sk_buff *); - size_t (*get_info_size)(const struct sock *); - void (*clone)(const struct request_sock *, struct sock *, const gfp_t); - char name[16]; - struct module *owner; -}; - -typedef unsigned int RING_IDX; - -struct pvcalls_data_intf { - RING_IDX in_cons; - RING_IDX in_prod; - RING_IDX in_error; - uint8_t pad1[52]; - RING_IDX out_cons; - RING_IDX out_prod; - RING_IDX out_error; - uint8_t pad2[52]; - RING_IDX ring_order; - grant_ref_t ref[0]; -}; - -struct pvcalls_data { - unsigned char *in; - unsigned char *out; -}; - -struct xen_pvcalls_socket { - uint64_t id; - uint32_t domain; - uint32_t type; - uint32_t protocol; -}; - -struct xen_pvcalls_connect { - uint64_t id; - uint8_t addr[28]; - uint32_t len; - uint32_t flags; - grant_ref_t ref; - uint32_t evtchn; -}; - -struct xen_pvcalls_release { - uint64_t id; - uint8_t reuse; -}; - -struct xen_pvcalls_bind { - uint64_t id; - uint8_t addr[28]; - uint32_t len; -}; - -struct xen_pvcalls_listen { - uint64_t id; - uint32_t backlog; -}; - -struct xen_pvcalls_accept { - uint64_t id; - uint64_t id_new; - grant_ref_t ref; - uint32_t evtchn; -}; - -struct xen_pvcalls_poll { - uint64_t id; -}; - -struct xen_pvcalls_dummy { - uint8_t dummy[56]; -}; - -struct xen_pvcalls_request { - uint32_t req_id; - uint32_t cmd; - union { - struct xen_pvcalls_socket socket; - struct xen_pvcalls_connect connect; - struct xen_pvcalls_release release; - struct xen_pvcalls_bind bind; - struct xen_pvcalls_listen listen; - struct xen_pvcalls_accept accept; - struct xen_pvcalls_poll poll; - struct xen_pvcalls_dummy dummy; - } u; -}; - -struct _xen_pvcalls_socket { - uint64_t id; -}; - -struct _xen_pvcalls_connect { - uint64_t id; -}; - -struct _xen_pvcalls_release { - uint64_t id; -}; - -struct _xen_pvcalls_bind { - uint64_t id; -}; - -struct _xen_pvcalls_listen { - uint64_t id; -}; - -struct _xen_pvcalls_accept { - uint64_t id; -}; - -struct _xen_pvcalls_poll { - uint64_t id; -}; - -struct _xen_pvcalls_dummy { - uint8_t dummy[8]; -}; - -struct xen_pvcalls_response { - uint32_t req_id; - uint32_t cmd; - int32_t ret; - uint32_t pad; - union { - struct _xen_pvcalls_socket socket; - struct _xen_pvcalls_connect connect; - struct _xen_pvcalls_release release; - struct _xen_pvcalls_bind bind; - struct _xen_pvcalls_listen listen; - struct _xen_pvcalls_accept accept; - struct _xen_pvcalls_poll poll; - struct _xen_pvcalls_dummy dummy; - } u; -}; - -union xen_pvcalls_sring_entry { - struct xen_pvcalls_request req; - struct xen_pvcalls_response rsp; -}; - -struct xen_pvcalls_sring { - RING_IDX req_prod; - RING_IDX req_event; - RING_IDX rsp_prod; - RING_IDX rsp_event; - uint8_t __pad[48]; - union xen_pvcalls_sring_entry ring[1]; -}; - -struct xen_pvcalls_back_ring { - RING_IDX rsp_prod_pvt; - RING_IDX req_cons; - unsigned int nr_ents; - struct xen_pvcalls_sring *sring; -}; - -struct pvcalls_back_global { - struct list_head frontends; - struct semaphore frontends_lock; -}; - -struct pvcalls_fedata { - struct list_head list; - struct xenbus_device *dev; - struct xen_pvcalls_sring *sring; - struct xen_pvcalls_back_ring ring; - int irq; - struct list_head socket_mappings; - struct xarray socketpass_mappings; - struct semaphore socket_lock; -}; - -struct pvcalls_ioworker { - struct work_struct register_work; - struct workqueue_struct *wq; -}; - -struct sockpass_mapping; - -struct sock_mapping { - struct list_head list; - struct pvcalls_fedata *fedata; - struct sockpass_mapping *sockpass; - struct socket *sock; - uint64_t id; - grant_ref_t ref; - struct pvcalls_data_intf *ring; - void *bytes; - struct pvcalls_data data; - uint32_t ring_order; - int irq; - atomic_t read; - atomic_t write; - atomic_t io; - atomic_t release; - atomic_t eoi; - void (*saved_data_ready)(struct sock *); - struct pvcalls_ioworker ioworker; -}; - -struct sockpass_mapping { - struct list_head list; - struct pvcalls_fedata *fedata; - struct socket *sock; - uint64_t id; - struct xen_pvcalls_request reqcopy; - spinlock_t copy_lock; - struct workqueue_struct *wq; - struct work_struct register_work; - void (*saved_data_ready)(struct sock *); -}; - -struct ww_class { - atomic_long_t stamp; - struct lock_class_key acquire_key; - struct lock_class_key mutex_key; - const char *acquire_name; - const char *mutex_name; - unsigned int is_wait_die; -}; - -struct pre_voltage_change_data { - long unsigned int old_uV; - long unsigned int min_uV; - long unsigned int max_uV; -}; - -struct regulator_bulk_data { - const char *supply; - struct regulator *consumer; - int ret; -}; - -struct regulator_voltage { - int min_uV; - int max_uV; -}; - -struct regulator { - struct device *dev; - struct list_head list; - unsigned int always_on: 1; - unsigned int bypass: 1; - unsigned int device_link: 1; - int uA_load; - unsigned int enable_count; - unsigned int deferred_disables; - struct regulator_voltage voltage[5]; - const char *supply_name; - struct device_attribute dev_attr; - struct regulator_dev *rdev; - struct dentry *debugfs; -}; - -struct regulator_coupler { - struct list_head list; - int (*attach_regulator)(struct regulator_coupler *, struct regulator_dev *); - int (*detach_regulator)(struct regulator_coupler *, struct regulator_dev *); - int (*balance_voltage)(struct regulator_coupler *, struct regulator_dev *, suspend_state_t); -}; - -enum regulator_status { - REGULATOR_STATUS_OFF = 0, - REGULATOR_STATUS_ON = 1, - REGULATOR_STATUS_ERROR = 2, - REGULATOR_STATUS_FAST = 3, - REGULATOR_STATUS_NORMAL = 4, - REGULATOR_STATUS_IDLE = 5, - REGULATOR_STATUS_STANDBY = 6, - REGULATOR_STATUS_BYPASS = 7, - REGULATOR_STATUS_UNDEFINED = 8, -}; - -enum regulator_detection_severity { - REGULATOR_SEVERITY_PROT = 0, - REGULATOR_SEVERITY_ERR = 1, - REGULATOR_SEVERITY_WARN = 2, -}; - -struct regulator_enable_gpio { - struct list_head list; - struct gpio_desc *gpiod; - u32 enable_count; - u32 request_count; -}; - -enum regulator_active_discharge { - REGULATOR_ACTIVE_DISCHARGE_DEFAULT = 0, - REGULATOR_ACTIVE_DISCHARGE_DISABLE = 1, - REGULATOR_ACTIVE_DISCHARGE_ENABLE = 2, -}; - -struct regulator_consumer_supply { - const char *dev_name; - const char *supply; -}; - -struct trace_event_raw_regulator_basic { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_regulator_range { - struct trace_entry ent; - u32 __data_loc_name; - int min; - int max; - char __data[0]; -}; - -struct trace_event_raw_regulator_value { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int val; - char __data[0]; -}; - -struct trace_event_data_offsets_regulator_basic { - u32 name; -}; - -struct trace_event_data_offsets_regulator_range { - u32 name; -}; - -struct trace_event_data_offsets_regulator_value { - u32 name; -}; - -typedef void (*btf_trace_regulator_enable)(void *, const char *); - -typedef void (*btf_trace_regulator_enable_delay)(void *, const char *); - -typedef void (*btf_trace_regulator_enable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_disable)(void *, const char *); - -typedef void (*btf_trace_regulator_disable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_enable)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_enable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_disable)(void *, const char *); - -typedef void (*btf_trace_regulator_bypass_disable_complete)(void *, const char *); - -typedef void (*btf_trace_regulator_set_voltage)(void *, const char *, int, int); - -typedef void (*btf_trace_regulator_set_voltage_complete)(void *, const char *, unsigned int); - -enum regulator_get_type { - NORMAL_GET = 0, - EXCLUSIVE_GET = 1, - OPTIONAL_GET = 2, - MAX_GET_TYPE = 3, -}; - -struct regulator_map { - struct list_head list; - const char *dev_name; - const char *supply; - struct regulator_dev *regulator; -}; - -struct regulator_supply_alias { - struct list_head list; - struct device *src_dev; - const char *src_supply; - struct device *alias_dev; - const char *alias_supply; -}; - -struct summary_data { - struct seq_file *s; - struct regulator_dev *parent; - int level; -}; - -struct summary_lock_data { - struct ww_acquire_ctx *ww_ctx; - struct regulator_dev **new_contended_rdev; - struct regulator_dev **old_contended_rdev; -}; - -struct fixed_voltage_config { - const char *supply_name; - const char *input_supply; - int microvolts; - unsigned int startup_delay; - unsigned int off_on_delay; - unsigned int enabled_at_boot: 1; - struct regulator_init_data *init_data; -}; - -struct fixed_regulator_data { - struct fixed_voltage_config cfg; - struct regulator_init_data init_data; - struct platform_device pdev; -}; - -struct regulator_err_state { - struct regulator_dev *rdev; - long unsigned int notifs; - long unsigned int errors; - int possible_errs; -}; - -struct regulator_irq_data { - struct regulator_err_state *states; - int num_states; - void *data; - long int opaque; -}; - -struct regulator_irq_desc { - const char *name; - int irq_flags; - int fatal_cnt; - int reread_ms; - int irq_off_ms; - bool skip_off; - bool high_prio; - void *data; - int (*die)(struct regulator_irq_data *); - int (*map_event)(int, struct regulator_irq_data *, long unsigned int *); - int (*renable)(struct regulator_irq_data *); -}; - -struct regulator_bulk_devres { - struct regulator_bulk_data *consumers; - int num_consumers; -}; - -struct regulator_supply_alias_match { - struct device *dev; - const char *id; -}; - -struct regulator_notifier_match { - struct regulator *regulator; - struct notifier_block *nb; -}; - -enum { - REGULATOR_ERROR_CLEARED = 0, - REGULATOR_FAILED_RETRY = 1, - REGULATOR_ERROR_ON = 2, -}; - -struct regulator_irq { - struct regulator_irq_data rdata; - struct regulator_irq_desc desc; - int irq; - int retry_cnt; - struct delayed_work isr_work; -}; - -struct reset_control___2; - -struct reset_control_bulk_data { - const char *id; - struct reset_control___2 *rstc; -}; - -struct reset_controller_dev; - -struct reset_control___2 { - struct reset_controller_dev *rcdev; - struct list_head list; - unsigned int id; - struct kref refcnt; - bool acquired; - bool shared; - bool array; - atomic_t deassert_count; - atomic_t triggered_count; -}; - -struct reset_control_ops { - int (*reset)(struct reset_controller_dev *, long unsigned int); - int (*assert)(struct reset_controller_dev *, long unsigned int); - int (*deassert)(struct reset_controller_dev *, long unsigned int); - int (*status)(struct reset_controller_dev *, long unsigned int); -}; - -struct reset_controller_dev { - const struct reset_control_ops *ops; - struct module *owner; - struct list_head list; - struct list_head reset_control_head; - struct device *dev; - struct device_node *of_node; - int of_reset_n_cells; - int (*of_xlate)(struct reset_controller_dev *, const struct of_phandle_args *); - unsigned int nr_resets; -}; - -struct reset_control_lookup { - struct list_head list; - const char *provider; - unsigned int index; - const char *dev_id; - const char *con_id; -}; - -struct reset_control_array { - struct reset_control___2 base; - unsigned int num_rstcs; - struct reset_control___2 *rstc[0]; -}; - -struct reset_control_bulk_devres { - int num_rstcs; - struct reset_control_bulk_data *rstcs; -}; - -struct serial_struct32 { - compat_int_t type; - compat_int_t line; - compat_uint_t port; - compat_int_t irq; - compat_int_t flags; - compat_int_t xmit_fifo_size; - compat_int_t custom_divisor; - compat_int_t baud_base; - short unsigned int close_delay; - char io_type; - char reserved_char; - compat_int_t hub6; - short unsigned int closing_wait; - short unsigned int closing_wait2; - compat_uint_t iomem_base; - short unsigned int iomem_reg_shift; - unsigned int port_high; - compat_int_t reserved; -}; - -struct n_tty_data { - size_t read_head; - size_t commit_head; - size_t canon_head; - size_t echo_head; - size_t echo_commit; - size_t echo_mark; - long unsigned int char_map[4]; - long unsigned int overrun_time; - int num_overrun; - bool no_room; - unsigned char lnext: 1; - unsigned char erasing: 1; - unsigned char raw: 1; - unsigned char real_raw: 1; - unsigned char icanon: 1; - unsigned char push: 1; - char read_buf[4096]; - long unsigned int read_flags[64]; - unsigned char echo_buf[4096]; - size_t read_tail; - size_t line_start; - unsigned int column; - unsigned int canon_column; - size_t echo_tail; - struct mutex atomic_read_lock; - struct mutex output_lock; -}; - -enum { - ERASE = 0, - WERASE = 1, - KILL = 2, -}; - -struct termios { - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[19]; -}; - -struct termios2 { - tcflag_t c_iflag; - tcflag_t c_oflag; - tcflag_t c_cflag; - tcflag_t c_lflag; - cc_t c_line; - cc_t c_cc[19]; - speed_t c_ispeed; - speed_t c_ospeed; -}; - -struct termio { - short unsigned int c_iflag; - short unsigned int c_oflag; - short unsigned int c_cflag; - short unsigned int c_lflag; - unsigned char c_line; - unsigned char c_cc[8]; -}; - -struct ldsem_waiter { - struct list_head list; - struct task_struct *task; -}; - -struct pts_fs_info___2; - -struct tty_audit_buf { - struct mutex mutex; - dev_t dev; - unsigned int icanon: 1; - size_t valid; - unsigned char *data; -}; - -struct sysrq_state { - struct input_handle handle; - struct work_struct reinject_work; - long unsigned int key_down[12]; - unsigned int alt; - unsigned int alt_use; - unsigned int shift; - unsigned int shift_use; - bool active; - bool need_reinject; - bool reinjecting; - bool reset_canceled; - bool reset_requested; - long unsigned int reset_keybit[12]; - int reset_seq_len; - int reset_seq_cnt; - int reset_seq_version; - struct timer_list keyreset_timer; -}; - -struct unipair { - short unsigned int unicode; - short unsigned int fontpos; -}; - -struct unimapdesc { - short unsigned int entry_ct; - struct unipair *entries; -}; - -struct kbentry { - unsigned char kb_table; - unsigned char kb_index; - short unsigned int kb_value; -}; - -struct kbsentry { - unsigned char kb_func; - unsigned char kb_string[512]; -}; - -struct kbkeycode { - unsigned int scancode; - unsigned int keycode; -}; - -struct kbd_repeat { - int delay; - int period; -}; - -struct console_font_op { - unsigned int op; - unsigned int flags; - unsigned int width; - unsigned int height; - unsigned int charcount; - unsigned char *data; -}; - -struct vt_stat { - short unsigned int v_active; - short unsigned int v_signal; - short unsigned int v_state; -}; - -struct vt_sizes { - short unsigned int v_rows; - short unsigned int v_cols; - short unsigned int v_scrollsize; -}; - -struct vt_consize { - short unsigned int v_rows; - short unsigned int v_cols; - short unsigned int v_vlin; - short unsigned int v_clin; - short unsigned int v_vcol; - short unsigned int v_ccol; -}; - -struct vt_event { - unsigned int event; - unsigned int oldev; - unsigned int newev; - unsigned int pad[4]; -}; - -struct vt_setactivate { - unsigned int console; - struct vt_mode mode; -}; - -struct vt_spawn_console { - spinlock_t lock; - struct pid *pid; - int sig; -}; - -struct vt_event_wait { - struct list_head list; - struct vt_event event; - int done; -}; - -struct compat_console_font_op { - compat_uint_t op; - compat_uint_t flags; - compat_uint_t width; - compat_uint_t height; - compat_uint_t charcount; - compat_caddr_t data; -}; - -struct compat_unimapdesc { - short unsigned int entry_ct; - compat_caddr_t entries; -}; - -struct vt_notifier_param { - struct vc_data *vc; - unsigned int c; -}; - -struct vcs_poll_data { - struct notifier_block notifier; - unsigned int cons_num; - int event; - wait_queue_head_t waitq; - struct fasync_struct *fasync; -}; - -struct tiocl_selection { - short unsigned int xs; - short unsigned int ys; - short unsigned int xe; - short unsigned int ye; - short unsigned int sel_mode; -}; - -struct vc_selection { - struct mutex lock; - struct vc_data *cons; - char *buffer; - unsigned int buf_len; - volatile int start; - int end; -}; - -struct kbdiacr { - unsigned char diacr; - unsigned char base; - unsigned char result; -}; - -struct kbdiacrs { - unsigned int kb_cnt; - struct kbdiacr kbdiacr[256]; -}; - -struct kbdiacruc { - unsigned int diacr; - unsigned int base; - unsigned int result; -}; - -struct kbdiacrsuc { - unsigned int kb_cnt; - struct kbdiacruc kbdiacruc[256]; -}; - -struct keyboard_notifier_param { - struct vc_data *vc; - int down; - int shift; - int ledstate; - unsigned int value; -}; - -struct kbd_struct { - unsigned char lockstate; - unsigned char slockstate; - unsigned char ledmode: 1; - unsigned char ledflagstate: 4; - char: 3; - unsigned char default_ledflagstate: 4; - unsigned char kbdmode: 3; - char: 1; - unsigned char modeflags: 5; -}; - -typedef void k_handler_fn(struct vc_data *, unsigned char, char); - -typedef void fn_handler_fn(struct vc_data *); - -struct getset_keycode_data { - struct input_keymap_entry ke; - int error; -}; - -struct kbd_led_trigger { - struct led_trigger trigger; - unsigned int mask; -}; - -struct uni_pagedir { - u16 **uni_pgdir[32]; - long unsigned int refcount; - long unsigned int sum; - unsigned char *inverse_translations[4]; - u16 *inverse_trans_unicode; -}; - -typedef uint32_t char32_t; - -struct uni_screen { - char32_t *lines[0]; -}; - -struct con_driver { - const struct consw *con; - const char *desc; - struct device *dev; - int node; - int first; - int last; - int flag; -}; - -enum { - blank_off = 0, - blank_normal_wait = 1, - blank_vesa_wait = 2, -}; - -enum { - EPecma = 0, - EPdec = 1, - EPeq = 2, - EPgt = 3, - EPlt = 4, -}; - -struct rgb { - u8 r; - u8 g; - u8 b; -}; - -enum { - ESnormal = 0, - ESesc = 1, - ESsquare = 2, - ESgetpars = 3, - ESfunckey = 4, - EShash = 5, - ESsetG0 = 6, - ESsetG1 = 7, - ESpercent = 8, - EScsiignore = 9, - ESnonstd = 10, - ESpalette = 11, - ESosc = 12, -}; - -struct interval { - uint32_t first; - uint32_t last; -}; - -struct vc_draw_region { - long unsigned int from; - long unsigned int to; - int x; -}; - -struct hv_ops; - -struct hvc_struct { - struct tty_port port; - spinlock_t lock; - int index; - int do_wakeup; - char *outbuf; - int outbuf_size; - int n_outbuf; - uint32_t vtermno; - const struct hv_ops *ops; - int irq_requested; - int data; - struct winsize ws; - struct work_struct tty_resize; - struct list_head next; - long unsigned int flags; -}; - -struct hv_ops { - int (*get_chars)(uint32_t, char *, int); - int (*put_chars)(uint32_t, const char *, int); - int (*flush)(uint32_t, bool); - int (*notifier_add)(struct hvc_struct *, int); - void (*notifier_del)(struct hvc_struct *, int); - void (*notifier_hangup)(struct hvc_struct *, int); - int (*tiocmget)(struct hvc_struct *); - int (*tiocmset)(struct hvc_struct *, unsigned int, unsigned int); - void (*dtr_rts)(struct hvc_struct *, int); -}; - -struct earlycon_device { - struct console *con; - struct uart_port port; - char options[16]; - unsigned int baud; -}; - -struct earlycon_id { - char name[15]; - char name_term; - char compatible[128]; - int (*setup)(struct earlycon_device *, const char *); -}; - -typedef uint32_t XENCONS_RING_IDX; - -struct xencons_interface { - char in[1024]; - char out[2048]; - XENCONS_RING_IDX in_cons; - XENCONS_RING_IDX in_prod; - XENCONS_RING_IDX out_cons; - XENCONS_RING_IDX out_prod; -}; - -struct xencons_info { - struct list_head list; - struct xenbus_device *xbdev; - struct xencons_interface *intf; - unsigned int evtchn; - struct hvc_struct *hvc; - int irq; - int vtermno; - grant_ref_t gntref; -}; - -struct uart_driver { - struct module *owner; - const char *driver_name; - const char *dev_name; - int major; - int minor; - int nr; - struct console *cons; - struct uart_state *state; - struct tty_driver *tty_driver; -}; - -struct uart_match { - struct uart_port *port; - struct uart_driver *driver; -}; - -enum hwparam_type { - hwparam_ioport = 0, - hwparam_iomem = 1, - hwparam_ioport_or_iomem = 2, - hwparam_irq = 3, - hwparam_dma = 4, - hwparam_dma_addr = 5, - hwparam_other = 6, -}; - -struct plat_serial8250_port { - long unsigned int iobase; - void *membase; - resource_size_t mapbase; - unsigned int irq; - long unsigned int irqflags; - unsigned int uartclk; - void *private_data; - unsigned char regshift; - unsigned char iotype; - unsigned char hub6; - unsigned char has_sysrq; - upf_t flags; - unsigned int type; - unsigned int (*serial_in)(struct uart_port *, int); - void (*serial_out)(struct uart_port *, int, int); - void (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *); - void (*set_ldisc)(struct uart_port *, struct ktermios *); - unsigned int (*get_mctrl)(struct uart_port *); - int (*handle_irq)(struct uart_port *); - void (*pm)(struct uart_port *, unsigned int, unsigned int); - void (*handle_break)(struct uart_port *); -}; - -enum { - PLAT8250_DEV_LEGACY = 4294967295, - PLAT8250_DEV_PLATFORM = 0, - PLAT8250_DEV_PLATFORM1 = 1, - PLAT8250_DEV_PLATFORM2 = 2, - PLAT8250_DEV_FOURPORT = 3, - PLAT8250_DEV_ACCENT = 4, - PLAT8250_DEV_BOCA = 5, - PLAT8250_DEV_EXAR_ST16C554 = 6, - PLAT8250_DEV_HUB6 = 7, - PLAT8250_DEV_AU1X00 = 8, - PLAT8250_DEV_SM501 = 9, -}; - -struct uart_8250_port; - -struct uart_8250_ops { - int (*setup_irq)(struct uart_8250_port *); - void (*release_irq)(struct uart_8250_port *); -}; - -struct mctrl_gpios; - -struct uart_8250_dma; - -struct uart_8250_em485; - -struct uart_8250_port { - struct uart_port port; - struct timer_list timer; - struct list_head list; - u32 capabilities; - short unsigned int bugs; - bool fifo_bug; - unsigned int tx_loadsz; - unsigned char acr; - unsigned char fcr; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned char mcr_mask; - unsigned char mcr_force; - unsigned char cur_iotype; - unsigned int rpm_tx_active; - unsigned char canary; - unsigned char probe; - struct mctrl_gpios *gpios; - unsigned char lsr_saved_flags; - unsigned char msr_saved_flags; - struct uart_8250_dma *dma; - const struct uart_8250_ops *ops; - int (*dl_read)(struct uart_8250_port *); - void (*dl_write)(struct uart_8250_port *, int); - struct uart_8250_em485 *em485; - void (*rs485_start_tx)(struct uart_8250_port *); - void (*rs485_stop_tx)(struct uart_8250_port *); - struct delayed_work overrun_backoff; - u32 overrun_backoff_time_ms; -}; - -struct uart_8250_em485 { - struct hrtimer start_tx_timer; - struct hrtimer stop_tx_timer; - struct hrtimer *active_timer; - struct uart_8250_port *port; - unsigned int tx_stopped: 1; -}; - -struct uart_8250_dma { - int (*tx_dma)(struct uart_8250_port *); - int (*rx_dma)(struct uart_8250_port *); - dma_filter_fn fn; - void *rx_param; - void *tx_param; - struct dma_slave_config rxconf; - struct dma_slave_config txconf; - struct dma_chan___2 *rxchan; - struct dma_chan___2 *txchan; - phys_addr_t rx_dma_addr; - phys_addr_t tx_dma_addr; - dma_addr_t rx_addr; - dma_addr_t tx_addr; - dma_cookie_t rx_cookie; - dma_cookie_t tx_cookie; - void *rx_buf; - size_t rx_size; - size_t tx_size; - unsigned char tx_running; - unsigned char tx_err; - unsigned char rx_running; -}; - -struct old_serial_port { - unsigned int uart; - unsigned int baud_base; - unsigned int port; - unsigned int irq; - upf_t flags; - unsigned char io_type; - unsigned char *iomem_base; - short unsigned int iomem_reg_shift; -}; - -struct irq_info___2 { - struct hlist_node node; - int irq; - spinlock_t lock; - struct list_head *head; -}; - -struct serial8250_config { - const char *name; - short unsigned int fifo_size; - short unsigned int tx_loadsz; - unsigned char fcr; - unsigned char rxtrig_bytes[4]; - unsigned int flags; -}; - -struct dw8250_port_data { - int line; - struct uart_8250_dma dma; - u8 dlf_size; -}; - -struct fintek_8250 { - u16 pid; - u16 base_port; - u8 index; - u8 key; -}; - -struct pciserial_board { - unsigned int flags; - unsigned int num_ports; - unsigned int base_baud; - unsigned int uart_offset; - unsigned int reg_shift; - unsigned int first_offset; -}; - -struct serial_private; - -struct pci_serial_quirk { - u32 vendor; - u32 device; - u32 subvendor; - u32 subdevice; - int (*probe)(struct pci_dev *); - int (*init)(struct pci_dev *); - int (*setup)(struct serial_private *, const struct pciserial_board *, struct uart_8250_port *, int); - void (*exit)(struct pci_dev *); -}; - -struct serial_private { - struct pci_dev *dev; - unsigned int nr; - struct pci_serial_quirk *quirk; - const struct pciserial_board *board; - int line[0]; -}; - -struct f815xxa_data { - spinlock_t lock; - int idx; -}; - -struct timedia_struct { - int num; - const short unsigned int *ids; -}; - -struct quatech_feature { - u16 devid; - bool amcc; -}; - -enum pci_board_num_t { - pbn_default = 0, - pbn_b0_1_115200 = 1, - pbn_b0_2_115200 = 2, - pbn_b0_4_115200 = 3, - pbn_b0_5_115200 = 4, - pbn_b0_8_115200 = 5, - pbn_b0_1_921600 = 6, - pbn_b0_2_921600 = 7, - pbn_b0_4_921600 = 8, - pbn_b0_2_1130000 = 9, - pbn_b0_4_1152000 = 10, - pbn_b0_4_1250000 = 11, - pbn_b0_2_1843200 = 12, - pbn_b0_4_1843200 = 13, - pbn_b0_1_3906250 = 14, - pbn_b0_bt_1_115200 = 15, - pbn_b0_bt_2_115200 = 16, - pbn_b0_bt_4_115200 = 17, - pbn_b0_bt_8_115200 = 18, - pbn_b0_bt_1_460800 = 19, - pbn_b0_bt_2_460800 = 20, - pbn_b0_bt_4_460800 = 21, - pbn_b0_bt_1_921600 = 22, - pbn_b0_bt_2_921600 = 23, - pbn_b0_bt_4_921600 = 24, - pbn_b0_bt_8_921600 = 25, - pbn_b1_1_115200 = 26, - pbn_b1_2_115200 = 27, - pbn_b1_4_115200 = 28, - pbn_b1_8_115200 = 29, - pbn_b1_16_115200 = 30, - pbn_b1_1_921600 = 31, - pbn_b1_2_921600 = 32, - pbn_b1_4_921600 = 33, - pbn_b1_8_921600 = 34, - pbn_b1_2_1250000 = 35, - pbn_b1_bt_1_115200 = 36, - pbn_b1_bt_2_115200 = 37, - pbn_b1_bt_4_115200 = 38, - pbn_b1_bt_2_921600 = 39, - pbn_b1_1_1382400 = 40, - pbn_b1_2_1382400 = 41, - pbn_b1_4_1382400 = 42, - pbn_b1_8_1382400 = 43, - pbn_b2_1_115200 = 44, - pbn_b2_2_115200 = 45, - pbn_b2_4_115200 = 46, - pbn_b2_8_115200 = 47, - pbn_b2_1_460800 = 48, - pbn_b2_4_460800 = 49, - pbn_b2_8_460800 = 50, - pbn_b2_16_460800 = 51, - pbn_b2_1_921600 = 52, - pbn_b2_4_921600 = 53, - pbn_b2_8_921600 = 54, - pbn_b2_8_1152000 = 55, - pbn_b2_bt_1_115200 = 56, - pbn_b2_bt_2_115200 = 57, - pbn_b2_bt_4_115200 = 58, - pbn_b2_bt_2_921600 = 59, - pbn_b2_bt_4_921600 = 60, - pbn_b3_2_115200 = 61, - pbn_b3_4_115200 = 62, - pbn_b3_8_115200 = 63, - pbn_b4_bt_2_921600 = 64, - pbn_b4_bt_4_921600 = 65, - pbn_b4_bt_8_921600 = 66, - pbn_panacom = 67, - pbn_panacom2 = 68, - pbn_panacom4 = 69, - pbn_plx_romulus = 70, - pbn_endrun_2_4000000 = 71, - pbn_oxsemi = 72, - pbn_oxsemi_1_3906250 = 73, - pbn_oxsemi_2_3906250 = 74, - pbn_oxsemi_4_3906250 = 75, - pbn_oxsemi_8_3906250 = 76, - pbn_intel_i960 = 77, - pbn_sgi_ioc3 = 78, - pbn_computone_4 = 79, - pbn_computone_6 = 80, - pbn_computone_8 = 81, - pbn_sbsxrsio = 82, - pbn_pasemi_1682M = 83, - pbn_ni8430_2 = 84, - pbn_ni8430_4 = 85, - pbn_ni8430_8 = 86, - pbn_ni8430_16 = 87, - pbn_ADDIDATA_PCIe_1_3906250 = 88, - pbn_ADDIDATA_PCIe_2_3906250 = 89, - pbn_ADDIDATA_PCIe_4_3906250 = 90, - pbn_ADDIDATA_PCIe_8_3906250 = 91, - pbn_ce4100_1_115200 = 92, - pbn_omegapci = 93, - pbn_NETMOS9900_2s_115200 = 94, - pbn_brcm_trumanage = 95, - pbn_fintek_4 = 96, - pbn_fintek_8 = 97, - pbn_fintek_12 = 98, - pbn_fintek_F81504A = 99, - pbn_fintek_F81508A = 100, - pbn_fintek_F81512A = 101, - pbn_wch382_2 = 102, - pbn_wch384_4 = 103, - pbn_wch384_8 = 104, - pbn_pericom_PI7C9X7951 = 105, - pbn_pericom_PI7C9X7952 = 106, - pbn_pericom_PI7C9X7954 = 107, - pbn_pericom_PI7C9X7958 = 108, - pbn_sunix_pci_1s = 109, - pbn_sunix_pci_2s = 110, - pbn_sunix_pci_4s = 111, - pbn_sunix_pci_8s = 112, - pbn_sunix_pci_16s = 113, - pbn_titan_1_4000000 = 114, - pbn_titan_2_4000000 = 115, - pbn_titan_4_4000000 = 116, - pbn_titan_8_4000000 = 117, - pbn_moxa8250_2p = 118, - pbn_moxa8250_4p = 119, - pbn_moxa8250_8p = 120, -}; - -struct lpss8250; - -struct lpss8250_board { - long unsigned int freq; - unsigned int base_baud; - int (*setup)(struct lpss8250 *, struct uart_port *); - void (*exit)(struct lpss8250 *); -}; - -struct lpss8250 { - struct dw8250_port_data data; - struct lpss8250_board *board; - struct dw_dma_chip dma_chip; - struct dw_dma_slave dma_param; - u8 dma_maxburst; -}; - -struct hsu_dma_slave { - struct device *dma_dev; - int chan_id; -}; - -struct mid8250; - -struct mid8250_board { - unsigned int flags; - long unsigned int freq; - unsigned int base_baud; - int (*setup)(struct mid8250 *, struct uart_port *); - void (*exit)(struct mid8250 *); -}; - -struct mid8250 { - int line; - int dma_index; - struct pci_dev *dma_dev; - struct uart_8250_dma dma; - struct mid8250_board *board; - struct hsu_dma_chip dma_chip; -}; - -struct gpio_array___2; - -enum mctrl_gpio_idx { - UART_GPIO_CTS = 0, - UART_GPIO_DSR = 1, - UART_GPIO_DCD = 2, - UART_GPIO_RNG = 3, - UART_GPIO_RI = 3, - UART_GPIO_RTS = 4, - UART_GPIO_DTR = 5, - UART_GPIO_MAX = 6, -}; - -struct mctrl_gpios___2 { - struct uart_port *port; - struct gpio_desc *gpio[6]; - int irq[6]; - unsigned int mctrl_prev; - bool mctrl_on; -}; - -struct serdev_device; - -struct serdev_device_ops { - int (*receive_buf)(struct serdev_device *, const unsigned char *, size_t); - void (*write_wakeup)(struct serdev_device *); -}; - -struct serdev_controller; - -struct serdev_device { - struct device dev; - int nr; - struct serdev_controller *ctrl; - const struct serdev_device_ops *ops; - struct completion write_comp; - struct mutex write_lock; -}; - -struct serdev_controller_ops; - -struct serdev_controller { - struct device dev; - unsigned int nr; - struct serdev_device *serdev; - const struct serdev_controller_ops *ops; -}; - -struct serdev_device_driver { - struct device_driver driver; - int (*probe)(struct serdev_device *); - void (*remove)(struct serdev_device *); -}; - -enum serdev_parity { - SERDEV_PARITY_NONE = 0, - SERDEV_PARITY_EVEN = 1, - SERDEV_PARITY_ODD = 2, -}; - -struct serdev_controller_ops { - int (*write_buf)(struct serdev_controller *, const unsigned char *, size_t); - void (*write_flush)(struct serdev_controller *); - int (*write_room)(struct serdev_controller *); - int (*open)(struct serdev_controller *); - void (*close)(struct serdev_controller *); - void (*set_flow_control)(struct serdev_controller *, bool); - int (*set_parity)(struct serdev_controller *, enum serdev_parity); - unsigned int (*set_baudrate)(struct serdev_controller *, unsigned int); - void (*wait_until_sent)(struct serdev_controller *, long int); - int (*get_tiocm)(struct serdev_controller *); - int (*set_tiocm)(struct serdev_controller *, unsigned int, unsigned int); -}; - -struct acpi_serdev_lookup { - acpi_handle device_handle; - acpi_handle controller_handle; - int n; - int index; -}; - -struct serport { - struct tty_port *port; - struct tty_struct *tty; - struct tty_driver *tty_drv; - int tty_idx; - long unsigned int flags; -}; - -struct memdev { - const char *name; - umode_t mode; - const struct file_operations *fops; - fmode_t fmode; -}; - -struct timer_rand_state { - cycles_t last_time; - long int last_delta; - long int last_delta2; -}; - -struct trace_event_raw_add_device_randomness { - struct trace_entry ent; - int bytes; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_random__mix_pool_bytes { - struct trace_entry ent; - const char *pool_name; - int bytes; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_credit_entropy_bits { - struct trace_entry ent; - const char *pool_name; - int bits; - int entropy_count; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_debit_entropy { - struct trace_entry ent; - const char *pool_name; - int debit_bits; - char __data[0]; -}; - -struct trace_event_raw_add_input_randomness { - struct trace_entry ent; - int input_bits; - char __data[0]; -}; - -struct trace_event_raw_add_disk_randomness { - struct trace_entry ent; - dev_t dev; - int input_bits; - char __data[0]; -}; - -struct trace_event_raw_random__get_random_bytes { - struct trace_entry ent; - int nbytes; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_random__extract_entropy { - struct trace_entry ent; - const char *pool_name; - int nbytes; - int entropy_count; - long unsigned int IP; - char __data[0]; -}; - -struct trace_event_raw_urandom_read { - struct trace_entry ent; - int got_bits; - int pool_left; - int input_left; - char __data[0]; -}; - -struct trace_event_raw_prandom_u32 { - struct trace_entry ent; - unsigned int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_add_device_randomness {}; - -struct trace_event_data_offsets_random__mix_pool_bytes {}; - -struct trace_event_data_offsets_credit_entropy_bits {}; - -struct trace_event_data_offsets_debit_entropy {}; - -struct trace_event_data_offsets_add_input_randomness {}; - -struct trace_event_data_offsets_add_disk_randomness {}; - -struct trace_event_data_offsets_random__get_random_bytes {}; - -struct trace_event_data_offsets_random__extract_entropy {}; - -struct trace_event_data_offsets_urandom_read {}; - -struct trace_event_data_offsets_prandom_u32 {}; - -typedef void (*btf_trace_add_device_randomness)(void *, int, long unsigned int); - -typedef void (*btf_trace_mix_pool_bytes)(void *, const char *, int, long unsigned int); - -typedef void (*btf_trace_mix_pool_bytes_nolock)(void *, const char *, int, long unsigned int); - -typedef void (*btf_trace_credit_entropy_bits)(void *, const char *, int, int, long unsigned int); - -typedef void (*btf_trace_debit_entropy)(void *, const char *, int); - -typedef void (*btf_trace_add_input_randomness)(void *, int); - -typedef void (*btf_trace_add_disk_randomness)(void *, dev_t, int); - -typedef void (*btf_trace_get_random_bytes)(void *, int, long unsigned int); - -typedef void (*btf_trace_get_random_bytes_arch)(void *, int, long unsigned int); - -typedef void (*btf_trace_extract_entropy)(void *, const char *, int, int, long unsigned int); - -typedef void (*btf_trace_urandom_read)(void *, int, int, int); - -typedef void (*btf_trace_prandom_u32)(void *, unsigned int); - -struct poolinfo { - int poolbitshift; - int poolwords; - int poolbytes; - int poolfracbits; - int tap1; - int tap2; - int tap3; - int tap4; - int tap5; -}; - -struct crng_state { - __u32 state[16]; - long unsigned int init_time; - spinlock_t lock; -}; - -struct entropy_store { - const struct poolinfo *poolinfo; - __u32 *pool; - const char *name; - spinlock_t lock; - short unsigned int add_ptr; - short unsigned int input_rotate; - int entropy_count; - unsigned int last_data_init: 1; - __u8 last_data[10]; -}; - -struct fast_pool { - __u32 pool[4]; - long unsigned int last; - short unsigned int reg_idx; - unsigned char count; -}; - -struct batched_entropy { - union { - u64 entropy_u64[8]; - u32 entropy_u32[16]; - }; - unsigned int position; - spinlock_t batch_lock; -}; - -struct hpet_info { - long unsigned int hi_ireqfreq; - long unsigned int hi_flags; - short unsigned int hi_hpet; - short unsigned int hi_timer; -}; - -struct hpet_timer { - u64 hpet_config; - union { - u64 _hpet_hc64; - u32 _hpet_hc32; - long unsigned int _hpet_compare; - } _u1; - u64 hpet_fsb[2]; -}; - -struct hpet { - u64 hpet_cap; - u64 res0; - u64 hpet_config; - u64 res1; - u64 hpet_isr; - u64 res2[25]; - union { - u64 _hpet_mc64; - u32 _hpet_mc32; - long unsigned int _hpet_mc; - } _u0; - u64 res3; - struct hpet_timer hpet_timers[1]; -}; - -struct hpets; - -struct hpet_dev { - struct hpets *hd_hpets; - struct hpet *hd_hpet; - struct hpet_timer *hd_timer; - long unsigned int hd_ireqfreq; - long unsigned int hd_irqdata; - wait_queue_head_t hd_waitqueue; - struct fasync_struct *hd_async_queue; - unsigned int hd_flags; - unsigned int hd_irq; - unsigned int hd_hdwirq; - char hd_name[7]; -}; - -struct hpets { - struct hpets *hp_next; - struct hpet *hp_hpet; - long unsigned int hp_hpet_phys; - struct clocksource *hp_clocksource; - long long unsigned int hp_tick_freq; - long unsigned int hp_delta; - unsigned int hp_ntimer; - unsigned int hp_which; - struct hpet_dev hp_dev[0]; -}; - -struct compat_hpet_info { - compat_ulong_t hi_ireqfreq; - compat_ulong_t hi_flags; - short unsigned int hi_hpet; - short unsigned int hi_timer; -}; - -struct nvram_ops { - ssize_t (*get_size)(); - unsigned char (*read_byte)(int); - void (*write_byte)(unsigned char, int); - ssize_t (*read)(char *, size_t, loff_t *); - ssize_t (*write)(char *, size_t, loff_t *); - long int (*initialize)(); - long int (*set_checksum)(); -}; - -struct vcpu_data; - -struct amd_iommu_pi_data { - u32 ga_tag; - u32 prev_ga_tag; - u64 base; - bool is_guest_mode; - struct vcpu_data *vcpu_data; - void *ir_data; -}; - -struct vcpu_data { - u64 pi_desc_addr; - u32 vector; -}; - -struct amd_iommu_device_info { - int max_pasids; - u32 flags; -}; - -enum io_pgtable_fmt { - ARM_32_LPAE_S1 = 0, - ARM_32_LPAE_S2 = 1, - ARM_64_LPAE_S1 = 2, - ARM_64_LPAE_S2 = 3, - ARM_V7S = 4, - ARM_MALI_LPAE = 5, - AMD_IOMMU_V1 = 6, - IO_PGTABLE_NUM_FMTS = 7, -}; - -struct iommu_flush_ops { - void (*tlb_flush_all)(void *); - void (*tlb_flush_walk)(long unsigned int, size_t, size_t, void *); - void (*tlb_add_page)(struct iommu_iotlb_gather *, long unsigned int, size_t, void *); -}; - -struct io_pgtable_cfg { - long unsigned int quirks; - long unsigned int pgsize_bitmap; - unsigned int ias; - unsigned int oas; - bool coherent_walk; - const struct iommu_flush_ops *tlb; - struct device *iommu_dev; - union { - struct { - u64 ttbr; - struct { - u32 ips: 3; - u32 tg: 2; - u32 sh: 2; - u32 orgn: 2; - u32 irgn: 2; - u32 tsz: 6; - } tcr; - u64 mair; - } arm_lpae_s1_cfg; - struct { - u64 vttbr; - struct { - u32 ps: 3; - u32 tg: 2; - u32 sh: 2; - u32 orgn: 2; - u32 irgn: 2; - u32 sl: 2; - u32 tsz: 6; - } vtcr; - } arm_lpae_s2_cfg; - struct { - u32 ttbr; - u32 tcr; - u32 nmrr; - u32 prrr; - } arm_v7s_cfg; - struct { - u64 transtab; - u64 memattr; - } arm_mali_lpae_cfg; - }; -}; - -struct io_pgtable_ops { - int (*map)(struct io_pgtable_ops *, long unsigned int, phys_addr_t, size_t, int, gfp_t); - size_t (*unmap)(struct io_pgtable_ops *, long unsigned int, size_t, struct iommu_iotlb_gather *); - phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *, long unsigned int); -}; - -struct io_pgtable { - enum io_pgtable_fmt fmt; - void *cookie; - struct io_pgtable_cfg cfg; - struct io_pgtable_ops ops; -}; - -struct irq_remap_table { - raw_spinlock_t lock; - unsigned int min_index; - u32 *table; -}; - -struct amd_iommu_fault { - u64 address; - u32 pasid; - u16 device_id; - u16 tag; - u16 flags; -}; - -struct amd_io_pgtable { - struct io_pgtable_cfg pgtbl_cfg; - struct io_pgtable iop; - int mode; - u64 *root; - atomic64_t pt_root; -}; - -struct protection_domain { - struct list_head dev_list; - struct iommu_domain domain; - struct amd_io_pgtable iop; - spinlock_t lock; - u16 id; - int glx; - u64 *gcr3_tbl; - long unsigned int flags; - unsigned int dev_cnt; - unsigned int dev_iommu[32]; -}; - -struct amd_irte_ops; - -struct amd_iommu___2 { - struct list_head list; - int index; - raw_spinlock_t lock; - struct pci_dev *dev; - struct pci_dev *root_pdev; - u64 mmio_phys; - u64 mmio_phys_end; - u8 *mmio_base; - u32 cap; - u8 acpi_flags; - u64 features; - bool is_iommu_v2; - u16 devid; - u16 cap_ptr; - u16 pci_seg; - u64 exclusion_start; - u64 exclusion_length; - u8 *cmd_buf; - u32 cmd_buf_head; - u32 cmd_buf_tail; - u8 *evt_buf; - u8 *ppr_log; - u8 *ga_log; - u8 *ga_log_tail; - bool int_enabled; - bool need_sync; - struct iommu_device iommu; - u32 stored_addr_lo; - u32 stored_addr_hi; - u32 stored_l1[108]; - u32 stored_l2[131]; - u8 max_banks; - u8 max_counters; - struct irq_domain *ir_domain; - struct irq_domain *msi_domain; - struct amd_irte_ops *irte_ops; - u32 flags; - volatile u64 *cmd_sem; - u64 cmd_sem_val; - struct irq_affinity_notify intcapxt_notify; -}; - -struct amd_irte_ops { - void (*prepare)(void *, u32, bool, u8, u32, int); - void (*activate)(void *, u16, u16); - void (*deactivate)(void *, u16, u16); - void (*set_affinity)(void *, u16, u16, u8, u32); - void * (*get)(struct irq_remap_table *, int); - void (*set_allocated)(struct irq_remap_table *, int); - bool (*is_allocated)(struct irq_remap_table *, int); - void (*clear_allocated)(struct irq_remap_table *, int); -}; - -struct acpihid_map_entry { - struct list_head list; - u8 uid[256]; - u8 hid[9]; - u16 devid; - u16 root_devid; - bool cmd_line; - struct iommu_group *group; -}; - -struct devid_map { - struct list_head list; - u8 id; - u16 devid; - bool cmd_line; -}; - -struct iommu_dev_data { - spinlock_t lock; - struct list_head list; - struct llist_node dev_data_list; - struct protection_domain *domain; - struct pci_dev *pdev; - u16 devid; - bool iommu_v2; - struct { - bool enabled; - int qdep; - } ats; - bool pri_tlp; - bool use_vapic; - bool defer_attach; - struct ratelimit_state rs; -}; - -struct dev_table_entry { - u64 data[4]; -}; - -struct unity_map_entry { - struct list_head list; - u16 devid_start; - u16 devid_end; - u64 address_start; - u64 address_end; - int prot; -}; - -enum amd_iommu_intr_mode_type { - AMD_IOMMU_GUEST_IR_LEGACY = 0, - AMD_IOMMU_GUEST_IR_LEGACY_GA = 1, - AMD_IOMMU_GUEST_IR_VAPIC = 2, -}; - -union irte { - u32 val; - struct { - u32 valid: 1; - u32 no_fault: 1; - u32 int_type: 3; - u32 rq_eoi: 1; - u32 dm: 1; - u32 rsvd_1: 1; - u32 destination: 8; - u32 vector: 8; - u32 rsvd_2: 8; - } fields; -}; - -union irte_ga_lo { - u64 val; - struct { - u64 valid: 1; - u64 no_fault: 1; - u64 int_type: 3; - u64 rq_eoi: 1; - u64 dm: 1; - u64 guest_mode: 1; - u64 destination: 24; - u64 ga_tag: 32; - } fields_remap; - struct { - u64 valid: 1; - u64 no_fault: 1; - u64 ga_log_intr: 1; - u64 rsvd1: 3; - u64 is_run: 1; - u64 guest_mode: 1; - u64 destination: 24; - u64 ga_tag: 32; - } fields_vapic; -}; - -union irte_ga_hi { - u64 val; - struct { - u64 vector: 8; - u64 rsvd_1: 4; - u64 ga_root_ptr: 40; - u64 rsvd_2: 4; - u64 destination: 8; - } fields; -}; - -struct irte_ga { - union irte_ga_lo lo; - union irte_ga_hi hi; -}; - -struct irq_2_irte { - u16 devid; - u16 index; -}; - -struct amd_ir_data { - u32 cached_ga_tag; - struct irq_2_irte irq_2_irte; - struct msi_msg msi_entry; - void *entry; - void *ref; - struct irq_cfg *cfg; - int ga_vector; - int ga_root_ptr; - int ga_tag; -}; - -struct irq_remap_ops { - int capability; - int (*prepare)(); - int (*enable)(); - void (*disable)(); - int (*reenable)(int); - int (*enable_faulting)(); -}; - -struct iommu_cmd { - u32 data[4]; -}; - -enum irq_remap_cap { - IRQ_POSTING_CAP = 0, -}; - -struct ivhd_header { - u8 type; - u8 flags; - u16 length; - u16 devid; - u16 cap_ptr; - u64 mmio_phys; - u16 pci_seg; - u16 info; - u32 efr_attr; - u64 efr_reg; - u64 res; -}; - -struct ivhd_entry { - u8 type; - u16 devid; - u8 flags; - u32 ext; - u32 hidh; - u64 cid; - u8 uidf; - u8 uidl; - u8 uid; -} __attribute__((packed)); - -struct ivmd_header { - u8 type; - u8 flags; - u16 length; - u16 devid; - u16 aux; - u64 resv; - u64 range_start; - u64 range_length; -}; - -enum iommu_init_state { - IOMMU_START_STATE = 0, - IOMMU_IVRS_DETECTED = 1, - IOMMU_ACPI_FINISHED = 2, - IOMMU_ENABLED = 3, - IOMMU_PCI_INIT = 4, - IOMMU_INTERRUPTS_EN = 5, - IOMMU_INITIALIZED = 6, - IOMMU_NOT_FOUND = 7, - IOMMU_INIT_ERROR = 8, - IOMMU_CMDLINE_DISABLED = 9, -}; - -union intcapxt { - u64 capxt; - struct { - u64 reserved_0: 2; - u64 dest_mode_logical: 1; - u64 reserved_1: 5; - u64 destid_0_23: 24; - u64 vector: 8; - u64 reserved_2: 16; - u64 destid_24_31: 8; - }; -}; - -struct ivrs_quirk_entry { - u8 id; - u16 devid; -}; - -enum { - DELL_INSPIRON_7375 = 0, - DELL_LATITUDE_5495 = 1, - LENOVO_IDEAPAD_330S_15ARR = 2, -}; - -struct io_pgtable_init_fns { - struct io_pgtable * (*alloc)(struct io_pgtable_cfg *, void *); - void (*free)(struct io_pgtable *); -}; - -typedef int (*amd_iommu_invalid_ppr_cb)(struct pci_dev *, u32, long unsigned int, u16); - -typedef void (*amd_iommu_invalidate_ctx)(struct pci_dev *, u32); - -struct pri_queue { - atomic_t inflight; - bool finish; - int status; -}; - -struct device_state; - -struct pasid_state { - struct list_head list; - atomic_t count; - unsigned int mmu_notifier_count; - struct mm_struct *mm; - struct mmu_notifier mn; - struct pri_queue pri[512]; - struct device_state *device_state; - u32 pasid; - bool invalid; - spinlock_t lock; - wait_queue_head_t wq; -}; - -struct device_state { - struct list_head list; - u16 devid; - atomic_t count; - struct pci_dev *pdev; - struct pasid_state **states; - struct iommu_domain *domain; - int pasid_levels; - int max_pasids; - amd_iommu_invalid_ppr_cb inv_ppr_cb; - amd_iommu_invalidate_ctx inv_ctx_cb; - spinlock_t lock; - wait_queue_head_t wq; -}; - -struct fault { - struct work_struct work; - struct device_state *dev_state; - struct pasid_state *state; - struct mm_struct *mm; - u64 address; - u16 devid; - u32 pasid; - u16 tag; - u16 finish; - u16 flags; -}; - -struct acpi_table_dmar { - struct acpi_table_header header; - u8 width; - u8 flags; - u8 reserved[10]; -}; - -struct acpi_dmar_header { - u16 type; - u16 length; -}; - -enum acpi_dmar_type { - ACPI_DMAR_TYPE_HARDWARE_UNIT = 0, - ACPI_DMAR_TYPE_RESERVED_MEMORY = 1, - ACPI_DMAR_TYPE_ROOT_ATS = 2, - ACPI_DMAR_TYPE_HARDWARE_AFFINITY = 3, - ACPI_DMAR_TYPE_NAMESPACE = 4, - ACPI_DMAR_TYPE_SATC = 5, - ACPI_DMAR_TYPE_RESERVED = 6, -}; - -struct acpi_dmar_device_scope { - u8 entry_type; - u8 length; - u16 reserved; - u8 enumeration_id; - u8 bus; -}; - -enum acpi_dmar_scope_type { - ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0, - ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1, - ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2, - ACPI_DMAR_SCOPE_TYPE_IOAPIC = 3, - ACPI_DMAR_SCOPE_TYPE_HPET = 4, - ACPI_DMAR_SCOPE_TYPE_NAMESPACE = 5, - ACPI_DMAR_SCOPE_TYPE_RESERVED = 6, -}; - -struct acpi_dmar_pci_path { - u8 device; - u8 function; -}; - -struct acpi_dmar_hardware_unit { - struct acpi_dmar_header header; - u8 flags; - u8 reserved; - u16 segment; - u64 address; -}; - -struct acpi_dmar_reserved_memory { - struct acpi_dmar_header header; - u16 reserved; - u16 segment; - u64 base_address; - u64 end_address; -}; - -struct acpi_dmar_atsr { - struct acpi_dmar_header header; - u8 flags; - u8 reserved; - u16 segment; -}; - -struct acpi_dmar_rhsa { - struct acpi_dmar_header header; - u32 reserved; - u64 base_address; - u32 proximity_domain; -} __attribute__((packed)); - -struct acpi_dmar_andd { - struct acpi_dmar_header header; - u8 reserved[3]; - u8 device_number; - char device_name[1]; -} __attribute__((packed)); - -struct acpi_dmar_satc { - struct acpi_dmar_header header; - u8 flags; - u8 reserved; - u16 segment; -}; - -struct dmar_dev_scope { - struct device *dev; - u8 bus; - u8 devfn; -}; - -struct intel_iommu; - -struct dmar_drhd_unit { - struct list_head list; - struct acpi_dmar_header *hdr; - u64 reg_base_addr; - struct dmar_dev_scope *devices; - int devices_cnt; - u16 segment; - u8 ignored: 1; - u8 include_all: 1; - u8 gfx_dedicated: 1; - struct intel_iommu *iommu; -}; - -struct iommu_flush { - void (*flush_context)(struct intel_iommu *, u16, u16, u8, u64); - void (*flush_iotlb)(struct intel_iommu *, u16, u64, unsigned int, u64); -}; - -typedef unsigned int ioasid_t; - -typedef ioasid_t (*ioasid_alloc_fn_t)(ioasid_t, ioasid_t, void *); - -typedef void (*ioasid_free_fn_t)(ioasid_t, void *); - -struct ioasid_allocator_ops { - ioasid_alloc_fn_t alloc; - ioasid_free_fn_t free; - struct list_head list; - void *pdata; -}; - -struct iopf_queue; - -struct dmar_domain; - -struct root_entry; - -struct page_req_dsc; - -struct q_inval; - -struct ir_table; - -struct intel_iommu { - void *reg; - u64 reg_phys; - u64 reg_size; - u64 cap; - u64 ecap; - u64 vccap; - u32 gcmd; - raw_spinlock_t register_lock; - int seq_id; - int agaw; - int msagaw; - unsigned int irq; - unsigned int pr_irq; - u16 segment; - unsigned char name[13]; - long unsigned int *domain_ids; - struct dmar_domain ***domains; - spinlock_t lock; - struct root_entry *root_entry; - struct iommu_flush flush; - struct page_req_dsc *prq; - unsigned char prq_name[16]; - struct completion prq_complete; - struct ioasid_allocator_ops pasid_allocator; - struct iopf_queue *iopf_queue; - unsigned char iopfq_name[16]; - struct q_inval *qi; - u32 *iommu_state; - struct ir_table *ir_table; - struct irq_domain *ir_domain; - struct irq_domain *ir_msi_domain; - struct iommu_device iommu; - int node; - u32 flags; - struct dmar_drhd_unit *drhd; - void *perf_statistic; -}; - -struct dmar_pci_path { - u8 bus; - u8 device; - u8 function; -}; - -struct dmar_pci_notify_info { - struct pci_dev *dev; - long unsigned int event; - int bus; - u16 seg; - u16 level; - struct dmar_pci_path path[0]; -}; - -struct irte___2 { - union { - struct { - __u64 present: 1; - __u64 fpd: 1; - __u64 __res0: 6; - __u64 avail: 4; - __u64 __res1: 3; - __u64 pst: 1; - __u64 vector: 8; - __u64 __res2: 40; - }; - struct { - __u64 r_present: 1; - __u64 r_fpd: 1; - __u64 dst_mode: 1; - __u64 redir_hint: 1; - __u64 trigger_mode: 1; - __u64 dlvry_mode: 3; - __u64 r_avail: 4; - __u64 r_res0: 4; - __u64 r_vector: 8; - __u64 r_res1: 8; - __u64 dest_id: 32; - }; - struct { - __u64 p_present: 1; - __u64 p_fpd: 1; - __u64 p_res0: 6; - __u64 p_avail: 4; - __u64 p_res1: 2; - __u64 p_urgent: 1; - __u64 p_pst: 1; - __u64 p_vector: 8; - __u64 p_res2: 14; - __u64 pda_l: 26; - }; - __u64 low; - }; - union { - struct { - __u64 sid: 16; - __u64 sq: 2; - __u64 svt: 2; - __u64 __res3: 44; - }; - struct { - __u64 p_sid: 16; - __u64 p_sq: 2; - __u64 p_svt: 2; - __u64 p_res3: 12; - __u64 pda_h: 32; - }; - __u64 high; - }; -}; - -struct iova { - struct rb_node node; - long unsigned int pfn_hi; - long unsigned int pfn_lo; -}; - -struct iova_magazine; - -struct iova_cpu_rcache; - -struct iova_rcache { - spinlock_t lock; - long unsigned int depot_size; - struct iova_magazine *depot[32]; - struct iova_cpu_rcache *cpu_rcaches; -}; - -struct iova_domain; - -typedef void (*iova_flush_cb)(struct iova_domain *); - -typedef void (*iova_entry_dtor)(long unsigned int); - -struct iova_fq; - -struct iova_domain { - spinlock_t iova_rbtree_lock; - struct rb_root rbroot; - struct rb_node *cached_node; - struct rb_node *cached32_node; - long unsigned int granule; - long unsigned int start_pfn; - long unsigned int dma_32bit_pfn; - long unsigned int max32_alloc_size; - struct iova_fq *fq; - atomic64_t fq_flush_start_cnt; - atomic64_t fq_flush_finish_cnt; - struct iova anchor; - struct iova_rcache rcaches[6]; - iova_flush_cb flush_cb; - iova_entry_dtor entry_dtor; - struct timer_list fq_timer; - atomic_t fq_timer_on; - struct hlist_node cpuhp_dead; -}; - -struct iova_fq_entry { - long unsigned int iova_pfn; - long unsigned int pages; - long unsigned int data; - u64 counter; -}; - -struct iova_fq { - struct iova_fq_entry entries[256]; - unsigned int head; - unsigned int tail; - spinlock_t lock; -}; - -enum { - QI_FREE = 0, - QI_IN_USE = 1, - QI_DONE = 2, - QI_ABORT = 3, -}; - -struct qi_desc { - u64 qw0; - u64 qw1; - u64 qw2; - u64 qw3; -}; - -struct q_inval { - raw_spinlock_t q_lock; - void *desc; - int *desc_status; - int free_head; - int free_tail; - int free_cnt; -}; - -struct ir_table { - struct irte___2 *base; - long unsigned int *bitmap; -}; - -struct root_entry { - u64 lo; - u64 hi; -}; - -struct dma_pte; - -struct dmar_domain { - int nid; - unsigned int iommu_refcnt[128]; - u16 iommu_did[128]; - u8 has_iotlb_device: 1; - u8 iommu_coherency: 1; - u8 iommu_snooping: 1; - struct list_head devices; - struct list_head subdevices; - struct iova_domain iovad; - struct dma_pte *pgd; - int gaw; - int agaw; - int flags; - int iommu_superpage; - u64 max_addr; - u32 default_pasid; - struct iommu_domain domain; -}; - -struct dma_pte { - u64 val; -}; - -enum latency_type { - DMAR_LATENCY_INV_IOTLB = 0, - DMAR_LATENCY_INV_DEVTLB = 1, - DMAR_LATENCY_INV_IEC = 2, - DMAR_LATENCY_PRQ = 3, - DMAR_LATENCY_NUM = 4, -}; - -enum latency_count { - COUNTS_10e2 = 0, - COUNTS_10e3 = 1, - COUNTS_10e4 = 2, - COUNTS_10e5 = 3, - COUNTS_10e6 = 4, - COUNTS_10e7 = 5, - COUNTS_10e8_plus = 6, - COUNTS_MIN = 7, - COUNTS_MAX = 8, - COUNTS_SUM = 9, - COUNTS_NUM = 10, -}; - -typedef int (*dmar_res_handler_t)(struct acpi_dmar_header *, void *); - -struct dmar_res_callback { - dmar_res_handler_t cb[6]; - void *arg[6]; - bool ignore_unhandled; - bool print_entry; -}; - -enum faulttype { - DMA_REMAP = 0, - INTR_REMAP = 1, - UNKNOWN = 2, -}; - -struct ioasid_set { - int dummy; -}; - -enum iommu_inv_granularity { - IOMMU_INV_GRANU_DOMAIN = 0, - IOMMU_INV_GRANU_PASID = 1, - IOMMU_INV_GRANU_ADDR = 2, - IOMMU_INV_GRANU_NR = 3, -}; - -enum { - SR_DMAR_FECTL_REG = 0, - SR_DMAR_FEDATA_REG = 1, - SR_DMAR_FEADDR_REG = 2, - SR_DMAR_FEUADDR_REG = 3, - MAX_SR_DMAR_REGS = 4, -}; - -struct context_entry { - u64 lo; - u64 hi; -}; - -struct subdev_domain_info { - struct list_head link_phys; - struct list_head link_domain; - struct device *pdev; - struct dmar_domain *domain; - int users; -}; - -struct pasid_table; - -struct device_domain_info { - struct list_head link; - struct list_head global; - struct list_head table; - struct list_head subdevices; - u32 segment; - u8 bus; - u8 devfn; - u16 pfsid; - u8 pasid_supported: 3; - u8 pasid_enabled: 1; - u8 pri_supported: 1; - u8 pri_enabled: 1; - u8 ats_supported: 1; - u8 ats_enabled: 1; - u8 auxd_enabled: 1; - u8 ats_qdep; - struct device *dev; - struct intel_iommu *iommu; - struct dmar_domain *domain; - struct pasid_table *pasid_table; -}; - -struct pasid_table { - void *table; - int order; - u32 max_pasid; - struct list_head dev; -}; - -enum cap_audit_type { - CAP_AUDIT_STATIC_DMAR = 0, - CAP_AUDIT_STATIC_IRQR = 1, - CAP_AUDIT_HOTPLUG_DMAR = 2, - CAP_AUDIT_HOTPLUG_IRQR = 3, -}; - -struct dmar_rmrr_unit { - struct list_head list; - struct acpi_dmar_header *hdr; - u64 base_address; - u64 end_address; - struct dmar_dev_scope *devices; - int devices_cnt; -}; - -struct dmar_atsr_unit { - struct list_head list; - struct acpi_dmar_header *hdr; - struct dmar_dev_scope *devices; - int devices_cnt; - u8 include_all: 1; -}; - -struct dmar_satc_unit { - struct list_head list; - struct acpi_dmar_header *hdr; - struct dmar_dev_scope *devices; - struct intel_iommu *iommu; - int devices_cnt; - u8 atc_required: 1; -}; - -struct domain_context_mapping_data { - struct dmar_domain *domain; - struct intel_iommu *iommu; - struct pasid_table *table; -}; - -struct pasid_dir_entry { - u64 val; -}; - -struct pasid_entry { - u64 val[8]; -}; - -struct pasid_table_opaque { - struct pasid_table **pasid_table; - int segment; - int bus; - int devfn; -}; - -struct trace_event_raw_qi_submit { - struct trace_entry ent; - u64 qw0; - u64 qw1; - u64 qw2; - u64 qw3; - u32 __data_loc_iommu; - char __data[0]; -}; - -struct trace_event_raw_prq_report { - struct trace_entry ent; - u64 dw0; - u64 dw1; - u64 dw2; - u64 dw3; - long unsigned int seq; - u32 __data_loc_iommu; - u32 __data_loc_dev; - u32 __data_loc_buff; - char __data[0]; -}; - -struct trace_event_data_offsets_qi_submit { - u32 iommu; -}; - -struct trace_event_data_offsets_prq_report { - u32 iommu; - u32 dev; - u32 buff; -}; - -typedef void (*btf_trace_qi_submit)(void *, struct intel_iommu *, u64, u64, u64, u64); - -typedef void (*btf_trace_prq_report)(void *, struct intel_iommu *, struct device *, u64, u64, u64, u64, long unsigned int); - -enum iommu_fault_type { - IOMMU_FAULT_DMA_UNRECOV = 1, - IOMMU_FAULT_PAGE_REQ = 2, -}; - -struct page_req_dsc { - union { - struct { - u64 type: 8; - u64 pasid_present: 1; - u64 priv_data_present: 1; - u64 rsvd: 6; - u64 rid: 16; - u64 pasid: 20; - u64 exe_req: 1; - u64 pm_req: 1; - u64 rsvd2: 10; - }; - u64 qw_0; - }; - union { - struct { - u64 rd_req: 1; - u64 wr_req: 1; - u64 lpig: 1; - u64 prg_index: 9; - u64 addr: 52; - }; - u64 qw_1; - }; - u64 priv_data[2]; -}; - -struct intel_svm_dev { - struct list_head list; - struct callback_head rcu; - struct device *dev; - struct intel_iommu *iommu; - struct iommu_sva sva; - long unsigned int prq_seq_number; - u32 pasid; - int users; - u16 did; - u16 dev_iotlb: 1; - u16 sid; - u16 qdep; -}; - -struct intel_svm { - struct mmu_notifier notifier; - struct mm_struct *mm; - unsigned int flags; - u32 pasid; - int gpasid; - struct list_head devs; -}; - -enum irq_mode { - IRQ_REMAPPING = 0, - IRQ_POSTING = 1, -}; - -struct ioapic_scope { - struct intel_iommu *iommu; - unsigned int id; - unsigned int bus; - unsigned int devfn; -}; - -struct hpet_scope { - struct intel_iommu *iommu; - u8 id; - unsigned int bus; - unsigned int devfn; -}; - -struct irq_2_iommu { - struct intel_iommu *iommu; - u16 irte_index; - u16 sub_handle; - u8 irte_mask; - enum irq_mode mode; -}; - -struct intel_ir_data { - struct irq_2_iommu irq_2_iommu; - struct irte___2 irte_entry; - union { - struct msi_msg msi_entry; - }; -}; - -struct set_msi_sid_data { - struct pci_dev *pdev; - u16 alias; - int count; - int busmatch_count; -}; - -struct iommu_group { - struct kobject kobj; - struct kobject *devices_kobj; - struct list_head devices; - struct mutex mutex; - struct blocking_notifier_head notifier; - void *iommu_data; - void (*iommu_data_release)(void *); - char *name; - int id; - struct iommu_domain *default_domain; - struct iommu_domain *domain; - struct list_head entry; -}; - -struct fsl_mc_obj_desc { - char type[16]; - int id; - u16 vendor; - u16 ver_major; - u16 ver_minor; - u8 irq_count; - u8 region_count; - u32 state; - char label[16]; - u16 flags; -}; - -struct fsl_mc_io; - -struct fsl_mc_device_irq; - -struct fsl_mc_resource; - -struct fsl_mc_device { - struct device dev; - u64 dma_mask; - u16 flags; - u32 icid; - u16 mc_handle; - struct fsl_mc_io *mc_io; - struct fsl_mc_obj_desc obj_desc; - struct resource *regions; - struct fsl_mc_device_irq **irqs; - struct fsl_mc_resource *resource; - struct device_link *consumer_link; - char *driver_override; -}; - -enum fsl_mc_pool_type { - FSL_MC_POOL_DPMCP = 0, - FSL_MC_POOL_DPBP = 1, - FSL_MC_POOL_DPCON = 2, - FSL_MC_POOL_IRQ = 3, - FSL_MC_NUM_POOL_TYPES = 4, -}; - -struct fsl_mc_resource_pool; - -struct fsl_mc_resource { - enum fsl_mc_pool_type type; - s32 id; - void *data; - struct fsl_mc_resource_pool *parent_pool; - struct list_head node; -}; - -struct fsl_mc_device_irq { - struct msi_desc *msi_desc; - struct fsl_mc_device *mc_dev; - u8 dev_irq_index; - struct fsl_mc_resource resource; -}; - -struct fsl_mc_io { - struct device *dev; - u16 flags; - u32 portal_size; - phys_addr_t portal_phys_addr; - void *portal_virt_addr; - struct fsl_mc_device *dpmcp_dev; - union { - struct mutex mutex; - raw_spinlock_t spinlock; - }; -}; - -struct group_device { - struct list_head list; - struct device *dev; - char *name; -}; - -struct iommu_group_attribute { - struct attribute attr; - ssize_t (*show)(struct iommu_group *, char *); - ssize_t (*store)(struct iommu_group *, const char *, size_t); -}; - -struct group_for_pci_data { - struct pci_dev *pdev; - struct iommu_group *group; -}; - -struct __group_domain_type { - struct device *dev; - unsigned int type; -}; - -struct trace_event_raw_iommu_group_event { - struct trace_entry ent; - int gid; - u32 __data_loc_device; - char __data[0]; -}; - -struct trace_event_raw_iommu_device_event { - struct trace_entry ent; - u32 __data_loc_device; - char __data[0]; -}; - -struct trace_event_raw_map { - struct trace_entry ent; - u64 iova; - u64 paddr; - size_t size; - char __data[0]; -}; - -struct trace_event_raw_unmap { - struct trace_entry ent; - u64 iova; - size_t size; - size_t unmapped_size; - char __data[0]; -}; - -struct trace_event_raw_iommu_error { - struct trace_entry ent; - u32 __data_loc_device; - u32 __data_loc_driver; - u64 iova; - int flags; - char __data[0]; -}; - -struct trace_event_data_offsets_iommu_group_event { - u32 device; -}; - -struct trace_event_data_offsets_iommu_device_event { - u32 device; -}; - -struct trace_event_data_offsets_map {}; - -struct trace_event_data_offsets_unmap {}; - -struct trace_event_data_offsets_iommu_error { - u32 device; - u32 driver; -}; - -typedef void (*btf_trace_add_device_to_group)(void *, int, struct device *); - -typedef void (*btf_trace_remove_device_from_group)(void *, int, struct device *); - -typedef void (*btf_trace_attach_device_to_domain)(void *, struct device *); - -typedef void (*btf_trace_detach_device_from_domain)(void *, struct device *); - -typedef void (*btf_trace_map)(void *, long unsigned int, phys_addr_t, size_t); - -typedef void (*btf_trace_unmap)(void *, long unsigned int, size_t, size_t); - -typedef void (*btf_trace_io_page_fault)(void *, struct device *, long unsigned int, int); - -struct iommu_dma_msi_page { - struct list_head list; - dma_addr_t iova; - phys_addr_t phys; -}; - -enum iommu_dma_cookie_type { - IOMMU_DMA_IOVA_COOKIE = 0, - IOMMU_DMA_MSI_COOKIE = 1, -}; - -struct iommu_dma_cookie { - enum iommu_dma_cookie_type type; - union { - struct iova_domain iovad; - dma_addr_t msi_iova; - }; - struct list_head msi_page_list; - struct iommu_domain *fq_domain; -}; - -struct ioasid_data { - ioasid_t id; - struct ioasid_set *set; - void *private; - struct callback_head rcu; - refcount_t refs; -}; - -struct ioasid_allocator_data { - struct ioasid_allocator_ops *ops; - struct list_head list; - struct list_head slist; - long unsigned int flags; - struct xarray xa; - struct callback_head rcu; -}; - -struct iova_magazine { - long unsigned int size; - long unsigned int pfns[128]; -}; - -struct iova_cpu_rcache { - spinlock_t lock; - struct iova_magazine *loaded; - struct iova_magazine *prev; -}; - -struct hyperv_root_ir_data { - u8 ioapic_id; - bool is_level; - struct hv_interrupt_entry entry; -} __attribute__((packed)); - -enum iommu_page_response_code { - IOMMU_PAGE_RESP_SUCCESS = 0, - IOMMU_PAGE_RESP_INVALID = 1, - IOMMU_PAGE_RESP_FAILURE = 2, -}; - -struct iopf_queue___2; - -struct iopf_device_param { - struct device *dev; - struct iopf_queue___2 *queue; - struct list_head queue_list; - struct list_head partial; -}; - -struct iopf_queue___2 { - struct workqueue_struct *wq; - struct list_head devices; - struct mutex lock; -}; - -struct iopf_fault { - struct iommu_fault fault; - struct list_head list; -}; - -struct iopf_group { - struct iopf_fault last_fault; - struct list_head faults; - struct work_struct work; - struct device *dev; -}; - -struct mipi_dsi_msg { - u8 channel; - u8 type; - u16 flags; - size_t tx_len; - const void *tx_buf; - size_t rx_len; - void *rx_buf; -}; - -struct mipi_dsi_packet { - size_t size; - u8 header[4]; - size_t payload_length; - const u8 *payload; -}; - -struct mipi_dsi_host; - -struct mipi_dsi_device; - -struct mipi_dsi_host_ops { - int (*attach)(struct mipi_dsi_host *, struct mipi_dsi_device *); - int (*detach)(struct mipi_dsi_host *, struct mipi_dsi_device *); - ssize_t (*transfer)(struct mipi_dsi_host *, const struct mipi_dsi_msg *); -}; - -struct mipi_dsi_host { - struct device *dev; - const struct mipi_dsi_host_ops *ops; - struct list_head list; -}; - -enum mipi_dsi_pixel_format { - MIPI_DSI_FMT_RGB888 = 0, - MIPI_DSI_FMT_RGB666 = 1, - MIPI_DSI_FMT_RGB666_PACKED = 2, - MIPI_DSI_FMT_RGB565 = 3, -}; - -struct mipi_dsi_device { - struct mipi_dsi_host *host; - struct device dev; - char name[20]; - unsigned int channel; - unsigned int lanes; - enum mipi_dsi_pixel_format format; - long unsigned int mode_flags; - long unsigned int hs_rate; - long unsigned int lp_rate; -}; - -struct mipi_dsi_device_info { - char type[20]; - u32 channel; - struct device_node *node; -}; - -enum mipi_dsi_dcs_tear_mode { - MIPI_DSI_DCS_TEAR_MODE_VBLANK = 0, - MIPI_DSI_DCS_TEAR_MODE_VHBLANK = 1, -}; - -struct mipi_dsi_driver { - struct device_driver driver; - int (*probe)(struct mipi_dsi_device *); - int (*remove)(struct mipi_dsi_device *); - void (*shutdown)(struct mipi_dsi_device *); -}; - -struct drm_dsc_picture_parameter_set { - u8 dsc_version; - u8 pps_identifier; - u8 pps_reserved; - u8 pps_3; - u8 pps_4; - u8 bits_per_pixel_low; - __be16 pic_height; - __be16 pic_width; - __be16 slice_height; - __be16 slice_width; - __be16 chunk_size; - u8 initial_xmit_delay_high; - u8 initial_xmit_delay_low; - __be16 initial_dec_delay; - u8 pps20_reserved; - u8 initial_scale_value; - __be16 scale_increment_interval; - u8 scale_decrement_interval_high; - u8 scale_decrement_interval_low; - u8 pps26_reserved; - u8 first_line_bpg_offset; - __be16 nfl_bpg_offset; - __be16 slice_bpg_offset; - __be16 initial_offset; - __be16 final_offset; - u8 flatness_min_qp; - u8 flatness_max_qp; - __be16 rc_model_size; - u8 rc_edge_factor; - u8 rc_quant_incr_limit0; - u8 rc_quant_incr_limit1; - u8 rc_tgt_offset; - u8 rc_buf_thresh[14]; - __be16 rc_range_parameters[15]; - u8 native_422_420; - u8 second_line_bpg_offset; - __be16 nsl_bpg_offset; - __be16 second_line_offset_adj; - u32 pps_long_94_reserved; - u32 pps_long_98_reserved; - u32 pps_long_102_reserved; - u32 pps_long_106_reserved; - u32 pps_long_110_reserved; - u32 pps_long_114_reserved; - u32 pps_long_118_reserved; - u32 pps_long_122_reserved; - __be16 pps_short_126_reserved; -} __attribute__((packed)); - -enum { - MIPI_DSI_V_SYNC_START = 1, - MIPI_DSI_V_SYNC_END = 17, - MIPI_DSI_H_SYNC_START = 33, - MIPI_DSI_H_SYNC_END = 49, - MIPI_DSI_COMPRESSION_MODE = 7, - MIPI_DSI_END_OF_TRANSMISSION = 8, - MIPI_DSI_COLOR_MODE_OFF = 2, - MIPI_DSI_COLOR_MODE_ON = 18, - MIPI_DSI_SHUTDOWN_PERIPHERAL = 34, - MIPI_DSI_TURN_ON_PERIPHERAL = 50, - MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 3, - MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 19, - MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 35, - MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 4, - MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 20, - MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 36, - MIPI_DSI_DCS_SHORT_WRITE = 5, - MIPI_DSI_DCS_SHORT_WRITE_PARAM = 21, - MIPI_DSI_DCS_READ = 6, - MIPI_DSI_EXECUTE_QUEUE = 22, - MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 55, - MIPI_DSI_NULL_PACKET = 9, - MIPI_DSI_BLANKING_PACKET = 25, - MIPI_DSI_GENERIC_LONG_WRITE = 41, - MIPI_DSI_DCS_LONG_WRITE = 57, - MIPI_DSI_PICTURE_PARAMETER_SET = 10, - MIPI_DSI_COMPRESSED_PIXEL_STREAM = 11, - MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 12, - MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 28, - MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 44, - MIPI_DSI_PACKED_PIXEL_STREAM_30 = 13, - MIPI_DSI_PACKED_PIXEL_STREAM_36 = 29, - MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 61, - MIPI_DSI_PACKED_PIXEL_STREAM_16 = 14, - MIPI_DSI_PACKED_PIXEL_STREAM_18 = 30, - MIPI_DSI_PIXEL_STREAM_3BYTE_18 = 46, - MIPI_DSI_PACKED_PIXEL_STREAM_24 = 62, -}; - -enum { - MIPI_DCS_NOP = 0, - MIPI_DCS_SOFT_RESET = 1, - MIPI_DCS_GET_COMPRESSION_MODE = 3, - MIPI_DCS_GET_DISPLAY_ID = 4, - MIPI_DCS_GET_ERROR_COUNT_ON_DSI = 5, - MIPI_DCS_GET_RED_CHANNEL = 6, - MIPI_DCS_GET_GREEN_CHANNEL = 7, - MIPI_DCS_GET_BLUE_CHANNEL = 8, - MIPI_DCS_GET_DISPLAY_STATUS = 9, - MIPI_DCS_GET_POWER_MODE = 10, - MIPI_DCS_GET_ADDRESS_MODE = 11, - MIPI_DCS_GET_PIXEL_FORMAT = 12, - MIPI_DCS_GET_DISPLAY_MODE = 13, - MIPI_DCS_GET_SIGNAL_MODE = 14, - MIPI_DCS_GET_DIAGNOSTIC_RESULT = 15, - MIPI_DCS_ENTER_SLEEP_MODE = 16, - MIPI_DCS_EXIT_SLEEP_MODE = 17, - MIPI_DCS_ENTER_PARTIAL_MODE = 18, - MIPI_DCS_ENTER_NORMAL_MODE = 19, - MIPI_DCS_GET_IMAGE_CHECKSUM_RGB = 20, - MIPI_DCS_GET_IMAGE_CHECKSUM_CT = 21, - MIPI_DCS_EXIT_INVERT_MODE = 32, - MIPI_DCS_ENTER_INVERT_MODE = 33, - MIPI_DCS_SET_GAMMA_CURVE = 38, - MIPI_DCS_SET_DISPLAY_OFF = 40, - MIPI_DCS_SET_DISPLAY_ON = 41, - MIPI_DCS_SET_COLUMN_ADDRESS = 42, - MIPI_DCS_SET_PAGE_ADDRESS = 43, - MIPI_DCS_WRITE_MEMORY_START = 44, - MIPI_DCS_WRITE_LUT = 45, - MIPI_DCS_READ_MEMORY_START = 46, - MIPI_DCS_SET_PARTIAL_ROWS = 48, - MIPI_DCS_SET_PARTIAL_COLUMNS = 49, - MIPI_DCS_SET_SCROLL_AREA = 51, - MIPI_DCS_SET_TEAR_OFF = 52, - MIPI_DCS_SET_TEAR_ON = 53, - MIPI_DCS_SET_ADDRESS_MODE = 54, - MIPI_DCS_SET_SCROLL_START = 55, - MIPI_DCS_EXIT_IDLE_MODE = 56, - MIPI_DCS_ENTER_IDLE_MODE = 57, - MIPI_DCS_SET_PIXEL_FORMAT = 58, - MIPI_DCS_WRITE_MEMORY_CONTINUE = 60, - MIPI_DCS_SET_3D_CONTROL = 61, - MIPI_DCS_READ_MEMORY_CONTINUE = 62, - MIPI_DCS_GET_3D_CONTROL = 63, - MIPI_DCS_SET_VSYNC_TIMING = 64, - MIPI_DCS_SET_TEAR_SCANLINE = 68, - MIPI_DCS_GET_SCANLINE = 69, - MIPI_DCS_SET_DISPLAY_BRIGHTNESS = 81, - MIPI_DCS_GET_DISPLAY_BRIGHTNESS = 82, - MIPI_DCS_WRITE_CONTROL_DISPLAY = 83, - MIPI_DCS_GET_CONTROL_DISPLAY = 84, - MIPI_DCS_WRITE_POWER_SAVE = 85, - MIPI_DCS_GET_POWER_SAVE = 86, - MIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 94, - MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 95, - MIPI_DCS_READ_DDB_START = 161, - MIPI_DCS_READ_PPS_START = 162, - MIPI_DCS_READ_DDB_CONTINUE = 168, - MIPI_DCS_READ_PPS_CONTINUE = 169, -}; - -struct drm_dmi_panel_orientation_data { - int width; - int height; - const char * const *bios_dates; - int orientation; -}; - -struct vga_device { - struct list_head list; - struct pci_dev *pdev; - unsigned int decodes; - unsigned int owns; - unsigned int locks; - unsigned int io_lock_cnt; - unsigned int mem_lock_cnt; - unsigned int io_norm_cnt; - unsigned int mem_norm_cnt; - bool bridge_has_one_vga; - void *cookie; - void (*irq_set_state)(void *, bool); - unsigned int (*set_vga_decode)(void *, bool); -}; - -struct vga_arb_user_card { - struct pci_dev *pdev; - unsigned int mem_cnt; - unsigned int io_cnt; -}; - -struct vga_arb_private { - struct list_head list; - struct pci_dev *target; - struct vga_arb_user_card cards[10]; - spinlock_t lock; -}; - -enum vga_switcheroo_handler_flags_t { - VGA_SWITCHEROO_CAN_SWITCH_DDC = 1, - VGA_SWITCHEROO_NEEDS_EDP_CONFIG = 2, -}; - -enum vga_switcheroo_state { - VGA_SWITCHEROO_OFF = 0, - VGA_SWITCHEROO_ON = 1, - VGA_SWITCHEROO_NOT_FOUND = 2, -}; - -enum vga_switcheroo_client_id { - VGA_SWITCHEROO_UNKNOWN_ID = 4096, - VGA_SWITCHEROO_IGD = 0, - VGA_SWITCHEROO_DIS = 1, - VGA_SWITCHEROO_MAX_CLIENTS = 2, -}; - -struct vga_switcheroo_handler { - int (*init)(); - int (*switchto)(enum vga_switcheroo_client_id); - int (*switch_ddc)(enum vga_switcheroo_client_id); - int (*power_state)(enum vga_switcheroo_client_id, enum vga_switcheroo_state); - enum vga_switcheroo_client_id (*get_client_id)(struct pci_dev *); -}; - -struct vga_switcheroo_client_ops { - void (*set_gpu_state)(struct pci_dev *, enum vga_switcheroo_state); - void (*reprobe)(struct pci_dev *); - bool (*can_switch)(struct pci_dev *); - void (*gpu_bound)(struct pci_dev *, enum vga_switcheroo_client_id); -}; - -struct vga_switcheroo_client { - struct pci_dev *pdev; - struct fb_info *fb_info; - enum vga_switcheroo_state pwr_state; - const struct vga_switcheroo_client_ops *ops; - enum vga_switcheroo_client_id id; - bool active; - bool driver_power_control; - struct list_head list; - struct pci_dev *vga_dev; -}; - -struct vgasr_priv { - bool active; - bool delayed_switch_active; - enum vga_switcheroo_client_id delayed_client_id; - struct dentry *debugfs_root; - int registered_clients; - struct list_head clients; - const struct vga_switcheroo_handler *handler; - enum vga_switcheroo_handler_flags_t handler_flags; - struct mutex mux_hw_lock; - int old_ddc_owner; -}; - -struct cb_id { - __u32 idx; - __u32 val; -}; - -struct cn_msg { - struct cb_id id; - __u32 seq; - __u32 ack; - __u16 len; - __u16 flags; - __u8 data[0]; -}; - -struct cn_queue_dev { - atomic_t refcnt; - unsigned char name[32]; - struct list_head queue_list; - spinlock_t queue_lock; - struct sock *nls; -}; - -struct cn_callback_id { - unsigned char name[32]; - struct cb_id id; -}; - -struct cn_callback_entry { - struct list_head callback_entry; - refcount_t refcnt; - struct cn_queue_dev *pdev; - struct cn_callback_id id; - void (*callback)(struct cn_msg *, struct netlink_skb_parms *); - u32 seq; - u32 group; -}; - -struct cn_dev { - struct cb_id id; - u32 seq; - u32 groups; - struct sock *nls; - struct cn_queue_dev *cbdev; -}; - -enum proc_cn_mcast_op { - PROC_CN_MCAST_LISTEN = 1, - PROC_CN_MCAST_IGNORE = 2, -}; - -struct fork_proc_event { - __kernel_pid_t parent_pid; - __kernel_pid_t parent_tgid; - __kernel_pid_t child_pid; - __kernel_pid_t child_tgid; -}; - -struct exec_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; -}; - -struct id_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - union { - __u32 ruid; - __u32 rgid; - } r; - union { - __u32 euid; - __u32 egid; - } e; -}; - -struct sid_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; -}; - -struct ptrace_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - __kernel_pid_t tracer_pid; - __kernel_pid_t tracer_tgid; -}; - -struct comm_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - char comm[16]; -}; - -struct coredump_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - __kernel_pid_t parent_pid; - __kernel_pid_t parent_tgid; -}; - -struct exit_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - __u32 exit_code; - __u32 exit_signal; - __kernel_pid_t parent_pid; - __kernel_pid_t parent_tgid; -}; - -struct proc_event { - enum what what; - __u32 cpu; - __u64 timestamp_ns; - union { - struct { - __u32 err; - } ack; - struct fork_proc_event fork; - struct exec_proc_event exec; - struct id_proc_event id; - struct sid_proc_event sid; - struct ptrace_proc_event ptrace; - struct comm_proc_event comm; - struct coredump_proc_event coredump; - struct exit_proc_event exit; - } event_data; -}; - -struct local_event { - local_lock_t lock; - __u32 count; -}; - -struct nvm_ioctl_info_tgt { - __u32 version[3]; - __u32 reserved; - char tgtname[48]; -}; - -struct nvm_ioctl_info { - __u32 version[3]; - __u16 tgtsize; - __u16 reserved16; - __u32 reserved[12]; - struct nvm_ioctl_info_tgt tgts[63]; -}; - -struct nvm_ioctl_device_info { - char devname[32]; - char bmname[48]; - __u32 bmversion[3]; - __u32 flags; - __u32 reserved[8]; -}; - -struct nvm_ioctl_get_devices { - __u32 nr_devices; - __u32 reserved[31]; - struct nvm_ioctl_device_info info[31]; -}; - -struct nvm_ioctl_create_simple { - __u32 lun_begin; - __u32 lun_end; -}; - -struct nvm_ioctl_create_extended { - __u16 lun_begin; - __u16 lun_end; - __u16 op; - __u16 rsv; -}; - -enum { - NVM_CONFIG_TYPE_SIMPLE = 0, - NVM_CONFIG_TYPE_EXTENDED = 1, -}; - -struct nvm_ioctl_create_conf { - __u32 type; - union { - struct nvm_ioctl_create_simple s; - struct nvm_ioctl_create_extended e; - }; -}; - -enum { - NVM_TARGET_FACTORY = 1, -}; - -struct nvm_ioctl_create { - char dev[32]; - char tgttype[48]; - char tgtname[32]; - __u32 flags; - struct nvm_ioctl_create_conf conf; -}; - -struct nvm_ioctl_remove { - char tgtname[32]; - __u32 flags; -}; - -struct nvm_ioctl_dev_init { - char dev[32]; - char mmtype[8]; - __u32 flags; -}; - -enum { - NVM_FACTORY_ERASE_ONLY_USER = 1, - NVM_FACTORY_RESET_HOST_BLKS = 2, - NVM_FACTORY_RESET_GRWN_BBLKS = 4, - NVM_FACTORY_NR_BITS = 8, -}; - -struct nvm_ioctl_dev_factory { - char dev[32]; - __u32 flags; -}; - -enum { - NVM_INFO_CMD = 32, - NVM_GET_DEVICES_CMD = 33, - NVM_DEV_CREATE_CMD = 34, - NVM_DEV_REMOVE_CMD = 35, - NVM_DEV_INIT_CMD = 36, - NVM_DEV_FACTORY_CMD = 37, - NVM_DEV_VIO_ADMIN_CMD = 65, - NVM_DEV_VIO_CMD = 66, - NVM_DEV_VIO_USER_CMD = 67, -}; - -enum { - NVM_OCSSD_SPEC_12 = 12, - NVM_OCSSD_SPEC_20 = 20, -}; - -struct ppa_addr { - union { - struct { - u64 ch: 8; - u64 lun: 8; - u64 blk: 16; - u64 reserved: 32; - } a; - struct { - u64 ch: 8; - u64 lun: 8; - u64 blk: 16; - u64 pg: 16; - u64 pl: 4; - u64 sec: 4; - u64 reserved: 8; - } g; - struct { - u64 grp: 8; - u64 pu: 8; - u64 chk: 16; - u64 sec: 24; - u64 reserved: 8; - } m; - struct { - u64 line: 63; - u64 is_cached: 1; - } c; - u64 ppa; - }; -}; - -struct nvm_dev; - -typedef int nvm_id_fn(struct nvm_dev *); - -struct nvm_addrf { - u8 ch_len; - u8 lun_len; - u8 chk_len; - u8 sec_len; - u8 rsv_len[2]; - u8 ch_offset; - u8 lun_offset; - u8 chk_offset; - u8 sec_offset; - u8 rsv_off[2]; - u64 ch_mask; - u64 lun_mask; - u64 chk_mask; - u64 sec_mask; - u64 rsv_mask[2]; -}; - -struct nvm_geo { - u8 major_ver_id; - u8 minor_ver_id; - u8 version; - int num_ch; - int num_lun; - int all_luns; - int all_chunks; - int op; - sector_t total_secs; - u32 num_chk; - u32 clba; - u16 csecs; - u16 sos; - bool ext; - u32 mdts; - u32 ws_min; - u32 ws_opt; - u32 mw_cunits; - u32 maxoc; - u32 maxocpu; - u32 mccap; - u32 trdt; - u32 trdm; - u32 tprt; - u32 tprm; - u32 tbet; - u32 tbem; - struct nvm_addrf addrf; - u8 vmnt; - u32 cap; - u32 dom; - u8 mtype; - u8 fmtype; - u16 cpar; - u32 mpos; - u8 num_pln; - u8 pln_mode; - u16 num_pg; - u16 fpg_sz; -}; - -struct nvm_dev_ops; - -struct nvm_dev { - struct nvm_dev_ops *ops; - struct list_head devices; - struct nvm_geo geo; - long unsigned int *lun_map; - void *dma_pool; - struct request_queue *q; - char name[32]; - void *private_data; - struct kref ref; - void *rmap; - struct mutex mlock; - spinlock_t lock; - struct list_head area_list; - struct list_head targets; -}; - -typedef int nvm_op_bb_tbl_fn(struct nvm_dev *, struct ppa_addr, u8 *); - -typedef int nvm_op_set_bb_fn(struct nvm_dev *, struct ppa_addr *, int, int); - -struct nvm_chk_meta; - -typedef int nvm_get_chk_meta_fn(struct nvm_dev *, sector_t, int, struct nvm_chk_meta *); - -struct nvm_chk_meta { - u8 state; - u8 type; - u8 wi; - u8 rsvd[5]; - u64 slba; - u64 cnlb; - u64 wp; -}; - -struct nvm_rq; - -typedef int nvm_submit_io_fn(struct nvm_dev *, struct nvm_rq *, void *); - -typedef void nvm_end_io_fn(struct nvm_rq *); - -struct nvm_tgt_dev; - -struct nvm_rq { - struct nvm_tgt_dev *dev; - struct bio *bio; - union { - struct ppa_addr ppa_addr; - dma_addr_t dma_ppa_list; - }; - struct ppa_addr *ppa_list; - void *meta_list; - dma_addr_t dma_meta_list; - nvm_end_io_fn *end_io; - uint8_t opcode; - uint16_t nr_ppas; - uint16_t flags; - u64 ppa_status; - int error; - int is_seq; - void *private; -}; - -typedef void *nvm_create_dma_pool_fn(struct nvm_dev *, char *, int); - -typedef void nvm_destroy_dma_pool_fn(void *); - -typedef void *nvm_dev_dma_alloc_fn(struct nvm_dev *, void *, gfp_t, dma_addr_t *); - -typedef void nvm_dev_dma_free_fn(void *, void *, dma_addr_t); - -struct nvm_dev_ops { - nvm_id_fn *identity; - nvm_op_bb_tbl_fn *get_bb_tbl; - nvm_op_set_bb_fn *set_bb_tbl; - nvm_get_chk_meta_fn *get_chk_meta; - nvm_submit_io_fn *submit_io; - nvm_create_dma_pool_fn *create_dma_pool; - nvm_destroy_dma_pool_fn *destroy_dma_pool; - nvm_dev_dma_alloc_fn *dev_dma_alloc; - nvm_dev_dma_free_fn *dev_dma_free; -}; - -enum { - NVM_RSP_L2P = 1, - NVM_RSP_ECC = 2, - NVM_ADDRMODE_LINEAR = 0, - NVM_ADDRMODE_CHANNEL = 1, - NVM_PLANE_SINGLE = 1, - NVM_PLANE_DOUBLE = 2, - NVM_PLANE_QUAD = 4, - NVM_RSP_SUCCESS = 0, - NVM_RSP_NOT_CHANGEABLE = 1, - NVM_RSP_ERR_FAILWRITE = 16639, - NVM_RSP_ERR_EMPTYPAGE = 17151, - NVM_RSP_ERR_FAILECC = 17025, - NVM_RSP_ERR_FAILCRC = 16388, - NVM_RSP_WARN_HIGHECC = 18176, - NVM_OP_PWRITE = 145, - NVM_OP_PREAD = 146, - NVM_OP_ERASE = 144, - NVM_IO_SNGL_ACCESS = 0, - NVM_IO_DUAL_ACCESS = 1, - NVM_IO_QUAD_ACCESS = 2, - NVM_IO_SUSPEND = 128, - NVM_IO_SLC_MODE = 256, - NVM_IO_SCRAMBLE_ENABLE = 512, - NVM_BLK_T_FREE = 0, - NVM_BLK_T_BAD = 1, - NVM_BLK_T_GRWN_BAD = 2, - NVM_BLK_T_DEV = 4, - NVM_BLK_T_HOST = 8, - NVM_ID_CAP_SLC = 1, - NVM_ID_CAP_CMD_SUSPEND = 2, - NVM_ID_CAP_SCRAMBLE = 4, - NVM_ID_CAP_ENCRYPT = 8, - NVM_ID_FMTYPE_SLC = 0, - NVM_ID_FMTYPE_MLC = 1, - NVM_ID_DCAP_BBLKMGMT = 1, - NVM_UD_DCAP_ECC = 2, -}; - -struct nvm_addrf_12 { - u8 ch_len; - u8 lun_len; - u8 blk_len; - u8 pg_len; - u8 pln_len; - u8 sec_len; - u8 ch_offset; - u8 lun_offset; - u8 blk_offset; - u8 pg_offset; - u8 pln_offset; - u8 sec_offset; - u64 ch_mask; - u64 lun_mask; - u64 blk_mask; - u64 pg_mask; - u64 pln_mask; - u64 sec_mask; -}; - -enum { - NVM_CHK_ST_FREE = 1, - NVM_CHK_ST_CLOSED = 2, - NVM_CHK_ST_OPEN = 4, - NVM_CHK_ST_OFFLINE = 8, - NVM_CHK_TP_W_SEQ = 1, - NVM_CHK_TP_W_RAN = 2, - NVM_CHK_TP_SZ_SPEC = 16, -}; - -struct nvm_tgt_type; - -struct nvm_target { - struct list_head list; - struct nvm_tgt_dev *dev; - struct nvm_tgt_type *type; - struct gendisk *disk; -}; - -struct nvm_tgt_dev { - struct nvm_geo geo; - struct ppa_addr *luns; - struct request_queue *q; - struct nvm_dev *parent; - void *map; -}; - -typedef sector_t nvm_tgt_capacity_fn(void *); - -typedef void *nvm_tgt_init_fn(struct nvm_tgt_dev *, struct gendisk *, int); - -typedef void nvm_tgt_exit_fn(void *, bool); - -typedef int nvm_tgt_sysfs_init_fn(struct gendisk *); - -typedef void nvm_tgt_sysfs_exit_fn(struct gendisk *); - -struct nvm_tgt_type { - const char *name; - unsigned int version[3]; - int flags; - const struct block_device_operations *bops; - nvm_tgt_capacity_fn *capacity; - nvm_tgt_init_fn *init; - nvm_tgt_exit_fn *exit; - nvm_tgt_sysfs_init_fn *sysfs_init; - nvm_tgt_sysfs_exit_fn *sysfs_exit; - struct list_head list; - struct module *owner; -}; - -enum { - NVM_TGT_F_DEV_L2P = 0, - NVM_TGT_F_HOST_L2P = 1, -}; - -struct nvm_ch_map { - int ch_off; - int num_lun; - int *lun_offs; -}; - -struct nvm_dev_map { - struct nvm_ch_map *chnls; - int num_ch; -}; - -struct component_ops { - int (*bind)(struct device *, struct device *, void *); - void (*unbind)(struct device *, struct device *, void *); -}; - -struct component_master_ops { - int (*bind)(struct device *); - void (*unbind)(struct device *); -}; - -struct component; - -struct component_match_array { - void *data; - int (*compare)(struct device *, void *); - int (*compare_typed)(struct device *, int, void *); - void (*release)(struct device *, void *); - struct component *component; - bool duplicate; -}; - -struct master; - -struct component { - struct list_head node; - struct master *master; - bool bound; - const struct component_ops *ops; - int subcomponent; - struct device *dev; -}; - -struct component_match { - size_t alloc; - size_t num; - struct component_match_array *compare; -}; - -struct master { - struct list_head node; - bool bound; - const struct component_master_ops *ops; - struct device *parent; - struct component_match *match; -}; - -struct fwnode_link { - struct fwnode_handle *supplier; - struct list_head s_hook; - struct fwnode_handle *consumer; - struct list_head c_hook; -}; - -struct wake_irq { - struct device *dev; - unsigned int status; - int irq; - const char *name; -}; - -enum dpm_order { - DPM_ORDER_NONE = 0, - DPM_ORDER_DEV_AFTER_PARENT = 1, - DPM_ORDER_PARENT_BEFORE_DEV = 2, - DPM_ORDER_DEV_LAST = 3, -}; - -struct subsys_private { - struct kset subsys; - struct kset *devices_kset; - struct list_head interfaces; - struct mutex mutex; - struct kset *drivers_kset; - struct klist klist_devices; - struct klist klist_drivers; - struct blocking_notifier_head bus_notifier; - unsigned int drivers_autoprobe: 1; - struct bus_type *bus; - struct kset glue_dirs; - struct class *class; -}; - -struct driver_private { - struct kobject kobj; - struct klist klist_devices; - struct klist_node knode_bus; - struct module_kobject *mkobj; - struct device_driver *driver; -}; - -struct device_private { - struct klist klist_children; - struct klist_node knode_parent; - struct klist_node knode_driver; - struct klist_node knode_bus; - struct klist_node knode_class; - struct list_head deferred_probe; - struct device_driver *async_driver; - char *deferred_probe_reason; - struct device *device; - u8 dead: 1; -}; - -union device_attr_group_devres { - const struct attribute_group *group; - const struct attribute_group **groups; -}; - -struct class_dir { - struct kobject kobj; - struct class *class; -}; - -struct root_device { - struct device dev; - struct module *owner; -}; - -struct subsys_dev_iter { - struct klist_iter ki; - const struct device_type *type; -}; - -struct device_attach_data { - struct device *dev; - bool check_async; - bool want_async; - bool have_async; -}; - -struct class_attribute { - struct attribute attr; - ssize_t (*show)(struct class *, struct class_attribute *, char *); - ssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t); -}; - -struct class_attribute_string { - struct class_attribute attr; - char *str; -}; - -struct class_compat { - struct kobject *kobj; -}; - -struct irq_affinity_devres { - unsigned int count; - unsigned int irq[0]; -}; - -struct platform_object { - struct platform_device pdev; - char name[0]; -}; - -struct cpu_attr { - struct device_attribute attr; - const struct cpumask * const map; -}; - -struct probe { - struct probe *next; - dev_t dev; - long unsigned int range; - struct module *owner; - kobj_probe_t *get; - int (*lock)(dev_t, void *); - void *data; -}; - -struct kobj_map___2 { - struct probe *probes[255]; - struct mutex *lock; -}; - -struct devres_node { - struct list_head entry; - dr_release_t release; - const char *name; - size_t size; -}; - -struct devres___2 { - struct devres_node node; - u8 data[0]; -}; - -struct devres_group { - struct devres_node node[2]; - void *id; - int color; -}; - -struct action_devres { - void *data; - void (*action)(void *); -}; - -struct pages_devres { - long unsigned int addr; - unsigned int order; -}; - -struct attribute_container { - struct list_head node; - struct klist containers; - struct class *class; - const struct attribute_group *grp; - struct device_attribute **attrs; - int (*match)(struct attribute_container *, struct device *); - long unsigned int flags; -}; - -struct internal_container { - struct klist_node node; - struct attribute_container *cont; - struct device classdev; -}; - -struct transport_container; - -struct transport_class { - struct class class; - int (*setup)(struct transport_container *, struct device *, struct device *); - int (*configure)(struct transport_container *, struct device *, struct device *); - int (*remove)(struct transport_container *, struct device *, struct device *); -}; - -struct transport_container { - struct attribute_container ac; - const struct attribute_group *statistics; -}; - -struct anon_transport_class { - struct transport_class tclass; - struct attribute_container container; -}; - -typedef void * (*devcon_match_fn_t)(struct fwnode_handle *, const char *, void *); - -struct mii_bus; - -struct mdio_device { - struct device dev; - struct mii_bus *bus; - char modalias[32]; - int (*bus_match)(struct device *, struct device_driver *); - void (*device_free)(struct mdio_device *); - void (*device_remove)(struct mdio_device *); - int addr; - int flags; - struct gpio_desc *reset_gpio; - struct reset_control *reset_ctrl; - unsigned int reset_assert_delay; - unsigned int reset_deassert_delay; -}; - -struct phy_c45_device_ids { - u32 devices_in_package; - u32 mmds_present; - u32 device_ids[32]; -}; - -enum phy_state { - PHY_DOWN = 0, - PHY_READY = 1, - PHY_HALTED = 2, - PHY_UP = 3, - PHY_RUNNING = 4, - PHY_NOLINK = 5, - PHY_CABLETEST = 6, -}; - -typedef enum { - PHY_INTERFACE_MODE_NA = 0, - PHY_INTERFACE_MODE_INTERNAL = 1, - PHY_INTERFACE_MODE_MII = 2, - PHY_INTERFACE_MODE_GMII = 3, - PHY_INTERFACE_MODE_SGMII = 4, - PHY_INTERFACE_MODE_TBI = 5, - PHY_INTERFACE_MODE_REVMII = 6, - PHY_INTERFACE_MODE_RMII = 7, - PHY_INTERFACE_MODE_REVRMII = 8, - PHY_INTERFACE_MODE_RGMII = 9, - PHY_INTERFACE_MODE_RGMII_ID = 10, - PHY_INTERFACE_MODE_RGMII_RXID = 11, - PHY_INTERFACE_MODE_RGMII_TXID = 12, - PHY_INTERFACE_MODE_RTBI = 13, - PHY_INTERFACE_MODE_SMII = 14, - PHY_INTERFACE_MODE_XGMII = 15, - PHY_INTERFACE_MODE_XLGMII = 16, - PHY_INTERFACE_MODE_MOCA = 17, - PHY_INTERFACE_MODE_QSGMII = 18, - PHY_INTERFACE_MODE_TRGMII = 19, - PHY_INTERFACE_MODE_100BASEX = 20, - PHY_INTERFACE_MODE_1000BASEX = 21, - PHY_INTERFACE_MODE_2500BASEX = 22, - PHY_INTERFACE_MODE_5GBASER = 23, - PHY_INTERFACE_MODE_RXAUI = 24, - PHY_INTERFACE_MODE_XAUI = 25, - PHY_INTERFACE_MODE_10GBASER = 26, - PHY_INTERFACE_MODE_25GBASER = 27, - PHY_INTERFACE_MODE_USXGMII = 28, - PHY_INTERFACE_MODE_10GKR = 29, - PHY_INTERFACE_MODE_MAX = 30, -} phy_interface_t; - -struct phy_led_trigger; - -struct phylink; - -struct phy_driver; - -struct phy_package_shared; - -struct mii_timestamper; - -struct phy_device { - struct mdio_device mdio; - struct phy_driver *drv; - u32 phy_id; - struct phy_c45_device_ids c45_ids; - unsigned int is_c45: 1; - unsigned int is_internal: 1; - unsigned int is_pseudo_fixed_link: 1; - unsigned int is_gigabit_capable: 1; - unsigned int has_fixups: 1; - unsigned int suspended: 1; - unsigned int suspended_by_mdio_bus: 1; - unsigned int sysfs_links: 1; - unsigned int loopback_enabled: 1; - unsigned int downshifted_rate: 1; - unsigned int is_on_sfp_module: 1; - unsigned int mac_managed_pm: 1; - unsigned int autoneg: 1; - unsigned int link: 1; - unsigned int autoneg_complete: 1; - unsigned int interrupts: 1; - enum phy_state state; - u32 dev_flags; - phy_interface_t interface; - int speed; - int duplex; - int port; - int pause; - int asym_pause; - u8 master_slave_get; - u8 master_slave_set; - u8 master_slave_state; - long unsigned int supported[2]; - long unsigned int advertising[2]; - long unsigned int lp_advertising[2]; - long unsigned int adv_old[2]; - u32 eee_broken_modes; - struct phy_led_trigger *phy_led_triggers; - unsigned int phy_num_led_triggers; - struct phy_led_trigger *last_triggered; - struct phy_led_trigger *led_link_trigger; - int irq; - void *priv; - struct phy_package_shared *shared; - struct sk_buff *skb; - void *ehdr; - struct nlattr *nest; - struct delayed_work state_queue; - struct mutex lock; - bool sfp_bus_attached; - struct sfp_bus *sfp_bus; - struct phylink *phylink; - struct net_device *attached_dev; - struct mii_timestamper *mii_ts; - u8 mdix; - u8 mdix_ctrl; - void (*phy_link_change)(struct phy_device *, bool); - void (*adjust_link)(struct net_device *); - const struct macsec_ops *macsec_ops; -}; - -struct phy_tdr_config { - u32 first; - u32 last; - u32 step; - s8 pair; -}; - -struct mdio_bus_stats { - u64_stats_t transfers; - u64_stats_t errors; - u64_stats_t writes; - u64_stats_t reads; - struct u64_stats_sync syncp; -}; - -struct mii_bus { - struct module *owner; - const char *name; - char id[61]; - void *priv; - int (*read)(struct mii_bus *, int, int); - int (*write)(struct mii_bus *, int, int, u16); - int (*reset)(struct mii_bus *); - struct mdio_bus_stats stats[32]; - struct mutex mdio_lock; - struct device *parent; - enum { - MDIOBUS_ALLOCATED = 1, - MDIOBUS_REGISTERED = 2, - MDIOBUS_UNREGISTERED = 3, - MDIOBUS_RELEASED = 4, - } state; - struct device dev; - struct mdio_device *mdio_map[32]; - u32 phy_mask; - u32 phy_ignore_ta_mask; - int irq[32]; - int reset_delay_us; - int reset_post_delay_us; - struct gpio_desc *reset_gpiod; - enum { - MDIOBUS_NO_CAP = 0, - MDIOBUS_C22 = 1, - MDIOBUS_C45 = 2, - MDIOBUS_C22_C45 = 3, - } probe_capabilities; - struct mutex shared_lock; - struct phy_package_shared *shared[32]; -}; - -struct mdio_driver_common { - struct device_driver driver; - int flags; -}; - -struct mii_timestamper { - bool (*rxtstamp)(struct mii_timestamper *, struct sk_buff *, int); - void (*txtstamp)(struct mii_timestamper *, struct sk_buff *, int); - int (*hwtstamp)(struct mii_timestamper *, struct ifreq *); - void (*link_state)(struct mii_timestamper *, struct phy_device *); - int (*ts_info)(struct mii_timestamper *, struct ethtool_ts_info *); - struct device *device; -}; - -struct phy_package_shared { - int addr; - refcount_t refcnt; - long unsigned int flags; - size_t priv_size; - void *priv; -}; - -struct phy_driver { - struct mdio_driver_common mdiodrv; - u32 phy_id; - char *name; - u32 phy_id_mask; - const long unsigned int * const features; - u32 flags; - const void *driver_data; - int (*soft_reset)(struct phy_device *); - int (*config_init)(struct phy_device *); - int (*probe)(struct phy_device *); - int (*get_features)(struct phy_device *); - int (*suspend)(struct phy_device *); - int (*resume)(struct phy_device *); - int (*config_aneg)(struct phy_device *); - int (*aneg_done)(struct phy_device *); - int (*read_status)(struct phy_device *); - int (*config_intr)(struct phy_device *); - irqreturn_t (*handle_interrupt)(struct phy_device *); - void (*remove)(struct phy_device *); - int (*match_phy_device)(struct phy_device *); - int (*set_wol)(struct phy_device *, struct ethtool_wolinfo *); - void (*get_wol)(struct phy_device *, struct ethtool_wolinfo *); - void (*link_change_notify)(struct phy_device *); - int (*read_mmd)(struct phy_device *, int, u16); - int (*write_mmd)(struct phy_device *, int, u16, u16); - int (*read_page)(struct phy_device *); - int (*write_page)(struct phy_device *, int); - int (*module_info)(struct phy_device *, struct ethtool_modinfo *); - int (*module_eeprom)(struct phy_device *, struct ethtool_eeprom *, u8 *); - int (*cable_test_start)(struct phy_device *); - int (*cable_test_tdr_start)(struct phy_device *, const struct phy_tdr_config *); - int (*cable_test_get_status)(struct phy_device *, bool *); - int (*get_sset_count)(struct phy_device *); - void (*get_strings)(struct phy_device *, u8 *); - void (*get_stats)(struct phy_device *, struct ethtool_stats *, u64 *); - int (*get_tunable)(struct phy_device *, struct ethtool_tunable *, void *); - int (*set_tunable)(struct phy_device *, struct ethtool_tunable *, const void *); - int (*set_loopback)(struct phy_device *, bool); - int (*get_sqi)(struct phy_device *); - int (*get_sqi_max)(struct phy_device *); -}; - -struct software_node_ref_args { - const struct software_node *node; - unsigned int nargs; - u64 args[8]; -}; - -struct swnode { - struct kobject kobj; - struct fwnode_handle fwnode; - const struct software_node *node; - int id; - struct ida child_ids; - struct list_head entry; - struct list_head children; - struct swnode *parent; - unsigned int allocated: 1; - unsigned int managed: 1; -}; - -struct auxiliary_device_id { - char name[32]; - kernel_ulong_t driver_data; -}; - -struct auxiliary_device { - struct device dev; - const char *name; - u32 id; -}; - -struct auxiliary_driver { - int (*probe)(struct auxiliary_device *, const struct auxiliary_device_id *); - void (*remove)(struct auxiliary_device *); - void (*shutdown)(struct auxiliary_device *); - int (*suspend)(struct auxiliary_device *, pm_message_t); - int (*resume)(struct auxiliary_device *); - const char *name; - struct device_driver driver; - const struct auxiliary_device_id *id_table; -}; - -struct req { - struct req *next; - struct completion done; - int err; - const char *name; - umode_t mode; - kuid_t uid; - kgid_t gid; - struct device *dev; -}; - -typedef int (*pm_callback_t)(struct device *); - -enum gpd_status { - GENPD_STATE_ON = 0, - GENPD_STATE_OFF = 1, -}; - -enum genpd_notication { - GENPD_NOTIFY_PRE_OFF = 0, - GENPD_NOTIFY_OFF = 1, - GENPD_NOTIFY_PRE_ON = 2, - GENPD_NOTIFY_ON = 3, -}; - -struct dev_power_governor { - bool (*power_down_ok)(struct dev_pm_domain *); - bool (*suspend_ok)(struct device *); -}; - -struct gpd_dev_ops { - int (*start)(struct device *); - int (*stop)(struct device *); -}; - -struct genpd_power_state { - s64 power_off_latency_ns; - s64 power_on_latency_ns; - s64 residency_ns; - u64 usage; - u64 rejected; - struct fwnode_handle *fwnode; - ktime_t idle_time; - void *data; -}; - -struct opp_table; - -struct dev_pm_opp; - -struct genpd_lock_ops; - -struct generic_pm_domain { - struct device dev; - struct dev_pm_domain domain; - struct list_head gpd_list_node; - struct list_head parent_links; - struct list_head child_links; - struct list_head dev_list; - struct dev_power_governor *gov; - struct work_struct power_off_work; - struct fwnode_handle *provider; - bool has_provider; - const char *name; - atomic_t sd_count; - enum gpd_status status; - unsigned int device_count; - unsigned int suspended_count; - unsigned int prepared_count; - unsigned int performance_state; - cpumask_var_t cpus; - int (*power_off)(struct generic_pm_domain *); - int (*power_on)(struct generic_pm_domain *); - struct raw_notifier_head power_notifiers; - struct opp_table *opp_table; - unsigned int (*opp_to_performance_state)(struct generic_pm_domain *, struct dev_pm_opp *); - int (*set_performance_state)(struct generic_pm_domain *, unsigned int); - struct gpd_dev_ops dev_ops; - s64 max_off_time_ns; - ktime_t next_wakeup; - bool max_off_time_changed; - bool cached_power_down_ok; - bool cached_power_down_state_idx; - int (*attach_dev)(struct generic_pm_domain *, struct device *); - void (*detach_dev)(struct generic_pm_domain *, struct device *); - unsigned int flags; - struct genpd_power_state *states; - void (*free_states)(struct genpd_power_state *, unsigned int); - unsigned int state_count; - unsigned int state_idx; - ktime_t on_time; - ktime_t accounting_time; - const struct genpd_lock_ops *lock_ops; - union { - struct mutex mlock; - struct { - spinlock_t slock; - long unsigned int lock_flags; - }; - }; -}; - -struct genpd_lock_ops { - void (*lock)(struct generic_pm_domain *); - void (*lock_nested)(struct generic_pm_domain *, int); - int (*lock_interruptible)(struct generic_pm_domain *); - void (*unlock)(struct generic_pm_domain *); -}; - -struct gpd_link { - struct generic_pm_domain *parent; - struct list_head parent_node; - struct generic_pm_domain *child; - struct list_head child_node; - unsigned int performance_state; - unsigned int prev_performance_state; -}; - -struct gpd_timing_data { - s64 suspend_latency_ns; - s64 resume_latency_ns; - s64 effective_constraint_ns; - bool constraint_changed; - bool cached_suspend_ok; -}; - -struct generic_pm_domain_data { - struct pm_domain_data base; - struct gpd_timing_data td; - struct notifier_block nb; - struct notifier_block *power_nb; - int cpu; - unsigned int performance_state; - unsigned int rpm_pstate; - ktime_t next_wakeup; - void *data; -}; - -struct pm_clk_notifier_block { - struct notifier_block nb; - struct dev_pm_domain *pm_domain; - char *con_ids[0]; -}; - -enum pce_status { - PCE_STATUS_NONE = 0, - PCE_STATUS_ACQUIRED = 1, - PCE_STATUS_PREPARED = 2, - PCE_STATUS_ENABLED = 3, - PCE_STATUS_ERROR = 4, -}; - -struct pm_clock_entry { - struct list_head node; - char *con_id; - struct clk *clk; - enum pce_status status; - bool enabled_when_prepared; -}; - -struct isa_driver { - int (*match)(struct device *, unsigned int); - int (*probe)(struct device *, unsigned int); - void (*remove)(struct device *, unsigned int); - void (*shutdown)(struct device *, unsigned int); - int (*suspend)(struct device *, unsigned int, pm_message_t); - int (*resume)(struct device *, unsigned int); - struct device_driver driver; - struct device *devices; -}; - -struct isa_dev { - struct device dev; - struct device *next; - unsigned int id; -}; - -enum fw_opt { - FW_OPT_UEVENT = 1, - FW_OPT_NOWAIT = 2, - FW_OPT_USERHELPER = 4, - FW_OPT_NO_WARN = 8, - FW_OPT_NOCACHE = 16, - FW_OPT_NOFALLBACK_SYSFS = 32, - FW_OPT_FALLBACK_PLATFORM = 64, - FW_OPT_PARTIAL = 128, -}; - -enum fw_status { - FW_STATUS_UNKNOWN = 0, - FW_STATUS_LOADING = 1, - FW_STATUS_DONE = 2, - FW_STATUS_ABORTED = 3, -}; - -struct fw_state { - struct completion completion; - enum fw_status status; -}; - -struct firmware_cache; - -struct fw_priv { - struct kref ref; - struct list_head list; - struct firmware_cache *fwc; - struct fw_state fw_st; - void *data; - size_t size; - size_t allocated_size; - size_t offset; - u32 opt_flags; - bool is_paged_buf; - struct page **pages; - int nr_pages; - int page_array_size; - const char *fw_name; -}; - -struct firmware_cache { - spinlock_t lock; - struct list_head head; - int state; - spinlock_t name_lock; - struct list_head fw_names; - struct delayed_work work; - struct notifier_block pm_notify; -}; - -struct fw_cache_entry { - struct list_head list; - const char *name; -}; - -struct fw_name_devm { - long unsigned int magic; - const char *name; -}; - -struct firmware_work { - struct work_struct work; - struct module *module; - const char *name; - struct device *device; - void *context; - void (*cont)(const struct firmware *, void *); - u32 opt_flags; -}; - -struct node_access_nodes { - struct device dev; - struct list_head list_node; - unsigned int access; - struct node_hmem_attrs hmem_attrs; -}; - -struct node_cache_info { - struct device dev; - struct list_head node; - struct node_cache_attrs cache_attrs; -}; - -struct node_attr { - struct device_attribute attr; - enum node_states state; -}; - -struct for_each_memory_block_cb_data { - walk_memory_blocks_func_t func; - void *arg; -}; - -struct reg_sequence { - unsigned int reg; - unsigned int def; - unsigned int delay_us; -}; - -struct regmap___2; - -struct regmap_async { - struct list_head list; - struct regmap___2 *map; - void *work_buf; -}; - -struct reg_field { - unsigned int reg; - unsigned int lsb; - unsigned int msb; - unsigned int id_size; - unsigned int id_offset; -}; - -struct regmap_format { - size_t buf_size; - size_t reg_bytes; - size_t pad_bytes; - size_t val_bytes; - void (*format_write)(struct regmap___2 *, unsigned int, unsigned int); - void (*format_reg)(void *, unsigned int, unsigned int); - void (*format_val)(void *, unsigned int, unsigned int); - unsigned int (*parse_val)(const void *); - void (*parse_inplace)(void *); -}; - -struct hwspinlock; - -struct regcache_ops; - -struct regmap___2 { - union { - struct mutex mutex; - struct { - spinlock_t spinlock; - long unsigned int spinlock_flags; - }; - }; - regmap_lock lock; - regmap_unlock unlock; - void *lock_arg; - gfp_t alloc_flags; - struct device *dev; - void *work_buf; - struct regmap_format format; - const struct regmap_bus *bus; - void *bus_context; - const char *name; - bool async; - spinlock_t async_lock; - wait_queue_head_t async_waitq; - struct list_head async_list; - struct list_head async_free; - int async_ret; - bool debugfs_disable; - struct dentry *debugfs; - const char *debugfs_name; - unsigned int debugfs_reg_len; - unsigned int debugfs_val_len; - unsigned int debugfs_tot_len; - struct list_head debugfs_off_cache; - struct mutex cache_lock; - unsigned int max_register; - bool (*writeable_reg)(struct device *, unsigned int); - bool (*readable_reg)(struct device *, unsigned int); - bool (*volatile_reg)(struct device *, unsigned int); - bool (*precious_reg)(struct device *, unsigned int); - bool (*writeable_noinc_reg)(struct device *, unsigned int); - bool (*readable_noinc_reg)(struct device *, unsigned int); - const struct regmap_access_table *wr_table; - const struct regmap_access_table *rd_table; - const struct regmap_access_table *volatile_table; - const struct regmap_access_table *precious_table; - const struct regmap_access_table *wr_noinc_table; - const struct regmap_access_table *rd_noinc_table; - int (*reg_read)(void *, unsigned int, unsigned int *); - int (*reg_write)(void *, unsigned int, unsigned int); - int (*reg_update_bits)(void *, unsigned int, unsigned int, unsigned int); - bool defer_caching; - long unsigned int read_flag_mask; - long unsigned int write_flag_mask; - int reg_shift; - int reg_stride; - int reg_stride_order; - const struct regcache_ops *cache_ops; - enum regcache_type cache_type; - unsigned int cache_size_raw; - unsigned int cache_word_size; - unsigned int num_reg_defaults; - unsigned int num_reg_defaults_raw; - bool cache_only; - bool cache_bypass; - bool cache_free; - struct reg_default *reg_defaults; - const void *reg_defaults_raw; - void *cache; - bool cache_dirty; - bool no_sync_defaults; - struct reg_sequence *patch; - int patch_regs; - bool use_single_read; - bool use_single_write; - bool can_multi_write; - size_t max_raw_read; - size_t max_raw_write; - struct rb_root range_tree; - void *selector_work_buf; - struct hwspinlock *hwlock; - bool can_sleep; -}; - -struct regcache_ops { - const char *name; - enum regcache_type type; - int (*init)(struct regmap___2 *); - int (*exit)(struct regmap___2 *); - void (*debugfs_init)(struct regmap___2 *); - int (*read)(struct regmap___2 *, unsigned int, unsigned int *); - int (*write)(struct regmap___2 *, unsigned int, unsigned int); - int (*sync)(struct regmap___2 *, unsigned int, unsigned int); - int (*drop)(struct regmap___2 *, unsigned int, unsigned int); -}; - -struct regmap_range_node { - struct rb_node node; - const char *name; - struct regmap___2 *map; - unsigned int range_min; - unsigned int range_max; - unsigned int selector_reg; - unsigned int selector_mask; - int selector_shift; - unsigned int window_start; - unsigned int window_len; -}; - -struct regmap_field { - struct regmap___2 *regmap; - unsigned int mask; - unsigned int shift; - unsigned int reg; - unsigned int id_size; - unsigned int id_offset; -}; - -struct trace_event_raw_regmap_reg { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int reg; - unsigned int val; - char __data[0]; -}; - -struct trace_event_raw_regmap_block { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int reg; - int count; - char __data[0]; -}; - -struct trace_event_raw_regcache_sync { - struct trace_entry ent; - u32 __data_loc_name; - u32 __data_loc_status; - u32 __data_loc_type; - char __data[0]; -}; - -struct trace_event_raw_regmap_bool { - struct trace_entry ent; - u32 __data_loc_name; - int flag; - char __data[0]; -}; - -struct trace_event_raw_regmap_async { - struct trace_entry ent; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_regcache_drop_region { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int from; - unsigned int to; - char __data[0]; -}; - -struct trace_event_data_offsets_regmap_reg { - u32 name; -}; - -struct trace_event_data_offsets_regmap_block { - u32 name; -}; - -struct trace_event_data_offsets_regcache_sync { - u32 name; - u32 status; - u32 type; -}; - -struct trace_event_data_offsets_regmap_bool { - u32 name; -}; - -struct trace_event_data_offsets_regmap_async { - u32 name; -}; - -struct trace_event_data_offsets_regcache_drop_region { - u32 name; -}; - -typedef void (*btf_trace_regmap_reg_write)(void *, struct regmap___2 *, unsigned int, unsigned int); - -typedef void (*btf_trace_regmap_reg_read)(void *, struct regmap___2 *, unsigned int, unsigned int); - -typedef void (*btf_trace_regmap_reg_read_cache)(void *, struct regmap___2 *, unsigned int, unsigned int); - -typedef void (*btf_trace_regmap_hw_read_start)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_hw_read_done)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_hw_write_start)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_hw_write_done)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regcache_sync)(void *, struct regmap___2 *, const char *, const char *); - -typedef void (*btf_trace_regmap_cache_only)(void *, struct regmap___2 *, bool); - -typedef void (*btf_trace_regmap_cache_bypass)(void *, struct regmap___2 *, bool); - -typedef void (*btf_trace_regmap_async_write_start)(void *, struct regmap___2 *, unsigned int, int); - -typedef void (*btf_trace_regmap_async_io_complete)(void *, struct regmap___2 *); - -typedef void (*btf_trace_regmap_async_complete_start)(void *, struct regmap___2 *); - -typedef void (*btf_trace_regmap_async_complete_done)(void *, struct regmap___2 *); - -typedef void (*btf_trace_regcache_drop_region)(void *, struct regmap___2 *, unsigned int, unsigned int); - -struct regcache_rbtree_node { - void *block; - long int *cache_present; - unsigned int base_reg; - unsigned int blklen; - struct rb_node node; -}; - -struct regcache_rbtree_ctx { - struct rb_root root; - struct regcache_rbtree_node *cached_rbnode; -}; - -struct regmap_debugfs_off_cache { - struct list_head list; - off_t min; - off_t max; - unsigned int base_reg; - unsigned int max_reg; -}; - -struct regmap_debugfs_node { - struct regmap___2 *map; - struct list_head link; -}; - -struct ptp_system_timestamp { - struct timespec64 pre_ts; - struct timespec64 post_ts; -}; - -struct spi_statistics { - spinlock_t lock; - long unsigned int messages; - long unsigned int transfers; - long unsigned int errors; - long unsigned int timedout; - long unsigned int spi_sync; - long unsigned int spi_sync_immediate; - long unsigned int spi_async; - long long unsigned int bytes; - long long unsigned int bytes_rx; - long long unsigned int bytes_tx; - long unsigned int transfer_bytes_histo[17]; - long unsigned int transfers_split_maxsize; -}; - -struct spi_delay { - u16 value; - u8 unit; -}; - -struct spi_controller; - -struct spi_device { - struct device dev; - struct spi_controller *controller; - struct spi_controller *master; - u32 max_speed_hz; - u8 chip_select; - u8 bits_per_word; - bool rt; - u32 mode; - int irq; - void *controller_state; - void *controller_data; - char modalias[32]; - const char *driver_override; - int cs_gpio; - struct gpio_desc *cs_gpiod; - struct spi_delay word_delay; - struct spi_statistics statistics; -}; - -struct spi_message; - -struct spi_transfer; - -struct spi_controller_mem_ops; - -struct spi_controller { - struct device dev; - struct list_head list; - s16 bus_num; - u16 num_chipselect; - u16 dma_alignment; - u32 mode_bits; - u32 buswidth_override_bits; - u32 bits_per_word_mask; - u32 min_speed_hz; - u32 max_speed_hz; - u16 flags; - bool devm_allocated; - bool slave; - size_t (*max_transfer_size)(struct spi_device *); - size_t (*max_message_size)(struct spi_device *); - struct mutex io_mutex; - spinlock_t bus_lock_spinlock; - struct mutex bus_lock_mutex; - bool bus_lock_flag; - int (*setup)(struct spi_device *); - int (*set_cs_timing)(struct spi_device *, struct spi_delay *, struct spi_delay *, struct spi_delay *); - int (*transfer)(struct spi_device *, struct spi_message *); - void (*cleanup)(struct spi_device *); - bool (*can_dma)(struct spi_controller *, struct spi_device *, struct spi_transfer *); - struct device *dma_map_dev; - bool queued; - struct kthread_worker *kworker; - struct kthread_work pump_messages; - spinlock_t queue_lock; - struct list_head queue; - struct spi_message *cur_msg; - bool idling; - bool busy; - bool running; - bool rt; - bool auto_runtime_pm; - bool cur_msg_prepared; - bool cur_msg_mapped; - bool last_cs_enable; - bool last_cs_mode_high; - bool fallback; - struct completion xfer_completion; - size_t max_dma_len; - int (*prepare_transfer_hardware)(struct spi_controller *); - int (*transfer_one_message)(struct spi_controller *, struct spi_message *); - int (*unprepare_transfer_hardware)(struct spi_controller *); - int (*prepare_message)(struct spi_controller *, struct spi_message *); - int (*unprepare_message)(struct spi_controller *, struct spi_message *); - int (*slave_abort)(struct spi_controller *); - void (*set_cs)(struct spi_device *, bool); - int (*transfer_one)(struct spi_controller *, struct spi_device *, struct spi_transfer *); - void (*handle_err)(struct spi_controller *, struct spi_message *); - const struct spi_controller_mem_ops *mem_ops; - struct spi_delay cs_setup; - struct spi_delay cs_hold; - struct spi_delay cs_inactive; - int *cs_gpios; - struct gpio_desc **cs_gpiods; - bool use_gpio_descriptors; - s8 unused_native_cs; - s8 max_native_cs; - struct spi_statistics statistics; - struct dma_chan___2 *dma_tx; - struct dma_chan___2 *dma_rx; - void *dummy_rx; - void *dummy_tx; - int (*fw_translate_cs)(struct spi_controller *, unsigned int); - bool ptp_sts_supported; - long unsigned int irq_flags; -}; - -struct spi_message { - struct list_head transfers; - struct spi_device *spi; - unsigned int is_dma_mapped: 1; - void (*complete)(void *); - void *context; - unsigned int frame_length; - unsigned int actual_length; - int status; - struct list_head queue; - void *state; - struct list_head resources; -}; - -struct spi_transfer { - const void *tx_buf; - void *rx_buf; - unsigned int len; - dma_addr_t tx_dma; - dma_addr_t rx_dma; - struct sg_table tx_sg; - struct sg_table rx_sg; - unsigned int dummy_data: 1; - unsigned int cs_change: 1; - unsigned int tx_nbits: 3; - unsigned int rx_nbits: 3; - u8 bits_per_word; - struct spi_delay delay; - struct spi_delay cs_change_delay; - struct spi_delay word_delay; - u32 speed_hz; - u32 effective_speed_hz; - unsigned int ptp_sts_word_pre; - unsigned int ptp_sts_word_post; - struct ptp_system_timestamp *ptp_sts; - bool timestamped; - struct list_head transfer_list; - u16 error; -}; - -struct spi_mem; - -struct spi_mem_op; - -struct spi_mem_dirmap_desc; - -struct spi_controller_mem_ops { - int (*adjust_op_size)(struct spi_mem *, struct spi_mem_op *); - bool (*supports_op)(struct spi_mem *, const struct spi_mem_op *); - int (*exec_op)(struct spi_mem *, const struct spi_mem_op *); - const char * (*get_name)(struct spi_mem *); - int (*dirmap_create)(struct spi_mem_dirmap_desc *); - void (*dirmap_destroy)(struct spi_mem_dirmap_desc *); - ssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *, u64, size_t, void *); - ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *, u64, size_t, const void *); - int (*poll_status)(struct spi_mem *, const struct spi_mem_op *, u16, u16, long unsigned int, long unsigned int, long unsigned int); -}; - -struct regmap_async_spi { - struct regmap_async core; - struct spi_message m; - struct spi_transfer t[2]; -}; - -struct regmap_mmio_context { - void *regs; - unsigned int val_bytes; - bool relaxed_mmio; - bool attached_clk; - struct clk *clk; - void (*reg_write)(struct regmap_mmio_context *, unsigned int, unsigned int); - unsigned int (*reg_read)(struct regmap_mmio_context *, unsigned int); -}; - -struct regmap_irq_chip_data___2 { - struct mutex lock; - struct irq_chip irq_chip; - struct regmap___2 *map; - const struct regmap_irq_chip *chip; - int irq_base; - struct irq_domain *domain; - int irq; - int wake_count; - void *status_reg_buf; - unsigned int *main_status_buf; - unsigned int *status_buf; - unsigned int *mask_buf; - unsigned int *mask_buf_def; - unsigned int *wake_buf; - unsigned int *type_buf; - unsigned int *type_buf_def; - unsigned int **virt_buf; - unsigned int irq_reg_stride; - unsigned int type_reg_stride; - bool clear_status: 1; -}; - -struct devcd_entry { - struct device devcd_dev; - void *data; - size_t datalen; - struct module *owner; - ssize_t (*read)(char *, loff_t, size_t, void *, size_t); - void (*free)(void *); - struct delayed_work del_wk; - struct device *failing_dev; -}; - -typedef void (*irq_write_msi_msg_t)(struct msi_desc *, struct msi_msg *); - -struct platform_msi_priv_data { - struct device *dev; - void *host_data; - msi_alloc_info_t arg; - irq_write_msi_msg_t write_msg; - int devid; -}; - -struct trace_event_raw_devres { - struct trace_entry ent; - u32 __data_loc_devname; - struct device *dev; - const char *op; - void *node; - const char *name; - size_t size; - char __data[0]; -}; - -struct trace_event_data_offsets_devres { - u32 devname; -}; - -typedef void (*btf_trace_devres_log)(void *, struct device *, const char *, void *, const char *, size_t); - -struct mfd_cell_acpi_match { - const char *pnpid; - const long long unsigned int adr; -}; - -enum { - CHIP_INVALID = 0, - CHIP_PM8606 = 1, - CHIP_PM8607 = 2, - CHIP_MAX = 3, -}; - -enum pm8606_ref_gp_and_osc_clients { - REF_GP_NO_CLIENTS = 0, - WLED1_DUTY = 1, - WLED2_DUTY = 2, - WLED3_DUTY = 4, - RGB1_ENABLE = 8, - RGB2_ENABLE = 16, - LDO_VBR_EN = 32, - REF_GP_MAX_CLIENT = 65535, -}; - -enum { - PM8607_IRQ_ONKEY = 0, - PM8607_IRQ_EXTON = 1, - PM8607_IRQ_CHG = 2, - PM8607_IRQ_BAT = 3, - PM8607_IRQ_RTC = 4, - PM8607_IRQ_CC = 5, - PM8607_IRQ_VBAT = 6, - PM8607_IRQ_VCHG = 7, - PM8607_IRQ_VSYS = 8, - PM8607_IRQ_TINT = 9, - PM8607_IRQ_GPADC0 = 10, - PM8607_IRQ_GPADC1 = 11, - PM8607_IRQ_GPADC2 = 12, - PM8607_IRQ_GPADC3 = 13, - PM8607_IRQ_AUDIO_SHORT = 14, - PM8607_IRQ_PEN = 15, - PM8607_IRQ_HEADSET = 16, - PM8607_IRQ_HOOK = 17, - PM8607_IRQ_MICIN = 18, - PM8607_IRQ_CHG_FAIL = 19, - PM8607_IRQ_CHG_DONE = 20, - PM8607_IRQ_CHG_FAULT = 21, -}; - -struct pm860x_chip { - struct device *dev; - struct mutex irq_lock; - struct mutex osc_lock; - struct i2c_client *client; - struct i2c_client *companion; - struct regmap *regmap; - struct regmap *regmap_companion; - int buck3_double; - int companion_addr; - short unsigned int osc_vote; - int id; - int irq_mode; - int irq_base; - int core_irq; - unsigned char chip_version; - unsigned char osc_status; - unsigned int wakeup_flag; -}; - -enum { - GI2C_PORT = 0, - PI2C_PORT = 1, -}; - -struct pm860x_backlight_pdata { - int pwm; - int iset; -}; - -struct pm860x_led_pdata { - int iset; -}; - -struct pm860x_rtc_pdata { - int (*sync)(unsigned int); - int vrtc; -}; - -struct pm860x_touch_pdata { - int gpadc_prebias; - int slot_cycle; - int off_scale; - int sw_cal; - int tsi_prebias; - int pen_prebias; - int pen_prechg; - int res_x; - long unsigned int flags; -}; - -struct pm860x_power_pdata { - int max_capacity; - int resistor; -}; - -struct charger_desc; - -struct pm860x_platform_data { - struct pm860x_backlight_pdata *backlight; - struct pm860x_led_pdata *led; - struct pm860x_rtc_pdata *rtc; - struct pm860x_touch_pdata *touch; - struct pm860x_power_pdata *power; - struct regulator_init_data *buck1; - struct regulator_init_data *buck2; - struct regulator_init_data *buck3; - struct regulator_init_data *ldo1; - struct regulator_init_data *ldo2; - struct regulator_init_data *ldo3; - struct regulator_init_data *ldo4; - struct regulator_init_data *ldo5; - struct regulator_init_data *ldo6; - struct regulator_init_data *ldo7; - struct regulator_init_data *ldo8; - struct regulator_init_data *ldo9; - struct regulator_init_data *ldo10; - struct regulator_init_data *ldo12; - struct regulator_init_data *ldo_vibrator; - struct regulator_init_data *ldo14; - struct charger_desc *chg_desc; - int companion_addr; - int i2c_port; - int irq_mode; - int irq_base; - int num_leds; - int num_backlights; -}; - -enum polling_modes { - CM_POLL_DISABLE = 0, - CM_POLL_ALWAYS = 1, - CM_POLL_EXTERNAL_POWER_ONLY = 2, - CM_POLL_CHARGING_ONLY = 3, -}; - -enum data_source { - CM_BATTERY_PRESENT = 0, - CM_NO_BATTERY = 1, - CM_FUEL_GAUGE = 2, - CM_CHARGER_STAT = 3, -}; - -struct charger_regulator; - -struct charger_desc { - const char *psy_name; - enum polling_modes polling_mode; - unsigned int polling_interval_ms; - unsigned int fullbatt_vchkdrop_uV; - unsigned int fullbatt_uV; - unsigned int fullbatt_soc; - unsigned int fullbatt_full_capacity; - enum data_source battery_present; - const char **psy_charger_stat; - int num_charger_regulators; - struct charger_regulator *charger_regulators; - const struct attribute_group **sysfs_groups; - const char *psy_fuel_gauge; - const char *thermal_zone; - int temp_min; - int temp_max; - int temp_diff; - bool measure_battery_temp; - u32 charging_max_duration_ms; - u32 discharging_max_duration_ms; -}; - -struct charger_manager; - -struct charger_cable { - const char *extcon_name; - const char *name; - struct extcon_dev *extcon_dev; - u64 extcon_type; - struct work_struct wq; - struct notifier_block nb; - bool attached; - struct charger_regulator *charger; - int min_uA; - int max_uA; - struct charger_manager *cm; -}; - -struct charger_regulator { - const char *regulator_name; - struct regulator *consumer; - int externally_control; - struct charger_cable *cables; - int num_cables; - struct attribute_group attr_grp; - struct device_attribute attr_name; - struct device_attribute attr_state; - struct device_attribute attr_externally_control; - struct attribute *attrs[4]; - struct charger_manager *cm; -}; - -struct charger_manager { - struct list_head entry; - struct device *dev; - struct charger_desc *desc; - struct thermal_zone_device *tzd_batt; - bool charger_enabled; - int emergency_stop; - char psy_name_buf[31]; - struct power_supply_desc charger_psy_desc; - struct power_supply *charger_psy; - u64 charging_start_time; - u64 charging_end_time; - int battery_status; -}; - -struct pm860x_irq_data { - int reg; - int mask_reg; - int enable; - int offs; -}; - -struct htcpld_chip_platform_data { - unsigned int addr; - unsigned int reset; - unsigned int num_gpios; - unsigned int gpio_out_base; - unsigned int gpio_in_base; - unsigned int irq_base; - unsigned int num_irqs; -}; - -struct htcpld_core_platform_data { - unsigned int int_reset_gpio_hi; - unsigned int int_reset_gpio_lo; - unsigned int i2c_adapter_id; - struct htcpld_chip_platform_data *chip; - unsigned int num_chip; -}; - -struct htcpld_chip { - spinlock_t lock; - u8 reset; - u8 addr; - struct device *dev; - struct i2c_client *client; - u8 cache_out; - struct gpio_chip chip_out; - u8 cache_in; - struct gpio_chip chip_in; - u16 irqs_enabled; - uint irq_start; - int nirqs; - unsigned int flow_type; - struct work_struct set_val_work; -}; - -struct htcpld_data { - u16 irqs_enabled; - uint irq_start; - int nirqs; - uint chained_irq; - unsigned int int_reset_gpio_hi; - unsigned int int_reset_gpio_lo; - struct htcpld_chip *chip; - unsigned int nchips; -}; - -struct wm8400_platform_data { - int (*platform_init)(struct device *); -}; - -struct wm8400 { - struct device *dev; - struct regmap *regmap; - struct platform_device regulators[6]; -}; - -enum wm831x_auxadc { - WM831X_AUX_CAL = 15, - WM831X_AUX_BKUP_BATT = 10, - WM831X_AUX_WALL = 9, - WM831X_AUX_BATT = 8, - WM831X_AUX_USB = 7, - WM831X_AUX_SYSVDD = 6, - WM831X_AUX_BATT_TEMP = 5, - WM831X_AUX_CHIP_TEMP = 4, - WM831X_AUX_AUX4 = 3, - WM831X_AUX_AUX3 = 2, - WM831X_AUX_AUX2 = 1, - WM831X_AUX_AUX1 = 0, -}; - -struct wm831x_backlight_pdata { - int isink; - int max_uA; -}; - -struct wm831x_backup_pdata { - int charger_enable; - int no_constant_voltage; - int vlim; - int ilim; -}; - -struct wm831x_battery_pdata { - int enable; - int fast_enable; - int off_mask; - int trickle_ilim; - int vsel; - int eoc_iterm; - int fast_ilim; - int timeout; -}; - -enum wm831x_status_src { - WM831X_STATUS_PRESERVE = 0, - WM831X_STATUS_OTP = 1, - WM831X_STATUS_POWER = 2, - WM831X_STATUS_CHARGER = 3, - WM831X_STATUS_MANUAL = 4, -}; - -struct wm831x_status_pdata { - enum wm831x_status_src default_src; - const char *name; - const char *default_trigger; -}; - -struct wm831x_touch_pdata { - int fivewire; - int isel; - int rpu; - int pressure; - unsigned int data_irq; - int data_irqf; - unsigned int pd_irq; - int pd_irqf; -}; - -enum wm831x_watchdog_action { - WM831X_WDOG_NONE = 0, - WM831X_WDOG_INTERRUPT = 1, - WM831X_WDOG_RESET = 2, - WM831X_WDOG_WAKE = 3, -}; - -struct wm831x_watchdog_pdata { - enum wm831x_watchdog_action primary; - enum wm831x_watchdog_action secondary; - unsigned int software: 1; -}; - -struct wm831x; - -struct wm831x_pdata { - int wm831x_num; - int (*pre_init)(struct wm831x *); - int (*post_init)(struct wm831x *); - bool irq_cmos; - bool disable_touch; - bool soft_shutdown; - int irq_base; - int gpio_base; - int gpio_defaults[16]; - struct wm831x_backlight_pdata *backlight; - struct wm831x_backup_pdata *backup; - struct wm831x_battery_pdata *battery; - struct wm831x_touch_pdata *touch; - struct wm831x_watchdog_pdata *watchdog; - struct wm831x_status_pdata *status[2]; - struct regulator_init_data *dcdc[4]; - struct regulator_init_data *epe[2]; - struct regulator_init_data *ldo[11]; - struct regulator_init_data *isink[2]; -}; - -enum wm831x_parent { - WM8310 = 33552, - WM8311 = 33553, - WM8312 = 33554, - WM8320 = 33568, - WM8321 = 33569, - WM8325 = 33573, - WM8326 = 33574, -}; - -typedef int (*wm831x_auxadc_read_fn)(struct wm831x *, enum wm831x_auxadc); - -struct wm831x { - struct mutex io_lock; - struct device *dev; - struct regmap *regmap; - struct wm831x_pdata pdata; - enum wm831x_parent type; - int irq; - struct mutex irq_lock; - struct irq_domain *irq_domain; - int irq_masks_cur[5]; - int irq_masks_cache[5]; - bool soft_shutdown; - unsigned int has_gpio_ena: 1; - unsigned int has_cs_sts: 1; - unsigned int charger_irq_wake: 1; - int num_gpio; - int gpio_update[16]; - bool gpio_level_high[16]; - bool gpio_level_low[16]; - struct mutex auxadc_lock; - struct list_head auxadc_pending; - u16 auxadc_active; - wm831x_auxadc_read_fn auxadc_read; - struct mutex key_lock; - unsigned int locked: 1; -}; - -struct wm831x_irq_data { - int primary; - int reg; - int mask; -}; - -struct wm831x_auxadc_req { - struct list_head list; - enum wm831x_auxadc input; - int val; - struct completion done; -}; - -struct spi_device_id { - char name[32]; - kernel_ulong_t driver_data; -}; - -struct spi_driver { - const struct spi_device_id *id_table; - int (*probe)(struct spi_device *); - int (*remove)(struct spi_device *); - void (*shutdown)(struct spi_device *); - struct device_driver driver; -}; - -struct wm8350_audio_platform_data { - int vmid_discharge_msecs; - int drain_msecs; - int cap_discharge_msecs; - int vmid_charge_msecs; - u32 vmid_s_curve: 2; - u32 dis_out4: 2; - u32 dis_out3: 2; - u32 dis_out2: 2; - u32 dis_out1: 2; - u32 vroi_out4: 1; - u32 vroi_out3: 1; - u32 vroi_out2: 1; - u32 vroi_out1: 1; - u32 vroi_enable: 1; - u32 codec_current_on: 2; - u32 codec_current_standby: 2; - u32 codec_current_charge: 2; -}; - -struct wm8350_codec { - struct platform_device *pdev; - struct wm8350_audio_platform_data *platform_data; -}; - -struct wm8350_gpio { - struct platform_device *pdev; -}; - -struct wm8350_led { - struct platform_device *pdev; - struct work_struct work; - spinlock_t value_lock; - enum led_brightness value; - struct led_classdev cdev; - int max_uA_index; - int enabled; - struct regulator *isink; - struct regulator_consumer_supply isink_consumer; - struct regulator_init_data isink_init; - struct regulator *dcdc; - struct regulator_consumer_supply dcdc_consumer; - struct regulator_init_data dcdc_init; -}; - -struct wm8350_pmic { - int max_dcdc; - int max_isink; - int isink_A_dcdc; - int isink_B_dcdc; - u16 dcdc1_hib_mode; - u16 dcdc3_hib_mode; - u16 dcdc4_hib_mode; - u16 dcdc6_hib_mode; - struct platform_device *pdev[12]; - struct wm8350_led led[2]; -}; - -struct rtc_device___2; - -struct wm8350_rtc { - struct platform_device *pdev; - struct rtc_device___2 *rtc; - int alarm_enabled; - int update_enabled; -}; - -struct wm8350_charger_policy { - int eoc_mA; - int charge_mV; - int fast_limit_mA; - int fast_limit_USB_mA; - int charge_timeout; - int trickle_start_mV; - int trickle_charge_mA; - int trickle_charge_USB_mA; -}; - -struct wm8350_power { - struct platform_device *pdev; - struct power_supply *battery; - struct power_supply *usb; - struct power_supply *ac; - struct wm8350_charger_policy *policy; - int rev_g_coeff; -}; - -struct wm8350_wdt { - struct platform_device *pdev; -}; - -struct wm8350_hwmon { - struct platform_device *pdev; - struct device *classdev; -}; - -struct wm8350 { - struct device *dev; - struct regmap *regmap; - bool unlocked; - struct mutex auxadc_mutex; - struct completion auxadc_done; - struct mutex irq_lock; - int chip_irq; - int irq_base; - u16 irq_masks[7]; - struct wm8350_codec codec; - struct wm8350_gpio gpio; - struct wm8350_hwmon hwmon; - struct wm8350_pmic pmic; - struct wm8350_power power; - struct wm8350_rtc rtc; - struct wm8350_wdt wdt; -}; - -struct wm8350_platform_data { - int (*init)(struct wm8350 *); - int irq_high; - int irq_base; - int gpio_base; -}; - -struct wm8350_reg_access { - u16 readable; - u16 writable; - u16 vol; -}; - -struct wm8350_irq_data { - int primary; - int reg; - int mask; - int primary_only; -}; - -struct tps65910_platform_data { - int irq; - int irq_base; -}; - -enum chips { - TPS80031 = 1, - TPS80032 = 2, -}; - -enum { - TPS80031_INT_PWRON = 0, - TPS80031_INT_RPWRON = 1, - TPS80031_INT_SYS_VLOW = 2, - TPS80031_INT_RTC_ALARM = 3, - TPS80031_INT_RTC_PERIOD = 4, - TPS80031_INT_HOT_DIE = 5, - TPS80031_INT_VXX_SHORT = 6, - TPS80031_INT_SPDURATION = 7, - TPS80031_INT_WATCHDOG = 8, - TPS80031_INT_BAT = 9, - TPS80031_INT_SIM = 10, - TPS80031_INT_MMC = 11, - TPS80031_INT_RES = 12, - TPS80031_INT_GPADC_RT = 13, - TPS80031_INT_GPADC_SW2_EOC = 14, - TPS80031_INT_CC_AUTOCAL = 15, - TPS80031_INT_ID_WKUP = 16, - TPS80031_INT_VBUSS_WKUP = 17, - TPS80031_INT_ID = 18, - TPS80031_INT_VBUS = 19, - TPS80031_INT_CHRG_CTRL = 20, - TPS80031_INT_EXT_CHRG = 21, - TPS80031_INT_INT_CHRG = 22, - TPS80031_INT_RES2 = 23, - TPS80031_INT_BAT_TEMP_OVRANGE = 24, - TPS80031_INT_BAT_REMOVED = 25, - TPS80031_INT_VBUS_DET = 26, - TPS80031_INT_VAC_DET = 27, - TPS80031_INT_FAULT_WDG = 28, - TPS80031_INT_LINCH_GATED = 29, - TPS80031_INT_NR = 30, -}; - -enum { - TPS80031_REGULATOR_VIO = 0, - TPS80031_REGULATOR_SMPS1 = 1, - TPS80031_REGULATOR_SMPS2 = 2, - TPS80031_REGULATOR_SMPS3 = 3, - TPS80031_REGULATOR_SMPS4 = 4, - TPS80031_REGULATOR_VANA = 5, - TPS80031_REGULATOR_LDO1 = 6, - TPS80031_REGULATOR_LDO2 = 7, - TPS80031_REGULATOR_LDO3 = 8, - TPS80031_REGULATOR_LDO4 = 9, - TPS80031_REGULATOR_LDO5 = 10, - TPS80031_REGULATOR_LDO6 = 11, - TPS80031_REGULATOR_LDO7 = 12, - TPS80031_REGULATOR_LDOLN = 13, - TPS80031_REGULATOR_LDOUSB = 14, - TPS80031_REGULATOR_VBUS = 15, - TPS80031_REGULATOR_REGEN1 = 16, - TPS80031_REGULATOR_REGEN2 = 17, - TPS80031_REGULATOR_SYSEN = 18, - TPS80031_REGULATOR_MAX = 19, -}; - -enum tps80031_ext_control { - TPS80031_PWR_REQ_INPUT_NONE = 0, - TPS80031_PWR_REQ_INPUT_PREQ1 = 1, - TPS80031_PWR_REQ_INPUT_PREQ2 = 2, - TPS80031_PWR_REQ_INPUT_PREQ3 = 4, - TPS80031_PWR_OFF_ON_SLEEP = 8, - TPS80031_PWR_ON_ON_SLEEP = 16, -}; - -enum tps80031_pupd_pins { - TPS80031_PREQ1 = 0, - TPS80031_PREQ2A = 1, - TPS80031_PREQ2B = 2, - TPS80031_PREQ2C = 3, - TPS80031_PREQ3 = 4, - TPS80031_NRES_WARM = 5, - TPS80031_PWM_FORCE = 6, - TPS80031_CHRG_EXT_CHRG_STATZ = 7, - TPS80031_SIM = 8, - TPS80031_MMC = 9, - TPS80031_GPADC_START = 10, - TPS80031_DVSI2C_SCL = 11, - TPS80031_DVSI2C_SDA = 12, - TPS80031_CTLI2C_SCL = 13, - TPS80031_CTLI2C_SDA = 14, -}; - -enum tps80031_pupd_settings { - TPS80031_PUPD_NORMAL = 0, - TPS80031_PUPD_PULLDOWN = 1, - TPS80031_PUPD_PULLUP = 2, -}; - -struct tps80031 { - struct device *dev; - long unsigned int chip_info; - int es_version; - struct i2c_client *clients[4]; - struct regmap *regmap[4]; - struct regmap_irq_chip_data *irq_data; -}; - -struct tps80031_pupd_init_data { - int input_pin; - int setting; -}; - -struct tps80031_regulator_platform_data { - struct regulator_init_data *reg_init_data; - unsigned int ext_ctrl_flag; - unsigned int config_flags; -}; - -struct tps80031_platform_data { - int irq_base; - bool use_power_off; - struct tps80031_pupd_init_data *pupd_init_data; - int pupd_init_data_size; - struct tps80031_regulator_platform_data *regulator_pdata[19]; -}; - -struct tps80031_pupd_data { - u8 reg; - u8 pullup_bit; - u8 pulldown_bit; -}; - -struct of_dev_auxdata { - char *compatible; - resource_size_t phys_addr; - char *name; - void *platform_data; -}; - -struct matrix_keymap_data { - const uint32_t *keymap; - unsigned int keymap_size; -}; - -enum twl_module_ids { - TWL_MODULE_USB = 0, - TWL_MODULE_PIH = 1, - TWL_MODULE_MAIN_CHARGE = 2, - TWL_MODULE_PM_MASTER = 3, - TWL_MODULE_PM_RECEIVER = 4, - TWL_MODULE_RTC = 5, - TWL_MODULE_PWM = 6, - TWL_MODULE_LED = 7, - TWL_MODULE_SECURED_REG = 8, - TWL_MODULE_LAST = 9, -}; - -enum twl4030_module_ids { - TWL4030_MODULE_AUDIO_VOICE = 9, - TWL4030_MODULE_GPIO = 10, - TWL4030_MODULE_INTBR = 11, - TWL4030_MODULE_TEST = 12, - TWL4030_MODULE_KEYPAD = 13, - TWL4030_MODULE_MADC = 14, - TWL4030_MODULE_INTERRUPTS = 15, - TWL4030_MODULE_PRECHARGE = 16, - TWL4030_MODULE_BACKUP = 17, - TWL4030_MODULE_INT = 18, - TWL5031_MODULE_ACCESSORY = 19, - TWL5031_MODULE_INTERRUPTS = 20, - TWL4030_MODULE_LAST = 21, -}; - -enum twl6030_module_ids { - TWL6030_MODULE_ID0 = 9, - TWL6030_MODULE_ID1 = 10, - TWL6030_MODULE_ID2 = 11, - TWL6030_MODULE_GPADC = 12, - TWL6030_MODULE_GASGAUGE = 13, - TWL6030_MODULE_LAST = 14, -}; - -struct twl4030_clock_init_data { - bool ck32k_lowpwr_enable; -}; - -struct twl4030_bci_platform_data { - int *battery_tmp_tbl; - unsigned int tblsize; - int bb_uvolt; - int bb_uamp; -}; - -struct twl4030_gpio_platform_data { - bool use_leds; - u8 mmc_cd; - u32 debounce; - u32 pullups; - u32 pulldowns; - int (*setup)(struct device *, unsigned int, unsigned int); - int (*teardown)(struct device *, unsigned int, unsigned int); -}; - -struct twl4030_madc_platform_data { - int irq_line; -}; - -struct twl4030_keypad_data { - const struct matrix_keymap_data *keymap_data; - unsigned int rows; - unsigned int cols; - bool rep; -}; - -enum twl4030_usb_mode { - T2_USB_MODE_ULPI = 1, - T2_USB_MODE_CEA2011_3PIN = 2, -}; - -struct twl4030_usb_data { - enum twl4030_usb_mode usb_mode; - long unsigned int features; - int (*phy_init)(struct device *); - int (*phy_exit)(struct device *); - int (*phy_power)(struct device *, int, int); - int (*phy_set_clock)(struct device *, int); - int (*phy_suspend)(struct device *, int); -}; - -struct twl4030_ins { - u16 pmb_message; - u8 delay; -}; - -struct twl4030_script { - struct twl4030_ins *script; - unsigned int size; - u8 flags; -}; - -struct twl4030_resconfig { - u8 resource; - u8 devgroup; - u8 type; - u8 type2; - u8 remap_off; - u8 remap_sleep; -}; - -struct twl4030_power_data { - struct twl4030_script **scripts; - unsigned int num; - struct twl4030_resconfig *resource_config; - struct twl4030_resconfig *board_config; - bool use_poweroff; - bool ac_charger_quirk; -}; - -struct twl4030_codec_data { - unsigned int digimic_delay; - unsigned int ramp_delay_value; - unsigned int offset_cncl_path; - unsigned int hs_extmute: 1; - int hs_extmute_gpio; -}; - -struct twl4030_vibra_data { - unsigned int coexist; -}; - -struct twl4030_audio_data { - unsigned int audio_mclk; - struct twl4030_codec_data *codec; - struct twl4030_vibra_data *vibra; - int audpwron_gpio; - int naudint_irq; - unsigned int irq_base; -}; - -struct twl4030_platform_data { - struct twl4030_clock_init_data *clock; - struct twl4030_bci_platform_data *bci; - struct twl4030_gpio_platform_data *gpio; - struct twl4030_madc_platform_data *madc; - struct twl4030_keypad_data *keypad; - struct twl4030_usb_data *usb; - struct twl4030_power_data *power; - struct twl4030_audio_data *audio; - struct regulator_init_data *vdac; - struct regulator_init_data *vaux1; - struct regulator_init_data *vaux2; - struct regulator_init_data *vaux3; - struct regulator_init_data *vdd1; - struct regulator_init_data *vdd2; - struct regulator_init_data *vdd3; - struct regulator_init_data *vpll1; - struct regulator_init_data *vpll2; - struct regulator_init_data *vmmc1; - struct regulator_init_data *vmmc2; - struct regulator_init_data *vsim; - struct regulator_init_data *vaux4; - struct regulator_init_data *vio; - struct regulator_init_data *vintana1; - struct regulator_init_data *vintana2; - struct regulator_init_data *vintdig; - struct regulator_init_data *vmmc; - struct regulator_init_data *vpp; - struct regulator_init_data *vusim; - struct regulator_init_data *vana; - struct regulator_init_data *vcxio; - struct regulator_init_data *vusb; - struct regulator_init_data *clk32kg; - struct regulator_init_data *v1v8; - struct regulator_init_data *v2v1; - struct regulator_init_data *ldo1; - struct regulator_init_data *ldo2; - struct regulator_init_data *ldo3; - struct regulator_init_data *ldo4; - struct regulator_init_data *ldo5; - struct regulator_init_data *ldo6; - struct regulator_init_data *ldo7; - struct regulator_init_data *ldoln; - struct regulator_init_data *ldousb; - struct regulator_init_data *smps3; - struct regulator_init_data *smps4; - struct regulator_init_data *vio6025; -}; - -struct twl_regulator_driver_data { - int (*set_voltage)(void *, int); - int (*get_voltage)(void *); - void *data; - long unsigned int features; -}; - -struct twl_client { - struct i2c_client *client; - struct regmap *regmap; -}; - -struct twl_mapping { - unsigned char sid; - unsigned char base; -}; - -struct twl_private { - bool ready; - u32 twl_idcode; - unsigned int twl_id; - struct twl_mapping *twl_map; - struct twl_client *twl_modules; -}; - -struct sih_irq_data { - u8 isr_offset; - u8 imr_offset; -}; - -struct sih { - char name[8]; - u8 module; - u8 control_offset; - bool set_cor; - u8 bits; - u8 bytes_ixr; - u8 edr_offset; - u8 bytes_edr; - u8 irq_lines; - struct sih_irq_data mask[2]; -}; - -struct sih_agent { - int irq_base; - const struct sih *sih; - u32 imr; - bool imr_change_pending; - u32 edge_change; - struct mutex irq_lock; - char *irq_name; -}; - -struct twl6030_irq { - unsigned int irq_base; - int twl_irq; - bool irq_wake_enabled; - atomic_t wakeirqs; - struct notifier_block pm_nb; - struct irq_chip irq_chip; - struct irq_domain *irq_domain; - const int *irq_mapping_tbl; -}; - -enum twl4030_audio_res { - TWL4030_AUDIO_RES_POWER = 0, - TWL4030_AUDIO_RES_APLL = 1, - TWL4030_AUDIO_RES_MAX = 2, -}; - -struct twl4030_audio_resource { - int request_count; - u8 reg; - u8 mask; -}; - -struct twl4030_audio { - unsigned int audio_mclk; - struct mutex mutex; - struct twl4030_audio_resource resource[2]; - struct mfd_cell cells[2]; -}; - -enum of_gpio_flags { - OF_GPIO_ACTIVE_LOW = 1, - OF_GPIO_SINGLE_ENDED = 2, - OF_GPIO_OPEN_DRAIN = 4, - OF_GPIO_TRANSITORY = 8, - OF_GPIO_PULL_UP = 16, - OF_GPIO_PULL_DOWN = 32, -}; - -struct twl6040 { - struct device *dev; - struct regmap *regmap; - struct regmap_irq_chip_data *irq_data; - struct regulator_bulk_data supplies[2]; - struct clk *clk32k; - struct clk *mclk; - struct mutex mutex; - struct mutex irq_mutex; - struct mfd_cell cells[4]; - struct completion ready; - int audpwron; - int power_count; - int rev; - int pll; - unsigned int sysclk_rate; - unsigned int mclk_rate; - unsigned int irq; - unsigned int irq_ready; - unsigned int irq_th; -}; - -struct mfd_of_node_entry { - struct list_head list; - struct device *dev; - struct device_node *np; -}; - -struct pcap_subdev { - int id; - const char *name; - void *platform_data; -}; - -struct pcap_platform_data { - unsigned int irq_base; - unsigned int config; - int gpio; - void (*init)(void *); - int num_subdevs; - struct pcap_subdev *subdevs; -}; - -struct pcap_adc_request { - u8 bank; - u8 ch[2]; - u32 flags; - void (*callback)(void *, u16 *); - void *data; -}; - -struct pcap_adc_sync_request { - u16 res[2]; - struct completion completion; -}; - -struct pcap_chip { - struct spi_device *spi; - u32 buf; - spinlock_t io_lock; - unsigned int irq_base; - u32 msr; - struct work_struct isr_work; - struct work_struct msr_work; - struct workqueue_struct *workqueue; - struct pcap_adc_request *adc_queue[8]; - u8 adc_head; - u8 adc_tail; - spinlock_t adc_lock; -}; - -struct da903x_subdev_info { - int id; - const char *name; - void *platform_data; -}; - -struct da903x_platform_data { - int num_subdevs; - struct da903x_subdev_info *subdevs; -}; - -struct da903x_chip; - -struct da903x_chip_ops { - int (*init_chip)(struct da903x_chip *); - int (*unmask_events)(struct da903x_chip *, unsigned int); - int (*mask_events)(struct da903x_chip *, unsigned int); - int (*read_events)(struct da903x_chip *, unsigned int *); - int (*read_status)(struct da903x_chip *, unsigned int *); -}; - -struct da903x_chip { - struct i2c_client *client; - struct device *dev; - const struct da903x_chip_ops *ops; - int type; - uint32_t events_mask; - struct mutex lock; - struct work_struct irq_work; - struct blocking_notifier_head notifier_list; -}; - -struct da9052 { - struct device *dev; - struct regmap *regmap; - struct mutex auxadc_lock; - struct completion done; - int irq_base; - struct regmap_irq_chip_data *irq_data; - u8 chip_id; - int chip_irq; - int (*fix_io)(struct da9052 *, unsigned char); -}; - -struct led_platform_data; - -struct da9052_pdata { - struct led_platform_data *pled; - int (*init)(struct da9052 *); - int irq_base; - int gpio_base; - int use_for_apm; - struct regulator_init_data *regulators[14]; -}; - -enum da9052_chip_id { - DA9052 = 0, - DA9053_AA = 1, - DA9053_BA = 2, - DA9053_BB = 3, - DA9053_BC = 4, -}; - -enum lp8788_int_id { - LP8788_INT_TSDL = 0, - LP8788_INT_TSDH = 1, - LP8788_INT_UVLO = 2, - LP8788_INT_FLAGMON = 3, - LP8788_INT_PWRON_TIME = 4, - LP8788_INT_PWRON = 5, - LP8788_INT_COMP1 = 6, - LP8788_INT_COMP2 = 7, - LP8788_INT_CHG_INPUT_STATE = 8, - LP8788_INT_CHG_STATE = 9, - LP8788_INT_EOC = 10, - LP8788_INT_CHG_RESTART = 11, - LP8788_INT_RESTART_TIMEOUT = 12, - LP8788_INT_FULLCHG_TIMEOUT = 13, - LP8788_INT_PRECHG_TIMEOUT = 14, - LP8788_INT_RTC_ALARM1 = 17, - LP8788_INT_RTC_ALARM2 = 18, - LP8788_INT_ENTER_SYS_SUPPORT = 19, - LP8788_INT_EXIT_SYS_SUPPORT = 20, - LP8788_INT_BATT_LOW = 21, - LP8788_INT_NO_BATT = 22, - LP8788_INT_MAX = 24, -}; - -enum lp8788_dvs_sel { - DVS_SEL_V0 = 0, - DVS_SEL_V1 = 1, - DVS_SEL_V2 = 2, - DVS_SEL_V3 = 3, -}; - -enum lp8788_charger_event { - NO_CHARGER = 0, - CHARGER_DETECTED = 1, -}; - -enum lp8788_bl_ctrl_mode { - LP8788_BL_REGISTER_ONLY = 0, - LP8788_BL_COMB_PWM_BASED = 1, - LP8788_BL_COMB_REGISTER_BASED = 2, -}; - -enum lp8788_bl_dim_mode { - LP8788_DIM_EXPONENTIAL = 0, - LP8788_DIM_LINEAR = 1, -}; - -enum lp8788_bl_full_scale_current { - LP8788_FULLSCALE_5000uA = 0, - LP8788_FULLSCALE_8500uA = 1, - LP8788_FULLSCALE_1200uA = 2, - LP8788_FULLSCALE_1550uA = 3, - LP8788_FULLSCALE_1900uA = 4, - LP8788_FULLSCALE_2250uA = 5, - LP8788_FULLSCALE_2600uA = 6, - LP8788_FULLSCALE_2950uA = 7, -}; - -enum lp8788_bl_ramp_step { - LP8788_RAMP_8us = 0, - LP8788_RAMP_1024us = 1, - LP8788_RAMP_2048us = 2, - LP8788_RAMP_4096us = 3, - LP8788_RAMP_8192us = 4, - LP8788_RAMP_16384us = 5, - LP8788_RAMP_32768us = 6, - LP8788_RAMP_65538us = 7, -}; - -enum lp8788_isink_scale { - LP8788_ISINK_SCALE_100mA = 0, - LP8788_ISINK_SCALE_120mA = 1, -}; - -enum lp8788_isink_number { - LP8788_ISINK_1 = 0, - LP8788_ISINK_2 = 1, - LP8788_ISINK_3 = 2, -}; - -enum lp8788_alarm_sel { - LP8788_ALARM_1 = 0, - LP8788_ALARM_2 = 1, - LP8788_ALARM_MAX = 2, -}; - -struct lp8788_buck1_dvs { - int gpio; - enum lp8788_dvs_sel vsel; -}; - -struct lp8788_buck2_dvs { - int gpio[2]; - enum lp8788_dvs_sel vsel; -}; - -struct lp8788_chg_param { - u8 addr; - u8 val; -}; - -struct lp8788; - -struct lp8788_charger_platform_data { - const char *adc_vbatt; - const char *adc_batt_temp; - unsigned int max_vbatt_mv; - struct lp8788_chg_param *chg_params; - int num_chg_params; - void (*charger_event)(struct lp8788 *, enum lp8788_charger_event); -}; - -struct lp8788_platform_data; - -struct lp8788 { - struct device *dev; - struct regmap *regmap; - struct irq_domain *irqdm; - int irq; - struct lp8788_platform_data *pdata; -}; - -struct lp8788_backlight_platform_data { - char *name; - int initial_brightness; - enum lp8788_bl_ctrl_mode bl_mode; - enum lp8788_bl_dim_mode dim_mode; - enum lp8788_bl_full_scale_current full_scale; - enum lp8788_bl_ramp_step rise_time; - enum lp8788_bl_ramp_step fall_time; - enum pwm_polarity pwm_pol; - unsigned int period_ns; -}; - -struct lp8788_led_platform_data { - char *name; - enum lp8788_isink_scale scale; - enum lp8788_isink_number num; - int iout_code; -}; - -struct lp8788_vib_platform_data { - char *name; - enum lp8788_isink_scale scale; - enum lp8788_isink_number num; - int iout_code; - int pwm_code; -}; - -struct iio_map; - -struct lp8788_platform_data { - int (*init_func)(struct lp8788 *); - struct regulator_init_data *buck_data[4]; - struct regulator_init_data *dldo_data[12]; - struct regulator_init_data *aldo_data[10]; - struct lp8788_buck1_dvs *buck1_dvs; - struct lp8788_buck2_dvs *buck2_dvs; - struct lp8788_charger_platform_data *chg_pdata; - enum lp8788_alarm_sel alarm_sel; - struct lp8788_backlight_platform_data *bl_pdata; - struct lp8788_led_platform_data *led_pdata; - struct lp8788_vib_platform_data *vib_pdata; - struct iio_map *adc_pdata; -}; - -struct lp8788_irq_data { - struct lp8788 *lp; - struct mutex irq_lock; - struct irq_domain *domain; - int enabled[24]; -}; - -struct da9055 { - struct regmap *regmap; - struct regmap_irq_chip_data *irq_data; - struct device *dev; - struct i2c_client *i2c_client; - int irq_base; - int chip_irq; -}; - -enum gpio_select { - NO_GPIO = 0, - GPIO_1 = 1, - GPIO_2 = 2, -}; - -struct da9055_pdata { - int (*init)(struct da9055 *); - int irq_base; - int gpio_base; - struct regulator_init_data *regulators[8]; - bool reset_enable; - int *gpio_ren; - int *gpio_rsel; - enum gpio_select *reg_ren; - enum gpio_select *reg_rsel; - struct gpio_desc **ena_gpiods; -}; - -enum max77693_types { - TYPE_MAX77693_UNKNOWN = 0, - TYPE_MAX77693 = 1, - TYPE_MAX77843 = 2, - TYPE_MAX77693_NUM = 3, -}; - -struct max77693_dev { - struct device *dev; - struct i2c_client *i2c; - struct i2c_client *i2c_muic; - struct i2c_client *i2c_haptic; - struct i2c_client *i2c_chg; - enum max77693_types type; - struct regmap *regmap; - struct regmap *regmap_muic; - struct regmap *regmap_haptic; - struct regmap *regmap_chg; - struct regmap_irq_chip_data *irq_data_led; - struct regmap_irq_chip_data *irq_data_topsys; - struct regmap_irq_chip_data *irq_data_chg; - struct regmap_irq_chip_data *irq_data_muic; - int irq; -}; - -enum max77843_sys_reg { - MAX77843_SYS_REG_PMICID = 0, - MAX77843_SYS_REG_PMICREV = 1, - MAX77843_SYS_REG_MAINCTRL1 = 2, - MAX77843_SYS_REG_INTSRC = 34, - MAX77843_SYS_REG_INTSRCMASK = 35, - MAX77843_SYS_REG_SYSINTSRC = 36, - MAX77843_SYS_REG_SYSINTMASK = 38, - MAX77843_SYS_REG_TOPSYS_STAT = 40, - MAX77843_SYS_REG_SAFEOUTCTRL = 198, - MAX77843_SYS_REG_END = 199, -}; - -enum max77843_charger_reg { - MAX77843_CHG_REG_CHG_INT = 176, - MAX77843_CHG_REG_CHG_INT_MASK = 177, - MAX77843_CHG_REG_CHG_INT_OK = 178, - MAX77843_CHG_REG_CHG_DTLS_00 = 179, - MAX77843_CHG_REG_CHG_DTLS_01 = 180, - MAX77843_CHG_REG_CHG_DTLS_02 = 181, - MAX77843_CHG_REG_CHG_CNFG_00 = 183, - MAX77843_CHG_REG_CHG_CNFG_01 = 184, - MAX77843_CHG_REG_CHG_CNFG_02 = 185, - MAX77843_CHG_REG_CHG_CNFG_03 = 186, - MAX77843_CHG_REG_CHG_CNFG_04 = 187, - MAX77843_CHG_REG_CHG_CNFG_06 = 189, - MAX77843_CHG_REG_CHG_CNFG_07 = 190, - MAX77843_CHG_REG_CHG_CNFG_09 = 192, - MAX77843_CHG_REG_CHG_CNFG_10 = 193, - MAX77843_CHG_REG_CHG_CNFG_11 = 194, - MAX77843_CHG_REG_CHG_CNFG_12 = 195, - MAX77843_CHG_REG_END = 196, -}; - -enum { - MAX8925_IRQ_VCHG_DC_OVP = 0, - MAX8925_IRQ_VCHG_DC_F = 1, - MAX8925_IRQ_VCHG_DC_R = 2, - MAX8925_IRQ_VCHG_THM_OK_R = 3, - MAX8925_IRQ_VCHG_THM_OK_F = 4, - MAX8925_IRQ_VCHG_SYSLOW_F = 5, - MAX8925_IRQ_VCHG_SYSLOW_R = 6, - MAX8925_IRQ_VCHG_RST = 7, - MAX8925_IRQ_VCHG_DONE = 8, - MAX8925_IRQ_VCHG_TOPOFF = 9, - MAX8925_IRQ_VCHG_TMR_FAULT = 10, - MAX8925_IRQ_GPM_RSTIN = 11, - MAX8925_IRQ_GPM_MPL = 12, - MAX8925_IRQ_GPM_SW_3SEC = 13, - MAX8925_IRQ_GPM_EXTON_F = 14, - MAX8925_IRQ_GPM_EXTON_R = 15, - MAX8925_IRQ_GPM_SW_1SEC = 16, - MAX8925_IRQ_GPM_SW_F = 17, - MAX8925_IRQ_GPM_SW_R = 18, - MAX8925_IRQ_GPM_SYSCKEN_F = 19, - MAX8925_IRQ_GPM_SYSCKEN_R = 20, - MAX8925_IRQ_RTC_ALARM1 = 21, - MAX8925_IRQ_RTC_ALARM0 = 22, - MAX8925_IRQ_TSC_STICK = 23, - MAX8925_IRQ_TSC_NSTICK = 24, - MAX8925_NR_IRQS = 25, -}; - -struct max8925_chip { - struct device *dev; - struct i2c_client *i2c; - struct i2c_client *adc; - struct i2c_client *rtc; - struct mutex io_lock; - struct mutex irq_lock; - int irq_base; - int core_irq; - int tsc_irq; - unsigned int wakeup_flag; -}; - -struct max8925_backlight_pdata { - int lxw_scl; - int lxw_freq; - int dual_string; -}; - -struct max8925_touch_pdata { - unsigned int flags; -}; - -struct max8925_power_pdata { - int (*set_charger)(int); - unsigned int batt_detect: 1; - unsigned int topoff_threshold: 2; - unsigned int fast_charge: 3; - unsigned int no_temp_support: 1; - unsigned int no_insert_detect: 1; - char **supplied_to; - int num_supplicants; -}; - -struct max8925_platform_data { - struct max8925_backlight_pdata *backlight; - struct max8925_touch_pdata *touch; - struct max8925_power_pdata *power; - struct regulator_init_data *sd1; - struct regulator_init_data *sd2; - struct regulator_init_data *sd3; - struct regulator_init_data *ldo1; - struct regulator_init_data *ldo2; - struct regulator_init_data *ldo3; - struct regulator_init_data *ldo4; - struct regulator_init_data *ldo5; - struct regulator_init_data *ldo6; - struct regulator_init_data *ldo7; - struct regulator_init_data *ldo8; - struct regulator_init_data *ldo9; - struct regulator_init_data *ldo10; - struct regulator_init_data *ldo11; - struct regulator_init_data *ldo12; - struct regulator_init_data *ldo13; - struct regulator_init_data *ldo14; - struct regulator_init_data *ldo15; - struct regulator_init_data *ldo16; - struct regulator_init_data *ldo17; - struct regulator_init_data *ldo18; - struct regulator_init_data *ldo19; - struct regulator_init_data *ldo20; - int irq_base; - int tsc_irq; -}; - -enum { - FLAGS_ADC = 1, - FLAGS_RTC = 2, -}; - -struct max8925_irq_data { - int reg; - int mask_reg; - int enable; - int offs; - int flags; - int tsc_irq; -}; - -struct max8997_regulator_data { - int id; - struct regulator_init_data *initdata; - struct device_node *reg_node; -}; - -struct max8997_muic_reg_data { - u8 addr; - u8 data; -}; - -struct max8997_muic_platform_data { - struct max8997_muic_reg_data *init_data; - int num_init_data; - int detcable_delay_ms; - int path_usb; - int path_uart; -}; - -enum max8997_haptic_motor_type { - MAX8997_HAPTIC_ERM = 0, - MAX8997_HAPTIC_LRA = 1, -}; - -enum max8997_haptic_pulse_mode { - MAX8997_EXTERNAL_MODE = 0, - MAX8997_INTERNAL_MODE = 1, -}; - -enum max8997_haptic_pwm_divisor { - MAX8997_PWM_DIVISOR_32 = 0, - MAX8997_PWM_DIVISOR_64 = 1, - MAX8997_PWM_DIVISOR_128 = 2, - MAX8997_PWM_DIVISOR_256 = 3, -}; - -struct max8997_haptic_platform_data { - unsigned int pwm_channel_id; - unsigned int pwm_period; - enum max8997_haptic_motor_type type; - enum max8997_haptic_pulse_mode mode; - enum max8997_haptic_pwm_divisor pwm_divisor; - unsigned int internal_mode_pattern; - unsigned int pattern_cycle; - unsigned int pattern_signal_period; -}; - -enum max8997_led_mode { - MAX8997_NONE = 0, - MAX8997_FLASH_MODE = 1, - MAX8997_MOVIE_MODE = 2, - MAX8997_FLASH_PIN_CONTROL_MODE = 3, - MAX8997_MOVIE_PIN_CONTROL_MODE = 4, -}; - -struct max8997_led_platform_data { - enum max8997_led_mode mode[2]; - u8 brightness[2]; -}; - -struct max8997_platform_data { - int ono; - struct max8997_regulator_data *regulators; - int num_regulators; - bool ignore_gpiodvs_side_effect; - int buck125_gpios[3]; - int buck125_default_idx; - unsigned int buck1_voltage[8]; - bool buck1_gpiodvs; - unsigned int buck2_voltage[8]; - bool buck2_gpiodvs; - unsigned int buck5_voltage[8]; - bool buck5_gpiodvs; - int eoc_mA; - int timeout; - struct max8997_muic_platform_data *muic_pdata; - struct max8997_haptic_platform_data *haptic_pdata; - struct max8997_led_platform_data *led_pdata; -}; - -enum max8997_pmic_reg { - MAX8997_REG_PMIC_ID0 = 0, - MAX8997_REG_PMIC_ID1 = 1, - MAX8997_REG_INTSRC = 2, - MAX8997_REG_INT1 = 3, - MAX8997_REG_INT2 = 4, - MAX8997_REG_INT3 = 5, - MAX8997_REG_INT4 = 6, - MAX8997_REG_INT1MSK = 8, - MAX8997_REG_INT2MSK = 9, - MAX8997_REG_INT3MSK = 10, - MAX8997_REG_INT4MSK = 11, - MAX8997_REG_STATUS1 = 13, - MAX8997_REG_STATUS2 = 14, - MAX8997_REG_STATUS3 = 15, - MAX8997_REG_STATUS4 = 16, - MAX8997_REG_MAINCON1 = 19, - MAX8997_REG_MAINCON2 = 20, - MAX8997_REG_BUCKRAMP = 21, - MAX8997_REG_BUCK1CTRL = 24, - MAX8997_REG_BUCK1DVS1 = 25, - MAX8997_REG_BUCK1DVS2 = 26, - MAX8997_REG_BUCK1DVS3 = 27, - MAX8997_REG_BUCK1DVS4 = 28, - MAX8997_REG_BUCK1DVS5 = 29, - MAX8997_REG_BUCK1DVS6 = 30, - MAX8997_REG_BUCK1DVS7 = 31, - MAX8997_REG_BUCK1DVS8 = 32, - MAX8997_REG_BUCK2CTRL = 33, - MAX8997_REG_BUCK2DVS1 = 34, - MAX8997_REG_BUCK2DVS2 = 35, - MAX8997_REG_BUCK2DVS3 = 36, - MAX8997_REG_BUCK2DVS4 = 37, - MAX8997_REG_BUCK2DVS5 = 38, - MAX8997_REG_BUCK2DVS6 = 39, - MAX8997_REG_BUCK2DVS7 = 40, - MAX8997_REG_BUCK2DVS8 = 41, - MAX8997_REG_BUCK3CTRL = 42, - MAX8997_REG_BUCK3DVS = 43, - MAX8997_REG_BUCK4CTRL = 44, - MAX8997_REG_BUCK4DVS = 45, - MAX8997_REG_BUCK5CTRL = 46, - MAX8997_REG_BUCK5DVS1 = 47, - MAX8997_REG_BUCK5DVS2 = 48, - MAX8997_REG_BUCK5DVS3 = 49, - MAX8997_REG_BUCK5DVS4 = 50, - MAX8997_REG_BUCK5DVS5 = 51, - MAX8997_REG_BUCK5DVS6 = 52, - MAX8997_REG_BUCK5DVS7 = 53, - MAX8997_REG_BUCK5DVS8 = 54, - MAX8997_REG_BUCK6CTRL = 55, - MAX8997_REG_BUCK6BPSKIPCTRL = 56, - MAX8997_REG_BUCK7CTRL = 57, - MAX8997_REG_BUCK7DVS = 58, - MAX8997_REG_LDO1CTRL = 59, - MAX8997_REG_LDO2CTRL = 60, - MAX8997_REG_LDO3CTRL = 61, - MAX8997_REG_LDO4CTRL = 62, - MAX8997_REG_LDO5CTRL = 63, - MAX8997_REG_LDO6CTRL = 64, - MAX8997_REG_LDO7CTRL = 65, - MAX8997_REG_LDO8CTRL = 66, - MAX8997_REG_LDO9CTRL = 67, - MAX8997_REG_LDO10CTRL = 68, - MAX8997_REG_LDO11CTRL = 69, - MAX8997_REG_LDO12CTRL = 70, - MAX8997_REG_LDO13CTRL = 71, - MAX8997_REG_LDO14CTRL = 72, - MAX8997_REG_LDO15CTRL = 73, - MAX8997_REG_LDO16CTRL = 74, - MAX8997_REG_LDO17CTRL = 75, - MAX8997_REG_LDO18CTRL = 76, - MAX8997_REG_LDO21CTRL = 77, - MAX8997_REG_MBCCTRL1 = 80, - MAX8997_REG_MBCCTRL2 = 81, - MAX8997_REG_MBCCTRL3 = 82, - MAX8997_REG_MBCCTRL4 = 83, - MAX8997_REG_MBCCTRL5 = 84, - MAX8997_REG_MBCCTRL6 = 85, - MAX8997_REG_OTPCGHCVS = 86, - MAX8997_REG_SAFEOUTCTRL = 90, - MAX8997_REG_LBCNFG1 = 94, - MAX8997_REG_LBCNFG2 = 95, - MAX8997_REG_BBCCTRL = 96, - MAX8997_REG_FLASH1_CUR = 99, - MAX8997_REG_FLASH2_CUR = 100, - MAX8997_REG_MOVIE_CUR = 101, - MAX8997_REG_GSMB_CUR = 102, - MAX8997_REG_BOOST_CNTL = 103, - MAX8997_REG_LEN_CNTL = 104, - MAX8997_REG_FLASH_CNTL = 105, - MAX8997_REG_WDT_CNTL = 106, - MAX8997_REG_MAXFLASH1 = 107, - MAX8997_REG_MAXFLASH2 = 108, - MAX8997_REG_FLASHSTATUS = 109, - MAX8997_REG_FLASHSTATUSMASK = 110, - MAX8997_REG_GPIOCNTL1 = 112, - MAX8997_REG_GPIOCNTL2 = 113, - MAX8997_REG_GPIOCNTL3 = 114, - MAX8997_REG_GPIOCNTL4 = 115, - MAX8997_REG_GPIOCNTL5 = 116, - MAX8997_REG_GPIOCNTL6 = 117, - MAX8997_REG_GPIOCNTL7 = 118, - MAX8997_REG_GPIOCNTL8 = 119, - MAX8997_REG_GPIOCNTL9 = 120, - MAX8997_REG_GPIOCNTL10 = 121, - MAX8997_REG_GPIOCNTL11 = 122, - MAX8997_REG_GPIOCNTL12 = 123, - MAX8997_REG_LDO1CONFIG = 128, - MAX8997_REG_LDO2CONFIG = 129, - MAX8997_REG_LDO3CONFIG = 130, - MAX8997_REG_LDO4CONFIG = 131, - MAX8997_REG_LDO5CONFIG = 132, - MAX8997_REG_LDO6CONFIG = 133, - MAX8997_REG_LDO7CONFIG = 134, - MAX8997_REG_LDO8CONFIG = 135, - MAX8997_REG_LDO9CONFIG = 136, - MAX8997_REG_LDO10CONFIG = 137, - MAX8997_REG_LDO11CONFIG = 138, - MAX8997_REG_LDO12CONFIG = 139, - MAX8997_REG_LDO13CONFIG = 140, - MAX8997_REG_LDO14CONFIG = 141, - MAX8997_REG_LDO15CONFIG = 142, - MAX8997_REG_LDO16CONFIG = 143, - MAX8997_REG_LDO17CONFIG = 144, - MAX8997_REG_LDO18CONFIG = 145, - MAX8997_REG_LDO21CONFIG = 146, - MAX8997_REG_DVSOKTIMER1 = 151, - MAX8997_REG_DVSOKTIMER2 = 152, - MAX8997_REG_DVSOKTIMER4 = 153, - MAX8997_REG_DVSOKTIMER5 = 154, - MAX8997_REG_PMIC_END = 155, -}; - -enum max8997_muic_reg { - MAX8997_MUIC_REG_ID = 0, - MAX8997_MUIC_REG_INT1 = 1, - MAX8997_MUIC_REG_INT2 = 2, - MAX8997_MUIC_REG_INT3 = 3, - MAX8997_MUIC_REG_STATUS1 = 4, - MAX8997_MUIC_REG_STATUS2 = 5, - MAX8997_MUIC_REG_STATUS3 = 6, - MAX8997_MUIC_REG_INTMASK1 = 7, - MAX8997_MUIC_REG_INTMASK2 = 8, - MAX8997_MUIC_REG_INTMASK3 = 9, - MAX8997_MUIC_REG_CDETCTRL = 10, - MAX8997_MUIC_REG_CONTROL1 = 12, - MAX8997_MUIC_REG_CONTROL2 = 13, - MAX8997_MUIC_REG_CONTROL3 = 14, - MAX8997_MUIC_REG_END = 15, -}; - -enum max8997_haptic_reg { - MAX8997_HAPTIC_REG_GENERAL = 0, - MAX8997_HAPTIC_REG_CONF1 = 1, - MAX8997_HAPTIC_REG_CONF2 = 2, - MAX8997_HAPTIC_REG_DRVCONF = 3, - MAX8997_HAPTIC_REG_CYCLECONF1 = 4, - MAX8997_HAPTIC_REG_CYCLECONF2 = 5, - MAX8997_HAPTIC_REG_SIGCONF1 = 6, - MAX8997_HAPTIC_REG_SIGCONF2 = 7, - MAX8997_HAPTIC_REG_SIGCONF3 = 8, - MAX8997_HAPTIC_REG_SIGCONF4 = 9, - MAX8997_HAPTIC_REG_SIGDC1 = 10, - MAX8997_HAPTIC_REG_SIGDC2 = 11, - MAX8997_HAPTIC_REG_SIGPWMDC1 = 12, - MAX8997_HAPTIC_REG_SIGPWMDC2 = 13, - MAX8997_HAPTIC_REG_SIGPWMDC3 = 14, - MAX8997_HAPTIC_REG_SIGPWMDC4 = 15, - MAX8997_HAPTIC_REG_MTR_REV = 16, - MAX8997_HAPTIC_REG_END = 17, -}; - -enum max8997_irq_source { - PMIC_INT1 = 0, - PMIC_INT2 = 1, - PMIC_INT3 = 2, - PMIC_INT4 = 3, - FUEL_GAUGE = 4, - MUIC_INT1 = 5, - MUIC_INT2 = 6, - MUIC_INT3 = 7, - GPIO_LOW = 8, - GPIO_HI = 9, - FLASH_STATUS = 10, - MAX8997_IRQ_GROUP_NR = 11, -}; - -struct max8997_dev { - struct device *dev; - struct max8997_platform_data *pdata; - struct i2c_client *i2c; - struct i2c_client *rtc; - struct i2c_client *haptic; - struct i2c_client *muic; - struct mutex iolock; - long unsigned int type; - struct platform_device *battery; - int irq; - int ono; - struct irq_domain *irq_domain; - struct mutex irqlock; - int irq_masks_cur[11]; - int irq_masks_cache[11]; - u8 reg_dump[187]; - bool gpio_status[12]; -}; - -enum max8997_types { - TYPE_MAX8997 = 0, - TYPE_MAX8966 = 1, -}; - -enum max8997_irq { - MAX8997_PMICIRQ_PWRONR = 0, - MAX8997_PMICIRQ_PWRONF = 1, - MAX8997_PMICIRQ_PWRON1SEC = 2, - MAX8997_PMICIRQ_JIGONR = 3, - MAX8997_PMICIRQ_JIGONF = 4, - MAX8997_PMICIRQ_LOWBAT2 = 5, - MAX8997_PMICIRQ_LOWBAT1 = 6, - MAX8997_PMICIRQ_JIGR = 7, - MAX8997_PMICIRQ_JIGF = 8, - MAX8997_PMICIRQ_MR = 9, - MAX8997_PMICIRQ_DVS1OK = 10, - MAX8997_PMICIRQ_DVS2OK = 11, - MAX8997_PMICIRQ_DVS3OK = 12, - MAX8997_PMICIRQ_DVS4OK = 13, - MAX8997_PMICIRQ_CHGINS = 14, - MAX8997_PMICIRQ_CHGRM = 15, - MAX8997_PMICIRQ_DCINOVP = 16, - MAX8997_PMICIRQ_TOPOFFR = 17, - MAX8997_PMICIRQ_CHGRSTF = 18, - MAX8997_PMICIRQ_MBCHGTMEXPD = 19, - MAX8997_PMICIRQ_RTC60S = 20, - MAX8997_PMICIRQ_RTCA1 = 21, - MAX8997_PMICIRQ_RTCA2 = 22, - MAX8997_PMICIRQ_SMPL_INT = 23, - MAX8997_PMICIRQ_RTC1S = 24, - MAX8997_PMICIRQ_WTSR = 25, - MAX8997_MUICIRQ_ADCError = 26, - MAX8997_MUICIRQ_ADCLow = 27, - MAX8997_MUICIRQ_ADC = 28, - MAX8997_MUICIRQ_VBVolt = 29, - MAX8997_MUICIRQ_DBChg = 30, - MAX8997_MUICIRQ_DCDTmr = 31, - MAX8997_MUICIRQ_ChgDetRun = 32, - MAX8997_MUICIRQ_ChgTyp = 33, - MAX8997_MUICIRQ_OVP = 34, - MAX8997_IRQ_NR = 35, -}; - -struct max8997_irq_data { - int mask; - enum max8997_irq_source group; -}; - -struct max8998_regulator_data { - int id; - struct regulator_init_data *initdata; - struct device_node *reg_node; -}; - -struct max8998_platform_data { - struct max8998_regulator_data *regulators; - int num_regulators; - unsigned int irq_base; - int ono; - bool buck_voltage_lock; - int buck1_voltage[4]; - int buck2_voltage[2]; - int buck1_set1; - int buck1_set2; - int buck1_default_idx; - int buck2_set3; - int buck2_default_idx; - bool wakeup; - bool rtc_delay; - int eoc; - int restart; - int timeout; -}; - -enum { - MAX8998_REG_IRQ1 = 0, - MAX8998_REG_IRQ2 = 1, - MAX8998_REG_IRQ3 = 2, - MAX8998_REG_IRQ4 = 3, - MAX8998_REG_IRQM1 = 4, - MAX8998_REG_IRQM2 = 5, - MAX8998_REG_IRQM3 = 6, - MAX8998_REG_IRQM4 = 7, - MAX8998_REG_STATUS1 = 8, - MAX8998_REG_STATUS2 = 9, - MAX8998_REG_STATUSM1 = 10, - MAX8998_REG_STATUSM2 = 11, - MAX8998_REG_CHGR1 = 12, - MAX8998_REG_CHGR2 = 13, - MAX8998_REG_LDO_ACTIVE_DISCHARGE1 = 14, - MAX8998_REG_LDO_ACTIVE_DISCHARGE2 = 15, - MAX8998_REG_BUCK_ACTIVE_DISCHARGE3 = 16, - MAX8998_REG_ONOFF1 = 17, - MAX8998_REG_ONOFF2 = 18, - MAX8998_REG_ONOFF3 = 19, - MAX8998_REG_ONOFF4 = 20, - MAX8998_REG_BUCK1_VOLTAGE1 = 21, - MAX8998_REG_BUCK1_VOLTAGE2 = 22, - MAX8998_REG_BUCK1_VOLTAGE3 = 23, - MAX8998_REG_BUCK1_VOLTAGE4 = 24, - MAX8998_REG_BUCK2_VOLTAGE1 = 25, - MAX8998_REG_BUCK2_VOLTAGE2 = 26, - MAX8998_REG_BUCK3 = 27, - MAX8998_REG_BUCK4 = 28, - MAX8998_REG_LDO2_LDO3 = 29, - MAX8998_REG_LDO4 = 30, - MAX8998_REG_LDO5 = 31, - MAX8998_REG_LDO6 = 32, - MAX8998_REG_LDO7 = 33, - MAX8998_REG_LDO8_LDO9 = 34, - MAX8998_REG_LDO10_LDO11 = 35, - MAX8998_REG_LDO12 = 36, - MAX8998_REG_LDO13 = 37, - MAX8998_REG_LDO14 = 38, - MAX8998_REG_LDO15 = 39, - MAX8998_REG_LDO16 = 40, - MAX8998_REG_LDO17 = 41, - MAX8998_REG_BKCHR = 42, - MAX8998_REG_LBCNFG1 = 43, - MAX8998_REG_LBCNFG2 = 44, -}; - -enum { - TYPE_MAX8998 = 0, - TYPE_LP3974 = 1, - TYPE_LP3979 = 2, -}; - -struct max8998_dev { - struct device *dev; - struct max8998_platform_data *pdata; - struct i2c_client *i2c; - struct i2c_client *rtc; - struct mutex iolock; - struct mutex irqlock; - unsigned int irq_base; - struct irq_domain *irq_domain; - int irq; - int ono; - u8 irq_masks_cur[4]; - u8 irq_masks_cache[4]; - long unsigned int type; - bool wakeup; -}; - -struct max8998_reg_dump { - u8 addr; - u8 val; -}; - -enum { - MAX8998_IRQ_DCINF = 0, - MAX8998_IRQ_DCINR = 1, - MAX8998_IRQ_JIGF = 2, - MAX8998_IRQ_JIGR = 3, - MAX8998_IRQ_PWRONF = 4, - MAX8998_IRQ_PWRONR = 5, - MAX8998_IRQ_WTSREVNT = 6, - MAX8998_IRQ_SMPLEVNT = 7, - MAX8998_IRQ_ALARM1 = 8, - MAX8998_IRQ_ALARM0 = 9, - MAX8998_IRQ_ONKEY1S = 10, - MAX8998_IRQ_TOPOFFR = 11, - MAX8998_IRQ_DCINOVPR = 12, - MAX8998_IRQ_CHGRSTF = 13, - MAX8998_IRQ_DONER = 14, - MAX8998_IRQ_CHGFAULT = 15, - MAX8998_IRQ_LOBAT1 = 16, - MAX8998_IRQ_LOBAT2 = 17, - MAX8998_IRQ_NR = 18, -}; - -struct max8998_irq_data { - int reg; - int mask; -}; - -struct max8997_dev___2; - -struct adp5520_gpio_platform_data { - unsigned int gpio_start; - u8 gpio_en_mask; - u8 gpio_pullup_mask; -}; - -struct adp5520_keys_platform_data { - int rows_en_mask; - int cols_en_mask; - const short unsigned int *keymap; - short unsigned int keymapsize; - unsigned int repeat: 1; -}; - -struct led_info; - -struct adp5520_leds_platform_data { - int num_leds; - struct led_info *leds; - u8 fade_in; - u8 fade_out; - u8 led_on_time; -}; - -struct adp5520_backlight_platform_data { - u8 fade_in; - u8 fade_out; - u8 fade_led_law; - u8 en_ambl_sens; - u8 abml_filt; - u8 l1_daylight_max; - u8 l1_daylight_dim; - u8 l2_office_max; - u8 l2_office_dim; - u8 l3_dark_max; - u8 l3_dark_dim; - u8 l2_trip; - u8 l2_hyst; - u8 l3_trip; - u8 l3_hyst; -}; - -struct adp5520_platform_data { - struct adp5520_keys_platform_data *keys; - struct adp5520_gpio_platform_data *gpio; - struct adp5520_leds_platform_data *leds; - struct adp5520_backlight_platform_data *backlight; -}; - -struct adp5520_chip { - struct i2c_client *client; - struct device *dev; - struct mutex lock; - struct blocking_notifier_head notifier_list; - int irq; - long unsigned int id; - uint8_t mode; -}; - -struct tps6586x_irq_data { - u8 mask_reg; - u8 mask_mask; -}; - -struct tps6586x { - struct device *dev; - struct i2c_client *client; - struct regmap *regmap; - int version; - int irq; - struct irq_chip irq_chip; - struct mutex irq_lock; - int irq_base; - u32 irq_en; - u8 mask_reg[5]; - struct irq_domain *irq_domain; -}; - -enum { - TPS65090_IRQ_INTERRUPT = 0, - TPS65090_IRQ_VAC_STATUS_CHANGE = 1, - TPS65090_IRQ_VSYS_STATUS_CHANGE = 2, - TPS65090_IRQ_BAT_STATUS_CHANGE = 3, - TPS65090_IRQ_CHARGING_STATUS_CHANGE = 4, - TPS65090_IRQ_CHARGING_COMPLETE = 5, - TPS65090_IRQ_OVERLOAD_DCDC1 = 6, - TPS65090_IRQ_OVERLOAD_DCDC2 = 7, - TPS65090_IRQ_OVERLOAD_DCDC3 = 8, - TPS65090_IRQ_OVERLOAD_FET1 = 9, - TPS65090_IRQ_OVERLOAD_FET2 = 10, - TPS65090_IRQ_OVERLOAD_FET3 = 11, - TPS65090_IRQ_OVERLOAD_FET4 = 12, - TPS65090_IRQ_OVERLOAD_FET5 = 13, - TPS65090_IRQ_OVERLOAD_FET6 = 14, - TPS65090_IRQ_OVERLOAD_FET7 = 15, -}; - -enum { - TPS65090_REGULATOR_DCDC1 = 0, - TPS65090_REGULATOR_DCDC2 = 1, - TPS65090_REGULATOR_DCDC3 = 2, - TPS65090_REGULATOR_FET1 = 3, - TPS65090_REGULATOR_FET2 = 4, - TPS65090_REGULATOR_FET3 = 5, - TPS65090_REGULATOR_FET4 = 6, - TPS65090_REGULATOR_FET5 = 7, - TPS65090_REGULATOR_FET6 = 8, - TPS65090_REGULATOR_FET7 = 9, - TPS65090_REGULATOR_LDO1 = 10, - TPS65090_REGULATOR_LDO2 = 11, - TPS65090_REGULATOR_MAX = 12, -}; - -struct tps65090 { - struct device *dev; - struct regmap *rmap; - struct regmap_irq_chip_data *irq_data; -}; - -struct tps65090_regulator_plat_data { - struct regulator_init_data *reg_init_data; - bool enable_ext_control; - struct gpio_desc *gpiod; - bool overcurrent_wait_valid; - int overcurrent_wait; -}; - -struct tps65090_platform_data { - int irq_base; - char **supplied_to; - size_t num_supplicants; - int enable_low_current_chrg; - struct tps65090_regulator_plat_data *reg_pdata[12]; -}; - -enum tps65090_cells { - PMIC = 0, - CHARGER = 1, -}; - -enum aat2870_id { - AAT2870_ID_BL = 0, - AAT2870_ID_LDOA = 1, - AAT2870_ID_LDOB = 2, - AAT2870_ID_LDOC = 3, - AAT2870_ID_LDOD = 4, -}; - -struct aat2870_register { - bool readable; - bool writeable; - u8 value; -}; - -struct aat2870_data { - struct device *dev; - struct i2c_client *client; - struct mutex io_lock; - struct aat2870_register *reg_cache; - int en_pin; - bool is_enable; - int (*init)(struct aat2870_data *); - void (*uninit)(struct aat2870_data *); - int (*read)(struct aat2870_data *, u8, u8 *); - int (*write)(struct aat2870_data *, u8, u8); - int (*update)(struct aat2870_data *, u8, u8, u8); - struct dentry *dentry_root; -}; - -struct aat2870_subdev_info { - int id; - const char *name; - void *platform_data; -}; - -struct aat2870_platform_data { - int en_pin; - struct aat2870_subdev_info *subdevs; - int num_subdevs; - int (*init)(struct aat2870_data *); - void (*uninit)(struct aat2870_data *); -}; - -enum { - PALMAS_EXT_CONTROL_ENABLE1 = 1, - PALMAS_EXT_CONTROL_ENABLE2 = 2, - PALMAS_EXT_CONTROL_NSLEEP = 4, -}; - -enum palmas_external_requestor_id { - PALMAS_EXTERNAL_REQSTR_ID_REGEN1 = 0, - PALMAS_EXTERNAL_REQSTR_ID_REGEN2 = 1, - PALMAS_EXTERNAL_REQSTR_ID_SYSEN1 = 2, - PALMAS_EXTERNAL_REQSTR_ID_SYSEN2 = 3, - PALMAS_EXTERNAL_REQSTR_ID_CLK32KG = 4, - PALMAS_EXTERNAL_REQSTR_ID_CLK32KGAUDIO = 5, - PALMAS_EXTERNAL_REQSTR_ID_REGEN3 = 6, - PALMAS_EXTERNAL_REQSTR_ID_SMPS12 = 7, - PALMAS_EXTERNAL_REQSTR_ID_SMPS3 = 8, - PALMAS_EXTERNAL_REQSTR_ID_SMPS45 = 9, - PALMAS_EXTERNAL_REQSTR_ID_SMPS6 = 10, - PALMAS_EXTERNAL_REQSTR_ID_SMPS7 = 11, - PALMAS_EXTERNAL_REQSTR_ID_SMPS8 = 12, - PALMAS_EXTERNAL_REQSTR_ID_SMPS9 = 13, - PALMAS_EXTERNAL_REQSTR_ID_SMPS10 = 14, - PALMAS_EXTERNAL_REQSTR_ID_LDO1 = 15, - PALMAS_EXTERNAL_REQSTR_ID_LDO2 = 16, - PALMAS_EXTERNAL_REQSTR_ID_LDO3 = 17, - PALMAS_EXTERNAL_REQSTR_ID_LDO4 = 18, - PALMAS_EXTERNAL_REQSTR_ID_LDO5 = 19, - PALMAS_EXTERNAL_REQSTR_ID_LDO6 = 20, - PALMAS_EXTERNAL_REQSTR_ID_LDO7 = 21, - PALMAS_EXTERNAL_REQSTR_ID_LDO8 = 22, - PALMAS_EXTERNAL_REQSTR_ID_LDO9 = 23, - PALMAS_EXTERNAL_REQSTR_ID_LDOLN = 24, - PALMAS_EXTERNAL_REQSTR_ID_LDOUSB = 25, - PALMAS_EXTERNAL_REQSTR_ID_MAX = 26, -}; - -enum tps65917_irqs { - TPS65917_RESERVED1 = 0, - TPS65917_PWRON_IRQ = 1, - TPS65917_LONG_PRESS_KEY_IRQ = 2, - TPS65917_RESERVED2 = 3, - TPS65917_PWRDOWN_IRQ = 4, - TPS65917_HOTDIE_IRQ = 5, - TPS65917_VSYS_MON_IRQ = 6, - TPS65917_RESERVED3 = 7, - TPS65917_RESERVED4 = 8, - TPS65917_OTP_ERROR_IRQ = 9, - TPS65917_WDT_IRQ = 10, - TPS65917_RESERVED5 = 11, - TPS65917_RESET_IN_IRQ = 12, - TPS65917_FSD_IRQ = 13, - TPS65917_SHORT_IRQ = 14, - TPS65917_RESERVED6 = 15, - TPS65917_GPADC_AUTO_0_IRQ = 16, - TPS65917_GPADC_AUTO_1_IRQ = 17, - TPS65917_GPADC_EOC_SW_IRQ = 18, - TPS65917_RESREVED6 = 19, - TPS65917_RESERVED7 = 20, - TPS65917_RESERVED8 = 21, - TPS65917_RESERVED9 = 22, - TPS65917_VBUS_IRQ = 23, - TPS65917_GPIO_0_IRQ = 24, - TPS65917_GPIO_1_IRQ = 25, - TPS65917_GPIO_2_IRQ = 26, - TPS65917_GPIO_3_IRQ = 27, - TPS65917_GPIO_4_IRQ = 28, - TPS65917_GPIO_5_IRQ = 29, - TPS65917_GPIO_6_IRQ = 30, - TPS65917_RESERVED10 = 31, - TPS65917_NUM_IRQ = 32, -}; - -struct palmas_driver_data { - unsigned int *features; - struct regmap_irq_chip *irq_chip; -}; - -enum { - RC5T583_DS_NONE = 0, - RC5T583_DS_DC0 = 1, - RC5T583_DS_DC1 = 2, - RC5T583_DS_DC2 = 3, - RC5T583_DS_DC3 = 4, - RC5T583_DS_LDO0 = 5, - RC5T583_DS_LDO1 = 6, - RC5T583_DS_LDO2 = 7, - RC5T583_DS_LDO3 = 8, - RC5T583_DS_LDO4 = 9, - RC5T583_DS_LDO5 = 10, - RC5T583_DS_LDO6 = 11, - RC5T583_DS_LDO7 = 12, - RC5T583_DS_LDO8 = 13, - RC5T583_DS_LDO9 = 14, - RC5T583_DS_PSO0 = 15, - RC5T583_DS_PSO1 = 16, - RC5T583_DS_PSO2 = 17, - RC5T583_DS_PSO3 = 18, - RC5T583_DS_PSO4 = 19, - RC5T583_DS_PSO5 = 20, - RC5T583_DS_PSO6 = 21, - RC5T583_DS_PSO7 = 22, - RC5T583_DS_MAX = 23, -}; - -enum { - RC5T583_EXT_PWRREQ1_CONTROL = 1, - RC5T583_EXT_PWRREQ2_CONTROL = 2, -}; - -struct deepsleep_control_data { - u8 reg_add; - u8 ds_pos_bit; -}; - -enum int_type { - SYS_INT = 1, - DCDC_INT = 2, - RTC_INT = 4, - ADC_INT = 8, - GPIO_INT = 16, -}; - -struct rc5t583_irq_data { - u8 int_type; - u8 master_bit; - u8 int_en_bit; - u8 mask_reg_index; - int grp_index; -}; - -struct syscon_platform_data { - const char *label; -}; - -struct syscon { - struct device_node *np; - struct regmap *regmap; - struct list_head list; -}; - -enum { - AS3711_REGULATOR_SD_1 = 0, - AS3711_REGULATOR_SD_2 = 1, - AS3711_REGULATOR_SD_3 = 2, - AS3711_REGULATOR_SD_4 = 3, - AS3711_REGULATOR_LDO_1 = 4, - AS3711_REGULATOR_LDO_2 = 5, - AS3711_REGULATOR_LDO_3 = 6, - AS3711_REGULATOR_LDO_4 = 7, - AS3711_REGULATOR_LDO_5 = 8, - AS3711_REGULATOR_LDO_6 = 9, - AS3711_REGULATOR_LDO_7 = 10, - AS3711_REGULATOR_LDO_8 = 11, - AS3711_REGULATOR_MAX = 12, -}; - -struct as3711 { - struct device *dev; - struct regmap *regmap; -}; - -enum as3711_su2_feedback { - AS3711_SU2_VOLTAGE = 0, - AS3711_SU2_CURR1 = 1, - AS3711_SU2_CURR2 = 2, - AS3711_SU2_CURR3 = 3, - AS3711_SU2_CURR_AUTO = 4, -}; - -enum as3711_su2_fbprot { - AS3711_SU2_LX_SD4 = 0, - AS3711_SU2_GPIO2 = 1, - AS3711_SU2_GPIO3 = 2, - AS3711_SU2_GPIO4 = 3, -}; - -struct as3711_regulator_pdata { - struct regulator_init_data *init_data[12]; -}; - -struct as3711_bl_pdata { - bool su1_fb; - int su1_max_uA; - bool su2_fb; - int su2_max_uA; - enum as3711_su2_feedback su2_feedback; - enum as3711_su2_fbprot su2_fbprot; - bool su2_auto_curr1; - bool su2_auto_curr2; - bool su2_auto_curr3; -}; - -struct as3711_platform_data { - struct as3711_regulator_pdata regulator; - struct as3711_bl_pdata backlight; -}; - -enum { - AS3711_REGULATOR = 0, - AS3711_BACKLIGHT = 1, -}; - -struct intel_soc_pmic_config { - long unsigned int irq_flags; - struct mfd_cell *cell_dev; - int n_cell_devs; - const struct regmap_config *regmap_config; - const struct regmap_irq_chip *irq_chip; -}; - -enum { - CHT_WC_PWRSRC_IRQ = 0, - CHT_WC_THRM_IRQ = 1, - CHT_WC_BCU_IRQ = 2, - CHT_WC_ADC_IRQ = 3, - CHT_WC_EXT_CHGR_IRQ = 4, - CHT_WC_GPIO_IRQ = 5, - CHT_WC_CRIT_IRQ = 7, -}; - -struct badrange { - struct list_head list; - spinlock_t lock; -}; - -enum { - NDD_ALIASING = 0, - NDD_UNARMED = 1, - NDD_LOCKED = 2, - NDD_SECURITY_OVERWRITE = 3, - NDD_WORK_PENDING = 4, - NDD_NOBLK = 5, - NDD_LABELING = 6, - ND_IOCTL_MAX_BUFLEN = 4194304, - ND_CMD_MAX_ELEM = 5, - ND_CMD_MAX_ENVELOPE = 256, - ND_MAX_MAPPINGS = 32, - ND_REGION_PAGEMAP = 0, - ND_REGION_PERSIST_CACHE = 1, - ND_REGION_PERSIST_MEMCTRL = 2, - ND_REGION_ASYNC = 3, - DPA_RESOURCE_ADJUSTED = 1, -}; - -struct nvdimm_bus_descriptor; - -struct nvdimm; - -typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *, struct nvdimm *, unsigned int, void *, unsigned int, int *); - -struct nvdimm_bus_fw_ops; - -struct nvdimm_bus_descriptor { - const struct attribute_group **attr_groups; - long unsigned int cmd_mask; - long unsigned int dimm_family_mask; - long unsigned int bus_family_mask; - struct module *module; - char *provider_name; - struct device_node *of_node; - ndctl_fn ndctl; - int (*flush_probe)(struct nvdimm_bus_descriptor *); - int (*clear_to_send)(struct nvdimm_bus_descriptor *, struct nvdimm *, unsigned int, void *); - const struct nvdimm_bus_fw_ops *fw_ops; -}; - -struct nvdimm_security_ops; - -struct nvdimm_fw_ops; - -struct nvdimm { - long unsigned int flags; - void *provider_data; - long unsigned int cmd_mask; - struct device dev; - atomic_t busy; - int id; - int num_flush; - struct resource *flush_wpq; - const char *dimm_id; - struct { - const struct nvdimm_security_ops *ops; - long unsigned int flags; - long unsigned int ext_flags; - unsigned int overwrite_tmo; - struct kernfs_node *overwrite_state; - } sec; - struct delayed_work dwork; - const struct nvdimm_fw_ops *fw_ops; -}; - -enum nvdimm_fwa_state { - NVDIMM_FWA_INVALID = 0, - NVDIMM_FWA_IDLE = 1, - NVDIMM_FWA_ARMED = 2, - NVDIMM_FWA_BUSY = 3, - NVDIMM_FWA_ARM_OVERFLOW = 4, -}; - -enum nvdimm_fwa_capability { - NVDIMM_FWA_CAP_INVALID = 0, - NVDIMM_FWA_CAP_NONE = 1, - NVDIMM_FWA_CAP_QUIESCE = 2, - NVDIMM_FWA_CAP_LIVE = 3, -}; - -struct nvdimm_bus_fw_ops { - enum nvdimm_fwa_state (*activate_state)(struct nvdimm_bus_descriptor *); - enum nvdimm_fwa_capability (*capability)(struct nvdimm_bus_descriptor *); - int (*activate)(struct nvdimm_bus_descriptor *); -}; - -struct nvdimm_bus { - struct nvdimm_bus_descriptor *nd_desc; - wait_queue_head_t wait; - struct list_head list; - struct device dev; - int id; - int probe_active; - atomic_t ioctl_active; - struct list_head mapping_list; - struct mutex reconfig_mutex; - struct badrange badrange; -}; - -struct nvdimm_key_data { - u8 data[32]; -}; - -enum nvdimm_passphrase_type { - NVDIMM_USER = 0, - NVDIMM_MASTER = 1, -}; - -struct nvdimm_security_ops { - long unsigned int (*get_flags)(struct nvdimm *, enum nvdimm_passphrase_type); - int (*freeze)(struct nvdimm *); - int (*change_key)(struct nvdimm *, const struct nvdimm_key_data *, const struct nvdimm_key_data *, enum nvdimm_passphrase_type); - int (*unlock)(struct nvdimm *, const struct nvdimm_key_data *); - int (*disable)(struct nvdimm *, const struct nvdimm_key_data *); - int (*erase)(struct nvdimm *, const struct nvdimm_key_data *, enum nvdimm_passphrase_type); - int (*overwrite)(struct nvdimm *, const struct nvdimm_key_data *); - int (*query_overwrite)(struct nvdimm *); -}; - -enum nvdimm_fwa_trigger { - NVDIMM_FWA_ARM = 0, - NVDIMM_FWA_DISARM = 1, -}; - -enum nvdimm_fwa_result { - NVDIMM_FWA_RESULT_INVALID = 0, - NVDIMM_FWA_RESULT_NONE = 1, - NVDIMM_FWA_RESULT_SUCCESS = 2, - NVDIMM_FWA_RESULT_NOTSTAGED = 3, - NVDIMM_FWA_RESULT_NEEDRESET = 4, - NVDIMM_FWA_RESULT_FAIL = 5, -}; - -struct nvdimm_fw_ops { - enum nvdimm_fwa_state (*activate_state)(struct nvdimm *); - enum nvdimm_fwa_result (*activate_result)(struct nvdimm *); - int (*arm)(struct nvdimm *, enum nvdimm_fwa_trigger); -}; - -enum { - ND_CMD_IMPLEMENTED = 0, - ND_CMD_ARS_CAP = 1, - ND_CMD_ARS_START = 2, - ND_CMD_ARS_STATUS = 3, - ND_CMD_CLEAR_ERROR = 4, - ND_CMD_SMART = 1, - ND_CMD_SMART_THRESHOLD = 2, - ND_CMD_DIMM_FLAGS = 3, - ND_CMD_GET_CONFIG_SIZE = 4, - ND_CMD_GET_CONFIG_DATA = 5, - ND_CMD_SET_CONFIG_DATA = 6, - ND_CMD_VENDOR_EFFECT_LOG_SIZE = 7, - ND_CMD_VENDOR_EFFECT_LOG = 8, - ND_CMD_VENDOR = 9, - ND_CMD_CALL = 10, -}; - -enum { - NSINDEX_SIG_LEN = 16, - NSINDEX_ALIGN = 256, - NSINDEX_SEQ_MASK = 3, - NSLABEL_UUID_LEN = 16, - NSLABEL_NAME_LEN = 64, - NSLABEL_FLAG_ROLABEL = 1, - NSLABEL_FLAG_LOCAL = 2, - NSLABEL_FLAG_BTT = 4, - NSLABEL_FLAG_UPDATING = 8, - BTT_ALIGN = 4096, - BTTINFO_SIG_LEN = 16, - BTTINFO_UUID_LEN = 16, - BTTINFO_FLAG_ERROR = 1, - BTTINFO_MAJOR_VERSION = 1, - ND_LABEL_MIN_SIZE = 1024, - ND_LABEL_ID_SIZE = 50, - ND_NSINDEX_INIT = 1, -}; - -struct nvdimm_map { - struct nvdimm_bus *nvdimm_bus; - struct list_head list; - resource_size_t offset; - long unsigned int flags; - size_t size; - union { - void *mem; - void *iomem; - }; - struct kref kref; -}; - -struct badrange_entry { - u64 start; - u64 length; - struct list_head list; -}; - -struct nd_cmd_desc { - int in_num; - int out_num; - u32 in_sizes[5]; - int out_sizes[5]; -}; - -struct nd_interleave_set { - u64 cookie1; - u64 cookie2; - u64 altcookie; - guid_t type_guid; -}; - -struct nvdimm_drvdata; - -struct nd_mapping { - struct nvdimm *nvdimm; - u64 start; - u64 size; - int position; - struct list_head labels; - struct mutex lock; - struct nvdimm_drvdata *ndd; -}; - -struct nd_percpu_lane; - -struct nd_region { - struct device dev; - struct ida ns_ida; - struct ida btt_ida; - struct ida pfn_ida; - struct ida dax_ida; - long unsigned int flags; - struct device *ns_seed; - struct device *btt_seed; - struct device *pfn_seed; - struct device *dax_seed; - long unsigned int align; - u16 ndr_mappings; - u64 ndr_size; - u64 ndr_start; - int id; - int num_lanes; - int ro; - int numa_node; - int target_node; - void *provider_data; - struct kernfs_node *bb_state; - struct badblocks bb; - struct nd_interleave_set *nd_set; - struct nd_percpu_lane *lane; - int (*flush)(struct nd_region *, struct bio *); - struct nd_mapping mapping[0]; -}; - -struct nd_cmd_get_config_size { - __u32 status; - __u32 config_size; - __u32 max_xfer; -}; - -struct nd_cmd_set_config_hdr { - __u32 in_offset; - __u32 in_length; - __u8 in_buf[0]; -}; - -struct nd_cmd_vendor_hdr { - __u32 opcode; - __u32 in_length; - __u8 in_buf[0]; -}; - -struct nd_cmd_ars_cap { - __u64 address; - __u64 length; - __u32 status; - __u32 max_ars_out; - __u32 clear_err_unit; - __u16 flags; - __u16 reserved; -}; - -struct nd_cmd_clear_error { - __u64 address; - __u64 length; - __u32 status; - __u8 reserved[4]; - __u64 cleared; -}; - -struct nd_cmd_pkg { - __u64 nd_family; - __u64 nd_command; - __u32 nd_size_in; - __u32 nd_size_out; - __u32 nd_reserved2[9]; - __u32 nd_fw_size; - unsigned char nd_payload[0]; -}; - -enum nvdimm_event { - NVDIMM_REVALIDATE_POISON = 0, - NVDIMM_REVALIDATE_REGION = 1, -}; - -enum nvdimm_claim_class { - NVDIMM_CCLASS_NONE = 0, - NVDIMM_CCLASS_BTT = 1, - NVDIMM_CCLASS_BTT2 = 2, - NVDIMM_CCLASS_PFN = 3, - NVDIMM_CCLASS_DAX = 4, - NVDIMM_CCLASS_UNKNOWN = 5, -}; - -struct nd_device_driver { - struct device_driver drv; - long unsigned int type; - int (*probe)(struct device *); - void (*remove)(struct device *); - void (*shutdown)(struct device *); - void (*notify)(struct device *, enum nvdimm_event); -}; - -struct nd_namespace_common { - int force_raw; - struct device dev; - struct device *claim; - enum nvdimm_claim_class claim_class; - int (*rw_bytes)(struct nd_namespace_common *, resource_size_t, void *, size_t, int, long unsigned int); -}; - -struct nd_namespace_io { - struct nd_namespace_common common; - struct resource res; - resource_size_t size; - void *addr; - struct badblocks bb; -}; - -struct nvdimm_drvdata { - struct device *dev; - int nslabel_size; - struct nd_cmd_get_config_size nsarea; - void *data; - int ns_current; - int ns_next; - struct resource dpa; - struct kref kref; -}; - -struct nd_percpu_lane { - int count; - spinlock_t lock; -}; - -struct btt; - -struct nd_btt { - struct device dev; - struct nd_namespace_common *ndns; - struct btt *btt; - long unsigned int lbasize; - u64 size; - u8 *uuid; - int id; - int initial_offset; - u16 version_major; - u16 version_minor; -}; - -enum nd_pfn_mode { - PFN_MODE_NONE = 0, - PFN_MODE_RAM = 1, - PFN_MODE_PMEM = 2, -}; - -struct nd_pfn_sb; - -struct nd_pfn { - int id; - u8 *uuid; - struct device dev; - long unsigned int align; - long unsigned int npfns; - enum nd_pfn_mode mode; - struct nd_pfn_sb *pfn_sb; - struct nd_namespace_common *ndns; -}; - -struct nd_pfn_sb { - u8 signature[16]; - u8 uuid[16]; - u8 parent_uuid[16]; - __le32 flags; - __le16 version_major; - __le16 version_minor; - __le64 dataoff; - __le64 npfns; - __le32 mode; - __le32 start_pad; - __le32 end_trunc; - __le32 align; - __le32 page_size; - __le16 page_struct_size; - u8 padding[3994]; - __le64 checksum; -}; - -struct nd_dax { - struct nd_pfn nd_pfn; -}; - -enum nd_async_mode { - ND_SYNC = 0, - ND_ASYNC = 1, -}; - -struct clear_badblocks_context { - resource_size_t phys; - resource_size_t cleared; -}; - -enum nd_ioctl_mode { - BUS_IOCTL = 0, - DIMM_IOCTL = 1, -}; - -struct nd_cmd_get_config_data_hdr { - __u32 in_offset; - __u32 in_length; - __u32 status; - __u8 out_buf[0]; -}; - -struct nd_blk_region { - int (*enable)(struct nvdimm_bus *, struct device *); - int (*do_io)(struct nd_blk_region *, resource_size_t, void *, u64, int); - void *blk_provider_data; - struct nd_region nd_region; -}; - -enum nvdimm_security_bits { - NVDIMM_SECURITY_DISABLED = 0, - NVDIMM_SECURITY_UNLOCKED = 1, - NVDIMM_SECURITY_LOCKED = 2, - NVDIMM_SECURITY_FROZEN = 3, - NVDIMM_SECURITY_OVERWRITE = 4, -}; - -struct nd_label_id { - char id[50]; -}; - -struct blk_alloc_info { - struct nd_mapping *nd_mapping; - resource_size_t available; - resource_size_t busy; - struct resource *res; -}; - -enum nd_driver_flags { - ND_DRIVER_DIMM = 2, - ND_DRIVER_REGION_PMEM = 4, - ND_DRIVER_REGION_BLK = 8, - ND_DRIVER_NAMESPACE_IO = 16, - ND_DRIVER_NAMESPACE_PMEM = 32, - ND_DRIVER_NAMESPACE_BLK = 64, - ND_DRIVER_DAX_PMEM = 128, -}; - -struct nd_mapping_desc { - struct nvdimm *nvdimm; - u64 start; - u64 size; - int position; -}; - -struct nd_region_desc { - struct resource *res; - struct nd_mapping_desc *mapping; - u16 num_mappings; - const struct attribute_group **attr_groups; - struct nd_interleave_set *nd_set; - void *provider_data; - int num_lanes; - int numa_node; - int target_node; - long unsigned int flags; - struct device_node *of_node; - int (*flush)(struct nd_region *, struct bio *); -}; - -struct nd_blk_region_desc { - int (*enable)(struct nvdimm_bus *, struct device *); - int (*do_io)(struct nd_blk_region *, resource_size_t, void *, u64, int); - struct nd_region_desc ndr_desc; -}; - -struct nd_namespace_index { - u8 sig[16]; - u8 flags[3]; - u8 labelsize; - __le32 seq; - __le64 myoff; - __le64 mysize; - __le64 otheroff; - __le64 labeloff; - __le32 nslot; - __le16 major; - __le16 minor; - __le64 checksum; - u8 free[0]; -}; - -struct nd_namespace_label { - u8 uuid[16]; - u8 name[64]; - __le32 flags; - __le16 nlabel; - __le16 position; - __le64 isetcookie; - __le64 lbasize; - __le64 dpa; - __le64 rawsize; - __le32 slot; - u8 align; - u8 reserved[3]; - guid_t type_guid; - guid_t abstraction_guid; - u8 reserved2[88]; - __le64 checksum; -}; - -enum { - ND_MAX_LANES = 256, - INT_LBASIZE_ALIGNMENT = 64, - NVDIMM_IO_ATOMIC = 1, -}; - -struct nd_region_data { - int ns_count; - int ns_active; - unsigned int hints_shift; - void *flush_wpq[0]; -}; - -struct nd_label_ent { - struct list_head list; - long unsigned int flags; - struct nd_namespace_label *label; -}; - -struct conflict_context { - struct nd_region *nd_region; - resource_size_t start; - resource_size_t size; -}; - -enum { - ND_MIN_NAMESPACE_SIZE = 4096, -}; - -struct nd_namespace_pmem { - struct nd_namespace_io nsio; - long unsigned int lbasize; - char *alt_name; - u8 *uuid; - int id; -}; - -struct nd_namespace_blk { - struct nd_namespace_common common; - char *alt_name; - u8 *uuid; - int id; - long unsigned int lbasize; - resource_size_t size; - int num_resources; - struct resource **res; -}; - -enum nd_label_flags { - ND_LABEL_REAP = 0, -}; - -enum alloc_loc { - ALLOC_ERR = 0, - ALLOC_BEFORE = 1, - ALLOC_MID = 2, - ALLOC_AFTER = 3, -}; - -struct btt { - struct gendisk *btt_disk; - struct list_head arena_list; - struct dentry *debugfs_dir; - struct nd_btt *nd_btt; - u64 nlba; - long long unsigned int rawsize; - u32 lbasize; - u32 sector_size; - struct nd_region *nd_region; - struct mutex init_lock; - int init_state; - int num_arenas; - struct badblocks *phys_bb; -}; - -struct nd_gen_sb { - char reserved[4088]; - __le64 checksum; -}; - -struct btt_sb { - u8 signature[16]; - u8 uuid[16]; - u8 parent_uuid[16]; - __le32 flags; - __le16 version_major; - __le16 version_minor; - __le32 external_lbasize; - __le32 external_nlba; - __le32 internal_lbasize; - __le32 internal_nlba; - __le32 nfree; - __le32 infosize; - __le64 nextoff; - __le64 dataoff; - __le64 mapoff; - __le64 logoff; - __le64 info2off; - u8 padding[3968]; - __le64 checksum; -}; - -struct dax_operations { - long int (*direct_access)(struct dax_device *, long unsigned int, long int, void **, pfn_t *); - bool (*dax_supported)(struct dax_device *, struct block_device *, int, sector_t, sector_t); - size_t (*copy_from_iter)(struct dax_device *, long unsigned int, void *, size_t, struct iov_iter *); - size_t (*copy_to_iter)(struct dax_device *, long unsigned int, void *, size_t, struct iov_iter *); - int (*zero_page_range)(struct dax_device *, long unsigned int, size_t); -}; - -struct dax_device { - struct hlist_node list; - struct inode inode; - struct cdev cdev; - const char *host; - void *private; - long unsigned int flags; - const struct dax_operations *ops; -}; - -enum dax_device_flags { - DAXDEV_ALIVE = 0, - DAXDEV_WRITE_CACHE = 1, - DAXDEV_SYNC = 2, -}; - -struct dax_region { - int id; - int target_node; - struct kref kref; - struct device *dev; - unsigned int align; - struct ida ida; - struct resource res; - struct device *seed; - struct device *youngest; -}; - -struct dax_mapping { - struct device dev; - int range_id; - int id; -}; - -struct dev_dax_range { - long unsigned int pgoff; - struct range range; - struct dax_mapping *mapping; -}; - -struct dev_dax { - struct dax_region *region; - struct dax_device *dax_dev; - unsigned int align; - int target_node; - int id; - struct ida ida; - struct device dev; - struct dev_pagemap *pgmap; - int nr_range; - struct dev_dax_range *ranges; -}; - -enum dev_dax_subsys { - DEV_DAX_BUS = 0, - DEV_DAX_CLASS = 1, -}; - -struct dev_dax_data { - struct dax_region *dax_region; - struct dev_pagemap *pgmap; - enum dev_dax_subsys subsys; - resource_size_t size; - int id; -}; - -struct dax_device_driver { - struct device_driver drv; - struct list_head ids; - int match_always; - int (*probe)(struct dev_dax *); - void (*remove)(struct dev_dax *); -}; - -struct dax_id { - struct list_head list; - char dev_name[30]; -}; - -enum id_action { - ID_REMOVE = 0, - ID_ADD = 1, -}; - -struct memregion_info { - int target_node; -}; - -struct seqcount_ww_mutex { - seqcount_t seqcount; -}; - -typedef struct seqcount_ww_mutex seqcount_ww_mutex_t; - -struct dma_buf_map { - union { - void *vaddr_iomem; - void *vaddr; - }; - bool is_iomem; -}; - -struct dma_fence_ops; - -struct dma_fence { - spinlock_t *lock; - const struct dma_fence_ops *ops; - union { - struct list_head cb_list; - ktime_t timestamp; - struct callback_head rcu; - }; - u64 context; - u64 seqno; - long unsigned int flags; - struct kref refcount; - int error; -}; - -struct dma_fence_ops { - bool use_64bit_seqno; - const char * (*get_driver_name)(struct dma_fence *); - const char * (*get_timeline_name)(struct dma_fence *); - bool (*enable_signaling)(struct dma_fence *); - bool (*signaled)(struct dma_fence *); - long int (*wait)(struct dma_fence *, bool, long int); - void (*release)(struct dma_fence *); - void (*fence_value_str)(struct dma_fence *, char *, int); - void (*timeline_value_str)(struct dma_fence *, char *, int); -}; - -enum dma_fence_flag_bits { - DMA_FENCE_FLAG_SIGNALED_BIT = 0, - DMA_FENCE_FLAG_TIMESTAMP_BIT = 1, - DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT = 2, - DMA_FENCE_FLAG_USER_BITS = 3, -}; - -struct dma_fence_cb; - -typedef void (*dma_fence_func_t)(struct dma_fence *, struct dma_fence_cb *); - -struct dma_fence_cb { - struct list_head node; - dma_fence_func_t func; -}; - -struct dma_buf; - -struct dma_buf_attachment; - -struct dma_buf_ops { - bool cache_sgt_mapping; - int (*attach)(struct dma_buf *, struct dma_buf_attachment *); - void (*detach)(struct dma_buf *, struct dma_buf_attachment *); - int (*pin)(struct dma_buf_attachment *); - void (*unpin)(struct dma_buf_attachment *); - struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction); - void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *, enum dma_data_direction); - void (*release)(struct dma_buf *); - int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction); - int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); - int (*mmap)(struct dma_buf *, struct vm_area_struct *); - int (*vmap)(struct dma_buf *, struct dma_buf_map *); - void (*vunmap)(struct dma_buf *, struct dma_buf_map *); -}; - -struct dma_buf_poll_cb_t { - struct dma_fence_cb cb; - wait_queue_head_t *poll; - __poll_t active; -}; - -struct dma_resv; - -struct dma_buf { - size_t size; - struct file *file; - struct list_head attachments; - const struct dma_buf_ops *ops; - struct mutex lock; - unsigned int vmapping_counter; - struct dma_buf_map vmap_ptr; - const char *exp_name; - const char *name; - spinlock_t name_lock; - struct module *owner; - struct list_head list_node; - void *priv; - struct dma_resv *resv; - wait_queue_head_t poll; - struct dma_buf_poll_cb_t cb_excl; - struct dma_buf_poll_cb_t cb_shared; -}; - -struct dma_buf_attach_ops; - -struct dma_buf_attachment { - struct dma_buf *dmabuf; - struct device *dev; - struct list_head node; - struct sg_table *sgt; - enum dma_data_direction dir; - bool peer2peer; - const struct dma_buf_attach_ops *importer_ops; - void *importer_priv; - void *priv; -}; - -struct dma_resv_list; - -struct dma_resv { - struct ww_mutex lock; - seqcount_ww_mutex_t seq; - struct dma_fence *fence_excl; - struct dma_resv_list *fence; -}; - -struct dma_buf_attach_ops { - bool allow_peer2peer; - void (*move_notify)(struct dma_buf_attachment *); -}; - -struct dma_buf_export_info { - const char *exp_name; - struct module *owner; - const struct dma_buf_ops *ops; - size_t size; - int flags; - struct dma_resv *resv; - void *priv; -}; - -struct dma_resv_list { - struct callback_head rcu; - u32 shared_count; - u32 shared_max; - struct dma_fence *shared[0]; -}; - -struct dma_buf_sync { - __u64 flags; -}; - -struct dma_buf_list { - struct list_head head; - struct mutex lock; -}; - -struct trace_event_raw_dma_fence { - struct trace_entry ent; - u32 __data_loc_driver; - u32 __data_loc_timeline; - unsigned int context; - unsigned int seqno; - char __data[0]; -}; - -struct trace_event_data_offsets_dma_fence { - u32 driver; - u32 timeline; -}; - -typedef void (*btf_trace_dma_fence_emit)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_init)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_destroy)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_enable_signal)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_signaled)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_wait_start)(void *, struct dma_fence *); - -typedef void (*btf_trace_dma_fence_wait_end)(void *, struct dma_fence *); - -struct default_wait_cb { - struct dma_fence_cb base; - struct task_struct *task; -}; - -struct dma_fence_array; - -struct dma_fence_array_cb { - struct dma_fence_cb cb; - struct dma_fence_array *array; -}; - -struct dma_fence_array { - struct dma_fence base; - spinlock_t lock; - unsigned int num_fences; - atomic_t num_pending; - struct dma_fence **fences; - struct irq_work work; -}; - -struct dma_fence_chain { - struct dma_fence base; - spinlock_t lock; - struct dma_fence *prev; - u64 prev_seqno; - struct dma_fence *fence; - struct dma_fence_cb cb; - struct irq_work work; -}; - -enum seqno_fence_condition { - SEQNO_FENCE_WAIT_GEQUAL = 0, - SEQNO_FENCE_WAIT_NONZERO = 1, -}; - -struct seqno_fence { - struct dma_fence base; - const struct dma_fence_ops *ops; - struct dma_buf *sync_buf; - uint32_t seqno_ofs; - enum seqno_fence_condition condition; -}; - -struct dma_heap; - -struct dma_heap_ops { - struct dma_buf * (*allocate)(struct dma_heap *, long unsigned int, long unsigned int, long unsigned int); -}; - -struct dma_heap { - const char *name; - const struct dma_heap_ops *ops; - void *priv; - dev_t heap_devt; - struct list_head list; - struct cdev heap_cdev; -}; - -struct dma_heap_export_info { - const char *name; - const struct dma_heap_ops *ops; - void *priv; -}; - -struct dma_heap_allocation_data { - __u64 len; - __u32 fd; - __u32 fd_flags; - __u64 heap_flags; -}; - -struct system_heap_buffer { - struct dma_heap *heap; - struct list_head attachments; - struct mutex lock; - long unsigned int len; - struct sg_table sg_table; - int vmap_cnt; - void *vaddr; -}; - -struct dma_heap_attachment { - struct device *dev; - struct sg_table *table; - struct list_head list; - bool mapped; -}; - -struct cma_heap { - struct dma_heap *heap; - struct cma *cma; -}; - -struct cma_heap_buffer { - struct cma_heap *heap; - struct list_head attachments; - struct mutex lock; - long unsigned int len; - struct page *cma_pages; - struct page **pages; - long unsigned int pagecount; - int vmap_cnt; - void *vaddr; -}; - -struct dma_heap_attachment___2 { - struct device *dev; - struct sg_table table; - struct list_head list; - bool mapped; -}; - -struct sync_file { - struct file *file; - char user_name[32]; - struct list_head sync_file_list; - wait_queue_head_t wq; - long unsigned int flags; - struct dma_fence *fence; - struct dma_fence_cb cb; -}; - -struct sync_merge_data { - char name[32]; - __s32 fd2; - __s32 fence; - __u32 flags; - __u32 pad; -}; - -struct sync_fence_info { - char obj_name[32]; - char driver_name[32]; - __s32 status; - __u32 flags; - __u64 timestamp_ns; -}; - -struct sync_file_info { - char name[32]; - __s32 status; - __u32 flags; - __u32 num_fences; - __u32 pad; - __u64 sync_fence_info; -}; - -struct udmabuf_create { - __u32 memfd; - __u32 flags; - __u64 offset; - __u64 size; -}; - -struct udmabuf_create_item { - __u32 memfd; - __u32 __pad; - __u64 offset; - __u64 size; -}; - -struct udmabuf_create_list { - __u32 flags; - __u32 count; - struct udmabuf_create_item list[0]; -}; - -struct udmabuf { - long unsigned int pagecount; - struct page **pages; - struct sg_table *sg; - struct miscdevice *device; -}; - -enum scsi_host_status { - DID_OK = 0, - DID_NO_CONNECT = 1, - DID_BUS_BUSY = 2, - DID_TIME_OUT = 3, - DID_BAD_TARGET = 4, - DID_ABORT = 5, - DID_PARITY = 6, - DID_ERROR = 7, - DID_RESET = 8, - DID_BAD_INTR = 9, - DID_PASSTHROUGH = 10, - DID_SOFT_ERROR = 11, - DID_IMM_RETRY = 12, - DID_REQUEUE = 13, - DID_TRANSPORT_DISRUPTED = 14, - DID_TRANSPORT_FAILFAST = 15, - DID_TARGET_FAILURE = 16, - DID_NEXUS_FAILURE = 17, - DID_ALLOC_FAILURE = 18, - DID_MEDIUM_ERROR = 19, - DID_TRANSPORT_MARGINAL = 20, -}; - -enum scsi_disposition { - NEEDS_RETRY = 8193, - SUCCESS = 8194, - FAILED = 8195, - QUEUED = 8196, - SOFT_ERROR = 8197, - ADD_TO_MLQUEUE = 8198, - TIMEOUT_ERROR = 8199, - SCSI_RETURN_NOT_HANDLED = 8200, - FAST_IO_FAIL = 8201, -}; - -typedef __u64 blist_flags_t; - -enum scsi_device_state { - SDEV_CREATED = 1, - SDEV_RUNNING = 2, - SDEV_CANCEL = 3, - SDEV_DEL = 4, - SDEV_QUIESCE = 5, - SDEV_OFFLINE = 6, - SDEV_TRANSPORT_OFFLINE = 7, - SDEV_BLOCK = 8, - SDEV_CREATED_BLOCK = 9, -}; - -struct scsi_vpd { - struct callback_head rcu; - int len; - unsigned char data[0]; -}; - -struct Scsi_Host; - -struct scsi_target; - -struct scsi_device_handler; - -struct scsi_device { - struct Scsi_Host *host; - struct request_queue *request_queue; - struct list_head siblings; - struct list_head same_target_siblings; - struct sbitmap budget_map; - atomic_t device_blocked; - atomic_t restarts; - spinlock_t list_lock; - struct list_head starved_entry; - short unsigned int queue_depth; - short unsigned int max_queue_depth; - short unsigned int last_queue_full_depth; - short unsigned int last_queue_full_count; - long unsigned int last_queue_full_time; - long unsigned int queue_ramp_up_period; - long unsigned int last_queue_ramp_up; - unsigned int id; - unsigned int channel; - u64 lun; - unsigned int manufacturer; - unsigned int sector_size; - void *hostdata; - unsigned char type; - char scsi_level; - char inq_periph_qual; - struct mutex inquiry_mutex; - unsigned char inquiry_len; - unsigned char *inquiry; - const char *vendor; - const char *model; - const char *rev; - struct scsi_vpd *vpd_pg0; - struct scsi_vpd *vpd_pg83; - struct scsi_vpd *vpd_pg80; - struct scsi_vpd *vpd_pg89; - unsigned char current_tag; - struct scsi_target *sdev_target; - blist_flags_t sdev_bflags; - unsigned int eh_timeout; - unsigned int removable: 1; - unsigned int changed: 1; - unsigned int busy: 1; - unsigned int lockable: 1; - unsigned int locked: 1; - unsigned int borken: 1; - unsigned int disconnect: 1; - unsigned int soft_reset: 1; - unsigned int sdtr: 1; - unsigned int wdtr: 1; - unsigned int ppr: 1; - unsigned int tagged_supported: 1; - unsigned int simple_tags: 1; - unsigned int was_reset: 1; - unsigned int expecting_cc_ua: 1; - unsigned int use_10_for_rw: 1; - unsigned int use_10_for_ms: 1; - unsigned int set_dbd_for_ms: 1; - unsigned int no_report_opcodes: 1; - unsigned int no_write_same: 1; - unsigned int use_16_for_rw: 1; - unsigned int skip_ms_page_8: 1; - unsigned int skip_ms_page_3f: 1; - unsigned int skip_vpd_pages: 1; - unsigned int try_vpd_pages: 1; - unsigned int use_192_bytes_for_3f: 1; - unsigned int no_start_on_add: 1; - unsigned int allow_restart: 1; - unsigned int manage_start_stop: 1; - unsigned int start_stop_pwr_cond: 1; - unsigned int no_uld_attach: 1; - unsigned int select_no_atn: 1; - unsigned int fix_capacity: 1; - unsigned int guess_capacity: 1; - unsigned int retry_hwerror: 1; - unsigned int last_sector_bug: 1; - unsigned int no_read_disc_info: 1; - unsigned int no_read_capacity_16: 1; - unsigned int try_rc_10_first: 1; - unsigned int security_supported: 1; - unsigned int is_visible: 1; - unsigned int wce_default_on: 1; - unsigned int no_dif: 1; - unsigned int broken_fua: 1; - unsigned int lun_in_cdb: 1; - unsigned int unmap_limit_for_ws: 1; - unsigned int rpm_autosuspend: 1; - bool offline_already; - atomic_t disk_events_disable_depth; - long unsigned int supported_events[1]; - long unsigned int pending_events[1]; - struct list_head event_list; - struct work_struct event_work; - unsigned int max_device_blocked; - atomic_t iorequest_cnt; - atomic_t iodone_cnt; - atomic_t ioerr_cnt; - struct device sdev_gendev; - struct device sdev_dev; - struct execute_work ew; - struct work_struct requeue_work; - struct scsi_device_handler *handler; - void *handler_data; - size_t dma_drain_len; - void *dma_drain_buf; - unsigned char access_state; - struct mutex state_mutex; - enum scsi_device_state sdev_state; - struct task_struct *quiesced_by; - long unsigned int sdev_data[0]; -}; - -enum scsi_host_state { - SHOST_CREATED = 1, - SHOST_RUNNING = 2, - SHOST_CANCEL = 3, - SHOST_DEL = 4, - SHOST_RECOVERY = 5, - SHOST_CANCEL_RECOVERY = 6, - SHOST_DEL_RECOVERY = 7, -}; - -struct scsi_host_template; - -struct scsi_transport_template; - -struct Scsi_Host { - struct list_head __devices; - struct list_head __targets; - struct list_head starved_list; - spinlock_t default_lock; - spinlock_t *host_lock; - struct mutex scan_mutex; - struct list_head eh_cmd_q; - struct task_struct *ehandler; - struct completion *eh_action; - wait_queue_head_t host_wait; - struct scsi_host_template *hostt; - struct scsi_transport_template *transportt; - struct blk_mq_tag_set tag_set; - atomic_t host_blocked; - unsigned int host_failed; - unsigned int host_eh_scheduled; - unsigned int host_no; - int eh_deadline; - long unsigned int last_reset; - unsigned int max_channel; - unsigned int max_id; - u64 max_lun; - unsigned int unique_id; - short unsigned int max_cmd_len; - int this_id; - int can_queue; - short int cmd_per_lun; - short unsigned int sg_tablesize; - short unsigned int sg_prot_tablesize; - unsigned int max_sectors; - unsigned int max_segment_size; - long unsigned int dma_boundary; - long unsigned int virt_boundary_mask; - unsigned int nr_hw_queues; - unsigned int nr_maps; - unsigned int active_mode: 2; - unsigned int host_self_blocked: 1; - unsigned int reverse_ordering: 1; - unsigned int tmf_in_progress: 1; - unsigned int async_scan: 1; - unsigned int eh_noresume: 1; - unsigned int no_write_same: 1; - unsigned int host_tagset: 1; - unsigned int short_inquiry: 1; - unsigned int no_scsi2_lun_in_cdb: 1; - char work_q_name[20]; - struct workqueue_struct *work_q; - struct workqueue_struct *tmf_work_q; - unsigned int max_host_blocked; - unsigned int prot_capabilities; - unsigned char prot_guard_type; - long unsigned int base; - long unsigned int io_port; - unsigned char n_io_port; - unsigned char dma_channel; - unsigned int irq; - enum scsi_host_state shost_state; - struct device shost_gendev; - struct device shost_dev; - void *shost_data; - struct device *dma_dev; - long unsigned int hostdata[0]; -}; - -enum scsi_target_state { - STARGET_CREATED = 1, - STARGET_RUNNING = 2, - STARGET_REMOVE = 3, - STARGET_CREATED_REMOVE = 4, - STARGET_DEL = 5, -}; - -struct scsi_target { - struct scsi_device *starget_sdev_user; - struct list_head siblings; - struct list_head devices; - struct device dev; - struct kref reap_ref; - unsigned int channel; - unsigned int id; - unsigned int create: 1; - unsigned int single_lun: 1; - unsigned int pdt_1f_for_no_lun: 1; - unsigned int no_report_luns: 1; - unsigned int expecting_lun_change: 1; - atomic_t target_busy; - atomic_t target_blocked; - unsigned int can_queue; - unsigned int max_target_blocked; - char scsi_level; - enum scsi_target_state state; - void *hostdata; - long unsigned int starget_data[0]; -}; - -struct scsi_host_cmd_pool; - -struct scsi_cmnd; - -struct scsi_host_template { - unsigned int cmd_size; - int (*queuecommand)(struct Scsi_Host *, struct scsi_cmnd *); - void (*commit_rqs)(struct Scsi_Host *, u16); - struct module *module; - const char *name; - const char * (*info)(struct Scsi_Host *); - int (*ioctl)(struct scsi_device *, unsigned int, void *); - int (*compat_ioctl)(struct scsi_device *, unsigned int, void *); - int (*init_cmd_priv)(struct Scsi_Host *, struct scsi_cmnd *); - int (*exit_cmd_priv)(struct Scsi_Host *, struct scsi_cmnd *); - int (*eh_abort_handler)(struct scsi_cmnd *); - int (*eh_device_reset_handler)(struct scsi_cmnd *); - int (*eh_target_reset_handler)(struct scsi_cmnd *); - int (*eh_bus_reset_handler)(struct scsi_cmnd *); - int (*eh_host_reset_handler)(struct scsi_cmnd *); - int (*slave_alloc)(struct scsi_device *); - int (*slave_configure)(struct scsi_device *); - void (*slave_destroy)(struct scsi_device *); - int (*target_alloc)(struct scsi_target *); - void (*target_destroy)(struct scsi_target *); - int (*scan_finished)(struct Scsi_Host *, long unsigned int); - void (*scan_start)(struct Scsi_Host *); - int (*change_queue_depth)(struct scsi_device *, int); - int (*map_queues)(struct Scsi_Host *); - int (*mq_poll)(struct Scsi_Host *, unsigned int); - bool (*dma_need_drain)(struct request *); - int (*bios_param)(struct scsi_device *, struct block_device *, sector_t, int *); - void (*unlock_native_capacity)(struct scsi_device *); - int (*show_info)(struct seq_file *, struct Scsi_Host *); - int (*write_info)(struct Scsi_Host *, char *, int); - enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); - bool (*eh_should_retry_cmd)(struct scsi_cmnd *); - int (*host_reset)(struct Scsi_Host *, int); - const char *proc_name; - struct proc_dir_entry *proc_dir; - int can_queue; - int this_id; - short unsigned int sg_tablesize; - short unsigned int sg_prot_tablesize; - unsigned int max_sectors; - unsigned int max_segment_size; - long unsigned int dma_boundary; - long unsigned int virt_boundary_mask; - short int cmd_per_lun; - unsigned char present; - int tag_alloc_policy; - unsigned int track_queue_depth: 1; - unsigned int supported_mode: 2; - unsigned int emulated: 1; - unsigned int skip_settle_delay: 1; - unsigned int no_write_same: 1; - unsigned int host_tagset: 1; - unsigned int max_host_blocked; - struct device_attribute **shost_attrs; - struct device_attribute **sdev_attrs; - const struct attribute_group **sdev_groups; - u64 vendor_id; - struct scsi_host_cmd_pool *cmd_pool; - int rpm_autosuspend_delay; -}; - -struct scsi_data_buffer { - struct sg_table table; - unsigned int length; -}; - -struct scsi_pointer { - char *ptr; - int this_residual; - struct scatterlist *buffer; - int buffers_residual; - dma_addr_t dma_handle; - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; -}; - -struct scsi_cmnd { - struct scsi_request req; - struct scsi_device *device; - struct list_head eh_entry; - struct delayed_work abort_work; - struct callback_head rcu; - int eh_eflags; - int budget_token; - long unsigned int jiffies_at_alloc; - int retries; - int allowed; - unsigned char prot_op; - unsigned char prot_type; - unsigned char prot_flags; - short unsigned int cmd_len; - enum dma_data_direction sc_data_direction; - unsigned char *cmnd; - struct scsi_data_buffer sdb; - struct scsi_data_buffer *prot_sdb; - unsigned int underflow; - unsigned int transfersize; - struct request *request; - unsigned char *sense_buffer; - void (*scsi_done)(struct scsi_cmnd *); - struct scsi_pointer SCp; - unsigned char *host_scribble; - int result; - int flags; - long unsigned int state; - unsigned char tag; - unsigned int extra_len; -}; - -enum scsi_prot_operations { - SCSI_PROT_NORMAL = 0, - SCSI_PROT_READ_INSERT = 1, - SCSI_PROT_WRITE_STRIP = 2, - SCSI_PROT_READ_STRIP = 3, - SCSI_PROT_WRITE_INSERT = 4, - SCSI_PROT_READ_PASS = 5, - SCSI_PROT_WRITE_PASS = 6, -}; - -struct scsi_driver { - struct device_driver gendrv; - void (*rescan)(struct device *); - blk_status_t (*init_command)(struct scsi_cmnd *); - void (*uninit_command)(struct scsi_cmnd *); - int (*done)(struct scsi_cmnd *); - int (*eh_action)(struct scsi_cmnd *, int); - void (*eh_reset)(struct scsi_cmnd *); -}; - -struct trace_event_raw_scsi_dispatch_cmd_start { - struct trace_entry ent; - unsigned int host_no; - unsigned int channel; - unsigned int id; - unsigned int lun; - unsigned int opcode; - unsigned int cmd_len; - unsigned int data_sglen; - unsigned int prot_sglen; - unsigned char prot_op; - u32 __data_loc_cmnd; - char __data[0]; -}; - -struct trace_event_raw_scsi_dispatch_cmd_error { - struct trace_entry ent; - unsigned int host_no; - unsigned int channel; - unsigned int id; - unsigned int lun; - int rtn; - unsigned int opcode; - unsigned int cmd_len; - unsigned int data_sglen; - unsigned int prot_sglen; - unsigned char prot_op; - u32 __data_loc_cmnd; - char __data[0]; -}; - -struct trace_event_raw_scsi_cmd_done_timeout_template { - struct trace_entry ent; - unsigned int host_no; - unsigned int channel; - unsigned int id; - unsigned int lun; - int result; - unsigned int opcode; - unsigned int cmd_len; - unsigned int data_sglen; - unsigned int prot_sglen; - unsigned char prot_op; - u32 __data_loc_cmnd; - char __data[0]; -}; - -struct trace_event_raw_scsi_eh_wakeup { - struct trace_entry ent; - unsigned int host_no; - char __data[0]; -}; - -struct trace_event_data_offsets_scsi_dispatch_cmd_start { - u32 cmnd; -}; - -struct trace_event_data_offsets_scsi_dispatch_cmd_error { - u32 cmnd; -}; - -struct trace_event_data_offsets_scsi_cmd_done_timeout_template { - u32 cmnd; -}; - -struct trace_event_data_offsets_scsi_eh_wakeup {}; - -typedef void (*btf_trace_scsi_dispatch_cmd_start)(void *, struct scsi_cmnd *); - -typedef void (*btf_trace_scsi_dispatch_cmd_error)(void *, struct scsi_cmnd *, int); - -typedef void (*btf_trace_scsi_dispatch_cmd_done)(void *, struct scsi_cmnd *); - -typedef void (*btf_trace_scsi_dispatch_cmd_timeout)(void *, struct scsi_cmnd *); - -typedef void (*btf_trace_scsi_eh_wakeup)(void *, struct Scsi_Host *); - -struct scsi_transport_template { - struct transport_container host_attrs; - struct transport_container target_attrs; - struct transport_container device_attrs; - int (*user_scan)(struct Scsi_Host *, uint, uint, u64); - int device_size; - int device_private_offset; - int target_size; - int target_private_offset; - int host_size; - unsigned int create_work_queue: 1; - void (*eh_strategy_handler)(struct Scsi_Host *); -}; - -struct scsi_host_busy_iter_data { - bool (*fn)(struct scsi_cmnd *, void *, bool); - void *priv; -}; - -struct scsi_idlun { - __u32 dev_id; - __u32 host_unique_id; -}; - -typedef void (*activate_complete)(void *, int); - -struct scsi_device_handler { - struct list_head list; - struct module *module; - const char *name; - enum scsi_disposition (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); - int (*attach)(struct scsi_device *); - void (*detach)(struct scsi_device *); - int (*activate)(struct scsi_device *, activate_complete, void *); - blk_status_t (*prep_fn)(struct scsi_device *, struct request *); - int (*set_params)(struct scsi_device *, const char *); - void (*rescan)(struct scsi_device *); -}; - -struct scsi_eh_save { - int result; - unsigned int resid_len; - int eh_eflags; - enum dma_data_direction data_direction; - unsigned int underflow; - unsigned char cmd_len; - unsigned char prot_op; - unsigned char *cmnd; - struct scsi_data_buffer sdb; - unsigned char eh_cmnd[16]; - struct scatterlist sense_sgl; -}; - -struct scsi_varlen_cdb_hdr { - __u8 opcode; - __u8 control; - __u8 misc[5]; - __u8 additional_cdb_length; - __be16 service_action; -}; - -struct scsi_mode_data { - __u32 length; - __u16 block_descriptor_length; - __u8 medium_type; - __u8 device_specific; - __u8 header_length; - __u8 longlba: 1; -}; - -struct scsi_event { - enum scsi_device_event evt_type; - struct list_head node; -}; - -enum scsi_host_prot_capabilities { - SHOST_DIF_TYPE1_PROTECTION = 1, - SHOST_DIF_TYPE2_PROTECTION = 2, - SHOST_DIF_TYPE3_PROTECTION = 4, - SHOST_DIX_TYPE0_PROTECTION = 8, - SHOST_DIX_TYPE1_PROTECTION = 16, - SHOST_DIX_TYPE2_PROTECTION = 32, - SHOST_DIX_TYPE3_PROTECTION = 64, -}; - -enum { - ACTION_FAIL = 0, - ACTION_REPREP = 1, - ACTION_RETRY = 2, - ACTION_DELAYED_RETRY = 3, -}; - -struct value_name_pair; - -struct sa_name_list { - int opcode; - const struct value_name_pair *arr; - int arr_sz; -}; - -struct value_name_pair { - int value; - const char *name; -}; - -struct error_info { - short unsigned int code12; - short unsigned int size; -}; - -struct error_info2 { - unsigned char code1; - unsigned char code2_min; - unsigned char code2_max; - const char *str; - const char *fmt; -}; - -struct scsi_lun { - __u8 scsi_lun[8]; -}; - -enum scsi_timeouts { - SCSI_DEFAULT_EH_TIMEOUT = 3000, -}; - -enum scsi_scan_mode { - SCSI_SCAN_INITIAL = 0, - SCSI_SCAN_RESCAN = 1, - SCSI_SCAN_MANUAL = 2, -}; - -struct async_scan_data { - struct list_head list; - struct Scsi_Host *shost; - struct completion prev_finished; -}; - -enum scsi_devinfo_key { - SCSI_DEVINFO_GLOBAL = 0, - SCSI_DEVINFO_SPI = 1, -}; - -struct scsi_dev_info_list { - struct list_head dev_info_list; - char vendor[8]; - char model[16]; - blist_flags_t flags; - unsigned int compatible; -}; - -struct scsi_dev_info_list_table { - struct list_head node; - struct list_head scsi_dev_info_list; - const char *name; - int key; -}; - -struct double_list { - struct list_head *top; - struct list_head *bottom; -}; - -struct scsi_nl_hdr { - __u8 version; - __u8 transport; - __u16 magic; - __u16 msgtype; - __u16 msglen; -}; - -enum { - SCSI_DH_OK = 0, - SCSI_DH_DEV_FAILED = 1, - SCSI_DH_DEV_TEMP_BUSY = 2, - SCSI_DH_DEV_UNSUPP = 3, - SCSI_DH_DEVICE_MAX = 4, - SCSI_DH_NOTCONN = 5, - SCSI_DH_CONN_FAILURE = 6, - SCSI_DH_TRANSPORT_MAX = 7, - SCSI_DH_IO = 8, - SCSI_DH_INVALID_IO = 9, - SCSI_DH_RETRY = 10, - SCSI_DH_IMM_RETRY = 11, - SCSI_DH_TIMED_OUT = 12, - SCSI_DH_RES_TEMP_UNAVAIL = 13, - SCSI_DH_DEV_OFFLINED = 14, - SCSI_DH_NOMEM = 15, - SCSI_DH_NOSYS = 16, - SCSI_DH_DRIVER_MAX = 17, -}; - -struct scsi_dh_blist { - const char *vendor; - const char *model; - const char *driver; -}; - -enum scsi_prot_flags { - SCSI_PROT_TRANSFER_PI = 1, - SCSI_PROT_GUARD_CHECK = 2, - SCSI_PROT_REF_CHECK = 4, - SCSI_PROT_REF_INCREMENT = 8, - SCSI_PROT_IP_CHECKSUM = 16, -}; - -enum { - SD_EXT_CDB_SIZE = 32, - SD_MEMPOOL_SIZE = 2, -}; - -enum { - SD_DEF_XFER_BLOCKS = 65535, - SD_MAX_XFER_BLOCKS = 4294967295, - SD_MAX_WS10_BLOCKS = 65535, - SD_MAX_WS16_BLOCKS = 8388607, -}; - -enum { - SD_LBP_FULL = 0, - SD_LBP_UNMAP = 1, - SD_LBP_WS16 = 2, - SD_LBP_WS10 = 3, - SD_LBP_ZERO = 4, - SD_LBP_DISABLE = 5, -}; - -enum { - SD_ZERO_WRITE = 0, - SD_ZERO_WS = 1, - SD_ZERO_WS16_UNMAP = 2, - SD_ZERO_WS10_UNMAP = 3, -}; - -struct opal_dev___2; - -struct scsi_disk { - struct scsi_driver *driver; - struct scsi_device *device; - struct device dev; - struct gendisk *disk; - struct opal_dev___2 *opal_dev; - u32 nr_zones; - u32 rev_nr_zones; - u32 zone_blocks; - u32 rev_zone_blocks; - u32 zones_optimal_open; - u32 zones_optimal_nonseq; - u32 zones_max_open; - u32 *zones_wp_offset; - spinlock_t zones_wp_offset_lock; - u32 *rev_wp_offset; - struct mutex rev_mutex; - struct work_struct zone_wp_offset_work; - char *zone_wp_update_buf; - atomic_t openers; - sector_t capacity; - int max_retries; - u32 max_xfer_blocks; - u32 opt_xfer_blocks; - u32 max_ws_blocks; - u32 max_unmap_blocks; - u32 unmap_granularity; - u32 unmap_alignment; - u32 index; - unsigned int physical_block_size; - unsigned int max_medium_access_timeouts; - unsigned int medium_access_timed_out; - u8 media_present; - u8 write_prot; - u8 protection_type; - u8 provisioning_mode; - u8 zeroing_mode; - unsigned int ATO: 1; - unsigned int cache_override: 1; - unsigned int WCE: 1; - unsigned int RCD: 1; - unsigned int DPOFUA: 1; - unsigned int first_scan: 1; - unsigned int lbpme: 1; - unsigned int lbprz: 1; - unsigned int lbpu: 1; - unsigned int lbpws: 1; - unsigned int lbpws10: 1; - unsigned int lbpvpd: 1; - unsigned int ws10: 1; - unsigned int ws16: 1; - unsigned int rc_basis: 2; - unsigned int zoned: 2; - unsigned int urswrz: 1; - unsigned int security: 1; - unsigned int ignore_medium_access_errors: 1; -}; - -enum scsi_host_guard_type { - SHOST_DIX_GUARD_CRC = 1, - SHOST_DIX_GUARD_IP = 2, -}; - -enum zbc_zone_type { - ZBC_ZONE_TYPE_CONV = 1, - ZBC_ZONE_TYPE_SEQWRITE_REQ = 2, - ZBC_ZONE_TYPE_SEQWRITE_PREF = 3, -}; - -enum zbc_zone_cond { - ZBC_ZONE_COND_NO_WP = 0, - ZBC_ZONE_COND_EMPTY = 1, - ZBC_ZONE_COND_IMP_OPEN = 2, - ZBC_ZONE_COND_EXP_OPEN = 3, - ZBC_ZONE_COND_CLOSED = 4, - ZBC_ZONE_COND_READONLY = 13, - ZBC_ZONE_COND_FULL = 14, - ZBC_ZONE_COND_OFFLINE = 15, -}; - -struct nvme_id_power_state { - __le16 max_power; - __u8 rsvd2; - __u8 flags; - __le32 entry_lat; - __le32 exit_lat; - __u8 read_tput; - __u8 read_lat; - __u8 write_tput; - __u8 write_lat; - __le16 idle_power; - __u8 idle_scale; - __u8 rsvd19; - __le16 active_power; - __u8 active_work_scale; - __u8 rsvd23[9]; -}; - -enum { - NVME_PS_FLAGS_MAX_POWER_SCALE = 1, - NVME_PS_FLAGS_NON_OP_STATE = 2, -}; - -enum nvme_ctrl_attr { - NVME_CTRL_ATTR_HID_128_BIT = 1, - NVME_CTRL_ATTR_TBKAS = 64, -}; - -struct nvme_id_ctrl { - __le16 vid; - __le16 ssvid; - char sn[20]; - char mn[40]; - char fr[8]; - __u8 rab; - __u8 ieee[3]; - __u8 cmic; - __u8 mdts; - __le16 cntlid; - __le32 ver; - __le32 rtd3r; - __le32 rtd3e; - __le32 oaes; - __le32 ctratt; - __u8 rsvd100[28]; - __le16 crdt1; - __le16 crdt2; - __le16 crdt3; - __u8 rsvd134[122]; - __le16 oacs; - __u8 acl; - __u8 aerl; - __u8 frmw; - __u8 lpa; - __u8 elpe; - __u8 npss; - __u8 avscc; - __u8 apsta; - __le16 wctemp; - __le16 cctemp; - __le16 mtfa; - __le32 hmpre; - __le32 hmmin; - __u8 tnvmcap[16]; - __u8 unvmcap[16]; - __le32 rpmbs; - __le16 edstt; - __u8 dsto; - __u8 fwug; - __le16 kas; - __le16 hctma; - __le16 mntmt; - __le16 mxtmt; - __le32 sanicap; - __le32 hmminds; - __le16 hmmaxd; - __u8 rsvd338[4]; - __u8 anatt; - __u8 anacap; - __le32 anagrpmax; - __le32 nanagrpid; - __u8 rsvd352[160]; - __u8 sqes; - __u8 cqes; - __le16 maxcmd; - __le32 nn; - __le16 oncs; - __le16 fuses; - __u8 fna; - __u8 vwc; - __le16 awun; - __le16 awupf; - __u8 nvscc; - __u8 nwpc; - __le16 acwu; - __u8 rsvd534[2]; - __le32 sgls; - __le32 mnan; - __u8 rsvd544[224]; - char subnqn[256]; - __u8 rsvd1024[768]; - __le32 ioccsz; - __le32 iorcsz; - __le16 icdoff; - __u8 ctrattr; - __u8 msdbd; - __u8 rsvd1804[244]; - struct nvme_id_power_state psd[32]; - __u8 vs[1024]; -}; - -enum { - NVME_CTRL_CMIC_MULTI_CTRL = 2, - NVME_CTRL_CMIC_ANA = 8, - NVME_CTRL_ONCS_COMPARE = 1, - NVME_CTRL_ONCS_WRITE_UNCORRECTABLE = 2, - NVME_CTRL_ONCS_DSM = 4, - NVME_CTRL_ONCS_WRITE_ZEROES = 8, - NVME_CTRL_ONCS_RESERVATIONS = 32, - NVME_CTRL_ONCS_TIMESTAMP = 64, - NVME_CTRL_VWC_PRESENT = 1, - NVME_CTRL_OACS_SEC_SUPP = 1, - NVME_CTRL_OACS_DIRECTIVES = 32, - NVME_CTRL_OACS_DBBUF_SUPP = 256, - NVME_CTRL_LPA_CMD_EFFECTS_LOG = 2, - NVME_CTRL_CTRATT_128_ID = 1, - NVME_CTRL_CTRATT_NON_OP_PSP = 2, - NVME_CTRL_CTRATT_NVM_SETS = 4, - NVME_CTRL_CTRATT_READ_RECV_LVLS = 8, - NVME_CTRL_CTRATT_ENDURANCE_GROUPS = 16, - NVME_CTRL_CTRATT_PREDICTABLE_LAT = 32, - NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY = 128, - NVME_CTRL_CTRATT_UUID_LIST = 512, -}; - -struct nvme_lbaf { - __le16 ms; - __u8 ds; - __u8 rp; -}; - -struct nvme_id_ns { - __le64 nsze; - __le64 ncap; - __le64 nuse; - __u8 nsfeat; - __u8 nlbaf; - __u8 flbas; - __u8 mc; - __u8 dpc; - __u8 dps; - __u8 nmic; - __u8 rescap; - __u8 fpi; - __u8 dlfeat; - __le16 nawun; - __le16 nawupf; - __le16 nacwu; - __le16 nabsn; - __le16 nabo; - __le16 nabspf; - __le16 noiob; - __u8 nvmcap[16]; - __le16 npwg; - __le16 npwa; - __le16 npdg; - __le16 npda; - __le16 nows; - __u8 rsvd74[18]; - __le32 anagrpid; - __u8 rsvd96[3]; - __u8 nsattr; - __le16 nvmsetid; - __le16 endgid; - __u8 nguid[16]; - __u8 eui64[8]; - struct nvme_lbaf lbaf[16]; - __u8 rsvd192[192]; - __u8 vs[3712]; -}; - -struct nvme_id_ctrl_nvm { - __u8 vsl; - __u8 wzsl; - __u8 wusl; - __u8 dmrl; - __le32 dmrsl; - __le64 dmsl; - __u8 rsvd16[4080]; -}; - -enum { - NVME_ID_CNS_NS = 0, - NVME_ID_CNS_CTRL = 1, - NVME_ID_CNS_NS_ACTIVE_LIST = 2, - NVME_ID_CNS_NS_DESC_LIST = 3, - NVME_ID_CNS_CS_NS = 5, - NVME_ID_CNS_CS_CTRL = 6, - NVME_ID_CNS_NS_PRESENT_LIST = 16, - NVME_ID_CNS_NS_PRESENT = 17, - NVME_ID_CNS_CTRL_NS_LIST = 18, - NVME_ID_CNS_CTRL_LIST = 19, - NVME_ID_CNS_SCNDRY_CTRL_LIST = 21, - NVME_ID_CNS_NS_GRANULARITY = 22, - NVME_ID_CNS_UUID_LIST = 23, -}; - -enum { - NVME_CSI_NVM = 0, - NVME_CSI_ZNS = 2, -}; - -enum { - NVME_DIR_IDENTIFY = 0, - NVME_DIR_STREAMS = 1, - NVME_DIR_SND_ID_OP_ENABLE = 1, - NVME_DIR_SND_ST_OP_REL_ID = 1, - NVME_DIR_SND_ST_OP_REL_RSC = 2, - NVME_DIR_RCV_ID_OP_PARAM = 1, - NVME_DIR_RCV_ST_OP_PARAM = 1, - NVME_DIR_RCV_ST_OP_STATUS = 2, - NVME_DIR_RCV_ST_OP_RESOURCE = 3, - NVME_DIR_ENDIR = 1, -}; - -enum { - NVME_NS_FEAT_THIN = 1, - NVME_NS_FEAT_ATOMICS = 2, - NVME_NS_FEAT_IO_OPT = 16, - NVME_NS_ATTR_RO = 1, - NVME_NS_FLBAS_LBA_MASK = 15, - NVME_NS_FLBAS_META_EXT = 16, - NVME_NS_NMIC_SHARED = 1, - NVME_LBAF_RP_BEST = 0, - NVME_LBAF_RP_BETTER = 1, - NVME_LBAF_RP_GOOD = 2, - NVME_LBAF_RP_DEGRADED = 3, - NVME_NS_DPC_PI_LAST = 16, - NVME_NS_DPC_PI_FIRST = 8, - NVME_NS_DPC_PI_TYPE3 = 4, - NVME_NS_DPC_PI_TYPE2 = 2, - NVME_NS_DPC_PI_TYPE1 = 1, - NVME_NS_DPS_PI_FIRST = 8, - NVME_NS_DPS_PI_MASK = 7, - NVME_NS_DPS_PI_TYPE1 = 1, - NVME_NS_DPS_PI_TYPE2 = 2, - NVME_NS_DPS_PI_TYPE3 = 3, -}; - -struct nvme_ns_id_desc { - __u8 nidt; - __u8 nidl; - __le16 reserved; -}; - -enum { - NVME_NIDT_EUI64 = 1, - NVME_NIDT_NGUID = 2, - NVME_NIDT_UUID = 3, - NVME_NIDT_CSI = 4, -}; - -struct nvme_fw_slot_info_log { - __u8 afi; - __u8 rsvd1[7]; - __le64 frs[7]; - __u8 rsvd64[448]; -}; - -enum { - NVME_CMD_EFFECTS_CSUPP = 1, - NVME_CMD_EFFECTS_LBCC = 2, - NVME_CMD_EFFECTS_NCC = 4, - NVME_CMD_EFFECTS_NIC = 8, - NVME_CMD_EFFECTS_CCC = 16, - NVME_CMD_EFFECTS_CSE_MASK = 196608, - NVME_CMD_EFFECTS_UUID_SEL = 524288, -}; - -struct nvme_effects_log { - __le32 acs[256]; - __le32 iocs[256]; - __u8 resv[2048]; -}; - -enum nvme_ana_state { - NVME_ANA_OPTIMIZED = 1, - NVME_ANA_NONOPTIMIZED = 2, - NVME_ANA_INACCESSIBLE = 3, - NVME_ANA_PERSISTENT_LOSS = 4, - NVME_ANA_CHANGE = 15, -}; - -struct nvme_ana_rsp_hdr { - __le64 chgcnt; - __le16 ngrps; - __le16 rsvd10[3]; -}; - -enum { - NVME_AER_ERROR = 0, - NVME_AER_SMART = 1, - NVME_AER_NOTICE = 2, - NVME_AER_CSS = 6, - NVME_AER_VS = 7, -}; - -enum { - NVME_AER_NOTICE_NS_CHANGED = 0, - NVME_AER_NOTICE_FW_ACT_STARTING = 1, - NVME_AER_NOTICE_ANA = 3, - NVME_AER_NOTICE_DISC_CHANGED = 240, -}; - -enum { - NVME_AEN_CFG_NS_ATTR = 256, - NVME_AEN_CFG_FW_ACT = 512, - NVME_AEN_CFG_ANA_CHANGE = 2048, - NVME_AEN_CFG_DISC_CHANGE = 2147483648, -}; - -enum nvme_opcode { - nvme_cmd_flush = 0, - nvme_cmd_write = 1, - nvme_cmd_read = 2, - nvme_cmd_write_uncor = 4, - nvme_cmd_compare = 5, - nvme_cmd_write_zeroes = 8, - nvme_cmd_dsm = 9, - nvme_cmd_verify = 12, - nvme_cmd_resv_register = 13, - nvme_cmd_resv_report = 14, - nvme_cmd_resv_acquire = 17, - nvme_cmd_resv_release = 21, - nvme_cmd_zone_mgmt_send = 121, - nvme_cmd_zone_mgmt_recv = 122, - nvme_cmd_zone_append = 125, -}; - -struct nvme_sgl_desc { - __le64 addr; - __le32 length; - __u8 rsvd[3]; - __u8 type; -}; - -struct nvme_keyed_sgl_desc { - __le64 addr; - __u8 length[3]; - __u8 key[4]; - __u8 type; -}; - -union nvme_data_ptr { - struct { - __le64 prp1; - __le64 prp2; - }; - struct nvme_sgl_desc sgl; - struct nvme_keyed_sgl_desc ksgl; -}; - -enum { - NVME_CMD_FUSE_FIRST = 1, - NVME_CMD_FUSE_SECOND = 2, - NVME_CMD_SGL_METABUF = 64, - NVME_CMD_SGL_METASEG = 128, - NVME_CMD_SGL_ALL = 192, -}; - -struct nvme_common_command { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __le32 cdw2[2]; - __le64 metadata; - union nvme_data_ptr dptr; - __le32 cdw10; - __le32 cdw11; - __le32 cdw12; - __le32 cdw13; - __le32 cdw14; - __le32 cdw15; -}; - -struct nvme_rw_command { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2; - __le64 metadata; - union nvme_data_ptr dptr; - __le64 slba; - __le16 length; - __le16 control; - __le32 dsmgmt; - __le32 reftag; - __le16 apptag; - __le16 appmask; -}; - -enum { - NVME_RW_LR = 32768, - NVME_RW_FUA = 16384, - NVME_RW_APPEND_PIREMAP = 512, - NVME_RW_DSM_FREQ_UNSPEC = 0, - NVME_RW_DSM_FREQ_TYPICAL = 1, - NVME_RW_DSM_FREQ_RARE = 2, - NVME_RW_DSM_FREQ_READS = 3, - NVME_RW_DSM_FREQ_WRITES = 4, - NVME_RW_DSM_FREQ_RW = 5, - NVME_RW_DSM_FREQ_ONCE = 6, - NVME_RW_DSM_FREQ_PREFETCH = 7, - NVME_RW_DSM_FREQ_TEMP = 8, - NVME_RW_DSM_LATENCY_NONE = 0, - NVME_RW_DSM_LATENCY_IDLE = 16, - NVME_RW_DSM_LATENCY_NORM = 32, - NVME_RW_DSM_LATENCY_LOW = 48, - NVME_RW_DSM_SEQ_REQ = 64, - NVME_RW_DSM_COMPRESSED = 128, - NVME_RW_PRINFO_PRCHK_REF = 1024, - NVME_RW_PRINFO_PRCHK_APP = 2048, - NVME_RW_PRINFO_PRCHK_GUARD = 4096, - NVME_RW_PRINFO_PRACT = 8192, - NVME_RW_DTYPE_STREAMS = 16, -}; - -struct nvme_dsm_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __le32 nr; - __le32 attributes; - __u32 rsvd12[4]; -}; - -enum { - NVME_DSMGMT_IDR = 1, - NVME_DSMGMT_IDW = 2, - NVME_DSMGMT_AD = 4, -}; - -struct nvme_dsm_range { - __le32 cattr; - __le32 nlb; - __le64 slba; -}; - -struct nvme_write_zeroes_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2; - __le64 metadata; - union nvme_data_ptr dptr; - __le64 slba; - __le16 length; - __le16 control; - __le32 dsmgmt; - __le32 reftag; - __le16 apptag; - __le16 appmask; -}; - -enum nvme_zone_mgmt_action { - NVME_ZONE_CLOSE = 1, - NVME_ZONE_FINISH = 2, - NVME_ZONE_OPEN = 3, - NVME_ZONE_RESET = 4, - NVME_ZONE_OFFLINE = 5, - NVME_ZONE_SET_DESC_EXT = 16, -}; - -struct nvme_zone_mgmt_send_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __le32 cdw2[2]; - __le64 metadata; - union nvme_data_ptr dptr; - __le64 slba; - __le32 cdw12; - __u8 zsa; - __u8 select_all; - __u8 rsvd13[2]; - __le32 cdw14[2]; -}; - -struct nvme_zone_mgmt_recv_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __le64 rsvd2[2]; - union nvme_data_ptr dptr; - __le64 slba; - __le32 numd; - __u8 zra; - __u8 zrasf; - __u8 pr; - __u8 rsvd13; - __le32 cdw14[2]; -}; - -struct nvme_feat_auto_pst { - __le64 entries[32]; -}; - -struct nvme_feat_host_behavior { - __u8 acre; - __u8 resv1[511]; -}; - -enum { - NVME_ENABLE_ACRE = 1, -}; - -enum nvme_admin_opcode { - nvme_admin_delete_sq = 0, - nvme_admin_create_sq = 1, - nvme_admin_get_log_page = 2, - nvme_admin_delete_cq = 4, - nvme_admin_create_cq = 5, - nvme_admin_identify = 6, - nvme_admin_abort_cmd = 8, - nvme_admin_set_features = 9, - nvme_admin_get_features = 10, - nvme_admin_async_event = 12, - nvme_admin_ns_mgmt = 13, - nvme_admin_activate_fw = 16, - nvme_admin_download_fw = 17, - nvme_admin_dev_self_test = 20, - nvme_admin_ns_attach = 21, - nvme_admin_keep_alive = 24, - nvme_admin_directive_send = 25, - nvme_admin_directive_recv = 26, - nvme_admin_virtual_mgmt = 28, - nvme_admin_nvme_mi_send = 29, - nvme_admin_nvme_mi_recv = 30, - nvme_admin_dbbuf = 124, - nvme_admin_format_nvm = 128, - nvme_admin_security_send = 129, - nvme_admin_security_recv = 130, - nvme_admin_sanitize_nvm = 132, - nvme_admin_get_lba_status = 134, - nvme_admin_vendor_start = 192, -}; - -enum { - NVME_QUEUE_PHYS_CONTIG = 1, - NVME_CQ_IRQ_ENABLED = 2, - NVME_SQ_PRIO_URGENT = 0, - NVME_SQ_PRIO_HIGH = 2, - NVME_SQ_PRIO_MEDIUM = 4, - NVME_SQ_PRIO_LOW = 6, - NVME_FEAT_ARBITRATION = 1, - NVME_FEAT_POWER_MGMT = 2, - NVME_FEAT_LBA_RANGE = 3, - NVME_FEAT_TEMP_THRESH = 4, - NVME_FEAT_ERR_RECOVERY = 5, - NVME_FEAT_VOLATILE_WC = 6, - NVME_FEAT_NUM_QUEUES = 7, - NVME_FEAT_IRQ_COALESCE = 8, - NVME_FEAT_IRQ_CONFIG = 9, - NVME_FEAT_WRITE_ATOMIC = 10, - NVME_FEAT_ASYNC_EVENT = 11, - NVME_FEAT_AUTO_PST = 12, - NVME_FEAT_HOST_MEM_BUF = 13, - NVME_FEAT_TIMESTAMP = 14, - NVME_FEAT_KATO = 15, - NVME_FEAT_HCTM = 16, - NVME_FEAT_NOPSC = 17, - NVME_FEAT_RRL = 18, - NVME_FEAT_PLM_CONFIG = 19, - NVME_FEAT_PLM_WINDOW = 20, - NVME_FEAT_HOST_BEHAVIOR = 22, - NVME_FEAT_SANITIZE = 23, - NVME_FEAT_SW_PROGRESS = 128, - NVME_FEAT_HOST_ID = 129, - NVME_FEAT_RESV_MASK = 130, - NVME_FEAT_RESV_PERSIST = 131, - NVME_FEAT_WRITE_PROTECT = 132, - NVME_FEAT_VENDOR_START = 192, - NVME_FEAT_VENDOR_END = 255, - NVME_LOG_ERROR = 1, - NVME_LOG_SMART = 2, - NVME_LOG_FW_SLOT = 3, - NVME_LOG_CHANGED_NS = 4, - NVME_LOG_CMD_EFFECTS = 5, - NVME_LOG_DEVICE_SELF_TEST = 6, - NVME_LOG_TELEMETRY_HOST = 7, - NVME_LOG_TELEMETRY_CTRL = 8, - NVME_LOG_ENDURANCE_GROUP = 9, - NVME_LOG_ANA = 12, - NVME_LOG_DISC = 112, - NVME_LOG_RESERVATION = 128, - NVME_FWACT_REPL = 0, - NVME_FWACT_REPL_ACTV = 8, - NVME_FWACT_ACTV = 16, -}; - -struct nvme_identify { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __u8 cns; - __u8 rsvd3; - __le16 ctrlid; - __u8 rsvd11[3]; - __u8 csi; - __u32 rsvd12[4]; -}; - -struct nvme_features { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __le32 fid; - __le32 dword11; - __le32 dword12; - __le32 dword13; - __le32 dword14; - __le32 dword15; -}; - -struct nvme_create_cq { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - __le64 prp1; - __u64 rsvd8; - __le16 cqid; - __le16 qsize; - __le16 cq_flags; - __le16 irq_vector; - __u32 rsvd12[4]; -}; - -struct nvme_create_sq { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - __le64 prp1; - __u64 rsvd8; - __le16 sqid; - __le16 qsize; - __le16 sq_flags; - __le16 cqid; - __u32 rsvd12[4]; -}; - -struct nvme_delete_queue { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[9]; - __le16 qid; - __u16 rsvd10; - __u32 rsvd11[5]; -}; - -struct nvme_abort_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[9]; - __le16 sqid; - __u16 cid; - __u32 rsvd11[5]; -}; - -struct nvme_download_firmware { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - union nvme_data_ptr dptr; - __le32 numd; - __le32 offset; - __u32 rsvd12[4]; -}; - -struct nvme_format_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[4]; - __le32 cdw10; - __u32 rsvd11[5]; -}; - -struct nvme_get_log_page_command { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __u8 lid; - __u8 lsp; - __le16 numdl; - __le16 numdu; - __u16 rsvd11; - union { - struct { - __le32 lpol; - __le32 lpou; - }; - __le64 lpo; - }; - __u8 rsvd14[3]; - __u8 csi; - __u32 rsvd15; -}; - -struct nvme_directive_cmd { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2[2]; - union nvme_data_ptr dptr; - __le32 numd; - __u8 doper; - __u8 dtype; - __le16 dspec; - __u8 endir; - __u8 tdtype; - __u16 rsvd15; - __u32 rsvd16[3]; -}; - -enum nvmf_fabrics_opcode { - nvme_fabrics_command = 127, -}; - -enum nvmf_capsule_command { - nvme_fabrics_type_property_set = 0, - nvme_fabrics_type_connect = 1, - nvme_fabrics_type_property_get = 4, -}; - -struct nvmf_common_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[35]; - __u8 ts[24]; -}; - -struct nvmf_connect_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[19]; - union nvme_data_ptr dptr; - __le16 recfmt; - __le16 qid; - __le16 sqsize; - __u8 cattr; - __u8 resv3; - __le32 kato; - __u8 resv4[12]; -}; - -struct nvmf_property_set_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[35]; - __u8 attrib; - __u8 resv3[3]; - __le32 offset; - __le64 value; - __u8 resv4[8]; -}; - -struct nvmf_property_get_command { - __u8 opcode; - __u8 resv1; - __u16 command_id; - __u8 fctype; - __u8 resv2[35]; - __u8 attrib; - __u8 resv3[3]; - __le32 offset; - __u8 resv4[16]; -}; - -struct nvme_dbbuf { - __u8 opcode; - __u8 flags; - __u16 command_id; - __u32 rsvd1[5]; - __le64 prp1; - __le64 prp2; - __u32 rsvd12[6]; -}; - -struct streams_directive_params { - __le16 msl; - __le16 nssa; - __le16 nsso; - __u8 rsvd[10]; - __le32 sws; - __le16 sgs; - __le16 nsa; - __le16 nso; - __u8 rsvd2[6]; -}; - -struct nvme_command { - union { - struct nvme_common_command common; - struct nvme_rw_command rw; - struct nvme_identify identify; - struct nvme_features features; - struct nvme_create_cq create_cq; - struct nvme_create_sq create_sq; - struct nvme_delete_queue delete_queue; - struct nvme_download_firmware dlfw; - struct nvme_format_cmd format; - struct nvme_dsm_cmd dsm; - struct nvme_write_zeroes_cmd write_zeroes; - struct nvme_zone_mgmt_send_cmd zms; - struct nvme_zone_mgmt_recv_cmd zmr; - struct nvme_abort_cmd abort; - struct nvme_get_log_page_command get_log_page; - struct nvmf_common_command fabrics; - struct nvmf_connect_command connect; - struct nvmf_property_set_command prop_set; - struct nvmf_property_get_command prop_get; - struct nvme_dbbuf dbbuf; - struct nvme_directive_cmd directive; - }; -}; - -enum { - NVME_SC_SUCCESS = 0, - NVME_SC_INVALID_OPCODE = 1, - NVME_SC_INVALID_FIELD = 2, - NVME_SC_CMDID_CONFLICT = 3, - NVME_SC_DATA_XFER_ERROR = 4, - NVME_SC_POWER_LOSS = 5, - NVME_SC_INTERNAL = 6, - NVME_SC_ABORT_REQ = 7, - NVME_SC_ABORT_QUEUE = 8, - NVME_SC_FUSED_FAIL = 9, - NVME_SC_FUSED_MISSING = 10, - NVME_SC_INVALID_NS = 11, - NVME_SC_CMD_SEQ_ERROR = 12, - NVME_SC_SGL_INVALID_LAST = 13, - NVME_SC_SGL_INVALID_COUNT = 14, - NVME_SC_SGL_INVALID_DATA = 15, - NVME_SC_SGL_INVALID_METADATA = 16, - NVME_SC_SGL_INVALID_TYPE = 17, - NVME_SC_CMB_INVALID_USE = 18, - NVME_SC_PRP_INVALID_OFFSET = 19, - NVME_SC_ATOMIC_WU_EXCEEDED = 20, - NVME_SC_OP_DENIED = 21, - NVME_SC_SGL_INVALID_OFFSET = 22, - NVME_SC_RESERVED = 23, - NVME_SC_HOST_ID_INCONSIST = 24, - NVME_SC_KA_TIMEOUT_EXPIRED = 25, - NVME_SC_KA_TIMEOUT_INVALID = 26, - NVME_SC_ABORTED_PREEMPT_ABORT = 27, - NVME_SC_SANITIZE_FAILED = 28, - NVME_SC_SANITIZE_IN_PROGRESS = 29, - NVME_SC_SGL_INVALID_GRANULARITY = 30, - NVME_SC_CMD_NOT_SUP_CMB_QUEUE = 31, - NVME_SC_NS_WRITE_PROTECTED = 32, - NVME_SC_CMD_INTERRUPTED = 33, - NVME_SC_TRANSIENT_TR_ERR = 34, - NVME_SC_INVALID_IO_CMD_SET = 44, - NVME_SC_LBA_RANGE = 128, - NVME_SC_CAP_EXCEEDED = 129, - NVME_SC_NS_NOT_READY = 130, - NVME_SC_RESERVATION_CONFLICT = 131, - NVME_SC_FORMAT_IN_PROGRESS = 132, - NVME_SC_CQ_INVALID = 256, - NVME_SC_QID_INVALID = 257, - NVME_SC_QUEUE_SIZE = 258, - NVME_SC_ABORT_LIMIT = 259, - NVME_SC_ABORT_MISSING = 260, - NVME_SC_ASYNC_LIMIT = 261, - NVME_SC_FIRMWARE_SLOT = 262, - NVME_SC_FIRMWARE_IMAGE = 263, - NVME_SC_INVALID_VECTOR = 264, - NVME_SC_INVALID_LOG_PAGE = 265, - NVME_SC_INVALID_FORMAT = 266, - NVME_SC_FW_NEEDS_CONV_RESET = 267, - NVME_SC_INVALID_QUEUE = 268, - NVME_SC_FEATURE_NOT_SAVEABLE = 269, - NVME_SC_FEATURE_NOT_CHANGEABLE = 270, - NVME_SC_FEATURE_NOT_PER_NS = 271, - NVME_SC_FW_NEEDS_SUBSYS_RESET = 272, - NVME_SC_FW_NEEDS_RESET = 273, - NVME_SC_FW_NEEDS_MAX_TIME = 274, - NVME_SC_FW_ACTIVATE_PROHIBITED = 275, - NVME_SC_OVERLAPPING_RANGE = 276, - NVME_SC_NS_INSUFFICIENT_CAP = 277, - NVME_SC_NS_ID_UNAVAILABLE = 278, - NVME_SC_NS_ALREADY_ATTACHED = 280, - NVME_SC_NS_IS_PRIVATE = 281, - NVME_SC_NS_NOT_ATTACHED = 282, - NVME_SC_THIN_PROV_NOT_SUPP = 283, - NVME_SC_CTRL_LIST_INVALID = 284, - NVME_SC_SELT_TEST_IN_PROGRESS = 285, - NVME_SC_BP_WRITE_PROHIBITED = 286, - NVME_SC_CTRL_ID_INVALID = 287, - NVME_SC_SEC_CTRL_STATE_INVALID = 288, - NVME_SC_CTRL_RES_NUM_INVALID = 289, - NVME_SC_RES_ID_INVALID = 290, - NVME_SC_PMR_SAN_PROHIBITED = 291, - NVME_SC_ANA_GROUP_ID_INVALID = 292, - NVME_SC_ANA_ATTACH_FAILED = 293, - NVME_SC_BAD_ATTRIBUTES = 384, - NVME_SC_INVALID_PI = 385, - NVME_SC_READ_ONLY = 386, - NVME_SC_ONCS_NOT_SUPPORTED = 387, - NVME_SC_CONNECT_FORMAT = 384, - NVME_SC_CONNECT_CTRL_BUSY = 385, - NVME_SC_CONNECT_INVALID_PARAM = 386, - NVME_SC_CONNECT_RESTART_DISC = 387, - NVME_SC_CONNECT_INVALID_HOST = 388, - NVME_SC_DISCOVERY_RESTART = 400, - NVME_SC_AUTH_REQUIRED = 401, - NVME_SC_ZONE_BOUNDARY_ERROR = 440, - NVME_SC_ZONE_FULL = 441, - NVME_SC_ZONE_READ_ONLY = 442, - NVME_SC_ZONE_OFFLINE = 443, - NVME_SC_ZONE_INVALID_WRITE = 444, - NVME_SC_ZONE_TOO_MANY_ACTIVE = 445, - NVME_SC_ZONE_TOO_MANY_OPEN = 446, - NVME_SC_ZONE_INVALID_TRANSITION = 447, - NVME_SC_WRITE_FAULT = 640, - NVME_SC_READ_ERROR = 641, - NVME_SC_GUARD_CHECK = 642, - NVME_SC_APPTAG_CHECK = 643, - NVME_SC_REFTAG_CHECK = 644, - NVME_SC_COMPARE_FAILED = 645, - NVME_SC_ACCESS_DENIED = 646, - NVME_SC_UNWRITTEN_BLOCK = 647, - NVME_SC_ANA_PERSISTENT_LOSS = 769, - NVME_SC_ANA_INACCESSIBLE = 770, - NVME_SC_ANA_TRANSITION = 771, - NVME_SC_HOST_PATH_ERROR = 880, - NVME_SC_HOST_ABORTED_CMD = 881, - NVME_SC_CRD = 6144, - NVME_SC_DNR = 16384, -}; - -union nvme_result { - __le16 u16; - __le32 u32; - __le64 u64; -}; - -enum nvme_quirks { - NVME_QUIRK_STRIPE_SIZE = 1, - NVME_QUIRK_IDENTIFY_CNS = 2, - NVME_QUIRK_DEALLOCATE_ZEROES = 4, - NVME_QUIRK_DELAY_BEFORE_CHK_RDY = 8, - NVME_QUIRK_NO_APST = 16, - NVME_QUIRK_NO_DEEPEST_PS = 32, - NVME_QUIRK_LIGHTNVM = 64, - NVME_QUIRK_MEDIUM_PRIO_SQ = 128, - NVME_QUIRK_IGNORE_DEV_SUBNQN = 256, - NVME_QUIRK_DISABLE_WRITE_ZEROES = 512, - NVME_QUIRK_SIMPLE_SUSPEND = 1024, - NVME_QUIRK_SINGLE_VECTOR = 2048, - NVME_QUIRK_128_BYTES_SQES = 4096, - NVME_QUIRK_SHARED_TAGS = 8192, - NVME_QUIRK_NO_TEMP_THRESH_CHANGE = 16384, - NVME_QUIRK_NO_NS_DESC_LIST = 32768, - NVME_QUIRK_DMA_ADDRESS_BITS_48 = 65536, -}; - -struct nvme_ctrl; - -struct nvme_request { - struct nvme_command *cmd; - union nvme_result result; - u8 retries; - u8 flags; - u16 status; - struct nvme_ctrl *ctrl; -}; - -enum nvme_ctrl_state { - NVME_CTRL_NEW = 0, - NVME_CTRL_LIVE = 1, - NVME_CTRL_RESETTING = 2, - NVME_CTRL_CONNECTING = 3, - NVME_CTRL_DELETING = 4, - NVME_CTRL_DELETING_NOIO = 5, - NVME_CTRL_DEAD = 6, -}; - -struct nvme_fault_inject {}; - -struct nvme_ctrl_ops; - -struct nvme_subsystem; - -struct nvmf_ctrl_options; - -struct nvme_ctrl { - bool comp_seen; - enum nvme_ctrl_state state; - bool identified; - spinlock_t lock; - struct mutex scan_lock; - const struct nvme_ctrl_ops *ops; - struct request_queue *admin_q; - struct request_queue *connect_q; - struct request_queue *fabrics_q; - struct device *dev; - int instance; - int numa_node; - struct blk_mq_tag_set *tagset; - struct blk_mq_tag_set *admin_tagset; - struct list_head namespaces; - struct rw_semaphore namespaces_rwsem; - struct device ctrl_device; - struct device *device; - struct device *hwmon_device; - struct cdev cdev; - struct work_struct reset_work; - struct work_struct delete_work; - wait_queue_head_t state_wq; - struct nvme_subsystem *subsys; - struct list_head subsys_entry; - struct opal_dev___2 *opal_dev; - char name[12]; - u16 cntlid; - u32 ctrl_config; - u16 mtfa; - u32 queue_count; - u64 cap; - u32 max_hw_sectors; - u32 max_segments; - u32 max_integrity_segments; - u32 max_discard_sectors; - u32 max_discard_segments; - u32 max_zeroes_sectors; - u32 max_zone_append; - u16 crdt[3]; - u16 oncs; - u16 oacs; - u16 nssa; - u16 nr_streams; - u16 sqsize; - u32 max_namespaces; - atomic_t abort_limit; - u8 vwc; - u32 vs; - u32 sgls; - u16 kas; - u8 npss; - u8 apsta; - u16 wctemp; - u16 cctemp; - u32 oaes; - u32 aen_result; - u32 ctratt; - unsigned int shutdown_timeout; - unsigned int kato; - bool subsystem; - long unsigned int quirks; - struct nvme_id_power_state psd[32]; - struct nvme_effects_log *effects; - struct xarray cels; - struct work_struct scan_work; - struct work_struct async_event_work; - struct delayed_work ka_work; - struct delayed_work failfast_work; - struct nvme_command ka_cmd; - struct work_struct fw_act_work; - long unsigned int events; - u8 anacap; - u8 anatt; - u32 anagrpmax; - u32 nanagrpid; - struct mutex ana_lock; - struct nvme_ana_rsp_hdr *ana_log_buf; - size_t ana_log_size; - struct timer_list anatt_timer; - struct work_struct ana_work; - u64 ps_max_latency_us; - bool apst_enabled; - u32 hmpre; - u32 hmmin; - u32 hmminds; - u16 hmmaxd; - u32 ioccsz; - u32 iorcsz; - u16 icdoff; - u16 maxcmd; - int nr_reconnects; - long unsigned int flags; - struct nvmf_ctrl_options *opts; - struct page *discard_page; - long unsigned int discard_page_busy; - struct nvme_fault_inject fault_inject; -}; - -enum { - NVME_REQ_CANCELLED = 1, - NVME_REQ_USERCMD = 2, -}; - -struct nvme_ctrl_ops { - const char *name; - struct module *module; - unsigned int flags; - int (*reg_read32)(struct nvme_ctrl *, u32, u32 *); - int (*reg_write32)(struct nvme_ctrl *, u32, u32); - int (*reg_read64)(struct nvme_ctrl *, u32, u64 *); - void (*free_ctrl)(struct nvme_ctrl *); - void (*submit_async_event)(struct nvme_ctrl *); - void (*delete_ctrl)(struct nvme_ctrl *); - int (*get_address)(struct nvme_ctrl *, char *, int); -}; - -enum nvme_iopolicy { - NVME_IOPOLICY_NUMA = 0, - NVME_IOPOLICY_RR = 1, -}; - -struct nvme_subsystem { - int instance; - struct device dev; - struct kref ref; - struct list_head entry; - struct mutex lock; - struct list_head ctrls; - struct list_head nsheads; - char subnqn[223]; - char serial[20]; - char model[40]; - char firmware_rev[8]; - u8 cmic; - u16 vendor_id; - u16 awupf; - struct ida ns_ida; - enum nvme_iopolicy iopolicy; -}; - -struct nvmf_host; - -struct nvmf_ctrl_options { - unsigned int mask; - char *transport; - char *subsysnqn; - char *traddr; - char *trsvcid; - char *host_traddr; - char *host_iface; - size_t queue_size; - unsigned int nr_io_queues; - unsigned int reconnect_delay; - bool discovery_nqn; - bool duplicate_connect; - unsigned int kato; - struct nvmf_host *host; - int max_reconnects; - bool disable_sqflow; - bool hdr_digest; - bool data_digest; - unsigned int nr_write_queues; - unsigned int nr_poll_queues; - int tos; - int fast_io_fail_tmo; -}; - -struct nvme_ns_ids { - u8 eui64[8]; - u8 nguid[16]; - uuid_t uuid; - u8 csi; -}; - -struct nvme_ns; - -struct nvme_ns_head { - struct list_head list; - struct srcu_struct srcu; - struct nvme_subsystem *subsys; - unsigned int ns_id; - struct nvme_ns_ids ids; - struct list_head entry; - struct kref ref; - bool shared; - int instance; - struct nvme_effects_log *effects; - struct cdev cdev; - struct device cdev_device; - struct gendisk *disk; - struct bio_list requeue_list; - spinlock_t requeue_lock; - struct work_struct requeue_work; - struct mutex lock; - long unsigned int flags; - struct nvme_ns *current_path[0]; -}; - -struct nvme_ns { - struct list_head list; - struct nvme_ctrl *ctrl; - struct request_queue *queue; - struct gendisk *disk; - enum nvme_ana_state ana_state; - u32 ana_grpid; - struct list_head siblings; - struct nvm_dev *ndev; - struct kref kref; - struct nvme_ns_head *head; - int lba_shift; - u16 ms; - u16 sgs; - u32 sws; - u8 pi_type; - u64 zsze; - long unsigned int features; - long unsigned int flags; - struct cdev cdev; - struct device cdev_device; - struct nvme_fault_inject fault_inject; -}; - -enum nvme_ns_features { - NVME_NS_EXT_LBAS = 1, - NVME_NS_METADATA_SUPPORTED = 2, -}; - -struct nvmf_host { - struct kref ref; - struct list_head list; - char nqn[223]; - uuid_t id; -}; - -struct trace_event_raw_nvme_setup_cmd { - struct trace_entry ent; - char disk[32]; - int ctrl_id; - int qid; - u8 opcode; - u8 flags; - u8 fctype; - u16 cid; - u32 nsid; - bool metadata; - u8 cdw10[24]; - char __data[0]; -}; - -struct trace_event_raw_nvme_complete_rq { - struct trace_entry ent; - char disk[32]; - int ctrl_id; - int qid; - int cid; - u64 result; - u8 retries; - u8 flags; - u16 status; - char __data[0]; -}; - -struct trace_event_raw_nvme_async_event { - struct trace_entry ent; - int ctrl_id; - u32 result; - char __data[0]; -}; - -struct trace_event_raw_nvme_sq { - struct trace_entry ent; - int ctrl_id; - char disk[32]; - int qid; - u16 sq_head; - u16 sq_tail; - char __data[0]; -}; - -struct trace_event_data_offsets_nvme_setup_cmd {}; - -struct trace_event_data_offsets_nvme_complete_rq {}; - -struct trace_event_data_offsets_nvme_async_event {}; - -struct trace_event_data_offsets_nvme_sq {}; - -typedef void (*btf_trace_nvme_setup_cmd)(void *, struct request *, struct nvme_command *); - -typedef void (*btf_trace_nvme_complete_rq)(void *, struct request *); - -typedef void (*btf_trace_nvme_async_event)(void *, struct nvme_ctrl *, u32); - -typedef void (*btf_trace_nvme_sq)(void *, struct request *, __le16, int); - -enum nvme_disposition { - COMPLETE = 0, - RETRY = 1, - FAILOVER = 2, -}; - -struct nvme_core_quirk_entry { - u16 vid; - const char *mn; - const char *fr; - long unsigned int quirks; -}; - -struct nvme_user_io { - __u8 opcode; - __u8 flags; - __u16 control; - __u16 nblocks; - __u16 rsvd; - __u64 metadata; - __u64 addr; - __u64 slba; - __u32 dsmgmt; - __u32 reftag; - __u16 apptag; - __u16 appmask; -}; - -struct nvme_passthru_cmd { - __u8 opcode; - __u8 flags; - __u16 rsvd1; - __u32 nsid; - __u32 cdw2; - __u32 cdw3; - __u64 metadata; - __u64 addr; - __u32 metadata_len; - __u32 data_len; - __u32 cdw10; - __u32 cdw11; - __u32 cdw12; - __u32 cdw13; - __u32 cdw14; - __u32 cdw15; - __u32 timeout_ms; - __u32 result; -}; - -struct nvme_passthru_cmd64 { - __u8 opcode; - __u8 flags; - __u16 rsvd1; - __u32 nsid; - __u32 cdw2; - __u32 cdw3; - __u64 metadata; - __u64 addr; - __u32 metadata_len; - __u32 data_len; - __u32 cdw10; - __u32 cdw11; - __u32 cdw12; - __u32 cdw13; - __u32 cdw14; - __u32 cdw15; - __u32 timeout_ms; - __u32 rsvd2; - __u64 result; -}; - -struct nvme_ana_group_desc { - __le32 grpid; - __le32 nnsids; - __le64 chgcnt; - __u8 state; - __u8 rsvd17[15]; - __le32 nsids[0]; -}; - -struct nvm_user_vio { - __u8 opcode; - __u8 flags; - __u16 control; - __u16 nppas; - __u16 rsvd; - __u64 metadata; - __u64 addr; - __u64 ppa_list; - __u32 metadata_len; - __u32 data_len; - __u64 status; - __u32 result; - __u32 rsvd3[3]; -}; - -struct nvm_passthru_vio { - __u8 opcode; - __u8 flags; - __u8 rsvd[2]; - __u32 nsid; - __u32 cdw2; - __u32 cdw3; - __u64 metadata; - __u64 addr; - __u32 metadata_len; - __u32 data_len; - __u64 ppa_list; - __u16 nppas; - __u16 control; - __u32 cdw13; - __u32 cdw14; - __u32 cdw15; - __u64 status; - __u32 result; - __u32 timeout_ms; -}; - -enum nvme_nvm_admin_opcode { - nvme_nvm_admin_identity = 226, - nvme_nvm_admin_get_bb_tbl = 242, - nvme_nvm_admin_set_bb_tbl = 241, -}; - -enum nvme_nvm_log_page { - NVME_NVM_LOG_REPORT_CHUNK = 202, -}; - -struct nvme_nvm_ph_rw { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd2; - __le64 metadata; - __le64 prp1; - __le64 prp2; - __le64 spba; - __le16 length; - __le16 control; - __le32 dsmgmt; - __le64 resv; -}; - -struct nvme_nvm_erase_blk { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd[2]; - __le64 prp1; - __le64 prp2; - __le64 spba; - __le16 length; - __le16 control; - __le32 dsmgmt; - __le64 resv; -}; - -struct nvme_nvm_identity { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd[2]; - __le64 prp1; - __le64 prp2; - __u32 rsvd11[6]; -}; - -struct nvme_nvm_getbbtbl { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __u64 rsvd[2]; - __le64 prp1; - __le64 prp2; - __le64 spba; - __u32 rsvd4[4]; -}; - -struct nvme_nvm_setbbtbl { - __u8 opcode; - __u8 flags; - __u16 command_id; - __le32 nsid; - __le64 rsvd[2]; - __le64 prp1; - __le64 prp2; - __le64 spba; - __le16 nlb; - __u8 value; - __u8 rsvd3; - __u32 rsvd4[3]; -}; - -struct nvme_nvm_command { - union { - struct nvme_common_command common; - struct nvme_nvm_ph_rw ph_rw; - struct nvme_nvm_erase_blk erase; - struct nvme_nvm_identity identity; - struct nvme_nvm_getbbtbl get_bb; - struct nvme_nvm_setbbtbl set_bb; - }; -}; - -struct nvme_nvm_id12_grp { - __u8 mtype; - __u8 fmtype; - __le16 res16; - __u8 num_ch; - __u8 num_lun; - __u8 num_pln; - __u8 rsvd1; - __le16 num_chk; - __le16 num_pg; - __le16 fpg_sz; - __le16 csecs; - __le16 sos; - __le16 rsvd2; - __le32 trdt; - __le32 trdm; - __le32 tprt; - __le32 tprm; - __le32 tbet; - __le32 tbem; - __le32 mpos; - __le32 mccap; - __le16 cpar; - __u8 reserved[906]; -}; - -struct nvme_nvm_id12_addrf { - __u8 ch_offset; - __u8 ch_len; - __u8 lun_offset; - __u8 lun_len; - __u8 pln_offset; - __u8 pln_len; - __u8 blk_offset; - __u8 blk_len; - __u8 pg_offset; - __u8 pg_len; - __u8 sec_offset; - __u8 sec_len; - __u8 res[4]; -}; - -struct nvme_nvm_id12 { - __u8 ver_id; - __u8 vmnt; - __u8 cgrps; - __u8 res; - __le32 cap; - __le32 dom; - struct nvme_nvm_id12_addrf ppaf; - __u8 resv[228]; - struct nvme_nvm_id12_grp grp; - __u8 resv2[2880]; -}; - -struct nvme_nvm_bb_tbl { - __u8 tblid[4]; - __le16 verid; - __le16 revid; - __le32 rvsd1; - __le32 tblks; - __le32 tfact; - __le32 tgrown; - __le32 tdresv; - __le32 thresv; - __le32 rsvd2[8]; - __u8 blk[0]; -}; - -struct nvme_nvm_id20_addrf { - __u8 grp_len; - __u8 pu_len; - __u8 chk_len; - __u8 lba_len; - __u8 resv[4]; -}; - -struct nvme_nvm_id20 { - __u8 mjr; - __u8 mnr; - __u8 resv[6]; - struct nvme_nvm_id20_addrf lbaf; - __le32 mccap; - __u8 resv2[12]; - __u8 wit; - __u8 resv3[31]; - __le16 num_grp; - __le16 num_pu; - __le32 num_chk; - __le32 clba; - __u8 resv4[52]; - __le32 ws_min; - __le32 ws_opt; - __le32 mw_cunits; - __le32 maxoc; - __le32 maxocpu; - __u8 resv5[44]; - __le32 trdt; - __le32 trdm; - __le32 twrt; - __le32 twrm; - __le32 tcrst; - __le32 tcrsm; - __u8 resv6[40]; - __u8 resv7[2816]; - __u8 vs[1024]; -}; - -struct nvme_nvm_chk_meta { - __u8 state; - __u8 type; - __u8 wi; - __u8 rsvd[5]; - __le64 slba; - __le64 cnlb; - __le64 wp; -}; - -struct nvme_zns_lbafe { - __le64 zsze; - __u8 zdes; - __u8 rsvd9[7]; -}; - -struct nvme_id_ns_zns { - __le16 zoc; - __le16 ozcs; - __le32 mar; - __le32 mor; - __le32 rrl; - __le32 frl; - __u8 rsvd20[2796]; - struct nvme_zns_lbafe lbafe[16]; - __u8 rsvd3072[768]; - __u8 vs[256]; -}; - -struct nvme_id_ctrl_zns { - __u8 zasl; - __u8 rsvd1[4095]; -}; - -struct nvme_zone_descriptor { - __u8 zt; - __u8 zs; - __u8 za; - __u8 rsvd3[5]; - __le64 zcap; - __le64 zslba; - __le64 wp; - __u8 rsvd32[32]; -}; - -enum { - NVME_ZONE_TYPE_SEQWRITE_REQ = 2, -}; - -struct nvme_zone_report { - __le64 nr_zones; - __u8 resv8[56]; - struct nvme_zone_descriptor entries[0]; -}; - -enum { - NVME_ZRA_ZONE_REPORT = 0, - NVME_ZRASF_ZONE_REPORT_ALL = 0, - NVME_ZRASF_ZONE_STATE_EMPTY = 1, - NVME_ZRASF_ZONE_STATE_IMP_OPEN = 2, - NVME_ZRASF_ZONE_STATE_EXP_OPEN = 3, - NVME_ZRASF_ZONE_STATE_CLOSED = 4, - NVME_ZRASF_ZONE_STATE_READONLY = 5, - NVME_ZRASF_ZONE_STATE_FULL = 6, - NVME_ZRASF_ZONE_STATE_OFFLINE = 7, - NVME_REPORT_ZONE_PARTIAL = 1, -}; - -enum hwmon_sensor_types { - hwmon_chip = 0, - hwmon_temp = 1, - hwmon_in = 2, - hwmon_curr = 3, - hwmon_power = 4, - hwmon_energy = 5, - hwmon_humidity = 6, - hwmon_fan = 7, - hwmon_pwm = 8, - hwmon_intrusion = 9, - hwmon_max = 10, -}; - -enum hwmon_chip_attributes { - hwmon_chip_temp_reset_history = 0, - hwmon_chip_in_reset_history = 1, - hwmon_chip_curr_reset_history = 2, - hwmon_chip_power_reset_history = 3, - hwmon_chip_register_tz = 4, - hwmon_chip_update_interval = 5, - hwmon_chip_alarms = 6, - hwmon_chip_samples = 7, - hwmon_chip_curr_samples = 8, - hwmon_chip_in_samples = 9, - hwmon_chip_power_samples = 10, - hwmon_chip_temp_samples = 11, -}; - -enum hwmon_temp_attributes { - hwmon_temp_enable = 0, - hwmon_temp_input = 1, - hwmon_temp_type = 2, - hwmon_temp_lcrit = 3, - hwmon_temp_lcrit_hyst = 4, - hwmon_temp_min = 5, - hwmon_temp_min_hyst = 6, - hwmon_temp_max = 7, - hwmon_temp_max_hyst = 8, - hwmon_temp_crit = 9, - hwmon_temp_crit_hyst = 10, - hwmon_temp_emergency = 11, - hwmon_temp_emergency_hyst = 12, - hwmon_temp_alarm = 13, - hwmon_temp_lcrit_alarm = 14, - hwmon_temp_min_alarm = 15, - hwmon_temp_max_alarm = 16, - hwmon_temp_crit_alarm = 17, - hwmon_temp_emergency_alarm = 18, - hwmon_temp_fault = 19, - hwmon_temp_offset = 20, - hwmon_temp_label = 21, - hwmon_temp_lowest = 22, - hwmon_temp_highest = 23, - hwmon_temp_reset_history = 24, - hwmon_temp_rated_min = 25, - hwmon_temp_rated_max = 26, -}; - -struct hwmon_ops { - umode_t (*is_visible)(const void *, enum hwmon_sensor_types, u32, int); - int (*read)(struct device *, enum hwmon_sensor_types, u32, int, long int *); - int (*read_string)(struct device *, enum hwmon_sensor_types, u32, int, const char **); - int (*write)(struct device *, enum hwmon_sensor_types, u32, int, long int); -}; - -struct hwmon_channel_info { - enum hwmon_sensor_types type; - const u32 *config; -}; - -struct hwmon_chip_info { - const struct hwmon_ops *ops; - const struct hwmon_channel_info **info; -}; - -struct nvme_smart_log { - __u8 critical_warning; - __u8 temperature[2]; - __u8 avail_spare; - __u8 spare_thresh; - __u8 percent_used; - __u8 endu_grp_crit_warn_sumry; - __u8 rsvd7[25]; - __u8 data_units_read[16]; - __u8 data_units_written[16]; - __u8 host_reads[16]; - __u8 host_writes[16]; - __u8 ctrl_busy_time[16]; - __u8 power_cycles[16]; - __u8 power_on_hours[16]; - __u8 unsafe_shutdowns[16]; - __u8 media_errors[16]; - __u8 num_err_log_entries[16]; - __le32 warning_temp_time; - __le32 critical_comp_time; - __le16 temp_sensor[8]; - __le32 thm_temp1_trans_count; - __le32 thm_temp2_trans_count; - __le32 thm_temp1_total_time; - __le32 thm_temp2_total_time; - __u8 rsvd232[280]; -}; - -enum { - NVME_SMART_CRIT_SPARE = 1, - NVME_SMART_CRIT_TEMPERATURE = 2, - NVME_SMART_CRIT_RELIABILITY = 4, - NVME_SMART_CRIT_MEDIA = 8, - NVME_SMART_CRIT_VOLATILE_MEMORY = 16, -}; - -enum { - NVME_TEMP_THRESH_MASK = 65535, - NVME_TEMP_THRESH_SELECT_SHIFT = 16, - NVME_TEMP_THRESH_TYPE_UNDER = 1048576, -}; - -struct nvme_hwmon_data { - struct nvme_ctrl *ctrl; - struct nvme_smart_log log; - struct mutex read_lock; -}; - -enum { - NVME_CMBSZ_SQS = 1, - NVME_CMBSZ_CQS = 2, - NVME_CMBSZ_LISTS = 4, - NVME_CMBSZ_RDS = 8, - NVME_CMBSZ_WDS = 16, - NVME_CMBSZ_SZ_SHIFT = 12, - NVME_CMBSZ_SZ_MASK = 1048575, - NVME_CMBSZ_SZU_SHIFT = 8, - NVME_CMBSZ_SZU_MASK = 15, -}; - -enum { - NVME_SGL_FMT_DATA_DESC = 0, - NVME_SGL_FMT_SEG_DESC = 2, - NVME_SGL_FMT_LAST_SEG_DESC = 3, - NVME_KEY_SGL_FMT_DATA_DESC = 4, - NVME_TRANSPORT_SGL_DATA_DESC = 5, -}; - -enum { - NVME_HOST_MEM_ENABLE = 1, - NVME_HOST_MEM_RETURN = 2, -}; - -struct nvme_host_mem_buf_desc { - __le64 addr; - __le32 size; - __u32 rsvd; -}; - -struct nvme_completion { - union nvme_result result; - __le16 sq_head; - __le16 sq_id; - __u16 command_id; - __le16 status; -}; - -struct nvme_queue; - -struct nvme_dev { - struct nvme_queue *queues; - struct blk_mq_tag_set tagset; - struct blk_mq_tag_set admin_tagset; - u32 *dbs; - struct device *dev; - struct dma_pool___2 *prp_page_pool; - struct dma_pool___2 *prp_small_pool; - unsigned int online_queues; - unsigned int max_qid; - unsigned int io_queues[3]; - unsigned int num_vecs; - u32 q_depth; - int io_sqes; - u32 db_stride; - void *bar; - long unsigned int bar_mapped_size; - struct work_struct remove_work; - struct mutex shutdown_lock; - bool subsystem; - u64 cmb_size; - bool cmb_use_sqes; - u32 cmbsz; - u32 cmbloc; - struct nvme_ctrl ctrl; - u32 last_ps; - mempool_t *iod_mempool; - u32 *dbbuf_dbs; - dma_addr_t dbbuf_dbs_dma_addr; - u32 *dbbuf_eis; - dma_addr_t dbbuf_eis_dma_addr; - u64 host_mem_size; - u32 nr_host_mem_descs; - dma_addr_t host_mem_descs_dma; - struct nvme_host_mem_buf_desc *host_mem_descs; - void **host_mem_desc_bufs; - unsigned int nr_allocated_queues; - unsigned int nr_write_queues; - unsigned int nr_poll_queues; -}; - -struct nvme_queue { - struct nvme_dev *dev; - spinlock_t sq_lock; - void *sq_cmds; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t cq_poll_lock; - struct nvme_completion *cqes; - dma_addr_t sq_dma_addr; - dma_addr_t cq_dma_addr; - u32 *q_db; - u32 q_depth; - u16 cq_vector; - u16 sq_tail; - u16 last_sq_tail; - u16 cq_head; - u16 qid; - u8 cq_phase; - u8 sqes; - long unsigned int flags; - u32 *dbbuf_sq_db; - u32 *dbbuf_cq_db; - u32 *dbbuf_sq_ei; - u32 *dbbuf_cq_ei; - struct completion delete_done; -}; - -struct nvme_iod { - struct nvme_request req; - struct nvme_command cmd; - struct nvme_queue *nvmeq; - bool use_sgl; - int aborted; - int npages; - int nents; - dma_addr_t first_dma; - unsigned int dma_len; - dma_addr_t meta_dma; - struct scatterlist *sg; -}; - -struct pci_saved_state___2; - -enum { - ATA_MAX_DEVICES = 2, - ATA_MAX_PRD = 256, - ATA_SECT_SIZE = 512, - ATA_MAX_SECTORS_128 = 128, - ATA_MAX_SECTORS = 256, - ATA_MAX_SECTORS_1024 = 1024, - ATA_MAX_SECTORS_LBA48 = 65535, - ATA_MAX_SECTORS_TAPE = 65535, - ATA_MAX_TRIM_RNUM = 64, - ATA_ID_WORDS = 256, - ATA_ID_CONFIG = 0, - ATA_ID_CYLS = 1, - ATA_ID_HEADS = 3, - ATA_ID_SECTORS = 6, - ATA_ID_SERNO = 10, - ATA_ID_BUF_SIZE = 21, - ATA_ID_FW_REV = 23, - ATA_ID_PROD = 27, - ATA_ID_MAX_MULTSECT = 47, - ATA_ID_DWORD_IO = 48, - ATA_ID_TRUSTED = 48, - ATA_ID_CAPABILITY = 49, - ATA_ID_OLD_PIO_MODES = 51, - ATA_ID_OLD_DMA_MODES = 52, - ATA_ID_FIELD_VALID = 53, - ATA_ID_CUR_CYLS = 54, - ATA_ID_CUR_HEADS = 55, - ATA_ID_CUR_SECTORS = 56, - ATA_ID_MULTSECT = 59, - ATA_ID_LBA_CAPACITY = 60, - ATA_ID_SWDMA_MODES = 62, - ATA_ID_MWDMA_MODES = 63, - ATA_ID_PIO_MODES = 64, - ATA_ID_EIDE_DMA_MIN = 65, - ATA_ID_EIDE_DMA_TIME = 66, - ATA_ID_EIDE_PIO = 67, - ATA_ID_EIDE_PIO_IORDY = 68, - ATA_ID_ADDITIONAL_SUPP = 69, - ATA_ID_QUEUE_DEPTH = 75, - ATA_ID_SATA_CAPABILITY = 76, - ATA_ID_SATA_CAPABILITY_2 = 77, - ATA_ID_FEATURE_SUPP = 78, - ATA_ID_MAJOR_VER = 80, - ATA_ID_COMMAND_SET_1 = 82, - ATA_ID_COMMAND_SET_2 = 83, - ATA_ID_CFSSE = 84, - ATA_ID_CFS_ENABLE_1 = 85, - ATA_ID_CFS_ENABLE_2 = 86, - ATA_ID_CSF_DEFAULT = 87, - ATA_ID_UDMA_MODES = 88, - ATA_ID_HW_CONFIG = 93, - ATA_ID_SPG = 98, - ATA_ID_LBA_CAPACITY_2 = 100, - ATA_ID_SECTOR_SIZE = 106, - ATA_ID_WWN = 108, - ATA_ID_LOGICAL_SECTOR_SIZE = 117, - ATA_ID_COMMAND_SET_3 = 119, - ATA_ID_COMMAND_SET_4 = 120, - ATA_ID_LAST_LUN = 126, - ATA_ID_DLF = 128, - ATA_ID_CSFO = 129, - ATA_ID_CFA_POWER = 160, - ATA_ID_CFA_KEY_MGMT = 162, - ATA_ID_CFA_MODES = 163, - ATA_ID_DATA_SET_MGMT = 169, - ATA_ID_SCT_CMD_XPORT = 206, - ATA_ID_ROT_SPEED = 217, - ATA_ID_PIO4 = 2, - ATA_ID_SERNO_LEN = 20, - ATA_ID_FW_REV_LEN = 8, - ATA_ID_PROD_LEN = 40, - ATA_ID_WWN_LEN = 8, - ATA_PCI_CTL_OFS = 2, - ATA_PIO0 = 1, - ATA_PIO1 = 3, - ATA_PIO2 = 7, - ATA_PIO3 = 15, - ATA_PIO4 = 31, - ATA_PIO5 = 63, - ATA_PIO6 = 127, - ATA_PIO4_ONLY = 16, - ATA_SWDMA0 = 1, - ATA_SWDMA1 = 3, - ATA_SWDMA2 = 7, - ATA_SWDMA2_ONLY = 4, - ATA_MWDMA0 = 1, - ATA_MWDMA1 = 3, - ATA_MWDMA2 = 7, - ATA_MWDMA3 = 15, - ATA_MWDMA4 = 31, - ATA_MWDMA12_ONLY = 6, - ATA_MWDMA2_ONLY = 4, - ATA_UDMA0 = 1, - ATA_UDMA1 = 3, - ATA_UDMA2 = 7, - ATA_UDMA3 = 15, - ATA_UDMA4 = 31, - ATA_UDMA5 = 63, - ATA_UDMA6 = 127, - ATA_UDMA7 = 255, - ATA_UDMA24_ONLY = 20, - ATA_UDMA_MASK_40C = 7, - ATA_PRD_SZ = 8, - ATA_PRD_TBL_SZ = 2048, - ATA_PRD_EOT = 2147483648, - ATA_DMA_TABLE_OFS = 4, - ATA_DMA_STATUS = 2, - ATA_DMA_CMD = 0, - ATA_DMA_WR = 8, - ATA_DMA_START = 1, - ATA_DMA_INTR = 4, - ATA_DMA_ERR = 2, - ATA_DMA_ACTIVE = 1, - ATA_HOB = 128, - ATA_NIEN = 2, - ATA_LBA = 64, - ATA_DEV1 = 16, - ATA_DEVICE_OBS = 160, - ATA_DEVCTL_OBS = 8, - ATA_BUSY = 128, - ATA_DRDY = 64, - ATA_DF = 32, - ATA_DSC = 16, - ATA_DRQ = 8, - ATA_CORR = 4, - ATA_SENSE = 2, - ATA_ERR = 1, - ATA_SRST = 4, - ATA_ICRC = 128, - ATA_BBK = 128, - ATA_UNC = 64, - ATA_MC = 32, - ATA_IDNF = 16, - ATA_MCR = 8, - ATA_ABORTED = 4, - ATA_TRK0NF = 2, - ATA_AMNF = 1, - ATAPI_LFS = 240, - ATAPI_EOM = 2, - ATAPI_ILI = 1, - ATAPI_IO = 2, - ATAPI_COD = 1, - ATA_REG_DATA = 0, - ATA_REG_ERR = 1, - ATA_REG_NSECT = 2, - ATA_REG_LBAL = 3, - ATA_REG_LBAM = 4, - ATA_REG_LBAH = 5, - ATA_REG_DEVICE = 6, - ATA_REG_STATUS = 7, - ATA_REG_FEATURE = 1, - ATA_REG_CMD = 7, - ATA_REG_BYTEL = 4, - ATA_REG_BYTEH = 5, - ATA_REG_DEVSEL = 6, - ATA_REG_IRQ = 2, - ATA_CMD_DEV_RESET = 8, - ATA_CMD_CHK_POWER = 229, - ATA_CMD_STANDBY = 226, - ATA_CMD_IDLE = 227, - ATA_CMD_EDD = 144, - ATA_CMD_DOWNLOAD_MICRO = 146, - ATA_CMD_DOWNLOAD_MICRO_DMA = 147, - ATA_CMD_NOP = 0, - ATA_CMD_FLUSH = 231, - ATA_CMD_FLUSH_EXT = 234, - ATA_CMD_ID_ATA = 236, - ATA_CMD_ID_ATAPI = 161, - ATA_CMD_SERVICE = 162, - ATA_CMD_READ = 200, - ATA_CMD_READ_EXT = 37, - ATA_CMD_READ_QUEUED = 38, - ATA_CMD_READ_STREAM_EXT = 43, - ATA_CMD_READ_STREAM_DMA_EXT = 42, - ATA_CMD_WRITE = 202, - ATA_CMD_WRITE_EXT = 53, - ATA_CMD_WRITE_QUEUED = 54, - ATA_CMD_WRITE_STREAM_EXT = 59, - ATA_CMD_WRITE_STREAM_DMA_EXT = 58, - ATA_CMD_WRITE_FUA_EXT = 61, - ATA_CMD_WRITE_QUEUED_FUA_EXT = 62, - ATA_CMD_FPDMA_READ = 96, - ATA_CMD_FPDMA_WRITE = 97, - ATA_CMD_NCQ_NON_DATA = 99, - ATA_CMD_FPDMA_SEND = 100, - ATA_CMD_FPDMA_RECV = 101, - ATA_CMD_PIO_READ = 32, - ATA_CMD_PIO_READ_EXT = 36, - ATA_CMD_PIO_WRITE = 48, - ATA_CMD_PIO_WRITE_EXT = 52, - ATA_CMD_READ_MULTI = 196, - ATA_CMD_READ_MULTI_EXT = 41, - ATA_CMD_WRITE_MULTI = 197, - ATA_CMD_WRITE_MULTI_EXT = 57, - ATA_CMD_WRITE_MULTI_FUA_EXT = 206, - ATA_CMD_SET_FEATURES = 239, - ATA_CMD_SET_MULTI = 198, - ATA_CMD_PACKET = 160, - ATA_CMD_VERIFY = 64, - ATA_CMD_VERIFY_EXT = 66, - ATA_CMD_WRITE_UNCORR_EXT = 69, - ATA_CMD_STANDBYNOW1 = 224, - ATA_CMD_IDLEIMMEDIATE = 225, - ATA_CMD_SLEEP = 230, - ATA_CMD_INIT_DEV_PARAMS = 145, - ATA_CMD_READ_NATIVE_MAX = 248, - ATA_CMD_READ_NATIVE_MAX_EXT = 39, - ATA_CMD_SET_MAX = 249, - ATA_CMD_SET_MAX_EXT = 55, - ATA_CMD_READ_LOG_EXT = 47, - ATA_CMD_WRITE_LOG_EXT = 63, - ATA_CMD_READ_LOG_DMA_EXT = 71, - ATA_CMD_WRITE_LOG_DMA_EXT = 87, - ATA_CMD_TRUSTED_NONDATA = 91, - ATA_CMD_TRUSTED_RCV = 92, - ATA_CMD_TRUSTED_RCV_DMA = 93, - ATA_CMD_TRUSTED_SND = 94, - ATA_CMD_TRUSTED_SND_DMA = 95, - ATA_CMD_PMP_READ = 228, - ATA_CMD_PMP_READ_DMA = 233, - ATA_CMD_PMP_WRITE = 232, - ATA_CMD_PMP_WRITE_DMA = 235, - ATA_CMD_CONF_OVERLAY = 177, - ATA_CMD_SEC_SET_PASS = 241, - ATA_CMD_SEC_UNLOCK = 242, - ATA_CMD_SEC_ERASE_PREP = 243, - ATA_CMD_SEC_ERASE_UNIT = 244, - ATA_CMD_SEC_FREEZE_LOCK = 245, - ATA_CMD_SEC_DISABLE_PASS = 246, - ATA_CMD_CONFIG_STREAM = 81, - ATA_CMD_SMART = 176, - ATA_CMD_MEDIA_LOCK = 222, - ATA_CMD_MEDIA_UNLOCK = 223, - ATA_CMD_DSM = 6, - ATA_CMD_CHK_MED_CRD_TYP = 209, - ATA_CMD_CFA_REQ_EXT_ERR = 3, - ATA_CMD_CFA_WRITE_NE = 56, - ATA_CMD_CFA_TRANS_SECT = 135, - ATA_CMD_CFA_ERASE = 192, - ATA_CMD_CFA_WRITE_MULT_NE = 205, - ATA_CMD_REQ_SENSE_DATA = 11, - ATA_CMD_SANITIZE_DEVICE = 180, - ATA_CMD_ZAC_MGMT_IN = 74, - ATA_CMD_ZAC_MGMT_OUT = 159, - ATA_CMD_RESTORE = 16, - ATA_SUBCMD_FPDMA_RECV_RD_LOG_DMA_EXT = 1, - ATA_SUBCMD_FPDMA_RECV_ZAC_MGMT_IN = 2, - ATA_SUBCMD_FPDMA_SEND_DSM = 0, - ATA_SUBCMD_FPDMA_SEND_WR_LOG_DMA_EXT = 2, - ATA_SUBCMD_NCQ_NON_DATA_ABORT_QUEUE = 0, - ATA_SUBCMD_NCQ_NON_DATA_SET_FEATURES = 5, - ATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT = 6, - ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT = 7, - ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES = 0, - ATA_SUBCMD_ZAC_MGMT_OUT_CLOSE_ZONE = 1, - ATA_SUBCMD_ZAC_MGMT_OUT_FINISH_ZONE = 2, - ATA_SUBCMD_ZAC_MGMT_OUT_OPEN_ZONE = 3, - ATA_SUBCMD_ZAC_MGMT_OUT_RESET_WRITE_POINTER = 4, - ATA_LOG_DIRECTORY = 0, - ATA_LOG_SATA_NCQ = 16, - ATA_LOG_NCQ_NON_DATA = 18, - ATA_LOG_NCQ_SEND_RECV = 19, - ATA_LOG_IDENTIFY_DEVICE = 48, - ATA_LOG_SECURITY = 6, - ATA_LOG_SATA_SETTINGS = 8, - ATA_LOG_ZONED_INFORMATION = 9, - ATA_LOG_DEVSLP_OFFSET = 48, - ATA_LOG_DEVSLP_SIZE = 8, - ATA_LOG_DEVSLP_MDAT = 0, - ATA_LOG_DEVSLP_MDAT_MASK = 31, - ATA_LOG_DEVSLP_DETO = 1, - ATA_LOG_DEVSLP_VALID = 7, - ATA_LOG_DEVSLP_VALID_MASK = 128, - ATA_LOG_NCQ_PRIO_OFFSET = 9, - ATA_LOG_NCQ_SEND_RECV_SUBCMDS_OFFSET = 0, - ATA_LOG_NCQ_SEND_RECV_SUBCMDS_DSM = 1, - ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET = 4, - ATA_LOG_NCQ_SEND_RECV_DSM_TRIM = 1, - ATA_LOG_NCQ_SEND_RECV_RD_LOG_OFFSET = 8, - ATA_LOG_NCQ_SEND_RECV_RD_LOG_SUPPORTED = 1, - ATA_LOG_NCQ_SEND_RECV_WR_LOG_OFFSET = 12, - ATA_LOG_NCQ_SEND_RECV_WR_LOG_SUPPORTED = 1, - ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_OFFSET = 16, - ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_OUT_SUPPORTED = 1, - ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_IN_SUPPORTED = 2, - ATA_LOG_NCQ_SEND_RECV_SIZE = 20, - ATA_LOG_NCQ_NON_DATA_SUBCMDS_OFFSET = 0, - ATA_LOG_NCQ_NON_DATA_ABORT_OFFSET = 0, - ATA_LOG_NCQ_NON_DATA_ABORT_NCQ = 1, - ATA_LOG_NCQ_NON_DATA_ABORT_ALL = 2, - ATA_LOG_NCQ_NON_DATA_ABORT_STREAMING = 4, - ATA_LOG_NCQ_NON_DATA_ABORT_NON_STREAMING = 8, - ATA_LOG_NCQ_NON_DATA_ABORT_SELECTED = 16, - ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OFFSET = 28, - ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OUT = 1, - ATA_LOG_NCQ_NON_DATA_SIZE = 64, - ATA_CMD_READ_LONG = 34, - ATA_CMD_READ_LONG_ONCE = 35, - ATA_CMD_WRITE_LONG = 50, - ATA_CMD_WRITE_LONG_ONCE = 51, - SETFEATURES_XFER = 3, - XFER_UDMA_7 = 71, - XFER_UDMA_6 = 70, - XFER_UDMA_5 = 69, - XFER_UDMA_4 = 68, - XFER_UDMA_3 = 67, - XFER_UDMA_2 = 66, - XFER_UDMA_1 = 65, - XFER_UDMA_0 = 64, - XFER_MW_DMA_4 = 36, - XFER_MW_DMA_3 = 35, - XFER_MW_DMA_2 = 34, - XFER_MW_DMA_1 = 33, - XFER_MW_DMA_0 = 32, - XFER_SW_DMA_2 = 18, - XFER_SW_DMA_1 = 17, - XFER_SW_DMA_0 = 16, - XFER_PIO_6 = 14, - XFER_PIO_5 = 13, - XFER_PIO_4 = 12, - XFER_PIO_3 = 11, - XFER_PIO_2 = 10, - XFER_PIO_1 = 9, - XFER_PIO_0 = 8, - XFER_PIO_SLOW = 0, - SETFEATURES_WC_ON = 2, - SETFEATURES_WC_OFF = 130, - SETFEATURES_RA_ON = 170, - SETFEATURES_RA_OFF = 85, - SETFEATURES_AAM_ON = 66, - SETFEATURES_AAM_OFF = 194, - SETFEATURES_SPINUP = 7, - SETFEATURES_SPINUP_TIMEOUT = 30000, - SETFEATURES_SATA_ENABLE = 16, - SETFEATURES_SATA_DISABLE = 144, - SATA_FPDMA_OFFSET = 1, - SATA_FPDMA_AA = 2, - SATA_DIPM = 3, - SATA_FPDMA_IN_ORDER = 4, - SATA_AN = 5, - SATA_SSP = 6, - SATA_DEVSLP = 9, - SETFEATURE_SENSE_DATA = 195, - ATA_SET_MAX_ADDR = 0, - ATA_SET_MAX_PASSWD = 1, - ATA_SET_MAX_LOCK = 2, - ATA_SET_MAX_UNLOCK = 3, - ATA_SET_MAX_FREEZE_LOCK = 4, - ATA_SET_MAX_PASSWD_DMA = 5, - ATA_SET_MAX_UNLOCK_DMA = 6, - ATA_DCO_RESTORE = 192, - ATA_DCO_FREEZE_LOCK = 193, - ATA_DCO_IDENTIFY = 194, - ATA_DCO_SET = 195, - ATA_SMART_ENABLE = 216, - ATA_SMART_READ_VALUES = 208, - ATA_SMART_READ_THRESHOLDS = 209, - ATA_DSM_TRIM = 1, - ATA_SMART_LBAM_PASS = 79, - ATA_SMART_LBAH_PASS = 194, - ATAPI_PKT_DMA = 1, - ATAPI_DMADIR = 4, - ATAPI_CDB_LEN = 16, - SATA_PMP_MAX_PORTS = 15, - SATA_PMP_CTRL_PORT = 15, - SATA_PMP_GSCR_DWORDS = 128, - SATA_PMP_GSCR_PROD_ID = 0, - SATA_PMP_GSCR_REV = 1, - SATA_PMP_GSCR_PORT_INFO = 2, - SATA_PMP_GSCR_ERROR = 32, - SATA_PMP_GSCR_ERROR_EN = 33, - SATA_PMP_GSCR_FEAT = 64, - SATA_PMP_GSCR_FEAT_EN = 96, - SATA_PMP_PSCR_STATUS = 0, - SATA_PMP_PSCR_ERROR = 1, - SATA_PMP_PSCR_CONTROL = 2, - SATA_PMP_FEAT_BIST = 1, - SATA_PMP_FEAT_PMREQ = 2, - SATA_PMP_FEAT_DYNSSC = 4, - SATA_PMP_FEAT_NOTIFY = 8, - ATA_CBL_NONE = 0, - ATA_CBL_PATA40 = 1, - ATA_CBL_PATA80 = 2, - ATA_CBL_PATA40_SHORT = 3, - ATA_CBL_PATA_UNK = 4, - ATA_CBL_PATA_IGN = 5, - ATA_CBL_SATA = 6, - SCR_STATUS = 0, - SCR_ERROR = 1, - SCR_CONTROL = 2, - SCR_ACTIVE = 3, - SCR_NOTIFICATION = 4, - SERR_DATA_RECOVERED = 1, - SERR_COMM_RECOVERED = 2, - SERR_DATA = 256, - SERR_PERSISTENT = 512, - SERR_PROTOCOL = 1024, - SERR_INTERNAL = 2048, - SERR_PHYRDY_CHG = 65536, - SERR_PHY_INT_ERR = 131072, - SERR_COMM_WAKE = 262144, - SERR_10B_8B_ERR = 524288, - SERR_DISPARITY = 1048576, - SERR_CRC = 2097152, - SERR_HANDSHAKE = 4194304, - SERR_LINK_SEQ_ERR = 8388608, - SERR_TRANS_ST_ERROR = 16777216, - SERR_UNRECOG_FIS = 33554432, - SERR_DEV_XCHG = 67108864, -}; - -enum ata_prot_flags { - ATA_PROT_FLAG_PIO = 1, - ATA_PROT_FLAG_DMA = 2, - ATA_PROT_FLAG_NCQ = 4, - ATA_PROT_FLAG_ATAPI = 8, - ATA_PROT_UNKNOWN = 255, - ATA_PROT_NODATA = 0, - ATA_PROT_PIO = 1, - ATA_PROT_DMA = 2, - ATA_PROT_NCQ_NODATA = 4, - ATA_PROT_NCQ = 6, - ATAPI_PROT_NODATA = 8, - ATAPI_PROT_PIO = 9, - ATAPI_PROT_DMA = 10, -}; - -struct ata_bmdma_prd { - __le32 addr; - __le32 flags_len; -}; - -enum { - ATA_MSG_DRV = 1, - ATA_MSG_INFO = 2, - ATA_MSG_PROBE = 4, - ATA_MSG_WARN = 8, - ATA_MSG_MALLOC = 16, - ATA_MSG_CTL = 32, - ATA_MSG_INTR = 64, - ATA_MSG_ERR = 128, -}; - -enum { - LIBATA_MAX_PRD = 128, - LIBATA_DUMB_MAX_PRD = 64, - ATA_DEF_QUEUE = 1, - ATA_MAX_QUEUE = 32, - ATA_TAG_INTERNAL = 32, - ATA_SHORT_PAUSE = 16, - ATAPI_MAX_DRAIN = 16384, - ATA_ALL_DEVICES = 3, - ATA_SHT_EMULATED = 1, - ATA_SHT_THIS_ID = 4294967295, - ATA_TFLAG_LBA48 = 1, - ATA_TFLAG_ISADDR = 2, - ATA_TFLAG_DEVICE = 4, - ATA_TFLAG_WRITE = 8, - ATA_TFLAG_LBA = 16, - ATA_TFLAG_FUA = 32, - ATA_TFLAG_POLLING = 64, - ATA_DFLAG_LBA = 1, - ATA_DFLAG_LBA48 = 2, - ATA_DFLAG_CDB_INTR = 4, - ATA_DFLAG_NCQ = 8, - ATA_DFLAG_FLUSH_EXT = 16, - ATA_DFLAG_ACPI_PENDING = 32, - ATA_DFLAG_ACPI_FAILED = 64, - ATA_DFLAG_AN = 128, - ATA_DFLAG_TRUSTED = 256, - ATA_DFLAG_DMADIR = 1024, - ATA_DFLAG_CFG_MASK = 4095, - ATA_DFLAG_PIO = 4096, - ATA_DFLAG_NCQ_OFF = 8192, - ATA_DFLAG_SLEEPING = 32768, - ATA_DFLAG_DUBIOUS_XFER = 65536, - ATA_DFLAG_NO_UNLOAD = 131072, - ATA_DFLAG_UNLOCK_HPA = 262144, - ATA_DFLAG_NCQ_SEND_RECV = 524288, - ATA_DFLAG_NCQ_PRIO = 1048576, - ATA_DFLAG_NCQ_PRIO_ENABLE = 2097152, - ATA_DFLAG_INIT_MASK = 16777215, - ATA_DFLAG_DETACH = 16777216, - ATA_DFLAG_DETACHED = 33554432, - ATA_DFLAG_DA = 67108864, - ATA_DFLAG_DEVSLP = 134217728, - ATA_DFLAG_ACPI_DISABLED = 268435456, - ATA_DFLAG_D_SENSE = 536870912, - ATA_DFLAG_ZAC = 1073741824, - ATA_DEV_UNKNOWN = 0, - ATA_DEV_ATA = 1, - ATA_DEV_ATA_UNSUP = 2, - ATA_DEV_ATAPI = 3, - ATA_DEV_ATAPI_UNSUP = 4, - ATA_DEV_PMP = 5, - ATA_DEV_PMP_UNSUP = 6, - ATA_DEV_SEMB = 7, - ATA_DEV_SEMB_UNSUP = 8, - ATA_DEV_ZAC = 9, - ATA_DEV_ZAC_UNSUP = 10, - ATA_DEV_NONE = 11, - ATA_LFLAG_NO_HRST = 2, - ATA_LFLAG_NO_SRST = 4, - ATA_LFLAG_ASSUME_ATA = 8, - ATA_LFLAG_ASSUME_SEMB = 16, - ATA_LFLAG_ASSUME_CLASS = 24, - ATA_LFLAG_NO_RETRY = 32, - ATA_LFLAG_DISABLED = 64, - ATA_LFLAG_SW_ACTIVITY = 128, - ATA_LFLAG_NO_LPM = 256, - ATA_LFLAG_RST_ONCE = 512, - ATA_LFLAG_CHANGED = 1024, - ATA_LFLAG_NO_DB_DELAY = 2048, - ATA_FLAG_SLAVE_POSS = 1, - ATA_FLAG_SATA = 2, - ATA_FLAG_NO_LPM = 4, - ATA_FLAG_NO_LOG_PAGE = 32, - ATA_FLAG_NO_ATAPI = 64, - ATA_FLAG_PIO_DMA = 128, - ATA_FLAG_PIO_LBA48 = 256, - ATA_FLAG_PIO_POLLING = 512, - ATA_FLAG_NCQ = 1024, - ATA_FLAG_NO_POWEROFF_SPINDOWN = 2048, - ATA_FLAG_NO_HIBERNATE_SPINDOWN = 4096, - ATA_FLAG_DEBUGMSG = 8192, - ATA_FLAG_FPDMA_AA = 16384, - ATA_FLAG_IGN_SIMPLEX = 32768, - ATA_FLAG_NO_IORDY = 65536, - ATA_FLAG_ACPI_SATA = 131072, - ATA_FLAG_AN = 262144, - ATA_FLAG_PMP = 524288, - ATA_FLAG_FPDMA_AUX = 1048576, - ATA_FLAG_EM = 2097152, - ATA_FLAG_SW_ACTIVITY = 4194304, - ATA_FLAG_NO_DIPM = 8388608, - ATA_FLAG_SAS_HOST = 16777216, - ATA_PFLAG_EH_PENDING = 1, - ATA_PFLAG_EH_IN_PROGRESS = 2, - ATA_PFLAG_FROZEN = 4, - ATA_PFLAG_RECOVERED = 8, - ATA_PFLAG_LOADING = 16, - ATA_PFLAG_SCSI_HOTPLUG = 64, - ATA_PFLAG_INITIALIZING = 128, - ATA_PFLAG_RESETTING = 256, - ATA_PFLAG_UNLOADING = 512, - ATA_PFLAG_UNLOADED = 1024, - ATA_PFLAG_SUSPENDED = 131072, - ATA_PFLAG_PM_PENDING = 262144, - ATA_PFLAG_INIT_GTM_VALID = 524288, - ATA_PFLAG_PIO32 = 1048576, - ATA_PFLAG_PIO32CHANGE = 2097152, - ATA_PFLAG_EXTERNAL = 4194304, - ATA_QCFLAG_ACTIVE = 1, - ATA_QCFLAG_DMAMAP = 2, - ATA_QCFLAG_IO = 8, - ATA_QCFLAG_RESULT_TF = 16, - ATA_QCFLAG_CLEAR_EXCL = 32, - ATA_QCFLAG_QUIET = 64, - ATA_QCFLAG_RETRY = 128, - ATA_QCFLAG_FAILED = 65536, - ATA_QCFLAG_SENSE_VALID = 131072, - ATA_QCFLAG_EH_SCHEDULED = 262144, - ATA_HOST_SIMPLEX = 1, - ATA_HOST_STARTED = 2, - ATA_HOST_PARALLEL_SCAN = 4, - ATA_HOST_IGNORE_ATA = 8, - ATA_TMOUT_BOOT = 30000, - ATA_TMOUT_BOOT_QUICK = 7000, - ATA_TMOUT_INTERNAL_QUICK = 5000, - ATA_TMOUT_MAX_PARK = 30000, - ATA_TMOUT_FF_WAIT_LONG = 2000, - ATA_TMOUT_FF_WAIT = 800, - ATA_WAIT_AFTER_RESET = 150, - ATA_TMOUT_PMP_SRST_WAIT = 5000, - ATA_TMOUT_SPURIOUS_PHY = 10000, - BUS_UNKNOWN = 0, - BUS_DMA = 1, - BUS_IDLE = 2, - BUS_NOINTR = 3, - BUS_NODATA = 4, - BUS_TIMER = 5, - BUS_PIO = 6, - BUS_EDD = 7, - BUS_IDENTIFY = 8, - BUS_PACKET = 9, - PORT_UNKNOWN = 0, - PORT_ENABLED = 1, - PORT_DISABLED = 2, - ATA_NR_PIO_MODES = 7, - ATA_NR_MWDMA_MODES = 5, - ATA_NR_UDMA_MODES = 8, - ATA_SHIFT_PIO = 0, - ATA_SHIFT_MWDMA = 7, - ATA_SHIFT_UDMA = 12, - ATA_SHIFT_PRIO = 6, - ATA_PRIO_HIGH = 2, - ATA_DMA_PAD_SZ = 4, - ATA_ERING_SIZE = 32, - ATA_DEFER_LINK = 1, - ATA_DEFER_PORT = 2, - ATA_EH_DESC_LEN = 80, - ATA_EH_REVALIDATE = 1, - ATA_EH_SOFTRESET = 2, - ATA_EH_HARDRESET = 4, - ATA_EH_RESET = 6, - ATA_EH_ENABLE_LINK = 8, - ATA_EH_PARK = 32, - ATA_EH_PERDEV_MASK = 33, - ATA_EH_ALL_ACTIONS = 15, - ATA_EHI_HOTPLUGGED = 1, - ATA_EHI_NO_AUTOPSY = 4, - ATA_EHI_QUIET = 8, - ATA_EHI_NO_RECOVERY = 16, - ATA_EHI_DID_SOFTRESET = 65536, - ATA_EHI_DID_HARDRESET = 131072, - ATA_EHI_PRINTINFO = 262144, - ATA_EHI_SETMODE = 524288, - ATA_EHI_POST_SETMODE = 1048576, - ATA_EHI_DID_RESET = 196608, - ATA_EHI_TO_SLAVE_MASK = 12, - ATA_EH_MAX_TRIES = 5, - ATA_LINK_RESUME_TRIES = 5, - ATA_PROBE_MAX_TRIES = 3, - ATA_EH_DEV_TRIES = 3, - ATA_EH_PMP_TRIES = 5, - ATA_EH_PMP_LINK_TRIES = 3, - SATA_PMP_RW_TIMEOUT = 3000, - ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 6, - ATA_HORKAGE_DIAGNOSTIC = 1, - ATA_HORKAGE_NODMA = 2, - ATA_HORKAGE_NONCQ = 4, - ATA_HORKAGE_MAX_SEC_128 = 8, - ATA_HORKAGE_BROKEN_HPA = 16, - ATA_HORKAGE_DISABLE = 32, - ATA_HORKAGE_HPA_SIZE = 64, - ATA_HORKAGE_IVB = 256, - ATA_HORKAGE_STUCK_ERR = 512, - ATA_HORKAGE_BRIDGE_OK = 1024, - ATA_HORKAGE_ATAPI_MOD16_DMA = 2048, - ATA_HORKAGE_FIRMWARE_WARN = 4096, - ATA_HORKAGE_1_5_GBPS = 8192, - ATA_HORKAGE_NOSETXFER = 16384, - ATA_HORKAGE_BROKEN_FPDMA_AA = 32768, - ATA_HORKAGE_DUMP_ID = 65536, - ATA_HORKAGE_MAX_SEC_LBA48 = 131072, - ATA_HORKAGE_ATAPI_DMADIR = 262144, - ATA_HORKAGE_NO_NCQ_TRIM = 524288, - ATA_HORKAGE_NOLPM = 1048576, - ATA_HORKAGE_WD_BROKEN_LPM = 2097152, - ATA_HORKAGE_ZERO_AFTER_TRIM = 4194304, - ATA_HORKAGE_NO_DMA_LOG = 8388608, - ATA_HORKAGE_NOTRIM = 16777216, - ATA_HORKAGE_MAX_SEC_1024 = 33554432, - ATA_HORKAGE_MAX_TRIM_128M = 67108864, - ATA_DMA_MASK_ATA = 1, - ATA_DMA_MASK_ATAPI = 2, - ATA_DMA_MASK_CFA = 4, - ATAPI_READ = 0, - ATAPI_WRITE = 1, - ATAPI_READ_CD = 2, - ATAPI_PASS_THRU = 3, - ATAPI_MISC = 4, - ATA_TIMING_SETUP = 1, - ATA_TIMING_ACT8B = 2, - ATA_TIMING_REC8B = 4, - ATA_TIMING_CYC8B = 8, - ATA_TIMING_8BIT = 14, - ATA_TIMING_ACTIVE = 16, - ATA_TIMING_RECOVER = 32, - ATA_TIMING_DMACK_HOLD = 64, - ATA_TIMING_CYCLE = 128, - ATA_TIMING_UDMA = 256, - ATA_TIMING_ALL = 511, - ATA_ACPI_FILTER_SETXFER = 1, - ATA_ACPI_FILTER_LOCK = 2, - ATA_ACPI_FILTER_DIPM = 4, - ATA_ACPI_FILTER_FPDMA_OFFSET = 8, - ATA_ACPI_FILTER_FPDMA_AA = 16, - ATA_ACPI_FILTER_DEFAULT = 7, -}; - -enum ata_xfer_mask { - ATA_MASK_PIO = 127, - ATA_MASK_MWDMA = 3968, - ATA_MASK_UDMA = 1044480, -}; - -enum ata_completion_errors { - AC_ERR_OK = 0, - AC_ERR_DEV = 1, - AC_ERR_HSM = 2, - AC_ERR_TIMEOUT = 4, - AC_ERR_MEDIA = 8, - AC_ERR_ATA_BUS = 16, - AC_ERR_HOST_BUS = 32, - AC_ERR_SYSTEM = 64, - AC_ERR_INVALID = 128, - AC_ERR_OTHER = 256, - AC_ERR_NODEV_HINT = 512, - AC_ERR_NCQ = 1024, -}; - -enum ata_lpm_policy { - ATA_LPM_UNKNOWN = 0, - ATA_LPM_MAX_POWER = 1, - ATA_LPM_MED_POWER = 2, - ATA_LPM_MED_POWER_WITH_DIPM = 3, - ATA_LPM_MIN_POWER_WITH_PARTIAL = 4, - ATA_LPM_MIN_POWER = 5, -}; - -struct ata_queued_cmd; - -typedef void (*ata_qc_cb_t)(struct ata_queued_cmd *); - -struct ata_taskfile { - long unsigned int flags; - u8 protocol; - u8 ctl; - u8 hob_feature; - u8 hob_nsect; - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; - u8 feature; - u8 nsect; - u8 lbal; - u8 lbam; - u8 lbah; - u8 device; - u8 command; - u32 auxiliary; -}; - -struct ata_port; - -struct ata_device; - -struct ata_queued_cmd { - struct ata_port *ap; - struct ata_device *dev; - struct scsi_cmnd *scsicmd; - void (*scsidone)(struct scsi_cmnd *); - struct ata_taskfile tf; - u8 cdb[16]; - long unsigned int flags; - unsigned int tag; - unsigned int hw_tag; - unsigned int n_elem; - unsigned int orig_n_elem; - int dma_dir; - unsigned int sect_size; - unsigned int nbytes; - unsigned int extrabytes; - unsigned int curbytes; - struct scatterlist sgent; - struct scatterlist *sg; - struct scatterlist *cursg; - unsigned int cursg_ofs; - unsigned int err_mask; - struct ata_taskfile result_tf; - ata_qc_cb_t complete_fn; - void *private_data; - void *lldd_task; -}; - -struct ata_link; - -typedef int (*ata_prereset_fn_t)(struct ata_link *, long unsigned int); - -struct ata_eh_info { - struct ata_device *dev; - u32 serror; - unsigned int err_mask; - unsigned int action; - unsigned int dev_action[2]; - unsigned int flags; - unsigned int probe_mask; - char desc[80]; - int desc_len; -}; - -struct ata_eh_context { - struct ata_eh_info i; - int tries[2]; - int cmd_timeout_idx[12]; - unsigned int classes[2]; - unsigned int did_probe_mask; - unsigned int unloaded_mask; - unsigned int saved_ncq_enabled; - u8 saved_xfer_mode[2]; - long unsigned int last_reset; -}; - -struct ata_ering_entry { - unsigned int eflags; - unsigned int err_mask; - u64 timestamp; -}; - -struct ata_ering { - int cursor; - struct ata_ering_entry ring[32]; -}; - -struct ata_device { - struct ata_link *link; - unsigned int devno; - unsigned int horkage; - long unsigned int flags; - struct scsi_device *sdev; - void *private_data; - union acpi_object *gtf_cache; - unsigned int gtf_filter; - void *zpodd; - struct device tdev; - u64 n_sectors; - u64 n_native_sectors; - unsigned int class; - long unsigned int unpark_deadline; - u8 pio_mode; - u8 dma_mode; - u8 xfer_mode; - unsigned int xfer_shift; - unsigned int multi_count; - unsigned int max_sectors; - unsigned int cdb_len; - long unsigned int pio_mask; - long unsigned int mwdma_mask; - long unsigned int udma_mask; - u16 cylinders; - u16 heads; - u16 sectors; - union { - u16 id[256]; - u32 gscr[128]; - }; - u8 devslp_timing[8]; - u8 ncq_send_recv_cmds[20]; - u8 ncq_non_data_cmds[64]; - u32 zac_zoned_cap; - u32 zac_zones_optimal_open; - u32 zac_zones_optimal_nonseq; - u32 zac_zones_max_open; - int spdn_cnt; - struct ata_ering ering; - long: 64; -}; - -struct ata_link { - struct ata_port *ap; - int pmp; - struct device tdev; - unsigned int active_tag; - u32 sactive; - unsigned int flags; - u32 saved_scontrol; - unsigned int hw_sata_spd_limit; - unsigned int sata_spd_limit; - unsigned int sata_spd; - enum ata_lpm_policy lpm_policy; - struct ata_eh_info eh_info; - struct ata_eh_context eh_context; - long: 64; - long: 64; - long: 64; - long: 64; - struct ata_device device[2]; - long unsigned int last_lpm_change; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef int (*ata_reset_fn_t)(struct ata_link *, unsigned int *, long unsigned int); - -typedef void (*ata_postreset_fn_t)(struct ata_link *, unsigned int *); - -enum sw_activity { - OFF = 0, - BLINK_ON = 1, - BLINK_OFF = 2, -}; - -struct ata_ioports { - void *cmd_addr; - void *data_addr; - void *error_addr; - void *feature_addr; - void *nsect_addr; - void *lbal_addr; - void *lbam_addr; - void *lbah_addr; - void *device_addr; - void *status_addr; - void *command_addr; - void *altstatus_addr; - void *ctl_addr; - void *bmdma_addr; - void *scr_addr; -}; - -struct ata_port_operations; - -struct ata_host { - spinlock_t lock; - struct device *dev; - void * const *iomap; - unsigned int n_ports; - unsigned int n_tags; - void *private_data; - struct ata_port_operations *ops; - long unsigned int flags; - struct kref kref; - struct mutex eh_mutex; - struct task_struct *eh_owner; - struct ata_port *simplex_claimed; - struct ata_port *ports[0]; -}; - -struct ata_port_operations { - int (*qc_defer)(struct ata_queued_cmd *); - int (*check_atapi_dma)(struct ata_queued_cmd *); - enum ata_completion_errors (*qc_prep)(struct ata_queued_cmd *); - unsigned int (*qc_issue)(struct ata_queued_cmd *); - bool (*qc_fill_rtf)(struct ata_queued_cmd *); - int (*cable_detect)(struct ata_port *); - long unsigned int (*mode_filter)(struct ata_device *, long unsigned int); - void (*set_piomode)(struct ata_port *, struct ata_device *); - void (*set_dmamode)(struct ata_port *, struct ata_device *); - int (*set_mode)(struct ata_link *, struct ata_device **); - unsigned int (*read_id)(struct ata_device *, struct ata_taskfile *, u16 *); - void (*dev_config)(struct ata_device *); - void (*freeze)(struct ata_port *); - void (*thaw)(struct ata_port *); - ata_prereset_fn_t prereset; - ata_reset_fn_t softreset; - ata_reset_fn_t hardreset; - ata_postreset_fn_t postreset; - ata_prereset_fn_t pmp_prereset; - ata_reset_fn_t pmp_softreset; - ata_reset_fn_t pmp_hardreset; - ata_postreset_fn_t pmp_postreset; - void (*error_handler)(struct ata_port *); - void (*lost_interrupt)(struct ata_port *); - void (*post_internal_cmd)(struct ata_queued_cmd *); - void (*sched_eh)(struct ata_port *); - void (*end_eh)(struct ata_port *); - int (*scr_read)(struct ata_link *, unsigned int, u32 *); - int (*scr_write)(struct ata_link *, unsigned int, u32); - void (*pmp_attach)(struct ata_port *); - void (*pmp_detach)(struct ata_port *); - int (*set_lpm)(struct ata_link *, enum ata_lpm_policy, unsigned int); - int (*port_suspend)(struct ata_port *, pm_message_t); - int (*port_resume)(struct ata_port *); - int (*port_start)(struct ata_port *); - void (*port_stop)(struct ata_port *); - void (*host_stop)(struct ata_host *); - void (*sff_dev_select)(struct ata_port *, unsigned int); - void (*sff_set_devctl)(struct ata_port *, u8); - u8 (*sff_check_status)(struct ata_port *); - u8 (*sff_check_altstatus)(struct ata_port *); - void (*sff_tf_load)(struct ata_port *, const struct ata_taskfile *); - void (*sff_tf_read)(struct ata_port *, struct ata_taskfile *); - void (*sff_exec_command)(struct ata_port *, const struct ata_taskfile *); - unsigned int (*sff_data_xfer)(struct ata_queued_cmd *, unsigned char *, unsigned int, int); - void (*sff_irq_on)(struct ata_port *); - bool (*sff_irq_check)(struct ata_port *); - void (*sff_irq_clear)(struct ata_port *); - void (*sff_drain_fifo)(struct ata_queued_cmd *); - void (*bmdma_setup)(struct ata_queued_cmd *); - void (*bmdma_start)(struct ata_queued_cmd *); - void (*bmdma_stop)(struct ata_queued_cmd *); - u8 (*bmdma_status)(struct ata_port *); - ssize_t (*em_show)(struct ata_port *, char *); - ssize_t (*em_store)(struct ata_port *, const char *, size_t); - ssize_t (*sw_activity_show)(struct ata_device *, char *); - ssize_t (*sw_activity_store)(struct ata_device *, enum sw_activity); - ssize_t (*transmit_led_message)(struct ata_port *, u32, ssize_t); - void (*phy_reset)(struct ata_port *); - void (*eng_timeout)(struct ata_port *); - const struct ata_port_operations *inherits; -}; - -struct ata_port_stats { - long unsigned int unhandled_irq; - long unsigned int idle_irq; - long unsigned int rw_reqbuf; -}; - -struct ata_acpi_drive { - u32 pio; - u32 dma; -}; - -struct ata_acpi_gtm { - struct ata_acpi_drive drive[2]; - u32 flags; -}; - -struct ata_port { - struct Scsi_Host *scsi_host; - struct ata_port_operations *ops; - spinlock_t *lock; - long unsigned int flags; - unsigned int pflags; - unsigned int print_id; - unsigned int local_port_no; - unsigned int port_no; - struct ata_ioports ioaddr; - u8 ctl; - u8 last_ctl; - struct ata_link *sff_pio_task_link; - struct delayed_work sff_pio_task; - struct ata_bmdma_prd *bmdma_prd; - dma_addr_t bmdma_prd_dma; - unsigned int pio_mask; - unsigned int mwdma_mask; - unsigned int udma_mask; - unsigned int cbl; - struct ata_queued_cmd qcmd[33]; - long unsigned int sas_tag_allocated; - u64 qc_active; - int nr_active_links; - unsigned int sas_last_tag; - long: 64; - struct ata_link link; - struct ata_link *slave_link; - int nr_pmp_links; - struct ata_link *pmp_link; - struct ata_link *excl_link; - struct ata_port_stats stats; - struct ata_host *host; - struct device *dev; - struct device tdev; - struct mutex scsi_scan_mutex; - struct delayed_work hotplug_task; - struct work_struct scsi_rescan_task; - unsigned int hsm_task_state; - u32 msg_enable; - struct list_head eh_done_q; - wait_queue_head_t eh_wait_q; - int eh_tries; - struct completion park_req_pending; - pm_message_t pm_mesg; - enum ata_lpm_policy target_lpm_policy; - struct timer_list fastdrain_timer; - long unsigned int fastdrain_cnt; - async_cookie_t cookie; - int em_message_type; - void *private_data; - struct ata_acpi_gtm __acpi_init_gtm; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u8 sector_buf[512]; -}; - -struct ata_port_info { - long unsigned int flags; - long unsigned int link_flags; - long unsigned int pio_mask; - long unsigned int mwdma_mask; - long unsigned int udma_mask; - struct ata_port_operations *port_ops; - void *private_data; -}; - -struct ata_timing { - short unsigned int mode; - short unsigned int setup; - short unsigned int act8b; - short unsigned int rec8b; - short unsigned int cyc8b; - short unsigned int active; - short unsigned int recover; - short unsigned int dmack_hold; - short unsigned int cycle; - short unsigned int udma; -}; - -struct pci_bits { - unsigned int reg; - unsigned int width; - long unsigned int mask; - long unsigned int val; -}; - -enum ata_link_iter_mode { - ATA_LITER_EDGE = 0, - ATA_LITER_HOST_FIRST = 1, - ATA_LITER_PMP_FIRST = 2, -}; - -enum ata_dev_iter_mode { - ATA_DITER_ENABLED = 0, - ATA_DITER_ENABLED_REVERSE = 1, - ATA_DITER_ALL = 2, - ATA_DITER_ALL_REVERSE = 3, -}; - -struct trace_event_raw_ata_qc_issue { - struct trace_entry ent; - unsigned int ata_port; - unsigned int ata_dev; - unsigned int tag; - unsigned char cmd; - unsigned char dev; - unsigned char lbal; - unsigned char lbam; - unsigned char lbah; - unsigned char nsect; - unsigned char feature; - unsigned char hob_lbal; - unsigned char hob_lbam; - unsigned char hob_lbah; - unsigned char hob_nsect; - unsigned char hob_feature; - unsigned char ctl; - unsigned char proto; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_ata_qc_complete_template { - struct trace_entry ent; - unsigned int ata_port; - unsigned int ata_dev; - unsigned int tag; - unsigned char status; - unsigned char dev; - unsigned char lbal; - unsigned char lbam; - unsigned char lbah; - unsigned char nsect; - unsigned char error; - unsigned char hob_lbal; - unsigned char hob_lbam; - unsigned char hob_lbah; - unsigned char hob_nsect; - unsigned char hob_feature; - unsigned char ctl; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_raw_ata_eh_link_autopsy { - struct trace_entry ent; - unsigned int ata_port; - unsigned int ata_dev; - unsigned int eh_action; - unsigned int eh_err_mask; - char __data[0]; -}; - -struct trace_event_raw_ata_eh_link_autopsy_qc { - struct trace_entry ent; - unsigned int ata_port; - unsigned int ata_dev; - unsigned int tag; - unsigned int qc_flags; - unsigned int eh_err_mask; - char __data[0]; -}; - -struct trace_event_data_offsets_ata_qc_issue {}; - -struct trace_event_data_offsets_ata_qc_complete_template {}; - -struct trace_event_data_offsets_ata_eh_link_autopsy {}; - -struct trace_event_data_offsets_ata_eh_link_autopsy_qc {}; - -typedef void (*btf_trace_ata_qc_issue)(void *, struct ata_queued_cmd *); - -typedef void (*btf_trace_ata_qc_complete_internal)(void *, struct ata_queued_cmd *); - -typedef void (*btf_trace_ata_qc_complete_failed)(void *, struct ata_queued_cmd *); - -typedef void (*btf_trace_ata_qc_complete_done)(void *, struct ata_queued_cmd *); - -typedef void (*btf_trace_ata_eh_link_autopsy)(void *, struct ata_device *, unsigned int, unsigned int); - -typedef void (*btf_trace_ata_eh_link_autopsy_qc)(void *, struct ata_queued_cmd *); - -enum { - ATA_READID_POSTRESET = 1, - ATA_DNXFER_PIO = 0, - ATA_DNXFER_DMA = 1, - ATA_DNXFER_40C = 2, - ATA_DNXFER_FORCE_PIO = 3, - ATA_DNXFER_FORCE_PIO0 = 4, - ATA_DNXFER_QUIET = 2147483648, -}; - -struct ata_force_param { - const char *name; - u8 cbl; - u8 spd_limit; - long unsigned int xfer_mask; - unsigned int horkage_on; - unsigned int horkage_off; - u16 lflags; -}; - -struct ata_force_ent { - int port; - int device; - struct ata_force_param param; -}; - -struct ata_xfer_ent { - int shift; - int bits; - u8 base; -}; - -struct ata_blacklist_entry { - const char *model_num; - const char *model_rev; - long unsigned int horkage; -}; - -typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *); - -struct ata_scsi_args { - struct ata_device *dev; - u16 *id; - struct scsi_cmnd *cmd; -}; - -enum ata_lpm_hints { - ATA_LPM_EMPTY = 1, - ATA_LPM_HIPM = 2, - ATA_LPM_WAKE_ONLY = 4, -}; - -enum { - ATA_EH_SPDN_NCQ_OFF = 1, - ATA_EH_SPDN_SPEED_DOWN = 2, - ATA_EH_SPDN_FALLBACK_TO_PIO = 4, - ATA_EH_SPDN_KEEP_ERRORS = 8, - ATA_EFLAG_IS_IO = 1, - ATA_EFLAG_DUBIOUS_XFER = 2, - ATA_EFLAG_OLD_ER = 2147483648, - ATA_ECAT_NONE = 0, - ATA_ECAT_ATA_BUS = 1, - ATA_ECAT_TOUT_HSM = 2, - ATA_ECAT_UNK_DEV = 3, - ATA_ECAT_DUBIOUS_NONE = 4, - ATA_ECAT_DUBIOUS_ATA_BUS = 5, - ATA_ECAT_DUBIOUS_TOUT_HSM = 6, - ATA_ECAT_DUBIOUS_UNK_DEV = 7, - ATA_ECAT_NR = 8, - ATA_EH_CMD_DFL_TIMEOUT = 5000, - ATA_EH_RESET_COOL_DOWN = 5000, - ATA_EH_PRERESET_TIMEOUT = 10000, - ATA_EH_FASTDRAIN_INTERVAL = 3000, - ATA_EH_UA_TRIES = 5, - ATA_EH_PROBE_TRIAL_INTERVAL = 60000, - ATA_EH_PROBE_TRIALS = 2, -}; - -struct ata_eh_cmd_timeout_ent { - const u8 *commands; - const long unsigned int *timeouts; -}; - -struct speed_down_verdict_arg { - u64 since; - int xfer_ok; - int nr_errors[8]; -}; - -struct ata_internal { - struct scsi_transport_template t; - struct device_attribute private_port_attrs[3]; - struct device_attribute private_link_attrs[3]; - struct device_attribute private_dev_attrs[9]; - struct transport_container link_attr_cont; - struct transport_container dev_attr_cont; - struct device_attribute *link_attrs[4]; - struct device_attribute *port_attrs[4]; - struct device_attribute *dev_attrs[10]; -}; - -struct ata_show_ering_arg { - char *buf; - int written; -}; - -enum hsm_task_states { - HSM_ST_IDLE = 0, - HSM_ST_FIRST = 1, - HSM_ST = 2, - HSM_ST_LAST = 3, - HSM_ST_ERR = 4, -}; - -struct ata_acpi_gtf { - u8 tf[7]; -}; - -struct ata_acpi_hotplug_context { - struct acpi_hotplug_context hp; - union { - struct ata_port *ap; - struct ata_device *dev; - } data; -}; - -struct rm_feature_desc { - __be16 feature_code; - __u8 curr: 1; - __u8 persistent: 1; - __u8 feature_version: 4; - __u8 reserved1: 2; - __u8 add_len; - __u8 lock: 1; - __u8 dbml: 1; - __u8 pvnt_jmpr: 1; - __u8 eject: 1; - __u8 load: 1; - __u8 mech_type: 3; - __u8 reserved2; - __u8 reserved3; - __u8 reserved4; -}; - -enum odd_mech_type { - ODD_MECH_TYPE_SLOT = 0, - ODD_MECH_TYPE_DRAWER = 1, - ODD_MECH_TYPE_UNSUPPORTED = 2, -}; - -struct zpodd { - enum odd_mech_type mech_type; - struct ata_device *dev; - bool from_notify; - bool zp_ready; - long unsigned int last_ready; - bool zp_sampled; - bool powered_off; -}; - -enum { - AHCI_MAX_PORTS = 32, - AHCI_MAX_CLKS = 5, - AHCI_MAX_SG = 168, - AHCI_DMA_BOUNDARY = 4294967295, - AHCI_MAX_CMDS = 32, - AHCI_CMD_SZ = 32, - AHCI_CMD_SLOT_SZ = 1024, - AHCI_RX_FIS_SZ = 256, - AHCI_CMD_TBL_CDB = 64, - AHCI_CMD_TBL_HDR_SZ = 128, - AHCI_CMD_TBL_SZ = 2816, - AHCI_CMD_TBL_AR_SZ = 90112, - AHCI_PORT_PRIV_DMA_SZ = 91392, - AHCI_PORT_PRIV_FBS_DMA_SZ = 95232, - AHCI_IRQ_ON_SG = 2147483648, - AHCI_CMD_ATAPI = 32, - AHCI_CMD_WRITE = 64, - AHCI_CMD_PREFETCH = 128, - AHCI_CMD_RESET = 256, - AHCI_CMD_CLR_BUSY = 1024, - RX_FIS_PIO_SETUP = 32, - RX_FIS_D2H_REG = 64, - RX_FIS_SDB = 88, - RX_FIS_UNK = 96, - HOST_CAP = 0, - HOST_CTL = 4, - HOST_IRQ_STAT = 8, - HOST_PORTS_IMPL = 12, - HOST_VERSION = 16, - HOST_EM_LOC = 28, - HOST_EM_CTL = 32, - HOST_CAP2 = 36, - HOST_RESET = 1, - HOST_IRQ_EN = 2, - HOST_MRSM = 4, - HOST_AHCI_EN = 2147483648, - HOST_CAP_SXS = 32, - HOST_CAP_EMS = 64, - HOST_CAP_CCC = 128, - HOST_CAP_PART = 8192, - HOST_CAP_SSC = 16384, - HOST_CAP_PIO_MULTI = 32768, - HOST_CAP_FBS = 65536, - HOST_CAP_PMP = 131072, - HOST_CAP_ONLY = 262144, - HOST_CAP_CLO = 16777216, - HOST_CAP_LED = 33554432, - HOST_CAP_ALPM = 67108864, - HOST_CAP_SSS = 134217728, - HOST_CAP_MPS = 268435456, - HOST_CAP_SNTF = 536870912, - HOST_CAP_NCQ = 1073741824, - HOST_CAP_64 = 2147483648, - HOST_CAP2_BOH = 1, - HOST_CAP2_NVMHCI = 2, - HOST_CAP2_APST = 4, - HOST_CAP2_SDS = 8, - HOST_CAP2_SADM = 16, - HOST_CAP2_DESO = 32, - PORT_LST_ADDR = 0, - PORT_LST_ADDR_HI = 4, - PORT_FIS_ADDR = 8, - PORT_FIS_ADDR_HI = 12, - PORT_IRQ_STAT = 16, - PORT_IRQ_MASK = 20, - PORT_CMD = 24, - PORT_TFDATA = 32, - PORT_SIG = 36, - PORT_CMD_ISSUE = 56, - PORT_SCR_STAT = 40, - PORT_SCR_CTL = 44, - PORT_SCR_ERR = 48, - PORT_SCR_ACT = 52, - PORT_SCR_NTF = 60, - PORT_FBS = 64, - PORT_DEVSLP = 68, - PORT_IRQ_COLD_PRES = 2147483648, - PORT_IRQ_TF_ERR = 1073741824, - PORT_IRQ_HBUS_ERR = 536870912, - PORT_IRQ_HBUS_DATA_ERR = 268435456, - PORT_IRQ_IF_ERR = 134217728, - PORT_IRQ_IF_NONFATAL = 67108864, - PORT_IRQ_OVERFLOW = 16777216, - PORT_IRQ_BAD_PMP = 8388608, - PORT_IRQ_PHYRDY = 4194304, - PORT_IRQ_DEV_ILCK = 128, - PORT_IRQ_CONNECT = 64, - PORT_IRQ_SG_DONE = 32, - PORT_IRQ_UNK_FIS = 16, - PORT_IRQ_SDB_FIS = 8, - PORT_IRQ_DMAS_FIS = 4, - PORT_IRQ_PIOS_FIS = 2, - PORT_IRQ_D2H_REG_FIS = 1, - PORT_IRQ_FREEZE = 683671632, - PORT_IRQ_ERROR = 2025848912, - DEF_PORT_IRQ = 2025848959, - PORT_CMD_ASP = 134217728, - PORT_CMD_ALPE = 67108864, - PORT_CMD_ATAPI = 16777216, - PORT_CMD_FBSCP = 4194304, - PORT_CMD_ESP = 2097152, - PORT_CMD_HPCP = 262144, - PORT_CMD_PMP = 131072, - PORT_CMD_LIST_ON = 32768, - PORT_CMD_FIS_ON = 16384, - PORT_CMD_FIS_RX = 16, - PORT_CMD_CLO = 8, - PORT_CMD_POWER_ON = 4, - PORT_CMD_SPIN_UP = 2, - PORT_CMD_START = 1, - PORT_CMD_ICC_MASK = 4026531840, - PORT_CMD_ICC_ACTIVE = 268435456, - PORT_CMD_ICC_PARTIAL = 536870912, - PORT_CMD_ICC_SLUMBER = 1610612736, - PORT_FBS_DWE_OFFSET = 16, - PORT_FBS_ADO_OFFSET = 12, - PORT_FBS_DEV_OFFSET = 8, - PORT_FBS_DEV_MASK = 3840, - PORT_FBS_SDE = 4, - PORT_FBS_DEC = 2, - PORT_FBS_EN = 1, - PORT_DEVSLP_DM_OFFSET = 25, - PORT_DEVSLP_DM_MASK = 503316480, - PORT_DEVSLP_DITO_OFFSET = 15, - PORT_DEVSLP_MDAT_OFFSET = 10, - PORT_DEVSLP_DETO_OFFSET = 2, - PORT_DEVSLP_DSP = 2, - PORT_DEVSLP_ADSE = 1, - AHCI_HFLAG_NO_NCQ = 1, - AHCI_HFLAG_IGN_IRQ_IF_ERR = 2, - AHCI_HFLAG_IGN_SERR_INTERNAL = 4, - AHCI_HFLAG_32BIT_ONLY = 8, - AHCI_HFLAG_MV_PATA = 16, - AHCI_HFLAG_NO_MSI = 32, - AHCI_HFLAG_NO_PMP = 64, - AHCI_HFLAG_SECT255 = 256, - AHCI_HFLAG_YES_NCQ = 512, - AHCI_HFLAG_NO_SUSPEND = 1024, - AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = 2048, - AHCI_HFLAG_NO_SNTF = 4096, - AHCI_HFLAG_NO_FPDMA_AA = 8192, - AHCI_HFLAG_YES_FBS = 16384, - AHCI_HFLAG_DELAY_ENGINE = 32768, - AHCI_HFLAG_NO_DEVSLP = 131072, - AHCI_HFLAG_NO_FBS = 262144, - AHCI_HFLAG_MULTI_MSI = 1048576, - AHCI_HFLAG_WAKE_BEFORE_STOP = 4194304, - AHCI_HFLAG_YES_ALPM = 8388608, - AHCI_HFLAG_NO_WRITE_TO_RO = 16777216, - AHCI_HFLAG_IS_MOBILE = 33554432, - AHCI_HFLAG_SUSPEND_PHYS = 67108864, - AHCI_HFLAG_IGN_NOTSUPP_POWER_ON = 134217728, - AHCI_HFLAG_NO_SXS = 268435456, - AHCI_FLAG_COMMON = 393346, - ICH_MAP = 144, - PCS_6 = 146, - PCS_7 = 148, - EM_MAX_SLOTS = 8, - EM_MAX_RETRY = 5, - EM_CTL_RST = 512, - EM_CTL_TM = 256, - EM_CTL_MR = 1, - EM_CTL_ALHD = 67108864, - EM_CTL_XMT = 33554432, - EM_CTL_SMB = 16777216, - EM_CTL_SGPIO = 524288, - EM_CTL_SES = 262144, - EM_CTL_SAFTE = 131072, - EM_CTL_LED = 65536, - EM_MSG_TYPE_LED = 1, - EM_MSG_TYPE_SAFTE = 2, - EM_MSG_TYPE_SES2 = 4, - EM_MSG_TYPE_SGPIO = 8, -}; - -struct ahci_cmd_hdr { - __le32 opts; - __le32 status; - __le32 tbl_addr; - __le32 tbl_addr_hi; - __le32 reserved[4]; -}; - -struct ahci_em_priv { - enum sw_activity blink_policy; - struct timer_list timer; - long unsigned int saved_activity; - long unsigned int activity; - long unsigned int led_state; - struct ata_link *link; -}; - -struct ahci_port_priv { - struct ata_link *active_link; - struct ahci_cmd_hdr *cmd_slot; - dma_addr_t cmd_slot_dma; - void *cmd_tbl; - dma_addr_t cmd_tbl_dma; - void *rx_fis; - dma_addr_t rx_fis_dma; - unsigned int ncq_saw_d2h: 1; - unsigned int ncq_saw_dmas: 1; - unsigned int ncq_saw_sdb: 1; - spinlock_t lock; - u32 intr_mask; - bool fbs_supported; - bool fbs_enabled; - int fbs_last_dev; - struct ahci_em_priv em_priv[8]; - char *irq_desc; -}; - -struct ahci_host_priv { - unsigned int flags; - u32 force_port_map; - u32 mask_port_map; - void *mmio; - u32 cap; - u32 cap2; - u32 version; - u32 port_map; - u32 saved_cap; - u32 saved_cap2; - u32 saved_port_map; - u32 em_loc; - u32 em_buf_sz; - u32 em_msg_type; - u32 remapped_nvme; - bool got_runtime_pm; - struct clk *clks[5]; - struct reset_control *rsts; - struct regulator **target_pwrs; - struct regulator *ahci_regulator; - struct regulator *phy_regulator; - struct phy **phys; - unsigned int nports; - void *plat_data; - unsigned int irq; - void (*start_engine)(struct ata_port *); - int (*stop_engine)(struct ata_port *); - irqreturn_t (*irq_handler)(int, void *); - int (*get_irq_vector)(struct ata_host *, int); -}; - -enum { - AHCI_PCI_BAR_STA2X11 = 0, - AHCI_PCI_BAR_CAVIUM = 0, - AHCI_PCI_BAR_LOONGSON = 0, - AHCI_PCI_BAR_ENMOTUS = 2, - AHCI_PCI_BAR_CAVIUM_GEN5 = 4, - AHCI_PCI_BAR_STANDARD = 5, -}; - -enum board_ids { - board_ahci = 0, - board_ahci_ign_iferr = 1, - board_ahci_mobile = 2, - board_ahci_nomsi = 3, - board_ahci_noncq = 4, - board_ahci_nosntf = 5, - board_ahci_yes_fbs = 6, - board_ahci_al = 7, - board_ahci_avn = 8, - board_ahci_mcp65 = 9, - board_ahci_mcp77 = 10, - board_ahci_mcp89 = 11, - board_ahci_mv = 12, - board_ahci_sb600 = 13, - board_ahci_sb700 = 14, - board_ahci_vt8251 = 15, - board_ahci_pcs7 = 16, - board_ahci_mcp_linux = 9, - board_ahci_mcp67 = 9, - board_ahci_mcp73 = 9, - board_ahci_mcp79 = 10, -}; - -struct ahci_sg { - __le32 addr; - __le32 addr_hi; - __le32 reserved; - __le32 flags_size; -}; - -typedef void (*spi_res_release_t)(struct spi_controller *, struct spi_message *, void *); - -struct spi_res { - struct list_head entry; - spi_res_release_t release; - long long unsigned int data[0]; -}; - -struct spi_replaced_transfers; - -typedef void (*spi_replaced_release_t)(struct spi_controller *, struct spi_message *, struct spi_replaced_transfers *); - -struct spi_replaced_transfers { - spi_replaced_release_t release; - void *extradata; - struct list_head replaced_transfers; - struct list_head *replaced_after; - size_t inserted; - struct spi_transfer inserted_transfers[0]; -}; - -struct spi_board_info { - char modalias[32]; - const void *platform_data; - const struct software_node *swnode; - void *controller_data; - int irq; - u32 max_speed_hz; - u16 bus_num; - u16 chip_select; - u32 mode; -}; - -enum spi_mem_data_dir { - SPI_MEM_NO_DATA = 0, - SPI_MEM_DATA_IN = 1, - SPI_MEM_DATA_OUT = 2, -}; - -struct spi_mem_op { - struct { - u8 nbytes; - u8 buswidth; - u8 dtr: 1; - u16 opcode; - } cmd; - struct { - u8 nbytes; - u8 buswidth; - u8 dtr: 1; - u64 val; - } addr; - struct { - u8 nbytes; - u8 buswidth; - u8 dtr: 1; - } dummy; - struct { - u8 buswidth; - u8 dtr: 1; - enum spi_mem_data_dir dir; - unsigned int nbytes; - union { - void *in; - const void *out; - } buf; - } data; -}; - -struct spi_mem_dirmap_info { - struct spi_mem_op op_tmpl; - u64 offset; - u64 length; -}; - -struct spi_mem_dirmap_desc { - struct spi_mem *mem; - struct spi_mem_dirmap_info info; - unsigned int nodirmap; - void *priv; -}; - -struct spi_mem { - struct spi_device *spi; - void *drvpriv; - const char *name; -}; - -struct trace_event_raw_spi_controller { - struct trace_entry ent; - int bus_num; - char __data[0]; -}; - -struct trace_event_raw_spi_setup { - struct trace_entry ent; - int bus_num; - int chip_select; - long unsigned int mode; - unsigned int bits_per_word; - unsigned int max_speed_hz; - int status; - char __data[0]; -}; - -struct trace_event_raw_spi_set_cs { - struct trace_entry ent; - int bus_num; - int chip_select; - long unsigned int mode; - bool enable; - char __data[0]; -}; - -struct trace_event_raw_spi_message { - struct trace_entry ent; - int bus_num; - int chip_select; - struct spi_message *msg; - char __data[0]; -}; - -struct trace_event_raw_spi_message_done { - struct trace_entry ent; - int bus_num; - int chip_select; - struct spi_message *msg; - unsigned int frame; - unsigned int actual; - char __data[0]; -}; - -struct trace_event_raw_spi_transfer { - struct trace_entry ent; - int bus_num; - int chip_select; - struct spi_transfer *xfer; - int len; - u32 __data_loc_rx_buf; - u32 __data_loc_tx_buf; - char __data[0]; -}; - -struct trace_event_data_offsets_spi_controller {}; - -struct trace_event_data_offsets_spi_setup {}; - -struct trace_event_data_offsets_spi_set_cs {}; - -struct trace_event_data_offsets_spi_message {}; - -struct trace_event_data_offsets_spi_message_done {}; - -struct trace_event_data_offsets_spi_transfer { - u32 rx_buf; - u32 tx_buf; -}; - -typedef void (*btf_trace_spi_controller_idle)(void *, struct spi_controller *); - -typedef void (*btf_trace_spi_controller_busy)(void *, struct spi_controller *); - -typedef void (*btf_trace_spi_setup)(void *, struct spi_device *, int); - -typedef void (*btf_trace_spi_set_cs)(void *, struct spi_device *, bool); - -typedef void (*btf_trace_spi_message_submit)(void *, struct spi_message *); - -typedef void (*btf_trace_spi_message_start)(void *, struct spi_message *); - -typedef void (*btf_trace_spi_message_done)(void *, struct spi_message *); - -typedef void (*btf_trace_spi_transfer_start)(void *, struct spi_message *, struct spi_transfer *); - -typedef void (*btf_trace_spi_transfer_stop)(void *, struct spi_message *, struct spi_transfer *); - -struct boardinfo { - struct list_head list; - struct spi_board_info board_info; -}; - -struct acpi_spi_lookup { - struct spi_controller *ctlr; - u32 max_speed_hz; - u32 mode; - int irq; - u8 bits_per_word; - u8 chip_select; -}; - -struct spi_mem_driver { - struct spi_driver spidrv; - int (*probe)(struct spi_mem *); - int (*remove)(struct spi_mem *); - void (*shutdown)(struct spi_mem *); -}; - -struct devprobe2 { - struct net_device * (*probe)(int); - int status; -}; - -enum { - NETIF_F_SG_BIT = 0, - NETIF_F_IP_CSUM_BIT = 1, - __UNUSED_NETIF_F_1 = 2, - NETIF_F_HW_CSUM_BIT = 3, - NETIF_F_IPV6_CSUM_BIT = 4, - NETIF_F_HIGHDMA_BIT = 5, - NETIF_F_FRAGLIST_BIT = 6, - NETIF_F_HW_VLAN_CTAG_TX_BIT = 7, - NETIF_F_HW_VLAN_CTAG_RX_BIT = 8, - NETIF_F_HW_VLAN_CTAG_FILTER_BIT = 9, - NETIF_F_VLAN_CHALLENGED_BIT = 10, - NETIF_F_GSO_BIT = 11, - NETIF_F_LLTX_BIT = 12, - NETIF_F_NETNS_LOCAL_BIT = 13, - NETIF_F_GRO_BIT = 14, - NETIF_F_LRO_BIT = 15, - NETIF_F_GSO_SHIFT = 16, - NETIF_F_TSO_BIT = 16, - NETIF_F_GSO_ROBUST_BIT = 17, - NETIF_F_TSO_ECN_BIT = 18, - NETIF_F_TSO_MANGLEID_BIT = 19, - NETIF_F_TSO6_BIT = 20, - NETIF_F_FSO_BIT = 21, - NETIF_F_GSO_GRE_BIT = 22, - NETIF_F_GSO_GRE_CSUM_BIT = 23, - NETIF_F_GSO_IPXIP4_BIT = 24, - NETIF_F_GSO_IPXIP6_BIT = 25, - NETIF_F_GSO_UDP_TUNNEL_BIT = 26, - NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT = 27, - NETIF_F_GSO_PARTIAL_BIT = 28, - NETIF_F_GSO_TUNNEL_REMCSUM_BIT = 29, - NETIF_F_GSO_SCTP_BIT = 30, - NETIF_F_GSO_ESP_BIT = 31, - NETIF_F_GSO_UDP_BIT = 32, - NETIF_F_GSO_UDP_L4_BIT = 33, - NETIF_F_GSO_FRAGLIST_BIT = 34, - NETIF_F_GSO_LAST = 34, - NETIF_F_FCOE_CRC_BIT = 35, - NETIF_F_SCTP_CRC_BIT = 36, - NETIF_F_FCOE_MTU_BIT = 37, - NETIF_F_NTUPLE_BIT = 38, - NETIF_F_RXHASH_BIT = 39, - NETIF_F_RXCSUM_BIT = 40, - NETIF_F_NOCACHE_COPY_BIT = 41, - NETIF_F_LOOPBACK_BIT = 42, - NETIF_F_RXFCS_BIT = 43, - NETIF_F_RXALL_BIT = 44, - NETIF_F_HW_VLAN_STAG_TX_BIT = 45, - NETIF_F_HW_VLAN_STAG_RX_BIT = 46, - NETIF_F_HW_VLAN_STAG_FILTER_BIT = 47, - NETIF_F_HW_L2FW_DOFFLOAD_BIT = 48, - NETIF_F_HW_TC_BIT = 49, - NETIF_F_HW_ESP_BIT = 50, - NETIF_F_HW_ESP_TX_CSUM_BIT = 51, - NETIF_F_RX_UDP_TUNNEL_PORT_BIT = 52, - NETIF_F_HW_TLS_TX_BIT = 53, - NETIF_F_HW_TLS_RX_BIT = 54, - NETIF_F_GRO_HW_BIT = 55, - NETIF_F_HW_TLS_RECORD_BIT = 56, - NETIF_F_GRO_FRAGLIST_BIT = 57, - NETIF_F_HW_MACSEC_BIT = 58, - NETIF_F_GRO_UDP_FWD_BIT = 59, - NETIF_F_HW_HSR_TAG_INS_BIT = 60, - NETIF_F_HW_HSR_TAG_RM_BIT = 61, - NETIF_F_HW_HSR_FWD_BIT = 62, - NETIF_F_HW_HSR_DUP_BIT = 63, - NETDEV_FEATURE_COUNT = 64, -}; - -typedef struct bio_vec skb_frag_t; - -struct skb_shared_hwtstamps { - ktime_t hwtstamp; -}; - -enum { - SKBTX_HW_TSTAMP = 1, - SKBTX_SW_TSTAMP = 2, - SKBTX_IN_PROGRESS = 4, - SKBTX_WIFI_STATUS = 16, - SKBTX_SCHED_TSTAMP = 64, -}; - -struct skb_shared_info { - __u8 flags; - __u8 meta_len; - __u8 nr_frags; - __u8 tx_flags; - short unsigned int gso_size; - short unsigned int gso_segs; - struct sk_buff *frag_list; - struct skb_shared_hwtstamps hwtstamps; - unsigned int gso_type; - u32 tskey; - atomic_t dataref; - void *destructor_arg; - skb_frag_t frags[17]; -}; - -enum netdev_priv_flags { - IFF_802_1Q_VLAN = 1, - IFF_EBRIDGE = 2, - IFF_BONDING = 4, - IFF_ISATAP = 8, - IFF_WAN_HDLC = 16, - IFF_XMIT_DST_RELEASE = 32, - IFF_DONT_BRIDGE = 64, - IFF_DISABLE_NETPOLL = 128, - IFF_MACVLAN_PORT = 256, - IFF_BRIDGE_PORT = 512, - IFF_OVS_DATAPATH = 1024, - IFF_TX_SKB_SHARING = 2048, - IFF_UNICAST_FLT = 4096, - IFF_TEAM_PORT = 8192, - IFF_SUPP_NOFCS = 16384, - IFF_LIVE_ADDR_CHANGE = 32768, - IFF_MACVLAN = 65536, - IFF_XMIT_DST_RELEASE_PERM = 131072, - IFF_L3MDEV_MASTER = 262144, - IFF_NO_QUEUE = 524288, - IFF_OPENVSWITCH = 1048576, - IFF_L3MDEV_SLAVE = 2097152, - IFF_TEAM = 4194304, - IFF_RXFH_CONFIGURED = 8388608, - IFF_PHONY_HEADROOM = 16777216, - IFF_MACSEC = 33554432, - IFF_NO_RX_HANDLER = 67108864, - IFF_FAILOVER = 134217728, - IFF_FAILOVER_SLAVE = 268435456, - IFF_L3MDEV_RX_HANDLER = 536870912, - IFF_LIVE_RENAME_OK = 1073741824, - IFF_TX_SKB_NO_LINEAR = 2147483648, -}; - -struct mdio_board_info { - const char *bus_id; - char modalias[32]; - int mdio_addr; - const void *platform_data; -}; - -struct mdio_board_entry { - struct list_head list; - struct mdio_board_info board_info; -}; - -struct mii_timestamping_ctrl { - struct mii_timestamper * (*probe_channel)(struct device *, unsigned int); - void (*release_channel)(struct device *, struct mii_timestamper *); -}; - -struct mii_timestamping_desc { - struct list_head list; - struct mii_timestamping_ctrl *ctrl; - struct device *device; -}; - -struct sfp; - -struct sfp_socket_ops; - -struct sfp_quirk; - -struct sfp_upstream_ops; - -struct sfp_bus { - struct kref kref; - struct list_head node; - struct fwnode_handle *fwnode; - const struct sfp_socket_ops *socket_ops; - struct device *sfp_dev; - struct sfp *sfp; - const struct sfp_quirk *sfp_quirk; - const struct sfp_upstream_ops *upstream_ops; - void *upstream; - struct phy_device *phydev; - bool registered; - bool started; -}; - -struct sfp_eeprom_base { - u8 phys_id; - u8 phys_ext_id; - u8 connector; - u8 if_1x_copper_passive: 1; - u8 if_1x_copper_active: 1; - u8 if_1x_lx: 1; - u8 if_1x_sx: 1; - u8 e10g_base_sr: 1; - u8 e10g_base_lr: 1; - u8 e10g_base_lrm: 1; - u8 e10g_base_er: 1; - u8 sonet_oc3_short_reach: 1; - u8 sonet_oc3_smf_intermediate_reach: 1; - u8 sonet_oc3_smf_long_reach: 1; - u8 unallocated_5_3: 1; - u8 sonet_oc12_short_reach: 1; - u8 sonet_oc12_smf_intermediate_reach: 1; - u8 sonet_oc12_smf_long_reach: 1; - u8 unallocated_5_7: 1; - u8 sonet_oc48_short_reach: 1; - u8 sonet_oc48_intermediate_reach: 1; - u8 sonet_oc48_long_reach: 1; - u8 sonet_reach_bit2: 1; - u8 sonet_reach_bit1: 1; - u8 sonet_oc192_short_reach: 1; - u8 escon_smf_1310_laser: 1; - u8 escon_mmf_1310_led: 1; - u8 e1000_base_sx: 1; - u8 e1000_base_lx: 1; - u8 e1000_base_cx: 1; - u8 e1000_base_t: 1; - u8 e100_base_lx: 1; - u8 e100_base_fx: 1; - u8 e_base_bx10: 1; - u8 e_base_px: 1; - u8 fc_tech_electrical_inter_enclosure: 1; - u8 fc_tech_lc: 1; - u8 fc_tech_sa: 1; - u8 fc_ll_m: 1; - u8 fc_ll_l: 1; - u8 fc_ll_i: 1; - u8 fc_ll_s: 1; - u8 fc_ll_v: 1; - u8 unallocated_8_0: 1; - u8 unallocated_8_1: 1; - u8 sfp_ct_passive: 1; - u8 sfp_ct_active: 1; - u8 fc_tech_ll: 1; - u8 fc_tech_sl: 1; - u8 fc_tech_sn: 1; - u8 fc_tech_electrical_intra_enclosure: 1; - u8 fc_media_sm: 1; - u8 unallocated_9_1: 1; - u8 fc_media_m5: 1; - u8 fc_media_m6: 1; - u8 fc_media_tv: 1; - u8 fc_media_mi: 1; - u8 fc_media_tp: 1; - u8 fc_media_tw: 1; - u8 fc_speed_100: 1; - u8 unallocated_10_1: 1; - u8 fc_speed_200: 1; - u8 fc_speed_3200: 1; - u8 fc_speed_400: 1; - u8 fc_speed_1600: 1; - u8 fc_speed_800: 1; - u8 fc_speed_1200: 1; - u8 encoding; - u8 br_nominal; - u8 rate_id; - u8 link_len[6]; - char vendor_name[16]; - u8 extended_cc; - char vendor_oui[3]; - char vendor_pn[16]; - char vendor_rev[4]; - union { - __be16 optical_wavelength; - __be16 cable_compliance; - struct { - u8 sff8431_app_e: 1; - u8 fc_pi_4_app_h: 1; - u8 reserved60_2: 6; - u8 reserved61: 8; - } passive; - struct { - u8 sff8431_app_e: 1; - u8 fc_pi_4_app_h: 1; - u8 sff8431_lim: 1; - u8 fc_pi_4_lim: 1; - u8 reserved60_4: 4; - u8 reserved61: 8; - } active; - }; - u8 reserved62; - u8 cc_base; -}; - -struct sfp_eeprom_ext { - __be16 options; - u8 br_max; - u8 br_min; - char vendor_sn[16]; - char datecode[8]; - u8 diagmon; - u8 enhopts; - u8 sff8472_compliance; - u8 cc_ext; -}; - -struct sfp_eeprom_id { - struct sfp_eeprom_base base; - struct sfp_eeprom_ext ext; -}; - -enum { - SFF8024_ID_UNK = 0, - SFF8024_ID_SFF_8472 = 2, - SFF8024_ID_SFP = 3, - SFF8024_ID_DWDM_SFP = 11, - SFF8024_ID_QSFP_8438 = 12, - SFF8024_ID_QSFP_8436_8636 = 13, - SFF8024_ID_QSFP28_8636 = 17, - SFF8024_ENCODING_UNSPEC = 0, - SFF8024_ENCODING_8B10B = 1, - SFF8024_ENCODING_4B5B = 2, - SFF8024_ENCODING_NRZ = 3, - SFF8024_ENCODING_8472_MANCHESTER = 4, - SFF8024_ENCODING_8472_SONET = 5, - SFF8024_ENCODING_8472_64B66B = 6, - SFF8024_ENCODING_8436_MANCHESTER = 6, - SFF8024_ENCODING_8436_SONET = 4, - SFF8024_ENCODING_8436_64B66B = 5, - SFF8024_ENCODING_256B257B = 7, - SFF8024_ENCODING_PAM4 = 8, - SFF8024_CONNECTOR_UNSPEC = 0, - SFF8024_CONNECTOR_SC = 1, - SFF8024_CONNECTOR_FIBERJACK = 6, - SFF8024_CONNECTOR_LC = 7, - SFF8024_CONNECTOR_MT_RJ = 8, - SFF8024_CONNECTOR_MU = 9, - SFF8024_CONNECTOR_SG = 10, - SFF8024_CONNECTOR_OPTICAL_PIGTAIL = 11, - SFF8024_CONNECTOR_MPO_1X12 = 12, - SFF8024_CONNECTOR_MPO_2X16 = 13, - SFF8024_CONNECTOR_HSSDC_II = 32, - SFF8024_CONNECTOR_COPPER_PIGTAIL = 33, - SFF8024_CONNECTOR_RJ45 = 34, - SFF8024_CONNECTOR_NOSEPARATE = 35, - SFF8024_CONNECTOR_MXC_2X16 = 36, - SFF8024_ECC_UNSPEC = 0, - SFF8024_ECC_100G_25GAUI_C2M_AOC = 1, - SFF8024_ECC_100GBASE_SR4_25GBASE_SR = 2, - SFF8024_ECC_100GBASE_LR4_25GBASE_LR = 3, - SFF8024_ECC_100GBASE_ER4_25GBASE_ER = 4, - SFF8024_ECC_100GBASE_SR10 = 5, - SFF8024_ECC_100GBASE_CR4 = 11, - SFF8024_ECC_25GBASE_CR_S = 12, - SFF8024_ECC_25GBASE_CR_N = 13, - SFF8024_ECC_10GBASE_T_SFI = 22, - SFF8024_ECC_10GBASE_T_SR = 28, - SFF8024_ECC_5GBASE_T = 29, - SFF8024_ECC_2_5GBASE_T = 30, -}; - -struct sfp_upstream_ops { - void (*attach)(void *, struct sfp_bus *); - void (*detach)(void *, struct sfp_bus *); - int (*module_insert)(void *, const struct sfp_eeprom_id *); - void (*module_remove)(void *); - int (*module_start)(void *); - void (*module_stop)(void *); - void (*link_down)(void *); - void (*link_up)(void *); - int (*connect_phy)(void *, struct phy_device *); - void (*disconnect_phy)(void *); -}; - -struct sfp_socket_ops { - void (*attach)(struct sfp *); - void (*detach)(struct sfp *); - void (*start)(struct sfp *); - void (*stop)(struct sfp *); - int (*module_info)(struct sfp *, struct ethtool_modinfo *); - int (*module_eeprom)(struct sfp *, struct ethtool_eeprom *, u8 *); - int (*module_eeprom_by_page)(struct sfp *, const struct ethtool_module_eeprom *, struct netlink_ext_ack *); -}; - -struct sfp_quirk { - const char *vendor; - const char *part; - void (*modes)(const struct sfp_eeprom_id *, long unsigned int *); -}; - -struct wl1251_platform_data { - int power_gpio; - int irq; - bool use_eeprom; -}; - -enum { - IFLA_UNSPEC = 0, - IFLA_ADDRESS = 1, - IFLA_BROADCAST = 2, - IFLA_IFNAME = 3, - IFLA_MTU = 4, - IFLA_LINK = 5, - IFLA_QDISC = 6, - IFLA_STATS = 7, - IFLA_COST = 8, - IFLA_PRIORITY = 9, - IFLA_MASTER = 10, - IFLA_WIRELESS = 11, - IFLA_PROTINFO = 12, - IFLA_TXQLEN = 13, - IFLA_MAP = 14, - IFLA_WEIGHT = 15, - IFLA_OPERSTATE = 16, - IFLA_LINKMODE = 17, - IFLA_LINKINFO = 18, - IFLA_NET_NS_PID = 19, - IFLA_IFALIAS = 20, - IFLA_NUM_VF = 21, - IFLA_VFINFO_LIST = 22, - IFLA_STATS64 = 23, - IFLA_VF_PORTS = 24, - IFLA_PORT_SELF = 25, - IFLA_AF_SPEC = 26, - IFLA_GROUP = 27, - IFLA_NET_NS_FD = 28, - IFLA_EXT_MASK = 29, - IFLA_PROMISCUITY = 30, - IFLA_NUM_TX_QUEUES = 31, - IFLA_NUM_RX_QUEUES = 32, - IFLA_CARRIER = 33, - IFLA_PHYS_PORT_ID = 34, - IFLA_CARRIER_CHANGES = 35, - IFLA_PHYS_SWITCH_ID = 36, - IFLA_LINK_NETNSID = 37, - IFLA_PHYS_PORT_NAME = 38, - IFLA_PROTO_DOWN = 39, - IFLA_GSO_MAX_SEGS = 40, - IFLA_GSO_MAX_SIZE = 41, - IFLA_PAD = 42, - IFLA_XDP = 43, - IFLA_EVENT = 44, - IFLA_NEW_NETNSID = 45, - IFLA_IF_NETNSID = 46, - IFLA_TARGET_NETNSID = 46, - IFLA_CARRIER_UP_COUNT = 47, - IFLA_CARRIER_DOWN_COUNT = 48, - IFLA_NEW_IFINDEX = 49, - IFLA_MIN_MTU = 50, - IFLA_MAX_MTU = 51, - IFLA_PROP_LIST = 52, - IFLA_ALT_IFNAME = 53, - IFLA_PERM_ADDRESS = 54, - IFLA_PROTO_DOWN_REASON = 55, - IFLA_PARENT_DEV_NAME = 56, - IFLA_PARENT_DEV_BUS_NAME = 57, - __IFLA_MAX = 58, -}; - -enum { - IFLA_INFO_UNSPEC = 0, - IFLA_INFO_KIND = 1, - IFLA_INFO_DATA = 2, - IFLA_INFO_XSTATS = 3, - IFLA_INFO_SLAVE_KIND = 4, - IFLA_INFO_SLAVE_DATA = 5, - __IFLA_INFO_MAX = 6, -}; - -enum wwan_port_type { - WWAN_PORT_AT = 0, - WWAN_PORT_MBIM = 1, - WWAN_PORT_QMI = 2, - WWAN_PORT_QCDM = 3, - WWAN_PORT_FIREHOSE = 4, - __WWAN_PORT_MAX = 5, - WWAN_PORT_MAX = 4, - WWAN_PORT_UNKNOWN = 5, -}; - -struct wwan_port; - -struct wwan_port_ops { - int (*start)(struct wwan_port *); - void (*stop)(struct wwan_port *); - int (*tx)(struct wwan_port *, struct sk_buff *); - int (*tx_blocking)(struct wwan_port *, struct sk_buff *); - __poll_t (*tx_poll)(struct wwan_port *, struct file *, poll_table *); -}; - -struct wwan_port { - enum wwan_port_type type; - unsigned int start_count; - long unsigned int flags; - const struct wwan_port_ops *ops; - struct mutex ops_lock; - struct device dev; - struct sk_buff_head rxq; - wait_queue_head_t waitqueue; - struct mutex data_lock; - union { - struct { - struct ktermios termios; - int mdmbits; - } at_data; - }; -}; - -struct wwan_netdev_priv { - u32 link_id; - int: 32; - u8 drv_priv[0]; -}; - -struct wwan_ops { - unsigned int priv_size; - void (*setup)(struct net_device *); - int (*newlink)(void *, struct net_device *, u32, struct netlink_ext_ack *); - void (*dellink)(void *, struct net_device *, struct list_head *); -}; - -struct ifinfomsg { - unsigned char ifi_family; - unsigned char __ifi_pad; - short unsigned int ifi_type; - int ifi_index; - unsigned int ifi_flags; - unsigned int ifi_change; -}; - -enum { - IFLA_WWAN_UNSPEC = 0, - IFLA_WWAN_LINK_ID = 1, - __IFLA_WWAN_MAX = 2, -}; - -struct wwan_device { - unsigned int id; - struct device dev; - atomic_t port_id; - const struct wwan_ops *ops; - void *ops_ctxt; -}; - -enum usb_otg_state { - OTG_STATE_UNDEFINED = 0, - OTG_STATE_B_IDLE = 1, - OTG_STATE_B_SRP_INIT = 2, - OTG_STATE_B_PERIPHERAL = 3, - OTG_STATE_B_WAIT_ACON = 4, - OTG_STATE_B_HOST = 5, - OTG_STATE_A_IDLE = 6, - OTG_STATE_A_WAIT_VRISE = 7, - OTG_STATE_A_WAIT_BCON = 8, - OTG_STATE_A_HOST = 9, - OTG_STATE_A_SUSPEND = 10, - OTG_STATE_A_PERIPHERAL = 11, - OTG_STATE_A_WAIT_VFALL = 12, - OTG_STATE_A_VBUS_ERR = 13, -}; - -enum usb_dr_mode { - USB_DR_MODE_UNKNOWN = 0, - USB_DR_MODE_HOST = 1, - USB_DR_MODE_PERIPHERAL = 2, - USB_DR_MODE_OTG = 3, -}; - -enum usb_led_event { - USB_LED_EVENT_HOST = 0, - USB_LED_EVENT_GADGET = 1, -}; - -struct usb_device_id { - __u16 match_flags; - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice_lo; - __u16 bcdDevice_hi; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 bInterfaceNumber; - kernel_ulong_t driver_info; -}; - -struct usb_descriptor_header { - __u8 bLength; - __u8 bDescriptorType; -}; - -enum usb_port_connect_type { - USB_PORT_CONNECT_TYPE_UNKNOWN = 0, - USB_PORT_CONNECT_TYPE_HOT_PLUG = 1, - USB_PORT_CONNECT_TYPE_HARD_WIRED = 2, - USB_PORT_NOT_USED = 3, -}; - -struct usb_dynids { - spinlock_t lock; - struct list_head list; -}; - -struct usbdrv_wrap { - struct device_driver driver; - int for_devices; -}; - -struct usb_driver { - const char *name; - int (*probe)(struct usb_interface *, const struct usb_device_id *); - void (*disconnect)(struct usb_interface *); - int (*unlocked_ioctl)(struct usb_interface *, unsigned int, void *); - int (*suspend)(struct usb_interface *, pm_message_t); - int (*resume)(struct usb_interface *); - int (*reset_resume)(struct usb_interface *); - int (*pre_reset)(struct usb_interface *); - int (*post_reset)(struct usb_interface *); - const struct usb_device_id *id_table; - const struct attribute_group **dev_groups; - struct usb_dynids dynids; - struct usbdrv_wrap drvwrap; - unsigned int no_dynamic_id: 1; - unsigned int supports_autosuspend: 1; - unsigned int disable_hub_initiated_lpm: 1; - unsigned int soft_unbind: 1; -}; - -struct usb_device_driver { - const char *name; - bool (*match)(struct usb_device *); - int (*probe)(struct usb_device *); - void (*disconnect)(struct usb_device *); - int (*suspend)(struct usb_device *, pm_message_t); - int (*resume)(struct usb_device *, pm_message_t); - const struct attribute_group **dev_groups; - struct usbdrv_wrap drvwrap; - const struct usb_device_id *id_table; - unsigned int supports_autosuspend: 1; - unsigned int generic_subclass: 1; -}; - -enum usb_phy_type { - USB_PHY_TYPE_UNDEFINED = 0, - USB_PHY_TYPE_USB2 = 1, - USB_PHY_TYPE_USB3 = 2, -}; - -enum usb_phy_events { - USB_EVENT_NONE = 0, - USB_EVENT_VBUS = 1, - USB_EVENT_ID = 2, - USB_EVENT_CHARGER = 3, - USB_EVENT_ENUMERATED = 4, -}; - -enum usb_charger_type { - UNKNOWN_TYPE = 0, - SDP_TYPE = 1, - DCP_TYPE = 2, - CDP_TYPE = 3, - ACA_TYPE = 4, -}; - -enum usb_charger_state { - USB_CHARGER_DEFAULT = 0, - USB_CHARGER_PRESENT = 1, - USB_CHARGER_ABSENT = 2, -}; - -struct usb_charger_current { - unsigned int sdp_min; - unsigned int sdp_max; - unsigned int dcp_min; - unsigned int dcp_max; - unsigned int cdp_min; - unsigned int cdp_max; - unsigned int aca_min; - unsigned int aca_max; -}; - -struct usb_otg; - -struct usb_phy_io_ops; - -struct usb_phy { - struct device *dev; - const char *label; - unsigned int flags; - enum usb_phy_type type; - enum usb_phy_events last_event; - struct usb_otg *otg; - struct device *io_dev; - struct usb_phy_io_ops *io_ops; - void *io_priv; - struct extcon_dev *edev; - struct extcon_dev *id_edev; - struct notifier_block vbus_nb; - struct notifier_block id_nb; - struct notifier_block type_nb; - enum usb_charger_type chg_type; - enum usb_charger_state chg_state; - struct usb_charger_current chg_cur; - struct work_struct chg_work; - struct atomic_notifier_head notifier; - u16 port_status; - u16 port_change; - struct list_head head; - int (*init)(struct usb_phy *); - void (*shutdown)(struct usb_phy *); - int (*set_vbus)(struct usb_phy *, int); - int (*set_power)(struct usb_phy *, unsigned int); - int (*set_suspend)(struct usb_phy *, int); - int (*set_wakeup)(struct usb_phy *, bool); - int (*notify_connect)(struct usb_phy *, enum usb_device_speed); - int (*notify_disconnect)(struct usb_phy *, enum usb_device_speed); - enum usb_charger_type (*charger_detect)(struct usb_phy *); -}; - -struct usb_port_status { - __le16 wPortStatus; - __le16 wPortChange; - __le32 dwExtPortStatus; -}; - -struct usb_hub_status { - __le16 wHubStatus; - __le16 wHubChange; -}; - -struct usb_hub_descriptor { - __u8 bDescLength; - __u8 bDescriptorType; - __u8 bNbrPorts; - __le16 wHubCharacteristics; - __u8 bPwrOn2PwrGood; - __u8 bHubContrCurrent; - union { - struct { - __u8 DeviceRemovable[4]; - __u8 PortPwrCtrlMask[4]; - } hs; - struct { - __u8 bHubHdrDecLat; - __le16 wHubDelay; - __le16 DeviceRemovable; - } __attribute__((packed)) ss; - } u; -} __attribute__((packed)); - -struct usb_phy_io_ops { - int (*read)(struct usb_phy *, u32); - int (*write)(struct usb_phy *, u32, u32); -}; - -struct usb_gadget; - -struct usb_otg { - u8 default_a; - struct phy *phy; - struct usb_phy *usb_phy; - struct usb_bus *host; - struct usb_gadget *gadget; - enum usb_otg_state state; - int (*set_host)(struct usb_otg *, struct usb_bus *); - int (*set_peripheral)(struct usb_otg *, struct usb_gadget *); - int (*set_vbus)(struct usb_otg *, bool); - int (*start_srp)(struct usb_otg *); - int (*start_hnp)(struct usb_otg *); -}; - -typedef u32 usb_port_location_t; - -struct usb_port; - -struct usb_hub { - struct device *intfdev; - struct usb_device *hdev; - struct kref kref; - struct urb *urb; - u8 (*buffer)[8]; - union { - struct usb_hub_status hub; - struct usb_port_status port; - } *status; - struct mutex status_mutex; - int error; - int nerrors; - long unsigned int event_bits[1]; - long unsigned int change_bits[1]; - long unsigned int removed_bits[1]; - long unsigned int wakeup_bits[1]; - long unsigned int power_bits[1]; - long unsigned int child_usage_bits[1]; - long unsigned int warm_reset_bits[1]; - struct usb_hub_descriptor *descriptor; - struct usb_tt tt; - unsigned int mA_per_port; - unsigned int wakeup_enabled_descendants; - unsigned int limited_power: 1; - unsigned int quiescing: 1; - unsigned int disconnected: 1; - unsigned int in_reset: 1; - unsigned int quirk_disable_autosuspend: 1; - unsigned int quirk_check_port_auto_suspend: 1; - unsigned int has_indicators: 1; - u8 indicator[31]; - struct delayed_work leds; - struct delayed_work init_work; - struct work_struct events; - spinlock_t irq_urb_lock; - struct timer_list irq_urb_retry; - struct usb_port **ports; -}; - -struct usb_dev_state; - -struct usb_port { - struct usb_device *child; - struct device dev; - struct usb_dev_state *port_owner; - struct usb_port *peer; - struct dev_pm_qos_request *req; - enum usb_port_connect_type connect_type; - usb_port_location_t location; - struct mutex status_lock; - u32 over_current_count; - u8 portnum; - u32 quirks; - unsigned int is_superspeed: 1; - unsigned int usb3_lpm_u1_permit: 1; - unsigned int usb3_lpm_u2_permit: 1; -}; - -struct find_interface_arg { - int minor; - struct device_driver *drv; -}; - -struct each_dev_arg { - void *data; - int (*fn)(struct usb_device *, void *); -}; - -struct each_hub_arg { - void *data; - int (*fn)(struct device *, void *); -}; - -struct usb_qualifier_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __u8 bNumConfigurations; - __u8 bRESERVED; -}; - -struct usb_set_sel_req { - __u8 u1_sel; - __u8 u1_pel; - __le16 u2_sel; - __le16 u2_pel; -}; - -struct usbdevfs_hub_portinfo { - char nports; - char port[127]; -}; - -enum hub_led_mode { - INDICATOR_AUTO = 0, - INDICATOR_CYCLE = 1, - INDICATOR_GREEN_BLINK = 2, - INDICATOR_GREEN_BLINK_OFF = 3, - INDICATOR_AMBER_BLINK = 4, - INDICATOR_AMBER_BLINK_OFF = 5, - INDICATOR_ALT_BLINK = 6, - INDICATOR_ALT_BLINK_OFF = 7, -}; - -struct usb_tt_clear { - struct list_head clear_list; - unsigned int tt; - u16 devinfo; - struct usb_hcd *hcd; - struct usb_host_endpoint *ep; -}; - -enum hub_activation_type { - HUB_INIT = 0, - HUB_INIT2 = 1, - HUB_INIT3 = 2, - HUB_POST_RESET = 3, - HUB_RESUME = 4, - HUB_RESET_RESUME = 5, -}; - -enum hub_quiescing_type { - HUB_DISCONNECT = 0, - HUB_PRE_RESET = 1, - HUB_SUSPEND = 2, -}; - -struct usb_ctrlrequest { - __u8 bRequestType; - __u8 bRequest; - __le16 wValue; - __le16 wIndex; - __le16 wLength; -}; - -struct usb_mon_operations { - void (*urb_submit)(struct usb_bus *, struct urb *); - void (*urb_submit_error)(struct usb_bus *, struct urb *, int); - void (*urb_complete)(struct usb_bus *, struct urb *, int); -}; - -struct usb_sg_request { - int status; - size_t bytes; - spinlock_t lock; - struct usb_device *dev; - int pipe; - int entries; - struct urb **urbs; - int count; - struct completion complete; -}; - -struct usb_cdc_header_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdCDC; -} __attribute__((packed)); - -struct usb_cdc_call_mgmt_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bmCapabilities; - __u8 bDataInterface; -}; - -struct usb_cdc_acm_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bmCapabilities; -}; - -struct usb_cdc_union_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bMasterInterface0; - __u8 bSlaveInterface0; -}; - -struct usb_cdc_country_functional_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 iCountryCodeRelDate; - __le16 wCountyCode0; -}; - -struct usb_cdc_network_terminal_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bEntityId; - __u8 iName; - __u8 bChannelIndex; - __u8 bPhysicalInterface; -}; - -struct usb_cdc_ether_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 iMACAddress; - __le32 bmEthernetStatistics; - __le16 wMaxSegmentSize; - __le16 wNumberMCFilters; - __u8 bNumberPowerFilters; -} __attribute__((packed)); - -struct usb_cdc_dmm_desc { - __u8 bFunctionLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u16 bcdVersion; - __le16 wMaxCommand; -} __attribute__((packed)); - -struct usb_cdc_mdlm_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdVersion; - __u8 bGUID[16]; -} __attribute__((packed)); - -struct usb_cdc_mdlm_detail_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bGuidDescriptorType; - __u8 bDetailData[0]; -}; - -struct usb_cdc_obex_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdVersion; -} __attribute__((packed)); - -struct usb_cdc_ncm_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdNcmVersion; - __u8 bmNetworkCapabilities; -} __attribute__((packed)); - -struct usb_cdc_mbim_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdMBIMVersion; - __le16 wMaxControlMessage; - __u8 bNumberFilters; - __u8 bMaxFilterSize; - __le16 wMaxSegmentSize; - __u8 bmNetworkCapabilities; -} __attribute__((packed)); - -struct usb_cdc_mbim_extended_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __le16 bcdMBIMExtendedVersion; - __u8 bMaxOutstandingCommandMessages; - __le16 wMTU; -} __attribute__((packed)); - -struct usb_cdc_parsed_header { - struct usb_cdc_union_desc *usb_cdc_union_desc; - struct usb_cdc_header_desc *usb_cdc_header_desc; - struct usb_cdc_call_mgmt_descriptor *usb_cdc_call_mgmt_descriptor; - struct usb_cdc_acm_descriptor *usb_cdc_acm_descriptor; - struct usb_cdc_country_functional_desc *usb_cdc_country_functional_desc; - struct usb_cdc_network_terminal_desc *usb_cdc_network_terminal_desc; - struct usb_cdc_ether_desc *usb_cdc_ether_desc; - struct usb_cdc_dmm_desc *usb_cdc_dmm_desc; - struct usb_cdc_mdlm_desc *usb_cdc_mdlm_desc; - struct usb_cdc_mdlm_detail_desc *usb_cdc_mdlm_detail_desc; - struct usb_cdc_obex_desc *usb_cdc_obex_desc; - struct usb_cdc_ncm_desc *usb_cdc_ncm_desc; - struct usb_cdc_mbim_desc *usb_cdc_mbim_desc; - struct usb_cdc_mbim_extended_desc *usb_cdc_mbim_extended_desc; - bool phonet_magic_present; -}; - -struct api_context { - struct completion done; - int status; -}; - -struct set_config_request { - struct usb_device *udev; - int config; - struct work_struct work; - struct list_head node; -}; - -struct usb_dynid { - struct list_head node; - struct usb_device_id id; -}; - -struct usb_dev_cap_header { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; -}; - -struct usb_class_driver { - char *name; - char * (*devnode)(struct device *, umode_t *); - const struct file_operations *fops; - int minor_base; -}; - -struct usb_class { - struct kref kref; - struct class *class; -}; - -struct ep_device { - struct usb_endpoint_descriptor *desc; - struct usb_device *udev; - struct device dev; -}; - -struct usbdevfs_ctrltransfer { - __u8 bRequestType; - __u8 bRequest; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - __u32 timeout; - void *data; -}; - -struct usbdevfs_bulktransfer { - unsigned int ep; - unsigned int len; - unsigned int timeout; - void *data; -}; - -struct usbdevfs_setinterface { - unsigned int interface; - unsigned int altsetting; -}; - -struct usbdevfs_disconnectsignal { - unsigned int signr; - void *context; -}; - -struct usbdevfs_getdriver { - unsigned int interface; - char driver[256]; -}; - -struct usbdevfs_connectinfo { - unsigned int devnum; - unsigned char slow; -}; - -struct usbdevfs_conninfo_ex { - __u32 size; - __u32 busnum; - __u32 devnum; - __u32 speed; - __u8 num_ports; - __u8 ports[7]; -}; - -struct usbdevfs_iso_packet_desc { - unsigned int length; - unsigned int actual_length; - unsigned int status; -}; - -struct usbdevfs_urb { - unsigned char type; - unsigned char endpoint; - int status; - unsigned int flags; - void *buffer; - int buffer_length; - int actual_length; - int start_frame; - union { - int number_of_packets; - unsigned int stream_id; - }; - int error_count; - unsigned int signr; - void *usercontext; - struct usbdevfs_iso_packet_desc iso_frame_desc[0]; -}; - -struct usbdevfs_ioctl { - int ifno; - int ioctl_code; - void *data; -}; - -struct usbdevfs_disconnect_claim { - unsigned int interface; - unsigned int flags; - char driver[256]; -}; - -struct usbdevfs_streams { - unsigned int num_streams; - unsigned int num_eps; - unsigned char eps[0]; -}; - -struct usbdevfs_ctrltransfer32 { - u8 bRequestType; - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; - u32 timeout; - compat_caddr_t data; -}; - -struct usbdevfs_bulktransfer32 { - compat_uint_t ep; - compat_uint_t len; - compat_uint_t timeout; - compat_caddr_t data; -}; - -struct usbdevfs_disconnectsignal32 { - compat_int_t signr; - compat_caddr_t context; -}; - -struct usbdevfs_urb32 { - unsigned char type; - unsigned char endpoint; - compat_int_t status; - compat_uint_t flags; - compat_caddr_t buffer; - compat_int_t buffer_length; - compat_int_t actual_length; - compat_int_t start_frame; - compat_int_t number_of_packets; - compat_int_t error_count; - compat_uint_t signr; - compat_caddr_t usercontext; - struct usbdevfs_iso_packet_desc iso_frame_desc[0]; -}; - -struct usbdevfs_ioctl32 { - s32 ifno; - s32 ioctl_code; - compat_caddr_t data; -}; - -struct usb_dev_state___2 { - struct list_head list; - struct usb_device *dev; - struct file *file; - spinlock_t lock; - struct list_head async_pending; - struct list_head async_completed; - struct list_head memory_list; - wait_queue_head_t wait; - wait_queue_head_t wait_for_resume; - unsigned int discsignr; - struct pid *disc_pid; - const struct cred *cred; - sigval_t disccontext; - long unsigned int ifclaimed; - u32 disabled_bulk_eps; - long unsigned int interface_allowed_mask; - int not_yet_resumed; - bool suspend_allowed; - bool privileges_dropped; -}; - -struct usb_memory { - struct list_head memlist; - int vma_use_count; - int urb_use_count; - u32 size; - void *mem; - dma_addr_t dma_handle; - long unsigned int vm_start; - struct usb_dev_state___2 *ps; -}; - -struct async { - struct list_head asynclist; - struct usb_dev_state___2 *ps; - struct pid *pid; - const struct cred *cred; - unsigned int signr; - unsigned int ifnum; - void *userbuffer; - void *userurb; - sigval_t userurb_sigval; - struct urb *urb; - struct usb_memory *usbm; - unsigned int mem_usage; - int status; - u8 bulk_addr; - u8 bulk_status; -}; - -enum snoop_when { - SUBMIT = 0, - COMPLETE___2 = 1, -}; - -struct quirk_entry { - u16 vid; - u16 pid; - u32 flags; -}; - -struct class_info { - int class; - char *class_name; -}; - -struct usb_phy_roothub___2 { - struct phy *phy; - struct list_head list; -}; - -typedef void (*companion_fn)(struct pci_dev *, struct usb_hcd *, struct pci_dev *, struct usb_hcd *); - -struct phy_devm { - struct usb_phy *phy; - struct notifier_block *nb; -}; - -enum amd_chipset_gen { - NOT_AMD_CHIPSET = 0, - AMD_CHIPSET_SB600 = 1, - AMD_CHIPSET_SB700 = 2, - AMD_CHIPSET_SB800 = 3, - AMD_CHIPSET_HUDSON2 = 4, - AMD_CHIPSET_BOLTON = 5, - AMD_CHIPSET_YANGTZE = 6, - AMD_CHIPSET_TAISHAN = 7, - AMD_CHIPSET_UNKNOWN = 8, -}; - -struct amd_chipset_type { - enum amd_chipset_gen gen; - u8 rev; -}; - -struct amd_chipset_info { - struct pci_dev *nb_dev; - struct pci_dev *smbus_dev; - int nb_type; - struct amd_chipset_type sb_type; - int isoc_reqs; - int probe_count; - bool need_pll_quirk; -}; - -struct ehci_stats { - long unsigned int normal; - long unsigned int error; - long unsigned int iaa; - long unsigned int lost_iaa; - long unsigned int complete; - long unsigned int unlink; -}; - -struct ehci_per_sched { - struct usb_device *udev; - struct usb_host_endpoint *ep; - struct list_head ps_list; - u16 tt_usecs; - u16 cs_mask; - u16 period; - u16 phase; - u8 bw_phase; - u8 phase_uf; - u8 usecs; - u8 c_usecs; - u8 bw_uperiod; - u8 bw_period; -}; - -enum ehci_rh_state { - EHCI_RH_HALTED = 0, - EHCI_RH_SUSPENDED = 1, - EHCI_RH_RUNNING = 2, - EHCI_RH_STOPPING = 3, -}; - -enum ehci_hrtimer_event { - EHCI_HRTIMER_POLL_ASS = 0, - EHCI_HRTIMER_POLL_PSS = 1, - EHCI_HRTIMER_POLL_DEAD = 2, - EHCI_HRTIMER_UNLINK_INTR = 3, - EHCI_HRTIMER_FREE_ITDS = 4, - EHCI_HRTIMER_ACTIVE_UNLINK = 5, - EHCI_HRTIMER_START_UNLINK_INTR = 6, - EHCI_HRTIMER_ASYNC_UNLINKS = 7, - EHCI_HRTIMER_IAA_WATCHDOG = 8, - EHCI_HRTIMER_DISABLE_PERIODIC = 9, - EHCI_HRTIMER_DISABLE_ASYNC = 10, - EHCI_HRTIMER_IO_WATCHDOG = 11, - EHCI_HRTIMER_NUM_EVENTS = 12, -}; - -struct ehci_caps; - -struct ehci_regs; - -struct ehci_dbg_port; - -struct ehci_qh; - -union ehci_shadow; - -struct ehci_itd; - -struct ehci_sitd; - -struct ehci_hcd { - enum ehci_hrtimer_event next_hrtimer_event; - unsigned int enabled_hrtimer_events; - ktime_t hr_timeouts[12]; - struct hrtimer hrtimer; - int PSS_poll_count; - int ASS_poll_count; - int died_poll_count; - struct ehci_caps *caps; - struct ehci_regs *regs; - struct ehci_dbg_port *debug; - __u32 hcs_params; - spinlock_t lock; - enum ehci_rh_state rh_state; - bool scanning: 1; - bool need_rescan: 1; - bool intr_unlinking: 1; - bool iaa_in_progress: 1; - bool async_unlinking: 1; - bool shutdown: 1; - struct ehci_qh *qh_scan_next; - struct ehci_qh *async; - struct ehci_qh *dummy; - struct list_head async_unlink; - struct list_head async_idle; - unsigned int async_unlink_cycle; - unsigned int async_count; - __le32 old_current; - __le32 old_token; - unsigned int periodic_size; - __le32 *periodic; - dma_addr_t periodic_dma; - struct list_head intr_qh_list; - unsigned int i_thresh; - union ehci_shadow *pshadow; - struct list_head intr_unlink_wait; - struct list_head intr_unlink; - unsigned int intr_unlink_wait_cycle; - unsigned int intr_unlink_cycle; - unsigned int now_frame; - unsigned int last_iso_frame; - unsigned int intr_count; - unsigned int isoc_count; - unsigned int periodic_count; - unsigned int uframe_periodic_max; - struct list_head cached_itd_list; - struct ehci_itd *last_itd_to_free; - struct list_head cached_sitd_list; - struct ehci_sitd *last_sitd_to_free; - long unsigned int reset_done[15]; - long unsigned int bus_suspended; - long unsigned int companion_ports; - long unsigned int owned_ports; - long unsigned int port_c_suspend; - long unsigned int suspended_ports; - long unsigned int resuming_ports; - struct dma_pool___2 *qh_pool; - struct dma_pool___2 *qtd_pool; - struct dma_pool___2 *itd_pool; - struct dma_pool___2 *sitd_pool; - unsigned int random_frame; - long unsigned int next_statechange; - ktime_t last_periodic_enable; - u32 command; - unsigned int no_selective_suspend: 1; - unsigned int has_fsl_port_bug: 1; - unsigned int has_fsl_hs_errata: 1; - unsigned int has_fsl_susp_errata: 1; - unsigned int big_endian_mmio: 1; - unsigned int big_endian_desc: 1; - unsigned int big_endian_capbase: 1; - unsigned int has_amcc_usb23: 1; - unsigned int need_io_watchdog: 1; - unsigned int amd_pll_fix: 1; - unsigned int use_dummy_qh: 1; - unsigned int has_synopsys_hc_bug: 1; - unsigned int frame_index_bug: 1; - unsigned int need_oc_pp_cycle: 1; - unsigned int imx28_write_fix: 1; - unsigned int spurious_oc: 1; - __le32 *ohci_hcctrl_reg; - unsigned int has_hostpc: 1; - unsigned int has_tdi_phy_lpm: 1; - unsigned int has_ppcd: 1; - u8 sbrn; - struct ehci_stats stats; - struct dentry *debug_dir; - u8 bandwidth[64]; - u8 tt_budget[64]; - struct list_head tt_list; - long unsigned int priv[0]; -}; - -struct ehci_caps { - u32 hc_capbase; - u32 hcs_params; - u32 hcc_params; - u8 portroute[8]; -}; - -struct ehci_regs { - u32 command; - u32 status; - u32 intr_enable; - u32 frame_index; - u32 segment; - u32 frame_list; - u32 async_next; - u32 reserved1[2]; - u32 txfill_tuning; - u32 reserved2[6]; - u32 configured_flag; - u32 port_status[0]; - u32 reserved3[9]; - u32 usbmode; - u32 reserved4[6]; - u32 hostpc[0]; - u32 reserved5[17]; - u32 usbmode_ex; -}; - -struct ehci_dbg_port { - u32 control; - u32 pids; - u32 data03; - u32 data47; - u32 address; -}; - -struct ehci_fstn; - -union ehci_shadow { - struct ehci_qh *qh; - struct ehci_itd *itd; - struct ehci_sitd *sitd; - struct ehci_fstn *fstn; - __le32 *hw_next; - void *ptr; -}; - -struct ehci_qh_hw; - -struct ehci_qtd; - -struct ehci_qh { - struct ehci_qh_hw *hw; - dma_addr_t qh_dma; - union ehci_shadow qh_next; - struct list_head qtd_list; - struct list_head intr_node; - struct ehci_qtd *dummy; - struct list_head unlink_node; - struct ehci_per_sched ps; - unsigned int unlink_cycle; - u8 qh_state; - u8 xacterrs; - u8 unlink_reason; - u8 gap_uf; - unsigned int is_out: 1; - unsigned int clearing_tt: 1; - unsigned int dequeue_during_giveback: 1; - unsigned int should_be_inactive: 1; -}; - -struct ehci_iso_stream; - -struct ehci_itd { - __le32 hw_next; - __le32 hw_transaction[8]; - __le32 hw_bufp[7]; - __le32 hw_bufp_hi[7]; - dma_addr_t itd_dma; - union ehci_shadow itd_next; - struct urb *urb; - struct ehci_iso_stream *stream; - struct list_head itd_list; - unsigned int frame; - unsigned int pg; - unsigned int index[8]; - long: 64; -}; - -struct ehci_sitd { - __le32 hw_next; - __le32 hw_fullspeed_ep; - __le32 hw_uframe; - __le32 hw_results; - __le32 hw_buf[2]; - __le32 hw_backpointer; - __le32 hw_buf_hi[2]; - dma_addr_t sitd_dma; - union ehci_shadow sitd_next; - struct urb *urb; - struct ehci_iso_stream *stream; - struct list_head sitd_list; - unsigned int frame; - unsigned int index; -}; - -struct ehci_qtd { - __le32 hw_next; - __le32 hw_alt_next; - __le32 hw_token; - __le32 hw_buf[5]; - __le32 hw_buf_hi[5]; - dma_addr_t qtd_dma; - struct list_head qtd_list; - struct urb *urb; - size_t length; -}; - -struct ehci_fstn { - __le32 hw_next; - __le32 hw_prev; - dma_addr_t fstn_dma; - union ehci_shadow fstn_next; - long: 64; -}; - -struct ehci_qh_hw { - __le32 hw_next; - __le32 hw_info1; - __le32 hw_info2; - __le32 hw_current; - __le32 hw_qtd_next; - __le32 hw_alt_next; - __le32 hw_token; - __le32 hw_buf[5]; - __le32 hw_buf_hi[5]; - long: 32; - long: 64; - long: 64; - long: 64; -}; - -struct ehci_iso_packet { - u64 bufp; - __le32 transaction; - u8 cross; - u32 buf1; -}; - -struct ehci_iso_sched { - struct list_head td_list; - unsigned int span; - unsigned int first_packet; - struct ehci_iso_packet packet[0]; -}; - -struct ehci_iso_stream { - struct ehci_qh_hw *hw; - u8 bEndpointAddress; - u8 highspeed; - struct list_head td_list; - struct list_head free_list; - struct ehci_per_sched ps; - unsigned int next_uframe; - __le32 splits; - u16 uperiod; - u16 maxp; - unsigned int bandwidth; - __le32 buf0; - __le32 buf1; - __le32 buf2; - __le32 address; -}; - -struct ehci_tt { - u16 bandwidth[8]; - struct list_head tt_list; - struct list_head ps_list; - struct usb_tt *usb_tt; - int tt_port; -}; - -struct ehci_driver_overrides { - size_t extra_priv_size; - int (*reset)(struct usb_hcd *); - int (*port_power)(struct usb_hcd *, int, bool); -}; - -struct debug_buffer { - ssize_t (*fill_func)(struct debug_buffer *); - struct usb_bus *bus; - struct mutex mutex; - size_t count; - char *output_buf; - size_t alloc_size; -}; - -typedef __u32 __hc32; - -typedef __u16 __hc16; - -struct td; - -struct ed { - __hc32 hwINFO; - __hc32 hwTailP; - __hc32 hwHeadP; - __hc32 hwNextED; - dma_addr_t dma; - struct td *dummy; - struct ed *ed_next; - struct ed *ed_prev; - struct list_head td_list; - struct list_head in_use_list; - u8 state; - u8 type; - u8 branch; - u16 interval; - u16 load; - u16 last_iso; - u16 tick; - unsigned int takeback_wdh_cnt; - struct td *pending_td; - long: 64; -}; - -struct td { - __hc32 hwINFO; - __hc32 hwCBP; - __hc32 hwNextTD; - __hc32 hwBE; - __hc16 hwPSW[2]; - __u8 index; - struct ed *ed; - struct td *td_hash; - struct td *next_dl_td; - struct urb *urb; - dma_addr_t td_dma; - dma_addr_t data_dma; - struct list_head td_list; - long: 64; -}; - -struct ohci_hcca { - __hc32 int_table[32]; - __hc32 frame_no; - __hc32 done_head; - u8 reserved_for_hc[116]; - u8 what[4]; -}; - -struct ohci_roothub_regs { - __hc32 a; - __hc32 b; - __hc32 status; - __hc32 portstatus[15]; -}; - -struct ohci_regs { - __hc32 revision; - __hc32 control; - __hc32 cmdstatus; - __hc32 intrstatus; - __hc32 intrenable; - __hc32 intrdisable; - __hc32 hcca; - __hc32 ed_periodcurrent; - __hc32 ed_controlhead; - __hc32 ed_controlcurrent; - __hc32 ed_bulkhead; - __hc32 ed_bulkcurrent; - __hc32 donehead; - __hc32 fminterval; - __hc32 fmremaining; - __hc32 fmnumber; - __hc32 periodicstart; - __hc32 lsthresh; - struct ohci_roothub_regs roothub; - long: 64; - long: 64; -}; - -struct urb_priv { - struct ed *ed; - u16 length; - u16 td_cnt; - struct list_head pending; - struct td *td[0]; -}; - -typedef struct urb_priv urb_priv_t; - -enum ohci_rh_state { - OHCI_RH_HALTED = 0, - OHCI_RH_SUSPENDED = 1, - OHCI_RH_RUNNING = 2, -}; - -struct ohci_hcd { - spinlock_t lock; - struct ohci_regs *regs; - struct ohci_hcca *hcca; - dma_addr_t hcca_dma; - struct ed *ed_rm_list; - struct ed *ed_bulktail; - struct ed *ed_controltail; - struct ed *periodic[32]; - void (*start_hnp)(struct ohci_hcd *); - struct dma_pool___2 *td_cache; - struct dma_pool___2 *ed_cache; - struct td *td_hash[64]; - struct td *dl_start; - struct td *dl_end; - struct list_head pending; - struct list_head eds_in_use; - enum ohci_rh_state rh_state; - int num_ports; - int load[32]; - u32 hc_control; - long unsigned int next_statechange; - u32 fminterval; - unsigned int autostop: 1; - unsigned int working: 1; - unsigned int restart_work: 1; - long unsigned int flags; - unsigned int prev_frame_no; - unsigned int wdh_cnt; - unsigned int prev_wdh_cnt; - u32 prev_donehead; - struct timer_list io_watchdog; - struct work_struct nec_work; - struct dentry *debug_dir; - long unsigned int priv[0]; -}; - -struct ohci_driver_overrides { - const char *product_desc; - size_t extra_priv_size; - int (*reset)(struct usb_hcd *); -}; - -struct debug_buffer___2 { - ssize_t (*fill_func)(struct debug_buffer___2 *); - struct ohci_hcd *ohci; - struct mutex mutex; - size_t count; - char *page; -}; - -struct uhci_td; - -struct uhci_qh { - __le32 link; - __le32 element; - dma_addr_t dma_handle; - struct list_head node; - struct usb_host_endpoint *hep; - struct usb_device *udev; - struct list_head queue; - struct uhci_td *dummy_td; - struct uhci_td *post_td; - struct usb_iso_packet_descriptor *iso_packet_desc; - long unsigned int advance_jiffies; - unsigned int unlink_frame; - unsigned int period; - short int phase; - short int load; - unsigned int iso_frame; - int state; - int type; - int skel; - unsigned int initial_toggle: 1; - unsigned int needs_fixup: 1; - unsigned int is_stopped: 1; - unsigned int wait_expired: 1; - unsigned int bandwidth_reserved: 1; -}; - -struct uhci_td { - __le32 link; - __le32 status; - __le32 token; - __le32 buffer; - dma_addr_t dma_handle; - struct list_head list; - int frame; - struct list_head fl_list; -}; - -enum uhci_rh_state { - UHCI_RH_RESET = 0, - UHCI_RH_SUSPENDED = 1, - UHCI_RH_AUTO_STOPPED = 2, - UHCI_RH_RESUMING = 3, - UHCI_RH_SUSPENDING = 4, - UHCI_RH_RUNNING = 5, - UHCI_RH_RUNNING_NODEVS = 6, -}; - -struct uhci_hcd { - long unsigned int io_addr; - void *regs; - struct dma_pool___2 *qh_pool; - struct dma_pool___2 *td_pool; - struct uhci_td *term_td; - struct uhci_qh *skelqh[11]; - struct uhci_qh *next_qh; - spinlock_t lock; - dma_addr_t frame_dma_handle; - __le32 *frame; - void **frame_cpu; - enum uhci_rh_state rh_state; - long unsigned int auto_stop_time; - unsigned int frame_number; - unsigned int is_stopped; - unsigned int last_iso_frame; - unsigned int cur_iso_frame; - unsigned int scan_in_progress: 1; - unsigned int need_rescan: 1; - unsigned int dead: 1; - unsigned int RD_enable: 1; - unsigned int is_initialized: 1; - unsigned int fsbr_is_on: 1; - unsigned int fsbr_is_wanted: 1; - unsigned int fsbr_expiring: 1; - struct timer_list fsbr_timer; - unsigned int oc_low: 1; - unsigned int wait_for_hp: 1; - unsigned int big_endian_mmio: 1; - unsigned int big_endian_desc: 1; - unsigned int is_aspeed: 1; - long unsigned int port_c_suspend; - long unsigned int resuming_ports; - long unsigned int ports_timeout; - struct list_head idle_qh_list; - int rh_numports; - wait_queue_head_t waitqh; - int num_waiting; - int total_load; - short int load[32]; - struct clk *clk; - void (*reset_hc)(struct uhci_hcd *); - int (*check_and_reset_hc)(struct uhci_hcd *); - void (*configure_hc)(struct uhci_hcd *); - int (*resume_detect_interrupts_are_broken)(struct uhci_hcd *); - int (*global_suspend_mode_is_broken)(struct uhci_hcd *); -}; - -struct urb_priv___2 { - struct list_head node; - struct urb *urb; - struct uhci_qh *qh; - struct list_head td_list; - unsigned int fsbr: 1; -}; - -struct uhci_debug { - int size; - char *data; -}; - -struct xhci_cap_regs { - __le32 hc_capbase; - __le32 hcs_params1; - __le32 hcs_params2; - __le32 hcs_params3; - __le32 hcc_params; - __le32 db_off; - __le32 run_regs_off; - __le32 hcc_params2; -}; - -struct xhci_op_regs { - __le32 command; - __le32 status; - __le32 page_size; - __le32 reserved1; - __le32 reserved2; - __le32 dev_notification; - __le64 cmd_ring; - __le32 reserved3[4]; - __le64 dcbaa_ptr; - __le32 config_reg; - __le32 reserved4[241]; - __le32 port_status_base; - __le32 port_power_base; - __le32 port_link_base; - __le32 reserved5; - __le32 reserved6[1016]; -}; - -struct xhci_intr_reg { - __le32 irq_pending; - __le32 irq_control; - __le32 erst_size; - __le32 rsvd; - __le64 erst_base; - __le64 erst_dequeue; -}; - -struct xhci_run_regs { - __le32 microframe_index; - __le32 rsvd[7]; - struct xhci_intr_reg ir_set[128]; -}; - -struct xhci_doorbell_array { - __le32 doorbell[256]; -}; - -struct xhci_container_ctx { - unsigned int type; - int size; - u8 *bytes; - dma_addr_t dma; -}; - -struct xhci_slot_ctx { - __le32 dev_info; - __le32 dev_info2; - __le32 tt_info; - __le32 dev_state; - __le32 reserved[4]; -}; - -struct xhci_ep_ctx { - __le32 ep_info; - __le32 ep_info2; - __le64 deq; - __le32 tx_info; - __le32 reserved[3]; -}; - -struct xhci_input_control_ctx { - __le32 drop_flags; - __le32 add_flags; - __le32 rsvd2[6]; -}; - -union xhci_trb; - -struct xhci_command { - struct xhci_container_ctx *in_ctx; - u32 status; - int slot_id; - struct completion *completion; - union xhci_trb *command_trb; - struct list_head cmd_list; -}; - -struct xhci_link_trb { - __le64 segment_ptr; - __le32 intr_target; - __le32 control; -}; - -struct xhci_transfer_event { - __le64 buffer; - __le32 transfer_len; - __le32 flags; -}; - -struct xhci_event_cmd { - __le64 cmd_trb; - __le32 status; - __le32 flags; -}; - -struct xhci_generic_trb { - __le32 field[4]; -}; - -union xhci_trb { - struct xhci_link_trb link; - struct xhci_transfer_event trans_event; - struct xhci_event_cmd event_cmd; - struct xhci_generic_trb generic; -}; - -struct xhci_stream_ctx { - __le64 stream_ring; - __le32 reserved[2]; -}; - -struct xhci_ring; - -struct xhci_stream_info { - struct xhci_ring **stream_rings; - unsigned int num_streams; - struct xhci_stream_ctx *stream_ctx_array; - unsigned int num_stream_ctxs; - dma_addr_t ctx_array_dma; - struct xarray trb_address_map; - struct xhci_command *free_streams_command; -}; - -enum xhci_ring_type { - TYPE_CTRL = 0, - TYPE_ISOC = 1, - TYPE_BULK = 2, - TYPE_INTR = 3, - TYPE_STREAM = 4, - TYPE_COMMAND = 5, - TYPE_EVENT = 6, -}; - -struct xhci_segment; - -struct xhci_ring { - struct xhci_segment *first_seg; - struct xhci_segment *last_seg; - union xhci_trb *enqueue; - struct xhci_segment *enq_seg; - union xhci_trb *dequeue; - struct xhci_segment *deq_seg; - struct list_head td_list; - u32 cycle_state; - unsigned int err_count; - unsigned int stream_id; - unsigned int num_segs; - unsigned int num_trbs_free; - unsigned int num_trbs_free_temp; - unsigned int bounce_buf_len; - enum xhci_ring_type type; - bool last_td_was_short; - struct xarray *trb_address_map; -}; - -struct xhci_bw_info { - unsigned int ep_interval; - unsigned int mult; - unsigned int num_packets; - unsigned int max_packet_size; - unsigned int max_esit_payload; - unsigned int type; -}; - -struct xhci_virt_device; - -struct xhci_hcd; - -struct xhci_virt_ep { - struct xhci_virt_device *vdev; - unsigned int ep_index; - struct xhci_ring *ring; - struct xhci_stream_info *stream_info; - struct xhci_ring *new_ring; - unsigned int ep_state; - struct list_head cancelled_td_list; - struct timer_list stop_cmd_timer; - struct xhci_hcd *xhci; - struct xhci_segment *queued_deq_seg; - union xhci_trb *queued_deq_ptr; - bool skip; - struct xhci_bw_info bw_info; - struct list_head bw_endpoint_list; - int next_frame_id; - bool use_extended_tbc; -}; - -struct xhci_interval_bw_table; - -struct xhci_tt_bw_info; - -struct xhci_virt_device { - int slot_id; - struct usb_device *udev; - struct xhci_container_ctx *out_ctx; - struct xhci_container_ctx *in_ctx; - struct xhci_virt_ep eps[31]; - u8 fake_port; - u8 real_port; - struct xhci_interval_bw_table *bw_table; - struct xhci_tt_bw_info *tt_info; - long unsigned int flags; - u16 current_mel; - void *debugfs_private; -}; - -struct xhci_erst_entry; - -struct xhci_erst { - struct xhci_erst_entry *entries; - unsigned int num_entries; - dma_addr_t erst_dma_addr; - unsigned int erst_size; -}; - -struct s3_save { - u32 command; - u32 dev_nt; - u64 dcbaa_ptr; - u32 config_reg; - u32 irq_pending; - u32 irq_control; - u32 erst_size; - u64 erst_base; - u64 erst_dequeue; -}; - -struct xhci_bus_state { - long unsigned int bus_suspended; - long unsigned int next_statechange; - u32 port_c_suspend; - u32 suspended_ports; - u32 port_remote_wakeup; - long unsigned int resume_done[31]; - long unsigned int resuming_ports; - long unsigned int rexit_ports; - struct completion rexit_done[31]; - struct completion u3exit_done[31]; -}; - -struct xhci_port; - -struct xhci_hub { - struct xhci_port **ports; - unsigned int num_ports; - struct usb_hcd *hcd; - struct xhci_bus_state bus_state; - u8 maj_rev; - u8 min_rev; -}; - -struct xhci_device_context_array; - -struct xhci_scratchpad; - -struct xhci_root_port_bw_info; - -struct xhci_port_cap; - -struct xhci_hcd { - struct usb_hcd *main_hcd; - struct usb_hcd *shared_hcd; - struct xhci_cap_regs *cap_regs; - struct xhci_op_regs *op_regs; - struct xhci_run_regs *run_regs; - struct xhci_doorbell_array *dba; - struct xhci_intr_reg *ir_set; - __u32 hcs_params1; - __u32 hcs_params2; - __u32 hcs_params3; - __u32 hcc_params; - __u32 hcc_params2; - spinlock_t lock; - u8 sbrn; - u16 hci_version; - u8 max_slots; - u8 max_interrupters; - u8 max_ports; - u8 isoc_threshold; - u32 imod_interval; - u32 isoc_bei_interval; - int event_ring_max; - int page_size; - int page_shift; - int msix_count; - struct clk *clk; - struct clk *reg_clk; - struct reset_control *reset; - struct xhci_device_context_array *dcbaa; - struct xhci_ring *cmd_ring; - unsigned int cmd_ring_state; - struct list_head cmd_list; - unsigned int cmd_ring_reserved_trbs; - struct delayed_work cmd_timer; - struct completion cmd_ring_stop_completion; - struct xhci_command *current_cmd; - struct xhci_ring *event_ring; - struct xhci_erst erst; - struct xhci_scratchpad *scratchpad; - struct list_head lpm_failed_devs; - struct mutex mutex; - struct xhci_command *lpm_command; - struct xhci_virt_device *devs[256]; - struct xhci_root_port_bw_info *rh_bw; - struct dma_pool___2 *device_pool; - struct dma_pool___2 *segment_pool; - struct dma_pool___2 *small_streams_pool; - struct dma_pool___2 *medium_streams_pool; - unsigned int xhc_state; - u32 command; - struct s3_save s3; - long long unsigned int quirks; - unsigned int num_active_eps; - unsigned int limit_active_eps; - struct xhci_port *hw_ports; - struct xhci_hub usb2_rhub; - struct xhci_hub usb3_rhub; - unsigned int hw_lpm_support: 1; - unsigned int broken_suspend: 1; - u32 *ext_caps; - unsigned int num_ext_caps; - struct xhci_port_cap *port_caps; - unsigned int num_port_caps; - struct timer_list comp_mode_recovery_timer; - u32 port_status_u0; - u16 test_mode; - struct dentry *debugfs_root; - struct dentry *debugfs_slots; - struct list_head regset_list; - void *dbc; - long unsigned int priv[0]; -}; - -struct xhci_segment { - union xhci_trb *trbs; - struct xhci_segment *next; - dma_addr_t dma; - dma_addr_t bounce_dma; - void *bounce_buf; - unsigned int bounce_offs; - unsigned int bounce_len; -}; - -enum xhci_overhead_type { - LS_OVERHEAD_TYPE = 0, - FS_OVERHEAD_TYPE = 1, - HS_OVERHEAD_TYPE = 2, -}; - -struct xhci_interval_bw { - unsigned int num_packets; - struct list_head endpoints; - unsigned int overhead[3]; -}; - -struct xhci_interval_bw_table { - unsigned int interval0_esit_payload; - struct xhci_interval_bw interval_bw[16]; - unsigned int bw_used; - unsigned int ss_bw_in; - unsigned int ss_bw_out; -}; - -struct xhci_tt_bw_info { - struct list_head tt_list; - int slot_id; - int ttport; - struct xhci_interval_bw_table bw_table; - int active_eps; -}; - -struct xhci_root_port_bw_info { - struct list_head tts; - unsigned int num_active_tts; - struct xhci_interval_bw_table bw_table; -}; - -struct xhci_device_context_array { - __le64 dev_context_ptrs[256]; - dma_addr_t dma; -}; - -enum xhci_setup_dev { - SETUP_CONTEXT_ONLY = 0, - SETUP_CONTEXT_ADDRESS = 1, -}; - -enum xhci_cancelled_td_status { - TD_DIRTY = 0, - TD_HALTED = 1, - TD_CLEARING_CACHE = 2, - TD_CLEARED = 3, -}; - -struct xhci_td { - struct list_head td_list; - struct list_head cancelled_td_list; - int status; - enum xhci_cancelled_td_status cancel_status; - struct urb *urb; - struct xhci_segment *start_seg; - union xhci_trb *first_trb; - union xhci_trb *last_trb; - struct xhci_segment *last_trb_seg; - struct xhci_segment *bounce_seg; - bool urb_length_set; - unsigned int num_trbs; -}; - -struct xhci_erst_entry { - __le64 seg_addr; - __le32 seg_size; - __le32 rsvd; -}; - -struct xhci_scratchpad { - u64 *sp_array; - dma_addr_t sp_dma; - void **sp_buffers; -}; - -struct urb_priv___3 { - int num_tds; - int num_tds_done; - struct xhci_td td[0]; -}; - -struct xhci_port_cap { - u32 *psi; - u8 psi_count; - u8 psi_uid_count; - u8 maj_rev; - u8 min_rev; -}; - -struct xhci_port { - __le32 *addr; - int hw_portnum; - int hcd_portnum; - struct xhci_hub *rhub; - struct xhci_port_cap *port_cap; -}; - -struct xhci_driver_overrides { - size_t extra_priv_size; - int (*reset)(struct usb_hcd *); - int (*start)(struct usb_hcd *); - int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); - int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); - int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); - void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); -}; - -typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); - -enum xhci_ep_reset_type { - EP_HARD_RESET = 0, - EP_SOFT_RESET = 1, -}; - -struct dbc_regs { - __le32 capability; - __le32 doorbell; - __le32 ersts; - __le32 __reserved_0; - __le64 erstba; - __le64 erdp; - __le32 control; - __le32 status; - __le32 portsc; - __le32 __reserved_1; - __le64 dccp; - __le32 devinfo1; - __le32 devinfo2; -}; - -struct dbc_str_descs { - char string0[64]; - char manufacturer[64]; - char product[64]; - char serial[64]; -}; - -enum dbc_state { - DS_DISABLED = 0, - DS_INITIALIZED = 1, - DS_ENABLED = 2, - DS_CONNECTED = 3, - DS_CONFIGURED = 4, - DS_STALLED = 5, -}; - -struct xhci_dbc; - -struct dbc_ep { - struct xhci_dbc *dbc; - struct list_head list_pending; - struct xhci_ring *ring; - unsigned int direction: 1; -}; - -struct dbc_driver; - -struct xhci_dbc { - spinlock_t lock; - struct device *dev; - struct xhci_hcd *xhci; - struct dbc_regs *regs; - struct xhci_ring *ring_evt; - struct xhci_ring *ring_in; - struct xhci_ring *ring_out; - struct xhci_erst erst; - struct xhci_container_ctx *ctx; - struct dbc_str_descs *string; - dma_addr_t string_dma; - size_t string_size; - enum dbc_state state; - struct delayed_work event_work; - unsigned int resume_required: 1; - struct dbc_ep eps[2]; - const struct dbc_driver *driver; - void *priv; -}; - -struct dbc_driver { - int (*configure)(struct xhci_dbc *); - void (*disconnect)(struct xhci_dbc *); -}; - -struct dbc_request { - void *buf; - unsigned int length; - dma_addr_t dma; - void (*complete)(struct xhci_dbc *, struct dbc_request *); - struct list_head list_pool; - int status; - unsigned int actual; - struct xhci_dbc *dbc; - struct list_head list_pending; - dma_addr_t trb_dma; - union xhci_trb *trb; - unsigned int direction: 1; -}; - -struct trace_event_raw_xhci_log_msg { - struct trace_entry ent; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ctx { - struct trace_entry ent; - int ctx_64; - unsigned int ctx_type; - dma_addr_t ctx_dma; - u8 *ctx_va; - unsigned int ctx_ep_num; - int slot_id; - u32 __data_loc_ctx_data; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_trb { - struct trace_entry ent; - u32 type; - u32 field0; - u32 field1; - u32 field2; - u32 field3; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_free_virt_dev { - struct trace_entry ent; - void *vdev; - long long unsigned int out_ctx; - long long unsigned int in_ctx; - u8 fake_port; - u8 real_port; - u16 current_mel; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_virt_dev { - struct trace_entry ent; - void *vdev; - long long unsigned int out_ctx; - long long unsigned int in_ctx; - int devnum; - int state; - int speed; - u8 portnum; - u8 level; - int slot_id; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_urb { - struct trace_entry ent; - void *urb; - unsigned int pipe; - unsigned int stream; - int status; - unsigned int flags; - int num_mapped_sgs; - int num_sgs; - int length; - int actual; - int epnum; - int dir_in; - int type; - int slot_id; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ep_ctx { - struct trace_entry ent; - u32 info; - u32 info2; - u64 deq; - u32 tx_info; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_slot_ctx { - struct trace_entry ent; - u32 info; - u32 info2; - u32 tt_info; - u32 state; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ctrl_ctx { - struct trace_entry ent; - u32 drop; - u32 add; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_ring { - struct trace_entry ent; - u32 type; - void *ring; - dma_addr_t enq; - dma_addr_t deq; - dma_addr_t enq_seg; - dma_addr_t deq_seg; - unsigned int num_segs; - unsigned int stream_id; - unsigned int cycle_state; - unsigned int num_trbs_free; - unsigned int bounce_buf_len; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_portsc { - struct trace_entry ent; - u32 portnum; - u32 portsc; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_log_doorbell { - struct trace_entry ent; - u32 slot; - u32 doorbell; - u32 __data_loc_str; - char __data[0]; -}; - -struct trace_event_raw_xhci_dbc_log_request { - struct trace_entry ent; - struct dbc_request *req; - bool dir; - unsigned int actual; - unsigned int length; - int status; - char __data[0]; -}; - -struct trace_event_data_offsets_xhci_log_msg { - u32 msg; -}; - -struct trace_event_data_offsets_xhci_log_ctx { - u32 ctx_data; -}; - -struct trace_event_data_offsets_xhci_log_trb { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_free_virt_dev {}; - -struct trace_event_data_offsets_xhci_log_virt_dev {}; - -struct trace_event_data_offsets_xhci_log_urb {}; - -struct trace_event_data_offsets_xhci_log_ep_ctx { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_slot_ctx { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_ctrl_ctx { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_ring {}; - -struct trace_event_data_offsets_xhci_log_portsc { - u32 str; -}; - -struct trace_event_data_offsets_xhci_log_doorbell { - u32 str; -}; - -struct trace_event_data_offsets_xhci_dbc_log_request {}; - -typedef void (*btf_trace_xhci_dbg_address)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_context_change)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_quirks)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_reset_ep)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_cancel_urb)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_init)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_dbg_ring_expansion)(void *, struct va_format *); - -typedef void (*btf_trace_xhci_address_ctx)(void *, struct xhci_hcd *, struct xhci_container_ctx *, unsigned int); - -typedef void (*btf_trace_xhci_handle_event)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_handle_command)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_handle_transfer)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_queue_trb)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_dbc_handle_event)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_dbc_handle_transfer)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_dbc_gadget_ep_queue)(void *, struct xhci_ring *, struct xhci_generic_trb *); - -typedef void (*btf_trace_xhci_free_virt_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_alloc_virt_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_setup_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_setup_addressable_virt_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_stop_device)(void *, struct xhci_virt_device *); - -typedef void (*btf_trace_xhci_urb_enqueue)(void *, struct urb *); - -typedef void (*btf_trace_xhci_urb_giveback)(void *, struct urb *); - -typedef void (*btf_trace_xhci_urb_dequeue)(void *, struct urb *); - -typedef void (*btf_trace_xhci_handle_cmd_stop_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_set_deq_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_reset_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_config_ep)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_add_endpoint)(void *, struct xhci_ep_ctx *); - -typedef void (*btf_trace_xhci_alloc_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_free_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_disable_slot)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_discover_or_reset_device)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_setup_device_slot)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_addr_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_reset_dev)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_handle_cmd_set_deq)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_configure_endpoint)(void *, struct xhci_slot_ctx *); - -typedef void (*btf_trace_xhci_address_ctrl_ctx)(void *, struct xhci_input_control_ctx *); - -typedef void (*btf_trace_xhci_configure_endpoint_ctrl_ctx)(void *, struct xhci_input_control_ctx *); - -typedef void (*btf_trace_xhci_ring_alloc)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_ring_free)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_ring_expansion)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_inc_enq)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_inc_deq)(void *, struct xhci_ring *); - -typedef void (*btf_trace_xhci_handle_port_status)(void *, u32, u32); - -typedef void (*btf_trace_xhci_get_port_status)(void *, u32, u32); - -typedef void (*btf_trace_xhci_hub_status_data)(void *, u32, u32); - -typedef void (*btf_trace_xhci_ring_ep_doorbell)(void *, u32, u32); - -typedef void (*btf_trace_xhci_ring_host_doorbell)(void *, u32, u32); - -typedef void (*btf_trace_xhci_dbc_alloc_request)(void *, struct dbc_request *); - -typedef void (*btf_trace_xhci_dbc_free_request)(void *, struct dbc_request *); - -typedef void (*btf_trace_xhci_dbc_queue_request)(void *, struct dbc_request *); - -typedef void (*btf_trace_xhci_dbc_giveback_request)(void *, struct dbc_request *); - -struct xhci_regset { - char name[32]; - struct debugfs_regset32 regset; - size_t nregs; - struct list_head list; -}; - -struct xhci_file_map { - const char *name; - int (*show)(struct seq_file *, void *); -}; - -struct xhci_ep_priv { - char name[32]; - struct dentry *root; - struct xhci_stream_info *stream_info; - struct xhci_ring *show_ring; - unsigned int stream_id; -}; - -struct xhci_slot_priv { - char name[32]; - struct dentry *root; - struct xhci_ep_priv *eps[31]; - struct xhci_virt_device *dev; -}; - -struct async_icount { - __u32 cts; - __u32 dsr; - __u32 rng; - __u32 dcd; - __u32 tx; - __u32 rx; - __u32 frame; - __u32 parity; - __u32 overrun; - __u32 brk; - __u32 buf_overrun; -}; - -struct kfifo { - union { - struct __kfifo kfifo; - unsigned char *type; - const unsigned char *const_type; - char (*rectype)[0]; - void *ptr; - const void *ptr_const; - }; - unsigned char buf[0]; -}; - -struct usb_serial; - -struct usb_serial_port { - struct usb_serial *serial; - struct tty_port port; - spinlock_t lock; - u32 minor; - u8 port_number; - unsigned char *interrupt_in_buffer; - struct urb *interrupt_in_urb; - __u8 interrupt_in_endpointAddress; - unsigned char *interrupt_out_buffer; - int interrupt_out_size; - struct urb *interrupt_out_urb; - __u8 interrupt_out_endpointAddress; - unsigned char *bulk_in_buffer; - int bulk_in_size; - struct urb *read_urb; - __u8 bulk_in_endpointAddress; - unsigned char *bulk_in_buffers[2]; - struct urb *read_urbs[2]; - long unsigned int read_urbs_free; - unsigned char *bulk_out_buffer; - int bulk_out_size; - struct urb *write_urb; - struct kfifo write_fifo; - unsigned char *bulk_out_buffers[2]; - struct urb *write_urbs[2]; - long unsigned int write_urbs_free; - __u8 bulk_out_endpointAddress; - struct async_icount icount; - int tx_bytes; - long unsigned int flags; - struct work_struct work; - long unsigned int sysrq; - struct device dev; -}; - -struct usb_serial_driver; - -struct usb_serial { - struct usb_device *dev; - struct usb_serial_driver *type; - struct usb_interface *interface; - struct usb_interface *sibling; - unsigned int suspend_count; - unsigned char disconnected: 1; - unsigned char attached: 1; - unsigned char minors_reserved: 1; - unsigned char num_ports; - unsigned char num_port_pointers; - unsigned char num_interrupt_in; - unsigned char num_interrupt_out; - unsigned char num_bulk_in; - unsigned char num_bulk_out; - struct usb_serial_port *port[16]; - struct kref kref; - struct mutex disc_mutex; - void *private; -}; - -struct usb_serial_endpoints; - -struct usb_serial_driver { - const char *description; - const struct usb_device_id *id_table; - struct list_head driver_list; - struct device_driver driver; - struct usb_driver *usb_driver; - struct usb_dynids dynids; - unsigned char num_ports; - unsigned char num_bulk_in; - unsigned char num_bulk_out; - unsigned char num_interrupt_in; - unsigned char num_interrupt_out; - size_t bulk_in_size; - size_t bulk_out_size; - int (*probe)(struct usb_serial *, const struct usb_device_id *); - int (*attach)(struct usb_serial *); - int (*calc_num_ports)(struct usb_serial *, struct usb_serial_endpoints *); - void (*disconnect)(struct usb_serial *); - void (*release)(struct usb_serial *); - int (*port_probe)(struct usb_serial_port *); - void (*port_remove)(struct usb_serial_port *); - int (*suspend)(struct usb_serial *, pm_message_t); - int (*resume)(struct usb_serial *); - int (*reset_resume)(struct usb_serial *); - int (*open)(struct tty_struct *, struct usb_serial_port *); - void (*close)(struct usb_serial_port *); - int (*write)(struct tty_struct *, struct usb_serial_port *, const unsigned char *, int); - unsigned int (*write_room)(struct tty_struct *); - int (*ioctl)(struct tty_struct *, unsigned int, long unsigned int); - void (*get_serial)(struct tty_struct *, struct serial_struct *); - int (*set_serial)(struct tty_struct *, struct serial_struct *); - void (*set_termios)(struct tty_struct *, struct usb_serial_port *, struct ktermios *); - void (*break_ctl)(struct tty_struct *, int); - unsigned int (*chars_in_buffer)(struct tty_struct *); - void (*wait_until_sent)(struct tty_struct *, long int); - bool (*tx_empty)(struct usb_serial_port *); - void (*throttle)(struct tty_struct *); - void (*unthrottle)(struct tty_struct *); - int (*tiocmget)(struct tty_struct *); - int (*tiocmset)(struct tty_struct *, unsigned int, unsigned int); - int (*tiocmiwait)(struct tty_struct *, long unsigned int); - int (*get_icount)(struct tty_struct *, struct serial_icounter_struct *); - void (*dtr_rts)(struct usb_serial_port *, int); - int (*carrier_raised)(struct usb_serial_port *); - void (*init_termios)(struct tty_struct *); - void (*read_int_callback)(struct urb *); - void (*write_int_callback)(struct urb *); - void (*read_bulk_callback)(struct urb *); - void (*write_bulk_callback)(struct urb *); - void (*process_read_urb)(struct urb *); - int (*prepare_write_buffer)(struct usb_serial_port *, void *, size_t); -}; - -struct usb_serial_endpoints { - unsigned char num_bulk_in; - unsigned char num_bulk_out; - unsigned char num_interrupt_in; - unsigned char num_interrupt_out; - struct usb_endpoint_descriptor *bulk_in[16]; - struct usb_endpoint_descriptor *bulk_out[16]; - struct usb_endpoint_descriptor *interrupt_in[16]; - struct usb_endpoint_descriptor *interrupt_out[16]; -}; - -struct usbcons_info { - int magic; - int break_flag; - struct usb_serial_port *port; -}; - -struct usb_debug_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDebugInEndpoint; - __u8 bDebugOutEndpoint; -}; - -struct ehci_dev { - u32 bus; - u32 slot; - u32 func; -}; - -typedef void (*set_debug_port_t)(int); - -struct usb_hcd___2; - -struct usb_string_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 wData[1]; -}; - -struct xdbc_regs { - __le32 capability; - __le32 doorbell; - __le32 ersts; - __le32 __reserved_0; - __le64 erstba; - __le64 erdp; - __le32 control; - __le32 status; - __le32 portsc; - __le32 __reserved_1; - __le64 dccp; - __le32 devinfo1; - __le32 devinfo2; -}; - -struct xdbc_trb { - __le32 field[4]; -}; - -struct xdbc_erst_entry { - __le64 seg_addr; - __le32 seg_size; - __le32 __reserved_0; -}; - -struct xdbc_info_context { - __le64 string0; - __le64 manufacturer; - __le64 product; - __le64 serial; - __le32 length; - __le32 __reserved_0[7]; -}; - -struct xdbc_ep_context { - __le32 ep_info1; - __le32 ep_info2; - __le64 deq; - __le32 tx_info; - __le32 __reserved_0[11]; -}; - -struct xdbc_context { - struct xdbc_info_context info; - struct xdbc_ep_context out; - struct xdbc_ep_context in; -}; - -struct xdbc_strings { - char string0[64]; - char manufacturer[64]; - char product[64]; - char serial[64]; -}; - -struct xdbc_segment { - struct xdbc_trb *trbs; - dma_addr_t dma; -}; - -struct xdbc_ring { - struct xdbc_segment *segment; - struct xdbc_trb *enqueue; - struct xdbc_trb *dequeue; - u32 cycle_state; -}; - -struct xdbc_state { - u16 vendor; - u16 device; - u32 bus; - u32 dev; - u32 func; - void *xhci_base; - u64 xhci_start; - size_t xhci_length; - int port_number; - struct xdbc_regs *xdbc_reg; - dma_addr_t table_dma; - void *table_base; - dma_addr_t erst_dma; - size_t erst_size; - void *erst_base; - struct xdbc_ring evt_ring; - struct xdbc_segment evt_seg; - dma_addr_t dbcc_dma; - size_t dbcc_size; - void *dbcc_base; - dma_addr_t string_dma; - size_t string_size; - void *string_base; - struct xdbc_ring out_ring; - struct xdbc_segment out_seg; - void *out_buf; - dma_addr_t out_dma; - struct xdbc_ring in_ring; - struct xdbc_segment in_seg; - void *in_buf; - dma_addr_t in_dma; - u32 flags; - raw_spinlock_t lock; -}; - -struct input_mt_slot { - int abs[14]; - unsigned int frame; - unsigned int key; -}; - -struct input_mt { - int trkid; - int num_slots; - int slot; - unsigned int flags; - unsigned int frame; - int *red; - struct input_mt_slot slots[0]; -}; - -union input_seq_state { - struct { - short unsigned int pos; - bool mutex_acquired; - }; - void *p; -}; - -struct input_devres { - struct input_dev *input; -}; - -struct input_event { - __kernel_ulong_t __sec; - __kernel_ulong_t __usec; - __u16 type; - __u16 code; - __s32 value; -}; - -struct input_event_compat { - compat_ulong_t sec; - compat_ulong_t usec; - __u16 type; - __u16 code; - __s32 value; -}; - -struct ff_periodic_effect_compat { - __u16 waveform; - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; - struct ff_envelope envelope; - __u32 custom_len; - compat_uptr_t custom_data; -}; - -struct ff_effect_compat { - __u16 type; - __s16 id; - __u16 direction; - struct ff_trigger trigger; - struct ff_replay replay; - union { - struct ff_constant_effect constant; - struct ff_ramp_effect ramp; - struct ff_periodic_effect_compat periodic; - struct ff_condition_effect condition[2]; - struct ff_rumble_effect rumble; - } u; -}; - -struct input_mt_pos { - s16 x; - s16 y; -}; - -struct input_dev_poller { - void (*poll)(struct input_dev *); - unsigned int poll_interval; - unsigned int poll_interval_max; - unsigned int poll_interval_min; - struct input_dev *input; - struct delayed_work work; -}; - -struct touchscreen_properties { - unsigned int max_x; - unsigned int max_y; - bool invert_x; - bool invert_y; - bool swap_x_y; -}; - -struct led_init_data { - struct fwnode_handle *fwnode; - const char *default_label; - const char *devicename; - bool devname_mandatory; -}; - -struct input_led { - struct led_classdev cdev; - struct input_handle *handle; - unsigned int code; -}; - -struct input_leds { - struct input_handle handle; - unsigned int num_leds; - struct input_led leds[0]; -}; - -struct input_mask { - __u32 type; - __u32 codes_size; - __u64 codes_ptr; -}; - -struct evdev_client; - -struct evdev { - int open; - struct input_handle handle; - struct evdev_client *grab; - struct list_head client_list; - spinlock_t client_lock; - struct mutex mutex; - struct device dev; - struct cdev cdev; - bool exist; -}; - -struct evdev_client { - unsigned int head; - unsigned int tail; - unsigned int packet_head; - spinlock_t buffer_lock; - wait_queue_head_t wait; - struct fasync_struct *fasync; - struct evdev *evdev; - struct list_head node; - enum input_clock_type clk_type; - bool revoked; - long unsigned int *evmasks[32]; - unsigned int bufsize; - struct input_event buffer[0]; -}; - -struct trace_event_raw_rtc_time_alarm_class { - struct trace_entry ent; - time64_t secs; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_irq_set_freq { - struct trace_entry ent; - int freq; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_irq_set_state { - struct trace_entry ent; - int enabled; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_alarm_irq_enable { - struct trace_entry ent; - unsigned int enabled; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_offset_class { - struct trace_entry ent; - long int offset; - int err; - char __data[0]; -}; - -struct trace_event_raw_rtc_timer_class { - struct trace_entry ent; - struct rtc_timer *timer; - ktime_t expires; - ktime_t period; - char __data[0]; -}; - -struct trace_event_data_offsets_rtc_time_alarm_class {}; - -struct trace_event_data_offsets_rtc_irq_set_freq {}; - -struct trace_event_data_offsets_rtc_irq_set_state {}; - -struct trace_event_data_offsets_rtc_alarm_irq_enable {}; - -struct trace_event_data_offsets_rtc_offset_class {}; - -struct trace_event_data_offsets_rtc_timer_class {}; - -typedef void (*btf_trace_rtc_set_time)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_read_time)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_set_alarm)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_read_alarm)(void *, time64_t, int); - -typedef void (*btf_trace_rtc_irq_set_freq)(void *, int, int); - -typedef void (*btf_trace_rtc_irq_set_state)(void *, int, int); - -typedef void (*btf_trace_rtc_alarm_irq_enable)(void *, unsigned int, int); - -typedef void (*btf_trace_rtc_set_offset)(void *, long int, int); - -typedef void (*btf_trace_rtc_read_offset)(void *, long int, int); - -typedef void (*btf_trace_rtc_timer_enqueue)(void *, struct rtc_timer *); - -typedef void (*btf_trace_rtc_timer_dequeue)(void *, struct rtc_timer *); - -typedef void (*btf_trace_rtc_timer_fired)(void *, struct rtc_timer *); - -enum { - none = 0, - day = 1, - month = 2, - year = 3, -}; - -struct nvmem_cell_info { - const char *name; - unsigned int offset; - unsigned int bytes; - unsigned int bit_offset; - unsigned int nbits; -}; - -typedef int (*nvmem_reg_read_t)(void *, unsigned int, void *, size_t); - -typedef int (*nvmem_reg_write_t)(void *, unsigned int, void *, size_t); - -enum nvmem_type { - NVMEM_TYPE_UNKNOWN = 0, - NVMEM_TYPE_EEPROM = 1, - NVMEM_TYPE_OTP = 2, - NVMEM_TYPE_BATTERY_BACKED = 3, - NVMEM_TYPE_FRAM = 4, -}; - -struct nvmem_keepout { - unsigned int start; - unsigned int end; - unsigned char value; -}; - -struct nvmem_config { - struct device *dev; - const char *name; - int id; - struct module *owner; - struct gpio_desc *wp_gpio; - const struct nvmem_cell_info *cells; - int ncells; - const struct nvmem_keepout *keepout; - unsigned int nkeepout; - enum nvmem_type type; - bool read_only; - bool root_only; - struct device_node *of_node; - bool no_of_node; - nvmem_reg_read_t reg_read; - nvmem_reg_write_t reg_write; - int size; - int word_size; - int stride; - void *priv; - bool compat; - struct device *base_dev; -}; - -struct nvmem_device; - -struct cmos_rtc_board_info { - void (*wake_on)(struct device *); - void (*wake_off)(struct device *); - u32 flags; - int address_space; - u8 rtc_day_alarm; - u8 rtc_mon_alarm; - u8 rtc_century; -}; - -struct cmos_rtc { - struct rtc_device *rtc; - struct device *dev; - int irq; - struct resource *iomem; - time64_t alarm_expires; - void (*wake_on)(struct device *); - void (*wake_off)(struct device *); - u8 enabled_wake; - u8 suspend_ctrl; - u8 day_alrm; - u8 mon_alrm; - u8 century; - struct rtc_wkalrm saved_wkalrm; -}; - -struct i2c_devinfo { - struct list_head list; - int busnum; - struct i2c_board_info board_info; -}; - -struct i2c_device_identity { - u16 manufacturer_id; - u16 part_id; - u8 die_revision; -}; - -struct i2c_timings { - u32 bus_freq_hz; - u32 scl_rise_ns; - u32 scl_fall_ns; - u32 scl_int_delay_ns; - u32 sda_fall_ns; - u32 sda_hold_ns; - u32 digital_filter_width_ns; - u32 analog_filter_cutoff_freq_hz; -}; - -struct trace_event_raw_i2c_write { - struct trace_entry ent; - int adapter_nr; - __u16 msg_nr; - __u16 addr; - __u16 flags; - __u16 len; - u32 __data_loc_buf; - char __data[0]; -}; - -struct trace_event_raw_i2c_read { - struct trace_entry ent; - int adapter_nr; - __u16 msg_nr; - __u16 addr; - __u16 flags; - __u16 len; - char __data[0]; -}; - -struct trace_event_raw_i2c_reply { - struct trace_entry ent; - int adapter_nr; - __u16 msg_nr; - __u16 addr; - __u16 flags; - __u16 len; - u32 __data_loc_buf; - char __data[0]; -}; - -struct trace_event_raw_i2c_result { - struct trace_entry ent; - int adapter_nr; - __u16 nr_msgs; - __s16 ret; - char __data[0]; -}; - -struct trace_event_data_offsets_i2c_write { - u32 buf; -}; - -struct trace_event_data_offsets_i2c_read {}; - -struct trace_event_data_offsets_i2c_reply { - u32 buf; -}; - -struct trace_event_data_offsets_i2c_result {}; - -typedef void (*btf_trace_i2c_write)(void *, const struct i2c_adapter *, const struct i2c_msg *, int); - -typedef void (*btf_trace_i2c_read)(void *, const struct i2c_adapter *, const struct i2c_msg *, int); - -typedef void (*btf_trace_i2c_reply)(void *, const struct i2c_adapter *, const struct i2c_msg *, int); - -typedef void (*btf_trace_i2c_result)(void *, const struct i2c_adapter *, int, int); - -struct class_compat___2; - -struct i2c_cmd_arg { - unsigned int cmd; - void *arg; -}; - -struct i2c_smbus_alert_setup { - int irq; -}; - -struct trace_event_raw_smbus_write { - struct trace_entry ent; - int adapter_nr; - __u16 addr; - __u16 flags; - __u8 command; - __u8 len; - __u32 protocol; - __u8 buf[34]; - char __data[0]; -}; - -struct trace_event_raw_smbus_read { - struct trace_entry ent; - int adapter_nr; - __u16 flags; - __u16 addr; - __u8 command; - __u32 protocol; - __u8 buf[34]; - char __data[0]; -}; - -struct trace_event_raw_smbus_reply { - struct trace_entry ent; - int adapter_nr; - __u16 addr; - __u16 flags; - __u8 command; - __u8 len; - __u32 protocol; - __u8 buf[34]; - char __data[0]; -}; - -struct trace_event_raw_smbus_result { - struct trace_entry ent; - int adapter_nr; - __u16 addr; - __u16 flags; - __u8 read_write; - __u8 command; - __s16 res; - __u32 protocol; - char __data[0]; -}; - -struct trace_event_data_offsets_smbus_write {}; - -struct trace_event_data_offsets_smbus_read {}; - -struct trace_event_data_offsets_smbus_reply {}; - -struct trace_event_data_offsets_smbus_result {}; - -typedef void (*btf_trace_smbus_write)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, const union i2c_smbus_data *); - -typedef void (*btf_trace_smbus_read)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int); - -typedef void (*btf_trace_smbus_reply)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, const union i2c_smbus_data *, int); - -typedef void (*btf_trace_smbus_result)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, int); - -struct i2c_acpi_handler_data { - struct acpi_connection_info info; - struct i2c_adapter *adapter; -}; - -struct gsb_buffer { - u8 status; - u8 len; - union { - u16 wdata; - u8 bdata; - u8 data[0]; - }; -}; - -struct i2c_acpi_lookup { - struct i2c_board_info *info; - acpi_handle adapter_handle; - acpi_handle device_handle; - acpi_handle search_handle; - int n; - int index; - u32 speed; - u32 min_speed; - u32 force_speed; -}; - -struct dw_i2c_dev { - struct device *dev; - struct regmap *map; - struct regmap *sysmap; - void *base; - void *ext; - struct completion cmd_complete; - struct clk *clk; - struct clk *pclk; - struct reset_control *rst; - struct i2c_client *slave; - u32 (*get_clk_rate_khz)(struct dw_i2c_dev *); - int cmd_err; - struct i2c_msg *msgs; - int msgs_num; - int msg_write_idx; - u32 tx_buf_len; - u8 *tx_buf; - int msg_read_idx; - u32 rx_buf_len; - u8 *rx_buf; - int msg_err; - unsigned int status; - u32 abort_source; - int irq; - u32 flags; - struct i2c_adapter adapter; - u32 functionality; - u32 master_cfg; - u32 slave_cfg; - unsigned int tx_fifo_depth; - unsigned int rx_fifo_depth; - int rx_outstanding; - struct i2c_timings timings; - u32 sda_hold_time; - u16 ss_hcnt; - u16 ss_lcnt; - u16 fs_hcnt; - u16 fs_lcnt; - u16 fp_hcnt; - u16 fp_lcnt; - u16 hs_hcnt; - u16 hs_lcnt; - int (*acquire_lock)(); - void (*release_lock)(); - bool shared_with_punit; - void (*disable)(struct dw_i2c_dev *); - void (*disable_int)(struct dw_i2c_dev *); - int (*init)(struct dw_i2c_dev *); - int (*set_sda_hold_time)(struct dw_i2c_dev *); - int mode; - struct i2c_bus_recovery_info rinfo; - bool suspended; -}; - -enum dw_pci_ctl_id_t { - medfield = 0, - merrifield = 1, - baytrail = 2, - cherrytrail = 3, - haswell = 4, - elkhartlake = 5, - navi_amd = 6, -}; - -struct dw_scl_sda_cfg { - u32 ss_hcnt; - u32 fs_hcnt; - u32 ss_lcnt; - u32 fs_lcnt; - u32 sda_hold; -}; - -struct dw_pci_controller { - u32 bus_num; - u32 flags; - struct dw_scl_sda_cfg *scl_sda_cfg; - int (*setup)(struct pci_dev *, struct dw_pci_controller *); - u32 (*get_clk_rate_khz)(struct dw_i2c_dev *); -}; - -struct lirc_scancode { - __u64 timestamp; - __u16 flags; - __u16 rc_proto; - __u32 keycode; - __u64 scancode; -}; - -enum rc_proto { - RC_PROTO_UNKNOWN = 0, - RC_PROTO_OTHER = 1, - RC_PROTO_RC5 = 2, - RC_PROTO_RC5X_20 = 3, - RC_PROTO_RC5_SZ = 4, - RC_PROTO_JVC = 5, - RC_PROTO_SONY12 = 6, - RC_PROTO_SONY15 = 7, - RC_PROTO_SONY20 = 8, - RC_PROTO_NEC = 9, - RC_PROTO_NECX = 10, - RC_PROTO_NEC32 = 11, - RC_PROTO_SANYO = 12, - RC_PROTO_MCIR2_KBD = 13, - RC_PROTO_MCIR2_MSE = 14, - RC_PROTO_RC6_0 = 15, - RC_PROTO_RC6_6A_20 = 16, - RC_PROTO_RC6_6A_24 = 17, - RC_PROTO_RC6_6A_32 = 18, - RC_PROTO_RC6_MCE = 19, - RC_PROTO_SHARP = 20, - RC_PROTO_XMP = 21, - RC_PROTO_CEC = 22, - RC_PROTO_IMON = 23, - RC_PROTO_RCMM12 = 24, - RC_PROTO_RCMM24 = 25, - RC_PROTO_RCMM32 = 26, - RC_PROTO_XBOX_DVD = 27, - RC_PROTO_MAX = 27, -}; - -struct rc_map_table { - u64 scancode; - u32 keycode; -}; - -struct rc_map { - struct rc_map_table *scan; - unsigned int size; - unsigned int len; - unsigned int alloc; - enum rc_proto rc_proto; - const char *name; - spinlock_t lock; -}; - -struct rc_map_list { - struct list_head list; - struct rc_map map; -}; - -enum rc_driver_type { - RC_DRIVER_SCANCODE = 0, - RC_DRIVER_IR_RAW = 1, - RC_DRIVER_IR_RAW_TX = 2, -}; - -struct rc_scancode_filter { - u32 data; - u32 mask; -}; - -enum rc_filter_type { - RC_FILTER_NORMAL = 0, - RC_FILTER_WAKEUP = 1, - RC_FILTER_MAX = 2, -}; - -struct ir_raw_event_ctrl; - -struct rc_dev { - struct device dev; - bool managed_alloc; - const struct attribute_group *sysfs_groups[5]; - const char *device_name; - const char *input_phys; - struct input_id input_id; - const char *driver_name; - const char *map_name; - struct rc_map rc_map; - struct mutex lock; - unsigned int minor; - struct ir_raw_event_ctrl *raw; - struct input_dev *input_dev; - enum rc_driver_type driver_type; - bool idle; - bool encode_wakeup; - u64 allowed_protocols; - u64 enabled_protocols; - u64 allowed_wakeup_protocols; - enum rc_proto wakeup_protocol; - struct rc_scancode_filter scancode_filter; - struct rc_scancode_filter scancode_wakeup_filter; - u32 scancode_mask; - u32 users; - void *priv; - spinlock_t keylock; - bool keypressed; - long unsigned int keyup_jiffies; - struct timer_list timer_keyup; - struct timer_list timer_repeat; - u32 last_keycode; - enum rc_proto last_protocol; - u64 last_scancode; - u8 last_toggle; - u32 timeout; - u32 min_timeout; - u32 max_timeout; - u32 rx_resolution; - u32 tx_resolution; - struct device lirc_dev; - struct cdev lirc_cdev; - ktime_t gap_start; - u64 gap_duration; - bool gap; - spinlock_t lirc_fh_lock; - struct list_head lirc_fh; - bool registered; - int (*change_protocol)(struct rc_dev *, u64 *); - int (*open)(struct rc_dev *); - void (*close)(struct rc_dev *); - int (*s_tx_mask)(struct rc_dev *, u32); - int (*s_tx_carrier)(struct rc_dev *, u32); - int (*s_tx_duty_cycle)(struct rc_dev *, u32); - int (*s_rx_carrier_range)(struct rc_dev *, u32, u32); - int (*tx_ir)(struct rc_dev *, unsigned int *, unsigned int); - void (*s_idle)(struct rc_dev *, bool); - int (*s_learning_mode)(struct rc_dev *, int); - int (*s_carrier_report)(struct rc_dev *, int); - int (*s_filter)(struct rc_dev *, struct rc_scancode_filter *); - int (*s_wakeup_filter)(struct rc_dev *, struct rc_scancode_filter *); - int (*s_timeout)(struct rc_dev *, unsigned int); -}; - -struct ir_raw_event { - union { - u32 duration; - u32 carrier; - }; - u8 duty_cycle; - unsigned int pulse: 1; - unsigned int reset: 1; - unsigned int timeout: 1; - unsigned int carrier_report: 1; -}; - -struct nec_dec { - int state; - unsigned int count; - u32 bits; - bool is_nec_x; - bool necx_repeat; -}; - -struct rc5_dec { - int state; - u32 bits; - unsigned int count; - bool is_rc5x; -}; - -struct rc6_dec { - int state; - u8 header; - u32 body; - bool toggle; - unsigned int count; - unsigned int wanted_bits; -}; - -struct sony_dec { - int state; - u32 bits; - unsigned int count; -}; - -struct jvc_dec { - int state; - u16 bits; - u16 old_bits; - unsigned int count; - bool first; - bool toggle; -}; - -struct sanyo_dec { - int state; - unsigned int count; - u64 bits; -}; - -struct sharp_dec { - int state; - unsigned int count; - u32 bits; - unsigned int pulse_len; -}; - -struct mce_kbd_dec { - spinlock_t keylock; - struct timer_list rx_timeout; - int state; - u8 header; - u32 body; - unsigned int count; - unsigned int wanted_bits; -}; - -struct xmp_dec { - int state; - unsigned int count; - u32 durations[16]; -}; - -struct imon_dec { - int state; - int count; - int last_chk; - unsigned int bits; - bool stick_keyboard; -}; - -struct rcmm_dec { - int state; - unsigned int count; - u32 bits; -}; - -struct ir_raw_event_ctrl { - struct list_head list; - struct task_struct *thread; - struct { - union { - struct __kfifo kfifo; - struct ir_raw_event *type; - const struct ir_raw_event *const_type; - char (*rectype)[0]; - struct ir_raw_event *ptr; - const struct ir_raw_event *ptr_const; - }; - struct ir_raw_event buf[512]; - } kfifo; - ktime_t last_event; - struct rc_dev *dev; - spinlock_t edge_spinlock; - struct timer_list edge_handle; - struct ir_raw_event prev_ev; - struct ir_raw_event this_ev; - u32 bpf_sample; - struct bpf_prog_array *progs; - struct nec_dec nec; - struct rc5_dec rc5; - struct rc6_dec rc6; - struct sony_dec sony; - struct jvc_dec jvc; - struct sanyo_dec sanyo; - struct sharp_dec sharp; - struct mce_kbd_dec mce_kbd; - struct xmp_dec xmp; - struct imon_dec imon; - struct rcmm_dec rcmm; -}; - -struct rc_filter_attribute { - struct device_attribute attr; - enum rc_filter_type type; - bool mask; -}; - -struct ir_raw_handler { - struct list_head list; - u64 protocols; - int (*decode)(struct rc_dev *, struct ir_raw_event); - int (*encode)(enum rc_proto, u32, struct ir_raw_event *, unsigned int); - u32 carrier; - u32 min_timeout; - int (*raw_register)(struct rc_dev *); - int (*raw_unregister)(struct rc_dev *); -}; - -struct ir_raw_timings_manchester { - unsigned int leader_pulse; - unsigned int leader_space; - unsigned int clock; - unsigned int invert: 1; - unsigned int trailer_space; -}; - -struct ir_raw_timings_pd { - unsigned int header_pulse; - unsigned int header_space; - unsigned int bit_pulse; - unsigned int bit_space[2]; - unsigned int trailer_pulse; - unsigned int trailer_space; - unsigned int msb_first: 1; -}; - -struct ir_raw_timings_pl { - unsigned int header_pulse; - unsigned int bit_space; - unsigned int bit_pulse[2]; - unsigned int trailer_space; - unsigned int msb_first: 1; -}; - -struct lirc_fh { - struct list_head list; - struct rc_dev *rc; - int carrier_low; - bool send_timeout_reports; - struct { - union { - struct __kfifo kfifo; - unsigned int *type; - const unsigned int *const_type; - char (*rectype)[0]; - unsigned int *ptr; - const unsigned int *ptr_const; - }; - unsigned int buf[0]; - } rawir; - struct { - union { - struct __kfifo kfifo; - struct lirc_scancode *type; - const struct lirc_scancode *const_type; - char (*rectype)[0]; - struct lirc_scancode *ptr; - const struct lirc_scancode *ptr_const; - }; - struct lirc_scancode buf[0]; - } scancodes; - wait_queue_head_t wait_poll; - u8 send_mode; - u8 rec_mode; -}; - -typedef u64 (*btf_bpf_rc_repeat)(u32 *); - -typedef u64 (*btf_bpf_rc_keydown)(u32 *, u32, u64, u32); - -typedef u64 (*btf_bpf_rc_pointer_rel)(u32 *, s32, s32); - -struct pps_ktime { - __s64 sec; - __s32 nsec; - __u32 flags; -}; - -struct pps_ktime_compat { - __s64 sec; - __s32 nsec; - __u32 flags; -}; - -struct pps_kinfo { - __u32 assert_sequence; - __u32 clear_sequence; - struct pps_ktime assert_tu; - struct pps_ktime clear_tu; - int current_mode; -}; - -struct pps_kinfo_compat { - __u32 assert_sequence; - __u32 clear_sequence; - struct pps_ktime_compat assert_tu; - struct pps_ktime_compat clear_tu; - int current_mode; -} __attribute__((packed)); - -struct pps_kparams { - int api_version; - int mode; - struct pps_ktime assert_off_tu; - struct pps_ktime clear_off_tu; -}; - -struct pps_fdata { - struct pps_kinfo info; - struct pps_ktime timeout; -}; - -struct pps_fdata_compat { - struct pps_kinfo_compat info; - struct pps_ktime_compat timeout; -} __attribute__((packed)); - -struct pps_bind_args { - int tsformat; - int edge; - int consumer; -}; - -struct pps_device; - -struct pps_source_info { - char name[32]; - char path[32]; - int mode; - void (*echo)(struct pps_device *, int, void *); - struct module *owner; - struct device *dev; -}; - -struct pps_device { - struct pps_source_info info; - struct pps_kparams params; - __u32 assert_sequence; - __u32 clear_sequence; - struct pps_ktime assert_tu; - struct pps_ktime clear_tu; - int current_mode; - unsigned int last_ev; - wait_queue_head_t queue; - unsigned int id; - const void *lookup_cookie; - struct cdev cdev; - struct device *dev; - struct fasync_struct *async_queue; - spinlock_t lock; -}; - -struct pps_event_time { - struct timespec64 ts_real; -}; - -struct ptp_clock_time { - __s64 sec; - __u32 nsec; - __u32 reserved; -}; - -struct ptp_extts_request { - unsigned int index; - unsigned int flags; - unsigned int rsv[2]; -}; - -struct ptp_perout_request { - union { - struct ptp_clock_time start; - struct ptp_clock_time phase; - }; - struct ptp_clock_time period; - unsigned int index; - unsigned int flags; - union { - struct ptp_clock_time on; - unsigned int rsv[4]; - }; -}; - -enum ptp_pin_function { - PTP_PF_NONE = 0, - PTP_PF_EXTTS = 1, - PTP_PF_PEROUT = 2, - PTP_PF_PHYSYNC = 3, -}; - -struct ptp_pin_desc { - char name[64]; - unsigned int index; - unsigned int func; - unsigned int chan; - unsigned int rsv[5]; -}; - -struct ptp_extts_event { - struct ptp_clock_time t; - unsigned int index; - unsigned int flags; - unsigned int rsv[2]; -}; - -struct ptp_clock_request { - enum { - PTP_CLK_REQ_EXTTS = 0, - PTP_CLK_REQ_PEROUT = 1, - PTP_CLK_REQ_PPS = 2, - } type; - union { - struct ptp_extts_request extts; - struct ptp_perout_request perout; - }; -}; - -struct ptp_clock_info { - struct module *owner; - char name[32]; - s32 max_adj; - int n_alarm; - int n_ext_ts; - int n_per_out; - int n_pins; - int pps; - struct ptp_pin_desc *pin_config; - int (*adjfine)(struct ptp_clock_info *, long int); - int (*adjfreq)(struct ptp_clock_info *, s32); - int (*adjphase)(struct ptp_clock_info *, s32); - int (*adjtime)(struct ptp_clock_info *, s64); - int (*gettime64)(struct ptp_clock_info *, struct timespec64 *); - int (*gettimex64)(struct ptp_clock_info *, struct timespec64 *, struct ptp_system_timestamp *); - int (*getcrosststamp)(struct ptp_clock_info *, struct system_device_crosststamp *); - int (*settime64)(struct ptp_clock_info *, const struct timespec64 *); - int (*enable)(struct ptp_clock_info *, struct ptp_clock_request *, int); - int (*verify)(struct ptp_clock_info *, unsigned int, enum ptp_pin_function, unsigned int); - long int (*do_aux_work)(struct ptp_clock_info *); -}; - -enum ptp_clock_events { - PTP_CLOCK_ALARM = 0, - PTP_CLOCK_EXTTS = 1, - PTP_CLOCK_PPS = 2, - PTP_CLOCK_PPSUSR = 3, -}; - -struct ptp_clock_event { - int type; - int index; - union { - u64 timestamp; - struct pps_event_time pps_times; - }; -}; - -struct timestamp_event_queue { - struct ptp_extts_event buf[128]; - int head; - int tail; - spinlock_t lock; -}; - -struct ptp_clock { - struct posix_clock clock; - struct device dev; - struct ptp_clock_info *info; - dev_t devid; - int index; - struct pps_device *pps_source; - long int dialed_frequency; - struct timestamp_event_queue tsevq; - struct mutex tsevq_mux; - struct mutex pincfg_mux; - wait_queue_head_t tsev_wq; - int defunct; - struct device_attribute *pin_dev_attr; - struct attribute **pin_attr; - struct attribute_group pin_attr_group; - const struct attribute_group *pin_attr_groups[2]; - struct kthread_worker *kworker; - struct kthread_delayed_work aux_work; - unsigned int max_vclocks; - unsigned int n_vclocks; - int *vclock_index; - struct mutex n_vclocks_mux; - bool is_virtual_clock; -}; - -struct ptp_clock_caps { - int max_adj; - int n_alarm; - int n_ext_ts; - int n_per_out; - int pps; - int n_pins; - int cross_timestamping; - int adjust_phase; - int rsv[12]; -}; - -struct ptp_sys_offset { - unsigned int n_samples; - unsigned int rsv[3]; - struct ptp_clock_time ts[51]; -}; - -struct ptp_sys_offset_extended { - unsigned int n_samples; - unsigned int rsv[3]; - struct ptp_clock_time ts[75]; -}; - -struct ptp_sys_offset_precise { - struct ptp_clock_time device; - struct ptp_clock_time sys_realtime; - struct ptp_clock_time sys_monoraw; - unsigned int rsv[4]; -}; - -struct ptp_vclock { - struct ptp_clock *pclock; - struct ptp_clock_info info; - struct ptp_clock *clock; - struct cyclecounter cc; - struct timecounter tc; - spinlock_t lock; -}; - -struct mt6397_chip { - struct device *dev; - struct regmap *regmap; - struct notifier_block pm_nb; - int irq; - struct irq_domain *irq_domain; - struct mutex irqlock; - u16 wake_mask[2]; - u16 irq_masks_cur[2]; - u16 irq_masks_cache[2]; - u16 int_con[2]; - u16 int_status[2]; - u16 chip_id; - void *irq_data; -}; - -struct mt6323_pwrc { - struct device *dev; - struct regmap *regmap; - u32 base; -}; - -enum power_supply_notifier_events { - PSY_EVENT_PROP_CHANGED = 0, -}; - -struct power_supply_battery_ocv_table { - int ocv; - int capacity; -}; - -struct power_supply_resistance_temp_table { - int temp; - int resistance; -}; - -struct power_supply_battery_info { - int energy_full_design_uwh; - int charge_full_design_uah; - int voltage_min_design_uv; - int voltage_max_design_uv; - int tricklecharge_current_ua; - int precharge_current_ua; - int precharge_voltage_max_uv; - int charge_term_current_ua; - int charge_restart_voltage_uv; - int overvoltage_limit_uv; - int constant_charge_current_max_ua; - int constant_charge_voltage_max_uv; - int factory_internal_resistance_uohm; - int ocv_temp[20]; - int temp_ambient_alert_min; - int temp_ambient_alert_max; - int temp_alert_min; - int temp_alert_max; - int temp_min; - int temp_max; - struct power_supply_battery_ocv_table *ocv_table[20]; - int ocv_table_size[20]; - struct power_supply_resistance_temp_table *resist_table; - int resist_table_size; -}; - -struct psy_am_i_supplied_data { - struct power_supply *psy; - unsigned int count; -}; - -enum { - POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0, - POWER_SUPPLY_CHARGE_TYPE_NONE = 1, - POWER_SUPPLY_CHARGE_TYPE_TRICKLE = 2, - POWER_SUPPLY_CHARGE_TYPE_FAST = 3, - POWER_SUPPLY_CHARGE_TYPE_STANDARD = 4, - POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE = 5, - POWER_SUPPLY_CHARGE_TYPE_CUSTOM = 6, - POWER_SUPPLY_CHARGE_TYPE_LONGLIFE = 7, -}; - -enum { - POWER_SUPPLY_HEALTH_UNKNOWN = 0, - POWER_SUPPLY_HEALTH_GOOD = 1, - POWER_SUPPLY_HEALTH_OVERHEAT = 2, - POWER_SUPPLY_HEALTH_DEAD = 3, - POWER_SUPPLY_HEALTH_OVERVOLTAGE = 4, - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5, - POWER_SUPPLY_HEALTH_COLD = 6, - POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7, - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8, - POWER_SUPPLY_HEALTH_OVERCURRENT = 9, - POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED = 10, - POWER_SUPPLY_HEALTH_WARM = 11, - POWER_SUPPLY_HEALTH_COOL = 12, - POWER_SUPPLY_HEALTH_HOT = 13, -}; - -enum { - POWER_SUPPLY_SCOPE_UNKNOWN = 0, - POWER_SUPPLY_SCOPE_SYSTEM = 1, - POWER_SUPPLY_SCOPE_DEVICE = 2, -}; - -struct power_supply_attr { - const char *prop_name; - char attr_name[31]; - struct device_attribute dev_attr; - const char * const *text_values; - int text_values_len; -}; - -enum hwmon_in_attributes { - hwmon_in_enable = 0, - hwmon_in_input = 1, - hwmon_in_min = 2, - hwmon_in_max = 3, - hwmon_in_lcrit = 4, - hwmon_in_crit = 5, - hwmon_in_average = 6, - hwmon_in_lowest = 7, - hwmon_in_highest = 8, - hwmon_in_reset_history = 9, - hwmon_in_label = 10, - hwmon_in_alarm = 11, - hwmon_in_min_alarm = 12, - hwmon_in_max_alarm = 13, - hwmon_in_lcrit_alarm = 14, - hwmon_in_crit_alarm = 15, - hwmon_in_rated_min = 16, - hwmon_in_rated_max = 17, -}; - -enum hwmon_curr_attributes { - hwmon_curr_enable = 0, - hwmon_curr_input = 1, - hwmon_curr_min = 2, - hwmon_curr_max = 3, - hwmon_curr_lcrit = 4, - hwmon_curr_crit = 5, - hwmon_curr_average = 6, - hwmon_curr_lowest = 7, - hwmon_curr_highest = 8, - hwmon_curr_reset_history = 9, - hwmon_curr_label = 10, - hwmon_curr_alarm = 11, - hwmon_curr_min_alarm = 12, - hwmon_curr_max_alarm = 13, - hwmon_curr_lcrit_alarm = 14, - hwmon_curr_crit_alarm = 15, - hwmon_curr_rated_min = 16, - hwmon_curr_rated_max = 17, -}; - -struct power_supply_hwmon { - struct power_supply *psy; - long unsigned int *props; -}; - -struct hwmon_type_attr_list { - const u32 *attrs; - size_t n_attrs; -}; - -enum cm_batt_temp { - CM_BATT_OK = 0, - CM_BATT_OVERHEAT = 1, - CM_BATT_COLD = 2, -}; - -enum hwmon_power_attributes { - hwmon_power_enable = 0, - hwmon_power_average = 1, - hwmon_power_average_interval = 2, - hwmon_power_average_interval_max = 3, - hwmon_power_average_interval_min = 4, - hwmon_power_average_highest = 5, - hwmon_power_average_lowest = 6, - hwmon_power_average_max = 7, - hwmon_power_average_min = 8, - hwmon_power_input = 9, - hwmon_power_input_highest = 10, - hwmon_power_input_lowest = 11, - hwmon_power_reset_history = 12, - hwmon_power_accuracy = 13, - hwmon_power_cap = 14, - hwmon_power_cap_hyst = 15, - hwmon_power_cap_max = 16, - hwmon_power_cap_min = 17, - hwmon_power_min = 18, - hwmon_power_max = 19, - hwmon_power_crit = 20, - hwmon_power_lcrit = 21, - hwmon_power_label = 22, - hwmon_power_alarm = 23, - hwmon_power_cap_alarm = 24, - hwmon_power_min_alarm = 25, - hwmon_power_max_alarm = 26, - hwmon_power_lcrit_alarm = 27, - hwmon_power_crit_alarm = 28, - hwmon_power_rated_min = 29, - hwmon_power_rated_max = 30, -}; - -enum hwmon_energy_attributes { - hwmon_energy_enable = 0, - hwmon_energy_input = 1, - hwmon_energy_label = 2, -}; - -enum hwmon_humidity_attributes { - hwmon_humidity_enable = 0, - hwmon_humidity_input = 1, - hwmon_humidity_label = 2, - hwmon_humidity_min = 3, - hwmon_humidity_min_hyst = 4, - hwmon_humidity_max = 5, - hwmon_humidity_max_hyst = 6, - hwmon_humidity_alarm = 7, - hwmon_humidity_fault = 8, - hwmon_humidity_rated_min = 9, - hwmon_humidity_rated_max = 10, -}; - -enum hwmon_fan_attributes { - hwmon_fan_enable = 0, - hwmon_fan_input = 1, - hwmon_fan_label = 2, - hwmon_fan_min = 3, - hwmon_fan_max = 4, - hwmon_fan_div = 5, - hwmon_fan_pulses = 6, - hwmon_fan_target = 7, - hwmon_fan_alarm = 8, - hwmon_fan_min_alarm = 9, - hwmon_fan_max_alarm = 10, - hwmon_fan_fault = 11, -}; - -enum hwmon_pwm_attributes { - hwmon_pwm_input = 0, - hwmon_pwm_enable = 1, - hwmon_pwm_mode = 2, - hwmon_pwm_freq = 3, -}; - -enum hwmon_intrusion_attributes { - hwmon_intrusion_alarm = 0, - hwmon_intrusion_beep = 1, -}; - -struct trace_event_raw_hwmon_attr_class { - struct trace_entry ent; - int index; - u32 __data_loc_attr_name; - long int val; - char __data[0]; -}; - -struct trace_event_raw_hwmon_attr_show_string { - struct trace_entry ent; - int index; - u32 __data_loc_attr_name; - u32 __data_loc_label; - char __data[0]; -}; - -struct trace_event_data_offsets_hwmon_attr_class { - u32 attr_name; -}; - -struct trace_event_data_offsets_hwmon_attr_show_string { - u32 attr_name; - u32 label; -}; - -typedef void (*btf_trace_hwmon_attr_show)(void *, int, const char *, long int); - -typedef void (*btf_trace_hwmon_attr_store)(void *, int, const char *, long int); - -typedef void (*btf_trace_hwmon_attr_show_string)(void *, int, const char *, const char *); - -struct hwmon_device { - const char *name; - struct device dev; - const struct hwmon_chip_info *chip; - struct list_head tzdata; - struct attribute_group group; - const struct attribute_group **groups; -}; - -struct hwmon_device_attribute { - struct device_attribute dev_attr; - const struct hwmon_ops *ops; - enum hwmon_sensor_types type; - u32 attr; - int index; - char name[32]; -}; - -struct thermal_attr { - struct device_attribute attr; - char name[20]; -}; - -struct devfreq_dev_status { - long unsigned int total_time; - long unsigned int busy_time; - long unsigned int current_frequency; - void *private_data; -}; - -struct trace_event_raw_thermal_temperature { - struct trace_entry ent; - u32 __data_loc_thermal_zone; - int id; - int temp_prev; - int temp; - char __data[0]; -}; - -struct trace_event_raw_cdev_update { - struct trace_entry ent; - u32 __data_loc_type; - long unsigned int target; - char __data[0]; -}; - -struct trace_event_raw_thermal_zone_trip { - struct trace_entry ent; - u32 __data_loc_thermal_zone; - int id; - int trip; - enum thermal_trip_type trip_type; - char __data[0]; -}; - -struct trace_event_raw_thermal_power_devfreq_get_power { - struct trace_entry ent; - u32 __data_loc_type; - long unsigned int freq; - u32 busy_time; - u32 total_time; - u32 power; - char __data[0]; -}; - -struct trace_event_raw_thermal_power_devfreq_limit { - struct trace_entry ent; - u32 __data_loc_type; - unsigned int freq; - long unsigned int cdev_state; - u32 power; - char __data[0]; -}; - -struct trace_event_data_offsets_thermal_temperature { - u32 thermal_zone; -}; - -struct trace_event_data_offsets_cdev_update { - u32 type; -}; - -struct trace_event_data_offsets_thermal_zone_trip { - u32 thermal_zone; -}; - -struct trace_event_data_offsets_thermal_power_devfreq_get_power { - u32 type; -}; - -struct trace_event_data_offsets_thermal_power_devfreq_limit { - u32 type; -}; - -typedef void (*btf_trace_thermal_temperature)(void *, struct thermal_zone_device *); - -typedef void (*btf_trace_cdev_update)(void *, struct thermal_cooling_device *, long unsigned int); - -typedef void (*btf_trace_thermal_zone_trip)(void *, struct thermal_zone_device *, int, enum thermal_trip_type); - -typedef void (*btf_trace_thermal_power_devfreq_get_power)(void *, struct thermal_cooling_device *, struct devfreq_dev_status *, long unsigned int, u32); - -typedef void (*btf_trace_thermal_power_devfreq_limit)(void *, struct thermal_cooling_device *, long unsigned int, long unsigned int, u32); - -struct thermal_instance { - int id; - char name[20]; - struct thermal_zone_device *tz; - struct thermal_cooling_device *cdev; - int trip; - bool initialized; - long unsigned int upper; - long unsigned int lower; - long unsigned int target; - char attr_name[20]; - struct device_attribute attr; - char weight_attr_name[20]; - struct device_attribute weight_attr; - struct list_head tz_node; - struct list_head cdev_node; - unsigned int weight; -}; - -struct genl_dumpit_info { - const struct genl_family *family; - struct genl_ops op; - struct nlattr **attrs; -}; - -enum thermal_genl_attr { - THERMAL_GENL_ATTR_UNSPEC = 0, - THERMAL_GENL_ATTR_TZ = 1, - THERMAL_GENL_ATTR_TZ_ID = 2, - THERMAL_GENL_ATTR_TZ_TEMP = 3, - THERMAL_GENL_ATTR_TZ_TRIP = 4, - THERMAL_GENL_ATTR_TZ_TRIP_ID = 5, - THERMAL_GENL_ATTR_TZ_TRIP_TYPE = 6, - THERMAL_GENL_ATTR_TZ_TRIP_TEMP = 7, - THERMAL_GENL_ATTR_TZ_TRIP_HYST = 8, - THERMAL_GENL_ATTR_TZ_MODE = 9, - THERMAL_GENL_ATTR_TZ_NAME = 10, - THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT = 11, - THERMAL_GENL_ATTR_TZ_GOV = 12, - THERMAL_GENL_ATTR_TZ_GOV_NAME = 13, - THERMAL_GENL_ATTR_CDEV = 14, - THERMAL_GENL_ATTR_CDEV_ID = 15, - THERMAL_GENL_ATTR_CDEV_CUR_STATE = 16, - THERMAL_GENL_ATTR_CDEV_MAX_STATE = 17, - THERMAL_GENL_ATTR_CDEV_NAME = 18, - THERMAL_GENL_ATTR_GOV_NAME = 19, - __THERMAL_GENL_ATTR_MAX = 20, -}; - -enum thermal_genl_sampling { - THERMAL_GENL_SAMPLING_TEMP = 0, - __THERMAL_GENL_SAMPLING_MAX = 1, -}; - -enum thermal_genl_event { - THERMAL_GENL_EVENT_UNSPEC = 0, - THERMAL_GENL_EVENT_TZ_CREATE = 1, - THERMAL_GENL_EVENT_TZ_DELETE = 2, - THERMAL_GENL_EVENT_TZ_DISABLE = 3, - THERMAL_GENL_EVENT_TZ_ENABLE = 4, - THERMAL_GENL_EVENT_TZ_TRIP_UP = 5, - THERMAL_GENL_EVENT_TZ_TRIP_DOWN = 6, - THERMAL_GENL_EVENT_TZ_TRIP_CHANGE = 7, - THERMAL_GENL_EVENT_TZ_TRIP_ADD = 8, - THERMAL_GENL_EVENT_TZ_TRIP_DELETE = 9, - THERMAL_GENL_EVENT_CDEV_ADD = 10, - THERMAL_GENL_EVENT_CDEV_DELETE = 11, - THERMAL_GENL_EVENT_CDEV_STATE_UPDATE = 12, - THERMAL_GENL_EVENT_TZ_GOV_CHANGE = 13, - __THERMAL_GENL_EVENT_MAX = 14, -}; - -enum thermal_genl_cmd { - THERMAL_GENL_CMD_UNSPEC = 0, - THERMAL_GENL_CMD_TZ_GET_ID = 1, - THERMAL_GENL_CMD_TZ_GET_TRIP = 2, - THERMAL_GENL_CMD_TZ_GET_TEMP = 3, - THERMAL_GENL_CMD_TZ_GET_GOV = 4, - THERMAL_GENL_CMD_TZ_GET_MODE = 5, - THERMAL_GENL_CMD_CDEV_GET = 6, - __THERMAL_GENL_CMD_MAX = 7, -}; - -struct param { - struct nlattr **attrs; - struct sk_buff *msg; - const char *name; - int tz_id; - int cdev_id; - int trip_id; - int trip_temp; - int trip_type; - int trip_hyst; - int temp; - int cdev_state; - int cdev_max_state; -}; - -typedef int (*cb_t)(struct param *); - -struct thermal_hwmon_device { - char type[20]; - struct device *device; - int count; - struct list_head tz_list; - struct list_head node; -}; - -struct thermal_hwmon_attr { - struct device_attribute attr; - char name[16]; -}; - -struct thermal_hwmon_temp { - struct list_head hwmon_node; - struct thermal_zone_device *tz; - struct thermal_hwmon_attr temp_input; - struct thermal_hwmon_attr temp_crit; -}; - -struct trace_event_raw_thermal_power_allocator { - struct trace_entry ent; - int tz_id; - u32 __data_loc_req_power; - u32 total_req_power; - u32 __data_loc_granted_power; - u32 total_granted_power; - size_t num_actors; - u32 power_range; - u32 max_allocatable_power; - int current_temp; - s32 delta_temp; - char __data[0]; -}; - -struct trace_event_raw_thermal_power_allocator_pid { - struct trace_entry ent; - int tz_id; - s32 err; - s32 err_integral; - s64 p; - s64 i; - s64 d; - s32 output; - char __data[0]; -}; - -struct trace_event_data_offsets_thermal_power_allocator { - u32 req_power; - u32 granted_power; -}; - -struct trace_event_data_offsets_thermal_power_allocator_pid {}; - -typedef void (*btf_trace_thermal_power_allocator)(void *, struct thermal_zone_device *, u32 *, u32, u32 *, u32, size_t, u32, u32, int, s32); - -typedef void (*btf_trace_thermal_power_allocator_pid)(void *, struct thermal_zone_device *, s32, s32, s64, s64, s64, s32); - -struct power_allocator_params { - bool allocated_tzp; - s64 err_integral; - s32 prev_err; - int trip_switch_on; - int trip_max_desired_temperature; - u32 sustainable_power; -}; - -enum devfreq_timer { - DEVFREQ_TIMER_DEFERRABLE = 0, - DEVFREQ_TIMER_DELAYED = 1, - DEVFREQ_TIMER_NUM = 2, -}; - -struct devfreq_dev_profile { - long unsigned int initial_freq; - unsigned int polling_ms; - enum devfreq_timer timer; - bool is_cooling_device; - int (*target)(struct device *, long unsigned int *, u32); - int (*get_dev_status)(struct device *, struct devfreq_dev_status *); - int (*get_cur_freq)(struct device *, long unsigned int *); - void (*exit)(struct device *); - long unsigned int *freq_table; - unsigned int max_state; -}; - -struct devfreq_stats { - unsigned int total_trans; - unsigned int *trans_table; - u64 *time_in_state; - u64 last_update; -}; - -struct devfreq_governor; - -struct devfreq { - struct list_head node; - struct mutex lock; - struct device dev; - struct devfreq_dev_profile *profile; - const struct devfreq_governor *governor; - struct opp_table *opp_table; - struct notifier_block nb; - struct delayed_work work; - long unsigned int previous_freq; - struct devfreq_dev_status last_status; - void *data; - struct dev_pm_qos_request user_min_freq_req; - struct dev_pm_qos_request user_max_freq_req; - long unsigned int scaling_min_freq; - long unsigned int scaling_max_freq; - bool stop_polling; - long unsigned int suspend_freq; - long unsigned int resume_freq; - atomic_t suspend_count; - struct devfreq_stats stats; - struct srcu_notifier_head transition_notifier_list; - struct thermal_cooling_device *cdev; - struct notifier_block nb_min; - struct notifier_block nb_max; -}; - -struct devfreq_governor { - struct list_head node; - const char name[16]; - const u64 attrs; - const u64 flags; - int (*get_target_freq)(struct devfreq *, long unsigned int *); - int (*event_handler)(struct devfreq *, unsigned int, void *); -}; - -struct devfreq_cooling_power { - int (*get_real_power)(struct devfreq *, u32 *, long unsigned int, long unsigned int); -}; - -struct devfreq_cooling_device { - struct thermal_cooling_device *cdev; - struct devfreq *devfreq; - long unsigned int cooling_state; - u32 *freq_table; - size_t max_state; - struct devfreq_cooling_power *power_ops; - u32 res_util; - int capped_state; - struct dev_pm_qos_request req_max_freq; - struct em_perf_domain *em_pd; -}; - -struct _thermal_state { - u64 next_check; - u64 last_interrupt_time; - struct delayed_work therm_work; - long unsigned int count; - long unsigned int last_count; - long unsigned int max_time_ms; - long unsigned int total_time_ms; - bool rate_control_active; - bool new_event; - u8 level; - u8 sample_index; - u8 sample_count; - u8 average; - u8 baseline_temp; - u8 temp_samples[3]; -}; - -struct thermal_state { - struct _thermal_state core_throttle; - struct _thermal_state core_power_limit; - struct _thermal_state package_throttle; - struct _thermal_state package_power_limit; - struct _thermal_state core_thresh0; - struct _thermal_state core_thresh1; - struct _thermal_state pkg_thresh0; - struct _thermal_state pkg_thresh1; -}; - -struct watchdog_info { - __u32 options; - __u32 firmware_version; - __u8 identity[32]; -}; - -struct watchdog_device; - -struct watchdog_ops { - struct module *owner; - int (*start)(struct watchdog_device *); - int (*stop)(struct watchdog_device *); - int (*ping)(struct watchdog_device *); - unsigned int (*status)(struct watchdog_device *); - int (*set_timeout)(struct watchdog_device *, unsigned int); - int (*set_pretimeout)(struct watchdog_device *, unsigned int); - unsigned int (*get_timeleft)(struct watchdog_device *); - int (*restart)(struct watchdog_device *, long unsigned int, void *); - long int (*ioctl)(struct watchdog_device *, unsigned int, long unsigned int); -}; - -struct watchdog_governor; - -struct watchdog_core_data; - -struct watchdog_device { - int id; - struct device *parent; - const struct attribute_group **groups; - const struct watchdog_info *info; - const struct watchdog_ops *ops; - const struct watchdog_governor *gov; - unsigned int bootstatus; - unsigned int timeout; - unsigned int pretimeout; - unsigned int min_timeout; - unsigned int max_timeout; - unsigned int min_hw_heartbeat_ms; - unsigned int max_hw_heartbeat_ms; - struct notifier_block reboot_nb; - struct notifier_block restart_nb; - void *driver_data; - struct watchdog_core_data *wd_data; - long unsigned int status; - struct list_head deferred; -}; - -struct watchdog_governor { - const char name[20]; - void (*pretimeout)(struct watchdog_device *); -}; - -struct watchdog_core_data { - struct device dev; - struct cdev cdev; - struct watchdog_device *wdd; - struct mutex lock; - ktime_t last_keepalive; - ktime_t last_hw_keepalive; - ktime_t open_deadline; - struct hrtimer timer; - struct kthread_work work; - long unsigned int status; -}; - -struct watchdog_pretimeout { - struct watchdog_device *wdd; - struct list_head entry; -}; - -struct governor_priv { - struct watchdog_governor *gov; - struct list_head entry; -}; - -struct dm_kobject_holder { - struct kobject kobj; - struct completion completion; -}; - -enum dev_type { - DEV_UNKNOWN = 0, - DEV_X1 = 1, - DEV_X2 = 2, - DEV_X4 = 3, - DEV_X8 = 4, - DEV_X16 = 5, - DEV_X32 = 6, - DEV_X64 = 7, -}; - -enum hw_event_mc_err_type { - HW_EVENT_ERR_CORRECTED = 0, - HW_EVENT_ERR_UNCORRECTED = 1, - HW_EVENT_ERR_DEFERRED = 2, - HW_EVENT_ERR_FATAL = 3, - HW_EVENT_ERR_INFO = 4, -}; - -enum mem_type { - MEM_EMPTY = 0, - MEM_RESERVED = 1, - MEM_UNKNOWN = 2, - MEM_FPM = 3, - MEM_EDO = 4, - MEM_BEDO = 5, - MEM_SDR = 6, - MEM_RDR = 7, - MEM_DDR = 8, - MEM_RDDR = 9, - MEM_RMBS = 10, - MEM_DDR2 = 11, - MEM_FB_DDR2 = 12, - MEM_RDDR2 = 13, - MEM_XDR = 14, - MEM_DDR3 = 15, - MEM_RDDR3 = 16, - MEM_LRDDR3 = 17, - MEM_LPDDR3 = 18, - MEM_DDR4 = 19, - MEM_RDDR4 = 20, - MEM_LRDDR4 = 21, - MEM_LPDDR4 = 22, - MEM_DDR5 = 23, - MEM_NVDIMM = 24, - MEM_WIO2 = 25, -}; - -enum edac_type { - EDAC_UNKNOWN = 0, - EDAC_NONE = 1, - EDAC_RESERVED = 2, - EDAC_PARITY = 3, - EDAC_EC = 4, - EDAC_SECDED = 5, - EDAC_S2ECD2ED = 6, - EDAC_S4ECD4ED = 7, - EDAC_S8ECD8ED = 8, - EDAC_S16ECD16ED = 9, -}; - -enum scrub_type { - SCRUB_UNKNOWN = 0, - SCRUB_NONE = 1, - SCRUB_SW_PROG = 2, - SCRUB_SW_SRC = 3, - SCRUB_SW_PROG_SRC = 4, - SCRUB_SW_TUNABLE = 5, - SCRUB_HW_PROG = 6, - SCRUB_HW_SRC = 7, - SCRUB_HW_PROG_SRC = 8, - SCRUB_HW_TUNABLE = 9, -}; - -enum edac_mc_layer_type { - EDAC_MC_LAYER_BRANCH = 0, - EDAC_MC_LAYER_CHANNEL = 1, - EDAC_MC_LAYER_SLOT = 2, - EDAC_MC_LAYER_CHIP_SELECT = 3, - EDAC_MC_LAYER_ALL_MEM = 4, -}; - -struct edac_mc_layer { - enum edac_mc_layer_type type; - unsigned int size; - bool is_virt_csrow; -}; - -struct mem_ctl_info; - -struct dimm_info { - struct device dev; - char label[32]; - unsigned int location[3]; - struct mem_ctl_info *mci; - unsigned int idx; - u32 grain; - enum dev_type dtype; - enum mem_type mtype; - enum edac_type edac_mode; - u32 nr_pages; - unsigned int csrow; - unsigned int cschannel; - u16 smbios_handle; - u32 ce_count; - u32 ue_count; -}; - -struct mcidev_sysfs_attribute; - -struct edac_raw_error_desc { - char location[256]; - char label[296]; - long int grain; - u16 error_count; - enum hw_event_mc_err_type type; - int top_layer; - int mid_layer; - int low_layer; - long unsigned int page_frame_number; - long unsigned int offset_in_page; - long unsigned int syndrome; - const char *msg; - const char *other_detail; -}; - -struct csrow_info; - -struct mem_ctl_info { - struct device dev; - struct bus_type *bus; - struct list_head link; - struct module *owner; - long unsigned int mtype_cap; - long unsigned int edac_ctl_cap; - long unsigned int edac_cap; - long unsigned int scrub_cap; - enum scrub_type scrub_mode; - int (*set_sdram_scrub_rate)(struct mem_ctl_info *, u32); - int (*get_sdram_scrub_rate)(struct mem_ctl_info *); - void (*edac_check)(struct mem_ctl_info *); - long unsigned int (*ctl_page_to_phys)(struct mem_ctl_info *, long unsigned int); - int mc_idx; - struct csrow_info **csrows; - unsigned int nr_csrows; - unsigned int num_cschannel; - unsigned int n_layers; - struct edac_mc_layer *layers; - bool csbased; - unsigned int tot_dimms; - struct dimm_info **dimms; - struct device *pdev; - const char *mod_name; - const char *ctl_name; - const char *dev_name; - void *pvt_info; - long unsigned int start_time; - u32 ce_noinfo_count; - u32 ue_noinfo_count; - u32 ue_mc; - u32 ce_mc; - struct completion complete; - const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; - struct delayed_work work; - struct edac_raw_error_desc error_desc; - int op_state; - struct dentry *debugfs; - u8 fake_inject_layer[3]; - bool fake_inject_ue; - u16 fake_inject_count; -}; - -struct rank_info { - int chan_idx; - struct csrow_info *csrow; - struct dimm_info *dimm; - u32 ce_count; -}; - -struct csrow_info { - struct device dev; - long unsigned int first_page; - long unsigned int last_page; - long unsigned int page_mask; - int csrow_idx; - u32 ue_count; - u32 ce_count; - struct mem_ctl_info *mci; - u32 nr_channels; - struct rank_info **channels; -}; - -struct edac_device_counter { - u32 ue_count; - u32 ce_count; -}; - -struct edac_device_ctl_info; - -struct edac_dev_sysfs_attribute { - struct attribute attr; - ssize_t (*show)(struct edac_device_ctl_info *, char *); - ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t); -}; - -struct edac_device_instance; - -struct edac_device_ctl_info { - struct list_head link; - struct module *owner; - int dev_idx; - int log_ue; - int log_ce; - int panic_on_ue; - unsigned int poll_msec; - long unsigned int delay; - struct edac_dev_sysfs_attribute *sysfs_attributes; - struct bus_type *edac_subsys; - int op_state; - struct delayed_work work; - void (*edac_check)(struct edac_device_ctl_info *); - struct device *dev; - const char *mod_name; - const char *ctl_name; - const char *dev_name; - void *pvt_info; - long unsigned int start_time; - struct completion removal_complete; - char name[32]; - u32 nr_instances; - struct edac_device_instance *instances; - struct edac_device_counter counters; - struct kobject kobj; -}; - -struct edac_device_block; - -struct edac_dev_sysfs_block_attribute { - struct attribute attr; - ssize_t (*show)(struct kobject *, struct attribute *, char *); - ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); - struct edac_device_block *block; - unsigned int value; -}; - -struct edac_device_block { - struct edac_device_instance *instance; - char name[32]; - struct edac_device_counter counters; - int nr_attribs; - struct edac_dev_sysfs_block_attribute *block_attributes; - struct kobject kobj; -}; - -struct edac_device_instance { - struct edac_device_ctl_info *ctl; - char name[35]; - struct edac_device_counter counters; - u32 nr_blocks; - struct edac_device_block *blocks; - struct kobject kobj; -}; - -struct dev_ch_attribute { - struct device_attribute attr; - unsigned int channel; -}; - -struct ctl_info_attribute { - struct attribute attr; - ssize_t (*show)(struct edac_device_ctl_info *, char *); - ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t); -}; - -struct instance_attribute { - struct attribute attr; - ssize_t (*show)(struct edac_device_instance *, char *); - ssize_t (*store)(struct edac_device_instance *, const char *, size_t); -}; - -struct edac_pci_counter { - atomic_t pe_count; - atomic_t npe_count; -}; - -struct edac_pci_ctl_info { - struct list_head link; - int pci_idx; - struct bus_type *edac_subsys; - int op_state; - struct delayed_work work; - void (*edac_check)(struct edac_pci_ctl_info *); - struct device *dev; - const char *mod_name; - const char *ctl_name; - const char *dev_name; - void *pvt_info; - long unsigned int start_time; - struct completion complete; - char name[32]; - struct edac_pci_counter counters; - struct kobject kobj; -}; - -struct edac_pci_gen_data { - int edac_idx; -}; - -struct instance_attribute___2 { - struct attribute attr; - ssize_t (*show)(struct edac_pci_ctl_info *, char *); - ssize_t (*store)(struct edac_pci_ctl_info *, const char *, size_t); -}; - -struct edac_pci_dev_attribute { - struct attribute attr; - void *value; - ssize_t (*show)(void *, char *); - ssize_t (*store)(void *, const char *, size_t); -}; - -typedef void (*pci_parity_check_fn_t)(struct pci_dev *); - -struct ghes_pvt { - struct mem_ctl_info *mci; - char other_detail[400]; - char msg[80]; -}; - -struct ghes_hw_desc { - int num_dimms; - struct dimm_info *dimms; -}; - -struct memdev_dmi_entry { - u8 type; - u8 length; - u16 handle; - u16 phys_mem_array_handle; - u16 mem_err_info_handle; - u16 total_width; - u16 data_width; - u16 size; - u8 form_factor; - u8 device_set; - u8 device_locator; - u8 bank_locator; - u8 memory_type; - u16 type_detail; - u16 speed; - u8 manufacturer; - u8 serial_number; - u8 asset_tag; - u8 part_number; - u8 attributes; - u32 extended_size; - u16 conf_mem_clk_speed; -} __attribute__((packed)); - -enum opp_table_access { - OPP_TABLE_ACCESS_UNKNOWN = 0, - OPP_TABLE_ACCESS_EXCLUSIVE = 1, - OPP_TABLE_ACCESS_SHARED = 2, -}; - -struct icc_path; - -struct dev_pm_opp___2; - -struct dev_pm_set_opp_data; - -struct dev_pm_opp_supply; - -struct opp_table___2 { - struct list_head node; - struct list_head lazy; - struct blocking_notifier_head head; - struct list_head dev_list; - struct list_head opp_list; - struct kref kref; - struct mutex lock; - struct device_node *np; - long unsigned int clock_latency_ns_max; - unsigned int voltage_tolerance_v1; - unsigned int parsed_static_opps; - enum opp_table_access shared_opp; - long unsigned int current_rate; - struct dev_pm_opp___2 *current_opp; - struct dev_pm_opp___2 *suspend_opp; - struct mutex genpd_virt_dev_lock; - struct device **genpd_virt_devs; - struct opp_table___2 **required_opp_tables; - unsigned int required_opp_count; - unsigned int *supported_hw; - unsigned int supported_hw_count; - const char *prop_name; - struct clk *clk; - struct regulator **regulators; - int regulator_count; - struct icc_path **paths; - unsigned int path_count; - bool enabled; - bool genpd_performance_state; - bool is_genpd; - int (*set_opp)(struct dev_pm_set_opp_data *); - struct dev_pm_opp_supply *sod_supplies; - struct dev_pm_set_opp_data *set_opp_data; - struct dentry *dentry; - char dentry_name[255]; -}; - -struct dev_pm_opp_icc_bw; - -struct dev_pm_opp___2 { - struct list_head node; - struct kref kref; - bool available; - bool dynamic; - bool turbo; - bool suspend; - bool removed; - unsigned int pstate; - long unsigned int rate; - unsigned int level; - struct dev_pm_opp_supply *supplies; - struct dev_pm_opp_icc_bw *bandwidth; - long unsigned int clock_latency_ns; - struct dev_pm_opp___2 **required_opps; - struct opp_table___2 *opp_table; - struct device_node *np; - struct dentry *dentry; -}; - -enum dev_pm_opp_event { - OPP_EVENT_ADD = 0, - OPP_EVENT_REMOVE = 1, - OPP_EVENT_ENABLE = 2, - OPP_EVENT_DISABLE = 3, - OPP_EVENT_ADJUST_VOLTAGE = 4, -}; - -struct dev_pm_opp_supply { - long unsigned int u_volt; - long unsigned int u_volt_min; - long unsigned int u_volt_max; - long unsigned int u_amp; -}; - -struct dev_pm_opp_icc_bw { - u32 avg; - u32 peak; -}; - -struct dev_pm_opp_info { - long unsigned int rate; - struct dev_pm_opp_supply *supplies; -}; - -struct dev_pm_set_opp_data { - struct dev_pm_opp_info old_opp; - struct dev_pm_opp_info new_opp; - struct regulator **regulators; - unsigned int regulator_count; - struct clk *clk; - struct device *dev; -}; - -struct opp_device { - struct list_head node; - const struct device *dev; - struct dentry *dentry; -}; - -struct cpufreq_policy_data { - struct cpufreq_cpuinfo cpuinfo; - struct cpufreq_frequency_table *freq_table; - unsigned int cpu; - unsigned int min; - unsigned int max; -}; - -struct freq_attr { - struct attribute attr; - ssize_t (*show)(struct cpufreq_policy *, char *); - ssize_t (*store)(struct cpufreq_policy *, const char *, size_t); -}; - -struct cpufreq_driver { - char name[16]; - u16 flags; - void *driver_data; - int (*init)(struct cpufreq_policy *); - int (*verify)(struct cpufreq_policy_data *); - int (*setpolicy)(struct cpufreq_policy *); - int (*target)(struct cpufreq_policy *, unsigned int, unsigned int); - int (*target_index)(struct cpufreq_policy *, unsigned int); - unsigned int (*fast_switch)(struct cpufreq_policy *, unsigned int); - void (*adjust_perf)(unsigned int, long unsigned int, long unsigned int, long unsigned int); - unsigned int (*get_intermediate)(struct cpufreq_policy *, unsigned int); - int (*target_intermediate)(struct cpufreq_policy *, unsigned int); - unsigned int (*get)(unsigned int); - void (*update_limits)(unsigned int); - int (*bios_limit)(int, unsigned int *); - int (*online)(struct cpufreq_policy *); - int (*offline)(struct cpufreq_policy *); - int (*exit)(struct cpufreq_policy *); - int (*suspend)(struct cpufreq_policy *); - int (*resume)(struct cpufreq_policy *); - void (*ready)(struct cpufreq_policy *); - struct freq_attr **attr; - bool boost_enabled; - int (*set_boost)(struct cpufreq_policy *, int); -}; - -struct cpufreq_stats { - unsigned int total_trans; - long long unsigned int last_time; - unsigned int max_state; - unsigned int state_num; - unsigned int last_index; - u64 *time_in_state; - unsigned int *freq_table; - unsigned int *trans_table; - unsigned int reset_pending; - long long unsigned int reset_time; -}; - -enum { - OD_NORMAL_SAMPLE = 0, - OD_SUB_SAMPLE = 1, -}; - -struct dbs_data { - struct gov_attr_set attr_set; - void *tuners; - unsigned int ignore_nice_load; - unsigned int sampling_rate; - unsigned int sampling_down_factor; - unsigned int up_threshold; - unsigned int io_is_busy; -}; - -struct policy_dbs_info { - struct cpufreq_policy *policy; - struct mutex update_mutex; - u64 last_sample_time; - s64 sample_delay_ns; - atomic_t work_count; - struct irq_work irq_work; - struct work_struct work; - struct dbs_data *dbs_data; - struct list_head list; - unsigned int rate_mult; - unsigned int idle_periods; - bool is_shared; - bool work_in_progress; -}; - -struct dbs_governor { - struct cpufreq_governor gov; - struct kobj_type kobj_type; - struct dbs_data *gdbs_data; - unsigned int (*gov_dbs_update)(struct cpufreq_policy *); - struct policy_dbs_info * (*alloc)(); - void (*free)(struct policy_dbs_info *); - int (*init)(struct dbs_data *); - void (*exit)(struct dbs_data *); - void (*start)(struct cpufreq_policy *); -}; - -struct od_ops { - unsigned int (*powersave_bias_target)(struct cpufreq_policy *, unsigned int, unsigned int); -}; - -struct od_policy_dbs_info { - struct policy_dbs_info policy_dbs; - unsigned int freq_lo; - unsigned int freq_lo_delay_us; - unsigned int freq_hi_delay_us; - unsigned int sample_type: 1; -}; - -struct od_dbs_tuners { - unsigned int powersave_bias; -}; - -struct cs_policy_dbs_info { - struct policy_dbs_info policy_dbs; - unsigned int down_skip; - unsigned int requested_freq; -}; - -struct cs_dbs_tuners { - unsigned int down_threshold; - unsigned int freq_step; -}; - -struct cpu_dbs_info { - u64 prev_cpu_idle; - u64 prev_update_time; - u64 prev_cpu_nice; - unsigned int prev_load; - struct update_util_data update_util; - struct policy_dbs_info *policy_dbs; -}; - -enum acpi_preferred_pm_profiles { - PM_UNSPECIFIED = 0, - PM_DESKTOP = 1, - PM_MOBILE = 2, - PM_WORKSTATION = 3, - PM_ENTERPRISE_SERVER = 4, - PM_SOHO_SERVER = 5, - PM_APPLIANCE_PC = 6, - PM_PERFORMANCE_SERVER = 7, - PM_TABLET = 8, -}; - -struct sample { - int32_t core_avg_perf; - int32_t busy_scaled; - u64 aperf; - u64 mperf; - u64 tsc; - u64 time; -}; - -struct pstate_data { - int current_pstate; - int min_pstate; - int max_pstate; - int max_pstate_physical; - int perf_ctl_scaling; - int scaling; - int turbo_pstate; - unsigned int min_freq; - unsigned int max_freq; - unsigned int turbo_freq; -}; - -struct vid_data { - int min; - int max; - int turbo; - int32_t ratio; -}; - -struct global_params { - bool no_turbo; - bool turbo_disabled; - bool turbo_disabled_mf; - int max_perf_pct; - int min_perf_pct; -}; - -struct cpudata { - int cpu; - unsigned int policy; - struct update_util_data update_util; - bool update_util_set; - struct pstate_data pstate; - struct vid_data vid; - u64 last_update; - u64 last_sample_time; - u64 aperf_mperf_shift; - u64 prev_aperf; - u64 prev_mperf; - u64 prev_tsc; - u64 prev_cummulative_iowait; - struct sample sample; - int32_t min_perf_ratio; - int32_t max_perf_ratio; - struct acpi_processor_performance acpi_perf_data; - bool valid_pss_table; - unsigned int iowait_boost; - s16 epp_powersave; - s16 epp_policy; - s16 epp_default; - s16 epp_cached; - u64 hwp_req_cached; - u64 hwp_cap_cached; - u64 last_io_update; - unsigned int sched_flags; - u32 hwp_boost_min; - bool suspended; -}; - -struct pstate_funcs { - int (*get_max)(); - int (*get_max_physical)(); - int (*get_min)(); - int (*get_turbo)(); - int (*get_scaling)(); - int (*get_aperf_mperf_shift)(); - u64 (*get_val)(struct cpudata *, int); - void (*get_vid)(struct cpudata *); -}; - -enum { - PSS = 0, - PPC = 1, -}; - -struct cpuidle_governor { - char name[16]; - struct list_head governor_list; - unsigned int rating; - int (*enable)(struct cpuidle_driver *, struct cpuidle_device *); - void (*disable)(struct cpuidle_driver *, struct cpuidle_device *); - int (*select)(struct cpuidle_driver *, struct cpuidle_device *, bool *); - void (*reflect)(struct cpuidle_device *, int); -}; - -struct cpuidle_state_kobj { - struct cpuidle_state *state; - struct cpuidle_state_usage *state_usage; - struct completion kobj_unregister; - struct kobject kobj; - struct cpuidle_device *device; -}; - -struct cpuidle_device_kobj { - struct cpuidle_device *dev; - struct completion kobj_unregister; - struct kobject kobj; -}; - -struct cpuidle_attr { - struct attribute attr; - ssize_t (*show)(struct cpuidle_device *, char *); - ssize_t (*store)(struct cpuidle_device *, const char *, size_t); -}; - -struct cpuidle_state_attr { - struct attribute attr; - ssize_t (*show)(struct cpuidle_state *, struct cpuidle_state_usage *, char *); - ssize_t (*store)(struct cpuidle_state *, struct cpuidle_state_usage *, const char *, size_t); -}; - -struct ladder_device_state { - struct { - u32 promotion_count; - u32 demotion_count; - u64 promotion_time_ns; - u64 demotion_time_ns; - } threshold; - struct { - int promotion_count; - int demotion_count; - } stats; -}; - -struct ladder_device { - struct ladder_device_state states[10]; -}; - -struct menu_device { - int needs_update; - int tick_wakeup; - u64 next_timer_ns; - unsigned int bucket; - unsigned int correction_factor[12]; - unsigned int intervals[8]; - int interval_ptr; -}; - -struct teo_bin { - unsigned int intercepts; - unsigned int hits; - unsigned int recent; -}; - -struct teo_cpu { - s64 time_span_ns; - s64 sleep_length_ns; - struct teo_bin state_bins[10]; - unsigned int total; - int next_recent_idx; - int recent_idx[9]; -}; - -struct pci_dev___2; - -struct sdhci_pci_data { - struct pci_dev___2 *pdev; - int slotno; - int rst_n_gpio; - int cd_gpio; - int (*setup)(struct sdhci_pci_data *); - void (*cleanup)(struct sdhci_pci_data *); -}; - -struct led_properties { - u32 color; - bool color_present; - const char *function; - u32 func_enum; - bool func_enum_present; - const char *label; -}; - -enum cpu_led_event { - CPU_LED_IDLE_START = 0, - CPU_LED_IDLE_END = 1, - CPU_LED_START = 2, - CPU_LED_STOP = 3, - CPU_LED_HALTED = 4, -}; - -struct led_trigger_cpu { - bool is_active; - char name[8]; - struct led_trigger *_trig; -}; - -struct dmi_memdev_info { - const char *device; - const char *bank; - u64 size; - u16 handle; - u8 type; -}; - -struct dmi_sysfs_entry { - struct dmi_header dh; - struct kobject kobj; - int instance; - int position; - struct list_head list; - struct kobject *child; -}; - -struct dmi_sysfs_attribute { - struct attribute attr; - ssize_t (*show)(struct dmi_sysfs_entry *, char *); -}; - -struct dmi_sysfs_mapped_attribute { - struct attribute attr; - ssize_t (*show)(struct dmi_sysfs_entry *, const struct dmi_header *, char *); -}; - -typedef ssize_t (*dmi_callback)(struct dmi_sysfs_entry *, const struct dmi_header *, void *); - -struct find_dmi_data { - struct dmi_sysfs_entry *entry; - dmi_callback callback; - void *private; - int instance_countdown; - ssize_t ret; -}; - -struct dmi_read_state { - char *buf; - loff_t pos; - size_t count; -}; - -struct dmi_entry_attr_show_data { - struct attribute *attr; - char *buf; -}; - -struct dmi_system_event_log { - struct dmi_header header; - u16 area_length; - u16 header_start_offset; - u16 data_start_offset; - u8 access_method; - u8 status; - u32 change_token; - union { - struct { - u16 index_addr; - u16 data_addr; - } io; - u32 phys_addr32; - u16 gpnv_handle; - u32 access_method_address; - }; - u8 header_format; - u8 type_descriptors_supported_count; - u8 per_log_type_descriptor_length; - u8 supported_log_type_descriptos[0]; -} __attribute__((packed)); - -typedef u8 (*sel_io_reader)(const struct dmi_system_event_log *, loff_t); - -struct dmi_device_attribute { - struct device_attribute dev_attr; - int field; -}; - -struct mafield { - const char *prefix; - int field; -}; - -struct acpi_table_ibft { - struct acpi_table_header header; - u8 reserved[12]; -}; - -struct firmware_map_entry { - u64 start; - u64 end; - const char *type; - struct list_head list; - struct kobject kobj; -}; - -struct memmap_attribute { - struct attribute attr; - ssize_t (*show)(struct firmware_map_entry *, char *); -}; - -struct bmp_header { - u16 id; - u32 size; -} __attribute__((packed)); - -typedef efi_status_t efi_query_variable_store_t(u32, long unsigned int, bool); - -typedef struct { - u16 version; - u16 length; - u32 runtime_services_supported; -} efi_rt_properties_table_t; - -struct efivar_operations { - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_set_variable_t *set_variable_nonblocking; - efi_query_variable_store_t *query_variable_store; -}; - -struct efivars { - struct kset *kset; - struct kobject *kobject; - const struct efivar_operations *ops; -}; - -struct linux_efi_random_seed { - u32 size; - u8 bits[0]; -}; - -struct linux_efi_memreserve { - int size; - atomic_t count; - phys_addr_t next; - struct { - phys_addr_t base; - phys_addr_t size; - } entry[0]; -}; - -struct efi_generic_dev_path { - u8 type; - u8 sub_type; - u16 length; -}; - -struct variable_validate { - efi_guid_t vendor; - char *name; - bool (*validate)(efi_char16_t *, int, u8 *, long unsigned int); -}; - -typedef struct { - u32 version; - u32 num_entries; - u32 desc_size; - u32 reserved; - efi_memory_desc_t entry[0]; -} efi_memory_attributes_table_t; - -struct linux_efi_tpm_eventlog { - u32 size; - u32 final_events_preboot_size; - u8 version; - u8 log[0]; -}; - -struct efi_tcg2_final_events_table { - u64 version; - u64 nr_events; - u8 events[0]; -}; - -struct tpm_digest { - u16 alg_id; - u8 digest[64]; -}; - -enum tpm_duration { - TPM_SHORT = 0, - TPM_MEDIUM = 1, - TPM_LONG = 2, - TPM_LONG_LONG = 3, - TPM_UNDEFINED = 4, - TPM_NUM_DURATIONS = 4, -}; - -enum tcpa_event_types { - PREBOOT = 0, - POST_CODE = 1, - UNUSED = 2, - NO_ACTION = 3, - SEPARATOR = 4, - ACTION = 5, - EVENT_TAG = 6, - SCRTM_CONTENTS = 7, - SCRTM_VERSION = 8, - CPU_MICROCODE = 9, - PLATFORM_CONFIG_FLAGS = 10, - TABLE_OF_DEVICES = 11, - COMPACT_HASH = 12, - IPL = 13, - IPL_PARTITION_DATA = 14, - NONHOST_CODE = 15, - NONHOST_CONFIG = 16, - NONHOST_INFO = 17, -}; - -struct tcg_efi_specid_event_algs { - u16 alg_id; - u16 digest_size; -}; - -struct tcg_efi_specid_event_head { - u8 signature[16]; - u32 platform_class; - u8 spec_version_minor; - u8 spec_version_major; - u8 spec_errata; - u8 uintnsize; - u32 num_algs; - struct tcg_efi_specid_event_algs digest_sizes[0]; -}; - -struct tcg_pcr_event { - u32 pcr_idx; - u32 event_type; - u8 digest[20]; - u32 event_size; - u8 event[0]; -}; - -struct tcg_event_field { - u32 event_size; - u8 event[0]; -}; - -struct tcg_pcr_event2_head { - u32 pcr_idx; - u32 event_type; - u32 count; - struct tpm_digest digests[0]; -}; - -typedef u64 efi_physical_addr_t; - -typedef struct { - u64 length; - u64 data; -} efi_capsule_block_desc_t; - -struct efi_system_resource_entry_v1 { - efi_guid_t fw_class; - u32 fw_type; - u32 fw_version; - u32 lowest_supported_fw_version; - u32 capsule_flags; - u32 last_attempt_version; - u32 last_attempt_status; -}; - -struct efi_system_resource_table { - u32 fw_resource_count; - u32 fw_resource_count_max; - u64 fw_resource_version; - u8 entries[0]; -}; - -struct esre_entry { - union { - struct efi_system_resource_entry_v1 *esre1; - } esre; - struct kobject kobj; - struct list_head list; -}; - -struct esre_attribute { - struct attribute attr; - ssize_t (*show)(struct esre_entry *, char *); - ssize_t (*store)(struct esre_entry *, const char *, size_t); -}; - -struct cper_sec_proc_generic { - u64 validation_bits; - u8 proc_type; - u8 proc_isa; - u8 proc_error_type; - u8 operation; - u8 flags; - u8 level; - u16 reserved; - u64 cpu_version; - char cpu_brand[128]; - u64 proc_id; - u64 target_addr; - u64 requestor_id; - u64 responder_id; - u64 ip; -}; - -struct cper_sec_proc_ia { - u64 validation_bits; - u64 lapic_id; - u8 cpuid[48]; -}; - -struct cper_mem_err_compact { - u64 validation_bits; - u16 node; - u16 card; - u16 module; - u16 bank; - u16 device; - u16 row; - u16 column; - u16 bit_pos; - u64 requestor_id; - u64 responder_id; - u64 target_id; - u16 rank; - u16 mem_array_handle; - u16 mem_dev_handle; - u8 extended; -} __attribute__((packed)); - -struct cper_sec_fw_err_rec_ref { - u8 record_type; - u8 revision; - u8 reserved[6]; - u64 record_identifier; - guid_t record_identifier_guid; -}; - -struct efi_runtime_map_entry { - efi_memory_desc_t md; - struct kobject kobj; -}; - -struct map_attribute { - struct attribute attr; - ssize_t (*show)(struct efi_runtime_map_entry *, char *); -}; - -struct efi_acpi_dev_path { - struct efi_generic_dev_path header; - u32 hid; - u32 uid; -}; - -struct efi_pci_dev_path { - struct efi_generic_dev_path header; - u8 fn; - u8 dev; -}; - -struct efi_vendor_dev_path { - struct efi_generic_dev_path header; - efi_guid_t vendorguid; - u8 vendordata[0]; -}; - -struct efi_dev_path { - union { - struct efi_generic_dev_path header; - struct efi_acpi_dev_path acpi; - struct efi_pci_dev_path pci; - struct efi_vendor_dev_path vendor; - }; -}; - -struct dev_header { - u32 len; - u32 prop_count; - struct efi_dev_path path[0]; -}; - -struct properties_header { - u32 len; - u32 version; - u32 dev_count; - struct dev_header dev_header[0]; -}; - -struct efi_embedded_fw { - struct list_head list; - const char *name; - const u8 *data; - size_t length; -}; - -struct efi_embedded_fw_desc { - const char *name; - u8 prefix[8]; - u32 length; - u8 sha256[32]; -}; - -struct cper_ia_err_info { - guid_t err_type; - u64 validation_bits; - u64 check_info; - u64 target_id; - u64 requestor_id; - u64 responder_id; - u64 ip; -}; - -enum err_types { - ERR_TYPE_CACHE = 0, - ERR_TYPE_TLB = 1, - ERR_TYPE_BUS = 2, - ERR_TYPE_MS = 3, - N_ERR_TYPES = 4, -}; - -struct hid_device_id { - __u16 bus; - __u16 group; - __u32 vendor; - __u32 product; - kernel_ulong_t driver_data; -}; - -struct hid_item { - unsigned int format; - __u8 size; - __u8 type; - __u8 tag; - union { - __u8 u8; - __s8 s8; - __u16 u16; - __s16 s16; - __u32 u32; - __s32 s32; - __u8 *longdata; - } data; -}; - -struct hid_global { - unsigned int usage_page; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned int unit; - unsigned int report_id; - unsigned int report_size; - unsigned int report_count; -}; - -struct hid_local { - unsigned int usage[12288]; - u8 usage_size[12288]; - unsigned int collection_index[12288]; - unsigned int usage_index; - unsigned int usage_minimum; - unsigned int delimiter_depth; - unsigned int delimiter_branch; -}; - -struct hid_collection { - int parent_idx; - unsigned int type; - unsigned int usage; - unsigned int level; -}; - -struct hid_usage { - unsigned int hid; - unsigned int collection_index; - unsigned int usage_index; - __s8 resolution_multiplier; - __s8 wheel_factor; - __u16 code; - __u8 type; - __s8 hat_min; - __s8 hat_max; - __s8 hat_dir; - __s16 wheel_accumulated; -}; - -struct hid_report; - -struct hid_input; - -struct hid_field { - unsigned int physical; - unsigned int logical; - unsigned int application; - struct hid_usage *usage; - unsigned int maxusage; - unsigned int flags; - unsigned int report_offset; - unsigned int report_size; - unsigned int report_count; - unsigned int report_type; - __s32 *value; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned int unit; - struct hid_report *report; - unsigned int index; - struct hid_input *hidinput; - __u16 dpad; -}; - -struct hid_device; - -struct hid_report { - struct list_head list; - struct list_head hidinput_list; - unsigned int id; - unsigned int type; - unsigned int application; - struct hid_field *field[256]; - unsigned int maxfield; - unsigned int size; - struct hid_device *device; -}; - -struct hid_input { - struct list_head list; - struct hid_report *report; - struct input_dev *input; - const char *name; - bool registered; - struct list_head reports; - unsigned int application; -}; - -enum hid_type { - HID_TYPE_OTHER = 0, - HID_TYPE_USBMOUSE = 1, - HID_TYPE_USBNONE = 2, -}; - -struct hid_report_enum { - unsigned int numbered; - struct list_head report_list; - struct hid_report *report_id_hash[256]; -}; - -enum hid_battery_status { - HID_BATTERY_UNKNOWN = 0, - HID_BATTERY_QUERIED = 1, - HID_BATTERY_REPORTED = 2, -}; - -struct hid_driver; - -struct hid_ll_driver; - -struct hid_device { - __u8 *dev_rdesc; - unsigned int dev_rsize; - __u8 *rdesc; - unsigned int rsize; - struct hid_collection *collection; - unsigned int collection_size; - unsigned int maxcollection; - unsigned int maxapplication; - __u16 bus; - __u16 group; - __u32 vendor; - __u32 product; - __u32 version; - enum hid_type type; - unsigned int country; - struct hid_report_enum report_enum[3]; - struct work_struct led_work; - struct semaphore driver_input_lock; - struct device dev; - struct hid_driver *driver; - struct hid_ll_driver *ll_driver; - struct mutex ll_open_lock; - unsigned int ll_open_count; - struct power_supply *battery; - __s32 battery_capacity; - __s32 battery_min; - __s32 battery_max; - __s32 battery_report_type; - __s32 battery_report_id; - enum hid_battery_status battery_status; - bool battery_avoid_query; - ktime_t battery_ratelimit_time; - long unsigned int status; - unsigned int claimed; - unsigned int quirks; - bool io_started; - struct list_head inputs; - void *hiddev; - void *hidraw; - char name[128]; - char phys[64]; - char uniq[64]; - void *driver_data; - int (*ff_init)(struct hid_device *); - int (*hiddev_connect)(struct hid_device *, unsigned int); - void (*hiddev_disconnect)(struct hid_device *); - void (*hiddev_hid_event)(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); - void (*hiddev_report_event)(struct hid_device *, struct hid_report *); - short unsigned int debug; - struct dentry *debug_dir; - struct dentry *debug_rdesc; - struct dentry *debug_events; - struct list_head debug_list; - spinlock_t debug_list_lock; - wait_queue_head_t debug_wait; -}; - -struct hid_report_id; - -struct hid_usage_id; - -struct hid_driver { - char *name; - const struct hid_device_id *id_table; - struct list_head dyn_list; - spinlock_t dyn_lock; - bool (*match)(struct hid_device *, bool); - int (*probe)(struct hid_device *, const struct hid_device_id *); - void (*remove)(struct hid_device *); - const struct hid_report_id *report_table; - int (*raw_event)(struct hid_device *, struct hid_report *, u8 *, int); - const struct hid_usage_id *usage_table; - int (*event)(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); - void (*report)(struct hid_device *, struct hid_report *); - __u8 * (*report_fixup)(struct hid_device *, __u8 *, unsigned int *); - int (*input_mapping)(struct hid_device *, struct hid_input *, struct hid_field *, struct hid_usage *, long unsigned int **, int *); - int (*input_mapped)(struct hid_device *, struct hid_input *, struct hid_field *, struct hid_usage *, long unsigned int **, int *); - int (*input_configured)(struct hid_device *, struct hid_input *); - void (*feature_mapping)(struct hid_device *, struct hid_field *, struct hid_usage *); - int (*suspend)(struct hid_device *, pm_message_t); - int (*resume)(struct hid_device *); - int (*reset_resume)(struct hid_device *); - struct device_driver driver; -}; - -struct hid_ll_driver { - int (*start)(struct hid_device *); - void (*stop)(struct hid_device *); - int (*open)(struct hid_device *); - void (*close)(struct hid_device *); - int (*power)(struct hid_device *, int); - int (*parse)(struct hid_device *); - void (*request)(struct hid_device *, struct hid_report *, int); - int (*wait)(struct hid_device *); - int (*raw_request)(struct hid_device *, unsigned char, __u8 *, size_t, unsigned char, int); - int (*output_report)(struct hid_device *, __u8 *, size_t); - int (*idle)(struct hid_device *, int, int, int); - bool (*may_wakeup)(struct hid_device *); -}; - -struct hid_parser { - struct hid_global global; - struct hid_global global_stack[4]; - unsigned int global_stack_ptr; - struct hid_local local; - unsigned int *collection_stack; - unsigned int collection_stack_ptr; - unsigned int collection_stack_size; - struct hid_device *device; - unsigned int scan_flags; -}; - -struct hid_report_id { - __u32 report_type; -}; - -struct hid_usage_id { - __u32 usage_hid; - __u32 usage_type; - __u32 usage_code; -}; - -struct hiddev { - int minor; - int exist; - int open; - struct mutex existancelock; - wait_queue_head_t wait; - struct hid_device *hid; - struct list_head list; - spinlock_t list_lock; - bool initialized; -}; - -struct hidraw { - unsigned int minor; - int exist; - int open; - wait_queue_head_t wait; - struct hid_device *hid; - struct device *dev; - spinlock_t list_lock; - struct list_head list; -}; - -struct hid_dynid { - struct list_head list; - struct hid_device_id id; -}; - -typedef bool (*hid_usage_cmp_t)(struct hid_usage *, unsigned int, unsigned int); - -struct quirks_list_struct { - struct hid_device_id hid_bl_item; - struct list_head node; -}; - -struct hid_debug_list { - struct { - union { - struct __kfifo kfifo; - char *type; - const char *const_type; - char (*rectype)[0]; - char *ptr; - const char *ptr_const; - }; - char buf[0]; - } hid_debug_fifo; - struct fasync_struct *fasync; - struct hid_device *hdev; - struct list_head node; - struct mutex read_mutex; -}; - -struct hid_usage_entry { - unsigned int page; - unsigned int usage; - const char *description; -}; - -struct hidraw_devinfo { - __u32 bustype; - __s16 vendor; - __s16 product; -}; - -struct hidraw_report { - __u8 *value; - int len; -}; - -struct hidraw_list { - struct hidraw_report buffer[64]; - int head; - int tail; - struct fasync_struct *fasync; - struct hidraw *hidraw; - struct list_head node; - struct mutex read_mutex; -}; - -struct ts_dmi_data { - struct efi_embedded_fw_desc embedded_fw; - const char *acpi_name; - const struct property_entry *properties; -}; - -enum ppfear_regs { - SPT_PMC_XRAM_PPFEAR0A = 1424, - SPT_PMC_XRAM_PPFEAR0B = 1425, - SPT_PMC_XRAM_PPFEAR0C = 1426, - SPT_PMC_XRAM_PPFEAR0D = 1427, - SPT_PMC_XRAM_PPFEAR1A = 1428, -}; - -struct pmc_bit_map { - const char *name; - u32 bit_mask; -}; - -struct pmc_reg_map { - const struct pmc_bit_map **pfear_sts; - const struct pmc_bit_map *mphy_sts; - const struct pmc_bit_map *pll_sts; - const struct pmc_bit_map **slps0_dbg_maps; - const struct pmc_bit_map *ltr_show_sts; - const struct pmc_bit_map *msr_sts; - const struct pmc_bit_map **lpm_sts; - const u32 slp_s0_offset; - const int slp_s0_res_counter_step; - const u32 ltr_ignore_offset; - const int regmap_length; - const u32 ppfear0_offset; - const int ppfear_buckets; - const u32 pm_cfg_offset; - const int pm_read_disable_bit; - const u32 slps0_dbg_offset; - const u32 ltr_ignore_max; - const u32 pm_vric1_offset; - const int lpm_num_maps; - const int lpm_res_counter_step_x2; - const u32 lpm_sts_latch_en_offset; - const u32 lpm_en_offset; - const u32 lpm_priority_offset; - const u32 lpm_residency_offset; - const u32 lpm_status_offset; - const u32 lpm_live_status_offset; - const u32 etr3_offset; -}; - -struct pmc_dev { - u32 base_addr; - void *regbase; - const struct pmc_reg_map *map; - struct dentry *dbgfs_dir; - int pmc_xram_read_bit; - struct mutex lock; - bool check_counters; - u64 pc10_counter; - u64 s0ix_counter; - int num_lpm_modes; - int lpm_en_modes[8]; - u32 *lpm_req_regs; -}; - -struct intel_scu_ipc_data { - struct resource mem; - int irq; -}; - -struct intel_scu_ipc_dev___2 { - struct device dev; - struct resource mem; - struct module *owner; - int irq; - void *ipc_base; - struct completion cmd_complete; -}; - -struct intel_scu_ipc_devres { - struct intel_scu_ipc_dev___2 *scu; -}; - -struct pmc_reg_map___2 { - const struct pmc_bit_map *d3_sts_0; - const struct pmc_bit_map *d3_sts_1; - const struct pmc_bit_map *func_dis; - const struct pmc_bit_map *func_dis_2; - const struct pmc_bit_map *pss; -}; - -struct pmc_data { - const struct pmc_reg_map___2 *map; - const struct pmc_clk *clks; -}; - -struct pmc_dev___2 { - u32 base_addr; - void *regmap; - const struct pmc_reg_map___2 *map; - struct dentry *dbgfs_dir; - bool init; -}; - -enum ec_status { - EC_RES_SUCCESS = 0, - EC_RES_INVALID_COMMAND = 1, - EC_RES_ERROR = 2, - EC_RES_INVALID_PARAM = 3, - EC_RES_ACCESS_DENIED = 4, - EC_RES_INVALID_RESPONSE = 5, - EC_RES_INVALID_VERSION = 6, - EC_RES_INVALID_CHECKSUM = 7, - EC_RES_IN_PROGRESS = 8, - EC_RES_UNAVAILABLE = 9, - EC_RES_TIMEOUT = 10, - EC_RES_OVERFLOW = 11, - EC_RES_INVALID_HEADER = 12, - EC_RES_REQUEST_TRUNCATED = 13, - EC_RES_RESPONSE_TOO_BIG = 14, - EC_RES_BUS_ERROR = 15, - EC_RES_BUSY = 16, - EC_RES_INVALID_HEADER_VERSION = 17, - EC_RES_INVALID_HEADER_CRC = 18, - EC_RES_INVALID_DATA_CRC = 19, - EC_RES_DUP_UNAVAILABLE = 20, -}; - -enum host_event_code { - EC_HOST_EVENT_LID_CLOSED = 1, - EC_HOST_EVENT_LID_OPEN = 2, - EC_HOST_EVENT_POWER_BUTTON = 3, - EC_HOST_EVENT_AC_CONNECTED = 4, - EC_HOST_EVENT_AC_DISCONNECTED = 5, - EC_HOST_EVENT_BATTERY_LOW = 6, - EC_HOST_EVENT_BATTERY_CRITICAL = 7, - EC_HOST_EVENT_BATTERY = 8, - EC_HOST_EVENT_THERMAL_THRESHOLD = 9, - EC_HOST_EVENT_DEVICE = 10, - EC_HOST_EVENT_THERMAL = 11, - EC_HOST_EVENT_USB_CHARGER = 12, - EC_HOST_EVENT_KEY_PRESSED = 13, - EC_HOST_EVENT_INTERFACE_READY = 14, - EC_HOST_EVENT_KEYBOARD_RECOVERY = 15, - EC_HOST_EVENT_THERMAL_SHUTDOWN = 16, - EC_HOST_EVENT_BATTERY_SHUTDOWN = 17, - EC_HOST_EVENT_THROTTLE_START = 18, - EC_HOST_EVENT_THROTTLE_STOP = 19, - EC_HOST_EVENT_HANG_DETECT = 20, - EC_HOST_EVENT_HANG_REBOOT = 21, - EC_HOST_EVENT_PD_MCU = 22, - EC_HOST_EVENT_BATTERY_STATUS = 23, - EC_HOST_EVENT_PANIC = 24, - EC_HOST_EVENT_KEYBOARD_FASTBOOT = 25, - EC_HOST_EVENT_RTC = 26, - EC_HOST_EVENT_MKBP = 27, - EC_HOST_EVENT_USB_MUX = 28, - EC_HOST_EVENT_MODE_CHANGE = 29, - EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT = 30, - EC_HOST_EVENT_WOV = 31, - EC_HOST_EVENT_INVALID = 32, -}; - -struct ec_host_request { - uint8_t struct_version; - uint8_t checksum; - uint16_t command; - uint8_t command_version; - uint8_t reserved; - uint16_t data_len; -}; - -struct ec_params_hello { - uint32_t in_data; -}; - -struct ec_response_hello { - uint32_t out_data; -}; - -struct ec_params_get_cmd_versions { - uint8_t cmd; -}; - -struct ec_response_get_cmd_versions { - uint32_t version_mask; -}; - -enum ec_comms_status { - EC_COMMS_STATUS_PROCESSING = 1, -}; - -struct ec_response_get_comms_status { - uint32_t flags; -}; - -struct ec_response_get_protocol_info { - uint32_t protocol_versions; - uint16_t max_request_packet_size; - uint16_t max_response_packet_size; - uint32_t flags; -}; - -enum ec_led_colors { - EC_LED_COLOR_RED = 0, - EC_LED_COLOR_GREEN = 1, - EC_LED_COLOR_BLUE = 2, - EC_LED_COLOR_YELLOW = 3, - EC_LED_COLOR_WHITE = 4, - EC_LED_COLOR_AMBER = 5, - EC_LED_COLOR_COUNT = 6, -}; - -enum motionsense_command { - MOTIONSENSE_CMD_DUMP = 0, - MOTIONSENSE_CMD_INFO = 1, - MOTIONSENSE_CMD_EC_RATE = 2, - MOTIONSENSE_CMD_SENSOR_ODR = 3, - MOTIONSENSE_CMD_SENSOR_RANGE = 4, - MOTIONSENSE_CMD_KB_WAKE_ANGLE = 5, - MOTIONSENSE_CMD_DATA = 6, - MOTIONSENSE_CMD_FIFO_INFO = 7, - MOTIONSENSE_CMD_FIFO_FLUSH = 8, - MOTIONSENSE_CMD_FIFO_READ = 9, - MOTIONSENSE_CMD_PERFORM_CALIB = 10, - MOTIONSENSE_CMD_SENSOR_OFFSET = 11, - MOTIONSENSE_CMD_LIST_ACTIVITIES = 12, - MOTIONSENSE_CMD_SET_ACTIVITY = 13, - MOTIONSENSE_CMD_LID_ANGLE = 14, - MOTIONSENSE_CMD_FIFO_INT_ENABLE = 15, - MOTIONSENSE_CMD_SPOOF = 16, - MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE = 17, - MOTIONSENSE_CMD_SENSOR_SCALE = 18, - MOTIONSENSE_NUM_CMDS = 19, -}; - -struct ec_response_motion_sensor_data { - uint8_t flags; - uint8_t sensor_num; - union { - int16_t data[3]; - struct { - uint16_t reserved; - uint32_t timestamp; - } __attribute__((packed)); - struct { - uint8_t activity; - uint8_t state; - int16_t add_info[2]; - }; - }; -} __attribute__((packed)); - -struct ec_response_motion_sense_fifo_info { - uint16_t size; - uint16_t count; - uint32_t timestamp; - uint16_t total_lost; - uint16_t lost[0]; -} __attribute__((packed)); - -struct ec_response_motion_sense_fifo_data { - uint32_t number_data; - struct ec_response_motion_sensor_data data[0]; -}; - -struct ec_motion_sense_activity { - uint8_t sensor_num; - uint8_t activity; - uint8_t enable; - uint8_t reserved; - uint16_t parameters[3]; -}; - -struct ec_params_motion_sense { - uint8_t cmd; - union { - struct { - uint8_t max_sensor_count; - } dump; - struct { - int16_t data; - } kb_wake_angle; - struct { - uint8_t sensor_num; - } info; - struct { - uint8_t sensor_num; - } info_3; - struct { - uint8_t sensor_num; - } data; - struct { - uint8_t sensor_num; - } fifo_flush; - struct { - uint8_t sensor_num; - } perform_calib; - struct { - uint8_t sensor_num; - } list_activities; - struct { - uint8_t sensor_num; - uint8_t roundup; - uint16_t reserved; - int32_t data; - } ec_rate; - struct { - uint8_t sensor_num; - uint8_t roundup; - uint16_t reserved; - int32_t data; - } sensor_odr; - struct { - uint8_t sensor_num; - uint8_t roundup; - uint16_t reserved; - int32_t data; - } sensor_range; - struct { - uint8_t sensor_num; - uint16_t flags; - int16_t temp; - int16_t offset[3]; - } __attribute__((packed)) sensor_offset; - struct { - uint8_t sensor_num; - uint16_t flags; - int16_t temp; - uint16_t scale[3]; - } __attribute__((packed)) sensor_scale; - struct { - uint32_t max_data_vector; - } fifo_read; - struct ec_motion_sense_activity set_activity; - struct { - int8_t enable; - } fifo_int_enable; - struct { - uint8_t sensor_id; - uint8_t spoof_enable; - uint8_t reserved; - int16_t components[3]; - } __attribute__((packed)) spoof; - struct { - int16_t lid_angle; - int16_t hys_degree; - } tablet_mode_threshold; - }; -} __attribute__((packed)); - -struct ec_response_motion_sense { - union { - struct { - uint8_t module_flags; - uint8_t sensor_count; - struct ec_response_motion_sensor_data sensor[0]; - } __attribute__((packed)) dump; - struct { - uint8_t type; - uint8_t location; - uint8_t chip; - } info; - struct { - uint8_t type; - uint8_t location; - uint8_t chip; - uint32_t min_frequency; - uint32_t max_frequency; - uint32_t fifo_max_event_count; - } info_3; - struct ec_response_motion_sensor_data data; - struct { - int32_t ret; - } ec_rate; - struct { - int32_t ret; - } sensor_odr; - struct { - int32_t ret; - } sensor_range; - struct { - int32_t ret; - } kb_wake_angle; - struct { - int32_t ret; - } fifo_int_enable; - struct { - int32_t ret; - } spoof; - struct { - int16_t temp; - int16_t offset[3]; - } sensor_offset; - struct { - int16_t temp; - int16_t offset[3]; - } perform_calib; - struct { - int16_t temp; - uint16_t scale[3]; - } sensor_scale; - struct ec_response_motion_sense_fifo_info fifo_info; - struct ec_response_motion_sense_fifo_info fifo_flush; - struct ec_response_motion_sense_fifo_data fifo_read; - struct { - uint16_t reserved; - uint32_t enabled; - uint32_t disabled; - } __attribute__((packed)) list_activities; - struct { - uint16_t value; - } lid_angle; - struct { - uint16_t lid_angle; - uint16_t hys_degree; - } tablet_mode_threshold; - }; -}; - -enum ec_temp_thresholds { - EC_TEMP_THRESH_WARN = 0, - EC_TEMP_THRESH_HIGH = 1, - EC_TEMP_THRESH_HALT = 2, - EC_TEMP_THRESH_COUNT = 3, -}; - -enum ec_mkbp_event { - EC_MKBP_EVENT_KEY_MATRIX = 0, - EC_MKBP_EVENT_HOST_EVENT = 1, - EC_MKBP_EVENT_SENSOR_FIFO = 2, - EC_MKBP_EVENT_BUTTON = 3, - EC_MKBP_EVENT_SWITCH = 4, - EC_MKBP_EVENT_FINGERPRINT = 5, - EC_MKBP_EVENT_SYSRQ = 6, - EC_MKBP_EVENT_HOST_EVENT64 = 7, - EC_MKBP_EVENT_CEC_EVENT = 8, - EC_MKBP_EVENT_CEC_MESSAGE = 9, - EC_MKBP_EVENT_COUNT = 10, -}; - -union ec_response_get_next_data_v1 { - uint8_t key_matrix[16]; - uint32_t host_event; - uint64_t host_event64; - struct { - uint8_t reserved[3]; - struct ec_response_motion_sense_fifo_info info; - } __attribute__((packed)) sensor_fifo; - uint32_t buttons; - uint32_t switches; - uint32_t fp_events; - uint32_t sysrq; - uint32_t cec_events; - uint8_t cec_message[16]; -}; - -struct ec_response_get_next_event_v1 { - uint8_t event_type; - union ec_response_get_next_data_v1 data; -} __attribute__((packed)); - -struct ec_response_host_event_mask { - uint32_t mask; -}; - -enum { - EC_MSG_TX_HEADER_BYTES = 3, - EC_MSG_TX_TRAILER_BYTES = 1, - EC_MSG_TX_PROTO_BYTES = 4, - EC_MSG_RX_PROTO_BYTES = 3, - EC_PROTO2_MSG_BYTES = 256, - EC_MAX_MSG_BYTES = 65536, -}; - -struct cros_ec_command { - uint32_t version; - uint32_t command; - uint32_t outsize; - uint32_t insize; - uint32_t result; - uint8_t data[0]; -}; - -struct cros_ec_device { - const char *phys_name; - struct device *dev; - bool was_wake_device; - struct class *cros_class; - int (*cmd_readmem)(struct cros_ec_device *, unsigned int, unsigned int, void *); - u16 max_request; - u16 max_response; - u16 max_passthru; - u16 proto_version; - void *priv; - int irq; - u8 *din; - u8 *dout; - int din_size; - int dout_size; - bool wake_enabled; - bool suspended; - int (*cmd_xfer)(struct cros_ec_device *, struct cros_ec_command *); - int (*pkt_xfer)(struct cros_ec_device *, struct cros_ec_command *); - struct mutex lock; - u8 mkbp_event_supported; - bool host_sleep_v1; - struct blocking_notifier_head event_notifier; - struct ec_response_get_next_event_v1 event_data; - int event_size; - u32 host_event_wake_mask; - u32 last_resume_result; - ktime_t last_event_time; - struct notifier_block notifier_ready; - struct platform_device *ec; - struct platform_device *pd; -}; - -struct cros_ec_debugfs; - -struct cros_ec_dev { - struct device class_dev; - struct cros_ec_device *ec_dev; - struct device *dev; - struct cros_ec_debugfs *debug_info; - bool has_kb_wake_angle; - u16 cmd_offset; - u32 features[2]; -}; - -struct trace_event_raw_cros_ec_request_start { - struct trace_entry ent; - uint32_t version; - uint32_t offset; - uint32_t command; - uint32_t outsize; - uint32_t insize; - char __data[0]; -}; - -struct trace_event_raw_cros_ec_request_done { - struct trace_entry ent; - uint32_t version; - uint32_t offset; - uint32_t command; - uint32_t outsize; - uint32_t insize; - uint32_t result; - int retval; - char __data[0]; -}; - -struct trace_event_data_offsets_cros_ec_request_start {}; - -struct trace_event_data_offsets_cros_ec_request_done {}; - -typedef void (*btf_trace_cros_ec_request_start)(void *, struct cros_ec_command *); - -typedef void (*btf_trace_cros_ec_request_done)(void *, struct cros_ec_command *, int); - -struct acpi_table_pcct { - struct acpi_table_header header; - u32 flags; - u64 reserved; -}; - -enum acpi_pcct_type { - ACPI_PCCT_TYPE_GENERIC_SUBSPACE = 0, - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE = 1, - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2 = 2, - ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE = 3, - ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE = 4, - ACPI_PCCT_TYPE_HW_REG_COMM_SUBSPACE = 5, - ACPI_PCCT_TYPE_RESERVED = 6, -}; - -struct acpi_pcct_subspace { - struct acpi_subtable_header header; - u8 reserved[6]; - u64 base_address; - u64 length; - struct acpi_generic_address doorbell_register; - u64 preserve_mask; - u64 write_mask; - u32 latency; - u32 max_access_rate; - u16 min_turnaround_time; -} __attribute__((packed)); - -struct acpi_pcct_hw_reduced_type2 { - struct acpi_subtable_header header; - u32 platform_interrupt; - u8 flags; - u8 reserved; - u64 base_address; - u64 length; - struct acpi_generic_address doorbell_register; - u64 preserve_mask; - u64 write_mask; - u32 latency; - u32 max_access_rate; - u16 min_turnaround_time; - struct acpi_generic_address platform_ack_register; - u64 ack_preserve_mask; - u64 ack_write_mask; -} __attribute__((packed)); - -struct hwspinlock___2; - -struct hwspinlock_ops { - int (*trylock)(struct hwspinlock___2 *); - void (*unlock)(struct hwspinlock___2 *); - void (*relax)(struct hwspinlock___2 *); -}; - -struct hwspinlock_device; - -struct hwspinlock___2 { - struct hwspinlock_device *bank; - spinlock_t lock; - void *priv; -}; - -struct hwspinlock_device { - struct device *dev; - const struct hwspinlock_ops *ops; - int base_id; - int num_locks; - struct hwspinlock___2 lock[0]; -}; - -struct resource_table { - u32 ver; - u32 num; - u32 reserved[2]; - u32 offset[0]; -}; - -struct fw_rsc_hdr { - u32 type; - u8 data[0]; -}; - -enum fw_resource_type { - RSC_CARVEOUT = 0, - RSC_DEVMEM = 1, - RSC_TRACE = 2, - RSC_VDEV = 3, - RSC_LAST = 4, - RSC_VENDOR_START = 128, - RSC_VENDOR_END = 512, -}; - -struct fw_rsc_carveout { - u32 da; - u32 pa; - u32 len; - u32 flags; - u32 reserved; - u8 name[32]; -}; - -struct fw_rsc_devmem { - u32 da; - u32 pa; - u32 len; - u32 flags; - u32 reserved; - u8 name[32]; -}; - -struct fw_rsc_trace { - u32 da; - u32 len; - u32 reserved; - u8 name[32]; -}; - -struct fw_rsc_vdev_vring { - u32 da; - u32 align; - u32 num; - u32 notifyid; - u32 pa; -}; - -struct fw_rsc_vdev { - u32 id; - u32 notifyid; - u32 dfeatures; - u32 gfeatures; - u32 config_len; - u8 status; - u8 num_of_vrings; - u8 reserved[2]; - struct fw_rsc_vdev_vring vring[0]; -}; - -struct rproc; - -struct rproc_mem_entry { - void *va; - bool is_iomem; - dma_addr_t dma; - size_t len; - u32 da; - void *priv; - char name[32]; - struct list_head node; - u32 rsc_offset; - u32 flags; - u32 of_resm_idx; - int (*alloc)(struct rproc *, struct rproc_mem_entry *); - int (*release)(struct rproc *, struct rproc_mem_entry *); -}; - -enum rproc_dump_mechanism { - RPROC_COREDUMP_DISABLED = 0, - RPROC_COREDUMP_ENABLED = 1, - RPROC_COREDUMP_INLINE = 2, -}; - -struct rproc_ops; - -struct rproc { - struct list_head node; - struct iommu_domain *domain; - const char *name; - const char *firmware; - void *priv; - struct rproc_ops *ops; - struct device dev; - atomic_t power; - unsigned int state; - enum rproc_dump_mechanism dump_conf; - struct mutex lock; - struct dentry *dbg_dir; - struct list_head traces; - int num_traces; - struct list_head carveouts; - struct list_head mappings; - u64 bootaddr; - struct list_head rvdevs; - struct list_head subdevs; - struct idr notifyids; - int index; - struct work_struct crash_handler; - unsigned int crash_cnt; - bool recovery_disabled; - int max_notifyid; - struct resource_table *table_ptr; - struct resource_table *clean_table; - struct resource_table *cached_table; - size_t table_sz; - bool has_iommu; - bool auto_boot; - struct list_head dump_segments; - int nb_vdev; - u8 elf_class; - u16 elf_machine; - struct cdev cdev; - bool cdev_put_on_release; -}; - -enum rsc_handling_status { - RSC_HANDLED = 0, - RSC_IGNORED = 1, -}; - -struct rproc_ops { - int (*prepare)(struct rproc *); - int (*unprepare)(struct rproc *); - int (*start)(struct rproc *); - int (*stop)(struct rproc *); - int (*attach)(struct rproc *); - int (*detach)(struct rproc *); - void (*kick)(struct rproc *, int); - void * (*da_to_va)(struct rproc *, u64, size_t, bool *); - int (*parse_fw)(struct rproc *, const struct firmware *); - int (*handle_rsc)(struct rproc *, u32, void *, int, int); - struct resource_table * (*find_loaded_rsc_table)(struct rproc *, const struct firmware *); - struct resource_table * (*get_loaded_rsc_table)(struct rproc *, size_t *); - int (*load)(struct rproc *, const struct firmware *); - int (*sanity_check)(struct rproc *, const struct firmware *); - u64 (*get_boot_addr)(struct rproc *, const struct firmware *); - long unsigned int (*panic)(struct rproc *); - void (*coredump)(struct rproc *); -}; - -enum rproc_state { - RPROC_OFFLINE = 0, - RPROC_SUSPENDED = 1, - RPROC_RUNNING = 2, - RPROC_CRASHED = 3, - RPROC_DELETED = 4, - RPROC_ATTACHED = 5, - RPROC_DETACHED = 6, - RPROC_LAST = 7, -}; - -enum rproc_crash_type { - RPROC_MMUFAULT = 0, - RPROC_WATCHDOG = 1, - RPROC_FATAL_ERROR = 2, -}; - -struct rproc_subdev { - struct list_head node; - int (*prepare)(struct rproc_subdev *); - int (*start)(struct rproc_subdev *); - void (*stop)(struct rproc_subdev *, bool); - void (*unprepare)(struct rproc_subdev *); -}; - -struct rproc_vdev; - -struct rproc_vring { - void *va; - int len; - u32 da; - u32 align; - int notifyid; - struct rproc_vdev *rvdev; - struct virtqueue *vq; -}; - -struct rproc_vdev { - struct kref refcount; - struct rproc_subdev subdev; - struct device dev; - unsigned int id; - struct list_head node; - struct rproc *rproc; - struct rproc_vring vring[2]; - u32 rsc_offset; - u32 index; -}; - -struct rproc_debug_trace { - struct rproc *rproc; - struct dentry *tfile; - struct list_head node; - struct rproc_mem_entry trace_mem; -}; - -typedef int (*rproc_handle_resource_t)(struct rproc *, void *, int, int); - -struct rproc_dump_segment { - struct list_head node; - dma_addr_t da; - size_t size; - void *priv; - void (*dump)(struct rproc *, struct rproc_dump_segment *, void *, size_t, size_t); - loff_t offset; -}; - -struct rproc_coredump_state { - struct rproc *rproc; - void *header; - struct completion dump_done; -}; - -struct devfreq_freqs { - long unsigned int old; - long unsigned int new; -}; - -struct devfreq_passive_data { - struct devfreq *parent; - int (*get_target_freq)(struct devfreq *, long unsigned int *); - struct devfreq *this; - struct notifier_block nb; -}; - -struct trace_event_raw_devfreq_frequency { - struct trace_entry ent; - u32 __data_loc_dev_name; - long unsigned int freq; - long unsigned int prev_freq; - long unsigned int busy_time; - long unsigned int total_time; - char __data[0]; -}; - -struct trace_event_raw_devfreq_monitor { - struct trace_entry ent; - long unsigned int freq; - long unsigned int busy_time; - long unsigned int total_time; - unsigned int polling_ms; - u32 __data_loc_dev_name; - char __data[0]; -}; - -struct trace_event_data_offsets_devfreq_frequency { - u32 dev_name; -}; - -struct trace_event_data_offsets_devfreq_monitor { - u32 dev_name; -}; - -typedef void (*btf_trace_devfreq_frequency)(void *, struct devfreq *, long unsigned int, long unsigned int); - -typedef void (*btf_trace_devfreq_monitor)(void *, struct devfreq *); - -struct devfreq_notifier_devres { - struct devfreq *devfreq; - struct notifier_block *nb; - unsigned int list; -}; - -struct devfreq_event_desc; - -struct devfreq_event_dev { - struct list_head node; - struct device dev; - struct mutex lock; - u32 enable_count; - const struct devfreq_event_desc *desc; -}; - -struct devfreq_event_ops; - -struct devfreq_event_desc { - const char *name; - u32 event_type; - void *driver_data; - const struct devfreq_event_ops *ops; -}; - -struct devfreq_event_data { - long unsigned int load_count; - long unsigned int total_count; -}; - -struct devfreq_event_ops { - int (*enable)(struct devfreq_event_dev *); - int (*disable)(struct devfreq_event_dev *); - int (*reset)(struct devfreq_event_dev *); - int (*set_event)(struct devfreq_event_dev *); - int (*get_event)(struct devfreq_event_dev *, struct devfreq_event_data *); -}; - -union extcon_property_value { - int intval; -}; - -struct extcon_cable; - -struct extcon_dev___2 { - const char *name; - const unsigned int *supported_cable; - const u32 *mutually_exclusive; - struct device dev; - struct raw_notifier_head nh_all; - struct raw_notifier_head *nh; - struct list_head entry; - int max_supported; - spinlock_t lock; - u32 state; - struct device_type extcon_dev_type; - struct extcon_cable *cables; - struct attribute_group attr_g_muex; - struct attribute **attrs_muex; - struct device_attribute *d_attrs_muex; -}; - -struct extcon_cable { - struct extcon_dev___2 *edev; - int cable_index; - struct attribute_group attr_g; - struct device_attribute attr_name; - struct device_attribute attr_state; - struct attribute *attrs[3]; - union extcon_property_value usb_propval[3]; - union extcon_property_value chg_propval[1]; - union extcon_property_value jack_propval[1]; - union extcon_property_value disp_propval[2]; - long unsigned int usb_bits[1]; - long unsigned int chg_bits[1]; - long unsigned int jack_bits[1]; - long unsigned int disp_bits[1]; -}; - -struct __extcon_info { - unsigned int type; - unsigned int id; - const char *name; -}; - -struct extcon_dev_notifier_devres { - struct extcon_dev___2 *edev; - unsigned int id; - struct notifier_block *nb; -}; - -struct powercap_control_type; - -struct powercap_control_type_ops { - int (*set_enable)(struct powercap_control_type *, bool); - int (*get_enable)(struct powercap_control_type *, bool *); - int (*release)(struct powercap_control_type *); -}; - -struct powercap_control_type { - struct device dev; - struct idr idr; - int nr_zones; - const struct powercap_control_type_ops *ops; - struct mutex lock; - bool allocated; - struct list_head node; -}; - -struct powercap_zone; - -struct powercap_zone_ops { - int (*get_max_energy_range_uj)(struct powercap_zone *, u64 *); - int (*get_energy_uj)(struct powercap_zone *, u64 *); - int (*reset_energy_uj)(struct powercap_zone *); - int (*get_max_power_range_uw)(struct powercap_zone *, u64 *); - int (*get_power_uw)(struct powercap_zone *, u64 *); - int (*set_enable)(struct powercap_zone *, bool); - int (*get_enable)(struct powercap_zone *, bool *); - int (*release)(struct powercap_zone *); -}; - -struct powercap_zone_constraint; - -struct powercap_zone { - int id; - char *name; - void *control_type_inst; - const struct powercap_zone_ops *ops; - struct device dev; - int const_id_cnt; - struct idr idr; - struct idr *parent_idr; - void *private_data; - struct attribute **zone_dev_attrs; - int zone_attr_count; - struct attribute_group dev_zone_attr_group; - const struct attribute_group *dev_attr_groups[2]; - bool allocated; - struct powercap_zone_constraint *constraints; -}; - -struct powercap_zone_constraint_ops; - -struct powercap_zone_constraint { - int id; - struct powercap_zone *power_zone; - const struct powercap_zone_constraint_ops *ops; -}; - -struct powercap_zone_constraint_ops { - int (*set_power_limit_uw)(struct powercap_zone *, int, u64); - int (*get_power_limit_uw)(struct powercap_zone *, int, u64 *); - int (*set_time_window_us)(struct powercap_zone *, int, u64); - int (*get_time_window_us)(struct powercap_zone *, int, u64 *); - int (*get_max_power_uw)(struct powercap_zone *, int, u64 *); - int (*get_min_power_uw)(struct powercap_zone *, int, u64 *); - int (*get_max_time_window_us)(struct powercap_zone *, int, u64 *); - int (*get_min_time_window_us)(struct powercap_zone *, int, u64 *); - const char * (*get_name)(struct powercap_zone *, int); -}; - -struct dtpm_ops; - -struct dtpm { - struct powercap_zone zone; - struct dtpm *parent; - struct list_head sibling; - struct list_head children; - struct dtpm_ops *ops; - long unsigned int flags; - u64 power_limit; - u64 power_max; - u64 power_min; - int weight; - void *private; -}; - -struct dtpm_ops { - u64 (*set_power_uw)(struct dtpm *, u64); - u64 (*get_power_uw)(struct dtpm *); - void (*release)(struct dtpm *); -}; - -struct dtpm_descr; - -typedef int (*dtpm_init_t)(struct dtpm_descr *); - -struct dtpm_descr { - struct dtpm *parent; - const char *name; - dtpm_init_t init; -}; - -struct dtpm_cpu { - struct freq_qos_request qos_req; - int cpu; -}; - -struct powercap_constraint_attr { - struct device_attribute power_limit_attr; - struct device_attribute time_window_attr; - struct device_attribute max_power_attr; - struct device_attribute min_power_attr; - struct device_attribute max_time_window_attr; - struct device_attribute min_time_window_attr; - struct device_attribute name_attr; -}; - -struct idle_inject_thread { - struct task_struct *tsk; - int should_run; -}; - -struct idle_inject_device { - struct hrtimer timer; - unsigned int idle_duration_us; - unsigned int run_duration_us; - unsigned int latency_us; - long unsigned int cpumask[0]; -}; - -struct trace_event_raw_extlog_mem_event { - struct trace_entry ent; - u32 err_seq; - u8 etype; - u8 sev; - u64 pa; - u8 pa_mask_lsb; - guid_t fru_id; - u32 __data_loc_fru_text; - struct cper_mem_err_compact data; - char __data[0]; -}; - -struct trace_event_raw_mc_event { - struct trace_entry ent; - unsigned int error_type; - u32 __data_loc_msg; - u32 __data_loc_label; - u16 error_count; - u8 mc_index; - s8 top_layer; - s8 middle_layer; - s8 lower_layer; - long int address; - u8 grain_bits; - long int syndrome; - u32 __data_loc_driver_detail; - char __data[0]; -}; - -struct trace_event_raw_arm_event { - struct trace_entry ent; - u64 mpidr; - u64 midr; - u32 running_state; - u32 psci_state; - u8 affinity; - char __data[0]; -}; - -struct trace_event_raw_non_standard_event { - struct trace_entry ent; - char sec_type[16]; - char fru_id[16]; - u32 __data_loc_fru_text; - u8 sev; - u32 len; - u32 __data_loc_buf; - char __data[0]; -}; - -struct trace_event_raw_aer_event { - struct trace_entry ent; - u32 __data_loc_dev_name; - u32 status; - u8 severity; - u8 tlp_header_valid; - u32 tlp_header[4]; - char __data[0]; -}; - -struct trace_event_raw_memory_failure_event { - struct trace_entry ent; - long unsigned int pfn; - int type; - int result; - char __data[0]; -}; - -struct trace_event_data_offsets_extlog_mem_event { - u32 fru_text; -}; - -struct trace_event_data_offsets_mc_event { - u32 msg; - u32 label; - u32 driver_detail; -}; - -struct trace_event_data_offsets_arm_event {}; - -struct trace_event_data_offsets_non_standard_event { - u32 fru_text; - u32 buf; -}; - -struct trace_event_data_offsets_aer_event { - u32 dev_name; -}; - -struct trace_event_data_offsets_memory_failure_event {}; - -typedef void (*btf_trace_extlog_mem_event)(void *, struct cper_sec_mem_err *, u32, const guid_t *, const char *, u8); - -typedef void (*btf_trace_mc_event)(void *, const unsigned int, const char *, const char *, const int, const u8, const s8, const s8, const s8, long unsigned int, const u8, long unsigned int, const char *); - -typedef void (*btf_trace_arm_event)(void *, const struct cper_sec_proc_arm *); - -typedef void (*btf_trace_non_standard_event)(void *, const guid_t *, const guid_t *, const char *, const u8, const u8 *, const u32); - -typedef void (*btf_trace_aer_event)(void *, const char *, const u32, const u8, const u8, struct aer_header_log_regs *); - -typedef void (*btf_trace_memory_failure_event)(void *, long unsigned int, int, int); - -struct ce_array { - u64 *array; - unsigned int n; - unsigned int decay_count; - u64 pfns_poisoned; - u64 ces_entered; - u64 decays_done; - union { - struct { - __u32 disabled: 1; - __u32 __resv: 31; - }; - __u32 flags; - }; -}; - -struct nvmem_cell_lookup { - const char *nvmem_name; - const char *cell_name; - const char *dev_id; - const char *con_id; - struct list_head node; -}; - -enum { - NVMEM_ADD = 1, - NVMEM_REMOVE = 2, - NVMEM_CELL_ADD = 3, - NVMEM_CELL_REMOVE = 4, -}; - -struct nvmem_cell_table { - const char *nvmem_name; - const struct nvmem_cell_info *cells; - size_t ncells; - struct list_head node; -}; - -struct nvmem_device___2 { - struct module *owner; - struct device dev; - int stride; - int word_size; - int id; - struct kref refcnt; - size_t size; - bool read_only; - bool root_only; - int flags; - enum nvmem_type type; - struct bin_attribute eeprom; - struct device *base_dev; - struct list_head cells; - const struct nvmem_keepout *keepout; - unsigned int nkeepout; - nvmem_reg_read_t reg_read; - nvmem_reg_write_t reg_write; - struct gpio_desc *wp_gpio; - void *priv; -}; - -struct nvmem_cell { - const char *name; - int offset; - int bytes; - int bit_offset; - int nbits; - struct device_node *np; - struct nvmem_device___2 *nvmem; - struct list_head node; -}; - -struct icc_node; - -struct icc_req { - struct hlist_node req_node; - struct icc_node *node; - struct device *dev; - bool enabled; - u32 tag; - u32 avg_bw; - u32 peak_bw; -}; - -struct icc_path___2 { - const char *name; - size_t num_nodes; - struct icc_req reqs[0]; -}; - -struct icc_node_data { - struct icc_node *node; - u32 tag; -}; - -struct icc_provider; - -struct icc_node { - int id; - const char *name; - struct icc_node **links; - size_t num_links; - struct icc_provider *provider; - struct list_head node_list; - struct list_head search_list; - struct icc_node *reverse; - u8 is_traversed: 1; - struct hlist_head req_list; - u32 avg_bw; - u32 peak_bw; - u32 init_avg; - u32 init_peak; - void *data; -}; - -struct icc_onecell_data { - unsigned int num_nodes; - struct icc_node *nodes[0]; -}; - -struct icc_provider { - struct list_head provider_list; - struct list_head nodes; - int (*set)(struct icc_node *, struct icc_node *); - int (*aggregate)(struct icc_node *, u32, u32, u32, u32 *, u32 *); - void (*pre_aggregate)(struct icc_node *); - int (*get_bw)(struct icc_node *, u32 *, u32 *); - struct icc_node * (*xlate)(struct of_phandle_args *, void *); - struct icc_node_data * (*xlate_extended)(struct of_phandle_args *, void *); - struct device *dev; - int users; - bool inter_set; - void *data; -}; - -struct trace_event_raw_icc_set_bw { - struct trace_entry ent; - u32 __data_loc_path_name; - u32 __data_loc_dev; - u32 __data_loc_node_name; - u32 avg_bw; - u32 peak_bw; - u32 node_avg_bw; - u32 node_peak_bw; - char __data[0]; -}; - -struct trace_event_raw_icc_set_bw_end { - struct trace_entry ent; - u32 __data_loc_path_name; - u32 __data_loc_dev; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_icc_set_bw { - u32 path_name; - u32 dev; - u32 node_name; -}; - -struct trace_event_data_offsets_icc_set_bw_end { - u32 path_name; - u32 dev; -}; - -typedef void (*btf_trace_icc_set_bw)(void *, struct icc_path___2 *, struct icc_node *, int, u32, u32); - -typedef void (*btf_trace_icc_set_bw_end)(void *, struct icc_path___2 *, int); - -struct icc_bulk_data { - struct icc_path *path; - const char *name; - u32 avg_bw; - u32 peak_bw; -}; - -struct net_device_devres { - struct net_device *ndev; -}; - -struct __kernel_old_timespec { - __kernel_old_time_t tv_sec; - long int tv_nsec; -}; - -struct __kernel_sock_timeval { - __s64 tv_sec; - __s64 tv_usec; -}; - -struct mmsghdr { - struct user_msghdr msg_hdr; - unsigned int msg_len; -}; - -struct scm_timestamping_internal { - struct timespec64 ts[3]; -}; - -struct ifconf { - int ifc_len; - union { - char *ifcu_buf; - struct ifreq *ifcu_req; - } ifc_ifcu; -}; - -struct compat_ifmap { - compat_ulong_t mem_start; - compat_ulong_t mem_end; - short unsigned int base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct compat_if_settings { - unsigned int type; - unsigned int size; - compat_uptr_t ifs_ifsu; -}; - -struct compat_ifreq { - union { - char ifrn_name[16]; - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short int ifru_flags; - compat_int_t ifru_ivalue; - compat_int_t ifru_mtu; - struct compat_ifmap ifru_map; - char ifru_slave[16]; - char ifru_newname[16]; - compat_caddr_t ifru_data; - struct compat_if_settings ifru_settings; - } ifr_ifru; -}; - -struct compat_ifconf { - compat_int_t ifc_len; - compat_caddr_t ifcbuf; -}; - -enum sock_shutdown_cmd { - SHUT_RD = 0, - SHUT_WR = 1, - SHUT_RDWR = 2, -}; - -struct net_proto_family { - int family; - int (*create)(struct net *, struct socket *, int, int); - struct module *owner; -}; - -enum { - SOCK_WAKE_IO = 0, - SOCK_WAKE_WAITD = 1, - SOCK_WAKE_SPACE = 2, - SOCK_WAKE_URG = 3, -}; - -struct compat_ethtool_rx_flow_spec { - u32 flow_type; - union ethtool_flow_union h_u; - struct ethtool_flow_ext h_ext; - union ethtool_flow_union m_u; - struct ethtool_flow_ext m_ext; - compat_u64 ring_cookie; - u32 location; -} __attribute__((packed)); - -struct compat_ethtool_rxnfc { - u32 cmd; - u32 flow_type; - compat_u64 data; - struct compat_ethtool_rx_flow_spec fs; - u32 rule_cnt; - u32 rule_locs[0]; -} __attribute__((packed)); - -struct libipw_device; - -struct iw_spy_data; - -struct iw_public_data { - struct iw_spy_data *spy_data; - struct libipw_device *libipw; -}; - -struct iw_param { - __s32 value; - __u8 fixed; - __u8 disabled; - __u16 flags; -}; - -struct iw_point { - void *pointer; - __u16 length; - __u16 flags; -}; - -struct iw_freq { - __s32 m; - __s16 e; - __u8 i; - __u8 flags; -}; - -struct iw_quality { - __u8 qual; - __u8 level; - __u8 noise; - __u8 updated; -}; - -struct iw_discarded { - __u32 nwid; - __u32 code; - __u32 fragment; - __u32 retries; - __u32 misc; -}; - -struct iw_missed { - __u32 beacon; -}; - -struct iw_statistics { - __u16 status; - struct iw_quality qual; - struct iw_discarded discard; - struct iw_missed miss; -}; - -union iwreq_data { - char name[16]; - struct iw_point essid; - struct iw_param nwid; - struct iw_freq freq; - struct iw_param sens; - struct iw_param bitrate; - struct iw_param txpower; - struct iw_param rts; - struct iw_param frag; - __u32 mode; - struct iw_param retry; - struct iw_point encoding; - struct iw_param power; - struct iw_quality qual; - struct sockaddr ap_addr; - struct sockaddr addr; - struct iw_param param; - struct iw_point data; -}; - -struct iw_priv_args { - __u32 cmd; - __u16 set_args; - __u16 get_args; - char name[16]; -}; - -struct compat_mmsghdr { - struct compat_msghdr msg_hdr; - compat_uint_t msg_len; -}; - -struct iw_request_info { - __u16 cmd; - __u16 flags; -}; - -struct iw_spy_data { - int spy_number; - u_char spy_address[48]; - struct iw_quality spy_stat[8]; - struct iw_quality spy_thr_low; - struct iw_quality spy_thr_high; - u_char spy_thr_under[8]; -}; - -enum { - SOF_TIMESTAMPING_TX_HARDWARE = 1, - SOF_TIMESTAMPING_TX_SOFTWARE = 2, - SOF_TIMESTAMPING_RX_HARDWARE = 4, - SOF_TIMESTAMPING_RX_SOFTWARE = 8, - SOF_TIMESTAMPING_SOFTWARE = 16, - SOF_TIMESTAMPING_SYS_HARDWARE = 32, - SOF_TIMESTAMPING_RAW_HARDWARE = 64, - SOF_TIMESTAMPING_OPT_ID = 128, - SOF_TIMESTAMPING_TX_SCHED = 256, - SOF_TIMESTAMPING_TX_ACK = 512, - SOF_TIMESTAMPING_OPT_CMSG = 1024, - SOF_TIMESTAMPING_OPT_TSONLY = 2048, - SOF_TIMESTAMPING_OPT_STATS = 4096, - SOF_TIMESTAMPING_OPT_PKTINFO = 8192, - SOF_TIMESTAMPING_OPT_TX_SWHW = 16384, - SOF_TIMESTAMPING_BIND_PHC = 32768, - SOF_TIMESTAMPING_LAST = 32768, - SOF_TIMESTAMPING_MASK = 65535, -}; - -struct scm_ts_pktinfo { - __u32 if_index; - __u32 pkt_length; - __u32 reserved[2]; -}; - -struct sock_skb_cb { - u32 dropcount; -}; - -struct sock_ee_data_rfc4884 { - __u16 len; - __u8 flags; - __u8 reserved; -}; - -struct sock_extended_err { - __u32 ee_errno; - __u8 ee_origin; - __u8 ee_type; - __u8 ee_code; - __u8 ee_pad; - __u32 ee_info; - union { - __u32 ee_data; - struct sock_ee_data_rfc4884 ee_rfc4884; - }; -}; - -struct sock_exterr_skb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - struct sock_extended_err ee; - u16 addr_offset; - __be16 port; - u8 opt_stats: 1; - u8 unused: 7; -}; - -struct used_address { - struct __kernel_sockaddr_storage name; - unsigned int name_len; -}; - -struct linger { - int l_onoff; - int l_linger; -}; - -struct cmsghdr { - __kernel_size_t cmsg_len; - int cmsg_level; - int cmsg_type; -}; - -struct ucred { - __u32 pid; - __u32 uid; - __u32 gid; -}; - -struct mmpin { - struct user_struct *user; - unsigned int num_pg; -}; - -struct ubuf_info { - void (*callback)(struct sk_buff *, struct ubuf_info *, bool); - union { - struct { - long unsigned int desc; - void *ctx; - }; - struct { - u32 id; - u16 len; - u16 zerocopy: 1; - u32 bytelen; - }; - }; - refcount_t refcnt; - u8 flags; - struct mmpin mmp; -}; - -enum { - SKB_GSO_TCPV4 = 1, - SKB_GSO_DODGY = 2, - SKB_GSO_TCP_ECN = 4, - SKB_GSO_TCP_FIXEDID = 8, - SKB_GSO_TCPV6 = 16, - SKB_GSO_FCOE = 32, - SKB_GSO_GRE = 64, - SKB_GSO_GRE_CSUM = 128, - SKB_GSO_IPXIP4 = 256, - SKB_GSO_IPXIP6 = 512, - SKB_GSO_UDP_TUNNEL = 1024, - SKB_GSO_UDP_TUNNEL_CSUM = 2048, - SKB_GSO_PARTIAL = 4096, - SKB_GSO_TUNNEL_REMCSUM = 8192, - SKB_GSO_SCTP = 16384, - SKB_GSO_ESP = 32768, - SKB_GSO_UDP = 65536, - SKB_GSO_UDP_L4 = 131072, - SKB_GSO_FRAGLIST = 262144, -}; - -struct prot_inuse { - int val[64]; -}; - -struct gro_list { - struct list_head list; - int count; -}; - -struct napi_struct { - struct list_head poll_list; - long unsigned int state; - int weight; - int defer_hard_irqs_count; - long unsigned int gro_bitmask; - int (*poll)(struct napi_struct *, int); - int poll_owner; - struct net_device *dev; - struct gro_list gro_hash[8]; - struct sk_buff *skb; - struct list_head rx_list; - int rx_count; - struct hrtimer timer; - struct list_head dev_list; - struct hlist_node napi_hash_node; - unsigned int napi_id; - struct task_struct *thread; -}; - -struct sd_flow_limit { - u64 count; - unsigned int num_buckets; - unsigned int history_head; - u16 history[128]; - u8 buckets[0]; -}; - -struct softnet_data { - struct list_head poll_list; - struct sk_buff_head process_queue; - unsigned int processed; - unsigned int time_squeeze; - unsigned int received_rps; - struct softnet_data *rps_ipi_list; - struct sd_flow_limit *flow_limit; - struct Qdisc *output_queue; - struct Qdisc **output_queue_tailp; - struct sk_buff *completion_queue; - struct sk_buff_head xfrm_backlog; - struct { - u16 recursion; - u8 more; - } xmit; - int: 32; - unsigned int input_queue_head; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - call_single_data_t csd; - struct softnet_data *rps_ipi_next; - unsigned int cpu; - unsigned int input_queue_tail; - unsigned int dropped; - struct sk_buff_head input_pkt_queue; - struct napi_struct backlog; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct so_timestamping { - int flags; - int bind_phc; -}; - -enum txtime_flags { - SOF_TXTIME_DEADLINE_MODE = 1, - SOF_TXTIME_REPORT_ERRORS = 2, - SOF_TXTIME_FLAGS_LAST = 2, - SOF_TXTIME_FLAGS_MASK = 3, -}; - -struct sock_txtime { - __kernel_clockid_t clockid; - __u32 flags; -}; - -enum sk_pacing { - SK_PACING_NONE = 0, - SK_PACING_NEEDED = 1, - SK_PACING_FQ = 2, -}; - -struct sockcm_cookie { - u64 transmit_time; - u32 mark; - u16 tsflags; -}; - -struct inet_bind_bucket { - possible_net_t ib_net; - int l3mdev; - short unsigned int port; - signed char fastreuse; - signed char fastreuseport; - kuid_t fastuid; - struct in6_addr fast_v6_rcv_saddr; - __be32 fast_rcv_saddr; - short unsigned int fast_sk_family; - bool fast_ipv6_only; - struct hlist_node node; - struct hlist_head owners; -}; - -struct tcp_fastopen_cookie { - __le64 val[2]; - s8 len; - bool exp; -}; - -struct tcp_sack_block { - u32 start_seq; - u32 end_seq; -}; - -struct tcp_options_received { - int ts_recent_stamp; - u32 ts_recent; - u32 rcv_tsval; - u32 rcv_tsecr; - u16 saw_tstamp: 1; - u16 tstamp_ok: 1; - u16 dsack: 1; - u16 wscale_ok: 1; - u16 sack_ok: 3; - u16 smc_ok: 1; - u16 snd_wscale: 4; - u16 rcv_wscale: 4; - u8 saw_unknown: 1; - u8 unused: 7; - u8 num_sacks; - u16 user_mss; - u16 mss_clamp; -}; - -struct tcp_rack { - u64 mstamp; - u32 rtt_us; - u32 end_seq; - u32 last_delivered; - u8 reo_wnd_steps; - u8 reo_wnd_persist: 5; - u8 dsack_seen: 1; - u8 advanced: 1; -}; - -struct tcp_sock_af_ops; - -struct tcp_md5sig_info; - -struct tcp_fastopen_request; - -struct tcp_sock { - struct inet_connection_sock inet_conn; - u16 tcp_header_len; - u16 gso_segs; - __be32 pred_flags; - u64 bytes_received; - u32 segs_in; - u32 data_segs_in; - u32 rcv_nxt; - u32 copied_seq; - u32 rcv_wup; - u32 snd_nxt; - u32 segs_out; - u32 data_segs_out; - u64 bytes_sent; - u64 bytes_acked; - u32 dsack_dups; - u32 snd_una; - u32 snd_sml; - u32 rcv_tstamp; - u32 lsndtime; - u32 last_oow_ack_time; - u32 compressed_ack_rcv_nxt; - u32 tsoffset; - struct list_head tsq_node; - struct list_head tsorted_sent_queue; - u32 snd_wl1; - u32 snd_wnd; - u32 max_window; - u32 mss_cache; - u32 window_clamp; - u32 rcv_ssthresh; - struct tcp_rack rack; - u16 advmss; - u8 compressed_ack; - u8 dup_ack_counter: 2; - u8 tlp_retrans: 1; - u8 unused: 5; - u32 chrono_start; - u32 chrono_stat[3]; - u8 chrono_type: 2; - u8 rate_app_limited: 1; - u8 fastopen_connect: 1; - u8 fastopen_no_cookie: 1; - u8 is_sack_reneg: 1; - u8 fastopen_client_fail: 2; - u8 nonagle: 4; - u8 thin_lto: 1; - u8 recvmsg_inq: 1; - u8 repair: 1; - u8 frto: 1; - u8 repair_queue; - u8 save_syn: 2; - u8 syn_data: 1; - u8 syn_fastopen: 1; - u8 syn_fastopen_exp: 1; - u8 syn_fastopen_ch: 1; - u8 syn_data_acked: 1; - u8 is_cwnd_limited: 1; - u32 tlp_high_seq; - u32 tcp_tx_delay; - u64 tcp_wstamp_ns; - u64 tcp_clock_cache; - u64 tcp_mstamp; - u32 srtt_us; - u32 mdev_us; - u32 mdev_max_us; - u32 rttvar_us; - u32 rtt_seq; - struct minmax rtt_min; - u32 packets_out; - u32 retrans_out; - u32 max_packets_out; - u32 max_packets_seq; - u16 urg_data; - u8 ecn_flags; - u8 keepalive_probes; - u32 reordering; - u32 reord_seen; - u32 snd_up; - struct tcp_options_received rx_opt; - u32 snd_ssthresh; - u32 snd_cwnd; - u32 snd_cwnd_cnt; - u32 snd_cwnd_clamp; - u32 snd_cwnd_used; - u32 snd_cwnd_stamp; - u32 prior_cwnd; - u32 prr_delivered; - u32 prr_out; - u32 delivered; - u32 delivered_ce; - u32 lost; - u32 app_limited; - u64 first_tx_mstamp; - u64 delivered_mstamp; - u32 rate_delivered; - u32 rate_interval_us; - u32 rcv_wnd; - u32 write_seq; - u32 notsent_lowat; - u32 pushed_seq; - u32 lost_out; - u32 sacked_out; - struct hrtimer pacing_timer; - struct hrtimer compressed_ack_timer; - struct sk_buff *lost_skb_hint; - struct sk_buff *retransmit_skb_hint; - struct rb_root out_of_order_queue; - struct sk_buff *ooo_last_skb; - struct tcp_sack_block duplicate_sack[1]; - struct tcp_sack_block selective_acks[4]; - struct tcp_sack_block recv_sack_cache[4]; - struct sk_buff *highest_sack; - int lost_cnt_hint; - u32 prior_ssthresh; - u32 high_seq; - u32 retrans_stamp; - u32 undo_marker; - int undo_retrans; - u64 bytes_retrans; - u32 total_retrans; - u32 urg_seq; - unsigned int keepalive_time; - unsigned int keepalive_intvl; - int linger2; - u8 bpf_sock_ops_cb_flags; - u16 timeout_rehash; - u32 rcv_ooopack; - u32 rcv_rtt_last_tsecr; - struct { - u32 rtt_us; - u32 seq; - u64 time; - } rcv_rtt_est; - struct { - u32 space; - u32 seq; - u64 time; - } rcvq_space; - struct { - u32 probe_seq_start; - u32 probe_seq_end; - } mtu_probe; - u32 mtu_info; - bool is_mptcp; - bool syn_smc; - const struct tcp_sock_af_ops *af_specific; - struct tcp_md5sig_info *md5sig_info; - struct tcp_fastopen_request *fastopen_req; - struct request_sock *fastopen_rsk; - struct saved_syn *saved_syn; -}; - -struct tcp_md5sig_key; - -struct tcp_sock_af_ops { - struct tcp_md5sig_key * (*md5_lookup)(const struct sock *, const struct sock *); - int (*calc_md5_hash)(char *, const struct tcp_md5sig_key *, const struct sock *, const struct sk_buff *); - int (*md5_parse)(struct sock *, int, sockptr_t, int); -}; - -struct tcp_md5sig_info { - struct hlist_head head; - struct callback_head rcu; -}; - -struct tcp_fastopen_request { - struct tcp_fastopen_cookie cookie; - struct msghdr *data; - size_t size; - int copied; - struct ubuf_info *uarg; -}; - -union tcp_md5_addr { - struct in_addr a4; - struct in6_addr a6; -}; - -struct tcp_md5sig_key { - struct hlist_node node; - u8 keylen; - u8 family; - u8 prefixlen; - union tcp_md5_addr addr; - int l3index; - u8 key[80]; - struct callback_head rcu; -}; - -struct net_protocol { - int (*early_demux)(struct sk_buff *); - int (*early_demux_handler)(struct sk_buff *); - int (*handler)(struct sk_buff *); - int (*err_handler)(struct sk_buff *, u32); - unsigned int no_policy: 1; - unsigned int icmp_strict_tag_validation: 1; -}; - -struct cgroup_cls_state { - struct cgroup_subsys_state css; - u32 classid; -}; - -enum { - SK_MEMINFO_RMEM_ALLOC = 0, - SK_MEMINFO_RCVBUF = 1, - SK_MEMINFO_WMEM_ALLOC = 2, - SK_MEMINFO_SNDBUF = 3, - SK_MEMINFO_FWD_ALLOC = 4, - SK_MEMINFO_WMEM_QUEUED = 5, - SK_MEMINFO_OPTMEM = 6, - SK_MEMINFO_BACKLOG = 7, - SK_MEMINFO_DROPS = 8, - SK_MEMINFO_VARS = 9, -}; - -enum sknetlink_groups { - SKNLGRP_NONE = 0, - SKNLGRP_INET_TCP_DESTROY = 1, - SKNLGRP_INET_UDP_DESTROY = 2, - SKNLGRP_INET6_TCP_DESTROY = 3, - SKNLGRP_INET6_UDP_DESTROY = 4, - __SKNLGRP_MAX = 5, -}; - -struct inet_request_sock { - struct request_sock req; - u16 snd_wscale: 4; - u16 rcv_wscale: 4; - u16 tstamp_ok: 1; - u16 sack_ok: 1; - u16 wscale_ok: 1; - u16 ecn_ok: 1; - u16 acked: 1; - u16 no_srccheck: 1; - u16 smc_ok: 1; - u32 ir_mark; - union { - struct ip_options_rcu *ireq_opt; - struct { - struct ipv6_txoptions *ipv6_opt; - struct sk_buff *pktopts; - }; - }; -}; - -struct tcp_request_sock_ops; - -struct tcp_request_sock { - struct inet_request_sock req; - const struct tcp_request_sock_ops *af_specific; - u64 snt_synack; - bool tfo_listener; - bool is_mptcp; - bool drop_req; - u32 txhash; - u32 rcv_isn; - u32 snt_isn; - u32 ts_off; - u32 last_oow_ack_time; - u32 rcv_nxt; - u8 syn_tos; -}; - -enum tcp_synack_type { - TCP_SYNACK_NORMAL = 0, - TCP_SYNACK_FASTOPEN = 1, - TCP_SYNACK_COOKIE = 2, -}; - -struct tcp_request_sock_ops { - u16 mss_clamp; - struct tcp_md5sig_key * (*req_md5_lookup)(const struct sock *, const struct sock *); - int (*calc_md5_hash)(char *, const struct tcp_md5sig_key *, const struct sock *, const struct sk_buff *); - __u32 (*cookie_init_seq)(const struct sk_buff *, __u16 *); - struct dst_entry * (*route_req)(const struct sock *, struct sk_buff *, struct flowi *, struct request_sock *); - u32 (*init_seq)(const struct sk_buff *); - u32 (*init_ts_off)(const struct net *, const struct sk_buff *); - int (*send_synack)(const struct sock *, struct dst_entry *, struct flowi *, struct request_sock *, struct tcp_fastopen_cookie *, enum tcp_synack_type, struct sk_buff *); -}; - -struct nf_conntrack { - atomic_t use; -}; - -enum { - SKBFL_ZEROCOPY_ENABLE = 1, - SKBFL_SHARED_FRAG = 2, -}; - -enum { - SKB_FCLONE_UNAVAILABLE = 0, - SKB_FCLONE_ORIG = 1, - SKB_FCLONE_CLONE = 2, -}; - -struct sk_buff_fclones { - struct sk_buff skb1; - struct sk_buff skb2; - refcount_t fclone_ref; -}; - -struct skb_seq_state { - __u32 lower_offset; - __u32 upper_offset; - __u32 frag_idx; - __u32 stepped_offset; - struct sk_buff *root_skb; - struct sk_buff *cur_skb; - __u8 *frag_data; - __u32 frag_off; -}; - -struct skb_checksum_ops { - __wsum (*update)(const void *, int, __wsum); - __wsum (*combine)(__wsum, __wsum, int, int); -}; - -struct skb_gso_cb { - union { - int mac_offset; - int data_offset; - }; - int encap_level; - __wsum csum; - __u16 csum_start; -}; - -struct napi_gro_cb { - void *frag0; - unsigned int frag0_len; - int data_offset; - u16 flush; - u16 flush_id; - u16 count; - u16 gro_remcsum_start; - long unsigned int age; - u16 proto; - u8 same_flow: 1; - u8 encap_mark: 1; - u8 csum_valid: 1; - u8 csum_cnt: 3; - u8 free: 2; - u8 is_ipv6: 1; - u8 is_fou: 1; - u8 is_atomic: 1; - u8 recursion_counter: 4; - u8 is_flist: 1; - __wsum csum; - struct sk_buff *last; -}; - -enum skb_free_reason { - SKB_REASON_CONSUMED = 0, - SKB_REASON_DROPPED = 1, -}; - -struct vlan_hdr { - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -struct vlan_ethhdr { - unsigned char h_dest[6]; - unsigned char h_source[6]; - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -struct qdisc_walker { - int stop; - int skip; - int count; - int (*fn)(struct Qdisc *, long unsigned int, struct qdisc_walker *); -}; - -struct ip_auth_hdr { - __u8 nexthdr; - __u8 hdrlen; - __be16 reserved; - __be32 spi; - __be32 seq_no; - __u8 auth_data[0]; -}; - -struct frag_hdr { - __u8 nexthdr; - __u8 reserved; - __be16 frag_off; - __be32 identification; -}; - -enum { - SCM_TSTAMP_SND = 0, - SCM_TSTAMP_SCHED = 1, - SCM_TSTAMP_ACK = 2, -}; - -struct mpls_shim_hdr { - __be32 label_stack_entry; -}; - -struct napi_alloc_cache { - struct page_frag_cache page; - unsigned int skb_count; - void *skb_cache[64]; -}; - -typedef int (*sendmsg_func)(struct sock *, struct msghdr *, struct kvec *, size_t, size_t); - -typedef int (*sendpage_func)(struct sock *, struct page *, int, size_t, int); - -struct ahash_request___2; - -struct scm_cookie { - struct pid *pid; - struct scm_fp_list *fp; - struct scm_creds creds; - u32 secid; -}; - -struct scm_timestamping { - struct __kernel_old_timespec ts[3]; -}; - -struct scm_timestamping64 { - struct __kernel_timespec ts[3]; -}; - -enum { - TCA_STATS_UNSPEC = 0, - TCA_STATS_BASIC = 1, - TCA_STATS_RATE_EST = 2, - TCA_STATS_QUEUE = 3, - TCA_STATS_APP = 4, - TCA_STATS_RATE_EST64 = 5, - TCA_STATS_PAD = 6, - TCA_STATS_BASIC_HW = 7, - TCA_STATS_PKT64 = 8, - __TCA_STATS_MAX = 9, -}; - -struct gnet_stats_basic { - __u64 bytes; - __u32 packets; -}; - -struct gnet_stats_rate_est { - __u32 bps; - __u32 pps; -}; - -struct gnet_stats_rate_est64 { - __u64 bps; - __u64 pps; -}; - -struct gnet_estimator { - signed char interval; - unsigned char ewma_log; -}; - -struct net_rate_estimator___2 { - struct gnet_stats_basic_packed *bstats; - spinlock_t *stats_lock; - seqcount_t *running; - struct gnet_stats_basic_cpu *cpu_bstats; - u8 ewma_log; - u8 intvl_log; - seqcount_t seq; - u64 last_packets; - u64 last_bytes; - u64 avpps; - u64 avbps; - long unsigned int next_jiffies; - struct timer_list timer; - struct callback_head rcu; -}; - -struct rtgenmsg { - unsigned char rtgen_family; -}; - -enum rtnetlink_groups { - RTNLGRP_NONE = 0, - RTNLGRP_LINK = 1, - RTNLGRP_NOTIFY = 2, - RTNLGRP_NEIGH = 3, - RTNLGRP_TC = 4, - RTNLGRP_IPV4_IFADDR = 5, - RTNLGRP_IPV4_MROUTE = 6, - RTNLGRP_IPV4_ROUTE = 7, - RTNLGRP_IPV4_RULE = 8, - RTNLGRP_IPV6_IFADDR = 9, - RTNLGRP_IPV6_MROUTE = 10, - RTNLGRP_IPV6_ROUTE = 11, - RTNLGRP_IPV6_IFINFO = 12, - RTNLGRP_DECnet_IFADDR = 13, - RTNLGRP_NOP2 = 14, - RTNLGRP_DECnet_ROUTE = 15, - RTNLGRP_DECnet_RULE = 16, - RTNLGRP_NOP4 = 17, - RTNLGRP_IPV6_PREFIX = 18, - RTNLGRP_IPV6_RULE = 19, - RTNLGRP_ND_USEROPT = 20, - RTNLGRP_PHONET_IFADDR = 21, - RTNLGRP_PHONET_ROUTE = 22, - RTNLGRP_DCB = 23, - RTNLGRP_IPV4_NETCONF = 24, - RTNLGRP_IPV6_NETCONF = 25, - RTNLGRP_MDB = 26, - RTNLGRP_MPLS_ROUTE = 27, - RTNLGRP_NSID = 28, - RTNLGRP_MPLS_NETCONF = 29, - RTNLGRP_IPV4_MROUTE_R = 30, - RTNLGRP_IPV6_MROUTE_R = 31, - RTNLGRP_NEXTHOP = 32, - RTNLGRP_BRVLAN = 33, - __RTNLGRP_MAX = 34, -}; - -enum { - NETNSA_NONE = 0, - NETNSA_NSID = 1, - NETNSA_PID = 2, - NETNSA_FD = 3, - NETNSA_TARGET_NSID = 4, - NETNSA_CURRENT_NSID = 5, - __NETNSA_MAX = 6, -}; - -struct pcpu_gen_cookie { - local_t nesting; - u64 last; -}; - -struct gen_cookie { - struct pcpu_gen_cookie *local; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - atomic64_t forward_last; - atomic64_t reverse_last; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, struct netlink_ext_ack *); - -typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *); - -enum rtnl_link_flags { - RTNL_FLAG_DOIT_UNLOCKED = 1, -}; - -struct net_fill_args { - u32 portid; - u32 seq; - int flags; - int cmd; - int nsid; - bool add_ref; - int ref_nsid; -}; - -struct rtnl_net_dump_cb { - struct net *tgt_net; - struct net *ref_net; - struct sk_buff *skb; - struct net_fill_args fillargs; - int idx; - int s_idx; -}; - -typedef u16 u_int16_t; - -typedef u32 u_int32_t; - -typedef u64 u_int64_t; - -struct flow_dissector_key_control { - u16 thoff; - u16 addr_type; - u32 flags; -}; - -enum flow_dissect_ret { - FLOW_DISSECT_RET_OUT_GOOD = 0, - FLOW_DISSECT_RET_OUT_BAD = 1, - FLOW_DISSECT_RET_PROTO_AGAIN = 2, - FLOW_DISSECT_RET_IPPROTO_AGAIN = 3, - FLOW_DISSECT_RET_CONTINUE = 4, -}; - -struct flow_dissector_key_basic { - __be16 n_proto; - u8 ip_proto; - u8 padding; -}; - -struct flow_dissector_key_tags { - u32 flow_label; -}; - -struct flow_dissector_key_vlan { - union { - struct { - u16 vlan_id: 12; - u16 vlan_dei: 1; - u16 vlan_priority: 3; - }; - __be16 vlan_tci; - }; - __be16 vlan_tpid; -}; - -struct flow_dissector_mpls_lse { - u32 mpls_ttl: 8; - u32 mpls_bos: 1; - u32 mpls_tc: 3; - u32 mpls_label: 20; -}; - -struct flow_dissector_key_mpls { - struct flow_dissector_mpls_lse ls[7]; - u8 used_lses; -}; - -struct flow_dissector_key_enc_opts { - u8 data[255]; - u8 len; - __be16 dst_opt_type; -}; - -struct flow_dissector_key_keyid { - __be32 keyid; -}; - -struct flow_dissector_key_ipv4_addrs { - __be32 src; - __be32 dst; -}; - -struct flow_dissector_key_ipv6_addrs { - struct in6_addr src; - struct in6_addr dst; -}; - -struct flow_dissector_key_tipc { - __be32 key; -}; - -struct flow_dissector_key_addrs { - union { - struct flow_dissector_key_ipv4_addrs v4addrs; - struct flow_dissector_key_ipv6_addrs v6addrs; - struct flow_dissector_key_tipc tipckey; - }; -}; - -struct flow_dissector_key_arp { - __u32 sip; - __u32 tip; - __u8 op; - unsigned char sha[6]; - unsigned char tha[6]; -}; - -struct flow_dissector_key_ports { - union { - __be32 ports; - struct { - __be16 src; - __be16 dst; - }; - }; -}; - -struct flow_dissector_key_icmp { - struct { - u8 type; - u8 code; - }; - u16 id; -}; - -struct flow_dissector_key_eth_addrs { - unsigned char dst[6]; - unsigned char src[6]; -}; - -struct flow_dissector_key_tcp { - __be16 flags; -}; - -struct flow_dissector_key_ip { - __u8 tos; - __u8 ttl; -}; - -struct flow_dissector_key_meta { - int ingress_ifindex; - u16 ingress_iftype; -}; - -struct flow_dissector_key_ct { - u16 ct_state; - u16 ct_zone; - u32 ct_mark; - u32 ct_labels[4]; -}; - -struct flow_dissector_key_hash { - u32 hash; -}; - -struct flow_dissector_key { - enum flow_dissector_key_id key_id; - size_t offset; -}; - -struct flow_dissector { - unsigned int used_keys; - short unsigned int offset[28]; -}; - -struct flow_keys_basic { - struct flow_dissector_key_control control; - struct flow_dissector_key_basic basic; -}; - -struct flow_keys { - struct flow_dissector_key_control control; - struct flow_dissector_key_basic basic; - struct flow_dissector_key_tags tags; - struct flow_dissector_key_vlan vlan; - struct flow_dissector_key_vlan cvlan; - struct flow_dissector_key_keyid keyid; - struct flow_dissector_key_ports ports; - struct flow_dissector_key_icmp icmp; - struct flow_dissector_key_addrs addrs; - int: 32; -}; - -struct flow_keys_digest { - u8 data[16]; -}; - -enum ip_conntrack_info { - IP_CT_ESTABLISHED = 0, - IP_CT_RELATED = 1, - IP_CT_NEW = 2, - IP_CT_IS_REPLY = 3, - IP_CT_ESTABLISHED_REPLY = 3, - IP_CT_RELATED_REPLY = 4, - IP_CT_NUMBER = 5, - IP_CT_UNTRACKED = 7, -}; - -union nf_inet_addr { - __u32 all[4]; - __be32 ip; - __be32 ip6[4]; - struct in_addr in; - struct in6_addr in6; -}; - -struct ip_ct_tcp_state { - u_int32_t td_end; - u_int32_t td_maxend; - u_int32_t td_maxwin; - u_int32_t td_maxack; - u_int8_t td_scale; - u_int8_t flags; -}; - -struct ip_ct_tcp { - struct ip_ct_tcp_state seen[2]; - u_int8_t state; - u_int8_t last_dir; - u_int8_t retrans; - u_int8_t last_index; - u_int32_t last_seq; - u_int32_t last_ack; - u_int32_t last_end; - u_int16_t last_win; - u_int8_t last_wscale; - u_int8_t last_flags; -}; - -union nf_conntrack_man_proto { - __be16 all; - struct { - __be16 port; - } tcp; - struct { - __be16 port; - } udp; - struct { - __be16 id; - } icmp; - struct { - __be16 port; - } dccp; - struct { - __be16 port; - } sctp; - struct { - __be16 key; - } gre; -}; - -struct nf_ct_dccp { - u_int8_t role[2]; - u_int8_t state; - u_int8_t last_pkt; - u_int8_t last_dir; - u_int64_t handshake_seq; -}; - -struct ip_ct_sctp { - enum sctp_conntrack state; - __be32 vtag[2]; - u8 last_dir; - u8 flags; -}; - -struct nf_ct_event; - -struct nf_ct_event_notifier { - int (*fcn)(unsigned int, struct nf_ct_event *); -}; - -struct nf_exp_event; - -struct nf_exp_event_notifier { - int (*fcn)(unsigned int, struct nf_exp_event *); -}; - -enum bpf_ret_code { - BPF_OK = 0, - BPF_DROP = 2, - BPF_REDIRECT = 7, - BPF_LWT_REROUTE = 128, -}; - -enum { - BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = 1, - BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = 2, - BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = 4, -}; - -enum { - TCA_FLOWER_KEY_CT_FLAGS_NEW = 1, - TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED = 2, - TCA_FLOWER_KEY_CT_FLAGS_RELATED = 4, - TCA_FLOWER_KEY_CT_FLAGS_TRACKED = 8, - TCA_FLOWER_KEY_CT_FLAGS_INVALID = 16, - TCA_FLOWER_KEY_CT_FLAGS_REPLY = 32, - __TCA_FLOWER_KEY_CT_FLAGS_MAX = 33, -}; - -enum devlink_port_type { - DEVLINK_PORT_TYPE_NOTSET = 0, - DEVLINK_PORT_TYPE_AUTO = 1, - DEVLINK_PORT_TYPE_ETH = 2, - DEVLINK_PORT_TYPE_IB = 3, -}; - -enum devlink_port_flavour { - DEVLINK_PORT_FLAVOUR_PHYSICAL = 0, - DEVLINK_PORT_FLAVOUR_CPU = 1, - DEVLINK_PORT_FLAVOUR_DSA = 2, - DEVLINK_PORT_FLAVOUR_PCI_PF = 3, - DEVLINK_PORT_FLAVOUR_PCI_VF = 4, - DEVLINK_PORT_FLAVOUR_VIRTUAL = 5, - DEVLINK_PORT_FLAVOUR_UNUSED = 6, - DEVLINK_PORT_FLAVOUR_PCI_SF = 7, -}; - -struct devlink_port_phys_attrs { - u32 port_number; - u32 split_subport_number; -}; - -struct devlink_port_pci_pf_attrs { - u32 controller; - u16 pf; - u8 external: 1; -}; - -struct devlink_port_pci_vf_attrs { - u32 controller; - u16 pf; - u16 vf; - u8 external: 1; -}; - -struct devlink_port_pci_sf_attrs { - u32 controller; - u32 sf; - u16 pf; - u8 external: 1; -}; - -struct devlink_port_attrs { - u8 split: 1; - u8 splittable: 1; - u32 lanes; - enum devlink_port_flavour flavour; - struct netdev_phys_item_id switch_id; - union { - struct devlink_port_phys_attrs phys; - struct devlink_port_pci_pf_attrs pci_pf; - struct devlink_port_pci_vf_attrs pci_vf; - struct devlink_port_pci_sf_attrs pci_sf; - }; -}; - -struct devlink; - -struct devlink_rate; - -struct devlink_port { - struct list_head list; - struct list_head param_list; - struct list_head region_list; - struct devlink *devlink; - unsigned int index; - bool registered; - spinlock_t type_lock; - enum devlink_port_type type; - enum devlink_port_type desired_type; - void *type_dev; - struct devlink_port_attrs attrs; - u8 attrs_set: 1; - u8 switch_port: 1; - struct delayed_work type_warn_dw; - struct list_head reporter_list; - struct mutex reporters_lock; - struct devlink_rate *devlink_rate; -}; - -struct ip_tunnel_parm { - char name[16]; - int link; - __be16 i_flags; - __be16 o_flags; - __be32 i_key; - __be32 o_key; - struct iphdr iph; -}; - -enum phylink_op_type { - PHYLINK_NETDEV = 0, - PHYLINK_DEV = 1, -}; - -struct phylink_link_state; - -struct phylink_config { - struct device *dev; - enum phylink_op_type type; - bool pcs_poll; - bool poll_fixed_state; - bool ovr_an_inband; - void (*get_fixed_state)(struct phylink_config *, struct phylink_link_state *); -}; - -struct dsa_device_ops; - -struct dsa_switch_tree; - -struct packet_type; - -struct dsa_switch; - -struct dsa_netdevice_ops; - -struct dsa_port { - union { - struct net_device *master; - struct net_device *slave; - }; - const struct dsa_device_ops *tag_ops; - struct dsa_switch_tree *dst; - struct sk_buff * (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *); - bool (*filter)(const struct sk_buff *, struct net_device *); - enum { - DSA_PORT_TYPE_UNUSED = 0, - DSA_PORT_TYPE_CPU = 1, - DSA_PORT_TYPE_DSA = 2, - DSA_PORT_TYPE_USER = 3, - } type; - struct dsa_switch *ds; - unsigned int index; - const char *name; - struct dsa_port *cpu_dp; - u8 mac[6]; - struct device_node *dn; - unsigned int ageing_time; - bool vlan_filtering; - u8 stp_state; - struct net_device *bridge_dev; - struct devlink_port devlink_port; - bool devlink_port_setup; - struct phylink *pl; - struct phylink_config pl_config; - struct net_device *lag_dev; - bool lag_tx_enabled; - struct net_device *hsr_dev; - struct list_head list; - void *priv; - const struct ethtool_ops *orig_ethtool_ops; - const struct dsa_netdevice_ops *netdev_ops; - struct list_head fdbs; - struct list_head mdbs; - bool setup; -}; - -struct packet_type { - __be16 type; - bool ignore_outgoing; - struct net_device *dev; - int (*func)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); - void (*list_func)(struct list_head *, struct packet_type *, struct net_device *); - bool (*id_match)(struct packet_type *, struct sock *); - void *af_packet_priv; - struct list_head list; -}; - -enum netdev_lag_tx_type { - NETDEV_LAG_TX_TYPE_UNKNOWN = 0, - NETDEV_LAG_TX_TYPE_RANDOM = 1, - NETDEV_LAG_TX_TYPE_BROADCAST = 2, - NETDEV_LAG_TX_TYPE_ROUNDROBIN = 3, - NETDEV_LAG_TX_TYPE_ACTIVEBACKUP = 4, - NETDEV_LAG_TX_TYPE_HASH = 5, -}; - -enum netdev_lag_hash { - NETDEV_LAG_HASH_NONE = 0, - NETDEV_LAG_HASH_L2 = 1, - NETDEV_LAG_HASH_L34 = 2, - NETDEV_LAG_HASH_L23 = 3, - NETDEV_LAG_HASH_E23 = 4, - NETDEV_LAG_HASH_E34 = 5, - NETDEV_LAG_HASH_VLAN_SRCMAC = 6, - NETDEV_LAG_HASH_UNKNOWN = 7, -}; - -struct netdev_lag_upper_info { - enum netdev_lag_tx_type tx_type; - enum netdev_lag_hash hash_type; -}; - -struct netdev_notifier_changeupper_info { - struct netdev_notifier_info info; - struct net_device *upper_dev; - bool master; - bool linking; - void *upper_info; -}; - -struct flow_match { - struct flow_dissector *dissector; - void *mask; - void *key; -}; - -enum flow_action_id { - FLOW_ACTION_ACCEPT = 0, - FLOW_ACTION_DROP = 1, - FLOW_ACTION_TRAP = 2, - FLOW_ACTION_GOTO = 3, - FLOW_ACTION_REDIRECT = 4, - FLOW_ACTION_MIRRED = 5, - FLOW_ACTION_REDIRECT_INGRESS = 6, - FLOW_ACTION_MIRRED_INGRESS = 7, - FLOW_ACTION_VLAN_PUSH = 8, - FLOW_ACTION_VLAN_POP = 9, - FLOW_ACTION_VLAN_MANGLE = 10, - FLOW_ACTION_TUNNEL_ENCAP = 11, - FLOW_ACTION_TUNNEL_DECAP = 12, - FLOW_ACTION_MANGLE = 13, - FLOW_ACTION_ADD = 14, - FLOW_ACTION_CSUM = 15, - FLOW_ACTION_MARK = 16, - FLOW_ACTION_PTYPE = 17, - FLOW_ACTION_PRIORITY = 18, - FLOW_ACTION_WAKE = 19, - FLOW_ACTION_QUEUE = 20, - FLOW_ACTION_SAMPLE = 21, - FLOW_ACTION_POLICE = 22, - FLOW_ACTION_CT = 23, - FLOW_ACTION_CT_METADATA = 24, - FLOW_ACTION_MPLS_PUSH = 25, - FLOW_ACTION_MPLS_POP = 26, - FLOW_ACTION_MPLS_MANGLE = 27, - FLOW_ACTION_GATE = 28, - FLOW_ACTION_PPPOE_PUSH = 29, - NUM_FLOW_ACTIONS = 30, -}; - -enum flow_action_mangle_base { - FLOW_ACT_MANGLE_UNSPEC = 0, - FLOW_ACT_MANGLE_HDR_TYPE_ETH = 1, - FLOW_ACT_MANGLE_HDR_TYPE_IP4 = 2, - FLOW_ACT_MANGLE_HDR_TYPE_IP6 = 3, - FLOW_ACT_MANGLE_HDR_TYPE_TCP = 4, - FLOW_ACT_MANGLE_HDR_TYPE_UDP = 5, -}; - -enum flow_action_hw_stats { - FLOW_ACTION_HW_STATS_IMMEDIATE = 1, - FLOW_ACTION_HW_STATS_DELAYED = 2, - FLOW_ACTION_HW_STATS_ANY = 3, - FLOW_ACTION_HW_STATS_DISABLED = 4, - FLOW_ACTION_HW_STATS_DONT_CARE = 7, -}; - -typedef void (*action_destr)(void *); - -struct flow_action_cookie { - u32 cookie_len; - u8 cookie[0]; -}; - -struct nf_flowtable; - -struct ip_tunnel_key { - __be64 tun_id; - union { - struct { - __be32 src; - __be32 dst; - } ipv4; - struct { - struct in6_addr src; - struct in6_addr dst; - } ipv6; - } u; - __be16 tun_flags; - u8 tos; - u8 ttl; - __be32 label; - __be16 tp_src; - __be16 tp_dst; -}; - -struct dst_cache_pcpu; - -struct dst_cache { - struct dst_cache_pcpu *cache; - long unsigned int reset_ts; -}; - -struct ip_tunnel_info { - struct ip_tunnel_key key; - struct dst_cache dst_cache; - u8 options_len; - u8 mode; -}; - -struct psample_group; - -struct action_gate_entry; - -struct flow_action_entry { - enum flow_action_id id; - enum flow_action_hw_stats hw_stats; - action_destr destructor; - void *destructor_priv; - union { - u32 chain_index; - struct net_device *dev; - struct { - u16 vid; - __be16 proto; - u8 prio; - } vlan; - struct { - enum flow_action_mangle_base htype; - u32 offset; - u32 mask; - u32 val; - } mangle; - struct ip_tunnel_info *tunnel; - u32 csum_flags; - u32 mark; - u16 ptype; - u32 priority; - struct { - u32 ctx; - u32 index; - u8 vf; - } queue; - struct { - struct psample_group *psample_group; - u32 rate; - u32 trunc_size; - bool truncate; - } sample; - struct { - u32 index; - u32 burst; - u64 rate_bytes_ps; - u64 burst_pkt; - u64 rate_pkt_ps; - u32 mtu; - } police; - struct { - int action; - u16 zone; - struct nf_flowtable *flow_table; - } ct; - struct { - long unsigned int cookie; - u32 mark; - u32 labels[4]; - bool orig_dir; - } ct_metadata; - struct { - u32 label; - __be16 proto; - u8 tc; - u8 bos; - u8 ttl; - } mpls_push; - struct { - __be16 proto; - } mpls_pop; - struct { - u32 label; - u8 tc; - u8 bos; - u8 ttl; - } mpls_mangle; - struct { - u32 index; - s32 prio; - u64 basetime; - u64 cycletime; - u64 cycletimeext; - u32 num_entries; - struct action_gate_entry *entries; - } gate; - struct { - u16 sid; - } pppoe; - }; - struct flow_action_cookie *cookie; -}; - -struct flow_action { - unsigned int num_entries; - struct flow_action_entry entries[0]; -}; - -struct flow_rule { - struct flow_match match; - struct flow_action action; -}; - -struct flow_stats { - u64 pkts; - u64 bytes; - u64 drops; - u64 lastused; - enum flow_action_hw_stats used_hw_stats; - bool used_hw_stats_valid; -}; - -enum flow_cls_command { - FLOW_CLS_REPLACE = 0, - FLOW_CLS_DESTROY = 1, - FLOW_CLS_STATS = 2, - FLOW_CLS_TMPLT_CREATE = 3, - FLOW_CLS_TMPLT_DESTROY = 4, -}; - -struct flow_cls_common_offload { - u32 chain_index; - __be16 protocol; - u32 prio; - struct netlink_ext_ack *extack; -}; - -struct flow_cls_offload { - struct flow_cls_common_offload common; - enum flow_cls_command command; - long unsigned int cookie; - struct flow_rule *rule; - struct flow_stats stats; - u32 classid; -}; - -union tcp_word_hdr { - struct tcphdr hdr; - __be32 words[5]; -}; - -struct dsa_chip_data { - struct device *host_dev; - int sw_addr; - struct device *netdev[12]; - int eeprom_len; - struct device_node *of_node; - char *port_names[12]; - struct device_node *port_dn[12]; - s8 rtable[4]; -}; - -struct dsa_platform_data { - struct device *netdev; - struct net_device *of_netdev; - int nr_chips; - struct dsa_chip_data *chip; -}; - -struct phylink_link_state { - long unsigned int advertising[2]; - long unsigned int lp_advertising[2]; - phy_interface_t interface; - int speed; - int duplex; - int pause; - unsigned int link: 1; - unsigned int an_enabled: 1; - unsigned int an_complete: 1; -}; - -enum devlink_sb_pool_type { - DEVLINK_SB_POOL_TYPE_INGRESS = 0, - DEVLINK_SB_POOL_TYPE_EGRESS = 1, -}; - -enum devlink_sb_threshold_type { - DEVLINK_SB_THRESHOLD_TYPE_STATIC = 0, - DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC = 1, -}; - -enum devlink_eswitch_encap_mode { - DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0, - DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1, -}; - -enum devlink_rate_type { - DEVLINK_RATE_TYPE_LEAF = 0, - DEVLINK_RATE_TYPE_NODE = 1, -}; - -enum devlink_param_cmode { - DEVLINK_PARAM_CMODE_RUNTIME = 0, - DEVLINK_PARAM_CMODE_DRIVERINIT = 1, - DEVLINK_PARAM_CMODE_PERMANENT = 2, - __DEVLINK_PARAM_CMODE_MAX = 3, - DEVLINK_PARAM_CMODE_MAX = 2, -}; - -enum devlink_trap_action { - DEVLINK_TRAP_ACTION_DROP = 0, - DEVLINK_TRAP_ACTION_TRAP = 1, - DEVLINK_TRAP_ACTION_MIRROR = 2, -}; - -enum devlink_trap_type { - DEVLINK_TRAP_TYPE_DROP = 0, - DEVLINK_TRAP_TYPE_EXCEPTION = 1, - DEVLINK_TRAP_TYPE_CONTROL = 2, -}; - -enum devlink_reload_action { - DEVLINK_RELOAD_ACTION_UNSPEC = 0, - DEVLINK_RELOAD_ACTION_DRIVER_REINIT = 1, - DEVLINK_RELOAD_ACTION_FW_ACTIVATE = 2, - __DEVLINK_RELOAD_ACTION_MAX = 3, - DEVLINK_RELOAD_ACTION_MAX = 2, -}; - -enum devlink_reload_limit { - DEVLINK_RELOAD_LIMIT_UNSPEC = 0, - DEVLINK_RELOAD_LIMIT_NO_RESET = 1, - __DEVLINK_RELOAD_LIMIT_MAX = 2, - DEVLINK_RELOAD_LIMIT_MAX = 1, -}; - -enum devlink_dpipe_field_mapping_type { - DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0, - DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 1, -}; - -enum devlink_port_fn_state { - DEVLINK_PORT_FN_STATE_INACTIVE = 0, - DEVLINK_PORT_FN_STATE_ACTIVE = 1, -}; - -enum devlink_port_fn_opstate { - DEVLINK_PORT_FN_OPSTATE_DETACHED = 0, - DEVLINK_PORT_FN_OPSTATE_ATTACHED = 1, -}; - -struct devlink_dev_stats { - u32 reload_stats[6]; - u32 remote_reload_stats[6]; -}; - -struct devlink_dpipe_headers; - -struct devlink_ops; - -struct devlink { - struct list_head list; - struct list_head port_list; - struct list_head rate_list; - struct list_head sb_list; - struct list_head dpipe_table_list; - struct list_head resource_list; - struct list_head param_list; - struct list_head region_list; - struct list_head reporter_list; - struct mutex reporters_lock; - struct devlink_dpipe_headers *dpipe_headers; - struct list_head trap_list; - struct list_head trap_group_list; - struct list_head trap_policer_list; - const struct devlink_ops *ops; - struct xarray snapshot_ids; - struct devlink_dev_stats stats; - struct device *dev; - possible_net_t _net; - struct mutex lock; - u8 reload_failed: 1; - u8 reload_enabled: 1; - u8 registered: 1; - long: 61; - long: 64; - long: 64; - long: 64; - char priv[0]; -}; - -struct devlink_dpipe_header; - -struct devlink_dpipe_headers { - struct devlink_dpipe_header **headers; - unsigned int headers_count; -}; - -struct devlink_sb_pool_info; - -struct devlink_info_req; - -struct devlink_flash_update_params; - -struct devlink_trap; - -struct devlink_trap_group; - -struct devlink_trap_policer; - -struct devlink_port_new_attrs; - -struct devlink_ops { - u32 supported_flash_update_params; - long unsigned int reload_actions; - long unsigned int reload_limits; - int (*reload_down)(struct devlink *, bool, enum devlink_reload_action, enum devlink_reload_limit, struct netlink_ext_ack *); - int (*reload_up)(struct devlink *, enum devlink_reload_action, enum devlink_reload_limit, u32 *, struct netlink_ext_ack *); - int (*port_type_set)(struct devlink_port *, enum devlink_port_type); - int (*port_split)(struct devlink *, unsigned int, unsigned int, struct netlink_ext_ack *); - int (*port_unsplit)(struct devlink *, unsigned int, struct netlink_ext_ack *); - int (*sb_pool_get)(struct devlink *, unsigned int, u16, struct devlink_sb_pool_info *); - int (*sb_pool_set)(struct devlink *, unsigned int, u16, u32, enum devlink_sb_threshold_type, struct netlink_ext_ack *); - int (*sb_port_pool_get)(struct devlink_port *, unsigned int, u16, u32 *); - int (*sb_port_pool_set)(struct devlink_port *, unsigned int, u16, u32, struct netlink_ext_ack *); - int (*sb_tc_pool_bind_get)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u16 *, u32 *); - int (*sb_tc_pool_bind_set)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u16, u32, struct netlink_ext_ack *); - int (*sb_occ_snapshot)(struct devlink *, unsigned int); - int (*sb_occ_max_clear)(struct devlink *, unsigned int); - int (*sb_occ_port_pool_get)(struct devlink_port *, unsigned int, u16, u32 *, u32 *); - int (*sb_occ_tc_port_bind_get)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u32 *, u32 *); - int (*eswitch_mode_get)(struct devlink *, u16 *); - int (*eswitch_mode_set)(struct devlink *, u16, struct netlink_ext_ack *); - int (*eswitch_inline_mode_get)(struct devlink *, u8 *); - int (*eswitch_inline_mode_set)(struct devlink *, u8, struct netlink_ext_ack *); - int (*eswitch_encap_mode_get)(struct devlink *, enum devlink_eswitch_encap_mode *); - int (*eswitch_encap_mode_set)(struct devlink *, enum devlink_eswitch_encap_mode, struct netlink_ext_ack *); - int (*info_get)(struct devlink *, struct devlink_info_req *, struct netlink_ext_ack *); - int (*flash_update)(struct devlink *, struct devlink_flash_update_params *, struct netlink_ext_ack *); - int (*trap_init)(struct devlink *, const struct devlink_trap *, void *); - void (*trap_fini)(struct devlink *, const struct devlink_trap *, void *); - int (*trap_action_set)(struct devlink *, const struct devlink_trap *, enum devlink_trap_action, struct netlink_ext_ack *); - int (*trap_group_init)(struct devlink *, const struct devlink_trap_group *); - int (*trap_group_set)(struct devlink *, const struct devlink_trap_group *, const struct devlink_trap_policer *, struct netlink_ext_ack *); - int (*trap_group_action_set)(struct devlink *, const struct devlink_trap_group *, enum devlink_trap_action, struct netlink_ext_ack *); - int (*trap_drop_counter_get)(struct devlink *, const struct devlink_trap *, u64 *); - int (*trap_policer_init)(struct devlink *, const struct devlink_trap_policer *); - void (*trap_policer_fini)(struct devlink *, const struct devlink_trap_policer *); - int (*trap_policer_set)(struct devlink *, const struct devlink_trap_policer *, u64, u64, struct netlink_ext_ack *); - int (*trap_policer_counter_get)(struct devlink *, const struct devlink_trap_policer *, u64 *); - int (*port_function_hw_addr_get)(struct devlink *, struct devlink_port *, u8 *, int *, struct netlink_ext_ack *); - int (*port_function_hw_addr_set)(struct devlink *, struct devlink_port *, const u8 *, int, struct netlink_ext_ack *); - int (*port_new)(struct devlink *, const struct devlink_port_new_attrs *, struct netlink_ext_ack *, unsigned int *); - int (*port_del)(struct devlink *, unsigned int, struct netlink_ext_ack *); - int (*port_fn_state_get)(struct devlink *, struct devlink_port *, enum devlink_port_fn_state *, enum devlink_port_fn_opstate *, struct netlink_ext_ack *); - int (*port_fn_state_set)(struct devlink *, struct devlink_port *, enum devlink_port_fn_state, struct netlink_ext_ack *); - int (*rate_leaf_tx_share_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *); - int (*rate_leaf_tx_max_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *); - int (*rate_node_tx_share_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *); - int (*rate_node_tx_max_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *); - int (*rate_node_new)(struct devlink_rate *, void **, struct netlink_ext_ack *); - int (*rate_node_del)(struct devlink_rate *, void *, struct netlink_ext_ack *); - int (*rate_leaf_parent_set)(struct devlink_rate *, struct devlink_rate *, void *, void *, struct netlink_ext_ack *); - int (*rate_node_parent_set)(struct devlink_rate *, struct devlink_rate *, void *, void *, struct netlink_ext_ack *); -}; - -struct devlink_rate { - struct list_head list; - enum devlink_rate_type type; - struct devlink *devlink; - void *priv; - u64 tx_share; - u64 tx_max; - struct devlink_rate *parent; - union { - struct devlink_port *devlink_port; - struct { - char *name; - refcount_t refcnt; - }; - }; -}; - -struct devlink_port_new_attrs { - enum devlink_port_flavour flavour; - unsigned int port_index; - u32 controller; - u32 sfnum; - u16 pfnum; - u8 port_index_valid: 1; - u8 controller_valid: 1; - u8 sfnum_valid: 1; -}; - -struct devlink_sb_pool_info { - enum devlink_sb_pool_type pool_type; - u32 size; - enum devlink_sb_threshold_type threshold_type; - u32 cell_size; -}; - -struct devlink_dpipe_field { - const char *name; - unsigned int id; - unsigned int bitwidth; - enum devlink_dpipe_field_mapping_type mapping_type; -}; - -struct devlink_dpipe_header { - const char *name; - unsigned int id; - struct devlink_dpipe_field *fields; - unsigned int fields_count; - bool global; -}; - -union devlink_param_value { - u8 vu8; - u16 vu16; - u32 vu32; - char vstr[32]; - bool vbool; -}; - -struct devlink_param_gset_ctx { - union devlink_param_value val; - enum devlink_param_cmode cmode; -}; - -struct devlink_flash_update_params { - const struct firmware *fw; - const char *component; - u32 overwrite_mask; -}; - -struct devlink_trap_policer { - u32 id; - u64 init_rate; - u64 init_burst; - u64 max_rate; - u64 min_rate; - u64 max_burst; - u64 min_burst; -}; - -struct devlink_trap_group { - const char *name; - u16 id; - bool generic; - u32 init_policer_id; -}; - -struct devlink_trap { - enum devlink_trap_type type; - enum devlink_trap_action init_action; - bool generic; - u16 id; - const char *name; - u16 init_group_id; - u32 metadata_cap; -}; - -struct arphdr { - __be16 ar_hrd; - __be16 ar_pro; - unsigned char ar_hln; - unsigned char ar_pln; - __be16 ar_op; -}; - -struct fib_info; - -struct fib_nh { - struct fib_nh_common nh_common; - struct hlist_node nh_hash; - struct fib_info *nh_parent; - __u32 nh_tclassid; - __be32 nh_saddr; - int nh_saddr_genid; -}; - -struct fib_info { - struct hlist_node fib_hash; - struct hlist_node fib_lhash; - struct list_head nh_list; - struct net *fib_net; - int fib_treeref; - refcount_t fib_clntref; - unsigned int fib_flags; - unsigned char fib_dead; - unsigned char fib_protocol; - unsigned char fib_scope; - unsigned char fib_type; - __be32 fib_prefsrc; - u32 fib_tb_id; - u32 fib_priority; - struct dst_metrics *fib_metrics; - int fib_nhs; - bool fib_nh_is_v6; - bool nh_updated; - struct nexthop *nh; - struct callback_head rcu; - struct fib_nh fib_nh[0]; -}; - -struct nh_info; - -struct nh_group; - -struct nexthop { - struct rb_node rb_node; - struct list_head fi_list; - struct list_head f6i_list; - struct list_head fdb_list; - struct list_head grp_list; - struct net *net; - u32 id; - u8 protocol; - u8 nh_flags; - bool is_group; - refcount_t refcnt; - struct callback_head rcu; - union { - struct nh_info *nh_info; - struct nh_group *nh_grp; - }; -}; - -struct switchdev_brport_flags { - long unsigned int val; - long unsigned int mask; -}; - -enum switchdev_obj_id { - SWITCHDEV_OBJ_ID_UNDEFINED = 0, - SWITCHDEV_OBJ_ID_PORT_VLAN = 1, - SWITCHDEV_OBJ_ID_PORT_MDB = 2, - SWITCHDEV_OBJ_ID_HOST_MDB = 3, - SWITCHDEV_OBJ_ID_MRP = 4, - SWITCHDEV_OBJ_ID_RING_TEST_MRP = 5, - SWITCHDEV_OBJ_ID_RING_ROLE_MRP = 6, - SWITCHDEV_OBJ_ID_RING_STATE_MRP = 7, - SWITCHDEV_OBJ_ID_IN_TEST_MRP = 8, - SWITCHDEV_OBJ_ID_IN_ROLE_MRP = 9, - SWITCHDEV_OBJ_ID_IN_STATE_MRP = 10, -}; - -struct switchdev_obj { - struct list_head list; - struct net_device *orig_dev; - enum switchdev_obj_id id; - u32 flags; - void *complete_priv; - void (*complete)(struct net_device *, int, void *); -}; - -struct switchdev_obj_port_vlan { - struct switchdev_obj obj; - u16 flags; - u16 vid; -}; - -struct switchdev_obj_port_mdb { - struct switchdev_obj obj; - unsigned char addr[6]; - u16 vid; -}; - -struct switchdev_obj_mrp { - struct switchdev_obj obj; - struct net_device *p_port; - struct net_device *s_port; - u32 ring_id; - u16 prio; -}; - -struct switchdev_obj_ring_role_mrp { - struct switchdev_obj obj; - u8 ring_role; - u32 ring_id; - u8 sw_backup; -}; - -enum dsa_tag_protocol { - DSA_TAG_PROTO_NONE = 0, - DSA_TAG_PROTO_BRCM = 1, - DSA_TAG_PROTO_BRCM_LEGACY = 22, - DSA_TAG_PROTO_BRCM_PREPEND = 2, - DSA_TAG_PROTO_DSA = 3, - DSA_TAG_PROTO_EDSA = 4, - DSA_TAG_PROTO_GSWIP = 5, - DSA_TAG_PROTO_KSZ9477 = 6, - DSA_TAG_PROTO_KSZ9893 = 7, - DSA_TAG_PROTO_LAN9303 = 8, - DSA_TAG_PROTO_MTK = 9, - DSA_TAG_PROTO_QCA = 10, - DSA_TAG_PROTO_TRAILER = 11, - DSA_TAG_PROTO_8021Q = 12, - DSA_TAG_PROTO_SJA1105 = 13, - DSA_TAG_PROTO_KSZ8795 = 14, - DSA_TAG_PROTO_OCELOT = 15, - DSA_TAG_PROTO_AR9331 = 16, - DSA_TAG_PROTO_RTL4_A = 17, - DSA_TAG_PROTO_HELLCREEK = 18, - DSA_TAG_PROTO_XRS700X = 19, - DSA_TAG_PROTO_OCELOT_8021Q = 20, - DSA_TAG_PROTO_SEVILLE = 21, - DSA_TAG_PROTO_SJA1110 = 23, -}; - -struct dsa_device_ops { - struct sk_buff * (*xmit)(struct sk_buff *, struct net_device *); - struct sk_buff * (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *); - void (*flow_dissect)(const struct sk_buff *, __be16 *, int *); - bool (*filter)(const struct sk_buff *, struct net_device *); - unsigned int needed_headroom; - unsigned int needed_tailroom; - const char *name; - enum dsa_tag_protocol proto; - bool promisc_on_master; -}; - -struct dsa_netdevice_ops { - int (*ndo_do_ioctl)(struct net_device *, struct ifreq *, int); -}; - -struct dsa_switch_tree { - struct list_head list; - struct raw_notifier_head nh; - unsigned int index; - struct kref refcount; - bool setup; - const struct dsa_device_ops *tag_ops; - enum dsa_tag_protocol default_proto; - struct dsa_platform_data *pd; - struct list_head ports; - struct list_head rtable; - struct net_device **lags; - unsigned int lags_len; -}; - -struct dsa_mall_mirror_tc_entry { - u8 to_local_port; - bool ingress; -}; - -struct dsa_mall_policer_tc_entry { - u32 burst; - u64 rate_bytes_per_sec; -}; - -struct dsa_switch_ops; - -struct dsa_switch { - bool setup; - struct device *dev; - struct dsa_switch_tree *dst; - unsigned int index; - struct notifier_block nb; - void *priv; - struct dsa_chip_data *cd; - const struct dsa_switch_ops *ops; - u32 phys_mii_mask; - struct mii_bus *slave_mii_bus; - unsigned int ageing_time_min; - unsigned int ageing_time_max; - struct devlink *devlink; - unsigned int num_tx_queues; - bool vlan_filtering_is_global; - bool configure_vlan_while_not_filtering; - bool untag_bridge_pvid; - bool assisted_learning_on_cpu_port; - bool vlan_filtering; - bool pcs_poll; - bool mtu_enforcement_ingress; - unsigned int num_lag_ids; - size_t num_ports; -}; - -struct fixed_phy_status; - -typedef int dsa_fdb_dump_cb_t(const unsigned char *, u16, bool, void *); - -struct dsa_switch_ops { - enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *, int, enum dsa_tag_protocol); - int (*change_tag_protocol)(struct dsa_switch *, int, enum dsa_tag_protocol); - int (*setup)(struct dsa_switch *); - void (*teardown)(struct dsa_switch *); - u32 (*get_phy_flags)(struct dsa_switch *, int); - int (*phy_read)(struct dsa_switch *, int, int); - int (*phy_write)(struct dsa_switch *, int, int, u16); - void (*adjust_link)(struct dsa_switch *, int, struct phy_device *); - void (*fixed_link_update)(struct dsa_switch *, int, struct fixed_phy_status *); - void (*phylink_validate)(struct dsa_switch *, int, long unsigned int *, struct phylink_link_state *); - int (*phylink_mac_link_state)(struct dsa_switch *, int, struct phylink_link_state *); - void (*phylink_mac_config)(struct dsa_switch *, int, unsigned int, const struct phylink_link_state *); - void (*phylink_mac_an_restart)(struct dsa_switch *, int); - void (*phylink_mac_link_down)(struct dsa_switch *, int, unsigned int, phy_interface_t); - void (*phylink_mac_link_up)(struct dsa_switch *, int, unsigned int, phy_interface_t, struct phy_device *, int, int, bool, bool); - void (*phylink_fixed_state)(struct dsa_switch *, int, struct phylink_link_state *); - void (*get_strings)(struct dsa_switch *, int, u32, uint8_t *); - void (*get_ethtool_stats)(struct dsa_switch *, int, uint64_t *); - int (*get_sset_count)(struct dsa_switch *, int, int); - void (*get_ethtool_phy_stats)(struct dsa_switch *, int, uint64_t *); - void (*get_stats64)(struct dsa_switch *, int, struct rtnl_link_stats64 *); - void (*self_test)(struct dsa_switch *, int, struct ethtool_test *, u64 *); - void (*get_wol)(struct dsa_switch *, int, struct ethtool_wolinfo *); - int (*set_wol)(struct dsa_switch *, int, struct ethtool_wolinfo *); - int (*get_ts_info)(struct dsa_switch *, int, struct ethtool_ts_info *); - int (*suspend)(struct dsa_switch *); - int (*resume)(struct dsa_switch *); - int (*port_enable)(struct dsa_switch *, int, struct phy_device *); - void (*port_disable)(struct dsa_switch *, int); - int (*set_mac_eee)(struct dsa_switch *, int, struct ethtool_eee *); - int (*get_mac_eee)(struct dsa_switch *, int, struct ethtool_eee *); - int (*get_eeprom_len)(struct dsa_switch *); - int (*get_eeprom)(struct dsa_switch *, struct ethtool_eeprom *, u8 *); - int (*set_eeprom)(struct dsa_switch *, struct ethtool_eeprom *, u8 *); - int (*get_regs_len)(struct dsa_switch *, int); - void (*get_regs)(struct dsa_switch *, int, struct ethtool_regs *, void *); - int (*port_prechangeupper)(struct dsa_switch *, int, struct netdev_notifier_changeupper_info *); - int (*set_ageing_time)(struct dsa_switch *, unsigned int); - int (*port_bridge_join)(struct dsa_switch *, int, struct net_device *); - void (*port_bridge_leave)(struct dsa_switch *, int, struct net_device *); - void (*port_stp_state_set)(struct dsa_switch *, int, u8); - void (*port_fast_age)(struct dsa_switch *, int); - int (*port_pre_bridge_flags)(struct dsa_switch *, int, struct switchdev_brport_flags, struct netlink_ext_ack *); - int (*port_bridge_flags)(struct dsa_switch *, int, struct switchdev_brport_flags, struct netlink_ext_ack *); - int (*port_set_mrouter)(struct dsa_switch *, int, bool, struct netlink_ext_ack *); - int (*port_vlan_filtering)(struct dsa_switch *, int, bool, struct netlink_ext_ack *); - int (*port_vlan_add)(struct dsa_switch *, int, const struct switchdev_obj_port_vlan *, struct netlink_ext_ack *); - int (*port_vlan_del)(struct dsa_switch *, int, const struct switchdev_obj_port_vlan *); - int (*port_fdb_add)(struct dsa_switch *, int, const unsigned char *, u16); - int (*port_fdb_del)(struct dsa_switch *, int, const unsigned char *, u16); - int (*port_fdb_dump)(struct dsa_switch *, int, dsa_fdb_dump_cb_t *, void *); - int (*port_mdb_add)(struct dsa_switch *, int, const struct switchdev_obj_port_mdb *); - int (*port_mdb_del)(struct dsa_switch *, int, const struct switchdev_obj_port_mdb *); - int (*get_rxnfc)(struct dsa_switch *, int, struct ethtool_rxnfc *, u32 *); - int (*set_rxnfc)(struct dsa_switch *, int, struct ethtool_rxnfc *); - int (*cls_flower_add)(struct dsa_switch *, int, struct flow_cls_offload *, bool); - int (*cls_flower_del)(struct dsa_switch *, int, struct flow_cls_offload *, bool); - int (*cls_flower_stats)(struct dsa_switch *, int, struct flow_cls_offload *, bool); - int (*port_mirror_add)(struct dsa_switch *, int, struct dsa_mall_mirror_tc_entry *, bool); - void (*port_mirror_del)(struct dsa_switch *, int, struct dsa_mall_mirror_tc_entry *); - int (*port_policer_add)(struct dsa_switch *, int, struct dsa_mall_policer_tc_entry *); - void (*port_policer_del)(struct dsa_switch *, int); - int (*port_setup_tc)(struct dsa_switch *, int, enum tc_setup_type, void *); - int (*crosschip_bridge_join)(struct dsa_switch *, int, int, int, struct net_device *); - void (*crosschip_bridge_leave)(struct dsa_switch *, int, int, int, struct net_device *); - int (*crosschip_lag_change)(struct dsa_switch *, int, int); - int (*crosschip_lag_join)(struct dsa_switch *, int, int, struct net_device *, struct netdev_lag_upper_info *); - int (*crosschip_lag_leave)(struct dsa_switch *, int, int, struct net_device *); - int (*port_hwtstamp_get)(struct dsa_switch *, int, struct ifreq *); - int (*port_hwtstamp_set)(struct dsa_switch *, int, struct ifreq *); - void (*port_txtstamp)(struct dsa_switch *, int, struct sk_buff *); - bool (*port_rxtstamp)(struct dsa_switch *, int, struct sk_buff *, unsigned int); - int (*devlink_param_get)(struct dsa_switch *, u32, struct devlink_param_gset_ctx *); - int (*devlink_param_set)(struct dsa_switch *, u32, struct devlink_param_gset_ctx *); - int (*devlink_info_get)(struct dsa_switch *, struct devlink_info_req *, struct netlink_ext_ack *); - int (*devlink_sb_pool_get)(struct dsa_switch *, unsigned int, u16, struct devlink_sb_pool_info *); - int (*devlink_sb_pool_set)(struct dsa_switch *, unsigned int, u16, u32, enum devlink_sb_threshold_type, struct netlink_ext_ack *); - int (*devlink_sb_port_pool_get)(struct dsa_switch *, int, unsigned int, u16, u32 *); - int (*devlink_sb_port_pool_set)(struct dsa_switch *, int, unsigned int, u16, u32, struct netlink_ext_ack *); - int (*devlink_sb_tc_pool_bind_get)(struct dsa_switch *, int, unsigned int, u16, enum devlink_sb_pool_type, u16 *, u32 *); - int (*devlink_sb_tc_pool_bind_set)(struct dsa_switch *, int, unsigned int, u16, enum devlink_sb_pool_type, u16, u32, struct netlink_ext_ack *); - int (*devlink_sb_occ_snapshot)(struct dsa_switch *, unsigned int); - int (*devlink_sb_occ_max_clear)(struct dsa_switch *, unsigned int); - int (*devlink_sb_occ_port_pool_get)(struct dsa_switch *, int, unsigned int, u16, u32 *, u32 *); - int (*devlink_sb_occ_tc_port_bind_get)(struct dsa_switch *, int, unsigned int, u16, enum devlink_sb_pool_type, u32 *, u32 *); - int (*port_change_mtu)(struct dsa_switch *, int, int); - int (*port_max_mtu)(struct dsa_switch *, int); - int (*port_lag_change)(struct dsa_switch *, int); - int (*port_lag_join)(struct dsa_switch *, int, struct net_device *, struct netdev_lag_upper_info *); - int (*port_lag_leave)(struct dsa_switch *, int, struct net_device *); - int (*port_hsr_join)(struct dsa_switch *, int, struct net_device *); - int (*port_hsr_leave)(struct dsa_switch *, int, struct net_device *); - int (*port_mrp_add)(struct dsa_switch *, int, const struct switchdev_obj_mrp *); - int (*port_mrp_del)(struct dsa_switch *, int, const struct switchdev_obj_mrp *); - int (*port_mrp_add_ring_role)(struct dsa_switch *, int, const struct switchdev_obj_ring_role_mrp *); - int (*port_mrp_del_ring_role)(struct dsa_switch *, int, const struct switchdev_obj_ring_role_mrp *); -}; - -enum lwtunnel_encap_types { - LWTUNNEL_ENCAP_NONE = 0, - LWTUNNEL_ENCAP_MPLS = 1, - LWTUNNEL_ENCAP_IP = 2, - LWTUNNEL_ENCAP_ILA = 3, - LWTUNNEL_ENCAP_IP6 = 4, - LWTUNNEL_ENCAP_SEG6 = 5, - LWTUNNEL_ENCAP_BPF = 6, - LWTUNNEL_ENCAP_SEG6_LOCAL = 7, - LWTUNNEL_ENCAP_RPL = 8, - __LWTUNNEL_ENCAP_MAX = 9, -}; - -struct nh_info { - struct hlist_node dev_hash; - struct nexthop *nh_parent; - u8 family; - bool reject_nh; - bool fdb_nh; - union { - struct fib_nh_common fib_nhc; - struct fib_nh fib_nh; - struct fib6_nh fib6_nh; - }; -}; - -struct nh_grp_entry; - -struct nh_res_bucket { - struct nh_grp_entry *nh_entry; - atomic_long_t used_time; - long unsigned int migrated_time; - bool occupied; - u8 nh_flags; -}; - -struct nh_grp_entry { - struct nexthop *nh; - u8 weight; - union { - struct { - atomic_t upper_bound; - } hthr; - struct { - struct list_head uw_nh_entry; - u16 count_buckets; - u16 wants_buckets; - } res; - }; - struct list_head nh_list; - struct nexthop *nh_parent; -}; - -struct nh_res_table { - struct net *net; - u32 nhg_id; - struct delayed_work upkeep_dw; - struct list_head uw_nh_entries; - long unsigned int unbalanced_since; - u32 idle_timer; - u32 unbalanced_timer; - u16 num_nh_buckets; - struct nh_res_bucket nh_buckets[0]; -}; - -struct nh_group { - struct nh_group *spare; - u16 num_nh; - bool is_multipath; - bool hash_threshold; - bool resilient; - bool fdb_nh; - bool has_v4; - struct nh_res_table *res_table; - struct nh_grp_entry nh_entries[0]; -}; - -enum metadata_type { - METADATA_IP_TUNNEL = 0, - METADATA_HW_PORT_MUX = 1, -}; - -struct hw_port_info { - struct net_device *lower_dev; - u32 port_id; -}; - -struct metadata_dst { - struct dst_entry dst; - enum metadata_type type; - union { - struct ip_tunnel_info tun_info; - struct hw_port_info port_info; - } u; -}; - -struct gre_base_hdr { - __be16 flags; - __be16 protocol; -}; - -struct gre_full_hdr { - struct gre_base_hdr fixed_header; - __be16 csum; - __be16 reserved1; - __be32 key; - __be32 seq; -}; - -struct pptp_gre_header { - struct gre_base_hdr gre_hd; - __be16 payload_len; - __be16 call_id; - __be32 seq; - __be32 ack; -}; - -struct tipc_basic_hdr { - __be32 w[4]; -}; - -struct icmphdr { - __u8 type; - __u8 code; - __sum16 checksum; - union { - struct { - __be16 id; - __be16 sequence; - } echo; - __be32 gateway; - struct { - __be16 __unused; - __be16 mtu; - } frag; - __u8 reserved[4]; - } un; -}; - -enum l2tp_debug_flags { - L2TP_MSG_DEBUG = 1, - L2TP_MSG_CONTROL = 2, - L2TP_MSG_SEQ = 4, - L2TP_MSG_DATA = 8, -}; - -struct pppoe_tag { - __be16 tag_type; - __be16 tag_len; - char tag_data[0]; -}; - -struct pppoe_hdr { - __u8 type: 4; - __u8 ver: 4; - __u8 code; - __be16 sid; - __be16 length; - struct pppoe_tag tag[0]; -}; - -struct mpls_label { - __be32 entry; -}; - -struct clock_identity { - u8 id[8]; -}; - -struct port_identity { - struct clock_identity clock_identity; - __be16 port_number; -}; - -struct ptp_header { - u8 tsmt; - u8 ver; - __be16 message_length; - u8 domain_number; - u8 reserved1; - u8 flag_field[2]; - __be64 correction; - __be32 reserved2; - struct port_identity source_port_identity; - __be16 sequence_id; - u8 control; - u8 log_message_interval; -} __attribute__((packed)); - -enum batadv_packettype { - BATADV_IV_OGM = 0, - BATADV_BCAST = 1, - BATADV_CODED = 2, - BATADV_ELP = 3, - BATADV_OGM2 = 4, - BATADV_UNICAST = 64, - BATADV_UNICAST_FRAG = 65, - BATADV_UNICAST_4ADDR = 66, - BATADV_ICMP = 67, - BATADV_UNICAST_TVLV = 68, -}; - -struct batadv_unicast_packet { - __u8 packet_type; - __u8 version; - __u8 ttl; - __u8 ttvn; - __u8 dest[6]; -}; - -struct nf_conntrack_zone { - u16 id; - u8 flags; - u8 dir; -}; - -struct nf_conntrack_man { - union nf_inet_addr u3; - union nf_conntrack_man_proto u; - u_int16_t l3num; -}; - -struct nf_conntrack_tuple { - struct nf_conntrack_man src; - struct { - union nf_inet_addr u3; - union { - __be16 all; - struct { - __be16 port; - } tcp; - struct { - __be16 port; - } udp; - struct { - u_int8_t type; - u_int8_t code; - } icmp; - struct { - __be16 port; - } dccp; - struct { - __be16 port; - } sctp; - struct { - __be16 key; - } gre; - } u; - u_int8_t protonum; - u_int8_t dir; - } dst; -}; - -struct nf_conntrack_tuple_hash { - struct hlist_nulls_node hnnode; - struct nf_conntrack_tuple tuple; -}; - -struct nf_ct_udp { - long unsigned int stream_ts; -}; - -struct nf_ct_gre { - unsigned int stream_timeout; - unsigned int timeout; -}; - -union nf_conntrack_proto { - struct nf_ct_dccp dccp; - struct ip_ct_sctp sctp; - struct ip_ct_tcp tcp; - struct nf_ct_udp udp; - struct nf_ct_gre gre; - unsigned int tmpl_padto; -}; - -struct nf_ct_ext; - -struct nf_conn { - struct nf_conntrack ct_general; - spinlock_t lock; - u32 timeout; - struct nf_conntrack_zone zone; - struct nf_conntrack_tuple_hash tuplehash[2]; - long unsigned int status; - u16 cpu; - possible_net_t ct_net; - struct hlist_node nat_bysource; - struct { } __nfct_init_offset; - struct nf_conn *master; - u_int32_t mark; - u_int32_t secmark; - struct nf_ct_ext *ext; - union nf_conntrack_proto proto; -}; - -struct nf_conntrack_tuple_mask { - struct { - union nf_inet_addr u3; - union nf_conntrack_man_proto u; - } src; -}; - -struct nf_ct_ext { - u8 offset[9]; - u8 len; - char data[0]; -}; - -struct nf_conntrack_helper; - -struct nf_conntrack_expect { - struct hlist_node lnode; - struct hlist_node hnode; - struct nf_conntrack_tuple tuple; - struct nf_conntrack_tuple_mask mask; - void (*expectfn)(struct nf_conn *, struct nf_conntrack_expect *); - struct nf_conntrack_helper *helper; - struct nf_conn *master; - struct timer_list timeout; - refcount_t use; - unsigned int flags; - unsigned int class; - union nf_inet_addr saved_addr; - union nf_conntrack_man_proto saved_proto; - enum ip_conntrack_dir dir; - struct callback_head rcu; -}; - -enum nf_ct_ext_id { - NF_CT_EXT_HELPER = 0, - NF_CT_EXT_NAT = 1, - NF_CT_EXT_SEQADJ = 2, - NF_CT_EXT_ACCT = 3, - NF_CT_EXT_ECACHE = 4, - NF_CT_EXT_TSTAMP = 5, - NF_CT_EXT_TIMEOUT = 6, - NF_CT_EXT_LABELS = 7, - NF_CT_EXT_SYNPROXY = 8, - NF_CT_EXT_NUM = 9, -}; - -struct nf_ct_event { - struct nf_conn *ct; - u32 portid; - int report; -}; - -struct nf_exp_event { - struct nf_conntrack_expect *exp; - u32 portid; - int report; -}; - -struct nf_conn_labels { - long unsigned int bits[2]; -}; - -struct _flow_keys_digest_data { - __be16 n_proto; - u8 ip_proto; - u8 padding; - __be32 ports; - __be32 src; - __be32 dst; -}; - -struct rps_sock_flow_table { - u32 mask; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 ents[0]; -}; - -struct tc_skb_ext { - __u32 chain; - __u16 mru; - bool post_ct; -}; - -struct ipv4_devconf { - void *sysctl; - int data[32]; - long unsigned int state[1]; -}; - -enum nf_dev_hooks { - NF_NETDEV_INGRESS = 0, - NF_NETDEV_NUMHOOKS = 1, -}; - -enum { - IF_OPER_UNKNOWN = 0, - IF_OPER_NOTPRESENT = 1, - IF_OPER_DOWN = 2, - IF_OPER_LOWERLAYERDOWN = 3, - IF_OPER_TESTING = 4, - IF_OPER_DORMANT = 5, - IF_OPER_UP = 6, -}; - -struct ifbond { - __s32 bond_mode; - __s32 num_slaves; - __s32 miimon; -}; - -typedef struct ifbond ifbond; - -struct ifslave { - __s32 slave_id; - char slave_name[16]; - __s8 link; - __s8 state; - __u32 link_failure_count; -}; - -typedef struct ifslave ifslave; - -enum netdev_state_t { - __LINK_STATE_START = 0, - __LINK_STATE_PRESENT = 1, - __LINK_STATE_NOCARRIER = 2, - __LINK_STATE_LINKWATCH_PENDING = 3, - __LINK_STATE_DORMANT = 4, - __LINK_STATE_TESTING = 5, -}; - -struct netdev_boot_setup { - char name[16]; - struct ifmap map; -}; - -enum { - NAPIF_STATE_SCHED = 1, - NAPIF_STATE_MISSED = 2, - NAPIF_STATE_DISABLE = 4, - NAPIF_STATE_NPSVC = 8, - NAPIF_STATE_LISTED = 16, - NAPIF_STATE_NO_BUSY_POLL = 32, - NAPIF_STATE_IN_BUSY_POLL = 64, - NAPIF_STATE_PREFER_BUSY_POLL = 128, - NAPIF_STATE_THREADED = 256, - NAPIF_STATE_SCHED_THREADED = 512, -}; - -enum gro_result { - GRO_MERGED = 0, - GRO_MERGED_FREE = 1, - GRO_HELD = 2, - GRO_NORMAL = 3, - GRO_CONSUMED = 4, -}; - -typedef enum gro_result gro_result_t; - -enum netdev_queue_state_t { - __QUEUE_STATE_DRV_XOFF = 0, - __QUEUE_STATE_STACK_XOFF = 1, - __QUEUE_STATE_FROZEN = 2, -}; - -struct net_device_path_stack { - int num_paths; - struct net_device_path path[5]; -}; - -struct bpf_xdp_link { - struct bpf_link link; - struct net_device *dev; - int flags; -}; - -struct netdev_net_notifier { - struct list_head list; - struct notifier_block *nb; -}; - -struct netpoll; - -struct netpoll_info { - refcount_t refcnt; - struct semaphore dev_lock; - struct sk_buff_head txq; - struct delayed_work tx_work; - struct netpoll *netpoll; - struct callback_head rcu; -}; - -struct in_ifaddr; - -struct ip_mc_list; - -struct in_device { - struct net_device *dev; - refcount_t refcnt; - int dead; - struct in_ifaddr *ifa_list; - struct ip_mc_list *mc_list; - struct ip_mc_list **mc_hash; - int mc_count; - spinlock_t mc_tomb_lock; - struct ip_mc_list *mc_tomb; - long unsigned int mr_v1_seen; - long unsigned int mr_v2_seen; - long unsigned int mr_maxdelay; - long unsigned int mr_qi; - long unsigned int mr_qri; - unsigned char mr_qrv; - unsigned char mr_gq_running; - u32 mr_ifc_count; - struct timer_list mr_gq_timer; - struct timer_list mr_ifc_timer; - struct neigh_parms *arp_parms; - struct ipv4_devconf cnf; - struct callback_head callback_head; -}; - -struct offload_callbacks { - struct sk_buff * (*gso_segment)(struct sk_buff *, netdev_features_t); - struct sk_buff * (*gro_receive)(struct list_head *, struct sk_buff *); - int (*gro_complete)(struct sk_buff *, int); -}; - -struct packet_offload { - __be16 type; - u16 priority; - struct offload_callbacks callbacks; - struct list_head list; -}; - -struct netdev_notifier_info_ext { - struct netdev_notifier_info info; - union { - u32 mtu; - } ext; -}; - -struct netdev_notifier_change_info { - struct netdev_notifier_info info; - unsigned int flags_changed; -}; - -struct netdev_notifier_changelowerstate_info { - struct netdev_notifier_info info; - void *lower_state_info; -}; - -struct netdev_notifier_pre_changeaddr_info { - struct netdev_notifier_info info; - const unsigned char *dev_addr; -}; - -typedef int (*bpf_op_t)(struct net_device *, struct netdev_bpf *); - -enum { - NESTED_SYNC_IMM_BIT = 0, - NESTED_SYNC_TODO_BIT = 1, -}; - -struct netdev_nested_priv { - unsigned char flags; - void *data; -}; - -struct netdev_bonding_info { - ifslave slave; - ifbond master; -}; - -struct netdev_notifier_bonding_info { - struct netdev_notifier_info info; - struct netdev_bonding_info bonding_info; -}; - -union inet_addr { - __u32 all[4]; - __be32 ip; - __be32 ip6[4]; - struct in_addr in; - struct in6_addr in6; -}; - -struct netpoll { - struct net_device *dev; - char dev_name[16]; - const char *name; - union inet_addr local_ip; - union inet_addr remote_ip; - bool ipv6; - u16 local_port; - u16 remote_port; - u8 remote_mac[6]; -}; - -enum qdisc_state_t { - __QDISC_STATE_SCHED = 0, - __QDISC_STATE_DEACTIVATED = 1, - __QDISC_STATE_MISSED = 2, - __QDISC_STATE_DRAINING = 3, -}; - -struct tcf_walker { - int stop; - int skip; - int count; - bool nonempty; - long unsigned int cookie; - int (*fn)(struct tcf_proto *, void *, struct tcf_walker *); -}; - -enum { - IPV4_DEVCONF_FORWARDING = 1, - IPV4_DEVCONF_MC_FORWARDING = 2, - IPV4_DEVCONF_PROXY_ARP = 3, - IPV4_DEVCONF_ACCEPT_REDIRECTS = 4, - IPV4_DEVCONF_SECURE_REDIRECTS = 5, - IPV4_DEVCONF_SEND_REDIRECTS = 6, - IPV4_DEVCONF_SHARED_MEDIA = 7, - IPV4_DEVCONF_RP_FILTER = 8, - IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE = 9, - IPV4_DEVCONF_BOOTP_RELAY = 10, - IPV4_DEVCONF_LOG_MARTIANS = 11, - IPV4_DEVCONF_TAG = 12, - IPV4_DEVCONF_ARPFILTER = 13, - IPV4_DEVCONF_MEDIUM_ID = 14, - IPV4_DEVCONF_NOXFRM = 15, - IPV4_DEVCONF_NOPOLICY = 16, - IPV4_DEVCONF_FORCE_IGMP_VERSION = 17, - IPV4_DEVCONF_ARP_ANNOUNCE = 18, - IPV4_DEVCONF_ARP_IGNORE = 19, - IPV4_DEVCONF_PROMOTE_SECONDARIES = 20, - IPV4_DEVCONF_ARP_ACCEPT = 21, - IPV4_DEVCONF_ARP_NOTIFY = 22, - IPV4_DEVCONF_ACCEPT_LOCAL = 23, - IPV4_DEVCONF_SRC_VMARK = 24, - IPV4_DEVCONF_PROXY_ARP_PVLAN = 25, - IPV4_DEVCONF_ROUTE_LOCALNET = 26, - IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL = 27, - IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL = 28, - IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN = 29, - IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST = 30, - IPV4_DEVCONF_DROP_GRATUITOUS_ARP = 31, - IPV4_DEVCONF_BC_FORWARDING = 32, - __IPV4_DEVCONF_MAX = 33, -}; - -struct in_ifaddr { - struct hlist_node hash; - struct in_ifaddr *ifa_next; - struct in_device *ifa_dev; - struct callback_head callback_head; - __be32 ifa_local; - __be32 ifa_address; - __be32 ifa_mask; - __u32 ifa_rt_priority; - __be32 ifa_broadcast; - unsigned char ifa_scope; - unsigned char ifa_prefixlen; - __u32 ifa_flags; - char ifa_label[16]; - __u32 ifa_valid_lft; - __u32 ifa_preferred_lft; - long unsigned int ifa_cstamp; - long unsigned int ifa_tstamp; -}; - -struct udp_tunnel_info { - short unsigned int type; - sa_family_t sa_family; - __be16 port; - u8 hw_priv; -}; - -struct udp_tunnel_nic_shared { - struct udp_tunnel_nic *udp_tunnel_nic_info; - struct list_head devices; -}; - -struct dev_kfree_skb_cb { - enum skb_free_reason reason; -}; - -struct netdev_adjacent { - struct net_device *dev; - bool master; - bool ignore; - u16 ref_nr; - void *private; - struct list_head list; - struct callback_head rcu; -}; - -struct netdev_hw_addr { - struct list_head list; - unsigned char addr[32]; - unsigned char type; - bool global_use; - int sync_cnt; - int refcount; - int synced; - struct callback_head callback_head; -}; - -enum { - NDA_UNSPEC = 0, - NDA_DST = 1, - NDA_LLADDR = 2, - NDA_CACHEINFO = 3, - NDA_PROBES = 4, - NDA_VLAN = 5, - NDA_PORT = 6, - NDA_VNI = 7, - NDA_IFINDEX = 8, - NDA_MASTER = 9, - NDA_LINK_NETNSID = 10, - NDA_SRC_VNI = 11, - NDA_PROTOCOL = 12, - NDA_NH_ID = 13, - NDA_FDB_EXT_ATTRS = 14, - __NDA_MAX = 15, -}; - -struct nda_cacheinfo { - __u32 ndm_confirmed; - __u32 ndm_used; - __u32 ndm_updated; - __u32 ndm_refcnt; -}; - -struct ndt_stats { - __u64 ndts_allocs; - __u64 ndts_destroys; - __u64 ndts_hash_grows; - __u64 ndts_res_failed; - __u64 ndts_lookups; - __u64 ndts_hits; - __u64 ndts_rcv_probes_mcast; - __u64 ndts_rcv_probes_ucast; - __u64 ndts_periodic_gc_runs; - __u64 ndts_forced_gc_runs; - __u64 ndts_table_fulls; -}; - -enum { - NDTPA_UNSPEC = 0, - NDTPA_IFINDEX = 1, - NDTPA_REFCNT = 2, - NDTPA_REACHABLE_TIME = 3, - NDTPA_BASE_REACHABLE_TIME = 4, - NDTPA_RETRANS_TIME = 5, - NDTPA_GC_STALETIME = 6, - NDTPA_DELAY_PROBE_TIME = 7, - NDTPA_QUEUE_LEN = 8, - NDTPA_APP_PROBES = 9, - NDTPA_UCAST_PROBES = 10, - NDTPA_MCAST_PROBES = 11, - NDTPA_ANYCAST_DELAY = 12, - NDTPA_PROXY_DELAY = 13, - NDTPA_PROXY_QLEN = 14, - NDTPA_LOCKTIME = 15, - NDTPA_QUEUE_LENBYTES = 16, - NDTPA_MCAST_REPROBES = 17, - NDTPA_PAD = 18, - __NDTPA_MAX = 19, -}; - -struct ndtmsg { - __u8 ndtm_family; - __u8 ndtm_pad1; - __u16 ndtm_pad2; -}; - -struct ndt_config { - __u16 ndtc_key_len; - __u16 ndtc_entry_size; - __u32 ndtc_entries; - __u32 ndtc_last_flush; - __u32 ndtc_last_rand; - __u32 ndtc_hash_rnd; - __u32 ndtc_hash_mask; - __u32 ndtc_hash_chain_gc; - __u32 ndtc_proxy_qlen; -}; - -enum { - NDTA_UNSPEC = 0, - NDTA_NAME = 1, - NDTA_THRESH1 = 2, - NDTA_THRESH2 = 3, - NDTA_THRESH3 = 4, - NDTA_CONFIG = 5, - NDTA_PARMS = 6, - NDTA_STATS = 7, - NDTA_GC_INTERVAL = 8, - NDTA_PAD = 9, - __NDTA_MAX = 10, -}; - -enum { - RTN_UNSPEC = 0, - RTN_UNICAST = 1, - RTN_LOCAL = 2, - RTN_BROADCAST = 3, - RTN_ANYCAST = 4, - RTN_MULTICAST = 5, - RTN_BLACKHOLE = 6, - RTN_UNREACHABLE = 7, - RTN_PROHIBIT = 8, - RTN_THROW = 9, - RTN_NAT = 10, - RTN_XRESOLVE = 11, - __RTN_MAX = 12, -}; - -enum { - NEIGH_ARP_TABLE = 0, - NEIGH_ND_TABLE = 1, - NEIGH_DN_TABLE = 2, - NEIGH_NR_TABLES = 3, - NEIGH_LINK_TABLE = 3, -}; - -struct neigh_seq_state { - struct seq_net_private p; - struct neigh_table *tbl; - struct neigh_hash_table *nht; - void * (*neigh_sub_iter)(struct neigh_seq_state *, struct neighbour *, loff_t *); - unsigned int bucket; - unsigned int flags; -}; - -struct neighbour_cb { - long unsigned int sched_next; - unsigned int flags; -}; - -enum netevent_notif_type { - NETEVENT_NEIGH_UPDATE = 1, - NETEVENT_REDIRECT = 2, - NETEVENT_DELAY_PROBE_TIME_UPDATE = 3, - NETEVENT_IPV4_MPATH_HASH_UPDATE = 4, - NETEVENT_IPV6_MPATH_HASH_UPDATE = 5, - NETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE = 6, -}; - -struct neigh_dump_filter { - int master_idx; - int dev_idx; -}; - -struct neigh_sysctl_table { - struct ctl_table_header *sysctl_header; - struct ctl_table neigh_vars[21]; -}; - -struct netlink_dump_control { - int (*start)(struct netlink_callback *); - int (*dump)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - void *data; - struct module *module; - u32 min_dump_alloc; -}; - -struct rtnl_link_stats { - __u32 rx_packets; - __u32 tx_packets; - __u32 rx_bytes; - __u32 tx_bytes; - __u32 rx_errors; - __u32 tx_errors; - __u32 rx_dropped; - __u32 tx_dropped; - __u32 multicast; - __u32 collisions; - __u32 rx_length_errors; - __u32 rx_over_errors; - __u32 rx_crc_errors; - __u32 rx_frame_errors; - __u32 rx_fifo_errors; - __u32 rx_missed_errors; - __u32 tx_aborted_errors; - __u32 tx_carrier_errors; - __u32 tx_fifo_errors; - __u32 tx_heartbeat_errors; - __u32 tx_window_errors; - __u32 rx_compressed; - __u32 tx_compressed; - __u32 rx_nohandler; -}; - -struct rtnl_link_ifmap { - __u64 mem_start; - __u64 mem_end; - __u64 base_addr; - __u16 irq; - __u8 dma; - __u8 port; -}; - -enum { - IFLA_PROTO_DOWN_REASON_UNSPEC = 0, - IFLA_PROTO_DOWN_REASON_MASK = 1, - IFLA_PROTO_DOWN_REASON_VALUE = 2, - __IFLA_PROTO_DOWN_REASON_CNT = 3, - IFLA_PROTO_DOWN_REASON_MAX = 2, -}; - -enum { - IFLA_BRPORT_UNSPEC = 0, - IFLA_BRPORT_STATE = 1, - IFLA_BRPORT_PRIORITY = 2, - IFLA_BRPORT_COST = 3, - IFLA_BRPORT_MODE = 4, - IFLA_BRPORT_GUARD = 5, - IFLA_BRPORT_PROTECT = 6, - IFLA_BRPORT_FAST_LEAVE = 7, - IFLA_BRPORT_LEARNING = 8, - IFLA_BRPORT_UNICAST_FLOOD = 9, - IFLA_BRPORT_PROXYARP = 10, - IFLA_BRPORT_LEARNING_SYNC = 11, - IFLA_BRPORT_PROXYARP_WIFI = 12, - IFLA_BRPORT_ROOT_ID = 13, - IFLA_BRPORT_BRIDGE_ID = 14, - IFLA_BRPORT_DESIGNATED_PORT = 15, - IFLA_BRPORT_DESIGNATED_COST = 16, - IFLA_BRPORT_ID = 17, - IFLA_BRPORT_NO = 18, - IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19, - IFLA_BRPORT_CONFIG_PENDING = 20, - IFLA_BRPORT_MESSAGE_AGE_TIMER = 21, - IFLA_BRPORT_FORWARD_DELAY_TIMER = 22, - IFLA_BRPORT_HOLD_TIMER = 23, - IFLA_BRPORT_FLUSH = 24, - IFLA_BRPORT_MULTICAST_ROUTER = 25, - IFLA_BRPORT_PAD = 26, - IFLA_BRPORT_MCAST_FLOOD = 27, - IFLA_BRPORT_MCAST_TO_UCAST = 28, - IFLA_BRPORT_VLAN_TUNNEL = 29, - IFLA_BRPORT_BCAST_FLOOD = 30, - IFLA_BRPORT_GROUP_FWD_MASK = 31, - IFLA_BRPORT_NEIGH_SUPPRESS = 32, - IFLA_BRPORT_ISOLATED = 33, - IFLA_BRPORT_BACKUP_PORT = 34, - IFLA_BRPORT_MRP_RING_OPEN = 35, - IFLA_BRPORT_MRP_IN_OPEN = 36, - IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT = 37, - IFLA_BRPORT_MCAST_EHT_HOSTS_CNT = 38, - __IFLA_BRPORT_MAX = 39, -}; - -enum { - IFLA_VF_INFO_UNSPEC = 0, - IFLA_VF_INFO = 1, - __IFLA_VF_INFO_MAX = 2, -}; - -enum { - IFLA_VF_UNSPEC = 0, - IFLA_VF_MAC = 1, - IFLA_VF_VLAN = 2, - IFLA_VF_TX_RATE = 3, - IFLA_VF_SPOOFCHK = 4, - IFLA_VF_LINK_STATE = 5, - IFLA_VF_RATE = 6, - IFLA_VF_RSS_QUERY_EN = 7, - IFLA_VF_STATS = 8, - IFLA_VF_TRUST = 9, - IFLA_VF_IB_NODE_GUID = 10, - IFLA_VF_IB_PORT_GUID = 11, - IFLA_VF_VLAN_LIST = 12, - IFLA_VF_BROADCAST = 13, - __IFLA_VF_MAX = 14, -}; - -struct ifla_vf_mac { - __u32 vf; - __u8 mac[32]; -}; - -struct ifla_vf_broadcast { - __u8 broadcast[32]; -}; - -struct ifla_vf_vlan { - __u32 vf; - __u32 vlan; - __u32 qos; -}; - -enum { - IFLA_VF_VLAN_INFO_UNSPEC = 0, - IFLA_VF_VLAN_INFO = 1, - __IFLA_VF_VLAN_INFO_MAX = 2, -}; - -struct ifla_vf_vlan_info { - __u32 vf; - __u32 vlan; - __u32 qos; - __be16 vlan_proto; -}; - -struct ifla_vf_tx_rate { - __u32 vf; - __u32 rate; -}; - -struct ifla_vf_rate { - __u32 vf; - __u32 min_tx_rate; - __u32 max_tx_rate; -}; - -struct ifla_vf_spoofchk { - __u32 vf; - __u32 setting; -}; - -struct ifla_vf_link_state { - __u32 vf; - __u32 link_state; -}; - -struct ifla_vf_rss_query_en { - __u32 vf; - __u32 setting; -}; - -enum { - IFLA_VF_STATS_RX_PACKETS = 0, - IFLA_VF_STATS_TX_PACKETS = 1, - IFLA_VF_STATS_RX_BYTES = 2, - IFLA_VF_STATS_TX_BYTES = 3, - IFLA_VF_STATS_BROADCAST = 4, - IFLA_VF_STATS_MULTICAST = 5, - IFLA_VF_STATS_PAD = 6, - IFLA_VF_STATS_RX_DROPPED = 7, - IFLA_VF_STATS_TX_DROPPED = 8, - __IFLA_VF_STATS_MAX = 9, -}; - -struct ifla_vf_trust { - __u32 vf; - __u32 setting; -}; - -enum { - IFLA_VF_PORT_UNSPEC = 0, - IFLA_VF_PORT = 1, - __IFLA_VF_PORT_MAX = 2, -}; - -enum { - IFLA_PORT_UNSPEC = 0, - IFLA_PORT_VF = 1, - IFLA_PORT_PROFILE = 2, - IFLA_PORT_VSI_TYPE = 3, - IFLA_PORT_INSTANCE_UUID = 4, - IFLA_PORT_HOST_UUID = 5, - IFLA_PORT_REQUEST = 6, - IFLA_PORT_RESPONSE = 7, - __IFLA_PORT_MAX = 8, -}; - -struct if_stats_msg { - __u8 family; - __u8 pad1; - __u16 pad2; - __u32 ifindex; - __u32 filter_mask; -}; - -enum { - IFLA_STATS_UNSPEC = 0, - IFLA_STATS_LINK_64 = 1, - IFLA_STATS_LINK_XSTATS = 2, - IFLA_STATS_LINK_XSTATS_SLAVE = 3, - IFLA_STATS_LINK_OFFLOAD_XSTATS = 4, - IFLA_STATS_AF_SPEC = 5, - __IFLA_STATS_MAX = 6, -}; - -enum { - IFLA_OFFLOAD_XSTATS_UNSPEC = 0, - IFLA_OFFLOAD_XSTATS_CPU_HIT = 1, - __IFLA_OFFLOAD_XSTATS_MAX = 2, -}; - -enum { - XDP_ATTACHED_NONE = 0, - XDP_ATTACHED_DRV = 1, - XDP_ATTACHED_SKB = 2, - XDP_ATTACHED_HW = 3, - XDP_ATTACHED_MULTI = 4, -}; - -enum { - IFLA_XDP_UNSPEC = 0, - IFLA_XDP_FD = 1, - IFLA_XDP_ATTACHED = 2, - IFLA_XDP_FLAGS = 3, - IFLA_XDP_PROG_ID = 4, - IFLA_XDP_DRV_PROG_ID = 5, - IFLA_XDP_SKB_PROG_ID = 6, - IFLA_XDP_HW_PROG_ID = 7, - IFLA_XDP_EXPECTED_FD = 8, - __IFLA_XDP_MAX = 9, -}; - -enum { - IFLA_EVENT_NONE = 0, - IFLA_EVENT_REBOOT = 1, - IFLA_EVENT_FEATURES = 2, - IFLA_EVENT_BONDING_FAILOVER = 3, - IFLA_EVENT_NOTIFY_PEERS = 4, - IFLA_EVENT_IGMP_RESEND = 5, - IFLA_EVENT_BONDING_OPTIONS = 6, -}; - -enum { - IFLA_BRIDGE_FLAGS = 0, - IFLA_BRIDGE_MODE = 1, - IFLA_BRIDGE_VLAN_INFO = 2, - IFLA_BRIDGE_VLAN_TUNNEL_INFO = 3, - IFLA_BRIDGE_MRP = 4, - IFLA_BRIDGE_CFM = 5, - __IFLA_BRIDGE_MAX = 6, -}; - -enum { - BR_MCAST_DIR_RX = 0, - BR_MCAST_DIR_TX = 1, - BR_MCAST_DIR_SIZE = 2, -}; - -enum rtattr_type_t { - RTA_UNSPEC = 0, - RTA_DST = 1, - RTA_SRC = 2, - RTA_IIF = 3, - RTA_OIF = 4, - RTA_GATEWAY = 5, - RTA_PRIORITY = 6, - RTA_PREFSRC = 7, - RTA_METRICS = 8, - RTA_MULTIPATH = 9, - RTA_PROTOINFO = 10, - RTA_FLOW = 11, - RTA_CACHEINFO = 12, - RTA_SESSION = 13, - RTA_MP_ALGO = 14, - RTA_TABLE = 15, - RTA_MARK = 16, - RTA_MFC_STATS = 17, - RTA_VIA = 18, - RTA_NEWDST = 19, - RTA_PREF = 20, - RTA_ENCAP_TYPE = 21, - RTA_ENCAP = 22, - RTA_EXPIRES = 23, - RTA_PAD = 24, - RTA_UID = 25, - RTA_TTL_PROPAGATE = 26, - RTA_IP_PROTO = 27, - RTA_SPORT = 28, - RTA_DPORT = 29, - RTA_NH_ID = 30, - __RTA_MAX = 31, -}; - -struct rta_cacheinfo { - __u32 rta_clntref; - __u32 rta_lastuse; - __s32 rta_expires; - __u32 rta_error; - __u32 rta_used; - __u32 rta_id; - __u32 rta_ts; - __u32 rta_tsage; -}; - -struct rtnl_af_ops { - struct list_head list; - int family; - int (*fill_link_af)(struct sk_buff *, const struct net_device *, u32); - size_t (*get_link_af_size)(const struct net_device *, u32); - int (*validate_link_af)(const struct net_device *, const struct nlattr *); - int (*set_link_af)(struct net_device *, const struct nlattr *, struct netlink_ext_ack *); - int (*fill_stats_af)(struct sk_buff *, const struct net_device *); - size_t (*get_stats_af_size)(const struct net_device *); -}; - -struct rtnl_link { - rtnl_doit_func doit; - rtnl_dumpit_func dumpit; - struct module *owner; - unsigned int flags; - struct callback_head rcu; -}; - -enum { - IF_LINK_MODE_DEFAULT = 0, - IF_LINK_MODE_DORMANT = 1, - IF_LINK_MODE_TESTING = 2, -}; - -enum lw_bits { - LW_URGENT = 0, -}; - -struct seg6_pernet_data { - struct mutex lock; - struct in6_addr *tun_src; - struct rhashtable hmac_infos; -}; - -enum { - BPF_F_RECOMPUTE_CSUM = 1, - BPF_F_INVALIDATE_HASH = 2, -}; - -enum { - BPF_F_HDR_FIELD_MASK = 15, -}; - -enum { - BPF_F_PSEUDO_HDR = 16, - BPF_F_MARK_MANGLED_0 = 32, - BPF_F_MARK_ENFORCE = 64, -}; - -enum { - BPF_F_INGRESS = 1, -}; - -enum { - BPF_F_TUNINFO_IPV6 = 1, -}; - -enum { - BPF_F_ZERO_CSUM_TX = 2, - BPF_F_DONT_FRAGMENT = 4, - BPF_F_SEQ_NUMBER = 8, -}; - -enum { - BPF_CSUM_LEVEL_QUERY = 0, - BPF_CSUM_LEVEL_INC = 1, - BPF_CSUM_LEVEL_DEC = 2, - BPF_CSUM_LEVEL_RESET = 3, -}; - -enum { - BPF_F_ADJ_ROOM_FIXED_GSO = 1, - BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = 2, - BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = 4, - BPF_F_ADJ_ROOM_ENCAP_L4_GRE = 8, - BPF_F_ADJ_ROOM_ENCAP_L4_UDP = 16, - BPF_F_ADJ_ROOM_NO_CSUM_RESET = 32, - BPF_F_ADJ_ROOM_ENCAP_L2_ETH = 64, -}; - -enum { - BPF_ADJ_ROOM_ENCAP_L2_MASK = 255, - BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 56, -}; - -enum { - BPF_SK_LOOKUP_F_REPLACE = 1, - BPF_SK_LOOKUP_F_NO_REUSEPORT = 2, -}; - -enum bpf_adj_room_mode { - BPF_ADJ_ROOM_NET = 0, - BPF_ADJ_ROOM_MAC = 1, -}; - -enum bpf_hdr_start_off { - BPF_HDR_START_MAC = 0, - BPF_HDR_START_NET = 1, -}; - -enum bpf_lwt_encap_mode { - BPF_LWT_ENCAP_SEG6 = 0, - BPF_LWT_ENCAP_SEG6_INLINE = 1, - BPF_LWT_ENCAP_IP = 2, -}; - -struct bpf_tunnel_key { - __u32 tunnel_id; - union { - __u32 remote_ipv4; - __u32 remote_ipv6[4]; - }; - __u8 tunnel_tos; - __u8 tunnel_ttl; - __u16 tunnel_ext; - __u32 tunnel_label; -}; - -struct bpf_xfrm_state { - __u32 reqid; - __u32 spi; - __u16 family; - __u16 ext; - union { - __u32 remote_ipv4; - __u32 remote_ipv6[4]; - }; -}; - -struct bpf_tcp_sock { - __u32 snd_cwnd; - __u32 srtt_us; - __u32 rtt_min; - __u32 snd_ssthresh; - __u32 rcv_nxt; - __u32 snd_nxt; - __u32 snd_una; - __u32 mss_cache; - __u32 ecn_flags; - __u32 rate_delivered; - __u32 rate_interval_us; - __u32 packets_out; - __u32 retrans_out; - __u32 total_retrans; - __u32 segs_in; - __u32 data_segs_in; - __u32 segs_out; - __u32 data_segs_out; - __u32 lost_out; - __u32 sacked_out; - __u64 bytes_received; - __u64 bytes_acked; - __u32 dsack_dups; - __u32 delivered; - __u32 delivered_ce; - __u32 icsk_retransmits; -}; - -struct bpf_sock_tuple { - union { - struct { - __be32 saddr; - __be32 daddr; - __be16 sport; - __be16 dport; - } ipv4; - struct { - __be32 saddr[4]; - __be32 daddr[4]; - __be16 sport; - __be16 dport; - } ipv6; - }; -}; - -struct bpf_xdp_sock { - __u32 queue_id; -}; - -enum { - BPF_SOCK_OPS_RTO_CB_FLAG = 1, - BPF_SOCK_OPS_RETRANS_CB_FLAG = 2, - BPF_SOCK_OPS_STATE_CB_FLAG = 4, - BPF_SOCK_OPS_RTT_CB_FLAG = 8, - BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = 16, - BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = 32, - BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = 64, - BPF_SOCK_OPS_ALL_CB_FLAGS = 127, -}; - -enum { - BPF_SOCK_OPS_VOID = 0, - BPF_SOCK_OPS_TIMEOUT_INIT = 1, - BPF_SOCK_OPS_RWND_INIT = 2, - BPF_SOCK_OPS_TCP_CONNECT_CB = 3, - BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB = 4, - BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB = 5, - BPF_SOCK_OPS_NEEDS_ECN = 6, - BPF_SOCK_OPS_BASE_RTT = 7, - BPF_SOCK_OPS_RTO_CB = 8, - BPF_SOCK_OPS_RETRANS_CB = 9, - BPF_SOCK_OPS_STATE_CB = 10, - BPF_SOCK_OPS_TCP_LISTEN_CB = 11, - BPF_SOCK_OPS_RTT_CB = 12, - BPF_SOCK_OPS_PARSE_HDR_OPT_CB = 13, - BPF_SOCK_OPS_HDR_OPT_LEN_CB = 14, - BPF_SOCK_OPS_WRITE_HDR_OPT_CB = 15, -}; - -enum { - TCP_BPF_IW = 1001, - TCP_BPF_SNDCWND_CLAMP = 1002, - TCP_BPF_DELACK_MAX = 1003, - TCP_BPF_RTO_MIN = 1004, - TCP_BPF_SYN = 1005, - TCP_BPF_SYN_IP = 1006, - TCP_BPF_SYN_MAC = 1007, -}; - -enum { - BPF_LOAD_HDR_OPT_TCP_SYN = 1, -}; - -enum { - BPF_FIB_LOOKUP_DIRECT = 1, - BPF_FIB_LOOKUP_OUTPUT = 2, -}; - -enum { - BPF_FIB_LKUP_RET_SUCCESS = 0, - BPF_FIB_LKUP_RET_BLACKHOLE = 1, - BPF_FIB_LKUP_RET_UNREACHABLE = 2, - BPF_FIB_LKUP_RET_PROHIBIT = 3, - BPF_FIB_LKUP_RET_NOT_FWDED = 4, - BPF_FIB_LKUP_RET_FWD_DISABLED = 5, - BPF_FIB_LKUP_RET_UNSUPP_LWT = 6, - BPF_FIB_LKUP_RET_NO_NEIGH = 7, - BPF_FIB_LKUP_RET_FRAG_NEEDED = 8, -}; - -struct bpf_fib_lookup { - __u8 family; - __u8 l4_protocol; - __be16 sport; - __be16 dport; - union { - __u16 tot_len; - __u16 mtu_result; - }; - __u32 ifindex; - union { - __u8 tos; - __be32 flowinfo; - __u32 rt_metric; - }; - union { - __be32 ipv4_src; - __u32 ipv6_src[4]; - }; - union { - __be32 ipv4_dst; - __u32 ipv6_dst[4]; - }; - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - __u8 smac[6]; - __u8 dmac[6]; -}; - -struct bpf_redir_neigh { - __u32 nh_family; - union { - __be32 ipv4_nh; - __u32 ipv6_nh[4]; - }; -}; - -enum bpf_check_mtu_flags { - BPF_MTU_CHK_SEGS = 1, -}; - -enum bpf_check_mtu_ret { - BPF_MTU_CHK_RET_SUCCESS = 0, - BPF_MTU_CHK_RET_FRAG_NEEDED = 1, - BPF_MTU_CHK_RET_SEGS_TOOBIG = 2, -}; - -enum rt_scope_t { - RT_SCOPE_UNIVERSE = 0, - RT_SCOPE_SITE = 200, - RT_SCOPE_LINK = 253, - RT_SCOPE_HOST = 254, - RT_SCOPE_NOWHERE = 255, -}; - -enum rt_class_t { - RT_TABLE_UNSPEC = 0, - RT_TABLE_COMPAT = 252, - RT_TABLE_DEFAULT = 253, - RT_TABLE_MAIN = 254, - RT_TABLE_LOCAL = 255, - RT_TABLE_MAX = 4294967295, -}; - -struct nl_info { - struct nlmsghdr *nlh; - struct net *nl_net; - u32 portid; - u8 skip_notify: 1; - u8 skip_notify_kernel: 1; -}; - -struct inet_timewait_sock { - struct sock_common __tw_common; - __u32 tw_mark; - volatile unsigned char tw_substate; - unsigned char tw_rcv_wscale; - __be16 tw_sport; - unsigned int tw_kill: 1; - unsigned int tw_transparent: 1; - unsigned int tw_flowlabel: 20; - unsigned int tw_pad: 2; - unsigned int tw_tos: 8; - u32 tw_txhash; - u32 tw_priority; - struct timer_list tw_timer; - struct inet_bind_bucket *tw_tb; -}; - -struct tcp_timewait_sock { - struct inet_timewait_sock tw_sk; - u32 tw_rcv_wnd; - u32 tw_ts_offset; - u32 tw_ts_recent; - u32 tw_last_oow_ack_time; - int tw_ts_recent_stamp; - u32 tw_tx_delay; - struct tcp_md5sig_key *tw_md5_key; -}; - -struct udp_sock { - struct inet_sock inet; - int pending; - unsigned int corkflag; - __u8 encap_type; - unsigned char no_check6_tx: 1; - unsigned char no_check6_rx: 1; - unsigned char encap_enabled: 1; - unsigned char gro_enabled: 1; - unsigned char accept_udp_l4: 1; - unsigned char accept_udp_fraglist: 1; - __u16 len; - __u16 gso_size; - __u16 pcslen; - __u16 pcrlen; - __u8 pcflag; - __u8 unused[3]; - int (*encap_rcv)(struct sock *, struct sk_buff *); - int (*encap_err_lookup)(struct sock *, struct sk_buff *); - void (*encap_destroy)(struct sock *); - struct sk_buff * (*gro_receive)(struct sock *, struct list_head *, struct sk_buff *); - int (*gro_complete)(struct sock *, struct sk_buff *, int); - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - struct sk_buff_head reader_queue; - int forward_deficit; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct udp6_sock { - struct udp_sock udp; - struct ipv6_pinfo inet6; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct tcp6_sock { - struct tcp_sock tcp; - struct ipv6_pinfo inet6; -}; - -struct fib6_result; - -struct fib6_config; - -struct ipv6_stub { - int (*ipv6_sock_mc_join)(struct sock *, int, const struct in6_addr *); - int (*ipv6_sock_mc_drop)(struct sock *, int, const struct in6_addr *); - struct dst_entry * (*ipv6_dst_lookup_flow)(struct net *, const struct sock *, struct flowi6 *, const struct in6_addr *); - int (*ipv6_route_input)(struct sk_buff *); - struct fib6_table * (*fib6_get_table)(struct net *, u32); - int (*fib6_lookup)(struct net *, int, struct flowi6 *, struct fib6_result *, int); - int (*fib6_table_lookup)(struct net *, struct fib6_table *, int, struct flowi6 *, struct fib6_result *, int); - void (*fib6_select_path)(const struct net *, struct fib6_result *, struct flowi6 *, int, bool, const struct sk_buff *, int); - u32 (*ip6_mtu_from_fib6)(const struct fib6_result *, const struct in6_addr *, const struct in6_addr *); - int (*fib6_nh_init)(struct net *, struct fib6_nh *, struct fib6_config *, gfp_t, struct netlink_ext_ack *); - void (*fib6_nh_release)(struct fib6_nh *); - void (*fib6_update_sernum)(struct net *, struct fib6_info *); - int (*ip6_del_rt)(struct net *, struct fib6_info *, bool); - void (*fib6_rt_update)(struct net *, struct fib6_info *, struct nl_info *); - void (*udpv6_encap_enable)(); - void (*ndisc_send_na)(struct net_device *, const struct in6_addr *, const struct in6_addr *, bool, bool, bool, bool); - void (*xfrm6_local_rxpmtu)(struct sk_buff *, u32); - int (*xfrm6_udp_encap_rcv)(struct sock *, struct sk_buff *); - int (*xfrm6_rcv_encap)(struct sk_buff *, int, __be32, int); - struct neigh_table *nd_tbl; - int (*ipv6_fragment)(struct net *, struct sock *, struct sk_buff *, int (*)(struct net *, struct sock *, struct sk_buff *)); - struct net_device * (*ipv6_dev_find)(struct net *, const struct in6_addr *, struct net_device *); -}; - -struct fib6_result { - struct fib6_nh *nh; - struct fib6_info *f6i; - u32 fib6_flags; - u8 fib6_type; - struct rt6_info *rt6; -}; - -struct fib6_config { - u32 fc_table; - u32 fc_metric; - int fc_dst_len; - int fc_src_len; - int fc_ifindex; - u32 fc_flags; - u32 fc_protocol; - u16 fc_type; - u16 fc_delete_all_nh: 1; - u16 fc_ignore_dev_down: 1; - u16 __unused: 14; - u32 fc_nh_id; - struct in6_addr fc_dst; - struct in6_addr fc_src; - struct in6_addr fc_prefsrc; - struct in6_addr fc_gateway; - long unsigned int fc_expires; - struct nlattr *fc_mx; - int fc_mx_len; - int fc_mp_len; - struct nlattr *fc_mp; - struct nl_info fc_nlinfo; - struct nlattr *fc_encap; - u16 fc_encap_type; - bool fc_is_fdb; -}; - -struct ipv6_bpf_stub { - int (*inet6_bind)(struct sock *, struct sockaddr *, int, u32); - struct sock * (*udp6_lib_lookup)(struct net *, const struct in6_addr *, __be16, const struct in6_addr *, __be16, int, int, struct udp_table *, struct sk_buff *); -}; - -struct fib_result { - __be32 prefix; - unsigned char prefixlen; - unsigned char nh_sel; - unsigned char type; - unsigned char scope; - u32 tclassid; - struct fib_nh_common *nhc; - struct fib_info *fi; - struct fib_table *table; - struct hlist_head *fa_head; -}; - -enum { - INET_ECN_NOT_ECT = 0, - INET_ECN_ECT_1 = 1, - INET_ECN_ECT_0 = 2, - INET_ECN_CE = 3, - INET_ECN_MASK = 3, -}; - -struct tcp_skb_cb { - __u32 seq; - __u32 end_seq; - union { - __u32 tcp_tw_isn; - struct { - u16 tcp_gso_segs; - u16 tcp_gso_size; - }; - }; - __u8 tcp_flags; - __u8 sacked; - __u8 ip_dsfield; - __u8 txstamp_ack: 1; - __u8 eor: 1; - __u8 has_rxtstamp: 1; - __u8 unused: 5; - __u32 ack_seq; - union { - struct { - __u32 in_flight: 30; - __u32 is_app_limited: 1; - __u32 unused: 1; - __u32 delivered; - u64 first_tx_mstamp; - u64 delivered_mstamp; - } tx; - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - }; -}; - -struct strp_msg { - int full_len; - int offset; -}; - -struct xdp_umem { - void *addrs; - u64 size; - u32 headroom; - u32 chunk_size; - u32 chunks; - u32 npgs; - struct user_struct *user; - refcount_t users; - u8 flags; - bool zc; - struct page **pgs; - int id; - struct list_head xsk_dma_list; - struct work_struct work; -}; - -struct xsk_queue; - -struct xdp_sock { - struct sock sk; - struct xsk_queue *rx; - struct net_device *dev; - struct xdp_umem *umem; - struct list_head flush_node; - struct xsk_buff_pool *pool; - u16 queue_id; - bool zc; - enum { - XSK_READY = 0, - XSK_BOUND = 1, - XSK_UNBOUND = 2, - } state; - long: 64; - struct xsk_queue *tx; - struct list_head tx_list; - spinlock_t rx_lock; - u64 rx_dropped; - u64 rx_queue_full; - struct list_head map_list; - spinlock_t map_list_lock; - struct mutex mutex; - struct xsk_queue *fq_tmp; - struct xsk_queue *cq_tmp; - long: 64; -}; - -struct ipv6_sr_hdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 type; - __u8 segments_left; - __u8 first_segment; - __u8 flags; - __u16 tag; - struct in6_addr segments[0]; -}; - -enum { - SEG6_LOCAL_ACTION_UNSPEC = 0, - SEG6_LOCAL_ACTION_END = 1, - SEG6_LOCAL_ACTION_END_X = 2, - SEG6_LOCAL_ACTION_END_T = 3, - SEG6_LOCAL_ACTION_END_DX2 = 4, - SEG6_LOCAL_ACTION_END_DX6 = 5, - SEG6_LOCAL_ACTION_END_DX4 = 6, - SEG6_LOCAL_ACTION_END_DT6 = 7, - SEG6_LOCAL_ACTION_END_DT4 = 8, - SEG6_LOCAL_ACTION_END_B6 = 9, - SEG6_LOCAL_ACTION_END_B6_ENCAP = 10, - SEG6_LOCAL_ACTION_END_BM = 11, - SEG6_LOCAL_ACTION_END_S = 12, - SEG6_LOCAL_ACTION_END_AS = 13, - SEG6_LOCAL_ACTION_END_AM = 14, - SEG6_LOCAL_ACTION_END_BPF = 15, - SEG6_LOCAL_ACTION_END_DT46 = 16, - __SEG6_LOCAL_ACTION_MAX = 17, -}; - -struct seg6_bpf_srh_state { - struct ipv6_sr_hdr *srh; - u16 hdrlen; - bool valid; -}; - -struct tls_crypto_info { - __u16 version; - __u16 cipher_type; -}; - -struct tls12_crypto_info_aes_gcm_128 { - struct tls_crypto_info info; - unsigned char iv[8]; - unsigned char key[16]; - unsigned char salt[4]; - unsigned char rec_seq[8]; -}; - -struct tls12_crypto_info_aes_gcm_256 { - struct tls_crypto_info info; - unsigned char iv[8]; - unsigned char key[32]; - unsigned char salt[4]; - unsigned char rec_seq[8]; -}; - -struct tls12_crypto_info_chacha20_poly1305 { - struct tls_crypto_info info; - unsigned char iv[12]; - unsigned char key[32]; - unsigned char salt[0]; - unsigned char rec_seq[8]; -}; - -struct tls_sw_context_rx { - struct crypto_aead *aead_recv; - struct crypto_wait async_wait; - struct strparser strp; - struct sk_buff_head rx_list; - void (*saved_data_ready)(struct sock *); - struct sk_buff *recv_pkt; - u8 control; - u8 async_capable: 1; - u8 decrypted: 1; - atomic_t decrypt_pending; - spinlock_t decrypt_compl_lock; - bool async_notify; -}; - -struct cipher_context { - char *iv; - char *rec_seq; -}; - -union tls_crypto_context { - struct tls_crypto_info info; - union { - struct tls12_crypto_info_aes_gcm_128 aes_gcm_128; - struct tls12_crypto_info_aes_gcm_256 aes_gcm_256; - struct tls12_crypto_info_chacha20_poly1305 chacha20_poly1305; - }; -}; - -struct tls_prot_info { - u16 version; - u16 cipher_type; - u16 prepend_size; - u16 tag_size; - u16 overhead_size; - u16 iv_size; - u16 salt_size; - u16 rec_seq_size; - u16 aad_size; - u16 tail_size; -}; - -struct tls_context { - struct tls_prot_info prot_info; - u8 tx_conf: 3; - u8 rx_conf: 3; - int (*push_pending_record)(struct sock *, int); - void (*sk_write_space)(struct sock *); - void *priv_ctx_tx; - void *priv_ctx_rx; - struct net_device *netdev; - struct cipher_context tx; - struct cipher_context rx; - struct scatterlist *partially_sent_record; - u16 partially_sent_offset; - bool in_tcp_sendpages; - bool pending_open_record_frags; - struct mutex tx_lock; - long unsigned int flags; - struct proto *sk_proto; - struct sock *sk; - void (*sk_destruct)(struct sock *); - union tls_crypto_context crypto_send; - union tls_crypto_context crypto_recv; - struct list_head list; - refcount_t refcount; - struct callback_head rcu; -}; - -typedef u64 (*btf_bpf_skb_get_pay_offset)(struct sk_buff *); - -typedef u64 (*btf_bpf_skb_get_nlattr)(struct sk_buff *, u32, u32); - -typedef u64 (*btf_bpf_skb_get_nlattr_nest)(struct sk_buff *, u32, u32); - -typedef u64 (*btf_bpf_skb_load_helper_8)(const struct sk_buff *, const void *, int, int); - -typedef u64 (*btf_bpf_skb_load_helper_8_no_cache)(const struct sk_buff *, int); - -typedef u64 (*btf_bpf_skb_load_helper_16)(const struct sk_buff *, const void *, int, int); - -typedef u64 (*btf_bpf_skb_load_helper_16_no_cache)(const struct sk_buff *, int); - -typedef u64 (*btf_bpf_skb_load_helper_32)(const struct sk_buff *, const void *, int, int); - -typedef u64 (*btf_bpf_skb_load_helper_32_no_cache)(const struct sk_buff *, int); - -struct bpf_scratchpad { - union { - __be32 diff[128]; - u8 buff[512]; - }; -}; - -typedef u64 (*btf_bpf_skb_store_bytes)(struct sk_buff *, u32, const void *, u32, u64); - -typedef u64 (*btf_bpf_skb_load_bytes)(const struct sk_buff *, u32, void *, u32); - -typedef u64 (*btf_bpf_flow_dissector_load_bytes)(const struct bpf_flow_dissector *, u32, void *, u32); - -typedef u64 (*btf_bpf_skb_load_bytes_relative)(const struct sk_buff *, u32, void *, u32, u32); - -typedef u64 (*btf_bpf_skb_pull_data)(struct sk_buff *, u32); - -typedef u64 (*btf_bpf_sk_fullsock)(struct sock *); - -typedef u64 (*btf_sk_skb_pull_data)(struct sk_buff *, u32); - -typedef u64 (*btf_bpf_l3_csum_replace)(struct sk_buff *, u32, u64, u64, u64); - -typedef u64 (*btf_bpf_l4_csum_replace)(struct sk_buff *, u32, u64, u64, u64); - -typedef u64 (*btf_bpf_csum_diff)(__be32 *, u32, __be32 *, u32, __wsum); - -typedef u64 (*btf_bpf_csum_update)(struct sk_buff *, __wsum); - -typedef u64 (*btf_bpf_csum_level)(struct sk_buff *, u64); - -enum { - BPF_F_NEIGH = 2, - BPF_F_PEER = 4, - BPF_F_NEXTHOP = 8, -}; - -typedef u64 (*btf_bpf_clone_redirect)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_bpf_redirect)(u32, u64); - -typedef u64 (*btf_bpf_redirect_peer)(u32, u64); - -typedef u64 (*btf_bpf_redirect_neigh)(u32, struct bpf_redir_neigh *, int, u64); - -typedef u64 (*btf_bpf_msg_apply_bytes)(struct sk_msg *, u32); - -typedef u64 (*btf_bpf_msg_cork_bytes)(struct sk_msg *, u32); - -typedef u64 (*btf_bpf_msg_pull_data)(struct sk_msg *, u32, u32, u64); - -typedef u64 (*btf_bpf_msg_push_data)(struct sk_msg *, u32, u32, u64); - -typedef u64 (*btf_bpf_msg_pop_data)(struct sk_msg *, u32, u32, u64); - -typedef u64 (*btf_bpf_get_cgroup_classid_curr)(); - -typedef u64 (*btf_bpf_skb_cgroup_classid)(const struct sk_buff *); - -typedef u64 (*btf_bpf_get_cgroup_classid)(const struct sk_buff *); - -typedef u64 (*btf_bpf_get_route_realm)(const struct sk_buff *); - -typedef u64 (*btf_bpf_get_hash_recalc)(struct sk_buff *); - -typedef u64 (*btf_bpf_set_hash_invalid)(struct sk_buff *); - -typedef u64 (*btf_bpf_set_hash)(struct sk_buff *, u32); - -typedef u64 (*btf_bpf_skb_vlan_push)(struct sk_buff *, __be16, u16); - -typedef u64 (*btf_bpf_skb_vlan_pop)(struct sk_buff *); - -typedef u64 (*btf_bpf_skb_change_proto)(struct sk_buff *, __be16, u64); - -typedef u64 (*btf_bpf_skb_change_type)(struct sk_buff *, u32); - -typedef u64 (*btf_sk_skb_adjust_room)(struct sk_buff *, s32, u32, u64); - -typedef u64 (*btf_bpf_skb_adjust_room)(struct sk_buff *, s32, u32, u64); - -typedef u64 (*btf_bpf_skb_change_tail)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_sk_skb_change_tail)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_bpf_skb_change_head)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_sk_skb_change_head)(struct sk_buff *, u32, u64); - -typedef u64 (*btf_bpf_xdp_adjust_head)(struct xdp_buff *, int); - -typedef u64 (*btf_bpf_xdp_adjust_tail)(struct xdp_buff *, int); - -typedef u64 (*btf_bpf_xdp_adjust_meta)(struct xdp_buff *, int); - -typedef u64 (*btf_bpf_xdp_redirect)(u32, u64); - -typedef u64 (*btf_bpf_xdp_redirect_map)(struct bpf_map *, u32, u64); - -typedef u64 (*btf_bpf_skb_event_output)(struct sk_buff *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_skb_get_tunnel_key)(struct sk_buff *, struct bpf_tunnel_key *, u32, u64); - -typedef u64 (*btf_bpf_skb_get_tunnel_opt)(struct sk_buff *, u8 *, u32); - -typedef u64 (*btf_bpf_skb_set_tunnel_key)(struct sk_buff *, const struct bpf_tunnel_key *, u32, u64); - -typedef u64 (*btf_bpf_skb_set_tunnel_opt)(struct sk_buff *, const u8 *, u32); - -typedef u64 (*btf_bpf_skb_under_cgroup)(struct sk_buff *, struct bpf_map *, u32); - -typedef u64 (*btf_bpf_skb_cgroup_id)(const struct sk_buff *); - -typedef u64 (*btf_bpf_skb_ancestor_cgroup_id)(const struct sk_buff *, int); - -typedef u64 (*btf_bpf_sk_cgroup_id)(struct sock *); - -typedef u64 (*btf_bpf_sk_ancestor_cgroup_id)(struct sock *, int); - -typedef u64 (*btf_bpf_xdp_event_output)(struct xdp_buff *, struct bpf_map *, u64, void *, u64); - -typedef u64 (*btf_bpf_get_socket_cookie)(struct sk_buff *); - -typedef u64 (*btf_bpf_get_socket_cookie_sock_addr)(struct bpf_sock_addr_kern *); - -typedef u64 (*btf_bpf_get_socket_cookie_sock)(struct sock *); - -typedef u64 (*btf_bpf_get_socket_ptr_cookie)(struct sock *); - -typedef u64 (*btf_bpf_get_socket_cookie_sock_ops)(struct bpf_sock_ops_kern *); - -typedef u64 (*btf_bpf_get_netns_cookie_sock)(struct sock *); - -typedef u64 (*btf_bpf_get_netns_cookie_sock_addr)(struct bpf_sock_addr_kern *); - -typedef u64 (*btf_bpf_get_socket_uid)(struct sk_buff *); - -typedef u64 (*btf_bpf_sock_addr_setsockopt)(struct bpf_sock_addr_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_addr_getsockopt)(struct bpf_sock_addr_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_ops_setsockopt)(struct bpf_sock_ops_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_ops_getsockopt)(struct bpf_sock_ops_kern *, int, int, char *, int); - -typedef u64 (*btf_bpf_sock_ops_cb_flags_set)(struct bpf_sock_ops_kern *, int); - -typedef u64 (*btf_bpf_bind)(struct bpf_sock_addr_kern *, struct sockaddr *, int); - -typedef u64 (*btf_bpf_skb_get_xfrm_state)(struct sk_buff *, u32, struct bpf_xfrm_state *, u32, u64); - -typedef u64 (*btf_bpf_xdp_fib_lookup)(struct xdp_buff *, struct bpf_fib_lookup *, int, u32); - -typedef u64 (*btf_bpf_skb_fib_lookup)(struct sk_buff *, struct bpf_fib_lookup *, int, u32); - -typedef u64 (*btf_bpf_skb_check_mtu)(struct sk_buff *, u32, u32 *, s32, u64); - -typedef u64 (*btf_bpf_xdp_check_mtu)(struct xdp_buff *, u32, u32 *, s32, u64); - -typedef u64 (*btf_bpf_lwt_in_push_encap)(struct sk_buff *, u32, void *, u32); - -typedef u64 (*btf_bpf_lwt_xmit_push_encap)(struct sk_buff *, u32, void *, u32); - -typedef u64 (*btf_bpf_lwt_seg6_store_bytes)(struct sk_buff *, u32, const void *, u32); - -typedef u64 (*btf_bpf_lwt_seg6_action)(struct sk_buff *, u32, void *, u32); - -typedef u64 (*btf_bpf_lwt_seg6_adjust_srh)(struct sk_buff *, u32, s32); - -typedef u64 (*btf_bpf_skc_lookup_tcp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sk_lookup_tcp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sk_lookup_udp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sk_release)(struct sock *); - -typedef u64 (*btf_bpf_xdp_sk_lookup_udp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64); - -typedef u64 (*btf_bpf_xdp_skc_lookup_tcp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64); - -typedef u64 (*btf_bpf_xdp_sk_lookup_tcp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64); - -typedef u64 (*btf_bpf_sock_addr_skc_lookup_tcp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sock_addr_sk_lookup_tcp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_sock_addr_sk_lookup_udp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64); - -typedef u64 (*btf_bpf_tcp_sock)(struct sock *); - -typedef u64 (*btf_bpf_get_listener_sock)(struct sock *); - -typedef u64 (*btf_bpf_skb_ecn_set_ce)(struct sk_buff *); - -typedef u64 (*btf_bpf_tcp_check_syncookie)(struct sock *, void *, u32, struct tcphdr *, u32); - -typedef u64 (*btf_bpf_tcp_gen_syncookie)(struct sock *, void *, u32, struct tcphdr *, u32); - -typedef u64 (*btf_bpf_sk_assign)(struct sk_buff *, struct sock *, u64); - -typedef u64 (*btf_bpf_sock_ops_load_hdr_opt)(struct bpf_sock_ops_kern *, void *, u32, u64); - -typedef u64 (*btf_bpf_sock_ops_store_hdr_opt)(struct bpf_sock_ops_kern *, const void *, u32, u64); - -typedef u64 (*btf_bpf_sock_ops_reserve_hdr_opt)(struct bpf_sock_ops_kern *, u32, u64); - -typedef u64 (*btf_sk_select_reuseport)(struct sk_reuseport_kern *, struct bpf_map *, void *, u32); - -typedef u64 (*btf_sk_reuseport_load_bytes)(const struct sk_reuseport_kern *, u32, void *, u32); - -typedef u64 (*btf_sk_reuseport_load_bytes_relative)(const struct sk_reuseport_kern *, u32, void *, u32, u32); - -typedef u64 (*btf_bpf_sk_lookup_assign)(struct bpf_sk_lookup_kern *, struct sock *, u64); - -typedef u64 (*btf_bpf_skc_to_tcp6_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_tcp_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_tcp_timewait_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_tcp_request_sock)(struct sock *); - -typedef u64 (*btf_bpf_skc_to_udp6_sock)(struct sock *); - -typedef u64 (*btf_bpf_sock_from_file)(struct file *); - -struct bpf_dtab_netdev___2; - -struct bpf_cpu_map_entry___2; - -enum { - INET_DIAG_REQ_NONE = 0, - INET_DIAG_REQ_BYTECODE = 1, - INET_DIAG_REQ_SK_BPF_STORAGES = 2, - INET_DIAG_REQ_PROTOCOL = 3, - __INET_DIAG_REQ_MAX = 4, -}; - -struct sock_diag_req { - __u8 sdiag_family; - __u8 sdiag_protocol; -}; - -struct sock_diag_handler { - __u8 family; - int (*dump)(struct sk_buff *, struct nlmsghdr *); - int (*get_info)(struct sk_buff *, struct sock *); - int (*destroy)(struct sk_buff *, struct nlmsghdr *); -}; - -struct broadcast_sk { - struct sock *sk; - struct work_struct work; -}; - -typedef int gifconf_func_t(struct net_device *, char *, int, int); - -struct hwtstamp_config { - int flags; - int tx_type; - int rx_filter; -}; - -enum hwtstamp_tx_types { - HWTSTAMP_TX_OFF = 0, - HWTSTAMP_TX_ON = 1, - HWTSTAMP_TX_ONESTEP_SYNC = 2, - HWTSTAMP_TX_ONESTEP_P2P = 3, - __HWTSTAMP_TX_CNT = 4, -}; - -enum hwtstamp_rx_filters { - HWTSTAMP_FILTER_NONE = 0, - HWTSTAMP_FILTER_ALL = 1, - HWTSTAMP_FILTER_SOME = 2, - HWTSTAMP_FILTER_PTP_V1_L4_EVENT = 3, - HWTSTAMP_FILTER_PTP_V1_L4_SYNC = 4, - HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ = 5, - HWTSTAMP_FILTER_PTP_V2_L4_EVENT = 6, - HWTSTAMP_FILTER_PTP_V2_L4_SYNC = 7, - HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ = 8, - HWTSTAMP_FILTER_PTP_V2_L2_EVENT = 9, - HWTSTAMP_FILTER_PTP_V2_L2_SYNC = 10, - HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ = 11, - HWTSTAMP_FILTER_PTP_V2_EVENT = 12, - HWTSTAMP_FILTER_PTP_V2_SYNC = 13, - HWTSTAMP_FILTER_PTP_V2_DELAY_REQ = 14, - HWTSTAMP_FILTER_NTP_ALL = 15, - __HWTSTAMP_FILTER_CNT = 16, -}; - -struct tso_t { - int next_frag_idx; - int size; - void *data; - u16 ip_id; - u8 tlen; - bool ipv6; - u32 tcp_seq; -}; - -struct fib_notifier_info { - int family; - struct netlink_ext_ack *extack; -}; - -enum fib_event_type { - FIB_EVENT_ENTRY_REPLACE = 0, - FIB_EVENT_ENTRY_APPEND = 1, - FIB_EVENT_ENTRY_ADD = 2, - FIB_EVENT_ENTRY_DEL = 3, - FIB_EVENT_RULE_ADD = 4, - FIB_EVENT_RULE_DEL = 5, - FIB_EVENT_NH_ADD = 6, - FIB_EVENT_NH_DEL = 7, - FIB_EVENT_VIF_ADD = 8, - FIB_EVENT_VIF_DEL = 9, -}; - -struct fib_notifier_net { - struct list_head fib_notifier_ops; - struct atomic_notifier_head fib_chain; -}; - -struct xdp_frame_bulk { - int count; - void *xa; - void *q[16]; -}; - -struct xdp_attachment_info { - struct bpf_prog *prog; - u32 flags; -}; - -struct xdp_buff_xsk; - -struct xsk_buff_pool { - struct device *dev; - struct net_device *netdev; - struct list_head xsk_tx_list; - spinlock_t xsk_tx_list_lock; - refcount_t users; - struct xdp_umem *umem; - struct work_struct work; - struct list_head free_list; - u32 heads_cnt; - u16 queue_id; - long: 16; - long: 64; - long: 64; - long: 64; - struct xsk_queue *fq; - struct xsk_queue *cq; - dma_addr_t *dma_pages; - struct xdp_buff_xsk *heads; - u64 chunk_mask; - u64 addrs_cnt; - u32 free_list_cnt; - u32 dma_pages_cnt; - u32 free_heads_cnt; - u32 headroom; - u32 chunk_size; - u32 frame_len; - u8 cached_need_wakeup; - bool uses_need_wakeup; - bool dma_need_sync; - bool unaligned; - void *addrs; - spinlock_t cq_lock; - struct xdp_buff_xsk *free_heads[0]; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct xdp_buff_xsk { - struct xdp_buff xdp; - dma_addr_t dma; - dma_addr_t frame_dma; - struct xsk_buff_pool *pool; - bool unaligned; - u64 orig_addr; - struct list_head free_list_node; -}; - -struct flow_match_meta { - struct flow_dissector_key_meta *key; - struct flow_dissector_key_meta *mask; -}; - -struct flow_match_basic { - struct flow_dissector_key_basic *key; - struct flow_dissector_key_basic *mask; -}; - -struct flow_match_control { - struct flow_dissector_key_control *key; - struct flow_dissector_key_control *mask; -}; - -struct flow_match_eth_addrs { - struct flow_dissector_key_eth_addrs *key; - struct flow_dissector_key_eth_addrs *mask; -}; - -struct flow_match_vlan { - struct flow_dissector_key_vlan *key; - struct flow_dissector_key_vlan *mask; -}; - -struct flow_match_ipv4_addrs { - struct flow_dissector_key_ipv4_addrs *key; - struct flow_dissector_key_ipv4_addrs *mask; -}; - -struct flow_match_ipv6_addrs { - struct flow_dissector_key_ipv6_addrs *key; - struct flow_dissector_key_ipv6_addrs *mask; -}; - -struct flow_match_ip { - struct flow_dissector_key_ip *key; - struct flow_dissector_key_ip *mask; -}; - -struct flow_match_ports { - struct flow_dissector_key_ports *key; - struct flow_dissector_key_ports *mask; -}; - -struct flow_match_icmp { - struct flow_dissector_key_icmp *key; - struct flow_dissector_key_icmp *mask; -}; - -struct flow_match_tcp { - struct flow_dissector_key_tcp *key; - struct flow_dissector_key_tcp *mask; -}; - -struct flow_match_mpls { - struct flow_dissector_key_mpls *key; - struct flow_dissector_key_mpls *mask; -}; - -struct flow_match_enc_keyid { - struct flow_dissector_key_keyid *key; - struct flow_dissector_key_keyid *mask; -}; - -struct flow_match_enc_opts { - struct flow_dissector_key_enc_opts *key; - struct flow_dissector_key_enc_opts *mask; -}; - -struct flow_match_ct { - struct flow_dissector_key_ct *key; - struct flow_dissector_key_ct *mask; -}; - -enum flow_block_command { - FLOW_BLOCK_BIND = 0, - FLOW_BLOCK_UNBIND = 1, -}; - -enum flow_block_binder_type { - FLOW_BLOCK_BINDER_TYPE_UNSPEC = 0, - FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS = 1, - FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS = 2, - FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP = 3, - FLOW_BLOCK_BINDER_TYPE_RED_MARK = 4, -}; - -struct flow_block_offload { - enum flow_block_command command; - enum flow_block_binder_type binder_type; - bool block_shared; - bool unlocked_driver_cb; - struct net *net; - struct flow_block *block; - struct list_head cb_list; - struct list_head *driver_block_list; - struct netlink_ext_ack *extack; - struct Qdisc *sch; -}; - -struct flow_block_cb; - -struct flow_block_indr { - struct list_head list; - struct net_device *dev; - struct Qdisc *sch; - enum flow_block_binder_type binder_type; - void *data; - void *cb_priv; - void (*cleanup)(struct flow_block_cb *); -}; - -struct flow_block_cb { - struct list_head driver_list; - struct list_head list; - flow_setup_cb_t *cb; - void *cb_ident; - void *cb_priv; - void (*release)(void *); - struct flow_block_indr indr; - unsigned int refcnt; -}; - -typedef int flow_indr_block_bind_cb_t(struct net_device *, struct Qdisc *, void *, enum tc_setup_type, void *, void *, void (*)(struct flow_block_cb *)); - -struct flow_indr_dev { - struct list_head list; - flow_indr_block_bind_cb_t *cb; - void *cb_priv; - refcount_t refcnt; - struct callback_head rcu; -}; - -struct rx_queue_attribute { - struct attribute attr; - ssize_t (*show)(struct netdev_rx_queue *, char *); - ssize_t (*store)(struct netdev_rx_queue *, const char *, size_t); -}; - -struct netdev_queue_attribute { - struct attribute attr; - ssize_t (*show)(struct netdev_queue *, char *); - ssize_t (*store)(struct netdev_queue *, const char *, size_t); -}; - -struct inet6_ifaddr { - struct in6_addr addr; - __u32 prefix_len; - __u32 rt_priority; - __u32 valid_lft; - __u32 prefered_lft; - refcount_t refcnt; - spinlock_t lock; - int state; - __u32 flags; - __u8 dad_probes; - __u8 stable_privacy_retry; - __u16 scope; - __u64 dad_nonce; - long unsigned int cstamp; - long unsigned int tstamp; - struct delayed_work dad_work; - struct inet6_dev *idev; - struct fib6_info *rt; - struct hlist_node addr_lst; - struct list_head if_list; - struct list_head tmp_list; - struct inet6_ifaddr *ifpub; - int regen_count; - bool tokenized; - struct callback_head rcu; - struct in6_addr peer_addr; -}; - -struct fib_rule_uid_range { - __u32 start; - __u32 end; -}; - -enum { - FRA_UNSPEC = 0, - FRA_DST = 1, - FRA_SRC = 2, - FRA_IIFNAME = 3, - FRA_GOTO = 4, - FRA_UNUSED2 = 5, - FRA_PRIORITY = 6, - FRA_UNUSED3 = 7, - FRA_UNUSED4 = 8, - FRA_UNUSED5 = 9, - FRA_FWMARK = 10, - FRA_FLOW = 11, - FRA_TUN_ID = 12, - FRA_SUPPRESS_IFGROUP = 13, - FRA_SUPPRESS_PREFIXLEN = 14, - FRA_TABLE = 15, - FRA_FWMASK = 16, - FRA_OIFNAME = 17, - FRA_PAD = 18, - FRA_L3MDEV = 19, - FRA_UID_RANGE = 20, - FRA_PROTOCOL = 21, - FRA_IP_PROTO = 22, - FRA_SPORT_RANGE = 23, - FRA_DPORT_RANGE = 24, - __FRA_MAX = 25, -}; - -enum { - FR_ACT_UNSPEC = 0, - FR_ACT_TO_TBL = 1, - FR_ACT_GOTO = 2, - FR_ACT_NOP = 3, - FR_ACT_RES3 = 4, - FR_ACT_RES4 = 5, - FR_ACT_BLACKHOLE = 6, - FR_ACT_UNREACHABLE = 7, - FR_ACT_PROHIBIT = 8, - __FR_ACT_MAX = 9, -}; - -struct fib_rule_notifier_info { - struct fib_notifier_info info; - struct fib_rule *rule; -}; - -struct trace_event_raw_kfree_skb { - struct trace_entry ent; - void *skbaddr; - void *location; - short unsigned int protocol; - char __data[0]; -}; - -struct trace_event_raw_consume_skb { - struct trace_entry ent; - void *skbaddr; - char __data[0]; -}; - -struct trace_event_raw_skb_copy_datagram_iovec { - struct trace_entry ent; - const void *skbaddr; - int len; - char __data[0]; -}; - -struct trace_event_data_offsets_kfree_skb {}; - -struct trace_event_data_offsets_consume_skb {}; - -struct trace_event_data_offsets_skb_copy_datagram_iovec {}; - -typedef void (*btf_trace_kfree_skb)(void *, struct sk_buff *, void *); - -typedef void (*btf_trace_consume_skb)(void *, struct sk_buff *); - -typedef void (*btf_trace_skb_copy_datagram_iovec)(void *, const struct sk_buff *, int); - -struct trace_event_raw_net_dev_start_xmit { - struct trace_entry ent; - u32 __data_loc_name; - u16 queue_mapping; - const void *skbaddr; - bool vlan_tagged; - u16 vlan_proto; - u16 vlan_tci; - u16 protocol; - u8 ip_summed; - unsigned int len; - unsigned int data_len; - int network_offset; - bool transport_offset_valid; - int transport_offset; - u8 tx_flags; - u16 gso_size; - u16 gso_segs; - u16 gso_type; - char __data[0]; -}; - -struct trace_event_raw_net_dev_xmit { - struct trace_entry ent; - void *skbaddr; - unsigned int len; - int rc; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_net_dev_xmit_timeout { - struct trace_entry ent; - u32 __data_loc_name; - u32 __data_loc_driver; - int queue_index; - char __data[0]; -}; - -struct trace_event_raw_net_dev_template { - struct trace_entry ent; - void *skbaddr; - unsigned int len; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_raw_net_dev_rx_verbose_template { - struct trace_entry ent; - u32 __data_loc_name; - unsigned int napi_id; - u16 queue_mapping; - const void *skbaddr; - bool vlan_tagged; - u16 vlan_proto; - u16 vlan_tci; - u16 protocol; - u8 ip_summed; - u32 hash; - bool l4_hash; - unsigned int len; - unsigned int data_len; - unsigned int truesize; - bool mac_header_valid; - int mac_header; - unsigned char nr_frags; - u16 gso_size; - u16 gso_type; - char __data[0]; -}; - -struct trace_event_raw_net_dev_rx_exit_template { - struct trace_entry ent; - int ret; - char __data[0]; -}; - -struct trace_event_data_offsets_net_dev_start_xmit { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_xmit { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_xmit_timeout { - u32 name; - u32 driver; -}; - -struct trace_event_data_offsets_net_dev_template { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_rx_verbose_template { - u32 name; -}; - -struct trace_event_data_offsets_net_dev_rx_exit_template {}; - -typedef void (*btf_trace_net_dev_start_xmit)(void *, const struct sk_buff *, const struct net_device *); - -typedef void (*btf_trace_net_dev_xmit)(void *, struct sk_buff *, int, struct net_device *, unsigned int); - -typedef void (*btf_trace_net_dev_xmit_timeout)(void *, struct net_device *, int); - -typedef void (*btf_trace_net_dev_queue)(void *, struct sk_buff *); - -typedef void (*btf_trace_netif_receive_skb)(void *, struct sk_buff *); - -typedef void (*btf_trace_netif_rx)(void *, struct sk_buff *); - -typedef void (*btf_trace_napi_gro_frags_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_napi_gro_receive_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_receive_skb_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_receive_skb_list_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_rx_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_netif_rx_ni_entry)(void *, const struct sk_buff *); - -typedef void (*btf_trace_napi_gro_frags_exit)(void *, int); - -typedef void (*btf_trace_napi_gro_receive_exit)(void *, int); - -typedef void (*btf_trace_netif_receive_skb_exit)(void *, int); - -typedef void (*btf_trace_netif_rx_exit)(void *, int); - -typedef void (*btf_trace_netif_rx_ni_exit)(void *, int); - -typedef void (*btf_trace_netif_receive_skb_list_exit)(void *, int); - -struct trace_event_raw_napi_poll { - struct trace_entry ent; - struct napi_struct *napi; - u32 __data_loc_dev_name; - int work; - int budget; - char __data[0]; -}; - -struct trace_event_data_offsets_napi_poll { - u32 dev_name; -}; - -typedef void (*btf_trace_napi_poll)(void *, struct napi_struct *, int, int); - -enum tcp_ca_state { - TCP_CA_Open = 0, - TCP_CA_Disorder = 1, - TCP_CA_CWR = 2, - TCP_CA_Recovery = 3, - TCP_CA_Loss = 4, -}; - -struct trace_event_raw_sock_rcvqueue_full { - struct trace_entry ent; - int rmem_alloc; - unsigned int truesize; - int sk_rcvbuf; - char __data[0]; -}; - -struct trace_event_raw_sock_exceed_buf_limit { - struct trace_entry ent; - char name[32]; - long int *sysctl_mem; - long int allocated; - int sysctl_rmem; - int rmem_alloc; - int sysctl_wmem; - int wmem_alloc; - int wmem_queued; - int kind; - char __data[0]; -}; - -struct trace_event_raw_inet_sock_set_state { - struct trace_entry ent; - const void *skaddr; - int oldstate; - int newstate; - __u16 sport; - __u16 dport; - __u16 family; - __u16 protocol; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - char __data[0]; -}; - -struct trace_event_raw_inet_sk_error_report { - struct trace_entry ent; - int error; - __u16 sport; - __u16 dport; - __u16 family; - __u16 protocol; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - char __data[0]; -}; - -struct trace_event_data_offsets_sock_rcvqueue_full {}; - -struct trace_event_data_offsets_sock_exceed_buf_limit {}; - -struct trace_event_data_offsets_inet_sock_set_state {}; - -struct trace_event_data_offsets_inet_sk_error_report {}; - -typedef void (*btf_trace_sock_rcvqueue_full)(void *, struct sock *, struct sk_buff *); - -typedef void (*btf_trace_sock_exceed_buf_limit)(void *, struct sock *, struct proto *, long int, int); - -typedef void (*btf_trace_inet_sock_set_state)(void *, const struct sock *, const int, const int); - -typedef void (*btf_trace_inet_sk_error_report)(void *, const struct sock *); - -struct trace_event_raw_udp_fail_queue_rcv_skb { - struct trace_entry ent; - int rc; - __u16 lport; - char __data[0]; -}; - -struct trace_event_data_offsets_udp_fail_queue_rcv_skb {}; - -typedef void (*btf_trace_udp_fail_queue_rcv_skb)(void *, int, struct sock *); - -struct trace_event_raw_tcp_event_sk_skb { - struct trace_entry ent; - const void *skbaddr; - const void *skaddr; - int state; - __u16 sport; - __u16 dport; - __u16 family; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - char __data[0]; -}; - -struct trace_event_raw_tcp_event_sk { - struct trace_entry ent; - const void *skaddr; - __u16 sport; - __u16 dport; - __u16 family; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - __u64 sock_cookie; - char __data[0]; -}; - -struct trace_event_raw_tcp_retransmit_synack { - struct trace_entry ent; - const void *skaddr; - const void *req; - __u16 sport; - __u16 dport; - __u16 family; - __u8 saddr[4]; - __u8 daddr[4]; - __u8 saddr_v6[16]; - __u8 daddr_v6[16]; - char __data[0]; -}; - -struct trace_event_raw_tcp_probe { - struct trace_entry ent; - __u8 saddr[28]; - __u8 daddr[28]; - __u16 sport; - __u16 dport; - __u16 family; - __u32 mark; - __u16 data_len; - __u32 snd_nxt; - __u32 snd_una; - __u32 snd_cwnd; - __u32 ssthresh; - __u32 snd_wnd; - __u32 srtt; - __u32 rcv_wnd; - __u64 sock_cookie; - char __data[0]; -}; - -struct trace_event_raw_tcp_event_skb { - struct trace_entry ent; - const void *skbaddr; - __u8 saddr[28]; - __u8 daddr[28]; - char __data[0]; -}; - -struct trace_event_data_offsets_tcp_event_sk_skb {}; - -struct trace_event_data_offsets_tcp_event_sk {}; - -struct trace_event_data_offsets_tcp_retransmit_synack {}; - -struct trace_event_data_offsets_tcp_probe {}; - -struct trace_event_data_offsets_tcp_event_skb {}; - -typedef void (*btf_trace_tcp_retransmit_skb)(void *, const struct sock *, const struct sk_buff *); - -typedef void (*btf_trace_tcp_send_reset)(void *, const struct sock *, const struct sk_buff *); - -typedef void (*btf_trace_tcp_receive_reset)(void *, struct sock *); - -typedef void (*btf_trace_tcp_destroy_sock)(void *, struct sock *); - -typedef void (*btf_trace_tcp_rcv_space_adjust)(void *, struct sock *); - -typedef void (*btf_trace_tcp_retransmit_synack)(void *, const struct sock *, const struct request_sock *); - -typedef void (*btf_trace_tcp_probe)(void *, struct sock *, struct sk_buff *); - -typedef void (*btf_trace_tcp_bad_csum)(void *, const struct sk_buff *); - -struct trace_event_raw_fib_table_lookup { - struct trace_entry ent; - u32 tb_id; - int err; - int oif; - int iif; - u8 proto; - __u8 tos; - __u8 scope; - __u8 flags; - __u8 src[4]; - __u8 dst[4]; - __u8 gw4[4]; - __u8 gw6[16]; - u16 sport; - u16 dport; - u32 __data_loc_name; - char __data[0]; -}; - -struct trace_event_data_offsets_fib_table_lookup { - u32 name; -}; - -typedef void (*btf_trace_fib_table_lookup)(void *, u32, const struct flowi4 *, const struct fib_nh_common *, int); - -struct trace_event_raw_qdisc_dequeue { - struct trace_entry ent; - struct Qdisc *qdisc; - const struct netdev_queue *txq; - int packets; - void *skbaddr; - int ifindex; - u32 handle; - u32 parent; - long unsigned int txq_state; - char __data[0]; -}; - -struct trace_event_raw_qdisc_enqueue { - struct trace_entry ent; - struct Qdisc *qdisc; - void *skbaddr; - int ifindex; - u32 handle; - u32 parent; - char __data[0]; -}; - -struct trace_event_raw_qdisc_reset { - struct trace_entry ent; - u32 __data_loc_dev; - u32 __data_loc_kind; - u32 parent; - u32 handle; - char __data[0]; -}; - -struct trace_event_raw_qdisc_destroy { - struct trace_entry ent; - u32 __data_loc_dev; - u32 __data_loc_kind; - u32 parent; - u32 handle; - char __data[0]; -}; - -struct trace_event_raw_qdisc_create { - struct trace_entry ent; - u32 __data_loc_dev; - u32 __data_loc_kind; - u32 parent; - char __data[0]; -}; - -struct trace_event_data_offsets_qdisc_dequeue {}; - -struct trace_event_data_offsets_qdisc_enqueue {}; - -struct trace_event_data_offsets_qdisc_reset { - u32 dev; - u32 kind; -}; - -struct trace_event_data_offsets_qdisc_destroy { - u32 dev; - u32 kind; -}; - -struct trace_event_data_offsets_qdisc_create { - u32 dev; - u32 kind; -}; - -typedef void (*btf_trace_qdisc_dequeue)(void *, struct Qdisc *, const struct netdev_queue *, int, struct sk_buff *); - -typedef void (*btf_trace_qdisc_enqueue)(void *, struct Qdisc *, const struct netdev_queue *, struct sk_buff *); - -typedef void (*btf_trace_qdisc_reset)(void *, struct Qdisc *); - -typedef void (*btf_trace_qdisc_destroy)(void *, struct Qdisc *); - -typedef void (*btf_trace_qdisc_create)(void *, const struct Qdisc_ops *, struct net_device *, u32); - -struct bridge_stp_xstats { - __u64 transition_blk; - __u64 transition_fwd; - __u64 rx_bpdu; - __u64 tx_bpdu; - __u64 rx_tcn; - __u64 tx_tcn; -}; - -struct br_mcast_stats { - __u64 igmp_v1queries[2]; - __u64 igmp_v2queries[2]; - __u64 igmp_v3queries[2]; - __u64 igmp_leaves[2]; - __u64 igmp_v1reports[2]; - __u64 igmp_v2reports[2]; - __u64 igmp_v3reports[2]; - __u64 igmp_parse_errors; - __u64 mld_v1queries[2]; - __u64 mld_v2queries[2]; - __u64 mld_leaves[2]; - __u64 mld_v1reports[2]; - __u64 mld_v2reports[2]; - __u64 mld_parse_errors; - __u64 mcast_bytes[2]; - __u64 mcast_packets[2]; -}; - -struct br_ip { - union { - __be32 ip4; - struct in6_addr ip6; - } src; - union { - __be32 ip4; - struct in6_addr ip6; - unsigned char mac_addr[6]; - } dst; - __be16 proto; - __u16 vid; -}; - -struct bridge_id { - unsigned char prio[2]; - unsigned char addr[6]; -}; - -typedef struct bridge_id bridge_id; - -struct mac_addr { - unsigned char addr[6]; -}; - -typedef struct mac_addr mac_addr; - -typedef __u16 port_id; - -struct bridge_mcast_own_query { - struct timer_list timer; - u32 startup_sent; -}; - -struct bridge_mcast_other_query { - struct timer_list timer; - long unsigned int delay_time; -}; - -struct net_bridge_port; - -struct bridge_mcast_querier { - struct br_ip addr; - struct net_bridge_port *port; -}; - -struct net_bridge; - -struct net_bridge_vlan_group; - -struct bridge_mcast_stats; - -struct net_bridge_port { - struct net_bridge *br; - struct net_device *dev; - struct list_head list; - long unsigned int flags; - struct net_bridge_vlan_group *vlgrp; - struct net_bridge_port *backup_port; - u8 priority; - u8 state; - u16 port_no; - unsigned char topology_change_ack; - unsigned char config_pending; - port_id port_id; - port_id designated_port; - bridge_id designated_root; - bridge_id designated_bridge; - u32 path_cost; - u32 designated_cost; - long unsigned int designated_age; - struct timer_list forward_delay_timer; - struct timer_list hold_timer; - struct timer_list message_age_timer; - struct kobject kobj; - struct callback_head rcu; - struct bridge_mcast_own_query ip4_own_query; - struct timer_list ip4_mc_router_timer; - struct hlist_node ip4_rlist; - struct bridge_mcast_own_query ip6_own_query; - struct timer_list ip6_mc_router_timer; - struct hlist_node ip6_rlist; - u32 multicast_eht_hosts_limit; - u32 multicast_eht_hosts_cnt; - unsigned char multicast_router; - struct bridge_mcast_stats *mcast_stats; - struct hlist_head mglist; - char sysfs_name[16]; - struct netpoll *np; - int offload_fwd_mark; - u16 group_fwd_mask; - u16 backup_redirected_cnt; - struct bridge_stp_xstats stp_xstats; -}; - -struct bridge_mcast_stats { - struct br_mcast_stats mstats; - struct u64_stats_sync syncp; -}; - -struct net_bridge { - spinlock_t lock; - spinlock_t hash_lock; - struct hlist_head frame_type_list; - struct net_device *dev; - long unsigned int options; - __be16 vlan_proto; - u16 default_pvid; - struct net_bridge_vlan_group *vlgrp; - struct rhashtable fdb_hash_tbl; - struct list_head port_list; - union { - struct rtable fake_rtable; - struct rt6_info fake_rt6_info; - }; - u16 group_fwd_mask; - u16 group_fwd_mask_required; - bridge_id designated_root; - bridge_id bridge_id; - unsigned char topology_change; - unsigned char topology_change_detected; - u16 root_port; - long unsigned int max_age; - long unsigned int hello_time; - long unsigned int forward_delay; - long unsigned int ageing_time; - long unsigned int bridge_max_age; - long unsigned int bridge_hello_time; - long unsigned int bridge_forward_delay; - long unsigned int bridge_ageing_time; - u32 root_path_cost; - u8 group_addr[6]; - enum { - BR_NO_STP = 0, - BR_KERNEL_STP = 1, - BR_USER_STP = 2, - } stp_enabled; - u32 hash_max; - u32 multicast_last_member_count; - u32 multicast_startup_query_count; - u8 multicast_igmp_version; - u8 multicast_router; - u8 multicast_mld_version; - spinlock_t multicast_lock; - long unsigned int multicast_last_member_interval; - long unsigned int multicast_membership_interval; - long unsigned int multicast_querier_interval; - long unsigned int multicast_query_interval; - long unsigned int multicast_query_response_interval; - long unsigned int multicast_startup_query_interval; - struct rhashtable mdb_hash_tbl; - struct rhashtable sg_port_tbl; - struct hlist_head mcast_gc_list; - struct hlist_head mdb_list; - struct hlist_head ip4_mc_router_list; - struct timer_list ip4_mc_router_timer; - struct bridge_mcast_other_query ip4_other_query; - struct bridge_mcast_own_query ip4_own_query; - struct bridge_mcast_querier ip4_querier; - struct bridge_mcast_stats *mcast_stats; - struct hlist_head ip6_mc_router_list; - struct timer_list ip6_mc_router_timer; - struct bridge_mcast_other_query ip6_other_query; - struct bridge_mcast_own_query ip6_own_query; - struct bridge_mcast_querier ip6_querier; - struct work_struct mcast_gc_work; - struct timer_list hello_timer; - struct timer_list tcn_timer; - struct timer_list topology_change_timer; - struct delayed_work gc_work; - struct kobject *ifobj; - u32 auto_cnt; - int offload_fwd_mark; - struct hlist_head fdb_list; - struct hlist_head mrp_list; - struct hlist_head mep_list; -}; - -struct net_bridge_vlan_group { - struct rhashtable vlan_hash; - struct rhashtable tunnel_hash; - struct list_head vlan_list; - u16 num_vlans; - u16 pvid; - u8 pvid_state; -}; - -struct net_bridge_fdb_key { - mac_addr addr; - u16 vlan_id; -}; - -struct net_bridge_fdb_entry { - struct rhash_head rhnode; - struct net_bridge_port *dst; - struct net_bridge_fdb_key key; - struct hlist_node fdb_node; - long unsigned int flags; - long: 64; - long: 64; - long unsigned int updated; - long unsigned int used; - struct callback_head rcu; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct trace_event_raw_br_fdb_add { - struct trace_entry ent; - u8 ndm_flags; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - u16 nlh_flags; - char __data[0]; -}; - -struct trace_event_raw_br_fdb_external_learn_add { - struct trace_entry ent; - u32 __data_loc_br_dev; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - char __data[0]; -}; - -struct trace_event_raw_fdb_delete { - struct trace_entry ent; - u32 __data_loc_br_dev; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - char __data[0]; -}; - -struct trace_event_raw_br_fdb_update { - struct trace_entry ent; - u32 __data_loc_br_dev; - u32 __data_loc_dev; - unsigned char addr[6]; - u16 vid; - long unsigned int flags; - char __data[0]; -}; - -struct trace_event_data_offsets_br_fdb_add { - u32 dev; -}; - -struct trace_event_data_offsets_br_fdb_external_learn_add { - u32 br_dev; - u32 dev; -}; - -struct trace_event_data_offsets_fdb_delete { - u32 br_dev; - u32 dev; -}; - -struct trace_event_data_offsets_br_fdb_update { - u32 br_dev; - u32 dev; -}; - -typedef void (*btf_trace_br_fdb_add)(void *, struct ndmsg *, struct net_device *, const unsigned char *, u16, u16); - -typedef void (*btf_trace_br_fdb_external_learn_add)(void *, struct net_bridge *, struct net_bridge_port *, const unsigned char *, u16); - -typedef void (*btf_trace_fdb_delete)(void *, struct net_bridge *, struct net_bridge_fdb_entry *); - -typedef void (*btf_trace_br_fdb_update)(void *, struct net_bridge *, struct net_bridge_port *, const unsigned char *, u16, long unsigned int); - -struct trace_event_raw_page_pool_release { - struct trace_entry ent; - const struct page_pool *pool; - s32 inflight; - u32 hold; - u32 release; - u64 cnt; - char __data[0]; -}; - -struct trace_event_raw_page_pool_state_release { - struct trace_entry ent; - const struct page_pool *pool; - const struct page *page; - u32 release; - long unsigned int pfn; - char __data[0]; -}; - -struct trace_event_raw_page_pool_state_hold { - struct trace_entry ent; - const struct page_pool *pool; - const struct page *page; - u32 hold; - long unsigned int pfn; - char __data[0]; -}; - -struct trace_event_raw_page_pool_update_nid { - struct trace_entry ent; - const struct page_pool *pool; - int pool_nid; - int new_nid; - char __data[0]; -}; - -struct trace_event_data_offsets_page_pool_release {}; - -struct trace_event_data_offsets_page_pool_state_release {}; - -struct trace_event_data_offsets_page_pool_state_hold {}; - -struct trace_event_data_offsets_page_pool_update_nid {}; - -typedef void (*btf_trace_page_pool_release)(void *, const struct page_pool *, s32, u32, u32); - -typedef void (*btf_trace_page_pool_state_release)(void *, const struct page_pool *, const struct page *, u32); - -typedef void (*btf_trace_page_pool_state_hold)(void *, const struct page_pool *, const struct page *, u32); - -typedef void (*btf_trace_page_pool_update_nid)(void *, const struct page_pool *, int); - -struct trace_event_raw_neigh_create { - struct trace_entry ent; - u32 family; - u32 __data_loc_dev; - int entries; - u8 created; - u8 gc_exempt; - u8 primary_key4[4]; - u8 primary_key6[16]; - char __data[0]; -}; - -struct trace_event_raw_neigh_update { - struct trace_entry ent; - u32 family; - u32 __data_loc_dev; - u8 lladdr[32]; - u8 lladdr_len; - u8 flags; - u8 nud_state; - u8 type; - u8 dead; - int refcnt; - __u8 primary_key4[4]; - __u8 primary_key6[16]; - long unsigned int confirmed; - long unsigned int updated; - long unsigned int used; - u8 new_lladdr[32]; - u8 new_state; - u32 update_flags; - u32 pid; - char __data[0]; -}; - -struct trace_event_raw_neigh__update { - struct trace_entry ent; - u32 family; - u32 __data_loc_dev; - u8 lladdr[32]; - u8 lladdr_len; - u8 flags; - u8 nud_state; - u8 type; - u8 dead; - int refcnt; - __u8 primary_key4[4]; - __u8 primary_key6[16]; - long unsigned int confirmed; - long unsigned int updated; - long unsigned int used; - u32 err; - char __data[0]; -}; - -struct trace_event_data_offsets_neigh_create { - u32 dev; -}; - -struct trace_event_data_offsets_neigh_update { - u32 dev; -}; - -struct trace_event_data_offsets_neigh__update { - u32 dev; -}; - -typedef void (*btf_trace_neigh_create)(void *, struct neigh_table *, struct net_device *, const void *, const struct neighbour *, bool); - -typedef void (*btf_trace_neigh_update)(void *, struct neighbour *, const u8 *, u8, u32, u32); - -typedef void (*btf_trace_neigh_update_done)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_timer_handler)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_event_send_done)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_event_send_dead)(void *, struct neighbour *, int); - -typedef void (*btf_trace_neigh_cleanup_and_release)(void *, struct neighbour *, int); - -struct net_dm_drop_point { - __u8 pc[8]; - __u32 count; -}; - -struct net_dm_alert_msg { - __u32 entries; - struct net_dm_drop_point points[0]; -}; - -enum { - NET_DM_CMD_UNSPEC = 0, - NET_DM_CMD_ALERT = 1, - NET_DM_CMD_CONFIG = 2, - NET_DM_CMD_START = 3, - NET_DM_CMD_STOP = 4, - NET_DM_CMD_PACKET_ALERT = 5, - NET_DM_CMD_CONFIG_GET = 6, - NET_DM_CMD_CONFIG_NEW = 7, - NET_DM_CMD_STATS_GET = 8, - NET_DM_CMD_STATS_NEW = 9, - _NET_DM_CMD_MAX = 10, -}; - -enum net_dm_attr { - NET_DM_ATTR_UNSPEC = 0, - NET_DM_ATTR_ALERT_MODE = 1, - NET_DM_ATTR_PC = 2, - NET_DM_ATTR_SYMBOL = 3, - NET_DM_ATTR_IN_PORT = 4, - NET_DM_ATTR_TIMESTAMP = 5, - NET_DM_ATTR_PROTO = 6, - NET_DM_ATTR_PAYLOAD = 7, - NET_DM_ATTR_PAD = 8, - NET_DM_ATTR_TRUNC_LEN = 9, - NET_DM_ATTR_ORIG_LEN = 10, - NET_DM_ATTR_QUEUE_LEN = 11, - NET_DM_ATTR_STATS = 12, - NET_DM_ATTR_HW_STATS = 13, - NET_DM_ATTR_ORIGIN = 14, - NET_DM_ATTR_HW_TRAP_GROUP_NAME = 15, - NET_DM_ATTR_HW_TRAP_NAME = 16, - NET_DM_ATTR_HW_ENTRIES = 17, - NET_DM_ATTR_HW_ENTRY = 18, - NET_DM_ATTR_HW_TRAP_COUNT = 19, - NET_DM_ATTR_SW_DROPS = 20, - NET_DM_ATTR_HW_DROPS = 21, - NET_DM_ATTR_FLOW_ACTION_COOKIE = 22, - __NET_DM_ATTR_MAX = 23, - NET_DM_ATTR_MAX = 22, -}; - -enum net_dm_alert_mode { - NET_DM_ALERT_MODE_SUMMARY = 0, - NET_DM_ALERT_MODE_PACKET = 1, -}; - -enum { - NET_DM_ATTR_PORT_NETDEV_IFINDEX = 0, - NET_DM_ATTR_PORT_NETDEV_NAME = 1, - __NET_DM_ATTR_PORT_MAX = 2, - NET_DM_ATTR_PORT_MAX = 1, -}; - -enum { - NET_DM_ATTR_STATS_DROPPED = 0, - __NET_DM_ATTR_STATS_MAX = 1, - NET_DM_ATTR_STATS_MAX = 0, -}; - -enum net_dm_origin { - NET_DM_ORIGIN_SW = 0, - NET_DM_ORIGIN_HW = 1, -}; - -struct devlink_trap_metadata { - const char *trap_name; - const char *trap_group_name; - struct net_device *input_dev; - const struct flow_action_cookie *fa_cookie; - enum devlink_trap_type trap_type; -}; - -struct net_dm_stats { - u64 dropped; - struct u64_stats_sync syncp; -}; - -struct net_dm_hw_entry { - char trap_name[40]; - u32 count; -}; - -struct net_dm_hw_entries { - u32 num_entries; - struct net_dm_hw_entry entries[0]; -}; - -struct per_cpu_dm_data { - spinlock_t lock; - union { - struct sk_buff *skb; - struct net_dm_hw_entries *hw_entries; - }; - struct sk_buff_head drop_queue; - struct work_struct dm_alert_work; - struct timer_list send_timer; - struct net_dm_stats stats; -}; - -struct dm_hw_stat_delta { - struct net_device *dev; - long unsigned int last_rx; - struct list_head list; - struct callback_head rcu; - long unsigned int last_drop_val; -}; - -struct net_dm_alert_ops { - void (*kfree_skb_probe)(void *, struct sk_buff *, void *); - void (*napi_poll_probe)(void *, struct napi_struct *, int, int); - void (*work_item_func)(struct work_struct *); - void (*hw_work_item_func)(struct work_struct *); - void (*hw_trap_probe)(void *, const struct devlink *, struct sk_buff *, const struct devlink_trap_metadata *); -}; - -struct net_dm_skb_cb { - union { - struct devlink_trap_metadata *hw_metadata; - void *pc; - }; -}; - -struct update_classid_context { - u32 classid; - unsigned int batch; -}; - -struct rtnexthop { - short unsigned int rtnh_len; - unsigned char rtnh_flags; - unsigned char rtnh_hops; - int rtnh_ifindex; -}; - -struct lwtunnel_encap_ops { - int (*build_state)(struct net *, struct nlattr *, unsigned int, const void *, struct lwtunnel_state **, struct netlink_ext_ack *); - void (*destroy_state)(struct lwtunnel_state *); - int (*output)(struct net *, struct sock *, struct sk_buff *); - int (*input)(struct sk_buff *); - int (*fill_encap)(struct sk_buff *, struct lwtunnel_state *); - int (*get_encap_size)(struct lwtunnel_state *); - int (*cmp_encap)(struct lwtunnel_state *, struct lwtunnel_state *); - int (*xmit)(struct sk_buff *); - struct module *owner; -}; - -enum { - LWT_BPF_PROG_UNSPEC = 0, - LWT_BPF_PROG_FD = 1, - LWT_BPF_PROG_NAME = 2, - __LWT_BPF_PROG_MAX = 3, -}; - -enum { - LWT_BPF_UNSPEC = 0, - LWT_BPF_IN = 1, - LWT_BPF_OUT = 2, - LWT_BPF_XMIT = 3, - LWT_BPF_XMIT_HEADROOM = 4, - __LWT_BPF_MAX = 5, -}; - -enum { - LWTUNNEL_XMIT_DONE = 0, - LWTUNNEL_XMIT_CONTINUE = 1, -}; - -struct bpf_lwt_prog { - struct bpf_prog *prog; - char *name; -}; - -struct bpf_lwt { - struct bpf_lwt_prog in; - struct bpf_lwt_prog out; - struct bpf_lwt_prog xmit; - int family; -}; - -struct dst_cache_pcpu { - long unsigned int refresh_ts; - struct dst_entry *dst; - u32 cookie; - union { - struct in_addr in_saddr; - struct in6_addr in6_saddr; - }; -}; - -enum devlink_command { - DEVLINK_CMD_UNSPEC = 0, - DEVLINK_CMD_GET = 1, - DEVLINK_CMD_SET = 2, - DEVLINK_CMD_NEW = 3, - DEVLINK_CMD_DEL = 4, - DEVLINK_CMD_PORT_GET = 5, - DEVLINK_CMD_PORT_SET = 6, - DEVLINK_CMD_PORT_NEW = 7, - DEVLINK_CMD_PORT_DEL = 8, - DEVLINK_CMD_PORT_SPLIT = 9, - DEVLINK_CMD_PORT_UNSPLIT = 10, - DEVLINK_CMD_SB_GET = 11, - DEVLINK_CMD_SB_SET = 12, - DEVLINK_CMD_SB_NEW = 13, - DEVLINK_CMD_SB_DEL = 14, - DEVLINK_CMD_SB_POOL_GET = 15, - DEVLINK_CMD_SB_POOL_SET = 16, - DEVLINK_CMD_SB_POOL_NEW = 17, - DEVLINK_CMD_SB_POOL_DEL = 18, - DEVLINK_CMD_SB_PORT_POOL_GET = 19, - DEVLINK_CMD_SB_PORT_POOL_SET = 20, - DEVLINK_CMD_SB_PORT_POOL_NEW = 21, - DEVLINK_CMD_SB_PORT_POOL_DEL = 22, - DEVLINK_CMD_SB_TC_POOL_BIND_GET = 23, - DEVLINK_CMD_SB_TC_POOL_BIND_SET = 24, - DEVLINK_CMD_SB_TC_POOL_BIND_NEW = 25, - DEVLINK_CMD_SB_TC_POOL_BIND_DEL = 26, - DEVLINK_CMD_SB_OCC_SNAPSHOT = 27, - DEVLINK_CMD_SB_OCC_MAX_CLEAR = 28, - DEVLINK_CMD_ESWITCH_GET = 29, - DEVLINK_CMD_ESWITCH_SET = 30, - DEVLINK_CMD_DPIPE_TABLE_GET = 31, - DEVLINK_CMD_DPIPE_ENTRIES_GET = 32, - DEVLINK_CMD_DPIPE_HEADERS_GET = 33, - DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET = 34, - DEVLINK_CMD_RESOURCE_SET = 35, - DEVLINK_CMD_RESOURCE_DUMP = 36, - DEVLINK_CMD_RELOAD = 37, - DEVLINK_CMD_PARAM_GET = 38, - DEVLINK_CMD_PARAM_SET = 39, - DEVLINK_CMD_PARAM_NEW = 40, - DEVLINK_CMD_PARAM_DEL = 41, - DEVLINK_CMD_REGION_GET = 42, - DEVLINK_CMD_REGION_SET = 43, - DEVLINK_CMD_REGION_NEW = 44, - DEVLINK_CMD_REGION_DEL = 45, - DEVLINK_CMD_REGION_READ = 46, - DEVLINK_CMD_PORT_PARAM_GET = 47, - DEVLINK_CMD_PORT_PARAM_SET = 48, - DEVLINK_CMD_PORT_PARAM_NEW = 49, - DEVLINK_CMD_PORT_PARAM_DEL = 50, - DEVLINK_CMD_INFO_GET = 51, - DEVLINK_CMD_HEALTH_REPORTER_GET = 52, - DEVLINK_CMD_HEALTH_REPORTER_SET = 53, - DEVLINK_CMD_HEALTH_REPORTER_RECOVER = 54, - DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE = 55, - DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET = 56, - DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR = 57, - DEVLINK_CMD_FLASH_UPDATE = 58, - DEVLINK_CMD_FLASH_UPDATE_END = 59, - DEVLINK_CMD_FLASH_UPDATE_STATUS = 60, - DEVLINK_CMD_TRAP_GET = 61, - DEVLINK_CMD_TRAP_SET = 62, - DEVLINK_CMD_TRAP_NEW = 63, - DEVLINK_CMD_TRAP_DEL = 64, - DEVLINK_CMD_TRAP_GROUP_GET = 65, - DEVLINK_CMD_TRAP_GROUP_SET = 66, - DEVLINK_CMD_TRAP_GROUP_NEW = 67, - DEVLINK_CMD_TRAP_GROUP_DEL = 68, - DEVLINK_CMD_TRAP_POLICER_GET = 69, - DEVLINK_CMD_TRAP_POLICER_SET = 70, - DEVLINK_CMD_TRAP_POLICER_NEW = 71, - DEVLINK_CMD_TRAP_POLICER_DEL = 72, - DEVLINK_CMD_HEALTH_REPORTER_TEST = 73, - DEVLINK_CMD_RATE_GET = 74, - DEVLINK_CMD_RATE_SET = 75, - DEVLINK_CMD_RATE_NEW = 76, - DEVLINK_CMD_RATE_DEL = 77, - __DEVLINK_CMD_MAX = 78, - DEVLINK_CMD_MAX = 77, -}; - -enum devlink_eswitch_mode { - DEVLINK_ESWITCH_MODE_LEGACY = 0, - DEVLINK_ESWITCH_MODE_SWITCHDEV = 1, -}; - -enum { - DEVLINK_ATTR_STATS_RX_PACKETS = 0, - DEVLINK_ATTR_STATS_RX_BYTES = 1, - DEVLINK_ATTR_STATS_RX_DROPPED = 2, - __DEVLINK_ATTR_STATS_MAX = 3, - DEVLINK_ATTR_STATS_MAX = 2, -}; - -enum { - DEVLINK_FLASH_OVERWRITE_SETTINGS_BIT = 0, - DEVLINK_FLASH_OVERWRITE_IDENTIFIERS_BIT = 1, - __DEVLINK_FLASH_OVERWRITE_MAX_BIT = 2, - DEVLINK_FLASH_OVERWRITE_MAX_BIT = 1, -}; - -enum { - DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT = 0, - DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE = 1, -}; - -enum devlink_attr { - DEVLINK_ATTR_UNSPEC = 0, - DEVLINK_ATTR_BUS_NAME = 1, - DEVLINK_ATTR_DEV_NAME = 2, - DEVLINK_ATTR_PORT_INDEX = 3, - DEVLINK_ATTR_PORT_TYPE = 4, - DEVLINK_ATTR_PORT_DESIRED_TYPE = 5, - DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6, - DEVLINK_ATTR_PORT_NETDEV_NAME = 7, - DEVLINK_ATTR_PORT_IBDEV_NAME = 8, - DEVLINK_ATTR_PORT_SPLIT_COUNT = 9, - DEVLINK_ATTR_PORT_SPLIT_GROUP = 10, - DEVLINK_ATTR_SB_INDEX = 11, - DEVLINK_ATTR_SB_SIZE = 12, - DEVLINK_ATTR_SB_INGRESS_POOL_COUNT = 13, - DEVLINK_ATTR_SB_EGRESS_POOL_COUNT = 14, - DEVLINK_ATTR_SB_INGRESS_TC_COUNT = 15, - DEVLINK_ATTR_SB_EGRESS_TC_COUNT = 16, - DEVLINK_ATTR_SB_POOL_INDEX = 17, - DEVLINK_ATTR_SB_POOL_TYPE = 18, - DEVLINK_ATTR_SB_POOL_SIZE = 19, - DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE = 20, - DEVLINK_ATTR_SB_THRESHOLD = 21, - DEVLINK_ATTR_SB_TC_INDEX = 22, - DEVLINK_ATTR_SB_OCC_CUR = 23, - DEVLINK_ATTR_SB_OCC_MAX = 24, - DEVLINK_ATTR_ESWITCH_MODE = 25, - DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26, - DEVLINK_ATTR_DPIPE_TABLES = 27, - DEVLINK_ATTR_DPIPE_TABLE = 28, - DEVLINK_ATTR_DPIPE_TABLE_NAME = 29, - DEVLINK_ATTR_DPIPE_TABLE_SIZE = 30, - DEVLINK_ATTR_DPIPE_TABLE_MATCHES = 31, - DEVLINK_ATTR_DPIPE_TABLE_ACTIONS = 32, - DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED = 33, - DEVLINK_ATTR_DPIPE_ENTRIES = 34, - DEVLINK_ATTR_DPIPE_ENTRY = 35, - DEVLINK_ATTR_DPIPE_ENTRY_INDEX = 36, - DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES = 37, - DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES = 38, - DEVLINK_ATTR_DPIPE_ENTRY_COUNTER = 39, - DEVLINK_ATTR_DPIPE_MATCH = 40, - DEVLINK_ATTR_DPIPE_MATCH_VALUE = 41, - DEVLINK_ATTR_DPIPE_MATCH_TYPE = 42, - DEVLINK_ATTR_DPIPE_ACTION = 43, - DEVLINK_ATTR_DPIPE_ACTION_VALUE = 44, - DEVLINK_ATTR_DPIPE_ACTION_TYPE = 45, - DEVLINK_ATTR_DPIPE_VALUE = 46, - DEVLINK_ATTR_DPIPE_VALUE_MASK = 47, - DEVLINK_ATTR_DPIPE_VALUE_MAPPING = 48, - DEVLINK_ATTR_DPIPE_HEADERS = 49, - DEVLINK_ATTR_DPIPE_HEADER = 50, - DEVLINK_ATTR_DPIPE_HEADER_NAME = 51, - DEVLINK_ATTR_DPIPE_HEADER_ID = 52, - DEVLINK_ATTR_DPIPE_HEADER_FIELDS = 53, - DEVLINK_ATTR_DPIPE_HEADER_GLOBAL = 54, - DEVLINK_ATTR_DPIPE_HEADER_INDEX = 55, - DEVLINK_ATTR_DPIPE_FIELD = 56, - DEVLINK_ATTR_DPIPE_FIELD_NAME = 57, - DEVLINK_ATTR_DPIPE_FIELD_ID = 58, - DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH = 59, - DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE = 60, - DEVLINK_ATTR_PAD = 61, - DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62, - DEVLINK_ATTR_RESOURCE_LIST = 63, - DEVLINK_ATTR_RESOURCE = 64, - DEVLINK_ATTR_RESOURCE_NAME = 65, - DEVLINK_ATTR_RESOURCE_ID = 66, - DEVLINK_ATTR_RESOURCE_SIZE = 67, - DEVLINK_ATTR_RESOURCE_SIZE_NEW = 68, - DEVLINK_ATTR_RESOURCE_SIZE_VALID = 69, - DEVLINK_ATTR_RESOURCE_SIZE_MIN = 70, - DEVLINK_ATTR_RESOURCE_SIZE_MAX = 71, - DEVLINK_ATTR_RESOURCE_SIZE_GRAN = 72, - DEVLINK_ATTR_RESOURCE_UNIT = 73, - DEVLINK_ATTR_RESOURCE_OCC = 74, - DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID = 75, - DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS = 76, - DEVLINK_ATTR_PORT_FLAVOUR = 77, - DEVLINK_ATTR_PORT_NUMBER = 78, - DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER = 79, - DEVLINK_ATTR_PARAM = 80, - DEVLINK_ATTR_PARAM_NAME = 81, - DEVLINK_ATTR_PARAM_GENERIC = 82, - DEVLINK_ATTR_PARAM_TYPE = 83, - DEVLINK_ATTR_PARAM_VALUES_LIST = 84, - DEVLINK_ATTR_PARAM_VALUE = 85, - DEVLINK_ATTR_PARAM_VALUE_DATA = 86, - DEVLINK_ATTR_PARAM_VALUE_CMODE = 87, - DEVLINK_ATTR_REGION_NAME = 88, - DEVLINK_ATTR_REGION_SIZE = 89, - DEVLINK_ATTR_REGION_SNAPSHOTS = 90, - DEVLINK_ATTR_REGION_SNAPSHOT = 91, - DEVLINK_ATTR_REGION_SNAPSHOT_ID = 92, - DEVLINK_ATTR_REGION_CHUNKS = 93, - DEVLINK_ATTR_REGION_CHUNK = 94, - DEVLINK_ATTR_REGION_CHUNK_DATA = 95, - DEVLINK_ATTR_REGION_CHUNK_ADDR = 96, - DEVLINK_ATTR_REGION_CHUNK_LEN = 97, - DEVLINK_ATTR_INFO_DRIVER_NAME = 98, - DEVLINK_ATTR_INFO_SERIAL_NUMBER = 99, - DEVLINK_ATTR_INFO_VERSION_FIXED = 100, - DEVLINK_ATTR_INFO_VERSION_RUNNING = 101, - DEVLINK_ATTR_INFO_VERSION_STORED = 102, - DEVLINK_ATTR_INFO_VERSION_NAME = 103, - DEVLINK_ATTR_INFO_VERSION_VALUE = 104, - DEVLINK_ATTR_SB_POOL_CELL_SIZE = 105, - DEVLINK_ATTR_FMSG = 106, - DEVLINK_ATTR_FMSG_OBJ_NEST_START = 107, - DEVLINK_ATTR_FMSG_PAIR_NEST_START = 108, - DEVLINK_ATTR_FMSG_ARR_NEST_START = 109, - DEVLINK_ATTR_FMSG_NEST_END = 110, - DEVLINK_ATTR_FMSG_OBJ_NAME = 111, - DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE = 112, - DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA = 113, - DEVLINK_ATTR_HEALTH_REPORTER = 114, - DEVLINK_ATTR_HEALTH_REPORTER_NAME = 115, - DEVLINK_ATTR_HEALTH_REPORTER_STATE = 116, - DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT = 117, - DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT = 118, - DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS = 119, - DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD = 120, - DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER = 121, - DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME = 122, - DEVLINK_ATTR_FLASH_UPDATE_COMPONENT = 123, - DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG = 124, - DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE = 125, - DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL = 126, - DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127, - DEVLINK_ATTR_PORT_PCI_VF_NUMBER = 128, - DEVLINK_ATTR_STATS = 129, - DEVLINK_ATTR_TRAP_NAME = 130, - DEVLINK_ATTR_TRAP_ACTION = 131, - DEVLINK_ATTR_TRAP_TYPE = 132, - DEVLINK_ATTR_TRAP_GENERIC = 133, - DEVLINK_ATTR_TRAP_METADATA = 134, - DEVLINK_ATTR_TRAP_GROUP_NAME = 135, - DEVLINK_ATTR_RELOAD_FAILED = 136, - DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS = 137, - DEVLINK_ATTR_NETNS_FD = 138, - DEVLINK_ATTR_NETNS_PID = 139, - DEVLINK_ATTR_NETNS_ID = 140, - DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP = 141, - DEVLINK_ATTR_TRAP_POLICER_ID = 142, - DEVLINK_ATTR_TRAP_POLICER_RATE = 143, - DEVLINK_ATTR_TRAP_POLICER_BURST = 144, - DEVLINK_ATTR_PORT_FUNCTION = 145, - DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER = 146, - DEVLINK_ATTR_PORT_LANES = 147, - DEVLINK_ATTR_PORT_SPLITTABLE = 148, - DEVLINK_ATTR_PORT_EXTERNAL = 149, - DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150, - DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT = 151, - DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK = 152, - DEVLINK_ATTR_RELOAD_ACTION = 153, - DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED = 154, - DEVLINK_ATTR_RELOAD_LIMITS = 155, - DEVLINK_ATTR_DEV_STATS = 156, - DEVLINK_ATTR_RELOAD_STATS = 157, - DEVLINK_ATTR_RELOAD_STATS_ENTRY = 158, - DEVLINK_ATTR_RELOAD_STATS_LIMIT = 159, - DEVLINK_ATTR_RELOAD_STATS_VALUE = 160, - DEVLINK_ATTR_REMOTE_RELOAD_STATS = 161, - DEVLINK_ATTR_RELOAD_ACTION_INFO = 162, - DEVLINK_ATTR_RELOAD_ACTION_STATS = 163, - DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164, - DEVLINK_ATTR_RATE_TYPE = 165, - DEVLINK_ATTR_RATE_TX_SHARE = 166, - DEVLINK_ATTR_RATE_TX_MAX = 167, - DEVLINK_ATTR_RATE_NODE_NAME = 168, - DEVLINK_ATTR_RATE_PARENT_NODE_NAME = 169, - __DEVLINK_ATTR_MAX = 170, - DEVLINK_ATTR_MAX = 169, -}; - -enum devlink_dpipe_match_type { - DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT = 0, -}; - -enum devlink_dpipe_action_type { - DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY = 0, -}; - -enum devlink_dpipe_field_ethernet_id { - DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC = 0, -}; - -enum devlink_dpipe_field_ipv4_id { - DEVLINK_DPIPE_FIELD_IPV4_DST_IP = 0, -}; - -enum devlink_dpipe_field_ipv6_id { - DEVLINK_DPIPE_FIELD_IPV6_DST_IP = 0, -}; - -enum devlink_dpipe_header_id { - DEVLINK_DPIPE_HEADER_ETHERNET = 0, - DEVLINK_DPIPE_HEADER_IPV4 = 1, - DEVLINK_DPIPE_HEADER_IPV6 = 2, -}; - -enum devlink_resource_unit { - DEVLINK_RESOURCE_UNIT_ENTRY = 0, -}; - -enum devlink_port_function_attr { - DEVLINK_PORT_FUNCTION_ATTR_UNSPEC = 0, - DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR = 1, - DEVLINK_PORT_FN_ATTR_STATE = 2, - DEVLINK_PORT_FN_ATTR_OPSTATE = 3, - __DEVLINK_PORT_FUNCTION_ATTR_MAX = 4, - DEVLINK_PORT_FUNCTION_ATTR_MAX = 3, -}; - -struct devlink_dpipe_match { - enum devlink_dpipe_match_type type; - unsigned int header_index; - struct devlink_dpipe_header *header; - unsigned int field_id; -}; - -struct devlink_dpipe_action { - enum devlink_dpipe_action_type type; - unsigned int header_index; - struct devlink_dpipe_header *header; - unsigned int field_id; -}; - -struct devlink_dpipe_value { - union { - struct devlink_dpipe_action *action; - struct devlink_dpipe_match *match; - }; - unsigned int mapping_value; - bool mapping_valid; - unsigned int value_size; - void *value; - void *mask; -}; - -struct devlink_dpipe_entry { - u64 index; - struct devlink_dpipe_value *match_values; - unsigned int match_values_count; - struct devlink_dpipe_value *action_values; - unsigned int action_values_count; - u64 counter; - bool counter_valid; -}; - -struct devlink_dpipe_dump_ctx { - struct genl_info *info; - enum devlink_command cmd; - struct sk_buff *skb; - struct nlattr *nest; - void *hdr; -}; - -struct devlink_dpipe_table_ops; - -struct devlink_dpipe_table { - void *priv; - struct list_head list; - const char *name; - bool counters_enabled; - bool counter_control_extern; - bool resource_valid; - u64 resource_id; - u64 resource_units; - struct devlink_dpipe_table_ops *table_ops; - struct callback_head rcu; -}; - -struct devlink_dpipe_table_ops { - int (*actions_dump)(void *, struct sk_buff *); - int (*matches_dump)(void *, struct sk_buff *); - int (*entries_dump)(void *, bool, struct devlink_dpipe_dump_ctx *); - int (*counters_set_update)(void *, bool); - u64 (*size_get)(void *); -}; - -struct devlink_resource_size_params { - u64 size_min; - u64 size_max; - u64 size_granularity; - enum devlink_resource_unit unit; -}; - -typedef u64 devlink_resource_occ_get_t(void *); - -struct devlink_resource { - const char *name; - u64 id; - u64 size; - u64 size_new; - bool size_valid; - struct devlink_resource *parent; - struct devlink_resource_size_params size_params; - struct list_head list; - struct list_head resource_list; - devlink_resource_occ_get_t *occ_get; - void *occ_get_priv; -}; - -enum devlink_param_type { - DEVLINK_PARAM_TYPE_U8 = 0, - DEVLINK_PARAM_TYPE_U16 = 1, - DEVLINK_PARAM_TYPE_U32 = 2, - DEVLINK_PARAM_TYPE_STRING = 3, - DEVLINK_PARAM_TYPE_BOOL = 4, -}; - -struct devlink_flash_notify { - const char *status_msg; - const char *component; - long unsigned int done; - long unsigned int total; - long unsigned int timeout; -}; - -struct devlink_param { - u32 id; - const char *name; - bool generic; - enum devlink_param_type type; - long unsigned int supported_cmodes; - int (*get)(struct devlink *, u32, struct devlink_param_gset_ctx *); - int (*set)(struct devlink *, u32, struct devlink_param_gset_ctx *); - int (*validate)(struct devlink *, u32, union devlink_param_value, struct netlink_ext_ack *); -}; - -struct devlink_param_item { - struct list_head list; - const struct devlink_param *param; - union devlink_param_value driverinit_value; - bool driverinit_value_valid; - bool published; -}; - -enum devlink_param_generic_id { - DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET = 0, - DEVLINK_PARAM_GENERIC_ID_MAX_MACS = 1, - DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV = 2, - DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT = 3, - DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI = 4, - DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX = 5, - DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN = 6, - DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY = 7, - DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE = 8, - DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE = 9, - DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET = 10, - __DEVLINK_PARAM_GENERIC_ID_MAX = 11, - DEVLINK_PARAM_GENERIC_ID_MAX = 10, -}; - -struct devlink_region_ops { - const char *name; - void (*destructor)(const void *); - int (*snapshot)(struct devlink *, const struct devlink_region_ops *, struct netlink_ext_ack *, u8 **); - void *priv; -}; - -struct devlink_port_region_ops { - const char *name; - void (*destructor)(const void *); - int (*snapshot)(struct devlink_port *, const struct devlink_port_region_ops *, struct netlink_ext_ack *, u8 **); - void *priv; -}; - -enum devlink_health_reporter_state { - DEVLINK_HEALTH_REPORTER_STATE_HEALTHY = 0, - DEVLINK_HEALTH_REPORTER_STATE_ERROR = 1, -}; - -struct devlink_health_reporter; - -struct devlink_fmsg; - -struct devlink_health_reporter_ops { - char *name; - int (*recover)(struct devlink_health_reporter *, void *, struct netlink_ext_ack *); - int (*dump)(struct devlink_health_reporter *, struct devlink_fmsg *, void *, struct netlink_ext_ack *); - int (*diagnose)(struct devlink_health_reporter *, struct devlink_fmsg *, struct netlink_ext_ack *); - int (*test)(struct devlink_health_reporter *, struct netlink_ext_ack *); -}; - -struct devlink_health_reporter { - struct list_head list; - void *priv; - const struct devlink_health_reporter_ops *ops; - struct devlink *devlink; - struct devlink_port *devlink_port; - struct devlink_fmsg *dump_fmsg; - struct mutex dump_lock; - u64 graceful_period; - bool auto_recover; - bool auto_dump; - u8 health_state; - u64 dump_ts; - u64 dump_real_ts; - u64 error_count; - u64 recovery_count; - u64 last_recovery_ts; - refcount_t refcount; -}; - -struct devlink_fmsg { - struct list_head item_list; - bool putting_binary; -}; - -enum devlink_trap_generic_id { - DEVLINK_TRAP_GENERIC_ID_SMAC_MC = 0, - DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH = 1, - DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER = 2, - DEVLINK_TRAP_GENERIC_ID_INGRESS_STP_FILTER = 3, - DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST = 4, - DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER = 5, - DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE = 6, - DEVLINK_TRAP_GENERIC_ID_TTL_ERROR = 7, - DEVLINK_TRAP_GENERIC_ID_TAIL_DROP = 8, - DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET = 9, - DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC = 10, - DEVLINK_TRAP_GENERIC_ID_DIP_LB = 11, - DEVLINK_TRAP_GENERIC_ID_SIP_MC = 12, - DEVLINK_TRAP_GENERIC_ID_SIP_LB = 13, - DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR = 14, - DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC = 15, - DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE = 16, - DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE = 17, - DEVLINK_TRAP_GENERIC_ID_MTU_ERROR = 18, - DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH = 19, - DEVLINK_TRAP_GENERIC_ID_RPF = 20, - DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE = 21, - DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS = 22, - DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS = 23, - DEVLINK_TRAP_GENERIC_ID_NON_ROUTABLE = 24, - DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR = 25, - DEVLINK_TRAP_GENERIC_ID_OVERLAY_SMAC_MC = 26, - DEVLINK_TRAP_GENERIC_ID_INGRESS_FLOW_ACTION_DROP = 27, - DEVLINK_TRAP_GENERIC_ID_EGRESS_FLOW_ACTION_DROP = 28, - DEVLINK_TRAP_GENERIC_ID_STP = 29, - DEVLINK_TRAP_GENERIC_ID_LACP = 30, - DEVLINK_TRAP_GENERIC_ID_LLDP = 31, - DEVLINK_TRAP_GENERIC_ID_IGMP_QUERY = 32, - DEVLINK_TRAP_GENERIC_ID_IGMP_V1_REPORT = 33, - DEVLINK_TRAP_GENERIC_ID_IGMP_V2_REPORT = 34, - DEVLINK_TRAP_GENERIC_ID_IGMP_V3_REPORT = 35, - DEVLINK_TRAP_GENERIC_ID_IGMP_V2_LEAVE = 36, - DEVLINK_TRAP_GENERIC_ID_MLD_QUERY = 37, - DEVLINK_TRAP_GENERIC_ID_MLD_V1_REPORT = 38, - DEVLINK_TRAP_GENERIC_ID_MLD_V2_REPORT = 39, - DEVLINK_TRAP_GENERIC_ID_MLD_V1_DONE = 40, - DEVLINK_TRAP_GENERIC_ID_IPV4_DHCP = 41, - DEVLINK_TRAP_GENERIC_ID_IPV6_DHCP = 42, - DEVLINK_TRAP_GENERIC_ID_ARP_REQUEST = 43, - DEVLINK_TRAP_GENERIC_ID_ARP_RESPONSE = 44, - DEVLINK_TRAP_GENERIC_ID_ARP_OVERLAY = 45, - DEVLINK_TRAP_GENERIC_ID_IPV6_NEIGH_SOLICIT = 46, - DEVLINK_TRAP_GENERIC_ID_IPV6_NEIGH_ADVERT = 47, - DEVLINK_TRAP_GENERIC_ID_IPV4_BFD = 48, - DEVLINK_TRAP_GENERIC_ID_IPV6_BFD = 49, - DEVLINK_TRAP_GENERIC_ID_IPV4_OSPF = 50, - DEVLINK_TRAP_GENERIC_ID_IPV6_OSPF = 51, - DEVLINK_TRAP_GENERIC_ID_IPV4_BGP = 52, - DEVLINK_TRAP_GENERIC_ID_IPV6_BGP = 53, - DEVLINK_TRAP_GENERIC_ID_IPV4_VRRP = 54, - DEVLINK_TRAP_GENERIC_ID_IPV6_VRRP = 55, - DEVLINK_TRAP_GENERIC_ID_IPV4_PIM = 56, - DEVLINK_TRAP_GENERIC_ID_IPV6_PIM = 57, - DEVLINK_TRAP_GENERIC_ID_UC_LB = 58, - DEVLINK_TRAP_GENERIC_ID_LOCAL_ROUTE = 59, - DEVLINK_TRAP_GENERIC_ID_EXTERNAL_ROUTE = 60, - DEVLINK_TRAP_GENERIC_ID_IPV6_UC_DIP_LINK_LOCAL_SCOPE = 61, - DEVLINK_TRAP_GENERIC_ID_IPV6_DIP_ALL_NODES = 62, - DEVLINK_TRAP_GENERIC_ID_IPV6_DIP_ALL_ROUTERS = 63, - DEVLINK_TRAP_GENERIC_ID_IPV6_ROUTER_SOLICIT = 64, - DEVLINK_TRAP_GENERIC_ID_IPV6_ROUTER_ADVERT = 65, - DEVLINK_TRAP_GENERIC_ID_IPV6_REDIRECT = 66, - DEVLINK_TRAP_GENERIC_ID_IPV4_ROUTER_ALERT = 67, - DEVLINK_TRAP_GENERIC_ID_IPV6_ROUTER_ALERT = 68, - DEVLINK_TRAP_GENERIC_ID_PTP_EVENT = 69, - DEVLINK_TRAP_GENERIC_ID_PTP_GENERAL = 70, - DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_SAMPLE = 71, - DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_TRAP = 72, - DEVLINK_TRAP_GENERIC_ID_EARLY_DROP = 73, - DEVLINK_TRAP_GENERIC_ID_VXLAN_PARSING = 74, - DEVLINK_TRAP_GENERIC_ID_LLC_SNAP_PARSING = 75, - DEVLINK_TRAP_GENERIC_ID_VLAN_PARSING = 76, - DEVLINK_TRAP_GENERIC_ID_PPPOE_PPP_PARSING = 77, - DEVLINK_TRAP_GENERIC_ID_MPLS_PARSING = 78, - DEVLINK_TRAP_GENERIC_ID_ARP_PARSING = 79, - DEVLINK_TRAP_GENERIC_ID_IP_1_PARSING = 80, - DEVLINK_TRAP_GENERIC_ID_IP_N_PARSING = 81, - DEVLINK_TRAP_GENERIC_ID_GRE_PARSING = 82, - DEVLINK_TRAP_GENERIC_ID_UDP_PARSING = 83, - DEVLINK_TRAP_GENERIC_ID_TCP_PARSING = 84, - DEVLINK_TRAP_GENERIC_ID_IPSEC_PARSING = 85, - DEVLINK_TRAP_GENERIC_ID_SCTP_PARSING = 86, - DEVLINK_TRAP_GENERIC_ID_DCCP_PARSING = 87, - DEVLINK_TRAP_GENERIC_ID_GTP_PARSING = 88, - DEVLINK_TRAP_GENERIC_ID_ESP_PARSING = 89, - DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_NEXTHOP = 90, - DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER = 91, - __DEVLINK_TRAP_GENERIC_ID_MAX = 92, - DEVLINK_TRAP_GENERIC_ID_MAX = 91, -}; - -enum devlink_trap_group_generic_id { - DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS = 0, - DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS = 1, - DEVLINK_TRAP_GROUP_GENERIC_ID_L3_EXCEPTIONS = 2, - DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS = 3, - DEVLINK_TRAP_GROUP_GENERIC_ID_TUNNEL_DROPS = 4, - DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_DROPS = 5, - DEVLINK_TRAP_GROUP_GENERIC_ID_STP = 6, - DEVLINK_TRAP_GROUP_GENERIC_ID_LACP = 7, - DEVLINK_TRAP_GROUP_GENERIC_ID_LLDP = 8, - DEVLINK_TRAP_GROUP_GENERIC_ID_MC_SNOOPING = 9, - DEVLINK_TRAP_GROUP_GENERIC_ID_DHCP = 10, - DEVLINK_TRAP_GROUP_GENERIC_ID_NEIGH_DISCOVERY = 11, - DEVLINK_TRAP_GROUP_GENERIC_ID_BFD = 12, - DEVLINK_TRAP_GROUP_GENERIC_ID_OSPF = 13, - DEVLINK_TRAP_GROUP_GENERIC_ID_BGP = 14, - DEVLINK_TRAP_GROUP_GENERIC_ID_VRRP = 15, - DEVLINK_TRAP_GROUP_GENERIC_ID_PIM = 16, - DEVLINK_TRAP_GROUP_GENERIC_ID_UC_LB = 17, - DEVLINK_TRAP_GROUP_GENERIC_ID_LOCAL_DELIVERY = 18, - DEVLINK_TRAP_GROUP_GENERIC_ID_EXTERNAL_DELIVERY = 19, - DEVLINK_TRAP_GROUP_GENERIC_ID_IPV6 = 20, - DEVLINK_TRAP_GROUP_GENERIC_ID_PTP_EVENT = 21, - DEVLINK_TRAP_GROUP_GENERIC_ID_PTP_GENERAL = 22, - DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_SAMPLE = 23, - DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_TRAP = 24, - DEVLINK_TRAP_GROUP_GENERIC_ID_PARSER_ERROR_DROPS = 25, - __DEVLINK_TRAP_GROUP_GENERIC_ID_MAX = 26, - DEVLINK_TRAP_GROUP_GENERIC_ID_MAX = 25, -}; - -struct devlink_info_req { - struct sk_buff *msg; -}; - -struct trace_event_raw_devlink_hwmsg { - struct trace_entry ent; - u32 __data_loc_bus_name; - u32 __data_loc_dev_name; - u32 __data_loc_driver_name; - bool incoming; - long unsigned int type; - u32 __data_loc_buf; - size_t len; - char __data[0]; -}; - -struct trace_event_raw_devlink_hwerr { - struct trace_entry ent; - u32 __data_loc_bus_name; - u32 __data_loc_dev_name; - u32 __data_loc_driver_name; - int err; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_raw_devlink_health_report { - struct trace_entry ent; - u32 __data_loc_bus_name; - u32 __data_loc_dev_name; - u32 __data_loc_driver_name; - u32 __data_loc_reporter_name; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_raw_devlink_health_recover_aborted { - struct trace_entry ent; - u32 __data_loc_bus_name; - u32 __data_loc_dev_name; - u32 __data_loc_driver_name; - u32 __data_loc_reporter_name; - bool health_state; - u64 time_since_last_recover; - char __data[0]; -}; - -struct trace_event_raw_devlink_health_reporter_state_update { - struct trace_entry ent; - u32 __data_loc_bus_name; - u32 __data_loc_dev_name; - u32 __data_loc_driver_name; - u32 __data_loc_reporter_name; - u8 new_state; - char __data[0]; -}; - -struct trace_event_raw_devlink_trap_report { - struct trace_entry ent; - u32 __data_loc_bus_name; - u32 __data_loc_dev_name; - u32 __data_loc_driver_name; - u32 __data_loc_trap_name; - u32 __data_loc_trap_group_name; - u32 __data_loc_input_dev_name; - char __data[0]; -}; - -struct trace_event_data_offsets_devlink_hwmsg { - u32 bus_name; - u32 dev_name; - u32 driver_name; - u32 buf; -}; - -struct trace_event_data_offsets_devlink_hwerr { - u32 bus_name; - u32 dev_name; - u32 driver_name; - u32 msg; -}; - -struct trace_event_data_offsets_devlink_health_report { - u32 bus_name; - u32 dev_name; - u32 driver_name; - u32 reporter_name; - u32 msg; -}; - -struct trace_event_data_offsets_devlink_health_recover_aborted { - u32 bus_name; - u32 dev_name; - u32 driver_name; - u32 reporter_name; -}; - -struct trace_event_data_offsets_devlink_health_reporter_state_update { - u32 bus_name; - u32 dev_name; - u32 driver_name; - u32 reporter_name; -}; - -struct trace_event_data_offsets_devlink_trap_report { - u32 bus_name; - u32 dev_name; - u32 driver_name; - u32 trap_name; - u32 trap_group_name; - u32 input_dev_name; -}; - -typedef void (*btf_trace_devlink_hwmsg)(void *, const struct devlink *, bool, long unsigned int, const u8 *, size_t); - -typedef void (*btf_trace_devlink_hwerr)(void *, const struct devlink *, int, const char *); - -typedef void (*btf_trace_devlink_health_report)(void *, const struct devlink *, const char *, const char *); - -typedef void (*btf_trace_devlink_health_recover_aborted)(void *, const struct devlink *, const char *, bool, u64); - -typedef void (*btf_trace_devlink_health_reporter_state_update)(void *, const struct devlink *, const char *, bool); - -typedef void (*btf_trace_devlink_trap_report)(void *, const struct devlink *, struct sk_buff *, const struct devlink_trap_metadata *); - -struct devlink_sb { - struct list_head list; - unsigned int index; - u32 size; - u16 ingress_pools_count; - u16 egress_pools_count; - u16 ingress_tc_count; - u16 egress_tc_count; -}; - -struct devlink_region { - struct devlink *devlink; - struct devlink_port *port; - struct list_head list; - union { - const struct devlink_region_ops *ops; - const struct devlink_port_region_ops *port_ops; - }; - struct list_head snapshot_list; - u32 max_snapshots; - u32 cur_snapshots; - u64 size; -}; - -struct devlink_snapshot { - struct list_head list; - struct devlink_region *region; - u8 *data; - u32 id; -}; - -enum devlink_multicast_groups { - DEVLINK_MCGRP_CONFIG = 0, -}; - -struct devlink_reload_combination { - enum devlink_reload_action action; - enum devlink_reload_limit limit; -}; - -struct devlink_fmsg_item { - struct list_head list; - int attrtype; - u8 nla_type; - u16 len; - int value[0]; -}; - -struct devlink_stats { - u64 rx_bytes; - u64 rx_packets; - struct u64_stats_sync syncp; -}; - -struct devlink_trap_policer_item { - const struct devlink_trap_policer *policer; - u64 rate; - u64 burst; - struct list_head list; -}; - -struct devlink_trap_group_item { - const struct devlink_trap_group *group; - struct devlink_trap_policer_item *policer_item; - struct list_head list; - struct devlink_stats *stats; -}; - -struct devlink_trap_item { - const struct devlink_trap *trap; - struct devlink_trap_group_item *group_item; - struct list_head list; - enum devlink_trap_action action; - struct devlink_stats *stats; - void *priv; -}; - -struct gro_cell; - -struct gro_cells { - struct gro_cell *cells; -}; - -struct gro_cell { - struct sk_buff_head napi_skbs; - struct napi_struct napi; -}; - -enum __sk_action { - __SK_DROP = 0, - __SK_PASS = 1, - __SK_REDIRECT = 2, - __SK_NONE = 3, -}; - -enum sk_psock_state_bits { - SK_PSOCK_TX_ENABLED = 0, -}; - -struct sk_psock_link { - struct list_head list; - struct bpf_map *map; - void *link_raw; -}; - -struct bpf_stab { - struct bpf_map map; - struct sock **sks; - struct sk_psock_progs progs; - raw_spinlock_t lock; - long: 32; - long: 64; - long: 64; -}; - -typedef u64 (*btf_bpf_sock_map_update)(struct bpf_sock_ops_kern *, struct bpf_map *, void *, u64); - -typedef u64 (*btf_bpf_sk_redirect_map)(struct sk_buff *, struct bpf_map *, u32, u64); - -typedef u64 (*btf_bpf_msg_redirect_map)(struct sk_msg *, struct bpf_map *, u32, u64); - -struct sock_map_seq_info { - struct bpf_map *map; - struct sock *sk; - u32 index; -}; - -struct bpf_iter__sockmap { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_map *map; - }; - union { - void *key; - }; - union { - struct sock *sk; - }; -}; - -struct bpf_shtab_elem { - struct callback_head rcu; - u32 hash; - struct sock *sk; - struct hlist_node node; - u8 key[0]; -}; - -struct bpf_shtab_bucket { - struct hlist_head head; - raw_spinlock_t lock; -}; - -struct bpf_shtab { - struct bpf_map map; - struct bpf_shtab_bucket *buckets; - u32 buckets_num; - u32 elem_size; - struct sk_psock_progs progs; - atomic_t count; - long: 32; - long: 64; -}; - -typedef u64 (*btf_bpf_sock_hash_update)(struct bpf_sock_ops_kern *, struct bpf_map *, void *, u64); - -typedef u64 (*btf_bpf_sk_redirect_hash)(struct sk_buff *, struct bpf_map *, void *, u64); - -typedef u64 (*btf_bpf_msg_redirect_hash)(struct sk_msg *, struct bpf_map *, void *, u64); - -struct sock_hash_seq_info { - struct bpf_map *map; - struct bpf_shtab *htab; - u32 bucket_id; -}; - -enum { - SK_DIAG_BPF_STORAGE_REQ_NONE = 0, - SK_DIAG_BPF_STORAGE_REQ_MAP_FD = 1, - __SK_DIAG_BPF_STORAGE_REQ_MAX = 2, -}; - -enum { - SK_DIAG_BPF_STORAGE_REP_NONE = 0, - SK_DIAG_BPF_STORAGE = 1, - __SK_DIAG_BPF_STORAGE_REP_MAX = 2, -}; - -enum { - SK_DIAG_BPF_STORAGE_NONE = 0, - SK_DIAG_BPF_STORAGE_PAD = 1, - SK_DIAG_BPF_STORAGE_MAP_ID = 2, - SK_DIAG_BPF_STORAGE_MAP_VALUE = 3, - __SK_DIAG_BPF_STORAGE_MAX = 4, -}; - -typedef u64 (*btf_bpf_sk_storage_get)(struct bpf_map *, struct sock *, void *, u64); - -typedef u64 (*btf_bpf_sk_storage_delete)(struct bpf_map *, struct sock *); - -typedef u64 (*btf_bpf_sk_storage_get_tracing)(struct bpf_map *, struct sock *, void *, u64); - -typedef u64 (*btf_bpf_sk_storage_delete_tracing)(struct bpf_map *, struct sock *); - -struct bpf_sk_storage_diag { - u32 nr_maps; - struct bpf_map *maps[0]; -}; - -struct bpf_iter_seq_sk_storage_map_info { - struct bpf_map *map; - unsigned int bucket_id; - unsigned int skip_elems; -}; - -struct bpf_iter__bpf_sk_storage_map { - union { - struct bpf_iter_meta *meta; - }; - union { - struct bpf_map *map; - }; - union { - struct sock *sk; - }; - union { - void *value; - }; -}; - -struct compat_cmsghdr { - compat_size_t cmsg_len; - compat_int_t cmsg_level; - compat_int_t cmsg_type; -}; - -struct nvmem_cell___2; - -struct fch_hdr { - __u8 daddr[6]; - __u8 saddr[6]; -}; - -struct fcllc { - __u8 dsap; - __u8 ssap; - __u8 llc; - __u8 protid[3]; - __be16 ethertype; -}; - -enum macvlan_mode { - MACVLAN_MODE_PRIVATE = 1, - MACVLAN_MODE_VEPA = 2, - MACVLAN_MODE_BRIDGE = 4, - MACVLAN_MODE_PASSTHRU = 8, - MACVLAN_MODE_SOURCE = 16, -}; - -struct tc_ratespec { - unsigned char cell_log; - __u8 linklayer; - short unsigned int overhead; - short int cell_align; - short unsigned int mpu; - __u32 rate; -}; - -struct tc_prio_qopt { - int bands; - __u8 priomap[16]; -}; - -enum { - TCA_UNSPEC = 0, - TCA_KIND = 1, - TCA_OPTIONS = 2, - TCA_STATS = 3, - TCA_XSTATS = 4, - TCA_RATE = 5, - TCA_FCNT = 6, - TCA_STATS2 = 7, - TCA_STAB = 8, - TCA_PAD = 9, - TCA_DUMP_INVISIBLE = 10, - TCA_CHAIN = 11, - TCA_HW_OFFLOAD = 12, - TCA_INGRESS_BLOCK = 13, - TCA_EGRESS_BLOCK = 14, - TCA_DUMP_FLAGS = 15, - __TCA_MAX = 16, -}; - -struct vlan_pcpu_stats { - u64 rx_packets; - u64 rx_bytes; - u64 rx_multicast; - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; - u32 rx_errors; - u32 tx_dropped; -}; - -struct netpoll___2; - -struct skb_array { - struct ptr_ring ring; -}; - -struct macvlan_port; - -struct macvlan_dev { - struct net_device *dev; - struct list_head list; - struct hlist_node hlist; - struct macvlan_port *port; - struct net_device *lowerdev; - void *accel_priv; - struct vlan_pcpu_stats *pcpu_stats; - long unsigned int mc_filter[4]; - netdev_features_t set_features; - enum macvlan_mode mode; - u16 flags; - unsigned int macaddr_count; - u32 bc_queue_len_req; - struct netpoll___2 *netpoll; -}; - -struct psched_ratecfg { - u64 rate_bytes_ps; - u32 mult; - u16 overhead; - u8 linklayer; - u8 shift; -}; - -struct psched_pktrate { - u64 rate_pkts_ps; - u32 mult; - u8 shift; -}; - -struct mini_Qdisc_pair { - struct mini_Qdisc miniq1; - struct mini_Qdisc miniq2; - struct mini_Qdisc **p_miniq; -}; - -struct pfifo_fast_priv { - struct skb_array q[3]; -}; - -struct tc_qopt_offload_stats { - struct gnet_stats_basic_packed *bstats; - struct gnet_stats_queue *qstats; -}; - -enum tc_mq_command { - TC_MQ_CREATE = 0, - TC_MQ_DESTROY = 1, - TC_MQ_STATS = 2, - TC_MQ_GRAFT = 3, -}; - -struct tc_mq_opt_offload_graft_params { - long unsigned int queue; - u32 child_handle; -}; - -struct tc_mq_qopt_offload { - enum tc_mq_command command; - u32 handle; - union { - struct tc_qopt_offload_stats stats; - struct tc_mq_opt_offload_graft_params graft_params; - }; -}; - -struct mq_sched { - struct Qdisc **qdiscs; -}; - -struct sch_frag_data { - long unsigned int dst; - struct qdisc_skb_cb cb; - __be16 inner_protocol; - u16 vlan_tci; - __be16 vlan_proto; - unsigned int l2_len; - u8 l2_data[18]; - int (*xmit)(struct sk_buff *); -}; - -enum tc_link_layer { - TC_LINKLAYER_UNAWARE = 0, - TC_LINKLAYER_ETHERNET = 1, - TC_LINKLAYER_ATM = 2, -}; - -enum { - TCA_STAB_UNSPEC = 0, - TCA_STAB_BASE = 1, - TCA_STAB_DATA = 2, - __TCA_STAB_MAX = 3, -}; - -struct qdisc_rate_table { - struct tc_ratespec rate; - u32 data[256]; - struct qdisc_rate_table *next; - int refcnt; -}; - -struct Qdisc_class_common { - u32 classid; - struct hlist_node hnode; -}; - -struct Qdisc_class_hash { - struct hlist_head *hash; - unsigned int hashsize; - unsigned int hashmask; - unsigned int hashelems; -}; - -struct qdisc_watchdog { - u64 last_expires; - struct hrtimer timer; - struct Qdisc *qdisc; -}; - -enum tc_root_command { - TC_ROOT_GRAFT = 0, -}; - -struct tc_root_qopt_offload { - enum tc_root_command command; - u32 handle; - bool ingress; -}; - -struct check_loop_arg { - struct qdisc_walker w; - struct Qdisc *p; - int depth; -}; - -struct tcf_bind_args { - struct tcf_walker w; - long unsigned int base; - long unsigned int cl; - u32 classid; -}; - -struct tc_bind_class_args { - struct qdisc_walker w; - long unsigned int new_cl; - u32 portid; - u32 clid; -}; - -struct qdisc_dump_args { - struct qdisc_walker w; - struct sk_buff *skb; - struct netlink_callback *cb; -}; - -enum net_xmit_qdisc_t { - __NET_XMIT_STOLEN = 65536, - __NET_XMIT_BYPASS = 131072, -}; - -enum { - TCA_ACT_UNSPEC = 0, - TCA_ACT_KIND = 1, - TCA_ACT_OPTIONS = 2, - TCA_ACT_INDEX = 3, - TCA_ACT_STATS = 4, - TCA_ACT_PAD = 5, - TCA_ACT_COOKIE = 6, - TCA_ACT_FLAGS = 7, - TCA_ACT_HW_STATS = 8, - TCA_ACT_USED_HW_STATS = 9, - __TCA_ACT_MAX = 10, -}; - -enum tca_id { - TCA_ID_UNSPEC = 0, - TCA_ID_POLICE = 1, - TCA_ID_GACT = 5, - TCA_ID_IPT = 6, - TCA_ID_PEDIT = 7, - TCA_ID_MIRRED = 8, - TCA_ID_NAT = 9, - TCA_ID_XT = 10, - TCA_ID_SKBEDIT = 11, - TCA_ID_VLAN = 12, - TCA_ID_BPF = 13, - TCA_ID_CONNMARK = 14, - TCA_ID_SKBMOD = 15, - TCA_ID_CSUM = 16, - TCA_ID_TUNNEL_KEY = 17, - TCA_ID_SIMP = 22, - TCA_ID_IFE = 25, - TCA_ID_SAMPLE = 26, - TCA_ID_CTINFO = 27, - TCA_ID_MPLS = 28, - TCA_ID_CT = 29, - TCA_ID_GATE = 30, - __TCA_ID_MAX = 255, -}; - -struct tcf_t { - __u64 install; - __u64 lastuse; - __u64 expires; - __u64 firstuse; -}; - -struct psample_group { - struct list_head list; - struct net *net; - u32 group_num; - u32 refcount; - u32 seq; - struct callback_head rcu; -}; - -struct action_gate_entry { - u8 gate_state; - u32 interval; - s32 ipv; - s32 maxoctets; -}; - -enum qdisc_class_ops_flags { - QDISC_CLASS_OPS_DOIT_UNLOCKED = 1, -}; - -enum tcf_proto_ops_flags { - TCF_PROTO_OPS_DOIT_UNLOCKED = 1, -}; - -typedef void tcf_chain_head_change_t(struct tcf_proto *, void *); - -struct tcf_idrinfo { - struct mutex lock; - struct idr action_idr; - struct net *net; -}; - -struct tc_action_ops; - -struct tc_cookie; - -struct tc_action { - const struct tc_action_ops *ops; - __u32 type; - struct tcf_idrinfo *idrinfo; - u32 tcfa_index; - refcount_t tcfa_refcnt; - atomic_t tcfa_bindcnt; - int tcfa_action; - struct tcf_t tcfa_tm; - struct gnet_stats_basic_packed tcfa_bstats; - struct gnet_stats_basic_packed tcfa_bstats_hw; - struct gnet_stats_queue tcfa_qstats; - struct net_rate_estimator *tcfa_rate_est; - spinlock_t tcfa_lock; - struct gnet_stats_basic_cpu *cpu_bstats; - struct gnet_stats_basic_cpu *cpu_bstats_hw; - struct gnet_stats_queue *cpu_qstats; - struct tc_cookie *act_cookie; - struct tcf_chain *goto_chain; - u32 tcfa_flags; - u8 hw_stats; - u8 used_hw_stats; - bool used_hw_stats_valid; -}; - -typedef void (*tc_action_priv_destructor)(void *); - -struct tc_action_ops { - struct list_head head; - char kind[16]; - enum tca_id id; - size_t size; - struct module *owner; - int (*act)(struct sk_buff *, const struct tc_action *, struct tcf_result *); - int (*dump)(struct sk_buff *, struct tc_action *, int, int); - void (*cleanup)(struct tc_action *); - int (*lookup)(struct net *, struct tc_action **, u32); - int (*init)(struct net *, struct nlattr *, struct nlattr *, struct tc_action **, int, int, bool, struct tcf_proto *, u32, struct netlink_ext_ack *); - int (*walk)(struct net *, struct sk_buff *, struct netlink_callback *, int, const struct tc_action_ops *, struct netlink_ext_ack *); - void (*stats_update)(struct tc_action *, u64, u64, u64, u64, bool); - size_t (*get_fill_size)(const struct tc_action *); - struct net_device * (*get_dev)(const struct tc_action *, tc_action_priv_destructor *); - struct psample_group * (*get_psample_group)(const struct tc_action *, tc_action_priv_destructor *); -}; - -struct tc_cookie { - u8 *data; - u32 len; - struct callback_head rcu; -}; - -struct tcf_block_ext_info { - enum flow_block_binder_type binder_type; - tcf_chain_head_change_t *chain_head_change; - void *chain_head_change_priv; - u32 block_index; -}; - -struct tcf_qevent { - struct tcf_block *block; - struct tcf_block_ext_info info; - struct tcf_proto *filter_chain; -}; - -struct tcf_exts { - __u32 type; - int nr_actions; - struct tc_action **actions; - struct net *net; - int action; - int police; -}; - -enum pedit_header_type { - TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK = 0, - TCA_PEDIT_KEY_EX_HDR_TYPE_ETH = 1, - TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 = 2, - TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 = 3, - TCA_PEDIT_KEY_EX_HDR_TYPE_TCP = 4, - TCA_PEDIT_KEY_EX_HDR_TYPE_UDP = 5, - __PEDIT_HDR_TYPE_MAX = 6, -}; - -enum pedit_cmd { - TCA_PEDIT_KEY_EX_CMD_SET = 0, - TCA_PEDIT_KEY_EX_CMD_ADD = 1, - __PEDIT_CMD_MAX = 2, -}; - -struct tc_pedit_key { - __u32 mask; - __u32 val; - __u32 off; - __u32 at; - __u32 offmask; - __u32 shift; -}; - -struct tcf_pedit_key_ex { - enum pedit_header_type htype; - enum pedit_cmd cmd; -}; - -struct tcf_pedit { - struct tc_action common; - unsigned char tcfp_nkeys; - unsigned char tcfp_flags; - struct tc_pedit_key *tcfp_keys; - struct tcf_pedit_key_ex *tcfp_keys_ex; -}; - -struct tcf_mirred { - struct tc_action common; - int tcfm_eaction; - bool tcfm_mac_header_xmit; - struct net_device *tcfm_dev; - struct list_head tcfm_list; -}; - -struct tcf_vlan_params { - int tcfv_action; - unsigned char tcfv_push_dst[6]; - unsigned char tcfv_push_src[6]; - u16 tcfv_push_vid; - __be16 tcfv_push_proto; - u8 tcfv_push_prio; - bool tcfv_push_prio_exists; - struct callback_head rcu; -}; - -struct tcf_vlan { - struct tc_action common; - struct tcf_vlan_params *vlan_p; -}; - -struct tcf_tunnel_key_params { - struct callback_head rcu; - int tcft_action; - struct metadata_dst *tcft_enc_metadata; -}; - -struct tcf_tunnel_key { - struct tc_action common; - struct tcf_tunnel_key_params *params; -}; - -struct tcf_csum_params { - u32 update_flags; - struct callback_head rcu; -}; - -struct tcf_csum { - struct tc_action common; - struct tcf_csum_params *params; -}; - -struct tcf_gact { - struct tc_action common; - u16 tcfg_ptype; - u16 tcfg_pval; - int tcfg_paction; - atomic_t packets; -}; - -struct tcf_police_params { - int tcfp_result; - u32 tcfp_ewma_rate; - s64 tcfp_burst; - u32 tcfp_mtu; - s64 tcfp_mtu_ptoks; - s64 tcfp_pkt_burst; - struct psched_ratecfg rate; - bool rate_present; - struct psched_ratecfg peak; - bool peak_present; - struct psched_pktrate ppsrate; - bool pps_present; - struct callback_head rcu; -}; - -struct tcf_police { - struct tc_action common; - struct tcf_police_params *params; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - spinlock_t tcfp_lock; - s64 tcfp_toks; - s64 tcfp_ptoks; - s64 tcfp_pkttoks; - s64 tcfp_t_c; - long: 64; - long: 64; - long: 64; -}; - -struct tcf_sample { - struct tc_action common; - u32 rate; - bool truncate; - u32 trunc_size; - struct psample_group *psample_group; - u32 psample_group_num; - struct list_head tcfm_list; -}; - -struct tcf_skbedit_params { - u32 flags; - u32 priority; - u32 mark; - u32 mask; - u16 queue_mapping; - u16 ptype; - struct callback_head rcu; -}; - -struct tcf_skbedit { - struct tc_action common; - struct tcf_skbedit_params *params; -}; - -struct nf_nat_range2 { - unsigned int flags; - union nf_inet_addr min_addr; - union nf_inet_addr max_addr; - union nf_conntrack_man_proto min_proto; - union nf_conntrack_man_proto max_proto; - union nf_conntrack_man_proto base_proto; -}; - -struct tcf_ct_flow_table; - -struct tcf_ct_params { - struct nf_conn *tmpl; - u16 zone; - u32 mark; - u32 mark_mask; - u32 labels[4]; - u32 labels_mask[4]; - struct nf_nat_range2 range; - bool ipv4_range; - u16 ct_action; - struct callback_head rcu; - struct tcf_ct_flow_table *ct_ft; - struct nf_flowtable *nf_ft; -}; - -struct tcf_ct { - struct tc_action common; - struct tcf_ct_params *params; -}; - -struct tcf_mpls_params { - int tcfm_action; - u32 tcfm_label; - u8 tcfm_tc; - u8 tcfm_ttl; - u8 tcfm_bos; - __be16 tcfm_proto; - struct callback_head rcu; -}; - -struct tcf_mpls { - struct tc_action common; - struct tcf_mpls_params *mpls_p; -}; - -struct tcfg_gate_entry { - int index; - u8 gate_state; - u32 interval; - s32 ipv; - s32 maxoctets; - struct list_head list; -}; - -struct tcf_gate_params { - s32 tcfg_priority; - u64 tcfg_basetime; - u64 tcfg_cycletime; - u64 tcfg_cycletime_ext; - u32 tcfg_flags; - s32 tcfg_clockid; - size_t num_entries; - struct list_head entries; -}; - -struct tcf_gate { - struct tc_action common; - struct tcf_gate_params param; - u8 current_gate_status; - ktime_t current_close_time; - u32 current_entry_octets; - s32 current_max_octets; - struct tcfg_gate_entry *next_entry; - struct hrtimer hitimer; - enum tk_offsets tk_offset; -}; - -struct tcf_filter_chain_list_item { - struct list_head list; - tcf_chain_head_change_t *chain_head_change; - void *chain_head_change_priv; -}; - -struct tcf_net { - spinlock_t idr_lock; - struct idr idr; -}; - -struct tcf_block_owner_item { - struct list_head list; - struct Qdisc *q; - enum flow_block_binder_type binder_type; -}; - -struct tcf_chain_info { - struct tcf_proto **pprev; - struct tcf_proto *next; -}; - -struct tcf_dump_args { - struct tcf_walker w; - struct sk_buff *skb; - struct netlink_callback *cb; - struct tcf_block *block; - struct Qdisc *q; - u32 parent; - bool terse_dump; -}; - -struct tcamsg { - unsigned char tca_family; - unsigned char tca__pad1; - short unsigned int tca__pad2; -}; - -enum { - TCA_ROOT_UNSPEC = 0, - TCA_ROOT_TAB = 1, - TCA_ROOT_FLAGS = 2, - TCA_ROOT_COUNT = 3, - TCA_ROOT_TIME_DELTA = 4, - __TCA_ROOT_MAX = 5, -}; - -struct tc_action_net { - struct tcf_idrinfo *idrinfo; - const struct tc_action_ops *ops; -}; - -struct tc_fifo_qopt { - __u32 limit; -}; - -enum tc_fifo_command { - TC_FIFO_REPLACE = 0, - TC_FIFO_DESTROY = 1, - TC_FIFO_STATS = 2, -}; - -struct tc_fifo_qopt_offload { - enum tc_fifo_command command; - u32 handle; - u32 parent; - union { - struct tc_qopt_offload_stats stats; - }; -}; - -enum { - TCA_FQ_CODEL_UNSPEC = 0, - TCA_FQ_CODEL_TARGET = 1, - TCA_FQ_CODEL_LIMIT = 2, - TCA_FQ_CODEL_INTERVAL = 3, - TCA_FQ_CODEL_ECN = 4, - TCA_FQ_CODEL_FLOWS = 5, - TCA_FQ_CODEL_QUANTUM = 6, - TCA_FQ_CODEL_CE_THRESHOLD = 7, - TCA_FQ_CODEL_DROP_BATCH_SIZE = 8, - TCA_FQ_CODEL_MEMORY_LIMIT = 9, - __TCA_FQ_CODEL_MAX = 10, -}; - -enum { - TCA_FQ_CODEL_XSTATS_QDISC = 0, - TCA_FQ_CODEL_XSTATS_CLASS = 1, -}; - -struct tc_fq_codel_qd_stats { - __u32 maxpacket; - __u32 drop_overlimit; - __u32 ecn_mark; - __u32 new_flow_count; - __u32 new_flows_len; - __u32 old_flows_len; - __u32 ce_mark; - __u32 memory_usage; - __u32 drop_overmemory; -}; - -struct tc_fq_codel_cl_stats { - __s32 deficit; - __u32 ldelay; - __u32 count; - __u32 lastcount; - __u32 dropping; - __s32 drop_next; -}; - -struct tc_fq_codel_xstats { - __u32 type; - union { - struct tc_fq_codel_qd_stats qdisc_stats; - struct tc_fq_codel_cl_stats class_stats; - }; -}; - -typedef u32 codel_time_t; - -typedef s32 codel_tdiff_t; - -struct codel_params { - codel_time_t target; - codel_time_t ce_threshold; - codel_time_t interval; - u32 mtu; - bool ecn; -}; - -struct codel_vars { - u32 count; - u32 lastcount; - bool dropping; - u16 rec_inv_sqrt; - codel_time_t first_above_time; - codel_time_t drop_next; - codel_time_t ldelay; -}; - -struct codel_stats { - u32 maxpacket; - u32 drop_count; - u32 drop_len; - u32 ecn_mark; - u32 ce_mark; -}; - -typedef u32 (*codel_skb_len_t)(const struct sk_buff *); - -typedef codel_time_t (*codel_skb_time_t)(const struct sk_buff *); - -typedef void (*codel_skb_drop_t)(struct sk_buff *, void *); - -typedef struct sk_buff * (*codel_skb_dequeue_t)(struct codel_vars *, void *); - -struct codel_skb_cb { - codel_time_t enqueue_time; - unsigned int mem_usage; -}; - -struct fq_codel_flow { - struct sk_buff *head; - struct sk_buff *tail; - struct list_head flowchain; - int deficit; - struct codel_vars cvars; -}; - -struct fq_codel_sched_data { - struct tcf_proto *filter_list; - struct tcf_block *block; - struct fq_codel_flow *flows; - u32 *backlogs; - u32 flows_cnt; - u32 quantum; - u32 drop_batch_size; - u32 memory_limit; - struct codel_params cparams; - struct codel_stats cstats; - u32 memory_usage; - u32 drop_overmemory; - u32 drop_overlimit; - u32 new_flow_count; - struct list_head new_flows; - struct list_head old_flows; -}; - -struct tcf_ematch_tree_hdr { - __u16 nmatches; - __u16 progid; -}; - -enum { - TCA_EMATCH_TREE_UNSPEC = 0, - TCA_EMATCH_TREE_HDR = 1, - TCA_EMATCH_TREE_LIST = 2, - __TCA_EMATCH_TREE_MAX = 3, -}; - -struct tcf_ematch_hdr { - __u16 matchid; - __u16 kind; - __u16 flags; - __u16 pad; -}; - -struct tcf_pkt_info { - unsigned char *ptr; - int nexthdr; -}; - -struct tcf_ematch_ops; - -struct tcf_ematch { - struct tcf_ematch_ops *ops; - long unsigned int data; - unsigned int datalen; - u16 matchid; - u16 flags; - struct net *net; -}; - -struct tcf_ematch_ops { - int kind; - int datalen; - int (*change)(struct net *, void *, int, struct tcf_ematch *); - int (*match)(struct sk_buff *, struct tcf_ematch *, struct tcf_pkt_info *); - void (*destroy)(struct tcf_ematch *); - int (*dump)(struct sk_buff *, struct tcf_ematch *); - struct module *owner; - struct list_head link; -}; - -struct tcf_ematch_tree { - struct tcf_ematch_tree_hdr hdr; - struct tcf_ematch *matches; -}; - -struct sockaddr_nl { - __kernel_sa_family_t nl_family; - short unsigned int nl_pad; - __u32 nl_pid; - __u32 nl_groups; -}; - -struct nlmsgerr { - int error; - struct nlmsghdr msg; -}; - -enum nlmsgerr_attrs { - NLMSGERR_ATTR_UNUSED = 0, - NLMSGERR_ATTR_MSG = 1, - NLMSGERR_ATTR_OFFS = 2, - NLMSGERR_ATTR_COOKIE = 3, - NLMSGERR_ATTR_POLICY = 4, - __NLMSGERR_ATTR_MAX = 5, - NLMSGERR_ATTR_MAX = 4, -}; - -struct nl_pktinfo { - __u32 group; -}; - -enum { - NETLINK_UNCONNECTED = 0, - NETLINK_CONNECTED = 1, -}; - -enum netlink_skb_flags { - NETLINK_SKB_DST = 8, -}; - -struct netlink_notify { - struct net *net; - u32 portid; - int protocol; -}; - -struct netlink_tap { - struct net_device *dev; - struct module *module; - struct list_head list; -}; - -struct trace_event_raw_netlink_extack { - struct trace_entry ent; - u32 __data_loc_msg; - char __data[0]; -}; - -struct trace_event_data_offsets_netlink_extack { - u32 msg; -}; - -typedef void (*btf_trace_netlink_extack)(void *, const char *); - -struct netlink_sock { - struct sock sk; - u32 portid; - u32 dst_portid; - u32 dst_group; - u32 flags; - u32 subscriptions; - u32 ngroups; - long unsigned int *groups; - long unsigned int state; - size_t max_recvmsg_len; - wait_queue_head_t wait; - bool bound; - bool cb_running; - int dump_done_errno; - struct netlink_callback cb; - struct mutex *cb_mutex; - struct mutex cb_def_mutex; - void (*netlink_rcv)(struct sk_buff *); - int (*netlink_bind)(struct net *, int); - void (*netlink_unbind)(struct net *, int); - struct module *module; - struct rhash_head node; - struct callback_head rcu; - struct work_struct work; -}; - -struct listeners; - -struct netlink_table { - struct rhashtable hash; - struct hlist_head mc_list; - struct listeners *listeners; - unsigned int flags; - unsigned int groups; - struct mutex *cb_mutex; - struct module *module; - int (*bind)(struct net *, int); - void (*unbind)(struct net *, int); - bool (*compare)(struct net *, struct sock *); - int registered; -}; - -struct listeners { - struct callback_head rcu; - long unsigned int masks[0]; -}; - -struct netlink_tap_net { - struct list_head netlink_tap_all; - struct mutex netlink_tap_lock; -}; - -struct netlink_compare_arg { - possible_net_t pnet; - u32 portid; -}; - -struct netlink_broadcast_data { - struct sock *exclude_sk; - struct net *net; - u32 portid; - u32 group; - int failure; - int delivery_failure; - int congested; - int delivered; - gfp_t allocation; - struct sk_buff *skb; - struct sk_buff *skb2; - int (*tx_filter)(struct sock *, struct sk_buff *, void *); - void *tx_data; -}; - -struct netlink_set_err_data { - struct sock *exclude_sk; - u32 portid; - u32 group; - int code; -}; - -struct nl_seq_iter { - struct seq_net_private p; - struct rhashtable_iter hti; - int link; -}; - -struct bpf_iter__netlink { - union { - struct bpf_iter_meta *meta; - }; - union { - struct netlink_sock *sk; - }; -}; - -enum { - CTRL_CMD_UNSPEC = 0, - CTRL_CMD_NEWFAMILY = 1, - CTRL_CMD_DELFAMILY = 2, - CTRL_CMD_GETFAMILY = 3, - CTRL_CMD_NEWOPS = 4, - CTRL_CMD_DELOPS = 5, - CTRL_CMD_GETOPS = 6, - CTRL_CMD_NEWMCAST_GRP = 7, - CTRL_CMD_DELMCAST_GRP = 8, - CTRL_CMD_GETMCAST_GRP = 9, - CTRL_CMD_GETPOLICY = 10, - __CTRL_CMD_MAX = 11, -}; - -enum { - CTRL_ATTR_UNSPEC = 0, - CTRL_ATTR_FAMILY_ID = 1, - CTRL_ATTR_FAMILY_NAME = 2, - CTRL_ATTR_VERSION = 3, - CTRL_ATTR_HDRSIZE = 4, - CTRL_ATTR_MAXATTR = 5, - CTRL_ATTR_OPS = 6, - CTRL_ATTR_MCAST_GROUPS = 7, - CTRL_ATTR_POLICY = 8, - CTRL_ATTR_OP_POLICY = 9, - CTRL_ATTR_OP = 10, - __CTRL_ATTR_MAX = 11, -}; - -enum { - CTRL_ATTR_OP_UNSPEC = 0, - CTRL_ATTR_OP_ID = 1, - CTRL_ATTR_OP_FLAGS = 2, - __CTRL_ATTR_OP_MAX = 3, -}; - -enum { - CTRL_ATTR_MCAST_GRP_UNSPEC = 0, - CTRL_ATTR_MCAST_GRP_NAME = 1, - CTRL_ATTR_MCAST_GRP_ID = 2, - __CTRL_ATTR_MCAST_GRP_MAX = 3, -}; - -enum { - CTRL_ATTR_POLICY_UNSPEC = 0, - CTRL_ATTR_POLICY_DO = 1, - CTRL_ATTR_POLICY_DUMP = 2, - __CTRL_ATTR_POLICY_DUMP_MAX = 3, - CTRL_ATTR_POLICY_DUMP_MAX = 2, -}; - -struct genl_start_context { - const struct genl_family *family; - struct nlmsghdr *nlh; - struct netlink_ext_ack *extack; - const struct genl_ops *ops; - int hdrlen; -}; - -struct netlink_policy_dump_state; - -struct ctrl_dump_policy_ctx { - struct netlink_policy_dump_state *state; - const struct genl_family *rt; - unsigned int opidx; - u32 op; - u16 fam_id; - u8 policies: 1; - u8 single_op: 1; -}; - -enum netlink_attribute_type { - NL_ATTR_TYPE_INVALID = 0, - NL_ATTR_TYPE_FLAG = 1, - NL_ATTR_TYPE_U8 = 2, - NL_ATTR_TYPE_U16 = 3, - NL_ATTR_TYPE_U32 = 4, - NL_ATTR_TYPE_U64 = 5, - NL_ATTR_TYPE_S8 = 6, - NL_ATTR_TYPE_S16 = 7, - NL_ATTR_TYPE_S32 = 8, - NL_ATTR_TYPE_S64 = 9, - NL_ATTR_TYPE_BINARY = 10, - NL_ATTR_TYPE_STRING = 11, - NL_ATTR_TYPE_NUL_STRING = 12, - NL_ATTR_TYPE_NESTED = 13, - NL_ATTR_TYPE_NESTED_ARRAY = 14, - NL_ATTR_TYPE_BITFIELD32 = 15, -}; - -enum netlink_policy_type_attr { - NL_POLICY_TYPE_ATTR_UNSPEC = 0, - NL_POLICY_TYPE_ATTR_TYPE = 1, - NL_POLICY_TYPE_ATTR_MIN_VALUE_S = 2, - NL_POLICY_TYPE_ATTR_MAX_VALUE_S = 3, - NL_POLICY_TYPE_ATTR_MIN_VALUE_U = 4, - NL_POLICY_TYPE_ATTR_MAX_VALUE_U = 5, - NL_POLICY_TYPE_ATTR_MIN_LENGTH = 6, - NL_POLICY_TYPE_ATTR_MAX_LENGTH = 7, - NL_POLICY_TYPE_ATTR_POLICY_IDX = 8, - NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE = 9, - NL_POLICY_TYPE_ATTR_BITFIELD32_MASK = 10, - NL_POLICY_TYPE_ATTR_PAD = 11, - NL_POLICY_TYPE_ATTR_MASK = 12, - __NL_POLICY_TYPE_ATTR_MAX = 13, - NL_POLICY_TYPE_ATTR_MAX = 12, -}; - -struct netlink_policy_dump_state___2 { - unsigned int policy_idx; - unsigned int attr_idx; - unsigned int n_alloc; - struct { - const struct nla_policy *policy; - unsigned int maxtype; - } policies[0]; -}; - -struct trace_event_raw_bpf_test_finish { - struct trace_entry ent; - int err; - char __data[0]; -}; - -struct trace_event_data_offsets_bpf_test_finish {}; - -typedef void (*btf_trace_bpf_test_finish)(void *, int *); - -struct bpf_test_timer { - enum { - NO_PREEMPT = 0, - NO_MIGRATE = 1, - } mode; - u32 i; - u64 time_start; - u64 time_spent; -}; - -struct bpf_fentry_test_t { - struct bpf_fentry_test_t *a; -}; - -struct bpf_raw_tp_test_run_info { - struct bpf_prog *prog; - void *ctx; - u32 retval; -}; - -struct ethtool_cmd { - __u32 cmd; - __u32 supported; - __u32 advertising; - __u16 speed; - __u8 duplex; - __u8 port; - __u8 phy_address; - __u8 transceiver; - __u8 autoneg; - __u8 mdio_support; - __u32 maxtxpkt; - __u32 maxrxpkt; - __u16 speed_hi; - __u8 eth_tp_mdix; - __u8 eth_tp_mdix_ctrl; - __u32 lp_advertising; - __u32 reserved[2]; -}; - -struct ethtool_value { - __u32 cmd; - __u32 data; -}; - -enum tunable_id { - ETHTOOL_ID_UNSPEC = 0, - ETHTOOL_RX_COPYBREAK = 1, - ETHTOOL_TX_COPYBREAK = 2, - ETHTOOL_PFC_PREVENTION_TOUT = 3, - __ETHTOOL_TUNABLE_COUNT = 4, -}; - -enum tunable_type_id { - ETHTOOL_TUNABLE_UNSPEC = 0, - ETHTOOL_TUNABLE_U8 = 1, - ETHTOOL_TUNABLE_U16 = 2, - ETHTOOL_TUNABLE_U32 = 3, - ETHTOOL_TUNABLE_U64 = 4, - ETHTOOL_TUNABLE_STRING = 5, - ETHTOOL_TUNABLE_S8 = 6, - ETHTOOL_TUNABLE_S16 = 7, - ETHTOOL_TUNABLE_S32 = 8, - ETHTOOL_TUNABLE_S64 = 9, -}; - -enum phy_tunable_id { - ETHTOOL_PHY_ID_UNSPEC = 0, - ETHTOOL_PHY_DOWNSHIFT = 1, - ETHTOOL_PHY_FAST_LINK_DOWN = 2, - ETHTOOL_PHY_EDPD = 3, - __ETHTOOL_PHY_TUNABLE_COUNT = 4, -}; - -enum ethtool_stringset { - ETH_SS_TEST = 0, - ETH_SS_STATS = 1, - ETH_SS_PRIV_FLAGS = 2, - ETH_SS_NTUPLE_FILTERS = 3, - ETH_SS_FEATURES = 4, - ETH_SS_RSS_HASH_FUNCS = 5, - ETH_SS_TUNABLES = 6, - ETH_SS_PHY_STATS = 7, - ETH_SS_PHY_TUNABLES = 8, - ETH_SS_LINK_MODES = 9, - ETH_SS_MSG_CLASSES = 10, - ETH_SS_WOL_MODES = 11, - ETH_SS_SOF_TIMESTAMPING = 12, - ETH_SS_TS_TX_TYPES = 13, - ETH_SS_TS_RX_FILTERS = 14, - ETH_SS_UDP_TUNNEL_TYPES = 15, - ETH_SS_STATS_STD = 16, - ETH_SS_STATS_ETH_PHY = 17, - ETH_SS_STATS_ETH_MAC = 18, - ETH_SS_STATS_ETH_CTRL = 19, - ETH_SS_STATS_RMON = 20, - ETH_SS_COUNT = 21, -}; - -struct ethtool_gstrings { - __u32 cmd; - __u32 string_set; - __u32 len; - __u8 data[0]; -}; - -struct ethtool_sset_info { - __u32 cmd; - __u32 reserved; - __u64 sset_mask; - __u32 data[0]; -}; - -struct ethtool_perm_addr { - __u32 cmd; - __u32 size; - __u8 data[0]; -}; - -enum ethtool_flags { - ETH_FLAG_TXVLAN = 128, - ETH_FLAG_RXVLAN = 256, - ETH_FLAG_LRO = 32768, - ETH_FLAG_NTUPLE = 134217728, - ETH_FLAG_RXHASH = 268435456, -}; - -struct ethtool_rxfh { - __u32 cmd; - __u32 rss_context; - __u32 indir_size; - __u32 key_size; - __u8 hfunc; - __u8 rsvd8[3]; - __u32 rsvd32; - __u32 rss_config[0]; -}; - -struct ethtool_get_features_block { - __u32 available; - __u32 requested; - __u32 active; - __u32 never_changed; -}; - -struct ethtool_gfeatures { - __u32 cmd; - __u32 size; - struct ethtool_get_features_block features[0]; -}; - -struct ethtool_set_features_block { - __u32 valid; - __u32 requested; -}; - -struct ethtool_sfeatures { - __u32 cmd; - __u32 size; - struct ethtool_set_features_block features[0]; -}; - -enum ethtool_sfeatures_retval_bits { - ETHTOOL_F_UNSUPPORTED__BIT = 0, - ETHTOOL_F_WISH__BIT = 1, - ETHTOOL_F_COMPAT__BIT = 2, -}; - -struct ethtool_per_queue_op { - __u32 cmd; - __u32 sub_command; - __u32 queue_mask[128]; - char data[0]; -}; - -enum ethtool_fec_config_bits { - ETHTOOL_FEC_NONE_BIT = 0, - ETHTOOL_FEC_AUTO_BIT = 1, - ETHTOOL_FEC_OFF_BIT = 2, - ETHTOOL_FEC_RS_BIT = 3, - ETHTOOL_FEC_BASER_BIT = 4, - ETHTOOL_FEC_LLRS_BIT = 5, -}; - -enum { - ETH_RSS_HASH_TOP_BIT = 0, - ETH_RSS_HASH_XOR_BIT = 1, - ETH_RSS_HASH_CRC32_BIT = 2, - ETH_RSS_HASH_FUNCS_COUNT = 3, -}; - -struct ethtool_rx_flow_rule { - struct flow_rule *rule; - long unsigned int priv[0]; -}; - -struct ethtool_rx_flow_spec_input { - const struct ethtool_rx_flow_spec *fs; - u32 rss_ctx; -}; - -struct ethtool_phy_ops { - int (*get_sset_count)(struct phy_device *); - int (*get_strings)(struct phy_device *, u8 *); - int (*get_stats)(struct phy_device *, struct ethtool_stats *, u64 *); - int (*start_cable_test)(struct phy_device *, struct netlink_ext_ack *); - int (*start_cable_test_tdr)(struct phy_device *, struct netlink_ext_ack *, const struct phy_tdr_config *); -}; - -enum { - ETHTOOL_MSG_KERNEL_NONE = 0, - ETHTOOL_MSG_STRSET_GET_REPLY = 1, - ETHTOOL_MSG_LINKINFO_GET_REPLY = 2, - ETHTOOL_MSG_LINKINFO_NTF = 3, - ETHTOOL_MSG_LINKMODES_GET_REPLY = 4, - ETHTOOL_MSG_LINKMODES_NTF = 5, - ETHTOOL_MSG_LINKSTATE_GET_REPLY = 6, - ETHTOOL_MSG_DEBUG_GET_REPLY = 7, - ETHTOOL_MSG_DEBUG_NTF = 8, - ETHTOOL_MSG_WOL_GET_REPLY = 9, - ETHTOOL_MSG_WOL_NTF = 10, - ETHTOOL_MSG_FEATURES_GET_REPLY = 11, - ETHTOOL_MSG_FEATURES_SET_REPLY = 12, - ETHTOOL_MSG_FEATURES_NTF = 13, - ETHTOOL_MSG_PRIVFLAGS_GET_REPLY = 14, - ETHTOOL_MSG_PRIVFLAGS_NTF = 15, - ETHTOOL_MSG_RINGS_GET_REPLY = 16, - ETHTOOL_MSG_RINGS_NTF = 17, - ETHTOOL_MSG_CHANNELS_GET_REPLY = 18, - ETHTOOL_MSG_CHANNELS_NTF = 19, - ETHTOOL_MSG_COALESCE_GET_REPLY = 20, - ETHTOOL_MSG_COALESCE_NTF = 21, - ETHTOOL_MSG_PAUSE_GET_REPLY = 22, - ETHTOOL_MSG_PAUSE_NTF = 23, - ETHTOOL_MSG_EEE_GET_REPLY = 24, - ETHTOOL_MSG_EEE_NTF = 25, - ETHTOOL_MSG_TSINFO_GET_REPLY = 26, - ETHTOOL_MSG_CABLE_TEST_NTF = 27, - ETHTOOL_MSG_CABLE_TEST_TDR_NTF = 28, - ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY = 29, - ETHTOOL_MSG_FEC_GET_REPLY = 30, - ETHTOOL_MSG_FEC_NTF = 31, - ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY = 32, - ETHTOOL_MSG_STATS_GET_REPLY = 33, - ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY = 34, - __ETHTOOL_MSG_KERNEL_CNT = 35, - ETHTOOL_MSG_KERNEL_MAX = 34, -}; - -enum { - ETHTOOL_A_STATS_UNSPEC = 0, - ETHTOOL_A_STATS_PAD = 1, - ETHTOOL_A_STATS_HEADER = 2, - ETHTOOL_A_STATS_GROUPS = 3, - ETHTOOL_A_STATS_GRP = 4, - __ETHTOOL_A_STATS_CNT = 5, - ETHTOOL_A_STATS_MAX = 4, -}; - -struct ethtool_link_usettings { - struct ethtool_link_settings base; - struct { - __u32 supported[3]; - __u32 advertising[3]; - __u32 lp_advertising[3]; - } link_modes; -}; - -struct ethtool_rx_flow_key { - struct flow_dissector_key_basic basic; - union { - struct flow_dissector_key_ipv4_addrs ipv4; - struct flow_dissector_key_ipv6_addrs ipv6; - }; - struct flow_dissector_key_ports tp; - struct flow_dissector_key_ip ip; - struct flow_dissector_key_vlan vlan; - struct flow_dissector_key_eth_addrs eth_addrs; - long: 48; -}; - -struct ethtool_rx_flow_match { - struct flow_dissector dissector; - int: 32; - struct ethtool_rx_flow_key key; - struct ethtool_rx_flow_key mask; -}; - -enum { - ETHTOOL_UDP_TUNNEL_TYPE_VXLAN = 0, - ETHTOOL_UDP_TUNNEL_TYPE_GENEVE = 1, - ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE = 2, - __ETHTOOL_UDP_TUNNEL_TYPE_CNT = 3, -}; - -struct link_mode_info { - int speed; - u8 lanes; - u8 duplex; -}; - -enum { - ETHTOOL_MSG_USER_NONE = 0, - ETHTOOL_MSG_STRSET_GET = 1, - ETHTOOL_MSG_LINKINFO_GET = 2, - ETHTOOL_MSG_LINKINFO_SET = 3, - ETHTOOL_MSG_LINKMODES_GET = 4, - ETHTOOL_MSG_LINKMODES_SET = 5, - ETHTOOL_MSG_LINKSTATE_GET = 6, - ETHTOOL_MSG_DEBUG_GET = 7, - ETHTOOL_MSG_DEBUG_SET = 8, - ETHTOOL_MSG_WOL_GET = 9, - ETHTOOL_MSG_WOL_SET = 10, - ETHTOOL_MSG_FEATURES_GET = 11, - ETHTOOL_MSG_FEATURES_SET = 12, - ETHTOOL_MSG_PRIVFLAGS_GET = 13, - ETHTOOL_MSG_PRIVFLAGS_SET = 14, - ETHTOOL_MSG_RINGS_GET = 15, - ETHTOOL_MSG_RINGS_SET = 16, - ETHTOOL_MSG_CHANNELS_GET = 17, - ETHTOOL_MSG_CHANNELS_SET = 18, - ETHTOOL_MSG_COALESCE_GET = 19, - ETHTOOL_MSG_COALESCE_SET = 20, - ETHTOOL_MSG_PAUSE_GET = 21, - ETHTOOL_MSG_PAUSE_SET = 22, - ETHTOOL_MSG_EEE_GET = 23, - ETHTOOL_MSG_EEE_SET = 24, - ETHTOOL_MSG_TSINFO_GET = 25, - ETHTOOL_MSG_CABLE_TEST_ACT = 26, - ETHTOOL_MSG_CABLE_TEST_TDR_ACT = 27, - ETHTOOL_MSG_TUNNEL_INFO_GET = 28, - ETHTOOL_MSG_FEC_GET = 29, - ETHTOOL_MSG_FEC_SET = 30, - ETHTOOL_MSG_MODULE_EEPROM_GET = 31, - ETHTOOL_MSG_STATS_GET = 32, - ETHTOOL_MSG_PHC_VCLOCKS_GET = 33, - __ETHTOOL_MSG_USER_CNT = 34, - ETHTOOL_MSG_USER_MAX = 33, -}; - -enum { - ETHTOOL_A_HEADER_UNSPEC = 0, - ETHTOOL_A_HEADER_DEV_INDEX = 1, - ETHTOOL_A_HEADER_DEV_NAME = 2, - ETHTOOL_A_HEADER_FLAGS = 3, - __ETHTOOL_A_HEADER_CNT = 4, - ETHTOOL_A_HEADER_MAX = 3, -}; - -enum { - ETHTOOL_A_STRSET_UNSPEC = 0, - ETHTOOL_A_STRSET_HEADER = 1, - ETHTOOL_A_STRSET_STRINGSETS = 2, - ETHTOOL_A_STRSET_COUNTS_ONLY = 3, - __ETHTOOL_A_STRSET_CNT = 4, - ETHTOOL_A_STRSET_MAX = 3, -}; - -enum { - ETHTOOL_A_LINKINFO_UNSPEC = 0, - ETHTOOL_A_LINKINFO_HEADER = 1, - ETHTOOL_A_LINKINFO_PORT = 2, - ETHTOOL_A_LINKINFO_PHYADDR = 3, - ETHTOOL_A_LINKINFO_TP_MDIX = 4, - ETHTOOL_A_LINKINFO_TP_MDIX_CTRL = 5, - ETHTOOL_A_LINKINFO_TRANSCEIVER = 6, - __ETHTOOL_A_LINKINFO_CNT = 7, - ETHTOOL_A_LINKINFO_MAX = 6, -}; - -enum { - ETHTOOL_A_LINKMODES_UNSPEC = 0, - ETHTOOL_A_LINKMODES_HEADER = 1, - ETHTOOL_A_LINKMODES_AUTONEG = 2, - ETHTOOL_A_LINKMODES_OURS = 3, - ETHTOOL_A_LINKMODES_PEER = 4, - ETHTOOL_A_LINKMODES_SPEED = 5, - ETHTOOL_A_LINKMODES_DUPLEX = 6, - ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG = 7, - ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE = 8, - ETHTOOL_A_LINKMODES_LANES = 9, - __ETHTOOL_A_LINKMODES_CNT = 10, - ETHTOOL_A_LINKMODES_MAX = 9, -}; - -enum { - ETHTOOL_A_LINKSTATE_UNSPEC = 0, - ETHTOOL_A_LINKSTATE_HEADER = 1, - ETHTOOL_A_LINKSTATE_LINK = 2, - ETHTOOL_A_LINKSTATE_SQI = 3, - ETHTOOL_A_LINKSTATE_SQI_MAX = 4, - ETHTOOL_A_LINKSTATE_EXT_STATE = 5, - ETHTOOL_A_LINKSTATE_EXT_SUBSTATE = 6, - __ETHTOOL_A_LINKSTATE_CNT = 7, - ETHTOOL_A_LINKSTATE_MAX = 6, -}; - -enum { - ETHTOOL_A_DEBUG_UNSPEC = 0, - ETHTOOL_A_DEBUG_HEADER = 1, - ETHTOOL_A_DEBUG_MSGMASK = 2, - __ETHTOOL_A_DEBUG_CNT = 3, - ETHTOOL_A_DEBUG_MAX = 2, -}; - -enum { - ETHTOOL_A_WOL_UNSPEC = 0, - ETHTOOL_A_WOL_HEADER = 1, - ETHTOOL_A_WOL_MODES = 2, - ETHTOOL_A_WOL_SOPASS = 3, - __ETHTOOL_A_WOL_CNT = 4, - ETHTOOL_A_WOL_MAX = 3, -}; - -enum { - ETHTOOL_A_FEATURES_UNSPEC = 0, - ETHTOOL_A_FEATURES_HEADER = 1, - ETHTOOL_A_FEATURES_HW = 2, - ETHTOOL_A_FEATURES_WANTED = 3, - ETHTOOL_A_FEATURES_ACTIVE = 4, - ETHTOOL_A_FEATURES_NOCHANGE = 5, - __ETHTOOL_A_FEATURES_CNT = 6, - ETHTOOL_A_FEATURES_MAX = 5, -}; - -enum { - ETHTOOL_A_PRIVFLAGS_UNSPEC = 0, - ETHTOOL_A_PRIVFLAGS_HEADER = 1, - ETHTOOL_A_PRIVFLAGS_FLAGS = 2, - __ETHTOOL_A_PRIVFLAGS_CNT = 3, - ETHTOOL_A_PRIVFLAGS_MAX = 2, -}; - -enum { - ETHTOOL_A_RINGS_UNSPEC = 0, - ETHTOOL_A_RINGS_HEADER = 1, - ETHTOOL_A_RINGS_RX_MAX = 2, - ETHTOOL_A_RINGS_RX_MINI_MAX = 3, - ETHTOOL_A_RINGS_RX_JUMBO_MAX = 4, - ETHTOOL_A_RINGS_TX_MAX = 5, - ETHTOOL_A_RINGS_RX = 6, - ETHTOOL_A_RINGS_RX_MINI = 7, - ETHTOOL_A_RINGS_RX_JUMBO = 8, - ETHTOOL_A_RINGS_TX = 9, - __ETHTOOL_A_RINGS_CNT = 10, - ETHTOOL_A_RINGS_MAX = 9, -}; - -enum { - ETHTOOL_A_CHANNELS_UNSPEC = 0, - ETHTOOL_A_CHANNELS_HEADER = 1, - ETHTOOL_A_CHANNELS_RX_MAX = 2, - ETHTOOL_A_CHANNELS_TX_MAX = 3, - ETHTOOL_A_CHANNELS_OTHER_MAX = 4, - ETHTOOL_A_CHANNELS_COMBINED_MAX = 5, - ETHTOOL_A_CHANNELS_RX_COUNT = 6, - ETHTOOL_A_CHANNELS_TX_COUNT = 7, - ETHTOOL_A_CHANNELS_OTHER_COUNT = 8, - ETHTOOL_A_CHANNELS_COMBINED_COUNT = 9, - __ETHTOOL_A_CHANNELS_CNT = 10, - ETHTOOL_A_CHANNELS_MAX = 9, -}; - -enum { - ETHTOOL_A_COALESCE_UNSPEC = 0, - ETHTOOL_A_COALESCE_HEADER = 1, - ETHTOOL_A_COALESCE_RX_USECS = 2, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES = 3, - ETHTOOL_A_COALESCE_RX_USECS_IRQ = 4, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ = 5, - ETHTOOL_A_COALESCE_TX_USECS = 6, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES = 7, - ETHTOOL_A_COALESCE_TX_USECS_IRQ = 8, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ = 9, - ETHTOOL_A_COALESCE_STATS_BLOCK_USECS = 10, - ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX = 11, - ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX = 12, - ETHTOOL_A_COALESCE_PKT_RATE_LOW = 13, - ETHTOOL_A_COALESCE_RX_USECS_LOW = 14, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW = 15, - ETHTOOL_A_COALESCE_TX_USECS_LOW = 16, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW = 17, - ETHTOOL_A_COALESCE_PKT_RATE_HIGH = 18, - ETHTOOL_A_COALESCE_RX_USECS_HIGH = 19, - ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH = 20, - ETHTOOL_A_COALESCE_TX_USECS_HIGH = 21, - ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH = 22, - ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 23, - __ETHTOOL_A_COALESCE_CNT = 24, - ETHTOOL_A_COALESCE_MAX = 23, -}; - -enum { - ETHTOOL_A_PAUSE_UNSPEC = 0, - ETHTOOL_A_PAUSE_HEADER = 1, - ETHTOOL_A_PAUSE_AUTONEG = 2, - ETHTOOL_A_PAUSE_RX = 3, - ETHTOOL_A_PAUSE_TX = 4, - ETHTOOL_A_PAUSE_STATS = 5, - __ETHTOOL_A_PAUSE_CNT = 6, - ETHTOOL_A_PAUSE_MAX = 5, -}; - -enum { - ETHTOOL_A_EEE_UNSPEC = 0, - ETHTOOL_A_EEE_HEADER = 1, - ETHTOOL_A_EEE_MODES_OURS = 2, - ETHTOOL_A_EEE_MODES_PEER = 3, - ETHTOOL_A_EEE_ACTIVE = 4, - ETHTOOL_A_EEE_ENABLED = 5, - ETHTOOL_A_EEE_TX_LPI_ENABLED = 6, - ETHTOOL_A_EEE_TX_LPI_TIMER = 7, - __ETHTOOL_A_EEE_CNT = 8, - ETHTOOL_A_EEE_MAX = 7, -}; - -enum { - ETHTOOL_A_TSINFO_UNSPEC = 0, - ETHTOOL_A_TSINFO_HEADER = 1, - ETHTOOL_A_TSINFO_TIMESTAMPING = 2, - ETHTOOL_A_TSINFO_TX_TYPES = 3, - ETHTOOL_A_TSINFO_RX_FILTERS = 4, - ETHTOOL_A_TSINFO_PHC_INDEX = 5, - __ETHTOOL_A_TSINFO_CNT = 6, - ETHTOOL_A_TSINFO_MAX = 5, -}; - -enum { - ETHTOOL_A_PHC_VCLOCKS_UNSPEC = 0, - ETHTOOL_A_PHC_VCLOCKS_HEADER = 1, - ETHTOOL_A_PHC_VCLOCKS_NUM = 2, - ETHTOOL_A_PHC_VCLOCKS_INDEX = 3, - __ETHTOOL_A_PHC_VCLOCKS_CNT = 4, - ETHTOOL_A_PHC_VCLOCKS_MAX = 3, -}; - -enum { - ETHTOOL_A_CABLE_TEST_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_HEADER = 1, - __ETHTOOL_A_CABLE_TEST_CNT = 2, - ETHTOOL_A_CABLE_TEST_MAX = 1, -}; - -enum { - ETHTOOL_A_CABLE_TEST_TDR_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_TDR_HEADER = 1, - ETHTOOL_A_CABLE_TEST_TDR_CFG = 2, - __ETHTOOL_A_CABLE_TEST_TDR_CNT = 3, - ETHTOOL_A_CABLE_TEST_TDR_MAX = 2, -}; - -enum { - ETHTOOL_A_TUNNEL_INFO_UNSPEC = 0, - ETHTOOL_A_TUNNEL_INFO_HEADER = 1, - ETHTOOL_A_TUNNEL_INFO_UDP_PORTS = 2, - __ETHTOOL_A_TUNNEL_INFO_CNT = 3, - ETHTOOL_A_TUNNEL_INFO_MAX = 2, -}; - -enum { - ETHTOOL_A_FEC_UNSPEC = 0, - ETHTOOL_A_FEC_HEADER = 1, - ETHTOOL_A_FEC_MODES = 2, - ETHTOOL_A_FEC_AUTO = 3, - ETHTOOL_A_FEC_ACTIVE = 4, - ETHTOOL_A_FEC_STATS = 5, - __ETHTOOL_A_FEC_CNT = 6, - ETHTOOL_A_FEC_MAX = 5, -}; - -enum { - ETHTOOL_A_MODULE_EEPROM_UNSPEC = 0, - ETHTOOL_A_MODULE_EEPROM_HEADER = 1, - ETHTOOL_A_MODULE_EEPROM_OFFSET = 2, - ETHTOOL_A_MODULE_EEPROM_LENGTH = 3, - ETHTOOL_A_MODULE_EEPROM_PAGE = 4, - ETHTOOL_A_MODULE_EEPROM_BANK = 5, - ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS = 6, - ETHTOOL_A_MODULE_EEPROM_DATA = 7, - __ETHTOOL_A_MODULE_EEPROM_CNT = 8, - ETHTOOL_A_MODULE_EEPROM_MAX = 7, -}; - -enum { - ETHTOOL_STATS_ETH_PHY = 0, - ETHTOOL_STATS_ETH_MAC = 1, - ETHTOOL_STATS_ETH_CTRL = 2, - ETHTOOL_STATS_RMON = 3, - __ETHTOOL_STATS_CNT = 4, -}; - -enum { - ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR = 0, - __ETHTOOL_A_STATS_ETH_PHY_CNT = 1, - ETHTOOL_A_STATS_ETH_PHY_MAX = 0, -}; - -enum { - ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT = 0, - ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL = 1, - ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL = 2, - ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT = 3, - ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR = 4, - ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR = 5, - ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES = 6, - ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER = 7, - ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL = 8, - ETHTOOL_A_STATS_ETH_MAC_11_XS_COL = 9, - ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR = 10, - ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR = 11, - ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES = 12, - ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR = 13, - ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST = 14, - ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST = 15, - ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER = 16, - ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST = 17, - ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST = 18, - ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR = 19, - ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN = 20, - ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR = 21, - __ETHTOOL_A_STATS_ETH_MAC_CNT = 22, - ETHTOOL_A_STATS_ETH_MAC_MAX = 21, -}; - -enum { - ETHTOOL_A_STATS_ETH_CTRL_3_TX = 0, - ETHTOOL_A_STATS_ETH_CTRL_4_RX = 1, - ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP = 2, - __ETHTOOL_A_STATS_ETH_CTRL_CNT = 3, - ETHTOOL_A_STATS_ETH_CTRL_MAX = 2, -}; - -enum { - ETHTOOL_A_STATS_RMON_UNDERSIZE = 0, - ETHTOOL_A_STATS_RMON_OVERSIZE = 1, - ETHTOOL_A_STATS_RMON_FRAG = 2, - ETHTOOL_A_STATS_RMON_JABBER = 3, - __ETHTOOL_A_STATS_RMON_CNT = 4, - ETHTOOL_A_STATS_RMON_MAX = 3, -}; - -enum ethtool_multicast_groups { - ETHNL_MCGRP_MONITOR = 0, -}; - -struct ethnl_req_info { - struct net_device *dev; - u32 flags; -}; - -struct ethnl_reply_data { - struct net_device *dev; -}; - -struct ethnl_request_ops { - u8 request_cmd; - u8 reply_cmd; - u16 hdr_attr; - unsigned int req_info_size; - unsigned int reply_data_size; - bool allow_nodev_do; - int (*parse_request)(struct ethnl_req_info *, struct nlattr **, struct netlink_ext_ack *); - int (*prepare_data)(const struct ethnl_req_info *, struct ethnl_reply_data *, struct genl_info *); - int (*reply_size)(const struct ethnl_req_info *, const struct ethnl_reply_data *); - int (*fill_reply)(struct sk_buff *, const struct ethnl_req_info *, const struct ethnl_reply_data *); - void (*cleanup_data)(struct ethnl_reply_data *); -}; - -struct ethnl_dump_ctx { - const struct ethnl_request_ops *ops; - struct ethnl_req_info *req_info; - struct ethnl_reply_data *reply_data; - int pos_hash; - int pos_idx; -}; - -typedef void (*ethnl_notify_handler_t)(struct net_device *, unsigned int, const void *); - -enum { - ETHTOOL_A_BITSET_BIT_UNSPEC = 0, - ETHTOOL_A_BITSET_BIT_INDEX = 1, - ETHTOOL_A_BITSET_BIT_NAME = 2, - ETHTOOL_A_BITSET_BIT_VALUE = 3, - __ETHTOOL_A_BITSET_BIT_CNT = 4, - ETHTOOL_A_BITSET_BIT_MAX = 3, -}; - -enum { - ETHTOOL_A_BITSET_BITS_UNSPEC = 0, - ETHTOOL_A_BITSET_BITS_BIT = 1, - __ETHTOOL_A_BITSET_BITS_CNT = 2, - ETHTOOL_A_BITSET_BITS_MAX = 1, -}; - -enum { - ETHTOOL_A_BITSET_UNSPEC = 0, - ETHTOOL_A_BITSET_NOMASK = 1, - ETHTOOL_A_BITSET_SIZE = 2, - ETHTOOL_A_BITSET_BITS = 3, - ETHTOOL_A_BITSET_VALUE = 4, - ETHTOOL_A_BITSET_MASK = 5, - __ETHTOOL_A_BITSET_CNT = 6, - ETHTOOL_A_BITSET_MAX = 5, -}; - -typedef const char (* const ethnl_string_array_t)[32]; - -enum { - ETHTOOL_A_STRING_UNSPEC = 0, - ETHTOOL_A_STRING_INDEX = 1, - ETHTOOL_A_STRING_VALUE = 2, - __ETHTOOL_A_STRING_CNT = 3, - ETHTOOL_A_STRING_MAX = 2, -}; - -enum { - ETHTOOL_A_STRINGS_UNSPEC = 0, - ETHTOOL_A_STRINGS_STRING = 1, - __ETHTOOL_A_STRINGS_CNT = 2, - ETHTOOL_A_STRINGS_MAX = 1, -}; - -enum { - ETHTOOL_A_STRINGSET_UNSPEC = 0, - ETHTOOL_A_STRINGSET_ID = 1, - ETHTOOL_A_STRINGSET_COUNT = 2, - ETHTOOL_A_STRINGSET_STRINGS = 3, - __ETHTOOL_A_STRINGSET_CNT = 4, - ETHTOOL_A_STRINGSET_MAX = 3, -}; - -enum { - ETHTOOL_A_STRINGSETS_UNSPEC = 0, - ETHTOOL_A_STRINGSETS_STRINGSET = 1, - __ETHTOOL_A_STRINGSETS_CNT = 2, - ETHTOOL_A_STRINGSETS_MAX = 1, -}; - -struct strset_info { - bool per_dev; - bool free_strings; - unsigned int count; - const char (*strings)[32]; -}; - -struct strset_req_info { - struct ethnl_req_info base; - u32 req_ids; - bool counts_only; -}; - -struct strset_reply_data { - struct ethnl_reply_data base; - struct strset_info sets[21]; -}; - -struct linkinfo_reply_data { - struct ethnl_reply_data base; - struct ethtool_link_ksettings ksettings; - struct ethtool_link_settings *lsettings; -}; - -struct linkmodes_reply_data { - struct ethnl_reply_data base; - struct ethtool_link_ksettings ksettings; - struct ethtool_link_settings *lsettings; - bool peer_empty; -}; - -struct linkstate_reply_data { - struct ethnl_reply_data base; - int link; - int sqi; - int sqi_max; - bool link_ext_state_provided; - struct ethtool_link_ext_state_info ethtool_link_ext_state_info; -}; - -struct debug_reply_data { - struct ethnl_reply_data base; - u32 msg_mask; -}; - -struct wol_reply_data { - struct ethnl_reply_data base; - struct ethtool_wolinfo wol; - bool show_sopass; -}; - -struct features_reply_data { - struct ethnl_reply_data base; - u32 hw[2]; - u32 wanted[2]; - u32 active[2]; - u32 nochange[2]; - u32 all[2]; -}; - -struct privflags_reply_data { - struct ethnl_reply_data base; - const char (*priv_flag_names)[32]; - unsigned int n_priv_flags; - u32 priv_flags; -}; - -struct rings_reply_data { - struct ethnl_reply_data base; - struct ethtool_ringparam ringparam; -}; - -struct channels_reply_data { - struct ethnl_reply_data base; - struct ethtool_channels channels; -}; - -struct coalesce_reply_data { - struct ethnl_reply_data base; - struct ethtool_coalesce coalesce; - u32 supported_params; -}; - -enum { - ETHTOOL_A_PAUSE_STAT_UNSPEC = 0, - ETHTOOL_A_PAUSE_STAT_PAD = 1, - ETHTOOL_A_PAUSE_STAT_TX_FRAMES = 2, - ETHTOOL_A_PAUSE_STAT_RX_FRAMES = 3, - __ETHTOOL_A_PAUSE_STAT_CNT = 4, - ETHTOOL_A_PAUSE_STAT_MAX = 3, -}; - -struct pause_reply_data { - struct ethnl_reply_data base; - struct ethtool_pauseparam pauseparam; - struct ethtool_pause_stats pausestat; -}; - -struct eee_reply_data { - struct ethnl_reply_data base; - struct ethtool_eee eee; -}; - -struct tsinfo_reply_data { - struct ethnl_reply_data base; - struct ethtool_ts_info ts_info; -}; - -enum { - ETHTOOL_A_CABLE_PAIR_A = 0, - ETHTOOL_A_CABLE_PAIR_B = 1, - ETHTOOL_A_CABLE_PAIR_C = 2, - ETHTOOL_A_CABLE_PAIR_D = 3, -}; - -enum { - ETHTOOL_A_CABLE_RESULT_UNSPEC = 0, - ETHTOOL_A_CABLE_RESULT_PAIR = 1, - ETHTOOL_A_CABLE_RESULT_CODE = 2, - __ETHTOOL_A_CABLE_RESULT_CNT = 3, - ETHTOOL_A_CABLE_RESULT_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC = 0, - ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR = 1, - ETHTOOL_A_CABLE_FAULT_LENGTH_CM = 2, - __ETHTOOL_A_CABLE_FAULT_LENGTH_CNT = 3, - ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_TEST_NTF_STATUS_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED = 1, - ETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED = 2, -}; - -enum { - ETHTOOL_A_CABLE_NEST_UNSPEC = 0, - ETHTOOL_A_CABLE_NEST_RESULT = 1, - ETHTOOL_A_CABLE_NEST_FAULT_LENGTH = 2, - __ETHTOOL_A_CABLE_NEST_CNT = 3, - ETHTOOL_A_CABLE_NEST_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_TEST_NTF_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_NTF_HEADER = 1, - ETHTOOL_A_CABLE_TEST_NTF_STATUS = 2, - ETHTOOL_A_CABLE_TEST_NTF_NEST = 3, - __ETHTOOL_A_CABLE_TEST_NTF_CNT = 4, - ETHTOOL_A_CABLE_TEST_NTF_MAX = 3, -}; - -enum { - ETHTOOL_A_CABLE_TEST_TDR_CFG_UNSPEC = 0, - ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST = 1, - ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST = 2, - ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP = 3, - ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR = 4, - __ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT = 5, - ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX = 4, -}; - -enum { - ETHTOOL_A_CABLE_AMPLITUDE_UNSPEC = 0, - ETHTOOL_A_CABLE_AMPLITUDE_PAIR = 1, - ETHTOOL_A_CABLE_AMPLITUDE_mV = 2, - __ETHTOOL_A_CABLE_AMPLITUDE_CNT = 3, - ETHTOOL_A_CABLE_AMPLITUDE_MAX = 2, -}; - -enum { - ETHTOOL_A_CABLE_PULSE_UNSPEC = 0, - ETHTOOL_A_CABLE_PULSE_mV = 1, - __ETHTOOL_A_CABLE_PULSE_CNT = 2, - ETHTOOL_A_CABLE_PULSE_MAX = 1, -}; - -enum { - ETHTOOL_A_CABLE_STEP_UNSPEC = 0, - ETHTOOL_A_CABLE_STEP_FIRST_DISTANCE = 1, - ETHTOOL_A_CABLE_STEP_LAST_DISTANCE = 2, - ETHTOOL_A_CABLE_STEP_STEP_DISTANCE = 3, - __ETHTOOL_A_CABLE_STEP_CNT = 4, - ETHTOOL_A_CABLE_STEP_MAX = 3, -}; - -enum { - ETHTOOL_A_CABLE_TDR_NEST_UNSPEC = 0, - ETHTOOL_A_CABLE_TDR_NEST_STEP = 1, - ETHTOOL_A_CABLE_TDR_NEST_AMPLITUDE = 2, - ETHTOOL_A_CABLE_TDR_NEST_PULSE = 3, - __ETHTOOL_A_CABLE_TDR_NEST_CNT = 4, - ETHTOOL_A_CABLE_TDR_NEST_MAX = 3, -}; - -enum { - ETHTOOL_A_TUNNEL_UDP_ENTRY_UNSPEC = 0, - ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT = 1, - ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE = 2, - __ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT = 3, - ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX = 2, -}; - -enum { - ETHTOOL_A_TUNNEL_UDP_TABLE_UNSPEC = 0, - ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE = 1, - ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES = 2, - ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY = 3, - __ETHTOOL_A_TUNNEL_UDP_TABLE_CNT = 4, - ETHTOOL_A_TUNNEL_UDP_TABLE_MAX = 3, -}; - -enum { - ETHTOOL_A_TUNNEL_UDP_UNSPEC = 0, - ETHTOOL_A_TUNNEL_UDP_TABLE = 1, - __ETHTOOL_A_TUNNEL_UDP_CNT = 2, - ETHTOOL_A_TUNNEL_UDP_MAX = 1, -}; - -enum udp_parsable_tunnel_type { - UDP_TUNNEL_TYPE_VXLAN = 1, - UDP_TUNNEL_TYPE_GENEVE = 2, - UDP_TUNNEL_TYPE_VXLAN_GPE = 4, -}; - -enum udp_tunnel_nic_info_flags { - UDP_TUNNEL_NIC_INFO_MAY_SLEEP = 1, - UDP_TUNNEL_NIC_INFO_OPEN_ONLY = 2, - UDP_TUNNEL_NIC_INFO_IPV4_ONLY = 4, - UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN = 8, -}; - -struct udp_tunnel_nic_ops { - void (*get_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *); - void (*set_port_priv)(struct net_device *, unsigned int, unsigned int, u8); - void (*add_port)(struct net_device *, struct udp_tunnel_info *); - void (*del_port)(struct net_device *, struct udp_tunnel_info *); - void (*reset_ntf)(struct net_device *); - size_t (*dump_size)(struct net_device *, unsigned int); - int (*dump_write)(struct net_device *, unsigned int, struct sk_buff *); -}; - -struct ethnl_tunnel_info_dump_ctx { - struct ethnl_req_info req_info; - int pos_hash; - int pos_idx; -}; - -enum { - ETHTOOL_A_FEC_STAT_UNSPEC = 0, - ETHTOOL_A_FEC_STAT_PAD = 1, - ETHTOOL_A_FEC_STAT_CORRECTED = 2, - ETHTOOL_A_FEC_STAT_UNCORR = 3, - ETHTOOL_A_FEC_STAT_CORR_BITS = 4, - __ETHTOOL_A_FEC_STAT_CNT = 5, - ETHTOOL_A_FEC_STAT_MAX = 4, -}; - -struct fec_stat_grp { - u64 stats[9]; - u8 cnt; -}; - -struct fec_reply_data { - struct ethnl_reply_data base; - long unsigned int fec_link_modes[2]; - u32 active_fec; - u8 fec_auto; - struct fec_stat_grp corr; - struct fec_stat_grp uncorr; - struct fec_stat_grp corr_bits; -}; - -struct eeprom_req_info { - struct ethnl_req_info base; - u32 offset; - u32 length; - u8 page; - u8 bank; - u8 i2c_address; -}; - -struct eeprom_reply_data { - struct ethnl_reply_data base; - u32 length; - u8 *data; -}; - -enum { - ETHTOOL_A_STATS_GRP_UNSPEC = 0, - ETHTOOL_A_STATS_GRP_PAD = 1, - ETHTOOL_A_STATS_GRP_ID = 2, - ETHTOOL_A_STATS_GRP_SS_ID = 3, - ETHTOOL_A_STATS_GRP_STAT = 4, - ETHTOOL_A_STATS_GRP_HIST_RX = 5, - ETHTOOL_A_STATS_GRP_HIST_TX = 6, - ETHTOOL_A_STATS_GRP_HIST_BKT_LOW = 7, - ETHTOOL_A_STATS_GRP_HIST_BKT_HI = 8, - ETHTOOL_A_STATS_GRP_HIST_VAL = 9, - __ETHTOOL_A_STATS_GRP_CNT = 10, - ETHTOOL_A_STATS_GRP_MAX = 4, -}; - -struct stats_req_info { - struct ethnl_req_info base; - long unsigned int stat_mask[1]; -}; - -struct stats_reply_data { - struct ethnl_reply_data base; - struct ethtool_eth_phy_stats phy_stats; - struct ethtool_eth_mac_stats mac_stats; - struct ethtool_eth_ctrl_stats ctrl_stats; - struct ethtool_rmon_stats rmon_stats; - const struct ethtool_rmon_hist_range *rmon_ranges; -}; - -struct phc_vclocks_reply_data { - struct ethnl_reply_data base; - int num; - int *index; -}; - -struct nf_hook_entries_rcu_head { - struct callback_head head; - void *allocation; -}; - -struct nf_conn___2; - -enum nf_nat_manip_type; - -struct nf_nat_hook { - int (*parse_nat_setup)(struct nf_conn___2 *, enum nf_nat_manip_type, const struct nlattr *); - void (*decode_session)(struct sk_buff *, struct flowi *); - unsigned int (*manip_pkt)(struct sk_buff *, struct nf_conn___2 *, enum nf_nat_manip_type, enum ip_conntrack_dir); -}; - -struct nf_conntrack_tuple___2; - -struct nf_ct_hook { - int (*update)(struct net *, struct sk_buff *); - void (*destroy)(struct nf_conntrack *); - bool (*get_tuple_skb)(struct nf_conntrack_tuple___2 *, const struct sk_buff *); -}; - -struct nfnl_ct_hook { - size_t (*build_size)(const struct nf_conn___2 *); - int (*build)(struct sk_buff *, struct nf_conn___2 *, enum ip_conntrack_info, u_int16_t, u_int16_t); - int (*parse)(const struct nlattr *, struct nf_conn___2 *); - int (*attach_expect)(const struct nlattr *, struct nf_conn___2 *, u32, u32); - void (*seq_adjust)(struct sk_buff *, struct nf_conn___2 *, enum ip_conntrack_info, s32); -}; - -struct nf_ipv6_ops { - void (*route_input)(struct sk_buff *); - int (*fragment)(struct net *, struct sock *, struct sk_buff *, int (*)(struct net *, struct sock *, struct sk_buff *)); - int (*reroute)(struct sk_buff *, const struct nf_queue_entry *); -}; - -struct nf_queue_entry { - struct list_head list; - struct sk_buff *skb; - unsigned int id; - unsigned int hook_index; - struct net_device *physin; - struct net_device *physout; - struct nf_hook_state state; - u16 size; -}; - -struct nf_loginfo { - u_int8_t type; - union { - struct { - u_int32_t copy_len; - u_int16_t group; - u_int16_t qthreshold; - u_int16_t flags; - } ulog; - struct { - u_int8_t level; - u_int8_t logflags; - } log; - } u; -}; - -struct nf_log_buf { - unsigned int count; - char buf[1020]; -}; - -struct nf_bridge_info { - enum { - BRNF_PROTO_UNCHANGED = 0, - BRNF_PROTO_8021Q = 1, - BRNF_PROTO_PPPOE = 2, - } orig_proto: 8; - u8 pkt_otherhost: 1; - u8 in_prerouting: 1; - u8 bridged_dnat: 1; - __u16 frag_max_size; - struct net_device *physindev; - struct net_device *physoutdev; - union { - __be32 ipv4_daddr; - struct in6_addr ipv6_daddr; - char neigh_header[8]; - }; -}; - -struct ip_rt_info { - __be32 daddr; - __be32 saddr; - u_int8_t tos; - u_int32_t mark; -}; - -struct ip6_rt_info { - struct in6_addr daddr; - struct in6_addr saddr; - u_int32_t mark; -}; - -struct nf_sockopt_ops { - struct list_head list; - u_int8_t pf; - int set_optmin; - int set_optmax; - int (*set)(struct sock *, int, sockptr_t, unsigned int); - int get_optmin; - int get_optmax; - int (*get)(struct sock *, int, void *, int *); - struct module *owner; -}; - -struct ip_mreqn { - struct in_addr imr_multiaddr; - struct in_addr imr_address; - int imr_ifindex; -}; - -struct rtmsg { - unsigned char rtm_family; - unsigned char rtm_dst_len; - unsigned char rtm_src_len; - unsigned char rtm_tos; - unsigned char rtm_table; - unsigned char rtm_protocol; - unsigned char rtm_scope; - unsigned char rtm_type; - unsigned int rtm_flags; -}; - -struct rtvia { - __kernel_sa_family_t rtvia_family; - __u8 rtvia_addr[0]; -}; - -struct ip_sf_list; - -struct ip_mc_list { - struct in_device *interface; - __be32 multiaddr; - unsigned int sfmode; - struct ip_sf_list *sources; - struct ip_sf_list *tomb; - long unsigned int sfcount[2]; - union { - struct ip_mc_list *next; - struct ip_mc_list *next_rcu; - }; - struct ip_mc_list *next_hash; - struct timer_list timer; - int users; - refcount_t refcnt; - spinlock_t lock; - char tm_running; - char reporter; - char unsolicit_count; - char loaded; - unsigned char gsquery; - unsigned char crcount; - struct callback_head rcu; -}; - -struct ip_sf_socklist { - unsigned int sl_max; - unsigned int sl_count; - struct callback_head rcu; - __be32 sl_addr[0]; -}; - -struct ip_mc_socklist { - struct ip_mc_socklist *next_rcu; - struct ip_mreqn multi; - unsigned int sfmode; - struct ip_sf_socklist *sflist; - struct callback_head rcu; -}; - -struct ip_sf_list { - struct ip_sf_list *sf_next; - long unsigned int sf_count[2]; - __be32 sf_inaddr; - unsigned char sf_gsresp; - unsigned char sf_oldin; - unsigned char sf_crcount; -}; - -struct ipv4_addr_key { - __be32 addr; - int vif; -}; - -struct inetpeer_addr { - union { - struct ipv4_addr_key a4; - struct in6_addr a6; - u32 key[4]; - }; - __u16 family; -}; - -struct inet_peer { - struct rb_node rb_node; - struct inetpeer_addr daddr; - u32 metrics[17]; - u32 rate_tokens; - u32 n_redirects; - long unsigned int rate_last; - union { - struct { - atomic_t rid; - }; - struct callback_head rcu; - }; - __u32 dtime; - refcount_t refcnt; -}; - -struct fib_rt_info { - struct fib_info *fi; - u32 tb_id; - __be32 dst; - int dst_len; - u8 tos; - u8 type; - u8 offload: 1; - u8 trap: 1; - u8 offload_failed: 1; - u8 unused: 5; -}; - -struct uncached_list { - spinlock_t lock; - struct list_head head; -}; - -struct ip_rt_acct { - __u32 o_bytes; - __u32 o_packets; - __u32 i_bytes; - __u32 i_packets; -}; - -struct rt_cache_stat { - unsigned int in_slow_tot; - unsigned int in_slow_mc; - unsigned int in_no_route; - unsigned int in_brd; - unsigned int in_martian_dst; - unsigned int in_martian_src; - unsigned int out_slow_tot; - unsigned int out_slow_mc; -}; - -struct fib_alias { - struct hlist_node fa_list; - struct fib_info *fa_info; - u8 fa_tos; - u8 fa_type; - u8 fa_state; - u8 fa_slen; - u32 tb_id; - s16 fa_default; - u8 offload: 1; - u8 trap: 1; - u8 offload_failed: 1; - u8 unused: 5; - struct callback_head rcu; -}; - -struct fib_prop { - int error; - u8 scope; -}; - -struct net_offload { - struct offload_callbacks callbacks; - unsigned int flags; -}; - -struct raw_hashinfo { - rwlock_t lock; - struct hlist_head ht[256]; -}; - -enum ip_defrag_users { - IP_DEFRAG_LOCAL_DELIVER = 0, - IP_DEFRAG_CALL_RA_CHAIN = 1, - IP_DEFRAG_CONNTRACK_IN = 2, - __IP_DEFRAG_CONNTRACK_IN_END = 65537, - IP_DEFRAG_CONNTRACK_OUT = 65538, - __IP_DEFRAG_CONNTRACK_OUT_END = 131073, - IP_DEFRAG_CONNTRACK_BRIDGE_IN = 131074, - __IP_DEFRAG_CONNTRACK_BRIDGE_IN = 196609, - IP_DEFRAG_VS_IN = 196610, - IP_DEFRAG_VS_OUT = 196611, - IP_DEFRAG_VS_FWD = 196612, - IP_DEFRAG_AF_PACKET = 196613, - IP_DEFRAG_MACVLAN = 196614, -}; - -enum { - INET_FRAG_FIRST_IN = 1, - INET_FRAG_LAST_IN = 2, - INET_FRAG_COMPLETE = 4, - INET_FRAG_HASH_DEAD = 8, -}; - -struct ipq { - struct inet_frag_queue q; - u8 ecn; - u16 max_df_size; - int iif; - unsigned int rid; - struct inet_peer *peer; -}; - -struct ip_options_data { - struct ip_options_rcu opt; - char data[40]; -}; - -struct ipcm_cookie { - struct sockcm_cookie sockc; - __be32 addr; - int oif; - struct ip_options_rcu *opt; - __u8 ttl; - __s16 tos; - char priority; - __u16 gso_size; -}; - -struct ip_fraglist_iter { - struct sk_buff *frag; - struct iphdr *iph; - int offset; - unsigned int hlen; -}; - -struct ip_frag_state { - bool DF; - unsigned int hlen; - unsigned int ll_rs; - unsigned int mtu; - unsigned int left; - int offset; - int ptr; - __be16 not_last_frag; -}; - -struct ip_reply_arg { - struct kvec iov[1]; - int flags; - __wsum csum; - int csumoffset; - int bound_dev_if; - u8 tos; - kuid_t uid; -}; - -struct ip_mreq_source { - __be32 imr_multiaddr; - __be32 imr_interface; - __be32 imr_sourceaddr; -}; - -struct ip_msfilter { - __be32 imsf_multiaddr; - __be32 imsf_interface; - __u32 imsf_fmode; - __u32 imsf_numsrc; - __be32 imsf_slist[1]; -}; - -struct group_req { - __u32 gr_interface; - struct __kernel_sockaddr_storage gr_group; -}; - -struct group_source_req { - __u32 gsr_interface; - struct __kernel_sockaddr_storage gsr_group; - struct __kernel_sockaddr_storage gsr_source; -}; - -struct group_filter { - __u32 gf_interface; - struct __kernel_sockaddr_storage gf_group; - __u32 gf_fmode; - __u32 gf_numsrc; - struct __kernel_sockaddr_storage gf_slist[1]; -}; - -struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; -}; - -struct compat_group_req { - __u32 gr_interface; - struct __kernel_sockaddr_storage gr_group; -} __attribute__((packed)); - -struct compat_group_source_req { - __u32 gsr_interface; - struct __kernel_sockaddr_storage gsr_group; - struct __kernel_sockaddr_storage gsr_source; -} __attribute__((packed)); - -struct compat_group_filter { - __u32 gf_interface; - struct __kernel_sockaddr_storage gf_group; - __u32 gf_fmode; - __u32 gf_numsrc; - struct __kernel_sockaddr_storage gf_slist[1]; -} __attribute__((packed)); - -struct tcpvegas_info { - __u32 tcpv_enabled; - __u32 tcpv_rttcnt; - __u32 tcpv_rtt; - __u32 tcpv_minrtt; -}; - -struct tcp_dctcp_info { - __u16 dctcp_enabled; - __u16 dctcp_ce_state; - __u32 dctcp_alpha; - __u32 dctcp_ab_ecn; - __u32 dctcp_ab_tot; -}; - -struct tcp_bbr_info { - __u32 bbr_bw_lo; - __u32 bbr_bw_hi; - __u32 bbr_min_rtt; - __u32 bbr_pacing_gain; - __u32 bbr_cwnd_gain; -}; - -union tcp_cc_info { - struct tcpvegas_info vegas; - struct tcp_dctcp_info dctcp; - struct tcp_bbr_info bbr; -}; - -enum { - BPF_TCP_ESTABLISHED = 1, - BPF_TCP_SYN_SENT = 2, - BPF_TCP_SYN_RECV = 3, - BPF_TCP_FIN_WAIT1 = 4, - BPF_TCP_FIN_WAIT2 = 5, - BPF_TCP_TIME_WAIT = 6, - BPF_TCP_CLOSE = 7, - BPF_TCP_CLOSE_WAIT = 8, - BPF_TCP_LAST_ACK = 9, - BPF_TCP_LISTEN = 10, - BPF_TCP_CLOSING = 11, - BPF_TCP_NEW_SYN_RECV = 12, - BPF_TCP_MAX_STATES = 13, -}; - -enum inet_csk_ack_state_t { - ICSK_ACK_SCHED = 1, - ICSK_ACK_TIMER = 2, - ICSK_ACK_PUSHED = 4, - ICSK_ACK_PUSHED2 = 8, - ICSK_ACK_NOW = 16, -}; - -enum { - TCP_FLAG_CWR = 32768, - TCP_FLAG_ECE = 16384, - TCP_FLAG_URG = 8192, - TCP_FLAG_ACK = 4096, - TCP_FLAG_PSH = 2048, - TCP_FLAG_RST = 1024, - TCP_FLAG_SYN = 512, - TCP_FLAG_FIN = 256, - TCP_RESERVED_BITS = 15, - TCP_DATA_OFFSET = 240, -}; - -struct tcp_repair_opt { - __u32 opt_code; - __u32 opt_val; -}; - -struct tcp_repair_window { - __u32 snd_wl1; - __u32 snd_wnd; - __u32 max_window; - __u32 rcv_wnd; - __u32 rcv_wup; -}; - -enum { - TCP_NO_QUEUE = 0, - TCP_RECV_QUEUE = 1, - TCP_SEND_QUEUE = 2, - TCP_QUEUES_NR = 3, -}; - -struct tcp_info { - __u8 tcpi_state; - __u8 tcpi_ca_state; - __u8 tcpi_retransmits; - __u8 tcpi_probes; - __u8 tcpi_backoff; - __u8 tcpi_options; - __u8 tcpi_snd_wscale: 4; - __u8 tcpi_rcv_wscale: 4; - __u8 tcpi_delivery_rate_app_limited: 1; - __u8 tcpi_fastopen_client_fail: 2; - __u32 tcpi_rto; - __u32 tcpi_ato; - __u32 tcpi_snd_mss; - __u32 tcpi_rcv_mss; - __u32 tcpi_unacked; - __u32 tcpi_sacked; - __u32 tcpi_lost; - __u32 tcpi_retrans; - __u32 tcpi_fackets; - __u32 tcpi_last_data_sent; - __u32 tcpi_last_ack_sent; - __u32 tcpi_last_data_recv; - __u32 tcpi_last_ack_recv; - __u32 tcpi_pmtu; - __u32 tcpi_rcv_ssthresh; - __u32 tcpi_rtt; - __u32 tcpi_rttvar; - __u32 tcpi_snd_ssthresh; - __u32 tcpi_snd_cwnd; - __u32 tcpi_advmss; - __u32 tcpi_reordering; - __u32 tcpi_rcv_rtt; - __u32 tcpi_rcv_space; - __u32 tcpi_total_retrans; - __u64 tcpi_pacing_rate; - __u64 tcpi_max_pacing_rate; - __u64 tcpi_bytes_acked; - __u64 tcpi_bytes_received; - __u32 tcpi_segs_out; - __u32 tcpi_segs_in; - __u32 tcpi_notsent_bytes; - __u32 tcpi_min_rtt; - __u32 tcpi_data_segs_in; - __u32 tcpi_data_segs_out; - __u64 tcpi_delivery_rate; - __u64 tcpi_busy_time; - __u64 tcpi_rwnd_limited; - __u64 tcpi_sndbuf_limited; - __u32 tcpi_delivered; - __u32 tcpi_delivered_ce; - __u64 tcpi_bytes_sent; - __u64 tcpi_bytes_retrans; - __u32 tcpi_dsack_dups; - __u32 tcpi_reord_seen; - __u32 tcpi_rcv_ooopack; - __u32 tcpi_snd_wnd; -}; - -enum { - TCP_NLA_PAD = 0, - TCP_NLA_BUSY = 1, - TCP_NLA_RWND_LIMITED = 2, - TCP_NLA_SNDBUF_LIMITED = 3, - TCP_NLA_DATA_SEGS_OUT = 4, - TCP_NLA_TOTAL_RETRANS = 5, - TCP_NLA_PACING_RATE = 6, - TCP_NLA_DELIVERY_RATE = 7, - TCP_NLA_SND_CWND = 8, - TCP_NLA_REORDERING = 9, - TCP_NLA_MIN_RTT = 10, - TCP_NLA_RECUR_RETRANS = 11, - TCP_NLA_DELIVERY_RATE_APP_LMT = 12, - TCP_NLA_SNDQ_SIZE = 13, - TCP_NLA_CA_STATE = 14, - TCP_NLA_SND_SSTHRESH = 15, - TCP_NLA_DELIVERED = 16, - TCP_NLA_DELIVERED_CE = 17, - TCP_NLA_BYTES_SENT = 18, - TCP_NLA_BYTES_RETRANS = 19, - TCP_NLA_DSACK_DUPS = 20, - TCP_NLA_REORD_SEEN = 21, - TCP_NLA_SRTT = 22, - TCP_NLA_TIMEOUT_REHASH = 23, - TCP_NLA_BYTES_NOTSENT = 24, - TCP_NLA_EDT = 25, - TCP_NLA_TTL = 26, -}; - -struct tcp_zerocopy_receive { - __u64 address; - __u32 length; - __u32 recv_skip_hint; - __u32 inq; - __s32 err; - __u64 copybuf_address; - __s32 copybuf_len; - __u32 flags; - __u64 msg_control; - __u64 msg_controllen; - __u32 msg_flags; - __u32 reserved; -}; - -struct tcp_md5sig_pool { - struct ahash_request *md5_req; - void *scratch; -}; - -enum tcp_chrono { - TCP_CHRONO_UNSPEC = 0, - TCP_CHRONO_BUSY = 1, - TCP_CHRONO_RWND_LIMITED = 2, - TCP_CHRONO_SNDBUF_LIMITED = 3, - __TCP_CHRONO_MAX = 4, -}; - -enum { - TCP_CMSG_INQ = 1, - TCP_CMSG_TS = 2, -}; - -struct tcp_splice_state { - struct pipe_inode_info *pipe; - size_t len; - unsigned int flags; -}; - -enum tcp_fastopen_client_fail { - TFO_STATUS_UNSPEC = 0, - TFO_COOKIE_UNAVAILABLE = 1, - TFO_DATA_NOT_ACKED = 2, - TFO_SYN_RETRANSMITTED = 3, -}; - -struct tcp_sack_block_wire { - __be32 start_seq; - __be32 end_seq; -}; - -struct static_key_false_deferred { - struct static_key_false key; - long unsigned int timeout; - struct delayed_work work; -}; - -struct mptcp_ext { - union { - u64 data_ack; - u32 data_ack32; - }; - u64 data_seq; - u32 subflow_seq; - u16 data_len; - __sum16 csum; - u8 use_map: 1; - u8 dsn64: 1; - u8 data_fin: 1; - u8 use_ack: 1; - u8 ack64: 1; - u8 mpc_map: 1; - u8 frozen: 1; - u8 reset_transient: 1; - u8 reset_reason: 4; - u8 csum_reqd: 1; -}; - -enum tcp_queue { - TCP_FRAG_IN_WRITE_QUEUE = 0, - TCP_FRAG_IN_RTX_QUEUE = 1, -}; - -enum tcp_ca_ack_event_flags { - CA_ACK_SLOWPATH = 1, - CA_ACK_WIN_UPDATE = 2, - CA_ACK_ECE = 4, -}; - -struct tcp_sacktag_state { - u64 first_sackt; - u64 last_sackt; - u32 reord; - u32 sack_delivered; - int flag; - unsigned int mss_now; - struct rate_sample *rate; -}; - -enum pkt_hash_types { - PKT_HASH_TYPE_NONE = 0, - PKT_HASH_TYPE_L2 = 1, - PKT_HASH_TYPE_L3 = 2, - PKT_HASH_TYPE_L4 = 3, -}; - -enum { - BPF_WRITE_HDR_TCP_CURRENT_MSS = 1, - BPF_WRITE_HDR_TCP_SYNACK_COOKIE = 2, -}; - -enum tsq_flags { - TSQF_THROTTLED = 1, - TSQF_QUEUED = 2, - TCPF_TSQ_DEFERRED = 4, - TCPF_WRITE_TIMER_DEFERRED = 8, - TCPF_DELACK_TIMER_DEFERRED = 16, - TCPF_MTU_REDUCED_DEFERRED = 32, -}; - -struct mptcp_rm_list { - u8 ids[8]; - u8 nr; -}; - -struct mptcp_addr_info { - u8 id; - sa_family_t family; - __be16 port; - union { - struct in_addr addr; - struct in6_addr addr6; - }; -}; - -struct mptcp_out_options { - u16 suboptions; - u64 sndr_key; - u64 rcvr_key; - u64 ahmac; - struct mptcp_addr_info addr; - struct mptcp_rm_list rm_list; - u8 join_id; - u8 backup; - u8 reset_reason: 4; - u8 reset_transient: 1; - u8 csum_reqd: 1; - u8 allow_join_id0: 1; - u32 nonce; - u64 thmac; - u32 token; - u8 hmac[20]; - struct mptcp_ext ext_copy; -}; - -struct tcp_out_options { - u16 options; - u16 mss; - u8 ws; - u8 num_sack_blocks; - u8 hash_size; - u8 bpf_opt_len; - __u8 *hash_location; - __u32 tsval; - __u32 tsecr; - struct tcp_fastopen_cookie *fastopen_cookie; - struct mptcp_out_options mptcp; -}; - -struct tsq_tasklet { - struct tasklet_struct tasklet; - struct list_head head; -}; - -struct tcp_md5sig { - struct __kernel_sockaddr_storage tcpm_addr; - __u8 tcpm_flags; - __u8 tcpm_prefixlen; - __u16 tcpm_keylen; - int tcpm_ifindex; - __u8 tcpm_key[80]; -}; - -struct icmp_err { - int errno; - unsigned int fatal: 1; -}; - -enum tcp_tw_status { - TCP_TW_SUCCESS = 0, - TCP_TW_RST = 1, - TCP_TW_ACK = 2, - TCP_TW_SYN = 3, -}; - -struct tcp4_pseudohdr { - __be32 saddr; - __be32 daddr; - __u8 pad; - __u8 protocol; - __be16 len; -}; - -enum tcp_seq_states { - TCP_SEQ_STATE_LISTENING = 0, - TCP_SEQ_STATE_ESTABLISHED = 1, -}; - -struct tcp_seq_afinfo { - sa_family_t family; -}; - -struct tcp_iter_state { - struct seq_net_private p; - enum tcp_seq_states state; - struct sock *syn_wait_sk; - struct tcp_seq_afinfo *bpf_seq_afinfo; - int bucket; - int offset; - int sbucket; - int num; - loff_t last_pos; -}; - -struct bpf_iter__tcp { - union { - struct bpf_iter_meta *meta; - }; - union { - struct sock_common *sk_common; - }; - uid_t uid; -}; - -enum tcp_metric_index { - TCP_METRIC_RTT = 0, - TCP_METRIC_RTTVAR = 1, - TCP_METRIC_SSTHRESH = 2, - TCP_METRIC_CWND = 3, - TCP_METRIC_REORDERING = 4, - TCP_METRIC_RTT_US = 5, - TCP_METRIC_RTTVAR_US = 6, - __TCP_METRIC_MAX = 7, -}; - -enum { - TCP_METRICS_ATTR_UNSPEC = 0, - TCP_METRICS_ATTR_ADDR_IPV4 = 1, - TCP_METRICS_ATTR_ADDR_IPV6 = 2, - TCP_METRICS_ATTR_AGE = 3, - TCP_METRICS_ATTR_TW_TSVAL = 4, - TCP_METRICS_ATTR_TW_TS_STAMP = 5, - TCP_METRICS_ATTR_VALS = 6, - TCP_METRICS_ATTR_FOPEN_MSS = 7, - TCP_METRICS_ATTR_FOPEN_SYN_DROPS = 8, - TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS = 9, - TCP_METRICS_ATTR_FOPEN_COOKIE = 10, - TCP_METRICS_ATTR_SADDR_IPV4 = 11, - TCP_METRICS_ATTR_SADDR_IPV6 = 12, - TCP_METRICS_ATTR_PAD = 13, - __TCP_METRICS_ATTR_MAX = 14, -}; - -enum { - TCP_METRICS_CMD_UNSPEC = 0, - TCP_METRICS_CMD_GET = 1, - TCP_METRICS_CMD_DEL = 2, - __TCP_METRICS_CMD_MAX = 3, -}; - -struct tcp_fastopen_metrics { - u16 mss; - u16 syn_loss: 10; - u16 try_exp: 2; - long unsigned int last_syn_loss; - struct tcp_fastopen_cookie cookie; -}; - -struct tcp_metrics_block { - struct tcp_metrics_block *tcpm_next; - possible_net_t tcpm_net; - struct inetpeer_addr tcpm_saddr; - struct inetpeer_addr tcpm_daddr; - long unsigned int tcpm_stamp; - u32 tcpm_lock; - u32 tcpm_vals[5]; - struct tcp_fastopen_metrics tcpm_fastopen; - struct callback_head callback_head; -}; - -struct tcpm_hash_bucket { - struct tcp_metrics_block *chain; -}; - -struct icmp_filter { - __u32 data; -}; - -struct raw_iter_state { - struct seq_net_private p; - int bucket; -}; - -struct raw_sock { - struct inet_sock inet; - struct icmp_filter filter; - u32 ipmr_table; -}; - -struct raw_frag_vec { - struct msghdr *msg; - union { - struct icmphdr icmph; - char c[1]; - } hdr; - int hlen; -}; - -struct ip_tunnel_encap { - u16 type; - u16 flags; - __be16 sport; - __be16 dport; -}; - -struct ip_tunnel_encap_ops { - size_t (*encap_hlen)(struct ip_tunnel_encap *); - int (*build_header)(struct sk_buff *, struct ip_tunnel_encap *, u8 *, struct flowi4 *); - int (*err_handler)(struct sk_buff *, u32); -}; - -struct udp_skb_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - __u16 cscov; - __u8 partial_cov; -}; - -struct udp_dev_scratch { - u32 _tsize_state; - u16 len; - bool is_linear; - bool csum_unnecessary; -}; - -struct udp_seq_afinfo { - sa_family_t family; - struct udp_table *udp_table; -}; - -struct udp_iter_state { - struct seq_net_private p; - int bucket; - struct udp_seq_afinfo *bpf_seq_afinfo; -}; - -struct bpf_iter__udp { - union { - struct bpf_iter_meta *meta; - }; - union { - struct udp_sock *udp_sk; - }; - uid_t uid; - int: 32; - int bucket; -}; - -struct inet_protosw { - struct list_head list; - short unsigned int type; - short unsigned int protocol; - struct proto *prot; - const struct proto_ops *ops; - unsigned char flags; -}; - -typedef struct sk_buff * (*gro_receive_t)(struct list_head *, struct sk_buff *); - -typedef struct sk_buff * (*gro_receive_sk_t)(struct sock *, struct list_head *, struct sk_buff *); - -typedef struct sock * (*udp_lookup_t)(const struct sk_buff *, __be16, __be16); - -struct arpreq { - struct sockaddr arp_pa; - struct sockaddr arp_ha; - int arp_flags; - struct sockaddr arp_netmask; - char arp_dev[16]; -}; - -typedef struct { - char ax25_call[7]; -} ax25_address; - -enum { - AX25_VALUES_IPDEFMODE = 0, - AX25_VALUES_AXDEFMODE = 1, - AX25_VALUES_BACKOFF = 2, - AX25_VALUES_CONMODE = 3, - AX25_VALUES_WINDOW = 4, - AX25_VALUES_EWINDOW = 5, - AX25_VALUES_T1 = 6, - AX25_VALUES_T2 = 7, - AX25_VALUES_T3 = 8, - AX25_VALUES_IDLE = 9, - AX25_VALUES_N2 = 10, - AX25_VALUES_PACLEN = 11, - AX25_VALUES_PROTOCOL = 12, - AX25_VALUES_DS_TIMEOUT = 13, - AX25_MAX_VALUES = 14, -}; - -enum ip_conntrack_status { - IPS_EXPECTED_BIT = 0, - IPS_EXPECTED = 1, - IPS_SEEN_REPLY_BIT = 1, - IPS_SEEN_REPLY = 2, - IPS_ASSURED_BIT = 2, - IPS_ASSURED = 4, - IPS_CONFIRMED_BIT = 3, - IPS_CONFIRMED = 8, - IPS_SRC_NAT_BIT = 4, - IPS_SRC_NAT = 16, - IPS_DST_NAT_BIT = 5, - IPS_DST_NAT = 32, - IPS_NAT_MASK = 48, - IPS_SEQ_ADJUST_BIT = 6, - IPS_SEQ_ADJUST = 64, - IPS_SRC_NAT_DONE_BIT = 7, - IPS_SRC_NAT_DONE = 128, - IPS_DST_NAT_DONE_BIT = 8, - IPS_DST_NAT_DONE = 256, - IPS_NAT_DONE_MASK = 384, - IPS_DYING_BIT = 9, - IPS_DYING = 512, - IPS_FIXED_TIMEOUT_BIT = 10, - IPS_FIXED_TIMEOUT = 1024, - IPS_TEMPLATE_BIT = 11, - IPS_TEMPLATE = 2048, - IPS_UNTRACKED_BIT = 12, - IPS_UNTRACKED = 4096, - IPS_NAT_CLASH_BIT = 12, - IPS_NAT_CLASH = 4096, - IPS_HELPER_BIT = 13, - IPS_HELPER = 8192, - IPS_OFFLOAD_BIT = 14, - IPS_OFFLOAD = 16384, - IPS_HW_OFFLOAD_BIT = 15, - IPS_HW_OFFLOAD = 32768, - IPS_UNCHANGEABLE_MASK = 56313, - __IPS_MAX_BIT = 16, -}; - -enum { - XFRM_LOOKUP_ICMP = 1, - XFRM_LOOKUP_QUEUE = 2, - XFRM_LOOKUP_KEEP_DST_REF = 4, -}; - -struct icmp_ext_hdr { - __u8 reserved1: 4; - __u8 version: 4; - __u8 reserved2; - __sum16 checksum; -}; - -struct icmp_extobj_hdr { - __be16 length; - __u8 class_num; - __u8 class_type; -}; - -struct icmp_ext_echo_ctype3_hdr { - __be16 afi; - __u8 addrlen; - __u8 reserved; -}; - -struct icmp_ext_echo_iio { - struct icmp_extobj_hdr extobj_hdr; - union { - char name[16]; - __be32 ifindex; - struct { - struct icmp_ext_echo_ctype3_hdr ctype3_hdr; - union { - __be32 ipv4_addr; - struct in6_addr ipv6_addr; - } ip_addr; - } addr; - } ident; -}; - -struct icmp_bxm { - struct sk_buff *skb; - int offset; - int data_len; - struct { - struct icmphdr icmph; - __be32 times[3]; - } data; - int head_len; - struct ip_options_data replyopts; -}; - -struct icmp_control { - bool (*handler)(struct sk_buff *); - short int error; -}; - -struct ifaddrmsg { - __u8 ifa_family; - __u8 ifa_prefixlen; - __u8 ifa_flags; - __u8 ifa_scope; - __u32 ifa_index; -}; - -enum { - IFA_UNSPEC = 0, - IFA_ADDRESS = 1, - IFA_LOCAL = 2, - IFA_LABEL = 3, - IFA_BROADCAST = 4, - IFA_ANYCAST = 5, - IFA_CACHEINFO = 6, - IFA_MULTICAST = 7, - IFA_FLAGS = 8, - IFA_RT_PRIORITY = 9, - IFA_TARGET_NETNSID = 10, - __IFA_MAX = 11, -}; - -struct ifa_cacheinfo { - __u32 ifa_prefered; - __u32 ifa_valid; - __u32 cstamp; - __u32 tstamp; -}; - -enum { - IFLA_INET_UNSPEC = 0, - IFLA_INET_CONF = 1, - __IFLA_INET_MAX = 2, -}; - -struct in_validator_info { - __be32 ivi_addr; - struct in_device *ivi_dev; - struct netlink_ext_ack *extack; -}; - -struct netconfmsg { - __u8 ncm_family; -}; - -enum { - NETCONFA_UNSPEC = 0, - NETCONFA_IFINDEX = 1, - NETCONFA_FORWARDING = 2, - NETCONFA_RP_FILTER = 3, - NETCONFA_MC_FORWARDING = 4, - NETCONFA_PROXY_NEIGH = 5, - NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN = 6, - NETCONFA_INPUT = 7, - NETCONFA_BC_FORWARDING = 8, - __NETCONFA_MAX = 9, -}; - -struct inet_fill_args { - u32 portid; - u32 seq; - int event; - unsigned int flags; - int netnsid; - int ifindex; -}; - -struct devinet_sysctl_table { - struct ctl_table_header *sysctl_header; - struct ctl_table devinet_vars[33]; -}; - -struct rtentry { - long unsigned int rt_pad1; - struct sockaddr rt_dst; - struct sockaddr rt_gateway; - struct sockaddr rt_genmask; - short unsigned int rt_flags; - short int rt_pad2; - long unsigned int rt_pad3; - void *rt_pad4; - short int rt_metric; - char *rt_dev; - long unsigned int rt_mtu; - long unsigned int rt_window; - short unsigned int rt_irtt; -}; - -struct pingv6_ops { - int (*ipv6_recv_error)(struct sock *, struct msghdr *, int, int *); - void (*ip6_datagram_recv_common_ctl)(struct sock *, struct msghdr *, struct sk_buff *); - void (*ip6_datagram_recv_specific_ctl)(struct sock *, struct msghdr *, struct sk_buff *); - int (*icmpv6_err_convert)(u8, u8, int *); - void (*ipv6_icmp_error)(struct sock *, struct sk_buff *, int, __be16, u32, u8 *); - int (*ipv6_chk_addr)(struct net *, const struct in6_addr *, const struct net_device *, int); -}; - -struct compat_rtentry { - u32 rt_pad1; - struct sockaddr rt_dst; - struct sockaddr rt_gateway; - struct sockaddr rt_genmask; - short unsigned int rt_flags; - short int rt_pad2; - u32 rt_pad3; - unsigned char rt_tos; - unsigned char rt_class; - short int rt_pad4; - short int rt_metric; - compat_uptr_t rt_dev; - u32 rt_mtu; - u32 rt_window; - short unsigned int rt_irtt; -}; - -struct igmphdr { - __u8 type; - __u8 code; - __sum16 csum; - __be32 group; -}; - -struct igmpv3_grec { - __u8 grec_type; - __u8 grec_auxwords; - __be16 grec_nsrcs; - __be32 grec_mca; - __be32 grec_src[0]; -}; - -struct igmpv3_report { - __u8 type; - __u8 resv1; - __sum16 csum; - __be16 resv2; - __be16 ngrec; - struct igmpv3_grec grec[0]; -}; - -struct igmpv3_query { - __u8 type; - __u8 code; - __sum16 csum; - __be32 group; - __u8 qrv: 3; - __u8 suppress: 1; - __u8 resv: 4; - __u8 qqic; - __be16 nsrcs; - __be32 srcs[0]; -}; - -struct igmp_mc_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct in_device *in_dev; -}; - -struct igmp_mcf_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct in_device *idev; - struct ip_mc_list *im; -}; - -struct fib_config { - u8 fc_dst_len; - u8 fc_tos; - u8 fc_protocol; - u8 fc_scope; - u8 fc_type; - u8 fc_gw_family; - u32 fc_table; - __be32 fc_dst; - union { - __be32 fc_gw4; - struct in6_addr fc_gw6; - }; - int fc_oif; - u32 fc_flags; - u32 fc_priority; - __be32 fc_prefsrc; - u32 fc_nh_id; - struct nlattr *fc_mx; - struct rtnexthop *fc_mp; - int fc_mx_len; - int fc_mp_len; - u32 fc_flow; - u32 fc_nlflags; - struct nl_info fc_nlinfo; - struct nlattr *fc_encap; - u16 fc_encap_type; -}; - -struct fib_result_nl { - __be32 fl_addr; - u32 fl_mark; - unsigned char fl_tos; - unsigned char fl_scope; - unsigned char tb_id_in; - unsigned char tb_id; - unsigned char prefixlen; - unsigned char nh_sel; - unsigned char type; - unsigned char scope; - int err; -}; - -struct fib_dump_filter { - u32 table_id; - bool filter_set; - bool dump_routes; - bool dump_exceptions; - unsigned char protocol; - unsigned char rt_type; - unsigned int flags; - struct net_device *dev; -}; - -struct fib_nh_notifier_info { - struct fib_notifier_info info; - struct fib_nh *fib_nh; -}; - -struct fib_entry_notifier_info { - struct fib_notifier_info info; - u32 dst; - int dst_len; - struct fib_info *fi; - u8 tos; - u8 type; - u32 tb_id; -}; - -typedef unsigned int t_key; - -struct key_vector { - t_key key; - unsigned char pos; - unsigned char bits; - unsigned char slen; - union { - struct hlist_head leaf; - struct key_vector *tnode[0]; - }; -}; - -struct tnode { - struct callback_head rcu; - t_key empty_children; - t_key full_children; - struct key_vector *parent; - struct key_vector kv[1]; -}; - -struct trie_use_stats { - unsigned int gets; - unsigned int backtrack; - unsigned int semantic_match_passed; - unsigned int semantic_match_miss; - unsigned int null_node_hit; - unsigned int resize_node_skipped; -}; - -struct trie_stat { - unsigned int totdepth; - unsigned int maxdepth; - unsigned int tnodes; - unsigned int leaves; - unsigned int nullpointers; - unsigned int prefixes; - unsigned int nodesizes[32]; -}; - -struct trie { - struct key_vector kv[1]; - struct trie_use_stats *stats; -}; - -struct fib_trie_iter { - struct seq_net_private p; - struct fib_table *tb; - struct key_vector *tnode; - unsigned int index; - unsigned int depth; -}; - -struct fib_route_iter { - struct seq_net_private p; - struct fib_table *main_tb; - struct key_vector *tnode; - loff_t pos; - t_key key; -}; - -struct ipfrag_skb_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - }; - struct sk_buff *next_frag; - int frag_run_len; -}; - -struct icmpv6_echo { - __be16 identifier; - __be16 sequence; -}; - -struct icmpv6_nd_advt { - __u32 reserved: 5; - __u32 override: 1; - __u32 solicited: 1; - __u32 router: 1; - __u32 reserved2: 24; -}; - -struct icmpv6_nd_ra { - __u8 hop_limit; - __u8 reserved: 3; - __u8 router_pref: 2; - __u8 home_agent: 1; - __u8 other: 1; - __u8 managed: 1; - __be16 rt_lifetime; -}; - -struct icmp6hdr { - __u8 icmp6_type; - __u8 icmp6_code; - __sum16 icmp6_cksum; - union { - __be32 un_data32[1]; - __be16 un_data16[2]; - __u8 un_data8[4]; - struct icmpv6_echo u_echo; - struct icmpv6_nd_advt u_nd_advt; - struct icmpv6_nd_ra u_nd_ra; - } icmp6_dataun; -}; - -struct ping_iter_state { - struct seq_net_private p; - int bucket; - sa_family_t family; -}; - -struct pingfakehdr { - struct icmphdr icmph; - struct msghdr *msg; - sa_family_t family; - __wsum wcheck; -}; - -struct ping_table { - struct hlist_nulls_head hash[64]; - rwlock_t lock; -}; - -enum lwtunnel_ip_t { - LWTUNNEL_IP_UNSPEC = 0, - LWTUNNEL_IP_ID = 1, - LWTUNNEL_IP_DST = 2, - LWTUNNEL_IP_SRC = 3, - LWTUNNEL_IP_TTL = 4, - LWTUNNEL_IP_TOS = 5, - LWTUNNEL_IP_FLAGS = 6, - LWTUNNEL_IP_PAD = 7, - LWTUNNEL_IP_OPTS = 8, - __LWTUNNEL_IP_MAX = 9, -}; - -enum lwtunnel_ip6_t { - LWTUNNEL_IP6_UNSPEC = 0, - LWTUNNEL_IP6_ID = 1, - LWTUNNEL_IP6_DST = 2, - LWTUNNEL_IP6_SRC = 3, - LWTUNNEL_IP6_HOPLIMIT = 4, - LWTUNNEL_IP6_TC = 5, - LWTUNNEL_IP6_FLAGS = 6, - LWTUNNEL_IP6_PAD = 7, - LWTUNNEL_IP6_OPTS = 8, - __LWTUNNEL_IP6_MAX = 9, -}; - -enum { - LWTUNNEL_IP_OPTS_UNSPEC = 0, - LWTUNNEL_IP_OPTS_GENEVE = 1, - LWTUNNEL_IP_OPTS_VXLAN = 2, - LWTUNNEL_IP_OPTS_ERSPAN = 3, - __LWTUNNEL_IP_OPTS_MAX = 4, -}; - -enum { - LWTUNNEL_IP_OPT_GENEVE_UNSPEC = 0, - LWTUNNEL_IP_OPT_GENEVE_CLASS = 1, - LWTUNNEL_IP_OPT_GENEVE_TYPE = 2, - LWTUNNEL_IP_OPT_GENEVE_DATA = 3, - __LWTUNNEL_IP_OPT_GENEVE_MAX = 4, -}; - -enum { - LWTUNNEL_IP_OPT_VXLAN_UNSPEC = 0, - LWTUNNEL_IP_OPT_VXLAN_GBP = 1, - __LWTUNNEL_IP_OPT_VXLAN_MAX = 2, -}; - -enum { - LWTUNNEL_IP_OPT_ERSPAN_UNSPEC = 0, - LWTUNNEL_IP_OPT_ERSPAN_VER = 1, - LWTUNNEL_IP_OPT_ERSPAN_INDEX = 2, - LWTUNNEL_IP_OPT_ERSPAN_DIR = 3, - LWTUNNEL_IP_OPT_ERSPAN_HWID = 4, - __LWTUNNEL_IP_OPT_ERSPAN_MAX = 5, -}; - -struct ip6_tnl_encap_ops { - size_t (*encap_hlen)(struct ip_tunnel_encap *); - int (*build_header)(struct sk_buff *, struct ip_tunnel_encap *, u8 *, struct flowi6 *); - int (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32); -}; - -struct geneve_opt { - __be16 opt_class; - u8 type; - u8 length: 5; - u8 r3: 1; - u8 r2: 1; - u8 r1: 1; - u8 opt_data[0]; -}; - -struct vxlan_metadata { - u32 gbp; -}; - -struct erspan_md2 { - __be32 timestamp; - __be16 sgt; - __u8 hwid_upper: 2; - __u8 ft: 5; - __u8 p: 1; - __u8 o: 1; - __u8 gra: 2; - __u8 dir: 1; - __u8 hwid: 4; -}; - -struct erspan_metadata { - int version; - union { - __be32 index; - struct erspan_md2 md2; - } u; -}; - -struct nhmsg { - unsigned char nh_family; - unsigned char nh_scope; - unsigned char nh_protocol; - unsigned char resvd; - unsigned int nh_flags; -}; - -struct nexthop_grp { - __u32 id; - __u8 weight; - __u8 resvd1; - __u16 resvd2; -}; - -enum { - NEXTHOP_GRP_TYPE_MPATH = 0, - NEXTHOP_GRP_TYPE_RES = 1, - __NEXTHOP_GRP_TYPE_MAX = 2, -}; - -enum { - NHA_UNSPEC = 0, - NHA_ID = 1, - NHA_GROUP = 2, - NHA_GROUP_TYPE = 3, - NHA_BLACKHOLE = 4, - NHA_OIF = 5, - NHA_GATEWAY = 6, - NHA_ENCAP_TYPE = 7, - NHA_ENCAP = 8, - NHA_GROUPS = 9, - NHA_MASTER = 10, - NHA_FDB = 11, - NHA_RES_GROUP = 12, - NHA_RES_BUCKET = 13, - __NHA_MAX = 14, -}; - -enum { - NHA_RES_GROUP_UNSPEC = 0, - NHA_RES_GROUP_PAD = 0, - NHA_RES_GROUP_BUCKETS = 1, - NHA_RES_GROUP_IDLE_TIMER = 2, - NHA_RES_GROUP_UNBALANCED_TIMER = 3, - NHA_RES_GROUP_UNBALANCED_TIME = 4, - __NHA_RES_GROUP_MAX = 5, -}; - -enum { - NHA_RES_BUCKET_UNSPEC = 0, - NHA_RES_BUCKET_PAD = 0, - NHA_RES_BUCKET_INDEX = 1, - NHA_RES_BUCKET_IDLE_TIME = 2, - NHA_RES_BUCKET_NH_ID = 3, - __NHA_RES_BUCKET_MAX = 4, -}; - -struct nh_config { - u32 nh_id; - u8 nh_family; - u8 nh_protocol; - u8 nh_blackhole; - u8 nh_fdb; - u32 nh_flags; - int nh_ifindex; - struct net_device *dev; - union { - __be32 ipv4; - struct in6_addr ipv6; - } gw; - struct nlattr *nh_grp; - u16 nh_grp_type; - u16 nh_grp_res_num_buckets; - long unsigned int nh_grp_res_idle_timer; - long unsigned int nh_grp_res_unbalanced_timer; - bool nh_grp_res_has_num_buckets; - bool nh_grp_res_has_idle_timer; - bool nh_grp_res_has_unbalanced_timer; - struct nlattr *nh_encap; - u16 nh_encap_type; - u32 nlflags; - struct nl_info nlinfo; -}; - -enum nexthop_event_type { - NEXTHOP_EVENT_DEL = 0, - NEXTHOP_EVENT_REPLACE = 1, - NEXTHOP_EVENT_RES_TABLE_PRE_REPLACE = 2, - NEXTHOP_EVENT_BUCKET_REPLACE = 3, -}; - -enum nh_notifier_info_type { - NH_NOTIFIER_INFO_TYPE_SINGLE = 0, - NH_NOTIFIER_INFO_TYPE_GRP = 1, - NH_NOTIFIER_INFO_TYPE_RES_TABLE = 2, - NH_NOTIFIER_INFO_TYPE_RES_BUCKET = 3, -}; - -struct nh_notifier_single_info { - struct net_device *dev; - u8 gw_family; - union { - __be32 ipv4; - struct in6_addr ipv6; - }; - u8 is_reject: 1; - u8 is_fdb: 1; - u8 has_encap: 1; -}; - -struct nh_notifier_grp_entry_info { - u8 weight; - u32 id; - struct nh_notifier_single_info nh; -}; - -struct nh_notifier_grp_info { - u16 num_nh; - bool is_fdb; - struct nh_notifier_grp_entry_info nh_entries[0]; -}; - -struct nh_notifier_res_bucket_info { - u16 bucket_index; - unsigned int idle_timer_ms; - bool force; - struct nh_notifier_single_info old_nh; - struct nh_notifier_single_info new_nh; -}; - -struct nh_notifier_res_table_info { - u16 num_nh_buckets; - struct nh_notifier_single_info nhs[0]; -}; - -struct nh_notifier_info { - struct net *net; - struct netlink_ext_ack *extack; - u32 id; - enum nh_notifier_info_type type; - union { - struct nh_notifier_single_info *nh; - struct nh_notifier_grp_info *nh_grp; - struct nh_notifier_res_table_info *nh_res_table; - struct nh_notifier_res_bucket_info *nh_res_bucket; - }; -}; - -struct nh_dump_filter { - u32 nh_id; - int dev_idx; - int master_idx; - bool group_filter; - bool fdb_filter; - u32 res_bucket_nh_id; -}; - -struct rtm_dump_nh_ctx { - u32 idx; -}; - -struct rtm_dump_res_bucket_ctx { - struct rtm_dump_nh_ctx nh; - u16 bucket_index; - u32 done_nh_idx; -}; - -struct rtm_dump_nexthop_bucket_data { - struct rtm_dump_res_bucket_ctx *ctx; - struct nh_dump_filter filter; -}; - -struct inet6_protocol { - void (*early_demux)(struct sk_buff *); - void (*early_demux_handler)(struct sk_buff *); - int (*handler)(struct sk_buff *); - int (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32); - unsigned int flags; -}; - -struct snmp_mib { - const char *name; - int entry; -}; - -struct fib4_rule { - struct fib_rule common; - u8 dst_len; - u8 src_len; - u8 tos; - __be32 src; - __be32 srcmask; - __be32 dst; - __be32 dstmask; - u32 tclassid; -}; - -enum { - PIM_TYPE_HELLO = 0, - PIM_TYPE_REGISTER = 1, - PIM_TYPE_REGISTER_STOP = 2, - PIM_TYPE_JOIN_PRUNE = 3, - PIM_TYPE_BOOTSTRAP = 4, - PIM_TYPE_ASSERT = 5, - PIM_TYPE_GRAFT = 6, - PIM_TYPE_GRAFT_ACK = 7, - PIM_TYPE_CANDIDATE_RP_ADV = 8, -}; - -struct pimreghdr { - __u8 type; - __u8 reserved; - __be16 csum; - __be32 flags; -}; - -typedef short unsigned int vifi_t; - -struct vifctl { - vifi_t vifc_vifi; - unsigned char vifc_flags; - unsigned char vifc_threshold; - unsigned int vifc_rate_limit; - union { - struct in_addr vifc_lcl_addr; - int vifc_lcl_ifindex; - }; - struct in_addr vifc_rmt_addr; -}; - -struct mfcctl { - struct in_addr mfcc_origin; - struct in_addr mfcc_mcastgrp; - vifi_t mfcc_parent; - unsigned char mfcc_ttls[32]; - unsigned int mfcc_pkt_cnt; - unsigned int mfcc_byte_cnt; - unsigned int mfcc_wrong_if; - int mfcc_expire; -}; - -struct sioc_sg_req { - struct in_addr src; - struct in_addr grp; - long unsigned int pktcnt; - long unsigned int bytecnt; - long unsigned int wrong_if; -}; - -struct sioc_vif_req { - vifi_t vifi; - long unsigned int icount; - long unsigned int ocount; - long unsigned int ibytes; - long unsigned int obytes; -}; - -struct igmpmsg { - __u32 unused1; - __u32 unused2; - unsigned char im_msgtype; - unsigned char im_mbz; - unsigned char im_vif; - unsigned char im_vif_hi; - struct in_addr im_src; - struct in_addr im_dst; -}; - -enum { - IPMRA_TABLE_UNSPEC = 0, - IPMRA_TABLE_ID = 1, - IPMRA_TABLE_CACHE_RES_QUEUE_LEN = 2, - IPMRA_TABLE_MROUTE_REG_VIF_NUM = 3, - IPMRA_TABLE_MROUTE_DO_ASSERT = 4, - IPMRA_TABLE_MROUTE_DO_PIM = 5, - IPMRA_TABLE_VIFS = 6, - IPMRA_TABLE_MROUTE_DO_WRVIFWHOLE = 7, - __IPMRA_TABLE_MAX = 8, -}; - -enum { - IPMRA_VIF_UNSPEC = 0, - IPMRA_VIF = 1, - __IPMRA_VIF_MAX = 2, -}; - -enum { - IPMRA_VIFA_UNSPEC = 0, - IPMRA_VIFA_IFINDEX = 1, - IPMRA_VIFA_VIF_ID = 2, - IPMRA_VIFA_FLAGS = 3, - IPMRA_VIFA_BYTES_IN = 4, - IPMRA_VIFA_BYTES_OUT = 5, - IPMRA_VIFA_PACKETS_IN = 6, - IPMRA_VIFA_PACKETS_OUT = 7, - IPMRA_VIFA_LOCAL_ADDR = 8, - IPMRA_VIFA_REMOTE_ADDR = 9, - IPMRA_VIFA_PAD = 10, - __IPMRA_VIFA_MAX = 11, -}; - -enum { - IPMRA_CREPORT_UNSPEC = 0, - IPMRA_CREPORT_MSGTYPE = 1, - IPMRA_CREPORT_VIF_ID = 2, - IPMRA_CREPORT_SRC_ADDR = 3, - IPMRA_CREPORT_DST_ADDR = 4, - IPMRA_CREPORT_PKT = 5, - IPMRA_CREPORT_TABLE = 6, - __IPMRA_CREPORT_MAX = 7, -}; - -struct vif_device { - struct net_device *dev; - long unsigned int bytes_in; - long unsigned int bytes_out; - long unsigned int pkt_in; - long unsigned int pkt_out; - long unsigned int rate_limit; - unsigned char threshold; - short unsigned int flags; - int link; - struct netdev_phys_item_id dev_parent_id; - __be32 local; - __be32 remote; -}; - -struct vif_entry_notifier_info { - struct fib_notifier_info info; - struct net_device *dev; - short unsigned int vif_index; - short unsigned int vif_flags; - u32 tb_id; -}; - -enum { - MFC_STATIC = 1, - MFC_OFFLOAD = 2, -}; - -struct mr_mfc { - struct rhlist_head mnode; - short unsigned int mfc_parent; - int mfc_flags; - union { - struct { - long unsigned int expires; - struct sk_buff_head unresolved; - } unres; - struct { - long unsigned int last_assert; - int minvif; - int maxvif; - long unsigned int bytes; - long unsigned int pkt; - long unsigned int wrong_if; - long unsigned int lastuse; - unsigned char ttls[32]; - refcount_t refcount; - } res; - } mfc_un; - struct list_head list; - struct callback_head rcu; - void (*free)(struct callback_head *); -}; - -struct mfc_entry_notifier_info { - struct fib_notifier_info info; - struct mr_mfc *mfc; - u32 tb_id; -}; - -struct mr_table_ops { - const struct rhashtable_params *rht_params; - void *cmparg_any; -}; - -struct mr_table { - struct list_head list; - possible_net_t net; - struct mr_table_ops ops; - u32 id; - struct sock *mroute_sk; - struct timer_list ipmr_expire_timer; - struct list_head mfc_unres_queue; - struct vif_device vif_table[32]; - struct rhltable mfc_hash; - struct list_head mfc_cache_list; - int maxvif; - atomic_t cache_resolve_queue_len; - bool mroute_do_assert; - bool mroute_do_pim; - bool mroute_do_wrvifwhole; - int mroute_reg_vif_num; -}; - -struct mr_vif_iter { - struct seq_net_private p; - struct mr_table *mrt; - int ct; -}; - -struct mr_mfc_iter { - struct seq_net_private p; - struct mr_table *mrt; - struct list_head *cache; - spinlock_t *lock; -}; - -struct mfc_cache_cmp_arg { - __be32 mfc_mcastgrp; - __be32 mfc_origin; -}; - -struct mfc_cache { - struct mr_mfc _c; - union { - struct { - __be32 mfc_mcastgrp; - __be32 mfc_origin; - }; - struct mfc_cache_cmp_arg cmparg; - }; -}; - -struct ipmr_result { - struct mr_table *mrt; -}; - -struct compat_sioc_sg_req { - struct in_addr src; - struct in_addr grp; - compat_ulong_t pktcnt; - compat_ulong_t bytecnt; - compat_ulong_t wrong_if; -}; - -struct compat_sioc_vif_req { - vifi_t vifi; - compat_ulong_t icount; - compat_ulong_t ocount; - compat_ulong_t ibytes; - compat_ulong_t obytes; -}; - -struct rta_mfc_stats { - __u64 mfcs_packets; - __u64 mfcs_bytes; - __u64 mfcs_wrong_if; -}; - -struct bictcp { - u32 cnt; - u32 last_max_cwnd; - u32 last_cwnd; - u32 last_time; - u32 bic_origin_point; - u32 bic_K; - u32 delay_min; - u32 epoch_start; - u32 ack_cnt; - u32 tcp_cwnd; - u16 unused; - u8 sample_cnt; - u8 found; - u32 round_start; - u32 end_seq; - u32 last_ack; - u32 curr_rtt; -}; - -struct tls_rec { - struct list_head list; - int tx_ready; - int tx_flags; - struct sk_msg msg_plaintext; - struct sk_msg msg_encrypted; - struct scatterlist sg_aead_in[2]; - struct scatterlist sg_aead_out[2]; - char content_type; - struct scatterlist sg_content_type; - char aad_space[13]; - u8 iv_data[16]; - struct aead_request aead_req; - u8 aead_req_ctx[0]; -}; - -struct tx_work { - struct delayed_work work; - struct sock *sk; -}; - -struct tls_sw_context_tx { - struct crypto_aead *aead_send; - struct crypto_wait async_wait; - struct tx_work tx_work; - struct tls_rec *open_rec; - struct list_head tx_list; - atomic_t encrypt_pending; - spinlock_t encrypt_compl_lock; - int async_notify; - u8 async_capable: 1; - long unsigned int tx_bitmask; -}; - -enum { - TCP_BPF_IPV4 = 0, - TCP_BPF_IPV6 = 1, - TCP_BPF_NUM_PROTS = 2, -}; - -enum { - TCP_BPF_BASE = 0, - TCP_BPF_TX = 1, - TCP_BPF_NUM_CFGS = 2, -}; - -enum { - UDP_BPF_IPV4 = 0, - UDP_BPF_IPV6 = 1, - UDP_BPF_NUM_PROTS = 2, -}; - -struct cipso_v4_map_cache_bkt { - spinlock_t lock; - u32 size; - struct list_head list; -}; - -struct cipso_v4_map_cache_entry { - u32 hash; - unsigned char *key; - size_t key_len; - struct netlbl_lsm_cache *lsm_data; - u32 activity; - struct list_head list; -}; - -struct xfrm_policy_afinfo { - struct dst_ops *dst_ops; - struct dst_entry * (*dst_lookup)(struct net *, int, int, const xfrm_address_t *, const xfrm_address_t *, u32); - int (*get_saddr)(struct net *, int, xfrm_address_t *, xfrm_address_t *, u32); - int (*fill_dst)(struct xfrm_dst *, struct net_device *, const struct flowi *); - struct dst_entry * (*blackhole_route)(struct net *, struct dst_entry *); -}; - -struct xfrm_state_afinfo { - u8 family; - u8 proto; - const struct xfrm_type_offload *type_offload_esp; - const struct xfrm_type *type_esp; - const struct xfrm_type *type_ipip; - const struct xfrm_type *type_ipip6; - const struct xfrm_type *type_comp; - const struct xfrm_type *type_ah; - const struct xfrm_type *type_routing; - const struct xfrm_type *type_dstopts; - int (*output)(struct net *, struct sock *, struct sk_buff *); - int (*transport_finish)(struct sk_buff *, int); - void (*local_error)(struct sk_buff *, u32); -}; - -struct ip_tunnel; - -struct ip6_tnl; - -struct xfrm_tunnel_skb_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - union { - struct ip_tunnel *ip4; - struct ip6_tnl *ip6; - } tunnel; -}; - -struct xfrm_mode_skb_cb { - struct xfrm_tunnel_skb_cb header; - __be16 id; - __be16 frag_off; - u8 ihl; - u8 tos; - u8 ttl; - u8 protocol; - u8 optlen; - u8 flow_lbl[3]; -}; - -struct xfrm_spi_skb_cb { - struct xfrm_tunnel_skb_cb header; - unsigned int daddroff; - unsigned int family; - __be32 seq; -}; - -struct xfrm_input_afinfo { - u8 family; - bool is_ipip; - int (*callback)(struct sk_buff *, u8, int); -}; - -struct xfrm4_protocol { - int (*handler)(struct sk_buff *); - int (*input_handler)(struct sk_buff *, int, __be32, int); - int (*cb_handler)(struct sk_buff *, int); - int (*err_handler)(struct sk_buff *, u32); - struct xfrm4_protocol *next; - int priority; -}; - -typedef u64 (*btf_bpf_tcp_send_ack)(struct tcp_sock *, u32); - -enum { - XFRM_STATE_VOID = 0, - XFRM_STATE_ACQ = 1, - XFRM_STATE_VALID = 2, - XFRM_STATE_ERROR = 3, - XFRM_STATE_EXPIRED = 4, - XFRM_STATE_DEAD = 5, -}; - -struct xfrm_if; - -struct xfrm_if_cb { - struct xfrm_if * (*decode_session)(struct sk_buff *, short unsigned int); -}; - -struct xfrm_if_parms { - int link; - u32 if_id; -}; - -struct xfrm_if { - struct xfrm_if *next; - struct net_device *dev; - struct net *net; - struct xfrm_if_parms p; - struct gro_cells gro_cells; -}; - -struct xfrm_policy_walk { - struct xfrm_policy_walk_entry walk; - u8 type; - u32 seq; -}; - -struct xfrm_kmaddress { - xfrm_address_t local; - xfrm_address_t remote; - u32 reserved; - u16 family; -}; - -struct xfrm_migrate { - xfrm_address_t old_daddr; - xfrm_address_t old_saddr; - xfrm_address_t new_daddr; - xfrm_address_t new_saddr; - u8 proto; - u8 mode; - u16 reserved; - u32 reqid; - u16 old_family; - u16 new_family; -}; - -struct xfrmk_spdinfo { - u32 incnt; - u32 outcnt; - u32 fwdcnt; - u32 inscnt; - u32 outscnt; - u32 fwdscnt; - u32 spdhcnt; - u32 spdhmcnt; -}; - -struct ip6_mh { - __u8 ip6mh_proto; - __u8 ip6mh_hdrlen; - __u8 ip6mh_type; - __u8 ip6mh_reserved; - __u16 ip6mh_cksum; - __u8 data[0]; -}; - -struct xfrm_flo { - struct dst_entry *dst_orig; - u8 flags; -}; - -struct xfrm_pol_inexact_node { - struct rb_node node; - union { - xfrm_address_t addr; - struct callback_head rcu; - }; - u8 prefixlen; - struct rb_root root; - struct hlist_head hhead; -}; - -struct xfrm_pol_inexact_key { - possible_net_t net; - u32 if_id; - u16 family; - u8 dir; - u8 type; -}; - -struct xfrm_pol_inexact_bin { - struct xfrm_pol_inexact_key k; - struct rhash_head head; - struct hlist_head hhead; - seqcount_spinlock_t count; - struct rb_root root_d; - struct rb_root root_s; - struct list_head inexact_bins; - struct callback_head rcu; -}; - -enum xfrm_pol_inexact_candidate_type { - XFRM_POL_CAND_BOTH = 0, - XFRM_POL_CAND_SADDR = 1, - XFRM_POL_CAND_DADDR = 2, - XFRM_POL_CAND_ANY = 3, - XFRM_POL_CAND_MAX = 4, -}; - -struct xfrm_pol_inexact_candidates { - struct hlist_head *res[4]; -}; - -enum xfrm_ae_ftype_t { - XFRM_AE_UNSPEC = 0, - XFRM_AE_RTHR = 1, - XFRM_AE_RVAL = 2, - XFRM_AE_LVAL = 4, - XFRM_AE_ETHR = 8, - XFRM_AE_CR = 16, - XFRM_AE_CE = 32, - XFRM_AE_CU = 64, - __XFRM_AE_MAX = 65, -}; - -enum xfrm_nlgroups { - XFRMNLGRP_NONE = 0, - XFRMNLGRP_ACQUIRE = 1, - XFRMNLGRP_EXPIRE = 2, - XFRMNLGRP_SA = 3, - XFRMNLGRP_POLICY = 4, - XFRMNLGRP_AEVENTS = 5, - XFRMNLGRP_REPORT = 6, - XFRMNLGRP_MIGRATE = 7, - XFRMNLGRP_MAPPING = 8, - __XFRMNLGRP_MAX = 9, -}; - -enum { - XFRM_MODE_FLAG_TUNNEL = 1, -}; - -struct km_event { - union { - u32 hard; - u32 proto; - u32 byid; - u32 aevent; - u32 type; - } data; - u32 seq; - u32 portid; - u32 event; - struct net *net; -}; - -struct xfrm_mgr { - struct list_head list; - int (*notify)(struct xfrm_state *, const struct km_event *); - int (*acquire)(struct xfrm_state *, struct xfrm_tmpl *, struct xfrm_policy *); - struct xfrm_policy * (*compile_policy)(struct sock *, int, u8 *, int, int *); - int (*new_mapping)(struct xfrm_state *, xfrm_address_t *, __be16); - int (*notify_policy)(struct xfrm_policy *, int, const struct km_event *); - int (*report)(struct net *, u8, struct xfrm_selector *, xfrm_address_t *); - int (*migrate)(const struct xfrm_selector *, u8, u8, const struct xfrm_migrate *, int, const struct xfrm_kmaddress *, const struct xfrm_encap_tmpl *); - bool (*is_alive)(const struct km_event *); -}; - -struct xfrmk_sadinfo { - u32 sadhcnt; - u32 sadhmcnt; - u32 sadcnt; -}; - -struct xfrm_translator { - int (*alloc_compat)(struct sk_buff *, const struct nlmsghdr *); - struct nlmsghdr * (*rcv_msg_compat)(const struct nlmsghdr *, int, const struct nla_policy *, struct netlink_ext_ack *); - int (*xlate_user_policy_sockptr)(u8 **, int); - struct module *owner; -}; - -struct ip_beet_phdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 padlen; - __u8 reserved; -}; - -struct ip_tunnel_6rd_parm { - struct in6_addr prefix; - __be32 relay_prefix; - u16 prefixlen; - u16 relay_prefixlen; -}; - -struct ip_tunnel_prl_entry; - -struct ip_tunnel { - struct ip_tunnel *next; - struct hlist_node hash_node; - struct net_device *dev; - struct net *net; - long unsigned int err_time; - int err_count; - u32 i_seqno; - u32 o_seqno; - int tun_hlen; - u32 index; - u8 erspan_ver; - u8 dir; - u16 hwid; - struct dst_cache dst_cache; - struct ip_tunnel_parm parms; - int mlink; - int encap_hlen; - int hlen; - struct ip_tunnel_encap encap; - struct ip_tunnel_6rd_parm ip6rd; - struct ip_tunnel_prl_entry *prl; - unsigned int prl_count; - unsigned int ip_tnl_net_id; - struct gro_cells gro_cells; - __u32 fwmark; - bool collect_md; - bool ignore_df; -}; - -struct __ip6_tnl_parm { - char name[16]; - int link; - __u8 proto; - __u8 encap_limit; - __u8 hop_limit; - bool collect_md; - __be32 flowinfo; - __u32 flags; - struct in6_addr laddr; - struct in6_addr raddr; - __be16 i_flags; - __be16 o_flags; - __be32 i_key; - __be32 o_key; - __u32 fwmark; - __u32 index; - __u8 erspan_ver; - __u8 dir; - __u16 hwid; -}; - -struct ip6_tnl { - struct ip6_tnl *next; - struct net_device *dev; - struct net *net; - struct __ip6_tnl_parm parms; - struct flowi fl; - struct dst_cache dst_cache; - struct gro_cells gro_cells; - int err_count; - long unsigned int err_time; - __u32 i_seqno; - __u32 o_seqno; - int hlen; - int tun_hlen; - int encap_hlen; - struct ip_tunnel_encap encap; - int mlink; -}; - -struct xfrm_skb_cb { - struct xfrm_tunnel_skb_cb header; - union { - struct { - __u32 low; - __u32 hi; - } output; - struct { - __be32 low; - __be32 hi; - } input; - } seq; -}; - -struct ip_tunnel_prl_entry { - struct ip_tunnel_prl_entry *next; - __be32 addr; - u16 flags; - struct callback_head callback_head; -}; - -struct xfrm_trans_tasklet { - struct tasklet_struct tasklet; - struct sk_buff_head queue; -}; - -struct xfrm_trans_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - int (*finish)(struct net *, struct sock *, struct sk_buff *); - struct net *net; -}; - -struct xfrm_user_offload { - int ifindex; - __u8 flags; -}; - -struct sadb_alg { - __u8 sadb_alg_id; - __u8 sadb_alg_ivlen; - __u16 sadb_alg_minbits; - __u16 sadb_alg_maxbits; - __u16 sadb_alg_reserved; -}; - -struct xfrm_algo_aead_info { - char *geniv; - u16 icv_truncbits; -}; - -struct xfrm_algo_auth_info { - u16 icv_truncbits; - u16 icv_fullbits; -}; - -struct xfrm_algo_encr_info { - char *geniv; - u16 blockbits; - u16 defkeybits; -}; - -struct xfrm_algo_comp_info { - u16 threshold; -}; - -struct xfrm_algo_desc { - char *name; - char *compat; - u8 available: 1; - u8 pfkey_supported: 1; - union { - struct xfrm_algo_aead_info aead; - struct xfrm_algo_auth_info auth; - struct xfrm_algo_encr_info encr; - struct xfrm_algo_comp_info comp; - } uinfo; - struct sadb_alg desc; -}; - -struct xfrm_algo_list { - struct xfrm_algo_desc *algs; - int entries; - u32 type; - u32 mask; -}; - -struct xfrm_aead_name { - const char *name; - int icvbits; -}; - -enum { - XFRM_SHARE_ANY = 0, - XFRM_SHARE_SESSION = 1, - XFRM_SHARE_USER = 2, - XFRM_SHARE_UNIQUE = 3, -}; - -struct xfrm_user_tmpl { - struct xfrm_id id; - __u16 family; - xfrm_address_t saddr; - __u32 reqid; - __u8 mode; - __u8 share; - __u8 optional; - __u32 aalgos; - __u32 ealgos; - __u32 calgos; -}; - -struct xfrm_userpolicy_type { - __u8 type; - __u16 reserved1; - __u8 reserved2; -}; - -enum xfrm_sadattr_type_t { - XFRMA_SAD_UNSPEC = 0, - XFRMA_SAD_CNT = 1, - XFRMA_SAD_HINFO = 2, - __XFRMA_SAD_MAX = 3, -}; - -struct xfrmu_sadhinfo { - __u32 sadhcnt; - __u32 sadhmcnt; -}; - -enum xfrm_spdattr_type_t { - XFRMA_SPD_UNSPEC = 0, - XFRMA_SPD_INFO = 1, - XFRMA_SPD_HINFO = 2, - XFRMA_SPD_IPV4_HTHRESH = 3, - XFRMA_SPD_IPV6_HTHRESH = 4, - __XFRMA_SPD_MAX = 5, -}; - -struct xfrmu_spdinfo { - __u32 incnt; - __u32 outcnt; - __u32 fwdcnt; - __u32 inscnt; - __u32 outscnt; - __u32 fwdscnt; -}; - -struct xfrmu_spdhinfo { - __u32 spdhcnt; - __u32 spdhmcnt; -}; - -struct xfrmu_spdhthresh { - __u8 lbits; - __u8 rbits; -}; - -struct xfrm_usersa_info { - struct xfrm_selector sel; - struct xfrm_id id; - xfrm_address_t saddr; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - struct xfrm_stats stats; - __u32 seq; - __u32 reqid; - __u16 family; - __u8 mode; - __u8 replay_window; - __u8 flags; -}; - -struct xfrm_usersa_id { - xfrm_address_t daddr; - __be32 spi; - __u16 family; - __u8 proto; -}; - -struct xfrm_aevent_id { - struct xfrm_usersa_id sa_id; - xfrm_address_t saddr; - __u32 flags; - __u32 reqid; -}; - -struct xfrm_userspi_info { - struct xfrm_usersa_info info; - __u32 min; - __u32 max; -}; - -struct xfrm_userpolicy_info { - struct xfrm_selector sel; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - __u32 priority; - __u32 index; - __u8 dir; - __u8 action; - __u8 flags; - __u8 share; -}; - -struct xfrm_userpolicy_id { - struct xfrm_selector sel; - __u32 index; - __u8 dir; -}; - -struct xfrm_user_acquire { - struct xfrm_id id; - xfrm_address_t saddr; - struct xfrm_selector sel; - struct xfrm_userpolicy_info policy; - __u32 aalgos; - __u32 ealgos; - __u32 calgos; - __u32 seq; -}; - -struct xfrm_user_expire { - struct xfrm_usersa_info state; - __u8 hard; -}; - -struct xfrm_user_polexpire { - struct xfrm_userpolicy_info pol; - __u8 hard; -}; - -struct xfrm_usersa_flush { - __u8 proto; -}; - -struct xfrm_user_report { - __u8 proto; - struct xfrm_selector sel; -}; - -struct xfrm_user_kmaddress { - xfrm_address_t local; - xfrm_address_t remote; - __u32 reserved; - __u16 family; -}; - -struct xfrm_user_migrate { - xfrm_address_t old_daddr; - xfrm_address_t old_saddr; - xfrm_address_t new_daddr; - xfrm_address_t new_saddr; - __u8 proto; - __u8 mode; - __u16 reserved; - __u32 reqid; - __u16 old_family; - __u16 new_family; -}; - -struct xfrm_user_mapping { - struct xfrm_usersa_id id; - __u32 reqid; - xfrm_address_t old_saddr; - xfrm_address_t new_saddr; - __be16 old_sport; - __be16 new_sport; -}; - -struct xfrm_dump_info { - struct sk_buff *in_skb; - struct sk_buff *out_skb; - u32 nlmsg_seq; - u16 nlmsg_flags; -}; - -struct xfrm_link { - int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); - int (*start)(struct netlink_callback *); - int (*dump)(struct sk_buff *, struct netlink_callback *); - int (*done)(struct netlink_callback *); - const struct nla_policy *nla_pol; - int nla_max; -}; - -struct espintcp_msg { - struct sk_buff *skb; - struct sk_msg skmsg; - int offset; - int len; -}; - -struct espintcp_ctx { - struct strparser strp; - struct sk_buff_head ike_queue; - struct sk_buff_head out_queue; - struct espintcp_msg partial; - void (*saved_data_ready)(struct sock *); - void (*saved_write_space)(struct sock *); - void (*saved_destruct)(struct sock *); - struct work_struct work; - bool tx_running; -}; - -struct unix_stream_read_state { - int (*recv_actor)(struct sk_buff *, int, int, struct unix_stream_read_state *); - struct socket *socket; - struct msghdr *msg; - struct pipe_inode_info *pipe; - size_t size; - int flags; - unsigned int splice_flags; -}; - -struct ipv6_params { - __s32 disable_ipv6; - __s32 autoconf; -}; - -enum flowlabel_reflect { - FLOWLABEL_REFLECT_ESTABLISHED = 1, - FLOWLABEL_REFLECT_TCP_RESET = 2, - FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES = 4, -}; - -struct in6_rtmsg { - struct in6_addr rtmsg_dst; - struct in6_addr rtmsg_src; - struct in6_addr rtmsg_gateway; - __u32 rtmsg_type; - __u16 rtmsg_dst_len; - __u16 rtmsg_src_len; - __u32 rtmsg_metric; - long unsigned int rtmsg_info; - __u32 rtmsg_flags; - int rtmsg_ifindex; -}; - -struct compat_in6_rtmsg { - struct in6_addr rtmsg_dst; - struct in6_addr rtmsg_src; - struct in6_addr rtmsg_gateway; - u32 rtmsg_type; - u16 rtmsg_dst_len; - u16 rtmsg_src_len; - u32 rtmsg_metric; - u32 rtmsg_info; - u32 rtmsg_flags; - s32 rtmsg_ifindex; -}; - -struct ac6_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct inet6_dev *idev; -}; - -struct ip6_fraglist_iter { - struct ipv6hdr *tmp_hdr; - struct sk_buff *frag; - int offset; - unsigned int hlen; - __be32 frag_id; - u8 nexthdr; -}; - -struct ip6_frag_state { - u8 *prevhdr; - unsigned int hlen; - unsigned int mtu; - unsigned int left; - int offset; - int ptr; - int hroom; - int troom; - __be32 frag_id; - u8 nexthdr; -}; - -struct ip6_ra_chain { - struct ip6_ra_chain *next; - struct sock *sk; - int sel; - void (*destructor)(struct sock *); -}; - -struct ipcm6_cookie { - struct sockcm_cookie sockc; - __s16 hlimit; - __s16 tclass; - __s8 dontfrag; - struct ipv6_txoptions *opt; - __u16 gso_size; -}; - -enum { - IFLA_INET6_UNSPEC = 0, - IFLA_INET6_FLAGS = 1, - IFLA_INET6_CONF = 2, - IFLA_INET6_STATS = 3, - IFLA_INET6_MCAST = 4, - IFLA_INET6_CACHEINFO = 5, - IFLA_INET6_ICMP6STATS = 6, - IFLA_INET6_TOKEN = 7, - IFLA_INET6_ADDR_GEN_MODE = 8, - __IFLA_INET6_MAX = 9, -}; - -enum in6_addr_gen_mode { - IN6_ADDR_GEN_MODE_EUI64 = 0, - IN6_ADDR_GEN_MODE_NONE = 1, - IN6_ADDR_GEN_MODE_STABLE_PRIVACY = 2, - IN6_ADDR_GEN_MODE_RANDOM = 3, -}; - -struct ifla_cacheinfo { - __u32 max_reasm_len; - __u32 tstamp; - __u32 reachable_time; - __u32 retrans_time; -}; - -struct wpan_phy; - -struct wpan_dev_header_ops; - -struct wpan_dev { - struct wpan_phy *wpan_phy; - int iftype; - struct list_head list; - struct net_device *netdev; - const struct wpan_dev_header_ops *header_ops; - struct net_device *lowpan_dev; - u32 identifier; - __le16 pan_id; - __le16 short_addr; - __le64 extended_addr; - atomic_t bsn; - atomic_t dsn; - u8 min_be; - u8 max_be; - u8 csma_retries; - s8 frame_retries; - bool lbt; - bool promiscuous_mode; - bool ackreq; -}; - -struct prefixmsg { - unsigned char prefix_family; - unsigned char prefix_pad1; - short unsigned int prefix_pad2; - int prefix_ifindex; - unsigned char prefix_type; - unsigned char prefix_len; - unsigned char prefix_flags; - unsigned char prefix_pad3; -}; - -enum { - PREFIX_UNSPEC = 0, - PREFIX_ADDRESS = 1, - PREFIX_CACHEINFO = 2, - __PREFIX_MAX = 3, -}; - -struct prefix_cacheinfo { - __u32 preferred_time; - __u32 valid_time; -}; - -struct in6_ifreq { - struct in6_addr ifr6_addr; - __u32 ifr6_prefixlen; - int ifr6_ifindex; -}; - -enum { - DEVCONF_FORWARDING = 0, - DEVCONF_HOPLIMIT = 1, - DEVCONF_MTU6 = 2, - DEVCONF_ACCEPT_RA = 3, - DEVCONF_ACCEPT_REDIRECTS = 4, - DEVCONF_AUTOCONF = 5, - DEVCONF_DAD_TRANSMITS = 6, - DEVCONF_RTR_SOLICITS = 7, - DEVCONF_RTR_SOLICIT_INTERVAL = 8, - DEVCONF_RTR_SOLICIT_DELAY = 9, - DEVCONF_USE_TEMPADDR = 10, - DEVCONF_TEMP_VALID_LFT = 11, - DEVCONF_TEMP_PREFERED_LFT = 12, - DEVCONF_REGEN_MAX_RETRY = 13, - DEVCONF_MAX_DESYNC_FACTOR = 14, - DEVCONF_MAX_ADDRESSES = 15, - DEVCONF_FORCE_MLD_VERSION = 16, - DEVCONF_ACCEPT_RA_DEFRTR = 17, - DEVCONF_ACCEPT_RA_PINFO = 18, - DEVCONF_ACCEPT_RA_RTR_PREF = 19, - DEVCONF_RTR_PROBE_INTERVAL = 20, - DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN = 21, - DEVCONF_PROXY_NDP = 22, - DEVCONF_OPTIMISTIC_DAD = 23, - DEVCONF_ACCEPT_SOURCE_ROUTE = 24, - DEVCONF_MC_FORWARDING = 25, - DEVCONF_DISABLE_IPV6 = 26, - DEVCONF_ACCEPT_DAD = 27, - DEVCONF_FORCE_TLLAO = 28, - DEVCONF_NDISC_NOTIFY = 29, - DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL = 30, - DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL = 31, - DEVCONF_SUPPRESS_FRAG_NDISC = 32, - DEVCONF_ACCEPT_RA_FROM_LOCAL = 33, - DEVCONF_USE_OPTIMISTIC = 34, - DEVCONF_ACCEPT_RA_MTU = 35, - DEVCONF_STABLE_SECRET = 36, - DEVCONF_USE_OIF_ADDRS_ONLY = 37, - DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT = 38, - DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN = 39, - DEVCONF_DROP_UNICAST_IN_L2_MULTICAST = 40, - DEVCONF_DROP_UNSOLICITED_NA = 41, - DEVCONF_KEEP_ADDR_ON_DOWN = 42, - DEVCONF_RTR_SOLICIT_MAX_INTERVAL = 43, - DEVCONF_SEG6_ENABLED = 44, - DEVCONF_SEG6_REQUIRE_HMAC = 45, - DEVCONF_ENHANCED_DAD = 46, - DEVCONF_ADDR_GEN_MODE = 47, - DEVCONF_DISABLE_POLICY = 48, - DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN = 49, - DEVCONF_NDISC_TCLASS = 50, - DEVCONF_RPL_SEG_ENABLED = 51, - DEVCONF_RA_DEFRTR_METRIC = 52, - DEVCONF_MAX = 53, -}; - -enum { - INET6_IFADDR_STATE_PREDAD = 0, - INET6_IFADDR_STATE_DAD = 1, - INET6_IFADDR_STATE_POSTDAD = 2, - INET6_IFADDR_STATE_ERRDAD = 3, - INET6_IFADDR_STATE_DEAD = 4, -}; - -enum nl802154_cca_modes { - __NL802154_CCA_INVALID = 0, - NL802154_CCA_ENERGY = 1, - NL802154_CCA_CARRIER = 2, - NL802154_CCA_ENERGY_CARRIER = 3, - NL802154_CCA_ALOHA = 4, - NL802154_CCA_UWB_SHR = 5, - NL802154_CCA_UWB_MULTIPLEXED = 6, - __NL802154_CCA_ATTR_AFTER_LAST = 7, - NL802154_CCA_ATTR_MAX = 6, -}; - -enum nl802154_cca_opts { - NL802154_CCA_OPT_ENERGY_CARRIER_AND = 0, - NL802154_CCA_OPT_ENERGY_CARRIER_OR = 1, - __NL802154_CCA_OPT_ATTR_AFTER_LAST = 2, - NL802154_CCA_OPT_ATTR_MAX = 1, -}; - -enum nl802154_supported_bool_states { - NL802154_SUPPORTED_BOOL_FALSE = 0, - NL802154_SUPPORTED_BOOL_TRUE = 1, - __NL802154_SUPPORTED_BOOL_INVALD = 2, - NL802154_SUPPORTED_BOOL_BOTH = 3, - __NL802154_SUPPORTED_BOOL_AFTER_LAST = 4, - NL802154_SUPPORTED_BOOL_MAX = 3, -}; - -struct wpan_phy_supported { - u32 channels[32]; - u32 cca_modes; - u32 cca_opts; - u32 iftypes; - enum nl802154_supported_bool_states lbt; - u8 min_minbe; - u8 max_minbe; - u8 min_maxbe; - u8 max_maxbe; - u8 min_csma_backoffs; - u8 max_csma_backoffs; - s8 min_frame_retries; - s8 max_frame_retries; - size_t tx_powers_size; - size_t cca_ed_levels_size; - const s32 *tx_powers; - const s32 *cca_ed_levels; -}; - -struct wpan_phy_cca { - enum nl802154_cca_modes mode; - enum nl802154_cca_opts opt; -}; - -struct wpan_phy { - const void *privid; - u32 flags; - u8 current_channel; - u8 current_page; - struct wpan_phy_supported supported; - s32 transmit_power; - struct wpan_phy_cca cca; - __le64 perm_extended_addr; - s32 cca_ed_level; - u8 symbol_duration; - u16 lifs_period; - u16 sifs_period; - struct device dev; - possible_net_t _net; - char priv[0]; -}; - -struct ieee802154_addr { - u8 mode; - __le16 pan_id; - union { - __le16 short_addr; - __le64 extended_addr; - }; -}; - -struct wpan_dev_header_ops { - int (*create)(struct sk_buff *, struct net_device *, const struct ieee802154_addr *, const struct ieee802154_addr *, unsigned int); -}; - -union fwnet_hwaddr { - u8 u[16]; - struct { - __be64 uniq_id; - u8 max_rec; - u8 sspd; - __be16 fifo_hi; - __be32 fifo_lo; - } uc; -}; - -struct in6_validator_info { - struct in6_addr i6vi_addr; - struct inet6_dev *i6vi_dev; - struct netlink_ext_ack *extack; -}; - -struct ifa6_config { - const struct in6_addr *pfx; - unsigned int plen; - const struct in6_addr *peer_pfx; - u32 rt_priority; - u32 ifa_flags; - u32 preferred_lft; - u32 valid_lft; - u16 scope; -}; - -enum cleanup_prefix_rt_t { - CLEANUP_PREFIX_RT_NOP = 0, - CLEANUP_PREFIX_RT_DEL = 1, - CLEANUP_PREFIX_RT_EXPIRE = 2, -}; - -enum { - IPV6_SADDR_RULE_INIT = 0, - IPV6_SADDR_RULE_LOCAL = 1, - IPV6_SADDR_RULE_SCOPE = 2, - IPV6_SADDR_RULE_PREFERRED = 3, - IPV6_SADDR_RULE_OIF = 4, - IPV6_SADDR_RULE_LABEL = 5, - IPV6_SADDR_RULE_PRIVACY = 6, - IPV6_SADDR_RULE_ORCHID = 7, - IPV6_SADDR_RULE_PREFIX = 8, - IPV6_SADDR_RULE_NOT_OPTIMISTIC = 9, - IPV6_SADDR_RULE_MAX = 10, -}; - -struct ipv6_saddr_score { - int rule; - int addr_type; - struct inet6_ifaddr *ifa; - long unsigned int scorebits[1]; - int scopedist; - int matchlen; -}; - -struct ipv6_saddr_dst { - const struct in6_addr *addr; - int ifindex; - int scope; - int label; - unsigned int prefs; -}; - -struct if6_iter_state { - struct seq_net_private p; - int bucket; - int offset; -}; - -enum addr_type_t { - UNICAST_ADDR = 0, - MULTICAST_ADDR = 1, - ANYCAST_ADDR = 2, -}; - -struct inet6_fill_args { - u32 portid; - u32 seq; - int event; - unsigned int flags; - int netnsid; - int ifindex; - enum addr_type_t type; -}; - -enum { - DAD_PROCESS = 0, - DAD_BEGIN = 1, - DAD_ABORT = 2, -}; - -struct ifaddrlblmsg { - __u8 ifal_family; - __u8 __ifal_reserved; - __u8 ifal_prefixlen; - __u8 ifal_flags; - __u32 ifal_index; - __u32 ifal_seq; -}; - -enum { - IFAL_ADDRESS = 1, - IFAL_LABEL = 2, - __IFAL_MAX = 3, -}; - -struct ip6addrlbl_entry { - struct in6_addr prefix; - int prefixlen; - int ifindex; - int addrtype; - u32 label; - struct hlist_node list; - struct callback_head rcu; -}; - -struct ip6addrlbl_init_table { - const struct in6_addr *prefix; - int prefixlen; - u32 label; -}; - -struct rd_msg { - struct icmp6hdr icmph; - struct in6_addr target; - struct in6_addr dest; - __u8 opt[0]; -}; - -struct fib6_gc_args { - int timeout; - int more; -}; - -struct rt6_exception { - struct hlist_node hlist; - struct rt6_info *rt6i; - long unsigned int stamp; - struct callback_head rcu; -}; - -typedef struct rt6_info * (*pol_lookup_t)(struct net *, struct fib6_table *, struct flowi6 *, const struct sk_buff *, int); - -struct route_info { - __u8 type; - __u8 length; - __u8 prefix_len; - __u8 reserved_l: 3; - __u8 route_pref: 2; - __u8 reserved_h: 3; - __be32 lifetime; - __u8 prefix[0]; -}; - -struct rt6_rtnl_dump_arg { - struct sk_buff *skb; - struct netlink_callback *cb; - struct net *net; - struct fib_dump_filter filter; -}; - -struct netevent_redirect { - struct dst_entry *old; - struct dst_entry *new; - struct neighbour *neigh; - const void *daddr; -}; - -struct trace_event_raw_fib6_table_lookup { - struct trace_entry ent; - u32 tb_id; - int err; - int oif; - int iif; - __u8 tos; - __u8 scope; - __u8 flags; - __u8 src[16]; - __u8 dst[16]; - u16 sport; - u16 dport; - u8 proto; - u8 rt_type; - u32 __data_loc_name; - __u8 gw[16]; - char __data[0]; -}; - -struct trace_event_data_offsets_fib6_table_lookup { - u32 name; -}; - -typedef void (*btf_trace_fib6_table_lookup)(void *, const struct net *, const struct fib6_result *, struct fib6_table *, const struct flowi6 *); - -enum rt6_nud_state { - RT6_NUD_FAIL_HARD = 4294967293, - RT6_NUD_FAIL_PROBE = 4294967294, - RT6_NUD_FAIL_DO_RR = 4294967295, - RT6_NUD_SUCCEED = 1, -}; - -struct fib6_nh_dm_arg { - struct net *net; - const struct in6_addr *saddr; - int oif; - int flags; - struct fib6_nh *nh; -}; - -struct __rt6_probe_work { - struct work_struct work; - struct in6_addr target; - struct net_device *dev; -}; - -struct fib6_nh_frl_arg { - u32 flags; - int oif; - int strict; - int *mpri; - bool *do_rr; - struct fib6_nh *nh; -}; - -struct fib6_nh_excptn_arg { - struct rt6_info *rt; - int plen; -}; - -struct fib6_nh_match_arg { - const struct net_device *dev; - const struct in6_addr *gw; - struct fib6_nh *match; -}; - -struct fib6_nh_age_excptn_arg { - struct fib6_gc_args *gc_args; - long unsigned int now; -}; - -struct fib6_nh_rd_arg { - struct fib6_result *res; - struct flowi6 *fl6; - const struct in6_addr *gw; - struct rt6_info **ret; -}; - -struct ip6rd_flowi { - struct flowi6 fl6; - struct in6_addr gateway; -}; - -struct fib6_nh_del_cached_rt_arg { - struct fib6_config *cfg; - struct fib6_info *f6i; -}; - -struct arg_dev_net_ip { - struct net_device *dev; - struct net *net; - struct in6_addr *addr; -}; - -struct arg_netdev_event { - const struct net_device *dev; - union { - unsigned char nh_flags; - long unsigned int event; - }; -}; - -struct rt6_mtu_change_arg { - struct net_device *dev; - unsigned int mtu; - struct fib6_info *f6i; -}; - -struct rt6_nh { - struct fib6_info *fib6_info; - struct fib6_config r_cfg; - struct list_head next; -}; - -struct fib6_nh_exception_dump_walker { - struct rt6_rtnl_dump_arg *dump; - struct fib6_info *rt; - unsigned int flags; - unsigned int skip; - unsigned int count; -}; - -enum fib6_walk_state { - FWS_S = 0, - FWS_L = 1, - FWS_R = 2, - FWS_C = 3, - FWS_U = 4, -}; - -struct fib6_walker { - struct list_head lh; - struct fib6_node *root; - struct fib6_node *node; - struct fib6_info *leaf; - enum fib6_walk_state state; - unsigned int skip; - unsigned int count; - unsigned int skip_in_node; - int (*func)(struct fib6_walker *); - void *args; -}; - -struct fib6_entry_notifier_info { - struct fib_notifier_info info; - struct fib6_info *rt; - unsigned int nsiblings; -}; - -struct ipv6_route_iter { - struct seq_net_private p; - struct fib6_walker w; - loff_t skip; - struct fib6_table *tbl; - int sernum; -}; - -struct bpf_iter__ipv6_route { - union { - struct bpf_iter_meta *meta; - }; - union { - struct fib6_info *rt; - }; -}; - -struct fib6_cleaner { - struct fib6_walker w; - struct net *net; - int (*func)(struct fib6_info *, void *); - int sernum; - void *arg; - bool skip_notify; -}; - -enum { - FIB6_NO_SERNUM_CHANGE = 0, -}; - -struct fib6_dump_arg { - struct net *net; - struct notifier_block *nb; - struct netlink_ext_ack *extack; -}; - -struct fib6_nh_pcpu_arg { - struct fib6_info *from; - const struct fib6_table *table; -}; - -struct lookup_args { - int offset; - const struct in6_addr *addr; -}; - -struct ipv6_mreq { - struct in6_addr ipv6mr_multiaddr; - int ipv6mr_ifindex; -}; - -struct in6_flowlabel_req { - struct in6_addr flr_dst; - __be32 flr_label; - __u8 flr_action; - __u8 flr_share; - __u16 flr_flags; - __u16 flr_expires; - __u16 flr_linger; - __u32 __flr_pad; -}; - -struct ip6_mtuinfo { - struct sockaddr_in6 ip6m_addr; - __u32 ip6m_mtu; -}; - -struct nduseroptmsg { - unsigned char nduseropt_family; - unsigned char nduseropt_pad1; - short unsigned int nduseropt_opts_len; - int nduseropt_ifindex; - __u8 nduseropt_icmp_type; - __u8 nduseropt_icmp_code; - short unsigned int nduseropt_pad2; - unsigned int nduseropt_pad3; -}; - -enum { - NDUSEROPT_UNSPEC = 0, - NDUSEROPT_SRCADDR = 1, - __NDUSEROPT_MAX = 2, -}; - -struct nd_msg { - struct icmp6hdr icmph; - struct in6_addr target; - __u8 opt[0]; -}; - -struct rs_msg { - struct icmp6hdr icmph; - __u8 opt[0]; -}; - -struct ra_msg { - struct icmp6hdr icmph; - __be32 reachable_time; - __be32 retrans_timer; -}; - -struct icmp6_filter { - __u32 data[8]; -}; - -struct raw6_sock { - struct inet_sock inet; - __u32 checksum; - __u32 offset; - struct icmp6_filter filter; - __u32 ip6mr_table; - struct ipv6_pinfo inet6; -}; - -typedef int mh_filter_t(struct sock *, struct sk_buff *); - -struct raw6_frag_vec { - struct msghdr *msg; - int hlen; - char c[4]; -}; - -struct ipv6_destopt_hao { - __u8 type; - __u8 length; - struct in6_addr addr; -} __attribute__((packed)); - -typedef void ip6_icmp_send_t(struct sk_buff *, u8, u8, __u32, const struct in6_addr *, const struct inet6_skb_parm *); - -struct icmpv6_msg { - struct sk_buff *skb; - int offset; - uint8_t type; -}; - -struct icmp6_err { - int err; - int fatal; -}; - -struct mld_msg { - struct icmp6hdr mld_hdr; - struct in6_addr mld_mca; -}; - -struct mld2_grec { - __u8 grec_type; - __u8 grec_auxwords; - __be16 grec_nsrcs; - struct in6_addr grec_mca; - struct in6_addr grec_src[0]; -}; - -struct mld2_report { - struct icmp6hdr mld2r_hdr; - struct mld2_grec mld2r_grec[0]; -}; - -struct mld2_query { - struct icmp6hdr mld2q_hdr; - struct in6_addr mld2q_mca; - __u8 mld2q_qrv: 3; - __u8 mld2q_suppress: 1; - __u8 mld2q_resv2: 4; - __u8 mld2q_qqic; - __be16 mld2q_nsrcs; - struct in6_addr mld2q_srcs[0]; -}; - -struct igmp6_mc_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct inet6_dev *idev; -}; - -struct igmp6_mcf_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct inet6_dev *idev; - struct ifmcaddr6 *im; -}; - -enum ip6_defrag_users { - IP6_DEFRAG_LOCAL_DELIVER = 0, - IP6_DEFRAG_CONNTRACK_IN = 1, - __IP6_DEFRAG_CONNTRACK_IN = 65536, - IP6_DEFRAG_CONNTRACK_OUT = 65537, - __IP6_DEFRAG_CONNTRACK_OUT = 131072, - IP6_DEFRAG_CONNTRACK_BRIDGE_IN = 131073, - __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = 196608, -}; - -struct frag_queue { - struct inet_frag_queue q; - int iif; - __u16 nhoffset; - u8 ecn; -}; - -struct tcp6_pseudohdr { - struct in6_addr saddr; - struct in6_addr daddr; - __be32 len; - __be32 protocol; -}; - -struct rt0_hdr { - struct ipv6_rt_hdr rt_hdr; - __u32 reserved; - struct in6_addr addr[0]; -}; - -struct ipv6_rpl_sr_hdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 type; - __u8 segments_left; - __u32 cmpre: 4; - __u32 cmpri: 4; - __u32 reserved: 4; - __u32 pad: 4; - __u32 reserved1: 16; - union { - struct in6_addr addr[0]; - __u8 data[0]; - } segments; -}; - -struct tlvtype_proc { - int type; - bool (*func)(struct sk_buff *, int); -}; - -struct ip6fl_iter_state { - struct seq_net_private p; - struct pid_namespace *pid_ns; - int bucket; -}; - -struct sr6_tlv { - __u8 type; - __u8 len; - __u8 data[0]; -}; - -enum { - SEG6_ATTR_UNSPEC = 0, - SEG6_ATTR_DST = 1, - SEG6_ATTR_DSTLEN = 2, - SEG6_ATTR_HMACKEYID = 3, - SEG6_ATTR_SECRET = 4, - SEG6_ATTR_SECRETLEN = 5, - SEG6_ATTR_ALGID = 6, - SEG6_ATTR_HMACINFO = 7, - __SEG6_ATTR_MAX = 8, -}; - -enum { - SEG6_CMD_UNSPEC = 0, - SEG6_CMD_SETHMAC = 1, - SEG6_CMD_DUMPHMAC = 2, - SEG6_CMD_SET_TUNSRC = 3, - SEG6_CMD_GET_TUNSRC = 4, - __SEG6_CMD_MAX = 5, -}; - -struct seg6_hmac_info { - struct rhash_head node; - struct callback_head rcu; - u32 hmackeyid; - char secret[64]; - u8 slen; - u8 alg_id; -}; - -typedef short unsigned int mifi_t; - -typedef __u32 if_mask; - -struct if_set { - if_mask ifs_bits[8]; -}; - -struct mif6ctl { - mifi_t mif6c_mifi; - unsigned char mif6c_flags; - unsigned char vifc_threshold; - __u16 mif6c_pifi; - unsigned int vifc_rate_limit; -}; - -struct mf6cctl { - struct sockaddr_in6 mf6cc_origin; - struct sockaddr_in6 mf6cc_mcastgrp; - mifi_t mf6cc_parent; - struct if_set mf6cc_ifset; -}; - -struct sioc_sg_req6 { - struct sockaddr_in6 src; - struct sockaddr_in6 grp; - long unsigned int pktcnt; - long unsigned int bytecnt; - long unsigned int wrong_if; -}; - -struct sioc_mif_req6 { - mifi_t mifi; - long unsigned int icount; - long unsigned int ocount; - long unsigned int ibytes; - long unsigned int obytes; -}; - -struct mrt6msg { - __u8 im6_mbz; - __u8 im6_msgtype; - __u16 im6_mif; - __u32 im6_pad; - struct in6_addr im6_src; - struct in6_addr im6_dst; -}; - -enum { - IP6MRA_CREPORT_UNSPEC = 0, - IP6MRA_CREPORT_MSGTYPE = 1, - IP6MRA_CREPORT_MIF_ID = 2, - IP6MRA_CREPORT_SRC_ADDR = 3, - IP6MRA_CREPORT_DST_ADDR = 4, - IP6MRA_CREPORT_PKT = 5, - __IP6MRA_CREPORT_MAX = 6, -}; - -struct mfc6_cache_cmp_arg { - struct in6_addr mf6c_mcastgrp; - struct in6_addr mf6c_origin; -}; - -struct mfc6_cache { - struct mr_mfc _c; - union { - struct { - struct in6_addr mf6c_mcastgrp; - struct in6_addr mf6c_origin; - }; - struct mfc6_cache_cmp_arg cmparg; - }; -}; - -struct ip6mr_result { - struct mr_table *mrt; -}; - -struct compat_sioc_sg_req6 { - struct sockaddr_in6 src; - struct sockaddr_in6 grp; - compat_ulong_t pktcnt; - compat_ulong_t bytecnt; - compat_ulong_t wrong_if; -}; - -struct compat_sioc_mif_req6 { - mifi_t mifi; - compat_ulong_t icount; - compat_ulong_t ocount; - compat_ulong_t ibytes; - compat_ulong_t obytes; -}; - -struct xfrm6_protocol { - int (*handler)(struct sk_buff *); - int (*input_handler)(struct sk_buff *, int, __be32, int); - int (*cb_handler)(struct sk_buff *, int); - int (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32); - struct xfrm6_protocol *next; - int priority; -}; - -struct br_input_skb_cb { - struct net_device *brdev; - u16 frag_max_size; - u8 igmp; - u8 mrouters_only: 1; - u8 proxyarp_replied: 1; - u8 src_port_isolated: 1; - u8 vlan_filtered: 1; - u8 br_netfilter_broute: 1; - int offload_fwd_mark; -}; - -struct nf_bridge_frag_data; - -struct fib6_rule { - struct fib_rule common; - struct rt6key src; - struct rt6key dst; - u8 tclass; -}; - -struct calipso_doi; - -struct netlbl_calipso_ops { - int (*doi_add)(struct calipso_doi *, struct netlbl_audit *); - void (*doi_free)(struct calipso_doi *); - int (*doi_remove)(u32, struct netlbl_audit *); - struct calipso_doi * (*doi_getdef)(u32); - void (*doi_putdef)(struct calipso_doi *); - int (*doi_walk)(u32 *, int (*)(struct calipso_doi *, void *), void *); - int (*sock_getattr)(struct sock *, struct netlbl_lsm_secattr *); - int (*sock_setattr)(struct sock *, const struct calipso_doi *, const struct netlbl_lsm_secattr *); - void (*sock_delattr)(struct sock *); - int (*req_setattr)(struct request_sock *, const struct calipso_doi *, const struct netlbl_lsm_secattr *); - void (*req_delattr)(struct request_sock *); - int (*opt_getattr)(const unsigned char *, struct netlbl_lsm_secattr *); - unsigned char * (*skbuff_optptr)(const struct sk_buff *); - int (*skbuff_setattr)(struct sk_buff *, const struct calipso_doi *, const struct netlbl_lsm_secattr *); - int (*skbuff_delattr)(struct sk_buff *); - void (*cache_invalidate)(); - int (*cache_add)(const unsigned char *, const struct netlbl_lsm_secattr *); -}; - -struct calipso_doi { - u32 doi; - u32 type; - refcount_t refcount; - struct list_head list; - struct callback_head rcu; -}; - -struct calipso_map_cache_bkt { - spinlock_t lock; - u32 size; - struct list_head list; -}; - -struct calipso_map_cache_entry { - u32 hash; - unsigned char *key; - size_t key_len; - struct netlbl_lsm_cache *lsm_data; - u32 activity; - struct list_head list; -}; - -enum { - SEG6_IPTUNNEL_UNSPEC = 0, - SEG6_IPTUNNEL_SRH = 1, - __SEG6_IPTUNNEL_MAX = 2, -}; - -struct seg6_iptunnel_encap { - int mode; - struct ipv6_sr_hdr srh[0]; -}; - -enum { - SEG6_IPTUN_MODE_INLINE = 0, - SEG6_IPTUN_MODE_ENCAP = 1, - SEG6_IPTUN_MODE_L2ENCAP = 2, -}; - -struct seg6_lwt { - struct dst_cache cache; - struct seg6_iptunnel_encap tuninfo[0]; -}; - -enum l3mdev_type { - L3MDEV_TYPE_UNSPEC = 0, - L3MDEV_TYPE_VRF = 1, - __L3MDEV_TYPE_MAX = 2, -}; - -enum { - IP6_FH_F_FRAG = 1, - IP6_FH_F_AUTH = 2, - IP6_FH_F_SKIP_RH = 4, -}; - -enum { - SEG6_LOCAL_UNSPEC = 0, - SEG6_LOCAL_ACTION = 1, - SEG6_LOCAL_SRH = 2, - SEG6_LOCAL_TABLE = 3, - SEG6_LOCAL_NH4 = 4, - SEG6_LOCAL_NH6 = 5, - SEG6_LOCAL_IIF = 6, - SEG6_LOCAL_OIF = 7, - SEG6_LOCAL_BPF = 8, - SEG6_LOCAL_VRFTABLE = 9, - SEG6_LOCAL_COUNTERS = 10, - __SEG6_LOCAL_MAX = 11, -}; - -enum { - SEG6_LOCAL_BPF_PROG_UNSPEC = 0, - SEG6_LOCAL_BPF_PROG = 1, - SEG6_LOCAL_BPF_PROG_NAME = 2, - __SEG6_LOCAL_BPF_PROG_MAX = 3, -}; - -enum { - SEG6_LOCAL_CNT_UNSPEC = 0, - SEG6_LOCAL_CNT_PAD = 1, - SEG6_LOCAL_CNT_PACKETS = 2, - SEG6_LOCAL_CNT_BYTES = 3, - SEG6_LOCAL_CNT_ERRORS = 4, - __SEG6_LOCAL_CNT_MAX = 5, -}; - -struct seg6_local_lwt; - -struct seg6_local_lwtunnel_ops { - int (*build_state)(struct seg6_local_lwt *, const void *, struct netlink_ext_ack *); - void (*destroy_state)(struct seg6_local_lwt *); -}; - -enum seg6_end_dt_mode { - DT_INVALID_MODE = 4294967274, - DT_LEGACY_MODE = 0, - DT_VRF_MODE = 1, -}; - -struct seg6_end_dt_info { - enum seg6_end_dt_mode mode; - struct net *net; - int vrf_ifindex; - int vrf_table; - u16 family; -}; - -struct pcpu_seg6_local_counters; - -struct seg6_action_desc; - -struct seg6_local_lwt { - int action; - struct ipv6_sr_hdr *srh; - int table; - struct in_addr nh4; - struct in6_addr nh6; - int iif; - int oif; - struct bpf_lwt_prog bpf; - struct seg6_end_dt_info dt_info; - struct pcpu_seg6_local_counters *pcpu_counters; - int headroom; - struct seg6_action_desc *desc; - long unsigned int parsed_optattrs; -}; - -struct seg6_action_desc { - int action; - long unsigned int attrs; - long unsigned int optattrs; - int (*input)(struct sk_buff *, struct seg6_local_lwt *); - int static_headroom; - struct seg6_local_lwtunnel_ops slwt_ops; -}; - -struct pcpu_seg6_local_counters { - u64_stats_t packets; - u64_stats_t bytes; - u64_stats_t errors; - struct u64_stats_sync syncp; -}; - -struct seg6_local_counters { - __u64 packets; - __u64 bytes; - __u64 errors; -}; - -struct seg6_action_param { - int (*parse)(struct nlattr **, struct seg6_local_lwt *); - int (*put)(struct sk_buff *, struct seg6_local_lwt *); - int (*cmp)(struct seg6_local_lwt *, struct seg6_local_lwt *); - void (*destroy)(struct seg6_local_lwt *); -}; - -struct sr6_tlv_hmac { - struct sr6_tlv tlvhdr; - __u16 reserved; - __be32 hmackeyid; - __u8 hmac[32]; -}; - -enum { - SEG6_HMAC_ALGO_SHA1 = 1, - SEG6_HMAC_ALGO_SHA256 = 2, -}; - -struct seg6_hmac_algo { - u8 alg_id; - char name[64]; - struct crypto_shash **tfms; - struct shash_desc **shashs; -}; - -enum { - RPL_IPTUNNEL_UNSPEC = 0, - RPL_IPTUNNEL_SRH = 1, - __RPL_IPTUNNEL_MAX = 2, -}; - -struct rpl_iptunnel_encap { - struct ipv6_rpl_sr_hdr srh[0]; -}; - -struct rpl_lwt { - struct dst_cache cache; - struct rpl_iptunnel_encap tuninfo; -}; - -struct sockaddr_pkt { - short unsigned int spkt_family; - unsigned char spkt_device[14]; - __be16 spkt_protocol; -}; - -struct sockaddr_ll { - short unsigned int sll_family; - __be16 sll_protocol; - int sll_ifindex; - short unsigned int sll_hatype; - unsigned char sll_pkttype; - unsigned char sll_halen; - unsigned char sll_addr[8]; -}; - -struct tpacket_stats { - unsigned int tp_packets; - unsigned int tp_drops; -}; - -struct tpacket_stats_v3 { - unsigned int tp_packets; - unsigned int tp_drops; - unsigned int tp_freeze_q_cnt; -}; - -struct tpacket_rollover_stats { - __u64 tp_all; - __u64 tp_huge; - __u64 tp_failed; -}; - -union tpacket_stats_u { - struct tpacket_stats stats1; - struct tpacket_stats_v3 stats3; -}; - -struct tpacket_auxdata { - __u32 tp_status; - __u32 tp_len; - __u32 tp_snaplen; - __u16 tp_mac; - __u16 tp_net; - __u16 tp_vlan_tci; - __u16 tp_vlan_tpid; -}; - -struct tpacket_hdr { - long unsigned int tp_status; - unsigned int tp_len; - unsigned int tp_snaplen; - short unsigned int tp_mac; - short unsigned int tp_net; - unsigned int tp_sec; - unsigned int tp_usec; -}; - -struct tpacket2_hdr { - __u32 tp_status; - __u32 tp_len; - __u32 tp_snaplen; - __u16 tp_mac; - __u16 tp_net; - __u32 tp_sec; - __u32 tp_nsec; - __u16 tp_vlan_tci; - __u16 tp_vlan_tpid; - __u8 tp_padding[4]; -}; - -struct tpacket_hdr_variant1 { - __u32 tp_rxhash; - __u32 tp_vlan_tci; - __u16 tp_vlan_tpid; - __u16 tp_padding; -}; - -struct tpacket3_hdr { - __u32 tp_next_offset; - __u32 tp_sec; - __u32 tp_nsec; - __u32 tp_snaplen; - __u32 tp_len; - __u32 tp_status; - __u16 tp_mac; - __u16 tp_net; - union { - struct tpacket_hdr_variant1 hv1; - }; - __u8 tp_padding[8]; -}; - -struct tpacket_bd_ts { - unsigned int ts_sec; - union { - unsigned int ts_usec; - unsigned int ts_nsec; - }; -}; - -struct tpacket_hdr_v1 { - __u32 block_status; - __u32 num_pkts; - __u32 offset_to_first_pkt; - __u32 blk_len; - __u64 seq_num; - struct tpacket_bd_ts ts_first_pkt; - struct tpacket_bd_ts ts_last_pkt; -}; - -union tpacket_bd_header_u { - struct tpacket_hdr_v1 bh1; -}; - -struct tpacket_block_desc { - __u32 version; - __u32 offset_to_priv; - union tpacket_bd_header_u hdr; -}; - -enum tpacket_versions { - TPACKET_V1 = 0, - TPACKET_V2 = 1, - TPACKET_V3 = 2, -}; - -struct tpacket_req { - unsigned int tp_block_size; - unsigned int tp_block_nr; - unsigned int tp_frame_size; - unsigned int tp_frame_nr; -}; - -struct tpacket_req3 { - unsigned int tp_block_size; - unsigned int tp_block_nr; - unsigned int tp_frame_size; - unsigned int tp_frame_nr; - unsigned int tp_retire_blk_tov; - unsigned int tp_sizeof_priv; - unsigned int tp_feature_req_word; -}; - -union tpacket_req_u { - struct tpacket_req req; - struct tpacket_req3 req3; -}; - -struct fanout_args { - __u16 id; - __u16 type_flags; - __u32 max_num_members; -}; - -struct virtio_net_hdr { - __u8 flags; - __u8 gso_type; - __virtio16 hdr_len; - __virtio16 gso_size; - __virtio16 csum_start; - __virtio16 csum_offset; -}; - -struct packet_mclist { - struct packet_mclist *next; - int ifindex; - int count; - short unsigned int type; - short unsigned int alen; - unsigned char addr[32]; -}; - -struct pgv; - -struct tpacket_kbdq_core { - struct pgv *pkbdq; - unsigned int feature_req_word; - unsigned int hdrlen; - unsigned char reset_pending_on_curr_blk; - unsigned char delete_blk_timer; - short unsigned int kactive_blk_num; - short unsigned int blk_sizeof_priv; - short unsigned int last_kactive_blk_num; - char *pkblk_start; - char *pkblk_end; - int kblk_size; - unsigned int max_frame_len; - unsigned int knum_blocks; - uint64_t knxt_seq_num; - char *prev; - char *nxt_offset; - struct sk_buff *skb; - rwlock_t blk_fill_in_prog_lock; - short unsigned int retire_blk_tov; - short unsigned int version; - long unsigned int tov_in_jiffies; - struct timer_list retire_blk_timer; -}; - -struct pgv { - char *buffer; -}; - -struct packet_ring_buffer { - struct pgv *pg_vec; - unsigned int head; - unsigned int frames_per_block; - unsigned int frame_size; - unsigned int frame_max; - unsigned int pg_vec_order; - unsigned int pg_vec_pages; - unsigned int pg_vec_len; - unsigned int *pending_refcnt; - union { - long unsigned int *rx_owner_map; - struct tpacket_kbdq_core prb_bdqc; - }; -}; - -struct packet_fanout { - possible_net_t net; - unsigned int num_members; - u32 max_num_members; - u16 id; - u8 type; - u8 flags; - union { - atomic_t rr_cur; - struct bpf_prog *bpf_prog; - }; - struct list_head list; - spinlock_t lock; - refcount_t sk_ref; - long: 64; - struct packet_type prot_hook; - struct sock *arr[0]; -}; - -struct packet_rollover { - int sock; - atomic_long_t num; - atomic_long_t num_huge; - atomic_long_t num_failed; - long: 64; - long: 64; - long: 64; - long: 64; - u32 history[16]; -}; - -struct packet_sock { - struct sock sk; - struct packet_fanout *fanout; - union tpacket_stats_u stats; - struct packet_ring_buffer rx_ring; - struct packet_ring_buffer tx_ring; - int copy_thresh; - spinlock_t bind_lock; - struct mutex pg_vec_lock; - unsigned int running; - unsigned int auxdata: 1; - unsigned int origdev: 1; - unsigned int has_vnet_hdr: 1; - unsigned int tp_loss: 1; - unsigned int tp_tx_has_off: 1; - int pressure; - int ifindex; - __be16 num; - struct packet_rollover *rollover; - struct packet_mclist *mclist; - atomic_t mapped; - enum tpacket_versions tp_version; - unsigned int tp_hdrlen; - unsigned int tp_reserve; - unsigned int tp_tstamp; - struct completion skb_completion; - struct net_device *cached_dev; - int (*xmit)(struct sk_buff *); - struct packet_type prot_hook; - atomic_t tp_drops; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct packet_mreq_max { - int mr_ifindex; - short unsigned int mr_type; - short unsigned int mr_alen; - unsigned char mr_address[32]; -}; - -union tpacket_uhdr { - struct tpacket_hdr *h1; - struct tpacket2_hdr *h2; - struct tpacket3_hdr *h3; - void *raw; -}; - -struct packet_skb_cb { - union { - struct sockaddr_pkt pkt; - union { - unsigned int origlen; - struct sockaddr_ll ll; - }; - } sa; -}; - -struct _strp_msg { - struct strp_msg strp; - int accum_len; -}; - -struct vlan_group { - unsigned int nr_vlan_devs; - struct hlist_node hlist; - struct net_device **vlan_devices_arrays[16]; -}; - -struct vlan_info { - struct net_device *real_dev; - struct vlan_group grp; - struct list_head vid_list; - unsigned int nr_vids; - struct callback_head rcu; -}; - -enum vlan_flags { - VLAN_FLAG_REORDER_HDR = 1, - VLAN_FLAG_GVRP = 2, - VLAN_FLAG_LOOSE_BINDING = 4, - VLAN_FLAG_MVRP = 8, - VLAN_FLAG_BRIDGE_BINDING = 16, -}; - -struct vlan_priority_tci_mapping { - u32 priority; - u16 vlan_qos; - struct vlan_priority_tci_mapping *next; -}; - -struct vlan_dev_priv { - unsigned int nr_ingress_mappings; - u32 ingress_priority_map[8]; - unsigned int nr_egress_mappings; - struct vlan_priority_tci_mapping *egress_priority_map[16]; - __be16 vlan_proto; - u16 vlan_id; - u16 flags; - struct net_device *real_dev; - unsigned char real_dev_addr[6]; - struct proc_dir_entry *dent; - struct vlan_pcpu_stats *vlan_pcpu_stats; - struct netpoll *netpoll; -}; - -enum vlan_protos { - VLAN_PROTO_8021Q = 0, - VLAN_PROTO_8021AD = 1, - VLAN_PROTO_NUM = 2, -}; - -struct vlan_vid_info { - struct list_head list; - __be16 proto; - u16 vid; - int refcount; -}; - -enum nl80211_iftype { - NL80211_IFTYPE_UNSPECIFIED = 0, - NL80211_IFTYPE_ADHOC = 1, - NL80211_IFTYPE_STATION = 2, - NL80211_IFTYPE_AP = 3, - NL80211_IFTYPE_AP_VLAN = 4, - NL80211_IFTYPE_WDS = 5, - NL80211_IFTYPE_MONITOR = 6, - NL80211_IFTYPE_MESH_POINT = 7, - NL80211_IFTYPE_P2P_CLIENT = 8, - NL80211_IFTYPE_P2P_GO = 9, - NL80211_IFTYPE_P2P_DEVICE = 10, - NL80211_IFTYPE_OCB = 11, - NL80211_IFTYPE_NAN = 12, - NUM_NL80211_IFTYPES = 13, - NL80211_IFTYPE_MAX = 12, -}; - -struct cfg80211_conn; - -struct cfg80211_cached_keys; - -enum ieee80211_bss_type { - IEEE80211_BSS_TYPE_ESS = 0, - IEEE80211_BSS_TYPE_PBSS = 1, - IEEE80211_BSS_TYPE_IBSS = 2, - IEEE80211_BSS_TYPE_MBSS = 3, - IEEE80211_BSS_TYPE_ANY = 4, -}; - -struct cfg80211_internal_bss; - -enum nl80211_chan_width { - NL80211_CHAN_WIDTH_20_NOHT = 0, - NL80211_CHAN_WIDTH_20 = 1, - NL80211_CHAN_WIDTH_40 = 2, - NL80211_CHAN_WIDTH_80 = 3, - NL80211_CHAN_WIDTH_80P80 = 4, - NL80211_CHAN_WIDTH_160 = 5, - NL80211_CHAN_WIDTH_5 = 6, - NL80211_CHAN_WIDTH_10 = 7, - NL80211_CHAN_WIDTH_1 = 8, - NL80211_CHAN_WIDTH_2 = 9, - NL80211_CHAN_WIDTH_4 = 10, - NL80211_CHAN_WIDTH_8 = 11, - NL80211_CHAN_WIDTH_16 = 12, -}; - -enum ieee80211_edmg_bw_config { - IEEE80211_EDMG_BW_CONFIG_4 = 4, - IEEE80211_EDMG_BW_CONFIG_5 = 5, - IEEE80211_EDMG_BW_CONFIG_6 = 6, - IEEE80211_EDMG_BW_CONFIG_7 = 7, - IEEE80211_EDMG_BW_CONFIG_8 = 8, - IEEE80211_EDMG_BW_CONFIG_9 = 9, - IEEE80211_EDMG_BW_CONFIG_10 = 10, - IEEE80211_EDMG_BW_CONFIG_11 = 11, - IEEE80211_EDMG_BW_CONFIG_12 = 12, - IEEE80211_EDMG_BW_CONFIG_13 = 13, - IEEE80211_EDMG_BW_CONFIG_14 = 14, - IEEE80211_EDMG_BW_CONFIG_15 = 15, -}; - -struct ieee80211_edmg { - u8 channels; - enum ieee80211_edmg_bw_config bw_config; -}; - -struct ieee80211_channel; - -struct cfg80211_chan_def { - struct ieee80211_channel *chan; - enum nl80211_chan_width width; - u32 center_freq1; - u32 center_freq2; - struct ieee80211_edmg edmg; - u16 freq1_offset; -}; - -struct ieee80211_mcs_info { - u8 rx_mask[10]; - __le16 rx_highest; - u8 tx_params; - u8 reserved[3]; -}; - -struct ieee80211_ht_cap { - __le16 cap_info; - u8 ampdu_params_info; - struct ieee80211_mcs_info mcs; - __le16 extended_ht_cap_info; - __le32 tx_BF_cap_info; - u8 antenna_selection_info; -} __attribute__((packed)); - -struct key_params; - -struct cfg80211_ibss_params { - const u8 *ssid; - const u8 *bssid; - struct cfg80211_chan_def chandef; - const u8 *ie; - u8 ssid_len; - u8 ie_len; - u16 beacon_interval; - u32 basic_rates; - bool channel_fixed; - bool privacy; - bool control_port; - bool control_port_over_nl80211; - bool userspace_handles_dfs; - int: 24; - int mcast_rate[5]; - struct ieee80211_ht_cap ht_capa; - struct ieee80211_ht_cap ht_capa_mask; - struct key_params *wep_keys; - int wep_tx_key; - int: 32; -} __attribute__((packed)); - -enum nl80211_auth_type { - NL80211_AUTHTYPE_OPEN_SYSTEM = 0, - NL80211_AUTHTYPE_SHARED_KEY = 1, - NL80211_AUTHTYPE_FT = 2, - NL80211_AUTHTYPE_NETWORK_EAP = 3, - NL80211_AUTHTYPE_SAE = 4, - NL80211_AUTHTYPE_FILS_SK = 5, - NL80211_AUTHTYPE_FILS_SK_PFS = 6, - NL80211_AUTHTYPE_FILS_PK = 7, - __NL80211_AUTHTYPE_NUM = 8, - NL80211_AUTHTYPE_MAX = 7, - NL80211_AUTHTYPE_AUTOMATIC = 8, -}; - -enum nl80211_mfp { - NL80211_MFP_NO = 0, - NL80211_MFP_REQUIRED = 1, - NL80211_MFP_OPTIONAL = 2, -}; - -enum nl80211_sae_pwe_mechanism { - NL80211_SAE_PWE_UNSPECIFIED = 0, - NL80211_SAE_PWE_HUNT_AND_PECK = 1, - NL80211_SAE_PWE_HASH_TO_ELEMENT = 2, - NL80211_SAE_PWE_BOTH = 3, -}; - -struct cfg80211_crypto_settings { - u32 wpa_versions; - u32 cipher_group; - int n_ciphers_pairwise; - u32 ciphers_pairwise[5]; - int n_akm_suites; - u32 akm_suites[2]; - bool control_port; - __be16 control_port_ethertype; - bool control_port_no_encrypt; - bool control_port_over_nl80211; - bool control_port_no_preauth; - struct key_params *wep_keys; - int wep_tx_key; - const u8 *psk; - const u8 *sae_pwd; - u8 sae_pwd_len; - enum nl80211_sae_pwe_mechanism sae_pwe; -}; - -struct ieee80211_vht_mcs_info { - __le16 rx_mcs_map; - __le16 rx_highest; - __le16 tx_mcs_map; - __le16 tx_highest; -}; - -struct ieee80211_vht_cap { - __le32 vht_cap_info; - struct ieee80211_vht_mcs_info supp_mcs; -}; - -enum nl80211_bss_select_attr { - __NL80211_BSS_SELECT_ATTR_INVALID = 0, - NL80211_BSS_SELECT_ATTR_RSSI = 1, - NL80211_BSS_SELECT_ATTR_BAND_PREF = 2, - NL80211_BSS_SELECT_ATTR_RSSI_ADJUST = 3, - __NL80211_BSS_SELECT_ATTR_AFTER_LAST = 4, - NL80211_BSS_SELECT_ATTR_MAX = 3, -}; - -enum nl80211_band { - NL80211_BAND_2GHZ = 0, - NL80211_BAND_5GHZ = 1, - NL80211_BAND_60GHZ = 2, - NL80211_BAND_6GHZ = 3, - NL80211_BAND_S1GHZ = 4, - NUM_NL80211_BANDS = 5, -}; - -struct cfg80211_bss_select_adjust { - enum nl80211_band band; - s8 delta; -}; - -struct cfg80211_bss_selection { - enum nl80211_bss_select_attr behaviour; - union { - enum nl80211_band band_pref; - struct cfg80211_bss_select_adjust adjust; - } param; -}; - -struct cfg80211_connect_params { - struct ieee80211_channel *channel; - struct ieee80211_channel *channel_hint; - const u8 *bssid; - const u8 *bssid_hint; - const u8 *ssid; - size_t ssid_len; - enum nl80211_auth_type auth_type; - int: 32; - const u8 *ie; - size_t ie_len; - bool privacy; - int: 24; - enum nl80211_mfp mfp; - struct cfg80211_crypto_settings crypto; - const u8 *key; - u8 key_len; - u8 key_idx; - short: 16; - u32 flags; - int bg_scan_period; - struct ieee80211_ht_cap ht_capa; - struct ieee80211_ht_cap ht_capa_mask; - struct ieee80211_vht_cap vht_capa; - struct ieee80211_vht_cap vht_capa_mask; - bool pbss; - int: 24; - struct cfg80211_bss_selection bss_select; - const u8 *prev_bssid; - const u8 *fils_erp_username; - size_t fils_erp_username_len; - const u8 *fils_erp_realm; - size_t fils_erp_realm_len; - u16 fils_erp_next_seq_num; - long: 48; - const u8 *fils_erp_rrk; - size_t fils_erp_rrk_len; - bool want_1x; - int: 24; - struct ieee80211_edmg edmg; - int: 32; -} __attribute__((packed)); - -struct cfg80211_cqm_config; - -struct wiphy; - -struct wireless_dev { - struct wiphy *wiphy; - enum nl80211_iftype iftype; - struct list_head list; - struct net_device *netdev; - u32 identifier; - struct list_head mgmt_registrations; - spinlock_t mgmt_registrations_lock; - u8 mgmt_registrations_need_update: 1; - struct mutex mtx; - bool use_4addr; - bool is_running; - bool registered; - bool registering; - u8 address[6]; - u8 ssid[32]; - u8 ssid_len; - u8 mesh_id_len; - u8 mesh_id_up_len; - struct cfg80211_conn *conn; - struct cfg80211_cached_keys *connect_keys; - enum ieee80211_bss_type conn_bss_type; - u32 conn_owner_nlportid; - struct work_struct disconnect_wk; - u8 disconnect_bssid[6]; - struct list_head event_list; - spinlock_t event_lock; - struct cfg80211_internal_bss *current_bss; - struct cfg80211_chan_def preset_chandef; - struct cfg80211_chan_def chandef; - bool ibss_fixed; - bool ibss_dfs_possible; - bool ps; - int ps_timeout; - int beacon_interval; - u32 ap_unexpected_nlportid; - u32 owner_nlportid; - bool nl_owner_dead; - bool cac_started; - long unsigned int cac_start_time; - unsigned int cac_time_ms; - struct { - struct cfg80211_ibss_params ibss; - struct cfg80211_connect_params connect; - struct cfg80211_cached_keys *keys; - const u8 *ie; - size_t ie_len; - u8 bssid[6]; - u8 prev_bssid[6]; - u8 ssid[32]; - s8 default_key; - s8 default_mgmt_key; - bool prev_bssid_valid; - } wext; - struct cfg80211_cqm_config *cqm_config; - struct list_head pmsr_list; - spinlock_t pmsr_lock; - struct work_struct pmsr_free_wk; - long unsigned int unprot_beacon_reported; -}; - -struct iw_encode_ext { - __u32 ext_flags; - __u8 tx_seq[8]; - __u8 rx_seq[8]; - struct sockaddr addr; - __u16 alg; - __u16 key_len; - __u8 key[0]; -}; - -struct iwreq { - union { - char ifrn_name[16]; - } ifr_ifrn; - union iwreq_data u; -}; - -struct iw_event { - __u16 len; - __u16 cmd; - union iwreq_data u; -}; - -struct compat_iw_point { - compat_caddr_t pointer; - __u16 length; - __u16 flags; -}; - -struct __compat_iw_event { - __u16 len; - __u16 cmd; - compat_caddr_t pointer; -}; - -enum nl80211_reg_initiator { - NL80211_REGDOM_SET_BY_CORE = 0, - NL80211_REGDOM_SET_BY_USER = 1, - NL80211_REGDOM_SET_BY_DRIVER = 2, - NL80211_REGDOM_SET_BY_COUNTRY_IE = 3, -}; - -enum nl80211_dfs_regions { - NL80211_DFS_UNSET = 0, - NL80211_DFS_FCC = 1, - NL80211_DFS_ETSI = 2, - NL80211_DFS_JP = 3, -}; - -enum nl80211_user_reg_hint_type { - NL80211_USER_REG_HINT_USER = 0, - NL80211_USER_REG_HINT_CELL_BASE = 1, - NL80211_USER_REG_HINT_INDOOR = 2, -}; - -enum nl80211_mntr_flags { - __NL80211_MNTR_FLAG_INVALID = 0, - NL80211_MNTR_FLAG_FCSFAIL = 1, - NL80211_MNTR_FLAG_PLCPFAIL = 2, - NL80211_MNTR_FLAG_CONTROL = 3, - NL80211_MNTR_FLAG_OTHER_BSS = 4, - NL80211_MNTR_FLAG_COOK_FRAMES = 5, - NL80211_MNTR_FLAG_ACTIVE = 6, - __NL80211_MNTR_FLAG_AFTER_LAST = 7, - NL80211_MNTR_FLAG_MAX = 6, -}; - -enum nl80211_key_mode { - NL80211_KEY_RX_TX = 0, - NL80211_KEY_NO_TX = 1, - NL80211_KEY_SET_TX = 2, -}; - -enum nl80211_bss_scan_width { - NL80211_BSS_CHAN_WIDTH_20 = 0, - NL80211_BSS_CHAN_WIDTH_10 = 1, - NL80211_BSS_CHAN_WIDTH_5 = 2, - NL80211_BSS_CHAN_WIDTH_1 = 3, - NL80211_BSS_CHAN_WIDTH_2 = 4, -}; - -struct nl80211_wowlan_tcp_data_seq { - __u32 start; - __u32 offset; - __u32 len; -}; - -struct nl80211_wowlan_tcp_data_token { - __u32 offset; - __u32 len; - __u8 token_stream[0]; -}; - -struct nl80211_wowlan_tcp_data_token_feature { - __u32 min_len; - __u32 max_len; - __u32 bufsize; -}; - -enum nl80211_ext_feature_index { - NL80211_EXT_FEATURE_VHT_IBSS = 0, - NL80211_EXT_FEATURE_RRM = 1, - NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER = 2, - NL80211_EXT_FEATURE_SCAN_START_TIME = 3, - NL80211_EXT_FEATURE_BSS_PARENT_TSF = 4, - NL80211_EXT_FEATURE_SET_SCAN_DWELL = 5, - NL80211_EXT_FEATURE_BEACON_RATE_LEGACY = 6, - NL80211_EXT_FEATURE_BEACON_RATE_HT = 7, - NL80211_EXT_FEATURE_BEACON_RATE_VHT = 8, - NL80211_EXT_FEATURE_FILS_STA = 9, - NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA = 10, - NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED = 11, - NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI = 12, - NL80211_EXT_FEATURE_CQM_RSSI_LIST = 13, - NL80211_EXT_FEATURE_FILS_SK_OFFLOAD = 14, - NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK = 15, - NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X = 16, - NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME = 17, - NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP = 18, - NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE = 19, - NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 20, - NL80211_EXT_FEATURE_MFP_OPTIONAL = 21, - NL80211_EXT_FEATURE_LOW_SPAN_SCAN = 22, - NL80211_EXT_FEATURE_LOW_POWER_SCAN = 23, - NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN = 24, - NL80211_EXT_FEATURE_DFS_OFFLOAD = 25, - NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211 = 26, - NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT = 27, - NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = 27, - NL80211_EXT_FEATURE_TXQS = 28, - NL80211_EXT_FEATURE_SCAN_RANDOM_SN = 29, - NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT = 30, - NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 = 31, - NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER = 32, - NL80211_EXT_FEATURE_AIRTIME_FAIRNESS = 33, - NL80211_EXT_FEATURE_AP_PMKSA_CACHING = 34, - NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD = 35, - NL80211_EXT_FEATURE_EXT_KEY_ID = 36, - NL80211_EXT_FEATURE_STA_TX_PWR = 37, - NL80211_EXT_FEATURE_SAE_OFFLOAD = 38, - NL80211_EXT_FEATURE_VLAN_OFFLOAD = 39, - NL80211_EXT_FEATURE_AQL = 40, - NL80211_EXT_FEATURE_BEACON_PROTECTION = 41, - NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH = 42, - NL80211_EXT_FEATURE_PROTECTED_TWT = 43, - NL80211_EXT_FEATURE_DEL_IBSS_STA = 44, - NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS = 45, - NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT = 46, - NL80211_EXT_FEATURE_SCAN_FREQ_KHZ = 47, - NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS = 48, - NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION = 49, - NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK = 50, - NL80211_EXT_FEATURE_SAE_OFFLOAD_AP = 51, - NL80211_EXT_FEATURE_FILS_DISCOVERY = 52, - NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP = 53, - NL80211_EXT_FEATURE_BEACON_RATE_HE = 54, - NL80211_EXT_FEATURE_SECURE_LTF = 55, - NL80211_EXT_FEATURE_SECURE_RTT = 56, - NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE = 57, - NUM_NL80211_EXT_FEATURES = 58, - MAX_NL80211_EXT_FEATURES = 57, -}; - -enum nl80211_dfs_state { - NL80211_DFS_USABLE = 0, - NL80211_DFS_UNAVAILABLE = 1, - NL80211_DFS_AVAILABLE = 2, -}; - -struct nl80211_vendor_cmd_info { - __u32 vendor_id; - __u32 subcmd; -}; - -enum nl80211_sar_type { - NL80211_SAR_TYPE_POWER = 0, - NUM_NL80211_SAR_TYPE = 1, -}; - -struct ieee80211_he_cap_elem { - u8 mac_cap_info[6]; - u8 phy_cap_info[11]; -}; - -struct ieee80211_he_mcs_nss_supp { - __le16 rx_mcs_80; - __le16 tx_mcs_80; - __le16 rx_mcs_160; - __le16 tx_mcs_160; - __le16 rx_mcs_80p80; - __le16 tx_mcs_80p80; -}; - -struct ieee80211_he_6ghz_capa { - __le16 capa; -}; - -struct rfkill; - -enum environment_cap { - ENVIRON_ANY = 0, - ENVIRON_INDOOR = 1, - ENVIRON_OUTDOOR = 2, -}; - -struct regulatory_request { - struct callback_head callback_head; - int wiphy_idx; - enum nl80211_reg_initiator initiator; - enum nl80211_user_reg_hint_type user_reg_hint_type; - char alpha2[3]; - enum nl80211_dfs_regions dfs_region; - bool intersect; - bool processed; - enum environment_cap country_ie_env; - struct list_head list; -}; - -struct ieee80211_freq_range { - u32 start_freq_khz; - u32 end_freq_khz; - u32 max_bandwidth_khz; -}; - -struct ieee80211_power_rule { - u32 max_antenna_gain; - u32 max_eirp; -}; - -struct ieee80211_wmm_ac { - u16 cw_min; - u16 cw_max; - u16 cot; - u8 aifsn; -}; - -struct ieee80211_wmm_rule { - struct ieee80211_wmm_ac client[4]; - struct ieee80211_wmm_ac ap[4]; -}; - -struct ieee80211_reg_rule { - struct ieee80211_freq_range freq_range; - struct ieee80211_power_rule power_rule; - struct ieee80211_wmm_rule wmm_rule; - u32 flags; - u32 dfs_cac_ms; - bool has_wmm; -}; - -struct ieee80211_regdomain { - struct callback_head callback_head; - u32 n_reg_rules; - char alpha2[3]; - enum nl80211_dfs_regions dfs_region; - struct ieee80211_reg_rule reg_rules[0]; -}; - -struct ieee80211_channel { - enum nl80211_band band; - u32 center_freq; - u16 freq_offset; - u16 hw_value; - u32 flags; - int max_antenna_gain; - int max_power; - int max_reg_power; - bool beacon_found; - u32 orig_flags; - int orig_mag; - int orig_mpwr; - enum nl80211_dfs_state dfs_state; - long unsigned int dfs_state_entered; - unsigned int dfs_cac_ms; -}; - -struct ieee80211_rate { - u32 flags; - u16 bitrate; - u16 hw_value; - u16 hw_value_short; -}; - -struct ieee80211_sta_ht_cap { - u16 cap; - bool ht_supported; - u8 ampdu_factor; - u8 ampdu_density; - struct ieee80211_mcs_info mcs; - char: 8; -} __attribute__((packed)); - -struct ieee80211_sta_vht_cap { - bool vht_supported; - u32 cap; - struct ieee80211_vht_mcs_info vht_mcs; -}; - -struct ieee80211_sta_he_cap { - bool has_he; - struct ieee80211_he_cap_elem he_cap_elem; - struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp; - u8 ppe_thres[25]; -} __attribute__((packed)); - -struct ieee80211_sband_iftype_data { - u16 types_mask; - struct ieee80211_sta_he_cap he_cap; - struct ieee80211_he_6ghz_capa he_6ghz_capa; - long: 40; - struct { - const u8 *data; - unsigned int len; - } vendor_elems; -} __attribute__((packed)); - -struct ieee80211_sta_s1g_cap { - bool s1g; - u8 cap[10]; - u8 nss_mcs[5]; -}; - -struct ieee80211_supported_band { - struct ieee80211_channel *channels; - struct ieee80211_rate *bitrates; - enum nl80211_band band; - int n_channels; - int n_bitrates; - struct ieee80211_sta_ht_cap ht_cap; - struct ieee80211_sta_vht_cap vht_cap; - struct ieee80211_sta_s1g_cap s1g_cap; - struct ieee80211_edmg edmg_cap; - u16 n_iftype_data; - const struct ieee80211_sband_iftype_data *iftype_data; -}; - -struct key_params { - const u8 *key; - const u8 *seq; - int key_len; - int seq_len; - u16 vlan_id; - u32 cipher; - enum nl80211_key_mode mode; -}; - -struct mac_address { - u8 addr[6]; -}; - -struct cfg80211_sar_freq_ranges { - u32 start_freq; - u32 end_freq; -}; - -struct cfg80211_sar_capa { - enum nl80211_sar_type type; - u32 num_freq_ranges; - const struct cfg80211_sar_freq_ranges *freq_ranges; -}; - -struct cfg80211_ssid { - u8 ssid[32]; - u8 ssid_len; -}; - -enum cfg80211_signal_type { - CFG80211_SIGNAL_TYPE_NONE = 0, - CFG80211_SIGNAL_TYPE_MBM = 1, - CFG80211_SIGNAL_TYPE_UNSPEC = 2, -}; - -struct ieee80211_txrx_stypes; - -struct ieee80211_iface_combination; - -struct wiphy_iftype_akm_suites; - -struct wiphy_wowlan_support; - -struct cfg80211_wowlan; - -struct wiphy_iftype_ext_capab; - -struct wiphy_coalesce_support; - -struct wiphy_vendor_command; - -struct cfg80211_pmsr_capabilities; - -struct wiphy { - struct mutex mtx; - u8 perm_addr[6]; - u8 addr_mask[6]; - struct mac_address *addresses; - const struct ieee80211_txrx_stypes *mgmt_stypes; - const struct ieee80211_iface_combination *iface_combinations; - int n_iface_combinations; - u16 software_iftypes; - u16 n_addresses; - u16 interface_modes; - u16 max_acl_mac_addrs; - u32 flags; - u32 regulatory_flags; - u32 features; - u8 ext_features[8]; - u32 ap_sme_capa; - enum cfg80211_signal_type signal_type; - int bss_priv_size; - u8 max_scan_ssids; - u8 max_sched_scan_reqs; - u8 max_sched_scan_ssids; - u8 max_match_sets; - u16 max_scan_ie_len; - u16 max_sched_scan_ie_len; - u32 max_sched_scan_plans; - u32 max_sched_scan_plan_interval; - u32 max_sched_scan_plan_iterations; - int n_cipher_suites; - const u32 *cipher_suites; - int n_akm_suites; - const u32 *akm_suites; - const struct wiphy_iftype_akm_suites *iftype_akm_suites; - unsigned int num_iftype_akm_suites; - u8 retry_short; - u8 retry_long; - u32 frag_threshold; - u32 rts_threshold; - u8 coverage_class; - char fw_version[32]; - u32 hw_version; - const struct wiphy_wowlan_support *wowlan; - struct cfg80211_wowlan *wowlan_config; - u16 max_remain_on_channel_duration; - u8 max_num_pmkids; - u32 available_antennas_tx; - u32 available_antennas_rx; - u32 probe_resp_offload; - const u8 *extended_capabilities; - const u8 *extended_capabilities_mask; - u8 extended_capabilities_len; - const struct wiphy_iftype_ext_capab *iftype_ext_capab; - unsigned int num_iftype_ext_capab; - const void *privid; - struct ieee80211_supported_band *bands[5]; - void (*reg_notifier)(struct wiphy *, struct regulatory_request *); - const struct ieee80211_regdomain *regd; - struct device dev; - bool registered; - struct dentry *debugfsdir; - const struct ieee80211_ht_cap *ht_capa_mod_mask; - const struct ieee80211_vht_cap *vht_capa_mod_mask; - struct list_head wdev_list; - possible_net_t _net; - const struct iw_handler_def *wext; - const struct wiphy_coalesce_support *coalesce; - const struct wiphy_vendor_command *vendor_commands; - const struct nl80211_vendor_cmd_info *vendor_events; - int n_vendor_commands; - int n_vendor_events; - u16 max_ap_assoc_sta; - u8 max_num_csa_counters; - u32 bss_select_support; - u8 nan_supported_bands; - u32 txq_limit; - u32 txq_memory_limit; - u32 txq_quantum; - long unsigned int tx_queue_len; - u8 support_mbssid: 1; - u8 support_only_he_mbssid: 1; - const struct cfg80211_pmsr_capabilities *pmsr_capa; - struct { - u64 peer; - u64 vif; - u8 max_retry; - } tid_config_support; - u8 max_data_retry_count; - const struct cfg80211_sar_capa *sar_capa; - struct rfkill *rfkill; - long: 64; - char priv[0]; -}; - -struct cfg80211_match_set { - struct cfg80211_ssid ssid; - u8 bssid[6]; - s32 rssi_thold; - s32 per_band_rssi_thold[5]; -}; - -struct cfg80211_sched_scan_plan { - u32 interval; - u32 iterations; -}; - -struct cfg80211_sched_scan_request { - u64 reqid; - struct cfg80211_ssid *ssids; - int n_ssids; - u32 n_channels; - enum nl80211_bss_scan_width scan_width; - const u8 *ie; - size_t ie_len; - u32 flags; - struct cfg80211_match_set *match_sets; - int n_match_sets; - s32 min_rssi_thold; - u32 delay; - struct cfg80211_sched_scan_plan *scan_plans; - int n_scan_plans; - u8 mac_addr[6]; - u8 mac_addr_mask[6]; - bool relative_rssi_set; - s8 relative_rssi; - struct cfg80211_bss_select_adjust rssi_adjust; - struct wiphy *wiphy; - struct net_device *dev; - long unsigned int scan_start; - bool report_results; - struct callback_head callback_head; - u32 owner_nlportid; - bool nl_owner_dead; - struct list_head list; - struct ieee80211_channel *channels[0]; -}; - -struct cfg80211_pkt_pattern { - const u8 *mask; - const u8 *pattern; - int pattern_len; - int pkt_offset; -}; - -struct cfg80211_wowlan_tcp { - struct socket *sock; - __be32 src; - __be32 dst; - u16 src_port; - u16 dst_port; - u8 dst_mac[6]; - int payload_len; - const u8 *payload; - struct nl80211_wowlan_tcp_data_seq payload_seq; - u32 data_interval; - u32 wake_len; - const u8 *wake_data; - const u8 *wake_mask; - u32 tokens_size; - struct nl80211_wowlan_tcp_data_token payload_tok; -}; - -struct cfg80211_wowlan { - bool any; - bool disconnect; - bool magic_pkt; - bool gtk_rekey_failure; - bool eap_identity_req; - bool four_way_handshake; - bool rfkill_release; - struct cfg80211_pkt_pattern *patterns; - struct cfg80211_wowlan_tcp *tcp; - int n_patterns; - struct cfg80211_sched_scan_request *nd_config; -}; - -struct ieee80211_iface_limit { - u16 max; - u16 types; -}; - -struct ieee80211_iface_combination { - const struct ieee80211_iface_limit *limits; - u32 num_different_channels; - u16 max_interfaces; - u8 n_limits; - bool beacon_int_infra_match; - u8 radar_detect_widths; - u8 radar_detect_regions; - u32 beacon_int_min_gcd; -}; - -struct ieee80211_txrx_stypes { - u16 tx; - u16 rx; -}; - -struct wiphy_wowlan_tcp_support { - const struct nl80211_wowlan_tcp_data_token_feature *tok; - u32 data_payload_max; - u32 data_interval_max; - u32 wake_payload_max; - bool seq; -}; - -struct wiphy_wowlan_support { - u32 flags; - int n_patterns; - int pattern_max_len; - int pattern_min_len; - int max_pkt_offset; - int max_nd_match_sets; - const struct wiphy_wowlan_tcp_support *tcp; -}; - -struct wiphy_coalesce_support { - int n_rules; - int max_delay; - int n_patterns; - int pattern_max_len; - int pattern_min_len; - int max_pkt_offset; -}; - -struct wiphy_vendor_command { - struct nl80211_vendor_cmd_info info; - u32 flags; - int (*doit)(struct wiphy *, struct wireless_dev *, const void *, int); - int (*dumpit)(struct wiphy *, struct wireless_dev *, struct sk_buff *, const void *, int, long unsigned int *); - const struct nla_policy *policy; - unsigned int maxattr; -}; - -struct wiphy_iftype_ext_capab { - enum nl80211_iftype iftype; - const u8 *extended_capabilities; - const u8 *extended_capabilities_mask; - u8 extended_capabilities_len; -}; - -struct cfg80211_pmsr_capabilities { - unsigned int max_peers; - u8 report_ap_tsf: 1; - u8 randomize_mac_addr: 1; - struct { - u32 preambles; - u32 bandwidths; - s8 max_bursts_exponent; - u8 max_ftms_per_burst; - u8 supported: 1; - u8 asap: 1; - u8 non_asap: 1; - u8 request_lci: 1; - u8 request_civicloc: 1; - u8 trigger_based: 1; - u8 non_trigger_based: 1; - } ftm; -}; - -struct wiphy_iftype_akm_suites { - u16 iftypes_mask; - const u32 *akm_suites; - int n_akm_suites; -}; - -struct iw_ioctl_description { - __u8 header_type; - __u8 token_type; - __u16 token_size; - __u16 min_tokens; - __u16 max_tokens; - __u32 flags; -}; - -typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, unsigned int, struct iw_request_info *, iw_handler); - -struct iw_thrspy { - struct sockaddr addr; - struct iw_quality qual; - struct iw_quality low; - struct iw_quality high; -}; - -struct netlbl_af4list { - __be32 addr; - __be32 mask; - u32 valid; - struct list_head list; -}; - -struct netlbl_af6list { - struct in6_addr addr; - struct in6_addr mask; - u32 valid; - struct list_head list; -}; - -struct netlbl_domaddr_map { - struct list_head list4; - struct list_head list6; -}; - -struct netlbl_dommap_def { - u32 type; - union { - struct netlbl_domaddr_map *addrsel; - struct cipso_v4_doi *cipso; - struct calipso_doi *calipso; - }; -}; - -struct netlbl_domaddr4_map { - struct netlbl_dommap_def def; - struct netlbl_af4list list; -}; - -struct netlbl_domaddr6_map { - struct netlbl_dommap_def def; - struct netlbl_af6list list; -}; - -struct netlbl_dom_map { - char *domain; - u16 family; - struct netlbl_dommap_def def; - u32 valid; - struct list_head list; - struct callback_head rcu; -}; - -struct netlbl_domhsh_tbl { - struct list_head *tbl; - u32 size; -}; - -enum { - NLBL_MGMT_C_UNSPEC = 0, - NLBL_MGMT_C_ADD = 1, - NLBL_MGMT_C_REMOVE = 2, - NLBL_MGMT_C_LISTALL = 3, - NLBL_MGMT_C_ADDDEF = 4, - NLBL_MGMT_C_REMOVEDEF = 5, - NLBL_MGMT_C_LISTDEF = 6, - NLBL_MGMT_C_PROTOCOLS = 7, - NLBL_MGMT_C_VERSION = 8, - __NLBL_MGMT_C_MAX = 9, -}; - -enum { - NLBL_MGMT_A_UNSPEC = 0, - NLBL_MGMT_A_DOMAIN = 1, - NLBL_MGMT_A_PROTOCOL = 2, - NLBL_MGMT_A_VERSION = 3, - NLBL_MGMT_A_CV4DOI = 4, - NLBL_MGMT_A_IPV6ADDR = 5, - NLBL_MGMT_A_IPV6MASK = 6, - NLBL_MGMT_A_IPV4ADDR = 7, - NLBL_MGMT_A_IPV4MASK = 8, - NLBL_MGMT_A_ADDRSELECTOR = 9, - NLBL_MGMT_A_SELECTORLIST = 10, - NLBL_MGMT_A_FAMILY = 11, - NLBL_MGMT_A_CLPDOI = 12, - __NLBL_MGMT_A_MAX = 13, -}; - -struct netlbl_domhsh_walk_arg { - struct netlink_callback *nl_cb; - struct sk_buff *skb; - u32 seq; -}; - -enum { - NLBL_UNLABEL_C_UNSPEC = 0, - NLBL_UNLABEL_C_ACCEPT = 1, - NLBL_UNLABEL_C_LIST = 2, - NLBL_UNLABEL_C_STATICADD = 3, - NLBL_UNLABEL_C_STATICREMOVE = 4, - NLBL_UNLABEL_C_STATICLIST = 5, - NLBL_UNLABEL_C_STATICADDDEF = 6, - NLBL_UNLABEL_C_STATICREMOVEDEF = 7, - NLBL_UNLABEL_C_STATICLISTDEF = 8, - __NLBL_UNLABEL_C_MAX = 9, -}; - -enum { - NLBL_UNLABEL_A_UNSPEC = 0, - NLBL_UNLABEL_A_ACPTFLG = 1, - NLBL_UNLABEL_A_IPV6ADDR = 2, - NLBL_UNLABEL_A_IPV6MASK = 3, - NLBL_UNLABEL_A_IPV4ADDR = 4, - NLBL_UNLABEL_A_IPV4MASK = 5, - NLBL_UNLABEL_A_IFACE = 6, - NLBL_UNLABEL_A_SECCTX = 7, - __NLBL_UNLABEL_A_MAX = 8, -}; - -struct netlbl_unlhsh_tbl { - struct list_head *tbl; - u32 size; -}; - -struct netlbl_unlhsh_addr4 { - u32 secid; - struct netlbl_af4list list; - struct callback_head rcu; -}; - -struct netlbl_unlhsh_addr6 { - u32 secid; - struct netlbl_af6list list; - struct callback_head rcu; -}; - -struct netlbl_unlhsh_iface { - int ifindex; - struct list_head addr4_list; - struct list_head addr6_list; - u32 valid; - struct list_head list; - struct callback_head rcu; -}; - -struct netlbl_unlhsh_walk_arg { - struct netlink_callback *nl_cb; - struct sk_buff *skb; - u32 seq; -}; - -enum { - NLBL_CIPSOV4_C_UNSPEC = 0, - NLBL_CIPSOV4_C_ADD = 1, - NLBL_CIPSOV4_C_REMOVE = 2, - NLBL_CIPSOV4_C_LIST = 3, - NLBL_CIPSOV4_C_LISTALL = 4, - __NLBL_CIPSOV4_C_MAX = 5, -}; - -enum { - NLBL_CIPSOV4_A_UNSPEC = 0, - NLBL_CIPSOV4_A_DOI = 1, - NLBL_CIPSOV4_A_MTYPE = 2, - NLBL_CIPSOV4_A_TAG = 3, - NLBL_CIPSOV4_A_TAGLST = 4, - NLBL_CIPSOV4_A_MLSLVLLOC = 5, - NLBL_CIPSOV4_A_MLSLVLREM = 6, - NLBL_CIPSOV4_A_MLSLVL = 7, - NLBL_CIPSOV4_A_MLSLVLLST = 8, - NLBL_CIPSOV4_A_MLSCATLOC = 9, - NLBL_CIPSOV4_A_MLSCATREM = 10, - NLBL_CIPSOV4_A_MLSCAT = 11, - NLBL_CIPSOV4_A_MLSCATLST = 12, - __NLBL_CIPSOV4_A_MAX = 13, -}; - -struct netlbl_cipsov4_doiwalk_arg { - struct netlink_callback *nl_cb; - struct sk_buff *skb; - u32 seq; -}; - -struct netlbl_domhsh_walk_arg___2 { - struct netlbl_audit *audit_info; - u32 doi; -}; - -enum { - NLBL_CALIPSO_C_UNSPEC = 0, - NLBL_CALIPSO_C_ADD = 1, - NLBL_CALIPSO_C_REMOVE = 2, - NLBL_CALIPSO_C_LIST = 3, - NLBL_CALIPSO_C_LISTALL = 4, - __NLBL_CALIPSO_C_MAX = 5, -}; - -enum { - NLBL_CALIPSO_A_UNSPEC = 0, - NLBL_CALIPSO_A_DOI = 1, - NLBL_CALIPSO_A_MTYPE = 2, - __NLBL_CALIPSO_A_MAX = 3, -}; - -struct netlbl_calipso_doiwalk_arg { - struct netlink_callback *nl_cb; - struct sk_buff *skb; - u32 seq; -}; - -struct dcbmsg { - __u8 dcb_family; - __u8 cmd; - __u16 dcb_pad; -}; - -enum dcbnl_commands { - DCB_CMD_UNDEFINED = 0, - DCB_CMD_GSTATE = 1, - DCB_CMD_SSTATE = 2, - DCB_CMD_PGTX_GCFG = 3, - DCB_CMD_PGTX_SCFG = 4, - DCB_CMD_PGRX_GCFG = 5, - DCB_CMD_PGRX_SCFG = 6, - DCB_CMD_PFC_GCFG = 7, - DCB_CMD_PFC_SCFG = 8, - DCB_CMD_SET_ALL = 9, - DCB_CMD_GPERM_HWADDR = 10, - DCB_CMD_GCAP = 11, - DCB_CMD_GNUMTCS = 12, - DCB_CMD_SNUMTCS = 13, - DCB_CMD_PFC_GSTATE = 14, - DCB_CMD_PFC_SSTATE = 15, - DCB_CMD_BCN_GCFG = 16, - DCB_CMD_BCN_SCFG = 17, - DCB_CMD_GAPP = 18, - DCB_CMD_SAPP = 19, - DCB_CMD_IEEE_SET = 20, - DCB_CMD_IEEE_GET = 21, - DCB_CMD_GDCBX = 22, - DCB_CMD_SDCBX = 23, - DCB_CMD_GFEATCFG = 24, - DCB_CMD_SFEATCFG = 25, - DCB_CMD_CEE_GET = 26, - DCB_CMD_IEEE_DEL = 27, - __DCB_CMD_ENUM_MAX = 28, - DCB_CMD_MAX = 27, -}; - -enum dcbnl_attrs { - DCB_ATTR_UNDEFINED = 0, - DCB_ATTR_IFNAME = 1, - DCB_ATTR_STATE = 2, - DCB_ATTR_PFC_STATE = 3, - DCB_ATTR_PFC_CFG = 4, - DCB_ATTR_NUM_TC = 5, - DCB_ATTR_PG_CFG = 6, - DCB_ATTR_SET_ALL = 7, - DCB_ATTR_PERM_HWADDR = 8, - DCB_ATTR_CAP = 9, - DCB_ATTR_NUMTCS = 10, - DCB_ATTR_BCN = 11, - DCB_ATTR_APP = 12, - DCB_ATTR_IEEE = 13, - DCB_ATTR_DCBX = 14, - DCB_ATTR_FEATCFG = 15, - DCB_ATTR_CEE = 16, - __DCB_ATTR_ENUM_MAX = 17, - DCB_ATTR_MAX = 16, -}; - -enum ieee_attrs { - DCB_ATTR_IEEE_UNSPEC = 0, - DCB_ATTR_IEEE_ETS = 1, - DCB_ATTR_IEEE_PFC = 2, - DCB_ATTR_IEEE_APP_TABLE = 3, - DCB_ATTR_IEEE_PEER_ETS = 4, - DCB_ATTR_IEEE_PEER_PFC = 5, - DCB_ATTR_IEEE_PEER_APP = 6, - DCB_ATTR_IEEE_MAXRATE = 7, - DCB_ATTR_IEEE_QCN = 8, - DCB_ATTR_IEEE_QCN_STATS = 9, - DCB_ATTR_DCB_BUFFER = 10, - __DCB_ATTR_IEEE_MAX = 11, -}; - -enum ieee_attrs_app { - DCB_ATTR_IEEE_APP_UNSPEC = 0, - DCB_ATTR_IEEE_APP = 1, - __DCB_ATTR_IEEE_APP_MAX = 2, -}; - -enum cee_attrs { - DCB_ATTR_CEE_UNSPEC = 0, - DCB_ATTR_CEE_PEER_PG = 1, - DCB_ATTR_CEE_PEER_PFC = 2, - DCB_ATTR_CEE_PEER_APP_TABLE = 3, - DCB_ATTR_CEE_TX_PG = 4, - DCB_ATTR_CEE_RX_PG = 5, - DCB_ATTR_CEE_PFC = 6, - DCB_ATTR_CEE_APP_TABLE = 7, - DCB_ATTR_CEE_FEAT = 8, - __DCB_ATTR_CEE_MAX = 9, -}; - -enum peer_app_attr { - DCB_ATTR_CEE_PEER_APP_UNSPEC = 0, - DCB_ATTR_CEE_PEER_APP_INFO = 1, - DCB_ATTR_CEE_PEER_APP = 2, - __DCB_ATTR_CEE_PEER_APP_MAX = 3, -}; - -enum dcbnl_pfc_up_attrs { - DCB_PFC_UP_ATTR_UNDEFINED = 0, - DCB_PFC_UP_ATTR_0 = 1, - DCB_PFC_UP_ATTR_1 = 2, - DCB_PFC_UP_ATTR_2 = 3, - DCB_PFC_UP_ATTR_3 = 4, - DCB_PFC_UP_ATTR_4 = 5, - DCB_PFC_UP_ATTR_5 = 6, - DCB_PFC_UP_ATTR_6 = 7, - DCB_PFC_UP_ATTR_7 = 8, - DCB_PFC_UP_ATTR_ALL = 9, - __DCB_PFC_UP_ATTR_ENUM_MAX = 10, - DCB_PFC_UP_ATTR_MAX = 9, -}; - -enum dcbnl_pg_attrs { - DCB_PG_ATTR_UNDEFINED = 0, - DCB_PG_ATTR_TC_0 = 1, - DCB_PG_ATTR_TC_1 = 2, - DCB_PG_ATTR_TC_2 = 3, - DCB_PG_ATTR_TC_3 = 4, - DCB_PG_ATTR_TC_4 = 5, - DCB_PG_ATTR_TC_5 = 6, - DCB_PG_ATTR_TC_6 = 7, - DCB_PG_ATTR_TC_7 = 8, - DCB_PG_ATTR_TC_MAX = 9, - DCB_PG_ATTR_TC_ALL = 10, - DCB_PG_ATTR_BW_ID_0 = 11, - DCB_PG_ATTR_BW_ID_1 = 12, - DCB_PG_ATTR_BW_ID_2 = 13, - DCB_PG_ATTR_BW_ID_3 = 14, - DCB_PG_ATTR_BW_ID_4 = 15, - DCB_PG_ATTR_BW_ID_5 = 16, - DCB_PG_ATTR_BW_ID_6 = 17, - DCB_PG_ATTR_BW_ID_7 = 18, - DCB_PG_ATTR_BW_ID_MAX = 19, - DCB_PG_ATTR_BW_ID_ALL = 20, - __DCB_PG_ATTR_ENUM_MAX = 21, - DCB_PG_ATTR_MAX = 20, -}; - -enum dcbnl_tc_attrs { - DCB_TC_ATTR_PARAM_UNDEFINED = 0, - DCB_TC_ATTR_PARAM_PGID = 1, - DCB_TC_ATTR_PARAM_UP_MAPPING = 2, - DCB_TC_ATTR_PARAM_STRICT_PRIO = 3, - DCB_TC_ATTR_PARAM_BW_PCT = 4, - DCB_TC_ATTR_PARAM_ALL = 5, - __DCB_TC_ATTR_PARAM_ENUM_MAX = 6, - DCB_TC_ATTR_PARAM_MAX = 5, -}; - -enum dcbnl_cap_attrs { - DCB_CAP_ATTR_UNDEFINED = 0, - DCB_CAP_ATTR_ALL = 1, - DCB_CAP_ATTR_PG = 2, - DCB_CAP_ATTR_PFC = 3, - DCB_CAP_ATTR_UP2TC = 4, - DCB_CAP_ATTR_PG_TCS = 5, - DCB_CAP_ATTR_PFC_TCS = 6, - DCB_CAP_ATTR_GSP = 7, - DCB_CAP_ATTR_BCN = 8, - DCB_CAP_ATTR_DCBX = 9, - __DCB_CAP_ATTR_ENUM_MAX = 10, - DCB_CAP_ATTR_MAX = 9, -}; - -enum dcbnl_numtcs_attrs { - DCB_NUMTCS_ATTR_UNDEFINED = 0, - DCB_NUMTCS_ATTR_ALL = 1, - DCB_NUMTCS_ATTR_PG = 2, - DCB_NUMTCS_ATTR_PFC = 3, - __DCB_NUMTCS_ATTR_ENUM_MAX = 4, - DCB_NUMTCS_ATTR_MAX = 3, -}; - -enum dcbnl_bcn_attrs { - DCB_BCN_ATTR_UNDEFINED = 0, - DCB_BCN_ATTR_RP_0 = 1, - DCB_BCN_ATTR_RP_1 = 2, - DCB_BCN_ATTR_RP_2 = 3, - DCB_BCN_ATTR_RP_3 = 4, - DCB_BCN_ATTR_RP_4 = 5, - DCB_BCN_ATTR_RP_5 = 6, - DCB_BCN_ATTR_RP_6 = 7, - DCB_BCN_ATTR_RP_7 = 8, - DCB_BCN_ATTR_RP_ALL = 9, - DCB_BCN_ATTR_BCNA_0 = 10, - DCB_BCN_ATTR_BCNA_1 = 11, - DCB_BCN_ATTR_ALPHA = 12, - DCB_BCN_ATTR_BETA = 13, - DCB_BCN_ATTR_GD = 14, - DCB_BCN_ATTR_GI = 15, - DCB_BCN_ATTR_TMAX = 16, - DCB_BCN_ATTR_TD = 17, - DCB_BCN_ATTR_RMIN = 18, - DCB_BCN_ATTR_W = 19, - DCB_BCN_ATTR_RD = 20, - DCB_BCN_ATTR_RU = 21, - DCB_BCN_ATTR_WRTT = 22, - DCB_BCN_ATTR_RI = 23, - DCB_BCN_ATTR_C = 24, - DCB_BCN_ATTR_ALL = 25, - __DCB_BCN_ATTR_ENUM_MAX = 26, - DCB_BCN_ATTR_MAX = 25, -}; - -enum dcb_general_attr_values { - DCB_ATTR_VALUE_UNDEFINED = 255, -}; - -enum dcbnl_app_attrs { - DCB_APP_ATTR_UNDEFINED = 0, - DCB_APP_ATTR_IDTYPE = 1, - DCB_APP_ATTR_ID = 2, - DCB_APP_ATTR_PRIORITY = 3, - __DCB_APP_ATTR_ENUM_MAX = 4, - DCB_APP_ATTR_MAX = 3, -}; - -enum dcbnl_featcfg_attrs { - DCB_FEATCFG_ATTR_UNDEFINED = 0, - DCB_FEATCFG_ATTR_ALL = 1, - DCB_FEATCFG_ATTR_PG = 2, - DCB_FEATCFG_ATTR_PFC = 3, - DCB_FEATCFG_ATTR_APP = 4, - __DCB_FEATCFG_ATTR_ENUM_MAX = 5, - DCB_FEATCFG_ATTR_MAX = 4, -}; - -struct dcb_app_type { - int ifindex; - struct dcb_app app; - struct list_head list; - u8 dcbx; -}; - -struct dcb_ieee_app_prio_map { - u64 map[8]; -}; - -struct dcb_ieee_app_dscp_map { - u8 map[64]; -}; - -enum dcbevent_notif_type { - DCB_APP_EVENT = 1, -}; - -struct reply_func { - int type; - int (*cb)(struct net_device *, struct nlmsghdr *, u32, struct nlattr **, struct sk_buff *); -}; - -enum switchdev_attr_id { - SWITCHDEV_ATTR_ID_UNDEFINED = 0, - SWITCHDEV_ATTR_ID_PORT_STP_STATE = 1, - SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS = 2, - SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS = 3, - SWITCHDEV_ATTR_ID_PORT_MROUTER = 4, - SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME = 5, - SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING = 6, - SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL = 7, - SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED = 8, - SWITCHDEV_ATTR_ID_BRIDGE_MROUTER = 9, - SWITCHDEV_ATTR_ID_MRP_PORT_ROLE = 10, -}; - -struct switchdev_attr { - struct net_device *orig_dev; - enum switchdev_attr_id id; - u32 flags; - void *complete_priv; - void (*complete)(struct net_device *, int, void *); - union { - u8 stp_state; - struct switchdev_brport_flags brport_flags; - bool mrouter; - clock_t ageing_time; - bool vlan_filtering; - u16 vlan_protocol; - bool mc_disabled; - u8 mrp_port_role; - } u; -}; - -enum switchdev_notifier_type { - SWITCHDEV_FDB_ADD_TO_BRIDGE = 1, - SWITCHDEV_FDB_DEL_TO_BRIDGE = 2, - SWITCHDEV_FDB_ADD_TO_DEVICE = 3, - SWITCHDEV_FDB_DEL_TO_DEVICE = 4, - SWITCHDEV_FDB_OFFLOADED = 5, - SWITCHDEV_FDB_FLUSH_TO_BRIDGE = 6, - SWITCHDEV_PORT_OBJ_ADD = 7, - SWITCHDEV_PORT_OBJ_DEL = 8, - SWITCHDEV_PORT_ATTR_SET = 9, - SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE = 10, - SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE = 11, - SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE = 12, - SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE = 13, - SWITCHDEV_VXLAN_FDB_OFFLOADED = 14, -}; - -struct switchdev_notifier_info { - struct net_device *dev; - struct netlink_ext_ack *extack; - const void *ctx; -}; - -struct switchdev_notifier_port_obj_info { - struct switchdev_notifier_info info; - const struct switchdev_obj *obj; - bool handled; -}; - -struct switchdev_notifier_port_attr_info { - struct switchdev_notifier_info info; - const struct switchdev_attr *attr; - bool handled; -}; - -typedef void switchdev_deferred_func_t(struct net_device *, const void *); - -struct switchdev_deferred_item { - struct list_head list; - struct net_device *dev; - switchdev_deferred_func_t *func; - long unsigned int data[0]; -}; - -typedef int (*lookup_by_table_id_t)(struct net *, u32); - -struct l3mdev_handler { - lookup_by_table_id_t dev_lookup; -}; - -struct ncsi_dev { - int state; - int link_up; - struct net_device *dev; - void (*handler)(struct ncsi_dev *); -}; - -enum { - NCSI_CAP_BASE = 0, - NCSI_CAP_GENERIC = 0, - NCSI_CAP_BC = 1, - NCSI_CAP_MC = 2, - NCSI_CAP_BUFFER = 3, - NCSI_CAP_AEN = 4, - NCSI_CAP_VLAN = 5, - NCSI_CAP_MAX = 6, -}; - -enum { - NCSI_MODE_BASE = 0, - NCSI_MODE_ENABLE = 0, - NCSI_MODE_TX_ENABLE = 1, - NCSI_MODE_LINK = 2, - NCSI_MODE_VLAN = 3, - NCSI_MODE_BC = 4, - NCSI_MODE_MC = 5, - NCSI_MODE_AEN = 6, - NCSI_MODE_FC = 7, - NCSI_MODE_MAX = 8, -}; - -struct ncsi_channel_version { - u32 version; - u32 alpha2; - u8 fw_name[12]; - u32 fw_version; - u16 pci_ids[4]; - u32 mf_id; -}; - -struct ncsi_channel_cap { - u32 index; - u32 cap; -}; - -struct ncsi_channel_mode { - u32 index; - u32 enable; - u32 size; - u32 data[8]; -}; - -struct ncsi_channel_mac_filter { - u8 n_uc; - u8 n_mc; - u8 n_mixed; - u64 bitmap; - unsigned char *addrs; -}; - -struct ncsi_channel_vlan_filter { - u8 n_vids; - u64 bitmap; - u16 *vids; -}; - -struct ncsi_channel_stats { - u32 hnc_cnt_hi; - u32 hnc_cnt_lo; - u32 hnc_rx_bytes; - u32 hnc_tx_bytes; - u32 hnc_rx_uc_pkts; - u32 hnc_rx_mc_pkts; - u32 hnc_rx_bc_pkts; - u32 hnc_tx_uc_pkts; - u32 hnc_tx_mc_pkts; - u32 hnc_tx_bc_pkts; - u32 hnc_fcs_err; - u32 hnc_align_err; - u32 hnc_false_carrier; - u32 hnc_runt_pkts; - u32 hnc_jabber_pkts; - u32 hnc_rx_pause_xon; - u32 hnc_rx_pause_xoff; - u32 hnc_tx_pause_xon; - u32 hnc_tx_pause_xoff; - u32 hnc_tx_s_collision; - u32 hnc_tx_m_collision; - u32 hnc_l_collision; - u32 hnc_e_collision; - u32 hnc_rx_ctl_frames; - u32 hnc_rx_64_frames; - u32 hnc_rx_127_frames; - u32 hnc_rx_255_frames; - u32 hnc_rx_511_frames; - u32 hnc_rx_1023_frames; - u32 hnc_rx_1522_frames; - u32 hnc_rx_9022_frames; - u32 hnc_tx_64_frames; - u32 hnc_tx_127_frames; - u32 hnc_tx_255_frames; - u32 hnc_tx_511_frames; - u32 hnc_tx_1023_frames; - u32 hnc_tx_1522_frames; - u32 hnc_tx_9022_frames; - u32 hnc_rx_valid_bytes; - u32 hnc_rx_runt_pkts; - u32 hnc_rx_jabber_pkts; - u32 ncsi_rx_cmds; - u32 ncsi_dropped_cmds; - u32 ncsi_cmd_type_errs; - u32 ncsi_cmd_csum_errs; - u32 ncsi_rx_pkts; - u32 ncsi_tx_pkts; - u32 ncsi_tx_aen_pkts; - u32 pt_tx_pkts; - u32 pt_tx_dropped; - u32 pt_tx_channel_err; - u32 pt_tx_us_err; - u32 pt_rx_pkts; - u32 pt_rx_dropped; - u32 pt_rx_channel_err; - u32 pt_rx_us_err; - u32 pt_rx_os_err; -}; - -struct ncsi_package; - -struct ncsi_channel { - unsigned char id; - int state; - bool reconfigure_needed; - spinlock_t lock; - struct ncsi_package *package; - struct ncsi_channel_version version; - struct ncsi_channel_cap caps[6]; - struct ncsi_channel_mode modes[8]; - struct ncsi_channel_mac_filter mac_filter; - struct ncsi_channel_vlan_filter vlan_filter; - struct ncsi_channel_stats stats; - struct { - struct timer_list timer; - bool enabled; - unsigned int state; - } monitor; - struct list_head node; - struct list_head link; -}; - -struct ncsi_dev_priv; - -struct ncsi_package { - unsigned char id; - unsigned char uuid[16]; - struct ncsi_dev_priv *ndp; - spinlock_t lock; - unsigned int channel_num; - struct list_head channels; - struct list_head node; - bool multi_channel; - u32 channel_whitelist; - struct ncsi_channel *preferred_channel; -}; - -struct ncsi_request { - unsigned char id; - bool used; - unsigned int flags; - struct ncsi_dev_priv *ndp; - struct sk_buff *cmd; - struct sk_buff *rsp; - struct timer_list timer; - bool enabled; - u32 snd_seq; - u32 snd_portid; - struct nlmsghdr nlhdr; -}; - -struct ncsi_dev_priv { - struct ncsi_dev ndev; - unsigned int flags; - unsigned int gma_flag; - spinlock_t lock; - unsigned int package_probe_id; - unsigned int package_num; - struct list_head packages; - struct ncsi_channel *hot_channel; - struct ncsi_request requests[256]; - unsigned int request_id; - unsigned int pending_req_num; - struct ncsi_package *active_package; - struct ncsi_channel *active_channel; - struct list_head channel_queue; - struct work_struct work; - struct packet_type ptype; - struct list_head node; - struct list_head vlan_vids; - bool multi_package; - bool mlx_multi_host; - u32 package_whitelist; -}; - -struct ncsi_cmd_arg { - struct ncsi_dev_priv *ndp; - unsigned char type; - unsigned char id; - unsigned char package; - unsigned char channel; - short unsigned int payload; - unsigned int req_flags; - union { - unsigned char bytes[16]; - short unsigned int words[8]; - unsigned int dwords[4]; - }; - unsigned char *data; - struct genl_info *info; -}; - -struct ncsi_pkt_hdr { - unsigned char mc_id; - unsigned char revision; - unsigned char reserved; - unsigned char id; - unsigned char type; - unsigned char channel; - __be16 length; - __be32 reserved1[2]; -}; - -struct ncsi_cmd_pkt_hdr { - struct ncsi_pkt_hdr common; -}; - -struct ncsi_cmd_pkt { - struct ncsi_cmd_pkt_hdr cmd; - __be32 checksum; - unsigned char pad[26]; -}; - -struct ncsi_cmd_sp_pkt { - struct ncsi_cmd_pkt_hdr cmd; - unsigned char reserved[3]; - unsigned char hw_arbitration; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_cmd_dc_pkt { - struct ncsi_cmd_pkt_hdr cmd; - unsigned char reserved[3]; - unsigned char ald; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_cmd_rc_pkt { - struct ncsi_cmd_pkt_hdr cmd; - __be32 reserved; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_cmd_ae_pkt { - struct ncsi_cmd_pkt_hdr cmd; - unsigned char reserved[3]; - unsigned char mc_id; - __be32 mode; - __be32 checksum; - unsigned char pad[18]; -}; - -struct ncsi_cmd_sl_pkt { - struct ncsi_cmd_pkt_hdr cmd; - __be32 mode; - __be32 oem_mode; - __be32 checksum; - unsigned char pad[18]; -}; - -struct ncsi_cmd_svf_pkt { - struct ncsi_cmd_pkt_hdr cmd; - __be16 reserved; - __be16 vlan; - __be16 reserved1; - unsigned char index; - unsigned char enable; - __be32 checksum; - unsigned char pad[18]; -}; - -struct ncsi_cmd_ev_pkt { - struct ncsi_cmd_pkt_hdr cmd; - unsigned char reserved[3]; - unsigned char mode; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_cmd_sma_pkt { - struct ncsi_cmd_pkt_hdr cmd; - unsigned char mac[6]; - unsigned char index; - unsigned char at_e; - __be32 checksum; - unsigned char pad[18]; -}; - -struct ncsi_cmd_ebf_pkt { - struct ncsi_cmd_pkt_hdr cmd; - __be32 mode; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_cmd_egmf_pkt { - struct ncsi_cmd_pkt_hdr cmd; - __be32 mode; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_cmd_snfc_pkt { - struct ncsi_cmd_pkt_hdr cmd; - unsigned char reserved[3]; - unsigned char mode; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_cmd_oem_pkt { - struct ncsi_cmd_pkt_hdr cmd; - __be32 mfr_id; - unsigned char data[0]; -}; - -struct ncsi_cmd_handler { - unsigned char type; - int payload; - int (*handler)(struct sk_buff *, struct ncsi_cmd_arg *); -}; - -enum { - NCSI_CAP_GENERIC_HWA = 1, - NCSI_CAP_GENERIC_HDS = 2, - NCSI_CAP_GENERIC_FC = 4, - NCSI_CAP_GENERIC_FC1 = 8, - NCSI_CAP_GENERIC_MC = 16, - NCSI_CAP_GENERIC_HWA_UNKNOWN = 0, - NCSI_CAP_GENERIC_HWA_SUPPORT = 32, - NCSI_CAP_GENERIC_HWA_NOT_SUPPORT = 64, - NCSI_CAP_GENERIC_HWA_RESERVED = 96, - NCSI_CAP_GENERIC_HWA_MASK = 96, - NCSI_CAP_GENERIC_MASK = 127, - NCSI_CAP_BC_ARP = 1, - NCSI_CAP_BC_DHCPC = 2, - NCSI_CAP_BC_DHCPS = 4, - NCSI_CAP_BC_NETBIOS = 8, - NCSI_CAP_BC_MASK = 15, - NCSI_CAP_MC_IPV6_NEIGHBOR = 1, - NCSI_CAP_MC_IPV6_ROUTER = 2, - NCSI_CAP_MC_DHCPV6_RELAY = 4, - NCSI_CAP_MC_DHCPV6_WELL_KNOWN = 8, - NCSI_CAP_MC_IPV6_MLD = 16, - NCSI_CAP_MC_IPV6_NEIGHBOR_S = 32, - NCSI_CAP_MC_MASK = 63, - NCSI_CAP_AEN_LSC = 1, - NCSI_CAP_AEN_CR = 2, - NCSI_CAP_AEN_HDS = 4, - NCSI_CAP_AEN_MASK = 7, - NCSI_CAP_VLAN_ONLY = 1, - NCSI_CAP_VLAN_NO = 2, - NCSI_CAP_VLAN_ANY = 4, - NCSI_CAP_VLAN_MASK = 7, -}; - -struct ncsi_rsp_pkt_hdr { - struct ncsi_pkt_hdr common; - __be16 code; - __be16 reason; -}; - -struct ncsi_rsp_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 checksum; - unsigned char pad[22]; -}; - -struct ncsi_rsp_oem_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 mfr_id; - unsigned char data[0]; -}; - -struct ncsi_rsp_oem_mlx_pkt { - unsigned char cmd_rev; - unsigned char cmd; - unsigned char param; - unsigned char optional; - unsigned char data[0]; -}; - -struct ncsi_rsp_oem_bcm_pkt { - unsigned char ver; - unsigned char type; - __be16 len; - unsigned char data[0]; -}; - -struct ncsi_rsp_gls_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 status; - __be32 other; - __be32 oem_status; - __be32 checksum; - unsigned char pad[10]; -}; - -struct ncsi_rsp_gvi_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 ncsi_version; - unsigned char reserved[3]; - unsigned char alpha2; - unsigned char fw_name[12]; - __be32 fw_version; - __be16 pci_ids[4]; - __be32 mf_id; - __be32 checksum; -}; - -struct ncsi_rsp_gc_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 cap; - __be32 bc_cap; - __be32 mc_cap; - __be32 buf_cap; - __be32 aen_cap; - unsigned char vlan_cnt; - unsigned char mixed_cnt; - unsigned char mc_cnt; - unsigned char uc_cnt; - unsigned char reserved[2]; - unsigned char vlan_mode; - unsigned char channel_cnt; - __be32 checksum; -}; - -struct ncsi_rsp_gp_pkt { - struct ncsi_rsp_pkt_hdr rsp; - unsigned char mac_cnt; - unsigned char reserved[2]; - unsigned char mac_enable; - unsigned char vlan_cnt; - unsigned char reserved1; - __be16 vlan_enable; - __be32 link_mode; - __be32 bc_mode; - __be32 valid_modes; - unsigned char vlan_mode; - unsigned char fc_mode; - unsigned char reserved2[2]; - __be32 aen_mode; - unsigned char mac[6]; - __be16 vlan; - __be32 checksum; -}; - -struct ncsi_rsp_gcps_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 cnt_hi; - __be32 cnt_lo; - __be32 rx_bytes; - __be32 tx_bytes; - __be32 rx_uc_pkts; - __be32 rx_mc_pkts; - __be32 rx_bc_pkts; - __be32 tx_uc_pkts; - __be32 tx_mc_pkts; - __be32 tx_bc_pkts; - __be32 fcs_err; - __be32 align_err; - __be32 false_carrier; - __be32 runt_pkts; - __be32 jabber_pkts; - __be32 rx_pause_xon; - __be32 rx_pause_xoff; - __be32 tx_pause_xon; - __be32 tx_pause_xoff; - __be32 tx_s_collision; - __be32 tx_m_collision; - __be32 l_collision; - __be32 e_collision; - __be32 rx_ctl_frames; - __be32 rx_64_frames; - __be32 rx_127_frames; - __be32 rx_255_frames; - __be32 rx_511_frames; - __be32 rx_1023_frames; - __be32 rx_1522_frames; - __be32 rx_9022_frames; - __be32 tx_64_frames; - __be32 tx_127_frames; - __be32 tx_255_frames; - __be32 tx_511_frames; - __be32 tx_1023_frames; - __be32 tx_1522_frames; - __be32 tx_9022_frames; - __be32 rx_valid_bytes; - __be32 rx_runt_pkts; - __be32 rx_jabber_pkts; - __be32 checksum; -}; - -struct ncsi_rsp_gns_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 rx_cmds; - __be32 dropped_cmds; - __be32 cmd_type_errs; - __be32 cmd_csum_errs; - __be32 rx_pkts; - __be32 tx_pkts; - __be32 tx_aen_pkts; - __be32 checksum; -}; - -struct ncsi_rsp_gnpts_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 tx_pkts; - __be32 tx_dropped; - __be32 tx_channel_err; - __be32 tx_us_err; - __be32 rx_pkts; - __be32 rx_dropped; - __be32 rx_channel_err; - __be32 rx_us_err; - __be32 rx_os_err; - __be32 checksum; -}; - -struct ncsi_rsp_gps_pkt { - struct ncsi_rsp_pkt_hdr rsp; - __be32 status; - __be32 checksum; -}; - -struct ncsi_rsp_gpuuid_pkt { - struct ncsi_rsp_pkt_hdr rsp; - unsigned char uuid[16]; - __be32 checksum; -}; - -struct ncsi_rsp_oem_handler { - unsigned int mfr_id; - int (*handler)(struct ncsi_request *); -}; - -struct ncsi_rsp_handler { - unsigned char type; - int payload; - int (*handler)(struct ncsi_request *); -}; - -struct ncsi_aen_pkt_hdr { - struct ncsi_pkt_hdr common; - unsigned char reserved2[3]; - unsigned char type; -}; - -struct ncsi_aen_lsc_pkt { - struct ncsi_aen_pkt_hdr aen; - __be32 status; - __be32 oem_status; - __be32 checksum; - unsigned char pad[14]; -}; - -struct ncsi_aen_hncdsc_pkt { - struct ncsi_aen_pkt_hdr aen; - __be32 status; - __be32 checksum; - unsigned char pad[18]; -}; - -struct ncsi_aen_handler { - unsigned char type; - int payload; - int (*handler)(struct ncsi_dev_priv *, struct ncsi_aen_pkt_hdr *); -}; - -enum { - ncsi_dev_state_registered = 0, - ncsi_dev_state_functional = 256, - ncsi_dev_state_probe = 512, - ncsi_dev_state_config = 768, - ncsi_dev_state_suspend = 1024, -}; - -enum { - MLX_MC_RBT_SUPPORT = 1, - MLX_MC_RBT_AVL = 8, -}; - -enum { - ncsi_dev_state_major = 65280, - ncsi_dev_state_minor = 255, - ncsi_dev_state_probe_deselect = 513, - ncsi_dev_state_probe_package = 514, - ncsi_dev_state_probe_channel = 515, - ncsi_dev_state_probe_mlx_gma = 516, - ncsi_dev_state_probe_mlx_smaf = 517, - ncsi_dev_state_probe_cis = 518, - ncsi_dev_state_probe_keep_phy = 519, - ncsi_dev_state_probe_gvi = 520, - ncsi_dev_state_probe_gc = 521, - ncsi_dev_state_probe_gls = 522, - ncsi_dev_state_probe_dp = 523, - ncsi_dev_state_config_sp = 769, - ncsi_dev_state_config_cis = 770, - ncsi_dev_state_config_oem_gma = 771, - ncsi_dev_state_config_clear_vids = 772, - ncsi_dev_state_config_svf = 773, - ncsi_dev_state_config_ev = 774, - ncsi_dev_state_config_sma = 775, - ncsi_dev_state_config_ebf = 776, - ncsi_dev_state_config_dgmf = 777, - ncsi_dev_state_config_ecnt = 778, - ncsi_dev_state_config_ec = 779, - ncsi_dev_state_config_ae = 780, - ncsi_dev_state_config_gls = 781, - ncsi_dev_state_config_done = 782, - ncsi_dev_state_suspend_select = 1025, - ncsi_dev_state_suspend_gls = 1026, - ncsi_dev_state_suspend_dcnt = 1027, - ncsi_dev_state_suspend_dc = 1028, - ncsi_dev_state_suspend_deselect = 1029, - ncsi_dev_state_suspend_done = 1030, -}; - -struct vlan_vid { - struct list_head list; - __be16 proto; - u16 vid; -}; - -struct ncsi_oem_gma_handler { - unsigned int mfr_id; - int (*handler)(struct ncsi_cmd_arg *); -}; - -enum ncsi_nl_commands { - NCSI_CMD_UNSPEC = 0, - NCSI_CMD_PKG_INFO = 1, - NCSI_CMD_SET_INTERFACE = 2, - NCSI_CMD_CLEAR_INTERFACE = 3, - NCSI_CMD_SEND_CMD = 4, - NCSI_CMD_SET_PACKAGE_MASK = 5, - NCSI_CMD_SET_CHANNEL_MASK = 6, - __NCSI_CMD_AFTER_LAST = 7, - NCSI_CMD_MAX = 6, -}; - -enum ncsi_nl_attrs { - NCSI_ATTR_UNSPEC = 0, - NCSI_ATTR_IFINDEX = 1, - NCSI_ATTR_PACKAGE_LIST = 2, - NCSI_ATTR_PACKAGE_ID = 3, - NCSI_ATTR_CHANNEL_ID = 4, - NCSI_ATTR_DATA = 5, - NCSI_ATTR_MULTI_FLAG = 6, - NCSI_ATTR_PACKAGE_MASK = 7, - NCSI_ATTR_CHANNEL_MASK = 8, - __NCSI_ATTR_AFTER_LAST = 9, - NCSI_ATTR_MAX = 8, -}; - -enum ncsi_nl_pkg_attrs { - NCSI_PKG_ATTR_UNSPEC = 0, - NCSI_PKG_ATTR = 1, - NCSI_PKG_ATTR_ID = 2, - NCSI_PKG_ATTR_FORCED = 3, - NCSI_PKG_ATTR_CHANNEL_LIST = 4, - __NCSI_PKG_ATTR_AFTER_LAST = 5, - NCSI_PKG_ATTR_MAX = 4, -}; - -enum ncsi_nl_channel_attrs { - NCSI_CHANNEL_ATTR_UNSPEC = 0, - NCSI_CHANNEL_ATTR = 1, - NCSI_CHANNEL_ATTR_ID = 2, - NCSI_CHANNEL_ATTR_VERSION_MAJOR = 3, - NCSI_CHANNEL_ATTR_VERSION_MINOR = 4, - NCSI_CHANNEL_ATTR_VERSION_STR = 5, - NCSI_CHANNEL_ATTR_LINK_STATE = 6, - NCSI_CHANNEL_ATTR_ACTIVE = 7, - NCSI_CHANNEL_ATTR_FORCED = 8, - NCSI_CHANNEL_ATTR_VLAN_LIST = 9, - NCSI_CHANNEL_ATTR_VLAN_ID = 10, - __NCSI_CHANNEL_ATTR_AFTER_LAST = 11, - NCSI_CHANNEL_ATTR_MAX = 10, -}; - -struct sockaddr_xdp { - __u16 sxdp_family; - __u16 sxdp_flags; - __u32 sxdp_ifindex; - __u32 sxdp_queue_id; - __u32 sxdp_shared_umem_fd; -}; - -struct xdp_ring_offset { - __u64 producer; - __u64 consumer; - __u64 desc; - __u64 flags; -}; - -struct xdp_mmap_offsets { - struct xdp_ring_offset rx; - struct xdp_ring_offset tx; - struct xdp_ring_offset fr; - struct xdp_ring_offset cr; -}; - -struct xdp_umem_reg { - __u64 addr; - __u64 len; - __u32 chunk_size; - __u32 headroom; - __u32 flags; -}; - -struct xdp_statistics { - __u64 rx_dropped; - __u64 rx_invalid_descs; - __u64 tx_invalid_descs; - __u64 rx_ring_full; - __u64 rx_fill_ring_empty_descs; - __u64 tx_ring_empty_descs; -}; - -struct xdp_options { - __u32 flags; -}; - -struct xdp_desc { - __u64 addr; - __u32 len; - __u32 options; -}; - -struct xsk_map { - struct bpf_map map; - spinlock_t lock; - struct xdp_sock *xsk_map[0]; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct xdp_ring; - -struct xsk_queue { - u32 ring_mask; - u32 nentries; - u32 cached_prod; - u32 cached_cons; - struct xdp_ring *ring; - u64 invalid_descs; - u64 queue_empty_descs; -}; - -struct xdp_ring_offset_v1 { - __u64 producer; - __u64 consumer; - __u64 desc; -}; - -struct xdp_mmap_offsets_v1 { - struct xdp_ring_offset_v1 rx; - struct xdp_ring_offset_v1 tx; - struct xdp_ring_offset_v1 fr; - struct xdp_ring_offset_v1 cr; -}; - -struct xsk_map_node { - struct list_head node; - struct xsk_map *map; - struct xdp_sock **map_entry; -}; - -struct xdp_ring { - u32 producer; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 pad1; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 consumer; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 pad2; - u32 flags; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - u32 pad3; - long: 32; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; - long: 64; -}; - -struct xdp_rxtx_ring { - struct xdp_ring ptrs; - struct xdp_desc desc[0]; -}; - -struct xdp_umem_ring { - struct xdp_ring ptrs; - u64 desc[0]; -}; - -struct xsk_dma_map { - dma_addr_t *dma_pages; - struct device *dev; - struct net_device *netdev; - refcount_t users; - struct list_head list; - u32 dma_pages_cnt; - bool dma_need_sync; -}; - -struct mptcp_mib { - long unsigned int mibs[37]; -}; - -enum mptcp_event_type { - MPTCP_EVENT_UNSPEC = 0, - MPTCP_EVENT_CREATED = 1, - MPTCP_EVENT_ESTABLISHED = 2, - MPTCP_EVENT_CLOSED = 3, - MPTCP_EVENT_ANNOUNCED = 6, - MPTCP_EVENT_REMOVED = 7, - MPTCP_EVENT_SUB_ESTABLISHED = 10, - MPTCP_EVENT_SUB_CLOSED = 11, - MPTCP_EVENT_SUB_PRIORITY = 13, -}; - -struct mptcp_options_received { - u64 sndr_key; - u64 rcvr_key; - u64 data_ack; - u64 data_seq; - u32 subflow_seq; - u16 data_len; - __sum16 csum; - u16 mp_capable: 1; - u16 mp_join: 1; - u16 fastclose: 1; - u16 reset: 1; - u16 dss: 1; - u16 add_addr: 1; - u16 rm_addr: 1; - u16 mp_prio: 1; - u16 echo: 1; - u16 csum_reqd: 1; - u16 backup: 1; - u16 deny_join_id0: 1; - u32 token; - u32 nonce; - u64 thmac; - u8 hmac[20]; - u8 join_id; - u8 use_map: 1; - u8 dsn64: 1; - u8 data_fin: 1; - u8 use_ack: 1; - u8 ack64: 1; - u8 mpc_map: 1; - u8 __unused: 2; - struct mptcp_addr_info addr; - struct mptcp_rm_list rm_list; - u64 ahmac; - u8 reset_reason: 4; - u8 reset_transient: 1; -}; - -struct mptcp_pm_data { - struct mptcp_addr_info local; - struct mptcp_addr_info remote; - struct list_head anno_list; - spinlock_t lock; - u8 addr_signal; - bool server_side; - bool work_pending; - bool accept_addr; - bool accept_subflow; - bool remote_deny_join_id0; - u8 add_addr_signaled; - u8 add_addr_accepted; - u8 local_addr_used; - u8 subflows; - u8 status; - struct mptcp_rm_list rm_list_tx; - struct mptcp_rm_list rm_list_rx; -}; - -struct mptcp_data_frag { - struct list_head list; - u64 data_seq; - u16 data_len; - u16 offset; - u16 overhead; - u16 already_sent; - struct page *page; -}; - -struct mptcp_sock { - struct inet_connection_sock sk; - u64 local_key; - u64 remote_key; - u64 write_seq; - u64 snd_nxt; - u64 ack_seq; - u64 rcv_wnd_sent; - u64 rcv_data_fin_seq; - int wmem_reserved; - struct sock *last_snd; - int snd_burst; - int old_wspace; - u64 snd_una; - u64 wnd_end; - long unsigned int timer_ival; - u32 token; - int rmem_released; - long unsigned int flags; - bool can_ack; - bool fully_established; - bool rcv_data_fin; - bool snd_data_fin_enable; - bool rcv_fastclose; - bool use_64bit_ack; - bool csum_enabled; - spinlock_t join_list_lock; - struct work_struct work; - struct sk_buff *ooo_last_skb; - struct rb_root out_of_order_queue; - struct sk_buff_head receive_queue; - int tx_pending_data; - struct list_head conn_list; - struct list_head rtx_queue; - struct mptcp_data_frag *first_pending; - struct list_head join_list; - struct socket *subflow; - struct sock *first; - struct mptcp_pm_data pm; - struct { - u32 space; - u32 copied; - u64 time; - u64 rtt_us; - } rcvq_space; - u32 setsockopt_seq; - char ca_name[16]; -}; - -struct mptcp_subflow_request_sock { - struct tcp_request_sock sk; - u16 mp_capable: 1; - u16 mp_join: 1; - u16 backup: 1; - u16 csum_reqd: 1; - u16 allow_join_id0: 1; - u8 local_id; - u8 remote_id; - u64 local_key; - u64 idsn; - u32 token; - u32 ssn_offset; - u64 thmac; - u32 local_nonce; - u32 remote_nonce; - struct mptcp_sock *msk; - struct hlist_nulls_node token_node; -}; - -enum mptcp_data_avail { - MPTCP_SUBFLOW_NODATA = 0, - MPTCP_SUBFLOW_DATA_AVAIL = 1, -}; - -struct mptcp_delegated_action { - struct napi_struct napi; - struct list_head head; -}; - -struct mptcp_subflow_context { - struct list_head node; - u64 local_key; - u64 remote_key; - u64 idsn; - u64 map_seq; - u32 snd_isn; - u32 token; - u32 rel_write_seq; - u32 map_subflow_seq; - u32 ssn_offset; - u32 map_data_len; - __wsum map_data_csum; - u32 map_csum_len; - u32 request_mptcp: 1; - u32 request_join: 1; - u32 request_bkup: 1; - u32 mp_capable: 1; - u32 mp_join: 1; - u32 fully_established: 1; - u32 pm_notified: 1; - u32 conn_finished: 1; - u32 map_valid: 1; - u32 map_csum_reqd: 1; - u32 map_data_fin: 1; - u32 mpc_map: 1; - u32 backup: 1; - u32 send_mp_prio: 1; - u32 rx_eof: 1; - u32 can_ack: 1; - u32 disposable: 1; - enum mptcp_data_avail data_avail; - u32 remote_nonce; - u64 thmac; - u32 local_nonce; - u32 remote_token; - u8 hmac[20]; - u8 local_id; - u8 remote_id; - u8 reset_seen: 1; - u8 reset_transient: 1; - u8 reset_reason: 4; - long int delegated_status; - struct list_head delegated_node; - u32 setsockopt_seq; - struct sock *tcp_sock; - struct sock *conn; - const struct inet_connection_sock_af_ops *icsk_af_ops; - void (*tcp_data_ready)(struct sock *); - void (*tcp_state_change)(struct sock *); - void (*tcp_write_space)(struct sock *); - void (*tcp_error_report)(struct sock *); - struct callback_head rcu; -}; - -enum linux_mptcp_mib_field { - MPTCP_MIB_NUM = 0, - MPTCP_MIB_MPCAPABLEPASSIVE = 1, - MPTCP_MIB_MPCAPABLEACTIVE = 2, - MPTCP_MIB_MPCAPABLEACTIVEACK = 3, - MPTCP_MIB_MPCAPABLEPASSIVEACK = 4, - MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK = 5, - MPTCP_MIB_MPCAPABLEACTIVEFALLBACK = 6, - MPTCP_MIB_TOKENFALLBACKINIT = 7, - MPTCP_MIB_RETRANSSEGS = 8, - MPTCP_MIB_JOINNOTOKEN = 9, - MPTCP_MIB_JOINSYNRX = 10, - MPTCP_MIB_JOINSYNACKRX = 11, - MPTCP_MIB_JOINSYNACKMAC = 12, - MPTCP_MIB_JOINACKRX = 13, - MPTCP_MIB_JOINACKMAC = 14, - MPTCP_MIB_DSSNOMATCH = 15, - MPTCP_MIB_INFINITEMAPRX = 16, - MPTCP_MIB_DSSTCPMISMATCH = 17, - MPTCP_MIB_DATACSUMERR = 18, - MPTCP_MIB_OFOQUEUETAIL = 19, - MPTCP_MIB_OFOQUEUE = 20, - MPTCP_MIB_OFOMERGE = 21, - MPTCP_MIB_NODSSWINDOW = 22, - MPTCP_MIB_DUPDATA = 23, - MPTCP_MIB_ADDADDR = 24, - MPTCP_MIB_ECHOADD = 25, - MPTCP_MIB_PORTADD = 26, - MPTCP_MIB_JOINPORTSYNRX = 27, - MPTCP_MIB_JOINPORTSYNACKRX = 28, - MPTCP_MIB_JOINPORTACKRX = 29, - MPTCP_MIB_MISMATCHPORTSYNRX = 30, - MPTCP_MIB_MISMATCHPORTACKRX = 31, - MPTCP_MIB_RMADDR = 32, - MPTCP_MIB_RMSUBFLOW = 33, - MPTCP_MIB_MPPRIOTX = 34, - MPTCP_MIB_MPPRIORX = 35, - MPTCP_MIB_RCVPRUNED = 36, - __MPTCP_MIB_MAX = 37, -}; - -struct trace_event_raw_mptcp_subflow_get_send { - struct trace_entry ent; - bool active; - bool free; - u32 snd_wnd; - u32 pace; - u8 backup; - u64 ratio; - char __data[0]; -}; - -struct trace_event_raw_mptcp_dump_mpext { - struct trace_entry ent; - u64 data_ack; - u64 data_seq; - u32 subflow_seq; - u16 data_len; - u16 csum; - u8 use_map; - u8 dsn64; - u8 data_fin; - u8 use_ack; - u8 ack64; - u8 mpc_map; - u8 frozen; - u8 reset_transient; - u8 reset_reason; - u8 csum_reqd; - char __data[0]; -}; - -struct trace_event_raw_ack_update_msk { - struct trace_entry ent; - u64 data_ack; - u64 old_snd_una; - u64 new_snd_una; - u64 new_wnd_end; - u64 msk_wnd_end; - char __data[0]; -}; - -struct trace_event_raw_subflow_check_data_avail { - struct trace_entry ent; - u8 status; - const void *skb; - char __data[0]; -}; - -struct trace_event_data_offsets_mptcp_subflow_get_send {}; - -struct trace_event_data_offsets_mptcp_dump_mpext {}; - -struct trace_event_data_offsets_ack_update_msk {}; - -struct trace_event_data_offsets_subflow_check_data_avail {}; - -typedef void (*btf_trace_mptcp_subflow_get_send)(void *, struct mptcp_subflow_context *); - -typedef void (*btf_trace_get_mapping_status)(void *, struct mptcp_ext *); - -typedef void (*btf_trace_ack_update_msk)(void *, u64, u64, u64, u64, u64); - -typedef void (*btf_trace_subflow_check_data_avail)(void *, __u8, struct sk_buff *); - -struct mptcp_skb_cb { - u64 map_seq; - u64 end_seq; - u32 offset; - u8 has_rxtstamp: 1; -}; - -enum { - MPTCP_CMSG_TS = 1, -}; - -struct mptcp_sendmsg_info { - int mss_now; - int size_goal; - u16 limit; - u16 sent; - unsigned int flags; -}; - -struct subflow_send_info { - struct sock *ssk; - u64 ratio; -}; - -struct csum_pseudo_header { - __be64 data_seq; - __be32 subflow_seq; - __be16 data_len; - __sum16 csum; -}; - -enum mapping_status { - MAPPING_OK = 0, - MAPPING_INVALID = 1, - MAPPING_EMPTY = 2, - MAPPING_DATA_FIN = 3, - MAPPING_DUMMY = 4, -}; - -enum mptcp_addr_signal_status { - MPTCP_ADD_ADDR_SIGNAL = 0, - MPTCP_ADD_ADDR_ECHO = 1, - MPTCP_ADD_ADDR_IPV6 = 2, - MPTCP_ADD_ADDR_PORT = 3, - MPTCP_RM_ADDR_SIGNAL = 4, -}; - -struct mptcp_pm_add_entry; - -struct token_bucket { - spinlock_t lock; - int chain_len; - struct hlist_nulls_head req_chain; - struct hlist_nulls_head msk_chain; -}; - -struct mptcp_pernet { - struct ctl_table_header *ctl_table_hdr; - u8 mptcp_enabled; - unsigned int add_addr_timeout; - u8 checksum_enabled; - u8 allow_join_initial_addr_port; -}; - -enum mptcp_pm_status { - MPTCP_PM_ADD_ADDR_RECEIVED = 0, - MPTCP_PM_ADD_ADDR_SEND_ACK = 1, - MPTCP_PM_RM_ADDR_RECEIVED = 2, - MPTCP_PM_ESTABLISHED = 3, - MPTCP_PM_ALREADY_ESTABLISHED = 4, - MPTCP_PM_SUBFLOW_ESTABLISHED = 5, -}; - -enum { - INET_ULP_INFO_UNSPEC = 0, - INET_ULP_INFO_NAME = 1, - INET_ULP_INFO_TLS = 2, - INET_ULP_INFO_MPTCP = 3, - __INET_ULP_INFO_MAX = 4, -}; - -enum { - MPTCP_SUBFLOW_ATTR_UNSPEC = 0, - MPTCP_SUBFLOW_ATTR_TOKEN_REM = 1, - MPTCP_SUBFLOW_ATTR_TOKEN_LOC = 2, - MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ = 3, - MPTCP_SUBFLOW_ATTR_MAP_SEQ = 4, - MPTCP_SUBFLOW_ATTR_MAP_SFSEQ = 5, - MPTCP_SUBFLOW_ATTR_SSN_OFFSET = 6, - MPTCP_SUBFLOW_ATTR_MAP_DATALEN = 7, - MPTCP_SUBFLOW_ATTR_FLAGS = 8, - MPTCP_SUBFLOW_ATTR_ID_REM = 9, - MPTCP_SUBFLOW_ATTR_ID_LOC = 10, - MPTCP_SUBFLOW_ATTR_PAD = 11, - __MPTCP_SUBFLOW_ATTR_MAX = 12, -}; - -enum { - MPTCP_PM_ATTR_UNSPEC = 0, - MPTCP_PM_ATTR_ADDR = 1, - MPTCP_PM_ATTR_RCV_ADD_ADDRS = 2, - MPTCP_PM_ATTR_SUBFLOWS = 3, - __MPTCP_PM_ATTR_MAX = 4, -}; - -enum { - MPTCP_PM_ADDR_ATTR_UNSPEC = 0, - MPTCP_PM_ADDR_ATTR_FAMILY = 1, - MPTCP_PM_ADDR_ATTR_ID = 2, - MPTCP_PM_ADDR_ATTR_ADDR4 = 3, - MPTCP_PM_ADDR_ATTR_ADDR6 = 4, - MPTCP_PM_ADDR_ATTR_PORT = 5, - MPTCP_PM_ADDR_ATTR_FLAGS = 6, - MPTCP_PM_ADDR_ATTR_IF_IDX = 7, - __MPTCP_PM_ADDR_ATTR_MAX = 8, -}; - -enum { - MPTCP_PM_CMD_UNSPEC = 0, - MPTCP_PM_CMD_ADD_ADDR = 1, - MPTCP_PM_CMD_DEL_ADDR = 2, - MPTCP_PM_CMD_GET_ADDR = 3, - MPTCP_PM_CMD_FLUSH_ADDRS = 4, - MPTCP_PM_CMD_SET_LIMITS = 5, - MPTCP_PM_CMD_GET_LIMITS = 6, - MPTCP_PM_CMD_SET_FLAGS = 7, - __MPTCP_PM_CMD_AFTER_LAST = 8, -}; - -enum mptcp_event_attr { - MPTCP_ATTR_UNSPEC = 0, - MPTCP_ATTR_TOKEN = 1, - MPTCP_ATTR_FAMILY = 2, - MPTCP_ATTR_LOC_ID = 3, - MPTCP_ATTR_REM_ID = 4, - MPTCP_ATTR_SADDR4 = 5, - MPTCP_ATTR_SADDR6 = 6, - MPTCP_ATTR_DADDR4 = 7, - MPTCP_ATTR_DADDR6 = 8, - MPTCP_ATTR_SPORT = 9, - MPTCP_ATTR_DPORT = 10, - MPTCP_ATTR_BACKUP = 11, - MPTCP_ATTR_ERROR = 12, - MPTCP_ATTR_FLAGS = 13, - MPTCP_ATTR_TIMEOUT = 14, - MPTCP_ATTR_IF_IDX = 15, - MPTCP_ATTR_RESET_REASON = 16, - MPTCP_ATTR_RESET_FLAGS = 17, - __MPTCP_ATTR_AFTER_LAST = 18, -}; - -struct mptcp_pm_addr_entry { - struct list_head list; - struct mptcp_addr_info addr; - u8 flags; - int ifindex; - struct socket *lsk; -}; - -struct mptcp_pm_add_entry___2 { - struct list_head list; - struct mptcp_addr_info addr; - struct timer_list add_timer; - struct mptcp_sock *sock; - u8 retrans_times; -}; - -struct pm_nl_pernet { - spinlock_t lock; - struct list_head local_addr_list; - unsigned int addrs; - unsigned int add_addr_signal_max; - unsigned int add_addr_accept_max; - unsigned int local_addr_max; - unsigned int subflows_max; - unsigned int next_id; - long unsigned int id_bitmap[4]; -}; - -struct join_entry { - u32 token; - u32 remote_nonce; - u32 local_nonce; - u8 join_id; - u8 local_id; - u8 backup; - u8 valid; -}; - -struct pcibios_fwaddrmap { - struct list_head list; - struct pci_dev *dev; - resource_size_t fw_addr[17]; -}; - -struct pci_check_idx_range { - int start; - int end; -}; - -struct pci_raw_ops { - int (*read)(unsigned int, unsigned int, unsigned int, int, int, u32 *); - int (*write)(unsigned int, unsigned int, unsigned int, int, int, u32); -}; - -struct acpi_table_mcfg { - struct acpi_table_header header; - u8 reserved[8]; -}; - -struct acpi_mcfg_allocation { - u64 address; - u16 pci_segment; - u8 start_bus_number; - u8 end_bus_number; - u32 reserved; -}; - -struct pci_mmcfg_hostbridge_probe { - u32 bus; - u32 devfn; - u32 vendor; - u32 device; - const char * (*probe)(); -}; - -typedef bool (*check_reserved_t)(u64, u64, enum e820_type); - -struct physdev_restore_msi { - uint8_t bus; - uint8_t devfn; -}; - -struct physdev_setup_gsi { - int gsi; - uint8_t triggering; - uint8_t polarity; -}; - -struct xen_pci_frontend_ops { - int (*enable_msi)(struct pci_dev *, int *); - void (*disable_msi)(struct pci_dev *); - int (*enable_msix)(struct pci_dev *, int *, int); - void (*disable_msix)(struct pci_dev *); -}; - -struct xen_msi_ops { - int (*setup_msi_irqs)(struct pci_dev *, int, int); - void (*teardown_msi_irqs)(struct pci_dev *); -}; - -struct xen_device_domain_owner { - domid_t domain; - struct pci_dev *dev; - struct list_head list; -}; - -struct pci_root_info { - struct acpi_pci_root_info common; - struct pci_sysdata sd; - bool mcfg_added; - u8 start_bus; - u8 end_bus; -}; - -struct irq_info___3 { - u8 bus; - u8 devfn; - struct { - u8 link; - u16 bitmap; - } __attribute__((packed)) irq[4]; - u8 slot; - u8 rfu; -}; - -struct irq_routing_table { - u32 signature; - u16 version; - u16 size; - u8 rtr_bus; - u8 rtr_devfn; - u16 exclusive_irqs; - u16 rtr_vendor; - u16 rtr_device; - u32 miniport_data; - u8 rfu[11]; - u8 checksum; - struct irq_info___3 slots[0]; -}; - -struct irq_router { - char *name; - u16 vendor; - u16 device; - int (*get)(struct pci_dev *, struct pci_dev *, int); - int (*set)(struct pci_dev *, struct pci_dev *, int, int); -}; - -struct irq_router_handler { - u16 vendor; - int (*probe)(struct irq_router *, struct pci_dev *, u16); -}; - -struct pci_setup_rom { - struct setup_data data; - uint16_t vendor; - uint16_t devid; - uint64_t pcilen; - long unsigned int segment; - long unsigned int bus; - long unsigned int device; - long unsigned int function; - uint8_t romdata[0]; -}; - -enum pci_bf_sort_state { - pci_bf_sort_default = 0, - pci_force_nobf = 1, - pci_force_bf = 2, - pci_dmi_bf = 3, -}; - -struct pci_root_res { - struct list_head list; - struct resource res; -}; - -struct pci_root_info___2 { - struct list_head list; - char name[12]; - struct list_head resources; - struct resource busn; - int node; - int link; -}; - -struct amd_hostbridge { - u32 bus; - u32 slot; - u32 device; -}; - -struct saved_msr { - bool valid; - struct msr_info info; -}; - -struct saved_msrs { - unsigned int num; - struct saved_msr *array; -}; - -struct saved_context { - struct pt_regs regs; - u16 ds; - u16 es; - u16 fs; - u16 gs; - long unsigned int kernelmode_gs_base; - long unsigned int usermode_gs_base; - long unsigned int fs_base; - long unsigned int cr0; - long unsigned int cr2; - long unsigned int cr3; - long unsigned int cr4; - u64 misc_enable; - bool misc_enable_saved; - struct saved_msrs saved_msrs; - long unsigned int efer; - u16 gdt_pad; - struct desc_ptr gdt_desc; - u16 idt_pad; - struct desc_ptr idt; - u16 ldt; - u16 tss; - long unsigned int tr; - long unsigned int safety; - long unsigned int return_address; -} __attribute__((packed)); - -typedef int (*pm_cpu_match_t)(const struct x86_cpu_id *); - -struct restore_data_record { - long unsigned int jump_address; - long unsigned int jump_address_phys; - long unsigned int cr3; - long unsigned int magic; - long unsigned int e820_checksum; -}; - -#ifndef BPF_NO_PRESERVE_ACCESS_INDEX -#pragma clang attribute pop -#endif - -#endif /* __VMLINUX_H__ */ \ No newline at end of file diff --git a/ebpf/bpf/vmlinux/vmlinux.h b/ebpf/bpf/vmlinux/vmlinux.h deleted file mode 100644 index d0fb380b40..0000000000 --- a/ebpf/bpf/vmlinux/vmlinux.h +++ /dev/null @@ -1,7 +0,0 @@ -#if defined(__TARGET_ARCH_x86) -#include "vmlinux-x86.h" -#elif defined(__TARGET_ARCH_arm64) -#include "vmlinux-arm64.h" -#else -#error "Unknown architecture" -#endif \ No newline at end of file diff --git a/ebpf/cmd/glibc_dwarfdump/main.go b/ebpf/cmd/glibc_dwarfdump/main.go deleted file mode 100644 index e41b854d32..0000000000 --- a/ebpf/cmd/glibc_dwarfdump/main.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "fmt" - "os" - "regexp" - "sort" - "strconv" - - "github.com/grafana/pyroscope/ebpf/dwarfdump" -) - -func main() { - if len(os.Args) < 2 { - fmt.Println("Please provide glibc elf files.") - return - } - var es []dwarfdump.Entry - for _, fp := range os.Args[1:] { - fields := dwarfdump.Dump(fp, pythonFields) - re := regexp.MustCompile("glibc-2\\.(\\d+)") - version := re.FindAllSubmatch([]byte(fp), -1) - if len(version) != 1 { - panic("no version found" + fp) - } - - iversion := dwarfdump.Version{} - iversion.Major = 2 - iversion.Minor, _ = strconv.Atoi(string(version[0][1])) - iversion.Patch = 0 - es = append(es, dwarfdump.Entry{ - Version: iversion, - Offsets: fields, - SrcFile: fp, - }) - } - sort.Slice(es, func(i, j int) bool { - return es[i].Version.Compare(es[j].Version) > 0 - }) - const header = ` -// Code generated by glibc_dwarfdump. DO NOT EDIT. -package python - -var glibcOffsets = map[Version]*GlibcOffsets{` - fmt.Println(header) - for _, e := range es { - fmt.Printf("// %d.%d %s\n", e.Version.Major, e.Version.Minor, e.SrcFile) - fmt.Printf("{%d, %d, %d}: {\n", e.Version.Major, e.Version.Minor, e.Version.Patch) - for _, offset := range e.Offsets { - fmt.Printf(" %s: %d,\n", offset.Name, offset.Offset) - } - fmt.Printf("},\n") - } - fmt.Println("}") - -} - -var pythonFields = []dwarfdump.Need{ - {Name: "pthread", Fields: []dwarfdump.NeedField{ - {"specific_1stblock", ""}, - }, Size: true}, - {Name: "pthread_key_data", Fields: []dwarfdump.NeedField{ - {"data", ""}, - }, Size: true}, -} diff --git a/ebpf/cmd/musl_dwarfdump/main.go b/ebpf/cmd/musl_dwarfdump/main.go deleted file mode 100644 index b75acb1292..0000000000 --- a/ebpf/cmd/musl_dwarfdump/main.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "os" - "regexp" - "sort" - "strconv" - - "github.com/grafana/pyroscope/ebpf/dwarfdump" -) - -func main() { - if len(os.Args) < 2 { - fmt.Println("Please provide musl elf debug files.") - return - } - var es []dwarfdump.Entry - for _, fp := range os.Args[1:] { - f, err := os.ReadFile(fp) - if err != nil { - panic(err) - } - fields := dwarfdump.Dump(fp, fields) - re := regexp.MustCompile("[^\\d]1\\.([1-2])\\.(\\d+)") - version := re.FindAllSubmatch(f, -1) - for _, v := range version { - fmt.Fprintf(os.Stderr, "%s => v %s \n", fp, v[0]) - } - if len(version) == 0 { - panic("no version found" + fp) - } - if len(version) > 1 { - vv := version[0][0] - for _, v := range version { - if !bytes.Equal(v[0], vv) { - panic("multiple versions found" + fp) - } - } - } - - iversion := dwarfdump.Version{} - iversion.Major = 1 - iversion.Minor, _ = strconv.Atoi(string(version[0][1])) - iversion.Patch, _ = strconv.Atoi(string(version[0][2])) - es = append(es, dwarfdump.Entry{ - Version: iversion, - Offsets: fields, - SrcFile: fp, - }) - } - sort.Slice(es, func(i, j int) bool { - return es[i].Version.Compare(es[j].Version) > 0 - }) - const header = ` -// Code generated by musl_dwarfdump. DO NOT EDIT. -package python - -var muslOffsets = map[Version]*MuslOffsets{` - fmt.Println(header) - for _, e := range es { - fmt.Printf("// %d.%d %s\n", e.Version.Major, e.Version.Minor, e.SrcFile) - fmt.Printf("{%d, %d, %d}: {\n", e.Version.Major, e.Version.Minor, e.Version.Patch) - for _, offset := range e.Offsets { - fmt.Printf(" %s: %d,\n", offset.Name, offset.Offset) - } - fmt.Printf("},\n") - } - fmt.Println("}") - -} - -var fields = []dwarfdump.Need{ - {Name: "__pthread", Fields: []dwarfdump.NeedField{ - {"tsd", ""}, - }, Size: true}, -} diff --git a/ebpf/cmd/playground/main.go b/ebpf/cmd/playground/main.go deleted file mode 100644 index 8a6556dd0e..0000000000 --- a/ebpf/cmd/playground/main.go +++ /dev/null @@ -1,362 +0,0 @@ -//go:build linux - -package main - -import ( - "bytes" - "context" - "encoding/json" - "flag" - "fmt" - "os" - "strconv" - "strings" - "time" - - "connectrpc.com/connect" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/cpp/demangle" - ebpfmetrics "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus" - commonconfig "github.com/prometheus/common/config" - "github.com/prometheus/common/model" - "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/model/relabel" - - pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" - "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" - typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - ebpfspy "github.com/grafana/pyroscope/ebpf" - "github.com/grafana/pyroscope/ebpf/pprof" - "github.com/grafana/pyroscope/ebpf/sd" - "github.com/grafana/pyroscope/ebpf/symtab" -) - -var configFile = flag.String("config", "", "config file path") -var server = flag.String("server", "http://localhost:4040", "") -var discoverFreq = flag.Duration("discover.freq", - 5*time.Second, - "") - -var collectFreq = flag.Duration("collect.freq", - 15*time.Second, - "") - -var ( - config *Config - logger log.Logger - session ebpfspy.Session -) - -type splitLog struct { - err log.Logger - rest log.Logger -} - -func (s splitLog) Log(keyvals ...interface{}) error { - if len(keyvals)%2 != 0 { - return s.err.Log(keyvals...) - } - for i := 0; i < len(keyvals); i += 2 { - if keyvals[i] == "level" { - vv := keyvals[i+1] - vvs, ok := vv.(fmt.Stringer) - if ok && vvs.String() == "error" { - return s.err.Log(keyvals...) - } - } - } - return s.rest.Log(keyvals...) -} - -func main() { - config = getConfig() - - logger = &splitLog{ - err: log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)), - rest: log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout)), - } - - targetFinder, err := sd.NewTargetFinder(os.DirFS("/"), logger, convertTargetOptions()) - if err != nil { - panic(fmt.Errorf("ebpf target finder create: %w", err)) - } - options := convertSessionOptions() - session, err = ebpfspy.NewSession( - logger, - targetFinder, - options, - ) - err = session.Start() - if err != nil { - panic(err) - } - - profiles := make(chan *pushv1.PushRequest, 128) - go ingest(profiles) - - discoverTicker := time.NewTicker(*discoverFreq) - collectTicker := time.NewTicker(*collectFreq) - - for { - select { - case <-discoverTicker.C: - session.UpdateTargets(convertTargetOptions()) - case <-collectTicker.C: - collectProfiles(profiles) - } - } -} - -func collectProfiles(profiles chan *pushv1.PushRequest) { - builders := pprof.NewProfileBuilders(pprof.BuildersOptions{ - SampleRate: int64(config.SessionOptions.SampleRate), - PerPIDProfile: true, - }) - err := pprof.Collect(builders, session) - - if err != nil { - panic(err) - } - level.Debug(logger).Log("msg", "ebpf collectProfiles done", "profiles", len(builders.Builders)) - - for _, builder := range builders.Builders { - protoLabels := make([]*typesv1.LabelPair, 0, builder.Labels.Len()) - for _, label := range builder.Labels { - protoLabels = append(protoLabels, &typesv1.LabelPair{ - Name: label.Name, Value: label.Value, - }) - } - - buf := bytes.NewBuffer(nil) - _, err := builder.Write(buf) - if err != nil { - panic(err) - } - req := &pushv1.PushRequest{Series: []*pushv1.RawProfileSeries{{ - Labels: protoLabels, - Samples: []*pushv1.RawSample{{ - RawProfile: buf.Bytes(), - }}, - }}} - select { - case profiles <- req: - default: - _ = level.Error(logger).Log("err", "dropping profile", "target", builder.Labels.String()) - } - - } - - if err != nil { - panic(err) - } -} - -func ingest(profiles chan *pushv1.PushRequest) { - httpClient, err := commonconfig.NewClientFromConfig(commonconfig.DefaultHTTPClientConfig, "http_playground") - if err != nil { - panic(err) - } - client := pushv1connect.NewPusherServiceClient(httpClient, *server) - - for { - it := <-profiles - res, err := client.Push(context.TODO(), connect.NewRequest(it)) - if err != nil { - fmt.Println(err) - } - if res != nil { - fmt.Println(res) - } - } - -} - -func convertTargetOptions() sd.TargetsOptions { - targets := relabelProcessTargets(getProcessTargets(), config.RelabelConfig) - o := config.TargetsOptions - o.Targets = targets - return o -} - -func convertSessionOptions() ebpfspy.SessionOptions { - return config.SessionOptions -} - -func getConfig() *Config { - flag.Parse() - - var config = new(Config) - *config = defaultConfig - if *configFile == "" { - return config - } - configBytes, err := os.ReadFile(*configFile) - if err != nil { - panic(err) - } - err = json.Unmarshal(configBytes, config) - if err != nil { - panic(err) - } - return config -} - -var defaultConfig = Config{ - TargetsOptions: sd.TargetsOptions{ - Targets: nil, - TargetsOnly: true, - DefaultTarget: nil, - ContainerCacheSize: 1024, - }, - RelabelConfig: nil, - SessionOptions: ebpfspy.SessionOptions{ - CollectUser: true, - CollectKernel: true, - UnknownSymbolModuleOffset: true, - UnknownSymbolAddress: true, - PythonEnabled: true, - CacheOptions: symtab.CacheOptions{ - - PidCacheOptions: symtab.GCacheOptions{ - Size: 239, - KeepRounds: 8, - }, - BuildIDCacheOptions: symtab.GCacheOptions{ - Size: 239, - KeepRounds: 8, - }, - SameFileCacheOptions: symtab.GCacheOptions{ - Size: 239, - KeepRounds: 8, - }, - }, - SymbolOptions: symtab.SymbolOptions{ - GoTableFallback: true, - PythonFullFilePath: false, - DemangleOptions: demangle.DemangleFull, - }, - Metrics: ebpfmetrics.New(prometheus.DefaultRegisterer), - SampleRate: 97, - VerifierLogSize: 1024 * 1024 * 1024, - PythonBPFErrorLogEnabled: true, - PythonBPFDebugLogEnabled: true, - BPFMapsOptions: ebpfspy.BPFMapsOptions{ - PIDMapSize: 2048, - SymbolsMapSize: 16384, - }, - }, -} - -type Config struct { - TargetsOptions sd.TargetsOptions - RelabelConfig []*RelabelConfig - SessionOptions ebpfspy.SessionOptions -} - -type RelabelConfig struct { - SourceLabels []string - - Separator string - - Regex string - - TargetLabel string `yaml:"target_label,omitempty"` - - Replacement string `yaml:"replacement,omitempty"` - - Action string -} - -func getProcessTargets() []sd.DiscoveryTarget { - dir, err := os.ReadDir("/proc") - if err != nil { - panic(err) - } - var res []sd.DiscoveryTarget - for _, entry := range dir { - if !entry.IsDir() { - continue - } - spid := entry.Name() - pid, err := strconv.ParseUint(spid, 10, 32) - if err != nil { - continue - } - if pid == 0 { - continue - } - cwd, err := os.Readlink(fmt.Sprintf("/proc/%s/cwd", spid)) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - _ = level.Error(logger).Log("err", err, "msg", "reading cwd", "pid", spid) - } - continue - } - cwd = strings.TrimSpace(cwd) - - exe, err := os.Readlink(fmt.Sprintf("/proc/%s/exe", spid)) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - _ = level.Error(logger).Log("err", err, "msg", "reading exe", "pid", spid) - } - continue - } - comm, err := os.ReadFile(fmt.Sprintf("/proc/%s/comm", spid)) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - _ = level.Error(logger).Log("err", err, "msg", "reading comm", "pid", spid) - } - } - cmdline, err := os.ReadFile(fmt.Sprintf("/proc/%s/cmdline", spid)) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - _ = level.Error(logger).Log("err", err, "msg", "reading cmdline", "pid", spid) - } - } else { - cmdline = bytes.ReplaceAll(cmdline, []byte{0}, []byte(" ")) - } - target := sd.DiscoveryTarget{ - "__process_pid__": spid, - "cwd": cwd, - "comm": strings.TrimSpace(string(comm)), - "pid": spid, - "exe": exe, - "service_name": fmt.Sprintf("%s @ %s", cmdline, cwd), - } - res = append(res, target) - } - return res -} - -func relabelProcessTargets(targets []sd.DiscoveryTarget, cfg []*RelabelConfig) []sd.DiscoveryTarget { - var promConfig []*relabel.Config - for _, c := range cfg { - var srcLabels model.LabelNames - for _, label := range c.SourceLabels { - srcLabels = append(srcLabels, model.LabelName(label)) - } - promConfig = append(promConfig, &relabel.Config{ - SourceLabels: srcLabels, - Separator: c.Separator, - Regex: relabel.MustNewRegexp(c.Regex), - TargetLabel: c.TargetLabel, - Replacement: c.Replacement, - Action: relabel.Action(c.Action), - }) - } - var res []sd.DiscoveryTarget - for _, target := range targets { - lbls := labels.FromMap(target) - lbls, keep := relabel.Process(lbls, promConfig...) - - if !keep { - continue - } - tt := sd.DiscoveryTarget(lbls.Map()) - res = append(res, tt) - } - return res -} diff --git a/ebpf/cmd/python_dwarfdump/main.go b/ebpf/cmd/python_dwarfdump/main.go deleted file mode 100644 index e7f5ac7f88..0000000000 --- a/ebpf/cmd/python_dwarfdump/main.go +++ /dev/null @@ -1,120 +0,0 @@ -package main - -import ( - "fmt" - "os" - "regexp" - "sort" - "strconv" - - "github.com/grafana/pyroscope/ebpf/dwarfdump" -) - -func main() { - if len(os.Args) < 2 { - fmt.Println("Please provide python / libpython elf files.") - return - } - var es []dwarfdump.Entry - for _, fp := range os.Args[1:] { - fields := dwarfdump.Dump(fp, pythonFields) - re := regexp.MustCompile("(\\d+)\\.(\\d+)\\.(\\d+)") - version := re.FindAllSubmatch([]byte(fp), -1) - if len(version) != 1 { - panic("no version found" + fp) - } - - iversion := dwarfdump.Version{} - iversion.Major, _ = strconv.Atoi(string(version[0][1])) - iversion.Minor, _ = strconv.Atoi(string(version[0][2])) - iversion.Patch, _ = strconv.Atoi(string(version[0][3])) - es = append(es, dwarfdump.Entry{ - Version: iversion, - Offsets: fields, - SrcFile: fp, - }) - } - sort.Slice(es, func(i, j int) bool { - return es[i].Version.Compare(es[j].Version) > 0 - }) - const header = ` -// Code generated by python_dwarfdump. DO NOT EDIT. -package python - -var pyVersions = map[Version]*UserOffsets{` - fmt.Println(header) - for _, e := range es { - fmt.Printf("// %d.%d.%d %s\n", e.Version.Major, e.Version.Minor, e.Version.Patch, e.SrcFile) - fmt.Printf("{%d, %d, %d}: {\n", e.Version.Major, e.Version.Minor, e.Version.Patch) - for _, offset := range e.Offsets { - fmt.Printf(" %s: %d,\n", offset.Name, offset.Offset) - } - fmt.Printf("},\n") - } - fmt.Println("}") - -} - -var pythonFields = []dwarfdump.Need{ - - {Name: "PyVarObject", Fields: []dwarfdump.NeedField{ - {"ob_size", "PyVarObject_ob_size"}, - }}, - {Name: "PyObject", Fields: []dwarfdump.NeedField{ - {"ob_type", "PyObject_ob_type"}, - }}, - {Name: "_typeobject", PrettyName: "PyTypeObject", Fields: []dwarfdump.NeedField{ - {"tp_name", "PyTypeObject_tp_name"}, - }}, - {Name: "_ts", Fields: []dwarfdump.NeedField{ - {"frame", "PyThreadState_frame"}, - {"cframe", "PyThreadState_cframe"}, - {"current_frame", "PyThreadState_current_frame"}, - }}, - {Name: "_PyCFrame", Fields: []dwarfdump.NeedField{ - {"current_frame", "PyCFrame_current_frame"}, - }}, - //typedef struct _frame PyFrameObject; - {Name: "_frame", PrettyName: "PyFrameObject", Fields: []dwarfdump.NeedField{ - {"f_back", "PyFrameObject_f_back"}, - {"f_code", "PyFrameObject_f_code"}, - {"f_localsplus", "PyFrameObject_f_localsplus"}, - }}, - {Name: "PyCodeObject", Fields: []dwarfdump.NeedField{ - {"co_filename", "PyCodeObject_co_filename"}, - {"co_name", "PyCodeObject_co_name"}, - {"co_varnames", "PyCodeObject_co_varnames"}, - {"co_localsplusnames", "PyCodeObject_co_localsplusnames"}, - {"co_cell2arg", "PyCodeObject__co_cell2arg"}, - {"co_cellvars", "PyCodeObject__co_cellvars"}, - {"co_nlocals", "PyCodeObject__co_nlocals"}, - }}, - {Name: "PyTupleObject", Fields: []dwarfdump.NeedField{ - {"ob_item", "PyTupleObject_ob_item"}, - }}, - {Name: "_PyInterpreterFrame", Fields: []dwarfdump.NeedField{ - {"f_code", "PyInterpreterFrame_f_code"}, - {"f_executable", "PyInterpreterFrame_f_executable"}, - {"previous", "PyInterpreterFrame_previous"}, - {"localsplus", "PyInterpreterFrame_localsplus"}, - {"owner", "PyInterpreterFrame_owner"}, - }}, - {Name: "_PyRuntimeState", Fields: []dwarfdump.NeedField{ - {"gilstate", "PyRuntimeState_gilstate"}, - {"autoTSSkey", "PyRuntimeState_autoTSSkey"}, - }}, - {Name: "_gilstate_runtime_state", Fields: []dwarfdump.NeedField{ - {"autoTSSkey", "Gilstate_runtime_state_autoTSSkey"}, - }}, - {Name: "_Py_tss_t", Size: true, Fields: []dwarfdump.NeedField{ - {"_is_initialized", "PyTssT_is_initialized"}, - {"_key", "PyTssT_key"}, - }}, - {Name: "PyASCIIObject", PrettyName: "PyASCIIObject", Size: true}, - {Name: "PyCompactUnicodeObject", PrettyName: "PyCompactUnicodeObject", Size: true}, - {Name: "PyCellObject", Fields: []dwarfdump.NeedField{ - {"ob_ref", "PyCellObject__ob_ref"}, - }}, - - //{Name: "_is", PrettyName: "PyInterpreterState", Fields: []string{}}, -} diff --git a/ebpf/cpp/demangle/demangle.go b/ebpf/cpp/demangle/demangle.go deleted file mode 100644 index 7bf7fd7754..0000000000 --- a/ebpf/cpp/demangle/demangle.go +++ /dev/null @@ -1,24 +0,0 @@ -package demangle - -import "github.com/ianlancetaylor/demangle" - -var DemangleUnspecified []demangle.Option = nil -var DemangleNoneSpecified []demangle.Option = make([]demangle.Option, 0) -var DemangleSimplified = []demangle.Option{demangle.NoParams, demangle.NoEnclosingParams, demangle.NoTemplateParams} -var DemangleTemplates = []demangle.Option{demangle.NoParams, demangle.NoEnclosingParams} -var DemangleFull = []demangle.Option{demangle.NoClones} - -func ConvertDemangleOptions(o string) []demangle.Option { - switch o { - case "none": - return DemangleNoneSpecified - case "simplified": - return DemangleSimplified - case "templates": - return DemangleTemplates - case "full": - return DemangleFull - default: - return DemangleUnspecified - } -} diff --git a/ebpf/cpuonline/cpuonline.go b/ebpf/cpuonline/cpuonline.go deleted file mode 100644 index 435506c2e8..0000000000 --- a/ebpf/cpuonline/cpuonline.go +++ /dev/null @@ -1,43 +0,0 @@ -package cpuonline - -import ( - "os" - "strconv" - "strings" -) - -const cpuOnline = "/sys/devices/system/cpu/online" - -// Get returns a slice with the online CPUs, for example `[0, 2, 3]` -func Get() ([]uint, error) { - buf, err := os.ReadFile(cpuOnline) - if err != nil { - return nil, err - } - return ReadCPURange(string(buf)) -} - -// loosely based on https://github.com/iovisor/bcc/blob/v0.3.0/src/python/bcc/utils.py#L15 -func ReadCPURange(cpuRangeStr string) ([]uint, error) { - var cpus []uint - cpuRangeStr = strings.Trim(cpuRangeStr, "\n ") - for _, cpuRange := range strings.Split(cpuRangeStr, ",") { - rangeOp := strings.SplitN(cpuRange, "-", 2) - first, err := strconv.ParseUint(rangeOp[0], 10, 32) - if err != nil { - return nil, err - } - if len(rangeOp) == 1 { - cpus = append(cpus, uint(first)) - continue - } - last, err := strconv.ParseUint(rangeOp[1], 10, 32) - if err != nil { - return nil, err - } - for n := first; n <= last; n++ { - cpus = append(cpus, uint(n)) - } - } - return cpus, nil -} diff --git a/ebpf/dwarfdump/dwarfdump.go b/ebpf/dwarfdump/dwarfdump.go deleted file mode 100644 index d96247e8dc..0000000000 --- a/ebpf/dwarfdump/dwarfdump.go +++ /dev/null @@ -1,316 +0,0 @@ -package dwarfdump - -import ( - "debug/dwarf" - "debug/elf" - "fmt" - "os" - "reflect" - "strings" -) - -// based on https://github.com/grafana/beyla/blob/6b46732da73f2f2cb84e41efdc74789509a7fa2b/pkg/internal/goexec/structmembers.go - -type Field struct { - Name string - Offset uint64 - - //attrs map[dwarf.Attr]any -} -type Typedef struct { - Name string - TypeOffsets []dwarf.Offset -} -type Typ struct { - Name string - Fields []Field - Size int64 -} - -func (t Typ) GetField(name string) *Field { - for i, field := range t.Fields { - if field.Name == name { - return &t.Fields[i] - } - } - return nil -} - -type Index struct { - offset2Type map[dwarf.Offset]*Typ - typedefs map[string]*Typedef -} - -func (i *Index) GetTypeByName2(name string) *Typ { - if name == "" { - return nil - } - typedef := i.typedefs[name] - if typedef == nil { - return i.GetTypeByName(name) - } - var res []*Typ - for _, offset := range typedef.TypeOffsets { - typ := i.offset2Type[offset] - if typ == nil { - panic(fmt.Sprintf("%s %d not found", name, offset)) - } - res = append(res, typ) - if len(res) > 0 { - prev := res[len(res)-1] - if !reflect.DeepEqual(prev, typ) { - panic(fmt.Sprintf("not eq %v prev %v", typ, prev)) - } - } - } - if len(res) == 0 { - return nil - } - return res[0] -} -func (i *Index) GetTypeByName(name string) *Typ { - var res []*Typ - for _, typ := range i.offset2Type { - if typ.Name == name { - res = append(res, typ) - if len(res) > 0 { - prev := res[len(res)-1] - if !reflect.DeepEqual(prev, typ) { - panic(fmt.Sprintf("not eq %v prev %v", typ, prev)) - } - } - } - } - if len(res) == 0 { - return nil - //panic(fmt.Sprintf("%s not found", name)) - } - return res[0] -} - -// structMemberOffsetsFromDwarf reads the executable dwarf information to get -// the offsets specified in the structMembers map -func structMemberOffsetsFromDwarf(data *dwarf.Data) (Index, error) { - - reader := data.Reader() - res := Index{ - //name2Type : map[string]*Typ{}, - offset2Type: map[dwarf.Offset]*Typ{}, - typedefs: map[string]*Typedef{}, - } - - for { - entry, err := reader.Next() - if err != nil { - return res, err - } - if entry == nil { // END of dwarf data - return res, nil - } - attrs := getAttrs(entry) - - if entry.Tag != dwarf.TagStructType && entry.Tag != dwarf.TagTypedef { - continue - } - if entry.Tag == dwarf.TagTypedef { - typeName, _ := attrs[dwarf.AttrName].(string) - if typeName != "" { - typedef := res.typedefs[typeName] - if typedef == nil { - typedef = &Typedef{Name: typeName} - res.typedefs[typeName] = typedef - } - tt := attrs[dwarf.AttrType] - if tt != nil { - typedef.TypeOffsets = append(typedef.TypeOffsets, tt.(dwarf.Offset)) - } else { - //fmt.Println("hek") - } - } - continue - } - typeName, _ := attrs[dwarf.AttrName].(string) - - sz, _ := attrs[dwarf.AttrByteSize].(int64) - if sz == 0 { - reader.SkipChildren() - continue - } - - offsets, err := readMembers(reader) - if err != nil { - return res, err - } - nt := &Typ{ - Name: typeName, - Size: sz, - Fields: offsets, - } - res.offset2Type[(entry.Offset)] = nt - - } -} - -func readMembers( - reader *dwarf.Reader, -) ([]Field, error) { - var res []Field - for { - entry, err := reader.Next() - if err != nil { - return res, fmt.Errorf("can't read DWARF data: %w", err) - } - if entry == nil { // END of dwarf data - return res, nil - } - // Nil tag: end of the members list - if entry.Tag == 0 { - return res, nil - } - attrs := getAttrs(entry) - name, nok := attrs[dwarf.AttrName].(string) - value, vok := attrs[dwarf.AttrDataMemberLoc] - //fmt.Printf(" %s %d\n", name, value) - if nok && vok { - - res = append(res, Field{ - name, - uint64(value.(int64)), - }) - } - } -} -func getAttrs(entry *dwarf.Entry) map[dwarf.Attr]any { - attrs := map[dwarf.Attr]any{} - for f := range entry.Field { - attrs[entry.Field[f].Attr] = entry.Field[f].Val - } - return attrs -} - -type FieldDump struct { - Name string - Offset int -} - -func Dump(elfPath string, fields []Need) []FieldDump { - fmt.Fprintf(os.Stderr, "Dumping %s\n", elfPath) - var err error - - f, err := elf.Open(elfPath) - if err != nil { - panic(err) - } - defer f.Close() - - d, err := f.DWARF() - if err != nil { - panic(err) - - } - - types, err := structMemberOffsetsFromDwarf(d) - if err != nil { - panic(err) - } - - var e []FieldDump - for _, need := range fields { - typ := types.GetTypeByName2(need.Name) - if typ == nil { - typ = types.GetTypeByName2(need.PrettyName) - } - //if typ == nil { - // panic(fmt.Sprintf("typ %s not found", need.Name)) - //} - - for _, needField := range need.Fields { - o := -1 - if typ != nil { - f := typ.GetField(needField.Name) - if f != nil { - o = int(f.Offset) - } - } - pname := needField.PrintName - if pname == "" { - pname = fmt.Sprintf("%s%s", typeName(need), fieldName(needField.Name)) - } - e = append(e, FieldDump{pname, o}) - } - if need.Size { - szName := typeName(need) + "Size" - if typ == nil { - e = append(e, FieldDump{szName, -1}) - } else { - e = append(e, FieldDump{szName, int(typ.Size)}) - } - } - } - return e - -} - -func typeName(need Need) string { - n := need.Name - if need.PrettyName != "" { - n = need.PrettyName - } - n = strings.TrimSuffix(n, "_") - n = strings.TrimSuffix(n, "__") - n = strings.TrimPrefix(n, "__") - n = strings.TrimPrefix(n, "_") - parts := strings.Split(n, "_") - for i := range parts { - p1 := parts[i][:1] - p2 := parts[i][1:] - parts[i] = strings.ToUpper(p1) + p2 - } - return strings.Join(parts, "") - -} - -func fieldName(field string) string { - field = strings.TrimPrefix(field, "_") - parts := strings.Split(field, "_") - for i := range parts { - p1 := parts[i][:1] - p2 := parts[i][1:] - parts[i] = strings.ToUpper(p1) + p2 - } - return strings.Join(parts, "") -} - -type Need struct { - Name string - PrettyName string - Fields []NeedField - Size bool -} -type NeedField struct { - Name string - PrintName string -} - -type Version struct { - Major, Minor, Patch int -} - -func (p *Version) Compare(other Version) int { - major := other.Major - p.Major - if major != 0 { - return major - } - - minor := other.Minor - p.Minor - if minor != 0 { - return minor - } - return other.Patch - p.Patch -} - -type Entry struct { - SrcFile string - Version Version - Offsets []FieldDump -} diff --git a/ebpf/go.mod b/ebpf/go.mod deleted file mode 100644 index a78a661d82..0000000000 --- a/ebpf/go.mod +++ /dev/null @@ -1,52 +0,0 @@ -module github.com/grafana/pyroscope/ebpf - -go 1.21 - -require ( - connectrpc.com/connect v1.16.2 - github.com/avvmoto/buf-readerat v0.0.0-20171115124131-a17c8cb89270 - github.com/cespare/xxhash/v2 v2.2.0 - github.com/cilium/ebpf v0.11.0 - github.com/go-kit/log v0.2.1 - github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 - github.com/grafana/pyroscope/api v0.4.0 - github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab - github.com/klauspost/compress v1.17.7 - github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.19.0 - github.com/prometheus/common v0.52.3 - github.com/prometheus/prometheus v0.51.2 - github.com/samber/lo v1.38.1 - github.com/stretchr/testify v1.9.0 - golang.org/x/sys v0.19.0 -) - -require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect - github.com/jpillora/backoff v1.0.0 // indirect - github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect - google.golang.org/grpc v1.62.1 // indirect - google.golang.org/protobuf v1.34.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) - -// x/sys: v0.14.0 removes definition of BPF_F_KPROBE_MULTI_RETURN in unix/zerrors_linux.go -// https://github.com/golang/go/issues/63969 -replace golang.org/x/sys => golang.org/x/sys v0.13.0 diff --git a/ebpf/go.sum b/ebpf/go.sum deleted file mode 100644 index 01dbf90a0c..0000000000 --- a/ebpf/go.sum +++ /dev/null @@ -1,116 +0,0 @@ -connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= -connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= -github.com/avvmoto/buf-readerat v0.0.0-20171115124131-a17c8cb89270 h1:JIxGEMs4E5Zb6R7z2C5IgecI0mkqS97WAEF31wUbYTM= -github.com/avvmoto/buf-readerat v0.0.0-20171115124131-a17c8cb89270/go.mod h1:2XtVRGCw/HthOLxU0Qw6o6jSJrcEoOb2OCCl8gQYvGw= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= -github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= -github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= -github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grafana/pyroscope/api v0.4.0 h1:J86DxoNeLOvtJhB1Cn65JMZkXe682D+RqeoIUiYc/eo= -github.com/grafana/pyroscope/api v0.4.0/go.mod h1:MFnZNeUM4RDsDOnbgKW3GWoLSBpLzMMT9nkvhHHo81o= -github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db h1:7aN5cccjIqCLTzedH7MZzRZt5/lsAHch6Z3L2ZGn5FA= -github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe6ZTd9F8kXETBoijjFJ/ntaa//1wiH9BZu4zU= -github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA= -github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.51.2 h1:U0faf1nT4CB9DkBW87XLJCBi2s8nwWXdTbyzRUAkX0w= -github.com/prometheus/prometheus v0.51.2/go.mod h1:yv4MwOn3yHMQ6MZGHPg/U7Fcyqf+rxqiZfSur6myVtc= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= -github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/ebpf/metrics/metrics.go b/ebpf/metrics/metrics.go deleted file mode 100644 index 506d1a21a5..0000000000 --- a/ebpf/metrics/metrics.go +++ /dev/null @@ -1,19 +0,0 @@ -package metrics - -import "github.com/prometheus/client_golang/prometheus" - -type Metrics struct { - Symtab *SymtabMetrics - Python *PythonMetrics -} - -func New(reg prometheus.Registerer) *Metrics { - res := &Metrics{ - Symtab: NewSymtabMetrics(reg), - Python: NewPythonMetrics(reg), - } - if reg != nil { - reg.MustRegister() - } - return res -} diff --git a/ebpf/metrics/python.go b/ebpf/metrics/python.go deleted file mode 100644 index 96127d14c3..0000000000 --- a/ebpf/metrics/python.go +++ /dev/null @@ -1,65 +0,0 @@ -package metrics - -import "github.com/prometheus/client_golang/prometheus" - -type PythonMetrics struct { - PidDataError *prometheus.CounterVec - LostSamples prometheus.Counter - SymbolLookup *prometheus.CounterVec - UnknownSymbols *prometheus.CounterVec - StacktraceError prometheus.Counter - ProcessInitSuccess *prometheus.CounterVec - Load prometheus.Counter - LoadError prometheus.Counter -} - -func NewPythonMetrics(reg prometheus.Registerer) *PythonMetrics { - m := &PythonMetrics{ - PidDataError: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_pid_data_errors_total", - Help: "Total number of errors while trying to collect python data (offsets and memory values) from a running process", - }, []string{"service_name"}), - - LostSamples: prometheus.NewCounter(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_lost_samples_total", - Help: "Total number of samples that were lost due to a buffer overflow", - }), - SymbolLookup: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_symbol_lookup_total", - Help: "Total number of symbol lookups", - }, []string{"service_name"}), - StacktraceError: prometheus.NewCounter(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_stacktrace_errors_total", - Help: "Total number of errors while trying to collect stacktrace", - }), - UnknownSymbols: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_unknown_symbols_total", - Help: "Total number of unknown symbols", - }, []string{"service_name"}), - ProcessInitSuccess: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_process_init_success_total", - Help: "Total number of successful init calls", - }, []string{"service_name"}), - Load: prometheus.NewCounter(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_load", - Help: "Total number of pyperf loads", - }), - LoadError: prometheus.NewCounter(prometheus.CounterOpts{ - Name: "pyroscope_pyperf_load_error_total", - Help: "Total number of pyperf load errors", - }), - } - - if reg != nil { - reg.MustRegister( - m.PidDataError, - m.LostSamples, - m.SymbolLookup, - m.StacktraceError, - m.UnknownSymbols, - m.ProcessInitSuccess, - ) - } - - return m -} diff --git a/ebpf/metrics/symtab.go b/ebpf/metrics/symtab.go deleted file mode 100644 index 58238c0b9b..0000000000 --- a/ebpf/metrics/symtab.go +++ /dev/null @@ -1,54 +0,0 @@ -package metrics - -import "github.com/prometheus/client_golang/prometheus" - -type SymtabMetrics struct { - ElfErrors *prometheus.CounterVec - ProcErrors *prometheus.CounterVec - KnownSymbols *prometheus.CounterVec - UnknownSymbols *prometheus.CounterVec - UnknownModules *prometheus.CounterVec - UnknownStacks *prometheus.CounterVec -} - -func NewSymtabMetrics(reg prometheus.Registerer) *SymtabMetrics { - m := &SymtabMetrics{ - ElfErrors: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_symtab_elf_errors_total", - Help: "Total number of errors while trying to open an elf file", - }, []string{"error"}), - ProcErrors: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_symtab_proc_errors_total", - Help: "Total number of errors while trying refreshing /proc/pid/maps", - }, []string{"error"}), - KnownSymbols: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_symtab_known_symbols_total", - Help: "Total number of successfully resolved symbols", - }, []string{"service_name"}), - UnknownSymbols: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_symtab_unknown_symbols_total", - Help: "Total number of unresolved symbols for a module", - }, []string{"service_name"}), - UnknownModules: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_symtab_unknown_modules_total", - Help: "Total number of unknown modules - could not find an entry in /proc/pid/maps for a RIP", - }, []string{"service_name"}), - UnknownStacks: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_symtab_unknown_stacks_total", - Help: "Total number of stacks with unknowns > knowns", - }, []string{"service_name"}), - } - - if reg != nil { - reg.MustRegister( - m.ElfErrors, - m.ProcErrors, - m.KnownSymbols, - m.UnknownSymbols, - m.UnknownModules, - m.UnknownStacks, - ) - } - - return m -} diff --git a/ebpf/perf_event.go b/ebpf/perf_event.go deleted file mode 100644 index e3d83e7ba0..0000000000 --- a/ebpf/perf_event.go +++ /dev/null @@ -1,81 +0,0 @@ -//go:build linux - -package ebpfspy - -import ( - "fmt" - "syscall" - - "github.com/cilium/ebpf" - "github.com/cilium/ebpf/link" - "golang.org/x/sys/unix" -) - -type perfEvent struct { - fd int - ioctl bool - link *link.RawLink -} - -func newPerfEvent(cpu int, sampleRate int) (*perfEvent, error) { - var ( - fd int - err error - ) - attr := unix.PerfEventAttr{ - Type: unix.PERF_TYPE_SOFTWARE, - Config: unix.PERF_COUNT_SW_CPU_CLOCK, - Bits: unix.PerfBitFreq, - Sample: uint64(sampleRate), - } - fd, err = unix.PerfEventOpen(&attr, -1, cpu, -1, unix.PERF_FLAG_FD_CLOEXEC) - if err != nil { - return nil, fmt.Errorf("open perf event: %w", err) - } - return &perfEvent{fd: fd}, nil -} - -func (pe *perfEvent) Close() error { - _ = syscall.Close(pe.fd) - if pe.link != nil { - _ = pe.link.Close() - } - return nil -} - -func (pe *perfEvent) attachPerfEvent(prog *ebpf.Program) error { - err := pe.attachPerfEventLink(prog) - if err == nil { - return nil - } - return pe.attachPerfEventIoctl(prog) -} - -func (pe *perfEvent) attachPerfEventIoctl(prog *ebpf.Program) error { - var err error - err = unix.IoctlSetInt(pe.fd, unix.PERF_EVENT_IOC_SET_BPF, prog.FD()) - if err != nil { - return fmt.Errorf("setting perf event bpf program: %w", err) - } - if err = unix.IoctlSetInt(pe.fd, unix.PERF_EVENT_IOC_ENABLE, 0); err != nil { - return fmt.Errorf("enable perf event: %w", err) - } - pe.ioctl = true - return nil -} - -func (pe *perfEvent) attachPerfEventLink(prog *ebpf.Program) error { - var err error - opts := link.RawLinkOptions{ - Target: pe.fd, - Program: prog, - Attach: ebpf.AttachPerfEvent, - } - - pe.link, err = link.AttachRawLink(opts) - if err != nil { - return fmt.Errorf("attach raw link: %w", err) - } - - return nil -} diff --git a/ebpf/pprof/pprof.go b/ebpf/pprof/pprof.go deleted file mode 100644 index 62f94bbbfa..0000000000 --- a/ebpf/pprof/pprof.go +++ /dev/null @@ -1,266 +0,0 @@ -package pprof - -import ( - "fmt" - "io" - "reflect" - "sync" - "time" - "unsafe" - - "github.com/cespare/xxhash/v2" - "github.com/google/pprof/profile" - "github.com/grafana/pyroscope/ebpf/sd" - "github.com/klauspost/compress/gzip" - "github.com/prometheus/prometheus/model/labels" -) - -var ( - gzipWriterPool = sync.Pool{ - New: func() any { - res, err := gzip.NewWriterLevel(io.Discard, gzip.BestSpeed) - if err != nil { - panic(err) - } - return res - }, - } -) - -type SampleType uint32 - -var SampleTypeCpu = SampleType(0) -var SampleTypeMem = SampleType(1) - -type SampleAggregation bool - -var ( - // SampleAggregated mean samples are accumulated in ebpf, no need to dedup these - SampleAggregated = SampleAggregation(true) -) - -type CollectProfilesCallback func(sample ProfileSample) - -type SamplesCollector interface { - CollectProfiles(callback CollectProfilesCallback) error -} - -type ProfileSample struct { - Target *sd.Target - Pid uint32 - SampleType SampleType - Aggregation SampleAggregation - Stack []string - Value uint64 - Value2 uint64 -} - -type BuildersOptions struct { - SampleRate int64 - PerPIDProfile bool -} - -type builderHashKey struct { - labelsHash uint64 - pid uint32 - sampleType SampleType -} - -type ProfileBuilders struct { - Builders map[builderHashKey]*ProfileBuilder - opt BuildersOptions -} - -func NewProfileBuilders(options BuildersOptions) *ProfileBuilders { - return &ProfileBuilders{Builders: make(map[builderHashKey]*ProfileBuilder), opt: options} -} - -func Collect(builders *ProfileBuilders, collector SamplesCollector) error { - return collector.CollectProfiles(func(sample ProfileSample) { - builders.AddSample(&sample) - }) -} - -func (b *ProfileBuilders) AddSample(sample *ProfileSample) { - bb := b.BuilderForSample(sample) - if sample.Aggregation == SampleAggregated { - bb.CreateSample(sample) - } else { - bb.CreateSampleOrAddValue(sample) - } -} - -func (b *ProfileBuilders) BuilderForSample(sample *ProfileSample) *ProfileBuilder { - labelsHash, labels := sample.Target.Labels() - - k := builderHashKey{labelsHash: labelsHash, sampleType: sample.SampleType} - if b.opt.PerPIDProfile { - k.pid = sample.Pid - } - res := b.Builders[k] - if res != nil { - return res - } - - var sampleType []*profile.ValueType - var periodType *profile.ValueType - var period int64 - if sample.SampleType == SampleTypeCpu { - sampleType = []*profile.ValueType{{Type: "cpu", Unit: "nanoseconds"}} - periodType = &profile.ValueType{Type: "cpu", Unit: "nanoseconds"} - period = time.Second.Nanoseconds() / b.opt.SampleRate - } else { - sampleType = []*profile.ValueType{{Type: "alloc_objects", Unit: "count"}, {Type: "alloc_space", Unit: "bytes"}} - periodType = &profile.ValueType{Type: "space", Unit: "bytes"} - period = 512 * 1024 // todo - } - builder := &ProfileBuilder{ - locations: make(map[string]*profile.Location), - functions: make(map[string]*profile.Function), - sampleHashToSample: make(map[uint64]*profile.Sample), - Labels: labels, - Profile: &profile.Profile{ - Mapping: []*profile.Mapping{ - { - ID: 1, - }, - }, - SampleType: sampleType, - Period: period, - PeriodType: periodType, - TimeNanos: time.Now().UnixNano(), - }, - tmpLocationIDs: make([]uint64, 0, 128), - tmpLocations: make([]*profile.Location, 0, 128), - } - res = builder - b.Builders[k] = res - return res -} - -type ProfileBuilder struct { - locations map[string]*profile.Location - functions map[string]*profile.Function - sampleHashToSample map[uint64]*profile.Sample - Profile *profile.Profile - Labels labels.Labels - - tmpLocations []*profile.Location - tmpLocationIDs []uint64 -} - -func (p *ProfileBuilder) CreateSample(inputSample *ProfileSample) { - sample := p.newSample(inputSample) - p.addValue(inputSample, sample) - for i, s := range inputSample.Stack { - sample.Location[i] = p.addLocation(s) - } - p.Profile.Sample = append(p.Profile.Sample, sample) -} - -func (p *ProfileBuilder) CreateSampleOrAddValue(inputSample *ProfileSample) { - p.tmpLocations = p.tmpLocations[:0] - p.tmpLocationIDs = p.tmpLocationIDs[:0] - for _, s := range inputSample.Stack { - loc := p.addLocation(s) - p.tmpLocations = append(p.tmpLocations, loc) - p.tmpLocationIDs = append(p.tmpLocationIDs, loc.ID) - } - h := xxhash.Sum64(uint64Bytes(p.tmpLocationIDs)) - sample := p.sampleHashToSample[h] - if sample != nil { - p.addValue(inputSample, sample) - return - } - sample = p.newSample(inputSample) - p.addValue(inputSample, sample) - copy(sample.Location, p.tmpLocations) - p.sampleHashToSample[h] = sample - p.Profile.Sample = append(p.Profile.Sample, sample) -} - -func (p *ProfileBuilder) addLocation(function string) *profile.Location { - loc, ok := p.locations[function] - if ok { - return loc - } - - id := uint64(len(p.Profile.Location) + 1) - loc = &profile.Location{ - ID: id, - Mapping: p.Profile.Mapping[0], - Line: []profile.Line{ - { - Function: p.addFunction(function), - }, - }, - } - p.Profile.Location = append(p.Profile.Location, loc) - p.locations[function] = loc - return loc -} - -func (p *ProfileBuilder) addFunction(function string) *profile.Function { - f, ok := p.functions[function] - if ok { - return f - } - - id := uint64(len(p.Profile.Function) + 1) - f = &profile.Function{ - ID: id, - Name: function, - } - p.Profile.Function = append(p.Profile.Function, f) - p.functions[function] = f - return f -} - -func (p *ProfileBuilder) Write(dst io.Writer) (int64, error) { - gzipWriter := gzipWriterPool.Get().(*gzip.Writer) - gzipWriter.Reset(dst) - defer func() { - gzipWriter.Reset(io.Discard) - gzipWriterPool.Put(gzipWriter) - }() - err := p.Profile.WriteUncompressed(gzipWriter) - if err != nil { - return 0, fmt.Errorf("ebpf profile encode %w", err) - } - err = gzipWriter.Close() - if err != nil { - return 0, fmt.Errorf("ebpf profile encode %w", err) - } - return 0, nil -} - -func uint64Bytes(s []uint64) []byte { - if len(s) == 0 { - return nil - } - var bs []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) - hdr.Len = len(s) * 8 - hdr.Cap = hdr.Len - hdr.Data = uintptr(unsafe.Pointer(&s[0])) - return bs -} -func (p *ProfileBuilder) newSample(inputSample *ProfileSample) *profile.Sample { - sample := new(profile.Sample) - if inputSample.SampleType == SampleTypeCpu { - sample.Value = []int64{0} - } else { - sample.Value = []int64{0, 0} - } - sample.Location = make([]*profile.Location, len(inputSample.Stack)) - return sample -} - -func (p *ProfileBuilder) addValue(inputSample *ProfileSample, sample *profile.Sample) { - if inputSample.SampleType == SampleTypeCpu { - sample.Value[0] += int64(inputSample.Value) * p.Profile.Period - } else { - sample.Value[0] += int64(inputSample.Value) - sample.Value[1] += int64(inputSample.Value2) - } -} diff --git a/ebpf/pprof/pprof_test.go b/ebpf/pprof/pprof_test.go deleted file mode 100644 index 99412484c4..0000000000 --- a/ebpf/pprof/pprof_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package pprof - -import ( - "bytes" - "fmt" - "strings" - "testing" - "time" - - "github.com/google/pprof/profile" - "github.com/grafana/pyroscope/ebpf/sd" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestBackAndForth(t *testing.T) { - const sampleRate = 97 - period := time.Second.Nanoseconds() / int64(sampleRate) - - builders := NewProfileBuilders(BuildersOptions{ - SampleRate: int64(97), - PerPIDProfile: false, - }) - - builders.AddSample( - sample([]string{"a", "b", "c"}, 239)) - builders.AddSample( - sample([]string{"a", "b", "d"}, 4242)) - - builder := builders.BuilderForSample(sample([]string{"a", "b", "c"}, 0)) - - buf := bytes.NewBuffer(nil) - - _, err := builder.Write(buf) - assert.NoError(t, err) - - rawProfile := buf.Bytes() - - parsed, err := profile.Parse(bytes.NewBuffer(rawProfile)) - assert.NoError(t, err) - require.NotNil(t, parsed) - assert.Equal(t, 2, len(parsed.Sample)) - assert.Equal(t, 4, len(parsed.Function)) - assert.Equal(t, 4, len(parsed.Location)) - - stacks := stackCollapse(parsed) - - assert.Equal(t, 239*period, stacks["a;b;c"]) - assert.Equal(t, 4242*period, stacks["a;b;d"]) -} - -var testTarget = sd.NewTarget("", 1, sd.DiscoveryTarget{"foo": "bar"}) - -func sample(stack []string, v uint64) *ProfileSample { - return &ProfileSample{ - Pid: 1, - Target: testTarget, - SampleType: SampleTypeCpu, - Aggregation: SampleAggregated, - Stack: stack, - Value: v, - } -} - -func TestMergeSamples(t *testing.T) { - const sampleRate = 97 - period := time.Second.Nanoseconds() / int64(sampleRate) - - builders := NewProfileBuilders(BuildersOptions{ - SampleRate: int64(97), - }) - - builder := builders.BuilderForSample(sample([]string{"a", "b", "c"}, 0)) - - builder.CreateSampleOrAddValue(sample([]string{"a", "b", "d"}, 4242)) - - for i := 0; i < 14; i++ { - builder.CreateSampleOrAddValue(sample([]string{"a", "b", "c"}, 239)) - } - - var longStack []string - for i := 0; i < 512; i++ { - longStack = append(longStack, fmt.Sprintf("l_%d", i)) - } - builder.CreateSampleOrAddValue(sample(longStack, 3)) - builder.CreateSampleOrAddValue(sample([]string{"a", "b"}, 42)) - - assert.Equal(t, 4, len(builder.Profile.Sample)) - - buf := bytes.NewBuffer(nil) - _, err := builder.Write(buf) - assert.NoError(t, err) - rawProfile := buf.Bytes() - - parsed, err := profile.Parse(bytes.NewBuffer(rawProfile)) - assert.NoError(t, err) - require.NotNil(t, parsed) - assert.Equal(t, 4, len(parsed.Sample)) - assert.Equal(t, 4+512, len(parsed.Function)) - assert.Equal(t, 4+512, len(parsed.Location)) - - stacks := stackCollapse(parsed) - - assert.Equal(t, 14*239*period, stacks["a;b;c"]) - assert.Equal(t, 4242*period, stacks["a;b;d"]) - assert.Equal(t, 42*period, stacks["a;b"]) - assert.Equal(t, 3*period, stacks[strings.Join(longStack, ";")]) - assert.Equal(t, 4, len(parsed.Sample)) - if t.Failed() { - for s, i := range stacks { - t.Logf("%s: %d", s, i) - } - } -} - -func stackCollapse(parsed *profile.Profile) map[string]int64 { - stacks := map[string]int64{} - for _, sample := range parsed.Sample { - stack := "" - for i, location := range sample.Location { - if i != 0 { - stack += ";" - } - stack += location.Line[0].Function.Name - } - stacks[stack] += sample.Value[0] - } - return stacks -} diff --git a/ebpf/pyrobpf/gen.go b/ebpf/pyrobpf/gen.go deleted file mode 100644 index f788d89551..0000000000 --- a/ebpf/pyrobpf/gen.go +++ /dev/null @@ -1,4 +0,0 @@ -package pyrobpf - -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -type global_config_t -type pid_event -target amd64 -cc clang -cflags "-O2 -Wall -Werror -fpie -Wno-unused-variable -Wno-unused-function" Profile ../bpf/profile.bpf.c -- -I../bpf/libbpf -I../bpf/vmlinux/ -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -type global_config_t -type pid_event -target arm64 -cc clang -cflags "-O2 -Wall -Werror -fpie -Wno-unused-variable -Wno-unused-function" Profile ../bpf/profile.bpf.c -- -I../bpf/libbpf -I../bpf/vmlinux/ diff --git a/ebpf/pyrobpf/profile_bpfel_arm64.go b/ebpf/pyrobpf/profile_bpfel_arm64.go deleted file mode 100644 index e272315bdb..0000000000 --- a/ebpf/pyrobpf/profile_bpfel_arm64.go +++ /dev/null @@ -1,158 +0,0 @@ -// Code generated by bpf2go; DO NOT EDIT. -//go:build arm64 - -package pyrobpf - -import ( - "bytes" - _ "embed" - "fmt" - "io" - - "github.com/cilium/ebpf" -) - -type ProfileGlobalConfigT struct{ NsPidIno uint64 } - -type ProfilePidConfig struct { - Type uint8 - CollectUser uint8 - CollectKernel uint8 - Padding uint8 -} - -type ProfilePidEvent struct { - Op uint32 - Pid uint32 -} - -type ProfileSampleKey struct { - Pid uint32 - Flags uint32 - KernStack int64 - UserStack int64 -} - -// LoadProfile returns the embedded CollectionSpec for Profile. -func LoadProfile() (*ebpf.CollectionSpec, error) { - reader := bytes.NewReader(_ProfileBytes) - spec, err := ebpf.LoadCollectionSpecFromReader(reader) - if err != nil { - return nil, fmt.Errorf("can't load Profile: %w", err) - } - - return spec, err -} - -// LoadProfileObjects loads Profile and converts it into a struct. -// -// The following types are suitable as obj argument: -// -// *ProfileObjects -// *ProfilePrograms -// *ProfileMaps -// -// See ebpf.CollectionSpec.LoadAndAssign documentation for details. -func LoadProfileObjects(obj interface{}, opts *ebpf.CollectionOptions) error { - spec, err := LoadProfile() - if err != nil { - return err - } - - return spec.LoadAndAssign(obj, opts) -} - -// ProfileSpecs contains maps and programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type ProfileSpecs struct { - ProfileProgramSpecs - ProfileMapSpecs -} - -// ProfileSpecs contains programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type ProfileProgramSpecs struct { - DisassociateCtty *ebpf.ProgramSpec `ebpf:"disassociate_ctty"` - DoPerfEvent *ebpf.ProgramSpec `ebpf:"do_perf_event"` - Exec *ebpf.ProgramSpec `ebpf:"exec"` -} - -// ProfileMapSpecs contains maps before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type ProfileMapSpecs struct { - Counts *ebpf.MapSpec `ebpf:"counts"` - Events *ebpf.MapSpec `ebpf:"events"` - Pids *ebpf.MapSpec `ebpf:"pids"` - Progs *ebpf.MapSpec `ebpf:"progs"` - Stacks *ebpf.MapSpec `ebpf:"stacks"` -} - -// ProfileObjects contains all objects after they have been loaded into the kernel. -// -// It can be passed to LoadProfileObjects or ebpf.CollectionSpec.LoadAndAssign. -type ProfileObjects struct { - ProfilePrograms - ProfileMaps -} - -func (o *ProfileObjects) Close() error { - return _ProfileClose( - &o.ProfilePrograms, - &o.ProfileMaps, - ) -} - -// ProfileMaps contains all maps after they have been loaded into the kernel. -// -// It can be passed to LoadProfileObjects or ebpf.CollectionSpec.LoadAndAssign. -type ProfileMaps struct { - Counts *ebpf.Map `ebpf:"counts"` - Events *ebpf.Map `ebpf:"events"` - Pids *ebpf.Map `ebpf:"pids"` - Progs *ebpf.Map `ebpf:"progs"` - Stacks *ebpf.Map `ebpf:"stacks"` -} - -func (m *ProfileMaps) Close() error { - return _ProfileClose( - m.Counts, - m.Events, - m.Pids, - m.Progs, - m.Stacks, - ) -} - -// ProfilePrograms contains all programs after they have been loaded into the kernel. -// -// It can be passed to LoadProfileObjects or ebpf.CollectionSpec.LoadAndAssign. -type ProfilePrograms struct { - DisassociateCtty *ebpf.Program `ebpf:"disassociate_ctty"` - DoPerfEvent *ebpf.Program `ebpf:"do_perf_event"` - Exec *ebpf.Program `ebpf:"exec"` -} - -func (p *ProfilePrograms) Close() error { - return _ProfileClose( - p.DisassociateCtty, - p.DoPerfEvent, - p.Exec, - ) -} - -func _ProfileClose(closers ...io.Closer) error { - for _, closer := range closers { - if err := closer.Close(); err != nil { - return err - } - } - return nil -} - -// Do not access this directly. -// -//go:embed profile_bpfel_arm64.o -var _ProfileBytes []byte diff --git a/ebpf/pyrobpf/profile_bpfel_arm64.o b/ebpf/pyrobpf/profile_bpfel_arm64.o deleted file mode 100644 index 8b58dc6b13..0000000000 Binary files a/ebpf/pyrobpf/profile_bpfel_arm64.o and /dev/null differ diff --git a/ebpf/pyrobpf/profile_bpfel_x86.go b/ebpf/pyrobpf/profile_bpfel_x86.go deleted file mode 100644 index a8163aeb12..0000000000 --- a/ebpf/pyrobpf/profile_bpfel_x86.go +++ /dev/null @@ -1,158 +0,0 @@ -// Code generated by bpf2go; DO NOT EDIT. -//go:build 386 || amd64 - -package pyrobpf - -import ( - "bytes" - _ "embed" - "fmt" - "io" - - "github.com/cilium/ebpf" -) - -type ProfileGlobalConfigT struct{ NsPidIno uint64 } - -type ProfilePidConfig struct { - Type uint8 - CollectUser uint8 - CollectKernel uint8 - Padding uint8 -} - -type ProfilePidEvent struct { - Op uint32 - Pid uint32 -} - -type ProfileSampleKey struct { - Pid uint32 - Flags uint32 - KernStack int64 - UserStack int64 -} - -// LoadProfile returns the embedded CollectionSpec for Profile. -func LoadProfile() (*ebpf.CollectionSpec, error) { - reader := bytes.NewReader(_ProfileBytes) - spec, err := ebpf.LoadCollectionSpecFromReader(reader) - if err != nil { - return nil, fmt.Errorf("can't load Profile: %w", err) - } - - return spec, err -} - -// LoadProfileObjects loads Profile and converts it into a struct. -// -// The following types are suitable as obj argument: -// -// *ProfileObjects -// *ProfilePrograms -// *ProfileMaps -// -// See ebpf.CollectionSpec.LoadAndAssign documentation for details. -func LoadProfileObjects(obj interface{}, opts *ebpf.CollectionOptions) error { - spec, err := LoadProfile() - if err != nil { - return err - } - - return spec.LoadAndAssign(obj, opts) -} - -// ProfileSpecs contains maps and programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type ProfileSpecs struct { - ProfileProgramSpecs - ProfileMapSpecs -} - -// ProfileSpecs contains programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type ProfileProgramSpecs struct { - DisassociateCtty *ebpf.ProgramSpec `ebpf:"disassociate_ctty"` - DoPerfEvent *ebpf.ProgramSpec `ebpf:"do_perf_event"` - Exec *ebpf.ProgramSpec `ebpf:"exec"` -} - -// ProfileMapSpecs contains maps before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type ProfileMapSpecs struct { - Counts *ebpf.MapSpec `ebpf:"counts"` - Events *ebpf.MapSpec `ebpf:"events"` - Pids *ebpf.MapSpec `ebpf:"pids"` - Progs *ebpf.MapSpec `ebpf:"progs"` - Stacks *ebpf.MapSpec `ebpf:"stacks"` -} - -// ProfileObjects contains all objects after they have been loaded into the kernel. -// -// It can be passed to LoadProfileObjects or ebpf.CollectionSpec.LoadAndAssign. -type ProfileObjects struct { - ProfilePrograms - ProfileMaps -} - -func (o *ProfileObjects) Close() error { - return _ProfileClose( - &o.ProfilePrograms, - &o.ProfileMaps, - ) -} - -// ProfileMaps contains all maps after they have been loaded into the kernel. -// -// It can be passed to LoadProfileObjects or ebpf.CollectionSpec.LoadAndAssign. -type ProfileMaps struct { - Counts *ebpf.Map `ebpf:"counts"` - Events *ebpf.Map `ebpf:"events"` - Pids *ebpf.Map `ebpf:"pids"` - Progs *ebpf.Map `ebpf:"progs"` - Stacks *ebpf.Map `ebpf:"stacks"` -} - -func (m *ProfileMaps) Close() error { - return _ProfileClose( - m.Counts, - m.Events, - m.Pids, - m.Progs, - m.Stacks, - ) -} - -// ProfilePrograms contains all programs after they have been loaded into the kernel. -// -// It can be passed to LoadProfileObjects or ebpf.CollectionSpec.LoadAndAssign. -type ProfilePrograms struct { - DisassociateCtty *ebpf.Program `ebpf:"disassociate_ctty"` - DoPerfEvent *ebpf.Program `ebpf:"do_perf_event"` - Exec *ebpf.Program `ebpf:"exec"` -} - -func (p *ProfilePrograms) Close() error { - return _ProfileClose( - p.DisassociateCtty, - p.DoPerfEvent, - p.Exec, - ) -} - -func _ProfileClose(closers ...io.Closer) error { - for _, closer := range closers { - if err := closer.Close(); err != nil { - return err - } - } - return nil -} - -// Do not access this directly. -// -//go:embed profile_bpfel_x86.o -var _ProfileBytes []byte diff --git a/ebpf/pyrobpf/profile_bpfel_x86.o b/ebpf/pyrobpf/profile_bpfel_x86.o deleted file mode 100644 index 901593a6a1..0000000000 Binary files a/ebpf/pyrobpf/profile_bpfel_x86.o and /dev/null differ diff --git a/ebpf/pyrobpf/sync.go b/ebpf/pyrobpf/sync.go deleted file mode 100644 index 6608bc66cd..0000000000 --- a/ebpf/pyrobpf/sync.go +++ /dev/null @@ -1,39 +0,0 @@ -package pyrobpf - -const MapNamePIDs = "pids" - -type ProfilingType uint8 - -//#define PROFILING_TYPE_UNKNOWN 1 -//#define PROFILING_TYPE_FRAMEPOINTERS 2 -//#define PROFILING_TYPE_PYTHON 3 -//#define PROFILING_TYPE_ERROR 4 - -var ( - ProfilingTypeUnknown ProfilingType = 1 - ProfilingTypeFramepointers ProfilingType = 2 - ProfilingTypePython ProfilingType = 3 - ProfilingTypeError ProfilingType = 4 -) - -//#define OP_REQUEST_UNKNOWN_PROCESS_INFO 1 -//#define OP_PID_DEAD 2 -//#define OP_REQUEST_EXEC_PROCESS_INFO 3 - -type PidOp uint32 - -var ( - PidOpRequestUnknownProcessInfo PidOp = 1 - PidOpDead PidOp = 2 - PidOpRequestExecProcessInfo PidOp = 3 -) - -//#define SAMPLE_KEY_FLAG_PYTHON_STACK 1 -//#define SAMPLE_KEY_FLAG_STACK_TRUNCATED 2 - -type SampleKeyFlag uint32 - -var ( - SampleKeyFlagPythonStack SampleKeyFlag = 1 - SampleKeyFlagStackTruncated SampleKeyFlag = 2 -) diff --git a/ebpf/python/const_amd64.go b/ebpf/python/const_amd64.go deleted file mode 100644 index 38b4ee881c..0000000000 --- a/ebpf/python/const_amd64.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build amd64 && linux - -package python - -// https://github.com/bminor/glibc/blob/49b308a26e2a9e02ef396f67f59c462ad4171ea4/sysdeps/x86/nptl/bits/pthreadtypes-arch.h#L25 -// # define __SIZEOF_PTHREAD_MUTEX_T 40 -const mutexSizeGlibc = 40 - -// https://github.com/bminor/musl/blob/f314e133929b6379eccc632bef32eaebb66a7335/include/alltypes.h.in#L86C1-L86C173 -const mutexSizeMusl = 40 diff --git a/ebpf/python/const_arm64.go b/ebpf/python/const_arm64.go deleted file mode 100644 index 1fc6d66025..0000000000 --- a/ebpf/python/const_arm64.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build arm64 && linux - -package python - -// https://github.com/bminor/glibc/blob/49b308a26e2a9e02ef396f67f59c462ad4171ea4/sysdeps/aarch64/nptl/bits/pthreadtypes-arch.h#L34C24-L34C24 -// # define __SIZEOF_PTHREAD_MUTEX_T 48 -const mutexSizeGlibc = 48 - -// https://github.com/bminor/musl/blob/f314e133929b6379eccc632bef32eaebb66a7335/include/alltypes.h.in#L86C1-L86C173 -const mutexSizeMusl = 40 diff --git a/ebpf/python/gen.go b/ebpf/python/gen.go deleted file mode 100644 index 9b1e80c6a3..0000000000 --- a/ebpf/python/gen.go +++ /dev/null @@ -1,4 +0,0 @@ -package python - -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -type global_config_t -type libc -type py_str_type -type py_event -type py_offset_config -target amd64 -cc clang -cflags "-O2 -Wall -Werror -fpie -Wno-unused-variable -Wno-unused-function" Perf ../bpf/pyperf.bpf.c -- -I../bpf/libbpf -I../bpf/vmlinux/ -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -type global_config_t -type libc -type py_str_type -type py_event -type py_offset_config -target arm64 -cc clang -cflags "-O2 -Wall -Werror -fpie -Wno-unused-variable -Wno-unused-function" Perf ../bpf/pyperf.bpf.c -- -I../bpf/libbpf -I../bpf/vmlinux/ diff --git a/ebpf/python/glibc_offsets_gen_amd64.go b/ebpf/python/glibc_offsets_gen_amd64.go deleted file mode 100644 index 6acc9f3b16..0000000000 --- a/ebpf/python/glibc_offsets_gen_amd64.go +++ /dev/null @@ -1,91 +0,0 @@ -//go:build amd64 && linux - -// Code generated by glibc_dwarfdump. DO NOT EDIT. -package python - -var glibcOffsets = map[Version]*GlibcOffsets{ - // 2.27 testdata/glibc-x64/glibc-2.27/libc.so.6 - {2, 27, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2304, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.28 testdata/glibc-x64/glibc-2.28/libc.so.6 - {2, 28, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2304, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.29 testdata/glibc-x64/glibc-2.29/libc.so.6 - {2, 29, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2304, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.30 testdata/glibc-x64/glibc-2.30/libc.so.6 - {2, 30, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2304, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.31 testdata/glibc-x64/glibc-2.31/libc.so.6 - {2, 31, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2304, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.32 testdata/glibc-x64/glibc-2.32/libc.so.6 - {2, 32, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2496, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.33 testdata/glibc-x64/glibc-2.33/libc.so.6 - {2, 33, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2496, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.34 testdata/glibc-x64/glibc-2.34/libc.so.6 - {2, 34, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2496, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.35 testdata/glibc-x64/glibc-2.35/libc.so.6 - {2, 35, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2496, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.36 testdata/glibc-x64/glibc-2.36/libc.so.6 - {2, 36, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2368, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.37 testdata/glibc-x64/glibc-2.37/libc.so.6 - {2, 37, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2368, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.38 testdata/glibc-x64/glibc-2.38/libc.so.6 - {2, 38, 0}: { - PthreadSpecific1stblock: 784, - PthreadSize: 2368, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, -} diff --git a/ebpf/python/glibc_offsets_gen_arm64.go b/ebpf/python/glibc_offsets_gen_arm64.go deleted file mode 100644 index f66cb879a0..0000000000 --- a/ebpf/python/glibc_offsets_gen_arm64.go +++ /dev/null @@ -1,91 +0,0 @@ -//go:build arm64 && linux - -// Code generated by glibc_dwarfdump. DO NOT EDIT. -package python - -var glibcOffsets = map[Version]*GlibcOffsets{ - // 2.27 testdata/glibc-arm64/glibc-2.27/libc.so.6 - {2, 27, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1776, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.28 testdata/glibc-arm64/glibc-2.28/libc.so.6 - {2, 28, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1792, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.29 testdata/glibc-arm64/glibc-2.29/libc.so.6 - {2, 29, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1792, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.30 testdata/glibc-arm64/glibc-2.30/libc.so.6 - {2, 30, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1792, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.31 testdata/glibc-arm64/glibc-2.31/libc.so.6 - {2, 31, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1792, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.32 testdata/glibc-arm64/glibc-2.32/libc.so.6 - {2, 32, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1936, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.33 testdata/glibc-arm64/glibc-2.33/libc.so.6 - {2, 33, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1936, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.34 testdata/glibc-arm64/glibc-2.34/libc.so.6 - {2, 34, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1936, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.35 testdata/glibc-arm64/glibc-2.35/libc.so.6 - {2, 35, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1984, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.36 testdata/glibc-arm64/glibc-2.36/libc.so.6 - {2, 36, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1856, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.37 testdata/glibc-arm64/glibc-2.37/libc.so.6 - {2, 37, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1856, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, - // 2.38 testdata/glibc-arm64/glibc-2.38/libc.so.6 - {2, 38, 0}: { - PthreadSpecific1stblock: 272, - PthreadSize: 1856, - PthreadKeyDataData: 8, - PthreadKeyDataSize: 16, - }, -} diff --git a/ebpf/python/musl_offsets_gen_amd64.go b/ebpf/python/musl_offsets_gen_amd64.go deleted file mode 100644 index a9b84741d5..0000000000 --- a/ebpf/python/musl_offsets_gen_amd64.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build amd64 && linux - -// Code generated by musl_dwarfdump. DO NOT EDIT. -package python - -var muslOffsets = map[Version]*MuslOffsets{ - // 1.1 testdata/alpine-amd64/3.8/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 1, 19}: { - PthreadTsd: 152, - PthreadSize: 280, - }, - // 1.1 testdata/alpine-amd64/3.9/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 1, 20}: { - PthreadTsd: 152, - PthreadSize: 240, - }, - // 1.1 testdata/alpine-amd64/3.10/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 1, 22}: { - PthreadTsd: 136, - PthreadSize: 224, - }, - // 1.1 testdata/alpine-amd64/3.11/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 1, 24}: { - PthreadTsd: 136, - PthreadSize: 224, - }, - // 1.1 testdata/alpine-amd64/3.12/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 1, 24}: { - PthreadTsd: 136, - PthreadSize: 224, - }, - // 1.2 testdata/alpine-amd64/3.15/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 2, 2}: { - PthreadTsd: 128, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-amd64/3.13/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 2, 2}: { - PthreadTsd: 128, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-amd64/3.14/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 2, 2}: { - PthreadTsd: 128, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-amd64/3.17/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 2, 3}: { - PthreadTsd: 128, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-amd64/3.16/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 2, 3}: { - PthreadTsd: 128, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-amd64/3.18/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug - {1, 2, 4}: { - PthreadTsd: 128, - PthreadSize: 200, - }, -} diff --git a/ebpf/python/musl_offsets_gen_arm64.go b/ebpf/python/musl_offsets_gen_arm64.go deleted file mode 100644 index c689cc4075..0000000000 --- a/ebpf/python/musl_offsets_gen_arm64.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build arm64 && linux - -// Code generated by musl_dwarfdump. DO NOT EDIT. -package python - -var muslOffsets = map[Version]*MuslOffsets{ - // 1.1 testdata/alpine-arm64/3.8/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 1, 19}: { - PthreadTsd: 152, - PthreadSize: 280, - }, - // 1.1 testdata/alpine-arm64/3.9/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 1, 20}: { - PthreadTsd: 152, - PthreadSize: 240, - }, - // 1.1 testdata/alpine-arm64/3.10/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 1, 22}: { - PthreadTsd: 136, - PthreadSize: 224, - }, - // 1.1 testdata/alpine-arm64/3.11/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 1, 24}: { - PthreadTsd: 136, - PthreadSize: 224, - }, - // 1.1 testdata/alpine-arm64/3.12/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 1, 24}: { - PthreadTsd: 136, - PthreadSize: 224, - }, - // 1.2 testdata/alpine-arm64/3.15/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 2, 2}: { - PthreadTsd: 112, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-arm64/3.13/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 2, 2}: { - PthreadTsd: 112, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-arm64/3.14/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 2, 2}: { - PthreadTsd: 112, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-arm64/3.17/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 2, 3}: { - PthreadTsd: 112, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-arm64/3.16/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 2, 3}: { - PthreadTsd: 112, - PthreadSize: 200, - }, - // 1.2 testdata/alpine-arm64/3.18/usr/lib/debug/lib/ld-musl-aarch64.so.1.debug - {1, 2, 4}: { - PthreadTsd: 112, - PthreadSize: 200, - }, -} diff --git a/ebpf/python/perf_bpfel_arm64.go b/ebpf/python/perf_bpfel_arm64.go deleted file mode 100644 index fe682e2b30..0000000000 --- a/ebpf/python/perf_bpfel_arm64.go +++ /dev/null @@ -1,236 +0,0 @@ -// Code generated by bpf2go; DO NOT EDIT. -//go:build arm64 - -package python - -import ( - "bytes" - _ "embed" - "fmt" - "io" - - "github.com/cilium/ebpf" -) - -type PerfGlobalConfigT struct { - BpfLogErr uint8 - BpfLogDebug uint8 - _ [6]byte - NsPidIno uint64 -} - -type PerfLibc struct { - Musl bool - _ [1]byte - PthreadSize int16 - PthreadSpecific1stblock int16 -} - -type PerfPyEvent struct { - K PerfSampleKey - StackLen uint32 - Stack [96]uint32 - _ [4]byte -} - -type PerfPyOffsetConfig struct { - PyThreadStateFrame int16 - PyThreadStateCframe int16 - PyCFrameCurrentFrame int16 - PyCodeObjectCoFilename int16 - PyCodeObjectCoName int16 - PyCodeObjectCoVarnames int16 - PyCodeObjectCoLocalsplusnames int16 - PyCodeObjectCoCell2arg int16 - PyCodeObjectCoCellvars int16 - PyCodeObjectCoNlocals int16 - PyTupleObjectObItem int16 - PyVarObjectObSize int16 - PyObjectObType int16 - PyTypeObjectTpName int16 - VFrameCode int16 - VFramePrevious int16 - VFrameLocalsplus int16 - PyInterpreterFrameOwner int16 - PyASCIIObjectSize int16 - PyCompactUnicodeObjectSize int16 - PyCellObjectObRef int16 - _ [6]byte - Base uint64 - PyCellType uint64 -} - -type PerfPyPidData struct { - Offsets PerfPyOffsetConfig - Version struct { - Major uint32 - Minor uint32 - Patch uint32 - } - Libc PerfLibc - _ [2]byte - TssKey int32 - CollectKernel uint8 - _ [7]byte -} - -type PerfPySampleStateT struct { - SymbolCounter int64 - Offsets PerfPyOffsetConfig - CurCpu uint32 - _ [4]byte - FramePtr uint64 - PythonStackProgCallCnt int64 - Sym PerfPySymbol - Event PerfPyEvent - Padding uint64 -} - -type PerfPyStrType struct { - Type uint8 - SizeCodepoints uint8 -} - -type PerfPySymbol struct { - Classname [32]int8 - Name [64]int8 - File [128]int8 - ClassnameType PerfPyStrType - NameType PerfPyStrType - FileType PerfPyStrType - Padding PerfPyStrType -} - -type PerfSampleKey struct { - Pid uint32 - Flags uint32 - KernStack int64 - UserStack int64 -} - -// LoadPerf returns the embedded CollectionSpec for Perf. -func LoadPerf() (*ebpf.CollectionSpec, error) { - reader := bytes.NewReader(_PerfBytes) - spec, err := ebpf.LoadCollectionSpecFromReader(reader) - if err != nil { - return nil, fmt.Errorf("can't load Perf: %w", err) - } - - return spec, err -} - -// LoadPerfObjects loads Perf and converts it into a struct. -// -// The following types are suitable as obj argument: -// -// *PerfObjects -// *PerfPrograms -// *PerfMaps -// -// See ebpf.CollectionSpec.LoadAndAssign documentation for details. -func LoadPerfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { - spec, err := LoadPerf() - if err != nil { - return err - } - - return spec.LoadAndAssign(obj, opts) -} - -// PerfSpecs contains maps and programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type PerfSpecs struct { - PerfProgramSpecs - PerfMapSpecs -} - -// PerfSpecs contains programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type PerfProgramSpecs struct { - PyperfCollect *ebpf.ProgramSpec `ebpf:"pyperf_collect"` - ReadPythonStack *ebpf.ProgramSpec `ebpf:"read_python_stack"` -} - -// PerfMapSpecs contains maps before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type PerfMapSpecs struct { - Counts *ebpf.MapSpec `ebpf:"counts"` - PyPidConfig *ebpf.MapSpec `ebpf:"py_pid_config"` - PyProgs *ebpf.MapSpec `ebpf:"py_progs"` - PyStateHeap *ebpf.MapSpec `ebpf:"py_state_heap"` - PySymbols *ebpf.MapSpec `ebpf:"py_symbols"` - PythonStacks *ebpf.MapSpec `ebpf:"python_stacks"` - Stacks *ebpf.MapSpec `ebpf:"stacks"` -} - -// PerfObjects contains all objects after they have been loaded into the kernel. -// -// It can be passed to LoadPerfObjects or ebpf.CollectionSpec.LoadAndAssign. -type PerfObjects struct { - PerfPrograms - PerfMaps -} - -func (o *PerfObjects) Close() error { - return _PerfClose( - &o.PerfPrograms, - &o.PerfMaps, - ) -} - -// PerfMaps contains all maps after they have been loaded into the kernel. -// -// It can be passed to LoadPerfObjects or ebpf.CollectionSpec.LoadAndAssign. -type PerfMaps struct { - Counts *ebpf.Map `ebpf:"counts"` - PyPidConfig *ebpf.Map `ebpf:"py_pid_config"` - PyProgs *ebpf.Map `ebpf:"py_progs"` - PyStateHeap *ebpf.Map `ebpf:"py_state_heap"` - PySymbols *ebpf.Map `ebpf:"py_symbols"` - PythonStacks *ebpf.Map `ebpf:"python_stacks"` - Stacks *ebpf.Map `ebpf:"stacks"` -} - -func (m *PerfMaps) Close() error { - return _PerfClose( - m.Counts, - m.PyPidConfig, - m.PyProgs, - m.PyStateHeap, - m.PySymbols, - m.PythonStacks, - m.Stacks, - ) -} - -// PerfPrograms contains all programs after they have been loaded into the kernel. -// -// It can be passed to LoadPerfObjects or ebpf.CollectionSpec.LoadAndAssign. -type PerfPrograms struct { - PyperfCollect *ebpf.Program `ebpf:"pyperf_collect"` - ReadPythonStack *ebpf.Program `ebpf:"read_python_stack"` -} - -func (p *PerfPrograms) Close() error { - return _PerfClose( - p.PyperfCollect, - p.ReadPythonStack, - ) -} - -func _PerfClose(closers ...io.Closer) error { - for _, closer := range closers { - if err := closer.Close(); err != nil { - return err - } - } - return nil -} - -// Do not access this directly. -// -//go:embed perf_bpfel_arm64.o -var _PerfBytes []byte diff --git a/ebpf/python/perf_bpfel_arm64.o b/ebpf/python/perf_bpfel_arm64.o deleted file mode 100644 index e4e44eb4dd..0000000000 Binary files a/ebpf/python/perf_bpfel_arm64.o and /dev/null differ diff --git a/ebpf/python/perf_bpfel_x86.go b/ebpf/python/perf_bpfel_x86.go deleted file mode 100644 index 12e17f2591..0000000000 --- a/ebpf/python/perf_bpfel_x86.go +++ /dev/null @@ -1,236 +0,0 @@ -// Code generated by bpf2go; DO NOT EDIT. -//go:build 386 || amd64 - -package python - -import ( - "bytes" - _ "embed" - "fmt" - "io" - - "github.com/cilium/ebpf" -) - -type PerfGlobalConfigT struct { - BpfLogErr uint8 - BpfLogDebug uint8 - _ [6]byte - NsPidIno uint64 -} - -type PerfLibc struct { - Musl bool - _ [1]byte - PthreadSize int16 - PthreadSpecific1stblock int16 -} - -type PerfPyEvent struct { - K PerfSampleKey - StackLen uint32 - Stack [96]uint32 - _ [4]byte -} - -type PerfPyOffsetConfig struct { - PyThreadStateFrame int16 - PyThreadStateCframe int16 - PyCFrameCurrentFrame int16 - PyCodeObjectCoFilename int16 - PyCodeObjectCoName int16 - PyCodeObjectCoVarnames int16 - PyCodeObjectCoLocalsplusnames int16 - PyCodeObjectCoCell2arg int16 - PyCodeObjectCoCellvars int16 - PyCodeObjectCoNlocals int16 - PyTupleObjectObItem int16 - PyVarObjectObSize int16 - PyObjectObType int16 - PyTypeObjectTpName int16 - VFrameCode int16 - VFramePrevious int16 - VFrameLocalsplus int16 - PyInterpreterFrameOwner int16 - PyASCIIObjectSize int16 - PyCompactUnicodeObjectSize int16 - PyCellObjectObRef int16 - _ [6]byte - Base uint64 - PyCellType uint64 -} - -type PerfPyPidData struct { - Offsets PerfPyOffsetConfig - Version struct { - Major uint32 - Minor uint32 - Patch uint32 - } - Libc PerfLibc - _ [2]byte - TssKey int32 - CollectKernel uint8 - _ [7]byte -} - -type PerfPySampleStateT struct { - SymbolCounter int64 - Offsets PerfPyOffsetConfig - CurCpu uint32 - _ [4]byte - FramePtr uint64 - PythonStackProgCallCnt int64 - Sym PerfPySymbol - Event PerfPyEvent - Padding uint64 -} - -type PerfPyStrType struct { - Type uint8 - SizeCodepoints uint8 -} - -type PerfPySymbol struct { - Classname [32]int8 - Name [64]int8 - File [128]int8 - ClassnameType PerfPyStrType - NameType PerfPyStrType - FileType PerfPyStrType - Padding PerfPyStrType -} - -type PerfSampleKey struct { - Pid uint32 - Flags uint32 - KernStack int64 - UserStack int64 -} - -// LoadPerf returns the embedded CollectionSpec for Perf. -func LoadPerf() (*ebpf.CollectionSpec, error) { - reader := bytes.NewReader(_PerfBytes) - spec, err := ebpf.LoadCollectionSpecFromReader(reader) - if err != nil { - return nil, fmt.Errorf("can't load Perf: %w", err) - } - - return spec, err -} - -// LoadPerfObjects loads Perf and converts it into a struct. -// -// The following types are suitable as obj argument: -// -// *PerfObjects -// *PerfPrograms -// *PerfMaps -// -// See ebpf.CollectionSpec.LoadAndAssign documentation for details. -func LoadPerfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { - spec, err := LoadPerf() - if err != nil { - return err - } - - return spec.LoadAndAssign(obj, opts) -} - -// PerfSpecs contains maps and programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type PerfSpecs struct { - PerfProgramSpecs - PerfMapSpecs -} - -// PerfSpecs contains programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type PerfProgramSpecs struct { - PyperfCollect *ebpf.ProgramSpec `ebpf:"pyperf_collect"` - ReadPythonStack *ebpf.ProgramSpec `ebpf:"read_python_stack"` -} - -// PerfMapSpecs contains maps before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type PerfMapSpecs struct { - Counts *ebpf.MapSpec `ebpf:"counts"` - PyPidConfig *ebpf.MapSpec `ebpf:"py_pid_config"` - PyProgs *ebpf.MapSpec `ebpf:"py_progs"` - PyStateHeap *ebpf.MapSpec `ebpf:"py_state_heap"` - PySymbols *ebpf.MapSpec `ebpf:"py_symbols"` - PythonStacks *ebpf.MapSpec `ebpf:"python_stacks"` - Stacks *ebpf.MapSpec `ebpf:"stacks"` -} - -// PerfObjects contains all objects after they have been loaded into the kernel. -// -// It can be passed to LoadPerfObjects or ebpf.CollectionSpec.LoadAndAssign. -type PerfObjects struct { - PerfPrograms - PerfMaps -} - -func (o *PerfObjects) Close() error { - return _PerfClose( - &o.PerfPrograms, - &o.PerfMaps, - ) -} - -// PerfMaps contains all maps after they have been loaded into the kernel. -// -// It can be passed to LoadPerfObjects or ebpf.CollectionSpec.LoadAndAssign. -type PerfMaps struct { - Counts *ebpf.Map `ebpf:"counts"` - PyPidConfig *ebpf.Map `ebpf:"py_pid_config"` - PyProgs *ebpf.Map `ebpf:"py_progs"` - PyStateHeap *ebpf.Map `ebpf:"py_state_heap"` - PySymbols *ebpf.Map `ebpf:"py_symbols"` - PythonStacks *ebpf.Map `ebpf:"python_stacks"` - Stacks *ebpf.Map `ebpf:"stacks"` -} - -func (m *PerfMaps) Close() error { - return _PerfClose( - m.Counts, - m.PyPidConfig, - m.PyProgs, - m.PyStateHeap, - m.PySymbols, - m.PythonStacks, - m.Stacks, - ) -} - -// PerfPrograms contains all programs after they have been loaded into the kernel. -// -// It can be passed to LoadPerfObjects or ebpf.CollectionSpec.LoadAndAssign. -type PerfPrograms struct { - PyperfCollect *ebpf.Program `ebpf:"pyperf_collect"` - ReadPythonStack *ebpf.Program `ebpf:"read_python_stack"` -} - -func (p *PerfPrograms) Close() error { - return _PerfClose( - p.PyperfCollect, - p.ReadPythonStack, - ) -} - -func _PerfClose(closers ...io.Closer) error { - for _, closer := range closers { - if err := closer.Close(); err != nil { - return err - } - } - return nil -} - -// Do not access this directly. -// -//go:embed perf_bpfel_x86.o -var _PerfBytes []byte diff --git a/ebpf/python/perf_bpfel_x86.o b/ebpf/python/perf_bpfel_x86.o deleted file mode 100644 index 56c0a11154..0000000000 Binary files a/ebpf/python/perf_bpfel_x86.o and /dev/null differ diff --git a/ebpf/python/procinfo.go b/ebpf/python/procinfo.go deleted file mode 100644 index f334cbcab3..0000000000 --- a/ebpf/python/procinfo.go +++ /dev/null @@ -1,72 +0,0 @@ -package python - -import ( - "bufio" - "fmt" - "path/filepath" - "regexp" - "strconv" - "strings" - - "github.com/grafana/pyroscope/ebpf/symtab" -) - -type ProcInfo struct { - Version Version - PythonMaps []*symtab.ProcMap - LibPythonMaps []*symtab.ProcMap - Musl []*symtab.ProcMap - Glibc []*symtab.ProcMap -} - -var rePython = regexp.MustCompile("/.*/((?:lib)?python)(\\d+)\\.(\\d+)(?:[mu]?(-pyston\\d.\\d)?(?:\\.so)?)?(?:.1.0)?$") - -// GetProcInfo parses /proc/pid/map of a python process. -func GetProcInfo(s *bufio.Scanner) (ProcInfo, error) { - res := ProcInfo{} - i := 0 - for s.Scan() { - line := s.Bytes() - m, err := symtab.ParseProcMapLine(line, false) - if err != nil { - return res, err - } - if m.Pathname != "" { - matches := rePython.FindAllStringSubmatch(m.Pathname, -1) - if matches != nil { - if res.Version.Major == 0 { - maj, err := strconv.Atoi(matches[0][2]) - if err != nil { - return res, fmt.Errorf("failed to parse python version %s", m.Pathname) - } - min, err := strconv.Atoi(matches[0][3]) - if err != nil { - return res, fmt.Errorf("failed to parse python version %s", m.Pathname) - } - res.Version.Major = maj - res.Version.Minor = min - } - typ := matches[0][1] - if typ == "python" { - res.PythonMaps = append(res.PythonMaps, m) - } else { - res.LibPythonMaps = append(res.LibPythonMaps, m) - } - - i += 1 - } - - if strings.Contains(m.Pathname, "/lib/ld-musl-x86_64.so.1") || - strings.Contains(m.Pathname, "/lib/ld-musl-aarch64.so.1") { - res.Musl = append(res.Musl, m) - } - if strings.HasSuffix(m.Pathname, "/libc.so.6") || strings.HasPrefix(filepath.Base(m.Pathname), "libc-2.") { - res.Glibc = append(res.Glibc, m) - } - } - } - if res.LibPythonMaps == nil && res.PythonMaps == nil { - return res, fmt.Errorf("no python found") - } - return res, nil -} diff --git a/ebpf/python/procinfo_test.go b/ebpf/python/procinfo_test.go deleted file mode 100644 index 8474ab4bef..0000000000 --- a/ebpf/python/procinfo_test.go +++ /dev/null @@ -1,425 +0,0 @@ -package python - -import ( - "bufio" - "bytes" - "os" - "regexp" - "strconv" - "testing" - - "github.com/grafana/pyroscope/ebpf/testutil" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestPythonProcInfo(t *testing.T) { - var maps string - maps = `55bb7ceb9000-55bb7ceba000 r--p 00000000 fd:01 57017250 /home/korniltsev/.asdf/installs/python/3.6.0/bin/python3.6 -55bb7ceba000-55bb7cebb000 r-xp 00001000 fd:01 57017250 /home/korniltsev/.asdf/installs/python/3.6.0/bin/python3.6 -55bb7cebb000-55bb7cebc000 r--p 00002000 fd:01 57017250 /home/korniltsev/.asdf/installs/python/3.6.0/bin/python3.6 -55bb7cebc000-55bb7cebd000 r--p 00002000 fd:01 57017250 /home/korniltsev/.asdf/installs/python/3.6.0/bin/python3.6 -55bb7cebd000-55bb7cebe000 rw-p 00003000 fd:01 57017250 /home/korniltsev/.asdf/installs/python/3.6.0/bin/python3.6 -55bb7df87000-55bb7e02a000 rw-p 00000000 00:00 0 [heap] -7f94a5c00000-7f94a6180000 r--p 00000000 fd:01 45623802 /usr/lib/locale/locale-archive -7f94a619b000-7f94a6200000 rw-p 00000000 00:00 0 -7f94a6200000-7f94a6222000 r--p 00000000 fd:01 45643280 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f94a6222000-7f94a639a000 r-xp 00022000 fd:01 45643280 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f94a639a000-7f94a63f2000 r--p 0019a000 fd:01 45643280 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f94a63f2000-7f94a63f6000 r--p 001f1000 fd:01 45643280 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f94a63f6000-7f94a63f8000 rw-p 001f5000 fd:01 45643280 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f94a63f8000-7f94a6405000 rw-p 00000000 00:00 0 -7f94a6417000-7f94a6517000 rw-p 00000000 00:00 0 -7f94a6517000-7f94a6525000 r--p 00000000 fd:01 45643925 /usr/lib/x86_64-linux-gnu/libm.so.6 -7f94a6525000-7f94a65a3000 r-xp 0000e000 fd:01 45643925 /usr/lib/x86_64-linux-gnu/libm.so.6 -7f94a65a3000-7f94a65fe000 r--p 0008c000 fd:01 45643925 /usr/lib/x86_64-linux-gnu/libm.so.6 -7f94a65fe000-7f94a65ff000 r--p 000e6000 fd:01 45643925 /usr/lib/x86_64-linux-gnu/libm.so.6 -7f94a65ff000-7f94a6600000 rw-p 000e7000 fd:01 45643925 /usr/lib/x86_64-linux-gnu/libm.so.6 -7f94a6600000-7f94a665c000 r--p 00000000 fd:01 57017251 /home/korniltsev/.asdf/installs/python/3.6.0/lib/libpython3.6m.so.1.0 -7f94a665c000-7f94a67f3000 r-xp 0005c000 fd:01 57017251 /home/korniltsev/.asdf/installs/python/3.6.0/lib/libpython3.6m.so.1.0 -7f94a67f3000-7f94a6886000 r--p 001f3000 fd:01 57017251 /home/korniltsev/.asdf/installs/python/3.6.0/lib/libpython3.6m.so.1.0 -7f94a6886000-7f94a6889000 r--p 00285000 fd:01 57017251 /home/korniltsev/.asdf/installs/python/3.6.0/lib/libpython3.6m.so.1.0 -7f94a6889000-7f94a68ef000 rw-p 00288000 fd:01 57017251 /home/korniltsev/.asdf/installs/python/3.6.0/lib/libpython3.6m.so.1.0 -7f94a68ef000-7f94a6920000 rw-p 00000000 00:00 0 -7f94a693e000-7f94a69c0000 rw-p 00000000 00:00 0 -7f94a69d3000-7f94a69da000 r--s 00000000 fd:01 45645140 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache -7f94a69da000-7f94a69dc000 rw-p 00000000 00:00 0 -7f94a69dc000-7f94a69dd000 r--p 00000000 fd:01 45642507 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f94a69dd000-7f94a6a05000 r-xp 00001000 fd:01 45642507 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f94a6a05000-7f94a6a0f000 r--p 00029000 fd:01 45642507 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f94a6a0f000-7f94a6a11000 r--p 00033000 fd:01 45642507 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f94a6a11000-7f94a6a13000 rw-p 00035000 fd:01 45642507 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7ffc422c4000-7ffc422e6000 rw-p 00000000 00:00 0 [stack] -7ffc423a6000-7ffc423aa000 r--p 00000000 00:00 0 [vvar] -7ffc423aa000-7ffc423ac000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]` - info, err := GetProcInfo(bufio.NewScanner(bytes.NewReader([]byte(maps)))) - require.NoError(t, err) - require.Nil(t, info.Musl) - require.NotNil(t, info.Glibc) - require.Equal(t, info.Version, Version{3, 6, 0}) - require.NotNil(t, info.PythonMaps) - require.NotNil(t, info.LibPythonMaps) - - maps = `55c07863f000-55c078640000 r--p 00000000 00:32 39877587 /usr/bin/python3.11 -55c078640000-55c078641000 r-xp 00001000 00:32 39877587 /usr/bin/python3.11 -55c078641000-55c078642000 r--p 00002000 00:32 39877587 /usr/bin/python3.11 -55c078642000-55c078643000 r--p 00002000 00:32 39877587 /usr/bin/python3.11 -55c078643000-55c078644000 rw-p 00003000 00:32 39877587 /usr/bin/python3.11 -55c079447000-55c079448000 ---p 00000000 00:00 0 [heap] -55c079448000-55c07944a000 rw-p 00000000 00:00 0 [heap] -7f62329de000-7f6232a17000 rw-p 00000000 00:00 0 -7f6232a1e000-7f6232a26000 rw-p 00000000 00:00 0 -7f6232a27000-7f6232b2d000 rw-p 00000000 00:00 0 -7f6232b30000-7f6232b3e000 rw-p 00000000 00:00 0 -7f6232b3f000-7f6232b4a000 rw-p 00000000 00:00 0 -7f6232b4a000-7f6232b4b000 r--p 00000000 00:32 39878051 /usr/lib/python3.11/lib-dynload/_opcode.cpython-311-x86_64-linux-musl.so -7f6232b4b000-7f6232b4c000 r-xp 00001000 00:32 39878051 /usr/lib/python3.11/lib-dynload/_opcode.cpython-311-x86_64-linux-musl.so -7f6232b4c000-7f6232b4d000 r--p 00002000 00:32 39878051 /usr/lib/python3.11/lib-dynload/_opcode.cpython-311-x86_64-linux-musl.so -7f6232b4d000-7f6232b4e000 r--p 00002000 00:32 39878051 /usr/lib/python3.11/lib-dynload/_opcode.cpython-311-x86_64-linux-musl.so -7f6232b4e000-7f6232b4f000 rw-p 00003000 00:32 39878051 /usr/lib/python3.11/lib-dynload/_opcode.cpython-311-x86_64-linux-musl.so -7f6232b4f000-7f6232b95000 rw-p 00000000 00:00 0 -7f6232b96000-7f6232c28000 rw-p 00000000 00:00 0 -7f6232c28000-7f6232c35000 r--p 00000000 00:32 39877572 /usr/lib/libncursesw.so.6.4 -7f6232c35000-7f6232c5f000 r-xp 0000d000 00:32 39877572 /usr/lib/libncursesw.so.6.4 -7f6232c5f000-7f6232c76000 r--p 00037000 00:32 39877572 /usr/lib/libncursesw.so.6.4 -7f6232c76000-7f6232c7b000 r--p 0004d000 00:32 39877572 /usr/lib/libncursesw.so.6.4 -7f6232c7b000-7f6232c7c000 rw-p 00052000 00:32 39877572 /usr/lib/libncursesw.so.6.4 -7f6232c7c000-7f6232c90000 r--p 00000000 00:32 39877577 /usr/lib/libreadline.so.8.2 -7f6232c90000-7f6232cb0000 r-xp 00014000 00:32 39877577 /usr/lib/libreadline.so.8.2 -7f6232cb0000-7f6232cb9000 r--p 00034000 00:32 39877577 /usr/lib/libreadline.so.8.2 -7f6232cb9000-7f6232cbc000 r--p 0003d000 00:32 39877577 /usr/lib/libreadline.so.8.2 -7f6232cbc000-7f6232cc2000 rw-p 00040000 00:32 39877577 /usr/lib/libreadline.so.8.2 -7f6232cc2000-7f6232cc3000 rw-p 00000000 00:00 0 -7f6232cc3000-7f6232cc5000 r--p 00000000 00:32 39878086 /usr/lib/python3.11/lib-dynload/readline.cpython-311-x86_64-linux-musl.so -7f6232cc5000-7f6232cc7000 r-xp 00002000 00:32 39878086 /usr/lib/python3.11/lib-dynload/readline.cpython-311-x86_64-linux-musl.so -7f6232cc7000-7f6232cc9000 r--p 00004000 00:32 39878086 /usr/lib/python3.11/lib-dynload/readline.cpython-311-x86_64-linux-musl.so -7f6232cc9000-7f6232cca000 r--p 00006000 00:32 39878086 /usr/lib/python3.11/lib-dynload/readline.cpython-311-x86_64-linux-musl.so -7f6232cca000-7f6232ccb000 rw-p 00007000 00:32 39878086 /usr/lib/python3.11/lib-dynload/readline.cpython-311-x86_64-linux-musl.so -7f6232ccb000-7f6232dd4000 rw-p 00000000 00:00 0 -7f6232dd5000-7f6232faa000 rw-p 00000000 00:00 0 -7f6232faa000-7f6233016000 r--p 00000000 00:32 39877591 /usr/lib/libpython3.11.so.1.0 -7f6233016000-7f62331f8000 r-xp 0006c000 00:32 39877591 /usr/lib/libpython3.11.so.1.0 -7f62331f8000-7f62332e2000 r--p 0024e000 00:32 39877591 /usr/lib/libpython3.11.so.1.0 -7f62332e2000-7f6233311000 r--p 00338000 00:32 39877591 /usr/lib/libpython3.11.so.1.0 -7f6233311000-7f6233441000 rw-p 00367000 00:32 39877591 /usr/lib/libpython3.11.so.1.0 -7f6233441000-7f6233483000 rw-p 00000000 00:00 0 -7f6233483000-7f6233497000 r--p 00000000 00:32 39877100 /lib/ld-musl-x86_64.so.1 -7f6233497000-7f62334e3000 r-xp 00014000 00:32 39877100 /lib/ld-musl-x86_64.so.1 -7f62334e3000-7f6233519000 r--p 00060000 00:32 39877100 /lib/ld-musl-x86_64.so.1 -7f6233519000-7f623351a000 r--p 00095000 00:32 39877100 /lib/ld-musl-x86_64.so.1 -7f623351a000-7f623351b000 rw-p 00096000 00:32 39877100 /lib/ld-musl-x86_64.so.1 -7f623351b000-7f623351e000 rw-p 00000000 00:00 0 -7ffeabbad000-7ffeabbce000 rw-p 00000000 00:00 0 [stack] -7ffeabbe1000-7ffeabbe5000 r--p 00000000 00:00 0 [vvar] -7ffeabbe5000-7ffeabbe7000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]` - info, err = GetProcInfo(bufio.NewScanner(bytes.NewReader([]byte(maps)))) - require.NoError(t, err) - require.NotNil(t, info.Musl) - require.Nil(t, info.Glibc) - require.Equal(t, info.Version, Version{3, 11, 0}) - require.NotNil(t, info.PythonMaps) - require.NotNil(t, info.LibPythonMaps) - - maps = `00400000-006d8000 r-xp 00000000 08:01 2278062 /opt/splunk/bin/python3.7m -006d8000-006d9000 r--p 002d7000 08:01 2278062 /opt/splunk/bin/python3.7m -006d9000-00742000 rw-p 002d8000 08:01 2278062 /opt/splunk/bin/python3.7m -00742000-00762000 rw-p 00000000 00:00 0 -02067000-02966000 rw-p 00000000 00:00 0 [heap]` - info, err = GetProcInfo(bufio.NewScanner(bytes.NewReader([]byte(maps)))) - require.NoError(t, err) - require.Nil(t, info.Musl) - require.Nil(t, info.Glibc) - require.Equal(t, info.Version, Version{3, 7, 0}) - require.NotNil(t, info.PythonMaps) - require.Nil(t, info.LibPythonMaps) - - maps = `aaaae1f10000-aaaae2040000 r-xp 00000000 103:01 980158 /usr/bin/uwsgi -aaaae204f000-aaaae2052000 r--p 0012f000 103:01 980158 /usr/bin/uwsgi -aaaae2052000-aaaae2065000 rw-p 00132000 103:01 980158 /usr/bin/uwsgi -aaaae2065000-aaaae206c000 rw-p 00000000 00:00 0 -aaaaeb0dc000-aaaaef082000 rw-p 00000000 00:00 0 [heap] -aaaaef082000-aaaaf6ad7000 rw-p 00000000 00:00 0 [heap] -ffffa259d000-ffffa25a1000 rw-p 00000000 00:00 0 -ffffa25a1000-ffffa26fc000 r-xp 00000000 103:01 831681 /usr/lib/aarch64-linux-gnu/libc-2.31.so -ffffa26fc000-ffffa270b000 ---p 0015b000 103:01 831681 /usr/lib/aarch64-linux-gnu/libc-2.31.so -ffffa270b000-ffffa270f000 r--p 0015a000 103:01 831681 /usr/lib/aarch64-linux-gnu/libc-2.31.so -ffffa270f000-ffffa2711000 rw-p 0015e000 103:01 831681 /usr/lib/aarch64-linux-gnu/libc-2.31.so -ffffa2711000-ffffa2714000 rw-p 00000000 00:00 0 -ffffa2714000-ffffa2b35000 r-xp 00000000 103:01 836228 /usr/lib/libpython3.8-pyston2.3.so.1.0 -ffffa2b35000-ffffa2b45000 ---p 00421000 103:01 836228 /usr/lib/libpython3.8-pyston2.3.so.1.0 -ffffa2b45000-ffffa2b4c000 r--p 00421000 103:01 836228 /usr/lib/libpython3.8-pyston2.3.so.1.0 -ffffa2b4c000-ffffa2b83000 rw-p 00428000 103:01 836228 /usr/lib/libpython3.8-pyston2.3.so.1.0 -ffffa2b83000-ffffa2ba4000 rw-p 00000000 00:00 0 -ffffa32a1000-ffffa32a3000 r--p 00000000 00:00 0 [vvar] -ffffa32a3000-ffffa32a4000 r-xp 00000000 00:00 0 [vdso] -ffffa32a4000-ffffa32a5000 r--p 00021000 103:01 836208 /usr/lib/ld-linux-aarch64.so.1 -ffffa32a5000-ffffa32a7000 rw-p 00022000 103:01 836208 /usr/lib/ld-linux-aarch64.so.1 -ffffa4126000-ffffa45e6000 rwxp 00000000 00:00 0 -ffffa45e6000-ffffa52e6000 rwxp 00000000 00:00 0 -fffff8c25000-fffff8c53000 rw-p 00000000 00:00 0 [stack]` - - info, err = GetProcInfo(bufio.NewScanner(bytes.NewReader([]byte(maps)))) - require.NoError(t, err) - require.Nil(t, info.Musl) - require.NotNil(t, info.Glibc) - require.Equal(t, info.Version, Version{3, 8, 0}) - require.Nil(t, info.PythonMaps) - require.NotNil(t, info.LibPythonMaps) -} - -const testdataPath = "../testdata/" - -func TestMusl(t *testing.T) { - testutil.InitGitSubmodule(t) - testcases := []struct { - path string - version Version - }{ - {testdataPath + "./alpine-arm64/3.8/lib/ld-musl-aarch64.so.1", Version{1, 1, 19}}, - {testdataPath + "./alpine-arm64/3.11/lib/ld-musl-aarch64.so.1", Version{1, 1, 24}}, - {testdataPath + "./alpine-arm64/3.9/lib/ld-musl-aarch64.so.1", Version{1, 1, 20}}, - {testdataPath + "./alpine-arm64/3.12/lib/ld-musl-aarch64.so.1", Version{1, 1, 24}}, - {testdataPath + "./alpine-arm64/3.10/lib/ld-musl-aarch64.so.1", Version{1, 1, 22}}, - {testdataPath + "./alpine-arm64/3.15/lib/ld-musl-aarch64.so.1", Version{1, 2, 2}}, - {testdataPath + "./alpine-arm64/3.13/lib/ld-musl-aarch64.so.1", Version{1, 2, 2}}, - {testdataPath + "./alpine-arm64/3.17/lib/ld-musl-aarch64.so.1", Version{1, 2, 3}}, - {testdataPath + "./alpine-arm64/3.16/lib/ld-musl-aarch64.so.1", Version{1, 2, 3}}, - {testdataPath + "./alpine-arm64/3.18/lib/ld-musl-aarch64.so.1", Version{1, 2, 4}}, - {testdataPath + "./alpine-arm64/3.14/lib/ld-musl-aarch64.so.1", Version{1, 2, 2}}, - {testdataPath + "./alpine-amd64/3.8/lib/ld-musl-x86_64.so.1", Version{1, 1, 19}}, - {testdataPath + "./alpine-amd64/3.11/lib/ld-musl-x86_64.so.1", Version{1, 1, 24}}, - {testdataPath + "./alpine-amd64/3.9/lib/ld-musl-x86_64.so.1", Version{1, 1, 20}}, - {testdataPath + "./alpine-amd64/3.12/lib/ld-musl-x86_64.so.1", Version{1, 1, 24}}, - {testdataPath + "./alpine-amd64/3.10/lib/ld-musl-x86_64.so.1", Version{1, 1, 22}}, - {testdataPath + "./alpine-amd64/3.15/lib/ld-musl-x86_64.so.1", Version{1, 2, 2}}, - {testdataPath + "./alpine-amd64/3.13/lib/ld-musl-x86_64.so.1", Version{1, 2, 2}}, - {testdataPath + "./alpine-amd64/3.17/lib/ld-musl-x86_64.so.1", Version{1, 2, 3}}, - {testdataPath + "./alpine-amd64/3.16/lib/ld-musl-x86_64.so.1", Version{1, 2, 3}}, - {testdataPath + "./alpine-amd64/3.18/lib/ld-musl-x86_64.so.1", Version{1, 2, 4}}, - {testdataPath + "./alpine-amd64/3.14/lib/ld-musl-x86_64.so.1", Version{1, 2, 2}}, - } - for _, td := range testcases { - version, err := GetMuslVersionFromFile(td.path) - require.NoError(t, err) - assert.Equal(t, td.version, version) - } -} - -func TestPython(t *testing.T) { - testutil.InitGitSubmodule(t) - fs := []string{ - testdataPath + "python-x64/3.7.12/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.9.15/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.8.0/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.7.0/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.8.2/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.8.9/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.10.6/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.9.0/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.8.17/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.9.12/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.6.9/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.15/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.11.0/lib/libpython3.11.so.1.0", - testdataPath + "python-x64/3.6.7/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.4/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.8.15/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.7.9/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.11.3/lib/libpython3.11.so.1.0", - testdataPath + "python-x64/3.7.3/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.8.4/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.8.5/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.7.7/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.11.2/lib/libpython3.11.so.1.0", - testdataPath + "python-x64/3.9.2/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.6.15/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.17/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.7.14/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.9.4/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.6.4/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.10.4/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.10.3/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.10.10/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.6.13/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.10.12/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.9.6/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.9.7/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.11.1/lib/libpython3.11.so.1.0", - testdataPath + "python-x64/3.10.1/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.8.6/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.9.8/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.10.8/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.9.14/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.7.11/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.6.5/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.13/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.7.10/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.9.17/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.9.9/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.6.14/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.8.12/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.10.5/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.10.7/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.8.8/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.8.13/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.6.10/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.9.5/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.8.16/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.6.12/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.9.10/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.10.11/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.7.2/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.7.1/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.10.9/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.10.2/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.9.16/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.9.13/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.6.8/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.8.14/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.8.3/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.6.3/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.9.1/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.6.1/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.6/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.6.0/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.5/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.8.1/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.6.11/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.8/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.6.2/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.7.16/lib/libpython3.7m.so.1.0", - testdataPath + "python-x64/3.8.7/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.11.4/lib/libpython3.11.so.1.0", - testdataPath + "python-x64/3.9.11/lib/libpython3.9.so.1.0", - testdataPath + "python-x64/3.10.0/lib/libpython3.10.so.1.0", - testdataPath + "python-x64/3.6.6/lib/libpython3.6m.so.1.0", - testdataPath + "python-x64/3.8.11/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.8.10/lib/libpython3.8.so.1.0", - testdataPath + "python-x64/3.8.12/lib/libpython3.8-pyston2.3.so.1.0", - testdataPath + "python-x64/3.13.0a6/libpython3.13.so.1.0", - testdataPath + "python-arm64/3.7.12/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.5.1/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.9.15/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.8.0/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.7.0/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.8.2/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.8.9/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.5.8/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.5.2/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.10.6/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.9.0/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.8.17/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.9.12/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.6.9/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.7.15/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.11.0/lib/libpython3.11.so.1.0", - testdataPath + "python-arm64/3.6.7/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.9.18/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.7.4/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.8.15/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.7.9/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.11.3/lib/libpython3.11.so.1.0", - testdataPath + "python-arm64/3.7.3/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.8.4/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.8.5/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.7.7/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.11.2/lib/libpython3.11.so.1.0", - testdataPath + "python-arm64/3.9.2/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.6.15/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.5.4/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.11.6/lib/libpython3.11.so.1.0", - testdataPath + "python-arm64/3.7.17/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.7.14/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.9.4/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.6.4/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.10.4/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.5.10/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.10.3/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.10.10/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.6.13/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.5.9/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.10.12/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.9.6/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.5.7/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.9.7/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.11.1/lib/libpython3.11.so.1.0", - testdataPath + "python-arm64/3.10.1/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.8.6/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.5.3/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.9.8/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.10.8/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.13.0a6/libpython3.13.so.1.0", - testdataPath + "python-arm64/3.9.14/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.7.11/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.6.5/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.7.13/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.7.10/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.9.17/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.9.9/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.8.18/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.6.14/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.8.12/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.10.5/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.10.7/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.8.8/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.8.13/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.6.10/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.9.5/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.8.16/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.6.12/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.9.10/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.10.11/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.7.2/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.7.1/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.10.9/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.10.2/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.10.13/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.9.16/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.9.13/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.6.8/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.5.0/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.8.14/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.5.5/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.8.3/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.6.3/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.9.1/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.12.0/lib/libpython3.12.so.1.0", - testdataPath + "python-arm64/3.6.1/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.7.6/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.6.0/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.7.5/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.8.1/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.6.11/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.7.8/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.6.2/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.7.16/lib/libpython3.7m.so.1.0", - testdataPath + "python-arm64/3.11.5/lib/libpython3.11.so.1.0", - testdataPath + "python-arm64/3.8.7/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.11.4/lib/libpython3.11.so.1.0", - testdataPath + "python-arm64/3.9.11/lib/libpython3.9.so.1.0", - testdataPath + "python-arm64/3.5.6/lib/libpython3.5m.so.1.0", - testdataPath + "python-arm64/3.10.0/lib/libpython3.10.so.1.0", - testdataPath + "python-arm64/3.6.6/lib/libpython3.6m.so.1.0", - testdataPath + "python-arm64/3.8.11/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.8.10/lib/libpython3.8.so.1.0", - testdataPath + "python-arm64/3.8.12/lib/libpython3.8-pyston2.3.so.1.0", - } - for _, f := range fs { - t.Run(f, func(t *testing.T) { - re := regexp.MustCompile("(\\d+)\\.(\\d+)\\.(\\d+)") - m := re.FindStringSubmatch(f) - require.NotNil(t, m) - major, _ := strconv.Atoi(m[1]) - minor, _ := strconv.Atoi(m[2]) - patch, _ := strconv.Atoi(m[3]) - - fd, err := os.Open(f) - require.NoError(t, err) - version, err := GetPythonPatchVersion(fd, Version{major, minor, 0}) - require.NoError(t, err) - require.Equal(t, version.Patch, patch) - }) - } -} diff --git a/ebpf/python/pyperf.go b/ebpf/python/pyperf.go deleted file mode 100644 index 530ef4b901..0000000000 --- a/ebpf/python/pyperf.go +++ /dev/null @@ -1,193 +0,0 @@ -package python - -import ( - "errors" - "fmt" - "sync" - - "github.com/cilium/ebpf" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/grafana/pyroscope/ebpf/symtab" -) - -type Perf struct { - logger log.Logger - pidDataHashMap *ebpf.Map - symbolsHashMp *ebpf.Map - metrics *metrics.PythonMetrics - - events []*PerfPyEvent - eventsLock sync.Mutex - sc *symtab.SymbolCache - pidCache map[uint32]*Proc - prevSymbols map[uint32]*PerfPySymbol -} - -type Proc struct { // consider merging with symtab.ProcTable - PerfPyPidData *PerfPyPidData - SymbolOptions *symtab.SymbolOptions -} - -func NewPerf(logger log.Logger, metrics *metrics.PythonMetrics, pidDataHasMap *ebpf.Map, symbolsHashMap *ebpf.Map) (*Perf, error) { - pidCache := make(map[uint32]*Proc) - res := &Perf{ - logger: logger, - pidDataHashMap: pidDataHasMap, - symbolsHashMp: symbolsHashMap, - pidCache: pidCache, - metrics: metrics, - } - return res, nil -} - -func (s *Perf) FindProc(pid uint32) *Proc { - return s.pidCache[pid] -} - -func (s *Perf) NewProc(pid uint32, data *PerfPyPidData, options *symtab.SymbolOptions, serviceName string) (*Proc, error) { - prev := s.pidCache[pid] - if prev != nil { - return prev, nil - } - - err := s.pidDataHashMap.Update(pid, data, ebpf.UpdateAny) - if err != nil { // should never happen - return nil, fmt.Errorf("updating pid data hash map: %w", err) - } - s.metrics.ProcessInitSuccess.WithLabelValues(serviceName).Inc() - n := &Proc{ - PerfPyPidData: data, - SymbolOptions: options, - } - s.pidCache[pid] = n - return n, nil -} - -func (s *Perf) CollectEvents(buf []*PerfPyEvent) []*PerfPyEvent { - buf = buf[:0] - s.eventsLock.Lock() - defer s.eventsLock.Unlock() - if len(s.events) == 0 { - return buf - } - if len(s.events) > cap(buf) { - buf = make([]*PerfPyEvent, len(s.events)) - } else { - buf = buf[:len(s.events)] - } - copy(buf, s.events) - for i := range s.events { - s.events[i] = nil - } - s.events = s.events[:0] - - return buf -} - -func (s *Perf) GetLazySymbols() *LazySymbols { - return &LazySymbols{ - symbols: s.prevSymbols, - fresh: false, - perf: s, - } -} - -func (s *Perf) GetSymbols(svcReason string) (map[uint32]*PerfPySymbol, error) { - s.metrics.SymbolLookup.WithLabelValues(svcReason).Inc() - var ( - m = s.symbolsHashMp - mapSize = m.MaxEntries() - nextKey = PerfPySymbol{} - ) - keys := make([]PerfPySymbol, mapSize) - values := make([]uint32, mapSize) - res := make(map[uint32]*PerfPySymbol) - opts := &ebpf.BatchOptions{} - n, err := m.BatchLookup(nil, &nextKey, keys, values, opts) - if n > 0 { - level.Debug(s.logger).Log( - "msg", "GetSymbols BatchLookup", - "count", n, - ) - res := make(map[uint32]*PerfPySymbol, n) - for i := 0; i < n; i++ { - k := values[i] - res[k] = &keys[i] - } - s.prevSymbols = res - return res, nil - } - if errors.Is(err, ebpf.ErrKeyNotExist) { - return nil, nil - } - // batch not supported - - // try iterating if batch failed - it := m.Iterate() - - v := uint32(0) - for { - k := new(PerfPySymbol) - ok := it.Next(k, &v) - if !ok { - err := it.Err() - if err != nil { - err = fmt.Errorf("map %s iteration : %w", m.String(), err) - return nil, err - } - break - } - res[v] = k - } - level.Debug(s.logger).Log( - "msg", "GetSymbols iter", - "count", len(res), - ) - s.prevSymbols = res - return res, nil -} - -func (s *Perf) RemoveDeadPID(pid uint32) { - delete(s.pidCache, pid) - err := s.pidDataHashMap.Delete(pid) - if err != nil && !errors.Is(err, ebpf.ErrKeyNotExist) { - _ = level.Error(s.logger).Log("msg", "[pyperf] deleting pid data hash map", "err", err) - } -} - -// LazySymbols tries to reuse a map from previous profile collection. -// If found a new symbols, then full dump ( GetSymbols ) is performed. -type LazySymbols struct { - perf *Perf - symbols map[uint32]*PerfPySymbol - fresh bool -} - -func (s *LazySymbols) GetSymbol(symID uint32, svc string) (*PerfPySymbol, error) { - symbol, ok := s.symbols[symID] - if ok { - return symbol, nil - } - return s.getSymbol(symID, svc) - -} - -func (s *LazySymbols) getSymbol(id uint32, svc string) (*PerfPySymbol, error) { - if s.fresh { - return nil, fmt.Errorf("symbol %d not found", id) - } - // make it fresh - symbols, err := s.perf.GetSymbols(svc) - if err != nil { - return nil, fmt.Errorf("symbols refresh failed: %w", err) - } - s.symbols = symbols - s.fresh = true - symbol, ok := symbols[id] - if ok { - return symbol, nil - } - return nil, fmt.Errorf("symbol %d not found", id) -} diff --git a/ebpf/python/pyperf_pid_data.go b/ebpf/python/pyperf_pid_data.go deleted file mode 100644 index e59f262de6..0000000000 --- a/ebpf/python/pyperf_pid_data.go +++ /dev/null @@ -1,160 +0,0 @@ -package python - -import ( - "bufio" - "debug/elf" - "fmt" - "os" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/symtab" -) - -func GetPyPerfPidData(l log.Logger, pid uint32, collectKernel bool) (*PerfPyPidData, error) { - mapsFD, err := os.Open(fmt.Sprintf("/proc/%d/maps", pid)) - if err != nil { - return nil, fmt.Errorf("reading proc maps %d: %w", pid, err) - } - defer mapsFD.Close() - - info, err := GetProcInfo(bufio.NewScanner(mapsFD)) - - if err != nil { - return nil, fmt.Errorf("GetPythonProcInfo error %s: %w", fmt.Sprintf("/proc/%d/maps", pid), err) - } - var pythonMeat []*symtab.ProcMap - if info.LibPythonMaps == nil { - pythonMeat = info.PythonMaps - } else { - pythonMeat = info.LibPythonMaps - } - base_ := pythonMeat[0] - pythonPath := fmt.Sprintf("/proc/%d/root%s", pid, base_.Pathname) - pythonFD, err := os.Open(pythonPath) - if err != nil { - return nil, fmt.Errorf("could not open python path %s %w", pythonPath, err) - } - defer pythonFD.Close() - version, err := GetPythonPatchVersion(pythonFD, info.Version) - if err != nil { - return nil, fmt.Errorf("could not get python patch version %s %w", pythonPath, err) - } - - offsets, guess, err := GetUserOffsets(version) - if err != nil { - return nil, fmt.Errorf("unsupported python version %w %+v", err, version) - } - if guess { - level.Warn(l).Log("msg", "python offsets were not found, but guessed from the closest patch version") - } - - ef, err := elf.NewFile(pythonFD) - if err != nil { - return nil, fmt.Errorf("opening elf %s: %w", pythonPath, err) - } - symbols, err := ef.DynamicSymbols() - if err != nil { - return nil, fmt.Errorf("reading symbols from elf %s: %w", pythonPath, err) - } - - data := &PerfPyPidData{} - var ( - autoTLSkeyAddr, pyRuntimeAddr, PyCellType uint64 - ) - baseAddr := base_.StartAddr - if ef.FileHeader.Type == elf.ET_EXEC { - baseAddr = 0 - } - for _, symbol := range symbols { - switch symbol.Name { - case "autoTLSkey": - autoTLSkeyAddr = baseAddr + symbol.Value - case "_PyRuntime": - pyRuntimeAddr = baseAddr + symbol.Value - case "PyCell_Type": - PyCellType = baseAddr + symbol.Value - default: - continue - } - } - if pyRuntimeAddr == 0 && autoTLSkeyAddr == 0 { - return nil, fmt.Errorf("missing symbols pyRuntimeAddr autoTLSkeyAddr %s %v", pythonPath, version) - } - - data.Version.Major = uint32(version.Major) - data.Version.Minor = uint32(version.Minor) - data.Version.Patch = uint32(version.Patch) - data.Libc, err = GetLibc(l, pid, info) - if err != nil { - return nil, fmt.Errorf("failed to get python process libc %w", err) - } - data.TssKey, err = GetTSSKey(pid, version, offsets, autoTLSkeyAddr, pyRuntimeAddr, &data.Libc) - if err != nil { - return nil, fmt.Errorf("failed to get python tss key %w", err) - } - - var vframeCode, vframeBack, vframeLocalPlus int16 - if version.Compare(Py311) >= 0 { - if version.Compare(Py313) >= 0 { - vframeCode = offsets.PyInterpreterFrame_f_executable - } else { - vframeCode = offsets.PyInterpreterFrame_f_code - } - vframeBack = offsets.PyInterpreterFrame_previous - vframeLocalPlus = offsets.PyInterpreterFrame_localsplus - } else { - vframeCode = offsets.PyFrameObject_f_code - vframeBack = offsets.PyFrameObject_f_back - vframeLocalPlus = offsets.PyFrameObject_f_localsplus - } - if vframeCode == -1 || vframeBack == -1 || vframeLocalPlus == -1 { - return nil, fmt.Errorf("broken offsets %+v %+v", offsets, version) - } - - cframe := offsets.PyThreadState_cframe - currentFrame := offsets.PyCFrame_current_frame - frame := offsets.PyThreadState_frame - if version.Compare(Py313) >= 0 { - if cframe != -1 || currentFrame != -1 || frame != -1 { - return nil, fmt.Errorf("broken offsets %+v %+v", offsets, version) - } - // PyCFrame was removed in 3.13, lets pretend it was never there and frame field was just renamed to current_frame - frame = offsets.PyThreadState_current_frame - if frame == -1 { - return nil, fmt.Errorf("broken offsets %+v %+v", offsets, version) - } - } - - data.Offsets = PerfPyOffsetConfig{ - PyThreadStateFrame: frame, - PyThreadStateCframe: cframe, - PyCFrameCurrentFrame: currentFrame, - PyCodeObjectCoFilename: offsets.PyCodeObject_co_filename, - PyCodeObjectCoName: offsets.PyCodeObject_co_name, - PyCodeObjectCoVarnames: offsets.PyCodeObject_co_varnames, - PyCodeObjectCoLocalsplusnames: offsets.PyCodeObject_co_localsplusnames, - PyCodeObjectCoCell2arg: offsets.PyCodeObject__co_cell2arg, - PyCodeObjectCoCellvars: offsets.PyCodeObject__co_cellvars, - PyCodeObjectCoNlocals: offsets.PyCodeObject__co_nlocals, - PyTupleObjectObItem: offsets.PyTupleObject_ob_item, - VFrameCode: vframeCode, - VFramePrevious: vframeBack, - VFrameLocalsplus: vframeLocalPlus, - PyInterpreterFrameOwner: offsets.PyInterpreterFrame_owner, - PyASCIIObjectSize: offsets.PyASCIIObjectSize, - PyCompactUnicodeObjectSize: offsets.PyCompactUnicodeObjectSize, - PyVarObjectObSize: offsets.PyVarObject_ob_size, - PyObjectObType: offsets.PyObject_ob_type, - PyTypeObjectTpName: offsets.PyTypeObject_tp_name, - PyCellObjectObRef: offsets.PyCellObject__ob_ref, - Base: baseAddr, - PyCellType: PyCellType, - } - if collectKernel { - data.CollectKernel = 1 - } else { - data.CollectKernel = 0 - } - return data, nil -} diff --git a/ebpf/python/python_offsets_gen_amd64.go b/ebpf/python/python_offsets_gen_amd64.go deleted file mode 100644 index 806ee6681d..0000000000 --- a/ebpf/python/python_offsets_gen_amd64.go +++ /dev/null @@ -1,3822 +0,0 @@ -//go:build amd64 && linux - -// Code generated by python_dwarfdump. DO NOT EDIT. -package python - -var pyVersions = map[Version]*UserOffsets{ - // 3.5.0 testdata/python-x64/3.5.0/lib/libpython3.5m.so.1.0 - {3, 5, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.1 testdata/python-x64/3.5.1/lib/libpython3.5m.so.1.0 - {3, 5, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.2 testdata/python-x64/3.5.2/lib/libpython3.5m.so.1.0 - {3, 5, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.3 testdata/python-x64/3.5.3/lib/libpython3.5m.so.1.0 - {3, 5, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.4 testdata/python-x64/3.5.4/lib/libpython3.5m.so.1.0 - {3, 5, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.5 testdata/python-x64/3.5.5/lib/libpython3.5m.so.1.0 - {3, 5, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.6 testdata/python-x64/3.5.6/lib/libpython3.5m.so.1.0 - {3, 5, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.7 testdata/python-x64/3.5.7/lib/libpython3.5m.so.1.0 - {3, 5, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.8 testdata/python-x64/3.5.8/lib/libpython3.5m.so.1.0 - {3, 5, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.9 testdata/python-x64/3.5.9/lib/libpython3.5m.so.1.0 - {3, 5, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.10 testdata/python-x64/3.5.10/lib/libpython3.5m.so.1.0 - {3, 5, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.0 testdata/python-x64/3.6.0/lib/libpython3.6m.so.1.0 - {3, 6, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.1 testdata/python-x64/3.6.1/lib/libpython3.6m.so.1.0 - {3, 6, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.2 testdata/python-x64/3.6.2/lib/libpython3.6m.so.1.0 - {3, 6, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.3 testdata/python-x64/3.6.3/lib/libpython3.6m.so.1.0 - {3, 6, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.4 testdata/python-x64/3.6.4/lib/libpython3.6m.so.1.0 - {3, 6, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.5 testdata/python-x64/3.6.5/lib/libpython3.6m.so.1.0 - {3, 6, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.6 testdata/python-x64/3.6.6/lib/libpython3.6m.so.1.0 - {3, 6, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.7 testdata/python-x64/3.6.7/lib/libpython3.6m.so.1.0 - {3, 6, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.8 testdata/python-x64/3.6.8/lib/libpython3.6m.so.1.0 - {3, 6, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.9 testdata/python-x64/3.6.9/lib/libpython3.6m.so.1.0 - {3, 6, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.10 testdata/python-x64/3.6.10/lib/libpython3.6m.so.1.0 - {3, 6, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.11 testdata/python-x64/3.6.11/lib/libpython3.6m.so.1.0 - {3, 6, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.12 testdata/python-x64/3.6.12/lib/libpython3.6m.so.1.0 - {3, 6, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.13 testdata/python-x64/3.6.13/lib/libpython3.6m.so.1.0 - {3, 6, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.14 testdata/python-x64/3.6.14/lib/libpython3.6m.so.1.0 - {3, 6, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.15 testdata/python-x64/3.6.15/lib/libpython3.6m.so.1.0 - {3, 6, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.0 testdata/python-x64/3.7.0/lib/libpython3.7m.so.1.0 - {3, 7, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1384, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.1 testdata/python-x64/3.7.1/lib/libpython3.7m.so.1.0 - {3, 7, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1384, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.2 testdata/python-x64/3.7.2/lib/libpython3.7m.so.1.0 - {3, 7, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1384, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.3 testdata/python-x64/3.7.3/lib/libpython3.7m.so.1.0 - {3, 7, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1384, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.4 testdata/python-x64/3.7.4/lib/libpython3.7m.so.1.0 - {3, 7, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.5 testdata/python-x64/3.7.5/lib/libpython3.7m.so.1.0 - {3, 7, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.6 testdata/python-x64/3.7.6/lib/libpython3.7m.so.1.0 - {3, 7, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.7 testdata/python-x64/3.7.7/lib/libpython3.7m.so.1.0 - {3, 7, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.8 testdata/python-x64/3.7.8/lib/libpython3.7m.so.1.0 - {3, 7, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.9 testdata/python-x64/3.7.9/lib/libpython3.7m.so.1.0 - {3, 7, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.10 testdata/python-x64/3.7.10/lib/libpython3.7m.so.1.0 - {3, 7, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.11 testdata/python-x64/3.7.11/lib/libpython3.7m.so.1.0 - {3, 7, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.12 testdata/python-x64/3.7.12/lib/libpython3.7m.so.1.0 - {3, 7, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.13 testdata/python-x64/3.7.13/lib/libpython3.7m.so.1.0 - {3, 7, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.14 testdata/python-x64/3.7.14/lib/libpython3.7m.so.1.0 - {3, 7, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.15 testdata/python-x64/3.7.15/lib/libpython3.7m.so.1.0 - {3, 7, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.16 testdata/python-x64/3.7.16/lib/libpython3.7m.so.1.0 - {3, 7, 16}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.17 testdata/python-x64/3.7.17/lib/libpython3.7m.so.1.0 - {3, 7, 17}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1472, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.0 testdata/python-x64/3.8.0/lib/libpython3.8.so.1.0 - {3, 8, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.1 testdata/python-x64/3.8.1/lib/libpython3.8.so.1.0 - {3, 8, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.2 testdata/python-x64/3.8.2/lib/libpython3.8.so.1.0 - {3, 8, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.3 testdata/python-x64/3.8.3/lib/libpython3.8.so.1.0 - {3, 8, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.4 testdata/python-x64/3.8.4/lib/libpython3.8.so.1.0 - {3, 8, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.5 testdata/python-x64/3.8.5/lib/libpython3.8.so.1.0 - {3, 8, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.6 testdata/python-x64/3.8.6/lib/libpython3.8.so.1.0 - {3, 8, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.7 testdata/python-x64/3.8.7/lib/libpython3.8.so.1.0 - {3, 8, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.8 testdata/python-x64/3.8.8/lib/libpython3.8.so.1.0 - {3, 8, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.9 testdata/python-x64/3.8.9/lib/libpython3.8.so.1.0 - {3, 8, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.10 testdata/python-x64/3.8.10/lib/libpython3.8.so.1.0 - {3, 8, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.11 testdata/python-x64/3.8.11/lib/libpython3.8.so.1.0 - {3, 8, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.12 testdata/python-x64/3.8.12/lib/libpython3.8.so.1.0 - {3, 8, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.13 testdata/python-x64/3.8.13/lib/libpython3.8.so.1.0 - {3, 8, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.14 testdata/python-x64/3.8.14/lib/libpython3.8.so.1.0 - {3, 8, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.15 testdata/python-x64/3.8.15/lib/libpython3.8.so.1.0 - {3, 8, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.16 testdata/python-x64/3.8.16/lib/libpython3.8.so.1.0 - {3, 8, 16}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.17 testdata/python-x64/3.8.17/lib/libpython3.8.so.1.0 - {3, 8, 17}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.18 testdata/python-x64/3.8.18/lib/libpython3.8.so.1.0 - {3, 8, 18}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1360, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.0 testdata/python-x64/3.9.0/lib/libpython3.9.so.1.0 - {3, 9, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.1 testdata/python-x64/3.9.1/lib/libpython3.9.so.1.0 - {3, 9, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.2 testdata/python-x64/3.9.2/lib/libpython3.9.so.1.0 - {3, 9, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.4 testdata/python-x64/3.9.4/lib/libpython3.9.so.1.0 - {3, 9, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.5 testdata/python-x64/3.9.5/lib/libpython3.9.so.1.0 - {3, 9, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.6 testdata/python-x64/3.9.6/lib/libpython3.9.so.1.0 - {3, 9, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.7 testdata/python-x64/3.9.7/lib/libpython3.9.so.1.0 - {3, 9, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.8 testdata/python-x64/3.9.8/lib/libpython3.9.so.1.0 - {3, 9, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.9 testdata/python-x64/3.9.9/lib/libpython3.9.so.1.0 - {3, 9, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.10 testdata/python-x64/3.9.10/lib/libpython3.9.so.1.0 - {3, 9, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.11 testdata/python-x64/3.9.11/lib/libpython3.9.so.1.0 - {3, 9, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.12 testdata/python-x64/3.9.12/lib/libpython3.9.so.1.0 - {3, 9, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.13 testdata/python-x64/3.9.13/lib/libpython3.9.so.1.0 - {3, 9, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.14 testdata/python-x64/3.9.14/lib/libpython3.9.so.1.0 - {3, 9, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.15 testdata/python-x64/3.9.15/lib/libpython3.9.so.1.0 - {3, 9, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.16 testdata/python-x64/3.9.16/lib/libpython3.9.so.1.0 - {3, 9, 16}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.17 testdata/python-x64/3.9.17/lib/libpython3.9.so.1.0 - {3, 9, 17}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.18 testdata/python-x64/3.9.18/lib/libpython3.9.so.1.0 - {3, 9, 18}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.0 testdata/python-x64/3.10.0/lib/libpython3.10.so.1.0 - {3, 10, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.1 testdata/python-x64/3.10.1/lib/libpython3.10.so.1.0 - {3, 10, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.2 testdata/python-x64/3.10.2/lib/libpython3.10.so.1.0 - {3, 10, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.3 testdata/python-x64/3.10.3/lib/libpython3.10.so.1.0 - {3, 10, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.4 testdata/python-x64/3.10.4/lib/libpython3.10.so.1.0 - {3, 10, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.5 testdata/python-x64/3.10.5/lib/libpython3.10.so.1.0 - {3, 10, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.6 testdata/python-x64/3.10.6/lib/libpython3.10.so.1.0 - {3, 10, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.7 testdata/python-x64/3.10.7/lib/libpython3.10.so.1.0 - {3, 10, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.8 testdata/python-x64/3.10.8/lib/libpython3.10.so.1.0 - {3, 10, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.9 testdata/python-x64/3.10.9/lib/libpython3.10.so.1.0 - {3, 10, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.10 testdata/python-x64/3.10.10/lib/libpython3.10.so.1.0 - {3, 10, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.11 testdata/python-x64/3.10.11/lib/libpython3.10.so.1.0 - {3, 10, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.12 testdata/python-x64/3.10.12/lib/libpython3.10.so.1.0 - {3, 10, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.13 testdata/python-x64/3.10.13/lib/libpython3.10.so.1.0 - {3, 10, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 560, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.0 testdata/python-x64/3.11.0/lib/libpython3.11.so.1.0 - {3, 11, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.1 testdata/python-x64/3.11.1/lib/libpython3.11.so.1.0 - {3, 11, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.2 testdata/python-x64/3.11.2/lib/libpython3.11.so.1.0 - {3, 11, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.3 testdata/python-x64/3.11.3/lib/libpython3.11.so.1.0 - {3, 11, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.4 testdata/python-x64/3.11.4/lib/libpython3.11.so.1.0 - {3, 11, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.5 testdata/python-x64/3.11.5/lib/libpython3.11.so.1.0 - {3, 11, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.6 testdata/python-x64/3.11.6/lib/libpython3.11.so.1.0 - {3, 11, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.7 testdata/python-x64/3.11.7/lib/libpython3.11.so.1.0 - {3, 11, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.8 testdata/python-x64/3.11.8/lib/libpython3.11.so.1.0 - {3, 11, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 568, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.12.0 testdata/python-x64/3.12.0/lib/libpython3.12.so.1.0 - {3, 12, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 0, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 0, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 2560, - PyRuntimeState_autoTSSkey: 1544, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, - // 3.12.1 testdata/python-x64/3.12.1/lib/libpython3.12.so.1.0 - {3, 12, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 0, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 0, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 2560, - PyRuntimeState_autoTSSkey: 1544, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, - // 3.12.2 testdata/python-x64/3.12.2/lib/libpython3.12.so.1.0 - {3, 12, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 0, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 0, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 2560, - PyRuntimeState_autoTSSkey: 1544, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, - // 3.13.0 testdata/python-x64/3.13.0a6/libpython3.13.so.1.0 - {3, 13, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: -1, - PyThreadState_current_frame: 72, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: 0, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 3160, - PyRuntimeState_autoTSSkey: 1896, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, -} diff --git a/ebpf/python/python_offsets_gen_arm64.go b/ebpf/python/python_offsets_gen_arm64.go deleted file mode 100644 index 101e9883d3..0000000000 --- a/ebpf/python/python_offsets_gen_arm64.go +++ /dev/null @@ -1,3822 +0,0 @@ -//go:build arm64 && linux - -// Code generated by python_dwarfdump. DO NOT EDIT. -package python - -var pyVersions = map[Version]*UserOffsets{ - // 3.5.0 testdata/python-arm64/3.5.0/lib/libpython3.5m.so.1.0 - {3, 5, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.1 testdata/python-arm64/3.5.1/lib/libpython3.5m.so.1.0 - {3, 5, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.2 testdata/python-arm64/3.5.2/lib/libpython3.5m.so.1.0 - {3, 5, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.3 testdata/python-arm64/3.5.3/lib/libpython3.5m.so.1.0 - {3, 5, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.4 testdata/python-arm64/3.5.4/lib/libpython3.5m.so.1.0 - {3, 5, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.5 testdata/python-arm64/3.5.5/lib/libpython3.5m.so.1.0 - {3, 5, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.6 testdata/python-arm64/3.5.6/lib/libpython3.5m.so.1.0 - {3, 5, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.7 testdata/python-arm64/3.5.7/lib/libpython3.5m.so.1.0 - {3, 5, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.8 testdata/python-arm64/3.5.8/lib/libpython3.5m.so.1.0 - {3, 5, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.9 testdata/python-arm64/3.5.9/lib/libpython3.5m.so.1.0 - {3, 5, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.5.10 testdata/python-arm64/3.5.10/lib/libpython3.5m.so.1.0 - {3, 5, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.0 testdata/python-arm64/3.6.0/lib/libpython3.6m.so.1.0 - {3, 6, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.1 testdata/python-arm64/3.6.1/lib/libpython3.6m.so.1.0 - {3, 6, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.2 testdata/python-arm64/3.6.2/lib/libpython3.6m.so.1.0 - {3, 6, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.3 testdata/python-arm64/3.6.3/lib/libpython3.6m.so.1.0 - {3, 6, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.4 testdata/python-arm64/3.6.4/lib/libpython3.6m.so.1.0 - {3, 6, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.5 testdata/python-arm64/3.6.5/lib/libpython3.6m.so.1.0 - {3, 6, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.6 testdata/python-arm64/3.6.6/lib/libpython3.6m.so.1.0 - {3, 6, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.7 testdata/python-arm64/3.6.7/lib/libpython3.6m.so.1.0 - {3, 6, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.8 testdata/python-arm64/3.6.8/lib/libpython3.6m.so.1.0 - {3, 6, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.9 testdata/python-arm64/3.6.9/lib/libpython3.6m.so.1.0 - {3, 6, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.10 testdata/python-arm64/3.6.10/lib/libpython3.6m.so.1.0 - {3, 6, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.11 testdata/python-arm64/3.6.11/lib/libpython3.6m.so.1.0 - {3, 6, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.12 testdata/python-arm64/3.6.12/lib/libpython3.6m.so.1.0 - {3, 6, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.13 testdata/python-arm64/3.6.13/lib/libpython3.6m.so.1.0 - {3, 6, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.14 testdata/python-arm64/3.6.14/lib/libpython3.6m.so.1.0 - {3, 6, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.6.15 testdata/python-arm64/3.6.15/lib/libpython3.6m.so.1.0 - {3, 6, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 376, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: -1, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: -1, - PyTssT_key: -1, - PyTssTSize: -1, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.0 testdata/python-arm64/3.7.0/lib/libpython3.7m.so.1.0 - {3, 7, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1400, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.1 testdata/python-arm64/3.7.1/lib/libpython3.7m.so.1.0 - {3, 7, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1400, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.2 testdata/python-arm64/3.7.2/lib/libpython3.7m.so.1.0 - {3, 7, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1400, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.3 testdata/python-arm64/3.7.3/lib/libpython3.7m.so.1.0 - {3, 7, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1400, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.4 testdata/python-arm64/3.7.4/lib/libpython3.7m.so.1.0 - {3, 7, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.5 testdata/python-arm64/3.7.5/lib/libpython3.7m.so.1.0 - {3, 7, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.6 testdata/python-arm64/3.7.6/lib/libpython3.7m.so.1.0 - {3, 7, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.7 testdata/python-arm64/3.7.7/lib/libpython3.7m.so.1.0 - {3, 7, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.8 testdata/python-arm64/3.7.8/lib/libpython3.7m.so.1.0 - {3, 7, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.9 testdata/python-arm64/3.7.9/lib/libpython3.7m.so.1.0 - {3, 7, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.10 testdata/python-arm64/3.7.10/lib/libpython3.7m.so.1.0 - {3, 7, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.11 testdata/python-arm64/3.7.11/lib/libpython3.7m.so.1.0 - {3, 7, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.12 testdata/python-arm64/3.7.12/lib/libpython3.7m.so.1.0 - {3, 7, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.13 testdata/python-arm64/3.7.13/lib/libpython3.7m.so.1.0 - {3, 7, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.14 testdata/python-arm64/3.7.14/lib/libpython3.7m.so.1.0 - {3, 7, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.15 testdata/python-arm64/3.7.15/lib/libpython3.7m.so.1.0 - {3, 7, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.16 testdata/python-arm64/3.7.16/lib/libpython3.7m.so.1.0 - {3, 7, 16}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.7.17 testdata/python-arm64/3.7.17/lib/libpython3.7m.so.1.0 - {3, 7, 17}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 96, - PyCodeObject_co_name: 104, - PyCodeObject_co_varnames: 64, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 88, - PyCodeObject__co_cellvars: 80, - PyCodeObject__co_nlocals: 24, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1488, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.0 testdata/python-arm64/3.8.0/lib/libpython3.8.so.1.0 - {3, 8, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.1 testdata/python-arm64/3.8.1/lib/libpython3.8.so.1.0 - {3, 8, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.2 testdata/python-arm64/3.8.2/lib/libpython3.8.so.1.0 - {3, 8, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.3 testdata/python-arm64/3.8.3/lib/libpython3.8.so.1.0 - {3, 8, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.4 testdata/python-arm64/3.8.4/lib/libpython3.8.so.1.0 - {3, 8, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.5 testdata/python-arm64/3.8.5/lib/libpython3.8.so.1.0 - {3, 8, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.6 testdata/python-arm64/3.8.6/lib/libpython3.8.so.1.0 - {3, 8, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.7 testdata/python-arm64/3.8.7/lib/libpython3.8.so.1.0 - {3, 8, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.8 testdata/python-arm64/3.8.8/lib/libpython3.8.so.1.0 - {3, 8, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.9 testdata/python-arm64/3.8.9/lib/libpython3.8.so.1.0 - {3, 8, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.10 testdata/python-arm64/3.8.10/lib/libpython3.8.so.1.0 - {3, 8, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.11 testdata/python-arm64/3.8.11/lib/libpython3.8.so.1.0 - {3, 8, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.12 testdata/python-arm64/3.8.12/lib/libpython3.8.so.1.0 - {3, 8, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.13 testdata/python-arm64/3.8.13/lib/libpython3.8.so.1.0 - {3, 8, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.14 testdata/python-arm64/3.8.14/lib/libpython3.8.so.1.0 - {3, 8, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.15 testdata/python-arm64/3.8.15/lib/libpython3.8.so.1.0 - {3, 8, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.16 testdata/python-arm64/3.8.16/lib/libpython3.8.so.1.0 - {3, 8, 16}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.17 testdata/python-arm64/3.8.17/lib/libpython3.8.so.1.0 - {3, 8, 17}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.8.18 testdata/python-arm64/3.8.18/lib/libpython3.8.so.1.0 - {3, 8, 18}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 1376, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 32, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.0 testdata/python-arm64/3.9.0/lib/libpython3.9.so.1.0 - {3, 9, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.1 testdata/python-arm64/3.9.1/lib/libpython3.9.so.1.0 - {3, 9, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.2 testdata/python-arm64/3.9.2/lib/libpython3.9.so.1.0 - {3, 9, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.4 testdata/python-arm64/3.9.4/lib/libpython3.9.so.1.0 - {3, 9, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.5 testdata/python-arm64/3.9.5/lib/libpython3.9.so.1.0 - {3, 9, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.6 testdata/python-arm64/3.9.6/lib/libpython3.9.so.1.0 - {3, 9, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.7 testdata/python-arm64/3.9.7/lib/libpython3.9.so.1.0 - {3, 9, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.8 testdata/python-arm64/3.9.8/lib/libpython3.9.so.1.0 - {3, 9, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.9 testdata/python-arm64/3.9.9/lib/libpython3.9.so.1.0 - {3, 9, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.10 testdata/python-arm64/3.9.10/lib/libpython3.9.so.1.0 - {3, 9, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.11 testdata/python-arm64/3.9.11/lib/libpython3.9.so.1.0 - {3, 9, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.12 testdata/python-arm64/3.9.12/lib/libpython3.9.so.1.0 - {3, 9, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.13 testdata/python-arm64/3.9.13/lib/libpython3.9.so.1.0 - {3, 9, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.14 testdata/python-arm64/3.9.14/lib/libpython3.9.so.1.0 - {3, 9, 14}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.15 testdata/python-arm64/3.9.15/lib/libpython3.9.so.1.0 - {3, 9, 15}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.16 testdata/python-arm64/3.9.16/lib/libpython3.9.so.1.0 - {3, 9, 16}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.17 testdata/python-arm64/3.9.17/lib/libpython3.9.so.1.0 - {3, 9, 17}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.9.18 testdata/python-arm64/3.9.18/lib/libpython3.9.so.1.0 - {3, 9, 18}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: -1, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 360, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.0 testdata/python-arm64/3.10.0/lib/libpython3.10.so.1.0 - {3, 10, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.1 testdata/python-arm64/3.10.1/lib/libpython3.10.so.1.0 - {3, 10, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.2 testdata/python-arm64/3.10.2/lib/libpython3.10.so.1.0 - {3, 10, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.3 testdata/python-arm64/3.10.3/lib/libpython3.10.so.1.0 - {3, 10, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.4 testdata/python-arm64/3.10.4/lib/libpython3.10.so.1.0 - {3, 10, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.5 testdata/python-arm64/3.10.5/lib/libpython3.10.so.1.0 - {3, 10, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.6 testdata/python-arm64/3.10.6/lib/libpython3.10.so.1.0 - {3, 10, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.7 testdata/python-arm64/3.10.7/lib/libpython3.10.so.1.0 - {3, 10, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.8 testdata/python-arm64/3.10.8/lib/libpython3.10.so.1.0 - {3, 10, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.9 testdata/python-arm64/3.10.9/lib/libpython3.10.so.1.0 - {3, 10, 9}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.10 testdata/python-arm64/3.10.10/lib/libpython3.10.so.1.0 - {3, 10, 10}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.11 testdata/python-arm64/3.10.11/lib/libpython3.10.so.1.0 - {3, 10, 11}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.12 testdata/python-arm64/3.10.12/lib/libpython3.10.so.1.0 - {3, 10, 12}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.10.13 testdata/python-arm64/3.10.13/lib/libpython3.10.so.1.0 - {3, 10, 13}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: 24, - PyThreadState_cframe: 48, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 24, - PyFrameObject_f_code: 32, - PyFrameObject_f_localsplus: 352, - PyCodeObject_co_filename: 104, - PyCodeObject_co_name: 112, - PyCodeObject_co_varnames: 72, - PyCodeObject_co_localsplusnames: -1, - PyCodeObject__co_cell2arg: 96, - PyCodeObject__co_cellvars: 88, - PyCodeObject__co_nlocals: 28, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: -1, - PyInterpreterFrame_localsplus: -1, - PyInterpreterFrame_owner: -1, - PyRuntimeState_gilstate: 576, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.0 testdata/python-arm64/3.11.0/lib/libpython3.11.so.1.0 - {3, 11, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.1 testdata/python-arm64/3.11.1/lib/libpython3.11.so.1.0 - {3, 11, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.2 testdata/python-arm64/3.11.2/lib/libpython3.11.so.1.0 - {3, 11, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.3 testdata/python-arm64/3.11.3/lib/libpython3.11.so.1.0 - {3, 11, 3}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.4 testdata/python-arm64/3.11.4/lib/libpython3.11.so.1.0 - {3, 11, 4}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.5 testdata/python-arm64/3.11.5/lib/libpython3.11.so.1.0 - {3, 11, 5}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.6 testdata/python-arm64/3.11.6/lib/libpython3.11.so.1.0 - {3, 11, 6}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.7 testdata/python-arm64/3.11.7/libpython3.11.so.1.0 - {3, 11, 7}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.11.8 testdata/python-arm64/3.11.8/libpython3.11.so.1.0 - {3, 11, 8}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 8, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 32, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 48, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 69, - PyRuntimeState_gilstate: 584, - PyRuntimeState_autoTSSkey: -1, - Gilstate_runtime_state_autoTSSkey: 24, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 48, - PyCompactUnicodeObjectSize: 72, - PyCellObject__ob_ref: 16, - }, - // 3.12.0 testdata/python-arm64/3.12.0/lib/libpython3.12.so.1.0 - {3, 12, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 0, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 0, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 2560, - PyRuntimeState_autoTSSkey: 1544, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, - // 3.12.1 testdata/python-arm64/3.12.1/libpython3.12.so.1.0 - {3, 12, 1}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 0, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 0, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 2560, - PyRuntimeState_autoTSSkey: 1544, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, - // 3.12.2 testdata/python-arm64/3.12.2/libpython3.12.so.1.0 - {3, 12, 2}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: 56, - PyThreadState_current_frame: -1, - PyCFrame_current_frame: 0, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: 0, - PyInterpreterFrame_f_executable: -1, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 2560, - PyRuntimeState_autoTSSkey: 1544, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, - // 3.13.0 testdata/python-arm64/3.13.0a6/libpython3.13.so.1.0 - {3, 13, 0}: { - PyVarObject_ob_size: 16, - PyObject_ob_type: 8, - PyTypeObject_tp_name: 24, - PyThreadState_frame: -1, - PyThreadState_cframe: -1, - PyThreadState_current_frame: 72, - PyCFrame_current_frame: -1, - PyFrameObject_f_back: 16, - PyFrameObject_f_code: -1, - PyFrameObject_f_localsplus: -1, - PyCodeObject_co_filename: 112, - PyCodeObject_co_name: 120, - PyCodeObject_co_varnames: -1, - PyCodeObject_co_localsplusnames: 96, - PyCodeObject__co_cell2arg: -1, - PyCodeObject__co_cellvars: -1, - PyCodeObject__co_nlocals: 80, - PyTupleObject_ob_item: 24, - PyInterpreterFrame_f_code: -1, - PyInterpreterFrame_f_executable: 0, - PyInterpreterFrame_previous: 8, - PyInterpreterFrame_localsplus: 72, - PyInterpreterFrame_owner: 70, - PyRuntimeState_gilstate: 3160, - PyRuntimeState_autoTSSkey: 1896, - Gilstate_runtime_state_autoTSSkey: -1, - PyTssT_is_initialized: 0, - PyTssT_key: 4, - PyTssTSize: 8, - PyASCIIObjectSize: 40, - PyCompactUnicodeObjectSize: 56, - PyCellObject__ob_ref: 16, - }, -} diff --git a/ebpf/python/str.go b/ebpf/python/str.go deleted file mode 100644 index dce36e8dce..0000000000 --- a/ebpf/python/str.go +++ /dev/null @@ -1,52 +0,0 @@ -package python - -func PythonString(tok []int8, typ *PerfPyStrType) string { - if typ.Type&uint8(PyStrTypeAscii) != 0 || typ.Type&uint8(PyStrTypeUtf8) != 0 { - sz := int(typ.SizeCodepoints) // 128 max - if sz > len(tok) { - sz = len(tok) - } - buf := make([]byte, sz) - for i := 0; i < sz; i++ { - buf[i] = byte(tok[i]) - } - return string(buf) - } - - if typ.Type&uint8(PyStrType1Byte) != 0 { - sz := int(typ.SizeCodepoints) // 128 max - if sz > len(tok) { - sz = len(tok) - } - buf := make([]rune, sz) - for i := 0; i < sz; i++ { - buf[i] = rune(uint8(tok[i])) - } - return string(buf) - } - if typ.Type&uint8(PyStrType2Byte) != 0 { - sz := int(typ.SizeCodepoints) // 128 max - if sz*2 > len(tok) { - sz = len(tok) / 2 - } - buf := make([]rune, sz) - for i := 0; i < sz; i++ { - r := uint16(tok[i*2]) | uint16(tok[i*2+1])<<8 - buf[i] = rune(r) - } - return string(buf) - } - if typ.Type&uint8(PyStrType4Byte) != 0 { - sz := int(typ.SizeCodepoints) // 128 max - if sz*4 > len(tok) { - sz = len(tok) / 4 - } - buf := make([]rune, sz) - for i := 0; i < sz; i++ { - r := uint32(uint8(tok[i*4])) | uint32(uint8(tok[i*4+1]))<<8 | uint32(uint8(tok[i*4+2]))<<16 | uint32(uint8(tok[i*4+3]))<<24 - buf[i] = rune(r) - } - return string(buf) - } - return "" -} diff --git a/ebpf/python/str_test.go b/ebpf/python/str_test.go deleted file mode 100644 index 3468796ccb..0000000000 --- a/ebpf/python/str_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package python - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestPythonString(t *testing.T) { - testdata := []struct { - buf []int8 - typ *PerfPyStrType - res string - }{ - { - buf: []int8{-61}, - typ: &PerfPyStrType{Type: uint8(PyStrType1Byte), SizeCodepoints: 1}, - res: "Ã", - }, - { - buf: []int8{0x20, 0xa, 0x61}, - typ: &PerfPyStrType{Type: uint8(PyStrType1Byte | PyStrTypeAscii), SizeCodepoints: 2}, - res: " \n", - }, - { - buf: []int8{97, 0, 115, 0, 100, 0, 57, 4, 70, 4, 67, 4}, - typ: &PerfPyStrType{Type: uint8(PyStrType2Byte), SizeCodepoints: 6}, - res: "asdйцу", - }, { - buf: []int8{-61, 0, 0, 0, 35, -7, 1, 0}, - typ: &PerfPyStrType{Type: uint8(PyStrType4Byte), SizeCodepoints: 2}, - res: "Ã🤣", - }, { - buf: []int8{-61, -125, -48, -71, -47, -122, -47, -125}, - typ: &PerfPyStrType{Type: uint8(PyStrTypeUtf8), SizeCodepoints: 8}, - res: "Ãйцу", - }, { - buf: []int8{0x20}, - typ: &PerfPyStrType{Type: uint8(PyStrTypeNotCompact), SizeCodepoints: 239}, - res: "", - }, - } - for _, testdatum := range testdata { - t.Run(testdatum.res, func(t *testing.T) { - res := PythonString(testdatum.buf, testdatum.typ) - if res != testdatum.res { - assert.Equal(t, testdatum.res, res) - } - }) - } -} diff --git a/ebpf/python/sync.go b/ebpf/python/sync.go deleted file mode 100644 index 0fc9d8db81..0000000000 --- a/ebpf/python/sync.go +++ /dev/null @@ -1,118 +0,0 @@ -package python - -import "fmt" - -const MapNameSymbols = "py_symbols" - -/* -enum { - STACK_STATUS_COMPLETE = 0, - STACK_STATUS_ERROR = 1, - STACK_STATUS_TRUNCATED = 2, -}; - -enum { - PY_ERROR_GENERIC = 1, - PY_ERROR_THREAD_STATE = 2, - PY_ERROR_THREAD_STATE_NULL = 3, - PY_ERROR_TOP_FRAME = 4, - PY_ERROR_FRAME_CODE = 5, - PY_ERROR_FRAME_PREV = 6, - PY_ERROR_SYMBOL = 7, - PY_ERROR_TLSBASE = 8, - PY_ERROR_FIRST_ARG = 9, - PY_ERROR_CLASS_NAME = 10, - PY_ERROR_FILE_NAME = 11, - PY_ERROR_NAME = 12, - - - -}; -*/ - -type StackStatus uint8 - -var ( - StackStatusComplete StackStatus = 0 - StackStatusError StackStatus = 1 - StackStatusTruncated StackStatus = 2 -) - -func (s StackStatus) String() string { - switch s { - case StackStatusComplete: - return "StackStatusComplete" - case StackStatusError: - return "StackStatusError" - case StackStatusTruncated: - return "StackStatusTruncated" - default: - return fmt.Sprintf("StackStatus(%d)", s) - } -} - -type PyError uint8 - -var ( - PyErrorGeneric PyError = 1 - PyErrorThreadState PyError = 2 - PyErrorThreadStateNull PyError = 3 - PyErrorTopFrame PyError = 4 - PyErrorFrameCode PyError = 5 - PyErrorFramePrev PyError = 6 - PyErrorSymbol PyError = 7 - PyErrorTlsbase PyError = 8 - PyErrorFirstArg PyError = 9 - PyErrorClassName PyError = 10 - PyErrorFileName PyError = 11 - PyErrorName PyError = 12 -) - -func (e PyError) String() string { - switch e { - case PyErrorGeneric: - return "PyErrorGeneric" - case PyErrorThreadState: - return "PyErrorThreadState" - case PyErrorThreadStateNull: - return "PyErrorThreadStateNull" - case PyErrorTopFrame: - return "PyErrorTopFrame" - case PyErrorFrameCode: - return "PyErrorFrameCode" - case PyErrorFramePrev: - return "PyErrorFramePrev" - case PyErrorSymbol: - return "PyErrorSymbol" - case PyErrorTlsbase: - return "PyErrorTlsbase" - case PyErrorFirstArg: - return "PyErrorFirstArg" - case PyErrorClassName: - return "PyErrorClassName" - case PyErrorFileName: - return "PyErrorFileName" - case PyErrorName: - return "PyErrorName" - default: - return fmt.Sprintf("PyError(%d)", e) - } -} - -//#define PYSTR_TYPE_1BYTE 1 -//#define PYSTR_TYPE_2BYTE 2 -//#define PYSTR_TYPE_4BYTE 4 -//#define PYSTR_TYPE_ASCII 8 -//#define PYSTR_TYPE_UTF8 16 -//#define PYSTR_TYPE_NOT_COMPACT 32 - -type PyStrType uint8 - -var ( - PyStrType1Byte PyStrType = 1 - PyStrType2Byte PyStrType = 2 - PyStrType4Byte PyStrType = 4 - PyStrTypeAscii PyStrType = 8 - PyStrTypeUtf8 PyStrType = 16 - PyStrTypeNotCompact PyStrType = 32 -) diff --git a/ebpf/python/tss.go b/ebpf/python/tss.go deleted file mode 100644 index ffa6a76a71..0000000000 --- a/ebpf/python/tss.go +++ /dev/null @@ -1,87 +0,0 @@ -package python - -import ( - "encoding/binary" - "fmt" - "os" -) - -// todo split offsets validation and offset usage into separate routines -func GetTSSKey(pid uint32, version Version, offsets *UserOffsets, autoTLSkeyAddr, pyRuntime uint64, libc *PerfLibc) (int32, error) { - fd, err := os.Open(fmt.Sprintf("/proc/%d/mem", pid)) - if err != nil { - return 0, fmt.Errorf("python memory open failed %w", err) - } - defer fd.Close() - if version.Compare(Py37) < 0 { - return getAutoTLSKey(pid, version, autoTLSkeyAddr, fd) - } else { - return getPyTssKey(pid, version, offsets, pyRuntime, fd, libc) - } -} - -func getAutoTLSKey(pid uint32, version Version, autoTLSkeyAddr uint64, mem *os.File) (int32, error) { - var pkey int64 - var key [4]byte - if autoTLSkeyAddr == 0 { - return 0, fmt.Errorf("python missing symbols autoTLSkey %d %v", pid, version) - } - pkey = int64(autoTLSkeyAddr) - - n, err := mem.ReadAt(key[:], int64(pkey)) - if err != nil { - return 0, fmt.Errorf("python failed to read key %d %d %v %w", pid, pkey, version, err) - } - if n != 4 { - return 0, fmt.Errorf("python failed to read key %d %d %v %w", pid, pkey, version, err) - } - res := int32(binary.LittleEndian.Uint32(key[:])) - if res == -1 { - return 0, fmt.Errorf("python not initialized %+v", version) - } - return res, nil -} - -func getPyTssKey(pid uint32, version Version, offsets *UserOffsets, pyRuntime uint64, mem *os.File, libc *PerfLibc) (int32, error) { - if offsets.PyTssT_is_initialized != 0 || offsets.PyTssT_key != 4 || offsets.PyTssTSize != 8 { - return 0, fmt.Errorf("unexpected _Py_tss_t offsets %+v %+v", offsets, version) - } - var pkey int64 - var key [8]byte - if pyRuntime == 0 { - //should never happen - return 0, fmt.Errorf("python missing symbols pyRuntime %d %v", pid, version) - } - if version.Compare(Py312) >= 0 { - if offsets.PyRuntimeState_autoTSSkey == -1 { - // should never happen - return 0, fmt.Errorf("python missing offsets PyRuntimeState_autoTSSkey %d %v", pid, version) - } - pkey = int64(pyRuntime) + int64(offsets.PyRuntimeState_autoTSSkey) - } else { - if offsets.PyRuntimeState_gilstate == -1 || offsets.Gilstate_runtime_state_autoTSSkey == -1 { - // should never happen - return 0, fmt.Errorf("python missing offsets PyRuntimeStateGilstate GilstateRuntimeStateAutoTSSkey PyTssT_key %d %v", pid, version) - } - pkey = int64(pyRuntime) + int64(offsets.PyRuntimeState_gilstate+offsets.Gilstate_runtime_state_autoTSSkey) - if libc.Musl { - // _gil_runtime_state has two fields of type pthread_mutex_t which are different sizes in musl and glibc - // for now try to fix it as this is the only difference, in the future we may need to generate separate offsets - // for musl/glibc pythons - pkey -= 2 * (mutexSizeGlibc - mutexSizeMusl) - } - } - n, err := mem.ReadAt(key[:], int64(pkey)) - if err != nil { - return 0, fmt.Errorf("python failed to read key %d %d %v %w", pid, pkey, version, err) - } - if n != 8 { - return 0, fmt.Errorf("python failed to read key %d %d %v %w", pid, pkey, version, err) - } - isInitialized := int32(binary.LittleEndian.Uint32(key[:4])) - res := int32(binary.LittleEndian.Uint32(key[4:8])) - if isInitialized == 0 || res == -1 { - return 0, fmt.Errorf("python not initialized %+v", version) - } - return res, nil -} diff --git a/ebpf/python/versions.go b/ebpf/python/versions.go deleted file mode 100644 index 14a180178e..0000000000 --- a/ebpf/python/versions.go +++ /dev/null @@ -1,160 +0,0 @@ -package python - -import ( - "fmt" - "io" - "regexp" - "strconv" - - "github.com/pkg/errors" -) - -type Version struct { - Major, Minor, Patch int -} - -var Py313 = &Version{Major: 3, Minor: 13} -var Py312 = &Version{Major: 3, Minor: 12} -var Py311 = &Version{Major: 3, Minor: 11} -var Py310 = &Version{Major: 3, Minor: 10} -var Py37 = &Version{Major: 3, Minor: 7} - -func (p *Version) Compare(other *Version) int { - major := p.Major - other.Major - if major != 0 { - return major - } - - minor := p.Minor - other.Minor - if minor != 0 { - return minor - } - return p.Patch - other.Patch -} - -func (p *Version) String() string { - return fmt.Sprintf("%d.%d.%d", p.Major, p.Minor, p.Patch) -} - -// GetPythonPatchVersion searches for a patch version given a major + minor version with regexp -// r is libpython3.11.so or python3.11 elf binary -func GetPythonPatchVersion(r io.Reader, v Version) (Version, error) { - rePythonVersion := regexp.MustCompile(fmt.Sprintf("%d\\.%d\\.(\\d+)[^\\d]", v.Major, v.Minor)) - res := v - res.Patch = 0 - m, err := rgrep(r, rePythonVersion) - if err != nil { - return res, fmt.Errorf("rgrep python version %v %w", v, err) - } - patch, err := strconv.Atoi(string(m[1])) - if err != nil { - return res, fmt.Errorf("error trying to grep python patch version %s, %w", string(m[0]), err) - } - res.Patch = patch - return res, nil -} - -func rgrep(r io.Reader, re *regexp.Regexp) ([][]byte, error) { - const bufSize = 0x1000 - const lookBack = 0x10 - buf := make([]byte, bufSize+lookBack) - for { - n, err := r.Read(buf[lookBack:]) - if n > 0 { - it := buf[:lookBack+n] - submatch := re.FindSubmatch(it) - if submatch != nil { - return submatch, nil - } - copy(buf[:lookBack], it[len(it)-lookBack:]) - } - if err != nil { - if errors.Is(err, io.EOF) { - break - } - return nil, fmt.Errorf("error trying to grep python patch version %w", err) - } - } - return nil, fmt.Errorf("rgrep not found %v", re.String()) -} - -// UserOffsets keeps Python offsets which are then partially passed to ebpf with ProfilePyOffsetConfig -// -//goland:noinspection GoSnakeCaseUsage -type UserOffsets struct { - PyVarObject_ob_size int16 - PyObject_ob_type int16 - PyTypeObject_tp_name int16 - PyThreadState_frame int16 - PyThreadState_cframe int16 - PyThreadState_current_frame int16 - PyCFrame_current_frame int16 - PyFrameObject_f_back int16 - PyFrameObject_f_code int16 - PyFrameObject_f_localsplus int16 - PyCodeObject_co_filename int16 - PyCodeObject_co_name int16 - PyCodeObject_co_varnames int16 - PyCodeObject_co_localsplusnames int16 - PyCodeObject__co_cell2arg int16 - PyCodeObject__co_cellvars int16 - PyCodeObject__co_nlocals int16 - PyTupleObject_ob_item int16 - PyInterpreterFrame_f_code int16 - PyInterpreterFrame_f_executable int16 - PyInterpreterFrame_previous int16 - PyInterpreterFrame_localsplus int16 - PyInterpreterFrame_owner int16 - PyRuntimeState_gilstate int16 - PyRuntimeState_autoTSSkey int16 - Gilstate_runtime_state_autoTSSkey int16 - PyTssT_is_initialized int16 - PyTssT_key int16 - PyTssTSize int16 - PyASCIIObjectSize int16 - PyCompactUnicodeObjectSize int16 - PyCellObject__ob_ref int16 -} - -type GlibcOffsets struct { - PthreadSpecific1stblock int16 - PthreadSize int16 - PthreadKeyDataData int16 - PthreadKeyDataSize int16 -} - -type MuslOffsets struct { - PthreadTsd int16 - PthreadSize int16 -} - -func GetUserOffsets(version Version) (*UserOffsets, bool, error) { - return getVersionGuessing(version, pyVersions) -} - -// getVersionGuessing returns offsets for a given version. If version is not found, it tries to guess the closest one -// within the same major.minor version. If that fails, it returns an error. -func getVersionGuessing[T any](version Version, m map[Version]*T) (*T, bool, error) { - offsets, ok := m[version] - patchGuess := false - if !ok { - foundVersion := Version{} - for v, o := range m { - if v.Major == version.Major && v.Minor == version.Minor { - if offsets == nil { - offsets = o - foundVersion = v - } else if v.Compare(&foundVersion) > 0 { - offsets = o - foundVersion = v - } - } - } - if offsets == nil { - return nil, false, fmt.Errorf("unsupported version %v ", version) - } - patchGuess = true - } - - return offsets, patchGuess, nil -} diff --git a/ebpf/python/versions_libc.go b/ebpf/python/versions_libc.go deleted file mode 100644 index ed4d2130cb..0000000000 --- a/ebpf/python/versions_libc.go +++ /dev/null @@ -1,127 +0,0 @@ -package python - -import ( - "fmt" - "io" - "os" - "regexp" - "sort" - "strconv" - - log2 "github.com/go-kit/log" - "github.com/go-kit/log/level" -) - -var reMuslVersion = regexp.MustCompile("1\\.([12])\\.(\\d+)\\D") - -func GetMuslVersionFromFile(f string) (Version, error) { - muslFD, err := os.Open(f) - if err != nil { - return Version{}, fmt.Errorf("couldnot determine musl version %s %w", f, err) - } - defer muslFD.Close() - return GetMuslVersionFromReader(muslFD) -} - -// GetMuslVersionFromReader return minor musl version. For example 1 for 1.1.44 and 2 for 1.2.4 -func GetMuslVersionFromReader(r io.Reader) (Version, error) { - m, err := rgrep(r, reMuslVersion) - if err != nil { - return Version{}, fmt.Errorf("rgrep musl version %w", err) - } - minor, _ := strconv.Atoi(string(m[1])) - patch, _ := strconv.Atoi(string(m[2])) - return Version{Major: 1, Minor: minor, Patch: patch}, nil -} - -var reGlibcVersion = regexp.MustCompile("glibc 2\\.(\\d+)\\D") - -func GetGlibcVersionFromFile(f string) (Version, error) { - muslFD, err := os.Open(f) - if err != nil { - return Version{}, fmt.Errorf("couldnot determine glibc version %s %w", f, err) - } - defer muslFD.Close() - return GetGlibcVersionFromReader(muslFD) -} - -func GetGlibcVersionFromReader(r io.Reader) (Version, error) { - m, err := rgrep(r, reGlibcVersion) - if err != nil { - return Version{}, fmt.Errorf("rgrep python version %w", err) - } - minor, err := strconv.Atoi(string(m[1])) - if err != nil { - return Version{}, fmt.Errorf("error trying to grep musl minor version %s, %w", string(m[0]), err) - } - - return Version{Major: 2, Minor: minor}, nil -} - -func GetGlibcOffsets(version Version) (PerfLibc, bool, error) { - offsets, ok := glibcOffsets[version] - if ok { - return PerfLibc{ - Musl: false, - PthreadSize: offsets.PthreadSize, - PthreadSpecific1stblock: offsets.PthreadSpecific1stblock, - }, false, nil - } - versions := make([]Version, 0, len(glibcOffsets)) - for v := range glibcOffsets { - versions = append(versions, v) - } - sort.Slice(versions, func(i, j int) bool { - return versions[i].Compare(&versions[j]) < 0 - }) - if version.Compare(&versions[len(versions)-1]) > 0 { - return PerfLibc{ - Musl: false, - PthreadSize: glibcOffsets[versions[len(versions)-1]].PthreadSize, - PthreadSpecific1stblock: glibcOffsets[versions[len(versions)-1]].PthreadSpecific1stblock, - }, true, nil - } - return PerfLibc{}, false, fmt.Errorf("unsupported glibc version %v", version) -} - -func GetLibc(l log2.Logger, pid uint32, info ProcInfo) (PerfLibc, error) { - if info.Glibc == nil && info.Musl == nil { - return PerfLibc{}, fmt.Errorf("could not determine libc version %d, no libc found", pid) - } - if info.Musl != nil { - muslPath := fmt.Sprintf("/proc/%d/root%s", pid, info.Musl[0].Pathname) - muslVersion, err := GetMuslVersionFromFile(muslPath) - if err != nil { - return PerfLibc{}, fmt.Errorf("couldnot determine musl version %s %w", muslPath, err) - } - res := PerfLibc{Musl: true} - mo, guess, err := getVersionGuessing(muslVersion, muslOffsets) - if err != nil { - return PerfLibc{}, fmt.Errorf("unsupported musl version %w %+v", err, muslVersion) - } - if guess { - _ = level.Warn(l).Log("msg", "musl offsets were not found, but guessed from the closest version") - } - res.PthreadSize = mo.PthreadSize - res.PthreadSpecific1stblock = mo.PthreadTsd - _ = level.Debug(l).Log("msg", "musl offsets", "offsets", fmt.Sprintf("%+v", res)) - return res, nil - } - - glibcPath := fmt.Sprintf("/proc/%d/root%s", pid, info.Glibc[0].Pathname) - glibcVersion, err := GetGlibcVersionFromFile(glibcPath) - if err != nil { - return PerfLibc{}, fmt.Errorf("couldnot determine glibc version %s %w", glibcPath, err) - } - - res, guess, err := GetGlibcOffsets(glibcVersion) - if err != nil { - return PerfLibc{}, fmt.Errorf("unsupported glibc version %w %+v", err, glibcVersion) - } - if guess { - _ = level.Warn(l).Log("msg", "glibc offsets were not found, but guessed from the closest version") - } - _ = level.Debug(l).Log("msg", "glibc offsets", "offsets", fmt.Sprintf("%+v", res)) - return res, nil - -} diff --git a/ebpf/python/versions_test.go b/ebpf/python/versions_test.go deleted file mode 100644 index b1528b5288..0000000000 --- a/ebpf/python/versions_test.go +++ /dev/null @@ -1,226 +0,0 @@ -package python - -import ( - "slices" - "testing" - - "github.com/grafana/pyroscope/ebpf/testutil" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGlibcVersions(t *testing.T) { - testutil.InitGitSubmodule(t) - testdata := []struct { - path string - version Version - }{ - {"../testdata/glibc-arm64/glibc-2.31/libc.so.6", Version{2, 31, 0}}, - {"../testdata/glibc-arm64/glibc-2.36/libc.so.6", Version{2, 36, 0}}, - {"../testdata/glibc-arm64/glibc-2.29/libc.so.6", Version{2, 29, 0}}, - {"../testdata/glibc-arm64/glibc-2.37/libc.so.6", Version{2, 37, 0}}, - {"../testdata/glibc-arm64/glibc-2.34/libc.so.6", Version{2, 34, 0}}, - {"../testdata/glibc-arm64/glibc-2.32/libc.so.6", Version{2, 32, 0}}, - {"../testdata/glibc-arm64/glibc-2.27/libc.so.6", Version{2, 27, 0}}, - {"../testdata/glibc-arm64/glibc-2.28/libc.so.6", Version{2, 28, 0}}, - {"../testdata/glibc-arm64/glibc-2.35/libc.so.6", Version{2, 35, 0}}, - {"../testdata/glibc-arm64/glibc-2.30/libc.so.6", Version{2, 30, 0}}, - {"../testdata/glibc-arm64/glibc-2.33/libc.so.6", Version{2, 33, 0}}, - {"../testdata/glibc-arm64/glibc-2.38/libc.so.6", Version{2, 38, 0}}, - {"../testdata/glibc-x64/glibc-2.31/libc.so.6", Version{2, 31, 0}}, - {"../testdata/glibc-x64/glibc-2.36/libc.so.6", Version{2, 36, 0}}, - {"../testdata/glibc-x64/glibc-2.29/libc.so.6", Version{2, 29, 0}}, - {"../testdata/glibc-x64/glibc-2.37/libc.so.6", Version{2, 37, 0}}, - {"../testdata/glibc-x64/glibc-2.34/libc.so.6", Version{2, 34, 0}}, - {"../testdata/glibc-x64/glibc-2.32/libc.so.6", Version{2, 32, 0}}, - {"../testdata/glibc-x64/glibc-2.27/libc.so.6", Version{2, 27, 0}}, - {"../testdata/glibc-x64/glibc-2.28/libc.so.6", Version{2, 28, 0}}, - {"../testdata/glibc-x64/glibc-2.35/libc.so.6", Version{2, 35, 0}}, - {"../testdata/glibc-x64/glibc-2.30/libc.so.6", Version{2, 30, 0}}, - {"../testdata/glibc-x64/glibc-2.33/libc.so.6", Version{2, 33, 0}}, - {"../testdata/glibc-x64/glibc-2.38/libc.so.6", Version{2, 38, 0}}, - } - for _, testdatum := range testdata { - version, err := GetGlibcVersionFromFile(testdatum.path) - assert.NoError(t, err) - assert.Equal(t, testdatum.version, version) - - } -} - -func TestGlibcGuess(t *testing.T) { - orig := glibcOffsets - defer func() { - glibcOffsets = orig - }() - glibcOffsets = map[Version]*GlibcOffsets{} - v30 := Version{2, 30, 0} - glibcOffsets[v30] = orig[v30] - expected := PerfLibc{ - PthreadSize: orig[v30].PthreadSize, - PthreadSpecific1stblock: orig[v30].PthreadSpecific1stblock, - } - offsets, guess, err := GetGlibcOffsets(v30) - assert.NoError(t, err) - assert.False(t, guess) - assert.Equal(t, expected, offsets) - - offsets, guess, err = GetGlibcOffsets(Version{2, 31, 0}) - assert.NoError(t, err) - assert.True(t, guess) - assert.Equal(t, expected, offsets) - _, _, err = GetGlibcOffsets(Version{2, 27, 0}) - assert.Error(t, err) -} - -func TestKeyData(t *testing.T) { - for version, offsets := range glibcOffsets { - assert.Equal(t, int16(8), offsets.PthreadKeyDataData, version.String()) - assert.Equal(t, int16(16), offsets.PthreadKeyDataSize, version.String()) - } -} - -type versionOffset struct { - version Version - offsets *UserOffsets -} - -func sortVersionOffsets(offsets []versionOffset) { - slices.SortFunc(offsets, func(i, j versionOffset) int { - return i.version.Compare(&j.version) - }) -} - -func sortedVersionOffsets() []versionOffset { - var offsets []versionOffset - for version, o := range pyVersions { - offsets = append(offsets, versionOffset{version, o}) - } - sortVersionOffsets(offsets) - return offsets -} - -func TestPythonVersionsChangesWithinPatches(t *testing.T) { - knownChanges := map[Version]struct{}{ - {3, 7, 3}: {}, - } - - m := map[Version][]versionOffset{} - require.NotEmpty(t, pyVersions) - for version, offsets := range pyVersions { - minorVersion := version - minorVersion.Patch = 0 - m[minorVersion] = append(m[minorVersion], versionOffset{version, offsets}) - } - for _, offsets := range m { - sortVersionOffsets(offsets) - it := offsets[0] - rest := offsets[1:] - for len(rest) > 0 { - next := rest[0] - if _, ok := knownChanges[it.version]; !ok { - assert.Equal(t, it.offsets, next.offsets, it.version.String()) - } - rest = rest[1:] - it = next - } - } -} - -func TestPythonVersionFields(t *testing.T) { - - for _, it := range sortedVersionOffsets() { - version := it.version - offsets := it.offsets - t.Run(it.version.String(), func(t *testing.T) { - present := func(offset int16) { - t.Helper() - assert.True(t, offset >= 0) - } - missing := func(offset int16) { - t.Helper() - assert.False(t, offset >= 0) - } - if version.Compare(Py311) >= 0 { - if version.Compare(Py313) >= 0 { - present(offsets.PyInterpreterFrame_f_executable) - missing(offsets.PyInterpreterFrame_f_code) - } else { - present(offsets.PyInterpreterFrame_f_code) - missing(offsets.PyInterpreterFrame_f_executable) - } - present(offsets.PyInterpreterFrame_previous) - present(offsets.PyInterpreterFrame_localsplus) - //missing(offsets.PyFrameObject_f_back) //todo why?? - missing(offsets.PyFrameObject_f_localsplus) - } else { - present(offsets.PyFrameObject_f_code) - present(offsets.PyFrameObject_f_back) - present(offsets.PyFrameObject_f_localsplus) - missing(offsets.PyInterpreterFrame_previous) - missing(offsets.PyInterpreterFrame_localsplus) - } - - if version.Compare(Py37) >= 0 { - assert.Equal(t, int16(0), offsets.PyTssT_is_initialized) - assert.Equal(t, int16(4), offsets.PyTssT_key) - assert.Equal(t, int16(8), offsets.PyTssTSize) - - if version.Compare(Py312) >= 0 { - present(offsets.PyRuntimeState_autoTSSkey) - present(offsets.PyRuntimeState_gilstate) // we don't actually use it but it is there - missing(offsets.Gilstate_runtime_state_autoTSSkey) - } else { - missing(offsets.PyRuntimeState_autoTSSkey) - present(offsets.PyRuntimeState_gilstate) - present(offsets.Gilstate_runtime_state_autoTSSkey) - } - } else { - // using autoTLSkey from bss, not an offset - } - - //PyVarObject_ob_size int16 - present(offsets.PyVarObject_ob_size) - present(offsets.PyObject_ob_type) - present(offsets.PyTypeObject_tp_name) - present(offsets.PyTupleObject_ob_item) - if version.Compare(Py311) >= 0 && version.Compare(Py313) < 0 { - assert.True(t, offsets.PyThreadState_cframe >= 0) - assert.True(t, offsets.PyCFrame_current_frame >= 0) - } else { - if version.Compare(Py313) >= 0 { - missing(offsets.PyThreadState_cframe) - missing(offsets.PyCFrame_current_frame) - missing(offsets.PyThreadState_frame) - // PyCFrame was removed in 3.13, lets pretend it was never there and frame field was just renamed to current_frame - present(offsets.PyThreadState_current_frame) - } else { - if version.Compare(Py310) >= 0 { - present(offsets.PyThreadState_cframe) // we don't use it anyway - } else { - missing(offsets.PyThreadState_cframe) - } - missing(offsets.PyCFrame_current_frame) - present(offsets.PyThreadState_frame) - } - } - - if version.Compare(Py311) >= 0 { - present(offsets.PyInterpreterFrame_owner) - } else { - missing(offsets.PyInterpreterFrame_owner) - } - present(offsets.PyASCIIObjectSize) - present(offsets.PyCompactUnicodeObjectSize) - if version.Compare(Py311) >= 0 { - present(offsets.PyCodeObject_co_localsplusnames) - missing(offsets.PyCodeObject_co_varnames) - } else { - present(offsets.PyCodeObject_co_varnames) - missing(offsets.PyCodeObject_co_localsplusnames) - } - present(offsets.PyCodeObject_co_filename) - present(offsets.PyCodeObject_co_name) - }) - } -} diff --git a/ebpf/python_ebpf_expected.txt b/ebpf/python_ebpf_expected.txt deleted file mode 100644 index 219d664348..0000000000 --- a/ebpf/python_ebpf_expected.txt +++ /dev/null @@ -1,6 +0,0 @@ -python;server.py ;app.py Flask.run;serving.py run_simple;serving.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer._handle_request_noblock;socketserver.py BaseWSGIServer.process_request;socketserver.py BaseWSGIServer.finish_request;socketserver.py WSGIRequestHandler.__init__;serving.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle_one_request;serving.py WSGIRequestHandler.run_wsgi;serving.py execute;app.py Flask.__call__;app.py Flask.wsgi_app;app.py Flask.full_dispatch_request;app.py Flask.dispatch_request;server.py bike;bike.py order_bike;utility.py find_nearest_vehicle -python;server.py ;app.py Flask.run;serving.py run_simple;serving.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer._handle_request_noblock;socketserver.py BaseWSGIServer.process_request;socketserver.py BaseWSGIServer.finish_request;socketserver.py WSGIRequestHandler.__init__;serving.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle_one_request;serving.py WSGIRequestHandler.run_wsgi;serving.py execute;app.py Flask.__call__;app.py Flask.wsgi_app;app.py Flask.full_dispatch_request;app.py Flask.dispatch_request;server.py car;car.py order_car;utility.py find_nearest_vehicle -python;server.py ;app.py Flask.run;serving.py run_simple;serving.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer._handle_request_noblock;socketserver.py BaseWSGIServer.process_request;socketserver.py BaseWSGIServer.finish_request;socketserver.py WSGIRequestHandler.__init__;serving.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle_one_request;serving.py WSGIRequestHandler.run_wsgi;serving.py execute;app.py Flask.__call__;app.py Flask.wsgi_app;app.py Flask.full_dispatch_request;app.py Flask.dispatch_request;server.py car;car.py order_car;utility.py find_nearest_vehicle;utility.py check_driver_availability -python;server.py ;app.py Flask.run;serving.py run_simple;serving.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer._handle_request_noblock;socketserver.py BaseWSGIServer.process_request;socketserver.py BaseWSGIServer.finish_request;socketserver.py WSGIRequestHandler.__init__;serving.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle_one_request;serving.py WSGIRequestHandler.run_wsgi;serving.py execute;app.py Flask.__call__;app.py Flask.wsgi_app;app.py Flask.full_dispatch_request;app.py Flask.dispatch_request;server.py scooter;scooter.py order_scooter;utility.py find_nearest_vehicle -python;server.py ;app.py Flask.run;serving.py run_simple;serving.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer._handle_request_noblock;socketserver.py BaseWSGIServer.process_request;socketserver.py BaseWSGIServer.finish_request;socketserver.py WSGIRequestHandler.__init__;serving.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle_one_request;serving.py WSGIRequestHandler.run_wsgi;serving.py execute;app.py Flask.__call__;app.py Flask.wsgi_app;app.py Flask.full_dispatch_request;app.py Flask.dispatch_request;server.py cell_cls_issue;server.py CellClsIssueType.__call__ -python;server.py ;app.py Flask.run;serving.py run_simple;serving.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer.serve_forever;socketserver.py BaseWSGIServer._handle_request_noblock;socketserver.py BaseWSGIServer.process_request;socketserver.py BaseWSGIServer.finish_request;socketserver.py WSGIRequestHandler.__init__;serving.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle;server.py WSGIRequestHandler.handle_one_request;serving.py WSGIRequestHandler.run_wsgi;serving.py execute;app.py Flask.__call__;app.py Flask.wsgi_app;app.py Flask.full_dispatch_request;app.py Flask.dispatch_request;server.py cell_self_issue;server.py CellSelfIssue.bar;server.py asd diff --git a/ebpf/python_ebpf_test.go b/ebpf/python_ebpf_test.go deleted file mode 100644 index defeb24394..0000000000 --- a/ebpf/python_ebpf_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package ebpfspy - -import ( - _ "embed" - "fmt" - "io" - "net/http" - "os" - "regexp" - "strings" - "sync" - "testing" - - "github.com/go-kit/log" - "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/grafana/pyroscope/ebpf/pprof" - "github.com/grafana/pyroscope/ebpf/sd" - "github.com/grafana/pyroscope/ebpf/symtab" - "github.com/grafana/pyroscope/ebpf/testutil" - "github.com/samber/lo" - "github.com/stretchr/testify/require" -) - -//go:embed python_ebpf_expected.txt -var pythonEBPFExpected []byte - -func pythonEBPFExpectedUbuntu() []byte { - re := regexp.MustCompile("(?m)^python;") - return re.ReplaceAll(pythonEBPFExpected, []byte("python3;")) -} - -func TestEBPFPythonProfiler(t *testing.T) { - var testdata = []struct { - image string - expected []byte - }{ - {"pyroscope/ebpf-testdata-rideshare:3.8-slim", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.9-slim", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.10-slim", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.11-slim", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.12-slim", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.13-rc-slim", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.8-alpine", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.9-alpine", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.10-alpine", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.11-alpine", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.12-alpine", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:3.13-rc-alpine", pythonEBPFExpected}, - {"pyroscope/ebpf-testdata-rideshare:ubuntu-20.04", pythonEBPFExpectedUbuntu()}, - {"pyroscope/ebpf-testdata-rideshare:ubuntu-22.04", pythonEBPFExpectedUbuntu()}, - } - const ridesharePort = "5000" - - l := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) - l = log.With(l, "ts", log.DefaultTimestampUTC, "caller", log.Caller(5)) - - pullImages(t, testdata, l) - - for _, testdatum := range testdata { - testdatum := testdatum - t.Run(testdatum.image, func(t *testing.T) { - - l := log.With(l, "test", t.Name()) - - rideshare := testutil.RunContainerWithPort(t, l, testdatum.image, ridesharePort) - defer rideshare.Kill() - - profiler := startPythonProfiler(t, l, rideshare.ContainerID) - defer profiler.Stop() - - loadgen(t, l, rideshare.Url(), 2) - - profiles := collectProfiles(t, l, profiler) - - compareProfiles(t, l, testdatum.expected, profiles) - }) - } - -} - -func pullImages(t *testing.T, testdata []struct { - image string - expected []byte -}, l log.Logger) { - wg := sync.WaitGroup{} - for _, testdatum := range testdata { - wg.Add(1) - go func(img string) { - defer wg.Done() - testutil.PullImage(t, l, img) - }(testdatum.image) - } - wg.Wait() -} - -func compareProfiles(t *testing.T, l log.Logger, expected []byte, actual map[string]struct{}) { - expectedProfiles := map[string]struct{}{} - for _, line := range strings.Split(string(expected), "\n") { - if line == "" { - continue - } - expectedProfiles[line] = struct{}{} - _ = l.Log("expected", line) - } - for line := range actual { - _ = l.Log("actual", line) - } - - for profile := range expectedProfiles { - _, ok := actual[profile] - require.True(t, ok, fmt.Sprintf("profile %s not found in actual", profile)) - } -} - -func collectProfiles(t *testing.T, l log.Logger, profiler Session) map[string]struct{} { - l = log.With(l, "component", "profiles") - profiles := map[string]struct{}{} - err := profiler.CollectProfiles(func(ps pprof.ProfileSample) { - lo.Reverse(ps.Stack) - sample := strings.Join(ps.Stack, ";") - profiles[sample] = struct{}{} - _ = l.Log("target", ps.Target.String(), - "pid", ps.Pid, - "stack", sample) - }) - require.NoError(t, err) - return profiles -} - -func startPythonProfiler(t *testing.T, l log.Logger, containerID string) Session { - l = log.With(l, "component", "ebpf-session") - targetFinder, err := sd.NewTargetFinder(os.DirFS("/"), l, - sd.TargetsOptions{ - Targets: []sd.DiscoveryTarget{ - { - "__container_id__": containerID, - "service_name": containerID, - }, - }, - ContainerCacheSize: 1024, - TargetsOnly: true, - }) - require.NoError(t, err) - options := SessionOptions{ - CollectUser: true, - SampleRate: 97, - Metrics: metrics.New(nil), - PythonEnabled: true, - CacheOptions: symtab.CacheOptions{ - BuildIDCacheOptions: symtab.GCacheOptions{ - Size: 128, KeepRounds: 128, - }, - SameFileCacheOptions: symtab.GCacheOptions{ - Size: 128, KeepRounds: 128, - }, - PidCacheOptions: symtab.GCacheOptions{ - Size: 128, KeepRounds: 128, - }, - }, - } - s, err := NewSession( - l, - targetFinder, - options, - ) - require.NoError(t, err) - - err = s.Start() - _ = l.Log("err", err, "msg", "session.Start") - require.NoError(t, err, "Try running as privileged root user") - - impl := s.(*session) - fake_target := sd.NewTargetForTesting(containerID, 0, map[string]string{ - "service_name": "fake", - }) - perf := impl.getPyPerf(fake_target) // pyperf may take long time to load and verify, especially running in qemu with no kvm - require.NotNil(t, perf) - - return s -} - -func loadgen(t *testing.T, l log.Logger, url string, n int) { - l = log.With(l, "component", "loadgen") - orderVehicle := func(vehicle string) { - url := fmt.Sprintf("%s/%s", url, vehicle) - _ = l.Log("msg", "requesting", "url", url) - req, err := http.NewRequest("GET", url, nil) - require.NoError(t, err) - resp, err := http.DefaultClient.Do(req) - require.NoError(t, err) - body, err := io.ReadAll(resp.Body) - require.NoError(t, err) - _ = l.Log("msg", "response", "body", string(body)) - } - for i := 0; i < n; i++ { - orderVehicle("bike") - orderVehicle("car") - orderVehicle("scooter") - orderVehicle("cell_cls_issue") - orderVehicle("cell_self_issue") - } -} diff --git a/ebpf/rlimit/internal/internal_mirror.go b/ebpf/rlimit/internal/internal_mirror.go deleted file mode 100644 index 98a820d9ed..0000000000 --- a/ebpf/rlimit/internal/internal_mirror.go +++ /dev/null @@ -1,47 +0,0 @@ -//go:build linux - -package internal - -import ( - "runtime" - "unsafe" - - "golang.org/x/sys/unix" -) - -type MapType uint32 -type TypeID uint32 -type MapFlags uint32 -type ObjName [unix.BPF_OBJ_NAME_LEN]byte -type Cmd uint32 - -const ( - BPF_MAP_CREATE Cmd = 0 -) - -type MapCreateAttr struct { - MapType MapType - KeySize uint32 - ValueSize uint32 - MaxEntries uint32 - MapFlags MapFlags - InnerMapFd uint32 - NumaNode uint32 - MapName ObjName - MapIfindex uint32 - BtfFd uint32 - BtfKeyTypeId TypeID - BtfValueTypeId TypeID - BtfVmlinuxValueTypeId TypeID - MapExtra uint64 -} - -func MapCreate(attr *MapCreateAttr) (uintptr, error) { - var attr2 = unsafe.Pointer(attr) - r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(BPF_MAP_CREATE), uintptr(attr2), unsafe.Sizeof(*attr)) - runtime.KeepAlive(attr2) - if errNo == 0 { - return r1, nil - } - return r1, errNo -} diff --git a/ebpf/rlimit/rlimit.go b/ebpf/rlimit/rlimit.go deleted file mode 100644 index 549fe924df..0000000000 --- a/ebpf/rlimit/rlimit.go +++ /dev/null @@ -1,114 +0,0 @@ -//go:build linux - -// Package rlimit allows raising RLIMIT_MEMLOCK if necessary for the use of BPF. - -// this is a copied version of https://github.com/cilium/ebpf/blob/main/rlimit/rlimit.go -// with the following changes: -// 1. unsupportedMemcgAccounting = &internal.UnsupportedFeatureError replaced with unsupportedMemcgAccounting = errors.New -// to avoid importing internal package -// 2. haveMemcgAccounting is initialized once during RemoveMemlock -// 3. a bunch of internals copied to rlimit/internal/internal_mirror.go -package rlimit - -import ( - "errors" - "fmt" - "sync" - - "github.com/grafana/pyroscope/ebpf/rlimit/internal" - "golang.org/x/sys/unix" -) - -var ( - unsupportedMemcgAccounting = errors.New("unsupported memcg-based accounting for BPF memory. Minimum version: 5.11.0") - haveMemcgAccounting error - haveMemcgAccountingInit sync.Once - - rlimitMu sync.Mutex -) - -func detectMemcgAccounting() error { - // Retrieve the original limit to prevent lowering Max, since - // doing so is a permanent operation when running unprivileged. - var oldLimit unix.Rlimit - if err := unix.Prlimit(0, unix.RLIMIT_MEMLOCK, nil, &oldLimit); err != nil { - return fmt.Errorf("getting original memlock rlimit: %s", err) - } - - // Drop the current limit to zero, maintaining the old Max value. - // This is always permitted by the kernel for unprivileged users. - // Retrieve a new copy of the old limit tuple to minimize the chances - // of failing the restore operation below. - zeroLimit := unix.Rlimit{Cur: 0, Max: oldLimit.Max} - if err := unix.Prlimit(0, unix.RLIMIT_MEMLOCK, &zeroLimit, &oldLimit); err != nil { - return fmt.Errorf("lowering memlock rlimit: %s", err) - } - - attr := internal.MapCreateAttr{ - MapType: 2, /* Array */ - KeySize: 4, - ValueSize: 4, - MaxEntries: 1, - } - - // Creating a map allocates shared (and locked) memory that counts against - // the rlimit on pre-5.11 kernels, but against the memory cgroup budget on - // kernels 5.11 and over. If this call succeeds with the process' memlock - // rlimit set to 0, we can reasonably assume memcg accounting is supported. - fd, mapErr := internal.MapCreate(&attr) - defer unix.Close(int(fd)) - - // Restore old limits regardless of what happened. - if err := unix.Prlimit(0, unix.RLIMIT_MEMLOCK, &oldLimit, nil); err != nil { - return fmt.Errorf("restoring old memlock rlimit: %s", err) - } - - // Map creation successful, memcg accounting supported. - if mapErr == nil { - return nil - } - - // EPERM shows up when map creation would exceed the memory budget. - if errors.Is(mapErr, unix.EPERM) { - return unsupportedMemcgAccounting - } - - // This shouldn't happen really. - return fmt.Errorf("unexpected error detecting memory cgroup accounting: %s", mapErr) -} - -// RemoveMemlock removes the limit on the amount of memory the current -// process can lock into RAM, if necessary. -// -// This is not required to load eBPF resources on kernel versions 5.11+ -// due to the introduction of cgroup-based memory accounting. On such kernels -// the function is a no-op. -// -// Since the function may change global per-process limits it should be invoked -// at program start up, in main() or init(). -// -// This function exists as a convenience and should only be used when -// permanently raising RLIMIT_MEMLOCK to infinite is appropriate. Consider -// invoking prlimit(2) directly with a more reasonable limit if desired. -// -// Requires CAP_SYS_RESOURCE on kernels < 5.11. -func RemoveMemlock() error { - haveMemcgAccountingInit.Do(func() { - haveMemcgAccounting = detectMemcgAccounting() - }) - - if haveMemcgAccounting == nil { - return nil - } - if !errors.Is(haveMemcgAccounting, unsupportedMemcgAccounting) { - return haveMemcgAccounting - } - rlimitMu.Lock() - defer rlimitMu.Unlock() - // pid 0 affects the current process. Requires CAP_SYS_RESOURCE. - newLimit := unix.Rlimit{Cur: unix.RLIM_INFINITY, Max: unix.RLIM_INFINITY} - if err := unix.Prlimit(0, unix.RLIMIT_MEMLOCK, &newLimit, nil); err != nil { - return fmt.Errorf("failed to set memlock rlimit: %w", err) - } - return nil -} diff --git a/ebpf/sd/k8s.go b/ebpf/sd/k8s.go deleted file mode 100644 index ea5bce56ba..0000000000 --- a/ebpf/sd/k8s.go +++ /dev/null @@ -1,15 +0,0 @@ -package sd - -import "strings" - -var knownContainerIDPrefixes = []string{"docker://", "containerd://", "cri-o://"} - -// get container id from __meta_kubernetes_pod_container_id label -func getContainerIDFromK8S(k8sContainerID string) containerID { - for _, p := range knownContainerIDPrefixes { - if strings.HasPrefix(k8sContainerID, p) { - return containerID(strings.TrimPrefix(k8sContainerID, p)) - } - } - return "" -} diff --git a/ebpf/sd/procfs.go b/ebpf/sd/procfs.go deleted file mode 100644 index f9cfed7825..0000000000 --- a/ebpf/sd/procfs.go +++ /dev/null @@ -1,38 +0,0 @@ -package sd - -import ( - "bufio" - "fmt" - "regexp" -) - -var ( - // cgroupContainerIDRe matches a container ID from a /proc/{pid}}/cgroup - cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*-)?([0-9a-f]{64})(?:\.|\s*$)`) -) - -func (tf *targetFinder) getContainerIDFromPID(pid uint32) containerID { - f, err := tf.fs.Open(fmt.Sprintf("proc/%d/cgroup", pid)) - if err != nil { - return "" - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Bytes() - cid := getContainerIDFromCGroup(line) - if cid != "" { - return containerID(cid) - } - } - return "" -} - -func getContainerIDFromCGroup(line []byte) string { - matches := cgroupContainerIDRe.FindSubmatch(line) - if len(matches) <= 1 { - return "" - } - return string(matches[1]) -} diff --git a/ebpf/sd/target.go b/ebpf/sd/target.go deleted file mode 100644 index 6ec491c683..0000000000 --- a/ebpf/sd/target.go +++ /dev/null @@ -1,310 +0,0 @@ -package sd - -import ( - "fmt" - "io/fs" - "strconv" - "strings" - "sync" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - lru "github.com/hashicorp/golang-lru/v2" - "github.com/prometheus/common/model" - "github.com/prometheus/prometheus/model/labels" -) - -type DiscoveryTarget map[string]string - -func (t *DiscoveryTarget) DebugString() string { - var b strings.Builder - b.WriteByte('{') - for k, v := range *t { - b.WriteString(k) - b.WriteByte('=') - b.WriteString(v) - b.WriteByte(',') - } - b.WriteByte('}') - return b.String() -} - -const ( - labelContainerID = "__container_id__" - labelPID = "__process_pid__" - labelServiceName = "service_name" - labelServiceNameK8s = "__meta_kubernetes_pod_annotation_pyroscope_io_service_name" - metricValue = "process_cpu" - labelMetaPyroscopeOptionsPrefix = "__meta_pyroscope_ebpf_options_" - - OptionGoTableFallback = labelMetaPyroscopeOptionsPrefix + "go_table_fallback" - OptionCollectKernel = labelMetaPyroscopeOptionsPrefix + "collect_kernel" - OptionPythonFullFilePath = labelMetaPyroscopeOptionsPrefix + "python_full_file_path" - OptionPythonEnabled = labelMetaPyroscopeOptionsPrefix + "python_enabled" - OptionPythonBPFDebugLogEnabled = labelMetaPyroscopeOptionsPrefix + "python_bpf_debug_log" - OptionPythonBPFErrorLogEnabled = labelMetaPyroscopeOptionsPrefix + "python_bpf_error_log" - OptionDemangle = labelMetaPyroscopeOptionsPrefix + "demangle" -) - -type Target struct { - // todo make keep it a map until Append happens - labels labels.Labels - serviceName string - fingerprint uint64 - fingerprintCalculated bool -} - -// todo remove, make containerID exported or use string -func NewTargetForTesting(cid string, pid uint32, target DiscoveryTarget) *Target { - return NewTarget(containerID(cid), pid, target) -} - -func NewTarget(cid containerID, pid uint32, target DiscoveryTarget) *Target { - serviceName := target[labelServiceName] - if serviceName == "" { - serviceName = inferServiceName(target) - } - - lset := make(map[string]string, len(target)) - for k, v := range target { - if strings.HasPrefix(k, model.ReservedLabelPrefix) && - k != labels.MetricName && - !strings.HasPrefix(k, labelMetaPyroscopeOptionsPrefix) { - continue - } - lset[k] = v - } - if lset[labels.MetricName] == "" { - lset[labels.MetricName] = metricValue - } - if lset[labelServiceName] == "" { - lset[labelServiceName] = serviceName - } - if cid != "" { - lset[labelContainerID] = string(cid) - } - if pid != 0 { - lset[labelPID] = strconv.Itoa(int(pid)) - } - return &Target{ - labels: labels.FromMap(lset), - serviceName: serviceName, - } -} - -func (t *Target) ServiceName() string { - return t.serviceName -} - -func inferServiceName(target DiscoveryTarget) string { - k8sServiceName := target[labelServiceNameK8s] - if k8sServiceName != "" { - return k8sServiceName - } - k8sNamespace := target["__meta_kubernetes_namespace"] - k8sContainer := target["__meta_kubernetes_pod_container_name"] - if k8sNamespace != "" && k8sContainer != "" { - return fmt.Sprintf("ebpf/%s/%s", k8sNamespace, k8sContainer) - } - dockerContainer := target["__meta_docker_container_name"] - if dockerContainer != "" { - return dockerContainer - } - if swarmService := target["__meta_dockerswarm_container_label_service_name"]; swarmService != "" { - return swarmService - } - if swarmService := target["__meta_dockerswarm_service_name"]; swarmService != "" { - return swarmService - } - return "unspecified" -} - -func (t *Target) Labels() (uint64, labels.Labels) { - if !t.fingerprintCalculated { - t.fingerprint = t.labels.Hash() - t.fingerprintCalculated = true - } - return t.fingerprint, t.labels -} - -func (t *Target) String() string { - return t.labels.String() -} - -func (t *Target) Get(k string) (string, bool) { - v := t.labels.Get(k) - return v, v != "" -} - -func (t *Target) GetFlag(k string) (bool, bool) { - v := t.labels.Get(k) - return v == "true", v != "" -} - -type containerID string - -type TargetFinder interface { - FindTarget(pid uint32) *Target - RemoveDeadPID(pid uint32) - DebugInfo() []map[string]string - Update(args TargetsOptions) -} -type TargetsOptions struct { - Targets []DiscoveryTarget - TargetsOnly bool - DefaultTarget DiscoveryTarget - ContainerCacheSize int -} - -type targetFinder struct { - l log.Logger - cid2target map[containerID]*Target - pid2target map[uint32]*Target - - // todo make it never evict during a reset - containerIDCache *lru.Cache[uint32, containerID] - defaultTarget *Target - fs fs.FS - - sync sync.Mutex -} - -func NewTargetFinder(fs fs.FS, l log.Logger, options TargetsOptions) (TargetFinder, error) { - containerIDCache, err := lru.New[uint32, containerID](options.ContainerCacheSize) - if err != nil { - return nil, fmt.Errorf("containerIDCache create: %w", err) - } - res := &targetFinder{ - l: l, - containerIDCache: containerIDCache, - fs: fs, - } - res.setTargets(options) - return res, nil -} - -func (tf *targetFinder) FindTarget(pid uint32) *Target { - tf.sync.Lock() - defer tf.sync.Unlock() - res := tf.findTarget(pid) - if res != nil { - return res - } - return tf.defaultTarget -} - -func (tf *targetFinder) RemoveDeadPID(pid uint32) { - tf.sync.Lock() - defer tf.sync.Unlock() - tf.containerIDCache.Remove(pid) - delete(tf.pid2target, pid) -} - -func (tf *targetFinder) Update(args TargetsOptions) { - tf.sync.Lock() - defer tf.sync.Unlock() - tf.setTargets(args) - tf.resizeContainerIDCache(args.ContainerCacheSize) -} - -func (tf *targetFinder) setTargets(opts TargetsOptions) { - _ = level.Debug(tf.l).Log("msg", "set targets", "count", len(opts.Targets)) - containerID2Target := make(map[containerID]*Target) - pid2Target := make(map[uint32]*Target) - for _, target := range opts.Targets { - if pid := pidFromTarget(target); pid != 0 { - t := NewTarget("", pid, target) - pid2Target[pid] = t - } else if cid := containerIDFromTarget(target); cid != "" { - t := NewTarget(cid, 0, target) - containerID2Target[cid] = t - } - } - if len(opts.Targets) > 0 && len(containerID2Target) == 0 && len(pid2Target) == 0 { - _ = level.Warn(tf.l).Log("msg", "No targets found") - } - tf.cid2target = containerID2Target - tf.pid2target = pid2Target - if opts.TargetsOnly { - tf.defaultTarget = nil - } else { - t := NewTarget("", 0, opts.DefaultTarget) - tf.defaultTarget = t - } - _ = level.Debug(tf.l).Log("msg", "created targets", "count", len(tf.cid2target)) -} - -func (tf *targetFinder) findTarget(pid uint32) *Target { - if target, ok := tf.pid2target[pid]; ok { - return target - } - cid, ok := tf.containerIDCache.Get(pid) - if ok { - return tf.cid2target[cid] - } - - cid = tf.getContainerIDFromPID(pid) - tf.containerIDCache.Add(pid, cid) - return tf.cid2target[cid] -} - -func (tf *targetFinder) resizeContainerIDCache(size int) { - tf.containerIDCache.Resize(size) -} - -func (tf *targetFinder) DebugInfo() []map[string]string { - tf.sync.Lock() - defer tf.sync.Unlock() - - debugTargets := make([]map[string]string, 0, len(tf.cid2target)) - for _, target := range tf.cid2target { - - _, ls := target.Labels() - debugTargets = append(debugTargets, ls.Map()) - } - return debugTargets -} - -func (tf *targetFinder) Targets() []*Target { - tf.sync.Lock() - defer tf.sync.Unlock() - - res := make([]*Target, 0, len(tf.cid2target)) - for _, target := range tf.cid2target { - res = append(res, target) - } - return res -} - -func pidFromTarget(target DiscoveryTarget) uint32 { - t, ok := target[labelPID] - if !ok { - return 0 - } - var pid uint64 - var err error - pid, err = strconv.ParseUint(t, 10, 32) - if err != nil { - return 0 - } - return uint32(pid) -} - -func containerIDFromTarget(target DiscoveryTarget) containerID { - cid, ok := target[labelContainerID] - if ok && cid != "" { - return containerID(cid) - } - cid, ok = target["__meta_kubernetes_pod_container_id"] - if ok && cid != "" { - return getContainerIDFromK8S(cid) - } - cid, ok = target["__meta_docker_container_id"] - if ok && cid != "" { - return containerID(cid) - } - if cid, ok = target["__meta_dockerswarm_task_container_id"]; ok && cid != "" { - return containerID(cid) - } - return "" -} diff --git a/ebpf/sd/target_test.go b/ebpf/sd/target_test.go deleted file mode 100644 index 5d53bc8ccb..0000000000 --- a/ebpf/sd/target_test.go +++ /dev/null @@ -1,185 +0,0 @@ -package sd - -import ( - "fmt" - "io/fs" - "os" - "path/filepath" - "testing" - - "github.com/grafana/pyroscope/ebpf/util" - - "github.com/stretchr/testify/require" -) - -func TestCGroupMatching(t *testing.T) { - type testcase = struct { - containerID, cgroup, expectedID string - } - testcases := []testcase{ - { - containerID: "containerd://a534eb629135e43beb13213976e37bb2ab95cba4c0d1d0b4e27c6bc4d8091b83", - cgroup: "12:cpuset:/kubepods.slice/kubepods-burstable.slice/" + - "kubepods-burstable-pod471203d1_984f_477e_9c35_db96487ffe5e.slice/" + - "cri-containerd-a534eb629135e43beb13213976e37bb2ab95cba4c0d1d0b4e27c6bc4d8091b83.scope", - expectedID: "a534eb629135e43beb13213976e37bb2ab95cba4c0d1d0b4e27c6bc4d8091b83", - }, - { - containerID: "cri-o://0ecc7949cbaf17e883264ea1055f60b184a7cb264fd759c4a692e1155086fe2d", - cgroup: "0::/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podb57320a0_e7eb_4ac8_a791_4c4472796867.slice/" + - "crio-0ecc7949cbaf17e883264ea1055f60b184a7cb264fd759c4a692e1155086fe2d.scope", - expectedID: "0ecc7949cbaf17e883264ea1055f60b184a7cb264fd759c4a692e1155086fe2d", - }, - { - - containerID: "docker://656959d9ee87a0b131c601ce9d9f8f76b1dda60e8608c503b5979d849cbdc714", - cgroup: "0::/../../kubepods-besteffort-pod88f6f4e3_59c0_4ce8_9ecf_391c8b5a60ad.slice/" + - "docker-656959d9ee87a0b131c601ce9d9f8f76b1dda60e8608c503b5979d849cbdc714.scope", - expectedID: "656959d9ee87a0b131c601ce9d9f8f76b1dda60e8608c503b5979d849cbdc714", - }, - { - containerID: "containerd://47e320f795efcec1ecf2001c3a09c95e3701ed87de8256837b70b10e23818251", - cgroup: "0::/kubepods.slice/kubepods-burstable.slice/" + - "kubepods-burstable-podf9a04ecc_1875_491b_926c_d2f64757704e.slice/" + - "cri-containerd-47e320f795efcec1ecf2001c3a09c95e3701ed87de8256837b70b10e23818251.scope", - expectedID: "47e320f795efcec1ecf2001c3a09c95e3701ed87de8256837b70b10e23818251", - }, - { - containerID: "docker://7edda1de1e0d1d366351e478359cf5fa16bb8ab53063a99bb119e56971bfb7e2", - cgroup: "11:devices:/kubepods/besteffort/pod85adbef3-622f-4ef2-8f60-a8bdf3eb6c72/" + - "7edda1de1e0d1d366351e478359cf5fa16bb8ab53063a99bb119e56971bfb7e2", - expectedID: "7edda1de1e0d1d366351e478359cf5fa16bb8ab53063a99bb119e56971bfb7e2", - }, - { - containerID: "", - cgroup: "0::/../../user.slice/user-501.slice/session-3.scope", - expectedID: "", - }, - } - for i, tc := range testcases { - t.Run(fmt.Sprintf("testcase %d %s", i, tc.cgroup), func(t *testing.T) { - cid := getContainerIDFromCGroup([]byte(tc.cgroup)) - expected := tc.expectedID - require.Equal(t, expected, cid) - cid = string(getContainerIDFromK8S(tc.containerID)) - require.Equal(t, expected, cid) - }) - } -} - -type mockFS struct { - root fs.FS - rootPath string -} - -func newMockFS() (*mockFS, error) { - temp, err := os.MkdirTemp("", "TestTargetFinder") - if err != nil { - return nil, err - } - return &mockFS{ - rootPath: temp, - root: os.DirFS(temp), - }, nil -} - -func (fs *mockFS) add(path string, data []byte) error { - fpath := filepath.Join(fs.rootPath, path) - dir := filepath.Dir(fpath) - if _, err := os.Stat(dir); err != nil { - err = os.MkdirAll(dir, 0770) - if err != nil { - return err - } - } - return os.WriteFile(fpath, data, 0660) -} - -func (fs *mockFS) rm() { - _ = os.RemoveAll(fs.rootPath) -} - -func TestTargetFinder(t *testing.T) { - fs, err := newMockFS() - require.NoError(t, err) - defer fs.rm() - err = fs.add("/proc/1801264/cgroup", - []byte("12:blkio:/kubepods/burstable/pod7e5f5ac0-1af4-49ab-8938-664970a26cfd/9a7c72f122922fe3445ba85ce72c507c8976c0f3d919403fda7c22dfe516f66f")) - require.NoError(t, err) - err = fs.add("/proc/489323/cgroup", - []byte("12:blkio:/kubepods/burstable/pod83ca8044-3e7c-457b-8647-a21dabad5079/57ac76ffc93d7e7735ca186bc67115656967fc8aecbe1f65526c4c48b033e6a5")) - require.NoError(t, err) - - options := TargetsOptions{ - Targets: []DiscoveryTarget{ - map[string]string{ - "__meta_kubernetes_pod_container_id": "containerd://9a7c72f122922fe3445ba85ce72c507c8976c0f3d919403fda7c22dfe516f66f", - "__meta_kubernetes_namespace": "foo", - "__meta_kubernetes_pod_container_name": "bar", - }, - map[string]string{ - "__container_id__": "57ac76ffc93d7e7735ca186bc67115656967fc8aecbe1f65526c4c48b033e6a5", - "__meta_kubernetes_namespace": "qwe", - "__meta_kubernetes_pod_container_name": "asd", - }, - }, - TargetsOnly: true, - DefaultTarget: nil, - ContainerCacheSize: 1024, - } - - tf, err := NewTargetFinder(fs.root, util.TestLogger(t), options) - require.NoError(t, err) - - target := tf.FindTarget(1801264) - require.NotNil(t, target) - require.Equal(t, "ebpf/foo/bar", target.labels.Get("service_name")) - - target = tf.FindTarget(489323) - require.NotNil(t, target) - require.Equal(t, "ebpf/qwe/asd", target.labels.Get("service_name")) - - target = tf.FindTarget(239) - require.Nil(t, target) -} - -func TestPreferPIDOverContainerID(t *testing.T) { - fs, err := newMockFS() - require.NoError(t, err) - defer fs.rm() - - options := TargetsOptions{ - Targets: []DiscoveryTarget{ - map[string]string{ - "__meta_kubernetes_pod_container_id": "containerd://9a7c72f122922fe3445ba85ce72c507c8976c0f3d919403fda7c22dfe516f66f", - "__meta_kubernetes_namespace": "foo", - "__meta_kubernetes_pod_container_name": "bar", - "__process_pid__": "1801264", - "exe": "/bin/bash", - }, - map[string]string{ - "__meta_kubernetes_pod_container_id": "containerd://9a7c72f122922fe3445ba85ce72c507c8976c0f3d919403fda7c22dfe516f66f", - "__meta_kubernetes_namespace": "foo", - "__meta_kubernetes_pod_container_name": "bar", - "__process_pid__": "1801265", - "exe": "/bin/dash", - }, - }, - TargetsOnly: true, - DefaultTarget: nil, - ContainerCacheSize: 1024, - } - - tf, err := NewTargetFinder(fs.root, util.TestLogger(t), options) - require.NoError(t, err) - - target := tf.FindTarget(1801264) - require.NotNil(t, target) - require.Equal(t, "ebpf/foo/bar", target.labels.Get("service_name")) - require.Equal(t, "/bin/bash", target.labels.Get("exe")) - - target = tf.FindTarget(1801265) - require.NotNil(t, target) - require.Equal(t, "ebpf/foo/bar", target.labels.Get("service_name")) - require.Equal(t, "/bin/dash", target.labels.Get("exe")) -} diff --git a/ebpf/session.go b/ebpf/session.go deleted file mode 100644 index 4883255b7f..0000000000 --- a/ebpf/session.go +++ /dev/null @@ -1,946 +0,0 @@ -//go:build linux - -// Package ebpfspy provides integration with Linux eBPF. It is a rough copy of profile.py from BCC tools: -// -// https://github.com/iovisor/bcc/blob/master/tools/profile.py -package ebpfspy - -import ( - _ "embed" - "encoding/binary" - "errors" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - "sync" - "syscall" - - "github.com/cilium/ebpf" - "github.com/cilium/ebpf/btf" - "github.com/cilium/ebpf/link" - "github.com/cilium/ebpf/perf" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/cpp/demangle" - "github.com/grafana/pyroscope/ebpf/cpuonline" - "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/grafana/pyroscope/ebpf/pprof" - "github.com/grafana/pyroscope/ebpf/pyrobpf" - "github.com/grafana/pyroscope/ebpf/python" - "github.com/grafana/pyroscope/ebpf/rlimit" - "github.com/grafana/pyroscope/ebpf/sd" - "github.com/grafana/pyroscope/ebpf/symtab" - "github.com/samber/lo" -) - -type SessionOptions struct { - CollectUser bool //todo make these per target option overridable - CollectKernel bool - UnknownSymbolModuleOffset bool // use libfoo.so+0xef instead of libfoo.so for unknown symbols - UnknownSymbolAddress bool // use 0xcafebabe instead of [unknown] - PythonEnabled bool - CacheOptions symtab.CacheOptions - SymbolOptions symtab.SymbolOptions - Metrics *metrics.Metrics - SampleRate int - VerifierLogSize int - PythonBPFErrorLogEnabled bool - PythonBPFDebugLogEnabled bool - BPFMapsOptions BPFMapsOptions -} - -type BPFMapsOptions struct { - PIDMapSize uint32 - SymbolsMapSize uint32 -} - -type Session interface { - pprof.SamplesCollector - Start() error - Stop() - Update(SessionOptions) error - UpdateTargets(args sd.TargetsOptions) - DebugInfo() interface{} -} - -type SessionDebugInfo struct { - ElfCache symtab.ElfCacheDebugInfo `alloy:"elf_cache,attr,optional" river:"elf_cache,attr,optional"` - PidCache symtab.GCacheDebugInfo[symtab.ProcTableDebugInfo] `alloy:"pid_cache,attr,optional" river:"pid_cache,attr,optional"` - Arch string `alloy:"arch,attr" river:"arch,attr"` - Kernel string `alloy:"kernel,attr" river:"kernel,attr"` -} - -type pids struct { - // processes not selected for profiling by sd - unknown map[uint32]struct{} - // got a pid dead event or errored during refresh - dead map[uint32]struct{} - // contains all known pids, same as ebpf pids map but without unknowns - all map[uint32]procInfoLite -} -type session struct { - logger log.Logger - - targetFinder sd.TargetFinder - - perfEvents []*perfEvent - - symCache *symtab.SymbolCache - - bpf pyrobpf.ProfileObjects - - eventsReader *perf.Reader - pidInfoRequests chan uint32 - deadPIDEvents chan uint32 - - options SessionOptions - roundNumber int - - // all the Session methods should be guarded by mutex - // all the goroutines accessing fields should be guarded by mutex and check for started field - mutex sync.Mutex - // We have 3 goroutines - // 1 - reading perf events from ebpf. this one does not touch Session fields including mutex - // 2 - processing pid info requests. this one Session fields to update pid info and python info, this should be done under mutex - // 3 - processing pid dead events - // Accessing wg should be done with no Session.mutex held to avoid deadlock, therefore wg access (Start, Stop) should be - // synchronized outside - wg sync.WaitGroup - started bool - kprobes []link.Link - - pyperf *python.Perf - pyperfEvents []*python.PerfPyEvent - pyperfBpf python.PerfObjects - pyperfError error - - pids pids - pidExecRequests chan uint32 -} - -func NewSession( - logger log.Logger, - targetFinder sd.TargetFinder, - - sessionOptions SessionOptions, -) (Session, error) { - symCache, err := symtab.NewSymbolCache(logger, sessionOptions.CacheOptions, sessionOptions.Metrics.Symtab) - if err != nil { - return nil, err - } - - return &session{ - logger: logger, - symCache: symCache, - - targetFinder: targetFinder, - options: sessionOptions, - pids: pids{ - unknown: make(map[uint32]struct{}), - dead: make(map[uint32]struct{}), - all: make(map[uint32]procInfoLite), - }, - }, nil -} - -func (s *session) Start() error { - s.printDebugInfo() - s.mutex.Lock() - defer s.mutex.Unlock() - var err error - - if err = rlimit.RemoveMemlock(); err != nil { - return err - } - - opts := &ebpf.CollectionOptions{ - Programs: s.progOptions(), - } - spec, err := pyrobpf.LoadProfile() - if err != nil { - return fmt.Errorf("pyrobpf load %w", err) - } - if s.options.BPFMapsOptions.PIDMapSize != 0 { - spec.Maps[pyrobpf.MapNamePIDs].MaxEntries = s.options.BPFMapsOptions.PIDMapSize - } - - _, nsIno, err := getPIDNamespace() - if err != nil { - return fmt.Errorf("unable to get pid namespace %w", err) - } - err = spec.RewriteConstants(map[string]interface{}{ - "global_config": pyrobpf.ProfileGlobalConfigT{ - NsPidIno: nsIno, - }, - }) - if err != nil { - return fmt.Errorf("pyrobpf rewrite constants %w", err) - } - err = spec.LoadAndAssign(&s.bpf, opts) - if err != nil { - s.logVerifierError(err) - s.stopLocked() - return fmt.Errorf("load bpf objects: %w", err) - } - - btf.FlushKernelSpec() // save some memory - - eventsReader, err := perf.NewReader(s.bpf.ProfileMaps.Events, 4*os.Getpagesize()) - if err != nil { - s.stopLocked() - return fmt.Errorf("perf new reader for events map: %w", err) - } - s.perfEvents, err = attachPerfEvents(s.options.SampleRate, s.bpf.DoPerfEvent) - if err != nil { - s.stopLocked() - return fmt.Errorf("attach perf events: %w", err) - } - - err = s.linkKProbes() - if err != nil { - s.stopLocked() - return fmt.Errorf("link kprobes: %w", err) - } - - s.eventsReader = eventsReader - pidInfoRequests := make(chan uint32, 1024) - pidExecRequests := make(chan uint32, 1024) - deadPIDsEvents := make(chan uint32, 1024) - s.pidInfoRequests = pidInfoRequests - s.pidExecRequests = pidExecRequests - s.deadPIDEvents = deadPIDsEvents - s.wg.Add(4) - s.started = true - go func() { - defer s.wg.Done() - s.readEvents(eventsReader, pidInfoRequests, pidExecRequests, deadPIDsEvents) - }() - go func() { - defer s.wg.Done() - s.processPidInfoRequests(pidInfoRequests) - }() - go func() { - defer s.wg.Done() - s.processDeadPIDsEvents(deadPIDsEvents) - }() - go func() { - defer s.wg.Done() - s.processPIDExecRequests(pidExecRequests) - }() - return nil -} - -func (s *session) Stop() { - s.stopAndWait() -} - -func (s *session) Update(options SessionOptions) error { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.symCache.UpdateOptions(options.CacheOptions) - s.options = options - return nil -} - -func (s *session) UpdateTargets(args sd.TargetsOptions) { - s.targetFinder.Update(args) - - s.mutex.Lock() - defer s.mutex.Unlock() - - for pid := range s.pids.unknown { - target := s.targetFinder.FindTarget(pid) - if target == nil { - continue - } - s.startProfilingLocked(pid, target) - delete(s.pids.unknown, pid) - } -} - -func (s *session) CollectProfiles(cb pprof.CollectProfilesCallback) error { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.symCache.NextRound() - s.roundNumber++ - - err := s.collectRegularProfile(cb) - if err != nil { - return err - } - - s.cleanup() - - return nil -} - -func (s *session) DebugInfo() interface{} { - pv, _ := os.ReadFile("/proc/version") - s.mutex.Lock() - defer s.mutex.Unlock() - return SessionDebugInfo{ - ElfCache: s.symCache.ElfCacheDebugInfo(), - PidCache: s.symCache.PidCacheDebugInfo(), - Arch: runtime.GOARCH, - Kernel: string(pv), - } -} - -func (s *session) collectRegularProfile(cb pprof.CollectProfilesCallback) error { - sb := &stackBuilder{} - - keys, values, batch, err := s.getCountsMapValues() - if err != nil { - return fmt.Errorf("get counts map: %w", err) - } - - knownStacks := map[uint32]bool{} - knownPythonStacks := map[uint32]bool{} - var pySymbols *python.LazySymbols - if s.pyperf != nil { - pySymbols = s.pyperf.GetLazySymbols() - } - - for i := range keys { - ck := &keys[i] - value := values[i] - isPythonStack := ck.Flags&uint32(pyrobpf.SampleKeyFlagPythonStack) != 0 - if ck.UserStack > 0 { - if isPythonStack { - knownPythonStacks[uint32(ck.UserStack)] = true - } else { - knownStacks[uint32(ck.UserStack)] = true - } - } - if ck.KernStack >= 0 { - knownStacks[uint32(ck.KernStack)] = true - } - target := s.targetFinder.FindTarget(ck.Pid) - if target == nil { - continue - } - if _, ok := s.pids.dead[ck.Pid]; ok { - continue - } - - pk := symtab.PidKey(ck.Pid) - - var uStack []byte - var kStack []byte - if s.options.CollectUser { - if isPythonStack { - uStack = s.GetPythonStack(ck.UserStack) //todo lookup batch - } else { - uStack = s.GetStack(ck.UserStack) - } - } - if s.options.CollectKernel { - kStack = s.GetStack(ck.KernStack) - } - - stats := StackResolveStats{} - sb.reset() - sb.append(s.comm(ck.Pid)) - if s.options.CollectUser { - if isPythonStack { - pyProc := s.pyperf.FindProc(ck.Pid) - if pyProc != nil { - s.WalkPythonStack(sb, uStack, target, pyProc, pySymbols, &stats) - } - } else { - proc := s.symCache.GetProcTableCached(pk) - if proc == nil { - proc = s.symCache.NewProcTable(pk, s.targetSymbolOptions(target)) // todo make the creation of it at profiling type selection - } - if proc.Error() != nil { - s.pids.dead[uint32(proc.Pid())] = struct{}{} - // in theory if we saw this process alive before, we could try resolving tack anyway - // it may succeed if we have same binary loaded in another process, not doing it for now - continue - } else { - s.WalkStack(sb, uStack, proc, &stats) - } - } - } - if s.options.CollectKernel { - s.WalkStack(sb, kStack, s.symCache.GetKallsyms(), &stats) - } - if len(sb.stack) == 1 { - continue // only comm - } - lo.Reverse(sb.stack) - cb(pprof.ProfileSample{ - Target: target, - Pid: ck.Pid, - Aggregation: pprof.SampleAggregated, - SampleType: pprof.SampleTypeCpu, - Stack: sb.stack, - Value: uint64(value), - }) - s.collectMetrics(target, &stats, sb) - } - - if err = s.clearCountsMap(keys, batch); err != nil { - return fmt.Errorf("clear counts map %w", err) - } - if err = s.clearStacksMap(knownStacks, s.bpf.Stacks); err != nil { - return fmt.Errorf("clear stacks map %w", err) - } - if s.pyperfBpf.PythonStacks != nil && len(knownPythonStacks) > 0 { - if err = s.clearStacksMap(knownPythonStacks, s.pyperfBpf.PythonStacks); err != nil { //todo use batchdelete - return fmt.Errorf("clear stacks map %w", err) - } - } - return nil -} - -func (s *session) comm(pid uint32) string { - comm := s.pids.all[pid].comm - if comm != "" { - return comm - } - return "pid_unknown" -} - -func (s *session) collectMetrics(labels *sd.Target, stats *StackResolveStats, sb *stackBuilder) { - m := s.options.Metrics.Symtab - serviceName := labels.ServiceName() - if m != nil { - m.KnownSymbols.WithLabelValues(serviceName).Add(float64(stats.known)) - m.UnknownSymbols.WithLabelValues(serviceName).Add(float64(stats.unknownSymbols)) - m.UnknownModules.WithLabelValues(serviceName).Add(float64(stats.unknownModules)) - } - if len(sb.stack) > 2 && stats.unknownSymbols+stats.unknownModules > stats.known { - m.UnknownStacks.WithLabelValues(serviceName).Inc() - } -} - -func (s *session) stopAndWait() { - s.mutex.Lock() - s.stopLocked() - s.mutex.Unlock() - - s.wg.Wait() -} - -func (s *session) stopLocked() { - for _, pe := range s.perfEvents { - _ = pe.Close() - } - s.perfEvents = nil - for _, kprobe := range s.kprobes { - _ = kprobe.Close() - } - s.kprobes = nil - _ = s.bpf.Close() - if s.pyperf != nil { - s.pyperf = nil - } - if s.eventsReader != nil { - err := s.eventsReader.Close() - if err != nil { - _ = level.Error(s.logger).Log("err", err, "msg", "closing events map reader") - } - s.eventsReader = nil - } - if s.pidInfoRequests != nil { - close(s.pidInfoRequests) - s.pidInfoRequests = nil - } - if s.deadPIDEvents != nil { - close(s.deadPIDEvents) - s.deadPIDEvents = nil - } - if s.pidExecRequests != nil { - close(s.pidExecRequests) - s.pidExecRequests = nil - } - s.started = false -} - -func (s *session) setPidConfig(pid uint32, pi procInfoLite, collectUser bool, collectKernel bool) { - s.pids.all[pid] = pi - config := &pyrobpf.ProfilePidConfig{ - Type: uint8(pi.typ), - CollectUser: uint8FromBool(collectUser), - CollectKernel: uint8FromBool(collectKernel), - } - - if err := s.bpf.Pids.Update(&pid, config, ebpf.UpdateAny); err != nil { - _ = level.Error(s.logger).Log("msg", "updating pids map", "err", err) - } -} - -func uint8FromBool(b bool) uint8 { - if b { - return 1 - } - return 0 -} - -func attachPerfEvents(sampleRate int, prog *ebpf.Program) ([]*perfEvent, error) { - var perfEvents []*perfEvent - var cpus []uint - var err error - if cpus, err = cpuonline.Get(); err != nil { - return nil, fmt.Errorf("get cpuonline: %w", err) - } - for _, cpu := range cpus { - pe, err := newPerfEvent(int(cpu), sampleRate) - if err != nil { - return perfEvents, fmt.Errorf("new perf event: %w", err) - } - perfEvents = append(perfEvents, pe) - - err = pe.attachPerfEvent(prog) - if err != nil { - return perfEvents, fmt.Errorf("attach perf event: %w", err) - } - } - return perfEvents, nil -} - -func (s *session) GetStack(stackId int64) []byte { - if stackId < 0 { - return nil - } - stackIdU32 := uint32(stackId) - res, err := s.bpf.ProfileMaps.Stacks.LookupBytes(stackIdU32) - if err != nil { - return nil - } - return res -} - -type StackResolveStats struct { - known uint32 - unknownSymbols uint32 - unknownModules uint32 -} - -func (s *StackResolveStats) add(other StackResolveStats) { - s.known += other.known - s.unknownSymbols += other.unknownSymbols - s.unknownModules += other.unknownModules -} - -// WalkStack goes over stack, resolves symbols and appends top sb -// stack is an array of 127 uint64s, where each uint64 is an instruction pointer -func (s *session) WalkStack(sb *stackBuilder, stack []byte, resolver symtab.SymbolTable, stats *StackResolveStats) { - if len(stack) == 0 { - return - } - begin := len(sb.stack) - for i := 0; i < 127; i++ { - instructionPointerBytes := stack[i*8 : i*8+8] - instructionPointer := binary.LittleEndian.Uint64(instructionPointerBytes) - if instructionPointer == 0 { - break - } - sym := resolver.Resolve(instructionPointer) - var name string - if sym.Name != "" { - name = sym.Name - stats.known++ - } else { - if sym.Module != "" { - if s.options.UnknownSymbolModuleOffset { - name = fmt.Sprintf("%s+%x", sym.Module, sym.Start) - } else { - name = sym.Module - } - stats.unknownSymbols++ - } else { - if s.options.UnknownSymbolAddress { - name = fmt.Sprintf("%x", instructionPointer) - } else { - name = "[unknown]" - } - stats.unknownModules++ - } - } - sb.append(name) - } - end := len(sb.stack) - lo.Reverse(sb.stack[begin:end]) - -} - -func (s *session) readEvents(events *perf.Reader, - pidConfigRequest chan<- uint32, - pidExecRequest chan<- uint32, - deadPIDsEvents chan<- uint32) { - defer events.Close() - for { - record, err := events.Read() - if err != nil { - if errors.Is(err, perf.ErrClosed) { - return - } - _ = level.Error(s.logger).Log("msg", "reading from perf event reader", "err", err) - continue - } - - if record.LostSamples != 0 { - // this should not happen, should implement a fallback at reset time - _ = level.Error(s.logger).Log("err", "perf event ring buffer full, dropped samples", "n", record.LostSamples) - } - - if record.RawSample != nil { - if len(record.RawSample) < 8 { - _ = level.Error(s.logger).Log("msg", "perf event record too small", "len", len(record.RawSample)) - continue - } - e := pyrobpf.ProfilePidEvent{} - e.Op = binary.LittleEndian.Uint32(record.RawSample[0:4]) - e.Pid = binary.LittleEndian.Uint32(record.RawSample[4:8]) - //_ = level.Debug(s.logger).Log("msg", "perf event record", "op", e.Op, "pid", e.Pid) - if e.Op == uint32(pyrobpf.PidOpRequestUnknownProcessInfo) { - select { - case pidConfigRequest <- e.Pid: - default: - _ = level.Error(s.logger).Log("msg", "pid info request queue full, dropping request", "pid", e.Pid) - // this should not happen, should implement a fallback at reset time - } - } else if e.Op == uint32(pyrobpf.PidOpDead) { - select { - case deadPIDsEvents <- e.Pid: - default: - _ = level.Error(s.logger).Log("msg", "dead pid info queue full, dropping event", "pid", e.Pid) - } - } else if e.Op == uint32(pyrobpf.PidOpRequestExecProcessInfo) { - select { - case pidExecRequest <- e.Pid: - default: - _ = level.Error(s.logger).Log("msg", "pid exec request queue full, dropping event", "pid", e.Pid) - } - } else { - _ = level.Error(s.logger).Log("msg", "unknown perf event record", "op", e.Op, "pid", e.Pid) - } - } - } -} - -func (s *session) processPidInfoRequests(pidInfoRequests <-chan uint32) { - for pid := range pidInfoRequests { - target := s.targetFinder.FindTarget(pid) - - func() { - s.mutex.Lock() - defer s.mutex.Unlock() - - _, alreadyDead := s.pids.dead[pid] - if alreadyDead { - return - } - - if target == nil { - s.saveUnknownPIDLocked(pid) - } else { - s.startProfilingLocked(pid, target) - } - }() - } -} - -func (s *session) startProfilingLocked(pid uint32, target *sd.Target) { - if !s.started { - return - } - typ := s.selectProfilingType(pid, target) - if typ.typ == pyrobpf.ProfilingTypePython { - go s.tryStartPythonProfiling(pid, target, typ) - return - } - if s.pyperf != nil { - pyproc := s.pyperf.FindProc(pid) - if pyproc != nil { - s.pyperf.RemoveDeadPID(pid) - } - } - s.setPidConfig(pid, typ, s.options.CollectUser, s.collectKernelEnabled(target)) -} - -type procInfoLite struct { - pid uint32 - comm string - exe string - typ pyrobpf.ProfilingType -} - -func (s *session) selectProfilingType(pid uint32, target *sd.Target) procInfoLite { - exePath, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pid)) - if err != nil { - _ = s.procErrLogger(err).Log("err", err, "msg", "select profiling type failed", "pid", pid) - return procInfoLite{pid: pid, typ: pyrobpf.ProfilingTypeError} - } - comm, err := os.ReadFile(fmt.Sprintf("/proc/%d/comm", pid)) - if err != nil { - _ = s.procErrLogger(err).Log("err", err, "msg", "select profiling type failed", "pid", pid) - return procInfoLite{pid: pid, typ: pyrobpf.ProfilingTypeError} - } - if comm[len(comm)-1] == '\n' { - comm = comm[:len(comm)-1] - } - exe := filepath.Base(exePath) - - if s.pythonEnabled(target) && strings.HasPrefix(exe, "python") || exe == "uwsgi" { - return procInfoLite{pid: pid, comm: string(comm), typ: pyrobpf.ProfilingTypePython} - } - return procInfoLite{pid: pid, comm: string(comm), typ: pyrobpf.ProfilingTypeFramepointers} -} - -func (s *session) procErrLogger(err error) log.Logger { - if errors.Is(err, os.ErrNotExist) { - return level.Debug(s.logger) - } else { - return level.Error(s.logger) - } -} - -func (s *session) procAliveLogger(alive bool) log.Logger { - if alive { - return level.Error(s.logger) - } else { - return level.Debug(s.logger) - } -} - -// this is mostly needed for first discovery reset -// we started receiving profiles before first sd completed -// or a new process started in between sd runs -// this may be not needed after process discovery implemented -func (s *session) saveUnknownPIDLocked(pid uint32) { - s.pids.unknown[pid] = struct{}{} -} - -func (s *session) processDeadPIDsEvents(dead chan uint32) { - for pid := range dead { - func() { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.pids.dead[pid] = struct{}{} // keep them until next round - }() - } -} - -func (s *session) processPIDExecRequests(requests chan uint32) { - for pid := range requests { - target := s.targetFinder.FindTarget(pid) - func() { - s.mutex.Lock() - defer s.mutex.Unlock() - - _, alreadyDead := s.pids.dead[pid] - if alreadyDead { - return - } - - if target == nil { - s.saveUnknownPIDLocked(pid) - } else { - s.startProfilingLocked(pid, target) - } - }() - } -} - -func (s *session) linkKProbes() error { - type hook struct { - kprobe string - prog *ebpf.Program - required bool - } - var hooks []hook - - hooks = []hook{ - {kprobe: "disassociate_ctty", prog: s.bpf.DisassociateCtty, required: true}, - {kprobe: "sys_execve", prog: s.bpf.Exec, required: false}, - {kprobe: "sys_execveat", prog: s.bpf.Exec, required: false}, - } - for _, it := range hooks { - kp, err := link.Kprobe(it.kprobe, it.prog, nil) - if err != nil { - if it.required { - return fmt.Errorf("link kprobe %s: %w", it.kprobe, err) - } - _ = level.Error(s.logger).Log("msg", "link kprobe", "kprobe", it.kprobe, "err", err) - } - s.kprobes = append(s.kprobes, kp) - } - return nil - -} - -func (s *session) cleanup() { - s.symCache.Cleanup() - - for pid := range s.pids.dead { - delete(s.pids.dead, pid) - delete(s.pids.unknown, pid) - delete(s.pids.all, pid) - s.symCache.RemoveDeadPID(symtab.PidKey(pid)) - if s.pyperf != nil { - s.pyperf.RemoveDeadPID(pid) - } - s.targetFinder.RemoveDeadPID(pid) - } - - for pid := range s.pids.unknown { - _, err := os.Stat(fmt.Sprintf("/proc/%d", pid)) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - _ = level.Error(s.logger).Log("msg", "cleanup stat pid", "pid", pid, "err", err) - } - delete(s.pids.unknown, pid) - delete(s.pids.all, pid) - } - } - - if s.roundNumber%10 == 0 { - s.checkStalePids() - } -} - -// iterate over all pids and check if they are alive -// it is only needed in case disassociate_ctty hook somehow mises a process death -func (s *session) checkStalePids() { - var ( - m = s.bpf.Pids - mapSize = m.MaxEntries() - nextKey = uint32(0) - ) - keys := make([]uint32, mapSize) - values := make([]pyrobpf.ProfilePidConfig, mapSize) - n, err := m.BatchLookup(nil, &nextKey, keys, values, new(ebpf.BatchOptions)) - _ = level.Debug(s.logger).Log("msg", "check stale pids", "count", n) - for i := 0; i < n; i++ { - _, err := os.Stat(fmt.Sprintf("/proc/%d/status", keys[i])) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - _ = level.Error(s.logger).Log("msg", "check stale pids", "err", err) - } - if err := m.Delete(keys[i]); err != nil && !errors.Is(err, ebpf.ErrKeyNotExist) { - _ = level.Error(s.logger).Log("msg", "delete stale pid", "pid", keys[i], "err", err) - } - continue - } else { - } - } - if err != nil { - if !errors.Is(err, ebpf.ErrKeyNotExist) { - _ = level.Error(s.logger).Log("msg", "check stale pids", "err", err) - } - } -} - -func (s *session) logVerifierError(err error) { - if s.options.VerifierLogSize <= 0 { - return - } - var e *ebpf.VerifierError - if errors.As(err, &e) { - for _, l := range e.Log { - level.Error(s.logger).Log("verifier", l) - } - } -} - -func (s *session) progOptions() ebpf.ProgramOptions { - if s.options.VerifierLogSize > 0 { - return ebpf.ProgramOptions{ - LogDisabled: false, - LogSize: s.options.VerifierLogSize, - LogLevel: ebpf.LogLevelInstruction | ebpf.LogLevelBranch | ebpf.LogLevelStats, - } - } else { - return ebpf.ProgramOptions{ - LogDisabled: true, - } - } -} - -func (s *session) targetSymbolOptions(target *sd.Target) *symtab.SymbolOptions { - opt := new(symtab.SymbolOptions) - *opt = s.options.SymbolOptions - overrideSymbolOptions(target, opt) - return opt -} - -func overrideSymbolOptions(t *sd.Target, opt *symtab.SymbolOptions) { - if v, present := t.GetFlag(sd.OptionGoTableFallback); present { - opt.GoTableFallback = v - } - if v, present := t.GetFlag(sd.OptionPythonFullFilePath); present { - opt.PythonFullFilePath = v - } - if v, present := t.Get(sd.OptionDemangle); present { - opt.DemangleOptions = demangle.ConvertDemangleOptions(v) - } -} - -func (s *session) collectKernelEnabled(target *sd.Target) bool { - enabled := s.options.CollectKernel - if v, present := target.GetFlag(sd.OptionCollectKernel); present { - enabled = v - } - return enabled -} - -func (s *session) pythonEnabled(target *sd.Target) bool { - enabled := s.options.PythonEnabled - if v, present := target.GetFlag(sd.OptionPythonEnabled); present { - enabled = v - } - return enabled -} - -func (s *session) pythonBPFDebugLogEnabled(target *sd.Target) bool { - enabled := s.options.PythonBPFDebugLogEnabled - if v, present := target.GetFlag(sd.OptionPythonBPFDebugLogEnabled); present { - enabled = v - } - return enabled -} - -func (s *session) pythonBPFErrorLogEnabled(target *sd.Target) bool { - enabled := s.options.PythonBPFErrorLogEnabled - if v, present := target.GetFlag(sd.OptionPythonBPFErrorLogEnabled); present { - enabled = v - } - return enabled -} - -func (s *session) printDebugInfo() { - _ = level.Debug(s.logger).Log("arch", runtime.GOARCH) - pv, _ := os.ReadFile("/proc/version") - _ = level.Debug(s.logger).Log("/proc/version", pv) -} - -type stackBuilder struct { - stack []string -} - -func (s *stackBuilder) reset() { - s.stack = s.stack[:0] -} - -func (s *stackBuilder) append(sym string) { - s.stack = append(s.stack, sym) -} - -func getPIDNamespace() (dev uint64, ino uint64, err error) { - stat, err := os.Stat("/proc/self/ns/pid") - if err != nil { - return 0, 0, err - } - if st, ok := stat.Sys().(*syscall.Stat_t); ok { - return st.Dev, st.Ino, nil - } - return 0, 0, fmt.Errorf("could not determine pid namespace") -} diff --git a/ebpf/session_maps.go b/ebpf/session_maps.go deleted file mode 100644 index 380ce1d68c..0000000000 --- a/ebpf/session_maps.go +++ /dev/null @@ -1,137 +0,0 @@ -//go:build linux - -// Package ebpfspy provides integration with Linux eBPF. It is a rough copy of profile.py from BCC tools: -// -// https://github.com/iovisor/bcc/blob/master/tools/profile.py -package ebpfspy - -import ( - "errors" - "fmt" - - "github.com/cilium/ebpf" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/pyrobpf" -) - -func (s *session) getCountsMapValues() (keys []pyrobpf.ProfileSampleKey, values []uint32, batch bool, err error) { - // try batch first - var ( - m = s.bpf.ProfileMaps.Counts - mapSize = m.MaxEntries() - nextKey = pyrobpf.ProfileSampleKey{} - ) - keys = make([]pyrobpf.ProfileSampleKey, mapSize) - values = make([]uint32, mapSize) - - opts := &ebpf.BatchOptions{} - n, err := m.BatchLookupAndDelete(nil, &nextKey, keys, values, opts) - if n > 0 { - level.Debug(s.logger).Log( - "msg", "getCountsMapValues BatchLookupAndDelete", - "count", n, - ) - return keys[:n], values[:n], true, nil - } - if errors.Is(err, ebpf.ErrKeyNotExist) { - return nil, nil, true, nil - } - // try iterating if batch failed - resultKeys := keys[:0] - resultValues := values[:0] - it := m.Iterate() - k := pyrobpf.ProfileSampleKey{} - v := uint32(0) - for { - ok := it.Next(&k, &v) - if !ok { - err := it.Err() - if err != nil { - err = fmt.Errorf("map %s iteration : %w", m.String(), err) - return nil, nil, false, err - } - break - } - resultKeys = append(resultKeys, k) - resultValues = append(resultValues, v) - } - level.Debug(s.logger).Log( - "msg", "getCountsMapValues iter", - "count", len(keys), - ) - return resultKeys, resultValues, false, nil -} - -func (s *session) clearCountsMap(keys []pyrobpf.ProfileSampleKey, batch bool) error { - if len(keys) == 0 { - return nil - } - if batch { - // do nothing, already deleted with GetValueAndDeleteBatch in getCountsMapValues - return nil - } - m := s.bpf.ProfileMaps.Counts - for i := range keys { - err := m.Delete(&keys[i]) - if err != nil { - return err - } - } - level.Debug(s.logger).Log( - "msg", "clearCountsMap", - "count", len(keys), - ) - return nil -} - -func (s *session) clearStacksMap(knownKeys map[uint32]bool, m *ebpf.Map) error { - cnt := 0 - errs := 0 - if s.roundNumber%10 == 0 { - // do a full reset once in a while - it := m.Iterate() - v := make([]byte, m.ValueSize()) - var keys []uint32 - for { - k := uint32(0) - ok := it.Next(&k, &v) - if !ok { - err := it.Err() - if err != nil { - return fmt.Errorf("clearStacksMap fail: %w %s", err, m.String()) - } - break - } - keys = append(keys, k) - } - for i := range keys { - if err := m.Delete(&keys[i]); err != nil { - errs += 1 - } else { - cnt += 1 - } - } - level.Debug(s.logger).Log( - "msg", "clearStacksMap deleted all stacks", - "count", cnt, - "unsuccessful", errs, - "map", m.String(), - ) - return nil - } - for stackId := range knownKeys { - k := stackId - if err := m.Delete(&k); err != nil { - errs += 1 - } else { - cnt += 1 - } - } - level.Debug(s.logger).Log( - "msg", "clearStacksMap deleted known stacks", - "count", cnt, - "unsuccessful", errs, - "map", m.String(), - ) - return nil -} diff --git a/ebpf/session_python.go b/ebpf/session_python.go deleted file mode 100644 index 7f1e1fc9be..0000000000 --- a/ebpf/session_python.go +++ /dev/null @@ -1,233 +0,0 @@ -//go:build linux - -package ebpfspy - -import ( - "encoding/binary" - "fmt" - "os" - "strings" - "time" - - "github.com/cilium/ebpf" - "github.com/cilium/ebpf/btf" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/pyrobpf" - "github.com/grafana/pyroscope/ebpf/python" - "github.com/grafana/pyroscope/ebpf/sd" - "github.com/samber/lo" -) - -func (s *session) tryStartPythonProfiling(pid uint32, target *sd.Target, pi procInfoLite) { - const nTries = 4 - for i := 0; i < nTries; i++ { - shouldRetry := s.startPythonProfiling(pid, target, pi, i == nTries-1) - if !shouldRetry { - return - } - time.Sleep(10 * time.Millisecond) - } -} - -func (s *session) startPythonProfiling(pid uint32, target *sd.Target, pi procInfoLite, lastAttempt bool) bool { - s.mutex.Lock() - defer s.mutex.Unlock() - if !s.started { - return false - } - _, dead := s.pids.dead[pid] - if dead { - return false - } - pyPerf := s.getPyPerfLocked(target) - if pyPerf == nil { - _ = level.Error(s.logger).Log("err", "pyperf process profiling init failed. pyperf == nil", "pid", pid) - pi.typ = pyrobpf.ProfilingTypeError - s.setPidConfig(pid, pi, false, false) - return false - } - - pyData, err := python.GetPyPerfPidData(s.logger, pid, s.collectKernelEnabled(target)) - svc := target.ServiceName() - if err != nil { - alive := processAlive(pid) - if alive && lastAttempt { - s.options.Metrics.Python.PidDataError.WithLabelValues(svc).Inc() - _ = level.Error(s.logger).Log("err", err, "msg", "pyperf get python process data failed", "pid", pid, "target", target.String()) - } else { - _ = level.Debug(s.logger).Log("err", err, "msg", "pyperf get python process data failed", "pid", pid, "target", target.String()) - } - pi.typ = pyrobpf.ProfilingTypeError - s.setPidConfig(pid, pi, false, false) - return alive - } - err = nil - proc := pyPerf.FindProc(pid) - if proc == nil { - proc, err = pyPerf.NewProc(pid, pyData, s.targetSymbolOptions(target), svc) - if err != nil { - _ = level.Error(s.logger).Log("err", err, "msg", "pyperf process profiling init failed", "pid", pid) - pi.typ = pyrobpf.ProfilingTypeError - s.setPidConfig(pid, pi, false, false) - return false - } - } - _ = level.Info(s.logger).Log("msg", "pyperf process profiling init success", "pid", pid, - "py_data", fmt.Sprintf("%+v", pyData), "target", target.String()) - s.setPidConfig(pid, pi, s.options.CollectUser, s.options.CollectKernel) - return false -} - -// may return nil if loadPyPerf returns error -func (s *session) getPyPerfLocked(cause *sd.Target) *python.Perf { - if s.pyperf != nil { - return s.pyperf - } - if s.pyperfError != nil { - return nil - } - s.options.Metrics.Python.Load.Inc() - pyperf, err := s.loadPyPerf(cause) - if err != nil { - s.pyperfError = err - s.options.Metrics.Python.LoadError.Inc() - _ = level.Error(s.logger).Log("err", err, "msg", "load pyperf") - return nil - } - s.pyperf = pyperf - return s.pyperf -} - -// getPyPerf is used for testing to wait for pyperf to load -// it may take long time to load and verify, especially running in qemu with no kvm -func (s *session) getPyPerf(cause *sd.Target) *python.Perf { - s.mutex.Lock() - defer s.mutex.Unlock() - return s.getPyPerfLocked(cause) -} - -func (s *session) loadPyPerf(cause *sd.Target) (*python.Perf, error) { - defer btf.FlushKernelSpec() // save some memory - - opts := &ebpf.CollectionOptions{ - Programs: s.progOptions(), - MapReplacements: map[string]*ebpf.Map{ - "stacks": s.bpf.Stacks, - "counts": s.bpf.ProfileMaps.Counts, - }, - } - spec, err := python.LoadPerf() - if err != nil { - return nil, fmt.Errorf("pyperf load %w", err) - } - _, nsIno, err := getPIDNamespace() - if err != nil { - return nil, fmt.Errorf("unable to get pid namespace %w", err) - } - err = spec.RewriteConstants(map[string]interface{}{ - "global_config": python.PerfGlobalConfigT{ - BpfLogErr: boolToU8(s.pythonBPFErrorLogEnabled(cause)), - BpfLogDebug: boolToU8(s.pythonBPFDebugLogEnabled(cause)), - NsPidIno: nsIno, - }, - }) - if err != nil { - return nil, fmt.Errorf("pyperf rewrite constants %w", err) - } - if s.options.BPFMapsOptions.SymbolsMapSize != 0 { - spec.Maps[python.MapNameSymbols].MaxEntries = s.options.BPFMapsOptions.SymbolsMapSize - } - - err = spec.LoadAndAssign(&s.pyperfBpf, opts) - if err != nil { - s.logVerifierError(err) - return nil, fmt.Errorf("pyperf load %w", err) - } - pyperf, err := python.NewPerf(s.logger, s.options.Metrics.Python, s.pyperfBpf.PerfMaps.PyPidConfig, s.pyperfBpf.PerfMaps.PySymbols) - if err != nil { - return nil, fmt.Errorf("pyperf create %w", err) - } - err = s.bpf.ProfileMaps.Progs.Update(uint32(0), s.pyperfBpf.PerfPrograms.PyperfCollect, ebpf.UpdateAny) - if err != nil { - return nil, fmt.Errorf("pyperf link %w", err) - } - _ = level.Info(s.logger).Log("msg", "pyperf loaded") - return pyperf, nil -} - -func (s *session) GetPythonStack(stackId int64) []byte { - if s.pyperfBpf.PythonStacks == nil { - return nil - } - stackIdU32 := uint32(stackId) - res, err := s.pyperfBpf.PythonStacks.LookupBytes(stackIdU32) - if err != nil { - return nil - } - return res -} - -func (s *session) WalkPythonStack(sb *stackBuilder, stack []byte, target *sd.Target, proc *python.Proc, pySymbols *python.LazySymbols, stats *StackResolveStats) { - if len(stack) == 0 { - return - } - - svc := target.ServiceName() - - begin := len(sb.stack) - for len(stack) > 0 { - symbolIDBytes := stack[:4] - stack = stack[4:] - symbolID := binary.LittleEndian.Uint32(symbolIDBytes) - if symbolID == 0 { - break - } - sym, err := pySymbols.GetSymbol(symbolID, svc) - if err == nil { - filename := python.PythonString(sym.File[:], &sym.FileType) - if !proc.SymbolOptions.PythonFullFilePath { - iSep := strings.LastIndexByte(filename, '/') - if iSep != 1 { - filename = filename[iSep+1:] - } - } - classname := python.PythonString(sym.Classname[:], &sym.ClassnameType) - name := python.PythonString(sym.Name[:], &sym.NameType) - if skipPythonFrame(classname, filename, name) { - continue - } - var frame string - if classname == "" { - frame = filename + " " + name - } else { - frame = filename + " " + classname + "." + name - } - sb.append(frame) - stats.known += 1 - } else { - sb.append("pyperf_unknown") - s.options.Metrics.Python.UnknownSymbols.WithLabelValues(svc).Inc() - stats.unknownSymbols += 1 - } - } - end := len(sb.stack) - lo.Reverse(sb.stack[begin:end]) -} - -func skipPythonFrame(classname string, filename string, name string) bool { - // for now only skip _Py_InitCleanup frames in userspace - // https://github.com/python/cpython/blob/9eb2489266c4c1f115b8f72c0728db737cc8a815/Python/specialize.c#L2534 - return classname == "" && filename == "__init__" && name == "__init__" -} - -func processAlive(pid uint32) bool { - _, err := os.Stat(fmt.Sprintf("/proc/%d", pid)) - return err == nil -} - -func boolToU8(err bool) uint8 { - if err { - return 1 - } - return 0 -} diff --git a/ebpf/symtab/elf.go b/ebpf/symtab/elf.go deleted file mode 100644 index df33bb1ee6..0000000000 --- a/ebpf/symtab/elf.go +++ /dev/null @@ -1,363 +0,0 @@ -package symtab - -import ( - "debug/elf" - "errors" - "fmt" - "os" - "path" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/metrics" - elf2 "github.com/grafana/pyroscope/ebpf/symtab/elf" - "github.com/ianlancetaylor/demangle" -) - -var ( - errElfBaseNotFound = fmt.Errorf("elf base not found") -) - -type ElfTable struct { - fs string - elfFilePath string - table SymbolNameResolver - base uint64 - - loaded bool - loadedCached bool - err error - - options ElfTableOptions - logger log.Logger - procMap *ProcMap -} -type SymbolOptions struct { - GoTableFallback bool - PythonFullFilePath bool - DemangleOptions []demangle.Option -} - -var DefaultSymbolOptions = &SymbolOptions{ - GoTableFallback: false, -} - -type ElfTableOptions struct { - ElfCache *ElfCache - Metrics *metrics.SymtabMetrics - SymbolOptions *SymbolOptions -} - -func NewElfTable(logger log.Logger, procMap *ProcMap, fs string, elfFilePath string, options ElfTableOptions) *ElfTable { - if options.SymbolOptions == nil { - options.SymbolOptions = DefaultSymbolOptions - } - if options.Metrics == nil { - panic("metrics is nil") - } - res := &ElfTable{ - procMap: procMap, - fs: fs, - elfFilePath: elfFilePath, - logger: logger, - options: options, - table: &noopSymbolNameResolver{}, - } - return res -} - -func (et *ElfTable) findBase(e *elf2.MMapedElfFile) bool { - m := et.procMap - if e.FileHeader.Type == elf.ET_EXEC { - et.base = 0 - return true - } - for _, prog := range e.Progs { - if prog.Type == elf.PT_LOAD && (prog.Flags&elf.PF_X != 0) { - if uint64(m.Offset) == prog.Off { - et.base = m.StartAddr - prog.Vaddr - return true - } - alignedProgOffset := uint64(prog.Off) & 0xfffffffffffff000 - if uint64(m.Offset) == alignedProgOffset { - d := prog.Off - alignedProgOffset - et.base = m.StartAddr + d - prog.Vaddr - return true - } - } - } - return false -} - -func (et *ElfTable) load() { - if et.loaded { - return - } - et.loaded = true - fsElfFilePath := path.Join(et.fs, et.elfFilePath) - - me, err := elf2.NewMMapedElfFile(fsElfFilePath) - if err != nil { - et.onLoadError(err) - return - } - defer me.Close() // todo do not close if it is the selected elf - - if !et.findBase(me) { - et.onLoadError(errElfBaseNotFound) - return - } - buildID, err := me.BuildID() - if err != nil { - level.Error(et.logger).Log("msg", "failed to get build id", "err", err, "f", et.elfFilePath, "fs", et.fs) - } - - symbols := et.options.ElfCache.GetSymbolsByBuildID(buildID) - if symbols != nil { - et.table = symbols - et.loadedCached = true - return - } - fileInfo, err := os.Stat(fsElfFilePath) - if err != nil { - et.onLoadError(err) - return - } - symbols = et.options.ElfCache.GetSymbolsByStat(statFromFileInfo(fileInfo)) - if symbols != nil { - et.table = symbols - et.loadedCached = true - return - } - - debugFilePath := et.findDebugFile(buildID, me) - if debugFilePath != "" { - debugMe, err := elf2.NewMMapedElfFile(path.Join(et.fs, debugFilePath)) - if err != nil { - et.onLoadError(err) - return - } - defer debugMe.Close() // todo do not close if it is the selected elf - - symbols, err = et.createSymbolTable(debugMe) - if err != nil { - et.onLoadError(err) - return - } - et.table = symbols - et.options.ElfCache.CacheByBuildID(buildID, symbols) - return - } - - symbols, err = et.createSymbolTable(me) - if err != nil { - et.onLoadError(err) - return - } - - et.table = symbols - if buildID.Empty() { - et.options.ElfCache.CacheByStat(statFromFileInfo(fileInfo), symbols) - } else { - et.options.ElfCache.CacheByBuildID(buildID, symbols) - } -} - -func (et *ElfTable) createSymbolTable(me *elf2.MMapedElfFile) (SymbolNameResolver, error) { - level.Debug(et.logger).Log("msg", "create symbol table", "path", me.FilePath()) - goTable, goErr := me.NewGoTable() - if !et.options.SymbolOptions.GoTableFallback && goErr == nil { - return goTable, nil - } - symbolOptions := elf2.SymbolsOptions{ - DemangleOptions: et.options.SymbolOptions.DemangleOptions, - } - if goErr == nil && goTable.Index.Entry.Length() > 0 { - symbolOptions.FilterFrom = goTable.Index.Entry.Get(0) - symbolOptions.FilterTo = goTable.Index.End - } - symTable, symErr := me.NewSymbolTable(&symbolOptions) - if symErr != nil && goErr != nil { - return nil, fmt.Errorf("s: %s g: %s", symErr.Error(), goErr.Error()) - } - if symErr == nil && goErr == nil { - return &elf2.GoTableWithFallback{ - GoTable: goTable, - SymTable: symTable, - }, nil - } - if symErr == nil { - return symTable, nil - } - if goTable != nil { - return goTable, nil - } - panic("unreachable") -} - -var errTableDead = fmt.Errorf("non cached table dead") - -func (et *ElfTable) Resolve(pc uint64) string { - if !et.loaded { - et.load() - } - if et.err != nil { - return "" - } - pc -= et.base - res := et.table.Resolve(pc) - if res != "" { - return res - } - if !et.table.IsDead() { - return "" - } - if !et.loadedCached { - et.err = errTableDead - return "" - } - et.table = &noopSymbolNameResolver{} - et.loaded = false - et.loadedCached = false - et.load() - if et.err != nil { - return res - } - return et.table.Resolve(pc) -} - -func (et *ElfTable) Cleanup() { - if et.table != nil { - et.table.Cleanup() - } -} - -func (et *ElfTable) findDebugFileWithBuildID(buildID elf2.BuildID) string { - id := buildID.ID - if len(id) < 3 || !buildID.GNU() { - return "" - } - - debugFile := fmt.Sprintf("/usr/lib/debug/.build-id/%s/%s.debug", id[:2], id[2:]) - fsDebugFile := path.Join(et.fs, debugFile) - _, err := os.Stat(fsDebugFile) - if err == nil { - return debugFile - } - - return "" -} - -func (et *ElfTable) findDebugFile(buildID elf2.BuildID, elfFile *elf2.MMapedElfFile) string { - // https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html - // So, for example, suppose you ask GDB to debug /usr/bin/ls, which has a debug link that specifies the file - // ls.debug, and a build ID whose value in hex is abcdef1234. If the list of the global debug directories - // includes /usr/lib/debug, then GDB will look for the following debug information files, in the indicated order: - // - //- /usr/lib/debug/.build-id/ab/cdef1234.debug - //- /usr/bin/ls.debug - //- /usr/bin/.debug/ls.debug - //- /usr/lib/debug/usr/bin/ls.debug. - debugFile := et.findDebugFileWithBuildID(buildID) - if debugFile != "" { - return debugFile - } - debugFile = et.findDebugFileWithDebugLink(elfFile) - return debugFile -} - -func (et *ElfTable) findDebugFileWithDebugLink(elfFile *elf2.MMapedElfFile) string { - fs := et.fs - elfFilePath := et.elfFilePath - debugLinkSection := elfFile.Section(".gnu_debuglink") - if debugLinkSection == nil { - return "" - } - data, err := elfFile.SectionData(debugLinkSection) - if err != nil { - return "" - } - if len(data) < 6 { - return "" - } - crc := data[len(data)-4:] - _ = crc - debugLink := cString(data) - - // /usr/bin/ls.debug - fsDebugFile := path.Join(path.Dir(elfFilePath), debugLink) - _, err = os.Stat(path.Join(fs, fsDebugFile)) - if err == nil { - return fsDebugFile - } - // /usr/bin/.debug/ls.debug - fsDebugFile = path.Join(path.Dir(elfFilePath), ".debug", debugLink) - _, err = os.Stat(path.Join(fs, fsDebugFile)) - if err == nil { - return fsDebugFile - } - // /usr/lib/debug/usr/bin/ls.debug. - fsDebugFile = path.Join("/usr/lib/debug", path.Dir(elfFilePath), debugLink) - _, err = os.Stat(path.Join(fs, fsDebugFile)) - if err == nil { - return fsDebugFile - } - - return "" -} - -func cString(bs []byte) string { - i := 0 - for ; i < len(bs); i++ { - if bs[i] == 0 { - break - } - } - return string(bs[:i]) -} - -type ElfDebugInfo struct { - SymbolsCount int `alloy:"symbols_count,attr,optional" river:"symbols_count,attr,optional"` - File string `alloy:"file,attr,optional" river:"file,attr,optional"` -} - -func (et *ElfTable) DebugInfo() elf2.SymTabDebugInfo { - return et.table.DebugInfo() -} - -func (et *ElfTable) onLoadError(err error) { - et.err = err - var l log.Logger - if errors.Is(err, os.ErrNotExist) { - l = level.Debug(et.logger) - } else { - l = level.Error(et.logger) - } - l.Log( - "msg", "failed to load elf table", - "err", et.err, - "f", et.elfFilePath, - "fs", et.fs) - if et.options.Metrics != nil { - et.options.Metrics.ElfErrors.WithLabelValues(errorType(et.err)).Inc() - } -} - -func errorType(err error) string { - if errors.Is(err, os.ErrNotExist) { - return "ErrNotExist" - } - if errors.Is(err, os.ErrPermission) { - return "ErrPermission" - } - if errors.Is(err, os.ErrClosed) { - return "ErrClosed" - } - if errors.Is(err, os.ErrInvalid) { - return "ErrInvalid" - } - if errors.Is(err, errElfBaseNotFound) { - return "ElfBaseNotFound" - } - return "Other" -} diff --git a/ebpf/symtab/elf/buildid.go b/ebpf/symtab/elf/buildid.go deleted file mode 100644 index 4ed79b96d6..0000000000 --- a/ebpf/symtab/elf/buildid.go +++ /dev/null @@ -1,101 +0,0 @@ -package elf - -import ( - "bytes" - "encoding/hex" - "errors" - "fmt" -) - -type BuildID struct { - ID string - Typ string -} - -func GNUBuildID(s string) BuildID { - return BuildID{ID: s, Typ: "gnu"} -} -func GoBuildID(s string) BuildID { - return BuildID{ID: s, Typ: "go"} -} - -func (b *BuildID) Empty() bool { - return b.ID == "" || b.Typ == "" -} - -func (b *BuildID) GNU() bool { - return b.Typ == "gnu" -} - -var ( - ErrNoBuildIDSection = fmt.Errorf("build ID section not found") -) - -func (f *MMapedElfFile) BuildID() (BuildID, error) { - id, err := f.GNUBuildID() - if err != nil && !errors.Is(err, ErrNoBuildIDSection) { - return BuildID{}, err - } - if !id.Empty() { - return id, nil - } - id, err = f.GoBuildID() - if err != nil && !errors.Is(err, ErrNoBuildIDSection) { - return BuildID{}, err - } - if !id.Empty() { - return id, nil - } - - return BuildID{}, ErrNoBuildIDSection -} - -var goBuildIDSep = []byte("/") - -func (f *MMapedElfFile) GoBuildID() (BuildID, error) { - buildIDSection := f.Section(".note.go.buildid") - if buildIDSection == nil { - return BuildID{}, ErrNoBuildIDSection - } - data, err := f.SectionData(buildIDSection) - if err != nil { - return BuildID{}, fmt.Errorf("reading .note.go.buildid %w", err) - } - if len(data) < 17 { - return BuildID{}, fmt.Errorf(".note.gnu.build-id is too small") - } - - data = data[16 : len(data)-1] - if len(data) < 40 || bytes.Count(data, goBuildIDSep) < 2 { - return BuildID{}, fmt.Errorf("wrong .note.go.buildid %s", f.fpath) - } - id := string(data) - if id == "redacted" { - return BuildID{}, fmt.Errorf("blacklisted .note.go.buildid %s", f.fpath) - } - return GoBuildID(id), nil -} - -func (f *MMapedElfFile) GNUBuildID() (BuildID, error) { - buildIDSection := f.Section(".note.gnu.build-id") - if buildIDSection == nil { - return BuildID{}, ErrNoBuildIDSection - } - - data, err := f.SectionData(buildIDSection) - if err != nil { - return BuildID{}, fmt.Errorf("reading .note.gnu.build-id %w", err) - } - if len(data) < 16 { - return BuildID{}, fmt.Errorf(".note.gnu.build-id is too small : %s", hex.EncodeToString(data)) - } - if !bytes.Equal([]byte("GNU"), data[12:15]) { - return BuildID{}, fmt.Errorf(".note.gnu.build-id is not a GNU build-id : %s", hex.EncodeToString(data)) - } - rawBuildID := data[16:] - if len(rawBuildID) < 8 { - return BuildID{}, fmt.Errorf(".note.gnu.build-id has wrong size %s : %s ", f.fpath, hex.EncodeToString(data)) - } - buildIDHex := hex.EncodeToString(rawBuildID) - return GNUBuildID(buildIDHex), nil -} diff --git a/ebpf/symtab/elf/buildid_test.go b/ebpf/symtab/elf/buildid_test.go deleted file mode 100644 index 723509c972..0000000000 --- a/ebpf/symtab/elf/buildid_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package elf - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestGoBuildID(t *testing.T) { - testcases := []struct { - f string - typ string - id string - }{ - {"go12", "", ""}, - {"go12-static", "", ""}, - {"go16", "go", "92fNM3QG6qxprToyNKC6/aWDMs1NbNgS6utRcIALh/OnWrTUXnoISctQzMsAsP/X49oo_6m-sncjFUHr8D7"}, - {"go16-static", "go", "o2oH02eCzbftShmzN6SC/aWDMs1NbNgS6utRcIALh/OnWrTUXnoISctQzMsAsP/NLfmh3nn1x4IZuHkOpkn"}, - {"go18", "go", "OQZSseDjmXatQp02XfSs/YnxZZfCwiY5UEDTfATTP/ZvesUZonVPjE1Be6F2gG/ET_kcbC7pPCzH8jfF77U"}, - {"go18-static", "go", "rRo3GoXCsoYEDUJABXvH/F-vvosm8BXuqRFAmnxBr/ZvesUZonVPjE1Be6F2gG/PWVZt07QoO_gIVycOEBS"}, - {"go20", "go", "Qffu__H4fOgskLcG9xgZ/IJ9VzAiPxBstzejlZLmK/EGJHHzTL5Vs7GGklz10L/r6shgckObuxZ4kbw9YGX"}, - {"go20-static", "go", "otBDhR4Gpy9N5G-o7ltP/UAAPpyRPxBegdj7J8l7o/EGJHHzTL5Vs7GGklz10L/oyXFW3eY5aQbuMp6Y-up"}, - {"elf", "gnu", "1fcfa068c5fdb9f31e6d9f3f89019beacb70182d"}, - {"elf.debug", "gnu", "1fcfa068c5fdb9f31e6d9f3f89019beacb70182d"}, - {"elf.stripped", "gnu", "1fcfa068c5fdb9f31e6d9f3f89019beacb70182d"}, - } - for _, testcase := range testcases { - t.Run(testcase.f, func(t *testing.T) { - me, err := NewMMapedElfFile("./testdata/elfs/" + testcase.f) - require.NoError(t, err) - defer me.Close() - id, err := me.BuildID() - if testcase.id == "" { - require.Error(t, err) - require.Empty(t, id) - } else { - require.NoError(t, err) - require.Equal(t, testcase.id, id.ID) - require.Equal(t, testcase.typ, id.Typ) - } - }) - } -} diff --git a/ebpf/symtab/elf/elf_sym.go b/ebpf/symtab/elf/elf_sym.go deleted file mode 100644 index 6f1cc1c3d5..0000000000 --- a/ebpf/symtab/elf/elf_sym.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package elf implements access to ELF object files. - -# Security - -This package is not designed to be hardened against adversarial inputs, and is -outside the scope of https://go.dev/security/policy. In particular, only basic -validation is done when parsing object files. As such, care should be taken when -parsing untrusted inputs, as parsing malformed files may consume significant -resources, or cause panics. -*/ - -// Copied from here https://github.com/golang/go/blob/go1.20.5/src/debug/elf/file.go#L585 -// modified to not read symbol names in memory and return []SymbolIndex - -package elf - -import ( - "debug/elf" - "errors" - "fmt" - - "github.com/ianlancetaylor/demangle" -) - -type SymbolsOptions struct { - DemangleOptions []demangle.Option - // ignore symbols from FilterFrom to FilterTo - FilterFrom uint64 - FilterTo uint64 -} - -// todo consider using ReaderAt here, same as in gopcln -func (f *MMapedElfFile) getSymbols(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) { - switch f.Class { - case elf.ELFCLASS64: - return f.getSymbols64(typ, opt) - - case elf.ELFCLASS32: - return f.getSymbols32(typ, opt) - } - - return nil, 0, errors.New("not implemented") -} - -// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols -// if there is no such section in the File. -var ErrNoSymbols = errors.New("no symbol section") - -func (f *MMapedElfFile) getSymbols64(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) { - symtabSection := f.sectionByType(typ) - if symtabSection == nil { - return nil, 0, ErrNoSymbols - } - var linkIndex SectionLinkIndex - if typ == elf.SHT_DYNSYM { - linkIndex = sectionTypeDynSym - } else { - linkIndex = sectionTypeSym - } - - data, err := f.SectionData(symtabSection) - if err != nil { - return nil, 0, fmt.Errorf("cannot load symbol section: %w", err) - } - - if len(data)%elf.Sym64Size != 0 { - return nil, 0, errors.New("length of symbol section is not a multiple of Sym64Size") - } - - // The first entry is all zeros. - data = data[elf.Sym64Size:] - - symbols := make([]SymbolIndex, len(data)/elf.Sym64Size) - - i := 0 - var sym elf.Sym64 - for len(data) > 0 { - rawSym := data[:elf.Sym64Size] - data = data[elf.Sym64Size:] - sym = elf.Sym64{ - Name: f.ByteOrder.Uint32(rawSym[:4]), - Info: rawSym[4], - //Other: rawSym[5], - //Shndx: f.ByteOrder.Uint16(rawSym[6:8]), // not used - Value: f.ByteOrder.Uint64(rawSym[8:16]), - //Size: f.ByteOrder.Uint64(rawSym[16:24]), // not used - } - - if sym.Value != 0 && sym.Info&0xf == byte(elf.STT_FUNC) { - if sym.Name >= 0x7fffffff { - return nil, 0, fmt.Errorf("wrong sym name") - } - pc := sym.Value - if pc >= opt.FilterFrom && pc < opt.FilterTo { - continue - } - symbols[i].Value = pc - symbols[i].Name = NewName(sym.Name, linkIndex) - i++ - } - } - - return symbols[:i], symtabSection.Link, nil -} - -func (f *MMapedElfFile) getSymbols32(typ elf.SectionType, opt *SymbolsOptions) ([]SymbolIndex, uint32, error) { - symtabSection := f.sectionByType(typ) - if symtabSection == nil { - return nil, 0, ErrNoSymbols - } - var linkIndex SectionLinkIndex - if typ == elf.SHT_DYNSYM { - linkIndex = sectionTypeDynSym - } else { - linkIndex = sectionTypeSym - } - - data, err := f.SectionData(symtabSection) - if err != nil { - return nil, 0, fmt.Errorf("cannot load symbol section: %w", err) - } - - if len(data)%elf.Sym32Size != 0 { - return nil, 0, errors.New("length of symbol section is not a multiple of Sym64Size") - } - - // The first entry is all zeros. - data = data[elf.Sym32Size:] - - symbols := make([]SymbolIndex, len(data)/elf.Sym32Size) - - i := 0 - var sym elf.Sym32 - for len(data) > 0 { - rawSym := data[:elf.Sym32Size] - data = data[elf.Sym32Size:] - sym = elf.Sym32{ - Name: f.ByteOrder.Uint32(rawSym[:4]), - Value: f.ByteOrder.Uint32(rawSym[4:8]), - //Size: f.ByteOrder.Uint32(rawSym[8:12]), - Info: rawSym[12], - //Other: rawSym[13], - //Shndx: f.ByteOrder.Uint16(rawSym[14:16]), - } - - if sym.Value != 0 && sym.Info&0xf == byte(elf.STT_FUNC) { - if sym.Name >= 0x7fffffff { - return nil, 0, fmt.Errorf("wrong sym name") - } - pc := uint64(sym.Value) - if pc >= opt.FilterFrom && pc < opt.FilterTo { - continue - } - symbols[i].Name = NewName(sym.Name, linkIndex) - i++ - } - } - - return symbols[:i], symtabSection.Link, nil -} diff --git a/ebpf/symtab/elf/elfmmap.go b/ebpf/symtab/elf/elfmmap.go deleted file mode 100644 index 97040b9b40..0000000000 --- a/ebpf/symtab/elf/elfmmap.go +++ /dev/null @@ -1,158 +0,0 @@ -package elf - -import ( - "bytes" - "debug/elf" - "fmt" - "os" - "runtime" - "strings" - - "github.com/ianlancetaylor/demangle" -) - -type MMapedElfFile struct { - elf.FileHeader - Sections []elf.SectionHeader - Progs []elf.ProgHeader - - fpath string - err error - fd *os.File - - stringCache map[int]string -} - -func NewMMapedElfFile(fpath string) (*MMapedElfFile, error) { - res := &MMapedElfFile{ - fpath: fpath, - } - err := res.ensureOpen() - if err != nil { - res.Close() - return nil, err - } - elfFile, err := elf.NewFile(res.fd) - if err != nil { - res.Close() - return nil, err - } - progs := make([]elf.ProgHeader, 0, len(elfFile.Progs)) - sections := make([]elf.SectionHeader, 0, len(elfFile.Sections)) - for i := range elfFile.Progs { - progs = append(progs, elfFile.Progs[i].ProgHeader) - } - for i := range elfFile.Sections { - sections = append(sections, elfFile.Sections[i].SectionHeader) - } - res.FileHeader = elfFile.FileHeader - res.Progs = progs - res.Sections = sections - - runtime.SetFinalizer(res, (*MMapedElfFile).Finalize) - return res, nil -} - -func (f *MMapedElfFile) Section(name string) *elf.SectionHeader { - for i := range f.Sections { - s := &f.Sections[i] - if s.Name == name { - return s - } - } - return nil -} - -func (f *MMapedElfFile) sectionByType(typ elf.SectionType) *elf.SectionHeader { - for i := range f.Sections { - s := &f.Sections[i] - if s.Type == typ { - return s - } - } - return nil -} - -func (f *MMapedElfFile) ensureOpen() error { - if f.fd != nil { - return nil - } - return f.open() -} - -func (f *MMapedElfFile) Finalize() { - if f.fd != nil { - println("ebpf mmaped elf not closed") - } - f.Close() -} -func (f *MMapedElfFile) Close() { - if f.fd != nil { - f.fd.Close() - f.fd = nil - } - f.stringCache = nil - f.Sections = nil -} -func (f *MMapedElfFile) open() error { - if f.err != nil { - return fmt.Errorf("failed previously %w", f.err) - } - fd, err := os.OpenFile(f.fpath, os.O_RDONLY, 0) - if err != nil { - f.err = err - return fmt.Errorf("open elf file %s %w", f.fpath, err) - } - f.fd = fd - return nil -} - -func (f *MMapedElfFile) SectionData(s *elf.SectionHeader) ([]byte, error) { - if err := f.ensureOpen(); err != nil { - return nil, err - } - res := make([]byte, s.Size) - if _, err := f.fd.ReadAt(res, int64(s.Offset)); err != nil { - return nil, err - } - return res, nil -} - -func (f *MMapedElfFile) FilePath() string { - return f.fpath -} - -// getString extracts a string from an ELF string table. -func (f *MMapedElfFile) getString(start int, demangleOptions []demangle.Option) (string, bool) { - if err := f.ensureOpen(); err != nil { - return "", false - } - if s, ok := f.stringCache[start]; ok { - return s, true - } - const tmpBufSize = 128 - var tmpBuf [tmpBufSize]byte - sb := strings.Builder{} - for i := 0; i < 10; i++ { - _, err := f.fd.ReadAt(tmpBuf[:], int64(start+i*tmpBufSize)) - if err != nil { - return "", false - } - idx := bytes.IndexByte(tmpBuf[:], 0) - if idx >= 0 { - sb.Write(tmpBuf[:idx]) - s := sb.String() - if len(demangleOptions) > 0 { - s = demangle.Filter(s, demangleOptions...) - } - if f.stringCache == nil { - f.stringCache = make(map[int]string) - } - f.stringCache[start] = s - return s, true - } else { - sb.Write(tmpBuf[:]) - } - } - return "", false -} diff --git a/ebpf/symtab/elf/elfmmap_test.go b/ebpf/symtab/elf/elfmmap_test.go deleted file mode 100644 index bf3e82af9b..0000000000 --- a/ebpf/symtab/elf/elfmmap_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package elf - -import ( - "debug/elf" - "slices" - "strings" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestElfSymbolComparison(t *testing.T) { - testOneElfFile := func(t *testing.T, f string) { - e, err := elf.Open(f) - require.NoError(t, err) - defer e.Close() - - genuineSymbols := GetELFSymbolsFromSymtab(e) - - me, err := NewMMapedElfFile(f) - require.NoError(t, err) - defer me.Close() - - tab, _ := me.NewSymbolTable(new(SymbolsOptions)) - if tab == nil { - tab = &SymbolTable{} - } - var mySymbols []TestSym - - require.Equal(t, len(genuineSymbols), len(tab.Index.Names)) - for i, symbol := range genuineSymbols { - require.Equal(t, symbol.Start, tab.Index.Values.Value(i)) - name, _ := tab.symbolName(i) - mySymbols = append(mySymbols, TestSym{ - Name: name, - Start: symbol.Start, - }) - } - - cmp := func(a, b TestSym) int { - if a.Start == b.Start { - return strings.Compare(a.Name, b.Name) - } else if a.Start < b.Start { - return -1 - } else { - return 1 - } - } - slices.SortFunc(mySymbols, cmp) - slices.SortFunc(genuineSymbols, cmp) - require.Equal(t, genuineSymbols, mySymbols) - } - - fs := []string{ - "./testdata/elfs/elf", - "./testdata/elfs/elf.debug", - "./testdata/elfs/elf.nopie", - "./testdata/elfs/libexample.so", - "./testdata/elfs/go12", - "./testdata/elfs/go16", - "./testdata/elfs/go18", - "./testdata/elfs/go20", - "./testdata/elfs/go12-static", - "./testdata/elfs/go16-static", - "./testdata/elfs/go18-static", - "./testdata/elfs/go20-static", - } - for _, f := range fs { - t.Run(f, func(t *testing.T) { - testOneElfFile(t, f) - }) - } -} diff --git a/ebpf/symtab/elf/go_table.go b/ebpf/symtab/elf/go_table.go deleted file mode 100644 index b78fcd3a77..0000000000 --- a/ebpf/symtab/elf/go_table.go +++ /dev/null @@ -1,181 +0,0 @@ -package elf - -import ( - "debug/elf" - "errors" - "fmt" - - gosym2 "github.com/grafana/pyroscope/ebpf/symtab/gosym" -) - -type GoTable struct { - Index gosym2.FlatFuncIndex - File *MMapedElfFile - gopclnSection elf.SectionHeader - funcNameOffset uint64 -} - -func (g *GoTable) IsDead() bool { - return g.File.err != nil -} - -func (g *GoTable) DebugInfo() SymTabDebugInfo { - return SymTabDebugInfo{ - Name: fmt.Sprintf("GoTable %p", g), - Size: len(g.Index.Name), - File: g.File.fpath, - } -} - -func (g *GoTable) Size() int { - return len(g.Index.Name) -} - -func (g *GoTable) Refresh() { - -} - -func (g *GoTable) Resolve(addr uint64) string { - n := len(g.Index.Name) - if n == 0 { - return "" - } - if addr >= g.Index.End { - return "" - } - i := g.Index.Entry.FindIndex(addr) - if i == -1 { - return "" - } - name, _ := g.goSymbolName(i) - return name -} - -func (g *GoTable) Cleanup() { - g.File.Close() -} - -var ( - errEmptyText = errors.New("empty .text") - errGoPCLNTabNotFound = errors.New(".gopclntab not found") - errGoTooOld = errors.New("gosymtab: go sym tab too old") - errGoParseFailed = errors.New("gosymtab: go sym tab parse failed") - errGoFailed = errors.New("gosymtab: go sym tab failed") - errGoOOB = fmt.Errorf("go table oob") - errGoSymbolsNotFound = errors.New("gosymtab: no go symbols found") -) - -func (f *MMapedElfFile) NewGoTable() (*GoTable, error) { - obj := f - var err error - text := obj.Section(".text") - if text == nil { - return nil, errEmptyText - } - pclntab := obj.Section(".gopclntab") - if pclntab == nil { - return nil, errGoPCLNTabNotFound - } - if f.fd == nil { - return nil, fmt.Errorf("elf file not open") - } - - pclntabReader := gosym2.NewFilePCLNData(f.fd, int(pclntab.Offset)) - - pclntabHeader := make([]byte, 64) - if err = pclntabReader.ReadAt(pclntabHeader, 0); err != nil { - return nil, err - } - - textStart := gosym2.ParseRuntimeTextFromPclntab18(pclntabHeader) - - if textStart == 0 { - // for older versions text.Addr is enough - // https://github.com/golang/go/commit/b38ab0ac5f78ac03a38052018ff629c03e36b864 - textStart = text.Addr - } - if textStart < text.Addr || textStart >= text.Addr+text.Size { - return nil, fmt.Errorf(" runtime.text out of .text bounds %d %d %d", textStart, text.Addr, text.Size) - } - pcln := gosym2.NewLineTableStreaming(pclntabReader, textStart) - - if !pcln.IsGo12() { - return nil, errGoTooOld - } - if pcln.IsFailed() { - return nil, errGoParseFailed - } - funcs := pcln.Go12Funcs() - if len(funcs.Name) == 0 || funcs.Entry.Length() == 0 || funcs.End == 0 { - return nil, errGoSymbolsNotFound - } - //if funcs.Entry32 == nil && funcs.Entry64 == nil { - // return nil, errGoParseFailed // this should not happen - //} - //if funcs.Entry32 != nil && funcs.Entry64 != nil { - // return nil, errGoParseFailed // this should not happen - //} - if funcs.Entry.Length() != len(funcs.Name) { - return nil, errGoParseFailed // this should not happen - } - - funcNameOffset := pcln.FuncNameOffset() - return &GoTable{ - Index: funcs, - File: f, - gopclnSection: *pclntab, - funcNameOffset: funcNameOffset, - }, nil -} - -func (g *GoTable) goSymbolName(idx int) (string, error) { - offsetGpcln := g.gopclnSection.Offset - if idx >= len(g.Index.Name) { - return "", errGoOOB - } - - offsetName := g.Index.Name[idx] - name, ok := g.File.getString(int(offsetGpcln)+int(g.funcNameOffset)+int(offsetName), nil) - if !ok { - return "", errGoFailed - } - return name, nil -} - -type GoTableWithFallback struct { - GoTable *GoTable - SymTable *SymbolTable -} - -func (g *GoTableWithFallback) IsDead() bool { - return g.GoTable.File.err != nil -} - -func (g *GoTableWithFallback) DebugInfo() SymTabDebugInfo { - return SymTabDebugInfo{ - Name: fmt.Sprintf("GoTableWithFallback %p ", g), - Size: g.GoTable.Size() + g.SymTable.Size(), - File: g.GoTable.File.fpath, - } -} - -func (g *GoTableWithFallback) Size() int { - return g.GoTable.Size() + g.SymTable.Size() -} - -func (g *GoTableWithFallback) Refresh() { - -} - -func (g *GoTableWithFallback) Resolve(addr uint64) string { - name := g.GoTable.Resolve(addr) - if name != "" { - return name - } - return g.SymTable.Resolve(addr) -} - -func (g *GoTableWithFallback) Cleanup() { - g.GoTable.Cleanup() - g.SymTable.Cleanup() // second call is no op now, but call anyway just in case -} diff --git a/ebpf/symtab/elf/go_table_test.go b/ebpf/symtab/elf/go_table_test.go deleted file mode 100644 index 979fe69292..0000000000 --- a/ebpf/symtab/elf/go_table_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package elf - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestSelfGoSymbolComparison(t *testing.T) { - testGoSymbolTable := func(t *testing.T, expectedSymbols []TestSym, goTable *GoTable) { - for _, symbol := range expectedSymbols { - name := goTable.Resolve(symbol.Start) - require.Equal(t, symbol.Name, name) - } - - first := goTable.Index.Entry.First() - name := goTable.Resolve(first - 1) - require.Empty(t, name) - name = goTable.Resolve(goTable.Index.End) - require.Empty(t, name) - name = goTable.Resolve(goTable.Index.End + 1) - require.Empty(t, name) - } - - ts := []struct { - f string - expect32 bool - }{ - {"./testdata/elfs/go12", true}, - {"./testdata/elfs/go16", true}, - {"./testdata/elfs/go18", true}, - {"./testdata/elfs/go20", true}, - {"./testdata/elfs/go12-static", true}, - {"./testdata/elfs/go16-static", false}, // this one switches from 32 to 64 in the middle - {"./testdata/elfs/go18-static", false}, // this one starts with 64 - {"./testdata/elfs/go20-static", true}, - } - for _, testcase := range ts { - t.Run(testcase.f, func(t *testing.T) { - patchGo20Magic := strings.Contains(testcase.f, "go20") - expectedSymbols, err := GetGoSymbols(testcase.f, patchGo20Magic) - - require.NoError(t, err) - - me, err := NewMMapedElfFile(testcase.f) - require.NoError(t, err) - defer me.Close() - - goTable, err := me.NewGoTable() - - require.NoError(t, err) - require.Equal(t, testcase.expect32, goTable.Index.Entry.Is32()) - - require.Greater(t, len(expectedSymbols), 1000) - - testGoSymbolTable(t, expectedSymbols, goTable) - - if testcase.expect32 { - goTable2 := &GoTable{} - *goTable2 = *goTable - goTable2.Index.Entry = goTable2.Index.Entry.PCIndex64() - - require.False(t, goTable2.Index.Entry.Is32()) - testGoSymbolTable(t, expectedSymbols, goTable) - } - }) - } -} diff --git a/ebpf/symtab/elf/symbol_table.go b/ebpf/symtab/elf/symbol_table.go deleted file mode 100644 index 0e207c5dd5..0000000000 --- a/ebpf/symtab/elf/symbol_table.go +++ /dev/null @@ -1,150 +0,0 @@ -package elf - -import ( - "debug/elf" - "errors" - "fmt" - "sort" - - "github.com/grafana/pyroscope/ebpf/symtab/gosym" - "github.com/ianlancetaylor/demangle" -) - -// symbols from .symtab, .dynsym - -type SymbolIndex struct { - Name Name - Value uint64 -} - -type SectionLinkIndex uint8 - -var sectionTypeSym SectionLinkIndex = 0 -var sectionTypeDynSym SectionLinkIndex = 1 - -type Name uint32 - -func NewName(NameIndex uint32, linkIndex SectionLinkIndex) Name { - return Name((NameIndex & 0x7fffffff) | uint32(linkIndex)<<31) -} - -func (n *Name) NameIndex() uint32 { - return uint32(*n) & 0x7fffffff -} - -func (n *Name) LinkIndex() SectionLinkIndex { - return SectionLinkIndex(*n >> 31) -} - -type FlatSymbolIndex struct { - Links []elf.SectionHeader - Names []Name - Values gosym.PCIndex -} -type SymbolTable struct { - Index FlatSymbolIndex - File *MMapedElfFile - - demangleOptions []demangle.Option -} - -func (st *SymbolTable) IsDead() bool { - return st.File.err != nil -} - -func (st *SymbolTable) DebugInfo() SymTabDebugInfo { - return SymTabDebugInfo{ - Name: fmt.Sprintf("SymbolTable %p", st), - Size: len(st.Index.Names), - File: st.File.fpath, - } -} - -func (st *SymbolTable) Size() int { - return len(st.Index.Names) -} - -func (st *SymbolTable) Refresh() { - -} - -func (st *SymbolTable) DebugString() string { - return fmt.Sprintf("SymbolTable{ f = %s , sz = %d }", st.File.FilePath(), st.Index.Values.Length()) -} - -func (st *SymbolTable) Resolve(addr uint64) string { - if len(st.Index.Names) == 0 { - return "" - } - i := st.Index.Values.FindIndex(addr) - if i == -1 { - return "" - } - name, _ := st.symbolName(i) - return name -} - -func (st *SymbolTable) Cleanup() { - st.File.Close() -} - -func (f *MMapedElfFile) NewSymbolTable(opt *SymbolsOptions) (*SymbolTable, error) { - sym, sectionSym, err := f.getSymbols(elf.SHT_SYMTAB, opt) - if err != nil && !errors.Is(err, ErrNoSymbols) { - return nil, err - } - - dynsym, sectionDynSym, err := f.getSymbols(elf.SHT_DYNSYM, opt) - if err != nil && !errors.Is(err, ErrNoSymbols) { - return nil, err - } - total := len(dynsym) + len(sym) - if total == 0 { - return nil, ErrNoSymbols - } - all := make([]SymbolIndex, 0, total) // todo avoid allocation - all = append(all, sym...) - all = append(all, dynsym...) - - sort.Slice(all, func(i, j int) bool { - if all[i].Value == all[j].Value { - return all[i].Name < all[j].Name - } - return all[i].Value < all[j].Value - }) - - res := &SymbolTable{Index: FlatSymbolIndex{ - Links: []elf.SectionHeader{ - f.Sections[sectionSym], // should be at 0 - SectionTypeSym - f.Sections[sectionDynSym], // should be at 1 - SectionTypeDynSym - }, - Names: make([]Name, total), - Values: gosym.NewPCIndex(total), - }, - File: f, - demangleOptions: opt.DemangleOptions, - } - for i := range all { - res.Index.Names[i] = all[i].Name - res.Index.Values.Set(i, all[i].Value) - } - return res, nil -} - -func (st *SymbolTable) symbolName(idx int) (string, error) { - linkIndex := st.Index.Names[idx].LinkIndex() - SectionHeaderLink := &st.Index.Links[linkIndex] - NameIndex := st.Index.Names[idx].NameIndex() - s, b := st.File.getString(int(NameIndex)+int(SectionHeaderLink.Offset), st.demangleOptions) - if !b { - return "", fmt.Errorf("elf getString") - } - return s, nil -} - -type SymTabDebugInfo struct { - Name string `alloy:"name,attr,optional" river:"name,attr,optional"` - Size int `alloy:"symbol_count,attr,optional" river:"symbol_count,attr,optional"` - File string `alloy:"file,attr,optional" river:"file,attr,optional"` - LastUsedRound int `alloy:"last_used_round,attr,optional" river:"last_used_round,attr,optional"` -} diff --git a/ebpf/symtab/elf/symbol_table_test.go b/ebpf/symtab/elf/symbol_table_test.go deleted file mode 100644 index c4acca7fc2..0000000000 --- a/ebpf/symtab/elf/symbol_table_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package elf - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestName(t *testing.T) { - name := NewName(0xef, 1) - require.Equal(t, uint32(0xef), name.NameIndex()) - require.Equal(t, SectionLinkIndex(1), name.LinkIndex()) -} diff --git a/ebpf/symtab/elf/testdata/Dockerfile b/ebpf/symtab/elf/testdata/Dockerfile deleted file mode 100644 index 395bdc5294..0000000000 --- a/ebpf/symtab/elf/testdata/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 as builder - -RUN apt-get update && apt-get -y install gcc make - -ADD src.c lib.c docker.sh ./ -RUN bash docker.sh - - -FROM --platform=linux/amd64 golang:1.2 as go12 -ADD hello.go hello.go -RUN go build hello.go -RUN go build -ldflags="-extldflags=-static" -o hello-static hello.go - -FROM --platform=linux/amd64 golang:1.16 as go116 -ADD hello.go hello.go -RUN go build hello.go -RUN go build -ldflags="-extldflags=-static -T 4294963200" -o hello-static hello.go - -FROM --platform=linux/amd64 golang:1.18 as go118 -ADD hello.go hello.go -RUN go build hello.go -RUN go build -ldflags="-extldflags=-static -T 1099511623680" -o hello-static hello.go - -FROM --platform=linux/amd64 golang:1.20 as go120 -ADD hello.go hello.go -RUN go build hello.go -RUN go build -ldflags="-extldflags=-static" -o hello-static hello.go - -FROM scratch -COPY --from=builder elf elf.debug elf.stripped elf.debuglink elf.nopie elf.nobuildid libexample.so ./elfs/ -COPY --from=builder /usr/lib/debug/ ./usr/lib/debug/ -COPY --from=go12 /go/hello ./elfs/go12 -COPY --from=go116 /go/hello ./elfs/go16 -COPY --from=go118 /go/hello ./elfs/go18 -COPY --from=go120 /go/hello ./elfs/go20 -COPY --from=go12 /go/hello-static ./elfs/go12-static -COPY --from=go116 /go/hello-static ./elfs/go16-static -COPY --from=go118 /go/hello-static ./elfs/go18-static -COPY --from=go120 /go/hello-static ./elfs/go20-static diff --git a/ebpf/symtab/elf/testdata/Makefile b/ebpf/symtab/elf/testdata/Makefile deleted file mode 100644 index 2bb5df87e9..0000000000 --- a/ebpf/symtab/elf/testdata/Makefile +++ /dev/null @@ -1,5 +0,0 @@ - -.PHONY: testdata -testdata: - DOCKER_BUILDKIT=1 docker build . --output=. - diff --git a/ebpf/symtab/elf/testdata/docker.sh b/ebpf/symtab/elf/testdata/docker.sh deleted file mode 100644 index 24fd639253..0000000000 --- a/ebpf/symtab/elf/testdata/docker.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -ex - -gcc lib.c -o libexample.so -shared -gcc src.c -o elf -lexample -L. -Wl,-rpath=. -gcc src.c -no-pie -o elf.nopie -lexample -L. -Wl,-rpath=. -objcopy --only-keep-debug elf elf.debug -strip elf -o elf.stripped -objcopy --add-gnu-debuglink=elf.debug elf.stripped elf.debuglink - -strip --remove-section .note.gnu.build-id elf.debuglink -o elf.debuglink -objcopy --remove-section .note.gnu.build-id elf elf.nobuildid - - -build_id=$(readelf -n elf | grep 'Build ID' | awk '{print $3}') -dir=${build_id:0:2} -file=${build_id:2} -mkdir -p "/usr/lib/debug/.build-id/$dir" -cp elf.debug "/usr/lib/debug/.build-id/$dir/$file.debug" \ No newline at end of file diff --git a/ebpf/symtab/elf/testdata/elfs/elf b/ebpf/symtab/elf/testdata/elfs/elf deleted file mode 100755 index d461c084be..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/elf and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/elf.debug b/ebpf/symtab/elf/testdata/elfs/elf.debug deleted file mode 100755 index b19bb94fb9..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/elf.debug and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/elf.debuglink b/ebpf/symtab/elf/testdata/elfs/elf.debuglink deleted file mode 100755 index 7e3d068f9d..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/elf.debuglink and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/elf.nobuildid b/ebpf/symtab/elf/testdata/elfs/elf.nobuildid deleted file mode 100755 index 2f870228cf..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/elf.nobuildid and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/elf.nopie b/ebpf/symtab/elf/testdata/elfs/elf.nopie deleted file mode 100755 index 4e83be59dc..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/elf.nopie and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/elf.stripped b/ebpf/symtab/elf/testdata/elfs/elf.stripped deleted file mode 100755 index 42a1c615ea..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/elf.stripped and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go12 b/ebpf/symtab/elf/testdata/elfs/go12 deleted file mode 100755 index ee21a175b4..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go12 and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go12-static b/ebpf/symtab/elf/testdata/elfs/go12-static deleted file mode 100755 index ee21a175b4..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go12-static and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go16 b/ebpf/symtab/elf/testdata/elfs/go16 deleted file mode 100755 index 5e33a008d5..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go16 and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go16-static b/ebpf/symtab/elf/testdata/elfs/go16-static deleted file mode 100755 index e032eda5b2..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go16-static and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go18 b/ebpf/symtab/elf/testdata/elfs/go18 deleted file mode 100755 index ffd97b2073..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go18 and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go18-static b/ebpf/symtab/elf/testdata/elfs/go18-static deleted file mode 100755 index e309387087..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go18-static and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go20 b/ebpf/symtab/elf/testdata/elfs/go20 deleted file mode 100755 index 175ad3b828..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go20 and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/go20-static b/ebpf/symtab/elf/testdata/elfs/go20-static deleted file mode 100755 index 0817ab4797..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/go20-static and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/elfs/libexample.so b/ebpf/symtab/elf/testdata/elfs/libexample.so deleted file mode 100755 index 2fc8447f71..0000000000 Binary files a/ebpf/symtab/elf/testdata/elfs/libexample.so and /dev/null differ diff --git a/ebpf/symtab/elf/testdata/hello.go b/ebpf/symtab/elf/testdata/hello.go deleted file mode 100644 index 635db7ae6c..0000000000 --- a/ebpf/symtab/elf/testdata/hello.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "fmt" - -func main() { - fmt.Println("hello, world") -} diff --git a/ebpf/symtab/elf/testdata/lib.c b/ebpf/symtab/elf/testdata/lib.c deleted file mode 100644 index 686310fcfd..0000000000 --- a/ebpf/symtab/elf/testdata/lib.c +++ /dev/null @@ -1,10 +0,0 @@ - - -#include -#include -#include -#include - -void lib_iter() { - close(open("file", O_RDWR | O_TRUNC | O_CREAT, 0666)); -} \ No newline at end of file diff --git a/ebpf/symtab/elf/testdata/src.c b/ebpf/symtab/elf/testdata/src.c deleted file mode 100644 index 00b2591e01..0000000000 --- a/ebpf/symtab/elf/testdata/src.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include -#include - - -void lib_iter(); - -void iter() { - lib_iter(); -} - -int main() { - while (1) { - iter(); - } - return 0; - -} \ No newline at end of file diff --git a/ebpf/symtab/elf/testdata/usr/lib/debug/.build-id/1f/cfa068c5fdb9f31e6d9f3f89019beacb70182d.debug b/ebpf/symtab/elf/testdata/usr/lib/debug/.build-id/1f/cfa068c5fdb9f31e6d9f3f89019beacb70182d.debug deleted file mode 100755 index b19bb94fb9..0000000000 Binary files a/ebpf/symtab/elf/testdata/usr/lib/debug/.build-id/1f/cfa068c5fdb9f31e6d9f3f89019beacb70182d.debug and /dev/null differ diff --git a/ebpf/symtab/elf/testutils.go b/ebpf/symtab/elf/testutils.go deleted file mode 100644 index ae244895fc..0000000000 --- a/ebpf/symtab/elf/testutils.go +++ /dev/null @@ -1,114 +0,0 @@ -package elf - -import ( - "debug/elf" - "debug/gosym" - "encoding/binary" - "errors" - "fmt" - "slices" - "strings" - - gosym2 "github.com/grafana/pyroscope/ebpf/symtab/gosym" -) - -type TestSym struct { - Name string - Start uint64 -} - -func GetELFSymbolsFromSymtab(elfFile *elf.File) []TestSym { - symtab, _ := elfFile.Symbols() - dynsym, _ := elfFile.DynamicSymbols() - var symbols []TestSym - add := func(t []elf.Symbol) { - for _, sym := range t { - if sym.Value != 0 && sym.Info&0xf == byte(elf.STT_FUNC) { - symbols = append(symbols, TestSym{ - Name: sym.Name, - Start: sym.Value, - }) - } - } - } - - add(symtab) - - symCmp := func(a, b TestSym) int { - if a.Start == b.Start { - return strings.Compare(a.Name, b.Name) - } else if a.Start < b.Start { - return -1 - } else { - return 1 - } - } - - slices.SortFunc(symbols, symCmp) - add(dynsym) - slices.SortFunc(symbols, symCmp) - return symbols -} - -func GetGoSymbols(file string, patchGo20Magic bool) ([]TestSym, error) { - obj, err := elf.Open(file) - if err != nil { - return nil, fmt.Errorf("failed to open elf file: %w", err) - } - defer obj.Close() - - symbols, err := getGoSymbolsFromPCLN(obj, patchGo20Magic) - if err != nil { - return nil, err - } - return symbols, nil -} - -func getGoSymbolsFromPCLN(obj *elf.File, patchGo20Magic bool) ([]TestSym, error) { - var err error - var pclntab []byte - text := obj.Section(".text") - if text == nil { - return nil, errors.New("empty .text") - } - if sect := obj.Section(".gopclntab"); sect != nil { - if pclntab, err = sect.Data(); err != nil { - return nil, err - } - } else { - return nil, errors.New("empty .gopclntab") - } - - textStart := gosym2.ParseRuntimeTextFromPclntab18(pclntab) - - if textStart == 0 { - // for older versions text.Addr is enough - // https://github.com/golang/go/commit/b38ab0ac5f78ac03a38052018ff629c03e36b864 - textStart = text.Addr - } - if textStart < text.Addr || textStart >= text.Addr+text.Size { - return nil, fmt.Errorf(" runtime.text out of .text bounds %d %d %d", textStart, text.Addr, text.Size) - } - - if patchGo20Magic { - magic := pclntab[0:4] - if binary.LittleEndian.Uint32(magic) == 0xFFFFFFF1 { - binary.LittleEndian.PutUint32(magic, 0xFFFFFFF0) - } - } - pcln := gosym.NewLineTable(pclntab, textStart) - table, err := gosym.NewTable(nil, pcln) - if err != nil { - return nil, err - } - if len(table.Funcs) == 0 { - return nil, errors.New("gosymtab: no symbols found") - } - - es := make([]TestSym, 0, len(table.Funcs)) - for _, fun := range table.Funcs { - es = append(es, TestSym{Start: fun.Entry, Name: fun.Name}) - } - - return es, nil -} diff --git a/ebpf/symtab/elf_cache.go b/ebpf/symtab/elf_cache.go deleted file mode 100644 index 44c265ea6a..0000000000 --- a/ebpf/symtab/elf_cache.go +++ /dev/null @@ -1,102 +0,0 @@ -package symtab - -import ( - "github.com/grafana/pyroscope/ebpf/symtab/elf" -) - -type ElfCache struct { - BuildIDCache *GCache[elf.BuildID, SymbolNameResolver] - SameFileCache *GCache[Stat, SymbolNameResolver] -} - -func NewElfCache(buildIDCacheOptions GCacheOptions, sameFileCacheOptions GCacheOptions) (*ElfCache, error) { - buildIdCache, err := NewGCache[elf.BuildID, SymbolNameResolver](buildIDCacheOptions) - if err != nil { - return nil, err - } - - statCache, err := NewGCache[Stat, SymbolNameResolver](sameFileCacheOptions) - if err != nil { - return nil, err - } - return &ElfCache{ - BuildIDCache: buildIdCache, - SameFileCache: statCache}, nil -} - -func (e *ElfCache) GetSymbolsByBuildID(buildID elf.BuildID) SymbolNameResolver { - res := e.BuildIDCache.Get(buildID) - if res == nil { - return nil - } - if res.IsDead() { - e.BuildIDCache.Remove(buildID) - return nil - } - return res -} - -func (e *ElfCache) CacheByBuildID(buildID elf.BuildID, v SymbolNameResolver) { - if v == nil { - return - } - e.BuildIDCache.Cache(buildID, v) -} - -func (e *ElfCache) GetSymbolsByStat(s Stat) SymbolNameResolver { - res := e.SameFileCache.Get(s) - if res == nil { - return nil - } - if res.IsDead() { - e.SameFileCache.Remove(s) - return nil - } - return res -} - -func (e *ElfCache) CacheByStat(s Stat, v SymbolNameResolver) { - if v == nil { - return - } - e.SameFileCache.Cache(s, v) -} - -func (e *ElfCache) Update(buildIDCacheOptions GCacheOptions, sameFileCacheOptions GCacheOptions) { - e.BuildIDCache.Update(buildIDCacheOptions) - e.SameFileCache.Update(sameFileCacheOptions) -} - -func (e *ElfCache) NextRound() { - e.BuildIDCache.NextRound() - e.SameFileCache.NextRound() -} - -func (e *ElfCache) Cleanup() { - e.BuildIDCache.Cleanup() - e.SameFileCache.Cleanup() -} - -type ElfCacheDebugInfo struct { - BuildIDCache GCacheDebugInfo[elf.SymTabDebugInfo] `alloy:"build_id_cache,attr,optional" river:"build_id_cache,attr,optional"` - SameFileCache GCacheDebugInfo[elf.SymTabDebugInfo] `alloy:"same_file_cache,attr,optional" river:"same_file_cache,attr,optional"` -} - -func (e *ElfCache) DebugInfo() ElfCacheDebugInfo { - return ElfCacheDebugInfo{ - BuildIDCache: DebugInfo[elf.BuildID, SymbolNameResolver, elf.SymTabDebugInfo]( - e.BuildIDCache, - func(b elf.BuildID, v SymbolNameResolver, round int) elf.SymTabDebugInfo { - res := v.DebugInfo() - res.LastUsedRound = round - return res - }), - SameFileCache: DebugInfo[Stat, SymbolNameResolver, elf.SymTabDebugInfo]( - e.SameFileCache, - func(s Stat, v SymbolNameResolver, round int) elf.SymTabDebugInfo { - res := v.DebugInfo() - res.LastUsedRound = round - return res - }), - } -} diff --git a/ebpf/symtab/elf_cache_test.go b/ebpf/symtab/elf_cache_test.go deleted file mode 100644 index 1ccb4f37b9..0000000000 --- a/ebpf/symtab/elf_cache_test.go +++ /dev/null @@ -1,175 +0,0 @@ -package symtab - -import ( - "io" - "os" - "path/filepath" - "testing" - - "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/grafana/pyroscope/ebpf/util" - "github.com/stretchr/testify/require" -) - -var ( - testCacheOptions = GCacheOptions{32, 3} -) - -func TestElfCacheStrippedEmpty(t *testing.T) { - logger := util.TestLogger(t) - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - fs := "." // make it unable to find debug file by buildID - stripped := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, fs, "elf/testdata/elfs/elf.stripped", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - - syms := []struct { - name string - pc uint64 - }{ - {"iter", 0x1149}, - {"main", 0x115e}, - } - for _, sym := range syms { - res := stripped.Resolve(sym.pc) - require.Error(t, stripped.err) - require.Equal(t, "", res) - } -} - -func TestElfCacheBuildID(t *testing.T) { - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - debug := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, ".", "elf/testdata/elfs/elf", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - - stripped := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, ".", "elf/testdata/elfs/elf.stripped", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - - syms := []struct { - name string - pc uint64 - }{ - {"iter", 0x1149}, - {"main", 0x115e}, - } - for _, sym := range syms { - res := debug.Resolve(sym.pc) - require.NoError(t, debug.err) - require.Equal(t, sym.name, res) - res = stripped.Resolve(sym.pc) - require.NoError(t, stripped.err) - require.Equal(t, sym.name, res) - } - require.Equal(t, 1, elfCache.BuildIDCache.lruCache.Len()) - require.Equal(t, 0, elfCache.SameFileCache.lruCache.Len()) -} - -func TestElfCacheStat(t *testing.T) { - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - f1 := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, ".", "elf/testdata/elfs/elf.nobuildid", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - - f2 := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, ".", "elf/testdata/elfs/elf.nobuildid", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - - syms := []struct { - name string - pc uint64 - }{ - {"iter", 0x1149}, - {"main", 0x115e}, - } - for _, sym := range syms { - res := f1.Resolve(sym.pc) - require.NoError(t, f1.err) - require.Equal(t, sym.name, res) - res = f2.Resolve(sym.pc) - require.NoError(t, f2.err) - require.Equal(t, sym.name, res) - } - require.Equal(t, 0, elfCache.BuildIDCache.lruCache.Len()) - require.Equal(t, 1, elfCache.SameFileCache.lruCache.Len()) -} - -func TestElfCacheBuildIDProcessDeath(t *testing.T) { - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - root, err := os.MkdirTemp("", "elf_cache_test") - defer os.RemoveAll(root) - require.NoError(t, err) - _, err = copyFile("elf/testdata/elfs/elf", root+"/elf1") - require.NoError(t, err) - _, err = copyFile("elf/testdata/elfs/elf", root+"/elf2") - require.NoError(t, err) - - f1 := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, root, "/elf1", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - - f2 := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, root, "/elf2", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - require.Equal(t, "iter", f1.Resolve(0x1149)) - require.Equal(t, "iter", f2.Resolve(0x1149)) - require.True(t, f2.loadedCached) - - err = os.Remove(root + "/elf1") - require.NoError(t, err) - - elfCache.Cleanup() - - require.Equal(t, "iter", f2.Resolve(0x1149)) - require.False(t, f2.loadedCached) - - err = os.Remove(root + "/elf2") - require.NoError(t, err) - - elfCache.Cleanup() - - require.Equal(t, "", f2.Resolve(0x1149)) - require.False(t, f2.loadedCached) - require.True(t, f2.loaded) - require.Error(t, f2.err) -} - -func copyFile(src, dst string) (int64, error) { - cleanSrc := filepath.Clean(src) - cleanDst := filepath.Clean(dst) - if cleanSrc == cleanDst { - return 0, nil - } - sf, err := os.Open(cleanSrc) - if err != nil { - return 0, err - } - defer sf.Close() - if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) { - return 0, err - } - df, err := os.Create(cleanDst) - if err != nil { - return 0, err - } - defer df.Close() - return io.Copy(df, sf) -} diff --git a/ebpf/symtab/elf_test.go b/ebpf/symtab/elf_test.go deleted file mode 100644 index b01f39db98..0000000000 --- a/ebpf/symtab/elf_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package symtab - -import ( - elf2 "debug/elf" - "testing" - - "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/grafana/pyroscope/ebpf/symtab/elf" - "github.com/grafana/pyroscope/ebpf/util" - "github.com/stretchr/testify/assert" - - "github.com/stretchr/testify/require" -) - -func TestElf(t *testing.T) { - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - tab := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, ".", "elf/testdata/elfs/elf", - ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }) - - syms := []struct { - name string - pc uint64 - }{ - {"", 0x0}, - {"iter", 0x1149}, - {"main", 0x115e}, - } - for _, sym := range syms { - res := tab.Resolve(sym.pc) - require.Equal(t, res, sym.name) - } -} - -func TestGoTableFallbackFiltering(t *testing.T) { - ts := []struct { - f string - }{ - {"elf/testdata/elfs/go12"}, - {"elf/testdata/elfs/go16"}, - {"elf/testdata/elfs/go18"}, - {"elf/testdata/elfs/go20"}, - {"elf/testdata/elfs/go12-static"}, - {"elf/testdata/elfs/go16-static"}, - {"elf/testdata/elfs/go18-static"}, - {"elf/testdata/elfs/go20-static"}, - } - for _, e := range ts { - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - tab := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, ".", e.f, - ElfTableOptions{ - ElfCache: elfCache, - SymbolOptions: &SymbolOptions{GoTableFallback: true}, - Metrics: metrics.NewSymtabMetrics(nil), - }) - tab.load() - require.NoError(t, tab.err) - gt, ok := tab.table.(*elf.GoTableWithFallback) - require.True(t, ok) - _ = gt - for i := 0; i < gt.GoTable.Index.Entry.Length(); i++ { - pc := gt.GoTable.Index.Entry.Get(i) - s1 := gt.GoTable.Resolve(pc) - s2 := gt.SymTable.Resolve(pc) - require.NotEqual(t, "", s1) - require.Equal(t, "", s2) - } - elfCache.Cleanup() - } - -} - -func TestGoTableFallbackDisabled(t *testing.T) { - ts := []struct { - f string - }{ - {"elf/testdata/elfs/go12"}, - {"elf/testdata/elfs/go16"}, - {"elf/testdata/elfs/go18"}, - {"elf/testdata/elfs/go20"}, - {"elf/testdata/elfs/go12-static"}, - {"elf/testdata/elfs/go16-static"}, - {"elf/testdata/elfs/go18-static"}, - {"elf/testdata/elfs/go20-static"}, - } - for _, e := range ts { - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - tab := NewElfTable(logger, &ProcMap{StartAddr: 0x1000, Offset: 0x1000}, ".", e.f, - ElfTableOptions{ - ElfCache: elfCache, - SymbolOptions: &SymbolOptions{GoTableFallback: false}, - Metrics: metrics.NewSymtabMetrics(nil), - }) - tab.load() - require.NoError(t, tab.err) - _, ok := tab.table.(*elf.GoTable) - require.True(t, ok) - elfCache.Cleanup() - } - -} - -func TestFindBaseExec(t *testing.T) { - et := ElfTable{} - ef := elf.MMapedElfFile{} - ef.FileHeader.Type = elf2.ET_EXEC - assert.True(t, et.findBase(&ef)) - assert.Equal(t, uint64(0), et.base) -} - -func TestFindBaseAlignedNoSeparateCode(t *testing.T) { - //559f9d29f000-559f9d2ab000 r-xp 00000000 fc:01 53049243 /FibProfilingTest - //559f9d2ab000-559f9d2ac000 r--p 0000b000 fc:01 53049243 /FibProfilingTest - //559f9d2ac000-559f9d2ad000 rw-p 0000c000 fc:01 53049243 /FibProfilingTest - - //Program Headers: - //Type Offset VirtAddr PhysAddr - // FileSiz MemSiz Flags Align - //LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 - // 0x000000000000b1f4 0x000000000000b1f4 R E 0x1000 - // LOAD 0x000000000000bd90 0x000000000000cd90 0x000000000000cd90 - // 0x0000000000000370 0x00000000000003f8 RW 0x1000 - - et := ElfTable{} - et.procMap = &ProcMap{StartAddr: 0x559f9d29f000, EndAddr: 0x559f9d2ab000, Perms: &ProcMapPermissions{Execute: true, Read: true}, Offset: 0} - - ef := elf.MMapedElfFile{} - ef.FileHeader.Type = elf2.ET_DYN - ef.Progs = []elf2.ProgHeader{ - {Type: elf2.PT_LOAD, Flags: elf2.PF_X | elf2.PF_R, Off: 0, Vaddr: 0, Filesz: 0xb1f4, Memsz: 0xb1f4}, - } - assert.True(t, et.findBase(&ef)) - assert.Equal(t, uint64(0x559f9d29f000), et.base) -} - -func TestFindBaseUnalignedSeparateCode(t *testing.T) { - //555e3d192000-555e3d1ac000 r--p 00000000 00:3e 1824988 /smoketest - //555e3d1ac000-555e3d212000 r-xp 00019000 00:3e 1824988 /smoketest - //555e3d212000-555e3d218000 r--p 0007e000 00:3e 1824988 /smoketest - //555e3d218000-555e3d219000 rw-p 00083000 00:3e 1824988 /smoketest - - //Type Offset VirtAddr PhysAddr - // FileSiz MemSiz Flags Align - //LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 - // 0x0000000000019194 0x0000000000019194 R 0x1000 - //LOAD 0x00000000000191a0 0x000000000001a1a0 0x000000000001a1a0 - // 0x0000000000064ee0 0x0000000000064ee0 R E 0x1000 - //LOAD 0x000000000007e080 0x0000000000080080 0x0000000000080080 - // 0x0000000000005928 0x0000000000005928 RW 0x1000 - //LOAD 0x00000000000839b0 0x00000000000869b0 0x00000000000869b0 - // 0x0000000000000300 0x000000000020a764 RW 0x1000 - - et := ElfTable{} - et.procMap = &ProcMap{StartAddr: 0x555e3d1ac000, EndAddr: 0x555e3d212000, Perms: &ProcMapPermissions{Execute: true, Read: true}, Offset: 0x00019000} - - ef := elf.MMapedElfFile{} - ef.FileHeader.Type = elf2.ET_DYN - ef.Progs = []elf2.ProgHeader{ - {Type: elf2.PT_LOAD, Flags: elf2.PF_X | elf2.PF_R, Off: 0x191a0, Vaddr: 0x1a1a0, Filesz: 0x64ee0, Memsz: 0x64ee0}, - } - assert.True(t, et.findBase(&ef)) - assert.Equal(t, uint64(0x555e3d192000), et.base) -} diff --git a/ebpf/symtab/gcache.go b/ebpf/symtab/gcache.go deleted file mode 100644 index 07a65d1298..0000000000 --- a/ebpf/symtab/gcache.go +++ /dev/null @@ -1,176 +0,0 @@ -package symtab - -import ( - "fmt" - - lru "github.com/hashicorp/golang-lru/v2" -) - -type Resource interface { - Refresh() - Cleanup() -} - -type GCache[K comparable, V Resource] struct { - options GCacheOptions - - roundCache map[K]*entry[V] - lruCache *lru.Cache[K, *entry[V]] - - round int -} -type entry[V Resource] struct { - v V - round int -} - -type GCacheOptions struct { - Size int - KeepRounds int -} - -func NewGCache[K comparable, V Resource](options GCacheOptions) (*GCache[K, V], error) { - c, err := lru.NewWithEvict[K, *entry[V]](options.Size, func(key K, value *entry[V]) { - value.v.Cleanup() // in theory this is not required, but add just in case - }) - if err != nil { - return nil, fmt.Errorf("lru create %w", err) - } - return &GCache[K, V]{ - options: options, - roundCache: make(map[K]*entry[V]), - lruCache: c, - }, nil -} - -func (g *GCache[K, V]) NextRound() { - g.round++ -} - -func (g *GCache[K, V]) Get(k K) V { - var zeroKey K - var zeroVal V - if k == zeroKey { - return zeroVal - } - e, ok := g.lruCache.Get(k) - if ok && e != nil { - if e.round != g.round { - e.round = g.round - e.v.Refresh() - } - return e.v - } - e, ok = g.roundCache[k] - if ok && e != nil { - if e.round != g.round { - e.round = g.round - e.v.Refresh() - } - return e.v - } - return zeroVal -} - -func (g *GCache[K, V]) Cache(k K, v V) { - var zeroKey K - if k == zeroKey { - return - } - e := &entry[V]{v: v, round: g.round} - e.v.Refresh() - g.lruCache.Add(k, e) - g.roundCache[k] = e -} - -func (g *GCache[K, V]) Update(options GCacheOptions) { - g.lruCache.Resize(options.Size) - g.options = options -} - -func (g *GCache[K, V]) Cleanup() { - keys := g.lruCache.Keys() - for _, pid := range keys { - tab, ok := g.lruCache.Peek(pid) - if !ok || tab == nil { - continue - } - tab.v.Cleanup() - } - - prev := g.roundCache - next := make(map[K]*entry[V]) - for k, e := range prev { - e.v.Cleanup() - if e.round >= g.round-g.options.KeepRounds { - next[k] = e - } - } - g.roundCache = next - - //level.Debug(sc.logger).Log("msg", "symbolCache cleanup", "was", len(prev), "now", len(sc.roundCache)) -} - -func (g *GCache[K, V]) LRUSize() int { - return g.lruCache.Len() -} - -func (g *GCache[K, V]) Each(f func(k K, v V, round int)) { - g.EachLRU(f) - g.EachRound(f) -} -func (g *GCache[K, V]) EachLRU(f func(k K, v V, round int)) { - keys := g.lruCache.Keys() - for _, k := range keys { - e, ok := g.lruCache.Peek(k) - if !ok || e == nil { - continue - } - f(k, e.v, e.round) - } -} - -func (g *GCache[K, V]) RoundSize() int { - return len(g.roundCache) -} - -func (g *GCache[K, V]) EachRound(f func(k K, v V, round int)) { - keys := g.lruCache.Keys() - for _, k := range keys { - e, ok := g.lruCache.Peek(k) - if !ok || e == nil { - continue - } - f(k, e.v, e.round) - } -} - -func (g *GCache[K, V]) Remove(k K) { - g.lruCache.Remove(k) - delete(g.roundCache, k) -} - -type GCacheDebugInfo[T any] struct { - LRUSize int `alloy:"lru_size,attr,optional" river:"lru_size,attr,optional"` - RoundSize int `alloy:"round_size,attr,optional" river:"round_size,attr,optional"` - CurrentRound int `alloy:"current_round,attr,optional" river:"current_round,attr,optional"` - LRUDump []T `alloy:"lru_dump,block,optional" river:"lru_dump,block,optional"` - RoundDump []T `alloy:"round_dump,block,optional" river:"round_dump,block,optional"` -} - -func DebugInfo[K comparable, V Resource, D any](g *GCache[K, V], ff func(K, V, int) D) GCacheDebugInfo[D] { - res := GCacheDebugInfo[D]{ - LRUSize: g.LRUSize(), - RoundSize: g.RoundSize(), - CurrentRound: g.round, - LRUDump: make([]D, 0, g.LRUSize()), - RoundDump: make([]D, 0, g.RoundSize()), - } - g.EachLRU(func(k K, v V, round int) { - res.LRUDump = append(res.LRUDump, ff(k, v, round)) - }) - g.EachRound(func(k K, v V, round int) { - res.RoundDump = append(res.RoundDump, ff(k, v, round)) - }) - return res -} diff --git a/ebpf/symtab/gcache_test.go b/ebpf/symtab/gcache_test.go deleted file mode 100644 index bbbf315ffa..0000000000 --- a/ebpf/symtab/gcache_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package symtab - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -type mockResource struct { - name string - refresh int - cleanup int -} - -func (m *mockResource) Refresh() { - m.refresh++ -} - -func (m *mockResource) Cleanup() { - m.cleanup++ -} - -func (m *mockResource) DebugString() string { - return "mock{}" -} - -func TestGCache(t *testing.T) { - cache, err := NewGCache[string, *mockResource](GCacheOptions{Size: 2, KeepRounds: 3}) - require.NoError(t, err) - cache.NextRound() - require.Equal(t, 1, cache.round) - - r1 := &mockResource{name: "r1"} - r2 := &mockResource{name: "r2"} - r3 := &mockResource{name: "r3"} - - res := cache.Get("k1") - require.Nil(t, res) - - cache.Cache("k1", r1) - res = cache.Get("k1") - require.Equal(t, r1, res) - require.Equal(t, 1, res.refresh) - require.Equal(t, 0, res.cleanup) - - res = cache.Get("k1") - require.Equal(t, 1, res.refresh) - require.Equal(t, 0, res.cleanup) - - require.Equal(t, 1, len(cache.roundCache)) - require.Equal(t, 1, cache.lruCache.Len()) - - cache.Cache("k2", r2) - require.Equal(t, 1, r2.refresh) - require.Equal(t, 0, r2.cleanup) - require.Equal(t, 2, len(cache.roundCache)) - require.Equal(t, 2, cache.lruCache.Len()) - - cache.Cache("k3", r3) - require.Equal(t, 3, len(cache.roundCache)) - require.Equal(t, 2, cache.lruCache.Len()) - - cache.Cleanup() - require.NotEqual(t, 0, r1.cleanup) - require.NotEqual(t, 0, r2.cleanup) - require.NotEqual(t, 0, r3.cleanup) - require.Equal(t, 2, cache.lruCache.Len()) - require.Equal(t, 3, len(cache.roundCache)) - - // round 2 - cache.NextRound() - require.Equal(t, 2, cache.round) - - r1.cleanup = 0 - r2.cleanup = 0 - r3.cleanup = 0 - r1.refresh = 0 - r2.refresh = 0 - r3.refresh = 0 - - res = cache.Get("k1") - require.Equal(t, r1, res) - require.Equal(t, 1, r1.refresh) - - cache.Cleanup() - require.NotEqual(t, 0, r1.cleanup) - require.NotEqual(t, 0, r2.cleanup) - require.NotEqual(t, 0, r3.cleanup) - - // round 3 - - cache.NextRound() - cache.Cache("k4", &mockResource{}) - cache.Cache("k5", &mockResource{}) - cache.Cleanup() - - // round 4 - cache.NextRound() - cache.Cleanup() - - // round 5 - cache.NextRound() - cache.Cleanup() - - require.Equal(t, 2, cache.lruCache.Len()) - require.Equal(t, 3, len(cache.roundCache)) - - res = cache.Get("k1") - require.Equal(t, res, r1) - res = cache.Get("k2") - require.Nil(t, res) - res = cache.Get("k3") - require.Nil(t, res) - - res = cache.Get("k4") - require.NotNil(t, res) - res = cache.Get("k5") - require.NotNil(t, res) -} diff --git a/ebpf/symtab/gosym.go b/ebpf/symtab/gosym.go deleted file mode 100644 index 2f48d6c5f0..0000000000 --- a/ebpf/symtab/gosym.go +++ /dev/null @@ -1 +0,0 @@ -package symtab diff --git a/ebpf/symtab/gosym/data.go b/ebpf/symtab/gosym/data.go deleted file mode 100644 index ce00c31a97..0000000000 --- a/ebpf/symtab/gosym/data.go +++ /dev/null @@ -1,44 +0,0 @@ -package gosym - -import ( - "io" - "os" - - bufra "github.com/avvmoto/buf-readerat" -) - -type PCLNData interface { - ReadAt(data []byte, offset int) error -} - -type MemPCLNData struct { - Data []byte -} - -func (m MemPCLNData) ReadAt(data []byte, offset int) error { - copy(data, m.Data[offset:]) - return nil -} - -type FilePCLNData struct { - file io.ReaderAt - offset int -} - -func NewFilePCLNData(f *os.File, offset int) *FilePCLNData { - return &FilePCLNData{ - file: bufra.NewBufReaderAt(f, 4*0x1000), - offset: offset, - } -} - -func (f *FilePCLNData) ReadAt(data []byte, offset int) error { - n, err := f.file.ReadAt(data, int64(offset+f.offset)) - if err != nil { - return err - } - if n != len(data) { - return io.EOF - } - return nil -} diff --git a/ebpf/symtab/gosym/parse.go b/ebpf/symtab/gosym/parse.go deleted file mode 100644 index cc9f1c389b..0000000000 --- a/ebpf/symtab/gosym/parse.go +++ /dev/null @@ -1,33 +0,0 @@ -package gosym - -import "encoding/binary" - -func ParseRuntimeTextFromPclntab18(pclntab []byte) uint64 { - if len(pclntab) < 64 { - return 0 - } - magic := binary.LittleEndian.Uint32(pclntab[0:4]) - if magic == 0xFFFFFFF0 || magic == 0xFFFFFFF1 { - // https://github.com/golang/go/blob/go1.18/src/runtime/symtab.go#L395 - // 0xFFFFFFF1 is the same - // https://github.com/golang/go/commit/0f8dffd0aa71ed996d32e77701ac5ec0bc7cde01 - //type pcHeader struct { - // magic uint32 // 0xFFFFFFF0 - // pad1, pad2 uint8 // 0,0 - // minLC uint8 // min instruction size - // ptrSize uint8 // size of a ptr in bytes - // nfunc int // number of functions in the module - // nfiles uint // number of entries in the file tab - // textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text - // funcnameOffset uintptr // offset to the funcnametab variable from pcHeader - // cuOffset uintptr // offset to the cutab variable from pcHeader - // filetabOffset uintptr // offset to the filetab variable from pcHeader - // pctabOffset uintptr // offset to the pctab variable from pcHeader - // pclnOffset uintptr // offset to the pclntab variable from pcHeader - //} - textStart := binary.LittleEndian.Uint64(pclntab[24:32]) - return textStart - } - - return 0 -} diff --git a/ebpf/symtab/gosym/pcindex.go b/ebpf/symtab/gosym/pcindex.go deleted file mode 100644 index fa8928a0b5..0000000000 --- a/ebpf/symtab/gosym/pcindex.go +++ /dev/null @@ -1,119 +0,0 @@ -package gosym - -import ( - "math" - "slices" -) - -type PCIndex struct { - i32 []uint32 - i64 []uint64 -} - -func NewPCIndex(sz int) PCIndex { - return PCIndex{ - i32: make([]uint32, sz), - i64: nil, - } -} - -func (it *PCIndex) Set(idx int, value uint64) { - if it.i32 != nil && value < math.MaxUint32 { - it.i32[idx] = uint32(value) - return - } - it.setImpl(idx, value) -} - -func (it *PCIndex) setImpl(idx int, value uint64) { - if it.i32 != nil { - if value >= math.MaxUint32 { - Values64 := make([]uint64, len(it.i32)) - for j := 0; j < idx; j++ { - Values64[j] = uint64(it.i32[j]) - } - it.i32 = nil - Values64[idx] = value - it.i64 = Values64 - } else { - it.i32[idx] = uint32(value) - } - } else { - it.i64[idx] = value - } -} - -func (it *PCIndex) Length() int { - if it.i32 != nil { - return len(it.i32) - } - return len(it.i64) -} - -func (it *PCIndex) Get(idx int) uint64 { - if it.i32 != nil { - return uint64(it.i32[idx]) - } - return it.i64[idx] -} - -func (it *PCIndex) Is32() bool { - return it.i32 != nil -} -func (it *PCIndex) First() uint64 { - if it.i32 != nil { - return uint64(it.i32[0]) - } - return it.i64[0] -} - -func (it *PCIndex) FindIndex(addr uint64) int { - if it.i32 != nil { - - if addr < uint64(it.i32[0]) { - return -1 - } - i, found := slices.BinarySearch(it.i32, uint32(addr)) - if found { - return i - } - i-- - v := it.i32[i] - for i > 0 && it.i32[i-1] == v { - i-- - } - return i - } - if addr < it.i64[0] { - return -1 - } - i, found := slices.BinarySearch(it.i64, addr) - if found { - return i - } - i-- - v := it.i64[i] - for i > 0 && it.i64[i-1] == v { - i-- - } - return i -} - -func (it *PCIndex) Value(idx int) uint64 { - if it.i32 != nil { - return uint64(it.i32[idx]) - } - return it.i64[idx] -} -func (it *PCIndex) PCIndex64() PCIndex { - res := *it - if it.i64 != nil { - return res - } - res.i64 = make([]uint64, len(it.i32)) - for i := 0; i < len(it.i32); i++ { - res.i64[i] = uint64(res.i32[i]) - } - res.i32 = nil - return res -} diff --git a/ebpf/symtab/gosym/pcindex_test.go b/ebpf/symtab/gosym/pcindex_test.go deleted file mode 100644 index 23fec062d6..0000000000 --- a/ebpf/symtab/gosym/pcindex_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package gosym - -import ( - "math/rand" - "slices" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestPCIndex_FindIndex(t *testing.T) { - s := "aaaaccfff" - pci := NewPCIndex(len(s)) - for i := 0; i < len(s); i++ { - pci.Set(i, uint64(s[i])) - } - assert.Equal(t, -1, pci.FindIndex(uint64(0x20))) - assert.Equal(t, 0, pci.FindIndex(uint64('a'))) - assert.Equal(t, 0, pci.FindIndex(uint64('b'))) - assert.Equal(t, 4, pci.FindIndex(uint64('c'))) - assert.Equal(t, 4, pci.FindIndex(uint64('d'))) - assert.Equal(t, 4, pci.FindIndex(uint64('e'))) - assert.Equal(t, 6, pci.FindIndex(uint64('f'))) - assert.Equal(t, 6, pci.FindIndex(uint64('z'))) -} - -func BenchmarkBinSearch(b *testing.B) { - const nsym = 64 * 1024 - rnd := rand.NewSource(239) - syms := make([]uint64, nsym) - for i := 0; i < nsym; i++ { - syms[i] = uint64(rnd.Int63()) & 0x7fffffff - } - slices.Sort(syms) - - pci := NewPCIndex(nsym) - for i, sym := range syms { - pci.Set(i, sym) - } - b.ResetTimer() - idx := 0 - for i := 0; i < b.N; i++ { - for j := 0; j < nsym; j++ { - idx += pci.FindIndex(syms[j]) - } - } - b.StopTimer() - //fmt.Println(idx) -} diff --git a/ebpf/symtab/gosym/pclntab.go b/ebpf/symtab/gosym/pclntab.go deleted file mode 100644 index dd6871fadd..0000000000 --- a/ebpf/symtab/gosym/pclntab.go +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// copied from here -// https://github.com/golang/go/blob/go1.20.5/src/debug/gosym/pclntab.go -// modified go12Funcs function to be exported return a FlatFuncIndex instead of []Func -// added FuncNameOffset to export the funcnametabOffset - -/* - * Line tables - */ - -package gosym - -import ( - "encoding/binary" - "sync" -) - -// version of the pclntab -type version int - -const ( - verUnknown version = iota - ver11 - ver12 - ver116 - ver118 - ver120 -) - -// A LineTable is a data structure mapping program counters to line numbers. -// -// In Go 1.1 and earlier, each function (represented by a Func) had its own LineTable, -// and the line number corresponded to a numbering of all source lines in the -// program, across all files. That absolute line number would then have to be -// converted separately to a file name and line number within the file. -// -// In Go 1.2, the format of the data changed so that there is a single LineTable -// for the entire program, shared by all Funcs, and there are no absolute line -// numbers, just line numbers within specific files. -// -// For the most part, LineTable's methods should be treated as an internal -// detail of the package; callers should use the methods on Table instead. -type LineTable struct { - //Data []byte - PCLNData PCLNData - PC uint64 - Line int - - // This mutex is used to keep parsing of pclntab synchronous. - mu sync.Mutex - - // Contains the version of the pclntab section. - version version - - // Go 1.2/1.16/1.18 state - binary binary.ByteOrder - quantum uint32 - ptrsize uint32 - textStart uint64 // address of runtime.text symbol (1.18+) - funcdataOffset uint64 - functabOffset uint64 - nfunctab uint32 - funcnametabOffset uint64 - failed bool - tmpbuf [8]uint8 -} - -// NewLineTable returns a new PC/line table -// corresponding to the encoded data. -// Text must be the start address of the -// corresponding text segment. -func NewLineTable(data []byte, text uint64) *LineTable { - return &LineTable{ - //Data: data, - PCLNData: &MemPCLNData{data}, - PC: text, - Line: 0, - } -} - -func NewLineTableStreaming(data PCLNData, text uint64) *LineTable { - return &LineTable{ - //Data: data, - PCLNData: data, - PC: text, - Line: 0, - } -} - -// Go 1.2 symbol table format. -// See golang.org/s/go12symtab. -// -// A general note about the methods here: rather than try to avoid -// index out of bounds errors, we trust Go to detect them, and then -// we recover from the panics and treat them as indicative of a malformed -// or incomplete table. -// -// The methods called by symtab.go, which begin with "go12" prefixes, -// are expected to have that recovery logic. - -// IsGo12 reports whether this is a Go 1.2 (or later) symbol table. -func (t *LineTable) IsGo12() bool { - t.parsePclnTab() - return t.version >= ver12 -} - -const ( - go12magic = 0xfffffffb - go116magic = 0xfffffffa - go118magic = 0xfffffff0 - go120magic = 0xfffffff1 -) - -// uintptr returns the pointer-sized value encoded at b. -// The pointer size is dictated by the table being read. -func (t *LineTable) uintptrAt(at int) uint64 { - tmpbuf := t.tmpbuf[:t.ptrsize] - _ = t.PCLNData.ReadAt(tmpbuf, at) - if t.ptrsize == 4 { - return uint64(t.binary.Uint32(tmpbuf)) - } - return t.binary.Uint64(tmpbuf) -} - -// parsePclnTab parses the pclntab, setting the version. -func (t *LineTable) parsePclnTab() { - t.mu.Lock() - defer t.mu.Unlock() - if t.version != verUnknown { - return - } - - // Note that during this function, setting the version is the last thing we do. - // If we set the version too early, and parsing failed (likely as a panic on - // slice lookups), we'd have a mistaken version. - // - // Error paths through this code will default the version to 1.1. - t.version = ver11 - - if !disableRecover { - defer func() { - // If we panic parsing, assume it's a Go 1.1 pclntab. - if r := recover(); r != nil { - t.failed = true - } - }() - } - header := make([]byte, 16) - err := t.PCLNData.ReadAt(header, 0) - if err != nil { - return - } - - // Check header: 4-byte magic, two zeros, pc quantum, pointer size. - if len(header) < 16 || header[4] != 0 || header[5] != 0 || - (header[6] != 1 && header[6] != 2 && header[6] != 4) || // pc quantum - (header[7] != 4 && header[7] != 8) { // pointer size - - return - } - - var possibleVersion version - leMagic := binary.LittleEndian.Uint32(header) - beMagic := binary.BigEndian.Uint32(header) - switch { - case leMagic == go12magic: - t.binary, possibleVersion = binary.LittleEndian, ver12 - case beMagic == go12magic: - t.binary, possibleVersion = binary.BigEndian, ver12 - case leMagic == go116magic: - t.binary, possibleVersion = binary.LittleEndian, ver116 - case beMagic == go116magic: - t.binary, possibleVersion = binary.BigEndian, ver116 - case leMagic == go118magic: - t.binary, possibleVersion = binary.LittleEndian, ver118 - case beMagic == go118magic: - t.binary, possibleVersion = binary.BigEndian, ver118 - case leMagic == go120magic: - t.binary, possibleVersion = binary.LittleEndian, ver120 - case beMagic == go120magic: - t.binary, possibleVersion = binary.BigEndian, ver120 - default: - return - } - t.version = possibleVersion - - // quantum and ptrSize are the same between 1.2, 1.16, and 1.18 - t.quantum = uint32(header[6]) - t.ptrsize = uint32(header[7]) - - offset := func(word uint32) uint64 { - at := 8 + word*t.ptrsize - return t.uintptrAt(int(at)) - } - switch possibleVersion { - case ver118, ver120: - t.nfunctab = uint32(offset(0)) - t.textStart = t.PC // use the start PC instead of reading from the table, which may be unrelocated - t.funcnametabOffset = offset(3) - t.funcdataOffset = offset(7) - t.functabOffset = offset(7) - case ver116: - t.nfunctab = uint32(offset(0)) - t.funcnametabOffset = offset(2) - t.funcdataOffset = offset(6) - t.functabOffset = offset(6) - case ver12: - t.nfunctab = uint32(t.uintptrAt(8)) - t.funcdataOffset = 0 - t.funcnametabOffset = 0 - t.functabOffset = uint64(8 + t.ptrsize) - default: - panic("unreachable") - } -} - -// FlatFuncIndex -// Entry contains a sorted array of function entry address, which is ued for binary search. -// Name contains offsets into funcnametab, which is located in the .gopclntab section. -type FlatFuncIndex struct { - Entry PCIndex - Name []uint32 - End uint64 -} - -// Go12Funcs returns a slice of Funcs derived from the Go 1.2+ pcln table. -func (t *LineTable) Go12Funcs() (res FlatFuncIndex) { - // Assume it is malformed and return nil on error. - if !disableRecover { - defer func() { - err := recover() - if err != nil { - res = FlatFuncIndex{} - } - }() - } - - ft := t.funcTab() - nfunc := ft.Count() - res = FlatFuncIndex{ - Entry: NewPCIndex(nfunc), - Name: make([]uint32, nfunc), - } - funcDatas := make([]uint64, nfunc) - for i := 0; i < nfunc; i++ { - entry := ft.pc(i) - res.Entry.Set(i, entry) - res.End = ft.pc(i + 1) - dataOffset := t.funcTab().funcOff(int(i)) - - //info := t.funcData(uint32(i)) - funcDatas[i] = dataOffset - //res.Name[i] = dataOffset - } - for i := 0; i < nfunc; i++ { - //entry := ft.pc(i) - //res.Entry.Set(i, entry) - //res.End = ft.pc(i + 1) - //info := t.funcData(uint32(i)) - info := funcData{t: t, dataOffset: funcDatas[i]} - res.Name[i] = info.nameOff() - } - return -} - -// functabFieldSize returns the size in bytes of a single functab field. -func (t *LineTable) functabFieldSize() int { - if t.version >= ver118 { - return 4 - } - return int(t.ptrsize) -} - -// funcTab returns t's funcTab. -func (t *LineTable) funcTab() funcTab { - return funcTab{LineTable: t, sz: t.functabFieldSize()} -} - -// funcTab is memory corresponding to a slice of functab structs, followed by an invalid PC. -// A functab struct is a PC and a func offset. -type funcTab struct { - *LineTable - sz int // cached result of t.functabFieldSize -} - -// Count returns the number of func entries in f. -func (f funcTab) Count() int { - return int(f.nfunctab) -} - -// pc returns the PC of the i'th func in f. -func (f funcTab) pc(i int) uint64 { - u := f.uintAt(int(f.functabOffset) + 2*i*f.sz) - if f.version >= ver118 { - u += f.textStart - } - return u -} - -// funcOff returns the funcdata offset of the i'th func in f. -func (f funcTab) funcOff(i int) uint64 { - return f.uintAt(int(f.functabOffset) + (2*i+1)*f.sz) -} - -// uint returns the uint stored at b. -func (f funcTab) uintAt(at int) uint64 { - tmpbuf := f.tmpbuf[:f.sz] - _ = f.PCLNData.ReadAt(tmpbuf, at) - if f.sz == 4 { - return uint64(f.binary.Uint32(tmpbuf)) - } - return f.binary.Uint64(tmpbuf) -} - -// funcData is memory corresponding to an _func struct. -type funcData struct { - t *LineTable // LineTable this data is a part of - //data []byte // raw memory for the function - dataOffset uint64 // offset into funcdata -} - -// funcData returns the ith funcData in t.functab. -func (t *LineTable) funcData(i uint32) funcData { - dataOffset := t.funcTab().funcOff(int(i)) - return funcData{t: t, dataOffset: dataOffset} -} - -// IsZero reports whether f is the zero value. -//func (f funcData) IsZero() bool { -// return f.t == nil && f.data == nil -//} - -func (f funcData) nameOff() uint32 { return f.field(1) } - -// field returns the nth field of the _func struct. -// It panics if n == 0 or n > 9; for n == 0, call f.entryPC. -// Most callers should use a named field accessor (just above). -func (f funcData) field(n uint32) uint32 { - if n == 0 || n > 9 { - panic("bad funcdata field") - } - // In Go 1.18, the first field of _func changed - // from a uintptr entry PC to a uint32 entry offset. - sz0 := f.t.ptrsize - if f.t.version >= ver118 { - sz0 = 4 - } - off := sz0 + (n-1)*4 // subsequent fields are 4 bytes each - dataOffset := f.dataOffset + f.t.funcdataOffset + uint64(off) - //data := f.data[off:] - data := f.t.tmpbuf[:4] - - _ = f.t.PCLNData.ReadAt(data, int(dataOffset)) - return f.t.binary.Uint32(data) -} - -func (t *LineTable) IsFailed() bool { - return t.failed -} - -func (t *LineTable) FuncNameOffset() uint64 { - return t.funcnametabOffset -} - -// disableRecover causes this package not to swallow panics. -// This is useful when making changes. -const disableRecover = false diff --git a/ebpf/symtab/gosym_linux_test.go b/ebpf/symtab/gosym_linux_test.go deleted file mode 100644 index b8bf21bb7f..0000000000 --- a/ebpf/symtab/gosym_linux_test.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build linux - -package symtab - -import ( - "encoding/hex" - "reflect" - "strings" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/grafana/pyroscope/ebpf/symtab/elf" - gosym2 "github.com/grafana/pyroscope/ebpf/symtab/gosym" -) - -func TestGoSymSelfTest(t *testing.T) { - var ptr = reflect.ValueOf(TestGoSymSelfTest).Pointer() - mod := "/proc/self/exe" - me, err := elf.NewMMapedElfFile(mod) - require.NoError(t, err) - defer me.Close() - symtab, err := me.NewGoTable() - require.NoError(t, err) - sym := symtab.Resolve(uint64(ptr)) - expectedSym := "github.com/grafana/pyroscope/ebpf/symtab.TestGoSymSelfTest" - require.NotNil(t, sym) - require.Equal(t, expectedSym, sym) -} - -func TestPclntab18(t *testing.T) { - s := "f0 ff ff ff 00 00 01 08 9a 05 00 00 00 00 00 00 " + - " bb 00 00 00 00 00 00 00 a0 23 40 00 00 00 00 00" + - " 60 00 00 00 00 00 00 00 c0 bb 00 00 00 00 00 00" + - " c0 c3 00 00 00 00 00 00 c0 df 00 00 00 00 00 00" - bs, _ := hex.DecodeString(strings.ReplaceAll(s, " ", "")) - textStart := gosym2.ParseRuntimeTextFromPclntab18(bs) - expected := uint64(0x4023a0) - require.Equal(t, expected, textStart) -} - -func BenchmarkGoSym(b *testing.B) { - mod := "/proc/self/exe" - symbols, err := elf.GetGoSymbols(mod, false) - require.NoError(b, err) - me, err := elf.NewMMapedElfFile(mod) - require.NoError(b, err) - defer me.Close() - gosym, err := me.NewGoTable() - require.NoError(b, err) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - for _, symbol := range symbols { - gosym.Resolve(symbol.Start) - } - } -} diff --git a/ebpf/symtab/gosym_test.go b/ebpf/symtab/gosym_test.go deleted file mode 100644 index 2f48d6c5f0..0000000000 --- a/ebpf/symtab/gosym_test.go +++ /dev/null @@ -1 +0,0 @@ -package symtab diff --git a/ebpf/symtab/kallsyms.go b/ebpf/symtab/kallsyms.go deleted file mode 100644 index 3601dafa96..0000000000 --- a/ebpf/symtab/kallsyms.go +++ /dev/null @@ -1,98 +0,0 @@ -package symtab - -import ( - "bytes" - "fmt" - "os" - "runtime" - "strconv" -) - -var kallsymsModule = []byte("kernel") - -func NewKallsyms() (*SymbolTab, error) { - return NewKallsymsFromFile("/proc/kallsyms") -} - -func NewKallsymsFromFile(f string) (*SymbolTab, error) { - kallsymsData, err := os.ReadFile(f) - if err != nil { - return nil, fmt.Errorf("read kallsyms %w", err) - } - return NewKallsymsFromData(kallsymsData) -} - -func NewKallsymsFromData(kallsyms []byte) (*SymbolTab, error) { - kernelAddrSpace := uint64(0) - if runtime.GOARCH == "amd64" { - // https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt - kernelAddrSpace = 0x00ffffffffffffff - } - - var syms []Symbol - allZeros := true - for len(kallsyms) > 0 { - i := bytes.IndexByte(kallsyms, '\n') - var line []byte - if i == -1 { - line = kallsyms - kallsyms = nil - } else { - line = kallsyms[:i] - kallsyms = kallsyms[i+1:] - } - - if len(line) == 0 { - continue - } - space := bytes.IndexByte(line, ' ') - if space == -1 { - return nil, fmt.Errorf("no space found") - } - addr := line[:space] - line = line[space+1:] - - space = bytes.IndexByte(line, ' ') - if space == -1 { - return nil, fmt.Errorf("no space found") - } - typ := line[:space] - line = line[space+1:] - - var name []byte - var mod []byte - tab := bytes.IndexByte(line, '\t') - if tab == -1 { - name = line - mod = kallsymsModule - } else { - name = line[:tab] - mod = line[tab+1:] - } - - if typ[0] == 'b' || typ[0] == 'B' || typ[0] == 'd' || - typ[0] == 'D' || typ[0] == 'r' || typ[0] == 'R' { - - continue - } - - istart, err := strconv.ParseUint(string(addr), 16, 64) - if err != nil { - return nil, err - } - if istart < kernelAddrSpace { - continue - } - if bytes.HasPrefix(mod, []byte{'['}) && bytes.HasSuffix(mod, []byte{']'}) { - mod = mod[1 : len(mod)-1] - } - if istart != 0 { - allZeros = false - } - syms = append(syms, Symbol{istart, string(name), string(mod)}) - } - if allZeros { - return NewSymbolTab(nil), nil - } - return NewSymbolTab(syms), nil -} diff --git a/ebpf/symtab/kallsyms_test.go b/ebpf/symtab/kallsyms_test.go deleted file mode 100644 index fbb34bb3ae..0000000000 --- a/ebpf/symtab/kallsyms_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package symtab - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -var testdata = `ffffffff81000000 T _text -ffffffff81000040 T _stext -ffffffff81000060 T startup_64 -ffffffff81000170 T x86_64_start_kernel -ffffffff810001e0 T x86_64_start_reservations -ffffffff81000250 T start_kernel -ffffffff81000ad0 T setup_arch -ffffffff81001200 T setup_machine_fdt [fake_module] -ffffffff81001450 T setup_machine_tags -ffffffff81001630 T reserve_early -ffffffff81001640 D data_symbol -ffffffff81001660 T free_memory_resource -ffffffff810016a0 T alloc_memory_resource -ffffffff810016f0 T memblock_reserve -ffffffff81001720 T memblock_free -ffffffff81001750 T memblock_find -ffffffff81001780 T __memblock_alloc_base -ffffffff810017d0 T memblock_alloc -ffffffff81001820 T early_memtest -ffffffff810018a0 T early_memtest_report` - -func TestKallsyms(t *testing.T) { - kallsyms, err := NewKallsymsFromData([]byte(testdata)) - if err != nil { - t.Fatal(err) - } - testcases := []struct { - addr uint64 - name string - mod string - }{ - {0xffffffff81001820, "early_memtest", "kernel"}, - {0xffffffff810018a0, "early_memtest_report", "kernel"}, - {0xffffffff81001640, "reserve_early", "kernel"}, - {0xffffffff81001200, "setup_machine_fdt", "fake_module"}, - } - for _, testcase := range testcases { - resolved := kallsyms.Resolve(testcase.addr) - if testcase.name == "" { - require.Nil(t, resolved.Name) - return - } - require.Equal(t, testcase.name, resolved.Name) - require.Equal(t, testcase.mod, resolved.Module) - } -} diff --git a/ebpf/symtab/proc.go b/ebpf/symtab/proc.go deleted file mode 100644 index 7c10059d85..0000000000 --- a/ebpf/symtab/proc.go +++ /dev/null @@ -1,189 +0,0 @@ -package symtab - -import ( - "fmt" - "os" - "path" - "slices" - "strconv" - "strings" - - "github.com/grafana/pyroscope/ebpf/symtab/elf" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/pkg/errors" -) - -type ProcTable struct { - logger log.Logger - ranges []elfRange - file2Table map[file]*ElfTable - options ProcTableOptions - rootFS string - err error -} - -type ProcTableDebugInfo struct { - ElfTables map[string]elf.SymTabDebugInfo `alloy:"elfs,block,optional" river:"elfs,block,optional"` - Size int `alloy:"size,attr,optional" river:"size,attr,optional"` - Pid int `alloy:"pid,attr,optional" river:"pid,attr,optional"` - LastUsedRound int `alloy:"last_used_round,attr,optional" river:"last_used_round,attr,optional"` -} - -func (p *ProcTable) DebugInfo() ProcTableDebugInfo { - res := ProcTableDebugInfo{ - Pid: p.options.Pid, - Size: len(p.file2Table), - ElfTables: make(map[string]elf.SymTabDebugInfo), - } - for f, e := range p.file2Table { - d := e.table.DebugInfo() - if d.Size != 0 { - res.ElfTables[fmt.Sprintf("%x %x %s", f.dev, f.inode, f.path)] = d - } - } - return res -} - -type ProcTableOptions struct { - Pid int - ElfTableOptions -} - -func NewProcTable(logger log.Logger, options ProcTableOptions) *ProcTable { - return &ProcTable{ - logger: logger, - file2Table: make(map[file]*ElfTable), - options: options, - rootFS: path.Join("/proc", strconv.Itoa(options.Pid), "root"), - } -} - -type elfRange struct { - mapRange *ProcMap - // may be nil - elfTable *ElfTable -} - -func (p *ProcTable) Refresh() { - if p.err != nil { - return - } - procMaps, err := os.ReadFile(fmt.Sprintf("/proc/%d/maps", p.options.Pid)) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - level.Error(p.logger).Log("msg", "failed to read /proc/pid/maps", "err", err) - } - p.options.Metrics.ProcErrors.WithLabelValues(errorType(err)).Inc() - p.err = err - return - } - p.err = p.refreshProcMap(procMaps) - if p.err != nil { - _ = level.Error(p.logger).Log("err", p.err) - } else { - } -} - -func (p *ProcTable) Error() error { - return p.err -} - -func (p *ProcTable) refreshProcMap(procMaps []byte) error { - // todo support perf map files - for i := range p.ranges { - p.ranges[i].elfTable = nil - } - p.ranges = p.ranges[:0] - filesToKeep := make(map[file]struct{}) - maps, err := ParseProcMapsExecutableModules(procMaps, true) - if err != nil { - return err - } - - for _, m := range maps { - p.ranges = append(p.ranges, elfRange{ - mapRange: m, - }) - r := &p.ranges[len(p.ranges)-1] - e := p.getElfTable(r) - if e != nil { - r.elfTable = e - filesToKeep[r.mapRange.file()] = struct{}{} - } - } - var filesToDelete []file - for f := range p.file2Table { - _, keep := filesToKeep[f] - if !keep { - filesToDelete = append(filesToDelete, f) - } - } - for _, f := range filesToDelete { - delete(p.file2Table, f) - } - return nil -} - -func (p *ProcTable) getElfTable(r *elfRange) *ElfTable { - f := r.mapRange.file() - e, ok := p.file2Table[f] - if !ok { - e = p.createElfTable(r.mapRange) - if e != nil { - p.file2Table[f] = e - } - } - return e -} - -func (p *ProcTable) Resolve(pc uint64) Symbol { - if pc == 0xcccccccccccccccc || pc == 0x9090909090909090 { - return Symbol{Start: 0, Name: "end_of_stack", Module: "[unknown]"} - } - i, found := slices.BinarySearchFunc(p.ranges, pc, binarySearchElfRange) - if !found { - return Symbol{} - } - r := p.ranges[i] - t := r.elfTable - if t == nil { - return Symbol{} - } - s := t.Resolve(pc) - moduleOffset := pc - t.base - if s == "" { - return Symbol{Start: moduleOffset, Module: r.mapRange.Pathname} - } - - return Symbol{Start: moduleOffset, Name: s, Module: r.mapRange.Pathname} -} - -func (p *ProcTable) createElfTable(m *ProcMap) *ElfTable { - if !strings.HasPrefix(m.Pathname, "/") { - return nil - } - e := NewElfTable(p.logger, m, p.rootFS, m.Pathname, p.options.ElfTableOptions) - return e -} - -func (p *ProcTable) Cleanup() { - for _, table := range p.file2Table { - table.Cleanup() - } -} - -func (p *ProcTable) Pid() int { - return p.options.Pid -} - -func binarySearchElfRange(e elfRange, pc uint64) int { - if pc < e.mapRange.StartAddr { - return 1 - } - if pc >= e.mapRange.EndAddr { - return -1 - } - return 0 -} diff --git a/ebpf/symtab/proc_linux_test.go b/ebpf/symtab/proc_linux_test.go deleted file mode 100644 index 6f8b7118ec..0000000000 --- a/ebpf/symtab/proc_linux_test.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build linux - -package symtab - -import ( - elf0 "debug/elf" - "os" - "strings" - "testing" - - "github.com/go-kit/log" - "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/grafana/pyroscope/ebpf/symtab/elf" - "github.com/grafana/pyroscope/ebpf/util" - "github.com/stretchr/testify/require" -) - -func TestMallocResolve(t *testing.T) { - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - gosym := NewProcTable(logger, ProcTableOptions{ - Pid: os.Getpid(), - ElfTableOptions: ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }, - }) - gosym.Refresh() - malloc := testHelperGetMalloc() - res := gosym.Resolve(uint64(malloc)) - require.Contains(t, res.Name, "malloc") - if !strings.Contains(res.Module, "/libc.so") && !strings.Contains(res.Module, "/libc-") { - t.Errorf("expected libc, got %v", res.Module) - } -} - -func BenchmarkProc(b *testing.B) { - gosym, _ := elf.GetGoSymbols("/proc/self/exe", false) - logger := log.NewSyncLogger(log.NewLogfmtLogger(os.Stderr)) - proc := NewProcTable(logger, ProcTableOptions{Pid: os.Getpid()}) - proc.Refresh() - if len(gosym) < 1000 { - b.FailNow() - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - for _, symbol := range gosym { - proc.Resolve(symbol.Start) - } - } -} - -func TestSelfElfSymbolsLazy(t *testing.T) { - f, err := os.Readlink("/proc/self/exe") - require.NoError(t, err) - - e, err := elf0.Open(f) - require.NoError(t, err) - defer e.Close() - - expectedSymbols := elf.GetELFSymbolsFromSymtab(e) - - if len(expectedSymbols) == 0 { - t.Skip("no symbols found") - return - } - - me, err := elf.NewMMapedElfFile(f) - require.NoError(t, err) - defer me.Close() - - symbolTable, err := me.NewSymbolTable(new(elf.SymbolsOptions)) - require.NoError(t, err) - - for _, symbol := range expectedSymbols { - name := symbolTable.Resolve(symbol.Start) - if symbol.Name == "runtime.text" && name == "internal/cpu.Initialize" { - continue - } - var found []elf.TestSym - var nameMatches int - // there may be multiple symbols with the same start address - // in no particular order so just require to have at least one - for j := range expectedSymbols { - if expectedSymbols[j].Start == symbol.Start { - found = append(found, expectedSymbols[j]) - if expectedSymbols[j].Name == name { - nameMatches++ - } - } - } - require.GreaterOrEqualf(t, nameMatches, 1, "symbol %v at %x (found %v)", symbol.Name, symbol.Start, found) - } -} diff --git a/ebpf/symtab/proc_test.go b/ebpf/symtab/proc_test.go deleted file mode 100644 index 375e9518eb..0000000000 --- a/ebpf/symtab/proc_test.go +++ /dev/null @@ -1,391 +0,0 @@ -package symtab - -import ( - "crypto/md5" - "encoding/hex" - "os" - "path" - "strings" - "testing" - - "github.com/grafana/pyroscope/ebpf/metrics" - "github.com/grafana/pyroscope/ebpf/util" - - "github.com/stretchr/testify/require" -) - -func TestTestdataMD5(t *testing.T) { - elfs := []struct { - md5Sum, file string - }{ - {"5201d962e9f71ea220b9610d6352b57e", "elf"}, - {"e300c975548c3d7617a263243592ae46", "elf.debug"}, - {"668e90be1ac8a0e8e89ebd47284bf7fc", "elf.debuglink"}, - {"7ecf01cd4fe52e4a31d7840e8d93ac56", "elf.nobuildid"}, - {"4284c6ba06fedfe6e05627ddd5ccff18", "elf.nopie"}, - {"635fd79c77b9de925647fe566668ea6d", "elf.stripped"}, - {"b69d2a627f90ecac7868effa89a37c33", "libexample.so"}, - } - for _, elf := range elfs { - data, err := os.ReadFile(path.Join("elf", "testdata", "elfs", elf.file)) - if err != nil { - t.Errorf("failed to check md5 %v %v", elf, err) - continue - } - hash := md5.New() - hash.Write(data) - md5Sum := hex.EncodeToString(hash.Sum(nil)) - if md5Sum != elf.md5Sum { - t.Errorf("failed to check md5 %v %v", elf, md5Sum) - } - } -} - -type procTestdata struct { - name string - elf string - offset uint64 - base uint64 -} - -func testProc(t *testing.T, maps string, data []procTestdata) { - wd, _ := os.Getwd() - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - m := NewProcTable(logger, ProcTableOptions{ - Pid: 239, - ElfTableOptions: ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }, - }) - m.rootFS = path.Join(wd, "elf", "testdata") - m.refreshProcMap([]byte(maps)) - for _, td := range data { - sym := m.Resolve(td.base + td.offset) - require.Equal(t, sym.Name, td.name) - require.Contains(t, sym.Module, td.elf) - } -} - -func TestProc(t *testing.T) { - maps := `56483a0ee000-56483a0ef000 r--p 00000000 09:00 9469561 /elfs/elf -56483a0ef000-56483a0f0000 r-xp 00001000 09:00 9469561 /elfs/elf -56483a0f0000-56483a0f1000 r--p 00002000 09:00 9469561 /elfs/elf -56483a0f1000-56483a0f2000 r--p 00002000 09:00 9469561 /elfs/elf -56483a0f2000-56483a0f3000 rw-p 00003000 09:00 9469561 /elfs/elf -7fa9f6fda000-7fa9f6fdd000 rw-p 00000000 00:00 0 -7fa9f6fdd000-7fa9f7005000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fa9f7005000-7fa9f719a000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fa9f719a000-7fa9f71f2000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fa9f71f2000-7fa9f71f6000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fa9f71f6000-7fa9f71f8000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fa9f71f8000-7fa9f7205000 rw-p 00000000 00:00 0 -7fa9f720e000-7fa9f720f000 r--p 00000000 09:00 9543485 /elfs/libexample.so -7fa9f720f000-7fa9f7210000 r-xp 00001000 09:00 9543485 /elfs/libexample.so -7fa9f7210000-7fa9f7211000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fa9f7211000-7fa9f7212000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fa9f7212000-7fa9f7213000 rw-p 00003000 09:00 9543485 /elfs/libexample.so -7fa9f7213000-7fa9f7215000 rw-p 00000000 00:00 0 -7fa9f7215000-7fa9f7217000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fa9f7217000-7fa9f7241000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fa9f7241000-7fa9f724c000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fa9f724d000-7fa9f724f000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fa9f724f000-7fa9f7251000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7ffe08f0d000-7ffe08f2e000 rw-p 00000000 00:00 0 [stack] -7ffe08f52000-7ffe08f56000 r--p 00000000 00:00 0 [vvar] -7ffe08f56000-7ffe08f58000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - var syms = []procTestdata{ - {"iter", "elf", 0x1149, 0x56483a0ee000}, - {"main", "elf", 0x115e, 0x56483a0ee000}, - {"lib_iter", "libexample.so", 0x1139, 0x7fa9f720e000}, - } - testProc(t, maps, syms) -} - -func TestProcNoPie(t *testing.T) { - maps := `00400000-00401000 r--p 00000000 09:00 9543481 /elfs/elf.nopie -00401000-00402000 r-xp 00001000 09:00 9543481 /elfs/elf.nopie -00402000-00403000 r--p 00002000 09:00 9543481 /elfs/elf.nopie -00403000-00404000 r--p 00002000 09:00 9543481 /elfs/elf.nopie -00404000-00405000 rw-p 00003000 09:00 9543481 /elfs/elf.nopie -7f8f62c82000-7f8f62c85000 rw-p 00000000 00:00 0 -7f8f62c85000-7f8f62cad000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f8f62cad000-7f8f62e42000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f8f62e42000-7f8f62e9a000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f8f62e9a000-7f8f62e9e000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f8f62e9e000-7f8f62ea0000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f8f62ea0000-7f8f62ead000 rw-p 00000000 00:00 0 -7f8f62eb6000-7f8f62eb7000 r--p 00000000 09:00 9543485 /elfs/libexample.so -7f8f62eb7000-7f8f62eb8000 r-xp 00001000 09:00 9543485 /elfs/libexample.so -7f8f62eb8000-7f8f62eb9000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7f8f62eb9000-7f8f62eba000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7f8f62eba000-7f8f62ebb000 rw-p 00003000 09:00 9543485 /elfs/libexample.so -7f8f62ebb000-7f8f62ebd000 rw-p 00000000 00:00 0 -7f8f62ebd000-7f8f62ebf000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f8f62ebf000-7f8f62ee9000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f8f62ee9000-7f8f62ef4000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f8f62ef5000-7f8f62ef7000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f8f62ef7000-7f8f62ef9000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7ffe100a2000-7ffe100c3000 rw-p 00000000 00:00 0 [stack] -7ffe1013d000-7ffe10141000 r--p 00000000 00:00 0 [vvar] -7ffe10141000-7ffe10143000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - var syms = []procTestdata{ - {"iter", "elf.nopie", 0x401136, 0}, - {"main", "elf.nopie", 0x40114b, 0}, - {"lib_iter", "libexample.so", 0x1139, 0x7f8f62eb6000}, - } - testProc(t, maps, syms) -} - -func TestDebugFileBuildID(t *testing.T) { - maps := `556bf5712000-556bf5713000 r--p 00000000 09:00 9469523 /elfs/elf.stripped -556bf5713000-556bf5714000 r-xp 00001000 09:00 9469523 /elfs/elf.stripped -556bf5714000-556bf5715000 r--p 00002000 09:00 9469523 /elfs/elf.stripped -556bf5715000-556bf5716000 r--p 00002000 09:00 9469523 /elfs/elf.stripped -556bf5716000-556bf5717000 rw-p 00003000 09:00 9469523 /elfs/elf.stripped -7fb225802000-7fb225805000 rw-p 00000000 00:00 0 -7fb225805000-7fb22582d000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fb22582d000-7fb2259c2000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fb2259c2000-7fb225a1a000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fb225a1a000-7fb225a1e000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fb225a1e000-7fb225a20000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fb225a20000-7fb225a2d000 rw-p 00000000 00:00 0 -7fb225a36000-7fb225a37000 r--p 00000000 09:00 9543485 /elfs/libexample.so -7fb225a37000-7fb225a38000 r-xp 00001000 09:00 9543485 /elfs/libexample.so -7fb225a38000-7fb225a39000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fb225a39000-7fb225a3a000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fb225a3a000-7fb225a3b000 rw-p 00003000 09:00 9543485 /elfs/libexample.so -7fb225a3b000-7fb225a3d000 rw-p 00000000 00:00 0 -7fb225a3d000-7fb225a3f000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fb225a3f000-7fb225a69000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fb225a69000-7fb225a74000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fb225a75000-7fb225a77000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fb225a77000-7fb225a79000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7ffd99230000-7ffd99251000 rw-p 00000000 00:00 0 [stack] -7ffd99336000-7ffd9933a000 r--p 00000000 00:00 0 [vvar] -7ffd9933a000-7ffd9933c000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - var syms = []procTestdata{ - {"iter", "elf.stripped", 0x1149, 0x556bf5712000}, - {"main", "elf.stripped", 0x115e, 0x556bf5712000}, - {"lib_iter", "libexample.so", 0x1139, 0x7fb225a36000}, - } - testProc(t, maps, syms) -} - -func TestDebugFileDebugLink(t *testing.T) { - //nolint:goconst - maps := `559090826000-559090827000 r--p 00000000 09:00 9543482 /elfs/elf.debuglink -559090827000-559090828000 r-xp 00001000 09:00 9543482 /elfs/elf.debuglink -559090828000-559090829000 r--p 00002000 09:00 9543482 /elfs/elf.debuglink -559090829000-55909082b000 rw-p 00002000 09:00 9543482 /elfs/elf.debuglink -7fd1c6f27000-7fd1c6f2a000 rw-p 00000000 00:00 0 -7fd1c6f2a000-7fd1c6f52000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c6f52000-7fd1c70e7000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c70e7000-7fd1c713f000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c713f000-7fd1c7143000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7143000-7fd1c7145000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7145000-7fd1c7152000 rw-p 00000000 00:00 0 -7fd1c715b000-7fd1c715c000 r--p 00000000 09:00 9543485 /elfs/libexample.so -7fd1c715c000-7fd1c715d000 r-xp 00001000 09:00 9543485 /elfs/libexample.so -7fd1c715d000-7fd1c715e000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fd1c715e000-7fd1c715f000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fd1c715f000-7fd1c7160000 rw-p 00003000 09:00 9543485 /elfs/libexample.so -7fd1c7160000-7fd1c7162000 rw-p 00000000 00:00 0 -7fd1c7162000-7fd1c7164000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c7164000-7fd1c718e000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c718e000-7fd1c7199000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719a000-7fd1c719c000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719c000-7fd1c719e000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fffd9b57000-7fffd9b78000 rw-p 00000000 00:00 0 [stack] -7fffd9bd2000-7fffd9bd6000 r--p 00000000 00:00 0 [vvar] -7fffd9bd6000-7fffd9bd8000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - var syms = []procTestdata{ - {"iter", "elf.debuglink", 0x1149, 0x559090826000}, - {"main", "elf.debuglink", 0x115e, 0x559090826000}, - {"lib_iter", "libexample.so", 0x1139, 0x7fd1c715b000}, - } - testProc(t, maps, syms) -} - -func TestUnload(t *testing.T) { - //nolint:goconst - maps := `559090826000-559090827000 r--p 00000000 09:00 9543482 /elfs/elf.debuglink -559090827000-559090828000 r-xp 00001000 09:00 9543482 /elfs/elf.debuglink -559090828000-559090829000 r--p 00002000 09:00 9543482 /elfs/elf.debuglink -559090829000-55909082b000 rw-p 00002000 09:00 9543482 /elfs/elf.debuglink -7fd1c6f27000-7fd1c6f2a000 rw-p 00000000 00:00 0 -7fd1c6f2a000-7fd1c6f52000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c6f52000-7fd1c70e7000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c70e7000-7fd1c713f000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c713f000-7fd1c7143000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7143000-7fd1c7145000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7145000-7fd1c7152000 rw-p 00000000 00:00 0 -7fd1c715b000-7fd1c715c000 r--p 00000000 09:00 9543485 /elfs/libexample.so -7fd1c715c000-7fd1c715d000 r-xp 00001000 09:00 9543485 /elfs/libexample.so -7fd1c715d000-7fd1c715e000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fd1c715e000-7fd1c715f000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fd1c715f000-7fd1c7160000 rw-p 00003000 09:00 9543485 /elfs/libexample.so -7fd1c7160000-7fd1c7162000 rw-p 00000000 00:00 0 -7fd1c7162000-7fd1c7164000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c7164000-7fd1c718e000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c718e000-7fd1c7199000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719a000-7fd1c719c000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719c000-7fd1c719e000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fffd9b57000-7fffd9b78000 rw-p 00000000 00:00 0 [stack] -7fffd9bd2000-7fffd9bd6000 r--p 00000000 00:00 0 [vvar] -7fffd9bd6000-7fffd9bd8000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - iterSym := procTestdata{"lib_iter", "libexample.so", 0x1139, 0x7fd1c715b000} - var syms = []procTestdata{ - {"iter", "elf.debuglink", 0x1149, 0x559090826000}, - {"main", "elf.debuglink", 0x115e, 0x559090826000}, - iterSym, - } - - wd, _ := os.Getwd() - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - m := NewProcTable(logger, ProcTableOptions{ - Pid: 239, - ElfTableOptions: ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }, - }) - m.rootFS = path.Join(wd, "elf", "testdata") - m.refreshProcMap([]byte(maps)) - for _, td := range syms { - sym := m.Resolve(td.base + td.offset) - if sym.Name != td.name || !strings.Contains(sym.Module, td.elf) { - t.Errorf("failed to Resolve %v (%v)", td, sym) - } - } - maps = `559090826000-559090827000 r--p 00000000 09:00 9543482 /elfs/elf.debuglink -559090827000-559090828000 r-xp 00001000 09:00 9543482 /elfs/elf.debuglink -559090828000-559090829000 r--p 00002000 09:00 9543482 /elfs/elf.debuglink -559090829000-55909082b000 rw-p 00002000 09:00 9543482 /elfs/elf.debuglink -7fd1c6f27000-7fd1c6f2a000 rw-p 00000000 00:00 0 -7fd1c6f2a000-7fd1c6f52000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c6f52000-7fd1c70e7000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c70e7000-7fd1c713f000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c713f000-7fd1c7143000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7143000-7fd1c7145000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7145000-7fd1c7152000 rw-p 00000000 00:00 0 -7fd1c7162000-7fd1c7164000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c7164000-7fd1c718e000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c718e000-7fd1c7199000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719a000-7fd1c719c000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719c000-7fd1c719e000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fffd9b57000-7fffd9b78000 rw-p 00000000 00:00 0 [stack] -7fffd9bd2000-7fffd9bd6000 r--p 00000000 00:00 0 [vvar] -7fffd9bd6000-7fffd9bd8000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - require.Equal(t, 4, len(m.file2Table)) - m.refreshProcMap([]byte(maps)) - require.Equal(t, 3, len(m.file2Table)) - sym := m.Resolve(iterSym.base + iterSym.offset) - require.Empty(t, sym.Name) - require.Empty(t, sym.Module) - require.Empty(t, sym.Start) -} - -func TestInodeChange(t *testing.T) { - //nolint:goconst - maps := `559090826000-559090827000 r--p 00000000 09:00 9543482 /elfs/elf.debuglink -559090827000-559090828000 r-xp 00001000 09:00 9543482 /elfs/elf.debuglink -559090828000-559090829000 r--p 00002000 09:00 9543482 /elfs/elf.debuglink -559090829000-55909082b000 rw-p 00002000 09:00 9543482 /elfs/elf.debuglink -7fd1c6f27000-7fd1c6f2a000 rw-p 00000000 00:00 0 -7fd1c6f2a000-7fd1c6f52000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c6f52000-7fd1c70e7000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c70e7000-7fd1c713f000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c713f000-7fd1c7143000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7143000-7fd1c7145000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7145000-7fd1c7152000 rw-p 00000000 00:00 0 -7fd1c715b000-7fd1c715c000 r--p 00000000 09:00 9543485 /elfs/libexample.so -7fd1c715c000-7fd1c715d000 r-xp 00001000 09:00 9543485 /elfs/libexample.so -7fd1c715d000-7fd1c715e000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fd1c715e000-7fd1c715f000 r--p 00002000 09:00 9543485 /elfs/libexample.so -7fd1c715f000-7fd1c7160000 rw-p 00003000 09:00 9543485 /elfs/libexample.so -7fd1c7160000-7fd1c7162000 rw-p 00000000 00:00 0 -7fd1c7162000-7fd1c7164000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c7164000-7fd1c718e000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c718e000-7fd1c7199000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719a000-7fd1c719c000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719c000-7fd1c719e000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fffd9b57000-7fffd9b78000 rw-p 00000000 00:00 0 [stack] -7fffd9bd2000-7fffd9bd6000 r--p 00000000 00:00 0 [vvar] -7fffd9bd6000-7fffd9bd8000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - iterSym := procTestdata{"lib_iter", "libexample.so", 0x1139, 0x7fd1c715b000} - var syms = []procTestdata{ - {"iter", "elf.debuglink", 0x1149, 0x559090826000}, - {"main", "elf.debuglink", 0x115e, 0x559090826000}, - iterSym, - } - - wd, _ := os.Getwd() - elfCache, _ := NewElfCache(testCacheOptions, testCacheOptions) - logger := util.TestLogger(t) - m := NewProcTable(logger, ProcTableOptions{ - Pid: 239, - ElfTableOptions: ElfTableOptions{ - ElfCache: elfCache, - Metrics: metrics.NewSymtabMetrics(nil), - }, - }) - m.rootFS = path.Join(wd, "elf", "testdata") - m.refreshProcMap([]byte(maps)) - for _, td := range syms { - sym := m.Resolve(td.base + td.offset) - if sym.Name != td.name || !strings.Contains(sym.Module, td.elf) { - t.Errorf("failed to Resolve %v (%v)", td, sym) - } - } - maps = `559090826000-559090827000 r--p 00000000 09:00 9543482 /elfs/elf.debuglink -559090827000-559090828000 r-xp 00001000 09:00 9543482 /elfs/elf.debuglink -559090828000-559090829000 r--p 00002000 09:00 9543482 /elfs/elf.debuglink -559090829000-55909082b000 rw-p 00002000 09:00 9543482 /elfs/elf.debuglink -7fd1c6f27000-7fd1c6f2a000 rw-p 00000000 00:00 0 -7fd1c6f2a000-7fd1c6f52000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c6f52000-7fd1c70e7000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c70e7000-7fd1c713f000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c713f000-7fd1c7143000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7143000-7fd1c7145000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7fd1c7145000-7fd1c7152000 rw-p 00000000 00:00 0 -7fd1c715b000-7fd1c715c000 r--p 00000000 09:00 9543486 /elfs/libexample.so -7fd1c715c000-7fd1c715d000 r-xp 00001000 09:00 9543486 /elfs/libexample.so -7fd1c715d000-7fd1c715e000 r--p 00002000 09:00 9543486 /elfs/libexample.so -7fd1c715e000-7fd1c715f000 r--p 00002000 09:00 9543486 /elfs/libexample.so -7fd1c715f000-7fd1c7160000 rw-p 00003000 09:00 9543486 /elfs/libexample.so -7fd1c7160000-7fd1c7162000 rw-p 00000000 00:00 0 -7fd1c7162000-7fd1c7164000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c7164000-7fd1c718e000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c718e000-7fd1c7199000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719a000-7fd1c719c000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fd1c719c000-7fd1c719e000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7fffd9b57000-7fffd9b78000 rw-p 00000000 00:00 0 [stack] -7fffd9bd2000-7fffd9bd6000 r--p 00000000 00:00 0 [vvar] -7fffd9bd6000-7fffd9bd8000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - require.Equal(t, 4, len(m.file2Table)) - m.refreshProcMap([]byte(maps)) - require.Equal(t, 4, len(m.file2Table)) - sym := m.Resolve(iterSym.base + iterSym.offset) - require.NotEmpty(t, sym.Name) - require.NotEmpty(t, sym.Module) - require.NotEmpty(t, sym.Start) -} diff --git a/ebpf/symtab/procmap.go b/ebpf/symtab/procmap.go deleted file mode 100644 index 5b2eefff74..0000000000 --- a/ebpf/symtab/procmap.go +++ /dev/null @@ -1,339 +0,0 @@ -package symtab - -import ( - "bytes" - "fmt" - "reflect" - "strconv" - "strings" - "unsafe" -) - -// ProcMapPermissions contains permission settings read from `/proc/[pid]/maps`. -type ProcMapPermissions struct { - // mapping has the [R]ead flag set - Read bool - // mapping has the [W]rite flag set - Write bool - // mapping has the [X]ecutable flag set - Execute bool - // mapping has the [S]hared flag set - Shared bool - // mapping is marked as [P]rivate (copy on write) - Private bool -} - -func (p *ProcMapPermissions) String() string { - var res string - if p.Read { - res += "r" - } else { - res += "-" - } - if p.Write { - res += "w" - } else { - res += "-" - } - if p.Execute { - res += "x" - } else { - res += "-" - } - if p.Shared { - res += "s" - } else { - res += "-" - } - if p.Private { - res += "p" - } else { - res += "-" - } - return res -} - -// ProcMap contains the process memory-mappings of the process -// read from `/proc/[pid]/maps`. -type ProcMap struct { - // The start address of current mapping. - StartAddr uint64 - // The end address of the current mapping - EndAddr uint64 - // The permissions for this mapping - Perms *ProcMapPermissions - // The current offset into the file/fd (e.g., shared libs) - Offset int64 - // Device owner of this mapping (major:minor) in Mkdev format. - Dev uint64 - // The inode of the device above - Inode uint64 - // The file or psuedofile (or empty==anonymous) - Pathname string -} - -func (p *ProcMap) String() string { - return fmt.Sprintf("%x-%x %s %x %x:%x %s", - p.StartAddr, p.EndAddr, p.Perms.String(), p.Offset, p.Dev, p.Inode, p.Pathname) -} - -type ProcMaps []*ProcMap - -func (p ProcMaps) String() string { - var sb strings.Builder - for _, m := range p { - sb.WriteString(m.String()) - sb.WriteString("\n") - } - return sb.String() -} - -type file struct { - dev uint64 - inode uint64 - path string -} - -func (m *ProcMap) file() file { - return file{ - dev: m.Dev, - inode: m.Inode, - path: m.Pathname, - } -} - -// parseDevice parses the device token of a line and converts it to a dev_t -// (mkdev) like structure. -func parseDevice(s []byte) (uint64, error) { - i := bytes.IndexByte(s, ':') - if i == -1 { - return 0, fmt.Errorf("unexpected number of fields") - } - majorBytes := s[:i] - minorBytes := s[i+1:] - - major, err := strconv.ParseUint(tokenToStringUnsafe(majorBytes), 16, 0) - if err != nil { - return 0, err - } - - minor, err := strconv.ParseUint(tokenToStringUnsafe(minorBytes), 16, 0) - if err != nil { - return 0, err - } - - return mkdev(uint32(major), uint32(minor)), nil -} - -// mkdev returns a Linux device number generated from the given major and minor -// components. -// this is a copy-paste from unix.Mkdev -func mkdev(major, minor uint32) uint64 { - dev := (uint64(major) & 0x00000fff) << 8 - dev |= (uint64(major) & 0xfffff000) << 32 - dev |= (uint64(minor) & 0x000000ff) << 0 - dev |= (uint64(minor) & 0xffffff00) << 12 - return dev -} - -// parseAddress converts a hex-string to a uintptr. -func parseAddress(s []byte) (uint64, error) { - a, err := strconv.ParseUint(tokenToStringUnsafe(s), 16, 0) - if err != nil { - return 0, err - } - - return a, nil -} - -// parseAddresses parses the start-end address. -func parseAddresses(s []byte) (uint64, uint64, error) { - i := bytes.IndexByte(s, '-') - if i == -1 { - return 0, 0, fmt.Errorf("invalid address") - } - saddrBytes := s[:i] - eaddrBytes := s[i+1:] - - saddr, err := parseAddress(saddrBytes) - if err != nil { - return 0, 0, err - } - - eaddr, err := parseAddress(eaddrBytes) - if err != nil { - return 0, 0, err - } - - return saddr, eaddr, nil -} - -// parsePermissions parses a token and returns any that are set. -func parsePermissions(s []byte) (*ProcMapPermissions, error) { - if len(s) < 4 { - return nil, fmt.Errorf("invalid permissions token") - } - - perms := ProcMapPermissions{} - for _, ch := range s { - switch ch { - case 'r': - perms.Read = true - case 'w': - perms.Write = true - case 'x': - perms.Execute = true - case 'p': - perms.Private = true - case 's': - perms.Shared = true - } - } - - return &perms, nil -} - -// ParseProcMapLine will attempt to parse a single line within a proc/[pid]/maps -// buffer. -// 7f5822ebe000-7f5822ec0000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -// returns nil if entry is not executable -func ParseProcMapLine(line []byte, executableOnly bool) (*ProcMap, error) { - var i int - if i = bytes.IndexByte(line, ' '); i == -1 { - return nil, fmt.Errorf("invalid procmap entry: %s", line) - } - addresesBytes := line[:i] - line = line[i+1:] - - if i = bytes.IndexByte(line, ' '); i == -1 { - return nil, fmt.Errorf("invalid procmap entry: %s", line) - } - permsBytes := line[:i] - line = line[i+1:] - - if i = bytes.IndexByte(line, ' '); i == -1 { - return nil, fmt.Errorf("invalid procmap entry: %s", line) - } - offsetBytes := line[:i] - line = line[i+1:] - - if i = bytes.IndexByte(line, ' '); i == -1 { - return nil, fmt.Errorf("invalid procmap entry: %s", line) - } - deviceBytes := line[:i] - line = line[i+1:] - - var inodeBytes []byte - if i = bytes.IndexByte(line, ' '); i == -1 { - inodeBytes = line - line = nil - } else { - inodeBytes = line[:i] - line = line[i+1:] - } - - perms, err := parsePermissions(permsBytes) - if err != nil { - return nil, err - } - - if executableOnly && !perms.Execute { - return nil, nil - } - - saddr, eaddr, err := parseAddresses(addresesBytes) - if err != nil { - return nil, err - } - - offset, err := strconv.ParseInt(tokenToStringUnsafe(offsetBytes), 16, 0) - if err != nil { - return nil, err - } - - device, err := parseDevice(deviceBytes) - if err != nil { - return nil, err - } - - inode, err := strconv.ParseUint(tokenToStringUnsafe(inodeBytes), 10, 0) - if err != nil { - return nil, err - } - - pathname := "" - - for len(line) > 0 && line[0] == ' ' { - line = line[1:] - } - if len(line) > 0 { - pathname = string(line) - } - - return &ProcMap{ - StartAddr: saddr, - EndAddr: eaddr, - Perms: perms, - Offset: offset, - Dev: device, - Inode: inode, - Pathname: pathname, - }, nil -} - -func ParseProcMapsExecutableModules(procMaps []byte, executableOnly bool) ([]*ProcMap, error) { - var modules []*ProcMap - for len(procMaps) > 0 { - nl := bytes.IndexByte(procMaps, '\n') - var line []byte - if nl == -1 { - line = procMaps - procMaps = nil - } else { - line = procMaps[:nl] - procMaps = procMaps[nl+1:] - } - if len(line) == 0 { - continue - } - m, err := ParseProcMapLine(line, executableOnly) - if err != nil { - return nil, err - } - if m == nil { // not executable - continue - } - modules = append(modules, m) - } - return modules, nil -} - -func tokenToStringUnsafe(tok []byte) string { - res := "" - sh := (*reflect.StringHeader)(unsafe.Pointer(&res)) - sh.Data = uintptr(unsafe.Pointer(&tok[0])) - sh.Len = len(tok) - return res -} - -func FindLastRXMap(maps []*ProcMap) *ProcMap { - for i := len(maps) - 1; i >= 0; i-- { - m := maps[i] - if m.Perms.Read && m.Perms.Execute { - return m - } - } - return nil -} - -// FindReadableMap return a map entry that is readable and not writable or nil -func FindReadableMap(maps []*ProcMap) *ProcMap { - var readable *ProcMap - for _, m := range maps { - if m.Perms.Read && !m.Perms.Write { - readable = m - break - } - } - return readable -} diff --git a/ebpf/symtab/procmaps_test.go b/ebpf/symtab/procmaps_test.go deleted file mode 100644 index 1744577497..0000000000 --- a/ebpf/symtab/procmaps_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package symtab - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestProcMaps(t *testing.T) { - data := `5644e74cc000-5644e74ce000 r--p 00000000 09:00 523083 /usr/bin/cat -5644e74ce000-5644e74d2000 r-xp 00002000 09:00 523083 /usr/bin/cat -5644e74d2000-5644e74d4000 r--p 00006000 09:00 523083 /usr/bin/cat -5644e74d4000-5644e74d5000 r--p 00007000 09:00 523083 /usr/bin/cat -5644e74d5000-5644e74d6000 rw-p 00008000 09:00 523083 /usr/bin/cat -5644e9081000-5644e90a2000 rw-p 00000000 00:00 0 [heap] -7f582297e000-7f58229a0000 rw-p 00000000 00:00 0 -7f58229a0000-7f5822c89000 r--p 00000000 09:00 532371 /usr/lib/locale/locale-archive -7f5822c89000-7f5822c8c000 rw-p 00000000 00:00 0 -7f5822c8c000-7f5822cb4000 r--p 00000000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f5822cb4000-7f5822e49000 r-xp 00028000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f5822e49000-7f5822ea1000 r--p 001bd000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f5822ea1000-7f5822ea5000 r--p 00214000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f5822ea5000-7f5822ea7000 rw-p 00218000 09:00 533580 /usr/lib/x86_64-linux-gnu/libc.so.6 -7f5822ea7000-7f5822eb4000 rw-p 00000000 00:00 0 -7f5822ebc000-7f5822ebe000 rw-p 00000000 00:00 0 -7f5822ebe000-7f5822ec0000 r--p 00000000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f5822ec0000-7f5822eea000 r-xp 00002000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f5822eea000-7f5822ef5000 r--p 0002c000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f5822ef6000-7f5822ef8000 r--p 00037000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7f5822ef8000-7f5822efa000 rw-p 00039000 09:00 533429 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -7ffe15767000-7ffe15788000 rw-p 00000000 00:00 0 [stack] -7ffe157f0000-7ffe157f4000 r--p 00000000 00:00 0 [vvar] -7ffe157f4000-7ffe157f6000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -` - maps, err := ParseProcMapsExecutableModules([]byte(data), true) - if err != nil { - t.Fatal(err) - } - dev := mkdev(9, 0) - expected := []*ProcMap{ - { - StartAddr: 0x5644e74ce000, - EndAddr: 0x5644e74d2000, - Perms: &ProcMapPermissions{Read: true, Execute: true, Private: true}, - Offset: 0x00002000, - Dev: dev, - Inode: 523083, - Pathname: "/usr/bin/cat", - }, - { - StartAddr: 0x7f5822cb4000, - EndAddr: 0x7f5822e49000, - Perms: &ProcMapPermissions{Read: true, Execute: true, Private: true}, - Offset: 0x00028000, - Dev: dev, - Inode: 533580, - Pathname: "/usr/lib/x86_64-linux-gnu/libc.so.6", - }, - { - StartAddr: 0x7f5822ec0000, - EndAddr: 0x7f5822eea000, - Perms: &ProcMapPermissions{Read: true, Execute: true, Private: true}, - Offset: 0x00002000, - Dev: dev, - Inode: 533429, - Pathname: "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2", - }, - { - StartAddr: 0x7ffe157f4000, - EndAddr: 0x7ffe157f6000, - Perms: &ProcMapPermissions{Read: true, Execute: true, Private: true}, - Pathname: "[vdso]", - }, - { - StartAddr: 0xffffffffff600000, - EndAddr: 0xffffffffff601000, - Perms: &ProcMapPermissions{Read: false, Execute: true, Private: true}, - Pathname: "[vsyscall]", - }, - } - require.Equal(t, expected, maps) -} diff --git a/ebpf/symtab/stat_darwin.go b/ebpf/symtab/stat_darwin.go deleted file mode 100644 index 8f15ee084f..0000000000 --- a/ebpf/symtab/stat_darwin.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build darwin - -package symtab - -import ( - "os" - "syscall" -) - -type Stat struct { - Dev uint64 - Inode uint64 -} - -func statFromFileInfo(file os.FileInfo) Stat { - sys := file.Sys() - sysStat, ok := sys.(*syscall.Stat_t) - if !ok || sysStat == nil { - return Stat{} - } - return Stat{ - Dev: uint64(sysStat.Dev), - Inode: sysStat.Ino, - } -} diff --git a/ebpf/symtab/stat_linux.go b/ebpf/symtab/stat_linux.go deleted file mode 100644 index e325160321..0000000000 --- a/ebpf/symtab/stat_linux.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build linux - -package symtab - -import ( - "os" - "syscall" -) - -type Stat struct { - Dev uint64 - Inode uint64 -} - -func statFromFileInfo(file os.FileInfo) Stat { - sys := file.Sys() - sysStat, ok := sys.(*syscall.Stat_t) - if !ok || sysStat == nil { - return Stat{} - } - return Stat{ - Dev: sysStat.Dev, - Inode: sysStat.Ino, - } -} diff --git a/ebpf/symtab/stat_placeholder.go b/ebpf/symtab/stat_placeholder.go deleted file mode 100644 index 37bcba169f..0000000000 --- a/ebpf/symtab/stat_placeholder.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build !linux && !darwin - -package symtab - -import ( - "os" -) - -type Stat struct { - Dev uint64 - Ino uint64 -} - -func statFromFileInfo(file os.FileInfo) Stat { - return Stat{} -} diff --git a/ebpf/symtab/symbols.go b/ebpf/symtab/symbols.go deleted file mode 100644 index dace7737f4..0000000000 --- a/ebpf/symtab/symbols.go +++ /dev/null @@ -1,130 +0,0 @@ -package symtab - -import ( - "fmt" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/ebpf/metrics" -) - -type PidKey uint32 - -// SymbolCache is responsible for resolving PC address to Symbol -// maintaining a pid -> ProcTable cache -// resolving kernel symbols -type SymbolCache struct { - pidCache *GCache[PidKey, *ProcTable] - - elfCache *ElfCache - kallsyms *SymbolTab - logger log.Logger - - metrics *metrics.SymtabMetrics -} -type CacheOptions struct { - PidCacheOptions GCacheOptions - BuildIDCacheOptions GCacheOptions - SameFileCacheOptions GCacheOptions -} - -func NewSymbolCache(logger log.Logger, options CacheOptions, metrics *metrics.SymtabMetrics) (*SymbolCache, error) { - if metrics == nil { - panic("metrics is nil") - } - elfCache, err := NewElfCache(options.BuildIDCacheOptions, options.SameFileCacheOptions) - if err != nil { - return nil, fmt.Errorf("create elf cache %w", err) - } - - cache, err := NewGCache[PidKey, *ProcTable](options.PidCacheOptions) - if err != nil { - return nil, fmt.Errorf("create pid cache %w", err) - } - return &SymbolCache{ - logger: logger, - pidCache: cache, - kallsyms: nil, - elfCache: elfCache, - metrics: metrics, - }, nil -} - -func (sc *SymbolCache) NextRound() { - sc.pidCache.NextRound() - sc.elfCache.NextRound() -} - -func (sc *SymbolCache) Cleanup() { - sc.elfCache.Cleanup() - sc.pidCache.Cleanup() -} - -func (sc *SymbolCache) GetProcTableCached(pid PidKey) *ProcTable { - cached := sc.pidCache.Get(pid) - if cached != nil { - return cached - } - return nil -} - -func (sc *SymbolCache) NewProcTable(pid PidKey, symbolOptions *SymbolOptions) *ProcTable { - - level.Debug(sc.logger).Log("msg", "NewProcTable", "pid", pid) - fresh := NewProcTable(sc.logger, ProcTableOptions{ - Pid: int(pid), - ElfTableOptions: ElfTableOptions{ - ElfCache: sc.elfCache, - Metrics: sc.metrics, - SymbolOptions: symbolOptions, - }, - }) - - sc.pidCache.Cache(pid, fresh) - return fresh -} - -func (sc *SymbolCache) GetKallsyms() SymbolTable { - if sc.kallsyms != nil { - return sc.kallsyms - } - return sc.initKallsyms() -} - -func (sc *SymbolCache) initKallsyms() SymbolTable { - var err error - sc.kallsyms, err = NewKallsyms() - if err != nil { - level.Error(sc.logger).Log("msg", "kallsyms init fail", "err", err) - sc.kallsyms = NewSymbolTab(nil) - } - if len(sc.kallsyms.symbols) == 0 { - _ = level.Error(sc.logger). - Log("msg", "kallsyms is empty. check your permissions kptr_restrict==0 && sysctl_perf_event_paranoid <= 1 or kptr_restrict==1 && CAP_SYSLOG") - } - - return sc.kallsyms -} - -func (sc *SymbolCache) UpdateOptions(options CacheOptions) { - sc.pidCache.Update(options.PidCacheOptions) - sc.elfCache.Update(options.BuildIDCacheOptions, options.SameFileCacheOptions) -} - -func (sc *SymbolCache) PidCacheDebugInfo() GCacheDebugInfo[ProcTableDebugInfo] { - return DebugInfo[PidKey, *ProcTable, ProcTableDebugInfo]( - sc.pidCache, - func(k PidKey, v *ProcTable, round int) ProcTableDebugInfo { - res := v.DebugInfo() - res.LastUsedRound = round - return res - }) -} - -func (sc *SymbolCache) ElfCacheDebugInfo() ElfCacheDebugInfo { - return sc.elfCache.DebugInfo() -} - -func (sc *SymbolCache) RemoveDeadPID(pid PidKey) { - sc.pidCache.Remove(pid) -} diff --git a/ebpf/symtab/symtab.go b/ebpf/symtab/symtab.go deleted file mode 100644 index ee3c623941..0000000000 --- a/ebpf/symtab/symtab.go +++ /dev/null @@ -1,39 +0,0 @@ -package symtab - -import "github.com/grafana/pyroscope/ebpf/symtab/elf" - -type SymbolTable interface { - Refresh() - Cleanup() - Resolve(addr uint64) Symbol -} - -type SymbolNameResolver interface { - Refresh() - Cleanup() - DebugInfo() elf.SymTabDebugInfo - IsDead() bool - Resolve(addr uint64) string -} - -type noopSymbolNameResolver struct { -} - -func (n *noopSymbolNameResolver) IsDead() bool { - return false -} - -func (n *noopSymbolNameResolver) DebugInfo() elf.SymTabDebugInfo { - return elf.SymTabDebugInfo{} -} - -func (n *noopSymbolNameResolver) Resolve(addr uint64) string { - return "" -} - -func (n *noopSymbolNameResolver) Refresh() { - -} -func (n *noopSymbolNameResolver) Cleanup() { - -} diff --git a/ebpf/symtab/table.go b/ebpf/symtab/table.go deleted file mode 100644 index 1f18815bf9..0000000000 --- a/ebpf/symtab/table.go +++ /dev/null @@ -1,51 +0,0 @@ -package symtab - -import ( - "sort" -) - -type SymbolTab struct { - symbols []Symbol - base uint64 -} - -func (t *SymbolTab) DebugString() string { - return "SymbolTab{TODO}" -} - -type Symbol struct { - Start uint64 - Name string - Module string -} - -func NewSymbolTab(symbols []Symbol) *SymbolTab { - return &SymbolTab{symbols: symbols} -} - -func (t *SymbolTab) Refresh() { - -} - -func (t *SymbolTab) Cleanup() { - -} - -func (t *SymbolTab) Rebase(base uint64) { - t.base = base -} - -func (t *SymbolTab) Resolve(addr uint64) Symbol { - if len(t.symbols) == 0 { - return Symbol{} - } - addr -= t.base - if addr < t.symbols[0].Start { - return Symbol{} - } - i := sort.Search(len(t.symbols), func(i int) bool { - return addr < t.symbols[i].Start - }) - i-- - return t.symbols[i] -} diff --git a/ebpf/symtab/table_test.go b/ebpf/symtab/table_test.go deleted file mode 100644 index a3f646f7a4..0000000000 --- a/ebpf/symtab/table_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package symtab - -import ( - "sort" - "testing" - - "github.com/stretchr/testify/require" -) - -type MockSymTab struct { - Symbols []MockSym - base uint64 -} - -type MockSym struct { - Start uint64 - Name string -} - -func NewSymTab(symbols []MockSym) *MockSymTab { - return &MockSymTab{Symbols: symbols} -} - -func (t *MockSymTab) Rebase(base uint64) { - t.base = base -} - -func (t *MockSymTab) Resolve(addr uint64) *MockSym { - if len(t.Symbols) == 0 { - return nil - } - addr -= t.base - if addr < t.Symbols[0].Start { - return nil - } - i := sort.Search(len(t.Symbols), func(i int) bool { - return addr < t.Symbols[i].Start - }) - i-- - return &t.Symbols[i] -} - -func (t *MockSymTab) Length() int { - return len(t.Symbols) -} - -func TestSymTab(t *testing.T) { - sym := NewSymTab([]MockSym{ - {0x1000, "0x1000"}, - {0x1200, "0x1200"}, - {0x1300, "0x1300"}, - }) - expect := func(t *testing.T, expected string, at uint64) { - resolved := sym.Resolve(at) - if expected == "" { - require.Nil(t, resolved) - return - } - require.NotNil(t, resolved) - require.Equal(t, expected, resolved.Name) - } - bases := []uint64{0, 0x4000} - testcases := []struct { - expected string - addr uint64 - }{ - {"", 0xef}, - {"0x1000", 0x1000}, - {"0x1000", 0x1100}, - {"0x1000", 0x11FF}, - {"0x1200", 0x1200}, - {"0x1200", 0x12FF}, - {"0x1300", 0x1300}, - {"0x1300", 0x2FFF}, - {"0x1300", 0x3000}, - {"0x1300", 0x4000}, - } - for _, base := range bases { - for _, c := range testcases { - sym.Rebase(base) - expect(t, c.expected, base+c.addr) - } - } -} diff --git a/ebpf/symtab/test_helper.go b/ebpf/symtab/test_helper.go deleted file mode 100644 index 8319748b30..0000000000 --- a/ebpf/symtab/test_helper.go +++ /dev/null @@ -1,13 +0,0 @@ -package symtab - -/* -#include -static size_t get_malloc__(){ - return (size_t)malloc; -} -*/ -import "C" - -func testHelperGetMalloc() int { - return int(C.get_malloc__()) -} diff --git a/ebpf/testdata b/ebpf/testdata deleted file mode 160000 index 4be781722c..0000000000 --- a/ebpf/testdata +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4be781722c576cfa17dca8c938b43d89e3ae26eb diff --git a/ebpf/testutil/docker.go b/ebpf/testutil/docker.go deleted file mode 100644 index f253344bb0..0000000000 --- a/ebpf/testutil/docker.go +++ /dev/null @@ -1,103 +0,0 @@ -package testutil - -import ( - "fmt" - "io" - "net/http" - "os/exec" - "strings" - "testing" - "time" - - "github.com/go-kit/log" - "github.com/stretchr/testify/require" -) - -type Container struct { - T *testing.T - L log.Logger - ContainerID string - ContainerPort string - hostPort string -} - -func PullImage(t *testing.T, l log.Logger, image string) { - container := &Container{ - T: t, - L: log.With(l, "component", "docker pull"), - } - _, err := container.execute("docker", "pull", image) - require.NoError(t, err) -} - -func RunContainerWithPort(t *testing.T, l log.Logger, image string, port string) *Container { - container := &Container{ - T: t, - L: log.With(l, "component", "docker"), - } - - container.Run("docker", "run", "--rm", "-tid", "-p", port, image) - - container.ContainerPort = port - container.WaitForPort() - return container - -} -func (c *Container) Run(cmd ...string) { - out, err := c.execute(cmd...) - require.NoError(c.T, err) - c.ContainerID = strings.TrimSpace(string(out)) -} - -func (c *Container) Kill() { - _, err := c.execute("docker", "kill", c.ContainerID) - require.NoError(c.T, err) -} - -func (c *Container) Url() string { - return fmt.Sprintf("http://127.0.0.1:%s", c.HostPort()) -} - -func (c *Container) HostPort() string { - if c.hostPort != "" { - return c.hostPort - } - require.NotEqual(c.T, "", c.ContainerPort) - out, err := c.execute("docker", "port", c.ContainerID, c.ContainerPort) - require.NoError(c.T, err) - ports := strings.Split(string(out), "\n") - require.Greater(c.T, len(ports), 1) - port := ports[0] - fields := strings.Split(port, ":") - require.Equal(c.T, len(fields), 2) - c.hostPort = fields[1] - return fields[1] -} - -func (c *Container) WaitForPort() { - require.Eventually(c.T, func() bool { - req, err := http.NewRequest("GET", c.Url(), nil) - require.NoError(c.T, err) - resp, err := http.DefaultClient.Do(req) - if err != nil { - return false - } - if resp.StatusCode != 200 { - return false - } - _, err = io.ReadAll(resp.Body) - require.NoError(c.T, err) - return true - }, 10*time.Second, 100*time.Millisecond) -} - -func (c *Container) execute(cmd ...string) ([]byte, error) { - cc := exec.Command(cmd[0], cmd[1:]...) - c.L.Log("cmd", cc.String()) - out, err := cc.CombinedOutput() - _ = c.L.Log("cmd", cc.String(), "output", string(out), "err", err) - if err != nil { - return nil, fmt.Errorf("%s run failed: %s - %w", cc.String(), string(out), err) - } - return out, nil -} diff --git a/ebpf/testutil/testdata.go b/ebpf/testutil/testdata.go deleted file mode 100644 index 812684ced7..0000000000 --- a/ebpf/testutil/testdata.go +++ /dev/null @@ -1,16 +0,0 @@ -package testutil - -import ( - "os" - "os/exec" - "testing" - - "github.com/stretchr/testify/require" -) - -func InitGitSubmodule(t *testing.T) { - cmd := exec.Command("git", "submodule", "update", "--init", "--recursive") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - require.NoError(t, cmd.Run()) -} diff --git a/ebpf/util/test_logger.go b/ebpf/util/test_logger.go deleted file mode 100644 index e46417dde6..0000000000 --- a/ebpf/util/test_logger.go +++ /dev/null @@ -1,29 +0,0 @@ -package util - -import ( - "os" - "testing" - "time" - - "github.com/go-kit/log" -) - -// TestLogger generates a logger for a test. -func TestLogger(t *testing.T) log.Logger { - t.Helper() - - l := log.NewSyncLogger(log.NewLogfmtLogger(os.Stderr)) - l = log.WithPrefix(l, - "test", t.Name(), - "ts", log.Valuer(testTimestamp), - ) - - return l -} - -// testTimestamp is a log.Valuer that returns the timestamp -// without the date or timezone, reducing the noise in the test. -func testTimestamp() interface{} { - t := time.Now().UTC() - return t.Format("15:04:05.000") -} diff --git a/examples/README.md b/examples/README.md index defd7b08d2..73426320cd 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,6 +3,7 @@ Choose a language folder to select an example for your language of choice. # How Pyroscope works + Pyroscope identifies performance issues in your application by continuously profiling the code. If you've never used a profiler before, then welcome! @@ -16,16 +17,16 @@ If you are familiar with profiling and flame graphs, then you'll be happy to kno ## Auto-instrumentation and language SDK instrumentation examples Pyroscope is a continuous profiling database that allows you to analyze the performance of your applications. -When sending profiles to Pyroscope, you can choose between two primary methods: SDK Instrumentation and auto-instrumentation using the Grafana Agent. +When sending profiles to Pyroscope, you can choose between two primary methods: SDK Instrumentation and auto-instrumentation using Grafana Alloy. -![Pyroscope agent server diagram](https://grafana.com/media/docs/pyroscope/pyroscope_client_server_diagram.png) +![Pyroscope agent server diagram](https://grafana.com/media/docs/pyroscope/pyroscope_client_server_diagram_09_18_2024.png) ### About auto-instrumentation with Grafana Alloy or Agent collectors You can send data from your application using Grafana Alloy or Grafana Agent collectors. Both collectors support profiling with eBPF, Java, and Golang in pull mode. -For examples using auto-instrumentation with the collectors, try the `grafana-agent-auto-instrumentation` example. +For examples using auto-instrumentation with the collectors, try the `grafana-alloy-auto-instrumentation` example. [Grafana Alloy](https://grafana.com/docs/alloy/latest/) is a vendor-neutral distribution of the OpenTelemetry (OTel) Collector. Alloy uniquely combines the very best OSS observability signals in the community. @@ -70,10 +71,10 @@ Here are some factors to consider when making the choice: To get started, choose one of the integrations below: - - diff --git a/examples/_templates/grafana/docker-compose.yml b/examples/_templates/grafana/docker-compose.yml new file mode 100644 index 0000000000..5ec55210c4 --- /dev/null +++ b/examples/_templates/grafana/docker-compose.yml @@ -0,0 +1,13 @@ +services: + grafana: + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/_templates/prometheus/docker-compose.yml b/examples/_templates/prometheus/docker-compose.yml new file mode 100644 index 0000000000..2c9a3a1c42 --- /dev/null +++ b/examples/_templates/prometheus/docker-compose.yml @@ -0,0 +1,14 @@ +services: + prometheus: + image: prom/prometheus:v3.1.0 + ports: + - '9099:9090' + command: > + --enable-feature=remote-write-receiver + --enable-feature=exemplar-storage + --enable-feature=native-histograms + --config.file=/etc/prometheus/prometheus.yml + --storage.tsdb.path=/prometheus + --web.enable-otlp-receiver + volumes: + - ./prometheus-provisioning/prometheus.yaml:/etc/prometheus/prometheus.yml diff --git a/examples/_templates/prometheus/grafana-provisioning/datasources/prometheus.yml b/examples/_templates/prometheus/grafana-provisioning/datasources/prometheus.yml new file mode 100644 index 0000000000..2092eaed7a --- /dev/null +++ b/examples/_templates/prometheus/grafana-provisioning/datasources/prometheus.yml @@ -0,0 +1,16 @@ +--- +apiVersion: 1 +datasources: + - uid: local-prometheus + type: prometheus + name: Prometheus + access: proxy + url: http://prometheus:9090 + basicAuth: true #username: admin, password: admin + basicAuthUser: admin + jsonData: + manageAlerts: true + prometheusType: Prometheus #Cortex | Mimir | Prometheus | Thanos + prometheusVersion: 2.40.0 + secureJsonData: + basicAuthPassword: admin #https://grafana.com/docs/grafana/latest/administration/provisioning/#using-environment-variables diff --git a/examples/_templates/pyroscope/docker-compose.yml b/examples/_templates/pyroscope/docker-compose.yml new file mode 100644 index 0000000000..8106242cd8 --- /dev/null +++ b/examples/_templates/pyroscope/docker-compose.yml @@ -0,0 +1,5 @@ +services: + pyroscope: + image: grafana/pyroscope:latest + ports: + - 4040:4040 diff --git a/examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml b/examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..febbf9e92d --- /dev/null +++ b/examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,14 @@ +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/_templates/sync_test.go b/examples/_templates/sync_test.go new file mode 100644 index 0000000000..2555143d02 --- /dev/null +++ b/examples/_templates/sync_test.go @@ -0,0 +1,543 @@ +package templates_test + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "go.yaml.in/yaml/v3" +) + +const ( + modeCheck = "check" + modeUpdate = "update" + + // templatesDir is the repo-relative path of the templates directory. + // It is used solely to build the "generated from" path in file headers; + // update it here if the directory is ever moved. + templatesDir = "examples/_templates" +) + +// checkMode returns the value of EXAMPLE_CHECK_MODE ("check" or "update"). +// Any other value (including unset) causes the test to be skipped. +func checkMode() string { return os.Getenv("EXAMPLE_CHECK_MODE") } + +// fileHeader returns the "do not edit" comment block prepended to every +// non-docker-compose template file (Style A: #-comments at column 0). +// tmplName is the template directory name (e.g. "grafana"); rel is the +// file path relative to that template directory. +func fileHeader(tmplName, rel string) string { + src := templatesDir + "/" + tmplName + "/" + rel + return "# This file is generated from the template:\n" + + "# " + src + "\n" + + "# Do not edit directly. To update, edit the template and run:\n" + + "# make examples/sync-templates\n" +} + +// serviceHeader returns the two-line "do not edit" comment injected inside a +// docker-compose service block (Style B: 4-space-indented #-comments). +// tmplName is the template directory name (e.g. "grafana"). +func serviceHeader(tmplName string) string { + src := templatesDir + "/" + tmplName + "/docker-compose.yml" + return " # This service is generated from " + src + "\n" + + " # Do not edit directly. To update, edit the template and run: make examples/sync-templates\n" +} + +// injectServiceHeader inserts the Style B header comment on the second line of +// a service block (right after the " :" key line). +func injectServiceHeader(block, tmplName string) string { + idx := strings.Index(block, "\n") + if idx < 0 { + return block + } + return block[:idx+1] + serviceHeader(tmplName) + block[idx+1:] +} + +// example registers one example directory and which templates apply to it. +type example struct { + // compose is the path to the folder containing the docker-compose file, + // relative to examples/. + compose string + // templates lists template directory names (under examples/templates/) that + // govern this example. For each template: + // - docker-compose.yml → the service it defines is checked structurally. + // - all other files → checked byte-for-byte at the same relative path + // inside the example directory. + templates []string + // serviceVolumes maps a service name to extra volume mount lines that are + // appended after the template's own volumes entries for that service. + // Use this when an example legitimately extends a templated service with + // additional volume mounts (e.g. a custom grafana.ini or home dashboard). + // The template prefix is still enforced; only the extra lines are allowed + // to deviate. Lines should use the same 4-space indent as the template + // (e.g. " - ./grafana/grafana.ini:/etc/grafana/grafana.ini"). + serviceVolumes map[string][]string +} + +// j is a shorthand for filepath.Join. +var j = filepath.Join + +// examples is the authoritative list of every example directory and which +// templates apply to it. When adding a new example, register it here. +var examples = []example{ + // ── tracing ────────────────────────────────────────────────────────────── + { + compose: "tracing/dotnet", + templates: []string{"grafana", "tempo", "pyroscope"}, + }, + { + compose: "tracing/golang-push", + templates: []string{"grafana", "tempo", "pyroscope"}, + }, + { + compose: "tracing/java", + templates: []string{"grafana", "tempo", "pyroscope"}, + }, + { + compose: "tracing/java-wall", + templates: []string{"grafana", "tempo", "pyroscope"}, + }, + { + compose: "tracing/python", + templates: []string{"grafana", "tempo", "pyroscope"}, + }, + { + compose: "tracing/ruby", + templates: []string{"grafana", "tempo", "pyroscope"}, + }, + { + compose: "tracing/tempo", + templates: []string{"grafana", "tempo", "pyroscope"}, + }, + + // ── base-url ────────────────────────────────────────────────────────────── + { + compose: "base-url", + // grafana absent; pyroscope uses a custom command flag + }, + + // ── golang-pgo ─────────────────────────────────────────────────────────── + { + compose: "golang-pgo", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── grafana-alloy-auto-instrumentation ──────────────────────────────────── + { + compose: "grafana-alloy-auto-instrumentation/ebpf/docker", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "grafana-alloy-auto-instrumentation/ebpf/local", + templates: []string{"grafana", "pyroscope"}, + }, + { + // The grafana service mounts extra files (grafana.ini, home.json) for a + // custom default home dashboard — tracked via serviceVolumes so the + // template's shared config is still enforced. + compose: "grafana-alloy-auto-instrumentation/golang-pull", + templates: []string{"grafana", "pyroscope"}, + serviceVolumes: map[string][]string{ + "grafana": { + " - ./grafana/grafana.ini:/etc/grafana/grafana.ini", + " - ./grafana/home.json:/default-dashboard.json", + }, + }, + }, + { + compose: "grafana-alloy-auto-instrumentation/java/docker", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── language-sdk-instrumentation/dotnet ────────────────────────────────── + { + compose: "language-sdk-instrumentation/dotnet/fast-slow", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/dotnet/rideshare", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/dotnet/web-new", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── language-sdk-instrumentation/golang-push ───────────────────────────── + { + // The rideshare example also provisions a Prometheus datasource because + // its app exports OTLP metrics to Prometheus. The prometheus template + // provides the service definition and grafana datasource provisioning. + compose: "language-sdk-instrumentation/golang-push/rideshare", + templates: []string{"grafana", "pyroscope", "prometheus"}, + }, + { + compose: "language-sdk-instrumentation/golang-push/rideshare-alloy", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/golang-push/rideshare-k6", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/golang-push/simple", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── language-sdk-instrumentation/java ──────────────────────────────────── + { + compose: "language-sdk-instrumentation/java/fib", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/java/rideshare", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/java/simple", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── language-sdk-instrumentation/nodejs ────────────────────────────────── + { + compose: "language-sdk-instrumentation/nodejs/express", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/nodejs/express-pull", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/nodejs/express-ts", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/nodejs/express-ts-inline", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/nodejs/tinyhttp", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── language-sdk-instrumentation/python ────────────────────────────────── + { + compose: "language-sdk-instrumentation/python/rideshare/django", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/python/rideshare/fastapi", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/python/rideshare/flask", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/python/simple", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── language-sdk-instrumentation/ruby ──────────────────────────────────── + { + compose: "language-sdk-instrumentation/ruby/rideshare", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/ruby/rideshare_rails", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/ruby/simple", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── language-sdk-instrumentation/rust ──────────────────────────────────── + { + compose: "language-sdk-instrumentation/rust/basic", + templates: []string{"grafana", "pyroscope"}, + }, + { + compose: "language-sdk-instrumentation/rust/rideshare", + templates: []string{"grafana", "pyroscope"}, + }, + + // ── otel-collector ─────────────────────────────────────────────────────── + { + compose: "otel-collector/ebpf/docker", + // grafana omitted: has networks key + // pyroscope omitted: pinned version + networks + }, +} + +// TestExamplesConsistency verifies (or updates) every registered example's +// service blocks and config files against their templates. +// +// Check: EXAMPLE_CHECK_MODE=check go test ./examples/templates/ +// Sync: EXAMPLE_CHECK_MODE=update go test ./examples/templates/ +func TestExamplesConsistency(t *testing.T) { + switch checkMode() { + case modeCheck, modeUpdate: + // proceed + default: + t.Skip("set EXAMPLE_CHECK_MODE=check or EXAMPLE_CHECK_MODE=update to run") + } + + for _, ex := range examples { + ex := ex + t.Run(ex.compose, func(t *testing.T) { + exDir := j("..", ex.compose) + composePath := findCompose(t, exDir) + + for _, tmplName := range ex.templates { + tmplName := tmplName + t.Run(tmplName, func(t *testing.T) { + tmplDir := tmplName + + // Walk everything in the template dir. + err := filepath.WalkDir(tmplDir, func(path string, d fs.DirEntry, err error) error { + require.NoError(t, err) + if d.IsDir() { + return nil + } + + rel, err := filepath.Rel(tmplDir, path) + require.NoError(t, err) + + if rel == "docker-compose.yml" { + // Service block check: structural YAML comparison. + svcName, canonical := loadTemplateService(t, path) + // Inject the "do not edit" header comment into the block. + canonical = injectServiceHeader(canonical, tmplName) + // Apply any per-example extra volume mounts. + if extra, ok := ex.serviceVolumes[svcName]; ok { + canonical = injectVolumes(t, canonical, extra) + } + t.Run(svcName, func(t *testing.T) { + if checkMode() == modeUpdate { + require.NoError(t, updateService(t, composePath, svcName, canonical)) + return + } + got, err := extractService(t, composePath, svcName) + require.NoError(t, err) + require.NotEmpty(t, got, "service %q not found in %s", svcName, composePath) + require.Equal(t, canonical, got, + "services.%s in %s differs from template %s\n"+ + "Update the template or fix the compose file.", + svcName, composePath, path) + }) + } else { + // Config file check: prepend generated header then byte-identical. + dstPath := j(exDir, rel) + t.Run(rel, func(t *testing.T) { + body, err := os.ReadFile(path) + require.NoError(t, err) + canonical := []byte(fileHeader(tmplName, rel)) + canonical = append(canonical, body...) + if checkMode() == modeUpdate { + require.NoError(t, os.MkdirAll(filepath.Dir(dstPath), 0o755)) + require.NoError(t, os.WriteFile(dstPath, canonical, 0o644)) + return + } + got, err := os.ReadFile(dstPath) + require.NoError(t, err) + require.Equal(t, string(canonical), string(got), + "%s differs from template %s\nRun: EXAMPLE_CHECK_MODE=update go test ./examples/templates/", + dstPath, path) + }) + } + return nil + }) + require.NoError(t, err) + }) + } + }) + } +} + +// injectVolumes appends extra volume mount lines to the volumes: block of a +// service block string. The extra lines must use the same indentation as the +// existing entries (4-space indent). The volumes: key must already exist in +// the block. +func injectVolumes(t *testing.T, block string, extra []string) string { + t.Helper() + lines := strings.Split(block, "\n") + // Find the last existing volume entry — extra lines go right after it. + insertAt := -1 + inVolumes := false + for i, l := range lines { + trimmed := strings.TrimSpace(l) + if trimmed == "volumes:" { + inVolumes = true + continue + } + if inVolumes { + if strings.HasPrefix(l, " -") { + insertAt = i + } else if trimmed != "" && !strings.HasPrefix(l, " -") { + // Hit a new key at the same or higher level: stop. + break + } + } + } + require.NotEqual(t, -1, insertAt, "injectVolumes: no volume entries found in service block") + result := make([]string, 0, len(lines)+len(extra)) + result = append(result, lines[:insertAt+1]...) + result = append(result, extra...) + result = append(result, lines[insertAt+1:]...) + return strings.Join(result, "\n") +} + +// findCompose returns the path to the docker-compose file inside dir. +func findCompose(t *testing.T, dir string) string { + t.Helper() + for _, name := range []string{"docker-compose.yml", "docker-compose.yaml"} { + p := j(dir, name) + if _, err := os.Stat(p); err == nil { + return p + } + } + t.Fatalf("no docker-compose file found in %s", dir) + return "" +} + +// loadTemplateService reads a template docker-compose.yml, asserts it has +// exactly one service, and returns the service name and its raw text block. +func loadTemplateService(t *testing.T, path string) (name, content string) { + t.Helper() + data, err := os.ReadFile(path) + require.NoError(t, err) + var root yaml.Node + require.NoError(t, yaml.Unmarshal(data, &root)) + topMap := root.Content[0] + servicesNode := mappingValue(topMap, "services") + require.NotNil(t, servicesNode, "%s: missing 'services' key", path) + require.Equal(t, 2, len(servicesNode.Content), "%s: template must define exactly one service", path) + name = servicesNode.Content[0].Value + content, err = serviceBlock(data, topMap, name) + require.NoError(t, err) + return name, content +} + +// extractService returns the raw text block of the named service from a +// docker-compose file, or an empty string if the service is not found. +func extractService(t *testing.T, path, svcName string) (string, error) { + t.Helper() + data, err := os.ReadFile(path) + if err != nil { + return "", err + } + var root yaml.Node + if err := yaml.Unmarshal(data, &root); err != nil { + return "", err + } + if len(root.Content) == 0 { + return "", nil + } + return serviceBlock(data, root.Content[0], svcName) +} + +// updateService replaces the named service block in a docker-compose file with +// the provided canonical block (which already includes any per-example extras). +func updateService(t *testing.T, composePath, svcName, canonical string) error { + t.Helper() + + composeData, err := os.ReadFile(composePath) + if err != nil { + return err + } + var composeRoot yaml.Node + if err := yaml.Unmarshal(composeData, &composeRoot); err != nil { + return err + } + s, e := serviceLines(composeData, composeRoot.Content[0], svcName) + if s < 0 { + return fmt.Errorf("service %q not found in %s", svcName, composePath) + } + + lines := strings.Split(string(composeData), "\n") + var out strings.Builder + for _, l := range lines[:s] { + out.WriteString(l) + out.WriteByte('\n') + } + out.WriteString(canonical) + for _, l := range lines[e:] { + out.WriteString(l) + out.WriteByte('\n') + } + result := strings.TrimRight(out.String(), "\n") + "\n" + return os.WriteFile(composePath, []byte(result), 0o644) +} + +// serviceBlock returns the raw source text of the named service block, +// using yaml.Node line numbers to slice the file — no marshalling. +func serviceBlock(data []byte, topMap *yaml.Node, svcName string) (string, error) { + s, e := serviceLines(data, topMap, svcName) + if s < 0 { + return "", nil + } + lines := strings.Split(string(data), "\n") + return strings.Join(lines[s:e], "\n") + "\n", nil +} + +// serviceLines returns the 0-indexed [start, end) line range of the named +// service block, using yaml.Node.Line for boundaries. end trims trailing blank +// lines. Returns -1, -1 if the service is not found. +func serviceLines(data []byte, topMap *yaml.Node, svcName string) (start, end int) { + servicesNode := mappingValue(topMap, "services") + if servicesNode == nil { + return -1, -1 + } + + var startLine, endLine int // 1-indexed; endLine==0 means "not yet known" + for i := 0; i < len(servicesNode.Content)-1; i += 2 { + if servicesNode.Content[i].Value == svcName { + startLine = servicesNode.Content[i].Line + if i+2 < len(servicesNode.Content) { + // Next sibling service key marks the end. + endLine = servicesNode.Content[i+2].Line + } + break + } + } + if startLine == 0 { + return -1, -1 + } + + lines := strings.Split(string(data), "\n") + if endLine == 0 { + // Last (or only) service: end at the next top-level key, or EOF. + for i := 0; i < len(topMap.Content)-1; i += 2 { + if topMap.Content[i].Value == "services" && i+2 < len(topMap.Content) { + endLine = topMap.Content[i+2].Line + break + } + } + if endLine == 0 { + endLine = len(lines) + 1 + } + } + + // Convert to 0-indexed and trim trailing blank lines. + s := startLine - 1 + e := endLine - 1 + for e > s && strings.TrimSpace(lines[e-1]) == "" { + e-- + } + return s, e +} + +// mappingValue returns the value node for key in a YAML MappingNode, or nil. +func mappingValue(m *yaml.Node, key string) *yaml.Node { + for i := 0; i < len(m.Content)-1; i += 2 { + if m.Content[i].Value == key { + return m.Content[i+1] + } + } + return nil +} diff --git a/examples/_templates/tempo/docker-compose.yml b/examples/_templates/tempo/docker-compose.yml new file mode 100644 index 0000000000..6d6181bd9f --- /dev/null +++ b/examples/_templates/tempo/docker-compose.yml @@ -0,0 +1,13 @@ +services: + tempo: + image: grafana/tempo:2.10.5 + command: [ "-config.file=/etc/tempo.yml" ] + volumes: + - ./tempo/tempo.yml:/etc/tempo.yml + ports: + - "14268:14268" # jaeger ingest + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin diff --git a/examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml b/examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..445459c0e3 --- /dev/null +++ b/examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,25 @@ +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/_templates/tempo/tempo/tempo.yml b/examples/_templates/tempo/tempo/tempo.yml new file mode 100644 index 0000000000..d02325bac7 --- /dev/null +++ b/examples/_templates/tempo/tempo/tempo.yml @@ -0,0 +1,34 @@ +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + opencensus: + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks diff --git a/examples/base-url/docker-compose.yml b/examples/base-url/docker-compose.yml index c66452cf2e..302c1a2e97 100644 --- a/examples/base-url/docker-compose.yml +++ b/examples/base-url/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3' services: pyroscope: image: grafana/pyroscope diff --git a/examples/examples_test.go b/examples/examples_test.go new file mode 100644 index 0000000000..cfe028f531 --- /dev/null +++ b/examples/examples_test.go @@ -0,0 +1,905 @@ +//go:build examples + +package examples + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "os" + "os/signal" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "syscall" + "testing" + "time" + + "os/exec" + + "github.com/stretchr/testify/require" + "go.yaml.in/yaml/v3" +) + +const ( + timeoutPerExample = 20 * time.Minute + // How long to wait for all containers to come up and stay running. + runningTimeout = 90 * time.Second + // How long to wait for profiles to be ingested and become queryable. + profilesQueryTimeout = 3 * time.Minute + // How long to wait for traces to be ingested and become searchable. + tracesQueryTimeout = 3 * time.Minute + pollInterval = 3 * time.Second +) + +const ( + pyroscopeService = "pyroscope" + pyroscopePort = "4040" + tempoService = "tempo" + tempoPort = "3200" +) + +// activeStacks tracks the compose stacks that are currently up, so they can be +// torn down on an interrupt (where t.Cleanup does not run). +var ( + activeMu sync.Mutex + activeStacks = map[string]*env{} +) + +func registerActive(e *env) { activeMu.Lock(); activeStacks[e.projectName()] = e; activeMu.Unlock() } +func unregisterActive(e *env) { + activeMu.Lock() + delete(activeStacks, e.projectName()) + activeMu.Unlock() +} + +// TestMain installs a signal handler so that an interrupted run (Ctrl+C) still +// tears down the docker-compose stacks it started. t.Cleanup does not run when +// the test process is killed by a signal, which would otherwise leak containers. +func TestMain(m *testing.M) { + sig := make(chan os.Signal, 1) + signal.Notify(sig, os.Interrupt, syscall.SIGTERM) + go func() { + <-sig + activeMu.Lock() + envs := make([]*env, 0, len(activeStacks)) + for _, e := range activeStacks { + envs = append(envs, e) + } + activeMu.Unlock() + for _, e := range envs { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + _ = e.newCmd(ctx, "down", "--volumes").Run() + cancel() + } + os.Exit(1) + }() + os.Exit(m.Run()) +} + +type env struct { + dir string // project dir of docker-compose, relative to the test working directory + path string // path to docker-compose file + completedSuccessfully map[string]struct{} +} + +func (e *env) repoDir() string { + return filepath.Join("examples", e.dir) +} + +type status struct { + Name string `json:"Name"` + Service string `json:"Service"` + State string `json:"State"` + ExitCode int `json:"ExitCode"` +} + +func (e *env) projectName() string { + h := sha256.New() + _, _ = h.Write([]byte(e.dir)) + return fmt.Sprintf("%s_%x", filepath.Base(e.dir), h.Sum(nil)[0:2]) +} + +func (e *env) newCmd(ctx context.Context, args ...string) *exec.Cmd { + c := exec.CommandContext( + ctx, + "docker", + append([]string{ + "compose", + "--file", e.path, + "--project-directory", e.dir, + "--project-name", e.projectName(), + }, args...)...) + return c +} + +// run executes a docker compose command, buffering its output and surfacing it +// only when the command fails. This keeps successful runs readable under -v, +// while still capturing full logs for debugging failures. +func (e *env) run(t testing.TB, ctx context.Context, args ...string) error { + out, err := e.newCmd(ctx, args...).CombinedOutput() + if err != nil { + t.Logf("$ docker compose %s\n%s", strings.Join(args, " "), string(out)) + } + return err +} + +func (e *env) containerStatus(ctx context.Context) ([]status, error) { + data, err := e.newCmd(ctx, "ps", "--all", "--format", "json").Output() + if err != nil { + return nil, err + } + + var stats []status + dec := json.NewDecoder(bytes.NewReader(data)) + for { + var s status + err := dec.Decode(&s) + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return nil, err + } + stats = append(stats, s) + } + + return stats, nil +} + +func (e *env) containersReady(ctx context.Context) error { + statuses, err := e.containerStatus(ctx) + if err != nil { + return err + } + return containerStatusesReady(statuses, e.completedSuccessfully) +} + +func containerStatusesReady(statuses []status, completedSuccessfully map[string]struct{}) error { + if len(statuses) == 0 { + return errors.New("no containers found") + } + + var errs []error + for _, s := range statuses { + if s.State == "running" { + continue + } + _, isCompletedService := completedSuccessfully[s.Service] + if isCompletedService && s.State == "exited" && s.ExitCode == 0 { + continue + } + errs = append(errs, fmt.Errorf( + "container %s is not ready (service=%s, state=%s, exit_code=%d)", + s.Name, s.Service, s.State, s.ExitCode, + )) + } + + return errors.Join(errs...) +} + +func completedSuccessfullyServices(services map[string]interface{}) map[string]struct{} { + completed := make(map[string]struct{}) + for _, service := range services { + params, ok := service.(map[string]interface{}) + if !ok { + continue + } + dependencies, ok := params["depends_on"].(map[string]interface{}) + if !ok { + continue + } + for serviceName, dependency := range dependencies { + config, ok := dependency.(map[string]interface{}) + if !ok { + continue + } + if config["condition"] == "service_completed_successfully" { + completed[serviceName] = struct{}{} + } + } + } + return completed +} + +// prepareCompose rewrites the docker-compose file into a temporary copy so that: +// - every published port is bound to a random host port on localhost only +// (avoids conflicts when running examples in parallel and keeps the +// unauthenticated test services off the runner's external interfaces), and +// - the pyroscope (and, when present, tempo) services always publish their +// API ports so the test can query them over localhost. +func (e *env) prepareCompose(t testing.TB) *env { + var obj map[string]interface{} + + body, err := os.ReadFile(e.path) + require.NoError(t, err) + require.NoError(t, yaml.Unmarshal(body, &obj)) + + services, ok := obj["services"].(map[string]interface{}) + require.True(t, ok, "docker-compose file has no services map") + completedSuccessfully := completedSuccessfullyServices(services) + + for serviceName, service := range services { + params, ok := service.(map[string]interface{}) + if !ok { + require.NoError(t, fmt.Errorf("service '%s' is not a map", serviceName)) + } + localhostBindPorts(params) + } + + // Ensure the API ports we need to query are published (on localhost). + pp, _ := strconv.Atoi(pyroscopePort) + tp, _ := strconv.Atoi(tempoPort) + if svc, ok := services[pyroscopeService].(map[string]interface{}); ok { + ensurePublished(svc, pp) + } + if svc, ok := services[tempoService].(map[string]interface{}); ok { + ensurePublished(svc, tp) + } + + path := filepath.Join(t.TempDir(), "docker-compose.yml") + data, err := yaml.Marshal(obj) + require.NoError(t, err) + require.NoError(t, os.WriteFile(path, data, 0644)) + + return &env{ + dir: e.dir, + path: path, + completedSuccessfully: completedSuccessfully, + } +} + +// containerPortOf returns the container-side port of a docker-compose ports +// entry, handling short ("3000", "3000:3000", "127.0.0.1:80:8080"), numeric +// (4040) and long-form ({target: 4040, ...}) syntaxes. Returns 0 if unknown. +func containerPortOf(p interface{}) int { + switch v := p.(type) { + case int: + return v + case string: + parts := strings.Split(v, ":") + n, _ := strconv.Atoi(parts[len(parts)-1]) + return n + case map[string]interface{}: + return containerPortOf(v["target"]) + default: + return 0 + } +} + +// localhostPort is a long-form ports entry that binds the container port to a +// random host port on the loopback interface only. +func localhostPort(containerPort int) map[string]any { + return map[string]any{"target": containerPort, "host_ip": "127.0.0.1"} +} + +// localhostBindPorts rewrites every published port of a service to a random +// loopback-only binding. This both avoids host port conflicts when examples run +// in parallel and prevents exposing services on external interfaces. +func localhostBindPorts(params map[string]interface{}) { + ports, ok := params["ports"].([]interface{}) + if !ok { + return + } + for i := range ports { + if cp := containerPortOf(ports[i]); cp != 0 { + ports[i] = localhostPort(cp) + } + } +} + +func ensurePublished(params map[string]interface{}, containerPort int) { + ports, _ := params["ports"].([]interface{}) + for _, p := range ports { + if containerPortOf(p) == containerPort { + return + } + } + params["ports"] = append(ports, localhostPort(containerPort)) +} + +// hostPort resolves the random host port that the given service's container port +// has been published on. +func (e *env) hostPort(t testing.TB, ctx context.Context, service, containerPort string) string { + out, err := e.newCmd(ctx, "port", service, containerPort).Output() + require.NoError(t, err, "resolving host port for %s:%s", service, containerPort) + line := strings.TrimSpace(string(out)) + require.NotEmpty(t, line, "no published host port for %s:%s", service, containerPort) + line = strings.SplitN(line, "\n", 2)[0] + idx := strings.LastIndex(line, ":") + require.GreaterOrEqual(t, idx, 0, "unexpected docker compose port output: %q", line) + return line[idx+1:] +} + +// bringUp builds, pulls and starts the example detached. +func (e *env) bringUp(t *testing.T, ctx context.Context) { + // Register before starting and tear down on cleanup, so the stack is removed + // both on normal completion (t.Cleanup) and on interrupt (see TestMain). + registerActive(e) + t.Cleanup(func() { + unregisterActive(e) + if err := e.run(t, context.Background(), "down", "--volumes"); err != nil { + t.Logf("cleanup error=%v", err) + } + }) + t.Run("build", func(t *testing.T) { + require.NoError(t, e.run(t, ctx, "build")) + }) + // pull first so containers can start immediately + t.Run("pull", func(t *testing.T) { + require.NoError(t, e.run(t, ctx, "pull")) + }) + require.NoError(t, e.run(t, ctx, "up", "--detach")) +} + +// waitReady waits until all regular containers are running and all init +// services have completed successfully. Unexpected exits are caught here. +func (e *env) waitReady(t testing.TB, ctx context.Context) { + poll(t, ctx, runningTimeout, func(progress func(string, ...any)) error { + progress("[%s] waiting for all containers to be ready...", e.repoDir()) + return e.containersReady(ctx) + }) +} + +// poll calls fn until it returns nil, the timeout elapses, or the context is +// cancelled. On timeout it fails the test with the last error fn returned. +// +// fn receives a progress reporter it should use to announce what it is doing. +// Each distinct message is logged once across the whole poll, so steps show up +// as they are first reached without spamming a line on every retry. +func poll(t testing.TB, ctx context.Context, timeout time.Duration, fn func(progress func(string, ...any)) error) { + progress := func(format string, args ...any) { + msg := fmt.Sprintf(format, args...) + t.Log(msg) + } + deadline := time.Now().Add(timeout) + for { + err := fn(progress) + if err == nil { + return + } + progress("waiting: %s", err.Error()) + if time.Now().After(deadline) { + require.NoError(t, err, "condition not met within %s", timeout) + return + } + select { + case <-ctx.Done(): + require.NoError(t, ctx.Err()) + return + case <-time.After(pollInterval): + } + } +} + +// --- Pyroscope query helpers ------------------------------------------------- + +func nowWindowMillis() (start, end int64) { + now := time.Now() + return now.Add(-1 * time.Hour).UnixMilli(), now.Add(1 * time.Minute).UnixMilli() +} + +func (e *env) pyroscopePost(ctx context.Context, host, apiPath string, reqBody any, out any) error { + body, err := json.Marshal(reqBody) + if err != nil { + return err + } + url := fmt.Sprintf("http://%s/%s", host, apiPath) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("%s returned %d: %s", apiPath, resp.StatusCode, string(data)) + } + return json.Unmarshal(data, out) +} + +type labelPair struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type seriesResponse struct { + LabelsSet []struct { + Labels []labelPair `json:"labels"` + } `json:"labelsSet"` +} + +func labelValue(labels []labelPair, name string) string { + for _, l := range labels { + if l.Name == name { + return l.Value + } + } + return "" +} + +// seriesData maps a service name to its ingested CPU/wall profile types. Those +// are the types span profiles are attached to; other types (memory, lock, etc.) +// are not useful for these checks and are dropped. +type seriesData map[string][]string + +func sortedKeys(d seriesData) []string { + keys := make([]string, 0, len(d)) + for k := range d { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// selfProfilingService is the service name Pyroscope uses for its own profiles. +// Examples that don't disable self-profiling will surface it; we exclude it so +// the checks validate the example's application rather than the server. +const selfProfilingService = "pyroscope" + +// isCPUOrWallType reports whether a profile type is a CPU or wall-clock type. +func isCPUOrWallType(profileType string) bool { + return strings.HasPrefix(profileType, "process_cpu:") || strings.HasPrefix(profileType, "wall:") +} + +// discoverSeries queries the Series API and returns the application services and +// their ingested CPU/wall profile types. Self-profiling series and non-CPU/wall +// types are excluded. +func (e *env) discoverSeries(ctx context.Context, host string) (seriesData, error) { + start, end := nowWindowMillis() + var resp seriesResponse + err := e.pyroscopePost(ctx, host, "querier.v1.QuerierService/Series", map[string]any{ + "start": start, + "end": end, + "labelNames": []string{"service_name", "__profile_type__"}, + }, &resp) + if err != nil { + return nil, err + } + + data := seriesData{} + for _, ls := range resp.LabelsSet { + svc := labelValue(ls.Labels, "service_name") + pt := labelValue(ls.Labels, "__profile_type__") + if svc == "" || svc == selfProfilingService || !isCPUOrWallType(pt) { + continue + } + data[svc] = append(data[svc], pt) + } + if len(data) == 0 { + return nil, errors.New("no CPU or wall profile series ingested yet") + } + return data, nil +} + +type selectSeriesResponse struct { + Series []struct { + Labels []labelPair `json:"labels"` + Points []struct { + Value float64 `json:"value"` + Timestamp string `json:"timestamp"` + } `json:"points"` + } `json:"series"` +} + +// selectSeries fetches a time series for the given service and profile type and +// returns the number of series and the total number of data points found. +func (e *env) selectSeries(ctx context.Context, host, service, profileType string) (nSeries, nPoints int, err error) { + start, end := nowWindowMillis() + var resp selectSeriesResponse + err = e.pyroscopePost(ctx, host, "querier.v1.QuerierService/SelectSeries", map[string]any{ + "profileTypeID": profileType, + "labelSelector": fmt.Sprintf("{service_name=%q}", service), + "start": start, + "end": end, + "step": 60, + }, &resp) + if err != nil { + return 0, 0, err + } + for _, s := range resp.Series { + nPoints += len(s.Points) + } + return len(resp.Series), nPoints, nil +} + +type flamegraphResponse struct { + Flamegraph struct { + Names []string `json:"names"` + Levels []struct { + Values []json.Number `json:"values"` + } `json:"levels"` + } `json:"flamegraph"` +} + +// selectMergeSpanProfile fetches a span-scoped profile for the given span IDs and +// returns the total number of samples at the root of the flame graph. +func (e *env) selectMergeSpanProfile(ctx context.Context, host, service, profileType string, spanIDs []string) (int64, error) { + start, end := nowWindowMillis() + var resp flamegraphResponse + err := e.pyroscopePost(ctx, host, "querier.v1.QuerierService/SelectMergeSpanProfile", map[string]any{ + "profileTypeID": profileType, + "labelSelector": fmt.Sprintf("{service_name=%q}", service), + "spanSelector": spanIDs, + "start": start, + "end": end, + }, &resp) + if err != nil { + return 0, err + } + if len(resp.Flamegraph.Levels) == 0 || len(resp.Flamegraph.Levels[0].Values) < 2 { + return 0, nil + } + // levels[0].values = [offset, total, self, nameIndex]; index 1 is the total. + total, err := resp.Flamegraph.Levels[0].Values[1].Int64() + if err != nil { + return 0, err + } + return total, nil +} + +// --- Tempo query helpers ----------------------------------------------------- + +type tempoSearchResponse struct { + Traces []struct { + TraceID string `json:"traceID"` + } `json:"traces"` +} + +func (e *env) tempoSearch(ctx context.Context, host string) ([]string, error) { + start := time.Now().Add(-1 * time.Hour).Unix() + end := time.Now().Add(1 * time.Minute).Unix() + url := fmt.Sprintf("http://%s/api/search?start=%d&end=%d&limit=20", host, start, end) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("tempo search returned %d: %s", resp.StatusCode, string(data)) + } + var sr tempoSearchResponse + if err := json.Unmarshal(data, &sr); err != nil { + return nil, err + } + ids := make([]string, 0, len(sr.Traces)) + for _, tr := range sr.Traces { + ids = append(ids, tr.TraceID) + } + return ids, nil +} + +type otlpAttr struct { + Key string `json:"key"` + Value struct { + StringValue string `json:"stringValue"` + } `json:"value"` +} + +type tempoTrace struct { + Batches []struct { + ScopeSpans []struct { + Spans []struct { + Name string `json:"name"` + Attributes []otlpAttr `json:"attributes"` + } `json:"spans"` + } `json:"scopeSpans"` + } `json:"batches"` +} + +const pyroscopeProfileIDAttr = "pyroscope.profile.id" + +// profileIDsFromTrace fetches a trace and returns the values of every +// pyroscope.profile.id span attribute it contains. +func (e *env) profileIDsFromTrace(ctx context.Context, host, traceID string) ([]string, error) { + url := fmt.Sprintf("http://%s/api/traces/%s", host, traceID) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, err + } + req.Header.Set("Accept", "application/json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("tempo trace returned %d: %s", resp.StatusCode, string(data)) + } + var tr tempoTrace + if err := json.Unmarshal(data, &tr); err != nil { + return nil, err + } + var ids []string + for _, b := range tr.Batches { + for _, ss := range b.ScopeSpans { + for _, sp := range ss.Spans { + for _, a := range sp.Attributes { + if a.Key == pyroscopeProfileIDAttr && a.Value.StringValue != "" { + ids = append(ids, a.Value.StringValue) + } + } + } + } + } + return ids, nil +} + +// --- Tests ------------------------------------------------------------------- + +// examplesToTest discovers the docker-compose examples and filters them by the +// PYROSCOPE_TEST_EXAMPLES environment variable (a comma/newline/space separated +// list of repository-relative paths). +func examplesToTest(t *testing.T) []*env { + out, err := exec.Command("git", "ls-files", "**/docker-compose.yml", "**/docker-compose.yaml").Output() + require.NoError(t, err) + + // requested maps each requested path to whether it matched an example. + var requested map[string]bool + if raw := strings.TrimSpace(os.Getenv("PYROSCOPE_TEST_EXAMPLES")); raw != "" { + requested = map[string]bool{} + for _, f := range strings.FieldsFunc(raw, func(r rune) bool { + return r == ',' || r == '\n' || r == ' ' || r == '\t' + }) { + requested[strings.TrimRight(f, "/")] = false + } + } + + var envs []*env + for _, path := range strings.Split(strings.TrimSpace(string(out)), "\n") { + if path == "" { + continue + } + // Skip the _templates directory: its docker-compose files are partial + // (single-service stubs) and are not runnable examples. + if strings.Contains(path, "/_templates/") || strings.HasPrefix(path, "_templates/") { + continue + } + e := &env{dir: filepath.Dir(path), path: path} + if requested != nil { + matched := false + for p := range requested { + if e.repoDir() == p || strings.HasPrefix(e.repoDir(), p+"/") { + requested[p] = true + matched = true + } + } + if !matched { + continue + } + } + envs = append(envs, e) + } + + var unmatched []string + for p, matched := range requested { + if !matched { + unmatched = append(unmatched, p) + } + } + if len(unmatched) > 0 { + sort.Strings(unmatched) + t.Fatalf("PYROSCOPE_TEST_EXAMPLES references unknown example(s): %s", strings.Join(unmatched, ", ")) + } + return envs +} + +// isTracing reports whether the example lives under examples/tracing/. +func (e *env) isTracing() bool { + return strings.HasPrefix(e.repoDir(), filepath.Join("examples", "tracing")+string(filepath.Separator)) +} + +func TestContainerStatusesReady(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + statuses []status + completedSuccessfully map[string]struct{} + wantErr string + }{ + { + name: "running service", + statuses: []status{{Name: "app-1", Service: "app", State: "running"}}, + }, + { + name: "successfully completed init service", + statuses: []status{{Name: "migrate-1", Service: "migrate", State: "exited", ExitCode: 0}}, + completedSuccessfully: map[string]struct{}{"migrate": {}}, + }, + { + name: "failed init service", + statuses: []status{{Name: "migrate-1", Service: "migrate", State: "exited", ExitCode: 1}}, + completedSuccessfully: map[string]struct{}{"migrate": {}}, + wantErr: "container migrate-1 is not ready (service=migrate, state=exited, exit_code=1)", + }, + { + name: "unexpected normal service exit", + statuses: []status{{Name: "app-1", Service: "app", State: "exited", ExitCode: 0}}, + wantErr: "container app-1 is not ready (service=app, state=exited, exit_code=0)", + }, + { + name: "no containers", + wantErr: "no containers found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := containerStatusesReady(tt.statuses, tt.completedSuccessfully) + if tt.wantErr == "" { + require.NoError(t, err) + return + } + require.EqualError(t, err, tt.wantErr) + }) + } +} + +func TestCompletedSuccessfullyServices(t *testing.T) { + t.Parallel() + + services := map[string]interface{}{ + "app": map[string]interface{}{ + "depends_on": map[string]interface{}{ + "db": map[string]interface{}{"condition": "service_started"}, + "migrate": map[string]interface{}{"condition": "service_completed_successfully"}, + }, + }, + "other": map[string]interface{}{ + "depends_on": []interface{}{"db"}, + }, + } + + require.Equal(t, map[string]struct{}{"migrate": {}}, completedSuccessfullyServices(services)) +} + +// TestExamples brings each selected example up once and verifies it: profiles +// are always checked (Series + SelectSeries); tracing examples additionally get +// the trace-to-profile link checked (SelectMergeSpanProfile). +func TestExamples(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + for _, e := range examplesToTest(t) { + e := e + t.Run(e.repoDir(), func(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithTimeout(context.Background(), timeoutPerExample) + defer cancel() + + e := e.prepareCompose(t) + e.bringUp(t, ctx) + e.waitReady(t, ctx) + + pyroHost := "127.0.0.1:" + e.hostPort(t, ctx, pyroscopeService, pyroscopePort) + t.Logf("[%s] all containers ready; pyroscope on %s", e.repoDir(), pyroHost) + + t.Run("profiles", func(t *testing.T) { + e.checkProfilesQueryable(t, ctx, pyroHost) + }) + + if e.isTracing() { + tempoHost := "127.0.0.1:" + e.hostPort(t, ctx, tempoService, tempoPort) + t.Run("trace-link", func(t *testing.T) { + e.checkSpanProfilesQueryable(t, ctx, pyroHost, tempoHost) + }) + } + + require.NoError(t, e.containersReady(ctx), "containers must stay ready through the run") + }) + } +} + +// checkProfilesQueryable verifies profiles are queryable from Pyroscope via the +// Series and SelectSeries APIs. +func (e *env) checkProfilesQueryable(t *testing.T, ctx context.Context, host string) { + dir := e.repoDir() + var summary string + poll(t, ctx, profilesQueryTimeout, func(progress func(string, ...any)) error { + progress("[%s] querying Series for ingested profiles...", dir) + data, err := e.discoverSeries(ctx, host) + if err != nil { + return err + } + progress("[%s] Series found %d service(s): %s; querying SelectSeries...", dir, len(data), strings.Join(sortedKeys(data), ", ")) + for svc, types := range data { + for _, pt := range types { + nSeries, nPoints, err := e.selectSeries(ctx, host, svc, pt) + if err != nil { + return err + } + if nPoints > 0 { + summary = fmt.Sprintf("service=%q profileType=%q -> %d series, %d points (%d service(s) ingesting)", + svc, pt, nSeries, nPoints, len(data)) + return nil + } + progress("[%s] SelectSeries service=%q type=%q -> 0 points (waiting for data)", dir, svc, pt) + } + } + return fmt.Errorf("no data points for any of %d discovered series yet", len(data)) + }) + t.Logf("[%s] PASS profiles queryable via Series+SelectSeries: %s", dir, summary) +} + +// checkSpanProfilesQueryable verifies the trace-to-profile link end to end: a +// trace is found in Tempo, a span carries a pyroscope.profile.id attribute, and +// SelectMergeSpanProfile returns span-scoped profiling data for it. +func (e *env) checkSpanProfilesQueryable(t *testing.T, ctx context.Context, pyroHost, tempoHost string) { + dir := e.repoDir() + var summary string + poll(t, ctx, tracesQueryTimeout, func(progress func(string, ...any)) error { + progress("[%s] querying Series for ingested profiles...", dir) + data, err := e.discoverSeries(ctx, pyroHost) + if err != nil { + return err + } + progress("[%s] Series found %d service(s): %s; searching Tempo for traces...", dir, len(data), strings.Join(sortedKeys(data), ", ")) + + traceIDs, err := e.tempoSearch(ctx, tempoHost) + if err != nil { + return err + } + if len(traceIDs) == 0 { + return errors.New("no traces found in tempo yet") + } + progress("[%s] found %d trace(s); scanning spans for %s attribute...", dir, len(traceIDs), pyroscopeProfileIDAttr) + + var spanIDs []string + for _, id := range traceIDs { + ids, err := e.profileIDsFromTrace(ctx, tempoHost, id) + if err != nil { + return err + } + spanIDs = append(spanIDs, ids...) + } + if len(spanIDs) == 0 { + return fmt.Errorf("found %d traces in tempo but no span carried a %s attribute", len(traceIDs), pyroscopeProfileIDAttr) + } + progress("[%s] found %d span(s) with %s; querying SelectMergeSpanProfile...", dir, len(spanIDs), pyroscopeProfileIDAttr) + + for svc, types := range data { + for _, pt := range types { + total, err := e.selectMergeSpanProfile(ctx, pyroHost, svc, pt, spanIDs) + if err != nil { + return err + } + if total > 0 { + summary = fmt.Sprintf("service=%q profileType=%q -> %d span id(s) from %d trace(s), %d samples", + svc, pt, len(spanIDs), len(traceIDs), total) + return nil + } + progress("[%s] SelectMergeSpanProfile service=%q type=%q -> 0 samples", dir, svc, pt) + } + } + return fmt.Errorf("found %d span ids but SelectMergeSpanProfile returned no samples across %d service(s)", len(spanIDs), len(data)) + }) + t.Logf("[%s] PASS trace->profile link via SelectMergeSpanProfile: %s", dir, summary) +} diff --git a/examples/golang-pgo/Dockerfile b/examples/golang-pgo/Dockerfile index 123889c51b..ff2b8edcd4 100644 --- a/examples/golang-pgo/Dockerfile +++ b/examples/golang-pgo/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21.10 +FROM golang:1.25.12 WORKDIR /go/src/app COPY . . diff --git a/examples/golang-pgo/README.md b/examples/golang-pgo/README.md index b152692d0d..ca442bd38f 100644 --- a/examples/golang-pgo/README.md +++ b/examples/golang-pgo/README.md @@ -28,10 +28,9 @@ Here are the steps needed to use PGO in the Rideshare example application. 3. Extract a profile in pprof format with `profilecli` (see the [Profile CLI documentation](https://grafana.com/docs/pyroscope/latest/ingest-and-analyze-profile-data/profile-cli/#install-profile-cli) for further reference) ```shell - profilecli query merge \ + profilecli query go-pgo \ --query='{service_name="ride-sharing-app"}' \ - --profile-type="process_cpu:cpu:nanoseconds:cpu:nanoseconds" \ - --from="now-5m" \ + --from="now-1h" \ --to="now" \ --output=pprof=./default.pgo ``` diff --git a/examples/golang-pgo/default.pgo b/examples/golang-pgo/default.pgo index b44ac55a1c..bf64dee183 100644 Binary files a/examples/golang-pgo/default.pgo and b/examples/golang-pgo/default.pgo differ diff --git a/examples/golang-pgo/docker-compose.yml b/examples/golang-pgo/docker-compose.yml index 7e850fd1a7..0b22406cdd 100644 --- a/examples/golang-pgo/docker-compose.yml +++ b/examples/golang-pgo/docker-compose.yml @@ -1,15 +1,29 @@ -version: "3" services: rideshare-go: environment: - - REGION=us-east - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - REGION=us-east + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 build: context: . ports: - - '5001:5001' - + - 5001:5001 pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates image: grafana/pyroscope:latest ports: - - '4040:4040' + - 4040:4040 + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/golang-pgo/go.mod b/examples/golang-pgo/go.mod index 732199ad74..df437ae8a0 100644 --- a/examples/golang-pgo/go.mod +++ b/examples/golang-pgo/go.mod @@ -1,40 +1,45 @@ module rideshare -go 1.17 +go 1.25.0 + +toolchain go1.25.12 require ( - github.com/agoda-com/opentelemetry-logs-go v0.4.1 + github.com/agoda-com/opentelemetry-logs-go v0.5.1 github.com/grafana/otel-profiling-go v0.5.1 - github.com/grafana/pyroscope-go v1.1.1 - github.com/stretchr/testify v1.8.4 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 - go.opentelemetry.io/otel v1.21.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.20.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0 - go.opentelemetry.io/otel/sdk v1.21.0 - go.opentelemetry.io/otel/trace v1.21.0 + github.com/grafana/pyroscope-go v1.2.7 + github.com/stretchr/testify v1.11.1 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 ) require ( - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect - github.com/klauspost/compress v1.17.3 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/golang-pgo/go.sum b/examples/golang-pgo/go.sum index 15085cc577..aea49ce9ed 100644 --- a/examples/golang-pgo/go.sum +++ b/examples/golang-pgo/go.sum @@ -1,2195 +1,105 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= -cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= -cloud.google.com/go/accessapproval v1.7.2/go.mod h1:/gShiq9/kK/h8T/eEn1BTzalDvk0mZxJlhfw0p+Xuc0= -cloud.google.com/go/accessapproval v1.7.3/go.mod h1:4l8+pwIxGTNqSf4T3ds8nLO94NQf0W/KnMNuQ9PbnP8= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= -cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= -cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= -cloud.google.com/go/accesscontextmanager v1.8.2/go.mod h1:E6/SCRM30elQJ2PKtFMs2YhfJpZSNcJyejhuzoId4Zk= -cloud.google.com/go/accesscontextmanager v1.8.3/go.mod h1:4i/JkF2JiFbhLnnpnfoTX5vRXfhf9ukhU1ANOTALTOQ= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= -cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= -cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.1/go.mod h1:kY3nIMAVQOK2XDqDPHaOuD9e+FdMA6OOpfBjsvaFSOo= -cloud.google.com/go/aiplatform v1.51.2/go.mod h1:hCqVYB3mY45w99TmetEoe8eCQEwZEp9WHxeZdcv9phw= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= -cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.4/go.mod h1:zZgNCxLCy8b2rKKVfC1YkC2vTrpfZmeRCySM3aUbskA= -cloud.google.com/go/analytics v0.21.5/go.mod h1:BQtOBHWTlJ96axpPPnw5CvGJ6i3Ve/qX2fTxR8qWyr8= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= -cloud.google.com/go/apigateway v1.6.2/go.mod h1:CwMC90nnZElorCW63P2pAYm25AtQrHfuOkbRSHj0bT8= -cloud.google.com/go/apigateway v1.6.3/go.mod h1:k68PXWpEs6BVDTtnLQAyG606Q3mz8pshItwPXjgv44Y= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= -cloud.google.com/go/apigeeconnect v1.6.2/go.mod h1:s6O0CgXT9RgAxlq3DLXvG8riw8PYYbU/v25jqP3Dy18= -cloud.google.com/go/apigeeconnect v1.6.3/go.mod h1:peG0HFQ0si2bN15M6QSjEW/W7Gy3NYkWGz7pFz13cbo= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= -cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= -cloud.google.com/go/apigeeregistry v0.7.2/go.mod h1:9CA2B2+TGsPKtfi3F7/1ncCCsL62NXBRfM6iPoGSM+8= -cloud.google.com/go/apigeeregistry v0.8.1/go.mod h1:MW4ig1N4JZQsXmBSwH4rwpgDonocz7FPBSw6XPGHmYw= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= -cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= -cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= -cloud.google.com/go/appengine v1.8.2/go.mod h1:WMeJV9oZ51pvclqFN2PqHoGnys7rK0rz6s3Mp6yMvDo= -cloud.google.com/go/appengine v1.8.3/go.mod h1:2oUPZ1LVZ5EXi+AF1ihNAF+S8JrzQ3till5m9VQkrsk= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= -cloud.google.com/go/area120 v0.8.2/go.mod h1:a5qfo+x77SRLXnCynFWPUZhnZGeSgvQ+Y0v1kSItkh4= -cloud.google.com/go/area120 v0.8.3/go.mod h1:5zj6pMzVTH+SVHljdSKC35sriR/CVvQZzG/Icdyriw0= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= -cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= -cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= -cloud.google.com/go/artifactregistry v1.14.2/go.mod h1:Xk+QbsKEb0ElmyeMfdHAey41B+qBq3q5R5f5xD4XT3U= -cloud.google.com/go/artifactregistry v1.14.3/go.mod h1:A2/E9GXnsyXl7GUvQ/2CjHA+mVRoWAXC0brg2os+kNI= -cloud.google.com/go/artifactregistry v1.14.4/go.mod h1:SJJcZTMv6ce0LDMUnihCN7WSrI+kBSFV0KIKo8S8aYU= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= -cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= -cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= -cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+okxFECHcg= -cloud.google.com/go/asset v1.15.1/go.mod h1:yX/amTvFWRpp5rcFq6XbCxzKT8RJUam1UoboE179jU4= -cloud.google.com/go/asset v1.15.2/go.mod h1:B6H5tclkXvXz7PD22qCA2TDxSVQfasa3iDlM89O2NXs= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/assuredworkloads v1.11.2/go.mod h1:O1dfr+oZJMlE6mw0Bp0P1KZSlj5SghMBvTpZqIcUAW4= -cloud.google.com/go/assuredworkloads v1.11.3/go.mod h1:vEjfTKYyRUaIeA0bsGJceFV2JKpVRgyG2op3jfa59Zs= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= -cloud.google.com/go/automl v1.13.2/go.mod h1:gNY/fUmDEN40sP8amAX3MaXkxcqPIn7F1UIIPZpy4Mg= -cloud.google.com/go/automl v1.13.3/go.mod h1:Y8KwvyAZFOsMAPqUCfNu1AyclbC6ivCUF/MTwORymyY= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= -cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= -cloud.google.com/go/baremetalsolution v1.2.1/go.mod h1:3qKpKIw12RPXStwQXcbhfxVj1dqQGEvcmA+SX/mUR88= -cloud.google.com/go/baremetalsolution v1.2.2/go.mod h1:O5V6Uu1vzVelYahKfwEWRMaS3AbCkeYHy3145s1FkhM= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= -cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.1/go.mod h1:RpBuIYLkQu8+CWDk3dFD/t/jOCGuUpkpX+Y0n1Xccs8= -cloud.google.com/go/batch v1.6.1/go.mod h1:urdpD13zPe6YOK+6iZs/8/x2VBRofvblLpx0t57vM98= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= -cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= -cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.1/go.mod h1:zl/rWWAFVeV+kx+X2Javly7o1EIQThU4WlkynffL/lk= -cloud.google.com/go/beyondcorp v1.0.2/go.mod h1:m8cpG7caD+5su+1eZr+TSvF6r21NdLJk4f9u4SP2Ntc= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= -cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= -cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= -cloud.google.com/go/bigquery v1.56.0/go.mod h1:KDcsploXTEY7XT3fDQzMUZlpQLHzE4itubHrnmhUrZA= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= -cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= -cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.2/go.mod h1:u/AdV/3wr3xoRBk5xvUzYMS1IawOAPwQMuHgHMdljDg= -cloud.google.com/go/billing v1.17.3/go.mod h1:z83AkoZ7mZwBGT3yTnt6rSGI1OOsHSIi6a5M3mJ8NaU= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= -cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= -cloud.google.com/go/binaryauthorization v1.7.1/go.mod h1:GTAyfRWYgcbsP3NJogpV3yeunbUIjx2T9xVeYovtURE= -cloud.google.com/go/binaryauthorization v1.7.2/go.mod h1:kFK5fQtxEp97m92ziy+hbu+uKocka1qRRL8MVJIgjv0= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= -cloud.google.com/go/certificatemanager v1.7.2/go.mod h1:15SYTDQMd00kdoW0+XY5d9e+JbOPjp24AvF48D8BbcQ= -cloud.google.com/go/certificatemanager v1.7.3/go.mod h1:T/sZYuC30PTag0TLo28VedIRIj1KPGcOQzjWAptHa00= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= -cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= -cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= -cloud.google.com/go/channel v1.17.1/go.mod h1:xqfzcOZAcP4b/hUDH0GkGg1Sd5to6di1HOJn/pi5uBQ= -cloud.google.com/go/channel v1.17.2/go.mod h1:aT2LhnftnyfQceFql5I/mP8mIbiiJS4lWqgXA815zMk= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= -cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.1/go.mod h1:K7wGc/3zfvmYWOWwYTgF/d/UVJhS4pu+HAy7PL7mCsU= -cloud.google.com/go/cloudbuild v1.14.2/go.mod h1:Bn6RO0mBYk8Vlrt+8NLrru7WXlQ9/RDWz2uo5KG1/sg= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= -cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= -cloud.google.com/go/clouddms v1.7.1/go.mod h1:o4SR8U95+P7gZ/TX+YbJxehOCsM+fe6/brlrFquiszk= -cloud.google.com/go/clouddms v1.7.2/go.mod h1:Rk32TmWmHo64XqDvW7jgkFQet1tUKNVzs7oajtJT3jU= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= -cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.2/go.mod h1:A7nYkjNlW2gUoROg1kvJrQGhJP/38UaWwsnuBDOBVUk= -cloud.google.com/go/cloudtasks v1.12.3/go.mod h1:GPVXhIOSGEaR+3xT4Fp72ScI+HjHffSS4B8+BaBB5Ys= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJKSFOnQruhC5Lj9bZqWMTKiU= -cloud.google.com/go/contactcenterinsights v1.11.1/go.mod h1:FeNP3Kg8iteKM80lMwSk3zZZKVxr+PGnAId6soKuXwE= -cloud.google.com/go/contactcenterinsights v1.11.2/go.mod h1:A9PIR5ov5cRcd28KlDbmmXE8Aay+Gccer2h4wzkYFso= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= -cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= -cloud.google.com/go/container v1.26.1/go.mod h1:5smONjPRUxeEpDG7bMKWfDL4sauswqEtnBK1/KKpR04= -cloud.google.com/go/container v1.26.2/go.mod h1:YlO84xCt5xupVbLaMY4s3XNE79MUJ+49VmkInr6HvF4= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= -cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= -cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= -cloud.google.com/go/containeranalysis v0.11.1/go.mod h1:rYlUOM7nem1OJMKwE1SadufX0JP3wnXj844EtZAwWLY= -cloud.google.com/go/containeranalysis v0.11.2/go.mod h1:xibioGBC1MD2j4reTyV1xY1/MvKaz+fyM9ENWhmIeP8= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= -cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= -cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.1/go.mod h1:TzAWaz+ON1tkNr4MOcak8EBHX7wIRX/gZKM+yTVsv+A= -cloud.google.com/go/datacatalog v1.18.2/go.mod h1:SPVgWW2WEMuWHA+fHodYjmxPiMqcOiWfhc9OD5msigk= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= -cloud.google.com/go/dataflow v0.9.2/go.mod h1:vBfdBZ/ejlTaYIGB3zB4T08UshH70vbtZeMD+urnUSo= -cloud.google.com/go/dataflow v0.9.3/go.mod h1:HI4kMVjcHGTs3jTHW/kv3501YW+eloiJSLxkJa/vqFE= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= -cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= -cloud.google.com/go/dataform v0.8.2/go.mod h1:X9RIqDs6NbGPLR80tnYoPNiO1w0wenKTb8PxxlhTMKM= -cloud.google.com/go/dataform v0.8.3/go.mod h1:8nI/tvv5Fso0drO3pEjtowz58lodx8MVkdV2q0aPlqg= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= -cloud.google.com/go/datafusion v1.7.2/go.mod h1:62K2NEC6DRlpNmI43WHMWf9Vg/YvN6QVi8EVwifElI0= -cloud.google.com/go/datafusion v1.7.3/go.mod h1:eoLt1uFXKGBq48jy9LZ+Is8EAVLnmn50lNncLzwYokE= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= -cloud.google.com/go/datalabeling v0.8.2/go.mod h1:cyDvGHuJWu9U/cLDA7d8sb9a0tWLEletStu2sTmg3BE= -cloud.google.com/go/datalabeling v0.8.3/go.mod h1:tvPhpGyS/V7lqjmb3V0TaDdGvhzgR1JoW7G2bpi2UTI= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= -cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.10.1/go.mod h1:1MzmBv8FvjYfc7vDdxhnLFNskikkB+3vl475/XdCDhs= -cloud.google.com/go/dataplex v1.10.2/go.mod h1:xdC8URdTrCrZMW6keY779ZT1cTOfV8KEPNsw+LTRT1Y= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= -cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= -cloud.google.com/go/dataproc/v2 v2.2.1/go.mod h1:QdAJLaBjh+l4PVlVZcmrmhGccosY/omC1qwfQ61Zv/o= -cloud.google.com/go/dataproc/v2 v2.2.2/go.mod h1:aocQywVmQVF4i8CL740rNI/ZRpsaaC1Wh2++BJ7HEJ4= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= -cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= -cloud.google.com/go/dataqna v0.8.2/go.mod h1:KNEqgx8TTmUipnQsScOoDpq/VlXVptUqVMZnt30WAPs= -cloud.google.com/go/dataqna v0.8.3/go.mod h1:wXNBW2uvc9e7Gl5k8adyAMnLush1KVV6lZUhB+rqNu4= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= -cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= -cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.1/go.mod h1:7ngSYwnw95YFyTd5tOGBxHlOZiL+OtpjheqU7t2/s/c= -cloud.google.com/go/datastream v1.10.2/go.mod h1:W42TFgKAs/om6x/CdXX5E4oiAsKlH+e8MTGy81zdYt0= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= -cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.1/go.mod h1:8jeadyLkH9qu9xgO3hVWw8jVr29N1mnW42gRJT8GY6g= -cloud.google.com/go/deploy v1.14.1/go.mod h1:N8S0b+aIHSEeSr5ORVoC0+/mOPUysVt8ae4QkZYolAw= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= -cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.1/go.mod h1:n/h+/N2ouKOO+rbe/ZnI186xImpqvCVj2DdsWS/0EAk= -cloud.google.com/go/dialogflow v1.44.2/go.mod h1:QzFYndeJhpVPElnFkUXxdlptx0wPnBWLCBT9BvtC3/c= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= -cloud.google.com/go/dlp v1.10.2/go.mod h1:ZbdKIhcnyhILgccwVDzkwqybthh7+MplGC3kZVZsIOQ= -cloud.google.com/go/dlp v1.10.3/go.mod h1:iUaTc/ln8I+QT6Ai5vmuwfw8fqTk2kaz0FvCwhLCom0= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= -cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.2/go.mod h1:Q/wcRT+qnuXOpjAkvOV4A+IeQl04q2/ReT7SSbytLSo= -cloud.google.com/go/documentai v1.23.4/go.mod h1:4MYAaEMnADPN1LPN5xboDR5QVB6AgsaxgFdJhitlE2Y= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= -cloud.google.com/go/domains v0.9.2/go.mod h1:3YvXGYzZG1Temjbk7EyGCuGGiXHJwVNmwIf+E/cUp5I= -cloud.google.com/go/domains v0.9.3/go.mod h1:29k66YNDLDY9LCFKpGFeh6Nj9r62ZKm5EsUJxAl84KU= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= -cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= -cloud.google.com/go/edgecontainer v1.1.2/go.mod h1:wQRjIzqxEs9e9wrtle4hQPSR1Y51kqN75dgF7UllZZ4= -cloud.google.com/go/edgecontainer v1.1.3/go.mod h1:Ll2DtIABzEfaxaVSbwj3QHFaOOovlDFiWVDu349jSsA= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= -cloud.google.com/go/essentialcontacts v1.6.3/go.mod h1:yiPCD7f2TkP82oJEFXFTou8Jl8L6LBRPeBEkTaO0Ggo= -cloud.google.com/go/essentialcontacts v1.6.4/go.mod h1:iju5Vy3d9tJUg0PYMd1nHhjV7xoCXaOAVabrwLaPBEM= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= -cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.1/go.mod h1:EqBxmGHFrruIara4FUQ3RHlgfCn7yo1HYsu2Hpt/C3Y= -cloud.google.com/go/eventarc v1.13.2/go.mod h1:X9A80ShVu19fb4e5sc/OLV7mpFUKZMwfJFeeWhcIObM= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= -cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= -cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= -cloud.google.com/go/filestore v1.7.2/go.mod h1:TYOlyJs25f/omgj+vY7/tIG/E7BX369triSPzE4LdgE= -cloud.google.com/go/filestore v1.7.3/go.mod h1:Qp8WaEERR3cSkxToxFPHh/b8AACkSut+4qlCjAmKTV0= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.12.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= -cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= -cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= -cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= -cloud.google.com/go/functions v1.15.2/go.mod h1:CHAjtcR6OU4XF2HuiVeriEdELNcnvRZSk1Q8RMqy4lE= -cloud.google.com/go/functions v1.15.3/go.mod h1:r/AMHwBheapkkySEhiZYLDBwVJCdlRwsm4ieJu35/Ug= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.2/go.mod h1:OMZbXzEJloyXMC7gqdSB+EOEQ1AKcpGYvO3s1ec5ixk= -cloud.google.com/go/gkebackup v1.3.3/go.mod h1:eMk7/wVV5P22KBakhQnJxWSVftL1p4VBFLpv0kIft7I= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= -cloud.google.com/go/gkeconnect v0.8.2/go.mod h1:6nAVhwchBJYgQCXD2pHBFQNiJNyAd/wyxljpaa6ZPrY= -cloud.google.com/go/gkeconnect v0.8.3/go.mod h1:i9GDTrfzBSUZGCe98qSu1B8YB8qfapT57PenIb820Jo= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= -cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= -cloud.google.com/go/gkehub v0.14.2/go.mod h1:iyjYH23XzAxSdhrbmfoQdePnlMj2EWcvnR+tHdBQsCY= -cloud.google.com/go/gkehub v0.14.3/go.mod h1:jAl6WafkHHW18qgq7kqcrXYzN08hXeK/Va3utN8VKg8= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.1/go.mod h1:AcrGoin6VLKT/fwZEYuqvVominLriQBCKmbjtnbMjG8= -cloud.google.com/go/gkemulticloud v1.0.2/go.mod h1:+ee5VXxKb3H1l4LZAcgWB/rvI16VTNTrInWxDjAGsGo= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= -cloud.google.com/go/gsuiteaddons v1.6.2/go.mod h1:K65m9XSgs8hTF3X9nNTPi8IQueljSdYo9F+Mi+s4MyU= -cloud.google.com/go/gsuiteaddons v1.6.3/go.mod h1:sCFJkZoMrLZT3JTb8uJqgKPNshH2tfXeCwTFRebTq48= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= -cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= -cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= -cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= -cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= -cloud.google.com/go/iap v1.9.1/go.mod h1:SIAkY7cGMLohLSdBR25BuIxO+I4fXJiL06IBL7cy/5Q= -cloud.google.com/go/iap v1.9.2/go.mod h1:GwDTOs047PPSnwRD0Us5FKf4WDRcVvHg1q9WVkKBhdI= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= -cloud.google.com/go/ids v1.4.2/go.mod h1:3vw8DX6YddRu9BncxuzMyWn0g8+ooUjI2gslJ7FH3vk= -cloud.google.com/go/ids v1.4.3/go.mod h1:9CXPqI3GedjmkjbMWCUhMZ2P2N7TUMzAkVXYEH2orYU= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= -cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= -cloud.google.com/go/iot v1.7.2/go.mod h1:q+0P5zr1wRFpw7/MOgDXrG/HVA+l+cSwdObffkrpnSg= -cloud.google.com/go/iot v1.7.3/go.mod h1:t8itFchkol4VgNbHnIq9lXoOOtHNR3uAACQMYbN9N4I= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= -cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= -cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= -cloud.google.com/go/kms v1.15.3/go.mod h1:AJdXqHxS2GlPyduM99s9iGqi2nwbviBbhV/hdmt4iOQ= -cloud.google.com/go/kms v1.15.4/go.mod h1:L3Sdj6QTHK8dfwK5D1JLsAyELsNMnd3tAIwGS4ltKpc= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= -cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= -cloud.google.com/go/language v1.11.1/go.mod h1:Xyid9MG9WOX3utvDbpX7j3tXDmmDooMyMDqgUVpH17U= -cloud.google.com/go/language v1.12.1/go.mod h1:zQhalE2QlQIxbKIZt54IASBzmZpN/aDASea5zl1l+J4= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= -cloud.google.com/go/lifesciences v0.9.2/go.mod h1:QHEOO4tDzcSAzeJg7s2qwnLM2ji8IRpQl4p6m5Z9yTA= -cloud.google.com/go/lifesciences v0.9.3/go.mod h1:gNGBOJV80IWZdkd+xz4GQj4mbqaz737SCLHn2aRhQKM= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= -cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= -cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= -cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= -cloud.google.com/go/longrunning v0.5.3/go.mod h1:y/0ga59EYu58J6SHmmQOvekvND2qODbu8ywBBW7EK7Y= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= -cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8= -cloud.google.com/go/managedidentities v1.6.3/go.mod h1:tewiat9WLyFN0Fi7q1fDD5+0N4VUoL0SCX0OTCthZq4= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= -cloud.google.com/go/maps v1.3.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.1/go.mod h1:BxSa0BnW1g2U2gNdbq5zikLlHUuHW0GFWh7sgML2kIY= -cloud.google.com/go/maps v1.5.1/go.mod h1:NPMZw1LJwQZYCfz4y+EIw+SI+24A4bpdFJqdKVr0lt4= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= -cloud.google.com/go/mediatranslation v0.8.2/go.mod h1:c9pUaDRLkgHRx3irYE5ZC8tfXGrMYwNZdmDqKMSfFp8= -cloud.google.com/go/mediatranslation v0.8.3/go.mod h1:F9OnXTy336rteOEywtY7FOqCk+J43o2RF638hkOQl4Y= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= -cloud.google.com/go/memcache v1.10.2/go.mod h1:f9ZzJHLBrmd4BkguIAa/l/Vle6uTHzHokdnzSWOdQ6A= -cloud.google.com/go/memcache v1.10.3/go.mod h1:6z89A41MT2DVAW0P4iIRdu5cmRTsbsFn4cyiIx8gbwo= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.13.0/go.mod h1:URDhpG6XLeh5K+Glq0NOt74OfrPKTwS62gEPZzb5SOk= -cloud.google.com/go/metastore v1.13.1/go.mod h1:IbF62JLxuZmhItCppcIfzBBfUFq0DIB9HPDoLgWrVOU= -cloud.google.com/go/metastore v1.13.2/go.mod h1:KS59dD+unBji/kFebVp8XU/quNSyo8b6N6tPGspKszA= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= -cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= -cloud.google.com/go/monitoring v1.16.1/go.mod h1:6HsxddR+3y9j+o/cMJH6q/KJ/CBTvM/38L/1m7bTRJ4= -cloud.google.com/go/monitoring v1.16.2/go.mod h1:B44KGwi4ZCF8Rk/5n+FWeispDXoKSk9oss2QNlXJBgc= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= -cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= -cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.1/go.mod h1:LyGPXR742uQcDxZ/wv4EI0Vu5N6NKJ77ZYVnDe69Zug= -cloud.google.com/go/networkconnectivity v1.14.2/go.mod h1:5UFlwIisZylSkGG1AdwK/WZUaoz12PKu6wODwIbFzJo= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= -cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= -cloud.google.com/go/networkmanagement v1.9.1/go.mod h1:CCSYgrQQvW73EJawO2QamemYcOb57LvrDdDU51F0mcI= -cloud.google.com/go/networkmanagement v1.9.2/go.mod h1:iDGvGzAoYRghhp4j2Cji7sF899GnfGQcQRQwgVOWnDw= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= -cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= -cloud.google.com/go/networksecurity v0.9.2/go.mod h1:jG0SeAttWzPMUILEHDUvFYdQTl8L/E/KC8iZDj85lEI= -cloud.google.com/go/networksecurity v0.9.3/go.mod h1:l+C0ynM6P+KV9YjOnx+kk5IZqMSLccdBqW6GUoF4p/0= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= -cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= -cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= -cloud.google.com/go/notebooks v1.10.1/go.mod h1:5PdJc2SgAybE76kFQCWrTfJolCOUQXF97e+gteUUA6A= -cloud.google.com/go/notebooks v1.11.1/go.mod h1:V2Zkv8wX9kDCGRJqYoI+bQAaoVeE5kSiz4yYHd2yJwQ= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= -cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= -cloud.google.com/go/optimization v1.5.1/go.mod h1:NC0gnUD5MWVAF7XLdoYVPmYYVth93Q6BUzqAq3ZwtV8= -cloud.google.com/go/optimization v1.6.1/go.mod h1:hH2RYPTTM9e9zOiTaYPTiGPcGdNZVnBSBxjIAJzUkqo= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= -cloud.google.com/go/orchestration v1.8.2/go.mod h1:T1cP+6WyTmh6LSZzeUhvGf0uZVmJyTx7t8z7Vg87+A0= -cloud.google.com/go/orchestration v1.8.3/go.mod h1:xhgWAYqlbYjlz2ftbFghdyqENYW+JXuhBx9KsjMoGHs= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= -cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= -cloud.google.com/go/orgpolicy v1.11.2/go.mod h1:biRDpNwfyytYnmCRWZWxrKF22Nkz9eNVj9zyaBdpm1o= -cloud.google.com/go/orgpolicy v1.11.3/go.mod h1:oKAtJ/gkMjum5icv2aujkP4CxROxPXsBbYGCDbPO8MM= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= -cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= -cloud.google.com/go/osconfig v1.12.2/go.mod h1:eh9GPaMZpI6mEJEuhEjUJmaxvQ3gav+fFEJon1Y8Iw0= -cloud.google.com/go/osconfig v1.12.3/go.mod h1:L/fPS8LL6bEYUi1au832WtMnPeQNT94Zo3FwwV1/xGM= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= -cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3xlOxaboXE= -cloud.google.com/go/oslogin v1.11.1/go.mod h1:OhD2icArCVNUxKqtK0mcSmKL7lgr0LVlQz+v9s1ujTg= -cloud.google.com/go/oslogin v1.12.1/go.mod h1:VfwTeFJGbnakxAY236eN8fsnglLiVXndlbcNomY4iZU= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= -cloud.google.com/go/phishingprotection v0.8.2/go.mod h1:LhJ91uyVHEYKSKcMGhOa14zMMWfbEdxG032oT6ECbC8= -cloud.google.com/go/phishingprotection v0.8.3/go.mod h1:3B01yO7T2Ra/TMojifn8EoGd4G9jts/6cIO0DgDY9J8= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= -cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= -cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= -cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= -cloud.google.com/go/policytroubleshooter v1.9.1/go.mod h1:MYI8i0bCrL8cW+VHN1PoiBTyNZTstCg2WUw2eVC4c4U= -cloud.google.com/go/policytroubleshooter v1.10.1/go.mod h1:5C0rhT3TDZVxAu8813bwmTvd57Phbl8mr9F4ipOsxEs= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= -cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= -cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= -cloud.google.com/go/privatecatalog v0.9.2/go.mod h1:RMA4ATa8IXfzvjrhhK8J6H4wwcztab+oZph3c6WmtFc= -cloud.google.com/go/privatecatalog v0.9.3/go.mod h1:K5pn2GrVmOPjXz3T26mzwXLcKivfIJ9R5N79AFCF9UE= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= -cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3XuJyNsjEqMlMzg3v3scCJ46c= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.1/go.mod h1:JZYZJOeZjgSSTGP4uz7NlQ4/d1w5hGmksVgM0lbEij0= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.2/go.mod h1:kpaDBOpkwD4G0GVMzG1W6Doy1tFFC97XAV3xy+Rd/pw= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= -cloud.google.com/go/recommendationengine v0.8.2/go.mod h1:QIybYHPK58qir9CV2ix/re/M//Ty10OxjnnhWdaKS1Y= -cloud.google.com/go/recommendationengine v0.8.3/go.mod h1:m3b0RZV02BnODE9FeSvGv1qibFo8g0OnmB/RMwYy4V8= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= -cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= -cloud.google.com/go/recommender v1.11.1/go.mod h1:sGwFFAyI57v2Hc5LbIj+lTwXipGu9NW015rkaEM5B18= -cloud.google.com/go/recommender v1.11.2/go.mod h1:AeoJuzOvFR/emIcXdVFkspVXVTYpliRCmKNYDnyBv6Y= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= -cloud.google.com/go/redis v1.13.2/go.mod h1:0Hg7pCMXS9uz02q+LoEVl5dNHUkIQv+C/3L76fandSA= -cloud.google.com/go/redis v1.13.3/go.mod h1:vbUpCKUAZSYzFcWKmICnYgRAhTFg9r+djWqFxDYXi4U= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= -cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= -cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= -cloud.google.com/go/resourcemanager v1.9.2/go.mod h1:OujkBg1UZg5lX2yIyMo5Vz9O5hf7XQOSV7WxqxxMtQE= -cloud.google.com/go/resourcemanager v1.9.3/go.mod h1:IqrY+g0ZgLsihcfcmqSe+RKp1hzjXwG904B92AwBz6U= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= -cloud.google.com/go/resourcesettings v1.6.2/go.mod h1:mJIEDd9MobzunWMeniaMp6tzg4I2GvD3TTmPkc8vBXk= -cloud.google.com/go/resourcesettings v1.6.3/go.mod h1:pno5D+7oDYkMWZ5BpPsb4SO0ewg3IXcmmrUZaMJrFic= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= -cloud.google.com/go/retail v1.14.2/go.mod h1:W7rrNRChAEChX336QF7bnMxbsjugcOCPU44i5kbLiL8= -cloud.google.com/go/retail v1.14.3/go.mod h1:Omz2akDHeSlfCq8ArPKiBxlnRpKEBjUH386JYFLUvXo= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= -cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= -cloud.google.com/go/run v1.3.0/go.mod h1:S/osX/4jIPZGg+ssuqh6GNgg7syixKe3YnprwehzHKU= -cloud.google.com/go/run v1.3.1/go.mod h1:cymddtZOzdwLIAsmS6s+Asl4JoXIDm/K1cpZTxV4Q5s= -cloud.google.com/go/run v1.3.2/go.mod h1:SIhmqArbjdU/D9M6JoHaAqnAMKLFtXaVdNeq04NjnVE= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= -cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= -cloud.google.com/go/scheduler v1.10.2/go.mod h1:O3jX6HRH5eKCA3FutMw375XHZJudNIKVonSCHv7ropY= -cloud.google.com/go/scheduler v1.10.3/go.mod h1:8ANskEM33+sIbpJ+R4xRfw/jzOG+ZFE8WVLy7/yGvbc= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= -cloud.google.com/go/secretmanager v1.11.2/go.mod h1:MQm4t3deoSub7+WNwiC4/tRYgDBHJgJPvswqQVB1Vss= -cloud.google.com/go/secretmanager v1.11.3/go.mod h1:0bA2o6FabmShrEy328i67aV+65XoUFFSmVeLBn/51jI= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= -cloud.google.com/go/security v1.15.2/go.mod h1:2GVE/v1oixIRHDaClVbHuPcZwAqFM28mXuAKCfMgYIg= -cloud.google.com/go/security v1.15.3/go.mod h1:gQ/7Q2JYUZZgOzqKtw9McShH+MjNvtDpL40J1cT+vBs= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= -cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= -cloud.google.com/go/securitycenter v1.23.1/go.mod h1:w2HV3Mv/yKhbXKwOCu2i8bCuLtNP1IMHuiYQn4HJq5s= -cloud.google.com/go/securitycenter v1.24.1/go.mod h1:3h9IdjjHhVMXdQnmqzVnM7b0wMn/1O/U20eWVpMpZjI= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= -cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.1/go.mod h1:tJywXimEWzNzw9FvtNjsQxxJ3/41jseeILgwU/QLrGI= -cloud.google.com/go/servicedirectory v1.11.2/go.mod h1:KD9hCLhncWRV5jJphwIpugKwM5bn1x0GyVVD4NO8mGg= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= -cloud.google.com/go/shell v1.7.2/go.mod h1:KqRPKwBV0UyLickMn0+BY1qIyE98kKyI216sH/TuHmc= -cloud.google.com/go/shell v1.7.3/go.mod h1:cTTEz/JdaBsQAeTQ3B6HHldZudFoYBOqjteev07FbIc= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= -cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.50.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.51.0/go.mod h1:c5KNo5LQ1X5tJwma9rSQZsXNBDNvj4/n8BVc3LNahq0= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= -cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= -cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.1/go.mod h1:WcuaWz/3hOlzPFOVo9DUsblMIHwxP589y6ZMtaG+iAA= -cloud.google.com/go/speech v1.19.2/go.mod h1:2OYFfj+Ch5LWjsaSINuCZsre/789zlcCI3SY4oAi2oI= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= -cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= -cloud.google.com/go/storagetransfer v1.10.1/go.mod h1:rS7Sy0BtPviWYTTJVWCSV4QrbBitgPeuK4/FKa4IdLs= -cloud.google.com/go/storagetransfer v1.10.2/go.mod h1:meIhYQup5rg9juQJdyppnA/WLQCOguxtk1pr3/vBWzA= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= -cloud.google.com/go/talent v1.6.3/go.mod h1:xoDO97Qd4AK43rGjJvyBHMskiEf3KulgYzcH6YWOVoo= -cloud.google.com/go/talent v1.6.4/go.mod h1:QsWvi5eKeh6gG2DlBkpMaFYZYrYUnIpo34f6/V5QykY= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= -cloud.google.com/go/texttospeech v1.7.2/go.mod h1:VYPT6aTOEl3herQjFHYErTlSZJ4vB00Q2ZTmuVgluD4= -cloud.google.com/go/texttospeech v1.7.3/go.mod h1:Av/zpkcgWfXlDLRYob17lqMstGZ3GqlvJXqKMp2u8so= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= -cloud.google.com/go/tpu v1.6.2/go.mod h1:NXh3NDwt71TsPZdtGWgAG5ThDfGd32X1mJ2cMaRlVgU= -cloud.google.com/go/tpu v1.6.3/go.mod h1:lxiueqfVMlSToZY1151IaZqp89ELPSrk+3HIQ5HRkbY= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= -cloud.google.com/go/trace v1.10.2/go.mod h1:NPXemMi6MToRFcSxRl2uDnu/qAlAQ3oULUphcHGh1vA= -cloud.google.com/go/trace v1.10.3/go.mod h1:Ke1bgfc73RV3wUFml+uQp7EsDw4dGaETLxB7Iq/r4CY= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.1/go.mod h1:TWIgDZknq2+JD4iRcojgeDtqGEp154HN/uL6hMvylS8= -cloud.google.com/go/translate v1.9.2/go.mod h1:E3Tc6rUTsQkVrXW6avbUhKJSr7ZE3j7zNmqzXKHqRrY= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= -cloud.google.com/go/video v1.20.1/go.mod h1:3gJS+iDprnj8SY6pe0SwLeC5BUW80NjhwX7INWEuWGU= -cloud.google.com/go/video v1.20.2/go.mod h1:lrixr5JeKNThsgfM9gqtwb6Okuqzfo4VrY2xynaViTA= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= -cloud.google.com/go/videointelligence v1.11.2/go.mod h1:ocfIGYtIVmIcWk1DsSGOoDiXca4vaZQII1C85qtoplc= -cloud.google.com/go/videointelligence v1.11.3/go.mod h1:tf0NUaGTjU1iS2KEkGWvO5hRHeCkFK3nPo0/cOZhZAo= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= -cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= -cloud.google.com/go/vision/v2 v2.7.3/go.mod h1:V0IcLCY7W+hpMKXK1JYE0LV5llEqVmj+UJChjvA1WsM= -cloud.google.com/go/vision/v2 v2.7.4/go.mod h1:ynDKnsDN/0RtqkKxQZ2iatv3Dm9O+HfRb5djl7l4Vvw= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= -cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= -cloud.google.com/go/vmmigration v1.7.2/go.mod h1:iA2hVj22sm2LLYXGPT1pB63mXHhrH1m/ruux9TwWLd8= -cloud.google.com/go/vmmigration v1.7.3/go.mod h1:ZCQC7cENwmSWlwyTrZcWivchn78YnFniEQYRWQ65tBo= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= -cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.1/go.mod h1:aT3Xsm5sNx0QShk1Jc1B8OddrxAScYLwzVoaiXfdzzk= -cloud.google.com/go/vmwareengine v1.0.2/go.mod h1:xMSNjIk8/itYrz1JA8nV3Ajg4L4n3N+ugP8JKzk3OaA= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= -cloud.google.com/go/vpcaccess v1.7.2/go.mod h1:mmg/MnRHv+3e8FJUjeSibVFvQF1cCy2MsFaFqxeY1HU= -cloud.google.com/go/vpcaccess v1.7.3/go.mod h1:YX4skyfW3NC8vI3Fk+EegJnlYFatA+dXK4o236EUCUc= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= -cloud.google.com/go/webrisk v1.9.2/go.mod h1:pY9kfDgAqxUpDBOrG4w8deLfhvJmejKB0qd/5uQIPBc= -cloud.google.com/go/webrisk v1.9.3/go.mod h1:RUYXe9X/wBDXhVilss7EDLW9ZNa06aowPuinUOPCXH8= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= -cloud.google.com/go/websecurityscanner v1.6.2/go.mod h1:7YgjuU5tun7Eg2kpKgGnDuEOXWIrh8x8lWrJT4zfmas= -cloud.google.com/go/websecurityscanner v1.6.3/go.mod h1:x9XANObUFR+83Cya3g/B9M/yoHVqzxPnFtgF8yYGAXw= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= -cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= -cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCwLM1P1tBRGHM= -cloud.google.com/go/workflows v1.12.2/go.mod h1:+OmBIgNqYJPVggnMo9nqmizW0qEXHhmnAzK/CnBqsHc= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/agoda-com/opentelemetry-logs-go v0.4.1 h1:PWGqIxkEEg4HIjnHsHmNa+yGu0lhxHz4XPGKeT4o6T0= -github.com/agoda-com/opentelemetry-logs-go v0.4.1/go.mod h1:CeDuVaK9yCWN+8UjOW8AciYJE0rl7K/mw4ejBntGYkc= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= -github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/agoda-com/opentelemetry-logs-go v0.5.1 h1:6iQrLaY4M0glBZb/xVN559qQutK4V+HJ/mB1cbwaX3c= +github.com/agoda-com/opentelemetry-logs-go v0.5.1/go.mod h1:35B5ypjX5pkVCPJR01i6owJSYWe8cnbWLpEyHgAGD/E= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-pkcs11 v0.2.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= -github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= -github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ= -github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88= -github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo= -github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA= -github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= +github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= -github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 h1:KfYpVmrjI7JuToy5k8XV3nkapjWx48k4E4JOtVstzQI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48= -go.opentelemetry.io/otel v1.18.0/go.mod h1:9lWqYO0Db579XzVuCKFNPDl4s73Voa+zEck3wHaAYQI= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.20.0 h1:CsBiKCiQPdSjS+MlRiqeTI9JDDpSuk0Hb6QTRfwer8k= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.20.0/go.mod h1:CMJYNAfooOwSZSAmAeMUV1M+TXld3BiK++z9fqIm2xk= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0 h1:4s9HxB4azeeQkhY0GE5wZlMj4/pz8tE5gx2OQpGUw58= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0/go.mod h1:djVA3TUJ2fSdMX0JE5XxFBOaZzprElJoP7fD4vnV2SU= -go.opentelemetry.io/otel/metric v1.18.0/go.mod h1:nNSpsVDjWGfb7chbRLUNW+PBNdcSTHD4Uu5pfFMOI0k= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= -go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.18.0/go.mod h1:T2+SGJGuYZY3bjj5rgh/hN7KIrlpWC5nS8Mjvzckz+0= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= -google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= -google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= -google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= -google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20230821184602-ccc8af3d0e93/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= -modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= -modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/examples/golang-pgo/go.work b/examples/golang-pgo/go.work index 6da44691e9..a860ee362f 100644 --- a/examples/golang-pgo/go.work +++ b/examples/golang-pgo/go.work @@ -1,5 +1,3 @@ -go 1.19 +go 1.25.0 -use ( - . -) +use . diff --git a/examples/golang-pgo/go.work.sum b/examples/golang-pgo/go.work.sum index 17fedccdc6..2b5c0c9313 100644 --- a/examples/golang-pgo/go.work.sum +++ b/examples/golang-pgo/go.work.sum @@ -1,31 +1,162 @@ +cel.dev/expr v0.16.0 h1:yloc84fytn4zmJX2GU3TkXGsaieaV7dQ057Qs4sIG2Y= +cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les= +github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= +github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= diff --git a/examples/golang-pgo/grafana-provisioning/datasources/pyroscope.yml b/examples/golang-pgo/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/golang-pgo/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/grafana-agent-auto-instrumentation/ebpf/docker/config.river b/examples/grafana-agent-auto-instrumentation/ebpf/docker/config.river deleted file mode 100644 index dc72493831..0000000000 --- a/examples/grafana-agent-auto-instrumentation/ebpf/docker/config.river +++ /dev/null @@ -1,40 +0,0 @@ - -discovery.docker "all" { - host = "unix:///var/run/docker.sock" -} - -discovery.relabel "pyroscope" { - targets = discovery.docker.all.targets - // Filter needed containers based on docker labels - // See more info at reference doc https://grafana.com/docs/agent/next/flow/reference/components/discovery.docker/ - rule { - source_labels = ["__meta_docker_container_name"] - regex = ".*pyroscope.*" - action = "keep" - } - // provide arbitrary service_name label, otherwise it will default to value of __meta_docker_container_name - rule { - source_labels = ["__meta_docker_container_name"] - regex = ".*pyroscope.*" - action = "replace" - target_label = "service_name" - replacement = "ebpf/docker/pyroscope" - } -} - - -pyroscope.ebpf "instance" { - forward_to = [pyroscope.write.endpoint.receiver] - targets = discovery.relabel.pyroscope.output -} - -pyroscope.write "endpoint" { - endpoint { - url = "http://pyroscope:4040" - // url = "" - // basic_auth { - // username = "" - // password = "" - // } - } -} diff --git a/examples/grafana-agent-auto-instrumentation/ebpf/docker/docker-compose.yml b/examples/grafana-agent-auto-instrumentation/ebpf/docker/docker-compose.yml deleted file mode 100644 index 9b11911359..0000000000 --- a/examples/grafana-agent-auto-instrumentation/ebpf/docker/docker-compose.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -version: '3.9' -services: - pyroscope: - image: grafana/pyroscope - ports: - - '4040:4040' - - grafana-agent: - image: 'grafana/agent:main' - user: root - privileged: true - pid: 'host' - environment: - - AGENT_MODE=flow - volumes: - - '/var/run/docker.sock:/var/run/docker.sock' - - ./config.river:/config.river - ports: - - '12345:12345' - command: - - 'run' - - '/config.river' - - '--storage.path=/tmp/agent' - - '--server.http.listen-addr=0.0.0.0:12345' diff --git a/examples/grafana-agent-auto-instrumentation/ebpf/k8s/config.river b/examples/grafana-agent-auto-instrumentation/ebpf/k8s/config.river deleted file mode 100644 index 8a74b9fb75..0000000000 --- a/examples/grafana-agent-auto-instrumentation/ebpf/k8s/config.river +++ /dev/null @@ -1,70 +0,0 @@ -// This is an example grafana agent config to set up eBPF profiling in kubernetes. -// for more info see https://grafana.com/docs/pyroscope/latest/configure-client/grafana-agent/ebpf/setup-kubernetes/ - -discovery.kubernetes "local_pods" { - selectors { - field = "spec.nodeName=" + env("HOSTNAME") // Note: this assume HOSTNAME is set to the node name - role = "pod" - } - role = "pod" -} - -discovery.relabel "specific_pods" { - targets = discovery.kubernetes.local_pods.targets - rule { - action = "drop" - regex = "Succeeded|Failed|Completed" - source_labels = ["__meta_kubernetes_pod_phase"] - } - rule { - action = "replace" - source_labels = ["__meta_kubernetes_namespace"] - target_label = "namespace" - } - rule { - action = "replace" - source_labels = ["__meta_kubernetes_pod_name"] - target_label = "pod" - } - rule { - action = "replace" - source_labels = ["__meta_kubernetes_pod_node_name"] - target_label = "node" - } - rule { - action = "replace" - source_labels = ["__meta_kubernetes_pod_container_name"] - target_label = "container" - } - // provide arbitrary service_name label, otherwise it will be set to {__meta_kubernetes_namespace}/{__meta_kubernetes_pod_container_name} - rule { - action = "replace" - regex = "(.*)@(.*)" - replacement = "ebpf/k8s/${1}/${2}" - separator = "@" - source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"] - target_label = "service_name" - } - // Filter specific targets to profile - rule { - source_labels = ["service_name"] - regex = "(ebpf/grafana-agent/agent|ebpf/pyroscope/pyroscope)" - action = "keep" - } -} - -pyroscope.ebpf "instance" { - forward_to = [pyroscope.write.endpoint.receiver] - targets = discovery.relabel.specific_pods.output -} - -pyroscope.write "endpoint" { - endpoint { - url = "http://pyroscope:4040" - // url = "" - // basic_auth { - // username = "" - // password = "" - // } - } -} diff --git a/examples/grafana-agent-auto-instrumentation/ebpf/local/config.river b/examples/grafana-agent-auto-instrumentation/ebpf/local/config.river deleted file mode 100644 index d10937a5e0..0000000000 --- a/examples/grafana-agent-auto-instrumentation/ebpf/local/config.river +++ /dev/null @@ -1,54 +0,0 @@ - -// discovery.process produces targets with the following labels:` -// "__process_pid__" -// "__meta_process_exe" -// "__meta_process_cwd" -// "__meta_process_commandline" -// "__meta_process_username" -// "__meta_process_uid" -// "__container_id__" -// See reference doc for more info https://grafana.com/docs/agent/next/flow/reference/components/discovery.process/ - -discovery.process "all" { - -} - -discovery.relabel "agent" { - targets = discovery.process.all.targets - // Filter needed processes - rule { - source_labels = ["__meta_process_exe"] - regex = ".*/grafana-agent" - action = "keep" - } - // provide arbitrary service_name label, otherwise it will be "unspecified" - rule { - source_labels = ["__meta_process_exe"] - target_label = "service_name" - regex = ".*/grafana-agent" - action = "replace" - replacement = "ebpf/local/grafana-agent" - } -} - - -pyroscope.ebpf "instance" { - forward_to = [pyroscope.write.endpoint.receiver] - targets = concat( - discovery.relabel.agent.output, - [{"__process_pid__" = "1", "service_name" = "ebpf/local/init"}], - ) -} - - -pyroscope.write "endpoint" { - endpoint { - url = "http://pyroscope:4040" - // url = "" - // basic_auth { - // username = "" - // password = "" - // } - } -} - diff --git a/examples/grafana-agent-auto-instrumentation/ebpf/local/docker-compose.yml b/examples/grafana-agent-auto-instrumentation/ebpf/local/docker-compose.yml deleted file mode 100644 index 23b1a05e81..0000000000 --- a/examples/grafana-agent-auto-instrumentation/ebpf/local/docker-compose.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -version: '3.9' -services: - pyroscope: - image: grafana/pyroscope - ports: - - '4040:4040' - - app: - image: 'grafana/agent:main' - user: root - privileged: true - pid: 'host' - environment: - - AGENT_MODE=flow - volumes: - - ./config.river:/config.river - ports: - - '12345:12345' - command: - - 'run' - - '/config.river' - - '--storage.path=/tmp/agent' - - '--server.http.listen-addr=0.0.0.0:12345' diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/README.md b/examples/grafana-agent-auto-instrumentation/golang-pull/README.md deleted file mode 100644 index c86e87e5c3..0000000000 --- a/examples/grafana-agent-auto-instrumentation/golang-pull/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Grafana Agent Pull Mode Integration - -This example demonstrates how you can use Grafana Agent with Grafana Pyroscope (formerly known as Phlare). - -### 1. Configure Grafana agent - -You'll need to configure the Grafana agent for things like profiling configuration, targets, and possibly authentication in order to have the Grafana Agent pull profiles from your application. - -You can find a list of [arguments](https://grafana.com/docs/agent/latest/flow/reference/components/pyroscope.scrape/#arguments) and [supported blocks](https://grafana.com/docs/agent/latest/flow/reference/components/pyroscope.scrape/#blocks) in the [Grafana Agent documentation for pyroscope](https://grafana.com/docs/agent/latest/flow/reference/components/pyroscope.scrape/) - -Refer to [config file](agent/config/config.river) to see an example of how to configure Grafana Agent to send profiling data to Pyroscope. - -### 2. Run Grafana agent, Grafana and Pyroscope - -```shell -docker-compose up -d -``` - -### 3. Observe profiling data - -Now that everything is set up, you can browse profiling data via [Grafana UI](http://localhost:3000). - -#### Explore view -For showing profiling data alongside traces -![image](https://github.com/grafana/pyroscope/assets/23323466/a9c2f28c-d35a-49b0-a3bc-678d3fbdd321) - -#### Dashboard -For showing real-time overview of profiling data -![image](https://github.com/grafana/pyroscope/assets/23323466/59a84d0c-87d2-4cfc-8e34-b54576cb6540) - diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/agent/config/agent.yaml b/examples/grafana-agent-auto-instrumentation/golang-pull/agent/config/agent.yaml deleted file mode 100644 index 9faaad5f71..0000000000 --- a/examples/grafana-agent-auto-instrumentation/golang-pull/agent/config/agent.yaml +++ /dev/null @@ -1,2 +0,0 @@ -server: - log_level: info diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/agent/config/config.river b/examples/grafana-agent-auto-instrumentation/golang-pull/agent/config/config.river deleted file mode 100644 index 92774355a9..0000000000 --- a/examples/grafana-agent-auto-instrumentation/golang-pull/agent/config/config.river +++ /dev/null @@ -1,29 +0,0 @@ -logging { - level = "debug" - format = "logfmt" -} - -pyroscope.write "example" { - // Send metrics to a locally running Pyroscope instance. - endpoint { - url = "http://pyroscope:4040" - - // To send data to Grafana Cloud you'll need to provide username and password. - // basic_auth { - // username = "myuser" - // password = "mypassword" - // } - } - external_labels = { - "env" = "example", - } -} - - -pyroscope.scrape "default" { - targets = [ - {"__address__" = "pyroscope:4040", "service_name"="pyroscope"}, - {"__address__" = "agent:12345", "service_name"="agent"}, - ] - forward_to = [pyroscope.write.example.receiver] -} diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/docker-compose.yml b/examples/grafana-agent-auto-instrumentation/golang-pull/docker-compose.yml deleted file mode 100644 index 5b6933e4f8..0000000000 --- a/examples/grafana-agent-auto-instrumentation/golang-pull/docker-compose.yml +++ /dev/null @@ -1,29 +0,0 @@ -version: '3.9' -services: - grafana: - image: grafana/grafana:latest - volumes: - - ./grafana-provisioning:/etc/grafana/provisioning - - ./grafana/grafana.ini:/etc/grafana/grafana.ini - - ./grafana/home.json:/default-dashboard.json - ports: - - 3000:3000 - - pyroscope: - image: 'grafana/pyroscope:latest' - ports: - - 4040:4040 - - agent: - image: grafana/agent:latest - volumes: - - ./agent/config:/etc/agent-config - command: - - run - - /etc/agent-config/config.river - - --server.http.listen-addr=0.0.0.0:12345 - environment: - HOSTNAME: agent - AGENT_MODE: flow - ports: - - "12345:12345" diff --git a/examples/grafana-agent-auto-instrumentation/java/README.md b/examples/grafana-agent-auto-instrumentation/java/README.md deleted file mode 100644 index 604d8138da..0000000000 --- a/examples/grafana-agent-auto-instrumentation/java/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Grafana Agent Java profiling via auto-instrumentation example - -This repository provides a practical demonstration of leveraging the Grafana Agent for continuous Java application profiling using Pyroscope in a dockerized environment. It illustrates a seamless approach to profiling Java processes, aiding in performance optimization. - -## Overview - -The Grafana Agent automates Java process discovery for profiling, streamlining the setup per application. It enables precise and targeted profiling configurations through the Grafana Agent settings. - -Java profiling via the Grafana Agent is based on a few Grafana Agent components: -- `discovery.process` (and optionally `discovery.kubernetes`) for process discovery -- `discovery.relabel` for detecting java processes and setting up labels -- `pyroscope.java` for enabling profiling for specific applications -- `pyroscope.write` for writing the profiles data to a remote endpoint - -Refer to the [official documentation](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-agent/java/) for an in-depth understanding and additional configuration options for Java profiling with the Grafana Agent. -Also, check the [Grafana Agent Components reference](https://grafana.com/docs/agent/latest/flow/reference/components/) for more details on each used component. - -### async-profiler - -The `pyroscope.java` agent component internally uses the [async-profiler](https://github.com/async-profiler/async-profiler) library. -This approach offers a key advantage over other instrumentation mechanisms in that you can profile applications that are already running without interruptions (code changes, config changes or restarts). - -Under the hood, this is achieved by attaching to the application at a process level and issuing commands to control profiling. - -## Getting started - -To use this example: - -1. Install and run Docker. -2. Clone this repository and navigate to the example's directory. -3. Use Docker Compose to build and initiate the container: - -```shell - docker-compose up --build -``` - -After the container is operational, the Grafana Agent profiles the Java application using he defined configuration. - -## Considerations - -You need root privileges to run the Grafana Agent for profiling. The Agent must be executed within the host's PID namespace. - -## Documentation - -Refer to the [official documentation](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-agent/java/) for an in-depth understanding and additional configuration options for Java profiling with the Grafana Agent. diff --git a/examples/grafana-agent-auto-instrumentation/java/config.river b/examples/grafana-agent-auto-instrumentation/java/config.river deleted file mode 100644 index b94edb7180..0000000000 --- a/examples/grafana-agent-auto-instrumentation/java/config.river +++ /dev/null @@ -1,56 +0,0 @@ -logging { - level = "debug" - format = "logfmt" -} - -discovery.process "all" { - // join kuberenetes targets with process targets on container_id to have k8s labels - // join = discovery.kubernetes.containers.targets -} - -discovery.relabel "java" { - targets = discovery.process.all.targets - rule { - source_labels = ["__meta_process_exe"] - action = "keep" - regex = ".*/java$" - } - rule { - source_labels = ["__meta_process_commandline"] - regex = "java FastSlow" - action = "keep" - } - rule { - action = "replace" - target_label = "service_name" - replacement = "java-fast-slow-fibonacci" - } -} - -pyroscope.java "java" { - profiling_config { - interval = "15s" - alloc = "512k" - cpu = true - lock = "10ms" - sample_rate = 100 - } - forward_to = [pyroscope.write.example.receiver] - targets = discovery.relabel.java.output -} - -pyroscope.write "example" { - // Send metrics to a locally running Pyroscope instance. - endpoint { - url = "http://pyroscope:4040" - - // To send data to Grafana Cloud you'll need to provide username and password. - // basic_auth { - // username = "myuser" - // password = "mypassword" - // } - } - external_labels = { - "env" = "example", - } -} \ No newline at end of file diff --git a/examples/grafana-agent-auto-instrumentation/java/docker-compose.yml b/examples/grafana-agent-auto-instrumentation/java/docker-compose.yml deleted file mode 100644 index 7430435253..0000000000 --- a/examples/grafana-agent-auto-instrumentation/java/docker-compose.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: '3.9' -services: - java: - build: - context: . - dockerfile: java.Dockerfile - pyroscope: - image: 'grafana/pyroscope:latest' - ports: - - 4040:4040 - - agent: - image: grafana/agent:main - volumes: - - ./config.river:/etc/agent-config/config.river - command: - - run - - /etc/agent-config/config.river - - --server.http.listen-addr=0.0.0.0:12345 - environment: - HOSTNAME: agent - AGENT_MODE: flow - ports: - - "12345:12345" - privileged: true - pid: host diff --git a/examples/grafana-agent-auto-instrumentation/java/java.Dockerfile b/examples/grafana-agent-auto-instrumentation/java/java.Dockerfile deleted file mode 100644 index c661a9b7f8..0000000000 --- a/examples/grafana-agent-auto-instrumentation/java/java.Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM openjdk:17-jdk-slim - -ADD ./FastSlow.java /FastSlow.java -RUN javac FastSlow.java - -CMD ["java", "FastSlow"] diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf-otel b/examples/grafana-alloy-auto-instrumentation/ebpf-otel new file mode 120000 index 0000000000..ffd0ebb562 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf-otel @@ -0,0 +1 @@ +../otel-collector/ebpf/ \ No newline at end of file diff --git a/examples/grafana-agent-auto-instrumentation/ebpf/README.md b/examples/grafana-alloy-auto-instrumentation/ebpf/README.md similarity index 100% rename from examples/grafana-agent-auto-instrumentation/ebpf/README.md rename to examples/grafana-alloy-auto-instrumentation/ebpf/README.md diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/docker/config.alloy b/examples/grafana-alloy-auto-instrumentation/ebpf/docker/config.alloy new file mode 100644 index 0000000000..be5d510eb4 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/docker/config.alloy @@ -0,0 +1,40 @@ + +discovery.docker "all" { + host = "unix:///var/run/docker.sock" +} + +discovery.relabel "pyroscope" { + targets = discovery.docker.all.targets + // Filter needed containers based on docker labels + // See more info at reference doc https://grafana.com/docs/alloy/next/reference/components/discovery/discovery.docker/ + rule { + source_labels = ["__meta_docker_container_name"] + regex = ".*pyroscope.*" + action = "keep" + } + // provide arbitrary service_name label, otherwise it will default to value of __meta_docker_container_name + rule { + source_labels = ["__meta_docker_container_name"] + regex = ".*pyroscope.*" + action = "replace" + target_label = "service_name" + replacement = "ebpf/docker/pyroscope" + } +} + + +pyroscope.ebpf "instance" { + forward_to = [pyroscope.write.endpoint.receiver] + targets = discovery.relabel.pyroscope.output +} + +pyroscope.write "endpoint" { + endpoint { + url = "http://pyroscope:4040" + // url = "" + // basic_auth { + // username = "" + // password = "" + // } + } +} diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/docker/docker-compose.yml b/examples/grafana-alloy-auto-instrumentation/ebpf/docker/docker-compose.yml new file mode 100644 index 0000000000..83bc88604d --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/docker/docker-compose.yml @@ -0,0 +1,36 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + grafana-alloy: + image: grafana/alloy:latest + user: root + privileged: true + pid: host + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./config.alloy:/config.alloy + ports: + - 12345:12345 + command: + - run + - /config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/docker/grafana-provisioning/datasources/pyroscope.yml b/examples/grafana-alloy-auto-instrumentation/ebpf/docker/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/docker/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/README.md b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/README.md new file mode 100644 index 0000000000..22024a081c --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/README.md @@ -0,0 +1,40 @@ +# Grafana Alloy eBPF profiling via auto-instrumentation in Kubernetes + +This repository provides a practical demonstration of leveraging Grafana Alloy for continuous application profiling +using eBPF and Pyroscope in Kubernetes. It illustrates a seamless approach to profiling Golang and Python processes, +aiding in performance optimization. + +## Overview + +eBPF profiling via Grafana Alloy is based on a few components: +- `discovery.kubernetes` for discovering Kubernetes pods +- `discovery.relabel` for detecting and filtering target processes and setting up labels +- `pyroscope.ebpf` for enabling eBPF profiling for specific applications +- `pyroscope.write` for writing the profiles data to a remote endpoint + +Refer to the [official documentation](https://grafana.com/docs/alloy/latest/reference/components/pyroscope/pyroscope.ebpf/) for an in-depth understanding and additional configuration options for eBPF with Grafana Alloy. +Also, check the [Grafana Alloy Components reference](https://grafana.com/docs/alloy/latest/reference/components/) for more details on each used component. + + + +## Getting started + +To use this example: + +1. Set up a local kubernetes cluster using Kind or a similar tool. +2. Clone this repository and navigate to this example's directory. +3. Deploy the manifests: + ```shell + kubectl apply -f alloy.yaml -f grafana.yaml -f pyroscope.yaml -f python-fast-slow.yaml + ``` +4. Port-forward the Grafana service to access the Profiles Drilldown app: + ```shell + kubectl port-forward -n pyroscope-ebpf service/grafana 3000:3000 + ``` +5. Profiles Drilldown http://localhost:3000/a/grafana-pyroscope-app/explore + +After the deployment is operational, the Grafana Alloy will profile the Go and Python applications using `pyroscope.ebpf` component. + +## Documentation + +Refer to the [official documentation](https://grafana.com/docs/alloy/latest/reference/components/pyroscope/pyroscope.ebpf/) for an in-depth understanding and additional configuration options for eBPF profiling with Grafana Alloy. diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/alloy.yaml b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/alloy.yaml new file mode 100644 index 0000000000..92052a4046 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/alloy.yaml @@ -0,0 +1,177 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: pyroscope-ebpf +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole # needed for the discovery.kubernetes alloy component +metadata: + name: grafana-alloy-role +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch + +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: grafana-alloy + namespace: pyroscope-ebpf +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: grafana-alloy-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: grafana-alloy-role +subjects: + - kind: ServiceAccount + name: grafana-alloy + namespace: pyroscope-ebpf + +--- + +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: grafana-alloy + namespace: pyroscope-ebpf +spec: + selector: + matchLabels: + app: grafana-alloy + template: + metadata: + labels: + app: grafana-alloy + spec: + serviceAccountName: grafana-alloy + containers: + - name: grafana-alloy + image: grafana/alloy:latest + command: + - /bin/alloy + - run + - /etc/alloy-config/config.alloy + - --server.http.listen-addr=0.0.0.0:12345 + env: + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - containerPort: 12345 + volumeMounts: + - name: alloy-config + mountPath: /etc/alloy-config + securityContext: + privileged: true + runAsGroup: 0 + runAsUser: 0 + volumes: + - name: alloy-config + configMap: + name: alloy-config + + hostPID: true + +--- + +apiVersion: v1 +kind: ConfigMap +metadata: + name: alloy-config + namespace: pyroscope-ebpf +data: + config.alloy: | + // This is an example grafana alloy config to set up eBPF profiling in kubernetes. + // for more info see https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/ebpf/setup-kubernetes/ + logging { + level = "debug" + format = "logfmt" + } + + discovery.kubernetes "local_pods" { + selectors { + field = "spec.nodeName=" + env("HOSTNAME") // Note: this assume HOSTNAME is set to the node name + role = "pod" + } + role = "pod" + } + + discovery.relabel "specific_pods" { + targets = discovery.kubernetes.local_pods.targets + rule { + action = "drop" + regex = "Succeeded|Failed|Completed" + source_labels = ["__meta_kubernetes_pod_phase"] + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_node_name"] + target_label = "node" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // provide arbitrary service_name label, otherwise it will be set to {__meta_kubernetes_namespace}/{__meta_kubernetes_pod_container_name} + rule { + action = "replace" + regex = "(.*)@(.*)" + replacement = "${1}/${2}" + separator = "@" + source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"] + target_label = "service_name" + } + + // Filter specific targets to profile + rule { + source_labels = ["service_name"] + regex = "(.*alloy|.*pyroscope|.*fast-slow)" + action = "keep" + } + } + + pyroscope.ebpf "instance" { + forward_to = [pyroscope.write.endpoint.receiver] + targets = discovery.relabel.specific_pods.output + python_enabled = true + } + + pyroscope.write "endpoint" { + endpoint { + url = "http://pyroscope.pyroscope-ebpf.svc.cluster.local.:4040" + // url = "" + // basic_auth { + // username = "" + // password = "" + // } + } + } +--- diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/grafana.yaml b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/grafana.yaml new file mode 100644 index 0000000000..f99c129e4c --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/grafana.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: pyroscope-ebpf +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + spec: + containers: + - name: grafana + image: grafana/grafana:latest + env: + - name: GF_PLUGINS_PREINSTALL_SYNC + value: grafana-pyroscope-app + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "true" + ports: + - containerPort: 3000 + volumeMounts: + - name: grafana-provisioning + mountPath: /etc/grafana/provisioning + volumes: + - name: grafana-provisioning + configMap: + name: grafana-provisioning + items: + - key: datasources + path: datasources/datasources.yaml + - key: plugins + path: plugins/plugins.yaml +--- +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: pyroscope-ebpf +spec: + selector: + app: grafana + ports: + - protocol: TCP + port: 3000 + targetPort: 3000 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-provisioning + namespace: pyroscope-ebpf +data: + "datasources": | + apiVersion: 1 + datasources: + - uid: local-pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + + "plugins": | + apiVersion: 1 + apps: + - type: grafana-pyroscope-app + jsonData: + backendUrl: http://pyroscope:4040 + secureJsonData: diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/pyroscope.yaml b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/pyroscope.yaml new file mode 100644 index 0000000000..65a602a841 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/pyroscope.yaml @@ -0,0 +1,34 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope + namespace: pyroscope-ebpf +spec: + replicas: 1 + selector: + matchLabels: + app: pyroscope + template: + metadata: + labels: + app: pyroscope + spec: + containers: + - name: pyroscope + image: grafana/pyroscope:latest + ports: + - containerPort: 4040 +--- + +apiVersion: v1 +kind: Service +metadata: + name: pyroscope + namespace: pyroscope-ebpf +spec: + selector: + app: pyroscope + ports: + - protocol: TCP + port: 4040 + targetPort: 4040 diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/python-fast-slow.yaml b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/python-fast-slow.yaml new file mode 100644 index 0000000000..66e4a2732e --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/kubernetes/python-fast-slow.yaml @@ -0,0 +1,60 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: python-app + namespace: pyroscope-ebpf +data: + main: | + #!/usr/bin/env python3 + + import logging + import os + + def work(n): + i = 0 + while i < n: + i += 1 + + def fast_function(): + work(20000) + + def slow_function(): + work(80000) + + if __name__ == "__main__": + while True: + fast_function() + slow_function() + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: python-fast-slow + namespace: pyroscope-ebpf +spec: + replicas: 1 + selector: + matchLabels: + app: python-fast-slow + template: + metadata: + labels: + app: python-fast-slow + spec: + containers: + - name: python-fast-slow + image: python:3.11 + imagePullPolicy: IfNotPresent + command: [ "python3" ] + args: [ "/app/main.py" ] + volumeMounts: + - name: app + mountPath: /app + volumes: + - name: app + configMap: + name: python-app + items: + - key: main + path: main.py diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/local/config.alloy b/examples/grafana-alloy-auto-instrumentation/ebpf/local/config.alloy new file mode 100644 index 0000000000..4c1bf18489 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/local/config.alloy @@ -0,0 +1,54 @@ + +// discovery.process produces targets with the following labels:` +// "__process_pid__" +// "__meta_process_exe" +// "__meta_process_cwd" +// "__meta_process_commandline" +// "__meta_process_username" +// "__meta_process_uid" +// "__container_id__" +// See reference doc for more info https://grafana.com/docs/alloy/next/reference/components/discovery/discovery.process/ + +discovery.process "all" { + +} + +discovery.relabel "alloy" { + targets = discovery.process.all.targets + // Filter needed processes + rule { + source_labels = ["__meta_process_exe"] + regex = ".*/alloy" + action = "keep" + } + // provide arbitrary service_name label, otherwise it will be "unspecified" + rule { + source_labels = ["__meta_process_exe"] + target_label = "service_name" + regex = ".*/alloy" + action = "replace" + replacement = "ebpf/local/alloy" + } +} + + +pyroscope.ebpf "instance" { + forward_to = [pyroscope.write.endpoint.receiver] + targets = concat( + discovery.relabel.alloy.output, + [{"__process_pid__" = "1", "service_name" = "ebpf/local/init"}], + ) +} + + +pyroscope.write "endpoint" { + endpoint { + url = "http://pyroscope:4040" + // url = "" + // basic_auth { + // username = "" + // password = "" + // } + } +} + diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/local/docker-compose.yml b/examples/grafana-alloy-auto-instrumentation/ebpf/local/docker-compose.yml new file mode 100644 index 0000000000..189dd4956e --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/local/docker-compose.yml @@ -0,0 +1,35 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + app: + image: grafana/alloy:latest + user: root + privileged: true + pid: host + volumes: + - ./config.alloy:/config.alloy + ports: + - 12345:12345 + command: + - run + - /config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/grafana-alloy-auto-instrumentation/ebpf/local/grafana-provisioning/datasources/pyroscope.yml b/examples/grafana-alloy-auto-instrumentation/ebpf/local/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/ebpf/local/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/grafana-alloy-auto-instrumentation/golang-pull/README.md b/examples/grafana-alloy-auto-instrumentation/golang-pull/README.md new file mode 100644 index 0000000000..ceb325b5a8 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/golang-pull/README.md @@ -0,0 +1,36 @@ +# Grafana Alloy Pull Mode Integration + +This example demonstrates how you can use Grafana Alloy with Grafana Pyroscope (formerly known as Phlare). + +### 1. Configure Grafana Alloy + +You'll need to configure the Grafana Alloy for things like profiling configuration, targets, and possibly authentication in order to have the Grafana Alloy pull profiles from your application. + +You can find a list of [arguments](https://grafana.com/docs/alloy/latest/reference/components/pyroscope/pyroscope.scrape/#arguments) and [supported blocks](https://grafana.com/docs/alloy/latest/reference/components/pyroscope/pyroscope.scrape/#blocks) in the [Grafana Alloy documentation for pyroscope](https://grafana.com/docs/alloy/latest/reference/components/pyroscope/pyroscope.scrape/) + +Refer to [config file](alloy/config.alloy) to see an example of how to configure Grafana Alloy to send profiling data to Pyroscope. + +### 2. Run Grafana Alloy, Grafana and Pyroscope + +```shell +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest +docker pull grafana/alloy:latest + +docker-compose up -d +``` + +### 3. Observe profiling data + +Now that everything is set up, you can browse profiling data. + +#### Explore profiles +[Profiles Drilldown](http://localhost:3000/a/grafana-pyroscope-app/explore). + +![image](https://github.com/user-attachments/assets/71cb5a6e-2f5f-4f80-b868-d17fc30c2ca1) +![image](https://github.com/user-attachments/assets/00e45eac-0d2d-4229-85f0-3d2321c4542a) + +#### Dashboard +You will also find a dummy [dashboard](http://localhost:3000/d/65gjqY3Mk/main). + diff --git a/examples/grafana-alloy-auto-instrumentation/golang-pull/alloy/config.alloy b/examples/grafana-alloy-auto-instrumentation/golang-pull/alloy/config.alloy new file mode 100644 index 0000000000..2188c07bdb --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/golang-pull/alloy/config.alloy @@ -0,0 +1,29 @@ +logging { + level = "debug" + format = "logfmt" +} + +pyroscope.write "example" { + // Send metrics to a locally running Pyroscope instance. + endpoint { + url = "http://pyroscope:4040" + + // To send data to Grafana Cloud you'll need to provide username and password. + // basic_auth { + // username = "myuser" + // password = "mypassword" + // } + } + external_labels = { + "env" = "example", + } +} + + +pyroscope.scrape "default" { + targets = [ + {"__address__" = "pyroscope:4040", "service_name"="pyroscope"}, + {"__address__" = "alloy:12345", "service_name"="alloy"}, + ] + forward_to = [pyroscope.write.example.receiver] +} diff --git a/examples/grafana-alloy-auto-instrumentation/golang-pull/docker-compose.yml b/examples/grafana-alloy-auto-instrumentation/golang-pull/docker-compose.yml new file mode 100644 index 0000000000..c496a71c7f --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/golang-pull/docker-compose.yml @@ -0,0 +1,33 @@ +services: + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + - ./grafana/grafana.ini:/etc/grafana/grafana.ini + - ./grafana/home.json:/default-dashboard.json + ports: + - 3000:3000 + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + alloy: + image: grafana/alloy:latest + volumes: + - ./alloy/config.alloy:/etc/alloy/config.alloy + command: + - run + - /etc/alloy/config.alloy + - --server.http.listen-addr=0.0.0.0:12345 + ports: + - "12345:12345" diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.json b/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.json similarity index 100% rename from examples/grafana-agent-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.json rename to examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.json diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.yml b/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.yml similarity index 100% rename from examples/grafana-agent-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.yml rename to examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/dashboards/main.yml diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/grafana-provisioning/datasources/datasources.yml b/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/datasources/datasources.yml similarity index 100% rename from examples/grafana-agent-auto-instrumentation/golang-pull/grafana-provisioning/datasources/datasources.yml rename to examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/datasources/datasources.yml diff --git a/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/datasources/pyroscope.yml b/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/grafana/grafana.ini b/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana/grafana.ini similarity index 100% rename from examples/grafana-agent-auto-instrumentation/golang-pull/grafana/grafana.ini rename to examples/grafana-alloy-auto-instrumentation/golang-pull/grafana/grafana.ini diff --git a/examples/grafana-agent-auto-instrumentation/golang-pull/grafana/home.json b/examples/grafana-alloy-auto-instrumentation/golang-pull/grafana/home.json similarity index 100% rename from examples/grafana-agent-auto-instrumentation/golang-pull/grafana/home.json rename to examples/grafana-alloy-auto-instrumentation/golang-pull/grafana/home.json diff --git a/examples/grafana-agent-auto-instrumentation/java/FastSlow.java b/examples/grafana-alloy-auto-instrumentation/java/docker/FastSlow.java similarity index 100% rename from examples/grafana-agent-auto-instrumentation/java/FastSlow.java rename to examples/grafana-alloy-auto-instrumentation/java/docker/FastSlow.java diff --git a/examples/grafana-alloy-auto-instrumentation/java/docker/README.md b/examples/grafana-alloy-auto-instrumentation/java/docker/README.md new file mode 100644 index 0000000000..901c8b517e --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/docker/README.md @@ -0,0 +1,59 @@ +# Java profiling via auto-instrumentation example in Docker with Grafana Alloy + +This repository provides a practical demonstration of leveraging the Grafana Alloy for continuous Java application profiling using Pyroscope in a dockerized environment. It illustrates a seamless approach to profiling Java processes, aiding in performance optimization. + +## Overview + +Grafana Alloy automates Java process discovery for profiling, streamlining the setup per application. It enables precise and targeted profiling configurations through Grafana Alloy settings. + +Java profiling via Grafana Alloy is based on a few Grafana Alloy components: +- `discovery.process` (and optionally `discovery.kubernetes`) for process discovery +- `discovery.relabel` for detecting java processes and setting up labels +- `pyroscope.java` for enabling profiling for specific applications +- `pyroscope.write` for writing the profiles data to a remote endpoint + +Refer to the [official documentation](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/java/) for an in-depth understanding and additional configuration options for Java profiling with Grafana Alloy. +Also, check the [Grafana Alloy Components reference](https://grafana.com/docs/alloy/latest/reference/components/) for more details on each used component. + +### async-profiler + +The `pyroscope.java` component internally uses the [async-profiler](https://github.com/async-profiler/async-profiler) library. +This approach offers a key advantage over other instrumentation mechanisms in that you can profile applications that are already running without interruptions (code changes, config changes or restarts). + +Under the hood, this is achieved by attaching to the application at a process level and issuing commands to control profiling. + +## Getting started + +To use this example: + +1. Install and run Docker. +2. Clone this repository and navigate to the example's directory. +3. Use Docker Compose to build and initiate the container: + +```shell +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest +docker pull grafana/alloy:latest + +docker-compose up --build +``` + +After the container is operational, Grafana Alloy profiles the Java application using he defined configuration. + +### Observe profiling data + +Now that everything is set up, you can browse profiling data through the [Profiles Drilldown app](http://localhost:3000/a/grafana-pyroscope-app/explore). + +![image](https://github.com/user-attachments/assets/16f5559a-0bbc-4cf3-9589-fa4374bbc7e8) +![image](https://github.com/user-attachments/assets/ca28d228-93c3-4e16-a63c-285005c7b203) + + + +## Considerations + +You need root privileges to run Grafana Alloy for profiling. It must be executed within the host's PID namespace. + +## Documentation + +Refer to the [official documentation](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/java/) for an in-depth understanding and additional configuration options for Java profiling with Grafana Alloy. diff --git a/examples/grafana-alloy-auto-instrumentation/java/docker/config.alloy b/examples/grafana-alloy-auto-instrumentation/java/docker/config.alloy new file mode 100644 index 0000000000..4d18acfdd2 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/docker/config.alloy @@ -0,0 +1,56 @@ +logging { + level = "debug" + format = "logfmt" +} + +discovery.process "all" { + // join kubernetes targets with process targets on container_id to have k8s labels + // join = discovery.kubernetes.containers.targets +} + +discovery.relabel "java" { + targets = discovery.process.all.targets + rule { + source_labels = ["__meta_process_exe"] + action = "keep" + regex = ".*/java$" + } + rule { + source_labels = ["__meta_process_commandline"] + regex = "java FastSlow" + action = "keep" + } + rule { + action = "replace" + target_label = "service_name" + replacement = "java-fast-slow-fibonacci" + } +} + +pyroscope.java "java" { + profiling_config { + interval = "15s" + alloc = "512k" + cpu = true + lock = "10ms" + sample_rate = 100 + } + forward_to = [pyroscope.write.example.receiver] + targets = discovery.relabel.java.output +} + +pyroscope.write "example" { + // Send metrics to a locally running Pyroscope instance. + endpoint { + url = "http://pyroscope:4040" + + // To send data to Grafana Cloud you'll need to provide username and password. + // basic_auth { + // username = "myuser" + // password = "mypassword" + // } + } + external_labels = { + "env" = "example", + } +} diff --git a/examples/grafana-alloy-auto-instrumentation/java/docker/docker-compose.yml b/examples/grafana-alloy-auto-instrumentation/java/docker/docker-compose.yml new file mode 100644 index 0000000000..bc0d662a81 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/docker/docker-compose.yml @@ -0,0 +1,37 @@ +services: + java: + build: + context: . + dockerfile: java.Dockerfile + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + alloy: + image: grafana/alloy:latest + volumes: + - ./config.alloy:/etc/alloy-config/config.alloy + command: + - run + - /etc/alloy-config/config.alloy + - --server.http.listen-addr=0.0.0.0:12345 + ports: + - 12345:12345 + privileged: true + pid: host + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/grafana-alloy-auto-instrumentation/java/docker/grafana-provisioning/datasources/pyroscope.yml b/examples/grafana-alloy-auto-instrumentation/java/docker/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/docker/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/grafana-alloy-auto-instrumentation/java/docker/java.Dockerfile b/examples/grafana-alloy-auto-instrumentation/java/docker/java.Dockerfile new file mode 100644 index 0000000000..002863eb52 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/docker/java.Dockerfile @@ -0,0 +1,6 @@ +FROM sapmachine:17-jdk-headless + +ADD ./FastSlow.java /FastSlow.java +RUN javac FastSlow.java + +CMD ["java", "FastSlow"] diff --git a/examples/grafana-alloy-auto-instrumentation/java/kubernetes/README.md b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/README.md new file mode 100644 index 0000000000..1439c9ac6d --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/README.md @@ -0,0 +1,60 @@ +# Grafana Alloy Java profiling via auto-instrumentation in Kubernetes + +This repository provides a practical demonstration of leveraging Grafana Alloy for continuous Java application profiling using Pyroscope in Kubernetes. +It illustrates a seamless approach to profiling Java processes, aiding in performance optimization. + +## Overview + +Grafana Alloy automates Java process discovery for profiling, streamlining the setup for applications. It enables precise and targeted profiling configurations through the Grafana Alloy settings. + +Java profiling via Grafana Alloy is based on a few components: +- `discovery.process` for process discovery +- `discovery.kubernetes` for adding Kubernetes labels (namespace, pod, and more) +- `discovery.relabel` for detecting java processes and setting up labels +- `pyroscope.java` for enabling profiling for specific applications +- `pyroscope.write` for writing the profiles data to a remote endpoint + +Refer to the [official documentation](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/java/) for an in-depth understanding and additional configuration options for Java profiling with Grafana Alloy. +Also, check the [Grafana Alloy Components reference](https://grafana.com/docs/alloy/latest/reference/components/) for more details on each used component. + +### async-profiler + +The `pyroscope.java` component internally uses the [async-profiler](https://github.com/async-profiler/async-profiler) library. +This approach offers a key advantage over other instrumentation mechanisms in that you can profile applications that are already running without interruptions (code changes, config changes or restarts). + +Under the hood, this is achieved by attaching to the application at a process level and issuing commands to control profiling. + +## Getting started + +To use this example: + +1. Set up a local kubernetes cluster using Kind or a similar tool. +2. Clone this repository and navigate to this example's directory. +3. Create a `pyroscope-java` namespace: + ```shell + kubectl create namespace pyroscope-java + ``` +4. Deploy the manifests: + ```shell + kubectl apply -n pyroscope-java -f . + ``` + +After the deployment is operational, the Grafana Alloy will profile the Java application using the defined configuration. +The example will deploy a Grafana instance in the same cluster, available via the `grafana` service at port 3000. + +### Observe profiling data + +You can open grafana in your browser by port-forwarding traffic to the service: +```shell +kubectl port-forward -n pyroscope-java deployment/grafana 3000 3000 +``` + +Now that everything is set up, you can browse profiling data through the [Profiles Drilldown app](http://localhost:3000/a/grafana-pyroscope-app/explore). + +![image](https://github.com/user-attachments/assets/16f5559a-0bbc-4cf3-9589-fa4374bbc7e8) +![image](https://github.com/user-attachments/assets/ca28d228-93c3-4e16-a63c-285005c7b203) + + +## Documentation + +Refer to the [official documentation](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/java/) for an in-depth understanding and additional configuration options for Java profiling with Grafana Alloy. diff --git a/examples/grafana-alloy-auto-instrumentation/java/kubernetes/grafana-alloy.yaml b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/grafana-alloy.yaml new file mode 100644 index 0000000000..60734e344b --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/grafana-alloy.yaml @@ -0,0 +1,176 @@ +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole # needed for the discovery.kubernetes alloy component +metadata: + name: grafana-alloy-role +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["list", "watch"] + +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: grafana-alloy + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: grafana-alloy-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: grafana-alloy-role +subjects: + - kind: ServiceAccount + name: grafana-alloy + namespace: pyroscope-java + +--- + +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: grafana-alloy +spec: + selector: + matchLabels: + app: grafana-alloy + template: + metadata: + labels: + app: grafana-alloy + spec: + serviceAccountName: grafana-alloy + containers: + - name: grafana-alloy + image: grafana/alloy + command: + - /bin/alloy + - run + - /etc/alloy-config/config.alloy + - --server.http.listen-addr=0.0.0.0:12345 + ports: + - containerPort: 12345 + volumeMounts: + - name: alloy-config + mountPath: /etc/alloy-config + securityContext: + privileged: true + runAsGroup: 0 + runAsUser: 0 + capabilities: + add: + - PERFMON + - SYS_PTRACE + - SYS_RESOURCE + - SYS_ADMIN + volumes: + - name: alloy-config + configMap: + name: alloy-config + hostPID: true + +--- + +apiVersion: v1 +kind: ConfigMap +metadata: + name: alloy-config +data: + config.alloy: | + logging { + level = "debug" + format = "logfmt" + } + + // Discovers all kubernetes pods. + // Relies on serviceAccountName=grafana-alloy in the pod spec for permissions. + discovery.kubernetes "pods" { + role = "pod" + } + + // Discovers all processes running on the node. + // Relies on a security context with elevated permissions for the alloy container (running as root). + // Relies on hostPID=true on the pod spec, to be able to see processes from other pods. + discovery.process "all" { + // Merges kubernetes and process data (using container_id), to attach kubernetes labels to discovered processes. + join = discovery.kubernetes.pods.targets + } + + // Drops non-java processes and adjusts labels. + discovery.relabel "java" { + targets = discovery.process.all.targets + // Drops non-java processes. + rule { + source_labels = ["__meta_process_exe"] + action = "keep" + regex = ".*/java$" + } + // Sets up the service_name using the namespace and container names. + rule { + source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"] + target_label = "service_name" + separator = "/" + } + // Sets up kubernetes labels (labels with the __ prefix are ultimately dropped). + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_node_name"] + target_label = "node" + } + rule { + action = "replace" + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + // Sets up the cluster label. + // Relies on a pod-level annotation with the "cluster_name" name. + // Alternatively it can be set up using external_labels in pyroscope.write. + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_cluster_name"] + target_label = "cluster" + } + } + + // Attaches the Pyroscope profiler to the processes returned by the discovery.relabel component. + // Relies on a security context with elevated permissions for the alloy container (running as root). + // Relies on hostPID=true on the pod spec, to be able to access processes from other pods. + pyroscope.java "java" { + profiling_config { + interval = "15s" + alloc = "512k" + cpu = true + lock = "10ms" + sample_rate = 100 + } + forward_to = [pyroscope.write.local.receiver] + targets = discovery.relabel.java.output + } + + pyroscope.write "local" { + // Send metrics to the locally running Pyroscope instance. + endpoint { + url = "http://pyroscope:4040" + } + external_labels = { + "static_label" = "static_label_value", + } + } +--- diff --git a/examples/grafana-alloy-auto-instrumentation/java/kubernetes/grafana.yaml b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/grafana.yaml new file mode 100644 index 0000000000..4458f5a41f --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/grafana.yaml @@ -0,0 +1,75 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + spec: + containers: + - name: grafana + image: grafana/grafana:latest + env: + - name: GF_PLUGINS_PREINSTALL_SYNC + value: grafana-pyroscope-app + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "true" + ports: + - containerPort: 3000 + volumeMounts: + - name: grafana-provisioning + mountPath: /etc/grafana/provisioning + volumes: + - name: grafana-provisioning + configMap: + name: grafana-provisioning + items: + - key: datasources + path: datasources/datasources.yaml + - key: plugins + path: plugins/plugins.yaml +--- +apiVersion: v1 +kind: Service +metadata: + name: grafana +spec: + selector: + app: grafana + ports: + - protocol: TCP + port: 3000 + targetPort: 3000 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-provisioning +data: + "datasources": | + apiVersion: 1 + datasources: + - uid: local-pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + + "plugins": | + apiVersion: 1 + apps: + - type: grafana-pyroscope-app + jsonData: + backendUrl: http://pyroscope:4040 + secureJsonData: diff --git a/examples/grafana-alloy-auto-instrumentation/java/kubernetes/java-fast-slow.yaml b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/java-fast-slow.yaml new file mode 100644 index 0000000000..d7d6b2a8c0 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/java-fast-slow.yaml @@ -0,0 +1,40 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: java-app-jar +binaryData: # holds FastSlow.jar from the sibling "Docker" directory, as a base64 encoded binary + jar: | + UEsDBAoAAAgAAD1iQlkAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAFBLAwQUAAgICAA9YkJZAAAAAAAAAAAAAAAAFAAAAE1FVEEtSU5GL01BTklGRVNULk1G803My0xLLS7RDUstKs7Mz7NSMNQz4OXyTczM03XOSSwutlJwSywuCc7JL+flci5KTSxJTdF1qrRSMAKq0zNU0HBNzsksKE5VcEzJLyjJLM3V5OXi5QIAUEsHCJiPQHxXAAAAVgAAAFBLAwQUAAgICAASYkJZAAAAAAAAAAAAAAAADgAAAEZhc3RTbG93LmNsYXNznVTLUhNBFD0dkgwMAxke8ohPMEgCSkDxGYRSCkqsoItQaJWrzqSBgclMaqaHxwf4I25csXAlsvADLD/HtXp7QggWgpSpSvfcvvece27fW/3t5+FXAM8wpyOGFg1xAwkkGcxNvs3zDnfX86/Lm8KSDMkZ27XlLENLNreqoxVtGnQD7TAYWhd5IEuOt0PeNbvMEM8u5V7q6ERKg2mgC90M1yLOUNpO3vJcK/R94cr8wq6wQun5AUO/K3ZKtrvuiJUNX/BKw8WQzeaK56JLwt+2LVHopmp6DVxCH2mwuOMwDJ2FnSc3Lzui0I4BDGpIG7iMKwyZi2Si+wjCctWmi5nN/oP/jPyLoQx9USCh816FCFNF2xWvwmpZ+CsKx9BRktzaWua1Izte5bbL0Jd9V2z2pyR9urNCbpVBX9i1RE3anhtoyDCMnlMJBR1Ha7jVaE9EueRK4fthTYrKcQypcXi1XOEZJSIzydDbuNgTY1LQMMbQ0zw+gddLXuhbYtGOSmtMzISKpYF77nkykD6vLQu54VUCE9lUEpNq0KYMjEbWPR3TuK/hgYGHeMQw3Mxju9velsgXI4lEwde4Rd3aY2ivnrS+Z4unQPWML7hbcUSQKXreVlgrnL7hs4ArezXxf856yvOxudNeNVglW6rRMZZcV/jzDg8CQT2nk5ELlafh6R8d/1sojXg9GEPUhBjULw6mHghar5J1lXZGe2LsM9gn+iBOWpPRYQva1ONwFDoXQYG+dOIDkun3++l45QBaOqFWvk+eWITtJJxiSEBTTwyuR0xMfd4gHbGIbIp2pafrAB3F8UP0AF/QH8ObpoY6Twdl7YSJXgxHrDHcxIipq3E6opo+KixlpknIW3NArR9//TgWpEcBJoG7GmIQsal6cmSOR6G3cYd2Ve1dOptAnv6PIzjDE8xgFoO/AVBLBwipPrnIuQIAAG0FAABQSwECCgAKAAAIAAA9YkJZAAAAAAAAAAAAAAAACQAEAAAAAAAAAAAAAAAAAAAATUVUQS1JTkYv/soAAFBLAQIUABQACAgIAD1iQlmYj0B8VwAAAFYAAAAUAAAAAAAAAAAAAAAAACsAAABNRVRBLUlORi9NQU5JRkVTVC5NRlBLAQIUABQACAgIABJiQlmpPrnIuQIAAG0FAAAOAAAAAAAAAAAAAAAAAMQAAABGYXN0U2xvdy5jbGFzc1BLBQYAAAAAAwADALkAAAC5AwAAAAA= +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: java-fast-slow +spec: + replicas: 1 + selector: + matchLabels: + app: java-fast-slow + template: + metadata: + annotations: + cluster-name: dev-us-east-1 + labels: + app: java-fast-slow + spec: + containers: + - name: java-fast-slow + image: sapmachine:21-jdk-headless + imagePullPolicy: IfNotPresent + command: [ "java" ] + args: [ "-jar", "/app/FastSlow.jar" ] + volumeMounts: + - name: app-jar + mountPath: /app + volumes: + - name: app-jar + configMap: + name: java-app-jar + items: + - key: jar + path: FastSlow.jar diff --git a/examples/grafana-alloy-auto-instrumentation/java/kubernetes/pyroscope.yaml b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/pyroscope.yaml new file mode 100644 index 0000000000..6fece4a132 --- /dev/null +++ b/examples/grafana-alloy-auto-instrumentation/java/kubernetes/pyroscope.yaml @@ -0,0 +1,32 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope +spec: + replicas: 1 + selector: + matchLabels: + app: pyroscope + template: + metadata: + labels: + app: pyroscope + spec: + containers: + - name: pyroscope + image: grafana/pyroscope:latest + ports: + - containerPort: 4040 +--- + +apiVersion: v1 +kind: Service +metadata: + name: pyroscope +spec: + selector: + app: pyroscope + ports: + - protocol: TCP + port: 4040 + targetPort: 4040 diff --git a/examples/language-sdk-instrumentation/dotnet/fast-slow/Dockerfile b/examples/language-sdk-instrumentation/dotnet/fast-slow/Dockerfile index 659b978978..b7ed4cfee8 100644 --- a/examples/language-sdk-instrumentation/dotnet/fast-slow/Dockerfile +++ b/examples/language-sdk-instrumentation/dotnet/fast-slow/Dockerfile @@ -1,9 +1,25 @@ +ARG PROFILER_VERSION=1.0.0 + +FROM alpine:3 AS sdk +ARG PROFILER_VERSION +ARG TARGETARCH +RUN apk add --no-cache curl tar +RUN case "$TARGETARCH" in \ + amd64) PROFILER_ARCH=x86_64 ;; \ + arm64) PROFILER_ARCH=aarch64 ;; \ + *) echo "unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \ + esac \ + && curl -fsSL -o /tmp/pyroscope.tar.gz \ + "https://github.com/grafana/pyroscope-dotnet/releases/download/pyroscope-${PROFILER_VERSION}/pyroscope.${PROFILER_VERSION}-glibc-${PROFILER_ARCH}.tar.gz" \ + && mkdir -p /pyroscope \ + && tar -xzf /tmp/pyroscope.tar.gz -C /pyroscope + FROM mcr.microsoft.com/dotnet/sdk:6.0 WORKDIR /dotnet -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-glibc /Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-glibc /Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +COPY --from=sdk /pyroscope/Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so +COPY --from=sdk /pyroscope/Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so ADD example . @@ -13,6 +29,7 @@ ENV CORECLR_ENABLE_PROFILING=1 ENV CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A} ENV CORECLR_PROFILER_PATH=/dotnet/Pyroscope.Profiler.Native.so ENV LD_PRELOAD=/dotnet/Pyroscope.Linux.ApiWrapper.x64.so +ENV LD_LIBRARY_PATH=/dotnet ENV PYROSCOPE_APPLICATION_NAME=fast-slow.dotnet.app diff --git a/examples/language-sdk-instrumentation/dotnet/fast-slow/docker-compose.yml b/examples/language-sdk-instrumentation/dotnet/fast-slow/docker-compose.yml index af79b0f000..520566e3b2 100644 --- a/examples/language-sdk-instrumentation/dotnet/fast-slow/docker-compose.yml +++ b/examples/language-sdk-instrumentation/dotnet/fast-slow/docker-compose.yml @@ -1,19 +1,31 @@ ---- -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 app-glibc: platform: linux/amd64 build: context: . dockerfile: Dockerfile - app-musl: platform: linux/amd64 build: context: . dockerfile: musl.Dockerfile + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/dotnet/fast-slow/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/dotnet/fast-slow/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/dotnet/fast-slow/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/dotnet/fast-slow/musl.Dockerfile b/examples/language-sdk-instrumentation/dotnet/fast-slow/musl.Dockerfile index 6ae9fe8a5a..4c6802e221 100644 --- a/examples/language-sdk-instrumentation/dotnet/fast-slow/musl.Dockerfile +++ b/examples/language-sdk-instrumentation/dotnet/fast-slow/musl.Dockerfile @@ -1,9 +1,26 @@ +ARG PROFILER_VERSION=1.0.0 + +# Fetch the profiler artifacts from the GitHub release. +FROM alpine:3 AS sdk +ARG PROFILER_VERSION +ARG TARGETARCH +RUN apk add --no-cache curl tar +RUN case "$TARGETARCH" in \ + amd64) PROFILER_ARCH=x86_64 ;; \ + arm64) PROFILER_ARCH=aarch64 ;; \ + *) echo "unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \ + esac \ + && curl -fsSL -o /tmp/pyroscope.tar.gz \ + "https://github.com/grafana/pyroscope-dotnet/releases/download/pyroscope-${PROFILER_VERSION}/pyroscope.${PROFILER_VERSION}-musl-${PROFILER_ARCH}.tar.gz" \ + && mkdir -p /pyroscope \ + && tar -xzf /tmp/pyroscope.tar.gz -C /pyroscope + FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine WORKDIR /dotnet -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-musl /Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-musl /Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +COPY --from=sdk /pyroscope/Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so +COPY --from=sdk /pyroscope/Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so ADD example . diff --git a/examples/language-sdk-instrumentation/dotnet/rideshare/Dockerfile b/examples/language-sdk-instrumentation/dotnet/rideshare/Dockerfile index e7b8f0a9a1..c497192b6a 100644 --- a/examples/language-sdk-instrumentation/dotnet/rideshare/Dockerfile +++ b/examples/language-sdk-instrumentation/dotnet/rideshare/Dockerfile @@ -1,19 +1,57 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0 +ARG SDK_VERSION=8.0 +ARG PROFILER_VERSION=1.0.0 +# The build images takes an SDK image of the buildplatform, so the platform the build is running on. +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:$SDK_VERSION-bookworm-slim AS build + +ARG TARGETPLATFORM +ARG BUILDPLATFORM +ARG SDK_VERSION WORKDIR /dotnet -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-glibc /Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-glibc /Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +ADD example/BikeService.cs \ + example/CarService.cs \ + example/Example.csproj \ + example/OrderService.cs \ + example/Program.cs \ + example/ScooterService.cs ./ + +# Set the target framework to SDK_VERSION +RUN sed -i -E 's|.*|net'$SDK_VERSION'|' Example.csproj + +# We hardcode linux-x64 here, as the profiler doesn't support any other platform +RUN dotnet publish -o . --framework net$SDK_VERSION --runtime linux-x64 --no-self-contained + +# Fetch the profiler artifacts from the GitHub release. +FROM --platform=linux/amd64 alpine:3 AS sdk +ARG PROFILER_VERSION +RUN apk add --no-cache curl tar +RUN curl -fsSL -o /tmp/pyroscope.tar.gz \ + "https://github.com/grafana/pyroscope-dotnet/releases/download/pyroscope-${PROFILER_VERSION}/pyroscope.${PROFILER_VERSION}-glibc-x86_64.tar.gz" \ + && mkdir -p /pyroscope \ + && tar -xzf /tmp/pyroscope.tar.gz -C /pyroscope +# Runtime only image of the targetplatfrom, so the platform the image will be running on. +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:$SDK_VERSION-noble-chiseled-extra -ADD example . +WORKDIR /dotnet + +# chiseled images don't include CA certs by default +COPY --from=build /etc/ssl/certs /etc/ssl/certs + +COPY --from=sdk /pyroscope/Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so +COPY --from=sdk /pyroscope/Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +COPY --from=build /dotnet/ ./ -RUN dotnet publish -o . -r $(dotnet --info | grep RID | cut -b 6- | tr -d ' ') ENV CORECLR_ENABLE_PROFILING=1 ENV CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A} ENV CORECLR_PROFILER_PATH=/dotnet/Pyroscope.Profiler.Native.so ENV LD_PRELOAD=/dotnet/Pyroscope.Linux.ApiWrapper.x64.so +ENV LD_LIBRARY_PATH=/dotnet + +# point OpenSSL to the CA certificates bundle +ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt ENV PYROSCOPE_APPLICATION_NAME=rideshare.dotnet.app ENV PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 @@ -22,7 +60,9 @@ ENV PYROSCOPE_PROFILING_ENABLED=1 ENV PYROSCOPE_PROFILING_ALLOCATION_ENABLED=true ENV PYROSCOPE_PROFILING_CONTENTION_ENABLED=true ENV PYROSCOPE_PROFILING_EXCEPTION_ENABLED=true +ENV PYROSCOPE_PROFILING_HEAP_ENABLED=true ENV RIDESHARE_LISTEN_PORT=5000 +ENV ASPNETCORE_URLS=http://*:5000 -CMD sh -c "ASPNETCORE_URLS=http://*:${RIDESHARE_LISTEN_PORT} exec dotnet /dotnet/example.dll" +CMD ["/dotnet/example.dll"] diff --git a/examples/language-sdk-instrumentation/dotnet/rideshare/docker-compose.yml b/examples/language-sdk-instrumentation/dotnet/rideshare/docker-compose.yml index 7c64baad09..c09f0a47fc 100644 --- a/examples/language-sdk-instrumentation/dotnet/rideshare/docker-compose.yml +++ b/examples/language-sdk-instrumentation/dotnet/rideshare/docker-compose.yml @@ -1,67 +1,76 @@ -version: "3" services: pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: platform: linux/amd64 ports: - - 5000 + - 5000 environment: - - REGION=us-east - - PYROSCOPE_LABELS=region:us-east - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 - - RIDESHARE_LISTEN_PORT=5000 + - REGION=us-east + - PYROSCOPE_LABELS=region:us-east + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - RIDESHARE_LISTEN_PORT=5000 build: context: . - eu-north: platform: linux/amd64 ports: - - 5000 + - 5000 environment: - - REGION=eu-north - - PYROSCOPE_LABELS=region:eu-north - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 - - RIDESHARE_LISTEN_PORT=5000 - + - REGION=eu-north + - PYROSCOPE_LABELS=region:eu-north + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - RIDESHARE_LISTEN_PORT=5000 build: context: . - ap-south: platform: linux/amd64 ports: - - 5000 + - 5000 environment: - - REGION=ap-south - - PYROSCOPE_LABELS=region:ap-south - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 - - RIDESHARE_LISTEN_PORT=5000 + - REGION=ap-south + - PYROSCOPE_LABELS=region:ap-south + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - RIDESHARE_LISTEN_PORT=5000 build: context: . - ap-south-alpine: platform: linux/amd64 ports: - - 5000 + - 5000 environment: - - REGION=ap-south - - PYROSCOPE_LABELS=region:ap-south-alpine - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 - - RIDESHARE_LISTEN_PORT=5000 + - REGION=ap-south + - PYROSCOPE_LABELS=region:ap-south-alpine + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - RIDESHARE_LISTEN_PORT=5000 build: context: . dockerfile: musl.Dockerfile - load-generator: build: context: . dockerfile: Dockerfile.load-generator depends_on: - - pyroscope - - us-east - - eu-north - - ap-south - - ap-south-alpine + - pyroscope + - us-east + - eu-north + - ap-south + - ap-south-alpine + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/dotnet/rideshare/example/.dockerignore b/examples/language-sdk-instrumentation/dotnet/rideshare/example/.dockerignore new file mode 100644 index 0000000000..27e48df5ab --- /dev/null +++ b/examples/language-sdk-instrumentation/dotnet/rideshare/example/.dockerignore @@ -0,0 +1,3 @@ +.idea/ +bin/ +obj/ diff --git a/examples/language-sdk-instrumentation/dotnet/rideshare/example/Example.csproj b/examples/language-sdk-instrumentation/dotnet/rideshare/example/Example.csproj index 95e3a743d9..1150397b45 100644 --- a/examples/language-sdk-instrumentation/dotnet/rideshare/example/Example.csproj +++ b/examples/language-sdk-instrumentation/dotnet/rideshare/example/Example.csproj @@ -1,6 +1,6 @@ - net6.0 + net8.0 example Exe example @@ -11,7 +11,7 @@ - + diff --git a/examples/language-sdk-instrumentation/dotnet/rideshare/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/dotnet/rideshare/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/dotnet/rideshare/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/dotnet/rideshare/load-generator.py b/examples/language-sdk-instrumentation/dotnet/rideshare/load-generator.py index e746c39d41..a697a083f4 100644 --- a/examples/language-sdk-instrumentation/dotnet/rideshare/load-generator.py +++ b/examples/language-sdk-instrumentation/dotnet/rideshare/load-generator.py @@ -1,6 +1,7 @@ import random import requests import time +import traceback HOSTS = [ 'us-east', @@ -19,9 +20,13 @@ print(f"starting load generator") time.sleep(3) while True: - host = HOSTS[random.randint(0, len(HOSTS) - 1)] - vehicle = VEHICLES[random.randint(0, len(VEHICLES) - 1)] - print(f"requesting {vehicle} from {host}") - resp = requests.get(f'http://{host}:5000/{vehicle}') - print(f"received {resp}") + try: + host = HOSTS[random.randint(0, len(HOSTS) - 1)] + vehicle = VEHICLES[random.randint(0, len(VEHICLES) - 1)] + print(f"requesting {vehicle} from {host}") + resp = requests.get(f'http://{host}:5000/{vehicle}') + print(f"received {resp}") + except: + traceback.print_exc() + time.sleep(random.uniform(0.2, 0.4)) diff --git a/examples/language-sdk-instrumentation/dotnet/rideshare/musl.Dockerfile b/examples/language-sdk-instrumentation/dotnet/rideshare/musl.Dockerfile index 15e29b6f04..64f3c05b58 100644 --- a/examples/language-sdk-instrumentation/dotnet/rideshare/musl.Dockerfile +++ b/examples/language-sdk-instrumentation/dotnet/rideshare/musl.Dockerfile @@ -1,14 +1,45 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine +ARG SDK_VERSION=8.0 +ARG PROFILER_VERSION=1.0.0 +# The build images takes an SDK image of the buildplatform, so the platform the build is running on. +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:$SDK_VERSION-alpine AS build + +ARG TARGETPLATFORM +ARG BUILDPLATFORM +ARG SDK_VERSION WORKDIR /dotnet -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-musl /Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-musl /Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +ADD example/BikeService.cs \ + example/CarService.cs \ + example/Example.csproj \ + example/OrderService.cs \ + example/Program.cs \ + example/ScooterService.cs ./ + +# Set the target framework to SDK_VERSION +RUN sed -i -E 's|.*|net'$SDK_VERSION'|' Example.csproj +# We hardcode linux-x64 here, as the profiler doesn't support any other platform +RUN dotnet publish -o . --framework net$SDK_VERSION --runtime linux-musl-x64 --no-self-contained -ADD example . +# Fetch the profiler artifacts from the GitHub release. +FROM --platform=linux/amd64 alpine:3 AS sdk +ARG PROFILER_VERSION +RUN apk add --no-cache curl tar +RUN curl -fsSL -o /tmp/pyroscope.tar.gz \ + "https://github.com/grafana/pyroscope-dotnet/releases/download/pyroscope-${PROFILER_VERSION}/pyroscope.${PROFILER_VERSION}-musl-x86_64.tar.gz" \ + && mkdir -p /pyroscope \ + && tar -xzf /tmp/pyroscope.tar.gz -C /pyroscope + +# Runtime only image of the targetplatfrom, so the platform the image will be running on. +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:$SDK_VERSION-alpine + +WORKDIR /dotnet + +COPY --from=sdk /pyroscope/Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so +COPY --from=sdk /pyroscope/Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +COPY --from=build /dotnet/ ./ -RUN dotnet publish -o . -r $(dotnet --info | grep RID | cut -b 6- | tr -d ' ') ENV CORECLR_ENABLE_PROFILING=1 ENV CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A} @@ -22,6 +53,8 @@ ENV PYROSCOPE_PROFILING_ENABLED=1 ENV PYROSCOPE_PROFILING_ALLOCATION_ENABLED=true ENV PYROSCOPE_PROFILING_CONTENTION_ENABLED=true ENV PYROSCOPE_PROFILING_EXCEPTION_ENABLED=true +ENV PYROSCOPE_PROFILING_HEAP_ENABLED=true ENV RIDESHARE_LISTEN_PORT=5000 + CMD sh -c "ASPNETCORE_URLS=http://*:${RIDESHARE_LISTEN_PORT} exec dotnet /dotnet/example.dll" diff --git a/examples/language-sdk-instrumentation/dotnet/web-new/Dockerfile b/examples/language-sdk-instrumentation/dotnet/web-new/Dockerfile index d3e1774821..2341092ba3 100644 --- a/examples/language-sdk-instrumentation/dotnet/web-new/Dockerfile +++ b/examples/language-sdk-instrumentation/dotnet/web-new/Dockerfile @@ -1,10 +1,21 @@ +ARG PROFILER_VERSION=1.0.0 + +# Fetch the profiler artifacts from the GitHub release. +FROM --platform=linux/amd64 alpine:3 AS sdk +ARG PROFILER_VERSION +RUN apk add --no-cache curl tar +RUN curl -fsSL -o /tmp/pyroscope.tar.gz \ + "https://github.com/grafana/pyroscope-dotnet/releases/download/pyroscope-${PROFILER_VERSION}/pyroscope.${PROFILER_VERSION}-glibc-x86_64.tar.gz" \ + && mkdir -p /pyroscope \ + && tar -xzf /tmp/pyroscope.tar.gz -C /pyroscope + FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/sdk:6.0 # FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/sdk:6.0-alpine WORKDIR /dotnet -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-glibc /Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so -COPY --from=pyroscope/pyroscope-dotnet:0.8.14-glibc /Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +COPY --from=sdk /pyroscope/Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so +COPY --from=sdk /pyroscope/Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so ADD example . @@ -14,6 +25,7 @@ ENV CORECLR_ENABLE_PROFILING=1 ENV CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A} ENV CORECLR_PROFILER_PATH=/dotnet/Pyroscope.Profiler.Native.so ENV LD_PRELOAD=/dotnet/Pyroscope.Linux.ApiWrapper.x64.so +ENV LD_LIBRARY_PATH=/dotnet ENV PYROSCOPE_APPLICATION_NAME=web.dotnet.app ENV PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 diff --git a/examples/language-sdk-instrumentation/dotnet/web-new/docker-compose.yml b/examples/language-sdk-instrumentation/dotnet/web-new/docker-compose.yml index fc4d331fe5..72e251163f 100644 --- a/examples/language-sdk-instrumentation/dotnet/web-new/docker-compose.yml +++ b/examples/language-sdk-instrumentation/dotnet/web-new/docker-compose.yml @@ -1,15 +1,29 @@ ---- -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 app: platform: linux/amd64 environment: ASPNETCORE_URLS: http://*:5000 ports: - - '5000:5000' - build: '' + - 5000:5000 + build: + context: . + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/dotnet/web-new/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/dotnet/web-new/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/dotnet/web-new/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/golang-push/README.md b/examples/language-sdk-instrumentation/golang-push/README.md index 1a243cb03a..9cfa24fee1 100644 --- a/examples/language-sdk-instrumentation/golang-push/README.md +++ b/examples/language-sdk-instrumentation/golang-push/README.md @@ -55,8 +55,9 @@ What this block does, is: ### Running the example To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: docker-compose up --build diff --git a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md index 113eea39dc..f5472c70ad 100644 --- a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md +++ b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md @@ -1,8 +1,9 @@ # Migrating from standard pprof to Pyroscope in a Go application -This README provides a comprehensive guide on migrating from the standard pprof library to Pyroscope in a Go application. The example demonstrates the transition within a detective-themed Go application, enhancing the process of profiling with Pyroscope's advanced capabilities. The actual changes needed to migrate from standard `pprof` to using the Pyroscope SDK is very simple (it extends the standard pprof library with extra functionality and performance improvements). If you would like to use standard `pprof` _algonside_ the pyroscope go sdk simultaneously see the [example here](https://github.com/grafana/pyroscope-go/tree/main/example/http). +This README provides a comprehensive guide on migrating from the standard `pprof` library to Pyroscope in a Go application. The example demonstrates the transition within a detective-themed Go application, showcasing how to enhance the profiling process with Pyroscope's advanced capabilities. The actual changes needed to migrate from the standard `pprof` to using [the Pyroscope SDK](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/go_push/) are very simple. See [the source PR](https://github.com/grafana/pyroscope/pull/2830). + +The Pyroscope Go SDK extends the standard `pprof` library with extra functionality and performance improvements. If you would like to use the standard `pprof` _alongside_ the Pyroscope Go SDK simultaneously, see the [example here](https://github.com/grafana/pyroscope-go/tree/main/example/http). -See link to [source PR here](https://github.com/grafana/pyroscope/pull/2830) image ## Changes made @@ -16,13 +17,27 @@ Originally in the pre-pyroscope code, the `main.go` file used the standard `net/ In the post-pyroscope code, to leverage the advanced features of Pyroscope, we made the following changes: 1. **Removed Standard pprof Import:** The `_ "net/http/pprof"` import was removed, as Pyroscope replaces its functionality. -2. **Added Pyroscope SDK:** We installed the Pyroscope module using `go get github.com/grafana/pyroscope-go` and imported it in our `main.go`. -3. **Configured Pyroscope:** Inside the `main()` function, we set up Pyroscope using the `pyroscope.Start()` method with the following configuration: + + +2. **Added Pyroscope SDK:** We installed the Pyroscope module using the following command and imported it in our `main.go`: + +> go get github.com/grafana/pyroscope-go + +3. **Enabled block and mutex profilers:** This step is only required if you're using mutex or block profiling. Inside the `main()` function, we enabled the block and mutex profilers using the runtime functions: + +```go +runtime.SetMutexProfileFraction(5) +runtime.SetBlockProfileRate(5) +``` + +4. **Configured Pyroscope:** Inside the `main()` function, we set up Pyroscope using the `pyroscope.Start()` method with the following configuration: - Application name and server address. - Logger configuration. - Tags for additional metadata. - Profile types to be captured. -4. Consider using [godeltaprof](https://pkg.go.dev/github.com/grafana/pyroscope-go/godeltaprof) -- which is an optimized way to do memory profiling more efficiently + + +5. **Consider using [godeltaprof](https://pkg.go.dev/github.com/grafana/pyroscope-go/godeltaprof):** It provides an optimized way to perform memory, mutex, and block profiling more efficiently. ## Benefits of using Pyroscope @@ -35,9 +50,8 @@ In the post-pyroscope code, to leverage the advanced features of Pyroscope, we m ## Migration guide -To view the exact changes made during the migration, refer to our [pull request](https://github.com/grafana/pyroscope/pull/2830). This PR clearly illustrates the differences and necessary steps to transition from standard pprof to Pyroscope. +To view the exact changes made during the migration, refer to our [pull request](https://github.com/grafana/pyroscope/pull/2830). This PR clearly illustrates the differences and the necessary steps to transition from the standard `pprof` library to Pyroscope. ## Conclusion -Migrating to Pyroscope SDK in a Go application is a straightforward process that significantly enhances profiling capabilities. By following the steps outlined in this guide and reviewing the provided PR, developers can easily switch from standard pprof to Pyroscope, benefiting from real-time, continuous profiling and advanced performance insights. - +Migrating to the Pyroscope SDK in a Go application is a straightforward process that significantly enhances profiling capabilities. By following the steps outlined in this guide and reviewing the provided PR, developers can easily transition from the standard `pprof` library to Pyroscope, benefiting from real-time, continuous profiling and advanced performance insights. diff --git a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go index 1e305c163f..0be0ed2c3e 100644 --- a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go +++ b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "net/http" + "log" "os" "runtime" "sync" @@ -49,18 +49,19 @@ func solveMystery(wg *sync.WaitGroup) { } func main() { - // Pyroscope configuration + // These 2 lines are only required if you're using mutex or block profiling runtime.SetMutexProfileFraction(5) runtime.SetBlockProfileRate(5) - pyroscope.Start(pyroscope.Config{ + // Pyroscope configuration + profiler, err := pyroscope.Start(pyroscope.Config{ ApplicationName: "detective.mystery.app", - ServerAddress: "https://profiles-prod-001.grafana.net", // if OSS then http://localhost:4040 + ServerAddress: "https://profiles-prod-001.grafana.net", // If OSS, then "http://pyroscope.local:4040" // Optional HTTP Basic authentication - BasicAuthUser: "", // 900009 - BasicAuthPassword: "", // glc_SAMPLEAPIKEY0000000000== - Logger: pyroscope.StandardLogger, - Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")}, + // BasicAuthUser: "", // 900009 + // BasicAuthPassword: "", // glc_SAMPLEAPIKEY0000000000== + Logger: pyroscope.StandardLogger, + Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")}, ProfileTypes: []pyroscope.ProfileType{ pyroscope.ProfileCPU, pyroscope.ProfileAllocObjects, @@ -74,16 +75,22 @@ func main() { pyroscope.ProfileBlockDuration, }, }) - - var wg sync.WaitGroup - - // Server for pprof - go func() { - fmt.Println(http.ListenAndServe("localhost:6060", nil)) + if err != nil { + log.Fatalf("Error starting profiler: %v", err) + } + defer func() { + err := profiler.Stop() + if err != nil { + log.Printf("Error stopping profiler: %v", err) + } }() - wg.Add(1) // pprof - so we won't exit prematurely - wg.Add(4) // Adding 4 detective tasks + // pyroscope.Start is non-blocking: the profiler will start shortly. + // To ensure we don't miss the investigation, we wait briefly. + time.Sleep(time.Second) + + var wg sync.WaitGroup + wg.Add(5) // Adding 5 detective tasks go gatherClues(&wg) go analyzeEvidence(&wg) go interviewWitnesses(&wg) diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/Dockerfile b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/Dockerfile new file mode 100644 index 0000000000..37517ecd28 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/Dockerfile @@ -0,0 +1,6 @@ +FROM golang:1.25.12 + +WORKDIR /go/src/app +COPY . . +RUN go build main.go +CMD ["./main"] diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/Dockerfile.load-generator b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/Dockerfile.load-generator new file mode 100644 index 0000000000..eb16110dcd --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/Dockerfile.load-generator @@ -0,0 +1,6 @@ +FROM golang:1.25.12 + +WORKDIR /go/src/app +COPY . . +RUN go build loadgen.go +CMD ["./loadgen"] diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/README.md b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/README.md new file mode 100644 index 0000000000..d061434704 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/README.md @@ -0,0 +1,57 @@ +# Rideshare Example with Alloy Profiling + +This example demonstrates how to use Alloy to receive and forward profiles from the rideshare example application. + +To learn more about the `pyroscope.receive_http` component in Alloy, refer to the [`receive_profiles`](https://grafana.com/docs/pyroscope/latest/configure-client/grafana-alloy/receive_profiles/) documentation. + +## Architecture + +- Regional services (us-east, eu-north, ap-south) push profiles to Alloy +- Alloy receives profiles on port 9999 and forwards them to Pyroscope +- Pyroscope stores and processes profiles +- Grafana visualizes the profiling data + +![Pyroscope agent server diagram](https://grafana.com/media/docs/pyroscope/pyroscope_client_server_diagram_11_18_2024.png) + +## Configuration + +The example uses this Alloy configuration: +```alloy +pyroscope.receive_http "default" { + http { + listen_address = "0.0.0.0" + listen_port = 9999 + } + forward_to = [pyroscope.write.backend.receiver] +} + +pyroscope.write "backend" { + endpoint { + url = "http://pyroscope:4040" + // url = "" + // basic_auth { + // username = "" + // password = "" + // } + } + external_labels = { + "env" = "production", + } +} +``` + +## Running the example +```bash +# Pull latest images +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest +docker pull grafana/alloy:v1.7.1 + +# Run the example +docker-compose up --build + +# Reset if needed +docker-compose down +``` + +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/bike/bike.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/bike/bike.go new file mode 100644 index 0000000000..98ad8325fb --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/bike/bike.go @@ -0,0 +1,12 @@ +package bike + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderBike(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering bike, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "bike") +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/car/car.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/car/car.go new file mode 100644 index 0000000000..16898fb8ea --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/car/car.go @@ -0,0 +1,12 @@ +package car + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderCar(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering car, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "car") +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/config.alloy b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/config.alloy new file mode 100644 index 0000000000..42daf60586 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/config.alloy @@ -0,0 +1,66 @@ +pyroscope.receive_http "default" { + http { + listen_address = "0.0.0.0" + listen_port = 9999 + } + forward_to = [pyroscope.relabel.filter_profiles.receiver] +} + +pyroscope.relabel "filter_profiles" { + // Group regions into geographical areas for better aggregation + rule { + action = "replace" + source_labels = ["region"] + target_label = "geo_area" + regex = "(us-.*)" + replacement = "americas" + } + rule { + action = "replace" + source_labels = ["region"] + target_label = "geo_area" + regex = "(eu-.*)" + replacement = "emea" + } + rule { + action = "replace" + source_labels = ["region"] + target_label = "geo_area" + regex = "(ap-.*)" + replacement = "apac" + } + + rule { + action = "replace" + source_labels = ["service_name"] + target_label = "tier" + regex = "^load-generator$" + replacement = "testing" + } + + // Example: Sample profiles by service_name (drop 30% of services) + // rule { + // action = "hashmod" + // source_labels = ["service_name"] + // target_label = "__tmp_hash" + // modulus = 10 + //} + // rule { + // action = "drop" + // source_labels = ["__tmp_hash"] + // regex = "^(0|1|2)$" // Drop profiles from services that hash to 0-2 + // } + + forward_to = [pyroscope.write.backend.receiver] +} + +pyroscope.write "backend" { + endpoint { + url = "http://pyroscope:4040" + // url = "" + // basic_auth { + // username = "" + // password = "" + // } + } +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/docker-compose.yml b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/docker-compose.yml new file mode 100644 index 0000000000..c4e96c7315 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/docker-compose.yml @@ -0,0 +1,67 @@ +services: + us-east: + ports: + - 5000 + environment: + - REGION=us-east + - PYROSCOPE_SERVER_ADDRESS=http://alloy:9999 + - PARAMETERS_POOL_SIZE=1000 + - PARAMETERS_POOL_BUFFER_SIZE_KB=1000 + build: + context: . + eu-north: + ports: + - 5000 + environment: + - REGION=eu-north + - PYROSCOPE_SERVER_ADDRESS=http://alloy:9999 + build: + context: . + ap-south: + ports: + - 5000 + environment: + - REGION=ap-south + - PYROSCOPE_SERVER_ADDRESS=http://alloy:9999 + build: + context: . + + alloy: + image: grafana/alloy:v1.7.1 + command: + - run + - /etc/alloy/config.alloy + - --stability.level=public-preview + volumes: + - ./config.alloy:/etc/alloy/config.alloy + ports: + - "9999:9999" + - "12345:12345" + + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + load-generator: + build: + context: . + dockerfile: Dockerfile.load-generator + environment: + - PYROSCOPE_SERVER_ADDRESS=http://alloy:9999 + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.mod b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.mod new file mode 100644 index 0000000000..dc56688b76 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.mod @@ -0,0 +1,43 @@ +module rideshare + +go 1.25.0 + +toolchain go1.25.12 + +require ( + github.com/agoda-com/opentelemetry-logs-go v0.4.1 + github.com/grafana/otel-profiling-go v0.5.1 + github.com/grafana/pyroscope-go v1.2.7 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect +) diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.sum b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.sum new file mode 100644 index 0000000000..c4e9de0a6d --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.sum @@ -0,0 +1,99 @@ +github.com/agoda-com/opentelemetry-logs-go v0.4.1 h1:PWGqIxkEEg4HIjnHsHmNa+yGu0lhxHz4XPGKeT4o6T0= +github.com/agoda-com/opentelemetry-logs-go v0.4.1/go.mod h1:CeDuVaK9yCWN+8UjOW8AciYJE0rl7K/mw4ejBntGYkc= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= +github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= +github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= +github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.work b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.work new file mode 100644 index 0000000000..a860ee362f --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.work @@ -0,0 +1,3 @@ +go 1.25.0 + +use . diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.work.sum b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.work.sum new file mode 100644 index 0000000000..3310b330c5 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/go.work.sum @@ -0,0 +1,146 @@ +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= +github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/loadgen.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/loadgen.go new file mode 100644 index 0000000000..7dbcd92453 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/loadgen.go @@ -0,0 +1,140 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "net/http" + "os" + "strconv" + "time" + + otelpyroscope "github.com/grafana/otel-profiling-go" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/propagation" + + "rideshare/rideshare" +) + +var urls = []string{} + +var vehicles = []string{ + "bike", + "scooter", + "car", +} + +var client *http.Client + +func main() { + c := rideshare.ReadConfig() + c.AppName = "load-generator" + urls = os.Args[1:] + if len(urls) == 0 { + urls = []string{ + "http://us-east:5000", + "http://eu-north:5000", + "http://ap-south:5000", + } + } + + groupByFactor := 3 + if os.Getenv("LOADGEN_GROUP_BY_FACTOR") != "" { + var err error + groupByFactor, err = strconv.Atoi(os.Getenv("LOADGEN_GROUP_BY_FACTOR")) + if err != nil { + log.Fatalf("issue with LOADGEN_GROUP_BY_FACTOR: %v\n", err) + } + } + + // Configure profiler. + p, err := rideshare.Profiler(c) + if err != nil { + log.Fatalf("failed to initialize profiler: %v\n", err) + } + defer func() { + _ = p.Stop() + }() + + // Configure tracing. + tp, err := rideshare.TracerProvider(c) + if err != nil { + log.Fatalf("failed to initialize profiler: %v\n", err) + } + + // Set the Tracer Provider and the W3C Trace Context propagator as globals. + // We wrap the tracer provider to also annotate goroutines with Span ID so + // that pprof would add corresponding labels to profiling samples. + otel.SetTracerProvider(otelpyroscope.NewTracerProvider(tp)) + + // Register the trace c ontext and baggage propagators so data is propagated across services/processes. + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + client = &http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)} + + defer func() { + _ = tp.Shutdown(context.Background()) + }() + + groups := groupHosts(urls, groupByFactor) + for _, group := range groups { + go func(group []string) { + for { + host := group[rand.Intn(len(group))] + vehicle := vehicles[rand.Intn(len(vehicles))] + if err = orderVehicle(context.Background(), host, vehicle); err != nil { + fmt.Println(err) + } + } + }(group) + } + + select {} +} + +func groupHosts(hosts []string, groupsOf int) [][]string { + var res [][]string + for i := 0; i < len(hosts); i += groupsOf { + upperBoundary := i + groupsOf + if upperBoundary > len(hosts) { + upperBoundary = len(hosts) + } + res = append(res, hosts[i:upperBoundary]) + } + return res +} + +func orderVehicle(ctx context.Context, baseURL, vehicle string) error { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "OrderVehicle") + defer span.End() + + // Spend some time on CPU. + d := time.Duration(200+rand.Intn(200)) * time.Millisecond + begin := time.Now() + for { + if time.Now().Sub(begin) > d { + break + } + } + + span.SetAttributes(attribute.String("vehicle", vehicle)) + url := fmt.Sprintf("%s/%s", baseURL, vehicle) + fmt.Println("requesting", url) + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return err + } + resp, err := client.Do(req) + if err != nil { + return err + } + _ = resp.Body.Close() + return nil +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/main.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/main.go new file mode 100644 index 0000000000..711ba0d8c9 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + + "rideshare/bike" + "rideshare/car" + "rideshare/rideshare" + "rideshare/scooter" + "rideshare/utility" + + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + + otellogs "github.com/agoda-com/opentelemetry-logs-go" + otelpyroscope "github.com/grafana/otel-profiling-go" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + sdktrace "go.opentelemetry.io/otel/sdk/trace" +) + +func bikeRoute(w http.ResponseWriter, r *http.Request) { + bike.OrderBike(r.Context(), 1) + w.Write([]byte("

Bike ordered

")) +} + +func scooterRoute(w http.ResponseWriter, r *http.Request) { + scooter.OrderScooter(r.Context(), 2) + w.Write([]byte("

Scooter ordered

")) +} + +func carRoute(w http.ResponseWriter, r *http.Request) { + car.OrderCar(r.Context(), 3) + w.Write([]byte("

Car ordered

")) +} + +func index(w http.ResponseWriter, r *http.Request) { + rideshare.Log.Print(r.Context(), "showing index") + result := "

environment vars:

" + for _, env := range os.Environ() { + result += env + "
" + } + w.Write([]byte(result)) +} + +func main() { + config := rideshare.ReadConfig() + + tp, _ := setupOTEL(config) + defer func() { + _ = tp.Shutdown(context.Background()) + }() + + p, err := rideshare.Profiler(config) + + if err != nil { + log.Fatalf("error starting pyroscope profiler: %v", err) + } + defer func() { + _ = p.Stop() + }() + + cleanup := utility.InitWorkerPool(config) + defer cleanup() + + rideshare.Log.Print(context.Background(), "started ride-sharing app") + + http.Handle("/", otelhttp.NewHandler(http.HandlerFunc(index), "IndexHandler")) + http.Handle("/bike", otelhttp.NewHandler(http.HandlerFunc(bikeRoute), "BikeHandler")) + http.Handle("/scooter", otelhttp.NewHandler(http.HandlerFunc(scooterRoute), "ScooterHandler")) + http.Handle("/car", otelhttp.NewHandler(http.HandlerFunc(carRoute), "CarHandler")) + + addr := fmt.Sprintf(":%s", config.RideshareListenPort) + log.Fatal(http.ListenAndServe(addr, nil)) +} + +func setupOTEL(c rideshare.Config) (tp *sdktrace.TracerProvider, err error) { + tp, err = rideshare.TracerProvider(c) + if err != nil { + return nil, err + } + + lp, err := rideshare.LoggerProvider(c) + if err != nil { + return nil, err + } + otellogs.SetLoggerProvider(lp) + + const ( + instrumentationName = "otel/zap" + instrumentationVersion = "0.0.1" + ) + + // Set the Tracer Provider and the W3C Trace Context propagator as globals. + // We wrap the tracer provider to also annotate goroutines with Span ID so + // that pprof would add corresponding labels to profiling samples. + otel.SetTracerProvider(otelpyroscope.NewTracerProvider(tp)) + + // Register the trace context and baggage propagators so data is propagated across services/processes. + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + return tp, err +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/rideshare/rideshare.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/rideshare/rideshare.go new file mode 100644 index 0000000000..eaecea732d --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/rideshare/rideshare.go @@ -0,0 +1,272 @@ +package rideshare + +import ( + "context" + "encoding/base64" + "fmt" + "os" + "strconv" + "time" + + "github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs" + "github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs/otlplogshttp" + "github.com/agoda-com/opentelemetry-logs-go/exporters/stdout/stdoutlogs" + "github.com/agoda-com/opentelemetry-logs-go/logs" + sdklogs "github.com/agoda-com/opentelemetry-logs-go/sdk/logs" + "github.com/grafana/pyroscope-go" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.20.0" + "go.opentelemetry.io/otel/trace" +) + +type loggerAdapter struct { + logger logs.Logger +} + +func (la *loggerAdapter) Print(ctx context.Context, msg string) { + severityNumber := logs.INFO + now := time.Now() + c := logs.LogRecordConfig{ + ObservedTimestamp: now, + Timestamp: &now, + SeverityNumber: &severityNumber, + Body: &msg, + } + + span := trace.SpanFromContext(ctx) + if spanID := span.SpanContext().SpanID(); spanID.IsValid() { + c.SpanId = &spanID + } + if traceID := span.SpanContext().TraceID(); traceID.IsValid() { + c.TraceId = &traceID + } + la.logger.Emit(logs.NewLogRecord(c)) +} + +func (la *loggerAdapter) Printf(ctx context.Context, format string, v ...interface{}) { + la.Print(ctx, fmt.Sprintf(format, v...)) +} + +var Log = &loggerAdapter{logger: nil} + +type Config struct { + AppName string + PyroscopeServerAddress string + PyroscopeAuthToken string // for OG pyroscope and cloudstorage + PyroscopeBasicAuthUser string // for grafana + PyroscopeBasicAuthPassword string // for grafana + + OTLPUrl string + OTLPInsecure bool + OTLPBasicAuthUser string + OTLPBasicAuthPassword string + OTLPTracesUrlPath string + + UseDebugTracer bool + UseDebugLogger bool + Tags map[string]string + + ParametersPoolSize int + ParametersPoolBufferSize int + RideshareListenPort string +} + +func ReadConfig() Config { + appName := os.Getenv("PYROSCOPE_APPLICATION_NAME") + if appName == "" { + appName = "ride-sharing-app" + } + hostname, err := os.Hostname() + if err != nil { + hostname = "unknown" + } + c := Config{ + AppName: appName, + PyroscopeServerAddress: os.Getenv("PYROSCOPE_SERVER_ADDRESS"), + PyroscopeBasicAuthUser: os.Getenv("PYROSCOPE_BASIC_AUTH_USER"), + PyroscopeBasicAuthPassword: os.Getenv("PYROSCOPE_BASIC_AUTH_PASSWORD"), + + OTLPUrl: os.Getenv("OTLP_URL"), + OTLPInsecure: os.Getenv("OTLP_INSECURE") == "1", + OTLPBasicAuthUser: os.Getenv("OTLP_BASIC_AUTH_USER"), + OTLPBasicAuthPassword: os.Getenv("OTLP_BASIC_AUTH_PASSWORD"), + OTLPTracesUrlPath: os.Getenv("OTLP_TRACES_URL_PATH"), + + UseDebugTracer: os.Getenv("DEBUG_TRACER") == "1", + UseDebugLogger: os.Getenv("DEBUG_LOGGER") == "1", + Tags: map[string]string{ + "region": os.Getenv("REGION"), + "hostname": hostname, + "service_git_ref": "HEAD", + "service_repository": "https://github.com/grafana/pyroscope", + "service_root_path": "examples/language-sdk-instrumentation/golang-push/rideshare", + }, + + ParametersPoolSize: envIntOrDefault("PARAMETERS_POOL_SIZE", 1000), + + // Internally, we represent this as buffer size in bytes, but to make it + // more readable from as an env var, we represent the env var value in + // kb. + ParametersPoolBufferSize: envIntOrDefault("PARAMETERS_POOL_BUFFER_SIZE_KB", 1000) * 1000, + + RideshareListenPort: os.Getenv("RIDESHARE_LISTEN_PORT"), + } + if c.RideshareListenPort == "" { + c.RideshareListenPort = "5000" + } + if c.AppName == "" { + c.AppName = "ride-sharing-app" + } + if c.PyroscopeServerAddress == "" { + c.PyroscopeServerAddress = "http://localhost:4040" + } + return c +} + +func basicAuth(username, password string) string { + auth := username + ":" + password + return base64.StdEncoding.EncodeToString([]byte(auth)) +} + +func newResource(c Config, extraAttrs ...attribute.KeyValue) *resource.Resource { + host, _ := os.Hostname() + + attrs := append([]attribute.KeyValue{ + semconv.ServiceNameKey.String(c.AppName), + semconv.CloudRegionKey.String(os.Getenv("REGION")), + semconv.HostName(host), + }, extraAttrs...) + return resource.NewWithAttributes( + semconv.SchemaURL, + // Note that ServiceNameKey attribute can include chars not allowed in Pyroscope + // application name, therefore it should be used carefully. + attrs..., + ) +} + +func LoggerProvider(c Config) (*sdklogs.LoggerProvider, error) { + if c.UseDebugLogger || c.OTLPUrl == "" { + consoleProvider, err := stdoutlogs.NewExporter(stdoutlogs.WithWriter(os.Stderr)) + if err != nil { + return nil, err + } + loggerProvider := sdklogs.NewLoggerProvider( + sdklogs.WithBatcher(consoleProvider), + sdklogs.WithResource(newResource(c)), + ) + Log.logger = loggerProvider.Logger( + "ride-share", + logs.WithInstrumentationVersion("0.0.1"), + logs.WithSchemaURL(semconv.SchemaURL), + ) + return loggerProvider, nil + } + + exporter, _ := otlplogs.NewExporter(context.Background(), otlplogs.WithClient(otlplogshttp.NewClient( + otlplogshttp.WithEndpoint(c.OTLPUrl), + otlplogshttp.WithURLPath("/otlp/v1/logs"), + otlplogshttp.WithHeaders(map[string]string{ + "Authorization": "Basic " + basicAuth(c.OTLPBasicAuthUser, c.OTLPBasicAuthPassword), + }), + ))) + + // tell loki to use host.name and cloud.region as labels + lokiHint := attribute.KeyValue{ + Key: attribute.Key("loki.resource.labels"), + Value: attribute.StringSliceValue([]string{ + string(semconv.CloudRegionKey.String("").Key), + string(semconv.ServiceNameKey.String("").Key), + string(semconv.HostName("").Key), + }), + } + + loggerProvider := sdklogs.NewLoggerProvider( + sdklogs.WithBatcher(exporter), + sdklogs.WithResource(newResource(c, lokiHint)), + ) + + Log.logger = loggerProvider.Logger( + "ride-share", + logs.WithInstrumentationVersion("0.0.1"), + logs.WithSchemaURL(semconv.SchemaURL), + ) + + return loggerProvider, nil +} + +func TracerProvider(c Config) (*sdktrace.TracerProvider, error) { + if c.UseDebugTracer || c.OTLPUrl == "" { + return debugTracerProvider() + } + ctx := context.Background() + opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(c.OTLPUrl)} + if c.OTLPTracesUrlPath != "" { + opts = append(opts, otlptracehttp.WithURLPath(c.OTLPTracesUrlPath)) + } + if c.OTLPInsecure { + opts = append(opts, otlptracehttp.WithInsecure()) + } + if c.OTLPBasicAuthUser != "" { + opts = append(opts, otlptracehttp.WithHeaders(map[string]string{ + "Authorization": "Basic " + basicAuth(c.OTLPBasicAuthUser, c.OTLPBasicAuthPassword), + })) + } + + exp, err := otlptrace.New(ctx, otlptracehttp.NewClient(opts...)) + if err != nil { + return nil, err + } + + // Create a new tracer provider with a batch span processor and the otlp exporter. + tp2 := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exp), + sdktrace.WithResource(newResource(c)), + ) + + return tp2, nil +} + +func debugTracerProvider() (*sdktrace.TracerProvider, error) { + exp, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) + if err != nil { + return nil, err + } + return sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exp))), nil +} + +func Profiler(c Config) (*pyroscope.Profiler, error) { + config := pyroscope.Config{ + ApplicationName: c.AppName, + ServerAddress: c.PyroscopeServerAddress, + Logger: pyroscope.StandardLogger, + Tags: c.Tags, + } + if c.PyroscopeAuthToken != "" { + config.AuthToken = c.PyroscopeAuthToken + } else if c.PyroscopeBasicAuthUser != "" { + config.BasicAuthUser = c.PyroscopeBasicAuthUser + config.BasicAuthPassword = c.PyroscopeBasicAuthPassword + } + return pyroscope.Start(config) +} + +// envIntOrDefault looks up the environment variable key and returns the value +// as an int. +func envIntOrDefault(key string, fallback int) int { + s, ok := os.LookupEnv(key) + if !ok { + return fallback + } + + v, err := strconv.Atoi(s) + if err != nil { + return fallback + } + + return v +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/scooter/scooter.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/scooter/scooter.go new file mode 100644 index 0000000000..e6eb356526 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/scooter/scooter.go @@ -0,0 +1,12 @@ +package scooter + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderScooter(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering scooter, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "scooter") +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/utility/pool.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/utility/pool.go new file mode 100644 index 0000000000..8a650eeba1 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/utility/pool.go @@ -0,0 +1,92 @@ +package utility + +import ( + "os" + "sync" + + "rideshare/rideshare" +) + +type workerPool struct { + poolLock *sync.Mutex + pool []chan struct{} + limit int + bufferSize int +} + +// Run a function using a pool. +func (c *workerPool) Run(fn func()) { + if os.Getenv("REGION") != "us-east" { + // Only leak memory for us-east. If not us-east, run the worker + // function in a blocking manner. + + fn() + return + } + + stop := make(chan struct{}, 1) + done := make(chan struct{}, 1) + + c.poolLock.Lock() + size := len(c.pool) + if c.limit != 0 && size >= c.limit { + // We're at max pool limit, reset the pool. + c.resetWithoutLock() + } + c.pool = append(c.pool, stop) + c.poolLock.Unlock() + + // Create a goroutine to run the function. It will write to done when the + // work is over, but won't clean up until it receives a signal from stop. + go c.doWork(fn, stop, done) + + // Block until the worker signals it's done. + <-done + close(done) +} + +// Closes the pool, cleaning up all resources. +func (c *workerPool) Close() { + c.poolLock.Lock() + defer c.poolLock.Unlock() + + c.resetWithoutLock() +} + +func (c *workerPool) resetWithoutLock() { + for _, c := range c.pool { + c <- struct{}{} + close(c) + } + c.pool = c.pool[:0] +} + +func (c *workerPool) doWork(fn func(), stop <-chan struct{}, done chan<- struct{}) { + buf := make([]byte, 0) + + // Do work. + fn() + + // Simulate the work in fn requiring some data to be added to a buffer. + for i := 0; i < c.bufferSize; i++ { + buf = append(buf, byte(i)) + } + + // Don't let the compiler optimize away the buf. + var _ = buf + + // Signal we're done working. + done <- struct{}{} + + // Block until we're told to clean up. + <-stop +} + +func newPool(c rideshare.Config) *workerPool { + return &workerPool{ + poolLock: &sync.Mutex{}, + pool: make([]chan struct{}, 0, c.ParametersPoolSize), + limit: c.ParametersPoolSize, + bufferSize: c.ParametersPoolBufferSize, + } +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/utility/utility.go b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/utility/utility.go new file mode 100644 index 0000000000..dbc0b64dcb --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-alloy/utility/utility.go @@ -0,0 +1,75 @@ +package utility + +import ( + "context" + "os" + "time" + + "rideshare/rideshare" + + "github.com/grafana/pyroscope-go" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" +) + +const durationConstant = time.Duration(200 * time.Millisecond) + +var pool *workerPool + +// InitWorkPool initializes the worker pool and returns a clean up function. +func InitWorkerPool(c rideshare.Config) func() { + pool = newPool(c) + return pool.Close +} + +func mutexLock(n int64) { + var i int64 = 0 + + // start time is number of seconds since epoch + startTime := time.Now() + + // This changes the amplitude of cpu bars + for time.Since(startTime) < time.Duration(n*30)*durationConstant { + i++ + } +} + +func checkDriverAvailability(n int64) { + var i int64 = 0 + + // start time is number of seconds since epoch + startTime := time.Now() + + pool.Run(func() { + for time.Since(startTime) < time.Duration(n)*durationConstant { + i++ + } + }) + + // Every other minute this will artificially create make requests in eu-north region slow + // this is just for demonstration purposes to show how performance impacts show up in the + // flamegraph + force_mutex_lock := time.Now().Minute()%2 == 0 + if os.Getenv("REGION") == "eu-north" && force_mutex_lock { + mutexLock(n) + } +} + +func FindNearestVehicle(ctx context.Context, searchRadius int64, vehicle string) { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "FindNearestVehicle") + span.SetAttributes(attribute.String("vehicle", vehicle)) + defer span.End() + + pyroscope.TagWrapper(ctx, pyroscope.Labels("vehicle", vehicle), func(ctx context.Context) { + var i int64 = 0 + + startTime := time.Now() + for time.Since(startTime) < time.Duration(searchRadius)*durationConstant { + i++ + } + + if vehicle == "car" { + checkDriverAvailability(searchRadius) + } + }) +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/Dockerfile b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/Dockerfile new file mode 100644 index 0000000000..37517ecd28 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/Dockerfile @@ -0,0 +1,6 @@ +FROM golang:1.25.12 + +WORKDIR /go/src/app +COPY . . +RUN go build main.go +CMD ["./main"] diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/Dockerfile.load-generator b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/Dockerfile.load-generator new file mode 100644 index 0000000000..eb16110dcd --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/Dockerfile.load-generator @@ -0,0 +1,6 @@ +FROM golang:1.25.12 + +WORKDIR /go/src/app +COPY . . +RUN go build loadgen.go +CMD ["./loadgen"] diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/README.md b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/README.md new file mode 100644 index 0000000000..f8b59d10b4 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/README.md @@ -0,0 +1,34 @@ +# Pyroscope k6 integration + +This example demonstrates Pyroscope's k6 integration. This example requires k6 +to be installed. To install k6, see: https://grafana.com/docs/k6/latest/set-up/install-k6/. + +## Running the example + +To run the example, use the following command to start all the necessary services. + +``` +docker compose up +``` + +This includes the following services: + +- A Pyroscope server (http://localhost:4040) +- Grafana instance with the Profiles Drilldown app and a Pyroscope data source installed (http://localhost:3000) +- An nginx load balancer for the Rideshare services (http://localhost:5001) + +> [!NOTE] +> We use nginx as a load balancer for the Rideshare services to simplify the +> load test script. Without nginx, the k6 load test would need to be aware of +> each Rideshare instance, resulting in tests with unnecessary boilerplate which +> would generally not be seen in the real world. + +Once Docker Compose is running, use the following command to execute a k6 load +test against the Rideshare service. + +``` +k6 run load.js +``` + +Finally, navigate to http://localhost:3000 and open the Profiles Drilldown app. After a small delay, k6 test metadata should begin to appears as labels on the +"ride-sharing-app" application tile. diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/bike/bike.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/bike/bike.go new file mode 100644 index 0000000000..98ad8325fb --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/bike/bike.go @@ -0,0 +1,12 @@ +package bike + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderBike(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering bike, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "bike") +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/car/car.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/car/car.go new file mode 100644 index 0000000000..16898fb8ea --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/car/car.go @@ -0,0 +1,12 @@ +package car + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderCar(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering car, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "car") +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/docker-compose.yml b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/docker-compose.yml new file mode 100644 index 0000000000..f0740bc7b1 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/docker-compose.yml @@ -0,0 +1,69 @@ +services: + us-east: + ports: + - 5000 + environment: + - REGION=us-east + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - PARAMETERS_POOL_SIZE=1000 + - PARAMETERS_POOL_BUFFER_SIZE_KB=1000 + build: + context: . + eu-north: + ports: + - 5000 + environment: + - REGION=eu-north + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + build: + context: . + ap-south: + ports: + - 5000 + environment: + - REGION=ap-south + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + build: + context: . + + nginx: + image: nginx:latest + ports: + - 5001:80 + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + depends_on: + - us-east + - eu-north + - ap-south + + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + load-generator: + build: + context: . + dockerfile: Dockerfile.load-generator + environment: + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - RIDESHARE_URL=http://nginx:80 + - VUS=1 + - SLEEP=500ms + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.mod b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.mod new file mode 100644 index 0000000000..a6d34d7f9f --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.mod @@ -0,0 +1,44 @@ +module rideshare + +go 1.25.0 + +toolchain go1.25.12 + +require ( + github.com/agoda-com/opentelemetry-logs-go v0.4.1 + github.com/grafana/otel-profiling-go v0.5.1 + github.com/grafana/pyroscope-go v1.2.7 + github.com/grafana/pyroscope-go/x/k6 v0.0.0-20241129154546-3e89ad952d8f + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect +) diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.sum b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.sum new file mode 100644 index 0000000000..392d0da60d --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.sum @@ -0,0 +1,101 @@ +github.com/agoda-com/opentelemetry-logs-go v0.4.1 h1:PWGqIxkEEg4HIjnHsHmNa+yGu0lhxHz4XPGKeT4o6T0= +github.com/agoda-com/opentelemetry-logs-go v0.4.1/go.mod h1:CeDuVaK9yCWN+8UjOW8AciYJE0rl7K/mw4ejBntGYkc= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= +github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= +github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= +github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grafana/pyroscope-go/x/k6 v0.0.0-20241129154546-3e89ad952d8f h1:5v8jrCB7XCFPo4tXxqHyYbJfuRxTdCtkWYwGW54qpfM= +github.com/grafana/pyroscope-go/x/k6 v0.0.0-20241129154546-3e89ad952d8f/go.mod h1:nfbW6/4ke3ywlqLb+Zgr9t1z9Zv3m+2ImUp+vbkzHpc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.work b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.work new file mode 100644 index 0000000000..a860ee362f --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.work @@ -0,0 +1,3 @@ +go 1.25.0 + +use . diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.work.sum b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.work.sum new file mode 100644 index 0000000000..2df5366298 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/go.work.sum @@ -0,0 +1,310 @@ +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 h1:QfV5XZt6iNa2aWMAt96CZEbfJ7kgG/qYIpq465Shr5E= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/KimMachineGun/automemlimit v0.5.0 h1:BeOe+BbJc8L5chL3OwzVYjVzyvPALdd5wxVVOWuUZmQ= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= +github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/aws/aws-sdk-go v1.50.0 h1:HBtrLeO+QyDKnc3t1+5DR1RxodOHCGr8ZcrHudpv7jI= +github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= +github.com/digitalocean/godo v1.108.0 h1:fWyMENvtxpCpva1UbKzOFnyAS04N1FNuBWWfPeTGquQ= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/docker/docker v25.0.0+incompatible h1:g9b6wZTblhMgzOT2tspESstfw6ySZ9kdm94BLDKaZac= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= +github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= +github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= +github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= +github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc= +github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= +github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hetznercloud/hcloud-go/v2 v2.6.0 h1:RJOA2hHZ7rD1pScA4O1NF6qhkHyUdbbxjHgFNot8928= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/linode/linodego v1.27.1 h1:KoQm5g2fppw8qIClJqUEL0yKH0+f+7te3Mewagb5QKE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc= +github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= +github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= +github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= +github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 h1:wJrcTdddKOI8TFxs8cemnhKP2EmKy3yfUKHj3ZdfzYo= +github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opentelemetry.io/collector/featuregate v1.0.1 h1:ok//hLSXttBbyu4sSV1pTx1nKdr5udSmrWy5sFMIIbM= +go.opentelemetry.io/collector/pdata v1.0.1 h1:dGX2h7maA6zHbl5D3AsMnF1c3Nn+3EUftbVCLzeyNvA= +go.opentelemetry.io/collector/semconv v0.93.0 h1:eBlMcVNTwYYsVdAsCVDs4wvVYs75K1xcIDpqj16PG4c= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +google.golang.org/api v0.157.0 h1:ORAeqmbrrozeyw5NjnMxh7peHO0UzV4wWYSwZeCUb20= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +k8s.io/api v0.28.6 h1:yy6u9CuIhmg55YvF/BavPBBXB+5QicB64njJXxVnzLo= +k8s.io/apimachinery v0.28.6 h1:RsTeR4z6S07srPg6XYrwXpTJVMXsjPXn0ODakMytSW0= +k8s.io/client-go v0.28.6 h1:Gge6ziyIdafRchfoBKcpaARuz7jfrK1R1azuwORIsQI= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/grafana-provisioning/pyroscope/config.yml b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/grafana-provisioning/pyroscope/config.yml new file mode 100644 index 0000000000..257748221e --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/grafana-provisioning/pyroscope/config.yml @@ -0,0 +1,2 @@ +self_profiling: + use_k6_middleware: true diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/load.js b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/load.js new file mode 100644 index 0000000000..7d993d13b2 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/load.js @@ -0,0 +1,25 @@ +import http from 'k6/http'; +import { check } from 'k6'; +import pyroscope from 'https://jslib.k6.io/http-instrumentation-pyroscope/1.0.1/index.js'; + +pyroscope.instrumentHTTP(); + +export let options = { + vus: 3, + duration: '1m', +}; + +export default function () { + const vehicles = [ + 'car', + 'scooter', + 'bike', + ]; + + for (const v of vehicles) { + const req = http.get(`http://localhost:5001/${v}`); + check(req, { + 'status is 200': (r) => r.status === 200, + }); + } +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/loadgen.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/loadgen.go new file mode 100644 index 0000000000..f2a2050a8c --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/loadgen.go @@ -0,0 +1,143 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + otelpyroscope "github.com/grafana/otel-profiling-go" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/propagation" + + "rideshare/rideshare" + "rideshare/utility" +) + +var vehicles = []string{ + "bike", + "scooter", + "car", +} + +var client *http.Client + +func main() { + c := rideshare.ReadConfig() + c.AppName = "load-generator" + + url, ok := os.LookupEnv("RIDESHARE_URL") + if !ok { + log.Fatalf("RIDESHARE_URL is not set") + } + + vus := utility.EnvIntOrDefault("VUS", 1) + jitter := utility.EnvDurationOrDefault("JITTER", 100*time.Millisecond) + sleep := utility.EnvDurationOrDefault("SLEEP", 100*time.Millisecond) + + // Configure profiler. + p, err := rideshare.Profiler(c) + if err != nil { + log.Fatalf("failed to initialize profiler: %v\n", err) + } + defer func() { + _ = p.Stop() + }() + + // Configure tracing. + tp, err := rideshare.TracerProvider(c) + if err != nil { + log.Fatalf("failed to initialize profiler: %v\n", err) + } + + // Set the Tracer Provider and the W3C Trace Context propagator as globals. + // We wrap the tracer provider to also annotate goroutines with Span ID so + // that pprof would add corresponding labels to profiling samples. + otel.SetTracerProvider(otelpyroscope.NewTracerProvider(tp)) + + // Register the trace context and baggage propagators so data is propagated + // across services/processes. + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + client = &http.Client{ + Transport: otelhttp.NewTransport(http.DefaultTransport), + } + + defer func() { + _ = tp.Shutdown(context.Background()) + }() + + doneChs := make([]chan struct{}, vus) + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT) + + for i := 0; i < vus; i++ { + doneChs[i] = make(chan struct{}) + + go func(done <-chan struct{}) { + for { + select { + case <-done: + return + default: + err := sendThrottledRequest(context.Background(), url, sleep, jitter) + if err != nil { + log.Printf("failed to send request to %s: %v", url, err) + } + } + } + }(doneChs[i]) + } + + <-sig + for _, done := range doneChs { + close(done) + } +} + +func sendThrottledRequest(ctx context.Context, baseURL string, sleep time.Duration, jitter time.Duration) error { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "SendRequest") + defer span.End() + + vehicle := vehicles[rand.Intn(len(vehicles))] + err := orderVehicle(ctx, baseURL, vehicle) + if err != nil { + return fmt.Errorf("failed to order %s: %v", vehicle, err) + } + + jitter = time.Duration(rand.Intn(int(jitter))) + time.Sleep(sleep + jitter) + return nil +} + +func orderVehicle(ctx context.Context, baseURL, vehicle string) error { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "OrderVehicle") + defer span.End() + + span.SetAttributes(attribute.String("vehicle", vehicle)) + url := fmt.Sprintf("%s/%s", baseURL, vehicle) + log.Printf("requesting %s", url) + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return err + } + + resp, err := client.Do(req) + if err != nil { + return err + } + + _ = resp.Body.Close() + return nil +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/main.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/main.go new file mode 100644 index 0000000000..a44756b060 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/main.go @@ -0,0 +1,143 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + + "rideshare/bike" + "rideshare/car" + "rideshare/rideshare" + "rideshare/scooter" + "rideshare/utility" + + otellogs "github.com/agoda-com/opentelemetry-logs-go" + otelpyroscope "github.com/grafana/otel-profiling-go" + "github.com/grafana/pyroscope-go/x/k6" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + sdktrace "go.opentelemetry.io/otel/sdk/trace" +) + +func bikeRoute(w http.ResponseWriter, r *http.Request) { + bike.OrderBike(r.Context(), 1) + w.Write([]byte("

Bike ordered

")) +} + +func scooterRoute(w http.ResponseWriter, r *http.Request) { + scooter.OrderScooter(r.Context(), 2) + w.Write([]byte("

Scooter ordered

")) +} + +func carRoute(w http.ResponseWriter, r *http.Request) { + car.OrderCar(r.Context(), 3) + w.Write([]byte("

Car ordered

")) +} + +func index(w http.ResponseWriter, r *http.Request) { + rideshare.Log.Print(r.Context(), "showing index") + result := "

environment vars:

" + for _, env := range os.Environ() { + result += env + "
" + } + w.Write([]byte(result)) +} + +func main() { + config := rideshare.ReadConfig() + + tp, _ := setupOTEL(config) + defer func() { + _ = tp.Shutdown(context.Background()) + }() + + p, err := rideshare.Profiler(config) + + if err != nil { + log.Fatalf("error starting pyroscope profiler: %v", err) + } + defer func() { + _ = p.Stop() + }() + + cleanup := utility.InitWorkerPool(config) + defer cleanup() + + rideshare.Log.Print(context.Background(), "started ride-sharing app") + + routes := []route{ + {"/", "IndexHandler", http.HandlerFunc(index)}, + {"/bike", "BikeHandler", http.HandlerFunc(bikeRoute)}, + {"/scooter", "ScooterHandler", http.HandlerFunc(scooterRoute)}, + {"/car", "CarHandler", http.HandlerFunc(carRoute)}, + } + + routes = applyOtelMiddleware(routes) + routes = applyK6Middleware(routes) + registerRoutes(http.DefaultServeMux, routes) + + addr := fmt.Sprintf(":%s", config.RideshareListenPort) + log.Fatal(http.ListenAndServe(addr, nil)) +} + +func setupOTEL(c rideshare.Config) (tp *sdktrace.TracerProvider, err error) { + tp, err = rideshare.TracerProvider(c) + if err != nil { + return nil, err + } + + lp, err := rideshare.LoggerProvider(c) + if err != nil { + return nil, err + } + otellogs.SetLoggerProvider(lp) + + const ( + instrumentationName = "otel/zap" + instrumentationVersion = "0.0.1" + ) + + // Set the Tracer Provider and the W3C Trace Context propagator as globals. + // We wrap the tracer provider to also annotate goroutines with Span ID so + // that pprof would add corresponding labels to profiling samples. + otel.SetTracerProvider(otelpyroscope.NewTracerProvider(tp)) + + // Register the trace context and baggage propagators so data is propagated across services/processes. + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + return tp, err +} + +type route struct { + Path string + Name string + Handler http.Handler +} + +func registerRoutes(mux *http.ServeMux, handlers []route) { + for _, handler := range handlers { + mux.Handle(handler.Path, handler.Handler) + } +} + +func applyOtelMiddleware(routes []route) []route { + for i, route := range routes { + routes[i].Handler = otelhttp.NewHandler(route.Handler, route.Name) + } + return routes +} + +// applyK6Middleware adds the k6 instrumentation middleware to all routes. This +// enables the Pyroscope SDK to label the profiles with k6 test metadata. +func applyK6Middleware(routes []route) []route { + for i, route := range routes { + routes[i].Handler = k6.LabelsFromBaggageHandler(route.Handler) + } + return routes +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/nginx.conf b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/nginx.conf new file mode 100644 index 0000000000..f92dcfc43a --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/nginx.conf @@ -0,0 +1,23 @@ +events {} + +http { + upstream backend_servers { + random; + + server us-east:5000; + server eu-north:5000; + server ap-south:5000; + } + + server { + listen 80; + + location / { + proxy_pass http://backend_servers/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/rideshare/rideshare.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/rideshare/rideshare.go new file mode 100644 index 0000000000..c43b27fee9 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/rideshare/rideshare.go @@ -0,0 +1,279 @@ +package rideshare + +import ( + "context" + "encoding/base64" + "fmt" + "os" + "strconv" + "time" + + "github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs" + "github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs/otlplogshttp" + "github.com/agoda-com/opentelemetry-logs-go/exporters/stdout/stdoutlogs" + "github.com/agoda-com/opentelemetry-logs-go/logs" + sdklogs "github.com/agoda-com/opentelemetry-logs-go/sdk/logs" + "github.com/grafana/pyroscope-go" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.20.0" + "go.opentelemetry.io/otel/trace" +) + +type loggerAdapter struct { + logger logs.Logger +} + +func (la *loggerAdapter) Print(ctx context.Context, msg string) { + severityNumber := logs.INFO + now := time.Now() + c := logs.LogRecordConfig{ + ObservedTimestamp: now, + Timestamp: &now, + SeverityNumber: &severityNumber, + Body: &msg, + } + + span := trace.SpanFromContext(ctx) + if spanID := span.SpanContext().SpanID(); spanID.IsValid() { + c.SpanId = &spanID + } + if traceID := span.SpanContext().TraceID(); traceID.IsValid() { + c.TraceId = &traceID + } + la.logger.Emit(logs.NewLogRecord(c)) +} + +func (la *loggerAdapter) Printf(ctx context.Context, format string, v ...interface{}) { + la.Print(ctx, fmt.Sprintf(format, v...)) +} + +var Log = &loggerAdapter{logger: nil} + +type Config struct { + AppName string + PyroscopeServerAddress string + PyroscopeAuthToken string // for OG pyroscope and cloudstorage + PyroscopeBasicAuthUser string // for grafana + PyroscopeBasicAuthPassword string // for grafana + + OTLPUrl string + OTLPInsecure bool + OTLPBasicAuthUser string + OTLPBasicAuthPassword string + OTLPTracesUrlPath string + + UseDebugTracer bool + UseDebugLogger bool + Tags map[string]string + + ParametersPoolSize int + ParametersPoolBufferSize int + RideshareListenPort string +} + +func ReadConfig() Config { + appName := os.Getenv("PYROSCOPE_APPLICATION_NAME") + if appName == "" { + appName = "ride-sharing-app" + } + hostname, err := os.Hostname() + if err != nil { + hostname = "unknown" + } + c := Config{ + AppName: appName, + PyroscopeServerAddress: os.Getenv("PYROSCOPE_SERVER_ADDRESS"), + PyroscopeBasicAuthUser: os.Getenv("PYROSCOPE_BASIC_AUTH_USER"), + PyroscopeBasicAuthPassword: os.Getenv("PYROSCOPE_BASIC_AUTH_PASSWORD"), + + OTLPUrl: os.Getenv("OTLP_URL"), + OTLPInsecure: os.Getenv("OTLP_INSECURE") == "1", + OTLPBasicAuthUser: os.Getenv("OTLP_BASIC_AUTH_USER"), + OTLPBasicAuthPassword: os.Getenv("OTLP_BASIC_AUTH_PASSWORD"), + OTLPTracesUrlPath: os.Getenv("OTLP_TRACES_URL_PATH"), + + UseDebugTracer: os.Getenv("DEBUG_TRACER") == "1", + UseDebugLogger: os.Getenv("DEBUG_LOGGER") == "1", + Tags: map[string]string{ + "region": os.Getenv("REGION"), + "hostname": hostname, + "service_git_ref": "HEAD", + "service_repository": "https://github.com/grafana/pyroscope", + "service_root_path": "examples/language-sdk-instrumentation/golang-push/rideshare", + }, + + ParametersPoolSize: envIntOrDefault("PARAMETERS_POOL_SIZE", 1000), + + // Internally, we represent this as buffer size in bytes, but to make it + // more readable from as an env var, we represent the env var value in + // kb. + ParametersPoolBufferSize: envIntOrDefault("PARAMETERS_POOL_BUFFER_SIZE_KB", 1000) * 1000, + + RideshareListenPort: os.Getenv("RIDESHARE_LISTEN_PORT"), + } + if c.RideshareListenPort == "" { + c.RideshareListenPort = "5000" + } + if c.AppName == "" { + c.AppName = "ride-sharing-app" + } + if c.PyroscopeServerAddress == "" { + c.PyroscopeServerAddress = "http://localhost:4040" + } + return c +} + +func basicAuth(username, password string) string { + auth := username + ":" + password + return base64.StdEncoding.EncodeToString([]byte(auth)) +} + +func newResource(c Config, extraAttrs ...attribute.KeyValue) *resource.Resource { + host, _ := os.Hostname() + + attrs := append([]attribute.KeyValue{ + semconv.ServiceNameKey.String(c.AppName), + semconv.CloudRegionKey.String(os.Getenv("REGION")), + semconv.HostName(host), + }, extraAttrs...) + return resource.NewWithAttributes( + semconv.SchemaURL, + // Note that ServiceNameKey attribute can include chars not allowed in Pyroscope + // application name, therefore it should be used carefully. + attrs..., + ) +} + +func LoggerProvider(c Config) (*sdklogs.LoggerProvider, error) { + if c.UseDebugLogger || c.OTLPUrl == "" { + consoleProvider, err := stdoutlogs.NewExporter(stdoutlogs.WithWriter(os.Stderr)) + if err != nil { + return nil, err + } + loggerProvider := sdklogs.NewLoggerProvider( + sdklogs.WithBatcher(consoleProvider), + sdklogs.WithResource(newResource(c)), + ) + Log.logger = loggerProvider.Logger( + "ride-share", + logs.WithInstrumentationVersion("0.0.1"), + logs.WithSchemaURL(semconv.SchemaURL), + ) + return loggerProvider, nil + } + + exporter, _ := otlplogs.NewExporter(context.Background(), otlplogs.WithClient(otlplogshttp.NewClient( + otlplogshttp.WithEndpoint(c.OTLPUrl), + otlplogshttp.WithURLPath("/otlp/v1/logs"), + otlplogshttp.WithHeaders(map[string]string{ + "Authorization": "Basic " + basicAuth(c.OTLPBasicAuthUser, c.OTLPBasicAuthPassword), + }), + ))) + + // tell loki to use host.name and cloud.region as labels + lokiHint := attribute.KeyValue{ + Key: attribute.Key("loki.resource.labels"), + Value: attribute.StringSliceValue([]string{ + string(semconv.CloudRegionKey.String("").Key), + string(semconv.ServiceNameKey.String("").Key), + string(semconv.HostName("").Key), + }), + } + + loggerProvider := sdklogs.NewLoggerProvider( + sdklogs.WithBatcher(exporter), + sdklogs.WithResource(newResource(c, lokiHint)), + ) + + Log.logger = loggerProvider.Logger( + "ride-share", + logs.WithInstrumentationVersion("0.0.1"), + logs.WithSchemaURL(semconv.SchemaURL), + ) + + return loggerProvider, nil +} + +func TracerProvider(c Config) (*sdktrace.TracerProvider, error) { + if c.OTLPUrl == "" { + return stdoutTracerProvider(c.UseDebugTracer) + } + + ctx := context.Background() + opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(c.OTLPUrl)} + if c.OTLPTracesUrlPath != "" { + opts = append(opts, otlptracehttp.WithURLPath(c.OTLPTracesUrlPath)) + } + + if c.OTLPInsecure { + opts = append(opts, otlptracehttp.WithInsecure()) + } + + if c.OTLPBasicAuthUser != "" { + opts = append(opts, otlptracehttp.WithHeaders(map[string]string{ + "Authorization": "Basic " + basicAuth(c.OTLPBasicAuthUser, c.OTLPBasicAuthPassword), + })) + } + + exp, err := otlptrace.New(ctx, otlptracehttp.NewClient(opts...)) + if err != nil { + return nil, err + } + + // Create a new tracer provider with a batch span processor and the otlp exporter. + tp2 := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exp), + sdktrace.WithResource(newResource(c)), + ) + + return tp2, nil +} + +func stdoutTracerProvider(debug bool) (*sdktrace.TracerProvider, error) { + if !debug { + return sdktrace.NewTracerProvider(), nil + } + + exp, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) + if err != nil { + return nil, err + } + return sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exp))), nil +} + +func Profiler(c Config) (*pyroscope.Profiler, error) { + config := pyroscope.Config{ + ApplicationName: c.AppName, + ServerAddress: c.PyroscopeServerAddress, + Logger: pyroscope.StandardLogger, + Tags: c.Tags, + } + if c.PyroscopeAuthToken != "" { + config.AuthToken = c.PyroscopeAuthToken + } else if c.PyroscopeBasicAuthUser != "" { + config.BasicAuthUser = c.PyroscopeBasicAuthUser + config.BasicAuthPassword = c.PyroscopeBasicAuthPassword + } + return pyroscope.Start(config) +} + +// envIntOrDefault looks up the environment variable key and returns the value +// as an int. +func envIntOrDefault(key string, fallback int) int { + s, ok := os.LookupEnv(key) + if !ok { + return fallback + } + + v, err := strconv.Atoi(s) + if err != nil { + return fallback + } + + return v +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/scooter/scooter.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/scooter/scooter.go new file mode 100644 index 0000000000..e6eb356526 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/scooter/scooter.go @@ -0,0 +1,12 @@ +package scooter + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderScooter(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering scooter, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "scooter") +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/pool.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/pool.go new file mode 100644 index 0000000000..8a650eeba1 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/pool.go @@ -0,0 +1,92 @@ +package utility + +import ( + "os" + "sync" + + "rideshare/rideshare" +) + +type workerPool struct { + poolLock *sync.Mutex + pool []chan struct{} + limit int + bufferSize int +} + +// Run a function using a pool. +func (c *workerPool) Run(fn func()) { + if os.Getenv("REGION") != "us-east" { + // Only leak memory for us-east. If not us-east, run the worker + // function in a blocking manner. + + fn() + return + } + + stop := make(chan struct{}, 1) + done := make(chan struct{}, 1) + + c.poolLock.Lock() + size := len(c.pool) + if c.limit != 0 && size >= c.limit { + // We're at max pool limit, reset the pool. + c.resetWithoutLock() + } + c.pool = append(c.pool, stop) + c.poolLock.Unlock() + + // Create a goroutine to run the function. It will write to done when the + // work is over, but won't clean up until it receives a signal from stop. + go c.doWork(fn, stop, done) + + // Block until the worker signals it's done. + <-done + close(done) +} + +// Closes the pool, cleaning up all resources. +func (c *workerPool) Close() { + c.poolLock.Lock() + defer c.poolLock.Unlock() + + c.resetWithoutLock() +} + +func (c *workerPool) resetWithoutLock() { + for _, c := range c.pool { + c <- struct{}{} + close(c) + } + c.pool = c.pool[:0] +} + +func (c *workerPool) doWork(fn func(), stop <-chan struct{}, done chan<- struct{}) { + buf := make([]byte, 0) + + // Do work. + fn() + + // Simulate the work in fn requiring some data to be added to a buffer. + for i := 0; i < c.bufferSize; i++ { + buf = append(buf, byte(i)) + } + + // Don't let the compiler optimize away the buf. + var _ = buf + + // Signal we're done working. + done <- struct{}{} + + // Block until we're told to clean up. + <-stop +} + +func newPool(c rideshare.Config) *workerPool { + return &workerPool{ + poolLock: &sync.Mutex{}, + pool: make([]chan struct{}, 0, c.ParametersPoolSize), + limit: c.ParametersPoolSize, + bufferSize: c.ParametersPoolBufferSize, + } +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/util.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/util.go new file mode 100644 index 0000000000..eb5660d5ac --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/util.go @@ -0,0 +1,35 @@ +package utility + +import ( + "os" + "strconv" + "time" +) + +func EnvIntOrDefault(name string, n int) int { + s, ok := os.LookupEnv(name) + if !ok { + return n + } + + v, err := strconv.Atoi(s) + if err != nil { + return n + } + + return v +} + +func EnvDurationOrDefault(name string, d time.Duration) time.Duration { + s, ok := os.LookupEnv(name) + if !ok { + return d + } + + v, err := time.ParseDuration(s) + if err != nil { + return d + } + + return v +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/utility.go b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/utility.go new file mode 100644 index 0000000000..dbc0b64dcb --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare-k6/utility/utility.go @@ -0,0 +1,75 @@ +package utility + +import ( + "context" + "os" + "time" + + "rideshare/rideshare" + + "github.com/grafana/pyroscope-go" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" +) + +const durationConstant = time.Duration(200 * time.Millisecond) + +var pool *workerPool + +// InitWorkPool initializes the worker pool and returns a clean up function. +func InitWorkerPool(c rideshare.Config) func() { + pool = newPool(c) + return pool.Close +} + +func mutexLock(n int64) { + var i int64 = 0 + + // start time is number of seconds since epoch + startTime := time.Now() + + // This changes the amplitude of cpu bars + for time.Since(startTime) < time.Duration(n*30)*durationConstant { + i++ + } +} + +func checkDriverAvailability(n int64) { + var i int64 = 0 + + // start time is number of seconds since epoch + startTime := time.Now() + + pool.Run(func() { + for time.Since(startTime) < time.Duration(n)*durationConstant { + i++ + } + }) + + // Every other minute this will artificially create make requests in eu-north region slow + // this is just for demonstration purposes to show how performance impacts show up in the + // flamegraph + force_mutex_lock := time.Now().Minute()%2 == 0 + if os.Getenv("REGION") == "eu-north" && force_mutex_lock { + mutexLock(n) + } +} + +func FindNearestVehicle(ctx context.Context, searchRadius int64, vehicle string) { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "FindNearestVehicle") + span.SetAttributes(attribute.String("vehicle", vehicle)) + defer span.End() + + pyroscope.TagWrapper(ctx, pyroscope.Labels("vehicle", vehicle), func(ctx context.Context) { + var i int64 = 0 + + startTime := time.Now() + for time.Since(startTime) < time.Duration(searchRadius)*durationConstant { + i++ + } + + if vehicle == "car" { + checkDriverAvailability(searchRadius) + } + }) +} diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile b/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile index f30447a7f9..37517ecd28 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21.10 +FROM golang:1.25.12 WORKDIR /go/src/app COPY . . diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile.load-generator b/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile.load-generator index 5e7ae449d8..eb16110dcd 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile.load-generator +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/Dockerfile.load-generator @@ -1,4 +1,4 @@ -FROM golang:1.21.10 +FROM golang:1.25.12 WORKDIR /go/src/app COPY . . diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/README.md b/examples/language-sdk-instrumentation/golang-push/rideshare/README.md index 1b3de44cf1..9822ba1253 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/README.md +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/README.md @@ -2,8 +2,9 @@ To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: docker-compose up --build diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/docker-compose.yml b/examples/language-sdk-instrumentation/golang-push/rideshare/docker-compose.yml index 43d3249c12..41a5544f85 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/docker-compose.yml +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/docker-compose.yml @@ -1,43 +1,79 @@ -version: "3" services: us-east: + container_name: us-east ports: - - 5000 + - 5000 environment: - - REGION=us-east - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 - - PARAMETERS_POOL_SIZE=1000 - - PARAMETERS_POOL_BUFFER_SIZE_KB=1000 + - REGION=us-east + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - PARAMETERS_POOL_SIZE=1000 + - PARAMETERS_POOL_BUFFER_SIZE_KB=1000 + - OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf + - OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://prometheus:9090/api/v1/otlp/v1/metrics build: context: . - eu-north: + container_name: eu-north ports: - - 5000 + - 5000 environment: - - REGION=eu-north - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 - + - REGION=eu-north + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf + - OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://prometheus:9090/api/v1/otlp/v1/metrics build: context: . - ap-south: + container_name: ap-south ports: - - 5000 + - 5000 environment: - - REGION=ap-south - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - REGION=ap-south + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf + - OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://prometheus:9090/api/v1/otlp/v1/metrics build: context: . - pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 load-generator: build: context: . dockerfile: Dockerfile.load-generator environment: - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf + - OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://prometheus:9090/api/v1/otlp/v1/metrics + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 + prometheus: + # This service is generated from examples/_templates/prometheus/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: prom/prometheus:v3.1.0 + ports: + - '9099:9090' + command: > + --enable-feature=remote-write-receiver + --enable-feature=exemplar-storage + --enable-feature=native-histograms + --config.file=/etc/prometheus/prometheus.yml + --storage.tsdb.path=/prometheus + --web.enable-otlp-receiver + volumes: + - ./prometheus-provisioning/prometheus.yaml:/etc/prometheus/prometheus.yml diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/go.mod b/examples/language-sdk-instrumentation/golang-push/rideshare/go.mod index 2e28f44778..ba05a368bc 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/go.mod +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/go.mod @@ -1,39 +1,50 @@ module rideshare -go 1.17 +go 1.25.0 + +toolchain go1.25.12 require ( - github.com/agoda-com/opentelemetry-logs-go v0.4.1 + github.com/agoda-com/opentelemetry-logs-go v0.5.1 github.com/grafana/otel-profiling-go v0.5.1 - github.com/grafana/pyroscope-go v1.1.1 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 - go.opentelemetry.io/otel v1.22.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0 - go.opentelemetry.io/otel/sdk v1.22.0 - go.opentelemetry.io/otel/trace v1.22.0 + github.com/grafana/pyroscope-go v1.3.1 + github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/common v0.62.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 + go.opentelemetry.io/otel/metric v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 + go.opentelemetry.io/otel/sdk/metric v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 ) require ( - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.7 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect - github.com/klauspost/compress v1.17.4 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect - go.uber.org/goleak v1.3.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/grpc v1.61.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.11 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/klauspost/compress v1.18.6 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/go.sum b/examples/language-sdk-instrumentation/golang-push/rideshare/go.sum index 8d7a9b76d5..78e093c1aa 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/go.sum +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/go.sum @@ -1,2375 +1,115 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= -cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= -cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= -cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= -cloud.google.com/go/accessapproval v1.7.2/go.mod h1:/gShiq9/kK/h8T/eEn1BTzalDvk0mZxJlhfw0p+Xuc0= -cloud.google.com/go/accessapproval v1.7.3/go.mod h1:4l8+pwIxGTNqSf4T3ds8nLO94NQf0W/KnMNuQ9PbnP8= -cloud.google.com/go/accessapproval v1.7.4/go.mod h1:/aTEh45LzplQgFYdQdwPMR9YdX0UlhBmvB84uAmQKUc= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= -cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= -cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= -cloud.google.com/go/accesscontextmanager v1.8.2/go.mod h1:E6/SCRM30elQJ2PKtFMs2YhfJpZSNcJyejhuzoId4Zk= -cloud.google.com/go/accesscontextmanager v1.8.3/go.mod h1:4i/JkF2JiFbhLnnpnfoTX5vRXfhf9ukhU1ANOTALTOQ= -cloud.google.com/go/accesscontextmanager v1.8.4/go.mod h1:ParU+WbMpD34s5JFEnGAnPBYAgUHozaTmDJU7aCU9+M= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= -cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= -cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.1/go.mod h1:kY3nIMAVQOK2XDqDPHaOuD9e+FdMA6OOpfBjsvaFSOo= -cloud.google.com/go/aiplatform v1.51.2/go.mod h1:hCqVYB3mY45w99TmetEoe8eCQEwZEp9WHxeZdcv9phw= -cloud.google.com/go/aiplatform v1.52.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.54.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.57.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.58.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= -cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.4/go.mod h1:zZgNCxLCy8b2rKKVfC1YkC2vTrpfZmeRCySM3aUbskA= -cloud.google.com/go/analytics v0.21.5/go.mod h1:BQtOBHWTlJ96axpPPnw5CvGJ6i3Ve/qX2fTxR8qWyr8= -cloud.google.com/go/analytics v0.21.6/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= -cloud.google.com/go/apigateway v1.6.2/go.mod h1:CwMC90nnZElorCW63P2pAYm25AtQrHfuOkbRSHj0bT8= -cloud.google.com/go/apigateway v1.6.3/go.mod h1:k68PXWpEs6BVDTtnLQAyG606Q3mz8pshItwPXjgv44Y= -cloud.google.com/go/apigateway v1.6.4/go.mod h1:0EpJlVGH5HwAN4VF4Iec8TAzGN1aQgbxAWGJsnPCGGY= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= -cloud.google.com/go/apigeeconnect v1.6.2/go.mod h1:s6O0CgXT9RgAxlq3DLXvG8riw8PYYbU/v25jqP3Dy18= -cloud.google.com/go/apigeeconnect v1.6.3/go.mod h1:peG0HFQ0si2bN15M6QSjEW/W7Gy3NYkWGz7pFz13cbo= -cloud.google.com/go/apigeeconnect v1.6.4/go.mod h1:CapQCWZ8TCjnU0d7PobxhpOdVz/OVJ2Hr/Zcuu1xFx0= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= -cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= -cloud.google.com/go/apigeeregistry v0.7.2/go.mod h1:9CA2B2+TGsPKtfi3F7/1ncCCsL62NXBRfM6iPoGSM+8= -cloud.google.com/go/apigeeregistry v0.8.1/go.mod h1:MW4ig1N4JZQsXmBSwH4rwpgDonocz7FPBSw6XPGHmYw= -cloud.google.com/go/apigeeregistry v0.8.2/go.mod h1:h4v11TDGdeXJDJvImtgK2AFVvMIgGWjSb0HRnBSjcX8= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= -cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= -cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= -cloud.google.com/go/appengine v1.8.2/go.mod h1:WMeJV9oZ51pvclqFN2PqHoGnys7rK0rz6s3Mp6yMvDo= -cloud.google.com/go/appengine v1.8.3/go.mod h1:2oUPZ1LVZ5EXi+AF1ihNAF+S8JrzQ3till5m9VQkrsk= -cloud.google.com/go/appengine v1.8.4/go.mod h1:TZ24v+wXBujtkK77CXCpjZbnuTvsFNT41MUaZ28D6vg= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= -cloud.google.com/go/area120 v0.8.2/go.mod h1:a5qfo+x77SRLXnCynFWPUZhnZGeSgvQ+Y0v1kSItkh4= -cloud.google.com/go/area120 v0.8.3/go.mod h1:5zj6pMzVTH+SVHljdSKC35sriR/CVvQZzG/Icdyriw0= -cloud.google.com/go/area120 v0.8.4/go.mod h1:jfawXjxf29wyBXr48+W+GyX/f8fflxp642D/bb9v68M= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= -cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= -cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= -cloud.google.com/go/artifactregistry v1.14.2/go.mod h1:Xk+QbsKEb0ElmyeMfdHAey41B+qBq3q5R5f5xD4XT3U= -cloud.google.com/go/artifactregistry v1.14.3/go.mod h1:A2/E9GXnsyXl7GUvQ/2CjHA+mVRoWAXC0brg2os+kNI= -cloud.google.com/go/artifactregistry v1.14.4/go.mod h1:SJJcZTMv6ce0LDMUnihCN7WSrI+kBSFV0KIKo8S8aYU= -cloud.google.com/go/artifactregistry v1.14.6/go.mod h1:np9LSFotNWHcjnOgh8UVK0RFPCTUGbO0ve3384xyHfE= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= -cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= -cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= -cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+okxFECHcg= -cloud.google.com/go/asset v1.15.1/go.mod h1:yX/amTvFWRpp5rcFq6XbCxzKT8RJUam1UoboE179jU4= -cloud.google.com/go/asset v1.15.2/go.mod h1:B6H5tclkXvXz7PD22qCA2TDxSVQfasa3iDlM89O2NXs= -cloud.google.com/go/asset v1.15.3/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.16.0/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/assuredworkloads v1.11.2/go.mod h1:O1dfr+oZJMlE6mw0Bp0P1KZSlj5SghMBvTpZqIcUAW4= -cloud.google.com/go/assuredworkloads v1.11.3/go.mod h1:vEjfTKYyRUaIeA0bsGJceFV2JKpVRgyG2op3jfa59Zs= -cloud.google.com/go/assuredworkloads v1.11.4/go.mod h1:4pwwGNwy1RP0m+y12ef3Q/8PaiWrIDQ6nD2E8kvWI9U= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= -cloud.google.com/go/automl v1.13.2/go.mod h1:gNY/fUmDEN40sP8amAX3MaXkxcqPIn7F1UIIPZpy4Mg= -cloud.google.com/go/automl v1.13.3/go.mod h1:Y8KwvyAZFOsMAPqUCfNu1AyclbC6ivCUF/MTwORymyY= -cloud.google.com/go/automl v1.13.4/go.mod h1:ULqwX/OLZ4hBVfKQaMtxMSTlPx0GqGbWN8uA/1EqCP8= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= -cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= -cloud.google.com/go/baremetalsolution v1.2.1/go.mod h1:3qKpKIw12RPXStwQXcbhfxVj1dqQGEvcmA+SX/mUR88= -cloud.google.com/go/baremetalsolution v1.2.2/go.mod h1:O5V6Uu1vzVelYahKfwEWRMaS3AbCkeYHy3145s1FkhM= -cloud.google.com/go/baremetalsolution v1.2.3/go.mod h1:/UAQ5xG3faDdy180rCUv47e0jvpp3BFxT+Cl0PFjw5g= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= -cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.1/go.mod h1:RpBuIYLkQu8+CWDk3dFD/t/jOCGuUpkpX+Y0n1Xccs8= -cloud.google.com/go/batch v1.6.1/go.mod h1:urdpD13zPe6YOK+6iZs/8/x2VBRofvblLpx0t57vM98= -cloud.google.com/go/batch v1.6.3/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= -cloud.google.com/go/batch v1.7.0/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= -cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= -cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.1/go.mod h1:zl/rWWAFVeV+kx+X2Javly7o1EIQThU4WlkynffL/lk= -cloud.google.com/go/beyondcorp v1.0.2/go.mod h1:m8cpG7caD+5su+1eZr+TSvF6r21NdLJk4f9u4SP2Ntc= -cloud.google.com/go/beyondcorp v1.0.3/go.mod h1:HcBvnEd7eYr+HGDd5ZbuVmBYX019C6CEXBonXbCVwJo= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= -cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= -cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= -cloud.google.com/go/bigquery v1.56.0/go.mod h1:KDcsploXTEY7XT3fDQzMUZlpQLHzE4itubHrnmhUrZA= -cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= -cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= -cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.2/go.mod h1:u/AdV/3wr3xoRBk5xvUzYMS1IawOAPwQMuHgHMdljDg= -cloud.google.com/go/billing v1.17.3/go.mod h1:z83AkoZ7mZwBGT3yTnt6rSGI1OOsHSIi6a5M3mJ8NaU= -cloud.google.com/go/billing v1.17.4/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= -cloud.google.com/go/billing v1.18.0/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= -cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= -cloud.google.com/go/binaryauthorization v1.7.1/go.mod h1:GTAyfRWYgcbsP3NJogpV3yeunbUIjx2T9xVeYovtURE= -cloud.google.com/go/binaryauthorization v1.7.2/go.mod h1:kFK5fQtxEp97m92ziy+hbu+uKocka1qRRL8MVJIgjv0= -cloud.google.com/go/binaryauthorization v1.7.3/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= -cloud.google.com/go/binaryauthorization v1.8.0/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= -cloud.google.com/go/certificatemanager v1.7.2/go.mod h1:15SYTDQMd00kdoW0+XY5d9e+JbOPjp24AvF48D8BbcQ= -cloud.google.com/go/certificatemanager v1.7.3/go.mod h1:T/sZYuC30PTag0TLo28VedIRIj1KPGcOQzjWAptHa00= -cloud.google.com/go/certificatemanager v1.7.4/go.mod h1:FHAylPe/6IIKuaRmHbjbdLhGhVQ+CWHSD5Jq0k4+cCE= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= -cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= -cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= -cloud.google.com/go/channel v1.17.1/go.mod h1:xqfzcOZAcP4b/hUDH0GkGg1Sd5to6di1HOJn/pi5uBQ= -cloud.google.com/go/channel v1.17.2/go.mod h1:aT2LhnftnyfQceFql5I/mP8mIbiiJS4lWqgXA815zMk= -cloud.google.com/go/channel v1.17.3/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= -cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.1/go.mod h1:K7wGc/3zfvmYWOWwYTgF/d/UVJhS4pu+HAy7PL7mCsU= -cloud.google.com/go/cloudbuild v1.14.2/go.mod h1:Bn6RO0mBYk8Vlrt+8NLrru7WXlQ9/RDWz2uo5KG1/sg= -cloud.google.com/go/cloudbuild v1.14.3/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= -cloud.google.com/go/cloudbuild v1.15.0/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= -cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= -cloud.google.com/go/clouddms v1.7.1/go.mod h1:o4SR8U95+P7gZ/TX+YbJxehOCsM+fe6/brlrFquiszk= -cloud.google.com/go/clouddms v1.7.2/go.mod h1:Rk32TmWmHo64XqDvW7jgkFQet1tUKNVzs7oajtJT3jU= -cloud.google.com/go/clouddms v1.7.3/go.mod h1:fkN2HQQNUYInAU3NQ3vRLkV2iWs8lIdmBKOx4nrL6Hc= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= -cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.2/go.mod h1:A7nYkjNlW2gUoROg1kvJrQGhJP/38UaWwsnuBDOBVUk= -cloud.google.com/go/cloudtasks v1.12.3/go.mod h1:GPVXhIOSGEaR+3xT4Fp72ScI+HjHffSS4B8+BaBB5Ys= -cloud.google.com/go/cloudtasks v1.12.4/go.mod h1:BEPu0Gtt2dU6FxZHNqqNdGqIG86qyWKBPGnsb7udGY0= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJKSFOnQruhC5Lj9bZqWMTKiU= -cloud.google.com/go/contactcenterinsights v1.11.1/go.mod h1:FeNP3Kg8iteKM80lMwSk3zZZKVxr+PGnAId6soKuXwE= -cloud.google.com/go/contactcenterinsights v1.11.2/go.mod h1:A9PIR5ov5cRcd28KlDbmmXE8Aay+Gccer2h4wzkYFso= -cloud.google.com/go/contactcenterinsights v1.11.3/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.12.0/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.12.1/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= -cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= -cloud.google.com/go/container v1.26.1/go.mod h1:5smONjPRUxeEpDG7bMKWfDL4sauswqEtnBK1/KKpR04= -cloud.google.com/go/container v1.26.2/go.mod h1:YlO84xCt5xupVbLaMY4s3XNE79MUJ+49VmkInr6HvF4= -cloud.google.com/go/container v1.27.1/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.28.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.29.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= -cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= -cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= -cloud.google.com/go/containeranalysis v0.11.1/go.mod h1:rYlUOM7nem1OJMKwE1SadufX0JP3wnXj844EtZAwWLY= -cloud.google.com/go/containeranalysis v0.11.2/go.mod h1:xibioGBC1MD2j4reTyV1xY1/MvKaz+fyM9ENWhmIeP8= -cloud.google.com/go/containeranalysis v0.11.3/go.mod h1:kMeST7yWFQMGjiG9K7Eov+fPNQcGhb8mXj/UcTiWw9U= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= -cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= -cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.1/go.mod h1:TzAWaz+ON1tkNr4MOcak8EBHX7wIRX/gZKM+yTVsv+A= -cloud.google.com/go/datacatalog v1.18.2/go.mod h1:SPVgWW2WEMuWHA+fHodYjmxPiMqcOiWfhc9OD5msigk= -cloud.google.com/go/datacatalog v1.18.3/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= -cloud.google.com/go/datacatalog v1.19.0/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= -cloud.google.com/go/dataflow v0.9.2/go.mod h1:vBfdBZ/ejlTaYIGB3zB4T08UshH70vbtZeMD+urnUSo= -cloud.google.com/go/dataflow v0.9.3/go.mod h1:HI4kMVjcHGTs3jTHW/kv3501YW+eloiJSLxkJa/vqFE= -cloud.google.com/go/dataflow v0.9.4/go.mod h1:4G8vAkHYCSzU8b/kmsoR2lWyHJD85oMJPHMtan40K8w= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= -cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= -cloud.google.com/go/dataform v0.8.2/go.mod h1:X9RIqDs6NbGPLR80tnYoPNiO1w0wenKTb8PxxlhTMKM= -cloud.google.com/go/dataform v0.8.3/go.mod h1:8nI/tvv5Fso0drO3pEjtowz58lodx8MVkdV2q0aPlqg= -cloud.google.com/go/dataform v0.9.1/go.mod h1:pWTg+zGQ7i16pyn0bS1ruqIE91SdL2FDMvEYu/8oQxs= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= -cloud.google.com/go/datafusion v1.7.2/go.mod h1:62K2NEC6DRlpNmI43WHMWf9Vg/YvN6QVi8EVwifElI0= -cloud.google.com/go/datafusion v1.7.3/go.mod h1:eoLt1uFXKGBq48jy9LZ+Is8EAVLnmn50lNncLzwYokE= -cloud.google.com/go/datafusion v1.7.4/go.mod h1:BBs78WTOLYkT4GVZIXQCZT3GFpkpDN4aBY4NDX/jVlM= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= -cloud.google.com/go/datalabeling v0.8.2/go.mod h1:cyDvGHuJWu9U/cLDA7d8sb9a0tWLEletStu2sTmg3BE= -cloud.google.com/go/datalabeling v0.8.3/go.mod h1:tvPhpGyS/V7lqjmb3V0TaDdGvhzgR1JoW7G2bpi2UTI= -cloud.google.com/go/datalabeling v0.8.4/go.mod h1:Z1z3E6LHtffBGrNUkKwbwbDxTiXEApLzIgmymj8A3S8= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= -cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.10.1/go.mod h1:1MzmBv8FvjYfc7vDdxhnLFNskikkB+3vl475/XdCDhs= -cloud.google.com/go/dataplex v1.10.2/go.mod h1:xdC8URdTrCrZMW6keY779ZT1cTOfV8KEPNsw+LTRT1Y= -cloud.google.com/go/dataplex v1.11.1/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.11.2/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.13.0/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= -cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= -cloud.google.com/go/dataproc/v2 v2.2.1/go.mod h1:QdAJLaBjh+l4PVlVZcmrmhGccosY/omC1qwfQ61Zv/o= -cloud.google.com/go/dataproc/v2 v2.2.2/go.mod h1:aocQywVmQVF4i8CL740rNI/ZRpsaaC1Wh2++BJ7HEJ4= -cloud.google.com/go/dataproc/v2 v2.2.3/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= -cloud.google.com/go/dataproc/v2 v2.3.0/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= -cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= -cloud.google.com/go/dataqna v0.8.2/go.mod h1:KNEqgx8TTmUipnQsScOoDpq/VlXVptUqVMZnt30WAPs= -cloud.google.com/go/dataqna v0.8.3/go.mod h1:wXNBW2uvc9e7Gl5k8adyAMnLush1KVV6lZUhB+rqNu4= -cloud.google.com/go/dataqna v0.8.4/go.mod h1:mySRKjKg5Lz784P6sCov3p1QD+RZQONRMRjzGNcFd0c= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= -cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= -cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.1/go.mod h1:7ngSYwnw95YFyTd5tOGBxHlOZiL+OtpjheqU7t2/s/c= -cloud.google.com/go/datastream v1.10.2/go.mod h1:W42TFgKAs/om6x/CdXX5E4oiAsKlH+e8MTGy81zdYt0= -cloud.google.com/go/datastream v1.10.3/go.mod h1:YR0USzgjhqA/Id0Ycu1VvZe8hEWwrkjuXrGbzeDOSEA= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= -cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.1/go.mod h1:8jeadyLkH9qu9xgO3hVWw8jVr29N1mnW42gRJT8GY6g= -cloud.google.com/go/deploy v1.14.1/go.mod h1:N8S0b+aIHSEeSr5ORVoC0+/mOPUysVt8ae4QkZYolAw= -cloud.google.com/go/deploy v1.14.2/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.15.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.16.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= -cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.1/go.mod h1:n/h+/N2ouKOO+rbe/ZnI186xImpqvCVj2DdsWS/0EAk= -cloud.google.com/go/dialogflow v1.44.2/go.mod h1:QzFYndeJhpVPElnFkUXxdlptx0wPnBWLCBT9BvtC3/c= -cloud.google.com/go/dialogflow v1.44.3/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.47.0/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= -cloud.google.com/go/dlp v1.10.2/go.mod h1:ZbdKIhcnyhILgccwVDzkwqybthh7+MplGC3kZVZsIOQ= -cloud.google.com/go/dlp v1.10.3/go.mod h1:iUaTc/ln8I+QT6Ai5vmuwfw8fqTk2kaz0FvCwhLCom0= -cloud.google.com/go/dlp v1.11.1/go.mod h1:/PA2EnioBeXTL/0hInwgj0rfsQb3lpE3R8XUJxqUNKI= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= -cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.2/go.mod h1:Q/wcRT+qnuXOpjAkvOV4A+IeQl04q2/ReT7SSbytLSo= -cloud.google.com/go/documentai v1.23.4/go.mod h1:4MYAaEMnADPN1LPN5xboDR5QVB6AgsaxgFdJhitlE2Y= -cloud.google.com/go/documentai v1.23.5/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.6/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.7/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= -cloud.google.com/go/domains v0.9.2/go.mod h1:3YvXGYzZG1Temjbk7EyGCuGGiXHJwVNmwIf+E/cUp5I= -cloud.google.com/go/domains v0.9.3/go.mod h1:29k66YNDLDY9LCFKpGFeh6Nj9r62ZKm5EsUJxAl84KU= -cloud.google.com/go/domains v0.9.4/go.mod h1:27jmJGShuXYdUNjyDG0SodTfT5RwLi7xmH334Gvi3fY= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= -cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= -cloud.google.com/go/edgecontainer v1.1.2/go.mod h1:wQRjIzqxEs9e9wrtle4hQPSR1Y51kqN75dgF7UllZZ4= -cloud.google.com/go/edgecontainer v1.1.3/go.mod h1:Ll2DtIABzEfaxaVSbwj3QHFaOOovlDFiWVDu349jSsA= -cloud.google.com/go/edgecontainer v1.1.4/go.mod h1:AvFdVuZuVGdgaE5YvlL1faAoa1ndRR/5XhXZvPBHbsE= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= -cloud.google.com/go/essentialcontacts v1.6.3/go.mod h1:yiPCD7f2TkP82oJEFXFTou8Jl8L6LBRPeBEkTaO0Ggo= -cloud.google.com/go/essentialcontacts v1.6.4/go.mod h1:iju5Vy3d9tJUg0PYMd1nHhjV7xoCXaOAVabrwLaPBEM= -cloud.google.com/go/essentialcontacts v1.6.5/go.mod h1:jjYbPzw0x+yglXC890l6ECJWdYeZ5dlYACTFL0U/VuM= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= -cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.1/go.mod h1:EqBxmGHFrruIara4FUQ3RHlgfCn7yo1HYsu2Hpt/C3Y= -cloud.google.com/go/eventarc v1.13.2/go.mod h1:X9A80ShVu19fb4e5sc/OLV7mpFUKZMwfJFeeWhcIObM= -cloud.google.com/go/eventarc v1.13.3/go.mod h1:RWH10IAZIRcj1s/vClXkBgMHwh59ts7hSWcqD3kaclg= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= -cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= -cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= -cloud.google.com/go/filestore v1.7.2/go.mod h1:TYOlyJs25f/omgj+vY7/tIG/E7BX369triSPzE4LdgE= -cloud.google.com/go/filestore v1.7.3/go.mod h1:Qp8WaEERR3cSkxToxFPHh/b8AACkSut+4qlCjAmKTV0= -cloud.google.com/go/filestore v1.7.4/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= -cloud.google.com/go/filestore v1.8.0/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.12.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= -cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= -cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= -cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= -cloud.google.com/go/functions v1.15.2/go.mod h1:CHAjtcR6OU4XF2HuiVeriEdELNcnvRZSk1Q8RMqy4lE= -cloud.google.com/go/functions v1.15.3/go.mod h1:r/AMHwBheapkkySEhiZYLDBwVJCdlRwsm4ieJu35/Ug= -cloud.google.com/go/functions v1.15.4/go.mod h1:CAsTc3VlRMVvx+XqXxKqVevguqJpnVip4DdonFsX28I= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.2/go.mod h1:OMZbXzEJloyXMC7gqdSB+EOEQ1AKcpGYvO3s1ec5ixk= -cloud.google.com/go/gkebackup v1.3.3/go.mod h1:eMk7/wVV5P22KBakhQnJxWSVftL1p4VBFLpv0kIft7I= -cloud.google.com/go/gkebackup v1.3.4/go.mod h1:gLVlbM8h/nHIs09ns1qx3q3eaXcGSELgNu1DWXYz1HI= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= -cloud.google.com/go/gkeconnect v0.8.2/go.mod h1:6nAVhwchBJYgQCXD2pHBFQNiJNyAd/wyxljpaa6ZPrY= -cloud.google.com/go/gkeconnect v0.8.3/go.mod h1:i9GDTrfzBSUZGCe98qSu1B8YB8qfapT57PenIb820Jo= -cloud.google.com/go/gkeconnect v0.8.4/go.mod h1:84hZz4UMlDCKl8ifVW8layK4WHlMAFeq8vbzjU0yJkw= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= -cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= -cloud.google.com/go/gkehub v0.14.2/go.mod h1:iyjYH23XzAxSdhrbmfoQdePnlMj2EWcvnR+tHdBQsCY= -cloud.google.com/go/gkehub v0.14.3/go.mod h1:jAl6WafkHHW18qgq7kqcrXYzN08hXeK/Va3utN8VKg8= -cloud.google.com/go/gkehub v0.14.4/go.mod h1:Xispfu2MqnnFt8rV/2/3o73SK1snL8s9dYJ9G2oQMfc= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.1/go.mod h1:AcrGoin6VLKT/fwZEYuqvVominLriQBCKmbjtnbMjG8= -cloud.google.com/go/gkemulticloud v1.0.2/go.mod h1:+ee5VXxKb3H1l4LZAcgWB/rvI16VTNTrInWxDjAGsGo= -cloud.google.com/go/gkemulticloud v1.0.3/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= -cloud.google.com/go/gsuiteaddons v1.6.2/go.mod h1:K65m9XSgs8hTF3X9nNTPi8IQueljSdYo9F+Mi+s4MyU= -cloud.google.com/go/gsuiteaddons v1.6.3/go.mod h1:sCFJkZoMrLZT3JTb8uJqgKPNshH2tfXeCwTFRebTq48= -cloud.google.com/go/gsuiteaddons v1.6.4/go.mod h1:rxtstw7Fx22uLOXBpsvb9DUbC+fiXs7rF4U29KHM/pE= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= -cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= -cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= -cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= -cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= -cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= -cloud.google.com/go/iap v1.9.1/go.mod h1:SIAkY7cGMLohLSdBR25BuIxO+I4fXJiL06IBL7cy/5Q= -cloud.google.com/go/iap v1.9.2/go.mod h1:GwDTOs047PPSnwRD0Us5FKf4WDRcVvHg1q9WVkKBhdI= -cloud.google.com/go/iap v1.9.3/go.mod h1:DTdutSZBqkkOm2HEOTBzhZxh2mwwxshfD/h3yofAiCw= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= -cloud.google.com/go/ids v1.4.2/go.mod h1:3vw8DX6YddRu9BncxuzMyWn0g8+ooUjI2gslJ7FH3vk= -cloud.google.com/go/ids v1.4.3/go.mod h1:9CXPqI3GedjmkjbMWCUhMZ2P2N7TUMzAkVXYEH2orYU= -cloud.google.com/go/ids v1.4.4/go.mod h1:z+WUc2eEl6S/1aZWzwtVNWoSZslgzPxAboS0lZX0HjI= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= -cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= -cloud.google.com/go/iot v1.7.2/go.mod h1:q+0P5zr1wRFpw7/MOgDXrG/HVA+l+cSwdObffkrpnSg= -cloud.google.com/go/iot v1.7.3/go.mod h1:t8itFchkol4VgNbHnIq9lXoOOtHNR3uAACQMYbN9N4I= -cloud.google.com/go/iot v1.7.4/go.mod h1:3TWqDVvsddYBG++nHSZmluoCAVGr1hAcabbWZNKEZLk= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= -cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= -cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= -cloud.google.com/go/kms v1.15.3/go.mod h1:AJdXqHxS2GlPyduM99s9iGqi2nwbviBbhV/hdmt4iOQ= -cloud.google.com/go/kms v1.15.4/go.mod h1:L3Sdj6QTHK8dfwK5D1JLsAyELsNMnd3tAIwGS4ltKpc= -cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= -cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= -cloud.google.com/go/language v1.11.1/go.mod h1:Xyid9MG9WOX3utvDbpX7j3tXDmmDooMyMDqgUVpH17U= -cloud.google.com/go/language v1.12.1/go.mod h1:zQhalE2QlQIxbKIZt54IASBzmZpN/aDASea5zl1l+J4= -cloud.google.com/go/language v1.12.2/go.mod h1:9idWapzr/JKXBBQ4lWqVX/hcadxB194ry20m/bTrhWc= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= -cloud.google.com/go/lifesciences v0.9.2/go.mod h1:QHEOO4tDzcSAzeJg7s2qwnLM2ji8IRpQl4p6m5Z9yTA= -cloud.google.com/go/lifesciences v0.9.3/go.mod h1:gNGBOJV80IWZdkd+xz4GQj4mbqaz737SCLHn2aRhQKM= -cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqNj+Nia7hF0Z7JA= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= -cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= -cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= -cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= -cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= -cloud.google.com/go/longrunning v0.5.3/go.mod h1:y/0ga59EYu58J6SHmmQOvekvND2qODbu8ywBBW7EK7Y= -cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= -cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8= -cloud.google.com/go/managedidentities v1.6.3/go.mod h1:tewiat9WLyFN0Fi7q1fDD5+0N4VUoL0SCX0OTCthZq4= -cloud.google.com/go/managedidentities v1.6.4/go.mod h1:WgyaECfHmF00t/1Uk8Oun3CQ2PGUtjc3e9Alh79wyiM= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= -cloud.google.com/go/maps v1.3.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.1/go.mod h1:BxSa0BnW1g2U2gNdbq5zikLlHUuHW0GFWh7sgML2kIY= -cloud.google.com/go/maps v1.5.1/go.mod h1:NPMZw1LJwQZYCfz4y+EIw+SI+24A4bpdFJqdKVr0lt4= -cloud.google.com/go/maps v1.6.1/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= -cloud.google.com/go/maps v1.6.2/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= -cloud.google.com/go/mediatranslation v0.8.2/go.mod h1:c9pUaDRLkgHRx3irYE5ZC8tfXGrMYwNZdmDqKMSfFp8= -cloud.google.com/go/mediatranslation v0.8.3/go.mod h1:F9OnXTy336rteOEywtY7FOqCk+J43o2RF638hkOQl4Y= -cloud.google.com/go/mediatranslation v0.8.4/go.mod h1:9WstgtNVAdN53m6TQa5GjIjLqKQPXe74hwSCxUP6nj4= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= -cloud.google.com/go/memcache v1.10.2/go.mod h1:f9ZzJHLBrmd4BkguIAa/l/Vle6uTHzHokdnzSWOdQ6A= -cloud.google.com/go/memcache v1.10.3/go.mod h1:6z89A41MT2DVAW0P4iIRdu5cmRTsbsFn4cyiIx8gbwo= -cloud.google.com/go/memcache v1.10.4/go.mod h1:v/d8PuC8d1gD6Yn5+I3INzLR01IDn0N4Ym56RgikSI0= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.13.0/go.mod h1:URDhpG6XLeh5K+Glq0NOt74OfrPKTwS62gEPZzb5SOk= -cloud.google.com/go/metastore v1.13.1/go.mod h1:IbF62JLxuZmhItCppcIfzBBfUFq0DIB9HPDoLgWrVOU= -cloud.google.com/go/metastore v1.13.2/go.mod h1:KS59dD+unBji/kFebVp8XU/quNSyo8b6N6tPGspKszA= -cloud.google.com/go/metastore v1.13.3/go.mod h1:K+wdjXdtkdk7AQg4+sXS8bRrQa9gcOr+foOMF2tqINE= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= -cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= -cloud.google.com/go/monitoring v1.16.1/go.mod h1:6HsxddR+3y9j+o/cMJH6q/KJ/CBTvM/38L/1m7bTRJ4= -cloud.google.com/go/monitoring v1.16.2/go.mod h1:B44KGwi4ZCF8Rk/5n+FWeispDXoKSk9oss2QNlXJBgc= -cloud.google.com/go/monitoring v1.16.3/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= -cloud.google.com/go/monitoring v1.17.0/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= -cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= -cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.1/go.mod h1:LyGPXR742uQcDxZ/wv4EI0Vu5N6NKJ77ZYVnDe69Zug= -cloud.google.com/go/networkconnectivity v1.14.2/go.mod h1:5UFlwIisZylSkGG1AdwK/WZUaoz12PKu6wODwIbFzJo= -cloud.google.com/go/networkconnectivity v1.14.3/go.mod h1:4aoeFdrJpYEXNvrnfyD5kIzs8YtHg945Og4koAjHQek= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= -cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= -cloud.google.com/go/networkmanagement v1.9.1/go.mod h1:CCSYgrQQvW73EJawO2QamemYcOb57LvrDdDU51F0mcI= -cloud.google.com/go/networkmanagement v1.9.2/go.mod h1:iDGvGzAoYRghhp4j2Cji7sF899GnfGQcQRQwgVOWnDw= -cloud.google.com/go/networkmanagement v1.9.3/go.mod h1:y7WMO1bRLaP5h3Obm4tey+NquUvB93Co1oh4wpL+XcU= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= -cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= -cloud.google.com/go/networksecurity v0.9.2/go.mod h1:jG0SeAttWzPMUILEHDUvFYdQTl8L/E/KC8iZDj85lEI= -cloud.google.com/go/networksecurity v0.9.3/go.mod h1:l+C0ynM6P+KV9YjOnx+kk5IZqMSLccdBqW6GUoF4p/0= -cloud.google.com/go/networksecurity v0.9.4/go.mod h1:E9CeMZ2zDsNBkr8axKSYm8XyTqNhiCHf1JO/Vb8mD1w= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= -cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= -cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= -cloud.google.com/go/notebooks v1.10.1/go.mod h1:5PdJc2SgAybE76kFQCWrTfJolCOUQXF97e+gteUUA6A= -cloud.google.com/go/notebooks v1.11.1/go.mod h1:V2Zkv8wX9kDCGRJqYoI+bQAaoVeE5kSiz4yYHd2yJwQ= -cloud.google.com/go/notebooks v1.11.2/go.mod h1:z0tlHI/lREXC8BS2mIsUeR3agM1AkgLiS+Isov3SS70= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= -cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= -cloud.google.com/go/optimization v1.5.1/go.mod h1:NC0gnUD5MWVAF7XLdoYVPmYYVth93Q6BUzqAq3ZwtV8= -cloud.google.com/go/optimization v1.6.1/go.mod h1:hH2RYPTTM9e9zOiTaYPTiGPcGdNZVnBSBxjIAJzUkqo= -cloud.google.com/go/optimization v1.6.2/go.mod h1:mWNZ7B9/EyMCcwNl1frUGEuY6CPijSkz88Fz2vwKPOY= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= -cloud.google.com/go/orchestration v1.8.2/go.mod h1:T1cP+6WyTmh6LSZzeUhvGf0uZVmJyTx7t8z7Vg87+A0= -cloud.google.com/go/orchestration v1.8.3/go.mod h1:xhgWAYqlbYjlz2ftbFghdyqENYW+JXuhBx9KsjMoGHs= -cloud.google.com/go/orchestration v1.8.4/go.mod h1:d0lywZSVYtIoSZXb0iFjv9SaL13PGyVOKDxqGxEf/qI= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= -cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= -cloud.google.com/go/orgpolicy v1.11.2/go.mod h1:biRDpNwfyytYnmCRWZWxrKF22Nkz9eNVj9zyaBdpm1o= -cloud.google.com/go/orgpolicy v1.11.3/go.mod h1:oKAtJ/gkMjum5icv2aujkP4CxROxPXsBbYGCDbPO8MM= -cloud.google.com/go/orgpolicy v1.11.4/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= -cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= -cloud.google.com/go/osconfig v1.12.2/go.mod h1:eh9GPaMZpI6mEJEuhEjUJmaxvQ3gav+fFEJon1Y8Iw0= -cloud.google.com/go/osconfig v1.12.3/go.mod h1:L/fPS8LL6bEYUi1au832WtMnPeQNT94Zo3FwwV1/xGM= -cloud.google.com/go/osconfig v1.12.4/go.mod h1:B1qEwJ/jzqSRslvdOCI8Kdnp0gSng0xW4LOnIebQomA= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= -cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3xlOxaboXE= -cloud.google.com/go/oslogin v1.11.1/go.mod h1:OhD2icArCVNUxKqtK0mcSmKL7lgr0LVlQz+v9s1ujTg= -cloud.google.com/go/oslogin v1.12.1/go.mod h1:VfwTeFJGbnakxAY236eN8fsnglLiVXndlbcNomY4iZU= -cloud.google.com/go/oslogin v1.12.2/go.mod h1:CQ3V8Jvw4Qo4WRhNPF0o+HAM4DiLuE27Ul9CX9g2QdY= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= -cloud.google.com/go/phishingprotection v0.8.2/go.mod h1:LhJ91uyVHEYKSKcMGhOa14zMMWfbEdxG032oT6ECbC8= -cloud.google.com/go/phishingprotection v0.8.3/go.mod h1:3B01yO7T2Ra/TMojifn8EoGd4G9jts/6cIO0DgDY9J8= -cloud.google.com/go/phishingprotection v0.8.4/go.mod h1:6b3kNPAc2AQ6jZfFHioZKg9MQNybDg4ixFd4RPZZ2nE= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= -cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= -cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= -cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= -cloud.google.com/go/policytroubleshooter v1.9.1/go.mod h1:MYI8i0bCrL8cW+VHN1PoiBTyNZTstCg2WUw2eVC4c4U= -cloud.google.com/go/policytroubleshooter v1.10.1/go.mod h1:5C0rhT3TDZVxAu8813bwmTvd57Phbl8mr9F4ipOsxEs= -cloud.google.com/go/policytroubleshooter v1.10.2/go.mod h1:m4uF3f6LseVEnMV6nknlN2vYGRb+75ylQwJdnOXfnv0= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= -cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= -cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= -cloud.google.com/go/privatecatalog v0.9.2/go.mod h1:RMA4ATa8IXfzvjrhhK8J6H4wwcztab+oZph3c6WmtFc= -cloud.google.com/go/privatecatalog v0.9.3/go.mod h1:K5pn2GrVmOPjXz3T26mzwXLcKivfIJ9R5N79AFCF9UE= -cloud.google.com/go/privatecatalog v0.9.4/go.mod h1:SOjm93f+5hp/U3PqMZAHTtBtluqLygrDrVO8X8tYtG0= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= -cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3XuJyNsjEqMlMzg3v3scCJ46c= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.1/go.mod h1:JZYZJOeZjgSSTGP4uz7NlQ4/d1w5hGmksVgM0lbEij0= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.2/go.mod h1:kpaDBOpkwD4G0GVMzG1W6Doy1tFFC97XAV3xy+Rd/pw= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.3/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.4/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.0/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= -cloud.google.com/go/recommendationengine v0.8.2/go.mod h1:QIybYHPK58qir9CV2ix/re/M//Ty10OxjnnhWdaKS1Y= -cloud.google.com/go/recommendationengine v0.8.3/go.mod h1:m3b0RZV02BnODE9FeSvGv1qibFo8g0OnmB/RMwYy4V8= -cloud.google.com/go/recommendationengine v0.8.4/go.mod h1:GEteCf1PATl5v5ZsQ60sTClUE0phbWmo3rQ1Js8louU= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= -cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= -cloud.google.com/go/recommender v1.11.1/go.mod h1:sGwFFAyI57v2Hc5LbIj+lTwXipGu9NW015rkaEM5B18= -cloud.google.com/go/recommender v1.11.2/go.mod h1:AeoJuzOvFR/emIcXdVFkspVXVTYpliRCmKNYDnyBv6Y= -cloud.google.com/go/recommender v1.11.3/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= -cloud.google.com/go/recommender v1.12.0/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= -cloud.google.com/go/redis v1.13.2/go.mod h1:0Hg7pCMXS9uz02q+LoEVl5dNHUkIQv+C/3L76fandSA= -cloud.google.com/go/redis v1.13.3/go.mod h1:vbUpCKUAZSYzFcWKmICnYgRAhTFg9r+djWqFxDYXi4U= -cloud.google.com/go/redis v1.14.1/go.mod h1:MbmBxN8bEnQI4doZPC1BzADU4HGocHBk2de3SbgOkqs= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= -cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= -cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= -cloud.google.com/go/resourcemanager v1.9.2/go.mod h1:OujkBg1UZg5lX2yIyMo5Vz9O5hf7XQOSV7WxqxxMtQE= -cloud.google.com/go/resourcemanager v1.9.3/go.mod h1:IqrY+g0ZgLsihcfcmqSe+RKp1hzjXwG904B92AwBz6U= -cloud.google.com/go/resourcemanager v1.9.4/go.mod h1:N1dhP9RFvo3lUfwtfLWVxfUWq8+KUQ+XLlHLH3BoFJ0= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= -cloud.google.com/go/resourcesettings v1.6.2/go.mod h1:mJIEDd9MobzunWMeniaMp6tzg4I2GvD3TTmPkc8vBXk= -cloud.google.com/go/resourcesettings v1.6.3/go.mod h1:pno5D+7oDYkMWZ5BpPsb4SO0ewg3IXcmmrUZaMJrFic= -cloud.google.com/go/resourcesettings v1.6.4/go.mod h1:pYTTkWdv2lmQcjsthbZLNBP4QW140cs7wqA3DuqErVI= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= -cloud.google.com/go/retail v1.14.2/go.mod h1:W7rrNRChAEChX336QF7bnMxbsjugcOCPU44i5kbLiL8= -cloud.google.com/go/retail v1.14.3/go.mod h1:Omz2akDHeSlfCq8ArPKiBxlnRpKEBjUH386JYFLUvXo= -cloud.google.com/go/retail v1.14.4/go.mod h1:l/N7cMtY78yRnJqp5JW8emy7MB1nz8E4t2yfOmklYfg= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= -cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= -cloud.google.com/go/run v1.3.0/go.mod h1:S/osX/4jIPZGg+ssuqh6GNgg7syixKe3YnprwehzHKU= -cloud.google.com/go/run v1.3.1/go.mod h1:cymddtZOzdwLIAsmS6s+Asl4JoXIDm/K1cpZTxV4Q5s= -cloud.google.com/go/run v1.3.2/go.mod h1:SIhmqArbjdU/D9M6JoHaAqnAMKLFtXaVdNeq04NjnVE= -cloud.google.com/go/run v1.3.3/go.mod h1:WSM5pGyJ7cfYyYbONVQBN4buz42zFqwG67Q3ch07iK4= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= -cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= -cloud.google.com/go/scheduler v1.10.2/go.mod h1:O3jX6HRH5eKCA3FutMw375XHZJudNIKVonSCHv7ropY= -cloud.google.com/go/scheduler v1.10.3/go.mod h1:8ANskEM33+sIbpJ+R4xRfw/jzOG+ZFE8WVLy7/yGvbc= -cloud.google.com/go/scheduler v1.10.4/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= -cloud.google.com/go/scheduler v1.10.5/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= -cloud.google.com/go/secretmanager v1.11.2/go.mod h1:MQm4t3deoSub7+WNwiC4/tRYgDBHJgJPvswqQVB1Vss= -cloud.google.com/go/secretmanager v1.11.3/go.mod h1:0bA2o6FabmShrEy328i67aV+65XoUFFSmVeLBn/51jI= -cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= -cloud.google.com/go/security v1.15.2/go.mod h1:2GVE/v1oixIRHDaClVbHuPcZwAqFM28mXuAKCfMgYIg= -cloud.google.com/go/security v1.15.3/go.mod h1:gQ/7Q2JYUZZgOzqKtw9McShH+MjNvtDpL40J1cT+vBs= -cloud.google.com/go/security v1.15.4/go.mod h1:oN7C2uIZKhxCLiAAijKUCuHLZbIt/ghYEo8MqwD/Ty4= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= -cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= -cloud.google.com/go/securitycenter v1.23.1/go.mod h1:w2HV3Mv/yKhbXKwOCu2i8bCuLtNP1IMHuiYQn4HJq5s= -cloud.google.com/go/securitycenter v1.24.1/go.mod h1:3h9IdjjHhVMXdQnmqzVnM7b0wMn/1O/U20eWVpMpZjI= -cloud.google.com/go/securitycenter v1.24.2/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= -cloud.google.com/go/securitycenter v1.24.3/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= -cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.1/go.mod h1:tJywXimEWzNzw9FvtNjsQxxJ3/41jseeILgwU/QLrGI= -cloud.google.com/go/servicedirectory v1.11.2/go.mod h1:KD9hCLhncWRV5jJphwIpugKwM5bn1x0GyVVD4NO8mGg= -cloud.google.com/go/servicedirectory v1.11.3/go.mod h1:LV+cHkomRLr67YoQy3Xq2tUXBGOs5z5bPofdq7qtiAw= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= -cloud.google.com/go/shell v1.7.2/go.mod h1:KqRPKwBV0UyLickMn0+BY1qIyE98kKyI216sH/TuHmc= -cloud.google.com/go/shell v1.7.3/go.mod h1:cTTEz/JdaBsQAeTQ3B6HHldZudFoYBOqjteev07FbIc= -cloud.google.com/go/shell v1.7.4/go.mod h1:yLeXB8eKLxw0dpEmXQ/FjriYrBijNsONpwnWsdPqlKM= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= -cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.50.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.51.0/go.mod h1:c5KNo5LQ1X5tJwma9rSQZsXNBDNvj4/n8BVc3LNahq0= -cloud.google.com/go/spanner v1.53.0/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= -cloud.google.com/go/spanner v1.53.1/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= -cloud.google.com/go/spanner v1.54.0/go.mod h1:wZvSQVBgngF0Gq86fKup6KIYmN2be7uOKjtK97X+bQU= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= -cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= -cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.1/go.mod h1:WcuaWz/3hOlzPFOVo9DUsblMIHwxP589y6ZMtaG+iAA= -cloud.google.com/go/speech v1.19.2/go.mod h1:2OYFfj+Ch5LWjsaSINuCZsre/789zlcCI3SY4oAi2oI= -cloud.google.com/go/speech v1.20.1/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= -cloud.google.com/go/speech v1.21.0/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= -cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= -cloud.google.com/go/storagetransfer v1.10.1/go.mod h1:rS7Sy0BtPviWYTTJVWCSV4QrbBitgPeuK4/FKa4IdLs= -cloud.google.com/go/storagetransfer v1.10.2/go.mod h1:meIhYQup5rg9juQJdyppnA/WLQCOguxtk1pr3/vBWzA= -cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= -cloud.google.com/go/talent v1.6.3/go.mod h1:xoDO97Qd4AK43rGjJvyBHMskiEf3KulgYzcH6YWOVoo= -cloud.google.com/go/talent v1.6.4/go.mod h1:QsWvi5eKeh6gG2DlBkpMaFYZYrYUnIpo34f6/V5QykY= -cloud.google.com/go/talent v1.6.5/go.mod h1:Mf5cma696HmE+P2BWJ/ZwYqeJXEeU0UqjHFXVLadEDI= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= -cloud.google.com/go/texttospeech v1.7.2/go.mod h1:VYPT6aTOEl3herQjFHYErTlSZJ4vB00Q2ZTmuVgluD4= -cloud.google.com/go/texttospeech v1.7.3/go.mod h1:Av/zpkcgWfXlDLRYob17lqMstGZ3GqlvJXqKMp2u8so= -cloud.google.com/go/texttospeech v1.7.4/go.mod h1:vgv0002WvR4liGuSd5BJbWy4nDn5Ozco0uJymY5+U74= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= -cloud.google.com/go/tpu v1.6.2/go.mod h1:NXh3NDwt71TsPZdtGWgAG5ThDfGd32X1mJ2cMaRlVgU= -cloud.google.com/go/tpu v1.6.3/go.mod h1:lxiueqfVMlSToZY1151IaZqp89ELPSrk+3HIQ5HRkbY= -cloud.google.com/go/tpu v1.6.4/go.mod h1:NAm9q3Rq2wIlGnOhpYICNI7+bpBebMJbh0yyp3aNw1Y= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= -cloud.google.com/go/trace v1.10.2/go.mod h1:NPXemMi6MToRFcSxRl2uDnu/qAlAQ3oULUphcHGh1vA= -cloud.google.com/go/trace v1.10.3/go.mod h1:Ke1bgfc73RV3wUFml+uQp7EsDw4dGaETLxB7Iq/r4CY= -cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGmE6TXNWY= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.1/go.mod h1:TWIgDZknq2+JD4iRcojgeDtqGEp154HN/uL6hMvylS8= -cloud.google.com/go/translate v1.9.2/go.mod h1:E3Tc6rUTsQkVrXW6avbUhKJSr7ZE3j7zNmqzXKHqRrY= -cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= -cloud.google.com/go/video v1.20.1/go.mod h1:3gJS+iDprnj8SY6pe0SwLeC5BUW80NjhwX7INWEuWGU= -cloud.google.com/go/video v1.20.2/go.mod h1:lrixr5JeKNThsgfM9gqtwb6Okuqzfo4VrY2xynaViTA= -cloud.google.com/go/video v1.20.3/go.mod h1:TnH/mNZKVHeNtpamsSPygSR0iHtvrR/cW1/GDjN5+GU= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= -cloud.google.com/go/videointelligence v1.11.2/go.mod h1:ocfIGYtIVmIcWk1DsSGOoDiXca4vaZQII1C85qtoplc= -cloud.google.com/go/videointelligence v1.11.3/go.mod h1:tf0NUaGTjU1iS2KEkGWvO5hRHeCkFK3nPo0/cOZhZAo= -cloud.google.com/go/videointelligence v1.11.4/go.mod h1:kPBMAYsTPFiQxMLmmjpcZUMklJp3nC9+ipJJtprccD8= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= -cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= -cloud.google.com/go/vision/v2 v2.7.3/go.mod h1:V0IcLCY7W+hpMKXK1JYE0LV5llEqVmj+UJChjvA1WsM= -cloud.google.com/go/vision/v2 v2.7.4/go.mod h1:ynDKnsDN/0RtqkKxQZ2iatv3Dm9O+HfRb5djl7l4Vvw= -cloud.google.com/go/vision/v2 v2.7.5/go.mod h1:GcviprJLFfK9OLf0z8Gm6lQb6ZFUulvpZws+mm6yPLM= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= -cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= -cloud.google.com/go/vmmigration v1.7.2/go.mod h1:iA2hVj22sm2LLYXGPT1pB63mXHhrH1m/ruux9TwWLd8= -cloud.google.com/go/vmmigration v1.7.3/go.mod h1:ZCQC7cENwmSWlwyTrZcWivchn78YnFniEQYRWQ65tBo= -cloud.google.com/go/vmmigration v1.7.4/go.mod h1:yBXCmiLaB99hEl/G9ZooNx2GyzgsjKnw5fWcINRgD70= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= -cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.1/go.mod h1:aT3Xsm5sNx0QShk1Jc1B8OddrxAScYLwzVoaiXfdzzk= -cloud.google.com/go/vmwareengine v1.0.2/go.mod h1:xMSNjIk8/itYrz1JA8nV3Ajg4L4n3N+ugP8JKzk3OaA= -cloud.google.com/go/vmwareengine v1.0.3/go.mod h1:QSpdZ1stlbfKtyt6Iu19M6XRxjmXO+vb5a/R6Fvy2y4= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= -cloud.google.com/go/vpcaccess v1.7.2/go.mod h1:mmg/MnRHv+3e8FJUjeSibVFvQF1cCy2MsFaFqxeY1HU= -cloud.google.com/go/vpcaccess v1.7.3/go.mod h1:YX4skyfW3NC8vI3Fk+EegJnlYFatA+dXK4o236EUCUc= -cloud.google.com/go/vpcaccess v1.7.4/go.mod h1:lA0KTvhtEOb/VOdnH/gwPuOzGgM+CWsmGu6bb4IoMKk= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= -cloud.google.com/go/webrisk v1.9.2/go.mod h1:pY9kfDgAqxUpDBOrG4w8deLfhvJmejKB0qd/5uQIPBc= -cloud.google.com/go/webrisk v1.9.3/go.mod h1:RUYXe9X/wBDXhVilss7EDLW9ZNa06aowPuinUOPCXH8= -cloud.google.com/go/webrisk v1.9.4/go.mod h1:w7m4Ib4C+OseSr2GL66m0zMBywdrVNTDKsdEsfMl7X0= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= -cloud.google.com/go/websecurityscanner v1.6.2/go.mod h1:7YgjuU5tun7Eg2kpKgGnDuEOXWIrh8x8lWrJT4zfmas= -cloud.google.com/go/websecurityscanner v1.6.3/go.mod h1:x9XANObUFR+83Cya3g/B9M/yoHVqzxPnFtgF8yYGAXw= -cloud.google.com/go/websecurityscanner v1.6.4/go.mod h1:mUiyMQ+dGpPPRkHgknIZeCzSHJ45+fY4F52nZFDHm2o= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= -cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= -cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCwLM1P1tBRGHM= -cloud.google.com/go/workflows v1.12.2/go.mod h1:+OmBIgNqYJPVggnMo9nqmizW0qEXHhmnAzK/CnBqsHc= -cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/agoda-com/opentelemetry-logs-go v0.4.1 h1:PWGqIxkEEg4HIjnHsHmNa+yGu0lhxHz4XPGKeT4o6T0= -github.com/agoda-com/opentelemetry-logs-go v0.4.1/go.mod h1:CeDuVaK9yCWN+8UjOW8AciYJE0rl7K/mw4ejBntGYkc= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= -github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/agoda-com/opentelemetry-logs-go v0.5.1 h1:6iQrLaY4M0glBZb/xVN559qQutK4V+HJ/mB1cbwaX3c= +github.com/agoda-com/opentelemetry-logs-go v0.5.1/go.mod h1:35B5ypjX5pkVCPJR01i6owJSYWe8cnbWLpEyHgAGD/E= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-pkcs11 v0.2.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= -github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= -github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ= -github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88= -github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= -github.com/grafana/pyroscope-go/godeltaprof v0.1.7 h1:C11j63y7gymiW8VugJ9ZW0pWfxTZugdSJyC48olk5KY= -github.com/grafana/pyroscope-go/godeltaprof v0.1.7/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= -github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/grafana/pyroscope-go v1.3.1 h1:Eb9h55+vtLezn/DQ4iXz+SJrOz8CNghDk9xx8XQ4tc0= +github.com/grafana/pyroscope-go v1.3.1/go.mod h1:vjZr7UNVSvbpVH+G9SBy8K0fATjfYwl+W12xLNOx9Xg= +github.com/grafana/pyroscope-go/godeltaprof v0.1.11 h1:el5LYpXissAiCKZ5/6yjlr6mhYVV6Cp5lahTocxraXM= +github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPIDDG7CtjSjT/ECbp6eLVuMxYRI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0 h1:4s9HxB4azeeQkhY0GE5wZlMj4/pz8tE5gx2OQpGUw58= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0/go.mod h1:djVA3TUJ2fSdMX0JE5XxFBOaZzprElJoP7fD4vnV2SU= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 h1:TC+BewnDpeiAmcscXbGMfxkO+mwYUwE/VySwvw88PfA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0/go.mod h1:J/ZyF4vfPwsSr9xJSPyQ4LqtcTPULFR64KwTikGLe+A= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= -google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= -google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= -google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= -google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= -google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20230821184602-ccc8af3d0e93/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= -google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= -google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= -google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= -google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= -modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= -modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/go.work b/examples/language-sdk-instrumentation/golang-push/rideshare/go.work index 6da44691e9..a860ee362f 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/go.work +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/go.work @@ -1,5 +1,3 @@ -go 1.19 +go 1.25.0 -use ( - . -) +use . diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/go.work.sum b/examples/language-sdk-instrumentation/golang-push/rideshare/go.work.sum index bcba5e1dcd..5defab82b9 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/go.work.sum +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/go.work.sum @@ -1,190 +1,218 @@ -cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 h1:QfV5XZt6iNa2aWMAt96CZEbfJ7kgG/qYIpq465Shr5E= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= -github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g= -github.com/KimMachineGun/automemlimit v0.5.0 h1:BeOe+BbJc8L5chL3OwzVYjVzyvPALdd5wxVVOWuUZmQ= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +cel.dev/expr v0.16.0 h1:yloc84fytn4zmJX2GU3TkXGsaieaV7dQ057Qs4sIG2Y= +cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= +cel.dev/expr v0.16.2/go.mod h1:gXngZQMkWJoSbE8mOzehJlXQyubn/Vg0vR9/F3W7iw8= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.2/go.mod h1:itPGVDKf9cC/ov4MdvJ2QZ0khw4bfoo9jzwTJlaxy2k= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= -github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/aws/aws-sdk-go v1.50.0 h1:HBtrLeO+QyDKnc3t1+5DR1RxodOHCGr8ZcrHudpv7jI= -github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= -github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= -github.com/digitalocean/godo v1.108.0 h1:fWyMENvtxpCpva1UbKzOFnyAS04N1FNuBWWfPeTGquQ= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/docker/docker v25.0.0+incompatible h1:g9b6wZTblhMgzOT2tspESstfw6ySZ9kdm94BLDKaZac= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= -github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= -github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= -github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= -github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc= -github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= -github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= -github.com/hetznercloud/hcloud-go/v2 v2.6.0 h1:RJOA2hHZ7rD1pScA4O1NF6qhkHyUdbbxjHgFNot8928= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les= +github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8= +github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= +github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= -github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/linode/linodego v1.27.1 h1:KoQm5g2fppw8qIClJqUEL0yKH0+f+7te3Mewagb5QKE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= -github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM= -github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= -github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc= -github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= -github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= -github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 h1:wJrcTdddKOI8TFxs8cemnhKP2EmKy3yfUKHj3ZdfzYo= -github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= -go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opentelemetry.io/collector/featuregate v1.0.1 h1:ok//hLSXttBbyu4sSV1pTx1nKdr5udSmrWy5sFMIIbM= -go.opentelemetry.io/collector/pdata v1.0.1 h1:dGX2h7maA6zHbl5D3AsMnF1c3Nn+3EUftbVCLzeyNvA= -go.opentelemetry.io/collector/semconv v0.93.0 h1:eBlMcVNTwYYsVdAsCVDs4wvVYs75K1xcIDpqj16PG4c= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opentelemetry.io/contrib/detectors/gcp v1.31.0/go.mod h1:tzQL6E1l+iV44YFTkcAeNQqzXUiekSYP9jjJjXwEd00= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 h1:umZgi92IyxfXd/l4kaDhnKgY8rnN/cZcF1LKc6I8OQ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0/go.mod h1:4lVs6obhSVRb1EW5FhOuBTyiQhtRtAnnva9vD3yRfq8= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0 h1:kn1BudCgwtE7PxLqcZkErpD8GKqLZ6BSzeW9QihQJeM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0/go.mod h1:ljkUDtAMdleoi9tIG1R6dJUpVwDcYjw3J2Q6Q/SuiC0= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= +go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -google.golang.org/api v0.157.0 h1:ORAeqmbrrozeyw5NjnMxh7peHO0UzV4wWYSwZeCUb20= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc h1:Nf+EdcTLHR8qDNN/KfkQL0u0ssxt9OhbaWCl5C0ucEI= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -k8s.io/api v0.28.6 h1:yy6u9CuIhmg55YvF/BavPBBXB+5QicB64njJXxVnzLo= -k8s.io/apimachinery v0.28.6 h1:RsTeR4z6S07srPg6XYrwXpTJVMXsjPXn0ODakMytSW0= -k8s.io/client-go v0.28.6 h1:Gge6ziyIdafRchfoBKcpaARuz7jfrK1R1azuwORIsQI= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/grafana-provisioning/datasources/prometheus.yml b/examples/language-sdk-instrumentation/golang-push/rideshare/grafana-provisioning/datasources/prometheus.yml new file mode 100644 index 0000000000..fbb06d69ec --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/grafana-provisioning/datasources/prometheus.yml @@ -0,0 +1,20 @@ +# This file is generated from the template: +# examples/_templates/prometheus/grafana-provisioning/datasources/prometheus.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: local-prometheus + type: prometheus + name: Prometheus + access: proxy + url: http://prometheus:9090 + basicAuth: true #username: admin, password: admin + basicAuthUser: admin + jsonData: + manageAlerts: true + prometheusType: Prometheus #Cortex | Mimir | Prometheus | Thanos + prometheusVersion: 2.40.0 + secureJsonData: + basicAuthPassword: admin #https://grafana.com/docs/grafana/latest/administration/provisioning/#using-environment-variables diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/golang-push/rideshare/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/main.go b/examples/language-sdk-instrumentation/golang-push/rideshare/main.go index 711ba0d8c9..bd7eafa55a 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/main.go +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/main.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "time" "rideshare/bike" "rideshare/car" @@ -16,9 +17,14 @@ import ( "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" otellogs "github.com/agoda-com/opentelemetry-logs-go" + sdklogs "github.com/agoda-com/opentelemetry-logs-go/sdk/logs" otelpyroscope "github.com/grafana/otel-profiling-go" + "github.com/prometheus/client_golang/prometheus/promhttp" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + mmetric "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -49,9 +55,11 @@ func index(w http.ResponseWriter, r *http.Request) { func main() { config := rideshare.ReadConfig() - tp, _ := setupOTEL(config) + tp, lp, mp, _ := setupOTEL(config) defer func() { _ = tp.Shutdown(context.Background()) + _ = lp.Shutdown(context.Background()) + _ = mp.Shutdown(context.Background()) }() p, err := rideshare.Profiler(config) @@ -59,33 +67,79 @@ func main() { if err != nil { log.Fatalf("error starting pyroscope profiler: %v", err) } + defer func() { _ = p.Stop() }() + histogram, err := otel.GetMeterProvider().Meter("histogram").Float64Histogram( + "handler.duration", + mmetric.WithDescription("The duration of handler execution."), + mmetric.WithUnit("s"), + ) + if err != nil { + panic(err) + } + cleanup := utility.InitWorkerPool(config) defer cleanup() rideshare.Log.Print(context.Background(), "started ride-sharing app") + // Register Prometheus metrics handler + http.Handle("/metrics", promhttp.Handler()) + http.Handle("/", otelhttp.NewHandler(http.HandlerFunc(index), "IndexHandler")) - http.Handle("/bike", otelhttp.NewHandler(http.HandlerFunc(bikeRoute), "BikeHandler")) - http.Handle("/scooter", otelhttp.NewHandler(http.HandlerFunc(scooterRoute), "ScooterHandler")) - http.Handle("/car", otelhttp.NewHandler(http.HandlerFunc(carRoute), "CarHandler")) + + http.Handle("/bike", otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + bikeRoute(w, r) + duration := time.Since(start) + histogram.Record(r.Context(), duration.Seconds(), + mmetric.WithAttributes( + attribute.String("vehicle", "bike"), + attribute.String("route", "/bike"), + ), + ) + }), "BikeHandler")) + + http.Handle("/scooter", otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + scooterRoute(w, r) + duration := time.Since(start) + histogram.Record(r.Context(), duration.Seconds(), + mmetric.WithAttributes( + attribute.String("vehicle", "scooter"), + attribute.String("route", "/scooter"), + ), + ) + }), "ScooterHandler")) + + http.Handle("/car", otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + carRoute(w, r) + duration := time.Since(start) + histogram.Record(r.Context(), duration.Seconds(), + mmetric.WithAttributes( + attribute.String("vehicle", "car"), + attribute.String("route", "/car"), + ), + ) + }), "CarHandler")) addr := fmt.Sprintf(":%s", config.RideshareListenPort) log.Fatal(http.ListenAndServe(addr, nil)) } -func setupOTEL(c rideshare.Config) (tp *sdktrace.TracerProvider, err error) { +func setupOTEL(c rideshare.Config) (tp *sdktrace.TracerProvider, lp *sdklogs.LoggerProvider, mp *sdkmetric.MeterProvider, err error) { tp, err = rideshare.TracerProvider(c) if err != nil { - return nil, err + return nil, nil, nil, err } - lp, err := rideshare.LoggerProvider(c) + lp, err = rideshare.LoggerProvider(c) if err != nil { - return nil, err + return nil, nil, nil, err } otellogs.SetLoggerProvider(lp) @@ -105,5 +159,11 @@ func setupOTEL(c rideshare.Config) (tp *sdktrace.TracerProvider, err error) { propagation.Baggage{}, )) - return tp, err + mp, err = rideshare.MeterProvider(c) + if err != nil { + return nil, nil, nil, err + } + otel.SetMeterProvider(mp) + + return tp, lp, mp, err } diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/prometheus-provisioning/prometheus.yaml b/examples/language-sdk-instrumentation/golang-push/rideshare/prometheus-provisioning/prometheus.yaml new file mode 100644 index 0000000000..7428542db4 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/prometheus-provisioning/prometheus.yaml @@ -0,0 +1,26 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +otlp: + promote_resource_attributes: + - service.name + - cloud.region + - host.name + +scrape_configs: + - job_name: grafana + static_configs: + - targets: + - grafana:3000 + - job_name: pyroscope + static_configs: + - targets: + - pyroscope:4040 + - job_name: prometheus + static_configs: + - targets: + - prometheus:9090 + - job_name: 'rideshare' + static_configs: + - targets: ['us-east:5000', 'eu-north:5000', 'ap-south:5000'] diff --git a/examples/language-sdk-instrumentation/golang-push/rideshare/rideshare/rideshare.go b/examples/language-sdk-instrumentation/golang-push/rideshare/rideshare/rideshare.go index a4476a6b91..a34d8cc80f 100644 --- a/examples/language-sdk-instrumentation/golang-push/rideshare/rideshare/rideshare.go +++ b/examples/language-sdk-instrumentation/golang-push/rideshare/rideshare/rideshare.go @@ -14,10 +14,16 @@ import ( "github.com/agoda-com/opentelemetry-logs-go/logs" sdklogs "github.com/agoda-com/opentelemetry-logs-go/sdk/logs" "github.com/grafana/pyroscope-go" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prometheus/common/model" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.20.0" @@ -67,9 +73,10 @@ type Config struct { OTLPBasicAuthPassword string OTLPTracesUrlPath string - UseDebugTracer bool - UseDebugLogger bool - Tags map[string]string + UseDebugTracer bool + UseDebugLogger bool + UseDebugMeterer bool + Tags map[string]string ParametersPoolSize int ParametersPoolBufferSize int @@ -91,17 +98,21 @@ func ReadConfig() Config { PyroscopeBasicAuthUser: os.Getenv("PYROSCOPE_BASIC_AUTH_USER"), PyroscopeBasicAuthPassword: os.Getenv("PYROSCOPE_BASIC_AUTH_PASSWORD"), - OTLPUrl: os.Getenv("OTLP_URL"), + OTLPUrl: getOTLPUrl(), OTLPInsecure: os.Getenv("OTLP_INSECURE") == "1", OTLPBasicAuthUser: os.Getenv("OTLP_BASIC_AUTH_USER"), OTLPBasicAuthPassword: os.Getenv("OTLP_BASIC_AUTH_PASSWORD"), OTLPTracesUrlPath: os.Getenv("OTLP_TRACES_URL_PATH"), - UseDebugTracer: os.Getenv("DEBUG_TRACER") == "1", - UseDebugLogger: os.Getenv("DEBUG_LOGGER") == "1", + UseDebugTracer: os.Getenv("DEBUG_TRACER") == "1", + UseDebugLogger: os.Getenv("DEBUG_LOGGER") == "1", + UseDebugMeterer: os.Getenv("DEBUG_METERER") == "1", Tags: map[string]string{ - "region": os.Getenv("REGION"), - "hostname": hostname, + "region": os.Getenv("REGION"), + "hostname": hostname, + "service_git_ref": "HEAD", + "service_repository": "https://github.com/grafana/pyroscope", + "service_root_path": "examples/language-sdk-instrumentation/golang-push/rideshare", }, ParametersPoolSize: envIntOrDefault("PARAMETERS_POOL_SIZE", 1000), @@ -125,6 +136,14 @@ func ReadConfig() Config { return c } +// getOTLPUrl returns the OTLP URL from environment variables, with OTEL_EXPORTER_OTLP_METRICS_ENDPOINT taking precedence +func getOTLPUrl() string { + if url := os.Getenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"); url != "" { + return url + } + return os.Getenv("OTLP_URL") +} + func basicAuth(username, password string) string { auth := username + ":" + password return base64.StdEncoding.EncodeToString([]byte(auth)) @@ -236,6 +255,100 @@ func debugTracerProvider() (*sdktrace.TracerProvider, error) { return sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exp))), nil } +type dimension struct { + label string + getNextValue func() string +} + +func init() { + // Configure Prometheus to use UTF-8 validation for metric names + model.NameEscapingScheme = model.ValueEncodingEscaping + + // Initialize metrics + dimensions := []string{ + "a_legacy_label", + "label with space", + "label with 📈", + "label.with.spaß", + "instance", + "job", + "site", + "room", + } + + utf8Metric := promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "a_utf8_metric", + Help: "a utf8 metric with utf8 labels", + }, dimensions) + + opsProcessed := promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "a_utf8_http_requests_total", + Help: "a metric with utf8 labels", + }, dimensions) + + target_info := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "target_info", + Help: "an info metric model for otel", + ConstLabels: map[string]string{"job": "job", "instance": "instance", "resource 1": "1", "resource 2": "2", "resource ę": "e", "deployment_environment": "prod"}, + }) + + // Start the metrics update goroutine + go func() { + for { + labels := []string{ + "legacy", + "space", + "metrics", + "this_is_fun", + "instance", + "job", + "LA-EPI", + `"Friends Don't Lie"`, + } + + utf8Metric.WithLabelValues(labels...).Inc() + opsProcessed.WithLabelValues(labels...).Inc() + target_info.Set(1) + + time.Sleep(time.Second * 5) + } + }() +} + +func MeterProvider(c Config) (*sdkmetric.MeterProvider, error) { + // Default is 1m. Set to 3s for demonstrative purposes. + interval := 3 * time.Second + + if c.UseDebugMeterer { + // create stdout exporter, when no OTLP url is set + exp, err := stdoutmetric.New() + if err != nil { + return nil, err + } + + return sdkmetric.NewMeterProvider( + sdkmetric.WithResource(newResource(c)), + sdkmetric.WithReader(sdkmetric.NewPeriodicReader(exp, + sdkmetric.WithInterval(interval))), + ), nil + } + + ctx := context.Background() + exp, err := otlpmetrichttp.New(ctx) + if err != nil { + return nil, err + } + + // Create a new meter provider with a periodic reader and the otlp exporter + mp := sdkmetric.NewMeterProvider( + sdkmetric.WithResource(newResource(c)), + sdkmetric.WithReader(sdkmetric.NewPeriodicReader(exp, + sdkmetric.WithInterval(interval))), + ) + + return mp, nil +} + func Profiler(c Config) (*pyroscope.Profiler, error) { config := pyroscope.Config{ ApplicationName: c.AppName, @@ -243,9 +356,7 @@ func Profiler(c Config) (*pyroscope.Profiler, error) { Logger: pyroscope.StandardLogger, Tags: c.Tags, } - if c.PyroscopeAuthToken != "" { - config.AuthToken = c.PyroscopeAuthToken - } else if c.PyroscopeBasicAuthUser != "" { + if c.PyroscopeBasicAuthUser != "" { config.BasicAuthUser = c.PyroscopeBasicAuthUser config.BasicAuthPassword = c.PyroscopeBasicAuthPassword } diff --git a/examples/language-sdk-instrumentation/golang-push/simple/Dockerfile b/examples/language-sdk-instrumentation/golang-push/simple/Dockerfile index 1ad056a58a..d6af984bfc 100644 --- a/examples/language-sdk-instrumentation/golang-push/simple/Dockerfile +++ b/examples/language-sdk-instrumentation/golang-push/simple/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21.10 +FROM golang:1.25.12 WORKDIR /go/src/app diff --git a/examples/language-sdk-instrumentation/golang-push/simple/docker-compose.yml b/examples/language-sdk-instrumentation/golang-push/simple/docker-compose.yml index 6344e3564d..9c1ee1759f 100644 --- a/examples/language-sdk-instrumentation/golang-push/simple/docker-compose.yml +++ b/examples/language-sdk-instrumentation/golang-push/simple/docker-compose.yml @@ -1,12 +1,25 @@ ---- -version: '3.9' services: pyroscope: - image: 'grafana/pyroscope:latest' + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 app: build: . environment: - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/golang-push/simple/go.mod b/examples/language-sdk-instrumentation/golang-push/simple/go.mod index d99f8bb778..b14171340a 100644 --- a/examples/language-sdk-instrumentation/golang-push/simple/go.mod +++ b/examples/language-sdk-instrumentation/golang-push/simple/go.mod @@ -1,10 +1,12 @@ module pushsimple -go 1.17 +go 1.25.0 -require github.com/grafana/pyroscope-go v1.1.1 +toolchain go1.25.12 + +require github.com/grafana/pyroscope-go v1.3.1 require ( - github.com/grafana/pyroscope-go/godeltaprof v0.1.7 // indirect - github.com/klauspost/compress v1.17.3 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.11 // indirect + github.com/klauspost/compress v1.18.6 // indirect ) diff --git a/examples/language-sdk-instrumentation/golang-push/simple/go.sum b/examples/language-sdk-instrumentation/golang-push/simple/go.sum index 210c61b491..579b95094c 100644 --- a/examples/language-sdk-instrumentation/golang-push/simple/go.sum +++ b/examples/language-sdk-instrumentation/golang-push/simple/go.sum @@ -1,7 +1,16 @@ -github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ= -github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88= -github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= -github.com/grafana/pyroscope-go/godeltaprof v0.1.7 h1:C11j63y7gymiW8VugJ9ZW0pWfxTZugdSJyC48olk5KY= -github.com/grafana/pyroscope-go/godeltaprof v0.1.7/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= -github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA= -github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/grafana/pyroscope-go v1.3.1 h1:Eb9h55+vtLezn/DQ4iXz+SJrOz8CNghDk9xx8XQ4tc0= +github.com/grafana/pyroscope-go v1.3.1/go.mod h1:vjZr7UNVSvbpVH+G9SBy8K0fATjfYwl+W12xLNOx9Xg= +github.com/grafana/pyroscope-go/godeltaprof v0.1.11 h1:el5LYpXissAiCKZ5/6yjlr6mhYVV6Cp5lahTocxraXM= +github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPIDDG7CtjSjT/ECbp6eLVuMxYRI= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/language-sdk-instrumentation/golang-push/simple/go.work b/examples/language-sdk-instrumentation/golang-push/simple/go.work index 6da44691e9..a860ee362f 100644 --- a/examples/language-sdk-instrumentation/golang-push/simple/go.work +++ b/examples/language-sdk-instrumentation/golang-push/simple/go.work @@ -1,5 +1,3 @@ -go 1.19 +go 1.25.0 -use ( - . -) +use . diff --git a/examples/language-sdk-instrumentation/golang-push/simple/go.work.sum b/examples/language-sdk-instrumentation/golang-push/simple/go.work.sum new file mode 100644 index 0000000000..145f256335 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/simple/go.work.sum @@ -0,0 +1,4 @@ +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/examples/language-sdk-instrumentation/golang-push/simple/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/golang-push/simple/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/golang-push/simple/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/java/fib/Dockerfile b/examples/language-sdk-instrumentation/java/fib/Dockerfile index b919b0c2eb..85f8a3079a 100644 --- a/examples/language-sdk-instrumentation/java/fib/Dockerfile +++ b/examples/language-sdk-instrumentation/java/fib/Dockerfile @@ -1,10 +1,10 @@ -FROM openjdk:17-slim-bullseye +FROM sapmachine:17-jdk-headless WORKDIR /opt/app RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates && apt-get install -y git -ADD https://github.com/grafana/pyroscope-java/releases/download/v0.13.1/pyroscope.jar /opt/app/pyroscope.jar +ADD https://github.com/grafana/pyroscope-java/releases/download/v2.5.4/pyroscope.jar /opt/app/pyroscope.jar COPY Main.java ./ diff --git a/examples/language-sdk-instrumentation/java/fib/docker-compose.yml b/examples/language-sdk-instrumentation/java/fib/docker-compose.yml index 9f01fab1a2..ac36d8556d 100644 --- a/examples/language-sdk-instrumentation/java/fib/docker-compose.yml +++ b/examples/language-sdk-instrumentation/java/fib/docker-compose.yml @@ -1,15 +1,28 @@ ---- -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 app: build: . privileged: true environment: - - 'PYROSCOPE_APPLICATION_NAME=fibonacci-java-lock-push' - - 'PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040' - - 'PYROSCOPE_FORMAT=jfr' + - PYROSCOPE_APPLICATION_NAME=fibonacci-java-lock-push + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - PYROSCOPE_FORMAT=jfr + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/java/fib/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/java/fib/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/java/fib/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/java/rideshare/.gitignore b/examples/language-sdk-instrumentation/java/rideshare/.gitignore index e4f95f5e53..cb6a621933 100644 --- a/examples/language-sdk-instrumentation/java/rideshare/.gitignore +++ b/examples/language-sdk-instrumentation/java/rideshare/.gitignore @@ -3,3 +3,4 @@ build/ .gradle pyroscope.jar out/ +bin/ diff --git a/examples/language-sdk-instrumentation/java/rideshare/.pyroscope.yaml b/examples/language-sdk-instrumentation/java/rideshare/.pyroscope.yaml new file mode 100644 index 0000000000..6758b4e1da --- /dev/null +++ b/examples/language-sdk-instrumentation/java/rideshare/.pyroscope.yaml @@ -0,0 +1,37 @@ +version: v1 +source_code: + mappings: + - function_name: + - prefix: org/example/rideshare + language: java + source: + local: + path: src/main/java + - function_name: + - prefix: java + language: java + source: + github: + owner: openjdk + repo: jdk + ref: jdk-17+0 + path: src/java.base/share/classes + - function_name: + - prefix: org/springframework/http + - prefix: org/springframework/web + language: java + source: + github: + owner: spring-projects + repo: spring-framework + ref: v5.3.20 + path: spring-web/src/main/java + - function_name: + - prefix: org/springframework/web/servlet + language: java + source: + github: + owner: spring-projects + repo: spring-framework + ref: v5.3.20 + path: spring-webmvc/src/main/java diff --git a/examples/language-sdk-instrumentation/java/rideshare/Dockerfile b/examples/language-sdk-instrumentation/java/rideshare/Dockerfile index 79a7dcae2c..6739566d04 100644 --- a/examples/language-sdk-instrumentation/java/rideshare/Dockerfile +++ b/examples/language-sdk-instrumentation/java/rideshare/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM openjdk:17-slim-bullseye as builder +FROM --platform=$BUILDPLATFORM sapmachine:21-jdk-headless AS builder WORKDIR /opt/app @@ -17,7 +17,7 @@ COPY src src RUN ./gradlew assemble --no-daemon -FROM openjdk:17-slim-bullseye +FROM sapmachine:21-jdk-headless RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates @@ -37,6 +37,6 @@ COPY --from=builder /opt/app/build/libs/rideshare-1.0-SNAPSHOT.jar /opt/app/buil WORKDIR /opt/app -ADD https://github.com/grafana/pyroscope-java/releases/download/v0.13.1/pyroscope.jar /opt/app/pyroscope.jar +ADD https://github.com/grafana/pyroscope-java/releases/download/v2.5.4/pyroscope.jar /opt/app/pyroscope.jar CMD sh -c "exec java -Dserver.port=${RIDESHARE_LISTEN_PORT} -javaagent:pyroscope.jar -jar ./build/libs/rideshare-1.0-SNAPSHOT.jar" diff --git a/examples/language-sdk-instrumentation/java/rideshare/Dockerfile.otel-instrumentation b/examples/language-sdk-instrumentation/java/rideshare/Dockerfile.otel-instrumentation deleted file mode 100644 index bb98f4dd83..0000000000 --- a/examples/language-sdk-instrumentation/java/rideshare/Dockerfile.otel-instrumentation +++ /dev/null @@ -1,50 +0,0 @@ -FROM --platform=$BUILDPLATFORM openjdk:17-slim-bullseye as builder - -WORKDIR /opt/app - -RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates - - - -COPY gradlew . -COPY gradle gradle -RUN ./gradlew - -COPY build.gradle.kts settings.gradle.kts ./ -RUN ./gradlew dependencies --no-daemon - -COPY src src -RUN ./gradlew assemble --no-daemon - - -FROM openjdk:17-slim-bullseye - -RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates - -ENV PYROSCOPE_APPLICATION_NAME=rideshare.java.push.app -ENV PYROSCOPE_FORMAT=jfr -ENV PYROSCOPE_PROFILING_INTERVAL=10ms -ENV PYROSCOPE_PROFILER_EVENT=itimer -ENV PYROSCOPE_PROFILER_LOCK=10ms -ENV PYROSCOPE_PROFILER_ALLOC=512k -ENV PYROSCOPE_UPLOAD_INTERVAL=15s -ENV PYROSCOPE_LOG_LEVEL=debug -ENV PYROSCOPE_SERVER_ADDRESS=http://localhost:4040 - -ENV OTEL_JAVAAGENT_EXTENSIONS=./pyroscope-otel.jar - -ENV OTEL_PYROSCOPE_ADD_PROFILE_URL=false -ENV OTEL_PYROSCOPE_ADD_PROFILE_BASELINE_URL=false -ENV OTEL_PYROSCOPE_START_PROFILING=true - -COPY --from=builder /opt/app/build/libs/rideshare-1.0-SNAPSHOT.jar /opt/app/build/libs/rideshare-1.0-SNAPSHOT.jar - -WORKDIR /opt/app - -ADD https://github.com/grafana/pyroscope-java/releases/download/v0.12.2/pyroscope.jar /opt/app/pyroscope.jar -ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.17.0/opentelemetry-javaagent.jar opentelemetry-javaagent.jar -ADD https://repo1.maven.org/maven2/io/pyroscope/otel/0.10.1.11/otel-0.10.1.11.jar pyroscope-otel.jar - -EXPOSE 5000 - -CMD ["java", "-Dserver.port=5000", "-javaagent:./opentelemetry-javaagent.jar", "-javaagent:pyroscope.jar", "-jar", "./build/libs/rideshare-1.0-SNAPSHOT.jar" ] diff --git a/examples/language-sdk-instrumentation/java/rideshare/README.md b/examples/language-sdk-instrumentation/java/rideshare/README.md index eb1d5a9d43..7c29d1c537 100644 --- a/examples/language-sdk-instrumentation/java/rideshare/README.md +++ b/examples/language-sdk-instrumentation/java/rideshare/README.md @@ -49,8 +49,9 @@ What this block does, is: ### Running the example To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: docker-compose up --build diff --git a/examples/language-sdk-instrumentation/java/rideshare/build.gradle.kts b/examples/language-sdk-instrumentation/java/rideshare/build.gradle.kts index c482284773..c71a57c3a7 100644 --- a/examples/language-sdk-instrumentation/java/rideshare/build.gradle.kts +++ b/examples/language-sdk-instrumentation/java/rideshare/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java") - id("org.springframework.boot") version "2.7.0" - id("io.spring.dependency-management") version "1.0.11.RELEASE" + id("org.springframework.boot") version "3.3.6" + id("io.spring.dependency-management") version "1.1.6" } group = "org.example" @@ -11,8 +11,11 @@ repositories { mavenCentral() } +ext["tomcat.version"] = "10.1.35" + dependencies { - implementation("io.pyroscope:agent:0.13.1") + implementation("io.pyroscope:agent:2.5.4") + implementation("org.jetbrains:annotations:26.0.2") implementation("org.springframework.boot:spring-boot-starter-web") testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2") diff --git a/examples/language-sdk-instrumentation/java/rideshare/docker-compose.yml b/examples/language-sdk-instrumentation/java/rideshare/docker-compose.yml index 9e77934032..362b1155b9 100644 --- a/examples/language-sdk-instrumentation/java/rideshare/docker-compose.yml +++ b/examples/language-sdk-instrumentation/java/rideshare/docker-compose.yml @@ -1,38 +1,49 @@ -version: '3' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: ports: - - 5000 + - 5000 environment: - - REGION=us-east - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - REGION=us-east + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 build: context: . - eu-north: ports: - - 5000 + - 5000 environment: - - REGION=eu-north - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - REGION=eu-north + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 build: context: . - ap-south: ports: - - 5000 + - 5000 environment: - - REGION=ap-south - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - REGION=ap-south + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 build: context: . - load-generator: build: context: . dockerfile: Dockerfile.load-generator + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/java/rideshare/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/java/rideshare/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/java/rideshare/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/Main.java b/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/Main.java index faf80719ff..da033d7103 100644 --- a/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/Main.java +++ b/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/Main.java @@ -1,6 +1,10 @@ package org.example.rideshare; -import io.pyroscope.labels.Pyroscope; +import io.pyroscope.javaagent.PyroscopeAgent; +import io.pyroscope.javaagent.config.Config; +import io.pyroscope.javaagent.impl.DefaultConfigurationProvider; +import io.pyroscope.labels.v2.Pyroscope; +import org.jetbrains.annotations.NotNull; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -10,8 +14,21 @@ public class Main { public static void main(String[] args) { Pyroscope.setStaticLabels(Map.of( - "region", System.getenv("REGION"), - "hostname", System.getenv("HOSTNAME"))); + "region", env("REGION", "us-east-1"), + "hostname", env("HOSTNAME", "localhost"))); + if (!PyroscopeAgent.isStarted()) { + // If we have not started the sdk with -javaagent (for example running from an IDE) + // allow starting the sdk here for convenience + PyroscopeAgent.start(Config.build(DefaultConfigurationProvider.INSTANCE)); + } SpringApplication.run(Main.class, args); } + + public static @NotNull String env(@NotNull String key, @NotNull String fallback) { + final String env = System.getenv(key); + if (env == null) { + return fallback; + } + return env; + } } diff --git a/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/OrderService.java b/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/OrderService.java index 40620c5e83..d86cd15b7e 100644 --- a/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/OrderService.java +++ b/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/OrderService.java @@ -1,7 +1,7 @@ package org.example.rideshare; -import io.pyroscope.labels.LabelsSet; -import io.pyroscope.labels.Pyroscope; +import io.pyroscope.labels.v2.LabelsSet; +import io.pyroscope.labels.v2.Pyroscope; import org.springframework.stereotype.Service; import java.time.Duration; diff --git a/examples/language-sdk-instrumentation/java/simple/Dockerfile b/examples/language-sdk-instrumentation/java/simple/Dockerfile index e8d3960b70..f80c6609b6 100644 --- a/examples/language-sdk-instrumentation/java/simple/Dockerfile +++ b/examples/language-sdk-instrumentation/java/simple/Dockerfile @@ -1,8 +1,8 @@ -FROM openjdk:11.0.11-jdk +FROM eclipse-temurin:11.0.31_11-jdk-jammy WORKDIR /opt/app -ADD https://github.com/grafana/pyroscope-java/releases/download/v0.13.1/pyroscope.jar /opt/app/pyroscope.jar +ADD https://github.com/grafana/pyroscope-java/releases/download/v2.5.4/pyroscope.jar /opt/app/pyroscope.jar COPY Main.java ./Main.java RUN javac Main.java diff --git a/examples/language-sdk-instrumentation/java/simple/README.md b/examples/language-sdk-instrumentation/java/simple/README.md index 039ef5aff0..ed20024ebd 100644 --- a/examples/language-sdk-instrumentation/java/simple/README.md +++ b/examples/language-sdk-instrumentation/java/simple/README.md @@ -4,8 +4,9 @@ To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: docker-compose up --build diff --git a/examples/language-sdk-instrumentation/java/simple/docker-compose.yml b/examples/language-sdk-instrumentation/java/simple/docker-compose.yml index fbf457ba64..7e67901144 100644 --- a/examples/language-sdk-instrumentation/java/simple/docker-compose.yml +++ b/examples/language-sdk-instrumentation/java/simple/docker-compose.yml @@ -1,11 +1,24 @@ ---- -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 app: build: . privileged: true + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/java/simple/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/java/simple/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/java/simple/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/load.js b/examples/language-sdk-instrumentation/load.js new file mode 100644 index 0000000000..ee11f8a28b --- /dev/null +++ b/examples/language-sdk-instrumentation/load.js @@ -0,0 +1,18 @@ +import { check } from 'k6'; +import http from 'k6/http'; + +export const options = { + duration: '5m', + vus: 3, +}; + +const URL = __ENV.TARGET_URL || 'http://localhost:5000'; + +export default function() { + for (const endpoint of ['car', 'scooter', 'bike']) { + const res = http.get(`${URL}/${endpoint}`); + check(res, { + 'status is 200': (r) => r.status === 200, + }); + } +} diff --git a/examples/language-sdk-instrumentation/nodejs/README.md b/examples/language-sdk-instrumentation/nodejs/README.md index 5099d66cf9..2a1555c4b9 100644 --- a/examples/language-sdk-instrumentation/nodejs/README.md +++ b/examples/language-sdk-instrumentation/nodejs/README.md @@ -43,8 +43,9 @@ To use any of the examples, run the following commands: # change directory cd express # or cd express-ts / cs express-pull -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: docker-compose up --build diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/.gitignore b/examples/language-sdk-instrumentation/nodejs/express-pull/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/.npmrc b/examples/language-sdk-instrumentation/nodejs/express-pull/.npmrc new file mode 100644 index 0000000000..97b895e2f9 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/.npmrc @@ -0,0 +1 @@ +ignore-scripts=true diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/.yarnrc b/examples/language-sdk-instrumentation/nodejs/express-pull/.yarnrc new file mode 100644 index 0000000000..00d04ff37e --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/.yarnrc @@ -0,0 +1 @@ +--install.ignore-scripts true diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/Dockerfile b/examples/language-sdk-instrumentation/nodejs/express-pull/Dockerfile index 708be4d4c9..702514a271 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-pull/Dockerfile +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/Dockerfile @@ -1,8 +1,8 @@ -FROM node:latest +FROM node:25 WORKDIR /app -COPY package.json yarn.lock . +COPY package.json yarn.lock .npmrc .yarnrc . RUN yarn install COPY index.js . diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/README.md b/examples/language-sdk-instrumentation/nodejs/express-pull/README.md index 87ce20ec92..9ce3e46cfa 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-pull/README.md +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/README.md @@ -1,39 +1,21 @@ -# Pyroscope pull with static targets +# Pyroscope pull mode with Grafana Alloy -This example demonstrates how Pyroscope can be used to scrape pprof profiles from remote nodejs targets. +This example demonstrates how Pyroscope can be used to scrape pprof profiles from remote nodejs targets using [Grafana Alloy](https://grafana.com/docs/alloy/latest/). -### 1. Run Pyroscope server and demo application in docker containers +Instead of the application pushing profiles to Pyroscope, Alloy periodically scrapes the pprof endpoints exposed by each nodejs instance and forwards the profiles to the Pyroscope server. + +### 1. Run Pyroscope server, Alloy, and demo application in docker containers ```shell docker-compose up -d ``` -As a sample application we use slightly modified rideshare app - -Note that we apply configuration defined in `server.yml`: - -
- server.yml - -```yaml ---- -log-level: debug -scrape-configs: - - job-name: testing - enabled-profiles: [cpu] - static-configs: - - application: rideshare - spy-name: nodespy - targets: - - rideshare:3000 - labels: - env: dev -``` +As a sample application we use a slightly modified rideshare app, started in three regions (`us-east`, `eu-north`, `ap-south`). Each instance exposes pprof endpoints via the `@pyroscope/nodejs` express middleware. -
+The scrape configuration lives in [`alloy.config.alloy`](./alloy.config.alloy): Alloy scrapes each target and forwards the profiles to the Pyroscope `write` endpoint. ### 2. Observe profiling data -Profiling is more fun when the application does some work, so it shipped with built-in load generator. +Profiling is more fun when the application does some work, so it ships with a built-in load generator. -Now that everything is set up, you can browse profiling data via [Pyroscope UI](http://localhost:4040). +Now that everything is set up, you can browse profiling data via the [Pyroscope UI](http://localhost:4040) or the bundled [Grafana instance](http://localhost:3000). Alloy's own UI is available at http://localhost:12345. diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/agent.config.river b/examples/language-sdk-instrumentation/nodejs/express-pull/alloy.config.alloy similarity index 100% rename from examples/language-sdk-instrumentation/nodejs/express-pull/agent.config.river rename to examples/language-sdk-instrumentation/nodejs/express-pull/alloy.config.alloy diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/docker-compose.yml b/examples/language-sdk-instrumentation/nodejs/express-pull/docker-compose.yml index 7d854ccc35..1331551f3d 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-pull/docker-compose.yml +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/docker-compose.yml @@ -1,47 +1,54 @@ -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - - agent: - image: grafana/agent:latest + - 4040:4040 + alloy: + image: grafana/alloy:latest volumes: - - ./agent.config.river:/etc/agent-config/config.river:ro + - ./alloy.config.alloy:/etc/alloy-config/config.alloy:ro command: - - run - - /etc/agent-config/config.river - - --server.http.listen-addr=0.0.0.0:12345 - environment: - HOSTNAME: agent - AGENT_MODE: flow + - run + - /etc/alloy-config/config.alloy + - --server.http.listen-addr=0.0.0.0:12345 ports: - - "12345:12345" - + - 12345:12345 us-east: environment: - - REGION=us-east + - REGION=us-east build: context: . - eu-north: environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: ../ dockerfile: Dockerfile.load-generator depends_on: - - us-east - - eu-north - - ap-south + - us-east + - eu-north + - ap-south + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/nodejs/express-pull/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/package.json b/examples/language-sdk-instrumentation/nodejs/express-pull/package.json index 1fad9d924f..28c1d0208e 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-pull/package.json +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/package.json @@ -10,12 +10,12 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "@pyroscope/nodejs": "v0.3.11", + "@pyroscope/nodejs": "v0.4.11", "express": "^4.19.2", "morgan": "^1.10.0" }, "resolutions": { - "protobufjs": "^7.2.5", + "protobufjs": "^7.5.5", "tar": "^6.2.1" } } diff --git a/examples/language-sdk-instrumentation/nodejs/express-pull/yarn.lock b/examples/language-sdk-instrumentation/nodejs/express-pull/yarn.lock index 0ef5de8d9f..0d5296da57 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-pull/yarn.lock +++ b/examples/language-sdk-instrumentation/nodejs/express-pull/yarn.lock @@ -2,15 +2,15 @@ # yarn lockfile v1 -"@datadog/pprof@^5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219" - integrity sha512-53z2Q3K92T6Pf4vz4Ezh8kfkVEvLzbnVqacZGgcbkP//q0joFzO8q00Etw1S6NdnCX0XmX08ULaF4rUI5r14mw== +"@datadog/pprof@5.13.3": + version "5.13.3" + resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.13.3.tgz#7080d38b6c05736cb8a027835707ee4ee43eedf3" + integrity sha512-G25IicP7pc5CXmAfVz7nrIERsKK9hvPz6p7xsLTUwG4Qs+Zgd5KFedKCVsnvNasLc7l7OXQ6839ajowgQLWTyw== dependencies: delay "^5.0.0" node-gyp-build "<4.0" p-limit "^3.1.0" - pprof-format "^2.1.0" + pprof-format "^2.2.1" source-map "^0.7.4" "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": @@ -66,17 +66,16 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@pyroscope/nodejs@v0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.3.11.tgz#d3ffed8423b628701d06cdc6ef97fd5943d91939" - integrity sha512-xqxUDrzgdfTic4QU3FyvPvO3iAF63zEEI+gXgBBNA6MrJVOJxaEDJkeOGnH0AT7yG/vLJVmSeo4+VyIKrCmztw== +"@pyroscope/nodejs@v0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.4.11.tgz#ef78d106845834773d4aed21264f400d72a93dbc" + integrity sha512-hfLE72zc8toxC4UPgSPHxglHfFF9+62YqhqUC6LsK5pdaBQBKjqvIW9EFL6vp5c3lSs7ctjnLy2Rki9RCsqQ8g== dependencies: - "@datadog/pprof" "^5.3.0" - axios "^0.28.0" - debug "^4.3.3" - form-data "^4.0.0" - regenerator-runtime "^0.13.11" - source-map "^0.7.3" + "@datadog/pprof" "5.13.3" + debug "^4.4.3" + p-limit "^7.3.0" + regenerator-runtime "^0.14.1" + source-map "^0.7.6" "@types/node@>=13.7.0": version "20.11.20" @@ -98,20 +97,6 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -axios@^0.28.0: - version "0.28.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.0.tgz#801a4d991d0404961bccef46800e1170f8278c89" - integrity sha512-Tu7NYoGY4Yoc7I+Npf9HhUMtEEpV7ZiLH9yndTCoNhcpBH0kwcvFbzYN9/u5QKI5A6uefjsNNWaz5olJVYS62Q== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - basic-auth@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" @@ -158,13 +143,6 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -194,12 +172,12 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^4.3.3: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: - ms "2.1.2" + ms "^2.1.3" define-data-property@^1.1.2: version "1.1.4" @@ -215,11 +193,6 @@ delay@^5.0.0: resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - depd@2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -312,20 +285,6 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" -follow-redirects@^1.15.0: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -443,7 +402,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -496,12 +455,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -547,6 +501,13 @@ p-limit@^3.1.0: dependencies: yocto-queue "^0.1.0" +p-limit@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-7.3.0.tgz#821398d91491c6b6a1340ecd09cdc402a9c8d0ee" + integrity sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw== + dependencies: + yocto-queue "^1.2.1" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -557,15 +518,15 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== -pprof-format@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.1.0.tgz#acc8d7773bcf4faf0a3d3df11bceefba7ac06664" - integrity sha512-0+G5bHH0RNr8E5hoZo/zJYsL92MhkZjwrHp3O2IxmY8RJL9ooKeuZ8Tm0ZNBw5sGZ9TiM71sthTjWoR2Vf5/xw== +pprof-format@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.2.1.tgz#64d32207fb46990349eb52825defb449d6ccc9b4" + integrity sha512-p4tVN7iK19ccDqQv8heyobzUmbHyds4N2FI6aBMcXz6y99MglTWDxIyhFkNaLeEXs6IFUEzT0zya0icbSLLY0g== -protobufjs@^7.2.5: - version "7.2.6" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215" - integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== +protobufjs@^7.5.5: + version "7.5.5" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.5.tgz#b7089ca4410374c75150baf277353ef76db69f96" + integrity sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -588,11 +549,6 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -615,10 +571,10 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== safe-buffer@5.1.2: version "5.1.2" @@ -691,11 +647,16 @@ side-channel@^1.0.4: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -source-map@^0.7.3, source-map@^0.7.4: +source-map@^0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +source-map@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -755,3 +716,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yocto-queue@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" + integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.gitignore b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.npmrc b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.npmrc new file mode 100644 index 0000000000..97b895e2f9 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.npmrc @@ -0,0 +1 @@ +ignore-scripts=true diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.yarnrc b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.yarnrc new file mode 100644 index 0000000000..00d04ff37e --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/.yarnrc @@ -0,0 +1 @@ +--install.ignore-scripts true diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile index b8694b5bd1..2f1625fa54 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/Dockerfile @@ -1,12 +1,13 @@ -FROM node:latest +FROM node:25 WORKDIR /app -COPY package.json yarn.lock . +COPY package.json yarn.lock .npmrc .yarnrc . +RUN yarn + COPY tsconfig.json . -RUN yarn COPY *.ts . RUN yarn build -ENV DEBUG=pyroscope -CMD ["yarn", "run", "run"] +ENV DEBUG=pyroscope +CMD ["yarn", "start"] diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/docker-compose.yml b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/docker-compose.yml index 6f23a94ebf..4609880438 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/docker-compose.yml +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/docker-compose.yml @@ -1,40 +1,50 @@ ---- -version: '3.9' services: pyroscope: - image: 'grafana/pyroscope:latest' + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: ports: - - 5000 + - 5000 environment: - - REGION=us-east + - REGION=us-east build: context: . - eu-north: ports: - - 5000 + - 5000 environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: ports: - - 5000 + - 5000 environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: ../ dockerfile: Dockerfile.load-generator depends_on: - - us-east - - eu-north - - ap-south + - us-east + - eu-north + - ap-south + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts index d85af51fb2..88a5d0375b 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/index.ts @@ -6,17 +6,18 @@ const Pyroscope = require('@pyroscope/nodejs'); const SourceMapper = Pyroscope.default.SourceMapper; const port = process.env['PORT'] || 5000; - const region = process.env['REGION'] || 'default'; +const appName = process.env['APP_NAME'] || 'express-ts-inline'; +const pyroscopeUrl = process.env['PYROSCOPE_URL'] || 'http://pyroscope:4040'; const app = express(); app.use(morgan('dev')); -app.get('/', (req, res) => { +app.get('/', (_, res) => { res.send('Available routes are: /bike, /car, /scooter'); }); -const genericSearchHandler = (p: number) => (req: any, res: any) => { +const genericSearchHandler = (p: number) => (_: any, res: any) => { const time = +new Date() + p * 1000; let i = 0; while (+new Date() < time) { @@ -30,11 +31,13 @@ app.get('/bike', function bikeSearchHandler(req, res) { genericSearchHandler(0.2)(req, res) ); }); + app.get('/car', function carSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'car' }, () => genericSearchHandler(1)(req, res) ); }); + app.get('/scooter', function scooterSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'scooter' }, () => genericSearchHandler(0.5)(req, res) @@ -44,14 +47,14 @@ app.get('/scooter', function scooterSearchHandler(req, res) { SourceMapper.create(['.']) .then((sourceMapper) => { Pyroscope.init({ - appName: 'nodejs', - serverAddress: 'http://pyroscope:4040', + appName: appName, + serverAddress: pyroscopeUrl, sourceMapper: sourceMapper, tags: { region }, }); Pyroscope.start(); }) - .catch((e) => { + .catch((e: any) => { console.error(e); }); diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json index 2c7a384eb3..d2850dc640 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/package.json @@ -5,24 +5,29 @@ "scripts": { "build": "tsc", "test": "echo \"Error: no test specified\" && exit 1", - "run": "node build/index.js" + "start": "node build/index.js", + "start:local": "yarn build && PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" }, "author": "", "license": "Apache-2.0", "dependencies": { - "@pyroscope/nodejs": "v0.3.11", - "axios": "^0.28.0", - "express": "^4.19.2", - "morgan": "^1.10.0", - "typescript": "^4.6.2" + "@pyroscope/nodejs": "v0.4.11", + "axios": "^1.15.2", + "express": "^4.20.0", + "morgan": "^1.10.0" }, "devDependencies": { "@types/express": "^4.17.13", - "@types/morgan": "^1.9.3" + "@types/morgan": "^1.9.3", + "typescript": "^4.6.2" }, "resolutions": { - "protobufjs": "^7.2.5", + "protobufjs": "^7.5.8", "tar": "^6.2.1", - "@types/mime": "3.0.4" + "@types/mime": "3.0.4", + "qs": "^6.14.1", + "path-to-regexp": "^0.1.12" } } diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/yarn.lock b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/yarn.lock index 69b464e665..d86ee81919 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts-inline/yarn.lock +++ b/examples/language-sdk-instrumentation/nodejs/express-ts-inline/yarn.lock @@ -2,15 +2,15 @@ # yarn lockfile v1 -"@datadog/pprof@^5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219" - integrity sha512-53z2Q3K92T6Pf4vz4Ezh8kfkVEvLzbnVqacZGgcbkP//q0joFzO8q00Etw1S6NdnCX0XmX08ULaF4rUI5r14mw== +"@datadog/pprof@5.13.3": + version "5.13.3" + resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.13.3.tgz#7080d38b6c05736cb8a027835707ee4ee43eedf3" + integrity sha512-G25IicP7pc5CXmAfVz7nrIERsKK9hvPz6p7xsLTUwG4Qs+Zgd5KFedKCVsnvNasLc7l7OXQ6839ajowgQLWTyw== dependencies: delay "^5.0.0" node-gyp-build "<4.0" p-limit "^3.1.0" - pprof-format "^2.1.0" + pprof-format "^2.2.1" source-map "^0.7.4" "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": @@ -23,33 +23,32 @@ resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== +"@protobufjs/codegen@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.5.tgz#d9315ad7cf3f30aac70bda3c068443dc6f143659" + integrity sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g== -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== +"@protobufjs/eventemitter@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz#d512cb26c0ae026091ee2c1167f1be6faf5c842a" + integrity sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg== -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== +"@protobufjs/fetch@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.1.tgz#4d6fc00c8fb64016a5c81b469d549046350f1065" + integrity sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw== dependencies: "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" "@protobufjs/float@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== +"@protobufjs/inquire@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.2.tgz#ae64fbc014ff44c8bfad03dd4c93cd2d6a4c82db" + integrity sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw== "@protobufjs/path@^1.1.2": version "1.1.2" @@ -61,22 +60,21 @@ resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@protobufjs/utf8@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.1.tgz#eaee5900122c110a3dbcb728c0597014a2621774" + integrity sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg== -"@pyroscope/nodejs@v0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.3.11.tgz#d3ffed8423b628701d06cdc6ef97fd5943d91939" - integrity sha512-xqxUDrzgdfTic4QU3FyvPvO3iAF63zEEI+gXgBBNA6MrJVOJxaEDJkeOGnH0AT7yG/vLJVmSeo4+VyIKrCmztw== +"@pyroscope/nodejs@v0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.4.11.tgz#ef78d106845834773d4aed21264f400d72a93dbc" + integrity sha512-hfLE72zc8toxC4UPgSPHxglHfFF9+62YqhqUC6LsK5pdaBQBKjqvIW9EFL6vp5c3lSs7ctjnLy2Rki9RCsqQ8g== dependencies: - "@datadog/pprof" "^5.3.0" - axios "^0.28.0" - debug "^4.3.3" - form-data "^4.0.0" - regenerator-runtime "^0.13.11" - source-map "^0.7.3" + "@datadog/pprof" "5.13.3" + debug "^4.4.3" + p-limit "^7.3.0" + regenerator-runtime "^0.14.1" + source-map "^0.7.6" "@types/body-parser@*": version "1.19.5" @@ -182,14 +180,14 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@^0.28.0: - version "0.28.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.1.tgz#2a7bcd34a3837b71ee1a5ca3762214b86b703e70" - integrity sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ== +axios@^1.15.2: + version "1.15.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.15.2.tgz#eb8fb6d30349abace6ade5b4cb4d9e8a0dc23e5b" + integrity sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A== dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" + follow-redirects "^1.15.11" + form-data "^4.0.5" + proxy-from-env "^2.1.0" basic-auth@~2.0.1: version "2.0.1" @@ -198,10 +196,10 @@ basic-auth@~2.0.1: dependencies: safe-buffer "5.1.2" -body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -211,7 +209,7 @@ body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -221,16 +219,21 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: - es-define-property "^1.0.0" es-errors "^1.3.0" function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" + +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" chownr@^2.0.0: version "2.0.0" @@ -273,21 +276,12 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^4.3.3: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -define-data-property@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== +debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" + ms "^2.1.3" delay@^5.0.0: version "5.0.0" @@ -309,6 +303,15 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -319,18 +322,38 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -341,37 +364,37 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -express@^4.19.2: - version "4.19.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== +express@^4.20.0: + version "4.20.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.20.0.tgz#f1d08e591fcec770c07be4767af8eb9bcfd67c48" + integrity sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" finalhandler "1.2.0" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" qs "6.11.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.0" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -391,18 +414,20 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" -follow-redirects@^1.15.0: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +follow-redirects@^1.15.11: + version "1.16.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.16.0.tgz#28474a159d3b9d11ef62050a14ed60e4df6d61bc" + integrity sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw== -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +form-data@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" mime-types "^2.1.12" forwarded@0.2.0: @@ -427,45 +452,56 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== +get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" es-errors "^1.3.0" + es-object-atoms "^1.1.1" function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" -gopd@^1.0.1: +get-proto@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -has-property-descriptors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== dependencies: - es-define-property "^1.0.0" + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" -has-proto@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -hasown@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa" - integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -497,20 +533,25 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -long@^5.0.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" - integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== +long@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== methods@~1.1.2: version "1.1.2" @@ -575,12 +616,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -595,10 +631,10 @@ node-gyp-build@<4.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.9.0.tgz#53a350187dd4d5276750da21605d1cb681d09e25" integrity sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A== -object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== on-finished@2.4.1: version "2.4.1" @@ -626,38 +662,45 @@ p-limit@^3.1.0: dependencies: yocto-queue "^0.1.0" +p-limit@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-7.3.0.tgz#821398d91491c6b6a1340ecd09cdc402a9c8d0ee" + integrity sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw== + dependencies: + yocto-queue "^1.2.1" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@0.1.10, path-to-regexp@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== -pprof-format@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.1.0.tgz#acc8d7773bcf4faf0a3d3df11bceefba7ac06664" - integrity sha512-0+G5bHH0RNr8E5hoZo/zJYsL92MhkZjwrHp3O2IxmY8RJL9ooKeuZ8Tm0ZNBw5sGZ9TiM71sthTjWoR2Vf5/xw== +pprof-format@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.2.1.tgz#64d32207fb46990349eb52825defb449d6ccc9b4" + integrity sha512-p4tVN7iK19ccDqQv8heyobzUmbHyds4N2FI6aBMcXz6y99MglTWDxIyhFkNaLeEXs6IFUEzT0zya0icbSLLY0g== -protobufjs@^7.2.5: - version "7.2.6" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215" - integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== +protobufjs@^7.5.8: + version "7.6.1" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.6.1.tgz#6320bb08c3be7dcfc6f9193ee03d3a4643f1eb37" + integrity sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" + "@protobufjs/codegen" "^2.0.5" + "@protobufjs/eventemitter" "^1.1.1" + "@protobufjs/fetch" "^1.1.1" "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" + "@protobufjs/inquire" "^1.1.2" "@protobufjs/path" "^1.1.2" "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" + "@protobufjs/utf8" "^1.1.1" "@types/node" ">=13.7.0" - long "^5.0.0" + long "^5.3.2" proxy-addr@~2.0.7: version "2.0.7" @@ -667,17 +710,17 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +proxy-from-env@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz#a7487568adad577cfaaa7e88c49cab3ab3081aba" + integrity sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.11.0, qs@6.13.0, qs@^6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.1.tgz#a41d85b9d3902f31d27861790506294881871159" + integrity sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ== dependencies: - side-channel "^1.0.4" + side-channel "^1.1.0" range-parser@~1.2.1: version "1.2.1" @@ -694,10 +737,10 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== safe-buffer@5.1.2: version "5.1.2" @@ -733,48 +776,90 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" encodeurl "~1.0.2" escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" -set-function-length@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425" - integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== +serve-static@1.16.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.0.tgz#2bf4ed49f8af311b519c46f272bf6ac3baf38a92" + integrity sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA== dependencies: - define-data-property "^1.1.2" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -side-channel@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.5.tgz#9a84546599b48909fb6af1211708d23b1946221b" - integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== dependencies: - call-bind "^1.0.6" + call-bound "^1.0.2" es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" -source-map@^0.7.3, source-map@^0.7.4: +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +source-map@^0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +source-map@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -839,3 +924,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yocto-queue@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" + integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/.gitignore b/examples/language-sdk-instrumentation/nodejs/express-ts/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/.npmrc b/examples/language-sdk-instrumentation/nodejs/express-ts/.npmrc new file mode 100644 index 0000000000..97b895e2f9 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/.npmrc @@ -0,0 +1 @@ +ignore-scripts=true diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/.yarnrc b/examples/language-sdk-instrumentation/nodejs/express-ts/.yarnrc new file mode 100644 index 0000000000..00d04ff37e --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/.yarnrc @@ -0,0 +1 @@ +--install.ignore-scripts true diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile b/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile index b8694b5bd1..2f1625fa54 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/Dockerfile @@ -1,12 +1,13 @@ -FROM node:latest +FROM node:25 WORKDIR /app -COPY package.json yarn.lock . +COPY package.json yarn.lock .npmrc .yarnrc . +RUN yarn + COPY tsconfig.json . -RUN yarn COPY *.ts . RUN yarn build -ENV DEBUG=pyroscope -CMD ["yarn", "run", "run"] +ENV DEBUG=pyroscope +CMD ["yarn", "start"] diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/docker-compose.yml b/examples/language-sdk-instrumentation/nodejs/express-ts/docker-compose.yml index 6f23a94ebf..4609880438 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/docker-compose.yml +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/docker-compose.yml @@ -1,40 +1,50 @@ ---- -version: '3.9' services: pyroscope: - image: 'grafana/pyroscope:latest' + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: ports: - - 5000 + - 5000 environment: - - REGION=us-east + - REGION=us-east build: context: . - eu-north: ports: - - 5000 + - 5000 environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: ports: - - 5000 + - 5000 environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: ../ dockerfile: Dockerfile.load-generator depends_on: - - us-east - - eu-north - - ap-south + - us-east + - eu-north + - ap-south + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/nodejs/express-ts/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts b/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts index 0ac251d9d6..7619b58f50 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/index.ts @@ -6,17 +6,18 @@ import Pyroscope from '@pyroscope/nodejs'; const SourceMapper = Pyroscope.SourceMapper; const port = process.env['PORT'] || 5000; - const region = process.env['REGION'] || 'default'; +const appName = process.env['APP_NAME'] || 'express-ts'; +const pyroscopeUrl = process.env['PYROSCOPE_URL'] || 'http://pyroscope:4040'; const app = express(); app.use(morgan('dev')); -app.get('/', (req, res) => { +app.get('/', (_, res) => { res.send('Available routes are: /bike, /car, /scooter'); }); -const genericSearchHandler = (p: number) => (req: any, res: any) => { +const genericSearchHandler = (p: number) => (_: any, res: any) => { const time = +new Date() + p * 1000; let i = 0; while (+new Date() < time) { @@ -30,11 +31,13 @@ app.get('/bike', function bikeSearchHandler(req, res) { genericSearchHandler(0.2)(req, res) ); }); + app.get('/car', function carSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'car' }, () => genericSearchHandler(1)(req, res) ); }); + app.get('/scooter', function scooterSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'scooter' }, () => genericSearchHandler(0.5)(req, res) @@ -44,8 +47,8 @@ app.get('/scooter', function scooterSearchHandler(req, res) { SourceMapper.create(['.']) .then((sourceMapper) => { Pyroscope.init({ - appName: 'nodejs', - serverAddress: 'http://pyroscope:4040', + appName: appName, + serverAddress: pyroscopeUrl, sourceMapper: sourceMapper, tags: { region }, }); diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/package.json b/examples/language-sdk-instrumentation/nodejs/express-ts/package.json index 2c7a384eb3..11a8a63eb3 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/package.json +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/package.json @@ -5,23 +5,26 @@ "scripts": { "build": "tsc", "test": "echo \"Error: no test specified\" && exit 1", - "run": "node build/index.js" + "start": "node build/index.js", + "start:local": "yarn build && PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" }, "author": "", "license": "Apache-2.0", "dependencies": { - "@pyroscope/nodejs": "v0.3.11", - "axios": "^0.28.0", + "@pyroscope/nodejs": "v0.4.11", + "axios": "^1.15.0", "express": "^4.19.2", - "morgan": "^1.10.0", - "typescript": "^4.6.2" + "morgan": "^1.10.0" }, "devDependencies": { "@types/express": "^4.17.13", - "@types/morgan": "^1.9.3" + "@types/morgan": "^1.9.3", + "typescript": "^4.6.2" }, "resolutions": { - "protobufjs": "^7.2.5", + "protobufjs": "^7.5.5", "tar": "^6.2.1", "@types/mime": "3.0.4" } diff --git a/examples/language-sdk-instrumentation/nodejs/express-ts/yarn.lock b/examples/language-sdk-instrumentation/nodejs/express-ts/yarn.lock index 69b464e665..08751f02a8 100644 --- a/examples/language-sdk-instrumentation/nodejs/express-ts/yarn.lock +++ b/examples/language-sdk-instrumentation/nodejs/express-ts/yarn.lock @@ -2,15 +2,15 @@ # yarn lockfile v1 -"@datadog/pprof@^5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219" - integrity sha512-53z2Q3K92T6Pf4vz4Ezh8kfkVEvLzbnVqacZGgcbkP//q0joFzO8q00Etw1S6NdnCX0XmX08ULaF4rUI5r14mw== +"@datadog/pprof@5.13.3": + version "5.13.3" + resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.13.3.tgz#7080d38b6c05736cb8a027835707ee4ee43eedf3" + integrity sha512-G25IicP7pc5CXmAfVz7nrIERsKK9hvPz6p7xsLTUwG4Qs+Zgd5KFedKCVsnvNasLc7l7OXQ6839ajowgQLWTyw== dependencies: delay "^5.0.0" node-gyp-build "<4.0" p-limit "^3.1.0" - pprof-format "^2.1.0" + pprof-format "^2.2.1" source-map "^0.7.4" "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": @@ -23,33 +23,32 @@ resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== +"@protobufjs/codegen@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.5.tgz#d9315ad7cf3f30aac70bda3c068443dc6f143659" + integrity sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g== -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== +"@protobufjs/eventemitter@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz#d512cb26c0ae026091ee2c1167f1be6faf5c842a" + integrity sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg== -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== +"@protobufjs/fetch@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.1.tgz#4d6fc00c8fb64016a5c81b469d549046350f1065" + integrity sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw== dependencies: "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" "@protobufjs/float@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== +"@protobufjs/inquire@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.2.tgz#ae64fbc014ff44c8bfad03dd4c93cd2d6a4c82db" + integrity sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw== "@protobufjs/path@^1.1.2": version "1.1.2" @@ -61,22 +60,21 @@ resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@protobufjs/utf8@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.1.tgz#eaee5900122c110a3dbcb728c0597014a2621774" + integrity sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg== -"@pyroscope/nodejs@v0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.3.11.tgz#d3ffed8423b628701d06cdc6ef97fd5943d91939" - integrity sha512-xqxUDrzgdfTic4QU3FyvPvO3iAF63zEEI+gXgBBNA6MrJVOJxaEDJkeOGnH0AT7yG/vLJVmSeo4+VyIKrCmztw== +"@pyroscope/nodejs@v0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.4.11.tgz#ef78d106845834773d4aed21264f400d72a93dbc" + integrity sha512-hfLE72zc8toxC4UPgSPHxglHfFF9+62YqhqUC6LsK5pdaBQBKjqvIW9EFL6vp5c3lSs7ctjnLy2Rki9RCsqQ8g== dependencies: - "@datadog/pprof" "^5.3.0" - axios "^0.28.0" - debug "^4.3.3" - form-data "^4.0.0" - regenerator-runtime "^0.13.11" - source-map "^0.7.3" + "@datadog/pprof" "5.13.3" + debug "^4.4.3" + p-limit "^7.3.0" + regenerator-runtime "^0.14.1" + source-map "^0.7.6" "@types/body-parser@*": version "1.19.5" @@ -182,14 +180,14 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@^0.28.0: - version "0.28.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.1.tgz#2a7bcd34a3837b71ee1a5ca3762214b86b703e70" - integrity sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ== +axios@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.15.2.tgz#eb8fb6d30349abace6ade5b4cb4d9e8a0dc23e5b" + integrity sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A== dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" + follow-redirects "^1.15.11" + form-data "^4.0.5" + proxy-from-env "^2.1.0" basic-auth@~2.0.1: version "2.0.1" @@ -221,6 +219,14 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" @@ -273,12 +279,12 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^4.3.3: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: - ms "2.1.2" + ms "^2.1.3" define-data-property@^1.1.2: version "1.1.4" @@ -309,6 +315,15 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -326,11 +341,33 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -391,18 +428,20 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" -follow-redirects@^1.15.0: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +follow-redirects@^1.15.11: + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +form-data@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" mime-types "^2.1.12" forwarded@0.2.0: @@ -438,6 +477,30 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + gopd@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" @@ -445,6 +508,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + has-property-descriptors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" @@ -462,6 +530,18 @@ has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + hasown@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa" @@ -469,6 +549,13 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -497,10 +584,15 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -long@^5.0.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" - integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== +long@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== media-typer@0.3.0: version "0.3.0" @@ -575,12 +667,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -626,6 +713,13 @@ p-limit@^3.1.0: dependencies: yocto-queue "^0.1.0" +p-limit@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-7.3.0.tgz#821398d91491c6b6a1340ecd09cdc402a9c8d0ee" + integrity sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw== + dependencies: + yocto-queue "^1.2.1" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -636,28 +730,28 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== -pprof-format@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.1.0.tgz#acc8d7773bcf4faf0a3d3df11bceefba7ac06664" - integrity sha512-0+G5bHH0RNr8E5hoZo/zJYsL92MhkZjwrHp3O2IxmY8RJL9ooKeuZ8Tm0ZNBw5sGZ9TiM71sthTjWoR2Vf5/xw== +pprof-format@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.2.1.tgz#64d32207fb46990349eb52825defb449d6ccc9b4" + integrity sha512-p4tVN7iK19ccDqQv8heyobzUmbHyds4N2FI6aBMcXz6y99MglTWDxIyhFkNaLeEXs6IFUEzT0zya0icbSLLY0g== -protobufjs@^7.2.5: - version "7.2.6" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215" - integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== +protobufjs@^7.5.5: + version "7.6.1" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.6.1.tgz#6320bb08c3be7dcfc6f9193ee03d3a4643f1eb37" + integrity sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" + "@protobufjs/codegen" "^2.0.5" + "@protobufjs/eventemitter" "^1.1.1" + "@protobufjs/fetch" "^1.1.1" "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" + "@protobufjs/inquire" "^1.1.2" "@protobufjs/path" "^1.1.2" "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" + "@protobufjs/utf8" "^1.1.1" "@types/node" ">=13.7.0" - long "^5.0.0" + long "^5.3.2" proxy-addr@~2.0.7: version "2.0.7" @@ -667,10 +761,10 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +proxy-from-env@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz#a7487568adad577cfaaa7e88c49cab3ab3081aba" + integrity sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA== qs@6.11.0: version "6.11.0" @@ -694,10 +788,10 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== safe-buffer@5.1.2: version "5.1.2" @@ -770,11 +864,16 @@ side-channel@^1.0.4: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -source-map@^0.7.3, source-map@^0.7.4: +source-map@^0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +source-map@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -839,3 +938,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yocto-queue@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" + integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== diff --git a/examples/language-sdk-instrumentation/nodejs/express/.gitignore b/examples/language-sdk-instrumentation/nodejs/express/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/express/.npmrc b/examples/language-sdk-instrumentation/nodejs/express/.npmrc new file mode 100644 index 0000000000..97b895e2f9 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express/.npmrc @@ -0,0 +1 @@ +ignore-scripts=true diff --git a/examples/language-sdk-instrumentation/nodejs/express/.yarnrc b/examples/language-sdk-instrumentation/nodejs/express/.yarnrc new file mode 100644 index 0000000000..00d04ff37e --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express/.yarnrc @@ -0,0 +1 @@ +--install.ignore-scripts true diff --git a/examples/language-sdk-instrumentation/nodejs/express/Dockerfile b/examples/language-sdk-instrumentation/nodejs/express/Dockerfile index 708be4d4c9..9d14049b79 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/Dockerfile +++ b/examples/language-sdk-instrumentation/nodejs/express/Dockerfile @@ -1,11 +1,11 @@ -FROM node:latest +FROM node:25 WORKDIR /app -COPY package.json yarn.lock . +COPY package.json yarn.lock .npmrc .yarnrc . RUN yarn install COPY index.js . ENV DEBUG=pyroscope ENV PYROSCOPE_WALL_COLLECT_CPU_TIME=true -CMD ["node", "index.js"] +CMD ["node", "index.js"] diff --git a/examples/language-sdk-instrumentation/nodejs/express/docker-compose.yml b/examples/language-sdk-instrumentation/nodejs/express/docker-compose.yml index 798cf54bff..4609880438 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/docker-compose.yml +++ b/examples/language-sdk-instrumentation/nodejs/express/docker-compose.yml @@ -1,39 +1,50 @@ -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: ports: - - 5000 + - 5000 environment: - - REGION=us-east + - REGION=us-east build: context: . - eu-north: ports: - - 5000 + - 5000 environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: ports: - - 5000 + - 5000 environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: ../ dockerfile: Dockerfile.load-generator depends_on: - - us-east - - eu-north - - ap-south + - us-east + - eu-north + - ap-south + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/nodejs/express/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/nodejs/express/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/express/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/nodejs/express/index.js b/examples/language-sdk-instrumentation/nodejs/express/index.js index ac29ee3df3..e2511c6733 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/index.js +++ b/examples/language-sdk-instrumentation/nodejs/express/index.js @@ -1,20 +1,23 @@ /* eslint-disable */ const Pyroscope = require('@pyroscope/nodejs'); -const port = process.env['PORT'] || 5000; - +const port = process.env['RIDESHARE_LISTEN_PORT'] || 5000; const region = process.env['REGION'] || 'default'; +const appName = process.env['PYROSCOPE_APPLICATION_NAME'] || 'express'; +const pyroscopeUrl = process.env['PYROSCOPE_SERVER_ADDRESS'] || 'http://pyroscope:4040'; +const pyroscopeUser = process.env['PYROSCOPE_BASIC_AUTH_USER'] || ''; +const pyroscopePassword = process.env['PYROSCOPE_BASIC_AUTH_PASSWORD'] || ''; const express = require('express'); const morgan = require('morgan'); const app = express(); app.use(morgan('dev')); -app.get('/', (req, res) => { +app.get('/', (_, res) => { res.send('Available routes are: /bike, /car, /scooter'); }); -const genericSearchHandler = (p) => (req, res) => { +const genericSearchHandler = (p) => (_, res) => { const time = +new Date() + p * 1000; let i = 0; while (+new Date() < time) { @@ -24,11 +27,12 @@ const genericSearchHandler = (p) => (req, res) => { }; Pyroscope.init({ - appName: 'nodejs', - serverAddress: process.env['PYROSCOPE_SERVER'] || 'http://pyroscope:4040', + appName: appName, + serverAddress: pyroscopeUrl, + basicAuthUser: pyroscopeUser, + basicAuthPassword: pyroscopePassword, tags: { region }, }); - Pyroscope.start(); app.get('/bike', function bikeSearchHandler(req, res) { @@ -36,11 +40,13 @@ app.get('/bike', function bikeSearchHandler(req, res) { genericSearchHandler(0.5)(req, res) ); }); + app.get('/car', function carSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'car' }, () => genericSearchHandler(1)(req, res) ); }); + app.get('/scooter', function scooterSearchHandler(req, res) { Pyroscope.wrapWithLabels({ vehicle: 'scooter' }, () => genericSearchHandler(0.25)(req, res) diff --git a/examples/language-sdk-instrumentation/nodejs/express/package.json b/examples/language-sdk-instrumentation/nodejs/express/package.json index d97ad3668a..0e6803e400 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/package.json +++ b/examples/language-sdk-instrumentation/nodejs/express/package.json @@ -5,17 +5,20 @@ "main": "index.js", "scripts": { "start": "node index.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start:local": "PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" }, "author": "", "license": "Apache-2.0", "dependencies": { - "@pyroscope/nodejs": "v0.3.11", + "@pyroscope/nodejs": "v0.4.11", "express": "^4.19.2", "morgan": "^1.10.0" }, "resolutions": { - "protobufjs": "^7.2.5", + "protobufjs": "^7.5.5", "tar": "^6.2.1" } } diff --git a/examples/language-sdk-instrumentation/nodejs/express/yarn.lock b/examples/language-sdk-instrumentation/nodejs/express/yarn.lock index 0ef5de8d9f..0d5296da57 100644 --- a/examples/language-sdk-instrumentation/nodejs/express/yarn.lock +++ b/examples/language-sdk-instrumentation/nodejs/express/yarn.lock @@ -2,15 +2,15 @@ # yarn lockfile v1 -"@datadog/pprof@^5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219" - integrity sha512-53z2Q3K92T6Pf4vz4Ezh8kfkVEvLzbnVqacZGgcbkP//q0joFzO8q00Etw1S6NdnCX0XmX08ULaF4rUI5r14mw== +"@datadog/pprof@5.13.3": + version "5.13.3" + resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.13.3.tgz#7080d38b6c05736cb8a027835707ee4ee43eedf3" + integrity sha512-G25IicP7pc5CXmAfVz7nrIERsKK9hvPz6p7xsLTUwG4Qs+Zgd5KFedKCVsnvNasLc7l7OXQ6839ajowgQLWTyw== dependencies: delay "^5.0.0" node-gyp-build "<4.0" p-limit "^3.1.0" - pprof-format "^2.1.0" + pprof-format "^2.2.1" source-map "^0.7.4" "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": @@ -66,17 +66,16 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@pyroscope/nodejs@v0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.3.11.tgz#d3ffed8423b628701d06cdc6ef97fd5943d91939" - integrity sha512-xqxUDrzgdfTic4QU3FyvPvO3iAF63zEEI+gXgBBNA6MrJVOJxaEDJkeOGnH0AT7yG/vLJVmSeo4+VyIKrCmztw== +"@pyroscope/nodejs@v0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.4.11.tgz#ef78d106845834773d4aed21264f400d72a93dbc" + integrity sha512-hfLE72zc8toxC4UPgSPHxglHfFF9+62YqhqUC6LsK5pdaBQBKjqvIW9EFL6vp5c3lSs7ctjnLy2Rki9RCsqQ8g== dependencies: - "@datadog/pprof" "^5.3.0" - axios "^0.28.0" - debug "^4.3.3" - form-data "^4.0.0" - regenerator-runtime "^0.13.11" - source-map "^0.7.3" + "@datadog/pprof" "5.13.3" + debug "^4.4.3" + p-limit "^7.3.0" + regenerator-runtime "^0.14.1" + source-map "^0.7.6" "@types/node@>=13.7.0": version "20.11.20" @@ -98,20 +97,6 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -axios@^0.28.0: - version "0.28.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.0.tgz#801a4d991d0404961bccef46800e1170f8278c89" - integrity sha512-Tu7NYoGY4Yoc7I+Npf9HhUMtEEpV7ZiLH9yndTCoNhcpBH0kwcvFbzYN9/u5QKI5A6uefjsNNWaz5olJVYS62Q== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - basic-auth@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" @@ -158,13 +143,6 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -194,12 +172,12 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^4.3.3: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: - ms "2.1.2" + ms "^2.1.3" define-data-property@^1.1.2: version "1.1.4" @@ -215,11 +193,6 @@ delay@^5.0.0: resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - depd@2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -312,20 +285,6 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" -follow-redirects@^1.15.0: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -443,7 +402,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -496,12 +455,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -547,6 +501,13 @@ p-limit@^3.1.0: dependencies: yocto-queue "^0.1.0" +p-limit@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-7.3.0.tgz#821398d91491c6b6a1340ecd09cdc402a9c8d0ee" + integrity sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw== + dependencies: + yocto-queue "^1.2.1" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -557,15 +518,15 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== -pprof-format@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.1.0.tgz#acc8d7773bcf4faf0a3d3df11bceefba7ac06664" - integrity sha512-0+G5bHH0RNr8E5hoZo/zJYsL92MhkZjwrHp3O2IxmY8RJL9ooKeuZ8Tm0ZNBw5sGZ9TiM71sthTjWoR2Vf5/xw== +pprof-format@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.2.1.tgz#64d32207fb46990349eb52825defb449d6ccc9b4" + integrity sha512-p4tVN7iK19ccDqQv8heyobzUmbHyds4N2FI6aBMcXz6y99MglTWDxIyhFkNaLeEXs6IFUEzT0zya0icbSLLY0g== -protobufjs@^7.2.5: - version "7.2.6" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215" - integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== +protobufjs@^7.5.5: + version "7.5.5" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.5.tgz#b7089ca4410374c75150baf277353ef76db69f96" + integrity sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -588,11 +549,6 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -615,10 +571,10 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== safe-buffer@5.1.2: version "5.1.2" @@ -691,11 +647,16 @@ side-channel@^1.0.4: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -source-map@^0.7.3, source-map@^0.7.4: +source-map@^0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +source-map@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -755,3 +716,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yocto-queue@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" + integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/.gitignore b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.gitignore new file mode 100644 index 0000000000..febbb5c964 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/build diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/.npmrc b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.npmrc new file mode 100644 index 0000000000..97b895e2f9 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.npmrc @@ -0,0 +1 @@ +ignore-scripts=true diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/.yarnrc b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.yarnrc new file mode 100644 index 0000000000..00d04ff37e --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/.yarnrc @@ -0,0 +1 @@ +--install.ignore-scripts true diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/Dockerfile b/examples/language-sdk-instrumentation/nodejs/tinyhttp/Dockerfile new file mode 100644 index 0000000000..fd0c8bb313 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/Dockerfile @@ -0,0 +1,10 @@ +FROM node:25 + +WORKDIR /app + +COPY package.json yarn.lock .npmrc .yarnrc . +RUN yarn install + +COPY index.js . + +CMD ["node", "index.js"] diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/docker-compose.yml b/examples/language-sdk-instrumentation/nodejs/tinyhttp/docker-compose.yml new file mode 100644 index 0000000000..4609880438 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/docker-compose.yml @@ -0,0 +1,50 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + us-east: + ports: + - 5000 + environment: + - REGION=us-east + build: + context: . + eu-north: + ports: + - 5000 + environment: + - REGION=eu-north + build: + context: . + ap-south: + ports: + - 5000 + environment: + - REGION=ap-south + build: + context: . + load-generator: + build: + context: ../ + dockerfile: Dockerfile.load-generator + depends_on: + - us-east + - eu-north + - ap-south + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/index.js b/examples/language-sdk-instrumentation/nodejs/tinyhttp/index.js new file mode 100644 index 0000000000..0847e03126 --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/index.js @@ -0,0 +1,45 @@ +import { init, start } from '@pyroscope/nodejs'; +import { App } from '@tinyhttp/app'; +import { logger } from '@tinyhttp/logger'; + +const port = process.env['PORT'] || 5000; +const region = process.env['REGION'] || 'default'; +const appName = process.env['APP_NAME'] || 'tinyhttp'; +const pyroscopeUrl = process.env['PYROSCOPE_URL'] || 'http://pyroscope:4040'; + +init({ + appName: appName, + serverAddress: pyroscopeUrl, + tags: { region }, +}); +start(); + +const app = new App(); +app.use(logger()); + +app.get('/', (_, res) => { + res.send('Available routes are: /bike, /car, /scooter'); +}) + +const genericSearchHandler = (p) => (_, res) => { + const time = +new Date() + p * 1000; + let i = 0; + while (+new Date() < time) { + i = i + Math.random(); + } + res.send('Vehicle found'); +}; + +app.get('/bike', (req, res) => { + genericSearchHandler(0.5)(req, res); +}); + +app.get('/car', (req, res) => { + genericSearchHandler(1)(req, res); +}); + +app.get('/scooter', (req, res) => { + genericSearchHandler(0.25)(req, res); +}); + +app.listen(port, () => console.log(`Started on http://localhost:${port}`)); diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/package.json b/examples/language-sdk-instrumentation/nodejs/tinyhttp/package.json new file mode 100644 index 0000000000..0460a081ea --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/package.json @@ -0,0 +1,21 @@ +{ + "name": "rideshare-app-express", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "start": "node index.js", + "test": "echo \"Error: no test specified\" && exit 1", + "start:local": "PYROSCOPE_URL=http://localhost:4040 yarn start", + "up": "yarn down && docker compose up --build --force-recreate --no-deps", + "down": "docker compose down" + }, + "author": "", + "license": "Apache-2.0", + "dependencies": { + "@pyroscope/nodejs": "v0.4.11", + "@tinyhttp/app": "^2.4.0", + "@tinyhttp/logger": "^2.0.0" + } +} diff --git a/examples/language-sdk-instrumentation/nodejs/tinyhttp/yarn.lock b/examples/language-sdk-instrumentation/nodejs/tinyhttp/yarn.lock new file mode 100644 index 0000000000..92761fc93c --- /dev/null +++ b/examples/language-sdk-instrumentation/nodejs/tinyhttp/yarn.lock @@ -0,0 +1,266 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@datadog/pprof@5.13.3": + version "5.13.3" + resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.13.3.tgz#7080d38b6c05736cb8a027835707ee4ee43eedf3" + integrity sha512-G25IicP7pc5CXmAfVz7nrIERsKK9hvPz6p7xsLTUwG4Qs+Zgd5KFedKCVsnvNasLc7l7OXQ6839ajowgQLWTyw== + dependencies: + delay "^5.0.0" + node-gyp-build "<4.0" + p-limit "^3.1.0" + pprof-format "^2.2.1" + source-map "^0.7.4" + +"@pyroscope/nodejs@v0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@pyroscope/nodejs/-/nodejs-0.4.11.tgz#ef78d106845834773d4aed21264f400d72a93dbc" + integrity sha512-hfLE72zc8toxC4UPgSPHxglHfFF9+62YqhqUC6LsK5pdaBQBKjqvIW9EFL6vp5c3lSs7ctjnLy2Rki9RCsqQ8g== + dependencies: + "@datadog/pprof" "5.13.3" + debug "^4.4.3" + p-limit "^7.3.0" + regenerator-runtime "^0.14.1" + source-map "^0.7.6" + +"@tinyhttp/accepts@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/accepts/-/accepts-2.2.3.tgz#be7601206eeda8bd8350ad82a2307808efcb7831" + integrity sha512-9pQN6pJAJOU3McmdJWTcyq7LLFW8Lj5q+DadyKcvp+sxMkEpktKX5sbfJgJuOvjk6+1xWl7pe0YL1US1vaO/1w== + dependencies: + mime "4.0.4" + negotiator "^0.6.3" + +"@tinyhttp/app@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/app/-/app-2.4.0.tgz#d91b3f36146d2dc63cf8b1492b94488ecea3cc6d" + integrity sha512-vOPiCemQRJq5twnl06dde6XnWiNbVMdVRFJWW/yC/9G0qgvV2TvzNNTxrdlz6YmyB7vIC7Fg3qS6m6gx8RbBNQ== + dependencies: + "@tinyhttp/cookie" "2.1.1" + "@tinyhttp/proxy-addr" "2.2.0" + "@tinyhttp/req" "2.2.4" + "@tinyhttp/res" "2.2.4" + "@tinyhttp/router" "2.2.3" + header-range-parser "1.1.3" + regexparam "^2.0.2" + +"@tinyhttp/content-disposition@2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@tinyhttp/content-disposition/-/content-disposition-2.2.2.tgz#1207d18bdd59e1cd38ecf2493ee187f4f592ebe7" + integrity sha512-crXw1txzrS36huQOyQGYFvhTeLeG0Si1xu+/l6kXUVYpE0TjFjEZRqTbuadQLfKGZ0jaI+jJoRyqaWwxOSHW2g== + +"@tinyhttp/content-type@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/content-type/-/content-type-0.1.4.tgz#112bce3b564213e0ed43fa76fccca4237be3a634" + integrity sha512-dl6f3SHIJPYbhsW1oXdrqOmLSQF/Ctlv3JnNfXAE22kIP7FosqJHxkz/qj2gv465prG8ODKH5KEyhBkvwrueKQ== + +"@tinyhttp/cookie-signature@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/cookie-signature/-/cookie-signature-2.1.1.tgz#ae2caad6aec4ec51d42e7d852ae34a04196d5138" + integrity sha512-VDsSMY5OJfQJIAtUgeQYhqMPSZptehFSfvEEtxr+4nldPA8IImlp3QVcOVuK985g4AFR4Hl1sCbWCXoqBnVWnw== + +"@tinyhttp/cookie@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/cookie/-/cookie-2.1.1.tgz#50ad664f732357a466a14cdc888e88e80dc3440e" + integrity sha512-h/kL9jY0e0Dvad+/QU3efKZww0aTvZJslaHj3JTPmIPC9Oan9+kYqmh3M6L5JUQRuTJYFK2nzgL2iJtH2S+6dA== + +"@tinyhttp/encode-url@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/encode-url/-/encode-url-2.1.1.tgz#a52bdbd75f541455190d1a16b0a81374c8dc587d" + integrity sha512-AhY+JqdZ56qV77tzrBm0qThXORbsVjs/IOPgGCS7x/wWnsa/Bx30zDUU/jPAUcSzNOzt860x9fhdGpzdqbUeUw== + +"@tinyhttp/etag@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@tinyhttp/etag/-/etag-2.1.2.tgz#34fc91933bd1acce3cda3a64e5352ce5514abe4e" + integrity sha512-j80fPKimGqdmMh6962y+BtQsnYPVCzZfJw0HXjyH70VaJBHLKGF+iYhcKqzI3yef6QBNa8DKIPsbEYpuwApXTw== + +"@tinyhttp/forwarded@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/forwarded/-/forwarded-2.1.1.tgz#dbf2cae75a1737b88b71c2a2d1931e5e9ced73c3" + integrity sha512-nO3kq0R1LRl2+CAMlnggm22zE6sT8gfvGbNvSitV6F9eaUSurHP0A8YZFMihSkugHxK+uIegh1TKrqgD8+lyGQ== + +"@tinyhttp/logger@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/logger/-/logger-2.0.0.tgz#64c0e53497abc82765c17289a05cd75edbd4c04a" + integrity sha512-8DfLQjGDIaIJeivYamVrrpmwmsGwS8wt2DGvzlcY5HEBagdiI4QJy/veAFcUHuaJqufn4wLwmn4q5VUkW8BCpQ== + dependencies: + colorette "^2.0.20" + dayjs "^1.11.10" + http-status-emojis "^2.2.0" + +"@tinyhttp/proxy-addr@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/proxy-addr/-/proxy-addr-2.2.0.tgz#82487f25af4d320d79e613bbecac17c7ad69c8f2" + integrity sha512-WM/PPL9xNvrs7/8Om5nhKbke5FHrP3EfjOOR+wBnjgESfibqn0K7wdUTnzSLp1lBmemr88os1XvzwymSgaibyA== + dependencies: + "@tinyhttp/forwarded" "2.1.1" + ipaddr.js "^2.2.0" + +"@tinyhttp/req@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/req/-/req-2.2.4.tgz#c9dfc40e3a3b3cc1eb48bdc137b5d0cd71501057" + integrity sha512-lQAZIAo0NOeghxFOZS57tQzxpHSPPLs9T68Krq2BncEBImKwqaDKUt7M9Y5Kb+rvC/GwIL3LeErhkg7f5iG4IQ== + dependencies: + "@tinyhttp/accepts" "2.2.3" + "@tinyhttp/type-is" "2.2.4" + "@tinyhttp/url" "2.1.1" + header-range-parser "^1.1.3" + +"@tinyhttp/res@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/res/-/res-2.2.4.tgz#ed79d511f21d6ef226ae907bdecc26f69c93583c" + integrity sha512-ETBRShnO19oJyIg2XQHQoofXPWeTXPAuwnIVYkU8WaftvXd/Vz4y5+WFQDHUzKlmdGOw5fAFnrEU7pIVMeFeVA== + dependencies: + "@tinyhttp/content-disposition" "2.2.2" + "@tinyhttp/cookie" "2.1.1" + "@tinyhttp/cookie-signature" "2.1.1" + "@tinyhttp/encode-url" "2.1.1" + "@tinyhttp/req" "2.2.4" + "@tinyhttp/send" "2.2.3" + "@tinyhttp/vary" "^0.1.3" + es-escape-html "^0.1.1" + mime "4.0.4" + +"@tinyhttp/router@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/router/-/router-2.2.3.tgz#a29a33da89ae7365f5897aed20f44663509273a4" + integrity sha512-O0MQqWV3Vpg/uXsMYg19XsIgOhwjyhTYWh51Qng7bxqXixxx2PEvZWnFjP7c84K7kU/nUX41KpkEBTLnznk9/Q== + +"@tinyhttp/send@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/send/-/send-2.2.3.tgz#726c400af76c62963bd71fe92e6e6838f35a7996" + integrity sha512-o4cVHHGQ8WjVBS8UT0EE/2WnjoybrfXikHwsRoNlG1pfrC/Sd01u1N4Te8cOd/9aNGLr4mGxWb5qTm2RRtEi7g== + dependencies: + "@tinyhttp/content-type" "^0.1.4" + "@tinyhttp/etag" "2.1.2" + mime "4.0.4" + +"@tinyhttp/type-is@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/type-is/-/type-is-2.2.4.tgz#8f5a30bb3cdc93dd02f399e152d88b815b0efc99" + integrity sha512-7F328NheridwjIfefBB2j1PEcKKABpADgv7aCJaE8x8EON77ZFrAkI3Rir7pGjopV7V9MBmW88xUQigBEX2rmQ== + dependencies: + "@tinyhttp/content-type" "^0.1.4" + mime "4.0.4" + +"@tinyhttp/url@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/url/-/url-2.1.1.tgz#77fa8963f5b698bacbdc6912407f946d32c793e1" + integrity sha512-POJeq2GQ5jI7Zrdmj22JqOijB5/GeX+LEX7DUdml1hUnGbJOTWDx7zf2b5cCERj7RoXL67zTgyzVblBJC+NJWg== + +"@tinyhttp/vary@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/vary/-/vary-0.1.3.tgz#f5bea4769f380c43a158832a8daad8e8b186757c" + integrity sha512-SoL83sQXAGiHN1jm2VwLUWQSQeDAAl1ywOm6T0b0Cg1CZhVsjoiZadmjhxF6FHCCY7OHHVaLnTgSMxTPIDLxMg== + +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +dayjs@^1.11.10: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + +es-escape-html@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/es-escape-html/-/es-escape-html-0.1.1.tgz#9a582d49754ec6204524952c76a383fe5f03c1c0" + integrity sha512-yUx1o+8RsG7UlszmYPtks+dm6Lho2m8lgHMOsLJQsFI0R8XwUJwiMhM1M4E/S8QLeGyf6MkDV/pWgjQ0tdTSyQ== + +header-range-parser@1.1.3, header-range-parser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/header-range-parser/-/header-range-parser-1.1.3.tgz#6414b5b12e3b645d29d85225a58fd207d66d30ef" + integrity sha512-B9zCFt3jH8g09LR1vHL4pcAn8yMEtlSlOUdQemzHMRKMImNIhhszdeosYFfNW0WXKQtXIlWB+O4owHJKvEJYaA== + +http-status-emojis@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/http-status-emojis/-/http-status-emojis-2.2.0.tgz#2cf3316f0c1610c4fc94c6fccdada35aa70f992a" + integrity sha512-ompKtgwpx8ff0hsbpIB7oE4ax1LXoHmftsHHStMELX56ivG3GhofTX8ZHWlUaFKfGjcGjw6G3rPk7dJRXMmbbg== + +ipaddr.js@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== + +mime@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.4.tgz#9f851b0fc3c289d063b20a7a8055b3014b25664b" + integrity sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +negotiator@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +node-gyp-build@<4.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.9.0.tgz#53a350187dd4d5276750da21605d1cb681d09e25" + integrity sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A== + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-limit@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-7.3.0.tgz#821398d91491c6b6a1340ecd09cdc402a9c8d0ee" + integrity sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw== + dependencies: + yocto-queue "^1.2.1" + +pprof-format@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/pprof-format/-/pprof-format-2.2.1.tgz#64d32207fb46990349eb52825defb449d6ccc9b4" + integrity sha512-p4tVN7iK19ccDqQv8heyobzUmbHyds4N2FI6aBMcXz6y99MglTWDxIyhFkNaLeEXs6IFUEzT0zya0icbSLLY0g== + +regenerator-runtime@^0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regexparam@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.2.tgz#a0f6aa057c67b1c9c09508c45823c0755b1f6e58" + integrity sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w== + +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +source-map@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yocto-queue@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" + integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== diff --git a/examples/language-sdk-instrumentation/python/README.md b/examples/language-sdk-instrumentation/python/README.md index 5660c4baae..b65c08a236 100644 --- a/examples/language-sdk-instrumentation/python/README.md +++ b/examples/language-sdk-instrumentation/python/README.md @@ -1,42 +1,61 @@ ## Continuous Profiling for Python applications + ### Profiling a Python Rideshare App with Pyroscope -![python_example_architecture_05_00](https://user-images.githubusercontent.com/23323466/135728737-0c5e54ca-1e78-4c6d-933c-145f441c96a9.gif) + +![python_example_architecture_new_00](https://user-images.githubusercontent.com/23323466/173369382-267af200-6126-4bd0-8607-a933e8400dbb.gif) #### _Read this in other languages._ + [简体中文](README_zh.md) -Note: For documentation on the Pyroscope pip package visit [our website](https://pyroscope.io/docs/python/) +Note: For documentation on the Pyroscope pip package visit [our website](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/python/) + +## Interactive Tutorial + +Explore our [interactive Ride Share tutorial](https://killercoda.com/grafana-labs/course/pyroscope/ride-share-tutorial) on KillerCoda, where you can learn how to use Pyroscope by profiling a "Ride Share" application. + +## Live Demo + +Feel free to check out the [live demo](https://play.grafana.org/a/grafana-pyroscope-app/explore?searchText=&panelType=time-series&layout=grid&hideNoData=off&explorationType=flame-graph&var-serviceName=pyroscope-rideshare-python&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds&var-dataSource=grafanacloud-profiles) of this example on our demo page. + ## Background + In this example we show a simplified, basic use case of Pyroscope. We simulate a "ride share" company which has three endpoints found in `server.py`: + - `/bike` : calls the `order_bike(search_radius)` function to order a bike - `/car` : calls the `order_car(search_radius)` function to order a car - `/scooter` : calls the `order_scooter(search_radius)` function to order a scooter -We also simulate running 3 distinct servers in 3 different regions (via [docker-compose.yml](https://github.com/pyroscope-io/pyroscope/blob/main/examples/python/docker-compose.yml)) +We also simulate running 3 distinct servers in 3 different regions: + - us-east - eu-north - ap-south One of the most useful capabilities of Pyroscope is the ability to tag your data in a way that is meaningful to you. In this case, we have two natural divisions, and so we "tag" our data to represent those: + - `region`: statically tags the region of the server running the code - `vehicle`: dynamically tags the endpoint (similar to how one might tag a controller rails) - ## Tagging static region + Tagging something static, like the `region`, can be done in the initialization code in the `config.tags` variable: -``` + +```python pyroscope.configure( application_name = "ride-sharing-app", - server_address = "http://pyroscope:4040", - tags = { + server_address = "http://pyroscope:4040", + tags = { "region": f'{os.getenv("REGION")}', # Tags the region based off the environment variable } ) ``` ## Tagging dynamically within functions + Tagging something more dynamically, like we do for the `vehicle` tag can be done inside our utility `find_nearest_vehicle()` function using a `with pyroscope.tag_wrapper()` block -``` + +```python def find_nearest_vehicle(n, vehicle): with pyroscope.tag_wrapper({ "vehicle": vehicle}): i = 0 @@ -46,57 +65,63 @@ def find_nearest_vehicle(n, vehicle): ``` What this block does, is: + 1. Add the tag `{ "vehicle" => "car" }` 2. execute the `find_nearest_vehicle()` function 3. Before the block ends it will (behind the scenes) remove the `{ "vehicle" => "car" }` from the application since that block is complete ## Resulting flame graph / performance results from the example + ### Running the example -To run the example run the following commands: -``` -# Pull latest pyroscope image: + +Try out one of the Django, Flask, or FastAPI examples located in the `rideshare` directory by running the following commands: + +```shell +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: -docker-compose up --build +docker compose up --build # Reset the database (if needed): -# docker-compose down +docker compose down ``` -What this example will do is run all the code mentioned above and also send some mock-load to the 3 servers as well as their respective 3 endpoints. If you select our application: `ride-sharing-app.cpu` from the dropdown, you should see a flame graph that looks like this (below). After we give 20-30 seconds for the flame graph to update and then click the refresh button we see our 3 functions at the bottom of the flame graph taking CPU resources _proportional to the size_ of their respective `search_radius` parameters. +What this example will do is run all the code mentioned above and also send some mock-load to the 3 servers as well as their respective 3 endpoints. If you select our application: `ride-sharing-app` from the dropdown, you should see a flame graph that looks like this (below). After we give 20-30 seconds for the flame graph to update and then click the refresh button we see our 3 functions at the bottom of the flame graph taking CPU resources _proportional to the size_ of their respective `search_radius` parameters. ## Where's the performance bottleneck? -![python_first_slide_05](https://user-images.githubusercontent.com/23323466/135881284-c75a5b65-6151-44fb-a459-c1f9559cb51a.jpg) + +![python_slide_1](https://github.com/user-attachments/assets/1d38ddbf-2a9e-4f07-8d70-343cff878307) The first step when analyzing a profile outputted from your application, is to take note of the _largest node_ which is where your application is spending the most resources. In this case, it happens to be the `order_car` function. -The benefit of using the Pyroscope package, is that now that we can investigate further as to _why_ the `order_car()` function is problematic. Tagging both `region` and `vehicle` allows us to test two good hypotheses: +The benefit of using the Pyroscope package, is that now that we can investigate further as to _why_ the `order_car` function is problematic. Tagging both `region` and `vehicle` allows us to test two good hypotheses: - Something is wrong with the `/car` endpoint code - Something is wrong with one of our regions -To analyze this we can select one or more tags from the "Select Tag" dropdown: +To analyze this we can select one or more labels on the "Labels" page: -![image](https://user-images.githubusercontent.com/23323466/135525308-b81e87b0-6ffb-4ef0-a6bf-3338483d0fc4.png) +![python_slide_2](https://github.com/user-attachments/assets/5a8ee6ed-d2e1-42f3-98f3-d977adfccd08) -## Narrowing in on the Issue Using Tags -Knowing there is an issue with the `order_car()` function we automatically select that tag. Then, after inspecting multiple `region` tags, it becomes clear by looking at the timeline that there is an issue with the `eu-north` region, where it alternates between high-cpu times and low-cpu times. +## Narrowing in on the Issue Using Labels -We can also see that the `mutex_lock()` function is consuming almost 70% of CPU resources during this time period. -![python_second_slide_05](https://user-images.githubusercontent.com/23323466/135805908-ae9a1650-51fc-457a-8c47-0b56e8538b08.jpg) +Knowing there is an issue with the `order_car` function we automatically select that tag. Then, after inspecting multiple `region` tags, it becomes clear by looking at the timeline that there is an issue with the `eu-north` region, where it alternates between high-cpu times and low-cpu times. -## Comparing two time periods -Using Pyroscope's "comparison view" we can actually select two different time ranges from the timeline to compare the resulting flame graphs. The pink section on the left timeline results in the left flame graph, and the blue section on the right represents the right flame graph. +We can also see that the `find_nearest_vehicle` function is consuming almost 70% of CPU resources during this time period. -When we select a period of low-cpu utilization and a period of high-cpu utilization we can see that there is clearly different behavior in the `mutex_lock()` function where it takes **51% of CPU** during low-cpu times and **78% of CPU** during high-cpu times. -![python_third_slide_05](https://user-images.githubusercontent.com/23323466/135805969-55fdee40-fe0c-412d-9ec0-0bbc6a748ed4.jpg) +![python_slide_3](https://github.com/user-attachments/assets/57614064-bced-4363-bdba-b028c132e1e9) ## Visualizing diff between two flame graphs + While the difference _in this case_ is stark enough to see in the comparison view, sometimes the diff between the two flame graphs is better visualized with them overlayed over each other. Without changing any parameters, we can simply select the diff view tab and see the difference represented in a color-coded diff flame graph. -![python_fourth_slide_05](https://user-images.githubusercontent.com/23323466/135805986-594ffa3b-e735-4f91-875d-4f76fdff2b60.jpg) + +![python_slide_4](https://github.com/user-attachments/assets/9c89458f-f7fb-4561-80a2-6a86c7c2ed4c) ### More use cases + We have been beta testing this feature with several different companies and some of the ways that we've seen companies tag their performance data: +- Linking profiles with trace data - Tagging controllers - Tagging regions - Tagging jobs from a redis / sidekiq / rabbitmq queue @@ -106,6 +131,7 @@ We have been beta testing this feature with several different companies and some - Etc... ### Future Roadmap + We would love for you to try out this example and see what ways you can adapt this to your python application. Continuous profiling has become an increasingly popular tool for the monitoring and debugging of performance issues (arguably the fourth pillar of observability). We'd love to continue to improve this pip package by adding things like integrations with popular tools, memory profiling, etc. and we would love to hear what features _you would like to see_. diff --git a/examples/language-sdk-instrumentation/python/README_zh.md b/examples/language-sdk-instrumentation/python/README_zh.md index cdf3733eea..db0bfc8ddb 100644 --- a/examples/language-sdk-instrumentation/python/README_zh.md +++ b/examples/language-sdk-instrumentation/python/README_zh.md @@ -1,10 +1,10 @@ ### Pyroscope Rideshare 示例 -![python_example_architecture_05_00](https://user-images.githubusercontent.com/23323466/135728737-0c5e54ca-1e78-4c6d-933c-145f441c96a9.gif) +![python_example_architecture_new_00](https://user-images.githubusercontent.com/23323466/173369382-267af200-6126-4bd0-8607-a933e8400dbb.gif) #### _用其他语言阅读此文。_ [English](README.md) -注意:关于Pyroscope pip包的文档,请访问[我们的网站](https://pyroscope.io/docs/python/) +注意:关于Pyroscope pip包的文档,请访问[我们的网站](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/python/) ## 背景介绍 在这个例子中,我们展示了 Pyroscope 的一个简化的基本用例。我们模拟了一个 "骑行共享" 公司,它有三个请求端点,可以在`server.py`中找到: @@ -53,8 +53,9 @@ def find_nearest_vehicle(n, vehicle): ### 运行这个例子 要运行该例子,请运行以下命令: ``` -# 拉取最新的 pyroscope 镜像: +# 拉取最新的 pyroscope/pyroscope 镜像: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # 运行示例项目: docker-compose up --build diff --git a/examples/language-sdk-instrumentation/python/rideshare/README.md b/examples/language-sdk-instrumentation/python/rideshare/README.md deleted file mode 100644 index 33ced7ae94..0000000000 --- a/examples/language-sdk-instrumentation/python/rideshare/README.md +++ /dev/null @@ -1,137 +0,0 @@ -## Continuous Profiling for Python applications - -### Profiling a Python Rideshare App with Pyroscope - -![python_example_architecture_new_00](https://user-images.githubusercontent.com/23323466/173369382-267af200-6126-4bd0-8607-a933e8400dbb.gif) - -#### _Read this in other languages._ - -[简体中文](README_zh.md) - -Note: For documentation on the Pyroscope pip package visit [our website](https://pyroscope.io/docs/python/) - -## Background - -In this example we show a simplified, basic use case of Pyroscope. We simulate a "ride share" company which has three endpoints found in `server.py`: - -- `/bike` : calls the `order_bike(search_radius)` function to order a bike -- `/car` : calls the `order_car(search_radius)` function to order a car -- `/scooter` : calls the `order_scooter(search_radius)` function to order a scooter - -We also simulate running 3 distinct servers in 3 different regions (via [docker-compose.yml](https://github.com/pyroscope-io/pyroscope/blob/main/examples/python/docker-compose.yml)) - -- us-east -- eu-north -- ap-south - -One of the most useful capabilities of Pyroscope is the ability to tag your data in a way that is meaningful to you. In this case, we have two natural divisions, and so we "tag" our data to represent those: - -- `region`: statically tags the region of the server running the code -- `vehicle`: dynamically tags the endpoint (similar to how one might tag a controller rails) - -## Tagging static region - -Tagging something static, like the `region`, can be done in the initialization code in the `config.tags` variable: - -```python -pyroscope.configure( - application_name = "ride-sharing-app", - server_address = "http://pyroscope:4040", - tags = { - "region": f'{os.getenv("REGION")}', # Tags the region based off the environment variable - } -) -``` - -## Tagging dynamically within functions - -Tagging something more dynamically, like we do for the `vehicle` tag can be done inside our utility `find_nearest_vehicle()` function using a `with pyroscope.tag_wrapper()` block - -```python -def find_nearest_vehicle(n, vehicle): - with pyroscope.tag_wrapper({ "vehicle": vehicle}): - i = 0 - start_time = time.time() - while time.time() - start_time < n: - i += 1 -``` - -What this block does, is: - -1. Add the tag `{ "vehicle" => "car" }` -2. execute the `find_nearest_vehicle()` function -3. Before the block ends it will (behind the scenes) remove the `{ "vehicle" => "car" }` from the application since that block is complete - -## Resulting flame graph / performance results from the example - -### Running the example - -To run the example run the following commands: - -```shell -# Pull latest pyroscope image: -docker pull grafana/pyroscope:latest - -# Run the example project: -docker-compose up --build - -# Reset the database (if needed): -# docker-compose down -``` - -What this example will do is run all the code mentioned above and also send some mock-load to the 3 servers as well as their respective 3 endpoints. If you select our application: `ride-sharing-app.cpu` from the dropdown, you should see a flame graph that looks like this (below). After we give 20-30 seconds for the flame graph to update and then click the refresh button we see our 3 functions at the bottom of the flame graph taking CPU resources _proportional to the size_ of their respective `search_radius` parameters. - -## Where's the performance bottleneck? - -Profiling is most effective for applications that contain tags. The first step when analyzing performance from your application, is to use the Tag Explorer page in order to determine if any tags are consuming more resources than others. - -![vehicle_tag_breakdown](https://user-images.githubusercontent.com/23323466/191306637-a601f463-a247-4588-a285-639424a08b87.png) - -![image](https://user-images.githubusercontent.com/23323466/191319887-8fff2605-dc74-48ba-b0b7-918e3c95ed91.png) - -The benefit of using Pyroscope, is that by tagging both `region` and `vehicle` and looking at the Tag Explorer page we can hypothesize: - -- Something is wrong with the `/car` endpoint code where `car` vehicle tag is consuming **68% of CPU** -- Something is wrong with one of our regions where `eu-north` region tag is consuming **54% of CPU** - -From the flame graph we can see that for the `eu-north` tag the biggest performance impact comes from the `find_nearest_vehicle()` function which consumes close to **68% of cpu**. To analyze this we can go directly to the comparison page using the comparison dropdown. - -## Comparing two time periods - -Using Pyroscope's "comparison view" we can actually select two different queries and compare the resulting flame graphs: -- Left flame graph: `{ region != "eu-north", ... }` -- Right flame graph: `{ region = "eu-north", ... }` - -When we select a period of low-cpu utilization and a period of high-cpu utilization we can see that there is clearly different behavior in the `find_nearest_vehicle()` function where it takes: -- Left flame graph: **22% of CPU** when `{ region != "eu-north", ... }` -- right flame graph: **82% of CPU** when `{ region = "eu-north", ... }` - -![python_pop_out_library_comparison_00](https://user-images.githubusercontent.com/23323466/191374975-d374db02-4cb1-48d5-bc1a-6194193a9f09.png) - -## Visualizing diff between two flame graphs - -While the difference _in this case_ is stark enough to see in the comparison view, sometimes the diff between the two flame graphs is better visualized with them overlayed over each other. Without changing any parameters, we can simply select the diff view tab and see the difference represented in a color-coded diff flame graph. -![find_nearest_vehicle_diff](https://user-images.githubusercontent.com/23323466/191320888-b49eb7de-06d5-4e6b-b9ac-198d7c9e2fcf.png) - - -### More use cases - -We have been beta testing this feature with several different companies and some of the ways that we've seen companies tag their performance data: -- Linking profiles with trace data -- Tagging controllers -- Tagging regions -- Tagging jobs from a redis / sidekiq / rabbitmq queue -- Tagging commits -- Tagging staging / production environments -- Tagging different parts of their testing suites -- Etc... - -### Live Demo - -Feel free to check out the [live demo](https://demo.pyroscope.io/explore?query=rideshare-app-python.cpu%7B%7D&groupBy=region&groupByValue=All) of this example on our demo page. - -### Future Roadmap - -We would love for you to try out this example and see what ways you can adapt this to your python application. Continuous profiling has become an increasingly popular tool for the monitoring and debugging of performance issues (arguably the fourth pillar of observability). - -We'd love to continue to improve this pip package by adding things like integrations with popular tools, memory profiling, etc. and we would love to hear what features _you would like to see_. diff --git a/examples/language-sdk-instrumentation/python/rideshare/README_zh.md b/examples/language-sdk-instrumentation/python/rideshare/README_zh.md deleted file mode 100644 index 001c87c53a..0000000000 --- a/examples/language-sdk-instrumentation/python/rideshare/README_zh.md +++ /dev/null @@ -1,109 +0,0 @@ -### Pyroscope Rideshare 示例 -![python_example_architecture_new_00](https://user-images.githubusercontent.com/23323466/173369382-267af200-6126-4bd0-8607-a933e8400dbb.gif) - -#### _用其他语言阅读此文。_ -[English](README.md) - -注意:关于Pyroscope pip包的文档,请访问[我们的网站](https://pyroscope.io/docs/python/) -## 背景介绍 - -在这个例子中,我们展示了 Pyroscope 的一个简化的基本用例。我们模拟了一个 "骑行共享" 公司,它有三个请求端点,可以在`server.py`中找到: -- `/bike`:调用`order_bike(search_radius)`函数来订购共享自行车 -- `/car` : 调用`order_car(search_radius)`函数来订购共享汽车 -- `/scooter` : 调用`order_scooter(search_radius)`函数来订购共享摩托车 - -我们还模拟了在3个不同地区运行3个不同的服务器(通过[docker-compose.yml](https://github.com/pyroscope-io/pyroscope/blob/main/examples/python/docker-compose.yml)) -- us-east -- eu-north -- ap-south - - -Pyroscope最有用的功能之一是能够以对你有意义的方式来标记你的数据。在这种情况下,我们有两个自然划分,因此我们 "标记(tag)" 我们的数据以表示这些: -- `region`:静态地标记运行代码的服务器的区域 -- `vehicle`: 动态标记端点(类似于标记控制器轨道的方式) - -## 标记静态区域 -标记一些静态的东西,如`reigon`,可以在初始化代码中的`config.tags`变量中完成: -``` -pyroscope.configure( - app_name = "ride-sharing-app", - server_address = "http://pyroscope:4040", - tags = { - "region": f'{os.getenv("REGION")}', # 根据环境变量标记该区域 - } -) -``` - -## 在函数中动态地添加标签 -像我们对 `vehicle` 标签所做的那样,可以在我们的实用程序 `find_nearest_vehicle()` 函数中使用 `with pyroscope.tag_wrapper()` 上下文区块来完成更动态的标记 -``` -def find_nearest_vehicle(n, vehicle): - with pyroscope.tag_wrapper({ "vehicle": vehicle}): - i = 0 - start_time = time.time() - while time.time() - start_time < n: - i += 1 -``` -这个上下文区块的作用是: -1. 添加标签 `{ "vehicle" => "car" }` -2. 执行`find_nearest_vehicle()`函数 -3. 在该块结束之前,它将(在后台)从应用程序中删除`{ "vehicle" => "car" }`,因为该上下文区块已经完成 - -## 例子中产生的火焰图/性能结果 -### 运行这个例子 -要运行该例子,请运行以下命令: -``` -# 拉取最新的 pyroscope 镜像: -docker pull grafana/pyroscope:latest - -# 运行示例项目: -docker-compose up --build - -# 重置数据库(非必需): -# docker-compose down -``` - - -这个例子要做的是运行上面提到的所有代码,同时向3个服务器以及它们各自的3个端点发送一些模拟负载。如果你从下拉菜单中选择我们的应用程序:`rid-sharing-app.cpu`,你应该看到一个看起来像这样的火焰图(见下文)。在我们给予20-30秒的时间来更新火焰图之后,点击刷新按钮,我们看到火焰图底部的3个函数占用的CPU资源与它们各自的`search_radius`参数 _大小成正比_。 -## 性能瓶颈在哪里? -![python_first_slide_05](https://user-images.githubusercontent.com/23323466/135881284-c75a5b65-6151-44fb-a459-c1f9559cb51a.jpg) - -当分析从你的应用程序输出的剖析文件时,第一步是注意 _最大的节点_,这是你的应用程序花费最多资源的地方。在这个例子中,它恰好是 `order_car` 函数。 - -使用 Pyroscope 包的好处是,现在我们可以进一步调查为什么 `order_car()` 函数有问题。同时标记 `region`和 `vehicle`使我们能够测试两个好的假设: -- `/car` 端点的代码出了问题 -- 我们的一个区域出了问题 - -为了分析这一点,我们可以从 "Select Tag" 下拉菜单中选择一个或多个标签: - -![image](https://user-images.githubusercontent.com/23323466/135525308-b81e87b0-6ffb-4ef0-a6bf-3338483d0fc4.png) - -## 使用标签缩小问题的范围 -知道`order_car()`函数有问题,我们就自动选择该标签。然后,在检查了多个 `region` 标签后,通过查看时间线,可以清楚地看到 `eu-north`区域存在问题,它在高cpu时间和低cpu时间之间交替出现。 - -我们还可以看到,`mutex_lock()`函数在这段时间内几乎消耗了70%的CPU资源。 -![python_second_slide_05](https://user-images.githubusercontent.com/23323466/135805908-ae9a1650-51fc-457a-8c47-0b56e8538b08.jpg) - -## 比较两个时间段的情况 -使用 Pyroscope 的 "比较视图",我们实际上可以从时间线上选择两个不同的时间范围来比较所产生的火焰图。左边时间线上的粉红色部分结果是左边的火焰图,右边的蓝色部分代表右边的火焰图。 -当我们选择一个低CPU利用率的时期和一个高CPU利用率的时期时,我们可以看到`mutex_lock()`函数有明显不同的行为,它在低CPU时期占用**51%的CPU**,在高CPU时期占用**78%的CPU**。 -![python_third_slide_05](https://user-images.githubusercontent.com/23323466/135805969-55fdee40-fe0c-412d-9ec0-0bbc6a748ed4.jpg) - -## 可视化两个火焰图之间的差异 -虽然在 _这个例子_ 中,差异足以在比较视图中看到,但有时两个火焰图之间的差异在相互叠加的情况下会更直观。在不改变任何参数的情况下,我们可以简单地选择差异视图选项卡,看到用彩色编码的差异火焰图表示的差异。 -![python_fourth_slide_05](https://user-images.githubusercontent.com/23323466/135805986-594ffa3b-e735-4f91-875d-4f76fdff2b60.jpg) - -### 更多用例 -我们一直在与几个不同的公司测试这一功能,我们看到一些公司标记其业务数据的方式: -- 标记控制器 -- 标记区域 -- 从redis / sidekiq / rabbitmq队列中标记作业 -- 标记提交 -- 标记预发/生产环境 -- 标记其测试套件的不同部分 -- 等等... - -### 未来路线图 -我们希望你能尝试一下这个例子,看看你能用什么方式来适配你的 python 应用。持续剖析已经成为监测和调试性能问题的一个越来越流行的工具(可以说是可观察性的第四个支柱)。 - -我们希望通过增加与流行工具的集成、内存分析等内容来继续改进这个pip包,我们很想听听 _你希望看到的功能_。 diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/.env.dev b/examples/language-sdk-instrumentation/python/rideshare/django/.env.dev index b5d6844cdc..1d27496e4f 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/django/.env.dev +++ b/examples/language-sdk-instrumentation/python/rideshare/django/.env.dev @@ -1,6 +1,6 @@ DEBUG=1 SECRET_KEY=foo -DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] web +DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] eu-north us-east ap-south SQL_ENGINE=django.db.backends.postgresql SQL_DATABASE=hello_django_dev SQL_USER=hello_django diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/README.md b/examples/language-sdk-instrumentation/python/rideshare/django/README.md index 2e18c81b66..dce14ed736 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/django/README.md +++ b/examples/language-sdk-instrumentation/python/rideshare/django/README.md @@ -1,15 +1,23 @@ -# Dockerizing Django with Pyroscope, Postgres, Gunicorn, and Nginx -This is a simple rideshare example that adds Pyroscope to a Django application and uses it to profile various routes +# Django Example -### Development -Uses the default Django development server. +This example runs Django with Gunicorn and preloads the application before Gunicorn forks its workers. +The Pyroscope Python client starts background threads and must not be initialized in the Gunicorn master process before those forks. -1. Rename *.env.dev-sample* to *.env.dev*. -1. Update the environment variables in the *docker-compose.yml* and *.env.dev* files. -1. Build the images and run the containers: +The [`post_fork` hook](app/gunicorn.conf.py) calls `pyroscope.configure()` separately in each worker. +Don't move that call into Django settings or another application module: Gunicorn imports those modules in the master process when `preload_app` is enabled. +For more information, refer to the [Python client documentation](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/python/#use-the-python-client-with-forked-processes). - ```sh - $ docker-compose up -d --build - ``` +To run the example run the following commands: +``` +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest - Test it out at [http://localhost:8000](http://localhost:8000). The "app" folder is mounted into the container and your code changes apply automatically. +# Run the example project: +docker compose up --build + +# Reset the database (if needed): +docker compose down +``` + +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/app/Dockerfile b/examples/language-sdk-instrumentation/python/rideshare/django/app/Dockerfile index 48c7ccec3b..fb1e3a621d 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/django/app/Dockerfile +++ b/examples/language-sdk-instrumentation/python/rideshare/django/app/Dockerfile @@ -1,5 +1,5 @@ # pull official base image -FROM python:3.9 +FROM python:3.12 # set work directory WORKDIR /usr/src/app diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/app/Dockerfile.prod b/examples/language-sdk-instrumentation/python/rideshare/django/app/Dockerfile.prod deleted file mode 100644 index 856c39af71..0000000000 --- a/examples/language-sdk-instrumentation/python/rideshare/django/app/Dockerfile.prod +++ /dev/null @@ -1,72 +0,0 @@ -########### -# BUILDER # -########### - -# pull official base image -FROM python:3.9.6-alpine as builder - -# set work directory -WORKDIR /usr/src/app - -# set environment variables -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PYTHONUNBUFFERED 1 - -# install psycopg2 dependencies -RUN apk update \ - && apk add postgresql-dev gcc python3-dev musl-dev - -# lint -RUN pip install --upgrade pip -RUN pip install flake8==3.9.2 -COPY . . -RUN flake8 --ignore=E501,F401 . - -# install dependencies -COPY ./requirements.txt . -RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt - - -######### -# FINAL # -######### - -# pull official base image -FROM python:3.9.6-alpine - -# create directory for the app user -RUN mkdir -p /home/app - -# create the app user -RUN addgroup -S app && adduser -S app -G app - -# create the appropriate directories -ENV HOME=/home/app -ENV APP_HOME=/home/app/web -RUN mkdir $APP_HOME -RUN mkdir $APP_HOME/staticfiles -RUN mkdir $APP_HOME/mediafiles -WORKDIR $APP_HOME - -# install dependencies -RUN apk update && apk add libpq -COPY --from=builder /usr/src/app/wheels /wheels -COPY --from=builder /usr/src/app/requirements.txt . -RUN pip install --no-cache /wheels/* - -# copy entrypoint.prod.sh -COPY ./entrypoint.prod.sh . -RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh -RUN chmod +x $APP_HOME/entrypoint.prod.sh - -# copy project -COPY . $APP_HOME - -# chown all the files to the app user -RUN chown -R app:app $APP_HOME - -# change to the app user -USER app - -# run entrypoint.prod.sh -ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"] diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/app/entrypoint.sh b/examples/language-sdk-instrumentation/python/rideshare/django/app/entrypoint.sh index de693815e5..37fa201ef6 100755 --- a/examples/language-sdk-instrumentation/python/rideshare/django/app/entrypoint.sh +++ b/examples/language-sdk-instrumentation/python/rideshare/django/app/entrypoint.sh @@ -11,7 +11,4 @@ then echo "PostgreSQL started" fi -python manage.py flush --no-input -python manage.py migrate - exec "$@" diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/app/gunicorn.conf.py b/examples/language-sdk-instrumentation/python/rideshare/django/app/gunicorn.conf.py new file mode 100644 index 0000000000..b245abb084 --- /dev/null +++ b/examples/language-sdk-instrumentation/python/rideshare/django/app/gunicorn.conf.py @@ -0,0 +1,24 @@ +import os + +import pyroscope +from django.db import connections + + +bind = "0.0.0.0:8000" +workers = 2 +preload_app = True + + +def post_fork(server, worker): + # Don't share connections opened while preloading the app with workers. + connections.close_all() + server.log.info("Configuring Pyroscope in worker pid %s", worker.pid) + pyroscope.configure( + application_name=os.getenv("PYROSCOPE_APPLICATION_NAME", "ride-sharing-app"), + server_address=os.getenv("PYROSCOPE_SERVER_ADDRESS", "http://pyroscope:4040"), + basic_auth_username=os.getenv("PYROSCOPE_BASIC_AUTH_USER", ""), + basic_auth_password=os.getenv("PYROSCOPE_BASIC_AUTH_PASSWORD", ""), + tags={ + "region": os.getenv("REGION", ""), + }, + ) diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/app/hello_django/settings.py b/examples/language-sdk-instrumentation/python/rideshare/django/app/hello_django/settings.py index 85babbf47a..1d2cb54c1f 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/django/app/hello_django/settings.py +++ b/examples/language-sdk-instrumentation/python/rideshare/django/app/hello_django/settings.py @@ -11,7 +11,6 @@ """ import os -import pyroscope from pathlib import Path @@ -118,8 +117,6 @@ USE_I18N = True -USE_L10N = True - USE_TZ = True @@ -137,18 +134,3 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' - -app_name = os.getenv("PYROSCOPE_APPLICATION_NAME", "django-ride-sharing-app") -server_addr = os.getenv("PYROSCOPE_SERVER_ADDRESS", "http://pyroscope:4040") -basic_auth_username = os.getenv("PYROSCOPE_BASIC_AUTH_USER", "") -basic_auth_password = os.getenv("PYROSCOPE_BASIC_AUTH_PASSWORD", "") - -pyroscope.configure( - application_name = app_name, - server_address = server_addr, - basic_auth_username = basic_auth_username, - basic_auth_password = basic_auth_password, - # tags = { - # "region": f'{os.getenv("REGION")}', - # } -) diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/app/requirements.txt b/examples/language-sdk-instrumentation/python/rideshare/django/app/requirements.txt index 4d956638c8..a5fc73d694 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/django/app/requirements.txt +++ b/examples/language-sdk-instrumentation/python/rideshare/django/app/requirements.txt @@ -1,5 +1,12 @@ -Django==3.2.25 -djangorestframework==3.12.4 -gunicorn==20.1.0 -psycopg2-binary==2.9.1 -pyroscope-io==0.8.6 +asgiref==3.11.1 +cffi==2.0.0 +Django==5.2.8 +djangorestframework==3.15.2 +gunicorn==23.0.0 +psycopg==3.2.9 +psycopg-binary==3.2.9 +pycparser==3.0 +pyroscope-io==1.0.5 +setuptools==82.0.1 +sqlparse==0.5.5 +typing_extensions==4.15.0 diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/docker-compose.yml b/examples/language-sdk-instrumentation/python/rideshare/django/docker-compose.yml index 696e0d3d73..9571346bcc 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/django/docker-compose.yml +++ b/examples/language-sdk-instrumentation/python/rideshare/django/docker-compose.yml @@ -1,34 +1,72 @@ -version: '3' - services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - - web: + - 4040:4040 + migrate: build: ./app - command: python manage.py runserver 0.0.0.0:8000 - ports: - - 8000:8000 + command: python manage.py migrate --no-input env_file: - ./.env.dev depends_on: - db - + us-east: + build: ./app + command: gunicorn --config gunicorn.conf.py hello_django.wsgi:application + env_file: + - ./.env.dev + environment: + - REGION=us-east + depends_on: + migrate: + condition: service_completed_successfully + eu-north: + build: ./app + command: gunicorn --config gunicorn.conf.py hello_django.wsgi:application + env_file: + - ./.env.dev + environment: + - REGION=eu-north + depends_on: + migrate: + condition: service_completed_successfully + ap-south: + build: ./app + command: gunicorn --config gunicorn.conf.py hello_django.wsgi:application + env_file: + - ./.env.dev + environment: + - REGION=ap-south + depends_on: + migrate: + condition: service_completed_successfully db: - image: postgres:13.0-alpine + image: postgres:16-alpine ports: - - '5432' + - '5432' environment: - - POSTGRES_USER=hello_django - - POSTGRES_PASSWORD=hello_django - - POSTGRES_DB=hello_django_dev - + - POSTGRES_USER=hello_django + - POSTGRES_PASSWORD=hello_django + - POSTGRES_DB=hello_django_dev load-generator: build: context: . dockerfile: Dockerfile.load-generator - + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 volumes: - postgres_data: + postgres_data: null diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/python/rideshare/django/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/python/rideshare/django/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/python/rideshare/django/load-generator.py b/examples/language-sdk-instrumentation/python/rideshare/django/load-generator.py index bcdaf92945..c399d92942 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/django/load-generator.py +++ b/examples/language-sdk-instrumentation/python/rideshare/django/load-generator.py @@ -3,7 +3,9 @@ import time HOSTS = [ - 'web', + 'us-east', + 'eu-north', + 'ap-south', ] VEHICLES = [ @@ -14,8 +16,7 @@ if __name__ == "__main__": print(f"starting load generator") - time.sleep(15) - print('done sleeping') + time.sleep(3) while True: host = HOSTS[random.randint(0, len(HOSTS) - 1)] vehicle = VEHICLES[random.randint(0, len(VEHICLES) - 1)] @@ -27,4 +28,4 @@ except BaseException as e: print (f"http error {e}") - time.sleep(random.uniform(0.2, 0.4)) + time.sleep(random.uniform(0.1, 0.2)) diff --git a/examples/language-sdk-instrumentation/python/rideshare/fastapi/Dockerfile b/examples/language-sdk-instrumentation/python/rideshare/fastapi/Dockerfile index 55c0e27984..17a1462484 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/fastapi/Dockerfile +++ b/examples/language-sdk-instrumentation/python/rideshare/fastapi/Dockerfile @@ -1,6 +1,7 @@ -FROM python:3.9 +FROM python:3.11 -RUN pip3 install fastapi pyroscope-io==0.8.6 uvicorn[standard] +COPY requirements.txt . +RUN pip3 install -r requirements.txt ENV FLASK_ENV=development ENV PYTHONUNBUFFERED=1 diff --git a/examples/language-sdk-instrumentation/python/rideshare/fastapi/README.md b/examples/language-sdk-instrumentation/python/rideshare/fastapi/README.md index 748aea7090..04b0aeb49c 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/fastapi/README.md +++ b/examples/language-sdk-instrumentation/python/rideshare/fastapi/README.md @@ -1,13 +1,16 @@ -## Fastapi Example +## FastAPI Example To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: -docker-compose up --build +docker compose up --build # Reset the database (if needed): -# docker-compose down +docker compose down ``` + +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/python/rideshare/fastapi/docker-compose.yml b/examples/language-sdk-instrumentation/python/rideshare/fastapi/docker-compose.yml index 25adcf9a5a..952658253b 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/fastapi/docker-compose.yml +++ b/examples/language-sdk-instrumentation/python/rideshare/fastapi/docker-compose.yml @@ -1,29 +1,40 @@ -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: environment: - - REGION=us-east + - REGION=us-east build: context: . - eu-north: environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: . dockerfile: Dockerfile.load-generator + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/python/rideshare/fastapi/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/python/rideshare/fastapi/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/python/rideshare/fastapi/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/python/rideshare/fastapi/requirements.txt b/examples/language-sdk-instrumentation/python/rideshare/fastapi/requirements.txt new file mode 100644 index 0000000000..489525c90b --- /dev/null +++ b/examples/language-sdk-instrumentation/python/rideshare/fastapi/requirements.txt @@ -0,0 +1,22 @@ +annotated-doc==0.0.4 +annotated-types==0.7.0 +anyio==4.13.0 +cffi==2.0.0 +click==8.4.1 +fastapi==0.136.3 +h11==0.16.0 +httptools==0.8.0 +idna==3.18 +pycparser==3.0 +pydantic==2.13.4 +pydantic_core==2.46.4 +pyroscope-io==1.0.4 +python-dotenv==1.2.2 +PyYAML==6.0.3 +starlette==1.2.1 +typing-inspection==0.4.2 +typing_extensions==4.15.0 +uvicorn==0.48.0 +uvloop==0.22.1 +watchfiles==1.2.0 +websockets==16.0 diff --git a/examples/language-sdk-instrumentation/python/rideshare/flask/Dockerfile b/examples/language-sdk-instrumentation/python/rideshare/flask/Dockerfile index d80b3bd08a..49685f2273 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/flask/Dockerfile +++ b/examples/language-sdk-instrumentation/python/rideshare/flask/Dockerfile @@ -1,7 +1,7 @@ -FROM python:3.9 +FROM python:3.12-slim -RUN pip3 install flask pyroscope-io==0.8.7 pyroscope-otel==0.1.0 -RUN pip3 install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-flask opentelemetry-exporter-otlp-proto-grpc +COPY requirements.txt . +RUN pip3 install -r requirements.txt ENV FLASK_ENV=development ENV PYTHONUNBUFFERED=1 diff --git a/examples/language-sdk-instrumentation/python/rideshare/flask/README.md b/examples/language-sdk-instrumentation/python/rideshare/flask/README.md index 21566a0071..c859df7c8a 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/flask/README.md +++ b/examples/language-sdk-instrumentation/python/rideshare/flask/README.md @@ -2,12 +2,15 @@ To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: -docker-compose up --build +docker compose up --build # Reset the database (if needed): -# docker-compose down +docker compose down ``` + +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/python/rideshare/flask/docker-compose.yml b/examples/language-sdk-instrumentation/python/rideshare/flask/docker-compose.yml index b56be64379..21a348f448 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/flask/docker-compose.yml +++ b/examples/language-sdk-instrumentation/python/rideshare/flask/docker-compose.yml @@ -1,35 +1,46 @@ -version: '3' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: ports: - - 5000 + - 5000 environment: - - REGION=us-east + - REGION=us-east build: context: . - eu-north: ports: - - 5000 + - 5000 environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: ports: - - 5000 + - 5000 environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: . dockerfile: Dockerfile.load-generator + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/python/rideshare/flask/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/python/rideshare/flask/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/python/rideshare/flask/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/python/rideshare/flask/lib/server.py b/examples/language-sdk-instrumentation/python/rideshare/flask/lib/server.py index 27ab2b7393..518148805a 100644 --- a/examples/language-sdk-instrumentation/python/rideshare/flask/lib/server.py +++ b/examples/language-sdk-instrumentation/python/rideshare/flask/lib/server.py @@ -22,7 +22,7 @@ # Sets the global default tracer provider trace.set_tracer_provider(provider) -app_name = os.getenv("PYROSCOPE_APPLICATION_NAME", "flask-ride-sharing-app") +app_name = os.getenv("PYROSCOPE_APPLICATION_NAME", "ride-sharing-app") server_addr = os.getenv("PYROSCOPE_SERVER_ADDRESS", "http://pyroscope:4040") basic_auth_username = os.getenv("PYROSCOPE_BASIC_AUTH_USER", "") basic_auth_password = os.getenv("PYROSCOPE_BASIC_AUTH_PASSWORD", "") diff --git a/examples/language-sdk-instrumentation/python/rideshare/flask/requirements.txt b/examples/language-sdk-instrumentation/python/rideshare/flask/requirements.txt new file mode 100644 index 0000000000..caf96ffefe --- /dev/null +++ b/examples/language-sdk-instrumentation/python/rideshare/flask/requirements.txt @@ -0,0 +1,27 @@ +blinker==1.9.0 +cffi==2.0.0 +click==8.4.1 +Flask==3.1.3 +googleapis-common-protos==1.75.0 +grpcio==1.81.0 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +opentelemetry-api==1.42.1 +opentelemetry-exporter-otlp-proto-common==1.42.1 +opentelemetry-exporter-otlp-proto-grpc==1.42.1 +opentelemetry-instrumentation==0.63b1 +opentelemetry-instrumentation-flask==0.63b1 +opentelemetry-instrumentation-wsgi==0.63b1 +opentelemetry-proto==1.42.1 +opentelemetry-sdk==1.42.1 +opentelemetry-semantic-conventions==0.63b1 +opentelemetry-util-http==0.63b1 +packaging==26.2 +protobuf==6.33.6 +pycparser==3.0 +pyroscope-io==1.0.11 +pyroscope-otel==1.0.1 +typing_extensions==4.15.0 +Werkzeug==3.1.8 +wrapt==2.2.1 diff --git a/examples/language-sdk-instrumentation/python/simple/README.md b/examples/language-sdk-instrumentation/python/simple/README.md new file mode 100644 index 0000000000..4700d4b5cb --- /dev/null +++ b/examples/language-sdk-instrumentation/python/simple/README.md @@ -0,0 +1,16 @@ +## Basic Example + +To run the example run the following commands: +``` +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +# Run the example project: +docker compose up --build + +# Reset the database (if needed): +docker compose down +``` + +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=simple.python.app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/python/simple/docker-compose.yml b/examples/language-sdk-instrumentation/python/simple/docker-compose.yml index 6ddeb49d27..c7d68d9107 100644 --- a/examples/language-sdk-instrumentation/python/simple/docker-compose.yml +++ b/examples/language-sdk-instrumentation/python/simple/docker-compose.yml @@ -1,11 +1,23 @@ ---- -version: '3.9' - services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 app: build: . + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/python/simple/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/python/simple/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/python/simple/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/python/simple/requirements.txt b/examples/language-sdk-instrumentation/python/simple/requirements.txt index 2b889cb104..651f5ad4aa 100644 --- a/examples/language-sdk-instrumentation/python/simple/requirements.txt +++ b/examples/language-sdk-instrumentation/python/simple/requirements.txt @@ -1 +1 @@ -pyroscope-io==0.8.6 +pyroscope-io==1.0.4 diff --git a/examples/language-sdk-instrumentation/ruby/README.md b/examples/language-sdk-instrumentation/ruby/README.md index 968dfba2ee..9fa61fc6f6 100644 --- a/examples/language-sdk-instrumentation/ruby/README.md +++ b/examples/language-sdk-instrumentation/ruby/README.md @@ -1,27 +1,39 @@ ## Continuous Profiling for Ruby applications + ### Profiling a Ruby Rideshare App with Pyroscope + ![ruby_example_architecture_new_00](https://user-images.githubusercontent.com/23323466/173369670-ba6fe5ce-eab0-4824-94dd-c72255efc063.gif) -Note: For documentation on the Pyroscope ruby gem visit [our website](https://pyroscope.io/docs/ruby/) +Note: For documentation on the Pyroscope ruby gem visit [our website](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/ruby/). + +## Live Demo + +Feel free to check out the [live demo](https://play.grafana.org/a/grafana-pyroscope-app/explore?searchText=&panelType=time-series&layout=grid&hideNoData=off&explorationType=flame-graph&var-serviceName=pyroscope-rideshare-ruby&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds&var-dataSource=grafanacloud-profiles) of this example on our demo page. + ## Background + In this example we show a simplified, basic use case of Pyroscope. We simulate a "ride share" company which has three endpoints found in `server.rb`: + - `/bike` : calls the `order_bike(search_radius)` function to order a bike - `/car` : calls the `order_car(search_radius)` function to order a car - `/scooter` : calls the `order_scooter(search_radius)` function to order a scooter -We also simulate running 3 distinct servers in 3 different regions (via [docker-compose.yml](https://github.com/pyroscope-io/pyroscope/blob/main/examples/ruby/docker-compose.yml)) +We also simulate running 3 distinct servers in 3 different regions: + - us-east - eu-north - ap-south One of the most useful capabilities of Pyroscope is the ability to tag your data in a way that is meaningful to you. In this case, we have two natural divisions, and so we "tag" our data to represent those: + - `region`: statically tags the region of the server running the code - `vehicle`: dynamically tags the endpoint (similar to how one might tag a controller rails) - ## Tagging static region + Tagging something static, like the `region`, can be done in the initialization code in the `config.tags` variable: -``` + +```ruby Pyroscope.configure do |config| config.app_name = "ride-sharing-app" config.server_address = "http://pyroscope:4040" @@ -32,8 +44,10 @@ end ``` ## Tagging dynamically within functions + Tagging something more dynamically, like we do for the `vehicle` tag can be done inside our utility `find_nearest_vehicle()` function using a `Pyroscope.tag_wrapper` block -``` + +```ruby def find_nearest_vehicle(n, vehicle) Pyroscope.tag_wrapper({ "vehicle" => vehicle }) do ...code to find nearest vehicle @@ -42,62 +56,66 @@ end ``` What this block does, is: + 1. Add the tag `{ "vehicle" => "car" }` 2. execute the `find_nearest_vehicle()` function 3. Before the block ends it will (behind the scenes) remove the `{ "vehicle" => "car" }` from the application since that block is complete -## Resulting flamgraph / performance results from the example +## Resulting flame graph / performance results from the example + ### Running the example -To run the example run the following commands: -``` -# Pull latest pyroscope image: + +To run the example run the following commands in the `rideshare` directory: + +```shell +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: -docker-compose up --build +docker compose up --build # Reset the database (if needed): -# docker-compose down +docker compose down ``` -What this example will do is run all the code mentioned above and also send some mock-load to the 3 servers as well as their respective 3 endpoints. If you select our application: `ride-sharing-app.cpu` from the dropdown, you should see a flame graph that looks like this. After we give 20-30 seconds for the flame graph to update and then click the refresh button we see our 3 functions at the bottom of the flame graph taking CPU resources _proportional to the size_ of their respective `search_radius` parameters. +The Rails version of the example is available in the `raidshare_rails` directory. + +What this example will do is run all the code mentioned above and also send some mock-load to the 3 servers as well as their respective 3 endpoints. If you select our application: `ride-sharing-app` from the dropdown, you should see a flame graph that looks like this. After we give 20-30 seconds for the flame graph to update and then click the refresh button we see our 3 functions at the bottom of the flame graph taking CPU resources _proportional to the size_ of their respective `search_radius` parameters. ## Where's the performance bottleneck? -![ruby_first_slide_01-01](https://user-images.githubusercontent.com/23323466/139566972-2f04b826-d05c-4307-9b60-4376840001ab.jpg) +![ruby_slide_1](https://github.com/user-attachments/assets/d1304b3d-f2a0-4bce-88cf-9113ecdd1a14) The first step when analyzing a profile outputted from your application, is to take note of the _largest node_ which is where your application is spending the most resources. In this case, it happens to be the `order_car` function. The benefit of using the Pyroscope package, is that now that we can investigate further as to _why_ the `order_car()` function is problematic. Tagging both `region` and `vehicle` allows us to test two good hypotheses: + - Something is wrong with the `/car` endpoint code - Something is wrong with one of our regions To analyze this we can select one or more tags from the "Select Tag" dropdown: -![image](https://user-images.githubusercontent.com/23323466/135525308-b81e87b0-6ffb-4ef0-a6bf-3338483d0fc4.png) +![ruby_slide_2](https://github.com/user-attachments/assets/e3d44542-a953-4419-a67e-a61214de5396) ## Narrowing in on the Issue Using Tags + Knowing there is an issue with the `order_car()` function we automatically select that tag. Then, after inspecting multiple `region` tags, it becomes clear by looking at the timeline that there is an issue with the `eu-north` region, where it alternates between high-cpu times and low-cpu times. We can also see that the `mutex_lock()` function is consuming almost 70% of CPU resources during this time period. -![ruby_second_slide_01](https://user-images.githubusercontent.com/23323466/139566994-f3f8c2f3-6bc4-40ca-ac4e-8fc862d0c0ad.jpg) - -## Comparing two time periods -Using Pyroscope's "comparison view" we can actually select two different time ranges from the timeline to compare the resulting flame graphs. The pink section on the left timeline results in the left flame graph and the blue section on the right represents the right flame graph. - -When we select a period of low-cpu utilization, and a period of high-cpu utilization we can see that there is clearly different behavior in the `mutex_lock()` function where it takes **23% of CPU** during low-cpu times and **70% of CPU** during high-cpu times. - -![ruby_third_slide_01-01](https://user-images.githubusercontent.com/23323466/139567004-96064c5b-570c-48a4-aa9a-07a46a0646a5.jpg) +![ruby_slide_3](https://github.com/user-attachments/assets/3eef7cfb-c008-4443-a2d1-ca58d8ce2421) ## Visualizing diff between two flame graphs -While the difference _in this case_ is stark enough to see in the comparison view, sometimes the diff between the two flame graphs is better visualized with them overlayed over each other. Without changing any parameters, we can simply select the diff view tab and see the difference represented in a color-coded diff flame graph. -![ruby_fourth_slide_01-01](https://user-images.githubusercontent.com/23323466/139567016-3f738923-2429-4f93-8fe0-cc0ca8c765fd.jpg) +While the difference _in this case_ is stark enough to see in the comparison view, sometimes the diff between the two flame graphs is better visualized with them overlayed over each other. Without changing any parameters, we can simply select the diff view tab and see the difference represented in a color-coded diff flame graph. +![ruby_slide_4](https://github.com/user-attachments/assets/33857a48-3942-429d-9abf-63f4619ad605) ### More use cases + We have been beta testing this feature with several different companies and some of the ways that we've seen companies tag their performance data: +- Linking profiles with trace data - Tagging controllers - Tagging regions - Tagging jobs from a redis or sidekiq queue @@ -107,6 +125,7 @@ We have been beta testing this feature with several different companies and some - Etc... ### Future Roadmap + We would love for you to try out this example and see what ways you can adapt this to your ruby application. Continuous profiling has become an increasingly popular tool for the monitoring and debugging of performance issues (arguably the fourth pillar of observability). We'd love to continue to improve this gem by adding things like integrations with popular tools, memory profiling, etc. and we would love to hear what features _you would like to see_. diff --git a/examples/language-sdk-instrumentation/ruby/README_zh.md b/examples/language-sdk-instrumentation/ruby/README_zh.md index eeb1dfb7b2..4986d84f01 100644 --- a/examples/language-sdk-instrumentation/ruby/README_zh.md +++ b/examples/language-sdk-instrumentation/ruby/README_zh.md @@ -4,7 +4,7 @@ #### _用其他语言阅读此文。_ [English](README.md) -注意:关于 Pyroscope ruby gem 的文档,请访问[我们的网站](https://pyroscope.io/docs/ruby/) +注意:关于 Pyroscope ruby gem 的文档,请访问[我们的网站](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/ruby/) ## 背景介绍 在这个例子中,我们展示了 Pyroscope 的一个简化的基本用例。我们模拟了一个 "骑行共享" 公司,它有三个请求端点,可以在`server.rb`中找到: @@ -52,8 +52,9 @@ end ### 运行这个例子 要运行该例子,请运行以下命令: ``` -# 拉取最新的 pyroscope 镜像: +# 拉取最新的 pyroscope/grafana 镜像: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # 运行示例项目: docker-compose up --build diff --git a/examples/language-sdk-instrumentation/ruby/rideshare/Dockerfile b/examples/language-sdk-instrumentation/ruby/rideshare/Dockerfile index e0b302d8f4..6b2fb210c4 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare/Dockerfile +++ b/examples/language-sdk-instrumentation/ruby/rideshare/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.2.2 +FROM ruby:3.3.9 WORKDIR /opt/app @@ -9,4 +9,6 @@ RUN bundle install COPY lib ./lib +ENV APP_ENV=production + CMD [ "ruby", "lib/server.rb" ] diff --git a/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile b/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile index 7a56c065ed..3f1a1dce15 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile +++ b/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile @@ -4,8 +4,12 @@ source "https://rubygems.org" git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } -# gem "rails" -gem 'pyroscope', '= 0.5.11' -gem "sinatra", "~> 2.1" - -gem "thin", "~> 1.8" +gem 'pyroscope', '= 1.0.1' +gem "sinatra", "~> 4.2" +gem "thin", "~> 2.0" +gem 'pyroscope-otel' +gem 'opentelemetry-sdk' +gem 'opentelemetry-exporter-otlp' + +gem "rackup", "~> 2.2" +gem "puma", "~> 6.6" diff --git a/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile.lock b/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile.lock index c9a62c43d6..8fc0d950d2 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile.lock +++ b/examples/language-sdk-instrumentation/ruby/rideshare/Gemfile.lock @@ -1,41 +1,130 @@ GEM remote: https://rubygems.org/ specs: + base64 (0.3.0) + bigdecimal (3.1.8) daemons (1.4.1) eventmachine (1.2.7) - ffi (1.16.3) - mustermann (2.0.2) + ffi (1.17.4) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm-linux-gnu) + ffi (1.17.4-arm-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86-linux-gnu) + ffi (1.17.4-x86-linux-musl) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + ffi (1.17.4-x86_64-linux-musl) + google-protobuf (4.29.1) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-aarch64-linux) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-arm64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-x86-linux) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-x86_64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-x86_64-linux) + bigdecimal + rake (>= 13) + googleapis-common-protos-types (1.16.0) + google-protobuf (>= 3.18, < 5.a) + logger (1.7.0) + mustermann (3.0.4) ruby2_keywords (~> 0.0.1) - pyroscope (0.5.11-aarch64-linux) + nio4r (2.7.4) + opentelemetry-api (1.5.0) + opentelemetry-common (0.21.0) + opentelemetry-api (~> 1.0) + opentelemetry-exporter-otlp (0.29.1) + google-protobuf (>= 3.18) + googleapis-common-protos-types (~> 1.3) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-sdk (~> 1.2) + opentelemetry-semantic_conventions + opentelemetry-registry (0.3.1) + opentelemetry-api (~> 1.1) + opentelemetry-sdk (1.6.0) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-registry (~> 0.2) + opentelemetry-semantic_conventions + opentelemetry-semantic_conventions (1.10.1) + opentelemetry-api (~> 1.0) + puma (6.6.0) + nio4r (~> 2.0) + pyroscope (1.0.1) ffi - pyroscope (0.5.11-arm64-darwin) + pyroscope (1.0.1-aarch64-linux) ffi - pyroscope (0.5.11-x86_64-linux) + pyroscope (1.0.1-arm64-darwin) ffi - rack (2.2.8.1) - rack-protection (2.2.4) - rack + pyroscope (1.0.1-x86_64-darwin) + ffi + pyroscope (1.0.1-x86_64-linux) + ffi + pyroscope-otel (0.2.0) + opentelemetry-api (~> 1.1) + pyroscope (>= 1.0, < 2.0) + rack (3.2.6) + rack-protection (4.2.0) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.2) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rackup (2.2.1) + rack (>= 3) + rake (13.2.1) ruby2_keywords (0.0.5) - sinatra (2.2.4) - mustermann (~> 2.0) - rack (~> 2.2) - rack-protection (= 2.2.4) + sinatra (4.2.0) + logger (>= 1.6.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.2.0) + rack-session (>= 2.0.0, < 3) tilt (~> 2.0) - thin (1.8.2) + thin (2.0.1) daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) - rack (>= 1, < 3) - tilt (2.3.0) + logger + rack (>= 1, < 4) + tilt (2.6.1) PLATFORMS aarch64-linux - arm64-darwin-22 + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux + x86-linux-gnu + x86-linux-musl + x86_64-darwin x86_64-linux + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES - pyroscope (= 0.5.11) - sinatra (~> 2.1) - thin (~> 1.8) + opentelemetry-exporter-otlp + opentelemetry-sdk + puma (~> 6.6) + pyroscope (= 1.0.1) + pyroscope-otel + rackup (~> 2.2) + sinatra (~> 4.2) + thin (~> 2.0) BUNDLED WITH - 2.4.10 + 2.5.22 diff --git a/examples/language-sdk-instrumentation/ruby/rideshare/README.md b/examples/language-sdk-instrumentation/ruby/rideshare/README.md index cfb080a751..bf57c45f13 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare/README.md +++ b/examples/language-sdk-instrumentation/ruby/rideshare/README.md @@ -1,112 +1,16 @@ -## Continuous Profiling for Ruby applications -### Profiling a Ruby Rideshare App with Pyroscope -![ruby_example_architecture_05](https://user-images.githubusercontent.com/23323466/135726784-0c367d3f-c9e5-4e3f-91be-761d4d6d21b1.gif) +# Rideshare Example -Note: For documentation on the Pyroscope ruby gem visit [our website](https://pyroscope.io/docs/ruby/) -## Background -In this example we show a simplified, basic use case of Pyroscope. We simulate a "ride share" company which has three endpoints found in `server.rb`: -- `/bike` : calls the `order_bike(search_radius)` function to order a bike -- `/car` : calls the `order_car(search_radius)` function to order a car -- `/scooter` : calls the `order_scooter(search_radius)` function to order a scooter - -We also simulate running 3 distinct servers in 3 different regions (via [docker-compose.yml](https://github.com/pyroscope-io/pyroscope/blob/main/examples/ruby/docker-compose.yml)) -- us-east -- eu-north -- ap-south - -One of the most useful capabilities of Pyroscope is the ability to tag your data in a way that is meaningful to you. In this case, we have two natural divisions, and so we "tag" our data to represent those: -- `region`: statically tags the region of the server running the code -- `vehicle`: dynamically tags the endpoint (similar to how one might tag a controller rails) - - -## Tagging static region -Tagging something static, like the `region`, can be done in the initialization code in the `config.tags` variable: -``` -Pyroscope.configure do |config| - config.app_name = "ride-sharing-app" - config.server_address = "http://pyroscope:4040" - config.tags = { - "region": ENV["REGION"], # Tags the region based of the environment variable - } -end -``` - -## Tagging dynamically within functions -Tagging something more dynamically, like we do for the `vehicle` tag can be done inside our utility `find_nearest_vehicle()` function using a `Pyroscope.tag_wrapper` block -``` -def find_nearest_vehicle(n, vehicle) - Pyroscope.tag_wrapper({ "vehicle" => vehicle }) do - ...code to find nearest vehicle - end -end -``` - -What this block does, is: -1. Add the tag `{ "vehicle" => "car" }` -2. execute the `find_nearest_vehicle()` function -3. Before the block ends it will (behind the scenes) remove the `{ "vehicle" => "car" }` from the application since that block is complete - -## Resulting flamgraph / performance results from the example -### Running the example To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: -docker-compose up --build +docker compose up --build # Reset the database (if needed): -# docker-compose down +docker compose down ``` -What this example will do is run all the code mentioned above and also send some mock-load to the 3 servers as well as their respective 3 endpoints. If you select our application: `ride-sharing-app.cpu` from the dropdown, you should see a flame graph that looks like this. After we give 20-30 seconds for the flame graph to update and then click the refresh button we see our 3 functions at the bottom of the flame graph taking CPU resources _proportional to the size_ of their respective `search_radius` parameters. - -## Where's the performance bottleneck? -![ruby_first_slide_01-01](https://user-images.githubusercontent.com/23323466/139566972-2f04b826-d05c-4307-9b60-4376840001ab.jpg) - - -The first step when analyzing a profile outputted from your application, is to take note of the _largest node_ which is where your application is spending the most resources. In this case, it happens to be the `order_car` function. - -The benefit of using the Pyroscope package, is that now that we can investigate further as to _why_ the `order_car()` function is problematic. Tagging both `region` and `vehicle` allows us to test two good hypotheses: -- Something is wrong with the `/car` endpoint code -- Something is wrong with one of our regions - -To analyze this we can select one or more tags from the "Select Tag" dropdown: - -![image](https://user-images.githubusercontent.com/23323466/135525308-b81e87b0-6ffb-4ef0-a6bf-3338483d0fc4.png) - -## Narrowing in on the Issue Using Tags -Knowing there is an issue with the `order_car()` function we automatically select that tag. Then, after inspecting multiple `region` tags, it becomes clear by looking at the timeline that there is an issue with the `eu-north` region, where it alternates between high-cpu times and low-cpu times. - -We can also see that the `mutex_lock()` function is consuming almost 70% of CPU resources during this time period. - -![ruby_second_slide_01](https://user-images.githubusercontent.com/23323466/139566994-f3f8c2f3-6bc4-40ca-ac4e-8fc862d0c0ad.jpg) - -## Comparing two time periods -Using Pyroscope's "comparison view" we can actually select two different time ranges from the timeline to compare the resulting flame graphs. The pink section on the left timeline results in the left flame graph and the blue section on the right represents the right flame graph. - -When we select a period of low-cpu utilization, and a period of high-cpu utilization we can see that there is clearly different behavior in the `mutex_lock()` function where it takes **23% of CPU** during low-cpu times and **70% of CPU** during high-cpu times. - -![ruby_third_slide_01-01](https://user-images.githubusercontent.com/23323466/139567004-96064c5b-570c-48a4-aa9a-07a46a0646a5.jpg) - -## Visualizing diff between two flame graphs -While the difference _in this case_ is stark enough to see in the comparison view, sometimes the diff between the two flame graphs is better visualized with them overlayed over each other. Without changing any parameters, we can simply select the diff view tab and see the difference represented in a color-coded diff flame graph. - -![ruby_fourth_slide_01-01](https://user-images.githubusercontent.com/23323466/139567016-3f738923-2429-4f93-8fe0-cc0ca8c765fd.jpg) - - -### More use cases -We have been beta testing this feature with several different companies and some of the ways that we've seen companies tag their performance data: -- Tagging controllers -- Tagging regions -- Tagging jobs from a redis or sidekiq queue -- Tagging commits -- Tagging staging / production environments -- Tagging different parts of their testing suites -- Etc... - -### Future Roadmap -We would love for you to try out this example and see what ways you can adapt this to your ruby application. Continuous profiling has become an increasingly popular tool for the monitoring and debugging of performance issues (arguably the fourth pillar of observability). - -We'd love to continue to improve this gem by adding things like integrations with popular tools, memory profiling, etc. and we would love to hear what features _you would like to see_. +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/ruby/rideshare/README_zh.md b/examples/language-sdk-instrumentation/ruby/rideshare/README_zh.md deleted file mode 100644 index 4b13183e9d..0000000000 --- a/examples/language-sdk-instrumentation/ruby/rideshare/README_zh.md +++ /dev/null @@ -1,108 +0,0 @@ -### Pyroscope Rideshare 示例 -![ruby_example_architecture_05](https://user-images.githubusercontent.com/23323466/135726784-0c367d3f-c9e5-4e3f-91be-761d4d6d21b1.gif) - -#### _用其他语言阅读此文。_ -[English](README.md) - -注意:关于 Pyroscope ruby gem 的文档,请访问[我们的网站](https://pyroscope.io/docs/ruby/) -## 背景介绍 - -在这个例子中,我们展示了 Pyroscope 的一个简化的基本用例。我们模拟了一个 "骑行共享" 公司,它有三个请求端点,可以在`server.rb`中找到: -- `/bike`:调用`order_bike(search_radius)`函数来订购共享自行车 -- `/car` : 调用`order_car(search_radius)`函数来订购共享汽车 -- `/scooter` : 调用`order_scooter(search_radius)`函数来订购共享摩托车 - -我们还模拟了在3个不同地区运行3个不同的服务器(通过[docker-compose.yml](https://github.com/pyroscope-io/pyroscope/blob/main/examples/ruby/docker-compose.yml)) -- us-east -- eu-north -- ap-south - - -Pyroscope 最有用的功能之一是能够以对你有意义的方式来标记你的数据。在这种情况下,我们有两个自然划分,因此我们 "标记(tag)" 我们的数据以表示这些: -- `region`:静态地标记运行代码的服务器的区域 -- `vehicle`: 动态标记端点(类似于标记控制器轨道的方式) - -## 标记静态区域 -标记一些静态的东西,如`region`,可以在初始化代码中的`config.tags`变量中完成: -``` -Pyroscope.configure do |config| - config.app_name = "ride-sharing-app" - config.server_address = "http://pyroscope:4040" - config.tags = { - "region": ENV["REGION"], # 根据环境变量标记该区域 - } -end -``` - -## 在函数中动态地添加标签 -像我们对 `vehicle` 标签所做的那样,可以在我们的实用程序 `find_nearest_vehicle()` 函数中使用 `Pyroscope.tag_wrapper` 块来完成更动态的标记 -``` -def find_nearest_vehicle(n, vehicle) - Pyroscope.tag_wrapper({ "vehicle" => vehicle }) do - ...code to find nearest vehicle - end -end -``` -这个块的作用是: -1. 添加标签 `{ "vehicle" => "car" }` -2. 执行`find_nearest_vehicle()`函数 -3. 在该块结束之前,它将(在后台)从应用程序中删除`{ "vehicle" => "car" }`,因为该上下文区块已经完成 - -## 例子中产生的火焰图/性能结果 -### 运行这个例子 -要运行该例子,请运行以下命令: -``` -# 拉取最新的 pyroscope 镜像: -docker pull grafana/pyroscope:latest - -# 运行示例项目: -docker-compose up --build - -# 重置数据库(非必需): -# docker-compose down -``` - - -这个例子要做的是运行上面提到的所有代码,同时向3个服务器以及它们各自的3个端点发送一些模拟负载。如果你从下拉菜单中选择我们的应用程序:`rid-sharing-app.cpu`,你应该看到一个看起来像这样的火焰图(见下文)。在我们给予20-30秒的时间来更新火焰图之后,点击刷新按钮,我们看到火焰图底部的3个函数占用的CPU资源与它们各自的`search_radius`参数 _大小成正比_。 -## 性能瓶颈在哪里? -![ruby_first_slide_00](https://user-images.githubusercontent.com/23323466/135945825-a1d793e8-ecd9-4143-88d8-de08837a4761.jpg) - -当分析从你的应用程序输出的剖析文件时,第一步是注意 _最大的节点_,这是你的应用程序花费最多资源的地方。在这个例子中,它恰好是 `order_car` 函数。 - -使用 Pyroscope 包的好处是,现在我们可以进一步调查为什么 `order_car()` 函数有问题。同时标记 `region`和 `vehicle`使我们能够测试两个好的假设: -- `/car` 端点的代码出了问题 -- 我们的一个区域出了问题 - -为了分析这一点,我们可以从 "Select Tag" 下拉菜单中选择一个或多个标签: - -![image](https://user-images.githubusercontent.com/23323466/135525308-b81e87b0-6ffb-4ef0-a6bf-3338483d0fc4.png) - -## 使用标签缩小问题的范围 -知道`order_car()`函数有问题,我们就自动选择该标签。然后,在检查了多个 `region` 标签后,通过查看时间线,可以清楚地看到 `eu-north`区域存在问题,它在高cpu时间和低cpu时间之间交替出现。 - -我们还可以看到,`mutex_lock()`函数在这段时间内几乎消耗了70%的CPU资源。 -![ruby_second_slide_00](https://user-images.githubusercontent.com/23323466/135946038-32ff05dd-2909-4bef-ba46-05a16c57410a.jpg) - -## 比较两个时间段的情况 -使用 Pyroscope 的 "比较视图",我们实际上可以从时间线上选择两个不同的时间范围来比较所产生的火焰图。左边时间线上的粉红色部分结果是左边的火焰图,右边的蓝色部分代表右边的火焰图。 -当我们选择一个低CPU利用率的时期和一个高CPU利用率的时期时,我们可以看到`mutex_lock()`函数有明显不同的行为,它在低CPU时期占用**51%的CPU**,在高CPU时期占用**78%的CPU**。 -![ruby_third_slide_00](https://user-images.githubusercontent.com/23323466/135946117-05a15195-6e3c-499c-b98d-f1b9db2844e6.jpg) - -## 可视化两个火焰图之间的差异 -虽然在 _这个例子_ 中,差异足以在比较视图中看到,但有时两个火焰图之间的差异在相互叠加的情况下会更直观。在不改变任何参数的情况下,我们可以简单地选择差异视图选项卡,看到用彩色编码的差异火焰图表示的差异。 -![ruby_fourth_slide_00](https://user-images.githubusercontent.com/23323466/135946209-e44ff6f6-22d6-41e0-bb08-693675257b84.jpg) - -### 更多用例 -我们一直在与几个不同的公司测试这一功能,我们看到一些公司标记其业务数据的方式: -- 标记控制器 -- 标记区域 -- 从redis / sidekiq / rabbitmq队列中标记作业 -- 标记提交 -- 标记预发/生产环境 -- 标记其测试套件的不同部分 -- 等等... - -### 未来路线图 -我们希望你能尝试一下这个例子,看看你能用什么方式来适配你的 ruby 应用。持续剖析已经成为监测和调试性能问题的一个越来越流行的工具(可以说是可观察性的第四个支柱)。 - -我们希望通过增加与流行工具的集成、内存分析等内容来继续改进这个 gem 包,我们很想听听 _你希望看到的功能_。 diff --git a/examples/language-sdk-instrumentation/ruby/rideshare/docker-compose.yml b/examples/language-sdk-instrumentation/ruby/rideshare/docker-compose.yml index 25adcf9a5a..952658253b 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare/docker-compose.yml +++ b/examples/language-sdk-instrumentation/ruby/rideshare/docker-compose.yml @@ -1,29 +1,40 @@ -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: environment: - - REGION=us-east + - REGION=us-east build: context: . - eu-north: environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: . dockerfile: Dockerfile.load-generator + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/ruby/rideshare/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/ruby/rideshare/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/rideshare/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/.ruby-version b/examples/language-sdk-instrumentation/ruby/rideshare_rails/.ruby-version index 72b3400f1f..d569de08f9 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare_rails/.ruby-version +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/.ruby-version @@ -1 +1 @@ -ruby-3.2.1 +ruby-3.3.9 diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/Dockerfile b/examples/language-sdk-instrumentation/ruby/rideshare_rails/Dockerfile index fc7f2f9aca..f2b3b4e16e 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare_rails/Dockerfile +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/Dockerfile @@ -1,11 +1,22 @@ -FROM ruby:3.2.2 +FROM ruby:3.3.9-slim + +# Install runtime and build dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + libsqlite3-0 \ + libyaml-0-2 \ + build-essential \ + libsqlite3-dev \ + libyaml-dev \ + pkg-config \ + && rm -rf /var/lib/apt/lists/* RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -ENV RAILS_ENV production -ENV RAILS_SERVE_STATIC_FILES true -ENV RAILS_LOG_TO_STDOUT true +ENV RAILS_ENV=production +ENV RAILS_SERVE_STATIC_FILES=true +ENV RAILS_LOG_TO_STDOUT=true +ENV SECRET_KEY_BASE=demo-secret-key-base-not-for-production COPY Gemfile /usr/src/app/ COPY Gemfile.lock /usr/src/app/ diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile b/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile index df050cd491..b59b478a28 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile @@ -1,10 +1,15 @@ source "https://rubygems.org" git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby "3.2.2" +ruby "3.3.9" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem "rails", "~> 7.0.8" +gem "rails", "~> 7.2.3", ">= 7.2.3.1" + +gem "activestorage", "~> 7.2.3", ">= 7.2.3.1" + +# Security update for nokogiri CVE (GHSA-353f-x4gh-cqq8) +gem "nokogiri", ">= 1.18.9" # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] gem "sprockets-rails" @@ -13,11 +18,11 @@ gem "sprockets-rails" gem "sqlite3", "~> 1.4" # Use the Puma web server [https://github.com/puma/puma] -gem "puma", "~> 5.6" +gem "puma", "~> 6.0" -gem 'pyroscope', '= 0.5.11' +gem 'pyroscope', '= 1.0.1' -gem "pyroscope-otel", "~> 0.1.1" +gem "pyroscope-otel", "~> 0.2.0" gem 'opentelemetry-sdk', "~> 1.2.0" gem 'opentelemetry-exporter-jaeger', '~> 0.22.0' gem 'opentelemetry-instrumentation-rails' # it's top span is "http get" which is not super usefull for demo diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile.lock b/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile.lock index f32bf752e7..6ffc1d8838 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile.lock +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/Gemfile.lock @@ -1,123 +1,144 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.8.1) - actionpack (= 7.0.8.1) - activesupport (= 7.0.8.1) + actioncable (7.2.3.1) + actionpack (= 7.2.3.1) + activesupport (= 7.2.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.8.1) - actionpack (= 7.0.8.1) - activejob (= 7.0.8.1) - activerecord (= 7.0.8.1) - activestorage (= 7.0.8.1) - activesupport (= 7.0.8.1) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.0.8.1) - actionpack (= 7.0.8.1) - actionview (= 7.0.8.1) - activejob (= 7.0.8.1) - activesupport (= 7.0.8.1) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.8.1) - actionview (= 7.0.8.1) - activesupport (= 7.0.8.1) - rack (~> 2.0, >= 2.2.4) + zeitwerk (~> 2.6) + actionmailbox (7.2.3.1) + actionpack (= 7.2.3.1) + activejob (= 7.2.3.1) + activerecord (= 7.2.3.1) + activestorage (= 7.2.3.1) + activesupport (= 7.2.3.1) + mail (>= 2.8.0) + actionmailer (7.2.3.1) + actionpack (= 7.2.3.1) + actionview (= 7.2.3.1) + activejob (= 7.2.3.1) + activesupport (= 7.2.3.1) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (7.2.3.1) + actionview (= 7.2.3.1) + activesupport (= 7.2.3.1) + cgi + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4, < 3.3) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.8.1) - actionpack (= 7.0.8.1) - activerecord (= 7.0.8.1) - activestorage (= 7.0.8.1) - activesupport (= 7.0.8.1) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (7.2.3.1) + actionpack (= 7.2.3.1) + activerecord (= 7.2.3.1) + activestorage (= 7.2.3.1) + activesupport (= 7.2.3.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.8.1) - activesupport (= 7.0.8.1) + actionview (7.2.3.1) + activesupport (= 7.2.3.1) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.8.1) - activesupport (= 7.0.8.1) + cgi + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.2.3.1) + activesupport (= 7.2.3.1) globalid (>= 0.3.6) - activemodel (7.0.8.1) - activesupport (= 7.0.8.1) - activerecord (7.0.8.1) - activemodel (= 7.0.8.1) - activesupport (= 7.0.8.1) - activestorage (7.0.8.1) - actionpack (= 7.0.8.1) - activejob (= 7.0.8.1) - activerecord (= 7.0.8.1) - activesupport (= 7.0.8.1) + activemodel (7.2.3.1) + activesupport (= 7.2.3.1) + activerecord (7.2.3.1) + activemodel (= 7.2.3.1) + activesupport (= 7.2.3.1) + timeout (>= 0.4.0) + activestorage (7.2.3.1) + actionpack (= 7.2.3.1) + activejob (= 7.2.3.1) + activerecord (= 7.2.3.1) + activesupport (= 7.2.3.1) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.8.1) - concurrent-ruby (~> 1.0, >= 1.0.2) + activesupport (7.2.3.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - builder (3.2.4) - concurrent-ruby (1.2.3) + logger (>= 1.4.2) + minitest (>= 5.1, < 6) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (4.1.2) + builder (3.3.0) + cgi (0.5.1) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) crass (1.0.6) - date (3.3.4) - debug (1.8.0) - irb (>= 1.5.0) - reline (>= 0.3.1) - erubi (1.12.0) - ffi (1.16.3) - globalid (1.2.1) + date (3.5.1) + debug (1.11.1) + irb (~> 1.10) + reline (>= 0.3.8) + drb (2.2.3) + erb (6.0.4) + erubi (1.13.1) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + globalid (1.3.0) activesupport (>= 6.1) - i18n (1.14.1) + i18n (1.14.8) concurrent-ruby (~> 1.0) - io-console (0.6.0) - irb (1.8.1) - rdoc - reline (>= 0.3.8) - loofah (2.22.0) + io-console (0.8.2) + irb (1.18.0) + pp (>= 0.6.0) + prism (>= 1.3.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + logger (1.7.0) + loofah (2.25.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.8.1) + mail (2.9.0) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.2) - method_source (1.0.0) + marcel (1.1.0) mini_mime (1.1.5) - mini_portile2 (2.8.5) - minitest (5.22.2) - net-imap (0.4.10) + minitest (5.27.0) + net-imap (0.6.3) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.4.0.1) + net-smtp (0.5.1) net-protocol - nio4r (2.7.0) - nokogiri (1.16.2) - mini_portile2 (~> 2.8.2) + nio4r (2.7.5) + nokogiri (1.19.2-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.16.2-aarch64-linux) + nokogiri (1.19.2-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.16.2-arm64-darwin) + nokogiri (1.19.2-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.2-x86_64-darwin) + nokogiri (1.19.2-x86_64-darwin) racc (~> 1.4) - nokogiri (1.16.2-x86_64-linux) + nokogiri (1.19.2-x86_64-linux-gnu) racc (~> 1.4) - opentelemetry-api (1.1.0) + opentelemetry-api (1.9.0) + logger opentelemetry-common (0.19.7) opentelemetry-api (~> 1.0) opentelemetry-exporter-jaeger (0.22.0) @@ -126,149 +147,174 @@ GEM opentelemetry-sdk (~> 1.2) opentelemetry-semantic_conventions thrift - opentelemetry-instrumentation-action_pack (0.7.0) + opentelemetry-instrumentation-action_mailer (0.3.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-active_support (~> 0.7) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-action_pack (0.10.0) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) opentelemetry-instrumentation-rack (~> 0.21) - opentelemetry-instrumentation-action_view (0.6.0) + opentelemetry-instrumentation-action_view (0.8.0) opentelemetry-api (~> 1.0) - opentelemetry-instrumentation-active_support (~> 0.1) + opentelemetry-instrumentation-active_support (~> 0.7) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-active_job (0.6.0) + opentelemetry-instrumentation-active_job (0.7.8) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-active_record (0.6.2) + opentelemetry-instrumentation-active_record (0.8.1) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - ruby2_keywords - opentelemetry-instrumentation-active_support (0.4.2) + opentelemetry-instrumentation-active_support (0.7.0) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-base (0.22.2) + opentelemetry-instrumentation-base (0.22.3) opentelemetry-api (~> 1.0) opentelemetry-registry (~> 0.1) - opentelemetry-instrumentation-rack (0.23.2) + opentelemetry-instrumentation-concurrent_ruby (0.21.4) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-rack (0.25.0) opentelemetry-api (~> 1.0) - opentelemetry-common (~> 0.19.3) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-rails (0.28.0) + opentelemetry-instrumentation-rails (0.34.1) opentelemetry-api (~> 1.0) - opentelemetry-instrumentation-action_pack (~> 0.7.0) - opentelemetry-instrumentation-action_view (~> 0.6.0) - opentelemetry-instrumentation-active_job (~> 0.6.0) - opentelemetry-instrumentation-active_record (~> 0.6.1) - opentelemetry-instrumentation-active_support (~> 0.4.1) + opentelemetry-instrumentation-action_mailer (~> 0.3.0) + opentelemetry-instrumentation-action_pack (~> 0.10.0) + opentelemetry-instrumentation-action_view (~> 0.8.0) + opentelemetry-instrumentation-active_job (~> 0.7.0) + opentelemetry-instrumentation-active_record (~> 0.8.0) + opentelemetry-instrumentation-active_support (~> 0.7.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-registry (0.3.0) + opentelemetry-instrumentation-concurrent_ruby (~> 0.21.4) + opentelemetry-registry (0.5.0) opentelemetry-api (~> 1.1) opentelemetry-sdk (1.2.1) opentelemetry-api (~> 1.1) opentelemetry-common (~> 0.19.3) opentelemetry-registry (~> 0.2) opentelemetry-semantic_conventions - opentelemetry-semantic_conventions (1.10.0) + opentelemetry-semantic_conventions (1.37.0) opentelemetry-api (~> 1.0) - psych (5.1.2) + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + prism (1.9.0) + psych (5.3.1) + date stringio - puma (5.6.8) + puma (6.6.1) nio4r (~> 2.0) - pyroscope (0.5.11) - ffi - pyroscope (0.5.11-aarch64-linux) + pyroscope (1.0.1-aarch64-linux) ffi - pyroscope (0.5.11-arm64-darwin) + pyroscope (1.0.1-arm64-darwin) ffi - pyroscope (0.5.11-x86_64-darwin) + pyroscope (1.0.1-x86_64-darwin) ffi - pyroscope (0.5.11-x86_64-linux) + pyroscope (1.0.1-x86_64-linux) ffi - pyroscope-otel (0.1.1) - opentelemetry-api (~> 1.1.0) - pyroscope (~> 0.5.1) - racc (1.7.3) - rack (2.2.8.1) - rack-test (2.1.0) + pyroscope-otel (0.2.0) + opentelemetry-api (~> 1.1) + pyroscope (>= 1.0, < 2.0) + racc (1.8.1) + rack (3.2.6) + rack-session (2.1.2) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) rack (>= 1.3) - rails (7.0.8.1) - actioncable (= 7.0.8.1) - actionmailbox (= 7.0.8.1) - actionmailer (= 7.0.8.1) - actionpack (= 7.0.8.1) - actiontext (= 7.0.8.1) - actionview (= 7.0.8.1) - activejob (= 7.0.8.1) - activemodel (= 7.0.8.1) - activerecord (= 7.0.8.1) - activestorage (= 7.0.8.1) - activesupport (= 7.0.8.1) + rackup (2.3.1) + rack (>= 3) + rails (7.2.3.1) + actioncable (= 7.2.3.1) + actionmailbox (= 7.2.3.1) + actionmailer (= 7.2.3.1) + actionpack (= 7.2.3.1) + actiontext (= 7.2.3.1) + actionview (= 7.2.3.1) + activejob (= 7.2.3.1) + activemodel (= 7.2.3.1) + activerecord (= 7.2.3.1) + activestorage (= 7.2.3.1) + activesupport (= 7.2.3.1) bundler (>= 1.15.0) - railties (= 7.0.8.1) - rails-dom-testing (2.2.0) + railties (= 7.2.3.1) + rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) - loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.0.8.1) - actionpack (= 7.0.8.1) - activesupport (= 7.0.8.1) - method_source + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (7.2.3.1) + actionpack (= 7.2.3.1) + activesupport (= 7.2.3.1) + cgi + irb (~> 1.13) + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) - rake (13.1.0) - rdoc (6.6.3.1) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) + rake (13.4.2) + rdoc (7.2.0) + erb psych (>= 4.0.0) - reline (0.3.8) + tsort + reline (0.6.3) io-console (~> 0.5) - ruby2_keywords (0.0.5) - sprockets (4.2.1) + securerandom (0.4.1) + sprockets (4.2.2) concurrent-ruby (~> 1.0) + logger rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) - sqlite3 (1.6.6) - mini_portile2 (~> 2.8.0) - sqlite3 (1.6.6-aarch64-linux) - sqlite3 (1.6.6-arm64-darwin) - sqlite3 (1.6.6-x86_64-darwin) - sqlite3 (1.6.6-x86_64-linux) - stringio (3.1.0) - thor (1.3.1) - thrift (0.19.0) - timeout (0.4.1) + sqlite3 (1.7.3-aarch64-linux) + sqlite3 (1.7.3-arm64-darwin) + sqlite3 (1.7.3-x86_64-darwin) + sqlite3 (1.7.3-x86_64-linux) + stringio (3.2.0) + thor (1.5.0) + thrift (0.22.0) + timeout (0.6.1) + tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - websocket-driver (0.7.6) + useragent (0.16.11) + websocket-driver (0.8.0) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.6.13) + zeitwerk (2.7.5) PLATFORMS aarch64-linux + aarch64-linux-musl arm64-darwin-22 - ruby + arm64-darwin-24 x86_64-darwin-21 x86_64-linux DEPENDENCIES + activestorage (~> 7.2.3, >= 7.2.3.1) debug + nokogiri (>= 1.18.9) opentelemetry-exporter-jaeger (~> 0.22.0) opentelemetry-instrumentation-rails opentelemetry-sdk (~> 1.2.0) - puma (~> 5.6) - pyroscope (= 0.5.11) - pyroscope-otel (~> 0.1.1) - rails (~> 7.0.8) + puma (~> 6.0) + pyroscope (= 1.0.1) + pyroscope-otel (~> 0.2.0) + rails (~> 7.2.3, >= 7.2.3.1) sprockets-rails sqlite3 (~> 1.4) tzinfo-data RUBY VERSION - ruby 3.2.2p53 + ruby 3.3.9p170 BUNDLED WITH - 2.4.10 + 2.5.22 diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/README.md b/examples/language-sdk-instrumentation/ruby/rideshare_rails/README.md index 5703b51512..7ddc9618fb 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare_rails/README.md +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/README.md @@ -1,12 +1,16 @@ -# Rails rideshare example +# Rails Rideshare Example +To run the example run the following commands: ``` -# Pull latest pyroscope image: +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: -docker-compose up --build +docker compose up --build # Reset the database (if needed): -docker-compose down +docker compose down ``` + +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/bundle b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/bundle new file mode 100755 index 0000000000..5b593cb62d --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/bundle @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_requirement + @bundler_requirement ||= + env_var_version || cli_arg_version || + bundler_requirement_for(lockfile_version) + end + + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version + + bundler_gem_version = Gem::Version.new(version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem.rubygems_version < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/rails b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/rails new file mode 100755 index 0000000000..efc0377492 --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/rake b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/rake new file mode 100755 index 0000000000..4fbf10b960 --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/setup b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/setup new file mode 100755 index 0000000000..ec47b79b3b --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/config/initializers/pyroscope.rb b/examples/language-sdk-instrumentation/ruby/rideshare_rails/config/initializers/pyroscope.rb index e15f94979b..27244a109a 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare_rails/config/initializers/pyroscope.rb +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/config/initializers/pyroscope.rb @@ -1,6 +1,6 @@ require 'pyroscope/otel' -app_name = ENV.fetch("PYROSCOPE_APPLICATION_NAME", "rails-ride-sharing-app") +app_name = ENV.fetch("PYROSCOPE_APPLICATION_NAME", "ride-sharing-app") pyroscope_server_address = ENV.fetch("PYROSCOPE_SERVER_ADDRESS", "http://pyroscope:4040") jaeger_endpoint = ENV.fetch("JAEGER_ENDPOINT", "http://localhost:14268/api/traces") diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/docker-compose.yml b/examples/language-sdk-instrumentation/ruby/rideshare_rails/docker-compose.yml index 5e689ee362..6dbcdce6d8 100644 --- a/examples/language-sdk-instrumentation/ruby/rideshare_rails/docker-compose.yml +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/docker-compose.yml @@ -1,41 +1,52 @@ -version: "3" services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: ports: - - 5000 + - 5000 environment: - - REGION=us-east + - REGION=us-east build: context: . links: - - 'pyroscope' - + - pyroscope eu-north: ports: - - 5000 + - 5000 environment: - - REGION=eu-north + - REGION=eu-north build: context: . - ap-south: ports: - - 5000 + - 5000 environment: - - REGION=ap-south + - REGION=ap-south build: context: . - load-generator: build: context: . dockerfile: Dockerfile.load-generator links: - - us-east - - ap-south - - eu-north + - us-east + - ap-south + - eu-north + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/ruby/rideshare_rails/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/ruby/rideshare_rails/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/rideshare_rails/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/ruby/simple/Dockerfile b/examples/language-sdk-instrumentation/ruby/simple/Dockerfile index 0631d0b584..f52d05600d 100644 --- a/examples/language-sdk-instrumentation/ruby/simple/Dockerfile +++ b/examples/language-sdk-instrumentation/ruby/simple/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.2.2 +FROM ruby:3.3.9 WORKDIR /usr/src/app @@ -6,9 +6,9 @@ RUN adduser --disabled-password --gecos --quiet pyroscope USER pyroscope COPY --from=pyroscope/pyroscope:latest /usr/bin/pyroscope /usr/bin/pyroscope -COPY main.rb ./main.rb -COPY Gemfile ./Gemfile -COPY Gemfile.lock ./Gemfile.lock +COPY --chown=pyroscope main.rb ./main.rb +COPY --chown=pyroscope Gemfile ./Gemfile +COPY --chown=pyroscope Gemfile.lock ./Gemfile.lock ENV PYROSCOPE_APPLICATION_NAME=simple.ruby.app ENV PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040/ diff --git a/examples/language-sdk-instrumentation/ruby/simple/Gemfile b/examples/language-sdk-instrumentation/ruby/simple/Gemfile index 4266da763e..dad13bff00 100644 --- a/examples/language-sdk-instrumentation/ruby/simple/Gemfile +++ b/examples/language-sdk-instrumentation/ruby/simple/Gemfile @@ -1,3 +1,3 @@ source 'https://rubygems.org' -gem 'pyroscope', '= 0.5.11' +gem 'pyroscope', '= 1.0.1' diff --git a/examples/language-sdk-instrumentation/ruby/simple/Gemfile.lock b/examples/language-sdk-instrumentation/ruby/simple/Gemfile.lock index 690fcafcbb..07fe543d77 100644 --- a/examples/language-sdk-instrumentation/ruby/simple/Gemfile.lock +++ b/examples/language-sdk-instrumentation/ruby/simple/Gemfile.lock @@ -1,12 +1,14 @@ GEM remote: https://rubygems.org/ specs: - ffi (1.16.3) - pyroscope (0.5.11-aarch64-linux) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + pyroscope (1.0.1-aarch64-linux) ffi - pyroscope (0.5.11-arm64-darwin) + pyroscope (1.0.1-arm64-darwin) ffi - pyroscope (0.5.11-x86_64-linux) + pyroscope (1.0.1-x86_64-linux) ffi PLATFORMS @@ -15,7 +17,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - pyroscope (= 0.5.11) + pyroscope (= 1.0.1) BUNDLED WITH - 2.4.10 + 2.5.22 diff --git a/examples/language-sdk-instrumentation/ruby/simple/README.md b/examples/language-sdk-instrumentation/ruby/simple/README.md new file mode 100644 index 0000000000..34e55184ab --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/simple/README.md @@ -0,0 +1,16 @@ +# Basic Example + +To run the example run the following commands: +``` +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +# Run the example project: +docker compose up --build + +# Reset the database (if needed): +docker compose down +``` + +Navigate to [Grafana](http://localhost:3000/a/grafana-pyroscope-app/explore?explorationType=flame-graph&var-serviceName=test.ruby.app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds) to explore profiles. diff --git a/examples/language-sdk-instrumentation/ruby/simple/docker-compose.yml b/examples/language-sdk-instrumentation/ruby/simple/docker-compose.yml index c5662aec98..c7d68d9107 100644 --- a/examples/language-sdk-instrumentation/ruby/simple/docker-compose.yml +++ b/examples/language-sdk-instrumentation/ruby/simple/docker-compose.yml @@ -1,10 +1,23 @@ ---- -version: '3.9' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 app: build: . + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/ruby/simple/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/ruby/simple/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/ruby/simple/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/rust/README.md b/examples/language-sdk-instrumentation/rust/README.md index 9583f872ab..17e45adf28 100644 --- a/examples/language-sdk-instrumentation/rust/README.md +++ b/examples/language-sdk-instrumentation/rust/README.md @@ -1,2 +1,148 @@ ## Continuous Profiling for Rust applications + ### Profiling a Rust Rideshare App with Pyroscope + +![Image](https://github.com/user-attachments/assets/9a6e50a1-b8df-4923-9632-79ace3fea216) + +> [!NOTE] +> For documentation on Pyroscope's Rust integration, refer to the [Rust push mode](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/rust/) documentation. + +## Background + +This example shows a simplified, basic use case of Pyroscope that uses a "ride share" company which has three +endpoints found in `main.rs`: + +- `/bike` : calls the `order_bike(search_radius)` function to order a bike +- `/car` : calls the `order_car(search_radius)` function to order a car +- `/scooter` : calls the `order_scooter(search_radius)` function to order a scooter + +The example also simulates running 3 distinct servers in 3 different regions ( +via [docker-compose.yml](https://github.com/grafana/pyroscope/blob/main/examples/language-sdk-instrumentation/rust/rideshare/docker-compose.yml)): + +- us-east +- eu-north +- ap-south + +Pyroscope lets you tag your data in a way that is meaningful to you. In +this case, there are two natural divisions, and so data is "tagged" to represent them: + +- `region`: statically tags the region of the server running the code +- `vehicle`: dynamically tags the endpoint (similar to how one might tag a controller) + +## Tagging static region + +Tagging something static, like the `region`, can be done using `PyroscopeAgentBuilder#tags` method in the initialization +code in the `main` function: + +```rust +let agent = PyroscopeAgent::builder(server_address, app_name.to_owned()) + .backend(pprof_backend(PprofConfig::new().sample_rate(100))) + .tags(vec![("region", ®ion)]) + .build()?; +``` + +## Tagging dynamically within functions + +Tagging something more dynamically can be done using `PyroscopeAgent#tag_wrapper`. For example, you'd use code like this for the `vehicle` tag: + +```rust +let (add_tag, remove_tag) = agent_running.tag_wrapper(); +let add = Arc::new(add_tag); +let remove = Arc::new(remove_tag); +let car = warp::path("car").map(move || { + add("vehicle".to_string(), "car".to_string()); + order_car(3); + remove("vehicle".to_string(), "car".to_string()); + "Car ordered" +}); +``` + +This block does the following: + +1. Add the label `vehicle=car` +2. Execute the `order_car` function +3. Remove the label `vehicle=car` + +## Resulting flame graph / performance results from the example + +### Running the example + +To run the example, use the following commands: + +``` +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +# Run the example project: +docker-compose up --build + +# Reset the database (if needed): +# docker-compose down +``` + +This example runs all the code mentioned above and also sends some mock-load to the 3 servers as well as +their respective 3 endpoints. If you select `rust-ride-sharing-app` from the dropdown, you should see a +flame graph that looks like this (below). Wait 20-30 seconds for the flame graph to update, and then click the +refresh button to see 3 functions at the bottom of the flame graph taking CPU `resources _proportional` to the `size_` +of their respective `search_radius` parameters. + +[//]: # (http://localhost:3000/a/grafana-pyroscope-app/explore?searchText=&panelType=time-series&layout=grid&hideNoData=off&explorationType=flame-graph&var-serviceName=rust-ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds&var-dataSource=local-pyroscope&var-groupBy=all&var-filters=&maxNodes=16384&from=now-5m&to=now&var-filtersBaseline=&var-filtersComparison=) + +## Where's the performance bottleneck? + +![Image](https://github.com/user-attachments/assets/d4b0f85d-cc8d-4058-b019-1c5198849676) + +To analyze a profile outputted from your application, take note of the _largest node_ which is +where your application is spending the most resources. In this case, it happens to be the `order_car` function. + +ThePyroscope package lets you investigate further as to _why_ the `order_car()` +function is problematic. Tagging both `region` and `vehicle` allows us to test two good hypotheses: + +- Something is wrong with the `/car` endpoint code +- Something is wrong with one of our regions + +To analyze this, select one or more tags on the "Labels" page: + +![Image](https://github.com/user-attachments/assets/3e5cb3ac-609e-493a-ae4d-248de150a33b) + +## Narrowing in on the Issue Using Tags + +Since you know there is an issue with the `order_car` function, select that tag. After inspecting +multiple `region` tags, the timeline shows that there is an issue with the `eu-north` region, +where it alternates between high-cpu times and low-cpu times. + +Note that the `mutex_lock()` function is consuming almost 70% of CPU resources during this time period. + +![Image](https://github.com/user-attachments/assets/12fc0912-8b65-4c24-9284-b0aa1eef45ba) + +## Visualizing Diff Between Two Flame graphs + +While the difference _in this case_ is stark enough to see in the comparison view, sometimes the diff between the two +flame graphs is better visualized with them overlayed over each other. Without changing any parameters, you can +select the diff view tab and see the difference represented in a color-coded diff flame graph. + +![Image](https://github.com/user-attachments/assets/97f6e51c-4211-4a0a-8f11-d2ee0402e396) + +### More use cases + +We have been beta testing this feature with several different companies and some of the ways that we've seen companies +tag their performance data: + +- Tagging Kubernetes attributes +- Tagging controllers +- Tagging regions +- Tagging jobs from a queue +- Tagging commits +- Tagging staging / production environments +- Tagging different parts of their testing suites +- Etc... + +### Future Roadmap + +We would love for you to try out this example and see what ways you can adapt this to your Rust application. Continuous +profiling has become an increasingly popular tool for the monitoring and debugging of performance issues (arguably the +fourth pillar of observability). + +We'd love to continue to improve our Rust integrations, and so we would love to hear what features _you would like to +see_. diff --git a/examples/language-sdk-instrumentation/rust/basic/.dockerignore b/examples/language-sdk-instrumentation/rust/basic/.dockerignore new file mode 100644 index 0000000000..9f970225ad --- /dev/null +++ b/examples/language-sdk-instrumentation/rust/basic/.dockerignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/examples/language-sdk-instrumentation/rust/basic/Cargo.lock b/examples/language-sdk-instrumentation/rust/basic/Cargo.lock index 7b9ea0a621..d45fb63bf1 100644 --- a/examples/language-sdk-instrumentation/rust/basic/Cargo.lock +++ b/examples/language-sdk-instrumentation/rust/basic/Cargo.lock @@ -1,21 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ - "gimli", + "gimli 0.32.3", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adler32" @@ -23,56 +23,97 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arrayvec" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "atty" -version = "0.2.14" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "aws-lc-rs" +version = "1.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "aws-lc-sys", + "zeroize", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "aws-lc-sys" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.37.3", "rustc-demangle", + "windows-link", ] [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "basic" version = "0.1.0" dependencies = [ + "pretty_env_logger", "pyroscope", - "pyroscope_pprofrs", ] [[package]] @@ -83,78 +124,76 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytes" -version = "1.5.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.0.90" +version = "1.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "clap" -version = "3.2.25" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_derive", - "clap_lex", - "indexmap 1.9.3", - "once_cell", - "strsim", - "termcolor", - "textwrap", -] +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "clap_derive" -version = "3.2.25" +name = "cmake" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", + "cc", ] [[package]] -name = "clap_lex" -version = "0.2.4" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "os_str_bytes", + "bytes", + "memchr", ] [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -162,28 +201,34 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "cpp_demangle" -version = "0.4.3" +name = "core2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" dependencies = [ - "cfg-if", + "memchr", ] [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] +[[package]] +name = "dary_heap" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04" + [[package]] name = "debugid" version = "0.8.0" @@ -193,42 +238,95 @@ dependencies = [ "uuid", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" -version = "1.10.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "encoding_rs" -version = "0.8.33" +name = "env_logger" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ - "cfg-if", + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fastrand" -version = "2.0.1" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "findshlibs" @@ -243,372 +341,645 @@ dependencies = [ ] [[package]] -name = "fnv" -version = "1.0.7" +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] +[[package]] +name = "framehop" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f54fe4785e899d4d6f43793b151c63c5647240fc630b005509d2614a939f693" +dependencies = [ + "arrayvec", + "cfg-if", + "fallible-iterator", + "gimli 0.33.0", + "macho-unwind-info", + "pe-unwind-info", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-io", + "futures-sink", "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] -name = "h2" -version = "0.3.25" +name = "gimli" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.2.5", - "slab", - "tokio", - "tokio-util", - "tracing", + "stable_deref_trait", ] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "http" -version = "0.2.12" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", + "futures-core", "http", + "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "httpdate" -version = "1.0.3" +name = "humantime" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "0.14.28" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ + "atomic-waker", "bytes", "futures-channel", "futures-core", - "futures-util", - "h2", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", "http", "hyper", + "hyper-util", "rustls", + "rustls-pki-types", "tokio", "tokio-rustls", + "tower-service", ] [[package]] -name = "idna" -version = "0.5.0" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "icu_collections" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "indexmap" -version = "2.2.5" +name = "icu_locale_core" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ - "equivalent", - "hashbrown 0.14.3", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itertools" -version = "0.10.5" +name = "icu_normalizer" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ - "either", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "itoa" -version = "1.0.10" +name = "icu_normalizer_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] -name = "js-sys" -version = "0.3.69" +name = "icu_properties" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ - "wasm-bindgen", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "json" -version = "0.12.4" +name = "icu_properties_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "icu_provider" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] [[package]] -name = "libc" -version = "0.2.153" +name = "id-arena" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] -name = "libflate" -version = "1.4.0" +name = "idna" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "adler32", - "crc32fast", - "libflate_lz77", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "libflate_lz77" -version = "1.2.0" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "rle-decode-fast", + "icu_normalizer", + "icu_properties", ] [[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" +name = "indexmap" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ - "autocfg", - "scopeguard", + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] -name = "log" -version = "0.4.21" +name = "ipnet" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] -name = "memchr" -version = "2.7.1" +name = "iri-string" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] [[package]] -name = "memmap2" -version = "0.9.4" +name = "is-terminal" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ + "hermit-abi", "libc", + "windows-sys 0.61.2", ] [[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ - "adler", + "either", ] [[package]] -name = "mio" -version = "0.8.11" +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", "libc", - "wasi", - "windows-sys 0.48.0", ] [[package]] -name = "names" -version = "0.14.0" +name = "js-sys" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ - "clap", - "rand", + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.184" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" + +[[package]] +name = "libflate" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3248b8d211bd23a104a42d81b4fa8bb8ac4a3b75e7a43d85d2c9ccb6179cd74" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a599cb10a9cd92b1300debcef28da8f70b935ec937f44fcd1b70a7c986a11c5c" +dependencies = [ + "core2", + "hashbrown 0.16.1", + "rle-decode-fast", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "macho-unwind-info" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" +dependencies = [ + "thiserror 2.0.18", + "zerocopy", + "zerocopy-derive", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -624,130 +995,113 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "object" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" +dependencies = [ + "flate2", + "memchr", + "ruzstd", +] [[package]] -name = "os_str_bytes" -version = "6.6.1" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "parking_lot" -version = "0.12.1" +name = "openssl-probe" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] -name = "parking_lot_core" -version = "0.9.9" +name = "pe-unwind-info" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", + "arrayvec", + "bitflags 2.11.0", + "thiserror 2.0.18", + "zerocopy", + "zerocopy-derive", ] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "potential_utf" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pprof" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978385d59daf9269189d052ca8a84c1acfd0715c0599a5d5188d4acc078ca46a" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ - "backtrace", - "cfg-if", - "findshlibs", - "libc", - "log", - "nix", - "once_cell", - "parking_lot", - "smallvec", - "symbolic-demangle", - "tempfile", - "thiserror", + "zerovec", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "pretty_env_logger" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "env_logger", + "log", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "quote", - "version_check", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.11.9" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -755,72 +1109,139 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "pyroscope" -version = "0.5.7" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8a53ce01af1087eaeee6ce7c4fbf50ea4040ab1825c0115c4bafa039644ba9" +checksum = "b6869e0f2cae5cef10281c57d5a260f91372d7f190a7f717eb1a54f643d92151" dependencies = [ - "json", + "aligned-vec", + "backtrace", + "findshlibs", + "framehop", + "lazy_static", "libc", "libflate", "log", - "names", + "memmap2", + "nix", + "object 0.39.1", + "once_cell", "prost", "reqwest", - "thiserror", + "serde_json", + "smallvec", + "spin", + "symbolic-demangle", + "tempfile", + "thiserror 2.0.18", "url", - "winapi", + "uuid", ] [[package]] -name = "pyroscope_pprofrs" -version = "0.2.7" +name = "quinn" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f010b2a981a7f8449a650f25f309e520b5206ea2d89512dcb146aaa5518ff4" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "log", - "pprof", - "pyroscope", - "thiserror", + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" -version = "0.8.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -828,74 +1249,91 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom", + "getrandom 0.3.4", ] [[package]] -name = "redox_syscall" -version = "0.4.1" +name = "regex" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ - "bitflags 1.3.2", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", ] +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + [[package]] name = "reqwest" -version = "0.11.26" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64", "bytes", - "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", + "http-body-util", "hyper", "hyper-rustls", - "ipnet", + "hyper-util", "js-sys", "log", - "mime", - "once_cell", "percent-encoding", "pin-project-lite", + "quinn", "rustls", - "rustls-pemfile", + "rustls-pki-types", + "rustls-platform-verifier", "serde", - "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-rustls", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", - "winreg", ] [[package]] name = "ring" -version = "0.17.8" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.17", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -908,59 +1346,142 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustix" -version = "0.38.31" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.21.10" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ - "log", - "ring", + "aws-lc-rs", + "once_cell", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] -name = "rustls-pemfile" -version = "1.0.4" +name = "rustls-native-certs" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "base64", + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", ] +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ + "aws-lc-rs", "ring", + "rustls-pki-types", "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ruzstd" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" +dependencies = [ + "twox-hash", +] + [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] [[package]] name = "scopeguard" @@ -969,44 +1490,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sct" -version = "0.7.1" +name = "security-framework" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "ring", - "untrusted", + "bitflags 2.11.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" -version = "1.0.197" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] @@ -1021,54 +1573,66 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.6" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "spin" -version = "0.9.8" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "1527984ca054dfca79333baec451042863f485fbee01b7bf6d911de915cac865" +dependencies = [ + "lock_api", +] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] -name = "strsim" -version = "0.10.0" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symbolic-common" -version = "12.8.0" +version = "13.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" +checksum = "0c30da69ccd7ab2780ce5309791f3cd2ef9716262c07a0a29096226d4235a979" dependencies = [ "debugid", "memmap2", @@ -1078,31 +1642,19 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.8.0" +version = "13.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" +checksum = "1245acf80236b4a0d99e9216532102a1670950e79c70b980b607c2040966e83d" dependencies = [ - "cpp_demangle", "rustc-demangle", "symbolic-common", ] [[package]] name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.53" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1111,41 +1663,35 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", + "futures-core", ] [[package]] -name = "system-configuration-sys" -version = "0.5.0" +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "core-foundation-sys", - "libc", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "tempfile" -version = "3.10.1" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.4.2", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1158,36 +1704,60 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.16.1" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] [[package]] name = "thiserror" -version = "1.0.58" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -1200,54 +1770,78 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", "bytes", "libc", "mio", "pin-project-lite", "socket2", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", ] [[package]] -name = "tokio-util" -version = "0.7.10" +name = "tower" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ - "bytes", "futures-core", - "futures-sink", + "futures-util", "pin-project-lite", + "sync_wrapper", "tokio", - "tracing", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", ] +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-core", @@ -1255,9 +1849,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -1269,25 +1863,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "unicode-bidi" -version = "0.3.15" +name = "twox-hash" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] -name = "unicode-normalization" -version = "0.1.23" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -1297,26 +1888,42 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "uuid" -version = "1.8.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] [[package]] -name = "version_check" -version = "0.9.4" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "want" @@ -1329,52 +1936,56 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasm-bindgen" -version = "0.2.92" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "cfg-if", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "bumpalo", - "log", + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +dependencies = [ + "cfg-if", "once_cell", - "proc-macro2", - "quote", - "syn 2.0.53", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" dependencies = [ - "cfg-if", "js-sys", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1382,38 +1993,88 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.53", - "wasm-bindgen-backend", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "webpki-roots" -version = "0.25.4" +name = "webpki-root-certs" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "winapi" @@ -1433,11 +2094,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "winapi", + "windows-sys 0.61.2", ] [[package]] @@ -1446,13 +2107,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.42.2", ] [[package]] @@ -1461,129 +2128,412 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] -name = "winreg" -version = "0.50.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", ] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/examples/language-sdk-instrumentation/rust/basic/Cargo.toml b/examples/language-sdk-instrumentation/rust/basic/Cargo.toml index fcc5e3dcb3..db616f74de 100644 --- a/examples/language-sdk-instrumentation/rust/basic/Cargo.toml +++ b/examples/language-sdk-instrumentation/rust/basic/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -pyroscope = "0.5" -pyroscope_pprofrs = "0.2" +pyroscope = { version = "^2.0.6", features = ["backend-pprof-rs"] } +pretty_env_logger = "0.5" diff --git a/examples/language-sdk-instrumentation/rust/basic/Dockerfile b/examples/language-sdk-instrumentation/rust/basic/Dockerfile new file mode 100644 index 0000000000..6f524fd252 --- /dev/null +++ b/examples/language-sdk-instrumentation/rust/basic/Dockerfile @@ -0,0 +1,8 @@ +FROM rust:latest + +WORKDIR /usr/src/server +COPY src src +COPY Cargo.toml Cargo.lock ./ +RUN cargo install --profile release --path . +EXPOSE 5000 +CMD ["basic"] diff --git a/examples/language-sdk-instrumentation/rust/basic/README.md b/examples/language-sdk-instrumentation/rust/basic/README.md new file mode 100644 index 0000000000..3b3ef7dde6 --- /dev/null +++ b/examples/language-sdk-instrumentation/rust/basic/README.md @@ -0,0 +1,19 @@ +## Rust Example + +To run the basic example run the following commands: +``` +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +# Run the example project: +docker compose up --build + +# Reset the database (if needed): +# docker compose down +``` + +Example output: + +![Image](https://github.com/user-attachments/assets/65c3000f-3170-4d41-94d4-257413f1f54d) +![Image](https://github.com/user-attachments/assets/d9948c21-ab74-4e7c-aef4-ac376751a51f) diff --git a/examples/language-sdk-instrumentation/rust/basic/docker-compose.yml b/examples/language-sdk-instrumentation/rust/basic/docker-compose.yml new file mode 100644 index 0000000000..5de5d3666e --- /dev/null +++ b/examples/language-sdk-instrumentation/rust/basic/docker-compose.yml @@ -0,0 +1,24 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + basic: + build: + context: . + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/rust/basic/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/rust/basic/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/rust/basic/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/rust/basic/src/main.rs b/examples/language-sdk-instrumentation/rust/basic/src/main.rs index 86981dbe7d..98cb4e57b5 100644 --- a/examples/language-sdk-instrumentation/rust/basic/src/main.rs +++ b/examples/language-sdk-instrumentation/rust/basic/src/main.rs @@ -1,37 +1,37 @@ -use pyroscope::PyroscopeAgent; -use pyroscope_pprofrs::{pprof_backend, PprofConfig}; +use pyroscope::pyroscope::PyroscopeAgentBuilder; +use pyroscope::backend::{pprof_backend, BackendConfig, PprofConfig}; fn main() -> Result<(), Box> { - // Create Pyroscope Agent - let agent = PyroscopeAgent::builder("http://localhost:4040", "rust-app") - .backend(pprof_backend(PprofConfig::new().sample_rate(100))) - .tags(vec![("Hostname", "pyroscope")]) - .build()?; + std::env::set_var("RUST_LOG", "debug"); + pretty_env_logger::init_timed(); + + let agent = PyroscopeAgentBuilder::new( + "http://pyroscope:4040", + "rust-app", + 100, + "pyroscope-rs", + env!("CARGO_PKG_VERSION"), + pprof_backend(PprofConfig::default(), BackendConfig::default()), + ) + .tags(vec![("Hostname", "pyroscope")]) + .build()?; - // Start Agent let agent_running = agent.start()?; let (add_tag, _remove_tag) = agent_running.tag_wrapper(); - // Add tag add_tag("Batch".to_string(), "first".to_string())?; - // Do some work for first batch. mutex_lock(2); - // Change Tag add_tag("Batch".to_string(), "second".to_string())?; - // Do some work for second batch. mutex_lock(5); - // Change Tag add_tag("Batch".to_string(), "third".to_string())?; - // Do some work for third batch. mutex_lock(12); - // Stop Agent let agent_ready = agent_running.stop()?; agent_ready.shutdown(); diff --git a/examples/language-sdk-instrumentation/rust/rideshare/.dockerignore b/examples/language-sdk-instrumentation/rust/rideshare/.dockerignore new file mode 100644 index 0000000000..50043eb9ad --- /dev/null +++ b/examples/language-sdk-instrumentation/rust/rideshare/.dockerignore @@ -0,0 +1 @@ +server/target/ diff --git a/examples/language-sdk-instrumentation/rust/rideshare/Dockerfile b/examples/language-sdk-instrumentation/rust/rideshare/Dockerfile index 8739618ee4..175649c7f7 100644 --- a/examples/language-sdk-instrumentation/rust/rideshare/Dockerfile +++ b/examples/language-sdk-instrumentation/rust/rideshare/Dockerfile @@ -1,7 +1,21 @@ -FROM rust:latest +FROM rust:latest as deps WORKDIR /usr/src/server -COPY server/ . +# Copy only files needed for dependency resolution +COPY server/Cargo.toml server/Cargo.lock ./ +# Create a dummy main.rs to compile dependencies +RUN mkdir src && \ + echo "fn main() {}" > src/main.rs && \ + cargo build --release && \ + rm -rf src + +FROM deps as builder +# Now copy the actual source code +COPY server/src ./src +# Build the application RUN cargo install --profile release --path . + +FROM rust:slim as runtime +COPY --from=builder /usr/local/cargo/bin/server /usr/local/bin/server EXPOSE 5000 CMD ["server"] diff --git a/examples/language-sdk-instrumentation/rust/rideshare/README.md b/examples/language-sdk-instrumentation/rust/rideshare/README.md index ab2b42fce4..bb9db8d1c3 100644 --- a/examples/language-sdk-instrumentation/rust/rideshare/README.md +++ b/examples/language-sdk-instrumentation/rust/rideshare/README.md @@ -1,17 +1,20 @@ ## Rust Example -To run the example run the following commands: -``` -# Pull latest pyroscope image: +To run the rideshare example run the following commands: +```shell +# Pull latest pyroscope and grafana images: docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest # Run the example project: -docker-compose up --build +docker compose up --build # Reset the database (if needed): -# docker-compose down +# docker compose down ``` Example output: -image +![Image](https://github.com/user-attachments/assets/0c402f72-3936-4c27-a22e-9b7af456fb21) +![Image](https://github.com/user-attachments/assets/b5f51af8-57d6-4dd6-b98e-44f5162d2ca2) + diff --git a/examples/language-sdk-instrumentation/rust/rideshare/docker-compose.yml b/examples/language-sdk-instrumentation/rust/rideshare/docker-compose.yml index 7915c3b2bc..362b1155b9 100644 --- a/examples/language-sdk-instrumentation/rust/rideshare/docker-compose.yml +++ b/examples/language-sdk-instrumentation/rust/rideshare/docker-compose.yml @@ -1,39 +1,49 @@ -version: '3' services: pyroscope: - image: grafana/pyroscope + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest ports: - - '4040:4040' - + - 4040:4040 us-east: ports: - - 5000 + - 5000 environment: - - REGION=us-east - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - REGION=us-east + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 build: context: . - eu-north: ports: - - 5000 + - 5000 environment: - - REGION=eu-north - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 - + - REGION=eu-north + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 build: context: . - ap-south: ports: - - 5000 + - 5000 environment: - - REGION=ap-south - - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 + - REGION=ap-south + - PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 build: context: . - load-generator: build: context: . dockerfile: Dockerfile.load-generator + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 diff --git a/examples/language-sdk-instrumentation/rust/rideshare/grafana-provisioning/datasources/pyroscope.yml b/examples/language-sdk-instrumentation/rust/rideshare/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/language-sdk-instrumentation/rust/rideshare/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/language-sdk-instrumentation/rust/rideshare/load-generator.py b/examples/language-sdk-instrumentation/rust/rideshare/load-generator.py index ffe96e6a68..536453aacd 100644 --- a/examples/language-sdk-instrumentation/rust/rideshare/load-generator.py +++ b/examples/language-sdk-instrumentation/rust/rideshare/load-generator.py @@ -1,6 +1,7 @@ import random import requests import time +import threading HOSTS = [ 'us-east', @@ -14,18 +15,44 @@ 'car', ] -if __name__ == "__main__": - print(f"starting load generator") - time.sleep(3) +def generate_load(host, vehicle): while True: - host = HOSTS[random.randint(0, len(HOSTS) - 1)] - vehicle = VEHICLES[random.randint(0, len(VEHICLES) - 1)] + start_time = time.time() print(f"requesting {vehicle} from {host}") + try: resp = requests.get(f'http://{host}:5000/{vehicle}') resp.raise_for_status() - print(f"received {resp}") + duration = time.time() - start_time + print(f"received {resp} in {duration:.2f}s from {host}/{vehicle}") + + # Sleep to complete the 4-second cycle + sleep_time = max(4 - duration, 0) + if sleep_time > 0: + time.sleep(sleep_time) + except BaseException as e: - print (f"http error {e}") + print(f"http error for {host}/{vehicle}: {e}") + # On error, still maintain the 10-second cycle + time.sleep(4) - time.sleep(random.uniform(0.2, 0.4)) +if __name__ == "__main__": + print(f"starting load generator with thread per region-vehicle combination") + time.sleep(3) + + threads = [] + # Create one thread per host-vehicle combination + for host in HOSTS: + for vehicle in VEHICLES: + thread = threading.Thread(target=generate_load, args=(host, vehicle)) + thread.daemon = True + threads.append(thread) + thread.start() + print(f"Started thread for {host}/{vehicle}") + + # Keep the main thread running + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + print("Shutting down load generator") diff --git a/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.lock b/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.lock index a839e4b59b..0fedfe6ed9 100644 --- a/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.lock +++ b/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.lock @@ -1,21 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ - "gimli", + "gimli 0.32.3", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adler32" @@ -25,18 +25,27 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] -name = "android-tzdata" -version = "0.1.1" +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android_system_properties" @@ -49,40 +58,63 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "atty" -version = "0.2.14" +name = "aws-lc-rs" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "aws-lc-sys", + "zeroize", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "aws-lc-sys" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.37.3", "rustc-demangle", + "windows-link", ] [[package]] @@ -91,6 +123,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -99,9 +137,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -114,9 +152,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "byteorder" @@ -126,80 +164,77 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.0.90" +version = "1.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.4", -] - -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_derive", - "clap_lex", - "indexmap 1.9.3", - "once_cell", - "strsim", - "termcolor", - "textwrap", + "windows-link", ] [[package]] -name = "clap_derive" -version = "3.2.25" +name = "cmake" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", + "cc", ] [[package]] -name = "clap_lex" -version = "0.2.4" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "os_str_bytes", + "bytes", + "memchr", ] [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -207,52 +242,58 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "cpp_demangle" -version = "0.4.3" +name = "core2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" dependencies = [ - "cfg-if", + "memchr", ] [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", ] +[[package]] +name = "dary_heap" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04" + [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "debugid" @@ -273,55 +314,104 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" -version = "1.10.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "env_logger" -version = "0.7.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ - "atty", "humantime", + "is-terminal", "log", "regex", "termcolor", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fastrand" -version = "2.0.1" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "findshlibs" @@ -335,26 +425,68 @@ dependencies = [ "winapi", ] +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] +[[package]] +name = "framehop" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f54fe4785e899d4d6f43793b151c63c5647240fc630b005509d2614a939f693" +dependencies = [ + "arrayvec", + "cfg-if", + "fallible-iterator", + "gimli 0.33.0", + "macho-unwind-info", + "pe-unwind-info", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -362,33 +494,33 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-io", @@ -396,7 +528,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -412,34 +543,72 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "gimli" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" +dependencies = [ + "stable_deref_trait", +] [[package]] name = "h2" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http", - "indexmap 2.2.5", + "http 0.2.12", + "indexmap", "slab", "tokio", "tokio-util", @@ -448,15 +617,23 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "headers" @@ -464,10 +641,10 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "headers-core", - "http", + "http 0.2.12", "httpdate", "mime", "sha1", @@ -479,29 +656,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.12", ] [[package]] name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "http" @@ -514,6 +682,16 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -521,15 +699,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.4.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -539,61 +740,104 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "1.3.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", - "http", - "hyper", + "http 1.4.0", + "hyper 1.9.0", + "hyper-util", "rustls", + "rustls-pki-types", "tokio", "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.9.0", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.3", + "tokio", + "tower-service", + "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -608,136 +852,331 @@ dependencies = [ ] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_collections" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "icu_locale_core" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "indexmap" -version = "2.2.5" +name = "icu_normalizer" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ - "equivalent", - "hashbrown 0.14.3", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "ipnet" -version = "2.9.0" +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] [[package]] name = "itertools" -version = "0.10.5" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ + "cfg-if", + "futures-util", + "once_cell", "wasm-bindgen", ] [[package]] -name = "json" -version = "0.12.4" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libflate" -version = "1.4.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18" +checksum = "e3248b8d211bd23a104a42d81b4fa8bb8ac4a3b75e7a43d85d2c9ccb6179cd74" dependencies = [ "adler32", + "core2", "crc32fast", + "dary_heap", "libflate_lz77", ] [[package]] name = "libflate_lz77" -version = "1.2.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf" +checksum = "a599cb10a9cd92b1300debcef28da8f70b935ec937f44fcd1b70a7c986a11c5c" dependencies = [ + "core2", + "hashbrown 0.16.1", "rle-decode-fast", ] [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.21" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "macho-unwind-info" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" +dependencies = [ + "thiserror 2.0.18", + "zerocopy", + "zerocopy-derive", +] [[package]] name = "memchr" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] @@ -750,9 +1189,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -760,22 +1199,23 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -787,25 +1227,15 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.12", "httparse", "log", "memchr", "mime", - "spin", + "spin 0.9.8", "version_check", ] -[[package]] -name = "names" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" -dependencies = [ - "clap", - "rand", -] - [[package]] name = "nix" version = "0.26.4" @@ -819,49 +1249,50 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] -name = "num_cpus" -version = "1.16.0" +name = "object" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ - "hermit-abi 0.3.9", - "libc", + "memchr", ] [[package]] name = "object" -version = "0.32.2" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" dependencies = [ + "flate2", "memchr", + "ruzstd", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "os_str_bytes" -version = "6.6.1" +name = "openssl-probe" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -869,129 +1300,114 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-link", +] + +[[package]] +name = "pe-unwind-info" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97f6fccfd2d9d2df765ca23ff85fe5cc437fb0e6d3e164e4d3cbe09d14780c93" +dependencies = [ + "arrayvec", + "bitflags 2.11.0", + "thiserror 2.0.18", + "zerocopy", + "zerocopy-derive", ] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn", ] [[package]] name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] -name = "pprof" -version = "0.12.1" +name = "potential_utf" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978385d59daf9269189d052ca8a84c1acfd0715c0599a5d5188d4acc078ca46a" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ - "backtrace", - "cfg-if", - "findshlibs", - "libc", - "log", - "nix", - "once_cell", - "parking_lot", - "smallvec", - "symbolic-demangle", - "tempfile", - "thiserror", + "zerovec", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "pretty_env_logger" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ "env_logger", "log", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "quote", - "version_check", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.11.9" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -999,62 +1415,124 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "pyroscope" -version = "0.5.7" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8a53ce01af1087eaeee6ce7c4fbf50ea4040ab1825c0115c4bafa039644ba9" +checksum = "b6869e0f2cae5cef10281c57d5a260f91372d7f190a7f717eb1a54f643d92151" dependencies = [ - "json", + "aligned-vec", + "backtrace", + "findshlibs", + "framehop", + "lazy_static", "libc", "libflate", "log", - "names", + "memmap2", + "nix", + "object 0.39.1", + "once_cell", "prost", "reqwest", - "thiserror", + "serde_json", + "smallvec", + "spin 0.12.0", + "symbolic-demangle", + "tempfile", + "thiserror 2.0.18", "url", - "winapi", + "uuid", ] [[package]] -name = "pyroscope_pprofrs" -version = "0.2.7" +name = "quinn" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f010b2a981a7f8449a650f25f309e520b5206ea2d89512dcb146aaa5518ff4" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "log", - "pprof", - "pyroscope", - "thiserror", + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.6.3", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "quinn-udp" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.3", + "tracing", + "windows-sys 0.60.2", +] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -1062,8 +1540,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] @@ -1073,7 +1561,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", ] [[package]] @@ -1082,23 +1580,32 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.11.0", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1108,9 +1615,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1119,62 +1626,59 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "reqwest" -version = "0.11.26" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ - "base64", + "base64 0.22.1", "bytes", - "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.9.0", "hyper-rustls", - "ipnet", + "hyper-util", "js-sys", "log", - "mime", - "once_cell", "percent-encoding", "pin-project-lite", + "quinn", "rustls", - "rustls-pemfile", + "rustls-pki-types", + "rustls-platform-verifier", "serde", - "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-rustls", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", - "winreg", ] [[package]] name = "ring" -version = "0.17.8" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.17", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -1187,59 +1691,142 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustc-hash" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustix" -version = "0.38.31" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.21.10" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ - "log", - "ring", + "aws-lc-rs", + "once_cell", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] -name = "rustls-pemfile" -version = "1.0.4" +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "base64", + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", ] +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ + "aws-lc-rs", "ring", + "rustls-pki-types", "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ruzstd" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" +dependencies = [ + "twox-hash", +] + [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] [[package]] name = "scoped-tls" @@ -1254,44 +1841,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sct" -version = "0.7.1" +name = "security-framework" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "ring", - "untrusted", + "bitflags 2.11.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" -version = "1.0.197" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] @@ -1314,7 +1932,6 @@ dependencies = [ "log", "pretty_env_logger", "pyroscope", - "pyroscope_pprofrs", "tokio", "warp", ] @@ -1330,63 +1947,92 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spin" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1527984ca054dfca79333baec451042863f485fbee01b7bf6d911de915cac865" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] -name = "strsim" -version = "0.10.0" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symbolic-common" -version = "12.8.0" +version = "13.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" +checksum = "0c30da69ccd7ab2780ce5309791f3cd2ef9716262c07a0a29096226d4235a979" dependencies = [ "debugid", "memmap2", @@ -1396,31 +2042,19 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.8.0" +version = "13.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" +checksum = "1245acf80236b4a0d99e9216532102a1670950e79c70b980b607c2040966e83d" dependencies = [ - "cpp_demangle", "rustc-demangle", "symbolic-common", ] [[package]] name = "syn" -version = "1.0.109" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1429,41 +2063,35 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", + "futures-core", ] [[package]] -name = "system-configuration-sys" -version = "0.5.0" +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "core-foundation-sys", - "libc", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "tempfile" -version = "3.10.1" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.4.2", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1476,36 +2104,60 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.16.1" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] [[package]] name = "thiserror" -version = "1.0.58" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -1518,92 +2170,117 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.6.3", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn", ] [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", ] [[package]] -name = "tokio-stream" -version = "0.1.15" +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ + "bytes", "futures-core", + "futures-sink", "pin-project-lite", "tokio", ] [[package]] -name = "tokio-tungstenite" -version = "0.20.1" +name = "tower" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ + "futures-core", "futures-util", - "log", + "pin-project-lite", + "sync_wrapper", "tokio", - "tungstenite", + "tower-layer", + "tower-service", ] [[package]] -name = "tokio-util" -version = "0.7.10" +name = "tower-http" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ + "bitflags 2.11.0", "bytes", - "futures-core", - "futures-sink", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "iri-string", "pin-project-lite", - "tokio", - "tracing", + "tower", + "tower-layer", + "tower-service", ] +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -1612,9 +2289,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -1627,58 +2304,52 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 1.4.0", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", ] [[package]] -name = "typenum" -version = "1.17.0" +name = "twox-hash" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" [[package]] -name = "unicase" -version = "2.7.0" +name = "typenum" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] -name = "unicode-bidi" -version = "0.3.15" +name = "unicase" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] -name = "unicode-normalization" -version = "0.1.23" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -1688,13 +2359,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -1703,17 +2375,38 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "uuid" -version = "1.8.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "want" @@ -1726,29 +2419,27 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" dependencies = [ "bytes", "futures-channel", "futures-util", "headers", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.32", "log", "mime", "mime_guess", "multer", "percent-encoding", "pin-project", - "rustls-pemfile", "scoped-tls", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-stream", "tokio-tungstenite", "tokio-util", "tower-service", @@ -1757,52 +2448,56 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasm-bindgen" -version = "0.2.92" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "cfg-if", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "bumpalo", - "log", + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +dependencies = [ + "cfg-if", "once_cell", - "proc-macro2", - "quote", - "syn 2.0.53", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" dependencies = [ - "cfg-if", "js-sys", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1810,38 +2505,88 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.53", - "wasm-bindgen-backend", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "webpki-roots" -version = "0.25.4" +name = "webpki-root-certs" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "winapi" @@ -1861,11 +2606,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "winapi", + "windows-sys 0.61.2", ] [[package]] @@ -1876,20 +2621,70 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-targets 0.52.4", + "windows-link", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.42.2", ] [[package]] @@ -1898,129 +2693,412 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] -name = "winreg" -version = "0.50.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", ] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.toml b/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.toml index 514d500a55..6b0b5c8166 100644 --- a/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.toml +++ b/examples/language-sdk-instrumentation/rust/rideshare/server/Cargo.toml @@ -16,8 +16,7 @@ codegen-units = 4 [dependencies] tokio = { version = "1", features = ["full"] } warp = "0.3" -pyroscope = "0.5" -pyroscope_pprofrs = "0.2" +pyroscope = { version = "^2.0.6", features = ["backend-pprof-rs"] } log = "0.4" -pretty_env_logger = "0.4" +pretty_env_logger = "0.5" chrono = "0.4" diff --git a/examples/language-sdk-instrumentation/rust/rideshare/server/src/main.rs b/examples/language-sdk-instrumentation/rust/rideshare/server/src/main.rs index 97a06a047a..970e8930e9 100644 --- a/examples/language-sdk-instrumentation/rust/rideshare/server/src/main.rs +++ b/examples/language-sdk-instrumentation/rust/rideshare/server/src/main.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use chrono::prelude::*; -use pyroscope::PyroscopeAgent; -use pyroscope_pprofrs::{pprof_backend, PprofConfig}; +use pyroscope::backend::{pprof_backend, BackendConfig, PprofConfig}; +use pyroscope::pyroscope::PyroscopeAgentBuilder; use warp::Filter; // Vehicle enum @@ -15,16 +15,12 @@ enum Vehicle { #[tokio::main] async fn main() -> Result<(), Box> { - // Force rustc to display the log messages in the console. std::env::set_var("RUST_LOG", "trace"); - // Initialize the logger. - pretty_env_logger::init_timed(); // Get Pyroscope server address from environment variable. + pretty_env_logger::init_timed(); - // Get Pyroscope server address from environment variable. let server_address = std::env::var("PYROSCOPE_SERVER_ADDRESS") .unwrap_or_else(|_| "http://localhost:4040".to_string()); - // Get Region from environment variable. let region = std::env::var("REGION").unwrap_or_else(|_| "us-east".to_string()); let app_name = std::env::var("PYROSCOPE_APPLICATION_NAME") @@ -36,15 +32,19 @@ async fn main() -> Result<(), Box> { let auth_password = std::env::var("PYROSCOPE_BASIC_AUTH_PASSWORD") .unwrap_or_else(|_| "".to_string()); - // Configure Pyroscope client. - let agent = PyroscopeAgent::builder(server_address, app_name.to_owned()) - .basic_auth(auth_user, auth_password) - .backend(pprof_backend(PprofConfig::new().sample_rate(100))) - .tags(vec![("region", ®ion)]) - .build() - .unwrap(); + let agent = PyroscopeAgentBuilder::new( + server_address, + app_name, + 100, + "pyroscope-rs", + env!("CARGO_PKG_VERSION"), + pprof_backend(PprofConfig::default(), BackendConfig::default()), + ) + .basic_auth(auth_user, auth_password) + .tags(vec![("region", ®ion)]) + .build() + .unwrap(); - // Start the Pyroscope client. let agent_running = agent.start()?; // Root Route @@ -61,7 +61,6 @@ async fn main() -> Result<(), Box> { let add = Arc::new(add_tag); let remove = Arc::new(remove_tag); - // Bike Route let bike = warp::path("bike").map(move || { add("vehicle".to_string(), "bike".to_string()); order_bike(1); @@ -74,7 +73,6 @@ async fn main() -> Result<(), Box> { let add = Arc::new(add_tag); let remove = Arc::new(remove_tag); - // Scooter Route let scooter = warp::path("scooter").map(move || { add("vehicle".to_string(), "scooter".to_string()); order_scooter(2); @@ -87,7 +85,6 @@ async fn main() -> Result<(), Box> { let add = Arc::new(add_tag); let remove = Arc::new(remove_tag); - // Car Route let car = warp::path("car").map(move || { add("vehicle".to_string(), "car".to_string()); order_car(3); @@ -96,16 +93,12 @@ async fn main() -> Result<(), Box> { "Car ordered" }); - // Create a routes filter. let routes = warp::get().and(root).or(bike).or(scooter).or(car); - // Serve the routes. warp::serve(routes).run(([0, 0, 0, 0], 5000)).await; - // Stop the Pyroscope client. let agent_ready = agent_running.stop()?; - // Shutdown PyroscopeAgent agent_ready.shutdown(); Ok(()) @@ -127,7 +120,7 @@ fn find_nearest_vehicle(search_radius: u64, vehicle: Vehicle) { let mut _i: u64 = 0; let start_time = std::time::Instant::now(); - while start_time.elapsed().as_secs() < search_radius { + while start_time.elapsed().as_millis() < u128::from(search_radius * 200) { _i += 1; } @@ -140,7 +133,7 @@ fn check_driver_availability(search_radius: u64) { let mut _i: u64 = 0; let start_time = std::time::Instant::now(); - while start_time.elapsed().as_secs() < (search_radius / 2) { + while start_time.elapsed().as_millis() < u128::from(search_radius * 200) { _i += 1; } // Every 4 minutes this will artificially create make requests in eu-north region slow @@ -148,7 +141,7 @@ fn check_driver_availability(search_radius: u64) { // flamegraph let time_minutes = Local::now().minute(); if std::env::var("REGION").unwrap_or_else(|_| "eu-north".to_owned()) == "eu-north" - && (time_minutes * 8 % 4 == 0) + && (time_minutes % 4 == 0) { mutex_lock(search_radius); } @@ -158,7 +151,7 @@ fn mutex_lock(search_radius: u64) { let mut _i: u64 = 0; let start_time = std::time::Instant::now(); - while start_time.elapsed().as_secs() < (search_radius * 10) { + while start_time.elapsed().as_millis() < u128::from(search_radius * 4000) { _i += 1; } } diff --git a/examples/otel-collector/ebpf/README.md b/examples/otel-collector/ebpf/README.md new file mode 100644 index 0000000000..d72a38813c --- /dev/null +++ b/examples/otel-collector/ebpf/README.md @@ -0,0 +1,84 @@ +# OpenTelemetry eBPF Profiler with Pyroscope + +This example demonstrates system-wide continuous profiling using the [OpenTelemetry eBPF profiler](https://github.com/open-telemetry/opentelemetry-ebpf-profiler), with profiles exported to [Pyroscope](https://github.com/grafana/pyroscope) and visualized in Grafana. + +**Linux only (amd64/arm64).** The eBPF profiler requires the Linux kernel and privileged access to system resources (`/proc`, `/sys/kernel`, cgroups). + +## Architecture + +```mermaid +flowchart LR + A["OTel eBPF Profiler
collects CPU profiles
system-wide via eBPF
"] -- "OTLP gRPC" --> B["Pyroscope
stores & aggregates
profiling data
"] + B -- query --> C["Grafana
visualize as
flamegraphs
"] +``` + +The profiler runs with host PID namespace access and collects CPU profiles at 97 samples/second from all processes on the host. Profiles are sent to Pyroscope via OTLP gRPC, where `process.executable.name` is relabeled to `service_name`. + +## Docker Compose + +### Prerequisites + +- Docker with Compose v2 +- Linux host (amd64 or arm64) + +### Run + +```bash +cd docker +docker compose up +``` + +Services: +- **Grafana**: http://localhost:3000 (anonymous auth, no login required) +- **Pyroscope**: http://localhost:4040 + +To stop: +```bash +docker compose down +``` + +## Kubernetes + +### Prerequisites + +- A Kubernetes cluster (e.g., minikube, kind) +- `kubectl` with kustomize support + +### Deploy + +```bash +kubectl apply -k kubernetes/ +``` + +This deploys: +- **otel-ebpf-profiler** DaemonSet -- runs the profiler on every node (privileged, hostPID) +- **pyroscope** Deployment + Service -- stores profiling data +- **grafana** Deployment + Service -- visualizes profiles (pre-configured with Pyroscope datasource) +- **cpu-stress** Deployment -- sample workload to generate visible profiles +- RBAC resources for the profiler's Kubernetes metadata enrichment + +### Access + +```bash +kubectl port-forward svc/grafana 3000:3000 +``` + +Then open http://localhost:3000. + +### Clean up + +```bash +kubectl delete -k kubernetes/ +``` + +## Configuration + +| File | Description | +|------|-------------| +| `docker/config/ebpf-profiler-config.yaml` | OTel Collector config for Docker (profiling receiver, OTLP exporter) | +| `docker/config/pyroscope.yaml` | Pyroscope config with `process.executable.name` -> `service_name` relabeling | +| `kubernetes/config/ebpf-profiler-config.yaml` | OTel Collector config for Kubernetes (adds k8sattributes processor for pod metadata) | + +## Example output + +![Profiles in Grafana](https://github.com/user-attachments/assets/15ff58d4-218a-43dd-9835-df12e13ced3f) diff --git a/examples/otel-collector/ebpf/docker/config/ebpf-profiler-config.yaml b/examples/otel-collector/ebpf/docker/config/ebpf-profiler-config.yaml new file mode 100644 index 0000000000..3d3c12143c --- /dev/null +++ b/examples/otel-collector/ebpf/docker/config/ebpf-profiler-config.yaml @@ -0,0 +1,58 @@ +receivers: + profiling: + samples_per_second: 97 + +processors: + # This is abusing the k8s_attributes processor for getting access to docker metadata using a docker shim + k8s_attributes/docker-shim: + auth_type: kubeConfig + extract: + metadata: + - container.id + - container.image.name + - container.image.tag + - k8s.pod.name # This is actually the container name + - k8s.pod.ip # This is actually the container ip + labels: + - tag_name: docker.compose.project + key: com.docker.compose.project + from: pod + - tag_name: docker.compose.service + key: com.docker.compose.service + from: pod + # Associate by container ID for multi-container pods + pod_association: + - sources: + - from: resource_attribute + name: container.id + resource/docker-shim: + attributes: + - key: container.ip + from_attribute: k8s.pod.ip + action: insert + - key: k8s.pod.ip + action: delete + - key: container.name + from_attribute: k8s.pod.name + action: insert + - key: service.name + from_attribute: k8s.pod.name + action: insert + - key: k8s.pod.name + action: delete + + +exporters: + otlp_grpc: + endpoint: pyroscope:4040 + tls: + insecure: true + +service: + pipelines: + profiles: + receivers: [profiling] + exporters: [otlp_grpc] + processors: + - k8s_attributes/docker-shim + - resource/docker-shim diff --git a/examples/otel-collector/ebpf/docker/config/kubeconfig.yaml b/examples/otel-collector/ebpf/docker/config/kubeconfig.yaml new file mode 100644 index 0000000000..d1b5edcb79 --- /dev/null +++ b/examples/otel-collector/ebpf/docker/config/kubeconfig.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Config +clusters: +- name: shim + cluster: + server: http://docker-k8sattributesprocessor-shim:16442 +users: +- name: shim +contexts: +- name: shim + context: + cluster: shim + user: shim +current-context: shim diff --git a/examples/otel-collector/ebpf/docker/docker-compose.yml b/examples/otel-collector/ebpf/docker/docker-compose.yml new file mode 100644 index 0000000000..011dc5024d --- /dev/null +++ b/examples/otel-collector/ebpf/docker/docker-compose.yml @@ -0,0 +1,52 @@ +services: + + otel-ebpf-profiler: + image: otel/opentelemetry-collector-ebpf-profiler:0.147.0 + command: + - --config=/etc/ebpf-profiler-config.yaml + - --feature-gates=service.profilesSupport + hostname: ebpf-profiler + privileged: true + pid: "host" + volumes: + - ./config/ebpf-profiler-config.yaml:/etc/ebpf-profiler-config.yaml:ro + - ./config/kubeconfig.yaml:/root/.kube/config:ro + - /sys/kernel/debug:/sys/kernel/debug:ro + - /sys/fs/cgroup:/sys/fs/cgroup:ro + networks: + - otel-net + + # The otel-ebpf-profiler doesnt support adding docker metadata, this shim translates it into kubernetes API and makes it available + docker-k8sattributesprocessor-shim: + image: ghcr.io/simonswine/docker-k8sattributesprocessor-shim:latest + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - otel-net + + pyroscope: + image: grafana/pyroscope:1.18.1 + command: + - -self-profiling.disable-push=true + ports: + - "4040:4040" + networks: + - otel-net + + grafana: + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - "3000:3000" + networks: + - otel-net + +networks: + otel-net: + driver: bridge diff --git a/examples/otel-collector/ebpf/docker/grafana-provisioning/datasources/pyroscope.yml b/examples/otel-collector/ebpf/docker/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..1ac5fa535b --- /dev/null +++ b/examples/otel-collector/ebpf/docker/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,14 @@ +--- +apiVersion: 1 +datasources: + - uid: local-pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + # Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/otel-collector/ebpf/kubernetes/config/ebpf-profiler-config.yaml b/examples/otel-collector/ebpf/kubernetes/config/ebpf-profiler-config.yaml new file mode 100644 index 0000000000..f2cd78c316 --- /dev/null +++ b/examples/otel-collector/ebpf/kubernetes/config/ebpf-profiler-config.yaml @@ -0,0 +1,51 @@ +receivers: + profiling: + samples_per_second: 97 + +processors: + resource/metadata: + attributes: + - action: upsert + key: k8s.cluster.name + value: demo + + k8sattributes/profiles: + auth_type: serviceAccount + passthrough: false +# TODO: Investigate why this breaks it +# filter: +# node_from_env_var: KUBERNETES_NODE_NAME + extract: + metadata: + - k8s.pod.name + - k8s.pod.uid + - k8s.namespace.name + - k8s.deployment.name + - k8s.node.name + - k8s.cluster.uid + - k8s.container.name + - container.image.name + - container.image.tag + - service.name + - service.namespace + - service.instance.id + otel_annotations: true + pod_association: + - sources: + - from: resource_attribute + name: container.id + +exporters: + otlp_grpc: + endpoint: pyroscope:4040 + tls: + insecure: true + +service: + pipelines: + profiles: + receivers: [profiling] + exporters: [otlp_grpc] + processors: + - k8sattributes/profiles + - resource/metadata diff --git a/examples/otel-collector/ebpf/kubernetes/cpu-stress.yaml b/examples/otel-collector/ebpf/kubernetes/cpu-stress.yaml new file mode 100644 index 0000000000..349a18c9ce --- /dev/null +++ b/examples/otel-collector/ebpf/kubernetes/cpu-stress.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cpu-stress +spec: + replicas: 1 + selector: + matchLabels: + app: cpu-stress + template: + metadata: + labels: + app: cpu-stress + spec: + containers: + - name: stress + image: polinux/stress + command: ["stress"] + args: ["--cpu", "2"] + resources: + limits: + cpu: "2" + requests: + cpu: "1" diff --git a/examples/otel-collector/ebpf/kubernetes/grafana.yaml b/examples/otel-collector/ebpf/kubernetes/grafana.yaml new file mode 100644 index 0000000000..0332004d56 --- /dev/null +++ b/examples/otel-collector/ebpf/kubernetes/grafana.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana +spec: + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + spec: + containers: + - name: grafana + image: grafana/grafana:latest + ports: + - containerPort: 3000 + env: + - name: GF_PLUGINS_PREINSTALL_SYNC + value: grafana-pyroscope-app + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "true" + volumeMounts: + - name: grafana-provisioning + mountPath: /etc/grafana/provisioning + volumes: + - name: grafana-provisioning + configMap: + name: grafana-provisioning + items: + - key: datasources + path: datasources/datasources.yaml +--- +apiVersion: v1 +kind: Service +metadata: + name: grafana +spec: + selector: + app: grafana + ports: + - protocol: TCP + port: 3000 + targetPort: 3000 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-provisioning +data: + "datasources": | + apiVersion: 1 + datasources: + - uid: local-pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] diff --git a/examples/otel-collector/ebpf/kubernetes/kustomization.yaml b/examples/otel-collector/ebpf/kubernetes/kustomization.yaml new file mode 100644 index 0000000000..875c7dc13a --- /dev/null +++ b/examples/otel-collector/ebpf/kubernetes/kustomization.yaml @@ -0,0 +1,17 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - rbac.yaml + - otel-ebpf-profiler.yaml + - pyroscope.yaml + - grafana.yaml + - cpu-stress.yaml + +configMapGenerator: + - name: otel-ebpf-profiler-config + files: + - config.yaml=config/ebpf-profiler-config.yaml + +generatorOptions: + #disableNameSuffixHash: true diff --git a/examples/otel-collector/ebpf/kubernetes/otel-ebpf-profiler.yaml b/examples/otel-collector/ebpf/kubernetes/otel-ebpf-profiler.yaml new file mode 100644 index 0000000000..ef9cc7e4ed --- /dev/null +++ b/examples/otel-collector/ebpf/kubernetes/otel-ebpf-profiler.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: otel-ebpf-profiler +spec: + selector: + matchLabels: + app: otel-ebpf-profiler + template: + metadata: + labels: + app: otel-ebpf-profiler + spec: + hostPID: true + serviceAccountName: otel-ebpf-profiler + containers: + - name: profiler + image: otel/opentelemetry-collector-ebpf-profiler:0.147.0 + args: + - "--config=/etc/otel/config.yaml" + - "--feature-gates=+service.profilesSupport" + env: + - name: KUBERNETES_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: OTEL_RESOURCE_ATTRIBUTES + value: "host.name=$(KUBERNETES_NODE_NAME)" + resources: + requests: + cpu: 200m + memory: 256Mi + limits: + cpu: "1" + memory: 1Gi + securityContext: + privileged: true + volumeMounts: + - name: config + mountPath: /etc/otel/config.yaml + subPath: config.yaml + - name: sys-kernel + mountPath: /sys/kernel + readOnly: true + - name: tracefs + mountPath: /sys/kernel/tracing + readOnly: true + - name: lib-modules + mountPath: /lib/modules + readOnly: true + - name: proc + mountPath: /proc + readOnly: true + volumes: + - name: config + configMap: + name: otel-ebpf-profiler-config + - name: sys-kernel + hostPath: + path: /sys/kernel + - name: tracefs + hostPath: + path: /sys/kernel/tracing + - name: lib-modules + hostPath: + path: /lib/modules + - name: proc + hostPath: + path: /proc + tolerations: + - operator: Exists diff --git a/examples/otel-collector/ebpf/kubernetes/pyroscope.yaml b/examples/otel-collector/ebpf/kubernetes/pyroscope.yaml new file mode 100644 index 0000000000..9a346ad61c --- /dev/null +++ b/examples/otel-collector/ebpf/kubernetes/pyroscope.yaml @@ -0,0 +1,34 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope +spec: + replicas: 1 + selector: + matchLabels: + app: pyroscope + template: + metadata: + labels: + app: pyroscope + spec: + containers: + - name: pyroscope + image: grafana/pyroscope:1.18.1 + # fixed versions for pyroscope, otel-collector, otel-profiler due to protocol changes + args: + - "-self-profiling.disable-push=true" + ports: + - containerPort: 4040 +--- +apiVersion: v1 +kind: Service +metadata: + name: pyroscope +spec: + selector: + app: pyroscope + ports: + - protocol: TCP + port: 4040 + targetPort: 4040 diff --git a/examples/otel-collector/ebpf/kubernetes/rbac.yaml b/examples/otel-collector/ebpf/kubernetes/rbac.yaml new file mode 100644 index 0000000000..ba97b3e64a --- /dev/null +++ b/examples/otel-collector/ebpf/kubernetes/rbac.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: otel-ebpf-profiler +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: otel-ebpf-profiler +rules: + - apiGroups: [""] + resources: ["pods", "namespaces", "nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["replicasets", "deployments", "statefulsets", "daemonsets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: otel-ebpf-profiler +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: otel-ebpf-profiler +subjects: + - kind: ServiceAccount + name: otel-ebpf-profiler + namespace: default diff --git a/examples/tracing/dotnet/.gitignore b/examples/tracing/dotnet/.gitignore new file mode 100644 index 0000000000..140f8cf80f --- /dev/null +++ b/examples/tracing/dotnet/.gitignore @@ -0,0 +1 @@ +*.so diff --git a/examples/tracing/dotnet/Dockerfile b/examples/tracing/dotnet/Dockerfile new file mode 100644 index 0000000000..74500b0272 --- /dev/null +++ b/examples/tracing/dotnet/Dockerfile @@ -0,0 +1,55 @@ +ARG SDK_VERSION=8.0 +ARG PROFILER_VERSION=1.0.0 +# The build images takes an SDK image of the buildplatform, so the platform the build is running on. +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:$SDK_VERSION AS build + +ARG TARGETPLATFORM +ARG BUILDPLATFORM +ARG SDK_VERSION + +WORKDIR /dotnet + +ADD example . + +# Set the target framework to SDK_VERSION +RUN sed -i -E 's|.*|net'$SDK_VERSION'|' Example.csproj + +# We hardcode linux-x64 here, as the profiler doesn't support any other platform +RUN dotnet publish -o . --framework net$SDK_VERSION --runtime linux-x64 --no-self-contained + +FROM --platform=linux/amd64 alpine:3 AS sdk +ARG PROFILER_VERSION +RUN apk add --no-cache curl tar +RUN curl -fsSL -o /tmp/pyroscope.tar.gz \ + "https://github.com/grafana/pyroscope-dotnet/releases/download/pyroscope-${PROFILER_VERSION}/pyroscope.${PROFILER_VERSION}-glibc-x86_64.tar.gz" \ + && mkdir -p /pyroscope \ + && tar -xzf /tmp/pyroscope.tar.gz -C /pyroscope + +# Runtime only image of the targetplatfrom, so the platform the image will be running on. +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:$SDK_VERSION + +WORKDIR /dotnet + +COPY --from=sdk /pyroscope/Pyroscope.Profiler.Native.so ./Pyroscope.Profiler.Native.so +COPY --from=sdk /pyroscope/Pyroscope.Linux.ApiWrapper.x64.so ./Pyroscope.Linux.ApiWrapper.x64.so +COPY --from=build /dotnet/ ./ + + +ENV CORECLR_ENABLE_PROFILING=1 +ENV CORECLR_PROFILER={BD1A650D-AC5D-4896-B64F-D6FA25D6B26A} +ENV CORECLR_PROFILER_PATH=/dotnet/Pyroscope.Profiler.Native.so +ENV LD_PRELOAD=/dotnet/Pyroscope.Linux.ApiWrapper.x64.so +ENV LD_LIBRARY_PATH=/dotnet + +ENV PYROSCOPE_APPLICATION_NAME=rideshare.dotnet.push.app +ENV PYROSCOPE_SERVER_ADDRESS=http://pyroscope:4040 +ENV PYROSCOPE_LOG_LEVEL=debug +ENV PYROSCOPE_PROFILING_ENABLED=1 +ENV PYROSCOPE_PROFILING_ALLOCATION_ENABLED=true +ENV PYROSCOPE_PROFILING_CONTENTION_ENABLED=true +ENV PYROSCOPE_PROFILING_EXCEPTION_ENABLED=true +ENV PYROSCOPE_PROFILING_HEAP_ENABLED=true +ENV RIDESHARE_LISTEN_PORT=5000 + + +CMD sh -c "ASPNETCORE_URLS=http://*:${RIDESHARE_LISTEN_PORT} exec dotnet /dotnet/example.dll" diff --git a/examples/tracing/dotnet/Dockerfile.load-generator b/examples/tracing/dotnet/Dockerfile.load-generator new file mode 100644 index 0000000000..5c55f3d27c --- /dev/null +++ b/examples/tracing/dotnet/Dockerfile.load-generator @@ -0,0 +1,10 @@ +FROM python:3.9 + +RUN pip3 install requests + +COPY load-generator.py ./load-generator.py + +ENV PYTHONUNBUFFERED=1 + +CMD [ "python", "load-generator.py" ] + diff --git a/examples/tracing/dotnet/README.md b/examples/tracing/dotnet/README.md new file mode 100644 index 0000000000..14602f8c5e --- /dev/null +++ b/examples/tracing/dotnet/README.md @@ -0,0 +1,53 @@ +# Span Profiles with Grafana Tempo and Pyroscope + +The docker compose consists of: +- The .NET Rideshare App +- Tempo +- Pyroscope +- Grafana + +The `rideshare` app generate traces and profiling data that should be available in Grafana. +Datasources for Pyroscope and Tempo are provisioned automatically. + +### Build and run + +The project can be run locally with the following commands: + +```shell +# (optionally) pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +# build and run the example +docker compose up --build +``` + +Navigate to the [Explore page](http://localhost:3000/explore?schemaVersion=1&panes=%7B%22f36%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22rideshare.dotnet.push.app%22%5D,%22valueType%22:%22string%22%7D%5D,%22query%22:%22%7Bresource.service.name%3D%5C%22rideshare.dotnet.push.app%5C%22%7D%22%7D%5D,%22range%22:%7B%22from%22:%22now-15m%22,%22to%22:%22now%22%7D%7D%7D&orgId=1), select a trace and click on a span that has a linked profile: + +![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593) + +By default, only the root span gets labeled (the first span created locally): such spans are marked with the _link_ icon +and have the `pyroscope.profile.id` attribute set to the corresponding span ID. +Please note that presence of the attribute does not necessarily +indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is +less than the sample interval (10ms). + +### Instrumentation + +The `rideshare` demo application is instrumented with Pyroscope: [Pyroscope .NET Agent](https://github.com/grafana/pyroscope-dotnet) + +### Grafana Tempo configuration + +In order to correlate trace spans with profiling data, the Tempo datasource should have the following configured: +- The profiling data source +- Tags to use when making profiling queries + +![image](https://github.com/grafana/pyroscope/assets/12090599/380ac574-a298-440d-acfb-7bc0935a3a7c) + +While tags are optional, configuring them is highly recommended for optimizing query performance. +In our example, we configured the `service.name` tag for use in Pyroscope queries as the `service_name` label. +This configuration restricts the data set for lookup, ensuring that queries remain +consistently fast. Note that the tags you configure must be present in the span attributes or resources +for a trace to profiles span link to appear. + +Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details. diff --git a/examples/tracing/dotnet/docker-compose.yml b/examples/tracing/dotnet/docker-compose.yml new file mode 100644 index 0000000000..51e042ef3d --- /dev/null +++ b/examples/tracing/dotnet/docker-compose.yml @@ -0,0 +1,73 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + us-east: + ports: + - "5000" + environment: &env + OTLP_URL: tempo:4318 + OTEL_TRACES_EXPORTER: otlp + OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4317 + OTEL_SERVICE_NAME: rideshare.dotnet.push.app + OTEL_METRICS_EXPORTER: none + OTEL_TRACES_SAMPLER: always_on + OTEL_PROPAGATORS: tracecontext + REGION: us-east + PYROSCOPE_LABELS: region=us-east + PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040 + build: + context: . + eu-north: + ports: + - "5000" + environment: + <<: *env + REGION: eu-north + build: + context: . + ap-south: + ports: + - "5000" + environment: + <<: *env + REGION: ap-south + build: + context: . + + load-generator: + build: + context: . + dockerfile: Dockerfile.load-generator + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 + tempo: + # This service is generated from examples/_templates/tempo/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/tempo:2.10.5 + command: [ "-config.file=/etc/tempo.yml" ] + volumes: + - ./tempo/tempo.yml:/etc/tempo.yml + ports: + - "14268:14268" # jaeger ingest + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin diff --git a/examples/tracing/dotnet/example/.gitignore b/examples/tracing/dotnet/example/.gitignore new file mode 100644 index 0000000000..cd42ee34e8 --- /dev/null +++ b/examples/tracing/dotnet/example/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ diff --git a/examples/tracing/dotnet/example/BikeService.cs b/examples/tracing/dotnet/example/BikeService.cs new file mode 100644 index 0000000000..009180e01a --- /dev/null +++ b/examples/tracing/dotnet/example/BikeService.cs @@ -0,0 +1,16 @@ +namespace Example; + +internal class BikeService +{ + private readonly OrderService _orderService; + + public BikeService(OrderService orderService) + { + _orderService = orderService; + } + + public void Order(int searchRadius) + { + _orderService.FindNearestVehicle(searchRadius, "bike"); + } +} \ No newline at end of file diff --git a/examples/tracing/dotnet/example/CarService.cs b/examples/tracing/dotnet/example/CarService.cs new file mode 100644 index 0000000000..885b534ee6 --- /dev/null +++ b/examples/tracing/dotnet/example/CarService.cs @@ -0,0 +1,16 @@ +namespace Example; + +internal class CarService +{ + private readonly OrderService _orderService; + + public CarService(OrderService orderService) + { + _orderService = orderService; + } + + public void Order(int searchRadius) + { + _orderService.FindNearestVehicle(searchRadius, "car"); + } +} \ No newline at end of file diff --git a/examples/tracing/dotnet/example/Example.csproj b/examples/tracing/dotnet/example/Example.csproj new file mode 100644 index 0000000000..2a81035fd3 --- /dev/null +++ b/examples/tracing/dotnet/example/Example.csproj @@ -0,0 +1,16 @@ + + + net8.0 + example + Exe + example + enable + + + + + + + + + diff --git a/examples/tracing/dotnet/example/Folder.DotSettings.user b/examples/tracing/dotnet/example/Folder.DotSettings.user new file mode 100644 index 0000000000..13b97375cf --- /dev/null +++ b/examples/tracing/dotnet/example/Folder.DotSettings.user @@ -0,0 +1,4 @@ + + <AssemblyExplorer> + <Assembly Path="/home/korniltsev/.nuget/packages/pyroscope/0.4.0/lib/net6.0/Pyroscope.dll" /> +</AssemblyExplorer> diff --git a/examples/tracing/dotnet/example/OrderService.cs b/examples/tracing/dotnet/example/OrderService.cs new file mode 100644 index 0000000000..2332330ffe --- /dev/null +++ b/examples/tracing/dotnet/example/OrderService.cs @@ -0,0 +1,57 @@ +using System; + +namespace Example; + +internal class OrderService +{ + public void FindNearestVehicle(long searchRadius, string vehicle) + { + lock (_lock) + { + var labels = Pyroscope.LabelSet.Empty.BuildUpon() + .Add("vehicle", vehicle) + .Build(); + Pyroscope.LabelsWrapper.Do(labels, () => + { + for (long i = 0; i < searchRadius * 1000000000; i++) + { + } + + if (vehicle.Equals("car")) + { + CheckDriverAvailability(labels, searchRadius); + } + }); + } + } + + private readonly object _lock = new(); + + private static void CheckDriverAvailability(Pyroscope.LabelSet ctx, long searchRadius) + { + var region = System.Environment.GetEnvironmentVariable("REGION") ?? "unknown_region"; + ctx = ctx.BuildUpon() + .Add("driver_region", region) + .Build(); + Pyroscope.LabelsWrapper.Do(ctx, () => + { + for (long i = 0; i < searchRadius * 1000000000; i++) + { + } + + var now = DateTime.Now.Minute % 2 == 0; + var forceMutexLock = DateTime.Now.Minute % 2 == 0; + if ("eu-north".Equals(region) && forceMutexLock) + { + MutexLock(searchRadius); + } + }); + } + + private static void MutexLock(long searchRadius) + { + for (long i = 0; i < 30 * searchRadius * 1000000000; i++) + { + } + } +} \ No newline at end of file diff --git a/examples/tracing/dotnet/example/Program.cs b/examples/tracing/dotnet/example/Program.cs new file mode 100644 index 0000000000..83beb1a632 --- /dev/null +++ b/examples/tracing/dotnet/example/Program.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Collections; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +using OpenTelemetry.Trace; + +using Pyroscope.OpenTelemetry; + +namespace Example; + +public static class Program +{ + private static readonly List Files = new(); + public const string CustomActivitySourceName = "Example.ScooterService"; + public static void Main(string[] args) + { + for (int i = 0; i < 1024; i++) + { + Files.Add(File.Open("/dev/null", FileMode.Open, FileAccess.Read, FileShare.Read)); + } + object globalLock = new(); + var strings = new List(); + + var orderService = new OrderService(); + var bikeService = new BikeService(orderService); + var scooterService = new ScooterService(orderService); + var carService = new CarService(orderService); + + var builder = WebApplication.CreateBuilder(args); + builder.Services.AddOpenTelemetry() + .WithTracing(b => + { + b + .AddAspNetCoreInstrumentation() + .AddSource(CustomActivitySourceName) + .AddConsoleExporter() + .AddOtlpExporter() + .AddProcessor(new PyroscopeSpanProcessor()); + }); + var app = builder.Build(); + + app.MapGet("/bike", () => + { + bikeService.Order(1); + return "Bike ordered"; + }); + app.MapGet("/scooter", () => + { + scooterService.Order(2); + return "Scooter ordered"; + }); + + app.MapGet("/car", () => + { + carService.Order(3); + return "Car ordered"; + }); + + + app.MapGet("/pyroscope/cpu", (HttpRequest request) => + { + var enable = request.Query["enable"] == "true"; + Pyroscope.Profiler.Instance.SetCPUTrackingEnabled(enable); + return "OK"; + }); + app.MapGet("/pyroscope/allocation", (HttpRequest request) => + { + var enable = request.Query["enable"] == "true"; + Pyroscope.Profiler.Instance.SetAllocationTrackingEnabled(enable); + return "OK"; + }); + app.MapGet("/pyroscope/contention", (HttpRequest request) => + { + var enable = request.Query["enable"] == "true"; + Pyroscope.Profiler.Instance.SetContentionTrackingEnabled(enable); + return "OK"; + }); + app.MapGet("/pyroscope/exception", (HttpRequest request) => + { + var enable = request.Query["enable"] == "true"; + Pyroscope.Profiler.Instance.SetExceptionTrackingEnabled(enable); + return "OK"; + }); + + + app.MapGet("/playground/allocation", (HttpRequest request) => + { + var strings = new List(); + for (var i = 0; i < 10000; i++) + { + strings.Add("foobar" + i); + } + + return "OK"; + }); + app.MapGet("/playground/contention", (HttpRequest request) => + { + for (var i = 0; i < 100; i++) + { + lock (globalLock) + { + Thread.Sleep(10); + } + } + return "OK"; + }); + app.MapGet("/playground/exception", (HttpRequest request) => + { + for (var i = 0; i < 1000; i++) + { + try + { + throw new Exception("foobar" + i); + } + catch (Exception) + { + } + } + return "OK"; + }); + app.MapGet("/playground/leak", (HttpRequest request) => + { + for (var i = 0; i < 1000; i++) + { + strings.Add("leak " + i); + } + return "OK"; + }); + app.MapGet("/", () => + { + string env = ""; + foreach (DictionaryEntry e in System.Environment.GetEnvironmentVariables()) + { + env += e.Key + " = " + e.Value + "
\n"; + } + return env; + }); + + app.Run(); + } +} diff --git a/examples/tracing/dotnet/example/ScooterService.cs b/examples/tracing/dotnet/example/ScooterService.cs new file mode 100644 index 0000000000..a67fdbb993 --- /dev/null +++ b/examples/tracing/dotnet/example/ScooterService.cs @@ -0,0 +1,39 @@ +using System.Diagnostics; + +namespace Example; + +internal class ScooterService +{ + private static readonly ActivitySource CustomActivity = new(Program.CustomActivitySourceName); + + private readonly OrderService _orderService; + + public ScooterService(OrderService orderService) + { + _orderService = orderService; + } + + public void Order(int searchRadius) + { + using var activity = CustomActivity.StartActivity("OrderScooter"); + activity?.SetTag("type", "scooter"); + for (long i = 0; i < 2000000000; i++) + { + } + OrderInternal(searchRadius); + DoSomeOtherWork(); + } + + private void OrderInternal(int searchRadius) + { + using var activity = CustomActivity.StartActivity("OrderScooterInternal"); + _orderService.FindNearestVehicle(searchRadius, "scooter"); + } + + private void DoSomeOtherWork() + { + for (long i = 0; i < 1000000000; i++) + { + } + } +} diff --git a/examples/tracing/dotnet/grafana-provisioning/datasources/pyroscope.yml b/examples/tracing/dotnet/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/tracing/dotnet/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/tracing/dotnet/grafana-provisioning/datasources/tempo.yml b/examples/tracing/dotnet/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..a225551398 --- /dev/null +++ b/examples/tracing/dotnet/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,29 @@ +# This file is generated from the template: +# examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/tracing/dotnet/load-generator.py b/examples/tracing/dotnet/load-generator.py new file mode 100644 index 0000000000..792a914cfe --- /dev/null +++ b/examples/tracing/dotnet/load-generator.py @@ -0,0 +1,26 @@ +import random +import requests +import time + +HOSTS = [ + 'us-east', + 'eu-north', + 'ap-south', +] + +VEHICLES = [ + 'bike', + 'scooter', + 'car', +] + +if __name__ == "__main__": + print(f"starting load generator") + time.sleep(3) + while True: + host = HOSTS[random.randint(0, len(HOSTS) - 1)] + vehicle = VEHICLES[random.randint(0, len(VEHICLES) - 1)] + print(f"requesting {vehicle} from {host}") + resp = requests.get(f'http://{host}:5000/{vehicle}') + print(f"received {resp}") + time.sleep(random.uniform(0.2, 0.4)) diff --git a/examples/tracing/dotnet/tempo/tempo.yml b/examples/tracing/dotnet/tempo/tempo.yml new file mode 100644 index 0000000000..6db27a824c --- /dev/null +++ b/examples/tracing/dotnet/tempo/tempo.yml @@ -0,0 +1,38 @@ +# This file is generated from the template: +# examples/_templates/tempo/tempo/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + opencensus: + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks diff --git a/examples/tracing/golang-push/.dockerignore b/examples/tracing/golang-push/.dockerignore new file mode 100644 index 0000000000..2046f58e2d --- /dev/null +++ b/examples/tracing/golang-push/.dockerignore @@ -0,0 +1,3 @@ +docker-compose.yml +tempo/ +grafana-provisioning/ diff --git a/examples/tracing/golang-push/Dockerfile b/examples/tracing/golang-push/Dockerfile new file mode 100644 index 0000000000..37517ecd28 --- /dev/null +++ b/examples/tracing/golang-push/Dockerfile @@ -0,0 +1,6 @@ +FROM golang:1.25.12 + +WORKDIR /go/src/app +COPY . . +RUN go build main.go +CMD ["./main"] diff --git a/examples/tracing/golang-push/Dockerfile.load-generator b/examples/tracing/golang-push/Dockerfile.load-generator new file mode 100644 index 0000000000..eb16110dcd --- /dev/null +++ b/examples/tracing/golang-push/Dockerfile.load-generator @@ -0,0 +1,6 @@ +FROM golang:1.25.12 + +WORKDIR /go/src/app +COPY . . +RUN go build loadgen.go +CMD ["./loadgen"] diff --git a/examples/tracing/golang-push/README.md b/examples/tracing/golang-push/README.md new file mode 100644 index 0000000000..2f869896d8 --- /dev/null +++ b/examples/tracing/golang-push/README.md @@ -0,0 +1,58 @@ +# Span profiles with Traces to profiles for Go + +This example consists of: +- The Go Rideshare App +- Tempo +- Pyroscope +- Grafana + +The `rideshare` app generate traces and profiling data that then can be +analysed in Grafana. The datasources for Pyroscope and Tempo are provisioned +automatically. + +## Usage + +The project can be run locally with the following commands: + +```shell +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +docker compose up +``` + +Using the [Profiles Drilldown app], you can inspect the profiles for different request types: + + +[Profiles Drilldown app]:http://localhost:3000/a/grafana-pyroscope-app/explore?searchText=&panelType=time-series&layout=grid&hideNoData=off&explorationType=labels&var-serviceName=ride-sharing-app&var-profileMetricId=process_cpu:cpu:nanoseconds:cpu:nanoseconds&var-dataSource=pyroscope&var-groupBy=all&var-filters= + +![Profiles Drilldown screenshot](https://github.com/user-attachments/assets/6e6f1b35-4494-4f8f-afba-b231b09d4565) + + +Navigate to the [Explore Tempo page], select a trace and click on a span that has a linked profile: + +[Explore Tempo page]: http://localhost:3000/explore?schemaVersion=1&panes=%7B%22yM9%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22ride-sharing-app%22%5D,%22valueType%22:%22string%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-6h%22,%22to%22:%22now%22%7D%7D%7D&orgId=1 + +![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593) + +By default, only the root span gets labeled (the first span created locally): such spans are marked with the _link_ icon +and have `pyroscope.profile.id` attribute set to the corresponding span ID. +Please note that presence of the attribute does not necessarily +indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is +less than the sample interval (10ms). + + +### Instrumentation + +- `rideshare` demo application instrumented with OpenTelemetry: [OTel integration] . Please refer to our [documentation] for more details. +- `pyroscope` itself is instrumented with OpenTelemetry and [`otel-profiling-go`] for profiling integration. + +[OTel integration]:https://github.com/grafana/otel-profiling-go +[`otel-profiling-go`]:https://github.com/grafana/otel-profiling-go +[documentation]:https://grafana.com/docs/pyroscope/latest/configure-client/trace-span-profiles/go-span-profiles/ + + +### Grafana Tempo configuration + +Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details. diff --git a/examples/tracing/golang-push/bike/bike.go b/examples/tracing/golang-push/bike/bike.go new file mode 100644 index 0000000000..98ad8325fb --- /dev/null +++ b/examples/tracing/golang-push/bike/bike.go @@ -0,0 +1,12 @@ +package bike + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderBike(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering bike, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "bike") +} diff --git a/examples/tracing/golang-push/car/car.go b/examples/tracing/golang-push/car/car.go new file mode 100644 index 0000000000..16898fb8ea --- /dev/null +++ b/examples/tracing/golang-push/car/car.go @@ -0,0 +1,12 @@ +package car + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderCar(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering car, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "car") +} diff --git a/examples/tracing/golang-push/docker-compose.yml b/examples/tracing/golang-push/docker-compose.yml new file mode 100644 index 0000000000..fb00f2bf72 --- /dev/null +++ b/examples/tracing/golang-push/docker-compose.yml @@ -0,0 +1,75 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + us-east: + ports: + - "5000" + environment: &env + PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040 + OTLP_URL: tempo:4318 + OTLP_INSECURE: 1 + DEBUG_LOGGER: 1 + REGION: us-east + build: + context: . + eu-north: + ports: + - "5000" + environment: + <<: *env + REGION: eu-north + build: + context: . + ap-south: + ports: + - "5000" + environment: + <<: *env + REGION: ap-south + build: + context: . + + load-generator: + environment: + <<: *env + build: + context: . + dockerfile: Dockerfile.load-generator + command: + - ./loadgen + - http://us-east:5000 + - http://eu-north:5000 + - http://ap-south:5000 + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 + tempo: + # This service is generated from examples/_templates/tempo/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/tempo:2.10.5 + command: [ "-config.file=/etc/tempo.yml" ] + volumes: + - ./tempo/tempo.yml:/etc/tempo.yml + ports: + - "14268:14268" # jaeger ingest + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin diff --git a/examples/tracing/golang-push/go.mod b/examples/tracing/golang-push/go.mod new file mode 100644 index 0000000000..d70b623a3d --- /dev/null +++ b/examples/tracing/golang-push/go.mod @@ -0,0 +1,41 @@ +module rideshare + +go 1.25.0 + +toolchain go1.25.12 + +require ( + github.com/agoda-com/opentelemetry-logs-go v0.5.1 + github.com/grafana/otel-profiling-go v0.5.1 + github.com/grafana/pyroscope-go v1.2.7 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 + go.opentelemetry.io/otel/sdk v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect +) diff --git a/examples/tracing/golang-push/go.sum b/examples/tracing/golang-push/go.sum new file mode 100644 index 0000000000..c8fe9f0073 --- /dev/null +++ b/examples/tracing/golang-push/go.sum @@ -0,0 +1,97 @@ +github.com/agoda-com/opentelemetry-logs-go v0.5.1 h1:6iQrLaY4M0glBZb/xVN559qQutK4V+HJ/mB1cbwaX3c= +github.com/agoda-com/opentelemetry-logs-go v0.5.1/go.mod h1:35B5ypjX5pkVCPJR01i6owJSYWe8cnbWLpEyHgAGD/E= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= +github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= +github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= +github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/tracing/golang-push/go.work b/examples/tracing/golang-push/go.work new file mode 100644 index 0000000000..a860ee362f --- /dev/null +++ b/examples/tracing/golang-push/go.work @@ -0,0 +1,3 @@ +go 1.25.0 + +use . diff --git a/examples/tracing/golang-push/go.work.sum b/examples/tracing/golang-push/go.work.sum new file mode 100644 index 0000000000..8dcd405515 --- /dev/null +++ b/examples/tracing/golang-push/go.work.sum @@ -0,0 +1,165 @@ +cel.dev/expr v0.16.0 h1:yloc84fytn4zmJX2GU3TkXGsaieaV7dQ057Qs4sIG2Y= +cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les= +github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= +github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 h1:umZgi92IyxfXd/l4kaDhnKgY8rnN/cZcF1LKc6I8OQ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0/go.mod h1:4lVs6obhSVRb1EW5FhOuBTyiQhtRtAnnva9vD3yRfq8= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0 h1:kn1BudCgwtE7PxLqcZkErpD8GKqLZ6BSzeW9QihQJeM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0/go.mod h1:ljkUDtAMdleoi9tIG1R6dJUpVwDcYjw3J2Q6Q/SuiC0= +go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= +go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc h1:Nf+EdcTLHR8qDNN/KfkQL0u0ssxt9OhbaWCl5C0ucEI= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/examples/tracing/golang-push/grafana-provisioning/datasources/pyroscope.yml b/examples/tracing/golang-push/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/tracing/golang-push/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/tracing/golang-push/grafana-provisioning/datasources/tempo.yml b/examples/tracing/golang-push/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..a225551398 --- /dev/null +++ b/examples/tracing/golang-push/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,29 @@ +# This file is generated from the template: +# examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/tracing/golang-push/loadgen.go b/examples/tracing/golang-push/loadgen.go new file mode 100644 index 0000000000..7dbcd92453 --- /dev/null +++ b/examples/tracing/golang-push/loadgen.go @@ -0,0 +1,140 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "net/http" + "os" + "strconv" + "time" + + otelpyroscope "github.com/grafana/otel-profiling-go" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/propagation" + + "rideshare/rideshare" +) + +var urls = []string{} + +var vehicles = []string{ + "bike", + "scooter", + "car", +} + +var client *http.Client + +func main() { + c := rideshare.ReadConfig() + c.AppName = "load-generator" + urls = os.Args[1:] + if len(urls) == 0 { + urls = []string{ + "http://us-east:5000", + "http://eu-north:5000", + "http://ap-south:5000", + } + } + + groupByFactor := 3 + if os.Getenv("LOADGEN_GROUP_BY_FACTOR") != "" { + var err error + groupByFactor, err = strconv.Atoi(os.Getenv("LOADGEN_GROUP_BY_FACTOR")) + if err != nil { + log.Fatalf("issue with LOADGEN_GROUP_BY_FACTOR: %v\n", err) + } + } + + // Configure profiler. + p, err := rideshare.Profiler(c) + if err != nil { + log.Fatalf("failed to initialize profiler: %v\n", err) + } + defer func() { + _ = p.Stop() + }() + + // Configure tracing. + tp, err := rideshare.TracerProvider(c) + if err != nil { + log.Fatalf("failed to initialize profiler: %v\n", err) + } + + // Set the Tracer Provider and the W3C Trace Context propagator as globals. + // We wrap the tracer provider to also annotate goroutines with Span ID so + // that pprof would add corresponding labels to profiling samples. + otel.SetTracerProvider(otelpyroscope.NewTracerProvider(tp)) + + // Register the trace c ontext and baggage propagators so data is propagated across services/processes. + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + client = &http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)} + + defer func() { + _ = tp.Shutdown(context.Background()) + }() + + groups := groupHosts(urls, groupByFactor) + for _, group := range groups { + go func(group []string) { + for { + host := group[rand.Intn(len(group))] + vehicle := vehicles[rand.Intn(len(vehicles))] + if err = orderVehicle(context.Background(), host, vehicle); err != nil { + fmt.Println(err) + } + } + }(group) + } + + select {} +} + +func groupHosts(hosts []string, groupsOf int) [][]string { + var res [][]string + for i := 0; i < len(hosts); i += groupsOf { + upperBoundary := i + groupsOf + if upperBoundary > len(hosts) { + upperBoundary = len(hosts) + } + res = append(res, hosts[i:upperBoundary]) + } + return res +} + +func orderVehicle(ctx context.Context, baseURL, vehicle string) error { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "OrderVehicle") + defer span.End() + + // Spend some time on CPU. + d := time.Duration(200+rand.Intn(200)) * time.Millisecond + begin := time.Now() + for { + if time.Now().Sub(begin) > d { + break + } + } + + span.SetAttributes(attribute.String("vehicle", vehicle)) + url := fmt.Sprintf("%s/%s", baseURL, vehicle) + fmt.Println("requesting", url) + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return err + } + resp, err := client.Do(req) + if err != nil { + return err + } + _ = resp.Body.Close() + return nil +} diff --git a/examples/tracing/golang-push/main.go b/examples/tracing/golang-push/main.go new file mode 100644 index 0000000000..711ba0d8c9 --- /dev/null +++ b/examples/tracing/golang-push/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + + "rideshare/bike" + "rideshare/car" + "rideshare/rideshare" + "rideshare/scooter" + "rideshare/utility" + + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + + otellogs "github.com/agoda-com/opentelemetry-logs-go" + otelpyroscope "github.com/grafana/otel-profiling-go" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + sdktrace "go.opentelemetry.io/otel/sdk/trace" +) + +func bikeRoute(w http.ResponseWriter, r *http.Request) { + bike.OrderBike(r.Context(), 1) + w.Write([]byte("

Bike ordered

")) +} + +func scooterRoute(w http.ResponseWriter, r *http.Request) { + scooter.OrderScooter(r.Context(), 2) + w.Write([]byte("

Scooter ordered

")) +} + +func carRoute(w http.ResponseWriter, r *http.Request) { + car.OrderCar(r.Context(), 3) + w.Write([]byte("

Car ordered

")) +} + +func index(w http.ResponseWriter, r *http.Request) { + rideshare.Log.Print(r.Context(), "showing index") + result := "

environment vars:

" + for _, env := range os.Environ() { + result += env + "
" + } + w.Write([]byte(result)) +} + +func main() { + config := rideshare.ReadConfig() + + tp, _ := setupOTEL(config) + defer func() { + _ = tp.Shutdown(context.Background()) + }() + + p, err := rideshare.Profiler(config) + + if err != nil { + log.Fatalf("error starting pyroscope profiler: %v", err) + } + defer func() { + _ = p.Stop() + }() + + cleanup := utility.InitWorkerPool(config) + defer cleanup() + + rideshare.Log.Print(context.Background(), "started ride-sharing app") + + http.Handle("/", otelhttp.NewHandler(http.HandlerFunc(index), "IndexHandler")) + http.Handle("/bike", otelhttp.NewHandler(http.HandlerFunc(bikeRoute), "BikeHandler")) + http.Handle("/scooter", otelhttp.NewHandler(http.HandlerFunc(scooterRoute), "ScooterHandler")) + http.Handle("/car", otelhttp.NewHandler(http.HandlerFunc(carRoute), "CarHandler")) + + addr := fmt.Sprintf(":%s", config.RideshareListenPort) + log.Fatal(http.ListenAndServe(addr, nil)) +} + +func setupOTEL(c rideshare.Config) (tp *sdktrace.TracerProvider, err error) { + tp, err = rideshare.TracerProvider(c) + if err != nil { + return nil, err + } + + lp, err := rideshare.LoggerProvider(c) + if err != nil { + return nil, err + } + otellogs.SetLoggerProvider(lp) + + const ( + instrumentationName = "otel/zap" + instrumentationVersion = "0.0.1" + ) + + // Set the Tracer Provider and the W3C Trace Context propagator as globals. + // We wrap the tracer provider to also annotate goroutines with Span ID so + // that pprof would add corresponding labels to profiling samples. + otel.SetTracerProvider(otelpyroscope.NewTracerProvider(tp)) + + // Register the trace context and baggage propagators so data is propagated across services/processes. + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + return tp, err +} diff --git a/examples/tracing/golang-push/pyroscope/pyroscope.yml b/examples/tracing/golang-push/pyroscope/pyroscope.yml new file mode 100644 index 0000000000..b0b83f36c0 --- /dev/null +++ b/examples/tracing/golang-push/pyroscope/pyroscope.yml @@ -0,0 +1,2 @@ +tracing: + profiling_enabled: true diff --git a/examples/tracing/golang-push/rideshare/rideshare.go b/examples/tracing/golang-push/rideshare/rideshare.go new file mode 100644 index 0000000000..eaecea732d --- /dev/null +++ b/examples/tracing/golang-push/rideshare/rideshare.go @@ -0,0 +1,272 @@ +package rideshare + +import ( + "context" + "encoding/base64" + "fmt" + "os" + "strconv" + "time" + + "github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs" + "github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs/otlplogshttp" + "github.com/agoda-com/opentelemetry-logs-go/exporters/stdout/stdoutlogs" + "github.com/agoda-com/opentelemetry-logs-go/logs" + sdklogs "github.com/agoda-com/opentelemetry-logs-go/sdk/logs" + "github.com/grafana/pyroscope-go" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.20.0" + "go.opentelemetry.io/otel/trace" +) + +type loggerAdapter struct { + logger logs.Logger +} + +func (la *loggerAdapter) Print(ctx context.Context, msg string) { + severityNumber := logs.INFO + now := time.Now() + c := logs.LogRecordConfig{ + ObservedTimestamp: now, + Timestamp: &now, + SeverityNumber: &severityNumber, + Body: &msg, + } + + span := trace.SpanFromContext(ctx) + if spanID := span.SpanContext().SpanID(); spanID.IsValid() { + c.SpanId = &spanID + } + if traceID := span.SpanContext().TraceID(); traceID.IsValid() { + c.TraceId = &traceID + } + la.logger.Emit(logs.NewLogRecord(c)) +} + +func (la *loggerAdapter) Printf(ctx context.Context, format string, v ...interface{}) { + la.Print(ctx, fmt.Sprintf(format, v...)) +} + +var Log = &loggerAdapter{logger: nil} + +type Config struct { + AppName string + PyroscopeServerAddress string + PyroscopeAuthToken string // for OG pyroscope and cloudstorage + PyroscopeBasicAuthUser string // for grafana + PyroscopeBasicAuthPassword string // for grafana + + OTLPUrl string + OTLPInsecure bool + OTLPBasicAuthUser string + OTLPBasicAuthPassword string + OTLPTracesUrlPath string + + UseDebugTracer bool + UseDebugLogger bool + Tags map[string]string + + ParametersPoolSize int + ParametersPoolBufferSize int + RideshareListenPort string +} + +func ReadConfig() Config { + appName := os.Getenv("PYROSCOPE_APPLICATION_NAME") + if appName == "" { + appName = "ride-sharing-app" + } + hostname, err := os.Hostname() + if err != nil { + hostname = "unknown" + } + c := Config{ + AppName: appName, + PyroscopeServerAddress: os.Getenv("PYROSCOPE_SERVER_ADDRESS"), + PyroscopeBasicAuthUser: os.Getenv("PYROSCOPE_BASIC_AUTH_USER"), + PyroscopeBasicAuthPassword: os.Getenv("PYROSCOPE_BASIC_AUTH_PASSWORD"), + + OTLPUrl: os.Getenv("OTLP_URL"), + OTLPInsecure: os.Getenv("OTLP_INSECURE") == "1", + OTLPBasicAuthUser: os.Getenv("OTLP_BASIC_AUTH_USER"), + OTLPBasicAuthPassword: os.Getenv("OTLP_BASIC_AUTH_PASSWORD"), + OTLPTracesUrlPath: os.Getenv("OTLP_TRACES_URL_PATH"), + + UseDebugTracer: os.Getenv("DEBUG_TRACER") == "1", + UseDebugLogger: os.Getenv("DEBUG_LOGGER") == "1", + Tags: map[string]string{ + "region": os.Getenv("REGION"), + "hostname": hostname, + "service_git_ref": "HEAD", + "service_repository": "https://github.com/grafana/pyroscope", + "service_root_path": "examples/language-sdk-instrumentation/golang-push/rideshare", + }, + + ParametersPoolSize: envIntOrDefault("PARAMETERS_POOL_SIZE", 1000), + + // Internally, we represent this as buffer size in bytes, but to make it + // more readable from as an env var, we represent the env var value in + // kb. + ParametersPoolBufferSize: envIntOrDefault("PARAMETERS_POOL_BUFFER_SIZE_KB", 1000) * 1000, + + RideshareListenPort: os.Getenv("RIDESHARE_LISTEN_PORT"), + } + if c.RideshareListenPort == "" { + c.RideshareListenPort = "5000" + } + if c.AppName == "" { + c.AppName = "ride-sharing-app" + } + if c.PyroscopeServerAddress == "" { + c.PyroscopeServerAddress = "http://localhost:4040" + } + return c +} + +func basicAuth(username, password string) string { + auth := username + ":" + password + return base64.StdEncoding.EncodeToString([]byte(auth)) +} + +func newResource(c Config, extraAttrs ...attribute.KeyValue) *resource.Resource { + host, _ := os.Hostname() + + attrs := append([]attribute.KeyValue{ + semconv.ServiceNameKey.String(c.AppName), + semconv.CloudRegionKey.String(os.Getenv("REGION")), + semconv.HostName(host), + }, extraAttrs...) + return resource.NewWithAttributes( + semconv.SchemaURL, + // Note that ServiceNameKey attribute can include chars not allowed in Pyroscope + // application name, therefore it should be used carefully. + attrs..., + ) +} + +func LoggerProvider(c Config) (*sdklogs.LoggerProvider, error) { + if c.UseDebugLogger || c.OTLPUrl == "" { + consoleProvider, err := stdoutlogs.NewExporter(stdoutlogs.WithWriter(os.Stderr)) + if err != nil { + return nil, err + } + loggerProvider := sdklogs.NewLoggerProvider( + sdklogs.WithBatcher(consoleProvider), + sdklogs.WithResource(newResource(c)), + ) + Log.logger = loggerProvider.Logger( + "ride-share", + logs.WithInstrumentationVersion("0.0.1"), + logs.WithSchemaURL(semconv.SchemaURL), + ) + return loggerProvider, nil + } + + exporter, _ := otlplogs.NewExporter(context.Background(), otlplogs.WithClient(otlplogshttp.NewClient( + otlplogshttp.WithEndpoint(c.OTLPUrl), + otlplogshttp.WithURLPath("/otlp/v1/logs"), + otlplogshttp.WithHeaders(map[string]string{ + "Authorization": "Basic " + basicAuth(c.OTLPBasicAuthUser, c.OTLPBasicAuthPassword), + }), + ))) + + // tell loki to use host.name and cloud.region as labels + lokiHint := attribute.KeyValue{ + Key: attribute.Key("loki.resource.labels"), + Value: attribute.StringSliceValue([]string{ + string(semconv.CloudRegionKey.String("").Key), + string(semconv.ServiceNameKey.String("").Key), + string(semconv.HostName("").Key), + }), + } + + loggerProvider := sdklogs.NewLoggerProvider( + sdklogs.WithBatcher(exporter), + sdklogs.WithResource(newResource(c, lokiHint)), + ) + + Log.logger = loggerProvider.Logger( + "ride-share", + logs.WithInstrumentationVersion("0.0.1"), + logs.WithSchemaURL(semconv.SchemaURL), + ) + + return loggerProvider, nil +} + +func TracerProvider(c Config) (*sdktrace.TracerProvider, error) { + if c.UseDebugTracer || c.OTLPUrl == "" { + return debugTracerProvider() + } + ctx := context.Background() + opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(c.OTLPUrl)} + if c.OTLPTracesUrlPath != "" { + opts = append(opts, otlptracehttp.WithURLPath(c.OTLPTracesUrlPath)) + } + if c.OTLPInsecure { + opts = append(opts, otlptracehttp.WithInsecure()) + } + if c.OTLPBasicAuthUser != "" { + opts = append(opts, otlptracehttp.WithHeaders(map[string]string{ + "Authorization": "Basic " + basicAuth(c.OTLPBasicAuthUser, c.OTLPBasicAuthPassword), + })) + } + + exp, err := otlptrace.New(ctx, otlptracehttp.NewClient(opts...)) + if err != nil { + return nil, err + } + + // Create a new tracer provider with a batch span processor and the otlp exporter. + tp2 := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exp), + sdktrace.WithResource(newResource(c)), + ) + + return tp2, nil +} + +func debugTracerProvider() (*sdktrace.TracerProvider, error) { + exp, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) + if err != nil { + return nil, err + } + return sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exp))), nil +} + +func Profiler(c Config) (*pyroscope.Profiler, error) { + config := pyroscope.Config{ + ApplicationName: c.AppName, + ServerAddress: c.PyroscopeServerAddress, + Logger: pyroscope.StandardLogger, + Tags: c.Tags, + } + if c.PyroscopeAuthToken != "" { + config.AuthToken = c.PyroscopeAuthToken + } else if c.PyroscopeBasicAuthUser != "" { + config.BasicAuthUser = c.PyroscopeBasicAuthUser + config.BasicAuthPassword = c.PyroscopeBasicAuthPassword + } + return pyroscope.Start(config) +} + +// envIntOrDefault looks up the environment variable key and returns the value +// as an int. +func envIntOrDefault(key string, fallback int) int { + s, ok := os.LookupEnv(key) + if !ok { + return fallback + } + + v, err := strconv.Atoi(s) + if err != nil { + return fallback + } + + return v +} diff --git a/examples/tracing/golang-push/scooter/scooter.go b/examples/tracing/golang-push/scooter/scooter.go new file mode 100644 index 0000000000..e6eb356526 --- /dev/null +++ b/examples/tracing/golang-push/scooter/scooter.go @@ -0,0 +1,12 @@ +package scooter + +import ( + "context" + "rideshare/rideshare" + "rideshare/utility" +) + +func OrderScooter(ctx context.Context, searchRadius int64) { + rideshare.Log.Printf(ctx, "ordering scooter, with searchRadius=%d", searchRadius) + utility.FindNearestVehicle(ctx, searchRadius, "scooter") +} diff --git a/examples/tracing/golang-push/tempo/tempo.yml b/examples/tracing/golang-push/tempo/tempo.yml new file mode 100644 index 0000000000..6db27a824c --- /dev/null +++ b/examples/tracing/golang-push/tempo/tempo.yml @@ -0,0 +1,38 @@ +# This file is generated from the template: +# examples/_templates/tempo/tempo/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + opencensus: + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks diff --git a/examples/tracing/golang-push/utility/pool.go b/examples/tracing/golang-push/utility/pool.go new file mode 100644 index 0000000000..8a650eeba1 --- /dev/null +++ b/examples/tracing/golang-push/utility/pool.go @@ -0,0 +1,92 @@ +package utility + +import ( + "os" + "sync" + + "rideshare/rideshare" +) + +type workerPool struct { + poolLock *sync.Mutex + pool []chan struct{} + limit int + bufferSize int +} + +// Run a function using a pool. +func (c *workerPool) Run(fn func()) { + if os.Getenv("REGION") != "us-east" { + // Only leak memory for us-east. If not us-east, run the worker + // function in a blocking manner. + + fn() + return + } + + stop := make(chan struct{}, 1) + done := make(chan struct{}, 1) + + c.poolLock.Lock() + size := len(c.pool) + if c.limit != 0 && size >= c.limit { + // We're at max pool limit, reset the pool. + c.resetWithoutLock() + } + c.pool = append(c.pool, stop) + c.poolLock.Unlock() + + // Create a goroutine to run the function. It will write to done when the + // work is over, but won't clean up until it receives a signal from stop. + go c.doWork(fn, stop, done) + + // Block until the worker signals it's done. + <-done + close(done) +} + +// Closes the pool, cleaning up all resources. +func (c *workerPool) Close() { + c.poolLock.Lock() + defer c.poolLock.Unlock() + + c.resetWithoutLock() +} + +func (c *workerPool) resetWithoutLock() { + for _, c := range c.pool { + c <- struct{}{} + close(c) + } + c.pool = c.pool[:0] +} + +func (c *workerPool) doWork(fn func(), stop <-chan struct{}, done chan<- struct{}) { + buf := make([]byte, 0) + + // Do work. + fn() + + // Simulate the work in fn requiring some data to be added to a buffer. + for i := 0; i < c.bufferSize; i++ { + buf = append(buf, byte(i)) + } + + // Don't let the compiler optimize away the buf. + var _ = buf + + // Signal we're done working. + done <- struct{}{} + + // Block until we're told to clean up. + <-stop +} + +func newPool(c rideshare.Config) *workerPool { + return &workerPool{ + poolLock: &sync.Mutex{}, + pool: make([]chan struct{}, 0, c.ParametersPoolSize), + limit: c.ParametersPoolSize, + bufferSize: c.ParametersPoolBufferSize, + } +} diff --git a/examples/tracing/golang-push/utility/utility.go b/examples/tracing/golang-push/utility/utility.go new file mode 100644 index 0000000000..dbc0b64dcb --- /dev/null +++ b/examples/tracing/golang-push/utility/utility.go @@ -0,0 +1,75 @@ +package utility + +import ( + "context" + "os" + "time" + + "rideshare/rideshare" + + "github.com/grafana/pyroscope-go" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" +) + +const durationConstant = time.Duration(200 * time.Millisecond) + +var pool *workerPool + +// InitWorkPool initializes the worker pool and returns a clean up function. +func InitWorkerPool(c rideshare.Config) func() { + pool = newPool(c) + return pool.Close +} + +func mutexLock(n int64) { + var i int64 = 0 + + // start time is number of seconds since epoch + startTime := time.Now() + + // This changes the amplitude of cpu bars + for time.Since(startTime) < time.Duration(n*30)*durationConstant { + i++ + } +} + +func checkDriverAvailability(n int64) { + var i int64 = 0 + + // start time is number of seconds since epoch + startTime := time.Now() + + pool.Run(func() { + for time.Since(startTime) < time.Duration(n)*durationConstant { + i++ + } + }) + + // Every other minute this will artificially create make requests in eu-north region slow + // this is just for demonstration purposes to show how performance impacts show up in the + // flamegraph + force_mutex_lock := time.Now().Minute()%2 == 0 + if os.Getenv("REGION") == "eu-north" && force_mutex_lock { + mutexLock(n) + } +} + +func FindNearestVehicle(ctx context.Context, searchRadius int64, vehicle string) { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "FindNearestVehicle") + span.SetAttributes(attribute.String("vehicle", vehicle)) + defer span.End() + + pyroscope.TagWrapper(ctx, pyroscope.Labels("vehicle", vehicle), func(ctx context.Context) { + var i int64 = 0 + + startTime := time.Now() + for time.Since(startTime) < time.Duration(searchRadius)*durationConstant { + i++ + } + + if vehicle == "car" { + checkDriverAvailability(searchRadius) + } + }) +} diff --git a/examples/tracing/java-wall/.gitignore b/examples/tracing/java-wall/.gitignore new file mode 100644 index 0000000000..cb6a621933 --- /dev/null +++ b/examples/tracing/java-wall/.gitignore @@ -0,0 +1,6 @@ +build/ +.idea/ +.gradle +pyroscope.jar +out/ +bin/ diff --git a/examples/tracing/java-wall/Dockerfile b/examples/tracing/java-wall/Dockerfile new file mode 100644 index 0000000000..be8ee5d7bb --- /dev/null +++ b/examples/tracing/java-wall/Dockerfile @@ -0,0 +1,49 @@ +FROM --platform=$BUILDPLATFORM sapmachine:17-jdk-headless as builder + +WORKDIR /opt/app + +RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates + + + +COPY gradlew . +COPY gradle gradle +RUN ./gradlew + +COPY build.gradle.kts settings.gradle.kts ./ +RUN ./gradlew dependencies --no-daemon + +COPY src src +RUN ./gradlew assemble --no-daemon + + +FROM sapmachine:17-jdk-headless + +RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates + +ENV PYROSCOPE_APPLICATION_NAME=rideshare.java.push.app +ENV PYROSCOPE_FORMAT=jfr +ENV PYROSCOPE_PROFILING_INTERVAL=10ms +ENV PYROSCOPE_PROFILER_EVENT=wall +ENV PYROSCOPE_PROFILER_LOCK=10ms +ENV PYROSCOPE_PROFILER_ALLOC=512k +ENV PYROSCOPE_UPLOAD_INTERVAL=15s +ENV PYROSCOPE_LOG_LEVEL=debug +ENV PYROSCOPE_SERVER_ADDRESS=http://localhost:4040 + +ENV OTEL_JAVAAGENT_EXTENSIONS=./pyroscope-otel-javaagent-extension.jar + +ENV OTEL_PYROSCOPE_ADD_PROFILE_URL=false +ENV OTEL_PYROSCOPE_ADD_PROFILE_BASELINE_URL=false +ENV OTEL_PYROSCOPE_START_PROFILING=true + +COPY --from=builder /opt/app/build/libs/rideshare-1.0-SNAPSHOT.jar /opt/app/build/libs/rideshare-1.0-SNAPSHOT.jar + +WORKDIR /opt/app + +ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.15.0/opentelemetry-javaagent.jar opentelemetry-javaagent.jar +ADD https://github.com/grafana/otel-profiling-java/releases/download/v2.0.5/pyroscope-otel-javaagent-extension.jar pyroscope-otel-javaagent-extension.jar + +EXPOSE 5000 + +CMD ["java", "-Dserver.port=5000", "-javaagent:./opentelemetry-javaagent.jar", "-jar", "./build/libs/rideshare-1.0-SNAPSHOT.jar" ] diff --git a/examples/tracing/java-wall/Dockerfile.load-generator b/examples/tracing/java-wall/Dockerfile.load-generator new file mode 100644 index 0000000000..5b4ab20553 --- /dev/null +++ b/examples/tracing/java-wall/Dockerfile.load-generator @@ -0,0 +1,9 @@ +FROM python:3.9 + +RUN pip3 install requests + +COPY load-generator.py ./load-generator.py + +ENV PYTHONUNBUFFERED=1 + +CMD [ "python", "load-generator.py" ] diff --git a/examples/tracing/java-wall/README.md b/examples/tracing/java-wall/README.md new file mode 100644 index 0000000000..59b5107731 --- /dev/null +++ b/examples/tracing/java-wall/README.md @@ -0,0 +1,53 @@ +# Span Profiles with Grafana Tempo and Pyroscope + +The docker compose consists of: +- The Java Rideshare App +- Tempo +- Pyroscope +- Grafana + +The `rideshare` app generate traces and profiling data that should be available in Grafana. +Datasources for Pyroscope and Tempo are provisioned automatically. + +### Build and run + +The project can be run locally with the following commands: + +```shell +# (optionally) pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +# build and run the example +docker compose up --build +``` + +Navigate to the [Explore page](http://localhost:3000/explore?schemaVersion=1&panes=%7B%22f36%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22rideshare.java.push.app%22%5D,%22valueType%22:%22string%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-15m%22,%22to%22:%22now%22%7D%7D%7D&orgId=1), select a trace and click on a span that has a linked profile: + +![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593) + +By default, only the root span gets labeled (the first span created locally): such spans are marked with the _link_ icon +and have the `pyroscope.profile.id` attribute set to the corresponding span ID. +Please note that presence of the attribute does not necessarily +indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is +less than the sample interval (10ms). + +### Instrumentation + +The `rideshare` demo application is instrumented with OpenTelemetry: [OTel integration](https://github.com/grafana/otel-profiling-java) + +### Grafana Tempo configuration + +In order to correlate trace spans with profiling data, the Tempo datasource should have the following configured: +- The profiling data source +- Tags to use when making profiling queries + +![image](https://github.com/grafana/pyroscope/assets/12090599/380ac574-a298-440d-acfb-7bc0935a3a7c) + +While tags are optional, configuring them is highly recommended for optimizing query performance. +In our example, we configured the `service.name` tag for use in Pyroscope queries as the `service_name` label. +This configuration restricts the data set for lookup, ensuring that queries remain +consistently fast. Note that the tags you configure must be present in the span attributes or resources +for a trace to profiles span link to appear. + +Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details. diff --git a/examples/tracing/java-wall/build.gradle.kts b/examples/tracing/java-wall/build.gradle.kts new file mode 100644 index 0000000000..68b97bb86e --- /dev/null +++ b/examples/tracing/java-wall/build.gradle.kts @@ -0,0 +1,24 @@ +plugins { + id("java") + id("org.springframework.boot") version "2.7.0" + id("io.spring.dependency-management") version "1.0.11.RELEASE" +} + +group = "org.example" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + implementation("io.pyroscope:agent:2.1.2") + + implementation("org.springframework.boot:spring-boot-starter-web") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2") +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/examples/tracing/java-wall/docker-compose.yml b/examples/tracing/java-wall/docker-compose.yml new file mode 100644 index 0000000000..4bd356ad02 --- /dev/null +++ b/examples/tracing/java-wall/docker-compose.yml @@ -0,0 +1,74 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + us-east: + ports: + - "5000" + environment: &env + OTLP_URL: tempo:4318 + OTLP_INSECURE: 1 + OTEL_TRACES_EXPORTER: otlp + OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4317 + OTEL_EXPORTER_OTLP_PROTOCOL: grpc + OTEL_SERVICE_NAME: rideshare.java.push.app + OTEL_METRICS_EXPORTER: none + OTEL_TRACES_SAMPLER: always_on + OTEL_PROPAGATORS: tracecontext + REGION: us-east + PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040 + build: + context: . + eu-north: + ports: + - "5000" + environment: + <<: *env + REGION: eu-north + build: + context: . + ap-south: + ports: + - "5000" + environment: + <<: *env + REGION: ap-south + build: + context: . + + load-generator: + build: + context: . + dockerfile: Dockerfile.load-generator + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 + tempo: + # This service is generated from examples/_templates/tempo/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/tempo:2.10.5 + command: [ "-config.file=/etc/tempo.yml" ] + volumes: + - ./tempo/tempo.yml:/etc/tempo.yml + ports: + - "14268:14268" # jaeger ingest + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin diff --git a/examples/tracing/java-wall/gradle/wrapper/gradle-wrapper.jar b/examples/tracing/java-wall/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..41d9927a4d Binary files /dev/null and b/examples/tracing/java-wall/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/tracing/java-wall/gradle/wrapper/gradle-wrapper.properties b/examples/tracing/java-wall/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..84a0b92f9a --- /dev/null +++ b/examples/tracing/java-wall/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/tracing/java-wall/gradlew b/examples/tracing/java-wall/gradlew new file mode 100755 index 0000000000..1b6c787337 --- /dev/null +++ b/examples/tracing/java-wall/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/tracing/java-wall/gradlew.bat b/examples/tracing/java-wall/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/examples/tracing/java-wall/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/tracing/java-wall/grafana-provisioning/datasources/pyroscope.yml b/examples/tracing/java-wall/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/tracing/java-wall/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/tracing/java-wall/grafana-provisioning/datasources/tempo.yml b/examples/tracing/java-wall/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..a225551398 --- /dev/null +++ b/examples/tracing/java-wall/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,29 @@ +# This file is generated from the template: +# examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/tracing/java-wall/load-generator.py b/examples/tracing/java-wall/load-generator.py new file mode 100644 index 0000000000..d5e55d324e --- /dev/null +++ b/examples/tracing/java-wall/load-generator.py @@ -0,0 +1,32 @@ +import random +import requests +import time +import traceback + +HOSTS = [ + 'us-east', + 'eu-north', + 'ap-south', +] + +VEHICLES = [ + 'bike', + 'scooter', + 'car', +] + +if __name__ == "__main__": + print(f"starting load generator") + time.sleep(3) + while True: + host = HOSTS[random.randint(0, len(HOSTS) - 1)] + vehicle = VEHICLES[random.randint(0, len(VEHICLES) - 1)] + print(f"requesting {vehicle} from {host}") + try: + resp = requests.get(f'http://{host}:5000/{vehicle}') + resp.raise_for_status() + print(f"received {resp}") + except BaseException as e: + print (f"http error {e}") + + time.sleep(random.uniform(0.2, 0.4)) diff --git a/examples/tracing/java-wall/settings.gradle.kts b/examples/tracing/java-wall/settings.gradle.kts new file mode 100644 index 0000000000..f0cca049c3 --- /dev/null +++ b/examples/tracing/java-wall/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "rideshare" diff --git a/examples/tracing/java-wall/src/main/java/org/example/rideshare/Main.java b/examples/tracing/java-wall/src/main/java/org/example/rideshare/Main.java new file mode 100644 index 0000000000..0193789a45 --- /dev/null +++ b/examples/tracing/java-wall/src/main/java/org/example/rideshare/Main.java @@ -0,0 +1,17 @@ +package org.example.rideshare; + +import io.pyroscope.labels.v2.Pyroscope; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.util.Map; + +@SpringBootApplication +public class Main { + public static void main(String[] args) { + Pyroscope.setStaticLabels(Map.of( + "region", System.getenv("REGION"), + "hostname", System.getenv("HOSTNAME"))); + SpringApplication.run(Main.class, args); + } +} diff --git a/examples/tracing/java-wall/src/main/java/org/example/rideshare/OrderService.java b/examples/tracing/java-wall/src/main/java/org/example/rideshare/OrderService.java new file mode 100644 index 0000000000..cbd3074010 --- /dev/null +++ b/examples/tracing/java-wall/src/main/java/org/example/rideshare/OrderService.java @@ -0,0 +1,85 @@ +package org.example.rideshare; + +import io.pyroscope.labels.v2.LabelsSet; +import io.pyroscope.labels.v2.Pyroscope; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.concurrent.atomic.AtomicLong; + +@Service +public class OrderService { + + public static final Duration OP_DURATION = Duration.of(200, ChronoUnit.MILLIS); + + public void findNearestVehicle(int searchRadius, String vehicle) { + Pyroscope.LabelsWrapper.run(new LabelsSet("vehicle", vehicle), () -> { + AtomicLong i = new AtomicLong(); + Instant end = Instant.now() + .plus(OP_DURATION.multipliedBy(searchRadius)); + while (Instant.now().compareTo(end) <= 0) { + i.incrementAndGet(); + } + waitForVehicleResponse(searchRadius); + + if (vehicle.equals("car")) { + checkDriverAvailability(searchRadius); + } + }); + } + + private void waitForVehicleResponse(int searchRadius) { + try { + Thread.sleep(OP_DURATION.multipliedBy(searchRadius).toMillis()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + private void checkDriverAvailability(int searchRadius) { + AtomicLong i = new AtomicLong(); + Instant end = Instant.now() + .plus(OP_DURATION.multipliedBy(searchRadius)); + while (Instant.now().compareTo(end) <= 0) { + i.incrementAndGet(); + } + waitForDriverConfirmation(searchRadius); + // Every other minute this will artificially create make requests in eu-north region slow + // this is just for demonstration purposes to show how performance impacts show up in the + // flamegraph + boolean force_mutex_lock = Instant.now().atZone(ZoneOffset.UTC).getMinute() % 2 == 0; + if (System.getenv("REGION").equals("eu-north") && force_mutex_lock) { + mutexLock(searchRadius); + } + } + + private void waitForDriverConfirmation(int searchRadius) { + try { + Thread.sleep(OP_DURATION.multipliedBy(searchRadius).toMillis()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + private void mutexLock(int searchRadius) { + AtomicLong i = new AtomicLong(); + Instant end = Instant.now() + .plus(OP_DURATION.multipliedBy(30L * searchRadius)); + while (Instant.now().compareTo(end) <= 0) { + i.incrementAndGet(); + } + waitForMutexRelease(searchRadius); + } + + private void waitForMutexRelease(int searchRadius) { + try { + Thread.sleep(OP_DURATION.multipliedBy(30L * searchRadius).toMillis()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + +} diff --git a/examples/tracing/java-wall/src/main/java/org/example/rideshare/RideShareController.java b/examples/tracing/java-wall/src/main/java/org/example/rideshare/RideShareController.java new file mode 100644 index 0000000000..74b9531df4 --- /dev/null +++ b/examples/tracing/java-wall/src/main/java/org/example/rideshare/RideShareController.java @@ -0,0 +1,51 @@ +package org.example.rideshare; + +import org.example.rideshare.bike.BikeService; +import org.example.rideshare.car.CarService; +import org.example.rideshare.scooter.ScooterService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +public class RideShareController { + + + @Autowired + CarService carService; + + @Autowired + ScooterService scooterService; + + @Autowired + BikeService bikeService; + + @GetMapping("/bike") + public String orderBike() { + bikeService.orderBike(/* searchRadius */ 1); + return "

Bike ordered

"; + } + + @GetMapping("/scooter") + public String orderScooter() { + scooterService.orderScooter(/* searchRadius */ 2); + return "

Scooter ordered

"; + } + + @GetMapping("/car") + public String orderCar() { + carService.orderCar(/* searchRadius */ 3); + return "

Car ordered

"; + } + + @GetMapping("/") + public String env() { + StringBuilder sb = new StringBuilder(); + for (Map.Entry it : System.getenv().entrySet()) { + sb.append(it.getKey()).append(" = ").append(it.getValue()).append("
\n"); + } + return sb.toString(); + } +} diff --git a/examples/tracing/java-wall/src/main/java/org/example/rideshare/bike/BikeService.java b/examples/tracing/java-wall/src/main/java/org/example/rideshare/bike/BikeService.java new file mode 100644 index 0000000000..bec8bb39cf --- /dev/null +++ b/examples/tracing/java-wall/src/main/java/org/example/rideshare/bike/BikeService.java @@ -0,0 +1,15 @@ +package org.example.rideshare.bike; + +import org.example.rideshare.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class BikeService { + @Autowired + OrderService orderService; + + public void orderBike(int searchRadius) { + orderService.findNearestVehicle(searchRadius, "bike"); + } +} diff --git a/examples/tracing/java-wall/src/main/java/org/example/rideshare/car/CarService.java b/examples/tracing/java-wall/src/main/java/org/example/rideshare/car/CarService.java new file mode 100644 index 0000000000..ee60352069 --- /dev/null +++ b/examples/tracing/java-wall/src/main/java/org/example/rideshare/car/CarService.java @@ -0,0 +1,16 @@ +package org.example.rideshare.car; + +import org.example.rideshare.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class CarService { + @Autowired + OrderService orderService; + + public void orderCar(int searchRadius) { + orderService.findNearestVehicle(searchRadius, "car"); + } + +} diff --git a/examples/tracing/java-wall/src/main/java/org/example/rideshare/scooter/ScooterService.java b/examples/tracing/java-wall/src/main/java/org/example/rideshare/scooter/ScooterService.java new file mode 100644 index 0000000000..f321ab4776 --- /dev/null +++ b/examples/tracing/java-wall/src/main/java/org/example/rideshare/scooter/ScooterService.java @@ -0,0 +1,16 @@ +package org.example.rideshare.scooter; + +import org.example.rideshare.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ScooterService { + @Autowired + OrderService orderService; + + public void orderScooter(int searchRadius) { + orderService.findNearestVehicle(searchRadius, "scooter"); + } + +} diff --git a/examples/tracing/java-wall/tempo/tempo.yml b/examples/tracing/java-wall/tempo/tempo.yml new file mode 100644 index 0000000000..6db27a824c --- /dev/null +++ b/examples/tracing/java-wall/tempo/tempo.yml @@ -0,0 +1,38 @@ +# This file is generated from the template: +# examples/_templates/tempo/tempo/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + opencensus: + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks diff --git a/examples/tracing/java/.gitignore b/examples/tracing/java/.gitignore new file mode 100644 index 0000000000..cb6a621933 --- /dev/null +++ b/examples/tracing/java/.gitignore @@ -0,0 +1,6 @@ +build/ +.idea/ +.gradle +pyroscope.jar +out/ +bin/ diff --git a/examples/tracing/java/Dockerfile b/examples/tracing/java/Dockerfile new file mode 100644 index 0000000000..1cdb70d10b --- /dev/null +++ b/examples/tracing/java/Dockerfile @@ -0,0 +1,49 @@ +FROM --platform=$BUILDPLATFORM sapmachine:17-jdk-headless as builder + +WORKDIR /opt/app + +RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates + + + +COPY gradlew . +COPY gradle gradle +RUN ./gradlew + +COPY build.gradle.kts settings.gradle.kts ./ +RUN ./gradlew dependencies --no-daemon + +COPY src src +RUN ./gradlew assemble --no-daemon + + +FROM sapmachine:17-jdk-headless + +RUN apt-get update && apt-get install ca-certificates -y && update-ca-certificates + +ENV PYROSCOPE_APPLICATION_NAME=rideshare.java.push.app +ENV PYROSCOPE_FORMAT=jfr +ENV PYROSCOPE_PROFILING_INTERVAL=10ms +ENV PYROSCOPE_PROFILER_EVENT=itimer +ENV PYROSCOPE_PROFILER_LOCK=10ms +ENV PYROSCOPE_PROFILER_ALLOC=512k +ENV PYROSCOPE_UPLOAD_INTERVAL=15s +ENV PYROSCOPE_LOG_LEVEL=debug +ENV PYROSCOPE_SERVER_ADDRESS=http://localhost:4040 + +ENV OTEL_JAVAAGENT_EXTENSIONS=./pyroscope-otel-javaagent-extension.jar + +ENV OTEL_PYROSCOPE_ADD_PROFILE_URL=false +ENV OTEL_PYROSCOPE_ADD_PROFILE_BASELINE_URL=false +ENV OTEL_PYROSCOPE_START_PROFILING=true + +COPY --from=builder /opt/app/build/libs/rideshare-1.0-SNAPSHOT.jar /opt/app/build/libs/rideshare-1.0-SNAPSHOT.jar + +WORKDIR /opt/app + +ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.15.0/opentelemetry-javaagent.jar opentelemetry-javaagent.jar +ADD https://github.com/grafana/otel-profiling-java/releases/download/v2.0.5/pyroscope-otel-javaagent-extension.jar pyroscope-otel-javaagent-extension.jar + +EXPOSE 5000 + +CMD ["java", "-Dserver.port=5000", "-javaagent:./opentelemetry-javaagent.jar", "-jar", "./build/libs/rideshare-1.0-SNAPSHOT.jar" ] diff --git a/examples/tracing/java/Dockerfile.load-generator b/examples/tracing/java/Dockerfile.load-generator new file mode 100644 index 0000000000..5b4ab20553 --- /dev/null +++ b/examples/tracing/java/Dockerfile.load-generator @@ -0,0 +1,9 @@ +FROM python:3.9 + +RUN pip3 install requests + +COPY load-generator.py ./load-generator.py + +ENV PYTHONUNBUFFERED=1 + +CMD [ "python", "load-generator.py" ] diff --git a/examples/tracing/java/README.md b/examples/tracing/java/README.md new file mode 100644 index 0000000000..59b5107731 --- /dev/null +++ b/examples/tracing/java/README.md @@ -0,0 +1,53 @@ +# Span Profiles with Grafana Tempo and Pyroscope + +The docker compose consists of: +- The Java Rideshare App +- Tempo +- Pyroscope +- Grafana + +The `rideshare` app generate traces and profiling data that should be available in Grafana. +Datasources for Pyroscope and Tempo are provisioned automatically. + +### Build and run + +The project can be run locally with the following commands: + +```shell +# (optionally) pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +# build and run the example +docker compose up --build +``` + +Navigate to the [Explore page](http://localhost:3000/explore?schemaVersion=1&panes=%7B%22f36%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22rideshare.java.push.app%22%5D,%22valueType%22:%22string%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-15m%22,%22to%22:%22now%22%7D%7D%7D&orgId=1), select a trace and click on a span that has a linked profile: + +![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593) + +By default, only the root span gets labeled (the first span created locally): such spans are marked with the _link_ icon +and have the `pyroscope.profile.id` attribute set to the corresponding span ID. +Please note that presence of the attribute does not necessarily +indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is +less than the sample interval (10ms). + +### Instrumentation + +The `rideshare` demo application is instrumented with OpenTelemetry: [OTel integration](https://github.com/grafana/otel-profiling-java) + +### Grafana Tempo configuration + +In order to correlate trace spans with profiling data, the Tempo datasource should have the following configured: +- The profiling data source +- Tags to use when making profiling queries + +![image](https://github.com/grafana/pyroscope/assets/12090599/380ac574-a298-440d-acfb-7bc0935a3a7c) + +While tags are optional, configuring them is highly recommended for optimizing query performance. +In our example, we configured the `service.name` tag for use in Pyroscope queries as the `service_name` label. +This configuration restricts the data set for lookup, ensuring that queries remain +consistently fast. Note that the tags you configure must be present in the span attributes or resources +for a trace to profiles span link to appear. + +Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details. diff --git a/examples/tracing/java/build.gradle.kts b/examples/tracing/java/build.gradle.kts new file mode 100644 index 0000000000..423296c94a --- /dev/null +++ b/examples/tracing/java/build.gradle.kts @@ -0,0 +1,24 @@ +plugins { + id("java") + id("org.springframework.boot") version "2.7.0" + id("io.spring.dependency-management") version "1.0.11.RELEASE" +} + +group = "org.example" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + implementation("io.pyroscope:agent:2.5.4") + + implementation("org.springframework.boot:spring-boot-starter-web") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2") +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/examples/tracing/java/docker-compose.yml b/examples/tracing/java/docker-compose.yml new file mode 100644 index 0000000000..4bd356ad02 --- /dev/null +++ b/examples/tracing/java/docker-compose.yml @@ -0,0 +1,74 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + us-east: + ports: + - "5000" + environment: &env + OTLP_URL: tempo:4318 + OTLP_INSECURE: 1 + OTEL_TRACES_EXPORTER: otlp + OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4317 + OTEL_EXPORTER_OTLP_PROTOCOL: grpc + OTEL_SERVICE_NAME: rideshare.java.push.app + OTEL_METRICS_EXPORTER: none + OTEL_TRACES_SAMPLER: always_on + OTEL_PROPAGATORS: tracecontext + REGION: us-east + PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040 + build: + context: . + eu-north: + ports: + - "5000" + environment: + <<: *env + REGION: eu-north + build: + context: . + ap-south: + ports: + - "5000" + environment: + <<: *env + REGION: ap-south + build: + context: . + + load-generator: + build: + context: . + dockerfile: Dockerfile.load-generator + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 + tempo: + # This service is generated from examples/_templates/tempo/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/tempo:2.10.5 + command: [ "-config.file=/etc/tempo.yml" ] + volumes: + - ./tempo/tempo.yml:/etc/tempo.yml + ports: + - "14268:14268" # jaeger ingest + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin diff --git a/examples/tracing/java/gradle/wrapper/gradle-wrapper.jar b/examples/tracing/java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..41d9927a4d Binary files /dev/null and b/examples/tracing/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/tracing/java/gradle/wrapper/gradle-wrapper.properties b/examples/tracing/java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..84a0b92f9a --- /dev/null +++ b/examples/tracing/java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/tracing/java/gradlew b/examples/tracing/java/gradlew new file mode 100755 index 0000000000..1b6c787337 --- /dev/null +++ b/examples/tracing/java/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/tracing/java/gradlew.bat b/examples/tracing/java/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/examples/tracing/java/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/tracing/java/grafana-provisioning/datasources/pyroscope.yml b/examples/tracing/java/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/tracing/java/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/tracing/java/grafana-provisioning/datasources/tempo.yml b/examples/tracing/java/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..a225551398 --- /dev/null +++ b/examples/tracing/java/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,29 @@ +# This file is generated from the template: +# examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/tracing/java/load-generator.py b/examples/tracing/java/load-generator.py new file mode 100644 index 0000000000..d5e55d324e --- /dev/null +++ b/examples/tracing/java/load-generator.py @@ -0,0 +1,32 @@ +import random +import requests +import time +import traceback + +HOSTS = [ + 'us-east', + 'eu-north', + 'ap-south', +] + +VEHICLES = [ + 'bike', + 'scooter', + 'car', +] + +if __name__ == "__main__": + print(f"starting load generator") + time.sleep(3) + while True: + host = HOSTS[random.randint(0, len(HOSTS) - 1)] + vehicle = VEHICLES[random.randint(0, len(VEHICLES) - 1)] + print(f"requesting {vehicle} from {host}") + try: + resp = requests.get(f'http://{host}:5000/{vehicle}') + resp.raise_for_status() + print(f"received {resp}") + except BaseException as e: + print (f"http error {e}") + + time.sleep(random.uniform(0.2, 0.4)) diff --git a/examples/tracing/java/settings.gradle.kts b/examples/tracing/java/settings.gradle.kts new file mode 100644 index 0000000000..f0cca049c3 --- /dev/null +++ b/examples/tracing/java/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "rideshare" diff --git a/examples/tracing/java/src/main/java/org/example/rideshare/Main.java b/examples/tracing/java/src/main/java/org/example/rideshare/Main.java new file mode 100644 index 0000000000..0193789a45 --- /dev/null +++ b/examples/tracing/java/src/main/java/org/example/rideshare/Main.java @@ -0,0 +1,17 @@ +package org.example.rideshare; + +import io.pyroscope.labels.v2.Pyroscope; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import java.util.Map; + +@SpringBootApplication +public class Main { + public static void main(String[] args) { + Pyroscope.setStaticLabels(Map.of( + "region", System.getenv("REGION"), + "hostname", System.getenv("HOSTNAME"))); + SpringApplication.run(Main.class, args); + } +} diff --git a/examples/tracing/java/src/main/java/org/example/rideshare/OrderService.java b/examples/tracing/java/src/main/java/org/example/rideshare/OrderService.java new file mode 100644 index 0000000000..d86cd15b7e --- /dev/null +++ b/examples/tracing/java/src/main/java/org/example/rideshare/OrderService.java @@ -0,0 +1,58 @@ +package org.example.rideshare; + +import io.pyroscope.labels.v2.LabelsSet; +import io.pyroscope.labels.v2.Pyroscope; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.concurrent.atomic.AtomicLong; + +@Service +public class OrderService { + + public static final Duration OP_DURATION = Duration.of(200, ChronoUnit.MILLIS); + + public synchronized void findNearestVehicle(int searchRadius, String vehicle) { + Pyroscope.LabelsWrapper.run(new LabelsSet("vehicle", vehicle), () -> { + AtomicLong i = new AtomicLong(); + Instant end = Instant.now() + .plus(OP_DURATION.multipliedBy(searchRadius)); + while (Instant.now().compareTo(end) <= 0) { + i.incrementAndGet(); + } + + if (vehicle.equals("car")) { + checkDriverAvailability(searchRadius); + } + }); + } + + private void checkDriverAvailability(int searchRadius) { + AtomicLong i = new AtomicLong(); + Instant end = Instant.now() + .plus(OP_DURATION.multipliedBy(searchRadius)); + while (Instant.now().compareTo(end) <= 0) { + i.incrementAndGet(); + } + // Every other minute this will artificially create make requests in eu-north region slow + // this is just for demonstration purposes to show how performance impacts show up in the + // flamegraph + boolean force_mutex_lock = Instant.now().atZone(ZoneOffset.UTC).getMinute() % 2 == 0; + if (System.getenv("REGION").equals("eu-north") && force_mutex_lock) { + mutexLock(searchRadius); + } + } + + private void mutexLock(int searchRadius) { + AtomicLong i = new AtomicLong(); + Instant end = Instant.now() + .plus(OP_DURATION.multipliedBy(30L * searchRadius)); + while (Instant.now().compareTo(end) <= 0) { + i.incrementAndGet(); + } + } + +} diff --git a/examples/tracing/java/src/main/java/org/example/rideshare/RideShareController.java b/examples/tracing/java/src/main/java/org/example/rideshare/RideShareController.java new file mode 100644 index 0000000000..74b9531df4 --- /dev/null +++ b/examples/tracing/java/src/main/java/org/example/rideshare/RideShareController.java @@ -0,0 +1,51 @@ +package org.example.rideshare; + +import org.example.rideshare.bike.BikeService; +import org.example.rideshare.car.CarService; +import org.example.rideshare.scooter.ScooterService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +public class RideShareController { + + + @Autowired + CarService carService; + + @Autowired + ScooterService scooterService; + + @Autowired + BikeService bikeService; + + @GetMapping("/bike") + public String orderBike() { + bikeService.orderBike(/* searchRadius */ 1); + return "

Bike ordered

"; + } + + @GetMapping("/scooter") + public String orderScooter() { + scooterService.orderScooter(/* searchRadius */ 2); + return "

Scooter ordered

"; + } + + @GetMapping("/car") + public String orderCar() { + carService.orderCar(/* searchRadius */ 3); + return "

Car ordered

"; + } + + @GetMapping("/") + public String env() { + StringBuilder sb = new StringBuilder(); + for (Map.Entry it : System.getenv().entrySet()) { + sb.append(it.getKey()).append(" = ").append(it.getValue()).append("
\n"); + } + return sb.toString(); + } +} diff --git a/examples/tracing/java/src/main/java/org/example/rideshare/bike/BikeService.java b/examples/tracing/java/src/main/java/org/example/rideshare/bike/BikeService.java new file mode 100644 index 0000000000..bec8bb39cf --- /dev/null +++ b/examples/tracing/java/src/main/java/org/example/rideshare/bike/BikeService.java @@ -0,0 +1,15 @@ +package org.example.rideshare.bike; + +import org.example.rideshare.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class BikeService { + @Autowired + OrderService orderService; + + public void orderBike(int searchRadius) { + orderService.findNearestVehicle(searchRadius, "bike"); + } +} diff --git a/examples/tracing/java/src/main/java/org/example/rideshare/car/CarService.java b/examples/tracing/java/src/main/java/org/example/rideshare/car/CarService.java new file mode 100644 index 0000000000..ee60352069 --- /dev/null +++ b/examples/tracing/java/src/main/java/org/example/rideshare/car/CarService.java @@ -0,0 +1,16 @@ +package org.example.rideshare.car; + +import org.example.rideshare.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class CarService { + @Autowired + OrderService orderService; + + public void orderCar(int searchRadius) { + orderService.findNearestVehicle(searchRadius, "car"); + } + +} diff --git a/examples/tracing/java/src/main/java/org/example/rideshare/scooter/ScooterService.java b/examples/tracing/java/src/main/java/org/example/rideshare/scooter/ScooterService.java new file mode 100644 index 0000000000..f321ab4776 --- /dev/null +++ b/examples/tracing/java/src/main/java/org/example/rideshare/scooter/ScooterService.java @@ -0,0 +1,16 @@ +package org.example.rideshare.scooter; + +import org.example.rideshare.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ScooterService { + @Autowired + OrderService orderService; + + public void orderScooter(int searchRadius) { + orderService.findNearestVehicle(searchRadius, "scooter"); + } + +} diff --git a/examples/tracing/java/tempo/tempo.yml b/examples/tracing/java/tempo/tempo.yml new file mode 100644 index 0000000000..6db27a824c --- /dev/null +++ b/examples/tracing/java/tempo/tempo.yml @@ -0,0 +1,38 @@ +# This file is generated from the template: +# examples/_templates/tempo/tempo/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + opencensus: + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks diff --git a/examples/tracing/python/Dockerfile b/examples/tracing/python/Dockerfile new file mode 100644 index 0000000000..a29e3058a0 --- /dev/null +++ b/examples/tracing/python/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.9 + +RUN pip3 install flask pyroscope-io==0.8.8 pyroscope-otel==0.4.0 +RUN pip3 install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-flask opentelemetry-exporter-otlp-proto-grpc + +ENV FLASK_ENV=development +ENV PYTHONUNBUFFERED=1 + +COPY lib ./lib +CMD [ "python", "lib/server.py" ] diff --git a/examples/tracing/python/README.md b/examples/tracing/python/README.md new file mode 100644 index 0000000000..1a6e1c5a83 --- /dev/null +++ b/examples/tracing/python/README.md @@ -0,0 +1,54 @@ +# Span Profiles with Grafana Tempo and Pyroscope + +The docker compose consists of: +- Three Python Rideshare App instances (us-east, eu-north, ap-south regions) +- Tempo for trace collection +- Pyroscope for continuous profiling +- Grafana for visualization +- Load Generator for simulating traffic + +For a detailed guide about Python span profiles configuration, refer to the docs [Pyroscope documentation](https://grafana.com/docs/pyroscope/latest/configure-client/trace-span-profiles/python-span-profiles/). + +The `rideshare` app generates traces and profiling data that should be available in Grafana. +Pyroscope and Tempo datasources are provisioned automatically. + +### Build and run + +The project can be run locally with the following commands: + +```shell +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +docker compose up +``` +The load generator will automatically start sending requests to all regional instances. + +### Viewing Traces and Profiles + +Navigate to the [Explore page](http://localhost:3000/explore?schemaVersion=1&panes=%7B%22yM9%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22rideshare.python.push.app%22%5D,%22valueType%22:%22string%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-6h%22,%22to%22:%22now%22%7D%7D%7D&orgId=1), select a trace and click on a span that has a linked profile: + +![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593) + +By default, only the root span gets labeled (the first span created locally): such spans are marked with the link icon +and have `pyroscope.profile.id` attribute set to the corresponding span ID. +Please note that presence of the attribute does not necessarily +indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is +less than the sample interval (10ms). + +### Grafana Tempo configuration + +In order to correlate trace spans with profiling data, the Tempo datasource should have the following configured: +- The profiling data source +- Tags to use when making profiling queries + +![image](https://github.com/grafana/pyroscope/assets/12090599/380ac574-a298-440d-acfb-7bc0935a3a7c) + +While tags are optional, configuring them is highly recommended for optimizing query performance. +In our example, we configured the `service.name` tag for use in Pyroscope queries as the `service_name` label. +This configuration restricts the data set for lookup, ensuring that queries remain +consistently fast. Note that the tags you configure must be present in the span attributes or resources +for a trace to profiles span link to appear. + +Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details. diff --git a/examples/tracing/python/docker-compose.yaml b/examples/tracing/python/docker-compose.yaml new file mode 100644 index 0000000000..e70a5d1fd2 --- /dev/null +++ b/examples/tracing/python/docker-compose.yaml @@ -0,0 +1,90 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + us-east: + ports: + - "5000" + hostname: us-east + environment: &env + OTLP_URL: tempo:4318 + OTLP_INSECURE: 1 + DEBUG_LOGGER: 1 + OTEL_TRACES_EXPORTER: otlp + OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4317 + OTEL_SERVICE_NAME: rideshare.python.push.app + OTEL_METRICS_EXPORTER: none + OTEL_TRACES_SAMPLER: always_on + OTEL_PROPAGATORS: tracecontext + PYROSCOPE_LABELS: hostname=us-east + REGION: us-east + PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040 + PYTHONUNBUFFERED: 1 # Python-specific: Ensures logging output isn't buffered + build: + context: . + + eu-north: + ports: + - "5000" + hostname: eu-north + environment: + <<: *env + REGION: eu-north + PYROSCOPE_LABELS: hostname=eu-north + build: + context: . + + ap-south: + ports: + - "5000" + hostname: ap-south + environment: + <<: *env + REGION: ap-south + PYROSCOPE_LABELS: hostname=ap-south + build: + context: . + + load-generator: + environment: + <<: *env + build: + context: ../../language-sdk-instrumentation/golang-push/rideshare + dockerfile: Dockerfile.load-generator + command: + - ./loadgen + - http://ap-south:5000 + - http://eu-north:5000 + - http://us-east:5000 + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 + tempo: + # This service is generated from examples/_templates/tempo/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/tempo:2.10.5 + command: [ "-config.file=/etc/tempo.yml" ] + volumes: + - ./tempo/tempo.yml:/etc/tempo.yml + ports: + - "14268:14268" # jaeger ingest + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin diff --git a/examples/tracing/python/grafana-provisioning/datasources/pyroscope.yml b/examples/tracing/python/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/tracing/python/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/tracing/python/grafana-provisioning/datasources/tempo.yml b/examples/tracing/python/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..a225551398 --- /dev/null +++ b/examples/tracing/python/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,29 @@ +# This file is generated from the template: +# examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/tracing/python/lib/__init__.py b/examples/tracing/python/lib/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/tracing/python/lib/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/tracing/python/lib/bike/__init__.py b/examples/tracing/python/lib/bike/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/tracing/python/lib/bike/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/tracing/python/lib/bike/bike.py b/examples/tracing/python/lib/bike/bike.py new file mode 100644 index 0000000000..3d132725c2 --- /dev/null +++ b/examples/tracing/python/lib/bike/bike.py @@ -0,0 +1,4 @@ +from utility.utility import find_nearest_vehicle + +def order_bike(search_radius): + find_nearest_vehicle(search_radius, "bike") diff --git a/examples/tracing/python/lib/car/__init__.py b/examples/tracing/python/lib/car/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/tracing/python/lib/car/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/tracing/python/lib/car/car.py b/examples/tracing/python/lib/car/car.py new file mode 100644 index 0000000000..2cadff0c2f --- /dev/null +++ b/examples/tracing/python/lib/car/car.py @@ -0,0 +1,4 @@ +from utility.utility import find_nearest_vehicle + +def order_car(search_radius): + find_nearest_vehicle(search_radius, "car") diff --git a/examples/tracing/python/lib/scooter/__init__.py b/examples/tracing/python/lib/scooter/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/tracing/python/lib/scooter/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/tracing/python/lib/scooter/scooter.py b/examples/tracing/python/lib/scooter/scooter.py new file mode 100644 index 0000000000..455ca1a3dc --- /dev/null +++ b/examples/tracing/python/lib/scooter/scooter.py @@ -0,0 +1,4 @@ +from utility.utility import find_nearest_vehicle + +def order_scooter(search_radius): + find_nearest_vehicle(search_radius, "scooter") diff --git a/examples/tracing/python/lib/server.py b/examples/tracing/python/lib/server.py new file mode 100644 index 0000000000..4a8073e7e1 --- /dev/null +++ b/examples/tracing/python/lib/server.py @@ -0,0 +1,68 @@ +import os + +import pyroscope +from flask import Flask + +# OpenTelemetry +from opentelemetry.instrumentation.flask import FlaskInstrumentor +from opentelemetry import trace +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import BatchSpanProcessor +from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter +from pyroscope.otel import PyroscopeSpanProcessor + +from bike.bike import order_bike +from car.car import order_car +from scooter.scooter import order_scooter + +provider = TracerProvider() +provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter())) +provider.add_span_processor(PyroscopeSpanProcessor()) + +# Sets the global default tracer provider +trace.set_tracer_provider(provider) + +app_name = os.getenv("PYROSCOPE_APPLICATION_NAME", "rideshare.python.push.app") +server_addr = os.getenv("PYROSCOPE_SERVER_ADDRESS", "http://pyroscope:4040") +basic_auth_username = os.getenv("PYROSCOPE_BASIC_AUTH_USER", "") +basic_auth_password = os.getenv("PYROSCOPE_BASIC_AUTH_PASSWORD", "") +port = int(os.getenv("RIDESHARE_LISTEN_PORT", "5000")) + +pyroscope.configure( + application_name = app_name, + server_address = server_addr, + basic_auth_username = basic_auth_username, # for grafana cloud + basic_auth_password = basic_auth_password, # for grafana cloud + tags = { + "region": f'{os.getenv("REGION")}', + } +) + +app = Flask(__name__) +FlaskInstrumentor().instrument_app(app) + +@app.route("/bike") +def bike(): + order_bike(0.2) + return "

Bike ordered

" + +@app.route("/scooter") +def scooter(): + order_scooter(0.3) + return "

Scooter ordered

" + +@app.route("/car") +def car(): + order_car(0.4) + return "

Car ordered

" + + +@app.route("/") +def environment(): + result = "

environment vars:

" + for key, value in os.environ.items(): + result +=f"

{key}={value}

" + return result + +if __name__ == '__main__': + app.run(threaded=False, processes=1, host='0.0.0.0', port=port, debug=False) diff --git a/examples/tracing/python/lib/utility/__init__.py b/examples/tracing/python/lib/utility/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/tracing/python/lib/utility/__init__.py @@ -0,0 +1 @@ + diff --git a/examples/tracing/python/lib/utility/utility.py b/examples/tracing/python/lib/utility/utility.py new file mode 100644 index 0000000000..598ece2184 --- /dev/null +++ b/examples/tracing/python/lib/utility/utility.py @@ -0,0 +1,35 @@ +import time +import pyroscope +import os +from datetime import datetime + + +def mutex_lock(n): + i = 0 + start_time = time.time() + while time.time() - start_time < n * 10: + i += 1 + +def check_driver_availability(n): + i = 0 + start_time = time.time() + while time.time() - start_time < n / 2: + i += 1 + + # Every 4 minutes this will artificially create make requests in eu-north region slow + # this is just for demonstration purposes to show how performance impacts show up in the + # flamegraph + + force_mutex_lock = datetime.today().minute * 4 % 8 == 0 + if os.getenv("REGION") == "eu-north" and force_mutex_lock: + mutex_lock(n) + + +def find_nearest_vehicle(n, vehicle): + with pyroscope.tag_wrapper({ "vehicle": vehicle}): + i = 0 + start_time = time.time() + while time.time() - start_time < n: + i += 1 + if vehicle == "car": + check_driver_availability(n) diff --git a/examples/tracing/python/tempo/tempo.yml b/examples/tracing/python/tempo/tempo.yml new file mode 100644 index 0000000000..6db27a824c --- /dev/null +++ b/examples/tracing/python/tempo/tempo.yml @@ -0,0 +1,38 @@ +# This file is generated from the template: +# examples/_templates/tempo/tempo/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + opencensus: + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks diff --git a/examples/tracing/ruby/.ruby-version b/examples/tracing/ruby/.ruby-version new file mode 100644 index 0000000000..be94e6f53d --- /dev/null +++ b/examples/tracing/ruby/.ruby-version @@ -0,0 +1 @@ +3.2.2 diff --git a/examples/tracing/ruby/Dockerfile b/examples/tracing/ruby/Dockerfile new file mode 100644 index 0000000000..6b2fb210c4 --- /dev/null +++ b/examples/tracing/ruby/Dockerfile @@ -0,0 +1,14 @@ +FROM ruby:3.3.9 + +WORKDIR /opt/app + +COPY Gemfile ./Gemfile +COPY Gemfile.lock ./Gemfile.lock +# RUN bundle config set --local deployment true +RUN bundle install + +COPY lib ./lib + +ENV APP_ENV=production + +CMD [ "ruby", "lib/server.rb" ] diff --git a/examples/tracing/ruby/Gemfile b/examples/tracing/ruby/Gemfile new file mode 100644 index 0000000000..7f0fe19d03 --- /dev/null +++ b/examples/tracing/ruby/Gemfile @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } + +gem 'pyroscope', '= 0.6.4' +gem "sinatra", "~> 4.1" +gem "thin", "~> 2.0" +gem 'pyroscope-otel' +gem 'opentelemetry-sdk' +gem 'opentelemetry-exporter-otlp' + +gem "rackup", "~> 2.2" +gem "puma", "~> 6.6" diff --git a/examples/tracing/ruby/Gemfile.lock b/examples/tracing/ruby/Gemfile.lock new file mode 100644 index 0000000000..29bacb0724 --- /dev/null +++ b/examples/tracing/ruby/Gemfile.lock @@ -0,0 +1,130 @@ +GEM + remote: https://rubygems.org/ + specs: + base64 (0.3.0) + bigdecimal (3.1.8) + daemons (1.4.1) + eventmachine (1.2.7) + ffi (1.17.2) + ffi (1.17.2-aarch64-linux-gnu) + ffi (1.17.2-aarch64-linux-musl) + ffi (1.17.2-arm-linux-gnu) + ffi (1.17.2-arm-linux-musl) + ffi (1.17.2-arm64-darwin) + ffi (1.17.2-x86-linux-gnu) + ffi (1.17.2-x86-linux-musl) + ffi (1.17.2-x86_64-darwin) + ffi (1.17.2-x86_64-linux-gnu) + ffi (1.17.2-x86_64-linux-musl) + google-protobuf (4.29.1) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-aarch64-linux) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-arm64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-x86-linux) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-x86_64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.29.1-x86_64-linux) + bigdecimal + rake (>= 13) + googleapis-common-protos-types (1.16.0) + google-protobuf (>= 3.18, < 5.a) + logger (1.7.0) + mustermann (3.0.3) + ruby2_keywords (~> 0.0.1) + nio4r (2.7.4) + opentelemetry-api (1.5.0) + opentelemetry-common (0.21.0) + opentelemetry-api (~> 1.0) + opentelemetry-exporter-otlp (0.29.1) + google-protobuf (>= 3.18) + googleapis-common-protos-types (~> 1.3) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-sdk (~> 1.2) + opentelemetry-semantic_conventions + opentelemetry-registry (0.3.1) + opentelemetry-api (~> 1.1) + opentelemetry-sdk (1.6.0) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-registry (~> 0.2) + opentelemetry-semantic_conventions + opentelemetry-semantic_conventions (1.10.1) + opentelemetry-api (~> 1.0) + puma (6.6.0) + nio4r (~> 2.0) + pyroscope (0.6.4) + ffi + pyroscope (0.6.4-aarch64-linux) + ffi + pyroscope (0.6.4-arm64-darwin) + ffi + pyroscope (0.6.4-x86_64-darwin) + ffi + pyroscope (0.6.4-x86_64-linux) + ffi + pyroscope-otel (0.1.4) + opentelemetry-api (~> 1.1) + pyroscope (>= 0.5.1, < 1.0) + rack (3.2.6) + rack-protection (4.1.1) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.2) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rackup (2.2.1) + rack (>= 3) + rake (13.2.1) + ruby2_keywords (0.0.5) + sinatra (4.1.1) + logger (>= 1.6.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.1.1) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + thin (2.0.1) + daemons (~> 1.0, >= 1.0.9) + eventmachine (~> 1.0, >= 1.0.4) + logger + rack (>= 1, < 4) + tilt (2.6.0) + +PLATFORMS + aarch64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + opentelemetry-exporter-otlp + opentelemetry-sdk + puma (~> 6.6) + pyroscope (= 0.6.4) + pyroscope-otel + rackup (~> 2.2) + sinatra (~> 4.1) + thin (~> 2.0) + +BUNDLED WITH + 2.5.23 diff --git a/examples/tracing/ruby/README.md b/examples/tracing/ruby/README.md new file mode 100644 index 0000000000..3fd8ca4139 --- /dev/null +++ b/examples/tracing/ruby/README.md @@ -0,0 +1,56 @@ +# Span Profiles with Grafana Tempo and Pyroscope + +The docker compose consists of: +- Three Ruby Rideshare App instances (us-east, eu-north, ap-south regions) +- Tempo for trace collection +- Pyroscope for continuous profiling +- Grafana for visualization +- Load Generator for simulating traffic + +For a detailed guide about Ruby span profiles configuration, refer to the docs [Pyroscope documentation](https://grafana.com/docs/pyroscope/latest/configure-client/trace-span-profiles/ruby-span-profiles/). + +The `rideshare` app generates traces and profiling data that should be available in Grafana. +Pyroscope and Tempo datasources are provisioned automatically. + +### Build and run + +The project can be run locally with the following commands: + +```shell +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + +bundle install + +docker compose up +``` +The load generator will automatically start sending requests to all regional instances. + +### Viewing Traces and Profiles + +Navigate to the [Explore page](http://localhost:3000/explore?schemaVersion=1&panes=%7B%22yM9%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22rideshare.ruby.push.app%22%5D,%22valueType%22:%22string%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-6h%22,%22to%22:%22now%22%7D%7D%7D&orgId=1), select a trace and click on a span that has a linked profile: + +![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593) + +By default, only the root span gets labeled (the first span created locally): such spans are marked with the link icon +and have `pyroscope.profile.id` attribute set to the corresponding span ID. +Please note that presence of the attribute does not necessarily +indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is +less than the sample interval (10ms). + +### Grafana Tempo configuration + +In order to correlate trace spans with profiling data, the Tempo datasource should have the following configured: +- The profiling data source +- Tags to use when making profiling queries + +![image](https://github.com/grafana/pyroscope/assets/12090599/380ac574-a298-440d-acfb-7bc0935a3a7c) + +While tags are optional, configuring them is highly recommended for optimizing query performance. +In our example, we configured the `service.name` tag for use in Pyroscope queries as the `service_name` label. +This configuration restricts the data set for lookup, ensuring that queries remain +consistently fast. Note that the tags you configure must be present in the span attributes or resources +for a trace to profiles span link to appear. + +Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details. diff --git a/examples/tracing/ruby/docker-compose.yml b/examples/tracing/ruby/docker-compose.yml new file mode 100644 index 0000000000..c56fa9bd3a --- /dev/null +++ b/examples/tracing/ruby/docker-compose.yml @@ -0,0 +1,91 @@ +services: + pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/pyroscope:latest + ports: + - 4040:4040 + us-east: + ports: + - "5000" + hostname: us-east + environment: &env + OTLP_URL: tempo:4318 + OTLP_INSECURE: 1 + DEBUG_LOGGER: 1 + OTEL_LOG_LEVEL: debug + OTEL_TRACES_EXPORTER: otlp + OTEL_EXPORTER_OTLP_ENDPOINT: "http://tempo:4318" + OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf" + OTEL_SDK_DEBUG: "true" + OTEL_SERVICE_NAME: rideshare.ruby.push.app + OTEL_METRICS_EXPORTER: none + OTEL_TRACES_SAMPLER: always_on + OTEL_PROPAGATORS: tracecontext + REGION: us-east + PYROSCOPE_LABELS: hostname=us-east + PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040 + build: + context: . + + eu-north: + ports: + - "5000" + hostname: eu-north + environment: + <<: *env + REGION: eu-north + PYROSCOPE_LABELS: hostname=eu-north + build: + context: . + + ap-south: + ports: + - "5000" + hostname: ap-south + environment: + <<: *env + REGION: ap-south + PYROSCOPE_LABELS: hostname=ap-south + build: + context: . + + load-generator: + environment: *env + build: + context: ../../language-sdk-instrumentation/golang-push/rideshare + dockerfile: Dockerfile.load-generator + command: + - ./loadgen + - http://us-east:5000 + - http://eu-north:5000 + - http://ap-south:5000 + + grafana: + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest + environment: + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + volumes: + - ./grafana-provisioning:/etc/grafana/provisioning + ports: + - 3000:3000 + tempo: + # This service is generated from examples/_templates/tempo/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/tempo:2.10.5 + command: [ "-config.file=/etc/tempo.yml" ] + volumes: + - ./tempo/tempo.yml:/etc/tempo.yml + ports: + - "14268:14268" # jaeger ingest + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin diff --git a/examples/tracing/ruby/grafana-provisioning/datasources/pyroscope.yml b/examples/tracing/ruby/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/tracing/ruby/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/tracing/ruby/grafana-provisioning/datasources/tempo.yml b/examples/tracing/ruby/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..a225551398 --- /dev/null +++ b/examples/tracing/ruby/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,29 @@ +# This file is generated from the template: +# examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/tracing/ruby/lib/bike/bike.rb b/examples/tracing/ruby/lib/bike/bike.rb new file mode 100644 index 0000000000..492cfae42b --- /dev/null +++ b/examples/tracing/ruby/lib/bike/bike.rb @@ -0,0 +1,5 @@ +require_relative '../utility/utility' + +def order_bike(search_radius) + find_nearest_vehicle(search_radius, "bike") +end diff --git a/examples/tracing/ruby/lib/car/car.rb b/examples/tracing/ruby/lib/car/car.rb new file mode 100644 index 0000000000..452d78d2df --- /dev/null +++ b/examples/tracing/ruby/lib/car/car.rb @@ -0,0 +1,5 @@ +require_relative '../utility/utility' + +def order_car(search_radius) + find_nearest_vehicle(search_radius, "car") +end diff --git a/examples/tracing/ruby/lib/scooter/scooter.rb b/examples/tracing/ruby/lib/scooter/scooter.rb new file mode 100644 index 0000000000..d9c13ac9da --- /dev/null +++ b/examples/tracing/ruby/lib/scooter/scooter.rb @@ -0,0 +1,5 @@ +require_relative '../utility/utility' + +def order_scooter(search_radius) + find_nearest_vehicle(search_radius, "scooter") +end diff --git a/examples/tracing/ruby/lib/server.rb b/examples/tracing/ruby/lib/server.rb new file mode 100644 index 0000000000..5e92ec332e --- /dev/null +++ b/examples/tracing/ruby/lib/server.rb @@ -0,0 +1,83 @@ +require "sinatra" +require "thin" +require "pyroscope" +require "pyroscope/otel" +require "opentelemetry-sdk" +require 'opentelemetry-exporter-otlp' +require 'opentelemetry/trace/propagation/trace_context' +require_relative 'scooter/scooter' +require_relative 'bike/bike' +require_relative 'car/car' + +app_name = ENV.fetch("PYROSCOPE_APPLICATION_NAME", "rideshare.ruby.push.app") +pyroscope_server_address = ENV.fetch("PYROSCOPE_SERVER_ADDRESS", "http://pyroscope:4040") + +Pyroscope.configure do |config| + config.app_name = app_name + config.server_address = pyroscope_server_address + config.tags = { + "region": ENV["REGION"], + } +end + +OpenTelemetry::SDK.configure do |c| + c.add_span_processor Pyroscope::Otel::SpanProcessor.new("#{app_name}.cpu", pyroscope_server_address) + + c.add_span_processor( + OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new( + OpenTelemetry::Exporter::OTLP::Exporter.new( + endpoint: 'http://tempo:4318/v1/traces' + ) + ) + ) + +end + +# Extract trace context from load generator requests to link our handler spans with the parent +# load generator trace, creating a complete distributed trace across both services. +before do + if (traceparent = request.env['HTTP_TRACEPARENT']) + # Parse traceparent: version-traceid-spanid-flags + _version, trace_id_hex, parent_span_id_hex, _flags = traceparent.split('-') + + # Get the propagator and carrier + carrier = { 'traceparent' => traceparent } + + # Extract context using the propagator + @extracted_context = OpenTelemetry.propagation.extract(carrier) + end +end + +tracer = OpenTelemetry.tracer_provider.tracer('my-tracer') + +get "/bike" do + OpenTelemetry::Context.with_current(@extracted_context) do + tracer.in_span("BikeHandler") do |span| + order_bike(0.4) + "

Bike ordered

" + end + end +end + +get "/scooter" do + OpenTelemetry::Context.with_current(@extracted_context) do + tracer.in_span("ScooterHandler") do |span| + order_scooter(0.6) + "

scooter ordered

" + end + end +end + +get "/car" do + OpenTelemetry::Context.with_current(@extracted_context) do + tracer.in_span("CarHandler") do |span| + order_car(0.8) + "

car ordered

" + end + end +end + +set :bind, '0.0.0.0' +set :port, ENV["RIDESHARE_LISTEN_PORT"] || 5000 + +run Sinatra::Application.run! diff --git a/examples/tracing/ruby/lib/utility/utility.rb b/examples/tracing/ruby/lib/utility/utility.rb new file mode 100644 index 0000000000..8f1a5edaea --- /dev/null +++ b/examples/tracing/ruby/lib/utility/utility.rb @@ -0,0 +1,38 @@ +require "pyroscope" + +def mutex_lock(n) + i = 0 + start_time = Time.new + while Time.new - start_time < n * 10 do + i += 1 + end +end + +def check_driver_availability(n) + i = 0 + start_time = Time.new + while Time.new - start_time < n / 2 do + i += 1 + end + + # Every 4 minutes this will artificially create make requests in eu-north region slow + # this is just for demonstration purposes to show how performance impacts show up in the + # flamegraph + current_time = Time.now + current_minute = current_time.strftime('%M').to_i + force_mutex_lock = (current_minute * 4 % 8) == 0 + + mutex_lock(n) if ENV["REGION"] == "eu-north" and force_mutex_lock +end + +def find_nearest_vehicle(n, vehicle) + Pyroscope.tag_wrapper({ "vehicle" => vehicle }) do + i = 0 + start_time = Time.new + while Time.new - start_time < n do + i += 1 + end + + check_driver_availability(n) if vehicle == "car" + end +end diff --git a/examples/tracing/ruby/tempo/tempo.yml b/examples/tracing/ruby/tempo/tempo.yml new file mode 100644 index 0000000000..6db27a824c --- /dev/null +++ b/examples/tracing/ruby/tempo/tempo.yml @@ -0,0 +1,38 @@ +# This file is generated from the template: +# examples/_templates/tempo/tempo/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + opencensus: + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks diff --git a/examples/tracing/tempo/README.md b/examples/tracing/tempo/README.md index a8c68eb746..c394fdf3d6 100644 --- a/examples/tracing/tempo/README.md +++ b/examples/tracing/tempo/README.md @@ -14,6 +14,10 @@ Pyroscope and Tempo datasources are provisioned automatically. The project can be run locally with the following commands: ```shell +# Pull latest pyroscope and grafana images: +docker pull grafana/pyroscope:latest +docker pull grafana/grafana:latest + docker-compose up ``` @@ -33,7 +37,7 @@ less than the sample interval (10ms). - `rideshare` demo application instrumented with OpenTelemetry: - Go [OTel integration](https://github.com/grafana/otel-profiling-go) - Java [OTel integration](https://github.com/grafana/otel-profiling-java) - - `pyroscope` itself is instrumented with `opentracing-go` SDK and [`spanprofiler`](https://github.com/grafana/dskit/tree/main/spanprofiler) for profiling integration. + - `pyroscope` itself is instrumented with OpenTelemetry and [`otel-profiling-go`](https://github.com/grafana/otel-profiling-go) for profiling integration. ### Grafana Tempo configuration diff --git a/examples/tracing/tempo/docker-compose.yml b/examples/tracing/tempo/docker-compose.yml index 04af08f274..c449c6684b 100644 --- a/examples/tracing/tempo/docker-compose.yml +++ b/examples/tracing/tempo/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3" services: rideshare-go-ap-south: @@ -24,26 +23,7 @@ services: build: context: ../../language-sdk-instrumentation/golang-push/rideshare - rideshare-java-us-east: - ports: - - 5000 - hostname: rideshare-java-us-east - environment: - <<: *env - OTEL_TRACES_EXPORTER: otlp - OTEL_EXPORTER_OTLP_ENDPOINT: http://tempo:4317 - OTEL_SERVICE_NAME: rideshare.java.push.app - OTEL_METRICS_EXPORTER: none - OTEL_TRACES_SAMPLER: always_on - OTEL_PROPAGATORS: tracecontext - PYROSCOPE_LABELS: hostname=rideshare-java-us-east - REGION: us-east - build: - context: ../../language-sdk-instrumentation/java/rideshare - dockerfile: Dockerfile.otel-instrumentation - rideshare-dotnet-eu-west: - platform: linux/amd64 ports: - 5000 hostname: rideshare-dotnet-eu-west @@ -89,44 +69,40 @@ services: - ./loadgen - http://rideshare-go-ap-south:5000 - http://rideshare-go-eu-north:5000 - - http://rideshare-java-us-east:5000 - http://rideshare-dotnet-eu-west:5000 - http://rideshare-python-eu-east:5000 grafana: - image: grafana/grafana-dev:10.3.0-151740 + # This service is generated from examples/_templates/grafana/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/grafana:latest environment: - - GF_AUTH_ANONYMOUS_ENABLED=true - - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin - - GF_AUTH_DISABLE_LOGIN_FORM=true - - GF_INSTALL_PLUGINS=pyroscope-panel - - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph + - GF_PLUGINS_PREINSTALL_SYNC=grafana-pyroscope-app + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph volumes: - - ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources + - ./grafana-provisioning:/etc/grafana/provisioning ports: - - '3000:3000' - + - 3000:3000 tempo: - image: grafana/tempo:latest + # This service is generated from examples/_templates/tempo/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates + image: grafana/tempo:2.10.5 command: [ "-config.file=/etc/tempo.yml" ] volumes: - ./tempo/tempo.yml:/etc/tempo.yml ports: - "14268:14268" # jaeger ingest - - "3200:3200" # tempo - - "9095:9095" # tempo grpc - - "4317:4317" # otlp grpc - - "4318:4318" # otlp http - - "9411:9411" # zipkin - + - "3200:3200" # tempo + - "9095:9095" # tempo grpc + - "4317:4317" # otlp grpc + - "4318:4318" # otlp http + - "9411:9411" # zipkin pyroscope: + # This service is generated from examples/_templates/pyroscope/docker-compose.yml + # Do not edit directly. To update, edit the template and run: make examples/sync-templates image: grafana/pyroscope:latest - environment: - JAEGER_AGENT_HOST: tempo - JAEGER_SAMPLER_TYPE: const - JAEGER_SAMPLER_PARAM: 1 - command: [ "-config.file=/etc/pyroscope.yml" ] ports: - - '4040:4040' - volumes: - - ./pyroscope/pyroscope.yml:/etc/pyroscope.yml + - 4040:4040 diff --git a/examples/tracing/tempo/grafana-provisioning/datasources/pyroscope.yml b/examples/tracing/tempo/grafana-provisioning/datasources/pyroscope.yml new file mode 100644 index 0000000000..8b5ec5f2b6 --- /dev/null +++ b/examples/tracing/tempo/grafana-provisioning/datasources/pyroscope.yml @@ -0,0 +1,18 @@ +# This file is generated from the template: +# examples/_templates/pyroscope/grafana-provisioning/datasources/pyroscope.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - uid: pyroscope + type: grafana-pyroscope-datasource + name: Pyroscope + url: http://pyroscope:4040 + jsonData: + keepCookies: [pyroscope_git_session] + ## Uncomment these if using with Grafana Cloud + # basicAuth: true + # basicAuthUser: '123456' + # secureJsonData: + # basicAuthPassword: PASSWORD diff --git a/examples/tracing/tempo/grafana-provisioning/datasources/tempo.yml b/examples/tracing/tempo/grafana-provisioning/datasources/tempo.yml new file mode 100644 index 0000000000..a225551398 --- /dev/null +++ b/examples/tracing/tempo/grafana-provisioning/datasources/tempo.yml @@ -0,0 +1,29 @@ +# This file is generated from the template: +# examples/_templates/tempo/grafana-provisioning/datasources/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates +--- +apiVersion: 1 +datasources: + - name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus + tracesToProfiles: + customQuery: false + datasourceUid: "pyroscope" + profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + tags: + - key: "service.name" + value: "service_name" diff --git a/examples/tracing/tempo/tempo/tempo.yml b/examples/tracing/tempo/tempo/tempo.yml index 7a558043a3..6db27a824c 100644 --- a/examples/tracing/tempo/tempo/tempo.yml +++ b/examples/tracing/tempo/tempo/tempo.yml @@ -1,3 +1,7 @@ +# This file is generated from the template: +# examples/_templates/tempo/tempo/tempo.yml +# Do not edit directly. To update, edit the template and run: +# make examples/sync-templates server: http_listen_port: 3200 @@ -20,16 +24,11 @@ distributor: otlp: protocols: http: + endpoint: 0.0.0.0:4318 grpc: + endpoint: 0.0.0.0:4317 opencensus: -ingester: - max_block_duration: 5m # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally - -compactor: - compaction: - block_retention: 1h # overall Tempo trace retention. set for demo purposes - storage: trace: backend: local # backend configuration to use diff --git a/globalSetup.js b/globalSetup.js deleted file mode 100644 index e85cb18232..0000000000 --- a/globalSetup.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = (config) => { - process.env['PYROSCOPE_SAMPLING_DURATION'] = 1000; - const Pyroscope = require('@pyroscope/nodejs'); - - Pyroscope.init({ serverAddress: '_', appName: 'pyroscope-oss.frontend' }); - if (process.env.CI) { - Pyroscope.start(); - } -}; diff --git a/globalTeardown.js b/globalTeardown.js deleted file mode 100644 index 6c39297fae..0000000000 --- a/globalTeardown.js +++ /dev/null @@ -1,8 +0,0 @@ -const Pyroscope = require('@pyroscope/nodejs'); - -module.exports = (config) => { - if (process.env.CI) { - Pyroscope.stopCpuProfiling(); - Pyroscope.stopHeapProfiling(); - } -}; diff --git a/go.mod b/go.mod index f4c34a3183..00aad53491 100644 --- a/go.mod +++ b/go.mod @@ -1,248 +1,353 @@ -module github.com/grafana/pyroscope +module github.com/grafana/pyroscope/v2 -go 1.21 +go 1.25.8 + +toolchain go1.25.12 require ( - connectrpc.com/connect v1.16.2 - connectrpc.com/grpchealth v1.3.0 - github.com/PuerkitoBio/goquery v1.8.1 - github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 - github.com/briandowns/spinner v1.23.0 - github.com/cespare/xxhash/v2 v2.2.0 + connectrpc.com/connect v1.19.2 + connectrpc.com/grpchealth v1.4.0 + github.com/PuerkitoBio/goquery v1.12.0 + github.com/alecthomas/kingpin/v2 v2.4.0 + github.com/cespare/xxhash/v2 v2.3.0 github.com/colega/zeropool v0.0.0-20230505084239-6fb4a4f75381 - github.com/dennwc/varint v1.0.0 + github.com/dgraph-io/ristretto/v2 v2.4.0 github.com/dgryski/go-groupvarint v0.0.0-20230630160417-2bfb7969fb3c github.com/dolthub/swiss v0.2.1 github.com/drone/envsubst v1.0.3 github.com/dustin/go-humanize v1.0.1 - github.com/fatih/color v1.15.0 - github.com/felixge/fgprof v0.9.4-0.20221116204635-ececf7638e93 + github.com/fatih/color v1.19.0 + github.com/felixge/fgprof v0.9.5 github.com/felixge/httpsnoop v1.0.4 + github.com/fsnotify/fsnotify v1.10.1 + github.com/getkin/kin-openapi v0.137.0 github.com/go-kit/log v0.2.1 github.com/gogo/protobuf v1.3.2 - github.com/gogo/status v1.1.1 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da - github.com/google/go-cmp v0.6.0 - github.com/google/go-github/v58 v58.0.1-0.20240111193443-e9f52699f5e5 - github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 + github.com/google/go-cmp v0.7.0 + github.com/google/go-github/v81 v81.0.0 + github.com/google/pprof v0.0.0-20260507013755-92041b743c96 github.com/google/uuid v1.6.0 - github.com/gorilla/mux v1.8.0 - github.com/grafana/dskit v0.0.0-20231221015914-de83901bf4d6 - github.com/grafana/jfr-parser/pprof v0.0.0-20240228024232-8abcb81c304c - github.com/grafana/pyroscope-go v1.0.3 - github.com/grafana/pyroscope-go/godeltaprof v0.1.7 - github.com/grafana/pyroscope/api v0.4.0 - github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db - github.com/grafana/river v0.3.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 + github.com/gorilla/mux v1.8.1 + github.com/grafana/alloy/syntax v0.1.0 + github.com/grafana/dskit v0.0.0-20260616135346-e96eda8260cd + github.com/grafana/pyroscope-go v1.2.8 + github.com/grafana/pyroscope-go/godeltaprof v0.1.11 + github.com/grafana/pyroscope-go/x/k6 v0.0.0-20241003203156-a917cea171d3 + github.com/grafana/pyroscope/api v1.5.0 + github.com/grafana/pyroscope/lidia v0.0.2 + github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/json-iterator/go v1.1.12 - github.com/k0kubun/pp/v3 v3.2.0 - github.com/klauspost/compress v1.17.7 - github.com/kubescape/go-git-url v0.0.27 - github.com/mattn/go-isatty v0.0.19 - github.com/minio/minio-go/v7 v7.0.61 + github.com/hashicorp/raft v1.7.3 + github.com/hashicorp/raft-wal v0.4.2 + github.com/klauspost/compress v1.18.6 + github.com/kubescape/go-git-url v0.0.31 + github.com/minio/minio-go/v7 v7.1.0 github.com/mitchellh/go-wordwrap v1.0.1 - github.com/oauth2-proxy/oauth2-proxy/v7 v7.5.1 - github.com/oklog/ulid v1.3.1 + github.com/oklog/ulid/v2 v2.1.1 github.com/olekukonko/tablewriter v0.0.5 - github.com/onsi/ginkgo/v2 v2.13.0 - github.com/onsi/gomega v1.29.0 - github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e - github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b - github.com/parquet-go/parquet-go v0.18.1-0.20231004061202-cde8189c4c26 - github.com/pkg/errors v0.9.1 - github.com/planetscale/vtprotobuf v0.6.0 - github.com/prometheus/client_golang v1.19.0 - github.com/prometheus/client_model v0.6.0 - github.com/prometheus/common v0.52.3 - github.com/prometheus/prometheus v0.51.2 - github.com/samber/lo v1.38.1 + github.com/parquet-go/parquet-go v0.26.4 + github.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25 + github.com/platinummonkey/go-concurrency-limits v0.10.0 + github.com/prometheus/client_golang v1.23.2 + github.com/prometheus/client_model v0.6.2 + github.com/prometheus/common v0.67.5 + github.com/prometheus/prometheus v0.311.3 + github.com/samber/lo v1.53.0 github.com/simonswine/tempopb v0.2.0 - github.com/sirupsen/logrus v1.9.3 - github.com/spf13/afero v1.11.0 - github.com/stretchr/testify v1.9.0 - github.com/thanos-io/objstore v0.0.0-20230727115635-d0c43443ecda - github.com/uber/jaeger-client-go v2.30.0+incompatible + github.com/sony/gobreaker/v2 v2.4.0 + github.com/spf13/afero v1.15.0 + github.com/stretchr/testify v1.11.1 + github.com/thanos-io/objstore v0.0.0-20250813080715-4e5fd4289b50 github.com/valyala/bytebufferpool v1.0.0 github.com/xlab/treeprint v1.2.0 - go.opentelemetry.io/proto/otlp v1.1.0 + go.etcd.io/bbolt v1.4.3 + go.opentelemetry.io/otel v1.44.0 + go.opentelemetry.io/proto/otlp v1.10.0 + go.opentelemetry.io/proto/otlp/collector/profiles/v1development v0.3.0 + go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 go.uber.org/atomic v1.11.0 + go.uber.org/automaxprocs v1.6.0 go.uber.org/goleak v1.3.0 - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a - golang.org/x/mod v0.16.0 - golang.org/x/net v0.24.0 - golang.org/x/oauth2 v0.18.0 - golang.org/x/sync v0.6.0 - golang.org/x/sys v0.19.0 - golang.org/x/text v0.14.0 - golang.org/x/time v0.5.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.34.1 - gopkg.in/alecthomas/kingpin.v2 v2.2.6 - gopkg.in/yaml.v3 v3.0.1 - sigs.k8s.io/yaml v1.3.0 + go.yaml.in/yaml/v3 v3.0.4 + golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f + golang.org/x/mod v0.37.0 + golang.org/x/net v0.56.0 + golang.org/x/oauth2 v0.36.0 + golang.org/x/sync v0.21.0 + golang.org/x/sys v0.46.0 + golang.org/x/text v0.39.0 + golang.org/x/time v0.15.0 + google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 + google.golang.org/grpc v1.82.1 + google.golang.org/protobuf v1.36.11 ) require ( - cloud.google.com/go v0.112.0 // indirect - cloud.google.com/go/compute v1.23.4 // indirect - cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 // indirect - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/storage v1.36.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect - github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad // indirect + github.com/buger/jsonparser v1.1.2 // indirect + github.com/dennwc/varint v1.0.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-openapi/swag/cmdutils v0.25.5 // indirect + github.com/go-openapi/swag/conv v0.25.5 // indirect + github.com/go-openapi/swag/fileutils v0.25.5 // indirect + github.com/go-openapi/swag/jsonname v0.25.5 // indirect + github.com/go-openapi/swag/jsonutils v0.25.5 // indirect + github.com/go-openapi/swag/loading v0.25.5 // indirect + github.com/go-openapi/swag/mangling v0.25.5 // indirect + github.com/go-openapi/swag/netutils v0.25.5 // indirect + github.com/go-openapi/swag/stringutils v0.25.5 // indirect + github.com/go-openapi/swag/typeutils v0.25.5 // indirect + github.com/go-openapi/swag/yamlutils v0.25.5 // indirect + github.com/gogo/status v1.1.1 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/crc32 v1.3.0 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/opentracing-contrib/go-grpc v0.1.2 // indirect + github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect + github.com/parquet-go/bitpack v1.0.0 // indirect + github.com/parquet-go/jsonlite v1.0.0 // indirect + github.com/pb33f/jsonpath v0.8.1 // indirect + github.com/pb33f/libopenapi v0.34.3 // indirect + github.com/pb33f/libopenapi-validator v0.13.3 // indirect + github.com/pb33f/ordered-map/v2 v2.3.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 // indirect + github.com/puzpuzpuz/xsync/v4 v4.4.0 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xhit/go-str2duration/v2 v2.1.0 // indirect + github.com/zeebo/xxh3 v1.1.0 // indirect + go.opentelemetry.io/collector/internal/componentalias v0.148.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect +) + +require ( + cel.dev/expr v0.25.1 // indirect + cloud.google.com/go v0.121.6 // indirect + cloud.google.com/go/auth v0.18.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.5.3 // indirect + cloud.google.com/go/monitoring v1.24.3 // indirect + cloud.google.com/go/storage v1.56.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect + github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/aliyun/aliyun-oss-go-sdk v2.2.6+incompatible // indirect - github.com/andybalholm/brotli v1.0.5 // indirect - github.com/andybalholm/cascadia v1.3.1 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/andybalholm/cascadia v1.3.3 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.50.32 // indirect - github.com/aws/aws-sdk-go-v2 v1.18.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.18.27 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.26 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect - github.com/aws/smithy-go v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.4 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.12 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.12 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect + github.com/aws/smithy-go v1.24.2 // indirect github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 // indirect + github.com/benbjohnson/immutable v0.4.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/chainguard-dev/git-urls v1.0.2 // indirect github.com/clbanning/mxj v1.8.4 // indirect - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect + github.com/coreos/etcd v3.3.27+incompatible // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // indirect + github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dolthub/maphash v0.1.0 // indirect - github.com/edsrzf/mmap-go v1.1.0 // indirect + github.com/edsrzf/mmap-go v1.2.0 // indirect github.com/efficientgo/core v1.0.0-rc.2 // indirect github.com/efficientgo/e2e v0.14.1-0.20230710114240-c316eb95ae5b // indirect + github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-ini/ini v1.67.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.22.2 // indirect - github.com/go-openapi/errors v0.21.1 // indirect - github.com/go-openapi/jsonpointer v0.20.2 // indirect - github.com/go-openapi/jsonreference v0.20.4 // indirect - github.com/go-openapi/loads v0.21.5 // indirect - github.com/go-openapi/spec v0.20.14 // indirect - github.com/go-openapi/strfmt v0.22.2 // indirect - github.com/go-openapi/swag v0.22.9 // indirect - github.com/go-openapi/validate v0.23.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-openapi/analysis v0.24.2 // indirect + github.com/go-openapi/errors v0.22.7 // indirect + github.com/go-openapi/jsonpointer v0.22.5 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/loads v0.23.2 // indirect + github.com/go-openapi/spec v0.22.3 // indirect + github.com/go-openapi/strfmt v0.26.1 // indirect + github.com/go-openapi/swag v0.25.5 // indirect + github.com/go-openapi/validate v0.25.1 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/googleapis v1.4.1 // indirect - github.com/golang-jwt/jwt/v5 v5.2.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/go-querystring v1.1.0 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.2 // indirect - github.com/grafana/jfr-parser v0.8.1-0.20240228024232-8abcb81c304c // indirect - github.com/hashicorp/consul/api v1.28.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/gnostic v0.7.1 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-querystring v1.2.0 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect + github.com/googleapis/gax-go/v2 v2.18.0 // indirect + github.com/grafana/jfr-parser v0.18.0 + github.com/grafana/otel-profiling-go v0.6.0 + github.com/hashicorp/consul/api v1.33.7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-msgpack v1.1.5 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.5 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-sockaddr v1.0.6 // indirect - github.com/hashicorp/go-version v1.6.0 // indirect - github.com/hashicorp/golang-lru v0.6.0 // indirect - github.com/hashicorp/memberlist v0.5.0 // indirect - github.com/hashicorp/serf v0.10.1 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect + github.com/hashicorp/go-version v1.8.0 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/memberlist v0.5.4 // indirect + github.com/hashicorp/serf v0.10.2 // indirect + github.com/jaegertracing/jaeger-idl v0.6.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.11 // indirect + github.com/knadh/koanf/maps v0.1.2 // indirect + github.com/knadh/koanf/providers/confmap v1.0.0 // indirect + github.com/knadh/koanf/v2 v2.3.3 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/miekg/dns v1.1.58 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect + github.com/miekg/dns v1.1.72 // indirect + github.com/minio/crc64nvme v1.1.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mozillazg/go-httpheader v0.3.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/ncw/swift v1.0.53 // indirect - github.com/opencontainers/image-spec v1.1.0-rc3 // indirect - github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect - github.com/pierrec/lz4/v4 v4.1.18 // indirect + github.com/oasdiff/yaml v0.0.9 // indirect + github.com/oasdiff/yaml3 v0.0.12 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0 // indirect + github.com/opentracing-contrib/go-stdlib v1.1.1 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/philhofer/fwd v1.2.0 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/pires/go-proxyproto v0.11.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/alertmanager v0.27.0 // indirect - github.com/prometheus/common/sigv4 v0.1.0 // indirect - github.com/prometheus/exporter-toolkit v0.11.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/rivo/uniseg v0.4.3 // indirect - github.com/rs/xid v1.5.0 // indirect + github.com/prometheus/alertmanager v0.31.1 // indirect + github.com/prometheus/exporter-toolkit v0.15.1 // indirect + github.com/prometheus/otlptranslator v1.0.0 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + github.com/prometheus/sigv4 v0.4.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rs/xid v1.6.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - github.com/segmentio/encoding v0.3.6 // indirect - github.com/sercand/kuberesolver/v5 v5.1.1 // indirect - github.com/soheilhy/cmux v0.1.5 // indirect + github.com/sercand/kuberesolver/v6 v6.0.1 // indirect + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tencentyun/cos-go-sdk-v5 v0.7.40 // indirect + github.com/tinylib/msgp v1.6.1 // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - go.etcd.io/etcd/api/v3 v3.5.7 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect - go.etcd.io/etcd/client/v3 v3.5.7 // indirect - go.mongodb.org/mongo-driver v1.14.0 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/collector/featuregate v1.3.0 // indirect - go.opentelemetry.io/collector/pdata v1.3.0 // indirect - go.opentelemetry.io/collector/semconv v0.96.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + go.etcd.io/etcd/api/v3 v3.6.9 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.9 // indirect + go.etcd.io/etcd/client/v3 v3.6.9 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/collector/component v1.54.0 // indirect + go.opentelemetry.io/collector/confmap v1.54.0 // indirect + go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 // indirect + go.opentelemetry.io/collector/consumer v1.54.0 // indirect + go.opentelemetry.io/collector/featuregate v1.54.0 // indirect + go.opentelemetry.io/collector/pdata v1.54.0 // indirect + go.opentelemetry.io/collector/pipeline v1.54.0 // indirect + go.opentelemetry.io/collector/processor v1.54.0 // indirect + go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.43.0 // indirect + go.opentelemetry.io/contrib/exporters/autoexport v0.68.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 + go.opentelemetry.io/contrib/propagators/jaeger v1.42.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.36.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.65.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 // indirect + go.opentelemetry.io/otel/log v0.19.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 + go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/tools v0.19.0 // indirect - google.golang.org/api v0.168.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect + go.uber.org/zap v1.27.1 // indirect + golang.org/x/crypto v0.53.0 // indirect + golang.org/x/term v0.44.0 // indirect + golang.org/x/tools v0.47.0 // indirect + google.golang.org/api v0.272.0 // indirect + google.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apimachinery v0.29.2 // indirect - k8s.io/client-go v0.29.2 // indirect - k8s.io/klog/v2 v2.120.1 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + k8s.io/apimachinery v0.35.3 // indirect + k8s.io/client-go v0.35.3 // indirect + k8s.io/klog/v2 v2.140.0 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect ) replace ( github.com/grafana/pyroscope/api => ./api + github.com/grafana/pyroscope/lidia => ./lidia // Replace memberlist with our fork which includes some fixes that haven't been // merged upstream yet. - github.com/hashicorp/memberlist => github.com/grafana/memberlist v0.3.1-0.20220708130638-bd88e10a3d91 - - // Replaced with fork, to allow prefix listing, see https://github.com/simonswine/objstore/commit/84f91ea90e721f17d2263cf479fff801cab7cf27 - github.com/thanos-io/objstore => github.com/grafana/objstore v0.0.0-20231121154247-84f91ea90e72 + github.com/hashicorp/memberlist => github.com/grafana/memberlist v0.3.1-0.20260515134459-1798cf41aca7 // gopkg.in/yaml.v3 // + https://github.com/go-yaml/yaml/pull/691 diff --git a/go.sum b/go.sum index 63f8691f3f..f84da4b549 100644 --- a/go.sum +++ b/go.sum @@ -1,185 +1,210 @@ +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= -cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= -cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= -cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 h1:aRVqY1p2IJaBGStWMsQMpkAa83cPkCDLl80eOj0Rbz4= -cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68/go.mod h1:1a3eRNYX12fs5UABBIXS8HXVvQbX9hRB/RkEBPORpe8= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= -cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= -cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= -connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= -connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= -connectrpc.com/grpchealth v1.3.0 h1:FA3OIwAvuMokQIXQrY5LbIy8IenftksTP/lG4PbYN+E= -connectrpc.com/grpchealth v1.3.0/go.mod h1:3vpqmX25/ir0gVgW6RdnCPPZRcR6HvqtXX5RNPmDXHM= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 h1:MxA59PGoCFb+vCwRQi3PhQEwHj4+r2dhuv9HG+vM7iM= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= +cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c= +cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI= +cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM= +cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= +cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= +cloud.google.com/go/logging v1.13.2 h1:qqlHCBvieJT9Cdq4QqYx1KPadCQ2noD4FK02eNqHAjA= +cloud.google.com/go/logging v1.13.2/go.mod h1:zaybliM3yun1J8mU2dVQ1/qDzjbOqEijZCn6hSBtKak= +cloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8= +cloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk= +cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE= +cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI= +cloud.google.com/go/storage v1.56.0 h1:iixmq2Fse2tqxMbWhLWC9HfBj1qdxqAmiK8/eqtsLxI= +cloud.google.com/go/storage v1.56.0/go.mod h1:Tpuj6t4NweCLzlNbw9Z9iwxEkrSem20AetIeH/shgVU= +cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U= +cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s= +connectrpc.com/connect v1.19.2 h1:McQ83FGdzL+t60peksi0gXC7MQ/iLKgLduAnThbM0mo= +connectrpc.com/connect v1.19.2/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= +connectrpc.com/grpchealth v1.4.0 h1:MJC96JLelARPgZTiRF9KRfY/2N9OcoQvF2EWX07v2IE= +connectrpc.com/grpchealth v1.4.0/go.mod h1:WhW6m1EzTmq3Ky1FE8EfkIpSDc6TfUx2M2KqZO3ts/Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0 h1:LkHbJbgF3YyvC53aqYGR+wWQDn2Rdp9AQdGndf9QvY4= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0/go.mod h1:QyiQdW4f4/BIfB8ZutZ2s+28RAgfa/pT+zS++ZHyM1I= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0/go.mod h1:Y/HgrePTmGy9HjdSGTqZNa+apUpTVIEVKXJyARP2lrk= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0 h1:LR0kAX9ykz8G4YgLCaRDVJ3+n43R8MneB5dTy2konZo= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0/go.mod h1:DWAciXemNf++PQJLeXUB4HHH5OpsAh12HZnu2wXE1jA= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g= -github.com/Code-Hex/go-generics-cache v1.3.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4= +github.com/Code-Hex/go-generics-cache v1.5.1 h1:6vhZGc5M7Y/YD8cIUcY8kcuQLB4cHR7U+0KMqAA0KcU= +github.com/Code-Hex/go-generics-cache v1.5.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= -github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 h1:rIkQfkCOVKc1OiRCNcSDD8ml5RJlZbH/Xsq7lbpynwc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= +github.com/HdrHistogram/hdrhistogram-go v1.2.0 h1:XMJkDWuz6bM9Fzy7zORuVFKH7ZJY41G2q8KWhVGkNiY= +github.com/HdrHistogram/hdrhistogram-go v1.2.0/go.mod h1:CiIeGiHSd06zjX+FypuEJ5EQ07KKtxZ+8J6hszwVQig= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo= +github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/aliyun/aliyun-oss-go-sdk v2.2.6+incompatible h1:KXeJoM1wo9I/6xPTyt6qCxoSZnmASiAjlrr0dyTUKt8= github.com/aliyun/aliyun-oss-go-sdk v2.2.6+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= -github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= +github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.50.32 h1:POt81DvegnpQKM4DMDLlHz1CO6OBnEoQ1gRhYFd7QRY= -github.com/aws/aws-sdk-go v1.50.32/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.18.1 h1:+tefE750oAb7ZQGzla6bLkOwfcQCEtC5y2RqoqCeqKo= -github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.27 h1:Az9uLwmssTE6OGTpsFqOnaGpLnKDqNYOJzWuC6UAYzA= -github.com/aws/aws-sdk-go-v2/config v1.18.27/go.mod h1:0My+YgmkGxeqjXZb5BYme5pc4drjTnM+x1GJ3zv42Nw= -github.com/aws/aws-sdk-go-v2/credentials v1.13.26 h1:qmU+yhKmOCyujmuPY7tf5MxR/RKyZrOPO3V4DobiTUk= -github.com/aws/aws-sdk-go-v2/credentials v1.13.26/go.mod h1:GoXt2YC8jHUBbA4jr+W3JiemnIbkXOfxSXcisUsZ3os= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 h1:LxK/bitrAr4lnh9LnIS6i7zWbCOdMsfzKFBI6LUCS0I= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4/go.mod h1:E1hLXN/BL2e6YizK1zFlYd8vsfi2GTjbjBazinMmeaM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 h1:A5UqQEmPaCFpedKouS4v+dHCTUo2sKqhoKO9U5kxyWo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 h1:srIVS45eQuewqz6fKKu6ZGXaq6FuFg5NzgQBAM6g8Y4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28/go.mod h1:7VRpKQQedkfIEXb4k52I7swUnZP0wohVajJMRn3vsUw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 h1:LWA+3kDM8ly001vJ1X1waCuLJdtTl48gwkPKWy9sosI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35/go.mod h1:0Eg1YjxE0Bhn56lx+SHJwCzhW+2JGtizsrx+lCqrfm0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 h1:bkRyG4a929RCnpVSTvLM2j/T4ls015ZhhYApbmYs15s= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28/go.mod h1:jj7znCIg05jXlaGBlFMGP8+7UN3VtCkRBG2spnmRQkU= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 h1:nneMBM2p79PGWBQovYO/6Xnc2ryRMw3InnDJq1FHkSY= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.12/go.mod h1:HuCOxYsF21eKrerARYO6HapNeh9GBNq7fius2AcwodY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 h1:2qTR7IFk7/0IN/adSFhYu9Xthr0zVFTgBrmPldILn80= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12/go.mod h1:E4VrHCPzmVB/KFXtqBGKb3c8zpbNBgKe3fisDNLAW5w= -github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 h1:XFJ2Z6sNUUcAz9poj+245DMkrHE4h2j5I9/xD50RHfE= -github.com/aws/aws-sdk-go-v2/service/sts v1.19.2/go.mod h1:dp0yLPsLBOi++WTxzCjA/oZqi6NPIhoR+uF7GeMU9eg= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= -github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k= +github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0= +github.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g= +github.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8= +github.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0 h1:98Miqj16un1WLNyM1RjVDhXYumhqZrQfAeG8i4jPG6o= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0/go.mod h1:T6ndRfdhnXLIY5oKBHjYZDVj706los2zGdpThppquvA= +github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0 h1:YS5TXaEvzDb+sV+wdQFUtuCAk0GeFR9Ai6HFdxpz6q8= +github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0/go.mod h1:10kBgdaNJz0FO/+JWDUH+0rtSjkn5yafgavDDmmhFzs= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.12 h1:S066ajzfPRCSW4lsSHOYglne6SNi2CHt1u5omzW1RBg= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.12/go.mod h1:86SE4NcXxbxr8KTG3yOyDmd4HyiFmKl8TexXnhYJ+Bw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk= +github.com/aws/aws-sdk-go-v2/service/kafka v1.49.1 h1:BgBatWcQIFqF1l6KGHjv66V0d/ISnWrTwxDx/Jf6EJM= +github.com/aws/aws-sdk-go-v2/service/kafka v1.49.1/go.mod h1:pMpys+PlrN//vj8j5s0oOAMJjauj81VkHzIZxPVWOro= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0 h1:cg6PxzoIide2wiEyLfikOFN+XwHafwR8p5+L9U1E8dQ= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0/go.mod h1:YvX7hjUWecrKX8fBkbEncyddEW85xjNH+u5JHioITOw= +github.com/aws/aws-sdk-go-v2/service/rds v1.117.0 h1:T1Xe9sYxSUUQOvd1RsFeVk/IXFPdqSiN0atXu/Hy/8A= +github.com/aws/aws-sdk-go-v2/service/rds v1.117.0/go.mod h1:QbXW4coAMakHQhf1qhE0eVVCen9gwB/Kvn+HHHKhpGY= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk= +github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= +github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/baidubce/bce-sdk-go v0.9.111 h1:yGgtPpZYUZW4uoVorQ4xnuEgVeddACydlcJKW87MDV4= github.com/baidubce/bce-sdk-go v0.9.111/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= +github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad h1:3swAvbzgfaI6nKuDDU7BiKfZRdF+h2ZwKgMHd8Ha4t8= +github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad/go.mod h1:9+nBLYNWkvPcq9ep0owWUsPTLgL9ZXTsZWcCSVGGLJ0= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0= -github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= -github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/immutable v0.4.0 h1:CTqXbEerYso8YzVPxmWxh2gnoRQbbB9X1quUC8+vGZA= +github.com/benbjohnson/immutable v0.4.0/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= -github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= +github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow= +github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= +github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= +github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= +github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= +github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ= github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/colega/go-yaml-yaml v0.0.0-20220720105220-255a8d16d094 h1:FpZSn61BWXbtyH68+uSv416veEswX1M2HRyQfdHnOyQ= github.com/colega/go-yaml-yaml v0.0.0-20220720105220-255a8d16d094/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= github.com/colega/zeropool v0.0.0-20230505084239-6fb4a4f75381 h1:d5EKgQfRQvO97jnISfR89AiCCCJMwMFoSxUiU0OGCRU= github.com/colega/zeropool v0.0.0-20230505084239-6fb4a4f75381/go.mod h1:OU76gHeRo8xrzGJU3F3I1CqX1ekM8dfJw0+wPeMwnp0= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA= +github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= +github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf h1:GOPo6vn/vTN+3IwZBvXX0y5doJfSC7My0cdzelyOCsQ= +github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= +github.com/dgraph-io/ristretto/v2 v2.4.0 h1:I/w09yLjhdcVD2QV192UJcq8dPBaAJb9pOuMyNy0XlU= +github.com/dgraph-io/ristretto/v2 v2.4.0/go.mod h1:0KsrXtXvnv0EqnzyowllbVJB8yBonswa2lTCK2gGo9E= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-groupvarint v0.0.0-20230630160417-2bfb7969fb3c h1:cHaw4wmusVzAZLEPWOCCGCfu6UvFXx9UboCHQCnjvxY= github.com/dgryski/go-groupvarint v0.0.0-20230630160417-2bfb7969fb3c/go.mod h1:MlkUQveSLEDbIgq2r1e++tSf0zfzU9mQpa9Qkczl+9Y= -github.com/digitalocean/godo v1.109.0 h1:4W97RJLJSUQ3veRZDNbp1Ol3Rbn6Lmt9bKGvfqYI5SU= -github.com/digitalocean/godo v1.109.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ= -github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/digitalocean/godo v1.178.0 h1:+B4xGOaoFwwwpM7TKhoyGHdmFg5eF9zDB1YfOLvNJ2E= +github.com/digitalocean/godo v1.178.0/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= +github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= @@ -190,39 +215,47 @@ github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= -github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= +github.com/edsrzf/mmap-go v1.2.0 h1:hXLYlkbaPzt1SaQk+anYwKSRNhufIDCchSPkUD6dD84= +github.com/edsrzf/mmap-go v1.2.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/efficientgo/core v1.0.0-rc.2 h1:7j62qHLnrZqO3V3UA0AqOGd5d5aXV3AX6m/NZBHp78I= github.com/efficientgo/core v1.0.0-rc.2/go.mod h1:FfGdkzWarkuzOlY04VY+bGfb1lWrjaL6x/GLcQ4vJps= github.com/efficientgo/e2e v0.14.1-0.20230710114240-c316eb95ae5b h1:8VX23BNufsa4KCqnnEonvI3yrou2Pjp8JLcbdVn0Fs8= github.com/efficientgo/e2e v0.14.1-0.20230710114240-c316eb95ae5b/go.mod h1:plsKU0YHE9uX+7utvr7SiDtVBSHJyEfHRO4UnUgDmts= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= -github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ= +github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds= +github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0= github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/fgprof v0.9.4-0.20221116204635-ececf7638e93 h1:S8ZdFFDRXUKs3fHpMDPVh9oWd46hKqEEt/X3oxhtF5Q= -github.com/felixge/fgprof v0.9.4-0.20221116204635-ececf7638e93/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= +github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= +github.com/fullstorydev/emulators/storage v1.0.0 h1:fU+p9PkzQV35QJVKZl4I8frQvPLcwheud0ammOLJhZY= +github.com/fullstorydev/emulators/storage v1.0.0/go.mod h1:tKvCtgVqtN/OdLUdVWcBC56T2Mo6GC1Tf17AimCogr0= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/getkin/kin-openapi v0.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= +github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -234,36 +267,70 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/analysis v0.22.2 h1:ZBmNoP2h5omLKr/srIC9bfqrUGzT6g6gNv03HE9Vpj0= -github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo= -github.com/go-openapi/errors v0.21.1 h1:rVisxQPdETctjlYntm0Ek4dKf68nAQocCloCT50vWuI= -github.com/go-openapi/errors v0.21.1/go.mod h1:LyiY9bgc7AVVh6wtVvMYEyoj3KJYNoRw92mmvnMWgj8= -github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= -github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= -github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= -github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= -github.com/go-openapi/loads v0.21.5 h1:jDzF4dSoHw6ZFADCGltDb2lE4F6De7aWSpe+IcsRzT0= -github.com/go-openapi/loads v0.21.5/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8= -github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do= -github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= -github.com/go-openapi/strfmt v0.22.2 h1:DPYOrm6gexCfZZfXUaXFS4+Jw6HAaIIG0SZ5630f8yw= -github.com/go-openapi/strfmt v0.22.2/go.mod h1:HB/b7TCm91rno75Dembc1dFW/0FPLk5CEXsoF9ReNc4= -github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= -github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= -github.com/go-openapi/validate v0.23.0 h1:2l7PJLzCis4YUGEoW6eoQw3WhyM65WSIcjX6SQnlfDw= -github.com/go-openapi/validate v0.23.0/go.mod h1:EeiAZ5bmpSIOJV1WLfyYF9qp/B1ZgSaEpHTJHtN5cbE= -github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= -github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= +github.com/go-openapi/analysis v0.24.2 h1:6p7WXEuKy1llDgOH8FooVeO+Uq2za9qoAOq4ZN08B50= +github.com/go-openapi/analysis v0.24.2/go.mod h1:x27OOHKANE0lutg2ml4kzYLoHGMKgRm1Cj2ijVOjJuE= +github.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA= +github.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w= +github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= +github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/loads v0.23.2 h1:rJXAcP7g1+lWyBHC7iTY+WAF0rprtM+pm8Jxv1uQJp4= +github.com/go-openapi/loads v0.23.2/go.mod h1:IEVw1GfRt/P2Pplkelxzj9BYFajiWOtY2nHZNj4UnWY= +github.com/go-openapi/spec v0.22.3 h1:qRSmj6Smz2rEBxMnLRBMeBWxbbOvuOoElvSvObIgwQc= +github.com/go-openapi/spec v0.22.3/go.mod h1:iIImLODL2loCh3Vnox8TY2YWYJZjMAKYyLH2Mu8lOZs= +github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c= +github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y= +github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU= +github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA= +github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c= +github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= +github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= +github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk= +github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc= +github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= +github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= +github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= +github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= +github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= +github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw= +github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY= +github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU= +github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14= +github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= +github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= +github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= +github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= +github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= +github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= +github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw= +github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/validate v0.25.1 h1:sSACUI6Jcnbo5IWqbYHgjibrhhmt3vR6lCzKZnmAgBw= +github.com/go-openapi/validate v0.25.1/go.mod h1:RMVyVFYte0gbSTaZ0N4KmTn6u/kClvAFp+mAVfS/DQc= +github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk= +github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= -github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-zookeeper/zk v1.0.4 h1:DPzxraQx7OrPyXq2phlGlNSIyWEsAox0RJmjTseMV6I= +github.com/go-zookeeper/zk v1.0.4/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -274,192 +341,151 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= -github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= -github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic v0.7.1 h1:t5Kc7j/8kYr8t2u11rykRrPPovlEMG4+xdc/SpekATs= +github.com/google/gnostic v0.7.1/go.mod h1:KSw6sxnxEBFM8jLPfJd46xZP+yQcfE8XkiqfZx5zR28= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v58 v58.0.1-0.20240111193443-e9f52699f5e5 h1:Cm3eMs9Qj7fqDQOascVTJg37N0T7Vb2foS//WopCpWw= -github.com/google/go-github/v58 v58.0.1-0.20240111193443-e9f52699f5e5/go.mod h1:k4hxDKEfoWpSqFlc8LTpGd9fu2KrV1YAa6Hi6FmDNY4= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v81 v81.0.0 h1:hTLugQRxSLD1Yei18fk4A5eYjOGLUBKAl/VCqOfFkZc= +github.com/google/go-github/v81 v81.0.0/go.mod h1:upyjaybucIbBIuxgJS7YLOZGziyvvJ92WX6WEBNE3sM= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0= +github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= -github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/pprof v0.0.0-20260507013755-92041b743c96 h1:YDDnaZ9afWajDboPMt9Vikqca/yWAX7KAxVzb4lJU1M= +github.com/google/pprof v0.0.0-20260507013755-92041b743c96/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= -github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= -github.com/gophercloud/gophercloud v1.8.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/dskit v0.0.0-20231221015914-de83901bf4d6 h1:Z78JZ7pa6InQ5BcMB27M+NMTZ7LV+MXgOd3dZPfEdG4= -github.com/grafana/dskit v0.0.0-20231221015914-de83901bf4d6/go.mod h1:kkWM4WUV230bNG3urVRWPBnSJHs64y/0RmWjftnnn0c= -github.com/grafana/jfr-parser v0.8.1-0.20240228024232-8abcb81c304c h1:vNY68kvB3UYSeh7zHehOpfqk6CCpLYmuYKnF53GTpSk= -github.com/grafana/jfr-parser v0.8.1-0.20240228024232-8abcb81c304c/go.mod h1:M5u1ux34Qo47ZBWksbMYVk40s7dvU3WMVYpxweEu4R0= -github.com/grafana/jfr-parser/pprof v0.0.0-20240228024232-8abcb81c304c h1:tGu1DTlK+gbYR/uBUcRhT2OZB1dSauxamLtDuSUj7AQ= -github.com/grafana/jfr-parser/pprof v0.0.0-20240228024232-8abcb81c304c/go.mod h1:P5406BrWxjahTzVF6aCSumNI1KPlZJc0zO0v+zKZ4gc= -github.com/grafana/memberlist v0.3.1-0.20220708130638-bd88e10a3d91 h1:/NipyHnOmvRsVzj81j2qE0VxsvsqhOB0f4vJIhk2qCQ= -github.com/grafana/memberlist v0.3.1-0.20220708130638-bd88e10a3d91/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/grafana/objstore v0.0.0-20231121154247-84f91ea90e72 h1:o22hsDMQ3kv/0N9PkzHQSd5xMmmmdA5UJR7Jb4xISZQ= -github.com/grafana/objstore v0.0.0-20231121154247-84f91ea90e72/go.mod h1:JauBAcJ61tRSv9widgISVmA6akQXDeUMXBrVmWW4xog= -github.com/grafana/pyroscope-go v1.0.3 h1:8WWmItzLfg4m8G+j//ElSjMeMr88Y6Lvblar6qeTyKk= -github.com/grafana/pyroscope-go v1.0.3/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= -github.com/grafana/pyroscope-go/godeltaprof v0.1.7 h1:C11j63y7gymiW8VugJ9ZW0pWfxTZugdSJyC48olk5KY= -github.com/grafana/pyroscope-go/godeltaprof v0.1.7/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= -github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db h1:7aN5cccjIqCLTzedH7MZzRZt5/lsAHch6Z3L2ZGn5FA= -github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/grafana/river v0.3.0 h1:6TsaR/vkkcppUM9I0muGbPIUedCtpPu6OWreE5+CE6g= -github.com/grafana/river v0.3.0/go.mod h1:icSidCSHYXJUYy6TjGAi/D+X7FsP7Gc7cxvBUIwYMmY= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= -github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= -github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= -github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= -github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= -github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= +github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8= +github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.18.0 h1:jxP5Uuo3bxm3M6gGtV94P4lliVetoCB4Wk2x8QA86LI= +github.com/googleapis/gax-go/v2 v2.18.0/go.mod h1:uSzZN4a356eRG985CzJ3WfbFSpqkLTjsnhWGJR6EwrE= +github.com/gophercloud/gophercloud/v2 v2.11.1 h1:jCs4vLH8sJgRqrPzqVfWgl7uI6JnIIlsgeIRM0uHjxY= +github.com/gophercloud/gophercloud/v2 v2.11.1/go.mod h1:Rm0YvKQ4QYX2rY9XaDKnjRzSGwlG5ge4h6ABYnmkKQM= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/grafana/alloy/syntax v0.1.0 h1:+1xQakvQPH6N0y9+q2Fu5QePyzrve6i1wMNuXdWd1rQ= +github.com/grafana/alloy/syntax v0.1.0/go.mod h1:8H9ToCc1M8F6A+je4rIH6saIe1MUCmjSk+Uje+LNLEo= +github.com/grafana/dskit v0.0.0-20260616135346-e96eda8260cd h1:0nhpm/ZeGIeJ25fsYpYo7DeMIYxf7iObMxUdPPAEfu0= +github.com/grafana/dskit v0.0.0-20260616135346-e96eda8260cd/go.mod h1:T0r0vLv/JwmOoSc/EOZw/5ni7r/djCoCdJ3/JnHDAjQ= +github.com/grafana/jfr-parser v0.18.0 h1:KluVBviZn3n83FGXOVx9CpB2BJaambaH917FzBWvlTQ= +github.com/grafana/jfr-parser v0.18.0/go.mod h1:YmrPKBeaA6KeXCNVNi2wvoPN1i81yBmXhSIBp8QlKTA= +github.com/grafana/memberlist v0.3.1-0.20260515134459-1798cf41aca7 h1:F5hMoc+tCK4AeUKfaL1XFEVEPSg+eKQe712fsSO/JA0= +github.com/grafana/memberlist v0.3.1-0.20260515134459-1798cf41aca7/go.mod h1:OSu8+LHxPUHB67c9v5Gfw5NQZxFWOL3EKmn9TgHvyCo= +github.com/grafana/otel-profiling-go v0.6.0 h1:W7lOZaJj4IJISXMcM1UBk3fJF3tzF2OD6MJBJaQp1H8= +github.com/grafana/otel-profiling-go v0.6.0/go.mod h1:cqLIDgNXlnzknJ0WLiEe+JPjZk2MZ4ftMdqRJRWj1ZM= +github.com/grafana/pyroscope-go v1.2.8 h1:UvCwIhlx9DeV7F6TW/z8q1Mi4PIm3vuUJ2ZlCEvmA4M= +github.com/grafana/pyroscope-go v1.2.8/go.mod h1:SSi59eQ1/zmKoY/BKwa5rSFsJaq+242Bcrr4wPix1g8= +github.com/grafana/pyroscope-go/godeltaprof v0.1.11 h1:el5LYpXissAiCKZ5/6yjlr6mhYVV6Cp5lahTocxraXM= +github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPIDDG7CtjSjT/ECbp6eLVuMxYRI= +github.com/grafana/pyroscope-go/x/k6 v0.0.0-20241003203156-a917cea171d3 h1:GtwQDlBz8aJHMy2Ko28UDRGgGzi7v4Vf20+ZyXaGy7M= +github.com/grafana/pyroscope-go/x/k6 v0.0.0-20241003203156-a917cea171d3/go.mod h1:nfbW6/4ke3ywlqLb+Zgr9t1z9Zv3m+2ImUp+vbkzHpc= +github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 h1:cLN4IBkmkYZNnk7EAJ0BHIethd+J6LqxFNw5mSiI2bM= +github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= +github.com/hashicorp/consul/api v1.33.7 h1:apLZVzX7O7BLgHyh4pvczcsBzPmYSVXGKZQbOaA1ae0= +github.com/hashicorp/consul/api v1.33.7/go.mod h1:SjR3cjwCUSLLDfVw5dFg76rnnKjOySxr8W8lC5s01C8= +github.com/hashicorp/consul/sdk v0.17.3 h1:oZMMxzQGSsiT+ToOH50y3Qcs0nc9Ud+7L5lRx+EmMU0= +github.com/hashicorp/consul/sdk v0.17.3/go.mod h1:jnOmYjiNfVRpBaujQ1DFFVs0N6g3S1y6wygSjLTzYfc= +github.com/hashicorp/cronexpr v1.1.3 h1:rl5IkxXN2m681EfivTlccqIryzYJSXRGRNa0xeG7NA4= +github.com/hashicorp/cronexpr v1.1.3/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= -github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-msgpack/v2 v2.1.5 h1:Ue879bPnutj/hXfmUk6s/jtIK90XxgiUIcXRl656T44= +github.com/hashicorp/go-msgpack/v2 v2.1.5/go.mod h1:bjCsRXpZ7NsJdk45PoCQnzRGDaK8TKm5ZnDI/9y3J4M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= -github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.6 h1:RSG8rKU28VTUTvEKghe5gIhIQpv8evvNpnDEyqO4u9I= -github.com/hashicorp/go-sockaddr v1.0.6/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4= +github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= -github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702 h1:fI1LXuBaS1d9z1kmb++Og6YD8uMRwadXorCwE+xgOFA= -github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702/go.mod h1:z71gkJdrkAt/Rl6C7Q79VE7AwJ5lUF+M+fzFTyIHYB0= -github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hetznercloud/hcloud-go/v2 v2.6.0 h1:RJOA2hHZ7rD1pScA4O1NF6qhkHyUdbbxjHgFNot8928= -github.com/hetznercloud/hcloud-go/v2 v2.6.0/go.mod h1:4J1cSE57+g0WS93IiHLV7ubTHItcp+awzeBp5bM9mfA= +github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a h1:HGwfgBNl90YBiHdbzZ/+8aMxO1UL9B/yNTAXa8iB8z8= +github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a/go.mod h1:KkLNLU0Nyfh5jWsFoF/PsmMbKpRIAoIV4lmQoJWgKCk= +github.com/hashicorp/raft v1.7.3 h1:DxpEqZJysHN0wK+fviai5mFcSYsCkNpFUl1xpAW8Rbo= +github.com/hashicorp/raft v1.7.3/go.mod h1:DfvCGFxpAUPE0L4Uc8JLlTPtc3GzSbdH0MTJCLgnmJQ= +github.com/hashicorp/raft-wal v0.4.2 h1:DV1jgqEumNfdNpOaZ9mL1Gu7Mz59epFtiE6CoqnHrlY= +github.com/hashicorp/raft-wal v0.4.2/go.mod h1:S92ainH+6fRuWk6BtZKJ8EgcGgNTKx48Hk5dhOOY1DM= +github.com/hashicorp/serf v0.10.2 h1:m5IORhuNSjaxeljg5DeQVDlQyVkhRIjJDimbkCa8aAc= +github.com/hashicorp/serf v0.10.2/go.mod h1:T1CmSGfSeGfnfNy/w0odXQUR1rfECGd2Qdsp84DjOiY= +github.com/hetznercloud/hcloud-go/v2 v2.36.0 h1:HlLL/aaVXUulqe+rsjoJmrxKhPi1MflL5O9iq5QEtvo= +github.com/hetznercloud/hcloud-go/v2 v2.36.0/go.mod h1:MnN/QJEa/RYNQiiVoJjNHPntM7Z1wlYPgJ2HA40/cDE= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible h1:tKTaPHNVwikS3I1rdyf1INNvgJXWSf/+TzqsiGbrgnQ= -github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= -github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/huaweicloud/huaweicloud-sdk-go-obs v3.25.4+incompatible h1:yNjwdvn9fwuN6Ouxr0xHM0cVu03YMUWUyFmu2van/Yc= +github.com/huaweicloud/huaweicloud-sdk-go-obs v3.25.4+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= +github.com/ionos-cloud/sdk-go/v6 v6.3.6 h1:l/TtKgdQ1wUH3DDe2SfFD78AW+TJWdEbDpQhHkWd6CM= +github.com/ionos-cloud/sdk-go/v6 v6.3.6/go.mod h1:nUGHP4kZHAZngCVr4v6C8nuargFrtvt7GrzH/hqn7c4= +github.com/jaegertracing/jaeger-idl v0.6.0 h1:LOVQfVby9ywdMPI9n3hMwKbyLVV3BL1XH2QqsP5KTMk= +github.com/jaegertracing/jaeger-idl v0.6.0/go.mod h1:mpW0lZfG907/+o5w5OlnNnig7nHJGT3SfKmRqC42HGQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -470,22 +496,26 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/k0kubun/pp/v3 v3.2.0 h1:h33hNTZ9nVFNP3u2Fsgz8JXiF5JINoZfFq4SvKJwNcs= -github.com/k0kubun/pp/v3 v3.2.0/go.mod h1:ODtJQbQcIRfAD3N+theGCV1m/CBxweERz2dapdz1EwA= +github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= +github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU= +github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM= +github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw= +github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= +github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE= +github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A= +github.com/knadh/koanf/v2 v2.3.3 h1:jLJC8XCRfLC7n4F+ZKKdBsbq1bfXTpuFhf4L7t94D94= +github.com/knadh/koanf/v2 v2.3.3/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -498,59 +528,62 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kubescape/go-git-url v0.0.27 h1:nvHDwuFs4ezOJ5CGL9U7ZL6gRMneWZdelBs0KEK8yb8= -github.com/kubescape/go-git-url v0.0.27/go.mod h1:3ddc1HEflms1vMhD9owt/3FBES070UaYTUarcjx8jDk= +github.com/kubescape/go-git-url v0.0.31 h1:VZnvtdGLVc42cQaR7llQeGZz0PnOxcs+eDig2Q9PJss= +github.com/kubescape/go-git-url v0.0.31/go.mod h1:3ddc1HEflms1vMhD9owt/3FBES070UaYTUarcjx8jDk= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/linode/linodego v1.29.0 h1:gDSQWAbKMAQX8db9FDCXHhodQPrJmLcmthjx6m+PyV4= -github.com/linode/linodego v1.29.0/go.mod h1:3k6WvCM10gillgYcnoLqIL23ST27BD9HhMsCJWb3Bpk= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= +github.com/linode/linodego v1.66.0 h1:rK8QJFaV53LWOEJvb/evhTg/dP5ElvtuZmx4iv4RJds= +github.com/linode/linodego v1.66.0/go.mod h1:12ykGs9qsvxE+OU3SXuW2w+DTruWF35FPlXC7gGk2tU= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI= +github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.61 h1:87c+x8J3jxQ5VUGimV9oHdpjsAvy3fhneEBKuoKEVUI= -github.com/minio/minio-go/v7 v7.0.61/go.mod h1:BTu8FcrEw+HidY0zd/0eny43QnVNkXRPXrLXFuQBHXg= -github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= -github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/minio/minio-go/v7 v7.1.0 h1:QEt5IStDpxgGjEdtOgpiZ5QhmSl3ax7qy61vi2SwHO8= +github.com/minio/minio-go/v7 v7.1.0/go.mod h1:Dm7WS1AgLmBa0NcQD6SeJnJf+K/EUW3GR7Ks6olB3OA= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mozillazg/go-httpheader v0.3.1 h1:IRP+HFrMX2SlwY9riuio7raffXUpzAosHtZu25BSJok= github.com/mozillazg/go-httpheader v0.3.1/go.mod h1:PuT8h0pw6efvp8ZeUec1Rs7dwjK08bt6gKSReGMqtdA= @@ -561,122 +594,151 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oauth2-proxy/oauth2-proxy/v7 v7.5.1 h1:zu+o5Zk0MJxeZTAKhgybBVm6GZwI6D8CD0WzCR8sESQ= -github.com/oauth2-proxy/oauth2-proxy/v7 v7.5.1/go.mod h1:9TIUszoaT174lwycQ2XmG4h5KVEfgqmVL1SISuIqu04= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= +github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= +github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= +github.com/oasdiff/yaml3 v0.0.12/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= +github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 h1:CiTjQE/Hh5xK2t56ogrDK4nl0+tJPNmASCs4zEYZ/xU= +github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0/go.mod h1:WUFkzTiOpt7EYyL67gv1GOf3RD8qKWGtin3lY9LYzW4= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 h1:1TLg6YrS3Au6F7xw3ws2Njbwj13IMqPplvGFi+18fWs= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0/go.mod h1:P8hZEDIQk4REgUWyLhSVRHwTxK6KkifKfg36BmmQ/DI= +github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0 h1:xgD/kNGp/wWY+bwY599Pc01OamYN17phRiTP934bM5Y= +github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0/go.mod h1:ZK7wvaefla9lB3bAW0rNKt7IzRPcTRQoOFqr4sZy/XM= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= -github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= -github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= -github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/opentracing-contrib/go-grpc v0.1.2 h1:MP16Ozc59kqqwn1v18aQxpeGZhsBanJ2iurZYaQSZ+g= +github.com/opentracing-contrib/go-grpc v0.1.2/go.mod h1:glU6rl1Fhfp9aXUHkE36K2mR4ht8vih0ekOVlWKEUHM= +github.com/opentracing-contrib/go-stdlib v1.1.1 h1:nl22krMt3PpAWPCKpDjFiAH4Qdr2855F5wOkQ52C0+w= +github.com/opentracing-contrib/go-stdlib v1.1.1/go.mod h1:S0p+X9p6dcBkoMTL+Qq2VOvxKs9ys5PpYWXWqlCS0bQ= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= github.com/oracle/oci-go-sdk/v65 v65.41.1 h1:+lbosOyNiib3TGJDvLq1HwEAuFqkOjPJDIkyxM15WdQ= github.com/oracle/oci-go-sdk/v65 v65.41.1/go.mod h1:MXMLMzHnnd9wlpgadPkdlkZ9YrwQmCOmbX5kjVEJodw= -github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= -github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= -github.com/parquet-go/parquet-go v0.18.1-0.20231004061202-cde8189c4c26 h1:46gJLpBloArJ3oU2AZpeBQgZmgLzE+iDCOgxz78cwgk= -github.com/parquet-go/parquet-go v0.18.1-0.20231004061202-cde8189c4c26/go.mod h1:6pu/Ca02WRyWyF6jbY1KceESGBZMsRMSijjLbajXaG8= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= +github.com/ovh/go-ovh v1.9.0 h1:6K8VoL3BYjVV3In9tPJUdT7qMx9h0GExN9EXx1r2kKE= +github.com/ovh/go-ovh v1.9.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c= +github.com/parquet-go/bitpack v1.0.0 h1:AUqzlKzPPXf2bCdjfj4sTeacrUwsT7NlcYDMUQxPcQA= +github.com/parquet-go/bitpack v1.0.0/go.mod h1:XnVk9TH+O40eOOmvpAVZ7K2ocQFrQwysLMnc6M/8lgs= +github.com/parquet-go/jsonlite v1.0.0 h1:87QNdi56wOfsE5bdgas0vRzHPxfJgzrXGml1zZdd7VU= +github.com/parquet-go/jsonlite v1.0.0/go.mod h1:nDjpkpL4EOtqs6NQugUsi0Rleq9sW/OtC1NnZEnxzF0= +github.com/parquet-go/parquet-go v0.26.4 h1:zJ3l8ef5WJZE2m63pKwyEJ2BhyDlgS0PfOEhuCQQU2A= +github.com/parquet-go/parquet-go v0.26.4/go.mod h1:h9GcSt41Knf5qXI1tp1TfR8bDBUtvdUMzSKe26aZcHk= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pb33f/jsonpath v0.8.1 h1:84C6QRyx6HcSm6PZnsMpcqYot3IsZ+m0n95+0NbBbvs= +github.com/pb33f/jsonpath v0.8.1/go.mod h1:zBV5LJW4OQOPatmQE2QdKpGQJvhDTlE5IEj6ASaRNTo= +github.com/pb33f/libopenapi v0.34.3 h1:3D1N56ayc7iOeEnKoy85QDe4tFbg5G1sj2J5UISi4Is= +github.com/pb33f/libopenapi v0.34.3/go.mod h1:sD2REdvz9QSFY9enfFHBCwwwZ41k/86krTM9qtKEBwQ= +github.com/pb33f/libopenapi-validator v0.13.3 h1:5KW4Y/mMoQvt6d89rLiNmW1zSfln7Oua2A0BqPXpjro= +github.com/pb33f/libopenapi-validator v0.13.3/go.mod h1:X58CRsmj/7l0iXethEMfq3OJIzQ5hces7EbJ071z6WI= +github.com/pb33f/ordered-map/v2 v2.3.0 h1:k2OhVEQkhTCQMhAicQ3Z6iInzoZNQ7L9MVomwKBZ5WQ= +github.com/pb33f/ordered-map/v2 v2.3.0/go.mod h1:oe5ue+6ZNhy7QN9cPZvPA23Hx0vMHnNVeMg4fGdCANw= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pires/go-proxyproto v0.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG68wXH4= +github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA= -github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25 h1:S1hI5JiKP7883xBzZAr1ydcxrKNSVNm7+3+JwjxZEsg= +github.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25/go.mod h1:ZQntvDG8TkPgljxtA0R9frDoND4QORU1VXz015N5Ks4= +github.com/platinummonkey/go-concurrency-limits v0.10.0 h1:LNF0gxmYmkBcW7+z2ZKrz5UlHMAtWrNBnNwLRcvOW2s= +github.com/platinummonkey/go-concurrency-limits v0.10.0/go.mod h1:dwS7NIGIH7tAuoTbXS9l//mOJJT+Nqs6+3ZY9g0h34k= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/alertmanager v0.27.0 h1:V6nTa2J5V4s8TG4C4HtrBP/WNSebCCTYGGv4qecA/+I= -github.com/prometheus/alertmanager v0.27.0/go.mod h1:8Ia/R3urPmbzJ8OsdvmZvIprDwvwmYCmUbwBL+jlPOE= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/alertmanager v0.31.1 h1:eAmIC42lzbWslHkMt693T36qdxfyZULswiHr681YS3Q= +github.com/prometheus/alertmanager v0.31.1/go.mod h1:zWPQwhbLt2ybee8rL921UONeQ59Oncash+m/hGP17tU= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 h1:1Y6bmpZb8peQCy1IpctnAhIFuyhrdtMaDnETChhSNns= +github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856/go.mod h1:Vf0QcmVhGqpjLxZOaWrFSep86vchQtJmbztFaMM4f6Q= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA= -github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= -github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= -github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= -github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= -github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/exporter-toolkit v0.15.1 h1:XrGGr/qWl8Gd+pqJqTkNLww9eG8vR/CoRk0FubOKfLE= +github.com/prometheus/exporter-toolkit v0.15.1/go.mod h1:P/NR9qFRGbCFgpklyhix9F6v6fFr/VQB/CVsrMDGKo4= +github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos= +github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.51.2 h1:U0faf1nT4CB9DkBW87XLJCBi2s8nwWXdTbyzRUAkX0w= -github.com/prometheus/prometheus v0.51.2/go.mod h1:yv4MwOn3yHMQ6MZGHPg/U7Fcyqf+rxqiZfSur6myVtc= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= +github.com/prometheus/prometheus v0.311.3 h1:3IrVxQv6v5i/ZCGi6OrYeBhtCwaPTn6Z3DYruXoYm3M= +github.com/prometheus/prometheus v0.311.3/go.mod h1:gjsCxTKtHO1Q8T9333u1s+lUR1OjPyM7ruuGH8RvVyo= +github.com/prometheus/sigv4 v0.4.1 h1:EIc3j+8NBea9u1iV6O5ZAN8uvPq2xOIUPcqCTivHuXs= +github.com/prometheus/sigv4 v0.4.1/go.mod h1:eu+ZbRvsc5TPiHwqh77OWuCnWK73IdkETYY46P4dXOU= +github.com/puzpuzpuz/xsync/v4 v4.4.0 h1:vlSN6/CkEY0pY8KaB0yqo/pCLZvp9nhdbBdjipT4gWo= +github.com/puzpuzpuz/xsync/v4 v4.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= -github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= -github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25 h1:/8rfZAdFfafRXOgz+ZpMZZWZ5pYggCY9t7e/BvjaBHM= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/samber/lo v1.53.0 h1:t975lj2py4kJPQ6haz1QMgtId2gtmfktACxIXArw3HM= +github.com/samber/lo v1.53.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P/ToHD/bdSb4Eg4tUo= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQWfuxwL4rf/2UEpxXz1o1EMtM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= -github.com/segmentio/encoding v0.3.6 h1:E6lVLyDPseWEulBmCmAKPanDd3jiyGDo5gMcugCRwZQ= -github.com/segmentio/encoding v0.3.6/go.mod h1:n0JeuIqEQrQoPDGsjo8UNd1iA0U8d8+oHAA4E3G3OxM= -github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= -github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= +github.com/sercand/kuberesolver/v6 v6.0.1 h1:XZUTA0gy/lgDYp/UhEwv7Js24F1j8NJ833QrWv0Xux4= +github.com/sercand/kuberesolver/v6 v6.0.1/go.mod h1:C0tsTuRMONSY+Xf7pv7RMW1/JlewY1+wS8SZE+1lf1s= github.com/simonswine/tempopb v0.2.0 h1:qWjiGI7I+9uelaRPvlYOJ1ellMFicFHdgCQ7tuZThVQ= github.com/simonswine/tempopb v0.2.0/go.mod h1:zfqdWNELQm8xvUj9Q/wGC6UVrFHqm8Y4XLuxm6ruW8c= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/sony/gobreaker/v2 v2.4.0 h1:g2KJRW1Ubty3+ZOcSEUN7K+REQJdN6yo6XvaML+jptg= +github.com/sony/gobreaker/v2 v2.4.0/go.mod h1:pTyFJgcZ3h2tdQVLZZruK2C0eoFL1fb/G83wK1ZQl+s= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +github.com/stackitcloud/stackit-sdk-go/core v0.23.0 h1:zPrOhf3Xe47rKRs1fg/AqKYUiJJRYjdcv+3qsS50mEs= +github.com/stackitcloud/stackit-sdk-go/core v0.23.0/go.mod h1:osMglDby4csGZ5sIfhNyYq1bS1TxIdPY88+skE/kkmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -686,126 +748,214 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4= github.com/tencentyun/cos-go-sdk-v5 v0.7.40 h1:W6vDGKCHe4wBACI1d2UgE6+50sJFhRWU4O8IB2ozzxM= github.com/tencentyun/cos-go-sdk-v5 v0.7.40/go.mod h1:4dCEtLHGh8QPxHEkgq+nFaky7yZxQuYwgSJM87icDaw= +github.com/thanos-io/objstore v0.0.0-20250813080715-4e5fd4289b50 h1:LQ/cJudNo7b1g6WhJmt6vl4TaIhi8GqyyANlnow4rmQ= +github.com/thanos-io/objstore v0.0.0-20250813080715-4e5fd4289b50/go.mod h1:47A17iRctHuA2KF73MSbOb7XELVyECduETzQAplRXNI= +github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY= +github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= -github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= +github.com/vultr/govultr/v3 v3.28.1 h1:KR3LhppYARlBujY7+dcrE7YKL0Yo9qXL+msxykKQrLI= +github.com/vultr/govultr/v3 v3.28.1/go.mod h1:2zyUw9yADQaGwKnwDesmIOlBNLrm7edsCfWHFJpWKf8= +github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= -go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= -go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= -go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= -go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= -go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= -go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= -go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/collector/featuregate v1.3.0 h1:nrFSx+zfjdisjE9oCx25Aep3nJ9RaUjeE1qFL6eovoU= -go.opentelemetry.io/collector/featuregate v1.3.0/go.mod h1:mm8+xyQfgDmqhyegZRNIQmoKsNnDTwWKFLsdMoXAb7A= -go.opentelemetry.io/collector/pdata v1.3.0 h1:JRYN7tVHYFwmtQhIYbxWeiKSa2L1nCohyAs8sYqKFZo= -go.opentelemetry.io/collector/pdata v1.3.0/go.mod h1:t7W0Undtes53HODPdSujPLTnfSR5fzT+WpL+RTaaayo= -go.opentelemetry.io/collector/semconv v0.96.0 h1:DrZy8BpzJDnN2zFxXRj6BhfGYxNlqpFHBqyuS9fVHRY= -go.opentelemetry.io/collector/semconv v0.96.0/go.mod h1:zOm/U3pgMIWcvrcnPbR9Xx2HinoXj46ERMK8PUV9wrs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= +go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= +go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= +go.etcd.io/etcd/api/v3 v3.6.9 h1:UA7iKfEW1AzgihcBSGXci2kDGQiokSq41F9HMCI/RTI= +go.etcd.io/etcd/api/v3 v3.6.9/go.mod h1:csEk/qTfxKL36NqJdU15Tgtl65A8dyEY2BYo7PRsIwk= +go.etcd.io/etcd/client/pkg/v3 v3.6.9 h1:T8nuk8Lz64C+Hzb0coBFLMSlVSQZBpAtFk46swdM1DA= +go.etcd.io/etcd/client/pkg/v3 v3.6.9/go.mod h1:WEy3PpwbbEBVRdh1NVJYsuUe/8eyI21PNJRazeD8z/Y= +go.etcd.io/etcd/client/v3 v3.6.9 h1:3X555hQXmhRr27O37wls53g68CpUiPOiHXrZfz2Al+o= +go.etcd.io/etcd/client/v3 v3.6.9/go.mod h1:KO7H1HLYh1qaljuVZJQwBFk1lRce6pJzt+C81GEnrlM= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/collector/component v1.54.0 h1:LvtX0Tzz18n44OrUFVk77N1FNsejfWJqztB28hrmDM8= +go.opentelemetry.io/collector/component v1.54.0/go.mod h1:yUMBYsySY/sDcXm8kOzEoZxt+JLdala6hxzSW0npOxY= +go.opentelemetry.io/collector/component/componentstatus v0.148.0 h1:sCGRaXNQolHFhPjrNJEwQ1WZOf96iL99tzm9GxuZsvg= +go.opentelemetry.io/collector/component/componentstatus v0.148.0/go.mod h1:yqg3SpGQc22W3wGICdnb+2kZVW9daBr3+LrGUCHkKfc= +go.opentelemetry.io/collector/component/componenttest v0.148.0 h1:tBXJWmy2X6KD8S0QU2YZa2zYBqP+IycSM4iOtwDD2pA= +go.opentelemetry.io/collector/component/componenttest v0.148.0/go.mod h1:1c1+6mZOmI0raoya5vA/X0F+fawEjNS6tCEs5xLATtA= +go.opentelemetry.io/collector/confmap v1.54.0 h1:RUoxQ4uAYHTI57GfHh61D00tTQsXm9T88ozrAiicByc= +go.opentelemetry.io/collector/confmap v1.54.0/go.mod h1:mQxG8bk0IWIt9gbWMvzE+cRkOuCuzbzkNGBq2YJ4wNM= +go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 h1:UW8MX5VlKJf67x4Et7J9kPwP9Rv4VSmJ+UUpgRcb//c= +go.opentelemetry.io/collector/confmap/xconfmap v0.148.0/go.mod h1:4qTMr3V0uSXXac9wVs/UD5fIqRKw5yIl58+Vjsc6RHM= +go.opentelemetry.io/collector/consumer v1.54.0 h1:RGGtUN+GbkV1px3T6XdUHmgJ+ldJ1hAHdesFzW/wgL0= +go.opentelemetry.io/collector/consumer v1.54.0/go.mod h1:1PC6XINTL9DdT1bwvfMdHE72EB4RWU/WcPemUrhqKN8= +go.opentelemetry.io/collector/consumer/consumertest v0.148.0 h1:ms0HtWMj17tI1Yds0hSuUI5QYpNEqd11AAhwIoUY2HE= +go.opentelemetry.io/collector/consumer/consumertest v0.148.0/go.mod h1:wScw/OzKkf/ZzJn4ToI30OoI1kJiY16WNrcFToXSzK0= +go.opentelemetry.io/collector/consumer/xconsumer v0.148.0 h1:m3b9rY7CLD5Pcge6sSKHIT3OlcPN6xqYsdtVs9oJ528= +go.opentelemetry.io/collector/consumer/xconsumer v0.148.0/go.mod h1:bG+Wz6xmIBl/gHzq1sqvksWXqTLuTX17Wo//zIsdZpw= +go.opentelemetry.io/collector/featuregate v1.54.0 h1:ufo5Hy4Co9pcHVg24hyanm8qFG3TkkYbVyQXPVAbwDc= +go.opentelemetry.io/collector/featuregate v1.54.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g= +go.opentelemetry.io/collector/internal/componentalias v0.148.0 h1:Y6MftNIZSzOr47TTj6A2z2UR3IwbeG46sAQshicGtDg= +go.opentelemetry.io/collector/internal/componentalias v0.148.0/go.mod h1:uwKzfehzwRgHxdHgFXYSBHNBeWSSqsqQYGWr5fk08G0= +go.opentelemetry.io/collector/internal/testutil v0.148.0 h1:3Z9hperte3vSmbBTYeNndoEUICICrNz8hzx+v0FYXBQ= +go.opentelemetry.io/collector/internal/testutil v0.148.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= +go.opentelemetry.io/collector/pdata v1.54.0 h1:3LharKb792cQ3VrUGxd3IcpWwfu3ST+GSTU382jVz1s= +go.opentelemetry.io/collector/pdata v1.54.0/go.mod h1:+MqC3VVOv/EX9YVFUo+mI4F0YmwJ+fXBYwjmu+mRiZ8= +go.opentelemetry.io/collector/pdata/pprofile v0.148.0 h1:MgrNZmqwhZGfiYwcKKtM/iXgTZqqvG5dUphriRXMZHU= +go.opentelemetry.io/collector/pdata/pprofile v0.148.0/go.mod h1:MTTMnZPqWX1S/rBDatU0W19udlycBkWuzVV5qnemHdc= +go.opentelemetry.io/collector/pdata/testdata v0.148.0 h1:yzakPuFgoKK8WcrlhyYHLMLA/kLScQKGsXkIgwieAQ8= +go.opentelemetry.io/collector/pdata/testdata v0.148.0/go.mod h1:2rFvxm8qwd3nlO90FtJw6ZGAjt+bLndxmQuJaMO9kfQ= +go.opentelemetry.io/collector/pipeline v1.54.0 h1:jYlCkdFLITVBdeB+IGS07zXWywEgvT3Ky46vdKKT+Ks= +go.opentelemetry.io/collector/pipeline v1.54.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs= +go.opentelemetry.io/collector/processor v1.54.0 h1:zmHBFiEFmU9ZYuHhVP3lHIkbfy+ueapzGpTdXVMcWBg= +go.opentelemetry.io/collector/processor v1.54.0/go.mod h1:L0lA6DZ0VbrtQBg44cmYfSpRlgm4zxW1I6QfBnRizPw= +go.opentelemetry.io/collector/processor/processortest v0.148.0 h1:p0k59frZxy/Z4fXe82i5eOJv/UyOH75XhI8nFD1ZWCE= +go.opentelemetry.io/collector/processor/processortest v0.148.0/go.mod h1:E2Li2gnkUXgvApvGyEtn3Eq5KyzV05ljfbFRsZ7sTC4= +go.opentelemetry.io/collector/processor/xprocessor v0.148.0 h1:v7Qv6k2b2cvgGWuTO5KN5QYDLl1r5sznt7Le4Fhpa4c= +go.opentelemetry.io/collector/processor/xprocessor v0.148.0/go.mod h1:r7ADpSX2nf0rZR9STxh956Qw1740QOWMXLnEM/ZiaF8= +go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 h1:w3zlHYETbDwXyWHZlyyR58ZC39XGi8rAhkBgUgJ9d5w= +go.opentelemetry.io/contrib/bridges/prometheus v0.68.0/go.mod h1:GR/mClR2nn7vE8RLwxKjoBNg+QtgdDhRzxVa93koy5o= +go.opentelemetry.io/contrib/detectors/gcp v1.43.0 h1:62yY3dT7/ShwOxzA0RsKRgshBmfElKI4d/Myu2OxDFU= +go.opentelemetry.io/contrib/detectors/gcp v1.43.0/go.mod h1:RyaZMFY7yi1kAs45S6mbFGz8O8rqB0dTY14uzvG4LCs= +go.opentelemetry.io/contrib/exporters/autoexport v0.68.0 h1:0D3GFvELGIwQGfC6agLsbrEYSGWZTRTxIXxcQUqrOuk= +go.opentelemetry.io/contrib/exporters/autoexport v0.68.0/go.mod h1:DM2NV7Zb8CcGeVPt6glouY0FAiwZQ/iqgcWExhgWeN8= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 h1:0Qx7VGBacMm9ZENQ7TnNObTYI4ShC+lHI16seduaxZo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0/go.mod h1:Sje3i3MjSPKTSPvVWCaL8ugBzJwik3u4smCjUeuupqg= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0 h1:c9r/G1CSw4dPI1jaNNG9RnQP+q4SvZnHciDQJVIvchU= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0/go.mod h1:gO9smoZe9KnZcJCqcB0lMmQ4Z5VEifYmjMTpnwtTSuQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= +go.opentelemetry.io/contrib/propagators/jaeger v1.42.0 h1:jP8unWI6q5kcb3gpGLjKDGaUa+JW+nHKWvpS/q+YuWA= +go.opentelemetry.io/contrib/propagators/jaeger v1.42.0/go.mod h1:xd89e/pUyPatUP1C4z1UknD9jHptESO99tWyvd4mWD4= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.36.0 h1:h8kHGv9+VIiJbQ2Qx6BbORZwcvVnd0le/SFK8Vom0bA= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.36.0/go.mod h1:tjrgaYHDx+1CmTk5YzNAUCbLX1ZrjrsogXBQHaVf7rI= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/prometheus v0.65.0 h1:jOveH/b4lU9HT7y+Gfamf18BqlOuz2PWEvs8yM7Q6XE= +go.opentelemetry.io/otel/exporters/prometheus v0.65.0/go.mod h1:i1P8pcumauPtUI4YNopea1dhzEMuEqWP1xoUZDylLHo= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 h1:GJkybS+crDMdExT/BUNCEgfrmfboztcS6PhvSo88HKM= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0/go.mod h1:NuAyxRYIG2lKX3YQkB+83StTxM7s52PUUkRRiC0wnYI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 h1:TC+BewnDpeiAmcscXbGMfxkO+mwYUwE/VySwvw88PfA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0/go.mod h1:J/ZyF4vfPwsSr9xJSPyQ4LqtcTPULFR64KwTikGLe+A= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= +go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= +go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= +go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= +go.opentelemetry.io/proto/otlp/collector/profiles/v1development v0.3.0 h1:AWBLtJn3ajH399gyOuJdqPsC9w152x3xGVVO/UK3vyM= +go.opentelemetry.io/proto/otlp/collector/profiles/v1development v0.3.0/go.mod h1:kCdbxyM9kfmv3v4ZQzZ2pACxoQ6lE0IsjP+UcZwQnr4= +go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 h1:ZQs05qo3Yh4KUHeVH6v89xErwmsvgA/cLX2/w5Ikp+k= +go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0/go.mod h1:3iiRVKaCfVo0UI1ZaSMm5WbCBbINRqVlD9SUmvyBNrY= +go.opentelemetry.io/proto/slim/otlp v1.10.0 h1:iR97Vs/ZDR+y9TfuP9b1XBtdPWeC+OMslIBmhcLU7jM= +go.opentelemetry.io/proto/slim/otlp v1.10.0/go.mod h1:lV9250stpjYLPNA5viFabIgP2QlUGRT1GdTgAf8SIUk= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.3.0 h1:RUF5rO0hAlgiJt1fzQVzcVs3vZVNHIcMLgOgG4rWNcQ= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.3.0/go.mod h1:I89cynRj8y+383o7tEQVg2SVA6SRgDVIouWPUVXjx0U= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.3.0 h1:CQvJSldHRUN6Z8jsUeYv8J0lXRvygALXIzsmAeCcZE0= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.3.0/go.mod h1:xSQ+mEfJe/GjK1LXEyVOoSI1N9JV9ZI923X5kup43W4= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U= +go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -813,307 +963,168 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.168.0 h1:MBRe+Ki4mMN93jhDDbpuRLjRddooArz4FeSObvUMmjY= -google.golang.org/api v0.168.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.272.0 h1:eLUQZGnAS3OHn31URRf9sAmRk3w2JjMx37d2k8AjJmA= +google.golang.org/api v0.272.0/go.mod h1:wKjowi5LNJc5qarNvDCvNQBn3rVK8nSy6jg2SwRwzIA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 h1:8eadJkXbwDEMNwcB5O0s5Y5eCfyuCLdvaiOIaGTrWmQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d h1:vsOm753cOAMkt76efriTCDKjpCbK18XGHMJHo0JUKhc= +google.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:0oz9d7g9QLSdv9/lgbIjowW1JoxMbxmBVNe8i6tORJI= +google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 h1:U8orV30l6KpDsi9dxU0CoJZGbjS8EEpw+6ba+XwGPQA= +google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348/go.mod h1:Yzdzr5OOZFgSsEV2D/Xi9NL3bszpXFAg0hFJiRohcD8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 h1:tEkOQcXgF6dH1G+MVKZrfpYvozGrzb91k6ha7jireSM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= +gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1123,31 +1134,24 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= -k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= -k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= -k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= -k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= -k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +k8s.io/api v0.35.3 h1:pA2fiBc6+N9PDf7SAiluKGEBuScsTzd2uYBkA5RzNWQ= +k8s.io/api v0.35.3/go.mod h1:9Y9tkBcFwKNq2sxwZTQh1Njh9qHl81D0As56tu42GA4= +k8s.io/apimachinery v0.35.3 h1:MeaUwQCV3tjKP4bcwWGgZ/cp/vpsRnQzqO6J6tJyoF8= +k8s.io/apimachinery v0.35.3/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/client-go v0.35.3 h1:s1lZbpN4uI6IxeTM2cpdtrwHcSOBML1ODNTCCfsP1pg= +k8s.io/client-go v0.35.3/go.mod h1:RzoXkc0mzpWIDvBrRnD+VlfXP+lRzqQjCmKtiwZ8Q9c= +k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= +k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/go.work b/go.work deleted file mode 100644 index 161e97afa1..0000000000 --- a/go.work +++ /dev/null @@ -1,7 +0,0 @@ -go 1.21 - -use ( - . - ./api - ./ebpf -) diff --git a/go.work.sum b/go.work.sum deleted file mode 100644 index 132718b1ae..0000000000 --- a/go.work.sum +++ /dev/null @@ -1,1361 +0,0 @@ -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= -cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= -cloud.google.com/go/accessapproval v1.7.4 h1:ZvLvJ952zK8pFHINjpMBY5k7LTAp/6pBf50RDMRgBUI= -cloud.google.com/go/accessapproval v1.7.4/go.mod h1:/aTEh45LzplQgFYdQdwPMR9YdX0UlhBmvB84uAmQKUc= -cloud.google.com/go/accessapproval v1.7.5 h1:uzmAMSgYcnlHa9X9YSQZ4Q1wlfl4NNkZyQgho1Z6p04= -cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0= -cloud.google.com/go/accesscontextmanager v1.8.4 h1:Yo4g2XrBETBCqyWIibN3NHNPQKUfQqti0lI+70rubeE= -cloud.google.com/go/accesscontextmanager v1.8.4/go.mod h1:ParU+WbMpD34s5JFEnGAnPBYAgUHozaTmDJU7aCU9+M= -cloud.google.com/go/accesscontextmanager v1.8.5 h1:2GLNaNu9KRJhJBFTIVRoPwk6xE5mUDgD47abBq4Zp/I= -cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q= -cloud.google.com/go/aiplatform v1.57.0 h1:WcZ6wDf/1qBWatmGM9Z+2BTiNjQQX54k2BekHUj93DQ= -cloud.google.com/go/aiplatform v1.57.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.58.2 h1:qu6n5nqCRntJOIjqs2/SztZp4KMuXTejyMRkPC0eGhM= -cloud.google.com/go/aiplatform v1.58.2/go.mod h1:c3kCiVmb6UC1dHAjZjcpDj6ZS0bHQ2slL88ZjC2LtlA= -cloud.google.com/go/analytics v0.21.6 h1:fnV7B8lqyEYxCU0LKk+vUL7mTlqRAq4uFlIthIdr/iA= -cloud.google.com/go/analytics v0.21.6/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= -cloud.google.com/go/analytics v0.23.0 h1:Q+y94XH84jM8SK8O7qiY/PJRexb6n7dRbQ6PiUa4YGM= -cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0= -cloud.google.com/go/apigateway v1.6.4 h1:VVIxCtVerchHienSlaGzV6XJGtEM9828Erzyr3miUGs= -cloud.google.com/go/apigateway v1.6.4/go.mod h1:0EpJlVGH5HwAN4VF4Iec8TAzGN1aQgbxAWGJsnPCGGY= -cloud.google.com/go/apigateway v1.6.5 h1:sPXnpk+6TneKIrjCjcpX5YGsAKy3PTdpIchoj8/74OE= -cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI= -cloud.google.com/go/apigeeconnect v1.6.4 h1:jSoGITWKgAj/ssVogNE9SdsTqcXnryPzsulENSRlusI= -cloud.google.com/go/apigeeconnect v1.6.4/go.mod h1:CapQCWZ8TCjnU0d7PobxhpOdVz/OVJ2Hr/Zcuu1xFx0= -cloud.google.com/go/apigeeconnect v1.6.5 h1:CrfIKv9Go3fh/QfQgisU3MeP90Ww7l/sVGmr3TpECo8= -cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow= -cloud.google.com/go/apigeeregistry v0.8.2 h1:DSaD1iiqvELag+lV4VnnqUUFd8GXELu01tKVdWZrviE= -cloud.google.com/go/apigeeregistry v0.8.2/go.mod h1:h4v11TDGdeXJDJvImtgK2AFVvMIgGWjSb0HRnBSjcX8= -cloud.google.com/go/apigeeregistry v0.8.3 h1:C+QU2K+DzDjk4g074ouwHQGkoff1h5OMQp6sblCVreQ= -cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs= -cloud.google.com/go/appengine v1.8.4 h1:Qub3fqR7iA1daJWdzjp/Q0Jz0fUG0JbMc7Ui4E9IX/E= -cloud.google.com/go/appengine v1.8.4/go.mod h1:TZ24v+wXBujtkK77CXCpjZbnuTvsFNT41MUaZ28D6vg= -cloud.google.com/go/appengine v1.8.5 h1:l2SviT44zWQiOv8bPoMBzW0vOcMO22iO0s+nVtVhdts= -cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo= -cloud.google.com/go/area120 v0.8.4 h1:YnSO8m02pOIo6AEOgiOoUDVbw4pf+bg2KLHi4rky320= -cloud.google.com/go/area120 v0.8.4/go.mod h1:jfawXjxf29wyBXr48+W+GyX/f8fflxp642D/bb9v68M= -cloud.google.com/go/area120 v0.8.5 h1:vTs08KPLN/iMzTbxpu5ciL06KcsrVPMjz4IwcQyZ4uY= -cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0= -cloud.google.com/go/artifactregistry v1.14.6 h1:/hQaadYytMdA5zBh+RciIrXZQBWK4vN7EUsrQHG+/t8= -cloud.google.com/go/artifactregistry v1.14.6/go.mod h1:np9LSFotNWHcjnOgh8UVK0RFPCTUGbO0ve3384xyHfE= -cloud.google.com/go/artifactregistry v1.14.7 h1:W9sVlyb1VRcUf83w7aM3yMsnp4HS4PoyGqYQNG0O5lI= -cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM= -cloud.google.com/go/asset v1.15.3 h1:uI8Bdm81s0esVWbWrTHcjFDFKNOa9aB7rI1vud1hO84= -cloud.google.com/go/asset v1.15.3/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.17.1 h1:xra2nJlExLat2rcpimofBw+SmPwgS78Xxhg4Lh/BcyA= -cloud.google.com/go/asset v1.17.1/go.mod h1:byvDw36UME5AzGNK7o4JnOnINkwOZ1yRrGrKIahHrng= -cloud.google.com/go/assuredworkloads v1.11.4 h1:FsLSkmYYeNuzDm8L4YPfLWV+lQaUrJmH5OuD37t1k20= -cloud.google.com/go/assuredworkloads v1.11.4/go.mod h1:4pwwGNwy1RP0m+y12ef3Q/8PaiWrIDQ6nD2E8kvWI9U= -cloud.google.com/go/assuredworkloads v1.11.5 h1:gCrN3IyvqY3cP0wh2h43d99CgH3G+WYs9CeuFVKChR8= -cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk= -cloud.google.com/go/automl v1.13.4 h1:i9tOKXX+1gE7+rHpWKjiuPfGBVIYoWvLNIGpWgPtF58= -cloud.google.com/go/automl v1.13.4/go.mod h1:ULqwX/OLZ4hBVfKQaMtxMSTlPx0GqGbWN8uA/1EqCP8= -cloud.google.com/go/automl v1.13.5 h1:ijiJy9sYWh75WrqImXsfWc1e3HR3iO+ef9fvW03Ig/4= -cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y= -cloud.google.com/go/baremetalsolution v1.2.3 h1:oQiFYYCe0vwp7J8ZmF6siVKEumWtiPFJMJcGuyDVRUk= -cloud.google.com/go/baremetalsolution v1.2.3/go.mod h1:/UAQ5xG3faDdy180rCUv47e0jvpp3BFxT+Cl0PFjw5g= -cloud.google.com/go/baremetalsolution v1.2.4 h1:LFydisRmS7hQk9P/YhekwuZGqb45TW4QavcrMToWo5A= -cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY= -cloud.google.com/go/batch v1.7.0 h1:AxuSPoL2fWn/rUyvWeNCNd0V2WCr+iHRCU9QO1PUmpY= -cloud.google.com/go/batch v1.7.0/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= -cloud.google.com/go/batch v1.8.0 h1:2HK4JerwVaIcCh/lJiHwh6+uswPthiMMWhiSWLELayk= -cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc= -cloud.google.com/go/beyondcorp v1.0.3 h1:VXf9SnrnSmj2BF2cHkoTHvOUp8gjsz1KJFOMW7czdsY= -cloud.google.com/go/beyondcorp v1.0.3/go.mod h1:HcBvnEd7eYr+HGDd5ZbuVmBYX019C6CEXBonXbCVwJo= -cloud.google.com/go/beyondcorp v1.0.4 h1:qs0J0O9Ol2h1yA0AU+r7l3hOCPzs2MjE1d6d/kaHIKo= -cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc= -cloud.google.com/go/bigquery v1.57.1 h1:FiULdbbzUxWD0Y4ZGPSVCDLvqRSyCIO6zKV7E2nf5uA= -cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug= -cloud.google.com/go/bigquery v1.58.0 h1:drSd9RcPVLJP2iFMimvOB9SCSIrcl+9HD4II03Oy7A0= -cloud.google.com/go/bigquery v1.58.0/go.mod h1:0eh4mWNY0KrBTjUzLjoYImapGORq9gEPT7MWjCy9lik= -cloud.google.com/go/billing v1.18.0 h1:GvKy4xLy1zF1XPbwP5NJb2HjRxhnhxjjXxvyZ1S/IAo= -cloud.google.com/go/billing v1.18.0/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= -cloud.google.com/go/billing v1.18.2 h1:oWUEQvuC4JvtnqLZ35zgzdbuHt4Itbftvzbe6aEyFdE= -cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE= -cloud.google.com/go/binaryauthorization v1.8.0 h1:PHS89lcFayWIEe0/s2jTBiEOtqghCxzc7y7bRNlifBs= -cloud.google.com/go/binaryauthorization v1.8.0/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= -cloud.google.com/go/binaryauthorization v1.8.1 h1:1jcyh2uIUwSZkJ/JmL8kd5SUkL/Krbv8zmYLEbAz6kY= -cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ= -cloud.google.com/go/certificatemanager v1.7.4 h1:5YMQ3Q+dqGpwUZ9X5sipsOQ1fLPsxod9HNq0+nrqc6I= -cloud.google.com/go/certificatemanager v1.7.4/go.mod h1:FHAylPe/6IIKuaRmHbjbdLhGhVQ+CWHSD5Jq0k4+cCE= -cloud.google.com/go/certificatemanager v1.7.5 h1:UMBr/twXvH3jcT5J5/YjRxf2tvwTYIfrpemTebe0txc= -cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM= -cloud.google.com/go/channel v1.17.3 h1:Rd4+fBrjiN6tZ4TR8R/38elkyEkz6oogGDr7jDyjmMY= -cloud.google.com/go/channel v1.17.3/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= -cloud.google.com/go/channel v1.17.5 h1:/omiBnyFjm4S1ETHoOmJbL7LH7Ljcei4rYG6Sj3hc80= -cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc= -cloud.google.com/go/cloudbuild v1.15.0 h1:9IHfEMWdCklJ1cwouoiQrnxmP0q3pH7JUt8Hqx4Qbck= -cloud.google.com/go/cloudbuild v1.15.0/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= -cloud.google.com/go/cloudbuild v1.15.1 h1:ZB6oOmJo+MTov9n629fiCrO9YZPOg25FZvQ7gIHu5ng= -cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals= -cloud.google.com/go/clouddms v1.7.3 h1:xe/wJKz55VO1+L891a1EG9lVUgfHr9Ju/I3xh1nwF84= -cloud.google.com/go/clouddms v1.7.3/go.mod h1:fkN2HQQNUYInAU3NQ3vRLkV2iWs8lIdmBKOx4nrL6Hc= -cloud.google.com/go/clouddms v1.7.4 h1:Sr0Zo5EAcPQiCBgHWICg3VGkcdS/LLP1d9SR7qQBM/s= -cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY= -cloud.google.com/go/cloudtasks v1.12.4 h1:5xXuFfAjg0Z5Wb81j2GAbB3e0bwroCeSF+5jBn/L650= -cloud.google.com/go/cloudtasks v1.12.4/go.mod h1:BEPu0Gtt2dU6FxZHNqqNdGqIG86qyWKBPGnsb7udGY0= -cloud.google.com/go/cloudtasks v1.12.6 h1:EUt1hIZ9bLv8Iz9yWaCrqgMnIU+Tdh0yXM1MMVGhjfE= -cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.20.0/go.mod h1:kn5BhC++qUWR/AM3Dn21myV7QbgqejW04cAOrtppaQI= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.12.1 h1:EiGBeejtDDtr3JXt9W7xlhXyZ+REB5k2tBgVPVtmNb0= -cloud.google.com/go/contactcenterinsights v1.12.1/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.13.0 h1:6Vs/YnDG5STGjlWMEjN/xtmft7MrOTOnOZYUZtGTx0w= -cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI= -cloud.google.com/go/container v1.29.0 h1:jIltU529R2zBFvP8rhiG1mgeTcnT27KhU0H/1d6SQRg= -cloud.google.com/go/container v1.29.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.30.1 h1:DbEwg6d9FggyNeSb+AiW6142m2YVPTSENzGx2INDv58= -cloud.google.com/go/container v1.30.1/go.mod h1:vkbfX0EnAKL/vgVECs5BZn24e1cJROzgszJirRKQ4Bg= -cloud.google.com/go/containeranalysis v0.11.3 h1:5rhYLX+3a01drpREqBZVXR9YmWH45RnML++8NsCtuD8= -cloud.google.com/go/containeranalysis v0.11.3/go.mod h1:kMeST7yWFQMGjiG9K7Eov+fPNQcGhb8mXj/UcTiWw9U= -cloud.google.com/go/containeranalysis v0.11.4 h1:doJ0M1ljS4hS0D2UbHywlHGwB7sQLNrt9vFk9Zyi7vY= -cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE= -cloud.google.com/go/datacatalog v1.19.0 h1:rbYNmHwvAOOwnW2FPXYkaK3Mf1MmGqRzK0mMiIEyLdo= -cloud.google.com/go/datacatalog v1.19.0/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= -cloud.google.com/go/datacatalog v1.19.3 h1:A0vKYCQdxQuV4Pi0LL9p39Vwvg4jH5yYveMv50gU5Tw= -cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4= -cloud.google.com/go/dataflow v0.9.4 h1:7VmCNWcPJBS/srN2QnStTB6nu4Eb5TMcpkmtaPVhRt4= -cloud.google.com/go/dataflow v0.9.4/go.mod h1:4G8vAkHYCSzU8b/kmsoR2lWyHJD85oMJPHMtan40K8w= -cloud.google.com/go/dataflow v0.9.5 h1:RYHtcPhmE664+F0Je46p+NvFbG8z//KCXp+uEqB4jZU= -cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ= -cloud.google.com/go/dataform v0.9.1 h1:jV+EsDamGX6cE127+QAcCR/lergVeeZdEQ6DdrxW3sQ= -cloud.google.com/go/dataform v0.9.1/go.mod h1:pWTg+zGQ7i16pyn0bS1ruqIE91SdL2FDMvEYu/8oQxs= -cloud.google.com/go/dataform v0.9.2 h1:5e4eqGrd0iDTCg4Q+VlAao5j2naKAA7xRurNtwmUknU= -cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI= -cloud.google.com/go/datafusion v1.7.4 h1:Q90alBEYlMi66zL5gMSGQHfbZLB55mOAg03DhwTTfsk= -cloud.google.com/go/datafusion v1.7.4/go.mod h1:BBs78WTOLYkT4GVZIXQCZT3GFpkpDN4aBY4NDX/jVlM= -cloud.google.com/go/datafusion v1.7.5 h1:HQ/BUOP8OIGJxuztpYvNvlb+/U+/Bfs9SO8tQbh61fk= -cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc= -cloud.google.com/go/datalabeling v0.8.4 h1:zrq4uMmunf2KFDl/7dS6iCDBBAxBnKVDyw6+ajz3yu0= -cloud.google.com/go/datalabeling v0.8.4/go.mod h1:Z1z3E6LHtffBGrNUkKwbwbDxTiXEApLzIgmymj8A3S8= -cloud.google.com/go/datalabeling v0.8.5 h1:GpIFRdm0qIZNsxqURFJwHt0ZBJZ0nF/mUVEigR7PH/8= -cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s= -cloud.google.com/go/dataplex v1.13.0 h1:ACVOuxwe7gP0SqEso9SLyXbcZNk5l8hjcTX+XLntI5s= -cloud.google.com/go/dataplex v1.13.0/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.14.1 h1:7qrFI9Mz7wNpYjloi6BYVxV0deV09/RbajprVV+ni6Q= -cloud.google.com/go/dataplex v1.14.1/go.mod h1:bWxQAbg6Smg+sca2+Ex7s8D9a5qU6xfXtwmq4BVReps= -cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataproc/v2 v2.3.0 h1:tTVP9tTxmc8fixxOd/8s6Q6Pz/+yzn7r7XdZHretQH0= -cloud.google.com/go/dataproc/v2 v2.3.0/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= -cloud.google.com/go/dataproc/v2 v2.4.0 h1:/u81Fd+BvCLp+xjctI1DiWVJn6cn9/s3Akc8xPH02yk= -cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4= -cloud.google.com/go/dataqna v0.8.4 h1:NJnu1kAPamZDs/if3bJ3+Wb6tjADHKL83NUWsaIp2zg= -cloud.google.com/go/dataqna v0.8.4/go.mod h1:mySRKjKg5Lz784P6sCov3p1QD+RZQONRMRjzGNcFd0c= -cloud.google.com/go/dataqna v0.8.5 h1:9ybXs3nr9BzxSGC04SsvtuXaHY0qmJSLIpIAbZo9GqQ= -cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM= -cloud.google.com/go/datastore v1.15.0 h1:0P9WcsQeTWjuD1H14JIY7XQscIPQ4Laje8ti96IC5vg= -cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastream v1.10.3 h1:Z2sKPIB7bT2kMW5Uhxy44ZgdJzxzE5uKjavoW+EuHEE= -cloud.google.com/go/datastream v1.10.3/go.mod h1:YR0USzgjhqA/Id0Ycu1VvZe8hEWwrkjuXrGbzeDOSEA= -cloud.google.com/go/datastream v1.10.4 h1:o1QDKMo/hk0FN7vhoUQURREuA0rgKmnYapB+1M+7Qz4= -cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo= -cloud.google.com/go/deploy v1.16.0 h1:5OVjzm8MPC5kP+Ywbs0mdE0O7AXvAUXksSyHAyMFyMg= -cloud.google.com/go/deploy v1.16.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.17.1 h1:m27Ojwj03gvpJqCbodLYiVmE9x4/LrHGGMjzc0LBfM4= -cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50= -cloud.google.com/go/dialogflow v1.47.0 h1:tLCWad8HZhlyUNfDzDP5m+oH6h/1Uvw/ei7B9AnsWMk= -cloud.google.com/go/dialogflow v1.47.0/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.48.2 h1:KK9beiSJIqdrjdVHJoUuDDNSnWReY2e+7Cm6adq7moA= -cloud.google.com/go/dialogflow v1.48.2/go.mod h1:7A2oDf6JJ1/+hdpnFRfb/RjJUOh2X3rhIa5P8wQSEX4= -cloud.google.com/go/dlp v1.11.1 h1:OFlXedmPP/5//X1hBEeq3D9kUVm9fb6ywYANlpv/EsQ= -cloud.google.com/go/dlp v1.11.1/go.mod h1:/PA2EnioBeXTL/0hInwgj0rfsQb3lpE3R8XUJxqUNKI= -cloud.google.com/go/dlp v1.11.2 h1:lTipOuJaSjlYnnotPMbEhKURLC6GzCMDDzVbJAEbmYM= -cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w= -cloud.google.com/go/documentai v1.23.6 h1:0/S3AhS23+0qaFe3tkgMmS3STxgDgmE1jg4TvaDOZ9g= -cloud.google.com/go/documentai v1.23.6/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.8 h1:ZObcx0ia1XTj737+K9W8ngWFzghyf9c0/BvdJcADONk= -cloud.google.com/go/documentai v1.23.8/go.mod h1:Vd/y5PosxCpUHmwC+v9arZyeMfTqBR9VIwOwIqQYYfA= -cloud.google.com/go/domains v0.9.4 h1:ua4GvsDztZ5F3xqjeLKVRDeOvJshf5QFgWGg1CKti3A= -cloud.google.com/go/domains v0.9.4/go.mod h1:27jmJGShuXYdUNjyDG0SodTfT5RwLi7xmH334Gvi3fY= -cloud.google.com/go/domains v0.9.5 h1:Mml/R6s3vQQvFPpi/9oX3O5dRirgjyJ8cksK8N19Y7g= -cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y= -cloud.google.com/go/edgecontainer v1.1.4 h1:Szy3Q/N6bqgQGyxqjI+6xJZbmvPvnFHp3UZr95DKcQ0= -cloud.google.com/go/edgecontainer v1.1.4/go.mod h1:AvFdVuZuVGdgaE5YvlL1faAoa1ndRR/5XhXZvPBHbsE= -cloud.google.com/go/edgecontainer v1.1.5 h1:tBY32km78ScpK2aOP84JoW/+wtpx5WluyPUSEE3270U= -cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M= -cloud.google.com/go/errorreporting v0.3.0 h1:kj1XEWMu8P0qlLhm3FwcaFsUvXChV/OraZwA70trRR0= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.6.5 h1:S2if6wkjR4JCEAfDtIiYtD+sTz/oXjh2NUG4cgT1y/Q= -cloud.google.com/go/essentialcontacts v1.6.5/go.mod h1:jjYbPzw0x+yglXC890l6ECJWdYeZ5dlYACTFL0U/VuM= -cloud.google.com/go/essentialcontacts v1.6.6 h1:13eHn5qBnsawxI7mIrv4jRIEmQ1xg0Ztqw5ZGqtUNfA= -cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q= -cloud.google.com/go/eventarc v1.13.3 h1:+pFmO4eu4dOVipSaFBLkmqrRYG94Xl/TQZFOeohkuqU= -cloud.google.com/go/eventarc v1.13.3/go.mod h1:RWH10IAZIRcj1s/vClXkBgMHwh59ts7hSWcqD3kaclg= -cloud.google.com/go/eventarc v1.13.4 h1:ORkd6/UV5FIdA8KZQDLNZYKS7BBOrj0p01DXPmT4tE4= -cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s= -cloud.google.com/go/filestore v1.8.0 h1:/+wUEGwk3x3Kxomi2cP5dsR8+SIXxo7M0THDjreFSYo= -cloud.google.com/go/filestore v1.8.0/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= -cloud.google.com/go/filestore v1.8.1 h1:X5G4y/vrUo1B8Nsz93qSWTMAcM8LXbGUldq33OdcdCw= -cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw= -cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= -cloud.google.com/go/functions v1.15.4 h1:ZjdiV3MyumRM6++1Ixu6N0VV9LAGlCX4AhW6Yjr1t+U= -cloud.google.com/go/functions v1.15.4/go.mod h1:CAsTc3VlRMVvx+XqXxKqVevguqJpnVip4DdonFsX28I= -cloud.google.com/go/functions v1.16.0 h1:IWVylmK5F6hJ3R5zaRW7jI5PrWhCvtBVU4axQLmXSo4= -cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k= -cloud.google.com/go/gkebackup v1.3.4 h1:KhnOrr9A1tXYIYeXKqCKbCI8TL2ZNGiD3dm+d7BDUBg= -cloud.google.com/go/gkebackup v1.3.4/go.mod h1:gLVlbM8h/nHIs09ns1qx3q3eaXcGSELgNu1DWXYz1HI= -cloud.google.com/go/gkebackup v1.3.5 h1:iuE8KNtTsPOc79qeWoNS8zOWoXPD9SAdOmwgxtlCmh8= -cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc= -cloud.google.com/go/gkeconnect v0.8.4 h1:1JLpZl31YhQDQeJ98tK6QiwTpgHFYRJwpntggpQQWis= -cloud.google.com/go/gkeconnect v0.8.4/go.mod h1:84hZz4UMlDCKl8ifVW8layK4WHlMAFeq8vbzjU0yJkw= -cloud.google.com/go/gkeconnect v0.8.5 h1:17d+ZSSXKqG/RwZCq3oFMIWLPI8Zw3b8+a9/BEVlwH0= -cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk= -cloud.google.com/go/gkehub v0.14.4 h1:J5tYUtb3r0cl2mM7+YHvV32eL+uZQ7lONyUZnPikCEo= -cloud.google.com/go/gkehub v0.14.4/go.mod h1:Xispfu2MqnnFt8rV/2/3o73SK1snL8s9dYJ9G2oQMfc= -cloud.google.com/go/gkehub v0.14.5 h1:RboLNFzf9wEMSo7DrKVBlf+YhK/A/jrLN454L5Tz99Q= -cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA= -cloud.google.com/go/gkemulticloud v1.0.3 h1:NmJsNX9uQ2CT78957xnjXZb26TDIMvv+d5W2vVUt0Pg= -cloud.google.com/go/gkemulticloud v1.0.3/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= -cloud.google.com/go/gkemulticloud v1.1.1 h1:rsSZAGLhyjyE/bE2ToT5fqo1qSW7S+Ubsc9jFOcbhSI= -cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q= -cloud.google.com/go/grafeas v0.3.0 h1:oyTL/KjiUeBs9eYLw/40cpSZglUC+0F7X4iu/8t7NWs= -cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= -cloud.google.com/go/grafeas v0.3.4 h1:D4x32R/cHX3MTofKwirz015uEdVk4uAxvZkZCZkOrF4= -cloud.google.com/go/grafeas v0.3.4/go.mod h1:A5m316hcG+AulafjAbPKXBO/+I5itU4LOdKO2R/uDIc= -cloud.google.com/go/gsuiteaddons v1.6.4 h1:uuw2Xd37yHftViSI8J2hUcCS8S7SH3ZWH09sUDLW30Q= -cloud.google.com/go/gsuiteaddons v1.6.4/go.mod h1:rxtstw7Fx22uLOXBpsvb9DUbC+fiXs7rF4U29KHM/pE= -cloud.google.com/go/gsuiteaddons v1.6.5 h1:CZEbaBwmbYdhFw21Fwbo+C35HMe36fTE0FBSR4KSfWg= -cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs= -cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= -cloud.google.com/go/iap v1.9.3 h1:M4vDbQ4TLXdaljXVZSwW7XtxpwXUUarY2lIs66m0aCM= -cloud.google.com/go/iap v1.9.3/go.mod h1:DTdutSZBqkkOm2HEOTBzhZxh2mwwxshfD/h3yofAiCw= -cloud.google.com/go/iap v1.9.4 h1:94zirc2r4t6KzhAMW0R6Dme005eTP6yf7g6vN4IhRrA= -cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w= -cloud.google.com/go/ids v1.4.4 h1:VuFqv2ctf/A7AyKlNxVvlHTzjrEvumWaZflUzBPz/M4= -cloud.google.com/go/ids v1.4.4/go.mod h1:z+WUc2eEl6S/1aZWzwtVNWoSZslgzPxAboS0lZX0HjI= -cloud.google.com/go/ids v1.4.5 h1:xd4U7pgl3GHV+MABnv1BF4/Vy/zBF7CYC8XngkOLzag= -cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo= -cloud.google.com/go/iot v1.7.4 h1:m1WljtkZnvLTIRYW1YTOv5A6H1yKgLHR6nU7O8yf27w= -cloud.google.com/go/iot v1.7.4/go.mod h1:3TWqDVvsddYBG++nHSZmluoCAVGr1hAcabbWZNKEZLk= -cloud.google.com/go/iot v1.7.5 h1:munTeBlbqI33iuTYgXy7S8lW2TCgi5l1hA4roSIY+EE= -cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs= -cloud.google.com/go/kms v1.15.5 h1:pj1sRfut2eRbD9pFRjNnPNg/CzJPuQAzUujMIM1vVeM= -cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= -cloud.google.com/go/kms v1.15.6 h1:ktpEMQmsOAYj3VZwH020FcQlm23BVYg8T8O1woG2GcE= -cloud.google.com/go/kms v1.15.6/go.mod h1:yF75jttnIdHfGBoE51AKsD/Yqf+/jICzB9v1s1acsms= -cloud.google.com/go/language v1.12.2 h1:zg9uq2yS9PGIOdc0Kz/l+zMtOlxKWonZjjo5w5YPG2A= -cloud.google.com/go/language v1.12.2/go.mod h1:9idWapzr/JKXBBQ4lWqVX/hcadxB194ry20m/bTrhWc= -cloud.google.com/go/language v1.12.3 h1:iaJZg6K4j/2PvZZVcjeO/btcWWIllVRBhuTFjGO4LXs= -cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8= -cloud.google.com/go/lifesciences v0.9.4 h1:rZEI/UxcxVKEzyoRS/kdJ1VoolNItRWjNN0Uk9tfexg= -cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqNj+Nia7hF0Z7JA= -cloud.google.com/go/lifesciences v0.9.5 h1:gXvN70m2p+4zgJFzaz6gMKaxTuF9WJ0USYoMLWAOm8g= -cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw= -cloud.google.com/go/logging v1.8.1 h1:26skQWPeYhvIasWKm48+Eq7oUqdcdbwsCVwz5Ys0FvU= -cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= -cloud.google.com/go/logging v1.9.0 h1:iEIOXFO9EmSiTjDmfpbRjOxECO7R8C7b8IXUGOj7xZw= -cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= -cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= -cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg= -cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= -cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= -cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= -cloud.google.com/go/managedidentities v1.6.4 h1:SF/u1IJduMqQQdJA4MDyivlIQ4SrV5qAawkr/ZEREkY= -cloud.google.com/go/managedidentities v1.6.4/go.mod h1:WgyaECfHmF00t/1Uk8Oun3CQ2PGUtjc3e9Alh79wyiM= -cloud.google.com/go/managedidentities v1.6.5 h1:+bpih1piZVLxla/XBqeSUzJBp8gv9plGHIMAI7DLpDM= -cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI= -cloud.google.com/go/maps v1.6.2 h1:WxxLo//b60nNFESefLgaBQevu8QGUmRV3+noOjCfIHs= -cloud.google.com/go/maps v1.6.2/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= -cloud.google.com/go/maps v1.6.4 h1:EVCZAiDvog9So46460BGbCasPhi613exoaQbpilMVlk= -cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI= -cloud.google.com/go/mediatranslation v0.8.4 h1:VRCQfZB4s6jN0CSy7+cO3m4ewNwgVnaePanVCQh/9Z4= -cloud.google.com/go/mediatranslation v0.8.4/go.mod h1:9WstgtNVAdN53m6TQa5GjIjLqKQPXe74hwSCxUP6nj4= -cloud.google.com/go/mediatranslation v0.8.5 h1:c76KdIXljQHSCb/Cy47S8H4s05A4zbK3pAFGzwcczZo= -cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs= -cloud.google.com/go/memcache v1.10.4 h1:cdex/ayDd294XBj2cGeMe6Y+H1JvhN8y78B9UW7pxuQ= -cloud.google.com/go/memcache v1.10.4/go.mod h1:v/d8PuC8d1gD6Yn5+I3INzLR01IDn0N4Ym56RgikSI0= -cloud.google.com/go/memcache v1.10.5 h1:yeDv5qxRedFosvpMSEswrqUsJM5OdWvssPHFliNFTc4= -cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA= -cloud.google.com/go/metastore v1.13.3 h1:94l/Yxg9oBZjin2bzI79oK05feYefieDq0o5fjLSkC8= -cloud.google.com/go/metastore v1.13.3/go.mod h1:K+wdjXdtkdk7AQg4+sXS8bRrQa9gcOr+foOMF2tqINE= -cloud.google.com/go/metastore v1.13.4 h1:dR7vqWXlK6IYR8Wbu9mdFfwlVjodIBhd1JRrpZftTEg= -cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE= -cloud.google.com/go/monitoring v1.16.3 h1:mf2SN9qSoBtIgiMA4R/y4VADPWZA7VCNJA079qLaZQ8= -cloud.google.com/go/monitoring v1.16.3/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= -cloud.google.com/go/monitoring v1.17.1 h1:xqcNr+JXmFMCPXnent/i1r0De6zrcqzgcMy5X1xa5vg= -cloud.google.com/go/monitoring v1.17.1/go.mod h1:SJzPMakCF0GHOuKEH/r4hxVKF04zl+cRPQyc3d/fqII= -cloud.google.com/go/networkconnectivity v1.14.3 h1:e9lUkCe2BexsqsUc2bjV8+gFBpQa54J+/F3qKVtW+wA= -cloud.google.com/go/networkconnectivity v1.14.3/go.mod h1:4aoeFdrJpYEXNvrnfyD5kIzs8YtHg945Og4koAjHQek= -cloud.google.com/go/networkconnectivity v1.14.4 h1:GBfXFhLyPspnaBE3nI/BRjdhW8vcbpT9QjE/4kDCDdc= -cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po= -cloud.google.com/go/networkmanagement v1.9.3 h1:HsQk4FNKJUX04k3OI6gUsoveiHMGvDRqlaFM2xGyvqU= -cloud.google.com/go/networkmanagement v1.9.3/go.mod h1:y7WMO1bRLaP5h3Obm4tey+NquUvB93Co1oh4wpL+XcU= -cloud.google.com/go/networkmanagement v1.9.4 h1:aLV5GcosBNmd6M8+a0ekB0XlLRexv4fvnJJrYnqeBcg= -cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA= -cloud.google.com/go/networksecurity v0.9.4 h1:947tNIPnj1bMGTIEBo3fc4QrrFKS5hh0bFVsHmFm4Vo= -cloud.google.com/go/networksecurity v0.9.4/go.mod h1:E9CeMZ2zDsNBkr8axKSYm8XyTqNhiCHf1JO/Vb8mD1w= -cloud.google.com/go/networksecurity v0.9.5 h1:+caSxBTj0E8OYVh/5wElFdjEMO1S/rZtE1152Cepchc= -cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8= -cloud.google.com/go/notebooks v1.11.2 h1:eTOTfNL1yM6L/PCtquJwjWg7ZZGR0URFaFgbs8kllbM= -cloud.google.com/go/notebooks v1.11.2/go.mod h1:z0tlHI/lREXC8BS2mIsUeR3agM1AkgLiS+Isov3SS70= -cloud.google.com/go/notebooks v1.11.3 h1:FH48boYmrWVQ6k0Mx/WrnNafXncT5iSYxA8CNyWTgy0= -cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo= -cloud.google.com/go/optimization v1.6.2 h1:iFsoexcp13cGT3k/Hv8PA5aK+FP7FnbhwDO9llnruas= -cloud.google.com/go/optimization v1.6.2/go.mod h1:mWNZ7B9/EyMCcwNl1frUGEuY6CPijSkz88Fz2vwKPOY= -cloud.google.com/go/optimization v1.6.3 h1:63NZaWyN+5rZEKHPX4ACpw3BjgyeuY8+rCehiCMaGPY= -cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA= -cloud.google.com/go/orchestration v1.8.4 h1:kgwZ2f6qMMYIVBtUGGoU8yjYWwMTHDanLwM/CQCFaoQ= -cloud.google.com/go/orchestration v1.8.4/go.mod h1:d0lywZSVYtIoSZXb0iFjv9SaL13PGyVOKDxqGxEf/qI= -cloud.google.com/go/orchestration v1.8.5 h1:YHgWMlrPttIVGItgGfuvO2KM7x+y9ivN/Yk92pMm1a4= -cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8= -cloud.google.com/go/orgpolicy v1.11.4 h1:RWuXQDr9GDYhjmrredQJC7aY7cbyqP9ZuLbq5GJGves= -cloud.google.com/go/orgpolicy v1.11.4/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= -cloud.google.com/go/orgpolicy v1.12.1 h1:2JbXigqBJVp8Dx5dONUttFqewu4fP0p3pgOdIZAhpYU= -cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I= -cloud.google.com/go/osconfig v1.12.4 h1:OrRCIYEAbrbXdhm13/JINn9pQchvTTIzgmOCA7uJw8I= -cloud.google.com/go/osconfig v1.12.4/go.mod h1:B1qEwJ/jzqSRslvdOCI8Kdnp0gSng0xW4LOnIebQomA= -cloud.google.com/go/osconfig v1.12.5 h1:Mo5jGAxOMKH/PmDY7fgY19yFcVbvwREb5D5zMPQjFfo= -cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8= -cloud.google.com/go/oslogin v1.12.2 h1:NP/KgsD9+0r9hmHC5wKye0vJXVwdciv219DtYKYjgqE= -cloud.google.com/go/oslogin v1.12.2/go.mod h1:CQ3V8Jvw4Qo4WRhNPF0o+HAM4DiLuE27Ul9CX9g2QdY= -cloud.google.com/go/oslogin v1.13.1 h1:1K4nOT5VEZNt7XkhaTXupBYos5HjzvJMfhvyD2wWdFs= -cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws= -cloud.google.com/go/phishingprotection v0.8.4 h1:sPLUQkHq6b4AL0czSJZ0jd6vL55GSTHz2B3Md+TCZI0= -cloud.google.com/go/phishingprotection v0.8.4/go.mod h1:6b3kNPAc2AQ6jZfFHioZKg9MQNybDg4ixFd4RPZZ2nE= -cloud.google.com/go/phishingprotection v0.8.5 h1:DH3WFLzEoJdW/6xgsmoDqOwT1xddFi7gKu0QGZQhpGU= -cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I= -cloud.google.com/go/policytroubleshooter v1.10.2 h1:sq+ScLP83d7GJy9+wpwYJVnY+q6xNTXwOdRIuYjvHT4= -cloud.google.com/go/policytroubleshooter v1.10.2/go.mod h1:m4uF3f6LseVEnMV6nknlN2vYGRb+75ylQwJdnOXfnv0= -cloud.google.com/go/policytroubleshooter v1.10.3 h1:c0WOzC6hz964QWNBkyKfna8A2jOIx1zzZa43Gx/P09o= -cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk= -cloud.google.com/go/privatecatalog v0.9.4 h1:Vo10IpWKbNvc/z/QZPVXgCiwfjpWoZ/wbgful4Uh/4E= -cloud.google.com/go/privatecatalog v0.9.4/go.mod h1:SOjm93f+5hp/U3PqMZAHTtBtluqLygrDrVO8X8tYtG0= -cloud.google.com/go/privatecatalog v0.9.5 h1:UZ0assTnATXSggoxUIh61RjTQ4P9zCMk/kEMbn0nMYA= -cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk= -cloud.google.com/go/pubsub v1.33.0 h1:6SPCPvWav64tj0sVX/+npCBKhUi/UjJehy9op/V3p2g= -cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.36.1 h1:dfEPuGCHGbWUhaMCTHUFjfroILEkx55iUmKBZTP5f+Y= -cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= -cloud.google.com/go/pubsublite v1.8.1 h1:pX+idpWMIH30/K7c0epN6V703xpIcMXWRjKJsz0tYGY= -cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.0 h1:Zrd4LvT9PaW91X/Z13H0i5RKEv9suCLuk8zp+bfOpN4= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.0/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.2 h1:U3Wfq12X9cVMuTpsWDSURnXF0Z9hSPTHj+xsnXDRLsw= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU= -cloud.google.com/go/recommendationengine v0.8.4 h1:JRiwe4hvu3auuh2hujiTc2qNgPPfVp+Q8KOpsXlEzKQ= -cloud.google.com/go/recommendationengine v0.8.4/go.mod h1:GEteCf1PATl5v5ZsQ60sTClUE0phbWmo3rQ1Js8louU= -cloud.google.com/go/recommendationengine v0.8.5 h1:ineqLswaCSBY0csYv5/wuXJMBlxATK6Xc5jJkpiTEdM= -cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ= -cloud.google.com/go/recommender v1.11.3 h1:VndmgyS/J3+izR8V8BHa7HV/uun8//ivQ3k5eVKKyyM= -cloud.google.com/go/recommender v1.11.3/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= -cloud.google.com/go/recommender v1.12.1 h1:LVLYS3r3u0MSCxQSDUtLSkporEGi9OAE6hGvayrZNPs= -cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0= -cloud.google.com/go/redis v1.14.1 h1:J9cEHxG9YLmA9o4jTSvWt/RuVEn6MTrPlYSCRHujxDQ= -cloud.google.com/go/redis v1.14.1/go.mod h1:MbmBxN8bEnQI4doZPC1BzADU4HGocHBk2de3SbgOkqs= -cloud.google.com/go/redis v1.14.2 h1:QF0maEdVv0Fj/2roU8sX3NpiDBzP9ICYTO+5F32gQNo= -cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw= -cloud.google.com/go/resourcemanager v1.9.4 h1:JwZ7Ggle54XQ/FVYSBrMLOQIKoIT/uer8mmNvNLK51k= -cloud.google.com/go/resourcemanager v1.9.4/go.mod h1:N1dhP9RFvo3lUfwtfLWVxfUWq8+KUQ+XLlHLH3BoFJ0= -cloud.google.com/go/resourcemanager v1.9.5 h1:AZWr1vWVDKGwfLsVhcN+vcwOz3xqqYxtmMa0aABCMms= -cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8= -cloud.google.com/go/resourcesettings v1.6.4 h1:yTIL2CsZswmMfFyx2Ic77oLVzfBFoWBYgpkgiSPnC4Y= -cloud.google.com/go/resourcesettings v1.6.4/go.mod h1:pYTTkWdv2lmQcjsthbZLNBP4QW140cs7wqA3DuqErVI= -cloud.google.com/go/resourcesettings v1.6.5 h1:BTr5MVykJwClASci/7Og4Qfx70aQ4n3epsNLj94ZYgw= -cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I= -cloud.google.com/go/retail v1.14.4 h1:geqdX1FNqqL2p0ADXjPpw8lq986iv5GrVcieTYafuJQ= -cloud.google.com/go/retail v1.14.4/go.mod h1:l/N7cMtY78yRnJqp5JW8emy7MB1nz8E4t2yfOmklYfg= -cloud.google.com/go/retail v1.15.1 h1:woH0EWW1IngTeyPqE95uVeMadJIB3N5VDYsRM4dJuzQ= -cloud.google.com/go/retail v1.15.1/go.mod h1:In9nSBOYhLbDGa87QvWlnE1XA14xBN2FpQRiRsUs9wU= -cloud.google.com/go/run v1.3.3 h1:qdfZteAm+vgzN1iXzILo3nJFQbzziudkJrvd9wCf3FQ= -cloud.google.com/go/run v1.3.3/go.mod h1:WSM5pGyJ7cfYyYbONVQBN4buz42zFqwG67Q3ch07iK4= -cloud.google.com/go/run v1.3.4 h1:m9WDA7DzTpczhZggwYlZcBWgCRb+kgSIisWn1sbw2rQ= -cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o= -cloud.google.com/go/scheduler v1.10.5 h1:eMEettHlFhG5pXsoHouIM5nRT+k+zU4+GUvRtnxhuVI= -cloud.google.com/go/scheduler v1.10.5/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= -cloud.google.com/go/scheduler v1.10.6 h1:5U8iXLoQ03qOB+ZXlAecU7fiE33+u3QiM9nh4cd0eTE= -cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE= -cloud.google.com/go/secretmanager v1.11.4 h1:krnX9qpG2kR2fJ+u+uNyNo+ACVhplIAS4Pu7u+4gd+k= -cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w= -cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY= -cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= -cloud.google.com/go/security v1.15.4 h1:sdnh4Islb1ljaNhpIXlIPgb3eYj70QWgPVDKOUYvzJc= -cloud.google.com/go/security v1.15.4/go.mod h1:oN7C2uIZKhxCLiAAijKUCuHLZbIt/ghYEo8MqwD/Ty4= -cloud.google.com/go/security v1.15.5 h1:wTKJQ10j8EYgvE8Y+KhovxDRVDk2iv/OsxZ6GrLP3kE= -cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= -cloud.google.com/go/securitycenter v1.24.3 h1:crdn2Z2rFIy8WffmmhdlX3CwZJusqCiShtnrGFRwpeE= -cloud.google.com/go/securitycenter v1.24.3/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= -cloud.google.com/go/securitycenter v1.24.4 h1:/5jjkZ+uGe8hZ7pvd7pO30VW/a+pT2MrrdgOqjyucKQ= -cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU= -cloud.google.com/go/servicedirectory v1.11.3 h1:5niCMfkw+jifmFtbBrtRedbXkJm3fubSR/KHbxSJZVM= -cloud.google.com/go/servicedirectory v1.11.3/go.mod h1:LV+cHkomRLr67YoQy3Xq2tUXBGOs5z5bPofdq7qtiAw= -cloud.google.com/go/servicedirectory v1.11.4 h1:da7HFI1229kyzIyuVEzHXip0cw0d+E0s8mjQby0WN+k= -cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM= -cloud.google.com/go/shell v1.7.4 h1:nurhlJcSVFZneoRZgkBEHumTYf/kFJptCK2eBUq/88M= -cloud.google.com/go/shell v1.7.4/go.mod h1:yLeXB8eKLxw0dpEmXQ/FjriYrBijNsONpwnWsdPqlKM= -cloud.google.com/go/shell v1.7.5 h1:3Fq2hzO0ZSyaqBboJrFkwwf/qMufDtqwwA6ep8EZxEI= -cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE= -cloud.google.com/go/spanner v1.53.1 h1:xNmE0SXMSxNBuk7lRZ5G/S+A49X91zkSTt7Jn5Ptlvw= -cloud.google.com/go/spanner v1.53.1/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= -cloud.google.com/go/spanner v1.56.0 h1:o/Cv7/zZ1WgRXVCd5g3Nc23ZI39p/1pWFqFwvg6Wcu8= -cloud.google.com/go/spanner v1.56.0/go.mod h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0= -cloud.google.com/go/speech v1.21.0 h1:qkxNao58oF8ghAHE1Eghen7XepawYEN5zuZXYWaUTA4= -cloud.google.com/go/speech v1.21.0/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= -cloud.google.com/go/speech v1.21.1 h1:nuFc+Kj5B8de75nN4FdPyUbI2SiBoHZG6BLurXL56Q0= -cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storagetransfer v1.10.3 h1:YM1dnj5gLjfL6aDldO2s4GeU8JoAvH1xyIwXre63KmI= -cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc= -cloud.google.com/go/storagetransfer v1.10.4 h1:dy4fL3wO0VABvzM05ycMUPFHxTPbJz9Em8ikAJVqSbI= -cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs= -cloud.google.com/go/talent v1.6.5 h1:LnRJhhYkODDBoTwf6BeYkiJHFw9k+1mAFNyArwZUZAs= -cloud.google.com/go/talent v1.6.5/go.mod h1:Mf5cma696HmE+P2BWJ/ZwYqeJXEeU0UqjHFXVLadEDI= -cloud.google.com/go/talent v1.6.6 h1:JssV0CE3FNujuSWn7SkosOzg7qrMxVnt6txOfGcMSa4= -cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ= -cloud.google.com/go/texttospeech v1.7.4 h1:ahrzTgr7uAbvebuhkBAAVU6kRwVD0HWsmDsvMhtad5Q= -cloud.google.com/go/texttospeech v1.7.4/go.mod h1:vgv0002WvR4liGuSd5BJbWy4nDn5Ozco0uJymY5+U74= -cloud.google.com/go/texttospeech v1.7.5 h1:dxY2Q5mHCbrGa3oPR2O3PCicdnvKa1JmwGQK36EFLOw= -cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M= -cloud.google.com/go/tpu v1.6.4 h1:XIEH5c0WeYGaVy9H+UueiTaf3NI6XNdB4/v6TFQJxtE= -cloud.google.com/go/tpu v1.6.4/go.mod h1:NAm9q3Rq2wIlGnOhpYICNI7+bpBebMJbh0yyp3aNw1Y= -cloud.google.com/go/tpu v1.6.5 h1:C8YyYda8WtNdBoCgFwwBzZd+S6+EScHOxM/z1h0NNp8= -cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs= -cloud.google.com/go/trace v1.10.4 h1:2qOAuAzNezwW3QN+t41BtkDJOG42HywL73q8x/f6fnM= -cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGmE6TXNWY= -cloud.google.com/go/trace v1.10.5 h1:0pr4lIKJ5XZFYD9GtxXEWr0KkVeigc3wlGpZco0X1oA= -cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M= -cloud.google.com/go/translate v1.9.3 h1:t5WXTqlrk8VVJu/i3WrYQACjzYJiff5szARHiyqqPzI= -cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= -cloud.google.com/go/translate v1.10.1 h1:upovZ0wRMdzZvXnu+RPam41B0mRJ+coRXFP2cYFJ7ew= -cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= -cloud.google.com/go/video v1.20.3 h1:Xrpbm2S9UFQ1pZEeJt9Vqm5t2T/z9y/M3rNXhFoo8Is= -cloud.google.com/go/video v1.20.3/go.mod h1:TnH/mNZKVHeNtpamsSPygSR0iHtvrR/cW1/GDjN5+GU= -cloud.google.com/go/video v1.20.4 h1:TXwotxkShP1OqgKsbd+b8N5hrIHavSyLGvYnLGCZ7xc= -cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0= -cloud.google.com/go/videointelligence v1.11.4 h1:YS4j7lY0zxYyneTFXjBJUj2r4CFe/UoIi/PJG0Zt/Rg= -cloud.google.com/go/videointelligence v1.11.4/go.mod h1:kPBMAYsTPFiQxMLmmjpcZUMklJp3nC9+ipJJtprccD8= -cloud.google.com/go/videointelligence v1.11.5 h1:mYaWH8uhUCXLJCN3gdXswKzRa2+lK0zN6/KsIubm6pE= -cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I= -cloud.google.com/go/vision/v2 v2.7.5 h1:T/ujUghvEaTb+YnFY/jiYwVAkMbIC8EieK0CJo6B4vg= -cloud.google.com/go/vision/v2 v2.7.5/go.mod h1:GcviprJLFfK9OLf0z8Gm6lQb6ZFUulvpZws+mm6yPLM= -cloud.google.com/go/vision/v2 v2.7.6 h1:xunpR5DR3vaIvoaVSXBWpYc9uGrMxEdhhfYL+NKv84c= -cloud.google.com/go/vision/v2 v2.7.6/go.mod h1:ZkvWTVNPBU3YZYzgF9Y1jwEbD1NBOCyJn0KFdQfE6Bw= -cloud.google.com/go/vmmigration v1.7.4 h1:qPNdab4aGgtaRX+51jCOtJxlJp6P26qua4o1xxUDjpc= -cloud.google.com/go/vmmigration v1.7.4/go.mod h1:yBXCmiLaB99hEl/G9ZooNx2GyzgsjKnw5fWcINRgD70= -cloud.google.com/go/vmmigration v1.7.5 h1:5v9RT2vWyuw3pK2ox0HQpkoftO7Q7/8591dTxxQc79g= -cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI= -cloud.google.com/go/vmwareengine v1.0.3 h1:WY526PqM6QNmFHSqe2sRfK6gRpzWjmL98UFkql2+JDM= -cloud.google.com/go/vmwareengine v1.0.3/go.mod h1:QSpdZ1stlbfKtyt6Iu19M6XRxjmXO+vb5a/R6Fvy2y4= -cloud.google.com/go/vmwareengine v1.1.1 h1:EGdDi9QbqThfZq3ILcDK5g+m9jTevc34AY5tACx5v7k= -cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs= -cloud.google.com/go/vpcaccess v1.7.4 h1:zbs3V+9ux45KYq8lxxn/wgXole6SlBHHKKyZhNJoS+8= -cloud.google.com/go/vpcaccess v1.7.4/go.mod h1:lA0KTvhtEOb/VOdnH/gwPuOzGgM+CWsmGu6bb4IoMKk= -cloud.google.com/go/vpcaccess v1.7.5 h1:XyL6hTLtEM/eE4F1GEge8xUN9ZCkiVWn44K/YA7z1rQ= -cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig= -cloud.google.com/go/webrisk v1.9.4 h1:iceR3k0BCRZgf2D/NiKviVMFfuNC9LmeNLtxUFRB/wI= -cloud.google.com/go/webrisk v1.9.4/go.mod h1:w7m4Ib4C+OseSr2GL66m0zMBywdrVNTDKsdEsfMl7X0= -cloud.google.com/go/webrisk v1.9.5 h1:251MvGuC8wisNN7+jqu9DDDZAi38KiMXxOpA/EWy4dE= -cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U= -cloud.google.com/go/websecurityscanner v1.6.4 h1:5Gp7h5j7jywxLUp6NTpjNPkgZb3ngl0tUSw6ICWvtJQ= -cloud.google.com/go/websecurityscanner v1.6.4/go.mod h1:mUiyMQ+dGpPPRkHgknIZeCzSHJ45+fY4F52nZFDHm2o= -cloud.google.com/go/websecurityscanner v1.6.5 h1:YqWZrZYabG88TZt7364XWRJGhxmxhony2ZUyZEYMF2k= -cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ= -cloud.google.com/go/workflows v1.12.3 h1:qocsqETmLAl34mSa01hKZjcqAvt699gaoFbooGGMvaM= -cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g= -cloud.google.com/go/workflows v1.12.4 h1:uHNmUiatTbPQ4H1pabwfzpfEYD4BBnqDHqMm2IesOh4= -cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w= -connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= -connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0/go.mod h1:243D9iHbcQXoFUtgHJwL7gl2zx1aDuDMjvBZVGr2uW0= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw= -github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= -github.com/KimMachineGun/automemlimit v0.5.0 h1:BeOe+BbJc8L5chL3OwzVYjVzyvPALdd5wxVVOWuUZmQ= -github.com/KimMachineGun/automemlimit v0.5.0/go.mod h1:di3GCKiu9Y+1fs92erCbUvKzPkNyViN3mA0vti/ykEQ= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.2.1 h1:n6EPaDyLSvCEa3frruQvAiHuNp2dhBlMSmkEr+HuzGc= -github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.6 h1:U68crOE3y3MPttCMQGywZOLrTeF5HHJ3/vDBCJn9/bA= -github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409 h1:DTQ/38ao/CfXsrK0cSAL+h4R/u0VVvfWLZEOlLwEROI= -github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjjBW6xcqyQA/j5e0D6GytH95g0gQ= -github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= -github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= -github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= -github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= -github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= -github.com/alicebob/miniredis/v2 v2.23.0 h1:+lwAJYjvvdIVg6doFHuotFjueJ/7KY10xo/vm3X3Scw= -github.com/alicebob/miniredis/v2 v2.23.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= -github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v12 v12.0.0 h1:xtZE63VWl7qLdB0JObIXvvhGjoVNrQ9ciIHG2OK5cmc= -github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= -github.com/apache/arrow/go/v12 v12.0.1 h1:JsR2+hzYYjgSUkBSaahpqCetqZMr76djX80fF/DiJbg= -github.com/apache/arrow/go/v12 v12.0.1/go.mod h1:weuTY7JvTG/HDPtMQxEUp7pU73vkLWMLpY67QwZ/WWw= -github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aws/aws-sdk-go v1.50.8/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1 h1:w/fPGB0t5rWwA43mux4e9ozFSH5zF1moQemlA131PWc= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= -github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bsm/redislock v0.9.1 h1:uTTZU82xg2PjI8X5T9PGcX/5k1FX3Id7bqkwy1As6c0= -github.com/bsm/redislock v0.9.1/go.mod h1:ToFoB1xQbOJYG7e2ZBiPXotlhImqWgEa4+u/lLQ1nSc= -github.com/casbin/casbin/v2 v2.37.0 h1:/poEwPSovi4bTOcP752/CsTQiRz2xycyVKFG7GUhbDw= -github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89 h1:aPflPkRFkVwbW6dmcVqfgwp1i+UWGFH6VgR1Jim5Ygc= -github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= -github.com/chromedp/chromedp v0.9.2 h1:dKtNz4kApb06KuSXoTQIyUC2TrA0fhGDwNZf3bcgfKw= -github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= -github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= -github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= -github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= -github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= -github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= -github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= -github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= -github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw= -github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= -github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cristalhq/hedgedhttp v0.9.1 h1:g68L9cf8uUyQKQJwciD0A1Vgbsz+QgCjuB1I8FAsCDs= -github.com/cristalhq/hedgedhttp v0.9.1/go.mod h1:XkqWU6qVMutbhW68NnzjWrGtH8NUx1UfYqGYtHVKIsI= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90 h1:WXb3TSNmHp2vHoCroCIB1foO/yQ36swABL8aOVeDpgg= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 h1:a9ENSRDFBUPkJ5lCgVZh26+ZbGyoVJG7yb5SSzF5H54= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= -github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= -github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= -github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= -github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-openapi/analysis v0.22.0/go.mod h1:acDnkkCI2QxIo8sSIPgmp1wUlRohV7vfGtAIVae73b0= -github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho= -github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= -github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= -github.com/go-openapi/runtime v0.27.1 h1:ae53yaOoh+fx/X5Eaq8cRmavHgDma65XPZuvBqvJYto= -github.com/go-openapi/runtime v0.27.1/go.mod h1:fijeJEiEclyS8BRurYE1DE5TLb9/KZl6eAdbzjsrlLU= -github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= -github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis= -github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= -github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= -github.com/go-openapi/swag v0.22.6/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd h1:hSkbZ9XSyjyBirMeqSqUrK+9HboWrweVlzRNqoBi2d4= -github.com/gobuffalo/depgen v0.1.0 h1:31atYa/UW9V5q8vMJ+W6wd64OaaTHUrCUXER358zLM4= -github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= -github.com/gobuffalo/flect v0.1.3 h1:3GQ53z7E3o00C/yy7Ko8VXqQXoJGLkrTQCLTF1EjoXU= -github.com/gobuffalo/genny v0.1.1 h1:iQ0D6SpNXIxu52WESsD+KoQ7af2e3nCfnSBoSF/hKe0= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211 h1:mSVZ4vj4khv+oThUfS+SQU3UuFIZ5Zo6UNcvK8E8Mz8= -github.com/gobuffalo/gogen v0.1.1 h1:dLg+zb+uOyd/mKeQUYIbwbNmfRsr9hd/WtYWepmayhI= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2 h1:8thhT+kUJMTMy3HlX4+y9Da+BNJck+p109tqqKp7WDs= -github.com/gobuffalo/mapi v1.0.2 h1:fq9WcL1BYrm36SzK6+aAnZ8hcp+SrmnDyAxhNx8dvJk= -github.com/gobuffalo/packd v0.1.0 h1:4sGKOD8yaYJ+dek1FDkwcxCHA40M4kfKgFHx8N2kwbU= -github.com/gobuffalo/packr/v2 v2.2.0 h1:Ir9W9XIm9j7bhhkKE9cokvtTl1vBm62A/fene/ZCj6A= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754 h1:tpom+2CJmpzAWj5/VEHync2rJGi+epHNIeRSWjzGA+4= -github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= -github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-yaml v1.9.5 h1:Eh/+3uk9kLxG4koCX6lRMAPS1OaMSAi+FJcya0INdB0= -github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= -github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= -github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= -github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= -github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9 h1:OF1IPgv+F4NmqmJ98KTjdN97Vs1JxDPB3vbmYzV2dpk= -github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ= -github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= -github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 h1:/of8Z8taCPftShATouOrBVy6GaTTjgQd/VfNiZp/VXQ= -github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= -github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= -github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/hudl/fargo v1.4.0 h1:ZDDILMbB37UlAVLlWcJ2Iz1XuahZZTDZfdCKeclfq2s= -github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= -github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= -github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab h1:HqW4xhhynfjrtEiiSGcQUd6vrK23iMam1FO8rI7mwig= -github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= -github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= -github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= -github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5 h1:PJr+ZMXIecYc1Ey2zucXdR73SMBtgjPgwa31099IMv0= -github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= -github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= -github.com/karrick/godirwalk v1.10.3 h1:lOpSw2vJP0y5eLBW906QwKsUK/fe/QDyoqM5rnnuPDY= -github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= -github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= -github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo= -github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= -github.com/lyft/protoc-gen-star/v2 v2.0.3 h1:/3+/2sWyXeMLzKd1bX+ixWKgEMsULrIivpDsuaF441o= -github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2 h1:JgVTCPf0uBVcUSWpyXmGpgOc62nK5HWUBKAGc3Qqa5k= -github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= -github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= -github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvBn0G0a7QBRdBUp6Y048BtLAHRTKPo= -github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= -github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= -github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= -github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5 h1:8Q0qkMVC/MmWkpIdlvZgcv2o2jrlF6zqVOh7W5YHdMA= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nats-io/jwt/v2 v2.0.3 h1:i/O6cmIsjpcQyWDYNcq2JyZ3/VTF8SJ4JWluI5OhpvI= -github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= -github.com/nats-io/nats-server/v2 v2.5.0 h1:wsnVaaXH9VRSg+A2MVg5Q727/CqxnmPLGFQ3YZYKTQg= -github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= -github.com/nats-io/nats.go v1.12.1 h1:+0ndxwUPz3CmQ2vjbXdkC1fo3FdiOQDim4gl3Mge8Qo= -github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= -github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= -github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= -github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM= -github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oauth2-proxy/mockoidc v0.0.0-20220221072942-e3afe97dec43 h1:V9YiO92tYBmVgVcKhdxK6I4avJCefBM+0Db4WM2dank= -github.com/oauth2-proxy/mockoidc v0.0.0-20220221072942-e3afe97dec43/go.mod h1:rW25Kyd08Wdn3UVn0YBsDTSvReu0jqpmJKzxITPSjks= -github.com/oauth2-proxy/tools/reference-gen v0.0.0-20210118095127-56ffd7384404 h1:ZpzR4Ou1nhldBG/vEzauoqyaUlofaUcLkv1C/gBK8ls= -github.com/oauth2-proxy/tools/reference-gen v0.0.0-20210118095127-56ffd7384404/go.mod h1:YpORG8zs14vNlpXvuHYnnDvWazIRaDk02MaY8lafqdI= -github.com/ohler55/ojg v1.19.3 h1:rFmEc33aZOvlwb7tibAmwVGEiPfMZkgvurK0YDDr1HI= -github.com/ohler55/ojg v1.19.3/go.mod h1:uHcD1ErbErC27Zhb5Df2jUjbseLLcmOCo6oxSr3jZxo= -github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= -github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin/zipkin-go v0.2.5 h1:UwtQQx2pyPIgWYHRg+epgdx1/HnBQTgN3/oIYEJTQzU= -github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= -github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw= -github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= -github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= -github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/performancecopilot/speed/v4 v4.0.0 h1:VxEDCmdkfbQYDlcr/GC9YoN9PQ6p8ulk9xVsepYy9ZY= -github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= -github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= -github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= -github.com/prometheus/common/assets v0.2.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI= -github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/redis/go-redis/v9 v9.0.2 h1:BA426Zqe/7r56kCcvxYLWe1mkaz71LKF77GwgFzSxfE= -github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= -github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= -github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= -github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= -github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= -github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk= -github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.6.0 h1:REOEXCs/NFY/1jOCEouMuT4zEniE5YoXbvpC5X/TLF8= -github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= -github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM= -github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= -github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= -github.com/shoenig/test v0.6.6 h1:Oe8TPH9wAbv++YPNDKJWUnI8Q4PPWCx3UbOfH+FxiMU= -github.com/shoenig/test v0.6.6/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= -github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= -github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= -github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= -github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= -github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= -github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= -github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= -github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e h1:mOtuXaRAbVZsxAHVdPR3IjfmN8T1h2iczJLynhLybf8= -github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194 h1:Oho9ykiKXwOHkeq5jSAvlkBAcRwNqnrUca/5WacvH2E= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194 h1:YB6qJyCPuwtHFr54/GAfYj1VfwhiDHnwtOKu40OaG2M= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= -github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= -github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= -github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 h1:k/gmLsJDWwWqbLCur2yWnJzwQEKRcAHXo6seXGuSwWw= -github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= -github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= -go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= -go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= -go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.4 h1:Dcx3/MYyfKcPNLpR4VVQUP5KgYrBeJtktBwEKkw08Ao= -go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= -go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= -go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= -go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b h1:Qh4dB5D/WpoUUp3lSod7qgoyEHbDGPUWjIbnqdqqe1k= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= -google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= -google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= -google.golang.org/api v0.160.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw= -google.golang.org/api v0.164.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20231120223509-83a465c0220f h1:hL+1ptbhFoeL1HcROQ8OGXaqH0jYRRibgWQWco0/Ugc= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20231120223509-83a465c0220f/go.mod h1:iIgEblxoG4klcXsG0d9cpoxJ4xndv6+1FkDROCHhPRI= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78 h1:YqFWYZXim8bG9v68xU8WjTZmYKb5M5dMeSOWIp6jogI= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:vh/N7795ftP0AkN1w8XKqN4w1OdUKXW5Eummda+ofv8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= -gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/telebot.v3 v3.1.3 h1:T+CTyOWpZMqp3ALHSweNgp1awQ9nMXdRAMpe/r6x9/s= -gopkg.in/telebot.v3 v3.1.3/go.mod h1:GJKwwWqp9nSkIVN51eRKU78aB5f5OnQuWdwiIZfPbko= -gopkg.in/telebot.v3 v3.2.1 h1:3I4LohaAyJBiivGmkfB+CiVu7QFOWkuZ4+KHgO/G3rs= -gopkg.in/telebot.v3 v3.2.1/go.mod h1:GJKwwWqp9nSkIVN51eRKU78aB5f5OnQuWdwiIZfPbko= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= -k8s.io/gengo v0.0.0-20201113003025-83324d819ded h1:JApXBKYyB7l9xx+DK7/+mFjC7A9Bt5A93FPvFD0HIFE= -k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= -rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= -rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= -rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/images/pyroscope-v2-compaction.gif b/images/pyroscope-v2-compaction.gif new file mode 100644 index 0000000000..20a840f041 Binary files /dev/null and b/images/pyroscope-v2-compaction.gif differ diff --git a/images/pyroscope-v2-read-path.gif b/images/pyroscope-v2-read-path.gif new file mode 100644 index 0000000000..41a0a610a5 Binary files /dev/null and b/images/pyroscope-v2-read-path.gif differ diff --git a/images/pyroscope-v2-write-path.gif b/images/pyroscope-v2-write-path.gif new file mode 100644 index 0000000000..335dfbf04d Binary files /dev/null and b/images/pyroscope-v2-write-path.gif differ diff --git a/jest-css-modules-transform-config.js b/jest-css-modules-transform-config.js deleted file mode 100644 index b1202d1b29..0000000000 --- a/jest-css-modules-transform-config.js +++ /dev/null @@ -1,17 +0,0 @@ -const path = require('path'); - -module.exports = { - sassConfig: { - // So that we can import scss files using ~mymodule - // https://github.com/Connormiha/jest-css-modules-transform/issues/32#issuecomment-787437223 - importer: [ - (url, prev) => { - if (!url.startsWith('~')) return null; - - return { - file: path.join(__dirname, `node_modules/${url.slice(1)}`), - }; - }, - ], - }, -}; diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index d6b607f5de..0000000000 --- a/jest.config.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); -const { pathsToModuleNameMapper } = require('ts-jest'); -const { compilerOptions } = require('./tsconfig'); - -module.exports = { - // TypeScript files (.ts, .tsx) will be transformed by ts-jest to CommonJS syntax, and JavaScript files (.js, jsx) will be transformed by babel-jest. - testEnvironment: 'jsdom', - testMatch: ['**/?(*.)+(spec|test).+(ts|tsx|js)'], - transform: { - '\\.module\\.(css|scss)$': 'jest-css-modules-transform', - '\\.(css|scss)$': 'jest-css-modules-transform', - '\\.svg$': path.join(__dirname, 'svg-transform.js'), - '^.+\\.(t|j)sx?$': ['@swc/jest'], - }, - - transformIgnorePatterns: [ - // force us to transpile these dependencies - // https://stackoverflow.com/a/69150188 - 'node_modules/(?!(true-myth|d3|d3-array|internmap|d3-scale|react-notifications-component|@react-hook))', - ], - - testPathIgnorePatterns: ['/node_modules/', '/og/'], - - // Reuse the same modules from typescript - moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { - prefix: '', - '@pyroscope/(.*)$': path.join(__dirname, 'public/app/$1'), - }), - - globalSetup: '/globalSetup.js', - globalTeardown: '/globalTeardown.js', - setupFilesAfterEnv: [path.join(__dirname, 'setupAfterEnv.ts')], -}; diff --git a/lidia/.gitignore b/lidia/.gitignore new file mode 100644 index 0000000000..d36977dc47 --- /dev/null +++ b/lidia/.gitignore @@ -0,0 +1 @@ +.tmp diff --git a/ebpf/LICENSE b/lidia/LICENSE similarity index 100% rename from ebpf/LICENSE rename to lidia/LICENSE diff --git a/lidia/README.md b/lidia/README.md new file mode 100644 index 0000000000..3b2c9b64cf --- /dev/null +++ b/lidia/README.md @@ -0,0 +1,209 @@ +# Lidia (Language-Independent-Debug-Information-Archive) + +Lidia is a binary format for efficient lookup of symbols of a binary by virtual address. + +## Features + +- Fast lookup of function symbols by address +- Compact binary format +- CRC32C checksums for data integrity +- Support for source file and line information + +## Features + +The Lidia format achieves its performance through a carefully designed architecture: + +1. **Fast Lookups**: Uses binary search on the sorted VA Table to quickly locate functions containing a specific address +2. **Direct Access**: Each VA Table entry has a corresponding Range Table entry at the same index, providing O(1) access to function metadata +3. **Memory Efficiency**: Stores each string only once in the Strings Table and references them by offset throughout the file +4. **Size Optimization**: Adapts field sizes (4 or 8 bytes) based on actual data values to minimize file size +5. **Minimal Parsing**: Stores data in a binary format that can be memory-mapped with minimal transformation + +This design makes Lidia particularly well-suited for applications that need to perform many address lookups, such as symbolizing profiles with thousands of samples. + +## Installation + +```bash +go get github.com/grafana/pyroscope/lidia +``` + +## File Format + +Lidia uses a binary format with the following sections: +- Header: Magic number, version, and section tables +- VA Table: Sorted virtual addresses +- Range Table: Function symbol information +- Strings Table: String data pool +- Line Tables: Source line information (when included) + +## Format Specification + +The Lidia file format consists of the following sections in order: + +### 1. Header (128 bytes) + +The header contains metadata about the file and its sections: + +| Offset | Size | Description | +|--------|------|-------------------------------------------------| +| 0x00 | 4 | Magic number: [0x2e, 0x64, 0x69, 0x61] (".dia") | +| 0x04 | 4 | Version number (currently 1) | +| 0x08 | 32 | VA Table Header | +| 0x28 | 32 | Range Table Header | +| 0x48 | 24 | Strings Table Header | +| 0x60 | 32 | Line Tables Header | + +#### VA Table Header (32 bytes at offset 0x08) +| Offset | Size | Description | +|--------|------|-------------| +| 0x00 | 8 | Entry size (4 or 8 bytes) | +| 0x08 | 8 | Number of entries | +| 0x10 | 8 | Offset to table data | +| 0x18 | 4 | CRC32C checksum | +| 0x1C | 4 | (reserved) | + +#### Range Table Header (32 bytes at offset 0x28) +| Offset | Size | Description | +|--------|------|-------------| +| 0x00 | 8 | Field size (4 or 8 bytes) | +| 0x08 | 8 | Number of entries | +| 0x10 | 8 | Offset to table data | +| 0x18 | 4 | CRC32C checksum | +| 0x1C | 4 | (reserved) | + +#### Strings Table Header (24 bytes at offset 0x48) +| Offset | Size | Description | +|--------|------|-------------| +| 0x00 | 8 | Size of strings data | +| 0x08 | 8 | Offset to table data | +| 0x10 | 4 | CRC32C checksum | +| 0x14 | 4 | (reserved) | + +#### Line Tables Header (32 bytes at offset 0x60) +| Offset | Size | Description | +|--------|------|-------------| +| 0x00 | 8 | Field size (2 or 4 bytes) | +| 0x08 | 8 | Number of entries | +| 0x10 | 8 | Offset to table data | +| 0x18 | 4 | CRC32C checksum | +| 0x1C | 4 | (reserved) | + +### 2. VA Table (Variable size) + +Follows immediately after the header at offset 0x80. Contains virtual addresses (VAs) of functions, sorted in ascending order. +- Each entry is either 4 or 8 bytes, as specified in the VA Table Header. +- The number of entries is specified in the VA Table Header. + +### 3. Range Table (Variable size) + +Follows after the VA Table. Contains information about each function range. +Each entry contains 8 fields: + +| Field | Description | +|-------------|-------------| +| length | Length of the function in bytes | +| depth | Inlining depth (0 for non-inlined functions) | +| funcOffset | Offset into the Strings Table for the function name | +| fileOffset | Offset into the Strings Table for the source file path | +| lineTable | {idx, count} Reference to Line Table entries | +| callFile | Offset into the Strings Table for the call site file path | +| callLine | Line number at the call site | + +Each field is either 4 or 8 bytes, as specified in the Range Table Header. + +### 4. Strings Table (Variable size) + +Follows after the Range Table. Contains null-terminated strings referenced by the Range Table. +- Strings are stored in a consecutive block. +- References to strings are offsets within this table. + +### 5. Line Tables (Variable size) + +Follows after the Strings Table. Contains line number information for functions. +Each entry contains two fields: + +| Field | Description | +|------------|-------------| +| Offset | Offset within the function | +| LineNumber | Source line number at this offset | + +Each field is either 2 or 4 bytes, as specified in the Line Tables Header. + +### CRC32C Checksums + +If enabled with `WithCRC()`, each section has a CRC32C checksum for data integrity validation. +The checksums are calculated using the Castagnoli polynomial. + +## Usage + +### Opening and Querying + +```go +import "github.com/grafana/pyroscope/lidia" + +// Open a lidia file +file, err := os.Open("symbolization.lidia") +if err != nil { + log.Fatal(err) +} +defer file.Close() + +table, err := lidia.OpenReader(file, lidia.WithCRC()) +if err != nil { + log.Fatal(err) +} +defer table.Close() + +// Look up a function symbol by address +frames, err := table.Lookup(0x408ed0) +if err != nil { + log.Fatal(err) +} + +for _, frame := range frames { + fmt.Printf("Function: %s\n", frame.FunctionName) + if frame.SourceFile != "" { + fmt.Printf(" File: %s:%d\n", frame.SourceFile, frame.SourceLine) + } +} +``` + +### Creating Lidia Files + +```go +// Create from an executable file +err := lidia.CreateLidia("path/to/executable", "output.lidia", + lidia.WithCRC(), lidia.WithLines(), lidia.WithFiles()) +if err != nil { + log.Fatal(err) +} + +// Or from an already opened ELF file +elfFile, err := elf.Open("path/to/executable") +if err != nil { + log.Fatal(err) +} +defer elfFile.Close() + +output, err := os.Create("output.lidia") +if err != nil { + log.Fatal(err) +} +defer output.Close() + +err = lidia.CreateLidiaFromELF(elfFile, output, + lidia.WithCRC(), lidia.WithLines(), lidia.WithFiles()) +if err != nil { + log.Fatal(err) +} +``` + +## Versioning + +This module is currently in development (v0.x). The API may change until v1.0.0 is released. + +We follow semantic versioning. + +## License + +See the [LICENSE](./LICENSE) file for details. diff --git a/lidia/builder.go b/lidia/builder.go new file mode 100644 index 0000000000..b89f76f2a2 --- /dev/null +++ b/lidia/builder.go @@ -0,0 +1,137 @@ +package lidia + +import ( + "encoding/binary" + "sort" +) + +type lineTableRef struct { + idx uint64 + count uint64 +} + +type lineBuilder struct { + entries []LineTableEntry +} + +func newLineTableBuilder() *lineBuilder { + return &lineBuilder{} +} + +func (ltb *lineBuilder) add(lines LineTable) lineTableRef { + o := len(ltb.entries) + sz := len(lines) + ltb.entries = append(ltb.entries, lines...) + return lineTableRef{idx: uint64(o), count: uint64(sz)} +} + +type stringBuilder struct { + buf []byte + unique map[string]stringOffset + offset stringOffset + overflow stringOffset + emptystr stringOffset +} + +func newStringBuilder() *stringBuilder { + sb := &stringBuilder{ + buf: make([]byte, 0), + unique: make(map[string]stringOffset), + } + sb.emptystr = sb.add("") + sb.overflow = sb.add("[overflow]") + return sb +} + +func (sb *stringBuilder) add(s string) stringOffset { + if prev, exists := sb.unique[s]; exists { + return prev + } + + strLen := len(s) + if strLen >= int(^uint32(0)) { + return sb.overflow + } + sb.buf = binary.LittleEndian.AppendUint32(sb.buf, uint32(strLen)) + sb.buf = append(sb.buf, s...) + + offset := sb.offset + sb.unique[s] = offset + sb.offset = stringOffset(uint64(sb.offset) + uint64(4+strLen)) + + return offset +} + +// rangesBuilder +type rangesBuilder struct { + entries []rangeEntry + va []uint64 +} + +func newRangesBuilder() *rangesBuilder { + return &rangesBuilder{} +} + +func (rb *rangesBuilder) add(va uint64, e rangeEntry) { + rb.entries = append(rb.entries, e) + rb.va = append(rb.va, va) +} + +func (rb *rangesBuilder) sort() { + sort.Stable(&sortByVADepth{rb}) +} + +// sortByVADepth sorts the ranges by VA and then by depth. +type sortByVADepth struct { + b *rangesBuilder +} + +func (s *sortByVADepth) Len() int { + return len(s.b.entries) +} + +func (s *sortByVADepth) Less(i, j int) bool { + if s.b.va[i] == s.b.va[j] { + return s.b.entries[i].depth < s.b.entries[j].depth + } + return s.b.va[i] < s.b.va[j] +} + +func (s *sortByVADepth) Swap(i, j int) { + s.b.entries[i], s.b.entries[j] = s.b.entries[j], s.b.entries[i] + s.b.va[i], s.b.va[j] = s.b.va[j], s.b.va[i] +} + +// rangeCollector +type rangeCollector struct { + sb *stringBuilder + rb *rangesBuilder + lb *lineBuilder + + opt options +} + +func (rc *rangeCollector) VisitRange(r *Range) { + lt := lineTableRef{} + funcOffset := rc.sb.add(r.Function) + fileOffset := rc.sb.emptystr + callFileOffset := rc.sb.emptystr + if rc.opt.files { + fileOffset = rc.sb.add(r.File) + callFileOffset = rc.sb.add(r.CallFile) + } + + if rc.opt.lines { + lt = rc.lb.add(r.LineTable) + } + e := rangeEntry{ + length: uint64(r.Length), + depth: uint64(r.Depth), + funcOffset: funcOffset, + fileOffset: fileOffset, + lineTable: lt, + callFile: callFileOffset, + callLine: uint64(r.CallLine), + } + rc.rb.add(r.VA, e) +} diff --git a/lidia/constants.go b/lidia/constants.go new file mode 100644 index 0000000000..8913e4a7c0 --- /dev/null +++ b/lidia/constants.go @@ -0,0 +1,33 @@ +package lidia + +import "hash/crc32" + +// File format constants +const ( + // Magic number for lidia files ("ldia" in little-endian ASCII) + // magic uint32 = 0x6169646c + + // Current version of the lidia format + version uint32 = 1 + + // Size of the file header in bytes + headerSize = 0x80 + + // Number of fields in a line table entry + lineTableFieldsCount = 2 + + // Number of fields in a range entry + fieldsCount = 8 + + // Size of a range entry with 4-byte fields + fieldsEntrySize4 = fieldsCount * 4 + + // Size of a range entry with 8-byte fields + fieldsEntrySize8 = fieldsCount * 8 +) + +// CRC32 table using the Castagnoli polynomial +var ( + castagnoli = crc32.MakeTable(crc32.Castagnoli) + magic = []byte{0x2e, 0x64, 0x69, 0x61} // ".dia" +) diff --git a/lidia/doc.go b/lidia/doc.go new file mode 100644 index 0000000000..c1901050c6 --- /dev/null +++ b/lidia/doc.go @@ -0,0 +1,76 @@ +// Package lidia implements a custom binary format for efficient symbolization of Go profiles. +// +// Lidia provides functionality to create, read, and query symbol tables stored in the +// lidia binary format. This format is optimized for fast symbol lookups by address, +// which is useful for symbolizing profiles collected from Go programs. +// +// # Creating Lidia Files +// +// There are two main ways to create a lidia file: +// +// // From an executable file +// err := lidia.CreateLidia("path/to/executable", "output.lidia", +// lidia.WithCRC(), lidia.WithLines(), lidia.WithFiles()) +// if err != nil { +// // handle error +// } +// +// // From an already opened ELF file +// elfFile, err := elf.Open("path/to/executable") +// if err != nil { +// // handle error +// } +// defer elfFile.Close() +// +// output, err := os.Create("output.lidia") +// if err != nil { +// // handle error +// } +// defer output.Close() +// +// err = lidia.CreateLidiaFromELF(elfFile, output, +// lidia.WithCRC(), lidia.WithLines(), lidia.WithFiles()) +// if err != nil { +// // handle error +// } +// +// # Reading and Querying Lidia Files +// +// // Read a lidia file into memory +// data, err := os.ReadFile("path/to/file.lidia") +// if err != nil { +// // handle error +// } +// +// // Create a reader from the data +// var reader lidia.ReaderAtCloser = &MyReaderAtCloser{data, 0} +// +// // Open the lidia table +// table, err := lidia.OpenReader(reader, lidia.WithCRC()) +// if err != nil { +// // handle error +// } +// defer table.Close() +// +// // Look up a function symbol by address +// frames, err := table.Lookup(0x408ed0) +// if err != nil { +// // handle error +// } +// +// // Use the symbolization results +// for _, frame := range frames { +// fmt.Println(frame.FunctionName) +// } +// +// # Available Options +// +// The following options can be used when creating or opening lidia files: +// +// - WithCRC(): Enables CRC32C checksums for data integrity +// - WithFiles(): Includes source file information +// - WithLines(): Includes line number information +// +// When creating a lidia file with WithCRC(), the same option must be used when +// opening the file, or an error will be returned. +package lidia diff --git a/lidia/format.go b/lidia/format.go new file mode 100644 index 0000000000..3366071679 --- /dev/null +++ b/lidia/format.go @@ -0,0 +1,348 @@ +package lidia + +import ( + "bufio" + "encoding/binary" + "hash/crc32" + "io" +) + +type stringOffset uint64 + +type rangeEntry struct { + length uint64 + depth uint64 + funcOffset stringOffset + fileOffset stringOffset + lineTable lineTableRef + callFile stringOffset + callLine uint64 +} + +// sz 0x20 +type vaTableHeader struct { + entrySize uint64 + count uint64 + offset uint64 + crc uint32 + _ uint32 +} + +// sz 0x20 +type rangeTableHeader struct { + fieldSize uint64 + count uint64 + offset uint64 + crc uint32 + _ uint32 +} + +// sz 0x18 +type stringsTableHeader struct { + size uint64 + offset uint64 + crc uint32 + _ uint32 +} + +// sz 0x20 +type lineTablesHeader struct { + fieldSize uint64 + count uint64 + offset uint64 + crc uint32 + _ uint32 +} + +type header struct { + // 0x0 + magic [4]byte + version uint32 + // 0x8 + vaTableHeader vaTableHeader + // 0x28 + rangeTableHeader rangeTableHeader + // 0x48 + stringsTableHeader stringsTableHeader + // 0x60 + lineTablesHeader lineTablesHeader + // 0x80 +} + +func readHeader(file io.Reader) (header, error) { + headerBuf := make([]byte, headerSize) + if _, readErr := file.Read(headerBuf); readErr != nil { + return header{}, readErr + } + hdr := header{} + copy(hdr.magic[:], headerBuf[0:4]) + hdr.version = binary.LittleEndian.Uint32(headerBuf[4:]) + + hdr.vaTableHeader.entrySize = binary.LittleEndian.Uint64(headerBuf[8:]) + hdr.vaTableHeader.count = binary.LittleEndian.Uint64(headerBuf[0x10:]) + hdr.vaTableHeader.offset = binary.LittleEndian.Uint64(headerBuf[0x18:]) + hdr.vaTableHeader.crc = binary.LittleEndian.Uint32(headerBuf[0x20:]) + + hdr.rangeTableHeader.fieldSize = binary.LittleEndian.Uint64(headerBuf[0x28:]) + hdr.rangeTableHeader.count = binary.LittleEndian.Uint64(headerBuf[0x30:]) + hdr.rangeTableHeader.offset = binary.LittleEndian.Uint64(headerBuf[0x38:]) + hdr.rangeTableHeader.crc = binary.LittleEndian.Uint32(headerBuf[0x40:]) + + hdr.stringsTableHeader.size = binary.LittleEndian.Uint64(headerBuf[0x48:]) + hdr.stringsTableHeader.offset = binary.LittleEndian.Uint64(headerBuf[0x50:]) + hdr.stringsTableHeader.crc = binary.LittleEndian.Uint32(headerBuf[0x58:]) + + hdr.lineTablesHeader.fieldSize = binary.LittleEndian.Uint64(headerBuf[0x60:]) + hdr.lineTablesHeader.count = binary.LittleEndian.Uint64(headerBuf[0x68:]) + hdr.lineTablesHeader.offset = binary.LittleEndian.Uint64(headerBuf[0x70:]) + hdr.lineTablesHeader.crc = binary.LittleEndian.Uint32(headerBuf[0x78:]) + + return hdr, nil +} + +func readFields4(entryBuf []byte) rangeEntry { + return rangeEntry{ + length: uint64(binary.LittleEndian.Uint32(entryBuf[0:])), + depth: uint64(binary.LittleEndian.Uint32(entryBuf[4:])), + funcOffset: stringOffset(binary.LittleEndian.Uint32(entryBuf[8:])), + fileOffset: stringOffset(binary.LittleEndian.Uint32(entryBuf[12:])), + lineTable: lineTableRef{ + idx: uint64(binary.LittleEndian.Uint32(entryBuf[16:])), + count: uint64(binary.LittleEndian.Uint32(entryBuf[20:])), + }, + callFile: stringOffset(binary.LittleEndian.Uint32(entryBuf[24:])), + callLine: uint64(binary.LittleEndian.Uint32(entryBuf[28:])), + } +} + +func readFields8(entryBuf []byte) rangeEntry { + return rangeEntry{ + length: binary.LittleEndian.Uint64(entryBuf[0:]), + depth: binary.LittleEndian.Uint64(entryBuf[8:]), + funcOffset: stringOffset(binary.LittleEndian.Uint64(entryBuf[16:])), + fileOffset: stringOffset(binary.LittleEndian.Uint64(entryBuf[24:])), + lineTable: lineTableRef{ + idx: binary.LittleEndian.Uint64(entryBuf[32:]), + count: binary.LittleEndian.Uint64(entryBuf[40:]), + }, + callFile: stringOffset(binary.LittleEndian.Uint64(entryBuf[48:])), + callLine: binary.LittleEndian.Uint64(entryBuf[56:]), + } +} + +func (rc *rangeCollector) write(f io.WriteSeeker) error { + buf := bufio.NewWriter(f) + hdr := &header{ + version: version, + } + + copy(hdr.magic[:], magic) + + if err := writeHeader(buf, hdr); err != nil { + return err + } + + hdr.vaTableHeader.offset = headerSize + hdr.rangeTableHeader.offset = headerSize + hdr.stringsTableHeader.offset = headerSize + hdr.stringsTableHeader.size = uint64(len(rc.sb.buf)) + + crc := crc32.New(castagnoli) + _, _ = crc.Write(rc.sb.buf) + hdr.stringsTableHeader.crc = crc.Sum32() + + if err := writeRangeEntries(rc.rb, hdr, buf); err != nil { + return err + } + if err := buf.Flush(); err != nil { + return err + } + + if _, err := f.Write(rc.sb.buf); err != nil { + return err + } + + if err := writeLineTableEntries(rc.lb, hdr, buf); err != nil { + return err + } + + if _, err := f.Seek(0, io.SeekStart); err != nil { + return err + } + + if err := writeHeader(f, hdr); err != nil { + return err + } + return nil +} + +func writeHeader(output io.Writer, hdr *header) error { + headerBuf := make([]byte, headerSize) + copy(headerBuf[0:4], hdr.magic[:]) + binary.LittleEndian.PutUint32(headerBuf[4:], hdr.version) + + binary.LittleEndian.PutUint64(headerBuf[0x8:], hdr.vaTableHeader.entrySize) + binary.LittleEndian.PutUint64(headerBuf[0x10:], hdr.vaTableHeader.count) + binary.LittleEndian.PutUint64(headerBuf[0x18:], hdr.vaTableHeader.offset) + binary.LittleEndian.PutUint32(headerBuf[0x20:], hdr.vaTableHeader.crc) + + binary.LittleEndian.PutUint64(headerBuf[0x28:], hdr.rangeTableHeader.fieldSize) + binary.LittleEndian.PutUint64(headerBuf[0x30:], hdr.rangeTableHeader.count) + binary.LittleEndian.PutUint64(headerBuf[0x38:], hdr.rangeTableHeader.offset) + binary.LittleEndian.PutUint32(headerBuf[0x40:], hdr.rangeTableHeader.crc) + + binary.LittleEndian.PutUint64(headerBuf[0x48:], hdr.stringsTableHeader.size) + binary.LittleEndian.PutUint64(headerBuf[0x50:], hdr.stringsTableHeader.offset) + binary.LittleEndian.PutUint32(headerBuf[0x58:], hdr.stringsTableHeader.crc) + + binary.LittleEndian.PutUint64(headerBuf[0x60:], hdr.lineTablesHeader.fieldSize) + binary.LittleEndian.PutUint64(headerBuf[0x68:], hdr.lineTablesHeader.count) + binary.LittleEndian.PutUint64(headerBuf[0x70:], hdr.lineTablesHeader.offset) + binary.LittleEndian.PutUint32(headerBuf[0x78:], hdr.lineTablesHeader.crc) + + if _, err := output.Write(headerBuf); err != nil { + return err + } + return nil +} + +func writeRangeEntries(rb *rangesBuilder, hdr *header, buf *bufio.Writer) error { + hdr.vaTableHeader.count = uint64(len(rb.va)) + hdr.rangeTableHeader.count = uint64(len(rb.entries)) + calculateSizes(rb, hdr) + vaBuf := make([]byte, hdr.vaTableHeader.entrySize) + { + crc := crc32.New(castagnoli) + ww := io.MultiWriter(crc, buf) + if hdr.vaTableHeader.entrySize == 4 { + for i := range rb.va { + binary.LittleEndian.PutUint32(vaBuf, uint32(rb.va[i])) + if _, err := ww.Write(vaBuf); err != nil { + return err + } + } + } else { + for i := range rb.va { + binary.LittleEndian.PutUint64(vaBuf, rb.va[i]) + if _, err := ww.Write(vaBuf); err != nil { + return err + } + } + } + hdr.vaTableHeader.crc = crc.Sum32() + } + bsWritten := len(rb.va) * int(hdr.vaTableHeader.entrySize) + hdr.rangeTableHeader.offset += uint64(bsWritten) + + { + crc := crc32.New(castagnoli) + ww := io.MultiWriter(crc, buf) + if hdr.rangeTableHeader.fieldSize == 4 { + entryBuf := make([]byte, fieldsEntrySize4) + for i := range rb.entries { + writeFields4(entryBuf, rb.entries[i]) + if _, err := ww.Write(entryBuf); err != nil { + return err + } + } + bsWritten += len(rb.entries) * fieldsEntrySize4 + } else { + entryBuf := make([]byte, fieldsEntrySize8) + for i := range rb.entries { + writeFields8(entryBuf, rb.entries[i]) + if _, err := ww.Write(entryBuf); err != nil { + return err + } + } + bsWritten += len(rb.entries) * fieldsEntrySize8 + } + hdr.rangeTableHeader.crc = crc.Sum32() + } + + hdr.stringsTableHeader.offset += uint64(bsWritten) + + return nil +} + +func writeLineTableEntries(lb *lineBuilder, hdr *header, buf *bufio.Writer) error { + hdr.lineTablesHeader.offset = hdr.stringsTableHeader.offset + hdr.stringsTableHeader.size + calculateLineTableFieldSize(lb, hdr) + hdr.lineTablesHeader.count = uint64(len(lb.entries)) + crc := crc32.New(castagnoli) + ww := io.MultiWriter(crc, buf) + if hdr.lineTablesHeader.fieldSize == 2 { + lineTableBuf := make([]byte, 4) + for i := range lb.entries { + binary.LittleEndian.PutUint16(lineTableBuf[0:], uint16(lb.entries[i].Offset)) + binary.LittleEndian.PutUint16(lineTableBuf[2:], uint16(lb.entries[i].LineNumber)) + if _, err := ww.Write(lineTableBuf); err != nil { + return err + } + } + } else { + lineTableBuf := make([]byte, 8) + for i := range lb.entries { + binary.LittleEndian.PutUint32(lineTableBuf[0:], lb.entries[i].Offset) + binary.LittleEndian.PutUint32(lineTableBuf[4:], lb.entries[i].LineNumber) + if _, err := ww.Write(lineTableBuf); err != nil { + return err + } + } + } + hdr.lineTablesHeader.crc = crc.Sum32() + return buf.Flush() +} + +func calculateSizes(rb *rangesBuilder, hdr *header) { + const maxUint32 = uint64(^uint32(0)) + hdr.vaTableHeader.entrySize = 4 + hdr.rangeTableHeader.fieldSize = 4 + for _, va := range rb.va { + if va > maxUint32 { + hdr.vaTableHeader.entrySize = 8 + break + } + } + + for _, e := range rb.entries { + if e.length > maxUint32 || e.depth > maxUint32 || uint64(e.funcOffset) > maxUint32 || + uint64(e.fileOffset) > maxUint32 || e.lineTable.idx > maxUint32 || + e.lineTable.count > maxUint32 { + hdr.rangeTableHeader.fieldSize = 8 + break + } + } +} + +func writeFields8(entryBuf []byte, e rangeEntry) { + binary.LittleEndian.PutUint64(entryBuf[0:], e.length) + binary.LittleEndian.PutUint64(entryBuf[8:], e.depth) + binary.LittleEndian.PutUint64(entryBuf[0x10:], uint64(e.funcOffset)) + binary.LittleEndian.PutUint64(entryBuf[0x18:], uint64(e.fileOffset)) + binary.LittleEndian.PutUint64(entryBuf[0x20:], e.lineTable.idx) + binary.LittleEndian.PutUint64(entryBuf[0x28:], e.lineTable.count) + binary.LittleEndian.PutUint64(entryBuf[0x30:], uint64(e.callFile)) + binary.LittleEndian.PutUint64(entryBuf[0x38:], e.callLine) +} + +func writeFields4(entryBuf []byte, e rangeEntry) { + binary.LittleEndian.PutUint32(entryBuf[0:], uint32(e.length)) + binary.LittleEndian.PutUint32(entryBuf[4:], uint32(e.depth)) + binary.LittleEndian.PutUint32(entryBuf[8:], uint32(e.funcOffset)) + binary.LittleEndian.PutUint32(entryBuf[0xc:], uint32(e.fileOffset)) + binary.LittleEndian.PutUint32(entryBuf[0x10:], uint32(e.lineTable.idx)) + binary.LittleEndian.PutUint32(entryBuf[0x14:], uint32(e.lineTable.count)) + binary.LittleEndian.PutUint32(entryBuf[0x18:], uint32(e.callFile)) + binary.LittleEndian.PutUint32(entryBuf[0x1c:], uint32(e.callLine)) +} + +func calculateLineTableFieldSize(lb *lineBuilder, hdr *header) { + const maxUint16 = uint32(^uint16(0)) + hdr.lineTablesHeader.fieldSize = 2 + for i := range lb.entries { + if lb.entries[i].Offset > maxUint16 || lb.entries[i].LineNumber > maxUint16 { + hdr.lineTablesHeader.fieldSize = 4 + break + } + } +} diff --git a/lidia/go.mod b/lidia/go.mod new file mode 100644 index 0000000000..94ccac26c0 --- /dev/null +++ b/lidia/go.mod @@ -0,0 +1,16 @@ +module github.com/grafana/pyroscope/lidia + +go 1.24.6 + +toolchain go1.25.12 + +require github.com/stretchr/testify v1.11.1 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/lidia/go.sum b/lidia/go.sum new file mode 100644 index 0000000000..5a10c39158 --- /dev/null +++ b/lidia/go.sum @@ -0,0 +1,23 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lidia/gosym/parse.go b/lidia/gosym/parse.go new file mode 100644 index 0000000000..95ee39d49a --- /dev/null +++ b/lidia/gosym/parse.go @@ -0,0 +1,79 @@ +package gosym + +import ( + "debug/elf" + "encoding/binary" + "errors" + "fmt" +) + +func ParseRuntimeTextFromPclntab18(pclntab []byte) uint64 { + if len(pclntab) < 64 { + return 0 + } + magic := binary.LittleEndian.Uint32(pclntab[0:4]) + if magic == 0xFFFFFFF0 || magic == 0xFFFFFFF1 { + // https://github.com/golang/go/blob/go1.18/src/runtime/symtab.go#L395 + // 0xFFFFFFF1 is the same + // https://github.com/golang/go/commit/0f8dffd0aa71ed996d32e77701ac5ec0bc7cde01 + //type pcHeader struct { + // magic uint32 // 0xFFFFFFF0 + // pad1, pad2 uint8 // 0,0 + // minLC uint8 // min instruction size + // ptrSize uint8 // size of a ptr in bytes + // nfunc int // number of functions in the module + // nfiles uint // number of entries in the file tab + // textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text + // funcnameOffset uintptr // offset to the funcnametab variable from pcHeader + // cuOffset uintptr // offset to the cutab variable from pcHeader + // filetabOffset uintptr // offset to the filetab variable from pcHeader + // pctabOffset uintptr // offset to the pctab variable from pcHeader + // pclnOffset uintptr // offset to the pclntab variable from pcHeader + //} + textStart := binary.LittleEndian.Uint64(pclntab[24:32]) + return textStart + } + + return 0 +} + +var errEmptyText = errors.New("empty text") + +func GoFunctions(f *elf.File) ([]Func, error) { + const headerSize = 64 + var err error + text := f.Section(".text") + if text == nil { + return nil, errEmptyText + } + pclntab := f.Section(".gopclntab") + if pclntab == nil { + return nil, nil // not a go binary - return no functions, no error + } + pclntabData, err := pclntab.Data() + if err != nil { + return nil, err + } + + if len(pclntabData) < headerSize { + return nil, fmt.Errorf("invalid .gopclntab header") + } + pclntabHeader := pclntabData[:headerSize] + + textStart := ParseRuntimeTextFromPclntab18(pclntabHeader) + + if textStart == 0 { + // for older versions text.Addr is enough + // https://github.com/golang/go/commit/b38ab0ac5f78ac03a38052018ff629c03e36b864 + textStart = text.Addr + } + if textStart < text.Addr || textStart >= text.Addr+text.Size { + return nil, fmt.Errorf("runtime.text out of .text bounds %d %d %d", textStart, text.Addr, text.Size) + } + pcln := NewLineTable(pclntabData, textStart) + + if !pcln.IsGo12() { + return nil, nil // too old - return no functions, no error + } + return pcln.Go12Funcs(), nil +} diff --git a/lidia/gosym/pclntab.go b/lidia/gosym/pclntab.go new file mode 100644 index 0000000000..aced061abb --- /dev/null +++ b/lidia/gosym/pclntab.go @@ -0,0 +1,483 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + * Line tables + */ + +//nolint:unused +package gosym + +import ( + "bytes" + "encoding/binary" + "sort" + "sync" +) + +type Sym struct { + Value uint64 + Type byte + Name string + GoType uint64 + // If this symbol is a function symbol, the corresponding Func + Func *Func + + goVersion version +} + +type Func struct { + Entry uint64 + *Sym + End uint64 + Params []*Sym // nil for Go 1.3 and later binaries + Locals []*Sym // nil for Go 1.3 and later binaries + FrameSize int + LineTable *LineTable + //Obj *Obj +} + +// version of the pclntab +type version int + +const ( + verUnknown version = iota + ver11 + ver12 + ver116 + ver118 + ver120 +) + +// A LineTable is a data structure mapping program counters to line numbers. +// +// In Go 1.1 and earlier, each function (represented by a [Func]) had its own LineTable, +// and the line number corresponded to a numbering of all source lines in the +// program, across all files. That absolute line number would then have to be +// converted separately to a file name and line number within the file. +// +// In Go 1.2, the format of the data changed so that there is a single LineTable +// for the entire program, shared by all Funcs, and there are no absolute line +// numbers, just line numbers within specific files. +// +// For the most part, LineTable's methods should be treated as an internal +// detail of the package; callers should use the methods on [Table] instead. +type LineTable struct { + Data []byte + PC uint64 + Line int + + // This mutex is used to keep parsing of pclntab synchronous. + mu sync.Mutex + + // Contains the version of the pclntab section. + version version + + // Go 1.2/1.16/1.18 state + binary binary.ByteOrder + quantum uint32 + ptrsize uint32 + textStart uint64 // address of runtime.text symbol (1.18+) + funcnametab []byte + cutab []byte + funcdata []byte + functab []byte + nfunctab uint32 + filetab []byte + pctab []byte // points to the pctables. + nfiletab uint32 + funcNames map[uint32]string // cache the function names + strings map[uint32]string // interned substrings of Data, keyed by offset +} + +// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4, +// but we have no idea whether we're using arm or not. This only +// matters in the old (pre-Go 1.2) symbol table format, so it's not worth +// fixing. +const oldQuantum = 1 + +func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) { + // The PC/line table can be thought of as a sequence of + // * + // batches. Each update batch results in a (pc, line) pair, + // where line applies to every PC from pc up to but not + // including the pc of the next pair. + // + // Here we process each update individually, which simplifies + // the code, but makes the corner cases more confusing. + b, pc, line = t.Data, t.PC, t.Line + for pc <= targetPC && line != targetLine && len(b) > 0 { + code := b[0] + b = b[1:] + switch { + case code == 0: + if len(b) < 4 { + b = b[0:0] + break + } + val := binary.BigEndian.Uint32(b) + b = b[4:] + line += int(val) + case code <= 64: + line += int(code) + case code <= 128: + line -= int(code - 64) + default: + pc += oldQuantum * uint64(code-128) + continue + } + pc += oldQuantum + } + return b, pc, line +} + +// NewLineTable returns a new PC/line table +// corresponding to the encoded data. +// Text must be the start address of the +// corresponding text segment, with the exact +// value stored in the 'runtime.text' symbol. +// This value may differ from the start +// address of the text segment if +// binary was built with cgo enabled. +func NewLineTable(data []byte, text uint64) *LineTable { + return &LineTable{Data: data, PC: text, Line: 0, funcNames: make(map[uint32]string), strings: make(map[uint32]string)} +} + +// Go 1.2 symbol table format. +// See golang.org/s/go12symtab. +// +// A general note about the methods here: rather than try to avoid +// index out of bounds errors, we trust Go to detect them, and then +// we recover from the panics and treat them as indicative of a malformed +// or incomplete table. +// +// The methods called by symtab.go, which begin with "go12" prefixes, +// are expected to have that recovery logic. + +// isGo12 reports whether this is a Go 1.2 (or later) symbol table. +func (t *LineTable) IsGo12() bool { + return t.isGo12() +} +func (t *LineTable) isGo12() bool { + t.parsePclnTab() + return t.version >= ver12 +} + +const ( + go12magic = 0xfffffffb + go116magic = 0xfffffffa + go118magic = 0xfffffff0 + go120magic = 0xfffffff1 +) + +// uintptr returns the pointer-sized value encoded at b. +// The pointer size is dictated by the table being read. +func (t *LineTable) uintptr(b []byte) uint64 { + if t.ptrsize == 4 { + return uint64(t.binary.Uint32(b)) + } + return t.binary.Uint64(b) +} + +// parsePclnTab parses the pclntab, setting the version. +func (t *LineTable) parsePclnTab() { + t.mu.Lock() + defer t.mu.Unlock() + if t.version != verUnknown { + return + } + + // Note that during this function, setting the version is the last thing we do. + // If we set the version too early, and parsing failed (likely as a panic on + // slice lookups), we'd have a mistaken version. + // + // Error paths through this code will default the version to 1.1. + t.version = ver11 + + if !disableRecover { + defer func() { + // If we panic parsing, assume it's a Go 1.1 pclntab. + _ = recover() + }() + } + + // Check header: 4-byte magic, two zeros, pc quantum, pointer size. + if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 || + (t.Data[6] != 1 && t.Data[6] != 2 && t.Data[6] != 4) || // pc quantum + (t.Data[7] != 4 && t.Data[7] != 8) { // pointer size + return + } + + var possibleVersion version + leMagic := binary.LittleEndian.Uint32(t.Data) + beMagic := binary.BigEndian.Uint32(t.Data) + switch { + case leMagic == go12magic: + t.binary, possibleVersion = binary.LittleEndian, ver12 + case beMagic == go12magic: + t.binary, possibleVersion = binary.BigEndian, ver12 + case leMagic == go116magic: + t.binary, possibleVersion = binary.LittleEndian, ver116 + case beMagic == go116magic: + t.binary, possibleVersion = binary.BigEndian, ver116 + case leMagic == go118magic: + t.binary, possibleVersion = binary.LittleEndian, ver118 + case beMagic == go118magic: + t.binary, possibleVersion = binary.BigEndian, ver118 + case leMagic == go120magic: + t.binary, possibleVersion = binary.LittleEndian, ver120 + case beMagic == go120magic: + t.binary, possibleVersion = binary.BigEndian, ver120 + default: + return + } + t.version = possibleVersion + + // quantum and ptrSize are the same between 1.2, 1.16, and 1.18 + t.quantum = uint32(t.Data[6]) + t.ptrsize = uint32(t.Data[7]) + + offset := func(word uint32) uint64 { + return t.uintptr(t.Data[8+word*t.ptrsize:]) + } + data := func(word uint32) []byte { + return t.Data[offset(word):] + } + + switch possibleVersion { + case ver118, ver120: + t.nfunctab = uint32(offset(0)) + t.nfiletab = uint32(offset(1)) + t.textStart = t.PC // use the start PC instead of reading from the table, which may be unrelocated + t.funcnametab = data(3) + t.cutab = data(4) + t.filetab = data(5) + t.pctab = data(6) + t.funcdata = data(7) + t.functab = data(7) + functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize() + t.functab = t.functab[:functabsize] + case ver116: + t.nfunctab = uint32(offset(0)) + t.nfiletab = uint32(offset(1)) + t.funcnametab = data(2) + t.cutab = data(3) + t.filetab = data(4) + t.pctab = data(5) + t.funcdata = data(6) + t.functab = data(6) + functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize() + t.functab = t.functab[:functabsize] + case ver12: + t.nfunctab = uint32(t.uintptr(t.Data[8:])) + t.funcdata = t.Data + t.funcnametab = t.Data + t.functab = t.Data[8+t.ptrsize:] + t.pctab = t.Data + functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize() + fileoff := t.binary.Uint32(t.functab[functabsize:]) + t.functab = t.functab[:functabsize] + t.filetab = t.Data[fileoff:] + t.nfiletab = t.binary.Uint32(t.filetab) + t.filetab = t.filetab[:t.nfiletab*4] + default: + panic("unreachable") + } +} + +// go12Funcs returns a slice of Funcs derived from the Go 1.2+ pcln table. +func (t *LineTable) go12Funcs() []Func { + // Assume it is malformed and return nil on error. + if !disableRecover { + defer func() { + _ = recover() + }() + } + + ft := t.funcTab() + funcs := make([]Func, ft.Count()) + syms := make([]Sym, len(funcs)) + for i := range funcs { + f := &funcs[i] + f.Entry = ft.pc(i) + f.End = ft.pc(i + 1) + info := t.funcData(uint32(i)) + f.LineTable = t + f.FrameSize = int(info.deferreturn()) + syms[i] = Sym{ + Value: f.Entry, + Type: 'T', + Name: t.funcName(info.nameOff()), + GoType: 0, + Func: f, + goVersion: t.version, + } + f.Sym = &syms[i] + } + return funcs +} + +// findFunc returns the funcData corresponding to the given program counter. +func (t *LineTable) findFunc(pc uint64) funcData { + ft := t.funcTab() + if pc < ft.pc(0) || pc >= ft.pc(ft.Count()) { + return funcData{} + } + idx := sort.Search(int(t.nfunctab), func(i int) bool { + return ft.pc(i) > pc + }) + idx-- + return t.funcData(uint32(idx)) +} + +// readvarint reads, removes, and returns a varint from *pp. +func (t *LineTable) readvarint(pp *[]byte) uint32 { + var v, shift uint32 + p := *pp + for shift = 0; ; shift += 7 { + b := p[0] + p = p[1:] + v |= (uint32(b) & 0x7F) << shift + if b&0x80 == 0 { + break + } + } + *pp = p + return v +} + +// funcName returns the name of the function found at off. +func (t *LineTable) funcName(off uint32) string { + if s, ok := t.funcNames[off]; ok { + return s + } + i := bytes.IndexByte(t.funcnametab[off:], 0) + s := string(t.funcnametab[off : off+uint32(i)]) + t.funcNames[off] = s + return s +} + +// stringFrom returns a Go string found at off from a position. +func (t *LineTable) stringFrom(arr []byte, off uint32) string { + if s, ok := t.strings[off]; ok { + return s + } + i := bytes.IndexByte(arr[off:], 0) + s := string(arr[off : off+uint32(i)]) + t.strings[off] = s + return s +} + +// string returns a Go string found at off. +func (t *LineTable) string(off uint32) string { + return t.stringFrom(t.funcdata, off) +} + +// functabFieldSize returns the size in bytes of a single functab field. +func (t *LineTable) functabFieldSize() int { + if t.version >= ver118 { + return 4 + } + return int(t.ptrsize) +} + +// funcTab returns t's funcTab. +func (t *LineTable) funcTab() funcTab { + return funcTab{LineTable: t, sz: t.functabFieldSize()} +} + +// funcTab is memory corresponding to a slice of functab structs, followed by an invalid PC. +// A functab struct is a PC and a func offset. +type funcTab struct { + *LineTable + sz int // cached result of t.functabFieldSize +} + +// Count returns the number of func entries in f. +func (f funcTab) Count() int { + return int(f.nfunctab) +} + +// pc returns the PC of the i'th func in f. +func (f funcTab) pc(i int) uint64 { + u := f.uint(f.functab[2*i*f.sz:]) + if f.version >= ver118 { + u += f.textStart + } + return u +} + +// funcOff returns the funcdata offset of the i'th func in f. +func (f funcTab) funcOff(i int) uint64 { + return f.uint(f.functab[(2*i+1)*f.sz:]) +} + +// uint returns the uint stored at b. +func (f funcTab) uint(b []byte) uint64 { + if f.sz == 4 { + return uint64(f.binary.Uint32(b)) + } + return f.binary.Uint64(b) +} + +// funcData is memory corresponding to an _func struct. +type funcData struct { + t *LineTable // LineTable this data is a part of + data []byte // raw memory for the function +} + +// funcData returns the ith funcData in t.functab. +func (t *LineTable) funcData(i uint32) funcData { + data := t.funcdata[t.funcTab().funcOff(int(i)):] + return funcData{t: t, data: data} +} + +// IsZero reports whether f is the zero value. +func (f funcData) IsZero() bool { + return f.t == nil && f.data == nil +} + +// entryPC returns the func's entry PC. +func (f *funcData) entryPC() uint64 { + // In Go 1.18, the first field of _func changed + // from a uintptr entry PC to a uint32 entry offset. + if f.t.version >= ver118 { + // TODO: support multiple text sections. + // See runtime/symtab.go:(*moduledata).textAddr. + return uint64(f.t.binary.Uint32(f.data)) + f.t.textStart + } + return f.t.uintptr(f.data) +} + +func (f funcData) nameOff() uint32 { return f.field(1) } +func (f funcData) deferreturn() uint32 { return f.field(3) } +func (f funcData) pcfile() uint32 { return f.field(5) } +func (f funcData) pcln() uint32 { return f.field(6) } +func (f funcData) cuOffset() uint32 { return f.field(8) } + +// field returns the nth field of the _func struct. +// It panics if n == 0 or n > 9; for n == 0, call f.entryPC. +// Most callers should use a named field accessor (just above). +func (f funcData) field(n uint32) uint32 { + if n == 0 || n > 9 { + panic("bad funcdata field") + } + // In Go 1.18, the first field of _func changed + // from a uintptr entry PC to a uint32 entry offset. + sz0 := f.t.ptrsize + if f.t.version >= ver118 { + sz0 = 4 + } + off := sz0 + (n-1)*4 // subsequent fields are 4 bytes each + data := f.data[off:] + return f.t.binary.Uint32(data) +} + +func (t *LineTable) Go12Funcs() []Func { + return t.go12Funcs() +} + +// disableRecover causes this package not to swallow panics. +// This is useful when making changes. +const disableRecover = false diff --git a/lidia/lidia.go b/lidia/lidia.go new file mode 100644 index 0000000000..046f230b61 --- /dev/null +++ b/lidia/lidia.go @@ -0,0 +1,295 @@ +// Package lidia implements a custom binary format for efficient symbolization of Go profiles. +// +// Lidia provides a compact binary representation of symbol information extracted from +// ELF files, optimized for fast lookup by memory address. This is particularly useful +// for symbolizing profile data collected from Go applications. +package lidia + +import ( + "debug/elf" + "errors" + "fmt" + "io" + "os" + "sort" + + "github.com/grafana/pyroscope/lidia/gosym" +) + +type ReaderAtCloser interface { + io.ReadCloser + io.ReaderAt +} + +// Table represents a lidia symbol table that can be queried for lookups. +type Table struct { + file ReaderAtCloser + hdr header + opt options + + vaTable []byte + + fieldsBuffer []byte +} + +// SourceInfoFrame represents a single frame of symbolized profiling information. +// It contains the name of the function, the source file path, and the line number +// at which the profiling sample was taken. +type SourceInfoFrame struct { + LineNumber uint64 + FunctionName string + FilePath string +} + +// Range represents a function range to be added to a lidia file. +type Range struct { + VA uint64 + Length uint32 + Function string + File string + CallFile string + CallLine uint32 + Depth uint32 + LineTable LineTable +} + +// LineTable represents source line number information. +type LineTable []LineTableEntry + +// LineTableEntry maps an offset to a line number. +type LineTableEntry struct { + Offset uint32 + LineNumber uint32 +} + +// OpenReader creates a new Table from the provided ReaderAtCloser. +// It reads the header, validates the format, and prepares the table for lookups. +// The caller is responsible for closing the returned Table. +func OpenReader(f ReaderAtCloser, opt ...Option) (*Table, error) { + var err error + res := new(Table) + + for _, o := range opt { + o(&res.opt) + } + + res.file = f + + hdr, err := readHeader(f) + if err != nil { + res.Close() + return nil, fmt.Errorf("failed to read header: %w", err) + } + + for i := range magic { + if hdr.magic[i] != magic[i] { + res.Close() + return nil, fmt.Errorf("invalid magic number") + } + } + + if hdr.version != version { + res.Close() + return nil, fmt.Errorf("unsupported version: expected %d, got %d", version, hdr.version) + } + + if hdr.vaTableHeader.entrySize != 4 && hdr.vaTableHeader.entrySize != 8 { + res.Close() + return nil, fmt.Errorf("invalid vaSize: %d, expected 4 or 8", hdr.vaTableHeader.entrySize) + } + + if hdr.rangeTableHeader.fieldSize != 4 && hdr.rangeTableHeader.fieldSize != 8 { + res.Close() + return nil, fmt.Errorf("invalid fieldSize: %d, expected 4 or 8", hdr.rangeTableHeader.fieldSize) + } + + if hdr.rangeTableHeader.count != hdr.vaTableHeader.count { + res.Close() + return nil, fmt.Errorf("count mismatch: range table count (%d) != VA table count (%d)", + hdr.rangeTableHeader.count, hdr.vaTableHeader.count) + } + + res.hdr = hdr + + res.fieldsBuffer = make([]byte, int(hdr.rangeTableHeader.fieldSize)*fieldsCount) + // all functions addresses sorted. + res.vaTable = make([]byte, int(hdr.vaTableHeader.entrySize)*int(hdr.vaTableHeader.count)) + + if _, err = f.ReadAt(res.vaTable, int64(hdr.vaTableHeader.offset)); err != nil { + res.Close() + return nil, fmt.Errorf("failed to read VA table: %w", err) + } + + if res.opt.crc { + if err = res.CheckCRC(); err != nil { + res.Close() + return nil, fmt.Errorf("CRC check failed: %w", err) + } + } + + return res, nil +} + +// CreateLidia generates a lidia format file from an ELF executable. +// It extracts symbol information and writes it to the output file. +func CreateLidia(executablePath, outputPath string, opts ...Option) error { + executable, err := os.Open(executablePath) + if err != nil { + return fmt.Errorf("failed to open executable: %w", err) + } + defer executable.Close() + + output, err := os.Create(outputPath) + if err != nil { + return fmt.Errorf("failed to create output file: %w", err) + } + defer output.Close() + + e, err := elf.NewFile(executable) + if err != nil { + return fmt.Errorf("failed to parse ELF file: %w", err) + } + + return CreateLidiaFromELF(e, output, opts...) +} + +// CreateLidiaFromELF generates a lidia format file from an already opened ELF file. +// This allows more control over the ELF file handling. +func CreateLidiaFromELF(elfFile *elf.File, output io.WriteSeeker, opts ...Option) error { + sb := newStringBuilder() + rb := newRangesBuilder() + lb := newLineTableBuilder() + rc := &rangeCollector{sb: sb, rb: rb, lb: lb, opt: options{ + symtab: true, + parseGoPclntab: true, + }} + + for _, o := range opts { + o(&rc.opt) + } + + if rc.opt.symtab { + var ( + symErr, dynSymErr error + ) + symbols, symErr := elfFile.Symbols() + if symErr != nil { + symbols, dynSymErr = elfFile.DynamicSymbols() + if dynSymErr != nil { + if !errors.Is(symErr, elf.ErrNoSymbols) || !errors.Is(dynSymErr, elf.ErrNoSymbols) { + return fmt.Errorf("failed to read symbols from ELF file: %w, %w", symErr, dynSymErr) + } + } + } + + for _, symbol := range symbols { + if elf.ST_TYPE(symbol.Info) != elf.STT_FUNC || symbol.Name == "" { + continue + } + rc.VisitRange(&Range{ + VA: symbol.Value, + Length: uint32(symbol.Size), + Function: symbol.Name, + File: "", + CallFile: "", + CallLine: 0, + Depth: 0, + LineTable: nil, + }) + } + } + if rc.opt.parseGoPclntab { + functions, err := gosym.GoFunctions(elfFile) + if err != nil { + return err + } + for i := range functions { + f := &functions[i] + rc.VisitRange(&Range{ + VA: f.Entry, + Length: uint32(f.End - f.Entry), + Function: f.Name, + }) + } + } + + rb.sort() + + err := rc.write(output) + if err != nil { + return fmt.Errorf("failed to write lidia file: %w", err) + } + + return nil +} + +// Lookup performs a symbol lookup by memory address. +// It accepts a destination slice 'dst' to store the results, allowing memory reuse +// between calls. The function returns a slice of SourceInfoFrame representing the +// symbolization result for the given address. The returned slice may be the same as +// the input slice 'dst' with updated contents, or a new slice if 'dst' needed to grow. +// If 'dst' is nil, a new slice will be allocated. +func (st *Table) Lookup(dst []SourceInfoFrame, addr uint64) ([]SourceInfoFrame, error) { + dst = dst[:0] + + idx := sort.Search(int(st.hdr.vaTableHeader.count), func(i int) bool { + return st.getEntryVA(i) > addr + }) + idx-- + + for idx >= 0 { + it, err := st.getEntry(idx) + if err != nil { + return dst, fmt.Errorf("failed to get entry at index %d: %w", idx, err) + } + + covered := it.va <= addr && addr < it.va+it.length + if covered { + name := st.str(it.funcOffset) + file := st.str(it.fileOffset) + + res := SourceInfoFrame{ + FunctionName: name, + FilePath: file, + } + + // Add line number information if available + //if it.lineTable.count > 0 { + // Line number could be extracted here if implemented + //} + + dst = append(dst, res) + } + + if it.depth == 0 { + break + } + idx-- + } + + return dst, nil +} + +// Close releases resources associated with the Table. +func (st *Table) Close() { + if st.file != nil { + _ = st.file.Close() + } +} + +// CheckCRC verifies the CRC checksums of all tables in the lidia file. +func (st *Table) CheckCRC() error { + if err := st.CheckCRCVA(); err != nil { + return err + } + if err := st.CheckCRCStrings(); err != nil { + return err + } + if err := st.CheckCRCFields(); err != nil { + return err + } + if err := st.CheckCRCLineTables(); err != nil { + return err + } + return nil +} diff --git a/lidia/lidia_test.go b/lidia/lidia_test.go new file mode 100644 index 0000000000..d874c5f3dd --- /dev/null +++ b/lidia/lidia_test.go @@ -0,0 +1,292 @@ +package lidia_test + +import ( + "archive/zip" + "debug/elf" + "io" + "os" + "path/filepath" + "reflect" + "runtime" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/lidia" +) + +const compressedTestBinaryFile = "testdata/test-binary.zip" +const decompressedDir = "decompressed" + +// TestCreateLidia tests the CreateLidia function with the test binary +func TestCreateLidia(t *testing.T) { + binaryPath := decompressBinary(t) + if binaryPath == "" { + return + } + + tmpDir := t.TempDir() + outputPath := filepath.Join(tmpDir, "test.lidia") + + err := lidia.CreateLidia(binaryPath, outputPath, + lidia.WithCRC(), lidia.WithFiles(), lidia.WithLines()) + require.NoError(t, err) + + fileInfo, err := os.Stat(outputPath) + require.NoError(t, err) + require.Greater(t, fileInfo.Size(), int64(0), "Lidia file should not be empty") +} + +// TestCreateLidiaFromELF tests the CreateLidiaFromELF function with the test binary +func TestCreateLidiaFromELF(t *testing.T) { + binaryPath := decompressBinary(t) + if binaryPath == "" { + return + } + + elfFile, err := elf.Open(binaryPath) + require.NoError(t, err) + defer elfFile.Close() + + tmpDir := t.TempDir() + outputPath := filepath.Join(tmpDir, "test.lidia") + outputFile, err := os.Create(outputPath) + require.NoError(t, err) + defer outputFile.Close() + + err = lidia.CreateLidiaFromELF(elfFile, outputFile, + lidia.WithCRC(), lidia.WithFiles(), lidia.WithLines()) + require.NoError(t, err) + + fileInfo, err := outputFile.Stat() + require.NoError(t, err) + require.Greater(t, fileInfo.Size(), int64(0), "Lidia file should not be empty") +} + +// TestCreateReadLookup is a comprehensive test that creates a lidia file, +// reads it back, and tests lookups against the same file +func TestCreateReadLookup(t *testing.T) { + binaryPath := decompressBinary(t) + if binaryPath == "" { + return + } + + tmpDir := t.TempDir() + lidiaPath := filepath.Join(tmpDir, "test.lidia") + + // Create the lidia file + err := lidia.CreateLidia(binaryPath, lidiaPath, + lidia.WithCRC(), lidia.WithFiles(), lidia.WithLines()) + require.NoError(t, err) + + // Read the created lidia file + bs, err := os.ReadFile(lidiaPath) + require.NoError(t, err) + + // Open the lidia table + var reader lidia.ReaderAtCloser = &bufferCloser{bs, 0} + table, err := lidia.OpenReader(reader, lidia.WithCRC()) + require.NoError(t, err) + defer table.Close() + + testCases := []struct { + name string + addr uint64 + expectFunction string + expectFound bool + }{ + { + name: "Unknown address", + addr: 0x100, + expectFunction: "", + expectFound: false, + }, + { + name: "Known function address", + addr: 0x3c85d0, + expectFunction: "github.com/prometheus/client_model/go.init", + expectFound: true, + }, + { + name: "Known struct function address", + addr: 0x3c8b70, + expectFunction: "github.com/prometheus/client_model/go.MetricType.Enum", + expectFound: true, + }, + } + + var results []lidia.SourceInfoFrame + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + results, err := table.Lookup(results, tc.addr) + require.NoError(t, err) + if tc.expectFound { + require.NotEmpty(t, results, "Expected to find a function at this address") + require.Equal(t, tc.expectFunction, results[0].FunctionName) + } else { + require.Empty(t, results, "Expected no function at this address") + } + }) + } +} + +func TestDynSym(t *testing.T) { + tmpDir := t.TempDir() + lidiaPath := filepath.Join(tmpDir, "test.lidia") + + err := lidia.CreateLidia("./testdata/libfib.so", lidiaPath, + lidia.WithCRC(), lidia.WithFiles(), lidia.WithLines()) + require.NoError(t, err) + + bs, err := os.ReadFile(lidiaPath) + require.NoError(t, err) + + var reader lidia.ReaderAtCloser = &bufferCloser{bs, 0} + table, err := lidia.OpenReader(reader, lidia.WithCRC()) + require.NoError(t, err) + defer table.Close() + + testCases := []struct { + name string + addr uint64 + expectFunction string + expectFound bool + }{ + { + name: "fib", + addr: 0x330, + expectFunction: "fib", + expectFound: true, + }, + } + + var results []lidia.SourceInfoFrame + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + results, err := table.Lookup(results, tc.addr) + require.NoError(t, err) + if tc.expectFound { + require.NotEmpty(t, results, "Expected to find a function at this address") + require.Equal(t, tc.expectFunction, results[0].FunctionName) + } else { + require.Empty(t, results, "Expected no function at this address") + } + }) + } +} + +// bufferCloser implements the lidia.ReaderAtCloser interface for testing +type bufferCloser struct { + bs []byte + off int64 +} + +func (b *bufferCloser) Read(p []byte) (n int, err error) { + res, err := b.ReadAt(p, b.off) + b.off += int64(res) + return res, err +} + +func (b *bufferCloser) ReadAt(p []byte, off int64) (n int, err error) { + if off >= int64(len(b.bs)) { + return 0, io.EOF + } + n = copy(p, b.bs[off:]) + return n, nil +} + +func (b *bufferCloser) Close() error { + return nil +} + +// TestGoPclntabSelfExe tests creating a lidia table from /proc/self/exe using only gopclntab +// (no symtab) and resolving the test function's address. +func TestGoPclntabSelfExe(t *testing.T) { + if runtime.GOOS != "linux" { + t.Skip("skipping: /proc/self/exe is only available on Linux") + } + // Get the address of this test function using reflect + testFuncAddr := reflect.ValueOf(TestGoPclntabSelfExe).Pointer() + + tmpDir := t.TempDir() + lidiaPath := filepath.Join(tmpDir, "self.lidia") + + // Create lidia file from /proc/self/exe using only gopclntab (disable symtab) + err := lidia.CreateLidia("/proc/self/exe", lidiaPath, + lidia.WithCRC(), + lidia.WithSymtab(false), // Disable symtab + lidia.WithParseGoPclntab(true), // Use only gopclntab + ) + require.NoError(t, err) + + // Read the created lidia file + bs, err := os.ReadFile(lidiaPath) + require.NoError(t, err) + + // Open the lidia table + var reader lidia.ReaderAtCloser = &bufferCloser{bs, 0} + table, err := lidia.OpenReader(reader, lidia.WithCRC()) + require.NoError(t, err) + defer table.Close() + + // Lookup the test function's address + var results []lidia.SourceInfoFrame + results, err = table.Lookup(results, uint64(testFuncAddr)) + require.NoError(t, err) + + // Verify we found the function and the name matches + require.NotEmpty(t, results, "Expected to find the test function at address %#x", testFuncAddr) + require.Equal(t, "github.com/grafana/pyroscope/lidia_test.TestGoPclntabSelfExe", results[0].FunctionName, + "Function name should match the test function") +} + +// decompressBinary decompresses the test binary from zip to a temporary location and returns its path +func decompressBinary(t *testing.T) string { + // Skip if the compressed test file doesn't exist + if _, err := os.Stat(compressedTestBinaryFile); os.IsNotExist(err) { + t.Skip("Compressed test binary not found") + return "" + } + + // Create a temporary directory for the decompressed file + tmpDir := t.TempDir() + decompressedPath := filepath.Join(tmpDir, decompressedDir) + err := os.MkdirAll(decompressedPath, 0755) + require.NoError(t, err) + + outputPath := filepath.Join(decompressedPath, "test-binary") + + // Open the zip archive + zipReader, err := zip.OpenReader(compressedTestBinaryFile) + require.NoError(t, err) + defer zipReader.Close() + + // We expect only one file in the archive - the binary + if len(zipReader.File) == 0 { + t.Skip("Zip archive is empty") + return "" + } + + // Get the first file from the archive + zipFile := zipReader.File[0] + zippedReader, err := zipFile.Open() + require.NoError(t, err) + defer zippedReader.Close() + + // Create output file + outputFile, err := os.Create(outputPath) + require.NoError(t, err) + defer outputFile.Close() + + // Copy unzipped data to output file + _, err = io.Copy(outputFile, zippedReader) + require.NoError(t, err) + + // Ensure the file is executable + err = os.Chmod(outputPath, 0755) + require.NoError(t, err) + + return outputPath +} diff --git a/lidia/options.go b/lidia/options.go new file mode 100644 index 0000000000..87ac46b330 --- /dev/null +++ b/lidia/options.go @@ -0,0 +1,48 @@ +// options.go +package lidia + +// Option configures a Table or file creation process. +type Option func(*options) + +// Options for controlling the behavior of lidia operations +type options struct { + crc bool // Enable CRC checking + lines bool // Include line number information + files bool // Include file path information + + parseGoPclntab bool + symtab bool +} + +// WithCRC enables CRC checking when opening lidia files. +func WithCRC() Option { + return func(o *options) { + o.crc = true + } +} + +// WithLines includes line number information in created lidia files. +func WithLines() Option { + return func(o *options) { + o.lines = true + } +} + +// WithFiles includes file path information in created lidia files. +func WithFiles() Option { + return func(o *options) { + o.files = true + } +} + +func WithParseGoPclntab(parse bool) Option { + return func(o *options) { + o.parseGoPclntab = parse + } +} + +func WithSymtab(parse bool) Option { + return func(o *options) { + o.symtab = parse + } +} diff --git a/lidia/table.go b/lidia/table.go new file mode 100644 index 0000000000..b204e41a25 --- /dev/null +++ b/lidia/table.go @@ -0,0 +1,119 @@ +package lidia + +import ( + "encoding/binary" + "errors" + "fmt" + "hash/crc32" + "io" +) + +type entry struct { + va uint64 + rangeEntry +} + +func (e entry) String() string { + return fmt.Sprintf("va: %x, length: %d depth: %d", e.va, e.length, e.depth) +} + +func (st *Table) getEntry(i int) (entry, error) { + if i < 0 || i >= int(st.hdr.vaTableHeader.count) { + return entry{}, errors.New("index out of bounds") + } + offset := int64(st.hdr.rangeTableHeader.offset) + int64(i)*int64(len(st.fieldsBuffer)) + + if _, err := st.file.ReadAt(st.fieldsBuffer, offset); err != nil { + return entry{}, err + } + e := entry{} + if st.hdr.rangeTableHeader.fieldSize == 4 { + e.rangeEntry = readFields4(st.fieldsBuffer) + } else { + e.rangeEntry = readFields8(st.fieldsBuffer) + } + e.va = st.getEntryVA(i) + return e, nil +} + +func (st *Table) CheckCRCVA() error { + crc := crc32.New(castagnoli) + _, _ = crc.Write(st.vaTable) + if crc.Sum32() != st.hdr.vaTableHeader.crc { + return errors.New("crc mismatch in va table") + } + return nil +} + +func (st *Table) CheckCRCStrings() error { + return checkCRC(st.file, + int64(st.hdr.stringsTableHeader.offset), + int64(st.hdr.stringsTableHeader.size), + st.hdr.stringsTableHeader.crc, + "strings") +} + +func (st *Table) CheckCRCFields() error { + elementSize := int64(st.hdr.rangeTableHeader.fieldSize) * fieldsCount + sz := elementSize * int64(st.hdr.rangeTableHeader.count) + return checkCRC(st.file, + int64(st.hdr.rangeTableHeader.offset), + sz, st.hdr.rangeTableHeader.crc, + "fields") +} + +func (st *Table) CheckCRCLineTables() error { + elementSize := int64(st.hdr.lineTablesHeader.fieldSize) * lineTableFieldsCount + return checkCRC(st.file, + int64(st.hdr.lineTablesHeader.offset), + elementSize*int64(st.hdr.lineTablesHeader.count), + st.hdr.lineTablesHeader.crc, + "linetable") +} + +func (st *Table) getEntryVA(i int) uint64 { + offset := int64(i) * int64(st.hdr.vaTableHeader.entrySize) + it := st.vaTable[offset : offset+int64(st.hdr.vaTableHeader.entrySize)] + if st.hdr.vaTableHeader.entrySize == 4 { + return uint64(binary.LittleEndian.Uint32(it)) + } + return binary.LittleEndian.Uint64(it) +} + +func (st *Table) str(offset stringOffset) string { + if offset == 0 { + return "" + } + var strLen uint32 + buf := st.fieldsBuffer[:4] + if _, err := st.readStrData(buf, uint64(offset)); err != nil { + return "" + } + strLen = binary.LittleEndian.Uint32(buf) + strData := make([]byte, strLen) + if _, err := st.readStrData(strData, uint64(offset)+4); err != nil { + if err != io.EOF { + return "" + } + } + return string(strData) +} + +func (st *Table) readStrData(buf []byte, o uint64) (int, error) { + return st.file.ReadAt(buf, int64(st.hdr.stringsTableHeader.offset+o)) +} + +func checkCRC(f ReaderAtCloser, offset, size int64, expected uint32, name string) error { + crc := crc32.New(castagnoli) + n, err := io.Copy(crc, io.NewSectionReader(f, offset, size)) + if err != nil { + return err + } + if n != size { + return errors.New("unexpected end of " + name) + } + if crc.Sum32() != expected { + return errors.New("crc mismatch in " + name) + } + return nil +} diff --git a/lidia/testdata/libfib.so b/lidia/testdata/libfib.so new file mode 100755 index 0000000000..3bfd329e6a Binary files /dev/null and b/lidia/testdata/libfib.so differ diff --git a/lidia/testdata/test-binary.zip b/lidia/testdata/test-binary.zip new file mode 100644 index 0000000000..773be67301 Binary files /dev/null and b/lidia/testdata/test-binary.zip differ diff --git a/og/.air-test.conf b/og/.air-test.conf deleted file mode 100644 index bacb3787fb..0000000000 --- a/og/.air-test.conf +++ /dev/null @@ -1,43 +0,0 @@ -# .air-test.conf -# Config file for [Air](https://github.com/cosmtrek/air) in TOML format - -# Working directory -# . or absolute path, please note that the directories following must be under root. -root = "." -tmp_dir = "tmp" - -[build] -# Just plain old shell command. You could use `make` as well. -cmd = "true" -# Binary file yields from `cmd`. -full_bin = "go test ./..." -# Customize binary. -# Watch these filename extensions. -include_ext = ["go", "tpl", "tmpl", "html"] -# Ignore these filename extensions or directories. -exclude_dir = ["assets", "tmp", "vendor", "node_modules", "webapp", "examples"] -# Watch these directories if you specified. -include_dir = [] -# Exclude files. -exclude_file = [] -# It's not necessary to trigger build each time file changes if it's too frequent. -delay = 1000 # ms -# Stop to run old binary when build errors occur. -stop_on_error = true -# This log file places in your tmp_dir. -log = "air_errors.log" - -[log] -# Show log time -time = false - -[color] -# Customize each part's color. If no color found, use the raw app log. -main = "magenta" -watcher = "cyan" -build = "yellow" -runner = "green" - -[misc] -# Delete tmp directory on exit -# clean_on_exit = true diff --git a/og/.air.conf b/og/.air.conf deleted file mode 100644 index dea404541f..0000000000 --- a/og/.air.conf +++ /dev/null @@ -1,48 +0,0 @@ -# .air.conf -# Config file for [Air](https://github.com/cosmtrek/air) in TOML format - -# Working directory -# . or absolute path, please note that the directories following must be under root. -root = "." -tmp_dir = "tmp" - -[build] -# Just plain old shell command. You could use `make` as well. -cmd = "make build" -# Binary file yields from `cmd`. -full_bin = "make server" -# Customize binary. -# Watch these filename extensions. -include_ext = ["go", "tpl", "tmpl", "html"] -# Ignore these filename extensions or directories. -exclude_dir = ["packages", "hacks", "monitoring", "assets", "tmp", "vendor", "node_modules", "webapp", "examples", "third_party", "coverage", "benchmark", "cypress"] -# Watch these directories if you specified. -include_dir = [] -# Exclude files. -exclude_file = [] -# It's not necessary to trigger build each time file changes if it's too frequent. -delay = 1000 # ms - -send_interrupt = true - -kill_delay = 2000000000 # ns - -# Stop to run old binary when build errors occur. -stop_on_error = true -# This log file places in your tmp_dir. -log = "air_errors.log" - -[log] -# Show log time -time = false - -[color] -# Customize each part's color. If no color found, use the raw app log. -main = "magenta" -watcher = "cyan" -build = "yellow" -runner = "green" - -[misc] -# Delete tmp directory on exit -# clean_on_exit = true diff --git a/og/.devcontainer/Dockerfile b/og/.devcontainer/Dockerfile deleted file mode 100644 index 04c45d971f..0000000000 --- a/og/.devcontainer/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM mcr.microsoft.com/vscode/devcontainers/go:1.17 - -USER root - -# Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -RUN /root/.cargo/bin/rustup target add $(uname -m)-unknown-linux-musl - -# PHP -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends php php-dev - -# Node -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends nodejs npm -RUN npm config set unsafe-perm true -RUN npm install -g yarn - -# libunwind -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends libunwind8-dev - -WORKDIR /workspaces/pyroscope - -USER vscode diff --git a/og/.devcontainer/devcontainer.json b/og/.devcontainer/devcontainer.json deleted file mode 100644 index 26e38ea04d..0000000000 --- a/og/.devcontainer/devcontainer.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "build": { "dockerfile": "Dockerfile" }, - "extensions": ["golang.go"], - "forwardPorts": [4040] -} diff --git a/og/.dockerignore b/og/.dockerignore deleted file mode 100644 index 55435ca03f..0000000000 --- a/og/.dockerignore +++ /dev/null @@ -1,20 +0,0 @@ -target -third_party/*/target -webapp/public/* -node_modules -.git/ -tmp - -benchmark/Dockerfile -benchmark/runs -benchmark/docker-compose.yml -benchmark/grafana-* -benchmark/node_modules -benchmark/*.env - -third_party/bcc/lib -third_party/bcc/src -third_party/libbpf/lib -third_party/libbpf/src -pkg/agent/ebpfspy/bpf/profile.bpf.o -pkg/agent/ebpfspy/bpf/vmlinux.h diff --git a/og/.eslintignore b/og/.eslintignore deleted file mode 100644 index a91bfb427c..0000000000 --- a/og/.eslintignore +++ /dev/null @@ -1,11 +0,0 @@ -/webapp/public/** -/webapp/javascript/util/** -/webapp/__tests__/** -/benchmark/** -scripts/** -dist -.eslintrc.js -stories -setupAfterEnv.ts -jest.config.js -cypress diff --git a/og/.eslintrc.js.notactive b/og/.eslintrc.js.notactive deleted file mode 100644 index 16e6d8e508..0000000000 --- a/og/.eslintrc.js.notactive +++ /dev/null @@ -1,151 +0,0 @@ -const path = require('path'); - -module.exports = { - plugins: ['@typescript-eslint', 'css-modules'], - extends: [ - 'airbnb-typescript-prettier', - 'plugin:cypress/recommended', - 'plugin:import/typescript', - 'plugin:css-modules/recommended', - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - rules: { - '@typescript-eslint/no-shadow': 'warn', - - // https://stackoverflow.com/questions/63818415/react-was-used-before-it-was-defined/64024916#64024916 - '@typescript-eslint/no-use-before-define': ['off'], - - // react functional components are usually written using PascalCase - '@typescript-eslint/naming-convention': [ - 'warn', - { selector: 'function', format: ['PascalCase', 'camelCase'] }, - ], - '@typescript-eslint/no-empty-function': 'warn', - '@typescript-eslint/no-var-requires': 'warn', - 'react-hooks/exhaustive-deps': 'warn', - - 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], - 'no-param-reassign': ['warn'], - 'no-case-declarations': ['warn'], - 'no-restricted-globals': ['warn'], - 'react/button-has-type': ['warn'], - 'react/prop-types': ['off'], - 'jsx-a11y/heading-has-content': ['warn'], - 'jsx-a11y/control-has-associated-label': ['warn'], - 'no-undef': ['warn'], - 'jsx-a11y/mouse-events-have-key-events': ['warn'], - 'jsx-a11y/click-events-have-key-events': ['warn'], - 'jsx-a11y/no-static-element-interactions': ['warn'], - 'jsx-a11y/label-has-associated-control': [ - 'error', - { - required: { - some: ['nesting', 'id'], - }, - }, - ], - 'react/jsx-filename-extension': [1, { extensions: ['.tsx', '.ts'] }], - 'import/extensions': [ - 'error', - 'always', - { - js: 'never', - jsx: 'never', - ts: 'never', - tsx: 'never', - }, - ], - 'spaced-comment': [2, 'always', { exceptions: ['*'] }], - 'react/require-default-props': 'off', - - 'import/no-extraneous-dependencies': [ - 'error', - { - devDependencies: [ - '**/*.spec.jsx', - '**/*.spec.ts', - '**/*.spec.tsx', - '**/*.stories.tsx', - ], - packageDir: [ - // TODO compute this dynamically - path.resolve(__dirname, 'packages/pyroscope-flamegraph'), - process.cwd(), - ], - }, - ], - // otherwise it conflincts with ts411 - 'dot-notation': 'off', - - // disable relative imports to force people to use '@webapp' - 'import/no-relative-packages': 'error', - - // https://humanwhocodes.com/blog/2019/01/stop-using-default-exports-javascript-module/ - 'import/prefer-default-export': 'off', - - '@typescript-eslint/no-unused-vars': [ - 'error', - { - ignoreRestSiblings: true, - }, - ], - - // any is bad, if really necessary one can use ShamefulAny - '@typescript-eslint/no-explicit-any': 'error', - - // ATM there's too many errors to deal with right now - // TODO: deal with each issue individually - '@typescript-eslint/no-unsafe-member-access': 'warn', - '@typescript-eslint/no-unsafe-argument': 'warn', - '@typescript-eslint/no-unsafe-call': 'warn', - '@typescript-eslint/no-unsafe-assignment': 'warn', - '@typescript-eslint/no-unsafe-return': 'warn', - '@typescript-eslint/restrict-template-expressions': 'warn', - - // https://github.com/typescript-eslint/typescript-eslint/issues/1184 - '@typescript-eslint/no-floating-promises': ['warn', { ignoreVoid: true }], - - // makes it easier to check what are local variables computated dynamically and what are static props - 'react/destructuring-assignment': 'off', - - '@typescript-eslint/switch-exhaustiveness-check': 'error', - }, - env: { - browser: true, - jquery: true, - }, - settings: { - 'import/internal-regex': '^@pyroscope', - 'import/resolver': { - 'eslint-import-resolver-lerna': { - packages: path.resolve(__dirname, 'packages'), - }, - typescript: { - project: 'tsconfig.json', - }, - }, - }, - overrides: [ - // Tests are completely different - // And we shouldn't be so strict - { - files: ['**/?(*.)+(spec|test).+(ts|tsx|js)'], - plugins: ['jest'], - env: { - node: true, - 'jest/globals': true, - }, - }, - ], - ignorePatterns: ['dist', 'public'], - globals: { - // see ./lib/alias.d.ts - ShamefulAny: true, - JSX: true, - }, - parserOptions: { - project: ['./tsconfig.json'], - }, -}; diff --git a/og/.github/auto-label.json b/og/.github/auto-label.json deleted file mode 100644 index 7cdb9270a4..0000000000 --- a/og/.github/auto-label.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "rules": { - "frontend": ["webapp/"], - "backend": ["*.go"] - } -} diff --git a/og/.github/cloud-compatibility-check.rb b/og/.github/cloud-compatibility-check.rb deleted file mode 100755 index f6e090aa06..0000000000 --- a/og/.github/cloud-compatibility-check.rb +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env ruby - -require 'json' - -# system "curl \ -# --silent \ -# -H \"Accept: application/vnd.github+json\" \ -# -H \"Authorization: Bearer #{ENV["GITHUB_TOKEN"]}\" \ -# https://api.github.com/repos/pyroscope-io/cloudstorage/actions/workflows/34992245/runs" - -latest_run = JSON.parse(`curl \ - --silent \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer #{ENV["GITHUB_TOKEN"]}" \ - https://api.github.com/repos/pyroscope-io/cloudstorage/actions/workflows/34992245/runs`)["workflow_runs"][0] - -puts "latest run: #{latest_run ? latest_run["id"] : "none"}" - - -puts "triggering a run" -system "curl \ --X POST \ --H \"Accept: application/vnd.github+json\" \ --H \"Authorization: Bearer #{ENV["GITHUB_TOKEN"]}\" \ -https://api.github.com/repos/pyroscope-io/cloudstorage/actions/workflows/34992245/dispatches \ --d '{\"ref\":\"main\",\"inputs\":{\"gitRef\":\"#{ENV["HEAD_REF"] || "main"}\"}'" - -# TODO: this logic is prone to race conditions, consider improving -run_id = nil -10.times do - runs = JSON.parse(`curl \ - --silent \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer #{ENV["GITHUB_TOKEN"]}" \ - https://api.github.com/repos/pyroscope-io/cloudstorage/actions/workflows/34992245/runs`)["workflow_runs"] - - run = runs.find { |r| latest_run.nil? || r["created_at"] > latest_run["created_at"] } - if run - run_id = run["id"] - break - end -end - -raise "could not find run" unless run_id - -puts "current run_id: #{run_id}" - -60.times do - status=JSON.parse(`curl \ - --silent \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer #{ENV["GITHUB_TOKEN"]}" \ - https://api.github.com/repos/pyroscope-io/cloudstorage/actions/runs/#{run_id}`)["status"] - - puts "status: #{status}" - break if status == "completed" - sleep 10 -end - -run = JSON.parse(`curl \ ---silent \ --H "Accept: application/vnd.github+json" \ --H "Authorization: Bearer #{ENV["GITHUB_TOKEN"]}" \ -https://api.github.com/repos/pyroscope-io/cloudstorage/actions/runs/#{run_id}`) - -conclusion=run["conclusion"] - -puts "conclusion: #{conclusion}" - -puts "" -puts "---" -puts "" - -if conclusion != "success" - puts "This version of pyroscope OSS is not compatible with downstream Pyroscope Cloud project" - puts "Go to https://github.com/pyroscope-io/cloudstorage/actions/runs/#{run_id} for more information" - # exit 1 -end diff --git a/og/.github/markdown-images/join-us-on-slack.svg b/og/.github/markdown-images/join-us-on-slack.svg deleted file mode 100644 index 45a6016c97..0000000000 --- a/og/.github/markdown-images/join-us-on-slack.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/og/.github/markdown-images/schedule-setup-call.svg b/og/.github/markdown-images/schedule-setup-call.svg deleted file mode 100644 index 57240dc7a2..0000000000 --- a/og/.github/markdown-images/schedule-setup-call.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - background - - - - Layer 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Schedule a set up - call - - diff --git a/og/.github/reviewers.yml b/og/.github/reviewers.yml deleted file mode 100644 index 4b77196de0..0000000000 --- a/og/.github/reviewers.yml +++ /dev/null @@ -1,35 +0,0 @@ -# For docs on this see https://github.com/marketplace/actions/auto-request-review#reviewers-configuration -reviewers: - # The default reviewers - defaults: - - repository-owners - - # Reviewer groups each of which has a list of GitHub usernames - groups: - repository-owners: - - petethepig - - Rperry2174 - go-experts: - - petethepig - js-experts: - - Rperry2174 - -files: - # Keys are glob expressions. - # You can assign groups defined above as well as GitHub usernames. - '**': - - repository-owners # group - '**/*.go': - - go-experts - 'webapp/**': - - js-experts - -options: - ignore_draft: true - ignored_keywords: - - DO NOT REVIEW - enable_group_assignment: false - - # Randomly pick reviewers up to this number. - # Do not set this option if you'd like to assign all matching reviewers. - # number_of_reviewers: 2 diff --git a/og/.github/workflows/auto-label.yml b/og/.github/workflows/auto-label.yml deleted file mode 100644 index 0a948c2e3f..0000000000 --- a/og/.github/workflows/auto-label.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Auto Label -on: - pull_request_target: - types: [opened, synchronize] - -jobs: - auto-label: - name: Auto Label - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - ref: ${{github.event.pull_request.head.ref}} - repository: ${{github.event.pull_request.head.repo.full_name}} - - uses: banyan/auto-label@1.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/og/.github/workflows/auto-request-review.yml b/og/.github/workflows/auto-request-review.yml deleted file mode 100644 index 181be80c40..0000000000 --- a/og/.github/workflows/auto-request-review.yml +++ /dev/null @@ -1,17 +0,0 @@ -# For docs on this see https://github.com/marketplace/actions/auto-request-review#workflow-configuration -name: Auto Request Review - -on: - pull_request_target: - types: [opened, ready_for_review, reopened] - -jobs: - auto-request-review: - name: Auto Request Review - runs-on: ubuntu-latest - steps: - - name: Request review based on files changes and/or groups the author belongs to - uses: necojackarc/auto-request-review@v0.4.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - config: .github/reviewers.yml # Config file location override diff --git a/og/.github/workflows/brew-publish.yml b/og/.github/workflows/brew-publish.yml deleted file mode 100644 index ae783a3780..0000000000 --- a/og/.github/workflows/brew-publish.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Homebrew -on: - workflow_dispatch: -jobs: - test: - runs-on: macos-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Update Homebrew formulae - uses: dawidd6/action-homebrew-bump-formula@v3 - with: - org: pyroscope - token: ${{ secrets.GITHUB_HOMEBREW_TOKEN }} - tap: homebrew/core - formula: pyroscope - tag: ${{ github.ref }} - revision: ${{ github.sha }} diff --git a/og/.github/workflows/build-docker.yml b/og/.github/workflows/build-docker.yml deleted file mode 100644 index 923b4a0d75..0000000000 --- a/og/.github/workflows/build-docker.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Build docker - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - docker: - runs-on: ubuntu-latest - steps: - - name: Build and push - uses: docker/build-push-action@v3 - with: - platforms: linux/amd64 - push: false diff --git a/og/.github/workflows/ci-profiling.yaml b/og/.github/workflows/ci-profiling.yaml deleted file mode 100644 index da60bb55f7..0000000000 --- a/og/.github/workflows/ci-profiling.yaml +++ /dev/null @@ -1,95 +0,0 @@ -name: CI Profiling - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - check: - runs-on: ubuntu-latest - outputs: - inputsChecked: ${{ steps.pyroscope_cloud_token_gate.outputs.inputsChecked }} - steps: - - uses: svrooij/secret-gate-action@v1 - id: pyroscope_cloud_token_gate - with: - inputsToCheck: 'token' - env: - token: ${{ secrets.PYROSCOPE_CLOUD_TOKEN }} - go-tests: - runs-on: ubuntu-latest - # skip if user has not access to the token - if: needs.check.outputs.inputsChecked == 'true' - needs: check - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '^1.18.0' - - name: Cache go mod directories - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Install go-task - uses: jaxxstorm/action-install-gh-release@v1.5.0 - with: - repo: pyroscope-io/ci - tag: latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: install - run: pyroscope-ci go install --applicationName=pyroscope-oss pkg/ - - name: uninstall from gospy since profiler is already running - run: rm pkg/agent/gospy/pyroscope_test.go - - name: Run Go tests and upload - run: pyroscope-ci exec --exportLocally --apiKey=${{ secrets.PYROSCOPE_CLOUD_TOKEN }} make test - - uses: pyroscope-io/flamegraph.com-github-action@main - with: - file: pyroscope-ci-output/* - postInPR: true - token: ${{ github.token }} - id: go-tests - js-tests: - runs-on: ubuntu-latest - # skip if user has not access to the token - if: needs.check.outputs.inputsChecked == 'true' - needs: check - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - name: Install go-task - uses: jaxxstorm/action-install-gh-release@v1.5.0 - with: - repo: pyroscope-io/ci - tag: latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Install Webapp dependencies - run: yarn install --frozen-lockfile - - name: Run tests and upload - run: pyroscope-ci exec --apiKey=${{ secrets.PYROSCOPE_CLOUD_TOKEN }} --exportLocally yarn test --no-cache --max-workers=1 - - uses: pyroscope-io/flamegraph.com-github-action@main - with: - file: pyroscope-ci-output/* - postInPR: true - token: ${{ github.token }} diff --git a/og/.github/workflows/cloud-compability-check.yml b/og/.github/workflows/cloud-compability-check.yml deleted file mode 100644 index 98dde893a1..0000000000 --- a/og/.github/workflows/cloud-compability-check.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Cloud Compatibility Check - -on: - push: - branches: [main] - -jobs: - cloud_compability_check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: cloud-compatibility-check - run: .github/cloud-compatibility-check.rb - env: - GITHUB_TOKEN: ${{ secrets.CLOUD_COMPAT_CHECK_GITHUB_TOKEN }} - HEAD_REF: ${{ github.head_ref || github.ref_name }} diff --git a/og/.github/workflows/conflicts.yml b/og/.github/workflows/conflicts.yml deleted file mode 100644 index c6ef2a320b..0000000000 --- a/og/.github/workflows/conflicts.yml +++ /dev/null @@ -1,15 +0,0 @@ -on: - push: - branches: - - main -jobs: - triage: - runs-on: ubuntu-latest - steps: - - name: Auto-label merge conflicts - uses: mschilde/auto-label-merge-conflicts@v2.0 - with: - CONFLICT_LABEL_NAME: 'has conflicts' - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - MAX_RETRIES: 5 - WAIT_MS: 5000 diff --git a/og/.github/workflows/cypress-tests.yml b/og/.github/workflows/cypress-tests.yml deleted file mode 100644 index 5200213f64..0000000000 --- a/og/.github/workflows/cypress-tests.yml +++ /dev/null @@ -1,215 +0,0 @@ -name: Cypress Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - cypress-tests: - runs-on: ubuntu-latest - env: - ENABLED_SPIES: none - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - uses: actions/setup-go@v2 - with: - go-version: '^1.19.0' - - name: Cache go mod directories - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - run: yarn install --frozen-lockfile - - run: make --version - - run: make -j e2e-build - - name: Cypress run - uses: cypress-io/github-action@v4 - with: - wait-on: http://localhost:4040 - start: make server - config-file: cypress/cypress.json - env: - # keep the server quiet - PYROSCOPE_LOG_LEVEL: error - ENABLED_SPIES: none - - uses: actions/upload-artifact@v2 - if: always() - with: - name: cypress-screenshots - path: cypress/screenshots - - cypress-tests-auth: - runs-on: ubuntu-latest - env: - ENABLED_SPIES: none - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '^1.19.0' - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Cache go mod directories - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - run: yarn install --frozen-lockfile - - run: make -j e2e-build - - name: Cypress run - uses: cypress-io/github-action@v4 - with: - wait-on: http://localhost:4040 - start: | - node ./scripts/oauth-mock/oauth-mock.js - make server SERVERPARAMS=--config=scripts/oauth-mock/pyroscope-config.yml - config-file: cypress/integration/auth/cypress.json - env: - # keep the server quiet - PYROSCOPE_LOG_LEVEL: error - ENABLED_SPIES: none - - uses: actions/upload-artifact@v2 - if: always() - with: - name: cypress-screenshots - path: cypress/screenshots - - cypress-tests-base-url: - runs-on: ubuntu-latest - env: - ENABLED_SPIES: none - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '^1.19.0' - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Cache go mod directories - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - run: yarn install --frozen-lockfile - - run: make -j e2e-build - - name: run nginx with /pyroscope - run: docker-compose -f cypress/base-url/base-url-docker-compose.yml up -d - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - wait-on: http://localhost:8080/pyroscope - start: make server - config-file: cypress/base-url/cypress.json - env: - # keep the server quiet - PYROSCOPE_BASE_URL: 'http://localhost:8080/pyroscope' - PYROSCOPE_LOG_LEVEL: error - - uses: actions/upload-artifact@v2 - if: always() - with: - name: cypress-screenshots - path: cypress/screenshots - - # Test auth when baseUrl is set - # We run the same tests from auth - # But with a different CYPRESS_BASE_URL - cypress-tests-base-url-auth: - runs-on: ubuntu-latest - env: - ENABLED_SPIES: none - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '^1.19.0' - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Cache go mod directories - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - run: yarn install --frozen-lockfile - - run: make -j e2e-build - - name: run nginx with /pyroscope - run: docker-compose -f cypress/base-url/base-url-docker-compose.yml up -d - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - wait-on: http://localhost:8080/pyroscope - start: | - node ./scripts/oauth-mock/oauth-mock.js - make server SERVERPARAMS=--config=scripts/oauth-mock/pyroscope-config-base-url.yml - config-file: cypress/integration/auth/cypress.json - env: - PYROSCOPE_BASE_URL: 'http://localhost:8080/pyroscope' - PYROSCOPE_LOG_LEVEL: error - CYPRESS_BASE_URL: 'http://localhost:8080/pyroscope' - - uses: actions/upload-artifact@v2 - if: always() - with: - name: cypress-screenshots - path: cypress/screenshots diff --git a/og/.github/workflows/fix-conflicts.yml b/og/.github/workflows/fix-conflicts.yml deleted file mode 100644 index 717b933bac..0000000000 --- a/og/.github/workflows/fix-conflicts.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Solve conflicts - -on: workflow_dispatch -# TODO: when we confirm this works well we should uncomment this -# on: -# pull_request: -# types: -# - synchronize -# - labeled - -jobs: - fix-conflicts: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '^1.19.0' - - name: Resolves merge conflicts - if: github.event.label.name == "has conflicts" - run: | - git config user.name "Pyroscope Bot" - git config user.email "dmitry+bot@pyroscope.io" - files=(`git diff --name-only --diff-filter=U -- yarn.lock go.sum`) - if [ ${#files[@]} -ge 1 ];then - git checkout origin/main -- "$files" - if echo $files | grep -o yarn.lock &> /dev/null; then - yarn - fi - if echo $files | grep -o go.sum &> /dev/null; then - go mod tidy - fi - git add "$files" - git commit -m "resolves merge conflict" - git push - fi diff --git a/og/.github/workflows/lint-general.yml b/og/.github/workflows/lint-general.yml deleted file mode 100644 index 04267bc2f8..0000000000 --- a/og/.github/workflows/lint-general.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: General Linting - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - general-lint: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Linelint - uses: fernandrone/linelint@0.0.4 - - name: Find Trailing Whitespace In Markdown - uses: ocular-d/trailing-spaces@0.0.2 diff --git a/og/.github/workflows/lint-go.yml b/og/.github/workflows/lint-go.yml deleted file mode 100644 index cfc9bbff8e..0000000000 --- a/og/.github/workflows/lint-go.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Go Linting - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - go-lint: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '^1.19.0' - - name: Run revive action - uses: korniltsev/revive-action@v6 - with: - config: revive.toml - # same as in the `lint` rule of Makefile - exclude: 'examples/...;vendor/...;./pkg/agent/pprof/...' diff --git a/og/.github/workflows/lint-js.yml b/og/.github/workflows/lint-js.yml deleted file mode 100644 index 35c5c7e3b1..0000000000 --- a/og/.github/workflows/lint-js.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: JS Lint - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - js-lint: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - - name: Install Webapp dependencies - run: yarn install --frozen-lockfile - - run: yarn build - - name: Run Format check - run: yarn format:check - - name: Run Lint - # Use use --quiet so that it only report errors - run: yarn lint:quiet - - - name: Run Type check - run: yarn type-check diff --git a/og/.github/workflows/lint-markdown.yml b/og/.github/workflows/lint-markdown.yml deleted file mode 100644 index 06ad2001ab..0000000000 --- a/og/.github/workflows/lint-markdown.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Markdown Linting - -# runs every monday at 9 am -on: - schedule: - - cron: '0 9 * * 1' - -jobs: - markdown-lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: gaurav-nelson/github-action-markdown-link-check@v1 - with: - config-file: .github/workflows/markdown-links-config.json diff --git a/og/.github/workflows/markdown-links-config.json b/og/.github/workflows/markdown-links-config.json deleted file mode 100644 index 66df9a4ad5..0000000000 --- a/og/.github/workflows/markdown-links-config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": "^https://github.com/pyroscope-io/pyroscope/issues/" - }, - { - "pattern": "^https://github.com/pyroscope-io/pyroscope/commit/" - }, - { - "pattern": "^http://localhost" - } - ] -} diff --git a/og/.github/workflows/max-size-check.yml b/og/.github/workflows/max-size-check.yml deleted file mode 100644 index 9faf14c724..0000000000 --- a/og/.github/workflows/max-size-check.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Max File Size Check - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - max-file-check: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actionsdesk/lfs-warning@v2.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - filesizelimit: '2097152' # 2 MB diff --git a/og/.github/workflows/publish-lib-to-npm.yml b/og/.github/workflows/publish-lib-to-npm.yml deleted file mode 100644 index 16f3962038..0000000000 --- a/og/.github/workflows/publish-lib-to-npm.yml +++ /dev/null @@ -1,133 +0,0 @@ -name: Publish packages to npmjs - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - check: - runs-on: ubuntu-latest - outputs: - inputsChecked: ${{ steps.github_token_gate.outputs.inputsChecked }} - steps: - - uses: svrooij/secret-gate-action@v1 - id: github_token_gate - with: - inputsToCheck: 'token' - env: - token: ${{ secrets.BOT_GITHUB_TOKEN }} - build: - # skip if user has not access to the token - if: needs.check.outputs.inputsChecked == 'true' - runs-on: ubuntu-latest - needs: check - steps: - ####################### - # Checkout # - ###################### - # For non-pull requests, fetch all tags - - uses: actions/checkout@v2 - if: github.event_name != 'pull_request' - with: - fetch-depth: 0 - token: ${{ secrets.BOT_GITHUB_TOKEN }} - # For pull requests, also checkout out the REAL commit (as opposed to a merge commit with main) - - uses: actions/checkout@v2 - if: github.event_name == 'pull_request' - # For PRs check the actual commit - # https://github.com/actions/checkout/issues/124#issuecomment-586664611 - # https://github.com/actions/checkout/issues/455#issuecomment-792228083 - with: - fetch-depth: 0 - token: ${{ secrets.BOT_GITHUB_TOKEN }} - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{github.event.pull_request.head.repo.full_name}} - - # pull all tags since they are required when generating locally - # https://github.com/lerna/lerna/issues/2542 - - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - if: github.event_name == 'pull_request' - - # Setup .npmrc file to publish to npm - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - registry-url: 'https://registry.npmjs.org' - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: Prepare - id: prep - run: | - TAG=$(echo $GITHUB_SHA | head -c7) - echo ::set-output name=tag::${TAG} - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - - name: Install Webapp dependencies - run: yarn install --frozen-lockfile - - # This step will bump the package.json version and NOT push to the repository - # this is needed since building grafana requires updating the plugin.json file - # with the package.json version - - name: Bump version, generate changelog etc - if: github.event_name == 'pull_request' - run: | - # Copied from https://github.com/pyroscope-io/pyroscope/blob/main/.github/workflows/update-contributors.yml#L23-L28 - git config --global user.email "dmitry+bot@pyroscope.io" - git config --global user.name "Pyroscope Bot " - yarn run lerna version --conventional-commits --conventional-prerelease --yes --no-push --preid=${{ github.event.pull_request.number }}-${{ steps.prep.outputs.tag }} - - # This step will bump the package.json version, generate a CHANGELOG.md - # And commit to the repository - - name: Bump version, generate changelog etc - if: github.event_name != 'pull_request' - run: | - # Copied from https://github.com/pyroscope-io/pyroscope/blob/main/.github/workflows/update-contributors.yml#L23-L28 - git config --global user.email "dmitry+bot@pyroscope.io" - git config --global user.name "Pyroscope Bot " - yarn run lerna version --conventional-commits --yes - env: - GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} - - # build all packages - - name: Build - run: yarn run lerna run build - - ##################### - # Publish # - ##################### - - name: Publish Main - if: github.event_name != 'pull_request' - run: | - yarn run lerna publish from-package \ - --skip-git \ - --conventional-commits \ - --yes \ - --no-verify-access - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Publish Pull Request - # Only publish if it comes from the main repo - if: (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.repository) - run: | - yarn run lerna publish from-git \ - --skip-git \ - --conventional-commits \ - --yes \ - --no-verify-access \ - --force-publish='*' \ - --canary - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/og/.github/workflows/size-limit.yml b/og/.github/workflows/size-limit.yml deleted file mode 100644 index b50b71a43b..0000000000 --- a/og/.github/workflows/size-limit.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Size Limit Checks - -on: - pull_request: - branches: [main] - -jobs: - size-check: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Install Webapp dependencies - run: yarn install --frozen-lockfile - - uses: andresz1/size-limit-action@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - build_script: build:size-limit diff --git a/og/.github/workflows/storybook.yml b/og/.github/workflows/storybook.yml deleted file mode 100644 index ad7f2abb00..0000000000 --- a/og/.github/workflows/storybook.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Storybook - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - js-tests: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - - name: Install Webapp dependencies - run: yarn install --frozen-lockfile - - run: yarn build - - run: yarn build-storybook - - # TODO: ideally we would able to view the index.html easily - # https://github.com/actions/upload-artifact/issues/14 - - uses: actions/upload-artifact@v3 - with: - name: storybook - path: storybook-static/ diff --git a/og/.github/workflows/tests-go.yml b/og/.github/workflows/tests-go.yml deleted file mode 100644 index c8e6377cc6..0000000000 --- a/og/.github/workflows/tests-go.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Go Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - go-tests: - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: '^1.19.0' - - name: Cache go mod directories - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: install dev-tools - run: make install-dev-tools - - name: Ensure logrus is not used by pkg/agent/profiler - run: make ensure-logrus-not-used - - name: Run Go tests - run: make coverage - - name: Upload codecov coverage - uses: codecov/codecov-action@v1 - with: - fail_ci_if_error: false - verbose: true diff --git a/og/.github/workflows/tests-js-snapshot.yml b/og/.github/workflows/tests-js-snapshot.yml deleted file mode 100644 index 7da012d1aa..0000000000 --- a/og/.github/workflows/tests-js-snapshot.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: JS Snapshot Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - js-snapshot-tests: - runs-on: ubuntu-latest - # ATTENTION - # if you ever update this container - # remember to update the container that runs locally - # (ie ./scripts/jest-snapshots) - container: node:16.18-slim - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Run Webapp Snapshot tests - run: UPDATE_SNAPSHOTS=false ./scripts/jest-snapshots/run-snapshots.sh - # since there are snapshot tests (for the flamegraph) - # store their diff when it fails, plus the original image - # to make it easier to compare - - uses: actions/upload-artifact@v2 - if: failure() - with: - name: image-snapshots - path: '**/__image_snapshots__/*' - - name: Upload codecov coverage - if: always() - uses: codecov/codecov-action@v1 - with: - name: js coverage - fail_ci_if_error: false - verbose: true diff --git a/og/.github/workflows/tests-js.yml b/og/.github/workflows/tests-js.yml deleted file mode 100644 index 2a2d5b0572..0000000000 --- a/og/.github/workflows/tests-js.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: JS Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - js-tests: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - uses: actions/cache@v2 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn - - - name: Install Webapp dependencies - run: yarn install --frozen-lockfile - - name: Get number of CPU cores - id: cpu-cores - uses: SimenB/github-actions-cpu-cores@v1 - - name: Run Webapp tests - run: yarn run test --coverage --max-workers ${{ steps.cpu-cores.outputs.count }} - - name: Upload codecov coverage - if: always() - uses: codecov/codecov-action@v1 - with: - name: js coverage - fail_ci_if_error: false - verbose: true diff --git a/og/.github/workflows/update-contributors.yml b/og/.github/workflows/update-contributors.yml deleted file mode 100644 index e9a4ba927b..0000000000 --- a/og/.github/workflows/update-contributors.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Update Contributors in README - -on: - push: - branches: [main] - -jobs: - update-contributors: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - token: ${{ secrets.BOT_GITHUB_TOKEN }} - - uses: actions/setup-node@v2 - with: - node-version: '16.18' - - name: Install dependencies - run: make install-web-dependencies - - - name: Update contributors - run: make update-contributors - - - uses: stefanzweifel/git-auto-commit-action@v4 - with: - # these are credentials for https://github.com/pyroscopebot - token: ${{ secrets.BOT_GITHUB_TOKEN }} - commit_user_name: Pyroscope Bot - commit_user_email: dmitry+bot@pyroscope.io - commit_author: 'Pyroscope Bot ' - commit_message: 'docs: updates the list of contributors in README' - file_pattern: README.md - env: - GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} diff --git a/og/.gitignore b/og/.gitignore deleted file mode 100644 index c2d9213b0c..0000000000 --- a/og/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -tmp -node_modules -/webapp/public -/bin -/third_party/*/lib*.a -/third_party/*/target -/third_party/phpspy_src -.DS_Store -/Icon* -/out/ -/scripts/packages/ -.eslintcache -*.pyc -*.internal -*.syso -*.exe -.idea -.vscode -vendor/ -benchmark/.env -benchmark/report -benchmark/fixtures -/.env -# diff output is stored per test -cypress/snapshots/**/__diff_output__ -cypress/videos -cypress/screenshots -coverage -# this file may contain sensitive credentials -pkg/server/testdata/oauth-config.yml -dist diff --git a/og/.husky/.gitignore b/og/.husky/.gitignore deleted file mode 100644 index 31354ec138..0000000000 --- a/og/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/og/.husky/pre-commit b/og/.husky/pre-commit deleted file mode 100755 index f23377e959..0000000000 --- a/og/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -yarn run lint-staged diff --git a/og/.linelint.yml b/og/.linelint.yml deleted file mode 100644 index eb0415cd12..0000000000 --- a/og/.linelint.yml +++ /dev/null @@ -1,32 +0,0 @@ ---- -# 'true' will fix files -autofix: false - -# list of paths to ignore, uses gitignore syntaxes (executes before any rule) -ignore: - - .git/ - - tmp/ - - node_modules/ - - /webapp/public - - /third_party/*/target - - pkged.go - - .DS_Store - - /scripts/packages/ - - .eslintcache - - .idea - - .vscode - - vendor/ - - examples/dotnet - - .github/markdown-images - - testdata/ - - examples/ruby/rideshare_rails - - '**/.keep' - -rules: - # checks if file ends in a newline character - end-of-file: - # set to true to enable this rule - enable: true - - # if true also checks if file ends in a single newline character - single-new-line: false diff --git a/og/.nvmrc b/og/.nvmrc deleted file mode 100644 index 50e4b92aeb..0000000000 --- a/og/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v16.18.0 diff --git a/og/.prettierignore b/og/.prettierignore deleted file mode 100644 index 97f1046d98..0000000000 --- a/og/.prettierignore +++ /dev/null @@ -1,10 +0,0 @@ -webapp/public -dist -third_party -*.md -monitoring/gen/* -.prettierignore -coverage -*.html -lerna.json -examples/* diff --git a/og/.prettierrc b/og/.prettierrc deleted file mode 100644 index 637787883f..0000000000 --- a/og/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -{ "singleQuote": true } diff --git a/og/.size-limit.js b/og/.size-limit.js deleted file mode 100644 index 39580c515b..0000000000 --- a/og/.size-limit.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = [ - { - path: ['webapp/public/assets/app.js'], - // ugly - limit: '300000ms', - }, - { - path: ['webapp/public/assets/app.css'], - }, - { - path: ['webapp/public/assets/styles.css'], - }, - { - path: ['packages/pyroscope-flamegraph/dist/index.js'], - }, - { - path: ['packages/pyroscope-flamegraph/dist/index.node.js'], - }, - { - path: ['packages/pyroscope-flamegraph/dist/index.css'], - }, -]; diff --git a/og/.tool-versions b/og/.tool-versions deleted file mode 100644 index c58772bb9a..0000000000 --- a/og/.tool-versions +++ /dev/null @@ -1,2 +0,0 @@ -nodejs 16.18.0 -golang 1.19 diff --git a/og/Makefile b/og/Makefile deleted file mode 100644 index 602d63676f..0000000000 --- a/og/Makefile +++ /dev/null @@ -1,289 +0,0 @@ -GOBUILD=go build -trimpath - -ARCH ?= $(shell uname -m) -OS ?= $(shell uname) - - -# if you change the name of this variable please change it in generate-git-info.sh file -PHPSPY_VERSION ?= 66b6fdb2f9da1d87912b46b7faf68796d471c209 - -ifeq ("$(OS)", "Darwin") - ifeq ("$(ARCH)", "arm64") -# on a mac it's called arm64 which rust doesn't know about -# see https://unix.stackexchange.com/questions/461179/what-is-the-difference-between-different-implemetation-of-arm64-aarch64-for-linu - ARCH=aarch64 -# this makes it work better on M1 machines - GODEBUG=asyncpreemptoff=1 - endif -endif - -ALL_SPIES = ebpfspy,dotnetspy,phpspy,debugspy -ifeq ("$(OS)", "Linux") - ENABLED_SPIES_RELEASE ?= ebpfspy,phpspy,dotnetspy -else - ENABLED_SPIES_RELEASE ?= dotnetspy -endif -ENABLED_SPIES ?= none - -ifeq ("$(OS)", "Linux") - THIRD_PARTY_DEPENDENCIES ?= "build-phpspy-dependencies" -else - THIRD_PARTY_DEPENDENCIES ?= "" -endif - -EXTRA_GO_TAGS ?= -CGO_CFLAGS ?= -CGO_LDFLAGS ?= -EXTRA_CGO_CFLAGS ?= -EXTRA_CGO_LDFLAGS ?= -GO_TAGS = $(ENABLED_SPIES)$(EXTRA_GO_TAGS) -ALPINE_TAG = - -ifneq (,$(findstring ebpfspy,$(GO_TAGS))) - EXTRA_CGO_CFLAGS := $(EXTRA_CGO_CFLAGS) -I$(abspath ./third_party/libbpf/lib/include) \ - -I$(abspath ./third_party/bcc/lib/include) - EXTRA_CGO_LDFLAGS := $(EXTRA_CGO_LDFLAGS) -L$(abspath ./third_party/libbpf/lib/lib64) -lbpf \ - -L$(abspath ./third_party/bcc/lib/lib) -lbcc-syms -lstdc++ -lelf -lz - THIRD_PARTY_DEPENDENCIES := $(THIRD_PARTY_DEPENDENCIES) build-profile-bpf build-bcc build-libbpf -endif - -ifeq ("$(OS)", "Linux") - ifeq ("$(shell cat /etc/os-release | grep ^ID=)", "ID=alpine") - GO_TAGS := $(GO_TAGS),musl - ALPINE_TAG := ,musl - else - - endif -else - ifeq ("$(OS)", "Darwin") - - endif -endif - -OPEN= -ifeq ("$(OS)", "Linux") - OPEN=xdg-open -else - OPEN=open -endif - -EMBEDDED_ASSETS_DEPS ?= "assets-release" -EXTRA_LDFLAGS ?= - -ifndef $(GOPATH) - GOPATH=$(shell go env GOPATH || true) - export GOPATH -endif - --include .env -export - -PYROSCOPE_LOG_LEVEL ?= debug -PYROSCOPE_BADGER_LOG_LEVEL ?= error -PYROSCOPE_STORAGE_PATH ?= tmp/pyroscope-storage - -.PHONY: all -all: build ## Runs the build target - -.PHONY: build-phpspy-static-library -build-phpspy-static-library: ## builds phpspy static library - mkdir -p ./out - $(GOBUILD) -tags nogospy,phpspy,clib$(ALPINE_TAG) -ldflags "$(shell scripts/generate-build-flags.sh false)" -buildmode=c-archive -o "./out/libpyroscope.phpspy.a" ./pkg/agent/clib -ifeq ("$(OS)", "Linux") - LC_CTYPE=C LANG=C strip --strip-debug ./out/libpyroscope.phpspy.a - ranlib ./out/libpyroscope.phpspy.a -endif - -.PHONY: install-go-dependencies -install-go-dependencies: ## installs golang dependencies - go mod download - -.PHONY: build -build: ## Builds the binary - CGO_CFLAGS="$(CGO_CFLAGS) $(EXTRA_CGO_CFLAGS)" \ - CGO_LDFLAGS="$(CGO_LDFLAGS) $(EXTRA_CGO_LDFLAGS)" \ - $(GOBUILD) -tags "$(GO_TAGS)" -ldflags "$(EXTRA_LDFLAGS) $(shell scripts/generate-build-flags.sh)" -o ./bin/pyroscope ./cmd/pyroscope - -.PHONY: build-release -build-release: embedded-assets ## Builds the release build - EXTRA_GO_TAGS=,embedassets,$(ENABLED_SPIES_RELEASE) $(MAKE) build - -.PHONY: build-panel -build-panel: - NODE_ENV=production $(shell yarn bin webpack) --config scripts/webpack/webpack.panel.js - -.PHONY: build-phpspy-dependencies -build-phpspy-dependencies: ## Builds the PHP dependency - cd third_party && cd phpspy_src || (git clone https://github.com/pyroscope-io/phpspy.git phpspy_src && cd phpspy_src) - cd third_party/phpspy_src && git checkout $(PHPSPY_VERSION) - cd third_party/phpspy_src && make clean static - cp third_party/phpspy_src/libphpspy.a third_party/phpspy/libphpspy.a - -.PHONY: build-libbpf -build-libbpf: - $(MAKE) -C third_party/libbpf - -.PHONY: build-bcc -build-bcc: - $(MAKE) -C third_party/bcc - -.PHONY: build-profile-bpf -build-profile-bpf: build-libbpf - CFLAGS="-I$(abspath ./third_party/libbpf/lib/include)" $(MAKE) -C pkg/agent/ebpfspy/bpf - - -.PHONY: build-third-party-dependencies -build-third-party-dependencies: $(shell echo $(THIRD_PARTY_DEPENDENCIES)) ## Builds third party dep - -.PHONY: test -test: ## Runs the test suite - go test -race -tags debugspy $(shell go list ./... | grep -v /examples/) - -.PHONY: coverage -coverage: ## Runs the test suite with coverage - go test -race -tags debugspy -coverprofile=coverage -covermode=atomic $(shell go list ./... | grep -v /examples/) - -.PHONY: server -server: ## Start the Pyroscope Server - bin/pyroscope server $(SERVERPARAMS) - -.PHONY: install-web-dependencies -install-web-dependencies: ## Install the web dependencies - yarn install --ignore-engines - -.PHONY: install-build-web-dependencies -install-build-web-dependencies: ## Install web dependencies only necessary for a build - NODE_ENV=production yarn install --frozen-lockfile --ignore-engines - -.PHONY: assets -assets: install-web-dependencies ## deprecated - @echo "This command is deprecated, please use `make dev` to develop locally" - exit 1 - # yarn dev - -.PHONY: assets-watch -assets-watch: install-web-dependencies ## deprecated - @echo "This command is deprecated, please use `make dev` to develop locally" - exit 1 - # yarn dev -- --watch - -.PHONY: assets-release -assets-release: ## Configure the assets for release - rm -rf webapp/public/assets - rm -rf webapp/public/*.html - yarn build - -.PHONY: assets-size-build -assets-size-build: assets-release ## Build assets for the size report - mv webapp/public/assets/app*.js webapp/public/assets/app.js - -.PHONY: embedded-assets -embedded-assets: install-dev-tools $(shell echo $(EMBEDDED_ASSETS_DEPS)) ## Configure the assets along with dev tools - -.PHONY: lint -lint: ## Run the lint across the codebase - go run "$(shell scripts/pinned-tool.sh github.com/mgechev/revive)" -config revive.toml -exclude ./pkg/agent/pprof/... -exclude ./vendor/... -exclude ./examples/... -formatter stylish ./... - -.PHONY: lint-summary -lint-summary: ## Get the lint summary - $(MAKE) lint | grep 'https://revive.run' | sed 's/[ ()0-9,]*//' | sort - -.PHONY: ensure-logrus-not-used -ensure-logrus-not-used: ## Verify if logrus not used in codebase - @! go run "$(shell scripts/pinned-tool.sh github.com/kisielk/godepgraph)" -nostdlib -s ./pkg/agent/profiler/ | grep ' -> "github.com/sirupsen/logrus' \ - || (echo "\n^ ERROR: make sure ./pkg/agent/profiler/ does not depend on logrus. We don't want users' logs to be tainted. Talk to @petethepig if have questions\n" &1>2; exit 1) - - @! go run "$(shell scripts/pinned-tool.sh github.com/kisielk/godepgraph)" -nostdlib -s ./pkg/agent/clib/ | grep ' -> "github.com/sirupsen/logrus' \ - || (echo "\n^ ERROR: make sure ./pkg/agent/clib/ does not depend on logrus. We don't want users' logs to be tainted. Talk to @petethepig if have questions\n" &1>2; exit 1) - -.PHONY: clib-deps -clib-deps: - go run "$(shell scripts/pinned-tool.sh github.com/kisielk/godepgraph)" -tags nogospy ./pkg/agent/clib/ | dot -Tsvg -o ./tmp/clib-deps.svg - -.PHONY: unused -unused: ## Staticcheck for unused code - staticcheck -f stylish -tags $(ALL_SPIES) -unused.whole-program ./... - -.PHONY: install-dev-tools -install-dev-tools: ## Install dev tools - go install github.com/cosmtrek/air@latest - cat tools/tools.go | grep _ | awk -F'"' '{print $$2}' | xargs -tI {} go install {} - -.PHONY: web-bootstrap -web-bootstrap: install-web-dependencies - yarn bootstrap -# build webapp just to get its dependencies built -# otherwise when first running, the webapp will fail to build since its deps don't exist yet - yarn build:webapp > /dev/null - -.PHONY: dev -dev: install-web-dependencies ## Start webpack and pyroscope server. Use this one for working on pyroscope - PYROSCOPE_ANALYTICS_OPT_OUT=true goreman -exit-on-error -f scripts/dev-procfile start - -.PHONY: godoc -godoc: ## Generate godoc - sleep 5 && $(OPEN) http://localhost:8090/pkg/github.com/pyroscope-io/pyroscope/ & - godoc -http :8090 - -.PHONY: go-deps-graph -go-deps-graph: ## Generate the deps graph - sh scripts/dependency-graph.sh - open -a "/Applications/Google Chrome.app" tmp/go-deps-graph.svg - -.PHONY: clean -clean: ## Clean up storage - rm -rf tmp/pyroscope-storage - $(MAKE) -C third_party/bcc clean - $(MAKE) -C third_party/libbpf clean - $(MAKE) -C pkg/agent/ebpfspy/bpf clean - -.PHONY: update-contributors -update-contributors: ## Update the contributors - $(shell yarn bin contributor-faces) \ - -e pyroscopebot \ - -l 100 \ - . - -.PHONY: preview-changelog -preview-changelog: ## Update the changelog - $(shell yarn bin conventional-changelog) -i CHANGELOG.md -p angular -u - -.PHONY: update-changelog -update-changelog: ## Update the changelog - $(shell yarn bin conventional-changelog) -i CHANGELOG.md -p angular -s - sed -i '/Updates the list of contributors in README/d' CHANGELOG.md - sed -i '/docs: updates the list of contributors in README/d' CHANGELOG.md - sed -i '/Update README.md/d' CHANGELOG.md - -.PHONY: update-protobuf -update-protobuf: ## Update the protobuf - go install google.golang.org/protobuf/cmd/protoc-gen-go - protoc --go_out=. pkg/convert/profile.proto - -.PHONY: docker-dev -docker-dev: ## Build the docker dev - docker build . --tag pyroscope/pyroscope:dev --progress=plain - -.PHONY: windows-dev -windows-dev: ## Build the windows dev - docker build --platform linux/amd64 -f Dockerfile.windows --progress=plain --output type=local,dest=out . - -.PHONY: print-deps-error-message -print-deps-error-message: - @echo "" - @echo " NOTE: you can still build pyroscope without spies by adding ENABLED_SPIES=none before the build command:" - @echo " $$ ENABLED_SPIES=none make build" - @echo "" - exit 1 - -.PHONY: e2e-build -e2e-build: build assets-release - -.PHONY: test-merge -test-merge: - curl --data 'foo;bar 100' http://localhost:4040/ingest?name="foo%7Bprofile_id=id1%7D" - curl --data 'foo;baz 200' http://localhost:4040/ingest?name="foo%7Bprofile_id=id2%7D" - @echo http://localhost:4040/tracing?queryID=$(shell curl --data '{"appName":"foo", "profiles":["id1", "id2"], "startTime":"now-1h", "endTime":"now"}' http://localhost:4040/merge | jq .queryID | tr -d '"') - -help: ## Show this help - @egrep '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | sed 's/Makefile://' | awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} /^[a-z0-9A-Z_-]+:.*?##/ { printf " \033[36m%-30s\033[0m %s\n", $$1, $$2 }' diff --git a/og/babel.config.js b/og/babel.config.js deleted file mode 100644 index 2442a78a14..0000000000 --- a/og/babel.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - presets: ['@babel/preset-env', '@babel/preset-react'], - plugins: ['transform-class-properties'], -}; diff --git a/og/codecov.yml b/og/codecov.yml deleted file mode 100644 index 21f2f3cf7e..0000000000 --- a/og/codecov.yml +++ /dev/null @@ -1,2 +0,0 @@ -ignore: - - '**/*.pb.go' # auto-generated code diff --git a/og/cypress/README.md b/og/cypress/README.md deleted file mode 100644 index 260637716d..0000000000 --- a/og/cypress/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Cypress tests - -[Cypress](https://www.cypress.io/) is a end-to-end testing library, used mainly to simulate real user scenario (ie. clicking around and interacting with). - -# Running locally - -While running the dev server, run `yarn cy:open` -Which will spawn a browser, click on the file that you want to work on. It will be refreshed automatically whenever you update that file. - -Or run `yarn cy:ci` to run all tests. - -# Writing tests - -- Try to use [testids](https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change/) to select DOM elements -- Since our application is relatively simple, there's no need for Page Objects yet -- [Don't write small tests with single assertions](https://docs.cypress.io/guides/references/best-practices#Creating-tiny-tests-with-a-single-assertion) -- [Mock HTTP requests](https://docs.cypress.io/guides/guides/network-requests#Stub-Responses) when appropriate - -# Visual testing -## tl;dr -To update the snapshots, run -``` -yarn cy:ss -``` -(`ss` stands for **screenshot**) - -It requires docker installed and available under the `docker` binary in `PATH`. -(Not tested with `podman` or other alternatives) - -To just run without updating the snapshots, run -``` -yarn cy:ss-check -``` - -## Why -Part of our core functionality revolves around rendering a flamegraph **canvas**, -which is not straightforward to test. - -We've decided to test it using [visual testing](https://docs.cypress.io/guides/tooling/visual-testing#Functional-vs-visual-testing). - -## How - -We use the [jaredpalmer/cypress-image-snapshot](https://github.com/jaredpalmer/cypress-image-snapshot) plugin to compare against "golden" screenshots. - -By default, visual testing is disabled (we instead log a `Screenshot comparison is disabled` message). That happens because comparing images is flaky, since it depends on many factors like OS, browser, viewport and pixel density, to name a few. - -Therefore we decided to update snapshots via a docker container, which is the same container that runs in ci. That way we have a consistent experience. - -If we ever update the docker image (`cypress/included:8.4.1` at the time of this writing). We need to update in 2 places (`scripts/cypress-screenshots.sh` and in `.github/workflows/cypress-tests.yml`) - - -## Debugging visual tests -These can be very painful. We recommend recording videos (it's enabled by default), they help understand what's going on. - -Feel free to add any tips as you learn about them. - -## References -https://www.thisdot.co/blog/how-to-set-up-screenshot-comparison-testing-with-cypress-inside-an-nx -https://www.youtube.com/watch?v=1XQbGtRITys&list=PLP9o9QNnQuAYhotnIDEUQNXuvXL7ZmlyZ&index=14 - -# Updating cypress -There are 3 places to update: - -- `package.json` -- `scripts/cypress-screenshots.sh` -- `.github/workflows/cypress-tests.yml` - -They should be ALL in sync, otherwise you gonna have weird failures, specially with snapshot tests. - -Don't forget to regenerate the snapshots (`yarn cy:ss`). diff --git a/og/cypress/base-url/base-url-docker-compose.yml b/og/cypress/base-url/base-url-docker-compose.yml deleted file mode 100644 index 23d4c102ac..0000000000 --- a/og/cypress/base-url/base-url-docker-compose.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: '3' -services: - nginx: - image: nginx - network_mode: host - volumes: - - ./nginx.conf:/etc/nginx/nginx.conf diff --git a/og/cypress/base-url/cypress.json b/og/cypress/base-url/cypress.json deleted file mode 100644 index 5aeae3877e..0000000000 --- a/og/cypress/base-url/cypress.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "video": false, - "baseUrl": "http://localhost:8080/pyroscope/", - "env": { - "basePath": "/pyroscope" - }, - "integrationFolder": "cypress/integration/webapp", - "retries": { - "runMode": 5 - } -} diff --git a/og/cypress/base-url/nginx.conf b/og/cypress/base-url/nginx.conf deleted file mode 100644 index c3de8aac81..0000000000 --- a/og/cypress/base-url/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -events {} -http { - server { - listen 8080; - - location /pyroscope/ { - rewrite /pyroscope(.*) $1 break; - proxy_pass http://localhost:4040; - } - } -} - diff --git a/og/cypress/cypress.json b/og/cypress/cypress.json deleted file mode 100644 index f0917e78eb..0000000000 --- a/og/cypress/cypress.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "video": false, - "baseUrl": "http://localhost:4040", - "integrationFolder": "cypress/integration/webapp", - "testFiles": "*.ts", - "retries": { - "runMode": 5 - } -} diff --git a/og/cypress/fixtures/appNames.json b/og/cypress/fixtures/appNames.json deleted file mode 100644 index c14ebcbc3d..0000000000 --- a/og/cypress/fixtures/appNames.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { "name": "pyroscope.server.alloc_objects" }, - { "name": "pyroscope.server.alloc_space" }, - { "name": "pyroscope.server.cpu" }, - { "name": "pyroscope.server.inuse_objects" }, - { "name": "pyroscope.server.inuse_space" } -] diff --git a/og/cypress/fixtures/cart-service-dotnet-cpu.json b/og/cypress/fixtures/cart-service-dotnet-cpu.json deleted file mode 100644 index e2c5e12743..0000000000 --- a/og/cypress/fixtures/cart-service-dotnet-cpu.json +++ /dev/null @@ -1,202 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "System.Private.CoreLib!System.Threading.TimerQueue.FireNextTimers()", - "System.Private.CoreLib!System.Threading.TimerQueue.EnsureTimerFiresBy(unsigned int32)", - "System.Private.CoreLib!System.Threading.ThreadPoolWorkQueue.Dispatch()", - "System.Private.CoreLib!System.Threading.ThreadPoolWorkQueue.EnsureThreadRequested()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.__Canon,cartservice.cartstore.RedisCartStore+\u003cGetCartAsync\u003ed__13].MoveNext(class System.Threading.Thread)", - "System.Private.CoreLib!System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(class System.Threading.Thread,class System.Threading.ExecutionContext,class System.Threading.ContextCallback,class System.Object)", - "cartservice!cartservice.cartstore.RedisCartStore+\u003cGetCartAsync\u003ed__13.MoveNext()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[System.__Canon].SetExistingTaskResult(class System.Threading.Tasks.Task`1\u003c!0\u003e,!0)", - "System.Private.CoreLib!System.Threading.Tasks.Task`1[System.__Canon].TrySetResult(!0)", - "System.Private.CoreLib!System.Threading.Tasks.Task.RunContinuations(class System.Object)", - "System.Private.CoreLib!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(class System.Runtime.CompilerServices.IAsyncStateMachineBox,bool)", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.__Canon,Grpc.Shared.Server.UnaryServerMethodInvoker`3+\u003cAwaitInvoker\u003ed__5[System.__Canon,System.__Canon,System.__Canon]].MoveNext(class System.Threading.Thread)", - "System.Private.CoreLib!System.Threading.ExecutionContext.RunInternal(class System.Threading.ExecutionContext,class System.Threading.ContextCallback,class System.Object)", - "Grpc.AspNetCore.Server!Grpc.Shared.Server.UnaryServerMethodInvoker`3+\u003cAwaitInvoker\u003ed__5[System.__Canon,System.__Canon,System.__Canon].MoveNext()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler`3+\u003cHandleCallAsyncCore\u003ed__2[System.__Canon,System.__Canon,System.__Canon]].MoveNext(class System.Threading.Thread)", - "Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler`3+\u003cHandleCallAsyncCore\u003ed__2[System.__Canon,System.__Canon,System.__Canon].MoveNext()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[System.Threading.Tasks.VoidTaskResult].SetExistingTaskResult(class System.Threading.Tasks.Task`1\u003c!0\u003e,!0)", - "System.Private.CoreLib!System.Threading.Tasks.Task`1[System.Threading.Tasks.VoidTaskResult].TrySetResult(!0)", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,Grpc.AspNetCore.Server.Internal.CallHandlers.ServerCallHandlerBase`3+\u003c\u003cHandleCallAsync\u003eg__AwaitHandleCall|8_0\u003ed[System.__Canon,System.__Canon,System.__Canon]].MoveNext(class System.Threading.Thread)", - "Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.CallHandlers.ServerCallHandlerBase`3+\u003c\u003cHandleCallAsync\u003eg__AwaitHandleCall|8_0\u003ed[System.__Canon,System.__Canon,System.__Canon].MoveNext()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,Microsoft.AspNetCore.Routing.EndpointMiddleware+\u003c\u003cInvoke\u003eg__AwaitRequestTask|6_0\u003ed].MoveNext(class System.Threading.Thread)", - "Microsoft.AspNetCore.Routing!Microsoft.AspNetCore.Routing.EndpointMiddleware+\u003c\u003cInvoke\u003eg__AwaitRequestTask|6_0\u003ed.MoveNext()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+\u003cProcessRequests\u003ed__223`1[System.__Canon]].MoveNext(class System.Threading.Thread)", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+\u003cProcessRequests\u003ed__223`1[System.__Canon].MoveNext()", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteSuffix()", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2OutputProducer.WriteStreamSuffixAsync()", - "System.IO.Pipelines!System.IO.Pipelines.Pipe.CompleteWriter(class System.Exception)", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2OutputProducer+\u003cProcessDataWrites\u003ed__47].MoveNext(class System.Threading.Thread)", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2OutputProducer+\u003cProcessDataWrites\u003ed__47.MoveNext()", - "System.IO.Pipelines!System.IO.Pipelines.Pipe+DefaultPipeReader.AdvanceTo(value class System.SequencePosition)", - "System.IO.Pipelines!System.IO.Pipelines.Pipe.AdvanceReader(class System.IO.Pipelines.BufferSegment,int32,class System.IO.Pipelines.BufferSegment,int32)", - "System.Net.Sockets!System.Net.Sockets.SocketAsyncEngine.System.Threading.IThreadPoolWorkItem.Execute()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketConnection+\u003cProcessReceives\u003ed__28].MoveNext(class System.Threading.Thread)", - "Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets!Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketConnection+\u003cProcessReceives\u003ed__28.MoveNext()", - "System.Net.Sockets!System.Net.Sockets.Socket.ReceiveAsync(class System.Net.Sockets.SocketAsyncEventArgs,value class System.Threading.CancellationToken)", - "System.Net.Sockets!System.Net.Sockets.SocketAsyncEventArgs.DoOperationReceive(class System.Net.Sockets.SafeSocketHandle,value class System.Threading.CancellationToken)", - "System.Net.Sockets!System.Net.Sockets.SocketAsyncContext.ReceiveAsync(value class System.Memory`1\u003cunsigned int8\u003e,value class System.Net.Sockets.SocketFlags,int32\u0026,class System.Action`5\u003cint32,unsigned int8[],int32,value class System.Net.Sockets.SocketFlags,value class System.Net.Sockets.SocketError\u003e,value class System.Threading.CancellationToken)", - "System.Net.Sockets!System.Net.Sockets.SocketPal.TryCompleteReceive(class System.Net.Sockets.SafeSocketHandle,value class System.Span`1\u003cunsigned int8\u003e,value class System.Net.Sockets.SocketFlags,int32\u0026,value class System.Net.Sockets.SocketError\u0026)", - "System.Net.Sockets!System.Net.Sockets.SocketPal.SysReceive(class System.Net.Sockets.SafeSocketHandle,value class System.Net.Sockets.SocketFlags,value class System.Span`1\u003cunsigned int8\u003e,value class Error\u0026)", - "System.Net.Sockets!System.Net.Sockets.SocketAsyncContext+OperationQueue`1[System.__Canon].ProcessAsyncOperation(!0)", - "System.Net.Sockets!System.Net.Sockets.SocketAsyncContext+OperationQueue`1[System.__Canon].ProcessQueuedOperation(!0)", - "System.Net.Sockets!System.Net.Sockets.SocketAsyncContext+BufferMemoryReceiveOperation.DoTryComplete(class System.Net.Sockets.SocketAsyncContext)", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2Stream`1[System.__Canon].Execute()", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequestsAsync(class Microsoft.AspNetCore.Hosting.Server.IHttpApplication`1\u003c!!0\u003e)", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start(!!0\u0026)", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+\u003cProcessRequestsAsync\u003ed__222`1[System.__Canon].MoveNext()", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests(class Microsoft.AspNetCore.Hosting.Server.IHttpApplication`1\u003c!!0\u003e)", - "Microsoft.AspNetCore.Hosting!Microsoft.AspNetCore.Hosting.HostingApplication.CreateContext(class Microsoft.AspNetCore.Http.Features.IFeatureCollection)", - "Microsoft.AspNetCore.Hosting!Microsoft.AspNetCore.Hosting.HostingApplicationDiagnostics.StartActivity(class Microsoft.AspNetCore.Http.HttpContext,bool\u0026)", - "System.Diagnostics.DiagnosticSource!System.Diagnostics.Activity.Start()", - "System.Diagnostics.DiagnosticSource!System.Diagnostics.Activity.GenerateW3CId()", - "System.Diagnostics.DiagnosticSource!System.Diagnostics.ActivityTraceId.CreateRandom()", - "System.Diagnostics.DiagnosticSource!System.Diagnostics.ActivityTraceId.SetToRandomBytes(value class System.Span`1\u003cunsigned int8\u003e)", - "System.Private.CoreLib!System.Guid.NewGuid()", - "Microsoft.AspNetCore.HostFiltering!Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke(class Microsoft.AspNetCore.Http.HttpContext)", - "Microsoft.AspNetCore.Routing!Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(class Microsoft.AspNetCore.Http.HttpContext)", - "Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.CallHandlers.ServerCallHandlerBase`3[System.__Canon,System.__Canon,System.__Canon].HandleCallAsync(class Microsoft.AspNetCore.Http.HttpContext)", - "Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler`3[System.__Canon,System.__Canon,System.__Canon].HandleCallAsyncCore(class Microsoft.AspNetCore.Http.HttpContext,class Grpc.AspNetCore.Server.Internal.HttpContextServerCallContext)", - "Grpc.AspNetCore.Server!Grpc.Shared.Server.UnaryServerMethodInvoker`3[System.__Canon,System.__Canon,System.__Canon].Invoke(class Microsoft.AspNetCore.Http.HttpContext,class Grpc.Core.ServerCallContext,!1)", - "cartservice!cartservice.services.CartService.EmptyCart(class Hipstershop.EmptyCartRequest,class Grpc.Core.ServerCallContext)", - "cartservice!cartservice.services.CartService+\u003cEmptyCart\u003ed__5.MoveNext()", - "cartservice!cartservice.cartstore.RedisCartStore.EmptyCartAsync(class System.String)", - "cartservice!cartservice.cartstore.RedisCartStore+\u003cEmptyCartAsync\u003ed__12.MoveNext()", - "StackExchange.Redis!StackExchange.Redis.ConnectionMultiplexer.ExecuteAsyncImpl(class StackExchange.Redis.Message,class StackExchange.Redis.ResultProcessor`1\u003c!!0\u003e,class System.Object,class StackExchange.Redis.ServerEndPoint)", - "StackExchange.Redis!StackExchange.Redis.PhysicalBridge.TryWriteAsync(class StackExchange.Redis.Message,bool)", - "StackExchange.Redis!StackExchange.Redis.PhysicalBridge.WriteMessageTakingWriteLockAsync(class StackExchange.Redis.PhysicalConnection,class StackExchange.Redis.Message)", - "Pipelines.Sockets.Unofficial!Pipelines.Sockets.Unofficial.Threading.MutexSlim.ActivateNextQueueItemWithValidatedToken(int32)", - "cartservice!cartservice.services.CartService.AddItem(class Hipstershop.AddItemRequest,class Grpc.Core.ServerCallContext)", - "cartservice!cartservice.services.CartService+\u003cAddItem\u003ed__3.MoveNext()", - "cartservice!cartservice.cartstore.RedisCartStore.AddItemAsync(class System.String,class System.String,int32)", - "cartservice!cartservice.cartstore.RedisCartStore+\u003cAddItemAsync\u003ed__11.MoveNext()", - "System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[System.Threading.Tasks.VoidTaskResult].GetStateMachineBox(!!0\u0026,class System.Threading.Tasks.Task`1\u003c!0\u003e\u0026)", - "System.Console!System.Console.WriteLine(class System.String)", - "System.Private.CoreLib!System.IO.TextWriter+SyncTextWriter.WriteLine(class System.String)", - "System.Private.CoreLib!System.IO.StreamWriter.WriteLine(class System.String)", - "System.Private.CoreLib!System.IO.StreamWriter.Flush(bool,bool)", - "System.Console!System.ConsolePal.Write(class Microsoft.Win32.SafeHandles.SafeFileHandle,unsigned int8[],int32,int32,bool)", - "System.Console!System.ConsolePal.Write(class Microsoft.Win32.SafeHandles.SafeFileHandle,unsigned int8*,int32,bool)", - "cartservice!cartservice.cartstore.RedisCartStore.GetCartAsync(class System.String)", - "StackExchange.Redis!StackExchange.Redis.RedisDatabase.HashGetAsync(value class StackExchange.Redis.RedisKey,value class StackExchange.Redis.RedisValue,value class StackExchange.Redis.CommandFlags)", - "StackExchange.Redis!StackExchange.Redis.PhysicalBridge.WriteMessageInsideLock(class StackExchange.Redis.PhysicalConnection,class StackExchange.Redis.Message)", - "StackExchange.Redis!StackExchange.Redis.PhysicalBridge.WriteMessageToServerInsideWriteLock(class StackExchange.Redis.PhysicalConnection,class StackExchange.Redis.Message)", - "StackExchange.Redis!StackExchange.Redis.PhysicalConnection.GetReadModeCommand(bool)", - "StackExchange.Redis!StackExchange.Redis.PhysicalConnection.get_BridgeCouldBeNull()", - "StackExchange.Redis!StackExchange.Redis.Message.WriteTo(class StackExchange.Redis.PhysicalConnection)", - "StackExchange.Redis!StackExchange.Redis.Message+CommandKeyValueMessage.WriteImpl(class StackExchange.Redis.PhysicalConnection)", - "StackExchange.Redis!StackExchange.Redis.PhysicalConnection.WriteHeader(value class StackExchange.Redis.RedisCommand,int32,value class StackExchange.Redis.CommandBytes)", - "System.IO.Pipelines!System.IO.Pipelines.Pipe.GetSpan(int32)", - "System.IO.Pipelines!System.IO.Pipelines.Pipe.AllocateWriteHeadSynchronized(int32)", - "Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.PipeExtensions.ReadSingleMessageAsync(class System.IO.Pipelines.PipeReader,class Grpc.AspNetCore.Server.Internal.HttpContextServerCallContext,class System.Func`2\u003cclass Grpc.Core.DeserializationContext,!!0\u003e)", - "Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.PipeExtensions+\u003cReadSingleMessageAsync\u003ed__13`1[System.__Canon].MoveNext()", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestPipeReader.AdvanceTo(value class System.SequencePosition)", - "Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.Http2MessageBody.AdvanceTo(value class System.SequencePosition,value class System.SequencePosition)", - "System.IO.Pipelines!System.IO.Pipelines.Pipe+DefaultPipeReader.AdvanceTo(value class System.SequencePosition,value class System.SequencePosition)" - ], - "levels": [ - [0, 3238, 0, 0], - [0, 3223, 0, 3, 0, 15, 0, 1], - [ - 0, 1877, 0, 43, 0, 604, 0, 32, 0, 425, 0, 5, 0, 317, 317, 4, 0, 15, 15, - 2 - ], - [0, 1877, 0, 44, 0, 513, 0, 40, 0, 91, 0, 33, 0, 425, 0, 6], - [0, 1877, 0, 45, 0, 513, 0, 41, 0, 91, 0, 13, 0, 425, 0, 7], - [0, 1877, 0, 46, 0, 513, 0, 42, 0, 91, 0, 34, 0, 425, 0, 8], - [0, 1877, 0, 47, 0, 513, 0, 38, 0, 91, 0, 35, 0, 425, 0, 9], - [0, 1877, 0, 45, 0, 513, 513, 39, 0, 91, 0, 36, 0, 425, 0, 10], - [0, 1877, 0, 24, 513, 91, 0, 37, 0, 425, 0, 11], - [0, 1686, 0, 55, 0, 191, 0, 48, 513, 91, 0, 38, 0, 425, 0, 12], - [0, 1686, 0, 56, 0, 191, 0, 49, 513, 91, 91, 39, 0, 425, 0, 13], - [0, 1686, 0, 57, 0, 191, 0, 50, 604, 425, 0, 14], - [0, 1686, 0, 58, 0, 191, 0, 51, 604, 425, 0, 8], - [0, 1686, 0, 45, 0, 191, 0, 52, 604, 425, 0, 9], - [0, 1686, 0, 16, 0, 191, 0, 53, 604, 425, 0, 10], - [0, 180, 0, 90, 0, 1506, 0, 59, 0, 191, 191, 54, 604, 425, 0, 11], - [ - 0, 180, 0, 45, 0, 1310, 0, 79, 0, 158, 0, 68, 0, 38, 0, 60, 795, 425, 0, - 15 - ], - [ - 0, 180, 0, 91, 0, 1310, 0, 45, 0, 158, 0, 45, 0, 38, 0, 45, 795, 425, 0, - 13 - ], - [ - 0, 180, 0, 92, 0, 1310, 0, 7, 0, 158, 0, 69, 0, 38, 0, 61, 795, 425, 0, - 16 - ], - [ - 0, 180, 0, 93, 0, 341, 0, 80, 0, 969, 0, 73, 0, 158, 0, 70, 0, 38, 0, - 62, 795, 425, 0, 17 - ], - [ - 0, 180, 0, 94, 0, 341, 0, 64, 0, 969, 0, 74, 0, 158, 0, 45, 0, 38, 0, - 45, 795, 425, 0, 18 - ], - [ - 0, 180, 180, 31, 0, 341, 0, 65, 0, 969, 0, 75, 0, 158, 0, 71, 0, 38, 0, - 63, 795, 425, 0, 10 - ], - [ - 180, 341, 0, 66, 0, 969, 0, 76, 0, 154, 0, 73, 0, 4, 4, 72, 0, 38, 0, - 64, 795, 425, 0, 11 - ], - [ - 180, 341, 0, 81, 0, 969, 0, 77, 0, 154, 6, 74, 4, 38, 0, 65, 795, 425, - 0, 19 - ], - [ - 180, 341, 0, 82, 0, 969, 969, 78, 6, 148, 0, 75, 4, 38, 0, 66, 795, 425, - 0, 13 - ], - [ - 180, 8, 0, 85, 0, 333, 0, 83, 975, 148, 0, 76, 4, 38, 38, 67, 795, 425, - 0, 20 - ], - [180, 8, 0, 86, 0, 333, 333, 84, 975, 148, 0, 77, 837, 425, 0, 17], - [180, 8, 0, 87, 1308, 148, 148, 78, 837, 425, 0, 18], - [180, 8, 0, 88, 2293, 425, 0, 10], - [180, 8, 8, 89, 2293, 425, 0, 11], - [2481, 425, 0, 21], - [2481, 425, 0, 13], - [2481, 425, 0, 22], - [2481, 425, 0, 17], - [2481, 425, 0, 18], - [2481, 425, 0, 10], - [2481, 425, 0, 11], - [2481, 425, 0, 23], - [2481, 425, 0, 13], - [2481, 425, 0, 24], - [2481, 425, 0, 25], - [2481, 425, 0, 26], - [2481, 425, 0, 27], - [2481, 425, 0, 28], - [2481, 425, 0, 13], - [2481, 425, 0, 29], - [2481, 425, 0, 30], - [2481, 425, 425, 31] - ], - "numTicks": 3238, - "maxSelf": 969, - "spyName": "dotnetspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "dotnetspy", - "units": "samples" - }, - "timeline": { - "startTime": 1634591500, - "samples": [361, 1613, 360, 908], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/example.json b/og/cypress/fixtures/example.json deleted file mode 100644 index 02e4254378..0000000000 --- a/og/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/og/cypress/fixtures/hotrod-python-driver-cpu.json b/og/cypress/fixtures/hotrod-python-driver-cpu.json deleted file mode 100644 index 6bf79498fd..0000000000 --- a/og/cypress/fixtures/hotrod-python-driver-cpu.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "threading.py:930 - _bootstrap", - "threading.py:973 - _bootstrap_inner", - "threading.py:910 - run", - "threadloop/threadloop.py:78 - _start_io_loop", - "tornado/platform/asyncio.py:199 - start", - "asyncio/base_events.py:596 - run_forever", - "asyncio/base_events.py:1891 - _run_once", - "asyncio/events.py:80 - _run", - "tornado/ioloop.py:688 - \u003clambda\u003e", - "tornado/ioloop.py:741 - _run_callback", - "tornado/gen.py:814 - inner", - "tornado/gen.py:775 - run", - "tornado/gen.py:818 - handle_yield", - "asyncio/base_events.py:1890 - _run_once", - "tornado/gen.py:769 - run", - "jaeger_client/reporter.py:168 - _consume_queue", - "tornado/gen.py:234 - wrapper", - "jaeger_client/reporter.py:194 - _submit", - "tornado/gen.py:216 - wrapper", - "jaeger_client/reporter.py:211 - _send", - "jaeger_client/thrift_gen/agent/Agent.py:99 - emitBatch", - "jaeger_client/thrift_gen/agent/Agent.py:108 - send_emitBatch", - "thrift/transport/TTransport.py:179 - flush", - "jaeger_client/TUDPTransport.py:41 - write", - "jaeger_client/thrift_gen/agent/Agent.py:266 - write", - "jaeger_client/thrift_gen/jaeger/ttypes.py:797 - write", - "jaeger_client/thrift_gen/jaeger/ttypes.py:588 - write", - "thrift/protocol/TCompactProtocol.py:42 - nested", - "thrift/protocol/TCompactProtocol.py:283 - __writeBinary", - "thrift/protocol/TCompactProtocol.py:220 - __writeSize", - "thrift/protocol/TCompactProtocol.py:154 - __writeVarint", - "thrift/protocol/TCompactProtocol.py:64 - writeVarint", - "jaeger_client/thrift_gen/agent/Agent.py:106 - send_emitBatch", - "jaeger_client/thrift_gen/agent/Agent.py:263 - write", - "thrift/protocol/TCompactProtocol.py:229 - writeCollectionBegin", - "jaeger_client/thrift_gen/jaeger/ttypes.py:151 - write", - "thrift/protocol/TCompactProtocol.py:179 - writeStructBegin", - "jaeger_client/thrift_gen/jaeger/ttypes.py:555 - write", - "thrift/protocol/TCompactProtocol.py:70 - writeVarint", - "asyncio/selector_events.py:120 - _read_from_self", - "flask/app.py:2088 - __call__", - "flask/app.py:2070 - wsgi_app", - "flask/app.py:1516 - full_dispatch_request", - "flask/app.py:1499 - dispatch_request", - "services/driver/server.py:25 - find_nearest", - "flask/json/__init__.py:347 - jsonify", - "werkzeug/local.py:430 - __get__", - "werkzeug/local.py:544 - _get_current_object", - "flask/globals.py:48 - _find_app", - "werkzeug/local.py:247 - top", - "werkzeug/local.py:153 - __getattr__", - "flask/app.py:1513 - full_dispatch_request", - "services/driver/server.py:32 - handle_find_nearest", - "services/driver/server.py:30 - \u003clistcomp\u003e", - "services/driver/redis.py:13 - get_driver", - "asyncio/events.py:95 - _run", - "tornado/ioloop.py:761 - _run_callback", - "tornado/gen.py:792 - run", - "tornado/gen.py:254 - wrapper", - "tornado/gen.py:741 - __init__", - "tornado/gen.py:780 - run", - "jaeger_client/reporter.py:195 - _submit" - ], - "levels": [ - [0, 8159, 0, 0], - [0, 1, 0, 7, 0, 2, 0, 41, 0, 8156, 0, 1], - [0, 1, 0, 7, 0, 2, 0, 42, 0, 8156, 0, 2], - [0, 1, 0, 56, 0, 1, 0, 52, 0, 1, 0, 43, 0, 8156, 0, 3], - [0, 1, 0, 9, 0, 1, 0, 44, 0, 1, 0, 44, 0, 8156, 0, 4], - [0, 1, 0, 57, 0, 1, 0, 45, 0, 1, 0, 45, 0, 8156, 0, 5], - [0, 1, 0, 11, 0, 1, 0, 53, 0, 1, 0, 46, 0, 8156, 0, 6], - [0, 1, 0, 58, 0, 1, 0, 54, 0, 1, 0, 47, 0, 8155, 0, 14, 0, 1, 0, 7], - [0, 1, 0, 7, 0, 1, 1, 55, 0, 1, 0, 48, 0, 8155, 0, 8, 0, 1, 0, 8], - [0, 1, 0, 56, 1, 1, 0, 49, 0, 465, 465, 40, 0, 7690, 0, 9, 0, 1, 0, 9], - [0, 1, 0, 9, 1, 1, 0, 50, 465, 7690, 0, 10, 0, 1, 0, 10], - [0, 1, 0, 57, 1, 1, 1, 51, 465, 7690, 0, 11, 0, 1, 0, 11], - [0, 1, 0, 11, 467, 7690, 0, 15, 0, 1, 0, 12], - [0, 1, 0, 58, 467, 7690, 0, 16, 0, 1, 1, 13], - [0, 1, 0, 7, 467, 7690, 0, 17], - [0, 1, 0, 56, 467, 7690, 0, 18], - [0, 1, 0, 9, 467, 7690, 0, 19], - [0, 1, 0, 57, 467, 7690, 0, 20], - [0, 1, 0, 11, 467, 7690, 0, 21], - [0, 1, 0, 59, 467, 3, 0, 33, 0, 7687, 0, 22], - [0, 1, 0, 60, 467, 3, 0, 34, 0, 1, 0, 25, 0, 7686, 0, 23], - [0, 1, 0, 61, 467, 3, 0, 26, 0, 1, 0, 26, 0, 7686, 7686, 24], - [0, 1, 1, 62, 467, 1, 0, 38, 0, 1, 0, 27, 0, 1, 1, 35, 0, 1, 0, 27], - [468, 1, 0, 28, 0, 1, 0, 36, 1, 1, 0, 28], - [468, 1, 0, 29, 0, 1, 1, 37, 1, 1, 0, 29], - [468, 1, 0, 30, 2, 1, 0, 30], - [468, 1, 0, 31, 2, 1, 0, 31], - [468, 1, 1, 39, 2, 1, 1, 32] - ], - "numTicks": 8159, - "maxSelf": 7686, - "spyName": "pyspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "pyspy", - "units": "samples" - }, - "timeline": { - "startTime": 1634591500, - "samples": [2405, 2168, 1761, 1829], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/hotrod-ruby-driver-cpu.json b/og/cypress/fixtures/hotrod-ruby-driver-cpu.json deleted file mode 100644 index 5e6bbd0ff4..0000000000 --- a/og/cypress/fixtures/hotrod-ruby-driver-cpu.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "webrick/utils.rb:194 - watch", - "(unknown):0 - pop [c function]", - "webrick/server.rb:325 - block in start_thread", - "webrick/log.rb:97 - debug", - "webrick/log.rb:154 - log", - "(unknown):0 - strftime [c function]", - "webrick/httpserver.rb:120 - run", - "webrick/httpserver.rb:225 - access_log", - "webrick/accesslog.rb:117 - setup_params", - "(unknown):0 - each [c function]", - "webrick/httpserver.rb:224 - block in access_log", - "(unknown):0 - \u003c\u003c [c function]", - "(unknown):0 - write [c function]", - "webrick/httpserver.rb:141 - service", - "gems/rack-2.0.5/lib/rack/handler/webrick.rb:117 - service", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1503 - call", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1731 - synchronize", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1502 - block in call", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1959 - call", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:199 - call", - "gems/sinatra-2.0.3/lib/sinatra/show_exceptions.rb:44 - call", - "gems/rack-2.0.5/lib/rack/head.rb:23 - call", - "gems/rack-2.0.5/lib/rack/null_logger.rb:10 - call", - "gems/rack-protection-2.0.3/lib/rack/protection/frame_options.rb:34 - call", - "gems/rack-protection-2.0.3/lib/rack/protection/base.rb:51 - call", - "gems/rack-protection-2.0.3/lib/rack/protection/json_csrf.rb:35 - call", - "gems/rack-protection-2.0.3/lib/rack/protection/path_traversal.rb:19 - call", - "gems/rack-protection-2.0.3/lib/rack/protection/xss_header.rb:22 - call", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:914 - call", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:936 - call!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:170 - finish", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:180 - drop_content_info?", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1088 - invoke", - "(unknown):0 - catch [c function]", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1076 - block in invoke", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:924 - block in call!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1107 - dispatch!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:82 - params", - "gems/rack-2.0.5/lib/rack/request.rb:21 - params", - "gems/rack-2.0.5/lib/rack/request.rb:361 - params", - "gems/rack-2.0.5/lib/rack/request.rb:323 - GET", - "gems/rack-2.0.5/lib/rack/request.rb:469 - parse_query", - "gems/rack-2.0.5/lib/rack/query_parser.rb:73 - parse_nested_query", - "(unknown):0 - (unknown) [c function]", - "gems/rack-2.0.5/lib/rack/query_parser.rb:68 - block in parse_nested_query", - "gems/rack-2.0.5/lib/rack/query_parser.rb:117 - normalize_params", - "gems/rack-2.0.5/lib/rack/query_parser.rb:65 - block (2 levels) in parse_nested_query", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1098 - block in dispatch!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1072 - static!", - "(unknown):0 - file? [c function]", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1007 - route!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:997 - block in route!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1047 - process_route", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1041 - block in process_route", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:993 - block (2 levels) in route!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1012 - route_eval", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:992 - block (3 levels) in route!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1635 - block in compile!", - "(unknown):0 - call [c function]", - "services/driver/server.rb:32 - block in \u003cclass:Site\u003e", - "gems/rack-2.0.5/lib/rack/utils.rb:473 - []=", - "gems/rack-protection-2.0.3/lib/rack/protection/json_csrf.rb:42 - has_vector?", - "gems/rack-protection-2.0.3/lib/rack/protection/base.rb:98 - referrer", - "uri/common.rb:235 - parse", - "uri/rfc3986_parser.rb:84 - parse", - "uri/rfc3986_parser.rb:69 - split", - "webrick/httprequest.rb:524 - read_body", - "(unknown):0 - member? [c function]", - "webrick/httpresponse.rb:235 - send_response", - "webrick/httpresponse.rb:351 - send_header", - "webrick/httpresponse.rb:339 - block in send_header", - "webrick/httpresponse.rb:417 - check_header", - "gems/rack-2.0.5/lib/rack/handler/webrick.rb:19 - setup_header", - "webrick/httpresponse.rb:301 - setup_header", - "time.rb:707 - httpdate", - "webrick/httprequest.rb:238 - parse", - "webrick/httputils.rb:41 - normalize_path", - "(unknown):0 - downcase [c function]", - "webrick/httputils.rb:216 - parse_qvalues", - "webrick/httprequest.rb:500 - parse_uri", - "webrick/httprequest.rb:477 - read_header", - "webrick/httputils.rb:168 - parse_header", - "webrick/httputils.rb:166 - block in parse_header", - "webrick/httprequest.rb:571 - read_line", - "webrick/httprequest.rb:567 - _read_data", - "webrick/utils.rb:267 - timeout", - "webrick/utils.rb:0 - ensure in timeout", - "webrick/utils.rb:144 - cancel", - "webrick/utils.rb:242 - cancel", - "(unknown):0 - wait_readable [c function]", - "(unknown):0 - eof? [c function]", - "services/driver/server.rb:36 - \u003cmain\u003e", - "(unknown):0 - new [c function]", - "services/driver/server.rb:11 - initialize", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1466 - run!", - "gems/sinatra-2.0.3/lib/sinatra/base.rb:1537 - start_server", - "gems/rack-2.0.5/lib/rack/handler/webrick.rb:35 - run", - "webrick/server.rb:214 - start", - "webrick/server.rb:33 - start", - "webrick/server.rb:213 - block in start", - "(unknown):0 - select [c function]" - ], - "levels": [ - [0, 41, 0, 0], - [0, 6, 6, 44, 0, 1, 0, 92, 0, 32, 1, 3, 0, 2, 0, 1], - [6, 1, 0, 93, 1, 30, 0, 7, 0, 1, 0, 4, 0, 2, 2, 2], - [ - 6, 1, 0, 94, 1, 1, 1, 44, 0, 1, 1, 91, 0, 1, 1, 90, 0, 10, 0, 76, 0, 4, - 1, 69, 0, 11, 1, 14, 0, 2, 0, 8, 0, 1, 0, 5 - ], - [ - 6, 1, 0, 95, 4, 1, 1, 44, 0, 2, 0, 81, 0, 5, 5, 80, 0, 1, 0, 79, 0, 1, - 0, 77, 1, 2, 0, 73, 0, 1, 0, 70, 1, 10, 0, 15, 0, 1, 0, 10, 0, 1, 1, 9, - 0, 1, 1, 6 - ], - [ - 6, 1, 0, 96, 5, 1, 0, 84, 0, 1, 0, 82, 5, 1, 1, 44, 0, 1, 1, 78, 1, 2, - 1, 74, 0, 1, 0, 44, 1, 1, 0, 44, 0, 9, 0, 16, 0, 1, 0, 11 - ], - [ - 6, 1, 0, 97, 5, 1, 0, 85, 0, 1, 0, 44, 9, 1, 0, 75, 0, 1, 0, 71, 1, 1, - 0, 67, 0, 9, 0, 17, 0, 1, 0, 12 - ], - [ - 6, 1, 0, 98, 5, 1, 0, 86, 0, 1, 1, 83, 9, 1, 1, 44, 0, 1, 1, 72, 1, 1, - 1, 68, 0, 9, 0, 18, 0, 1, 1, 13 - ], - [6, 1, 0, 99, 5, 1, 0, 87, 14, 9, 0, 19], - [6, 1, 0, 100, 5, 1, 0, 88, 14, 9, 0, 20], - [6, 1, 1, 101, 5, 1, 1, 89, 14, 9, 0, 21], - [27, 9, 0, 22], - [27, 9, 0, 23], - [27, 9, 0, 24], - [27, 9, 0, 25], - [27, 9, 0, 25], - [27, 9, 0, 26], - [27, 1, 0, 62, 0, 8, 0, 27], - [27, 1, 0, 63, 0, 8, 0, 28], - [27, 1, 0, 64, 0, 1, 1, 61, 0, 7, 0, 29], - [27, 1, 0, 65, 1, 7, 0, 30], - [27, 1, 0, 66, 1, 6, 0, 33, 0, 1, 0, 31], - [27, 1, 1, 44, 1, 1, 0, 44, 0, 5, 0, 34, 0, 1, 1, 32], - [29, 1, 0, 35, 0, 5, 0, 35], - [29, 1, 0, 36, 0, 5, 0, 36], - [29, 1, 0, 37, 0, 5, 0, 37], - [29, 1, 0, 33, 0, 1, 0, 33, 0, 4, 0, 38], - [29, 1, 0, 44, 0, 1, 0, 34, 0, 4, 0, 39], - [29, 1, 0, 35, 0, 1, 0, 35, 0, 4, 0, 40], - [29, 1, 0, 48, 0, 1, 0, 48, 0, 4, 0, 41], - [29, 1, 0, 51, 0, 1, 0, 49, 0, 4, 0, 42], - [29, 1, 0, 44, 0, 1, 1, 50, 0, 4, 1, 43], - [29, 1, 0, 52, 2, 3, 0, 44], - [29, 1, 0, 53, 2, 3, 0, 45], - [29, 1, 0, 34, 2, 1, 0, 44, 0, 2, 2, 46], - [29, 1, 0, 54, 2, 1, 1, 47], - [29, 1, 0, 55], - [29, 1, 0, 56], - [29, 1, 0, 57], - [29, 1, 0, 58], - [29, 1, 0, 59], - [29, 1, 0, 60], - [29, 1, 0, 44], - [29, 1, 0, 44], - [29, 1, 1, 44] - ], - "numTicks": 41, - "maxSelf": 6, - "spyName": "rbspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "rbspy", - "units": "samples" - }, - "timeline": { - "startTime": 1634591500, - "samples": [9, 13, 12, 11], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/pyroscope.server.alloc_objects.json b/og/cypress/fixtures/pyroscope.server.alloc_objects.json deleted file mode 100644 index a84dc6ade5..0000000000 --- a/og/cypress/fixtures/pyroscope.server.alloc_objects.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime/pprof.profileWriter", - "runtime/pprof.(*profileBuilder).build", - "compress/gzip.(*Writer).Write", - "compress/flate.NewWriter", - "compress/flate.(*compressor).init", - "net/http.(*conn).serve", - "net/http.serverHandler.ServeHTTP", - "net/http.HandlerFunc.ServeHTTP", - "github.com/klauspost/compress/gzhttp.NewWrapper.func1.1", - "net/http.(*ServeMux).ServeHTTP", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1", - "github.com/slok/go-http-metrics/middleware.Middleware.Measure", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1.1", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).ingestHandler", - "github.com/pyroscope-io/pyroscope/pkg/server.wrapConvertFunctionBuf.func1", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParseTrieBuf", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.IterateRaw", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).InsertInt", - "bufio.NewReaderSize", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.(*Reporter).Start", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.DiskUsage", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.dirSize", - "path/filepath.Walk", - "path/filepath.walk", - "path/filepath.readDirNames", - "os.(*File).Readdirnames", - "os.(*File).readdir", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Iterate", - "github.com/pyroscope-io/pyroscope/pkg/storage.IngestionObserver.Put", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Clone", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*treeNode).clone", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).GetOrCreate", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).get", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).GetOrSet", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).increment", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot", - "runtime/pprof.writeHeap", - "runtime/pprof.writeHeapInternal", - "runtime/pprof.writeHeapProto", - "runtime/pprof.(*profileBuilder).pbSample", - "runtime/pprof.(*profileBuilder).flush", - "compress/flate.newDeflateFast", - "runtime/pprof.(*profileBuilder).appendLocsForStack", - "runtime/pprof.(*profileBuilder).stringIndex", - "runtime/pprof.(*profileBuilder).emitLocation", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile", - "io/ioutil.ReadAll", - "io.ReadAll", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof", - "google.golang.org/protobuf/proto.Unmarshal", - "google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer", - "google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo", - "reflect.New", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func1", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.startCPUProfile", - "runtime/pprof.StartCPUProfile" - ], - "levels": [ - [0, 75489, 0, 0], - [ - 0, 4733, 0, 44, 0, 26930, 0, 28, 0, 21845, 0, 20, 0, 21973, 0, 6, 0, 8, - 0, 1 - ], - [ - 0, 4733, 0, 45, 0, 26930, 0, 29, 0, 21845, 0, 21, 0, 128, 128, 19, 0, - 21845, 0, 7, 0, 8, 0, 2 - ], - [ - 0, 1, 0, 65, 0, 4701, 0, 55, 0, 31, 0, 46, 0, 26930, 0, 30, 0, 21845, 0, - 22, 128, 21845, 0, 8, 0, 8, 0, 3 - ], - [ - 0, 1, 0, 66, 0, 4681, 0, 58, 0, 20, 0, 56, 0, 31, 0, 47, 0, 14746, 0, - 32, 0, 12184, 12184, 31, 0, 21845, 0, 23, 128, 21845, 0, 9, 0, 8, 3, 4 - ], - [ - 0, 1, 1, 67, 0, 4681, 0, 59, 0, 20, 20, 57, 0, 31, 0, 48, 0, 14746, 0, - 33, 12184, 21845, 0, 24, 128, 21845, 0, 10, 3, 5, 5, 5 - ], - [ - 1, 4681, 0, 60, 20, 22, 0, 52, 0, 9, 0, 49, 0, 6554, 0, 40, 0, 8192, 0, - 34, 12184, 21845, 0, 25, 128, 21845, 0, 8 - ], - [ - 1, 4681, 0, 61, 20, 3, 0, 54, 0, 19, 19, 53, 0, 9, 0, 50, 0, 6554, 0, - 41, 0, 8192, 0, 35, 12184, 21845, 0, 26, 128, 21845, 0, 8 - ], - [ - 1, 4681, 0, 62, 20, 3, 0, 50, 19, 9, 0, 3, 0, 6554, 0, 42, 0, 8192, 0, - 36, 12184, 21845, 21845, 27, 128, 21845, 0, 11 - ], - [ - 1, 4681, 0, 63, 20, 3, 0, 3, 19, 9, 2, 4, 0, 6554, 6554, 43, 0, 8192, 0, - 37, 34157, 21845, 0, 12 - ], - [ - 1, 4681, 4681, 64, 20, 3, 0, 4, 21, 2, 2, 5, 0, 5, 5, 51, 6554, 8192, 0, - 38, 34157, 21845, 0, 13 - ], - [4702, 3, 3, 5, 6582, 8192, 0, 39, 34157, 21845, 0, 8], - [11287, 8192, 0, 39, 34157, 21845, 0, 8], - [11287, 8192, 0, 39, 34157, 21845, 0, 14], - [11287, 8192, 0, 39, 34157, 21845, 0, 15], - [11287, 8192, 0, 39, 34157, 21845, 0, 16], - [11287, 8192, 0, 39, 34157, 21845, 0, 17], - [11287, 8192, 8192, 39, 34157, 21845, 21845, 18] - ], - "numTicks": 75489, - "maxSelf": 21845, - "spyName": "gospy", - "sampleRate": 100, - "units": "objects", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "objects" - }, - "timeline": { - "startTime": 1632505880, - "samples": [26580, 48911], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/pyroscope.server.alloc_space.json b/og/cypress/fixtures/pyroscope.server.alloc_space.json deleted file mode 100644 index 6a24e1810e..0000000000 --- a/og/cypress/fixtures/pyroscope.server.alloc_space.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime/pprof.profileWriter", - "runtime/pprof.(*profileBuilder).build", - "compress/gzip.(*Writer).Write", - "compress/flate.NewWriter", - "compress/flate.(*compressor).init", - "net/http.(*conn).serve", - "net/http.serverHandler.ServeHTTP", - "net/http.HandlerFunc.ServeHTTP", - "github.com/klauspost/compress/gzhttp.NewWrapper.func1.1", - "net/http.(*ServeMux).ServeHTTP", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1", - "github.com/slok/go-http-metrics/middleware.Middleware.Measure", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1.1", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).ingestHandler", - "github.com/pyroscope-io/pyroscope/pkg/server.wrapConvertFunctionBuf.func1", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParseTrieBuf", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.IterateRaw", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).InsertInt", - "bufio.NewReaderSize", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.(*Reporter).Start", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.DiskUsage", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.dirSize", - "path/filepath.Walk", - "path/filepath.walk", - "path/filepath.readDirNames", - "os.(*File).Readdirnames", - "os.(*File).readdir", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Iterate", - "github.com/pyroscope-io/pyroscope/pkg/storage.IngestionObserver.Put", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Clone", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*treeNode).clone", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).GetOrCreate", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).get", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).GetOrSet", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).increment", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot", - "runtime/pprof.writeHeap", - "runtime/pprof.writeHeapInternal", - "runtime/pprof.writeHeapProto", - "runtime/pprof.(*profileBuilder).pbSample", - "runtime/pprof.(*profileBuilder).flush", - "compress/flate.newDeflateFast", - "runtime/pprof.(*profileBuilder).appendLocsForStack", - "runtime/pprof.(*profileBuilder).stringIndex", - "runtime/pprof.(*profileBuilder).emitLocation", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile", - "io/ioutil.ReadAll", - "io.ReadAll", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof", - "google.golang.org/protobuf/proto.Unmarshal", - "google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer", - "google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo", - "reflect.New", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func1", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.startCPUProfile", - "runtime/pprof.StartCPUProfile" - ], - "levels": [ - [0, 12520922, 0, 0], - [ - 0, 5667556, 0, 44, 0, 2097456, 0, 28, 0, 524300, 0, 20, 0, 1050638, 0, - 6, 0, 3180972, 0, 1 - ], - [ - 0, 5667556, 0, 45, 0, 2097456, 0, 29, 0, 524300, 0, 21, 0, 526338, - 526338, 19, 0, 524300, 0, 7, 0, 3180972, 0, 2 - ], - [ - 0, 1212697, 0, 65, 0, 1062382, 0, 55, 0, 3392477, 0, 46, 0, 2097456, 0, - 30, 0, 524300, 0, 22, 526338, 524300, 0, 8, 0, 3180972, 0, 3 - ], - [ - 0, 1212697, 0, 66, 0, 524344, 0, 58, 0, 538038, 0, 56, 0, 3392477, 0, - 47, 0, 1048648, 0, 32, 0, 1048808, 1048808, 31, 0, 524300, 0, 23, - 526338, 524300, 0, 9, 0, 3180972, 1848497, 4 - ], - [ - 0, 1212697, 1212697, 67, 0, 524344, 0, 59, 0, 538038, 538038, 57, 0, - 3392477, 0, 48, 0, 1048648, 0, 33, 1048808, 524300, 0, 24, 526338, - 524300, 0, 10, 1848497, 1332475, 1332475, 5 - ], - [ - 1212697, 524344, 0, 60, 538038, 1204992, 0, 52, 0, 2187485, 0, 49, 0, - 524328, 0, 40, 0, 524320, 0, 34, 1048808, 524300, 0, 25, 526338, 524300, - 0, 8 - ], - [ - 1212697, 524344, 0, 61, 538038, 666238, 0, 54, 0, 538754, 538754, 53, 0, - 2187485, 0, 50, 0, 524328, 0, 41, 0, 524320, 0, 35, 1048808, 524300, 0, - 26, 526338, 524300, 0, 8 - ], - [ - 1212697, 524344, 0, 62, 538038, 666238, 0, 50, 538754, 2187485, 0, 3, 0, - 524328, 0, 42, 0, 524320, 0, 36, 1048808, 524300, 524300, 27, 526338, - 524300, 0, 11 - ], - [ - 1212697, 524344, 0, 63, 538038, 666238, 0, 3, 538754, 2187485, 924248, - 4, 0, 524328, 524328, 43, 0, 524320, 0, 37, 2099446, 524300, 0, 12 - ], - [ - 1212697, 524344, 524344, 64, 538038, 666238, 0, 4, 1463002, 666238, - 666238, 5, 0, 596999, 596999, 51, 524328, 524320, 0, 38, 2099446, - 524300, 0, 13 - ], - [ - 2275079, 666238, 666238, 5, 3250567, 524320, 0, 39, 2099446, 524300, 0, - 8 - ], - [6191884, 524320, 0, 39, 2099446, 524300, 0, 8], - [6191884, 524320, 0, 39, 2099446, 524300, 0, 14], - [6191884, 524320, 0, 39, 2099446, 524300, 0, 15], - [6191884, 524320, 0, 39, 2099446, 524300, 0, 16], - [6191884, 524320, 0, 39, 2099446, 524300, 0, 17], - [6191884, 524320, 524320, 39, 2099446, 524300, 524300, 18] - ], - "numTicks": 12520922, - "maxSelf": 1848497, - "spyName": "gospy", - "sampleRate": 100, - "units": "bytes", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "bytes" - }, - "timeline": { - "startTime": 1632505880, - "samples": [7116106, 5404818], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/pyroscope.server.cpu.json b/og/cypress/fixtures/pyroscope.server.cpu.json deleted file mode 100644 index 3e095d6c70..0000000000 --- a/og/cypress/fixtures/pyroscope.server.cpu.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime.mcall", - "runtime.park_m", - "runtime.schedule", - "runtime.resetspinning", - "runtime.wakep", - "runtime.startm", - "runtime.notewakeup", - "runtime.futexwakeup", - "runtime.futex", - "runtime.findrunnable", - "runtime.write", - "runtime.write1", - "runtime.stopm", - "runtime.mPark", - "runtime.notesleep", - "runtime.futexsleep", - "runtime.stealWork", - "runtime.checkTimers", - "runtime.runtimer", - "runtime.runOneTimer", - "time.sendTime", - "time.Now", - "runtime.nobarrierWakeTime", - "runtime.netpoll", - "runtime.read", - "runtime.epollwait", - "runtime.gcBgMarkWorker", - "runtime.systemstack", - "runtime.gcBgMarkWorker.func2", - "runtime.gcDrain", - "runtime.scanobject", - "runtime.findObject", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.(*Reporter).Start", - "github.com/pyroscope-io/pyroscope/pkg/util/debug.DiskUsage", - "path/filepath.Glob", - "path/filepath.glob", - "runtime.growslice", - "runtime.nextFreeFast", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "runtime.selectgo", - "runtime.gopark", - "runtime.newobject", - "runtime.mallocgc", - "runtime.arenaIndex", - "runtime.mapiterinit", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile", - "io/ioutil.ReadAll", - "io.ReadAll", - "compress/gzip.(*Reader).Read", - "compress/flate.(*decompressor).Read", - "compress/flate.(*decompressor).nextBlock", - "compress/flate.(*dictDecoder).tryWriteCopy", - "runtime.memmove", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).reset", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).uploadTries", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Diff", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).clone", - "github.com/dgraph-io/badger/v2.(*levelsController).runCompactor" - ], - "levels": [ - [0, 26, 0, 0], - [0, 1, 0, 59, 0, 6, 1, 39, 0, 1, 0, 33, 0, 2, 0, 27, 0, 16, 0, 1], - [ - 0, 1, 0, 40, 1, 1, 0, 55, 0, 1, 0, 46, 0, 1, 1, 45, 0, 1, 0, 42, 0, 1, - 0, 40, 0, 1, 0, 34, 0, 2, 0, 28, 0, 16, 0, 2 - ], - [ - 0, 1, 1, 41, 1, 1, 0, 56, 0, 1, 0, 47, 1, 1, 0, 43, 0, 1, 1, 41, 0, 1, - 0, 35, 0, 2, 0, 29, 0, 16, 0, 3 - ], - [ - 2, 1, 0, 57, 0, 1, 0, 48, 1, 1, 1, 44, 1, 1, 0, 36, 0, 2, 0, 30, 0, 14, - 1, 10, 0, 2, 0, 4 - ], - [ - 2, 1, 0, 58, 0, 1, 0, 49, 3, 1, 0, 37, 0, 2, 1, 31, 1, 6, 3, 24, 0, 1, - 1, 23, 0, 1, 0, 17, 0, 3, 0, 13, 0, 2, 0, 11, 0, 2, 0, 5 - ], - [ - 2, 1, 0, 58, 0, 1, 0, 50, 3, 1, 1, 38, 1, 1, 1, 32, 4, 2, 2, 26, 0, 1, - 1, 25, 1, 1, 0, 18, 0, 3, 0, 14, 0, 2, 2, 12, 0, 2, 0, 6 - ], - [2, 1, 0, 58, 0, 1, 0, 51, 14, 1, 0, 19, 0, 3, 0, 15, 2, 2, 0, 7], - [2, 1, 0, 58, 0, 1, 0, 52, 14, 1, 0, 20, 0, 3, 0, 16, 2, 2, 0, 8], - [2, 1, 0, 58, 0, 1, 0, 53, 14, 1, 0, 21, 0, 3, 3, 9, 2, 2, 2, 9], - [2, 1, 0, 58, 0, 1, 1, 54, 14, 1, 1, 22], - [2, 1, 0, 58], - [2, 1, 0, 58], - [2, 1, 0, 58], - [2, 1, 0, 58], - [2, 1, 0, 58], - [2, 1, 1, 58] - ], - "numTicks": 26, - "maxSelf": 3, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "samples" - }, - "timeline": { - "startTime": 1632505880, - "samples": [14, 14], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/pyroscope.server.inuse_objects.json b/og/cypress/fixtures/pyroscope.server.inuse_objects.json deleted file mode 100644 index f6bdb5deab..0000000000 --- a/og/cypress/fixtures/pyroscope.server.inuse_objects.json +++ /dev/null @@ -1,185 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime.systemstack", - "runtime.newproc.func1", - "runtime.newproc1", - "runtime.malg", - "runtime.mstart", - "runtime.mstart0", - "runtime.mstart1", - "runtime.schedule", - "runtime.resetspinning", - "runtime.wakep", - "runtime.startm", - "runtime.newm", - "runtime.allocm", - "runtime.mcall", - "runtime.park_m", - "runtime.main", - "runtime.doInit", - "encoding/base64.init", - "encoding/base64.NewEncoding", - "main.main", - "github.com/spf13/cobra.(*Command).Execute", - "github.com/spf13/cobra.(*Command).ExecuteC", - "github.com/spf13/cobra.(*Command).execute", - "github.com/pyroscope-io/pyroscope/pkg/cli.CreateCmdRunFn.func1", - "github.com/pyroscope-io/pyroscope/cmd/pyroscope/command.newServerCmd.func1", - "github.com/pyroscope-io/pyroscope/pkg/cli.StartServer", - "github.com/pyroscope-io/pyroscope/pkg/cli.newServerService", - "github.com/pyroscope-io/pyroscope/pkg/storage.New", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).newBadger", - "github.com/dgraph-io/badger/v2.newPublisher", - "github.com/dgraph-io/badger/v2.Open", - "github.com/dgraph-io/badger/v2/skl.newArena", - "github.com/pyroscope-io/pyroscope/cmd/pyroscope/command.Execute", - "github.com/pyroscope-io/pyroscope/cmd/pyroscope/command.newServerCmd", - "github.com/pyroscope-io/pyroscope/pkg/cli.PopulateFlagSet", - "github.com/pyroscope-io/pyroscope/pkg/cli.visitFields", - "github.com/spf13/pflag.(*FlagSet).VarP", - "github.com/spf13/pflag.(*FlagSet).VarPF", - "net/http.(*conn).serve", - "net/http.serverHandler.ServeHTTP", - "net/http.HandlerFunc.ServeHTTP", - "github.com/klauspost/compress/gzhttp.NewWrapper.func1.1", - "net/http.(*ServeMux).ServeHTTP", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1", - "github.com/slok/go-http-metrics/middleware.Middleware.Measure", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1.1", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).ingestHandler", - "github.com/pyroscope-io/pyroscope/pkg/server.wrapConvertFunctionBuf.func1", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParseTrieBuf", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.IterateRaw", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).InsertInt", - "bufio.NewReaderSize", - "github.com/pyroscope-io/pyroscope/pkg/analytics.(*Service).Start", - "github.com/pyroscope-io/pyroscope/pkg/analytics.(*Service).sendReport", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).AppsCount", - "github.com/pyroscope-io/pyroscope/pkg/util/hyperloglog.(*HyperLogLogPlus).Count", - "github.com/clarkduvall/hyperloglog.(*HyperLogLogPlus).Count", - "github.com/clarkduvall/hyperloglog.newCompressedList", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile", - "github.com/pyroscope-io/pyroscope/pkg/storage.IngestionObserver.Put", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Key).TreeKey", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.segmentKeyToTreeKey", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof", - "google.golang.org/protobuf/proto.Unmarshal", - "google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer", - "google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo", - "reflect.New", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func1", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.startCPUProfile", - "runtime/pprof.StartCPUProfile", - "github.com/dgraph-io/badger/v2.(*DB).updateSize", - "time.NewTicker", - "github.com/aybabtme/rgbterm.Interpret", - "bufio.NewWriterSize", - "crypto/tls.(*Conn).HandshakeContext", - "crypto/tls.(*Conn).handshakeContext", - "crypto/tls.(*Conn).clientHandshake", - "crypto/tls.(*clientHandshakeStateTLS13).handshake", - "crypto/tls.(*clientHandshakeStateTLS13).readServerCertificate", - "crypto/tls.(*Conn).verifyServerCertificate", - "sync.(*Once).Do", - "sync.(*Once).doSlow", - "crypto/x509.initSystemRoots", - "crypto/x509.loadSystemRoots", - "crypto/x509.(*CertPool).addCertFunc", - "crypto/x509.(*CertPool).AppendCertsFromPEM", - "encoding/pem.Decode" - ], - "levels": [ - [0, 44456, 0, 0], - [ - 0, 2862, 0, 87, 0, 128, 0, 85, 0, 5461, 0, 83, 0, 2341, 0, 70, 0, 10923, - 0, 59, 0, 2, 0, 53, 0, 10986, 0, 39, 0, 4856, 0, 16, 0, 2050, 0, 14, 0, - 3587, 0, 5, 0, 1260, 0, 1 - ], - [ - 0, 2862, 0, 88, 0, 128, 128, 86, 0, 5461, 5461, 84, 0, 2341, 0, 71, 0, - 10923, 0, 60, 0, 2, 0, 54, 0, 64, 64, 52, 0, 10922, 0, 40, 0, 3367, 0, - 20, 0, 1489, 0, 17, 0, 2050, 0, 15, 0, 3587, 0, 6, 0, 1260, 0, 2 - ], - [ - 0, 2862, 0, 89, 5589, 0, 0, 80, 0, 2340, 0, 72, 1, 10923, 0, 61, 0, 2, - 0, 55, 64, 10922, 0, 41, 0, 3277, 0, 33, 0, 90, 0, 21, 0, 1489, 0, 17, - 0, 2050, 0, 8, 0, 3587, 0, 7, 0, 1260, 0, 3 - ], - [ - 0, 2862, 0, 90, 5589, 0, 0, 81, 0, 2340, 0, 73, 1, 10923, 0, 62, 0, 2, - 0, 56, 64, 10922, 0, 42, 0, 3277, 0, 34, 0, 90, 0, 22, 0, 1489, 0, 17, - 0, 2050, 0, 9, 0, 3587, 0, 8, 0, 1260, 1260, 4 - ], - [ - 0, 2862, 0, 91, 5589, 0, 0, 82, 0, 2340, 0, 74, 1, 10923, 0, 63, 0, 2, - 0, 57, 64, 10922, 0, 43, 0, 3277, 0, 35, 0, 90, 0, 23, 0, 1489, 0, 17, - 0, 2050, 0, 10, 0, 3587, 0, 9 - ], - [ - 0, 2862, 0, 92, 5589, 2340, 0, 75, 1, 10923, 0, 64, 0, 2, 2, 58, 64, - 10922, 0, 41, 0, 3277, 0, 36, 0, 90, 0, 24, 0, 1489, 0, 17, 0, 2050, 0, - 11, 0, 3587, 0, 10 - ], - [ - 0, 2862, 0, 93, 5589, 2340, 0, 76, 1, 10923, 0, 65, 66, 10922, 0, 41, 0, - 3277, 0, 37, 0, 90, 0, 25, 0, 1489, 0, 18, 0, 2050, 0, 12, 0, 3587, 0, - 11 - ], - [ - 0, 2862, 0, 94, 5589, 2340, 0, 77, 1, 10923, 0, 66, 66, 10922, 0, 44, 0, - 3277, 3277, 38, 0, 90, 0, 26, 0, 1489, 1489, 19, 0, 2050, 2050, 13, 0, - 3587, 0, 12 - ], - [ - 0, 2862, 0, 95, 5589, 2340, 0, 78, 1, 10923, 0, 67, 66, 10922, 0, 45, - 3277, 90, 0, 27, 3539, 3587, 3587, 13 - ], - [ - 0, 2862, 0, 96, 5589, 2340, 2340, 79, 1, 10923, 0, 68, 66, 10922, 0, 46, - 3277, 90, 0, 28 - ], - [ - 0, 341, 0, 98, 0, 2521, 2521, 97, 7930, 10923, 10923, 69, 66, 10922, 0, - 41, 3277, 90, 0, 29 - ], - [0, 341, 341, 99, 21440, 10922, 0, 41, 3277, 69, 64, 31, 0, 21, 21, 30], - [21781, 10922, 0, 47, 3341, 5, 5, 32], - [21781, 10922, 0, 48], - [21781, 10922, 0, 49], - [21781, 10922, 0, 50], - [21781, 10922, 10922, 51] - ], - "numTicks": 44456, - "maxSelf": 10923, - "spyName": "gospy", - "sampleRate": 100, - "units": "objects", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "objects" - }, - "timeline": { - "startTime": 1632505880, - "samples": [57657, 31258], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/pyroscope.server.inuse_space.json b/og/cypress/fixtures/pyroscope.server.inuse_space.json deleted file mode 100644 index 3be22822e8..0000000000 --- a/og/cypress/fixtures/pyroscope.server.inuse_space.json +++ /dev/null @@ -1,192 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime.systemstack", - "runtime.newproc.func1", - "runtime.newproc1", - "runtime.malg", - "runtime.mstart", - "runtime.mstart0", - "runtime.mstart1", - "runtime.schedule", - "runtime.resetspinning", - "runtime.wakep", - "runtime.startm", - "runtime.newm", - "runtime.allocm", - "runtime.mcall", - "runtime.park_m", - "runtime.main", - "runtime.doInit", - "encoding/base64.init", - "encoding/base64.NewEncoding", - "main.main", - "github.com/spf13/cobra.(*Command).Execute", - "github.com/spf13/cobra.(*Command).ExecuteC", - "github.com/spf13/cobra.(*Command).execute", - "github.com/pyroscope-io/pyroscope/pkg/cli.CreateCmdRunFn.func1", - "github.com/pyroscope-io/pyroscope/cmd/pyroscope/command.newServerCmd.func1", - "github.com/pyroscope-io/pyroscope/pkg/cli.StartServer", - "github.com/pyroscope-io/pyroscope/pkg/cli.newServerService", - "github.com/pyroscope-io/pyroscope/pkg/storage.New", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).newBadger", - "github.com/dgraph-io/badger/v2.newPublisher", - "github.com/dgraph-io/badger/v2.Open", - "github.com/dgraph-io/badger/v2/skl.newArena", - "github.com/pyroscope-io/pyroscope/cmd/pyroscope/command.Execute", - "github.com/pyroscope-io/pyroscope/cmd/pyroscope/command.newServerCmd", - "github.com/pyroscope-io/pyroscope/pkg/cli.PopulateFlagSet", - "github.com/pyroscope-io/pyroscope/pkg/cli.visitFields", - "github.com/spf13/pflag.(*FlagSet).VarP", - "github.com/spf13/pflag.(*FlagSet).VarPF", - "net/http.(*conn).serve", - "net/http.serverHandler.ServeHTTP", - "net/http.HandlerFunc.ServeHTTP", - "github.com/klauspost/compress/gzhttp.NewWrapper.func1.1", - "net/http.(*ServeMux).ServeHTTP", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1", - "github.com/slok/go-http-metrics/middleware.Middleware.Measure", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1.1", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).ingestHandler", - "github.com/pyroscope-io/pyroscope/pkg/server.wrapConvertFunctionBuf.func1", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParseTrieBuf", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.IterateRaw", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).InsertInt", - "bufio.NewReaderSize", - "github.com/pyroscope-io/pyroscope/pkg/analytics.(*Service).Start", - "github.com/pyroscope-io/pyroscope/pkg/analytics.(*Service).sendReport", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).AppsCount", - "github.com/pyroscope-io/pyroscope/pkg/util/hyperloglog.(*HyperLogLogPlus).Count", - "github.com/clarkduvall/hyperloglog.(*HyperLogLogPlus).Count", - "github.com/clarkduvall/hyperloglog.newCompressedList", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile", - "github.com/pyroscope-io/pyroscope/pkg/storage.IngestionObserver.Put", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Key).TreeKey", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.segmentKeyToTreeKey", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof", - "google.golang.org/protobuf/proto.Unmarshal", - "google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer", - "google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo", - "reflect.New", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func1", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.startCPUProfile", - "runtime/pprof.StartCPUProfile", - "github.com/dgraph-io/badger/v2.(*DB).updateSize", - "time.NewTicker", - "github.com/aybabtme/rgbterm.Interpret", - "bufio.NewWriterSize", - "crypto/tls.(*Conn).HandshakeContext", - "crypto/tls.(*Conn).handshakeContext", - "crypto/tls.(*Conn).clientHandshake", - "crypto/tls.(*clientHandshakeStateTLS13).handshake", - "crypto/tls.(*clientHandshakeStateTLS13).readServerCertificate", - "crypto/tls.(*Conn).verifyServerCertificate", - "sync.(*Once).Do", - "sync.(*Once).doSlow", - "crypto/x509.initSystemRoots", - "crypto/x509.loadSystemRoots", - "crypto/x509.(*CertPool).addCertFunc", - "crypto/x509.(*CertPool).AppendCertsFromPEM", - "encoding/pem.Decode" - ], - "levels": [ - [0, 449319704, 0, 0], - [ - 0, 1049448, 0, 87, 0, 526338, 0, 85, 0, 524336, 0, 83, 0, 868520, 0, 70, - 0, 524312, 0, 59, 0, 666237, 0, 53, 0, 525319, 0, 39, 0, 438337897, 0, - 16, 0, 2099200, 0, 14, 0, 3673601, 0, 5, 0, 524496, 0, 1 - ], - [ - 0, 1049448, 0, 88, 0, 526338, 526338, 86, 0, 524336, 524336, 84, 0, - 868520, 0, 71, 0, 524312, 0, 60, 0, 666237, 0, 54, 0, 263169, 263169, - 52, 0, 262150, 0, 40, 0, 437813433, 0, 20, 0, 524464, 0, 17, 0, 2099200, - 0, 15, 0, 3673601, 0, 6, 0, 524496, 0, 2 - ], - [ - 0, 1049448, 0, 89, 1050674, 606348, 0, 80, 0, 262172, 0, 72, 0, 524312, - 0, 61, 0, 666237, 0, 55, 263169, 262150, 0, 41, 0, 524368, 0, 33, 0, - 437289065, 0, 21, 0, 524464, 0, 17, 0, 2099200, 0, 8, 0, 3673601, 0, 7, - 0, 524496, 0, 3 - ], - [ - 0, 1049448, 0, 90, 1050674, 606348, 0, 81, 0, 262172, 0, 73, 0, 524312, - 0, 62, 0, 666237, 0, 56, 263169, 262150, 0, 42, 0, 524368, 0, 34, 0, - 437289065, 0, 22, 0, 524464, 0, 17, 0, 2099200, 0, 9, 0, 3673601, 0, 8, - 0, 524496, 524496, 4 - ], - [ - 0, 1049448, 0, 91, 1050674, 606348, 606348, 82, 0, 262172, 0, 74, 0, - 524312, 0, 63, 0, 666237, 0, 57, 263169, 262150, 0, 43, 0, 524368, 0, - 35, 0, 437289065, 0, 23, 0, 524464, 0, 17, 0, 2099200, 0, 10, 0, - 3673601, 0, 9 - ], - [ - 0, 1049448, 0, 92, 1657022, 262172, 0, 75, 0, 524312, 0, 64, 0, 666237, - 666237, 58, 263169, 262150, 0, 41, 0, 524368, 0, 36, 0, 437289065, 0, - 24, 0, 524464, 0, 17, 0, 2099200, 0, 11, 0, 3673601, 0, 10 - ], - [ - 0, 1049448, 0, 93, 1657022, 262172, 0, 76, 0, 524312, 0, 65, 929406, - 262150, 0, 41, 0, 524368, 0, 37, 0, 437289065, 0, 25, 0, 524464, 0, 18, - 0, 2099200, 0, 12, 0, 3673601, 0, 11 - ], - [ - 0, 1049448, 0, 94, 1657022, 262172, 0, 77, 0, 524312, 0, 66, 929406, - 262150, 0, 44, 0, 524368, 524368, 38, 0, 437289065, 0, 26, 0, 524464, - 524464, 19, 0, 2099200, 2099200, 13, 0, 3673601, 0, 12 - ], - [ - 0, 1049448, 0, 95, 1657022, 262172, 0, 78, 0, 524312, 0, 67, 929406, - 262150, 0, 45, 524368, 437289065, 0, 27, 2623664, 3673601, 3673601, 13 - ], - [ - 0, 1049448, 0, 96, 1657022, 262172, 262172, 79, 0, 524312, 0, 68, - 929406, 262150, 0, 46, 524368, 437289065, 0, 28 - ], - [ - 0, 525056, 0, 98, 0, 524392, 524392, 97, 1919194, 524312, 524312, 69, - 929406, 262150, 0, 41, 524368, 437289065, 0, 29 - ], - [ - 0, 525056, 525056, 99, 3897304, 262150, 0, 41, 524368, 436752394, - 528394, 31, 0, 536671, 536671, 30 - ], - [4422360, 262150, 0, 47, 1052762, 436224000, 436224000, 32], - [4422360, 262150, 0, 48], - [4422360, 262150, 0, 49], - [4422360, 262150, 0, 50], - [4422360, 262150, 262150, 51] - ], - "numTicks": 449319704, - "maxSelf": 436224000, - "spyName": "gospy", - "sampleRate": 100, - "units": "bytes", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "bytes" - }, - "timeline": { - "startTime": 1632505880, - "samples": [450187206, 448452204], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/render.json b/og/cypress/fixtures/render.json deleted file mode 100644 index 0c2daf3fae..0000000000 --- a/og/cypress/fixtures/render.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "flamebearer": { - "names": [ - "function_0", - "function_1", - "function_2", - "function_3", - "function_4", - "function_5", - "function_6" - ], - "levels": [ - [32, 508, 500, 0], - [82, 50, 135, 1], - [32, 508, 10, 2], - [12, 8, 100, 2], - [32, 32, 47, 3], - [320, 50, 100, 3], - [11, 375, 320, 4], - [74, 298, 70, 5], - [77, 111, 55, 6] - ], - "numTicks": 50, - "maxSelf": 58, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "sampleRate": 100, - "spyName": "gospy", - "units": "samples", - "format": "single" - }, - "timeline": { - "startTime": 1631138160, - "samples": [1, 3, 1, 2, 2, 4, 2, 3, 1, 1, 3, 4], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/render2.json b/og/cypress/fixtures/render2.json deleted file mode 100644 index 0ecd740fb9..0000000000 --- a/og/cypress/fixtures/render2.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "flamebearer": { - "names": [ - "cpu_function_0", - "cpu_function_1", - "cpu_function_2", - "cpu_function_3" - ], - "levels": [ - [32, 508, 100, 0], - [32, 508, 100, 1], - [32, 508, 100, 2], - [32, 508, 100, 2], - [32, 508, 100, 3] - ], - "numTicks": 50, - "maxSelf": 58, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples" - }, - "metadata": { - "sampleRate": 100, - "spyName": "gospy", - "units": "samples" - }, - "timeline": { - "startTime": 1631138160, - "samples": [1, 3, 1, 2, 2, 4, 2, 3, 1, 1, 3, 4], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/shipping-service-go-cpu.json b/og/cypress/fixtures/shipping-service-go-cpu.json deleted file mode 100644 index eb1bb8a937..0000000000 --- a/og/cypress/fixtures/shipping-service-go-cpu.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime.mstart", - "runtime.mstart1", - "runtime.templateThread", - "runtime.notesleep", - "runtime.futexsleep", - "runtime.futex", - "runtime.sysmon", - "runtime.usleep", - "runtime.unlockWithRank", - "runtime.unlock2", - "runtime.notetsleep", - "runtime.notetsleep_internal", - "runtime.mcall", - "runtime.park_m", - "runtime.schedule", - "runtime.findrunnable", - "runtime.stopm", - "runtime.netpoll", - "runtime.epollwait", - "runtime.checkTimers", - "runtime.runtimer", - "runtime.runOneTimer", - "runtime.bgscavenge.func1", - "runtime.wakeScavenger", - "runtime.injectglist", - "runtime.injectglist.func1", - "runtime.startm", - "runtime.notewakeup", - "runtime.futexwakeup", - "runtime.gcBgMarkWorker", - "runtime.systemstack", - "runtime.gcBgMarkWorker.func2", - "runtime.gcDrain", - "runtime.scanobject", - "runtime.pageIndexOf", - "runtime.markBits.isMarked", - "runtime.markroot", - "runtime.markroot.func1", - "runtime.suspendG", - "runtime.procyield", - "runtime.scanstack", - "runtime.gentraceback", - "runtime.(*gcWork).tryGet", - "runtime.bgscavenge", - "runtime.bgscavenge.func2", - "runtime.(*pageAlloc).scavenge", - "runtime.(*pageAlloc).scavengeOne", - "runtime.(*pageAlloc).scavengeRangeLocked", - "runtime.sysUnused", - "runtime.madvise", - "google.golang.org/grpc.(*Server).serveStreams.func1.2", - "google.golang.org/grpc.(*Server).handleStream", - "runtime.mapaccess2_faststr", - "google.golang.org/grpc.(*Server).processUnaryRPC", - "google.golang.org/grpc.recvAndDecompress", - "google.golang.org/grpc.(*parser).recvMsg", - "google.golang.org/grpc.(*Server).handleRawConn.func1", - "google.golang.org/grpc.(*Server).serveStreams", - "google.golang.org/grpc/internal/transport.(*http2Server).HandleStreams", - "golang.org/x/net/http2.(*Framer).ReadFrame", - "golang.org/x/net/http2.parseHeadersFrame", - "runtime.newobject", - "runtime.nextFreeFast", - "golang.org/x/net/http2.(*Framer).readMetaFrame", - "golang.org/x/net/http2/hpack.(*Decoder).Write", - "golang.org/x/net/http2/hpack.(*Decoder).parseHeaderFieldRepr", - "golang.org/x/net/http2/hpack.(*Decoder).parseFieldLiteral", - "golang.org/x/net/http2/hpack.(*Decoder).readString", - "golang.org/x/net/http2/hpack.huffmanDecode", - "golang.org/x/net/http2.(*Framer).checkFrameOrder", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/remote.(*Remote).handleJobs", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/remote.(*Remote).safeUpload", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Bytes", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Serialize", - "runtime.growslice", - "runtime.mallocgc", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot", - "runtime/pprof.writeHeap", - "runtime/pprof.writeHeapInternal", - "runtime/pprof.writeHeapProto", - "runtime/pprof.(*profileBuilder).build", - "compress/flate.(*Writer).Close", - "compress/flate.(*compressor).close", - "compress/flate.(*compressor).encSpeed", - "compress/flate.(*huffmanBitWriter).writeBlockDynamic", - "compress/flate.(*huffmanBitWriter).indexTokens", - "compress/flate.(*huffmanEncoder).generate", - "compress/flate.(*huffmanEncoder).bitCounts", - "runtime/pprof.(*profileBuilder).appendLocsForStack", - "runtime.mapaccess2_fast64", - "runtime.funcline", - "runtime.funcline1", - "runtime.pcvalue", - "runtime.step", - "github.com/pyroscope-io/pyroscope/pkg/convert.(*Profile).Get", - "github.com/pyroscope-io/pyroscope/pkg/convert.(*Profile).findFunctionName", - "github.com/pyroscope-io/pyroscope/pkg/convert.(*Profile).findLocation", - "sort.Search", - "github.com/pyroscope-io/pyroscope/pkg/convert.(*Profile).findLocation.func1", - "github.com/pyroscope-io/pyroscope/pkg/convert.(*Profile).findFunction", - "github.com/pyroscope-io/pyroscope/pkg/convert.(*Profile).findFunction.func1", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func3", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots.func1", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Insert", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.newTrieNode", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).findNodeAt", - "runtime.(*mcache).nextFree", - "runtime.(*mcache).refill", - "runtime.(*mcentral).uncacheSpan", - "runtime.(*spanSet).push", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).insert", - "runtime.gcAssistAlloc", - "runtime.gcAssistAlloc.func1", - "runtime.gcAssistAlloc1", - "runtime.gcDrainN", - "runtime.findObject", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile", - "io/ioutil.ReadAll", - "io/ioutil.readAll", - "bytes.(*Buffer).ReadFrom", - "compress/gzip.(*Reader).Read", - "compress/flate.(*decompressor).Read", - "compress/flate.(*dictDecoder).tryWriteCopy", - "compress/flate.(*decompressor).nextBlock", - "compress/flate.(*decompressor).huffmanBlock", - "compress/flate.(*decompressor).huffSym", - "runtime.asyncPreempt", - "bytes.(*Reader).ReadByte", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof", - "google.golang.org/protobuf/proto.Unmarshal", - "google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer", - "google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo", - "reflect.New", - "reflect.unsafe_New", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).reset", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).uploadTries", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Diff" - ], - "levels": [ - [0, 57, 0, 0], - [ - 0, 27, 0, 77, 0, 1, 0, 71, 0, 3, 0, 57, 0, 2, 0, 51, 0, 2, 0, 44, 0, 5, - 0, 30, 0, 11, 0, 13, 0, 6, 0, 1 - ], - [ - 0, 1, 0, 138, 0, 26, 0, 78, 0, 1, 0, 72, 0, 3, 0, 58, 0, 2, 0, 52, 0, 2, - 0, 31, 0, 5, 0, 31, 0, 11, 0, 14, 0, 6, 0, 2 - ], - [ - 0, 1, 0, 139, 0, 4, 0, 118, 0, 19, 2, 96, 0, 3, 0, 79, 0, 1, 0, 73, 0, - 3, 0, 59, 0, 1, 0, 54, 0, 1, 1, 53, 0, 2, 0, 45, 0, 5, 0, 32, 0, 11, 0, - 15, 0, 5, 0, 7, 0, 1, 0, 3 - ], - [ - 0, 1, 0, 140, 0, 1, 0, 130, 0, 3, 0, 119, 2, 8, 0, 103, 0, 9, 1, 97, 0, - 3, 0, 80, 0, 1, 0, 74, 0, 3, 0, 60, 0, 1, 0, 55, 1, 2, 0, 46, 0, 5, 0, - 33, 0, 11, 0, 16, 0, 1, 0, 11, 0, 1, 0, 9, 0, 3, 3, 8, 0, 1, 0, 4 - ], - [ - 0, 1, 0, 107, 0, 1, 0, 131, 0, 3, 0, 120, 2, 8, 0, 104, 1, 4, 0, 101, 0, - 4, 0, 98, 0, 3, 0, 81, 0, 1, 0, 75, 0, 1, 1, 70, 0, 1, 0, 64, 0, 1, 0, - 61, 0, 1, 1, 56, 1, 2, 0, 47, 0, 1, 1, 43, 0, 2, 0, 37, 0, 2, 0, 34, 0, - 2, 0, 20, 0, 7, 1, 18, 0, 2, 0, 17, 0, 1, 0, 12, 0, 1, 1, 10, 3, 1, 0, 5 - ], - [ - 0, 1, 1, 76, 0, 1, 0, 132, 0, 3, 0, 121, 2, 8, 0, 105, 1, 4, 0, 99, 0, - 4, 0, 99, 0, 1, 0, 92, 0, 1, 0, 90, 0, 1, 0, 82, 0, 1, 1, 76, 1, 1, 0, - 65, 0, 1, 0, 62, 2, 2, 0, 48, 1, 2, 0, 38, 0, 1, 1, 36, 0, 1, 1, 35, 0, - 2, 0, 21, 1, 6, 6, 19, 0, 2, 0, 4, 0, 1, 0, 5, 4, 1, 1, 6 - ], - [ - 1, 1, 0, 133, 0, 3, 0, 122, 2, 7, 5, 107, 0, 1, 1, 106, 1, 4, 4, 102, 0, - 4, 4, 100, 0, 1, 0, 93, 0, 1, 1, 91, 0, 1, 0, 83, 2, 1, 0, 66, 0, 1, 1, - 63, 2, 2, 0, 49, 1, 1, 0, 41, 0, 1, 0, 39, 2, 2, 0, 22, 7, 2, 0, 5, 0, - 1, 1, 6 - ], - [ - 1, 1, 0, 134, 0, 3, 0, 123, 7, 1, 0, 112, 0, 1, 0, 76, 10, 1, 0, 94, 1, - 1, 0, 84, 2, 1, 0, 67, 3, 2, 2, 50, 1, 1, 1, 42, 0, 1, 1, 40, 2, 2, 0, - 23, 7, 2, 2, 6 - ], - [ - 1, 1, 0, 135, 0, 1, 0, 126, 0, 1, 0, 125, 0, 1, 1, 124, 7, 1, 0, 62, 0, - 1, 0, 108, 10, 1, 1, 95, 1, 1, 0, 85, 2, 1, 0, 68, 10, 2, 0, 24 - ], - [ - 1, 1, 0, 136, 0, 1, 0, 127, 0, 1, 0, 126, 8, 1, 0, 76, 0, 1, 0, 109, 12, - 1, 0, 86, 2, 1, 1, 69, 10, 2, 0, 25 - ], - [ - 1, 1, 0, 137, 0, 1, 1, 129, 0, 1, 0, 127, 8, 1, 0, 113, 0, 1, 0, 110, - 12, 1, 0, 87, 13, 2, 0, 26 - ], - [ - 1, 1, 1, 76, 1, 1, 1, 128, 8, 1, 0, 31, 0, 1, 1, 111, 12, 1, 0, 88, 13, - 2, 0, 27 - ], - [12, 1, 0, 114, 13, 1, 1, 89, 13, 2, 0, 28], - [12, 1, 0, 115, 27, 2, 0, 29], - [12, 1, 0, 116, 27, 2, 2, 6], - [12, 1, 0, 34], - [12, 1, 1, 117] - ], - "numTicks": 57, - "maxSelf": 6, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "samples" - }, - "timeline": { - "startTime": 1634591500, - "samples": [12, 16, 16, 17], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-dotnet-app-cpu.json b/og/cypress/fixtures/simple-dotnet-app-cpu.json deleted file mode 100644 index d7b522a596..0000000000 --- a/og/cypress/fixtures/simple-dotnet-app-cpu.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "example!Example.Program.Main(class System.String[])", - "example!Slow.Work..ctor()", - "example!Fast.Work..ctor()" - ], - "levels": [ - [0, 45, 0, 0], - [0, 45, 0, 1], - [0, 10, 10, 3, 0, 35, 35, 2] - ], - "numTicks": 45, - "maxSelf": 35, - "spyName": "dotnetspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "dotnetspy", - "units": "samples" - }, - "timeline": { - "startTime": 1632504460, - "samples": [0, 46], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-golang-app-cpu-diff.json b/og/cypress/fixtures/simple-golang-app-cpu-diff.json deleted file mode 100644 index 8d3b1ddb1a..0000000000 --- a/og/cypress/fixtures/simple-golang-app-cpu-diff.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "leftTicks": 991, - "rightTicks": 987, - "flamebearer": { - "names": [ - "total", - "runtime.main", - "main.main", - "main.becomesAdded", - "main.becomesSlower", - "main.work", - "runtime.asyncPreempt", - "main.becomesFaster", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/remote.(*Remote).handleJobs", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/remote.(*Remote).safeUpload", - "net/http.(*Client).Do", - "net/http.(*Client).do", - "net/http.(*Client).send", - "net/http.send", - "net/http.(*Transport).RoundTrip", - "net/http.setupRewindBody", - "runtime.newobject", - "runtime.mallocgc", - "runtime.arenaIndex", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "runtime.heapBitsSetType" - ], - "levels": [ - [0, 991, 0, 0, 987, 0, 0], - [0, 0, 0, 0, 1, 0, 19, 0, 0, 0, 0, 1, 0, 8, 0, 991, 0, 0, 985, 0, 1], - [ - 0, 0, 0, 0, 1, 0, 16, 0, 0, 0, 0, 1, 0, 9, 0, 217, 0, 0, 229, 0, 3, 0, - 165, 0, 0, 147, 0, 7, 0, 603, 1, 0, 604, 0, 4, 0, 6, 6, 0, 5, 4, 2 - ], - [ - 0, 0, 0, 0, 1, 0, 17, 0, 0, 0, 0, 1, 0, 10, 0, 217, 217, 0, 229, 229, 5, - 0, 165, 165, 0, 147, 147, 5, 1, 602, 601, 0, 604, 604, 5, 6, 0, 0, 4, 1, - 1, 3 - ], - [0, 0, 0, 0, 1, 1, 20, 0, 0, 0, 0, 1, 0, 11, 984, 1, 1, 980, 0, 0, 6], - [0, 0, 0, 1, 1, 0, 12], - [0, 0, 0, 1, 1, 0, 13], - [0, 0, 0, 1, 1, 0, 14], - [0, 0, 0, 1, 1, 0, 15], - [0, 0, 0, 1, 1, 0, 16], - [0, 0, 0, 1, 1, 0, 17], - [0, 0, 0, 1, 1, 1, 18] - ], - "numTicks": 1978, - "maxSelf": 604, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples", - "format": "double" - }, - "metadata": { - "format": "double", - "sampleRate": 100, - "spyName": "gospy", - "units": "samples" - }, - "timeline": { - "startTime": 1633024290, - "samples": [992, 988], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-golang-app-cpu.json b/og/cypress/fixtures/simple-golang-app-cpu.json deleted file mode 100644 index 1230bf0600..0000000000 --- a/og/cypress/fixtures/simple-golang-app-cpu.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime.main", - "main.slowFunction", - "main.work", - "main.main", - "main.fastFunction" - ], - "levels": [ - [0, 988, 0, 0], - [0, 988, 0, 1], - [0, 214, 0, 5, 0, 3, 2, 4, 0, 771, 0, 2], - [0, 214, 214, 3, 2, 1, 1, 5, 0, 771, 771, 3] - ], - "numTicks": 988, - "maxSelf": 771, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "samples" - }, - "timeline": { - "startTime": 1632335270, - "samples": [989], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-golang-app-cpu2.json b/og/cypress/fixtures/simple-golang-app-cpu2.json deleted file mode 100644 index 680aec5dce..0000000000 --- a/og/cypress/fixtures/simple-golang-app-cpu2.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime.main", - "main.main", - "main.becomesSlower", - "main.work", - "runtime.asyncPreempt", - "main.becomesFaster", - "main.becomesAdded" - ], - "levels": [ - [0, 991, 0, 0], - [0, 991, 0, 1], - [0, 217, 0, 7, 0, 165, 0, 6, 0, 603, 1, 3, 0, 6, 6, 2], - [0, 217, 217, 4, 0, 165, 165, 4, 1, 602, 601, 4], - [984, 1, 1, 5] - ], - "numTicks": 991, - "maxSelf": 601, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "samples" - }, - "timeline": { - "startTime": 1633024290, - "samples": [992], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-java-app-cpu.json b/og/cypress/fixtures/simple-java-app-cpu.json deleted file mode 100644 index 582e61d98b..0000000000 --- a/og/cypress/fixtures/simple-java-app-cpu.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "java/lang/Thread.run", - "io/pyroscope/javaagent/Uploader.run", - "io/pyroscope/javaagent/Uploader.uploadSnapshot", - "io/pyroscope/javaagent/Uploader.sendRequest", - "sun/net/www/protocol/http/HttpURLConnection.getOutputStream", - "sun/net/www/protocol/http/HttpURLConnection.getOutputStream0", - "sun/net/www/protocol/http/HttpURLConnection.connect", - "sun/net/www/protocol/http/HttpURLConnection.plainConnect", - "sun/net/www/protocol/http/HttpURLConnection.plainConnect0", - "sun/net/www/protocol/http/HttpURLConnection.getNewHttpClient", - "sun/net/NetworkClient.\u003cclinit\u003e", - "sun/net/NetworkClient.isASCIISuperset", - "java/util/Arrays.equals", - "jdk/internal/util/ArraysSupport.\u003cclinit\u003e", - "jdk/internal/util/ArraysSupport.exactLog2", - "Main.main", - "Main.work", - "Main.slowFunction", - "Main.fastFunction" - ], - "levels": [ - [0, 990, 0, 0], - [0, 2, 2, 19, 0, 987, 766, 16, 0, 1, 0, 1], - [768, 84, 43, 19, 0, 106, 68, 18, 0, 31, 31, 17, 0, 1, 0, 2], - [811, 41, 41, 17, 68, 38, 38, 17, 31, 1, 0, 3], - [989, 1, 0, 4], - [989, 1, 0, 5], - [989, 1, 0, 6], - [989, 1, 0, 7], - [989, 1, 0, 8], - [989, 1, 0, 9], - [989, 1, 0, 10], - [989, 1, 0, 11], - [989, 1, 0, 12], - [989, 1, 0, 13], - [989, 1, 0, 14], - [989, 1, 1, 15] - ], - "numTicks": 990, - "maxSelf": 766, - "spyName": "javaspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "javaspy", - "units": "samples" - }, - "timeline": { - "startTime": 1632504610, - "samples": [991], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-php-app-cpu.json b/og/cypress/fixtures/simple-php-app-cpu.json deleted file mode 100644 index a10a699de9..0000000000 --- a/og/cypress/fixtures/simple-php-app-cpu.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "flamebearer": { - "names": ["total", "\u003cinternal\u003e - sleep"], - "levels": [ - [0, 1, 0, 0], - [0, 1, 1, 1] - ], - "numTicks": 1, - "maxSelf": 1, - "spyName": "phpspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "phpspy", - "units": "samples" - }, - "timeline": { - "startTime": 1632504370, - "samples": [0, 2], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-python-app-cpu.json b/og/cypress/fixtures/simple-python-app-cpu.json deleted file mode 100644 index b24fa2d915..0000000000 --- a/og/cypress/fixtures/simple-python-app-cpu.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "main.py:26 - \u003cmodule\u003e", - "main.py:21 - slow_function", - "pyroscope_io/__init__.py:80 - set_tag", - "main.py:11 - work", - "main.py:10 - work", - "main.py:20 - slow_function", - "main.py:19 - slow_function", - "main.py:25 - \u003cmodule\u003e", - "main.py:16 - fast_function", - "main.py:15 - fast_function", - "main.py:14 - fast_function" - ], - "levels": [ - [0, 1000, 0, 0], - [0, 202, 0, 8, 0, 798, 0, 1], - [ - 0, 2, 0, 11, 0, 144, 0, 10, 0, 56, 0, 9, 0, 1, 0, 7, 0, 745, 0, 6, 0, - 52, 0, 2 - ], - [ - 0, 2, 2, 3, 0, 65, 65, 5, 0, 79, 79, 4, 0, 2, 2, 5, 0, 2, 2, 4, 0, 52, - 52, 3, 0, 1, 1, 3, 0, 320, 320, 5, 0, 425, 425, 4, 0, 1, 1, 5, 0, 1, 1, - 4, 0, 50, 50, 3 - ] - ], - "numTicks": 1000, - "maxSelf": 425, - "spyName": "pyspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "pyspy", - "units": "samples" - }, - "timeline": { - "startTime": 1632504210, - "samples": [1001], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/simple-ruby-app-cpu.json b/og/cypress/fixtures/simple-ruby-app-cpu.json deleted file mode 100644 index c9e50102d9..0000000000 --- a/og/cypress/fixtures/simple-ruby-app-cpu.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "main.rb:29 - \u003cmain\u003e", - "main.rb:25 - slow_function", - "main.rb:13 - work", - "gems/pyroscope-0.0.23/lib/pyroscope.rb:31 - set_tag", - "(unknown):0 - _set_tag [c function]", - "main.rb:19 - fast_function" - ], - "levels": [ - [0, 1941, 0, 0], - [0, 1941, 0, 1], - [0, 404, 1, 6, 0, 1537, 0, 2], - [1, 53, 6, 4, 0, 350, 350, 3, 0, 36, 4, 4, 0, 1501, 1501, 3], - [7, 47, 47, 5, 354, 32, 32, 5] - ], - "numTicks": 1941, - "maxSelf": 1501, - "spyName": "rbspy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "rbspy", - "units": "samples" - }, - "timeline": { - "startTime": 1632504320, - "samples": [942, 1001], - "durationDelta": 10 - }, - "groups": {} -} diff --git a/og/cypress/fixtures/targets.json b/og/cypress/fixtures/targets.json deleted file mode 100644 index 029b598cc7..0000000000 --- a/og/cypress/fixtures/targets.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "job": "testing", - "url": "http://nodejs:3000/debug/pprof/profile?seconds=10", - "discoveredLabels": { - "__address__": "nodejs:3000", - "__name__": "nodejs", - "__scheme__": "http", - "__scrape_interval__": "10s", - "__scrape_timeout__": "15s", - "env": "dev", - "job": "testing" - }, - "labels": { - "__name__": "nodejs", - "env": "dev", - "instance": "nodejs:3000", - "job": "testing" - }, - "health": "up", - "lastScrape": "2022-04-08T12:27:08.090385573Z", - "lastError": "", - "lastScrapeDuration": "65.224655ms" - } -] diff --git a/og/cypress/integration/auth/api.ts b/og/cypress/integration/auth/api.ts deleted file mode 100644 index 113aa3b4b5..0000000000 --- a/og/cypress/integration/auth/api.ts +++ /dev/null @@ -1,30 +0,0 @@ -// few tests just to quickly validate the endpoints are working -describe('unauth API tests', () => { - it('it should respond with 401 on unauthorized access', () => { - cy.request({ - method: 'GET', - url: '/render?from=now-5m&until=now&query=pyroscope.server.alloc_objects%7B%7D&format=json', - failOnStatusCode: false, - }) - .its('status') - .should('eq', 401); - }); - - it('it should respond with 200 on login and signup', () => { - cy.request({ - method: 'GET', - url: '/login', - failOnStatusCode: false, - }) - .its('status') - .should('eq', 200); - - cy.request({ - method: 'GET', - url: '/signup', - failOnStatusCode: false, - }) - .its('status') - .should('eq', 200); - }); -}); diff --git a/og/cypress/integration/auth/cypress.json b/og/cypress/integration/auth/cypress.json deleted file mode 100644 index 306ed72424..0000000000 --- a/og/cypress/integration/auth/cypress.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "video": false, - "baseUrl": "http://localhost:4040", - "integrationFolder": "cypress/integration/auth", - "testFiles": "*.ts", - "retries": { - "runMode": 1 - } -} diff --git a/og/cypress/integration/auth/intro.ts b/og/cypress/integration/auth/intro.ts deleted file mode 100644 index 928138ee0e..0000000000 --- a/og/cypress/integration/auth/intro.ts +++ /dev/null @@ -1,18 +0,0 @@ -describe('misc pages', () => { - it('should correctly display 404 page', () => { - cy.visit('/404', { failOnStatusCode: false }); - cy.get('h1').should('contain', 'This page does not exist'); - }); - - it('should redirect back to requested page after logging in', () => { - cy.visit('/comparison'); - // it should redirect back to login - cy.url().should('contain', '/login'); - // Enter credentials - cy.get('input#username').focus().type('admin'); - cy.get('input#password').focus().type('admin'); - cy.get('button.sign-in-button').click(); - - cy.url().should('contain', '/comparison'); - }); -}); diff --git a/og/cypress/integration/auth/oauth.ts b/og/cypress/integration/auth/oauth.ts deleted file mode 100644 index e1b5900887..0000000000 --- a/og/cypress/integration/auth/oauth.ts +++ /dev/null @@ -1,34 +0,0 @@ -describe('oauth with mock enabled', () => { - beforeEach(() => { - cy.clearCookies(); - }); - it('should correctly display buttons on login page', () => { - cy.visit('/login'); - - cy.get('#gitlab-link').should('be.visible'); - cy.get('#google-link').should('not.exist'); - cy.get('#github-link').should('not.exist'); - - cy.get('#gitlab-link').click(); - - // When accessing /login directly we should be redirected to the root - cy.location().should((loc) => { - const removeTrailingSlash = (url: string) => url.replace(/\/+$/, ''); - - const basePath = new URL(Cypress.config().baseUrl).pathname; - - expect(removeTrailingSlash(loc.pathname)).to.eq( - removeTrailingSlash(basePath) - ); - }); - - cy.intercept('/api/user'); - - cy.findByTestId('sidebar-settings').click(); - - cy.findByText('Change Password').should('not.exist'); - - cy.get('li.pro-menu-item').contains('Sign out').click({ force: true }); - cy.url().should('contain', '/login'); - }); -}); diff --git a/og/cypress/integration/auth/settings.ts b/og/cypress/integration/auth/settings.ts deleted file mode 100644 index 4dd6372f42..0000000000 --- a/og/cypress/integration/auth/settings.ts +++ /dev/null @@ -1,110 +0,0 @@ -// few tests just to quickly validate the endpoints are working -describe('Settings page', () => { - it('should display error when log in with random creds', () => { - cy.visit('/login'); - - cy.get('input#username').focus().type('random'); - cy.get('input#password').focus().type('user'); - cy.get('button.sign-in-button').click(); - cy.get('#error').should('contain.text', 'invalid credentials'); - // Expect it not to be redirected to main page - cy.url().should('contain', '/login'); - }); - - it('should be able to log in with default creds', () => { - cy.visit('/login'); - - cy.get('input#username').focus().type('admin'); - cy.get('input#password').focus().type('admin'); - cy.get('button.sign-in-button').click(); - - // Expect it to be redirected to main page - cy.url().should('contain', '/?query='); - - cy.visit('/logout'); - }); - - it.only('should be able to see correct settings page', () => { - cy.visit('/login'); - - cy.get('input#username').focus().type('admin'); - cy.get('input#password').focus().type('admin'); - cy.findByTestId('sign-in-button').click(); - - cy.findByTestId('sidebar-settings').click(); - cy.url().should('contain', '/settings'); - - cy.findByTestId('settings-userstab').click(); - - cy.url().should('contain', '/settings/users'); - - // Two users should be displayed - cy.findByTestId('table-ui').get('tbody>tr').should('have.length', 2); - cy.findByTestId('table-ui') - .get('tbody > tr:nth-child(1)') - .should('contain.text', 'admin@localhost'); - - cy.findByTestId('settings-adduser').click(); - cy.url().should('contain', '/settings/users/add'); - - cy.get('#userAddName').type('user'); - cy.get('#userAddPassword').type('user'); - cy.get('#userAddEmail').type('user@domain.com'); - cy.get('#userAddFullName').type('Readonly User'); - cy.findByTestId('settings-useradd').click(); - - cy.url().should('contain', '/settings/users'); - - // Two users should be displayed - cy.findByTestId('table-ui').get('tbody>tr').should('have.length', 3); - cy.findByTestId('table-ui') - .get('tbody>tr:nth-child(3)') - .should('contain.text', 'user@domain.com'); - - cy.visit('/logout'); - cy.visit('/login'); - - cy.get('input#username').focus().type('user'); - cy.get('input#password').focus().type('user'); - cy.findByTestId('sign-in-button').click(); - - // Expect it to be redirected to main page - cy.url().should('contain', '/?query='); - - cy.visit('/logout'); - }); - - it.only('should be able to change password', () => { - cy.visit('/login'); - - cy.get('input#username').focus().type('user'); - cy.get('input#password').focus().type('user'); - cy.findByTestId('sign-in-button').click(); - - cy.findByTestId('sidebar-settings').click(); - cy.url().should('contain', '/settings'); - - cy.findByText('Change Password').click(); - cy.url().should('contain', '/settings/security'); - - cy.get('input[name="oldPassword"]').focus().type('user'); - cy.get('input[name="password"]').focus().type('pass'); - cy.get('input[name="passwordAgain"]').focus().type('pass'); - - cy.get('button').findByText('Save').click(); - - cy.findByText('Password has been successfully changed').should( - 'be.visible' - ); - - cy.visit('/logout'); - cy.visit('/login'); - - cy.get('input#username').focus().type('user'); - cy.get('input#password').focus().type('pass'); - cy.findByTestId('sign-in-button').click(); - - cy.findByTestId('sidebar-settings').click(); - cy.url().should('contain', '/settings'); - }); -}); diff --git a/og/cypress/integration/webapp/annotations.ts b/og/cypress/integration/webapp/annotations.ts deleted file mode 100644 index 3ca5e2fd0c..0000000000 --- a/og/cypress/integration/webapp/annotations.ts +++ /dev/null @@ -1,51 +0,0 @@ -describe('Annotations', () => { - it('add annotation flow works as expected', () => { - const basePath = Cypress.env('basePath') || ''; - cy.intercept(`${basePath}**/labels*`).as('labels'); - cy.intercept(`${basePath}/api/apps`, { - fixture: 'appNames.json', - }).as('appNames'); - cy.intercept('**/render*', { - fixture: 'render.json', - }).as('render'); - - cy.visit('/'); - - cy.wait('@labels'); - cy.wait('@appNames'); - cy.wait('@render'); - - cy.get('canvas.flot-overlay').click(); - - cy.get('li[role=menuitem]').contains('Add annotation').click(); - - const content = 'test'; - let time; - - cy.get('form#annotation-form') - .findByTestId('annotation_timestamp_input') - .invoke('val') - .then((sometext) => (time = sometext)); - - cy.get('form#annotation-form') - .findByTestId('annotation_content_input') - .type(content); - - cy.get('button[form=annotation-form]').click(); - - cy.get('div[data-testid="annotation_mark_wrapper"]').click(); - - cy.get('form#annotation-form') - .findByTestId('annotation_content_input') - .should('have.value', content); - - cy.get('form#annotation-form') - .findByTestId('annotation_timestamp_input') - .invoke('val') - .then((sometext2) => assert.isTrue(sometext2 === time)); - - cy.get('button[form=annotation-form]').contains('Close').click(); - - cy.get('form#annotation-form').should('not.exist'); - }); -}); diff --git a/og/cypress/integration/webapp/api.ts b/og/cypress/integration/webapp/api.ts deleted file mode 100644 index de3aefa82f..0000000000 --- a/og/cypress/integration/webapp/api.ts +++ /dev/null @@ -1,37 +0,0 @@ -// few tests just to quickly validate the endpoints are working -describe('API tests', () => { - it('tests /render endpoint', () => { - cy.request( - 'GET', - '/render?from=now-5m&until=now&query=pyroscope.server.alloc_objects%7B%7D&format=json' - ) - .its('headers') - .its('content-type') - .should('include', 'application/json'); - }); - - it('tests /labels endpoint', () => { - // TODO - // this is not returning json - cy.request('GET', '/labels?query=pyroscope.server.alloc_objects'); - // .its('headers') - // .its('content-type') - // .should('include', 'application/json'); - }); - - it('tests /render-diff endpoint', () => { - cy.request( - 'GET', - 'http://localhost:4040/comparison-diff?query=pyroscope.server.cpu%7B%7D&rightQuery=pyroscope.server.cpu%7B%7D&leftQuery=pyroscope.server.cpu%7B%7D&leftFrom=1648154123&leftUntil=1648154128&rightFrom=1648154123&rightUntil=1648154129&from=1648154091&until=1648154131' - ); - }); - - it('tests 404 custom page', () => { - cy.request({ url: '/my-404-page', failOnStatusCode: false }) - .its('status') - .should('equal', 404); - - cy.visit({ url: '/my-404-page', failOnStatusCode: false }); - cy.get('.pyroscope-app').should('contain.text', 'does not exist'); - }); -}); diff --git a/og/cypress/integration/webapp/basic.ts b/og/cypress/integration/webapp/basic.ts deleted file mode 100644 index d48c43d89c..0000000000 --- a/og/cypress/integration/webapp/basic.ts +++ /dev/null @@ -1,419 +0,0 @@ -const BAR_HEIGHT = 21.5; - -// / -describe('basic test', () => { - beforeEach(function () { - const basePath = Cypress.env('basePath') || ''; - - cy.intercept(`${basePath}/api/apps`, { - fixture: 'appNames.json', - }).as('appNames'); - }); - - it('changes app via the application dropdown', () => { - cy.visit('/'); - cy.wait(`@appNames`); - - cy.get('.navbar').findAllByTestId('toggler').click(); - - // For some reason couldn't find the appropriate query - cy.findAllByRole('menuitem').then((items) => { - items.each((i, item) => { - if (item.innerText.includes('pyroscope.server.inuse_space')) { - item.click(); - } - }); - }); - - cy.location().then((loc) => { - const queryParams = new URLSearchParams(loc.search); - expect(queryParams.get('query')).to.eq('pyroscope.server.inuse_space{}'); - }); - }); - - it('view buttons should change view when clicked', () => { - // mock data since the first preselected application - // could have no data - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu.json', - times: 1, - }).as('render1'); - - cy.visit('/'); - - cy.findByTestId('table').click(); - cy.findByTestId('table-ui').should('be.visible'); - cy.findByTestId('flamegraph-view').should('not.exist'); - - cy.findByTestId('both').click(); - cy.findByTestId('table-ui').should('be.visible'); - cy.findByTestId('flamegraph-view').should('be.visible'); - - cy.findByTestId('flamegraph').click(); - cy.findByTestId('table-ui').should('not.exist'); - cy.findByTestId('flamegraph-view').should('be.visible'); - }); - - // TODO make this a unit test - it('sorting works', () => { - /** - * @param row 'first' | 'last' - * @param column 'location' | 'self' | 'total' - */ - - const columns = { - location: { - index: 1, - selector: '.symbol-name', - }, - self: { - index: 2, - selector: 'span', - }, - total: { - index: 3, - selector: 'span', - }, - }; - - const sortColumn = (columnIndex) => - cy - .findByTestId('table-ui') - .find(`thead > tr > :nth-child(${columnIndex})`) - .click(); - - const getCellContent = (row, column) => { - const query = `tbody > :nth-child(${row}) > :nth-child(${column.index})`; - return cy - .findByTestId('table-ui') - .find(query) - .then((cell) => cell[0].innerText); - }; - - cy.intercept('**/render*', { - fixture: 'render.json', - times: 1, - }).as('render'); - - cy.visit('/'); - - cy.findByTestId('table-ui') - .find('tbody > tr') - .then((rows) => { - const first = 1; - const last = rows.length; - - // sort by location desc - sortColumn(columns.location.index); - getCellContent(first, columns.location).should('eq', 'function_6'); - getCellContent(last, columns.location).should('eq', 'function_0'); - - // sort by location asc - sortColumn(columns.location.index); - getCellContent(first, columns.location).should('eq', 'function_0'); - getCellContent(last, columns.location).should('eq', 'function_6'); - - // sort by self desc - sortColumn(columns.self.index); - getCellContent(first, columns.self).should('eq', '5.00 seconds'); - getCellContent(last, columns.self).should('eq', '0.55 seconds'); - - // sort by self asc - sortColumn(columns.self.index); - getCellContent(first, columns.self).should('eq', '0.55 seconds'); - getCellContent(last, columns.self).should('eq', '5.00 seconds'); - - // sort by total desc - sortColumn(columns.total.index); - getCellContent(first, columns.total).should('eq', '5.16 seconds'); - getCellContent(last, columns.total).should('eq', '0.50 seconds'); - - // sort by total asc - sortColumn(columns.total.index); - getCellContent(first, columns.total).should('eq', '0.50 seconds'); - getCellContent(last, columns.total).should('eq', '5.16 seconds'); - }); - }); - - it('validates "Reset View" button works', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu.json', - }).as('render'); - - cy.visit('/'); - - cy.findByRole('button', { name: /Reset/ }).should('be.disabled'); - cy.waitForFlamegraphToRender().click(0, BAR_HEIGHT * 2); - cy.findByRole('button', { name: /Reset/ }).should('not.be.disabled'); - cy.findByRole('button', { name: /Reset/ }).click(); - cy.findByRole('button', { name: /Reset/ }).should('be.disabled'); - }); - - describe('tooltip', () => { - // on smaller screens component will be collapsed by default - beforeEach(() => { - cy.viewport(1440, 900); - }); - it('flamegraph tooltip works in single view', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu.json', - }).as('render'); - - cy.visit('/'); - - cy.findAllByTestId('tooltip').should('not.be.visible'); - - cy.waitForFlamegraphToRender().trigger('mousemove'); - - cy.findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('be.visible'); - - cy.findByTestId('tooltip-title').should('have.text', 'total'); - cy.findByTestId('tooltip-table').should( - 'have.text', - 'Share of CPU:100%CPU Time:9.88 secondsSamples:988' - ); - - cy.waitForFlamegraphToRender().trigger('mouseout'); - cy.findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('not.be.visible'); - }); - - it('flamegraph tooltip works in comparison view', () => { - const findFlamegraph = (n: number) => { - const query = `> :nth-child(${n})`; - - return cy.findByTestId('comparison-container').find(query); - }; - - cy.intercept('**/render*from=1633024300&until=1633024300*', { - fixture: 'simple-golang-app-cpu.json', - times: 1, - }).as('render-right'); - - cy.intercept('**/render*from=1633024290&until=1633024290*', { - fixture: 'simple-golang-app-cpu2.json', - times: 1, - }).as('render-left'); - - cy.visit( - '/comparison?query=simple.golang.app.cpu%7B%7D&from=1633024298&until=1633024302&leftFrom=1633024290&leftUntil=1633024290&rightFrom=1633024300&rightUntil=1633024300' - ); - - cy.wait('@render-right'); - cy.wait('@render-left'); - - // flamegraph 1 (the left one) - cy.log('left flamegraph'); - findFlamegraph(1) - .findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('not.be.visible'); - - findFlamegraph(1).waitForFlamegraphToRender().trigger('mousemove'); - - findFlamegraph(1) - .findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('have.css', 'visibility', 'visible'); - - findFlamegraph(1) - .findByTestId('tooltip-title') - .should('have.text', 'total'); - findFlamegraph(1) - .findByTestId('tooltip-table') - .should( - 'have.text', - 'Share of CPU:100%CPU Time:9.91 secondsSamples:991' - ); - - findFlamegraph(1).waitForFlamegraphToRender().trigger('mousemove'); - findFlamegraph(1).waitForFlamegraphToRender().trigger('mouseout'); - - findFlamegraph(1) - .findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('not.be.visible'); - - // flamegraph 2 (right one) - cy.log('right flamegraph'); - findFlamegraph(2) - .findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('not.be.visible'); - - findFlamegraph(2).waitForFlamegraphToRender().trigger('mousemove', 0, 0, { - force: true, - }); - - findFlamegraph(2) - .findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('have.css', 'visibility', 'visible'); - - findFlamegraph(2) - .findByTestId('tooltip-title') - .should('have.text', 'total'); - findFlamegraph(2) - .findByTestId('tooltip-table') - .should( - 'have.text', - 'Share of CPU:100%CPU Time:9.88 secondsSamples:988' - ); - - findFlamegraph(2) - .waitForFlamegraphToRender() - .trigger('mouseout', { force: true }); - findFlamegraph(2) - .findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('not.be.visible'); - }); - - it('flamegraph tooltip works in diff view', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu-diff.json', - times: 3, - }).as('render'); - - cy.visit( - '/comparison-diff?query=testapp%7B%7D&rightQuery=testapp%7B%7D&leftQuery=testapp%7B%7D&leftFrom=1&leftUntil=1&rightFrom=1&rightUntil=1&from=now-5m' - ); - - cy.wait('@render'); - cy.wait('@render'); - cy.wait('@render'); - - cy.waitForFlamegraphToRender(); - - // This test has a race condition, since it does not wait for the canvas to be rendered - cy.findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('not.be.visible'); - - cy.waitForFlamegraphToRender().trigger('mousemove', 0, 0); - cy.findByTestId('flamegraph-view') - .findByTestId('tooltip') - .should('have.css', 'visibility', 'visible'); - - cy.findByTestId('tooltip-title').should('have.text', 'total'); - cy.findByTestId('tooltip-table').should( - 'have.text', - 'BaselineComparisonDiffShare of CPU:100%100%CPU Time:9.91 seconds9.87 secondsSamples:991987' - ); - }); - - it('table tooltip works in single view', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu.json', - times: 3, - }).as('render'); - - cy.visit('/'); - - cy.wait('@render'); - - cy.findByTestId('table-view') - .findByTestId('tooltip') - .should('not.be.visible'); - - cy.findByTestId('table-view').trigger('mousemove', 150, 80); - cy.findByTestId('table-view') - .findByTestId('tooltip') - .should('have.css', 'visibility', 'visible'); - - cy.findByTestId('tooltip-table').should( - 'have.text', - 'Self (% of total CPU)Total (% of total CPU)CPU Time:0.02 seconds(0.20%)0.03 seconds(0.30%)' - ); - }); - - it('table tooltip works in diff view', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu-diff.json', - times: 3, - }).as('render'); - - cy.visit( - '/comparison-diff?query=testapp%7B%7D&rightQuery=testapp%7B%7D&leftQuery=testapp%7B%7D&leftFrom=1&leftUntil=1&rightFrom=1&rightUntil=1&from=now-5m' - ); - - cy.wait('@render'); - - cy.findByTestId('table-view') - .findByTestId('tooltip') - .should('not.be.visible'); - - cy.findByTestId('table-view').trigger('mousemove', 150, 80); - cy.findByTestId('table-view') - .findByTestId('tooltip') - .should('have.css', 'visibility', 'visible'); - - cy.findByTestId('tooltip-table').should( - 'have.text', - 'BaselineComparisonDiffShare of CPU:100%99.8%(-0.20%)CPU Time:9.91 seconds9.85 secondsSamples:991985' - ); - }); - }); - - describe('highlight', () => { - it('works in diff view', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu-diff.json', - times: 1, - }).as('render'); - - cy.visit( - '/comparison-diff?query=simple.golang.app.cpu%7B%7D&from=1633024298&until=1633024302&leftFrom=1633024290&leftUntil=1633024290&rightFrom=1633024300&rightUntil=1633024300' - ); - - cy.wait('@render'); - - cy.findByTestId('flamegraph-highlight').should('not.be.visible'); - - cy.wait(500); - - cy.waitForFlamegraphToRender().trigger('mousemove', 0, 0); - cy.findByTestId('flamegraph-highlight').should('be.visible'); - }); - }); - - describe('contextmenu', () => { - it("it works when 'clear view' is clicked", () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu.json', - times: 1, - }).as('render'); - - cy.visit('/'); - - // until we focus on a specific, it should not be enabled - cy.waitForFlamegraphToRender().rightclick(); - cy.findByRole('menuitem', { name: /Reset View/ }).should( - 'have.attr', - 'aria-disabled', - 'true' - ); - - // click on the second item - cy.waitForFlamegraphToRender().click(0, BAR_HEIGHT * 2); - cy.waitForFlamegraphToRender().rightclick(); - cy.findByRole('menuitem', { name: /Reset View/ }).should( - 'not.have.attr', - 'aria-disabled' - ); - cy.findByRole('menuitem', { name: /Reset View/ }).click(); - // TODO assert that it was indeed reset? - - // should be disabled again - cy.waitForFlamegraphToRender().rightclick(); - cy.findByRole('menuitem', { name: /Reset View/ }).should( - 'have.attr', - 'aria-disabled', - 'true' - ); - }); - }); -}); diff --git a/og/cypress/integration/webapp/e2e.ts b/og/cypress/integration/webapp/e2e.ts deleted file mode 100644 index 84f9dc3db9..0000000000 --- a/og/cypress/integration/webapp/e2e.ts +++ /dev/null @@ -1,135 +0,0 @@ -// Following tests should have NO mocking involved. -// The objective involve validating server/webapp interaction is working correctly - -import * as moment from 'moment'; - -function randomName() { - const letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - const num = 5; - - return Array(num) - .fill(0) - .map(() => letters.substr(Math.floor(Math.random() * num + 1), 1)) - .join(''); -} - -// assume this is probably the first app when ordered alphabetically -const firstApp = '0'; - -describe('E2E Tests', () => { - // TODO: - // instead of generating a new application - // delete the old one? - let appName = ''; - // use a fixed time IN THE DAY so that the hours in the timeline are always the same - const t0 = moment().startOf('day').unix(); - const t1 = moment().startOf('day').add(3, 'minutes').unix(); - const t2 = moment().startOf('day').add(5, 'minutes').unix(); - const t3 = moment().startOf('day').add(6, 'minutes').unix(); - const t4 = moment().startOf('day').add(10, 'minutes').unix(); - - before(() => { - appName = randomName(); - - // populate the db with 2 items - // - // it's important that they are recent - // otherwise the database may just drop them - // if they are older than the retention date - - cy.request({ - method: 'POST', - url: `/ingest?name=${firstApp}&sampleRate=100&from=${t1}&until=${t1}`, - body: 'foo;bar 100', - }); - - cy.request({ - method: 'POST', - url: `/ingest?name=${appName}&sampleRate=100&from=${t1}&until=${t1}`, - body: 'foo;bar 100', - }); - - cy.request({ - method: 'POST', - url: `/ingest?name=${appName}&sampleRate=100&from=${t3}&until=${t3}`, - body: 'foo;bar;baz 10', - }); - }); - - it('tests single view', () => { - const params = new URLSearchParams(); - params.set('query', appName); - params.set('from', t0); - params.set('until', t4); - - cy.visit(`/?${params.toString()}`); - - cy.waitForFlamegraphToRender(); - }); - - it('tests /comparison view', () => { - const params = new URLSearchParams(); - params.set('query', appName); - params.set('from', t0); - params.set('until', t4); - params.set('leftFrom', t0); - params.set('leftUntil', t2); - params.set('rightFrom', t2); - params.set('rightTo', t4); - - cy.visit(`/comparison?${params.toString()}`); - - const findFlamegraph = (n: number) => { - const query = `> :nth-child(${n})`; - - return cy.findByTestId('comparison-container').find(query); - }; - - // flamegraph 1 (the left one) - findFlamegraph(1).waitForFlamegraphToRender(); - - // flamegraph 2 (the right one) - findFlamegraph(2).waitForFlamegraphToRender(); - }); - - it('tests /explore view', () => { - const params = new URLSearchParams(); - params.set('query', appName); - params.set('from', t0); - params.set('until', t4); - - cy.visit('/'); - cy.findByTestId('collapse-sidebar').click(); - cy.findByTestId('sidebar-explore-page').click(); - - cy.findByTestId('explore-header'); - cy.findByTestId('timeline-explore-page'); - cy.findByTestId('explore-table'); - }); - - it('works with standalone view', () => { - const params = new URLSearchParams(); - params.set('query', appName); - params.set('from', t0); - params.set('until', t4); - params.set('leftFrom', t0); - params.set('leftUntil', t2); - params.set('rightFrom', t2); - params.set('rightTo', t4); - params.set('format', 'html'); - - cy.visit(`/render?${params.toString()}`); - cy.findByTestId('flamegraph-canvas'); - }); - - // This is tested as an e2e test - // Since the list of app names comes populated from the database - it('sets the first app as the query if nothing is set', () => { - cy.visit('/'); - - cy.location().should((loc) => { - const params = new URLSearchParams(loc.search); - expect(params.get('query')).to.eq(`${firstApp}{}`); - }); - }); -}); diff --git a/og/cypress/integration/webapp/pages.ts b/og/cypress/integration/webapp/pages.ts deleted file mode 100644 index 5f0a888d51..0000000000 --- a/og/cypress/integration/webapp/pages.ts +++ /dev/null @@ -1,66 +0,0 @@ -// These tests currently only cover the existence of the main components -// Such as timeline, flamegraph etc -describe('pages', () => { - it('loads / (single) correctly', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu.json', - }).as('render'); - - cy.visit('/'); - - cy.findByTestId('flamegraph-canvas'); - cy.findByTestId('timeline-single'); - }); - - it.only('loads /comparison correctly', () => { - cy.intercept('**/render*from=1633024298&until=1633024302*', { - fixture: 'simple-golang-app-cpu.json', - times: 1, - }).as('render-main-timeline'); - - cy.intercept('**/render*from=1633024300&until=1633024300*', { - fixture: 'simple-golang-app-cpu.json', - times: 1, - }).as('render-right'); - - cy.intercept('**/render*from=1633024290&until=1633024290*', { - fixture: 'simple-golang-app-cpu2.json', - times: 1, - }).as('render-left'); - - cy.visit( - '/comparison?query=simple.golang.app.cpu%7B%7D&from=1633024298&until=1633024302&leftFrom=1633024290&leftUntil=1633024290&rightFrom=1633024300&rightUntil=1633024300' - ); - - cy.wait('@render-right'); - cy.wait('@render-left'); - cy.wait('@render-main-timeline'); - - cy.findByTestId('timeline-main'); - cy.findByTestId('timeline-left'); - cy.findByTestId('timeline-right'); - - // There should be 2 canvas there - cy.findAllByTestId('flamegraph-canvas').should('have.length', 2); - }); - - it('loads /comparison-diff correctly', () => { - cy.intercept('**/render*', { - fixture: 'simple-golang-app-cpu-diff.json', - times: 1, - }).as('render'); - - cy.visit( - '/comparison-diff?query=simple.golang.app.cpu%7B%7D&from=1633024298&until=1633024302&leftFrom=1633024290&leftUntil=1633024290&rightFrom=1633024300&rightUntil=1633024300' - ); - - cy.wait('@render'); - - // there are 3 timelines - cy.findByTestId('timeline-main'); - cy.findByTestId('timeline-left'); - cy.findByTestId('timeline-right'); - - cy.findByTestId('flamegraph-canvas'); - }); -}); diff --git a/og/cypress/integration/webapp/routes.ts b/og/cypress/integration/webapp/routes.ts deleted file mode 100644 index d7c0b4e38e..0000000000 --- a/og/cypress/integration/webapp/routes.ts +++ /dev/null @@ -1,36 +0,0 @@ -describe('QueryParams', () => { - // on smaller screens component will be collapsed by default - beforeEach(() => { - cy.viewport(1440, 900); - }); - - // type a tag so that it's synced to the URL - // IMPORTANT! don't access the url directly since it will render this test useless - // since we are testing populating the queryParams and maintaining between routes - it('maintains queryParams when changing route', () => { - const myTag = 'myrandomtag{}'; - const validate = () => { - cy.location().then((loc) => { - const urlParams = new URLSearchParams(loc.search); - expect(urlParams.get('query')).to.eq(myTag); - }); - }; - - cy.visit('/'); - cy.get(`[aria-label="query-input"] textarea`).clear().type(myTag); - cy.get(`[aria-label="query-input"] button`).click(); - validate(); - - cy.findByTestId('sidebar-continuous-comparison').click(); - validate(); - - cy.findByTestId('sidebar-continuous-diff').click(); - validate(); - - cy.findByTestId('sidebar-continuous-single').click(); - validate(); - - cy.findByTestId('sidebar-explore-page').click(); - validate(); - }); -}); diff --git a/og/cypress/integration/webapp/serviceDiscovery.ts b/og/cypress/integration/webapp/serviceDiscovery.ts deleted file mode 100644 index cb4466b719..0000000000 --- a/og/cypress/integration/webapp/serviceDiscovery.ts +++ /dev/null @@ -1,16 +0,0 @@ -describe('service discovery page', () => { - it('works', () => { - const basePath = Cypress.env('basePath') || ''; - cy.intercept(`${basePath}/targets`, { - fixture: 'targets.json', - }).as('targets'); - - cy.visit('/service-discovery'); - cy.wait('@targets'); - - // one for the header and another for the content - cy.findAllByRole('row').should('have.length', 2); - - cy.findByText('http://nodejs:3000/debug/pprof/profile?seconds=10'); - }); -}); diff --git a/og/cypress/integration/webapp/sidebar.ts b/og/cypress/integration/webapp/sidebar.ts deleted file mode 100644 index 97949fc9ef..0000000000 --- a/og/cypress/integration/webapp/sidebar.ts +++ /dev/null @@ -1,69 +0,0 @@ -describe('sidebar', () => { - describe('not collapsed', () => { - // on smaller screens component will be collapsed by default - beforeEach(() => { - cy.viewport(1440, 900); - }); - - it('internal sidebar links work', () => { - cy.visit('/'); - - cy.findByTestId('sidebar-continuous-comparison').click(); - - const basePath = Cypress.env('basePath') || ''; - cy.location('pathname').should('eq', `${basePath}/comparison`); - - cy.findByTestId('sidebar-continuous-diff').click(); - cy.location('pathname').should('eq', `${basePath}/comparison-diff`); - - cy.findByTestId('sidebar-continuous-single').click(); - cy.location('pathname').should('eq', `${basePath}/`); - }); - }); - - describe('collapse/uncollapse', () => { - it('defaults to collapsed in smaller screens', () => { - cy.viewport(1000, 900); - cy.visit('/'); - cy.get('.app').find('.pro-sidebar').should('have.class', 'collapsed'); - }); - - it('defaults to uncollapsed in bigger screens', () => { - cy.viewport(1440, 900); - cy.visit('/'); - cy.get('.app').find('.pro-sidebar').should('not.have.class', 'collapsed'); - }); - - it('collapses when screen width changes', () => { - cy.viewport(1440, 900); - cy.visit('/'); - - cy.get('.app').find('.pro-sidebar').should('not.have.class', 'collapsed'); - - cy.viewport(1000, 900); - - cy.get('.app').find('.pro-sidebar').should('have.class', 'collapsed'); - }); - - describe('when user interacts', () => { - it('persists state across reloads', () => { - cy.viewport(1440, 900); - cy.visit('/'); - - cy.get('.app') - .find('.pro-sidebar') - .should('not.have.class', 'collapsed'); - cy.get('.app') - .find('.pro-sidebar') - .findByText('Collapse Sidebar') - .click(); - - cy.get('.app').find('.pro-sidebar').should('have.class', 'collapsed'); - - cy.reload(); - - cy.get('.app').find('.pro-sidebar').should('have.class', 'collapsed'); - }); - }); - }); -}); diff --git a/og/cypress/integration/webapp/timezone.ts b/og/cypress/integration/webapp/timezone.ts deleted file mode 100644 index 6e0126e308..0000000000 --- a/og/cypress/integration/webapp/timezone.ts +++ /dev/null @@ -1,51 +0,0 @@ -describe('timezone', () => { - describe('selector', () => { - it('disabled if local time = UTC', () => { - const diff = new Date().getTimezoneOffset(); - cy.visit('/'); - - cy.findByTestId('time-dropdown-button').click(); - - if (diff === 0) { - cy.get('#select-timezone').should('be.disabled'); - } else { - cy.get('#select-timezone').should('not.be.disabled'); - } - }); - - it('has correct values', () => { - cy.visit('/'); - - cy.findByTestId('time-dropdown-button').click(); - - cy.get('#select-timezone') - .select(0, { force: true }) - .should('have.value', String(new Date().getTimezoneOffset())); - - cy.get('#select-timezone') - .select(1, { force: true }) - .should('have.value', '0'); - }); - - it('changes what "until"-input renders on setting UTC/local time', () => { - cy.visit('/'); - cy.findByTestId('time-dropdown-button').click(); - cy.get('#datepicker-until') - .invoke('val') - .then((value) => { - const diff = new Date().getTimezoneOffset(); - cy.get('#select-timezone').select(1, { force: true }); - - if (diff !== 0) { - cy.get('#datepicker-until').should('not.have.value', value); - } else { - cy.get('#datepicker-until').should('have.value', value); - } - - cy.get('#select-timezone').select(0, { force: true }); - - cy.get('#datepicker-until').should('have.value', value); - }); - }); - }); -}); diff --git a/og/cypress/plugins/index.ts b/og/cypress/plugins/index.ts deleted file mode 100644 index 88fa8828e8..0000000000 --- a/og/cypress/plugins/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -// / -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) -import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin'; - -/** - * @type {Cypress.PluginConfig} - */ -// eslint-disable-next-line no-unused-vars -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config - addMatchImageSnapshotPlugin(on, config); - - // force color profile - on('before:browser:launch', (browser = {}, launchOptions) => { - if (browser.family === 'chromium' && browser.name !== 'electron') { - launchOptions.args.push('--force-color-profile=srgb'); - } - }); - - return config; -}; diff --git a/og/cypress/snapshots/basic.ts/grafana-simple-golang-app-cpu.snap.png b/og/cypress/snapshots/basic.ts/grafana-simple-golang-app-cpu.snap.png deleted file mode 100644 index 5b5c25badc..0000000000 Binary files a/og/cypress/snapshots/basic.ts/grafana-simple-golang-app-cpu.snap.png and /dev/null differ diff --git a/og/cypress/snapshots/basic.ts/simple-golang-app-cpu-highlight.snap.png b/og/cypress/snapshots/basic.ts/simple-golang-app-cpu-highlight.snap.png deleted file mode 100644 index b14b73ebaa..0000000000 Binary files a/og/cypress/snapshots/basic.ts/simple-golang-app-cpu-highlight.snap.png and /dev/null differ diff --git a/og/cypress/support/commands.js b/og/cypress/support/commands.js deleted file mode 100644 index 59a1e811ba..0000000000 --- a/og/cypress/support/commands.js +++ /dev/null @@ -1,67 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -import '@testing-library/cypress/add-commands'; - -import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command'; - -addMatchImageSnapshotCommand({ - failureThreshold: 0.15, - capture: 'viewport', -}); - -// We also overwrite the command, so it does not take a screenshot if we run the tests inside the test runner -Cypress.Commands.overwrite( - 'matchImageSnapshot', - (originalFn, snapshotName, options) => { - if (Cypress.env('COMPARE_SNAPSHOTS')) { - // wait a little bit - // that's to try to avoid blurry screenshots - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(500); - originalFn(snapshotName, options); - } else { - cy.log('Screenshot comparison is disabled'); - } - } -); - -// cy.findByTestId('my-container').get('waitForFlamegraphToRender') -// or -// cy.waitForFlamegraphToRender() -Cypress.Commands.add( - 'waitForFlamegraphToRender', - { prevSubject: 'optional' }, - ($element) => { - // it's important to use find/get since the caller requires a DOM element - if ($element) { - return cy - .wrap($element) - .find('[data-testid="flamegraph-canvas"][data-state="rendered"]'); - } - - return cy.get('[data-testid="flamegraph-canvas"][data-state="rendered"]'); - } -); diff --git a/og/cypress/support/index.js b/og/cypress/support/index.js deleted file mode 100644 index 37a498fb5b..0000000000 --- a/og/cypress/support/index.js +++ /dev/null @@ -1,20 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands'; - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/og/cypress/tsconfig.json b/og/cypress/tsconfig.json deleted file mode 100644 index 0ca312fddc..0000000000 --- a/og/cypress/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "target": "es2015", - "lib": ["es2015", "dom"], - "types": ["cypress", "@testing-library/cypress"] - }, - "include": ["**/*.ts"] -} diff --git a/og/docs/storage-design-ch.md b/og/docs/storage-design-ch.md deleted file mode 100644 index 957e8e68a9..0000000000 --- a/og/docs/storage-design-ch.md +++ /dev/null @@ -1,115 +0,0 @@ -![image](https://user-images.githubusercontent.com/23323466/110414341-8ad0c000-8044-11eb-9628-7b24e50295b2.png) - -# O(log n)让持续分析成为可能 - -Pyroscope是一种软件,可让你**持续地**分析代码以调试每行代码的性能问题。仅需几行代码,它即可执行以下操作: - -### Pyroscope客户端 -- 以0.01秒为单位检测堆栈跟踪,以查看哪些函数正在消耗资源 -- 将数据批量处理为10秒的数据块并发送给Pyroscope服务器 - -### Pyroscope服务器 -- 接收Pyroscope客户端发来的数据并对其进行处理以便高效存储 -- 对分析数据进行预汇总,以便在需要检索数据时能快速查询 - -## 存储效率 - -持续分析的挑战在于,如果你只是频繁地将分析数据块压缩并存储在某个地方,它将导致: -1. 太多数据以致无法有效存储 -2. 太多数据以致无法快速查询 - -我们可用以下方式解决这些问题: -1. 用字典树和树的组合来高效压缩数据 -2. 用线段树在O(log n)时间内返回任何时间段内的数据查询结果,而不是 O(n)的时间复杂度 - -## 步骤 1: 将分析数据转换为树 - -呈现分析数据的最简单方式是:在一个字符串列表中,每个字符串表示一个堆栈跟踪和该特定堆栈追踪在某个分析段中被看到的次数: - -```bash -server.py;fast_function;work 2 -server.py;slow_function;work 8 -``` - -我们要做的第一件事就是把这些数据转换为树。方便的是,该呈现方式也使后续生成火焰图变得更加容易。 - -![raw_vs_flame_graph](https://user-images.githubusercontent.com/23323466/110378930-0f065180-800b-11eb-9357-71724bc7258c.gif) - -将堆栈跟踪压缩为树可以在重复元素上节省空间。通过使用树,我们从原来的必须在数据库中多次存储诸如`net/http.request`之类的通用路径,到现在只需要存储该通用路径一次并保存它的存储位置的位置引用就可以了。这种存储方式在性能分析库中基本是标配,因为它是分析数据存储的优化中可最轻松实施的方法。 - -![fast-compress-stack-traces](https://user-images.githubusercontent.com/23323466/110227218-e109fb80-7eaa-11eb-81a8-cdf2b3944f1c.gif) - -## 步骤 2: 添加字典树以更有效地存储单个符号 - -目前,我们已通过转换为树来压缩原始分析数据,但该压缩树中有很多节点包含与其他节点共享重复元素的符号,例如: - -``` -net/http.request;net/io.read 100 samples -net/http.request;net/io.write 200 samples -``` - -尽管 `net/http.request`, `net/io.read`, 和`net/io.write`函数不同,但是`net/`是他们共同的祖先。 - -如下所示,每一行都可以使用前缀树的方式来序列化。这意味着不再需要多次存储相同的前缀,现在我们只需在字典树中存储它们一次,并通过储存内存地址的指针变量来访问它们: - -![storage-design-0](https://user-images.githubusercontent.com/23323466/110520399-446e7600-80c3-11eb-84e9-ecac7c0dbf23.gif) - -在这个基本示例中,我们从39字节减少到8字节,节省了约80%的空间。通常,符号名称要长得多,而且随着符号数量的增加,存储需求呈对数增长而非线性增长。 - -## 步骤 1 + 2: 将树和字典树结合 - -最后,通过使用树来压缩原始分析数据,然后使用字典树来压缩符号,我们基础示例的存储空间如下: - -``` -| 数据类型 | 字节 | -|---------------------|-------| -| 原始数据 | 93 | -| 树 | 58 | -| 树 + 字典树 | 10 | -``` - -如你所见,对于该基础示例,这是一个9倍的改进。实际情景中,压缩因子会变得更大。 - -![combine-segment-and-prefix_1](https://user-images.githubusercontent.com/23323466/110262208-ca75aa00-7f67-11eb-8f16-0572a4641ee1.gif) - -## 步骤 3:使用线段树优化以便快速读取 - -现在,我们已经有了有效存储数据的方法,接下来的问题是如何高效地查询数据。我们解决该问题的方法是把分析数据预先汇总,并将其存储在一个特殊的线段树中。 - -每10秒,Pyroscope客户端就会发送一个分析数据块到服务器,该服务器将数据和其相应的时间戳写入数据库中。你将注意到,每次写入只发生一次,但会被复制多次。 - -**每一层代表一个更大单位的时间块,所以在这种情况下,每两个10秒的时间块将创建一个20秒的时间块。这是为了使读取数据更加高效 (稍后详细介绍)**。 - -![segment_tree_animation_1](https://user-images.githubusercontent.com/23323466/110259555-196a1200-7f5d-11eb-9223-218bb4b34c6b.gif) - -## 将读取从O(n)优化到O(log n) - -如果你不使用线段树,只是将10秒为单位的数据块写入数据库,读取数据的时间复杂度将是基于以10秒为单位的查询请求的一个函数。如果,你想要提取1年的数据,那么你必须合并用来呈现分析数据的3,154,000棵树。通过使用线段树,你可以有效地将合并操作的数量从O(n)减少到O(log n)。 - -![segment_tree_reads](https://user-images.githubusercontent.com/23323466/110277713-b98a6000-7f8a-11eb-942f-3a924a6e0b09.gif) - - -## 帮助我们添加更多分析工具 - -我们花了很多时间来解决存储/查询问题,因为我们希望可以让软件在生产环境中也能真正地进行持续性能分析,而且不会造成太多虚耗。 - -虽然,目前Pyroscope支持4种语言,但我们希望能添加更多语言。 - -任何能够以上面链接中的“原始”格式导出数据的采样分析器都有可能成为Pyroscope的分析客户端。我们热切地希望你能帮助我们开发其他语言的分析工具! - - -- [x] [Go](https://pyroscope.io/docs/golang) -- [x] [Python](https://pyroscope.io/docs/python) -- [x] [eBPF](https://pyroscope.io/docs/ebpf) -- [x] [Ruby](https://pyroscope.io/docs/ruby) -- [x] [PHP](https://pyroscope.io/docs/php) -- [x] [Java](https://pyroscope.io/docs/java) -- [x] [.NET](https://pyroscope.io/docs/dotnet) -- [ ] [Rust](https://github.com/pyroscope-io/pyroscope/issues/83#issuecomment-784947654) -- [ ] [Node](https://github.com/pyroscope-io/pyroscope/issues/8) - -如果你想做出贡献或需要Pyroscope设置方面的帮助,你可以通过以下方式联系我们: -- 加入我们的[Slack](https://pyroscope.io/slack) -- 通过[此链接](https://pyroscope.io/setup-call)与我们预约会面 -- 提交[问题报告](https://github.com/pyroscope-io/pyroscope/issues) -- 在[Twitter](https://twitter.com/PyroscopeIO)上关注我们 diff --git a/og/docs/storage-design.md b/og/docs/storage-design.md deleted file mode 100644 index 55f8465736..0000000000 --- a/og/docs/storage-design.md +++ /dev/null @@ -1,117 +0,0 @@ -![image](https://user-images.githubusercontent.com/23323466/110414341-8ad0c000-8044-11eb-9628-7b24e50295b2.png) - -# O(log n) makes continuous profiling possible - -#### _Read this in other languages._ -[中文 (Simplified)](storage-design-ch.md) - -Pyroscope is software that lets you **continuously** profile your code to debug performance issues down to a line of code. With just a few lines of code it will do the following: - -### Pyroscope Agent -- Polls the stack trace every 0.01 seconds to see which functions are consuming resources -- Batches that data into 10s blocks and sends it to Pyroscope server - -### Pyroscope Server -- Receives data from the Pyroscope agent and processes it to be stored efficiently -- Pre-aggregates profiling data for fast querying when data needs to be retrieved - -## Storage Efficiency - -The challenge with continuous profiling is that if you just take frequent chunks of profiling data, compress it, and store it somewhere, it becomes: -1. Too much data to store efficiently -2. Too much data to query quickly - -We solve these problems by: -1. Using a combination of tries and trees to compress data efficiently -2. Using segment trees to return queries for any timespan of data in O(log n) vs O(n) time complexity - -## Step 1: Turning the profiling data into a tree - -The simplest way to represent profiling data is in a list of string each one representing a stack trace and a number of times this particular stack trace was seen during a profiling session: - -```bash -server.py;fast_function;work 2 -server.py;slow_function;work 8 -``` - -The first obvious thing we do is we turn this data into a tree. Conveniently, this representation also makes it easy to later generate flamegraphs. - -![raw_vs_flame_graph](https://user-images.githubusercontent.com/23323466/110378930-0f065180-800b-11eb-9357-71724bc7258c.gif) - -Compressing the stack traces into trees saves space on repeated elements. By using trees, we go from having to store common paths like `net/http.request` in the db multiple times to only having to store it 1 time and saving a reference to the location at which it's located. This is fairly standard with profiling libraries since its the lowest hanging fruit when it comes to optimizing storage with profiling data. - -![fast-compress-stack-traces](https://user-images.githubusercontent.com/23323466/110227218-e109fb80-7eaa-11eb-81a8-cdf2b3944f1c.gif) - -## Step 2: Adding tries to store individual symbols more efficiently - -So now that we've compressed the raw profiling data by converting into a tree, many of the nodes in this compressed tree contain symbols that also share repeated elements with other nodes. For example: - -``` -net/http.request;net/io.read 100 samples -net/http.request;net/io.write 200 samples -``` - -While the `net/http.request`, `net/io.read`, and `net/io.write` functions differ they share the same common ancestor of `net/`. - -Each of these lines can be serialized using a prefix tree as follows. This means that instead of storing the same prefixes multiple times, we can now just store them once in a trie and access them by storing a pointer to their position in memory: - -![storage-design-0](https://user-images.githubusercontent.com/23323466/110520399-446e7600-80c3-11eb-84e9-ecac7c0dbf23.gif) - -In this basic example we save ~80% of space going from 39 bytes to 8 bytes. Typically, symbol names are much longer and as the number of symbols grows, storage requirements grow logarithmically rather than linearly. - -## Step 1 + 2: Combining the trees with the tries - -In the end, by using a tree to compress the raw profiling data and then using tries to compress the symbols we get the following storage amounts for our simple example: - -``` -| data type | bytes | -|---------------------|-------| -| raw data | 93 | -| tree | 58 | -| tree + trie | 10 | -``` - -As you can see this is a 9x improvement for a fairly trivial case. In real world scenarios the compression factor gets much larger. - -![combine-segment-and-prefix_1](https://user-images.githubusercontent.com/23323466/110262208-ca75aa00-7f67-11eb-8f16-0572a4641ee1.gif) - -## Step 3: Optimizing for fast reads using Segment Trees - -Now that we have a way of storing the data efficiently the next problem that arises is how do we query it efficiently. The way we solve this problem is by pre-aggregating the profiling data and storing it in a special segment tree. - -Every 10s Pyroscope agent sends a chunk of profiling data to the server which writes the data into the db with the corresponding timestamp. You'll notice that each write happens once, but is replicated multiple times. - -**Each layer represents a time block of larger units so in this case for every two 10s time blocks, one 20s time block is created. This is to make reading the data more efficient (more on that in a second)**. - -![segment_tree_animation_1](https://user-images.githubusercontent.com/23323466/110259555-196a1200-7f5d-11eb-9223-218bb4b34c6b.gif) - -## Turn reads from O(n) to O(log n) - -If you don't use segment trees and just write data in 10 second chunks the time complexity for the reads becomes a function of how many 10s units the query asks for. If you want 1 year of data, you'll have to then merge 3,154,000 trees representing the profiling data. By using segment trees you can effectively decrease the amount of merge operations from O(n) to O(log n). - -![segment_tree_reads](https://user-images.githubusercontent.com/23323466/110277713-b98a6000-7f8a-11eb-942f-3a924a6e0b09.gif) - - -## Help us add more profilers - -We spent a lot of time on solving this storage / querying problem because we wanted to make software that can do truly continuous profiling in production without causing too much overhead. - -While Pyroscope currently supports 4 languages, we would love to add more. - -Any sampling profiler that can export data in the "raw" format linked above can become a Profiling agent with Pyroscope. We'd love your help building out profilers for other languages! - -- [x] [Go](https://pyroscope.io/docs/golang) -- [x] [Python](https://pyroscope.io/docs/python) -- [x] [eBPF](https://pyroscope.io/docs/ebpf) -- [x] [Ruby](https://pyroscope.io/docs/ruby) -- [x] [PHP](https://pyroscope.io/docs/php) -- [x] [Java](https://pyroscope.io/docs/java) -- [x] [.NET](https://pyroscope.io/docs/dotnet) -- [ ] [Rust](https://github.com/pyroscope-io/pyroscope/issues/83#issuecomment-784947654) -- [ ] [Node](https://github.com/pyroscope-io/pyroscope/issues/8) - -If you want to help contribute or need help setting up Pyroscope here's how you can reach us: -- Join our [Slack](https://pyroscope.io/slack) -- Set up a time to meet with us [here](https://pyroscope.io/setup-call) -- Write an [issue](https://github.com/pyroscope-io/pyroscope/issues) -- Follow us on [Twitter](https://twitter.com/PyroscopeIO) diff --git a/og/example.json b/og/example.json deleted file mode 100644 index ac39ed1f3f..0000000000 --- a/og/example.json +++ /dev/null @@ -1,999 +0,0 @@ -{ - "flamebearer": { - "names": [ - "total", - "runtime/pprof.profileWriter", - "runtime/pprof.(*profileBuilder).addCPUData", - "runtime/pprof.(*profMap).lookup", - "runtime.makeslice", - "runtime.mallocgc", - "runtime.(*mcache).nextFree", - "runtime.(*mcache).refill", - "runtime.(*mcentral).cacheSpan", - "runtime.(*mcentral).grow", - "runtime.(*mheap).alloc", - "runtime.systemstack", - "runtime.(*mheap).alloc.func1", - "runtime.(*mheap).allocSpan", - "runtime.nanotime", - "runtime.mcall", - "runtime.park_m", - "runtime.unlockWithRank", - "runtime.unlock2", - "runtime.selparkcommit", - "runtime.schedule", - "runtime.runqempty", - "runtime.resetspinning", - "runtime.wakep", - "runtime.startm", - "runtime.pidleget", - "runtime.pMask.set", - "runtime.notewakeup", - "runtime.futexwakeup", - "runtime.futex", - "runtime.releasem", - "runtime.mget", - "runtime.lockWithRank", - "runtime.lock2", - "runtime.pMask.read", - "runtime.nobarrierWakeTime", - "runtime.netpollinited", - "runtime.nanotime1", - "runtime.procyield", - "runtime.gcMarkWorkAvailable", - "runtime.findrunnable", - "runtime.stopm", - "runtime.mput", - "runtime.checkdead", - "runtime.mPark", - "runtime.notesleep", - "runtime.futexsleep", - "runtime.mDoFixup", - "runtime.acquirep", - "runtime.wirep", - "runtime.(*mcache).prepareForSweep", - "runtime.(*mcache).releaseAll", - "runtime.(*mcentral).uncacheSpan", - "runtime.(*mspan).sweep", - "runtime.(*spanSet).push", - "runtime.runqsteal", - "runtime.runqgrab", - "runtime.usleep", - "runtime.runqget", - "runtime.releasep", - "runtime.pidleput", - "runtime.updateTimerPMask", - "runtime.netpoll", - "runtime.epollwait", - "runtime.checkTimers", - "runtime.runtimer", - "runtime.runOneTimer", - "time.sendTime", - "time.Now", - "time.now", - "runtime.walltime", - "runtime.walltime1", - "runtime.selectnbsend", - "runtime.chansend", - "runtime.send", - "runtime.goready", - "runtime.goready.func1", - "runtime.ready", - "runtime.runqput", - "runtime.casgstatus", - "runtime.(*guintptr).cas", - "runtime.acquirem", - "runtime.(*waitq).dequeue", - "runtime.siftdownTimer", - "runtime.adjusttimers", - "runtime.fastrand", - "runtime.execute", - "runtime.(*randomOrder).start", - "runtime.(*randomEnum).position", - "runtime.(*randomEnum).next", - "runtime.(*randomEnum).done", - "runtime.gcBgMarkWorker.func1", - "runtime.(*lfstack).push", - "runtime.gosched_m", - "runtime.goschedImpl", - "runtime.globrunqget", - "runtime.(*gQueue).pop", - "runtime.(*gQueue).pushBack", - "runtime.goexit0", - "runtime.gcBgMarkWorker", - "runtime.gcBgMarkWorker.func2", - "runtime.gcDrain", - "runtime.spanOfUnchecked", - "runtime.scanobject", - "runtime.spanOf", - "runtime.spanClass.noscan", - "runtime.pageIndexOf", - "runtime.markBits.isMarked", - "runtime.greyobject", - "runtime.findObject", - "runtime.arenaIndex", - "runtime.(*gcWork).putFast", - "runtime.(*gcBits).bytep", - "runtime.(*gcBits).bitp", - "runtime.heapBitsForAddr", - "runtime.heapBits.next", - "runtime.heapBits.bits", - "runtime.gcFlushBgCredit", - "runtime.add1", - "runtime.(*gcWork).tryGetFast", - "runtime.(*gcWork).tryGet", - "runtime.putempty", - "runtime.(*lfstack).pop", - "runtime.(*gcWork).balance", - "runtime.handoff", - "runtime.putfull", - "runtime.memmove", - "runtime.getempty", - "runtime.(*workbuf).checkempty", - "runtime.(*gcControllerState).enlistWorker", - "runtime.gcMarkDone", - "runtime.stopTheWorldWithSema", - "runtime.preemptall", - "runtime.gcMarkDone.func1", - "runtime.forEachP", - "runtime.gcMarkDone.func1.1", - "runtime.gcMarkTermination", - "runtime.gcMarkTermination.func4", - "runtime.gcMarkTermination.func4.1", - "runtime.bgsweep", - "runtime.sweepone", - "runtime.spanClass.sizeclass", - "runtime.(*headTailIndex).incTail", - "runtime.(*mspan).refillAllocCache", - "runtime.(*mheap).freeSpan", - "runtime.(*mheap).freeSpan.func1", - "runtime.(*mheap).freeSpanLocked", - "runtime.(*gcBitsArena).tryAlloc", - "runtime.(*mheap).nextSpanForSweep", - "runtime.(*spanSet).pop", - "runtime.(*headTailIndex).cas", - "runtime._System", - "runtime.gogo", - "net/http.(*persistConn).addTLS.func2", - "crypto/tls.(*Conn).Handshake", - "crypto/tls.(*Conn).clientHandshake", - "crypto/tls.(*clientHandshakeStateTLS13).handshake", - "crypto/tls.(*clientHandshakeStateTLS13).readServerCertificate", - "crypto/tls.(*Conn).verifyServerCertificate", - "sync.(*Once).Do", - "sync.(*Once).doSlow", - "crypto/x509.initSystemRoots", - "crypto/x509.loadSystemRoots", - "crypto/x509.(*CertPool).AppendCertsFromPEM", - "encoding/asn1.Unmarshal", - "encoding/asn1.UnmarshalWithParams", - "encoding/asn1.parseField", - "encoding/asn1.parseSequenceOf", - "reflect.StructTag.Get", - "reflect.StructTag.Lookup", - "crypto/x509.ParseCertificate", - "reflect.(*rtype).Field", - "runtime.duffcopy", - "crypto/x509.parseCertificate", - "crypto/tls.(*clientHandshakeState).handshake", - "crypto/tls.(*clientHandshakeState).doFullHandshake", - "crypto/tls.(*ecdheKeyAgreement).processServerKeyExchange", - "crypto/tls.generateECDHEParameters", - "crypto/elliptic.GenerateKey", - "crypto/elliptic.p256Curve.ScalarBaseMult", - "crypto/elliptic.initTable", - "crypto/elliptic.p256Inverse", - "crypto/elliptic.p256Sqr", - "net/http.(*conn).serve", - "net/http.serverHandler.ServeHTTP", - "net/http.HandlerFunc.ServeHTTP", - "github.com/klauspost/compress/gzhttp.NewWrapper.func1.1", - "net/http.(*ServeMux).ServeHTTP", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1", - "github.com/slok/go-http-metrics/middleware.Middleware.Measure", - "github.com/slok/go-http-metrics/middleware/std.Handler.func1.1", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).renderHandler", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Get", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Get", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).get", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Get.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Get.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).Lookup", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).get", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).GetOrSet", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).get.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage.treeCodec.Deserialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.Deserialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*Dict).GetValue", - "github.com/pyroscope-io/pyroscope/pkg/util/varint.Read", - "encoding/binary.ReadUvarint", - "bytes.(*Reader).ReadByte", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Merge", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*treeNode).insert", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).indexHandler.func1", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).renderIndexPage", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).GetAppNames", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).GetValues", - "github.com/pyroscope-io/pyroscope/pkg/storage/labels.(*Labels).GetValues", - "github.com/dgraph-io/badger/v2.(*DB).View", - "github.com/pyroscope-io/pyroscope/pkg/storage/labels.(*Labels).GetValues.func1", - "github.com/dgraph-io/badger/v2.(*Iterator).Next", - "github.com/dgraph-io/badger/v2.(*Iterator).parseItem", - "github.com/dgraph-io/badger/v2/table.(*MergeIterator).Next", - "github.com/dgraph-io/badger/v2/table.(*node).next", - "github.com/dgraph-io/badger/v2/table.(*node).setKey", - "github.com/dgraph-io/badger/v2/skl.(*Iterator).Key", - "net/http.(*response).finishRequest", - "bufio.(*Writer).Flush", - "net/http.(*chunkWriter).Write", - "net/http.(*chunkWriter).writeHeader", - "net/http.(*conn).readRequest", - "runtime.newobject", - "runtime.profilealloc", - "runtime.mProf_Malloc", - "runtime.callers", - "runtime.callers.func1", - "runtime.gentraceback", - "runtime.funcspdelta", - "runtime.pcvalue", - "net/http.readRequest", - "net/url.ParseRequestURI", - "net/url.parse", - "net/url.(*URL).setPath", - "net/url.unescape", - "golang.org/x/sync/errgroup.(*Group).Go.func1", - "github.com/pyroscope-io/pyroscope/pkg/cli.(*serverService).Start.func1", - "github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).Start", - "net/http.(*Server).ListenAndServe", - "net/http.(*Server).Serve", - "net.(*TCPListener).Accept", - "github.com/sirupsen/logrus.(*Entry).Debug", - "github.com/sirupsen/logrus.(*Entry).Log", - "github.com/sirupsen/logrus.Entry.log", - "github.com/sirupsen/logrus.(*Entry).write", - "github.com/sirupsen/logrus.(*TextFormatter).Format", - "github.com/sirupsen/logrus.(*TextFormatter).printColored", - "fmt.Sprintf", - "fmt.(*pp).doPrintf", - "fmt.(*pp).printArg", - "fmt.(*pp).fmtString", - "runtime.newstack", - "runtime.copystack", - "runtime.adjustframe", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.New.func2", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).saveToDisk", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).Set", - "runtime.mapaccess2_faststr", - "github.com/pyroscope-io/pyroscope/pkg/storage.treeCodec.Serialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).SerializeTruncate", - "runtime.growslice", - "runtime.heapBitsSetType", - "runtime.(*mspan).init", - "runtime.memclrNoHeapPointers", - "github.com/valyala/bytebufferpool.(*ByteBuffer).Write", - "github.com/pyroscope-io/pyroscope/pkg/structs/cappedarr.New", - "runtime.(*pageAlloc).alloc", - "runtime.(*pageAlloc).allocRange", - "runtime.(*pallocBits).allocRange", - "runtime.(*pageBits).setRange", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).minValue", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).iterateWithTotal", - "runtime.typedslicecopy", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).minValue.func1", - "github.com/pyroscope-io/pyroscope/pkg/structs/cappedarr.(*CappedArray).Push", - "sort.Search", - "github.com/pyroscope-io/pyroscope/pkg/structs/cappedarr.(*CappedArray).Push.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*Dict).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*trieNode).findNodeAt", - "runtime.nextFreeFast", - "github.com/pyroscope-io/pyroscope/pkg/util/varint.Writer.Write", - "bytes.(*Buffer).tryGrowByReslice", - "bytes.(*Buffer).Write", - "bytes.(*Buffer).grow", - "encoding/binary.PutUvarint", - "bytes.Equal", - "runtime.memequal", - "github.com/pyroscope-io/pyroscope/pkg/storage.segmentCodec.Serialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Serialize", - "runtime.roundupsize", - "runtime.pcdatavalue", - "runtime.heapBits.initSpan", - "runtime.(*pageCache).alloc", - "runtime.(*pageAlloc).allocToCache", - "runtime.(*pageAlloc).update", - "runtime.(*pallocBits).summarize", - "runtime.getMCache", - "runtime.(*mcache).allocLarge", - "runtime.(*mheap).allocMSpanLocked", - "runtime.(*fixalloc).alloc", - "github.com/pyroscope-io/pyroscope/pkg/util/serialization.WriteMetadata", - "encoding/json.Marshal", - "encoding/json.(*encodeState).marshal", - "encoding/json.(*encodeState).reflectValue", - "encoding/json.mapEncoder.encode", - "reflect.Value.MapIndex", - "reflect.mapaccess", - "github.com/pyroscope-io/pyroscope/pkg/storage.dictionaryCodec.Serialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*Dict).Serialize", - "runtime.(*consistentHeapStats).acquire", - "github.com/pyroscope-io/pyroscope/pkg/util/varint.Write", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload", - "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile", - "fmt.Fprintf", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Iterate", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Insert", - "bytes.Split", - "bytes.genSplit", - "bytes.IndexByte", - "indexbytebody", - "bytes.Count", - "countbody", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.ParseKey", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*parser).nameParserCase", - "runtime.concatstring2", - "runtime.concatstrings", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.NewRetentionPolicy", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).put", - "math/big.(*Rat).Float64", - "math/big.nat.make", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.prependTreeNode", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.newNode", - "bytes.Compare", - "cmpbody", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Clone", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*treeNode).clone", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Key).TreeKey", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.TreeKey", - "strconv.FormatInt", - "strconv.formatBits", - "runtime.slicebytetostring", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).GetOrCreate", - "bufio.(*Reader).ReadByte", - "github.com/pyroscope-io/pyroscope/pkg/storage.dictionaryCodec.Deserialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/dict.Deserialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).get.func1.1", - "runtime.rawstringtmp", - "runtime.rawstring", - "github.com/dgraph-io/badger/v2.(*Txn).Get", - "github.com/dgraph-io/badger/v2.(*DB).get", - "github.com/dgraph-io/badger/v2/skl.(*Skiplist).Get", - "github.com/dgraph-io/badger/v2.(*levelsController).get", - "github.com/dgraph-io/badger/v2.(*levelHandler).get", - "github.com/dgraph-io/badger/v2/table.(*Table).DoesNotHave", - "github.com/dgraph-io/ristretto/z.(*Bloom).IsSet", - "expvar.(*Map).Add", - "sync.(*Map).Load", - "runtime.mapaccess2", - "runtime.nilinterequal", - "github.com/dgraph-io/badger/v2.(*DB).getMemTables", - "github.com/pyroscope-io/pyroscope/pkg/storage/labels.(*Labels).Put", - "github.com/dgraph-io/badger/v2.(*DB).Update", - "github.com/dgraph-io/badger/v2.(*Txn).Commit", - "github.com/dgraph-io/badger/v2.(*Txn).commitAndSend", - "github.com/dgraph-io/badger/v2.(*DB).sendToWriteCh", - "sync.(*WaitGroup).state", - "github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).remEntry", - "runtime.mapdelete_fast64", - "github.com/pyroscope-io/pyroscope/pkg/storage.segmentCodec.Deserialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.newNode", - "runtime.step", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.Deserialize", - "github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).replace", - "container/list.(*List).insertValue", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots", - "runtime.selectgo", - "runtime.selunlock", - "runtime.sellock", - "runtime.releaseSudog", - "runtime.gopark", - "runtime.acquireSudog", - "runtime.mapiternext", - "runtime.mapiterinit", - "runtime.makemap_small", - "runtime.(*mspan).nextFreeIndex", - "runtime.heapBits.forwardOrBoundary", - "runtime.heapBits.forward", - "runtime.duffzero", - "runtime.(*waitq).enqueue", - "runtime.(*waitq).dequeueSudoG", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.numGC", - "runtime.ReadMemStats", - "runtime.ReadMemStats.func1", - "runtime.readmemstats_m", - "runtime.updatememstats", - "runtime.flushallmcaches", - "runtime.flushmcache", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot", - "sync.(*Mutex).Unlock", - "runtime/pprof.writeHeap", - "runtime/pprof.writeHeapInternal", - "strings.HasPrefix", - "runtime/pprof.writeHeapProto", - "runtime/pprof.newProfileBuilder", - "runtime/pprof.(*profileBuilder).readMapping", - "runtime/pprof.parseProcSelfMaps", - "runtime/pprof.parseProcSelfMaps.func1", - "runtime/pprof.elfBuildID", - "os.(*File).pread", - "internal/poll.(*FD).Pread", - "syscall.Pread", - "syscall.Syscall6", - "os.(*File).Close", - "os.(*file).close", - "runtime.SetFinalizer", - "os.ReadFile", - "os.(*File).read", - "syscall.Read", - "syscall.read", - "syscall.Syscall", - "runtime/pprof.(*profileBuilder).pbValueType", - "runtime/pprof.(*protobuf).varint", - "runtime/pprof.(*profileBuilder).pbSample", - "runtime/pprof.writeHeapProto.func1", - "runtime/pprof.(*profileBuilder).pbLabel", - "runtime/pprof.(*protobuf).int64Opt", - "runtime/pprof.(*protobuf).uint64s", - "runtime/pprof.(*protobuf).endMessage", - "runtime/pprof.(*profileBuilder).build", - "runtime/pprof.(*protobuf).string", - "compress/flate.(*Writer).Write", - "compress/flate.(*compressor).write", - "compress/flate.(*compressor).fillStore", - "compress/flate.(*Writer).Close", - "compress/flate.(*compressor).close", - "compress/flate.(*compressor).encSpeed", - "compress/flate.hash", - "compress/flate.(*huffmanBitWriter).writeBlockDynamic", - "compress/flate.token.length", - "compress/flate.lengthCode", - "compress/flate.(*huffmanBitWriter).writeTokens", - "compress/flate.(*huffmanBitWriter).writeCode", - "compress/flate.(*huffmanBitWriter).indexTokens", - "compress/flate.(*huffmanEncoder).generate", - "compress/flate.(*byLiteral).sort", - "sort.Sort", - "sort.quickSort", - "sort.doPivot", - "sort.insertionSort", - "compress/flate.byLiteral.Swap", - "compress/flate.(*byFreq).sort", - "compress/flate.(*deflateFast).encode", - "compress/flate.emitLiteral", - "compress/flate.(*deflateFast).matchLen", - "runtime/pprof.(*profileBuilder).appendLocsForStack", - "runtime/pprof.runtime_expandFinalInlineFrame", - "runtime/pprof.allFrames", - "runtime.divRoundUp", - "runtime.(*Frames).Next", - "runtime.pcdatavalue1", - "runtime.readvarint", - "runtime.gostringnocopy", - "runtime.findnull", - "runtime.funcline1", - "runtime/pprof.(*profileBuilder).stringIndex", - "runtime.mapassign_faststr", - "runtime.hashGrow", - "runtime.makeBucketArray", - "runtime.newarray", - "runtime/pprof.(*profileBuilder).emitLocation", - "runtime/pprof.(*profileBuilder).pbLine", - "runtime/pprof.(*profileBuilder).flush", - "compress/gzip.(*Writer).Write", - "compress/flate.NewWriter", - "compress/flate.newDeflateFast", - "runtime.(*pageAlloc).find", - "aeshashbody", - "runtime.mapassign_fast64", - "runtime.growWork_fast64", - "runtime.evacuate_fast64", - "runtime.mapaccess1_faststr", - "runtime.add", - "runtime.mapaccess2_fast64", - "runtime.CallersFrames", - "runtime.funcline", - "runtime.FuncForPC", - "runtime.funcdata", - "runtime.MemProfile", - "runtime.record", - "runtime.(*bucket).mp", - "runtime.GC", - "runtime.offAddr.lessThan", - "runtime.(*fixalloc).free", - "runtime.(*mspan).countAlloc", - "github.com/valyala/bytebufferpool.(*ByteBuffer).WriteString", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).Get", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*cache).pprofLabelsToSpyLabels", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.getCacheKey", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).findFunctionName", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).findLocation", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).findLocation.func1", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).findFunction", - "github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).findFunction.func1", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func3", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots.func1", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Insert", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.newTrieNode", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).findNodeAt", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).insert", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Insert.func1", - "github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile", - "io/ioutil.ReadAll", - "io.ReadAll", - "compress/gzip.(*Reader).Read", - "compress/flate.(*decompressor).Read", - "compress/flate.(*dictDecoder).writeByte", - "compress/flate.(*decompressor).nextBlock", - "compress/flate.(*decompressor).readHuffman", - "compress/flate.(*huffmanDecoder).init", - "compress/flate.(*decompressor).huffSym", - "compress/flate.(*decompressor).huffmanBlock", - "compress/flate.noEOF", - "github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof", - "google.golang.org/protobuf/proto.Unmarshal", - "google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal", - "google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer", - "google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo", - "reflect.New", - "reflect.unsafe_New", - "reflect.(*rtype).ptrTo", - "google.golang.org/protobuf/internal/impl.consumeUint64Slice", - "google.golang.org/protobuf/internal/impl.consumeUint64", - "reflect.(*rtype).typeOff", - "runtime.(*_type).typeOff", - "reflect.resolveTypeOff", - "google.golang.org/protobuf/encoding/protowire.ConsumeBytes", - "google.golang.org/protobuf/internal/impl.consumeInt64Slice", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).reset", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).uploadTries", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Diff", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Diff.func1", - "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).clone", - "github.com/pyroscope-io/pyroscope/pkg/agent.addSuffix", - "runtime.intstring", - "github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).isDueForReset", - "time.Time.Truncate", - "time.div", - "time.Time.Add", - "time.(*Time).addSec", - "time.(*Time).nsec", - "github.com/dgraph-io/badger/v2/y.(*WaterMark).process", - "runtime.typedmemmove", - "github.com/dgraph-io/badger/v2/y.(*WaterMark).process.func1", - "runtime.convT64", - "container/heap.Push", - "github.com/dgraph-io/badger/v2/y.(*uint64Heap).Push", - "github.com/dgraph-io/badger/v2.(*levelsController).runCompactor", - "github.com/dgraph-io/badger/v2.(*levelsController).pickCompactLevels", - "sync.(*RWMutex).RLock", - "sort.Slice", - "sort.quickSort_func", - "internal/reflectlite.escapes", - "internal/reflectlite.ValueOf", - "internal/reflectlite.Swapper", - "internal/reflectlite.Value.Len", - "github.com/dgraph-io/badger/v2.(*compactStatus).overlapsWith", - "github.com/dgraph-io/badger/v2.(*levelCompactStatus).overlapsWith", - "github.com/dgraph-io/badger/v2.(*compactStatus).delSize", - "sync.(*RWMutex).RUnlock", - "github.com/dgraph-io/badger/v2.(*levelsController).isLevel0Compactable", - "github.com/dgraph-io/badger/v2.(*levelHandler).numTables", - "github.com/dgraph-io/badger/v2.(*levelsController).doCompact", - "github.com/dgraph-io/badger/v2.(*levelsController).runCompactDef", - "github.com/dgraph-io/badger/v2.(*levelsController).compactBuildTables", - "github.com/dgraph-io/badger/v2/table.(*MergeIterator).Value", - "github.com/dgraph-io/badger/v2/table.(*Iterator).Next", - "github.com/dgraph-io/badger/v2/table.(*Iterator).next", - "github.com/dgraph-io/badger/v2/table.(*Table).block", - "github.com/dgraph-io/badger/v2/y.ZSTDDecompress", - "github.com/DataDog/zstd.Decompress", - "github.com/DataDog/zstd.Decompress.func1", - "github.com/DataDog/zstd._Cfunc_ZSTD_decompress_wrapper", - "runtime.cgocall", - "github.com/dgraph-io/badger/v2/table.(*MergeIterator).Key", - "github.com/dgraph-io/badger/v2.(*levelHandler).isCompactable", - "github.com/dgraph-io/badger/v2.(*levelHandler).getTotalSize", - "github.com/dgraph-io/badger/v2.(*DB).updateSize", - "github.com/dgraph-io/badger/v2.(*DB).calculateSize", - "expvar.(*Map).Set", - "sync.(*Map).Store", - "sync.(*entry).tryStore", - "github.com/dgraph-io/badger/v2.(*DB).doWrites.func1", - "github.com/dgraph-io/badger/v2.(*DB).writeRequests", - "sync.(*WaitGroup).Done", - "sync.(*WaitGroup).Add", - "sync.runtime_Semrelease", - "runtime.semrelease1", - "runtime.readyWithTime", - "github.com/dgraph-io/badger/v2.(*valueLog).write", - "github.com/dgraph-io/badger/v2/y.Check2", - "github.com/dgraph-io/badger/v2/y.Check", - "github.com/dgraph-io/badger/v2.(*valueLog).write.func2", - "github.com/dgraph-io/badger/v2.(*valueLog).write.func1", - "os.(*File).write", - "syscall.Write", - "syscall.write", - "github.com/dgraph-io/badger/v2.(*logFile).encodeEntry", - "hash/crc32.New", - "runtime.stackalloc", - "runtime.stackcacherefill", - "runtime.stackpoolalloc", - "runtime.getStackMap", - "runtime.adjustdefers", - "hash/crc32.(*digest).Write", - "hash/crc32.archUpdateCastagnoli", - "hash/crc32.castagnoliSSE42Triple", - "bytes.makeSlice", - "github.com/dgraph-io/badger/v2.(*DB).writeToLSM", - "github.com/dgraph-io/badger/v2/skl.(*Skiplist).Put", - "github.com/dgraph-io/badger/v2.(*DB).doWrites", - "runtime.newproc", - "runtime.newproc.func1", - "runtime.newproc1", - "runtime.gfget", - "runtime.gfget.func1", - "runtime.(*mSpanList).remove" - ], - "levels": [ - [0, 3797, 0, 0], - [ - 0, 3, 0, 631, 0, 23, 0, 603, 0, 1, 0, 598, 0, 111, 8, 568, 0, 8, 0, 562, - 0, 572, 16, 385, 0, 68, 0, 317, 0, 296, 0, 259, 0, 1, 0, 246, 0, 1, 0, - 240, 0, 6, 0, 183, 0, 4, 0, 153, 0, 9, 0, 151, 0, 34, 1, 139, 0, 1036, - 1, 99, 0, 1620, 0, 15, 0, 3, 3, 14, 0, 1, 0, 1 - ], - [ - 0, 1, 0, 632, 0, 2, 0, 386, 0, 23, 0, 604, 0, 1, 0, 599, 8, 9, 0, 596, - 0, 5, 0, 583, 0, 6, 3, 581, 0, 43, 11, 569, 0, 1, 1, 400, 0, 39, 13, - 386, 0, 5, 2, 564, 0, 3, 0, 386, 16, 19, 7, 556, 0, 12, 0, 549, 0, 355, - 13, 408, 0, 2, 0, 401, 0, 1, 1, 400, 0, 1, 1, 399, 0, 2, 2, 398, 0, 31, - 0, 394, 0, 13, 9, 393, 0, 2, 2, 392, 0, 71, 6, 227, 0, 47, 16, 386, 0, - 68, 0, 318, 0, 296, 0, 260, 0, 1, 0, 247, 0, 1, 0, 241, 0, 2, 0, 226, 0, - 1, 0, 222, 0, 3, 0, 184, 0, 4, 0, 154, 0, 4, 4, 152, 0, 2, 2, 15, 0, 3, - 3, 11, 1, 33, 6, 140, 1, 4, 0, 130, 0, 1031, 0, 11, 0, 1, 0, 98, 0, 35, - 0, 93, 0, 1584, 5, 16, 3, 1, 0, 2 - ], - [ - 0, 1, 0, 11, 0, 2, 0, 17, 0, 1, 0, 629, 0, 20, 0, 610, 0, 2, 0, 605, 0, - 1, 0, 600, 8, 7, 5, 597, 0, 2, 2, 570, 0, 5, 0, 584, 3, 1, 1, 582, 0, 2, - 2, 570, 11, 2, 1, 579, 0, 10, 5, 577, 0, 18, 2, 571, 0, 2, 2, 570, 14, - 2, 2, 391, 0, 10, 10, 390, 0, 1, 0, 32, 0, 5, 5, 389, 0, 1, 1, 30, 0, 7, - 7, 388, 2, 2, 0, 566, 0, 1, 0, 565, 0, 1, 1, 390, 0, 2, 0, 563, 23, 2, - 0, 68, 0, 10, 2, 557, 0, 12, 0, 550, 13, 56, 0, 521, 0, 137, 3, 506, 0, - 5, 1, 505, 0, 38, 0, 501, 0, 104, 0, 410, 0, 2, 2, 409, 0, 2, 0, 402, 4, - 31, 2, 227, 9, 4, 4, 392, 8, 3, 3, 81, 0, 54, 21, 5, 0, 8, 8, 285, 16, - 1, 1, 391, 0, 9, 9, 390, 0, 7, 0, 32, 0, 3, 3, 389, 0, 7, 7, 388, 0, 2, - 2, 387, 0, 2, 0, 17, 0, 68, 0, 319, 0, 5, 0, 313, 0, 200, 0, 293, 0, 90, - 0, 264, 0, 1, 0, 261, 0, 1, 0, 248, 0, 1, 0, 242, 0, 1, 0, 235, 0, 1, 0, - 227, 0, 1, 0, 223, 0, 3, 0, 185, 0, 4, 0, 155, 16, 7, 1, 148, 0, 19, 4, - 53, 0, 1, 1, 141, 1, 2, 0, 136, 0, 2, 0, 11, 0, 1031, 0, 100, 0, 1, 0, - 20, 0, 1, 1, 97, 0, 20, 0, 94, 0, 12, 0, 32, 0, 2, 0, 17, 5, 1, 1, 79, - 0, 2, 1, 91, 0, 1567, 14, 20, 0, 1, 1, 19, 0, 8, 0, 17, 3, 1, 0, 3 - ], - [ - 0, 1, 0, 633, 0, 2, 2, 18, 0, 1, 1, 630, 0, 9, 0, 618, 0, 10, 0, 613, 0, - 1, 0, 611, 0, 2, 0, 606, 0, 1, 0, 601, 13, 2, 2, 580, 2, 5, 0, 585, 18, - 1, 1, 580, 5, 5, 5, 578, 2, 10, 8, 575, 0, 1, 1, 574, 0, 3, 3, 573, 0, - 2, 2, 572, 28, 1, 1, 33, 15, 2, 2, 567, 0, 1, 1, 285, 1, 2, 2, 126, 23, - 1, 1, 14, 0, 1, 1, 69, 2, 1, 1, 561, 0, 5, 2, 559, 0, 2, 2, 558, 0, 1, - 0, 554, 0, 11, 1, 551, 13, 30, 0, 533, 0, 26, 0, 522, 3, 63, 0, 514, 0, - 68, 10, 509, 0, 3, 1, 507, 1, 4, 4, 126, 0, 38, 10, 140, 0, 104, 1, 411, - 2, 2, 0, 11, 6, 20, 6, 5, 0, 9, 9, 285, 45, 4, 0, 6, 0, 1, 1, 110, 0, - 12, 12, 114, 0, 12, 12, 267, 0, 4, 4, 269, 34, 7, 7, 33, 12, 2, 2, 18, - 0, 43, 0, 333, 0, 1, 0, 329, 0, 22, 3, 321, 0, 2, 0, 246, 0, 5, 0, 314, - 0, 200, 17, 294, 0, 90, 3, 265, 0, 1, 0, 262, 0, 1, 0, 249, 0, 1, 0, - 243, 0, 1, 0, 236, 0, 1, 0, 5, 0, 1, 0, 224, 0, 3, 0, 186, 0, 1, 0, 174, - 0, 3, 0, 156, 17, 1, 1, 150, 0, 5, 5, 149, 4, 3, 3, 147, 0, 5, 0, 144, - 0, 1, 1, 143, 0, 6, 3, 54, 2, 2, 0, 11, 0, 1, 0, 133, 0, 1, 0, 131, 0, - 16, 16, 119, 0, 1015, 224, 101, 0, 1, 0, 40, 1, 20, 0, 20, 0, 12, 10, - 33, 0, 2, 2, 18, 7, 1, 1, 92, 14, 3, 3, 90, 0, 27, 27, 89, 0, 2, 2, 88, - 0, 14, 14, 87, 0, 4, 3, 86, 0, 6, 6, 85, 0, 1195, 168, 40, 0, 1, 1, 39, - 0, 11, 1, 32, 0, 37, 22, 14, 0, 1, 1, 36, 0, 14, 14, 35, 0, 20, 20, 34, - 0, 208, 2, 22, 0, 1, 1, 21, 0, 9, 2, 17, 1, 8, 8, 18, 3, 1, 0, 4 - ], - [ - 0, 1, 0, 634, 3, 2, 0, 288, 0, 1, 0, 625, 0, 6, 0, 619, 0, 10, 0, 614, - 0, 1, 1, 612, 0, 2, 0, 607, 0, 1, 1, 602, 17, 1, 1, 595, 0, 2, 0, 218, - 0, 2, 0, 586, 39, 2, 2, 576, 86, 3, 3, 560, 2, 1, 0, 329, 1, 2, 0, 553, - 0, 8, 2, 518, 13, 30, 0, 534, 0, 26, 0, 523, 3, 63, 2, 515, 10, 25, 1, - 512, 0, 33, 2, 510, 1, 1, 1, 508, 0, 1, 0, 227, 15, 13, 0, 148, 0, 2, 2, - 504, 0, 13, 0, 53, 1, 3, 0, 498, 0, 2, 0, 4, 0, 96, 0, 413, 0, 2, 2, - 412, 2, 2, 0, 403, 12, 4, 0, 6, 0, 1, 1, 114, 0, 8, 8, 267, 0, 1, 1, - 269, 54, 4, 0, 7, 84, 10, 0, 352, 0, 1, 0, 371, 0, 31, 0, 335, 0, 1, 0, - 334, 0, 1, 0, 330, 3, 2, 0, 323, 0, 2, 0, 322, 0, 11, 4, 266, 0, 1, 0, - 227, 0, 3, 1, 278, 0, 2, 0, 247, 0, 1, 0, 316, 0, 1, 0, 270, 0, 3, 0, - 266, 17, 8, 8, 290, 0, 1, 0, 306, 0, 55, 13, 286, 0, 108, 10, 266, 0, 2, - 2, 295, 0, 9, 3, 278, 3, 1, 1, 290, 0, 50, 0, 283, 0, 20, 0, 276, 0, 3, - 0, 271, 0, 3, 0, 270, 0, 10, 1, 266, 0, 1, 1, 263, 0, 1, 0, 250, 0, 1, - 0, 244, 0, 1, 0, 237, 0, 1, 0, 228, 0, 1, 1, 225, 0, 3, 0, 187, 0, 1, 0, - 175, 0, 3, 0, 157, 30, 5, 0, 11, 4, 3, 3, 142, 2, 2, 0, 137, 0, 1, 0, - 134, 0, 1, 1, 132, 240, 120, 1, 123, 0, 49, 0, 120, 0, 1, 1, 119, 0, 1, - 1, 118, 0, 1, 1, 110, 0, 2, 2, 117, 0, 6, 6, 116, 0, 13, 13, 115, 0, 25, - 25, 114, 0, 565, 325, 103, 0, 8, 8, 102, 0, 1, 0, 41, 1, 1, 1, 64, 0, 2, - 0, 86, 0, 10, 2, 40, 0, 3, 0, 32, 0, 2, 2, 14, 0, 2, 0, 17, 10, 2, 2, - 38, 73, 1, 1, 79, 174, 1, 1, 80, 0, 11, 5, 48, 0, 165, 46, 64, 0, 23, - 20, 14, 0, 438, 56, 62, 0, 9, 9, 26, 0, 18, 18, 25, 0, 23, 12, 60, 0, 2, - 2, 59, 0, 9, 9, 58, 0, 10, 1, 55, 0, 317, 4, 41, 0, 1, 0, 17, 2, 10, 9, - 33, 22, 15, 15, 37, 37, 206, 1, 23, 3, 7, 7, 18, 12, 1, 0, 5 - ], - [ - 0, 1, 0, 635, 3, 1, 0, 289, 0, 1, 1, 126, 0, 1, 0, 626, 0, 6, 0, 227, 0, - 10, 0, 615, 1, 2, 0, 608, 19, 2, 0, 219, 0, 2, 1, 586, 132, 1, 0, 330, - 1, 2, 0, 553, 2, 6, 0, 552, 13, 30, 0, 535, 0, 25, 0, 524, 0, 1, 0, 266, - 5, 59, 0, 516, 0, 1, 1, 491, 0, 1, 0, 227, 11, 24, 15, 281, 2, 31, 21, - 281, 2, 1, 0, 5, 15, 1, 1, 150, 0, 12, 12, 149, 2, 2, 2, 147, 0, 6, 0, - 144, 0, 4, 4, 54, 0, 1, 0, 32, 1, 1, 1, 500, 0, 2, 1, 499, 0, 2, 0, 5, - 0, 3, 0, 496, 0, 6, 0, 495, 0, 37, 0, 465, 0, 36, 0, 439, 0, 4, 0, 433, - 0, 1, 0, 431, 0, 9, 0, 414, 4, 2, 1, 404, 12, 2, 0, 7, 0, 2, 0, 395, 64, - 4, 0, 8, 84, 10, 0, 198, 0, 1, 0, 372, 0, 31, 0, 336, 0, 1, 0, 68, 0, 1, - 0, 331, 3, 2, 0, 324, 0, 1, 0, 208, 0, 1, 0, 5, 4, 6, 1, 5, 0, 1, 1, - 126, 0, 1, 0, 5, 1, 2, 2, 126, 0, 2, 0, 248, 0, 1, 0, 270, 0, 1, 1, 126, - 0, 3, 1, 5, 25, 1, 0, 307, 13, 42, 17, 270, 10, 1, 1, 81, 0, 1, 1, 302, - 0, 83, 26, 5, 0, 1, 1, 126, 0, 11, 11, 285, 0, 1, 1, 30, 5, 6, 6, 126, - 4, 1, 0, 291, 0, 47, 23, 284, 0, 2, 0, 227, 0, 20, 0, 277, 0, 3, 0, 4, - 0, 1, 0, 266, 0, 2, 2, 126, 1, 9, 1, 5, 1, 1, 0, 251, 0, 1, 1, 245, 0, - 1, 0, 238, 0, 1, 0, 229, 1, 3, 0, 185, 0, 1, 0, 176, 0, 3, 0, 158, 30, - 2, 0, 145, 0, 1, 0, 32, 0, 2, 0, 17, 9, 2, 0, 134, 0, 1, 0, 135, 242, 2, - 2, 129, 0, 117, 5, 124, 0, 32, 32, 122, 0, 17, 0, 121, 374, 7, 7, 113, - 0, 2, 2, 112, 0, 11, 11, 111, 0, 1, 1, 110, 0, 72, 72, 109, 0, 38, 38, - 108, 0, 36, 36, 107, 0, 30, 30, 106, 0, 1, 1, 105, 0, 42, 42, 104, 8, 1, - 0, 44, 2, 2, 2, 79, 2, 1, 1, 96, 0, 2, 2, 64, 0, 1, 1, 95, 0, 3, 3, 14, - 0, 1, 1, 58, 0, 3, 1, 33, 2, 2, 1, 18, 266, 5, 5, 50, 0, 1, 1, 49, 46, - 6, 6, 84, 0, 113, 17, 65, 20, 3, 3, 37, 56, 382, 382, 63, 39, 1, 0, 32, - 0, 10, 10, 61, 12, 9, 5, 56, 4, 20, 6, 48, 0, 287, 5, 44, 0, 6, 5, 42, - 0, 1, 1, 18, 11, 1, 1, 38, 75, 1, 0, 32, 0, 2, 2, 31, 0, 2, 2, 30, 0, - 200, 2, 24, 22, 1, 0, 6 - ], - [ - 0, 1, 0, 636, 3, 1, 0, 628, 1, 1, 1, 627, 0, 6, 0, 5, 0, 10, 0, 616, 1, - 2, 0, 609, 19, 2, 1, 218, 1, 1, 1, 586, 132, 1, 0, 555, 1, 2, 0, 553, 2, - 3, 0, 266, 0, 2, 0, 227, 0, 1, 0, 278, 13, 30, 0, 536, 0, 25, 0, 525, 0, - 1, 1, 126, 5, 2, 1, 291, 0, 56, 44, 518, 0, 1, 0, 517, 1, 1, 1, 81, 26, - 9, 9, 513, 23, 10, 10, 511, 2, 1, 0, 6, 32, 6, 0, 11, 4, 1, 0, 33, 3, 1, - 1, 492, 0, 2, 0, 303, 0, 2, 2, 497, 0, 1, 0, 470, 0, 6, 0, 474, 0, 4, 0, - 494, 0, 3, 3, 493, 0, 12, 1, 480, 0, 3, 0, 475, 0, 1, 1, 432, 0, 13, 1, - 467, 0, 1, 1, 466, 0, 34, 0, 444, 0, 1, 0, 441, 0, 1, 0, 440, 0, 1, 1, - 438, 0, 2, 2, 437, 0, 1, 0, 434, 0, 1, 0, 432, 0, 1, 1, 227, 0, 8, 0, - 415, 5, 1, 0, 405, 12, 2, 0, 8, 0, 2, 2, 143, 64, 3, 0, 9, 0, 1, 1, 149, - 84, 10, 0, 199, 0, 1, 0, 373, 0, 30, 0, 339, 0, 1, 0, 337, 0, 1, 1, 70, - 0, 1, 1, 332, 3, 1, 0, 327, 0, 1, 0, 325, 0, 1, 1, 5, 0, 1, 0, 6, 5, 3, - 0, 6, 0, 2, 2, 267, 1, 1, 1, 114, 3, 2, 0, 249, 0, 1, 1, 126, 2, 1, 0, - 6, 0, 1, 1, 267, 25, 1, 0, 308, 30, 1, 0, 266, 0, 24, 24, 126, 38, 19, - 0, 6, 0, 5, 5, 114, 0, 32, 32, 267, 0, 1, 0, 228, 28, 1, 1, 292, 23, 1, - 1, 290, 0, 19, 4, 286, 0, 3, 3, 126, 0, 1, 1, 285, 0, 2, 0, 5, 0, 11, 0, - 279, 0, 6, 0, 266, 0, 3, 1, 278, 0, 3, 0, 5, 0, 1, 1, 126, 4, 3, 0, 6, - 0, 1, 1, 114, 0, 4, 4, 267, 1, 1, 0, 252, 1, 1, 1, 239, 0, 1, 0, 230, 1, - 3, 0, 185, 0, 1, 0, 177, 0, 3, 0, 159, 30, 2, 2, 146, 0, 1, 1, 33, 0, 2, - 2, 18, 9, 2, 0, 138, 0, 1, 1, 107, 249, 76, 76, 122, 0, 6, 4, 127, 0, 2, - 2, 126, 0, 28, 0, 125, 32, 17, 17, 92, 622, 1, 1, 45, 15, 2, 2, 38, 3, - 1, 0, 28, 341, 96, 2, 66, 500, 1, 1, 33, 27, 4, 4, 57, 10, 11, 10, 50, - 0, 3, 3, 49, 5, 8, 8, 47, 0, 274, 22, 45, 5, 1, 1, 43, 88, 1, 1, 33, 6, - 195, 3, 27, 0, 2, 2, 26, 0, 1, 1, 25, 22, 1, 0, 7 - ], - [ - 0, 1, 0, 620, 3, 1, 0, 4, 2, 6, 0, 267, 0, 10, 0, 617, 1, 2, 0, 75, 20, - 1, 0, 219, 134, 1, 0, 358, 1, 2, 0, 553, 2, 2, 0, 5, 0, 1, 1, 126, 0, 2, - 1, 5, 0, 1, 1, 126, 13, 30, 1, 537, 0, 6, 3, 531, 0, 17, 0, 527, 0, 2, - 2, 526, 7, 1, 1, 292, 44, 1, 1, 520, 0, 7, 0, 519, 0, 1, 0, 5, 0, 2, 2, - 126, 0, 1, 1, 285, 0, 1, 0, 227, 72, 1, 0, 7, 32, 3, 0, 145, 0, 2, 0, - 32, 0, 1, 0, 17, 4, 1, 1, 38, 4, 2, 0, 10, 2, 1, 1, 234, 0, 6, 0, 234, - 0, 4, 0, 227, 4, 1, 1, 492, 0, 1, 0, 266, 0, 1, 1, 491, 0, 3, 0, 488, 0, - 1, 0, 476, 0, 1, 0, 482, 0, 1, 1, 481, 0, 2, 2, 432, 0, 2, 2, 263, 0, 1, - 0, 476, 2, 10, 0, 469, 0, 2, 0, 227, 1, 34, 0, 445, 0, 1, 0, 442, 0, 1, - 0, 266, 3, 1, 0, 435, 0, 1, 0, 266, 1, 4, 0, 426, 0, 4, 0, 416, 5, 1, 0, - 406, 12, 1, 0, 9, 0, 1, 1, 143, 66, 3, 1, 10, 85, 1, 0, 384, 0, 7, 0, - 200, 0, 1, 0, 377, 0, 1, 1, 263, 0, 1, 0, 374, 0, 30, 0, 340, 0, 1, 0, - 338, 5, 1, 1, 328, 0, 1, 1, 326, 1, 1, 0, 7, 5, 3, 0, 7, 7, 2, 0, 250, - 3, 1, 0, 7, 26, 1, 0, 309, 30, 1, 0, 5, 62, 19, 0, 7, 37, 1, 0, 229, 57, - 14, 8, 288, 0, 1, 1, 287, 4, 1, 1, 6, 0, 1, 1, 267, 0, 11, 0, 280, 0, 6, - 1, 5, 1, 2, 2, 126, 0, 3, 0, 6, 5, 3, 0, 7, 6, 1, 0, 253, 2, 1, 0, 11, - 1, 3, 0, 188, 0, 1, 0, 178, 0, 3, 0, 160, 44, 2, 0, 50, 330, 2, 2, 128, - 2, 28, 28, 92, 692, 1, 1, 29, 343, 7, 7, 83, 0, 87, 8, 67, 552, 1, 0, - 51, 38, 252, 10, 46, 104, 192, 3, 28, 25, 1, 0, 8 - ], - [ - 0, 1, 0, 621, 3, 1, 0, 5, 2, 6, 0, 256, 0, 10, 10, 430, 1, 2, 0, 11, 20, - 1, 0, 218, 134, 1, 1, 302, 1, 2, 0, 553, 2, 1, 1, 114, 0, 1, 1, 267, 2, - 1, 1, 269, 15, 29, 1, 538, 3, 3, 3, 530, 0, 14, 6, 531, 0, 3, 0, 528, - 55, 5, 0, 266, 0, 2, 0, 227, 0, 1, 0, 6, 3, 1, 1, 5, 72, 1, 1, 8, 32, 1, - 1, 503, 0, 2, 1, 146, 0, 2, 2, 33, 0, 1, 1, 18, 9, 1, 1, 269, 0, 1, 0, - 11, 3, 6, 6, 381, 0, 3, 1, 5, 0, 1, 1, 285, 5, 1, 1, 5, 1, 1, 0, 489, 0, - 2, 0, 477, 0, 1, 1, 487, 0, 1, 0, 483, 5, 1, 0, 477, 2, 5, 1, 474, 0, 2, - 0, 472, 0, 3, 0, 470, 0, 1, 1, 468, 0, 1, 1, 5, 1, 34, 0, 446, 0, 1, 0, - 443, 0, 1, 0, 5, 3, 1, 1, 436, 0, 1, 1, 285, 1, 4, 0, 427, 0, 1, 0, 325, - 0, 2, 0, 418, 0, 1, 1, 417, 5, 1, 0, 407, 12, 1, 0, 297, 68, 1, 1, 269, - 0, 1, 0, 11, 85, 1, 1, 227, 0, 7, 0, 379, 0, 1, 1, 378, 1, 1, 0, 375, 0, - 7, 0, 352, 0, 1, 0, 347, 0, 13, 0, 345, 0, 7, 1, 207, 0, 2, 0, 341, 0, - 1, 0, 4, 8, 1, 0, 52, 5, 2, 0, 8, 0, 1, 0, 52, 7, 2, 0, 251, 3, 1, 0, 8, - 26, 1, 0, 310, 30, 1, 0, 303, 62, 16, 0, 8, 0, 3, 0, 52, 37, 1, 0, 230, - 65, 3, 1, 289, 0, 3, 3, 126, 7, 3, 3, 126, 0, 8, 5, 281, 1, 1, 1, 6, 0, - 3, 3, 267, 0, 1, 1, 269, 3, 3, 0, 7, 5, 3, 0, 8, 6, 1, 0, 254, 2, 1, 0, - 231, 1, 3, 0, 189, 0, 1, 0, 179, 0, 3, 0, 161, 44, 2, 1, 51, 1413, 68, - 6, 72, 0, 11, 2, 68, 552, 1, 0, 52, 48, 242, 242, 29, 107, 189, 189, 29, - 25, 1, 0, 9 - ], - [ - 0, 1, 0, 622, 3, 1, 0, 303, 2, 6, 0, 257, 11, 2, 0, 76, 20, 1, 0, 219, - 136, 2, 0, 553, 23, 24, 5, 537, 0, 4, 0, 539, 12, 7, 6, 530, 0, 1, 1, - 532, 0, 1, 1, 530, 0, 2, 0, 529, 55, 4, 2, 5, 0, 1, 1, 285, 0, 1, 0, 5, - 0, 1, 1, 285, 0, 1, 0, 7, 111, 1, 1, 502, 13, 1, 0, 12, 10, 1, 0, 6, 0, - 1, 1, 114, 8, 1, 1, 490, 0, 2, 0, 478, 1, 1, 0, 484, 5, 1, 0, 478, 3, 4, - 1, 234, 0, 2, 0, 473, 0, 3, 0, 234, 3, 16, 8, 462, 0, 17, 0, 448, 0, 1, - 1, 447, 0, 1, 1, 126, 0, 1, 0, 6, 6, 4, 0, 428, 0, 1, 1, 326, 0, 1, 0, - 423, 0, 1, 0, 419, 6, 1, 0, 51, 12, 1, 0, 396, 69, 1, 1, 12, 86, 1, 1, - 383, 0, 3, 1, 382, 0, 2, 1, 380, 0, 1, 0, 204, 2, 1, 1, 376, 0, 7, 0, - 198, 0, 1, 0, 348, 0, 13, 0, 346, 1, 3, 0, 208, 0, 3, 0, 342, 0, 2, 1, - 278, 0, 1, 1, 5, 8, 1, 1, 54, 5, 2, 0, 9, 0, 1, 0, 54, 7, 2, 0, 320, 3, - 1, 0, 9, 26, 1, 0, 311, 30, 1, 0, 10, 62, 16, 0, 9, 0, 3, 3, 54, 37, 1, - 0, 11, 66, 2, 0, 4, 18, 3, 3, 282, 9, 3, 0, 8, 5, 3, 0, 9, 6, 1, 0, 255, - 2, 1, 0, 232, 1, 3, 0, 190, 0, 1, 0, 159, 0, 3, 0, 162, 45, 1, 0, 52, - 1419, 13, 13, 82, 0, 48, 17, 73, 0, 1, 0, 32, 2, 6, 4, 70, 0, 3, 3, 69, - 552, 1, 0, 53, 611, 1, 0, 10 - ], - [ - 0, 1, 1, 637, 3, 1, 0, 297, 2, 1, 1, 624, 0, 4, 1, 232, 0, 1, 0, 620, - 11, 2, 0, 77, 20, 1, 0, 587, 136, 2, 0, 553, 28, 2, 1, 548, 0, 8, 0, - 538, 0, 1, 1, 543, 0, 8, 3, 542, 0, 1, 1, 541, 0, 3, 0, 540, 18, 1, 1, - 206, 2, 2, 0, 4, 57, 1, 0, 6, 0, 1, 1, 267, 1, 1, 1, 267, 1, 1, 0, 8, - 125, 1, 0, 13, 10, 1, 0, 7, 10, 2, 0, 479, 1, 1, 0, 485, 5, 1, 0, 479, - 4, 3, 3, 381, 0, 2, 2, 326, 0, 1, 1, 471, 0, 2, 2, 381, 11, 6, 6, 464, - 0, 1, 1, 463, 0, 1, 1, 126, 0, 9, 2, 453, 0, 5, 4, 451, 0, 2, 2, 450, 0, - 1, 1, 449, 2, 1, 0, 7, 6, 4, 0, 429, 1, 1, 0, 424, 0, 1, 0, 420, 6, 1, - 1, 315, 12, 1, 1, 397, 158, 2, 0, 278, 1, 1, 0, 227, 0, 1, 0, 205, 3, 7, - 0, 199, 0, 1, 0, 349, 0, 13, 0, 346, 1, 3, 0, 281, 0, 3, 0, 227, 1, 1, - 1, 126, 15, 2, 0, 10, 0, 1, 1, 142, 7, 2, 2, 253, 3, 1, 0, 10, 26, 1, 1, - 312, 30, 1, 0, 11, 62, 15, 0, 10, 0, 1, 0, 297, 40, 1, 0, 231, 66, 2, 2, - 5, 30, 3, 0, 9, 5, 3, 0, 10, 6, 1, 0, 256, 2, 1, 0, 233, 1, 3, 0, 185, - 0, 1, 0, 160, 0, 3, 0, 163, 45, 1, 0, 53, 1449, 31, 1, 74, 0, 1, 1, 33, - 6, 2, 2, 71, 555, 1, 1, 54, 611, 1, 0, 11 - ], - [ - 4, 1, 1, 269, 4, 1, 0, 258, 0, 2, 0, 233, 0, 1, 0, 621, 11, 2, 0, 23, - 20, 1, 0, 588, 136, 2, 0, 553, 29, 1, 0, 266, 0, 1, 1, 547, 0, 1, 1, - 537, 0, 6, 1, 539, 4, 5, 1, 266, 1, 2, 1, 5, 0, 1, 1, 30, 21, 2, 0, 5, - 57, 1, 0, 395, 4, 1, 1, 149, 125, 1, 0, 272, 10, 1, 0, 8, 10, 2, 0, 5, - 1, 1, 0, 227, 5, 1, 0, 5, 33, 2, 0, 461, 0, 5, 0, 454, 4, 1, 1, 452, 5, - 1, 0, 8, 6, 4, 4, 430, 1, 1, 0, 425, 0, 1, 0, 421, 178, 2, 2, 126, 1, 1, - 0, 5, 0, 1, 1, 353, 3, 7, 0, 200, 0, 1, 0, 350, 0, 12, 1, 346, 0, 1, 0, - 4, 1, 3, 0, 343, 0, 3, 1, 5, 17, 2, 2, 269, 13, 1, 0, 11, 57, 1, 0, 12, - 62, 10, 10, 269, 0, 5, 0, 11, 0, 1, 1, 269, 40, 1, 0, 232, 98, 3, 0, 10, - 5, 1, 1, 269, 0, 2, 0, 11, 6, 1, 0, 257, 2, 1, 1, 234, 1, 3, 0, 185, 0, - 1, 0, 180, 0, 2, 0, 170, 0, 1, 0, 164, 45, 1, 0, 54, 1450, 30, 0, 75, - 1176, 1, 0, 12 - ], - [ - 9, 1, 0, 623, 0, 2, 1, 234, 0, 1, 1, 622, 11, 2, 0, 24, 20, 1, 0, 588, - 136, 2, 0, 553, 29, 1, 1, 5, 3, 2, 0, 544, 0, 3, 0, 540, 5, 1, 0, 5, 0, - 1, 1, 269, 0, 2, 2, 285, 2, 1, 1, 267, 22, 2, 0, 6, 57, 1, 1, 143, 130, - 1, 0, 273, 10, 1, 0, 9, 10, 1, 0, 6, 0, 1, 1, 269, 1, 1, 0, 5, 5, 1, 1, - 267, 33, 2, 0, 456, 0, 4, 0, 455, 0, 1, 0, 4, 10, 1, 0, 9, 11, 1, 1, - 109, 0, 1, 1, 422, 181, 1, 0, 228, 4, 5, 0, 214, 0, 2, 0, 201, 0, 1, 1, - 351, 1, 10, 0, 346, 0, 1, 0, 227, 0, 1, 1, 5, 1, 3, 3, 344, 1, 2, 2, - 267, 32, 1, 0, 12, 57, 1, 0, 13, 72, 5, 0, 12, 41, 1, 0, 296, 98, 1, 1, - 269, 0, 2, 0, 11, 6, 2, 0, 12, 6, 1, 0, 232, 4, 3, 0, 185, 0, 1, 0, 181, - 0, 1, 0, 173, 0, 1, 0, 164, 0, 1, 0, 165, 45, 1, 1, 122, 1450, 30, 5, - 76, 1176, 1, 1, 13 - ], - [ - 9, 1, 0, 296, 1, 1, 1, 381, 12, 2, 0, 27, 20, 1, 0, 589, 136, 2, 0, 553, - 33, 1, 1, 546, 0, 1, 1, 545, 0, 2, 0, 5, 0, 1, 1, 285, 5, 1, 0, 6, 28, - 2, 0, 7, 188, 1, 0, 300, 10, 1, 0, 10, 10, 1, 0, 7, 2, 1, 0, 303, 39, 2, - 0, 457, 0, 4, 0, 456, 0, 1, 0, 5, 10, 1, 0, 10, 194, 1, 0, 229, 4, 5, 0, - 356, 0, 1, 0, 352, 0, 1, 0, 204, 2, 8, 0, 346, 0, 2, 0, 4, 0, 1, 0, 5, - 40, 1, 0, 13, 57, 1, 0, 304, 72, 5, 3, 13, 41, 1, 1, 234, 99, 2, 0, 12, - 6, 1, 1, 13, 0, 1, 1, 268, 6, 1, 1, 258, 4, 1, 0, 209, 0, 2, 0, 191, 0, - 1, 1, 182, 0, 1, 0, 164, 0, 1, 0, 165, 0, 1, 0, 166, 1501, 1, 1, 81, 0, - 24, 9, 77 - ], - [ - 9, 1, 0, 234, 14, 2, 0, 28, 20, 1, 0, 590, 136, 1, 0, 553, 0, 1, 1, 4, - 35, 1, 1, 118, 0, 1, 1, 267, 6, 1, 1, 7, 28, 2, 1, 8, 188, 1, 1, 301, - 10, 1, 0, 11, 10, 1, 0, 8, 2, 1, 0, 10, 39, 1, 1, 458, 0, 1, 0, 457, 0, - 4, 0, 457, 0, 1, 1, 269, 10, 1, 1, 269, 194, 1, 0, 230, 4, 4, 0, 359, 0, - 1, 0, 331, 0, 1, 0, 198, 0, 1, 0, 205, 2, 8, 1, 346, 0, 2, 2, 5, 0, 1, - 0, 6, 40, 1, 1, 315, 57, 1, 1, 305, 75, 1, 0, 299, 0, 1, 1, 298, 141, 2, - 1, 13, 19, 1, 0, 210, 0, 2, 0, 192, 1, 1, 0, 165, 0, 1, 0, 166, 0, 1, 0, - 166, 1511, 1, 1, 80, 0, 6, 6, 79, 0, 3, 3, 78, 0, 5, 2, 23 - ], - [ - 9, 1, 1, 381, 14, 2, 2, 29, 20, 1, 0, 591, 136, 1, 0, 553, 74, 1, 1, - 149, 199, 1, 0, 12, 10, 1, 0, 9, 2, 1, 0, 11, 40, 1, 0, 457, 0, 4, 0, - 457, 206, 1, 0, 11, 4, 4, 0, 360, 0, 1, 0, 332, 0, 1, 0, 199, 0, 1, 1, - 353, 3, 5, 0, 346, 0, 2, 0, 227, 2, 1, 0, 7, 174, 1, 0, 300, 143, 1, 0, - 272, 19, 1, 0, 211, 0, 2, 0, 193, 1, 1, 1, 166, 0, 1, 0, 167, 0, 1, 0, - 166, 1523, 3, 0, 24 - ], - [ - 46, 1, 0, 592, 136, 1, 0, 553, 274, 1, 1, 13, 10, 1, 0, 10, 2, 1, 0, 12, - 40, 1, 1, 458, 0, 1, 1, 458, 0, 2, 1, 459, 0, 1, 0, 457, 206, 1, 0, 231, - 4, 1, 0, 370, 0, 2, 0, 362, 0, 1, 1, 361, 0, 1, 0, 357, 0, 1, 0, 200, 4, - 4, 0, 346, 0, 1, 0, 4, 0, 1, 0, 5, 0, 1, 1, 285, 2, 1, 1, 8, 174, 1, 1, - 301, 143, 1, 0, 273, 19, 1, 0, 212, 0, 2, 0, 194, 2, 1, 0, 166, 0, 1, 0, - 167, 1523, 3, 0, 27 - ], - [ - 46, 1, 0, 593, 136, 1, 0, 227, 285, 1, 0, 11, 2, 1, 0, 13, 43, 1, 1, - 460, 0, 1, 1, 458, 206, 1, 0, 232, 4, 1, 1, 227, 0, 2, 0, 363, 1, 1, 0, - 358, 0, 1, 0, 354, 4, 4, 0, 346, 0, 1, 1, 5, 0, 1, 1, 114, 322, 1, 0, - 274, 19, 1, 0, 213, 0, 2, 0, 194, 2, 1, 0, 167, 0, 1, 0, 168, 1523, 3, - 0, 28 - ], - [ - 46, 1, 1, 594, 136, 1, 0, 5, 285, 1, 0, 12, 2, 1, 0, 272, 251, 1, 0, - 296, 5, 1, 0, 366, 0, 1, 0, 364, 1, 1, 1, 285, 0, 1, 0, 355, 4, 4, 1, - 346, 324, 1, 1, 275, 19, 1, 0, 214, 0, 2, 0, 194, 2, 1, 0, 166, 0, 1, 1, - 169, 1523, 3, 3, 29 - ], - [ - 183, 1, 1, 267, 285, 1, 1, 13, 2, 1, 1, 486, 251, 1, 0, 234, 5, 1, 0, - 367, 0, 1, 1, 365, 2, 1, 0, 278, 5, 3, 0, 346, 344, 1, 0, 215, 0, 2, 0, - 194, 2, 1, 0, 171 - ], - [ - 724, 1, 1, 381, 5, 1, 0, 368, 3, 1, 1, 126, 5, 3, 0, 346, 344, 1, 0, - 216, 0, 1, 0, 195, 0, 1, 0, 194, 2, 1, 1, 172 - ], - [ - 730, 1, 1, 369, 9, 2, 0, 346, 0, 1, 0, 227, 344, 1, 0, 217, 0, 1, 0, - 196, 0, 1, 0, 195 - ], - [740, 2, 0, 346, 0, 1, 1, 5, 344, 1, 0, 218, 0, 1, 0, 207, 0, 1, 0, 196], - [ - 740, 1, 0, 346, 0, 1, 0, 227, 345, 1, 0, 219, 0, 1, 1, 208, 0, 1, 0, 197 - ], - [740, 1, 1, 346, 0, 1, 1, 5, 345, 1, 0, 220, 1, 1, 0, 198], - [1087, 1, 1, 221, 1, 1, 0, 199], - [1089, 1, 0, 200], - [1089, 1, 0, 201], - [1089, 1, 0, 202], - [1089, 1, 0, 203], - [1089, 1, 0, 204], - [1089, 1, 0, 205], - [1089, 1, 1, 206] - ], - "numTicks": 3797, - "maxSelf": 382, - "spyName": "gospy", - "sampleRate": 100, - "units": "samples", - "format": "single" - }, - "metadata": { - "format": "single", - "sampleRate": 100, - "spyName": "gospy", - "units": "samples" - }, - "timeline": { - "startTime": 1637177610, - "samples": [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 15, 15, - 16, 14, 16, 22, 14, 14, 13, 13, 10, 22, 13, 15, 13, 13, 17, 24, 13, 15, - 15, 13, 14, 21, 16, 17, 13, 15, 14, 25, 13, 15, 16, 16, 19, 24, 14, 18, - 13, 18, 19, 26, 16, 13, 15, 15, 14, 20, 16, 15, 13, 15, 13, 26, 12, 16, - 16, 15, 16, 22, 18, 13, 15, 16, 15, 23, 15, 15, 17, 15, 12, 25, 16, 14, - 16, 13, 16, 23, 14, 15, 11, 14, 11, 19, 16, 16, 13, 17, 15, 25, 17, 13, - 16, 14, 15, 24, 17, 16, 13, 15, 14, 25, 10, 13, 13, 14, 16, 23, 16, 14, - 13, 13, 16, 26, 15, 17, 16, 16, 14, 22, 17, 16, 17, 15, 18, 24, 17, 12, - 14, 15, 17, 25, 13, 16, 19, 16, 13, 22, 15, 12, 16, 17, 12, 21, 14, 13, - 13, 14, 13, 22, 18, 15, 16, 15, 16, 23, 17, 17, 14, 16, 15, 24, 16, 17, - 16, 14, 14, 23, 16, 15, 15, 17, 15, 24, 18, 14, 15, 16, 16, 26, 19, 17, - 17, 15, 17, 24, 16, 16, 15, 17, 16, 27, 18, 15, 14, 16, 16, 27, 17, 18, - 16, 17, 16, 26, 16, 16, 16, 17, 17, 27, 18, 19, 19, 17, 18, 27, 18, 17, - 16, 17, 20, 23, 19, 17, 18, 17, 19, 27, 16, 21, 14, 16, 16, 30, 15, 18, - 20, 15, 18, 0 - ], - "durationDelta": 10, - "watermarks": {} - } -} diff --git a/og/global.d.ts b/og/global.d.ts deleted file mode 100644 index f3499d2590..0000000000 --- a/og/global.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -// https://stackoverflow.com/a/60029264 -declare module '*.module.css'; diff --git a/og/go.mod b/og/go.mod deleted file mode 100644 index d5809a4727..0000000000 --- a/og/go.mod +++ /dev/null @@ -1,88 +0,0 @@ -module github.com/pyroscope-io/pyroscope - -go 1.19 - -require ( - github.com/blang/semver v3.5.1+incompatible - github.com/davecgh/go-spew v1.1.1 - github.com/dgraph-io/badger/v2 v2.2007.2 - github.com/fatih/color v1.13.0 - github.com/google/go-jsonnet v0.17.0 - github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 - github.com/josephspurrier/goversioninfo v1.2.0 - github.com/jsonnet-bundler/jsonnet-bundler v0.4.0 - github.com/kisielk/godepgraph v0.0.0-20190626013829-57a7e4a651a9 - github.com/kyoh86/richgo v0.3.3 - github.com/mattn/goreman v0.3.5 - github.com/mgechev/revive v1.0.3 - github.com/onsi/ginkgo/v2 v2.1.3 - github.com/onsi/gomega v1.17.0 - github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.2.1 - github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.8.1 - golang.org/x/tools v0.6.0 - gopkg.in/yaml.v2 v2.4.0 - honnef.co/go/tools v0.0.1-2020.1.6 - -) - -require ( - github.com/BurntSushi/toml v0.4.1 // indirect - github.com/DataDog/zstd v1.4.1 // indirect - github.com/akavel/rsrc v0.8.0 // indirect - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect - github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chzyer/readline v1.5.0 // indirect - github.com/dgraph-io/ristretto v0.1.0 // indirect - github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect - github.com/fatih/structtag v1.2.0 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/golang/glog v1.0.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.5.8 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/joho/godotenv v1.3.0 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/kyoh86/xdg v1.2.0 // indirect - github.com/magiconair/properties v1.8.5 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/mattn/go-runewidth v0.0.10 // indirect - github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.3 // indirect - github.com/morikuni/aec v1.0.0 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/pelletier/go-toml v1.9.3 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/sergi/go-diff v1.2.0 // indirect - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/stretchr/testify v1.7.1 // indirect - github.com/subosito/gotenv v1.2.0 // indirect - github.com/wacul/ptr v1.0.0 // indirect - github.com/yuin/goldmark v1.4.13 // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/ini.v1 v1.62.0 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect -) - -replace github.com/mgechev/revive v1.0.3 => github.com/pyroscope-io/revive v1.0.6-0.20210330033039-4a71146f9dc1 - -// replace github.com/pyroscope-io/client => ../client diff --git a/og/go.sum b/og/go.sum deleted file mode 100644 index 34de61b57e..0000000000 --- a/og/go.sum +++ /dev/null @@ -1,803 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= -github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= -github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= -github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= -github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.0 h1:+eqR0HfOetur4tgnC8ftU5imRnhi4te+BadWS95c5AM= -github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.0 h1:lSwwFrbNviGePhkewF1az4oLmcwqCZijQ2/Wi3BGHAI= -github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v0.0.0-20210722231415-061457976a23 h1:dZ0/VyGgQdVGAss6Ju0dt5P0QltE0SFY5Woh6hbIfiQ= -github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deadcheat/goblet v1.3.1 h1:OPOYQjHlbPmG8fFCt8GNNGECLVhaJ0n7F7cP5Mh7G/A= -github.com/deadcheat/goblet v1.3.1/go.mod h1:IrMNyAwyrVgB30HsND2WgleTUM4wHTS9m40yNY6NJQg= -github.com/deadcheat/gonch v0.0.0-20180528124129-c2ff7a019863/go.mod h1:/5mH3gAuXUxGN3maOBAxBfB8RXvP9tBIX5fx2x1k0V0= -github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= -github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= -github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-jsonnet v0.17.0 h1:/9NIEfhK1NQRKl3sP2536b2+x5HnZMdql7x3yK/l8JY= -github.com/google/go-jsonnet v0.17.0/go.mod h1:sOcuej3UW1vpPTZOr8L7RQimqai1a57bt5j22LzGZCw= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 h1:rcanfLhLDA8nozr/K289V1zcntHr3V+SHlXwzz1ZI2g= -github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/josephspurrier/goversioninfo v1.2.0 h1:tpLHXAxLHKHg/dCU2AAYx08A4m+v9/CWg6+WUvTF4uQ= -github.com/josephspurrier/goversioninfo v1.2.0/go.mod h1:AGP2a+Y/OVJZ+s6XM4IwFUpkETwvn0orYurY8qpw1+0= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jsonnet-bundler/jsonnet-bundler v0.4.0 h1:4BKZ6LDqPc2wJDmaKnmYD/vDjUptJtnUpai802MibFc= -github.com/jsonnet-bundler/jsonnet-bundler v0.4.0/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/godepgraph v0.0.0-20190626013829-57a7e4a651a9 h1:ZkWH0x1yafBo+Y2WdGGdszlJrMreMXWl7/dqpEkwsIk= -github.com/kisielk/godepgraph v0.0.0-20190626013829-57a7e4a651a9/go.mod h1:Gb5YEgxqiSSVrXKWQxDcKoCM94NO5QAwOwTaVmIUAMI= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kyoh86/richgo v0.3.3 h1:fW7ygWNMg1INcX3Yoha9v1C5nYlvd/IodJUf0Batz6Q= -github.com/kyoh86/richgo v0.3.3/go.mod h1:S65jllVRxBm59fqIXfCa3cPxQYRT9u9v45EPQVeuoH0= -github.com/kyoh86/xdg v0.0.0-20171007020617-d28e4c5d7b81/go.mod h1:Z5mDqe0fxyxn3W2yTxsBAOQqIrXADQIh02wrTnaRM38= -github.com/kyoh86/xdg v1.2.0 h1:CERuT/ShdTDj+A2UaX3hQ3mOV369+Sj+wyn2nIRIIkI= -github.com/kyoh86/xdg v1.2.0/go.mod h1:/mg8zwu1+qe76oTFUBnyS7rJzk7LLC0VGEzJyJ19DHs= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.0-20170925054904-a5cdd64afdee/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= -github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/goreman v0.3.5 h1:cY6wBfPs+uUIsVPsVjtsG7FH/XAEfQS9/Zu+V4+bRqE= -github.com/mattn/goreman v0.3.5/go.mod h1:ahZuLhEo4pfYmf56GLNu/pjTxfeE389h43IHKMXz2Ys= -github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 h1:QASJXOGm2RZ5Ardbc86qNFvby9AqkLDibfChMtAg5QM= -github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/pyroscope-io/revive v1.0.6-0.20210330033039-4a71146f9dc1 h1:0v9lBNgdmVtpyyk9PP/DfpJlOHkXriu5YgNlrhQw5YE= -github.com/pyroscope-io/revive v1.0.6-0.20210330033039-4a71146f9dc1/go.mod h1:tSw34BaGZ0iF+oVKDOjq1/LuxGifgW7shaJ6+dBYFXg= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/wacul/ptr v0.0.0-20170209030335-91632201dfc8/go.mod h1:BD0gjsZrCwtoR+yWDB9v2hQ8STlq9tT84qKfa+3txOc= -github.com/wacul/ptr v1.0.0 h1:FIKu08Wx0YUIf9MNsfF62OCmBSmz5A1Tk65zWhOIL/I= -github.com/wacul/ptr v1.0.0/go.mod h1:BD0gjsZrCwtoR+yWDB9v2hQ8STlq9tT84qKfa+3txOc= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180404174746-b3c676e531a6/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sys v0.0.0-20170927054621-314a259e304f/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc= -honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/og/jest.config.js b/og/jest.config.js deleted file mode 100644 index 720271fdff..0000000000 --- a/og/jest.config.js +++ /dev/null @@ -1,27 +0,0 @@ -const path = require('path'); - -module.exports = { - // TypeScript files (.ts, .tsx) will be transformed by ts-jest to CommonJS syntax, and JavaScript files (.js, jsx) will be transformed by babel-jest. - testEnvironment: 'jsdom', - setupFilesAfterEnv: [path.join(__dirname, 'setupAfterEnv.ts')], - testMatch: [ - '**/__tests__/**/*.+(ts|tsx|js)', - '**/?(*.)+(spec|test).+(ts|tsx|js)', - ], - moduleNameMapper: { - '@webapp(.*)$': path.join(__dirname, 'webapp/javascript/$1'), - }, - transform: { - '\\.module\\.(css|scss)$': 'jest-css-modules-transform', - '\\.(css|scss)$': 'jest-css-modules-transform', - '\\.svg$': path.join(__dirname, 'svg-transform.js'), - '^.+\\.(t|j)sx?$': ['@swc/jest'], - }, - transformIgnorePatterns: [ - // force us to not transpile these dependencies - // https://stackoverflow.com/a/69150188 - 'node_modules/(?!(true-myth|d3|d3-array|internmap|d3-scale|react-notifications-component|graphviz-react|@react-hook))', - ], - globalSetup: '/globalSetup.js', - globalTeardown: '/globalTeardown.js', -}; diff --git a/og/lerna.json b/og/lerna.json deleted file mode 100644 index cef50b03cd..0000000000 --- a/og/lerna.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "packages": [ - "packages/*", - "webapp" - ], - "useWorkspaces": true, - "npmClient": "yarn", - "version": "independent", - "command": { - "version": { - "ignoreChanges": ["*.md"], - "message": "chore(release): publish" - } - } -} diff --git a/og/lib/types.d.ts b/og/lib/types.d.ts deleted file mode 100644 index 11213ac68b..0000000000 --- a/og/lib/types.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -// https://github.com/Connormiha/jest-css-modules-transform/issues/33 -declare module '*.module.css' { - const classes: { [key: string]: string }; - export default classes; -} - -declare module '*.module.scss' { - const classes: { [key: string]: string }; - export default classes; -} - -declare module '*.module.sass' { - const classes: { [key: string]: string }; - export default classes; -} - -declare module '*.module.less' { - const classes: { [key: string]: string }; - export default classes; -} - -declare module '*.module.styl' { - const classes: { [key: string]: string }; - export default classes; -} - -// https://stackoverflow.com/a/45887328 -declare module '*.svg' { - const content: ShamefulAny; - export default content; -} - -declare module '*.gif' { - const content: ShamefulAny; - export default content; -} diff --git a/og/monitoring/Makefile b/og/monitoring/Makefile deleted file mode 100644 index a30b7db7db..0000000000 --- a/og/monitoring/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: dashboard benchmark-dashboard benchmark-pr - -benchmark-pr: - jsonnet -J vendor benchmark-pr.jsonnet | tee gen/benchmark-pr.json - -dashboard: - jsonnet -J vendor dashboard.jsonnet | tee gen/dashboard.json - -benchmark-dashboard: - jsonnet -J vendor benchmark.jsonnet | tee gen/benchmark-dashboard.json - -.PHONY: init -init: - jb install diff --git a/og/monitoring/README.md b/og/monitoring/README.md deleted file mode 100644 index d087d5a8dc..0000000000 --- a/og/monitoring/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Monitoring - -1. Install jsonnet/jb by running `make install-dev-tools` in the root Makefile. - -2. Install dependencies -``` -make init -``` - -3. (Re)Generate the dashboards -``` -make -``` - -# Development - - -Run the [grafana-integration](../examples/grafana-integration) example docker-compose then copy the generated dashboard there: - -``` -make && docker-compose -f ../examples/grafana-integration/docker-compose.yml up -d --force-recreate grafana -``` - -# Warnings -* If you ever rename the dashboard path, don't forget to update the references (see all the docker-compose.yaml) - -# References - -* https://grafana.github.io/grafonnet-lib/api-docs/ -* https://github.com/grafana/grafonnet-lib/tree/master/grafonnet -* https://github.com/kubernetes-monitoring/kubernetes-mixin diff --git a/og/monitoring/benchmark-pr.jsonnet b/og/monitoring/benchmark-pr.jsonnet deleted file mode 100644 index 61ff747d8a..0000000000 --- a/og/monitoring/benchmark-pr.jsonnet +++ /dev/null @@ -1,112 +0,0 @@ -local grafana = import 'grafonnet/grafana.libsonnet'; - -local width = 12; -local height = 10; - -// Dashboard to be used by Server benchmark PRs -grafana.dashboard.new( - 'Pyroscope Server PR Dashboard', - tags=['pyroscope'], - time_from='now-1h', - uid='QF9YgRbUbt3BA5Qd', - editable='true', - refresh = '5s', -) -.addTemplate( - grafana.template.datasource( - name='PROMETHEUS_DS', - query='prometheus', - current='prometheus', - hide='hidden', // anything other than '' and 'label works - ) -) -.addRow( - grafana.row.new( - title='Benchmark', - ) - .addPanel( - grafana.graphPanel.new( - 'Throughput', - datasource='$PROMETHEUS_DS', - ) - .addTarget(grafana.prometheus.target('rate(pyroscope_http_request_duration_seconds_count{handler="/ingest"}[5m])')), - ) - .addPanel( - grafana.graphPanel.new( - 'Disk Usage', - datasource='$PROMETHEUS_DS', - format='bytes', - legend_values='true', - legend_rightSide='true', - legend_alignAsTable='true', - legend_current='true', - legend_sort='current', - legend_sortDesc=true, - ) - .addTarget( - grafana.prometheus.target( - 'sum(pyroscope_storage_db_size_bytes) by (instance)', - legendFormat='total {{ instance }}', - ) - ), - ) - .addPanel( - grafana.graphPanel.new( - 'Memory', - datasource='$PROMETHEUS_DS', - format='bytes', - legend_values='true', - legend_rightSide='true', - legend_alignAsTable='true', - legend_current=true, - legend_max=true, - legend_sort='current', - legend_sortDesc=true, - logBase1Y=2, - ) - .addTarget( - grafana.prometheus.target( - 'go_memstats_heap_alloc_bytes{job="pyroscope"}', - legendFormat='heap size {{ instance }}', - ), - ) - ) - .addPanel( - grafana.graphPanel.new( - 'Upload Errors (Total)', - datasource='$PROMETHEUS_DS', - span=4, - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_benchmark_upload_errors{}', - ) - ), - ) - .addPanel( - grafana.graphPanel.new( - 'Successful Uploads (Total)', - datasource='$PROMETHEUS_DS', - span=4, - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_benchmark_successful_uploads{}', - ) - ), - ) - .addPanel( - grafana.graphPanel.new( - 'CPU Utilization', - datasource='$PROMETHEUS_DS', - format='percent', - min='0', - max='100', - ) - .addTarget( - grafana.prometheus.target( - 'process_cpu_seconds_total{job="pyroscope"}', - ) - ) - ) -) diff --git a/og/monitoring/benchmark.jsonnet b/og/monitoring/benchmark.jsonnet deleted file mode 100644 index 15cc391dfe..0000000000 --- a/og/monitoring/benchmark.jsonnet +++ /dev/null @@ -1,9 +0,0 @@ -local config = import 'config.libsonnet'; -local dashboard = import './lib/dashboard.libsonnet'; - -(config + dashboard + { - _config+:: { - benchmark: true, - selector: 'instance=~"$instance"', - } -}).dashboard diff --git a/og/monitoring/config.libsonnet b/og/monitoring/config.libsonnet deleted file mode 100644 index 1924345fa2..0000000000 --- a/og/monitoring/config.libsonnet +++ /dev/null @@ -1,7 +0,0 @@ -{ - _config+:: { - selector: 'instance="$instance"', - // whether to add additional benchmark fields or not - benchmark: false, - } -} diff --git a/og/monitoring/dashboard.jsonnet b/og/monitoring/dashboard.jsonnet deleted file mode 100644 index 4742cd4128..0000000000 --- a/og/monitoring/dashboard.jsonnet +++ /dev/null @@ -1,4 +0,0 @@ -local config = import 'config.libsonnet'; -local dashboard = import './lib/dashboard.libsonnet'; - -(config + dashboard).dashboard diff --git a/og/monitoring/gen/README.md b/og/monitoring/gen/README.md deleted file mode 100644 index 444bed7032..0000000000 --- a/og/monitoring/gen/README.md +++ /dev/null @@ -1,11 +0,0 @@ -This directory contains Grafana dashboards that can be useful for debugging / benchmarking. - -To use it: -* first, copy the content of [dashboard.json](https://raw.githubusercontent.com/pyroscope-io/pyroscope/main/monitoring/gen/dashboard.json) file. -* go to your Grafana instance and go to Create > Import -* paste the content dashboard.json into the text field and click the Load button -* pick a name for your dashboard and click "Import" - -After it's done you should see a dashboard that looks like this: - -![Screen Shot 2021-12-14 at 10 52 05 AM](https://user-images.githubusercontent.com/662636/146061369-512044d1-4bea-4b6c-843d-b77797a4c044.png) diff --git a/og/monitoring/gen/benchmark-dashboard.json b/og/monitoring/gen/benchmark-dashboard.json deleted file mode 100644 index 4a7368598a..0000000000 --- a/og/monitoring/gen/benchmark-dashboard.json +++ /dev/null @@ -1,2243 +0,0 @@ -{ - "__inputs": [ ], - "__requires": [ ], - "annotations": { - "list": [ ] - }, - "editable": "true", - "gnetId": null, - "graphTooltip": 0, - "hideControls": false, - "id": null, - "links": [ ], - "refresh": "5s", - "rows": [ - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "datasource": "$PROMETHEUS_DS", - "fieldConfig": { - "defaults": { - "links": [ ], - "mappings": [ ], - "max": 1, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - } - ] - }, - "unit": "percentunit" - } - }, - "gridPos": { }, - "id": 2, - "links": [ ], - "options": { - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "7", - "targets": [ - { - "expr": "(pyroscope_benchmark_successful_uploads + pyroscope_benchmark_upload_errors) / pyroscope_benchmark_requests_total", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "title": "Run Progress", - "transparent": false, - "type": "gauge" - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 3, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_benchmark_upload_errors{}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Upload Errors (Total)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 4, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_benchmark_successful_uploads{}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Successful Uploads (Total)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Benchmark", - "titleSize": "h6", - "type": "row" - }, - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "columns": [ ], - "datasource": "$PROMETHEUS_DS", - "gridPos": { }, - "height": 10, - "id": 5, - "links": [ ], - "span": 12, - "styles": [ - { - "alias": "__name__", - "pattern": "__name__", - "type": "hidden" - }, - { - "alias": "Time", - "pattern": "Time", - "type": "hidden" - }, - { - "alias": "instance", - "pattern": "instance", - "type": "hidden" - }, - { - "alias": "Value", - "pattern": "Value", - "type": "hidden" - }, - { - "alias": "job", - "pattern": "job", - "type": "hidden" - }, - { - "alias": "use_embedded_assets", - "pattern": "use_embedded_assets", - "type": "hidden" - } - ], - "targets": [ - { - "expr": "pyroscope_build_info{instance=~\"$instance\"}", - "format": "table", - "instant": true, - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "", - "type": "table" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Meta", - "titleSize": "h6", - "type": "row" - }, - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 6, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "histogram_quantile(0.99,\n sum(rate(pyroscope_http_request_duration_seconds_bucket{\n instance=\"$instance\",\n handler!=\"/metrics\",\n handler!=\"/healthz\"\n }[$__rate_interval]))\n by (le, handler)\n)\n", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Request Latency P99", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "seconds", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "seconds", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 7, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(rate(pyroscope_http_request_duration_seconds_count\n{instance=\"$instance\", code=~\"5..\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (handler)\n/\nsum(rate(pyroscope_http_request_duration_seconds_count{instance=\"$instance\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (handler)\n", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Error Rate", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 8, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(rate(pyroscope_http_request_duration_seconds_count{instance=\"$instance\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (handler)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Throughput", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 9, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(pyroscope_http_response_size_bytes_bucket{instance=\"$instance\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (le, handler))", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Response Size P99", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 10, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "process_cpu_seconds_total{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "CPU Utilization", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": "100", - "min": "0", - "show": true - }, - { - "format": "percent", - "label": null, - "logBase": 1, - "max": "100", - "min": "0", - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "General", - "titleSize": "h6", - "type": "row" - }, - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 11, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "(rate(pyroscope_storage_db_cache_reads_total[$__rate_interval])-\nrate(pyroscope_storage_db_cache_misses_total[$__rate_interval]))\n/\nrate(pyroscope_storage_db_cache_reads_total[$__rate_interval])\n", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ name }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Cache Hit Ratio", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "percentunit", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "percentunit", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 12, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(pyroscope_storage_db_cache_write_bytes_sum[$__rate_interval])*-1", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Writes - {{name}}", - "refId": "A" - }, - { - "expr": "rate(pyroscope_storage_db_cache_read_bytes_sum[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Reads - {{name}}", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Cache disk IO", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 13, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(pyroscope_storage_reads_total[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Reads", - "refId": "A" - }, - { - "expr": "rate(pyroscope_storage_writes_total[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Writes", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Storage Reads/Writes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 14, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_storage_eviction_task_duration_seconds{quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "evictions", - "refId": "A" - }, - { - "expr": "pyroscope_storage_writeback_task_duration_seconds{quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "write-back", - "refId": "B" - }, - { - "expr": "pyroscope_storage_retention_task_duration_seconds{quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "retention", - "refId": "C" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Periodic tasks", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "seconds", - "label": null, - "logBase": 2, - "max": null, - "min": null, - "show": true - }, - { - "format": "seconds", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 15, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_storage_db_size_bytes", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ name }}", - "refId": "A" - }, - { - "expr": "sum without(name)(pyroscope_storage_db_size_bytes)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "total", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Disk Usage", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 16, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_storage_db_cache_size", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ name }}", - "refId": "A" - }, - { - "expr": "sum without(name)(pyroscope_storage_db_cache_size)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "total", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Cache Size (number of items)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Storage", - "titleSize": "h6", - "type": "row" - }, - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 17, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_mspan_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "go_memstats_mspan_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - }, - { - "expr": "go_memstats_mcache_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "C" - }, - { - "expr": "go_memstats_mcache_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "D" - }, - { - "expr": "go_memstats_buck_hash_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "E" - }, - { - "expr": "go_memstats_gc_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "F" - }, - { - "expr": "go_memstats_other_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "G" - }, - { - "expr": "go_memstats_next_gc_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "H" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Memory Off-heap", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 18, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_heap_alloc_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "go_memstats_heap_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - }, - { - "expr": "go_memstats_heap_idle_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "C" - }, - { - "expr": "go_memstats_heap_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "D" - }, - { - "expr": "go_memstats_heap_released_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "E" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Memory In Heap", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 19, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_stack_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "go_memstats_stack_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Memory In Stack", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 20, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Total Used Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 21, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_mallocs_total{instance=\"$instance\"} - go_memstats_frees_total{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Number of Live Objects", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 22, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(go_memstats_mallocs_total{instance=\"$instance\"}[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Rate of Objects Allocated", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 23, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(go_memstats_alloc_bytes_total{instance=\"$instance\"}[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Rates of Allocation", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 24, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_goroutines{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Goroutines", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 25, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_gc_duration_seconds{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "GC duration quantile", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 26, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "process_open_fds{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "process_max_fds{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "File descriptors", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Go", - "titleSize": "h6", - "type": "row" - } - ], - "schemaVersion": 14, - "style": "dark", - "tags": [ - "pyroscope" - ], - "templating": { - "list": [ - { - "current": { - "text": "prometheus", - "value": "prometheus" - }, - "hide": 2, - "label": null, - "name": "PROMETHEUS_DS", - "options": [ ], - "query": "prometheus", - "refresh": 1, - "regex": "", - "type": "datasource" - }, - { - "allValue": null, - "current": { }, - "datasource": "$PROMETHEUS_DS", - "hide": 0, - "includeAll": false, - "label": "instance", - "multi": false, - "name": "instance", - "options": [ ], - "query": "label_values(pyroscope_build_info, instance)", - "refresh": 2, - "regex": "", - "sort": 0, - "tagValuesQuery": "", - "tags": [ ], - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "browser", - "title": "Pyroscope Server", - "uid": "tsWRL6ReZQkirFirmyvnWX1akHXJeHT8I8emjGJo", - "version": 0 -} diff --git a/og/monitoring/gen/benchmark-pr.json b/og/monitoring/gen/benchmark-pr.json deleted file mode 100644 index 456ff0841b..0000000000 --- a/og/monitoring/gen/benchmark-pr.json +++ /dev/null @@ -1,571 +0,0 @@ -{ - "__inputs": [ ], - "__requires": [ ], - "annotations": { - "list": [ ] - }, - "editable": "true", - "gnetId": null, - "graphTooltip": 0, - "hideControls": false, - "id": null, - "links": [ ], - "refresh": "5s", - "rows": [ - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 2, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(pyroscope_http_request_duration_seconds_count{handler=\"/ingest\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Throughput", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 3, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(pyroscope_storage_db_size_bytes) by (instance)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "total {{ instance }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Disk Usage", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 4, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": true, - "max": true, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_heap_alloc_bytes{job=\"pyroscope\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "heap size {{ instance }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 2, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 5, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_benchmark_upload_errors{}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Upload Errors (Total)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 6, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_benchmark_successful_uploads{}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Successful Uploads (Total)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 7, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "process_cpu_seconds_total{job=\"pyroscope\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "CPU Utilization", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": "100", - "min": "0", - "show": true - }, - { - "format": "percent", - "label": null, - "logBase": 1, - "max": "100", - "min": "0", - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Benchmark", - "titleSize": "h6", - "type": "row" - } - ], - "schemaVersion": 14, - "style": "dark", - "tags": [ - "pyroscope" - ], - "templating": { - "list": [ - { - "current": { - "text": "prometheus", - "value": "prometheus" - }, - "hide": 2, - "label": null, - "name": "PROMETHEUS_DS", - "options": [ ], - "query": "prometheus", - "refresh": 1, - "regex": "", - "type": "datasource" - } - ] - }, - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "browser", - "title": "Pyroscope Server PR Dashboard", - "uid": "QF9YgRbUbt3BA5Qd", - "version": 0 -} diff --git a/og/monitoring/gen/dashboard.json b/og/monitoring/gen/dashboard.json deleted file mode 100644 index 32d2ae5470..0000000000 --- a/og/monitoring/gen/dashboard.json +++ /dev/null @@ -1,2020 +0,0 @@ -{ - "__inputs": [ ], - "__requires": [ ], - "annotations": { - "list": [ ] - }, - "editable": "true", - "gnetId": null, - "graphTooltip": 0, - "hideControls": false, - "id": null, - "links": [ ], - "refresh": "", - "rows": [ - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "columns": [ ], - "datasource": "$PROMETHEUS_DS", - "gridPos": { }, - "height": 10, - "id": 2, - "links": [ ], - "span": 12, - "styles": [ - { - "alias": "__name__", - "pattern": "__name__", - "type": "hidden" - }, - { - "alias": "Time", - "pattern": "Time", - "type": "hidden" - }, - { - "alias": "instance", - "pattern": "instance", - "type": "hidden" - }, - { - "alias": "Value", - "pattern": "Value", - "type": "hidden" - }, - { - "alias": "job", - "pattern": "job", - "type": "hidden" - }, - { - "alias": "use_embedded_assets", - "pattern": "use_embedded_assets", - "type": "hidden" - } - ], - "targets": [ - { - "expr": "pyroscope_build_info{instance=\"$instance\"}", - "format": "table", - "instant": true, - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "", - "type": "table" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Meta", - "titleSize": "h6", - "type": "row" - }, - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 3, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "histogram_quantile(0.99,\n sum(rate(pyroscope_http_request_duration_seconds_bucket{\n instance=\"$instance\",\n handler!=\"/metrics\",\n handler!=\"/healthz\"\n }[$__rate_interval]))\n by (le, handler)\n)\n", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Request Latency P99", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "seconds", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "seconds", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 4, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(rate(pyroscope_http_request_duration_seconds_count\n{instance=\"$instance\", code=~\"5..\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (handler)\n/\nsum(rate(pyroscope_http_request_duration_seconds_count{instance=\"$instance\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (handler)\n", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Error Rate", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 5, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(rate(pyroscope_http_request_duration_seconds_count{instance=\"$instance\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (handler)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Throughput", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 6, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(pyroscope_http_response_size_bytes_bucket{instance=\"$instance\", handler!=\"/metrics\", handler!=\"/healthz\"}[$__rate_interval])) by (le, handler))", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ handler }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Response Size P99", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 7, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "process_cpu_seconds_total{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "CPU Utilization", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "percent", - "label": null, - "logBase": 1, - "max": "100", - "min": "0", - "show": true - }, - { - "format": "percent", - "label": null, - "logBase": 1, - "max": "100", - "min": "0", - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "General", - "titleSize": "h6", - "type": "row" - }, - { - "collapse": false, - "collapsed": false, - "panels": [ - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 8, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "(rate(pyroscope_storage_db_cache_reads_total[$__rate_interval])-\nrate(pyroscope_storage_db_cache_misses_total[$__rate_interval]))\n/\nrate(pyroscope_storage_db_cache_reads_total[$__rate_interval])\n", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ name }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Cache Hit Ratio", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "percentunit", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "percentunit", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 9, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(pyroscope_storage_db_cache_write_bytes_sum[$__rate_interval])*-1", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Writes - {{name}}", - "refId": "A" - }, - { - "expr": "rate(pyroscope_storage_db_cache_read_bytes_sum[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Reads - {{name}}", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Cache disk IO", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 10, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(pyroscope_storage_reads_total[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Reads", - "refId": "A" - }, - { - "expr": "rate(pyroscope_storage_writes_total[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "Writes", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Storage Reads/Writes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 11, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_storage_eviction_task_duration_seconds{quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "evictions", - "refId": "A" - }, - { - "expr": "pyroscope_storage_writeback_task_duration_seconds{quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "write-back", - "refId": "B" - }, - { - "expr": "pyroscope_storage_retention_task_duration_seconds{quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "retention", - "refId": "C" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Periodic tasks", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "seconds", - "label": null, - "logBase": 2, - "max": null, - "min": null, - "show": true - }, - { - "format": "seconds", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 12, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_storage_db_size_bytes", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ name }}", - "refId": "A" - }, - { - "expr": "sum without(name)(pyroscope_storage_db_size_bytes)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "total", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Disk Usage", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 13, - "legend": { - "alignAsTable": "true", - "avg": false, - "current": "true", - "max": false, - "min": false, - "rightSide": "true", - "show": true, - "sideWidth": null, - "sort": "current", - "sortDesc": true, - "total": false, - "values": "true" - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "pyroscope_storage_db_cache_size", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ name }}", - "refId": "A" - }, - { - "expr": "sum without(name)(pyroscope_storage_db_cache_size)", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "total", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Cache Size (number of items)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Storage", - "titleSize": "h6", - "type": "row" - }, - { - "collapse": true, - "collapsed": true, - "panels": [ - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 14, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_mspan_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "go_memstats_mspan_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - }, - { - "expr": "go_memstats_mcache_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "C" - }, - { - "expr": "go_memstats_mcache_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "D" - }, - { - "expr": "go_memstats_buck_hash_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "E" - }, - { - "expr": "go_memstats_gc_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "F" - }, - { - "expr": "go_memstats_other_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "G" - }, - { - "expr": "go_memstats_next_gc_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "H" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Memory Off-heap", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 15, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_heap_alloc_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "go_memstats_heap_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - }, - { - "expr": "go_memstats_heap_idle_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "C" - }, - { - "expr": "go_memstats_heap_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "D" - }, - { - "expr": "go_memstats_heap_released_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "E" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Memory In Heap", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 16, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_stack_inuse_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "go_memstats_stack_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Memory In Stack", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 17, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_sys_bytes{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Total Used Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 18, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_memstats_mallocs_total{instance=\"$instance\"} - go_memstats_frees_total{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Number of Live Objects", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 19, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(go_memstats_mallocs_total{instance=\"$instance\"}[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Rate of Objects Allocated", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 20, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(go_memstats_alloc_bytes_total{instance=\"$instance\"}[$__rate_interval])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Rates of Allocation", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 21, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_goroutines{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "Goroutines", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 22, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": false, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "go_gc_duration_seconds{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "GC duration quantile", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": { }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$PROMETHEUS_DS", - "fill": 1, - "fillGradient": 0, - "gridPos": { }, - "id": 23, - "legend": { - "alignAsTable": false, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": false, - "show": true, - "sideWidth": null, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ ], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "repeat": null, - "seriesOverrides": [ ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "process_open_fds{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "A" - }, - { - "expr": "process_max_fds{instance=\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{ __name__ }}", - "refId": "B" - } - ], - "thresholds": [ ], - "timeFrom": null, - "timeShift": null, - "title": "File descriptors", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [ ] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": true, - "title": "Go", - "titleSize": "h6", - "type": "row" - } - ], - "schemaVersion": 14, - "style": "dark", - "tags": [ - "pyroscope" - ], - "templating": { - "list": [ - { - "current": { - "text": "prometheus", - "value": "prometheus" - }, - "hide": 2, - "label": null, - "name": "PROMETHEUS_DS", - "options": [ ], - "query": "prometheus", - "refresh": 1, - "regex": "", - "type": "datasource" - }, - { - "allValue": null, - "current": { }, - "datasource": "$PROMETHEUS_DS", - "hide": 0, - "includeAll": false, - "label": "instance", - "multi": false, - "name": "instance", - "options": [ ], - "query": "label_values(pyroscope_build_info, instance)", - "refresh": 2, - "regex": "", - "sort": 0, - "tagValuesQuery": "", - "tags": [ ], - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "browser", - "title": "Pyroscope Server", - "uid": "tsWRL6ReZQkirFirmyvnWX1akHXJeHT8I8emjGJo", - "version": 0 -} diff --git a/og/monitoring/jsonnetfile.json b/og/monitoring/jsonnetfile.json deleted file mode 100644 index 93f3316ec3..0000000000 --- a/og/monitoring/jsonnetfile.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "version": 1, - "dependencies": [ - { - "source": { - "git": { - "remote": "https://github.com/grafana/grafonnet-lib.git", - "subdir": "grafonnet" - } - }, - "version": "master" - } - ], - "legacyImports": true -} diff --git a/og/monitoring/jsonnetfile.lock.json b/og/monitoring/jsonnetfile.lock.json deleted file mode 100644 index 7e9d67cc1f..0000000000 --- a/og/monitoring/jsonnetfile.lock.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": 1, - "dependencies": [ - { - "source": { - "git": { - "remote": "https://github.com/grafana/grafonnet-lib.git", - "subdir": "grafonnet" - } - }, - "version": "3082bfca110166cd69533fa3c0875fdb1b68c329", - "sum": "4/sUV0Kk+o8I+wlYxL9R6EPhL/NiLfYHk+NXlU64RUk=" - } - ], - "legacyImports": false -} diff --git a/og/monitoring/lib/dashboard.libsonnet b/og/monitoring/lib/dashboard.libsonnet deleted file mode 100644 index e2b73afabf..0000000000 --- a/og/monitoring/lib/dashboard.libsonnet +++ /dev/null @@ -1,531 +0,0 @@ -local grafana = import 'grafonnet/grafana.libsonnet'; - - -{ - dashboard: - local d = grafana.dashboard.new( - 'Pyroscope Server', - tags=['pyroscope'], - time_from='now-1h', - uid='tsWRL6ReZQkirFirmyvnWX1akHXJeHT8I8emjGJo', - editable='true', - refresh = if $._config.benchmark then '5s' else '', - ); - - // conditionally add a benchmark rowat the top if appropriate - local dashboard = if $._config.benchmark then - d - .addRow( - grafana.row.new( - title='Benchmark', - ) - .addPanel( - grafana.gaugePanel.new( - 'Run Progress', - datasource='$PROMETHEUS_DS', - unit='percentunit', - reducerFunction='lastNotNull', - min=0, - max=1, - ) - .addThreshold({ color: 'green', value: 0 }) - .addTarget( - grafana.prometheus.target( - '(pyroscope_benchmark_successful_uploads + pyroscope_benchmark_upload_errors) / pyroscope_benchmark_requests_total', - ) - ) - ) - .addPanel( - grafana.graphPanel.new( - 'Upload Errors (Total)', - datasource='$PROMETHEUS_DS', - span=4, - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_benchmark_upload_errors{}', - legendFormat='{{ __name__ }}', - ) - ) - ) - .addPanel( - grafana.graphPanel.new( - 'Successful Uploads (Total)', - datasource='$PROMETHEUS_DS', - span=4, - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_benchmark_successful_uploads{}', - legendFormat='{{ __name__ }}', - ) - ) - ) - ) - else d; - - dashboard - .addTemplate( - grafana.template.datasource( - name='PROMETHEUS_DS', - query='prometheus', - current='prometheus', - hide='hidden', // anything other than '' and 'label works - ) - ) - .addTemplate( - grafana.template.new( - 'instance', - '$PROMETHEUS_DS', - 'label_values(pyroscope_build_info, instance)', - // otherwise the variable may be unpopulated - // eg. when prometheus/grafana/pyroscope are started at the same time - refresh='time', - label='instance', - ) - ) - - .addRow( - grafana.row.new( - title='Meta', - ) - .addPanel( - grafana.tablePanel.new( - title='', - datasource='$PROMETHEUS_DS', - span=12, - height=10, - ) - // they don't provide any value - .hideColumn("__name__") - .hideColumn("Time") - .hideColumn("instance") - .hideColumn("Value") - .hideColumn("job") - - // somewhat useful but preferred to be hidden - // to make the table cleaner - .hideColumn("use_embedded_assets") - .addTarget( - grafana.prometheus.target( - 'pyroscope_build_info{%s}' % $._config.selector, - instant=true, - format='table', - ) - ) - ) - ) - - - // Only useful when running benchmark - - - .addRow( - grafana.row.new( - title='General', - ) - .addPanel( - grafana.graphPanel.new( - 'Request Latency P99', - datasource='$PROMETHEUS_DS', - format='seconds', - ) - .addTarget(grafana.prometheus.target(||| - histogram_quantile(0.99, - sum(rate(pyroscope_http_request_duration_seconds_bucket{ - instance="$instance", - handler!="/metrics", - handler!="/healthz" - }[$__rate_interval])) - by (le, handler) - ) - |||, - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Error Rate', - datasource='$PROMETHEUS_DS', - ) - .addTarget(grafana.prometheus.target(||| - sum(rate(pyroscope_http_request_duration_seconds_count - {instance="$instance", code=~"5..", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (handler) - / - sum(rate(pyroscope_http_request_duration_seconds_count{instance="$instance", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (handler) - |||, - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Throughput', - datasource='$PROMETHEUS_DS', - ) - .addTarget(grafana.prometheus.target('sum(rate(pyroscope_http_request_duration_seconds_count{instance="$instance", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (handler)', - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Response Size P99', - datasource='$PROMETHEUS_DS', - format='bytes', - ) - .addTarget(grafana.prometheus.target('histogram_quantile(0.95, sum(rate(pyroscope_http_response_size_bytes_bucket{instance="$instance", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (le, handler))', - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'CPU Utilization', - datasource='$PROMETHEUS_DS', - format='percent', - min='0', - max='100', - legend_show=false, - ) - .addTarget( - grafana.prometheus.target( - 'process_cpu_seconds_total{instance="$instance"}', - ) - ) - ) - - ) - - - .addRow( - grafana.row.new( - title='Storage', - ) - .addPanel( - grafana.graphPanel.new( - 'Cache Hit Ratio', - datasource='$PROMETHEUS_DS', - legend_values='true', - legend_rightSide='true', - legend_alignAsTable='true', - legend_current='true', - legend_sort='current', - legend_sortDesc=true, - format='percentunit', - ) - .addTarget( - grafana.prometheus.target(||| - (rate(pyroscope_storage_db_cache_reads_total[$__rate_interval])- - rate(pyroscope_storage_db_cache_misses_total[$__rate_interval])) - / - rate(pyroscope_storage_db_cache_reads_total[$__rate_interval]) - |||, - legendFormat='{{ name }}', - ) - ) - ) - .addPanel( - grafana.graphPanel.new( - 'Cache disk IO', - datasource='$PROMETHEUS_DS', - legend_values='true', - legend_rightSide='true', - legend_alignAsTable='true', - legend_current='true', - legend_sort='current', - legend_sortDesc=true, - format='Bps', - ) - .addTarget( - grafana.prometheus.target( - 'rate(pyroscope_storage_db_cache_write_bytes_sum[$__rate_interval])*-1', - legendFormat="Writes - {{name}}", - ) - ) - .addTarget( - grafana.prometheus.target( - 'rate(pyroscope_storage_db_cache_read_bytes_sum[$__rate_interval])', - legendFormat="Reads - {{name}}", - ) - ) - ) - - .addPanel( - grafana.graphPanel.new( - 'Storage Reads/Writes', - datasource='$PROMETHEUS_DS', - ) - .addTarget( - grafana.prometheus.target( - 'rate(pyroscope_storage_reads_total[$__rate_interval])', - legendFormat="Reads", - ) - ) - .addTarget( - grafana.prometheus.target( - 'rate(pyroscope_storage_writes_total[$__rate_interval])', - legendFormat="Writes", - ) - ) - ) - .addPanel( - grafana.graphPanel.new( - 'Periodic tasks', - datasource='$PROMETHEUS_DS', - legend_values='true', - format='seconds', - logBase1Y=2, - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_storage_eviction_task_duration_seconds{quantile="0.99"}', - legendFormat='evictions', - ), - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_storage_writeback_task_duration_seconds{quantile="0.99"}', - legendFormat='write-back', - ), - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_storage_retention_task_duration_seconds{quantile="0.99"}', - legendFormat='retention', - ), - ) - ) - - .addPanel( - grafana.graphPanel.new( - 'Disk Usage', - datasource='$PROMETHEUS_DS', - format='bytes', - legend_values='true', - legend_rightSide='true', - legend_alignAsTable='true', - legend_current='true', - legend_sort='current', - legend_sortDesc=true, - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_storage_db_size_bytes', - legendFormat='{{ name }}', - ), - ) - .addTarget( - grafana.prometheus.target( - 'sum without(name)(pyroscope_storage_db_size_bytes)', - legendFormat='total', - ), - ) - ) - - .addPanel( - grafana.graphPanel.new( - 'Cache Size (number of items)', - datasource='$PROMETHEUS_DS', - legend_values='true', - legend_rightSide='true', - legend_alignAsTable='true', - legend_current='true', - legend_sort='current', - legend_sortDesc=true, - ) - .addTarget( - grafana.prometheus.target( - 'pyroscope_storage_db_cache_size', - legendFormat='{{ name }}', - ), - ) - .addTarget( - grafana.prometheus.target( - 'sum without(name)(pyroscope_storage_db_cache_size)', - legendFormat='total', - ), - ) - ) - ) - - // inspired by - // https://github.com/aukhatov/grafana-dashboards/blob/master/Go%20Metrics-1567509764849.json - .addRow( - grafana.row.new( - title='Go', - collapse=if $._config.benchmark then false else true, - ) - .addPanel( - grafana.graphPanel.new( - 'Memory Off-heap', - datasource='$PROMETHEUS_DS', - format='bytes', - ) - .addTarget( - grafana.prometheus.target( - 'go_memstats_mspan_inuse_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - ) - ) - .addTarget( - grafana.prometheus.target( - 'go_memstats_mspan_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - ) - ) - .addTarget(grafana.prometheus.target( - 'go_memstats_mcache_inuse_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_mcache_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_buck_hash_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_gc_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_other_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_next_gc_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Memory In Heap', - datasource='$PROMETHEUS_DS', - format='bytes', - ) - .addTarget(grafana.prometheus.target( - 'go_memstats_heap_alloc_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_heap_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_heap_idle_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_heap_inuse_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'go_memstats_heap_released_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - ) - - - .addPanel( - grafana.graphPanel.new( - 'Memory In Stack', - datasource='$PROMETHEUS_DS', - format='decbytes', - ) - .addTarget( - grafana.prometheus.target( - 'go_memstats_stack_inuse_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - ) - ) - .addTarget( - grafana.prometheus.target( - 'go_memstats_stack_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - ) - ) - ) - - - - .addPanel( - grafana.graphPanel.new( - 'Total Used Memory', - datasource='$PROMETHEUS_DS', - format='decbytes', - ) - .addTarget(grafana.prometheus.target( - 'go_memstats_sys_bytes{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - ) - - - .addPanel( - grafana.graphPanel.new( - 'Number of Live Objects', - datasource='$PROMETHEUS_DS', - legend_show=false, - ) - .addTarget(grafana.prometheus.target( - 'go_memstats_mallocs_total{instance="$instance"} - go_memstats_frees_total{instance="$instance"}' - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Rate of Objects Allocated', - datasource='$PROMETHEUS_DS', - legend_show=false, - ) - .addTarget(grafana.prometheus.target('rate(go_memstats_mallocs_total{instance="$instance"}[$__rate_interval])')) - ) - - .addPanel( - grafana.graphPanel.new( - 'Rates of Allocation', - datasource='$PROMETHEUS_DS', - format="Bps", - legend_show=false, - ) - .addTarget(grafana.prometheus.target('rate(go_memstats_alloc_bytes_total{instance="$instance"}[$__rate_interval])')) - ) - - .addPanel( - grafana.graphPanel.new( - 'Goroutines', - datasource='$PROMETHEUS_DS', - legend_show=false, - ) - .addTarget(grafana.prometheus.target('go_goroutines{instance="$instance"}')) - ) - - .addPanel( - grafana.graphPanel.new( - 'GC duration quantile', - datasource='$PROMETHEUS_DS', - legend_show=false, - ) - .addTarget(grafana.prometheus.target('go_gc_duration_seconds{instance="$instance"}')) - ) - - .addPanel( - grafana.graphPanel.new( - 'File descriptors', - datasource='$PROMETHEUS_DS', - ) - .addTarget(grafana.prometheus.target( - 'process_open_fds{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - .addTarget(grafana.prometheus.target( - 'process_max_fds{instance="$instance"}', - legendFormat='{{ __name__ }}', - )) - ) - ) -} diff --git a/og/monitoring/lib/server-comparison.libsonnet b/og/monitoring/lib/server-comparison.libsonnet deleted file mode 100644 index acbbaf6667..0000000000 --- a/og/monitoring/lib/server-comparison.libsonnet +++ /dev/null @@ -1,149 +0,0 @@ -local grafana = import 'grafonnet/grafana.libsonnet'; - - -{ - dashboard: - local d = grafana.dashboard.new( - 'Pyroscope Server Comparison', - tags=['pyroscope'], - time_from='now-30m', - uid='8mDG2MCwXqg9hTPT', - editable='true', - refresh = '5s', - ); - - - d - .addTemplate( - grafana.template.datasource( - name='PROMETHEUS_DS', - query='prometheus', - current='prometheus', - hide='hidden', // anything other than '' and 'label works - ) - ) - .addTemplate( - grafana.template.new( - 'instance', - '$PROMETHEUS_DS', - 'label_values(pyroscope_build_info, instance)', - // otherwise the variable may be unpopulated - // eg. when prometheus/grafana/pyroscope are started at the same time - refresh='time', - label='instance', - includeAll=if $._config.benchmark then true else false, - ) - ) - - .addRow( - grafana.row.new( - title='Meta', - ) - .addPanel( - grafana.tablePanel.new( - title='', - datasource='$PROMETHEUS_DS', - span=12, - height=10, - ) - // they don't provide any value - .hideColumn("__name__") - .hideColumn("Time") - .hideColumn("Value") - .hideColumn("job") - - // somewhat useful but preferred to be hidden - // to make the table cleaner - .hideColumn("use_embedded_assets") - .addTarget( - grafana.prometheus.target( - 'pyroscope_build_info{%s}' % $._config.selector, - instant=true, - format='table', - ) - ) - ) - ) - - - // Only useful when running benchmark - - - .addRow( - grafana.row.new( - title='General', - ) - .addPanel( - grafana.graphPanel.new( - 'Request Latency P99', - datasource='$PROMETHEUS_DS', - format='seconds', - ) - .addTarget(grafana.prometheus.target(||| - histogram_quantile(0.99, - sum(rate(pyroscope_http_request_duration_seconds_bucket{ - instance="$instance", - handler!="/metrics", - handler!="/healthz" - }[$__rate_interval])) - by (le, handler) - ) - |||, - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Error Rate', - datasource='$PROMETHEUS_DS', - ) - .addTarget(grafana.prometheus.target(||| - sum(rate(pyroscope_http_request_duration_seconds_count - {instance="$instance", code=~"5..", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (handler) - / - sum(rate(pyroscope_http_request_duration_seconds_count{instance="$instance", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (handler) - |||, - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Throughput', - datasource='$PROMETHEUS_DS', - ) - .addTarget(grafana.prometheus.target('sum(rate(pyroscope_http_request_duration_seconds_count{instance="$instance", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (handler)', - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'Response Size P99', - datasource='$PROMETHEUS_DS', - format='bytes', - ) - .addTarget(grafana.prometheus.target('histogram_quantile(0.95, sum(rate(pyroscope_http_response_size_bytes_bucket{instance="$instance", handler!="/metrics", handler!="/healthz"}[$__rate_interval])) by (le, handler))', - legendFormat='{{ handler }}', - )) - ) - - .addPanel( - grafana.graphPanel.new( - 'CPU Utilization', - datasource='$PROMETHEUS_DS', - format='percent', - min='0', - max='100', - legend_show=false, - ) - .addTarget( - grafana.prometheus.target( - 'process_cpu_seconds_total{instance="$instance"}', - ) - ) - ) - - ) -} diff --git a/og/package.json b/og/package.json deleted file mode 100644 index 069090a81b..0000000000 --- a/og/package.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "author": "Pyroscope Team", - "name": "pyroscope-oss", - "private": true, - "version": "0.37.2", - "license": "Apache-2.0", - "main": "webapp/javascript/components/FlameGraph/FlameGraphComponent/index.jsx", - "scripts": { - "start": "lerna-watch @pyroscope/webapp", - "bootstrap": "lerna bootstrap && husky install", - "web-postinstall": "scripts/web-postinstall.js", - "postinstall": "yarn run web-postinstall", - "dev": "yarn run dev:webapp", - "dev:standalone": "webpack --config scripts/webpack/webpack.standalone.ts --watch", - "dev:flamegraph": "yarn run lerna run dev --scope=@pyroscope/flamegraph", - "dev:webapp": "yarn run lerna run dev --scope=@pyroscope/webapp", - "build": "yarn run build:webapp", - "build:webapp": "lerna run build --scope=@pyroscope/webapp --include-dependencies", - "build:standalone": "webpack --config scripts/webpack/webpack.standalone.ts", - "build:size-limit": "NODE_ENV=production NOHASH=true webpack --config scripts/webpack/webpack.size-limit.ts && yarn build:flamegraph", - "build:flamegraph": "lerna run build --scope=@pyroscope/flamegraph", - "test": "jest", - "test:ss": "UPDATE_SNAPSHOTS=true ./scripts/jest-snapshots/run-docker.sh", - "test:ss-check": "./scripts/jest-snapshots/run-docker.sh", - "lint": "lerna run lint --parallel --no-bail", - "lint:quiet": "lerna run lint --no-bail --parallel -- --quiet", - "type-check": "lerna run type-check", - "format": "prettier --write .", - "format:check": "prettier --check .", - "cy:open": "yarn cy:webapp:open", - "cy:ci": "yarn cy:webapp:ci", - "cy:ss": "yarn cy:webapp:ss", - "cy:ss-check": "yarn cy:webapp:ss-check", - "cy:webapp:open": "cypress open --config-file cypress/cypress.json", - "cy:webapp:ci": "cypress run --config-file cypress/cypress.json", - "cy:webapp:ss": "./scripts/cypress-screenshots.sh --config-file cypress/cypress.json", - "cy:webapp:ss-check": "CYPRESS_updateSnapshots=false ./scripts/cypress-screenshots.sh --config-file cypress/cypress.json", - "cy:webapp-auth:open": "cypress open --config-file cypress/integration/auth/cypress.json", - "cy:webapp-auth:ci": "cypress run --config-file cypress/integration/auth/cypress.json", - "cy:webapp-auth:ss-check": "CYPRESS_updateSnapshots=false ./scripts/cypress-screenshots.sh --config-file cypress/integration/auth/cypress.json", - "cy:webapp-base-url:open": "cypress open --config-file cypress/base-url/cypress.json", - "cy:webapp-base-url:ci": "cypress run --config-file cypress/base-url/cypress.json", - "cy:webapp-base-url:ss-check": "CYPRESS_updateSnapshots=false ./scripts/cypress-screenshots.sh --config-file cypress/base-url/cypress.json", - "lint-staged": "lint-staged", - "size": "size-limit", - "storybook": "start-storybook -p 6006", - "build-storybook": "build-storybook" - }, - "devDependencies": { - "@babel/core": "^7.22.9", - "@fortawesome/fontawesome-common-types": "~0.2.36", - "@size-limit/file": "^6.0.3", - "@size-limit/time": "^6.0.3", - "@storybook/addon-actions": "~6.5.0", - "@storybook/addon-essentials": "~6.5.0", - "@storybook/addon-links": "~6.5.0", - "@storybook/builder-webpack5": "~6.5.0", - "@storybook/manager-webpack5": "~6.5.0", - "@storybook/react": "~6.5.0", - "@swc/core": "^1.3.34", - "@swc/jest": "^0.2.24", - "@testing-library/cypress": "^8.0.0", - "@testing-library/dom": "^8.7.1", - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^12.1.1", - "@testing-library/react-hooks": "^8.0.1", - "@testing-library/user-event": "^13.2.1", - "@types/color": "^3.0.2", - "@types/d3-scale": "^4.0.2", - "@types/d3-scale-chromatic": "^3.0.0", - "@types/flot": "^0.0.32", - "@types/history": "4.7.11", - "@types/jest": "^27.0.2", - "@types/jest-image-snapshot": "^4.3.1", - "@types/jquery": "^3.5.13", - "@types/lodash": "^4.14.176", - "@types/lodash.debounce": "^4.0.6", - "@types/lodash.defaults": "^4.2.6", - "@types/lodash.groupby": "^4.6.7", - "@types/lodash.map": "^4.6.13", - "@types/mini-css-extract-plugin": "^2.4.0", - "@types/node": "^17.0.7", - "@types/prismjs": "^1.26.0", - "@types/react-copy-to-clipboard": "^5.0.2", - "@types/react-datepicker": "^4.3.4", - "@types/react-dev-utils": "^9.0.10", - "@types/react-helmet": "^6.1.5", - "@types/react-outside-click-handler": "^1.3.1", - "@types/webpack": "^5.28.0", - "@types/webpack-livereload-plugin": "^2.3.3", - "@typescript-eslint/eslint-plugin": "^5.6.0", - "@typescript-eslint/parser": "^5.6.0", - "babel-eslint": "^10.1.0", - "canvas": "^2.8.0", - "canvas-to-buffer": "^1.1.1", - "chokidar-cli": "^3.0.0", - "clean-webpack-plugin": "^3.0.0", - "contributor-faces": "^1.1.0", - "conventional-changelog-cli": "^2.1.1", - "cypress": "^8.6.0", - "cypress-image-snapshot": "^4.0.1", - "enzyme": "^3.11.0", - "enzyme-adapter-react-16": "^1.15.5", - "eslint": "7.2.0", - "eslint-config-airbnb": "18.2.1", - "eslint-config-airbnb-typescript": "^14.0.0", - "eslint-config-airbnb-typescript-prettier": "^4.2.0", - "eslint-config-prettier": "^7.1.0", - "eslint-import-resolver-lerna": "^2.0.0", - "eslint-import-resolver-typescript": "^2.0.0", - "eslint-plugin-css-modules": "^2.11.0", - "eslint-plugin-cypress": "^2.12.1", - "eslint-plugin-import": "~2.26.0", - "eslint-plugin-jest": "^25.3.4", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-prettier": "^3.3.1", - "eslint-plugin-react": "^7.21.5", - "eslint-plugin-react-hooks": "4.0.0", - "eslint-webpack-plugin": "^2.4.1", - "husky": "^7.0.2", - "jest": "^27.2.4", - "jest-canvas-mock": "^2.3.1", - "jest-css-modules-transform": "^4.3.0", - "jest-image-snapshot": "^4.5.1", - "lerna-watch": "^1.0.0", - "lint-staged": "^11.1.2", - "monaco-editor-webpack-plugin": "^1.9.0", - "npm-run-all": "^4.1.5", - "oauth2-mock-server": "^6.0.0", - "optimize-css-assets-webpack-plugin": "^6.0.1", - "prettier": "^2.2.1", - "redux-mock-store": "^1.5.4", - "regenerator-runtime": "^0.13.9", - "replace-in-file-webpack-plugin": "^1.0.6", - "sass": "^1.26.10", - "size-limit": "^6.0.3", - "typescript": "^4.5.2", - "typescript-plugin-css-modules": "^3.4.0", - "webpack": "~5.71.0", - "webpack-bundle-analyzer": "^4.4.2", - "webpack-livereload-plugin": "^3.0.2", - "webpack-merge": "^5.0.9", - "webpack-plugin-hash-output": "^3.2.1" - }, - "dependencies": { - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.10.4", - "@babel/preset-react": "^7.12.10", - "@babel/preset-typescript": "7.8.3", - "@emotion/react": "^11.10.6", - "@emotion/styled": "^11.10.6", - "@fortawesome/fontawesome-free": "~5.14.0", - "@fortawesome/fontawesome-svg-core": "~1.2.30", - "@fortawesome/free-brands-svg-icons": "~5.15.1", - "@fortawesome/free-regular-svg-icons": "~5.15.2", - "@fortawesome/free-solid-svg-icons": "~5.14.0", - "@fortawesome/react-fontawesome": "~0.1.11", - "@hookform/resolvers": "^2.9.8", - "@mui/base": "^5.0.0-alpha.98", - "@mui/material": "^5.10.11", - "@react-hook/resize-observer": "^1.2.4", - "@react-hook/window-size": "^3.0.7", - "@reduxjs/toolkit": "^1.6.2", - "@szhsin/react-menu": "3.3.0", - "@types/copy-webpack-plugin": "^6.0.0", - "@types/react": "^17.0.0", - "@types/react-notifications-component": "^3.1.1", - "@types/react-redux": "^7.1.20", - "@types/react-router-dom": "5.3.0", - "autoprefixer": "^9.8.5", - "babel-loader": "^8.1.0", - "babel-plugin-transform-class-properties": "^6.24.1", - "classnames": "^2.2.6", - "clsx": "^1.1.1", - "color": "^3.1.3", - "command-exists": "^1.2.9", - "copy-webpack-plugin": "^6.3.2", - "css-loader": "^4.0.0", - "d3": "^7.3.0", - "d3-array": "^3.1.1", - "d3-scale": "^4.0.2", - "d3-scale-chromatic": "^3.0.0", - "d3-time": "^3.0.0", - "date-fns": "^2.27.0", - "downlevel-dts": "^0.10.0", - "esbuild-loader": "^2.18.0", - "eslint-import-resolver-webpack": "^0.13.2", - "file-loader": "^6.2.0", - "glob": "^7.1.7", - "graphviz-react": "^1.2.5", - "html-inline-css-webpack-plugin": "^1.11.1", - "html-webpack-plugin": "^5.5.0", - "humanize-duration": "^3.25.1", - "jest-fetch-mock": "^3.0.3", - "jquery": "3.6.0", - "jquery.flot.tooltip": "^0.9.0", - "lerna": "^5.0.0", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "lodash.defaults": "^4.2.0", - "lodash.groupby": "^4.6.0", - "lodash.map": "^4.6.0", - "mini-css-extract-plugin": "^2.2.0", - "moment": "^2.27.0", - "msw": "^0.36.3", - "node-fetch": "^2.6.6", - "normalize.css": "^8.0.1", - "postcss-browser-reporter": "^0.6.0", - "postcss-loader": "^3.0.0", - "postcss-preset-env": "^7.0.1", - "postcss-reporter": "^6.0.1", - "prismjs": "^1.27.0", - "react": "16.14.0", - "react-copy-to-clipboard": "^5.0.4", - "react-datepicker": "^4.7.0", - "react-debounce-input": "^3.2.5", - "react-dev-utils": "^12.0.0", - "react-dom": "16.14.0", - "react-dropzone": "^11.4.2", - "react-flot": "^1.3.0", - "react-helmet": "^6.1.0", - "react-hook-form": "^7.36.0", - "react-modal": "^3.12.1", - "react-notifications-component": "~3.1.0", - "react-outside-click-handler": "^1.3.0", - "react-pro-sidebar": "^0.7.1", - "react-redux": "^7.2.1", - "react-router-dom": "5.3.0", - "react-svg-loader": "^3.0.3", - "react-svg-spinner": "^1.0.4", - "react-textarea-autosize": "8.3.0", - "redux": "^4.0.5", - "redux-devtools-extension": "^2.13.8", - "redux-localstorage": "^0.4.1", - "redux-persist": "^6.0.0", - "redux-promise": "^0.6.0", - "redux-query-sync": "^0.1.10", - "redux-thunk": "^2.3.0", - "sass-loader": "^9.0.2", - "serialize-error": "^9.1.0", - "style-loader": "^3.2.1", - "svg-url-loader": "^7.1.1", - "sweetalert2": "^11.4.0, <11.4.9", - "sweetalert2-react-content": "^4.2.0", - "timezone-mock": "^1.3.0", - "true-myth": "~5.2.0", - "ts-custom-error": "^3.2.0", - "ts-essentials": "^9.0.0", - "ts-node": "^10.4.0", - "url-loader": "^4.1.1", - "webpack-cli": "~4.9.2", - "zod": "3.22.3" - }, - "engines": { - "node": ">=16.18.0" - }, - "lint-staged": { - "*.{js,jsx,ts,tsx,json,yml,yaml,eslintrc,prettierrc,css,scss}": "prettier --write" - }, - "resolutions": { - "@babel/core": "^7.22.9", - "@babel/generator": "^7.22.9", - "@babel/traverse": "^7.22.8", - "d3-color": "^3.1.0", - "react": "16.14.0", - "react-dom": "16.14.0", - "jquery": "3.6.0", - "nth-check": "^2.0.1", - "protobufjs": "^7.2.4", - "tough-cookie": "^4.1.3", - "optionator": "^0.9.3", - "d3-graphviz": "5.0.2", - "d3-selection": "3.0.0", - "semver": "^7.5.2" - } -} diff --git a/og/packages/README.md b/og/packages/README.md deleted file mode 100644 index c88ddf353a..0000000000 --- a/og/packages/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Lerna packages - - -# Local debugging -If you are trying to debug the publish of packages locally, use `verdaccio` as the registry: - - -```sh -npx verdaccio - -verdaccio -npm set registry http://localhost:4873 -npm adduser --registry http://localhost:4873 -lerna publish -``` - -Then in your `lerna publish` command pass the `registry` flag pointing to `verdaccio`, -for example: `yarn lerna publish --registry=http://localhost:4873` - -source: https://github.com/lerna/lerna/issues/51#issuecomment-348256663 diff --git a/og/packages/pyroscope-flamegraph/.eslintrc.js b/og/packages/pyroscope-flamegraph/.eslintrc.js deleted file mode 100644 index c45512d9cf..0000000000 --- a/og/packages/pyroscope-flamegraph/.eslintrc.js +++ /dev/null @@ -1,28 +0,0 @@ -const path = require('path'); - -module.exports = { - extends: [path.join(__dirname, '../../.eslintrc.js')], - ignorePatterns: [ - 'babel.config.js', - 'jest.config.js', - 'setupAfterEnv.ts', - '*.spec.*', - '.eslintrc.js', - // This file is not actually bundled - // TODO move it to ./testFixtures or something - 'src/FlameGraph/FlameGraphComponent/testData.ts', - ], - - rules: { - // https://github.com/import-js/eslint-plugin-import/issues/1650 - 'import/no-extraneous-dependencies': [ - 'error', - { - packageDir: [process.cwd(), path.resolve(__dirname, '../../')], - }, - ], - }, - parserOptions: { - tsconfigRootDir: __dirname, - }, -}; diff --git a/og/packages/pyroscope-flamegraph/CHANGELOG.md b/og/packages/pyroscope-flamegraph/CHANGELOG.md deleted file mode 100644 index defc08119a..0000000000 --- a/og/packages/pyroscope-flamegraph/CHANGELOG.md +++ /dev/null @@ -1,1211 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [0.35.6](https://github.com/grafana/pyroscope/compare/@pyroscope/flamegraph@0.35.5...@pyroscope/flamegraph@0.35.6) (2023-05-25) - - -### Performance Improvements - -* **flamegraph:** improve performance ([#1957](https://github.com/grafana/pyroscope/issues/1957)) ([e1f2caf](https://github.com/grafana/pyroscope/commit/e1f2caf78c24850d2487b1abd0a1f5558486d8f8)) - - - - - -## [0.35.5](https://github.com/grafana/pyroscope/compare/@pyroscope/flamegraph@0.35.4...@pyroscope/flamegraph@0.35.5) (2023-03-29) - - -### Bug Fixes - -* **pyroscope-flamegraph:** don't pollute property from prototype ([#1907](https://github.com/grafana/pyroscope/issues/1907)) ([272fbe0](https://github.com/grafana/pyroscope/commit/272fbe097da25214d8f70d280a88faa580a4f5d6)) -* **pyroscope-flamegraph:** use map in sandwich conversion to not conflict with properties from the prototype ([#1906](https://github.com/grafana/pyroscope/issues/1906)) ([5371b95](https://github.com/grafana/pyroscope/commit/5371b95a6ca71d0c52fa25931c93e73942e00234)) - - - - - -## [0.35.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.35.3...@pyroscope/flamegraph@0.35.4) (2023-03-14) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.35.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.35.2...@pyroscope/flamegraph@0.35.3) (2023-03-14) - - -### Bug Fixes - -* **flamegraph:** fix styling when in light mode ([#1889](https://github.com/pyroscope-io/pyroscope/issues/1889)) ([6bd54e2](https://github.com/pyroscope-io/pyroscope/commit/6bd54e2079bb622723844ce26c1ea3c8dc6a91c3)) - - - - - -## [0.35.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.35.1...@pyroscope/flamegraph@0.35.2) (2023-02-07) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.35.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.35.0...@pyroscope/flamegraph@0.35.1) (2023-02-03) - - -### Performance Improvements - -* **flamegraph:** don't convert to graphviz format unnecessarily ([#1834](https://github.com/pyroscope-io/pyroscope/issues/1834)) ([8f78e54](https://github.com/pyroscope-io/pyroscope/commit/8f78e54d75cf6f8067ef38da5b2c2eb15860ec09)) - - - - - -# [0.35.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.34.3...@pyroscope/flamegraph@0.35.0) (2023-01-23) - - -### Features - -* graphviz visualization support ([#1759](https://github.com/pyroscope-io/pyroscope/issues/1759)) ([ca855d2](https://github.com/pyroscope-io/pyroscope/commit/ca855d2eb424590393d8c0086a1ffcd00f2bc88c)) - - - - - -## [0.34.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.34.2...@pyroscope/flamegraph@0.34.3) (2022-12-02) - - -### Bug Fixes - -* **webapp:** toolbar overlaps annotation ([#1785](https://github.com/pyroscope-io/pyroscope/issues/1785)) ([24722d2](https://github.com/pyroscope-io/pyroscope/commit/24722d2843539deef587781612d3ccee89e2e9d5)) - - - - - -## [0.34.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.34.1...@pyroscope/flamegraph@0.34.2) (2022-12-02) - - -### Bug Fixes - -* **flamegraph:** increase specificity of flamegraph tooltip table styling ([#1778](https://github.com/pyroscope-io/pyroscope/issues/1778)) ([6648fc5](https://github.com/pyroscope-io/pyroscope/commit/6648fc59b1da14aa7146a0b5dc3f72c29733c63e)) - - - - - -## [0.34.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.34.0...@pyroscope/flamegraph@0.34.1) (2022-12-01) - - -### Bug Fixes - -* small toolbar fixes ([#1777](https://github.com/pyroscope-io/pyroscope/issues/1777)) ([196c6d8](https://github.com/pyroscope-io/pyroscope/commit/196c6d84adeb91efb4a8e4ee9606b5bdcb6a31f4)) - - - - - -# [0.34.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.33.0...@pyroscope/flamegraph@0.34.0) (2022-11-30) - - -### Features - -* **flamegraph:** allow sorting by diff percentage ([#1776](https://github.com/pyroscope-io/pyroscope/issues/1776)) ([8d9c838](https://github.com/pyroscope-io/pyroscope/commit/8d9c838d7b96daf1e1aa482b1f2d0820bd81f8ed)) - - - - - -# [0.33.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.32.6...@pyroscope/flamegraph@0.33.0) (2022-11-30) - - -### Features - -* fix toolbar on narrow screens ([#1754](https://github.com/pyroscope-io/pyroscope/issues/1754)) ([78b27d8](https://github.com/pyroscope-io/pyroscope/commit/78b27d8cc8a93149c79f6d4103e8ae81d7b3b024)) - - - - - -## [0.32.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.32.5...@pyroscope/flamegraph@0.32.6) (2022-11-29) - - -### Bug Fixes - -* **flamegraph:** Make table tooltip invisible when user not hovering on table ([#1749](https://github.com/pyroscope-io/pyroscope/issues/1749)) ([5210aa7](https://github.com/pyroscope-io/pyroscope/commit/5210aa72724f7ac2f2c639fe6584d565d7ae1b75)) - - - - - -## [0.32.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.32.4...@pyroscope/flamegraph@0.32.5) (2022-11-28) - - -### Bug Fixes - -* make table rows only take one line ([#1765](https://github.com/pyroscope-io/pyroscope/issues/1765)) ([6d33d42](https://github.com/pyroscope-io/pyroscope/commit/6d33d426b4f94833059fea5ca995bb5aa9dd022a)) - - - - - -## [0.32.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.32.3...@pyroscope/flamegraph@0.32.4) (2022-11-28) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.32.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.32.2...@pyroscope/flamegraph@0.32.3) (2022-11-23) - - -### Bug Fixes - -* **flamegraph:** fix dropdown menu opening ([#1755](https://github.com/pyroscope-io/pyroscope/issues/1755)) ([0b1acef](https://github.com/pyroscope-io/pyroscope/commit/0b1acef9c5d5a2a268f952a529d12f784d257842)) - - - - - -## [0.32.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.32.1...@pyroscope/flamegraph@0.32.2) (2022-11-21) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.32.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.32.0...@pyroscope/flamegraph@0.32.1) (2022-11-18) - - -### Bug Fixes - -* make reset view available in sandwich mode context menu ([#1731](https://github.com/pyroscope-io/pyroscope/issues/1731)) ([e41bcaf](https://github.com/pyroscope-io/pyroscope/commit/e41bcaf5cbfc3458958132aa4f54998aedcd8328)) - - - - - -# [0.32.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.31.2...@pyroscope/flamegraph@0.32.0) (2022-11-17) - - -### Features - -* show percentages for diff table instead of absolute values ([#1697](https://github.com/pyroscope-io/pyroscope/issues/1697)) ([71efcb8](https://github.com/pyroscope-io/pyroscope/commit/71efcb868b14ff3771faa5858dd781eba0787bd8)) - - - - - -## [0.31.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.31.1...@pyroscope/flamegraph@0.31.2) (2022-11-17) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.31.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.31.0...@pyroscope/flamegraph@0.31.1) (2022-11-17) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.31.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.30.1...@pyroscope/flamegraph@0.31.0) (2022-11-15) - - -### Features - -* **webapp:** Make explore page show precise numbers in table ([#1695](https://github.com/pyroscope-io/pyroscope/issues/1695)) ([5b47c71](https://github.com/pyroscope-io/pyroscope/commit/5b47c71b6a1e85c39b4ac21b1eaeddf85bad0d94)) - - - - - -## [0.30.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.30.0...@pyroscope/flamegraph@0.30.1) (2022-11-15) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.30.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.29.1...@pyroscope/flamegraph@0.30.0) (2022-11-14) - - -### Features - -* **panel-plugin:** allow setting different views ([#1712](https://github.com/pyroscope-io/pyroscope/issues/1712)) ([058099c](https://github.com/pyroscope-io/pyroscope/commit/058099c857d80c3dc2f1c7c7a99391bd75c72178)) - - - - - -## [0.29.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.29.0...@pyroscope/flamegraph@0.29.1) (2022-11-14) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.29.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.28.0...@pyroscope/flamegraph@0.29.0) (2022-11-14) - - -### Features - -* add Fit Mode to Context Menu ([#1698](https://github.com/pyroscope-io/pyroscope/issues/1698)) ([082a971](https://github.com/pyroscope-io/pyroscope/commit/082a9715d5aed80682fc1f38988a927ca0bbcd93)) - - - - - -# [0.28.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.27.0...@pyroscope/flamegraph@0.28.0) (2022-11-11) - - -### Features - -* enable "reset view" button when table item is highlighted ([#1703](https://github.com/pyroscope-io/pyroscope/issues/1703)) ([7b1bfd5](https://github.com/pyroscope-io/pyroscope/commit/7b1bfd55a3d6186877104e7e164323ee9a4d4f34)) - - - - - -# [0.27.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.26.0...@pyroscope/flamegraph@0.27.0) (2022-11-10) - - -### Features - -* **flamegraph:** Redesign flamegraph toolbar to allow for more interactions ([#1674](https://github.com/pyroscope-io/pyroscope/issues/1674)) ([646501a](https://github.com/pyroscope-io/pyroscope/commit/646501a3816df6f069454213ac7884198f35cd0b)) - - - - - -# [0.26.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.25.4...@pyroscope/flamegraph@0.26.0) (2022-11-09) - - -### Bug Fixes - -* sandwich view prompt in comparison view ([#1688](https://github.com/pyroscope-io/pyroscope/issues/1688)) ([5f32774](https://github.com/pyroscope-io/pyroscope/commit/5f3277411c28988d811fa23f1029ff556a434578)) - - -### Features - -* disable sandwich view for diff page ([#1693](https://github.com/pyroscope-io/pyroscope/issues/1693)) ([b47b441](https://github.com/pyroscope-io/pyroscope/commit/b47b4411b97167c4d1b85543c0b062f0358310c2)) - - - - - -## [0.25.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.25.3...@pyroscope/flamegraph@0.25.4) (2022-11-09) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.25.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.25.2...@pyroscope/flamegraph@0.25.3) (2022-11-08) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.25.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.25.1...@pyroscope/flamegraph@0.25.2) (2022-11-06) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.25.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.25.0...@pyroscope/flamegraph@0.25.1) (2022-11-02) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.25.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.24.0...@pyroscope/flamegraph@0.25.0) (2022-11-01) - - -### Features - -* add sandwich view for table/flamegraph ([#1613](https://github.com/pyroscope-io/pyroscope/issues/1613)) ([870c0b8](https://github.com/pyroscope-io/pyroscope/commit/870c0b8f209b7b669b407f6d3b5214876e671d69)) - - - - - -# [0.24.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.23.0...@pyroscope/flamegraph@0.24.0) (2022-10-31) - - -### Features - -* add a generic Tooltip component ([#1643](https://github.com/pyroscope-io/pyroscope/issues/1643)) ([e04a9a5](https://github.com/pyroscope-io/pyroscope/commit/e04a9a5b8abacbf6c3fad87b1a8aaf2ed1636053)) - - - - - -# [0.23.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.22.0...@pyroscope/flamegraph@0.23.0) (2022-09-29) - - -### Features - -* show heatmap y-axis units ([#1559](https://github.com/pyroscope-io/pyroscope/issues/1559)) ([8199170](https://github.com/pyroscope-io/pyroscope/commit/81991706e0ba6767da9d9fdefcd89a65f527722a)) - - - - - -# [0.22.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.21.5...@pyroscope/flamegraph@0.22.0) (2022-09-29) - - -### Features - -* Heatmap should show error message if no data is returned ([#1565](https://github.com/pyroscope-io/pyroscope/issues/1565)) ([fe32a07](https://github.com/pyroscope-io/pyroscope/commit/fe32a07e6e1bf05b11a6634f6eea0b44bf8b0536)) - - - - - -## [0.21.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.21.4...@pyroscope/flamegraph@0.21.5) (2022-09-26) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.21.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.21.3...@pyroscope/flamegraph@0.21.4) (2022-09-06) - - -### Bug Fixes - -* **flamegraph:** add color to tooltip ([#1468](https://github.com/pyroscope-io/pyroscope/issues/1468)) ([1c29ef6](https://github.com/pyroscope-io/pyroscope/commit/1c29ef6328fb4f01389560a4d53f729bbca88ff3)) - - - - - -## [0.21.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.21.2...@pyroscope/flamegraph@0.21.3) (2022-09-06) - - -### Bug Fixes - -* **flamegraph:** table width ([#1466](https://github.com/pyroscope-io/pyroscope/issues/1466)) ([a60f608](https://github.com/pyroscope-io/pyroscope/commit/a60f608475a9caea0e1910f30d1c663fd38cee96)) - - - - - -## [0.21.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.21.1...@pyroscope/flamegraph@0.21.2) (2022-09-06) - - -### Bug Fixes - -* **flamegraph:** table width ([#1463](https://github.com/pyroscope-io/pyroscope/issues/1463)) ([f19b8ac](https://github.com/pyroscope-io/pyroscope/commit/f19b8ac778452ea86261563aa1d165dbc2d089e7)) - - - - - -## [0.21.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.21.0...@pyroscope/flamegraph@0.21.1) (2022-09-05) - - -### Bug Fixes - -* **flamegraph:** table, buttons colors for light mode ([#1458](https://github.com/pyroscope-io/pyroscope/issues/1458)) ([37afd3b](https://github.com/pyroscope-io/pyroscope/commit/37afd3bbdad6b9165143b92dd2312d6b125140f4)) - - - - - -# [0.21.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.20.0...@pyroscope/flamegraph@0.21.0) (2022-08-30) - - -### Features - -* **flamegraph:** added sub-second units support for trace visualization ([#1418](https://github.com/pyroscope-io/pyroscope/issues/1418)) ([21f6550](https://github.com/pyroscope-io/pyroscope/commit/21f6550bf7e280e7ee272982f9ab521bf30683c6)) - - - - - -# [0.20.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.19.3...@pyroscope/flamegraph@0.20.0) (2022-08-30) - - -### Features - -* **webapp:** dropdown component for head-first dropdown ([#1435](https://github.com/pyroscope-io/pyroscope/issues/1435)) ([a7d6891](https://github.com/pyroscope-io/pyroscope/commit/a7d6891c8b63d67dc197d7c52812bd946ca688e5)) - - - - - -## [0.19.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.19.2...@pyroscope/flamegraph@0.19.3) (2022-08-26) - - -### Bug Fixes - -* **flamegraph:** fixed tooltip display with color blind palette ([#1442](https://github.com/pyroscope-io/pyroscope/issues/1442)) ([702ad8b](https://github.com/pyroscope-io/pyroscope/commit/702ad8b937aa05e12e4dc21114c63febd93bf4c2)) - - - - - -## [0.19.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.19.1...@pyroscope/flamegraph@0.19.2) (2022-08-22) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.19.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.19.0...@pyroscope/flamegraph@0.19.1) (2022-08-22) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.19.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.18.6...@pyroscope/flamegraph@0.19.0) (2022-08-17) - - -### Features - -* reuse Table component everywhere ([#1403](https://github.com/pyroscope-io/pyroscope/issues/1403)) ([a79f61b](https://github.com/pyroscope-io/pyroscope/commit/a79f61b39d8ae5b199710e79dc05e9352044b3b4)) - - - - - -## [0.18.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.18.5...@pyroscope/flamegraph@0.18.6) (2022-08-15) - - -### Bug Fixes - -* **flamegraph:** fix its styling ([#1388](https://github.com/pyroscope-io/pyroscope/issues/1388)) ([5788cf9](https://github.com/pyroscope-io/pyroscope/commit/5788cf9943a579acd35de224537016488a98808f)) - - - - - -## [0.18.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.18.4...@pyroscope/flamegraph@0.18.5) (2022-08-11) - - -### Bug Fixes - -* Make trace units be time based ([#1387](https://github.com/pyroscope-io/pyroscope/issues/1387)) ([a567c2c](https://github.com/pyroscope-io/pyroscope/commit/a567c2c1877c462a6a4dceda87455017c1cf7276)) - - - - - -## [0.18.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.18.3...@pyroscope/flamegraph@0.18.4) (2022-08-11) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.18.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.18.2...@pyroscope/flamegraph@0.18.3) (2022-08-09) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.18.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.18.1...@pyroscope/flamegraph@0.18.2) (2022-08-08) - - -### Bug Fixes - -* make table value say 0 when it is 0 ([#1371](https://github.com/pyroscope-io/pyroscope/issues/1371)) ([30067ad](https://github.com/pyroscope-io/pyroscope/commit/30067ad5da6eec7655d99b19aef0c012be923853)) - - - - - -## [0.18.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.18.0...@pyroscope/flamegraph@0.18.1) (2022-08-08) - - -### Bug Fixes - -* export flamegraph "head" select styles ([#1367](https://github.com/pyroscope-io/pyroscope/issues/1367)) ([7bc8b3e](https://github.com/pyroscope-io/pyroscope/commit/7bc8b3e9d41faf8ac0422764d36406b8b890870b)) - - - - - -# [0.18.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.17.3...@pyroscope/flamegraph@0.18.0) (2022-08-05) - - -### Features - -* enhance tag explorer view ([#1329](https://github.com/pyroscope-io/pyroscope/issues/1329)) ([7d66d75](https://github.com/pyroscope-io/pyroscope/commit/7d66d750ba68d27a5046751221dd51d465a08488)) - - - - - -## [0.17.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.17.2...@pyroscope/flamegraph@0.17.3) (2022-08-05) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.17.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.17.1...@pyroscope/flamegraph@0.17.2) (2022-08-05) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.17.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.17.0...@pyroscope/flamegraph@0.17.1) (2022-08-04) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.17.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.16.3...@pyroscope/flamegraph@0.17.0) (2022-08-03) - - -### Features - -* add tooltip table text for when units is undefined ([#1341](https://github.com/pyroscope-io/pyroscope/issues/1341)) ([a9fd5ac](https://github.com/pyroscope-io/pyroscope/commit/a9fd5ac43f6429c70ccbc70cb8bf89c581e915fb)) - - - - - -## [0.16.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.16.2...@pyroscope/flamegraph@0.16.3) (2022-08-03) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.16.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.16.1...@pyroscope/flamegraph@0.16.2) (2022-07-29) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.16.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.16.0...@pyroscope/flamegraph@0.16.1) (2022-07-27) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.16.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.15.0...@pyroscope/flamegraph@0.16.0) (2022-07-25) - - -### Features - -* show functions % of total [units] in Table ([#1288](https://github.com/pyroscope-io/pyroscope/issues/1288)) ([6c71195](https://github.com/pyroscope-io/pyroscope/commit/6c71195295c3ed5591917ff754e670d4220b77d0)) - - - - - -# [0.15.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.9...@pyroscope/flamegraph@0.15.0) (2022-07-25) - - -### chore - -* **flamegraph/models:** make it mandatory to handle all spyNames ([#1300](https://github.com/pyroscope-io/pyroscope/issues/1300)) ([f7a95a0](https://github.com/pyroscope-io/pyroscope/commit/f7a95a0225c1a39262962a47fd2a1cd493a8333b)) - - -### BREAKING CHANGES - -* **flamegraph/models:** it will throw an error if spyName is unsupported - - - - - -## [0.14.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.8...@pyroscope/flamegraph@0.14.9) (2022-07-20) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.7...@pyroscope/flamegraph@0.14.8) (2022-07-19) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.6...@pyroscope/flamegraph@0.14.7) (2022-07-19) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.5...@pyroscope/flamegraph@0.14.6) (2022-07-18) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.4...@pyroscope/flamegraph@0.14.5) (2022-07-18) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.3...@pyroscope/flamegraph@0.14.4) (2022-07-18) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.2...@pyroscope/flamegraph@0.14.3) (2022-07-15) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.1...@pyroscope/flamegraph@0.14.2) (2022-07-15) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.14.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.14.0...@pyroscope/flamegraph@0.14.1) (2022-07-15) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.14.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.13.0...@pyroscope/flamegraph@0.14.0) (2022-07-15) - - -### Features - -* update right-click context menu ([#1259](https://github.com/pyroscope-io/pyroscope/issues/1259)) ([8aea02f](https://github.com/pyroscope-io/pyroscope/commit/8aea02f56320daacfd753d73db6936dcc7cdaef8)) - - - - - -# [0.13.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.12.5...@pyroscope/flamegraph@0.13.0) (2022-07-13) - - -### Features - -* add new tooltip design ([#1246](https://github.com/pyroscope-io/pyroscope/issues/1246)) ([8345168](https://github.com/pyroscope-io/pyroscope/commit/83451683d131671771b0e97e052068b08bfe35bd)) - - - - - -## [0.12.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.12.4...@pyroscope/flamegraph@0.12.5) (2022-07-13) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.12.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.12.3...@pyroscope/flamegraph@0.12.4) (2022-07-13) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.12.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.12.2...@pyroscope/flamegraph@0.12.3) (2022-07-12) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.12.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.12.1...@pyroscope/flamegraph@0.12.2) (2022-07-11) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.12.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.12.0...@pyroscope/flamegraph@0.12.1) (2022-07-11) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.12.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.11.0...@pyroscope/flamegraph@0.12.0) (2022-07-11) - - -### Features - -* **flamegraph:** Add support for visualizing traces ([#1233](https://github.com/pyroscope-io/pyroscope/issues/1233)) ([b15d094](https://github.com/pyroscope-io/pyroscope/commit/b15d094ebb06592a406b4b73485c0f316c411b08)) - - - - - -# [0.11.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.10.1...@pyroscope/flamegraph@0.11.0) (2022-07-07) - - -### Features - -* **flamegraph:** allow to filter items in table ([#1226](https://github.com/pyroscope-io/pyroscope/issues/1226)) ([e87284d](https://github.com/pyroscope-io/pyroscope/commit/e87284d4d25ae04f2ca50892d4ed89345aa64b3e)) - - - - - -## [0.10.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.10.0...@pyroscope/flamegraph@0.10.1) (2022-07-06) - - -### Bug Fixes - -* improved nodes coloring by fixing murmur math ([#1214](https://github.com/pyroscope-io/pyroscope/issues/1214)) ([8ea4f73](https://github.com/pyroscope-io/pyroscope/commit/8ea4f730fceb185dba3943dbba524444f2082596)) - - - - - -# [0.10.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.7...@pyroscope/flamegraph@0.10.0) (2022-07-06) - - -### Features - -* add titles to charts / flamegraphs ([#1208](https://github.com/pyroscope-io/pyroscope/issues/1208)) ([836fa97](https://github.com/pyroscope-io/pyroscope/commit/836fa97f126f8b7ebfb966bb52a97b5bdf179d83)) - - - - - -## [0.9.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.6...@pyroscope/flamegraph@0.9.7) (2022-07-05) - - -### Bug Fixes - -* **flamegraph:** do a deep comparison for whether the flamegraph is the same ([#1212](https://github.com/pyroscope-io/pyroscope/issues/1212)) ([910d8ea](https://github.com/pyroscope-io/pyroscope/commit/910d8eaeab9c23017da26ecc01c527c3b204b88a)) - - - - - -## [0.9.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.5...@pyroscope/flamegraph@0.9.6) (2022-07-01) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.9.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.4...@pyroscope/flamegraph@0.9.5) (2022-07-01) - - -### Bug Fixes - -* **frontend:** don't crash when flamegraph changes ([#1200](https://github.com/pyroscope-io/pyroscope/issues/1200)) ([f558e0d](https://github.com/pyroscope-io/pyroscope/commit/f558e0d70e9341d0374dd17c33202e09979b1e38)) - - - - - -## [0.9.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.3...@pyroscope/flamegraph@0.9.4) (2022-06-30) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.9.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.2...@pyroscope/flamegraph@0.9.3) (2022-06-30) - - -### Bug Fixes - -* Update flamegraph color pallette ([9476039](https://github.com/pyroscope-io/pyroscope/commit/9476039cff2fe5d06b11ad8748517d16b93f1cc1)) - - - - - -## [0.9.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.1...@pyroscope/flamegraph@0.9.2) (2022-06-29) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.9.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.9.0...@pyroscope/flamegraph@0.9.1) (2022-06-29) - - -### Bug Fixes - -* zoom/focus reset on changing selected node [refactored] ([#1184](https://github.com/pyroscope-io/pyroscope/issues/1184)) ([949052d](https://github.com/pyroscope-io/pyroscope/commit/949052d6db23daedde589a6eaa7c06a4db527cab)) - - - - - -# [0.9.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.8.4...@pyroscope/flamegraph@0.9.0) (2022-06-27) - - -### Features - -* adds proper support for goroutines, block, mutex profiling ([#1178](https://github.com/pyroscope-io/pyroscope/issues/1178)) ([b2e680c](https://github.com/pyroscope-io/pyroscope/commit/b2e680cfbf3c24856543f3a5478204cc24d7cbf7)) - - - - - -## [0.8.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.8.3...@pyroscope/flamegraph@0.8.4) (2022-06-13) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.8.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.8.2...@pyroscope/flamegraph@0.8.3) (2022-06-12) - - -### Bug Fixes - -* Merge jvm generated classes in jfr at ingestion time ([#1149](https://github.com/pyroscope-io/pyroscope/issues/1149)) ([c80878f](https://github.com/pyroscope-io/pyroscope/commit/c80878f765c6f1f8bcbe0d26eebd83d117f55113)) - - - - - -## [0.8.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.8.1...@pyroscope/flamegraph@0.8.2) (2022-06-10) - - -### Bug Fixes - -* fix regexp typo ([#1151](https://github.com/pyroscope-io/pyroscope/issues/1151)) ([6396017](https://github.com/pyroscope-io/pyroscope/commit/6396017b09c0dfe731b35925ea5ba9459888e922)) - - - - - -## [0.8.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.8.0...@pyroscope/flamegraph@0.8.1) (2022-06-10) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.8.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.7.0...@pyroscope/flamegraph@0.8.0) (2022-06-09) - - -### Features - -* Add Ability to Sync Search Bar in Comparison View ([#1120](https://github.com/pyroscope-io/pyroscope/issues/1120)) ([8300792](https://github.com/pyroscope-io/pyroscope/commit/830079299cef97db33d26ada31cbdccbc00e3268)) - - - - - -# [0.7.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.6.4...@pyroscope/flamegraph@0.7.0) (2022-05-30) - - -### Bug Fixes - -* flamegraph palette selector checkmark styles ([#1114](https://github.com/pyroscope-io/pyroscope/issues/1114)) ([755893f](https://github.com/pyroscope-io/pyroscope/commit/755893f23a04c1031a858c39e8729a5074eaf67b)) - - -### Features - -* Color mode ([#1103](https://github.com/pyroscope-io/pyroscope/issues/1103)) ([8855859](https://github.com/pyroscope-io/pyroscope/commit/885585958012775f0d51ea82208d641d10215574)) - - - - - -## [0.6.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.6.3...@pyroscope/flamegraph@0.6.4) (2022-05-26) - - -### Bug Fixes - -* flamegraph palette selector button styles ([#1113](https://github.com/pyroscope-io/pyroscope/issues/1113)) ([d7a7b11](https://github.com/pyroscope-io/pyroscope/commit/d7a7b117c13beb9528e730bec1353efe72767f83)) - - - - - -## [0.6.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.6.2...@pyroscope/flamegraph@0.6.3) (2022-05-25) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.6.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.6.1...@pyroscope/flamegraph@0.6.2) (2022-05-12) - - -### Bug Fixes - -* **flamegraph:** don't ship react-dom ([#1102](https://github.com/pyroscope-io/pyroscope/issues/1102)) ([c80240c](https://github.com/pyroscope-io/pyroscope/commit/c80240cbfda4d0573baf05b9c48d5b658791bffd)) - - - - - -## [0.6.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.6.0...@pyroscope/flamegraph@0.6.1) (2022-05-09) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -# [0.6.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.5.0...@pyroscope/flamegraph@0.6.0) (2022-05-02) - - -### Features - -* **flamegraph:** User should be able to adjust title visibility over the Flamegraph ([#1073](https://github.com/pyroscope-io/pyroscope/issues/1073)) ([bd74aae](https://github.com/pyroscope-io/pyroscope/commit/bd74aae448f3d30398484d589675ea168d816a70)) - - - - - -# [0.5.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.4.0...@pyroscope/flamegraph@0.5.0) (2022-05-02) - - -### Features - -* nodejs push & pull mode ([#1060](https://github.com/pyroscope-io/pyroscope/issues/1060)) ([4317103](https://github.com/pyroscope-io/pyroscope/commit/4317103354b5712c561e4cead7f6906c21a3005c)) - - - - - -# [0.4.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.3.1...@pyroscope/flamegraph@0.4.0) (2022-04-27) - - -### Features - -* rails example added ([#1041](https://github.com/pyroscope-io/pyroscope/issues/1041)) ([a722a6e](https://github.com/pyroscope-io/pyroscope/commit/a722a6e93fdd1895179a0e1481c5d25a3c0dd5a5)) - - - - - -## [0.3.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.3.0...@pyroscope/flamegraph@0.3.1) (2022-04-25) - - -### Bug Fixes - -* **jfr:** fixes a parser regression introduced in 1.15.0 ([#1050](https://github.com/pyroscope-io/pyroscope/issues/1050)) ([946468d](https://github.com/pyroscope-io/pyroscope/commit/946468dbf42ff4450edc94762812ddb4a5f3482d)) - - - - - -# [0.3.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.7...@pyroscope/flamegraph@0.3.0) (2022-04-15) - - -### Features - -* move login to react ([#1031](https://github.com/pyroscope-io/pyroscope/issues/1031)) ([1cb6f9a](https://github.com/pyroscope-io/pyroscope/commit/1cb6f9a08d825acf643b5ef8b51cecab338b1314)), closes [#985](https://github.com/pyroscope-io/pyroscope/issues/985) [#991](https://github.com/pyroscope-io/pyroscope/issues/991) - - - - - -## [0.2.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.6...@pyroscope/flamegraph@0.2.7) (2022-04-12) - - -### Bug Fixes - -* **flamegraph:** inject its styles via css only ([#1023](https://github.com/pyroscope-io/pyroscope/issues/1023)) ([c20a137](https://github.com/pyroscope-io/pyroscope/commit/c20a137a56141f944967c8e229c16c773ec4a607)) - - - - - -## [0.2.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.5...@pyroscope/flamegraph@0.2.6) (2022-04-11) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.2.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.4...@pyroscope/flamegraph@0.2.5) (2022-04-11) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.2.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.3...@pyroscope/flamegraph@0.2.4) (2022-04-06) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.2.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.2...@pyroscope/flamegraph@0.2.3) (2022-03-25) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.2.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.1...@pyroscope/flamegraph@0.2.2) (2022-03-24) - - -### Bug Fixes - -* **flamegraph:** only show diff options when in diff mode ([#972](https://github.com/pyroscope-io/pyroscope/issues/972)) ([625d4de](https://github.com/pyroscope-io/pyroscope/commit/625d4de340bc576f72b42f9db26605d02bc86c51)) - - - - - -## [0.2.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.2.0...@pyroscope/flamegraph@0.2.1) (2022-03-23) - - -### Bug Fixes - -* **flamegraph:** clicking on anywhere on a row selects that row ([#969](https://github.com/pyroscope-io/pyroscope/issues/969)) ([ee84788](https://github.com/pyroscope-io/pyroscope/commit/ee8478812743e1381818e769706df83506ed6f53)) - - - - - -# [0.2.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.1.3...@pyroscope/flamegraph@0.2.0) (2022-03-15) - - -### Features - -* **flamegraph:** publish FlamegraphRenderer for nodejs ([#944](https://github.com/pyroscope-io/pyroscope/issues/944)) ([c2a5631](https://github.com/pyroscope-io/pyroscope/commit/c2a56310e4b36bc6823d5f9debe6e7ac07c6b877)) - - - - - -## [0.1.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.1.2...@pyroscope/flamegraph@0.1.3) (2022-03-14) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.1.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.1.1...@pyroscope/flamegraph@0.1.2) (2022-03-14) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.1.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.1.0...@pyroscope/flamegraph@0.1.1) (2022-03-09) - - -### Bug Fixes - -* **flamegraph:** rerender when 'profile' changes ([#931](https://github.com/pyroscope-io/pyroscope/issues/931)) ([527ae29](https://github.com/pyroscope-io/pyroscope/commit/527ae29222625ec6c74cda270f2add72027ca1e3)) - - - - - -# [0.1.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.0.6...@pyroscope/flamegraph@0.1.0) (2022-03-08) - - -### Features - -* **flamegraph:** support a new profile field ([#929](https://github.com/pyroscope-io/pyroscope/issues/929)) ([95abe2a](https://github.com/pyroscope-io/pyroscope/commit/95abe2ae3dc253a25a03eb19a9378d13b85c8f08)) - - - - - -## [0.0.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.0.5...@pyroscope/flamegraph@0.0.6) (2022-03-07) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - -## [0.0.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.0.3...@pyroscope/flamegraph@0.0.5) (2022-02-24) - - -### Bug Fixes - -* disable pyroscope logo ([#890](https://github.com/pyroscope-io/pyroscope/issues/890)) ([0477cff](https://github.com/pyroscope-io/pyroscope/commit/0477cff8565406c330b48c819c0ed16a69653cee)) - - - - - -## [0.0.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/flamegraph@0.0.2...@pyroscope/flamegraph@0.0.3) (2022-02-24) - -**Note:** Version bump only for package @pyroscope/flamegraph - - - - - - -## 0.0.2 (2022-02-23) - -**Note:** Version bump only for package @pyroscope/flamegraph diff --git a/og/packages/pyroscope-flamegraph/DEVELOPING.md b/og/packages/pyroscope-flamegraph/DEVELOPING.md deleted file mode 100644 index ee39c6e2e5..0000000000 --- a/og/packages/pyroscope-flamegraph/DEVELOPING.md +++ /dev/null @@ -1,5 +0,0 @@ -# development - -If you are just updating this the `FlamegraphRenderer`, we recommend running `yarn run storybook`. - -Then access `http://localhost:6006` diff --git a/og/packages/pyroscope-flamegraph/LICENSE b/og/packages/pyroscope-flamegraph/LICENSE deleted file mode 100644 index d5361db622..0000000000 --- a/og/packages/pyroscope-flamegraph/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 Pyroscope - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/og/packages/pyroscope-flamegraph/README.md b/og/packages/pyroscope-flamegraph/README.md deleted file mode 100644 index 8e2f2a4125..0000000000 --- a/og/packages/pyroscope-flamegraph/README.md +++ /dev/null @@ -1,145 +0,0 @@ -# Pyroscope Flamegraph -This is a component which allows for you to render flamegraphs in your website or application. -While this is typically used for profiling data this can also be used to render tracing data as well - -## Rendering Profiling Data - -Import the CSS -``` -import '@pyroscope/flamegraph/dist/index.css'; -``` - -Import the `FlamegraphRenderer` component - -``` -import { FlamegraphRenderer, Box } from '@pyroscope/flamegraph'; - -const SimpleTree = { - version: 1, - flamebearer: { - names: [ - 'total', - 'runtime.mcall', - 'runtime.park_m', - 'runtime.schedule', - 'runtime.resetspinning', - 'runtime.wakep', - 'runtime.startm', - 'runtime.notewakeup', - 'runtime.semawakeup', - 'runtime.pthread_cond_signal', - 'runtime.findrunnable', - 'runtime.netpoll', - 'runtime.kevent', - 'runtime.main', - 'main.main', - 'github.com/pyroscope-io/client/pyroscope.TagWrapper', - 'runtime/pprof.Do', - 'github.com/pyroscope-io/client/pyroscope.TagWrapper.func1', - 'main.main.func1', - 'main.slowFunction', - 'main.slowFunction.func1', - 'main.work', - 'runtime.asyncPreempt', - 'main.fastFunction', - 'main.fastFunction.func1', - ], - levels: [ - [0, 609, 0, 0], - [0, 606, 0, 13, 0, 3, 0, 1], - [0, 606, 0, 14, 0, 3, 0, 2], - [0, 606, 0, 15, 0, 3, 0, 3], - [0, 606, 0, 16, 0, 1, 0, 10, 0, 2, 0, 4], - [0, 606, 0, 17, 0, 1, 0, 11, 0, 2, 0, 5], - [0, 606, 0, 18, 0, 1, 1, 12, 0, 2, 0, 6], - [0, 100, 0, 23, 0, 506, 0, 19, 1, 2, 0, 7], - [0, 100, 0, 15, 0, 506, 0, 16, 1, 2, 0, 8], - [0, 100, 0, 16, 0, 506, 0, 20, 1, 2, 2, 9], - [0, 100, 0, 17, 0, 506, 493, 21], - [0, 100, 0, 24, 493, 13, 13, 22], - [0, 100, 97, 21], - [97, 3, 3, 22], - ], - numTicks: 609, - maxSelf: 493, - }, - metadata: { - appName: 'simple.golang.app.cpu', - name: 'simple.golang.app.cpu 2022-09-06T12:16:31Z', - startTime: 1662466591, - endTime: 1662470191, - query: 'simple.golang.app.cpu{}', - maxNodes: 1024, - format: 'single' as const, - sampleRate: 100, - spyName: 'gospy' as const, - units: 'samples' as const, - }, - timeline: { - startTime: 1662466590, - samples: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 610, 0, - ], - durationDelta: 10, - }, -}; - -export const Flamegraph = () => { - return ( - - ); -}; -``` - -We recommend wrapping a `Box` around your component to give it some padding. -``` - - - -``` - -## Rendering Tracing Data -Note: Currently Pyroscope only supports rendering tracing data from Jaeger. - -``` -import { FlamegraphRenderer, convertJaegerTraceToProfile } from "@pyroscope/flamegraph"; -import "@pyroscope/flamegraph/dist/index.css"; - -let trace = jaegerTrace.data[0]; -let convertedProfile = convertJaegerTraceToProfile(trace); - -function App() { - return ( -
-

Trace Flamegraph

- -
- ); -} -``` diff --git a/og/packages/pyroscope-flamegraph/babel.config.js b/og/packages/pyroscope-flamegraph/babel.config.js deleted file mode 100644 index 2442a78a14..0000000000 --- a/og/packages/pyroscope-flamegraph/babel.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - presets: ['@babel/preset-env', '@babel/preset-react'], - plugins: ['transform-class-properties'], -}; diff --git a/og/packages/pyroscope-flamegraph/jest.config.js b/og/packages/pyroscope-flamegraph/jest.config.js deleted file mode 100644 index a214cb6131..0000000000 --- a/og/packages/pyroscope-flamegraph/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - ...require('../../jest.config'), - rootDir: '.', - setupFilesAfterEnv: ['/setupAfterEnv.ts'], -}; diff --git a/og/packages/pyroscope-flamegraph/package.json b/og/packages/pyroscope-flamegraph/package.json deleted file mode 100644 index 5bf222b66c..0000000000 --- a/og/packages/pyroscope-flamegraph/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@pyroscope/flamegraph", - "version": "0.35.6", - "main": "dist/index.node.js", - "browser": "dist/index.js", - "_types": "since we are importing stuff from webapp (ui components), tsc ends up generating a weird file tree", - "types": "dist/packages/pyroscope-flamegraph/src/index.d.ts", - "license": "Apache-2.0", - "files": [ - "src/**/*", - "dist/**/*", - "package.json", - "README.md", - "CHANGELOG.md", - "LICENSE" - ], - "scripts": { - "test": "jest", - "watch": "yarn build:lib --watch", - "dev": "chokidar --initial \"src/**/*\" -c \"yarn run build:lib\"", - "build": "yarn build:types && yarn build:lib", - "build:lib": "NODE_ENV=production webpack --config ../../scripts/webpack/webpack.flamegraph.ts", - "build:types": "tsc -p tsconfig.json --emitDeclarationOnly && downlevel-dts dist dist", - "build:types:watch": "tsc -p tsconfig.json --emitDeclarationOnly --watch --preserveWatchOutput", - "type-check": "tsc -p tsconfig.json --noEmit", - "lint": "eslint ./ --cache --fix" - }, - "peerDependencies": { - "graphviz-react": "^1.2.5", - "react": ">=16.14.0", - "react-dom": ">=16.14.0", - "true-myth": "^5.1.2" - }, - "devDependencies": { - "@pyroscope/models": "^0.4.7" - } -} diff --git a/og/packages/pyroscope-flamegraph/setupAfterEnv.ts b/og/packages/pyroscope-flamegraph/setupAfterEnv.ts deleted file mode 100644 index 31ea0cb948..0000000000 --- a/og/packages/pyroscope-flamegraph/setupAfterEnv.ts +++ /dev/null @@ -1,30 +0,0 @@ -import '@testing-library/jest-dom'; -import 'jest-canvas-mock'; -import { configureToMatchImageSnapshot } from 'jest-image-snapshot'; -import type { MatchImageSnapshotOptions } from 'jest-image-snapshot'; -import 'regenerator-runtime/runtime'; - -// TODO: maybe we don't need this file? -expect.extend({ - toMatchImageSnapshot(received: string, options: MatchImageSnapshotOptions) { - // If these checks pass, assume we're in a JSDOM environment with the 'canvas' package. - if (process.env.RUN_SNAPSHOTS) { - const customConfig = { threshold: 0.02 }; - const toMatchImageSnapshot = configureToMatchImageSnapshot({ - customDiffConfig: customConfig, - }) as any; - - // TODO - // for some reason it fails with - // Expected 1 arguments, but got 3. - // hence the any - return toMatchImageSnapshot.call(this, received, options); - } - - return { - pass: true, - message: () => - `Skipping 'toMatchImageSnapshot' assertion since env var 'RUN_SNAPSHOTS' is not set.`, - }; - }, -}); diff --git a/og/packages/pyroscope-flamegraph/tsconfig.json b/og/packages/pyroscope-flamegraph/tsconfig.json deleted file mode 100644 index fe3626ba50..0000000000 --- a/og/packages/pyroscope-flamegraph/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["./src", "../../lib"], - "exclude": ["src/**/*.spec.tsx", "src/**/*.spec.ts"], - "baseUrl": ".", - "compilerOptions": { - "resolveJsonModule": false, - "module": "commonjs", - "declaration": true, - "noImplicitAny": false, - "removeComments": true, - "noLib": false, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es6", - "sourceMap": true, - "lib": ["es6", "dom"], - "outDir": "./dist" - } -} diff --git a/og/packages/pyroscope-flamegraph/yarn.lock b/og/packages/pyroscope-flamegraph/yarn.lock deleted file mode 100644 index ba7654fd66..0000000000 --- a/og/packages/pyroscope-flamegraph/yarn.lock +++ /dev/null @@ -1,8 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"true-myth@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/true-myth/-/true-myth-5.1.2.tgz#58a425b0aefe57eed279ac2d1b65e567153ea9b0" - integrity sha512-4A8CVJiDt35EhS2U4DYoU1Kg8nMdqpC4sIc4ktan/nE3T2u5kLd7fJ1ZSQTn5xO/A41IB7DLF8R8xL6l0MPgsQ== diff --git a/og/packages/pyroscope-models/CHANGELOG.md b/og/packages/pyroscope-models/CHANGELOG.md deleted file mode 100644 index f3a2a50e77..0000000000 --- a/og/packages/pyroscope-models/CHANGELOG.md +++ /dev/null @@ -1,180 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [0.4.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.4.6...@pyroscope/models@0.4.7) (2023-02-07) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.4.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.4.5...@pyroscope/models@0.4.6) (2022-11-28) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.4.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.4.4...@pyroscope/models@0.4.5) (2022-11-15) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.4.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.4.3...@pyroscope/models@0.4.4) (2022-08-22) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.4.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.4.2...@pyroscope/models@0.4.3) (2022-08-22) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.4.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.4.1...@pyroscope/models@0.4.2) (2022-08-05) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.4.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.4.0...@pyroscope/models@0.4.1) (2022-08-03) - -**Note:** Version bump only for package @pyroscope/models - - - - - -# [0.4.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.3.0...@pyroscope/models@0.4.0) (2022-07-29) - - -### Features - -* create tag-explorer page for analyzing tag breakdowns ([#1293](https://github.com/pyroscope-io/pyroscope/issues/1293)) ([5456a86](https://github.com/pyroscope-io/pyroscope/commit/5456a866cfa6b3800fb7d359ff55032a84129138)) - - - - - -# [0.3.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.2.3...@pyroscope/models@0.3.0) (2022-07-25) - - -### chore - -* **flamegraph/models:** make it mandatory to handle all spyNames ([#1300](https://github.com/pyroscope-io/pyroscope/issues/1300)) ([f7a95a0](https://github.com/pyroscope-io/pyroscope/commit/f7a95a0225c1a39262962a47fd2a1cd493a8333b)) - - -### BREAKING CHANGES - -* **flamegraph/models:** it will throw an error if spyName is unsupported - - - - - -## [0.2.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.2.2...@pyroscope/models@0.2.3) (2022-07-18) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.2.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.2.1...@pyroscope/models@0.2.2) (2022-07-13) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.2.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.2.0...@pyroscope/models@0.2.1) (2022-07-11) - -**Note:** Version bump only for package @pyroscope/models - - - - - -# [0.2.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.1.0...@pyroscope/models@0.2.0) (2022-07-11) - - -### Features - -* **flamegraph:** Add support for visualizing traces ([#1233](https://github.com/pyroscope-io/pyroscope/issues/1233)) ([b15d094](https://github.com/pyroscope-io/pyroscope/commit/b15d094ebb06592a406b4b73485c0f316c411b08)) - - - - - -# [0.1.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.0.7...@pyroscope/models@0.1.0) (2022-06-27) - - -### Features - -* adds proper support for goroutines, block, mutex profiling ([#1178](https://github.com/pyroscope-io/pyroscope/issues/1178)) ([b2e680c](https://github.com/pyroscope-io/pyroscope/commit/b2e680cfbf3c24856543f3a5478204cc24d7cbf7)) - - - - - -## [0.0.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.0.6...@pyroscope/models@0.0.7) (2022-04-25) - - -### Bug Fixes - -* **jfr:** fixes a parser regression introduced in 1.15.0 ([#1050](https://github.com/pyroscope-io/pyroscope/issues/1050)) ([946468d](https://github.com/pyroscope-io/pyroscope/commit/946468dbf42ff4450edc94762812ddb4a5f3482d)) - - - - - -## [0.0.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.0.5...@pyroscope/models@0.0.6) (2022-04-11) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.0.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.0.4...@pyroscope/models@0.0.5) (2022-04-11) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.0.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.0.3...@pyroscope/models@0.0.4) (2022-03-23) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## [0.0.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/models@0.0.2...@pyroscope/models@0.0.3) (2022-03-14) - -**Note:** Version bump only for package @pyroscope/models - - - - - -## 0.0.2 (2022-03-07) - -**Note:** Version bump only for package @pyroscope/models diff --git a/og/packages/pyroscope-models/LICENSE b/og/packages/pyroscope-models/LICENSE deleted file mode 100644 index d5361db622..0000000000 --- a/og/packages/pyroscope-models/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 Pyroscope - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/og/packages/pyroscope-models/package.json b/og/packages/pyroscope-models/package.json deleted file mode 100644 index 9406a82c2b..0000000000 --- a/og/packages/pyroscope-models/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@pyroscope/models", - "version": "0.4.7", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "license": "Apache-2.0", - "files": [ - "dist/**/*", - "src/**/*", - "CHANGELOG.md", - "LICENSE" - ], - "scripts": { - "build": "tsc -p tsconfig.json", - "type-check": "tsc -p tsconfig.json --noEmit", - "lint": "echo 'noop'", - "watch": "yarn run build --watch --preserveWatchOutput" - }, - "peerDependencies": { - "zod": "^3.11.6" - } -} diff --git a/og/packages/pyroscope-models/tsconfig.json b/og/packages/pyroscope-models/tsconfig.json deleted file mode 100644 index 18b2778a76..0000000000 --- a/og/packages/pyroscope-models/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "baseUrl": ".", - "compilerOptions": { - "module": "commonjs", - "declaration": true, - "noImplicitAny": false, - "removeComments": true, - "noLib": false, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es6", - "sourceMap": true, - "lib": ["es6"], - "outDir": "./dist" - }, - "include": ["**/*.ts"], - "exclude": ["dist", "**/*.spec.ts"] -} diff --git a/og/pyroscope_suite_test.go b/og/pyroscope_suite_test.go deleted file mode 100644 index 9c638283da..0000000000 --- a/og/pyroscope_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package pyroscope_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestPyroscope(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Pyroscope Suite") -} diff --git a/og/revive.toml b/og/revive.toml deleted file mode 100644 index 9a7c5d9aed..0000000000 --- a/og/revive.toml +++ /dev/null @@ -1,80 +0,0 @@ -# See this page for descriptions: -# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md - -ignoreGeneratedHeader = false -severity = "error" -confidence = 0.8 -errorCode = 1 -warningCode = 0 - -[directive.specify-disable-reason] -[rule.context-keys-type] -[rule.time-naming] -[rule.var-declaration] -[rule.unexported-return] -[rule.errorf] -[rule.blank-imports] -[rule.context-as-argument] -[rule.dot-imports] -[rule.error-return] -[rule.error-strings] -[rule.error-naming] -# [rule.exported] -[rule.if-return] -[rule.increment-decrement] -[rule.var-naming] -[rule.package-comments] -[rule.range] -[rule.receiver-naming] -[rule.indent-error-flow] -[rule.argument-limit] - arguments = [5] -[rule.max-public-structs] - arguments = [10] -[rule.empty-block] -[rule.superfluous-else] -# [rule.get-return] -[rule.modifies-parameter] -[rule.confusing-results] -[rule.deep-exit] -[rule.unused-parameter] -[rule.unreachable-code] -# [rule.add-constant] -# arguments = [{maxLitCount = "10",allowStrs ="\"\"",allowInts="0,1,2,3,4,5,6,7,8,9,16,24,32,40,48,56,64,128,256,0xff",allowFloats="0.0,0.,1.0,1.,2.0,2."}] -# [rule.flag-parameter] -[rule.unnecessary-stmt] -[rule.struct-tag] -[rule.modifies-value-receiver] -[rule.constant-logical-expr] -[rule.bool-literal-in-expr] -[rule.redefines-builtin-id] -[rule.function-result-limit] - arguments = [4] -[rule.imports-blacklist] -[rule.range-val-in-closure] -[rule.range-val-address] -[rule.waitgroup-by-value] -[rule.atomic] -[rule.empty-lines] -[rule.line-length-limit] - arguments = [180] -[rule.duplicated-imports] -[rule.import-shadowing] -[rule.bare-return] -[rule.unused-receiver] -[rule.string-of-int] - -# Custom rules. We use a revive fork available here: https://github.com/pyroscope-io/revive -# See Makefile `lint` section for how to use the fork -#[rule.byte-array-limit] -# arguments = [7] - -# These are pretty much disabled -[rule.cognitive-complexity] - arguments = [55] - -[rule.cyclomatic] - arguments = [50] - -# [rule.unhandled-error] -# arguments = ["sb.WriteString", "fmt.Fprintf", "fmt.Printf", "fmt.Println"] diff --git a/og/scripts/cmd-test.sh b/og/scripts/cmd-test.sh deleted file mode 100644 index b66f8227a3..0000000000 --- a/og/scripts/cmd-test.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -export RUST_BACKTRACE=1 - -go build -o ./tmp/pyroscope ./cmd/pyroscope && tmp/pyroscope "$@" diff --git a/og/scripts/cypress-screenshots.sh b/og/scripts/cypress-screenshots.sh deleted file mode 100755 index 09247cf7e7..0000000000 --- a/og/scripts/cypress-screenshots.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -CYPRESS_updateSnapshots="${CYPRESS_updateSnapshots:-true}" - -# we use net=host since cypress will hit http://localhost:4040 -# and run with user 1000 since it -docker run \ - --net=host \ - --user 1000:1000 \ - -it --rm \ - -e CYPRESS_VIDEO=true \ - -e CYPRESS_COMPARE_SNAPSHOTS=true \ - -e CYPRESS_updateSnapshots="$CYPRESS_updateSnapshots" \ - -v $PWD:/cypress -w /cypress cypress/included:8.6.0 "$@" - diff --git a/og/scripts/dbtool/cmd/get.go b/og/scripts/dbtool/cmd/get.go deleted file mode 100644 index f43c0d6ee2..0000000000 --- a/og/scripts/dbtool/cmd/get.go +++ /dev/null @@ -1,35 +0,0 @@ -package cmd - -import ( - "bytes" - "io" - "os" - - "github.com/dgraph-io/badger/v2" - "github.com/spf13/cobra" -) - -func (d *dbTool) newGetCommand() *cobra.Command { - return &cobra.Command{ - Use: "get ", - Short: "Retrieves key value and dumps it to stdout", - RunE: d.runGet, - Args: cobra.MinimumNArgs(1), - PreRunE: d.openDB(true), - } -} - -func (d *dbTool) runGet(_ *cobra.Command, args []string) error { - return d.db.View(func(txn *badger.Txn) error { - item, err := txn.Get([]byte(args[0])) - if err != nil { - return err - } - v, err := item.ValueCopy(nil) - if err != nil { - return err - } - _, _ = io.Copy(os.Stdout, bytes.NewBuffer(v)) - return nil - }) -} diff --git a/og/scripts/dbtool/cmd/list.go b/og/scripts/dbtool/cmd/list.go deleted file mode 100644 index 658a76b1c2..0000000000 --- a/og/scripts/dbtool/cmd/list.go +++ /dev/null @@ -1,34 +0,0 @@ -package cmd - -import ( - "fmt" - "os" - - "github.com/dgraph-io/badger/v2" - "github.com/spf13/cobra" -) - -func (d *dbTool) newListCommand() *cobra.Command { - cmd := cobra.Command{ - Use: "list", - Short: "Lists db keys", - RunE: d.runList, - PreRunE: d.openDB(true), - } - cmd.Flags().StringVarP(&d.prefix, "prefix", "p", "", "key prefix") - return &cmd -} - -func (d *dbTool) runList(_ *cobra.Command, _ []string) error { - return d.db.View(func(txn *badger.Txn) error { - opts := badger.DefaultIteratorOptions - opts.PrefetchValues = false - opts.Prefix = []byte(d.prefix) - it := txn.NewIterator(opts) - defer it.Close() - for it.Rewind(); it.Valid(); it.Next() { - _, _ = fmt.Fprintf(os.Stdout, "%s\n", it.Item().Key()) - } - return nil - }) -} diff --git a/og/scripts/dbtool/cmd/remove.go b/og/scripts/dbtool/cmd/remove.go deleted file mode 100644 index 66f3a7927b..0000000000 --- a/og/scripts/dbtool/cmd/remove.go +++ /dev/null @@ -1,22 +0,0 @@ -package cmd - -import ( - "github.com/dgraph-io/badger/v2" - "github.com/spf13/cobra" -) - -func (d *dbTool) newRemoveCommand() *cobra.Command { - return &cobra.Command{ - Use: "remove ", - Short: "Removes key value from the database", - RunE: d.runRemove, - Args: cobra.MinimumNArgs(1), - PreRunE: d.openDB(false), - } -} - -func (d *dbTool) runRemove(_ *cobra.Command, args []string) error { - return d.db.Update(func(txn *badger.Txn) error { - return txn.Delete([]byte(args[0])) - }) -} diff --git a/og/scripts/dbtool/cmd/root.go b/og/scripts/dbtool/cmd/root.go deleted file mode 100644 index 437563c280..0000000000 --- a/og/scripts/dbtool/cmd/root.go +++ /dev/null @@ -1,80 +0,0 @@ -package cmd - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/dgraph-io/badger/v2" - "github.com/dgraph-io/badger/v2/options" - "github.com/spf13/cobra" -) - -type dbTool struct { - dir string - prefix string - - db *badger.DB -} - -func Execute() error { - return newRootCommand().Execute() -} - -func newRootCommand() *cobra.Command { - d := new(dbTool) - root := cobra.Command{ - Use: "dbtool [command]", - Short: "DB helper tool", - SilenceUsage: true, - SilenceErrors: true, - PersistentPostRunE: d.closeDB(), - } - - root.PersistentFlags().StringVarP(&d.dir, "dir", "d", ".", "database directory path") - root.AddCommand( - d.newListCommand(), - d.newRemoveCommand(), - d.newGetCommand()) - - return &root -} - -func (d *dbTool) openDB(ro bool) func(cmd *cobra.Command, args []string) error { - return func(c *cobra.Command, _ []string) error { - db, err := openDB(d.dir, ro) - if err != nil { - return fmt.Errorf("failed to open %s: %v", d.dir, err) - } - d.db = db - return nil - } -} - -func (d *dbTool) closeDB() func(cmd *cobra.Command, args []string) error { - return func(c *cobra.Command, _ []string) error { - if d.db == nil { - return nil - } - if err := d.db.Close(); err != nil { - return fmt.Errorf("closing database: %w", err) - } - return nil - } -} - -func openDB(dir string, ro bool) (*badger.DB, error) { - if !ro { - // When DB is opened for RW, badger.Open does not fail - // if the directory is not a badger database, instead it - // creates one. - f, err := os.Open(filepath.Join(dir, badger.ManifestFilename)) - if err != nil { - return nil, err - } - _ = f.Close() - } - return badger.Open(badger.DefaultOptions(dir). - WithCompression(options.ZSTD). - WithReadOnly(ro)) -} diff --git a/og/scripts/dbtool/main.go b/og/scripts/dbtool/main.go deleted file mode 100644 index 4dd6ff4416..0000000000 --- a/og/scripts/dbtool/main.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/fatih/color" - - "github.com/pyroscope-io/pyroscope/scripts/dbtool/cmd" -) - -func main() { - if err := cmd.Execute(); err != nil { - _, _ = fmt.Fprintln(os.Stderr, color.RedString("Error:"), err) - os.Exit(1) - } -} diff --git a/og/scripts/decode-resp/decode.go b/og/scripts/decode-resp/decode.go deleted file mode 100644 index 6b7cfabf79..0000000000 --- a/og/scripts/decode-resp/decode.go +++ /dev/null @@ -1,104 +0,0 @@ -package main - -//revive:disable:max-public-structs Config structs - -import ( - "github.com/pyroscope-io/pyroscope/pkg/storage/segment" - "github.com/pyroscope-io/pyroscope/pkg/storage/tree" -) - -type Input struct { - Timeline *segment.Timeline `json:"timeline"` - Flamebearer *tree.Flamebearer `json:"flamebearer"` - Metadata *InputMetadata `json:"metadata"` -} - -type InputMetadata struct { - SpyName string `json:"spyName"` - SampleRate uint32 `json:"sampleRate"` - Units string `json:"units"` - Format tree.Format `json:"format"` -} - -type Output struct { - Flamebearer *OutputFlamebearer `json:"flamebearer"` -} - -type OutputFlamebearer struct { - Levels [][]OutputItem `json:"levels"` -} - -type OutputItem interface{} - -type OutputItemSingle struct { - Row int `json:"_row"` - Col int `json:"_col"` - Name string `json:"name"` - Total int `json:"total"` - Self int `json:"self"` - Offset int `json:"offset"` -} - -type OutputItemDouble struct { - Row int `json:"_row"` - Col int `json:"_col"` - Name string `json:"name"` - LeftSelf int `json:"left_self"` - LeftTotal int `json:"left_total"` - LeftOffset int `json:"left_offset"` - RghtSelf int `json:"right_self"` - RghtTotal int `json:"right_total"` - RghtOffset int `json:"right_offset"` -} - -func decodeLevels(in *Input) *Output { - names, levels := in.Flamebearer.Names, in.Flamebearer.Levels - outLevels := make([][]OutputItem, 0, len(levels)) - isSingle := in.Flamebearer.Format != tree.FormatDouble - - step := 4 - if !isSingle { - step = 7 - } - - for rowIdx, row := range levels { - offsetLeft, offsetRght := 0, 0 - outRow := make([]OutputItem, 0, len(row)) - - for i, N := 0, len(row); i < N; i += step { - var outItem OutputItem - if isSingle { - offsetLeft += row[i+0] - outItem = OutputItemSingle{ - Row: rowIdx, Col: i / step, - Offset: offsetLeft, - Total: row[i+1], - Self: row[i+2], - Name: names[row[i+3]], - } - } else { - offsetLeft += row[i+0] - offsetRght += row[i+3] - outItem = OutputItemDouble{ - Row: rowIdx, Col: i / step, - LeftOffset: offsetLeft, - LeftTotal: row[i+1], - LeftSelf: row[i+2], - RghtOffset: offsetRght, - RghtTotal: row[i+4], - RghtSelf: row[i+6], - Name: names[row[i+6]], - } - } - outRow = append(outRow, outItem) - } - outLevels = append(outLevels, outRow) - } - - out := &Output{ - Flamebearer: &OutputFlamebearer{ - Levels: outLevels, - }, - } - return out -} diff --git a/og/scripts/decode-resp/decode_suite_test.go b/og/scripts/decode-resp/decode_suite_test.go deleted file mode 100644 index c31e57b3e4..0000000000 --- a/og/scripts/decode-resp/decode_suite_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - testing2 "github.com/pyroscope-io/pyroscope/pkg/testing" -) - -func TestDecode(t *testing.T) { - testing2.SetupLogging() - RegisterFailHandler(Fail) - RunSpecs(t, "Decode Suite") -} diff --git a/og/scripts/decode-resp/decode_test.go b/og/scripts/decode-resp/decode_test.go deleted file mode 100644 index 495033bfbb..0000000000 --- a/og/scripts/decode-resp/decode_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/pyroscope-io/pyroscope/pkg/storage/tree" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("Decode", func() { - Context("simple case", func() { - It("should decode correctly", func() { - names := strings.Split("total,a,b,c", ",") - levels := [][]int{ - {0, 3, 0, 0}, // total - {0, 3, 0, 1}, // a - {0, 1, 1, 3, 2, 2, 2, 2}, // b, c - } - in := &Input{ - Flamebearer: &tree.Flamebearer{ - Names: names, - Levels: levels, - }, - } - out := decodeLevels(in) - outJSON := marshal(out) - expected := `{ - "flamebearer": { - "levels": [ - [ - { - "_row": 0, - "_col": 0, - "name": "total", - "total": 3, - "self": 0, - "offset": 0 - } - ], - [ - { - "_row": 1, - "_col": 0, - "name": "a", - "total": 3, - "self": 0, - "offset": 0 - } - ], - [ - { - "_row": 2, - "_col": 0, - "name": "c", - "total": 1, - "self": 1, - "offset": 0 - }, - { - "_row": 2, - "_col": 1, - "name": "b", - "total": 2, - "self": 2, - "offset": 2 - } - ] - ] - } -}` - fmt.Println(outJSON) - Expect(outJSON).To(Equal(expected)) - }) - }) -}) - -func marshal(out interface{}) string { - data, _ := json.MarshalIndent(out, "", " ") - return strings.TrimSpace(string(data)) -} diff --git a/og/scripts/decode-resp/main.go b/og/scripts/decode-resp/main.go deleted file mode 100644 index 9e96e7f3a8..0000000000 --- a/og/scripts/decode-resp/main.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "encoding/json" - "flag" - "fmt" - "os" - "path/filepath" -) - -func usage() { - f, w := flag.CommandLine, flag.CommandLine.Output() - fmt.Fprintf(w, `Decode response from pyroscope, for debugging - -Usage: decode-resp -file - where is the body response from /render API - example: http://localhost:4040/render?from=now-1h&until=now&name=pyroscope.server.alloc_objects{}&max-nodes=1024&format=json - -Flags: -`) - f.PrintDefaults() -} - -func main() { - var inFile string - var outFile string - - flag.StringVar(&inFile, "file", "", "path to response file (required)") - flag.StringVar(&outFile, "out", "", "name of output file (default to NAME.out.EXT)") - flag.Usage = usage - flag.Parse() - - if inFile == "" { - usage() - os.Exit(2) - } - if outFile == "" { - dir, base := filepath.Dir(inFile), filepath.Base(inFile) - ext := filepath.Ext(base) - name := base[:len(base)-len(ext)] - outFile = filepath.Join(dir, name+".out"+ext) - } - - // read file - inData, err := os.ReadFile(inFile) - must(err) - var input Input - must(json.Unmarshal(inData, &input)) - - // decode - output := decodeLevels(&input) - - // write file - outData, err := json.MarshalIndent(output, "", " ") - must(err) - must(os.WriteFile(outFile, outData, 0644)) - - fmt.Fprintf(os.Stderr, "decoded to %v\n", outFile) -} - -func must(err error) { - if err != nil { - panic(err) - } -} diff --git a/og/scripts/dependency-graph.sh b/og/scripts/dependency-graph.sh deleted file mode 100644 index bcf4f50fdf..0000000000 --- a/og/scripts/dependency-graph.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -godepgraph -nostdlib -s ./cmd/pyroscope/ > tmp/deps.dot - -( - cat tmp/deps.dot | head -n 7 | grep -v 'splines=ortho' - cat tmp/deps.dot | \ - grep pyroscope | \ - sed 's/github.com\/pyroscope-io\/pyroscope\///g' | \ - grep -v 'pkg/config' | \ - grep -v 'pkg/build' | \ - grep -v .com - echo "}" -) | dot -Tsvg -o tmp/go-deps-graph.svg diff --git a/og/scripts/dev-procfile b/og/scripts/dev-procfile deleted file mode 100644 index 987e9278d8..0000000000 --- a/og/scripts/dev-procfile +++ /dev/null @@ -1,4 +0,0 @@ -air: air -frontend: yarn start -webpack-standalone: yarn dev:standalone -# example: go run ./examples/golang-push/simple/main.go diff --git a/og/scripts/generate-build-flags.sh b/og/scripts/generate-build-flags.sh deleted file mode 100755 index 48ad53b52b..0000000000 --- a/og/scripts/generate-build-flags.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -set -e - -CURRENT_TIME="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" -if [ -z $NO_BUILD_TIME_TAG ] -then - echo "-X github.com/pyroscope-io/pyroscope/pkg/build.Time=$CURRENT_TIME" -else - echo "-X github.com/pyroscope-io/pyroscope/pkg/build.Time=NO_BUILD_TIME_TAG" -fi - -# we don't copy .git to docker context, so in docker context we use git-info -if [ -d ".git" ] -then - scripts/generate-git-info.sh > scripts/packages/git-info -fi -source scripts/packages/git-info - -echo "-X github.com/pyroscope-io/pyroscope/pkg/build.Version=$GIT_TAG" -echo "-X github.com/pyroscope-io/pyroscope/pkg/build.GitSHA=$GIT_SHA" -echo "-X github.com/pyroscope-io/pyroscope/pkg/build.GitDirtyStr=$GIT_DIRTY" -echo "-X github.com/pyroscope-io/pyroscope/pkg/build.RbspyGitSHA=$RBSPY_GIT_SHA" -echo "-X github.com/pyroscope-io/pyroscope/pkg/build.PyspyGitSHA=$PYSPY_GIT_SHA" -echo "-X github.com/pyroscope-io/pyroscope/pkg/build.PhpspyGitSHA=$PHPSPY_GIT_SHA" diff --git a/og/scripts/generate-git-info.sh b/og/scripts/generate-git-info.sh deleted file mode 100755 index e9e46c79cc..0000000000 --- a/og/scripts/generate-git-info.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -set -e - -echo "GIT_TAG=\"$(git describe --tags --abbrev=0 --match 'v*' 2> /dev/null || echo v0.0.0)\"" -echo "GIT_SHA=\"$( (git show-ref --head --hash=8 2> /dev/null || echo 00000000) | head -n1)\"" -echo "GIT_DIRTY=\"$(echo $(git diff --no-ext-diff 2> /dev/null | wc -l))\"" - -echo "PHPSPY_GIT_SHA=\"$(cat Makefile | grep ^PHPSPY_VERSION | cut -d ' ' -f 3)\"" diff --git a/og/scripts/generate-sample-config/example.md b/og/scripts/generate-sample-config/example.md deleted file mode 100644 index a9f28b1835..0000000000 --- a/og/scripts/generate-sample-config/example.md +++ /dev/null @@ -1,74 +0,0 @@ - -| Name | Default Value | Usage | -| :- | :- | :- | -| analytics-opt-out | false | "disables analytics" | -| log-level | info | "log level: debug|info|warn|error" | -| badger-log-level | error | "log level: debug|info|warn|error" | -| storage-path | /var/lib/pyroscope | "directory where pyroscope stores profiling data" | -| api-bind-addr | :4040 | "port for the HTTP server used for data ingestion and web UI" | -| base-url | | "base URL for when the server is behind a reverse proxy with a different path" | -| cache-dimension-size | 1000 | "max number of elements in LRU cache for dimensions" | -| cache-dictionary-size | 1000 | "max number of elements in LRU cache for dictionaries" | -| cache-segment-size | 1000 | "max number of elements in LRU cache for segments" | -| cache-tree-size | 1000 | "max number of elements in LRU cache for trees" | -| badger-no-truncate | false | "indicates whether value log files should be truncated to delete corrupt data, if any" | -| max-nodes-serialization | 2048 | "max number of nodes used when saving profiles to disk" | -| max-nodes-render | 8192 | "max number of nodes used to display data on the frontend" | -| hide-applications | | "please don't use, this will soon be deprecated" | -| out-of-space-threshold | 512.00 MB | "Threshold value to consider out of space in bytes" | -| sample-rate | 100 | "sample rate for the profiler in Hz. 100 means reading 100 times per second" | - - - -```yaml ---- -# disables analytics -analytics-opt-out: "false" - -# log level: debug|info|warn|error -log-level: "info" - -# log level: debug|info|warn|error -badger-log-level: "error" - -# directory where pyroscope stores profiling data -storage-path: "/var/lib/pyroscope" - -# port for the HTTP server used for data ingestion and web UI -api-bind-addr: ":4040" - -# base URL for when the server is behind a reverse proxy with a different path -base-url: "" - -# max number of elements in LRU cache for dimensions -cache-dimension-size: "1000" - -# max number of elements in LRU cache for dictionaries -cache-dictionary-size: "1000" - -# max number of elements in LRU cache for segments -cache-segment-size: "1000" - -# max number of elements in LRU cache for trees -cache-tree-size: "1000" - -# indicates whether value log files should be truncated to delete corrupt data, if any -badger-no-truncate: "false" - -# max number of nodes used when saving profiles to disk -max-nodes-serialization: "2048" - -# max number of nodes used to display data on the frontend -max-nodes-render: "8192" - -# please don't use, this will soon be deprecated -hide-applications: "" - -# Threshold value to consider out of space in bytes -out-of-space-threshold: "512.00 MB" - -# sample rate for the profiler in Hz. 100 means reading 100 times per second -sample-rate: "100" - -``` - diff --git a/og/scripts/generate-sample-config/main.go b/og/scripts/generate-sample-config/main.go deleted file mode 100644 index d50021f899..0000000000 --- a/og/scripts/generate-sample-config/main.go +++ /dev/null @@ -1,192 +0,0 @@ -package main - -import ( - "bytes" - "flag" - "fmt" - "io" - "log" - "os" - "path/filepath" - "reflect" - "regexp" - "strings" - "unicode" - - "github.com/sirupsen/logrus" - "github.com/spf13/pflag" - "github.com/spf13/viper" - - "github.com/pyroscope-io/pyroscope/pkg/cli" - "github.com/pyroscope-io/pyroscope/pkg/config" - "github.com/pyroscope-io/pyroscope/pkg/util/slices" -) - -// to run this program: -// go run scripts/generate-sample-config/main.go -format yaml -// go run scripts/generate-sample-config/main.go -format md -// or: -// go run scripts/generate-sample-config/main.go -directory ../pyroscope.io/docs - -func main() { - var ( - format string - subcommand string - directory string - ) - flag.StringVar(&format, "format", "yaml", "yaml or md") - flag.StringVar(&subcommand, "subcommand", "server", "server, agent, exec...") - flag.StringVar(&directory, "directory", "", "directory to scan and perform auto replacements") - flag.Parse() - - if directory != "" { - err := filepath.Walk(directory, func(path string, f os.FileInfo, err error) error { - if slices.StringContains([]string{".mdx", ".md"}, filepath.Ext(path)) { - return processFile(path) - } - return nil - }) - if err != nil { - panic(err) - } - } else { - writeConfigDocs(os.Stdout, subcommand, format) - } -} - -var ( - sectionRegexp = regexp.MustCompile(`(?s).*?`) - headerRegexp = regexp.MustCompile("generate-sample-config:(.+?):(.+?)\\s*-") -) - -func processFile(path string) error { - content, err := os.ReadFile(path) - if err != nil { - return fmt.Errorf("reading file: %w", err) - } - - newContent := sectionRegexp.ReplaceAllFunc(content, func(b []byte) []byte { - submatches := headerRegexp.FindSubmatch(b) - buf := bytes.Buffer{} - subcommand := string(submatches[1]) - format := string(submatches[2]) - writeConfigDocs(&buf, subcommand, format) - return buf.Bytes() - }) - - if bytes.Equal(content, newContent) { - return nil - } - - fmt.Println(path) - return os.WriteFile(path, newContent, 0640) -} - -func writeConfigDocs(w io.Writer, subcommand, format string) { - flagSet := pflag.NewFlagSet("pyroscope "+subcommand, pflag.ExitOnError) - - v := viper.New() - v.SetEnvPrefix("PYROSCOPE") - v.AutomaticEnv() - v.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_")) - - opts := []cli.FlagOption{ - cli.WithReplacement("", "pyspy, rbspy, phpspy, dotnetspy, ebpfspy"), - cli.WithSkipDeprecated(true), - } - - var val interface{} - switch subcommand { - case "agent": - val = new(config.Agent) - // Skip `targets` only from CLI reference. - if format == "md" { - cli.PopulateFlagSet(val, flagSet, v, append(opts, cli.WithSkip("targets"))...) - } else { - cli.PopulateFlagSet(val, flagSet, v, opts...) - } - case "server": - val = new(config.Server) - // Skip `metrics-export-rules` only from CLI reference. - if format == "md" { - cli.PopulateFlagSet(val, flagSet, v, append(opts, cli.WithSkip("metrics-export-rules"))...) - } else { - cli.PopulateFlagSet(val, flagSet, v, opts...) - } - case "convert": - val = new(config.Convert) - cli.PopulateFlagSet(val, flagSet, v, opts...) - case "exec": - val = new(config.Exec) - cli.PopulateFlagSet(val, flagSet, v, append(opts, cli.WithSkip("pid"))...) - case "connect": - val = new(config.Exec) - cli.PopulateFlagSet(val, flagSet, v, append(opts, cli.WithSkip("group-name", "user-name", "no-root-drop"))...) - case "target": - val = new(config.Target) - cli.PopulateFlagSet(val, flagSet, v, append(opts, cli.WithSkip("tags"))...) - case "metric-export-rule": - val = new(config.MetricsExportRule) - cli.PopulateFlagSet(val, flagSet, v, opts...) - default: - //revive:disable-next-line:deep-exit fine for now - log.Fatalf("Unknown subcommand %q", subcommand) - } - - _, _ = fmt.Fprintf(w, "\n", subcommand, format) - - switch format { - case "yaml": - writeYaml(w, flagSet) - case "md": - writeMarkdown(w, flagSet) - default: - logrus.Fatalf("Unknown format %q", format) - } - - _, _ = fmt.Fprintf(w, "") -} - -func writeYaml(w io.Writer, flagSet *pflag.FlagSet) { - _, _ = fmt.Fprintf(w, "```yaml\n---\n") - flagSet.VisitAll(func(f *pflag.Flag) { - if f.Name == "config" { - return - } - var v string - switch reflect.TypeOf(f.Value).Elem().Kind() { - case reflect.Slice, reflect.Map: - v = f.Value.String() - default: - v = fmt.Sprintf("%q", f.Value) - } - _, _ = fmt.Fprintf(w, "# %s\n%s: %s\n\n", toPrettySentence(f.Usage), f.Name, v) - }) - _, _ = fmt.Fprintf(w, "```\n") -} - -func writeMarkdown(w io.Writer, flagSet *pflag.FlagSet) { - _, _ = fmt.Fprintf(w, "| %s | %s | %s |\n", "Name", "Default Value", "Usage") - _, _ = fmt.Fprintf(w, "| %s | %s | %s |\n", ":-", ":-", ":-") - flagSet.VisitAll(func(f *pflag.Flag) { - if f.Name == "config" { - return - } - // Replace vertical bar glyph with HTML code. - desc := strings.ReplaceAll(toPrettySentence(f.Usage), "|", `|`) - _, _ = fmt.Fprintf(w, "| %s | %s | %s |\n", f.Name, f.DefValue, desc) - }) -} - -// Capitalizes the first letter and adds period at the end, if necessary. -func toPrettySentence(s string) string { - if s == "" { - return "" - } - x := []rune(s) - x[0] = unicode.ToUpper(x[0]) - if x[len(s)-1] != '.' { - x = append(x, '.') - } - return string(x) -} diff --git a/og/scripts/ginkgo-bootstrap.sh b/og/scripts/ginkgo-bootstrap.sh deleted file mode 100755 index c476736937..0000000000 --- a/og/scripts/ginkgo-bootstrap.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -go list ./... | sed 's/github.com\/pyroscope-io\/pyroscope/./' | \ - grep -v 'pkg/agent/.\+spy' | \ - grep -v 'pkg/testing' | \ - grep -v 'pkg/agent/cli' | \ - grep -v 'pkg/dbmanager' | \ - grep -v 'scripts' | \ - grep -v 'tools' | \ - grep -v 'examples' | \ - xargs -I {} bash -c 'cd {} && ginkgo bootstrap' diff --git a/og/scripts/jest-snapshots/run-docker.sh b/og/scripts/jest-snapshots/run-docker.sh deleted file mode 100755 index e0cdc21d06..0000000000 --- a/og/scripts/jest-snapshots/run-docker.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -UPDATE_SNAPSHOTS="${UPDATE_SNAPSHOTS:-}" - -docker run \ - -it --rm \ - --entrypoint=/bin/bash \ - -e UPDATE_SNAPSHOTS="$UPDATE_SNAPSHOTS" \ - -v $PWD:/app \ - -v /app/node_modules \ - -w /app \ - node:14.17-slim ./scripts/jest-snapshots/run-snapshots.sh diff --git a/og/scripts/jest-snapshots/run-snapshots.sh b/og/scripts/jest-snapshots/run-snapshots.sh deleted file mode 100755 index acf8fa616d..0000000000 --- a/og/scripts/jest-snapshots/run-snapshots.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - - -updateArg="" - -if [ "$UPDATE_SNAPSHOTS" = true ]; then - updateArg="-u" -fi - - -apt update -y -apt install fontconfig -y - -if [ $(dpkg --print-architecture) = "arm64" ]; then -# The chromium binary is not available for arm64. - apt install chromium -y - - # To build canvas from source - apt install python pkg-config -y - apt install -y build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev -fi - -# ignore-engines due to -# warning webpack-plugin-serve@1.5.0: Invalid bin field for "webpack-plugin-serve". -# error eslint-import-resolver-webpack@0.13.1: The engine "node" is incompatible with this module. Expected version "^16 || ^15 || ^14 || ^13 || ^12 || ^11 || ^10 || ^9 || ^8 || ^7 || ^6". Got "17.0.1" -# error Found incompatible module. -yarn install --ignore-engines --frozen-lockfile -RUN_SNAPSHOTS=true yarn test --testNamePattern='group:snapshot' --verbose "$updateArg" --runInBand - diff --git a/og/scripts/oauth-mock/README.md b/og/scripts/oauth-mock/README.md deleted file mode 100644 index 8dd2103b9c..0000000000 --- a/og/scripts/oauth-mock/README.md +++ /dev/null @@ -1,20 +0,0 @@ -### What is this? - -This is a mock OAuth server for testing purposes. It allows you to run pyroscope with oauth enabled locally by mimicking gitlab oauth server. - - -### Usage - -To run the mock server, run the following command: -```shell -node ./scripts/oauth-mock/oauth-mock.js -``` - -To run pyroscope with the right config run: -```shell -make build -bin/pyroscope server -config scripts/oauth-mock/pyroscope-config.yml -``` - -Then go to http://localhost:4040/ and pyroscope should send you to log in via GitLab (which is really just our mock in this case). - diff --git a/og/scripts/oauth-mock/oauth-mock.js b/og/scripts/oauth-mock/oauth-mock.js deleted file mode 100644 index d64facba44..0000000000 --- a/og/scripts/oauth-mock/oauth-mock.js +++ /dev/null @@ -1,47 +0,0 @@ -async function main() { - // eslint-disable-next-line global-require - const { OAuth2Server } = require('oauth2-mock-server'); - - const server = new OAuth2Server(undefined, undefined, { - endpoints: { - wellKnownDocument: '/.well-known/openid-configuration', - token: '/token', - jwks: '/jwks', - authorize: '/authorize', - userinfo: '/user', - revoke: '/revoke', - endSession: '/endSession', - introspect: '/introspect', - }, - }); - - // hack to add /groups support to the mock server - server.service.requestHandler.get('/groups', (req, res) => { - res.status(200).json([{ path: 'allowed-group-example' }]); - }); - - server.service.addListener('beforeUserinfo', (userInfoResponse, req) => { - userInfoResponse.body = { - id: 1245, - email: 'test@test.com', - username: 'testuser', - avatarurl: - 'https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50', - }; - }); - - // Generate a new RSA key and add it to the keystore - await server.issuer.keys.generate('RS256'); - - // Start the server - await server.start(18080, '0.0.0.0'); - console.log('Issuer URL:', server.issuer.url); // -> http://localhost:8080 - - // Do some work with the server - // ... - - // Stop the server - // return await server.stop(); -} - -main(); diff --git a/og/scripts/oauth-mock/pyroscope-config-base-url.yml b/og/scripts/oauth-mock/pyroscope-config-base-url.yml deleted file mode 100644 index eb65cc6c0f..0000000000 --- a/og/scripts/oauth-mock/pyroscope-config-base-url.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -base-url: /pyroscope -no-self-profiling: true - -auth: - signup-default-role: Admin - internal: - enabled: true - - gitlab: - enabled: true - api-url: http://localhost:18080 - auth-url: http://localhost:18080/authorize - token-url: http://localhost:18080/token - client-id: 42fe36a3c42334416f36f71049aa5efe - client-secret: 16f36f71049aa5efe42fe36a3c423344 - redirect-url: http://localhost:8080/pyroscope/auth/gitlab/callback - - # allowed-groups: - # - allowed-group-example -storage-path: tmp/oauth-mock-storage -log-level: debug diff --git a/og/scripts/oauth-mock/pyroscope-config.yml b/og/scripts/oauth-mock/pyroscope-config.yml deleted file mode 100644 index 3704e9c042..0000000000 --- a/og/scripts/oauth-mock/pyroscope-config.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -auth: - signup-default-role: Admin - internal: - enabled: true - - gitlab: - enabled: true - api-url: http://localhost:18080 - auth-url: http://localhost:18080/authorize - token-url: http://localhost:18080/token - client-id: 42fe36a3c42334416f36f71049aa5efe - client-secret: 16f36f71049aa5efe42fe36a3c423344 - # allowed-groups: - # - allowed-group-example -storage-path: tmp/oauth-mock-storage -log-level: debug diff --git a/og/scripts/obfuscate.js b/og/scripts/obfuscate.js deleted file mode 100644 index 1680fe8969..0000000000 --- a/og/scripts/obfuscate.js +++ /dev/null @@ -1,20 +0,0 @@ -const fs = require('fs'); -const args = process.argv.slice(2); - -if (args.length != 1) { - console.error('Usage ./obfuscate [filepath]'); - process.exit(1); -} -// TODO(eh-am): read from stdin if available -const filename = args[0]; -const data = JSON.parse(fs.readFileSync(filename)); - -function randomName() { - let r = (Math.random() + 1).toString(36).substring(7); - return r; -} - -data.metadata.name = randomName(); -data.flamebearer.names = data.flamebearer.names.map(randomName); - -console.log(JSON.stringify(data)); diff --git a/og/scripts/pinned-tool.sh b/og/scripts/pinned-tool.sh deleted file mode 100755 index 79913d11d9..0000000000 --- a/og/scripts/pinned-tool.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -echo "$(go list -m -f '{{.Dir}}' $1)" diff --git a/og/scripts/pprof-view/main.go b/og/scripts/pprof-view/main.go deleted file mode 100644 index 90a2f89344..0000000000 --- a/og/scripts/pprof-view/main.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "io" - "log" - "os" - "strings" - "time" - - "github.com/pyroscope-io/pyroscope/pkg/convert/pprof" - "github.com/pyroscope-io/pyroscope/pkg/storage" - "github.com/pyroscope-io/pyroscope/pkg/storage/tree" - - "gopkg.in/yaml.v2" -) - -func main() { - // the idea here is that you can run it via go main like so: - // cat heap.pprof.gz | go run scripts/pprof-view/main.go - // and the script will print a json version of a given profile - if len(os.Args) == 1 { - if err := dumpJSON(os.Stdout); err != nil { - log.Fatalln(err) - } - return - } - - // You can also parse pprof with a config: - // go run scripts/pprof-view/main.go -path heap.pb.gz -type mem -config ./scripts/pprof-view/pprof-config.yaml - // If config is not specified, the default one is used (see tree.DefaultSampleTypeMapping). - var ( - configPath string - pprofPath string - profileType string - ) - - flag.StringVar(&configPath, "config", "", "path to pprof parsing config") - flag.StringVar(&pprofPath, "path", "", "path tp pprof data (gzip or plain)") - flag.StringVar(&profileType, "type", "cpu", "profile type from the config (cpu, mem, goroutines, etc)") - flag.Parse() - - if err := printProfiles(os.Stdout, pprofPath, configPath, profileType); err != nil { - log.Fatalln(err) - } -} - -func dumpJSON(w io.Writer) error { - var p tree.Profile - if err := pprof.Decode(os.Stdin, &p); err != nil { - return err - } - b, err := json.MarshalIndent(&p, "", " ") - if err != nil { - return err - } - _, err = fmt.Fprintln(w, string(b)) - return err -} - -type ingester struct{ actual []*storage.PutInput } - -func (m *ingester) Put(_ context.Context, p *storage.PutInput) error { - m.actual = append(m.actual, p) - return nil -} - -func printProfiles(w io.Writer, pprofPath, configPath, profileType string) error { - c := tree.DefaultSampleTypeMapping - if configPath != "" { - sc, err := readPprofConfig(configPath) - if err != nil { - return fmt.Errorf("reading pprof parsing config: %w", err) - } - var ok bool - if c, ok = sc[profileType]; !ok { - return fmt.Errorf("profile type not found in the config") - } - } - - p, err := readPprof(pprofPath) - if err != nil { - return fmt.Errorf("reading pprof file: %w", err) - } - - x := new(ingester) - pw := pprof.NewParser(pprof.ParserConfig{ - Putter: x, - SampleTypes: c, - SpyName: "spy-name", - Labels: nil, - }) - - if err = pw.Convert(context.TODO(), time.Time{}, time.Time{}, p, false); err != nil { - return fmt.Errorf("parsing pprof: %w", err) - } - - _, _ = fmt.Fprintln(w, "Found profiles:", len(x.actual)) - for i, profile := range x.actual { - _, _ = fmt.Fprintln(w, strings.Repeat("-", 80)) - _, _ = fmt.Fprintf(w, "Profile %d: %s\n", i+1, profile.Key.Normalized()) - _, _ = fmt.Fprintln(w, "\tAggregation:", profile.AggregationType) - _, _ = fmt.Fprintln(w, "\tUnits:", profile.Units) - _, _ = fmt.Fprintln(w, "\tTotal:", profile.Val.Samples()) - _, _ = fmt.Fprintln(w, "\tSample rate:", profile.SampleRate) - _, _ = fmt.Fprintf(w, "\n%s\n", profile.Val) - } - - return nil -} - -func readPprofConfig(path string) (map[string]map[string]*tree.SampleTypeConfig, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer func() { - _ = f.Close() - }() - var c map[string]map[string]*tree.SampleTypeConfig - if err = yaml.NewDecoder(f).Decode(&c); err != nil { - return nil, err - } - return c, nil -} - -func readPprof(path string) (*tree.Profile, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer func() { - _ = f.Close() - }() - var p tree.Profile - if err = pprof.Decode(f, &p); err != nil { - return nil, err - } - return &p, nil -} diff --git a/og/scripts/pprof-view/pprof-config.yaml b/og/scripts/pprof-view/pprof-config.yaml deleted file mode 100644 index 83c44dbff0..0000000000 --- a/og/scripts/pprof-view/pprof-config.yaml +++ /dev/null @@ -1,62 +0,0 @@ ---- -# type SampleTypeConfig struct { -# Units string `json:"units,omitempty"` -# DisplayName string `json:"display-name,omitempty"` -# Aggregation string `json:"aggregation,omitempty"` -# Cumulative bool `json:"cumulative,omitempty"` -# Sampled bool `json:"sampled,omitempty"` -# } - -cpu: - samples: - display-name: cpu - units: samples - sampled: true - -mem-js: - objects: - units: objects - aggregation: avg - space: - units: bytes - aggregation: avg - -mem: - inuse_objects: - units: objects - aggregation: avg - inuse_space: - units: bytes - aggregation: avg - alloc_objects: - units: objects - cumulative: true - alloc_space: - units: bytes - cumulative: true - -goroutines: - goroutine: - display-name: goroutines - units: objects - aggregation: average - -mutex: - contentions: - display-name: mutex-contentions - units: objects - aggregation: average - delay: - display-name: mutex-delay - units: nanoseconds - aggregation: average - -block: - contentions: - display-name: block-contentions - units: objects - aggregation: average - delay: - display-name: block-delay - units: nanoseconds - aggregation: average diff --git a/og/scripts/run-tests.sh b/og/scripts/run-tests.sh deleted file mode 100755 index 32522b284d..0000000000 --- a/og/scripts/run-tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - - - -for run in {1..10}; do - res=$(yarn cy:ss-check) - echo "$run statusCode=$?" - - if [ $? -ne 0 ]; then - echo $res - fi - -done diff --git a/og/scripts/traffic-duplicator/example.sh b/og/scripts/traffic-duplicator/example.sh deleted file mode 100755 index a03199c018..0000000000 --- a/og/scripts/traffic-duplicator/example.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -echo "http://localhost:4041/ingest" -echo "http://localhost:4042" -echo "http://localhost:4043" -echo "http://localhost:4044 .*rbspy.*" diff --git a/og/scripts/traffic-duplicator/main.go b/og/scripts/traffic-duplicator/main.go deleted file mode 100644 index 3a26cfbfdb..0000000000 --- a/og/scripts/traffic-duplicator/main.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "context" - "flag" - "io" - "net/http" - "net/url" - "os/exec" - "regexp" - "strings" - "sync" - "time" - - "github.com/sirupsen/logrus" -) - -type target struct { - url *url.URL - matcher *regexp.Regexp -} - -var ( - // input flags - bindAddr string - logLevel string - targetsPath string - - // list of upstream targets - targetsMutex sync.RWMutex - targets []target -) - -func main() { - flag.StringVar(&bindAddr, "bind-addr", ":4040", "bind address for http server") - flag.StringVar(&logLevel, "log-level", "info", "log level") - flag.StringVar(&targetsPath, "targets-path", "./generate-targets.sh", "path to a script that generates upstream targets") - flag.Parse() - - setupLogging() - go updateTargets() - startProxy() -} - -func setupLogging() { - l, err := logrus.ParseLevel(logLevel) - if err != nil { - logrus.Fatal(err) - } - logrus.SetLevel(l) -} - -func startProxy() { - logrus.WithFields(logrus.Fields{ - "bind-addr": bindAddr, - "targets-path": targetsPath, - }).Info("config") - - err := http.ListenAndServe(bindAddr, http.HandlerFunc(handleConn)) - logrus.WithError(err).WithField("bindAddr", bindAddr).Error("error listening") -} - -func handleConn(_ http.ResponseWriter, r *http.Request) { - b, err := io.ReadAll(r.Body) - if err != nil { - logrus.WithError(err).Error("failed to read body") - } - - targetsMutex.RLock() - targetsCopy := make([]target, len(targets)) - copy(targetsCopy, targets) - targetsMutex.RUnlock() - - for _, t := range targetsCopy { - appName := r.URL.Query().Get("name") - if t.matcher.MatchString(appName) { - logrus.WithField("target", t).Debug("uploading to upstream") - reader := bytes.NewReader(b) - - r.URL.Scheme = t.url.Scheme - r.URL.Host = t.url.Host - - resp, err := http.Post(r.URL.String(), r.Header.Get("Content-Type"), reader) - if err != nil { - logrus.WithError(err).WithField("target", t).Error("failed to upload to target") - continue - } - logrus.WithField("resp", resp).Debug("response") - if err := resp.Body.Close(); err != nil { - logrus.WithError(err).WithField("target", t).Error("failed to close response body") - } - } - } -} - -func updateTargets() { - for { - ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - cmd := exec.CommandContext(ctx, targetsPath) - buf := bytes.Buffer{} - cmd.Stdout = &buf - err := cmd.Run() - if err != nil { - logrus.WithError(err).Error("failed to generate targets") - } - targetsMutex.Lock() - targets = generateTargets(bytes.NewReader(buf.Bytes())) - logrus.Debug("new targets:") - for _, t := range targets { - logrus.Debugf("* %s %s", t.url, t.matcher) - } - targetsMutex.Unlock() - time.Sleep(10 * time.Second) - } -} - -func generateTargets(r io.Reader) []target { - var targets []target - scanner := bufio.NewScanner(r) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - arr := strings.SplitN(line, " ", 2) - if len(arr) < 2 { - arr = append(arr, ".*") - } - - u, err := url.ParseRequestURI(arr[0]) - if err != nil { - continue - } - matcher, err := regexp.Compile(arr[1]) - if err != nil { - continue - } - targets = append(targets, target{ - url: u, - matcher: matcher, - }) - } - return targets -} diff --git a/og/scripts/web-postinstall.js b/og/scripts/web-postinstall.js deleted file mode 100755 index 8bb1373790..0000000000 --- a/og/scripts/web-postinstall.js +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env node - -const fs = require('fs'); -const commandExists = require('command-exists').sync; -const { execSync } = require('child_process'); - -if (fs.existsSync('.git') && commandExists('git')) { - // makes git blame ignore commits that are purely reformatting code - execSync('git config blame.ignoreRevsFile .git-blame-ignore-revs'); -} diff --git a/og/scripts/webpack/.eslintrc.js b/og/scripts/webpack/.eslintrc.js deleted file mode 100644 index 0e6acda5e7..0000000000 --- a/og/scripts/webpack/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - rules: { - 'no-console': 'off', - }, -}; diff --git a/og/scripts/webpack/postcss.config.js b/og/scripts/webpack/postcss.config.js deleted file mode 100644 index 6055e05eb1..0000000000 --- a/og/scripts/webpack/postcss.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = () => ({ - plugins: { - autoprefixer: {}, - 'postcss-reporter': {}, - 'postcss-browser-reporter': {}, - }, -}); diff --git a/og/scripts/webpack/shared.ts b/og/scripts/webpack/shared.ts deleted file mode 100644 index 88ba84718d..0000000000 --- a/og/scripts/webpack/shared.ts +++ /dev/null @@ -1,60 +0,0 @@ -import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import path from 'path'; - -// TODO: -export function getStyleLoaders() { - return [ - { - test: /\.(css|scss)$/, - use: [ - MiniCssExtractPlugin.loader, - { - loader: 'css-loader', - options: { - importLoaders: 2, - url: true, - }, - }, - { - loader: 'postcss-loader', - options: { - config: { path: __dirname }, - }, - }, - { - loader: 'sass-loader', - options: { - // sourceMap: true, - }, - }, - ], - }, - ]; -} - -export function getAlias() { - return { - // rc-trigger uses babel-runtime which has internal dependency to core-js@2 - // this alias maps that dependency to core-js@t3 - 'core-js/library/fn': 'core-js/stable', - '@webapp': path.resolve(__dirname, '../../webapp/javascript'), - }; -} - -export function getJsLoader() { - return [ - { - test: /\.(js|ts)x?$/, - exclude: /node_modules/, - use: [ - { - loader: 'esbuild-loader', - options: { - loader: 'tsx', // Or 'ts' if you don't need tsx - target: 'es2015', - }, - }, - ], - }, - ]; -} diff --git a/og/scripts/webpack/webpack.common.ts b/og/scripts/webpack/webpack.common.ts deleted file mode 100644 index 3dfd110cd1..0000000000 --- a/og/scripts/webpack/webpack.common.ts +++ /dev/null @@ -1,164 +0,0 @@ -// @ts-nocheck -import webpack from 'webpack'; -import path from 'path'; -import glob from 'glob'; -import fs from 'fs'; -import HtmlWebpackPlugin from 'html-webpack-plugin'; -import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import CopyPlugin from 'copy-webpack-plugin'; -import { ESBuildMinifyPlugin } from 'esbuild-loader'; - -import { getAlias, getJsLoader, getStyleLoaders } from './shared'; - -const packagePath = path.resolve(__dirname, '../../webapp'); -const rootPath = path.resolve(__dirname, '../../'); - -// use a fake hash when running locally -const LOCAL_HASH = 'local'; - -function getFilename(ext: string) { - // We may want to produce no hash, example when running size-limit - if (process.env.NOHASH) { - return `[name].${ext}`; - } - - if (process.env.NODE_ENV === 'production') { - return `[name].[hash].${ext}`; - } - - // TODO: there's some cache busting issue when running locally - return `[name].${LOCAL_HASH}.${ext}`; -} - -const pages = glob - .sync(path.join(__dirname, '../../webapp/templates/!(standalone).html')) - .map((x) => path.basename(x)); - -const pagePlugins = pages.map( - (name) => - new HtmlWebpackPlugin({ - filename: path.resolve(packagePath, `public/${name}`), - template: path.resolve(packagePath, `templates/${name}`), - inject: false, - templateParameters: (compilation) => { - // TODO: - // ideally we should access via argv - // https://webpack.js.org/configuration/mode/ - const hash = - process.env.NODE_ENV === 'production' - ? compilation.getStats().toJson().hash - : LOCAL_HASH; - - return { - extra_metadata: process.env.EXTRA_METADATA - ? fs.readFileSync(process.env.EXTRA_METADATA) - : '', - mode: process.env.NODE_ENV, - webpack: { - hash, - }, - }; - }, - }) -); - -export default { - target: 'web', - - entry: { - app: path.join(packagePath, 'javascript/index.tsx'), - styles: path.join(packagePath, 'sass/profile.scss'), - }, - - output: { - publicPath: '', - path: path.resolve(packagePath, 'public/assets'), - - // https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling - filename: getFilename('js'), - clean: true, - }, - - resolve: { - extensions: ['.ts', '.tsx', '.es6', '.js', '.jsx', '.json', '.svg'], - alias: getAlias(), - }, - - stats: { - children: false, - warningsFilter: /export .* was not found in/, - source: false, - }, - - watchOptions: { - ignored: /node_modules/, - }, - - optimization: { - minimizer: [ - new ESBuildMinifyPlugin({ - target: 'es2015', - css: true, - }), - ], - }, - - module: { - // Note: order is bottom-to-top and/or right-to-left - rules: [ - ...getJsLoader(), - ...getStyleLoaders(), - { - test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/, - loader: 'file-loader', - - // We output files to assets/static/img, where /assets comes from webpack's output dir - // However, we still need to prefix the public URL with /assets/static/img - options: { - outputPath: 'static/img', - // using relative path to make this work when pyroscope is deployed to a subpath (with BaseURL config option) - publicPath: '../assets/static/img', - name: '[name].[hash:8].[ext]', - }, - }, - - // for SVG used via react - // we simply inline them as if they were normal react components - { - test: /\.svg$/, - issuer: /\.(j|t)sx?$/, - use: [ - { loader: 'babel-loader' }, - { - loader: 'react-svg-loader', - options: { - svgo: { - plugins: [ - { convertPathData: { noSpaceAfterFlags: false } }, - { removeViewBox: false }, - ], - }, - }, - }, - ], - }, - ], - }, - - plugins: [ - // uncomment if you want to see the webpack bundle analysis - // new BundleAnalyzerPlugin(), - ...pagePlugins, - new MiniCssExtractPlugin({ - filename: getFilename('css'), - }), - new CopyPlugin({ - patterns: [ - { - from: path.join(packagePath, 'images'), - to: 'images', - }, - ], - }), - ], -}; diff --git a/og/scripts/webpack/webpack.dev.ts b/og/scripts/webpack/webpack.dev.ts deleted file mode 100644 index 0103e912dc..0000000000 --- a/og/scripts/webpack/webpack.dev.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { merge } from 'webpack-merge'; -import LiveReloadPlugin from 'webpack-livereload-plugin'; -import common from './webpack.common'; - -module.exports = merge(common, { - devtool: 'eval-source-map', - mode: 'development', - plugins: [ - new LiveReloadPlugin({ - appendScriptTag: true, - }), - ], - // TODO deal with these types - // eslint-disable-next-line @typescript-eslint/no-explicit-any -} as any); diff --git a/og/scripts/webpack/webpack.flamegraph.ts b/og/scripts/webpack/webpack.flamegraph.ts deleted file mode 100644 index e0c989aa2e..0000000000 --- a/og/scripts/webpack/webpack.flamegraph.ts +++ /dev/null @@ -1,112 +0,0 @@ -import path from 'path'; -import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import { ESBuildMinifyPlugin } from 'esbuild-loader'; -import webpack from 'webpack'; -import { getAlias, getJsLoader, getStyleLoaders } from './shared'; - -const common = { - mode: 'production', - devtool: 'source-map', - - resolve: { - extensions: ['.ts', '.tsx', '.es6', '.js', '.jsx', '.json', '.svg'], - alias: getAlias(), - modules: [ - 'node_modules', - path.resolve('webapp'), - path.resolve('node_modules'), - ], - }, - - watchOptions: { - ignored: /node_modules/, - }, - - optimization: { - minimizer: [ - new ESBuildMinifyPlugin({ - target: 'es2015', - css: true, - }), - ], - }, - - module: { - // Note: order is bottom-to-top and/or right-to-left - rules: [ - ...getJsLoader(), - ...getStyleLoaders(), - { - test: /\.svg$/, - use: [ - { loader: 'babel-loader' }, - { - loader: 'react-svg-loader', - options: { - svgo: { - plugins: [ - { convertPathData: { noSpaceAfterFlags: false } }, - { removeViewBox: false }, - ], - }, - }, - }, - ], - }, - ], - }, - - plugins: [ - new MiniCssExtractPlugin({}), - new webpack.DefinePlugin({ - 'process.env': { - PYROSCOPE_HIDE_LOGO: process.env['PYROSCOPE_HIDE_LOGO'], - }, - }), - ], -}; - -export default [ - { - ...common, - target: 'node', - mode: 'production', - // devtool: 'source-map', - entry: { - index: './src/index.node.ts', - }, - output: { - publicPath: '', - path: path.resolve(__dirname, '../../packages/pyroscope-flamegraph/dist'), - libraryTarget: 'commonjs', - filename: 'index.node.js', - }, - - externals: { - react: 'react', - 'react-dom': 'react-dom', - }, - }, - { - ...common, - target: 'web', - mode: 'production', - // devtool: 'source-map', - entry: { - index: './src/index.tsx', - }, - output: { - publicPath: '', - path: path.resolve(__dirname, '../../packages/pyroscope-flamegraph/dist'), - libraryTarget: 'umd', - library: 'pyroscope', - filename: 'index.js', - globalObject: 'this', - }, - - externals: { - react: 'react', - 'react-dom': 'react-dom', - }, - }, -]; diff --git a/og/scripts/webpack/webpack.lib.ts b/og/scripts/webpack/webpack.lib.ts deleted file mode 100644 index b392ce8d5b..0000000000 --- a/og/scripts/webpack/webpack.lib.ts +++ /dev/null @@ -1,127 +0,0 @@ -import path from 'path'; -import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import { ESBuildMinifyPlugin } from 'esbuild-loader'; -import CopyWebpackPlugin from 'copy-webpack-plugin'; -import { getAlias, getJsLoader, getStyleLoaders } from './shared'; - -const common = { - mode: 'production', - devtool: 'source-map', - - resolve: { - extensions: ['.ts', '.tsx', '.es6', '.js', '.jsx', '.json', '.svg'], - alias: getAlias(), - modules: [ - 'node_modules', - path.resolve('webapp'), - path.resolve('node_modules'), - ], - }, - - watchOptions: { - ignored: /node_modules/, - }, - - optimization: { - minimizer: [ - new ESBuildMinifyPlugin({ - target: 'es2015', - css: true, - }), - ], - }, - - module: { - // Note: order is bottom-to-top and/or right-to-left - rules: [ - ...getJsLoader(), - ...getStyleLoaders(), - { - test: /\.svg$/, - use: [ - { loader: 'babel-loader' }, - { - loader: 'react-svg-loader', - options: { - svgo: { - plugins: [ - { convertPathData: { noSpaceAfterFlags: false } }, - { removeViewBox: false }, - ], - }, - }, - }, - ], - }, - ], - }, - - plugins: [ - new MiniCssExtractPlugin({}), - new CopyWebpackPlugin({ - patterns: [ - { from: path.join('./packages/flamegraph/', 'README.md'), to: '.' }, - { - from: path.join('./packages/flamegraph/', 'package.json'), - to: '.', - }, - ], - }), - // new ReplaceInFileWebpackPlugin([ - // { - // dir: './dist/lib', - // files: ['package.json', 'README.md'], - // rules: [ - // { - // search: '%VERSION%', - // replace: version, - // }, - // { - // search: '%TODAY%', - // replace: new Date().toISOString().substring(0, 10), - // }, - // ], - // }, - // ]), - ], -}; - -export default [ - { - ...common, - target: 'node', - mode: 'production', - devtool: 'source-map', - entry: { - index: './packages/flamegraph/src/index.node.ts', - }, - output: { - publicPath: '', - path: path.resolve(__dirname, '../../packages/flamegraph/dist'), - libraryTarget: 'commonjs', - filename: 'index.node.js', - }, - }, - { - ...common, - target: 'web', - mode: 'production', - devtool: 'source-map', - entry: { - index: './packages/flamegraph/src/index.tsx', - }, - output: { - publicPath: '', - path: path.resolve(__dirname, '../../packages/flamegraph/dist'), - libraryTarget: 'umd', - library: 'pyroscope', - filename: 'index.js', - globalObject: 'this', - }, - - externals: { - react: 'react', - reactDom: 'react-dom', - }, - }, -]; diff --git a/og/scripts/webpack/webpack.prod.ts b/og/scripts/webpack/webpack.prod.ts deleted file mode 100644 index acb678f110..0000000000 --- a/og/scripts/webpack/webpack.prod.ts +++ /dev/null @@ -1,13 +0,0 @@ -// @ts-nocheck -import { merge } from 'webpack-merge'; - -import common from './webpack.common'; - -export default merge(common, { - mode: 'production', - - // Recommended choice for production builds with high quality SourceMaps. - devtool: 'source-map', - // TODO deal with these types - // eslint-disable-next-line @typescript-eslint/no-explicit-any -} as any); diff --git a/og/scripts/webpack/webpack.size-limit.ts b/og/scripts/webpack/webpack.size-limit.ts deleted file mode 100644 index 8d23da5b7f..0000000000 --- a/og/scripts/webpack/webpack.size-limit.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { merge } from 'webpack-merge'; -import path from 'path'; -import prod from './webpack.prod'; - -module.exports = merge(prod, { - output: { - publicPath: '', - path: path.resolve(__dirname, '../../webapp/public/assets'), - clean: true, - }, -}); diff --git a/og/scripts/webpack/webpack.standalone.ts b/og/scripts/webpack/webpack.standalone.ts deleted file mode 100644 index 77718c9405..0000000000 --- a/og/scripts/webpack/webpack.standalone.ts +++ /dev/null @@ -1,95 +0,0 @@ -// @ts-nocheck -import HtmlWebpackPlugin from 'html-webpack-plugin'; -import InlineChunkHtmlPlugin from 'react-dev-utils/InlineChunkHtmlPlugin'; -import HTMLInlineCSSWebpackPlugin from 'html-inline-css-webpack-plugin'; -import path from 'path'; -import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import { getAlias, getJsLoader, getStyleLoaders } from './shared'; - -const packagePath = path.resolve(__dirname, '../../webapp'); - -// Creates a file in webapp/public/standalone.html -// With js+css+svg embed into the html -const config = (env, options) => { - let livereload = []; - - // conditionally use require - // so that in CI when building for production don't have to pull it - if (options.watch) { - // eslint-disable-next-line global-require - const LiveReloadPlugin = require('webpack-livereload-plugin'); - livereload = [ - new LiveReloadPlugin({ - // most likely the default port is used by the main webapp - port: 35730, - appendScriptTag: true, - }), - ]; - } - - return { - // We will always run in production mode, even when developing locally - // reason is that we rely on things like ModuleConcatenation, TerserPlugin etc - mode: 'production', - // devtool: 'eval-source-map', - entry: { - app: path.join(packagePath, './javascript/standalone.tsx'), - styles: path.join(packagePath, './sass/standalone.scss'), - }, - - optimization: { - mangleExports: false, - // minimize: false, - }, - - output: { - publicPath: '', - // Emit to another directory other than webapp/public/assets to not have any conflicts - path: path.resolve(__dirname, '../../dist/standalone'), - filename: '[name].js', - clean: true, - }, - module: { - // Note: order is bottom-to-top and/or right-to-left - rules: [ - ...getJsLoader(), - ...getStyleLoaders(), - { - test: /\.svg/, - use: { - loader: 'svg-url-loader', - }, - }, - ], - }, - resolve: { - extensions: ['.ts', '.tsx', '.js', '.jsx', '.svg'], - alias: getAlias(), - modules: [ - path.resolve(packagePath), - path.resolve(path.join(__dirname, '../../node_modules')), - path.resolve('node_modules'), - ], - }, - plugins: [ - new MiniCssExtractPlugin({ - filename: '[name].[hash].css', - }), - new HtmlWebpackPlugin({ - minify: { - // We need to keep the comments since go will use a comment - // to know what to replace for the flamegraph - removeComments: false, - }, - filename: path.resolve(packagePath, `public/standalone.html`), - template: path.resolve(packagePath, `templates/standalone.html`), - }), - new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/.*/]), - new HTMLInlineCSSWebpackPlugin(), - - ...livereload, - ], - }; -}; - -export default config; diff --git a/og/scripts/windows/generate-windows-version-info/README.md b/og/scripts/windows/generate-windows-version-info/README.md deleted file mode 100644 index 49e7b38394..0000000000 --- a/og/scripts/windows/generate-windows-version-info/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Windows Version Info - -This tool generates `syso` file which is required for windows build. -In particular, version info is used in MSI build. - -`go` embeds .syso object files at build, therefore the file should -be generated in advance. - -Refer for details: https://docs.microsoft.com/en-us/windows/win32/menurc/versioninfo-resource?redirectedfrom=MSDN diff --git a/og/scripts/windows/generate-windows-version-info/main.go b/og/scripts/windows/generate-windows-version-info/main.go deleted file mode 100644 index de0cee0bc6..0000000000 --- a/og/scripts/windows/generate-windows-version-info/main.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "errors" - "flag" - "fmt" - "os" - "strings" - - "github.com/blang/semver" - "github.com/josephspurrier/goversioninfo" -) - -func main() { - var version string - flag.StringVar(&version, "version", "", "Version in semver format.") - - var outputPath string - flag.StringVar(&outputPath, "out", "", "Output file path.") - - var iconPath string - flag.StringVar(&iconPath, "icon", "", "Icon file path.") - flag.Parse() - - if err := generateVersionInfo(version, outputPath, iconPath); err != nil { - _, _ = fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func generateVersionInfo(version, outputPath, iconPath string) error { - version = strings.Trim(version, `"`) - v, err := semver.Parse(strings.TrimPrefix(version, "v")) - - if version == "" { - return errors.New("version is required") - } - - if err != nil { - return fmt.Errorf("invalid version %q: %w", version, err) - } - - if outputPath == "" { - return errors.New("output path is required") - } - - versionInfo := goversioninfo.VersionInfo{ - FixedFileInfo: goversioninfo.FixedFileInfo{ - FileVersion: goversioninfo.FileVersion{ - Major: int(v.Major), - Minor: int(v.Minor), - Patch: int(v.Patch), - Build: 0, - }, - ProductVersion: goversioninfo.FileVersion{ - Major: int(v.Major), - Minor: int(v.Minor), - Patch: int(v.Patch), - Build: 0, - }, - FileFlagsMask: "3f", - FileFlags: "00", - FileOS: "040004", - FileType: "01", - FileSubType: "00", - }, - StringFileInfo: goversioninfo.StringFileInfo{ - Comments: "", - CompanyName: "Pyroscope, Inc", - FileDescription: "Pyroscope continuous profiling platform agent", - FileVersion: version, - InternalName: "pyroscope.exe", - LegalCopyright: "Copyright (c) 2021 Pyroscope, Inc", - LegalTrademarks: "", - OriginalFilename: "", - PrivateBuild: "", - ProductName: "Pyroscope Agent", - ProductVersion: version, - SpecialBuild: "", - }, - VarFileInfo: goversioninfo.VarFileInfo{ - Translation: goversioninfo.Translation{ - LangID: goversioninfo.LngUSEnglish, - CharsetID: goversioninfo.CsUnicode, - }, - }, - IconPath: iconPath, - ManifestPath: "", - } - - versionInfo.Build() - versionInfo.Walk() - - if err = versionInfo.WriteSyso(outputPath, "amd64"); err != nil { - return fmt.Errorf("failed to write output file %s: %w", outputPath, err) - } - - return nil -} diff --git a/og/scripts/windows/pyroscope.wsx b/og/scripts/windows/pyroscope.wsx deleted file mode 100644 index 4c98716882..0000000000 --- a/og/scripts/windows/pyroscope.wsx +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Privileged - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/og/scripts/windows/resources/app.ico b/og/scripts/windows/resources/app.ico deleted file mode 100644 index 88f56e5eb1..0000000000 Binary files a/og/scripts/windows/resources/app.ico and /dev/null differ diff --git a/og/third_party/bcc/.gitignore b/og/third_party/bcc/.gitignore deleted file mode 100644 index d917b5949e..0000000000 --- a/og/third_party/bcc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -lib/ -src/ diff --git a/og/third_party/bcc/Makefile b/og/third_party/bcc/Makefile deleted file mode 100644 index c522b9ad1d..0000000000 --- a/og/third_party/bcc/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -BCC_VERSION ?= b9554b585afe18540ba98dde5b667e5b4036f479 - -.PHONY: build-bcc -build-bcc: - test -d src || git clone https://github.com/korniltsev/bcc src - cd src && git checkout $(BCC_VERSION) - test -d src/build && rm -rf src/build || echo bcc src/build dir does not exits - mkdir src/build - cd src/build \ - && cmake ../build-syms \ - -DCMAKE_C_COMPILER=clang \ - -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$(shell pwd)/lib \ - && make -j16 install - -.PHONY: clean -clean: - rm -rf src lib diff --git a/og/third_party/libbpf/.gitignore b/og/third_party/libbpf/.gitignore deleted file mode 100644 index d917b5949e..0000000000 --- a/og/third_party/libbpf/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -lib/ -src/ diff --git a/og/third_party/libbpf/Makefile b/og/third_party/libbpf/Makefile deleted file mode 100644 index 4de35c7fe5..0000000000 --- a/og/third_party/libbpf/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -LIBBPF_VERSION ?= v0.8.1 - -.PHONY: build-libbpf -build-libbpf: - test -d src || git clone https://github.com/libbpf/libbpf src - cd src && git checkout $(LIBBPF_VERSION) - PREFIX=$(shell pwd)/lib make -C src/src -j16 install - -.PHONY: clean -clean: - rm -rf src lib diff --git a/og/third_party/phpspy/phpspy.h b/og/third_party/phpspy/phpspy.h deleted file mode 100644 index 2a1ace388c..0000000000 --- a/og/third_party/phpspy/phpspy.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __PYROSCOPE_API_H -#define __PYROSCOPE_API_H - -#include - -void phpspy_init_spy(const char *args); -int phpspy_init_pid(int pid_i, void *err_ptr, int err_len); -int phpspy_cleanup(int pid_i, void *err_ptr, int err_len); -int phpspy_snapshot(int pid_i, void *ptr, int len, void *err_ptr, int err_len); - -#endif diff --git a/og/tools/placeholder.go b/og/tools/placeholder.go deleted file mode 100644 index f74e980e3d..0000000000 --- a/og/tools/placeholder.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package tools is empty. See tools.go file for more context -package tools diff --git a/og/tools/tools.go b/og/tools/tools.go deleted file mode 100644 index a951e4e62b..0000000000 --- a/og/tools/tools.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build tools -// +build tools - -// Package tools is used to describe various tools we use. -// Think of it as "dev-dependencies" in ruby or node projects -// See: https://marcofranssen.nl/manage-go-tools-via-go-modules/ -// See Makefile for an example of how it's used -package tools - -import ( - _ "github.com/davecgh/go-spew/spew" - _ "github.com/google/go-jsonnet/cmd/jsonnet" - _ "github.com/google/pprof" - _ "github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb" - _ "github.com/kisielk/godepgraph" - _ "github.com/kyoh86/richgo" - _ "github.com/mattn/goreman" - _ "github.com/mgechev/revive" - _ "github.com/onsi/ginkgo/v2/ginkgo" - _ "golang.org/x/tools/cmd/godoc" - _ "honnef.co/go/tools/cmd/staticcheck" -) diff --git a/og/translations/README.ch.md b/og/translations/README.ch.md deleted file mode 100644 index c168bd8b6a..0000000000 --- a/og/translations/README.ch.md +++ /dev/null @@ -1,156 +0,0 @@ - -

Pyroscope

- -[![Go Tests Status](https://github.com/pyroscope-io/pyroscope/workflows/Go%20Tests/badge.svg)](https://github.com/pyroscope-io/pyroscope/actions?query=workflow%3AGo%20Tests) -[![JS Tests Status](https://github.com/pyroscope-io/pyroscope/workflows/JS%20Tests/badge.svg)](https://github.com/pyroscope-io/pyroscope/actions?query=workflow%3AJS%20Tests) -[![Go Report](https://goreportcard.com/badge/github.com/pyroscope-io/pyroscope)](https://goreportcard.com/report/github.com/pyroscope-io/pyroscope) -[![Apache 2 License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE) -[![Latest release](https://img.shields.io/github/release/pyroscope-io/pyroscope.svg)](https://github.com/pyroscope-io/pyroscope/releases) -[![DockerHub](https://img.shields.io/docker/pulls/pyroscope/pyroscope.svg)](https://hub.docker.com/r/pyroscope/pyroscope) -[![GoDoc](https://godoc.org/github.com/pyroscope-io/pyroscope?status.svg)](https://godoc.org/github.com/pyroscope-io/pyroscope) - -

- 官网 - - 文档 - - 演示 - - 示例 - - Slack -

- - -### 什么是 Pyroscope? -Pyroscope 是一个开源的持续性能剖析平台。它能够帮你: -* 找出源代码中的性能问题和瓶颈 -* 解决 CPU 利用率高的问题 -* 理解应用程序的调用树(call tree) -* 追踪随一段时间内变化的情况 - -## 🔥 [Pyroscope 在线演示](https://demo.pyroscope.io/?name=hotrod.python.frontend%7B%7D) 🔥 - -[![Pyroscope GIF Demo](https://user-images.githubusercontent.com/662636/105124618-55b9df80-5a8f-11eb-8ad5-0e18c17c827d.gif)](https://demo.pyroscope.io/) - - -## 特性 - -* 可以存储来自多个应用程序的多年剖析数据 -* 你可以一次查看多年的数据或单独查看特定的事件 -* 较低的 CPU 开销 -* 数据压缩效率高,磁盘空间要求低 -* 快捷的 UI 界面 - -## 通过2个步骤在本地添加 Pyroscope Server: -Pyroscope 支持所有主要的计算机架构,并且非常容易安装。作为例子,以下是在 Mac 上的安装方法: -```shell -# 安装 pyroscope -brew install pyroscope-io/brew/pyroscope - -# 启动 pyroscope server: -pyroscope server -``` - -## 通过 Pyroscope agent 发送数据到 server(特定语言) -关于如何将 Pyroscope agent 添加到你的代码中的更多信息,请参见我们网站上的[agent 文档](https://pyroscope.io/docs/agent-overview) 。 -- [Golang Agent](https://pyroscope.io/docs/golang) -- [Python Agent (pip)](https://pyroscope.io/docs/python) -- [Ruby Agent (gem)](https://pyroscope.io/docs/ruby) -- [eBPF Agent](https://pyroscope.io/docs/ebpf) -- [PHP Agent](https://pyroscope.io/docs/php) -- [.NET Agent](https://pyroscope.io/docs/dotnet) - -## 文档 - -关于如何在其他编程语言中使用 Pyroscope, 在 Linux 上安装它,或在生产环境中使用它的更多信息,请查看我们的文档。 - -* [公开的 Roadmap](https://github.com/pyroscope-io/pyroscope/projects/1) -* [入门文档](https://pyroscope.io/docs/) -* [部署指导](https://pyroscope.io/docs/deployment) -* [开发人员指导](https://pyroscope.io/docs/developer-guide) - - -## 部署示意图 - -![agent_server_diagram_10](https://user-images.githubusercontent.com/23323466/153685751-0aac3cd6-bbc1-4ab4-8350-8f4dc7f7c193.svg) - -## 下载 - -你可以从我们的 [下载页面](https://pyroscope.io/downloads/) 下载适用于macOS、linux和Docker的最新版本的 pyroscope。 - -## 已支持的集成 - -* [x] Ruby (通过 `rbspy`) -* [x] Python (通过 `py-spy`) -* [x] Go (通过 `pprof`) -* [x] Linux eBPF (通过`bcc-tools`的`profile.py`) -* [x] PHP (通过 `phpspy`) -* [x] .NET (通过 `dotnet trace`) -* [x] Java (通过 `async-profiler`) -* [ ] Node [(寻找贡献者)](https://github.com/pyroscope-io/pyroscope/issues/8) - - -你也可以在 [issue](https://github.com/pyroscope-io/pyroscope/issues?q=is%3Aissue+is%3Aopen+label%3Anew-profilers) 或者我们的 [slack](https://pyroscope.io/slack) 中来告诉我们你还想支持的平台。 - -## 鸣谢 - -Pyroscope 的出现要感谢许多人的出色工作,包括但不限于: - -* Brendan Gregg - Flame Graphs 的发明者 -* Julia Evans - rbspy 的创造者 - Ruby 的采样分析器 -* Vladimir Agafonkin --flamebearer的创造者 --快速火焰图的渲染器 -* Ben Frederickson - py-spy 的创造者 - Python 的采样分析器 -* Adam Saponara - phpspy 的创造者 - PHP 的抽样分析器 -* Alexei Starovoitov, Brendan Gregg, 和其他许多人,他们使 Linux 内核中基于 BPF 的剖析成为可能。 - - -## 贡献 - -在为我们贡献代码之前,请先查看我们的[贡献指南](../CONTRIBUTING.md)。 - - -### 感谢 Pyroscope 的贡献者! - -[//]: contributor-faces - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -[//]: contributor-faces diff --git a/og/translations/debug_python_with_pyroscope.ch.md b/og/translations/debug_python_with_pyroscope.ch.md deleted file mode 100644 index ffc418f0e0..0000000000 --- a/og/translations/debug_python_with_pyroscope.ch.md +++ /dev/null @@ -1,84 +0,0 @@ -# 如何使用性能分析来调试Python的性能问题 -## 使用火焰图找出问题根源 - -以本人经验来讲,在Python服务器上调试性能上的问题可令人沮丧。通常,流量的增加或暂时的故障都可能导致终端用户提交错误报告。 -通常,因为基本不可能复现故障场景,所以很难找出是哪一部分代码或者架构导致了服务器的性能问题。 -本文介绍如何使用火焰图持续剖析你的代码,并准确定位是哪些代码导致的性能问题。 - - -## 为什么你必须关心中央处理器性能 -通常公司使用云端(如AWS,谷歌云端等)运行软件时会将中央处理器的利用率作为程序性能的一个指标。 - -实际上,Netflix高级性能架构师Brendan Gregg提到过:如果,中央处理器利用率能下降1%就是一个很大的胜利,因为这样就能节省很多资源。不管怎样,较小的公司也可看到提升性能的好处。因为无论大小,在软件运行时,中央处理器时常与以下两个重要方面直接相关: -1.服务器的花费 : 所需的中央处理器资源越多,运行服务器的成本越高。 -2.终端用户经验 : 服务器的中央处理器负荷越大,网站或服务器的运行速度越慢。 - -因此,当你看到如下中央处理器利用率图表时: -![image](https://user-images.githubusercontent.com/23323466/105662478-aa40ce80-5e84-11eb-800a-57735c688fc9.png) - -在中央处理器利用率为100%,你可假设: -- 终端用户的经验并不好(如:应用程序/网站加载速度很慢) -- 配置新服务器处理额外负荷后,服务器成本将增加 - -关键是:**哪部分代码增加了中央处理器的利用率?** 火焰图这时就派上了用场! - -## 如何使用火焰图调试性能问题(并在服务器上节省下6.6万美元) -假设下面的火焰图对应呈现上图中央处理器利用率飙升的时段。在此高峰期间,服务器的中央处理器的使用情况如下: -- `foo()`消耗的时间是75% -- `bar()`消耗的时间是25% -- 10万美元的服务器成本 - -![pyro_python_blog_example_00-01](https://user-images.githubusercontent.com/23323466/105620812-75197b00-5db5-11eb-92af-33e356d9bb42.png) - -你可把火焰图视为超详细的饼图,其中: -- 火焰图的宽度代表着整个时段 -- 每个节点代表一个功能 -- 最大的节点占用了大部分中央处理器资源 -- 每个节点被其上方的节点调用 - -在这种情况下,`foo()`占据了整时间范围的75%,因此我们可以改进`foo()`及其调用的函数来减少中央处理器的利用率(并节省$$)。 - -## 用Pyroscope工具创建火焰图和表格 -为了用代码重现上文的例子,我们将使用Pyroscope工具 — 专门针对性能调试问题提供持续的性能分析,并且是开源。 -为了模拟服务器,我写了 `work(duration)` 函数,该函数在该持续时间段内模拟工作。这样,我们就可以通过下述代码构建火焰图,来复现`foo()` 所用的75%时间和 `bar()` 所用的25%时间: - - -foo_75_bar_25_minutes_30 - - -```python -# 模拟每次迭代中央处理器的时间 -def work(n): - i = 0 - while i < n: - i += 1 - -# 模拟中央处理器运行7.5秒 -def foo(): - work(75000) - -# 模拟中央处理器运行2.5秒 -def bar(): - work(25000) -``` -然后,假设你进行了代码优化,把 ‘foo()’ 的时间从75,000降到8000,但其它代码不变。新代码及火焰图所示如下: - -foo_25_bar_75_minutes_10 - -```python -# 模拟中央处理器运行0.8秒 -def foo(): - # work(75000) - work(8000) - -# T -def bar(): - work(25000) -``` -## 优化`foo()`为我们节省了6.6万美金 -火焰图帮助我们能立即发现`foo()`是我们代码中的瓶颈。进行优化之后,我们大幅降低中央处理器的利用率。 - -![image](https://user-images.githubusercontent.com/23323466/105666001-1a535280-5e8d-11eb-9407-c63955ba86a1.png) - - -这代表你的中央处理器的总利用率下降了66%。若你之前为了服务器支付10万美元,那现在只需要3.4万美元就能处理等量的负荷。 diff --git a/og/tsconfig.eslint.json b/og/tsconfig.eslint.json deleted file mode 100644 index 9a0d2e6013..0000000000 --- a/og/tsconfig.eslint.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["."], - // Since we excluded the test files in the main tsconfig.json - // We must renable them by explicitly setting an 'exclude' - "exclude": ["node_modules"] -} diff --git a/og/tsconfig.json b/og/tsconfig.json deleted file mode 100644 index 88375084e5..0000000000 --- a/og/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "jsx": "react", - "lib": ["dom", "esnext", "ES2015.Iterable"], - "module": "commonjs", - "moduleResolution": "node", - "esModuleInterop": true, - "sourceMap": true, - "allowSyntheticDefaultImports": true, - "skipLibCheck": true, - "paths": { - "@phlare/*": ["../public/app/*"], - }, - "types": ["node"], - "plugins": [{ "name": "typescript-plugin-css-modules" }], - "noImplicitAny": true, - "strictNullChecks": true, - "strict": true, - "resolveJsonModule": true - }, - // ts-node is currently only used by webpack - "ts-node": { - "compilerOptions": { - "module": "CommonJS" - } - }, - "include": ["./lib", "./webapp/javascript/"], - "exclude": [ - "webapp/javascript/**/*.spec.ts", - "webapp/javascript/**/*.spec.tsx", - "**/node_modules", - "**/.*/" - ] -} diff --git a/og/tsconfig.test.json b/og/tsconfig.test.json deleted file mode 100644 index 45c64b0de8..0000000000 --- a/og/tsconfig.test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "skipLibCheck": true, - "types": ["jest", "mocha", "@testing-library/jest-dom"], - "sourceMap": false - } -} diff --git a/og/webapp/.eslintrc.js b/og/webapp/.eslintrc.js deleted file mode 100644 index c30ea4cdb7..0000000000 --- a/og/webapp/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -const path = require('path'); - -module.exports = { - extends: [path.join(__dirname, '../.eslintrc.js')], - ignorePatterns: ['public', 'javascript/util', '*.spec.*', '.eslintrc.js'], - - rules: { - // https://github.com/import-js/eslint-plugin-import/issues/1650 - 'import/no-extraneous-dependencies': [ - 'error', - { - packageDir: [process.cwd(), path.resolve(__dirname, '../')], - }, - ], - // since we use immutablejs in the reducer - 'no-param-reassign': 'off', - }, - parserOptions: { - tsconfigRootDir: __dirname, - }, -}; diff --git a/og/webapp/CHANGELOG.md b/og/webapp/CHANGELOG.md deleted file mode 100644 index 8f2a562e4c..0000000000 --- a/og/webapp/CHANGELOG.md +++ /dev/null @@ -1,1481 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [1.68.22](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.21...@pyroscope/webapp@1.68.22) (2023-07-20) - -### Bug Fixes - -- limit time picker presets ([#2008](https://github.com/grafana/pyroscope/issues/2008)) ([56ec1d1](https://github.com/grafana/pyroscope/commit/56ec1d1e80f8d35a986c44ffba2e37e67908441e)) - -## [1.68.21](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.20...@pyroscope/webapp@1.68.21) (2023-06-21) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.20](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.19...@pyroscope/webapp@1.68.20) (2023-05-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.19](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.18...@pyroscope/webapp@1.68.19) (2023-05-24) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.18](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.17...@pyroscope/webapp@1.68.18) (2023-05-22) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.17](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.16...@pyroscope/webapp@1.68.17) (2023-04-24) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.16](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.15...@pyroscope/webapp@1.68.16) (2023-04-20) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.15](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.14...@pyroscope/webapp@1.68.15) (2023-04-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.14](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.13...@pyroscope/webapp@1.68.14) (2023-04-14) - -### Bug Fixes - -- **webapp:** only load timelines when both queries are set ([#1921](https://github.com/grafana/pyroscope/issues/1921)) ([dadec3e](https://github.com/grafana/pyroscope/commit/dadec3e8089f96b75a5e02fb14eca6c92ad99da5)) - -## [1.68.13](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.12...@pyroscope/webapp@1.68.13) (2023-04-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.12](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.11...@pyroscope/webapp@1.68.12) (2023-04-05) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.11](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.10...@pyroscope/webapp@1.68.11) (2023-03-29) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.10](https://github.com/grafana/pyroscope/compare/@pyroscope/webapp@1.68.9...@pyroscope/webapp@1.68.10) (2023-03-28) - -### Bug Fixes - -- **webapp:** fix heatmap y axis ([#1912](https://github.com/grafana/pyroscope/issues/1912)) ([7e3b651](https://github.com/grafana/pyroscope/commit/7e3b65165710937c10c2bbe128942da028a031dc)) - -## [1.68.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.8...@pyroscope/webapp@1.68.9) (2023-03-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.7...@pyroscope/webapp@1.68.8) (2023-03-14) - -### Bug Fixes - -- **flamegraph:** fix styling when in light mode ([#1889](https://github.com/pyroscope-io/pyroscope/issues/1889)) ([6bd54e2](https://github.com/pyroscope-io/pyroscope/commit/6bd54e2079bb622723844ce26c1ea3c8dc6a91c3)) - -## [1.68.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.6...@pyroscope/webapp@1.68.7) (2023-02-23) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.5...@pyroscope/webapp@1.68.6) (2023-02-22) - -### Bug Fixes - -- **webapp:** always render annotations in the viewport ([#1867](https://github.com/pyroscope-io/pyroscope/issues/1867)) ([2876881](https://github.com/pyroscope-io/pyroscope/commit/2876881a7204184668471b82fb8dab22509b7e7a)) - -## [1.68.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.4...@pyroscope/webapp@1.68.5) (2023-02-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.3...@pyroscope/webapp@1.68.4) (2023-02-07) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.2...@pyroscope/webapp@1.68.3) (2023-02-03) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.1...@pyroscope/webapp@1.68.2) (2023-01-23) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.68.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.68.0...@pyroscope/webapp@1.68.1) (2023-01-19) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.68.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.67.1...@pyroscope/webapp@1.68.0) (2023-01-18) - -### Features - -- **webapp:** sync crosshair in different timelines ([#1813](https://github.com/pyroscope-io/pyroscope/issues/1813)) ([e8f14bd](https://github.com/pyroscope-io/pyroscope/commit/e8f14bd79df15b099c4d45589ea22ed4e7297f95)) - -## [1.67.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.67.0...@pyroscope/webapp@1.67.1) (2023-01-16) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.67.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.21...@pyroscope/webapp@1.67.0) (2023-01-13) - -### Features - -- **webapp:** add annotations rendering to all timelines ([#1807](https://github.com/pyroscope-io/pyroscope/issues/1807)) ([6144df4](https://github.com/pyroscope-io/pyroscope/commit/6144df404e649c3bdf8460baf8d6da251752c074)) - -## [1.66.21](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.20...@pyroscope/webapp@1.66.21) (2023-01-10) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.20](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.19...@pyroscope/webapp@1.66.20) (2023-01-04) - -### Bug Fixes - -- **webapp:** make API table header match the actual content ([#1802](https://github.com/pyroscope-io/pyroscope/issues/1802)) ([3aac1df](https://github.com/pyroscope-io/pyroscope/commit/3aac1df0bb3dfdec0b38067923f2a4624e1eb11c)) - -## [1.66.19](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.18...@pyroscope/webapp@1.66.19) (2022-12-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.18](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.17...@pyroscope/webapp@1.66.18) (2022-12-02) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.17](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.16...@pyroscope/webapp@1.66.17) (2022-12-02) - -### Bug Fixes - -- **webapp:** timeline ticks overlapping ([#1786](https://github.com/pyroscope-io/pyroscope/issues/1786)) ([1a6b52d](https://github.com/pyroscope-io/pyroscope/commit/1a6b52d98dac60272ff5753542b7e9a598546dbd)) - -## [1.66.16](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.15...@pyroscope/webapp@1.66.16) (2022-12-02) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.15](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.14...@pyroscope/webapp@1.66.15) (2022-12-01) - -### Bug Fixes - -- tags loading ([#1784](https://github.com/pyroscope-io/pyroscope/issues/1784)) ([fb4fee8](https://github.com/pyroscope-io/pyroscope/commit/fb4fee858d749c61362c5a95c20fc0213d1e3a7c)) - -## [1.66.14](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.13...@pyroscope/webapp@1.66.14) (2022-12-01) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.13](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.12...@pyroscope/webapp@1.66.13) (2022-11-30) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.12](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.11...@pyroscope/webapp@1.66.12) (2022-11-30) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.11](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.10...@pyroscope/webapp@1.66.11) (2022-11-30) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.10](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.9...@pyroscope/webapp@1.66.10) (2022-11-30) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.8...@pyroscope/webapp@1.66.9) (2022-11-30) - -### Bug Fixes - -- update tag explorer dropdown ([#1772](https://github.com/pyroscope-io/pyroscope/issues/1772)) ([e04abd7](https://github.com/pyroscope-io/pyroscope/commit/e04abd7704861ac4bc0b7d0d9a420c37ab628a7a)) - -## [1.66.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.7...@pyroscope/webapp@1.66.8) (2022-11-29) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.6...@pyroscope/webapp@1.66.7) (2022-11-29) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.5...@pyroscope/webapp@1.66.6) (2022-11-29) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.4...@pyroscope/webapp@1.66.5) (2022-11-28) - -### Bug Fixes - -- move sandwich view message to correct location ([#1767](https://github.com/pyroscope-io/pyroscope/issues/1767)) ([6720c3f](https://github.com/pyroscope-io/pyroscope/commit/6720c3f2de303b25f2031d8c09bbb330561ddde4)) - -## [1.66.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.3...@pyroscope/webapp@1.66.4) (2022-11-28) - -### Bug Fixes - -- make table rows only take one line ([#1765](https://github.com/pyroscope-io/pyroscope/issues/1765)) ([6d33d42](https://github.com/pyroscope-io/pyroscope/commit/6d33d426b4f94833059fea5ca995bb5aa9dd022a)) - -## [1.66.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.2...@pyroscope/webapp@1.66.3) (2022-11-28) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.1...@pyroscope/webapp@1.66.2) (2022-11-28) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.66.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.66.0...@pyroscope/webapp@1.66.1) (2022-11-23) - -### Bug Fixes - -- **flamegraph:** fix dropdown menu opening ([#1755](https://github.com/pyroscope-io/pyroscope/issues/1755)) ([0b1acef](https://github.com/pyroscope-io/pyroscope/commit/0b1acef9c5d5a2a268f952a529d12f784d257842)) - -# [1.66.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.65.4...@pyroscope/webapp@1.66.0) (2022-11-22) - -### Features - -- **webapp:** add tooltip to main timeline in single view ([#1742](https://github.com/pyroscope-io/pyroscope/issues/1742)) ([508946c](https://github.com/pyroscope-io/pyroscope/commit/508946cf034d2f9aedae03c71429fc05d313897d)) - -## [1.65.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.65.3...@pyroscope/webapp@1.65.4) (2022-11-21) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.65.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.65.2...@pyroscope/webapp@1.65.3) (2022-11-21) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.65.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.65.1...@pyroscope/webapp@1.65.2) (2022-11-21) - -### Bug Fixes - -- tag explorer loading spinner ([#1748](https://github.com/pyroscope-io/pyroscope/issues/1748)) ([c1c83c2](https://github.com/pyroscope-io/pyroscope/commit/c1c83c290997b5b93e86ce7f7c29eaa49d809ee7)) - -## [1.65.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.65.0...@pyroscope/webapp@1.65.1) (2022-11-21) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.65.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.64.1...@pyroscope/webapp@1.65.0) (2022-11-19) - -### Features - -- make tag explorer modal adapt to content ([#1733](https://github.com/pyroscope-io/pyroscope/issues/1733)) ([7bdd8a4](https://github.com/pyroscope-io/pyroscope/commit/7bdd8a4f9ab79eeec0fa21afcf5db7c6dcb54fa0)) - -## [1.64.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.64.0...@pyroscope/webapp@1.64.1) (2022-11-18) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.64.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.63.1...@pyroscope/webapp@1.64.0) (2022-11-17) - -### Features - -- show percentages for diff table instead of absolute values ([#1697](https://github.com/pyroscope-io/pyroscope/issues/1697)) ([71efcb8](https://github.com/pyroscope-io/pyroscope/commit/71efcb868b14ff3771faa5858dd781eba0787bd8)) - -## [1.63.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.63.0...@pyroscope/webapp@1.63.1) (2022-11-17) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.63.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.62.1...@pyroscope/webapp@1.63.0) (2022-11-17) - -### Bug Fixes - -- tag explorer long tag overflow ([#1718](https://github.com/pyroscope-io/pyroscope/issues/1718)) ([b5ee72a](https://github.com/pyroscope-io/pyroscope/commit/b5ee72a651c00dae29e0651ba77e6c587f81c21f)) - -### Features - -- pie chart tooltip show units ([#1720](https://github.com/pyroscope-io/pyroscope/issues/1720)) ([8d5d658](https://github.com/pyroscope-io/pyroscope/commit/8d5d65869f8f66833b782e97e45261e460272beb)) -- **webapp:** filter out apps that are not cpu in exemplars page ([#1722](https://github.com/pyroscope-io/pyroscope/issues/1722)) ([100f943](https://github.com/pyroscope-io/pyroscope/commit/100f943d8b90e294de0ae076ae32f2a9846a1aa2)) - -## [1.62.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.62.0...@pyroscope/webapp@1.62.1) (2022-11-17) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.62.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.61.0...@pyroscope/webapp@1.62.0) (2022-11-16) - -### Features - -- **webapp:** render pie slice label as percent in tag explorer ([#1721](https://github.com/pyroscope-io/pyroscope/issues/1721)) ([79018aa](https://github.com/pyroscope-io/pyroscope/commit/79018aab7f5d089615c29b37a06a30cba237b522)) - -# [1.61.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.60.0...@pyroscope/webapp@1.61.0) (2022-11-16) - -### Features - -- **webapp:** Show top 10 items in Explore page ([#1663](https://github.com/pyroscope-io/pyroscope/issues/1663)) ([73544fb](https://github.com/pyroscope-io/pyroscope/commit/73544fb22f67bda9a27a0519a5b07c45523099a4)) - -# [1.60.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.59.1...@pyroscope/webapp@1.60.0) (2022-11-15) - -### Features - -- **webapp:** Add relative time period dropdown to comparison / diff view ([#1638](https://github.com/pyroscope-io/pyroscope/issues/1638)) ([23cf747](https://github.com/pyroscope-io/pyroscope/commit/23cf7474ec57c920dbc1f230cf3045fdc9a8b305)) - -## [1.59.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.59.0...@pyroscope/webapp@1.59.1) (2022-11-15) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.59.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.7...@pyroscope/webapp@1.59.0) (2022-11-15) - -### Features - -- **webapp:** Make explore page show precise numbers in table ([#1695](https://github.com/pyroscope-io/pyroscope/issues/1695)) ([5b47c71](https://github.com/pyroscope-io/pyroscope/commit/5b47c71b6a1e85c39b4ac21b1eaeddf85bad0d94)) - -## [1.58.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.6...@pyroscope/webapp@1.58.7) (2022-11-15) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.58.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.5...@pyroscope/webapp@1.58.6) (2022-11-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.58.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.4...@pyroscope/webapp@1.58.5) (2022-11-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.58.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.3...@pyroscope/webapp@1.58.4) (2022-11-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.58.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.2...@pyroscope/webapp@1.58.3) (2022-11-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.58.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.1...@pyroscope/webapp@1.58.2) (2022-11-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.58.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.58.0...@pyroscope/webapp@1.58.1) (2022-11-11) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.58.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.57.1...@pyroscope/webapp@1.58.0) (2022-11-10) - -### Features - -- **flamegraph:** Redesign flamegraph toolbar to allow for more interactions ([#1674](https://github.com/pyroscope-io/pyroscope/issues/1674)) ([646501a](https://github.com/pyroscope-io/pyroscope/commit/646501a3816df6f069454213ac7884198f35cd0b)) - -## [1.57.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.57.0...@pyroscope/webapp@1.57.1) (2022-11-10) - -### Bug Fixes - -- add TagsBar component to exemplars single view ([#1696](https://github.com/pyroscope-io/pyroscope/issues/1696)) ([8817502](https://github.com/pyroscope-io/pyroscope/commit/88175023c0db3756a726034b2ea7a5df32a3d25e)) -- heatmap y-axis value with "<" ([#1694](https://github.com/pyroscope-io/pyroscope/issues/1694)) ([76e5748](https://github.com/pyroscope-io/pyroscope/commit/76e574870829082a56963d82c2ede049bba743eb)) - -# [1.57.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.9...@pyroscope/webapp@1.57.0) (2022-11-09) - -### Features - -- add single, comparison, diff tabs to heatmap page ([#1672](https://github.com/pyroscope-io/pyroscope/issues/1672)) ([9afe5e5](https://github.com/pyroscope-io/pyroscope/commit/9afe5e564e1fea6fe4026c3180134412ac2930f9)) - -## [1.56.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.8...@pyroscope/webapp@1.56.9) (2022-11-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.56.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.7...@pyroscope/webapp@1.56.8) (2022-11-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.56.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.6...@pyroscope/webapp@1.56.7) (2022-11-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.56.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.5...@pyroscope/webapp@1.56.6) (2022-11-08) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.56.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.4...@pyroscope/webapp@1.56.5) (2022-11-08) - -### Bug Fixes - -- **webapp:** pass from,until when calling /label{-values} ([#1677](https://github.com/pyroscope-io/pyroscope/issues/1677)) ([a82077d](https://github.com/pyroscope-io/pyroscope/commit/a82077dd23148d839b75b46fb11b6b71492eec99)) - -## [1.56.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.3...@pyroscope/webapp@1.56.4) (2022-11-08) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.56.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.2...@pyroscope/webapp@1.56.3) (2022-11-07) - -### Bug Fixes - -- make oauth work when baseUrl is set ([#1673](https://github.com/pyroscope-io/pyroscope/issues/1673)) ([6cc1a2a](https://github.com/pyroscope-io/pyroscope/commit/6cc1a2a75387b0ca4a75ac57191a6a352a072a43)) - -## [1.56.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.1...@pyroscope/webapp@1.56.2) (2022-11-06) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.56.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.56.0...@pyroscope/webapp@1.56.1) (2022-11-06) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.56.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.55.1...@pyroscope/webapp@1.56.0) (2022-11-04) - -### Features - -- show gif when heatmap has no selection ([#1658](https://github.com/pyroscope-io/pyroscope/issues/1658)) ([2a3243d](https://github.com/pyroscope-io/pyroscope/commit/2a3243de46d27de5d9cbbc9f50dd1089ba517a5b)) - -## [1.55.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.55.0...@pyroscope/webapp@1.55.1) (2022-11-02) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.55.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.54.2...@pyroscope/webapp@1.55.0) (2022-11-02) - -### Features - -- **webapp:** [notifications] support 'warning' status and arbitrary jsx element ([#1656](https://github.com/pyroscope-io/pyroscope/issues/1656)) ([2ec2b07](https://github.com/pyroscope-io/pyroscope/commit/2ec2b073ffaf7699bdba9d1bc29b3fea8ef4b659)) - -## [1.54.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.54.1...@pyroscope/webapp@1.54.2) (2022-11-02) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.54.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.54.0...@pyroscope/webapp@1.54.1) (2022-11-01) - -### Bug Fixes - -- **webapp:** sort appNames alphabetically ([#1655](https://github.com/pyroscope-io/pyroscope/issues/1655)) ([e29d2e2](https://github.com/pyroscope-io/pyroscope/commit/e29d2e29862cf8e21354c194e67f2fd9e376e273)) - -# [1.54.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.53.0...@pyroscope/webapp@1.54.0) (2022-11-01) - -### Features - -- **webapp:** Issue when comparison / diff timelines are out of range ([#1615](https://github.com/pyroscope-io/pyroscope/issues/1615)) ([211ccca](https://github.com/pyroscope-io/pyroscope/commit/211ccca5a03fb78087bdf10b125ad0141b2a5dc9)) - -# [1.53.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.52.0...@pyroscope/webapp@1.53.0) (2022-11-01) - -### Features - -- add sandwich view for table/flamegraph ([#1613](https://github.com/pyroscope-io/pyroscope/issues/1613)) ([870c0b8](https://github.com/pyroscope-io/pyroscope/commit/870c0b8f209b7b669b407f6d3b5214876e671d69)) - -# [1.52.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.10...@pyroscope/webapp@1.52.0) (2022-10-31) - -### Bug Fixes - -- exemplars page shows weird y-axis numbers ([#1644](https://github.com/pyroscope-io/pyroscope/issues/1644)) ([c672ed7](https://github.com/pyroscope-io/pyroscope/commit/c672ed7d4ba601e3b9e45eaf328260f8f4c812ca)) - -### Features - -- add a generic Tooltip component ([#1643](https://github.com/pyroscope-io/pyroscope/issues/1643)) ([e04a9a5](https://github.com/pyroscope-io/pyroscope/commit/e04a9a5b8abacbf6c3fad87b1a8aaf2ed1636053)) -- **webapp:** Annotations flot plugin ([#1605](https://github.com/pyroscope-io/pyroscope/issues/1605)) ([fe80686](https://github.com/pyroscope-io/pyroscope/commit/fe80686837953a2f45aa8efc5a7d0a7c0efcc1a8)) - -## [1.51.10](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.9...@pyroscope/webapp@1.51.10) (2022-10-27) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.51.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.8...@pyroscope/webapp@1.51.9) (2022-10-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.51.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.7...@pyroscope/webapp@1.51.8) (2022-10-24) - -### Bug Fixes - -- **webapp:** make ui consistent when request is cancelled ([#1635](https://github.com/pyroscope-io/pyroscope/issues/1635)) ([d9b8290](https://github.com/pyroscope-io/pyroscope/commit/d9b8290a498fb658b206fc0d6253f6b206e21b9e)) - -## [1.51.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.6...@pyroscope/webapp@1.51.7) (2022-10-22) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.51.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.5...@pyroscope/webapp@1.51.6) (2022-10-21) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.51.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.4...@pyroscope/webapp@1.51.5) (2022-10-18) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.51.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.3...@pyroscope/webapp@1.51.4) (2022-10-14) - -### Bug Fixes - -- **webapp:** make app selector/timerange dropdowns to be above loading overlay ([#1618](https://github.com/pyroscope-io/pyroscope/issues/1618)) ([f4c8f17](https://github.com/pyroscope-io/pyroscope/commit/f4c8f1716e5a7352ddc4387dbf5613964ccd64e9)) - -## [1.51.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.2...@pyroscope/webapp@1.51.3) (2022-10-13) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.51.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.1...@pyroscope/webapp@1.51.2) (2022-10-09) - -### Bug Fixes - -- make adhoc table fit width ([#1591](https://github.com/pyroscope-io/pyroscope/issues/1591)) ([da74fe8](https://github.com/pyroscope-io/pyroscope/commit/da74fe896536b97911d9cf00a9288c64dda77a28)) - -## [1.51.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.51.0...@pyroscope/webapp@1.51.1) (2022-10-05) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.51.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.50.1...@pyroscope/webapp@1.51.0) (2022-10-04) - -### Features - -- add sorting to explore view table ([#1592](https://github.com/pyroscope-io/pyroscope/issues/1592)) ([64bc4b3](https://github.com/pyroscope-io/pyroscope/commit/64bc4b3ffaaa72ac01513093a74919c3389c45af)) - -## [1.50.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.50.0...@pyroscope/webapp@1.50.1) (2022-10-04) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.50.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.49.2...@pyroscope/webapp@1.50.0) (2022-10-03) - -### Features - -- Add count and latency to heatmap tooltip ([#1582](https://github.com/pyroscope-io/pyroscope/issues/1582)) ([4590901](https://github.com/pyroscope-io/pyroscope/commit/459090179b623e5f40d7c31bbfb1bae8c4e9146f)) - -## [1.49.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.49.1...@pyroscope/webapp@1.49.2) (2022-09-30) - -### Bug Fixes - -- export dropdown should close when clicking outside ([#1579](https://github.com/pyroscope-io/pyroscope/issues/1579)) ([b4074a7](https://github.com/pyroscope-io/pyroscope/commit/b4074a72f0482cd59e53960ce0ba437052475b50)) -- tag explorer modal should close when another one is clicked ([#1578](https://github.com/pyroscope-io/pyroscope/issues/1578)) ([c2d1e96](https://github.com/pyroscope-io/pyroscope/commit/c2d1e966e33aed1d483bcabdbfc05a545518a302)) - -## [1.49.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.49.0...@pyroscope/webapp@1.49.1) (2022-09-30) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.49.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.48.0...@pyroscope/webapp@1.49.0) (2022-09-29) - -### Features - -- change color of the selected area of the heatmap ([#1572](https://github.com/pyroscope-io/pyroscope/issues/1572)) ([9ebdded](https://github.com/pyroscope-io/pyroscope/commit/9ebdded1524684f405ad79a5100cde52a2548a0a)) - -# [1.48.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.47.0...@pyroscope/webapp@1.48.0) (2022-09-29) - -### Features - -- show heatmap y-axis units ([#1559](https://github.com/pyroscope-io/pyroscope/issues/1559)) ([8199170](https://github.com/pyroscope-io/pyroscope/commit/81991706e0ba6767da9d9fdefcd89a65f527722a)) - -# [1.47.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.46.0...@pyroscope/webapp@1.47.0) (2022-09-29) - -### Features - -- add table view to heatmap flamegraph ([#1574](https://github.com/pyroscope-io/pyroscope/issues/1574)) ([e55cc8a](https://github.com/pyroscope-io/pyroscope/commit/e55cc8aff22c863d8aab6395c1b895aee1c46278)) - -# [1.46.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.45.0...@pyroscope/webapp@1.46.0) (2022-09-29) - -### Features - -- add "Count" title above heatmap scale ([#1571](https://github.com/pyroscope-io/pyroscope/issues/1571)) ([910c496](https://github.com/pyroscope-io/pyroscope/commit/910c496a88c81d03efdc91548c4365dcff3a670a)) -- Heatmap should show error message if no data is returned ([#1565](https://github.com/pyroscope-io/pyroscope/issues/1565)) ([fe32a07](https://github.com/pyroscope-io/pyroscope/commit/fe32a07e6e1bf05b11a6634f6eea0b44bf8b0536)) - -# [1.45.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.44.0...@pyroscope/webapp@1.45.0) (2022-09-29) - -### Features - -- add ticks to x and y-axis ([#1558](https://github.com/pyroscope-io/pyroscope/issues/1558)) ([4a3e140](https://github.com/pyroscope-io/pyroscope/commit/4a3e1402ff1f117f3a806e4ef4cae456fe60c336)) - -# [1.44.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.7...@pyroscope/webapp@1.44.0) (2022-09-28) - -### Features - -- remove heatmap grid ([#1567](https://github.com/pyroscope-io/pyroscope/issues/1567)) ([541133b](https://github.com/pyroscope-io/pyroscope/commit/541133b54d7d10cde0c3815c17077e4e2de1109d)) - -## [1.43.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.6...@pyroscope/webapp@1.43.7) (2022-09-27) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.43.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.5...@pyroscope/webapp@1.43.6) (2022-09-26) - -### Bug Fixes - -- heatmap bug fixes ([#1545](https://github.com/pyroscope-io/pyroscope/issues/1545)) ([3218c62](https://github.com/pyroscope-io/pyroscope/commit/3218c6295383fa608bfe6fed40501949d1189708)) - -## [1.43.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.4...@pyroscope/webapp@1.43.5) (2022-09-26) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.43.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.3...@pyroscope/webapp@1.43.4) (2022-09-26) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.43.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.2...@pyroscope/webapp@1.43.3) (2022-09-26) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.43.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.1...@pyroscope/webapp@1.43.2) (2022-09-23) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.43.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.43.0...@pyroscope/webapp@1.43.1) (2022-09-22) - -### Bug Fixes - -- **webapp:** don't render popover outside the visible window ([#1534](https://github.com/pyroscope-io/pyroscope/issues/1534)) ([0ce4e7d](https://github.com/pyroscope-io/pyroscope/commit/0ce4e7de968bb3e919fab0dcd7394350eb4716b5)) - -# [1.43.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.42.4...@pyroscope/webapp@1.43.0) (2022-09-22) - -### Features - -- **webapp:** create annotations via ui ([#1524](https://github.com/pyroscope-io/pyroscope/issues/1524)) ([53836ce](https://github.com/pyroscope-io/pyroscope/commit/53836ce6b2f4a5eb2debc6a2e03c0b39812bf488)) - -## [1.42.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.42.3...@pyroscope/webapp@1.42.4) (2022-09-19) - -### Bug Fixes - -- **webapp:** format annotation using timezone ([#1522](https://github.com/pyroscope-io/pyroscope/issues/1522)) ([bc68da3](https://github.com/pyroscope-io/pyroscope/commit/bc68da3757154656fe8a799a8170928686305f68)) - -## [1.42.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.42.2...@pyroscope/webapp@1.42.3) (2022-09-16) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.42.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.42.1...@pyroscope/webapp@1.42.2) (2022-09-16) - -### Bug Fixes - -- **webapp:** show annotations tooltip only when hovering close to the marker ([#1510](https://github.com/pyroscope-io/pyroscope/issues/1510)) ([e8bdf4a](https://github.com/pyroscope-io/pyroscope/commit/e8bdf4abbff10efcdc317aea09d45ecd795e2f42)) - -## [1.42.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.42.0...@pyroscope/webapp@1.42.1) (2022-09-16) - -### Bug Fixes - -- **webapp:** annotation doesn't have a weird marking anymore ([#1512](https://github.com/pyroscope-io/pyroscope/issues/1512)) ([20abd58](https://github.com/pyroscope-io/pyroscope/commit/20abd58350a0fd729ac13cb2537c1f7b424178c8)) - -# [1.42.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.41.0...@pyroscope/webapp@1.42.0) (2022-09-15) - -### Features - -- **webapp:** annotations UI ([#1489](https://github.com/pyroscope-io/pyroscope/issues/1489)) ([0e57137](https://github.com/pyroscope-io/pyroscope/commit/0e571379e1bb4f99bfdb9c3a22d1b2827128e3a5)) - -# [1.41.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.40.1...@pyroscope/webapp@1.41.0) (2022-09-15) - -### Features - -- heatmap improvements ([#1501](https://github.com/pyroscope-io/pyroscope/issues/1501)) ([e9e5bfd](https://github.com/pyroscope-io/pyroscope/commit/e9e5bfdd1e93efaa0428d0a2d3803652d8c7b083)) - -## [1.40.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.40.0...@pyroscope/webapp@1.40.1) (2022-09-14) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.40.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.39.1...@pyroscope/webapp@1.40.0) (2022-09-14) - -### Features - -- **webapp:** Add Explore Page piechart ([#1477](https://github.com/pyroscope-io/pyroscope/issues/1477)) ([c421b42](https://github.com/pyroscope-io/pyroscope/commit/c421b4225baaa7543b22185c3b26fcf48a60a024)) - -## [1.39.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.39.0...@pyroscope/webapp@1.39.1) (2022-09-13) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.39.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.38.6...@pyroscope/webapp@1.39.0) (2022-09-13) - -### Features - -- **webapp:** Add tracing page with heatmap ([#1433](https://github.com/pyroscope-io/pyroscope/issues/1433)) ([587379a](https://github.com/pyroscope-io/pyroscope/commit/587379aa5067521f38bc892c364ccff6e1d35b28)) - -## [1.38.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.38.5...@pyroscope/webapp@1.38.6) (2022-09-13) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.38.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.38.4...@pyroscope/webapp@1.38.5) (2022-09-13) - -### Bug Fixes - -- **webapp:** CollapseBox overflow ([#1490](https://github.com/pyroscope-io/pyroscope/issues/1490)) ([0af9f1d](https://github.com/pyroscope-io/pyroscope/commit/0af9f1d0ec3f18f2b4cb366eb0b8afda3e2e8de5)) - -## [1.38.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.38.3...@pyroscope/webapp@1.38.4) (2022-09-12) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.38.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.38.2...@pyroscope/webapp@1.38.3) (2022-09-12) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.38.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.38.1...@pyroscope/webapp@1.38.2) (2022-09-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.38.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.38.0...@pyroscope/webapp@1.38.1) (2022-09-11) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.38.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.37.4...@pyroscope/webapp@1.38.0) (2022-09-09) - -### Features - -- **webapp:** Add component ([#1474](https://github.com/pyroscope-io/pyroscope/issues/1474)) ([6595794](https://github.com/pyroscope-io/pyroscope/commit/659579448bdf3e32a77f047aceffa01108d784b3)) - -## [1.37.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.37.3...@pyroscope/webapp@1.37.4) (2022-09-08) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.37.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.37.2...@pyroscope/webapp@1.37.3) (2022-09-08) - -### Bug Fixes - -- **webapp:** hide tooltip if there's no data ([#1472](https://github.com/pyroscope-io/pyroscope/issues/1472)) ([df4c8cc](https://github.com/pyroscope-io/pyroscope/commit/df4c8cc360877b7100d987513beae905bc735a74)) - -## [1.37.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.37.1...@pyroscope/webapp@1.37.2) (2022-09-06) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.37.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.37.0...@pyroscope/webapp@1.37.1) (2022-09-06) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.37.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.36.3...@pyroscope/webapp@1.37.0) (2022-09-06) - -### Features - -- **webapp:** Add tooltip in explore timeline ([#1422](https://github.com/pyroscope-io/pyroscope/issues/1422)) ([b5ce89a](https://github.com/pyroscope-io/pyroscope/commit/b5ce89a680256a7d6ff76e45ec38abc721df9a89)) - -## [1.36.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.36.2...@pyroscope/webapp@1.36.3) (2022-09-06) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.36.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.36.1...@pyroscope/webapp@1.36.2) (2022-09-06) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.36.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.36.0...@pyroscope/webapp@1.36.1) (2022-09-05) - -### Bug Fixes - -- **flamegraph:** table, buttons colors for light mode ([#1458](https://github.com/pyroscope-io/pyroscope/issues/1458)) ([37afd3b](https://github.com/pyroscope-io/pyroscope/commit/37afd3bbdad6b9165143b92dd2312d6b125140f4)) - -# [1.36.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.35.3...@pyroscope/webapp@1.36.0) (2022-09-02) - -### Features - -- **webapp:** display timer for notifications ([#1457](https://github.com/pyroscope-io/pyroscope/issues/1457)) ([b158f38](https://github.com/pyroscope-io/pyroscope/commit/b158f38592b0b1df9c9c1ff025577175075b897e)) - -## [1.35.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.35.2...@pyroscope/webapp@1.35.3) (2022-08-31) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.35.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.35.1...@pyroscope/webapp@1.35.2) (2022-08-31) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.35.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.35.0...@pyroscope/webapp@1.35.1) (2022-08-30) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.35.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.34.1...@pyroscope/webapp@1.35.0) (2022-08-30) - -### Features - -- **webapp:** dropdown component for head-first dropdown ([#1435](https://github.com/pyroscope-io/pyroscope/issues/1435)) ([a7d6891](https://github.com/pyroscope-io/pyroscope/commit/a7d6891c8b63d67dc197d7c52812bd946ca688e5)) - -## [1.34.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.34.0...@pyroscope/webapp@1.34.1) (2022-08-26) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.34.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.7...@pyroscope/webapp@1.34.0) (2022-08-24) - -### Features - -- **webapp:** Add settings/apps page ([#1424](https://github.com/pyroscope-io/pyroscope/issues/1424)) ([f87ce69](https://github.com/pyroscope-io/pyroscope/commit/f87ce69d8af890402d5845f7d3047e393682c934)) - -## [1.33.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.6...@pyroscope/webapp@1.33.7) (2022-08-22) - -### Bug Fixes - -- **webapp:** fixes auth ([#1434](https://github.com/pyroscope-io/pyroscope/issues/1434)) ([a70ca26](https://github.com/pyroscope-io/pyroscope/commit/a70ca269eb02983248d34b46bc9bbd9c596a0da6)) - -## [1.33.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.5...@pyroscope/webapp@1.33.6) (2022-08-22) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.33.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.4...@pyroscope/webapp@1.33.5) (2022-08-22) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.33.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.3...@pyroscope/webapp@1.33.4) (2022-08-19) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.33.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.2...@pyroscope/webapp@1.33.3) (2022-08-19) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.33.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.1...@pyroscope/webapp@1.33.2) (2022-08-18) - -### Bug Fixes - -- **webapp:** return empty string when range doesn't make sense ([#1419](https://github.com/pyroscope-io/pyroscope/issues/1419)) ([6f69c6f](https://github.com/pyroscope-io/pyroscope/commit/6f69c6f5209a12e1d8c54e962fcba6dc373bd7ff)) - -## [1.33.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.33.0...@pyroscope/webapp@1.33.1) (2022-08-17) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.33.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.32.3...@pyroscope/webapp@1.33.0) (2022-08-17) - -### Features - -- reuse Table component everywhere ([#1403](https://github.com/pyroscope-io/pyroscope/issues/1403)) ([a79f61b](https://github.com/pyroscope-io/pyroscope/commit/a79f61b39d8ae5b199710e79dc05e9352044b3b4)) - -## [1.32.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.32.2...@pyroscope/webapp@1.32.3) (2022-08-17) - -### Bug Fixes - -- Add different color palette for Explore Timeline ([#1399](https://github.com/pyroscope-io/pyroscope/issues/1399)) ([5e129e0](https://github.com/pyroscope-io/pyroscope/commit/5e129e0552422ca3b36c85153248c1d8278fc0de)) - -## [1.32.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.32.1...@pyroscope/webapp@1.32.2) (2022-08-16) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.32.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.32.0...@pyroscope/webapp@1.32.1) (2022-08-16) - -### Bug Fixes - -- **webapp:** refresh data when (re)submitting query ([#1410](https://github.com/pyroscope-io/pyroscope/issues/1410)) ([3554f84](https://github.com/pyroscope-io/pyroscope/commit/3554f84060ab54836e9ae1f2b49f9174c3e66041)), closes [#1406](https://github.com/pyroscope-io/pyroscope/issues/1406) - -# [1.32.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.31.1...@pyroscope/webapp@1.32.0) (2022-08-16) - -### Features - -- **webapp:** set title automatically ([#1397](https://github.com/pyroscope-io/pyroscope/issues/1397)) ([74821ca](https://github.com/pyroscope-io/pyroscope/commit/74821ca0f0e3ebec38c83f83bf54318d931f66f6)) - -## [1.31.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.31.0...@pyroscope/webapp@1.31.1) (2022-08-15) - -### Bug Fixes - -- **flamegraph:** fix its styling ([#1388](https://github.com/pyroscope-io/pyroscope/issues/1388)) ([5788cf9](https://github.com/pyroscope-io/pyroscope/commit/5788cf9943a579acd35de224537016488a98808f)) - -# [1.31.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.30.1...@pyroscope/webapp@1.31.0) (2022-08-12) - -### Features - -- support high number of series in explore view timeline ([#1384](https://github.com/pyroscope-io/pyroscope/issues/1384)) ([482e23e](https://github.com/pyroscope-io/pyroscope/commit/482e23e52f006a201e40a2b4ff6092e0f246aa03)) - -## [1.30.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.30.0...@pyroscope/webapp@1.30.1) (2022-08-12) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.30.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.29.4...@pyroscope/webapp@1.30.0) (2022-08-12) - -### Features - -- **webapp:** update timeline appearance and refactor flot plugins ([#1323](https://github.com/pyroscope-io/pyroscope/issues/1323)) ([9393449](https://github.com/pyroscope-io/pyroscope/commit/9393449fdabd0cb38c4fae87b3ba0ce73251b41d)) - -## [1.29.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.29.3...@pyroscope/webapp@1.29.4) (2022-08-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.29.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.29.2...@pyroscope/webapp@1.29.3) (2022-08-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.29.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.29.1...@pyroscope/webapp@1.29.2) (2022-08-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.29.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.29.0...@pyroscope/webapp@1.29.1) (2022-08-09) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.29.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.28.1...@pyroscope/webapp@1.29.0) (2022-08-08) - -### Features - -- add ProfilerTable arrow color ([#1366](https://github.com/pyroscope-io/pyroscope/issues/1366)) ([be3901d](https://github.com/pyroscope-io/pyroscope/commit/be3901da82fe1fbed54171938f2bef638819319b)) - -## [1.28.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.28.0...@pyroscope/webapp@1.28.1) (2022-08-08) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.28.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.27.1...@pyroscope/webapp@1.28.0) (2022-08-08) - -### Features - -- add loader to tag exlorer page ([#1368](https://github.com/pyroscope-io/pyroscope/issues/1368)) ([16a727d](https://github.com/pyroscope-io/pyroscope/commit/16a727d5f51847114fe360eb70aff1bf9bfd3a9e)) - -## [1.27.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.27.0...@pyroscope/webapp@1.27.1) (2022-08-08) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.27.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.26.0...@pyroscope/webapp@1.27.0) (2022-08-05) - -### Features - -- **webapp:** break adhoc ui upload into 2 steps ([#1352](https://github.com/pyroscope-io/pyroscope/issues/1352)) ([9c15298](https://github.com/pyroscope-io/pyroscope/commit/9c15298251048e06a96f738b85f2915326c44f25)) - -# [1.26.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.25.0...@pyroscope/webapp@1.26.0) (2022-08-05) - -### Features - -- enhance tag explorer view ([#1329](https://github.com/pyroscope-io/pyroscope/issues/1329)) ([7d66d75](https://github.com/pyroscope-io/pyroscope/commit/7d66d750ba68d27a5046751221dd51d465a08488)) - -# [1.25.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.24.5...@pyroscope/webapp@1.25.0) (2022-08-05) - -### Features - -- **webapp:** persist uploaded data via adhoc ui ([#1351](https://github.com/pyroscope-io/pyroscope/issues/1351)) ([cebefc9](https://github.com/pyroscope-io/pyroscope/commit/cebefc94305ffb98467261b24eb6c65ca5e1a18c)) - -## [1.24.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.24.4...@pyroscope/webapp@1.24.5) (2022-08-05) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.24.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.24.3...@pyroscope/webapp@1.24.4) (2022-08-05) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.24.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.24.2...@pyroscope/webapp@1.24.3) (2022-08-04) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.24.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.24.1...@pyroscope/webapp@1.24.2) (2022-08-03) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.24.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.24.0...@pyroscope/webapp@1.24.1) (2022-08-03) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.24.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.23.0...@pyroscope/webapp@1.24.0) (2022-08-03) - -### Features - -- add app dropdown footer ([#1340](https://github.com/pyroscope-io/pyroscope/issues/1340)) ([dc07d04](https://github.com/pyroscope-io/pyroscope/commit/dc07d04e28cdd821829eaf211a8543723b3956aa)) - -# [1.23.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.22.0...@pyroscope/webapp@1.23.0) (2022-08-03) - -### Features - -- upload any arbitrary data (collapsed/pprof/json) via adhoc ui ([#1327](https://github.com/pyroscope-io/pyroscope/issues/1327)) ([6620888](https://github.com/pyroscope-io/pyroscope/commit/662088820b430abb2e4dcb9270cbaf62771ca601)), closes [#1333](https://github.com/pyroscope-io/pyroscope/issues/1333) [#1333](https://github.com/pyroscope-io/pyroscope/issues/1333) - -# [1.22.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.15...@pyroscope/webapp@1.22.0) (2022-07-29) - -### Features - -- create tag-explorer page for analyzing tag breakdowns ([#1293](https://github.com/pyroscope-io/pyroscope/issues/1293)) ([5456a86](https://github.com/pyroscope-io/pyroscope/commit/5456a866cfa6b3800fb7d359ff55032a84129138)) - -## [1.21.15](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.14...@pyroscope/webapp@1.21.15) (2022-07-27) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.14](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.13...@pyroscope/webapp@1.21.14) (2022-07-26) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.13](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.12...@pyroscope/webapp@1.21.13) (2022-07-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.12](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.11...@pyroscope/webapp@1.21.12) (2022-07-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.11](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.10...@pyroscope/webapp@1.21.11) (2022-07-20) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.10](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.9...@pyroscope/webapp@1.21.10) (2022-07-20) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.8...@pyroscope/webapp@1.21.9) (2022-07-20) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.7...@pyroscope/webapp@1.21.8) (2022-07-19) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.6...@pyroscope/webapp@1.21.7) (2022-07-19) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.5...@pyroscope/webapp@1.21.6) (2022-07-18) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.4...@pyroscope/webapp@1.21.5) (2022-07-18) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.3...@pyroscope/webapp@1.21.4) (2022-07-18) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.2...@pyroscope/webapp@1.21.3) (2022-07-15) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.1...@pyroscope/webapp@1.21.2) (2022-07-15) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.21.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.21.0...@pyroscope/webapp@1.21.1) (2022-07-15) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.21.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.20.0...@pyroscope/webapp@1.21.0) (2022-07-15) - -### Features - -- update right-click context menu ([#1259](https://github.com/pyroscope-io/pyroscope/issues/1259)) ([8aea02f](https://github.com/pyroscope-io/pyroscope/commit/8aea02f56320daacfd753d73db6936dcc7cdaef8)) - -# [1.20.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.19.3...@pyroscope/webapp@1.20.0) (2022-07-13) - -### Features - -- add new tooltip design ([#1246](https://github.com/pyroscope-io/pyroscope/issues/1246)) ([8345168](https://github.com/pyroscope-io/pyroscope/commit/83451683d131671771b0e97e052068b08bfe35bd)) - -## [1.19.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.19.2...@pyroscope/webapp@1.19.3) (2022-07-13) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.19.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.19.1...@pyroscope/webapp@1.19.2) (2022-07-13) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.19.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.19.0...@pyroscope/webapp@1.19.1) (2022-07-13) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.19.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.18.5...@pyroscope/webapp@1.19.0) (2022-07-13) - -### Features - -- adds support for group-by queries on the backend ([#1244](https://github.com/pyroscope-io/pyroscope/issues/1244)) ([c52f0e4](https://github.com/pyroscope-io/pyroscope/commit/c52f0e4fdc08feced533d60b9daf0c21c565381c)) - -## [1.18.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.18.4...@pyroscope/webapp@1.18.5) (2022-07-12) - -### Bug Fixes - -- **frontend:** fix latest version checks ([#1243](https://github.com/pyroscope-io/pyroscope/issues/1243)) ([293078a](https://github.com/pyroscope-io/pyroscope/commit/293078a1bf6e8b8aa0a7e436faaa77bacaaa4b56)) - -## [1.18.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.18.3...@pyroscope/webapp@1.18.4) (2022-07-12) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.18.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.18.2...@pyroscope/webapp@1.18.3) (2022-07-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.18.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.18.1...@pyroscope/webapp@1.18.2) (2022-07-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.18.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.18.0...@pyroscope/webapp@1.18.1) (2022-07-11) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.18.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.17.5...@pyroscope/webapp@1.18.0) (2022-07-11) - -### Features - -- **flamegraph:** Add support for visualizing traces ([#1233](https://github.com/pyroscope-io/pyroscope/issues/1233)) ([b15d094](https://github.com/pyroscope-io/pyroscope/commit/b15d094ebb06592a406b4b73485c0f316c411b08)) - -## [1.17.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.17.4...@pyroscope/webapp@1.17.5) (2022-07-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.17.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.17.3...@pyroscope/webapp@1.17.4) (2022-07-07) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.17.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.17.2...@pyroscope/webapp@1.17.3) (2022-07-06) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.17.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.17.1...@pyroscope/webapp@1.17.2) (2022-07-06) - -### Bug Fixes - -- add sidebar separation lines ([#1216](https://github.com/pyroscope-io/pyroscope/issues/1216)) ([9efc566](https://github.com/pyroscope-io/pyroscope/commit/9efc5666f699a22b6759a326fa663bfe1bd072e3)) - -## [1.17.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.17.0...@pyroscope/webapp@1.17.1) (2022-07-06) - -### Bug Fixes - -- single view app update should change comp/diff view left and right apps ([#1211](https://github.com/pyroscope-io/pyroscope/issues/1211)) ([9a4f34d](https://github.com/pyroscope-io/pyroscope/commit/9a4f34d29090dea456de3014ce2a491e7da83f11)) - -# [1.17.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.16.0...@pyroscope/webapp@1.17.0) (2022-07-06) - -### Features - -- **webapp:** new app selector ([#1199](https://github.com/pyroscope-io/pyroscope/issues/1199)) ([d671810](https://github.com/pyroscope-io/pyroscope/commit/d6718109bc307191b7e44e0fd0c072958d5e0cc2)) - -# [1.16.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.15.1...@pyroscope/webapp@1.16.0) (2022-07-06) - -### Features - -- add titles to charts / flamegraphs ([#1208](https://github.com/pyroscope-io/pyroscope/issues/1208)) ([836fa97](https://github.com/pyroscope-io/pyroscope/commit/836fa97f126f8b7ebfb966bb52a97b5bdf179d83)) - -## [1.15.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.15.0...@pyroscope/webapp@1.15.1) (2022-07-05) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.15.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.14.0...@pyroscope/webapp@1.15.0) (2022-07-05) - -### Features - -- add an explanation for what each API Key Role is for ([#1210](https://github.com/pyroscope-io/pyroscope/issues/1210)) ([88e04f3](https://github.com/pyroscope-io/pyroscope/commit/88e04f34ed99327fbc95b713c2866968e35684d0)) - -# [1.14.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.13.6...@pyroscope/webapp@1.14.0) (2022-07-05) - -### Features - -- support for micro-, milli-, and nanoseconds ([#1209](https://github.com/pyroscope-io/pyroscope/issues/1209)) ([f1ba768](https://github.com/pyroscope-io/pyroscope/commit/f1ba76848163506a043ec3321a25052f66161bb9)) - -## [1.13.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.13.5...@pyroscope/webapp@1.13.6) (2022-07-04) - -### Bug Fixes - -- colors on login pages ([#1197](https://github.com/pyroscope-io/pyroscope/issues/1197)) ([a6b2b22](https://github.com/pyroscope-io/pyroscope/commit/a6b2b2275a21bd0f82dc8d4c62eeb34c80da9e3f)) - -## [1.13.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.13.4...@pyroscope/webapp@1.13.5) (2022-07-01) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.13.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.13.3...@pyroscope/webapp@1.13.4) (2022-07-01) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.13.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.13.2...@pyroscope/webapp@1.13.3) (2022-06-30) - -### Bug Fixes - -- default name when exporting diff ([#1195](https://github.com/pyroscope-io/pyroscope/issues/1195)) ([c8e9b79](https://github.com/pyroscope-io/pyroscope/commit/c8e9b79405be23a760260f40d0e594b8c484f165)) - -## [1.13.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.13.1...@pyroscope/webapp@1.13.2) (2022-06-30) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.13.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.13.0...@pyroscope/webapp@1.13.1) (2022-06-30) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.13.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.12.2...@pyroscope/webapp@1.13.0) (2022-06-29) - -### Features - -- **frontend:** support disabling exporting to flamegraph.com ([#1188](https://github.com/pyroscope-io/pyroscope/issues/1188)) ([cd48732](https://github.com/pyroscope-io/pyroscope/commit/cd48732bb28dfab903ef00799f2bacdb6d991e0d)) - -## [1.12.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.12.1...@pyroscope/webapp@1.12.2) (2022-06-29) - -### Bug Fixes - -- adhoc/diff-view data table initial render ([#1190](https://github.com/pyroscope-io/pyroscope/issues/1190)) ([b03794c](https://github.com/pyroscope-io/pyroscope/commit/b03794cdad8873685cca734dc287c546442bec99)) - -## [1.12.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.12.0...@pyroscope/webapp@1.12.1) (2022-06-29) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.12.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.8...@pyroscope/webapp@1.12.0) (2022-06-29) - -### Features - -- add adhoc sort by date ([#1187](https://github.com/pyroscope-io/pyroscope/issues/1187)) ([206d2c6](https://github.com/pyroscope-io/pyroscope/commit/206d2c6a6e35d30d85f35a0103b8fb0d71b8c0f5)) - -## [1.11.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.7...@pyroscope/webapp@1.11.8) (2022-06-29) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.11.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.6...@pyroscope/webapp@1.11.7) (2022-06-28) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.11.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.5...@pyroscope/webapp@1.11.6) (2022-06-27) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.11.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.4...@pyroscope/webapp@1.11.5) (2022-06-20) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.11.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.3...@pyroscope/webapp@1.11.4) (2022-06-13) - -### Bug Fixes - -- Fix missed style in tags submenu ([#1154](https://github.com/pyroscope-io/pyroscope/issues/1154)) ([006771b](https://github.com/pyroscope-io/pyroscope/commit/006771b4fa541289b1dec180e477ce3130e8ffd8)) - -## [1.11.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.2...@pyroscope/webapp@1.11.3) (2022-06-12) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.11.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.1...@pyroscope/webapp@1.11.2) (2022-06-10) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.11.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.11.0...@pyroscope/webapp@1.11.1) (2022-06-10) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.11.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.10.4...@pyroscope/webapp@1.11.0) (2022-06-09) - -### Features - -- Add Ability to Sync Search Bar in Comparison View ([#1120](https://github.com/pyroscope-io/pyroscope/issues/1120)) ([8300792](https://github.com/pyroscope-io/pyroscope/commit/830079299cef97db33d26ada31cbdccbc00e3268)) - -## [1.10.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.10.3...@pyroscope/webapp@1.10.4) (2022-06-08) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.10.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.10.2...@pyroscope/webapp@1.10.3) (2022-06-06) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.10.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.10.1...@pyroscope/webapp@1.10.2) (2022-06-06) - -### Bug Fixes - -- **webapp:** fix border of element ([#1127](https://github.com/pyroscope-io/pyroscope/issues/1127)) ([458b62b](https://github.com/pyroscope-io/pyroscope/commit/458b62bcbd50ecc612636565c6dfe821b395fd87)) - -## [1.10.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.10.0...@pyroscope/webapp@1.10.1) (2022-06-06) - -### Bug Fixes - -- infinite loop when no apps are available ([#1125](https://github.com/pyroscope-io/pyroscope/issues/1125)) ([330eb23](https://github.com/pyroscope-io/pyroscope/commit/330eb234a1f2b7b3de4b36f862729180462262ce)) - -# [1.10.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.9.0...@pyroscope/webapp@1.10.0) (2022-06-01) - -### Features - -- UTC timezone ([#1107](https://github.com/pyroscope-io/pyroscope/issues/1107)) ([9fa550c](https://github.com/pyroscope-io/pyroscope/commit/9fa550c0b577625780aeb00b5fcd9ca3858d410a)) - -# [1.9.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.8...@pyroscope/webapp@1.9.0) (2022-05-30) - -### Bug Fixes - -- flamegraph palette selector checkmark styles ([#1114](https://github.com/pyroscope-io/pyroscope/issues/1114)) ([755893f](https://github.com/pyroscope-io/pyroscope/commit/755893f23a04c1031a858c39e8729a5074eaf67b)) - -### Features - -- Color mode ([#1103](https://github.com/pyroscope-io/pyroscope/issues/1103)) ([8855859](https://github.com/pyroscope-io/pyroscope/commit/885585958012775f0d51ea82208d641d10215574)) - -## [1.8.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.7...@pyroscope/webapp@1.8.8) (2022-05-26) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.8.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.6...@pyroscope/webapp@1.8.7) (2022-05-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.8.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.5...@pyroscope/webapp@1.8.6) (2022-05-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.8.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.4...@pyroscope/webapp@1.8.5) (2022-05-25) - -### Bug Fixes - -- **webapp:** Add minimum width for "select tag" dropdown [#1065](https://github.com/pyroscope-io/pyroscope/issues/1065) ([#1109](https://github.com/pyroscope-io/pyroscope/issues/1109)) ([ab47ad5](https://github.com/pyroscope-io/pyroscope/commit/ab47ad52047b03fc3df42126cc178dd733d6471b)) - -## [1.8.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.3...@pyroscope/webapp@1.8.4) (2022-05-12) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.8.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.2...@pyroscope/webapp@1.8.3) (2022-05-10) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.8.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.1...@pyroscope/webapp@1.8.2) (2022-05-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.8.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.8.0...@pyroscope/webapp@1.8.1) (2022-05-06) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.8.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.7.1...@pyroscope/webapp@1.8.0) (2022-05-05) - -### Features - -- **frontend:** allow copying notification message ([#1086](https://github.com/pyroscope-io/pyroscope/issues/1086)) ([d30b787](https://github.com/pyroscope-io/pyroscope/commit/d30b78773ad58ec0aceadf40e3ba25900bc4971b)) - -## [1.7.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.7.0...@pyroscope/webapp@1.7.1) (2022-05-02) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.7.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.6.5...@pyroscope/webapp@1.7.0) (2022-05-02) - -### Features - -- nodejs push & pull mode ([#1060](https://github.com/pyroscope-io/pyroscope/issues/1060)) ([4317103](https://github.com/pyroscope-io/pyroscope/commit/4317103354b5712c561e4cead7f6906c21a3005c)) - -## [1.6.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.6.4...@pyroscope/webapp@1.6.5) (2022-04-27) - -### Bug Fixes - -- **webapp:** tag selector overflow ([#1055](https://github.com/pyroscope-io/pyroscope/issues/1055)) ([f7c7917](https://github.com/pyroscope-io/pyroscope/commit/f7c79179c323b95b8966a12729e1091e4a57dc0f)) - -### Reverts - -- Revert "fix(flamegraph): fix table contrast (#1053)" (#1063) ([a4dd7f6](https://github.com/pyroscope-io/pyroscope/commit/a4dd7f6417b9c37134c9a63143a1d1f8ccb2ee3d)), closes [#1053](https://github.com/pyroscope-io/pyroscope/issues/1053) [#1063](https://github.com/pyroscope-io/pyroscope/issues/1063) - -## [1.6.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.6.3...@pyroscope/webapp@1.6.4) (2022-04-27) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.6.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.6.2...@pyroscope/webapp@1.6.3) (2022-04-26) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.6.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.6.1...@pyroscope/webapp@1.6.2) (2022-04-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.6.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.6.0...@pyroscope/webapp@1.6.1) (2022-04-22) - -### Bug Fixes - -- **flamegraph:** fix table contrast ([#1053](https://github.com/pyroscope-io/pyroscope/issues/1053)) ([6246f21](https://github.com/pyroscope-io/pyroscope/commit/6246f211967d073febdca8fb578bb805b96597cd)) - -# [1.6.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.5.0...@pyroscope/webapp@1.6.0) (2022-04-15) - -### Features - -- move login to react ([#1031](https://github.com/pyroscope-io/pyroscope/issues/1031)) ([1cb6f9a](https://github.com/pyroscope-io/pyroscope/commit/1cb6f9a08d825acf643b5ef8b51cecab338b1314)), closes [#985](https://github.com/pyroscope-io/pyroscope/issues/985) [#991](https://github.com/pyroscope-io/pyroscope/issues/991) - -# [1.5.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.11...@pyroscope/webapp@1.5.0) (2022-04-14) - -### Features - -- **webapp:** add modal for custom export name ([#965](https://github.com/pyroscope-io/pyroscope/issues/965)) ([422ea82](https://github.com/pyroscope-io/pyroscope/commit/422ea82fd20a64eda44ae62821f67a89c129a594)) - -## [1.4.11](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.10...@pyroscope/webapp@1.4.11) (2022-04-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.10](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.9...@pyroscope/webapp@1.4.10) (2022-04-13) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.8...@pyroscope/webapp@1.4.9) (2022-04-12) - -### Bug Fixes - -- **flamegraph:** inject its styles via css only ([#1023](https://github.com/pyroscope-io/pyroscope/issues/1023)) ([c20a137](https://github.com/pyroscope-io/pyroscope/commit/c20a137a56141f944967c8e229c16c773ec4a607)) - -## [1.4.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.7...@pyroscope/webapp@1.4.8) (2022-04-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.6...@pyroscope/webapp@1.4.7) (2022-04-11) - -### Bug Fixes - -- **webapp:** service-discovery ([#1016](https://github.com/pyroscope-io/pyroscope/issues/1016)) ([2da460e](https://github.com/pyroscope-io/pyroscope/commit/2da460e57437193138110b73e49a4209b04d9984)) - -## [1.4.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.5...@pyroscope/webapp@1.4.6) (2022-04-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.4...@pyroscope/webapp@1.4.5) (2022-04-11) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.3...@pyroscope/webapp@1.4.4) (2022-04-08) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.2...@pyroscope/webapp@1.4.3) (2022-04-08) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.1...@pyroscope/webapp@1.4.2) (2022-04-06) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.4.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.4.0...@pyroscope/webapp@1.4.1) (2022-04-06) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.4.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.3.3...@pyroscope/webapp@1.4.0) (2022-03-28) - -### Features - -- **webapp:** diff arbitrary apps ([#967](https://github.com/pyroscope-io/pyroscope/issues/967)) ([f7e66f1](https://github.com/pyroscope-io/pyroscope/commit/f7e66f1082bb5e1ae2851b0f37f56f46ed43e5e1)) - -## [1.3.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.3.2...@pyroscope/webapp@1.3.3) (2022-03-25) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.3.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.3.1...@pyroscope/webapp@1.3.2) (2022-03-24) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.3.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.3.0...@pyroscope/webapp@1.3.1) (2022-03-23) - -**Note:** Version bump only for package @pyroscope/webapp - -# [1.3.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.2.0...@pyroscope/webapp@1.3.0) (2022-03-21) - -### Features - -- **webapp:** allow comparing distinct queries/tags ([#942](https://github.com/pyroscope-io/pyroscope/issues/942)) ([4d1307c](https://github.com/pyroscope-io/pyroscope/commit/4d1307c3751b263d88430977f2d87473c8ee280e)) - -# [1.2.0](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.10...@pyroscope/webapp@1.2.0) (2022-03-21) - -### Features - -- **webapp:** make search in app/tags selector bar sticky ([#950](https://github.com/pyroscope-io/pyroscope/issues/950)) ([c13ad6a](https://github.com/pyroscope-io/pyroscope/commit/c13ad6af04bdc96bbd980a0d89f8da07681fd321)) - -## [1.1.10](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.9...@pyroscope/webapp@1.1.10) (2022-03-18) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.9](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.8...@pyroscope/webapp@1.1.9) (2022-03-16) - -### Bug Fixes - -- **frontend:** date range picker styling ([#936](https://github.com/pyroscope-io/pyroscope/issues/936)) ([012eb9f](https://github.com/pyroscope-io/pyroscope/commit/012eb9f1b88b0f490d154c7289089eb136f2d197)) - -## [1.1.8](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.7...@pyroscope/webapp@1.1.8) (2022-03-16) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.7](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.6...@pyroscope/webapp@1.1.7) (2022-03-15) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.6](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.5...@pyroscope/webapp@1.1.6) (2022-03-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.5](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.4...@pyroscope/webapp@1.1.5) (2022-03-14) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.4](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.3...@pyroscope/webapp@1.1.4) (2022-03-10) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.3](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.2...@pyroscope/webapp@1.1.3) (2022-03-09) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.2](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.1...@pyroscope/webapp@1.1.2) (2022-03-08) - -**Note:** Version bump only for package @pyroscope/webapp - -## [1.1.1](https://github.com/pyroscope-io/pyroscope/compare/@pyroscope/webapp@1.1.0...@pyroscope/webapp@1.1.1) (2022-03-08) - -**Note:** Version bump only for package @pyroscope/webapp - -# 1.1.0 (2022-03-07) - -### Bug Fixes - -- adhoc comparison / diff routes. ([#834](https://github.com/pyroscope-io/pyroscope/issues/834)) ([1ab101c](https://github.com/pyroscope-io/pyroscope/commit/1ab101c20742d55c17b112f6d3eec942e96091bb)) -- assets handling when using base-url argument ([#611](https://github.com/pyroscope-io/pyroscope/issues/611)) ([97a6002](https://github.com/pyroscope-io/pyroscope/commit/97a60023e3e9d5b9fa705eacf0900386ee8367c7)) -- comparison view timeline ([#553](https://github.com/pyroscope-io/pyroscope/issues/553)) ([c615bb7](https://github.com/pyroscope-io/pyroscope/commit/c615bb7340202cf53bd37079a23bb66d40c78dce)) -- fix highlight and its test ([#491](https://github.com/pyroscope-io/pyroscope/issues/491)) ([dd6d6b5](https://github.com/pyroscope-io/pyroscope/commit/dd6d6b5f9139db03c9abc687727f974a4040a00f)) -- **frontend:** add tab panel styles to adhoc comparison component. ([#650](https://github.com/pyroscope-io/pyroscope/issues/650)) ([6537dfe](https://github.com/pyroscope-io/pyroscope/commit/6537dfe8578768db8aa3e31a13a728d7a480d541)) -- **frontend:** comparison diff ui fixes ([#627](https://github.com/pyroscope-io/pyroscope/issues/627)) ([202835b](https://github.com/pyroscope-io/pyroscope/commit/202835bcc5f41a5b8858d566b1c1917965a510ff)) -- **frontend:** don't allow selecting empty apps ([#723](https://github.com/pyroscope-io/pyroscope/issues/723)) ([2378ab5](https://github.com/pyroscope-io/pyroscope/commit/2378ab5cff3e10c1ad9f4b4edc423f16f975a3e4)) -- **frontend:** fix coloring for pull mode ([#822](https://github.com/pyroscope-io/pyroscope/issues/822)) ([a221400](https://github.com/pyroscope-io/pyroscope/commit/a221400027097ff33864f4cba0ff5bfde78295f1)) -- **frontend:** fix comparison view ([#549](https://github.com/pyroscope-io/pyroscope/issues/549)) ([4c9d2f8](https://github.com/pyroscope-io/pyroscope/commit/4c9d2f8d4b7a27ee922afa8d7f8c13b6456b7646)) -- **frontend:** fix flamegraph width in comparison view ([#639](https://github.com/pyroscope-io/pyroscope/issues/639)) ([1e6bef5](https://github.com/pyroscope-io/pyroscope/commit/1e6bef56423b02646f601f19d6c64f7749ef392e)) -- **frontend:** fixes golang package name coloring ([#635](https://github.com/pyroscope-io/pyroscope/issues/635)) ([6c390b5](https://github.com/pyroscope-io/pyroscope/commit/6c390b5d27a2ce1d2b61b7875cfaf6d1846937f8)) -- **frontend:** improves timeline UX by shifting bars 5 seconds forward ([#742](https://github.com/pyroscope-io/pyroscope/issues/742)) ([687219d](https://github.com/pyroscope-io/pyroscope/commit/687219d180224e4fd750dcd697396200f12bcac0)) -- **frontend:** keep query param when changing routes ([#674](https://github.com/pyroscope-io/pyroscope/issues/674)) ([389019b](https://github.com/pyroscope-io/pyroscope/commit/389019b8c4127ccd738cce74dbf14deebebcb273)) -- **frontend:** move CSS to css modules ([#842](https://github.com/pyroscope-io/pyroscope/issues/842)) ([3aadc13](https://github.com/pyroscope-io/pyroscope/commit/3aadc13749ed484f1167b858ded8aa8e56743c39)) -- **frontend:** quickfix for wierd dropdown behaviour ([#832](https://github.com/pyroscope-io/pyroscope/issues/832)) ([c6da525](https://github.com/pyroscope-io/pyroscope/commit/c6da525d30a4271fd5ca74e2c6bf35230042c47e)) -- **frontend:** safari date-fns fix ([#838](https://github.com/pyroscope-io/pyroscope/issues/838)) ([896b936](https://github.com/pyroscope-io/pyroscope/commit/896b93605bd0b0190838b45a647f4689d93360ab)) -- highlight in diff view ([#498](https://github.com/pyroscope-io/pyroscope/issues/498)) ([fbb826a](https://github.com/pyroscope-io/pyroscope/commit/fbb826a3263cac288fd8784c162b92fcb188d13d)) -- **panel:** import @szhsin/react-menu styles in contextmenu ([#669](https://github.com/pyroscope-io/pyroscope/issues/669)) ([2fb0fff](https://github.com/pyroscope-io/pyroscope/commit/2fb0fffd8394c1ec5958a85c0bb2628b946e0ec4)) -- plural of date picker ([#831](https://github.com/pyroscope-io/pyroscope/issues/831)) ([8bd6eb8](https://github.com/pyroscope-io/pyroscope/commit/8bd6eb840123feb395a77d9077a64215ccf4b286)) -- timeline guide text alignment ([#565](https://github.com/pyroscope-io/pyroscope/issues/565)) ([efc94a0](https://github.com/pyroscope-io/pyroscope/commit/efc94a0a3fbc07234113df826dc732d51375f59d)) -- Update drag and drop styling ([#756](https://github.com/pyroscope-io/pyroscope/issues/756)) ([25ce3b2](https://github.com/pyroscope-io/pyroscope/commit/25ce3b2f52428043d04f152f67fa10fb3b118049)) -- use the correct controller variable. ([#615](https://github.com/pyroscope-io/pyroscope/issues/615)) ([ccd97f9](https://github.com/pyroscope-io/pyroscope/commit/ccd97f9a68a18798c26282e4e74e1bd536b09d87)) - -### Features - -- add basic context menu ([#460](https://github.com/pyroscope-io/pyroscope/issues/460)) ([3df5d9d](https://github.com/pyroscope-io/pyroscope/commit/3df5d9d2b91f1c9bbf7034bef8972c604c808f7f)) -- added tooltip for timeline selection ([#730](https://github.com/pyroscope-io/pyroscope/issues/730)) ([d226370](https://github.com/pyroscope-io/pyroscope/commit/d226370239293dd14e01c907a471e68c8f915a2b)) -- adds a page with pull-mode targets ([#877](https://github.com/pyroscope-io/pyroscope/issues/877)) ([26c21f2](https://github.com/pyroscope-io/pyroscope/commit/26c21f2d3ecd5b043fe9facdb669dbee7cad6877)), closes [#592](https://github.com/pyroscope-io/pyroscope/issues/592) [#592](https://github.com/pyroscope-io/pyroscope/issues/592) -- adds adhoc single view ([#546](https://github.com/pyroscope-io/pyroscope/issues/546)) ([4983566](https://github.com/pyroscope-io/pyroscope/commit/4983566e9076223b46e0e0d75a101ad4a89173b2)) -- adhoc comparison diff support ([#652](https://github.com/pyroscope-io/pyroscope/issues/652)) ([65b7372](https://github.com/pyroscope-io/pyroscope/commit/65b7372e74540663a44356fd2302a69f55f27e19)) -- adhoc comparison UI ([#580](https://github.com/pyroscope-io/pyroscope/issues/580)) ([3272249](https://github.com/pyroscope-io/pyroscope/commit/3272249cfbe308e4b3b2e7ccaa0f446b0ea942e4)) -- export standalone html ([#691](https://github.com/pyroscope-io/pyroscope/issues/691)) ([8d20863](https://github.com/pyroscope-io/pyroscope/commit/8d20863e26c9ddc45389b2b37bd7cc9b20881247)) -- extract various components ([#868](https://github.com/pyroscope-io/pyroscope/issues/868)) ([fb4c2fc](https://github.com/pyroscope-io/pyroscope/commit/fb4c2fcb3dc279407685fea5eab9937f2dca1a81)) -- **frontend:** add package coloring for rust ([#798](https://github.com/pyroscope-io/pyroscope/issues/798)) ([c687f83](https://github.com/pyroscope-io/pyroscope/commit/c687f8382e0b5c87dcc6fd1ac3ffdd2e11464952)) -- **frontend:** adds ability to export to flamegraph.com ([#799](https://github.com/pyroscope-io/pyroscope/issues/799)) ([a3828bc](https://github.com/pyroscope-io/pyroscope/commit/a3828bc93fdf76478328f5c65c117b7737993e61)) -- **frontend:** allow to export flamegraph json ([#616](https://github.com/pyroscope-io/pyroscope/issues/616)) ([3435a21](https://github.com/pyroscope-io/pyroscope/commit/3435a212aa659d5240f84702926833d351a9d44f)) -- **frontend:** export comparison diff standalone html ([#749](https://github.com/pyroscope-io/pyroscope/issues/749)) ([697a66c](https://github.com/pyroscope-io/pyroscope/commit/697a66c925178de43d09d051f83a9dc0f39207a9)) -- **frontend:** export diff to flamegraph.com ([#808](https://github.com/pyroscope-io/pyroscope/issues/808)) ([a2e47b2](https://github.com/pyroscope-io/pyroscope/commit/a2e47b25646dc8bec386e1d98f9c87503c0ec0d2)) -- **frontend:** export pprof format ([#620](https://github.com/pyroscope-io/pyroscope/issues/620)) ([60c305d](https://github.com/pyroscope-io/pyroscope/commit/60c305ddd035a34e319d4b0967e9bb21eb82d5dd)) -- **frontend:** new app name selector component ([#682](https://github.com/pyroscope-io/pyroscope/issues/682)) ([b6282c3](https://github.com/pyroscope-io/pyroscope/commit/b6282c34e4985f8ec82c98a9eaa049455487a53b)) -- **frontend:** new sidebar ([#581](https://github.com/pyroscope-io/pyroscope/issues/581)) ([f373706](https://github.com/pyroscope-io/pyroscope/commit/f37370680047055f6d6be97eeb611873a9b44581)) -- **frontend:** new tags dropdown ([#642](https://github.com/pyroscope-io/pyroscope/issues/642)) ([6290e45](https://github.com/pyroscope-io/pyroscope/commit/6290e45506193ed95566cb4ab7264b81a32bd266)) -- **frontend:** persist sidebar collapsed state ([#699](https://github.com/pyroscope-io/pyroscope/issues/699)) ([c552bc2](https://github.com/pyroscope-io/pyroscope/commit/c552bc2c546960e7351134dfa6d7dbc63e4fb8d0)) -- identity and access management ([#739](https://github.com/pyroscope-io/pyroscope/issues/739)) ([0ca0d83](https://github.com/pyroscope-io/pyroscope/commit/0ca0d8398cbbc58799e0e53b658c70b8670c6e72)), closes [#770](https://github.com/pyroscope-io/pyroscope/issues/770) [#807](https://github.com/pyroscope-io/pyroscope/issues/807) [#814](https://github.com/pyroscope-io/pyroscope/issues/814) -- keep existing colors when highlighting ([#714](https://github.com/pyroscope-io/pyroscope/issues/714)) ([ab094c2](https://github.com/pyroscope-io/pyroscope/commit/ab094c258fa3963710dcc137cd9ff046da146be8)) -- New diff mode palette selection dropdown ([#754](https://github.com/pyroscope-io/pyroscope/issues/754)) ([dfd8a3d](https://github.com/pyroscope-io/pyroscope/commit/dfd8a3d04900eadead8faf588cfa1d01bbf519b2)) -- output standalone HTML files for adhoc profiles. ([#728](https://github.com/pyroscope-io/pyroscope/issues/728)) ([a4f90ab](https://github.com/pyroscope-io/pyroscope/commit/a4f90ab3cc6f5e4536db2f4fdbcb1d6bee5f790b)) - -### Performance Improvements - -- improve flamegraph by memoizing table ([#484](https://github.com/pyroscope-io/pyroscope/issues/484)) ([76cd773](https://github.com/pyroscope-io/pyroscope/commit/76cd773e5f621b6cb418df92101d3d426f3633db)) diff --git a/og/webapp/LICENSE b/og/webapp/LICENSE deleted file mode 100644 index d5361db622..0000000000 --- a/og/webapp/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 Pyroscope - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/og/webapp/README.md b/og/webapp/README.md deleted file mode 100644 index f2b5eabc5c..0000000000 --- a/og/webapp/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# Webapp - -# Tests -## Snapshot tests -Similar to what we do in cypress, we take snapshots of the canvas. - -To make the results reproducible, we run in `docker` - -To update the snapshots, run -``` -yarn test:ss -``` - -To check the snapshots, run -``` -yarn test:ss:check -``` - -Here ONLY tests matching the regex `group:snapshot` will run. -And the opposite is true, when running `yarn test`, these tests with `group:snapshot` in the name will be ignored. - -# dependencies vs devDependencies -When installing a new package, consider the following: -Add to `dependencies` if it's **absolutely necessary to build** the application. -Anything else (local dev, CI) add too `devDependencies`. - -The reasoning is that when building the docker image we install only `dependencies` required to build the application, by running `yarn install --production`. -Linting, testing etc is assumed to be ran in a different CI step. - -# Using alias imports -Alias imports allow importing as if it was an external package, for example: -```javascript -import Button from '@phlare/ui/Button'; -``` - -To be able to do that, you need to add the alias to the following files: -* `.storybook/main.js` -* `scripts/webpack/shared.ts` -* `tsconfig.json` -* `jest.config.js` - -# Developing the webapp/templates page -By default, developing pages other than the index require a bit of setup: - - -For example, acessing http://locahlost:4040/forbidden won't work -To be able to access it, update the variable `pages` in `scripts/webpack.common.ts` to allow building all pages when in dev mode. - -Beware, this will make the (local) build slower. - -# Investigating webpack speed -Run with `--progress=profile` to get more info. - -for example `yarn dev --progress=profile` - - -Another interesting flag is `--json`, which you can then analyze on https://chrisbateman.github.io/webpack-visualizer/ - -# Testing baseURL -It can be a bit of a pain in the ass. - -Install nginx -``` -nginx -c cypress/base-url/nginx.conf -g 'daemon off;' -``` - -Then run the server with `PYROSCOPE_BASE_URL=/pyroscope` - -## Testing baseURL + auth -Same as before, but also run the `oauth2-mock-server`: -``` -node scripts/oauth-mock/oauth-mock.js -``` - -Also run the server with -``` -make dev SERVERPARAMS=--config=scripts/oauth-mock/pyroscope-config-base-url.yml -``` diff --git a/og/webapp/assets.go b/og/webapp/assets.go deleted file mode 100644 index f94016b340..0000000000 --- a/og/webapp/assets.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build !embedassets -// +build !embedassets - -package webapp - -import ( - "net/http" -) - -var AssetsEmbedded = false - -func Assets() (http.FileSystem, error) { - return http.Dir("./webapp/public"), nil -} diff --git a/og/webapp/assets_embedded.go b/og/webapp/assets_embedded.go deleted file mode 100644 index 29075862b1..0000000000 --- a/og/webapp/assets_embedded.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build embedassets -// +build embedassets - -package webapp - -import ( - "embed" - "io/fs" - "net/http" -) - -var AssetsEmbedded = true - -//go:embed public -var assets embed.FS - -func Assets() (http.FileSystem, error) { - fsys, err := fs.Sub(assets, "public") - - if err != nil { - return nil, err - } - - return http.FS(fsys), nil -} diff --git a/og/webapp/javascript/globals.tsx b/og/webapp/javascript/globals.tsx deleted file mode 100644 index 7b26a3d64e..0000000000 --- a/og/webapp/javascript/globals.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import jquery from 'jquery'; - -interface Window { - jQuery?: unknown; - $?: unknown; -} - -// Used by react-flot/flotjs -(window as Window).jQuery = jquery; -(window as Window).$ = jquery; diff --git a/og/webapp/javascript/index.tsx b/og/webapp/javascript/index.tsx deleted file mode 100644 index 100a3f7e91..0000000000 --- a/og/webapp/javascript/index.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import './globals'; - -import ReactDOM from 'react-dom'; -import React from 'react'; -import { Provider } from 'react-redux'; -import { Router, Switch, Route } from 'react-router-dom'; -import { isAdhocUIEnabled, isAuthRequired } from '@webapp/util/features'; -import Notifications from '@webapp/ui/Notifications'; -import { PersistGate } from 'redux-persist/integration/react'; -import Footer from '@webapp/components/Footer'; -import PageTitle from '@webapp/components/PageTitle'; -import store, { persistor } from './redux/store'; - -import ContinuousSingleView from './pages/ContinuousSingleView'; -import ContinuousComparisonView from './pages/ContinuousComparisonView'; -import ContinuousDiffView from './pages/ContinuousDiffView'; -import TagExplorerView from './pages/TagExplorerView'; -import Continuous from './components/Continuous'; -import Settings from './components/Settings'; -import Sidebar from './components/Sidebar'; -import AdhocSingle from './pages/adhoc/AdhocSingle'; -import AdhocComparison from './pages/adhoc/AdhocComparison'; -import AdhocDiff from './pages/adhoc/AdhocDiff'; -import ServiceDiscoveryApp from './pages/ServiceDiscovery'; -import ServerNotifications from './components/ServerNotifications'; -import Protected from './components/Protected'; -import SignInPage from './pages/IntroPages/SignIn'; -import SignUpPage from './pages/IntroPages/SignUp'; -import Forbidden from './pages/IntroPages/Forbidden'; -import NotFound from './pages/IntroPages/NotFound'; -import { PAGES } from './pages/constants'; -import history from './util/history'; -import TracingSingleView from './pages/TracingSingleView'; -import ExemplarsSingleView from './pages/exemplars/ExemplarsSingleView'; - -function App() { - return ( -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {isAuthRequired && ( - - - - - - - - )} - - - - - - - - - - - - - - {isAdhocUIEnabled && ( - - - - - - - )} - {isAdhocUIEnabled && ( - - - - - - - )} - {isAdhocUIEnabled && ( - - - - - - - )} - - <> - - - - - - - <> - - - - - -
-
-
- ); -} - -ReactDOM.render( - - - - - - - - - , - document.getElementById('root') -); diff --git a/og/webapp/javascript/services/base.spec.ts b/og/webapp/javascript/services/base.spec.ts deleted file mode 100644 index 1dc0596cbf..0000000000 --- a/og/webapp/javascript/services/base.spec.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { Result } from '@webapp/util/fp'; -import path from 'path'; -import { ZodError } from 'zod'; -import { - request, - mountRequest, - RequestNotOkError, - RequestNotOkWithErrorsList, - ResponseOkNotInJSONFormat, - RequestIncompleteError, - ResponseNotOkInHTMLFormat, -} from './base'; -import { setupServer, rest } from './testUtils'; -import basename from '../util/baseurl'; - -jest.mock('../util/baseurl', () => jest.fn()); - -describe('Base HTTP', () => { - let server: ReturnType | null; - - afterEach(() => { - if (server) { - server.close(); - } - server = null; - }); - - describe('Server responds', () => { - it('with valid JSON data', async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - foo: 'bar', - }) - ); - }) - ); - server.listen(); - const res = await request('/test'); - - expect(res).toMatchObject( - Result.ok({ - foo: 'bar', - }) - ); - }); - - it('with invalid JSON data', async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res(ctx.status(200), ctx.text('bla')); - }) - ); - server.listen(); - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(ResponseOkNotInJSONFormat); - expect(res.error.message).toBe( - "Server returned with code: '200'. The body that could not be parsed contains 'bla'" - ); - }); - }); - - describe('Server never responded', () => { - it('fails', async () => { - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(RequestIncompleteError); - expect(res.error.message).toBe( - "Request failed to be completed. Description: 'request to http://localhost/test failed, reason: connect ECONNREFUSED 127.0.0.1:80'" - ); - }); - }); - - describe('Server responded with 2xx and data', () => { - it('works', () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res(ctx.status(200), ctx.json({})); - }) - ); - server.listen(); - }); - }); - - describe('Server responded with statusCode outside 2xx range', () => { - it(`Returns a default message if theres no body`, async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res(ctx.status(500)); - }) - ); - server.listen(); - - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(RequestNotOkError); - expect(res.error.message).toBe( - "Request failed with statusCode: '500' and description: 'No description available'" - ); - }); - - it(`Returns an error list if available`, async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res( - ctx.status(500), - ctx.json({ - errors: ['error1', 'error2'], - }) - ); - }) - ); - server.listen(); - - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(RequestNotOkWithErrorsList); - expect(res.error.message).toBe('Error(s) were found: "error1", "error2"'); - }); - - it(`Returns an error message if available`, async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res( - ctx.status(500), - ctx.json({ - error: 'error', - }) - ); - }) - ); - server.listen(); - - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(RequestNotOkError); - expect(res.error.message).toBe( - "Request failed with statusCode: '500' and description: 'error'" - ); - }); - - it(`Returns an error message if available`, async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res( - ctx.status(500), - ctx.json({ - message: 'error', - }) - ); - }) - ); - server.listen(); - - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(RequestNotOkError); - expect(res.error.message).toBe( - "Request failed with statusCode: '500' and description: 'error'" - ); - }); - - it(`Returns a bunch of data`, async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res( - ctx.status(500), - ctx.json({ - foo: 'foo', - bar: 'bar', - }) - ); - }) - ); - server.listen(); - - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(RequestNotOkError); - expect(res.error.message).toBe( - // eslint-disable-next-line no-useless-escape - `Request failed with statusCode: '500' and description: 'Could not identify an error message. Payload is {\"foo\":\"foo\",\"bar\":\"bar\"}'` - ); - }); - - it(`Returns the text body as message when there's response NOT in JSON format`, async () => { - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res(ctx.status(500), ctx.text('text error')); - }) - ); - server.listen(); - - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(RequestNotOkError); - expect(res.error.message).toBe( - "Request failed with statusCode: '500' and description: 'text error'" - ); - }); - - it('Returns a generic message when respond with HTML data', async () => { - const htmlData = require('fs').readFileSync( - path.resolve(__dirname, './testdata/example.html'), - 'utf8' - ); - - server = setupServer( - rest.get(`http://localhost/test`, (req, res, ctx) => { - return res(ctx.status(500), ctx.text(htmlData)); - }) - ); - server.listen(); - const res = await request('/test'); - - expect(res.error).toBeInstanceOf(ResponseNotOkInHTMLFormat); - expect(res.error.message).toBe( - "Server returned with code: '500'. The body contains an HTML page" - ); - }); - }); -}); - -// Normally this wouldn't be tested -// But since implementation is complex enough -// It's better to expose and test it -// TODO test when req is an object -describe('mountRequest', () => { - describe('basename is set', () => { - it('prepends browserURL with basename', () => { - (basename as any).mockImplementationOnce(() => { - return '/pyroscope'; - }); - - const got = mountRequest('my-request'); - expect(got).toBe('http://localhost/pyroscope/my-request'); - }); - }); - - describe('basename is NOT set', () => { - it('returns the browser url', () => { - (basename as any).mockImplementationOnce(() => { - return null; - }); - - const got = mountRequest('my-request'); - expect(got).toBe('http://localhost/my-request'); - }); - }); -}); diff --git a/og/webapp/javascript/services/tags.ts b/og/webapp/javascript/services/tags.ts deleted file mode 100644 index 46d0e3bc96..0000000000 --- a/og/webapp/javascript/services/tags.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - Tags, - TagsValuesSchema, - TagsValues, - TagsSchema, -} from '@webapp/models/tags'; -import { request, parseResponse } from './base'; - -export async function fetchTags(query: string, from: number, until: number) { - const params = new URLSearchParams({ - query, - from: from.toString(10), - until: until.toString(10), - }); - const response = await request(`/labels?${params.toString()}`); - return parseResponse(response, TagsSchema); -} - -export async function fetchLabelValues( - label: string, - query: string, - from: number, - until: number -) { - const params = new URLSearchParams({ - query, - label, - from: from.toString(10), - until: until.toString(10), - }); - const response = await request(`/label-values?${params.toString()}`); - return parseResponse(response, TagsValuesSchema); -} diff --git a/og/webapp/javascript/standalone.tsx b/og/webapp/javascript/standalone.tsx deleted file mode 100644 index f16c16d192..0000000000 --- a/og/webapp/javascript/standalone.tsx +++ /dev/null @@ -1,41 +0,0 @@ -// @typescript-eslint/restrict-template-expressions -import ReactDOM from 'react-dom'; -import React from 'react'; -import Box from '@webapp/ui/Box'; -import { decodeFlamebearer } from '@webapp/models/flamebearer'; -import { FlamegraphRenderer } from '@pyroscope/flamegraph/src/FlamegraphRenderer'; -import Footer from './components/Footer'; -import '@pyroscope/flamegraph/dist/index.css'; - -if (!(window as ShamefulAny).flamegraph) { - alert(`'flamegraph' is required`); - throw new Error(`'flamegraph' is required`); -} - -// TODO parse window.flamegraph -const { flamegraph } = window as ShamefulAny; - -function StandaloneApp() { - const flamebearer = decodeFlamebearer(flamegraph); - - return ( -
- - - -
-
- ); -} - -function run() { - ReactDOM.render(, document.getElementById('root')); -} - -// Since InlineChunkHtmlPlugin adds scripts to the head -// We must wait for the DOM to be loaded -// Otherwise React will fail to initialize since there's no DOM yet -window.addEventListener('DOMContentLoaded', run, false); diff --git a/og/webapp/javascript/types/alias.d.ts b/og/webapp/javascript/types/alias.d.ts deleted file mode 100644 index 5506cdc89a..0000000000 --- a/og/webapp/javascript/types/alias.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -// Alias for when you need to use 'any' as a workaround -// and plan to come back to fix it -type ShamefulAny = any; diff --git a/og/webapp/javascript/util/baseurl.spec.ts b/og/webapp/javascript/util/baseurl.spec.ts deleted file mode 100644 index 3f58ba756c..0000000000 --- a/og/webapp/javascript/util/baseurl.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import basename from './baseurl'; - -function checkSelector(selector: string) { - if (selector !== 'meta[name="pyroscope-base-url"]') { - throw new Error('Wrong selector'); - } -} -describe('baseurl', () => { - describe('no baseURL meta tag set', () => { - it('returns undefined', () => { - const got = basename(); - - expect(got).toBe(undefined); - }); - }); - - describe('baseURL meta tag set', () => { - describe('no content', () => { - beforeEach(() => { - jest - .spyOn(document, 'querySelector') - .mockImplementationOnce((selector) => { - checkSelector(selector); - return {} as HTMLMetaElement; - }); - }); - it('returns undefined', () => { - const got = basename(); - - expect(got).toBe(undefined); - }); - }); - - describe("there's content", () => { - it('works with a base Path', () => { - jest - .spyOn(document, 'querySelector') - .mockImplementationOnce((selector) => { - checkSelector(selector); - return { content: '/pyroscope' } as HTMLMetaElement; - }); - - const got = basename(); - - expect(got).toBe('/pyroscope'); - }); - - it('works with a full URL', () => { - jest - .spyOn(document, 'querySelector') - .mockImplementationOnce((selector) => { - checkSelector(selector); - return { - content: 'http://localhost:8080/pyroscope', - } as HTMLMetaElement; - }); - - const got = basename(); - - expect(got).toBe('/pyroscope'); - }); - }); - }); -}); diff --git a/og/webapp/javascript/util/baseurl.ts b/og/webapp/javascript/util/baseurl.ts deleted file mode 100644 index 0f94070336..0000000000 --- a/og/webapp/javascript/util/baseurl.ts +++ /dev/null @@ -1,21 +0,0 @@ -// There's a copy of this function in welcome.html -// TODO: maybe dedup somehow? -function basename() { - const baseURLMetaTag = document.querySelector( - 'meta[name="pyroscope-base-url"]' - ) as HTMLMetaElement; - - if (!baseURLMetaTag) { - return undefined; - } - - const baseURL = baseURLMetaTag.content; - - if (!baseURL) { - return undefined; - } - const url = new URL(baseURL, window.location.href); - return url.pathname; -} - -export default basename; diff --git a/og/webapp/javascript/util/history.ts b/og/webapp/javascript/util/history.ts deleted file mode 100644 index 611eacdc1f..0000000000 --- a/og/webapp/javascript/util/history.ts +++ /dev/null @@ -1,8 +0,0 @@ -// src/myHistory.js -import { createBrowserHistory } from 'history'; -import basename from './baseurl'; - -const history = createBrowserHistory({ - basename: basename(), -}); -export default history; diff --git a/og/webapp/package.json b/og/webapp/package.json deleted file mode 100644 index 5b3586da06..0000000000 --- a/og/webapp/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@pyroscope/legacy-webapp", - "version": "1.68.22", - "private": true, - "license": "Apache-2.0", - "scripts": { - "test": "echo \"Error: run tests from root\" && exit 1", - "dev": "webpack --config ../scripts/webpack/webpack.dev.ts --watch", - "lint": "eslint ./ --cache --fix", - "clean": "rm -rf public/assets && rm -rf public/*.html", - "type-check": "tsc -p tsconfig.json --noEmit", - "build": "yarn run clean && yarn run build:standalone && yarn run build:webapp", - "build:standalone": "webpack --config ../scripts/webpack/webpack.standalone.ts", - "build:webapp": "NODE_ENV=production webpack --config ../scripts/webpack/webpack.prod.ts" - }, - "dependencies": { - "@pyroscope/flamegraph": "^0.35.6", - "@pyroscope/models": "^0.4.7" - } -} diff --git a/og/webapp/templates/index.html b/og/webapp/templates/index.html deleted file mode 100644 index cdddc25627..0000000000 --- a/og/webapp/templates/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - Pyroscope - {{- if .BaseURL }} - - {{- end }} - - - {{ .ExtraMetadata }} <%= extra_metadata %> - - - -
- - - - - - - diff --git a/og/webapp/templates/standalone.html b/og/webapp/templates/standalone.html deleted file mode 100644 index 601f0619b2..0000000000 --- a/og/webapp/templates/standalone.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - Pyroscope - - - - -
- - diff --git a/og/webapp/traces/traceSample.json b/og/webapp/traces/traceSample.json deleted file mode 100755 index c50f6fa965..0000000000 --- a/og/webapp/traces/traceSample.json +++ /dev/null @@ -1,4058 +0,0 @@ -{ - "data": [ - { - "traceID": "68f464e5bf3714b6", - "spans": [ - { - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005", - "flags": 1, - "operationName": "/driver.DriverService/FindNearest", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "7f1e9a9b718ae1f0" - } - ], - "startTime": 1657053117821682, - "duration": 200138, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "component", - "type": "string", - "value": "gRPC" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117821708, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Searching for nearby drivers" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "location", - "type": "string", - "value": "728,326" - } - ] - }, - { - "timestamp": 1657053117900109, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Retrying GetDriver after error" - }, - { - "key": "error", - "type": "string", - "value": "redis timeout" - }, - { - "key": "level", - "type": "string", - "value": "error" - }, - { - "key": "retry_no", - "type": "int64", - "value": 1 - } - ] - }, - { - "timestamp": 1657053117974146, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Retrying GetDriver after error" - }, - { - "key": "error", - "type": "string", - "value": "redis timeout" - }, - { - "key": "level", - "type": "string", - "value": "error" - }, - { - "key": "retry_no", - "type": "int64", - "value": 1 - } - ] - }, - { - "timestamp": 1657053118021660, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Search successful" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "num_drivers", - "type": "int64", - "value": 10 - } - ] - } - ], - "processID": "p1", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "744a8efd50ea90ce", - "flags": 1, - "operationName": "HTTP GET /customer", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "4c3fc8341776759c" - } - ], - "startTime": 1657053117198664, - "duration": 622290, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/customer?customer=731" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117198681, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/customer?customer=731" - } - ] - }, - { - "timestamp": 1657053117198841, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Loading customer" - }, - { - "key": "customer_id", - "type": "string", - "value": "731" - }, - { - "key": "level", - "type": "string", - "value": "info" - } - ] - } - ], - "processID": "p2", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "1d61e407b8daf4e6", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "121a3c72e39f5854" - } - ], - "startTime": 1657053118093292, - "duration": 53154, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=412%2C772" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118093308, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=412%2C772" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "325a42e5de6b0f80", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "32d8d8c3b908a2ca" - } - ], - "startTime": 1657053118125378, - "duration": 44376, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=212%2C736" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118125394, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=212%2C736" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "77c208fe8ab7aeb4", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "6dc8d6be57df9285" - } - ], - "startTime": 1657053118143005, - "duration": 44505, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=308%2C18" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118143020, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=308%2C18" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "5d2a32aa4a976ca5", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "035eee4cc1eb3808" - } - ], - "startTime": 1657053118170194, - "duration": 36117, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=674%2C112" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118170209, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=674%2C112" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "2fef796e9e5e9bd2", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "0636a05b1994f23e" - } - ], - "startTime": 1657053118146907, - "duration": 77084, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=497%2C164" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118146922, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=497%2C164" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "1f0929e09181749d", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "704ea6215ee08f43" - } - ], - "startTime": 1657053118023772, - "duration": 52847, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=476%2C411" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118023786, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=476%2C411" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "2cb0eafd65cec65d", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "4df819ea0e6cf0eb" - } - ], - "startTime": 1657053118022885, - "duration": 38155, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=806%2C7" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118022899, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=806%2C7" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "478ade94c9061f4a", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "3d2240c454065688" - } - ], - "startTime": 1657053118022904, - "duration": 69706, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=41%2C539" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118022920, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=41%2C539" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "5e655614aae91336", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "543b889958d76834" - } - ], - "startTime": 1657053118061923, - "duration": 62826, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=309%2C347" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118062023, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=309%2C347" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "1331c571ba8ce878", - "flags": 1, - "operationName": "HTTP GET /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "54e8230288fef2bd" - } - ], - "startTime": 1657053118077154, - "duration": 64953, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=321%2C807" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118077171, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/route?dropoff=728%2C326&pickup=321%2C807" - } - ] - } - ], - "processID": "p3", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "0636a05b1994f23e", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "5f28b244e59c64d0" - } - ], - "startTime": 1657053118146682, - "duration": 77717, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=497%2C164" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118146698, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118146702, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118146713, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118146714, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118224267, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118224317, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118224400, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "5f28b244e59c64d0", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118146676, - "duration": 77727, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6", - "flags": 1, - "operationName": "HTTP GET /dispatch", - "references": [], - "startTime": 1657053117198075, - "duration": 1026463, - "tags": [ - { - "key": "sampler.type", - "type": "string", - "value": "const" - }, - { - "key": "sampler.param", - "type": "bool", - "value": true - }, - { - "key": "span.kind", - "type": "string", - "value": "server" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "/dispatch?customer=731&nonse=0.39846766354252927" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117198126, - "fields": [ - { - "key": "event", - "type": "string", - "value": "HTTP request received" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "method", - "type": "string", - "value": "GET" - }, - { - "key": "url", - "type": "string", - "value": "/dispatch?customer=731&nonse=0.39846766354252927" - } - ] - }, - { - "timestamp": 1657053117198195, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Getting customer" - }, - { - "key": "customer_id", - "type": "string", - "value": "731" - }, - { - "key": "level", - "type": "string", - "value": "info" - } - ] - }, - { - "timestamp": 1657053117821139, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Found customer" - }, - { - "key": "level", - "type": "string", - "value": "info" - } - ] - }, - { - "timestamp": 1657053117821204, - "fields": [ - { - "key": "event", - "type": "string", - "value": "baggage" - }, - { - "key": "key", - "type": "string", - "value": "customer" - }, - { - "key": "value", - "type": "string", - "value": "Japanese Desserts" - } - ] - }, - { - "timestamp": 1657053117821210, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding nearest drivers" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "location", - "type": "string", - "value": "728,326" - } - ] - }, - { - "timestamp": 1657053118022495, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Found drivers" - }, - { - "key": "level", - "type": "string", - "value": "info" - } - ] - }, - { - "timestamp": 1657053118022571, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "41,539" - } - ] - }, - { - "timestamp": 1657053118022658, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "806,7" - } - ] - }, - { - "timestamp": 1657053118022668, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "476,411" - } - ] - }, - { - "timestamp": 1657053118061291, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "309,347" - } - ] - }, - { - "timestamp": 1657053118076855, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "321,807" - } - ] - }, - { - "timestamp": 1657053118092862, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "412,772" - } - ] - }, - { - "timestamp": 1657053118124978, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "212,736" - } - ] - }, - { - "timestamp": 1657053118142531, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "308,18" - } - ] - }, - { - "timestamp": 1657053118146616, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "497,164" - } - ] - }, - { - "timestamp": 1657053118169995, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Finding route" - }, - { - "key": "dropoff", - "type": "string", - "value": "728,326" - }, - { - "key": "level", - "type": "string", - "value": "info" - }, - { - "key": "pickup", - "type": "string", - "value": "674,112" - } - ] - }, - { - "timestamp": 1657053118224422, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Found routes" - }, - { - "key": "level", - "type": "string", - "value": "info" - } - ] - }, - { - "timestamp": 1657053118224520, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Dispatch successful" - }, - { - "key": "driver", - "type": "string", - "value": "T790535C" - }, - { - "key": "eta", - "type": "string", - "value": "2m0s" - }, - { - "key": "level", - "type": "string", - "value": "info" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "4c3fc8341776759c", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "3e9d67a9f98a7c3b" - } - ], - "startTime": 1657053117198269, - "duration": 622854, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8081/customer?customer=731" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8081" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117198368, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053117198375, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053117198394, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053117198396, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053117821051, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053117821089, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053117821123, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "3e9d67a9f98a7c3b", - "flags": 1, - "operationName": "HTTP GET: /customer", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053117198230, - "duration": 622896, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "704ea6215ee08f43", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "3397b0c6f5ac2ae2" - } - ], - "startTime": 1657053118023071, - "duration": 53769, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=476%2C411" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": false - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": false - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118023088, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118023132, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ConnectStart" - }, - { - "key": "addr", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "network", - "type": "string", - "value": "tcp" - } - ] - }, - { - "timestamp": 1657053118023576, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ConnectDone" - }, - { - "key": "addr", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "network", - "type": "string", - "value": "tcp" - } - ] - }, - { - "timestamp": 1657053118023621, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118023657, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118023659, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118076784, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118076819, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118076837, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "3397b0c6f5ac2ae2", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118023066, - "duration": 53776, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "3d2240c454065688", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "401751934a1a7dc7" - } - ], - "startTime": 1657053118022619, - "duration": 70230, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=41%2C539" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118022652, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118022662, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118022684, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118022685, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118092785, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118092827, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118092849, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "401751934a1a7dc7", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118022611, - "duration": 70239, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "543b889958d76834", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "059078853f011b66" - } - ], - "startTime": 1657053118061528, - "duration": 63437, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=309%2C347" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118061550, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118061556, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118061617, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118061619, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118124913, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118124948, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118124965, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "059078853f011b66", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118061518, - "duration": 63449, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "54e8230288fef2bd", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "4d38e74c31f4eb12" - } - ], - "startTime": 1657053118076932, - "duration": 65561, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=321%2C807" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118076949, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118076953, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118076967, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118076968, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118142299, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118142410, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118142493, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "4d38e74c31f4eb12", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118076924, - "duration": 65594, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "121a3c72e39f5854", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "5de82eacf31c700f" - } - ], - "startTime": 1657053118092948, - "duration": 53631, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=412%2C772" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118092982, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118092986, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118093134, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118093136, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118146545, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118146568, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118146580, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "5de82eacf31c700f", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118092942, - "duration": 53665, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "32d8d8c3b908a2ca", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "1fefefd2921ca361" - } - ], - "startTime": 1657053118125109, - "duration": 44853, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=212%2C736" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118125128, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118125133, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118125151, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118125153, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118169894, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118169946, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118169962, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "1fefefd2921ca361", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118125102, - "duration": 44882, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "6dc8d6be57df9285", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "1c0d8426ab4510f4" - } - ], - "startTime": 1657053118142681, - "duration": 45051, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=308%2C18" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118142700, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118142705, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118142794, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118142796, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118187659, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118187717, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118187733, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "1c0d8426ab4510f4", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118142674, - "duration": 45060, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "035eee4cc1eb3808", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "4e9c00a0b6fd6d02" - } - ], - "startTime": 1657053118170053, - "duration": 36467, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=674%2C112" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118170068, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118170073, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118170085, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118170086, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118206476, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118206507, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118206521, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "4e9c00a0b6fd6d02", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118170047, - "duration": 36476, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "35712b15aeae601b", - "flags": 1, - "operationName": "HTTP GET: /route", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053118022747, - "duration": 38530, - "tags": [ - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "7f1e9a9b718ae1f0", - "flags": 1, - "operationName": "/driver.DriverService/FindNearest", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "68f464e5bf3714b6" - } - ], - "startTime": 1657053117821235, - "duration": 201161, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "gRPC" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "4df819ea0e6cf0eb", - "flags": 1, - "operationName": "HTTP GET", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "35712b15aeae601b" - } - ], - "startTime": 1657053118022753, - "duration": 38521, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "component", - "type": "string", - "value": "net/http" - }, - { - "key": "http.method", - "type": "string", - "value": "GET" - }, - { - "key": "http.url", - "type": "string", - "value": "http://0.0.0.0:8083/route?dropoff=728%2C326&pickup=806%2C7" - }, - { - "key": "http.url", - "type": "string", - "value": "0.0.0.0:8083" - }, - { - "key": "net/http.reused", - "type": "bool", - "value": true - }, - { - "key": "net/http.was_idle", - "type": "bool", - "value": true - }, - { - "key": "http.status_code", - "type": "int64", - "value": 200 - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053118022772, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GetConn" - } - ] - }, - { - "timestamp": 1657053118022779, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotConn" - } - ] - }, - { - "timestamp": 1657053118022795, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteHeaders" - } - ] - }, - { - "timestamp": 1657053118022796, - "fields": [ - { - "key": "event", - "type": "string", - "value": "WroteRequest" - } - ] - }, - { - "timestamp": 1657053118061185, - "fields": [ - { - "key": "event", - "type": "string", - "value": "GotFirstResponseByte" - } - ] - }, - { - "timestamp": 1657053118061255, - "fields": [ - { - "key": "event", - "type": "string", - "value": "PutIdleConn" - } - ] - }, - { - "timestamp": 1657053118061274, - "fields": [ - { - "key": "event", - "type": "string", - "value": "ClosedBody" - } - ] - } - ], - "processID": "p4", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "7abafb05ed52c5e5", - "flags": 1, - "operationName": "SQL SELECT", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "744a8efd50ea90ce" - } - ], - "startTime": 1657053117198860, - "duration": 622064, - "tags": [ - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "peer.service", - "type": "string", - "value": "mysql" - }, - { - "key": "sql.query", - "type": "string", - "value": "SELECT * FROM customer WHERE customer_id=731" - }, - { - "key": "request", - "type": "string", - "value": "1167-18" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117198918, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Waiting for lock behind 2 transactions" - }, - { - "key": "blockers", - "type": "string", - "value": "[1167-16 1167-17]" - } - ] - }, - { - "timestamp": 1657053117524887, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Acquired lock with 0 transactions waiting behind" - } - ] - } - ], - "processID": "p5", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "0feb46b34d54e227", - "flags": 1, - "operationName": "FindDriverIDs", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117821788, - "duration": 19604, - "tags": [ - { - "key": "param.location", - "type": "string", - "value": "728,326" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117841286, - "fields": [ - { - "key": "event", - "type": "string", - "value": "Found drivers" - }, - { - "key": "level", - "type": "string", - "value": "info" - } - ] - } - ], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "65fdc6b18363bb47", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117932518, - "duration": 13180, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T758841C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "23f95dffbb4b0a96", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117854214, - "duration": 15162, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T790535C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "20b8fc41adb089fb", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117869391, - "duration": 30708, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T711028C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "error", - "type": "bool", - "value": true - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117900033, - "fields": [ - { - "key": "event", - "type": "string", - "value": "redis timeout" - }, - { - "key": "driver_id", - "type": "string", - "value": "T711028C" - }, - { - "key": "error", - "type": "string", - "value": "redis timeout" - }, - { - "key": "level", - "type": "string", - "value": "error" - } - ] - } - ], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "725daf92af7dfc68", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117900126, - "duration": 10897, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T711028C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "6684d0b952f03e04", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117911031, - "duration": 9638, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T719153C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "50f430e347f413e3", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117920685, - "duration": 11819, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T738916C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "2a609819e14db090", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117985874, - "duration": 12407, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T713393C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "6cac46b01df1eac3", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117945724, - "duration": 28415, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T742757C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "error", - "type": "bool", - "value": true - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [ - { - "timestamp": 1657053117974072, - "fields": [ - { - "key": "event", - "type": "string", - "value": "redis timeout" - }, - { - "key": "driver_id", - "type": "string", - "value": "T742757C" - }, - { - "key": "error", - "type": "string", - "value": "redis timeout" - }, - { - "key": "level", - "type": "string", - "value": "error" - } - ] - } - ], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "1de9e0e4d2197b04", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117974160, - "duration": 11692, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T742757C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "79d48deb1e0a451c", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117998295, - "duration": 10013, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T790386C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "1a799962c0817139", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053118008361, - "duration": 13254, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T753177C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - }, - { - "traceID": "68f464e5bf3714b6", - "spanID": "2fcbdf95d41d62ab", - "flags": 1, - "operationName": "GetDriver", - "references": [ - { - "refType": "CHILD_OF", - "traceID": "68f464e5bf3714b6", - "spanID": "112052eebc933005" - } - ], - "startTime": 1657053117841406, - "duration": 12793, - "tags": [ - { - "key": "param.driverID", - "type": "string", - "value": "T725171C" - }, - { - "key": "span.kind", - "type": "string", - "value": "client" - }, - { - "key": "internal.span.format", - "type": "string", - "value": "proto" - } - ], - "logs": [], - "processID": "p6", - "warnings": null - } - ], - "processes": { - "p1": { - "serviceName": "driver", - "tags": [ - { - "key": "client-uuid", - "type": "string", - "value": "713b91c6a8606de5" - }, - { - "key": "hostname", - "type": "string", - "value": "03ffa89692db" - }, - { - "key": "ip", - "type": "string", - "value": "172.22.0.3" - }, - { - "key": "jaeger.version", - "type": "string", - "value": "Go-2.30.0" - } - ] - }, - "p2": { - "serviceName": "customer", - "tags": [ - { - "key": "client-uuid", - "type": "string", - "value": "6afa792a4d496294" - }, - { - "key": "hostname", - "type": "string", - "value": "03ffa89692db" - }, - { - "key": "ip", - "type": "string", - "value": "172.22.0.3" - }, - { - "key": "jaeger.version", - "type": "string", - "value": "Go-2.30.0" - } - ] - }, - "p3": { - "serviceName": "route", - "tags": [ - { - "key": "client-uuid", - "type": "string", - "value": "615c7b5286f82f9b" - }, - { - "key": "hostname", - "type": "string", - "value": "03ffa89692db" - }, - { - "key": "ip", - "type": "string", - "value": "172.22.0.3" - }, - { - "key": "jaeger.version", - "type": "string", - "value": "Go-2.30.0" - } - ] - }, - "p4": { - "serviceName": "frontend", - "tags": [ - { - "key": "client-uuid", - "type": "string", - "value": "31772d99b34a392c" - }, - { - "key": "hostname", - "type": "string", - "value": "03ffa89692db" - }, - { - "key": "ip", - "type": "string", - "value": "172.22.0.3" - }, - { - "key": "jaeger.version", - "type": "string", - "value": "Go-2.30.0" - } - ] - }, - "p5": { - "serviceName": "mysql", - "tags": [ - { - "key": "client-uuid", - "type": "string", - "value": "35fc49fd8606ce23" - }, - { - "key": "hostname", - "type": "string", - "value": "03ffa89692db" - }, - { - "key": "ip", - "type": "string", - "value": "172.22.0.3" - }, - { - "key": "jaeger.version", - "type": "string", - "value": "Go-2.30.0" - } - ] - }, - "p6": { - "serviceName": "redis", - "tags": [ - { - "key": "client-uuid", - "type": "string", - "value": "76efbe2afdd04d68" - }, - { - "key": "hostname", - "type": "string", - "value": "03ffa89692db" - }, - { - "key": "ip", - "type": "string", - "value": "172.22.0.3" - }, - { - "key": "jaeger.version", - "type": "string", - "value": "Go-2.30.0" - } - ] - } - }, - "warnings": null - } - ], - "total": 0, - "limit": 0, - "offset": 0, - "errors": null -} diff --git a/og/webapp/tsconfig.json b/og/webapp/tsconfig.json deleted file mode 100644 index 3a9aa0b682..0000000000 --- a/og/webapp/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../tsconfig.json", - "include": [ - "../lib", - "./javascript/**/*.tsx", - "./javascript/**/*.ts", - "./javascript/**/*.js", - "./javascript/**/*.jsx" -, "../../public/app/components/Sidebar.spec.tsx", "../../public/app/models/appNames.ts", "../../public/app/models/flamebearer.ts", "../../public/app/models/tags.ts", "../../public/app/models/adhoc.ts", "../../public/app/redux/reducers/continuous/adhoc.ts", "../../public/app/services/serviceDiscovery.ts", "../../public/app/services/exemplarsTestData.ts", "../../public/app/services/TestData.ts", "../../public/app/redux/reducers/tracing.ts", "../../public/app/components/TimelineChart/TimelineChartWrapper.tsx" ], - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@phlare/*": ["./javascript/*"] - } - } -} diff --git a/og/webapp/yarn-error.log b/og/webapp/yarn-error.log deleted file mode 100644 index 9179764f30..0000000000 --- a/og/webapp/yarn-error.log +++ /dev/null @@ -1,22797 +0,0 @@ -Arguments: - /home/eduardo/.fnm/node-versions/v14.17.0/installation/bin/node /home/eduardo/.yarn/bin/yarn.js add -D @types/react-tabs -W - -PATH: - /home/eduardo/.deno/bin:/tmp/fnm_multishell_833064_1647020870705/bin:/home/eduardo/.fnm:/home/eduardo/.config/nvm/14.17.0/bin:/home/eduardo/.cargo/bin:/home/eduardo/.yarn/bin:/home/eduardo/.deno/bin:/tmp/fnm_multishell_5248_1646930355449/bin:/home/eduardo/.fnm:/home/eduardo/.deno/bin:/tmp/fnm_multishell_4123_1646930351786/bin:/home/eduardo/.fnm:/var/lib/snapd/snap/bin/:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/var/lib/snapd/snap/bin:/home/eduardo/.local/bin:/usr/local/go/bin:/home/eduardo/go/bin:/home/eduardo/.krew/bin:/home/eduardo/bin:/home/eduardo/.local/bin:/usr/local/go/bin:/home/eduardo/go/bin:/home/eduardo/.krew/bin:/home/eduardo/bin:/home/eduardo/.local/bin:/usr/local/go/bin:/home/eduardo/go/bin:/home/eduardo/.krew/bin:/home/eduardo/bin - -Yarn version: - 1.22.5 - -Node version: - 14.17.0 - -Platform: - linux x64 - -Trace: - Invariant Violation: expected workspace package to exist for "eslint-config-airbnb-typescript-prettier" - at invariant (/home/eduardo/.yarn/lib/cli.js:2314:15) - at _loop2 (/home/eduardo/.yarn/lib/cli.js:94977:9) - at PackageHoister.init (/home/eduardo/.yarn/lib/cli.js:95036:19) - at PackageLinker.getFlatHoistedTree (/home/eduardo/.yarn/lib/cli.js:48744:20) - at PackageLinker. (/home/eduardo/.yarn/lib/cli.js:48755:27) - at Generator.next () - at step (/home/eduardo/.yarn/lib/cli.js:310:30) - at /home/eduardo/.yarn/lib/cli.js:328:14 - at new Promise () - at new F (/home/eduardo/.yarn/lib/cli.js:5301:28) - -npm manifest: - { - "name": "@pyroscope/webapp", - "version": "1.1.2", - "private": true, - "scripts": { - "test": "echo \"Error: run tests from root\" && exit 1", - "dev": "webpack --config ../scripts/webpack/webpack.dev.ts --watch", - "clean": "rm -rf public/assets && rm -rf public/*.html", - "type-check": "tsc -p tsconfig.json --noEmit", - "build": "yarn run clean && yarn run build:standalone && yarn run build:webapp", - "build:standalone": "webpack --config ../scripts/webpack/webpack.standalone.ts", - "build:webapp": "NODE_ENV=production webpack --config ../scripts/webpack/webpack.prod.ts" - }, - "dependencies": { - "@pyroscope/flamegraph": "^0.1.0", - "@pyroscope/models": "^0.0.2" - } - } - -yarn manifest: - No manifest - -Lockfile: - # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. - # yarn lockfile v1 - - - "@ampproject/remapping@^2.1.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" - integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== - dependencies: - "@jridgewell/trace-mapping" "^0.3.0" - - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - - "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.0.tgz#86850b8597ea6962089770952075dcaabb8dba34" - integrity sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng== - - "@babel/core@7.12.9": - version "7.12.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" - integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.5" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.5" - "@babel/parser" "^7.12.7" - "@babel/template" "^7.12.7" - "@babel/traverse" "^7.12.9" - "@babel/types" "^7.12.7" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - - "@babel/core@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf" - integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.16.7" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - - "@babel/core@7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" - integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.4" - "@babel/helpers" "^7.8.4" - "@babel/parser" "^7.8.4" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.4" - "@babel/types" "^7.8.3" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - - "@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.4.5", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": - version "7.17.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" - integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.17.2" - "@babel/parser" "^7.17.3" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - - "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.16.7", "@babel/generator@^7.17.3", "@babel/generator@^7.7.2", "@babel/generator@^7.8.4": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" - integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== - dependencies: - "@babel/types" "^7.17.0" - jsesc "^2.5.1" - source-map "^0.5.0" - - "@babel/helper-annotate-as-pure@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" - integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" - integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== - dependencies: - "@babel/compat-data" "^7.16.4" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.17.5" - semver "^6.3.0" - - "@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.1": - version "7.17.1" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz#9699f14a88833a7e055ce57dcd3ffdcd25186b21" - integrity sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - - "@babel/helper-create-regexp-features-plugin@^7.16.7": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1" - integrity sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - regexpu-core "^5.0.1" - - "@babel/helper-define-polyfill-provider@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz#3c2f91b7971b9fc11fe779c945c014065dea340e" - integrity sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg== - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - - "@babel/helper-define-polyfill-provider@^0.3.0", "@babel/helper-define-polyfill-provider@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" - integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - - "@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-explode-assignable-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" - integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" - integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== - dependencies: - "@babel/helper-get-function-arity" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/helper-get-function-arity@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" - integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-member-expression-to-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" - integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" - integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/helper-optimise-call-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" - integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-plugin-utils@7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - - "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" - integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== - - "@babel/helper-remap-async-to-generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" - integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-wrap-function" "^7.16.8" - "@babel/types" "^7.16.8" - - "@babel/helper-replace-supers@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" - integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/helper-simple-access@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" - integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" - integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== - dependencies: - "@babel/types" "^7.16.0" - - "@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - - "@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - - "@babel/helper-wrap-function@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" - integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== - dependencies: - "@babel/helper-function-name" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.8" - "@babel/types" "^7.16.8" - - "@babel/helpers@^7.12.5", "@babel/helpers@^7.16.7", "@babel/helpers@^7.17.2", "@babel/helpers@^7.8.4": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" - integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.0" - "@babel/types" "^7.17.0" - - "@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - - "@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.7.0", "@babel/parser@^7.8.4": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" - integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== - - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" - integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" - integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" - - "@babel/plugin-proposal-async-generator-functions@^7.16.7", "@babel/plugin-proposal-async-generator-functions@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" - integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-remap-async-to-generator" "^7.16.8" - "@babel/plugin-syntax-async-generators" "^7.8.4" - - "@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" - integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-proposal-class-static-block@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz#712357570b612106ef5426d13dc433ce0f200c2a" - integrity sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - - "@babel/plugin-proposal-decorators@^7.12.12": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz#c36372ddfe0360cac1ee331a238310bddca11493" - integrity sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.1" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/plugin-syntax-decorators" "^7.17.0" - charcodes "^0.2.0" - - "@babel/plugin-proposal-dynamic-import@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" - integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - - "@babel/plugin-proposal-export-default-from@^7.12.1": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.7.tgz#a40ab158ca55627b71c5513f03d3469026a9e929" - integrity sha512-+cENpW1rgIjExn+o5c8Jw/4BuH4eGKKYvkMB8/0ZxFQ9mC0t4z09VsPIwNg6waF69QYC81zxGeAsREGuqQoKeg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-export-default-from" "^7.16.7" - - "@babel/plugin-proposal-export-namespace-from@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" - integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - - "@babel/plugin-proposal-json-strings@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" - integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-json-strings" "^7.8.3" - - "@babel/plugin-proposal-logical-assignment-operators@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" - integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - - "@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" - integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - - "@babel/plugin-proposal-numeric-separator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" - integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - - "@babel/plugin-proposal-object-rest-spread@7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" - integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.12.1" - - "@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" - integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== - dependencies: - "@babel/compat-data" "^7.17.0" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.16.7" - - "@babel/plugin-proposal-optional-catch-binding@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" - integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - - "@babel/plugin-proposal-optional-chaining@^7.12.7", "@babel/plugin-proposal-optional-chaining@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" - integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - - "@babel/plugin-proposal-private-methods@^7.12.1", "@babel/plugin-proposal-private-methods@^7.16.11", "@babel/plugin-proposal-private-methods@^7.16.7": - version "7.16.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" - integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.10" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-proposal-private-property-in-object@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" - integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - - "@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" - integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - - "@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - - "@babel/plugin-syntax-decorators@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz#a2be3b2c9fe7d78bd4994e790896bc411e2f166d" - integrity sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-export-default-from@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.7.tgz#fa89cf13b60de2c3f79acdc2b52a21174c6de060" - integrity sha512-4C3E4NsrLOgftKaTYTULhHsuQrGv3FHrBzOMDiS7UYKIpgGBkAdawg4h+EI8zPeK9M0fiIIh72hIwsI24K7MbA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - - "@babel/plugin-syntax-flow@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz#202b147e5892b8452bbb0bb269c7ed2539ab8832" - integrity sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - - "@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-jsx@7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926" - integrity sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - - "@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.16.7", "@babel/plugin-syntax-jsx@^7.2.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" - integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - - "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - - "@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - - "@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - - "@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" - integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-arrow-functions@^7.12.1", "@babel/plugin-transform-arrow-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" - integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-async-to-generator@^7.16.7", "@babel/plugin-transform-async-to-generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" - integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-remap-async-to-generator" "^7.16.8" - - "@babel/plugin-transform-block-scoped-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" - integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-block-scoping@^7.12.12", "@babel/plugin-transform-block-scoping@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" - integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" - integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - globals "^11.1.0" - - "@babel/plugin-transform-computed-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" - integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-destructuring@^7.12.1", "@babel/plugin-transform-destructuring@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz#c445f75819641788a27a0a3a759d9df911df6abc" - integrity sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" - integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-duplicate-keys@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" - integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-exponentiation-operator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" - integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-flow-strip-types@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.7.tgz#291fb140c78dabbf87f2427e7c7c332b126964b8" - integrity sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-flow" "^7.16.7" - - "@babel/plugin-transform-for-of@^7.12.1", "@babel/plugin-transform-for-of@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" - integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" - integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== - dependencies: - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" - integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-member-expression-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" - integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-modules-amd@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" - integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== - dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" - - "@babel/plugin-transform-modules-commonjs@^7.16.7", "@babel/plugin-transform-modules-commonjs@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" - integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== - dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" - - "@babel/plugin-transform-modules-systemjs@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" - integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== - dependencies: - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" - - "@babel/plugin-transform-modules-umd@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" - integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== - dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-named-capturing-groups-regex@^7.16.7", "@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" - integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - - "@babel/plugin-transform-new-target@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" - integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-object-super@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" - integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - - "@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" - integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-property-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" - integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-react-display-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" - integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-react-jsx-development@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz#43a00724a3ed2557ed3f276a01a929e6686ac7b8" - integrity sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A== - dependencies: - "@babel/plugin-transform-react-jsx" "^7.16.7" - - "@babel/plugin-transform-react-jsx@^7.12.12", "@babel/plugin-transform-react-jsx@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1" - integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.16.7" - "@babel/types" "^7.17.0" - - "@babel/plugin-transform-react-pure-annotations@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz#232bfd2f12eb551d6d7d01d13fe3f86b45eb9c67" - integrity sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-regenerator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" - integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== - dependencies: - regenerator-transform "^0.14.2" - - "@babel/plugin-transform-reserved-words@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" - integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-runtime@^7.16.4": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz#0a2e08b5e2b2d95c4b1d3b3371a2180617455b70" - integrity sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" - semver "^6.3.0" - - "@babel/plugin-transform-shorthand-properties@^7.12.1", "@babel/plugin-transform-shorthand-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" - integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-spread@^7.12.1", "@babel/plugin-transform-spread@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" - integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - - "@babel/plugin-transform-sticky-regex@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" - integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-template-literals@^7.12.1", "@babel/plugin-transform-template-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" - integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-typeof-symbol@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" - integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-typescript@^7.16.7", "@babel/plugin-transform-typescript@^7.8.3": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" - integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-typescript" "^7.16.7" - - "@babel/plugin-transform-unicode-escapes@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" - integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-unicode-regex@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" - integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/preset-env@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.7.tgz#c491088856d0b3177822a2bf06cb74d76327aa56" - integrity sha512-urX3Cee4aOZbRWOSa3mKPk0aqDikfILuo+C7qq7HY0InylGNZ1fekq9jmlr3pLWwZHF4yD7heQooc2Pow2KMyQ== - dependencies: - "@babel/compat-data" "^7.16.4" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-async-generator-functions" "^7.16.7" - "@babel/plugin-proposal-class-properties" "^7.16.7" - "@babel/plugin-proposal-class-static-block" "^7.16.7" - "@babel/plugin-proposal-dynamic-import" "^7.16.7" - "@babel/plugin-proposal-export-namespace-from" "^7.16.7" - "@babel/plugin-proposal-json-strings" "^7.16.7" - "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" - "@babel/plugin-proposal-numeric-separator" "^7.16.7" - "@babel/plugin-proposal-object-rest-spread" "^7.16.7" - "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-private-methods" "^7.16.7" - "@babel/plugin-proposal-private-property-in-object" "^7.16.7" - "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.16.7" - "@babel/plugin-transform-async-to-generator" "^7.16.7" - "@babel/plugin-transform-block-scoped-functions" "^7.16.7" - "@babel/plugin-transform-block-scoping" "^7.16.7" - "@babel/plugin-transform-classes" "^7.16.7" - "@babel/plugin-transform-computed-properties" "^7.16.7" - "@babel/plugin-transform-destructuring" "^7.16.7" - "@babel/plugin-transform-dotall-regex" "^7.16.7" - "@babel/plugin-transform-duplicate-keys" "^7.16.7" - "@babel/plugin-transform-exponentiation-operator" "^7.16.7" - "@babel/plugin-transform-for-of" "^7.16.7" - "@babel/plugin-transform-function-name" "^7.16.7" - "@babel/plugin-transform-literals" "^7.16.7" - "@babel/plugin-transform-member-expression-literals" "^7.16.7" - "@babel/plugin-transform-modules-amd" "^7.16.7" - "@babel/plugin-transform-modules-commonjs" "^7.16.7" - "@babel/plugin-transform-modules-systemjs" "^7.16.7" - "@babel/plugin-transform-modules-umd" "^7.16.7" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.7" - "@babel/plugin-transform-new-target" "^7.16.7" - "@babel/plugin-transform-object-super" "^7.16.7" - "@babel/plugin-transform-parameters" "^7.16.7" - "@babel/plugin-transform-property-literals" "^7.16.7" - "@babel/plugin-transform-regenerator" "^7.16.7" - "@babel/plugin-transform-reserved-words" "^7.16.7" - "@babel/plugin-transform-shorthand-properties" "^7.16.7" - "@babel/plugin-transform-spread" "^7.16.7" - "@babel/plugin-transform-sticky-regex" "^7.16.7" - "@babel/plugin-transform-template-literals" "^7.16.7" - "@babel/plugin-transform-typeof-symbol" "^7.16.7" - "@babel/plugin-transform-unicode-escapes" "^7.16.7" - "@babel/plugin-transform-unicode-regex" "^7.16.7" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.16.7" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.4.0" - babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.19.1" - semver "^6.3.0" - - "@babel/preset-env@^7.10.4", "@babel/preset-env@^7.12.11": - version "7.16.11" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" - integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== - dependencies: - "@babel/compat-data" "^7.16.8" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-async-generator-functions" "^7.16.8" - "@babel/plugin-proposal-class-properties" "^7.16.7" - "@babel/plugin-proposal-class-static-block" "^7.16.7" - "@babel/plugin-proposal-dynamic-import" "^7.16.7" - "@babel/plugin-proposal-export-namespace-from" "^7.16.7" - "@babel/plugin-proposal-json-strings" "^7.16.7" - "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" - "@babel/plugin-proposal-numeric-separator" "^7.16.7" - "@babel/plugin-proposal-object-rest-spread" "^7.16.7" - "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-private-methods" "^7.16.11" - "@babel/plugin-proposal-private-property-in-object" "^7.16.7" - "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.16.7" - "@babel/plugin-transform-async-to-generator" "^7.16.8" - "@babel/plugin-transform-block-scoped-functions" "^7.16.7" - "@babel/plugin-transform-block-scoping" "^7.16.7" - "@babel/plugin-transform-classes" "^7.16.7" - "@babel/plugin-transform-computed-properties" "^7.16.7" - "@babel/plugin-transform-destructuring" "^7.16.7" - "@babel/plugin-transform-dotall-regex" "^7.16.7" - "@babel/plugin-transform-duplicate-keys" "^7.16.7" - "@babel/plugin-transform-exponentiation-operator" "^7.16.7" - "@babel/plugin-transform-for-of" "^7.16.7" - "@babel/plugin-transform-function-name" "^7.16.7" - "@babel/plugin-transform-literals" "^7.16.7" - "@babel/plugin-transform-member-expression-literals" "^7.16.7" - "@babel/plugin-transform-modules-amd" "^7.16.7" - "@babel/plugin-transform-modules-commonjs" "^7.16.8" - "@babel/plugin-transform-modules-systemjs" "^7.16.7" - "@babel/plugin-transform-modules-umd" "^7.16.7" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" - "@babel/plugin-transform-new-target" "^7.16.7" - "@babel/plugin-transform-object-super" "^7.16.7" - "@babel/plugin-transform-parameters" "^7.16.7" - "@babel/plugin-transform-property-literals" "^7.16.7" - "@babel/plugin-transform-regenerator" "^7.16.7" - "@babel/plugin-transform-reserved-words" "^7.16.7" - "@babel/plugin-transform-shorthand-properties" "^7.16.7" - "@babel/plugin-transform-spread" "^7.16.7" - "@babel/plugin-transform-sticky-regex" "^7.16.7" - "@babel/plugin-transform-template-literals" "^7.16.7" - "@babel/plugin-transform-typeof-symbol" "^7.16.7" - "@babel/plugin-transform-unicode-escapes" "^7.16.7" - "@babel/plugin-transform-unicode-regex" "^7.16.7" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.16.8" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.20.2" - semver "^6.3.0" - - "@babel/preset-flow@^7.12.1": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.16.7.tgz#7fd831323ab25eeba6e4b77a589f680e30581cbd" - integrity sha512-6ceP7IyZdUYQ3wUVqyRSQXztd1YmFHWI4Xv11MIqAlE4WqxBSd/FZ61V9k+TS5Gd4mkHOtQtPp9ymRpxH4y1Ug== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-flow-strip-types" "^7.16.7" - - "@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - - "@babel/preset-react@^7.0.0", "@babel/preset-react@^7.12.10": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" - integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-react-display-name" "^7.16.7" - "@babel/plugin-transform-react-jsx" "^7.16.7" - "@babel/plugin-transform-react-jsx-development" "^7.16.7" - "@babel/plugin-transform-react-pure-annotations" "^7.16.7" - - "@babel/preset-typescript@7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz#90af8690121beecd9a75d0cc26c6be39d1595d13" - integrity sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-typescript" "^7.8.3" - - "@babel/preset-typescript@^7.12.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" - integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-typescript" "^7.16.7" - - "@babel/register@^7.12.1": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.17.0.tgz#8051e0b7cb71385be4909324f072599723a1f084" - integrity sha512-UNZsMAZ7uKoGHo1HlEXfteEOYssf64n/PNLHGqOKq/bgYcu/4LrQWAHJwSCb3BRZK8Hi5gkJdRcwrGTO2wtRCg== - dependencies: - clone-deep "^4.0.1" - find-cache-dir "^2.0.0" - make-dir "^2.1.0" - pirates "^4.0.5" - source-map-support "^0.5.16" - - "@babel/runtime-corejs3@^7.10.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz#fdca2cd05fba63388babe85d349b6801b008fd13" - integrity sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg== - dependencies: - core-js-pure "^3.20.2" - regenerator-runtime "^0.13.4" - - "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.6", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.16.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" - integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== - dependencies: - regenerator-runtime "^0.13.4" - - "@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.3.3", "@babel/template@^7.8.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2", "@babel/traverse@^7.8.4": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" - integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.3" - "@babel/types" "^7.17.0" - debug "^4.1.0" - globals "^11.1.0" - - "@babel/types@^7.0.0", "@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" - integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" - - "@base2/pretty-print-object@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz#371ba8be66d556812dc7fb169ebc3c08378f69d4" - integrity sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA== - - "@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - - "@braintree/sanitize-url@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-5.0.2.tgz#b23080fa35520e993a8a37a0f5bca26aa4650a48" - integrity sha512-NBEJlHWrhQucLhZGHtSxM2loSaNUMajC7KOYJLyfcdW/6goVoff2HoYI3bz8YCDN0wKGbxtUL0gx2dvHpvnWlw== - - "@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - - "@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - - "@cspotcode/source-map-support@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" - integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== - dependencies: - "@cspotcode/source-map-consumer" "0.8.0" - - "@csstools/postcss-color-function@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-1.0.2.tgz#0843fe19be08eeb22e5d2242a6ac06f8b87b9ed2" - integrity sha512-uayvFqfa0hITPwVduxRYNL9YBD/anTqula0tu2llalaxblEd7QPuETSN3gB5PvTYxSfd0d8kS4Fypgo5JaUJ6A== - dependencies: - "@csstools/postcss-progressive-custom-properties" "^1.1.0" - postcss-value-parser "^4.2.0" - - "@csstools/postcss-font-format-keywords@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.0.tgz#7e7df948a83a0dfb7eb150a96e2390ac642356a1" - integrity sha512-oO0cZt8do8FdVBX8INftvIA4lUrKUSCcWUf9IwH9IPWOgKT22oAZFXeHLoDK7nhB2SmkNycp5brxfNMRLIhd6Q== - dependencies: - postcss-value-parser "^4.2.0" - - "@csstools/postcss-hwb-function@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.0.tgz#d6785c1c5ba8152d1d392c66f3a6a446c6034f6d" - integrity sha512-VSTd7hGjmde4rTj1rR30sokY3ONJph1reCBTUXqeW1fKwETPy1x4t/XIeaaqbMbC5Xg4SM/lyXZ2S8NELT2TaA== - dependencies: - postcss-value-parser "^4.2.0" - - "@csstools/postcss-ic-unit@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.0.tgz#f484db59fc94f35a21b6d680d23b0ec69b286b7f" - integrity sha512-i4yps1mBp2ijrx7E96RXrQXQQHm6F4ym1TOD0D69/sjDjZvQ22tqiEvaNw7pFZTUO5b9vWRHzbHzP9+UKuw+bA== - dependencies: - "@csstools/postcss-progressive-custom-properties" "^1.1.0" - postcss-value-parser "^4.2.0" - - "@csstools/postcss-is-pseudo-class@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.0.tgz#219a1c1d84de7d9e9b7e662a57fdc194eac38ea7" - integrity sha512-WnfZlyuh/CW4oS530HBbrKq0G8BKl/bsNr5NMFoubBFzJfvFRGJhplCgIJYWUidLuL3WJ/zhMtDIyNFTqhx63Q== - dependencies: - postcss-selector-parser "^6.0.9" - - "@csstools/postcss-normalize-display-values@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.0.tgz#ce698f688c28517447aedf15a9037987e3d2dc97" - integrity sha512-bX+nx5V8XTJEmGtpWTO6kywdS725t71YSLlxWt78XoHUbELWgoCXeOFymRJmL3SU1TLlKSIi7v52EWqe60vJTQ== - dependencies: - postcss-value-parser "^4.2.0" - - "@csstools/postcss-oklab-function@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.0.1.tgz#a12348eae202d4ded908a06aa92cf19a946b6cec" - integrity sha512-Bnly2FWWSTZX20hDJLYHpurhp1ot+ZGvojLOsrHa9frzOVruOv4oPYMZ6wQomi9KsbZZ+Af/CuRYaGReTyGtEg== - dependencies: - "@csstools/postcss-progressive-custom-properties" "^1.1.0" - postcss-value-parser "^4.2.0" - - "@csstools/postcss-progressive-custom-properties@^1.1.0", "@csstools/postcss-progressive-custom-properties@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.2.0.tgz#7d53b773de50874c3885918dcb10cac97bf66ed5" - integrity sha512-YLpFPK5OaLIRKZhUfnrZPT9s9cmtqltIOg7W6jPcxmiDpnZ4lk+odfufZttOAgcg6IHWvNLgcITSLpJxIQB/qQ== - dependencies: - postcss-value-parser "^4.2.0" - - "@cypress/request@^2.88.10", "@cypress/request@^2.88.6": - version "2.88.10" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce" - integrity sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - http-signature "~1.3.6" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^8.3.2" - - "@cypress/webpack-preprocessor@5.11.0": - version "5.11.0" - resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.11.0.tgz#f616a208b12b83636331d3421caa1574a7e0bd0c" - integrity sha512-0VMEodVAOkYYhCGKQ2wilI28RtISc3rCre9wlFhishwtnT0B1onJJ8fwhWmcT3Y2/K88WP+cyVO2ZaQPcsEFQg== - dependencies: - bluebird "3.7.1" - debug "^4.3.2" - lodash "^4.17.20" - - "@cypress/xvfb@^1.2.4": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" - integrity sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q== - dependencies: - debug "^3.1.0" - lodash.once "^4.1.1" - - "@discoveryjs/json-ext@^0.5.0", "@discoveryjs/json-ext@^0.5.3": - version "0.5.6" - resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f" - integrity sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA== - - "@emotion/babel-plugin@^11.7.1": - version "11.7.2" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0" - integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== - dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/plugin-syntax-jsx" "^7.12.13" - "@babel/runtime" "^7.13.10" - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.5" - "@emotion/serialize" "^1.0.2" - babel-plugin-macros "^2.6.1" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.0.13" - - "@emotion/cache@^10.0.27": - version "10.0.29" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" - integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ== - dependencies: - "@emotion/sheet" "0.9.4" - "@emotion/stylis" "0.8.5" - "@emotion/utils" "0.11.3" - "@emotion/weak-memoize" "0.2.5" - - "@emotion/cache@^11.4.0", "@emotion/cache@^11.7.1": - version "11.7.1" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539" - integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== - dependencies: - "@emotion/memoize" "^0.7.4" - "@emotion/sheet" "^1.1.0" - "@emotion/utils" "^1.0.0" - "@emotion/weak-memoize" "^0.2.5" - stylis "4.0.13" - - "@emotion/core@^10.1.1": - version "10.3.1" - resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.3.1.tgz#4021b6d8b33b3304d48b0bb478485e7d7421c69d" - integrity sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/cache" "^10.0.27" - "@emotion/css" "^10.0.27" - "@emotion/serialize" "^0.11.15" - "@emotion/sheet" "0.9.4" - "@emotion/utils" "0.11.3" - - "@emotion/css@11.7.1": - version "11.7.1" - resolved "https://registry.yarnpkg.com/@emotion/css/-/css-11.7.1.tgz#516b717340d36b0bbd2304ba7e1a090e866f8acc" - integrity sha512-RUUgPlMZunlc7SE5A6Hg+VWRzb2cU6O9xlV78KCFgcnl25s7Qz/20oQg71iKudpLqk7xj0vhbJlwcJJMT0BOZg== - dependencies: - "@emotion/babel-plugin" "^11.7.1" - "@emotion/cache" "^11.7.1" - "@emotion/serialize" "^1.0.0" - "@emotion/sheet" "^1.0.3" - "@emotion/utils" "^1.0.0" - - "@emotion/css@^10.0.27": - version "10.0.27" - resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" - integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw== - dependencies: - "@emotion/serialize" "^0.11.15" - "@emotion/utils" "0.11.3" - babel-plugin-emotion "^10.0.27" - - "@emotion/hash@0.8.0", "@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== - - "@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.6": - version "0.8.8" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== - dependencies: - "@emotion/memoize" "0.7.4" - - "@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== - - "@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" - integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== - - "@emotion/react@11.7.1": - version "11.7.1" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.7.1.tgz#3f800ce9b20317c13e77b8489ac4a0b922b2fe07" - integrity sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw== - dependencies: - "@babel/runtime" "^7.13.10" - "@emotion/cache" "^11.7.1" - "@emotion/serialize" "^1.0.2" - "@emotion/sheet" "^1.1.0" - "@emotion/utils" "^1.0.0" - "@emotion/weak-memoize" "^0.2.5" - hoist-non-react-statics "^3.3.1" - - "@emotion/react@^11.1.1": - version "11.8.1" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.8.1.tgz#5358b8c78367063881e26423057c030c57ce52eb" - integrity sha512-XGaie4nRxmtP1BZYBXqC5JGqMYF2KRKKI7vjqNvQxyRpekVAZhb6QqrElmZCAYXH1L90lAelADSVZC4PFsrJ8Q== - dependencies: - "@babel/runtime" "^7.13.10" - "@emotion/babel-plugin" "^11.7.1" - "@emotion/cache" "^11.7.1" - "@emotion/serialize" "^1.0.2" - "@emotion/sheet" "^1.1.0" - "@emotion/utils" "^1.1.0" - "@emotion/weak-memoize" "^0.2.5" - hoist-non-react-statics "^3.3.1" - - "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": - version "0.11.16" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" - integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg== - dependencies: - "@emotion/hash" "0.8.0" - "@emotion/memoize" "0.7.4" - "@emotion/unitless" "0.7.5" - "@emotion/utils" "0.11.3" - csstype "^2.5.7" - - "@emotion/serialize@^1.0.0", "@emotion/serialize@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" - integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== - dependencies: - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.4" - "@emotion/unitless" "^0.7.5" - "@emotion/utils" "^1.0.0" - csstype "^3.0.2" - - "@emotion/sheet@0.9.4": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" - integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== - - "@emotion/sheet@^1.0.3", "@emotion/sheet@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" - integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== - - "@emotion/styled-base@^10.3.0": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.3.0.tgz#9aa2c946100f78b47316e4bc6048321afa6d4e36" - integrity sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/is-prop-valid" "0.8.8" - "@emotion/serialize" "^0.11.15" - "@emotion/utils" "0.11.3" - - "@emotion/styled@^10.0.27": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.3.0.tgz#8ee959bf75730789abb5f67f7c3ded0c30aec876" - integrity sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ== - dependencies: - "@emotion/styled-base" "^10.3.0" - babel-plugin-emotion "^10.0.27" - - "@emotion/stylis@0.8.5": - version "0.8.5" - resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" - integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== - - "@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.5": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== - - "@emotion/utils@0.11.3": - version "0.11.3" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" - integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== - - "@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf" - integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ== - - "@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5": - version "0.2.5" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" - integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== - - "@formatjs/ecma402-abstract@1.11.3": - version "1.11.3" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.3.tgz#f25276dfd4ef3dac90da667c3961d8aa9732e384" - integrity sha512-kP/Buv5vVFMAYLHNvvUzr0lwRTU0u2WTy44Tqwku1X3C3lJ5dKqDCYVqA8wL+Y19Bq+MwHgxqd5FZJRCIsLRyQ== - dependencies: - "@formatjs/intl-localematcher" "0.2.24" - tslib "^2.1.0" - - "@formatjs/fast-memoize@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz#e6f5aee2e4fd0ca5edba6eba7668e2d855e0fc21" - integrity sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg== - dependencies: - tslib "^2.1.0" - - "@formatjs/icu-messageformat-parser@2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.18.tgz#b09e8f16b88e988fd125e7c5810300e8a6dd2c42" - integrity sha512-vquIzsAJJmZ5jWVH8dEgUKcbG4yu3KqtyPet+q35SW5reLOvblkfeCXTRW2TpIwNXzdVqsJBwjbTiRiSU9JxwQ== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/icu-skeleton-parser" "1.3.5" - tslib "^2.1.0" - - "@formatjs/icu-skeleton-parser@1.3.5": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.5.tgz#babc93a1c36383cf87cbb3d2f2145d26c2f7cb40" - integrity sha512-Nhyo2/6kG7ZfgeEfo02sxviOuBcvtzH6SYUharj3DLCDJH3A/4OxkKcmx/2PWGX4bc6iSieh+FA94CsKDxnZBQ== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - tslib "^2.1.0" - - "@formatjs/intl-localematcher@0.2.24": - version "0.2.24" - resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.24.tgz#b49fd753c0f54421f26a3c1d0e9cf98a3966e78f" - integrity sha512-K/HRGo6EMnCbhpth/y3u4rW4aXkmQNqRe1L2G+Y5jNr3v0gYhvaucV8WixNju/INAMbPBlbsRBRo/nfjnoOnxQ== - dependencies: - tslib "^2.1.0" - - "@fortawesome/fontawesome-common-types@^0.2.30", "@fortawesome/fontawesome-common-types@^0.2.36", "@fortawesome/fontawesome-common-types@~0.2.36": - version "0.2.36" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz#b44e52db3b6b20523e0c57ef8c42d315532cb903" - integrity sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg== - - "@fortawesome/fontawesome-free@~5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.14.0.tgz#a371e91029ebf265015e64f81bfbf7d228c9681f" - integrity sha512-OfdMsF+ZQgdKHP9jUbmDcRrP0eX90XXrsXIdyjLbkmSBzmMXPABB8eobUJtivaupucYaByz6WNe1PI1JuYm3qA== - - "@fortawesome/fontawesome-svg-core@~1.2.30": - version "1.2.36" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz#4f2ea6f778298e0c47c6524ce2e7fd58eb6930e3" - integrity sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.36" - - "@fortawesome/free-brands-svg-icons@~5.15.1": - version "5.15.4" - resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz#ec8a44dd383bcdd58aa7d1c96f38251e6fec9733" - integrity sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.36" - - "@fortawesome/free-regular-svg-icons@~5.15.2": - version "5.15.4" - resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz#b97edab436954333bbeac09cfc40c6a951081a02" - integrity sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.36" - - "@fortawesome/free-solid-svg-icons@~5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.14.0.tgz#970453f5e8c4915ad57856c3a0252ac63f6fec18" - integrity sha512-M933RDM8cecaKMWDSk3FRYdnzWGW7kBBlGNGfvqLVwcwhUPNj9gcw+xZMrqBdRqxnSXdl3zWzTCNNGEtFUq67Q== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.30" - - "@fortawesome/react-fontawesome@~0.1.11": - version "0.1.17" - resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.17.tgz#06fc06cb1a721e38e5b50b4a1cb851e9b9c77d7a" - integrity sha512-dX43Z5IvMaW7fwzU8farosYjKNGfRb2HB/DgjVBHeJZ/NSnuuaujPPx0YOdcAq+n3mqn70tyCde2HM1mqbhiuw== - dependencies: - prop-types "^15.8.1" - - "@gar/promisify@^1.0.1": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" - integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== - - "@grafana/aws-sdk@0.0.31": - version "0.0.31" - resolved "https://registry.yarnpkg.com/@grafana/aws-sdk/-/aws-sdk-0.0.31.tgz#ddc7f5e3f2f35e4ad5c43fdf3e8efe64c5a5303a" - integrity sha512-AUgw19cAnwkg2QTwghlMk7cmLkjph4oQtH5S57hjX6XywlbUF3SXCoMwTXlqfM6oeBPVelCJ4zM9imtmBQFAVQ== - - "@grafana/data@8.4.1", "@grafana/data@^8.3.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@grafana/data/-/data-8.4.1.tgz#05df01ff641ff257395691b4b25c9334f550ba05" - integrity sha512-gmWwkiGaG/Pp5CAuhAwd/Jq6ntIXptB88AGb0MXaQjnfdjMxbkKkSftlgQgh3D9SgX0VaUKMIUfuh7ZH8Dmk7g== - dependencies: - "@braintree/sanitize-url" "5.0.2" - "@grafana/schema" "8.4.1" - "@types/d3-interpolate" "^1.4.0" - d3-interpolate "1.4.0" - date-fns "2.28.0" - eventemitter3 "4.0.7" - lodash "4.17.21" - marked "4.0.10" - moment "2.29.1" - moment-timezone "0.5.34" - ol "6.12.0" - papaparse "5.3.1" - react "17.0.2" - react-dom "17.0.2" - regenerator-runtime "0.13.9" - rxjs "7.5.1" - tslib "2.3.1" - uplot "1.6.19" - xss "1.0.10" - - "@grafana/e2e-selectors@8.4.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@grafana/e2e-selectors/-/e2e-selectors-8.4.1.tgz#56b56a198d47755f0c963f10783bd8956e316c57" - integrity sha512-V5HwNj6hQbx/yD2+8vMTLaIYMtXsoiM79lsxyafwN2KSBJtTPXjwsN8Ei63VAMh3Y00yL9cGZ77DxsXxdQUYrQ== - dependencies: - "@grafana/tsconfig" "^1.0.0-rc1" - tslib "2.3.1" - typescript "4.4.4" - - "@grafana/e2e@^8.3.2": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@grafana/e2e/-/e2e-8.4.1.tgz#0c44b244f58d7160422ea29d82e6e8255b29f2ff" - integrity sha512-0s6RZIqp9W89zgMTCNw90TSNK0odZflMmgBRJLIrV2kf+z5u3hPyBP55PDtw343Dxjyji4a6frSXpNaRKC1eNQ== - dependencies: - "@babel/core" "7.16.7" - "@babel/preset-env" "7.16.7" - "@cypress/webpack-preprocessor" "5.11.0" - "@grafana/e2e-selectors" "8.4.1" - "@grafana/tsconfig" "^1.0.0-rc1" - "@mochajs/json-file-reporter" "^1.2.0" - babel-loader "8.2.3" - blink-diff "1.0.13" - chrome-remote-interface "0.31.1" - commander "8.3.0" - cypress "9.3.1" - cypress-file-upload "5.0.8" - devtools-protocol "0.0.927104" - execa "5.1.1" - lodash "4.17.21" - mocha "9.2.0" - resolve-as-bin "2.1.0" - rimraf "3.0.2" - tracelib "1.0.1" - ts-loader "6.2.1" - tslib "2.3.1" - typescript "4.4.4" - uuid "8.3.2" - yaml "^1.8.3" - - "@grafana/runtime@^8.3.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@grafana/runtime/-/runtime-8.4.1.tgz#d2e89dc0bd4d14d6adf55e8d04e13b18225244db" - integrity sha512-z7MrdWSjIAFazF9xwZK4MOCr3H7H5rVhG3T7Qcc6gQrWmpIcEG0B8DHbJtWr/sZDBYhBst8yIUmZ9FHOtsSqnw== - dependencies: - "@grafana/data" "8.4.1" - "@grafana/e2e-selectors" "8.4.1" - "@grafana/ui" "8.4.1" - "@sentry/browser" "6.17.2" - history "4.10.1" - lodash "4.17.21" - react "17.0.2" - react-dom "17.0.2" - rxjs "7.5.1" - systemjs "0.20.19" - tslib "2.3.1" - - "@grafana/schema@8.4.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@grafana/schema/-/schema-8.4.1.tgz#11e78d81c14f9088cf5cc6111a8340af4cea97f0" - integrity sha512-MlqUIYp8xNopCB62fkgNTUFnaWOtDjVyh92UEcfSUr2V+NeecBjgv6P0MEaI3JctdcKlLT0tK5TKTjP6bHZQOg== - dependencies: - tslib "2.3.1" - - "@grafana/slate-react@0.22.10-grafana": - version "0.22.10-grafana" - resolved "https://registry.yarnpkg.com/@grafana/slate-react/-/slate-react-0.22.10-grafana.tgz#53653bbef73530334a2db284129ccd0dfd682fef" - integrity sha512-Dl/Nfft7i6enS1ToWUInv7V3L5UhhtpIdRln+967f5roj+cI+enqOhpP0HY+4rAp6XW0qUVRujqc30KJKID3jg== - dependencies: - debug "^3.1.0" - get-window "^1.1.1" - is-window "^1.0.2" - lodash "^4.1.1" - memoize-one "^4.0.0" - prop-types "^15.5.8" - react-immutable-proptypes "^2.1.0" - selection-is-backward "^1.0.0" - slate-base64-serializer "^0.2.111" - slate-dev-environment "^0.2.2" - slate-hotkeys "^0.2.9" - slate-plain-serializer "^0.7.10" - slate-prop-types "^0.5.41" - slate-react-placeholder "^0.2.8" - tiny-invariant "^1.0.1" - tiny-warning "^0.0.3" - - "@grafana/tsconfig@^1.0.0-rc1": - version "1.0.0-rc1" - resolved "https://registry.yarnpkg.com/@grafana/tsconfig/-/tsconfig-1.0.0-rc1.tgz#d07ea16755a50cae21000113f30546b61647a200" - integrity sha512-nucKPGyzlSKYSiJk5RA8GzMdVWhdYNdF+Hh65AXxjD9PlY69JKr5wANj8bVdQboag6dgg0BFKqgKPyY+YtV4Iw== - - "@grafana/ui@8.4.1", "@grafana/ui@^8.3.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@grafana/ui/-/ui-8.4.1.tgz#f37764f232a2ec6ff2a7a3070b559dbcaa2654cd" - integrity sha512-FEVWZU8XtSmpH28b2TKNe6wzQ1wLu3tiGjOdNSqbPkLRzOgEhtxIUoyUEiPAMapCw7KfU9wUq/YUZhGYDqu8Mw== - dependencies: - "@emotion/css" "11.7.1" - "@emotion/react" "11.7.1" - "@grafana/aws-sdk" "0.0.31" - "@grafana/data" "8.4.1" - "@grafana/e2e-selectors" "8.4.1" - "@grafana/schema" "8.4.1" - "@grafana/slate-react" "0.22.10-grafana" - "@monaco-editor/react" "4.3.1" - "@popperjs/core" "2.11.2" - "@react-aria/button" "3.3.4" - "@react-aria/dialog" "3.1.4" - "@react-aria/focus" "3.5.0" - "@react-aria/menu" "3.3.0" - "@react-aria/overlays" "3.7.3" - "@react-stately/menu" "3.2.3" - "@sentry/browser" "6.17.2" - ansicolor "1.1.95" - calculate-size "1.1.1" - classnames "2.3.1" - core-js "3.20.2" - d3 "5.15.0" - date-fns "2.28.0" - hoist-non-react-statics "3.3.2" - immutable "4.0.0" - is-hotkey "0.2.0" - jquery "3.6.0" - lodash "4.17.21" - memoize-one "6.0.0" - moment "2.29.1" - monaco-editor "^0.31.1" - ol "6.12.0" - prismjs "1.26.0" - rc-cascader "3.2.1" - rc-drawer "4.4.3" - rc-slider "9.7.5" - rc-time-picker "^3.7.3" - react "17.0.2" - react-beautiful-dnd "13.1.0" - react-calendar "3.6.0" - react-colorful "5.5.1" - react-custom-scrollbars-2 "4.4.0" - react-dom "17.0.2" - react-dropzone "11.5.1" - react-highlight-words "0.17.0" - react-hook-form "7.5.3" - react-inlinesvg "2.3.0" - react-popper "2.2.5" - react-router-dom "^5.2.0" - react-select "5.2.1" - react-select-event "^5.1.0" - react-table "7.7.0" - react-transition-group "4.4.2" - react-use "17.3.2" - react-window "1.8.6" - rxjs "7.5.1" - slate "0.47.8" - slate-plain-serializer "0.7.10" - tinycolor2 "1.4.2" - tslib "2.3.1" - uplot "1.6.19" - uuid "8.3.2" - - "@hutson/parse-repository-url@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" - integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== - - "@internationalized/date@3.0.0-alpha.3": - version "3.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.0.0-alpha.3.tgz#ebd4a10001b1aa6f32f5a6b82ee98cb8c1334cb3" - integrity sha512-lfUzsXEXNLSR5zmBlwBlNcawrJ8V+u9+JCyoTX76KAEuiHlKtk5wE7S0fMf1WllFHWdrENqy7LbN00FC3HhADQ== - dependencies: - "@babel/runtime" "^7.6.2" - - "@internationalized/message@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.0.5.tgz#1c7c621ec8cbebb307c23bc2e05769bb3d636552" - integrity sha512-DMQ9nQHr9XlP8Z0gCCaQ1j8ReuVGW5YrV+ZEMQLoGlHAg+mVILlZPIAgwB/5l3hi6xUIGQovMqpnGT3AypX1ig== - dependencies: - "@babel/runtime" "^7.6.2" - intl-messageformat "^9.6.12" - - "@internationalized/number@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.0.5.tgz#08b797b8eaad7c69d21d6f6d63d0dfd7b51f4cb4" - integrity sha512-NDplomyqMnwEWaD/53yYNTbksLaEGc1tvVLEy/RnLKsJW2aMrDCMNjX84FnPU9i6+CoiTKmv89J9ihKihxuVUg== - dependencies: - "@babel/runtime" "^7.6.2" - - "@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - - "@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - - "@jest/console@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" - integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^27.5.1" - jest-util "^27.5.1" - slash "^3.0.0" - - "@jest/core@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" - integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/reporters" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.8.1" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^27.5.1" - jest-config "^27.5.1" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-resolve-dependencies "^27.5.1" - jest-runner "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - jest-watcher "^27.5.1" - micromatch "^4.0.4" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - - "@jest/environment@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" - integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== - dependencies: - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - - "@jest/fake-timers@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" - integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== - dependencies: - "@jest/types" "^27.5.1" - "@sinonjs/fake-timers" "^8.0.1" - "@types/node" "*" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-util "^27.5.1" - - "@jest/globals@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" - integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/types" "^27.5.1" - expect "^27.5.1" - - "@jest/reporters@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" - integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-haste-map "^27.5.1" - jest-resolve "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^8.1.0" - - "@jest/source-map@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" - integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.9" - source-map "^0.6.0" - - "@jest/test-result@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" - integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== - dependencies: - "@jest/console" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - - "@jest/test-sequencer@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" - integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== - dependencies: - "@jest/test-result" "^27.5.1" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-runtime "^27.5.1" - - "@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" - integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.6.2" - babel-plugin-istanbul "^6.0.0" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-regex-util "^26.0.0" - jest-util "^26.6.2" - micromatch "^4.0.2" - pirates "^4.0.1" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - - "@jest/transform@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" - integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^27.5.1" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-regex-util "^27.5.1" - jest-util "^27.5.1" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - - "@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - - "@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - - "@jridgewell/resolve-uri@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" - integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== - - "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.11" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" - integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== - - "@jridgewell/trace-mapping@^0.3.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" - integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - - "@juggle/resize-observer@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" - integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== - - "@lerna/add@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" - integrity sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng== - dependencies: - "@lerna/bootstrap" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - npm-package-arg "^8.1.0" - p-map "^4.0.0" - pacote "^11.2.6" - semver "^7.3.4" - - "@lerna/bootstrap@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" - integrity sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/has-npm-version" "4.0.0" - "@lerna/npm-install" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - get-port "^5.1.1" - multimatch "^5.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - read-package-tree "^5.3.1" - semver "^7.3.4" - - "@lerna/changed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" - integrity sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - - "@lerna/check-working-tree@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" - integrity sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q== - dependencies: - "@lerna/collect-uncommitted" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/validation-error" "4.0.0" - - "@lerna/child-process@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" - integrity sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q== - dependencies: - chalk "^4.1.0" - execa "^5.0.0" - strong-log-transformer "^2.1.0" - - "@lerna/clean@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" - integrity sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - - "@lerna/cli@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" - integrity sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA== - dependencies: - "@lerna/global-options" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - yargs "^16.2.0" - - "@lerna/collect-uncommitted@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" - integrity sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g== - dependencies: - "@lerna/child-process" "4.0.0" - chalk "^4.1.0" - npmlog "^4.1.2" - - "@lerna/collect-updates@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" - integrity sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/describe-ref" "4.0.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - slash "^3.0.0" - - "@lerna/command@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" - integrity sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/project" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/write-log-file" "4.0.0" - clone-deep "^4.0.1" - dedent "^0.7.0" - execa "^5.0.0" - is-ci "^2.0.0" - npmlog "^4.1.2" - - "@lerna/conventional-commits@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" - integrity sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw== - dependencies: - "@lerna/validation-error" "4.0.0" - conventional-changelog-angular "^5.0.12" - conventional-changelog-core "^4.2.2" - conventional-recommended-bump "^6.1.0" - fs-extra "^9.1.0" - get-stream "^6.0.0" - lodash.template "^4.5.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - semver "^7.3.4" - - "@lerna/create-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" - integrity sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig== - dependencies: - cmd-shim "^4.1.0" - fs-extra "^9.1.0" - npmlog "^4.1.2" - - "@lerna/create@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" - integrity sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - globby "^11.0.2" - init-package-json "^2.0.2" - npm-package-arg "^8.1.0" - p-reduce "^2.1.0" - pacote "^11.2.6" - pify "^5.0.0" - semver "^7.3.4" - slash "^3.0.0" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - whatwg-url "^8.4.0" - yargs-parser "20.2.4" - - "@lerna/describe-ref@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" - integrity sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - - "@lerna/diff@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" - integrity sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/validation-error" "4.0.0" - npmlog "^4.1.2" - - "@lerna/exec@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" - integrity sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - - "@lerna/filter-options@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" - integrity sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/filter-packages" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - - "@lerna/filter-packages@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" - integrity sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA== - dependencies: - "@lerna/validation-error" "4.0.0" - multimatch "^5.0.0" - npmlog "^4.1.2" - - "@lerna/get-npm-exec-opts@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" - integrity sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ== - dependencies: - npmlog "^4.1.2" - - "@lerna/get-packed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" - integrity sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w== - dependencies: - fs-extra "^9.1.0" - ssri "^8.0.1" - tar "^6.1.0" - - "@lerna/github-client@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" - integrity sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw== - dependencies: - "@lerna/child-process" "4.0.0" - "@octokit/plugin-enterprise-rest" "^6.0.1" - "@octokit/rest" "^18.1.0" - git-url-parse "^11.4.4" - npmlog "^4.1.2" - - "@lerna/gitlab-client@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" - integrity sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA== - dependencies: - node-fetch "^2.6.1" - npmlog "^4.1.2" - whatwg-url "^8.4.0" - - "@lerna/global-options@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" - integrity sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ== - - "@lerna/has-npm-version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" - integrity sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg== - dependencies: - "@lerna/child-process" "4.0.0" - semver "^7.3.4" - - "@lerna/import@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" - integrity sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - p-map-series "^2.1.0" - - "@lerna/info@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" - integrity sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/output" "4.0.0" - envinfo "^7.7.4" - - "@lerna/init@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" - integrity sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - write-json-file "^4.3.0" - - "@lerna/link@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" - integrity sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - p-map "^4.0.0" - slash "^3.0.0" - - "@lerna/list@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" - integrity sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - - "@lerna/listable@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" - integrity sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ== - dependencies: - "@lerna/query-graph" "4.0.0" - chalk "^4.1.0" - columnify "^1.5.4" - - "@lerna/log-packed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" - integrity sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ== - dependencies: - byte-size "^7.0.0" - columnify "^1.5.4" - has-unicode "^2.0.1" - npmlog "^4.1.2" - - "@lerna/npm-conf@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" - integrity sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw== - dependencies: - config-chain "^1.1.12" - pify "^5.0.0" - - "@lerna/npm-dist-tag@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" - integrity sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw== - dependencies: - "@lerna/otplease" "4.0.0" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - - "@lerna/npm-install@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" - integrity sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - fs-extra "^9.1.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - signal-exit "^3.0.3" - write-pkg "^4.0.0" - - "@lerna/npm-publish@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" - integrity sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w== - dependencies: - "@lerna/otplease" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - fs-extra "^9.1.0" - libnpmpublish "^4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - read-package-json "^3.0.0" - - "@lerna/npm-run-script@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" - integrity sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - npmlog "^4.1.2" - - "@lerna/otplease@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" - integrity sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw== - dependencies: - "@lerna/prompt" "4.0.0" - - "@lerna/output@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" - integrity sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w== - dependencies: - npmlog "^4.1.2" - - "@lerna/pack-directory@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" - integrity sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ== - dependencies: - "@lerna/get-packed" "4.0.0" - "@lerna/package" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - npm-packlist "^2.1.4" - npmlog "^4.1.2" - tar "^6.1.0" - temp-write "^4.0.0" - - "@lerna/package-graph@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" - integrity sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw== - dependencies: - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/validation-error" "4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - semver "^7.3.4" - - "@lerna/package-graph@^3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-3.18.5.tgz#c740e2ea3578d059e551633e950690831b941f6b" - integrity sha512-8QDrR9T+dBegjeLr+n9WZTVxUYUhIUjUgZ0gvNxUBN8S1WB9r6H5Yk56/MVaB64tA3oGAN9IIxX6w0WvTfFudA== - dependencies: - "@lerna/prerelease-id-from-version" "3.16.0" - "@lerna/validation-error" "3.13.0" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - semver "^6.2.0" - - "@lerna/package@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-3.16.0.tgz#7e0a46e4697ed8b8a9c14d59c7f890e0d38ba13c" - integrity sha512-2lHBWpaxcBoiNVbtyLtPUuTYEaB/Z+eEqRS9duxpZs6D+mTTZMNy6/5vpEVSCBmzvdYpyqhqaYjjSLvjjr5Riw== - dependencies: - load-json-file "^5.3.0" - npm-package-arg "^6.1.0" - write-pkg "^3.1.0" - - "@lerna/package@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" - integrity sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q== - dependencies: - load-json-file "^6.2.0" - npm-package-arg "^8.1.0" - write-pkg "^4.0.0" - - "@lerna/prerelease-id-from-version@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-3.16.0.tgz#b24bfa789f5e1baab914d7b08baae9b7bd7d83a1" - integrity sha512-qZyeUyrE59uOK8rKdGn7jQz+9uOpAaF/3hbslJVFL1NqF9ELDTqjCPXivuejMX/lN4OgD6BugTO4cR7UTq/sZA== - dependencies: - semver "^6.2.0" - - "@lerna/prerelease-id-from-version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" - integrity sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg== - dependencies: - semver "^7.3.4" - - "@lerna/profiler@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" - integrity sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - upath "^2.0.1" - - "@lerna/project@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" - integrity sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg== - dependencies: - "@lerna/package" "4.0.0" - "@lerna/validation-error" "4.0.0" - cosmiconfig "^7.0.0" - dedent "^0.7.0" - dot-prop "^6.0.1" - glob-parent "^5.1.1" - globby "^11.0.2" - load-json-file "^6.2.0" - npmlog "^4.1.2" - p-map "^4.0.0" - resolve-from "^5.0.0" - write-json-file "^4.3.0" - - "@lerna/project@^3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-3.21.0.tgz#5d784d2d10c561a00f20320bcdb040997c10502d" - integrity sha512-xT1mrpET2BF11CY32uypV2GPtPVm6Hgtha7D81GQP9iAitk9EccrdNjYGt5UBYASl4CIDXBRxwmTTVGfrCx82A== - dependencies: - "@lerna/package" "3.16.0" - "@lerna/validation-error" "3.13.0" - cosmiconfig "^5.1.0" - dedent "^0.7.0" - dot-prop "^4.2.0" - glob-parent "^5.0.0" - globby "^9.2.0" - load-json-file "^5.3.0" - npmlog "^4.1.2" - p-map "^2.1.0" - resolve-from "^4.0.0" - write-json-file "^3.2.0" - - "@lerna/prompt@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" - integrity sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ== - dependencies: - inquirer "^7.3.3" - npmlog "^4.1.2" - - "@lerna/publish@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" - integrity sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/log-packed" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/npm-dist-tag" "4.0.0" - "@lerna/npm-publish" "4.0.0" - "@lerna/otplease" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/pack-directory" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/version" "4.0.0" - fs-extra "^9.1.0" - libnpmaccess "^4.0.1" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - pacote "^11.2.6" - semver "^7.3.4" - - "@lerna/pulse-till-done@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" - integrity sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg== - dependencies: - npmlog "^4.1.2" - - "@lerna/query-graph@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" - integrity sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg== - dependencies: - "@lerna/package-graph" "4.0.0" - - "@lerna/resolve-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" - integrity sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - read-cmd-shim "^2.0.0" - - "@lerna/rimraf-dir@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" - integrity sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - path-exists "^4.0.0" - rimraf "^3.0.2" - - "@lerna/run-lifecycle@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" - integrity sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ== - dependencies: - "@lerna/npm-conf" "4.0.0" - npm-lifecycle "^3.1.5" - npmlog "^4.1.2" - - "@lerna/run-topologically@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" - integrity sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA== - dependencies: - "@lerna/query-graph" "4.0.0" - p-queue "^6.6.2" - - "@lerna/run@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" - integrity sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-run-script" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/timer" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - - "@lerna/symlink-binary@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" - integrity sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/package" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - - "@lerna/symlink-dependencies@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" - integrity sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/resolve-symlink" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - - "@lerna/timer@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" - integrity sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg== - - "@lerna/validation-error@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-3.13.0.tgz#c86b8f07c5ab9539f775bd8a54976e926f3759c3" - integrity sha512-SiJP75nwB8GhgwLKQfdkSnDufAaCbkZWJqEDlKOUPUvVOplRGnfL+BPQZH5nvq2BYSRXsksXWZ4UHVnQZI/HYA== - dependencies: - npmlog "^4.1.2" - - "@lerna/validation-error@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" - integrity sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw== - dependencies: - npmlog "^4.1.2" - - "@lerna/version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" - integrity sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/conventional-commits" "4.0.0" - "@lerna/github-client" "4.0.0" - "@lerna/gitlab-client" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - chalk "^4.1.0" - dedent "^0.7.0" - load-json-file "^6.2.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - p-reduce "^2.1.0" - p-waterfall "^2.1.1" - semver "^7.3.4" - slash "^3.0.0" - temp-write "^4.0.0" - write-json-file "^4.3.0" - - "@lerna/write-log-file@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" - integrity sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg== - dependencies: - npmlog "^4.1.2" - write-file-atomic "^3.0.3" - - "@mapbox/jsonlint-lines-primitives@~2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234" - integrity sha1-zlblOfg1UrWNENZy6k1vya3HsjQ= - - "@mapbox/mapbox-gl-style-spec@^13.20.1": - version "13.23.1" - resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.23.1.tgz#481f41801517b7b52fea595f07d3633a903a250c" - integrity sha512-C6wh8A/5EdsgzhL6y6yl464VCQNIxK0yjrpnvCvchcFe3sNK2RbBw/J9u3m+p8Y6S6MsGuSMt3AkGAXOKMYweQ== - dependencies: - "@mapbox/jsonlint-lines-primitives" "~2.0.2" - "@mapbox/point-geometry" "^0.1.0" - "@mapbox/unitbezier" "^0.0.0" - csscolorparser "~1.0.2" - json-stringify-pretty-compact "^2.0.0" - minimist "^1.2.5" - rw "^1.3.3" - sort-object "^0.3.2" - - "@mapbox/node-pre-gyp@^1.0.0": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz#32abc8a5c624bc4e46c43d84dfb8b26d33a96f58" - integrity sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg== - dependencies: - detect-libc "^1.0.3" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.5" - nopt "^5.0.0" - npmlog "^5.0.1" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.11" - - "@mapbox/point-geometry@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2" - integrity sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI= - - "@mapbox/unitbezier@^0.0.0": - version "0.0.0" - resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz#15651bd553a67b8581fb398810c98ad86a34524e" - integrity sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4= - - "@mdx-js/loader@^1.6.22": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-1.6.22.tgz#d9e8fe7f8185ff13c9c8639c048b123e30d322c4" - integrity sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q== - dependencies: - "@mdx-js/mdx" "1.6.22" - "@mdx-js/react" "1.6.22" - loader-utils "2.0.0" - - "@mdx-js/mdx@1.6.22", "@mdx-js/mdx@^1.6.22": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" - integrity sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA== - dependencies: - "@babel/core" "7.12.9" - "@babel/plugin-syntax-jsx" "7.12.1" - "@babel/plugin-syntax-object-rest-spread" "7.8.3" - "@mdx-js/util" "1.6.22" - babel-plugin-apply-mdx-type-prop "1.6.22" - babel-plugin-extract-import-names "1.6.22" - camelcase-css "2.0.1" - detab "2.0.4" - hast-util-raw "6.0.1" - lodash.uniq "4.5.0" - mdast-util-to-hast "10.0.1" - remark-footnotes "2.0.0" - remark-mdx "1.6.22" - remark-parse "8.0.3" - remark-squeeze-paragraphs "4.0.0" - style-to-object "0.3.0" - unified "9.2.0" - unist-builder "2.0.3" - unist-util-visit "2.0.3" - - "@mdx-js/react@1.6.22", "@mdx-js/react@^1.6.22": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" - integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== - - "@mdx-js/util@1.6.22": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" - integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== - - "@mochajs/json-file-reporter@^1.2.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@mochajs/json-file-reporter/-/json-file-reporter-1.3.0.tgz#63a53bcda93d75f5c5c74af60e45da063931370b" - integrity sha512-evIxpeP8EOixo/T2xh5xYEIzwbEHk8YNJfRUm1KeTs8F3bMjgNn2580Ogze9yisXNlTxu88JiJJYzXjjg5NdLA== - - "@monaco-editor/loader@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.2.0.tgz#373fad69973384624e3d9b60eefd786461a76acd" - integrity sha512-cJVCG/T/KxXgzYnjKqyAgsKDbH9mGLjcXxN6AmwumBwa2rVFkwvGcUj1RJtD0ko4XqLqJxwqsN/Z/KURB5f1OQ== - dependencies: - state-local "^1.0.6" - - "@monaco-editor/react@4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.3.1.tgz#d65bcbf174c39b6d4e7fec43d0cddda82b70a12a" - integrity sha512-f+0BK1PP/W5I50hHHmwf11+Ea92E5H1VZXs+wvKplWUWOfyMa1VVwqkJrXjRvbcqHL+XdIGYWhWNdi4McEvnZg== - dependencies: - "@monaco-editor/loader" "^1.2.0" - prop-types "^15.7.2" - - "@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - - "@mswjs/cookies@^0.1.7": - version "0.1.7" - resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-0.1.7.tgz#d334081b2c51057a61c1dd7b76ca3cac02251651" - integrity sha512-bDg1ReMBx+PYDB4Pk7y1Q07Zz1iKIEUWQpkEXiA2lEWg9gvOZ8UBmGXilCEUvyYoRFlmr/9iXTRR69TrgSwX/Q== - dependencies: - "@types/set-cookie-parser" "^2.4.0" - set-cookie-parser "^2.4.6" - - "@mswjs/interceptors@^0.12.7": - version "0.12.7" - resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.12.7.tgz#0d1cd4cd31a0f663e0455993951201faa09d0909" - integrity sha512-eGjZ3JRAt0Fzi5FgXiV/P3bJGj0NqsN7vBS0J0FO2AQRQ0jCKQS4lEFm4wvlSgKQNfeuc/Vz6d81VtU3Gkx/zg== - dependencies: - "@open-draft/until" "^1.0.3" - "@xmldom/xmldom" "^0.7.2" - debug "^4.3.2" - headers-utils "^3.0.2" - outvariant "^1.2.0" - strict-event-emitter "^0.2.0" - - "@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - - "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - - "@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - - "@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - - "@npmcli/ci-detect@^1.0.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz#18478bbaa900c37bfbd8a2006a6262c62e8b0fe1" - integrity sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q== - - "@npmcli/fs@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" - integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - - "@npmcli/git@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" - integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== - dependencies: - "@npmcli/promise-spawn" "^1.3.2" - lru-cache "^6.0.0" - mkdirp "^1.0.4" - npm-pick-manifest "^6.1.1" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^2.0.2" - - "@npmcli/installed-package-contents@^1.0.6": - version "1.0.7" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" - integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== - dependencies: - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - - "@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - - "@npmcli/node-gyp@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" - integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== - - "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" - integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== - dependencies: - infer-owner "^1.0.4" - - "@npmcli/run-script@^1.8.2": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" - integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== - dependencies: - "@npmcli/node-gyp" "^1.0.2" - "@npmcli/promise-spawn" "^1.3.2" - node-gyp "^7.1.0" - read-package-json-fast "^2.0.1" - - "@octokit/auth-token@^2.4.4": - version "2.5.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" - integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== - dependencies: - "@octokit/types" "^6.0.3" - - "@octokit/core@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" - integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.0" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - - "@octokit/endpoint@^6.0.1": - version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" - integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - - "@octokit/graphql@^4.5.8": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" - integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== - dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - - "@octokit/openapi-types@^11.2.0": - version "11.2.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" - integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== - - "@octokit/plugin-enterprise-rest@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" - integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== - - "@octokit/plugin-paginate-rest@^2.16.8": - version "2.17.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7" - integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw== - dependencies: - "@octokit/types" "^6.34.0" - - "@octokit/plugin-request-log@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" - integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== - - "@octokit/plugin-rest-endpoint-methods@^5.12.0": - version "5.13.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba" - integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA== - dependencies: - "@octokit/types" "^6.34.0" - deprecation "^2.3.1" - - "@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" - integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - - "@octokit/request@^5.6.0": - version "5.6.3" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0" - integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.7" - universal-user-agent "^6.0.0" - - "@octokit/rest@^18.1.0": - version "18.12.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" - integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== - dependencies: - "@octokit/core" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.8" - "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^5.12.0" - - "@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0": - version "6.34.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" - integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== - dependencies: - "@octokit/openapi-types" "^11.2.0" - - "@open-draft/until@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca" - integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q== - - "@petamoriken/float16@^3.4.7": - version "3.6.2" - resolved "https://registry.yarnpkg.com/@petamoriken/float16/-/float16-3.6.2.tgz#a4c986305718d22d0f92f0b89722f6ef6b3fc18e" - integrity sha512-zZnksXtFBqvONcXWuAtSWrl3YXaDbU2ArRCCuzM42mP0GBJclD6e0GC3zEemmrjiMSOHcLPyRC4vOnAsnomJIw== - - "@pmmmwh/react-refresh-webpack-plugin@^0.5.1": - version "0.5.4" - resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz#df0d0d855fc527db48aac93c218a0bf4ada41f99" - integrity sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw== - dependencies: - ansi-html-community "^0.0.8" - common-path-prefix "^3.0.0" - core-js-pure "^3.8.1" - error-stack-parser "^2.0.6" - find-up "^5.0.0" - html-entities "^2.1.0" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - source-map "^0.7.3" - - "@polka/url@^1.0.0-next.20": - version "1.0.0-next.21" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" - integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== - - "@popperjs/core@2.11.2", "@popperjs/core@^2.4.0", "@popperjs/core@^2.5.4", "@popperjs/core@^2.6.0", "@popperjs/core@^2.9.2": - version "2.11.2" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9" - integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA== - - "@react-aria/button@3.3.4": - version "3.3.4" - resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.3.4.tgz#3af6eb4e0a479a76ba7386d541051d1273cd68fa" - integrity sha512-vebTcf9YpwaKCvsca2VWhn6eYPa15OJtMENwaGop72UrL35Oa7xDgU0RG22RAjRjt8HRVlAfLpHkJQW6GBGU3g== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/focus" "^3.5.0" - "@react-aria/interactions" "^3.6.0" - "@react-aria/utils" "^3.9.0" - "@react-stately/toggle" "^3.2.3" - "@react-types/button" "^3.4.1" - - "@react-aria/dialog@3.1.4": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.1.4.tgz#7fe3f33e09b75dcdf598d0523e982262d6c89220" - integrity sha512-OtQGBol3CfcbBpjqXDqXzH5Ygny44PIuyAsZ1e3dfIdtaI+XHsoglyZnvDaVVealIgedHkMubreZnyNYnlzPLg== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/focus" "^3.4.1" - "@react-aria/utils" "^3.8.2" - "@react-stately/overlays" "^3.1.3" - "@react-types/dialog" "^3.3.1" - - "@react-aria/focus@3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.5.0.tgz#02b85f97d6114af1eccc0902ce40723b626cb7f9" - integrity sha512-Eib75Q6QgQdn8VVVByg5Vipaaj/C//8Bs++sQY7nkomRx4sdArOnXbDppul3YHP6mRfU9VRLvAigEUlReQF/Xw== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/interactions" "^3.6.0" - "@react-aria/utils" "^3.9.0" - "@react-types/shared" "^3.9.0" - clsx "^1.1.1" - - "@react-aria/focus@^3.4.1", "@react-aria/focus@^3.5.0", "@react-aria/focus@^3.5.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.5.2.tgz#250852f328fdb8317b8aa8b01427cf53b68ffca4" - integrity sha512-7o40oDWvguFOxflOCOe1xioa3z6LewTLPp9liThmVuQYe7DAso8ZV0E+ssxRWlMkI2Td6CJQek1+en5nVPXvfQ== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/interactions" "^3.8.1" - "@react-aria/utils" "^3.11.2" - "@react-types/shared" "^3.11.1" - clsx "^1.1.1" - - "@react-aria/i18n@^3.3.3", "@react-aria/i18n@^3.3.6": - version "3.3.6" - resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.3.6.tgz#94dd8d5de3ce6bba845461230d04189ae9683651" - integrity sha512-GOogCx5UR3RpkJSceQwwenLctaK7tbDP0DKzmaWQv1ZNUg9nr35w65VMq46WIGz2dIQhqydTagZP1Exci1KhkQ== - dependencies: - "@babel/runtime" "^7.6.2" - "@internationalized/date" "3.0.0-alpha.3" - "@internationalized/message" "^3.0.5" - "@internationalized/number" "^3.0.5" - "@react-aria/ssr" "^3.1.2" - "@react-aria/utils" "^3.11.2" - "@react-types/shared" "^3.11.1" - - "@react-aria/interactions@^3.6.0", "@react-aria/interactions@^3.7.0", "@react-aria/interactions@^3.8.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.8.1.tgz#d86aa8fcf93b38e2cf61dda7ef04c9e0a0527056" - integrity sha512-oE6Yo5BTiqInQCTnERMOALwULJy6TbBv+XXEAmifKWBvjbKSb6jN91lhWOruuYZpWAV+eAawHAk/u/KMzwVVEQ== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/utils" "^3.11.2" - "@react-types/shared" "^3.11.1" - - "@react-aria/menu@3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.3.0.tgz#09364a306b3b0dec7f3cf532bfa184a1f4e26da7" - integrity sha512-e/5zlWSwcsUYxH+kLrACPhLxh/Z+8/xvAB90G7xjBble1RusYQ+iH+M2U1n5vqoenZ3vjBpmEDsdo6vHeFeKxQ== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/interactions" "^3.7.0" - "@react-aria/overlays" "^3.7.3" - "@react-aria/selection" "^3.7.0" - "@react-aria/utils" "^3.10.0" - "@react-stately/collections" "^3.3.3" - "@react-stately/menu" "^3.2.3" - "@react-stately/tree" "^3.2.0" - "@react-types/button" "^3.4.1" - "@react-types/menu" "^3.3.0" - "@react-types/shared" "^3.10.0" - - "@react-aria/overlays@3.7.3": - version "3.7.3" - resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.7.3.tgz#b107b1d31c04c538355e566b1034d23e5696c18a" - integrity sha512-N5F/TVJ9KIYgGuOknVMrRnqqzkNKcFos4nxLHQz4TeFZTp4/P+NqEHd/VBmjsSTNEjEuNAivG+U2o4F1NWn/Pw== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/i18n" "^3.3.3" - "@react-aria/interactions" "^3.7.0" - "@react-aria/utils" "^3.10.0" - "@react-aria/visually-hidden" "^3.2.3" - "@react-stately/overlays" "^3.1.3" - "@react-types/button" "^3.4.1" - "@react-types/overlays" "^3.5.1" - dom-helpers "^3.3.1" - - "@react-aria/overlays@^3.7.3": - version "3.7.5" - resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.7.5.tgz#c14c82efd0ad5da500fb9686cbd69f44ea5e847e" - integrity sha512-ZXT2TUqStMWakt9qGW60ImZIqCqmNigXJ2ClM1kSEMBhIH8Z1pwEdlCtf0gyxBXJHOPJInQx06OMwCLmftNH0w== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/i18n" "^3.3.6" - "@react-aria/interactions" "^3.8.1" - "@react-aria/utils" "^3.11.2" - "@react-aria/visually-hidden" "^3.2.5" - "@react-stately/overlays" "^3.1.5" - "@react-types/button" "^3.4.3" - "@react-types/overlays" "^3.5.3" - dom-helpers "^3.3.1" - - "@react-aria/selection@^3.7.0": - version "3.7.3" - resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.7.3.tgz#3c9ed151aa90033a2dbb90d6f0b9bea550e388a0" - integrity sha512-aCaROIXz9Fu3uGVmfz+RaoVNhyOO5cFfU88NqEzr5UPaWlc0Ej3X3RpIPH6U+TuvHkMiXQWnkGeLWu6TSrjP8A== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/focus" "^3.5.2" - "@react-aria/i18n" "^3.3.6" - "@react-aria/interactions" "^3.8.1" - "@react-aria/utils" "^3.11.2" - "@react-stately/collections" "^3.3.6" - "@react-stately/selection" "^3.9.2" - "@react-types/shared" "^3.11.1" - - "@react-aria/ssr@^3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.1.2.tgz#665a6fd56385068c7417922af2d0d71b0618e52d" - integrity sha512-amXY11ImpokvkTMeKRHjsSsG7v1yzzs6yeqArCyBIk60J3Yhgxwx9Cah+Uu/804ATFwqzN22AXIo7SdtIaMP+g== - dependencies: - "@babel/runtime" "^7.6.2" - - "@react-aria/utils@^3.10.0", "@react-aria/utils@^3.11.2", "@react-aria/utils@^3.8.2", "@react-aria/utils@^3.9.0": - version "3.11.2" - resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.11.2.tgz#95747fb362bfcbc591270e5c67b7a38eaa60c187" - integrity sha512-mbOIPJ2zXgSMQTVXUenl8A8oOUvXPQPmlJv1OqkYPXf74yI5MagpWqbekj8t9Mwrbnj87LL3dY39pWjvlHoJ+w== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/ssr" "^3.1.2" - "@react-stately/utils" "^3.4.1" - "@react-types/shared" "^3.11.1" - clsx "^1.1.1" - - "@react-aria/visually-hidden@^3.2.3", "@react-aria/visually-hidden@^3.2.5": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.2.5.tgz#721a465ae094ddea119ff351c03d6aaf503b15fb" - integrity sha512-wHKBGN0BINd3e465YQAN6y/K662g1/bmOR0exh9Re5gXKyH572lFA9SquQDhUAIjkkZhCiVg9otil7z0lrnGsA== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-aria/interactions" "^3.8.1" - "@react-aria/utils" "^3.11.2" - clsx "^1.1.1" - - "@react-hook/debounce@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@react-hook/debounce/-/debounce-3.0.0.tgz#9eea8b5d81d4cb67cd72dd8657b3ff724afc7cad" - integrity sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag== - dependencies: - "@react-hook/latest" "^1.0.2" - - "@react-hook/event@^1.2.1": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@react-hook/event/-/event-1.2.6.tgz#52f91578add934acc1203328ca09ab14fc7ee58e" - integrity sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q== - - "@react-hook/latest@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80" - integrity sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg== - - "@react-hook/passive-layout-effect@^1.2.0": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz#c06dac2d011f36d61259aa1c6df4f0d5e28bc55e" - integrity sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg== - - "@react-hook/resize-observer@^1.2.4": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@react-hook/resize-observer/-/resize-observer-1.2.5.tgz#b59e2300de98bc6ddc6946942f21243cde10f984" - integrity sha512-qa0pPvRxq5VbdI8mMK2apPFsZOckhQ6D3Jc9yLuyHMNhui8yEih4qyFCZBDzzK3ymZS6LAltVSVg3l1Dg9vA0w== - dependencies: - "@juggle/resize-observer" "^3.3.1" - "@react-hook/latest" "^1.0.2" - "@react-hook/passive-layout-effect" "^1.2.0" - "@types/raf-schd" "^4.0.0" - raf-schd "^4.0.2" - - "@react-hook/throttle@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@react-hook/throttle/-/throttle-2.2.0.tgz#d0402714a06e1ba0bc1da1fdf5c3c5cd0e08d45a" - integrity sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg== - dependencies: - "@react-hook/latest" "^1.0.2" - - "@react-hook/window-size@^3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@react-hook/window-size/-/window-size-3.0.7.tgz#00d176e7a8eb55814e161eae34aae20afbcbe35d" - integrity sha512-bK5ed/jN+cxy0s1jt2CelCnUt7jZRseUvPQ22ZJkUl/QDOsD+7CA/6wcqC3c0QweM/fPBRP6uI56TJ48SnlVww== - dependencies: - "@react-hook/debounce" "^3.0.0" - "@react-hook/event" "^1.2.1" - "@react-hook/throttle" "^2.2.0" - - "@react-stately/collections@^3.3.3", "@react-stately/collections@^3.3.6": - version "3.3.6" - resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.3.6.tgz#89ae0309e5e9a9104f286ed5c618919789f16921" - integrity sha512-4gMRKeWdWyFW5N8J1oYpjYa53ALYofoIrv/paAR9mSx4jXS1bzAIRienKtuSrX+uGmGtDKnTISqxipUSx9zXyQ== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-types/shared" "^3.11.1" - - "@react-stately/menu@3.2.3": - version "3.2.3" - resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.2.3.tgz#eb58e3cfc941d49637bac04aa474935f08bc7215" - integrity sha512-r09qH8F+OaH7PTc9t2iAOfeCPy3jSg9uAwlDiGaev3zknM618XafIoQ1sWUNQYecSQ5BWWUyBYh5Vl8i2HnEvw== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-stately/overlays" "^3.1.3" - "@react-stately/utils" "^3.2.2" - "@react-types/menu" "^3.3.0" - "@react-types/shared" "^3.8.0" - - "@react-stately/menu@^3.2.3": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.2.5.tgz#336637198b2c00307522d7d2efc950521e8f908a" - integrity sha512-IA6oeiVQyzHNRtswQgl7QTa47IZ41o2nUS04p34dji3FeFOgzoxZD15rRxawKRLfv5edbbA1QiuYZsLcWDxbOw== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-stately/overlays" "^3.1.5" - "@react-stately/utils" "^3.4.1" - "@react-types/menu" "^3.5.1" - "@react-types/shared" "^3.11.1" - - "@react-stately/overlays@^3.1.3", "@react-stately/overlays@^3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.1.5.tgz#12bf7ca6a180127e260dccc408c23c4cdc1aaf7c" - integrity sha512-Md//mgFBk6toWYWqEvETS8OHStkZUrUz/PyMpRf3o0z/bInJzWtL+FHkCR6dksURJLjMbLH1CADC70GEa2cixA== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-stately/utils" "^3.4.1" - "@react-types/overlays" "^3.5.3" - - "@react-stately/selection@^3.9.2": - version "3.9.2" - resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.9.2.tgz#8d42b556f1e569e030dc4314379e6b16858e896d" - integrity sha512-4jpj50Cr0ncgcyPaPDT5StaML2IMKT3UlNkNzw2rzXSFqZQ+aYWqxDZ3POdZRZt+zKUGZE+Az66MpwD7E1vemw== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-stately/collections" "^3.3.6" - "@react-stately/utils" "^3.4.1" - "@react-types/shared" "^3.11.1" - - "@react-stately/toggle@^3.2.3": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.2.5.tgz#6a560600a6dcfe4e7b05ad0f6bd30a4d5f1474c6" - integrity sha512-xvruQcjVn/3J+8Y2o8uR7KDbFX8WPB+uMtyURbvuQ7WSWzW48iK0UQgPBaV0gbAKyV/mJCl2QdJ9CoxoQ1CKag== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-stately/utils" "^3.4.1" - "@react-types/checkbox" "^3.2.5" - "@react-types/shared" "^3.11.1" - - "@react-stately/tree@^3.2.0": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.2.2.tgz#b37cb5ff7ba972c3d2633e9fe6b2a92441770d97" - integrity sha512-Ow7nCG9TSXEzg8WsSxpWnzhoYEiB5PFlXEEg9JF7INEjEhhLOQvkrt/k59/PB3Qk5WtJIAcn8/lLsYtNQoc7dw== - dependencies: - "@babel/runtime" "^7.6.2" - "@react-stately/collections" "^3.3.6" - "@react-stately/selection" "^3.9.2" - "@react-stately/utils" "^3.4.1" - "@react-types/shared" "^3.11.1" - - "@react-stately/utils@^3.2.2", "@react-stately/utils@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.4.1.tgz#56f049aa1704d338968b5973c796ee606e9c0c62" - integrity sha512-mjFbKklj/W8KRw1CQSpUJxHd7lhUge4i00NwJTwGxbzmiJgsTWlKKS/1rBf48ey9hUBopXT5x5vG/AxQfWTQug== - dependencies: - "@babel/runtime" "^7.6.2" - - "@react-types/button@^3.4.1", "@react-types/button@^3.4.3": - version "3.4.3" - resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.4.3.tgz#3f363e37cb706bc2043f3a9942e48fc810f6aaf4" - integrity sha512-3rP3Nha16g/PUkSA5R22kHNXOdxPLSdegLss9P4anrt8W8lVjrniQErJVFGf/fqYcucBIg2QVPOTnZHhsz8y4g== - dependencies: - "@react-types/shared" "^3.11.1" - - "@react-types/checkbox@^3.2.5": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.2.5.tgz#bc7f89703ba72b1786819bdcac785671de8d4ac2" - integrity sha512-QP1+g/Fu3EageMGI7doWT6t4J/pFKOHoWoQIj3AXrFx6pljX8pA9eRhgTznF4uT+4e34TK/xDoEssPAWq24s2A== - dependencies: - "@react-types/shared" "^3.11.1" - - "@react-types/dialog@^3.3.1": - version "3.3.3" - resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.3.3.tgz#48bf67c35ef0350087e14f3765c0ebc927b18674" - integrity sha512-q30UyrOiycPffd8oovxE6aW0uh83qwMrBSEsmhTRW7dtuiDiLOFmaO+jh8WGc+yq2Wzb4azFfpYkMvBS8Woy9A== - dependencies: - "@react-types/overlays" "^3.5.3" - "@react-types/shared" "^3.11.1" - - "@react-types/menu@^3.3.0", "@react-types/menu@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.5.1.tgz#4382f71937a014ed957942d8927475fabce5185c" - integrity sha512-pEc+cW9wCGHN0tbPNxPFT3wvuKhtwz1usTc4alUz1v5jTn2B8RLKLL7/C9RUdkVwSAYlcl9qr+PgkHBVo8XBug== - dependencies: - "@react-types/overlays" "^3.5.3" - "@react-types/shared" "^3.11.1" - - "@react-types/overlays@^3.5.1", "@react-types/overlays@^3.5.3": - version "3.5.3" - resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.5.3.tgz#6a7b03a4302065baf1733450be9f3dcc0b49d29a" - integrity sha512-V8Muwy+WiX0PyAtUhcBYi64ZlAV08PfDPYuO7vzD9YXypvV2yrXCitYHnibzHt6KDU/bDdeUGp+e5N2AaVFGtQ== - dependencies: - "@react-types/shared" "^3.11.1" - - "@react-types/shared@^3.10.0", "@react-types/shared@^3.11.1", "@react-types/shared@^3.8.0", "@react-types/shared@^3.9.0": - version "3.11.1" - resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.11.1.tgz#fbe4f28b28f2b22461bbe88c4cce5d1d44d3ae64" - integrity sha512-2wwUnvLFsWPiNXK5kiKfS3+k6mtWXAtfp76haIow3OyyFLEezWD9F9ZsCtyjNG+R+JlRcmvQRgRjQaGoeUWLKg== - - "@reduxjs/toolkit@^1.6.2": - version "1.7.2" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.7.2.tgz#b428aaef92582379464f9de698dbb71957eafb02" - integrity sha512-wwr3//Ar8ZhM9bS58O+HCIaMlR4Y6SNHfuszz9hKnQuFIKvwaL3Kmjo6fpDKUOjo4Lv54Yi299ed8rofCJ/Vjw== - dependencies: - immer "^9.0.7" - redux "^4.1.2" - redux-thunk "^2.4.1" - reselect "^4.1.5" - - "@sentry/browser@6.17.2": - version "6.17.2" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.17.2.tgz#8e794b846f43a341068c83420918d896683d903e" - integrity sha512-4Ow5z9GxK5dG9+stBNKb7s6NoxE4wgEcHRmO66QTK4gH2NNmzV4R/aaZ7iDoS/lD86sH0M86jm76dpg9uiJPmw== - dependencies: - "@sentry/core" "6.17.2" - "@sentry/types" "6.17.2" - "@sentry/utils" "6.17.2" - tslib "^1.9.3" - - "@sentry/core@6.17.2": - version "6.17.2" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.17.2.tgz#f218920f269ccdbaee20a092bbc90a71a007cc88" - integrity sha512-Uew0CNMr+QvowrF4EJYjOUgHep/sZJ3l5zevPEELugIgqWBodd+ZDCV3fQFR7cr6KOqx1rMgVrgcKIkLl0l+RA== - dependencies: - "@sentry/hub" "6.17.2" - "@sentry/minimal" "6.17.2" - "@sentry/types" "6.17.2" - "@sentry/utils" "6.17.2" - tslib "^1.9.3" - - "@sentry/hub@6.17.2": - version "6.17.2" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.17.2.tgz#d92accada845fa21fff1b2b491d3c6964851693b" - integrity sha512-CMi6jU920bTwRTmGHjP4u8toOx4gm1dsx+rsxvp+FKzqRwpwoyi9mOw8oEYERVzaqaYceGdFylyRUrjdf0f77g== - dependencies: - "@sentry/types" "6.17.2" - "@sentry/utils" "6.17.2" - tslib "^1.9.3" - - "@sentry/minimal@6.17.2": - version "6.17.2" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.17.2.tgz#3b482a0d76aa33b6c9441dd21acbcc3a113e5120" - integrity sha512-Cdh+iM6QhLKfxwUWWP4mk2K7+EsQj4tuF2dGQke4Zcbp7zQ7wbcMruUcZHiZfvg5kiSYxwNVkH7cXMzcO7AJsg== - dependencies: - "@sentry/hub" "6.17.2" - "@sentry/types" "6.17.2" - tslib "^1.9.3" - - "@sentry/types@6.17.2": - version "6.17.2" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.17.2.tgz#4dde3423db5953e798b19ed29618c28fc7bf2e30" - integrity sha512-UrFLRDz5mn253O8k/XftLxoldF+NyZdkqKLGIQmST5HEVr7ub9nQJ4Y5ZFA3zJYWpraaW8faIbuw+pgetC8hmQ== - - "@sentry/utils@6.17.2": - version "6.17.2" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.17.2.tgz#e8044e753b47f86068053c8d79e4ae61a39b6732" - integrity sha512-ePWtO44KJQwUULOiU86fa1WU3Ird2TH0i39gqB2d3zNS3QyVp9qPlzSdPKSPJ9LdgadzBHw7ikEuE+GY8JTrhA== - dependencies: - "@sentry/types" "6.17.2" - tslib "^1.9.3" - - "@sindresorhus/is@^2.0.0": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-2.1.1.tgz#ceff6a28a5b4867c2dd4a1ba513de278ccbe8bb1" - integrity sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg== - - "@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== - dependencies: - type-detect "4.0.8" - - "@sinonjs/fake-timers@^8.0.1": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" - integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== - dependencies: - "@sinonjs/commons" "^1.7.0" - - "@sitespeed.io/tracium@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@sitespeed.io/tracium/-/tracium-0.3.3.tgz#b497a4a8d5837db1fd9e3053c99b78f6c0e1f53b" - integrity sha512-dNZafjM93Y+F+sfwTO5gTpsGXlnc/0Q+c2+62ViqP3gkMWvHEMSKkaEHgVJLcLg3i/g19GSIPziiKpgyne07Bw== - dependencies: - debug "^4.1.1" - - "@size-limit/file@^6.0.3": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@size-limit/file/-/file-6.0.4.tgz#64681f0e0ec93d69b1d99f0a40bbbcdd2fb7def6" - integrity sha512-SoGUUNEHsZJTDlw6znuMbR0z6apr/NmeEXSFT6iB6gUPyOHIdFtFJpvWeS1vijC7OFQhWHskedB6nBJ6L+bd+A== - dependencies: - semver "7.3.5" - - "@size-limit/time@^6.0.3": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@size-limit/time/-/time-6.0.4.tgz#f186c392c27ecf05dffdd16e6ddeedd2d2014f17" - integrity sha512-HA/YUsLi9KL/oMol1EmkFlwmxZa9OSkrfJxtGMsm9t3as/1Z/URmiaoMPKjOfaOEMZnnh2kgGRKZWwTSvPFqyg== - dependencies: - estimo "^2.2.8" - react "^17.0.2" - - "@storybook/addon-actions@6.4.19", "@storybook/addon-actions@^6.3.12": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-6.4.19.tgz#10631d9c0a6669810264ea7fac3bff7201553084" - integrity sha512-GpSvP8xV8GfNkmtGJjfCgaOx6mbjtyTK0aT9FqX9pU0s+KVMmoCTrBh43b7dWrwxxas01yleBK9VpYggzhi/Fw== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.19" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - polished "^4.0.5" - prop-types "^15.7.2" - react-inspector "^5.1.0" - regenerator-runtime "^0.13.7" - telejson "^5.3.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - uuid-browser "^3.1.0" - - "@storybook/addon-backgrounds@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-backgrounds/-/addon-backgrounds-6.4.19.tgz#76435e2037824bb3a6fed9f7d51b9df34fae8af2" - integrity sha512-yn8MTE7lctO48Rdw+DmmA1wKdf5eyAbA/vrug5ske/U2WPgGc65sApzwT8BItZfuyAMjuT5RnCWwd7o6hGRgGQ== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.19" - core-js "^3.8.2" - global "^4.4.0" - memoizerific "^1.11.3" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - - "@storybook/addon-controls@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-6.4.19.tgz#1ebf74f7b0843ea0eccd319f5295dfa48947a975" - integrity sha512-JHi5z9i6NsgQLfG5WOeQE1AyOrM+QJLrjT+uOYx40bq+OC1yWHH7qHiphPP8kjJJhCZlaQk1qqXYkkQXgaeHSw== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-common" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/node-logger" "6.4.19" - "@storybook/store" "6.4.19" - "@storybook/theming" "6.4.19" - core-js "^3.8.2" - lodash "^4.17.21" - ts-dedent "^2.0.0" - - "@storybook/addon-docs@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-6.4.19.tgz#229deabc74ea478c34fee96b85edb73da439680e" - integrity sha512-OEPyx/5ZXmZOPqIAWoPjlIP8Q/YfNjAmBosA8tmA8t5KCSiq/vpLcAvQhxqK6n0wk/B8Xp67Z8RpLfXjU8R3tw== - dependencies: - "@babel/core" "^7.12.10" - "@babel/generator" "^7.12.11" - "@babel/parser" "^7.12.11" - "@babel/plugin-transform-react-jsx" "^7.12.12" - "@babel/preset-env" "^7.12.11" - "@jest/transform" "^26.6.2" - "@mdx-js/loader" "^1.6.22" - "@mdx-js/mdx" "^1.6.22" - "@mdx-js/react" "^1.6.22" - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/builder-webpack4" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/csf-tools" "6.4.19" - "@storybook/node-logger" "6.4.19" - "@storybook/postinstall" "6.4.19" - "@storybook/preview-web" "6.4.19" - "@storybook/source-loader" "6.4.19" - "@storybook/store" "6.4.19" - "@storybook/theming" "6.4.19" - acorn "^7.4.1" - acorn-jsx "^5.3.1" - acorn-walk "^7.2.0" - core-js "^3.8.2" - doctrine "^3.0.0" - escodegen "^2.0.0" - fast-deep-equal "^3.1.3" - global "^4.4.0" - html-tags "^3.1.0" - js-string-escape "^1.0.1" - loader-utils "^2.0.0" - lodash "^4.17.21" - nanoid "^3.1.23" - p-limit "^3.1.0" - prettier ">=2.2.1 <=2.3.0" - prop-types "^15.7.2" - react-element-to-jsx-string "^14.3.4" - regenerator-runtime "^0.13.7" - remark-external-links "^8.0.0" - remark-slug "^6.0.0" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - - "@storybook/addon-essentials@^6.3.12": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-essentials/-/addon-essentials-6.4.19.tgz#20f6d65270d1f15830fb0631dfcc935fddb95137" - integrity sha512-vbV8sjepMVEuwhTDBHjO3E6vXluG7RiEeozV1QVuS9lGhjQdvUPdZ9rDNUcP6WHhTdEkS/ffTMaGIy1v8oZd7g== - dependencies: - "@storybook/addon-actions" "6.4.19" - "@storybook/addon-backgrounds" "6.4.19" - "@storybook/addon-controls" "6.4.19" - "@storybook/addon-docs" "6.4.19" - "@storybook/addon-measure" "6.4.19" - "@storybook/addon-outline" "6.4.19" - "@storybook/addon-toolbars" "6.4.19" - "@storybook/addon-viewport" "6.4.19" - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/node-logger" "6.4.19" - core-js "^3.8.2" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - - "@storybook/addon-links@^6.3.12": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-6.4.19.tgz#001f26c4ffc7d36fd6018b8a137449948b337869" - integrity sha512-ebFHYlGDQkHSmI5QEJb1NxGNToVOLgjKkxXUe+JXX7AfHvrWiXVrN/57aOtBPZzj4h2jRPRTZgwR5glhPIlfEQ== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.19" - "@types/qs" "^6.9.5" - core-js "^3.8.2" - global "^4.4.0" - prop-types "^15.7.2" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - - "@storybook/addon-measure@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-6.4.19.tgz#cd648a3d07b84505863f6d9918c6023a2921a596" - integrity sha512-PXeU0AlpnGEvnzBQ6snkzmlIpwE0ci8LdFtL1Vz1V1Xk5fbuETWYuEkPuk1oZ7L9igB9cfT32SyJlE5MC1iaGg== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - global "^4.4.0" - - "@storybook/addon-outline@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-outline/-/addon-outline-6.4.19.tgz#07990749de4286c525593cc74d49fbb120f7cf22" - integrity sha512-7ZDXo8qrms6dx0KRP9PInXIie82h5g9XCNrGOUdfZkQPvgofJVj0kNv6p+WOiGiaVfKPC5KMgIofqzBTFV+k6Q== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - global "^4.4.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - - "@storybook/addon-toolbars@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-toolbars/-/addon-toolbars-6.4.19.tgz#75a8d531c0f7bfda1c6c97d19bf95fdd2ad54d3f" - integrity sha512-2UtuX9yB1rD/CAZv1etnOnunfPTvsEKEg/J2HYMKE1lhenWC5muIUXvDXCXvwDC65WviPJ56nFNKaKK1Zz7JDg== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/theming" "6.4.19" - core-js "^3.8.2" - regenerator-runtime "^0.13.7" - - "@storybook/addon-viewport@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-6.4.19.tgz#08702f5c2103c8ec5bc69344c06b85553949d274" - integrity sha512-T1hdImxbLj8suQSTbp6HSA1LLHOlqaNK5jjnqzEOoAxY0O8LNPXMJ2jKIeT2fPQ0v+tWGU3tbwf+3xFq0parVQ== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/theming" "6.4.19" - core-js "^3.8.2" - global "^4.4.0" - memoizerific "^1.11.3" - prop-types "^15.7.2" - regenerator-runtime "^0.13.7" - - "@storybook/addons@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.4.19.tgz#797d912b8b5a86cd6e0d31fa4c42d1f80808a432" - integrity sha512-QNyRYhpqmHV8oJxxTBdkRlLSbDFhpBvfvMfIrIT1UXb/eemdBZTaCGVvXZ9UixoEEI7f8VwAQ44IvkU5B1509w== - dependencies: - "@storybook/api" "6.4.19" - "@storybook/channels" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.19" - "@storybook/theming" "6.4.19" - "@types/webpack-env" "^1.16.0" - core-js "^3.8.2" - global "^4.4.0" - regenerator-runtime "^0.13.7" - - "@storybook/api@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/api/-/api-6.4.19.tgz#8000a0e4c52c39b910b4ccc6731419e8e71800ef" - integrity sha512-aDvea+NpQCBjpNp9YidO1Pr7fzzCp15FSdkG+2ihGQfv5raxrN+IIJnGUXecpe71nvlYiB+29UXBVK7AL0j51Q== - dependencies: - "@storybook/channels" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/router" "6.4.19" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.4.19" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - regenerator-runtime "^0.13.7" - store2 "^2.12.0" - telejson "^5.3.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - - "@storybook/builder-webpack4@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/builder-webpack4/-/builder-webpack4-6.4.19.tgz#ca8228639be06e50d5f1555b844dd4177e5068ad" - integrity sha512-wxA6SMH11duc9D53aeVVBwrVRemFIoxHp/dOugkkg6ZZFAb4ZmWzf/ENc3vQIZdZpfNRi7IZIZEOfoHc994cmw== - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-decorators" "^7.12.12" - "@babel/plugin-proposal-export-default-from" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.12" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/preset-env" "^7.12.11" - "@babel/preset-react" "^7.12.10" - "@babel/preset-typescript" "^7.12.7" - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/channel-postmessage" "6.4.19" - "@storybook/channels" "6.4.19" - "@storybook/client-api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-common" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/node-logger" "6.4.19" - "@storybook/preview-web" "6.4.19" - "@storybook/router" "6.4.19" - "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.19" - "@storybook/theming" "6.4.19" - "@storybook/ui" "6.4.19" - "@types/node" "^14.0.10" - "@types/webpack" "^4.41.26" - autoprefixer "^9.8.6" - babel-loader "^8.0.0" - babel-plugin-macros "^2.8.0" - babel-plugin-polyfill-corejs3 "^0.1.0" - case-sensitive-paths-webpack-plugin "^2.3.0" - core-js "^3.8.2" - css-loader "^3.6.0" - file-loader "^6.2.0" - find-up "^5.0.0" - fork-ts-checker-webpack-plugin "^4.1.6" - glob "^7.1.6" - glob-promise "^3.4.0" - global "^4.4.0" - html-webpack-plugin "^4.0.0" - pnp-webpack-plugin "1.6.4" - postcss "^7.0.36" - postcss-flexbugs-fixes "^4.2.1" - postcss-loader "^4.2.0" - raw-loader "^4.0.2" - stable "^0.1.8" - style-loader "^1.3.0" - terser-webpack-plugin "^4.2.3" - ts-dedent "^2.0.0" - url-loader "^4.1.1" - util-deprecate "^1.0.2" - webpack "4" - webpack-dev-middleware "^3.7.3" - webpack-filter-warnings-plugin "^1.2.1" - webpack-hot-middleware "^2.25.1" - webpack-virtual-modules "^0.2.2" - - "@storybook/builder-webpack5@^6.3.12": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/builder-webpack5/-/builder-webpack5-6.4.19.tgz#f9d3cf6e7f7769ec2eba11e226e662e4116da659" - integrity sha512-AWM4YMN1gPaf7jfntqZTCGpIQ1tF6YRU1JtczPG4ox28rTaO6NMfOBi9aRhBre/59pPOh9bF6u2gu/MIHmRW+w== - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-decorators" "^7.12.12" - "@babel/plugin-proposal-export-default-from" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.12" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/preset-env" "^7.12.11" - "@babel/preset-react" "^7.12.10" - "@babel/preset-typescript" "^7.12.7" - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/channel-postmessage" "6.4.19" - "@storybook/channels" "6.4.19" - "@storybook/client-api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-common" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/node-logger" "6.4.19" - "@storybook/preview-web" "6.4.19" - "@storybook/router" "6.4.19" - "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.19" - "@storybook/theming" "6.4.19" - "@types/node" "^14.0.10" - babel-loader "^8.0.0" - babel-plugin-macros "^3.0.1" - babel-plugin-polyfill-corejs3 "^0.1.0" - case-sensitive-paths-webpack-plugin "^2.3.0" - core-js "^3.8.2" - css-loader "^5.0.1" - fork-ts-checker-webpack-plugin "^6.0.4" - glob "^7.1.6" - glob-promise "^3.4.0" - html-webpack-plugin "^5.0.0" - path-browserify "^1.0.1" - process "^0.11.10" - stable "^0.1.8" - style-loader "^2.0.0" - terser-webpack-plugin "^5.0.3" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - webpack "^5.9.0" - webpack-dev-middleware "^4.1.0" - webpack-hot-middleware "^2.25.1" - webpack-virtual-modules "^0.4.1" - - "@storybook/channel-postmessage@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-6.4.19.tgz#5db4e1188aaa9de05fee3ba6a6b7f3b988cade03" - integrity sha512-E5h/itFzQ/6M08LR4kqlgqqmeO3tmavI+nUAlZrkCrotpJFNMHE2i0PQHg0TkFJrRDpYcrwD+AjUW4IwdqrisQ== - dependencies: - "@storybook/channels" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - core-js "^3.8.2" - global "^4.4.0" - qs "^6.10.0" - telejson "^5.3.2" - - "@storybook/channel-websocket@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/channel-websocket/-/channel-websocket-6.4.19.tgz#5b2f34f9089966bab66c55721766d3d1803edf2e" - integrity sha512-cXKwQjIXttfdUyZlcHORelUmJ5nUKswsnCA/qy7IRWpZjD8yQJcNk1dYC+tTHDVqFgdRT89pL0hRRB1rlaaR8Q== - dependencies: - "@storybook/channels" "6.4.19" - "@storybook/client-logger" "6.4.19" - core-js "^3.8.2" - global "^4.4.0" - telejson "^5.3.2" - - "@storybook/channels@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-6.4.19.tgz#095bbaee494bf5b03f7cb92d34626f2f5063cb31" - integrity sha512-EwyoncFvTfmIlfsy8jTfayCxo2XchPkZk/9txipugWSmc057HdklMKPLOHWP0z5hLH0IbVIKXzdNISABm36jwQ== - dependencies: - core-js "^3.8.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - - "@storybook/client-api@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-6.4.19.tgz#131597e160f112f51240a4e407191053e5ed972f" - integrity sha512-OCrT5Um3FDvZnimQKwWtwsaI+5agPwq2i8YiqlofrI/NPMKp0I7DEkCGwE5IRD1Q8BIKqHcMo5tTmfYi0AxyOg== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/channel-postmessage" "6.4.19" - "@storybook/channels" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/store" "6.4.19" - "@types/qs" "^6.9.5" - "@types/webpack-env" "^1.16.0" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - store2 "^2.12.0" - synchronous-promise "^2.0.15" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - - "@storybook/client-logger@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-6.4.19.tgz#b2011ad2fa446cce4a9afdb41974b2a576e9fad2" - integrity sha512-zmg/2wyc9W3uZrvxaW4BfHcr40J0v7AGslqYXk9H+ERLVwIvrR4NhxQFaS6uITjBENyRDxwzfU3Va634WcmdDQ== - dependencies: - core-js "^3.8.2" - global "^4.4.0" - - "@storybook/components@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.4.19.tgz#084ba21f26a3eeab82f45178de6899688eecb2fc" - integrity sha512-q/0V37YAJA7CNc+wSiiefeM9+3XVk8ixBNylY36QCGJgIeGQ5/79vPyUe6K4lLmsQwpmZsIq1s1Ad5+VbboeOA== - dependencies: - "@popperjs/core" "^2.6.0" - "@storybook/client-logger" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/theming" "6.4.19" - "@types/color-convert" "^2.0.0" - "@types/overlayscrollbars" "^1.12.0" - "@types/react-syntax-highlighter" "11.0.5" - color-convert "^2.0.1" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - markdown-to-jsx "^7.1.3" - memoizerific "^1.11.3" - overlayscrollbars "^1.13.1" - polished "^4.0.5" - prop-types "^15.7.2" - react-colorful "^5.1.2" - react-popper-tooltip "^3.1.1" - react-syntax-highlighter "^13.5.3" - react-textarea-autosize "^8.3.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - - "@storybook/core-client@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/core-client/-/core-client-6.4.19.tgz#fc6902c4321ae9e7c2858126172bc0752a84321c" - integrity sha512-rQHRZjhArPleE7/S8ZUolgzwY+hC0smSKX/3PQxO2GcebDjnJj6+iSV3h+aSMHMmTdoCQvjYw9aBpT8scuRe+A== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/channel-postmessage" "6.4.19" - "@storybook/channel-websocket" "6.4.19" - "@storybook/client-api" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/preview-web" "6.4.19" - "@storybook/store" "6.4.19" - "@storybook/ui" "6.4.19" - airbnb-js-shims "^2.2.1" - ansi-to-html "^0.6.11" - core-js "^3.8.2" - global "^4.4.0" - lodash "^4.17.21" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - unfetch "^4.2.0" - util-deprecate "^1.0.2" - - "@storybook/core-common@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-6.4.19.tgz#18e6c6095ebd9a94b074529917c693084921d3ca" - integrity sha512-X1pJJkO48DFxl6iyEemIKqRkJ7j9/cBh3BRBUr+xZHXBvnD0GKDXIocwh0PjSxSC6XSu3UCQnqtKi3PbjRl8Dg== - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-decorators" "^7.12.12" - "@babel/plugin-proposal-export-default-from" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.7" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.12" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/preset-env" "^7.12.11" - "@babel/preset-react" "^7.12.10" - "@babel/preset-typescript" "^7.12.7" - "@babel/register" "^7.12.1" - "@storybook/node-logger" "6.4.19" - "@storybook/semver" "^7.3.2" - "@types/node" "^14.0.10" - "@types/pretty-hrtime" "^1.0.0" - babel-loader "^8.0.0" - babel-plugin-macros "^3.0.1" - babel-plugin-polyfill-corejs3 "^0.1.0" - chalk "^4.1.0" - core-js "^3.8.2" - express "^4.17.1" - file-system-cache "^1.0.5" - find-up "^5.0.0" - fork-ts-checker-webpack-plugin "^6.0.4" - fs-extra "^9.0.1" - glob "^7.1.6" - handlebars "^4.7.7" - interpret "^2.2.0" - json5 "^2.1.3" - lazy-universal-dotenv "^3.0.1" - picomatch "^2.3.0" - pkg-dir "^5.0.0" - pretty-hrtime "^1.0.3" - resolve-from "^5.0.0" - slash "^3.0.0" - telejson "^5.3.2" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - webpack "4" - - "@storybook/core-events@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.4.19.tgz#d2a03156783a3cb9bd9f7ba81a06a798a5c296ae" - integrity sha512-KICzUw6XVQUJzFSCXfvhfHAuyhn4Q5J4IZEfuZkcGJS4ODkrO6tmpdYE5Cfr+so95Nfp0ErWiLUuodBsW9/rtA== - dependencies: - core-js "^3.8.2" - - "@storybook/core-server@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/core-server/-/core-server-6.4.19.tgz#0d1b4b2094749b8bce03e3d01422e14e5fef8e66" - integrity sha512-bKsUB9f7hl5ya2JXxpIrErmbDQjoH39FVbzYZWjMo4t/b7+Xyi6vYadwyWcqlpUQmis09ZaSMv8L/Tw0TuwLAA== - dependencies: - "@discoveryjs/json-ext" "^0.5.3" - "@storybook/builder-webpack4" "6.4.19" - "@storybook/core-client" "6.4.19" - "@storybook/core-common" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/csf-tools" "6.4.19" - "@storybook/manager-webpack4" "6.4.19" - "@storybook/node-logger" "6.4.19" - "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.19" - "@types/node" "^14.0.10" - "@types/node-fetch" "^2.5.7" - "@types/pretty-hrtime" "^1.0.0" - "@types/webpack" "^4.41.26" - better-opn "^2.1.1" - boxen "^5.1.2" - chalk "^4.1.0" - cli-table3 "^0.6.1" - commander "^6.2.1" - compression "^1.7.4" - core-js "^3.8.2" - cpy "^8.1.2" - detect-port "^1.3.0" - express "^4.17.1" - file-system-cache "^1.0.5" - fs-extra "^9.0.1" - globby "^11.0.2" - ip "^1.1.5" - lodash "^4.17.21" - node-fetch "^2.6.1" - pretty-hrtime "^1.0.3" - prompts "^2.4.0" - regenerator-runtime "^0.13.7" - serve-favicon "^2.5.0" - slash "^3.0.0" - telejson "^5.3.3" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - watchpack "^2.2.0" - webpack "4" - ws "^8.2.3" - - "@storybook/core@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/core/-/core-6.4.19.tgz#58dd055bcc0ef335e0e0d3f6eca74b4d4d49eba1" - integrity sha512-55LOQ/h/kf1jMhjN85t/pIEdIwWEG9yV7bdwv3niVvmoypCxyyjn9/QNK0RKYAeDSUtdm6FVoJ6k5CpxWz2d8w== - dependencies: - "@storybook/core-client" "6.4.19" - "@storybook/core-server" "6.4.19" - - "@storybook/csf-tools@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/csf-tools/-/csf-tools-6.4.19.tgz#28bdea11da17501a8bc4e761b821d7721880eaf6" - integrity sha512-gf/zRhGoAVsFwSyV2tc+jeJfZQkxF6QsaZgbUSe24/IUvGFCT/PS/jZq1qy7dECAwrTOfykgu8juyBtj6WhWyw== - dependencies: - "@babel/core" "^7.12.10" - "@babel/generator" "^7.12.11" - "@babel/parser" "^7.12.11" - "@babel/plugin-transform-react-jsx" "^7.12.12" - "@babel/preset-env" "^7.12.11" - "@babel/traverse" "^7.12.11" - "@babel/types" "^7.12.11" - "@mdx-js/mdx" "^1.6.22" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - fs-extra "^9.0.1" - global "^4.4.0" - js-string-escape "^1.0.1" - lodash "^4.17.21" - prettier ">=2.2.1 <=2.3.0" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - - "@storybook/csf@0.0.2--canary.87bc651.0": - version "0.0.2--canary.87bc651.0" - resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.0.2--canary.87bc651.0.tgz#c7b99b3a344117ef67b10137b6477a3d2750cf44" - integrity sha512-ajk1Uxa+rBpFQHKrCcTmJyQBXZ5slfwHVEaKlkuFaW77it8RgbPJp/ccna3sgoi8oZ7FkkOyvv1Ve4SmwFqRqw== - dependencies: - lodash "^4.17.15" - - "@storybook/manager-webpack4@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/manager-webpack4/-/manager-webpack4-6.4.19.tgz#999577afb9b9a57fc478f7c5e5d95d785ea69da3" - integrity sha512-R8ugZjTYqXvlc6gDOcw909L65sIleOmIJLZR+N6/H85MivGXHu39jOwONqB7tVACufRty4FNecn8tEiQL2SAKA== - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/preset-react" "^7.12.10" - "@storybook/addons" "6.4.19" - "@storybook/core-client" "6.4.19" - "@storybook/core-common" "6.4.19" - "@storybook/node-logger" "6.4.19" - "@storybook/theming" "6.4.19" - "@storybook/ui" "6.4.19" - "@types/node" "^14.0.10" - "@types/webpack" "^4.41.26" - babel-loader "^8.0.0" - case-sensitive-paths-webpack-plugin "^2.3.0" - chalk "^4.1.0" - core-js "^3.8.2" - css-loader "^3.6.0" - express "^4.17.1" - file-loader "^6.2.0" - file-system-cache "^1.0.5" - find-up "^5.0.0" - fs-extra "^9.0.1" - html-webpack-plugin "^4.0.0" - node-fetch "^2.6.1" - pnp-webpack-plugin "1.6.4" - read-pkg-up "^7.0.1" - regenerator-runtime "^0.13.7" - resolve-from "^5.0.0" - style-loader "^1.3.0" - telejson "^5.3.2" - terser-webpack-plugin "^4.2.3" - ts-dedent "^2.0.0" - url-loader "^4.1.1" - util-deprecate "^1.0.2" - webpack "4" - webpack-dev-middleware "^3.7.3" - webpack-virtual-modules "^0.2.2" - - "@storybook/manager-webpack5@^6.3.12": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/manager-webpack5/-/manager-webpack5-6.4.19.tgz#161809337b69e6c4ea6a4eb6f881a32760bbeb60" - integrity sha512-hVjWhWAOgWaymBy0HeRskN+MfKLpqLP4Txfw+3Xqg1qplgexV0w2O4BQrS/SNEH4V/1qF9h8XTsk3L3oQIj3Mg== - dependencies: - "@babel/core" "^7.12.10" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/preset-react" "^7.12.10" - "@storybook/addons" "6.4.19" - "@storybook/core-client" "6.4.19" - "@storybook/core-common" "6.4.19" - "@storybook/node-logger" "6.4.19" - "@storybook/theming" "6.4.19" - "@storybook/ui" "6.4.19" - "@types/node" "^14.0.10" - babel-loader "^8.0.0" - case-sensitive-paths-webpack-plugin "^2.3.0" - chalk "^4.1.0" - core-js "^3.8.2" - css-loader "^5.0.1" - express "^4.17.1" - file-system-cache "^1.0.5" - find-up "^5.0.0" - fs-extra "^9.0.1" - html-webpack-plugin "^5.0.0" - node-fetch "^2.6.1" - process "^0.11.10" - read-pkg-up "^7.0.1" - regenerator-runtime "^0.13.7" - resolve-from "^5.0.0" - style-loader "^2.0.0" - telejson "^5.3.2" - terser-webpack-plugin "^5.0.3" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - webpack "^5.9.0" - webpack-dev-middleware "^4.1.0" - webpack-virtual-modules "^0.4.1" - - "@storybook/node-logger@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-6.4.19.tgz#554f9efad4e95ce6fa63222d026f43258293c896" - integrity sha512-hO2Aar3PgPnPtNq2fVgiuGlqo3EEVR6TKVBXMq7foL3tN2k4BQFKLDHbm5qZQQntyYKurKsRUGKPJFPuI1ov/w== - dependencies: - "@types/npmlog" "^4.1.2" - chalk "^4.1.0" - core-js "^3.8.2" - npmlog "^5.0.1" - pretty-hrtime "^1.0.3" - - "@storybook/postinstall@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/postinstall/-/postinstall-6.4.19.tgz#ba9799e30a727e39f51168f9c193aab99ef87bdf" - integrity sha512-/0tHHxyIV82zt1rw4BW70GmrQbDVu9IJPAxOqFzGjC1fNojwJ53mK6FfUsOzbhG5mWk5p0Ip5+zr74moP119AA== - dependencies: - core-js "^3.8.2" - - "@storybook/preview-web@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/preview-web/-/preview-web-6.4.19.tgz#bdfab7b2f760caf72140229dd64fd57617ad000b" - integrity sha512-jqltoBv5j7lvnxEfV9w8dLX9ASWGuvgz97yg8Yo5FqkftEwrHJenyvMGcTgDJKJPorF+wiz/9aIqnmd3LCAcZQ== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/channel-postmessage" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/store" "6.4.19" - ansi-to-html "^0.6.11" - core-js "^3.8.2" - global "^4.4.0" - lodash "^4.17.21" - qs "^6.10.0" - regenerator-runtime "^0.13.7" - synchronous-promise "^2.0.15" - ts-dedent "^2.0.0" - unfetch "^4.2.0" - util-deprecate "^1.0.2" - - "@storybook/react-docgen-typescript-plugin@1.0.2-canary.253f8c1.0": - version "1.0.2-canary.253f8c1.0" - resolved "https://registry.yarnpkg.com/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.2-canary.253f8c1.0.tgz#f2da40e6aae4aa586c2fb284a4a1744602c3c7fa" - integrity sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw== - dependencies: - debug "^4.1.1" - endent "^2.0.1" - find-cache-dir "^3.3.1" - flat-cache "^3.0.4" - micromatch "^4.0.2" - react-docgen-typescript "^2.0.0" - tslib "^2.0.0" - - "@storybook/react@^6.3.12": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-6.4.19.tgz#1707b785b5a65c867e291ede12113e7fd55f8998" - integrity sha512-5b3i8jkVrjQGmcxxxXwCduHPIh+cluWkfeweKeQOe+lW4BR8fuUICo3AMLrYPAtB/UcaJyYkIYmTvF2mkfepFA== - dependencies: - "@babel/preset-flow" "^7.12.1" - "@babel/preset-react" "^7.12.10" - "@pmmmwh/react-refresh-webpack-plugin" "^0.5.1" - "@storybook/addons" "6.4.19" - "@storybook/core" "6.4.19" - "@storybook/core-common" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - "@storybook/node-logger" "6.4.19" - "@storybook/react-docgen-typescript-plugin" "1.0.2-canary.253f8c1.0" - "@storybook/semver" "^7.3.2" - "@storybook/store" "6.4.19" - "@types/webpack-env" "^1.16.0" - babel-plugin-add-react-displayname "^0.0.5" - babel-plugin-named-asset-import "^0.3.1" - babel-plugin-react-docgen "^4.2.1" - core-js "^3.8.2" - global "^4.4.0" - lodash "^4.17.21" - prop-types "^15.7.2" - react-refresh "^0.11.0" - read-pkg-up "^7.0.1" - regenerator-runtime "^0.13.7" - ts-dedent "^2.0.0" - webpack "4" - - "@storybook/router@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-6.4.19.tgz#e653224dd9a521836bbd2610f604f609a2c77af2" - integrity sha512-KWWwIzuyeEIWVezkCihwY2A76Il9tUNg0I410g9qT7NrEsKyqXGRYOijWub7c1GGyNjLqz0jtrrehtixMcJkuA== - dependencies: - "@storybook/client-logger" "6.4.19" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - history "5.0.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - qs "^6.10.0" - react-router "^6.0.0" - react-router-dom "^6.0.0" - ts-dedent "^2.0.0" - - "@storybook/semver@^7.3.2": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@storybook/semver/-/semver-7.3.2.tgz#f3b9c44a1c9a0b933c04e66d0048fcf2fa10dac0" - integrity sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg== - dependencies: - core-js "^3.6.5" - find-up "^4.1.0" - - "@storybook/source-loader@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-6.4.19.tgz#24d134750bc41a13255b2b4a545f2d82613f004f" - integrity sha512-XqTsqddRglvfW7mhyjwoqd/B8L6samcBehhO0OEbsFp6FPWa9eXuObCxtRYIcjcSIe+ksbW3D/54ppEs1L/g1Q== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - estraverse "^5.2.0" - global "^4.4.0" - loader-utils "^2.0.0" - lodash "^4.17.21" - prettier ">=2.2.1 <=2.3.0" - regenerator-runtime "^0.13.7" - - "@storybook/store@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/store/-/store-6.4.19.tgz#bf4031499f4d49909d7b691c03cc5ef1ec00ad74" - integrity sha512-N9/ZjemRHGfT3InPIbqQqc6snkcfnf3Qh9oOr0smbfaVGJol//KOX65kzzobtzFcid0WxtTDZ3HmgFVH+GvuhQ== - dependencies: - "@storybook/addons" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/csf" "0.0.2--canary.87bc651.0" - core-js "^3.8.2" - fast-deep-equal "^3.1.3" - global "^4.4.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - regenerator-runtime "^0.13.7" - slash "^3.0.0" - stable "^0.1.8" - synchronous-promise "^2.0.15" - ts-dedent "^2.0.0" - util-deprecate "^1.0.2" - - "@storybook/theming@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.4.19.tgz#0a6834d91e0b0eadbb10282e7fb2947e2bbf9e9e" - integrity sha512-V4pWmTvAxmbHR6B3jA4hPkaxZPyExHvCToy7b76DpUTpuHihijNDMAn85KhOQYIeL9q14zP/aiz899tOHsOidg== - dependencies: - "@emotion/core" "^10.1.1" - "@emotion/is-prop-valid" "^0.8.6" - "@emotion/styled" "^10.0.27" - "@storybook/client-logger" "6.4.19" - core-js "^3.8.2" - deep-object-diff "^1.1.0" - emotion-theming "^10.0.27" - global "^4.4.0" - memoizerific "^1.11.3" - polished "^4.0.5" - resolve-from "^5.0.0" - ts-dedent "^2.0.0" - - "@storybook/ui@6.4.19": - version "6.4.19" - resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-6.4.19.tgz#1fb9f6cd875ee4937cf9d81ca45d5156800176d1" - integrity sha512-gFwdn5LA2U6oQ4bfUFLyHZnNasGQ01YVdwjbi+l6yjmnckBNtZfJoVTZ1rzGUbxSE9rK48InJRU+latTsr7xAg== - dependencies: - "@emotion/core" "^10.1.1" - "@storybook/addons" "6.4.19" - "@storybook/api" "6.4.19" - "@storybook/channels" "6.4.19" - "@storybook/client-logger" "6.4.19" - "@storybook/components" "6.4.19" - "@storybook/core-events" "6.4.19" - "@storybook/router" "6.4.19" - "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.4.19" - copy-to-clipboard "^3.3.1" - core-js "^3.8.2" - core-js-pure "^3.8.2" - downshift "^6.0.15" - emotion-theming "^10.0.27" - fuse.js "^3.6.1" - global "^4.4.0" - lodash "^4.17.21" - markdown-to-jsx "^7.1.3" - memoizerific "^1.11.3" - polished "^4.0.5" - qs "^6.10.0" - react-draggable "^4.4.3" - react-helmet-async "^1.0.7" - react-sizeme "^3.0.1" - regenerator-runtime "^0.13.7" - resolve-from "^5.0.0" - store2 "^2.12.0" - - "@szhsin/react-menu@^1.10.1": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@szhsin/react-menu/-/react-menu-1.11.0.tgz#3b4929d5cf5bb676eac3dc962da3029080b82bc2" - integrity sha512-kaW/IpcokmyVwX7WGe6ijQI/xQDw5nQXUKyiioy40dm5gt45+Lo7cqGVUoy7Qj8275Q9tgN6hcazWX/DCcYUfQ== - dependencies: - prop-types "^15.7.2" - - "@szmarczak/http-timer@^4.0.0": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" - integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== - dependencies: - defer-to-connect "^2.0.0" - - "@testing-library/cypress@^8.0.0": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@testing-library/cypress/-/cypress-8.0.2.tgz#b13f0ff2424dec4368b6670dfbfb7e43af8eefc9" - integrity sha512-KVdm7n37sg/A4e3wKMD4zUl0NpzzVhx06V9Tf0hZHZ7nrZ4yFva6Zwg2EFF1VzHkEfN/ahUzRtT1qiW+vuWnJw== - dependencies: - "@babel/runtime" "^7.14.6" - "@testing-library/dom" "^8.1.0" - - "@testing-library/dom@>=7", "@testing-library/dom@^8.0.0", "@testing-library/dom@^8.1.0", "@testing-library/dom@^8.7.1": - version "8.11.3" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.11.3.tgz#38fd63cbfe14557021e88982d931e33fb7c1a808" - integrity sha512-9LId28I+lx70wUiZjLvi1DB/WT2zGOxUh46glrSNMaWVx849kKAluezVzZrXJfTKKoQTmEOutLes/bHg4Bj3aA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/runtime" "^7.12.5" - "@types/aria-query" "^4.2.0" - aria-query "^5.0.0" - chalk "^4.1.0" - dom-accessibility-api "^0.5.9" - lz-string "^1.4.4" - pretty-format "^27.0.2" - - "@testing-library/jest-dom@^5.14.1": - version "5.16.2" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.2.tgz#f329b36b44aa6149cd6ced9adf567f8b6aa1c959" - integrity sha512-6ewxs1MXWwsBFZXIk4nKKskWANelkdUehchEOokHsN8X7c2eKXGw+77aRV63UU8f/DTSVUPLaGxdrj4lN7D/ug== - dependencies: - "@babel/runtime" "^7.9.2" - "@types/testing-library__jest-dom" "^5.9.1" - aria-query "^5.0.0" - chalk "^3.0.0" - css "^3.0.0" - css.escape "^1.5.1" - dom-accessibility-api "^0.5.6" - lodash "^4.17.15" - redent "^3.0.0" - - "@testing-library/react@^12.1.1": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.3.tgz#ef26c5f122661ea9b6f672b23dc6b328cadbbf26" - integrity sha512-oCULRXWRrBtC9m6G/WohPo1GLcLesH7T4fuKzRAKn1CWVu9BzXtqLXDDTA6KhFNNtRwLtfSMr20HFl+Qrdrvmg== - dependencies: - "@babel/runtime" "^7.12.5" - "@testing-library/dom" "^8.0.0" - "@types/react-dom" "*" - - "@testing-library/user-event@^13.2.1": - version "13.5.0" - resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295" - integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg== - dependencies: - "@babel/runtime" "^7.12.5" - - "@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - - "@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - - "@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== - - "@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== - - "@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== - - "@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== - - "@types/aria-query@^4.2.0": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" - integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== - - "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": - version "7.1.18" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" - integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - - "@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - - "@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - - "@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" - integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== - dependencies: - "@babel/types" "^7.3.0" - - "@types/body-parser@*": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" - integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== - dependencies: - "@types/connect" "*" - "@types/node" "*" - - "@types/cacheable-request@^6.0.1": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9" - integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA== - dependencies: - "@types/http-cache-semantics" "*" - "@types/keyv" "*" - "@types/node" "*" - "@types/responselike" "*" - - "@types/clean-css@*": - version "4.2.5" - resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.5.tgz#69ce62cc13557c90ca40460133f672dc52ceaf89" - integrity sha512-NEzjkGGpbs9S9fgC4abuBvTpVwE3i+Acu9BBod3PUyjDVZcNsGx61b8r2PphR61QGPnn0JHVs5ey6/I4eTrkxw== - dependencies: - "@types/node" "*" - source-map "^0.6.0" - - "@types/color-convert@*", "@types/color-convert@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-2.0.0.tgz#8f5ee6b9e863dcbee5703f5a517ffb13d3ea4e22" - integrity sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ== - dependencies: - "@types/color-name" "*" - - "@types/color-name@*": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - - "@types/color@^3.0.2": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.3.tgz#e6d8d72b7aaef4bb9fe80847c26c7c786191016d" - integrity sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA== - dependencies: - "@types/color-convert" "*" - - "@types/connect-history-api-fallback@*": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" - integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== - dependencies: - "@types/express-serve-static-core" "*" - "@types/node" "*" - - "@types/connect@*": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== - dependencies: - "@types/node" "*" - - "@types/cookie@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" - integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== - - "@types/copy-webpack-plugin@^6.0.0": - version "6.4.3" - resolved "https://registry.yarnpkg.com/@types/copy-webpack-plugin/-/copy-webpack-plugin-6.4.3.tgz#6604f06a2c9ca4516a453d2e4f87bf844819bccd" - integrity sha512-yk7QO2/WrtkDLcsqQXfjU3EIYzggNHVl5y6gnxfMtCPB+bxVUIUzwb1BNxlk+78wENoh9ZgkVSNqn80T9rqO8w== - dependencies: - "@types/webpack" "^4" - - "@types/d3-color@^1": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-1.4.2.tgz#944f281d04a0f06e134ea96adbb68303515b2784" - integrity sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA== - - "@types/d3-interpolate@^1.4.0": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz#88902a205f682773a517612299a44699285eed7b" - integrity sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg== - dependencies: - "@types/d3-color" "^1" - - "@types/d3-scale@^4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.2.tgz#41be241126af4630524ead9cb1008ab2f0f26e69" - integrity sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA== - dependencies: - "@types/d3-time" "*" - - "@types/d3-time@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819" - integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg== - - "@types/eslint-scope@^3.7.3": - version "3.7.3" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" - integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - - "@types/eslint@*": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.1.tgz#c48251553e8759db9e656de3efc846954ac32304" - integrity sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - - "@types/eslint@^7.28.2": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.29.0.tgz#e56ddc8e542815272720bb0b4ccc2aff9c3e1c78" - integrity sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - - "@types/estree@*", "@types/estree@^0.0.51": - version "0.0.51" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== - - "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": - version "4.17.28" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - - "@types/express@*": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" - integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.18" - "@types/qs" "*" - "@types/serve-static" "*" - - "@types/glob@*", "@types/glob@^7.1.1": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" - integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - - "@types/graceful-fs@^4.1.2": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== - dependencies: - "@types/node" "*" - - "@types/hast@^2.0.0": - version "2.3.4" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" - integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== - dependencies: - "@types/unist" "*" - - "@types/history@^4.7.11": - version "4.7.11" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" - integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== - - "@types/hoist-non-react-statics@^3.3.0": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - - "@types/html-minifier-terser@^5.0.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" - integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w== - - "@types/html-minifier-terser@^6.0.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" - integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== - - "@types/html-minifier@*": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/html-minifier/-/html-minifier-4.0.2.tgz#ea0b927ad0019821a2e9d14ba9c57d105b63cecc" - integrity sha512-4IkmkXJP/25R2fZsCHDX2abztXuQRzUAZq39PfCMz2loLFj8vS9y7aF6vDl58koXSTpsF+eL4Lc5Y4Aww/GCTQ== - dependencies: - "@types/clean-css" "*" - "@types/relateurl" "*" - "@types/uglify-js" "*" - - "@types/html-webpack-plugin@*": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@types/html-webpack-plugin/-/html-webpack-plugin-3.2.6.tgz#07951aaf0fa260dbf626f9644f1d13106d537625" - integrity sha512-U8uJSvlf9lwrKG6sKFnMhqY4qJw2QXad+PHlX9sqEXVUMilVt96aVvFde73tzsdXD+QH9JS6kEytuGO2JcYZog== - dependencies: - "@types/html-minifier" "*" - "@types/tapable" "^1" - "@types/webpack" "^4" - - "@types/http-cache-semantics@*": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" - integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== - - "@types/http-proxy@^1.17.5": - version "1.17.8" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.8.tgz#968c66903e7e42b483608030ee85800f22d03f55" - integrity sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA== - dependencies: - "@types/node" "*" - - "@types/inquirer@^8.1.3": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-8.2.0.tgz#b9566d048f5ff65159f2ed97aff45fe0f00b35ec" - integrity sha512-BNoMetRf3gmkpAlV5we+kxyZTle7YibdOntIZbU5pyIfMdcwy784KfeZDAcuyMznkh5OLa17RVXZOGA5LTlkgQ== - dependencies: - "@types/through" "*" - rxjs "^7.2.0" - - "@types/is-function@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.1.tgz#2d024eace950c836d9e3335a66b97960ae41d022" - integrity sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q== - - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - - "@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - - "@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - - "@types/jest-image-snapshot@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@types/jest-image-snapshot/-/jest-image-snapshot-4.3.1.tgz#1382e9e155d6e29af0a81efce1056aaba92110c9" - integrity sha512-WDdUruGF14C53axe/mNDgQP2YIhtcwXrwmmVP8eOGyfNTVD+FbxWjWR7RTU+lzEy4K6V6+z7nkVDm/auI/r3xQ== - dependencies: - "@types/jest" "*" - "@types/pixelmatch" "*" - ssim.js "^3.1.1" - - "@types/jest@*", "@types/jest@^27.0.2": - version "27.4.0" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.0.tgz#037ab8b872067cae842a320841693080f9cb84ed" - integrity sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ== - dependencies: - jest-diff "^27.0.0" - pretty-format "^27.0.0" - - "@types/jquery@^3.5.13": - version "3.5.13" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.13.tgz#5482d3ee325d5862f77a91c09369ae0a5b082bf3" - integrity sha512-ZxJrup8nz/ZxcU0vantG+TPdboMhB24jad2uSap50zE7Q9rUeYlCF25kFMSmHR33qoeOgqcdHEp3roaookC0Sg== - dependencies: - "@types/sizzle" "*" - - "@types/js-cookie@^2.2.6": - version "2.2.7" - resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" - integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA== - - "@types/js-levenshtein@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz#ba05426a43f9e4e30b631941e0aa17bf0c890ed5" - integrity sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g== - - "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - - "@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - - "@types/keyv@*", "@types/keyv@^3.1.1": - version "3.1.3" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.3.tgz#1c9aae32872ec1f20dcdaee89a9f3ba88f465e41" - integrity sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg== - dependencies: - "@types/node" "*" - - "@types/lodash.debounce@^4.0.6": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz#c5a2326cd3efc46566c47e4c0aa248dc0ee57d60" - integrity sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ== - dependencies: - "@types/lodash" "*" - - "@types/lodash.defaults@^4.2.6": - version "4.2.6" - resolved "https://registry.yarnpkg.com/@types/lodash.defaults/-/lodash.defaults-4.2.6.tgz#4ac29d3dd80a42803397076600f5b129f4aef911" - integrity sha512-JsUJheQIG2Yf/n/QRUMGXT76/7x4tLU5i0kxIPeoOcTIh9yNzdEzCHWbwD8mTf+VncGwYZiho+F2u1pEBsGswA== - dependencies: - "@types/lodash" "*" - - "@types/lodash@*", "@types/lodash@^4.14.176": - version "4.14.178" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" - integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== - - "@types/mdast@^3.0.0": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" - integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== - dependencies: - "@types/unist" "*" - - "@types/mime@^1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" - integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== - - "@types/mini-css-extract-plugin@^2.4.0": - version "2.5.1" - resolved "https://registry.yarnpkg.com/@types/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.1.tgz#c2ab735b353864019a148251e699b7038443bc77" - integrity sha512-evjjtJttaUexgg3au9ZJFy76tV9mySwX3a4Jl82BuormBYluWLRt0xk2urWrhOdPgDWzulRFyotwYOJTmkSgKw== - dependencies: - mini-css-extract-plugin "*" - - "@types/minimatch@*", "@types/minimatch@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== - - "@types/minimist@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== - - "@types/node-fetch@^2.5.7": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" - integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - - "@types/node@*", "@types/node@^17.0.7": - version "17.0.19" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.19.tgz#726171367f404bfbe8512ba608a09ebad810c7e6" - integrity sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA== - - "@types/node@^14.0.10", "@types/node@^14.14.31": - version "14.18.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.12.tgz#0d4557fd3b94497d793efd4e7d92df2f83b4ef24" - integrity sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A== - - "@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== - - "@types/npmlog@^4.1.2": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@types/npmlog/-/npmlog-4.1.4.tgz#30eb872153c7ead3e8688c476054ddca004115f6" - integrity sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ== - - "@types/overlayscrollbars@^1.12.0": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@types/overlayscrollbars/-/overlayscrollbars-1.12.1.tgz#fb637071b545834fb12aea94ee309a2ff4cdc0a8" - integrity sha512-V25YHbSoKQN35UasHf0EKD9U2vcmexRSp78qa8UglxFH8H3D+adEa9zGZwrqpH4TdvqeMrgMqVqsLB4woAryrQ== - - "@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - - "@types/parse5@^5.0.0": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" - integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== - - "@types/pixelmatch@*": - version "5.2.4" - resolved "https://registry.yarnpkg.com/@types/pixelmatch/-/pixelmatch-5.2.4.tgz#ca145cc5ede1388c71c68edf2d1f5190e5ddd0f6" - integrity sha512-HDaSHIAv9kwpMN7zlmwfTv6gax0PiporJOipcrGsVNF3Ba+kryOZc0Pio5pn6NhisgWr7TaajlPEKTbTAypIBQ== - dependencies: - "@types/node" "*" - - "@types/prettier@^2.1.5": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" - integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== - - "@types/pretty-hrtime@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz#72a26101dc567b0d68fd956cf42314556e42d601" - integrity sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ== - - "@types/prismjs@^1.26.0": - version "1.26.0" - resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.26.0.tgz#a1c3809b0ad61c62cac6d4e0c56d610c910b7654" - integrity sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ== - - "@types/prop-types@*": - version "15.7.4" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== - - "@types/q@^1.5.1": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" - integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== - - "@types/qs@*", "@types/qs@^6.9.5": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - - "@types/raf-schd@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/raf-schd/-/raf-schd-4.0.1.tgz#1f9e03736f277fe9c7b82102bf18570a6ee19f82" - integrity sha512-Ha+EnKHFIh9EKW0/XZJPUd3EGDFisEvauaBd4VVCRPKeOqUxNEc9TodiY2Zhk33XCgzJucoFEcaoNcBAPHTQ2A== - - "@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - - "@types/react-datepicker@^4.3.4": - version "4.3.4" - resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.3.4.tgz#1cccf5acfb8672fce08940d1cf69e664500ea63d" - integrity sha512-5nTTz37KdTUgMZ1AAxztMWNtEnIMVRo8oCAEhIv0a6uUqDjvSKaMyPRpBV+8chi6f/A8wlTKJIpojpXca2dx3A== - dependencies: - "@popperjs/core" "^2.9.2" - "@types/react" "*" - date-fns "^2.0.1" - react-popper "^2.2.5" - - "@types/react-dev-utils@^9.0.10": - version "9.0.10" - resolved "https://registry.yarnpkg.com/@types/react-dev-utils/-/react-dev-utils-9.0.10.tgz#92bcfb83b25c9788b124a1598673b6e11727fead" - integrity sha512-kkPY4YbdoEXwf4CZdrEKNEYPHshdRGwHiCixyqaWxmYSj337hMX3YD28+tZkNiV4XUmJ4NevKtgZNbylkLSQ+A== - dependencies: - "@types/eslint" "*" - "@types/express" "*" - "@types/html-webpack-plugin" "*" - "@types/webpack" "^4" - "@types/webpack-dev-server" "3" - - "@types/react-dom@*": - version "17.0.11" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466" - integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q== - dependencies: - "@types/react" "*" - - "@types/react-notifications-component@^3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@types/react-notifications-component/-/react-notifications-component-3.1.1.tgz#85691cb425e266eeda1c82b67ca95b36a6566e86" - integrity sha512-1b8yPkEOS266q1I5QebG4pcP437Nn9rQ/w8pcHF9kISLbU39HrpFilu9Lmg45FOpskowNzOkKyl/yh71FJwfzg== - dependencies: - "@types/react" "*" - - "@types/react-outside-click-handler@^1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@types/react-outside-click-handler/-/react-outside-click-handler-1.3.1.tgz#e4772ba550e1a548468203194d2615d8f06acdf9" - integrity sha512-0BNan5zIIDyO5k9LFSG+60ZxQ/0wf+LTF9BJx3oOUdOaJlZk6RCe52jRB75mlvLLJx2YLa61+NidOwBfptWMKw== - dependencies: - "@types/react" "*" - - "@types/react-redux@^7.1.20": - version "7.1.22" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.22.tgz#0eab76a37ef477cc4b53665aeaf29cb60631b72a" - integrity sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ== - dependencies: - "@types/hoist-non-react-statics" "^3.3.0" - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - redux "^4.0.0" - - "@types/react-router-dom@^5.3.3": - version "5.3.3" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" - integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router" "*" - - "@types/react-router@*": - version "5.1.18" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.18.tgz#c8851884b60bc23733500d86c1266e1cfbbd9ef3" - integrity sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - - "@types/react-syntax-highlighter@11.0.5": - version "11.0.5" - resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.5.tgz#0d546261b4021e1f9d85b50401c0a42acb106087" - integrity sha512-VIOi9i2Oj5XsmWWoB72p3KlZoEbdRAcechJa8Ztebw7bDl2YmR+odxIqhtJGp1q2EozHs02US+gzxJ9nuf56qg== - dependencies: - "@types/react" "*" - - "@types/react-transition-group@^4.4.0": - version "4.4.4" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" - integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== - dependencies: - "@types/react" "*" - - "@types/react@*", "@types/react@^17.0.0": - version "17.0.39" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" - integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - - "@types/react@^15.0.38": - version "15.7.6" - resolved "https://registry.yarnpkg.com/@types/react/-/react-15.7.6.tgz#b5d8c75fa8c7fae0205dfa4c17a173d2d55af930" - integrity sha512-4yVZxPR5+1T1uH1urxsyKqZNTbu9jMIbO8L8BXqUZEMIhilhO3CRwapLxHJp8DGDm7G4tuIyNf9mL6l2LwhL3w== - - "@types/relateurl@*": - version "0.2.29" - resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.29.tgz#68ccecec3d4ffdafb9c577fe764f912afc050fe6" - integrity sha512-QSvevZ+IRww2ldtfv1QskYsqVVVwCKQf1XbwtcyyoRvLIQzfyPhj/C+3+PKzSDRdiyejaiLgnq//XTkleorpLg== - - "@types/responselike@*": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" - integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== - dependencies: - "@types/node" "*" - - "@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== - - "@types/serve-static@*": - version "1.13.10" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" - integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== - dependencies: - "@types/mime" "^1" - "@types/node" "*" - - "@types/set-cookie-parser@^2.4.0": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz#b6a955219b54151bfebd4521170723df5e13caad" - integrity sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w== - dependencies: - "@types/node" "*" - - "@types/sinonjs__fake-timers@8.1.1": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" - integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== - - "@types/sinonjs__fake-timers@^6.0.2": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz#0ecc1b9259b76598ef01942f547904ce61a6a77d" - integrity sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A== - - "@types/sizzle@*", "@types/sizzle@^2.3.2": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef" - integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ== - - "@types/source-list-map@*": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" - integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== - - "@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - - "@types/tapable@^1", "@types/tapable@^1.0.5": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.8.tgz#b94a4391c85666c7b73299fd3ad79d4faa435310" - integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ== - - "@types/testing-library__jest-dom@^5.9.1": - version "5.14.2" - resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.2.tgz#564fb2b2dc827147e937a75b639a05d17ce18b44" - integrity sha512-vehbtyHUShPxIa9SioxDwCvgxukDMH//icJG90sXQBUm5lJOHLT5kNeU9tnivhnA/TkOFMzGIXN2cTc4hY8/kg== - dependencies: - "@types/jest" "*" - - "@types/through@*": - version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" - integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== - dependencies: - "@types/node" "*" - - "@types/uglify-js@*": - version "3.13.1" - resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.1.tgz#5e889e9e81e94245c75b6450600e1c5ea2878aea" - integrity sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ== - dependencies: - source-map "^0.6.1" - - "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" - integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== - - "@types/webpack-dev-server@3": - version "3.11.6" - resolved "https://registry.yarnpkg.com/@types/webpack-dev-server/-/webpack-dev-server-3.11.6.tgz#d8888cfd2f0630203e13d3ed7833a4d11b8a34dc" - integrity sha512-XCph0RiiqFGetukCTC3KVnY1jwLcZ84illFRMbyFzCcWl90B/76ew0tSqF46oBhnLC4obNDG7dMO0JfTN0MgMQ== - dependencies: - "@types/connect-history-api-fallback" "*" - "@types/express" "*" - "@types/serve-static" "*" - "@types/webpack" "^4" - http-proxy-middleware "^1.0.0" - - "@types/webpack-env@^1.16.0": - version "1.16.3" - resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.3.tgz#b776327a73e561b71e7881d0cd6d34a1424db86a" - integrity sha512-9gtOPPkfyNoEqCQgx4qJKkuNm/x0R2hKR7fdl7zvTJyHnIisuE/LfvXOsYWL0o3qq6uiBnKZNNNzi3l0y/X+xw== - - "@types/webpack-livereload-plugin@^2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@types/webpack-livereload-plugin/-/webpack-livereload-plugin-2.3.3.tgz#96f34133f1e1515571233a3e5099d863dc8723e7" - integrity sha512-R8P2HG2mAHY3Qptspt0il8zYVNqiEeOmMe2cGFcEjH7qnJZ4uC7hujLwfAm6jrIO7I5uEs6CxfpKSXM9ULAggw== - dependencies: - "@types/webpack" "^4" - - "@types/webpack-sources@*": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-3.2.0.tgz#16d759ba096c289034b26553d2df1bf45248d38b" - integrity sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg== - dependencies: - "@types/node" "*" - "@types/source-list-map" "*" - source-map "^0.7.3" - - "@types/webpack@^4", "@types/webpack@^4.4.31", "@types/webpack@^4.41.26", "@types/webpack@^4.41.8": - version "4.41.32" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.32.tgz#a7bab03b72904070162b2f169415492209e94212" - integrity sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg== - dependencies: - "@types/node" "*" - "@types/tapable" "^1" - "@types/uglify-js" "*" - "@types/webpack-sources" "*" - anymatch "^3.0.0" - source-map "^0.6.0" - - "@types/webpack@^5.28.0": - version "5.28.0" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.0.tgz#78dde06212f038d77e54116cfe69e88ae9ed2c03" - integrity sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w== - dependencies: - "@types/node" "*" - tapable "^2.2.0" - webpack "^5" - - "@types/yargs-parser@*": - version "20.2.1" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" - integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== - - "@types/yargs@^15.0.0": - version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== - dependencies: - "@types/yargs-parser" "*" - - "@types/yargs@^16.0.0": - version "16.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" - integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== - dependencies: - "@types/yargs-parser" "*" - - "@types/yauzl@^2.9.1": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" - integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA== - dependencies: - "@types/node" "*" - - "@typescript-eslint/eslint-plugin@^4.7.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== - dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - - "@typescript-eslint/eslint-plugin@^5.6.0": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz#b2cd3e288f250ce8332d5035a2ff65aba3374ac4" - integrity sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw== - dependencies: - "@typescript-eslint/scope-manager" "5.12.1" - "@typescript-eslint/type-utils" "5.12.1" - "@typescript-eslint/utils" "5.12.1" - debug "^4.3.2" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.2.0" - semver "^7.3.5" - tsutils "^3.21.0" - - "@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - - "@typescript-eslint/experimental-utils@^5.0.0": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.12.1.tgz#008cb39964d0860b00104a4e9853cfe3bb32ef20" - integrity sha512-4bEa8WrS5DdzJq43smPH12ys4AOoCxVu2xjYGXQR4DnNyM8pqNzCr28zodf38Jc4bxWdniSEKKC1bQaccXGq5Q== - dependencies: - "@typescript-eslint/utils" "5.12.1" - - "@typescript-eslint/parser@^4.7.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - - "@typescript-eslint/parser@^5.6.0": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.12.1.tgz#b090289b553b8aa0899740d799d0f96e6f49771b" - integrity sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw== - dependencies: - "@typescript-eslint/scope-manager" "5.12.1" - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/typescript-estree" "5.12.1" - debug "^4.3.2" - - "@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - - "@typescript-eslint/scope-manager@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz#58734fd45d2d1dec49641aacc075fba5f0968817" - integrity sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ== - dependencies: - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/visitor-keys" "5.12.1" - - "@typescript-eslint/type-utils@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz#8d58c6a0bb176b5e9a91581cda1a7f91a114d3f0" - integrity sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg== - dependencies: - "@typescript-eslint/utils" "5.12.1" - debug "^4.3.2" - tsutils "^3.21.0" - - "@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - - "@typescript-eslint/types@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.12.1.tgz#46a36a28ff4d946821b58fe5a73c81dc2e12aa89" - integrity sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA== - - "@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - - "@typescript-eslint/typescript-estree@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz#6a9425b9c305bcbc38e2d1d9a24c08e15e02b722" - integrity sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw== - dependencies: - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/visitor-keys" "5.12.1" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - - "@typescript-eslint/utils@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.1.tgz#447c24a05d9c33f9c6c64cb48f251f2371eef920" - integrity sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.12.1" - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/typescript-estree" "5.12.1" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - - "@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== - dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" - - "@typescript-eslint/visitor-keys@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz#f722da106c8f9695ae5640574225e45af3e52ec3" - integrity sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A== - dependencies: - "@typescript-eslint/types" "5.12.1" - eslint-visitor-keys "^3.0.0" - - "@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - - "@ungap/url-search-params@^0.1.2": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@ungap/url-search-params/-/url-search-params-0.1.4.tgz#727e9b4c811beaa6be6d7e4cc0516663c884cfd0" - integrity sha512-RLwrxCTDNiNev9hpr9rDq8NyeQ8Nn0X1we4Wu7Tlf368I8r+7hBj3uObhifhuLk74egaYaSX5nUsBlWz6kjj+A== - - "@webassemblyjs/ast@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" - integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - - "@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - - "@webassemblyjs/floating-point-hex-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" - integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== - - "@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== - - "@webassemblyjs/helper-api-error@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" - integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== - - "@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== - - "@webassemblyjs/helper-buffer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" - integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== - - "@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - - "@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - - "@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - - "@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== - dependencies: - "@webassemblyjs/ast" "1.9.0" - - "@webassemblyjs/helper-numbers@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" - integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@xtuc/long" "4.2.2" - - "@webassemblyjs/helper-wasm-bytecode@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" - integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== - - "@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== - - "@webassemblyjs/helper-wasm-section@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" - integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - - "@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - - "@webassemblyjs/ieee754@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" - integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== - dependencies: - "@xtuc/ieee754" "^1.2.0" - - "@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - - "@webassemblyjs/leb128@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" - integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== - dependencies: - "@xtuc/long" "4.2.2" - - "@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== - dependencies: - "@xtuc/long" "4.2.2" - - "@webassemblyjs/utf8@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" - integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== - - "@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== - - "@webassemblyjs/wasm-edit@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" - integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/helper-wasm-section" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-opt" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - "@webassemblyjs/wast-printer" "1.11.1" - - "@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - - "@webassemblyjs/wasm-gen@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" - integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - - "@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - - "@webassemblyjs/wasm-opt@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" - integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - - "@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - - "@webassemblyjs/wasm-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" - integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - - "@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - - "@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" - "@xtuc/long" "4.2.2" - - "@webassemblyjs/wast-printer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" - integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@xtuc/long" "4.2.2" - - "@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - - "@webpack-cli/configtest@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356" - integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg== - - "@webpack-cli/info@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea" - integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA== - dependencies: - envinfo "^7.7.3" - - "@webpack-cli/serve@^1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" - integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== - - "@wojtekmaj/date-utils@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@wojtekmaj/date-utils/-/date-utils-1.0.3.tgz#2dcfd92881425c5923e429c2aec86fb3609032a1" - integrity sha512-1VPkkTBk07gMR1fjpBtse4G+oJqpmE+0gUFB0dg3VIL7qJmUVaBoD/vlzMm/jNeOPfvlmerl1lpnsZyBUFIRuw== - - "@xmldom/xmldom@^0.7.2": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d" - integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A== - - "@xobotyi/scrollbar-width@^1.9.5": - version "1.9.5" - resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" - integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== - - "@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - - "@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - - JSONStream@^1.0.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - - abab@^2.0.3, abab@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== - - abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - - accepts@~1.3.5, accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - - acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - - acorn-import-assertions@^1.7.6: - version "1.8.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" - integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== - - acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - - acorn-walk@^7.1.1, acorn-walk@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - - acorn-walk@^8.0.0, acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - - acorn@^6.4.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - - acorn@^7.1.1, acorn@^7.4.0, acorn@^7.4.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - - acorn@^8.0.4, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - - add-dom-event-listener@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" - integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw== - dependencies: - object-assign "4.x" - - add-px-to-style@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a" - integrity sha1-0ME1RB+oAUqBN5BFMQlvZ/KPJjo= - - add-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" - integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= - - address@^1.0.1, address@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" - integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== - - agent-base@6, agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - - agentkeepalive@^4.1.3: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" - integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA== - dependencies: - debug "^4.1.0" - depd "^1.1.2" - humanize-ms "^1.2.1" - - aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - - airbnb-js-shims@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz#db481102d682b98ed1daa4c5baa697a05ce5c040" - integrity sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ== - dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" - array.prototype.flatmap "^1.2.1" - es5-shim "^4.5.13" - es6-shim "^0.35.5" - function.prototype.name "^1.1.0" - globalthis "^1.0.0" - object.entries "^1.1.0" - object.fromentries "^2.0.0 || ^1.0.0" - object.getownpropertydescriptors "^2.0.3" - object.values "^1.1.0" - promise.allsettled "^1.0.0" - promise.prototype.finally "^3.1.0" - string.prototype.matchall "^4.0.0 || ^3.0.1" - string.prototype.padend "^3.0.0" - string.prototype.padstart "^3.0.0" - symbol.prototype.description "^1.0.0" - - airbnb-prop-types@^2.15.0, airbnb-prop-types@^2.16.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz#b96274cefa1abb14f623f804173ee97c13971dc2" - integrity sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg== - dependencies: - array.prototype.find "^2.1.1" - function.prototype.name "^1.1.2" - is-regex "^1.1.0" - object-is "^1.1.2" - object.assign "^4.1.0" - object.entries "^1.1.2" - prop-types "^15.7.2" - prop-types-exact "^1.2.0" - react-is "^16.13.1" - - ajv-errors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" - integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== - - ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== - dependencies: - ajv "^8.0.0" - - ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - - ajv-keywords@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" - integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== - dependencies: - fast-deep-equal "^3.1.3" - - ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - - ajv@^8.0.0, ajv@^8.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - - ansi-align@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" - - ansi-colors@4.1.1, ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - - ansi-colors@^3.0.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - - ansi-escapes@^4.1.0, ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - - ansi-html-community@0.0.8, ansi-html-community@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" - integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== - - ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - - ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - - ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - - ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - - ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - - ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - - ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - - ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - - ansi-to-html@^0.6.11: - version "0.6.15" - resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.15.tgz#ac6ad4798a00f6aa045535d7f6a9cb9294eebea7" - integrity sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ== - dependencies: - entities "^2.0.0" - - ansicolor@1.1.95: - version "1.1.95" - resolved "https://registry.yarnpkg.com/ansicolor/-/ansicolor-1.1.95.tgz#978c494f04793d6c58115ba13a50f56593f736c6" - integrity sha512-R4yTmrfQZ2H9Wr5TZoM2iOz0+T6TNHqztpld7ZToaN8EaUj/06NG4r5UHQfegA9/+K/OY3E+WumprcglbcTMRA== - - anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - - anymatch@^3.0.0, anymatch@^3.0.3, anymatch@^3.1.1, anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - - app-path@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/app-path/-/app-path-3.3.0.tgz#0342a909db37079c593979c720f99e872475eba3" - integrity sha512-EAgEXkdcxH1cgEePOSsmUtw9ItPl0KTxnh/pj9ZbhvbKbij9x0oX6PWpGnorDr0DS5AosLgoa5n3T/hZmKQpYA== - dependencies: - execa "^1.0.0" - - app-root-dir@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/app-root-dir/-/app-root-dir-1.0.2.tgz#38187ec2dea7577fff033ffcb12172692ff6e118" - integrity sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg= - - aproba@^1.0.3, aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - - "aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - - arch@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" - integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== - - are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - - are-we-there-yet@~1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" - integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - - arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - - argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - - argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - - aria-query@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" - integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== - dependencies: - "@babel/runtime" "^7.10.2" - "@babel/runtime-corejs3" "^7.10.2" - - aria-query@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c" - integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg== - - arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= - dependencies: - arr-flatten "^1.0.1" - - arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - - arr-flatten@^1.0.1, arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - - arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - - array-differ@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" - integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== - - array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - - array-find@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8" - integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg= - - array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - - array-ify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" - integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= - - array-includes@^3.0.3, array-includes@^3.1.3, array-includes@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" - integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - is-string "^1.0.7" - - array-tree-filter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" - integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== - - array-union@^1.0.1, array-union@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - - array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - - array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - - array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - - array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - - array.prototype.filter@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array.prototype.filter/-/array.prototype.filter-1.0.1.tgz#20688792acdb97a09488eaaee9eebbf3966aae21" - integrity sha512-Dk3Ty7N42Odk7PjU/Ci3zT4pLj20YvuVnneG/58ICM6bt4Ij5kZaJTVQ9TSaWaIECX2sFyz4KItkVZqHNnciqw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - - array.prototype.find@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.2.tgz#6abbd0c2573925d8094f7d23112306af8c16d534" - integrity sha512-00S1O4ewO95OmmJW7EesWfQlrCrLEL8kZ40w3+GkLX2yTt0m2ggcePPa2uHPJ9KUmJvwRq+lCV9bD8Yim23x/Q== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - - array.prototype.flat@^1.2.1, array.prototype.flat@^1.2.3, array.prototype.flat@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" - integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - - array.prototype.flatmap@^1.2.1, array.prototype.flatmap@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" - integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.19.0" - - array.prototype.map@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.4.tgz#0d97b640cfdd036c1b41cfe706a5e699aa0711f2" - integrity sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - - arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - - arrify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - - asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - - asap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/asap/-/asap-1.0.0.tgz#b2a45da5fdfa20b0496fc3768cc27c12fa916a7d" - integrity sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0= - - asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - - asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - - assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - - assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - - assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - - ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= - - ast-types@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" - integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== - dependencies: - tslib "^2.0.1" - - astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - - astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - - async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - - async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - - async@^3.2.0: - version "3.2.3" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" - integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== - - asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - - at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - - atob@2.1.2, atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - - attr-accept@^2.2.1, attr-accept@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" - integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== - - autoprefixer@^10.4.2: - version "10.4.2" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" - integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== - dependencies: - browserslist "^4.19.1" - caniuse-lite "^1.0.30001297" - fraction.js "^4.1.2" - normalize-range "^0.1.2" - picocolors "^1.0.0" - postcss-value-parser "^4.2.0" - - autoprefixer@^9.8.5, autoprefixer@^9.8.6: - version "9.8.8" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" - integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== - dependencies: - browserslist "^4.12.0" - caniuse-lite "^1.0.30001109" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - picocolors "^0.2.1" - postcss "^7.0.32" - postcss-value-parser "^4.1.0" - - aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - - aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - - axe-core@^4.3.5: - version "4.4.1" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" - integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw== - - axobject-query@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" - integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== - - babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - - babel-eslint@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.0" - "@babel/traverse" "^7.7.0" - "@babel/types" "^7.7.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - - babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" - integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== - dependencies: - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^27.5.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - - babel-loader@8.2.3, babel-loader@^8.0.0, babel-loader@^8.1.0: - version "8.2.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" - integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== - dependencies: - find-cache-dir "^3.3.1" - loader-utils "^1.4.0" - make-dir "^3.1.0" - schema-utils "^2.6.5" - - babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-add-react-displayname@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz#339d4cddb7b65fd62d1df9db9fe04de134122bd5" - integrity sha1-M51M3be2X9YtHfnbn+BN4TQSK9U= - - babel-plugin-apply-mdx-type-prop@1.6.22: - version "1.6.22" - resolved "https://registry.yarnpkg.com/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz#d216e8fd0de91de3f1478ef3231e05446bc8705b" - integrity sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ== - dependencies: - "@babel/helper-plugin-utils" "7.10.4" - "@mdx-js/util" "1.6.22" - - babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - - babel-plugin-emotion@^10.0.27: - version "10.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz#a1fe3503cff80abfd0bdda14abd2e8e57a79d17d" - integrity sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@emotion/hash" "0.8.0" - "@emotion/memoize" "0.7.4" - "@emotion/serialize" "^0.11.16" - babel-plugin-macros "^2.0.0" - babel-plugin-syntax-jsx "^6.18.0" - convert-source-map "^1.5.0" - escape-string-regexp "^1.0.5" - find-root "^1.1.0" - source-map "^0.5.7" - - babel-plugin-extract-import-names@1.6.22: - version "1.6.22" - resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc" - integrity sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ== - dependencies: - "@babel/helper-plugin-utils" "7.10.4" - - babel-plugin-istanbul@^6.0.0, babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - - babel-plugin-jest-hoist@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" - integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - - babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.6.1, babel-plugin-macros@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" - integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== - dependencies: - "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" - - babel-plugin-macros@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" - integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== - dependencies: - "@babel/runtime" "^7.12.5" - cosmiconfig "^7.0.0" - resolve "^1.19.0" - - babel-plugin-named-asset-import@^0.3.1: - version "0.3.8" - resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz#6b7fa43c59229685368683c28bc9734f24524cc2" - integrity sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q== - - babel-plugin-polyfill-corejs2@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" - integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== - dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.1" - semver "^6.1.1" - - babel-plugin-polyfill-corejs3@^0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz#80449d9d6f2274912e05d9e182b54816904befd0" - integrity sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.1.5" - core-js-compat "^3.8.1" - - babel-plugin-polyfill-corejs3@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz#0b571f4cf3d67f911512f5c04842a7b8e8263087" - integrity sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.0" - core-js-compat "^3.18.0" - - babel-plugin-polyfill-corejs3@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" - integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - core-js-compat "^3.21.0" - - babel-plugin-polyfill-regenerator@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" - integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - - babel-plugin-react-docgen@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz#7cc8e2f94e8dc057a06e953162f0810e4e72257b" - integrity sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ== - dependencies: - ast-types "^0.14.2" - lodash "^4.17.15" - react-docgen "^5.0.0" - - babel-plugin-react-svg@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-svg/-/babel-plugin-react-svg-3.0.3.tgz#7da46a0bd8319f49ac85523d259f145ce5d78321" - integrity sha512-Pst1RWjUIiV0Ykv1ODSeceCBsFOP2Y4dusjq7/XkjuzJdvS9CjpkPMUIoO4MLlvp5PiLCeMlsOC7faEUA0gm3Q== - - babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= - - babel-plugin-syntax-jsx@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= - - babel-plugin-transform-class-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= - dependencies: - babel-helper-function-name "^6.24.1" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - - babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - - babel-preset-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" - integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== - dependencies: - babel-plugin-jest-hoist "^27.5.1" - babel-preset-current-node-syntax "^1.0.0" - - babel-runtime@6.x, babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - - babel-template@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - - babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - - babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - - babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - - bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== - - balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - - base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - - base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - - basic-auth@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" - integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== - dependencies: - safe-buffer "5.1.2" - - batch-processor@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/batch-processor/-/batch-processor-1.0.0.tgz#75c95c32b748e0850d10c2b168f6bdbe9891ace8" - integrity sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg= - - bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - - before-after-hook@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" - integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== - - better-opn@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-2.1.1.tgz#94a55b4695dc79288f31d7d0e5f658320759f7c6" - integrity sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA== - dependencies: - open "^7.0.3" - - big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - - big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - - binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - - binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - - bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - - bl@^4.0.3, bl@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - - blink-diff@1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/blink-diff/-/blink-diff-1.0.13.tgz#80e3df69de804b30d40c70f041e983841ecda899" - integrity sha1-gOPfad6ASzDUDHDwQemDhB7NqJk= - dependencies: - pngjs-image "~0.11.5" - preceptor-core "~0.10.0" - promise "6.0.0" - - blob-util@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" - integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== - - bluebird@3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" - integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== - - bluebird@^3.3.5, bluebird@^3.5.5, bluebird@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - - bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - - bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - - body-parser@1.19.2, body-parser@^1.19.1: - version "1.19.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" - integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.9.7" - raw-body "2.4.3" - type-is "~1.6.18" - - body@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" - integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= - dependencies: - continuable-cache "^0.3.1" - error "^7.0.0" - raw-body "~1.1.0" - safe-json-parse "~1.0.1" - - boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - - boxen@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" - integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^6.2.0" - chalk "^4.1.0" - cli-boxes "^2.2.1" - string-width "^4.2.2" - type-fest "^0.20.2" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - - brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - - braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - - braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - - braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - - brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - - browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - - browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - - browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - - browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - - browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - - browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - - browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - - browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - - browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.19.1: - version "4.19.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.3.tgz#29b7caad327ecf2859485f696f9604214bedd383" - integrity sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg== - dependencies: - caniuse-lite "^1.0.30001312" - electron-to-chromium "^1.4.71" - escalade "^3.1.1" - node-releases "^2.0.2" - picocolors "^1.0.0" - - bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - - bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - - buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - - buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - - buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - - buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - - buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - - builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - - builtins@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" - integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= - - byline@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" - integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= - - byte-size@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" - integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== - - bytes-iec@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bytes-iec/-/bytes-iec-3.1.1.tgz#94cd36bf95c2c22a82002c247df8772d1d591083" - integrity sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA== - - bytes@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" - integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= - - bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - - bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - - c8@^7.6.0: - version "7.11.0" - resolved "https://registry.yarnpkg.com/c8/-/c8-7.11.0.tgz#b3ab4e9e03295a102c47ce11d4ef6d735d9a9ac9" - integrity sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@istanbuljs/schema" "^0.1.2" - find-up "^5.0.0" - foreground-child "^2.0.0" - istanbul-lib-coverage "^3.0.1" - istanbul-lib-report "^3.0.0" - istanbul-reports "^3.0.2" - rimraf "^3.0.0" - test-exclude "^6.0.0" - v8-to-istanbul "^8.0.0" - yargs "^16.2.0" - yargs-parser "^20.2.7" - - cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - - cacache@^15.0.5, cacache@^15.2.0: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - - cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - - cacheable-lookup@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz#87be64a18b925234875e10a9bb1ebca4adce6b38" - integrity sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg== - dependencies: - "@types/keyv" "^3.1.1" - keyv "^4.0.0" - - cacheable-request@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" - integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^4.0.0" - lowercase-keys "^2.0.0" - normalize-url "^6.0.1" - responselike "^2.0.0" - - cachedir@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" - integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== - - calculate-size@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/calculate-size/-/calculate-size-1.1.1.tgz#ae7caa1c7795f82c4f035dc7be270e3581dae3ee" - integrity sha1-rnyqHHeV+CxPA13HvicONYHa4+4= - - call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - - call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - - caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - - caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - - callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - - callsites@^3.0.0, callsites@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - - camel-case@^4.1.1, camel-case@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" - integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== - dependencies: - pascal-case "^3.1.2" - tslib "^2.0.3" - - camelcase-css@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" - integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== - - camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - - camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - - camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - - camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - - camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - - camelcase@^6.0.0, camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - - caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - - caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001312: - version "1.0.30001312" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz#e11eba4b87e24d22697dae05455d5aea28550d5f" - integrity sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ== - - canvas-to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/canvas-to-buffer/-/canvas-to-buffer-1.1.1.tgz#3adceeb0a56c1583f3cf0cffc7b3ac08c1a1b4a1" - integrity sha512-AIc/EjM5cPkUDBPic+r1OPdD6WO95GatRulDV5ue1SXq6SmUtG6Myc7PeMfg8BdO/rhUrT5PtpQu+pK6sDBhsg== - dependencies: - atob "2.1.2" - typedarray-to-buffer "3.1.5" - - canvas@^2.8.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.9.0.tgz#7df0400b141a7e42e597824f377935ba96880f2a" - integrity sha512-0l93g7uxp7rMyr7H+XRQ28A3ud0dKIUTIEkUe1Dxh4rjUYN7B93+SjC3r1PDKA18xcQN87OFGgUnyw7LSgNLSQ== - dependencies: - "@mapbox/node-pre-gyp" "^1.0.0" - nan "^2.15.0" - simple-get "^3.0.3" - - capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - - case-sensitive-paths-webpack-plugin@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" - integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== - - caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - - ccount@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" - integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== - - chalk@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - - chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - - chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - - chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - - chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - - char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - - character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== - - character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== - - character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== - - charcodes@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/charcodes/-/charcodes-0.2.0.tgz#5208d327e6cc05f99eb80ffc814707572d1f14e4" - integrity sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ== - - chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - - check-more-types@^2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" - integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= - - cheerio-select@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823" - integrity sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg== - dependencies: - css-select "^4.1.3" - css-what "^5.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - domutils "^2.7.0" - - cheerio@^1.0.0-rc.3: - version "1.0.0-rc.10" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e" - integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw== - dependencies: - cheerio-select "^1.5.0" - dom-serializer "^1.3.2" - domhandler "^4.2.0" - htmlparser2 "^6.1.0" - parse5 "^6.0.1" - parse5-htmlparser2-tree-adapter "^6.0.1" - tslib "^2.2.0" - - chokidar@3.5.3, "chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.2: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - - chokidar@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - - chownr@^1.1.1, chownr@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - - chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - - chrome-remote-interface@0.31.1: - version "0.31.1" - resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.31.1.tgz#87c37c81f10d9f0832b6d6a42e52ac2c7ebb4008" - integrity sha512-cvNTnXfx4kYCaeh2sEKrdlqZsYRleACPL47O8LrrjihVfBQbfPmf03vVqSSm7SIeqyo2P77ZXovrBAs4D/nopQ== - dependencies: - commander "2.11.x" - ws "^7.2.0" - - chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - - ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - - ci-info@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" - integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== - - ci-job-number@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/ci-job-number/-/ci-job-number-1.2.2.tgz#f4e5918fcaeeda95b604f214be7d7d4a961fe0c0" - integrity sha512-CLOGsVDrVamzv8sXJGaILUVI6dsuAkouJP/n6t+OxLPeeA4DDby7zn9SB6EUpa1H7oIKoE+rMmkW80zYsFfUjA== - - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - - cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== - - class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - - classnames@2.3.1, classnames@2.x, classnames@^2.2.1, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== - - clean-css@^4.2.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" - integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== - dependencies: - source-map "~0.6.0" - - clean-css@^5.2.2: - version "5.2.4" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.4.tgz#982b058f8581adb2ae062520808fb2429bd487a4" - integrity sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg== - dependencies: - source-map "~0.6.0" - - clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - - clean-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz#a99d8ec34c1c628a4541567aa7b457446460c62b" - integrity sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A== - dependencies: - "@types/webpack" "^4.4.31" - del "^4.1.1" - - cli-boxes@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - - cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - - cli-spinners@^2.5.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== - - cli-table3@^0.6.1, cli-table3@~0.6.0, cli-table3@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.1.tgz#36ce9b7af4847f288d3cdd081fbd09bf7bd237b8" - integrity sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA== - dependencies: - string-width "^4.2.0" - optionalDependencies: - colors "1.4.0" - - cli-truncate@2.1.0, cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - - cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - - cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - - cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - - clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - - clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - - clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - - clsx@^1.1.0, clsx@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" - integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== - - cmd-shim@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" - integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== - dependencies: - mkdirp-infer-owner "^2.0.0" - - co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - - coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - - code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - - collapse-white-space@^1.0.2: - version "1.0.6" - resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" - integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== - - collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - - collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - - color-convert@^1.9.0, color-convert@^1.9.3: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - - color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - - color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - - color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - - color-string@^1.6.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" - integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - - color-support@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - - color@^3.1.3: - version "3.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" - integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== - dependencies: - color-convert "^1.9.3" - color-string "^1.6.0" - - colord@^2.9.1: - version "2.9.2" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" - integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== - - colorette@^1.2.2, colorette@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" - integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== - - colorette@^2.0.14, colorette@^2.0.16: - version "2.0.16" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== - - colors@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - - columnify@^1.5.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" - integrity sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q== - dependencies: - strip-ansi "^6.0.1" - wcwidth "^1.0.0" - - combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - - comma-separated-tokens@^1.0.0: - version "1.0.8" - resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" - integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== - - command-exists@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" - integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== - - commander@2, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - - commander@2.11.x: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== - - commander@7, commander@^7.0.0, commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - - commander@8.3.0, commander@^8.2.0, commander@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - - commander@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - - commander@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" - integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== - - commander@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - - commander@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.0.0.tgz#86d58f24ee98126568936bd1d3574e0308a99a40" - integrity sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw== - - common-path-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" - integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== - - common-tags@^1.8.0: - version "1.8.2" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" - integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== - - commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - - compare-func@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" - integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== - dependencies: - array-ify "^1.0.0" - dot-prop "^5.1.0" - - component-classes@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691" - integrity sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE= - dependencies: - component-indexof "0.0.3" - - component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - - component-indexof@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24" - integrity sha1-EdCRMSI5648yyPJa6csAL/6NPCQ= - - compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - - compression@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - - compute-scroll-into-view@^1.0.17: - version "1.0.17" - resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab" - integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg== - - concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - - concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - - concat-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" - integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.0.2" - typedarray "^0.0.6" - - config-chain@^1.1.12: - version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - - confusing-browser-globals@^1.0.10: - version "1.0.11" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" - integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== - - console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - - console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - - "consolidated-events@^1.1.1 || ^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/consolidated-events/-/consolidated-events-2.0.2.tgz#da8d8f8c2b232831413d9e190dc11669c79f4a91" - integrity sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ== - - constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - - content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - - content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - - continuable-cache@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" - integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= - - contributor-faces@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/contributor-faces/-/contributor-faces-1.1.0.tgz#79fc711d64c1a16066c111629eb8388602f627a5" - integrity sha512-MGVY/0WnoQi3FcLEEe1cvT0UadI2m7AqRfTkAiYo0FqfWSKxhRsFHnCDm5g7iMr1cpvcZ9nPPjZ6XZm2zg20LA== - dependencies: - gh-got "^9.0.0" - meow "^3.7.0" - micromatch "^2.3.11" - readme-filename "^1.0.0" - replace-in-file "^2.0.1" - - conventional-changelog-angular@^5.0.12: - version "5.0.13" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" - integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== - dependencies: - compare-func "^2.0.0" - q "^1.5.1" - - conventional-changelog-atom@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz#a759ec61c22d1c1196925fca88fe3ae89fd7d8de" - integrity sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw== - dependencies: - q "^1.5.1" - - conventional-changelog-cli@^2.1.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/conventional-changelog-cli/-/conventional-changelog-cli-2.2.2.tgz#9a7746cede92c6a8f27dc46692efaadfbed60daa" - integrity sha512-8grMV5Jo8S0kP3yoMeJxV2P5R6VJOqK72IiSV9t/4H5r/HiRqEBQ83bYGuz4Yzfdj4bjaAEhZN/FFbsFXr5bOA== - dependencies: - add-stream "^1.0.0" - conventional-changelog "^3.1.24" - lodash "^4.17.15" - meow "^8.0.0" - tempfile "^3.0.0" - - conventional-changelog-codemirror@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz#398e9530f08ce34ec4640af98eeaf3022eb1f7dc" - integrity sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw== - dependencies: - q "^1.5.1" - - conventional-changelog-conventionalcommits@^4.5.0: - version "4.6.3" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz#0765490f56424b46f6cb4db9135902d6e5a36dc2" - integrity sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g== - dependencies: - compare-func "^2.0.0" - lodash "^4.17.15" - q "^1.5.1" - - conventional-changelog-core@^4.2.1, conventional-changelog-core@^4.2.2: - version "4.2.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz#e50d047e8ebacf63fac3dc67bf918177001e1e9f" - integrity sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg== - dependencies: - add-stream "^1.0.0" - conventional-changelog-writer "^5.0.0" - conventional-commits-parser "^3.2.0" - dateformat "^3.0.0" - get-pkg-repo "^4.0.0" - git-raw-commits "^2.0.8" - git-remote-origin-url "^2.0.0" - git-semver-tags "^4.1.1" - lodash "^4.17.15" - normalize-package-data "^3.0.0" - q "^1.5.1" - read-pkg "^3.0.0" - read-pkg-up "^3.0.0" - through2 "^4.0.0" - - conventional-changelog-ember@^2.0.9: - version "2.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz#619b37ec708be9e74a220f4dcf79212ae1c92962" - integrity sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A== - dependencies: - q "^1.5.1" - - conventional-changelog-eslint@^3.0.9: - version "3.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz#689bd0a470e02f7baafe21a495880deea18b7cdb" - integrity sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA== - dependencies: - q "^1.5.1" - - conventional-changelog-express@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz#420c9d92a347b72a91544750bffa9387665a6ee8" - integrity sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ== - dependencies: - q "^1.5.1" - - conventional-changelog-jquery@^3.0.11: - version "3.0.11" - resolved "https://registry.yarnpkg.com/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz#d142207400f51c9e5bb588596598e24bba8994bf" - integrity sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw== - dependencies: - q "^1.5.1" - - conventional-changelog-jshint@^2.0.9: - version "2.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz#f2d7f23e6acd4927a238555d92c09b50fe3852ff" - integrity sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA== - dependencies: - compare-func "^2.0.0" - q "^1.5.1" - - conventional-changelog-preset-loader@^2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" - integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== - - conventional-changelog-writer@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz#e0757072f045fe03d91da6343c843029e702f359" - integrity sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ== - dependencies: - conventional-commits-filter "^2.0.7" - dateformat "^3.0.0" - handlebars "^4.7.7" - json-stringify-safe "^5.0.1" - lodash "^4.17.15" - meow "^8.0.0" - semver "^6.0.0" - split "^1.0.0" - through2 "^4.0.0" - - conventional-changelog@^3.1.24: - version "3.1.25" - resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.25.tgz#3e227a37d15684f5aa1fb52222a6e9e2536ccaff" - integrity sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ== - dependencies: - conventional-changelog-angular "^5.0.12" - conventional-changelog-atom "^2.0.8" - conventional-changelog-codemirror "^2.0.8" - conventional-changelog-conventionalcommits "^4.5.0" - conventional-changelog-core "^4.2.1" - conventional-changelog-ember "^2.0.9" - conventional-changelog-eslint "^3.0.9" - conventional-changelog-express "^2.0.6" - conventional-changelog-jquery "^3.0.11" - conventional-changelog-jshint "^2.0.9" - conventional-changelog-preset-loader "^2.3.4" - - conventional-commits-filter@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" - integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== - dependencies: - lodash.ismatch "^4.4.0" - modify-values "^1.0.0" - - conventional-commits-parser@^3.2.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz#a7d3b77758a202a9b2293d2112a8d8052c740972" - integrity sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q== - dependencies: - JSONStream "^1.0.4" - is-text-path "^1.0.1" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - - conventional-recommended-bump@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" - integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== - dependencies: - concat-stream "^2.0.0" - conventional-changelog-preset-loader "^2.3.4" - conventional-commits-filter "^2.0.7" - conventional-commits-parser "^3.2.0" - git-raw-commits "^2.0.8" - git-semver-tags "^4.1.1" - meow "^8.0.0" - q "^1.5.1" - - convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - - cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - - cookie@0.4.2, cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - - copy-anything@^2.0.1: - version "2.0.6" - resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480" - integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw== - dependencies: - is-what "^3.14.1" - - copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - - copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - - copy-to-clipboard@^3, copy-to-clipboard@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" - integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== - dependencies: - toggle-selection "^1.0.6" - - copy-webpack-plugin@^6.3.2: - version "6.4.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e" - integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA== - dependencies: - cacache "^15.0.5" - fast-glob "^3.2.4" - find-cache-dir "^3.3.1" - glob-parent "^5.1.1" - globby "^11.0.1" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" - - core-js-compat@^3.18.0, core-js-compat@^3.19.1, core-js-compat@^3.20.2, core-js-compat@^3.21.0, core-js-compat@^3.8.1: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.21.1.tgz#cac369f67c8d134ff8f9bd1623e3bc2c42068c82" - integrity sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g== - dependencies: - browserslist "^4.19.1" - semver "7.0.0" - - core-js-pure@^3.20.2, core-js-pure@^3.8.1, core-js-pure@^3.8.2: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51" - integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ== - - core-js@3.20.2: - version "3.20.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.20.2.tgz#46468d8601eafc8b266bd2dd6bf9dee622779581" - integrity sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw== - - core-js@^2.4.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" - integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== - - core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.2: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94" - integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig== - - core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - - core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - - cors@^2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - - cosmiconfig@^5.0.0, cosmiconfig@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - - cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - - cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - - cp-file@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" - integrity sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw== - dependencies: - graceful-fs "^4.1.2" - make-dir "^3.0.0" - nested-error-stacks "^2.0.0" - p-event "^4.1.0" - - cpy@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/cpy/-/cpy-8.1.2.tgz#e339ea54797ad23f8e3919a5cffd37bfc3f25935" - integrity sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg== - dependencies: - arrify "^2.0.1" - cp-file "^7.0.0" - globby "^9.2.0" - has-glob "^1.0.0" - junk "^3.1.0" - nested-error-stacks "^2.1.0" - p-all "^2.1.0" - p-filter "^2.1.0" - p-map "^3.0.0" - - create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - - create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - - create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - - create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - - cross-fetch@3.1.5, cross-fetch@^3.0.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== - dependencies: - node-fetch "2.6.7" - - cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - - cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - - cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - - crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - - css-animation@^1.3.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.6.1.tgz#162064a3b0d51f958b7ff37b3d6d4de18e17039e" - integrity sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog== - dependencies: - babel-runtime "6.x" - component-classes "^1.2.5" - - css-blank-pseudo@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz#36523b01c12a25d812df343a32c322d2a2324561" - integrity sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ== - dependencies: - postcss-selector-parser "^6.0.9" - - css-box-model@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" - integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== - dependencies: - tiny-invariant "^1.0.6" - - css-declaration-sorter@^6.0.3: - version "6.1.4" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz#b9bfb4ed9a41f8dcca9bf7184d849ea94a8294b4" - integrity sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw== - dependencies: - timsort "^0.3.0" - - css-has-pseudo@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz#57f6be91ca242d5c9020ee3e51bbb5b89fc7af73" - integrity sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw== - dependencies: - postcss-selector-parser "^6.0.9" - - css-in-js-utils@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz#3b472b398787291b47cfe3e44fecfdd9e914ba99" - integrity sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA== - dependencies: - hyphenate-style-name "^1.0.2" - isobject "^3.0.1" - - css-loader@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" - integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ== - dependencies: - camelcase "^5.3.1" - cssesc "^3.0.0" - icss-utils "^4.1.1" - loader-utils "^1.2.3" - normalize-path "^3.0.0" - postcss "^7.0.32" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.2.0" - postcss-modules-values "^3.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^2.7.0" - semver "^6.3.0" - - css-loader@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.3.0.tgz#c888af64b2a5b2e85462c72c0f4a85c7e2e0821e" - integrity sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg== - dependencies: - camelcase "^6.0.0" - cssesc "^3.0.0" - icss-utils "^4.1.1" - loader-utils "^2.0.0" - postcss "^7.0.32" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^3.0.3" - postcss-modules-scope "^2.2.0" - postcss-modules-values "^3.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^2.7.1" - semver "^7.3.2" - - css-loader@^5.0.1: - version "5.2.7" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.7.tgz#9b9f111edf6fb2be5dc62525644cbc9c232064ae" - integrity sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg== - dependencies: - icss-utils "^5.1.0" - loader-utils "^2.0.0" - postcss "^8.2.15" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^3.0.0" - semver "^7.3.5" - - css-parse@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" - integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q= - dependencies: - css "^2.0.0" - - css-prefers-color-scheme@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz#ca8a22e5992c10a5b9d315155e7caee625903349" - integrity sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA== - - css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - - css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - - css-select@^4.1.3: - version "4.2.1" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" - integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== - dependencies: - boolbase "^1.0.0" - css-what "^5.1.0" - domhandler "^4.3.0" - domutils "^2.8.0" - nth-check "^2.0.1" - - css-selector-tokenizer@^0.7.0: - version "0.7.3" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" - integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg== - dependencies: - cssesc "^3.0.0" - fastparse "^1.1.2" - - css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - - css-tree@^1.1.2, css-tree@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - - css-what@^3.2.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" - integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== - - css-what@^5.0.1, css-what@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" - integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== - - css.escape@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" - integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s= - - css@^2.0.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" - integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== - dependencies: - inherits "^2.0.3" - source-map "^0.6.1" - source-map-resolve "^0.5.2" - urix "^0.1.0" - - css@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" - integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== - dependencies: - inherits "^2.0.4" - source-map "^0.6.1" - source-map-resolve "^0.6.0" - - csscolorparser@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b" - integrity sha1-s085HupNqPPpgjHizNjfnAQfFxs= - - cssdb@^6.3.1: - version "6.4.0" - resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-6.4.0.tgz#54899b9042e302be3090b8510ea71fefd08c9e6b" - integrity sha512-8NMWrur/ewSNrRNZndbtOTXc2Xb2b+NCTPHj8VErFYvJUlgsMAiBGaFaxG6hjy9zbCjj2ZLwSQrMM+tormO8qA== - - cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - - cssfilter@0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" - integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4= - - cssfontparser@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/cssfontparser/-/cssfontparser-1.2.1.tgz#f4022fc8f9700c68029d542084afbaf425a3f3e3" - integrity sha1-9AIvyPlwDGgCnVQghK+69CWj8+M= - - cssnano-preset-default@^5.1.12: - version "5.1.12" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.12.tgz#64e2ad8e27a279e1413d2d2383ef89a41c909be9" - integrity sha512-rO/JZYyjW1QNkWBxMGV28DW7d98UDLaF759frhli58QFehZ+D/LSmwQ2z/ylBAe2hUlsIWTq6NYGfQPq65EF9w== - dependencies: - css-declaration-sorter "^6.0.3" - cssnano-utils "^3.0.2" - postcss-calc "^8.2.0" - postcss-colormin "^5.2.5" - postcss-convert-values "^5.0.4" - postcss-discard-comments "^5.0.3" - postcss-discard-duplicates "^5.0.3" - postcss-discard-empty "^5.0.3" - postcss-discard-overridden "^5.0.4" - postcss-merge-longhand "^5.0.6" - postcss-merge-rules "^5.0.6" - postcss-minify-font-values "^5.0.4" - postcss-minify-gradients "^5.0.6" - postcss-minify-params "^5.0.5" - postcss-minify-selectors "^5.1.3" - postcss-normalize-charset "^5.0.3" - postcss-normalize-display-values "^5.0.3" - postcss-normalize-positions "^5.0.4" - postcss-normalize-repeat-style "^5.0.4" - postcss-normalize-string "^5.0.4" - postcss-normalize-timing-functions "^5.0.3" - postcss-normalize-unicode "^5.0.4" - postcss-normalize-url "^5.0.5" - postcss-normalize-whitespace "^5.0.4" - postcss-ordered-values "^5.0.5" - postcss-reduce-initial "^5.0.3" - postcss-reduce-transforms "^5.0.4" - postcss-svgo "^5.0.4" - postcss-unique-selectors "^5.0.4" - - cssnano-utils@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.0.2.tgz#d82b4991a27ba6fec644b39bab35fe027137f516" - integrity sha512-KhprijuQv2sP4kT92sSQwhlK3SJTbDIsxcfIEySB0O+3m9esFOai7dP9bMx5enHAh2MwarVIcnwiWoOm01RIbQ== - - cssnano@^5.0.2: - version "5.0.17" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.17.tgz#ff45713c05cfc780a1aeb3e663b6f224d091cabf" - integrity sha512-fmjLP7k8kL18xSspeXTzRhaFtRI7DL9b8IcXR80JgtnWBpvAzHT7sCR/6qdn0tnxIaINUN6OEQu83wF57Gs3Xw== - dependencies: - cssnano-preset-default "^5.1.12" - lilconfig "^2.0.3" - yaml "^1.10.2" - - csso@^4.0.2, csso@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - - cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - - cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - - cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - - csstype@^2.5.7: - version "2.6.19" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa" - integrity sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ== - - csstype@^3.0.2, csstype@^3.0.6: - version "3.0.10" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" - integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== - - currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - - cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - - cypress-file-upload@5.0.8: - version "5.0.8" - resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1" - integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g== - - cypress-image-snapshot@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cypress-image-snapshot/-/cypress-image-snapshot-4.0.1.tgz#59084e713a8d03500c8e053ad7a76f3f18609648" - integrity sha512-PBpnhX/XItlx3/DAk5ozsXQHUi72exybBNH5Mpqj1DVmjq+S5Jd9WE5CRa4q5q0zuMZb2V2VpXHth6MjFpgj9Q== - dependencies: - chalk "^2.4.1" - fs-extra "^7.0.1" - glob "^7.1.3" - jest-image-snapshot "4.2.0" - pkg-dir "^3.0.0" - term-img "^4.0.0" - - cypress@9.3.1: - version "9.3.1" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-9.3.1.tgz#8116f52d49d6daf90a91e88f3eafd940234d2958" - integrity sha512-BODdPesxX6bkVUnH8BVsV8I/jn57zQtO1FEOUTiuG2us3kslW7g0tcuwiny7CKCmJUZz8S/D587ppC+s58a+5Q== - dependencies: - "@cypress/request" "^2.88.10" - "@cypress/xvfb" "^1.2.4" - "@types/node" "^14.14.31" - "@types/sinonjs__fake-timers" "8.1.1" - "@types/sizzle" "^2.3.2" - arch "^2.2.0" - blob-util "^2.0.2" - bluebird "^3.7.2" - buffer "^5.6.0" - cachedir "^2.3.0" - chalk "^4.1.0" - check-more-types "^2.24.0" - cli-cursor "^3.1.0" - cli-table3 "~0.6.1" - commander "^5.1.0" - common-tags "^1.8.0" - dayjs "^1.10.4" - debug "^4.3.2" - enquirer "^2.3.6" - eventemitter2 "^6.4.3" - execa "4.1.0" - executable "^4.1.1" - extract-zip "2.0.1" - figures "^3.2.0" - fs-extra "^9.1.0" - getos "^3.2.1" - is-ci "^3.0.0" - is-installed-globally "~0.4.0" - lazy-ass "^1.6.0" - listr2 "^3.8.3" - lodash "^4.17.21" - log-symbols "^4.0.0" - minimist "^1.2.5" - ospath "^1.2.2" - pretty-bytes "^5.6.0" - proxy-from-env "1.0.0" - request-progress "^3.0.0" - supports-color "^8.1.1" - tmp "~0.2.1" - untildify "^4.0.0" - url "^0.11.0" - yauzl "^2.10.0" - - cypress@^8.6.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-8.7.0.tgz#2ee371f383d8f233d3425b6cc26ddeec2668b6da" - integrity sha512-b1bMC3VQydC6sXzBMFnSqcvwc9dTZMgcaOzT0vpSD+Gq1yFc+72JDWi55sfUK5eIeNLAtWOGy1NNb6UlhMvB+Q== - dependencies: - "@cypress/request" "^2.88.6" - "@cypress/xvfb" "^1.2.4" - "@types/node" "^14.14.31" - "@types/sinonjs__fake-timers" "^6.0.2" - "@types/sizzle" "^2.3.2" - arch "^2.2.0" - blob-util "^2.0.2" - bluebird "^3.7.2" - cachedir "^2.3.0" - chalk "^4.1.0" - check-more-types "^2.24.0" - cli-cursor "^3.1.0" - cli-table3 "~0.6.0" - commander "^5.1.0" - common-tags "^1.8.0" - dayjs "^1.10.4" - debug "^4.3.2" - enquirer "^2.3.6" - eventemitter2 "^6.4.3" - execa "4.1.0" - executable "^4.1.1" - extract-zip "2.0.1" - figures "^3.2.0" - fs-extra "^9.1.0" - getos "^3.2.1" - is-ci "^3.0.0" - is-installed-globally "~0.4.0" - lazy-ass "^1.6.0" - listr2 "^3.8.3" - lodash "^4.17.21" - log-symbols "^4.0.0" - minimist "^1.2.5" - ospath "^1.2.2" - pretty-bytes "^5.6.0" - proxy-from-env "1.0.0" - ramda "~0.27.1" - request-progress "^3.0.0" - supports-color "^8.1.1" - tmp "~0.2.1" - untildify "^4.0.0" - url "^0.11.0" - yauzl "^2.10.0" - - d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" - integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== - - "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.1.1.tgz#7797eb53ead6b9083c75a45a681e93fc41bc468c" - integrity sha512-33qQ+ZoZlli19IFiQx4QEpf2CBEayMRzhlisJHSCsSUbDXv6ZishqS1x7uFVClKG4Wr7rZVHvaAttoLow6GqdQ== - dependencies: - internmap "1 - 2" - - d3-axis@1: - version "1.0.12" - resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9" - integrity sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ== - - d3-axis@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322" - integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw== - - d3-brush@1: - version "1.1.6" - resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.1.6.tgz#b0a22c7372cabec128bdddf9bddc058592f89e9b" - integrity sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA== - dependencies: - d3-dispatch "1" - d3-drag "1" - d3-interpolate "1" - d3-selection "1" - d3-transition "1" - - d3-brush@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c" - integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ== - dependencies: - d3-dispatch "1 - 3" - d3-drag "2 - 3" - d3-interpolate "1 - 3" - d3-selection "3" - d3-transition "3" - - d3-chord@1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.6.tgz#309157e3f2db2c752f0280fedd35f2067ccbb15f" - integrity sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA== - dependencies: - d3-array "1" - d3-path "1" - - d3-chord@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966" - integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g== - dependencies: - d3-path "1 - 3" - - d3-collection@1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e" - integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A== - - d3-color@1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" - integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== - - "d3-color@1 - 3", d3-color@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.0.1.tgz#03316e595955d1fcd39d9f3610ad41bb90194d0a" - integrity sha512-6/SlHkDOBLyQSJ1j1Ghs82OIUXpKWlR0hCsw0XrLSQhuUPuCSmLQ1QPH98vpnQxMUQM2/gfAkUEWsupVpd9JGw== - - d3-contour@1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-1.3.2.tgz#652aacd500d2264cb3423cee10db69f6f59bead3" - integrity sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg== - dependencies: - d3-array "^1.1.1" - - d3-contour@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-3.0.1.tgz#2c64255d43059599cd0dba8fe4cc3d51ccdd9bbd" - integrity sha512-0Oc4D0KyhwhM7ZL0RMnfGycLN7hxHB8CMmwZ3+H26PWAG0ozNuYG5hXSDNgmP1SgJkQMrlG6cP20HoaSbvcJTQ== - dependencies: - d3-array "2 - 3" - - d3-delaunay@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.2.tgz#7fd3717ad0eade2fc9939f4260acfb503f984e92" - integrity sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ== - dependencies: - delaunator "5" - - d3-dispatch@1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" - integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== - - "d3-dispatch@1 - 3", d3-dispatch@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" - integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== - - d3-drag@1: - version "1.2.5" - resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70" - integrity sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w== - dependencies: - d3-dispatch "1" - d3-selection "1" - - "d3-drag@2 - 3", d3-drag@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" - integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== - dependencies: - d3-dispatch "1 - 3" - d3-selection "3" - - d3-dsv@1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.2.0.tgz#9d5f75c3a5f8abd611f74d3f5847b0d4338b885c" - integrity sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g== - dependencies: - commander "2" - iconv-lite "0.4" - rw "1" - - "d3-dsv@1 - 3", d3-dsv@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" - integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== - dependencies: - commander "7" - iconv-lite "0.6" - rw "1" - - d3-ease@1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2" - integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ== - - "d3-ease@1 - 3", d3-ease@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" - integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== - - d3-fetch@1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-1.2.0.tgz#15ce2ecfc41b092b1db50abd2c552c2316cf7fc7" - integrity sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA== - dependencies: - d3-dsv "1" - - d3-fetch@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22" - integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw== - dependencies: - d3-dsv "1 - 3" - - d3-force@1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.2.1.tgz#fd29a5d1ff181c9e7f0669e4bd72bdb0e914ec0b" - integrity sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg== - dependencies: - d3-collection "1" - d3-dispatch "1" - d3-quadtree "1" - d3-timer "1" - - d3-force@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" - integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== - dependencies: - d3-dispatch "1 - 3" - d3-quadtree "1 - 3" - d3-timer "1 - 3" - - d3-format@1: - version "1.4.5" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" - integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ== - - "d3-format@1 - 3", d3-format@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" - integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== - - d3-geo@1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f" - integrity sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg== - dependencies: - d3-array "1" - - d3-geo@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.0.1.tgz#4f92362fd8685d93e3b1fae0fd97dc8980b1ed7e" - integrity sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA== - dependencies: - d3-array "2.5.0 - 3" - - d3-hierarchy@1: - version "1.1.9" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83" - integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ== - - d3-hierarchy@3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.1.tgz#9cbb0ffd2375137a351e6cfeed344a06d4ff4597" - integrity sha512-LtAIu54UctRmhGKllleflmHalttH3zkfSi4NlKrTAoFKjC+AFBJohsCAdgCBYQwH0F8hIOGY89X1pPqAchlMkA== - - d3-interpolate@1, d3-interpolate@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987" - integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA== - dependencies: - d3-color "1" - - "d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" - integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== - dependencies: - d3-color "1 - 3" - - d3-path@1: - version "1.0.9" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" - integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== - - "d3-path@1 - 3", d3-path@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.0.1.tgz#f09dec0aaffd770b7995f1a399152bf93052321e" - integrity sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w== - - d3-polygon@1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.6.tgz#0bf8cb8180a6dc107f518ddf7975e12abbfbd38e" - integrity sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ== - - d3-polygon@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398" - integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg== - - d3-quadtree@1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.7.tgz#ca8b84df7bb53763fe3c2f24bd435137f4e53135" - integrity sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA== - - "d3-quadtree@1 - 3", d3-quadtree@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" - integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== - - d3-random@1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-1.1.2.tgz#2833be7c124360bf9e2d3fd4f33847cfe6cab291" - integrity sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ== - - d3-random@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4" - integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ== - - d3-scale-chromatic@1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz#54e333fc78212f439b14641fb55801dd81135a98" - integrity sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg== - dependencies: - d3-color "1" - d3-interpolate "1" - - d3-scale-chromatic@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a" - integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g== - dependencies: - d3-color "1 - 3" - d3-interpolate "1 - 3" - - d3-scale@2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f" - integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw== - dependencies: - d3-array "^1.2.0" - d3-collection "1" - d3-format "1" - d3-interpolate "1" - d3-time "1" - d3-time-format "2" - - d3-scale@4, d3-scale@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" - integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== - dependencies: - d3-array "2.10.0 - 3" - d3-format "1 - 3" - d3-interpolate "1.2.0 - 3" - d3-time "2.1.1 - 3" - d3-time-format "2 - 4" - - d3-selection@1, d3-selection@^1.1.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c" - integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg== - - "d3-selection@2 - 3", d3-selection@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" - integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== - - d3-shape@1: - version "1.3.7" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" - integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== - dependencies: - d3-path "1" - - d3-shape@3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.1.0.tgz#c8a495652d83ea6f524e482fca57aa3f8bc32556" - integrity sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ== - dependencies: - d3-path "1 - 3" - - d3-time-format@2: - version "2.3.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850" - integrity sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ== - dependencies: - d3-time "1" - - "d3-time-format@2 - 4", d3-time-format@4: - version "4.1.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" - integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== - dependencies: - d3-time "1 - 3" - - d3-time@1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" - integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== - - "d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3, d3-time@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.0.0.tgz#65972cb98ae2d4954ef5c932e8704061335d4975" - integrity sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ== - dependencies: - d3-array "2 - 3" - - d3-timer@1: - version "1.0.10" - resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5" - integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw== - - "d3-timer@1 - 3", d3-timer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" - integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== - - d3-transition@1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398" - integrity sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA== - dependencies: - d3-color "1" - d3-dispatch "1" - d3-ease "1" - d3-interpolate "1" - d3-selection "^1.1.0" - d3-timer "1" - - "d3-transition@2 - 3", d3-transition@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" - integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== - dependencies: - d3-color "1 - 3" - d3-dispatch "1 - 3" - d3-ease "1 - 3" - d3-interpolate "1 - 3" - d3-timer "1 - 3" - - d3-voronoi@1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" - integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg== - - d3-zoom@1: - version "1.8.3" - resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.8.3.tgz#b6a3dbe738c7763121cd05b8a7795ffe17f4fc0a" - integrity sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ== - dependencies: - d3-dispatch "1" - d3-drag "1" - d3-interpolate "1" - d3-selection "1" - d3-transition "1" - - d3-zoom@3: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" - integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== - dependencies: - d3-dispatch "1 - 3" - d3-drag "2 - 3" - d3-interpolate "1 - 3" - d3-selection "2 - 3" - d3-transition "2 - 3" - - d3@5.15.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/d3/-/d3-5.15.0.tgz#ffd44958e6a3cb8a59a84429c45429b8bca5677a" - integrity sha512-C+E80SL2nLLtmykZ6klwYj5rPqB5nlfN5LdWEAVdWPppqTD8taoJi2PxLZjPeYT8FFRR2yucXq+kBlOnnvZeLg== - dependencies: - d3-array "1" - d3-axis "1" - d3-brush "1" - d3-chord "1" - d3-collection "1" - d3-color "1" - d3-contour "1" - d3-dispatch "1" - d3-drag "1" - d3-dsv "1" - d3-ease "1" - d3-fetch "1" - d3-force "1" - d3-format "1" - d3-geo "1" - d3-hierarchy "1" - d3-interpolate "1" - d3-path "1" - d3-polygon "1" - d3-quadtree "1" - d3-random "1" - d3-scale "2" - d3-scale-chromatic "1" - d3-selection "1" - d3-shape "1" - d3-time "1" - d3-time-format "2" - d3-timer "1" - d3-transition "1" - d3-voronoi "1" - d3-zoom "1" - - d3@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/d3/-/d3-7.3.0.tgz#f3d5a22c1f658952a6491cf50132f5267ed7a40a" - integrity sha512-MDRLJCMK232OJQRqGljQ/gCxtB8k3/sLKFjftMjzPB3nKVUODpdW9Rb3vcq7U8Ka5YKoZkAmp++Ur6I+6iNWIw== - dependencies: - d3-array "3" - d3-axis "3" - d3-brush "3" - d3-chord "3" - d3-color "3" - d3-contour "3" - d3-delaunay "6" - d3-dispatch "3" - d3-drag "3" - d3-dsv "3" - d3-ease "3" - d3-fetch "3" - d3-force "3" - d3-format "3" - d3-geo "3" - d3-hierarchy "3" - d3-interpolate "3" - d3-path "3" - d3-polygon "3" - d3-quadtree "3" - d3-random "3" - d3-scale "4" - d3-scale-chromatic "3" - d3-selection "3" - d3-shape "3" - d3-time "3" - d3-time-format "4" - d3-timer "3" - d3-transition "3" - d3-zoom "3" - - damerau-levenshtein@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" - integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== - - dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== - - dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - - data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - - date-fns@2.28.0, date-fns@^2.0.1, date-fns@^2.24.0, date-fns@^2.27.0: - version "2.28.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" - integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== - - date-format@^0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-0.0.0.tgz#09206863ab070eb459acea5542cbd856b11966b3" - integrity sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM= - - dateformat@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" - integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== - - dayjs@^1.10.4: - version "1.10.7" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" - integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== - - debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - - debug@4, debug@4.3.3, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - - debug@^0.7.2: - version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - integrity sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk= - - debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6, debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - - debug@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - - debuglog@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= - - decamelize-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - - decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - - decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - - decimal.js@^10.2.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== - - decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - - decompress-response@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" - integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== - dependencies: - mimic-response "^2.0.0" - - decompress-response@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f" - integrity sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw== - dependencies: - mimic-response "^2.0.0" - - dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= - - deep-equal@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - - deep-is@^0.1.3, deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - - deep-object-diff@^1.1.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.7.tgz#348b3246f426427dd633eaa50e1ed1fc2eafc7e4" - integrity sha512-QkgBca0mL08P6HiOjoqvmm6xOAl2W6CT2+34Ljhg0OeFan8cwlcdq8jrLKsBBuUFAZLsN5b6y491KdKEoSo9lg== - - deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - - defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - - defer-to-connect@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" - integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== - - define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== - - define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - - define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - - define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - - define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - - del@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" - integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== - dependencies: - "@types/glob" "^7.1.1" - globby "^6.1.0" - is-path-cwd "^2.0.0" - is-path-in-cwd "^2.0.0" - p-map "^2.0.0" - pify "^4.0.1" - rimraf "^2.6.3" - - delaunator@5: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b" - integrity sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw== - dependencies: - robust-predicates "^3.0.0" - - delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - - delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - - depd@^1.1.2, depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - - deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - - des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - - destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - - detab@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43" - integrity sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g== - dependencies: - repeat-string "^1.5.4" - - detect-indent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" - integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= - - detect-indent@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" - integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== - - detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - - detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - - detect-port-alt@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" - integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== - dependencies: - address "^1.0.1" - debug "^2.6.0" - - detect-port@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" - integrity sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ== - dependencies: - address "^1.0.1" - debug "^2.6.0" - - devtools-protocol@0.0.927104: - version "0.0.927104" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.927104.tgz#3bba0fca644bcdce1bcebb10ae392ab13428a7a0" - integrity sha512-5jfffjSuTOv0Lz53wTNNTcCUV8rv7d82AhYcapj28bC2B5tDxEZzVb7k51cNxZP2KHw24QE+sW7ZuSeD9NfMpA== - - devtools-protocol@0.0.960912: - version "0.0.960912" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.960912.tgz#411c1fa355eddb72f06c4a8743f2808766db6245" - integrity sha512-I3hWmV9rWHbdnUdmMKHF2NuYutIM2kXz2mdXW8ha7TbRlGTVs+PF+PsB5QWvpCek4Fy9B+msiispCfwlhG5Sqg== - - dezalgo@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - dependencies: - asap "^2.0.0" - wrappy "1" - - diff-sequences@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" - integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== - - diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - - diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - - diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - - dir-glob@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - - dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - - direction@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/direction/-/direction-0.1.5.tgz#ce5d797f97e26f8be7beff53f7dc40e1c1a9ec4c" - integrity sha1-zl15f5fib4vnvv9T99xA4cGp7Ew= - - discontinuous-range@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" - integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo= - - doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - - doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - - document.contains@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/document.contains/-/document.contains-1.0.2.tgz#4260abad67a6ae9e135c1be83d68da0db169d5f0" - integrity sha512-YcvYFs15mX8m3AO1QNQy3BlIpSMfNRj3Ujk2BEJxsZG+HZf7/hZ6jr7mDpXrF8q+ff95Vef5yjhiZxm8CGJr6Q== - dependencies: - define-properties "^1.1.3" - - dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: - version "0.5.12" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.12.tgz#0fea9b3f28976a52fed7298d2cfdcdff29811cda" - integrity sha512-gQ2mON6fLWZeM8ubjzL7RtMeHS/g8hb82j4MjHmcQECD7pevWsMlhqwp9BjIRrQvmyJMMyv/XiO1cXzeFlUw4g== - - dom-align@^1.7.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b" - integrity sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg== - - dom-converter@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" - integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== - dependencies: - utila "~0.4" - - dom-css@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/dom-css/-/dom-css-2.1.0.tgz#fdbc2d5a015d0a3e1872e11472bbd0e7b9e6a202" - integrity sha1-/bwtWgFdCj4YcuEUcrvQ57nmogI= - dependencies: - add-px-to-style "1.0.0" - prefix-style "2.0.1" - to-camel-case "1.0.0" - - dom-helpers@^3.3.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" - integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== - dependencies: - "@babel/runtime" "^7.1.2" - - dom-helpers@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" - integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - - dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - - dom-serializer@^1.0.1, dom-serializer@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" - integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - - dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - - domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - - domelementtype@1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - - domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== - - domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - - domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" - integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== - dependencies: - domelementtype "^2.2.0" - - domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - - domutils@^2.5.2, domutils@^2.7.0, domutils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" - integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - - dot-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" - integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - - dot-prop@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4" - integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ== - dependencies: - is-obj "^1.0.0" - - dot-prop@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - - dot-prop@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" - integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== - dependencies: - is-obj "^2.0.0" - - dotenv-expand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== - - dotenv@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== - - dotenv@^8.0.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - - downshift@^6.0.15: - version "6.1.7" - resolved "https://registry.yarnpkg.com/downshift/-/downshift-6.1.7.tgz#fdb4c4e4f1d11587985cd76e21e8b4b3fa72e44c" - integrity sha512-cVprZg/9Lvj/uhYRxELzlu1aezRcgPWBjTvspiGTVEU64gF5pRdSRKFVLcxqsZC637cLAGMbL40JavEfWnqgNg== - dependencies: - "@babel/runtime" "^7.14.8" - compute-scroll-into-view "^1.0.17" - prop-types "^15.7.2" - react-is "^17.0.2" - tslib "^2.3.0" - - duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - - duplexer@^0.1.1, duplexer@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - - duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - - ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - - ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - - electron-to-chromium@^1.4.71: - version "1.4.71" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.71.tgz#17056914465da0890ce00351a3b946fd4cd51ff6" - integrity sha512-Hk61vXXKRb2cd3znPE9F+2pLWdIOmP7GjiTj45y6L3W/lO+hSnUSUhq+6lEaERWBdZOHbk2s3YV5c9xVl3boVw== - - element-resize-detector@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.2.4.tgz#3e6c5982dd77508b5fa7e6d5c02170e26325c9b1" - integrity sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg== - dependencies: - batch-processor "1.0.0" - - elliptic@^6.5.3: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - - emittery@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" - integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== - - emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - - emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - - emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - - emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - - emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - - emotion-theming@^10.0.27: - version "10.3.0" - resolved "https://registry.yarnpkg.com/emotion-theming/-/emotion-theming-10.3.0.tgz#7f84d7099581d7ffe808aab5cd870e30843db72a" - integrity sha512-mXiD2Oj7N9b6+h/dC6oLf9hwxbtKHQjoIqtodEyL8CpkN4F3V4IK/BT4D0C7zSs4BBFOu4UlPJbvvBLa88SGEA== - dependencies: - "@babel/runtime" "^7.5.5" - "@emotion/weak-memoize" "0.2.5" - hoist-non-react-statics "^3.3.0" - - encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - - encoding@^0.1.12: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - - end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - - endent@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/endent/-/endent-2.1.0.tgz#5aaba698fb569e5e18e69e1ff7a28ff35373cd88" - integrity sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w== - dependencies: - dedent "^0.7.0" - fast-json-parse "^1.0.3" - objectorarray "^1.0.5" - - enhanced-resolve@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" - integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4= - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.2.0" - tapable "^0.1.8" - - enhanced-resolve@^4.0.0, enhanced-resolve@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - - enhanced-resolve@^5.8.3: - version "5.9.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.0.tgz#49ac24953ac8452ed8fed2ef1340fc8e043667ee" - integrity sha512-weDYmzbBygL7HzGGS26M3hGQx68vehdEg6VUmqSOaFzXExFqlnKuSvsEJCVGQHScS8CQMbrAqftT+AzzHNt/YA== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - - enquirer@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - - entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - - env-paths@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" - integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== - - envinfo@^7.7.3, envinfo@^7.7.4: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== - - enzyme-adapter-react-16@^1.15.5: - version "1.15.6" - resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.6.tgz#fd677a658d62661ac5afd7f7f541f141f8085901" - integrity sha512-yFlVJCXh8T+mcQo8M6my9sPgeGzj85HSHi6Apgf1Cvq/7EL/J9+1JoJmJsRxZgyTvPMAqOEpRSu/Ii/ZpyOk0g== - dependencies: - enzyme-adapter-utils "^1.14.0" - enzyme-shallow-equal "^1.0.4" - has "^1.0.3" - object.assign "^4.1.2" - object.values "^1.1.2" - prop-types "^15.7.2" - react-is "^16.13.1" - react-test-renderer "^16.0.0-0" - semver "^5.7.0" - - enzyme-adapter-utils@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.14.0.tgz#afbb0485e8033aa50c744efb5f5711e64fbf1ad0" - integrity sha512-F/z/7SeLt+reKFcb7597IThpDp0bmzcH1E9Oabqv+o01cID2/YInlqHbFl7HzWBl4h3OdZYedtwNDOmSKkk0bg== - dependencies: - airbnb-prop-types "^2.16.0" - function.prototype.name "^1.1.3" - has "^1.0.3" - object.assign "^4.1.2" - object.fromentries "^2.0.3" - prop-types "^15.7.2" - semver "^5.7.1" - - enzyme-shallow-equal@^1.0.1, enzyme-shallow-equal@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz#b9256cb25a5f430f9bfe073a84808c1d74fced2e" - integrity sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q== - dependencies: - has "^1.0.3" - object-is "^1.1.2" - - enzyme@^3.11.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.11.0.tgz#71d680c580fe9349f6f5ac6c775bc3e6b7a79c28" - integrity sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw== - dependencies: - array.prototype.flat "^1.2.3" - cheerio "^1.0.0-rc.3" - enzyme-shallow-equal "^1.0.1" - function.prototype.name "^1.1.2" - has "^1.0.3" - html-element-map "^1.2.0" - is-boolean-object "^1.0.1" - is-callable "^1.1.5" - is-number-object "^1.0.4" - is-regex "^1.0.5" - is-string "^1.0.5" - is-subset "^0.1.1" - lodash.escape "^4.0.1" - lodash.isequal "^4.5.0" - object-inspect "^1.7.0" - object-is "^1.0.2" - object.assign "^4.1.0" - object.entries "^1.1.1" - object.values "^1.1.1" - raf "^3.4.1" - rst-selector-parser "^2.2.3" - string.prototype.trim "^1.2.1" - - err-code@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" - integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== - - errno@^0.1.1, errno@^0.1.3, errno@^0.1.7, errno@~0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.1" - - error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - - error-stack-parser@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.7.tgz#b0c6e2ce27d0495cf78ad98715e0cad1219abb57" - integrity sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA== - dependencies: - stackframe "^1.1.1" - - error@^7.0.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" - integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== - dependencies: - string-template "~0.2.1" - - es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - - es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - - es-get-iterator@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" - integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.0" - has-symbols "^1.0.1" - is-arguments "^1.1.0" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.5" - isarray "^2.0.5" - - es-module-lexer@^0.9.0: - version "0.9.3" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" - integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== - - es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - - es5-shim@^4.5.13: - version "4.6.5" - resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.6.5.tgz#2124bb073b7cede2ed23b122a1fd87bb7b0bb724" - integrity sha512-vfQ4UAai8szn0sAubCy97xnZ4sJVDD1gt/Grn736hg8D7540wemIb1YPrYZSTqlM2H69EQX1or4HU/tSwRTI3w== - - es6-shim@^0.35.5: - version "0.35.6" - resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.6.tgz#d10578301a83af2de58b9eadb7c2c9945f7388a0" - integrity sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA== - - esbuild-android-arm64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.23.tgz#c89b3c50b4f47668dcbeb0b34ee4615258818e71" - integrity sha512-k9sXem++mINrZty1v4FVt6nC5BQCFG4K2geCIUUqHNlTdFnuvcqsY7prcKZLFhqVC1rbcJAr9VSUGFL/vD4vsw== - - esbuild-darwin-64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.23.tgz#1c131e8cb133ed935ca32f824349a117c896a15b" - integrity sha512-lB0XRbtOYYL1tLcYw8BoBaYsFYiR48RPrA0KfA/7RFTr4MV7Bwy/J4+7nLsVnv9FGuQummM3uJ93J3ptaTqFug== - - esbuild-darwin-arm64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.23.tgz#3c6245a50109dd84953f53d7833bd3b4f0e8c6fa" - integrity sha512-yat73Z/uJ5tRcfRiI4CCTv0FSnwErm3BJQeZAh+1tIP0TUNh6o+mXg338Zl5EKChD+YGp6PN+Dbhs7qa34RxSw== - - esbuild-freebsd-64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.23.tgz#0cdc54e72d3dd9cd992f9c2960055e68a7f8650c" - integrity sha512-/1xiTjoLuQ+LlbfjJdKkX45qK/M7ARrbLmyf7x3JhyQGMjcxRYVR6Dw81uH3qlMHwT4cfLW4aEVBhP1aNV7VsA== - - esbuild-freebsd-arm64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.23.tgz#1d11faed3a0c429e99b7dddef84103eb509788b2" - integrity sha512-uyPqBU/Zcp6yEAZS4LKj5jEE0q2s4HmlMBIPzbW6cTunZ8cyvjG6YWpIZXb1KK3KTJDe62ltCrk3VzmWHp+iLg== - - esbuild-linux-32@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.23.tgz#fd9f033fc27dcab61100cb1eb1c936893a68c841" - integrity sha512-37R/WMkQyUfNhbH7aJrr1uCjDVdnPeTHGeDhZPUNhfoHV0lQuZNCKuNnDvlH/u/nwIYZNdVvz1Igv5rY/zfrzQ== - - esbuild-linux-64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.23.tgz#c04c438514f1359ecb1529205d0c836d4165f198" - integrity sha512-H0gztDP60qqr8zoFhAO64waoN5yBXkmYCElFklpd6LPoobtNGNnDe99xOQm28+fuD75YJ7GKHzp/MLCLhw2+vQ== - - esbuild-linux-arm64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.23.tgz#d1b3ab2988ab0734886eb9e811726f7db099ab96" - integrity sha512-c4MLOIByNHR55n3KoYf9hYDfBRghMjOiHLaoYLhkQkIabb452RWi+HsNgB41sUpSlOAqfpqKPFNg7VrxL3UX9g== - - esbuild-linux-arm@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.23.tgz#df7558b6a5076f5eb9fd387c8704f768b61d97fb" - integrity sha512-x64CEUxi8+EzOAIpCUeuni0bZfzPw/65r8tC5cy5zOq9dY7ysOi5EVQHnzaxS+1NmV+/RVRpmrzGw1QgY2Xpmw== - - esbuild-linux-mips64le@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.23.tgz#bb4c47fccc9493d460ffeb1f88e8a97a98a14f8b" - integrity sha512-kHKyKRIAedYhKug2EJpyJxOUj3VYuamOVA1pY7EimoFPzaF3NeY7e4cFBAISC/Av0/tiV0xlFCt9q0HJ68IBIw== - - esbuild-linux-ppc64le@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.23.tgz#a332dbc8a1b4e30cfe1261bfaa5cef57c9c8c02a" - integrity sha512-7ilAiJEPuJJnJp/LiDO0oJm5ygbBPzhchJJh9HsHZzeqO+3PUzItXi+8PuicY08r0AaaOe25LA7sGJ0MzbfBag== - - esbuild-linux-riscv64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.23.tgz#85675f3f931f5cd7cfb238fd82f77a62ffcb6d86" - integrity sha512-fbL3ggK2wY0D8I5raPIMPhpCvODFE+Bhb5QGtNP3r5aUsRR6TQV+ZBXIaw84iyvKC8vlXiA4fWLGhghAd/h/Zg== - - esbuild-linux-s390x@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.23.tgz#a526282a696e6d846f4c628f5315475518c0c0f0" - integrity sha512-GHMDCyfy7+FaNSO8RJ8KCFsnax8fLUsOrj9q5Gi2JmZMY0Zhp75keb5abTFCq2/Oy6KVcT0Dcbyo/bFb4rIFJA== - - esbuild-loader@^2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.18.0.tgz#7b9548578ab954574fd94655693d22aa5ec74120" - integrity sha512-AKqxM3bI+gvGPV8o6NAhR+cBxVO8+dh+O0OXBHIXXwuSGumckbPWHzZ17subjBGI2YEGyJ1STH7Haj8aCrwL/w== - dependencies: - esbuild "^0.14.6" - joycon "^3.0.1" - json5 "^2.2.0" - loader-utils "^2.0.0" - tapable "^2.2.0" - webpack-sources "^2.2.0" - - esbuild-netbsd-64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.23.tgz#8e456605694719aa1be4be266d6cd569c06dfaf5" - integrity sha512-ovk2EX+3rrO1M2lowJfgMb/JPN1VwVYrx0QPUyudxkxLYrWeBxDKQvc6ffO+kB4QlDyTfdtAURrVzu3JeNdA2g== - - esbuild-openbsd-64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.23.tgz#f2fc51714b4ddabc86e4eb30ca101dd325db2f7d" - integrity sha512-uYYNqbVR+i7k8ojP/oIROAHO9lATLN7H2QeXKt2H310Fc8FJj4y3Wce6hx0VgnJ4k1JDrgbbiXM8rbEgQyg8KA== - - esbuild-sunos-64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.23.tgz#a408f33ea20e215909e20173a0fd78b1aaad1f8e" - integrity sha512-hAzeBeET0+SbScknPzS2LBY6FVDpgE+CsHSpe6CEoR51PApdn2IB0SyJX7vGelXzlyrnorM4CAsRyb9Qev4h9g== - - esbuild-windows-32@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.23.tgz#b9005bbff54dac3975ff355d5de2b5e37165d128" - integrity sha512-Kttmi3JnohdaREbk6o9e25kieJR379TsEWF0l39PQVHXq3FR6sFKtVPgY8wk055o6IB+rllrzLnbqOw/UV60EA== - - esbuild-windows-64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.23.tgz#2b5a99befeaca6aefdad32d738b945730a60a060" - integrity sha512-JtIT0t8ymkpl6YlmOl6zoSWL5cnCgyLaBdf/SiU/Eg3C13r0NbHZWNT/RDEMKK91Y6t79kTs3vyRcNZbfu5a8g== - - esbuild-windows-arm64@0.14.23: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.23.tgz#edc560bbadb097eb45fc235aeacb942cb94a38c0" - integrity sha512-cTFaQqT2+ik9e4hePvYtRZQ3pqOvKDVNarzql0VFIzhc0tru/ZgdLoXd6epLiKT+SzoSce6V9YJ+nn6RCn6SHw== - - esbuild@^0.14.6: - version "0.14.23" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.23.tgz#95e842cb22bc0c7d82c140adc16788aac91469fe" - integrity sha512-XjnIcZ9KB6lfonCa+jRguXyRYcldmkyZ99ieDksqW/C8bnyEX299yA4QH2XcgijCgaddEZePPTgvx/2imsq7Ig== - optionalDependencies: - esbuild-android-arm64 "0.14.23" - esbuild-darwin-64 "0.14.23" - esbuild-darwin-arm64 "0.14.23" - esbuild-freebsd-64 "0.14.23" - esbuild-freebsd-arm64 "0.14.23" - esbuild-linux-32 "0.14.23" - esbuild-linux-64 "0.14.23" - esbuild-linux-arm "0.14.23" - esbuild-linux-arm64 "0.14.23" - esbuild-linux-mips64le "0.14.23" - esbuild-linux-ppc64le "0.14.23" - esbuild-linux-riscv64 "0.14.23" - esbuild-linux-s390x "0.14.23" - esbuild-netbsd-64 "0.14.23" - esbuild-openbsd-64 "0.14.23" - esbuild-sunos-64 "0.14.23" - esbuild-windows-32 "0.14.23" - esbuild-windows-64 "0.14.23" - esbuild-windows-arm64 "0.14.23" - - escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - - escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - - escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - - escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - - escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - - escodegen@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" - integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - - eslint-config-airbnb-base@^14.2.1: - version "14.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" - integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== - dependencies: - confusing-browser-globals "^1.0.10" - object.assign "^4.1.2" - object.entries "^1.1.2" - - eslint-config-airbnb-typescript-prettier@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript-prettier/-/eslint-config-airbnb-typescript-prettier-4.2.0.tgz#54101963a3ec868c04d2f685f9ffcf04052d5cea" - integrity sha512-t2glck+2p/oAx0ibhZhWSU4xrJZtef6zrLH/tLNzS/JmfwYoGHWRQBT53p4lrLqk57DhE+GG9qh+6WN6IkiYvA== - dependencies: - "@typescript-eslint/eslint-plugin" "^4.7.0" - "@typescript-eslint/parser" "^4.7.0" - eslint-config-airbnb "^18.2.1" - eslint-config-prettier "^6.15.0" - eslint-plugin-import "^2.22.1" - eslint-plugin-jsx-a11y "^6.4.1" - eslint-plugin-prettier "^3.1.4" - eslint-plugin-react "^7.21.5" - eslint-plugin-react-hooks "^4.2.0" - - eslint-config-airbnb-typescript@^14.0.0: - version "14.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-14.0.2.tgz#4dc1583b9eab671bb011dea7d4ff1fc0d88e6e09" - integrity sha512-oaVR63DqpRUiOOeSVxIzhD3FXbqJRH+7Lt9GCMsS9SKgrRW3XpZINN2FO4JEsnaHEGkktumd0AHE9K7KQNuXSQ== - dependencies: - eslint-config-airbnb-base "^14.2.1" - - eslint-config-airbnb@18.2.1, eslint-config-airbnb@^18.2.1: - version "18.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz#b7fe2b42f9f8173e825b73c8014b592e449c98d9" - integrity sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg== - dependencies: - eslint-config-airbnb-base "^14.2.1" - object.assign "^4.1.2" - object.entries "^1.1.2" - - eslint-config-prettier@^6.15.0: - version "6.15.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" - integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== - dependencies: - get-stdin "^6.0.0" - - eslint-config-prettier@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz#f4a4bd2832e810e8cc7c1411ec85b3e85c0c53f9" - integrity sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg== - - eslint-import-resolver-lerna@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-lerna/-/eslint-import-resolver-lerna-2.0.0.tgz#a96a6eaa9c467d9bf195f538fa6c11cdbd95f5da" - integrity sha512-TJ//wx/tDR6SrSXMuORcc7dwQJQrkgf0AT7cnRD/ADEBpe9sLHc4rbh2JxVYRDw6rauHHxcvdYb4EICT+xd63Q== - - eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== - dependencies: - debug "^3.2.7" - resolve "^1.20.0" - - eslint-import-resolver-webpack@^0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.2.tgz#fc813df0d08b9265cc7072d22393bda5198bdc1e" - integrity sha512-XodIPyg1OgE2h5BDErz3WJoK7lawxKTJNhgPNafRST6csC/MZC+L5P6kKqsZGRInpbgc02s/WZMrb4uGJzcuRg== - dependencies: - array-find "^1.0.0" - debug "^3.2.7" - enhanced-resolve "^0.9.1" - find-root "^1.1.0" - has "^1.0.3" - interpret "^1.4.0" - is-core-module "^2.7.0" - is-regex "^1.1.4" - lodash "^4.17.21" - resolve "^1.20.0" - semver "^5.7.1" - - eslint-module-utils@^2.7.2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" - integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== - dependencies: - debug "^3.2.7" - find-up "^2.1.0" - - eslint-plugin-css-modules@^2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-css-modules/-/eslint-plugin-css-modules-2.11.0.tgz#8de4d01d523a2d51c03043fa8004aab6b6cf3b1a" - integrity sha512-CLvQvJOMlCywZzaI4HVu7QH/ltgNXvCg7giJGiE+sA9wh5zQ+AqTgftAzrERV22wHe1p688wrU/Zwxt1Ry922w== - dependencies: - gonzales-pe "^4.0.3" - lodash "^4.17.2" - - eslint-plugin-cypress@^2.12.1: - version "2.12.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz#9aeee700708ca8c058e00cdafe215199918c2632" - integrity sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA== - dependencies: - globals "^11.12.0" - - eslint-plugin-import@^2.22.1: - version "2.25.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" - integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== - dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.2" - has "^1.0.3" - is-core-module "^2.8.0" - is-glob "^4.0.3" - minimatch "^3.0.4" - object.values "^1.1.5" - resolve "^1.20.0" - tsconfig-paths "^3.12.0" - - eslint-plugin-jest@^25.3.4: - version "25.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz#ff4ac97520b53a96187bad9c9814e7d00de09a6a" - integrity sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ== - dependencies: - "@typescript-eslint/experimental-utils" "^5.0.0" - - eslint-plugin-jsx-a11y@^6.4.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" - integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g== - dependencies: - "@babel/runtime" "^7.16.3" - aria-query "^4.2.2" - array-includes "^3.1.4" - ast-types-flow "^0.0.7" - axe-core "^4.3.5" - axobject-query "^2.2.0" - damerau-levenshtein "^1.0.7" - emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.2.1" - language-tags "^1.0.5" - minimatch "^3.0.4" - - eslint-plugin-prettier@^3.1.4, eslint-plugin-prettier@^3.3.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" - integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== - dependencies: - prettier-linter-helpers "^1.0.0" - - eslint-plugin-react-hooks@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.0.tgz#81196b990043cde339e25c6662aeebe32ac52d01" - integrity sha512-YKBY+kilK5wrwIdQnCF395Ya6nDro3EAMoe+2xFkmyklyhF16fH83TrQOo9zbZIDxBsXFgBbywta/0JKRNFDkw== - - eslint-plugin-react-hooks@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" - integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== - - eslint-plugin-react@^7.21.5: - version "7.28.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz#8f3ff450677571a659ce76efc6d80b6a525adbdf" - integrity sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw== - dependencies: - array-includes "^3.1.4" - array.prototype.flatmap "^1.2.5" - doctrine "^2.1.0" - estraverse "^5.3.0" - jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.0.4" - object.entries "^1.1.5" - object.fromentries "^2.0.5" - object.hasown "^1.1.0" - object.values "^1.1.5" - prop-types "^15.7.2" - resolve "^2.0.0-next.3" - semver "^6.3.0" - string.prototype.matchall "^4.0.6" - - eslint-scope@5.1.1, eslint-scope@^5.1.0, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - - eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - - eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - - eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - - eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.2.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - - eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - - eslint-visitor-keys@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - - eslint-webpack-plugin@^2.4.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-2.6.0.tgz#3bd4ada4e539cb1f6687d2f619073dbb509361cd" - integrity sha512-V+LPY/T3kur5QO3u+1s34VDTcRxjXWPUGM4hlmTb5DwVD0OQz631yGTxJZf4SpAqAjdbBVe978S8BJeHpAdOhQ== - dependencies: - "@types/eslint" "^7.28.2" - arrify "^2.0.1" - jest-worker "^27.3.1" - micromatch "^4.0.4" - normalize-path "^3.0.0" - schema-utils "^3.1.1" - - eslint@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.2.0.tgz#d41b2e47804b30dbabb093a967fb283d560082e6" - integrity sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.1.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.2.0" - espree "^7.1.0" - esquery "^1.2.0" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.14" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - - esm@^3.2.25: - version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" - integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== - - espree@^7.1.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - - esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - - esquery@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - - esrecurse@^4.1.0, esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - - esrever@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/esrever/-/esrever-0.2.0.tgz#96e9d28f4f1b1a76784cd5d490eaae010e7407b8" - integrity sha1-lunSj08bGnZ4TNXUkOquAQ50B7g= - - estimo@^2.2.8: - version "2.3.3" - resolved "https://registry.yarnpkg.com/estimo/-/estimo-2.3.3.tgz#a8c58d350012822033810db0c130b625c492e63c" - integrity sha512-gl538IDBGtrT+ad9oLIPCdA4YeMJwyqDKFoqo8aHcls81RiX89OXmnEDV3dSMM/CLttuFm5Tl61ZJL0ERIEn/A== - dependencies: - "@sitespeed.io/tracium" "^0.3.3" - commander "^9.0.0" - find-chrome-bin "~0.1.0" - nanoid "^3.2.0" - puppeteer-core "^13.1.3" - - estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - - estree-to-babel@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/estree-to-babel/-/estree-to-babel-3.2.1.tgz#82e78315275c3ca74475fdc8ac1a5103c8a75bf5" - integrity sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg== - dependencies: - "@babel/traverse" "^7.1.6" - "@babel/types" "^7.2.0" - c8 "^7.6.0" - - esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - - etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - - eventemitter2@^6.4.3: - version "6.4.5" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.5.tgz#97380f758ae24ac15df8353e0cc27f8b95644655" - integrity sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw== - - eventemitter3@4.0.7, eventemitter3@^4.0.0, eventemitter3@^4.0.4: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - - events@^3.0.0, events@^3.2.0, events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - - evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - - exec-sh@^0.3.2: - version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== - - execa@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - - execa@5.1.1, execa@^5.0.0, execa@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - - execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - - execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - - executable@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" - integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== - dependencies: - pify "^2.2.0" - - exenv@^1.2.0, exenv@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" - integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= - - exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - - expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= - dependencies: - is-posix-bracket "^0.1.0" - - expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - dependencies: - fill-range "^2.1.0" - - expect@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" - integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== - dependencies: - "@jest/types" "^27.5.1" - jest-get-type "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - - express@^4.17.1, express@^4.17.2: - version "4.17.3" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" - integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.19.2" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.4.2" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.9.7" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.17.2" - serve-static "1.14.2" - setprototypeof "1.2.0" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - - extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - - extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - - extend@^3.0.0, extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - - external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - - extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= - dependencies: - is-extglob "^1.0.0" - - extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - extract-zip@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - - extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - - extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== - - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - - fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - - fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - - fast-glob@^3.2.4, fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - - fast-json-parse@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-json-parse/-/fast-json-parse-1.0.3.tgz#43e5c61ee4efa9265633046b770fb682a7577c4d" - integrity sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw== - - fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - - fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - - fast-shallow-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" - integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== - - fastest-levenshtein@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" - integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== - - fastest-stable-stringify@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76" - integrity sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q== - - fastparse@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - - fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - - fault@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" - integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== - dependencies: - format "^0.2.0" - - faye-websocket@~0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= - dependencies: - websocket-driver ">=0.5.1" - - fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - - fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - - figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - - figures@^3.0.0, figures@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - - file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - - file-loader@^6.2.0, file-loader@~6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" - integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - - file-selector@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80" - integrity sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA== - dependencies: - tslib "^2.0.3" - - file-selector@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.4.0.tgz#59ec4f27aa5baf0841e9c6385c8386bef4d18b17" - integrity sha512-iACCiXeMYOvZqlF1kTiYINzgepRBymz1wwjiuup9u9nayhb6g4fSwiyJ/6adli+EPwrWtpgQAh2PoS7HukEGEg== - dependencies: - tslib "^2.0.3" - - file-system-cache@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-1.0.5.tgz#84259b36a2bbb8d3d6eb1021d3132ffe64cfff4f" - integrity sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08= - dependencies: - bluebird "^3.3.5" - fs-extra "^0.30.0" - ramda "^0.21.0" - - file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - - filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= - - filesize@^8.0.6: - version "8.0.7" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" - integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ== - - fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - - fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - - fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - - filter-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" - integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= - - finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - - find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - - find-cache-dir@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - - find-chrome-bin@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/find-chrome-bin/-/find-chrome-bin-0.1.0.tgz#9fa3e6f86c275762c6d8be9da9af71e6fef05373" - integrity sha512-XoFZwaEn1R3pE6zNG8kH64l2e093hgB9+78eEKPmJK0o1EXEou+25cEWdtu2qq4DBQPDSe90VJAWVI2Sz9pX6Q== - - find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - - find-up@5.0.0, find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - - find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - - find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - - find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - - find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - - flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - - flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - - flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - - flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - - flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== - - flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - - flux-standard-action@^2.0.3: - version "2.1.2" - resolved "https://registry.yarnpkg.com/flux-standard-action/-/flux-standard-action-2.1.2.tgz#76141a9b8660585b773db32bab8aa9cc49b22da2" - integrity sha512-7vdgawlphCjzaMLdpZv8hlGC/FJCXu6sqE3Wuqe3HLZ22KcDiO4IFplxLDePDhEt6hgCrugt45RoUObuzZP6Kg== - dependencies: - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - - follow-redirects@^1.0.0: - version "1.14.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" - integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== - - for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - - for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - dependencies: - for-in "^1.0.1" - - foreground-child@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" - integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^3.0.2" - - forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - - fork-ts-checker-webpack-plugin@^4.1.6: - version "4.1.6" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" - integrity sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw== - dependencies: - "@babel/code-frame" "^7.5.5" - chalk "^2.4.1" - micromatch "^3.1.10" - minimatch "^3.0.4" - semver "^5.6.0" - tapable "^1.0.0" - worker-rpc "^0.1.0" - - fork-ts-checker-webpack-plugin@^6.0.4, fork-ts-checker-webpack-plugin@^6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz#0282b335fa495a97e167f69018f566ea7d2a2b5e" - integrity sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw== - dependencies: - "@babel/code-frame" "^7.8.3" - "@types/json-schema" "^7.0.5" - chalk "^4.1.0" - chokidar "^3.4.2" - cosmiconfig "^6.0.0" - deepmerge "^4.2.2" - fs-extra "^9.0.0" - glob "^7.1.6" - memfs "^3.1.2" - minimatch "^3.0.4" - schema-utils "2.7.0" - semver "^7.3.2" - tapable "^1.0.0" - - form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - - form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - - format@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" - integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= - - forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - - fraction.js@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.3.tgz#be65b0f20762ef27e1e793860bc2dfb716e99e65" - integrity sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg== - - fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - - fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - - from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - - fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - - fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - - fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - - fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - - fs-minipass@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - - fs-minipass@^2.0.0, fs-minipass@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - - fs-monkey@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" - integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== - - fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - - fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - - fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - - fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - - function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - - function.prototype.name@^1.1.0, function.prototype.name@^1.1.2, function.prototype.name@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - - functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - - functions-have-names@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.2.tgz#98d93991c39da9361f8e50b337c4f6e41f120e21" - integrity sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA== - - fuse.js@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.6.1.tgz#7de85fdd6e1b3377c23ce010892656385fd9b10c" - integrity sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw== - - gauge@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" - integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - object-assign "^4.1.1" - signal-exit "^3.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.2" - - gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - - generic-names@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-1.0.3.tgz#2d786a121aee508876796939e8e3bff836c20917" - integrity sha1-LXhqEhruUIh2eWk56OO/+DbCCRc= - dependencies: - loader-utils "^0.2.16" - - gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - - geotiff@^1.0.8: - version "1.0.9" - resolved "https://registry.yarnpkg.com/geotiff/-/geotiff-1.0.9.tgz#a2037c1f672c0a11bfbac8b46bbc56f901e32198" - integrity sha512-PY+q1OP8RtQZkx1630pVfC3hEkxFnGW9LwIF/glSzcalyShkrH+W8uM/M4RVY12j4QkDQvRXVKOpU65hq6t0iQ== - dependencies: - "@petamoriken/float16" "^3.4.7" - lerc "^3.0.0" - lru-cache "^6.0.0" - pako "^2.0.4" - parse-headers "^2.0.2" - threads "^1.7.0" - xml-utils "^1.0.2" - - get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - - get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - - get-document@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-document/-/get-document-1.0.0.tgz#4821bce66f1c24cb0331602be6cb6b12c4f01c4b" - integrity sha1-SCG85m8cJMsDMWAr5strEsTwHEs= - - get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - - get-own-enumerable-property-symbols@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" - integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== - - get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - - get-pkg-repo@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" - integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== - dependencies: - "@hutson/parse-repository-url" "^3.0.0" - hosted-git-info "^4.0.0" - through2 "^2.0.0" - yargs "^16.2.0" - - get-port@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - - get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - - get-stdin@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" - integrity sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g= - - get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - - get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - - get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - - get-stream@^5.0.0, get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - - get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - - get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - - get-user-locale@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/get-user-locale/-/get-user-locale-1.4.0.tgz#a2c4b5da46feec9f03c9b07d197b1620490a5370" - integrity sha512-gQo03lP1OArHLKlnoglqrGGl7b04u2EP9Xutmp72cMdtrrSD7ZgIsCsUKZynYWLDkVJW33Cj3pliP7uP0UonHQ== - dependencies: - lodash.once "^4.1.1" - - get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - - get-window@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/get-window/-/get-window-1.1.2.tgz#65fbaa999fb87f86ea5d30770f4097707044f47f" - integrity sha512-yjWpFcy9fjhLQHW1dPtg9ga4pmizLY8y4ZSHdGrAQ1NU277MRhnGnnLPxe19X8W5lWVsCZz++5xEuNozWMVmTw== - dependencies: - get-document "1" - - getos@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" - integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== - dependencies: - async "^3.2.0" - - getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - - gh-got@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-9.0.0.tgz#5f82eb5c97aa7a0235f50cf277331cdeda879670" - integrity sha512-RH5n6CDdb6AozElmiKwFhmO/1FmhWWVhfQAVv+JtU8jtPK12JLErce/VQFsFwZ9dTa01SfD7WXb/1iyZp/5XKg== - dependencies: - got "^10.5.7" - - git-raw-commits@^2.0.8: - version "2.0.11" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.11.tgz#bc3576638071d18655e1cc60d7f524920008d723" - integrity sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A== - dependencies: - dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - - git-remote-origin-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" - integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8= - dependencies: - gitconfiglocal "^1.0.0" - pify "^2.3.0" - - git-semver-tags@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" - integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA== - dependencies: - meow "^8.0.0" - semver "^6.0.0" - - git-up@^4.0.0: - version "4.0.5" - resolved "https://registry.yarnpkg.com/git-up/-/git-up-4.0.5.tgz#e7bb70981a37ea2fb8fe049669800a1f9a01d759" - integrity sha512-YUvVDg/vX3d0syBsk/CKUTib0srcQME0JyHkL5BaYdwLsiCslPWmDSi8PUMo9pXYjrryMcmsCoCgsTpSCJEQaA== - dependencies: - is-ssh "^1.3.0" - parse-url "^6.0.0" - - git-url-parse@^11.4.4: - version "11.6.0" - resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-11.6.0.tgz#c634b8de7faa66498a2b88932df31702c67df605" - integrity sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g== - dependencies: - git-up "^4.0.0" - - gitconfiglocal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" - integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s= - dependencies: - ini "^1.3.2" - - github-slugger@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e" - integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ== - - glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - - glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= - dependencies: - is-glob "^2.0.0" - - glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - - glob-parent@^5.0.0, glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - - glob-promise@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-3.4.0.tgz#b6b8f084504216f702dc2ce8c9bc9ac8866fdb20" - integrity sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw== - dependencies: - "@types/glob" "*" - - glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - - glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - - glob@7.2.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - - global-dirs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" - integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== - dependencies: - ini "2.0.0" - - global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - - global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - - global@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - - globals@^11.1.0, globals@^11.12.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - - globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - - globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - - globalthis@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b" - integrity sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ== - dependencies: - define-properties "^1.1.3" - - globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - - globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - - globby@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" - integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - - glur@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/glur/-/glur-1.1.2.tgz#f20ea36db103bfc292343921f1f91e83c3467689" - integrity sha1-8g6jbbEDv8KSNDkh8fkeg8NGdok= - - gonzales-pe@^4.0.3: - version "4.3.0" - resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" - integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== - dependencies: - minimist "^1.2.5" - - got@^10.5.7: - version "10.7.0" - resolved "https://registry.yarnpkg.com/got/-/got-10.7.0.tgz#62889dbcd6cca32cd6a154cc2d0c6895121d091f" - integrity sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg== - dependencies: - "@sindresorhus/is" "^2.0.0" - "@szmarczak/http-timer" "^4.0.0" - "@types/cacheable-request" "^6.0.1" - cacheable-lookup "^2.0.0" - cacheable-request "^7.0.1" - decompress-response "^5.0.0" - duplexer3 "^0.1.4" - get-stream "^5.0.0" - lowercase-keys "^2.0.0" - mimic-response "^2.1.0" - p-cancelable "^2.0.0" - p-event "^4.0.0" - responselike "^2.0.0" - to-readable-stream "^2.0.0" - type-fest "^0.10.0" - - graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.9: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - - graphql@^15.5.1: - version "15.8.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" - integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== - - growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - - gzip-size@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" - integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== - dependencies: - duplexer "^0.1.2" - - handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - - har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - - har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - - hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== - - has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - - has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - - has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - - has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - - has-glob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-glob/-/has-glob-1.0.0.tgz#9aaa9eedbffb1ba3990a7b0010fb678ee0081207" - integrity sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc= - dependencies: - is-glob "^3.0.0" - - has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - - has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - - has-unicode@^2.0.0, has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - - has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - - has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - - has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - - has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - - has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - - hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - - hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - - hast-to-hyperscript@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" - integrity sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA== - dependencies: - "@types/unist" "^2.0.3" - comma-separated-tokens "^1.0.0" - property-information "^5.3.0" - space-separated-tokens "^1.0.0" - style-to-object "^0.3.0" - unist-util-is "^4.0.0" - web-namespaces "^1.0.0" - - hast-util-from-parse5@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz#554e34abdeea25ac76f5bd950a1f0180e0b3bc2a" - integrity sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA== - dependencies: - "@types/parse5" "^5.0.0" - hastscript "^6.0.0" - property-information "^5.0.0" - vfile "^4.0.0" - vfile-location "^3.2.0" - web-namespaces "^1.0.0" - - hast-util-parse-selector@^2.0.0: - version "2.2.5" - resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" - integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== - - hast-util-raw@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-6.0.1.tgz#973b15930b7529a7b66984c98148b46526885977" - integrity sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig== - dependencies: - "@types/hast" "^2.0.0" - hast-util-from-parse5 "^6.0.0" - hast-util-to-parse5 "^6.0.0" - html-void-elements "^1.0.0" - parse5 "^6.0.0" - unist-util-position "^3.0.0" - vfile "^4.0.0" - web-namespaces "^1.0.0" - xtend "^4.0.0" - zwitch "^1.0.0" - - hast-util-to-parse5@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz#1ec44650b631d72952066cea9b1445df699f8479" - integrity sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ== - dependencies: - hast-to-hyperscript "^9.0.0" - property-information "^5.0.0" - web-namespaces "^1.0.0" - xtend "^4.0.0" - zwitch "^1.0.0" - - hastscript@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" - integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== - dependencies: - "@types/hast" "^2.0.0" - comma-separated-tokens "^1.0.0" - hast-util-parse-selector "^2.0.0" - property-information "^5.0.0" - space-separated-tokens "^1.0.0" - - he@1.2.0, he@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - - headers-utils@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/headers-utils/-/headers-utils-3.0.2.tgz#dfc65feae4b0e34357308aefbcafa99c895e59ef" - integrity sha512-xAxZkM1dRyGV2Ou5bzMxBPNLoRCjcX+ya7KSWybQD2KwLphxsapUVK6x/02o7f4VU6GPSXch9vNY2+gkU8tYWQ== - - highlight-words-core@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/highlight-words-core/-/highlight-words-core-1.2.2.tgz#1eff6d7d9f0a22f155042a00791237791b1eeaaa" - integrity sha512-BXUKIkUuh6cmmxzi5OIbUJxrG8OAk2MqoL1DtO3Wo9D2faJg2ph5ntyuQeLqaHJmzER6H5tllCDA9ZnNe9BVGg== - - highlight.js@^10.1.1, highlight.js@~10.7.0: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - - history@4.10.1, history@^4.8.0, history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - - history@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/history/-/history-5.0.0.tgz#0cabbb6c4bbf835addb874f8259f6d25101efd08" - integrity sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg== - dependencies: - "@babel/runtime" "^7.7.6" - - history@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/history/-/history-5.2.0.tgz#7cdd31cf9bac3c5d31f09c231c9928fad0007b7c" - integrity sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig== - dependencies: - "@babel/runtime" "^7.7.6" - - hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - - hoist-non-react-statics@3.3.2, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - - hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - - hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" - integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== - dependencies: - lru-cache "^6.0.0" - - html-element-map@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/html-element-map/-/html-element-map-1.3.1.tgz#44b2cbcfa7be7aa4ff59779e47e51012e1c73c08" - integrity sha512-6XMlxrAFX4UEEGxctfFnmrFaaZFNf9i5fNuV5wZ3WWQ4FVaNP1aX1LkX9j2mfEx1NpjeE/rL3nmgEn23GdFmrg== - dependencies: - array.prototype.filter "^1.0.0" - call-bind "^1.0.2" - - html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - - html-entities@^2.1.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488" - integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ== - - html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - - html-inline-css-webpack-plugin@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/html-inline-css-webpack-plugin/-/html-inline-css-webpack-plugin-1.11.1.tgz#e2aa6329687a108e90df6a30b65ad72d65731c03" - integrity sha512-P4GjZ4fxGn8Rm53TrYBUvjPMoOQAOzVGdVb8OKfrGkHyeTBl+M0+H0q6rjhiVZuF0I1MFUErc4N9hidcLlC1kg== - dependencies: - lodash "^4.17.15" - tslib "^1.9.3" - - html-minifier-terser@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054" - integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg== - dependencies: - camel-case "^4.1.1" - clean-css "^4.2.3" - commander "^4.1.1" - he "^1.2.0" - param-case "^3.0.3" - relateurl "^0.2.7" - terser "^4.6.3" - - html-minifier-terser@^6.0.2: - version "6.1.0" - resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" - integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== - dependencies: - camel-case "^4.1.2" - clean-css "^5.2.2" - commander "^8.3.0" - he "^1.2.0" - param-case "^3.0.4" - relateurl "^0.2.7" - terser "^5.10.0" - - html-tags@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" - integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== - - html-void-elements@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" - integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w== - - html-webpack-plugin@^4.0.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz#76fc83fa1a0f12dd5f7da0404a54e2699666bc12" - integrity sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A== - dependencies: - "@types/html-minifier-terser" "^5.0.0" - "@types/tapable" "^1.0.5" - "@types/webpack" "^4.41.8" - html-minifier-terser "^5.0.1" - loader-utils "^1.2.3" - lodash "^4.17.20" - pretty-error "^2.1.1" - tapable "^1.1.3" - util.promisify "1.0.0" - - html-webpack-plugin@^5.0.0, html-webpack-plugin@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" - integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== - dependencies: - "@types/html-minifier-terser" "^6.0.0" - html-minifier-terser "^6.0.2" - lodash "^4.17.21" - pretty-error "^4.0.0" - tapable "^2.0.0" - - htmlparser2@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" - integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils "^2.5.2" - entities "^2.0.0" - - http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - - http-errors@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - - http-parser-js@>=0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" - integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA== - - http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - - http-proxy-middleware@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz#43700d6d9eecb7419bf086a128d0f7205d9eb665" - integrity sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg== - dependencies: - "@types/http-proxy" "^1.17.5" - http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.2" - - http-proxy@^1.18.1: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - - http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - - http-signature@~1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" - integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== - dependencies: - assert-plus "^1.0.0" - jsprim "^2.0.2" - sshpk "^1.14.1" - - https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - - https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - - human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - - human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - - humanize-duration@^3.25.1: - version "3.27.1" - resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.27.1.tgz#2cd4ea4b03bd92184aee6d90d77a8f3d7628df69" - integrity sha512-jCVkMl+EaM80rrMrAPl96SGG4NRac53UyI1o/yAzebDntEY6K6/Fj2HOjdPg8omTqIe5Y0wPBai2q5xXrIbarA== - - humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= - dependencies: - ms "^2.0.0" - - husky@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" - integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== - - hyphenate-style-name@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" - integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== - - iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@^0.4.8: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - - iconv-lite@0.6, iconv-lite@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - - icss-utils@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-3.0.1.tgz#ee70d3ae8cac38c6be5ed91e851b27eed343ad0f" - integrity sha1-7nDTroysOMa+XtkehRsn7tNDrQ8= - dependencies: - postcss "^6.0.2" - - icss-utils@^4.0.0, icss-utils@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== - dependencies: - postcss "^7.0.14" - - icss-utils@^5.0.0, icss-utils@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - - ieee754@^1.1.12, ieee754@^1.1.13, ieee754@^1.1.4: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - - iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - - ignore-walk@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" - integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== - dependencies: - minimatch "^3.0.4" - - ignore@^4.0.3, ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - - ignore@^5.1.8, ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - - image-size@~0.5.0: - version "0.5.5" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" - integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= - - immer@^9.0.7: - version "9.0.12" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" - integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA== - - immutable@4.0.0, immutable@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" - integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== - - import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - - import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - - import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - - import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - - import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - - imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - - indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - - indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - - infer-owner@^1.0.3, infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - - inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - - inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - - inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - - inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - - ini@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" - integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== - - ini@^1.3.2, ini@^1.3.4, ini@^1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - - init-package-json@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.5.tgz#78b85f3c36014db42d8f32117252504f68022646" - integrity sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA== - dependencies: - npm-package-arg "^8.1.5" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "^4.1.1" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - - inline-style-parser@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" - integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== - - inline-style-prefixer@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.1.tgz#c5c0e43ba8831707afc5f5bbfd97edf45c1fa7ae" - integrity sha512-AsqazZ8KcRzJ9YPN1wMH2aNM7lkWQ8tSPrW5uDk1ziYwiAPWSZnUsC7lfZq+BDqLqz0B4Pho5wscWcJzVvRzDQ== - dependencies: - css-in-js-utils "^2.0.0" - - inquirer@^7.0.0, inquirer@^7.3.3: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - - inquirer@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" - integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.1" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.21" - mute-stream "0.0.8" - ora "^5.4.1" - run-async "^2.4.0" - rxjs "^7.2.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - - internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - - "internmap@1 - 2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" - integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== - - interpret@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - - interpret@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" - integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== - - intl-messageformat@^9.6.12: - version "9.11.4" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.11.4.tgz#0f9030bc6d10e6a48592142f88e646d88f05f1f2" - integrity sha512-77TSkNubIy/hsapz6LQpyR6OADcxhWdhSaboPb5flMaALCVkPvAIxr48AlPqaMl4r1anNcvR9rpLWVdwUY1IKg== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/fast-memoize" "1.2.1" - "@formatjs/icu-messageformat-parser" "2.0.18" - tslib "^2.1.0" - - invariant@^2.2.2, invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - - invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - - ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - - ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - - is-absolute-url@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" - integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== - - is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - - is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - - is-alphabetical@1.0.4, is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== - - is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - - is-arguments@^1.0.4, is-arguments@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - - is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - - is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - - is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - - is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - - is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - - is-boolean-object@^1.0.1, is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - - is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - - is-buffer@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - - is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - - is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - - is-ci@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" - integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== - dependencies: - ci-info "^3.2.0" - - is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.7.0, is-core-module@^2.8.0, is-core-module@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" - integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== - dependencies: - has "^1.0.3" - - is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - - is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - - is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - - is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== - - is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - - is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - - is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - - is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - - is-dom@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.1.0.tgz#af1fced292742443bb59ca3f76ab5e80907b4e8a" - integrity sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ== - dependencies: - is-object "^1.0.1" - is-window "^1.0.2" - - is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= - - is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= - dependencies: - is-primitive "^2.0.0" - - is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - - is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - - is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= - - is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - - is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - - is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - - is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - - is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - - is-function@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - - is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - - is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= - dependencies: - is-extglob "^1.0.0" - - is-glob@^3.0.0, is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - - is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== - - is-hotkey@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.4.tgz#c34d2c85d6ec8d09a871dcf71931c8067a824c7d" - integrity sha512-Py+aW4r5mBBY18TGzGz286/gKS+fCQ0Hee3qkaiSmEPiD0PqFpe0wuA3l7rTOUKyeXl8Mxf3XzJxIoTlSv+kxA== - - is-hotkey@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.2.0.tgz#1835a68171a91e5c9460869d96336947c8340cef" - integrity sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw== - - is-in-browser@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" - integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU= - - is-installed-globally@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" - integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== - dependencies: - global-dirs "^3.0.0" - is-path-inside "^3.0.2" - - is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - - is-lambda@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" - integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= - - is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - - is-negative-zero@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - - is-node-process@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.0.1.tgz#4fc7ac3a91e8aac58175fe0578abbc56f2831b23" - integrity sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ== - - is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== - dependencies: - has-tostringtag "^1.0.0" - - is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - - is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - - is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - - is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - - is-obj@^1.0.0, is-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - - is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - - is-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" - integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== - - is-observable@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-2.1.0.tgz#5c8d733a0b201c80dff7bb7c0df58c6a255c7c69" - integrity sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw== - - is-path-cwd@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - - is-path-in-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" - integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== - dependencies: - is-path-inside "^2.1.0" - - is-path-inside@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" - integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== - dependencies: - path-is-inside "^1.0.2" - - is-path-inside@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - - is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - - is-plain-obj@^2.0.0, is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - - is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== - - is-plain-object@5.0.0, is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - - is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - - is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= - - is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - - is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= - - is-promise@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - - is-regex@^1.0.4, is-regex@^1.0.5, is-regex@^1.1.0, is-regex@^1.1.2, is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - - is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= - - is-root@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" - integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== - - is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== - - is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - - is-ssh@^1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e" - integrity sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ== - dependencies: - protocols "^1.1.0" - - is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - - is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - - is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - - is-subset@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" - integrity sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY= - - is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - - is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= - dependencies: - text-extensions "^1.0.0" - - is-typedarray@^1.0.0, is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - - is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - - is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - - is-weakref@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - - is-what@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" - integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA== - - is-whitespace-character@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" - integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== - - is-window@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-window/-/is-window-1.0.2.tgz#2c896ca53db97de45d3c33133a65d8c9f563480d" - integrity sha1-LIlspT25feRdPDMTOmXYyfVjSA0= - - is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - - is-word-character@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" - integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== - - is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - - is-wsl@^2.1.1, is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - - isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - - isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - - isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - - isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - - isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - - isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - - isobject@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" - integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== - - isomorphic-base64@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/isomorphic-base64/-/isomorphic-base64-1.0.2.tgz#f426aae82569ba8a4ec5ca73ad21a44ab1ee7803" - integrity sha1-9Caq6CVpuopOxcpzrSGkSrHueAM= - - isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.1, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - - istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" - integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - - istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - - istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - - istanbul-reports@^3.0.2, istanbul-reports@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" - integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - - iterate-iterator@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.2.tgz#551b804c9eaa15b847ea6a7cdc2f5bf1ec150f91" - integrity sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw== - - iterate-value@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iterate-value/-/iterate-value-1.0.2.tgz#935115bd37d006a52046535ebc8d07e9c9337f57" - integrity sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== - dependencies: - es-get-iterator "^1.0.2" - iterate-iterator "^1.0.1" - - iterm2-version@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/iterm2-version/-/iterm2-version-4.2.0.tgz#b78069f747f34a772bc7dc17bda5bd9ed5e09633" - integrity sha512-IoiNVk4SMPu6uTcK+1nA5QaHNok2BMDLjSl5UomrOixe5g4GkylhPwuiGdw00ysSCrXAKNMfFTu+u/Lk5f6OLQ== - dependencies: - app-path "^3.2.0" - plist "^3.0.1" - - jest-canvas-mock@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/jest-canvas-mock/-/jest-canvas-mock-2.3.1.tgz#9535d14bc18ccf1493be36ac37dd349928387826" - integrity sha512-5FnSZPrX3Q2ZfsbYNE3wqKR3+XorN8qFzDzB5o0golWgt6EOX1+emBnpOc9IAQ+NXFj8Nzm3h7ZdE/9H0ylBcg== - dependencies: - cssfontparser "^1.2.1" - moo-color "^1.0.2" - - jest-changed-files@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" - integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== - dependencies: - "@jest/types" "^27.5.1" - execa "^5.0.0" - throat "^6.0.1" - - jest-circus@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" - integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - throat "^6.0.1" - - jest-cli@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" - integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== - dependencies: - "@jest/core" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - import-local "^3.0.2" - jest-config "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - prompts "^2.0.1" - yargs "^16.2.0" - - jest-config@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" - integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== - dependencies: - "@babel/core" "^7.8.0" - "@jest/test-sequencer" "^27.5.1" - "@jest/types" "^27.5.1" - babel-jest "^27.5.1" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.9" - jest-circus "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-get-type "^27.5.1" - jest-jasmine2 "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runner "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^27.5.1" - slash "^3.0.0" - strip-json-comments "^3.1.1" - - jest-css-modules-transform@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/jest-css-modules-transform/-/jest-css-modules-transform-4.3.0.tgz#e3599b6b9326230f9c127953aca99f91d9286ab1" - integrity sha512-0ACv/lpFK3oUdNkCZTJ6t5X4jUzGw2YnqBQz2fd+RwrGex+C92e0KSkkWmGUdG9wJ8emapi1Xm1IIqUqdkN3/g== - dependencies: - camelcase "^6.2.0" - postcss "^7.0.30 || ^8.0.0" - postcss-nested "^4.2.1 || ^5.0.0" - - jest-diff@^27.0.0, jest-diff@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" - integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - - jest-docblock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" - integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== - dependencies: - detect-newline "^3.0.0" - - jest-each@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" - integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - jest-get-type "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - - jest-environment-jsdom@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" - integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - jsdom "^16.6.0" - - jest-environment-node@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" - integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - - jest-fetch-mock@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b" - integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw== - dependencies: - cross-fetch "^3.0.4" - promise-polyfill "^8.1.3" - - jest-get-type@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" - integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== - - jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== - dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" - - jest-haste-map@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" - integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== - dependencies: - "@jest/types" "^27.5.1" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^27.5.1" - jest-serializer "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - - jest-image-snapshot@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/jest-image-snapshot/-/jest-image-snapshot-4.2.0.tgz#559d7ade69e9918517269cef184261c80029a69e" - integrity sha512-6aAqv2wtfOgxiJeBayBCqHo1zX+A12SUNNzo7rIxiXh6W6xYVu8QyHWkada8HeRi+QUTHddp0O0Xa6kmQr+xbQ== - dependencies: - chalk "^1.1.3" - get-stdin "^5.0.1" - glur "^1.1.2" - lodash "^4.17.4" - mkdirp "^0.5.1" - pixelmatch "^5.1.0" - pngjs "^3.4.0" - rimraf "^2.6.2" - ssim.js "^3.1.1" - - jest-image-snapshot@^4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/jest-image-snapshot/-/jest-image-snapshot-4.5.1.tgz#79fe0419c7729eb1be6c873365307a7b60f5cda0" - integrity sha512-0YkgupgkkCx0wIZkxvqs/oNiUT0X0d2WTpUhaAp+Dy6CpqBUZMRTIZo4KR1f+dqmx6WXrLCvecjnHLIsLkI+gQ== - dependencies: - chalk "^1.1.3" - get-stdin "^5.0.1" - glur "^1.1.2" - lodash "^4.17.4" - mkdirp "^0.5.1" - pixelmatch "^5.1.0" - pngjs "^3.4.0" - rimraf "^2.6.2" - ssim.js "^3.1.1" - - jest-jasmine2@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" - integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - throat "^6.0.1" - - jest-leak-detector@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" - integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== - dependencies: - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - - jest-matcher-utils@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" - integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== - dependencies: - chalk "^4.0.0" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - - jest-message-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" - integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.5.1" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - - jest-mock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" - integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - - jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== - - jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== - - jest-regex-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== - - jest-resolve-dependencies@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" - integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== - dependencies: - "@jest/types" "^27.5.1" - jest-regex-util "^27.5.1" - jest-snapshot "^27.5.1" - - jest-resolve@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" - integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-pnp-resolver "^1.2.2" - jest-util "^27.5.1" - jest-validate "^27.5.1" - resolve "^1.20.0" - resolve.exports "^1.1.0" - slash "^3.0.0" - - jest-runner@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" - integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.8.1" - graceful-fs "^4.2.9" - jest-docblock "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-haste-map "^27.5.1" - jest-leak-detector "^27.5.1" - jest-message-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runtime "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - source-map-support "^0.5.6" - throat "^6.0.1" - - jest-runtime@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" - integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/globals" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - execa "^5.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - slash "^3.0.0" - strip-bom "^4.0.0" - - jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - - jest-serializer@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" - integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.9" - - jest-snapshot@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" - integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== - dependencies: - "@babel/core" "^7.7.2" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.0.0" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^27.5.1" - graceful-fs "^4.2.9" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - jest-haste-map "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-util "^27.5.1" - natural-compare "^1.4.0" - pretty-format "^27.5.1" - semver "^7.3.2" - - jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" - - jest-util@^27.0.0, jest-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - - jest-validate@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" - integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== - dependencies: - "@jest/types" "^27.5.1" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^27.5.1" - leven "^3.1.0" - pretty-format "^27.5.1" - - jest-watcher@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" - integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== - dependencies: - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^27.5.1" - string-length "^4.0.1" - - jest-worker@^26.5.0, jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - - jest-worker@^27.3.1, jest-worker@^27.4.5, jest-worker@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - - jest@^27.2.4: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" - integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== - dependencies: - "@jest/core" "^27.5.1" - import-local "^3.0.2" - jest-cli "^27.5.1" - - jose@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/jose/-/jose-4.5.0.tgz#92829d8cf846351eb55aaaf94f252fb1d191f2d5" - integrity sha512-GFcVFQwYQKbQTUOo2JlpFGXTkgBw26uzDsRMD2q1WgSKNSnpKS9Ug7bdQ8dS+p4sZHNH6iRPu6WK2jLIjspaMA== - - joycon@^3.0.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== - - jquery.flot.tooltip@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/jquery.flot.tooltip/-/jquery.flot.tooltip-0.9.0.tgz#ae16bf94b26c2ed9ab4db167bba52dfdb615c1df" - integrity sha1-rha/lLJsLtmrTbFnu6Ut/bYVwd8= - - jquery@3.1.1, jquery@3.6.0, jquery@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.1.1.tgz#347c1c21c7e004115e0a4da32cece041fad3c8a3" - integrity sha1-NHwcIcfgBBFeCk2jLOzgQfrTyKM= - - js-cookie@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" - integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== - - js-levenshtein@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" - integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== - - js-string-escape@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - integrity sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8= - - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - - js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - - js-yaml@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - - js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - - jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - - jsdom@^16.6.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - - jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - - jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - - json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - - json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - - json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - - json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - - json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - - json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - - json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - - json-stringify-pretty-compact@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz#e77c419f52ff00c45a31f07f4c820c2433143885" - integrity sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ== - - json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - - json5@2.x, json5@^2.1.0, json5@^2.1.2, json5@^2.1.3, json5@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - - json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - - json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - - jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= - optionalDependencies: - graceful-fs "^4.1.6" - - jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - - jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - - jsonparse@^1.2.0, jsonparse@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= - - jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - - jsprim@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" - integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - - "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" - integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== - dependencies: - array-includes "^3.1.3" - object.assign "^4.1.2" - - junk@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" - integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== - - keyv@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.1.1.tgz#02c538bfdbd2a9308cc932d4096f05ae42bfa06a" - integrity sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ== - dependencies: - json-buffer "3.0.1" - - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - - kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - - kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - - kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - - klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= - optionalDependencies: - graceful-fs "^4.1.9" - - kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - - klona@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/klona/-/klona-1.1.2.tgz#a79e292518a5a5412ec8d097964bff1571a64db0" - integrity sha512-xf88rTeHiXk+XE2Vhi6yj8Wm3gMZrygGdKjJqN8HkV+PwF/t50/LdAKHoHpPcxFAlmQszTZ1CugrK25S7qDRLA== - - klona@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" - integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== - - language-subtag-registry@~0.3.2: - version "0.3.21" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" - integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg== - - language-tags@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= - dependencies: - language-subtag-registry "~0.3.2" - - last-call-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" - integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== - dependencies: - lodash "^4.17.5" - webpack-sources "^1.1.0" - - lazy-ass@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" - integrity sha1-eZllXoZGwX8In90YfRUNMyTVRRM= - - lazy-universal-dotenv@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz#a6c8938414bca426ab8c9463940da451a911db38" - integrity sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ== - dependencies: - "@babel/runtime" "^7.5.0" - app-root-dir "^1.0.2" - core-js "^3.0.4" - dotenv "^8.0.0" - dotenv-expand "^5.1.0" - - lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - - lerc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lerc/-/lerc-3.0.0.tgz#36f36fbd4ba46f0abf4833799fff2e7d6865f5cb" - integrity sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww== - - lerna-watch@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lerna-watch/-/lerna-watch-1.0.0.tgz#a035be3c127d893d8266edf2841c08bd720a7eec" - integrity sha512-5+NLjtob8lib7BuOk4VZMj/AwPifQm3mpqh363KznOH3wLAr3bm4GmBVuY6XUFHDRYORWszfkvAwgD04NNWQvQ== - dependencies: - "@lerna/package-graph" "^3.18.5" - "@lerna/project" "^3.21.0" - chalk "^4.1.0" - cross-spawn "^7.0.3" - debug "^4.1.1" - errno "^0.1.7" - minimist "^1.2.5" - npmlog "^4.1.2" - - lerna@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" - integrity sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg== - dependencies: - "@lerna/add" "4.0.0" - "@lerna/bootstrap" "4.0.0" - "@lerna/changed" "4.0.0" - "@lerna/clean" "4.0.0" - "@lerna/cli" "4.0.0" - "@lerna/create" "4.0.0" - "@lerna/diff" "4.0.0" - "@lerna/exec" "4.0.0" - "@lerna/import" "4.0.0" - "@lerna/info" "4.0.0" - "@lerna/init" "4.0.0" - "@lerna/link" "4.0.0" - "@lerna/list" "4.0.0" - "@lerna/publish" "4.0.0" - "@lerna/run" "4.0.0" - "@lerna/version" "4.0.0" - import-local "^3.0.2" - npmlog "^4.1.2" - - less@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/less/-/less-4.1.2.tgz#6099ee584999750c2624b65f80145f8674e4b4b0" - integrity sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA== - dependencies: - copy-anything "^2.0.1" - parse-node-version "^1.0.1" - tslib "^2.3.0" - optionalDependencies: - errno "^0.1.1" - graceful-fs "^4.1.2" - image-size "~0.5.0" - make-dir "^2.1.0" - mime "^1.4.1" - needle "^2.5.2" - source-map "~0.6.0" - - leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - - levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - - levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - - libnpmaccess@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" - integrity sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ== - dependencies: - aproba "^2.0.0" - minipass "^3.1.1" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" - - libnpmpublish@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" - integrity sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw== - dependencies: - normalize-package-data "^3.0.2" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" - semver "^7.1.3" - ssri "^8.0.1" - - lilconfig@^2.0.3, lilconfig@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" - integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== - - lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - - lint-staged@^11.1.2: - version "11.2.6" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.2.6.tgz#f477b1af0294db054e5937f171679df63baa4c43" - integrity sha512-Vti55pUnpvPE0J9936lKl0ngVeTdSZpEdTNhASbkaWX7J5R9OEifo1INBGQuGW4zmy6OG+TcWPJ3m5yuy5Q8Tg== - dependencies: - cli-truncate "2.1.0" - colorette "^1.4.0" - commander "^8.2.0" - cosmiconfig "^7.0.1" - debug "^4.3.2" - enquirer "^2.3.6" - execa "^5.1.1" - listr2 "^3.12.2" - micromatch "^4.0.4" - normalize-path "^3.0.0" - please-upgrade-node "^3.2.0" - string-argv "0.3.1" - stringify-object "3.3.0" - supports-color "8.1.1" - - listr2@^3.12.2, listr2@^3.8.3: - version "3.14.0" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" - integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.16" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.5.1" - through "^2.3.8" - wrap-ansi "^7.0.0" - - livereload-js@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" - integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== - - load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - - load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - - load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - - load-json-file@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-5.3.0.tgz#4d3c1e01fa1c03ea78a60ac7af932c9ce53403f3" - integrity sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw== - dependencies: - graceful-fs "^4.1.15" - parse-json "^4.0.0" - pify "^4.0.1" - strip-bom "^3.0.0" - type-fest "^0.3.0" - - load-json-file@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" - integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== - dependencies: - graceful-fs "^4.1.15" - parse-json "^5.0.0" - strip-bom "^4.0.0" - type-fest "^0.6.0" - - loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - - loader-runner@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" - integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== - - loader-utils@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" - integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - - loader-utils@^0.2.16: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" - - loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - - loader-utils@^2.0.0, loader-utils@~2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" - integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - - loader-utils@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.0.tgz#bcecc51a7898bee7473d4bc6b845b23af8304d4f" - integrity sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ== - - locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - - locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - - locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - - locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - - lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - - lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - - lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - - lodash.debounce@^4, lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - - lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - - lodash.escape@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" - integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg= - - lodash.flattendeep@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" - integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= - - lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= - - lodash.ismatch@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" - integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= - - lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - - lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= - - lodash.memoize@4.x, lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - - lodash.once@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= - - lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - - lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - - lodash.uniq@4.5.0, lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - - lodash@4.17.21, lodash@^4.1.1, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.7.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - - log-symbols@4.1.0, log-symbols@^4.0.0, log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - - log-symbols@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - - log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== - dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" - - log4js@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-1.1.1.tgz#c21d29c7604089e4f255833e7f94b3461de1ff43" - integrity sha1-wh0px2BAieTyVYM+f5SzRh3h/0M= - dependencies: - debug "^2.2.0" - semver "^5.3.0" - streamroller "^0.4.0" - - loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - - loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - - lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" - integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== - dependencies: - tslib "^2.0.3" - - lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - - lowlight@^1.14.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" - integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw== - dependencies: - fault "^1.0.0" - highlight.js "~10.7.0" - - lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - - lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - - lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - - lz-string@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" - integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= - - make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - - make-dir@^2.0.0, make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - - make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - - make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - - make-fetch-happen@^8.0.9: - version "8.0.14" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" - integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.0.5" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" - ssri "^8.0.0" - - make-fetch-happen@^9.0.1: - version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" - integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.2" - promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" - - makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - - map-age-cleaner@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - - map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - - map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - - map-obj@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" - integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== - - map-or-similar@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" - integrity sha1-beJlMXSt+12e3DPGnT6Sobdvrwg= - - map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - - mapbox-to-css-font@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/mapbox-to-css-font/-/mapbox-to-css-font-2.4.1.tgz#41bf38faed36b7dab069828aa3654e4bd91a1eda" - integrity sha512-QQ/iKiM43DM9+aujTL45Iz5o7gDeSFmy4LPl3HZmNcwCE++NxGazf+yFpY+wCb+YS23sDa1ghpo3zrNFOcHlow== - - markdown-escapes@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" - integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== - - markdown-to-jsx@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.6.tgz#421487df2a66fe4231d94db653a34da033691e62" - integrity sha512-1wrIGZYwIG2gR3yfRmbr4FlQmhaAKoKTpRo4wur4fp9p0njU1Hi7vR8fj0AUKKIcPduiJmPprzmCB5B/GvlC7g== - - marked@4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.10.tgz#423e295385cc0c3a70fa495e0df68b007b879423" - integrity sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw== - - math-random@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" - integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== - - md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - - mdast-squeeze-paragraphs@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97" - integrity sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ== - dependencies: - unist-util-remove "^2.0.0" - - mdast-util-definitions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" - integrity sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ== - dependencies: - unist-util-visit "^2.0.0" - - mdast-util-to-hast@10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb" - integrity sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - mdast-util-definitions "^4.0.0" - mdurl "^1.0.0" - unist-builder "^2.0.0" - unist-util-generated "^1.0.0" - unist-util-position "^3.0.0" - unist-util-visit "^2.0.0" - - mdast-util-to-string@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527" - integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A== - - mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - - mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - - mdurl@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= - - media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - - mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - - mem@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/mem/-/mem-8.1.1.tgz#cf118b357c65ab7b7e0817bdf00c8062297c0122" - integrity sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA== - dependencies: - map-age-cleaner "^0.1.3" - mimic-fn "^3.1.0" - - memfs@^3.1.2, memfs@^3.2.2: - version "3.4.1" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.1.tgz#b78092f466a0dce054d63d39275b24c71d3f1305" - integrity sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw== - dependencies: - fs-monkey "1.0.3" - - memoize-one@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" - integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== - - "memoize-one@>=3.1.1 <6", memoize-one@^5.0.0, memoize-one@^5.1.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" - integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== - - memoize-one@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.1.0.tgz#a2387c58c03fff27ca390c31b764a79addf3f906" - integrity sha512-2GApq0yI/b22J2j9rhbrAlsHb0Qcz+7yWxeLG8h+95sl1XPUgeLimQSOdur4Vw7cUhrBHwaUZxWFZueojqNRzA== - - memoizerific@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" - integrity sha1-fIekZGREwy11Q4VwkF8tvRsagFo= - dependencies: - map-or-similar "^1.5.0" - - memory-fs@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" - integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA= - - memory-fs@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - - memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - - meow@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - - meow@^8.0.0: - version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - - merge-class-names@^1.1.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/merge-class-names/-/merge-class-names-1.4.2.tgz#78d6d95ab259e7e647252a7988fd25a27d5a8835" - integrity sha512-bOl98VzwCGi25Gcn3xKxnR5p/WrhWFQB59MS/aGENcmUc6iSm96yrFDF0XSNurX9qN4LbJm0R9kfvsQ17i8zCw== - - merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - - merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - - merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - - methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - - microevent.ts@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" - integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== - - micromatch@^2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - - micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - - micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - - miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - - mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== - - "mime-db@>= 1.43.0 < 2": - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - - mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.30, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== - dependencies: - mime-db "1.51.0" - - mime@1.6.0, mime@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - - mime@^2.4.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - - mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - - mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - - mimic-fn@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" - integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== - - mimic-response@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - - mimic-response@^2.0.0, mimic-response@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" - integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== - - min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.0" - - min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - - mini-create-react-context@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" - integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== - dependencies: - "@babel/runtime" "^7.12.1" - tiny-warning "^1.0.3" - - mini-css-extract-plugin@*, mini-css-extract-plugin@^2.2.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9" - integrity sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw== - dependencies: - schema-utils "^4.0.0" - - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - - minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - - minimatch@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - - minimatch@^3.0.2, minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - - minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - - minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - - minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - - minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - - minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - - minipass-json-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" - integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== - dependencies: - jsonparse "^1.3.1" - minipass "^3.0.0" - - minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - - minipass-sized@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" - integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== - dependencies: - minipass "^3.0.0" - - minipass@^2.6.0, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - - minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.1.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" - integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== - dependencies: - yallist "^4.0.0" - - minizlib@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - - minizlib@^2.0.0, minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - - mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - - mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - - mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - - mkdirp-infer-owner@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" - integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== - dependencies: - chownr "^2.0.0" - infer-owner "^1.0.4" - mkdirp "^1.0.3" - - mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - - mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - - mocha@9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.0.tgz#2bfba73d46e392901f877ab9a47b7c9c5d0275cc" - integrity sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "3.0.4" - ms "2.1.3" - nanoid "3.2.0" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - - modify-values@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" - integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== - - moment-timezone@0.5.34: - version "0.5.34" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c" - integrity sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg== - dependencies: - moment ">= 2.9.0" - - moment@2.29.1, moment@2.x, "moment@>= 2.9.0", moment@^2.27.0: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== - - monaco-editor-webpack-plugin@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.9.1.tgz#eb4bbb1c5e5bfb554541c1ae1542e74c2a9f43fd" - integrity sha512-x7fx1w3i/uwZERIgztHAAK3VQMsL8+ku0lFXXbO81hKDg8IieACqjGEa2mqEueg0c/fX+wd0oI+75wB19KJAsA== - dependencies: - loader-utils "^1.2.3" - - monaco-editor@^0.31.1: - version "0.31.1" - resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.31.1.tgz#67f597b3e45679d1f551237e12a3a42c4438b97b" - integrity sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q== - - moo-color@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/moo-color/-/moo-color-1.0.2.tgz#837c40758d2d58763825d1359a84e330531eca64" - integrity sha512-5iXz5n9LWQzx/C2WesGFfpE6RLamzdHwsn3KpfzShwbfIqs7stnoEpaNErf/7+3mbxwZ4s8Foq7I0tPxw7BWHg== - dependencies: - color-name "^1.1.4" - - moo@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" - integrity sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w== - - move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - - mrmime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" - integrity sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ== - - ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - - ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - - ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - - ms@2.1.3, ms@^2.0.0, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - - msw@^0.36.3: - version "0.36.8" - resolved "https://registry.yarnpkg.com/msw/-/msw-0.36.8.tgz#33ff8bfb0299626a95f43d0e4c3dc2c73c17f1ba" - integrity sha512-K7lOQoYqhGhTSChsmHMQbf/SDCsxh/m0uhN6Ipt206lGoe81fpTmaGD0KLh4jUxCONMOUnwCSj0jtX2CM4pEdw== - dependencies: - "@mswjs/cookies" "^0.1.7" - "@mswjs/interceptors" "^0.12.7" - "@open-draft/until" "^1.0.3" - "@types/cookie" "^0.4.1" - "@types/inquirer" "^8.1.3" - "@types/js-levenshtein" "^1.1.0" - chalk "4.1.1" - chokidar "^3.4.2" - cookie "^0.4.1" - graphql "^15.5.1" - headers-utils "^3.0.2" - inquirer "^8.2.0" - is-node-process "^1.0.1" - js-levenshtein "^1.1.6" - node-fetch "^2.6.7" - path-to-regexp "^6.2.0" - statuses "^2.0.0" - strict-event-emitter "^0.2.0" - type-fest "^1.2.2" - yargs "^17.3.0" - - multimatch@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" - integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== - dependencies: - "@types/minimatch" "^3.0.3" - array-differ "^3.0.0" - array-union "^2.1.0" - arrify "^2.0.1" - minimatch "^3.0.4" - - mute-stream@0.0.8, mute-stream@~0.0.4: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - - nan@^2.12.1, nan@^2.15.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - - nano-css@^5.3.1: - version "5.3.4" - resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.4.tgz#40af6a83a76f84204f346e8ccaa9169cdae9167b" - integrity sha512-wfcviJB6NOxDIDfr7RFn/GlaN7I/Bhe4d39ZRCJ3xvZX60LVe2qZ+rDqM49nm4YT81gAjzS+ZklhKP/Gnfnubg== - dependencies: - css-tree "^1.1.2" - csstype "^3.0.6" - fastest-stable-stringify "^2.0.2" - inline-style-prefixer "^6.0.0" - rtl-css-js "^1.14.0" - sourcemap-codec "^1.4.8" - stacktrace-js "^2.0.2" - stylis "^4.0.6" - - nanoid@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" - integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== - - nanoid@^3.1.23, nanoid@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - - nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - nanospinner@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/nanospinner/-/nanospinner-0.4.0.tgz#f544f71fb990423528b8f6dd6c26134cf9f21659" - integrity sha512-FhxiB9PcEztMw6XfQDSLJBMlmN4n7B2hl/oiK4Hy9479r1+df0i2099DgcEx+m6yBfBJVUuKpILvP8fM3rK3Sw== - dependencies: - picocolors "^1.0.0" - - natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - - nearley@^2.7.10: - version "2.20.1" - resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474" - integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ== - dependencies: - commander "^2.19.0" - moo "^0.5.0" - railroad-diagrams "^1.0.0" - randexp "0.4.6" - - needle@^2.5.2: - version "2.9.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" - integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - - negotiator@0.6.3, negotiator@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - - neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1, neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - - nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" - integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== - - nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - - no-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" - integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - - node-dir@^0.1.10: - version "0.1.17" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" - integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= - dependencies: - minimatch "^3.0.2" - - node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.5, node-fetch@^2.6.6, node-fetch@^2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - - node-gyp@^5.0.2: - version "5.1.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" - integrity sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.2" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.1.2" - request "^2.88.0" - rimraf "^2.6.3" - semver "^5.7.1" - tar "^4.4.12" - which "^1.3.1" - - node-gyp@^7.1.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" - integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.3" - nopt "^5.0.0" - npmlog "^4.1.2" - request "^2.88.2" - rimraf "^3.0.2" - semver "^7.3.2" - tar "^6.0.2" - which "^2.0.2" - - node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - - node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - - node-releases@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" - integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== - - nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - - nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - - normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - - normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" - - normalize-path@^2.0.1, normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - - normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - - normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - - normalize-url@^6.0.1, normalize-url@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== - - normalize.css@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" - integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== - - npm-bundled@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" - integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== - dependencies: - npm-normalize-package-bin "^1.0.1" - - npm-install-checks@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" - integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== - dependencies: - semver "^7.1.1" - - npm-lifecycle@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" - integrity sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g== - dependencies: - byline "^5.0.0" - graceful-fs "^4.1.15" - node-gyp "^5.0.2" - resolve-from "^4.0.0" - slide "^1.1.6" - uid-number "0.0.6" - umask "^1.1.0" - which "^1.3.1" - - npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - - npm-package-arg@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" - integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== - dependencies: - hosted-git-info "^2.7.1" - osenv "^0.1.5" - semver "^5.6.0" - validate-npm-package-name "^3.0.0" - - npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2, npm-package-arg@^8.1.5: - version "8.1.5" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" - integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== - dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" - validate-npm-package-name "^3.0.0" - - npm-packlist@^2.1.4: - version "2.2.2" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" - integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== - dependencies: - glob "^7.1.6" - ignore-walk "^3.0.3" - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - - npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" - integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== - dependencies: - npm-install-checks "^4.0.0" - npm-normalize-package-bin "^1.0.1" - npm-package-arg "^8.1.2" - semver "^7.3.4" - - npm-registry-fetch@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" - integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== - dependencies: - make-fetch-happen "^9.0.1" - minipass "^3.1.3" - minipass-fetch "^1.3.0" - minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" - - npm-registry-fetch@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" - integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== - dependencies: - "@npmcli/ci-detect" "^1.0.0" - lru-cache "^6.0.0" - make-fetch-happen "^8.0.9" - minipass "^3.1.3" - minipass-fetch "^1.3.0" - minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" - - npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - - npm-run-path@^4.0.0, npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - - npmlog@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - - npmlog@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" - integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== - dependencies: - are-we-there-yet "^2.0.0" - console-control-strings "^1.1.0" - gauge "^3.0.0" - set-blocking "^2.0.0" - - nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - - nth-check@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" - integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== - dependencies: - boolbase "^1.0.0" - - num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - - number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - - nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - - oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - - oauth2-mock-server@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/oauth2-mock-server/-/oauth2-mock-server-4.3.0.tgz#a1a0e8e99c4bfa0fe52a37d806f74e79de3cc245" - integrity sha512-oBp5/RqBuCjXWahxq80MwEo1SooDY2RDGUTAvzE8LczbWLx7rDiJe94CqfNfK4GKJ2FeMTxg8xwEoXMbLYRK4w== - dependencies: - basic-auth "^2.0.1" - body-parser "^1.19.1" - cors "^2.8.5" - express "^4.17.2" - jose "^4.4.0" - lodash.isplainobject "^4.0.6" - uuid "^8.3.2" - - object-assign@4.x, object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - - object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - - object-inspect@^1.11.0, object-inspect@^1.7.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - - object-is@^1.0.1, object-is@^1.0.2, object-is@^1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - - object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - - object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - - object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - - object.entries@^1.1.0, object.entries@^1.1.1, object.entries@^1.1.2, object.entries@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" - integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - "object.fromentries@^2.0.0 || ^1.0.0", object.fromentries@^2.0.3, object.fromentries@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" - integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0, object.getownpropertydescriptors@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" - integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - object.hasown@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" - integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.19.1" - - object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - - object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - - object.values@^1.1.0, object.values@^1.1.1, object.values@^1.1.2, object.values@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - objectorarray@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" - integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== - - observable-fns@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/observable-fns/-/observable-fns-0.6.1.tgz#636eae4fdd1132e88c0faf38d33658cc79d87e37" - integrity sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg== - - ol-mapbox-style@^6.8.2: - version "6.9.0" - resolved "https://registry.yarnpkg.com/ol-mapbox-style/-/ol-mapbox-style-6.9.0.tgz#b9587e390d8cc2037481ecdea53f0a6b9ba1d46c" - integrity sha512-Isxk+IPB6pCBD2Pubz9cpQcZjEeuPhxyk/QsLZjb2+KwvyGaIFltdlxnxx/QXJ7rOxUiLvS/XhsOyiK0c7prEw== - dependencies: - "@mapbox/mapbox-gl-style-spec" "^13.20.1" - mapbox-to-css-font "^2.4.1" - webfont-matcher "^1.1.0" - - ol@6.12.0: - version "6.12.0" - resolved "https://registry.yarnpkg.com/ol/-/ol-6.12.0.tgz#0de51abad0aaeb0eca41cba3c6d26ee485a3e92b" - integrity sha512-HR87aV//64aiGWbgzfsyRF5zFG+1nM1keRE4SugY0vmYyG/jjoij8qh3uaFHkFNQThdAy99sgLiQwTFk6AvGgw== - dependencies: - geotiff "^1.0.8" - ol-mapbox-style "^6.8.2" - pbf "3.2.1" - rbush "^3.0.1" - - on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - - on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - - once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - - onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - - open@^7.0.3: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - - open@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" - integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - - opener@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - - optimize-css-assets-webpack-plugin@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-6.0.1.tgz#7719bceabba1f3891ec3ae04efb81a1cc99cd793" - integrity sha512-BshV2UZPfggZLdUfN3zFBbG4sl/DynUI+YCB6fRRDWaqO2OiWN8GPcp4Y0/fEV6B3k9Hzyk3czve3V/8B/SzKQ== - dependencies: - cssnano "^5.0.2" - last-call-webpack-plugin "^3.0.0" - postcss "^8.2.1" - - optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - - optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - - ora@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - - os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - - os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - - os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - - os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - - osenv@^0.1.4, osenv@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - - ospath@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" - integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs= - - outdent@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.7.1.tgz#e9b400443622a97760b0bc74fa3223252ccd02a2" - integrity sha512-VjIzdUHunL74DdhcwMDt5FhNDQ8NYmTkuW0B+usIV2afS9aWT/1c9z1TsnFW349TP3nxmYeUl7Z++XpJRByvgg== - - outvariant@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.2.1.tgz#e630f6cdc1dbf398ed857e36f219de4a005ccd35" - integrity sha512-bcILvFkvpMXh66+Ubax/inxbKRyWTUiiFIW2DWkiS79wakrLGn3Ydy+GvukadiyfZjaL6C7YhIem4EZSM282wA== - - overlayscrollbars@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz#0b840a88737f43a946b9d87875a2f9e421d0338a" - integrity sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ== - - p-all@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0" - integrity sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA== - dependencies: - p-map "^2.0.0" - - p-cancelable@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" - integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== - - p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - - p-event@^4.0.0, p-event@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" - integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== - dependencies: - p-timeout "^3.1.0" - - p-filter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c" - integrity sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw== - dependencies: - p-map "^2.0.0" - - p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - - p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - - p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - - p-limit@^3.0.2, p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - - p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - - p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - - p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - - p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - - p-map-series@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" - integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== - - p-map@^2.0.0, p-map@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - - p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== - dependencies: - aggregate-error "^3.0.0" - - p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - - p-pipe@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" - integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== - - p-queue@^6.6.2: - version "6.6.2" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" - integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== - dependencies: - eventemitter3 "^4.0.4" - p-timeout "^3.2.0" - - p-reduce@^2.0.0, p-reduce@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" - integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== - - p-timeout@^3.1.0, p-timeout@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" - - p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - - p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - - p-waterfall@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" - integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== - dependencies: - p-reduce "^2.0.0" - - pacote@^11.2.6: - version "11.3.5" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" - integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== - dependencies: - "@npmcli/git" "^2.1.0" - "@npmcli/installed-package-contents" "^1.0.6" - "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^1.8.2" - cacache "^15.0.5" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.3" - mkdirp "^1.0.3" - npm-package-arg "^8.0.1" - npm-packlist "^2.1.4" - npm-pick-manifest "^6.0.0" - npm-registry-fetch "^11.0.0" - promise-retry "^2.0.1" - read-package-json-fast "^2.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.1.0" - - pako@^0.2.6: - version "0.2.9" - resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU= - - pako@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d" - integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg== - - pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - - papaparse@5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.3.1.tgz#770b7a9124d821d4b2132132b7bd7dce7194b5b1" - integrity sha512-Dbt2yjLJrCwH2sRqKFFJaN5XgIASO9YOFeFP8rIBRG2Ain8mqk5r1M6DkfvqEVozVcz3r3HaUGw253hA1nLIcA== - - parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - - param-case@^3.0.3, param-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" - integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - - parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - - parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - - parse-entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" - integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - - parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - - parse-headers@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.4.tgz#9eaf2d02bed2d1eff494331ce3df36d7924760bf" - integrity sha512-psZ9iZoCNFLrgRjZ1d8mn0h9WRqJwFxM9q3x7iUjN/YT2OksthDJ5TiPCu2F38kS4zutqfW+YdVVkBZZx3/1aw== - - parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - - parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - - parse-json@^5.0.0, parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - - parse-node-version@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" - integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== - - parse-path@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf" - integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA== - dependencies: - is-ssh "^1.3.0" - protocols "^1.4.0" - qs "^6.9.4" - query-string "^6.13.8" - - parse-url@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d" - integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw== - dependencies: - is-ssh "^1.3.0" - normalize-url "^6.1.0" - parse-path "^4.0.0" - protocols "^1.4.0" - - parse5-htmlparser2-tree-adapter@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - - parse5@6.0.1, parse5@^6.0.0, parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - - parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - - pascal-case@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" - integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - - pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - - path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - - path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - - path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - - path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - - path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - - path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - - path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - - path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - - path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - - path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - - path-parse@^1.0.6, path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - - path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - - path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - - path-to-regexp@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38" - integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg== - - path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - - path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - - path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - - path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - - pbf@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/pbf/-/pbf-3.2.1.tgz#b4c1b9e72af966cd82c6531691115cc0409ffe2a" - integrity sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ== - dependencies: - ieee754 "^1.1.12" - resolve-protobuf-schema "^2.1.0" - - pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - - pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - - performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - - picocolors@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" - integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== - - picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - - picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - - pify@^2.0.0, pify@^2.2.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - - pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - - pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - - pify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - - pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - - pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - - pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== - - pixelmatch@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65" - integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ== - dependencies: - pngjs "^4.0.1" - - pkg-dir@4.2.0, pkg-dir@^4.1.0, pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - - pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - - pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.0.0" - - pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - - please-upgrade-node@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" - integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== - dependencies: - semver-compare "^1.0.0" - - plist@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.4.tgz#a62df837e3aed2bb3b735899d510c4f186019cbe" - integrity sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg== - dependencies: - base64-js "^1.5.1" - xmlbuilder "^9.0.7" - - pngjs-image@~0.11.5: - version "0.11.7" - resolved "https://registry.yarnpkg.com/pngjs-image/-/pngjs-image-0.11.7.tgz#631dd59924569fc82ffebae0d5d53f85f54dab62" - integrity sha1-Yx3VmSRWn8gv/rrg1dU/hfVNq2I= - dependencies: - iconv-lite "^0.4.8" - pako "^0.2.6" - pngjs "2.3.1" - request "^2.55.0" - stream-buffers "1.0.1" - underscore "1.7.0" - - pngjs@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-2.3.1.tgz#11d1e12b9cb64d63e30c143a330f4c1f567da85f" - integrity sha1-EdHhK5y2TWPjDBQ6Mw9MH1Z9qF8= - - pngjs@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - - pngjs@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe" - integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg== - - pnp-webpack-plugin@1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" - integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== - dependencies: - ts-pnp "^1.1.6" - - polished@^4.0.5: - version "4.1.4" - resolved "https://registry.yarnpkg.com/polished/-/polished-4.1.4.tgz#640293ba834109614961a700fdacbb6599fb12d0" - integrity sha512-Nq5Mbza+Auo7N3sQb1QMFaQiDO+4UexWuSGR7Cjb4Sw11SZIJcrrFtiZ+L0jT9MBsUsxDboHVASbCLbE1rnECg== - dependencies: - "@babel/runtime" "^7.16.7" - - portfinder@^1.0.17: - version "1.0.28" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" - integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== - dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.5" - - posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - - postcss-attribute-case-insensitive@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.0.tgz#39cbf6babf3ded1e4abf37d09d6eda21c644105c" - integrity sha512-b4g9eagFGq9T5SWX4+USfVyjIb3liPnjhHHRMP7FMB2kFVpYyfEscV0wP3eaXhKlcHKUut8lt5BGoeylWA/dBQ== - dependencies: - postcss-selector-parser "^6.0.2" - - postcss-browser-reporter@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/postcss-browser-reporter/-/postcss-browser-reporter-0.6.0.tgz#72f6b8fe89f5ff4ed1ab781cd3c256e0f415f395" - integrity sha512-61gzk4wgthOIen4TRURzYYVVIszyvcorkYmD40CopdM8cdwJaCTDMYo/y8HQqjTPqyelw7r2ptncmR9xrWpVnw== - dependencies: - postcss "^7.0.14" - - postcss-calc@^8.2.0: - version "8.2.4" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5" - integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q== - dependencies: - postcss-selector-parser "^6.0.9" - postcss-value-parser "^4.2.0" - - postcss-clamp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-clamp/-/postcss-clamp-4.0.0.tgz#766d3dbaa2dc56e8bea1b690291b632c0c5bf728" - integrity sha512-FsMmeBZtymFN7Jtlnw9is8I4nB+qEEb/qS0ZLTIqcKiwZyHBq44Yhv29Q+VQsTGHYFqIr/s/9tqvNM7j+j1d+g== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-color-functional-notation@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.2.tgz#f59ccaeb4ee78f1b32987d43df146109cc743073" - integrity sha512-DXVtwUhIk4f49KK5EGuEdgx4Gnyj6+t2jBSEmxvpIK9QI40tWrpS2Pua8Q7iIZWBrki2QOaeUdEaLPPa91K0RQ== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-color-hex-alpha@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.3.tgz#61a0fd151d28b128aa6a8a21a2dad24eebb34d52" - integrity sha512-fESawWJCrBV035DcbKRPAVmy21LpoyiXdPTuHUfWJ14ZRjY7Y7PA6P4g8z6LQGYhU1WAxkTxjIjurXzoe68Glw== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-color-rebeccapurple@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.0.2.tgz#5d397039424a58a9ca628762eb0b88a61a66e079" - integrity sha512-SFc3MaocHaQ6k3oZaFwH8io6MdypkUtEy/eXzXEB1vEQlO3S3oDc/FSZA8AsS04Z25RirQhlDlHLh3dn7XewWw== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-colormin@^5.2.5: - version "5.2.5" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.5.tgz#d1fc269ac2ad03fe641d462b5d1dada35c69968a" - integrity sha512-+X30aDaGYq81mFqwyPpnYInsZQnNpdxMX0ajlY7AExCexEFkPVV+KrO7kXwayqEWL2xwEbNQ4nUO0ZsRWGnevg== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - colord "^2.9.1" - postcss-value-parser "^4.2.0" - - postcss-convert-values@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.4.tgz#3e74dd97c581f475ae7b4500bc0a7c4fb3a6b1b6" - integrity sha512-bugzSAyjIexdObovsPZu/sBCTHccImJxLyFgeV0MmNBm/Lw5h5XnjfML6gzEmJ3A6nyfCW7hb1JXzcsA4Zfbdw== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-custom-media@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz#1be6aff8be7dc9bf1fe014bde3b71b92bb4552f1" - integrity sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g== - - postcss-custom-properties@^12.1.4: - version "12.1.4" - resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.4.tgz#e3d8a8000f28094453b836dff5132385f2862285" - integrity sha512-i6AytuTCoDLJkWN/MtAIGriJz3j7UX6bV7Z5t+KgFz+dwZS15/mlTJY1S0kRizlk6ba0V8u8hN50Fz5Nm7tdZw== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-custom-selectors@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-6.0.0.tgz#022839e41fbf71c47ae6e316cb0e6213012df5ef" - integrity sha512-/1iyBhz/W8jUepjGyu7V1OPcGbc636snN1yXEQCinb6Bwt7KxsiU7/bLQlp8GwAXzCh7cobBU5odNn/2zQWR8Q== - dependencies: - postcss-selector-parser "^6.0.4" - - postcss-dir-pseudo-class@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.4.tgz#9afe49ea631f0cb36fa0076e7c2feb4e7e3f049c" - integrity sha512-I8epwGy5ftdzNWEYok9VjW9whC4xnelAtbajGv4adql4FIF09rnrxnA9Y8xSHN47y7gqFIv10C5+ImsLeJpKBw== - dependencies: - postcss-selector-parser "^6.0.9" - - postcss-discard-comments@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.3.tgz#011acb63418d600fdbe18804e1bbecb543ad2f87" - integrity sha512-6W5BemziRoqIdAKT+1QjM4bNcJAQ7z7zk073730NHg4cUXh3/rQHHj7pmYxUB9aGhuRhBiUf0pXvIHkRwhQP0Q== - - postcss-discard-duplicates@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.3.tgz#10f202a4cfe9d407b73dfea7a477054d21ea0c1f" - integrity sha512-vPtm1Mf+kp7iAENTG7jI1MN1lk+fBqL5y+qxyi4v3H+lzsXEdfS3dwUZD45KVhgzDEgduur8ycB4hMegyMTeRw== - - postcss-discard-empty@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.3.tgz#ec185af4a3710b88933b0ff751aa157b6041dd6a" - integrity sha512-xGJugpaXKakwKI7sSdZjUuN4V3zSzb2Y0LOlmTajFbNinEjTfVs9PFW2lmKBaC/E64WwYppfqLD03P8l9BuueA== - - postcss-discard-overridden@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.4.tgz#cc999d6caf18ea16eff8b2b58f48ec3ddee35c9c" - integrity sha512-3j9QH0Qh1KkdxwiZOW82cId7zdwXVQv/gRXYDnwx5pBtR1sTkU4cXRK9lp5dSdiM0r0OICO/L8J6sV1/7m0kHg== - - postcss-double-position-gradients@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.0.tgz#a8614fb3a2a4b8877bffb8961b770e00322bbad1" - integrity sha512-oz73I08yMN3oxjj0s8mED1rG+uOYoK3H8N9RjQofyg52KBRNmePJKg3fVwTpL2U5ZFbCzXoZBsUD/CvZdlqE4Q== - dependencies: - "@csstools/postcss-progressive-custom-properties" "^1.1.0" - postcss-value-parser "^4.2.0" - - postcss-env-function@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-4.0.5.tgz#b9614d50abd91e4c88a114644a9766880dabe393" - integrity sha512-gPUJc71ji9XKyl0WSzAalBeEA/89kU+XpffpPxSaaaZ1c48OL36r1Ep5R6+9XAPkIiDlSvVAwP4io12q/vTcvA== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-filter-plugins@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-3.0.1.tgz#9d226e946d56542ab7c26123053459a331df545d" - integrity sha512-tRKbW4wWBEkSSFuJtamV2wkiV9rj6Yy7P3Y13+zaynlPEEZt8EgYKn3y/RBpMeIhNmHXFlSdzofml65hD5OafA== - dependencies: - postcss "^6.0.14" - - postcss-flexbugs-fixes@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz#9218a65249f30897deab1033aced8578562a6690" - integrity sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ== - dependencies: - postcss "^7.0.26" - - postcss-focus-visible@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz#50c9ea9afa0ee657fb75635fabad25e18d76bf9e" - integrity sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw== - dependencies: - postcss-selector-parser "^6.0.9" - - postcss-focus-within@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz#5b1d2ec603195f3344b716c0b75f61e44e8d2e20" - integrity sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ== - dependencies: - postcss-selector-parser "^6.0.9" - - postcss-font-variant@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz#efd59b4b7ea8bb06127f2d031bfbb7f24d32fa66" - integrity sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA== - - postcss-gap-properties@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz#6401bb2f67d9cf255d677042928a70a915e6ba60" - integrity sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ== - - postcss-icss-keyframes@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/postcss-icss-keyframes/-/postcss-icss-keyframes-0.2.1.tgz#80c4455e0112b0f2f9c3c05ac7515062bb9ff295" - integrity sha1-gMRFXgESsPL5w8Bax1FQYruf8pU= - dependencies: - icss-utils "^3.0.1" - postcss "^6.0.2" - postcss-value-parser "^3.3.0" - - postcss-icss-selectors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/postcss-icss-selectors/-/postcss-icss-selectors-2.0.3.tgz#27fa1afcaab6c602c866cbb298f3218e9bc1c9b3" - integrity sha1-J/oa/Kq2xgLIZsuymPMhjpvBybM= - dependencies: - css-selector-tokenizer "^0.7.0" - generic-names "^1.0.2" - icss-utils "^3.0.1" - lodash "^4.17.4" - postcss "^6.0.2" - - postcss-image-set-function@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-4.0.6.tgz#bcff2794efae778c09441498f40e0c77374870a9" - integrity sha512-KfdC6vg53GC+vPd2+HYzsZ6obmPqOk6HY09kttU19+Gj1nC3S3XBVEXDHxkhxTohgZqzbUb94bKXvKDnYWBm/A== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-initial@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42" - integrity sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ== - - postcss-lab-function@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-4.1.1.tgz#8b37dfcb9ca4ff82bbe7192c7ba3cc2bccbc0ef1" - integrity sha512-j3Z0WQCimY2tMle++YcmygnnVbt6XdnrCV1FO2IpzaCSmtTF2oO8h4ZYUA1Q+QHYroIiaWPvNHt9uBR4riCksQ== - dependencies: - "@csstools/postcss-progressive-custom-properties" "^1.1.0" - postcss-value-parser "^4.2.0" - - postcss-load-config@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a" - integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw== - dependencies: - cosmiconfig "^5.0.0" - import-cwd "^2.0.0" - - postcss-load-config@^3.0.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.3.tgz#21935b2c43b9a86e6581a576ca7ee1bde2bd1d23" - integrity sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw== - dependencies: - lilconfig "^2.0.4" - yaml "^1.10.2" - - postcss-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" - integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== - dependencies: - loader-utils "^1.1.0" - postcss "^7.0.0" - postcss-load-config "^2.0.0" - schema-utils "^1.0.0" - - postcss-loader@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.3.0.tgz#2c4de9657cd4f07af5ab42bd60a673004da1b8cc" - integrity sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q== - dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.4" - loader-utils "^2.0.0" - schema-utils "^3.0.0" - semver "^7.3.4" - - postcss-logical@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-5.0.4.tgz#ec75b1ee54421acc04d5921576b7d8db6b0e6f73" - integrity sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g== - - postcss-media-minmax@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz#7140bddec173e2d6d657edbd8554a55794e2a5b5" - integrity sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ== - - postcss-merge-longhand@^5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.6.tgz#090e60d5d3b3caad899f8774f8dccb33217d2166" - integrity sha512-rkmoPwQO6ymJSmWsX6l2hHeEBQa7C4kJb9jyi5fZB1sE8nSCv7sqchoYPixRwX/yvLoZP2y6FA5kcjiByeJqDg== - dependencies: - postcss-value-parser "^4.2.0" - stylehacks "^5.0.3" - - postcss-merge-rules@^5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.6.tgz#26b37411fe1e80202fcef61cab027265b8925f2b" - integrity sha512-nzJWJ9yXWp8AOEpn/HFAW72WKVGD2bsLiAmgw4hDchSij27bt6TF+sIK0cJUBAYT3SGcjtGGsOR89bwkkMuMgQ== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - cssnano-utils "^3.0.2" - postcss-selector-parser "^6.0.5" - - postcss-minify-font-values@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.4.tgz#627d824406b0712243221891f40a44fffe1467fd" - integrity sha512-RN6q3tyuEesvyCYYFCRGJ41J1XFvgV+dvYGHr0CeHv8F00yILlN8Slf4t8XW4IghlfZYCeyRrANO6HpJ948ieA== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-minify-gradients@^5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.6.tgz#b07cef51a93f075e94053fd972ff1cba2eaf6503" - integrity sha512-E/dT6oVxB9nLGUTiY/rG5dX9taugv9cbLNTFad3dKxOO+BQg25Q/xo2z2ddG+ZB1CbkZYaVwx5blY8VC7R/43A== - dependencies: - colord "^2.9.1" - cssnano-utils "^3.0.2" - postcss-value-parser "^4.2.0" - - postcss-minify-params@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.5.tgz#86cb624358cd45c21946f8c317893f0449396646" - integrity sha512-YBNuq3Rz5LfLFNHb9wrvm6t859b8qIqfXsWeK7wROm3jSKNpO1Y5e8cOyBv6Acji15TgSrAwb3JkVNCqNyLvBg== - dependencies: - browserslist "^4.16.6" - cssnano-utils "^3.0.2" - postcss-value-parser "^4.2.0" - - postcss-minify-selectors@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.3.tgz#6ac12d52aa661fd509469d87ab2cebb0a1e3a1b5" - integrity sha512-9RJfTiQEKA/kZhMaEXND893nBqmYQ8qYa/G+uPdVnXF6D/FzpfI6kwBtWEcHx5FqDbA79O9n6fQJfrIj6M8jvQ== - dependencies: - postcss-selector-parser "^6.0.5" - - postcss-modules-extract-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" - integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== - dependencies: - postcss "^7.0.5" - - postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== - - postcss-modules-local-by-default@^3.0.2, postcss-modules-local-by-default@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" - integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw== - dependencies: - icss-utils "^4.1.1" - postcss "^7.0.32" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - - postcss-modules-local-by-default@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - - postcss-modules-scope@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" - integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - - postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== - dependencies: - postcss-selector-parser "^6.0.4" - - postcss-modules-values@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" - integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== - dependencies: - icss-utils "^4.0.0" - postcss "^7.0.6" - - postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== - dependencies: - icss-utils "^5.0.0" - - "postcss-nested@^4.2.1 || ^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" - integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== - dependencies: - postcss-selector-parser "^6.0.6" - - postcss-nesting@^10.1.2: - version "10.1.2" - resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-10.1.2.tgz#2e5f811b3d75602ea18a95dd445bde5297145141" - integrity sha512-dJGmgmsvpzKoVMtDMQQG/T6FSqs6kDtUDirIfl4KnjMCiY9/ETX8jdKyCd20swSRAbUYkaBKV20pxkzxoOXLqQ== - dependencies: - postcss-selector-parser "^6.0.8" - - postcss-normalize-charset@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.3.tgz#719fb9f9ca9835fcbd4fed8d6e0d72a79e7b5472" - integrity sha512-iKEplDBco9EfH7sx4ut7R2r/dwTnUqyfACf62Unc9UiyFuI7uUqZZtY+u+qp7g8Qszl/U28HIfcsI3pEABWFfA== - - postcss-normalize-display-values@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.3.tgz#94cc82e20c51cc4ffba6b36e9618adc1e50db8c1" - integrity sha512-FIV5FY/qs4Ja32jiDb5mVj5iWBlS3N8tFcw2yg98+8MkRgyhtnBgSC0lxU+16AMHbjX5fbSJgw5AXLMolonuRQ== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-normalize-positions@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.4.tgz#4001f38c99675437b83277836fb4291887fcc6cc" - integrity sha512-qynirjBX0Lc73ROomZE3lzzmXXTu48/QiEzKgMeqh28+MfuHLsuqC9po4kj84igZqqFGovz8F8hf44hA3dPYmQ== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-normalize-repeat-style@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.4.tgz#d005adf9ee45fae78b673031a376c0c871315145" - integrity sha512-Innt+wctD7YpfeDR7r5Ik6krdyppyAg2HBRpX88fo5AYzC1Ut/l3xaxACG0KsbX49cO2n5EB13clPwuYVt8cMA== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-normalize-string@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.4.tgz#b5e00a07597e7aa8a871817bfeac2bfaa59c3333" - integrity sha512-Dfk42l0+A1CDnVpgE606ENvdmksttLynEqTQf5FL3XGQOyqxjbo25+pglCUvziicTxjtI2NLUR6KkxyUWEVubQ== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-normalize-timing-functions@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.3.tgz#47210227bfcba5e52650d7a18654337090de7072" - integrity sha512-QRfjvFh11moN4PYnJ7hia4uJXeFotyK3t2jjg8lM9mswleGsNw2Lm3I5wO+l4k1FzK96EFwEVn8X8Ojrp2gP4g== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-normalize-unicode@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.4.tgz#02866096937005cdb2c17116c690f29505a1623d" - integrity sha512-W79Regn+a+eXTzB+oV/8XJ33s3pDyFTND2yDuUCo0Xa3QSy1HtNIfRVPXNubHxjhlqmMFADr3FSCHT84ITW3ig== - dependencies: - browserslist "^4.16.6" - postcss-value-parser "^4.2.0" - - postcss-normalize-url@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.5.tgz#c39efc12ff119f6f45f0b4f516902b12c8080e3a" - integrity sha512-Ws3tX+PcekYlXh+ycAt0wyzqGthkvVtZ9SZLutMVvHARxcpu4o7vvXcNoiNKyjKuWecnjS6HDI3fjBuDr5MQxQ== - dependencies: - normalize-url "^6.0.1" - postcss-value-parser "^4.2.0" - - postcss-normalize-whitespace@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.4.tgz#1d477e7da23fecef91fc4e37d462272c7b55c5ca" - integrity sha512-wsnuHolYZjMwWZJoTC9jeI2AcjA67v4UuidDrPN9RnX8KIZfE+r2Nd6XZRwHVwUiHmRvKQtxiqo64K+h8/imaw== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-opacity-percentage@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz#bd698bb3670a0a27f6d657cc16744b3ebf3b1145" - integrity sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w== - - postcss-ordered-values@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.5.tgz#e878af822a130c3f3709737e24cb815ca7c6d040" - integrity sha512-mfY7lXpq+8bDEHfP+muqibDPhZ5eP9zgBEF9XRvoQgXcQe2Db3G1wcvjbnfjXG6wYsl+0UIjikqq4ym1V2jGMQ== - dependencies: - cssnano-utils "^3.0.2" - postcss-value-parser "^4.2.0" - - postcss-overflow-shorthand@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz#ebcfc0483a15bbf1b27fdd9b3c10125372f4cbc2" - integrity sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg== - - postcss-page-break@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-3.0.4.tgz#7fbf741c233621622b68d435babfb70dd8c1ee5f" - integrity sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ== - - postcss-place@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-7.0.4.tgz#eb026650b7f769ae57ca4f938c1addd6be2f62c9" - integrity sha512-MrgKeiiu5OC/TETQO45kV3npRjOFxEHthsqGtkh3I1rPbZSbXGD/lZVi9j13cYh+NA8PIAPyk6sGjT9QbRyvSg== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-preset-env@^7.0.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-7.4.1.tgz#ca6131c6e0d0e0bcc429dbef3e8f8d03250041ea" - integrity sha512-UvBVvPJ2vb4odAtckSbryndyBz+Me1q8wawqq0qznpDXy188I+8W5Sa929sCPqw2/NSYnqpHJbo41BKso3+I9A== - dependencies: - "@csstools/postcss-color-function" "^1.0.2" - "@csstools/postcss-font-format-keywords" "^1.0.0" - "@csstools/postcss-hwb-function" "^1.0.0" - "@csstools/postcss-ic-unit" "^1.0.0" - "@csstools/postcss-is-pseudo-class" "^2.0.0" - "@csstools/postcss-normalize-display-values" "^1.0.0" - "@csstools/postcss-oklab-function" "^1.0.1" - "@csstools/postcss-progressive-custom-properties" "^1.2.0" - autoprefixer "^10.4.2" - browserslist "^4.19.1" - css-blank-pseudo "^3.0.3" - css-has-pseudo "^3.0.4" - css-prefers-color-scheme "^6.0.3" - cssdb "^6.3.1" - postcss-attribute-case-insensitive "^5.0.0" - postcss-clamp "^4.0.0" - postcss-color-functional-notation "^4.2.2" - postcss-color-hex-alpha "^8.0.3" - postcss-color-rebeccapurple "^7.0.2" - postcss-custom-media "^8.0.0" - postcss-custom-properties "^12.1.4" - postcss-custom-selectors "^6.0.0" - postcss-dir-pseudo-class "^6.0.4" - postcss-double-position-gradients "^3.1.0" - postcss-env-function "^4.0.5" - postcss-focus-visible "^6.0.4" - postcss-focus-within "^5.0.4" - postcss-font-variant "^5.0.0" - postcss-gap-properties "^3.0.3" - postcss-image-set-function "^4.0.6" - postcss-initial "^4.0.1" - postcss-lab-function "^4.1.1" - postcss-logical "^5.0.4" - postcss-media-minmax "^5.0.0" - postcss-nesting "^10.1.2" - postcss-opacity-percentage "^1.1.2" - postcss-overflow-shorthand "^3.0.3" - postcss-page-break "^3.0.4" - postcss-place "^7.0.4" - postcss-pseudo-class-any-link "^7.1.1" - postcss-replace-overflow-wrap "^4.0.0" - postcss-selector-not "^5.0.0" - - postcss-pseudo-class-any-link@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.1.tgz#534eb1dadd9945eb07830dbcc06fb4d5d865b8e0" - integrity sha512-JRoLFvPEX/1YTPxRxp1JO4WxBVXJYrSY7NHeak5LImwJ+VobFMwYDQHvfTXEpcn+7fYIeGkC29zYFhFWIZD8fg== - dependencies: - postcss-selector-parser "^6.0.9" - - postcss-reduce-initial@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.3.tgz#68891594defd648253703bbd8f1093162f19568d" - integrity sha512-c88TkSnQ/Dnwgb4OZbKPOBbCaauwEjbECP5uAuFPOzQ+XdjNjRH7SG0dteXrpp1LlIFEKK76iUGgmw2V0xeieA== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - - postcss-reduce-transforms@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.4.tgz#717e72d30befe857f7d2784dba10eb1157863712" - integrity sha512-VIJB9SFSaL8B/B7AXb7KHL6/GNNbbCHslgdzS9UDfBZYIA2nx8NLY7iD/BXFSO/1sRUILzBTfHCoW5inP37C5g== - dependencies: - postcss-value-parser "^4.2.0" - - postcss-replace-overflow-wrap@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz#d2df6bed10b477bf9c52fab28c568b4b29ca4319" - integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw== - - postcss-reporter@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-6.0.1.tgz#7c055120060a97c8837b4e48215661aafb74245f" - integrity sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw== - dependencies: - chalk "^2.4.1" - lodash "^4.17.11" - log-symbols "^2.2.0" - postcss "^7.0.7" - - postcss-selector-not@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz#ac5fc506f7565dd872f82f5314c0f81a05630dc7" - integrity sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ== - dependencies: - balanced-match "^1.0.0" - - postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.8, postcss-selector-parser@^6.0.9: - version "6.0.9" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" - integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - - postcss-svgo@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.4.tgz#cfa8682f47b88f7cd75108ec499e133b43102abf" - integrity sha512-yDKHvULbnZtIrRqhZoA+rxreWpee28JSRH/gy9727u0UCgtpv1M/9WEWY3xySlFa0zQJcqf6oCBJPR5NwkmYpg== - dependencies: - postcss-value-parser "^4.2.0" - svgo "^2.7.0" - - postcss-unique-selectors@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.4.tgz#08e188126b634ddfa615fb1d6c262bafdd64826e" - integrity sha512-5ampwoSDJCxDPoANBIlMgoBcYUHnhaiuLYJR5pj1DLnYQvMRVyFuTA5C3Bvt+aHtiqWpJkD/lXT50Vo1D0ZsAQ== - dependencies: - postcss-selector-parser "^6.0.5" - - postcss-value-parser@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - - postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - - postcss@^6.0.14, postcss@^6.0.2: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - - postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.36, postcss@^7.0.5, postcss@^7.0.6, postcss@^7.0.7: - version "7.0.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" - integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== - dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" - - "postcss@^7.0.30 || ^8.0.0", postcss@^8.2.1, postcss@^8.2.15, postcss@^8.3.0: - version "8.4.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1" - integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA== - dependencies: - nanoid "^3.2.0" - picocolors "^1.0.0" - source-map-js "^1.0.2" - - preceptor-core@~0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/preceptor-core/-/preceptor-core-0.10.1.tgz#c31eb026fad91c24b44351308ac97e625ec69511" - integrity sha512-WLDk+UowEESixvlhiamGOj/iqWrp8IWeCCHvBZrLh0g4/A1Fa77fDQWqQUd5S5rScT+9u49aDfa45xYRkxqmiA== - dependencies: - log4js "1.1.1" - underscore "1.7.0" - - prefix-style@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" - integrity sha1-ZrupqHDP2jCKXcIOhekSCTLJWgY= - - prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - - prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - - preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= - - prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - - "prettier@>=2.2.1 <=2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18" - integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w== - - prettier@^2.2.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== - - pretty-bytes@^5.6.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" - integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== - - pretty-error@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" - integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw== - dependencies: - lodash "^4.17.20" - renderkid "^2.0.4" - - pretty-error@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" - integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== - dependencies: - lodash "^4.17.20" - renderkid "^3.0.0" - - pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" - integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== - dependencies: - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^17.0.1" - - pretty-hrtime@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" - integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= - - prismjs@1.26.0: - version "1.26.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.26.0.tgz#16881b594828bb6b45296083a8cbab46b0accd47" - integrity sha512-HUoH9C5Z3jKkl3UunCyiD5jwk0+Hz0fIgQ2nbwU2Oo/ceuTAQAg+pPVnfdt2TJWRVLcxKh9iuoYDUSc8clb5UQ== - - prismjs@^1.21.0, prismjs@^1.27.0: - version "1.27.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" - integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== - - prismjs@~1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" - integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== - - process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - - process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - - progress@2.0.3, progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - - promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - - promise-polyfill@^8.1.3: - version "8.2.1" - resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.1.tgz#1fa955b325bee4f6b8a4311e18148d4e5b46d254" - integrity sha512-3p9zj0cEHbp7NVUxEYUWjQlffXqnXaZIMPkAO7HhFh8u5636xLRDHOUo2vpWSK0T2mqm6fKLXYn1KP6PAZ2gKg== - - promise-retry@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" - integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== - dependencies: - err-code "^2.0.2" - retry "^0.12.0" - - promise.allsettled@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.5.tgz#2443f3d4b2aa8dfa560f6ac2aa6c4ea999d75f53" - integrity sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ== - dependencies: - array.prototype.map "^1.0.4" - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - iterate-value "^1.0.2" - - promise.prototype.finally@^3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.3.tgz#d3186e58fcf4df1682a150f934ccc27b7893389c" - integrity sha512-EXRF3fC9/0gz4qkt/f5EP5iW4kj9oFpBICNpCNOb/52+8nlHIX07FPLbi/q4qYBQ1xZqivMzTpNQSnArVASolQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - promise@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/promise/-/promise-6.0.0.tgz#456538dd4afdd25dc7d0f52a5201ed242b7c109d" - integrity sha1-RWU43Ur90l3H0PUqUgHtJCt8EJ0= - dependencies: - asap "~1.0.0" - - prompts@^2.0.1, prompts@^2.4.0, prompts@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - - promzard@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= - dependencies: - read "1" - - prop-types-exact@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/prop-types-exact/-/prop-types-exact-1.2.0.tgz#825d6be46094663848237e3925a98c6e944e9869" - integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA== - dependencies: - has "^1.0.3" - object.assign "^4.1.0" - reflect.ownkeys "^0.2.0" - - prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - - property-information@^5.0.0, property-information@^5.3.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" - integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== - dependencies: - xtend "^4.0.0" - - proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - - protocol-buffers-schema@^3.3.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03" - integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw== - - protocols@^1.1.0, protocols@^1.4.0: - version "1.4.8" - resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" - integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== - - proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - - proxy-from-env@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= - - proxy-from-env@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - - prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - - pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - - psl@^1.1.28, psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - - public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - - pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - - pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - - pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - - punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - - punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - - punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - - puppeteer-core@^13.1.3: - version "13.3.2" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-13.3.2.tgz#03b47c776fea881df69e7a55559848434f8110f3" - integrity sha512-9T8deXmLWf55/RvDpl32vP68stTufqvtj6fc9hH09ZwCLh5IwnN9Z0MWHfDMTLiW6MUpW2Flx5CQWt1SCUT47g== - dependencies: - cross-fetch "3.1.5" - debug "4.3.3" - devtools-protocol "0.0.960912" - extract-zip "2.0.1" - https-proxy-agent "5.0.0" - pkg-dir "4.2.0" - progress "2.0.3" - proxy-from-env "1.1.0" - rimraf "3.0.2" - tar-fs "2.1.1" - unbzip2-stream "1.4.3" - ws "8.5.0" - - q@^1.1.2, q@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - - qs@6.9.7: - version "6.9.7" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" - integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== - - qs@^6.10.0, qs@^6.4.0, qs@^6.9.4: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== - dependencies: - side-channel "^1.0.4" - - qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== - - query-string@^6.13.8: - version "6.14.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" - integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== - dependencies: - decode-uri-component "^0.2.0" - filter-obj "^1.1.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - - querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - - querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - - querystring@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== - - queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - - quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - - quickselect@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" - integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== - - raf-schd@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" - integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== - - raf@^3.1.0, raf@^3.4.0, raf@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" - integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== - dependencies: - performance-now "^2.1.0" - - railroad-diagrams@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" - integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= - - ramda@^0.21.0: - version "0.21.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" - integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= - - ramda@~0.27.1: - version "0.27.2" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.2.tgz#84463226f7f36dc33592f6f4ed6374c48306c3f1" - integrity sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA== - - randexp@0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" - integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ== - dependencies: - discontinuous-range "1.0.0" - ret "~0.1.10" - - randomatic@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" - integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - - randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - - range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - - raw-body@2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" - integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g== - dependencies: - bytes "3.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - unpipe "1.0.0" - - raw-body@~1.1.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" - integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= - dependencies: - bytes "1" - string_decoder "0.10" - - raw-loader@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6" - integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - - rbush@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf" - integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w== - dependencies: - quickselect "^2.0.0" - - rc-align@^2.4.0: - version "2.4.5" - resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-2.4.5.tgz#c941a586f59d1017f23a428f0b468663fb7102ab" - integrity sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw== - dependencies: - babel-runtime "^6.26.0" - dom-align "^1.7.0" - prop-types "^15.5.8" - rc-util "^4.0.4" - - rc-align@^4.0.0: - version "4.0.11" - resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-4.0.11.tgz#8198c62db266bc1b8ef05e56c13275bf72628a5e" - integrity sha512-n9mQfIYQbbNTbefyQnRHZPWuTEwG1rY4a9yKlIWHSTbgwI+XUMGRYd0uJ5pE2UbrNX0WvnMBA1zJ3Lrecpra/A== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - dom-align "^1.7.0" - lodash "^4.17.21" - rc-util "^5.3.0" - resize-observer-polyfill "^1.5.1" - - rc-animate@2.x: - version "2.11.1" - resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-2.11.1.tgz#2666eeb6f1f2a495a13b2af09e236712278fdb2c" - integrity sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ== - dependencies: - babel-runtime "6.x" - classnames "^2.2.6" - css-animation "^1.3.2" - prop-types "15.x" - raf "^3.4.0" - rc-util "^4.15.3" - react-lifecycles-compat "^3.0.4" - - rc-cascader@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.2.1.tgz#fc928d67d96c3d9f358263e4a9127bcf4257cc6b" - integrity sha512-Raxam9tFzBL4TCgHoyVcf7+Q2KSFneUk3FZXi9w1tfxEihLlezSH0oCNMjHJN8hxWwwx9ZbI9UzWTfFImjXc0Q== - dependencies: - "@babel/runtime" "^7.12.5" - array-tree-filter "^2.1.0" - classnames "^2.3.1" - rc-select "~14.0.0-alpha.23" - rc-tree "~5.4.3" - rc-util "^5.6.1" - - rc-drawer@4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-4.4.3.tgz#2094937a844e55dc9644236a2d9fba79c344e321" - integrity sha512-FYztwRs3uXnFOIf1hLvFxIQP9MiZJA+0w+Os8dfDh/90X7z/HqP/Yg+noLCIeHEbKln1Tqelv8ymCAN24zPcfQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-util "^5.7.0" - - rc-motion@^2.0.0, rc-motion@^2.0.1: - version "2.4.5" - resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.4.5.tgz#b061c50bb29ecd3d735d5f4c40924a3c78226cbd" - integrity sha512-f3uJHR4gcpeZS/s8/nYFSOrXt2Wu/h9GrEcbJmC0qmKrVNgwL1pTgrT5kW7lgG6PFeoL4yHDmpQoEKkrPtKIzQ== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-util "^5.18.1" - - rc-overflow@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.2.3.tgz#1754216d807f5473304272b0321c3aba7615f47a" - integrity sha512-Bz6dXTn/ww8nmu70tUQfRV0wT3BkfXY6j1lB1O38OVkDPz4xwfAcGK+LJ2zewUR5cTXkJ8hAN7YULohG8z4M7Q== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-resize-observer "^1.0.0" - rc-util "^5.15.0" - - rc-resize-observer@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz#9f46052f81cdf03498be35144cb7c53fd282c4c7" - integrity sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.1" - rc-util "^5.15.0" - resize-observer-polyfill "^1.5.1" - - rc-select@~14.0.0-alpha.23: - version "14.0.0-alpha.26" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.0.0-alpha.26.tgz#51ae0aee882d3a729648f86fe99fe7d0006d9bdb" - integrity sha512-5+vpP+qkYg9TiQb06BIVMTdnKwjXW/4ud8NWaCtnLGsyeqN6Hg7HGTUwlTTOyNOU5zMjbKHrAIvMk8NipGKqtA== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-motion "^2.0.1" - rc-overflow "^1.0.0" - rc-trigger "^5.0.4" - rc-util "^5.16.1" - rc-virtual-list "^3.2.0" - - rc-slider@9.7.5: - version "9.7.5" - resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-9.7.5.tgz#193141c68e99b1dc3b746daeb6bf852946f5b7f4" - integrity sha512-LV/MWcXFjco1epPbdw1JlLXlTgmWpB9/Y/P2yinf8Pg3wElHxA9uajN21lJiWtZjf5SCUekfSP6QMJfDo4t1hg== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.5" - rc-tooltip "^5.0.1" - rc-util "^5.16.1" - shallowequal "^1.1.0" - - rc-time-picker@^3.7.3: - version "3.7.3" - resolved "https://registry.yarnpkg.com/rc-time-picker/-/rc-time-picker-3.7.3.tgz#65a8de904093250ae9c82b02a4905e0f995e23e2" - integrity sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg== - dependencies: - classnames "2.x" - moment "2.x" - prop-types "^15.5.8" - raf "^3.4.1" - rc-trigger "^2.2.0" - react-lifecycles-compat "^3.0.4" - - rc-tooltip@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-5.1.1.tgz#94178ed162d0252bc4993b725f5dc2ac0fccf154" - integrity sha512-alt8eGMJulio6+4/uDm7nvV+rJq9bsfxFDCI0ljPdbuoygUscbsMYb6EQgwib/uqsXQUvzk+S7A59uYHmEgmDA== - dependencies: - "@babel/runtime" "^7.11.2" - rc-trigger "^5.0.0" - - rc-tree@~5.4.3: - version "5.4.3" - resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-5.4.3.tgz#8674644964e17e5ab9b111c5aa18676f673e7bd0" - integrity sha512-WAHV8FkBerulj9J/+61+Qn0TD/Zo37PrDG8/45WomzGTYavxFMur9YguKjQj/J+NxjVJzrJL3lvdSZsumfdbiA== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "2.x" - rc-motion "^2.0.1" - rc-util "^5.16.1" - rc-virtual-list "^3.4.1" - - rc-trigger@^2.2.0: - version "2.6.5" - resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-2.6.5.tgz#140a857cf28bd0fa01b9aecb1e26a50a700e9885" - integrity sha512-m6Cts9hLeZWsTvWnuMm7oElhf+03GOjOLfTuU0QmdB9ZrW7jR2IpI5rpNM7i9MvAAlMAmTx5Zr7g3uu/aMvZAw== - dependencies: - babel-runtime "6.x" - classnames "^2.2.6" - prop-types "15.x" - rc-align "^2.4.0" - rc-animate "2.x" - rc-util "^4.4.0" - react-lifecycles-compat "^3.0.4" - - rc-trigger@^5.0.0, rc-trigger@^5.0.4: - version "5.2.10" - resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.2.10.tgz#8a0057a940b1b9027eaa33beec8a6ecd85cce2b1" - integrity sha512-FkUf4H9BOFDaIwu42fvRycXMAvkttph9AlbCZXssZDVzz2L+QZ0ERvfB/4nX3ZFPh1Zd+uVGr1DEDeXxq4J1TA== - dependencies: - "@babel/runtime" "^7.11.2" - classnames "^2.2.6" - rc-align "^4.0.0" - rc-motion "^2.0.0" - rc-util "^5.5.0" - - rc-util@^4.0.4, rc-util@^4.15.3, rc-util@^4.4.0: - version "4.21.1" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.21.1.tgz#88602d0c3185020aa1053d9a1e70eac161becb05" - integrity sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg== - dependencies: - add-dom-event-listener "^1.1.0" - prop-types "^15.5.10" - react-is "^16.12.0" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.1.0" - - rc-util@^5.0.7, rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.18.1, rc-util@^5.3.0, rc-util@^5.5.0, rc-util@^5.6.1, rc-util@^5.7.0: - version "5.18.1" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.18.1.tgz#80bd1450b5254655d2fbea63e3d34f6871e9be79" - integrity sha512-24xaSrMZUEKh1+suDOtJWfPe9E6YrwryViZcoPO0miJTKzP4qhUlV5AAlKQ82AJilz/AOHfi3l6HoX8qa1ye8w== - dependencies: - "@babel/runtime" "^7.12.5" - react-is "^16.12.0" - shallowequal "^1.1.0" - - rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.2.tgz#1078327aa7230b5e456d679ed2ce99f3c036ebd1" - integrity sha512-OyVrrPvvFcHvV0ssz5EDZ+7Rf5qLat/+mmujjchNw5FfbJWNDwkpQ99EcVE6+FtNRmX9wFa1LGNpZLUTvp/4GQ== - dependencies: - classnames "^2.2.6" - rc-resize-observer "^1.0.0" - rc-util "^5.0.7" - - react-beautiful-dnd@13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz#ec97c81093593526454b0de69852ae433783844d" - integrity sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA== - dependencies: - "@babel/runtime" "^7.9.2" - css-box-model "^1.2.0" - memoize-one "^5.1.1" - raf-schd "^4.0.2" - react-redux "^7.2.0" - redux "^4.0.4" - use-memo-one "^1.1.1" - - react-calendar@3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-3.6.0.tgz#aec0a066439942972eb980b9f47730ba17f60eb3" - integrity sha512-hUNuPUPmiT6RGp7kZhes/yi/G9Kk1pitdzy8LShGW6wTC920HEF3hZkyZ8yT6HZNT3HPaav441i9E9pHQVrwEA== - dependencies: - "@wojtekmaj/date-utils" "^1.0.2" - get-user-locale "^1.2.0" - merge-class-names "^1.1.1" - prop-types "^15.6.0" - - react-colorful@5.5.1, react-colorful@^5.1.2: - version "5.5.1" - resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.5.1.tgz#29d9c4e496f2ca784dd2bb5053a3a4340cfaf784" - integrity sha512-M1TJH2X3RXEt12sWkpa6hLc/bbYS0H6F4rIqjQZ+RxNBstpY67d9TrFXtqdZwhpmBXcCwEi7stKqFue3ZRkiOg== - - react-copy-to-clipboard@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.4.tgz#42ec519b03eb9413b118af92d1780c403a5f19bf" - integrity sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ== - dependencies: - copy-to-clipboard "^3" - prop-types "^15.5.8" - - react-custom-scrollbars-2@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/react-custom-scrollbars-2/-/react-custom-scrollbars-2-4.4.0.tgz#6cc237abc18f5ab32b5392b336e6f072c2b4cfc1" - integrity sha512-I+oxZ9rfHfvYm85jdH2lQqpzwNr/ZAdYB8htm6R/hwRGoIEK31jq+YE6MmFwBzuO7C5zcAtH5HN9vwZxnW61NQ== - dependencies: - dom-css "^2.0.0" - prop-types "^15.5.10" - raf "^3.1.0" - - react-datepicker@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.7.0.tgz#75e03b0a6718b97b84287933307faf2ed5f03cf4" - integrity sha512-FS8KgbwqpxmJBv/bUdA42MYqYZa+fEYcpc746DZiHvVE2nhjrW/dg7c5B5fIUuI8gZET6FOzuDgezNcj568Czw== - dependencies: - "@popperjs/core" "^2.9.2" - classnames "^2.2.6" - date-fns "^2.24.0" - prop-types "^15.7.2" - react-onclickoutside "^6.12.0" - react-popper "^2.2.5" - - react-debounce-input@^3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/react-debounce-input/-/react-debounce-input-3.2.5.tgz#3a29682c4b9dcd62694d6e03f85d7bfa96cec433" - integrity sha512-WDc9nvZ8E/cT4nW1RlD/r+Nsc5Z5+Jmj2v9HT9RzsPtxkwRTQUBCKJvdt1fCYy5ME/nQPoqVYmWUWSv7whGmig== - dependencies: - lodash.debounce "^4" - prop-types "^15.7.2" - - react-dev-utils@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.0.tgz#4eab12cdb95692a077616770b5988f0adf806526" - integrity sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ== - dependencies: - "@babel/code-frame" "^7.16.0" - address "^1.1.2" - browserslist "^4.18.1" - chalk "^4.1.2" - cross-spawn "^7.0.3" - detect-port-alt "^1.1.6" - escape-string-regexp "^4.0.0" - filesize "^8.0.6" - find-up "^5.0.0" - fork-ts-checker-webpack-plugin "^6.5.0" - global-modules "^2.0.0" - globby "^11.0.4" - gzip-size "^6.0.0" - immer "^9.0.7" - is-root "^2.1.0" - loader-utils "^3.2.0" - open "^8.4.0" - pkg-up "^3.1.0" - prompts "^2.4.2" - react-error-overlay "^6.0.10" - recursive-readdir "^2.2.2" - shell-quote "^1.7.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - - react-docgen-typescript@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c" - integrity sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg== - - react-docgen@^5.0.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.4.0.tgz#2cd7236720ec2769252ef0421f23250b39a153a1" - integrity sha512-JBjVQ9cahmNlfjMGxWUxJg919xBBKAoy3hgDgKERbR+BcF4ANpDuzWAScC7j27hZfd8sJNmMPOLWo9+vB/XJEQ== - dependencies: - "@babel/core" "^7.7.5" - "@babel/generator" "^7.12.11" - "@babel/runtime" "^7.7.6" - ast-types "^0.14.2" - commander "^2.19.0" - doctrine "^3.0.0" - estree-to-babel "^3.1.0" - neo-async "^2.6.1" - node-dir "^0.1.10" - strip-indent "^3.0.0" - - react-dom@16.14.0, react-dom@17.0.2: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" - integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" - - react-draggable@^4.4.3: - version "4.4.4" - resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.4.tgz#5b26d9996be63d32d285a426f41055de87e59b2f" - integrity sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA== - dependencies: - clsx "^1.1.1" - prop-types "^15.6.0" - - react-dropzone@11.5.1: - version "11.5.1" - resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.5.1.tgz#f4d664437bf8af6acfccbf5040a9890c6780a49f" - integrity sha512-eNhttdq4ZDe3eKbXAe54Opt+sbtqmNK5NWTHf/l5d+1TdZqShJ8gMjBrya00qx5zkI//TYxRhu1d9pemTgaWwg== - dependencies: - attr-accept "^2.2.1" - file-selector "^0.2.2" - prop-types "^15.7.2" - - react-dropzone@^11.4.2: - version "11.7.1" - resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-11.7.1.tgz#3851bb75b26af0bf1b17ce1449fd980e643b9356" - integrity sha512-zxCMwhfPy1olUEbw3FLNPLhAm/HnaYH5aELIEglRbqabizKAdHs0h+WuyOpmA+v1JXn0++fpQDdNfUagWt5hJQ== - dependencies: - attr-accept "^2.2.2" - file-selector "^0.4.0" - prop-types "^15.8.1" - - react-element-to-jsx-string@^14.3.4: - version "14.3.4" - resolved "https://registry.yarnpkg.com/react-element-to-jsx-string/-/react-element-to-jsx-string-14.3.4.tgz#709125bc72f06800b68f9f4db485f2c7d31218a8" - integrity sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg== - dependencies: - "@base2/pretty-print-object" "1.0.1" - is-plain-object "5.0.0" - react-is "17.0.2" - - react-error-overlay@^6.0.10: - version "6.0.10" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6" - integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA== - - react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" - integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== - - react-flot@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/react-flot/-/react-flot-1.3.0.tgz#43d2de36f6394599d2fefb7e8d6b03d4c5620e7a" - integrity sha1-Q9LeNvY5RZnS/vt+jWsD1MViDno= - dependencies: - "@types/react" "^15.0.38" - deep-equal "^1.0.1" - jquery "^3.1.1" - - react-fps-stats@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/react-fps-stats/-/react-fps-stats-0.1.4.tgz#a7922267eeaa25cbcb402a1feed2da8d92a92eff" - integrity sha512-yEwZCuNnRoTxkss65khAANsisGGhXgdQfET98sBS631qRrvYJuWV2VWx4ndndKN2SNZDNDofAN1LCueBRIikmw== - - react-from-dom@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/react-from-dom/-/react-from-dom-0.6.1.tgz#6740f5a3d79e0c354703e5c096b8fdfe0db71b0f" - integrity sha512-7aAZx7LhRnmR51W5XtmTBYHGFl2n1AdEk1uoXLuzHa1OoGXrxOW/iwLcudvgp6BGX/l4Yh1rtMrIzvhlvbVddg== - - react-helmet-async@^1.0.7: - version "1.2.3" - resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.2.3.tgz#57326a69304ea3293036eafb49475e9ba454cb37" - integrity sha512-mCk2silF53Tq/YaYdkl2sB+/tDoPnaxN7dFS/6ZLJb/rhUY2EWGI5Xj2b4jHppScMqY45MbgPSwTxDchKpZ5Kw== - dependencies: - "@babel/runtime" "^7.12.5" - invariant "^2.2.4" - prop-types "^15.7.2" - react-fast-compare "^3.2.0" - shallowequal "^1.1.0" - - react-highlight-words@0.17.0: - version "0.17.0" - resolved "https://registry.yarnpkg.com/react-highlight-words/-/react-highlight-words-0.17.0.tgz#e79a559a2de301548339d7216264d6cd0f1eed6f" - integrity sha512-uX1Qh5IGjnLuJT0Zok234QDwRC8h4hcVMnB99Cb7aquB1NlPPDiWKm0XpSZOTdSactvnClCk8LOmVlP+75dgHA== - dependencies: - highlight-words-core "^1.2.0" - memoize-one "^4.0.0" - prop-types "^15.5.8" - - react-hook-form@7.5.3: - version "7.5.3" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.5.3.tgz#9a624fa14ec153b154891c5ebddae02ec5c2e40f" - integrity sha512-5T0mfJ4kCPKljd7t3Rgp7lML4Y2+kaZIeMdN6Zo/J7gBQ+WkrDBHOftdOtz4X+7/eqHGak5yL5evNpYdA9abVA== - - react-immutable-proptypes@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz#cce96d68cc3c18e89617cbf3092d08e35126af4a" - integrity sha512-Vf4gBsePlwdGvSZoLSBfd4HAP93HDauMY4fDjXhreg/vg6F3Fj/MXDNyTbltPC/xZKmZc+cjLu3598DdYK6sgQ== - dependencies: - invariant "^2.2.2" - - react-inlinesvg@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/react-inlinesvg/-/react-inlinesvg-2.3.0.tgz#62283c0ce7e9d11d8190ec3e89589102288830fd" - integrity sha512-fEGOdDf4k4bcveArbEpj01pJcH8pOCKLxmSj2POFdGvEk5YK0NZVnH6BXpW/PzACHPRsuh1YKAhNZyFnD28oxg== - dependencies: - exenv "^1.2.2" - react-from-dom "^0.6.0" - - react-inspector@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-5.1.1.tgz#58476c78fde05d5055646ed8ec02030af42953c8" - integrity sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg== - dependencies: - "@babel/runtime" "^7.0.0" - is-dom "^1.0.0" - prop-types "^15.0.0" - - react-is@17.0.2, react-is@^17.0.1, react-is@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - - react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.6: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - - react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - - react-modal@^3.12.1: - version "3.14.4" - resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.14.4.tgz#2ca7e8e9a180955e5c9508c228b73167c1e6f6a3" - integrity sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg== - dependencies: - exenv "^1.2.0" - prop-types "^15.7.2" - react-lifecycles-compat "^3.0.0" - warning "^4.0.3" - - react-notifications-component@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/react-notifications-component/-/react-notifications-component-3.1.0.tgz#c676b7897a3fb10c554b69dba25fe2a9da6170e2" - integrity sha512-qq+zgqVIa2zhlw+RvO2QSPk7xHLvZWTHl9VKRO56sMUef/UrcUTqOswL0DSJtRIpZYZhclquQUfDxD6H2w8aWA== - - react-onclickoutside@^6.12.0: - version "6.12.1" - resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz#92dddd28f55e483a1838c5c2930e051168c1e96b" - integrity sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q== - - react-outside-click-handler@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz#3831d541ac059deecd38ec5423f81e80ad60e115" - integrity sha512-Te/7zFU0oHpAnctl//pP3hEAeobfeHMyygHB8MnjP6sX5OR8KHT1G3jmLsV3U9RnIYo+Yn+peJYWu+D5tUS8qQ== - dependencies: - airbnb-prop-types "^2.15.0" - consolidated-events "^1.1.1 || ^2.0.0" - document.contains "^1.0.1" - object.values "^1.1.0" - prop-types "^15.7.2" - - react-popper-tooltip@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz#329569eb7b287008f04fcbddb6370452ad3f9eac" - integrity sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ== - dependencies: - "@babel/runtime" "^7.12.5" - "@popperjs/core" "^2.5.4" - react-popper "^2.2.4" - - react-popper@2.2.5, react-popper@^2.2.4, react-popper@^2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.5.tgz#1214ef3cec86330a171671a4fbcbeeb65ee58e96" - integrity sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw== - dependencies: - react-fast-compare "^3.0.1" - warning "^4.0.2" - - react-pro-sidebar@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/react-pro-sidebar/-/react-pro-sidebar-0.7.1.tgz#0b5edca0809ff6a23bda188c5db370f880690ee7" - integrity sha512-Iy1X8ce4t5Vqz4CsyzjwokGUE3/IObgmYzS0ins7/2eWKle0SMUPaWdgMKFIVjtVrMr5vmjPbRicq8FxnVaf8A== - dependencies: - "@popperjs/core" "^2.4.0" - classnames "^2.2.6" - react-slidedown "^2.4.5" - resize-observer-polyfill "^1.5.1" - - react-redux@^7.2.0, react-redux@^7.2.1: - version "7.2.6" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa" - integrity sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ== - dependencies: - "@babel/runtime" "^7.15.4" - "@types/react-redux" "^7.1.20" - hoist-non-react-statics "^3.3.2" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-is "^17.0.2" - - react-refresh@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" - integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== - - react-router-dom@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363" - integrity sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.2.1" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - - react-router-dom@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.2.1.tgz#32ec81829152fbb8a7b045bf593a22eadf019bec" - integrity sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA== - dependencies: - history "^5.2.0" - react-router "6.2.1" - - react-router@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.1.tgz#4d2e4e9d5ae9425091845b8dbc6d9d276239774d" - integrity sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - mini-create-react-context "^0.4.0" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - - react-router@6.2.1, react-router@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.2.1.tgz#be2a97a6006ce1d9123c28934e604faef51448a3" - integrity sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg== - dependencies: - history "^5.2.0" - - react-select-event@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/react-select-event/-/react-select-event-5.3.0.tgz#4548fffd615a47176951cbb301ee21a0c60b582a" - integrity sha512-Novkl7X9JJKmDV5LyYaKwl0vffWtqPrBa1vuI0v43P/f87mSA7JfdYxU93SFb99RssphVzBSIAbcnbX1w21QIQ== - dependencies: - "@testing-library/dom" ">=7" - - react-select@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.2.1.tgz#416c25c6b79b94687702374e019c4f2ed9d159d6" - integrity sha512-OOyNzfKrhOcw/BlembyGWgdlJ2ObZRaqmQppPFut1RptJO423j+Y+JIsmxkvsZ4D/3CpOmwIlCvWbbAWEdh12A== - dependencies: - "@babel/runtime" "^7.12.0" - "@emotion/cache" "^11.4.0" - "@emotion/react" "^11.1.1" - "@types/react-transition-group" "^4.4.0" - memoize-one "^5.0.0" - prop-types "^15.6.0" - react-transition-group "^4.3.0" - - react-sizeme@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-3.0.2.tgz#4a2f167905ba8f8b8d932a9e35164e459f9020e4" - integrity sha512-xOIAOqqSSmKlKFJLO3inBQBdymzDuXx4iuwkNcJmC96jeiOg5ojByvL+g3MW9LPEsojLbC6pf68zOfobK8IPlw== - dependencies: - element-resize-detector "^1.2.2" - invariant "^2.2.4" - shallowequal "^1.1.0" - throttle-debounce "^3.0.1" - - react-slidedown@^2.4.5: - version "2.4.7" - resolved "https://registry.yarnpkg.com/react-slidedown/-/react-slidedown-2.4.7.tgz#c09e72bba8aac25018fd644ece041da771854589" - integrity sha512-HGDfrqo70r1WVE0DwrySPdCT27/2wcZaJYh5kOnmuPSCtjDDJrNkDdn4Ep/cma2VVfwupeAGhbc2pbrGThU6VQ== - dependencies: - tslib "^2.0.0" - - react-svg-core@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/react-svg-core/-/react-svg-core-3.0.3.tgz#5d856efeaa4d089b0afeebe885b20b8c9500d162" - integrity sha512-Ws3eM3xCAwcaYeqm4Ajcz3zxBYNI6BeTWWhFR0cpOT+pWuVtozgHYK9xUM0S/ilapZgYMQDe49XgOxpvooFq4w== - dependencies: - "@babel/core" "^7.4.5" - "@babel/plugin-syntax-jsx" "^7.2.0" - "@babel/preset-react" "^7.0.0" - babel-plugin-react-svg "^3.0.3" - lodash.clonedeep "^4.5.0" - lodash.isplainobject "^4.0.6" - svgo "^1.2.2" - - react-svg-loader@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/react-svg-loader/-/react-svg-loader-3.0.3.tgz#8baa2d5daa32523dfd0745425ac65e0a90edae15" - integrity sha512-V1KnIUtvWVvc4xCig34n+f+/74ylMMugB2FbuAF/yq+QRi+WLi2hUYp9Ze3VylhA1D7ZgRygBh3Ojj8S3TPhJA== - dependencies: - loader-utils "^1.2.3" - react-svg-core "^3.0.3" - - react-svg-spinner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/react-svg-spinner/-/react-svg-spinner-1.0.4.tgz#32427f8987b3393cfd91c14f9b3751a67ec35546" - integrity sha512-lpOdpptU5sutxdToI5vffuWAqQDatfz1cbWa1ThEmX5fonmdH8UgoM/iAb6ToKf6iv0z+X4jZxSqDar5EtcEjQ== - dependencies: - prop-types "^15.7.2" - react "^16.0.0" - - react-syntax-highlighter@^13.5.3: - version "13.5.3" - resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz#9712850f883a3e19eb858cf93fad7bb357eea9c6" - integrity sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg== - dependencies: - "@babel/runtime" "^7.3.1" - highlight.js "^10.1.1" - lowlight "^1.14.0" - prismjs "^1.21.0" - refractor "^3.1.0" - - react-table@7.7.0: - version "7.7.0" - resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.7.0.tgz#e2ce14d7fe3a559f7444e9ecfe8231ea8373f912" - integrity sha512-jBlj70iBwOTvvImsU9t01LjFjy4sXEtclBovl3mTiqjz23Reu0DKnRza4zlLtOPACx6j2/7MrQIthIK1Wi+LIA== - - react-tabs@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.2.3.tgz#ccbb3e1241ad3f601047305c75db661239977f2f" - integrity sha512-jx325RhRVnS9DdFbeF511z0T0WEqEoMl1uCE3LoZ6VaZZm7ytatxbum0B8bCTmaiV0KsU+4TtLGTGevCic7SWg== - dependencies: - clsx "^1.1.0" - prop-types "^15.5.0" - - react-test-renderer@^16.0.0-0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae" - integrity sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg== - dependencies: - object-assign "^4.1.1" - prop-types "^15.6.2" - react-is "^16.8.6" - scheduler "^0.19.1" - - react-textarea-autosize@^8.3.0: - version "8.3.3" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8" - integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ== - dependencies: - "@babel/runtime" "^7.10.2" - use-composed-ref "^1.0.0" - use-latest "^1.0.0" - - react-transition-group@4.4.2, react-transition-group@^4.3.0: - version "4.4.2" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" - integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - - react-universal-interface@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" - integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== - - react-use@17.3.2: - version "17.3.2" - resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.3.2.tgz#448abf515f47c41c32455024db28167cb6e53be8" - integrity sha512-bj7OD0/1wL03KyWmzFXAFe425zziuTf7q8olwCYBfOeFHY1qfO1FAMjROQLsLZYwG4Rx63xAfb7XAbBrJsZmEw== - dependencies: - "@types/js-cookie" "^2.2.6" - "@xobotyi/scrollbar-width" "^1.9.5" - copy-to-clipboard "^3.3.1" - fast-deep-equal "^3.1.3" - fast-shallow-equal "^1.0.0" - js-cookie "^2.2.1" - nano-css "^5.3.1" - react-universal-interface "^0.6.2" - resize-observer-polyfill "^1.5.1" - screenfull "^5.1.0" - set-harmonic-interval "^1.0.1" - throttle-debounce "^3.0.1" - ts-easing "^0.2.0" - tslib "^2.1.0" - - react-window@1.8.6: - version "1.8.6" - resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112" - integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg== - dependencies: - "@babel/runtime" "^7.0.0" - memoize-one ">=3.1.1 <6" - - react@16.14.0, react@17.0.2, react@^16.0.0, react@^17.0.2: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - - read-cmd-shim@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" - integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== - - read-package-json-fast@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" - integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== - dependencies: - json-parse-even-better-errors "^2.3.0" - npm-normalize-package-bin "^1.0.1" - - read-package-json@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" - integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^2.0.0" - npm-normalize-package-bin "^1.0.0" - - read-package-json@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" - integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" - - read-package-json@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-4.1.1.tgz#153be72fce801578c1c86b8ef2b21188df1b9eea" - integrity sha512-P82sbZJ3ldDrWCOSKxJT0r/CXMWR0OR3KRh55SgKo3p91GSIEEC32v3lSHAvO/UcH3/IoL7uqhOFBduAnwdldw== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" - - read-package-tree@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" - integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== - dependencies: - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - util-promisify "^2.1.0" - - read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - - read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - - read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - - read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - - read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - - read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - - read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - - read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - - read@1, read@~1.0.1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= - dependencies: - mute-stream "~0.0.4" - - "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - - readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - - readable-stream@^1.1.7: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - - readdir-scoped-modules@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" - integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - graceful-fs "^4.1.2" - once "^1.3.0" - - readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - - readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - - readme-filename@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/readme-filename/-/readme-filename-1.0.0.tgz#08ec2dda26520cd16f3e836d01553f8a108efe5e" - integrity sha1-COwt2iZSDNFvPoNtAVU/ihCO/l4= - - rechoir@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" - integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== - dependencies: - resolve "^1.9.0" - - recursive-readdir@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" - integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== - dependencies: - minimatch "3.0.4" - - redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - - redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - - redux-devtools-extension@^2.13.8: - version "2.13.9" - resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz#6b764e8028b507adcb75a1cae790f71e6be08ae7" - integrity sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A== - - redux-localstorage@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/redux-localstorage/-/redux-localstorage-0.4.1.tgz#faf6d719c581397294d811473ffcedee065c933c" - integrity sha1-+vbXGcWBOXKU2BFHP/zt7gZckzw= - - redux-mock-store@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/redux-mock-store/-/redux-mock-store-1.5.4.tgz#90d02495fd918ddbaa96b83aef626287c9ab5872" - integrity sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA== - dependencies: - lodash.isplainobject "^4.0.6" - - redux-persist@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8" - integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ== - - redux-promise@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/redux-promise/-/redux-promise-0.6.0.tgz#c64723b5213bb5603c11b74302883b682e06b319" - integrity sha512-R2mGxJbPFgXyCNbFDE6LjTZhCEuACF54g1bxld3nqBhnRMX0OsUyWk77moF7UMGkUdl5WOAwc4BC5jOd1dunqQ== - dependencies: - flux-standard-action "^2.0.3" - is-promise "^2.1.0" - - redux-query-sync@^0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/redux-query-sync/-/redux-query-sync-0.1.10.tgz#e00552025d2a471d2d47c98cb7282457a0ba52be" - integrity sha512-F33z0pH7p17pNsKRAJzxOihdg5C/0CcUM8POU57a83vDPJXUXviBuuATNUI6xdhfUE3Y3gjV222EyaP7zwOktw== - dependencies: - "@ungap/url-search-params" "^0.1.2" - history "^4.8.0" - - redux-thunk@^2.3.0, redux-thunk@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.1.tgz#0dd8042cf47868f4b29699941de03c9301a75714" - integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q== - - redux@^4.0.0, redux@^4.0.4, redux@^4.0.5, redux@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" - integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== - dependencies: - "@babel/runtime" "^7.9.2" - - reflect.ownkeys@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" - integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA= - - refractor@^3.1.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.5.0.tgz#334586f352dda4beaf354099b48c2d18e0819aec" - integrity sha512-QwPJd3ferTZ4cSPPjdP5bsYHMytwWYnAN5EEnLtGvkqp/FCCnGsBgxrm9EuIDnjUC3Uc/kETtvVi7fSIVC74Dg== - dependencies: - hastscript "^6.0.0" - parse-entities "^2.0.0" - prismjs "~1.25.0" - - regenerate-unicode-properties@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" - integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== - dependencies: - regenerate "^1.4.2" - - regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - - regenerator-runtime@0.13.9, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7, regenerator-runtime@^0.13.9: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - - regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - - regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== - dependencies: - "@babel/runtime" "^7.8.4" - - regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== - dependencies: - is-equal-shallow "^0.1.3" - - regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - - regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" - integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - - regexpp@^3.1.0, regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - - regexpu-core@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" - integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.0.1" - regjsgen "^0.6.0" - regjsparser "^0.8.2" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" - - regjsgen@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" - integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== - - regjsparser@^0.8.2: - version "0.8.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" - integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== - dependencies: - jsesc "~0.5.0" - - relateurl@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - - remark-external-links@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/remark-external-links/-/remark-external-links-8.0.0.tgz#308de69482958b5d1cd3692bc9b725ce0240f345" - integrity sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA== - dependencies: - extend "^3.0.0" - is-absolute-url "^3.0.0" - mdast-util-definitions "^4.0.0" - space-separated-tokens "^1.0.0" - unist-util-visit "^2.0.0" - - remark-footnotes@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" - integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== - - remark-mdx@1.6.22: - version "1.6.22" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd" - integrity sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ== - dependencies: - "@babel/core" "7.12.9" - "@babel/helper-plugin-utils" "7.10.4" - "@babel/plugin-proposal-object-rest-spread" "7.12.1" - "@babel/plugin-syntax-jsx" "7.12.1" - "@mdx-js/util" "1.6.22" - is-alphabetical "1.0.4" - remark-parse "8.0.3" - unified "9.2.0" - - remark-parse@8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1" - integrity sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q== - dependencies: - ccount "^1.0.0" - collapse-white-space "^1.0.2" - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - is-word-character "^1.0.0" - markdown-escapes "^1.0.0" - parse-entities "^2.0.0" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - trim "0.0.1" - trim-trailing-lines "^1.0.0" - unherit "^1.0.4" - unist-util-remove-position "^2.0.0" - vfile-location "^3.0.0" - xtend "^4.0.1" - - remark-slug@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-6.1.0.tgz#0503268d5f0c4ecb1f33315c00465ccdd97923ce" - integrity sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ== - dependencies: - github-slugger "^1.0.0" - mdast-util-to-string "^1.0.0" - unist-util-visit "^2.0.0" - - remark-squeeze-paragraphs@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead" - integrity sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw== - dependencies: - mdast-squeeze-paragraphs "^4.0.0" - - remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - - renderkid@^2.0.4: - version "2.0.7" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" - integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ== - dependencies: - css-select "^4.1.3" - dom-converter "^0.2.0" - htmlparser2 "^6.1.0" - lodash "^4.17.21" - strip-ansi "^3.0.1" - - renderkid@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" - integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== - dependencies: - css-select "^4.1.3" - dom-converter "^0.2.0" - htmlparser2 "^6.1.0" - lodash "^4.17.21" - strip-ansi "^6.0.1" - - repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - - repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - - repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - - replace-in-file-webpack-plugin@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/replace-in-file-webpack-plugin/-/replace-in-file-webpack-plugin-1.0.6.tgz#eee7e139be967e8e48a0552f73037ed567b54dbd" - integrity sha512-+KRgNYL2nbc6nza6SeF+wTBNkovuHFTfJF8QIEqZg5MbwkYpU9no0kH2YU354wvY/BK8mAC2UKoJ7q+sJTvciw== - - replace-in-file@^2.0.1: - version "2.6.4" - resolved "https://registry.yarnpkg.com/replace-in-file/-/replace-in-file-2.6.4.tgz#a80e25c5c0e0efe9d04afe01a4a57ff98e8b6461" - integrity sha512-MMriy7P5/BB2f3Kp+qzSj3wrjde/5i9s9C80o2XHU3y0N1lKurMA7J4SN2UeKAWCk3/vEqSmI42vqRqH5Np9zg== - dependencies: - chalk "^2.1.0" - glob "^7.1.2" - yargs "^8.0.2" - - request-progress@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" - integrity sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4= - dependencies: - throttleit "^1.0.0" - - request@^2.55.0, request@^2.88.0, request@^2.88.2: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - - require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - - require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - - require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - - requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - - reselect@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" - integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== - - reserved-words@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1" - integrity sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE= - - resize-observer-polyfill@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" - integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== - - resolve-as-bin@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/resolve-as-bin/-/resolve-as-bin-2.1.0.tgz#25638f52e13203eae97125ab26f54082ab98c6e1" - integrity sha512-ileUuPIOP+xj+GS/d/EbB2XqRA8T2IeZTFkMggNIW2Mo72VyBMbq+HvIAxdW0ED9D44aEzJwHvUtbMm2PJT5Kw== - dependencies: - cross-spawn "^6.0.5" - - resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - - resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - - resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - - resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - - resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - - resolve-protobuf-schema@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758" - integrity sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ== - dependencies: - protocol-buffers-schema "^3.3.1" - - resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - - resolve.exports@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" - integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== - - resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2, resolve@^1.9.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== - dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - - resolve@^2.0.0-next.3: - version "2.0.0-next.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" - integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - - responselike@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723" - integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw== - dependencies: - lowercase-keys "^2.0.0" - - restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - - ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - - retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - - reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - - rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - - rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - - rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - - rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - - ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - - robust-predicates@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a" - integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g== - - rst-selector-parser@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91" - integrity sha1-gbIw6i/MYGbInjRy3nlChdmwPZE= - dependencies: - lodash.flattendeep "^4.4.0" - nearley "^2.7.10" - - rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - - rtl-css-js@^1.14.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.15.0.tgz#680ed816e570a9ebccba9e1cd0f202c6a8bb2dc0" - integrity sha512-99Cu4wNNIhrI10xxUaABHsdDqzalrSRTie4GeCmbGVuehm4oj+fIy8fTzB+16pmKe8Bv9rl+hxIBez6KxExTew== - dependencies: - "@babel/runtime" "^7.1.2" - - run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - - run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - - run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - - rw@1, rw@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" - integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q= - - rxjs@7.5.1: - version "7.5.1" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.1.tgz#af73df343cbcab37628197f43ea0c8256f54b157" - integrity sha512-KExVEeZWxMZnZhUZtsJcFwz8IvPvgu4G2Z2QyqjZQzUGr32KDYuSxrEYO4w3tFFNbfLozcrKUTvTPi+E9ywJkQ== - dependencies: - tslib "^2.1.0" - - rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - - rxjs@^7.2.0, rxjs@^7.5.1: - version "7.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.4.tgz#3d6bd407e6b7ce9a123e76b1e770dc5761aa368d" - integrity sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ== - dependencies: - tslib "^2.1.0" - - safe-buffer@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== - - safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - - safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - - safe-json-parse@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" - integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= - - safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - - "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - - sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - - sanitize.css@^11.0.1: - version "11.0.1" - resolved "https://registry.yarnpkg.com/sanitize.css/-/sanitize.css-11.0.1.tgz#e275e5e81a671adc34a8d36efd4182df0d5d4b93" - integrity sha512-Q762QXJGHIyFLayll6zUueGKslmGxNpbEDpSB/sdaZ9Xgz+v6AYlVc5P49sorc9cPR9y47npHBfXswGo1I32tg== - - sass-loader@^9.0.2: - version "9.0.3" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-9.0.3.tgz#086adcf0bfdcc9d920413e2cdc3ba3321373d547" - integrity sha512-fOwsP98ac1VMme+V3+o0HaaMHp8Q/C9P+MUazLFVi3Jl7ORGHQXL1XeRZt3zLSGZQQPC8xE42Y2WptItvGjDQg== - dependencies: - klona "^1.1.2" - loader-utils "^2.0.0" - neo-async "^2.6.2" - schema-utils "^2.7.0" - semver "^7.3.2" - - sass@^1.26.10, sass@^1.32.13: - version "1.49.8" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.8.tgz#9bbbc5d43d14862db07f1c04b786c9da9b641828" - integrity sha512-NoGOjvDDOU9og9oAxhRnap71QaTjjlzrvLnKecUJ3GxhaQBrV6e7gPuSPF28u1OcVAArVojPAe4ZhOXwwC4tGw== - dependencies: - chokidar ">=3.0.0 <4.0.0" - immutable "^4.0.0" - source-map-js ">=0.6.2 <2.0.0" - - sax@^1.2.4, sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - - saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - - scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - - schema-utils@2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" - integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== - dependencies: - "@types/json-schema" "^7.0.4" - ajv "^6.12.2" - ajv-keywords "^3.4.1" - - schema-utils@>1.0.0, schema-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" - integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== - dependencies: - "@types/json-schema" "^7.0.9" - ajv "^8.8.0" - ajv-formats "^2.1.1" - ajv-keywords "^5.0.0" - - schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - - schema-utils@^2.6.5, schema-utils@^2.7.0, schema-utils@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - - schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - - screenfull@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" - integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== - - selection-is-backward@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/selection-is-backward/-/selection-is-backward-1.0.0.tgz#97a54633188a511aba6419fc5c1fa91b467e6be1" - integrity sha1-l6VGMxiKURq6ZBn8XB+pG0Z+a+E= - - semver-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" - integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= - - "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - - semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - - semver@7.3.5, semver@7.x, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - - semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - - send@0.17.2: - version "0.17.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" - integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "1.8.1" - mime "1.6.0" - ms "2.1.3" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - - serialize-javascript@6.0.0, serialize-javascript@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" - - serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - - serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== - dependencies: - randombytes "^2.1.0" - - serve-favicon@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.5.0.tgz#935d240cdfe0f5805307fdfe967d88942a2cbcf0" - integrity sha1-k10kDN/g9YBTB/3+ln2IlCosvPA= - dependencies: - etag "~1.8.1" - fresh "0.5.2" - ms "2.1.1" - parseurl "~1.3.2" - safe-buffer "5.1.1" - - serve-static@1.14.2: - version "1.14.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" - integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.2" - - set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - - set-cookie-parser@^2.4.6: - version "2.4.8" - resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" - integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== - - set-harmonic-interval@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" - integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== - - set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - - setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - - setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - - sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - - shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - - shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - - shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - - shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - - shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - - shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - - shell-quote@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" - integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== - - side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - - signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - - simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== - - simple-get@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55" - integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== - dependencies: - decompress-response "^4.2.0" - once "^1.3.1" - simple-concat "^1.0.0" - - simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - - sirv@^1.0.7: - version "1.0.19" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" - integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ== - dependencies: - "@polka/url" "^1.0.0-next.20" - mrmime "^1.0.0" - totalist "^1.0.0" - - sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - - size-limit@^6.0.3: - version "6.0.4" - resolved "https://registry.yarnpkg.com/size-limit/-/size-limit-6.0.4.tgz#f3345206d8c25485d0d31ea41622761a3a1aad93" - integrity sha512-zo/9FrXzetvZGFJnd1LC4mR9GvirElALlerMY3EOwEGdW7Lwgl2WT0hTRC2559ZR2PGfRpnXEgAFkayGAJOebg== - dependencies: - bytes-iec "^3.1.1" - chokidar "^3.5.2" - ci-job-number "^1.2.2" - globby "^11.0.4" - lilconfig "^2.0.3" - nanospinner "^0.4.0" - picocolors "^1.0.0" - - slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - - slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - - slate-base64-serializer@^0.2.111: - version "0.2.115" - resolved "https://registry.yarnpkg.com/slate-base64-serializer/-/slate-base64-serializer-0.2.115.tgz#438e051959bde013b50507f3144257e74039ff7f" - integrity sha512-GnLV7bUW/UQ5j7rVIxCU5zdB6NOVsEU6YWsCp68dndIjSGTGLaQv2+WwV3NcnrGGZEYe5qgo33j2QWrPws2C1A== - dependencies: - isomorphic-base64 "^1.0.2" - - slate-dev-environment@^0.2.2: - version "0.2.5" - resolved "https://registry.yarnpkg.com/slate-dev-environment/-/slate-dev-environment-0.2.5.tgz#481b6906fde5becc390db7c14edf97a4bb0029f2" - integrity sha512-oLD8Fclv/RqrDv6RYfN2CRzNcRXsUB99Qgcw5L/njTjxAdDPguV6edQ3DgUG9Q2pLFLhI15DwsKClzVfFzfwGQ== - dependencies: - is-in-browser "^1.1.3" - - slate-hotkeys@^0.2.9: - version "0.2.11" - resolved "https://registry.yarnpkg.com/slate-hotkeys/-/slate-hotkeys-0.2.11.tgz#a94db117d9a98575671192329b05f23e6f485d6f" - integrity sha512-xhq/TlI74dRbO57O4ulGsvCcV4eaQ5nEEz9noZjeNLtNzFRd6lSgExRqAJqKGGIeJw+FnJ3OcqGvdb5CEc9/Ew== - dependencies: - is-hotkey "0.1.4" - slate-dev-environment "^0.2.2" - - slate-plain-serializer@0.7.10: - version "0.7.10" - resolved "https://registry.yarnpkg.com/slate-plain-serializer/-/slate-plain-serializer-0.7.10.tgz#bc4a6942cf52fde826019bb1095dffd0dac8cc08" - integrity sha512-/QvMCQ0F3NzbnuoW+bxsLIChPdRgxBjQeGhYhpRGTVvlZCLOmfDvavhN6fHsuEwkvdwOmocNF30xT1WVlmibYg== - - slate-plain-serializer@^0.7.10: - version "0.7.13" - resolved "https://registry.yarnpkg.com/slate-plain-serializer/-/slate-plain-serializer-0.7.13.tgz#6de8f5c645dd749f1b2e4426c20de74bfd213adf" - integrity sha512-TtrlaslxQBEMV0LYdf3s7VAbTxRPe1xaW10WNNGAzGA855/0RhkaHjKkQiRjHv5rvbRleVf7Nxr9fH+4uErfxQ== - - slate-prop-types@^0.5.41: - version "0.5.44" - resolved "https://registry.yarnpkg.com/slate-prop-types/-/slate-prop-types-0.5.44.tgz#da60b69c3451c3bd6cdd60a45d308eeba7e83c76" - integrity sha512-JS0iW7uaciE/W3ADuzeN1HOnSjncQhHPXJ65nZNQzB0DF7mXVmbwQKI6cmCo/xKni7XRJT0JbWSpXFhEdPiBUA== - - slate-react-placeholder@^0.2.8: - version "0.2.9" - resolved "https://registry.yarnpkg.com/slate-react-placeholder/-/slate-react-placeholder-0.2.9.tgz#30f450a05d4871c7d1a27668ebe7907861e7ca74" - integrity sha512-YSJ9Gb4tGpbzPje3eNKtu26hWM8ApxTk9RzjK+6zfD5V/RMTkuWONk24y6c9lZk0OAYNZNUmrnb/QZfU3j9nag== - - slate@0.47.8: - version "0.47.8" - resolved "https://registry.yarnpkg.com/slate/-/slate-0.47.8.tgz#1e987b74d8216d44ec56154f0e6d3c722ce21e6e" - integrity sha512-/Jt0eq4P40qZvtzeKIvNb+1N97zVICulGQgQoMDH0TI8h8B+5kqa1YeckRdRnuvfYJm3J/9lWn2V3J1PrF+hag== - dependencies: - debug "^3.1.0" - direction "^0.1.5" - esrever "^0.2.0" - is-plain-object "^2.0.4" - lodash "^4.17.4" - tiny-invariant "^1.0.1" - tiny-warning "^0.0.3" - type-of "^2.0.1" - - slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - - slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - - slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - - slide@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - - smart-buffer@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" - integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== - - snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - - snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - - snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - - socks-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" - integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== - dependencies: - agent-base "^6.0.2" - debug "4" - socks "^2.3.3" - - socks-proxy-agent@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" - integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== - dependencies: - agent-base "^6.0.2" - debug "^4.3.1" - socks "^2.6.1" - - socks@^2.3.3, socks@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" - integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== - dependencies: - ip "^1.1.5" - smart-buffer "^4.2.0" - - sort-asc@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/sort-asc/-/sort-asc-0.1.0.tgz#ab799df61fc73ea0956c79c4b531ed1e9e7727e9" - integrity sha1-q3md9h/HPqCVbHnEtTHtHp53J+k= - - sort-desc@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/sort-desc/-/sort-desc-0.1.1.tgz#198b8c0cdeb095c463341861e3925d4ee359a9ee" - integrity sha1-GYuMDN6wlcRjNBhh45JdTuNZqe4= - - sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - - sort-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" - integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== - dependencies: - is-plain-obj "^2.0.0" - - sort-object@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/sort-object/-/sort-object-0.3.2.tgz#98e0d199ede40e07c61a84403c61d6c3b290f9e2" - integrity sha1-mODRme3kDgfGGoRAPGHWw7KQ+eI= - dependencies: - sort-asc "^0.1.0" - sort-desc "^0.1.1" - - source-list-map@^2.0.0, source-list-map@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - - "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - - source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - - source-map-resolve@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" - integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - - source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - - source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - - source-map@0.5.6: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= - - source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - - source-map@^0.7.3, source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - - sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - - space-separated-tokens@^1.0.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" - integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== - - spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - - spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - - spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - - spdx-license-ids@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" - integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== - - split-on-first@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" - integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== - - split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - - split2@^3.0.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - - split@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - - sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - - sshpk@^1.14.1, sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - - ssim.js@^3.1.1: - version "3.5.0" - resolved "https://registry.yarnpkg.com/ssim.js/-/ssim.js-3.5.0.tgz#d7276b9ee99b57a5ff0db34035f02f35197e62df" - integrity sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g== - - ssri@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" - integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== - dependencies: - figgy-pudding "^3.5.1" - - ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - - stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - - stack-generator@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.5.tgz#fb00e5b4ee97de603e0773ea78ce944d81596c36" - integrity sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q== - dependencies: - stackframe "^1.1.1" - - stack-utils@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== - dependencies: - escape-string-regexp "^2.0.0" - - stackframe@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.1.tgz#1033a3473ee67f08e2f2fc8eba6aef4f845124e1" - integrity sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg== - - stacktrace-gps@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz#7688dc2fc09ffb3a13165ebe0dbcaf41bcf0c69a" - integrity sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg== - dependencies: - source-map "0.5.6" - stackframe "^1.1.1" - - stacktrace-js@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" - integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== - dependencies: - error-stack-parser "^2.0.6" - stack-generator "^2.0.5" - stacktrace-gps "^3.0.4" - - state-local@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5" - integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w== - - state-toggle@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" - integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== - - static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - - "statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - - statuses@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - - store2@^2.12.0: - version "2.13.1" - resolved "https://registry.yarnpkg.com/store2/-/store2-2.13.1.tgz#fae7b5bb9d35fc53dc61cd262df3abb2f6e59022" - integrity sha512-iJtHSGmNgAUx0b/MCS6ASGxb//hGrHHRgzvN+K5bvkBTN7A9RTpPSf1WSp+nPGvWCJ1jRnvY7MKnuqfoi3OEqg== - - stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - - stream-buffers@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-1.0.1.tgz#9a44a37555f96a5b78a5a765f0c48446cb160b8c" - integrity sha1-mkSjdVX5alt4padl8MSERssWC4w= - - stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - - stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - - stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - - streamroller@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-0.4.1.tgz#d435bd5974373abd9bd9068359513085106cc05f" - integrity sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8= - dependencies: - date-format "^0.0.0" - debug "^0.7.2" - mkdirp "^0.5.1" - readable-stream "^1.1.7" - - strict-event-emitter@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.2.0.tgz#78e2f75dc6ea502e5d8a877661065a1e2deedecd" - integrity sha512-zv7K2egoKwkQkZGEaH8m+i2D0XiKzx5jNsiSul6ja2IYFvil10A59Z9Y7PPAAe5OW53dQUf9CfsHKzjZzKkm1w== - dependencies: - events "^3.3.0" - - strict-uri-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - - string-argv@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== - - string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - - string-template@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= - - string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - - "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - - string-width@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - - string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - - "string.prototype.matchall@^4.0.0 || ^3.0.1", string.prototype.matchall@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" - side-channel "^1.0.4" - - string.prototype.padend@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz#997a6de12c92c7cb34dc8a201a6c53d9bd88a5f1" - integrity sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - string.prototype.padstart@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/string.prototype.padstart/-/string.prototype.padstart-3.1.3.tgz#4551d0117d9501692ec6000b15056ac3f816cfa5" - integrity sha512-NZydyOMtYxpTjGqp0VN5PYUF/tsU15yDMZnUdj16qRUIUiMJkHHSDElYyQFrMu+/WloTpA7MQSiADhBicDfaoA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - string.prototype.trim@^1.2.1: - version "1.2.5" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.5.tgz#a587bcc8bfad8cb9829a577f5de30dd170c1682c" - integrity sha512-Lnh17webJVsD6ECeovpVN17RlAKjmz4rF9S+8Y45CkMc/ufVpTkU3vZIyIC7sllQ1FCvObZnnCdNs/HXTUOTlg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - - string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - - string_decoder@0.10, string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - - string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - - string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - - stringify-object@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" - integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== - dependencies: - get-own-enumerable-property-symbols "^3.0.0" - is-obj "^1.0.1" - is-regexp "^1.0.0" - - strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - - strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - - strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - - strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - - strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - - strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - - strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - - strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - - strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - - strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - - strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - - strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - - strong-log-transformer@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" - integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== - dependencies: - duplexer "^0.1.1" - minimist "^1.2.0" - through "^2.3.4" - - style-loader@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" - integrity sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q== - dependencies: - loader-utils "^2.0.0" - schema-utils "^2.7.0" - - style-loader@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" - integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - - style-loader@^3.2.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" - integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== - - style-to-object@0.3.0, style-to-object@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" - integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== - dependencies: - inline-style-parser "0.1.1" - - stylehacks@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.3.tgz#2ef3de567bfa2be716d29a93bf3d208c133e8d04" - integrity sha512-ENcUdpf4yO0E1rubu8rkxI+JGQk4CgjchynZ4bDBJDfqdy+uhTRSWb8/F3Jtu+Bw5MW45Po3/aQGeIyyxgQtxg== - dependencies: - browserslist "^4.16.6" - postcss-selector-parser "^6.0.4" - - stylis@4.0.13, stylis@^4.0.6: - version "4.0.13" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== - - stylus@^0.54.8: - version "0.54.8" - resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" - integrity sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg== - dependencies: - css-parse "~2.0.0" - debug "~3.1.0" - glob "^7.1.6" - mkdirp "~1.0.4" - safer-buffer "^2.1.2" - sax "~1.2.4" - semver "^6.3.0" - source-map "^0.7.3" - - supports-color@8.1.1, supports-color@^8.0.0, supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - - supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - - supports-color@^5.3.0, supports-color@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - - supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - - supports-hyperlinks@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" - integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - - supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - - svg-url-loader@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/svg-url-loader/-/svg-url-loader-7.1.1.tgz#0cbdb30beb8679cb060c12eaf30085747fa7591f" - integrity sha512-NlsMCePODm7FQhU9aEZyGLPx5Xe1QRI1cSEUE6vTq5LJc9l9pStagvXoEIyZ9O3r00w6G3+Wbkimb+SC3DI/Aw== - dependencies: - file-loader "~6.2.0" - loader-utils "~2.0.0" - - svgo@^1.2.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - - svgo@^2.7.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" - integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^4.1.3" - css-tree "^1.1.3" - csso "^4.2.0" - picocolors "^1.0.0" - stable "^0.1.8" - - sweetalert2-react-content@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sweetalert2-react-content/-/sweetalert2-react-content-4.2.0.tgz#ab4a6e02e37150dd0ea34d00179ec76952e3f442" - integrity sha512-eB324swnq10UJH8nAH2S6GHuAKDgH6GpGU8vI+ulYdmlPzpb0T5QPc7O4RFNRx28GzVZUnfvtpxZbKtZ5/KOnQ== - - sweetalert2@^11.4.0: - version "11.4.0" - resolved "https://registry.yarnpkg.com/sweetalert2/-/sweetalert2-11.4.0.tgz#d5cb4b711af4cb5f580e4eef4389b95dbc417427" - integrity sha512-+p0jT2LxUQGreWa60j7nm1frJfqbcmamZcpZi4puEGAJ0CmyPqQ4UGmBqbB4WxkJYKsn8qcOA9ufqn0MWtQWLQ== - - symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - - symbol.prototype.description@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/symbol.prototype.description/-/symbol.prototype.description-1.0.5.tgz#d30e01263b6020fbbd2d2884a6276ce4d49ab568" - integrity sha512-x738iXRYsrAt9WBhRCVG5BtIC3B7CUkFwbHW2zOvGtwM33s7JjrCDyq8V0zgMYVb5ymsL8+qkzzpANH63CPQaQ== - dependencies: - call-bind "^1.0.2" - get-symbol-description "^1.0.0" - has-symbols "^1.0.2" - object.getownpropertydescriptors "^2.1.2" - - synchronous-promise@^2.0.15: - version "2.0.15" - resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.15.tgz#07ca1822b9de0001f5ff73595f3d08c4f720eb8e" - integrity sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg== - - systemjs@0.20.19: - version "0.20.19" - resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-0.20.19.tgz#c2b9e79c19f4bea53a19b1ed3f974ffb463be949" - integrity sha512-H/rKwNEEyej/+IhkmFNmKFyJul8tbH/muiPq5TyNoVTwsGhUjRsN3NlFnFQUvFXA3+GQmsXkCNXU6QKPl779aw== - - table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - - tapable@^0.1.8: - version "0.1.10" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" - integrity sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q= - - tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - - tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - - tar-fs@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" - integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - - tar-stream@^2.1.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - - tar@^4.4.12: - version "4.4.19" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" - integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== - dependencies: - chownr "^1.1.4" - fs-minipass "^1.2.7" - minipass "^2.9.0" - minizlib "^1.3.3" - mkdirp "^0.5.5" - safe-buffer "^5.2.1" - yallist "^3.1.1" - - tar@^6.0.2, tar@^6.1.0, tar@^6.1.11: - version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" - integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - - telejson@^5.3.2, telejson@^5.3.3: - version "5.3.3" - resolved "https://registry.yarnpkg.com/telejson/-/telejson-5.3.3.tgz#fa8ca84543e336576d8734123876a9f02bf41d2e" - integrity sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA== - dependencies: - "@types/is-function" "^1.0.0" - global "^4.4.0" - is-function "^1.0.2" - is-regex "^1.1.2" - is-symbol "^1.0.3" - isobject "^4.0.0" - lodash "^4.17.21" - memoizerific "^1.11.3" - - temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= - - temp-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" - integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== - - temp-write@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" - integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== - dependencies: - graceful-fs "^4.1.15" - is-stream "^2.0.0" - make-dir "^3.0.0" - temp-dir "^1.0.0" - uuid "^3.3.2" - - tempfile@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-3.0.0.tgz#5376a3492de7c54150d0cc0612c3f00e2cdaf76c" - integrity sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw== - dependencies: - temp-dir "^2.0.0" - uuid "^3.3.2" - - term-img@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/term-img/-/term-img-4.1.0.tgz#5b170961f7aa20b2f3b22deb8ad504beb963a8a5" - integrity sha512-DFpBhaF5j+2f7kheKFc1ajsAUUDGOaNPpKPtiIMxlbfud6mvfFZuWGnTRpaujUa5J7yl6cIw/h6nyr4mSsENPg== - dependencies: - ansi-escapes "^4.1.0" - iterm2-version "^4.1.0" - - terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - - terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - - terser-webpack-plugin@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" - integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== - dependencies: - cacache "^15.0.5" - find-cache-dir "^3.3.1" - jest-worker "^26.5.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - source-map "^0.6.1" - terser "^5.3.4" - webpack-sources "^1.4.3" - - terser-webpack-plugin@^5.0.3, terser-webpack-plugin@^5.1.3: - version "5.3.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54" - integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g== - dependencies: - jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.0" - source-map "^0.6.1" - terser "^5.7.2" - - terser@^4.1.2, terser@^4.6.3: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - - terser@^5.10.0, terser@^5.3.4, terser@^5.7.2: - version "5.11.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.11.0.tgz#2da5506c02e12cd8799947f30ce9c5b760be000f" - integrity sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A== - dependencies: - acorn "^8.5.0" - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.20" - - test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - - text-extensions@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== - - text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - - threads@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/threads/-/threads-1.7.0.tgz#d9e9627bfc1ef22ada3b733c2e7558bbe78e589c" - integrity sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ== - dependencies: - callsites "^3.1.0" - debug "^4.2.0" - is-observable "^2.1.0" - observable-fns "^0.6.1" - optionalDependencies: - tiny-worker ">= 2" - - throat@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" - integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== - - throttle-debounce@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" - integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== - - throttleit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw= - - through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - - through2@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - - through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - - timers-browserify@^2.0.4: - version "2.0.12" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== - dependencies: - setimmediate "^1.0.4" - - timezone-mock@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/timezone-mock/-/timezone-mock-1.3.1.tgz#750ca001831007be5af7456c78f350812398d947" - integrity sha512-kWK2liWUaYSLW/B2yJ6/oUbLc26cEbtIjM7BPrRxaX/3TSeqOOQfXQ6N4pNhy05ZBnUs9vywWAthiE9QYGZFwA== - - timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - - tiny-invariant@^1.0.1, tiny-invariant@^1.0.2, tiny-invariant@^1.0.6: - version "1.2.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" - integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== - - tiny-lr@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" - integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== - dependencies: - body "^5.1.0" - debug "^3.1.0" - faye-websocket "~0.10.0" - livereload-js "^2.3.0" - object-assign "^4.1.0" - qs "^6.4.0" - - tiny-warning@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-0.0.3.tgz#1807eb4c5f81784a6354d58ea1d5024f18c6c81f" - integrity sha512-r0SSA5Y5IWERF9Xh++tFPx0jITBgGggOsRLDWWew6YRw/C2dr4uNO1fw1vanrBmHsICmPyMLNBZboTlxUmUuaA== - - tiny-warning@^1.0.0, tiny-warning@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - - "tiny-worker@>= 2": - version "2.3.0" - resolved "https://registry.yarnpkg.com/tiny-worker/-/tiny-worker-2.3.0.tgz#715ae34304c757a9af573ae9a8e3967177e6011e" - integrity sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g== - dependencies: - esm "^3.2.25" - - tinycolor2@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" - integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== - - tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - - tmp@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - - tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - - to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - - to-camel-case@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46" - integrity sha1-GlYFSy+daWKYzmamCJcyK29CPkY= - dependencies: - to-space-case "^1.0.0" - - to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= - - to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - - to-no-case@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" - integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo= - - to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - - to-readable-stream@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-2.1.0.tgz#82880316121bea662cdc226adb30addb50cb06e8" - integrity sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w== - - to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - - to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - - to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - - to-space-case@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" - integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc= - dependencies: - to-no-case "^1.0.0" - - toggle-selection@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" - integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= - - toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - - totalist@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" - integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== - - tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.1.2" - - tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - - tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - - tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - - tracelib@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tracelib/-/tracelib-1.0.1.tgz#bb44ea96c19b8d7a6c85a6ee1cac9945c5b75c64" - integrity sha512-T2Vkpa/7Vdm3sV8nXRn8vZ0tnq6wlnO4Zx7Pux+JA1W6DMlg5EtbNcPZu/L7XRTPc9S0eAKhEFR4p/u0GcsDpQ== - - trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= - - trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== - - trim-trailing-lines@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0" - integrity sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ== - - trim@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= - - trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== - - "true-myth@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/true-myth/-/true-myth-5.1.2.tgz#58a425b0aefe57eed279ac2d1b65e567153ea9b0" - integrity sha512-4A8CVJiDt35EhS2U4DYoU1Kg8nMdqpC4sIc4ktan/nE3T2u5kLd7fJ1ZSQTn5xO/A41IB7DLF8R8xL6l0MPgsQ== - - ts-dedent@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" - integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== - - ts-easing@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" - integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== - - ts-essentials@^9.0.0: - version "9.1.2" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-9.1.2.tgz#46db6944b73b4cd603f3d959ef1123c16ba56f59" - integrity sha512-EaSmXsAhEiirrTY1Oaa7TSpei9dzuCuFPmjKRJRPamERYtfaGS8/KpOSbjergLz/Y76/aZlV9i/krgzsuWEBbg== - - ts-jest@^27.0.5: - version "27.1.3" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.3.tgz#1f723e7e74027c4da92c0ffbd73287e8af2b2957" - integrity sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^27.0.0" - json5 "2.x" - lodash.memoize "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "20.x" - - ts-loader@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.1.tgz#67939d5772e8a8c6bdaf6277ca023a4812da02ef" - integrity sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g== - dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" - micromatch "^4.0.0" - semver "^6.0.0" - - ts-node@^10.4.0: - version "10.5.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.5.0.tgz#618bef5854c1fbbedf5e31465cbb224a1d524ef9" - integrity sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw== - dependencies: - "@cspotcode/source-map-support" "0.7.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.0" - yn "3.1.1" - - ts-pnp@^1.1.6: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" - integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== - - tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" - integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - - tslib@2.3.1, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - - tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - - tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - - tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - - tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - - tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - - type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - - type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - - type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - - type-fest@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.10.0.tgz#7f06b2b9fbfc581068d1341ffabd0349ceafc642" - integrity sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw== - - type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== - - type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - - type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - - type-fest@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" - integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== - - type-fest@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" - integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== - - type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - - type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - - type-fest@^1.2.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" - integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== - - type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - - type-of@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/type-of/-/type-of-2.0.1.tgz#e72a1741896568e9f628378d816d6912f7f23972" - integrity sha1-5yoXQYllaOn2KDeNgW1pEvfyOXI= - - typedarray-to-buffer@3.1.5, typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - - typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - - typescript-plugin-css-modules@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/typescript-plugin-css-modules/-/typescript-plugin-css-modules-3.4.0.tgz#4ff6905d88028684d1608c05c62cb6346e5548cc" - integrity sha512-2MdjfSg4MGex1csCWRUwKD+MpgnvcvLLr9bSAMemU/QYGqBsXdez0cc06H/fFhLtRoKJjXg6PSTur3Gy1Umhpw== - dependencies: - dotenv "^10.0.0" - icss-utils "^5.1.0" - less "^4.1.1" - lodash.camelcase "^4.3.0" - postcss "^8.3.0" - postcss-filter-plugins "^3.0.1" - postcss-icss-keyframes "^0.2.1" - postcss-icss-selectors "^2.0.3" - postcss-load-config "^3.0.1" - reserved-words "^0.1.2" - sass "^1.32.13" - stylus "^0.54.8" - tsconfig-paths "^3.9.0" - - typescript@4.4.4: - version "4.4.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" - integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== - - typescript@^4.5.2: - version "4.5.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" - integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== - - uglify-js@^3.1.4: - version "3.15.1" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.1.tgz#9403dc6fa5695a6172a91bc983ea39f0f7c9086d" - integrity sha512-FAGKF12fWdkpvNJZENacOH0e/83eG6JyVQyanIJaBXCN1J11TUQv1T1/z8S+Z0CG0ZPk1nPcreF/c7lrTd0TEQ== - - uid-number@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= - - umask@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= - - unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - - unbzip2-stream@1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - - underscore@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" - integrity sha1-a7rwh3UA02vjTsqlhODbn+8DUgk= - - unfetch@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" - integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== - - unherit@^1.0.4: - version "1.1.3" - resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" - integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== - dependencies: - inherits "^2.0.0" - xtend "^4.0.0" - - unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" - integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== - - unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - - unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== - - unicode-property-aliases-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" - integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== - - unified@9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8" - integrity sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" - - union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - - unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - - unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - - unist-builder@2.0.3, unist-builder@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" - integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== - - unist-util-generated@^1.0.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" - integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== - - unist-util-is@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" - integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== - - unist-util-position@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" - integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== - - unist-util-remove-position@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" - integrity sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA== - dependencies: - unist-util-visit "^2.0.0" - - unist-util-remove@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-2.1.0.tgz#b0b4738aa7ee445c402fda9328d604a02d010588" - integrity sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q== - dependencies: - unist-util-is "^4.0.0" - - unist-util-stringify-position@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" - integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== - dependencies: - "@types/unist" "^2.0.2" - - unist-util-visit-parents@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" - integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^4.0.0" - - unist-util-visit@2.0.3, unist-util-visit@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" - integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^4.0.0" - unist-util-visit-parents "^3.0.0" - - universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - - universalify@^0.1.0, universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - - universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - - unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - - unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - - unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - - untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - - upath@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - - upath@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" - integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== - - uplot@1.6.19: - version "1.6.19" - resolved "https://registry.yarnpkg.com/uplot/-/uplot-1.6.19.tgz#98f461992a3f7f3bda7a62f4a028b8afa8da7942" - integrity sha512-s5Oab13s8zUzuZ/KiSV0GRhEvuKptAg2831fkt2PFsginIP1NSsiNrcozlc+tTPuUEAt+4rAXqX521I1DrZwEg== - - uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - - urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - - url-loader@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" - integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - - url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - - use-composed-ref@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" - integrity sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw== - - use-isomorphic-layout-effect@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" - integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ== - - use-latest@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232" - integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw== - dependencies: - use-isomorphic-layout-effect "^1.0.0" - - use-memo-one@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.2.tgz#0c8203a329f76e040047a35a1197defe342fab20" - integrity sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ== - - use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - - util-promisify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" - integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= - dependencies: - object.getownpropertydescriptors "^2.0.3" - - util.promisify@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - - util.promisify@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - - util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - - util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - - utila@~0.4: - version "0.4.0" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= - - utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - - uuid-browser@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid-browser/-/uuid-browser-3.1.0.tgz#0f05a40aef74f9e5951e20efbf44b11871e56410" - integrity sha1-DwWkCu90+eWVHiDvv0SxGHHlZBA= - - uuid@8.3.2, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - - uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - - v8-compile-cache-lib@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" - integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== - - v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - - v8-to-istanbul@^8.0.0, v8-to-istanbul@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" - integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - - validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - - validate-npm-package-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= - dependencies: - builtins "^1.0.3" - - value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - - vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - - verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - - vfile-location@^3.0.0, vfile-location@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c" - integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA== - - vfile-message@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" - integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^2.0.0" - - vfile@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" - integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^2.0.0" - vfile-message "^2.0.0" - - vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - - w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - - w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - - walker@^1.0.7, walker@~1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - - warning@^4.0.2, warning@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - - watchpack-chokidar2@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" - integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== - dependencies: - chokidar "^2.1.8" - - watchpack@^1.7.4: - version "1.7.5" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" - integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== - dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.1" - - watchpack@^2.2.0, watchpack@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" - integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - - wcwidth@^1.0.0, wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - - web-namespaces@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" - integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== - - webfont-matcher@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webfont-matcher/-/webfont-matcher-1.1.0.tgz#98ce95097b29e31fbe733053e10e571642d1c6c7" - integrity sha1-mM6VCXsp4x++czBT4Q5XFkLRxsc= - - webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - - webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - - webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - - webpack-bundle-analyzer@^4.4.2: - version "4.5.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz#1b0eea2947e73528754a6f9af3e91b2b6e0f79d5" - integrity sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ== - dependencies: - acorn "^8.0.4" - acorn-walk "^8.0.0" - chalk "^4.1.0" - commander "^7.2.0" - gzip-size "^6.0.0" - lodash "^4.17.20" - opener "^1.5.2" - sirv "^1.0.7" - ws "^7.3.1" - - webpack-cli@^4.8.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.2.tgz#77c1adaea020c3f9e2db8aad8ea78d235c83659d" - integrity sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ== - dependencies: - "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.1.1" - "@webpack-cli/info" "^1.4.1" - "@webpack-cli/serve" "^1.6.1" - colorette "^2.0.14" - commander "^7.0.0" - execa "^5.0.0" - fastest-levenshtein "^1.0.12" - import-local "^3.0.2" - interpret "^2.2.0" - rechoir "^0.7.0" - webpack-merge "^5.7.3" - - webpack-dev-middleware@^3.7.3: - version "3.7.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" - integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - - webpack-dev-middleware@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-4.3.0.tgz#179cc40795882cae510b1aa7f3710cbe93c9333e" - integrity sha512-PjwyVY95/bhBh6VUqt6z4THplYcsvQ8YNNBTBM873xLVmw8FLeALn0qurHbs9EmcfhzQis/eoqypSnZeuUz26w== - dependencies: - colorette "^1.2.2" - mem "^8.1.1" - memfs "^3.2.2" - mime-types "^2.1.30" - range-parser "^1.2.1" - schema-utils "^3.0.0" - - webpack-filter-warnings-plugin@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/webpack-filter-warnings-plugin/-/webpack-filter-warnings-plugin-1.2.1.tgz#dc61521cf4f9b4a336fbc89108a75ae1da951cdb" - integrity sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg== - - webpack-hot-middleware@^2.25.1: - version "2.25.1" - resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.25.1.tgz#581f59edf0781743f4ca4c200fd32c9266c6cf7c" - integrity sha512-Koh0KyU/RPYwel/khxbsDz9ibDivmUbrRuKSSQvW42KSDdO4w23WI3SkHpSUKHE76LrFnnM/L7JCrpBwu8AXYw== - dependencies: - ansi-html-community "0.0.8" - html-entities "^2.1.0" - querystring "^0.2.0" - strip-ansi "^6.0.0" - - webpack-livereload-plugin@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/webpack-livereload-plugin/-/webpack-livereload-plugin-3.0.2.tgz#b12f4ab56c75f03715eb32883bc2f24621f06da1" - integrity sha512-5JeZ2dgsvSNG+clrkD/u2sEiPcNk4qwCVZZmW8KpqKcNlkGv7IJjdVrq13+etAmMZYaCF1EGXdHkVFuLgP4zfw== - dependencies: - anymatch "^3.1.1" - portfinder "^1.0.17" - schema-utils ">1.0.0" - tiny-lr "^1.1.1" - - webpack-log@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" - integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== - dependencies: - ansi-colors "^3.0.0" - uuid "^3.3.2" - - webpack-merge@^5.0.9, webpack-merge@^5.7.3: - version "5.8.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" - integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== - dependencies: - clone-deep "^4.0.1" - wildcard "^2.0.0" - - webpack-plugin-hash-output@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/webpack-plugin-hash-output/-/webpack-plugin-hash-output-3.2.1.tgz#771e844ee3e94d53e116a607c20f06409113ead3" - integrity sha512-Iu4Sox3/bdiqd6TdYwZAExuH+XNbnJStPrwh6yhzOflwc/hZUP9MdiZDbFwTXrmm9ZwoXNUmvn7C0Qj4qRez2A== - dependencies: - outdent "^0.7.0" - - webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - - webpack-sources@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd" - integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA== - dependencies: - source-list-map "^2.0.1" - source-map "^0.6.1" - - webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - - webpack-virtual-modules@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz#20863dc3cb6bb2104729fff951fbe14b18bd0299" - integrity sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA== - dependencies: - debug "^3.0.0" - - webpack-virtual-modules@^0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.3.tgz#cd597c6d51d5a5ecb473eea1983a58fa8a17ded9" - integrity sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw== - - webpack@4: - version "4.46.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - - webpack@^5, webpack@^5.64.0, webpack@^5.9.0: - version "5.69.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.69.1.tgz#8cfd92c192c6a52c99ab00529b5a0d33aa848dc5" - integrity sha512-+VyvOSJXZMT2V5vLzOnDuMz5GxEqLk7hKWQ56YxPW/PQRUuKimPqmEIJOx8jHYeyo65pKbapbW464mvsKbaj4A== - dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^0.0.51" - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/wasm-edit" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - acorn "^8.4.1" - acorn-import-assertions "^1.7.6" - browserslist "^4.14.5" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.8.3" - es-module-lexer "^0.9.0" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" - json-parse-better-errors "^1.0.2" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.1.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.1.3" - watchpack "^2.3.1" - webpack-sources "^3.2.3" - - websocket-driver@>=0.5.1: - version "0.7.4" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" - integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - - websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" - integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== - - whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - - whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - - whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - - whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - - which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - - which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - - which@2.0.2, which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - - which@^1.2.9, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - - wide-align@^1.1.0, wide-align@^1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - - widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - - wildcard@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" - integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== - - word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - - wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - - worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - - worker-rpc@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" - integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== - dependencies: - microevent.ts "~0.1.1" - - workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== - - wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - - wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - - wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - - wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - - write-file-atomic@^2.0.0, write-file-atomic@^2.4.2: - version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" - integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - - write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - - write-json-file@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.3.0.tgz#2b64c8a33004d54b8698c76d585a77ceb61da32f" - integrity sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8= - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.2" - make-dir "^1.0.0" - pify "^3.0.0" - sort-keys "^2.0.0" - write-file-atomic "^2.0.0" - - write-json-file@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" - integrity sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ== - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.15" - make-dir "^2.1.0" - pify "^4.0.1" - sort-keys "^2.0.0" - write-file-atomic "^2.4.2" - - write-json-file@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" - integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== - dependencies: - detect-indent "^6.0.0" - graceful-fs "^4.1.15" - is-plain-obj "^2.0.0" - make-dir "^3.0.0" - sort-keys "^4.0.0" - write-file-atomic "^3.0.0" - - write-pkg@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-3.2.0.tgz#0e178fe97820d389a8928bc79535dbe68c2cff21" - integrity sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw== - dependencies: - sort-keys "^2.0.0" - write-json-file "^2.2.0" - - write-pkg@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" - integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== - dependencies: - sort-keys "^2.0.0" - type-fest "^0.4.1" - write-json-file "^3.2.0" - - write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - - ws@8.5.0, ws@^8.2.3: - version "8.5.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" - integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== - - ws@^7.2.0, ws@^7.3.1, ws@^7.4.6: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== - - xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - - xml-utils@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/xml-utils/-/xml-utils-1.0.2.tgz#8081bfefb87b72e03e4adbabdd217ccbbc395eeb" - integrity sha512-rEn0FvKi+YGjv9omf22oAf+0d6Ly/sgJ/CUufU/nOzS7SRLmgwSujrewc03KojXxt+aPaTRpm593TgehtUBMSQ== - - xmlbuilder@^9.0.7: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= - - xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - - xss@1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.10.tgz#5cd63a9b147a755a14cb0455c7db8866120eb4d2" - integrity sha512-qmoqrRksmzqSKvgqzN0055UFWY7OKx1/9JWeRswwEVX9fCG5jcYRxa/A2DHcmZX6VJvjzHRQ2STeeVcQkrmLSw== - dependencies: - commander "^2.20.3" - cssfilter "0.0.10" - - xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - - y18n@^3.2.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" - integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== - - y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - - y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - - yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - - yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - - yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - - yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2, yaml@^1.8.3: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - - yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - - yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.7: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - - yargs-parser@^21.0.0: - version "21.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" - integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== - - yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= - dependencies: - camelcase "^4.1.0" - - yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - - yargs@16.2.0, yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - - yargs@^17.3.0: - version "17.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" - integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.0.0" - - yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" - integrity sha1-YpmpBVsc78lp/355wdkY3Osiw2A= - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - - yauzl@^2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - - yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - - yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - - zod@^3.11.6: - version "3.11.6" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.11.6.tgz#e43a5e0c213ae2e02aefe7cb2b1a6fa3d7f1f483" - integrity sha512-daZ80A81I3/9lIydI44motWe6n59kRBfNzTuS2bfzVh1nAXi667TOTWWtatxyG+fwgNUiagSj/CWZwRRbevJIg== - - zwitch@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" - integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== diff --git a/operations/monitoring/dashboards-classic-histogram/operational.json b/operations/monitoring/dashboards-classic-histogram/operational.json new file mode 100644 index 0000000000..7cb97bb371 --- /dev/null +++ b/operations/monitoring/dashboards-classic-histogram/operational.json @@ -0,0 +1,7371 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + }, + { + "datasource": { + "uid": "$loki_datasource" + }, + "enable": true, + "expr": "{cluster=~\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=~\"$namespace\" | notes!~\".*Replicas.*\"", + "hide": false, + "iconColor": "rgba(255, 96, 96, 1)", + "name": "K8s Changes", + "showIn": 0, + "target": {} + }, + { + "datasource": { + "uid": "$loki_datasource" + }, + "enable": true, + "expr": "{cluster=~\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=~\"$namespace\" | notes=~\".*Replicas.*\"", + "hide": false, + "iconColor": "rgba(255, 96, 96, 1)", + "name": "K8s Changes(Replicas)", + "showIn": 0, + "target": {} + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\"} |= \"head successfully written to block\" | logfmt", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "Flush Events", + "tagKeys": "block_path,tenant", + "textFormat": "head successfully written to block", + "titleFormat": "Head Flush" + } + ] + }, + "description": "Bird eyes view of Pyroscope clusters", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 9933, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "title": "Global", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 1 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MBs per Tenant (Decompressed)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "cps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 7, + "y": 1 + }, + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (rate(pyroscope_distributor_received_decompressed_bytes_count{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Profiles/s per Tenant", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 5, + "x": 13, + "y": 1 + }, + "id": 24, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "increase(kube_pod_container_status_restarts_total{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m]) \u003e 0", + "hide": false, + "interval": "", + "legendFormat": "{{container}}-{{pod}}", + "refId": "B" + } + ], + "title": "Container Restarts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 18, + "y": 1 + }, + "id": 34, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"ingester\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"ingester\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Ingester Ring Status", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Distributor Ring is used for rate limiting", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 21, + "y": 1 + }, + "id": 35, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Distributor Ring Status", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "decbytes" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tenant" + }, + "properties": [ + { + "id": "custom.width", + "value": 78 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "slug" + }, + "properties": [ + { + "id": "custom.width", + "value": 132 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "org_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 142 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 5, + "x": 0, + "y": 7 + }, + "id": 85, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "count" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Value" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "\nsum by (tenant, slug, org_name, environment) (\n rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval])\n)\n", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Tenant id / name mapping", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": false, + "cluster": true + }, + "includeByName": {}, + "indexByName": { + "Time": 0, + "Value": 5, + "cluster": 1, + "org_name": 4, + "slug": 3, + "tenant": 2 + }, + "renameByName": {} + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "5xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed", + "seriesBy": "min" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "4xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 5, + "y": 7 + }, + "id": 7, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status) (\nlabel_replace(\n label_replace(\n rate(pyroscope_request_duration_seconds_count{cluster=~\"$cluster\", container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} ", + "range": true, + "refId": "A" + } + ], + "title": "Pushes/Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 11, + "y": 7 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "Push Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 31, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "showRowNums": false, + "sortBy": [] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count by (container,version) (pyroscope_build_info{cluster=~\"$cluster\",namespace=~\"$namespace\"}) or count by (container,version) (cloud_backend_gateway_build_info{cluster=~\"$cluster\",namespace=~\"$namespace\"})", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "hide": false, + "refId": "B" + } + ], + "title": "Version", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": {}, + "renameByName": { + "Value": "Pods" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "5xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed", + "seriesBy": "min" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "4xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 5, + "y": 12 + }, + "id": 6, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status) (\nlabel_replace(\n label_replace(\n rate(pyroscope_request_duration_seconds_count{cluster=~\"$cluster\", container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} ", + "range": true, + "refId": "A" + } + ], + "title": "Queries/Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 11, + "y": 12 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "Query Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 23, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 39, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (container)( count_over_time({namespace=~\"$namespace\",cluster=~\"$cluster\"} != \"stream context finished\" != \"fast-joining node failed\" != \"CAS attempt failed\" != \"memberlist TCPTransport\" |= \" panic \" or \"panic:\" or \" err=\" or \"level=error\" [$__interval]))", + "queryType": "range", + "refId": "A" + } + ], + "title": "Error \u0026 Panic rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 37, + "options": { + "dedupStrategy": "numbers", + "enableInfiniteScrolling": false, + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": true + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\"} != \"stream context finished\" != \"fast-joining node failed\" != \"CAS attempt failed\" != \"memberlist TCPTransport\" |= \" panic \" or \"panic:\" or \" err=\" or \"level=error\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "Errors and Panics", + "type": "logs" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "ts" + }, + "properties": [ + { + "id": "custom.width", + "value": 271 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "path" + }, + "properties": [ + { + "id": "custom.width", + "value": 388 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "applyToRow": false, + "mode": "gradient", + "type": "color-background", + "wrapText": false + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "from": 200, + "result": { + "color": "light-green", + "index": 0 + }, + "to": 399 + }, + "type": "range" + }, + { + "options": { + "from": 400, + "result": { + "color": "light-yellow", + "index": 1 + }, + "to": 499 + }, + "type": "range" + }, + { + "options": { + "from": 500, + "result": { + "color": "light-red", + "index": 2 + }, + "to": 599 + }, + "type": "range" + } + ] + }, + { + "id": "custom.width", + "value": 96 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "traceID" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Show trace", + "url": "/explore?schemaVersion=1\u0026panes=%7B%22xbp%22:%7B%22datasource%22:%22grafanacloud-traces%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22grafanacloud-traces%22%7D,%22queryType%22:%22traceql%22,%22limit%22:20,%22tableType%22:%22traces%22,%22metricsQueryType%22:%22range%22,%22query%22:%22${__value.text}%5Cn%22%7D%5D,%22range%22:%7B%22from%22:%22${__from}%22,%22to%22:%22${__to}%22%7D%7D%7D\u0026orgId=1" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 108, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "status" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "direction": "backward", + "editorMode": "code", + "expr": "{namespace=~\"$namespace\", cluster=~\"$cluster\", container=\"cortex-gw\"} |= `msg=\"request timings\"` | logfmt", + "queryType": "range", + "refId": "A" + } + ], + "title": "Query Activity", + "transformations": [ + { + "id": "extractFields", + "options": { + "delimiter": ",", + "format": "json", + "replace": true, + "source": "labels" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "__adaptive_logs_sampled__": true, + "caller": true, + "cluster": true, + "conn_send": false, + "container": true, + "detected_level": true, + "downstream": false, + "insight": true, + "job": true, + "level": true, + "msg": true, + "name": true, + "namespace": true, + "path": false, + "pod_template_hash": true, + "service_name": true, + "stream": true, + "total": false + }, + "includeByName": {}, + "indexByName": { + "__adaptive_logs_sampled__": 22, + "auth": 7, + "caller": 8, + "cluster": 9, + "conn_send": 25, + "container": 10, + "dashboard_id": 24, + "detected_level": 11, + "downstream": 26, + "grafana_username": 5, + "insight": 12, + "job": 13, + "level": 14, + "msg": 15, + "name": 16, + "namespace": 17, + "panel_id": 27, + "path": 1, + "pod": 18, + "pod_template_hash": 19, + "query_hash": 23, + "service_name": 20, + "status": 2, + "stream": 21, + "total": 6, + "traceID": 3, + "ts": 0, + "user": 4 + }, + "renameByName": { + "auth": "", + "caller": "", + "path": "", + "total": "", + "user": "tenant_id" + } + } + }, + { + "id": "convertFieldType", + "options": { + "conversions": [], + "fields": {} + } + } + ], + "type": "table" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 52, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 53, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 54, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 73, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 74, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 96, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/ingester\", cluster=~\"$cluster\",route=~\".*push.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/ingester\", cluster=~\"$cluster\",route=~\".*push.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/ingester\", cluster=~\"$cluster\",route=~\".*push.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "Push Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "5xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed", + "seriesBy": "min" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "4xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 69, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status) (\nlabel_replace(\n label_replace(\n rate(pyroscope_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"$namespace/ingester\", route=~\".*push.*\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} ", + "range": true, + "refId": "A" + } + ], + "title": "Pushes/Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 23 + }, + "id": 83, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (count_over_time({cluster=~\"$cluster\",namespace=~\"$namespace\"} |= \"upload new block\" | logfmt [$__interval]))", + "queryType": "range", + "refId": "A" + } + ], + "title": "Block Uploaded Per Tenant", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 84, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (count_over_time({cluster=~\"$cluster\",namespace=~\"$namespace\"} |= \"cut row group segment\" | logfmt [$__interval]))", + "hide": true, + "queryType": "range", + "refId": "A" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (sum_over_time({cluster=~\"$cluster\",namespace=~\"$namespace\"} |= \"cut row group segment\" | logfmt | unwrap numProfiles [$__interval]))", + "hide": false, + "queryType": "range", + "refId": "B" + } + ], + "title": "Profiles Flushed to disk", + "type": "timeseries" + } + ], + "title": "Ingesters", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 41, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 50 + }, + "id": 43, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10,sum by (tenant, reason) (rate(pyroscope_discarded_samples_total{cluster=~\"$cluster\",namespace=~\"$namespace\"}[1m])))", + "legendFormat": "{{ tenant }} - {{ reason }}", + "range": true, + "refId": "A" + } + ], + "title": "Discarded Profiles", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 45, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "showRowNums": false + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(10, sum by (tenant, reason) (sum_over_time(increase(pyroscope_discarded_samples_total{cluster=~\"$cluster\",namespace=~\"$namespace\"}[1m])[$__range:1m])))", + "format": "table", + "instant": true, + "legendFormat": "{{ tenant }} - {{ reason }}", + "range": false, + "refId": "A" + } + ], + "title": "Discarded Profiles Per Interval", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": { + "Time": 0, + "Value": 3, + "reason": 2, + "tenant": 1 + }, + "renameByName": { + "Value": "Profiles", + "reason": "Reason", + "tenant": "Tenant" + } + } + } + ], + "type": "table" + } + ], + "title": "Tenant Limits", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 42 + }, + "id": 47, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 4 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 50, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 12 + }, + "id": 71, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 12 + }, + "id": 72, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 63, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (rate(pyroscope_distributor_received_compressed_bytes_count{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Profiles /s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 62, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (rate(pyroscope_distributor_received_samples_sum{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Stacktrace Sample /s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 65, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Throughput Decompressed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (rate(pyroscope_distributor_received_samples_bytes_sum{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Throughput Samples Decompressed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 67, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (rate(pyroscope_distributor_received_symbols_bytes_sum{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Throughput Symbols Decompressed", + "type": "timeseries" + } + ], + "title": "Distributors", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 91, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/query-frontend\", cluster=~\"$cluster\",route=~\".*render.*|.*querier.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/query-frontend\", cluster=~\"$cluster\",route=~\".*render.*|.*querier.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/query-frontend\", cluster=~\"$cluster\",route=~\".*render.*|.*querier.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "API Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/2../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/5../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/4../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "shades" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 101, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status,route) (\nlabel_replace(\n label_replace(\n rate(pyroscope_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"$namespace/query-frontend\", route=~\".*render.*|.*querier.*\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} {{route}}", + "range": true, + "refId": "A" + } + ], + "title": "Request Rates", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 92, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 88, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 94, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 90, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 60, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": true + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\",container=\"query-frontend\"} |= \"http.go\" |~ \"QuerierService|pyroscope|render\" | logfmt | line_format \"tenant={{.orgID}} traceID={{.traceID}} {{.msg}}\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "Queries", + "type": "logs" + } + ], + "title": "Query Frontend", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 56, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 87, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 58, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 75, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 76, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + } + ], + "title": "Queriers", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 102, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 103, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 93, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + } + ], + "title": "Query Scheduler", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 46 + }, + "id": 86, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 98, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/store-gateway\", cluster=~\"$cluster\",route=~\".*store.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/store-gateway\", cluster=~\"$cluster\",route=~\".*store.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{job=~\"$namespace/store-gateway\", cluster=~\"$cluster\",route=~\".*store.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "API Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/2../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/5../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/4../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "shades" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 99, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status,route) (\nlabel_replace(\n label_replace(\n rate(pyroscope_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"$namespace/store-gateway\", route=~\".*store.*\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} {{route}}", + "range": true, + "refId": "A" + } + ], + "title": "Request Rates", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 104, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 89, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 95, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + } + ], + "title": "Store Gateway", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 78, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "get" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 58 + }, + "id": 80, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(operation) (rate(objstore_bucket_operations_total{namespace=~\"$namespace\",cluster=~\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bucket Operation /s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 58 + }, + "id": 81, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(objstore_bucket_operation_duration_seconds{namespace=~\"$namespace\",cluster=~\"$cluster\"}[$__rate_interval])) by (operation))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Latencies per Operation", + "type": "timeseries" + } + ], + "title": "Object Storage", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 105, + "panels": [], + "title": "GitHub API", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 49 + }, + "id": 106, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.99, sum by (le, route) (rate(pyroscope_vcs_github_request_duration_bucket{cluster=~\"$cluster\", namespace=~\"$namespace\", container=\"querier\"} [$__rate_interval])))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "GitHub API (P99)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 49 + }, + "id": 107, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (route, status_code) (rate(pyroscope_vcs_github_request_duration_count{cluster=~\"$cluster\", namespace=~\"$namespace\", container=\"querier\"} [$__rate_interval]))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "GitHub API (P99)", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "30s", + "schemaVersion": 41, + "tags": [ + "pyroscope" + ], + "templating": { + "list": [ + { + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "includeAll": false, + "label": "Data Source", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "current": { + "text": "Loki-Ops", + "value": "c-R8UWvVk" + }, + "includeAll": false, + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "label_values(pyroscope_build_info,cluster)", + "includeAll": true, + "label": "cluster", + "multi": true, + "name": "cluster", + "options": [], + "query": { + "labelFilters": [], + "query": "label_values(pyroscope_build_info,cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "current": { + "text": [ + "default" + ], + "value": [ + "default" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "includeAll": true, + "label": "namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": { + "labelFilters": [], + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Pyroscope / Operational", + "version": 14 +} \ No newline at end of file diff --git a/operations/monitoring/dashboards-classic-histogram/v2-metastore.json b/operations/monitoring/dashboards-classic-histogram/v2-metastore.json new file mode 100644 index 0000000000..8eeac6e765 --- /dev/null +++ b/operations/monitoring/dashboards-classic-histogram/v2-metastore.json @@ -0,0 +1,4168 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{cluster=\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=\"$namespace\"", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "K8s Changes", + "tagKeys": "type,name_extracted,verb", + "textFormat": "{{notes}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} != \"Preemption is not helpful\" != \"Failed deploy model\" | logfmt | type=\"Warning\"", + "hide": false, + "iconColor": "orange", + "instant": false, + "name": "K8s Warnings", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt | type!=\"Normal\" | type!=\"Warning\"", + "hide": false, + "iconColor": "red", + "instant": false, + "name": "K8s Errors", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt", + "hide": false, + "iconColor": "blue", + "instant": false, + "name": "K8s All Events", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 12198, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 71, + "panels": [], + "title": "Raft", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Raft node roles observed by each node. The view is not meant to be 100% consistent, and only serves monitoring purposes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisPlacement": "auto", + "fillOpacity": 15, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 1, + "spanNulls": false + }, + "fieldMinMax": false, + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Follower" + }, + "to": 99 + }, + "type": "range" + }, + { + "options": { + "from": 100, + "result": { + "color": "dark-red", + "index": 1, + "text": "Leader" + }, + "to": 1000000 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": 0 + }, + { + "color": "light-red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 81, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.8, + "showValue": "never", + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (pod) (\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Follower\"} or\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Leader\"} * 100\n)", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "D" + } + ], + "title": "Raft Nodes", + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of raft commands observed by the metastore leader", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 68, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.995, sum(rate(pyroscope_metastore_raft_apply_command_duration_seconds_bucket{\n namespace=\"$namespace\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + } + ], + "title": "Command Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of raft read index observed by the metastore nodes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 72, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_metastore_raft_read_index_wait_duration_seconds_bucket{\n namespace=\"$namespace\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + } + ], + "title": "ReadIndex Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The time takes to write a snapshot", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 78, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(0.99,(sum by (le, pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "{{pod}} Leader", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(0.99,(sum by (le, pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state!=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "{{pod}} Follower", + "range": true, + "refId": "A" + } + ], + "title": "Snapshot Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The size of BoltDB snapshot taken by FSM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 9 + }, + "id": 77, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "pyroscope_metastore_boltdb_persist_snapshot_size_bytes{namespace=\"$namespace\"}", + "hide": false, + "instant": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Snapshot Size", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The time takes to apply the command onto FSM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 79, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds_bucket{namespace=\"$namespace\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds_bucket{namespace=\"$namespace\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "FSM Latency", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 51, + "panels": [], + "title": "Metadata Index Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of AddBlock endpoint observed by metastore nodes\n\nThe only user is the segment-writer service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 18 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(1,(sum by (le, pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "Metastore leader snapshot ({{pod}})", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "AddBlock Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 18 + }, + "id": 95, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 18 + }, + "id": 50, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of GetBlockMetadata endpoint observed by metastore nodes.\n\nThe only user is the compaction-worker service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 26 + }, + "id": 75, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\",\n}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\",\n}[$__rate_interval])) by (le))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "GetBlockMetadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 26 + }, + "id": 99, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\"\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 26 + }, + "id": 76, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 89, + "panels": [], + "title": "Metadata Query Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadata endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 90, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])) by (le))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 98, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 92, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadataLabels endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 43 + }, + "id": 91, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])) by (le))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadataLabels Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 43 + }, + "id": 96, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 43 + }, + "id": 93, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 51 + }, + "id": 86, + "panels": [], + "title": "Compaction Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of PollCompactionJobs endpoint observed by metastore nodes.\n\nThe only user is the compaction-worker service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 52 + }, + "id": 87, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval])) by (le))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "PollCompactionJobs Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 52 + }, + "id": 97, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 52 + }, + "id": 88, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 60 + }, + "id": 67, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 61 + }, + "id": 65, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\",container=\"metastore\"})", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 61 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(container_memory_working_set_bytes{namespace=\"$namespace\", container=\"metastore\", image!=\"\"}) by (pod)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Requests", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Limit", + "range": true, + "refId": "C" + } + ], + "title": "Memory Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 61 + }, + "id": 84, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "kubelet_volume_stats_used_bytes{namespace=\"$namespace\",persistentvolumeclaim=~\".*metastore.*\"} /\nkubelet_volume_stats_capacity_bytes{namespace=\"$namespace\",persistentvolumeclaim=~\".*metastore.*\"}", + "hide": false, + "legendFormat": "{{persistentvolumeclaim}}", + "range": true, + "refId": "C" + } + ], + "title": "Disk Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 0, + "y": 69 + }, + "id": 85, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(operation) (rate(objstore_bucket_operations_total{namespace=\"$namespace\",container=\"metastore\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Storage I/O", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 6, + "y": 69 + }, + "id": 82, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*metastore.*\"}) by (namespace,pod)) * -1", + "hide": false, + "legendFormat": "tx {{pod}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*metastore.*\"}) by (namespace,pod))", + "hide": false, + "legendFormat": "rx {{pod}}", + "range": true, + "refId": "B" + } + ], + "title": "Network", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 12, + "y": 69 + }, + "id": 83, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_fs_writes_total{namespace=\"$namespace\",container=\"metastore\"}[$__rate_interval])) * -1", + "format": "time_series", + "hide": false, + "legendFormat": "write {{pod}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_fs_reads_total{namespace=\"$namespace\",container=\"metastore\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "read {{pod}}", + "range": true, + "refId": "B" + } + ], + "title": "Disk I/O", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 18, + "y": 69 + }, + "id": 94, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "irate(node_disk_io_time_seconds_total{cluster=\"$cluster\"}[$__rate_interval])\n+ on(instance, device) group_left(pod)\ntopk by(instance, device) (\n 1,\n 0 * label_replace(\n container_blkio_device_usage_total{\n cluster=\"$cluster\",\n namespace=\"$namespace\",\n container=\"metastore\",\n operation=\"Write\",\n },\n \"device\", \"$1\", \"device\", \"/dev/(.*)\"\n )\n)\n", + "hide": false, + "legendFormat": "{{pod}}/{{device}}", + "range": true, + "refId": "A" + } + ], + "title": "Disk I/O Wait", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 60, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "Number of OS threads created", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 113 + }, + "id": 61, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "go_threads{namespace=\"$namespace\",container=\"metastore\"}", + "hide": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Go Threads", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 113 + }, + "id": 62, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_goroutines{namespace=\"$namespace\",container=\"metastore\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Goroutines", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 113 + }, + "id": 63, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_memstats_heap_inuse_bytes{namespace=\"$namespace\",container=\"metastore\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Heap In-Use", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 113 + }, + "id": 64, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_file_descriptors{namespace=\"$namespace\",container=\"metastore\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "File Descriptors", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Runtime", + "type": "row" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [ + "pyroscope", + "pyroscope-v2" + ], + "templating": { + "list": [ + { + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "includeAll": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Grafana Logging", + "value": "000000193" + }, + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "pyroscope-dev", + "value": "pyroscope-dev" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "label": "cluster", + "name": "cluster", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "allowCustomValue": false, + "current": { + "text": "default", + "value": "default" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "label": "namespace", + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Pyroscope v2 / Metastore" +} \ No newline at end of file diff --git a/operations/monitoring/dashboards-classic-histogram/v2-read-path.json b/operations/monitoring/dashboards-classic-histogram/v2-read-path.json new file mode 100644 index 0000000000..cf91e3aeef --- /dev/null +++ b/operations/monitoring/dashboards-classic-histogram/v2-read-path.json @@ -0,0 +1,3491 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{cluster=\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=\"$namespace\"", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "K8s Changes", + "tagKeys": "type,name_extracted,verb", + "textFormat": "{{notes}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} != \"Preemption is not helpful\" != \"Failed deploy model\" | logfmt | type=\"Warning\"", + "hide": false, + "iconColor": "orange", + "instant": false, + "name": "K8s Warnings", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt | type!=\"Normal\" | type!=\"Warning\"", + "hide": false, + "iconColor": "red", + "instant": false, + "name": "K8s Errors", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt", + "hide": false, + "iconColor": "blue", + "instant": false, + "name": "K8s All events", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 12593, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 68, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "description": "SelectMergeProfile filtered out by default as the API is used by Canary Exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pod" + }, + "properties": [ + { + "id": "custom.width", + "value": 280 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "orgID" + }, + "properties": [ + { + "id": "custom.width", + "value": 86 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "uri" + }, + "properties": [ + { + "id": "custom.width", + "value": 312 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.width", + "value": 179 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trace ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 318 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Endpoint" + }, + "properties": [ + { + "id": "custom.width", + "value": 420 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Pod" + }, + "properties": [ + { + "id": "custom.width", + "value": 379 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "route" + }, + "properties": [ + { + "id": "custom.width", + "value": 347 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Route" + }, + "properties": [ + { + "id": "custom.width", + "value": 363 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 69, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Time" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "direction": "backward", + "editorMode": "code", + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\",container=\"query-frontend\"}\n|= \"route=/querier.v1.\"\n| logfmt | line_format \"tenant={{.orgID}} status={{.status}} duration={{.duration}} traceID={{.traceID}} {{.uri}}\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "All Queries", + "transformations": [ + { + "id": "extractFields", + "options": { + "delimiter": ",", + "format": "json", + "keepTime": false, + "replace": false, + "source": "labels" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Drone build for Grafana": true, + "Drone build for Grafana Enterprise": true, + "Line": true, + "Okta Logs": true, + "Profile TraceID": true, + "TraceID (json)": true, + "__adaptive_logs_sampled__": true, + "app_kubernetes_io_component": true, + "app_kubernetes_io_instance": true, + "app_kubernetes_io_name": true, + "caller": true, + "cluster": true, + "container": true, + "debug": true, + "detected_level": true, + "id": true, + "job": true, + "labelTypes": true, + "labels": true, + "level": true, + "method": true, + "msg": true, + "name": true, + "pod_template_hash": true, + "request_body_size": true, + "service_name": true, + "status": false, + "stream": true, + "test_run_id": true, + "traceID": true, + "traceID (label)": true, + "traceID 1": true, + "trace_id (labels)": true, + "ts": true, + "tsNs": true + }, + "includeByName": {}, + "indexByName": { + "Drone build for Grafana": 30, + "Drone build for Grafana Enterprise": 31, + "Line": 4, + "Time": 1, + "TraceID (json)": 8, + "TraceID (log line)": 29, + "app_kubernetes_io_component": 11, + "app_kubernetes_io_instance": 12, + "app_kubernetes_io_name": 13, + "caller": 14, + "cluster": 15, + "container": 16, + "detected_level": 17, + "duration": 18, + "id": 7, + "job": 19, + "labelTypes": 6, + "labels": 0, + "level": 20, + "msg": 21, + "name": 22, + "namespace": 24, + "pod": 23, + "pod_template_hash": 25, + "route": 3, + "service_name": 26, + "stream": 27, + "tenant": 2, + "test_run_id": 10, + "traceID": 9, + "traceID (label)": 32, + "trace_id (labels)": 33, + "ts": 28, + "tsNs": 5 + }, + "renameByName": { + "Line": "", + "Time": "", + "TraceID": "Trace ID", + "duration": "Duration", + "labels": "", + "namespace": "Namespace", + "orgID": "Tenant", + "pod": "Pod", + "pod_template_hash": "", + "route": "Route", + "status": "Status", + "tenant": "Tenant", + "uri": "Endpoint" + } + } + } + ], + "transparent": true, + "type": "table" + }, + { + "datasource": { + "type": "tempo", + "uid": "${tempo_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto", + "wrapText": false + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Trace Name" + }, + "properties": [ + { + "id": "custom.width", + "value": 455 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trace ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 311 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 70, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Start time" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "tempo", + "uid": "${tempo_datasource}" + }, + "filters": [ + { + "id": "d5be7410", + "operator": "=", + "scope": "resource", + "tag": "k8s.namespace.name", + "value": [ + "$namespace" + ], + "valueType": "string" + }, + { + "id": "service-name", + "operator": "=", + "scope": "resource", + "tag": "service.name", + "value": [ + "pyroscope-query-frontend", + "pyroscope-query-backend" + ], + "valueType": "string" + }, + { + "id": "min-duration", + "operator": "\u003e", + "tag": "duration", + "value": "100ms", + "valueType": "duration" + }, + { + "id": "span-name", + "operator": "!=", + "scope": "span", + "tag": "name", + "value": [ + "HTTP GET - debug_pprof" + ], + "valueType": "string" + } + ], + "limit": 25, + "metricsQueryType": "instant", + "queryType": "traceqlSearch", + "refId": "A", + "spss": 5, + "tableType": "traces" + } + ], + "title": "Traces", + "transparent": true, + "type": "table" + } + ], + "title": "Query Log", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 57, + "panels": [], + "title": "Metadata Query Service (metastore)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Raft node roles observed by each node. The view is not meant to be 100% consistent, and only serves monitoring purposes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisPlacement": "auto", + "fillOpacity": 15, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 1, + "spanNulls": false + }, + "fieldMinMax": false, + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Follower" + }, + "to": 99 + }, + "type": "range" + }, + { + "options": { + "from": 100, + "result": { + "color": "dark-red", + "index": 1, + "text": "Leader" + }, + "to": 1000000 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": 0 + }, + { + "color": "light-red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 54, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.8, + "showValue": "never", + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (pod) (\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Follower\"} or\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Leader\"} * 100\n)", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "D" + } + ], + "title": "Raft Nodes", + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadata endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 2 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadataLabels endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 2 + }, + "id": 55, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadataLabels Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The size of BoltDB snapshot taken by FSM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 60, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "pyroscope_metastore_boltdb_persist_snapshot_size_bytes{namespace=\"$namespace\"}", + "hide": false, + "instant": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Snapshot Size", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 9 + }, + "id": 58, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 9 + }, + "id": 59, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 63, + "panels": [], + "title": "Query Frontend", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Query rate observed by cortex-gw", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 1, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 67, + "options": { + "dataLinks": [], + "legend": { + "calcs": [ + "max", + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": true, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status_code) (rate(pyroscope_request_duration_seconds_count{cluster=~\"$cluster\", container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[5m]))", + "legendFormat": "{{status_code}} ", + "range": true, + "refId": "A" + } + ], + "title": "Query rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Query duration observed by cortex-gw", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (le, route) ( rate(pyroscope_request_duration_seconds_bucket{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Query Duartion", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 61, + "panels": [], + "title": "Query Backend", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Number of query-backend invocations.\n\nErrors are expected: usually those indicate that the query is throttled with the concurrency limiter.\n\nIf errors are presents in the query-frontend/gateway, the query is failed.\n", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 27 + }, + "id": 64, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Invocations", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "QueryBackend.Invoke latency observed by query-backend instances", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 27 + }, + "id": 62, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "Invocation Duration", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "QueryBackend.Invokeduration observed by query-backend instances", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 27 + }, + "id": 71, + "options": { + "calculate": false, + "cellGap": 0, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Rainbow", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum (rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n status_code=\"success\"\n}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + } + ], + "title": "Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 27 + }, + "id": 65, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Breakdown", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 32, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 36 + }, + "id": 29, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-query-backend\"}\n)", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-query-backend\"}\n)", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 36 + }, + "id": 72, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "Total", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(kube_pod_container_resource_requests{namespace=\"$namespace\", resource=\"cpu\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage (stack)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Request" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 30, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(container_memory_working_set_bytes{namespace=\"$namespace\", container=\"query-backend\", image!=\"\"}) by (pod)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(kube_pod_container_resource_requests{namespace=\"$namespace\", resource=\"memory\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max (kube_pod_container_resource_limits{namespace=\"$namespace\", resource=\"memory\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "C" + } + ], + "title": "Memory Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 31, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(operation) (irate(objstore_bucket_operations_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Storage I/O", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 44 + }, + "id": 53, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-backend.*\"}) by (namespace,pod)) * -1", + "hide": false, + "legendFormat": "tx {{pod}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-backend.*\"}) by (namespace,pod))", + "hide": false, + "legendFormat": "rx {{pod}}", + "range": true, + "refId": "B" + } + ], + "title": "Network", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 52 + }, + "id": 43, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "Number of OS threads created", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 155 + }, + "id": 48, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "go_threads{namespace=\"$namespace\",container=\"query-backend\"}", + "hide": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Go Threads", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 155 + }, + "id": 46, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_goroutines{namespace=\"$namespace\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Goroutines", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 155 + }, + "id": 44, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_memstats_heap_inuse_bytes{namespace=\"$namespace\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Heap In-Use", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 155 + }, + "id": 45, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_file_descriptors{namespace=\"$namespace\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "File Descriptors", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Runtime", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 53 + }, + "id": 42, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "OP27Xzxnk" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 156 + }, + "id": 41, + "options": { + "dedupStrategy": "none", + "enableInfiniteScrolling": false, + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "OP27Xzxnk" + }, + "direction": "backward", + "editorMode": "code", + "expr": "{cluster=\"$cluster\", namespace=\"$namespace\", container=\"query-backend\"} |= \"level=err\" or \"level=warn\" or \"panic\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "Worker log", + "transparent": true, + "type": "logs" + } + ], + "title": "Errors and warnings", + "type": "row" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [ + "pyroscope", + "pyroscope-v2" + ], + "templating": { + "list": [ + { + "allowCustomValue": true, + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "label": "metrics", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Grafana Logging", + "value": "000000193" + }, + "description": "", + "label": "logs", + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Tempo Ops (tempo-ops-01)", + "value": "fds8vtxx3ao74b" + }, + "description": "", + "label": "traces", + "name": "tempo_datasource", + "options": [], + "query": "tempo", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "pyroscope-dev", + "value": "pyroscope-dev" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "label": "cluster", + "name": "cluster", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "allowCustomValue": false, + "current": { + "text": "default", + "value": "default" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "label": "namespace", + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Pyroscope v2 / Read Path" +} \ No newline at end of file diff --git a/operations/monitoring/dashboards-classic-histogram/v2-write-path.json b/operations/monitoring/dashboards-classic-histogram/v2-write-path.json new file mode 100644 index 0000000000..566d76b92c --- /dev/null +++ b/operations/monitoring/dashboards-classic-histogram/v2-write-path.json @@ -0,0 +1,5026 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{cluster=\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=\"$namespace\"", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "K8s Changes", + "tagKeys": "type,name_extracted,verb", + "textFormat": "{{notes}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} != \"Preemption is not helpful\" != \"Failed deploy model\" | logfmt | type=\"Warning\"", + "hide": false, + "iconColor": "orange", + "instant": false, + "name": "K8s Warnings", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt | type!=\"Normal\" | type!=\"Warning\"", + "hide": false, + "iconColor": "red", + "instant": false, + "name": "K8s Errors", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt", + "hide": false, + "iconColor": "blue", + "instant": false, + "name": "K8s All Events", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 0, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 85, + "panels": [], + "title": "", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "footer": { + "reducers": [ + "countAll" + ] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "decbytes" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tenant" + }, + "properties": [ + { + "id": "custom.width", + "value": 78 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "slug" + }, + "properties": [ + { + "id": "custom.width", + "value": 132 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "org_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 142 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "lcd", + "type": "gauge", + "valueDisplayMode": "text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slug" + }, + "properties": [ + { + "id": "custom.width", + "value": 89 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Name" + }, + "properties": [ + { + "id": "custom.width", + "value": 143 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 104 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 68, + "options": { + "cellHeight": "sm", + "enablePagination": false, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Value" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "\nsum by (tenant, slug, org_name, environment) (\n rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval])\n)\n", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Tenants", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": false, + "cluster": true, + "environment": true, + "slug": false + }, + "includeByName": {}, + "indexByName": { + "Time": 0, + "Value": 4, + "environment": 5, + "org_name": 3, + "slug": 2, + "tenant": 1 + }, + "renameByName": { + "Time": "", + "Value": "", + "environment": "Env", + "org_name": "Name", + "slug": "Slug", + "tenant": "ID" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MBs per Tenant (Decompressed)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 4, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "cps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 67, + "options": { + "legend": { + "calcs": [ + "mean", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Mean", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (rate(pyroscope_distributor_received_decompressed_bytes_count{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Profiles/s per Tenant", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 82, + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Distributor Ring", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The ring is used by distributor to discover segment-writer instances. ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 81, + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"segment-writer\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"segment-writer\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Segment Writer Ring", + "type": "piechart" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 90, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency observed by distributor, indicating the overall write path latency.\n\nOnly successful requests are counted.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "dark-red", + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 1, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "p99 overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 34 + }, + "id": 94, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (le, pod) (rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*pusher.*|.*ingest.*\",\n status_code=\"200\",\n}[$__rate_interval])))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*pusher.*|.*ingest.*\",\n status_code=\"200\",\n}[$__rate_interval])) by (le))", + "hide": true, + "legendFormat": "p99 overall", + "range": true, + "refId": "A" + } + ], + "title": "Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 34 + }, + "id": 93, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*push.*|.*ingest.*\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 34 + }, + "id": 42, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status_code) (rate(\n pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*push.*|.*ingest.*\",\n }[1m])\n)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency observed by distributors (write path router), broken down by instance.\n\nLatencies are expected to be distributed evenly across instances. An outlier here likely indicates a neighborhood issue.\n\nOnly successful requests are counted.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 72, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_write_path_downstream_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n status=\"200\",\n primary=\"1\",\n}[$__rate_interval])) by (le, route,pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 primary {{pod}} =\u003e {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_write_path_downstream_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n status=\"200\",\n primary!=\"1\",\n}[$__rate_interval])) by (le, route,pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 secondary {{pod}} =\u003e {{route}}", + "range": true, + "refId": "B" + } + ], + "title": "Downstream Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency observed by the segment-writer client", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 56, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_write_path_downstream_request_duration_seconds{\n namespace=\"$namespace\",\n route=\"segment-writer\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 95, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_write_path_downstream_request_duration_seconds_count{\n namespace=\"$namespace\",\n primary=\"1\",\n}[$__rate_interval])) by (status,route)", + "instant": false, + "legendFormat": "primary {{route}} {{status}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_write_path_downstream_request_duration_seconds_count{\n namespace=\"$namespace\",\n primary=\"0\",\n}[$__rate_interval])) by (status,route)", + "hide": false, + "instant": false, + "legendFormat": "secondary {{route}} {{status}}", + "range": true, + "refId": "C" + } + ], + "title": "Downstream Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 50 + }, + "id": 97, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_memory_working_set_bytes{namespace=\"$namespace\",container=\"distributor\"})", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\", container=\"distributor\"})", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 50 + }, + "id": 62, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\",container=\"distributor\"})", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-distributor\"}\n)", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-distributor\"}\n)", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The chart showd distribution of requests from the upstream (cortex-gw/envoy)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 50 + }, + "id": 98, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (rate(\n pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*push.*|.*ingest.*\",\n }[1m])\n)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Upstream Distribution", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Distributor", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 47, + "panels": [], + "title": "Segment Writer", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of the Push endpoint observed by segment-writer.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Overall p99" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 27 + }, + "id": 79, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99 overall", + "range": true, + "refId": "Overall p99" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.90, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p90 overall", + "range": true, + "refId": "Overall p90" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p50 overall", + "range": true, + "refId": "Overall p50" + } + ], + "title": "Push Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency of the Push endpoint observed by segment-writer", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 27 + }, + "id": 76, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"segment-writer\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 27 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])) by (status_code)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Push Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency segment-writer observes when uploading segments to object store, including retries.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Overall p99" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99 overall", + "range": true, + "refId": "Overall p99" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.90, sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p90 overall", + "range": true, + "refId": "Overall p90" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p50 overall", + "range": true, + "refId": "Overall p50" + } + ], + "title": "Object Store Upload Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency of upload calls observed by the segment-writer", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 80, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "New objects created by segment-writer", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Hedged requests" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 59, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (rate(pyroscope_segment_writer_upload_duration_seconds_count{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (rate(pyroscope_segment_writer_hedged_upload_duration_seconds_count{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "{{status}} (hedged)", + "range": true, + "refId": "B" + } + ], + "title": "Object Store Upload Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency segment-writer observes when adding metadata entries to metastore, including retries.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Overall p99" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 43 + }, + "id": 77, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le, pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99 overall", + "range": true, + "refId": "Overall p99" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.90, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p90 overall", + "range": true, + "refId": "Overall p90" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p50 overall", + "range": true, + "refId": "Overall p50" + } + ], + "title": "Store Metadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency segment-writer observes when adding metadata entries, including retries", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 43 + }, + "id": 78, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "New metadata entries created by segment-writers", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 43 + }, + "id": 73, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (rate(pyroscope_segment_writer_store_metadata_duration_seconds_count{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (rate(pyroscope_segment_writer_store_metadata_dql{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "{{status}} (DLQ)", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_segment_writer_store_metadata_dlq{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "dlq", + "range": true, + "refId": "C" + } + ], + "title": "Store Metadata Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 51 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(pyroscope_segment_writer_segment_ingest_bytes_sum{namespace=\"$namespace\", container=\"segment-writer\"}[10m])) /\nsum by (pod) (rate(container_cpu_usage_seconds_total{namespace=\"$namespace\", container=\"segment-writer\"}[10m]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Processing Rate (MB/sec/core)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 51 + }, + "id": 63, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-segment-writer\"}\n)", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-segment-writer\"}\n)", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 51 + }, + "id": 27, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Mean", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "Total", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage (stack)", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 59 + }, + "id": 51, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of raft commands observed by the metastore leader", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisPlacement": "auto", + "fillOpacity": 15, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 1, + "spanNulls": false + }, + "fieldMinMax": false, + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Follower" + }, + "to": 99 + }, + "type": "range" + }, + { + "options": { + "from": 100, + "result": { + "color": "dark-red", + "index": 1, + "text": "Leader" + }, + "to": 1000000 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": 0 + }, + { + "color": "light-red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 106 + }, + "id": 65, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.8, + "showValue": "never", + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (pod) (\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Follower\"} or\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Leader\"} * 100\n)", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "D" + } + ], + "title": "Raft Nodes", + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of AddBlock endpoint observed by metastore nodes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 111 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(0.99,(sum by (le, pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "Metastore leader snapshot ({{pod}})", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds_bucket{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])) by (le))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 111 + }, + "id": 50, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds_count{\n namespace=\"$namespace\",\n method=\"gRPC\",\n container=\"metastore\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "{{status_code}}", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Metastore", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 60 + }, + "id": 22, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 3, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 17, + "x": 0, + "y": 69 + }, + "id": 44, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (dataset, tenant) (\n pyroscope_adaptive_placement_dataset_shard_limit{namespace=\"$namespace\"}\n) \u003e 1", + "legendFormat": "{{tenant}}/{{dataset}}", + "range": true, + "refId": "A" + } + ], + "title": "Dataset Shards", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Top-10", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 3, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 7, + "x": 17, + "y": 69 + }, + "id": 107, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, count by (tenant) (sum by (dataset, tenant) (\n pyroscope_adaptive_placement_dataset_shard_limit{namespace=\"$namespace\"}\n)))", + "legendFormat": "{{tenant}}", + "range": true, + "refId": "A" + } + ], + "title": "Datasets per tenant", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 23, + "options": { + "calculate": false, + "cellGap": 0, + "cellValues": { + "unit": "Bps" + }, + "color": { + "exponent": 0.5, + "fill": "red", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Rainbow", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto", + "value": "Shard" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisLabel": "Shard", + "axisPlacement": "right", + "reverse": true, + "unit": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (shard) (rate(pyroscope_segment_writer_client_sent_bytes_sum{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Distributed Bytes (per shard)", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 89 + }, + "id": 64, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (shard) (rate(pyroscope_segment_writer_client_sent_bytes_sum{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Distributed Bytes (per shard)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 89 + }, + "id": 26, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (shard) (rate(pyroscope_segment_writer_client_sent_bytes_sum{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Distributed Bytes (per shard, stack)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 98 + }, + "id": 24, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (rate(pyroscope_segment_writer_segment_ingest_bytes_sum{namespace=\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ingested Bytes (per node)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 98 + }, + "id": 34, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (rate(pyroscope_segment_writer_segment_ingest_bytes_sum{namespace=\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Ingested Bytes (per node, stack)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 107 + }, + "id": 35, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (rate(pyroscope_segment_writer_segment_ingest_bytes_count{namespace=\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ingested Profiles (per node)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 107 + }, + "id": 36, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (rate(pyroscope_segment_writer_segment_ingest_bytes_count{namespace=\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ingested Profiles (per node, stack)", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Data Distribution", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 86, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 168 + }, + "id": 87, + "options": { + "groupByField": "container", + "labelFields": [ + "container", + "instance_type" + ], + "textField": "instance_type", + "tiling": "treemapSquarify" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count by (instance_type, container) (\n rate(container_cpu_usage_seconds_total{\n cluster=\"$cluster\",\n namespace=\"$namespace\",\n container=~\"segment-writer|distributor|cortex-gw|metastore|compaction-worker\",\n }[$__rate_interval]) + on (instance) group_left(instance_type) (0 * label_replace(\n karpenter_nodes_allocatable{cluster=\"$cluster\", resource_type=\"cpu\"}, \"instance\", \"$1\", \"node_name\", \"(.*)\")\n )\n)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "{{instance_type}}", + "range": false, + "refId": "A" + } + ], + "title": "AWS | Intances By Machine Type", + "transparent": true, + "type": "marcusolsson-treemap-panel" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 168 + }, + "id": 84, + "options": { + "legend": { + "calcs": [ + "mean", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "avg by (instance_type, container) (\n rate(container_cpu_usage_seconds_total{\n cluster=\"$cluster\",\n namespace=\"$namespace\",\n container=~\"segment-writer|distributor|cortex-gw\",\n }[$__rate_interval]) + on (instance) group_left(instance_type) (0 * label_replace(\n karpenter_nodes_allocatable{cluster=\"$cluster\", resource_type=\"cpu\"}, \"instance\", \"$1\", \"node_name\", \"(.*)\")\n )\n)", + "hide": false, + "legendFormat": "{{container}}/{{instance_type}}", + "range": true, + "refId": "A" + } + ], + "title": "AWS | Average CPU Usage By Type", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Resource Allocation", + "type": "row" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [ + "pyroscope", + "pyroscope-v2" + ], + "templating": { + "list": [ + { + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "includeAll": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Grafana Logging", + "value": "000000193" + }, + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "pyroscope-dev", + "value": "pyroscope-dev" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "label": "cluster", + "name": "cluster", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "allowCustomValue": false, + "current": { + "text": "default", + "value": "default" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "label": "namespace", + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "type": "query" + }, + { + "baseFilters": [], + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "filters": [], + "name": "Filters", + "type": "adhoc" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Pyroscope v2 / Write Path" +} \ No newline at end of file diff --git a/operations/monitoring/dashboards/operational.json b/operations/monitoring/dashboards/operational.json new file mode 100644 index 0000000000..48cbeaceac --- /dev/null +++ b/operations/monitoring/dashboards/operational.json @@ -0,0 +1,7371 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + }, + { + "datasource": { + "uid": "$loki_datasource" + }, + "enable": true, + "expr": "{cluster=~\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=~\"$namespace\" | notes!~\".*Replicas.*\"", + "hide": false, + "iconColor": "rgba(255, 96, 96, 1)", + "name": "K8s Changes", + "showIn": 0, + "target": {} + }, + { + "datasource": { + "uid": "$loki_datasource" + }, + "enable": true, + "expr": "{cluster=~\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=~\"$namespace\" | notes=~\".*Replicas.*\"", + "hide": false, + "iconColor": "rgba(255, 96, 96, 1)", + "name": "K8s Changes(Replicas)", + "showIn": 0, + "target": {} + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\"} |= \"head successfully written to block\" | logfmt", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "Flush Events", + "tagKeys": "block_path,tenant", + "textFormat": "head successfully written to block", + "titleFormat": "Head Flush" + } + ] + }, + "description": "Bird eyes view of Pyroscope clusters", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 9933, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "title": "Global", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 1 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval])))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MBs per Tenant (Decompressed)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "cps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 7, + "y": 1 + }, + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (histogram_count(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Profiles/s per Tenant", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 5, + "x": 13, + "y": 1 + }, + "id": 24, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "increase(kube_pod_container_status_restarts_total{cluster=~\"$cluster\", namespace=~\"$namespace\"}[10m]) \u003e 0", + "hide": false, + "interval": "", + "legendFormat": "{{container}}-{{pod}}", + "refId": "B" + } + ], + "title": "Container Restarts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 18, + "y": 1 + }, + "id": 34, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"ingester\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"ingester\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Ingester Ring Status", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Distributor Ring is used for rate limiting", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 21, + "y": 1 + }, + "id": 35, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Distributor Ring Status", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "decbytes" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tenant" + }, + "properties": [ + { + "id": "custom.width", + "value": 78 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "slug" + }, + "properties": [ + { + "id": "custom.width", + "value": 132 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "org_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 142 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 5, + "x": 0, + "y": 7 + }, + "id": 85, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "count" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Value" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "\nsum by (tenant, slug, org_name, environment) (\n histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval]))\n)\n", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Tenant id / name mapping", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": false, + "cluster": true + }, + "includeByName": {}, + "indexByName": { + "Time": 0, + "Value": 5, + "cluster": 1, + "org_name": 4, + "slug": 3, + "tenant": 2 + }, + "renameByName": {} + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "5xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed", + "seriesBy": "min" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "4xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 5, + "y": 7 + }, + "id": 7, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status) (\nlabel_replace(\n label_replace(\n histogram_count(rate(pyroscope_request_duration_seconds{cluster=~\"$cluster\", container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} ", + "range": true, + "refId": "A" + } + ], + "title": "Pushes/Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 11, + "y": 7 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (route) ( rate(pyroscope_request_duration_seconds{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (route) ( rate(pyroscope_request_duration_seconds{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (route) ( rate(pyroscope_request_duration_seconds{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*ingest.*|.*pusher.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "Push Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 31, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "showHeader": true, + "showRowNums": false, + "sortBy": [] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count by (container,version) (pyroscope_build_info{cluster=~\"$cluster\",namespace=~\"$namespace\"}) or count by (container,version) (cloud_backend_gateway_build_info{cluster=~\"$cluster\",namespace=~\"$namespace\"})", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "hide": false, + "refId": "B" + } + ], + "title": "Version", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": {}, + "renameByName": { + "Value": "Pods" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "5xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed", + "seriesBy": "min" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "4xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 5, + "y": 12 + }, + "id": 6, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status) (\nlabel_replace(\n label_replace(\n histogram_count(rate(pyroscope_request_duration_seconds{cluster=~\"$cluster\", container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} ", + "range": true, + "refId": "A" + } + ], + "title": "Queries/Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 11, + "y": 12 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (route) ( rate(pyroscope_request_duration_seconds{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (route) ( rate(pyroscope_request_duration_seconds{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (route) ( rate(pyroscope_request_duration_seconds{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "Query Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 23, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 39, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (container)( count_over_time({namespace=~\"$namespace\",cluster=~\"$cluster\"} != \"stream context finished\" != \"fast-joining node failed\" != \"CAS attempt failed\" != \"memberlist TCPTransport\" |= \" panic \" or \"panic:\" or \" err=\" or \"level=error\" [$__interval]))", + "queryType": "range", + "refId": "A" + } + ], + "title": "Error \u0026 Panic rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 37, + "options": { + "dedupStrategy": "numbers", + "enableInfiniteScrolling": false, + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": true + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\"} != \"stream context finished\" != \"fast-joining node failed\" != \"CAS attempt failed\" != \"memberlist TCPTransport\" |= \" panic \" or \"panic:\" or \" err=\" or \"level=error\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "Errors and Panics", + "type": "logs" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "ts" + }, + "properties": [ + { + "id": "custom.width", + "value": 271 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "path" + }, + "properties": [ + { + "id": "custom.width", + "value": 388 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "applyToRow": false, + "mode": "gradient", + "type": "color-background", + "wrapText": false + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "from": 200, + "result": { + "color": "light-green", + "index": 0 + }, + "to": 399 + }, + "type": "range" + }, + { + "options": { + "from": 400, + "result": { + "color": "light-yellow", + "index": 1 + }, + "to": 499 + }, + "type": "range" + }, + { + "options": { + "from": 500, + "result": { + "color": "light-red", + "index": 2 + }, + "to": 599 + }, + "type": "range" + } + ] + }, + { + "id": "custom.width", + "value": 96 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "traceID" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Show trace", + "url": "/explore?schemaVersion=1\u0026panes=%7B%22xbp%22:%7B%22datasource%22:%22grafanacloud-traces%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22grafanacloud-traces%22%7D,%22queryType%22:%22traceql%22,%22limit%22:20,%22tableType%22:%22traces%22,%22metricsQueryType%22:%22range%22,%22query%22:%22${__value.text}%5Cn%22%7D%5D,%22range%22:%7B%22from%22:%22${__from}%22,%22to%22:%22${__to}%22%7D%7D%7D\u0026orgId=1" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 108, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "status" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "direction": "backward", + "editorMode": "code", + "expr": "{namespace=~\"$namespace\", cluster=~\"$cluster\", container=\"cortex-gw\"} |= `msg=\"request timings\"` | logfmt", + "queryType": "range", + "refId": "A" + } + ], + "title": "Query Activity", + "transformations": [ + { + "id": "extractFields", + "options": { + "delimiter": ",", + "format": "json", + "replace": true, + "source": "labels" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "__adaptive_logs_sampled__": true, + "caller": true, + "cluster": true, + "conn_send": false, + "container": true, + "detected_level": true, + "downstream": false, + "insight": true, + "job": true, + "level": true, + "msg": true, + "name": true, + "namespace": true, + "path": false, + "pod_template_hash": true, + "service_name": true, + "stream": true, + "total": false + }, + "includeByName": {}, + "indexByName": { + "__adaptive_logs_sampled__": 22, + "auth": 7, + "caller": 8, + "cluster": 9, + "conn_send": 25, + "container": 10, + "dashboard_id": 24, + "detected_level": 11, + "downstream": 26, + "grafana_username": 5, + "insight": 12, + "job": 13, + "level": 14, + "msg": 15, + "name": 16, + "namespace": 17, + "panel_id": 27, + "path": 1, + "pod": 18, + "pod_template_hash": 19, + "query_hash": 23, + "service_name": 20, + "status": 2, + "stream": 21, + "total": 6, + "traceID": 3, + "ts": 0, + "user": 4 + }, + "renameByName": { + "auth": "", + "caller": "", + "path": "", + "total": "", + "user": "tenant_id" + } + } + }, + { + "id": "convertFieldType", + "options": { + "conversions": [], + "fields": {} + } + } + ], + "type": "table" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 52, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 53, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 54, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 73, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 74, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*ingester.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 96, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/ingester\", cluster=~\"$cluster\",route=~\".*push.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/ingester\", cluster=~\"$cluster\",route=~\".*push.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/ingester\", cluster=~\"$cluster\",route=~\".*push.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "Push Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "5xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed", + "seriesBy": "min" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "4xx " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 69, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status) (\nlabel_replace(\n label_replace(\n histogram_count(rate(pyroscope_request_duration_seconds{cluster=~\"$cluster\", job=~\"$namespace/ingester\", route=~\".*push.*\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} ", + "range": true, + "refId": "A" + } + ], + "title": "Pushes/Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 23 + }, + "id": 83, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (count_over_time({cluster=~\"$cluster\",namespace=~\"$namespace\"} |= \"upload new block\" | logfmt [$__interval]))", + "queryType": "range", + "refId": "A" + } + ], + "title": "Block Uploaded Per Tenant", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 84, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (count_over_time({cluster=~\"$cluster\",namespace=~\"$namespace\"} |= \"cut row group segment\" | logfmt [$__interval]))", + "hide": true, + "queryType": "range", + "refId": "A" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (sum_over_time({cluster=~\"$cluster\",namespace=~\"$namespace\"} |= \"cut row group segment\" | logfmt | unwrap numProfiles [$__interval]))", + "hide": false, + "queryType": "range", + "refId": "B" + } + ], + "title": "Profiles Flushed to disk", + "type": "timeseries" + } + ], + "title": "Ingesters", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 41, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 50 + }, + "id": 43, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10,sum by (tenant, reason) (rate(pyroscope_discarded_samples_total{cluster=~\"$cluster\",namespace=~\"$namespace\"}[1m])))", + "legendFormat": "{{ tenant }} - {{ reason }}", + "range": true, + "refId": "A" + } + ], + "title": "Discarded Profiles", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 45, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "showRowNums": false + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(10, sum by (tenant, reason) (sum_over_time(increase(pyroscope_discarded_samples_total{cluster=~\"$cluster\",namespace=~\"$namespace\"}[1m])[$__range:1m])))", + "format": "table", + "instant": true, + "legendFormat": "{{ tenant }} - {{ reason }}", + "range": false, + "refId": "A" + } + ], + "title": "Discarded Profiles Per Interval", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": { + "Time": 0, + "Value": 3, + "reason": 2, + "tenant": 1 + }, + "renameByName": { + "Value": "Profiles", + "reason": "Reason", + "tenant": "Tenant" + } + } + } + ], + "type": "table" + } + ], + "title": "Tenant Limits", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 42 + }, + "id": 47, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 4 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 50, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 12 + }, + "id": 71, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 12 + }, + "id": 72, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*distributor.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 63, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (histogram_count(rate(pyroscope_distributor_received_compressed_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Profiles /s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 62, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (histogram_sum(rate(pyroscope_distributor_received_samples{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Stacktrace Sample /s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 65, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Throughput Decompressed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (histogram_sum(rate(pyroscope_distributor_received_samples_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Throughput Samples Decompressed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 16, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 67, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (type) (histogram_sum(rate(pyroscope_distributor_received_symbols_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Throughput Symbols Decompressed", + "type": "timeseries" + } + ], + "title": "Distributors", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 91, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/query-frontend\", cluster=~\"$cluster\",route=~\".*render.*|.*querier.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/query-frontend\", cluster=~\"$cluster\",route=~\".*render.*|.*querier.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/query-frontend\", cluster=~\"$cluster\",route=~\".*render.*|.*querier.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "API Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/2../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/5../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/4../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "shades" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 101, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status,route) (\nlabel_replace(\n label_replace(\n histogram_count(rate(pyroscope_request_duration_seconds{cluster=~\"$cluster\", job=~\"$namespace/query-frontend\", route=~\".*render.*|.*querier.*\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} {{route}}", + "range": true, + "refId": "A" + } + ], + "title": "Request Rates", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 92, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 88, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 94, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 90, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-frontend.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 60, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": true + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "editorMode": "code", + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\",container=\"query-frontend\"} |= \"http.go\" |~ \"QuerierService|pyroscope|render\" | logfmt | line_format \"tenant={{.orgID}} traceID={{.traceID}} {{.msg}}\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "Queries", + "type": "logs" + } + ], + "title": "Query Frontend", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 56, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 87, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 58, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 75, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 76, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*querier.*\", workload_type=\"deployment\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + } + ], + "title": "Queriers", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 102, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 103, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 93, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-scheduler\", workload_type=\"deployment\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + } + ], + "title": "Query Scheduler", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 46 + }, + "id": 86, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 98, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/store-gateway\", cluster=~\"$cluster\",route=~\".*store.*\"}[$__rate_interval])))", + "legendFormat": ".99 {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.75, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/store-gateway\", cluster=~\"$cluster\",route=~\".*store.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".75 {{route}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by (route) ( rate(pyroscope_request_duration_seconds{job=~\"$namespace/store-gateway\", cluster=~\"$cluster\",route=~\".*store.*\"}[$__rate_interval])))", + "hide": true, + "legendFormat": ".5 {{route}}", + "range": true, + "refId": "C" + } + ], + "title": "API Latencies", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/2../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/5../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "shades" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/4../" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "shades" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 99, + "options": { + "dataLinks": [], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status,route) (\nlabel_replace(\n label_replace(\n histogram_count(rate(pyroscope_request_duration_seconds{cluster=~\"$cluster\", job=~\"$namespace/store-gateway\", route=~\".*store.*\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n\"status\", \"${1}\", \"status_code\", \"([a-z]+)\")\n)", + "legendFormat": "{{status}} {{route}}", + "range": true, + "refId": "A" + } + ], + "title": "Request Rates", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"$cluster\", namespace=~\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 104, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n container_memory_working_set_bytes{cluster=~\"$cluster\", namespace=~\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n) by (pod)\n", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "instant": false, + "legendFormat": "request", + "range": true, + "refId": "request" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", cluster=~\"$cluster\", namespace=~\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway\", workload_type=\"statefulset\"}\n)", + "hide": false, + "legendFormat": "limit", + "range": true, + "refId": "limit" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 89, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 13, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 95, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*store-gateway.*\", workload_type=\"statefulset\"}) by (pod))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + } + ], + "title": "Store Gateway", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 78, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "get" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 58 + }, + "id": 80, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(operation) (rate(objstore_bucket_operations_total{namespace=~\"$namespace\",cluster=~\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bucket Operation /s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 58 + }, + "id": 81, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(objstore_bucket_operation_duration_seconds{namespace=~\"$namespace\",cluster=~\"$cluster\"}[$__rate_interval])) by (operation))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Latencies per Operation", + "type": "timeseries" + } + ], + "title": "Object Storage", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 105, + "panels": [], + "title": "GitHub API", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 49 + }, + "id": 106, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.99, sum by (route) (rate(pyroscope_vcs_github_request_duration{cluster=~\"$cluster\", namespace=~\"$namespace\", container=\"querier\"} [$__rate_interval])))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "GitHub API (P99)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 49 + }, + "id": 107, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (route, status_code) (histogram_count(rate(pyroscope_vcs_github_request_duration{cluster=~\"$cluster\", namespace=~\"$namespace\", container=\"querier\"} [$__rate_interval])))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "GitHub API (P99)", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "30s", + "schemaVersion": 41, + "tags": [ + "pyroscope" + ], + "templating": { + "list": [ + { + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "includeAll": false, + "label": "Data Source", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "current": { + "text": "Loki-Ops", + "value": "c-R8UWvVk" + }, + "includeAll": false, + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "label_values(pyroscope_build_info,cluster)", + "includeAll": true, + "label": "cluster", + "multi": true, + "name": "cluster", + "options": [], + "query": { + "labelFilters": [], + "query": "label_values(pyroscope_build_info,cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "current": { + "text": [ + "default" + ], + "value": [ + "default" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "includeAll": true, + "label": "namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": { + "labelFilters": [], + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Pyroscope / Operational", + "version": 14 +} \ No newline at end of file diff --git a/operations/monitoring/dashboards/v2-metastore.json b/operations/monitoring/dashboards/v2-metastore.json new file mode 100644 index 0000000000..f1ed89cdeb --- /dev/null +++ b/operations/monitoring/dashboards/v2-metastore.json @@ -0,0 +1,4168 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{cluster=\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=\"$namespace\"", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "K8s Changes", + "tagKeys": "type,name_extracted,verb", + "textFormat": "{{notes}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} != \"Preemption is not helpful\" != \"Failed deploy model\" | logfmt | type=\"Warning\"", + "hide": false, + "iconColor": "orange", + "instant": false, + "name": "K8s Warnings", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt | type!=\"Normal\" | type!=\"Warning\"", + "hide": false, + "iconColor": "red", + "instant": false, + "name": "K8s Errors", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt", + "hide": false, + "iconColor": "blue", + "instant": false, + "name": "K8s All Events", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 12198, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 71, + "panels": [], + "title": "Raft", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Raft node roles observed by each node. The view is not meant to be 100% consistent, and only serves monitoring purposes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisPlacement": "auto", + "fillOpacity": 15, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 1, + "spanNulls": false + }, + "fieldMinMax": false, + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Follower" + }, + "to": 99 + }, + "type": "range" + }, + { + "options": { + "from": 100, + "result": { + "color": "dark-red", + "index": 1, + "text": "Leader" + }, + "to": 1000000 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": 0 + }, + { + "color": "light-red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 81, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.8, + "showValue": "never", + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (pod) (\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Follower\"} or\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Leader\"} * 100\n)", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "D" + } + ], + "title": "Raft Nodes", + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of raft commands observed by the metastore leader", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 68, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.995, sum(rate(pyroscope_metastore_raft_apply_command_duration_seconds{\n namespace=\"$namespace\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + } + ], + "title": "Command Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of raft read index observed by the metastore nodes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 72, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_metastore_raft_read_index_wait_duration_seconds{\n namespace=\"$namespace\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + } + ], + "title": "ReadIndex Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The time takes to write a snapshot", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 78, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(0.99,(sum by (pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "{{pod}} Leader", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(0.99,(sum by (pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state!=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "{{pod}} Follower", + "range": true, + "refId": "A" + } + ], + "title": "Snapshot Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The size of BoltDB snapshot taken by FSM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 9 + }, + "id": 77, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "pyroscope_metastore_boltdb_persist_snapshot_size_bytes{namespace=\"$namespace\"}", + "hide": false, + "instant": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Snapshot Size", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The time takes to apply the command onto FSM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 79, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "FSM Latency", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 51, + "panels": [], + "title": "Metadata Index Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of AddBlock endpoint observed by metastore nodes\n\nThe only user is the segment-writer service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 18 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(1,(sum by (pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "Metastore leader snapshot ({{pod}})", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "AddBlock Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 18 + }, + "id": 95, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 18 + }, + "id": 50, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of GetBlockMetadata endpoint observed by metastore nodes.\n\nThe only user is the compaction-worker service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 26 + }, + "id": 75, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\",\n}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\",\n}[$__rate_interval])))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "GetBlockMetadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 26 + }, + "id": 99, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\"\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 26 + }, + "id": 76, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/GetBlockMetadata\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 89, + "panels": [], + "title": "Metadata Query Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadata endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 90, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 98, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 92, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadataLabels endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 43 + }, + "id": 91, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadataLabels Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 43 + }, + "id": 96, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 43 + }, + "id": 93, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 51 + }, + "id": 86, + "panels": [], + "title": "Compaction Service", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of PollCompactionJobs endpoint observed by metastore nodes.\n\nThe only user is the compaction-worker service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 52 + }, + "id": 87, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval])))", + "hide": true, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "PollCompactionJobs Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 52 + }, + "id": 97, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 52 + }, + "id": 88, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.CompactionService/PollCompactionJobs\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 60 + }, + "id": 67, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 61 + }, + "id": 65, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\",container=\"metastore\"})", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 61 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(container_memory_working_set_bytes{namespace=\"$namespace\", container=\"metastore\", image!=\"\"}) by (pod)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Requests", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\".*-metastore\"}\n)", + "hide": true, + "legendFormat": "Limit", + "range": true, + "refId": "C" + } + ], + "title": "Memory Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 61 + }, + "id": 84, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "kubelet_volume_stats_used_bytes{namespace=\"$namespace\",persistentvolumeclaim=~\".*metastore.*\"} /\nkubelet_volume_stats_capacity_bytes{namespace=\"$namespace\",persistentvolumeclaim=~\".*metastore.*\"}", + "hide": false, + "legendFormat": "{{persistentvolumeclaim}}", + "range": true, + "refId": "C" + } + ], + "title": "Disk Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 0, + "y": 69 + }, + "id": 85, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(operation) (rate(objstore_bucket_operations_total{namespace=\"$namespace\",container=\"metastore\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Storage I/O", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 6, + "y": 69 + }, + "id": 82, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*metastore.*\"}) by (namespace,pod)) * -1", + "hide": false, + "legendFormat": "tx {{pod}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*metastore.*\"}) by (namespace,pod))", + "hide": false, + "legendFormat": "rx {{pod}}", + "range": true, + "refId": "B" + } + ], + "title": "Network", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 12, + "y": 69 + }, + "id": 83, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_fs_writes_total{namespace=\"$namespace\",container=\"metastore\"}[$__rate_interval])) * -1", + "format": "time_series", + "hide": false, + "legendFormat": "write {{pod}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_fs_reads_total{namespace=\"$namespace\",container=\"metastore\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "read {{pod}}", + "range": true, + "refId": "B" + } + ], + "title": "Disk I/O", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 18, + "y": 69 + }, + "id": 94, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "irate(node_disk_io_time_seconds_total{cluster=\"$cluster\"}[$__rate_interval])\n+ on(instance, device) group_left(pod)\ntopk by(instance, device) (\n 1,\n 0 * label_replace(\n container_blkio_device_usage_total{\n cluster=\"$cluster\",\n namespace=\"$namespace\",\n container=\"metastore\",\n operation=\"Write\",\n },\n \"device\", \"$1\", \"device\", \"/dev/(.*)\"\n )\n)\n", + "hide": false, + "legendFormat": "{{pod}}/{{device}}", + "range": true, + "refId": "A" + } + ], + "title": "Disk I/O Wait", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 60, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "Number of OS threads created", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 113 + }, + "id": 61, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "go_threads{namespace=\"$namespace\",container=\"metastore\"}", + "hide": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Go Threads", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 113 + }, + "id": 62, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_goroutines{namespace=\"$namespace\",container=\"metastore\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Goroutines", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 113 + }, + "id": 63, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_memstats_heap_inuse_bytes{namespace=\"$namespace\",container=\"metastore\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Heap In-Use", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 113 + }, + "id": 64, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_file_descriptors{namespace=\"$namespace\",container=\"metastore\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "File Descriptors", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Runtime", + "type": "row" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [ + "pyroscope", + "pyroscope-v2" + ], + "templating": { + "list": [ + { + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "includeAll": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Grafana Logging", + "value": "000000193" + }, + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "pyroscope-dev", + "value": "pyroscope-dev" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "label": "cluster", + "name": "cluster", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "allowCustomValue": false, + "current": { + "text": "default", + "value": "default" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "label": "namespace", + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Pyroscope v2 / Metastore" +} \ No newline at end of file diff --git a/operations/monitoring/dashboards/v2-read-path.json b/operations/monitoring/dashboards/v2-read-path.json new file mode 100644 index 0000000000..916cb62d8c --- /dev/null +++ b/operations/monitoring/dashboards/v2-read-path.json @@ -0,0 +1,3491 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{cluster=\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=\"$namespace\"", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "K8s Changes", + "tagKeys": "type,name_extracted,verb", + "textFormat": "{{notes}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} != \"Preemption is not helpful\" != \"Failed deploy model\" | logfmt | type=\"Warning\"", + "hide": false, + "iconColor": "orange", + "instant": false, + "name": "K8s Warnings", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt | type!=\"Normal\" | type!=\"Warning\"", + "hide": false, + "iconColor": "red", + "instant": false, + "name": "K8s Errors", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt", + "hide": false, + "iconColor": "blue", + "instant": false, + "name": "K8s All events", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 12593, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 68, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "description": "SelectMergeProfile filtered out by default as the API is used by Canary Exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pod" + }, + "properties": [ + { + "id": "custom.width", + "value": 280 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "orgID" + }, + "properties": [ + { + "id": "custom.width", + "value": 86 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "uri" + }, + "properties": [ + { + "id": "custom.width", + "value": 312 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.width", + "value": 179 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trace ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 318 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Endpoint" + }, + "properties": [ + { + "id": "custom.width", + "value": 420 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Pod" + }, + "properties": [ + { + "id": "custom.width", + "value": 379 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "route" + }, + "properties": [ + { + "id": "custom.width", + "value": 347 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Route" + }, + "properties": [ + { + "id": "custom.width", + "value": 363 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 69, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Time" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "direction": "backward", + "editorMode": "code", + "expr": "{namespace=~\"$namespace\",cluster=~\"$cluster\",container=\"query-frontend\"}\n|= \"route=/querier.v1.\"\n| logfmt | line_format \"tenant={{.orgID}} status={{.status}} duration={{.duration}} traceID={{.traceID}} {{.uri}}\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "All Queries", + "transformations": [ + { + "id": "extractFields", + "options": { + "delimiter": ",", + "format": "json", + "keepTime": false, + "replace": false, + "source": "labels" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Drone build for Grafana": true, + "Drone build for Grafana Enterprise": true, + "Line": true, + "Okta Logs": true, + "Profile TraceID": true, + "TraceID (json)": true, + "__adaptive_logs_sampled__": true, + "app_kubernetes_io_component": true, + "app_kubernetes_io_instance": true, + "app_kubernetes_io_name": true, + "caller": true, + "cluster": true, + "container": true, + "debug": true, + "detected_level": true, + "id": true, + "job": true, + "labelTypes": true, + "labels": true, + "level": true, + "method": true, + "msg": true, + "name": true, + "pod_template_hash": true, + "request_body_size": true, + "service_name": true, + "status": false, + "stream": true, + "test_run_id": true, + "traceID": true, + "traceID (label)": true, + "traceID 1": true, + "trace_id (labels)": true, + "ts": true, + "tsNs": true + }, + "includeByName": {}, + "indexByName": { + "Drone build for Grafana": 30, + "Drone build for Grafana Enterprise": 31, + "Line": 4, + "Time": 1, + "TraceID (json)": 8, + "TraceID (log line)": 29, + "app_kubernetes_io_component": 11, + "app_kubernetes_io_instance": 12, + "app_kubernetes_io_name": 13, + "caller": 14, + "cluster": 15, + "container": 16, + "detected_level": 17, + "duration": 18, + "id": 7, + "job": 19, + "labelTypes": 6, + "labels": 0, + "level": 20, + "msg": 21, + "name": 22, + "namespace": 24, + "pod": 23, + "pod_template_hash": 25, + "route": 3, + "service_name": 26, + "stream": 27, + "tenant": 2, + "test_run_id": 10, + "traceID": 9, + "traceID (label)": 32, + "trace_id (labels)": 33, + "ts": 28, + "tsNs": 5 + }, + "renameByName": { + "Line": "", + "Time": "", + "TraceID": "Trace ID", + "duration": "Duration", + "labels": "", + "namespace": "Namespace", + "orgID": "Tenant", + "pod": "Pod", + "pod_template_hash": "", + "route": "Route", + "status": "Status", + "tenant": "Tenant", + "uri": "Endpoint" + } + } + } + ], + "transparent": true, + "type": "table" + }, + { + "datasource": { + "type": "tempo", + "uid": "${tempo_datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto", + "wrapText": false + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Trace Name" + }, + "properties": [ + { + "id": "custom.width", + "value": 455 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trace ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 311 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 70, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Start time" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "tempo", + "uid": "${tempo_datasource}" + }, + "filters": [ + { + "id": "d5be7410", + "operator": "=", + "scope": "resource", + "tag": "k8s.namespace.name", + "value": [ + "$namespace" + ], + "valueType": "string" + }, + { + "id": "service-name", + "operator": "=", + "scope": "resource", + "tag": "service.name", + "value": [ + "pyroscope-query-frontend", + "pyroscope-query-backend" + ], + "valueType": "string" + }, + { + "id": "min-duration", + "operator": "\u003e", + "tag": "duration", + "value": "100ms", + "valueType": "duration" + }, + { + "id": "span-name", + "operator": "!=", + "scope": "span", + "tag": "name", + "value": [ + "HTTP GET - debug_pprof" + ], + "valueType": "string" + } + ], + "limit": 25, + "metricsQueryType": "instant", + "queryType": "traceqlSearch", + "refId": "A", + "spss": 5, + "tableType": "traces" + } + ], + "title": "Traces", + "transparent": true, + "type": "table" + } + ], + "title": "Query Log", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 57, + "panels": [], + "title": "Metadata Query Service (metastore)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Raft node roles observed by each node. The view is not meant to be 100% consistent, and only serves monitoring purposes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisPlacement": "auto", + "fillOpacity": 15, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 1, + "spanNulls": false + }, + "fieldMinMax": false, + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Follower" + }, + "to": 99 + }, + "type": "range" + }, + { + "options": { + "from": 100, + "result": { + "color": "dark-red", + "index": 1, + "text": "Leader" + }, + "to": 1000000 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": 0 + }, + { + "color": "light-red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 54, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.8, + "showValue": "never", + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (pod) (\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Follower\"} or\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Leader\"} * 100\n)", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "D" + } + ], + "title": "Raft Nodes", + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadata endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 2 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of QueryMetadataLabels endpoint observed by metastore nodes.\n\nThe only user is the query-frontend service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 2 + }, + "id": 55, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "QueryMetadataLabels Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The size of BoltDB snapshot taken by FSM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 60, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "pyroscope_metastore_boltdb_persist_snapshot_size_bytes{namespace=\"$namespace\"}", + "hide": false, + "instant": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Snapshot Size", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 9 + }, + "id": 58, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadata\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 9 + }, + "id": 59, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.MetadataQueryService/QueryMetadataLabels\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 63, + "panels": [], + "title": "Query Frontend", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Query rate observed by cortex-gw", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 1, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 67, + "options": { + "dataLinks": [], + "legend": { + "calcs": [ + "max", + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": true, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by (status_code) (histogram_count(rate(pyroscope_request_duration_seconds{cluster=~\"$cluster\", container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[5m])))", + "legendFormat": "{{status_code}} ", + "range": true, + "refId": "A" + } + ], + "title": "Query rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Query duration observed by cortex-gw", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (route) ( rate(pyroscope_request_duration_seconds{container=~\"pyroscope|distributor|query-frontend\", namespace=~\"$namespace\", cluster=~\"$cluster\",route=~\".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Query Duartion", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 61, + "panels": [], + "title": "Query Backend", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Number of query-backend invocations.\n\nErrors are expected: usually those indicate that the query is throttled with the concurrency limiter.\n\nIf errors are presents in the query-frontend/gateway, the query is failed.\n", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 27 + }, + "id": 64, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Invocations", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "QueryBackend.Invoke latency observed by query-backend instances", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 27 + }, + "id": 62, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "Invocation Duration", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "QueryBackend.Invokeduration observed by query-backend instances", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 27 + }, + "id": 71, + "options": { + "calculate": false, + "cellGap": 0, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Rainbow", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum (rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n status_code=\"success\"\n}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + } + ], + "title": "Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 27 + }, + "id": 65, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/query.v1.QueryBackendService/Invoke\",\n}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Breakdown", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 32, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 36 + }, + "id": 29, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-query-backend\"}\n)", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-query-backend\"}\n)", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Request" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 36 + }, + "id": 72, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "Total", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(kube_pod_container_resource_requests{namespace=\"$namespace\", resource=\"cpu\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage (stack)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Request" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 30, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(container_memory_working_set_bytes{namespace=\"$namespace\", container=\"query-backend\", image!=\"\"}) by (pod)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(kube_pod_container_resource_requests{namespace=\"$namespace\", resource=\"memory\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max (kube_pod_container_resource_limits{namespace=\"$namespace\", resource=\"memory\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "C" + } + ], + "title": "Memory Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 31, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "last" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(operation) (irate(objstore_bucket_operations_total{namespace=\"$namespace\",container=\"query-backend\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Storage I/O", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 44 + }, + "id": 53, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_transmit_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-backend.*\"}) by (namespace,pod)) * -1", + "hide": false, + "legendFormat": "tx {{pod}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(sum(irate(container_network_receive_bytes_total{job=~\"(.*/)?cadvisor\", cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval]) * on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"$cluster\", namespace=~\"$namespace\", workload=~\".*query-backend.*\"}) by (namespace,pod))", + "hide": false, + "legendFormat": "rx {{pod}}", + "range": true, + "refId": "B" + } + ], + "title": "Network", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 52 + }, + "id": 43, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "Number of OS threads created", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 155 + }, + "id": 48, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "go_threads{namespace=\"$namespace\",container=\"query-backend\"}", + "hide": false, + "legendFormat": "{{pod}}", + "range": true, + "refId": "D" + } + ], + "title": "Go Threads", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 155 + }, + "id": 46, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_goroutines{namespace=\"$namespace\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Goroutines", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 155 + }, + "id": 44, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (go_memstats_heap_inuse_bytes{namespace=\"$namespace\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Heap In-Use", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 155 + }, + "id": 45, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_file_descriptors{namespace=\"$namespace\",container=\"query-backend\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "File Descriptors", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Runtime", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 53 + }, + "id": 42, + "panels": [ + { + "datasource": { + "type": "loki", + "uid": "OP27Xzxnk" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 156 + }, + "id": 41, + "options": { + "dedupStrategy": "none", + "enableInfiniteScrolling": false, + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "OP27Xzxnk" + }, + "direction": "backward", + "editorMode": "code", + "expr": "{cluster=\"$cluster\", namespace=\"$namespace\", container=\"query-backend\"} |= \"level=err\" or \"level=warn\" or \"panic\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "Worker log", + "transparent": true, + "type": "logs" + } + ], + "title": "Errors and warnings", + "type": "row" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [ + "pyroscope", + "pyroscope-v2" + ], + "templating": { + "list": [ + { + "allowCustomValue": true, + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "label": "metrics", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Grafana Logging", + "value": "000000193" + }, + "description": "", + "label": "logs", + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Tempo Ops (tempo-ops-01)", + "value": "fds8vtxx3ao74b" + }, + "description": "", + "label": "traces", + "name": "tempo_datasource", + "options": [], + "query": "tempo", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "pyroscope-dev", + "value": "pyroscope-dev" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "label": "cluster", + "name": "cluster", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "allowCustomValue": false, + "current": { + "text": "default", + "value": "default" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "label": "namespace", + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Pyroscope v2 / Read Path" +} \ No newline at end of file diff --git a/operations/monitoring/dashboards/v2-write-path.json b/operations/monitoring/dashboards/v2-write-path.json new file mode 100644 index 0000000000..e7eb0bc8a7 --- /dev/null +++ b/operations/monitoring/dashboards/v2-write-path.json @@ -0,0 +1,5026 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{cluster=\"$cluster\", container=\"kube-diff-logger\"} | json | namespace_extracted=\"$namespace\"", + "hide": false, + "iconColor": "yellow", + "instant": false, + "name": "K8s Changes", + "tagKeys": "type,name_extracted,verb", + "textFormat": "{{notes}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} != \"Preemption is not helpful\" != \"Failed deploy model\" | logfmt | type=\"Warning\"", + "hide": false, + "iconColor": "orange", + "instant": false, + "name": "K8s Warnings", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}", + "titleFormat": "" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": true, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt | type!=\"Normal\" | type!=\"Warning\"", + "hide": false, + "iconColor": "red", + "instant": false, + "name": "K8s Errors", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + }, + { + "datasource": { + "type": "loki", + "uid": "${loki_datasource}" + }, + "enable": false, + "expr": "{namespace=\"$namespace\",container=\"eventrouter\"} | logfmt", + "hide": false, + "iconColor": "blue", + "instant": false, + "name": "K8s All Events", + "tagKeys": "type,object_kind,object_name", + "textFormat": "{{message}}" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 0, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "pyroscope" + ], + "targetBlank": false, + "title": "Pyroscope Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 85, + "panels": [], + "title": "", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "footer": { + "reducers": [ + "countAll" + ] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "unit", + "value": "decbytes" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tenant" + }, + "properties": [ + { + "id": "custom.width", + "value": 78 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "slug" + }, + "properties": [ + { + "id": "custom.width", + "value": 132 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "org_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 142 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "lcd", + "type": "gauge", + "valueDisplayMode": "text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slug" + }, + "properties": [ + { + "id": "custom.width", + "value": 89 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Name" + }, + "properties": [ + { + "id": "custom.width", + "value": 143 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ID" + }, + "properties": [ + { + "id": "custom.width", + "value": 104 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 68, + "options": { + "cellHeight": "sm", + "enablePagination": false, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Value" + } + ] + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "\nsum by (tenant, slug, org_name, environment) (\n histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval]))\n)\n", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Tenants", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": false, + "cluster": true, + "environment": true, + "slug": false + }, + "includeByName": {}, + "indexByName": { + "Time": 0, + "Value": 4, + "environment": 5, + "org_name": 3, + "slug": 2, + "tenant": 1 + }, + "renameByName": { + "Time": "", + "Value": "", + "environment": "Env", + "org_name": "Name", + "slug": "Slug", + "tenant": "ID" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 66, + "options": { + "legend": { + "calcs": [ + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval])))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MBs per Tenant (Decompressed)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 4, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "cps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 67, + "options": { + "legend": { + "calcs": [ + "mean", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Mean", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (tenant) (histogram_count(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Profiles/s per Tenant", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 82, + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"distributor\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Distributor Ring", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The ring is used by distributor to discover segment-writer instances. ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 81, + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (state) (pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"segment-writer\"}) / count by (state)(pyroscope_ring_members{cluster=~\"$cluster\", namespace=~\"$namespace\", name=\"segment-writer\"})", + "format": "time_series", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Segment Writer Ring", + "type": "piechart" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 90, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency observed by distributor, indicating the overall write path latency.\n\nOnly successful requests are counted.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "dark-red", + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 1, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "p99 overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 34 + }, + "id": 94, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by (pod) (rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*pusher.*|.*ingest.*\",\n status_code=\"200\",\n}[$__rate_interval])))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*pusher.*|.*ingest.*\",\n status_code=\"200\",\n}[$__rate_interval])))", + "hide": true, + "legendFormat": "p99 overall", + "range": true, + "refId": "A" + } + ], + "title": "Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 34 + }, + "id": 93, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*push.*|.*ingest.*\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 34 + }, + "id": 42, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status_code) (histogram_count(rate(\n pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*push.*|.*ingest.*\",\n }[1m]))\n)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency observed by distributors (write path router), broken down by instance.\n\nLatencies are expected to be distributed evenly across instances. An outlier here likely indicates a neighborhood issue.\n\nOnly successful requests are counted.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 72, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_write_path_downstream_request_duration_seconds{\n namespace=\"$namespace\",\n status=\"200\",\n primary=\"1\",\n}[$__rate_interval])) by (route,pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 primary {{pod}} =\u003e {{route}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_write_path_downstream_request_duration_seconds{\n namespace=\"$namespace\",\n status=\"200\",\n primary!=\"1\",\n}[$__rate_interval])) by (route,pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 secondary {{pod}} =\u003e {{route}}", + "range": true, + "refId": "B" + } + ], + "title": "Downstream Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency observed by the segment-writer client", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 56, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_write_path_downstream_request_duration_seconds{\n namespace=\"$namespace\",\n route=\"segment-writer\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 95, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_write_path_downstream_request_duration_seconds{\n namespace=\"$namespace\",\n primary=\"1\",\n}[$__rate_interval]))) by (status,route)", + "instant": false, + "legendFormat": "primary {{route}} {{status}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_write_path_downstream_request_duration_seconds{\n namespace=\"$namespace\",\n primary=\"0\",\n}[$__rate_interval]))) by (status,route)", + "hide": false, + "instant": false, + "legendFormat": "secondary {{route}} {{status}}", + "range": true, + "refId": "C" + } + ], + "title": "Downstream Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 50 + }, + "id": 97, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_memory_working_set_bytes{namespace=\"$namespace\",container=\"distributor\"})", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\", container=\"distributor\"})", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 50 + }, + "id": 62, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\",container=\"distributor\"})", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-distributor\"}\n)", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-distributor\"}\n)", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The chart showd distribution of requests from the upstream (cortex-gw/envoy)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 50 + }, + "id": 98, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (histogram_count(rate(\n pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"distributor\",\n route=~\".*push.*|.*ingest.*\",\n }[1m]))\n)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Upstream Distribution", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Distributor", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 47, + "panels": [], + "title": "Segment Writer", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of the Push endpoint observed by segment-writer.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Overall p99" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 27 + }, + "id": 79, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99 overall", + "range": true, + "refId": "Overall p99" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.90, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p90 overall", + "range": true, + "refId": "Overall p90" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p50 overall", + "range": true, + "refId": "Overall p50" + } + ], + "title": "Push Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency of the Push endpoint observed by segment-writer", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 27 + }, + "id": 76, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n container=\"segment-writer\",\n method=\"gRPC\",\n # status_code=\"success\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 27 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(irate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/segmentwriter.v1.SegmentWriterService/Push\",\n}[$__rate_interval]))) by (status_code)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Push Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency segment-writer observes when uploading segments to object store, including retries.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Overall p99" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99 overall", + "range": true, + "refId": "Overall p99" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.90, sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p90 overall", + "range": true, + "refId": "Overall p90" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p50 overall", + "range": true, + "refId": "Overall p50" + } + ], + "title": "Object Store Upload Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency of upload calls observed by the segment-writer", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 80, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "New objects created by segment-writer", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Hedged requests" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 59, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (histogram_count(rate(pyroscope_segment_writer_upload_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (histogram_count(rate(pyroscope_segment_writer_hedged_upload_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "{{status}} (hedged)", + "range": true, + "refId": "B" + } + ], + "title": "Object Store Upload Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency segment-writer observes when adding metadata entries to metastore, including retries.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Overall p99" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 43 + }, + "id": 77, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (pod))", + "hide": false, + "instant": false, + "legendFormat": "p99 {{pod}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99 overall", + "range": true, + "refId": "Overall p99" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.90, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p90 overall", + "range": true, + "refId": "Overall p90" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p50 overall", + "range": true, + "refId": "Overall p50" + } + ], + "title": "Store Metadata Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "description": "The latency segment-writer observes when adding metadata entries, including retries", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 43 + }, + "id": 78, + "options": { + "calculate": false, + "calculation": { + "xBuckets": { + "mode": "count", + "value": "" + }, + "yBuckets": { + "mode": "count", + "scale": { + "type": "linear" + } + } + }, + "cellGap": 0, + "cellValues": { + "unit": "requests" + }, + "color": { + "exponent": 0.2, + "fill": "super-light-red", + "mode": "scheme", + "reverse": true, + "scale": "exponential", + "scheme": "Turbo", + "steps": 128 + }, + "exemplars": { + "color": "orange" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "s" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency Heatmap", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "New metadata entries created by segment-writers", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 43 + }, + "id": 73, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (histogram_count(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (status) (rate(pyroscope_segment_writer_store_metadata_dql{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "{{status}} (DLQ)", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(rate(pyroscope_segment_writer_store_metadata_dlq{namespace=\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "dlq", + "range": true, + "refId": "C" + } + ], + "title": "Store Metadata Rate", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 51 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (histogram_sum(irate(pyroscope_segment_writer_segment_ingest_bytes{namespace=\"$namespace\", container=\"segment-writer\"}[10m]))) /\nsum by (pod) (rate(container_cpu_usage_seconds_total{namespace=\"$namespace\", container=\"segment-writer\"}[10m]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Processing Rate (MB/sec/core)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 1, + "barWidthFactor": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.axisColorMode", + "value": "text" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 51 + }, + "id": 63, + "options": { + "legend": { + "calcs": [ + "last", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "by pod" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_requests{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-segment-writer\"}\n)", + "hide": false, + "legendFormat": "Request", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "max(\n kube_pod_container_resource_limits{job=~\"(.*/)?kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\".*-segment-writer\"}\n)", + "hide": false, + "legendFormat": "Limit", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 51 + }, + "id": 27, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": false, + "sortBy": "Mean", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval])) by (pod)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container=\"segment-writer\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "Total", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage (stack)", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 59 + }, + "id": 51, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of raft commands observed by the metastore leader", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisPlacement": "auto", + "fillOpacity": 15, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 1, + "spanNulls": false + }, + "fieldMinMax": false, + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Follower" + }, + "to": 99 + }, + "type": "range" + }, + { + "options": { + "from": 100, + "result": { + "color": "dark-red", + "index": 1, + "text": "Leader" + }, + "to": 1000000 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": 0 + }, + { + "color": "light-red", + "value": 100 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 106 + }, + "id": 65, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.8, + "showValue": "never", + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (pod) (\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Follower\"} or\n pyroscope_metastore_raft_state{namespace=\"$namespace\",state=\"Leader\"} * 100\n)", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "D" + } + ], + "title": "Raft Nodes", + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The latency of AddBlock endpoint observed by metastore nodes", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 11 + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 111 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "(\n histogram_quantile(0.99,(sum by (pod) (\n irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace=\"$namespace\"}[$__rate_interval])))\n ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace=\"$namespace\", state=\"Leader\"} \u003e= 1)\n)", + "hide": false, + "instant": false, + "legendFormat": "Metastore leader snapshot ({{pod}})", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p99", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "A" + } + ], + "title": "Latency", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 111 + }, + "id": 50, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(histogram_count(rate(pyroscope_request_duration_seconds{\n namespace=\"$namespace\",\n method=\"gRPC\",\n container=\"metastore\",\n route=\"/metastore.v1.IndexService/AddBlock\",\n}[$__rate_interval]))) by (status_code)", + "hide": false, + "instant": false, + "legendFormat": "{{status_code}}", + "range": true, + "refId": "D" + } + ], + "title": "", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Metastore", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 60 + }, + "id": 22, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 3, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 17, + "x": 0, + "y": 69 + }, + "id": 44, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (dataset, tenant) (\n pyroscope_adaptive_placement_dataset_shard_limit{namespace=\"$namespace\"}\n) \u003e 1", + "legendFormat": "{{tenant}}/{{dataset}}", + "range": true, + "refId": "A" + } + ], + "title": "Dataset Shards", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Top-10", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 3, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 7, + "x": 17, + "y": 69 + }, + "id": 107, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "topk(10, count by (tenant) (sum by (dataset, tenant) (\n pyroscope_adaptive_placement_dataset_shard_limit{namespace=\"$namespace\"}\n)))", + "legendFormat": "{{tenant}}", + "range": true, + "refId": "A" + } + ], + "title": "Datasets per tenant", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 23, + "options": { + "calculate": false, + "cellGap": 0, + "cellValues": { + "unit": "Bps" + }, + "color": { + "exponent": 0.5, + "fill": "red", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Rainbow", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto", + "value": "Shard" + }, + "tooltip": { + "mode": "single", + "showColorScale": true, + "yHistogram": true + }, + "yAxis": { + "axisLabel": "Shard", + "axisPlacement": "right", + "reverse": true, + "unit": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (shard) (histogram_sum(rate(pyroscope_segment_writer_client_sent_bytes{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Distributed Bytes (per shard)", + "transparent": true, + "type": "heatmap" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 89 + }, + "id": 64, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (shard) (histogram_sum(rate(pyroscope_segment_writer_client_sent_bytes{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Distributed Bytes (per shard)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 89 + }, + "id": 26, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (shard) (histogram_sum(rate(pyroscope_segment_writer_client_sent_bytes{namespace=\"$namespace\"}[$__rate_interval])))", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Distributed Bytes (per shard, stack)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 98 + }, + "id": 24, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (histogram_sum(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace=\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ingested Bytes (per node)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 98 + }, + "id": 34, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (histogram_sum(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace=\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Ingested Bytes (per node, stack)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 107 + }, + "id": 35, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (histogram_count(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace=\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ingested Profiles (per node)", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 7, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 107 + }, + "id": 36, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by (pod) (histogram_count(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace=\"$namespace\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ingested Profiles (per node, stack)", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Data Distribution", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 86, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 168 + }, + "id": 87, + "options": { + "groupByField": "container", + "labelFields": [ + "container", + "instance_type" + ], + "textField": "instance_type", + "tiling": "treemapSquarify" + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count by (instance_type, container) (\n rate(container_cpu_usage_seconds_total{\n cluster=\"$cluster\",\n namespace=\"$namespace\",\n container=~\"segment-writer|distributor|cortex-gw|metastore|compaction-worker\",\n }[$__rate_interval]) + on (instance) group_left(instance_type) (0 * label_replace(\n karpenter_nodes_allocatable{cluster=\"$cluster\", resource_type=\"cpu\"}, \"instance\", \"$1\", \"node_name\", \"(.*)\")\n )\n)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "{{instance_type}}", + "range": false, + "refId": "A" + } + ], + "title": "AWS | Intances By Machine Type", + "transparent": true, + "type": "marcusolsson-treemap-panel" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 168 + }, + "id": 84, + "options": { + "legend": { + "calcs": [ + "mean", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "avg by (instance_type, container) (\n rate(container_cpu_usage_seconds_total{\n cluster=\"$cluster\",\n namespace=\"$namespace\",\n container=~\"segment-writer|distributor|cortex-gw\",\n }[$__rate_interval]) + on (instance) group_left(instance_type) (0 * label_replace(\n karpenter_nodes_allocatable{cluster=\"$cluster\", resource_type=\"cpu\"}, \"instance\", \"$1\", \"node_name\", \"(.*)\")\n )\n)", + "hide": false, + "legendFormat": "{{container}}/{{instance_type}}", + "range": true, + "refId": "A" + } + ], + "title": "AWS | Average CPU Usage By Type", + "transparent": true, + "type": "timeseries" + } + ], + "title": "Resource Allocation", + "type": "row" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [ + "pyroscope", + "pyroscope-v2" + ], + "templating": { + "list": [ + { + "current": { + "text": "ops-cortex", + "value": "000000134" + }, + "includeAll": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "Grafana Logging", + "value": "000000193" + }, + "name": "loki_datasource", + "options": [], + "query": "loki", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allowCustomValue": false, + "current": { + "text": "pyroscope-dev", + "value": "pyroscope-dev" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "label": "cluster", + "name": "cluster", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info{namespace=\"$namespace\"},cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "allowCustomValue": false, + "current": { + "text": "default", + "value": "default" + }, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(pyroscope_build_info,namespace)", + "label": "namespace", + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(pyroscope_build_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": ".*", + "type": "query" + }, + { + "baseFilters": [], + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "filters": [], + "name": "Filters", + "type": "adhoc" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "utc", + "title": "Pyroscope v2 / Write Path" +} \ No newline at end of file diff --git a/operations/monitoring/helm/cr.yaml b/operations/monitoring/helm/cr.yaml new file mode 100644 index 0000000000..029ea5d5dd --- /dev/null +++ b/operations/monitoring/helm/cr.yaml @@ -0,0 +1,3 @@ +git-repo: helm-charts +owner: grafana +skip-existing: true diff --git a/operations/monitoring/helm/ct.yaml b/operations/monitoring/helm/ct.yaml new file mode 100644 index 0000000000..14f5c86997 --- /dev/null +++ b/operations/monitoring/helm/ct.yaml @@ -0,0 +1,10 @@ +# See https://github.com/helm/chart-testing#configuration +remote: origin +target-branch: main +kubeVersion: "1.23" +chart-dirs: + - operations/monitoring/helm +chart-repos: + - grafana=https://grafana.github.io/helm-charts +helm-extra-args: --timeout 600s +validate-maintainers: false diff --git a/operations/monitoring/helm/pyroscope-monitoring/.helmignore b/operations/monitoring/helm/pyroscope-monitoring/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/operations/monitoring/helm/pyroscope-monitoring/Chart.lock b/operations/monitoring/helm/pyroscope-monitoring/Chart.lock new file mode 100644 index 0000000000..17e650f60d --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: k8s-monitoring + repository: https://grafana.github.io/helm-charts + version: 3.8.8 +digest: sha256:24e3c550873de975579372d467a30ccfa3c77fd2f1ef02e1847f7e7445649c37 +generated: "2026-05-15T15:57:18.810885+01:00" diff --git a/operations/monitoring/helm/pyroscope-monitoring/Chart.yaml b/operations/monitoring/helm/pyroscope-monitoring/Chart.yaml new file mode 100644 index 0000000000..2f67ffff7e --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +name: pyroscope-monitoring +description: A Helm chart for monitoring Grafana Pyroscope. This helm chart uses otel-lgtm to monitor the health of the Grafana Pyroscope backend. +type: application + +version: 0.1.1 +appVersion: "0.0.0" + +dependencies: + - name: k8s-monitoring + alias: monitoring + version: 3.8.8 + repository: https://grafana.github.io/helm-charts + condition: monitoring.enabled diff --git a/operations/monitoring/helm/pyroscope-monitoring/README.md b/operations/monitoring/helm/pyroscope-monitoring/README.md new file mode 100644 index 0000000000..c4f37c9b64 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/README.md @@ -0,0 +1,66 @@ +# pyroscope-monitoring + +![Version: 0.1.1](https://img.shields.io/badge/Version-0.1.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.0.0](https://img.shields.io/badge/AppVersion-0.0.0-informational?style=flat-square) + +A Helm chart for monitoring Grafana Pyroscope. This helm chart uses otel-lgtm to monitor the health of the Grafana Pyroscope backend. + +> ⚠️ **Note:** This monitoring setup is not production grade and is intended for development and testing purposes only. + +## Dashboards + +This chart provisions the following Grafana dashboards under the "Pyroscope" folder: + +- **operational** - General operational metrics dashboard +- **v2-metastore** - Metastore-related metrics dashboard (only relevant with v2 storage layer) +- **v2-read-path** - Read path performance dashboard (focusing on v2 storage layer) +- **v2-write-path** - Write path performance dashboard (focusing on v2 storage layer) + +### Native vs classic histograms + +Set `dashboards.nativeHistograms` (default: `true`) to control which PromQL query style is used: + +- `true` — native histogram functions (`histogram_sum`, `histogram_count`, `histogram_quantile`, `histogram_avg`). Requires `scrape_native_histograms: true` in the Prometheus scrape config for Pyroscope. +- `false` — classic suffix queries (`_bucket`, `_sum`, `_count`). + +The committed JSON files under `operations/monitoring/dashboards/` (native) and `operations/monitoring/dashboards-classic-histogram/` (classic) are **generated** by `make helm/check` and should not be edited directly. + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://grafana.github.io/helm-charts | monitoring(k8s-monitoring) | 3.8.8 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| dashboards.cadvisorSelector | string | `"job=~\"(.*/)?cadvisor\""` | | +| dashboards.cloudBackendGateway | bool | `false` | | +| dashboards.cloudBackendGatewaySelector | string | `"container=~\"cortex-gw(-internal)?\""` | | +| dashboards.cluster | string | `"pyroscope-dev"` | | +| dashboards.ingestNamespaceSelector | string | `"namespace=~\"$namespace\""` | | +| dashboards.ingestSelector | string | `"container=~\"pyroscope|distributor|query-frontend\""` | | +| dashboards.kubeStateMetricsSelector | string | `"job=~\"(.*/)?kube-state-metrics\""` | | +| dashboards.namespace | string | `"default"` | | +| dashboards.namespaceRegex | string | `".*"` | | +| dashboards.namespaceRegexPerDashboard | object | `{}` | | +| dashboards.nativeHistograms | bool | `true` | | +| dashboards.tenantQuery | string | `"sum by (tenant, slug, org_name, environment) (\n {{- if .Values.dashboards.nativeHistograms }}\n histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval]))\n {{- else }}\n rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~\"$cluster\",namespace=~\"$namespace\"}[$__rate_interval])\n {{- end }}\n)\n"` | | +| fullnameOverride | string | `""` | | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.repository | string | `"grafana/otel-lgtm"` | | +| image.tag | string | `"0.11.10"` | | +| imagePullSecrets | list | `[]` | | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | | +| podAnnotations | object | `{}` | | +| podLabels | object | `{}` | | +| podSecurityContext | object | `{}` | | +| replicaCount | int | `1` | | +| resources | object | `{}` | | +| securityContext | object | `{}` | | +| service.deployStaticName | bool | `true` | | +| service.type | string | `"ClusterIP"` | | +| tolerations | list | `[]` | | + diff --git a/operations/monitoring/helm/pyroscope-monitoring/README.md.gotmpl b/operations/monitoring/helm/pyroscope-monitoring/README.md.gotmpl new file mode 100644 index 0000000000..def8db7995 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/README.md.gotmpl @@ -0,0 +1,39 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +> ⚠️ **Note:** This monitoring setup is not production grade and is intended for development and testing purposes only. + +## Dashboards + +This chart provisions the following Grafana dashboards under the "Pyroscope" folder: + +- **operational** - General operational metrics dashboard +- **v2-metastore** - Metastore-related metrics dashboard (only relevant with v2 storage layer) +- **v2-read-path** - Read path performance dashboard (focusing on v2 storage layer) +- **v2-write-path** - Write path performance dashboard (focusing on v2 storage layer) + +### Native vs classic histograms + +Set `dashboards.nativeHistograms` (default: `true`) to control which PromQL query style is used: + +- `true` — native histogram functions (`histogram_sum`, `histogram_count`, `histogram_quantile`, `histogram_avg`). Requires `scrape_native_histograms: true` in the Prometheus scrape config for Pyroscope. +- `false` — classic suffix queries (`_bucket`, `_sum`, `_count`). + +The committed JSON files under `operations/monitoring/dashboards/` (native) and `operations/monitoring/dashboards-classic-histogram/` (classic) are **generated** by `make helm/check` and should not be edited directly. + +{{ template "chart.homepageLine" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +{{ template "helm-docs.versionFooter" . }} + diff --git a/operations/monitoring/helm/pyroscope-monitoring/charts/k8s-monitoring-3.8.8.tgz b/operations/monitoring/helm/pyroscope-monitoring/charts/k8s-monitoring-3.8.8.tgz new file mode 100644 index 0000000000..ef3053b2f5 Binary files /dev/null and b/operations/monitoring/helm/pyroscope-monitoring/charts/k8s-monitoring-3.8.8.tgz differ diff --git a/operations/monitoring/helm/pyroscope-monitoring/convert-dashboard.sh b/operations/monitoring/helm/pyroscope-monitoring/convert-dashboard.sh new file mode 100755 index 0000000000..8bc8dac689 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/convert-dashboard.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# Goal of that script is to convert a grafana dashboard from internal GL environments so it can be used with this pyroscope-monitoring chart. + +set -eux +set -o pipefail + +# loop over inputs +for dashboard in "$@" +do + filename="$(basename $dashboard)" + name="${filename%.*}" + destination="templates/_dashboard_${name}.yaml" + + # create basic dashboard + echo "{{- define \"pyroscope-monitoring.dashboards.${name}\" -}}" > "${destination}" + echo "{{- \$dashboard := \"${name}\" -}}" >> "${destination}" + cat "$dashboard" | js-yaml | sed 's/{{.*}}/{{"\0\"}}/g' >> "${destination}" + echo "{{- end }}" >> "${destination}" + + # replace specific namespace + sed -i 's/profiles-ops-002/{{.Values.dashboards.namespace | quote}}/g' "${destination}" + sed -i 's/fire|profiles-\.\*/{{.Values.dashboards.namespaceRegex | quote}}/g' "${destination}" + sed -i 's/fire-\.\*|profiles-\.\*/{{.Values.dashboards.namespaceRegex | quote}}/g' "${destination}" + + # replace default cluster + sed -i 's/ops-eu-south-0/{{.Values.dashboards.cluster | quote}}/g' "${destination}" + + # replace cortex-gw selectors + sed -i 's/{job=~"$namespace\/cortex-gw(-internal)?"/{ {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace"/g' "${destination}" + sed -i 's/job=~"$namespace\/cortex-gw(-internal)?"/{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace"/g' "${destination}" + + # replace cadvisor selectors + sed -i 's/{job="kube-system\/cadvisor"/{ {{ .Values.dashboards.cadvisorSelector }}/g' "${destination}" + sed -i 's/job="kube-system\/cadvisor"/{{ .Values.dashboards.cadvisorSelector }}/g' "${destination}" + + # replace kube-state-metrics selectors + sed -i 's/{job="kube-system\/kube-state-metrics"/{ {{ .Values.dashboards.kubeStateMetricsSelector }}/g' "${destination}" + sed -i 's/job="kube-system\/kube-state-metrics"/{{ .Values.dashboards.kubeStateMetricsSelector }}/g' "${destination}" + sed -i 's/{job="kube-state-metrics\/kube-state-metrics"/{ {{ .Values.dashboards.kubeStateMetricsSelector }}/g' "${destination}" + sed -i 's/job="kube-state-metrics\/kube-state-metrics"/{{ .Values.dashboards.kubeStateMetricsSelector }}/g' "${destination}" + + # fix extra namespace + sed -i 's/{ {{/{{ "{" }}{{/g' "${destination}" +done diff --git a/operations/monitoring/helm/pyroscope-monitoring/lgtm.yaml b/operations/monitoring/helm/pyroscope-monitoring/lgtm.yaml new file mode 100644 index 0000000000..05244b9ee7 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/lgtm.yaml @@ -0,0 +1,78 @@ +# this is intended for demo / testing purposes only, not for production usage +apiVersion: v1 +kind: Service +metadata: + name: lgtm +spec: + selector: + app: lgtm + ports: + - name: grafana + protocol: TCP + port: 3000 + targetPort: 3000 + - name: otel-grpc + protocol: TCP + port: 4317 + targetPort: 4317 + - name: otel-http + protocol: TCP + port: 4318 + targetPort: 4318 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lgtm +spec: + replicas: 1 + selector: + matchLabels: + app: lgtm + template: + metadata: + labels: + app: lgtm + spec: + containers: + - name: lgtm + image: grafana/otel-lgtm:latest + ports: + - containerPort: 3000 + - containerPort: 4317 + - containerPort: 4318 + readinessProbe: + exec: + command: + - cat + - /tmp/ready + # NOTE: By default OpenShift does not allow writing the root directory. + # Thats why the data dirs for grafana, prometheus and loki can not be + # created and the pod never becomes ready. + # See: https://github.com/grafana/docker-otel-lgtm/issues/132 + volumeMounts: + - name: tempo-data + mountPath: /data/tempo + - name: grafana-data + mountPath: /data/grafana + - name: loki-data + mountPath: /data/loki + - name: loki-storage + mountPath: /loki + - name: p8s-storage + mountPath: /data/prometheus + - name: pyroscope-storage + mountPath: /data/pyroscope + volumes: + - name: tempo-data + emptyDir: {} + - name: loki-data + emptyDir: {} + - name: grafana-data + emptyDir: {} + - name: loki-storage + emptyDir: {} + - name: p8s-storage + emptyDir: {} + - name: pyroscope-storage + emptyDir: {} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/NOTES.txt b/operations/monitoring/helm/pyroscope-monitoring/templates/NOTES.txt new file mode 100644 index 0000000000..daf22c2d59 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/NOTES.txt @@ -0,0 +1 @@ +# TODO: Pyroscope Monitoring helm chart diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_operational.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_operational.yaml new file mode 100644 index 0000000000..babfb1916f --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_operational.yaml @@ -0,0 +1,5809 @@ +{{- define "pyroscope-monitoring.dashboards.operational" -}} +{{- $dashboard := "operational" -}} +annotations: + list: + - builtIn: 1 + datasource: + type: datasource + uid: grafana + enable: true + hide: true + iconColor: rgba(0, 211, 255, 1) + name: Annotations & Alerts + target: + limit: 100 + matchAny: false + tags: [] + type: dashboard + type: dashboard + - datasource: + uid: $loki_datasource + enable: true + expr: >- + {cluster=~"$cluster", container="kube-diff-logger"} | json | + namespace_extracted=~"$namespace" | notes!~".*Replicas.*" + hide: false + iconColor: rgba(255, 96, 96, 1) + name: K8s Changes + showIn: 0 + target: {} + - datasource: + uid: $loki_datasource + enable: true + expr: >- + {cluster=~"$cluster", container="kube-diff-logger"} | json | + namespace_extracted=~"$namespace" | notes=~".*Replicas.*" + hide: false + iconColor: rgba(255, 96, 96, 1) + name: K8s Changes(Replicas) + showIn: 0 + target: {} + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: >- + {namespace=~"$namespace",cluster=~"$cluster"} |= "head successfully + written to block" | logfmt + hide: false + iconColor: yellow + instant: false + name: Flush Events + tagKeys: block_path,tenant + textFormat: head successfully written to block + titleFormat: Head Flush +description: Bird eyes view of Pyroscope clusters +editable: true +fiscalYearStartMonth: 0 +graphTooltip: 0 +id: 9933 +links: +{{ .Values.dashboards.links.global | toYaml | nindent 2}} +{{- with (dig $dashboard (list) .Values.dashboards.links.perDashboard) }} +{{ . | toYaml | nindent 2}} +{{- end }} +panels: + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 0 + id: 4 + panels: [] + title: Global + type: row + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 10 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: binBps + overrides: [] + gridPos: + h: 6 + w: 7 + x: 0 + 'y': 1 + id: 29 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (tenant) + (histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (tenant) + (rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + hide: false + legendFormat: __auto + range: true + refId: A + title: MBs per Tenant (Decompressed) + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 10 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: cps + overrides: [] + gridPos: + h: 6 + w: 6 + x: 7 + 'y': 1 + id: 32 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (tenant) + (histogram_count(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (tenant) + (rate(pyroscope_distributor_received_decompressed_bytes_count{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Profiles/s per Tenant + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 10 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: short + overrides: [] + gridPos: + h: 6 + w: 5 + x: 13 + 'y': 1 + id: 24 + options: + dataLinks: [] + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + expr: >- + increase(kube_pod_container_status_restarts_total{cluster=~"$cluster", + namespace=~"$namespace"}[10m]) > 0 + hide: false + interval: '' + legendFormat: '{{"{{container}}-{{pod}}"}}' + refId: B + title: Container Restarts + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + hideFrom: + legend: false + tooltip: false + viz: false + mappings: [] + overrides: [] + gridPos: + h: 6 + w: 3 + x: 18 + 'y': 1 + id: 34 + options: + legend: + displayMode: list + placement: bottom + showLegend: true + pieType: pie + reduceOptions: + calcs: + - lastNotNull + fields: '' + values: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: >- + sum by (state) (pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="ingester"}) / count by + (state)(pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="ingester"}) + format: time_series + instant: true + legendFormat: __auto + range: false + refId: A + title: Ingester Ring Status + type: piechart + - datasource: + type: prometheus + uid: ${datasource} + description: Distributor Ring is used for rate limiting + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + hideFrom: + legend: false + tooltip: false + viz: false + mappings: [] + overrides: [] + gridPos: + h: 6 + w: 3 + x: 21 + 'y': 1 + id: 35 + options: + legend: + displayMode: list + placement: bottom + showLegend: true + pieType: pie + reduceOptions: + calcs: + - lastNotNull + fields: '' + values: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: >- + sum by (state) (pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="distributor"}) / count by + (state)(pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="distributor"}) + format: time_series + instant: true + legendFormat: __auto + range: false + refId: A + title: Distributor Ring Status + type: piechart + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: thresholds + custom: + align: left + cellOptions: + type: auto + filterable: true + inspect: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: + - matcher: + id: byName + options: Value + properties: + - id: unit + value: decbytes + - matcher: + id: byName + options: tenant + properties: + - id: custom.width + value: 78 + - matcher: + id: byName + options: slug + properties: + - id: custom.width + value: 132 + - matcher: + id: byName + options: org_name + properties: + - id: custom.width + value: 142 + gridPos: + h: 10 + w: 5 + x: 0 + 'y': 7 + id: 85 + options: + cellHeight: sm + footer: + countRows: false + enablePagination: true + fields: '' + reducer: + - count + show: false + showHeader: true + sortBy: + - desc: true + displayName: Value + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: | + {{ tpl .Values.dashboards.tenantQuery . | nindent 10 }} + format: table + instant: true + legendFormat: __auto + range: false + refId: A + title: Tenant id / name mapping + transformations: + - id: organize + options: + excludeByName: + Time: true + Value: false + cluster: true + includeByName: {} + indexByName: + Time: 0 + Value: 5 + cluster: 1 + org_name: 4 + slug: 3 + tenant: 2 + renameByName: {} + type: table + - datasource: + type: prometheus + uid: $datasource + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 40 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: reqps + overrides: + - matcher: + id: byName + options: '5xx ' + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: '2xx ' + properties: + - id: color + value: + fixedColor: green + mode: fixed + seriesBy: min + - matcher: + id: byName + options: '4xx ' + properties: + - id: color + value: + fixedColor: yellow + mode: fixed + gridPos: + h: 5 + w: 6 + x: 5 + 'y': 7 + id: 7 + options: + dataLinks: [] + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: multi + sort: none + targets: + - datasource: + uid: $datasource + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (status) ( + label_replace( + label_replace( + histogram_count(rate(pyroscope_request_duration_seconds{cluster=~"$cluster", {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", route=~".*ingest.*|.*pusher.*"}[$__rate_interval])), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- else }} + expr: |- + sum by (status) ( + label_replace( + label_replace( + rate(pyroscope_request_duration_seconds_count{cluster=~"$cluster", {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, route=~".*ingest.*|.*pusher.*"}[$__rate_interval]), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- end }} + legendFormat: '{{"{{status}}"}} ' + range: true + refId: A + title: Pushes/Second + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 5 + w: 7 + x: 11 + 'y': 7 + id: 27 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (route) ( + rate(pyroscope_request_duration_seconds{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*ingest.*|.*pusher.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + cluster=~"$cluster",route=~".*ingest.*|.*pusher.*"}[$__rate_interval]))) + {{- end }} + legendFormat: .99 {{"{{route}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.75, sum by (route) ( + rate(pyroscope_request_duration_seconds{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*ingest.*|.*pusher.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.75, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + cluster=~"$cluster",route=~".*ingest.*|.*pusher.*"}[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: .75 {{"{{route}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.5, sum by (route) ( + rate(pyroscope_request_duration_seconds{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*ingest.*|.*pusher.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.5, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + cluster=~"$cluster",route=~".*ingest.*|.*pusher.*"}[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: .5 {{"{{route}}"}} + range: true + refId: C + title: Push Latencies + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: thresholds + custom: + align: center + cellOptions: + type: auto + filterable: true + inspect: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 10 + w: 6 + x: 18 + 'y': 7 + id: 31 + options: + cellHeight: sm + footer: + countRows: false + enablePagination: false + fields: '' + reducer: + - sum + show: true + showHeader: true + showRowNums: false + sortBy: [] + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: >- + count by (container,version) + (pyroscope_build_info{cluster=~"$cluster",namespace=~"$namespace"}) or + count by (container,version) + (cloud_backend_gateway_build_info{cluster=~"$cluster",namespace=~"$namespace"}) + format: table + instant: true + legendFormat: __auto + range: false + refId: A + - datasource: + type: prometheus + uid: ${datasource} + hide: false + refId: B + title: Version + transformations: + - id: organize + options: + excludeByName: + Time: true + indexByName: {} + renameByName: + Value: Pods + type: table + - datasource: + type: prometheus + uid: $datasource + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 100 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: reqps + overrides: + - matcher: + id: byName + options: '5xx ' + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: '2xx ' + properties: + - id: color + value: + fixedColor: green + mode: fixed + seriesBy: min + - matcher: + id: byName + options: '4xx ' + properties: + - id: color + value: + fixedColor: yellow + mode: fixed + gridPos: + h: 5 + w: 6 + x: 5 + 'y': 12 + id: 6 + options: + dataLinks: [] + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: multi + sort: none + targets: + - datasource: + uid: $datasource + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (status) ( + label_replace( + label_replace( + histogram_count(rate(pyroscope_request_duration_seconds{cluster=~"$cluster", {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval])), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- else }} + expr: |- + sum by (status) ( + label_replace( + label_replace( + rate(pyroscope_request_duration_seconds_count{cluster=~"$cluster", {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- end }} + legendFormat: '{{"{{status}}"}} ' + range: true + refId: A + title: Queries/Second + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 5 + w: 7 + x: 11 + 'y': 12 + id: 26 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (route) ( + rate(pyroscope_request_duration_seconds{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- end }} + legendFormat: .99 {{"{{route}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.75, sum by (route) ( + rate(pyroscope_request_duration_seconds{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.75, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: .75 {{"{{route}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.5, sum by (route) ( + rate(pyroscope_request_duration_seconds{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.5, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: .5 {{"{{route}}"}} + range: true + refId: C + title: Query Latencies + type: timeseries + - datasource: + type: loki + uid: ${loki_datasource} + fieldConfig: + defaults: + color: + fixedColor: red + mode: fixed + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: bars + fillOpacity: 23 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 3 + w: 24 + x: 0 + 'y': 17 + id: 39 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: loki + uid: ${loki_datasource} + editorMode: code + expr: >- + sum by (container)( + count_over_time({namespace=~"$namespace",cluster=~"$cluster"} != + "stream context finished" != "fast-joining node failed" != "CAS + attempt failed" != "memberlist TCPTransport" |= " panic " or "panic:" + or " err=" or "level=error" [$__interval])) + queryType: range + refId: A + title: Error & Panic rate + type: timeseries + - datasource: + type: loki + uid: ${loki_datasource} + fieldConfig: + defaults: {} + overrides: [] + gridPos: + h: 10 + w: 24 + x: 0 + 'y': 20 + id: 37 + options: + dedupStrategy: numbers + enableInfiniteScrolling: false + enableLogDetails: true + prettifyLogMessage: false + showCommonLabels: false + showLabels: false + showTime: false + sortOrder: Descending + wrapLogMessage: true + targets: + - datasource: + type: loki + uid: ${loki_datasource} + editorMode: code + expr: >- + {namespace=~"$namespace",cluster=~"$cluster"} != "stream context + finished" != "fast-joining node failed" != "CAS attempt failed" != + "memberlist TCPTransport" |= " panic " or "panic:" or " err=" or + "level=error" + queryType: range + refId: A + title: Errors and Panics + type: logs + - datasource: + type: loki + uid: ${loki_datasource} + fieldConfig: + defaults: + color: + mode: thresholds + custom: + align: auto + cellOptions: + type: auto + filterable: true + inspect: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: + - matcher: + id: byName + options: ts + properties: + - id: custom.width + value: 271 + - matcher: + id: byName + options: path + properties: + - id: custom.width + value: 388 + - matcher: + id: byName + options: status + properties: + - id: custom.cellOptions + value: + applyToRow: false + mode: gradient + type: color-background + wrapText: false + - id: mappings + value: + - options: + from: 200 + result: + color: light-green + index: 0 + to: 399 + type: range + - options: + from: 400 + result: + color: light-yellow + index: 1 + to: 499 + type: range + - options: + from: 500 + result: + color: light-red + index: 2 + to: 599 + type: range + - id: custom.width + value: 96 + - matcher: + id: byName + options: traceID + properties: + - id: links + value: + - targetBlank: true + title: Show trace + url: >- + /explore?schemaVersion=1&panes=%7B%22xbp%22:%7B%22datasource%22:%22grafanacloud-traces%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22grafanacloud-traces%22%7D,%22queryType%22:%22traceql%22,%22limit%22:20,%22tableType%22:%22traces%22,%22metricsQueryType%22:%22range%22,%22query%22:%22${__value.text}%5Cn%22%7D%5D,%22range%22:%7B%22from%22:%22${__from}%22,%22to%22:%22${__to}%22%7D%7D%7D&orgId=1 + gridPos: + h: 10 + w: 24 + x: 0 + 'y': 30 + id: 108 + options: + cellHeight: sm + footer: + countRows: false + enablePagination: true + fields: '' + reducer: + - sum + show: false + showHeader: true + sortBy: + - desc: false + displayName: status + targets: + - datasource: + type: loki + uid: ${loki_datasource} + direction: backward + editorMode: code + expr: >- + {namespace=~"$namespace", cluster=~"$cluster", container="cortex-gw"} + |= `msg="request timings"` | logfmt + queryType: range + refId: A + title: Query Activity + transformations: + - id: extractFields + options: + delimiter: ',' + format: json + replace: true + source: labels + - id: organize + options: + excludeByName: + __adaptive_logs_sampled__: true + caller: true + cluster: true + conn_send: false + container: true + detected_level: true + downstream: false + insight: true + job: true + level: true + msg: true + name: true + namespace: true + path: false + pod_template_hash: true + service_name: true + stream: true + total: false + includeByName: {} + indexByName: + __adaptive_logs_sampled__: 22 + auth: 7 + caller: 8 + cluster: 9 + conn_send: 25 + container: 10 + dashboard_id: 24 + detected_level: 11 + downstream: 26 + grafana_username: 5 + insight: 12 + job: 13 + level: 14 + msg: 15 + name: 16 + namespace: 17 + panel_id: 27 + path: 1 + pod: 18 + pod_template_hash: 19 + query_hash: 23 + service_name: 20 + status: 2 + stream: 21 + total: 6 + traceID: 3 + ts: 0 + user: 4 + renameByName: + auth: '' + caller: '' + path: '' + total: '' + user: tenant_id + - id: convertFieldType + options: + conversions: [] + fields: {} + type: table + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 40 + id: 52 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 2 + id: 53 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~"$cluster", namespace=~"$namespace"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*ingester", workload_type="statefulset"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*ingester", workload_type="statefulset"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*ingester", workload_type="statefulset"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: CPU Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + unit: bytes + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.stacking + value: + group: A + mode: none + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 2 + id: 54 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + sum( + container_memory_working_set_bytes{cluster=~"$cluster", namespace=~"$namespace", container!="", image!=""} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*ingester", workload_type="statefulset"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*ingester", workload_type="statefulset"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*ingester", workload_type="statefulset"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: Memory Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 10 + id: 73 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_receive_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*ingester.*", + workload_type="statefulset"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Receive Bandwidth + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 10 + id: 74 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_transmit_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*ingester.*", + workload_type="statefulset"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Transmit Bandwidth + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 5 + w: 12 + x: 0 + 'y': 18 + id: 96 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/ingester", + cluster=~"$cluster",route=~".*push.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/ingester", + cluster=~"$cluster",route=~".*push.*"}[$__rate_interval]))) + {{- end }} + legendFormat: .99 {{"{{route}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.75, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/ingester", + cluster=~"$cluster",route=~".*push.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.75, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/ingester", + cluster=~"$cluster",route=~".*push.*"}[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: .75 {{"{{route}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.5, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/ingester", + cluster=~"$cluster",route=~".*push.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.5, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/ingester", + cluster=~"$cluster",route=~".*push.*"}[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: .5 {{"{{route}}"}} + range: true + refId: C + title: Push Latencies + type: timeseries + - datasource: + type: prometheus + uid: $datasource + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 40 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: reqps + overrides: + - matcher: + id: byName + options: '5xx ' + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: '2xx ' + properties: + - id: color + value: + fixedColor: green + mode: fixed + seriesBy: min + - matcher: + id: byName + options: '4xx ' + properties: + - id: color + value: + fixedColor: yellow + mode: fixed + gridPos: + h: 5 + w: 12 + x: 12 + 'y': 18 + id: 69 + options: + dataLinks: [] + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + uid: $datasource + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (status) ( + label_replace( + label_replace( + histogram_count(rate(pyroscope_request_duration_seconds{cluster=~"$cluster", job=~"$namespace/ingester", route=~".*push.*"}[$__rate_interval])), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- else }} + expr: |- + sum by (status) ( + label_replace( + label_replace( + rate(pyroscope_request_duration_seconds_count{cluster=~"$cluster", job=~"$namespace/ingester", route=~".*push.*"}[$__rate_interval]), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- end }} + legendFormat: '{{"{{status}}"}} ' + range: true + refId: A + title: Pushes/Second + type: timeseries + - datasource: + type: loki + uid: ${loki_datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 23 + id: 83 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: loki + uid: ${loki_datasource} + editorMode: code + expr: >- + sum by (tenant) + (count_over_time({cluster=~"$cluster",namespace=~"$namespace"} |= + "upload new block" | logfmt [$__interval])) + queryType: range + refId: A + title: Block Uploaded Per Tenant + type: timeseries + - datasource: + type: loki + uid: ${loki_datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: bars + fillOpacity: 15 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 23 + id: 84 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: loki + uid: ${loki_datasource} + editorMode: code + expr: >- + sum by (tenant) + (count_over_time({cluster=~"$cluster",namespace=~"$namespace"} |= + "cut row group segment" | logfmt [$__interval])) + hide: true + queryType: range + refId: A + - datasource: + type: loki + uid: ${loki_datasource} + editorMode: code + expr: >- + sum by (tenant) + (sum_over_time({cluster=~"$cluster",namespace=~"$namespace"} |= + "cut row group segment" | logfmt | unwrap numProfiles + [$__interval])) + hide: false + queryType: range + refId: B + title: Profiles Flushed to disk + type: timeseries + title: Ingesters + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 41 + id: 41 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 50 + id: 43 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + topk(10,sum by (tenant, reason) + (rate(pyroscope_discarded_samples_total{cluster=~"$cluster",namespace=~"$namespace"}[1m]))) + legendFormat: '{{"{{ tenant }} - {{ reason }}"}}' + range: true + refId: A + title: Discarded Profiles + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: thresholds + custom: + align: auto + cellOptions: + type: auto + inspect: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 50 + id: 45 + options: + cellHeight: sm + footer: + countRows: false + fields: '' + reducer: + - sum + show: false + showHeader: true + showRowNums: false + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: >- + topk(10, sum by (tenant, reason) + (sum_over_time(increase(pyroscope_discarded_samples_total{cluster=~"$cluster",namespace=~"$namespace"}[1m])[$__range:1m]))) + format: table + instant: true + legendFormat: '{{"{{ tenant }} - {{ reason }}"}}' + range: false + refId: A + title: Discarded Profiles Per Interval + transformations: + - id: organize + options: + excludeByName: + Time: true + indexByName: + Time: 0 + Value: 3 + reason: 2 + tenant: 1 + renameByName: + Value: Profiles + reason: Reason + tenant: Tenant + type: table + title: Tenant Limits + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 42 + id: 47 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 4 + id: 49 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~"$cluster", namespace=~"$namespace"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*distributor", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*distributor", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*distributor", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: CPU Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + unit: bytes + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.stacking + value: + group: A + mode: none + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 4 + id: 50 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + sum( + container_memory_working_set_bytes{cluster=~"$cluster", namespace=~"$namespace", container!="", image!=""} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*distributor", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*distributor", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*distributor", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: Memory Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 12 + id: 71 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_receive_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*distributor.*", + workload_type="deployment"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Receive Bandwidth + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 12 + id: 72 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_transmit_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*distributor.*", + workload_type="deployment"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Transmit Bandwidth + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 16 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 20 + id: 63 + options: + legend: + calcs: + - lastNotNull + displayMode: table + placement: right + showLegend: true + sortBy: Last * + sortDesc: true + tooltip: + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (type) + (histogram_count(rate(pyroscope_distributor_received_compressed_bytes{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (type) + (rate(pyroscope_distributor_received_compressed_bytes_count{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Profiles /s + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 16 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 20 + id: 62 + options: + legend: + calcs: + - lastNotNull + displayMode: table + placement: right + showLegend: true + sortBy: Last * + sortDesc: true + tooltip: + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (type) + (histogram_sum(rate(pyroscope_distributor_received_samples{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (type) + (rate(pyroscope_distributor_received_samples_sum{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Stacktrace Sample /s + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 16 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: decbytes + overrides: [] + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 28 + id: 65 + options: + legend: + calcs: + - lastNotNull + displayMode: table + placement: right + showLegend: false + sortBy: Last * + sortDesc: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (type) + (histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (type) + (rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Throughput Decompressed + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 16 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: decbytes + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 28 + id: 66 + options: + legend: + calcs: + - lastNotNull + displayMode: table + placement: right + showLegend: false + sortBy: Last * + sortDesc: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (type) + (histogram_sum(rate(pyroscope_distributor_received_samples_bytes{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (type) + (rate(pyroscope_distributor_received_samples_bytes_sum{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Throughput Samples Decompressed + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 16 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: decbytes + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 28 + id: 67 + options: + legend: + calcs: + - lastNotNull + displayMode: table + placement: right + showLegend: false + sortBy: Last * + sortDesc: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (type) + (histogram_sum(rate(pyroscope_distributor_received_symbols_bytes{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (type) + (rate(pyroscope_distributor_received_symbols_bytes_sum{cluster=~"$cluster", + namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Throughput Symbols Decompressed + type: timeseries + title: Distributors + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 43 + id: 91 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 5 + w: 12 + x: 0 + 'y': 5 + id: 100 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/query-frontend", + cluster=~"$cluster",route=~".*render.*|.*querier.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/query-frontend", + cluster=~"$cluster",route=~".*render.*|.*querier.*"}[$__rate_interval]))) + {{- end }} + legendFormat: .99 {{"{{route}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.75, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/query-frontend", + cluster=~"$cluster",route=~".*render.*|.*querier.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.75, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/query-frontend", + cluster=~"$cluster",route=~".*render.*|.*querier.*"}[$__rate_interval]))) + {{- end }} + hide: true + legendFormat: .75 {{"{{route}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.5, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/query-frontend", + cluster=~"$cluster",route=~".*render.*|.*querier.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.5, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/query-frontend", + cluster=~"$cluster",route=~".*render.*|.*querier.*"}[$__rate_interval]))) + {{- end }} + hide: true + legendFormat: .5 {{"{{route}}"}} + range: true + refId: C + title: API Latencies + type: timeseries + - datasource: + type: prometheus + uid: $datasource + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 40 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: reqps + overrides: + - matcher: + id: byRegexp + options: /2../ + properties: + - id: color + value: + fixedColor: green + mode: shades + - matcher: + id: byRegexp + options: /5../ + properties: + - id: color + value: + fixedColor: red + mode: shades + - matcher: + id: byRegexp + options: /4../ + properties: + - id: color + value: + fixedColor: yellow + mode: shades + gridPos: + h: 5 + w: 12 + x: 12 + 'y': 5 + id: 101 + options: + dataLinks: [] + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + uid: $datasource + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (status,route) ( + label_replace( + label_replace( + histogram_count(rate(pyroscope_request_duration_seconds{cluster=~"$cluster", job=~"$namespace/query-frontend", route=~".*render.*|.*querier.*"}[$__rate_interval])), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- else }} + expr: |- + sum by (status,route) ( + label_replace( + label_replace( + rate(pyroscope_request_duration_seconds_count{cluster=~"$cluster", job=~"$namespace/query-frontend", route=~".*render.*|.*querier.*"}[$__rate_interval]), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- end }} + legendFormat: '{{"{{status}} {{route}}"}}' + range: true + refId: A + title: Request Rates + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: custom.fillOpacity + value: 0 + - id: custom.stacking + value: + group: A + mode: none + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: red + mode: fixed + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 10 + id: 92 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~"$cluster", namespace=~"$namespace"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-frontend", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-frontend", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-frontend", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: CPU Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + unit: bytes + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.stacking + value: + group: A + mode: none + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 10 + id: 88 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + sum( + container_memory_working_set_bytes{cluster=~"$cluster", namespace=~"$namespace", container!="", image!=""} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-frontend", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-frontend", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-frontend", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: Memory Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 18 + id: 94 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_receive_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*query-frontend.*", + workload_type="deployment"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Receive Bandwidth + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 18 + id: 90 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_transmit_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*query-frontend.*", + workload_type="deployment"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Transmit Bandwidth + type: timeseries + - datasource: + type: loki + uid: ${loki_datasource} + fieldConfig: + defaults: {} + overrides: [] + gridPos: + h: 18 + w: 24 + x: 0 + 'y': 26 + id: 60 + options: + dedupStrategy: none + enableLogDetails: true + prettifyLogMessage: false + showCommonLabels: false + showLabels: false + showTime: false + sortOrder: Descending + wrapLogMessage: true + targets: + - datasource: + type: loki + uid: ${loki_datasource} + editorMode: code + expr: >- + {namespace=~"$namespace",cluster=~"$cluster",container="query-frontend"} + |= "http.go" |~ "QuerierService|pyroscope|render" | logfmt | + line_format "tenant={{"{{.orgID}} traceID={{.traceID}} {{.msg}}"}}" + queryType: range + refId: A + title: Queries + type: logs + title: Query Frontend + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 44 + id: 56 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: custom.fillOpacity + value: 0 + - id: custom.stacking + value: + group: A + mode: none + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: red + mode: fixed + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 6 + id: 87 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~"$cluster", namespace=~"$namespace"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*querier", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*querier", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*querier", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: CPU Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + unit: bytes + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.stacking + value: + group: A + mode: none + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 6 + id: 58 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + sum( + container_memory_working_set_bytes{cluster=~"$cluster", namespace=~"$namespace", container!="", image!=""} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*querier", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*querier", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*querier", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: Memory Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 14 + id: 75 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_receive_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*querier.*", + workload_type="deployment"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Receive Bandwidth + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 14 + id: 76 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_transmit_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*querier.*", + workload_type="deployment"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Transmit Bandwidth + type: timeseries + title: Queriers + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 45 + id: 102 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: custom.fillOpacity + value: 0 + - id: custom.stacking + value: + group: A + mode: none + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: red + mode: fixed + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 7 + id: 103 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~"$cluster", namespace=~"$namespace"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-scheduler", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-scheduler", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-scheduler", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: CPU Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + unit: bytes + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.stacking + value: + group: A + mode: none + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 7 + id: 93 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + sum( + container_memory_working_set_bytes{cluster=~"$cluster", namespace=~"$namespace", container!="", image!=""} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-scheduler", workload_type="deployment"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-scheduler", workload_type="deployment"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*query-scheduler", workload_type="deployment"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: Memory Usage + type: timeseries + title: Query Scheduler + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 46 + id: 86 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 5 + w: 12 + x: 0 + 'y': 8 + id: 98 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: true + tooltip: + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/store-gateway", + cluster=~"$cluster",route=~".*store.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/store-gateway", + cluster=~"$cluster",route=~".*store.*"}[$__rate_interval]))) + {{- end }} + legendFormat: .99 {{"{{route}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.75, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/store-gateway", + cluster=~"$cluster",route=~".*store.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.75, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/store-gateway", + cluster=~"$cluster",route=~".*store.*"}[$__rate_interval]))) + {{- end }} + hide: true + legendFormat: .75 {{"{{route}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.5, sum by (route) ( + rate(pyroscope_request_duration_seconds{job=~"$namespace/store-gateway", + cluster=~"$cluster",route=~".*store.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.5, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{job=~"$namespace/store-gateway", + cluster=~"$cluster",route=~".*store.*"}[$__rate_interval]))) + {{- end }} + hide: true + legendFormat: .5 {{"{{route}}"}} + range: true + refId: C + title: API Latencies + type: timeseries + - datasource: + type: prometheus + uid: $datasource + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 40 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: reqps + overrides: + - matcher: + id: byRegexp + options: /2../ + properties: + - id: color + value: + fixedColor: green + mode: shades + - matcher: + id: byRegexp + options: /5../ + properties: + - id: color + value: + fixedColor: red + mode: shades + - matcher: + id: byRegexp + options: /4../ + properties: + - id: color + value: + fixedColor: yellow + mode: shades + gridPos: + h: 5 + w: 12 + x: 12 + 'y': 8 + id: 99 + options: + dataLinks: [] + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + uid: $datasource + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (status,route) ( + label_replace( + label_replace( + histogram_count(rate(pyroscope_request_duration_seconds{cluster=~"$cluster", job=~"$namespace/store-gateway", route=~".*store.*"}[$__rate_interval])), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- else }} + expr: |- + sum by (status,route) ( + label_replace( + label_replace( + rate(pyroscope_request_duration_seconds_count{cluster=~"$cluster", job=~"$namespace/store-gateway", route=~".*store.*"}[$__rate_interval]), + "status", "${1}xx", "status_code", "([0-9]).."), + "status", "${1}", "status_code", "([a-z]+)") + ) + {{- end }} + legendFormat: '{{"{{status}} {{route}}"}}' + range: true + refId: A + title: Request Rates + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: custom.fillOpacity + value: 0 + - id: custom.stacking + value: + group: A + mode: none + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: red + mode: fixed + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 13 + id: 57 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~"$cluster", namespace=~"$namespace"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*store-gateway", workload_type="statefulset"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*store-gateway", workload_type="statefulset"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*store-gateway", workload_type="statefulset"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: CPU Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 21 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: yellow + value: 80 + - color: red + value: 90 + unit: bytes + overrides: + - matcher: + id: byName + options: request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: limit + properties: + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.stacking + value: + group: A + mode: none + - id: custom.fillOpacity + value: 0 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 13 + id: 104 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + sum( + container_memory_working_set_bytes{cluster=~"$cluster", namespace=~"$namespace", container!="", image!=""} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*store-gateway", workload_type="statefulset"} + ) by (pod) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*store-gateway", workload_type="statefulset"} + ) + hide: false + instant: false + legendFormat: request + range: true + refId: request + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, cluster=~"$cluster", namespace=~"$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", namespace=~"$namespace", workload=~".*store-gateway", workload_type="statefulset"} + ) + hide: false + legendFormat: limit + range: true + refId: limit + title: Memory Usage + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 21 + id: 89 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_receive_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*store-gateway.*", + workload_type="statefulset"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Receive Bandwidth + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 13 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 21 + id: 95 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_transmit_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) + + * on (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*store-gateway.*", + workload_type="statefulset"}) by (pod)) + legendFormat: __auto + range: true + refId: A + title: Transmit Bandwidth + type: timeseries + title: Store Gateway + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 47 + id: 78 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 12 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + overrides: + - __systemRef: hideSeriesFrom + matcher: + id: byNames + options: + mode: exclude + names: + - get + prefix: 'All except:' + readOnly: true + properties: + - id: custom.hideFrom + value: + legend: false + tooltip: false + viz: true + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 58 + id: 80 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by(operation) + (rate(objstore_bucket_operations_total{namespace=~"$namespace",cluster=~"$cluster"}[$__rate_interval])) + legendFormat: __auto + range: true + refId: A + title: Bucket Operation /s + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + drawStyle: line + fillOpacity: 12 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 58 + id: 81 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + histogram_quantile(0.95, + sum(rate(objstore_bucket_operation_duration_seconds{namespace=~"$namespace",cluster=~"$cluster"}[$__rate_interval])) + by (operation)) + legendFormat: __auto + range: true + refId: A + title: Latencies per Operation + type: timeseries + title: Object Storage + type: row + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 48 + id: 105 + panels: [] + title: GitHub API + type: row + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + noValue: '0' + thresholds: + mode: absolute + steps: + - color: green + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 49 + id: 106 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + disableTextWrap: false + editorMode: code + exemplar: false + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (route) + (rate(pyroscope_vcs_github_request_duration{cluster=~"$cluster", + namespace=~"$namespace", container="querier"} [$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, route) + (rate(pyroscope_vcs_github_request_duration_bucket{cluster=~"$cluster", + namespace=~"$namespace", container="querier"} [$__rate_interval]))) + {{- end }} + fullMetaSearch: false + hide: false + includeNullMetadata: true + instant: false + interval: '' + legendFormat: __auto + range: true + refId: B + useBackend: false + title: GitHub API (P99) + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: bars + fillOpacity: 100 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + noValue: '0' + thresholds: + mode: absolute + steps: + - color: green + unit: short + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 49 + id: 107 + options: + legend: + calcs: + - sum + displayMode: table + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + disableTextWrap: false + editorMode: code + exemplar: false + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (route, status_code) + (histogram_count(rate(pyroscope_vcs_github_request_duration{cluster=~"$cluster", + namespace=~"$namespace", container="querier"} [$__rate_interval]))) + {{- else }} + expr: >- + sum by (route, status_code) + (rate(pyroscope_vcs_github_request_duration_count{cluster=~"$cluster", + namespace=~"$namespace", container="querier"} [$__rate_interval])) + {{- end }} + fullMetaSearch: false + hide: false + includeNullMetadata: true + instant: false + interval: '' + legendFormat: __auto + range: true + refId: B + useBackend: false + title: GitHub API (P99) + type: timeseries +preload: false +refresh: 30s +schemaVersion: 41 +tags: + - pyroscope +templating: + list: + - current: + text: ops-cortex + value: '000000134' + includeAll: false + label: Data Source + name: datasource + options: [] + query: prometheus + refresh: 1 + regex: '' + type: datasource + - current: + text: Loki-Ops + value: c-R8UWvVk + includeAll: false + name: loki_datasource + options: [] + query: loki + refresh: 1 + regex: '' + type: datasource + - current: + text: All + value: + - $__all + datasource: + type: prometheus + uid: $datasource + definition: label_values(pyroscope_build_info,cluster) + includeAll: true + label: cluster + multi: true + name: cluster + options: [] + query: + labelFilters: [] + query: label_values(pyroscope_build_info,cluster) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: '' + sort: 1 + type: query + - current: + text: + - {{.Values.dashboards.namespace | quote}} + value: + - {{.Values.dashboards.namespace | quote}} + datasource: + type: prometheus + uid: $datasource + definition: label_values(pyroscope_build_info,namespace) + includeAll: true + label: namespace + multi: true + name: namespace + options: [] + query: + labelFilters: [] + query: label_values(pyroscope_build_info,namespace) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: {{ include "pyroscope-monitoring.dashboards-namespace-regex" (list . $dashboard) | quote }} + sort: 1 + type: query +time: + from: now-1h + to: now +timepicker: {} +timezone: '' +title: Pyroscope / Operational +version: 14 + +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-metastore.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-metastore.yaml new file mode 100644 index 0000000000..36f3455311 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-metastore.yaml @@ -0,0 +1,3447 @@ +{{- define "pyroscope-monitoring.dashboards.v2-metastore" -}} +{{- $dashboard := "v2-metastore" -}} +annotations: + list: + - builtIn: 1 + datasource: + type: grafana + uid: '-- Grafana --' + enable: true + hide: true + iconColor: rgba(0, 211, 255, 1) + name: Annotations & Alerts + type: dashboard + - datasource: + type: loki + uid: ${loki_datasource} + enable: true + expr: >- + {cluster="$cluster", container="kube-diff-logger"} | json | + namespace_extracted="$namespace" + hide: false + iconColor: yellow + instant: false + name: K8s Changes + tagKeys: type,name_extracted,verb + textFormat: '{{"{{notes}}"}}' + titleFormat: '' + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: >- + {namespace="$namespace",container="eventrouter"} != "Preemption is not + helpful" != "Failed deploy model" | logfmt | type="Warning" + hide: false + iconColor: orange + instant: false + name: K8s Warnings + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' + titleFormat: '' + - datasource: + type: loki + uid: ${loki_datasource} + enable: true + expr: >- + {namespace="$namespace",container="eventrouter"} | logfmt | + type!="Normal" | type!="Warning" + hide: false + iconColor: red + instant: false + name: K8s Errors + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: '{namespace="$namespace",container="eventrouter"} | logfmt' + hide: false + iconColor: blue + instant: false + name: K8s All Events + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' +editable: true +fiscalYearStartMonth: 0 +graphTooltip: 1 +id: 12198 +links: +{{ .Values.dashboards.links.global | toYaml | nindent 2}} +{{- with (dig $dashboard (list) .Values.dashboards.links.perDashboard) }} +{{ . | toYaml | nindent 2}} +{{- end }} +panels: + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 0 + id: 71 + panels: [] + title: Raft + type: row + - datasource: + type: prometheus + uid: ${datasource} + description: >- + Raft node roles observed by each node. The view is not meant to be 100% + consistent, and only serves monitoring purposes + fieldConfig: + defaults: + color: + mode: continuous-GrYlRd + custom: + axisPlacement: auto + fillOpacity: 15 + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineWidth: 1 + spanNulls: false + fieldMinMax: false + mappings: + - options: + from: 0 + result: + color: green + index: 0 + text: Follower + to: 99 + type: range + - options: + from: 100 + result: + color: dark-red + index: 1 + text: Leader + to: 1000000 + type: range + thresholds: + mode: absolute + steps: + - color: dark-blue + value: 0 + - color: light-red + value: 100 + unit: short + overrides: [] + gridPos: + h: 7 + w: 8 + x: 0 + 'y': 1 + id: 81 + options: + alignValue: center + legend: + displayMode: list + placement: bottom + showLegend: false + mergeValues: true + rowHeight: 0.8 + showValue: never + tooltip: + hideZeros: false + mode: multi + sort: asc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum by (pod) ( + pyroscope_metastore_raft_state{namespace="$namespace",state="Follower"} or + pyroscope_metastore_raft_state{namespace="$namespace",state="Leader"} * 100 + ) + format: time_series + hide: false + instant: false + legendFormat: '{{"{{label_name}}"}}' + range: true + refId: D + title: Raft Nodes + transparent: true + type: state-timeline + - datasource: + type: prometheus + uid: ${datasource} + description: The latency of raft commands observed by the metastore leader + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 1 + id: 68 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.995, + sum(rate(pyroscope_metastore_raft_apply_command_duration_seconds{ + namespace="$namespace", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.995, + sum(rate(pyroscope_metastore_raft_apply_command_duration_seconds_bucket{ + namespace="$namespace", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 + range: true + refId: D + title: Command Latency + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: The latency of raft read index observed by the metastore nodes + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 1 + id: 72 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_metastore_raft_read_index_wait_duration_seconds{ + namespace="$namespace", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_metastore_raft_read_index_wait_duration_seconds_bucket{ + namespace="$namespace", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 + range: true + refId: D + title: ReadIndex Latency + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: The time takes to write a snapshot + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 8 + id: 78 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + ( + histogram_quantile(0.99,(sum by (pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state="Leader"} >= 1) + ) + {{- else }} + expr: |- + ( + histogram_quantile(0.99,(sum by (le, pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state="Leader"} >= 1) + ) + {{- end }} + hide: false + instant: false + legendFormat: '{{"{{pod}}"}} Leader' + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + ( + histogram_quantile(0.99,(sum by (pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state!="Leader"} >= 1) + ) + {{- else }} + expr: |- + ( + histogram_quantile(0.99,(sum by (le, pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state!="Leader"} >= 1) + ) + {{- end }} + hide: false + instant: false + legendFormat: '{{"{{pod}}"}} Follower' + range: true + refId: A + title: Snapshot Latency + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: The size of BoltDB snapshot taken by FSM + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: decbytes + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 9 + id: 77 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + pyroscope_metastore_boltdb_persist_snapshot_size_bytes{namespace="$namespace"} + hide: false + instant: false + legendFormat: '{{"{{pod}}"}}' + range: true + refId: D + title: Snapshot Size + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: The time takes to apply the command onto FSM + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 9 + id: 79 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds_bucket{namespace="$namespace"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_metastore_fsm_apply_command_duration_seconds_bucket{namespace="$namespace"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p95 + range: true + refId: A + title: FSM Latency + transparent: true + type: timeseries + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 17 + id: 51 + panels: [] + title: Metadata Index Service + type: row + - datasource: + type: prometheus + uid: ${datasource} + description: |- + The latency of AddBlock endpoint observed by metastore nodes + + The only user is the segment-writer service. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + - id: custom.axisPlacement + value: right + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 18 + id: 49 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + ( + histogram_quantile(1,(sum by (pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state="Leader"} >= 1) + ) + {{- else }} + expr: |- + ( + histogram_quantile(1,(sum by (le, pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state="Leader"} >= 1) + ) + {{- end }} + hide: false + instant: false + legendFormat: Metastore leader snapshot ({{"{{pod}}"}}) + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p95 + range: true + refId: A + title: AddBlock Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 18 + id: 95 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 18 + id: 50 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: '' + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: |- + The latency of GetBlockMetadata endpoint observed by metastore nodes. + + The only user is the compaction-worker service. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 26 + id: 75 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/GetBlockMetadata", + }[$__rate_interval])) by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/GetBlockMetadata", + }[$__rate_interval])) by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/GetBlockMetadata", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/GetBlockMetadata", + }[$__rate_interval])) by (le)) + {{- end }} + hide: true + instant: false + legendFormat: p95 + range: true + refId: A + title: GetBlockMetadata Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 26 + id: 99 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/GetBlockMetadata" + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 26 + id: 76 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/GetBlockMetadata", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/GetBlockMetadata", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: '' + transparent: true + type: timeseries + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 34 + id: 89 + panels: [] + title: Metadata Query Service + type: row + - datasource: + type: prometheus + uid: ${datasource} + description: |- + The latency of QueryMetadata endpoint observed by metastore nodes. + + The only user is the query-frontend service. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 35 + id: 90 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) by (le)) + {{- end }} + hide: true + instant: false + legendFormat: p95 + range: true + refId: A + title: QueryMetadata Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 35 + id: 98 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 35 + id: 92 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: '' + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: |- + The latency of QueryMetadataLabels endpoint observed by metastore nodes. + + The only user is the query-frontend service. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 43 + id: 91 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) by (le)) + {{- end }} + hide: true + instant: false + legendFormat: p95 + range: true + refId: A + title: QueryMetadataLabels Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 43 + id: 96 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 43 + id: 93 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: '' + transparent: true + type: timeseries + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 51 + id: 86 + panels: [] + title: Compaction Service + type: row + - datasource: + type: prometheus + uid: ${datasource} + description: |- + The latency of PollCompactionJobs endpoint observed by metastore nodes. + + The only user is the compaction-worker service. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 52 + id: 87 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.CompactionService/PollCompactionJobs", + }[$__rate_interval])) by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.CompactionService/PollCompactionJobs", + }[$__rate_interval])) by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.CompactionService/PollCompactionJobs", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.CompactionService/PollCompactionJobs", + }[$__rate_interval])) by (le)) + {{- end }} + hide: true + instant: false + legendFormat: p95 + range: true + refId: A + title: PollCompactionJobs Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 52 + id: 97 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.CompactionService/PollCompactionJobs", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 52 + id: 88 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.CompactionService/PollCompactionJobs", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.CompactionService/PollCompactionJobs", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: '' + transparent: true + type: timeseries + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 60 + id: 67 + panels: [] + title: Resource Usage + type: row + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 61 + id: 65 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace="$namespace",container="metastore"}) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-metastore"} + ) + hide: true + legendFormat: Request + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-metastore"} + ) + hide: true + legendFormat: Limit + range: true + refId: B + title: CPU Usage + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: bytes + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 61 + id: 66 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(container_memory_working_set_bytes{namespace="$namespace", + container="metastore", image!=""}) by (pod) + hide: false + legendFormat: __auto + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-metastore"} + ) + hide: true + legendFormat: Requests + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="memory"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=".*-metastore"} + ) + hide: true + legendFormat: Limit + range: true + refId: C + title: Memory Usage + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: percentunit + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 61 + id: 84 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + kubelet_volume_stats_used_bytes{namespace="$namespace",persistentvolumeclaim=~".*metastore.*"} + / + + kubelet_volume_stats_capacity_bytes{namespace="$namespace",persistentvolumeclaim=~".*metastore.*"} + hide: false + legendFormat: '{{"{{persistentvolumeclaim}}"}}' + range: true + refId: C + title: Disk Usage + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: ops + overrides: [] + gridPos: + h: 9 + w: 6 + x: 0 + 'y': 69 + id: 85 + options: + legend: + calcs: + - mean + - max + - last + displayMode: table + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by(operation) + (rate(objstore_bucket_operations_total{namespace="$namespace",container="metastore"}[$__rate_interval])) + legendFormat: __auto + range: true + refId: A + title: Storage I/O + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 10 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: Bps + overrides: [] + gridPos: + h: 9 + w: 6 + x: 6 + 'y': 69 + id: 82 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_transmit_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) * on + (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*metastore.*"}) by + (namespace,pod)) * -1 + hide: false + legendFormat: tx {{"{{pod}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_receive_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) * on + (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*metastore.*"}) by + (namespace,pod)) + hide: false + legendFormat: rx {{"{{pod}}"}} + range: true + refId: B + title: Network + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: [] + gridPos: + h: 9 + w: 6 + x: 12 + 'y': 69 + id: 83 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (irate(container_fs_writes_total{namespace="$namespace",container="metastore"}[$__rate_interval])) + * -1 + format: time_series + hide: false + legendFormat: write {{"{{pod}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (irate(container_fs_reads_total{namespace="$namespace",container="metastore"}[$__rate_interval])) + hide: false + legendFormat: read {{"{{pod}}"}} + range: true + refId: B + title: Disk I/O + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: [] + gridPos: + h: 9 + w: 6 + x: 18 + 'y': 69 + id: 94 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: true + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: > + irate(node_disk_io_time_seconds_total{cluster="$cluster"}[$__rate_interval]) + + + on(instance, device) group_left(pod) + + topk by(instance, device) ( + 1, + 0 * label_replace( + container_blkio_device_usage_total{ + cluster="$cluster", + namespace="$namespace", + container="metastore", + operation="Write", + }, + "device", "$1", "device", "/dev/(.*)" + ) + ) + hide: false + legendFormat: '{{"{{pod}}/{{device}}"}}' + range: true + refId: A + title: Disk I/O Wait + transparent: true + type: timeseries + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 78 + id: 60 + panels: + - datasource: + type: datasource + uid: '-- Mixed --' + description: Number of OS threads created + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + unit: short + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 0 + 'y': 113 + id: 61 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: go_threads{namespace="$namespace",container="metastore"} + hide: false + legendFormat: '{{"{{pod}}"}}' + range: true + refId: D + title: Go Threads + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + unit: short + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 6 + 'y': 113 + id: 62 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (go_goroutines{namespace="$namespace",container="metastore"}) + hide: false + legendFormat: __auto + range: true + refId: D + title: Goroutines + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + unit: bytes + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 12 + 'y': 113 + id: 63 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (go_memstats_heap_inuse_bytes{namespace="$namespace",container="metastore"}) + hide: false + legendFormat: __auto + range: true + refId: D + title: Heap In-Use + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 18 + 'y': 113 + id: 64 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (container_file_descriptors{namespace="$namespace",container="metastore"}) + hide: false + legendFormat: __auto + range: true + refId: A + title: File Descriptors + transparent: true + type: timeseries + title: Runtime + type: row +preload: false +schemaVersion: 41 +tags: + - pyroscope + - pyroscope-v2 +templating: + list: + - current: + text: ops-cortex + value: '000000134' + includeAll: false + name: datasource + options: [] + query: prometheus + refresh: 1 + regex: '' + type: datasource + - allowCustomValue: false + current: + text: Grafana Logging + value: '000000193' + name: loki_datasource + options: [] + query: loki + refresh: 1 + regex: '' + type: datasource + - allowCustomValue: false + current: + text: {{.Values.dashboards.cluster | quote}} + value: {{.Values.dashboards.cluster | quote}} + datasource: + type: prometheus + uid: ${datasource} + definition: label_values(pyroscope_build_info{namespace="$namespace"},cluster) + label: cluster + name: cluster + options: [] + query: + qryType: 1 + query: label_values(pyroscope_build_info{namespace="$namespace"},cluster) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: '' + sort: 1 + type: query + - allowCustomValue: false + current: + text: {{.Values.dashboards.namespace | quote}} + value: {{.Values.dashboards.namespace | quote}} + datasource: + type: prometheus + uid: ${datasource} + definition: label_values(pyroscope_build_info,namespace) + label: namespace + name: namespace + options: [] + query: + qryType: 1 + query: label_values(pyroscope_build_info,namespace) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: {{ include "pyroscope-monitoring.dashboards-namespace-regex" (list . $dashboard) | quote }} + type: query +time: + from: now-6h + to: now +timepicker: {} +timezone: utc +title: Pyroscope v2 / Metastore + +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-read-path.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-read-path.yaml new file mode 100644 index 0000000000..b95c63665a --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-read-path.yaml @@ -0,0 +1,2762 @@ +{{- define "pyroscope-monitoring.dashboards.v2-read-path" -}} +{{- $dashboard := "v2-read-path" -}} +annotations: + list: + - builtIn: 1 + datasource: + type: grafana + uid: '-- Grafana --' + enable: true + hide: true + iconColor: rgba(0, 211, 255, 1) + name: Annotations & Alerts + type: dashboard + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: >- + {cluster="$cluster", container="kube-diff-logger"} | json | + namespace_extracted="$namespace" + hide: false + iconColor: yellow + instant: false + name: K8s Changes + tagKeys: type,name_extracted,verb + textFormat: '{{"{{notes}}"}}' + titleFormat: '' + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: >- + {namespace="$namespace",container="eventrouter"} != "Preemption is not + helpful" != "Failed deploy model" | logfmt | type="Warning" + hide: false + iconColor: orange + instant: false + name: K8s Warnings + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' + titleFormat: '' + - datasource: + type: loki + uid: ${loki_datasource} + enable: true + expr: >- + {namespace="$namespace",container="eventrouter"} | logfmt | + type!="Normal" | type!="Warning" + hide: false + iconColor: red + instant: false + name: K8s Errors + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: '{namespace="$namespace",container="eventrouter"} | logfmt' + hide: false + iconColor: blue + instant: false + name: K8s All events + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' +editable: true +fiscalYearStartMonth: 0 +graphTooltip: 1 +id: 12593 +links: +{{ .Values.dashboards.links.global | toYaml | nindent 2}} +{{- with (dig $dashboard (list) .Values.dashboards.links.perDashboard) }} +{{ . | toYaml | nindent 2}} +{{ end }} +panels: + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 0 + id: 68 + panels: + - datasource: + type: loki + uid: ${loki_datasource} + description: >- + SelectMergeProfile filtered out by default as the API is used by + Canary Exporter + fieldConfig: + defaults: + color: + mode: thresholds + custom: + align: auto + cellOptions: + type: auto + filterable: true + inspect: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: + - matcher: + id: byName + options: pod + properties: + - id: custom.width + value: 280 + - matcher: + id: byName + options: orgID + properties: + - id: custom.width + value: 86 + - matcher: + id: byName + options: uri + properties: + - id: custom.width + value: 312 + - matcher: + id: byName + options: Time + properties: + - id: custom.width + value: 179 + - matcher: + id: byName + options: Trace ID + properties: + - id: custom.width + value: 318 + - matcher: + id: byName + options: Endpoint + properties: + - id: custom.width + value: 420 + - matcher: + id: byName + options: Pod + properties: + - id: custom.width + value: 379 + - matcher: + id: byName + options: route + properties: + - id: custom.width + value: 347 + - matcher: + id: byName + options: Route + properties: + - id: custom.width + value: 363 + gridPos: + h: 8 + w: 24 + x: 0 + 'y': 1 + id: 69 + options: + cellHeight: sm + footer: + countRows: false + fields: '' + reducer: + - sum + show: false + showHeader: true + sortBy: + - desc: true + displayName: Time + targets: + - datasource: + type: loki + uid: ${loki_datasource} + direction: backward + editorMode: code + expr: >- + {namespace=~"$namespace",cluster=~"$cluster",container="query-frontend"} + + |= "route=/querier.v1." + + | logfmt | line_format "tenant={{"{{.orgID}} status={{.status}}"}} + duration={{"{{.duration}} traceID={{.traceID}} {{.uri}}"}}" + queryType: range + refId: A + title: All Queries + transformations: + - id: extractFields + options: + delimiter: ',' + format: json + keepTime: false + replace: false + source: labels + - id: organize + options: + excludeByName: + Drone build for Grafana: true + Drone build for Grafana Enterprise: true + Line: true + Okta Logs: true + Profile TraceID: true + TraceID (json): true + __adaptive_logs_sampled__: true + app_kubernetes_io_component: true + app_kubernetes_io_instance: true + app_kubernetes_io_name: true + caller: true + cluster: true + container: true + debug: true + detected_level: true + id: true + job: true + labelTypes: true + labels: true + level: true + method: true + msg: true + name: true + pod_template_hash: true + request_body_size: true + service_name: true + status: false + stream: true + test_run_id: true + traceID: true + traceID (label): true + traceID 1: true + trace_id (labels): true + ts: true + tsNs: true + includeByName: {} + indexByName: + Drone build for Grafana: 30 + Drone build for Grafana Enterprise: 31 + Line: 4 + Time: 1 + TraceID (json): 8 + TraceID (log line): 29 + app_kubernetes_io_component: 11 + app_kubernetes_io_instance: 12 + app_kubernetes_io_name: 13 + caller: 14 + cluster: 15 + container: 16 + detected_level: 17 + duration: 18 + id: 7 + job: 19 + labelTypes: 6 + labels: 0 + level: 20 + msg: 21 + name: 22 + namespace: 24 + pod: 23 + pod_template_hash: 25 + route: 3 + service_name: 26 + stream: 27 + tenant: 2 + test_run_id: 10 + traceID: 9 + traceID (label): 32 + trace_id (labels): 33 + ts: 28 + tsNs: 5 + renameByName: + Line: '' + Time: '' + TraceID: Trace ID + duration: Duration + labels: '' + namespace: Namespace + orgID: Tenant + pod: Pod + pod_template_hash: '' + route: Route + status: Status + tenant: Tenant + uri: Endpoint + transparent: true + type: table + - datasource: + type: tempo + uid: ${tempo_datasource} + fieldConfig: + defaults: + color: + mode: thresholds + custom: + align: auto + cellOptions: + type: auto + wrapText: false + filterable: true + inspect: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: + - matcher: + id: byName + options: Trace Name + properties: + - id: custom.width + value: 455 + - matcher: + id: byName + options: Trace ID + properties: + - id: custom.width + value: 311 + gridPos: + h: 10 + w: 24 + x: 0 + 'y': 9 + id: 70 + options: + cellHeight: sm + footer: + countRows: false + enablePagination: false + fields: '' + reducer: + - sum + show: false + frameIndex: 0 + showHeader: true + sortBy: + - desc: true + displayName: Start time + targets: + - datasource: + type: tempo + uid: ${tempo_datasource} + filters: + - id: d5be7410 + operator: '=' + scope: resource + tag: k8s.namespace.name + value: + - $namespace + valueType: string + - id: service-name + operator: '=' + scope: resource + tag: service.name + value: + - pyroscope-query-frontend + - pyroscope-query-backend + valueType: string + - id: min-duration + operator: '>' + tag: duration + value: 100ms + valueType: duration + - id: span-name + operator: '!=' + scope: span + tag: name + value: + - HTTP GET - debug_pprof + valueType: string + limit: 25 + metricsQueryType: instant + queryType: traceqlSearch + refId: A + spss: 5 + tableType: traces + title: Traces + transparent: true + type: table + title: Query Log + type: row + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 1 + id: 57 + panels: [] + title: Metadata Query Service (metastore) + type: row + - datasource: + type: prometheus + uid: ${datasource} + description: >- + Raft node roles observed by each node. The view is not meant to be 100% + consistent, and only serves monitoring purposes + fieldConfig: + defaults: + color: + mode: continuous-GrYlRd + custom: + axisPlacement: auto + fillOpacity: 15 + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineWidth: 1 + spanNulls: false + fieldMinMax: false + mappings: + - options: + from: 0 + result: + color: green + index: 0 + text: Follower + to: 99 + type: range + - options: + from: 100 + result: + color: dark-red + index: 1 + text: Leader + to: 1000000 + type: range + thresholds: + mode: absolute + steps: + - color: dark-blue + value: 0 + - color: light-red + value: 100 + unit: short + overrides: [] + gridPos: + h: 7 + w: 12 + x: 0 + 'y': 2 + id: 54 + options: + alignValue: center + legend: + displayMode: list + placement: bottom + showLegend: false + mergeValues: true + rowHeight: 0.8 + showValue: never + tooltip: + hideZeros: false + mode: multi + sort: asc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum by (pod) ( + pyroscope_metastore_raft_state{namespace="$namespace",state="Follower"} or + pyroscope_metastore_raft_state{namespace="$namespace",state="Leader"} * 100 + ) + format: time_series + hide: false + instant: false + legendFormat: '{{"{{label_name}}"}}' + range: true + refId: D + title: Raft Nodes + transparent: true + type: state-timeline + - datasource: + type: prometheus + uid: ${datasource} + description: |- + The latency of QueryMetadata endpoint observed by metastore nodes. + + The only user is the query-frontend service. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 7 + w: 6 + x: 12 + 'y': 2 + id: 56 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p95 + range: true + refId: A + title: QueryMetadata Latency + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: |- + The latency of QueryMetadataLabels endpoint observed by metastore nodes. + + The only user is the query-frontend service. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 7 + w: 6 + x: 18 + 'y': 2 + id: 55 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p95 + range: true + refId: A + title: QueryMetadataLabels Latency + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: The size of BoltDB snapshot taken by FSM + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: decbytes + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 7 + w: 12 + x: 0 + 'y': 9 + id: 60 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + pyroscope_metastore_boltdb_persist_snapshot_size_bytes{namespace="$namespace"} + hide: false + instant: false + legendFormat: '{{"{{pod}}"}}' + range: true + refId: D + title: Snapshot Size + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 7 + w: 6 + x: 12 + 'y': 9 + id: 58 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadata", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: '' + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 7 + w: 6 + x: 18 + 'y': 9 + id: 59 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.MetadataQueryService/QueryMetadataLabels", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: '' + transparent: true + type: timeseries + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 16 + id: 63 + panels: [] + title: Query Frontend + type: row + - datasource: + type: prometheus + uid: $datasource + description: Query rate observed by cortex-gw + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: true + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 1 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: reqps + overrides: [] + gridPos: + h: 9 + w: 12 + x: 0 + 'y': 17 + id: 67 + options: + dataLinks: [] + legend: + calcs: + - max + - mean + displayMode: table + placement: right + showLegend: true + tooltip: + hideZeros: true + mode: multi + sort: none + targets: + - datasource: + uid: $datasource + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (status_code) + (histogram_count(rate(pyroscope_request_duration_seconds{cluster=~"$cluster", + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[5m]))) + {{- else }} + expr: >- + sum by (status_code) + (rate(pyroscope_request_duration_seconds_count{cluster=~"$cluster", + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[5m])) + {{- end }} + legendFormat: '{{"{{status_code}}"}} ' + range: true + refId: A + title: Query rate + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: Query duration observed by cortex-gw + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 9 + w: 12 + x: 12 + 'y': 17 + id: 66 + options: + legend: + calcs: + - max + displayMode: table + placement: right + showLegend: true + sortBy: Name + sortDesc: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (route) ( + rate(pyroscope_request_duration_seconds{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, route) ( + rate(pyroscope_request_duration_seconds_bucket{{ "{" }}{{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + cluster=~"$cluster",route=~".*pyroscope_render.*|.*pyroscope_label.*|.*querierservice.*"}[$__rate_interval]))) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: Query Duartion + transparent: true + type: timeseries + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 26 + id: 61 + panels: [] + title: Query Backend + type: row + - datasource: + type: prometheus + uid: ${datasource} + description: > + Number of query-backend invocations. + + + Errors are expected: usually those indicate that the query is throttled + with the concurrency limiter. + + + If errors are presents in the query-frontend/gateway, the query is failed. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 6 + x: 0 + 'y': 27 + id: 64 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: D + title: Invocations + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: QueryBackend.Invoke latency observed by query-backend instances + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 6 + x: 6 + 'y': 27 + id: 62 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p95 + range: true + refId: A + title: Invocation Duration + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: QueryBackend.Invokeduration observed by query-backend instances + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: + - matcher: + id: byFrameRefID + options: B + properties: [] + gridPos: + h: 8 + w: 6 + x: 12 + 'y': 27 + id: 71 + options: + calculate: false + cellGap: 0 + cellValues: {} + color: + exponent: 0.5 + fill: dark-orange + mode: scheme + reverse: false + scale: exponential + scheme: Rainbow + steps: 64 + exemplars: + color: rgba(255,0,255,0.7) + filterValues: + le: 1.e-9 + legend: + show: true + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: false + yHistogram: false + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum (rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + status_code="success" + }[$__rate_interval])) + hide: false + instant: false + legendFormat: p99 + range: true + refId: D + title: Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + description: '' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 6 + x: 18 + 'y': 27 + id: 65 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval])) by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/query.v1.QueryBackendService/Invoke", + }[$__rate_interval])) by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: '{{"{{pod}}"}}' + range: true + refId: D + title: Breakdown + transparent: true + type: timeseries + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 35 + id: 32 + panels: [] + title: Resource Usage + type: row + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + overrides: + - matcher: + id: byFrameRefID + options: A + properties: + - id: custom.axisColorMode + value: text + - id: color + value: + fixedColor: orange + mode: fixed + - id: custom.lineWidth + value: 1 + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - id: custom.stacking + value: + group: A + mode: none + gridPos: + h: 8 + w: 6 + x: 0 + 'y': 36 + id: 29 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (irate(container_cpu_usage_seconds_total{namespace="$namespace",container="query-backend"}[$__rate_interval])) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-query-backend"} + ) + hide: false + legendFormat: Request + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-query-backend"} + ) + hide: false + legendFormat: Limit + range: true + refId: B + title: CPU Usage + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + overrides: + - matcher: + id: byFrameRefID + options: A + properties: + - id: custom.axisColorMode + value: text + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.stacking + value: + group: A + mode: none + - id: custom.lineWidth + value: 2 + - matcher: + id: byName + options: Request + properties: + - id: custom.stacking + value: + group: A + mode: none + - id: color + value: + fixedColor: yellow + mode: fixed + gridPos: + h: 8 + w: 6 + x: 6 + 'y': 36 + id: 72 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: right + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (irate(container_cpu_usage_seconds_total{namespace="$namespace",container="query-backend"}[$__rate_interval])) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum + (irate(container_cpu_usage_seconds_total{namespace="$namespace",container="query-backend"}[$__rate_interval])) + hide: false + legendFormat: Total + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(kube_pod_container_resource_requests{namespace="$namespace", + resource="cpu",container="query-backend"}) + hide: false + legendFormat: Request + range: true + refId: B + title: CPU Usage (stack) + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: bytes + overrides: + - matcher: + id: byName + options: Request + properties: + - id: color + value: + fixedColor: yellow + mode: fixed + - matcher: + id: byName + options: Limit + properties: + - id: color + value: + fixedColor: red + mode: fixed + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 36 + id: 30 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(container_memory_working_set_bytes{namespace="$namespace", + container="query-backend", image!=""}) by (pod) + hide: false + legendFormat: __auto + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + max(kube_pod_container_resource_requests{namespace="$namespace", + resource="memory",container="query-backend"}) + hide: false + legendFormat: Request + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + max (kube_pod_container_resource_limits{namespace="$namespace", + resource="memory",container="query-backend"}) + hide: false + legendFormat: Limit + range: true + refId: C + title: Memory Usage + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: ops + overrides: [] + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 44 + id: 31 + options: + legend: + calcs: + - mean + - max + - last + displayMode: table + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by(operation) + (irate(objstore_bucket_operations_total{namespace="$namespace",container="query-backend"}[$__rate_interval])) + legendFormat: __auto + range: true + refId: A + title: Storage I/O + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 10 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: Bps + overrides: [] + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 44 + id: 53 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_transmit_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) * on + (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*query-backend.*"}) by + (namespace,pod)) * -1 + hide: false + legendFormat: tx {{"{{pod}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + (sum(irate(container_network_receive_bytes_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, + cluster=~"$cluster", namespace=~"$namespace"}[$__rate_interval]) * on + (namespace,pod) + + group_left(workload,workload_type) + namespace_workload_pod:kube_pod_owner:relabel{cluster=~"$cluster", + namespace=~"$namespace", workload=~".*query-backend.*"}) by + (namespace,pod)) + hide: false + legendFormat: rx {{"{{pod}}"}} + range: true + refId: B + title: Network + transparent: true + type: timeseries + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 52 + id: 43 + panels: + - datasource: + type: datasource + uid: '-- Mixed --' + description: Number of OS threads created + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + unit: short + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 0 + 'y': 155 + id: 48 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: go_threads{namespace="$namespace",container="query-backend"} + hide: false + legendFormat: '{{"{{pod}}"}}' + range: true + refId: D + title: Go Threads + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + unit: short + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 6 + 'y': 155 + id: 46 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (go_goroutines{namespace="$namespace",container="query-backend"}) + hide: false + legendFormat: __auto + range: true + refId: D + title: Goroutines + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + unit: bytes + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 12 + 'y': 155 + id: 44 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (go_memstats_heap_inuse_bytes{namespace="$namespace",container="query-backend"}) + hide: false + legendFormat: __auto + range: true + refId: D + title: Heap In-Use + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + gridPos: + h: 8 + w: 6 + x: 18 + 'y': 155 + id: 45 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (container_file_descriptors{namespace="$namespace",container="query-backend"}) + hide: false + legendFormat: __auto + range: true + refId: A + title: File Descriptors + transparent: true + type: timeseries + title: Runtime + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 53 + id: 42 + panels: + - datasource: + type: loki + uid: OP27Xzxnk + fieldConfig: + defaults: {} + overrides: [] + gridPos: + h: 8 + w: 24 + x: 0 + 'y': 156 + id: 41 + options: + dedupStrategy: none + enableInfiniteScrolling: false + enableLogDetails: true + prettifyLogMessage: false + showCommonLabels: false + showLabels: false + showTime: false + sortOrder: Descending + wrapLogMessage: false + targets: + - datasource: + type: loki + uid: OP27Xzxnk + direction: backward + editorMode: code + expr: >- + {cluster="$cluster", namespace="$namespace", + container="query-backend"} |= "level=err" or "level=warn" or + "panic" + queryType: range + refId: A + title: Worker log + transparent: true + type: logs + title: Errors and warnings + type: row +preload: false +schemaVersion: 41 +tags: + - pyroscope + - pyroscope-v2 +templating: + list: + - allowCustomValue: true + current: + text: ops-cortex + value: '000000134' + label: metrics + name: datasource + options: [] + query: prometheus + refresh: 1 + regex: '' + type: datasource + - allowCustomValue: false + current: + text: Grafana Logging + value: '000000193' + description: '' + label: logs + name: loki_datasource + options: [] + query: loki + refresh: 1 + regex: '' + type: datasource + - allowCustomValue: false + current: + text: Tempo Ops (tempo-ops-01) + value: fds8vtxx3ao74b + description: '' + label: traces + name: tempo_datasource + options: [] + query: tempo + refresh: 1 + regex: '' + type: datasource + - allowCustomValue: false + current: + text: {{.Values.dashboards.cluster | quote}} + value: {{.Values.dashboards.cluster | quote}} + datasource: + type: prometheus + uid: ${datasource} + definition: label_values(pyroscope_build_info{namespace="$namespace"},cluster) + label: cluster + name: cluster + options: [] + query: + qryType: 1 + query: label_values(pyroscope_build_info{namespace="$namespace"},cluster) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: '' + sort: 1 + type: query + - allowCustomValue: false + current: + text: {{.Values.dashboards.namespace | quote}} + value: {{.Values.dashboards.namespace | quote}} + datasource: + type: prometheus + uid: ${datasource} + definition: label_values(pyroscope_build_info,namespace) + label: namespace + name: namespace + options: [] + query: + qryType: 1 + query: label_values(pyroscope_build_info,namespace) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: {{ include "pyroscope-monitoring.dashboards-namespace-regex" (list . $dashboard) | quote }} + type: query +time: + from: now-6h + to: now +timepicker: {} +timezone: utc +title: Pyroscope v2 / Read Path + +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-write-path.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-write-path.yaml new file mode 100644 index 0000000000..25d4c828e6 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboard_v2-write-path.yaml @@ -0,0 +1,4840 @@ +{{- define "pyroscope-monitoring.dashboards.v2-write-path" -}} +{{- $dashboard := "v2-write-path" -}} +annotations: + list: + - builtIn: 1 + datasource: + type: grafana + uid: '-- Grafana --' + enable: true + hide: true + iconColor: rgba(0, 211, 255, 1) + name: Annotations & Alerts + type: dashboard + - datasource: + type: loki + uid: ${loki_datasource} + enable: true + expr: >- + {cluster="$cluster", container="kube-diff-logger"} | json | + namespace_extracted="$namespace" + hide: false + iconColor: yellow + instant: false + name: K8s Changes + tagKeys: type,name_extracted,verb + textFormat: '{{"{{notes}}"}}' + titleFormat: '' + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: >- + {namespace="$namespace",container="eventrouter"} != "Preemption is not + helpful" != "Failed deploy model" | logfmt | type="Warning" + hide: false + iconColor: orange + instant: false + name: K8s Warnings + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' + titleFormat: '' + - datasource: + type: loki + uid: ${loki_datasource} + enable: true + expr: >- + {namespace="$namespace",container="eventrouter"} | logfmt | + type!="Normal" | type!="Warning" + hide: false + iconColor: red + instant: false + name: K8s Errors + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' + - datasource: + type: loki + uid: ${loki_datasource} + enable: false + expr: '{namespace="$namespace",container="eventrouter"} | logfmt' + hide: false + iconColor: blue + instant: false + name: K8s All Events + tagKeys: type,object_kind,object_name + textFormat: '{{"{{message}}"}}' +editable: true +fiscalYearStartMonth: 0 +graphTooltip: 1 +id: 0 +links: +{{ .Values.dashboards.links.global | toYaml | nindent 2}} +{{- with (dig $dashboard (list) .Values.dashboards.links.perDashboard) }} +{{ . | toYaml | nindent 2}} +{{ end }} +panels: + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 0 + id: 85 + panels: [] + title: '' + type: row + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: thresholds + custom: + align: left + cellOptions: + type: auto + filterable: true + footer: + reducers: + - countAll + inspect: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: + - matcher: + id: byName + options: Value + properties: + - id: unit + value: decbytes + - matcher: + id: byName + options: tenant + properties: + - id: custom.width + value: 78 + - matcher: + id: byName + options: slug + properties: + - id: custom.width + value: 132 + - matcher: + id: byName + options: org_name + properties: + - id: custom.width + value: 142 + - matcher: + id: byName + options: Value + properties: + - id: custom.cellOptions + value: + mode: lcd + type: gauge + valueDisplayMode: text + - id: color + value: + fixedColor: green + mode: fixed + - matcher: + id: byName + options: Slug + properties: + - id: custom.width + value: 89 + - matcher: + id: byName + options: Name + properties: + - id: custom.width + value: 143 + - matcher: + id: byName + options: ID + properties: + - id: custom.width + value: 104 + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 1 + id: 68 + options: + cellHeight: sm + enablePagination: false + showHeader: true + sortBy: + - desc: true + displayName: Value + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: | + {{ tpl .Values.dashboards.tenantQuery . | nindent 10 }} + format: table + instant: true + legendFormat: __auto + range: false + refId: A + title: Tenants + transformations: + - id: organize + options: + excludeByName: + Time: true + Value: false + cluster: true + environment: true + slug: false + includeByName: {} + indexByName: + Time: 0 + Value: 4 + environment: 5 + org_name: 3 + slug: 2 + tenant: 1 + renameByName: + Time: '' + Value: '' + environment: Env + org_name: Name + slug: Slug + tenant: ID + type: table + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 10 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: binBps + overrides: [] + gridPos: + h: 8 + w: 4 + x: 8 + 'y': 1 + id: 66 + options: + legend: + calcs: + - max + displayMode: table + placement: right + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (tenant) + (histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (tenant) + (rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + hide: false + legendFormat: __auto + range: true + refId: A + title: MBs per Tenant (Decompressed) + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 4 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: cps + overrides: [] + gridPos: + h: 8 + w: 4 + x: 12 + 'y': 1 + id: 67 + options: + legend: + calcs: + - mean + - max + displayMode: table + placement: right + showLegend: false + sortBy: Mean + sortDesc: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (tenant) + (histogram_count(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (tenant) + (rate(pyroscope_distributor_received_decompressed_bytes_count{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Profiles/s per Tenant + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + hideFrom: + legend: false + tooltip: false + viz: false + mappings: [] + overrides: [] + gridPos: + h: 8 + w: 4 + x: 16 + 'y': 1 + id: 82 + options: + legend: + displayMode: table + placement: bottom + showLegend: true + values: + - value + pieType: pie + reduceOptions: + calcs: + - lastNotNull + fields: '' + values: false + sort: desc + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: >- + sum by (state) (pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="distributor"}) / count by + (state)(pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="distributor"}) + format: time_series + instant: true + legendFormat: __auto + range: false + refId: A + title: Distributor Ring + type: piechart + - datasource: + type: prometheus + uid: ${datasource} + description: 'The ring is used by distributor to discover segment-writer instances. ' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + hideFrom: + legend: false + tooltip: false + viz: false + mappings: [] + overrides: [] + gridPos: + h: 8 + w: 4 + x: 20 + 'y': 1 + id: 81 + options: + legend: + displayMode: table + placement: bottom + showLegend: true + values: + - value + pieType: pie + reduceOptions: + calcs: + - lastNotNull + fields: '' + values: false + sort: desc + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: >- + sum by (state) (pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="segment-writer"}) / count by + (state)(pyroscope_ring_members{cluster=~"$cluster", + namespace=~"$namespace", name="segment-writer"}) + format: time_series + instant: true + legendFormat: __auto + range: false + refId: A + title: Segment Writer Ring + type: piechart +{{- if .Values.dashboards.cloudBackendGateway }} + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 9 + id: 43 + panels: [] + title: Cortex Gateway + type: row + - datasource: + type: datasource + uid: '-- Mixed --' + description: >- + The latency observed by cortex-gw, indicating the overall write path + latency. + + + Only successful requests are counted. + + * the purple line (1s) is our internal SLO + * the red line (2s) is the threshold when we start burning SLO budget + fieldConfig: + defaults: + color: + fixedColor: dark-red + mode: palette-classic + custom: + axisBorderShow: true + axisCenteredZero: true + axisColorMode: text + axisGridShow: true + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 1 + scaleDistribution: + log: 10 + type: log + showPoints: never + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: dashed + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: purple + value: 1 + - color: red + value: 2 + unit: s + overrides: + - matcher: + id: byName + options: p999 + properties: + - id: color + value: + fixedColor: green + mode: fixed + - matcher: + id: byName + options: p999 envoy-upstream + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: envoy-upstream p999 + properties: + - id: color + value: + fixedColor: orange + mode: fixed + - __systemRef: hideSeriesFrom + matcher: + id: byNames + options: + mode: exclude + names: + - p99 + - p95 + - p90 + - avg + - p50 + prefix: 'All except:' + readOnly: true + properties: + - id: custom.hideFrom + value: + legend: false + tooltip: true + viz: true + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 10 + id: 40 + options: + legend: + calcs: + - mean + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + histogram_quantile(0.999, + sum by(cluster, namespace,le) (rate(envoy_cluster_upstream_rq_time_bucket{ + namespace="$namespace", + container="envoy", + }[$__rate_interval])) + ) / 1000 + hide: false + legendFormat: envoy-upstream p999 + range: true + refId: F + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: | + histogram_quantile(0.999, + sum by(cluster, namespace,pod,le) (rate(envoy_cluster_external_upstream_rq_time_bucket{ + namespace="$namespace", + container="envoy", + }[$__rate_interval])) + ) / 1000 + hide: true + legendFormat: p999 envoy-upstream-external + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.999, sum by (status_code) + (rate(pyroscope_request_duration_seconds{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.999, sum by (le, status_code) + (rate(pyroscope_request_duration_seconds_bucket{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: p999 + range: true + refId: E + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (status_code) + (rate(pyroscope_request_duration_seconds{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, status_code) + (rate(pyroscope_request_duration_seconds_bucket{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: p99 + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, sum by (status_code) + (rate(pyroscope_request_duration_seconds{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, sum by (le, status_code) + (rate(pyroscope_request_duration_seconds_bucket{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: p95 + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.50, sum by (status_code) + (rate(pyroscope_request_duration_seconds{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}, namespace=~"$namespace", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.50, sum by (le, status_code) + (rate(pyroscope_request_duration_seconds_bucket{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: p50 + range: true + refId: C + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + histogram_avg(sum (rate(pyroscope_request_duration_seconds{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- else }} + expr: |- + sum(rate(pyroscope_request_duration_seconds_sum{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval])) / sum(rate(pyroscope_request_duration_seconds_count{ + {{ include "pyroscope-monitoring.dashboards-ingest-selector" . }}{{ include "pyroscope-monitoring.dashboards-ingest-namespace-selector" . }}, + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval])) + {{- end }} + hide: false + legendFormat: avg + range: true + refId: G + title: Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 10 + id: 53 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + route=~".*push.*|.*ingest.*", + container="cortex-gw", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + log: 2 + type: log + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: reqps + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 10 + id: 41 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (status_code) (histogram_count(rate( + pyroscope_request_duration_seconds{ + namespace="$namespace", + container="cortex-gw", + route=~".*push.*|.*ingest.*", + }[1m])) + ) + {{- else }} + expr: |- + sum by (status_code) (rate( + pyroscope_request_duration_seconds_count{ + namespace="$namespace", + container="cortex-gw", + route=~".*push.*|.*ingest.*", + }[1m]) + ) + {{- end }} + hide: false + legendFormat: __auto + range: true + refId: A + title: Rate + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: [] + gridPos: + h: 7 + w: 8 + x: 0 + 'y': 18 + id: 99 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (direction,pod) + (conntrack_pod_connections{namespace="$namespace",pod=~"cortex-gw-.*"}) + hide: false + legendFormat: '{{"{{pod}} {{direction}}"}}' + range: true + refId: A + title: Connections per pod + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: binBps + overrides: [] + gridPos: + h: 7 + w: 8 + x: 8 + 'y': 18 + id: 108 + options: + legend: + calcs: [] + displayMode: table + placement: right + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by(pod) + (rate(container_network_receive_bytes_total{namespace="$namespace", + cluster="$cluster", pod=~"cortex-gw.*"}[$__rate_interval])) + hide: false + legendFormat: '{{"{{pod}} {{direction}}"}}' + range: true + refId: A + title: MBs container received per pod + transparent: true + type: timeseries +{{- end }} + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 25 + id: 90 + panels: + - datasource: + type: datasource + uid: '-- Mixed --' + description: >- + The latency observed by distributor, indicating the overall write path + latency. + + + Only successful requests are counted. + fieldConfig: + defaults: + color: + fixedColor: dark-red + mode: palette-classic + custom: + axisBorderShow: true + axisCenteredZero: true + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 1 + scaleDistribution: + type: linear + showPoints: never + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: s + overrides: + - matcher: + id: byName + options: p99 overall + properties: + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 34 + id: 94 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, sum by (pod) + (rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + container="distributor", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, sum by (le, pod) + (rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + container="distributor", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- end }} + hide: false + legendFormat: __auto + range: true + refId: E + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + container="distributor", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + container="distributor", + route=~".*pusher.*|.*ingest.*", + status_code="200", + }[$__rate_interval])) by (le)) + {{- end }} + hide: true + legendFormat: p99 overall + range: true + refId: A + title: Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 34 + id: 93 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + container="distributor", + route=~".*push.*|.*ingest.*", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + log: 2 + type: log + showPoints: never + spanNulls: true + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: reqps + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 34 + id: 42 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (status_code) (histogram_count(rate( + pyroscope_request_duration_seconds{ + namespace="$namespace", + container="distributor", + route=~".*push.*|.*ingest.*", + }[1m])) + ) + {{- else }} + expr: |- + sum by (status_code) (rate( + pyroscope_request_duration_seconds_count{ + namespace="$namespace", + container="distributor", + route=~".*push.*|.*ingest.*", + }[1m]) + ) + {{- end }} + instant: false + legendFormat: __auto + range: true + refId: A + title: Rate + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: >- + The latency observed by distributors (write path router), broken down + by instance. + + + Latencies are expected to be distributed evenly across instances. An + outlier here likely indicates a neighborhood issue. + + + Only successful requests are counted. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + log: 2 + type: log + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: [] + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 42 + id: 72 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_write_path_downstream_request_duration_seconds{ + namespace="$namespace", + status="200", + primary="1", + }[$__rate_interval])) by (route,pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_write_path_downstream_request_duration_seconds_bucket{ + namespace="$namespace", + status="200", + primary="1", + }[$__rate_interval])) by (le, route,pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 primary {{"{{pod}} => {{route}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_write_path_downstream_request_duration_seconds{ + namespace="$namespace", + status="200", + primary!="1", + }[$__rate_interval])) by (route,pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_write_path_downstream_request_duration_seconds_bucket{ + namespace="$namespace", + status="200", + primary!="1", + }[$__rate_interval])) by (le, route,pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 secondary {{"{{pod}} => {{route}}"}} + range: true + refId: B + title: Downstream Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + description: The latency observed by the segment-writer client + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 42 + id: 56 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_write_path_downstream_request_duration_seconds{ + namespace="$namespace", + route="segment-writer", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + log: 2 + type: log + showPoints: never + spanNulls: true + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: reqps + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 42 + id: 95 + options: + legend: + calcs: + - last + displayMode: table + placement: right + showLegend: false + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: multi + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum(histogram_count(irate(pyroscope_write_path_downstream_request_duration_seconds{ + namespace="$namespace", + primary="1", + }[$__rate_interval]))) by (status,route) + {{- else }} + expr: >- + sum(irate(pyroscope_write_path_downstream_request_duration_seconds_count{ + namespace="$namespace", + primary="1", + }[$__rate_interval])) by (status,route) + {{- end }} + instant: false + legendFormat: primary {{"{{route}} {{status}}"}} + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum(histogram_count(irate(pyroscope_write_path_downstream_request_duration_seconds{ + namespace="$namespace", + primary="0", + }[$__rate_interval]))) by (status,route) + {{- else }} + expr: >- + sum(irate(pyroscope_write_path_downstream_request_duration_seconds_count{ + namespace="$namespace", + primary="0", + }[$__rate_interval])) by (status,route) + {{- end }} + hide: false + instant: false + legendFormat: secondary {{"{{route}} {{status}}"}} + range: true + refId: C + title: Downstream Rate + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + unit: bytes + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - matcher: + id: byFrameRefID + options: A + properties: + - id: custom.axisColorMode + value: text + - id: color + value: + fixedColor: semi-dark-red + mode: fixed + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 50 + id: 97 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (container_memory_working_set_bytes{namespace="$namespace",container="distributor"}) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + max(kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, + namespace="$namespace", resource="memory", + container="distributor"}) + hide: false + legendFormat: Request + range: true + refId: A + title: Memory Usage + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - matcher: + id: byFrameRefID + options: A + properties: + - id: custom.axisColorMode + value: text + - id: color + value: + fixedColor: semi-dark-red + mode: fixed + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 50 + id: 62 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace="$namespace",container="distributor"}) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-distributor"} + ) + hide: false + legendFormat: Request + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-distributor"} + ) + hide: false + legendFormat: Limit + range: true + refId: B + title: CPU Usage + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: >- + The chart showd distribution of requests from the upstream + (cortex-gw/envoy) + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + log: 2 + type: log + showPoints: never + spanNulls: true + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: reqps + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 50 + id: 98 + options: + legend: + calcs: + - last + displayMode: table + placement: right + showLegend: false + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: single + sort: asc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum by (pod) (histogram_count(rate( + pyroscope_request_duration_seconds{ + namespace="$namespace", + container="distributor", + route=~".*push.*|.*ingest.*", + }[1m])) + ) + {{- else }} + expr: |- + sum by (pod) (rate( + pyroscope_request_duration_seconds_count{ + namespace="$namespace", + container="distributor", + route=~".*push.*|.*ingest.*", + }[1m]) + ) + {{- end }} + instant: false + legendFormat: __auto + range: true + refId: A + title: Upstream Distribution + transparent: true + type: timeseries + title: Distributor + type: row + - collapsed: false + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 26 + id: 47 + panels: [] + title: Segment Writer + type: row + - datasource: + type: prometheus + uid: ${datasource} + description: The latency of the Push endpoint observed by segment-writer. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: Overall p99 + properties: + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: green + mode: fixed + - matcher: + id: byFrameRefID + properties: [] + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 27 + id: 79 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval])) by (pod)) + {{- else }} + expr: |- + histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval])) by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval]))) + {{- else }} + expr: |- + histogram_quantile(0.99, sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 overall + range: true + refId: Overall p99 + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + histogram_quantile(0.90, sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval]))) + {{- else }} + expr: |- + histogram_quantile(0.90, sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p90 overall + range: true + refId: Overall p90 + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.50, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.50, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p50 overall + range: true + refId: Overall p50 + title: Push Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + description: The latency of the Push endpoint observed by segment-writer + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 27 + id: 76 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + container="segment-writer", + method="gRPC", + # status_code="success", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + log: 2 + type: log + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: reqps + overrides: [] + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 27 + id: 52 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(irate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(irate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + route="/segmentwriter.v1.SegmentWriterService/Push", + }[$__rate_interval])) by (status_code) + {{- end }} + instant: false + legendFormat: __auto + range: true + refId: A + title: Push Rate + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: >- + The latency segment-writer observes when uploading segments to object + store, including retries. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: Overall p99 + properties: + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: green + mode: fixed + - matcher: + id: byFrameRefID + properties: [] + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 35 + id: 57 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 overall + range: true + refId: Overall p99 + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.90, + sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.90, + sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p90 overall + range: true + refId: Overall p90 + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.50, + sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.50, + sum(rate(pyroscope_segment_writer_upload_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p50 overall + range: true + refId: Overall p50 + title: Object Store Upload Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + description: The latency of upload calls observed by the segment-writer + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 35 + id: 80 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(rate(pyroscope_segment_writer_upload_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + description: New objects created by segment-writer + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + showValues: false + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.axisPlacement + value: right + - id: custom.axisLabel + value: Hedged requests + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 35 + id: 59 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (status) + (histogram_count(rate(pyroscope_segment_writer_upload_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (status) + (rate(pyroscope_segment_writer_upload_duration_seconds_count{namespace="$namespace"}[$__rate_interval])) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (status) + (histogram_count(rate(pyroscope_segment_writer_hedged_upload_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (status) + (rate(pyroscope_segment_writer_hedged_upload_duration_seconds_count{namespace="$namespace"}[$__rate_interval])) + {{- end }} + hide: false + instant: false + legendFormat: '{{"{{status}}"}} (hedged)' + range: true + refId: B + title: Object Store Upload Rate + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: >- + The latency segment-writer observes when adding metadata entries to + metastore, including retries. + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: Overall p99 + properties: + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: green + mode: fixed + - matcher: + id: byFrameRefID + properties: [] + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 43 + id: 77 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + by (pod)) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + by (le, pod)) + {{- end }} + hide: false + instant: false + legendFormat: p99 {{"{{pod}}"}} + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 overall + range: true + refId: Overall p99 + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.90, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.90, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p90 overall + range: true + refId: Overall p90 + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.50, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.50, + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds_bucket{namespace="$namespace",container="segment-writer"}[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p50 overall + range: true + refId: Overall p50 + title: Store Metadata Latency + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + description: >- + The latency segment-writer observes when adding metadata entries, + including retries + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 43 + id: 78 + options: + calculate: false + calculation: + xBuckets: + mode: count + value: '' + yBuckets: + mode: count + scale: + type: linear + cellGap: 0 + cellValues: + unit: requests + color: + exponent: 0.2 + fill: super-light-red + mode: scheme + reverse: true + scale: exponential + scheme: Turbo + steps: 128 + exemplars: + color: orange + filterValues: + le: 1.e-9 + legend: + show: false + rowsFrame: + layout: auto + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisPlacement: left + reverse: false + unit: s + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + hide: false + legendFormat: __auto + range: true + refId: B + title: Latency Heatmap + transparent: true + type: heatmap + - datasource: + type: prometheus + uid: ${datasource} + description: New metadata entries created by segment-writers + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 43 + id: 73 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (status) + (histogram_count(rate(pyroscope_segment_writer_store_metadata_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (status) + (rate(pyroscope_segment_writer_store_metadata_duration_seconds_count{namespace="$namespace"}[$__rate_interval])) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (status) + (rate(pyroscope_segment_writer_store_metadata_dql{namespace="$namespace"}[$__rate_interval])) + hide: false + instant: false + legendFormat: '{{"{{status}}"}} (DLQ)' + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(rate(pyroscope_segment_writer_store_metadata_dlq{namespace="$namespace"}[$__rate_interval])) + hide: false + instant: false + legendFormat: dlq + range: true + refId: C + title: Store Metadata Rate + transparent: true + type: timeseries + - datasource: + default: false + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: bytes + overrides: [] + gridPos: + h: 8 + w: 8 + x: 0 + 'y': 51 + id: 21 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (pod) + (histogram_sum(irate(pyroscope_segment_writer_segment_ingest_bytes{namespace="$namespace", + container="segment-writer"}[10m]))) / + + sum by (pod) + (rate(container_cpu_usage_seconds_total{namespace="$namespace", + container="segment-writer"}[10m])) + {{- else }} + expr: >- + sum by (pod) + (irate(pyroscope_segment_writer_segment_ingest_bytes_sum{namespace="$namespace", + container="segment-writer"}[10m])) / + + sum by (pod) + (rate(container_cpu_usage_seconds_total{namespace="$namespace", + container="segment-writer"}[10m])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Processing Rate (MB/sec/core) + transparent: true + type: timeseries + - datasource: + type: datasource + uid: '-- Mixed --' + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 1 + barWidthFactor: 1 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineStyle: + fill: solid + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + fieldMinMax: false + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + overrides: + - matcher: + id: byName + options: Limit + properties: + - id: custom.lineStyle + value: + dash: + - 10 + - 10 + fill: dash + - matcher: + id: byFrameRefID + options: A + properties: + - id: custom.axisColorMode + value: text + - id: color + value: + fixedColor: semi-dark-red + mode: fixed + - id: custom.lineWidth + value: 2 + gridPos: + h: 8 + w: 8 + x: 8 + 'y': 51 + id: 63 + options: + legend: + calcs: + - last + - max + displayMode: table + placement: bottom + showLegend: false + sortBy: Max + sortDesc: true + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum by (pod) + (irate(container_cpu_usage_seconds_total{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + legendFormat: __auto + range: true + refId: by pod + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_requests{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-segment-writer"} + ) + hide: false + legendFormat: Request + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + max( + kube_pod_container_resource_limits{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, namespace="$namespace", resource="cpu"} + * on(namespace,pod) + group_left(workload) namespace_workload_pod:kube_pod_owner:relabel{namespace="$namespace", workload=~".*-segment-writer"} + ) + hide: false + legendFormat: Limit + range: true + refId: B + title: CPU Usage + transparent: true + type: timeseries + - datasource: + default: false + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 7 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: short + overrides: + - matcher: + id: byName + options: Total + properties: + - id: custom.axisPlacement + value: right + - id: custom.lineWidth + value: 2 + - id: color + value: + fixedColor: red + mode: fixed + gridPos: + h: 8 + w: 8 + x: 16 + 'y': 51 + id: 27 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: false + sortBy: Mean + sortDesc: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(irate(container_cpu_usage_seconds_total{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + by (pod) + legendFormat: __auto + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: >- + sum(irate(container_cpu_usage_seconds_total{namespace="$namespace",container="segment-writer"}[$__rate_interval])) + hide: false + legendFormat: Total + range: true + refId: B + title: CPU Usage (stack) + transparent: true + type: timeseries + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 59 + id: 51 + panels: + - datasource: + type: prometheus + uid: ${datasource} + description: The latency of raft commands observed by the metastore leader + fieldConfig: + defaults: + color: + mode: continuous-GrYlRd + custom: + axisPlacement: auto + fillOpacity: 15 + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineWidth: 1 + spanNulls: false + fieldMinMax: false + mappings: + - options: + from: 0 + result: + color: green + index: 0 + text: Follower + to: 99 + type: range + - options: + from: 100 + result: + color: dark-red + index: 1 + text: Leader + to: 1000000 + type: range + thresholds: + mode: absolute + steps: + - color: dark-blue + value: 0 + - color: light-red + value: 100 + unit: short + overrides: [] + gridPos: + h: 5 + w: 24 + x: 0 + 'y': 106 + id: 65 + options: + alignValue: center + legend: + displayMode: list + placement: bottom + showLegend: false + mergeValues: true + rowHeight: 0.8 + showValue: never + tooltip: + hideZeros: false + mode: multi + sort: asc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + sum by (pod) ( + pyroscope_metastore_raft_state{namespace="$namespace",state="Follower"} or + pyroscope_metastore_raft_state{namespace="$namespace",state="Leader"} * 100 + ) + format: time_series + hide: false + instant: false + legendFormat: '{{"{{label_name}}"}}' + range: true + refId: D + title: Raft Nodes + transparent: true + type: state-timeline + - datasource: + type: prometheus + uid: ${datasource} + description: The latency of AddBlock endpoint observed by metastore nodes + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: s + overrides: + - matcher: + id: byFrameRefID + options: B + properties: + - id: custom.drawStyle + value: points + - id: color + value: + fixedColor: red + mode: fixed + - id: custom.pointSize + value: 11 + - id: custom.axisPlacement + value: right + gridPos: + h: 8 + w: 12 + x: 0 + 'y': 111 + id: 49 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + ( + histogram_quantile(0.99,(sum by (pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state="Leader"} >= 1) + ) + {{- else }} + expr: |- + ( + histogram_quantile(0.99,(sum by (le, pod) ( + irate(pyroscope_metastore_boltdb_persist_snapshot_duration_seconds_bucket{namespace="$namespace"}[$__rate_interval]))) + ) * on(pod) group_left() (pyroscope_metastore_raft_state{namespace="$namespace", state="Leader"} >= 1) + ) + {{- end }} + hide: false + instant: false + legendFormat: Metastore leader snapshot ({{"{{pod}}"}}) + range: true + refId: B + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.99, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p99 + range: true + refId: D + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval]))) + {{- else }} + expr: >- + histogram_quantile(0.95, + sum(rate(pyroscope_request_duration_seconds_bucket{ + namespace="$namespace", + method="gRPC", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) by (le)) + {{- end }} + hide: false + instant: false + legendFormat: p95 + range: true + refId: A + title: Latency + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + min: 0 + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: ops + overrides: + - matcher: + id: byName + options: error + properties: + - id: color + value: + fixedColor: red + mode: fixed + - matcher: + id: byName + options: success + properties: + - id: color + value: + fixedColor: green + mode: fixed + gridPos: + h: 8 + w: 12 + x: 12 + 'y': 111 + id: 50 + options: + legend: + calcs: [] + displayMode: list + placement: bottom + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: |- + sum(histogram_count(rate(pyroscope_request_duration_seconds{ + namespace="$namespace", + method="gRPC", + container="metastore", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval]))) by (status_code) + {{- else }} + expr: |- + sum(rate(pyroscope_request_duration_seconds_count{ + namespace="$namespace", + method="gRPC", + container="metastore", + route="/metastore.v1.IndexService/AddBlock", + }[$__rate_interval])) by (status_code) + {{- end }} + hide: false + instant: false + legendFormat: '{{"{{status_code}}"}}' + range: true + refId: D + title: '' + transparent: true + type: timeseries + title: Metastore + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 60 + id: 22 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: continuous-BlYlRd + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 3 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: [] + gridPos: + h: 9 + w: 17 + x: 0 + 'y': 69 + id: 44 + options: + legend: + calcs: + - lastNotNull + - mean + displayMode: table + placement: right + showLegend: true + sortBy: Last * + sortDesc: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + sum by (dataset, tenant) ( + pyroscope_adaptive_placement_dataset_shard_limit{namespace="$namespace"} + ) > 1 + legendFormat: '{{"{{tenant}}/{{dataset}}"}}' + range: true + refId: A + title: Dataset Shards + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + description: Top-10 + fieldConfig: + defaults: + color: + mode: continuous-BlYlRd + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 3 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: [] + gridPos: + h: 9 + w: 7 + x: 17 + 'y': 69 + id: 107 + options: + legend: + calcs: + - lastNotNull + displayMode: table + placement: right + showLegend: true + sortBy: Last * + sortDesc: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + topk(10, count by (tenant) (sum by (dataset, tenant) ( + pyroscope_adaptive_placement_dataset_shard_limit{namespace="$namespace"} + ))) + legendFormat: '{{"{{tenant}}"}}' + range: true + refId: A + title: Datasets per tenant + transparent: true + type: timeseries + - datasource: + default: false + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + custom: + hideFrom: + legend: false + tooltip: false + viz: false + scaleDistribution: + type: linear + overrides: [] + gridPos: + h: 11 + w: 24 + x: 0 + 'y': 78 + id: 23 + options: + calculate: false + cellGap: 0 + cellValues: + unit: Bps + color: + exponent: 0.5 + fill: red + mode: scheme + reverse: false + scale: exponential + scheme: Rainbow + steps: 64 + exemplars: + color: rgba(255,0,255,0.7) + filterValues: + le: 1.e-9 + legend: + show: true + rowsFrame: + layout: auto + value: Shard + tooltip: + mode: single + showColorScale: true + yHistogram: true + yAxis: + axisLabel: Shard + axisPlacement: right + reverse: true + unit: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (shard) + (histogram_sum(rate(pyroscope_segment_writer_client_sent_bytes{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (shard) + (rate(pyroscope_segment_writer_client_sent_bytes_sum{namespace="$namespace"}[$__rate_interval])) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: B + title: Distributed Bytes (per shard) + transparent: true + type: heatmap + - datasource: + default: false + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: bytes + overrides: [] + gridPos: + h: 9 + w: 12 + x: 0 + 'y': 89 + id: 64 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: true + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (shard) + (histogram_sum(rate(pyroscope_segment_writer_client_sent_bytes{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (shard) + (rate(pyroscope_segment_writer_client_sent_bytes_sum{namespace="$namespace"}[$__rate_interval])) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: B + title: Distributed Bytes (per shard) + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 7 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: bytes + overrides: [] + gridPos: + h: 9 + w: 12 + x: 12 + 'y': 89 + id: 26 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: true + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (shard) + (histogram_sum(rate(pyroscope_segment_writer_client_sent_bytes{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (shard) + (rate(pyroscope_segment_writer_client_sent_bytes_sum{namespace="$namespace"}[$__rate_interval])) + {{- end }} + hide: false + instant: false + legendFormat: __auto + range: true + refId: B + title: Distributed Bytes (per shard, stack) + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: bytes + overrides: [] + gridPos: + h: 9 + w: 12 + x: 0 + 'y': 98 + id: 24 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: true + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (pod) + (histogram_sum(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (pod) + (rate(pyroscope_segment_writer_segment_ingest_bytes_sum{namespace="$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Ingested Bytes (per node) + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 7 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: bytes + overrides: [] + gridPos: + h: 9 + w: 12 + x: 12 + 'y': 98 + id: 34 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: true + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (pod) + (histogram_sum(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (pod) + (rate(pyroscope_segment_writer_segment_ingest_bytes_sum{namespace="$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: '' + hide: false + instant: false + legendFormat: __auto + range: true + refId: B + title: Ingested Bytes (per node, stack) + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: short + overrides: [] + gridPos: + h: 9 + w: 12 + x: 0 + 'y': 107 + id: 35 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: true + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (pod) + (histogram_count(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (pod) + (rate(pyroscope_segment_writer_segment_ingest_bytes_count{namespace="$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Ingested Profiles (per node) + transparent: true + type: timeseries + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 7 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: normal + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + unit: short + overrides: [] + gridPos: + h: 9 + w: 12 + x: 12 + 'y': 107 + id: 36 + options: + legend: + calcs: + - mean + displayMode: table + placement: right + showLegend: true + sortBy: Name + sortDesc: false + tooltip: + hideZeros: false + mode: multi + sort: desc + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + {{- if .Values.dashboards.nativeHistograms }} + expr: >- + sum by (pod) + (histogram_count(rate(pyroscope_segment_writer_segment_ingest_bytes{namespace="$namespace"}[$__rate_interval]))) + {{- else }} + expr: >- + sum by (pod) + (rate(pyroscope_segment_writer_segment_ingest_bytes_count{namespace="$namespace"}[$__rate_interval])) + {{- end }} + legendFormat: __auto + range: true + refId: A + title: Ingested Profiles (per node, stack) + transparent: true + type: timeseries + title: Data Distribution + type: row + - collapsed: true + gridPos: + h: 1 + w: 24 + x: 0 + 'y': 61 + id: 86 + panels: + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: thresholds + fieldMinMax: false + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + overrides: [] + gridPos: + h: 13 + w: 12 + x: 0 + 'y': 168 + id: 87 + options: + groupByField: container + labelFields: + - container + - instance_type + textField: instance_type + tiling: treemapSquarify + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + exemplar: false + expr: |- + count by (instance_type, container) ( + rate(container_cpu_usage_seconds_total{ + cluster="$cluster", + namespace="$namespace", + container=~"segment-writer|distributor|cortex-gw|metastore|compaction-worker", + }[$__rate_interval]) + on (instance) group_left(instance_type) (0 * label_replace( + karpenter_nodes_allocatable{cluster="$cluster", resource_type="cpu"}, "instance", "$1", "node_name", "(.*)") + ) + ) + format: table + hide: false + instant: true + legendFormat: '{{"{{instance_type}}"}}' + range: false + refId: A + title: AWS | Intances By Machine Type + transparent: true + type: marcusolsson-treemap-panel + - datasource: + type: prometheus + uid: ${datasource} + fieldConfig: + defaults: + color: + mode: palette-classic + custom: + axisBorderShow: false + axisCenteredZero: false + axisColorMode: text + axisLabel: '' + axisPlacement: auto + axisSoftMin: 0 + barAlignment: 0 + barWidthFactor: 0.6 + drawStyle: line + fillOpacity: 0 + gradientMode: none + hideFrom: + legend: false + tooltip: false + viz: false + insertNulls: false + lineInterpolation: linear + lineWidth: 1 + pointSize: 5 + scaleDistribution: + type: linear + showPoints: auto + spanNulls: false + stacking: + group: A + mode: none + thresholdsStyle: + mode: 'off' + mappings: [] + thresholds: + mode: absolute + steps: + - color: green + value: 0 + - color: red + value: 80 + overrides: [] + gridPos: + h: 13 + w: 12 + x: 12 + 'y': 168 + id: 84 + options: + legend: + calcs: + - mean + - max + displayMode: table + placement: right + showLegend: true + tooltip: + hideZeros: false + mode: single + sort: none + targets: + - datasource: + type: prometheus + uid: ${datasource} + editorMode: code + expr: |- + avg by (instance_type, container) ( + rate(container_cpu_usage_seconds_total{ + cluster="$cluster", + namespace="$namespace", + container=~"segment-writer|distributor|cortex-gw", + }[$__rate_interval]) + on (instance) group_left(instance_type) (0 * label_replace( + karpenter_nodes_allocatable{cluster="$cluster", resource_type="cpu"}, "instance", "$1", "node_name", "(.*)") + ) + ) + hide: false + legendFormat: '{{"{{container}}/{{instance_type}}"}}' + range: true + refId: A + title: AWS | Average CPU Usage By Type + transparent: true + type: timeseries + title: Resource Allocation + type: row +preload: false +schemaVersion: 42 +tags: + - pyroscope + - pyroscope-v2 +templating: + list: + - current: + text: ops-cortex + value: '000000134' + includeAll: false + name: datasource + options: [] + query: prometheus + refresh: 1 + regex: '' + type: datasource + - allowCustomValue: false + current: + text: Grafana Logging + value: '000000193' + name: loki_datasource + options: [] + query: loki + refresh: 1 + regex: '' + type: datasource + - allowCustomValue: false + current: + text: {{.Values.dashboards.cluster | quote}} + value: {{.Values.dashboards.cluster | quote}} + datasource: + type: prometheus + uid: ${datasource} + definition: label_values(pyroscope_build_info{namespace="$namespace"},cluster) + label: cluster + name: cluster + options: [] + query: + qryType: 1 + query: label_values(pyroscope_build_info{namespace="$namespace"},cluster) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: '' + sort: 1 + type: query + - allowCustomValue: false + current: + text: {{.Values.dashboards.namespace | quote}} + value: {{.Values.dashboards.namespace | quote}} + datasource: + type: prometheus + uid: ${datasource} + definition: label_values(pyroscope_build_info,namespace) + label: namespace + name: namespace + options: [] + query: + qryType: 1 + query: label_values(pyroscope_build_info,namespace) + refId: PrometheusVariableQueryEditor-VariableQuery + refresh: 1 + regex: {{ include "pyroscope-monitoring.dashboards-namespace-regex" (list . $dashboard) | quote }} + type: query + - baseFilters: [] + datasource: + type: prometheus + uid: ${datasource} + filters: [] + name: Filters + type: adhoc +time: + from: now-6h + to: now +timepicker: {} +timezone: utc +title: Pyroscope v2 / Write Path + +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboards.tpl b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboards.tpl new file mode 100644 index 0000000000..d7a44bf526 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/_dashboards.tpl @@ -0,0 +1,64 @@ +{{/* +Config Map content for dashboard provisioning +*/}} +{{- define "pyroscope-monitoring.dashboards-configmap" -}} +{{/* +List of dashboards +*/}} +{{- $dashboards := list "operational" "v2-metastore" "v2-read-path" "v2-write-path" }} +data: + grafana-dashboards.yaml: | + apiVersion: 1 + providers: + {{- range $dashboard := $dashboards }} + {{- with $ }} + - name: "{{ $dashboard }}" + type: file + allowUiUpdates: true + folder: "Pyroscope" + options: + path: /otel-lgtm/grafana/conf/provisioning/dashboards/{{$dashboard}}.json + foldersFromFilesStructure: false + {{- end }} + {{- end }} + {{- range $dashboard := $dashboards }} + {{- with $ }} + {{$dashboard}}.json: | + {{- $content := (include (printf "pyroscope-monitoring.dashboards.%s" $dashboard) . | fromYaml) }} + {{- if hasKey $content "Error" }} + {{ fail (get $content "Error") }} + {{- end }} + {{- $content | mustToRawJson | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} + +{{/* +Get hash across all dashboards +*/}} +{{- define "pyroscope-monitoring.dashboards-hash" -}} +{{- include "pyroscope-monitoring.dashboards-configmap" . | sha256sum }} +{{- end }} + +{{/* +Ingest selector: This is the selector to be added to get the most outside metrics available. This depends it the cloud-backend-gataway is deployed or not (only in Grafana Cloud) +*/}} +{{- define "pyroscope-monitoring.dashboards-ingest-selector" -}} +{{- if .Values.dashboards.cloudBackendGateway }}{{ .Values.dashboards.cloudBackendGatewaySelector }}{{ else }}{{ .Values.dashboards.ingestSelector }}{{ end -}} +{{- end }} + +{{/* +Optional namespace matcher appended to the ingest selector. +*/}} +{{- define "pyroscope-monitoring.dashboards-ingest-namespace-selector" -}} +{{- with .Values.dashboards.ingestNamespaceSelector }}, {{ . }}{{- end -}} +{{- end }} + +{{/* +Namespace regex, optionally overridden per dashboard. +*/}} +{{- define "pyroscope-monitoring.dashboards-namespace-regex" -}} +{{- $root := index . 0 -}} +{{- $dashboard := index . 1 -}} +{{- default $root.Values.dashboards.namespaceRegex (dig $dashboard nil $root.Values.dashboards.namespaceRegexPerDashboard) -}} +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/_helpers.tpl b/operations/monitoring/helm/pyroscope-monitoring/templates/_helpers.tpl new file mode 100644 index 0000000000..9b6fdd3110 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "pyroscope-monitoring.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "pyroscope-monitoring.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "pyroscope-monitoring.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "pyroscope-monitoring.labels" -}} +helm.sh/chart: {{ include "pyroscope-monitoring.chart" . }} +{{ include "pyroscope-monitoring.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "pyroscope-monitoring.selectorLabels" -}} +app.kubernetes.io/name: {{ include "pyroscope-monitoring.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "pyroscope-monitoring.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "pyroscope-monitoring.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/_rules.tpl b/operations/monitoring/helm/pyroscope-monitoring/templates/_rules.tpl new file mode 100644 index 0000000000..66143f056c --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/_rules.tpl @@ -0,0 +1,119 @@ +{{/* +Config Map content for rules provisioning +*/}} +{{- define "pyroscope-monitoring.rules-configmap" -}} +{{/* +List of rules +*/}} +data: + prometheus.yaml: | + --- + otlp: + keep_identifying_resource_attributes: true + # Recommended attributes to be promoted to labels. + promote_resource_attributes: + - service.instance.id + - service.name + - service.namespace + - service.version + - cloud.availability_zone + - cloud.region + - container.name + - deployment.environment.name + - k8s.cluster.name + - k8s.container.name + - k8s.cronjob.name + - k8s.daemonset.name + - k8s.deployment.name + - k8s.job.name + - k8s.namespace.name + - k8s.pod.name + - k8s.replicaset.name + - k8s.statefulset.name + + storage: + tsdb: + # A 10min time window is enough because it can easily absorb retries and network delays. + out_of_order_time_window: 10m + rule_files: + - "/prometheus-rules/*.rules.yaml" + + k8s-rules-pod-owner.rules.yaml: | + groups: + - name: k8s.rules.pod_owner + rules: + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + label_replace( + kube_pod_owner{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, owner_kind="ReplicaSet"}, + "replicaset", "$1", "owner_name", "(.*)" + ) * on(replicaset, namespace) group_left(owner_name) topk by(replicaset, namespace) ( + 1, max by (replicaset, namespace, owner_name) ( + kube_replicaset_owner{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}} + ) + ), + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: deployment + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, owner_kind="DaemonSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: daemonset + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, owner_kind="StatefulSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: statefulset + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{{ "{" }}{{ .Values.dashboards.kubeStateMetricsSelector }}, owner_kind="Job"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: job + record: namespace_workload_pod:kube_pod_owner:relabel + k8s-rules-pod-container-cpu-usage-seconds-total.rules.yaml: | + groups: + - name: k8s.rules.container_cpu_usage_seconds_total + rules: + - expr: > + sum by (cluster, namespace, pod, container) ( + rate(container_cpu_usage_seconds_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, image!=""}[5m]) + ) * on (cluster, namespace, pod) group_left(node) topk by (cluster, + namespace, pod) ( + 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_rate5m + - expr: > + sum by (cluster, namespace, pod, container) ( + irate(container_cpu_usage_seconds_total{{ "{" }}{{ .Values.dashboards.cadvisorSelector }}, image!=""}[5m]) + ) * on (cluster, namespace, pod) group_left(node) topk by (cluster, + namespace, pod) ( + 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate +{{- end }} + +{{/* +Get hash across all rules +*/}} +{{- define "pyroscope-monitoring.rules-hash" -}} +{{- include "pyroscope-monitoring.rules-configmap" . | sha256sum }} +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/dashboards.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/dashboards.yaml new file mode 100644 index 0000000000..378a184baa --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/dashboards.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "pyroscope-monitoring.fullname" . }}-dashboards + labels: + {{- include "pyroscope-monitoring.labels" . | nindent 4 }} +{{- include "pyroscope-monitoring.dashboards-configmap" . }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/deployment.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/deployment.yaml new file mode 100644 index 0000000000..eee1a36a47 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/deployment.yaml @@ -0,0 +1,79 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "pyroscope-monitoring.fullname" . }} + labels: + {{- include "pyroscope-monitoring.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "pyroscope-monitoring.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + dashboards/hash: {{ include "pyroscope-monitoring.dashboards-hash" . | quote}} + rules/hash: {{ include "pyroscope-monitoring.rules-hash" . | quote}} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "pyroscope-monitoring.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + {{- range .Values.service.ports }} + - name: {{ .name | quote }} + containerPort: {{ .targetPort }} + protocol: {{ .protocol | quote }} + {{- end }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.env}} + env: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + volumes: + - name: dashboards + configMap: + name: {{ include "pyroscope-monitoring.fullname" . }}-dashboards + - name: rules + configMap: + name: {{ include "pyroscope-monitoring.fullname" . }}-rules + {{- with .Values.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/rules.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/rules.yaml new file mode 100644 index 0000000000..67fceee44e --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/rules.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "pyroscope-monitoring.fullname" . }}-rules + labels: + {{- include "pyroscope-monitoring.labels" . | nindent 4 }} +{{- include "pyroscope-monitoring.rules-configmap" . }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/service.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/service.yaml new file mode 100644 index 0000000000..0b7715900c --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/service.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "pyroscope-monitoring.fullname" . }} + labels: + {{- include "pyroscope-monitoring.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + {{- with .Values.service.ports }} + ports: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + {{- include "pyroscope-monitoring.selectorLabels" . | nindent 4 }} +{{- if and .Values.service.deployStaticName (not (eq (include "pyroscope-monitoring.fullname" .) "pyroscope-monitoring")) }} +--- +apiVersion: v1 +kind: Service +metadata: + # This name is fixed, as it is relied upon, by the subchart's config + name: pyroscope-monitoring + labels: + {{- include "pyroscope-monitoring.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + {{- with .Values.service.ports }} + ports: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + {{- include "pyroscope-monitoring.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/operations/monitoring/helm/pyroscope-monitoring/templates/tests/test-metrics.yaml b/operations/monitoring/helm/pyroscope-monitoring/templates/tests/test-metrics.yaml new file mode 100644 index 0000000000..4fdcd3cbe7 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/templates/tests/test-metrics.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "pyroscope-monitoring.fullname" . }}-test-metrics" + labels: + {{- include "pyroscope-monitoring.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: promtool + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /bin/bash + - -c + - | + set +euo pipefail + retries=30 + while ((retries > 0)); do + /otel-lgtm/prometheus/promtool query series --match 'kube_node_info' 'http://{{ include "pyroscope-monitoring.fullname" . }}:9090' | tee result.txt && + test $(cat result.txt | wc -l) -gt 0 && + break + + echo "something went wrong, let's wait 5 seconds and retry" + sleep 5 + ((retries --)) + done + if ((retries == 0 )); then + echo "Failed!" + exit 1 + fi + restartPolicy: Never diff --git a/operations/monitoring/helm/pyroscope-monitoring/values.yaml b/operations/monitoring/helm/pyroscope-monitoring/values.yaml new file mode 100644 index 0000000000..eca14e5fa6 --- /dev/null +++ b/operations/monitoring/helm/pyroscope-monitoring/values.yaml @@ -0,0 +1,264 @@ +# Default values for pyroscope-monitoring. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: grafana/otel-lgtm + tag: "0.11.10" + pullPolicy: IfNotPresent + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + +# Set environment variables +# -- @ignored +env: + - name: GF_PLUGINS_PREINSTALL + value: grafana-exploretraces-app + - name: GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH + value: /otel-lgtm/grafana/conf/provisioning/dashboards/operational.json + +service: + type: ClusterIP + # -- @ignored + ports: + - name: grafana + protocol: TCP + port: 3000 + targetPort: 3000 + - name: otel-grpc + protocol: TCP + port: 4317 + targetPort: 4317 + - name: otel-http + protocol: TCP + port: 4318 + targetPort: 4318 + - name: prometheus + protocol: TCP + port: 9090 + targetPort: 9090 + - name: loki + protocol: TCP + port: 3100 + targetPort: 3100 + # deploys a service with static name "pyroscope-monitoring" in order to allow the subchart to ingest to it. + deployStaticName: true + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# Additional volumes on the output Deployment definition. +# -- @ignored +volumes: + - emptyDir: {} + name: tempo-data + - emptyDir: {} + name: loki-data + - emptyDir: {} + name: grafana-data + - emptyDir: {} + name: loki-storage + - emptyDir: {} + name: p8s-storage + - emptyDir: {} + name: pyroscope-storage + +# Additional volumeMounts on the output Deployment definition. +# -- @ignored +volumeMounts: + - mountPath: /data/tempo + name: tempo-data + - mountPath: /data/grafana + name: grafana-data + - mountPath: /data/loki + name: loki-data + - mountPath: /loki + name: loki-storage + - mountPath: /data/prometheus + name: p8s-storage + - mountPath: /data/pyroscope + name: pyroscope-storage + - mountPath: /otel-lgtm/grafana/conf/provisioning/dashboards + name: dashboards + - mountPath: /otel-lgtm/prometheus.yaml + name: rules + subPath: prometheus.yaml + - mountPath: /prometheus-rules + name: rules + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# Customize dashboard generation +dashboards: + # Is the cloud-backend-gateway available (previously cortex-gw) + cloudBackendGateway: false + + # cloud backend gateway selector + cloudBackendGatewaySelector: container=~"cortex-gw(-internal)?" + + kubeStateMetricsSelector: job=~"(.*/)?kube-state-metrics" + cadvisorSelector: job=~"(.*/)?cadvisor" + + # Default namespace + namespace: default + + # Filter available namespaces by regex + namespaceRegex: .* + + # Default cluster + cluster: pyroscope-dev + + # ingest label selector + ingestSelector: container=~"pyroscope|distributor|query-frontend" + + # Set to true when Prometheus scrapes native histograms (scrape_native_histograms: true). + # When false, dashboards use classic _bucket/_sum/_count suffix queries instead. + nativeHistograms: true + + # Matcher appended to ingest queries. Set to "" to omit it. + ingestNamespaceSelector: namespace=~"$namespace" + + # Optional namespace regex overrides keyed by dashboard name. + namespaceRegexPerDashboard: {} + + # Tenant query rendered with Helm tpl. + tenantQuery: | + sum by (tenant, slug, org_name, environment) ( + {{- if .Values.dashboards.nativeHistograms }} + histogram_sum(rate(pyroscope_distributor_received_decompressed_bytes{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval])) + {{- else }} + rate(pyroscope_distributor_received_decompressed_bytes_sum{cluster=~"$cluster",namespace=~"$namespace"}[$__rate_interval]) + {{- end }} + ) + + # -- @ignored + links: + global: + - asDropdown: true + icon: external link + includeVars: true + keepTime: true + tags: + - pyroscope + targetBlank: false + title: Pyroscope Dashboards + type: dashboards + perDashboard: + my-dashboard: [] + +# -- @ignored +monitoring: + enabled: true + + global: + # This enables scraping of native histograms + scrapeProtocols: ["PrometheusProto", "OpenMetricsText1.0.0", "OpenMetricsText0.0.1", "PrometheusText0.0.4"] + scrapeClassicHistograms: true + scrapeNativeHistograms: true + cluster: + name: pyroscope-dev + + destinations: + - name: otlp-gateway + type: otlp + url: "http://pyroscope-monitoring:4318" + protocol: http + traces: {enabled: true} + # NOTE(simonswine): Unable to keep container/namespace/job/cluster as indexed label + - name: loki + type: loki + url: "http://pyroscope-monitoring:3100/loki/api/v1/push" + logs: {enabled: true} + # NOTE(simonswine): Was not able to get native histograms to work with otlp-gateway + - name: prometheus + type: prometheus + url: "http://pyroscope-monitoring:9090/api/v1/write" + metrics: {enabled: true} + sendNativeHistograms: true + + clusterMetrics: + enabled: true + opencost: + enabled: false + kepler: + enabled: false + + clusterEvents: + enabled: true + + podLogs: + enabled: true + + annotationAutodiscovery: + enabled: true + + applicationObservability: + enabled: true + receivers: + jaeger: + thriftHttp: {enabled: true} + thriftBinary: {enabled: true} + thriftCompact: {enabled: true} + + alloy-metrics: + enabled: true + image: + # NOTE(simonswine): Was not able to get native histograms to work with v1.11.0, as they are now default disabled and there is no flag + # https://github.com/grafana/k8s-monitoring-helm/pull/2049#pullrequestreview-3340565881 + tag: v1.10.2 + + alloy-logs: + enabled: true + + alloy-singleton: + enabled: true + + alloy-receiver: + enabled: true + alloy: + # Should no longer be necessary after https://github.com/grafana/k8s-monitoring-helm/pull/2071 merges + extraPorts: + - name: "thrift-compact" + port: 6831 + targetPort: 6831 + protocol: UDP + - name: jaeger-binary + port: 6832 + targetPort: 6832 + protocol: UDP + - name: jaeger-http + port: 14268 + targetPort: 14268 + protocol: TCP diff --git a/operations/monitoring/rules/k8s-rules-pod-container-cpu-usage-seconds-total.rules.yaml b/operations/monitoring/rules/k8s-rules-pod-container-cpu-usage-seconds-total.rules.yaml new file mode 100644 index 0000000000..6e8cd93c0a --- /dev/null +++ b/operations/monitoring/rules/k8s-rules-pod-container-cpu-usage-seconds-total.rules.yaml @@ -0,0 +1,19 @@ +groups: +- name: k8s.rules.container_cpu_usage_seconds_total + rules: + - expr: > + sum by (cluster, namespace, pod, container) ( + rate(container_cpu_usage_seconds_total{job=~"(.*/)?cadvisor", image!=""}[5m]) + ) * on (cluster, namespace, pod) group_left(node) topk by (cluster, + namespace, pod) ( + 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_rate5m + - expr: > + sum by (cluster, namespace, pod, container) ( + irate(container_cpu_usage_seconds_total{job=~"(.*/)?cadvisor", image!=""}[5m]) + ) * on (cluster, namespace, pod) group_left(node) topk by (cluster, + namespace, pod) ( + 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate diff --git a/operations/monitoring/rules/k8s-rules-pod-owner.rules.yaml b/operations/monitoring/rules/k8s-rules-pod-owner.rules.yaml new file mode 100644 index 0000000000..1038cb3dba --- /dev/null +++ b/operations/monitoring/rules/k8s-rules-pod-owner.rules.yaml @@ -0,0 +1,50 @@ +groups: +- name: k8s.rules.pod_owner + rules: + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + label_replace( + kube_pod_owner{job=~"(.*/)?kube-state-metrics", owner_kind="ReplicaSet"}, + "replicaset", "$1", "owner_name", "(.*)" + ) * on(replicaset, namespace) group_left(owner_name) topk by(replicaset, namespace) ( + 1, max by (replicaset, namespace, owner_name) ( + kube_replicaset_owner{job=~"(.*/)?kube-state-metrics"} + ) + ), + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: deployment + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job=~"(.*/)?kube-state-metrics", owner_kind="DaemonSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: daemonset + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job=~"(.*/)?kube-state-metrics", owner_kind="StatefulSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: statefulset + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: | + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job=~"(.*/)?kube-state-metrics", owner_kind="Job"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: job + record: namespace_workload_pod:kube_pod_owner:relabel diff --git a/operations/pyroscope/alloy_test.go b/operations/pyroscope/alloy_test.go new file mode 100644 index 0000000000..db98a1d741 --- /dev/null +++ b/operations/pyroscope/alloy_test.go @@ -0,0 +1,90 @@ +package pyroscope + +import ( + "bytes" + "errors" + "fmt" + "io" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/grafana/alloy/syntax/diag" + "github.com/grafana/alloy/syntax/parser" + "github.com/grafana/alloy/syntax/printer" + "github.com/stretchr/testify/require" + "go.yaml.in/yaml/v3" +) + +// Test_FormatAgentRiverConfig tests that the river config generated by helm is formatted correctly +func Test_FormatAgentRiverConfig(t *testing.T) { + fdata, err := os.Open("helm/pyroscope/rendered/single-binary.yaml") + require.NoError(t, err) + defer fdata.Close() + + values := map[string]interface{}{} + configString := `` + dec := yaml.NewDecoder(fdata) + for dec.Decode(&values) == nil { + if values["metadata"].(map[string]interface{})["name"] == "alloy-config-pyroscope" { + configString = values["data"].(map[string]interface{})["config.alloy"].(string) + break + } + } + fileName := fmt.Sprintf("%s/config.alloy", t.TempDir()) + require.NoError(t, os.WriteFile(fileName, []byte(configString), 0o644)) + fi, err := os.Stat(fileName) + require.NoError(t, err) + f, err := os.Open(fileName) + require.NoError(t, err) + defer f.Close() + + err = format(fileName, fi, f, true) + var diags diag.Diagnostics + if errors.As(err, &diags) { + for _, diag := range diags { + fmt.Fprintln(os.Stderr, diag) + } + t.Error("encountered errors during formatting") + } + fmtData, err := os.ReadFile(fileName) + require.NoError(t, err) + if diff := cmp.Diff(string(fmtData), configString); diff != "" { + t.Errorf("Grafana Agent Helm River config file is not formatted mismatch (-want +got):\n%s", diff) + t.Log("You need to fixes formatting issues in operations/pyroscope/helm/pyroscope/templates/configmap-agent.yaml and run make helm/check.") + } +} + +func format(filename string, fi os.FileInfo, r io.Reader, write bool) error { + bb, err := io.ReadAll(r) + if err != nil { + return err + } + + f, err := parser.ParseFile(filename, bb) + if err != nil { + return err + } + + var buf bytes.Buffer + if err := printer.Fprint(&buf, f); err != nil { + return err + } + + // Add a newline at the end of the file. + _, _ = buf.Write([]byte{'\n'}) + + if !write { + _, err := io.Copy(os.Stdout, &buf) + return err + } + + wf, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, fi.Mode().Perm()) + if err != nil { + return err + } + defer wf.Close() + + _, err = io.Copy(wf, &buf) + return err +} diff --git a/operations/pyroscope/helm/ct.yaml b/operations/pyroscope/helm/ct.yaml index 6777e31fba..53abd2a099 100644 --- a/operations/pyroscope/helm/ct.yaml +++ b/operations/pyroscope/helm/ct.yaml @@ -1,9 +1,9 @@ # See https://github.com/helm/chart-testing#configuration remote: origin -target-branch: next -kubeVersion: "1.22" +target-branch: main +kubeVersion: "1.23" chart-dirs: - - operations/pyroscope/helm/ + - operations/pyroscope/helm chart-repos: - minio=https://charts.min.io/ - grafana=https://grafana.github.io/helm-charts diff --git a/operations/pyroscope/helm/pyroscope/.helmignore b/operations/pyroscope/helm/pyroscope/.helmignore index 0e8a0eb36f..5189486fbe 100644 --- a/operations/pyroscope/helm/pyroscope/.helmignore +++ b/operations/pyroscope/helm/pyroscope/.helmignore @@ -21,3 +21,7 @@ .idea/ *.tmproj .vscode/ +# Integration tests and rendered reference manifests — not part of the chart package +e2e/ +ci/integration/ +rendered/ diff --git a/operations/pyroscope/helm/pyroscope/Chart.lock b/operations/pyroscope/helm/pyroscope/Chart.lock index 43f48225c6..4db0b49465 100644 --- a/operations/pyroscope/helm/pyroscope/Chart.lock +++ b/operations/pyroscope/helm/pyroscope/Chart.lock @@ -1,9 +1,12 @@ dependencies: - name: grafana-agent repository: https://grafana.github.io/helm-charts - version: 0.25.0 + version: 0.44.2 +- name: alloy + repository: https://grafana.github.io/helm-charts + version: 1.5.2 - name: minio repository: https://charts.min.io/ - version: 4.0.12 -digest: sha256:ac1a9529d0b7f81d81909bdd6cebb0b61cb28e039fa21a719f73626a5efc86be -generated: "2023-09-26T17:22:21.02154+01:00" + version: 4.1.0 +digest: sha256:6539cf3e08af8a90406747cea8b186872b43b8cd33b19bb479e5d011daa90b7e +generated: "2026-01-19T02:29:04.501652875Z" diff --git a/operations/pyroscope/helm/pyroscope/Chart.yaml b/operations/pyroscope/helm/pyroscope/Chart.yaml index 1cf7f8d872..316d116ce6 100644 --- a/operations/pyroscope/helm/pyroscope/Chart.yaml +++ b/operations/pyroscope/helm/pyroscope/Chart.yaml @@ -1,17 +1,26 @@ apiVersion: v2 name: pyroscope -description: 🔥 horizontally-scalable, highly-available, multi-tenant continuous profiling aggregation system +description: A horizontally scalable, highly available, multi-tenant continuous profiling database. +home: https://grafana.com/oss/pyroscope/ type: application -version: 1.6.0 -appVersion: 1.6.0 +version: 2.2.0 +appVersion: 2.2.0 dependencies: - name: grafana-agent alias: agent - version: "0.25.0" + version: "0.44.2" repository: https://grafana.github.io/helm-charts condition: agent.enabled + - name: alloy + alias: alloy + version: "1.5.2" + repository: https://grafana.github.io/helm-charts + condition: alloy.enabled - name: minio alias: minio - version: 4.0.12 + version: 4.1.0 repository: https://charts.min.io/ condition: minio.enabled +sources: + - https://github.com/grafana/pyroscope + - https://github.com/grafana/pyroscope/tree/main/operations/pyroscope/helm/pyroscope diff --git a/operations/pyroscope/helm/pyroscope/README.md b/operations/pyroscope/helm/pyroscope/README.md index da183b42fb..1840b6218e 100644 --- a/operations/pyroscope/helm/pyroscope/README.md +++ b/operations/pyroscope/helm/pyroscope/README.md @@ -1,48 +1,88 @@ # pyroscope -![Version: 1.5.1](https://img.shields.io/badge/Version-1.5.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.5.0](https://img.shields.io/badge/AppVersion-1.5.0-informational?style=flat-square) +![Version: 2.2.0](https://img.shields.io/badge/Version-2.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.2.0](https://img.shields.io/badge/AppVersion-2.2.0-informational?style=flat-square) -🔥 horizontally-scalable, highly-available, multi-tenant continuous profiling aggregation system +A horizontally scalable, highly available, multi-tenant continuous profiling database. + +**Homepage:** + +## Source Code + +* +* ## Requirements | Repository | Name | Version | |------------|------|---------| -| https://charts.min.io/ | minio(minio) | 4.0.12 | -| https://grafana.github.io/helm-charts | agent(grafana-agent) | 0.25.0 | +| https://charts.min.io/ | minio(minio) | 4.1.0 | +| https://grafana.github.io/helm-charts | alloy(alloy) | 1.5.2 | +| https://grafana.github.io/helm-charts | agent(grafana-agent) | 0.44.2 | ## Values | Key | Type | Default | Description | |-----|------|---------|-------------| -| agent | object | `{"agent":{"clustering":{"enabled":true},"configMap":{"create":false,"name":"grafana-agent-config-pyroscope"}},"controller":{"podAnnotations":{"profiles.grafana.com/cpu.port_name":"http-metrics","profiles.grafana.com/cpu.scrape":"true","profiles.grafana.com/goroutine.port_name":"http-metrics","profiles.grafana.com/goroutine.scrape":"true","profiles.grafana.com/memory.port_name":"http-metrics","profiles.grafana.com/memory.scrape":"true"},"replicas":1,"type":"statefulset"},"enabled":true}` | ----------------------------------- | +| agent | object | `{"agent":{"clustering":{"enabled":true},"configMap":{"create":false,"name":"grafana-agent-config-pyroscope"}},"controller":{"podAnnotations":{"profiles.grafana.com/cpu.port_name":"http-metrics","profiles.grafana.com/cpu.scrape":"true","profiles.grafana.com/goroutine.port_name":"http-metrics","profiles.grafana.com/goroutine.scrape":"true","profiles.grafana.com/memory.port_name":"http-metrics","profiles.grafana.com/memory.scrape":"true"},"replicas":1,"type":"statefulset"},"enabled":false}` | ----------------------------------- | +| alloy | object | `{"alloy":{"clustering":{"enabled":true},"configMap":{"create":false,"name":"alloy-config-pyroscope"},"stabilityLevel":"public-preview"},"controller":{"podAnnotations":{"profiles.grafana.com/cpu.port_name":"http-metrics","profiles.grafana.com/cpu.scrape":"true","profiles.grafana.com/goroutine.port_name":"http-metrics","profiles.grafana.com/goroutine.scrape":"true","profiles.grafana.com/memory.port_name":"http-metrics","profiles.grafana.com/memory.scrape":"true","profiles.grafana.com/service_git_ref":"v1.8.1","profiles.grafana.com/service_repository":"https://github.com/grafana/alloy"},"replicas":1,"type":"statefulset"},"enabled":true}` | ----------------------------------- | +| architecture.deployUnifiedServices | bool | `false` | Deploy unified write/read services. These endpoints will can be used no matter if the helm chart is configured as single-binary or microservices | +| architecture.microservices.clusterLabelSuffix | string | `"-micro-services"` | Memberlist cluster label that will be used for all members of this cluster | +| architecture.microservices.enabled | bool | `false` | Enable micro-services deployment mode. This is recommend for larger scale deployment and allow right size each aspect of Pyroscope. | +| architecture.overwriteResources | object | `{}` | This flag is useful for testing, it will overwrite all pods resource statements with its contents | +| architecture.storage.migration.ingesterWeight | float | `1` | Specifies the fraction [0:1] that should be send to the v1 write path / ingester in combined mode. 0 means no traffics is sent to ingester. 1 means 100% of requests are sent to ingester. | +| architecture.storage.migration.queryBackendFrom | string | `"auto"` | Specify a time stamp from when the v2 read path should serve traffic. Defaults to "auto" which determines the split point from the metastore. | +| architecture.storage.migration.segmentWriterWeight | float | `1` | Specifies the fraction [0:1] that should be send to the v2 write path / segment-writer in combined mode. 0 means no traffics is sent to segment-writer. 1 means 100% of requests are sent to segment-writer. | +| architecture.storage.v1 | bool | `false` | Enable v1 storage layer. | +| architecture.storage.v2 | bool | `true` | Enable v2 storage layer. | +| extraObjects | list | `[]` | Array of extra K8s manifests to deploy alongside the chart | +| global.imageRegistry | string | `nil` | Overrides the Docker registry globally for all images | +| httpRoute.annotations | object | `{}` | Additional annotations to add to HTTPRoute resource. | +| httpRoute.enabled | bool | `false` | | +| httpRoute.gateway.name | string | `""` | | +| httpRoute.gateway.namespace | string | `""` | | +| httpRoute.gateway.sectionName | string | `nil` | Optional to specify listener's name. | +| httpRoute.hostnames | list | `[]` | | +| httpRoute.labels | object | `{}` | Additional labels to add to HTTPRoute resource. | +| httpRoute.timeouts | object | `{}` | Timeout settings to add to each rule in HTTPRoute resource. https://gateway-api.sigs.k8s.io/reference/spec/#httproutetimeouts. | +| ingress.annotations | object | `{}` | | | ingress.className | string | `""` | | | ingress.enabled | bool | `false` | | -| minio | object | `{"buckets":[{"name":"grafana-pyroscope-data","policy":"none","purge":false}],"drivesPerNode":2,"enabled":false,"persistence":{"size":"5Gi"},"podAnnotations":{"phlare.grafana.com/port":"9000","phlare.grafana.com/scrape":"true"},"replicas":1,"resources":{"requests":{"cpu":"100m","memory":"128Mi"}},"rootPassword":"supersecret","rootUser":"grafana-pyroscope"}` | ----------------------------------- | +| ingress.labels | object | `{}` | | +| ingress.pathType | string | `"ImplementationSpecific"` | | +| minio | object | `{"buckets":[{"name":"grafana-pyroscope-data","policy":"none","purge":false}],"drivesPerNode":2,"enabled":false,"persistence":{"size":"5Gi"},"podAnnotations":{},"replicas":1,"resources":{"requests":{"cpu":"100m","memory":"128Mi"}},"rootPassword":"supersecret","rootUser":"grafana-pyroscope"}` | ----------------------------------- | | pyroscope.affinity | object | `{}` | | | pyroscope.cluster_domain | string | `".cluster.local."` | Kubernetes cluster domain suffix for DNS discovery | | pyroscope.components | object | `{}` | | -| pyroscope.config | string | The config depends on other values been set, details can be found in [`values.yaml`](./values.yaml) | Contains Phlare's configuration as a string. | +| pyroscope.config | string | The config depends on other values been set, details can be found in [`values.yaml`](./values.yaml) | Contains Pyroscope's configuration as a string. | +| pyroscope.disableSelfProfile | bool | `true` | Enable or disable Self profile push, useful to test | | pyroscope.dnsPolicy | string | `"ClusterFirst"` | | | pyroscope.extraArgs."log.level" | string | `"debug"` | | +| pyroscope.extraContainers | list | `[]` | | +| pyroscope.extraCustomEnvVars | object | `{}` | | | pyroscope.extraEnvFrom | list | `[]` | Environment variables from secrets or configmaps to add to the pods | | pyroscope.extraEnvVars | object | `{}` | | | pyroscope.extraLabels | object | `{}` | | | pyroscope.extraVolumeMounts | list | `[]` | | | pyroscope.extraVolumes | list | `[]` | | | pyroscope.fullnameOverride | string | `""` | | +| pyroscope.grpc.port | int | `9095` | | +| pyroscope.grpc.port_name | string | `"grpc"` | | | pyroscope.image.pullPolicy | string | `"IfNotPresent"` | | +| pyroscope.image.registry | string | `""` | | | pyroscope.image.repository | string | `"grafana/pyroscope"` | | | pyroscope.image.tag | string | `""` | | | pyroscope.imagePullSecrets | list | `[]` | | | pyroscope.initContainers | list | `[]` | | | pyroscope.memberlist.port | int | `7946` | | | pyroscope.memberlist.port_name | string | `"memberlist"` | | +| pyroscope.metastore.port | int | `9099` | | +| pyroscope.metastore.port_name | string | `"raft"` | | | pyroscope.nameOverride | string | `""` | | | pyroscope.nodeSelector | object | `{}` | | | pyroscope.persistence.accessModes[0] | string | `"ReadWriteOnce"` | | | pyroscope.persistence.annotations | object | `{}` | | | pyroscope.persistence.enabled | bool | `false` | | +| pyroscope.persistence.metastore.subPath | string | `".metastore"` | | | pyroscope.persistence.size | string | `"10Gi"` | | | pyroscope.podAnnotations."profiles.grafana.com/cpu.port_name" | string | `"http2"` | | | pyroscope.podAnnotations."profiles.grafana.com/cpu.scrape" | string | `"true"` | | @@ -55,11 +95,12 @@ | pyroscope.podSecurityContext.fsGroup | int | `10001` | | | pyroscope.podSecurityContext.runAsNonRoot | bool | `true` | | | pyroscope.podSecurityContext.runAsUser | int | `10001` | | -| pyroscope.rbac.create | bool | `true` | | +| pyroscope.rbac.create | bool | `true` | Whether to create RBAC resources | | pyroscope.replicaCount | int | `1` | | | pyroscope.resources | object | `{}` | | | pyroscope.securityContext | object | `{}` | | | pyroscope.service.annotations | object | `{}` | | +| pyroscope.service.headlessAnnotations | object | `{}` | | | pyroscope.service.port | int | `4040` | | | pyroscope.service.port_name | string | `"http2"` | | | pyroscope.service.scheme | string | `"HTTP"` | | @@ -67,9 +108,10 @@ | pyroscope.serviceAccount.annotations | object | `{}` | | | pyroscope.serviceAccount.create | bool | `true` | | | pyroscope.serviceAccount.name | string | `""` | | -| pyroscope.structuredConfig | object | `{}` | Allows to override Phlare's configuration using structured format. | +| pyroscope.structuredConfig | object | `{}` | Allows to override Pyroscope's configuration using structured format. | | pyroscope.tenantOverrides | object | `{}` | Allows to add tenant specific overrides to the default limit configuration. | | pyroscope.tolerations | list | `[]` | | +| pyroscope.topologySpreadConstraints | list | `[]` | Topology Spread Constraints | | serviceMonitor.annotations | object | `{}` | ServiceMonitor annotations | | serviceMonitor.enabled | bool | `false` | If enabled, ServiceMonitor resources for Prometheus Operator are created | | serviceMonitor.interval | string | `nil` | ServiceMonitor scrape interval | @@ -83,5 +125,3 @@ | serviceMonitor.targetLabels | list | `[]` | ServiceMonitor will add labels from the service to the Prometheus metric https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitorspec | | serviceMonitor.tlsConfig | string | `nil` | ServiceMonitor will use these tlsConfig settings to make the health check requests | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/operations/pyroscope/helm/pyroscope/charts/alloy-1.5.2.tgz b/operations/pyroscope/helm/pyroscope/charts/alloy-1.5.2.tgz new file mode 100644 index 0000000000..16f87c02fa Binary files /dev/null and b/operations/pyroscope/helm/pyroscope/charts/alloy-1.5.2.tgz differ diff --git a/operations/pyroscope/helm/pyroscope/charts/grafana-agent-0.25.0.tgz b/operations/pyroscope/helm/pyroscope/charts/grafana-agent-0.25.0.tgz deleted file mode 100644 index 265edc669f..0000000000 Binary files a/operations/pyroscope/helm/pyroscope/charts/grafana-agent-0.25.0.tgz and /dev/null differ diff --git a/operations/pyroscope/helm/pyroscope/charts/grafana-agent-0.44.2.tgz b/operations/pyroscope/helm/pyroscope/charts/grafana-agent-0.44.2.tgz new file mode 100644 index 0000000000..267283405f Binary files /dev/null and b/operations/pyroscope/helm/pyroscope/charts/grafana-agent-0.44.2.tgz differ diff --git a/operations/pyroscope/helm/pyroscope/charts/minio-4.0.12.tgz b/operations/pyroscope/helm/pyroscope/charts/minio-4.0.12.tgz deleted file mode 100644 index 7ab04b43d1..0000000000 Binary files a/operations/pyroscope/helm/pyroscope/charts/minio-4.0.12.tgz and /dev/null differ diff --git a/operations/pyroscope/helm/pyroscope/charts/minio-4.1.0.tgz b/operations/pyroscope/helm/pyroscope/charts/minio-4.1.0.tgz new file mode 100644 index 0000000000..0911284bb8 Binary files /dev/null and b/operations/pyroscope/helm/pyroscope/charts/minio-4.1.0.tgz differ diff --git a/operations/pyroscope/helm/pyroscope/ci/gateway-resources.yaml b/operations/pyroscope/helm/pyroscope/ci/gateway-resources.yaml new file mode 100644 index 0000000000..d358c042c2 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/ci/gateway-resources.yaml @@ -0,0 +1,48 @@ +# GatewayClass, EnvoyProxy config, and Gateway for the HTTPRoute e2e integration test. +# Applied to the Kind cluster by the Go test infrastructure in main_test.go. +# +# EnvoyProxy sets service type to ClusterIP so the Gateway reaches Programmed=True +# in Kind clusters where LoadBalancer external IPs are never assigned. +# +# allowedRoutes: from: All is required because each test variant installs the chart +# into its own namespace, and the HTTPRoute must cross namespaces to bind to the +# Gateway in the default namespace. +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyProxy +metadata: + name: proxy-config + namespace: envoy-gateway-system +spec: + provider: + type: Kubernetes + kubernetes: + envoyService: + type: ClusterIP +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: envoy +spec: + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: proxy-config + namespace: envoy-gateway-system +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: pyroscope + namespace: default +spec: + gatewayClassName: envoy + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All diff --git a/operations/pyroscope/helm/pyroscope/ci/integration/httproute-microservices-values.yaml b/operations/pyroscope/helm/pyroscope/ci/integration/httproute-microservices-values.yaml new file mode 100644 index 0000000000..89626d4e87 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/ci/integration/httproute-microservices-values.yaml @@ -0,0 +1,127 @@ +# Values for v2 microservices e2e integration test of HTTPRoute support. +# Placed in ci/integration/ (not ci/) so the standard call-lint-test-pyroscope +# job does not try to install this on a bare cluster without Gateway API CRDs. + +architecture: + storage: + v1: false + v2: true + microservices: + enabled: true + +pyroscope: + components: + distributor: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 1Gi + requests: + memory: 32Mi + cpu: 10m + query-frontend: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 1Gi + requests: + memory: 32Mi + cpu: 10m + query-backend: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 1Gi + requests: + memory: 32Mi + cpu: 10m + segment-writer: + kind: StatefulSet + replicaCount: 1 + resources: + limits: + memory: 4Gi + requests: + memory: 256Mi + cpu: 100m + initContainers: + - name: create-bucket + image: minio/mc:RELEASE.2025-04-08T15-39-49Z + command: + - /bin/sh + - -c + - | + export MC_CONFIG_DIR="/tmp/mc" + mkdir -p "$MC_CONFIG_DIR" + until mc config host add myminio http://$MINIO_ENDPOINT:9000 grafana-pyroscope supersecret; do + echo "Waiting for Minio to be available..." + sleep 5 + done + mc mb myminio/grafana-pyroscope-data --ignore-existing + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MINIO_ENDPOINT + value: $(POD_NAMESPACE)-minio + metastore: + kind: StatefulSet + replicaCount: 1 + # Default bootstrap-expect-peers is 3 (HA). Override for single-replica CI. + extraArgs: + metastore.raft.bootstrap-expect-peers: 1 + resources: + limits: + memory: 1Gi + requests: + memory: 64Mi + cpu: 10m + compaction-worker: + kind: StatefulSet + replicaCount: 1 + resources: + limits: + memory: 1Gi + requests: + memory: 64Mi + cpu: 10m + tenant-settings: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 512Mi + requests: + memory: 32Mi + cpu: 10m + ad-hoc-profiles: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 512Mi + requests: + memory: 32Mi + cpu: 10m + +minio: + enabled: true + +# Not needed for routing tests — saves image pull time and startup overhead +alloy: + enabled: false +agent: + enabled: false + +httpRoute: + enabled: true + gateway: + name: pyroscope + namespace: default + sectionName: http + hostnames: + - pyroscope.test diff --git a/operations/pyroscope/helm/pyroscope/ci/integration/httproute-values.yaml b/operations/pyroscope/helm/pyroscope/ci/integration/httproute-values.yaml new file mode 100644 index 0000000000..47299ef93f --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/ci/integration/httproute-values.yaml @@ -0,0 +1,17 @@ +# Values for v2 single-binary e2e integration test of HTTPRoute support. +# Placed in ci/integration/ (not ci/) so the standard call-lint-test-pyroscope +# job does not try to install this on a bare cluster without Gateway API CRDs. + +architecture: + storage: + v1: false + v2: true + +httpRoute: + enabled: true + gateway: + name: pyroscope + namespace: default + sectionName: http + hostnames: + - pyroscope.test diff --git a/operations/pyroscope/helm/pyroscope/ci/micro-services-values.yaml b/operations/pyroscope/helm/pyroscope/ci/micro-services-values.yaml index 6b14ec7962..c9abce8fb4 100644 --- a/operations/pyroscope/helm/pyroscope/ci/micro-services-values.yaml +++ b/operations/pyroscope/helm/pyroscope/ci/micro-services-values.yaml @@ -2,17 +2,12 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. +architecture: + microservices: + enabled: true + pyroscope: components: - querier: - kind: Deployment - replicaCount: 3 - resources: - limits: - memory: 1Gi - requests: - memory: 32Mi - cpu: 10m query-frontend: kind: Deployment replicaCount: 2 @@ -22,7 +17,7 @@ pyroscope: requests: memory: 32Mi cpu: 10m - query-scheduler: + query-backend: kind: Deployment replicaCount: 2 resources: @@ -40,7 +35,7 @@ pyroscope: requests: memory: 32Mi cpu: 50m - ingester: + segment-writer: kind: StatefulSet replicaCount: 3 resources: @@ -49,19 +44,45 @@ pyroscope: requests: memory: 256Mi cpu: 100m - store-gateway: + initContainers: + - name: create-bucket + image: minio/mc:RELEASE.2025-04-08T15-39-49Z + command: + - /bin/sh + - -c + - | + export MC_CONFIG_DIR="/tmp/mc" + mkdir -p "$MC_CONFIG_DIR" + until mc config host add myminio http://$MINIO_ENDPOINT:9000 grafana-pyroscope supersecret; do + echo "Waiting for Minio to be available..." + sleep 5 + done + mc mb myminio/grafana-pyroscope-data --ignore-existing + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MINIO_ENDPOINT + value: $(POD_NAMESPACE)-minio + metastore: kind: StatefulSet replicaCount: 3 - persistence: - # The store-gateway needs not need persistent storage, but we still run it as a StatefulSet - # This is to avoid having blocks of data being - enabled: false resources: limits: - memory: 4Gi + memory: 1Gi + requests: + memory: 64Mi + cpu: 10m + compaction-worker: + kind: StatefulSet + replicaCount: 3 + resources: + limits: + memory: 1Gi requests: memory: 64Mi - cpu: 20m + cpu: 10m minio: enabled: true diff --git a/operations/pyroscope/helm/pyroscope/e2e/httproute_test.go b/operations/pyroscope/helm/pyroscope/e2e/httproute_test.go new file mode 100644 index 0000000000..b9a9a8921c --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/e2e/httproute_test.go @@ -0,0 +1,258 @@ +//go:build helm_integration + +package e2e + +import ( + "bytes" + "context" + "fmt" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/google/pprof/profile" + "github.com/stretchr/testify/require" + + adhocprofilesv1 "github.com/grafana/pyroscope/api/gen/proto/go/adhocprofiles/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect" + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" + querierv1connect "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1/settingsv1connect" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +const ( + gatewayName = "pyroscope" + gatewayNS = "default" + gatewayHost = "pyroscope.test" + gatewayPort = "8080" + envoyGWNS = "envoy-gateway-system" + gwAPIVersion = "v1.2.0" + envoyGWVersion = "v1.2.0" +) + +func init() { + suiteSetup = setupHTTPRoute +} + +// setupHTTPRoute installs the Gateway API CRDs, Envoy Gateway, the test +// GatewayClass/Gateway, and starts a port-forward to the Envoy proxy. +func setupHTTPRoute() (func(), error) { + // ── 1. Gateway API CRDs ────────────────────────────────────────────────── + fmt.Println("==> Installing Gateway API CRDs") + if err := kubectl("apply", "-f", + "https://github.com/kubernetes-sigs/gateway-api/releases/download/"+gwAPIVersion+"/standard-install.yaml", + ); err != nil { + return nil, fmt.Errorf("gateway API CRDs: %w", err) + } + for _, crd := range []string{ + "gateways.gateway.networking.k8s.io", + "httproutes.gateway.networking.k8s.io", + "gatewayclasses.gateway.networking.k8s.io", + } { + if err := kubectl("wait", "--for=condition=established", "--timeout=1m", "crd/"+crd); err != nil { + return nil, fmt.Errorf("wait for CRD %s: %w", crd, err) + } + } + + // ── 2. Envoy Gateway ───────────────────────────────────────────────────── + fmt.Println("==> Installing Envoy Gateway", envoyGWVersion) + if err := kubectl("apply", "--server-side", "-f", + "https://github.com/envoyproxy/gateway/releases/download/"+envoyGWVersion+"/install.yaml", + ); err != nil { + return nil, fmt.Errorf("envoy gateway: %w", err) + } + if err := kubectl("wait", "--timeout=5m", + "-n", envoyGWNS, + "deployment/envoy-gateway", + "--for=condition=Available", + ); err != nil { + return nil, fmt.Errorf("wait for envoy-gateway deployment: %w", err) + } + + // ── 3. GatewayClass + Gateway ───────────────────────────────────────────── + fmt.Println("==> Applying GatewayClass and Gateway") + if err := kubectl("apply", "-f", filepath.Join(chartDir, "ci/gateway-resources.yaml")); err != nil { + return nil, fmt.Errorf("gateway resources: %w", err) + } + if err := kubectl("wait", "gatewayclass/envoy", "--for=condition=Accepted", "--timeout=1m"); err != nil { + return nil, fmt.Errorf("wait for GatewayClass: %w", err) + } + if err := kubectl("wait", "gateway/"+gatewayName, + "-n", gatewayNS, + "--for=condition=Programmed", + "--timeout=2m", + ); err != nil { + return nil, fmt.Errorf("wait for Gateway: %w", err) + } + + // ── 4. Port-forward Envoy proxy ─────────────────────────────────────────── + fmt.Println("==> Port-forwarding Envoy proxy on :" + gatewayPort) + pfCmd, err := startPortForward() + if err != nil { + return nil, fmt.Errorf("port-forward: %w", err) + } + return func() { _ = pfCmd.Process.Kill() }, nil +} + +func startPortForward() (*exec.Cmd, error) { + // Find the Envoy proxy service by label. + out, err := exec.Command("kubectl", + "--context", "kind-"+clusterName, + "get", "svc", "-n", envoyGWNS, + "-l", fmt.Sprintf( + "gateway.envoyproxy.io/owning-gateway-name=%s,gateway.envoyproxy.io/owning-gateway-namespace=%s", + gatewayName, gatewayNS, + ), + "-o", "jsonpath={.items[0].metadata.name}", + ).Output() + if err != nil { + return nil, fmt.Errorf("get envoy svc: %w", err) + } + svcName := strings.TrimSpace(string(out)) + if svcName == "" { + return nil, fmt.Errorf("envoy proxy service not found") + } + + cmd := exec.Command("kubectl", + "--context", "kind-"+clusterName, + "port-forward", + "-n", envoyGWNS, + "svc/"+svcName, + gatewayPort+":80", + ) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Start(); err != nil { + return nil, fmt.Errorf("start port-forward: %w", err) + } + + // Wait until the port-forward is accepting connections. + deadline := time.Now().Add(30 * time.Second) + client := &http.Client{Timeout: time.Second} + for time.Now().Before(deadline) { + resp, err := client.Get("http://localhost:" + gatewayPort + "/") + if err == nil { + resp.Body.Close() + return cmd, nil + } + time.Sleep(time.Second) + } + // Return the command even if not ready; the tests will produce clear errors. + return cmd, nil +} + +// variants defines the chart configurations under test. +// Each installs the chart, runs all route assertions, then uninstalls. +var variants = []struct { + name string + valuesFile string +}{ + {"single-binary", "ci/integration/httproute-values.yaml"}, + {"microservices", "ci/integration/httproute-microservices-values.yaml"}, +} + +// TestHTTPRoute installs the chart for each variant and verifies that all four +// HTTPRoute routing rules correctly deliver requests to Pyroscope. +func TestHTTPRoute(t *testing.T) { + for _, v := range variants { + t.Run(v.name, func(t *testing.T) { + installChart(t, v.valuesFile) + + httpClient := gatewayClient() + baseURL := "http://localhost:" + gatewayPort + ctx := context.Background() + + // ── query rule: / /querier.v1.QuerierService/ /render /render-diff ── + t.Run("querier", func(t *testing.T) { + client := querierv1connect.NewQuerierServiceClient(httpClient, baseURL) + now := time.Now() + _, err := client.LabelNames(ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: now.Add(-time.Hour).UnixMilli(), + End: now.UnixMilli(), + })) + require.NoError(t, err) + }) + + // ── ingest rule: /push.v1.PusherService/ /ingest ────────────────── + t.Run("pusher", func(t *testing.T) { + client := pushv1connect.NewPusherServiceClient(httpClient, baseURL) + _, err := client.Push(ctx, connect.NewRequest(&pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{{ + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "e2e.test.cpu.samples"}, + {Name: "service_name", Value: "e2e-test"}, + }, + Samples: []*pushv1.RawSample{{ + RawProfile: minimalPprofBytes(), + }}, + }}, + })) + require.NoError(t, err) + }) + + // ── settings rule: /settings.v1.SettingsService/ ───────────────── + t.Run("settings", func(t *testing.T) { + client := settingsv1connect.NewSettingsServiceClient(httpClient, baseURL) + _, err := client.Get(ctx, connect.NewRequest(&settingsv1.GetSettingsRequest{})) + require.NoError(t, err) + }) + + // ── adhoc profiles rule: /adhocprofiles.v1.AdHocProfileService/ ── + t.Run("adhoc-profiles", func(t *testing.T) { + client := adhocprofilesv1connect.NewAdHocProfileServiceClient(httpClient, baseURL) + _, err := client.List(ctx, connect.NewRequest(&adhocprofilesv1.AdHocProfilesListRequest{})) + require.NoError(t, err) + }) + }) + } +} + +// gatewayClient returns an HTTP client that routes through the Envoy Gateway +// by setting the Host and tenant headers on every request. +func gatewayClient() *http.Client { + return &http.Client{ + Timeout: 10 * time.Second, + Transport: &gatewayTransport{base: http.DefaultTransport}, + } +} + +type gatewayTransport struct { + base http.RoundTripper +} + +func (t *gatewayTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req = req.Clone(req.Context()) + req.Host = gatewayHost + req.Header.Set("X-Scope-OrgID", "anonymous") + return t.base.RoundTrip(req) +} + +// minimalPprofBytes returns a minimal but valid gzip-compressed pprof profile +// with a single CPU sample, sufficient for routing tests. +func minimalPprofBytes() []byte { + fn := &profile.Function{ID: 1, Name: "test.main", SystemName: "test.main", Filename: "test.go"} + loc := &profile.Location{ID: 1, Line: []profile.Line{{Function: fn, Line: 1}}} + p := &profile.Profile{ + SampleType: []*profile.ValueType{{Type: "cpu", Unit: "nanoseconds"}}, + PeriodType: &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}, + Period: 10000000, // 10ms + Function: []*profile.Function{fn}, + Location: []*profile.Location{loc}, + Sample: []*profile.Sample{{Location: []*profile.Location{loc}, Value: []int64{1000000}}}, + TimeNanos: time.Now().UnixNano(), + DurationNanos: int64(time.Second), + } + var buf bytes.Buffer + if err := p.Write(&buf); err != nil { + panic("minimalPprofBytes: " + err.Error()) + } + return buf.Bytes() +} diff --git a/operations/pyroscope/helm/pyroscope/e2e/main_test.go b/operations/pyroscope/helm/pyroscope/e2e/main_test.go new file mode 100644 index 0000000000..cab9e4413c --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/e2e/main_test.go @@ -0,0 +1,136 @@ +//go:build helm_integration + +package e2e + +import ( + "bytes" + "fmt" + "math/rand" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +const ( + clusterName = "pyroscope-helm-e2e" + kindNodeImage = "kindest/node:v1.33.7" +) + +// chartDir is the path to the Helm chart root (the e2e/ package directory's parent). +// Tests are run with the working directory set to the package directory. +var chartDir = ".." + +// suiteSetup is registered by a test suite's init() to run suite-specific +// infrastructure after the cluster is ready. It returns a cleanup function. +var suiteSetup func() (func(), error) + +func TestMain(m *testing.M) { + os.Exit(run(m)) +} + +func run(m *testing.M) (code int) { + // ── 1. Kind cluster ────────────────────────────────────────────────────── + fmt.Println("==> Creating Kind cluster", clusterName) + if err := kubectl("cluster-info"); err != nil { + // Cluster doesn't exist yet, create it. + if err := kind("create", "cluster", + "--name", clusterName, + "--image", kindNodeImage, + "--wait", "5m", + ); err != nil { + fmt.Fprintf(os.Stderr, "kind create cluster: %v\n", err) + return 1 + } + } else { + fmt.Println(" (reusing existing cluster)") + } + defer func() { + fmt.Println("==> Deleting Kind cluster", clusterName) + _ = kind("delete", "cluster", "--name", clusterName) + }() + + // ── 2. Helm chart dependencies ──────────────────────────────────────────── + fmt.Println("==> Updating Helm chart dependencies") + _ = helm("repo", "add", "minio", "https://charts.min.io/") + _ = helm("repo", "add", "grafana", "https://grafana.github.io/helm-charts") + if err := helm("dependency", "update", chartDir); err != nil { + fmt.Fprintf(os.Stderr, "helm dependency update: %v\n", err) + return 1 + } + + // ── 3. Suite-specific setup ─────────────────────────────────────────────── + if suiteSetup != nil { + cleanup, err := suiteSetup() + if err != nil { + fmt.Fprintf(os.Stderr, "suite setup: %v\n", err) + return 1 + } + defer cleanup() + } + + return m.Run() +} + +// installChart installs the Helm chart with the given values file and returns +// the release name. It registers cleanup with t so the release is always removed. +func installChart(t *testing.T, valuesFile string) string { + t.Helper() + release := fmt.Sprintf("pyroscope-%s", randStr(8)) + ns := release + + t.Logf("helm install %s (values: %s)", release, valuesFile) + if err := kubectl("create", "namespace", ns); err != nil { + t.Fatalf("create namespace: %v", err) + } + if err := helm("install", release, chartDir, + "--namespace", ns, + "--values", filepath.Join(chartDir, valuesFile), + "--wait", + "--timeout", "20m", + ); err != nil { + _ = kubectl("get", "pods", "-n", ns) + t.Fatalf("helm install: %v", err) + } + t.Cleanup(func() { + t.Logf("helm uninstall %s", release) + _ = helm("uninstall", release, "--namespace", ns) + _ = kubectl("delete", "namespace", ns, "--ignore-not-found") + }) + return release +} + +// ── helpers ──────────────────────────────────────────────────────────────────── + +func kind(args ...string) error { + return runCmd("kind", args...) +} + +func kubectl(args ...string) error { + return runCmd("kubectl", append([]string{"--context", "kind-" + clusterName}, args...)...) +} + +func helm(args ...string) error { + return runCmd("helm", append([]string{"--kube-context", "kind-" + clusterName}, args...)...) +} + +func runCmd(name string, args ...string) error { + cmd := exec.Command(name, args...) + var buf bytes.Buffer + cmd.Stdout = os.Stdout + cmd.Stderr = &buf + if err := cmd.Run(); err != nil { + return fmt.Errorf("%s %s: %w\n%s", name, strings.Join(args, " "), err, buf.String()) + } + return nil +} + +func randStr(n int) string { + const letters = "abcdefghijklmnopqrstuvwxyz0123456789" + b := make([]byte, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services-hpa.yaml b/operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services-hpa.yaml new file mode 100644 index 0000000000..cc06e3a3fd --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services-hpa.yaml @@ -0,0 +1,3359 @@ +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-compactor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-ingester + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-querier + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-query-scheduler + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-store-gateway + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" +--- +# Source: pyroscope/charts/alloy/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: true +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +--- +# Source: pyroscope/charts/minio/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "minio-sa" + namespace: "default" +--- +# Source: pyroscope/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pyroscope-dev + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +--- +# Source: pyroscope/charts/minio/templates/secrets.yaml +apiVersion: v1 +kind: Secret +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +type: Opaque +data: + rootUser: "Z3JhZmFuYS1weXJvc2NvcGU=" + rootPassword: "c3VwZXJzZWNyZXQ=" +--- +# Source: pyroscope/charts/minio/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +data: + initialize: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkBucketExists ($bucket) + # Check if the bucket exists, by using the exit code of `mc ls` + checkBucketExists() { + BUCKET=$1 + CMD=$(${MC} ls myminio/$BUCKET > /dev/null 2>&1) + return $? + } + + # createBucket ($bucket, $policy, $purge) + # Ensure bucket exists, purging if asked to + createBucket() { + BUCKET=$1 + POLICY=$2 + PURGE=$3 + VERSIONING=$4 + OBJECTLOCKING=$5 + + # Purge the bucket, if set & exists + # Since PURGE is user input, check explicitly for `true` + if [ $PURGE = true ]; then + if checkBucketExists $BUCKET ; then + echo "Purging bucket '$BUCKET'." + set +e ; # don't exit if this fails + ${MC} rm -r --force myminio/$BUCKET + set -e ; # reset `e` as active + else + echo "Bucket '$BUCKET' does not exist, skipping purge." + fi + fi + + # Create the bucket if it does not exist and set objectlocking if enabled (NOTE: versioning will be not changed if OBJECTLOCKING is set because it enables versioning to the Buckets created) + if ! checkBucketExists $BUCKET ; then + if [ ! -z $OBJECTLOCKING ] ; then + if [ $OBJECTLOCKING = true ] ; then + echo "Creating bucket with OBJECTLOCKING '$BUCKET'" + ${MC} mb --with-lock myminio/$BUCKET + elif [ $OBJECTLOCKING = false ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + fi + elif [ -z $OBJECTLOCKING ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + else + echo "Bucket '$BUCKET' already exists." + fi + fi + + + # set versioning for bucket if objectlocking is disabled or not set + if [ -z $OBJECTLOCKING ] ; then + if [ ! -z $VERSIONING ] ; then + if [ $VERSIONING = true ] ; then + echo "Enabling versioning for '$BUCKET'" + ${MC} version enable myminio/$BUCKET + elif [ $VERSIONING = false ] ; then + echo "Suspending versioning for '$BUCKET'" + ${MC} version suspend myminio/$BUCKET + fi + fi + else + echo "Bucket '$BUCKET' versioning unchanged." + fi + + + # At this point, the bucket should exist, skip checking for existence + # Set policy on the bucket + echo "Setting policy of bucket '$BUCKET' to '$POLICY'." + ${MC} policy set $POLICY myminio/$BUCKET + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + + # Create the buckets + createBucket grafana-pyroscope-data none false + add-user: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # AccessKey and secretkey credentials file are added to prevent shell execution errors caused by special characters. + # Special characters for example : ',",<,>,{,} + MINIO_ACCESSKEY_SECRETKEY_TMP="/tmp/accessKey_and_secretKey_tmp" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkUserExists () + # Check if the user exists, by using the exit code of `mc admin user info` + checkUserExists() { + CMD=$(${MC} admin user info myminio $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) > /dev/null 2>&1) + return $? + } + + # createUser ($policy) + createUser() { + POLICY=$1 + #check accessKey_and_secretKey_tmp file + if [[ ! -f $MINIO_ACCESSKEY_SECRETKEY_TMP ]];then + echo "credentials file does not exist" + return 1 + fi + if [[ $(cat $MINIO_ACCESSKEY_SECRETKEY_TMP|wc -l) -ne 2 ]];then + echo "credentials file is invalid" + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + return 1 + fi + USER=$(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) + # Create the user if it does not exist + if ! checkUserExists ; then + echo "Creating user '$USER'" + cat $MINIO_ACCESSKEY_SECRETKEY_TMP | ${MC} admin user add myminio + else + echo "User '$USER' already exists." + fi + #clean up credentials files. + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + + # set policy for user + if [ ! -z $POLICY -a $POLICY != " " ] ; then + echo "Adding policy '$POLICY' for '$USER'" + ${MC} admin policy set myminio $POLICY user=$USER + else + echo "User '$USER' has no policy attached." + fi + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + + # Create the users + echo console > $MINIO_ACCESSKEY_SECRETKEY_TMP + echo console123 >> $MINIO_ACCESSKEY_SECRETKEY_TMP + createUser consoleAdmin + + add-policy: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkPolicyExists ($policy) + # Check if the policy exists, by using the exit code of `mc admin policy info` + checkPolicyExists() { + POLICY=$1 + CMD=$(${MC} admin policy info myminio $POLICY > /dev/null 2>&1) + return $? + } + + # createPolicy($name, $filename) + createPolicy () { + NAME=$1 + FILENAME=$2 + + # Create the name if it does not exist + echo "Checking policy: $NAME (in /config/$FILENAME.json)" + if ! checkPolicyExists $NAME ; then + echo "Creating policy '$NAME'" + else + echo "Policy '$NAME' already exists." + fi + ${MC} admin policy add myminio $NAME /config/$FILENAME.json + + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + custom-command: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # runCommand ($@) + # Run custom mc command + runCommand() { + ${MC} "$@" + return $? + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme +--- +# Source: pyroscope/templates/configmap-alloy.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: alloy-config-pyroscope + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.alloy: | + logging { + level = "info" + format = "logfmt" + } + + discovery.kubernetes "pyroscope_kubernetes" { + role = "pod" + } + + // The default scrape config allows to define annotations based scraping. + // + // For example the following annotations: + // + // ``` + // profiles.grafana.com/memory.scrape: "true" + // profiles.grafana.com/memory.port: "8080" + // profiles.grafana.com/cpu.scrape: "true" + // profiles.grafana.com/cpu.port: "8080" + // profiles.grafana.com/goroutine.scrape: "true" + // profiles.grafana.com/goroutine.port: "8080" + // ``` + // + // will scrape the `memory`, `cpu` and `goroutine` profiles from the `8080` port of the pod. + // + // For more information see https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/helm/#optional-scrape-your-own-workloads-profiles + discovery.relabel "kubernetes_pods" { + targets = concat(discovery.kubernetes.pyroscope_kubernetes.targets) + + rule { + action = "drop" + source_labels = ["__meta_kubernetes_pod_phase"] + regex = "Pending|Succeeded|Failed|Completed" + } + + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_label_(.+)" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // Set service_name by choosing the first non-empty value from the following ordered list: + // - pod.annotation[profiles.grafana.com/service_name] + // - pod.annotation[resource.opentelemetry.io/service.name] + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_annotation_profiles_grafana_com_service_name", + "__meta_kubernetes_pod_annotation_resource_opentelemetry_io_service_name", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "service_name" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_repository"] + target_label = "service_repository" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_git_ref"] + target_label = "service_git_ref" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_root_path"] + target_label = "service_root_path" + } + } + + discovery.relabel "kubernetes_pods_memory_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_memory_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_memory" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_memory_default_name.output, discovery.relabel.kubernetes_pods_memory_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = true + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_cpu_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_cpu_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_cpu" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_cpu_default_name.output, discovery.relabel.kubernetes_pods_cpu_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = true + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_goroutine_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_goroutine_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_goroutine" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_goroutine_default_name.output, discovery.relabel.kubernetes_pods_goroutine_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = true + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_block_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_block_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_block" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_block_default_name.output, discovery.relabel.kubernetes_pods_block_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = true + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_mutex_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_mutex_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_mutex" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_mutex_default_name.output, discovery.relabel.kubernetes_pods_mutex_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = true + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_fgprof_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_fgprof_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_fgprof" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_fgprof_default_name.output, discovery.relabel.kubernetes_pods_fgprof_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = true + } + } + } + + pyroscope.write "pyroscope_write" { + endpoint { + url = "http://pyroscope-dev-distributor.default.svc.cluster.local.:4040" + } + } +--- +# Source: pyroscope/templates/configmap-overrides.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-overrides-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + overrides.yaml: | + overrides: + {} +--- +# Source: pyroscope/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.yaml: | + storage: + backend: s3 + s3: + access_key_id: grafana-pyroscope + bucket_name: grafana-pyroscope-data + endpoint: pyroscope-dev-minio:9000 + insecure: true + secret_access_key: supersecret +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +rules: + - apiGroups: + - "" + - discovery.k8s.io + - networking.k8s.io + resources: + - endpoints + - endpointslices + - ingresses + - pods + - services + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - pods + - pods/log + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.grafana.com + resources: + - podlogs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - prometheusrules + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - alertmanagerconfigs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - podmonitors + - servicemonitors + - probes + - scrapeconfigs + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - apps + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + - nodes/proxy + - nodes/metrics + verbs: + - get + - list + - watch + - nonResourceURLs: + - /metrics + verbs: + - get +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pyroscope-dev-alloy +subjects: + - kind: ServiceAccount + name: pyroscope-dev-alloy + namespace: default +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +rules: +- apiGroups: + - "" + - discovery.k8s.io + resources: + - endpointslices + - endpoints + - services + - pods + verbs: + - get + - watch + - list +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pyroscope-dev-discovery +subjects: +- kind: ServiceAccount + name: pyroscope-dev + namespace: default +--- +# Source: pyroscope/charts/alloy/templates/cluster_service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy-cluster + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + clusterIP: 'None' + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + # Do not include the -metrics suffix in the port name, otherwise metrics + # can be double-collected with the non-headless Service if it's also + # enabled. + # + # This service should only be used for clustering, and not metric + # collection. + - name: http + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/charts/alloy/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + - name: http-metrics + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/charts/minio/templates/console-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio-console + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +spec: + type: ClusterIP + ports: + - name: http + port: 9001 + protocol: TCP + targetPort: 9001 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/charts/minio/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + monitoring: "true" +spec: + type: ClusterIP + ports: + - name: http + port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/charts/minio/templates/statefulset.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio-svc + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: "pyroscope-dev" + heritage: "Helm" +spec: + publishNotReadyAddresses: true + clusterIP: None + ports: + - name: http + port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/templates/memberlist-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-memberlist + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + clusterIP: None + ports: + - name: memberlist + port: 7946 + protocol: TCP + targetPort: 7946 + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + # TODO: Ensure only services that offer memberlist register + # pyroscope.grafana.com/memberlist: "true" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-compactor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-compactor-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-distributor-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ingester + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ingester-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-querier + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-querier-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-frontend-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-scheduler + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-scheduler-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-store-gateway + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-store-gateway-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" + name: "distributor" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "distributor" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=distributor" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 500m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-querier + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" + name: "querier" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "querier" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=querier" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 1 + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" + name: "query-frontend" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "query-frontend" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=query-frontend" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-query-scheduler + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" + name: "query-scheduler" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "query-scheduler" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=query-scheduler" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/hpa.yaml +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: pyroscope-dev-distributor + minReplicas: 2 + maxReplicas: 3 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 60 +--- +# Source: pyroscope/templates/hpa.yaml +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: pyroscope-dev-querier + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: pyroscope-dev-querier + minReplicas: 2 + maxReplicas: 4 + metrics: + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 60 + behavior: + scaleDown: + stabilizationWindowSeconds: 60 +--- +# Source: pyroscope/templates/hpa.yaml +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: pyroscope-dev-query-frontend + minReplicas: 2 + maxReplicas: 4 + metrics: + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 60 +--- +# Source: pyroscope/templates/hpa.yaml +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: pyroscope-dev-query-scheduler + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: pyroscope-dev-query-scheduler + minReplicas: 2 + maxReplicas: 4 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 40 +--- +# Source: pyroscope/charts/alloy/templates/controllers/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy +spec: + replicas: 1 + podManagementPolicy: Parallel + minReadySeconds: 10 + serviceName: pyroscope-dev-alloy + selector: + matchLabels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: alloy + profiles.grafana.com/cpu.port_name: http-metrics + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http-metrics + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http-metrics + profiles.grafana.com/memory.scrape: "true" + profiles.grafana.com/service_git_ref: v1.8.1 + profiles.grafana.com/service_repository: https://github.com/grafana/alloy + labels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + spec: + serviceAccountName: pyroscope-dev-alloy + containers: + - name: alloy + image: docker.io/grafana/alloy:v1.12.2 + imagePullPolicy: IfNotPresent + args: + - run + - /etc/alloy/config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + - --server.http.ui-path-prefix=/ + - --cluster.enabled=true + - --cluster.join-addresses=pyroscope-dev-alloy-cluster + - --stability.level=public-preview + env: + - name: ALLOY_DEPLOY_MODE + value: "helm" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - containerPort: 12345 + name: http-metrics + readinessProbe: + httpGet: + path: /-/ready + port: 12345 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 1 + volumeMounts: + - name: config + mountPath: /etc/alloy + - name: config-reloader + image: quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0 + args: + - --watched-dir=/etc/alloy + - --reload-url=http://localhost:12345/-/reload + volumeMounts: + - name: config + mountPath: /etc/alloy + resources: + requests: + cpu: 10m + memory: 50Mi + dnsPolicy: ClusterFirst + volumes: + - name: config + configMap: + name: alloy-config-pyroscope +--- +# Source: pyroscope/charts/minio/templates/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +spec: + updateStrategy: + type: RollingUpdate + podManagementPolicy: "Parallel" + serviceName: pyroscope-dev-minio-svc + replicas: 1 + selector: + matchLabels: + app: minio + release: pyroscope-dev + template: + metadata: + name: pyroscope-dev-minio + labels: + app: minio + release: pyroscope-dev + annotations: + checksum/secrets: 1327df257dd66b53a08dc3d9f2584d6c07cd43932cd3c3f68a7ffc636c5a0d92 + checksum/config: 68ad5341411f10a6da13194dfbe5544a594ccedef5dfb12d34529d2be6d0f67f + spec: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + + serviceAccountName: minio-sa + containers: + - name: minio + image: quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z + imagePullPolicy: IfNotPresent + + command: [ "/bin/sh", + "-ce", + "/usr/bin/docker-entrypoint.sh minio server http://pyroscope-dev-minio-{0...0}.pyroscope-dev-minio-svc.default.svc.cluster.local/export-{0...1} -S /etc/minio/certs/ --address :9000 --console-address :9001" ] + volumeMounts: + - name: export-0 + mountPath: /export-0 + - name: export-1 + mountPath: /export-1 + ports: + - name: http + containerPort: 9000 + - name: http-console + containerPort: 9001 + env: + - name: MINIO_ROOT_USER + valueFrom: + secretKeyRef: + name: pyroscope-dev-minio + key: rootUser + - name: MINIO_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: pyroscope-dev-minio + key: rootPassword + - name: MINIO_PROMETHEUS_AUTH_TYPE + value: "public" + resources: + requests: + cpu: 100m + memory: 128Mi + volumes: + - name: minio-user + secret: + secretName: pyroscope-dev-minio + volumeClaimTemplates: + - metadata: + name: export-0 + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 5Gi + - metadata: + name: export-1 + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 5Gi +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-compactor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + serviceName: pyroscope-dev-compactor-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" + name: "compactor" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "compactor" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=compactor" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + subPath: default + - name: data + mountPath: /data-compactor + subPath: compactor + resources: + limits: + memory: 16Gi + requests: + cpu: 1 + memory: 8Gi + terminationGracePeriodSeconds: 1200 + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-ingester + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + serviceName: pyroscope-dev-ingester-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" + name: "ingester" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "ingester" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=ingester" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 16Gi + requests: + cpu: 1 + memory: 8Gi + terminationGracePeriodSeconds: 600 + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-store-gateway + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + serviceName: pyroscope-dev-store-gateway-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" + name: "store-gateway" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "store-gateway" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=store-gateway" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + initialDelaySeconds: 60 + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 16Gi + requests: + cpu: 1 + memory: 8Gi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/charts/minio/templates/post-install-create-bucket-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pyroscope-dev-minio-make-bucket-job + namespace: "default" + labels: + app: minio-make-bucket-job + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + app: minio-job + release: pyroscope-dev + spec: + restartPolicy: OnFailure + volumes: + - name: minio-configuration + projected: + sources: + - configMap: + name: pyroscope-dev-minio + - secret: + name: pyroscope-dev-minio + + serviceAccountName: minio-sa + containers: + - name: minio-mc + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "/config/initialize"] + env: + - name: MINIO_ENDPOINT + value: pyroscope-dev-minio + - name: MINIO_PORT + value: "9000" + volumeMounts: + - name: minio-configuration + mountPath: /config + resources: + requests: + memory: 128Mi +--- +# Source: pyroscope/charts/minio/templates/post-install-create-user-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pyroscope-dev-minio-make-user-job + namespace: "default" + labels: + app: minio-make-user-job + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + app: minio-job + release: pyroscope-dev + spec: + restartPolicy: OnFailure + volumes: + - name: minio-configuration + projected: + sources: + - configMap: + name: pyroscope-dev-minio + - secret: + name: pyroscope-dev-minio + + serviceAccountName: minio-sa + containers: + - name: minio-mc + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "/config/add-user"] + env: + - name: MINIO_ENDPOINT + value: pyroscope-dev-minio + - name: MINIO_PORT + value: "9000" + volumeMounts: + - name: minio-configuration + mountPath: /config + resources: + requests: + memory: 128Mi diff --git a/operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services.yaml b/operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services.yaml new file mode 100644 index 0000000000..51400f2278 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/rendered/legacy-micro-services.yaml @@ -0,0 +1,3630 @@ +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-compactor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-ingester + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-querier + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-query-scheduler + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-store-gateway + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/charts/alloy/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: true +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +--- +# Source: pyroscope/charts/minio/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "minio-sa" + namespace: "default" +--- +# Source: pyroscope/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pyroscope-dev + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +--- +# Source: pyroscope/charts/minio/templates/secrets.yaml +apiVersion: v1 +kind: Secret +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +type: Opaque +data: + rootUser: "Z3JhZmFuYS1weXJvc2NvcGU=" + rootPassword: "c3VwZXJzZWNyZXQ=" +--- +# Source: pyroscope/charts/minio/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +data: + initialize: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkBucketExists ($bucket) + # Check if the bucket exists, by using the exit code of `mc ls` + checkBucketExists() { + BUCKET=$1 + CMD=$(${MC} ls myminio/$BUCKET > /dev/null 2>&1) + return $? + } + + # createBucket ($bucket, $policy, $purge) + # Ensure bucket exists, purging if asked to + createBucket() { + BUCKET=$1 + POLICY=$2 + PURGE=$3 + VERSIONING=$4 + OBJECTLOCKING=$5 + + # Purge the bucket, if set & exists + # Since PURGE is user input, check explicitly for `true` + if [ $PURGE = true ]; then + if checkBucketExists $BUCKET ; then + echo "Purging bucket '$BUCKET'." + set +e ; # don't exit if this fails + ${MC} rm -r --force myminio/$BUCKET + set -e ; # reset `e` as active + else + echo "Bucket '$BUCKET' does not exist, skipping purge." + fi + fi + + # Create the bucket if it does not exist and set objectlocking if enabled (NOTE: versioning will be not changed if OBJECTLOCKING is set because it enables versioning to the Buckets created) + if ! checkBucketExists $BUCKET ; then + if [ ! -z $OBJECTLOCKING ] ; then + if [ $OBJECTLOCKING = true ] ; then + echo "Creating bucket with OBJECTLOCKING '$BUCKET'" + ${MC} mb --with-lock myminio/$BUCKET + elif [ $OBJECTLOCKING = false ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + fi + elif [ -z $OBJECTLOCKING ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + else + echo "Bucket '$BUCKET' already exists." + fi + fi + + + # set versioning for bucket if objectlocking is disabled or not set + if [ -z $OBJECTLOCKING ] ; then + if [ ! -z $VERSIONING ] ; then + if [ $VERSIONING = true ] ; then + echo "Enabling versioning for '$BUCKET'" + ${MC} version enable myminio/$BUCKET + elif [ $VERSIONING = false ] ; then + echo "Suspending versioning for '$BUCKET'" + ${MC} version suspend myminio/$BUCKET + fi + fi + else + echo "Bucket '$BUCKET' versioning unchanged." + fi + + + # At this point, the bucket should exist, skip checking for existence + # Set policy on the bucket + echo "Setting policy of bucket '$BUCKET' to '$POLICY'." + ${MC} policy set $POLICY myminio/$BUCKET + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + + # Create the buckets + createBucket grafana-pyroscope-data none false + add-user: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # AccessKey and secretkey credentials file are added to prevent shell execution errors caused by special characters. + # Special characters for example : ',",<,>,{,} + MINIO_ACCESSKEY_SECRETKEY_TMP="/tmp/accessKey_and_secretKey_tmp" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkUserExists () + # Check if the user exists, by using the exit code of `mc admin user info` + checkUserExists() { + CMD=$(${MC} admin user info myminio $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) > /dev/null 2>&1) + return $? + } + + # createUser ($policy) + createUser() { + POLICY=$1 + #check accessKey_and_secretKey_tmp file + if [[ ! -f $MINIO_ACCESSKEY_SECRETKEY_TMP ]];then + echo "credentials file does not exist" + return 1 + fi + if [[ $(cat $MINIO_ACCESSKEY_SECRETKEY_TMP|wc -l) -ne 2 ]];then + echo "credentials file is invalid" + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + return 1 + fi + USER=$(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) + # Create the user if it does not exist + if ! checkUserExists ; then + echo "Creating user '$USER'" + cat $MINIO_ACCESSKEY_SECRETKEY_TMP | ${MC} admin user add myminio + else + echo "User '$USER' already exists." + fi + #clean up credentials files. + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + + # set policy for user + if [ ! -z $POLICY -a $POLICY != " " ] ; then + echo "Adding policy '$POLICY' for '$USER'" + ${MC} admin policy set myminio $POLICY user=$USER + else + echo "User '$USER' has no policy attached." + fi + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + + # Create the users + echo console > $MINIO_ACCESSKEY_SECRETKEY_TMP + echo console123 >> $MINIO_ACCESSKEY_SECRETKEY_TMP + createUser consoleAdmin + + add-policy: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkPolicyExists ($policy) + # Check if the policy exists, by using the exit code of `mc admin policy info` + checkPolicyExists() { + POLICY=$1 + CMD=$(${MC} admin policy info myminio $POLICY > /dev/null 2>&1) + return $? + } + + # createPolicy($name, $filename) + createPolicy () { + NAME=$1 + FILENAME=$2 + + # Create the name if it does not exist + echo "Checking policy: $NAME (in /config/$FILENAME.json)" + if ! checkPolicyExists $NAME ; then + echo "Creating policy '$NAME'" + else + echo "Policy '$NAME' already exists." + fi + ${MC} admin policy add myminio $NAME /config/$FILENAME.json + + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + custom-command: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # runCommand ($@) + # Run custom mc command + runCommand() { + ${MC} "$@" + return $? + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme +--- +# Source: pyroscope/templates/configmap-alloy.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: alloy-config-pyroscope + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.alloy: | + logging { + level = "info" + format = "logfmt" + } + + discovery.kubernetes "pyroscope_kubernetes" { + role = "pod" + } + + // The default scrape config allows to define annotations based scraping. + // + // For example the following annotations: + // + // ``` + // profiles.grafana.com/memory.scrape: "true" + // profiles.grafana.com/memory.port: "8080" + // profiles.grafana.com/cpu.scrape: "true" + // profiles.grafana.com/cpu.port: "8080" + // profiles.grafana.com/goroutine.scrape: "true" + // profiles.grafana.com/goroutine.port: "8080" + // ``` + // + // will scrape the `memory`, `cpu` and `goroutine` profiles from the `8080` port of the pod. + // + // For more information see https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/helm/#optional-scrape-your-own-workloads-profiles + discovery.relabel "kubernetes_pods" { + targets = concat(discovery.kubernetes.pyroscope_kubernetes.targets) + + rule { + action = "drop" + source_labels = ["__meta_kubernetes_pod_phase"] + regex = "Pending|Succeeded|Failed|Completed" + } + + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_label_(.+)" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // Set service_name by choosing the first non-empty value from the following ordered list: + // - pod.annotation[profiles.grafana.com/service_name] + // - pod.annotation[resource.opentelemetry.io/service.name] + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_annotation_profiles_grafana_com_service_name", + "__meta_kubernetes_pod_annotation_resource_opentelemetry_io_service_name", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "service_name" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_repository"] + target_label = "service_repository" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_git_ref"] + target_label = "service_git_ref" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_root_path"] + target_label = "service_root_path" + } + } + + discovery.relabel "kubernetes_pods_memory_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_memory_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_memory" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_memory_default_name.output, discovery.relabel.kubernetes_pods_memory_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = true + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_cpu_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_cpu_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_cpu" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_cpu_default_name.output, discovery.relabel.kubernetes_pods_cpu_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = true + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_goroutine_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_goroutine_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_goroutine" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_goroutine_default_name.output, discovery.relabel.kubernetes_pods_goroutine_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = true + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_block_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_block_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_block" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_block_default_name.output, discovery.relabel.kubernetes_pods_block_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = true + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_mutex_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_mutex_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_mutex" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_mutex_default_name.output, discovery.relabel.kubernetes_pods_mutex_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = true + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_fgprof_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_fgprof_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_fgprof" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_fgprof_default_name.output, discovery.relabel.kubernetes_pods_fgprof_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = true + } + } + } + + pyroscope.write "pyroscope_write" { + endpoint { + url = "http://pyroscope-dev-distributor.default.svc.cluster.local.:4040" + } + } +--- +# Source: pyroscope/templates/configmap-overrides.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-overrides-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + overrides.yaml: | + overrides: + {} +--- +# Source: pyroscope/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.yaml: | + storage: + backend: s3 + s3: + access_key_id: grafana-pyroscope + bucket_name: grafana-pyroscope-data + endpoint: pyroscope-dev-minio:9000 + insecure: true + secret_access_key: supersecret +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +rules: + - apiGroups: + - "" + - discovery.k8s.io + - networking.k8s.io + resources: + - endpoints + - endpointslices + - ingresses + - pods + - services + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - pods + - pods/log + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.grafana.com + resources: + - podlogs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - prometheusrules + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - alertmanagerconfigs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - podmonitors + - servicemonitors + - probes + - scrapeconfigs + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - apps + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + - nodes/proxy + - nodes/metrics + verbs: + - get + - list + - watch + - nonResourceURLs: + - /metrics + verbs: + - get +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pyroscope-dev-alloy +subjects: + - kind: ServiceAccount + name: pyroscope-dev-alloy + namespace: default +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +rules: +- apiGroups: + - "" + - discovery.k8s.io + resources: + - endpointslices + - endpoints + - services + - pods + verbs: + - get + - watch + - list +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pyroscope-dev-discovery +subjects: +- kind: ServiceAccount + name: pyroscope-dev + namespace: default +--- +# Source: pyroscope/charts/alloy/templates/cluster_service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy-cluster + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + clusterIP: 'None' + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + # Do not include the -metrics suffix in the port name, otherwise metrics + # can be double-collected with the non-headless Service if it's also + # enabled. + # + # This service should only be used for clustering, and not metric + # collection. + - name: http + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/charts/alloy/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + - name: http-metrics + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/charts/minio/templates/console-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio-console + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +spec: + type: ClusterIP + ports: + - name: http + port: 9001 + protocol: TCP + targetPort: 9001 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/charts/minio/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + monitoring: "true" +spec: + type: ClusterIP + ports: + - name: http + port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/charts/minio/templates/statefulset.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio-svc + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: "pyroscope-dev" + heritage: "Helm" +spec: + publishNotReadyAddresses: true + clusterIP: None + ports: + - name: http + port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/templates/memberlist-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-memberlist + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + clusterIP: None + ports: + - name: memberlist + port: 7946 + protocol: TCP + targetPort: 7946 + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + # TODO: Ensure only services that offer memberlist register + # pyroscope.grafana.com/memberlist: "true" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ad-hoc-profiles-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-compactor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-compactor-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-distributor-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ingester + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ingester-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-querier + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-querier-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-frontend-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-scheduler + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-scheduler-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-store-gateway + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-store-gateway-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-tenant-settings-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" + name: "ad-hoc-profiles" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "ad-hoc-profiles" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=ad-hoc-profiles" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 4Gi + requests: + cpu: 0.1 + memory: 16Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" + name: "distributor" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "distributor" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=distributor" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 500m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-querier + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "querier" +spec: + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "querier" + name: "querier" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "querier" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=querier" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 1 + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" + name: "query-frontend" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "query-frontend" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=query-frontend" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-query-scheduler + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-scheduler" +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-scheduler" + name: "query-scheduler" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "query-scheduler" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=query-scheduler" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" + name: "tenant-settings" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "tenant-settings" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=tenant-settings" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 4Gi + requests: + cpu: 0.1 + memory: 16Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/charts/alloy/templates/controllers/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy +spec: + replicas: 1 + podManagementPolicy: Parallel + minReadySeconds: 10 + serviceName: pyroscope-dev-alloy + selector: + matchLabels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: alloy + profiles.grafana.com/cpu.port_name: http-metrics + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http-metrics + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http-metrics + profiles.grafana.com/memory.scrape: "true" + profiles.grafana.com/service_git_ref: v1.8.1 + profiles.grafana.com/service_repository: https://github.com/grafana/alloy + labels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + spec: + serviceAccountName: pyroscope-dev-alloy + containers: + - name: alloy + image: docker.io/grafana/alloy:v1.12.2 + imagePullPolicy: IfNotPresent + args: + - run + - /etc/alloy/config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + - --server.http.ui-path-prefix=/ + - --cluster.enabled=true + - --cluster.join-addresses=pyroscope-dev-alloy-cluster + - --stability.level=public-preview + env: + - name: ALLOY_DEPLOY_MODE + value: "helm" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - containerPort: 12345 + name: http-metrics + readinessProbe: + httpGet: + path: /-/ready + port: 12345 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 1 + volumeMounts: + - name: config + mountPath: /etc/alloy + - name: config-reloader + image: quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0 + args: + - --watched-dir=/etc/alloy + - --reload-url=http://localhost:12345/-/reload + volumeMounts: + - name: config + mountPath: /etc/alloy + resources: + requests: + cpu: 10m + memory: 50Mi + dnsPolicy: ClusterFirst + volumes: + - name: config + configMap: + name: alloy-config-pyroscope +--- +# Source: pyroscope/charts/minio/templates/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +spec: + updateStrategy: + type: RollingUpdate + podManagementPolicy: "Parallel" + serviceName: pyroscope-dev-minio-svc + replicas: 1 + selector: + matchLabels: + app: minio + release: pyroscope-dev + template: + metadata: + name: pyroscope-dev-minio + labels: + app: minio + release: pyroscope-dev + annotations: + checksum/secrets: 1327df257dd66b53a08dc3d9f2584d6c07cd43932cd3c3f68a7ffc636c5a0d92 + checksum/config: 68ad5341411f10a6da13194dfbe5544a594ccedef5dfb12d34529d2be6d0f67f + spec: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + + serviceAccountName: minio-sa + containers: + - name: minio + image: quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z + imagePullPolicy: IfNotPresent + + command: [ "/bin/sh", + "-ce", + "/usr/bin/docker-entrypoint.sh minio server http://pyroscope-dev-minio-{0...0}.pyroscope-dev-minio-svc.default.svc.cluster.local/export-{0...1} -S /etc/minio/certs/ --address :9000 --console-address :9001" ] + volumeMounts: + - name: export-0 + mountPath: /export-0 + - name: export-1 + mountPath: /export-1 + ports: + - name: http + containerPort: 9000 + - name: http-console + containerPort: 9001 + env: + - name: MINIO_ROOT_USER + valueFrom: + secretKeyRef: + name: pyroscope-dev-minio + key: rootUser + - name: MINIO_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: pyroscope-dev-minio + key: rootPassword + - name: MINIO_PROMETHEUS_AUTH_TYPE + value: "public" + resources: + requests: + cpu: 100m + memory: 128Mi + volumes: + - name: minio-user + secret: + secretName: pyroscope-dev-minio + volumeClaimTemplates: + - metadata: + name: export-0 + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 5Gi + - metadata: + name: export-1 + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 5Gi +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-compactor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compactor" +spec: + serviceName: pyroscope-dev-compactor-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compactor" + name: "compactor" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "compactor" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=compactor" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + subPath: default + - name: data + mountPath: /data-compactor + subPath: compactor + resources: + limits: + memory: 16Gi + requests: + cpu: 1 + memory: 8Gi + terminationGracePeriodSeconds: 1200 + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-ingester + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ingester" +spec: + serviceName: pyroscope-dev-ingester-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ingester" + name: "ingester" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "ingester" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=ingester" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 16Gi + requests: + cpu: 1 + memory: 8Gi + terminationGracePeriodSeconds: 600 + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-store-gateway + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "store-gateway" +spec: + serviceName: pyroscope-dev-store-gateway-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "store-gateway" + name: "store-gateway" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "store-gateway" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=store-gateway" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-store-gateway.sharding-ring.replication-factor=3" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + initialDelaySeconds: 60 + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 16Gi + requests: + cpu: 1 + memory: 8Gi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/charts/minio/templates/post-install-create-bucket-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pyroscope-dev-minio-make-bucket-job + namespace: "default" + labels: + app: minio-make-bucket-job + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + app: minio-job + release: pyroscope-dev + spec: + restartPolicy: OnFailure + volumes: + - name: minio-configuration + projected: + sources: + - configMap: + name: pyroscope-dev-minio + - secret: + name: pyroscope-dev-minio + + serviceAccountName: minio-sa + containers: + - name: minio-mc + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "/config/initialize"] + env: + - name: MINIO_ENDPOINT + value: pyroscope-dev-minio + - name: MINIO_PORT + value: "9000" + volumeMounts: + - name: minio-configuration + mountPath: /config + resources: + requests: + memory: 128Mi +--- +# Source: pyroscope/charts/minio/templates/post-install-create-user-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pyroscope-dev-minio-make-user-job + namespace: "default" + labels: + app: minio-make-user-job + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + app: minio-job + release: pyroscope-dev + spec: + restartPolicy: OnFailure + volumes: + - name: minio-configuration + projected: + sources: + - configMap: + name: pyroscope-dev-minio + - secret: + name: pyroscope-dev-minio + + serviceAccountName: minio-sa + containers: + - name: minio-mc + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "/config/add-user"] + env: + - name: MINIO_ENDPOINT + value: pyroscope-dev-minio + - name: MINIO_PORT + value: "9000" + volumeMounts: + - name: minio-configuration + mountPath: /config + resources: + requests: + memory: 128Mi diff --git a/operations/pyroscope/helm/pyroscope/rendered/micro-services-hpa.yaml b/operations/pyroscope/helm/pyroscope/rendered/micro-services-hpa.yaml deleted file mode 100644 index 82d9624a6a..0000000000 --- a/operations/pyroscope/helm/pyroscope/rendered/micro-services-hpa.yaml +++ /dev/null @@ -1,3098 +0,0 @@ ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: pyroscope-dev-compactor - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "compactor" -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "compactor" ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: pyroscope-dev-distributor - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "distributor" -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "distributor" ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: pyroscope-dev-ingester - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "ingester" -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "ingester" ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: pyroscope-dev-querier - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "querier" -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "querier" ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: pyroscope-dev-query-frontend - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-frontend" -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-frontend" ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: pyroscope-dev-query-scheduler - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-scheduler" -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-scheduler" ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: pyroscope-dev-store-gateway - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "store-gateway" -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "store-gateway" ---- -# Source: pyroscope/charts/agent/templates/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: pyroscope-dev-agent - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm ---- -# Source: pyroscope/charts/minio/templates/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: "minio-sa" - namespace: "default" ---- -# Source: pyroscope/templates/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: pyroscope-dev - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm ---- -# Source: pyroscope/charts/minio/templates/secrets.yaml -apiVersion: v1 -kind: Secret -metadata: - name: pyroscope-dev-minio - namespace: "default" - labels: - app: minio - chart: minio-4.0.12 - release: pyroscope-dev - heritage: Helm -type: Opaque -data: - rootUser: "Z3JhZmFuYS1weXJvc2NvcGU=" - rootPassword: "c3VwZXJzZWNyZXQ=" ---- -# Source: pyroscope/charts/minio/templates/configmap.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: pyroscope-dev-minio - namespace: "default" - labels: - app: minio - chart: minio-4.0.12 - release: pyroscope-dev - heritage: Helm -data: - initialize: |- - #!/bin/sh - set -e ; # Have script exit in the event of a failed command. - MC_CONFIG_DIR="/etc/minio/mc/" - MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" - - # connectToMinio - # Use a check-sleep-check loop to wait for MinIO service to be available - connectToMinio() { - SCHEME=$1 - ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts - set -e ; # fail if we can't read the keys. - ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; - set +e ; # The connections to minio are allowed to fail. - echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; - MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; - $MC_COMMAND ; - STATUS=$? ; - until [ $STATUS = 0 ] - do - ATTEMPTS=`expr $ATTEMPTS + 1` ; - echo \"Failed attempts: $ATTEMPTS\" ; - if [ $ATTEMPTS -gt $LIMIT ]; then - exit 1 ; - fi ; - sleep 2 ; # 1 second intervals between attempts - $MC_COMMAND ; - STATUS=$? ; - done ; - set -e ; # reset `e` as active - return 0 - } - - # checkBucketExists ($bucket) - # Check if the bucket exists, by using the exit code of `mc ls` - checkBucketExists() { - BUCKET=$1 - CMD=$(${MC} ls myminio/$BUCKET > /dev/null 2>&1) - return $? - } - - # createBucket ($bucket, $policy, $purge) - # Ensure bucket exists, purging if asked to - createBucket() { - BUCKET=$1 - POLICY=$2 - PURGE=$3 - VERSIONING=$4 - OBJECTLOCKING=$5 - - # Purge the bucket, if set & exists - # Since PURGE is user input, check explicitly for `true` - if [ $PURGE = true ]; then - if checkBucketExists $BUCKET ; then - echo "Purging bucket '$BUCKET'." - set +e ; # don't exit if this fails - ${MC} rm -r --force myminio/$BUCKET - set -e ; # reset `e` as active - else - echo "Bucket '$BUCKET' does not exist, skipping purge." - fi - fi - - # Create the bucket if it does not exist and set objectlocking if enabled (NOTE: versioning will be not changed if OBJECTLOCKING is set because it enables versioning to the Buckets created) - if ! checkBucketExists $BUCKET ; then - if [ ! -z $OBJECTLOCKING ] ; then - if [ $OBJECTLOCKING = true ] ; then - echo "Creating bucket with OBJECTLOCKING '$BUCKET'" - ${MC} mb --with-lock myminio/$BUCKET - elif [ $OBJECTLOCKING = false ] ; then - echo "Creating bucket '$BUCKET'" - ${MC} mb myminio/$BUCKET - fi - elif [ -z $OBJECTLOCKING ] ; then - echo "Creating bucket '$BUCKET'" - ${MC} mb myminio/$BUCKET - else - echo "Bucket '$BUCKET' already exists." - fi - fi - - - # set versioning for bucket if objectlocking is disabled or not set - if [ -z $OBJECTLOCKING ] ; then - if [ ! -z $VERSIONING ] ; then - if [ $VERSIONING = true ] ; then - echo "Enabling versioning for '$BUCKET'" - ${MC} version enable myminio/$BUCKET - elif [ $VERSIONING = false ] ; then - echo "Suspending versioning for '$BUCKET'" - ${MC} version suspend myminio/$BUCKET - fi - fi - else - echo "Bucket '$BUCKET' versioning unchanged." - fi - - - # At this point, the bucket should exist, skip checking for existence - # Set policy on the bucket - echo "Setting policy of bucket '$BUCKET' to '$POLICY'." - ${MC} policy set $POLICY myminio/$BUCKET - } - - # Try connecting to MinIO instance - scheme=http - connectToMinio $scheme - - - - # Create the buckets - createBucket grafana-pyroscope-data none false - add-user: |- - #!/bin/sh - set -e ; # Have script exit in the event of a failed command. - MC_CONFIG_DIR="/etc/minio/mc/" - MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" - - # AccessKey and secretkey credentials file are added to prevent shell execution errors caused by special characters. - # Special characters for example : ',",<,>,{,} - MINIO_ACCESSKEY_SECRETKEY_TMP="/tmp/accessKey_and_secretKey_tmp" - - # connectToMinio - # Use a check-sleep-check loop to wait for MinIO service to be available - connectToMinio() { - SCHEME=$1 - ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts - set -e ; # fail if we can't read the keys. - ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; - set +e ; # The connections to minio are allowed to fail. - echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; - MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; - $MC_COMMAND ; - STATUS=$? ; - until [ $STATUS = 0 ] - do - ATTEMPTS=`expr $ATTEMPTS + 1` ; - echo \"Failed attempts: $ATTEMPTS\" ; - if [ $ATTEMPTS -gt $LIMIT ]; then - exit 1 ; - fi ; - sleep 2 ; # 1 second intervals between attempts - $MC_COMMAND ; - STATUS=$? ; - done ; - set -e ; # reset `e` as active - return 0 - } - - # checkUserExists () - # Check if the user exists, by using the exit code of `mc admin user info` - checkUserExists() { - CMD=$(${MC} admin user info myminio $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) > /dev/null 2>&1) - return $? - } - - # createUser ($policy) - createUser() { - POLICY=$1 - #check accessKey_and_secretKey_tmp file - if [[ ! -f $MINIO_ACCESSKEY_SECRETKEY_TMP ]];then - echo "credentials file does not exist" - return 1 - fi - if [[ $(cat $MINIO_ACCESSKEY_SECRETKEY_TMP|wc -l) -ne 2 ]];then - echo "credentials file is invalid" - rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP - return 1 - fi - USER=$(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) - # Create the user if it does not exist - if ! checkUserExists ; then - echo "Creating user '$USER'" - cat $MINIO_ACCESSKEY_SECRETKEY_TMP | ${MC} admin user add myminio - else - echo "User '$USER' already exists." - fi - #clean up credentials files. - rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP - - # set policy for user - if [ ! -z $POLICY -a $POLICY != " " ] ; then - echo "Adding policy '$POLICY' for '$USER'" - ${MC} admin policy set myminio $POLICY user=$USER - else - echo "User '$USER' has no policy attached." - fi - } - - # Try connecting to MinIO instance - scheme=http - connectToMinio $scheme - - - - # Create the users - echo console > $MINIO_ACCESSKEY_SECRETKEY_TMP - echo console123 >> $MINIO_ACCESSKEY_SECRETKEY_TMP - createUser consoleAdmin - - add-policy: |- - #!/bin/sh - set -e ; # Have script exit in the event of a failed command. - MC_CONFIG_DIR="/etc/minio/mc/" - MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" - - # connectToMinio - # Use a check-sleep-check loop to wait for MinIO service to be available - connectToMinio() { - SCHEME=$1 - ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts - set -e ; # fail if we can't read the keys. - ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; - set +e ; # The connections to minio are allowed to fail. - echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; - MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; - $MC_COMMAND ; - STATUS=$? ; - until [ $STATUS = 0 ] - do - ATTEMPTS=`expr $ATTEMPTS + 1` ; - echo \"Failed attempts: $ATTEMPTS\" ; - if [ $ATTEMPTS -gt $LIMIT ]; then - exit 1 ; - fi ; - sleep 2 ; # 1 second intervals between attempts - $MC_COMMAND ; - STATUS=$? ; - done ; - set -e ; # reset `e` as active - return 0 - } - - # checkPolicyExists ($policy) - # Check if the policy exists, by using the exit code of `mc admin policy info` - checkPolicyExists() { - POLICY=$1 - CMD=$(${MC} admin policy info myminio $POLICY > /dev/null 2>&1) - return $? - } - - # createPolicy($name, $filename) - createPolicy () { - NAME=$1 - FILENAME=$2 - - # Create the name if it does not exist - echo "Checking policy: $NAME (in /config/$FILENAME.json)" - if ! checkPolicyExists $NAME ; then - echo "Creating policy '$NAME'" - else - echo "Policy '$NAME' already exists." - fi - ${MC} admin policy add myminio $NAME /config/$FILENAME.json - - } - - # Try connecting to MinIO instance - scheme=http - connectToMinio $scheme - - - custom-command: |- - #!/bin/sh - set -e ; # Have script exit in the event of a failed command. - MC_CONFIG_DIR="/etc/minio/mc/" - MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" - - # connectToMinio - # Use a check-sleep-check loop to wait for MinIO service to be available - connectToMinio() { - SCHEME=$1 - ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts - set -e ; # fail if we can't read the keys. - ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; - set +e ; # The connections to minio are allowed to fail. - echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; - MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; - $MC_COMMAND ; - STATUS=$? ; - until [ $STATUS = 0 ] - do - ATTEMPTS=`expr $ATTEMPTS + 1` ; - echo \"Failed attempts: $ATTEMPTS\" ; - if [ $ATTEMPTS -gt $LIMIT ]; then - exit 1 ; - fi ; - sleep 2 ; # 1 second intervals between attempts - $MC_COMMAND ; - STATUS=$? ; - done ; - set -e ; # reset `e` as active - return 0 - } - - # runCommand ($@) - # Run custom mc command - runCommand() { - ${MC} "$@" - return $? - } - - # Try connecting to MinIO instance - scheme=http - connectToMinio $scheme ---- -# Source: pyroscope/templates/configmap-agent.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: grafana-agent-config-pyroscope - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -data: - config.river: | - logging { - level = "info" - format = "logfmt" - } - - discovery.kubernetes "pyroscope_kubernetes" { - role = "pod" - } - - // The default scrape config allows to define annotations based scraping. - // - // For example the following annotations: - // - // ``` - // profiles.grafana.com/memory.scrape: "true" - // profiles.grafana.com/memory.port: "8080" - // profiles.grafana.com/cpu.scrape: "true" - // profiles.grafana.com/cpu.port: "8080" - // profiles.grafana.com/goroutine.scrape: "true" - // profiles.grafana.com/goroutine.port: "8080" - // ``` - // - // will scrape the `memory`, `cpu` and `goroutine` profiles from the `8080` port of the pod. - // - // For more information see https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/helm/#optional-scrape-your-own-workloads-profiles - discovery.relabel "kubernetes_pods" { - targets = concat(discovery.kubernetes.pyroscope_kubernetes.targets) - - rule { - action = "drop" - source_labels = ["__meta_kubernetes_pod_phase"] - regex = "Pending|Succeeded|Failed|Completed" - } - - rule { - action = "labelmap" - regex = "__meta_kubernetes_pod_label_(.+)" - } - - rule { - action = "replace" - source_labels = ["__meta_kubernetes_namespace"] - target_label = "namespace" - } - - rule { - action = "replace" - source_labels = ["__meta_kubernetes_pod_name"] - target_label = "pod" - } - - rule { - action = "replace" - source_labels = ["__meta_kubernetes_pod_container_name"] - target_label = "container" - } - } - - discovery.relabel "kubernetes_pods_memory_default_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] - action = "keep" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_number"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - discovery.relabel "kubernetes_pods_memory_custom_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] - action = "drop" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_name"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - pyroscope.scrape "pyroscope_scrape_memory" { - clustering { - enabled = true - } - - targets = concat(discovery.relabel.kubernetes_pods_memory_default_name.output, discovery.relabel.kubernetes_pods_memory_custom_name.output) - forward_to = [pyroscope.write.pyroscope_write.receiver] - - profiling_config { - profile.memory { - enabled = true - } - - profile.process_cpu { - enabled = false - } - - profile.goroutine { - enabled = false - } - - profile.block { - enabled = false - } - - profile.mutex { - enabled = false - } - - profile.fgprof { - enabled = false - } - } - } - - discovery.relabel "kubernetes_pods_cpu_default_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] - action = "keep" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_number"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - discovery.relabel "kubernetes_pods_cpu_custom_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] - action = "drop" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_name"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - pyroscope.scrape "pyroscope_scrape_cpu" { - clustering { - enabled = true - } - - targets = concat(discovery.relabel.kubernetes_pods_cpu_default_name.output, discovery.relabel.kubernetes_pods_cpu_custom_name.output) - forward_to = [pyroscope.write.pyroscope_write.receiver] - - profiling_config { - profile.memory { - enabled = false - } - - profile.process_cpu { - enabled = true - } - - profile.goroutine { - enabled = false - } - - profile.block { - enabled = false - } - - profile.mutex { - enabled = false - } - - profile.fgprof { - enabled = false - } - } - } - - discovery.relabel "kubernetes_pods_goroutine_default_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] - action = "keep" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_number"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - discovery.relabel "kubernetes_pods_goroutine_custom_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] - action = "drop" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_name"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - pyroscope.scrape "pyroscope_scrape_goroutine" { - clustering { - enabled = true - } - - targets = concat(discovery.relabel.kubernetes_pods_goroutine_default_name.output, discovery.relabel.kubernetes_pods_goroutine_custom_name.output) - forward_to = [pyroscope.write.pyroscope_write.receiver] - - profiling_config { - profile.memory { - enabled = false - } - - profile.process_cpu { - enabled = false - } - - profile.goroutine { - enabled = true - } - - profile.block { - enabled = false - } - - profile.mutex { - enabled = false - } - - profile.fgprof { - enabled = false - } - } - } - - discovery.relabel "kubernetes_pods_block_default_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] - action = "keep" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_number"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - discovery.relabel "kubernetes_pods_block_custom_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] - action = "drop" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_name"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - pyroscope.scrape "pyroscope_scrape_block" { - clustering { - enabled = true - } - - targets = concat(discovery.relabel.kubernetes_pods_block_default_name.output, discovery.relabel.kubernetes_pods_block_custom_name.output) - forward_to = [pyroscope.write.pyroscope_write.receiver] - - profiling_config { - profile.memory { - enabled = false - } - - profile.process_cpu { - enabled = false - } - - profile.goroutine { - enabled = false - } - - profile.block { - enabled = true - } - - profile.mutex { - enabled = false - } - - profile.fgprof { - enabled = false - } - } - } - - discovery.relabel "kubernetes_pods_mutex_default_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] - action = "keep" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_number"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - discovery.relabel "kubernetes_pods_mutex_custom_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] - action = "drop" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_name"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - pyroscope.scrape "pyroscope_scrape_mutex" { - clustering { - enabled = true - } - - targets = concat(discovery.relabel.kubernetes_pods_mutex_default_name.output, discovery.relabel.kubernetes_pods_mutex_custom_name.output) - forward_to = [pyroscope.write.pyroscope_write.receiver] - - profiling_config { - profile.memory { - enabled = false - } - - profile.process_cpu { - enabled = false - } - - profile.goroutine { - enabled = false - } - - profile.block { - enabled = false - } - - profile.mutex { - enabled = true - } - - profile.fgprof { - enabled = false - } - } - } - - discovery.relabel "kubernetes_pods_fgprof_default_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] - action = "keep" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_number"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - discovery.relabel "kubernetes_pods_fgprof_custom_name" { - targets = concat(discovery.relabel.kubernetes_pods.output) - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] - action = "keep" - regex = "true" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] - action = "drop" - regex = "" - } - - rule { - source_labels = ["__meta_kubernetes_pod_container_port_name"] - target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name" - action = "keepequal" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] - action = "replace" - regex = "(https?)" - target_label = "__scheme__" - replacement = "$1" - } - - rule { - source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] - action = "replace" - regex = "(.+)" - target_label = "__profile_path__" - replacement = "$1" - } - - rule { - source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] - action = "replace" - regex = "(.+?)(?::\\d+)?;(\\d+)" - target_label = "__address__" - replacement = "$1:$2" - } - } - - pyroscope.scrape "pyroscope_scrape_fgprof" { - clustering { - enabled = true - } - - targets = concat(discovery.relabel.kubernetes_pods_fgprof_default_name.output, discovery.relabel.kubernetes_pods_fgprof_custom_name.output) - forward_to = [pyroscope.write.pyroscope_write.receiver] - - profiling_config { - profile.memory { - enabled = false - } - - profile.process_cpu { - enabled = false - } - - profile.goroutine { - enabled = false - } - - profile.block { - enabled = false - } - - profile.mutex { - enabled = false - } - - profile.fgprof { - enabled = true - } - } - } - - pyroscope.write "pyroscope_write" { - endpoint { - url = "http://pyroscope-dev-distributor.default.svc.cluster.local.:4040" - } - } ---- -# Source: pyroscope/templates/configmap-overrides.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: pyroscope-dev-overrides-config - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -data: - overrides.yaml: | - overrides: - {} ---- -# Source: pyroscope/templates/configmap.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: pyroscope-dev-config - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -data: - config.yaml: | - storage: - backend: s3 - s3: - access_key_id: grafana-pyroscope - bucket_name: grafana-pyroscope-data - endpoint: pyroscope-dev-minio:9000 - insecure: true - secret_access_key: supersecret ---- -# Source: pyroscope/charts/agent/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: pyroscope-dev-agent - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm -rules: - # Rules which allow discovery.kubernetes to function. - - apiGroups: - - "" - - "discovery.k8s.io" - - "networking.k8s.io" - resources: - - endpoints - - endpointslices - - ingresses - - nodes - - nodes/proxy - - nodes/metrics - - pods - - services - verbs: - - get - - list - - watch - # Rules which allow loki.source.kubernetes and loki.source.podlogs to work. - - apiGroups: - - "" - resources: - - pods - - pods/log - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - "monitoring.grafana.com" - resources: - - podlogs - verbs: - - get - - list - - watch - # Rules which allow mimir.rules.kubernetes to work. - - apiGroups: ["monitoring.coreos.com"] - resources: - - prometheusrules - verbs: - - get - - list - - watch - - nonResourceURLs: - - /metrics - verbs: - - get - # Rules for prometheus.kubernetes.* - - apiGroups: ["monitoring.coreos.com"] - resources: - - podmonitors - - servicemonitors - - probes - verbs: - - get - - list - - watch - # Rules which allow eventhandler to work. - - apiGroups: - - "" - resources: - - events - verbs: - - get - - list - - watch ---- -# Source: pyroscope/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: default-pyroscope-dev - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -rules: -- apiGroups: - - "" - resources: - - pods - verbs: - - list - - watch -- apiGroups: - - "" - resources: - - nodes - verbs: - - get ---- -# Source: pyroscope/charts/agent/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: pyroscope-dev-agent - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: pyroscope-dev-agent -subjects: - - kind: ServiceAccount - name: pyroscope-dev-agent - namespace: default ---- -# Source: pyroscope/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: default-pyroscope-dev - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: default-pyroscope-dev -subjects: - - kind: ServiceAccount - name: pyroscope-dev - namespace: default ---- -# Source: pyroscope/charts/agent/templates/cluster_service.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-agent-cluster - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm -spec: - type: ClusterIP - clusterIP: 'None' - selector: - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - ports: - # Do not include the -metrics suffix in the port name, otherwise metrics - # can be double-collected with the non-headless Service if it's also - # enabled. - # - # This service should only be used for clustering, and not metric - # collection. - - name: http - port: 80 - targetPort: 80 - protocol: "TCP" ---- -# Source: pyroscope/charts/agent/templates/service.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-agent - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm -spec: - type: ClusterIP - selector: - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - ports: - - name: http-metrics - port: 80 - targetPort: 80 - protocol: "TCP" ---- -# Source: pyroscope/charts/minio/templates/console-service.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-minio-console - namespace: "default" - labels: - app: minio - chart: minio-4.0.12 - release: pyroscope-dev - heritage: Helm -spec: - type: ClusterIP - ports: - - name: http - port: 9001 - protocol: TCP - targetPort: 9001 - selector: - app: minio - release: pyroscope-dev ---- -# Source: pyroscope/charts/minio/templates/service.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-minio - namespace: "default" - labels: - app: minio - chart: minio-4.0.12 - release: pyroscope-dev - heritage: Helm - monitoring: "true" -spec: - type: ClusterIP - ports: - - name: http - port: 9000 - protocol: TCP - targetPort: 9000 - selector: - app: minio - release: pyroscope-dev ---- -# Source: pyroscope/charts/minio/templates/statefulset.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-minio-svc - namespace: "default" - labels: - app: minio - chart: minio-4.0.12 - release: "pyroscope-dev" - heritage: "Helm" -spec: - publishNotReadyAddresses: true - clusterIP: None - ports: - - name: http - port: 9000 - protocol: TCP - targetPort: 9000 - selector: - app: minio - release: pyroscope-dev ---- -# Source: pyroscope/templates/memberlist-service.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-memberlist - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -spec: - type: ClusterIP - clusterIP: None - ports: - - name: memberlist - port: 7946 - protocol: TCP - targetPort: 7946 - publishNotReadyAddresses: true - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - # TODO: Ensure only services that offer memberlist register - # pyroscope.grafana.com/memberlist: "true" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-compactor - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "compactor" -spec: - type: ClusterIP - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "compactor" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-compactor-headless - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "compactor" -spec: - type: ClusterIP - clusterIP: None - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "compactor" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-distributor - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "distributor" -spec: - type: ClusterIP - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "distributor" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-distributor-headless - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "distributor" -spec: - type: ClusterIP - clusterIP: None - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "distributor" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-ingester - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "ingester" -spec: - type: ClusterIP - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "ingester" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-ingester-headless - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "ingester" -spec: - type: ClusterIP - clusterIP: None - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "ingester" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-querier - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "querier" -spec: - type: ClusterIP - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "querier" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-querier-headless - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "querier" -spec: - type: ClusterIP - clusterIP: None - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "querier" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-query-frontend - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-frontend" -spec: - type: ClusterIP - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-frontend" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-query-frontend-headless - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-frontend" -spec: - type: ClusterIP - clusterIP: None - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-frontend" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-query-scheduler - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-scheduler" -spec: - type: ClusterIP - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-scheduler" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-query-scheduler-headless - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-scheduler" -spec: - type: ClusterIP - clusterIP: None - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-scheduler" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-store-gateway - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "store-gateway" -spec: - type: ClusterIP - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "store-gateway" ---- -# Source: pyroscope/templates/services.yaml -apiVersion: v1 -kind: Service -metadata: - name: pyroscope-dev-store-gateway-headless - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "store-gateway" -spec: - type: ClusterIP - clusterIP: None - ports: - - port: 4040 - targetPort: http2 - protocol: TCP - name: http2 - selector: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "store-gateway" ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pyroscope-dev-distributor - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "distributor" -spec: - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "distributor" - template: - metadata: - annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 - profiles.grafana.com/cpu.port_name: http2 - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http2 - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http2 - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "distributor" - name: "distributor" - spec: - serviceAccountName: pyroscope-dev - securityContext: - fsGroup: 10001 - runAsNonRoot: true - runAsUser: 10001 - dnsPolicy: ClusterFirst - containers: - - name: "distributor" - securityContext: - {} - image: "grafana/pyroscope:1.6.0" - imagePullPolicy: IfNotPresent - args: - - "-target=distributor" - - "-self-profiling.disable-push=true" - - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" - - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - - "-config.file=/etc/pyroscope/config.yaml" - - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" - ports: - - name: http2 - containerPort: 4040 - protocol: TCP - - name: memberlist - containerPort: 7946 - protocol: TCP - readinessProbe: - httpGet: - path: /ready - port: http2 - scheme: HTTP - volumeMounts: - - name: config - mountPath: /etc/pyroscope/config.yaml - subPath: config.yaml - - name: overrides-config - mountPath: /etc/pyroscope/overrides/ - - name: data - mountPath: /data - resources: - limits: - memory: 1Gi - requests: - cpu: 500m - memory: 256Mi - volumes: - - name: config - configMap: - name: pyroscope-dev-config - - name: overrides-config - configMap: - name: pyroscope-dev-overrides-config - - name: data - emptyDir: {} ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pyroscope-dev-querier - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "querier" -spec: - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "querier" - template: - metadata: - annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 - profiles.grafana.com/cpu.port_name: http2 - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http2 - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http2 - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "querier" - name: "querier" - spec: - serviceAccountName: pyroscope-dev - securityContext: - fsGroup: 10001 - runAsNonRoot: true - runAsUser: 10001 - dnsPolicy: ClusterFirst - containers: - - name: "querier" - securityContext: - {} - image: "grafana/pyroscope:1.6.0" - imagePullPolicy: IfNotPresent - args: - - "-target=querier" - - "-self-profiling.disable-push=true" - - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" - - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - - "-config.file=/etc/pyroscope/config.yaml" - - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" - ports: - - name: http2 - containerPort: 4040 - protocol: TCP - - name: memberlist - containerPort: 7946 - protocol: TCP - readinessProbe: - httpGet: - path: /ready - port: http2 - scheme: HTTP - volumeMounts: - - name: config - mountPath: /etc/pyroscope/config.yaml - subPath: config.yaml - - name: overrides-config - mountPath: /etc/pyroscope/overrides/ - - name: data - mountPath: /data - resources: - limits: - memory: 1Gi - requests: - cpu: 1 - memory: 256Mi - volumes: - - name: config - configMap: - name: pyroscope-dev-config - - name: overrides-config - configMap: - name: pyroscope-dev-overrides-config - - name: data - emptyDir: {} ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pyroscope-dev-query-frontend - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-frontend" -spec: - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-frontend" - template: - metadata: - annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 - profiles.grafana.com/cpu.port_name: http2 - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http2 - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http2 - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-frontend" - name: "query-frontend" - spec: - serviceAccountName: pyroscope-dev - securityContext: - fsGroup: 10001 - runAsNonRoot: true - runAsUser: 10001 - dnsPolicy: ClusterFirst - containers: - - name: "query-frontend" - securityContext: - {} - image: "grafana/pyroscope:1.6.0" - imagePullPolicy: IfNotPresent - args: - - "-target=query-frontend" - - "-self-profiling.disable-push=true" - - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" - - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - - "-config.file=/etc/pyroscope/config.yaml" - - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" - ports: - - name: http2 - containerPort: 4040 - protocol: TCP - - name: memberlist - containerPort: 7946 - protocol: TCP - readinessProbe: - httpGet: - path: /ready - port: http2 - scheme: HTTP - volumeMounts: - - name: config - mountPath: /etc/pyroscope/config.yaml - subPath: config.yaml - - name: overrides-config - mountPath: /etc/pyroscope/overrides/ - - name: data - mountPath: /data - resources: - limits: - memory: 1Gi - requests: - cpu: 100m - memory: 256Mi - volumes: - - name: config - configMap: - name: pyroscope-dev-config - - name: overrides-config - configMap: - name: pyroscope-dev-overrides-config - - name: data - emptyDir: {} ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pyroscope-dev-query-scheduler - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-scheduler" -spec: - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-scheduler" - template: - metadata: - annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 - profiles.grafana.com/cpu.port_name: http2 - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http2 - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http2 - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "query-scheduler" - name: "query-scheduler" - spec: - serviceAccountName: pyroscope-dev - securityContext: - fsGroup: 10001 - runAsNonRoot: true - runAsUser: 10001 - dnsPolicy: ClusterFirst - containers: - - name: "query-scheduler" - securityContext: - {} - image: "grafana/pyroscope:1.6.0" - imagePullPolicy: IfNotPresent - args: - - "-target=query-scheduler" - - "-self-profiling.disable-push=true" - - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" - - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - - "-config.file=/etc/pyroscope/config.yaml" - - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" - ports: - - name: http2 - containerPort: 4040 - protocol: TCP - - name: memberlist - containerPort: 7946 - protocol: TCP - readinessProbe: - httpGet: - path: /ready - port: http2 - scheme: HTTP - volumeMounts: - - name: config - mountPath: /etc/pyroscope/config.yaml - subPath: config.yaml - - name: overrides-config - mountPath: /etc/pyroscope/overrides/ - - name: data - mountPath: /data - resources: - limits: - memory: 1Gi - requests: - cpu: 100m - memory: 256Mi - volumes: - - name: config - configMap: - name: pyroscope-dev-config - - name: overrides-config - configMap: - name: pyroscope-dev-overrides-config - - name: data - emptyDir: {} ---- -# Source: pyroscope/templates/hpa.yaml -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: pyroscope-dev-distributor - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "distributor" -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: pyroscope-dev-distributor - minReplicas: 2 - maxReplicas: 3 - metrics: - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: 60 ---- -# Source: pyroscope/templates/hpa.yaml -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: pyroscope-dev-querier - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "querier" -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: pyroscope-dev-querier - minReplicas: 2 - maxReplicas: 4 - metrics: - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: 60 - behavior: - scaleDown: - stabilizationWindowSeconds: 60 ---- -# Source: pyroscope/templates/hpa.yaml -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: pyroscope-dev-query-frontend - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-frontend" -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: pyroscope-dev-query-frontend - minReplicas: 2 - maxReplicas: 4 - metrics: - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: 60 ---- -# Source: pyroscope/templates/hpa.yaml -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: pyroscope-dev-query-scheduler - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "query-scheduler" -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: pyroscope-dev-query-scheduler - minReplicas: 2 - maxReplicas: 4 - metrics: - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: 40 ---- -# Source: pyroscope/charts/agent/templates/controllers/statefulset.yaml -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: pyroscope-dev-agent - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - podManagementPolicy: Parallel - minReadySeconds: 10 - serviceName: pyroscope-dev-agent - selector: - matchLabels: - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - template: - metadata: - annotations: - profiles.grafana.com/cpu.port_name: http-metrics - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http-metrics - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http-metrics - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - spec: - serviceAccountName: pyroscope-dev-agent - containers: - - name: grafana-agent - image: docker.io/grafana/agent:v0.36.2 - imagePullPolicy: IfNotPresent - args: - - run - - /etc/agent/config.river - - --storage.path=/tmp/agent - - --server.http.listen-addr=0.0.0.0:80 - - --cluster.enabled=true - - --cluster.join-addresses=pyroscope-dev-agent-cluster - env: - - name: AGENT_MODE - value: flow - - name: HOSTNAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - ports: - - containerPort: 80 - name: http-metrics - readinessProbe: - httpGet: - path: /-/ready - port: 80 - initialDelaySeconds: 10 - timeoutSeconds: 1 - volumeMounts: - - name: config - mountPath: /etc/agent - - name: config-reloader - image: docker.io/jimmidyson/configmap-reload:v0.8.0 - args: - - --volume-dir=/etc/agent - - --webhook-url=http://localhost:80/-/reload - volumeMounts: - - name: config - mountPath: /etc/agent - resources: - requests: - cpu: 1m - memory: 5Mi - dnsPolicy: ClusterFirst - volumes: - - name: config - configMap: - name: grafana-agent-config-pyroscope ---- -# Source: pyroscope/charts/minio/templates/statefulset.yaml -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: pyroscope-dev-minio - namespace: "default" - labels: - app: minio - chart: minio-4.0.12 - release: pyroscope-dev - heritage: Helm -spec: - updateStrategy: - type: RollingUpdate - podManagementPolicy: "Parallel" - serviceName: pyroscope-dev-minio-svc - replicas: 1 - selector: - matchLabels: - app: minio - release: pyroscope-dev - template: - metadata: - name: pyroscope-dev-minio - labels: - app: minio - release: pyroscope-dev - annotations: - checksum/secrets: 2e760de5dbcac8daf468cd56713bca0aac7d7adc4445e2488b352dbb2b529507 - checksum/config: 925d78a7321daaaa06a6dc4ee47dbaf5b8952be192bdbb57f13805ad472ce4e1 - phlare.grafana.com/port: "9000" - phlare.grafana.com/scrape: "true" - spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - fsGroupChangePolicy: OnRootMismatch - - serviceAccountName: minio-sa - containers: - - name: minio - image: quay.io/minio/minio:RELEASE.2022-08-13T21-54-44Z - imagePullPolicy: IfNotPresent - - command: [ "/bin/sh", - "-ce", - "/usr/bin/docker-entrypoint.sh minio server http://pyroscope-dev-minio-{0...0}.pyroscope-dev-minio-svc.default.svc.cluster.local/export-{0...1} -S /etc/minio/certs/ --address :9000 --console-address :9001" ] - volumeMounts: - - name: export-0 - mountPath: /export-0 - - name: export-1 - mountPath: /export-1 - ports: - - name: http - containerPort: 9000 - - name: http-console - containerPort: 9001 - env: - - name: MINIO_ROOT_USER - valueFrom: - secretKeyRef: - name: pyroscope-dev-minio - key: rootUser - - name: MINIO_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: pyroscope-dev-minio - key: rootPassword - - name: MINIO_PROMETHEUS_AUTH_TYPE - value: "public" - resources: - requests: - cpu: 100m - memory: 128Mi - volumes: - - name: minio-user - secret: - secretName: pyroscope-dev-minio - volumeClaimTemplates: - - metadata: - name: export-0 - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: 5Gi - - metadata: - name: export-1 - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: 5Gi ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: pyroscope-dev-compactor - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "compactor" -spec: - serviceName: pyroscope-dev-compactor-headless - podManagementPolicy: Parallel - replicas: 3 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "compactor" - template: - metadata: - annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 - profiles.grafana.com/cpu.port_name: http2 - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http2 - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http2 - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "compactor" - name: "compactor" - spec: - serviceAccountName: pyroscope-dev - securityContext: - fsGroup: 10001 - runAsNonRoot: true - runAsUser: 10001 - dnsPolicy: ClusterFirst - containers: - - name: "compactor" - securityContext: - {} - image: "grafana/pyroscope:1.6.0" - imagePullPolicy: IfNotPresent - args: - - "-target=compactor" - - "-self-profiling.disable-push=true" - - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" - - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - - "-config.file=/etc/pyroscope/config.yaml" - - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" - ports: - - name: http2 - containerPort: 4040 - protocol: TCP - - name: memberlist - containerPort: 7946 - protocol: TCP - readinessProbe: - httpGet: - path: /ready - port: http2 - scheme: HTTP - volumeMounts: - - name: config - mountPath: /etc/pyroscope/config.yaml - subPath: config.yaml - - name: overrides-config - mountPath: /etc/pyroscope/overrides/ - - name: data - mountPath: /data - subPath: default - - name: data - mountPath: /data-compactor - subPath: compactor - resources: - limits: - memory: 16Gi - requests: - cpu: 1 - memory: 8Gi - terminationGracePeriodSeconds: 1200 - volumes: - - name: config - configMap: - name: pyroscope-dev-config - - name: overrides-config - configMap: - name: pyroscope-dev-overrides-config - - name: data - emptyDir: {} ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: pyroscope-dev-ingester - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "ingester" -spec: - serviceName: pyroscope-dev-ingester-headless - podManagementPolicy: Parallel - replicas: 3 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "ingester" - template: - metadata: - annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 - profiles.grafana.com/cpu.port_name: http2 - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http2 - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http2 - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "ingester" - name: "ingester" - spec: - serviceAccountName: pyroscope-dev - securityContext: - fsGroup: 10001 - runAsNonRoot: true - runAsUser: 10001 - dnsPolicy: ClusterFirst - containers: - - name: "ingester" - securityContext: - {} - image: "grafana/pyroscope:1.6.0" - imagePullPolicy: IfNotPresent - args: - - "-target=ingester" - - "-self-profiling.disable-push=true" - - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" - - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - - "-config.file=/etc/pyroscope/config.yaml" - - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" - ports: - - name: http2 - containerPort: 4040 - protocol: TCP - - name: memberlist - containerPort: 7946 - protocol: TCP - readinessProbe: - httpGet: - path: /ready - port: http2 - scheme: HTTP - volumeMounts: - - name: config - mountPath: /etc/pyroscope/config.yaml - subPath: config.yaml - - name: overrides-config - mountPath: /etc/pyroscope/overrides/ - - name: data - mountPath: /data - resources: - limits: - memory: 16Gi - requests: - cpu: 1 - memory: 8Gi - terminationGracePeriodSeconds: 600 - volumes: - - name: config - configMap: - name: pyroscope-dev-config - - name: overrides-config - configMap: - name: pyroscope-dev-overrides-config - - name: data - emptyDir: {} ---- -# Source: pyroscope/templates/deployments-statefulsets.yaml -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: pyroscope-dev-store-gateway - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/component: "store-gateway" -spec: - serviceName: pyroscope-dev-store-gateway-headless - podManagementPolicy: Parallel - replicas: 3 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "store-gateway" - template: - metadata: - annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 - profiles.grafana.com/cpu.port_name: http2 - profiles.grafana.com/cpu.scrape: "true" - profiles.grafana.com/goroutine.port_name: http2 - profiles.grafana.com/goroutine.scrape: "true" - profiles.grafana.com/memory.port_name: http2 - profiles.grafana.com/memory.scrape: "true" - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/component: "store-gateway" - name: "store-gateway" - spec: - serviceAccountName: pyroscope-dev - securityContext: - fsGroup: 10001 - runAsNonRoot: true - runAsUser: 10001 - dnsPolicy: ClusterFirst - containers: - - name: "store-gateway" - securityContext: - {} - image: "grafana/pyroscope:1.6.0" - imagePullPolicy: IfNotPresent - args: - - "-target=store-gateway" - - "-self-profiling.disable-push=true" - - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" - - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - - "-config.file=/etc/pyroscope/config.yaml" - - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" - ports: - - name: http2 - containerPort: 4040 - protocol: TCP - - name: memberlist - containerPort: 7946 - protocol: TCP - readinessProbe: - httpGet: - path: /ready - port: http2 - scheme: HTTP - initialDelaySeconds: 60 - volumeMounts: - - name: config - mountPath: /etc/pyroscope/config.yaml - subPath: config.yaml - - name: overrides-config - mountPath: /etc/pyroscope/overrides/ - - name: data - mountPath: /data - resources: - limits: - memory: 16Gi - requests: - cpu: 1 - memory: 8Gi - volumes: - - name: config - configMap: - name: pyroscope-dev-config - - name: overrides-config - configMap: - name: pyroscope-dev-overrides-config - - name: data - emptyDir: {} ---- -# Source: pyroscope/charts/minio/templates/post-install-create-bucket-job.yaml -apiVersion: batch/v1 -kind: Job -metadata: - name: pyroscope-dev-minio-make-bucket-job - namespace: "default" - labels: - app: minio-make-bucket-job - chart: minio-4.0.12 - release: pyroscope-dev - heritage: Helm - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation -spec: - template: - metadata: - labels: - app: minio-job - release: pyroscope-dev - spec: - restartPolicy: OnFailure - volumes: - - name: minio-configuration - projected: - sources: - - configMap: - name: pyroscope-dev-minio - - secret: - name: pyroscope-dev-minio - containers: - - name: minio-mc - image: "quay.io/minio/mc:RELEASE.2022-08-11T00-30-48Z" - imagePullPolicy: IfNotPresent - command: ["/bin/sh", "/config/initialize"] - env: - - name: MINIO_ENDPOINT - value: pyroscope-dev-minio - - name: MINIO_PORT - value: "9000" - volumeMounts: - - name: minio-configuration - mountPath: /config - resources: - requests: - memory: 128Mi ---- -# Source: pyroscope/charts/minio/templates/post-install-create-user-job.yaml -apiVersion: batch/v1 -kind: Job -metadata: - name: pyroscope-dev-minio-make-user-job - namespace: "default" - labels: - app: minio-make-user-job - chart: minio-4.0.12 - release: pyroscope-dev - heritage: Helm - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation -spec: - template: - metadata: - labels: - app: minio-job - release: pyroscope-dev - spec: - restartPolicy: OnFailure - volumes: - - name: minio-configuration - projected: - sources: - - configMap: - name: pyroscope-dev-minio - - secret: - name: pyroscope-dev-minio - containers: - - name: minio-mc - image: "quay.io/minio/mc:RELEASE.2022-08-11T00-30-48Z" - imagePullPolicy: IfNotPresent - command: ["/bin/sh", "/config/add-user"] - env: - - name: MINIO_ENDPOINT - value: pyroscope-dev-minio - - name: MINIO_PORT - value: "9000" - volumeMounts: - - name: minio-configuration - mountPath: /config - resources: - requests: - memory: 128Mi diff --git a/operations/pyroscope/helm/pyroscope/rendered/micro-services-v2.yaml b/operations/pyroscope/helm/pyroscope/rendered/micro-services-v2.yaml new file mode 100644 index 0000000000..86939f8e45 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/rendered/micro-services-v2.yaml @@ -0,0 +1,3642 @@ +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-admin + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "admin" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "admin" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-compaction-worker + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compaction-worker" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compaction-worker" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-metastore + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "metastore" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "metastore" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-query-backend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-backend" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-backend" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-segment-writer + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "segment-writer" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "segment-writer" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/charts/alloy/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: true +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +--- +# Source: pyroscope/charts/minio/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "minio-sa" + namespace: "default" +--- +# Source: pyroscope/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pyroscope-dev + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +--- +# Source: pyroscope/charts/minio/templates/secrets.yaml +apiVersion: v1 +kind: Secret +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +type: Opaque +data: + rootUser: "Z3JhZmFuYS1weXJvc2NvcGU=" + rootPassword: "c3VwZXJzZWNyZXQ=" +--- +# Source: pyroscope/charts/minio/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +data: + initialize: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkBucketExists ($bucket) + # Check if the bucket exists, by using the exit code of `mc ls` + checkBucketExists() { + BUCKET=$1 + CMD=$(${MC} ls myminio/$BUCKET > /dev/null 2>&1) + return $? + } + + # createBucket ($bucket, $policy, $purge) + # Ensure bucket exists, purging if asked to + createBucket() { + BUCKET=$1 + POLICY=$2 + PURGE=$3 + VERSIONING=$4 + OBJECTLOCKING=$5 + + # Purge the bucket, if set & exists + # Since PURGE is user input, check explicitly for `true` + if [ $PURGE = true ]; then + if checkBucketExists $BUCKET ; then + echo "Purging bucket '$BUCKET'." + set +e ; # don't exit if this fails + ${MC} rm -r --force myminio/$BUCKET + set -e ; # reset `e` as active + else + echo "Bucket '$BUCKET' does not exist, skipping purge." + fi + fi + + # Create the bucket if it does not exist and set objectlocking if enabled (NOTE: versioning will be not changed if OBJECTLOCKING is set because it enables versioning to the Buckets created) + if ! checkBucketExists $BUCKET ; then + if [ ! -z $OBJECTLOCKING ] ; then + if [ $OBJECTLOCKING = true ] ; then + echo "Creating bucket with OBJECTLOCKING '$BUCKET'" + ${MC} mb --with-lock myminio/$BUCKET + elif [ $OBJECTLOCKING = false ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + fi + elif [ -z $OBJECTLOCKING ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + else + echo "Bucket '$BUCKET' already exists." + fi + fi + + + # set versioning for bucket if objectlocking is disabled or not set + if [ -z $OBJECTLOCKING ] ; then + if [ ! -z $VERSIONING ] ; then + if [ $VERSIONING = true ] ; then + echo "Enabling versioning for '$BUCKET'" + ${MC} version enable myminio/$BUCKET + elif [ $VERSIONING = false ] ; then + echo "Suspending versioning for '$BUCKET'" + ${MC} version suspend myminio/$BUCKET + fi + fi + else + echo "Bucket '$BUCKET' versioning unchanged." + fi + + + # At this point, the bucket should exist, skip checking for existence + # Set policy on the bucket + echo "Setting policy of bucket '$BUCKET' to '$POLICY'." + ${MC} policy set $POLICY myminio/$BUCKET + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + + # Create the buckets + createBucket grafana-pyroscope-data none false + add-user: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # AccessKey and secretkey credentials file are added to prevent shell execution errors caused by special characters. + # Special characters for example : ',",<,>,{,} + MINIO_ACCESSKEY_SECRETKEY_TMP="/tmp/accessKey_and_secretKey_tmp" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkUserExists () + # Check if the user exists, by using the exit code of `mc admin user info` + checkUserExists() { + CMD=$(${MC} admin user info myminio $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) > /dev/null 2>&1) + return $? + } + + # createUser ($policy) + createUser() { + POLICY=$1 + #check accessKey_and_secretKey_tmp file + if [[ ! -f $MINIO_ACCESSKEY_SECRETKEY_TMP ]];then + echo "credentials file does not exist" + return 1 + fi + if [[ $(cat $MINIO_ACCESSKEY_SECRETKEY_TMP|wc -l) -ne 2 ]];then + echo "credentials file is invalid" + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + return 1 + fi + USER=$(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) + # Create the user if it does not exist + if ! checkUserExists ; then + echo "Creating user '$USER'" + cat $MINIO_ACCESSKEY_SECRETKEY_TMP | ${MC} admin user add myminio + else + echo "User '$USER' already exists." + fi + #clean up credentials files. + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + + # set policy for user + if [ ! -z $POLICY -a $POLICY != " " ] ; then + echo "Adding policy '$POLICY' for '$USER'" + ${MC} admin policy set myminio $POLICY user=$USER + else + echo "User '$USER' has no policy attached." + fi + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + + # Create the users + echo console > $MINIO_ACCESSKEY_SECRETKEY_TMP + echo console123 >> $MINIO_ACCESSKEY_SECRETKEY_TMP + createUser consoleAdmin + + add-policy: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # checkPolicyExists ($policy) + # Check if the policy exists, by using the exit code of `mc admin policy info` + checkPolicyExists() { + POLICY=$1 + CMD=$(${MC} admin policy info myminio $POLICY > /dev/null 2>&1) + return $? + } + + # createPolicy($name, $filename) + createPolicy () { + NAME=$1 + FILENAME=$2 + + # Create the name if it does not exist + echo "Checking policy: $NAME (in /config/$FILENAME.json)" + if ! checkPolicyExists $NAME ; then + echo "Creating policy '$NAME'" + else + echo "Policy '$NAME' already exists." + fi + ${MC} admin policy add myminio $NAME /config/$FILENAME.json + + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme + + + custom-command: |- + #!/bin/sh + set -e ; # Have script exit in the event of a failed command. + MC_CONFIG_DIR="/etc/minio/mc/" + MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" + + # connectToMinio + # Use a check-sleep-check loop to wait for MinIO service to be available + connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 + } + + # runCommand ($@) + # Run custom mc command + runCommand() { + ${MC} "$@" + return $? + } + + # Try connecting to MinIO instance + scheme=http + connectToMinio $scheme +--- +# Source: pyroscope/templates/configmap-alloy.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: alloy-config-pyroscope + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.alloy: | + logging { + level = "info" + format = "logfmt" + } + + discovery.kubernetes "pyroscope_kubernetes" { + role = "pod" + } + + // The default scrape config allows to define annotations based scraping. + // + // For example the following annotations: + // + // ``` + // profiles.grafana.com/memory.scrape: "true" + // profiles.grafana.com/memory.port: "8080" + // profiles.grafana.com/cpu.scrape: "true" + // profiles.grafana.com/cpu.port: "8080" + // profiles.grafana.com/goroutine.scrape: "true" + // profiles.grafana.com/goroutine.port: "8080" + // ``` + // + // will scrape the `memory`, `cpu` and `goroutine` profiles from the `8080` port of the pod. + // + // For more information see https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/helm/#optional-scrape-your-own-workloads-profiles + discovery.relabel "kubernetes_pods" { + targets = concat(discovery.kubernetes.pyroscope_kubernetes.targets) + + rule { + action = "drop" + source_labels = ["__meta_kubernetes_pod_phase"] + regex = "Pending|Succeeded|Failed|Completed" + } + + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_label_(.+)" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // Set service_name by choosing the first non-empty value from the following ordered list: + // - pod.annotation[profiles.grafana.com/service_name] + // - pod.annotation[resource.opentelemetry.io/service.name] + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_annotation_profiles_grafana_com_service_name", + "__meta_kubernetes_pod_annotation_resource_opentelemetry_io_service_name", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "service_name" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_repository"] + target_label = "service_repository" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_git_ref"] + target_label = "service_git_ref" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_root_path"] + target_label = "service_root_path" + } + } + + discovery.relabel "kubernetes_pods_memory_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_memory_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_memory" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_memory_default_name.output, discovery.relabel.kubernetes_pods_memory_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = true + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_cpu_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_cpu_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_cpu" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_cpu_default_name.output, discovery.relabel.kubernetes_pods_cpu_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = true + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_goroutine_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_goroutine_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_goroutine" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_goroutine_default_name.output, discovery.relabel.kubernetes_pods_goroutine_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = true + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_block_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_block_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_block" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_block_default_name.output, discovery.relabel.kubernetes_pods_block_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = true + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_mutex_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_mutex_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_mutex" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_mutex_default_name.output, discovery.relabel.kubernetes_pods_mutex_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = true + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_fgprof_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_fgprof_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_fgprof" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_fgprof_default_name.output, discovery.relabel.kubernetes_pods_fgprof_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = true + } + } + } + + pyroscope.write "pyroscope_write" { + endpoint { + url = "http://pyroscope-dev-distributor.default.svc.cluster.local.:4040" + } + } +--- +# Source: pyroscope/templates/configmap-overrides.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-overrides-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + overrides.yaml: | + overrides: + {} +--- +# Source: pyroscope/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.yaml: | + storage: + backend: s3 + s3: + access_key_id: grafana-pyroscope + bucket_name: grafana-pyroscope-data + endpoint: pyroscope-dev-minio:9000 + insecure: true + secret_access_key: supersecret +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +rules: + - apiGroups: + - "" + - discovery.k8s.io + - networking.k8s.io + resources: + - endpoints + - endpointslices + - ingresses + - pods + - services + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - pods + - pods/log + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.grafana.com + resources: + - podlogs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - prometheusrules + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - alertmanagerconfigs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - podmonitors + - servicemonitors + - probes + - scrapeconfigs + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - apps + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + - nodes/proxy + - nodes/metrics + verbs: + - get + - list + - watch + - nonResourceURLs: + - /metrics + verbs: + - get +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pyroscope-dev-alloy +subjects: + - kind: ServiceAccount + name: pyroscope-dev-alloy + namespace: default +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +rules: +- apiGroups: + - "" + - discovery.k8s.io + resources: + - endpointslices + - endpoints + - services + - pods + verbs: + - get + - watch + - list +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pyroscope-dev-discovery +subjects: +- kind: ServiceAccount + name: pyroscope-dev + namespace: default +--- +# Source: pyroscope/charts/alloy/templates/cluster_service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy-cluster + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + clusterIP: 'None' + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + # Do not include the -metrics suffix in the port name, otherwise metrics + # can be double-collected with the non-headless Service if it's also + # enabled. + # + # This service should only be used for clustering, and not metric + # collection. + - name: http + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/charts/alloy/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + - name: http-metrics + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/charts/minio/templates/console-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio-console + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +spec: + type: ClusterIP + ports: + - name: http + port: 9001 + protocol: TCP + targetPort: 9001 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/charts/minio/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + monitoring: "true" +spec: + type: ClusterIP + ports: + - name: http + port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/charts/minio/templates/statefulset.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-minio-svc + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: "pyroscope-dev" + heritage: "Helm" +spec: + publishNotReadyAddresses: true + clusterIP: None + ports: + - name: http + port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio + release: pyroscope-dev +--- +# Source: pyroscope/templates/memberlist-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-memberlist + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + clusterIP: None + ports: + - name: memberlist + port: 7946 + protocol: TCP + targetPort: 7946 + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + # TODO: Ensure only services that offer memberlist register + # pyroscope.grafana.com/memberlist: "true" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ad-hoc-profiles-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-admin + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "admin" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "admin" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-admin-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "admin" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "admin" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-compaction-worker + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compaction-worker" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compaction-worker" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-compaction-worker-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compaction-worker" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compaction-worker" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-distributor-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-metastore + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "metastore" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + - port: 9099 + targetPort: raft + protocol: TCP + name: raft + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "metastore" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-metastore-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "metastore" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + - port: 9099 + targetPort: raft + protocol: TCP + name: raft + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "metastore" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-backend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-backend" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-backend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-backend-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-backend" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-backend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-query-frontend-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-segment-writer + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "segment-writer" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "segment-writer" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-segment-writer-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "segment-writer" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "segment-writer" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-tenant-settings-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" + name: "ad-hoc-profiles" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "ad-hoc-profiles" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=ad-hoc-profiles" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 256Mi + requests: + cpu: 0.1 + memory: 16Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-admin + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "admin" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "admin" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "admin" + name: "admin" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "admin" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=admin" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 256Mi + requests: + cpu: 0.1 + memory: 16Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-distributor + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "distributor" +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "distributor" + name: "distributor" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "distributor" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=distributor" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 500m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-query-backend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-backend" +spec: + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-backend" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-backend" + name: "query-backend" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "query-backend" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=query-backend" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 1 + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-query-frontend + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "query-frontend" +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "query-frontend" + name: "query-frontend" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "query-frontend" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=query-frontend" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" + name: "tenant-settings" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "tenant-settings" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=tenant-settings" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 256Mi + requests: + cpu: 0.1 + memory: 16Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/charts/alloy/templates/controllers/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy +spec: + replicas: 1 + podManagementPolicy: Parallel + minReadySeconds: 10 + serviceName: pyroscope-dev-alloy + selector: + matchLabels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: alloy + profiles.grafana.com/cpu.port_name: http-metrics + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http-metrics + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http-metrics + profiles.grafana.com/memory.scrape: "true" + profiles.grafana.com/service_git_ref: v1.8.1 + profiles.grafana.com/service_repository: https://github.com/grafana/alloy + labels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + spec: + serviceAccountName: pyroscope-dev-alloy + containers: + - name: alloy + image: docker.io/grafana/alloy:v1.12.2 + imagePullPolicy: IfNotPresent + args: + - run + - /etc/alloy/config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + - --server.http.ui-path-prefix=/ + - --cluster.enabled=true + - --cluster.join-addresses=pyroscope-dev-alloy-cluster + - --stability.level=public-preview + env: + - name: ALLOY_DEPLOY_MODE + value: "helm" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - containerPort: 12345 + name: http-metrics + readinessProbe: + httpGet: + path: /-/ready + port: 12345 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 1 + volumeMounts: + - name: config + mountPath: /etc/alloy + - name: config-reloader + image: quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0 + args: + - --watched-dir=/etc/alloy + - --reload-url=http://localhost:12345/-/reload + volumeMounts: + - name: config + mountPath: /etc/alloy + resources: + requests: + cpu: 10m + memory: 50Mi + dnsPolicy: ClusterFirst + volumes: + - name: config + configMap: + name: alloy-config-pyroscope +--- +# Source: pyroscope/charts/minio/templates/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-minio + namespace: "default" + labels: + app: minio + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm +spec: + updateStrategy: + type: RollingUpdate + podManagementPolicy: "Parallel" + serviceName: pyroscope-dev-minio-svc + replicas: 1 + selector: + matchLabels: + app: minio + release: pyroscope-dev + template: + metadata: + name: pyroscope-dev-minio + labels: + app: minio + release: pyroscope-dev + annotations: + checksum/secrets: 1327df257dd66b53a08dc3d9f2584d6c07cd43932cd3c3f68a7ffc636c5a0d92 + checksum/config: 68ad5341411f10a6da13194dfbe5544a594ccedef5dfb12d34529d2be6d0f67f + spec: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + + serviceAccountName: minio-sa + containers: + - name: minio + image: quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z + imagePullPolicy: IfNotPresent + + command: [ "/bin/sh", + "-ce", + "/usr/bin/docker-entrypoint.sh minio server http://pyroscope-dev-minio-{0...0}.pyroscope-dev-minio-svc.default.svc.cluster.local/export-{0...1} -S /etc/minio/certs/ --address :9000 --console-address :9001" ] + volumeMounts: + - name: export-0 + mountPath: /export-0 + - name: export-1 + mountPath: /export-1 + ports: + - name: http + containerPort: 9000 + - name: http-console + containerPort: 9001 + env: + - name: MINIO_ROOT_USER + valueFrom: + secretKeyRef: + name: pyroscope-dev-minio + key: rootUser + - name: MINIO_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: pyroscope-dev-minio + key: rootPassword + - name: MINIO_PROMETHEUS_AUTH_TYPE + value: "public" + resources: + requests: + cpu: 100m + memory: 128Mi + volumes: + - name: minio-user + secret: + secretName: pyroscope-dev-minio + volumeClaimTemplates: + - metadata: + name: export-0 + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 5Gi + - metadata: + name: export-1 + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 5Gi +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-compaction-worker + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "compaction-worker" +spec: + serviceName: pyroscope-dev-compaction-worker-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compaction-worker" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "compaction-worker" + name: "compaction-worker" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "compaction-worker" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=compaction-worker" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 2Gi + requests: + cpu: 1 + memory: 1Gi + terminationGracePeriodSeconds: 1200 + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-metastore + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "metastore" +spec: + serviceName: pyroscope-dev-metastore-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "metastore" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "metastore" + name: "metastore" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "metastore" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=metastore" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-metastore.index.cleanup-interval=1m" + - "-metastore.raft.bootstrap-expect-peers=3" + - "-metastore.snapshot-compact-on-restore=true" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.data-dir=./data-metastore/data" + - "-metastore.raft.dir=./data-metastore/raft" + - "-metastore.raft.snapshots-dir=./data-metastore/raft" + - "-metastore.raft.bind-address=:9099" + - "-metastore.raft.server-id=$(POD_NAME).$(PYROSCOPE_METASTORE_SERVICE)" + - "-metastore.raft.advertise-address=$(POD_NAME).$(PYROSCOPE_METASTORE_SERVICE)" + - "-metastore.raft.bootstrap-peers=dnssrvnoa+_raft._tcp.$(PYROSCOPE_METASTORE_SERVICE)" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + - name: raft + containerPort: 9099 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + - name: data + mountPath: /data-metastore + subPath: .metastore + resources: + limits: + memory: 2Gi + requests: + cpu: 1 + memory: 1Gi + terminationGracePeriodSeconds: 1200 + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-segment-writer + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "segment-writer" +spec: + serviceName: pyroscope-dev-segment-writer-headless + podManagementPolicy: Parallel + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "segment-writer" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "segment-writer" + name: "segment-writer" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "segment-writer" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=segment-writer" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-query-backend-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-metastore-headless.$(NAMESPACE_FQDN):9095" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-metastore-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 4Gi + requests: + cpu: 1 + memory: 2Gi + terminationGracePeriodSeconds: 600 + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/charts/minio/templates/post-install-create-bucket-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pyroscope-dev-minio-make-bucket-job + namespace: "default" + labels: + app: minio-make-bucket-job + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + app: minio-job + release: pyroscope-dev + spec: + restartPolicy: OnFailure + volumes: + - name: minio-configuration + projected: + sources: + - configMap: + name: pyroscope-dev-minio + - secret: + name: pyroscope-dev-minio + + serviceAccountName: minio-sa + containers: + - name: minio-mc + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "/config/initialize"] + env: + - name: MINIO_ENDPOINT + value: pyroscope-dev-minio + - name: MINIO_PORT + value: "9000" + volumeMounts: + - name: minio-configuration + mountPath: /config + resources: + requests: + memory: 128Mi +--- +# Source: pyroscope/charts/minio/templates/post-install-create-user-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pyroscope-dev-minio-make-user-job + namespace: "default" + labels: + app: minio-make-user-job + chart: minio-4.1.0 + release: pyroscope-dev + heritage: Helm + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + app: minio-job + release: pyroscope-dev + spec: + restartPolicy: OnFailure + volumes: + - name: minio-configuration + projected: + sources: + - configMap: + name: pyroscope-dev-minio + - secret: + name: pyroscope-dev-minio + + serviceAccountName: minio-sa + containers: + - name: minio-mc + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "/config/add-user"] + env: + - name: MINIO_ENDPOINT + value: pyroscope-dev-minio + - name: MINIO_PORT + value: "9000" + volumeMounts: + - name: minio-configuration + mountPath: /config + resources: + requests: + memory: 128Mi diff --git a/operations/pyroscope/helm/pyroscope/rendered/micro-services.yaml b/operations/pyroscope/helm/pyroscope/rendered/micro-services.yaml index 73add4902c..2b18d69403 100644 --- a/operations/pyroscope/helm/pyroscope/rendered/micro-services.yaml +++ b/operations/pyroscope/helm/pyroscope/rendered/micro-services.yaml @@ -2,14 +2,35 @@ # Source: pyroscope/templates/deployments-statefulsets.yaml apiVersion: policy/v1 kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget metadata: name: pyroscope-dev-compactor namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "compactor" spec: @@ -27,10 +48,10 @@ metadata: name: pyroscope-dev-distributor namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "distributor" spec: @@ -48,10 +69,10 @@ metadata: name: pyroscope-dev-ingester namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "ingester" spec: @@ -69,10 +90,10 @@ metadata: name: pyroscope-dev-querier namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "querier" spec: @@ -90,10 +111,10 @@ metadata: name: pyroscope-dev-query-frontend namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-frontend" spec: @@ -111,10 +132,10 @@ metadata: name: pyroscope-dev-query-scheduler namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-scheduler" spec: @@ -132,10 +153,10 @@ metadata: name: pyroscope-dev-store-gateway namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "store-gateway" spec: @@ -146,17 +167,42 @@ spec: app.kubernetes.io/instance: pyroscope-dev app.kubernetes.io/component: "store-gateway" --- -# Source: pyroscope/charts/agent/templates/serviceaccount.yaml +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/charts/alloy/templates/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount +automountServiceAccountToken: true metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac --- # Source: pyroscope/charts/minio/templates/serviceaccount.yaml apiVersion: v1 @@ -172,10 +218,10 @@ metadata: name: pyroscope-dev namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm --- # Source: pyroscope/charts/minio/templates/secrets.yaml @@ -186,7 +232,7 @@ metadata: namespace: "default" labels: app: minio - chart: minio-4.0.12 + chart: minio-4.1.0 release: pyroscope-dev heritage: Helm type: Opaque @@ -202,7 +248,7 @@ metadata: namespace: "default" labels: app: minio - chart: minio-4.0.12 + chart: minio-4.1.0 release: pyroscope-dev heritage: Helm data: @@ -512,20 +558,20 @@ data: scheme=http connectToMinio $scheme --- -# Source: pyroscope/templates/configmap-agent.yaml +# Source: pyroscope/templates/configmap-alloy.yaml apiVersion: v1 kind: ConfigMap metadata: - name: grafana-agent-config-pyroscope + name: alloy-config-pyroscope namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm data: - config.river: | + config.alloy: | logging { level = "info" format = "logfmt" @@ -582,6 +628,39 @@ data: source_labels = ["__meta_kubernetes_pod_container_name"] target_label = "container" } + + // Set service_name by choosing the first non-empty value from the following ordered list: + // - pod.annotation[profiles.grafana.com/service_name] + // - pod.annotation[resource.opentelemetry.io/service.name] + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_annotation_profiles_grafana_com_service_name", + "__meta_kubernetes_pod_annotation_resource_opentelemetry_io_service_name", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "service_name" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_repository"] + target_label = "service_repository" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_git_ref"] + target_label = "service_git_ref" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_root_path"] + target_label = "service_root_path" + } } discovery.relabel "kubernetes_pods_memory_default_name" { @@ -1359,10 +1438,10 @@ metadata: name: pyroscope-dev-overrides-config namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm data: overrides.yaml: | @@ -1376,10 +1455,10 @@ metadata: name: pyroscope-dev-config namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm data: config.yaml: | @@ -1392,171 +1471,162 @@ data: insecure: true secret_access_key: supersecret --- -# Source: pyroscope/charts/agent/templates/rbac.yaml +# Source: pyroscope/charts/alloy/templates/rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac rules: - # Rules which allow discovery.kubernetes to function. - apiGroups: - - "" - - "discovery.k8s.io" - - "networking.k8s.io" + - "" + - discovery.k8s.io + - networking.k8s.io resources: - - endpoints - - endpointslices - - ingresses - - nodes - - nodes/proxy - - nodes/metrics - - pods - - services + - endpoints + - endpointslices + - ingresses + - pods + - services verbs: - - get - - list - - watch - # Rules which allow loki.source.kubernetes and loki.source.podlogs to work. + - get + - list + - watch - apiGroups: - - "" + - "" resources: - - pods - - pods/log - - namespaces + - pods + - pods/log + - namespaces verbs: - - get - - list - - watch + - get + - list + - watch - apiGroups: - - "monitoring.grafana.com" + - monitoring.grafana.com resources: - - podlogs + - podlogs verbs: - - get - - list - - watch - # Rules which allow mimir.rules.kubernetes to work. - - apiGroups: ["monitoring.coreos.com"] + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com resources: - - prometheusrules + - prometheusrules verbs: - - get - - list - - watch - - nonResourceURLs: - - /metrics + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - alertmanagerconfigs verbs: - - get - # Rules for prometheus.kubernetes.* - - apiGroups: ["monitoring.coreos.com"] + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com resources: - - podmonitors - - servicemonitors - - probes + - podmonitors + - servicemonitors + - probes + - scrapeconfigs verbs: - - get - - list - - watch - # Rules which allow eventhandler to work. + - get + - list + - watch - apiGroups: - - "" + - "" resources: - - events + - events verbs: - - get - - list - - watch ---- -# Source: pyroscope/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: default-pyroscope-dev - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -rules: -- apiGroups: - - "" - resources: - - pods - verbs: - - list - - watch -- apiGroups: - - "" - resources: - - nodes - verbs: - - get ---- -# Source: pyroscope/charts/agent/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: pyroscope-dev-agent - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: pyroscope-dev-agent -subjects: - - kind: ServiceAccount - name: pyroscope-dev-agent - namespace: default + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - apps + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + - nodes/proxy + - nodes/metrics + verbs: + - get + - list + - watch + - nonResourceURLs: + - /metrics + verbs: + - get --- -# Source: pyroscope/templates/rbac.yaml +# Source: pyroscope/charts/alloy/templates/rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: default-pyroscope-dev - namespace: default + name: pyroscope-dev-alloy labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: default-pyroscope-dev + name: pyroscope-dev-alloy subjects: - kind: ServiceAccount - name: pyroscope-dev + name: pyroscope-dev-alloy namespace: default --- -# Source: pyroscope/charts/agent/templates/cluster_service.yaml +# Source: pyroscope/charts/alloy/templates/cluster_service.yaml apiVersion: v1 kind: Service metadata: - name: pyroscope-dev-agent-cluster + name: pyroscope-dev-alloy-cluster + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking spec: type: ClusterIP clusterIP: 'None' + publishNotReadyAddresses: true selector: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev ports: # Do not include the -metrics suffix in the port name, otherwise metrics @@ -1566,30 +1636,33 @@ spec: # This service should only be used for clustering, and not metric # collection. - name: http - port: 80 - targetPort: 80 + port: 12345 + targetPort: 12345 protocol: "TCP" --- -# Source: pyroscope/charts/agent/templates/service.yaml +# Source: pyroscope/charts/alloy/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking spec: type: ClusterIP selector: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev ports: - name: http-metrics - port: 80 - targetPort: 80 + port: 12345 + targetPort: 12345 protocol: "TCP" --- # Source: pyroscope/charts/minio/templates/console-service.yaml @@ -1600,7 +1673,7 @@ metadata: namespace: "default" labels: app: minio - chart: minio-4.0.12 + chart: minio-4.1.0 release: pyroscope-dev heritage: Helm spec: @@ -1622,7 +1695,7 @@ metadata: namespace: "default" labels: app: minio - chart: minio-4.0.12 + chart: minio-4.1.0 release: pyroscope-dev heritage: Helm monitoring: "true" @@ -1645,7 +1718,7 @@ metadata: namespace: "default" labels: app: minio - chart: minio-4.0.12 + chart: minio-4.1.0 release: "pyroscope-dev" heritage: "Helm" spec: @@ -1667,10 +1740,10 @@ metadata: name: pyroscope-dev-memberlist namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP @@ -1690,14 +1763,65 @@ spec: # Source: pyroscope/templates/services.yaml apiVersion: v1 kind: Service +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-ad-hoc-profiles-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service metadata: name: pyroscope-dev-compactor namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "compactor" spec: @@ -1719,10 +1843,10 @@ metadata: name: pyroscope-dev-compactor-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "compactor" spec: @@ -1745,10 +1869,10 @@ metadata: name: pyroscope-dev-distributor namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "distributor" spec: @@ -1770,10 +1894,10 @@ metadata: name: pyroscope-dev-distributor-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "distributor" spec: @@ -1796,10 +1920,10 @@ metadata: name: pyroscope-dev-ingester namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "ingester" spec: @@ -1821,10 +1945,10 @@ metadata: name: pyroscope-dev-ingester-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "ingester" spec: @@ -1847,10 +1971,10 @@ metadata: name: pyroscope-dev-querier namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "querier" spec: @@ -1872,10 +1996,10 @@ metadata: name: pyroscope-dev-querier-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "querier" spec: @@ -1898,10 +2022,10 @@ metadata: name: pyroscope-dev-query-frontend namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-frontend" spec: @@ -1923,10 +2047,10 @@ metadata: name: pyroscope-dev-query-frontend-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-frontend" spec: @@ -1949,10 +2073,10 @@ metadata: name: pyroscope-dev-query-scheduler namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-scheduler" spec: @@ -1974,10 +2098,10 @@ metadata: name: pyroscope-dev-query-scheduler-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-scheduler" spec: @@ -2000,10 +2124,10 @@ metadata: name: pyroscope-dev-store-gateway namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "store-gateway" spec: @@ -2025,10 +2149,10 @@ metadata: name: pyroscope-dev-store-gateway-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "store-gateway" spec: @@ -2044,6 +2168,161 @@ spec: app.kubernetes.io/instance: pyroscope-dev app.kubernetes.io/component: "store-gateway" --- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-tenant-settings-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-ad-hoc-profiles + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "ad-hoc-profiles" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "ad-hoc-profiles" + name: "ad-hoc-profiles" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "ad-hoc-profiles" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=ad-hoc-profiles" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 4Gi + requests: + cpu: 0.1 + memory: 16Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- # Source: pyroscope/templates/deployments-statefulsets.yaml apiVersion: apps/v1 kind: Deployment @@ -2051,10 +2330,10 @@ metadata: name: pyroscope-dev-distributor namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "distributor" spec: @@ -2067,7 +2346,9 @@ spec: template: metadata: annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -2090,18 +2371,26 @@ spec: - name: "distributor" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=distributor" - "-self-profiling.disable-push=true" - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 @@ -2145,10 +2434,10 @@ metadata: name: pyroscope-dev-querier namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "querier" spec: @@ -2161,7 +2450,9 @@ spec: template: metadata: annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -2184,18 +2475,27 @@ spec: - name: "querier" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=querier" - "-self-profiling.disable-push=true" - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" - "-store-gateway.sharding-ring.replication-factor=3" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 @@ -2239,10 +2539,10 @@ metadata: name: pyroscope-dev-query-frontend namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-frontend" spec: @@ -2255,7 +2555,9 @@ spec: template: metadata: annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -2278,18 +2580,26 @@ spec: - name: "query-frontend" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=query-frontend" - "-self-profiling.disable-push=true" - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 @@ -2333,10 +2643,10 @@ metadata: name: pyroscope-dev-query-scheduler namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "query-scheduler" spec: @@ -2349,7 +2659,9 @@ spec: template: metadata: annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -2372,18 +2684,26 @@ spec: - name: "query-scheduler" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=query-scheduler" - "-self-profiling.disable-push=true" - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 @@ -2420,87 +2740,199 @@ spec: - name: data emptyDir: {} --- -# Source: pyroscope/charts/agent/templates/controllers/statefulset.yaml +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pyroscope-dev-tenant-settings + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "tenant-settings" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" + template: + metadata: + annotations: + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "tenant-settings" + name: "tenant-settings" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "tenant-settings" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=tenant-settings" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + resources: + limits: + memory: 4Gi + requests: + cpu: 0.1 + memory: 16Mi + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} +--- +# Source: pyroscope/charts/alloy/templates/controllers/statefulset.yaml apiVersion: apps/v1 kind: StatefulSet metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy spec: replicas: 1 podManagementPolicy: Parallel minReadySeconds: 10 - serviceName: pyroscope-dev-agent + serviceName: pyroscope-dev-alloy selector: matchLabels: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev template: metadata: annotations: + kubectl.kubernetes.io/default-container: alloy profiles.grafana.com/cpu.port_name: http-metrics profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http-metrics profiles.grafana.com/goroutine.scrape: "true" profiles.grafana.com/memory.port_name: http-metrics profiles.grafana.com/memory.scrape: "true" + profiles.grafana.com/service_git_ref: v1.8.1 + profiles.grafana.com/service_repository: https://github.com/grafana/alloy labels: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev spec: - serviceAccountName: pyroscope-dev-agent + serviceAccountName: pyroscope-dev-alloy containers: - - name: grafana-agent - image: docker.io/grafana/agent:v0.36.2 + - name: alloy + image: docker.io/grafana/alloy:v1.12.2 imagePullPolicy: IfNotPresent args: - run - - /etc/agent/config.river - - --storage.path=/tmp/agent - - --server.http.listen-addr=0.0.0.0:80 + - /etc/alloy/config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + - --server.http.ui-path-prefix=/ - --cluster.enabled=true - - --cluster.join-addresses=pyroscope-dev-agent-cluster + - --cluster.join-addresses=pyroscope-dev-alloy-cluster + - --stability.level=public-preview env: - - name: AGENT_MODE - value: flow + - name: ALLOY_DEPLOY_MODE + value: "helm" - name: HOSTNAME valueFrom: fieldRef: fieldPath: spec.nodeName ports: - - containerPort: 80 + - containerPort: 12345 name: http-metrics readinessProbe: httpGet: path: /-/ready - port: 80 + port: 12345 + scheme: HTTP initialDelaySeconds: 10 timeoutSeconds: 1 volumeMounts: - name: config - mountPath: /etc/agent + mountPath: /etc/alloy - name: config-reloader - image: docker.io/jimmidyson/configmap-reload:v0.8.0 + image: quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0 args: - - --volume-dir=/etc/agent - - --webhook-url=http://localhost:80/-/reload + - --watched-dir=/etc/alloy + - --reload-url=http://localhost:12345/-/reload volumeMounts: - name: config - mountPath: /etc/agent + mountPath: /etc/alloy resources: requests: - cpu: 1m - memory: 5Mi + cpu: 10m + memory: 50Mi dnsPolicy: ClusterFirst volumes: - name: config configMap: - name: grafana-agent-config-pyroscope + name: alloy-config-pyroscope --- # Source: pyroscope/charts/minio/templates/statefulset.yaml apiVersion: apps/v1 @@ -2510,7 +2942,7 @@ metadata: namespace: "default" labels: app: minio - chart: minio-4.0.12 + chart: minio-4.1.0 release: pyroscope-dev heritage: Helm spec: @@ -2530,10 +2962,8 @@ spec: app: minio release: pyroscope-dev annotations: - checksum/secrets: 2e760de5dbcac8daf468cd56713bca0aac7d7adc4445e2488b352dbb2b529507 - checksum/config: 925d78a7321daaaa06a6dc4ee47dbaf5b8952be192bdbb57f13805ad472ce4e1 - phlare.grafana.com/port: "9000" - phlare.grafana.com/scrape: "true" + checksum/secrets: 1327df257dd66b53a08dc3d9f2584d6c07cd43932cd3c3f68a7ffc636c5a0d92 + checksum/config: 68ad5341411f10a6da13194dfbe5544a594ccedef5dfb12d34529d2be6d0f67f spec: securityContext: runAsUser: 1000 @@ -2544,7 +2974,7 @@ spec: serviceAccountName: minio-sa containers: - name: minio - image: quay.io/minio/minio:RELEASE.2022-08-13T21-54-44Z + image: quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z imagePullPolicy: IfNotPresent command: [ "/bin/sh", @@ -2604,10 +3034,10 @@ metadata: name: pyroscope-dev-compactor namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "compactor" spec: @@ -2622,7 +3052,9 @@ spec: template: metadata: annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -2645,18 +3077,26 @@ spec: - name: "compactor" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=compactor" - "-self-profiling.disable-push=true" - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 @@ -2705,10 +3145,10 @@ metadata: name: pyroscope-dev-ingester namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "ingester" spec: @@ -2723,7 +3163,9 @@ spec: template: metadata: annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -2746,18 +3188,26 @@ spec: - name: "ingester" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=ingester" - "-self-profiling.disable-push=true" - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" - - "-store-gateway.sharding-ring.replication-factor=3" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 @@ -2802,10 +3252,10 @@ metadata: name: pyroscope-dev-store-gateway namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "store-gateway" spec: @@ -2820,7 +3270,9 @@ spec: template: metadata: annotations: - checksum/config: 6372712186025848713485fafd0ca4fc152d68d0f35f46f4769d029f96841616 + checksum/config: 78e5f1ddee5b4eec11ff83ec57e0ebaf27459a30022d096148780261a7be67cf + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -2843,18 +3295,27 @@ spec: - name: "store-gateway" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=store-gateway" - "-self-profiling.disable-push=true" - "-server.http-listen-port=4040" - - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.cluster-label=default-pyroscope-dev-micro-services" - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" - "-store-gateway.sharding-ring.replication-factor=3" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 @@ -2900,7 +3361,7 @@ metadata: namespace: "default" labels: app: minio-make-bucket-job - chart: minio-4.0.12 + chart: minio-4.1.0 release: pyroscope-dev heritage: Helm annotations: @@ -2922,9 +3383,11 @@ spec: name: pyroscope-dev-minio - secret: name: pyroscope-dev-minio + + serviceAccountName: minio-sa containers: - name: minio-mc - image: "quay.io/minio/mc:RELEASE.2022-08-11T00-30-48Z" + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" imagePullPolicy: IfNotPresent command: ["/bin/sh", "/config/initialize"] env: @@ -2947,7 +3410,7 @@ metadata: namespace: "default" labels: app: minio-make-user-job - chart: minio-4.0.12 + chart: minio-4.1.0 release: pyroscope-dev heritage: Helm annotations: @@ -2969,9 +3432,11 @@ spec: name: pyroscope-dev-minio - secret: name: pyroscope-dev-minio + + serviceAccountName: minio-sa containers: - name: minio-mc - image: "quay.io/minio/mc:RELEASE.2022-08-11T00-30-48Z" + image: "quay.io/minio/mc:RELEASE.2022-10-20T23-26-33Z" imagePullPolicy: IfNotPresent command: ["/bin/sh", "/config/add-user"] env: diff --git a/operations/pyroscope/helm/pyroscope/rendered/single-binary-v2.yaml b/operations/pyroscope/helm/pyroscope/rendered/single-binary-v2.yaml new file mode 100644 index 0000000000..b2ed7a7b0c --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/rendered/single-binary-v2.yaml @@ -0,0 +1,1501 @@ +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: pyroscope-dev + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "all" +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "all" +--- +# Source: pyroscope/charts/alloy/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: true +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +--- +# Source: pyroscope/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pyroscope-dev + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +--- +# Source: pyroscope/templates/configmap-alloy.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: alloy-config-pyroscope + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.alloy: | + logging { + level = "info" + format = "logfmt" + } + + discovery.kubernetes "pyroscope_kubernetes" { + role = "pod" + } + + // The default scrape config allows to define annotations based scraping. + // + // For example the following annotations: + // + // ``` + // profiles.grafana.com/memory.scrape: "true" + // profiles.grafana.com/memory.port: "8080" + // profiles.grafana.com/cpu.scrape: "true" + // profiles.grafana.com/cpu.port: "8080" + // profiles.grafana.com/goroutine.scrape: "true" + // profiles.grafana.com/goroutine.port: "8080" + // ``` + // + // will scrape the `memory`, `cpu` and `goroutine` profiles from the `8080` port of the pod. + // + // For more information see https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/helm/#optional-scrape-your-own-workloads-profiles + discovery.relabel "kubernetes_pods" { + targets = concat(discovery.kubernetes.pyroscope_kubernetes.targets) + + rule { + action = "drop" + source_labels = ["__meta_kubernetes_pod_phase"] + regex = "Pending|Succeeded|Failed|Completed" + } + + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_label_(.+)" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // Set service_name by choosing the first non-empty value from the following ordered list: + // - pod.annotation[profiles.grafana.com/service_name] + // - pod.annotation[resource.opentelemetry.io/service.name] + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_annotation_profiles_grafana_com_service_name", + "__meta_kubernetes_pod_annotation_resource_opentelemetry_io_service_name", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "service_name" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_repository"] + target_label = "service_repository" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_git_ref"] + target_label = "service_git_ref" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_root_path"] + target_label = "service_root_path" + } + } + + discovery.relabel "kubernetes_pods_memory_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_memory_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_memory_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_memory" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_memory_default_name.output, discovery.relabel.kubernetes_pods_memory_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = true + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_cpu_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_cpu_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_cpu_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_cpu" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_cpu_default_name.output, discovery.relabel.kubernetes_pods_cpu_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = true + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_goroutine_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_goroutine_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_goroutine_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_goroutine" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_goroutine_default_name.output, discovery.relabel.kubernetes_pods_goroutine_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = true + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_block_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_block_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_block_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_block_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_block" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_block_default_name.output, discovery.relabel.kubernetes_pods_block_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = true + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_mutex_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_mutex_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_mutex_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_mutex" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_mutex_default_name.output, discovery.relabel.kubernetes_pods_mutex_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = true + } + + profile.fgprof { + enabled = false + } + } + } + + discovery.relabel "kubernetes_pods_fgprof_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_fgprof_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_fgprof_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_fgprof" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_fgprof_default_name.output, discovery.relabel.kubernetes_pods_fgprof_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + profile.memory { + enabled = false + } + + profile.process_cpu { + enabled = false + } + + profile.goroutine { + enabled = false + } + + profile.block { + enabled = false + } + + profile.mutex { + enabled = false + } + + profile.fgprof { + enabled = true + } + } + } + + pyroscope.write "pyroscope_write" { + endpoint { + url = "http://pyroscope-dev.default.svc.cluster.local.:4040" + } + } +--- +# Source: pyroscope/templates/configmap-overrides.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-overrides-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + overrides.yaml: | + overrides: + {} +--- +# Source: pyroscope/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pyroscope-dev-config + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +data: + config.yaml: | + {} +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +rules: + - apiGroups: + - "" + - discovery.k8s.io + - networking.k8s.io + resources: + - endpoints + - endpointslices + - ingresses + - pods + - services + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - pods + - pods/log + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.grafana.com + resources: + - podlogs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - prometheusrules + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - alertmanagerconfigs + verbs: + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - podmonitors + - servicemonitors + - probes + - scrapeconfigs + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - apps + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + - nodes/proxy + - nodes/metrics + verbs: + - get + - list + - watch + - nonResourceURLs: + - /metrics + verbs: + - get +--- +# Source: pyroscope/charts/alloy/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pyroscope-dev-alloy + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pyroscope-dev-alloy +subjects: + - kind: ServiceAccount + name: pyroscope-dev-alloy + namespace: default +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +rules: +- apiGroups: + - "" + - discovery.k8s.io + resources: + - endpointslices + - endpoints + - services + - pods + verbs: + - get + - watch + - list +--- +# Source: pyroscope/templates/rbac-discovery.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pyroscope-dev-discovery + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pyroscope-dev-discovery +subjects: +- kind: ServiceAccount + name: pyroscope-dev + namespace: default +--- +# Source: pyroscope/charts/alloy/templates/cluster_service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy-cluster + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + clusterIP: 'None' + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + # Do not include the -metrics suffix in the port name, otherwise metrics + # can be double-collected with the non-headless Service if it's also + # enabled. + # + # This service should only be used for clustering, and not metric + # collection. + - name: http + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/charts/alloy/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + ports: + - name: http-metrics + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: pyroscope/templates/memberlist-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-memberlist + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + clusterIP: None + ports: + - name: memberlist + port: 7946 + protocol: TCP + targetPort: 7946 + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + # TODO: Ensure only services that offer memberlist register + # pyroscope.grafana.com/memberlist: "true" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "all" +spec: + type: ClusterIP + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + - port: 9099 + targetPort: raft + protocol: TCP + name: raft + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "all" +--- +# Source: pyroscope/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + name: pyroscope-dev-headless + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "all" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: 4040 + targetPort: http2 + protocol: TCP + name: http2 + - port: 9095 + targetPort: grpc + protocol: TCP + name: grpc + - port: 9099 + targetPort: raft + protocol: TCP + name: raft + publishNotReadyAddresses: true + selector: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "all" +--- +# Source: pyroscope/charts/alloy/templates/controllers/statefulset.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev-alloy + namespace: default + labels: + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "v1.12.2" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy +spec: + replicas: 1 + podManagementPolicy: Parallel + minReadySeconds: 10 + serviceName: pyroscope-dev-alloy + selector: + matchLabels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: alloy + profiles.grafana.com/cpu.port_name: http-metrics + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http-metrics + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http-metrics + profiles.grafana.com/memory.scrape: "true" + profiles.grafana.com/service_git_ref: v1.8.1 + profiles.grafana.com/service_repository: https://github.com/grafana/alloy + labels: + app.kubernetes.io/name: alloy + app.kubernetes.io/instance: pyroscope-dev + spec: + serviceAccountName: pyroscope-dev-alloy + containers: + - name: alloy + image: docker.io/grafana/alloy:v1.12.2 + imagePullPolicy: IfNotPresent + args: + - run + - /etc/alloy/config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + - --server.http.ui-path-prefix=/ + - --cluster.enabled=true + - --cluster.join-addresses=pyroscope-dev-alloy-cluster + - --stability.level=public-preview + env: + - name: ALLOY_DEPLOY_MODE + value: "helm" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - containerPort: 12345 + name: http-metrics + readinessProbe: + httpGet: + path: /-/ready + port: 12345 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 1 + volumeMounts: + - name: config + mountPath: /etc/alloy + - name: config-reloader + image: quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0 + args: + - --watched-dir=/etc/alloy + - --reload-url=http://localhost:12345/-/reload + volumeMounts: + - name: config + mountPath: /etc/alloy + resources: + requests: + cpu: 10m + memory: 50Mi + dnsPolicy: ClusterFirst + volumes: + - name: config + configMap: + name: alloy-config-pyroscope +--- +# Source: pyroscope/templates/deployments-statefulsets.yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: pyroscope-dev + namespace: default + labels: + helm.sh/chart: pyroscope-2.2.0 + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/version: "2.2.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: "all" +spec: + serviceName: pyroscope-dev-headless + podManagementPolicy: Parallel + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "all" + template: + metadata: + annotations: + checksum/config: 3aef793cd0d75d5d3e04e7a3cd572a8ef043518118df43b74beee3f27e623929 + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" + profiles.grafana.com/cpu.port_name: http2 + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/goroutine.port_name: http2 + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/memory.port_name: http2 + profiles.grafana.com/memory.scrape: "true" + labels: + app.kubernetes.io/name: pyroscope + app.kubernetes.io/instance: pyroscope-dev + app.kubernetes.io/component: "all" + name: "pyroscope" + spec: + serviceAccountName: pyroscope-dev + securityContext: + fsGroup: 10001 + runAsNonRoot: true + runAsUser: 10001 + dnsPolicy: ClusterFirst + containers: + - name: "pyroscope" + securityContext: + {} + image: "grafana/pyroscope:2.2.0" + imagePullPolicy: IfNotPresent + args: + - "-target=all" + - "-self-profiling.disable-push=true" + - "-server.http-listen-port=4040" + - "-memberlist.cluster-label=default-pyroscope-dev" + - "-memberlist.join=dns+pyroscope-dev-memberlist.default.svc.cluster.local.:7946" + - "-config.file=/etc/pyroscope/config.yaml" + - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" + - "-log.level=debug" + - "-query-backend.address=dns:///_grpc._tcp.pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.address=kubernetes:///pyroscope-dev-headless.$(NAMESPACE_FQDN):9095" + - "-metastore.data-dir=./data-metastore/data" + - "-metastore.raft.dir=./data-metastore/raft" + - "-metastore.raft.snapshots-dir=./data-metastore/raft" + - "-metastore.raft.bind-address=:9099" + - "-metastore.raft.server-id=$(POD_NAME).$(PYROSCOPE_METASTORE_SERVICE)" + - "-metastore.raft.advertise-address=$(POD_NAME).$(PYROSCOPE_METASTORE_SERVICE)" + - "-metastore.raft.bootstrap-peers=dnssrvnoa+_raft._tcp.$(PYROSCOPE_METASTORE_SERVICE)" + - "-architecture.storage=v2" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." + - name: PYROSCOPE_METASTORE_SERVICE + value: "pyroscope-dev-headless.default.svc.cluster.local.:9099" + ports: + - name: http2 + containerPort: 4040 + protocol: TCP + - name: memberlist + containerPort: 7946 + protocol: TCP + - name: grpc + containerPort: 9095 + protocol: TCP + - name: raft + containerPort: 9099 + protocol: TCP + readinessProbe: + httpGet: + path: /ready + port: http2 + scheme: HTTP + volumeMounts: + - name: config + mountPath: /etc/pyroscope/config.yaml + subPath: config.yaml + - name: overrides-config + mountPath: /etc/pyroscope/overrides/ + - name: data + mountPath: /data + - name: data + mountPath: /data-metastore + subPath: .metastore + resources: + {} + volumes: + - name: config + configMap: + name: pyroscope-dev-config + - name: overrides-config + configMap: + name: pyroscope-dev-overrides-config + - name: data + emptyDir: {} diff --git a/operations/pyroscope/helm/pyroscope/rendered/single-binary.yaml b/operations/pyroscope/helm/pyroscope/rendered/single-binary.yaml index ce33af8612..707c639b1c 100644 --- a/operations/pyroscope/helm/pyroscope/rendered/single-binary.yaml +++ b/operations/pyroscope/helm/pyroscope/rendered/single-binary.yaml @@ -6,10 +6,10 @@ metadata: name: pyroscope-dev namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "all" spec: @@ -20,17 +20,21 @@ spec: app.kubernetes.io/instance: pyroscope-dev app.kubernetes.io/component: "all" --- -# Source: pyroscope/charts/agent/templates/serviceaccount.yaml +# Source: pyroscope/charts/alloy/templates/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount +automountServiceAccountToken: true metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac --- # Source: pyroscope/templates/serviceaccount.yaml apiVersion: v1 @@ -39,26 +43,26 @@ metadata: name: pyroscope-dev namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm --- -# Source: pyroscope/templates/configmap-agent.yaml +# Source: pyroscope/templates/configmap-alloy.yaml apiVersion: v1 kind: ConfigMap metadata: - name: grafana-agent-config-pyroscope + name: alloy-config-pyroscope namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm data: - config.river: | + config.alloy: | logging { level = "info" format = "logfmt" @@ -115,6 +119,39 @@ data: source_labels = ["__meta_kubernetes_pod_container_name"] target_label = "container" } + + // Set service_name by choosing the first non-empty value from the following ordered list: + // - pod.annotation[profiles.grafana.com/service_name] + // - pod.annotation[resource.opentelemetry.io/service.name] + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_annotation_profiles_grafana_com_service_name", + "__meta_kubernetes_pod_annotation_resource_opentelemetry_io_service_name", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "service_name" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_repository"] + target_label = "service_repository" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_git_ref"] + target_label = "service_git_ref" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_root_path"] + target_label = "service_root_path" + } } discovery.relabel "kubernetes_pods_memory_default_name" { @@ -892,10 +929,10 @@ metadata: name: pyroscope-dev-overrides-config namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm data: overrides.yaml: | @@ -909,180 +946,171 @@ metadata: name: pyroscope-dev-config namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm data: config.yaml: | {} --- -# Source: pyroscope/charts/agent/templates/rbac.yaml +# Source: pyroscope/charts/alloy/templates/rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac rules: - # Rules which allow discovery.kubernetes to function. - apiGroups: - - "" - - "discovery.k8s.io" - - "networking.k8s.io" + - "" + - discovery.k8s.io + - networking.k8s.io resources: - - endpoints - - endpointslices - - ingresses - - nodes - - nodes/proxy - - nodes/metrics - - pods - - services + - endpoints + - endpointslices + - ingresses + - pods + - services verbs: - - get - - list - - watch - # Rules which allow loki.source.kubernetes and loki.source.podlogs to work. + - get + - list + - watch - apiGroups: - - "" + - "" resources: - - pods - - pods/log - - namespaces + - pods + - pods/log + - namespaces verbs: - - get - - list - - watch + - get + - list + - watch - apiGroups: - - "monitoring.grafana.com" + - monitoring.grafana.com resources: - - podlogs + - podlogs verbs: - - get - - list - - watch - # Rules which allow mimir.rules.kubernetes to work. - - apiGroups: ["monitoring.coreos.com"] + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com resources: - - prometheusrules + - prometheusrules verbs: - - get - - list - - watch - - nonResourceURLs: - - /metrics + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com + resources: + - alertmanagerconfigs verbs: - - get - # Rules for prometheus.kubernetes.* - - apiGroups: ["monitoring.coreos.com"] + - get + - list + - watch + - apiGroups: + - monitoring.coreos.com resources: - - podmonitors - - servicemonitors - - probes + - podmonitors + - servicemonitors + - probes + - scrapeconfigs verbs: - - get - - list - - watch - # Rules which allow eventhandler to work. + - get + - list + - watch - apiGroups: - - "" + - "" resources: - - events + - events verbs: - - get - - list - - watch ---- -# Source: pyroscope/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: default-pyroscope-dev - namespace: default - labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" - app.kubernetes.io/managed-by: Helm -rules: -- apiGroups: - - "" - resources: - - pods - verbs: - - list - - watch -- apiGroups: - - "" - resources: - - nodes - verbs: - - get ---- -# Source: pyroscope/charts/agent/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: pyroscope-dev-agent - labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent - app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: pyroscope-dev-agent -subjects: - - kind: ServiceAccount - name: pyroscope-dev-agent - namespace: default + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - apps + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + - nodes/proxy + - nodes/metrics + verbs: + - get + - list + - watch + - nonResourceURLs: + - /metrics + verbs: + - get --- -# Source: pyroscope/templates/rbac.yaml +# Source: pyroscope/charts/alloy/templates/rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: default-pyroscope-dev - namespace: default + name: pyroscope-dev-alloy labels: - helm.sh/chart: pyroscope-1.6.0 - app.kubernetes.io/name: pyroscope + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: default-pyroscope-dev + name: pyroscope-dev-alloy subjects: - kind: ServiceAccount - name: pyroscope-dev + name: pyroscope-dev-alloy namespace: default --- -# Source: pyroscope/charts/agent/templates/cluster_service.yaml +# Source: pyroscope/charts/alloy/templates/cluster_service.yaml apiVersion: v1 kind: Service metadata: - name: pyroscope-dev-agent-cluster + name: pyroscope-dev-alloy-cluster + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking spec: type: ClusterIP clusterIP: 'None' + publishNotReadyAddresses: true selector: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev ports: # Do not include the -metrics suffix in the port name, otherwise metrics @@ -1092,30 +1120,33 @@ spec: # This service should only be used for clustering, and not metric # collection. - name: http - port: 80 - targetPort: 80 + port: 12345 + targetPort: 12345 protocol: "TCP" --- -# Source: pyroscope/charts/agent/templates/service.yaml +# Source: pyroscope/charts/alloy/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking spec: type: ClusterIP selector: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev ports: - name: http-metrics - port: 80 - targetPort: 80 + port: 12345 + targetPort: 12345 protocol: "TCP" --- # Source: pyroscope/templates/memberlist-service.yaml @@ -1125,10 +1156,10 @@ metadata: name: pyroscope-dev-memberlist namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP @@ -1152,10 +1183,10 @@ metadata: name: pyroscope-dev namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "all" spec: @@ -1177,10 +1208,10 @@ metadata: name: pyroscope-dev-headless namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "all" spec: @@ -1196,87 +1227,95 @@ spec: app.kubernetes.io/instance: pyroscope-dev app.kubernetes.io/component: "all" --- -# Source: pyroscope/charts/agent/templates/controllers/statefulset.yaml +# Source: pyroscope/charts/alloy/templates/controllers/statefulset.yaml apiVersion: apps/v1 kind: StatefulSet metadata: - name: pyroscope-dev-agent + name: pyroscope-dev-alloy + namespace: default labels: - helm.sh/chart: agent-0.25.0 - app.kubernetes.io/name: agent + helm.sh/chart: alloy-1.5.2 + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "v0.36.2" + app.kubernetes.io/version: "v1.12.2" app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy spec: replicas: 1 podManagementPolicy: Parallel minReadySeconds: 10 - serviceName: pyroscope-dev-agent + serviceName: pyroscope-dev-alloy selector: matchLabels: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev template: metadata: annotations: + kubectl.kubernetes.io/default-container: alloy profiles.grafana.com/cpu.port_name: http-metrics profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http-metrics profiles.grafana.com/goroutine.scrape: "true" profiles.grafana.com/memory.port_name: http-metrics profiles.grafana.com/memory.scrape: "true" + profiles.grafana.com/service_git_ref: v1.8.1 + profiles.grafana.com/service_repository: https://github.com/grafana/alloy labels: - app.kubernetes.io/name: agent + app.kubernetes.io/name: alloy app.kubernetes.io/instance: pyroscope-dev spec: - serviceAccountName: pyroscope-dev-agent + serviceAccountName: pyroscope-dev-alloy containers: - - name: grafana-agent - image: docker.io/grafana/agent:v0.36.2 + - name: alloy + image: docker.io/grafana/alloy:v1.12.2 imagePullPolicy: IfNotPresent args: - run - - /etc/agent/config.river - - --storage.path=/tmp/agent - - --server.http.listen-addr=0.0.0.0:80 + - /etc/alloy/config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + - --server.http.ui-path-prefix=/ - --cluster.enabled=true - - --cluster.join-addresses=pyroscope-dev-agent-cluster + - --cluster.join-addresses=pyroscope-dev-alloy-cluster + - --stability.level=public-preview env: - - name: AGENT_MODE - value: flow + - name: ALLOY_DEPLOY_MODE + value: "helm" - name: HOSTNAME valueFrom: fieldRef: fieldPath: spec.nodeName ports: - - containerPort: 80 + - containerPort: 12345 name: http-metrics readinessProbe: httpGet: path: /-/ready - port: 80 + port: 12345 + scheme: HTTP initialDelaySeconds: 10 timeoutSeconds: 1 volumeMounts: - name: config - mountPath: /etc/agent + mountPath: /etc/alloy - name: config-reloader - image: docker.io/jimmidyson/configmap-reload:v0.8.0 + image: quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0 args: - - --volume-dir=/etc/agent - - --webhook-url=http://localhost:80/-/reload + - --watched-dir=/etc/alloy + - --reload-url=http://localhost:12345/-/reload volumeMounts: - name: config - mountPath: /etc/agent + mountPath: /etc/alloy resources: requests: - cpu: 1m - memory: 5Mi + cpu: 10m + memory: 50Mi dnsPolicy: ClusterFirst volumes: - name: config configMap: - name: grafana-agent-config-pyroscope + name: alloy-config-pyroscope --- # Source: pyroscope/templates/deployments-statefulsets.yaml apiVersion: apps/v1 @@ -1285,10 +1324,10 @@ metadata: name: pyroscope-dev namespace: default labels: - helm.sh/chart: pyroscope-1.6.0 + helm.sh/chart: pyroscope-2.2.0 app.kubernetes.io/name: pyroscope app.kubernetes.io/instance: pyroscope-dev - app.kubernetes.io/version: "1.6.0" + app.kubernetes.io/version: "2.2.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/component: "all" spec: @@ -1303,7 +1342,9 @@ spec: template: metadata: annotations: - checksum/config: 87cf168fac22b0904de880d498d2441d12f9dc06d27c8077b0f030df71bcbbc4 + checksum/config: 3aef793cd0d75d5d3e04e7a3cd572a8ef043518118df43b74beee3f27e623929 + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + profiles.grafana.com/service_git_ref: "v2.2.0" profiles.grafana.com/cpu.port_name: http2 profiles.grafana.com/cpu.scrape: "true" profiles.grafana.com/goroutine.port_name: http2 @@ -1326,7 +1367,7 @@ spec: - name: "pyroscope" securityContext: {} - image: "grafana/pyroscope:1.6.0" + image: "grafana/pyroscope:2.2.0" imagePullPolicy: IfNotPresent args: - "-target=all" @@ -1337,6 +1378,15 @@ spec: - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" - "-log.level=debug" + - "-architecture.storage=v1" + - "-write-path=ingester" + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "default.svc.cluster.local." ports: - name: http2 containerPort: 4040 diff --git a/operations/pyroscope/helm/pyroscope/templates/NOTES.txt b/operations/pyroscope/helm/pyroscope/templates/NOTES.txt index 27ec7b84ba..6438778b11 100644 --- a/operations/pyroscope/helm/pyroscope/templates/NOTES.txt +++ b/operations/pyroscope/helm/pyroscope/templates/NOTES.txt @@ -1,3 +1,4 @@ + Thanks for deploying Grafana Pyroscope. # Pyroscope UI & Grafana @@ -5,12 +6,7 @@ Thanks for deploying Grafana Pyroscope. Pyroscope database comes with a built-in UI, to access it from your localhost you can use: ``` -{{- if hasKey .Values.pyroscope.components "query-frontend" }} -{{- $port := ((index .Values.pyroscope.components "query-frontend").service).port | default .Values.pyroscope.service.port }} -kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "pyroscope.fullname" . }}-query-frontend {{ $port }}:{{ $port }} -{{- else }} -kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "pyroscope.fullname" . }} {{ .Values.pyroscope.service.port }}:{{ .Values.pyroscope.service.port }} -{{- end }} +{{ include "pyroscope.kubectl_port_forward_read" . }} ``` You can also use Grafana to explore Pyroscope data. @@ -20,18 +16,13 @@ See https://grafana.com/docs/grafana/latest/datasources/grafana-pyroscope/ for m The in-cluster query URL for the data source in Grafana is: ``` -{{- if hasKey .Values.pyroscope.components "query-frontend" }} -{{- $port := ((index .Values.pyroscope.components "query-frontend").service).port | default .Values.pyroscope.service.port }} -http://{{ include "pyroscope.fullname" . }}-query-frontend.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ $port }} -{{- else }} -http://{{ include "pyroscope.fullname" . }}.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ .Values.pyroscope.service.port }} -{{- end }} +{{ include "pyroscope.read_url" . }} ``` # Collecting profiles. -{{ if .Values.agent.enabled }} -The Grafana Agent has been installed to scrape and discover pprof profiles endpoint via pod annotations. +{{ if or .Values.agent.enabled .Values.alloy.enabled }} +The Grafana {{ if .Values.alloy.enabled }}Alloy{{ else }}Agent{{ end }} has been installed to scrape and discover pprof profiles endpoint via pod annotations. As an example, to start collecting memory and cpu profile using the 8080 port, add the following annotations to your workload: @@ -50,3 +41,19 @@ There are various ways to collect profiles from your application depending on yo Follow our guide to setup profiling data collection for your workload: https://grafana.com/docs/pyroscope/latest/configure-client/ + +{{- $storage := .Values.architecture.storage }} +{{- if and $storage.v1 $storage.v2 }} + +# Pyroscope v2 Migration is active + +Write traffic will be written to: +- {{ mul $storage.migration.ingesterWeight 100 }}% v1: ingester +- {{ mul $storage.migration.segmentWriterWeight 100 }}% v2: segment-writer + +Read traffic is served from v2 read path from {{if eq $storage.migration.queryBackendFrom "auto"}}as soon as data was first ingested to v2{{else}}{{$storage.migration.queryBackendFrom}}{{end}}. +{{- end }} + +{{- if and (not $storage.v1) (not $storage.v2) }} +{{- fail "you need to set at least one of .Values.architecture.storage.v1, .Values.architecture.storage.v2 to true" }} +{{- end }} diff --git a/operations/pyroscope/helm/pyroscope/templates/_helpers.tpl b/operations/pyroscope/helm/pyroscope/templates/_helpers.tpl index 5e567bce68..471a50a58a 100644 --- a/operations/pyroscope/helm/pyroscope/templates/_helpers.tpl +++ b/operations/pyroscope/helm/pyroscope/templates/_helpers.tpl @@ -80,18 +80,81 @@ Create a list of components that should be deployed. */}} {{- define "pyroscope.components" -}} {{- $full_name := (include "pyroscope.fullname" .) }} -{{- range $k, $v := .Values.pyroscope.components }} +{{- $components := dict }} +{{- if .Values.architecture.microservices.enabled }} +{{- if .Values.architecture.storage.v1 }} +{{- $components = mustMergeOverwrite (deepCopy $components) (.Values.architecture.microservices.v1 | default dict)}} +{{- end }} +{{- if .Values.architecture.storage.v2 }} +{{- $components = mustMergeOverwrite (deepCopy $components) (.Values.architecture.microservices.v2 | default dict)}} +{{- end }} +{{- end }} +{{- if .Values.architecture.microservices.enabled }} +{{- range $k, $v := (.Values.pyroscope.components | default dict) }} +{{- if hasKey $components $k }} +{{- $_ := set $components $k (mustMergeOverwrite (deepCopy (index $components $k)) $v) }} +{{- end }} +{{- end }} +{{- else }} +{{- $components = mustMergeOverwrite (deepCopy $components) (.Values.pyroscope.components | default dict)}} +{{- end }} +{{- range $k, $v := $components }} {{- $v := set $v "name" (printf "%s-%s" $full_name $k) }} {{$k}}: {{ $v | toJson }} {{- end }} {{/* If no components are defined fall back to single binary statefulset */}} -{{- if eq (len .Values.pyroscope.components) 0 }} +{{- if eq (len $components) 0 }} all: {kind: "StatefulSet", name: "{{$full_name}}"} {{- end }} {{- end }} + +{{/* +Return the URL for sending profiles to Pyroscope. +*/}} +{{- define "pyroscope.write_url" -}} +{{- $components := (fromYaml (include "pyroscope.components" .)) -}} +{{- if .Values.architecture.deployUnifiedServices -}} +http://{{ include "pyroscope.fullname" . }}-write.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }} +{{- else if hasKey $components "distributor" -}} +http://{{ include "pyroscope.fullname" . }}-distributor.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ ($components.distributor.service).port | default .Values.pyroscope.service.port}} +{{- else -}} +http://{{ include "pyroscope.fullname" . }}.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ .Values.pyroscope.service.port }} +{{- end }} +{{- end }} + +{{/* +Return the URL for querying profiles from Pyroscope. +*/}} +{{- define "pyroscope.read_url" -}} +{{- $components := (fromYaml (include "pyroscope.components" .)) -}} +{{- if .Values.architecture.deployUnifiedServices -}} +http://{{ include "pyroscope.fullname" . }}-read.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }} +{{- else if hasKey $components "query-frontend" -}}A +{{- $port := ((index $components "query-frontend").service).port | default .Values.pyroscope.service.port }} +http://{{ include "pyroscope.fullname" . }}-query-frontend.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ $port }} +{{- else -}} +http://{{ include "pyroscope.fullname" . }}.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ .Values.pyroscope.service.port }} +{{- end }} +{{- end }} + +{{/* +Return the kubectl port-forward command for querying profiles from Pyroscope. +*/}} +{{- define "pyroscope.kubectl_port_forward_read" -}} +{{- $components := (fromYaml (include "pyroscope.components" .)) -}} +{{- if .Values.architecture.deployUnifiedServices -}} +kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "pyroscope.fullname" . }}-read {{ .Values.pyroscope.service.port }}:80 +{{- else if hasKey $components "query-frontend" -}} +{{- $port := ((index $components "query-frontend").service).port | default .Values.pyroscope.service.port }} +kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "pyroscope.fullname" . }}-query-frontend {{ $port }}:{{ $port }} +{{- else -}} +kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "pyroscope.fullname" . }} {{ .Values.pyroscope.service.port }}:{{ .Values.pyroscope.service.port }} +{{- end }} +{{- end }} + {{- define "pyroscope.defaultAutoscalingComponents" -}} enabled: false minReplicas: 1 diff --git a/operations/pyroscope/helm/pyroscope/templates/configmap-agent.yaml b/operations/pyroscope/helm/pyroscope/templates/configmap-agent.yaml index 93a09636ac..1a500d3619 100644 --- a/operations/pyroscope/helm/pyroscope/templates/configmap-agent.yaml +++ b/operations/pyroscope/helm/pyroscope/templates/configmap-agent.yaml @@ -1,3 +1,4 @@ +{{- /* Note this config file is depreacted, use the alloy one instead */}} {{- if and (.Values.agent.enabled) (not .Values.agent.agent.configMap.create) }} apiVersion: v1 kind: ConfigMap @@ -182,11 +183,7 @@ data: pyroscope.write "pyroscope_write" { endpoint { - {{- if hasKey .Values.pyroscope.components "distributor" }} - url = "http://{{ include "pyroscope.fullname" . }}-distributor.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ (.Values.pyroscope.components.distributor.service).port | default .Values.pyroscope.service.port}}" - {{- else }} - url = "http://{{ include "pyroscope.fullname" . }}.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ .Values.pyroscope.service.port }}" - {{- end }} + url = "{{ include "pyroscope.write_url" . }}" } } diff --git a/operations/pyroscope/helm/pyroscope/templates/configmap-alloy.yaml b/operations/pyroscope/helm/pyroscope/templates/configmap-alloy.yaml new file mode 100644 index 0000000000..e8485a1e43 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/templates/configmap-alloy.yaml @@ -0,0 +1,222 @@ +{{- if and (.Values.alloy.enabled) (not .Values.alloy.alloy.configMap.create) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.alloy.alloy.configMap.name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "pyroscope.labels" . | nindent 4 }} +data: + config.alloy: | + logging { + level = "info" + format = "logfmt" + } + + discovery.kubernetes "pyroscope_kubernetes" { + role = "pod" + } + + // The default scrape config allows to define annotations based scraping. + // + // For example the following annotations: + // + // ``` + // profiles.grafana.com/memory.scrape: "true" + // profiles.grafana.com/memory.port: "8080" + // profiles.grafana.com/cpu.scrape: "true" + // profiles.grafana.com/cpu.port: "8080" + // profiles.grafana.com/goroutine.scrape: "true" + // profiles.grafana.com/goroutine.port: "8080" + // ``` + // + // will scrape the `memory`, `cpu` and `goroutine` profiles from the `8080` port of the pod. + // + // For more information see https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/helm/#optional-scrape-your-own-workloads-profiles + discovery.relabel "kubernetes_pods" { + targets = concat(discovery.kubernetes.pyroscope_kubernetes.targets) + + rule { + action = "drop" + source_labels = ["__meta_kubernetes_pod_phase"] + regex = "Pending|Succeeded|Failed|Completed" + } + + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_label_(.+)" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // Set service_name by choosing the first non-empty value from the following ordered list: + // - pod.annotation[profiles.grafana.com/service_name] + // - pod.annotation[resource.opentelemetry.io/service.name] + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_annotation_profiles_grafana_com_service_name", + "__meta_kubernetes_pod_annotation_resource_opentelemetry_io_service_name", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "service_name" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_repository"] + target_label = "service_repository" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_git_ref"] + target_label = "service_git_ref" + } + + rule { + action = "replace" + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_service_root_path"] + target_label = "service_root_path" + } + } + {{- $profileTypes := list "memory" "cpu" "goroutine" "block" "mutex" "fgprof" }} + {{- range $profileTypes }} + + discovery.relabel "kubernetes_pods_{{.}}_default_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_port_name"] + action = "keep" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_number"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_port" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + discovery.relabel "kubernetes_pods_{{.}}_custom_name" { + targets = concat(discovery.relabel.kubernetes_pods.output) + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_scrape"] + action = "keep" + regex = "true" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_port_name"] + action = "drop" + regex = "" + } + + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_port_name" + action = "keepequal" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_scheme"] + action = "replace" + regex = "(https?)" + target_label = "__scheme__" + replacement = "$1" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_path"] + action = "replace" + regex = "(.+)" + target_label = "__profile_path__" + replacement = "$1" + } + + rule { + source_labels = ["__address__", "__meta_kubernetes_pod_annotation_profiles_grafana_com_{{.}}_port"] + action = "replace" + regex = "(.+?)(?::\\d+)?;(\\d+)" + target_label = "__address__" + replacement = "$1:$2" + } + } + + pyroscope.scrape "pyroscope_scrape_{{.}}" { + clustering { + enabled = true + } + + targets = concat(discovery.relabel.kubernetes_pods_{{.}}_default_name.output, discovery.relabel.kubernetes_pods_{{.}}_custom_name.output) + forward_to = [pyroscope.write.pyroscope_write.receiver] + + profiling_config { + {{- $currentType := . -}} + {{- range $profileTypes }} + profile.{{if eq . "cpu"}}process_cpu{{else}}{{.}}{{end}} { + enabled = {{if eq . $currentType}}true{{else}}false{{end}} + } + {{- if ne . (last $profileTypes) }}{{ printf "\n" }}{{ end }} + {{- end }} + } + } + {{- end }} + + pyroscope.write "pyroscope_write" { + endpoint { + url = "{{ include "pyroscope.write_url" . }}" + } + } + +{{- end }} diff --git a/operations/pyroscope/helm/pyroscope/templates/deployments-statefulsets.yaml b/operations/pyroscope/helm/pyroscope/templates/deployments-statefulsets.yaml index d2bd71a643..28e14a3800 100644 --- a/operations/pyroscope/helm/pyroscope/templates/deployments-statefulsets.yaml +++ b/operations/pyroscope/helm/pyroscope/templates/deployments-statefulsets.yaml @@ -1,8 +1,14 @@ {{- $global := . }} -{{- range $component, $cfg := (fromYaml (include "pyroscope.components" .)) }} +{{- $components := (fromYaml (include "pyroscope.components" .)) }} +{{- $hasV1 := $global.Values.architecture.storage.v1 }} +{{- $hasV2 := $global.Values.architecture.storage.v2 }} +{{- $hasMetastore := hasKey $components "metastore" }} +{{- $hasQueryBackend := hasKey $components "query-backend" }} +{{- range $component, $cfg := $components }} {{- with $global }} {{- $values := mustMergeOverwrite (deepCopy .Values.pyroscope ) ($cfg | default dict)}} {{- $extraArgs := mustMergeOverwrite (deepCopy .Values.pyroscope.extraArgs ) ($cfg.extraArgs | default dict)}} +{{- $isMetastore := or (and (eq $component "all") ($hasV2)) (eq $component "metastore") }} --- apiVersion: apps/v1 kind: {{ $cfg.kind }} @@ -27,7 +33,15 @@ spec: template: metadata: annotations: + {{- if not (hasKey $values.podAnnotations "checksum/config") }} checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if not (hasKey $values.podAnnotations "profiles.grafana.com/service_repository") }} + profiles.grafana.com/service_repository: "https://github.com/grafana/pyroscope" + {{- end }} + {{- if not (hasKey $values.podAnnotations "profiles.grafana.com/service_git_ref") }} + profiles.grafana.com/service_git_ref: "{{ if regexMatch "^[0-9]" .Chart.AppVersion }}v{{ end }}{{ .Chart.AppVersion }}" + {{- end }} {{- with $values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} @@ -57,21 +71,96 @@ spec: - name: {{ if eq $component "all" }}"pyroscope"{{ else }}"{{ $component }}"{{ end }} securityContext: {{- toYaml $values.securityContext | nindent 12 }} - image: "{{ $values.image.repository }}:{{ $values.image.tag | default .Chart.AppVersion }}" + {{- $registry := $global.Values.global.imageRegistry | default $values.image.registry }} + image: "{{ if $registry }}{{ $registry }}/{{ end }}{{ $values.image.repository }}:{{ $values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ $values.image.pullPolicy }} args: - "-target={{ $component }}" - - "-self-profiling.disable-push=true" + - "-self-profiling.disable-push={{ .Values.pyroscope.disableSelfProfile }}" - "-server.http-listen-port={{ $values.service.port }}" - - "-memberlist.cluster-label={{ .Release.Namespace }}-{{ include "pyroscope.fullname" .}}" + - "-memberlist.cluster-label={{ .Release.Namespace }}-{{ include "pyroscope.fullname" .}}{{if $global.Values.architecture.microservices.enabled}}{{$global.Values.architecture.microservices.clusterLabelSuffix}}{{end}}" - "-memberlist.join=dns+{{ include "pyroscope.fullname" .}}-memberlist.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ .Values.pyroscope.memberlist.port }}" - "-config.file=/etc/pyroscope/config.yaml" - "-runtime-config.file=/etc/pyroscope/overrides/overrides.yaml" {{- range $key, $value := $extraArgs }} - "-{{ $key }}={{ $value }}" {{- end }} - {{- with $values.extraEnvVars }} + {{- /* v2 specific options for all components */}} + {{- if $hasV2 }} + {{- if (not (hasKey $extraArgs "query-backend.address")) }} + - "-query-backend.address=dns:///_grpc._tcp.{{ include "pyroscope.fullname" . }}{{ if $hasQueryBackend }}-query-backend{{ end }}-headless.$(NAMESPACE_FQDN):{{ .Values.pyroscope.grpc.port }}" + {{- end }} + {{- if (not (hasKey $extraArgs "metastore.address")) }} + - "-metastore.address=kubernetes:///{{ include "pyroscope.fullname" . }}{{ if $hasMetastore }}-metastore{{ end }}-headless.$(NAMESPACE_FQDN):{{ .Values.pyroscope.grpc.port }}" + {{- end }} + {{- end }} + {{- /* metastore specific v2 migration config */}} + {{- if $isMetastore }} + {{- if (not (hasKey $extraArgs "metastore.data-dir")) }} + - "-metastore.data-dir=./data-metastore/data" + {{- end }} + {{- if (not (hasKey $extraArgs "metastore.raft.dir")) }} + - "-metastore.raft.dir=./data-metastore/raft" + {{- end }} + {{- if (not (hasKey $extraArgs "metastore.raft.snapshots-dir")) }} + - "-metastore.raft.snapshots-dir=./data-metastore/raft" + {{- end }} + {{- if (not (hasKey $extraArgs "metastore.raft.bind-address")) }} + - "-metastore.raft.bind-address=:{{ .Values.pyroscope.metastore.port }}" + {{- end }} + {{- if (not (hasKey $extraArgs "metastore.raft.server-id")) }} + - "-metastore.raft.server-id=$(POD_NAME).$(PYROSCOPE_METASTORE_SERVICE)" + {{- end }} + {{- if (not (hasKey $extraArgs "metastore.raft.advertise-address")) }} + - "-metastore.raft.advertise-address=$(POD_NAME).$(PYROSCOPE_METASTORE_SERVICE)" + {{- end }} + {{- if (not (hasKey $extraArgs "metastore.raft.bootstrap-peers")) }} + - "-metastore.raft.bootstrap-peers=dnssrvnoa+_raft._tcp.$(PYROSCOPE_METASTORE_SERVICE)" + {{- end }} + {{- end }} + {{- /* architecture storage layer */}} + {{- if not (hasKey $extraArgs "architecture.storage") }} + {{- if and $hasV1 $hasV2 }} + - "-architecture.storage=v1-v2-dual" + {{- else if $hasV1 }} + - "-architecture.storage=v1" + {{- else if $hasV2 }} + - "-architecture.storage=v2" + {{- end }} + {{- end }} + {{- /* write path config */}} + {{- if (not (hasKey $extraArgs "write-path")) }} + {{- if and $hasV1 $hasV2 }} + - "-write-path=combined" + {{- if not (hasKey $extraArgs "write-path.ingester-weight") }} + - "-write-path.ingester-weight={{ $global.Values.architecture.storage.migration.ingesterWeight }}" + {{- end }} + {{- if not (hasKey $extraArgs "write-path.segment-writer-weight") }} + - "-write-path.segment-writer-weight={{ $global.Values.architecture.storage.migration.segmentWriterWeight }}" + {{- end }} + {{- else if not $hasV2 }} + - "-write-path=ingester" + {{- end }} + {{- end }} + {{- /* query-frontend v1-v2-dual migration config */}} + {{- if and $hasV1 $hasV2 (or (eq $component "all") (eq $component "query-frontend")) }} + {{- $qbFrom := $global.Values.architecture.storage.migration.queryBackendFrom }} + {{- if and (not (hasKey $extraArgs "enable-query-backend-from")) $qbFrom (ne $qbFrom "auto") }} + - "-enable-query-backend-from={{$qbFrom}}" + {{- end }} + {{- end }} env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE_FQDN + value: "{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}" + {{- if and $hasV2 (not (hasKey $values.extraEnvVars "PYROSCOPE_METASTORE_SERVICE")) }} + - name: PYROSCOPE_METASTORE_SERVICE + value: "{{ include "pyroscope.fullname" .}}{{ if $hasMetastore }}-metastore{{ end }}-headless.{{ .Release.Namespace }}.svc{{ .Values.pyroscope.cluster_domain }}:{{ .Values.pyroscope.metastore.port }}" + {{- end }} + {{- with $values.extraEnvVars }} {{- range $key, $value := . }} - name: {{ $key }} {{- if kindIs "map" $value }} @@ -81,6 +170,9 @@ spec: {{- end }} {{- end }} {{- end }} + {{- with $values.extraCustomEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} {{- with $values.extraEnvFrom }} envFrom: {{- toYaml . | nindent 12 }} @@ -92,12 +184,22 @@ spec: - name: {{ $values.memberlist.port_name }} containerPort: {{ $values.memberlist.port }} protocol: TCP + {{- if $hasV2 }} + - name: {{ $values.grpc.port_name }} + containerPort: {{ $values.grpc.port }} + protocol: TCP + {{- end }} + {{- if $isMetastore }} + - name: {{ $values.metastore.port_name }} + containerPort: {{ $values.metastore.port }} + protocol: TCP + {{- end }} readinessProbe: httpGet: path: /ready port: {{ $values.service.port_name }} scheme: {{ $values.service.scheme }} - {{- if and (hasKey $values "readinessProbe") (hasKey $values.readinessProbe "initialDelaySeconds") }} + {{- if ($values.readinessProbe).initialDelaySeconds }} initialDelaySeconds: {{ $values.readinessProbe.initialDelaySeconds }} {{- end }} volumeMounts: @@ -114,15 +216,31 @@ spec: mountPath: /data-compactor subPath: compactor {{- end }} + {{- if $isMetastore }} + - name: data + mountPath: /data-metastore + subPath: {{ $values.persistence.metastore.subPath }} + {{- end }} {{- with $values.extraVolumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} resources: + {{- if $global.Values.architecture.overwriteResources }} + {{- toYaml $global.Values.architecture.overwriteResources | nindent 12 }} + {{- else }} {{- toYaml $values.resources | nindent 12 }} + {{- end }} + {{- with $values.extraContainers }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- with $values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} + {{- with $values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with $values.affinity }} affinity: {{- toYaml . | nindent 8 }} @@ -131,6 +249,9 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- if hasKey $values "priorityClassName" }} + priorityClassName: {{ $values.priorityClassName | quote }} + {{- end }} {{- if $values.terminationGracePeriodSeconds }} terminationGracePeriodSeconds: {{ $values.terminationGracePeriodSeconds }} {{- end }} @@ -158,7 +279,9 @@ spec: claimName: {{ $cfg.name }}-data {{- else }} volumeClaimTemplates: - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data annotations: {{- toYaml $persistence.annotations | nindent 8 }} @@ -173,6 +296,9 @@ spec: selector: {{- toYaml $persistence.selector | nindent 8 }} {{- end }} + {{- with $persistence.extraVolumeClaimTemplates }} + {{- toYaml . | nindent 2 }} + {{- end }} {{- end }} --- {{- $pdb := $values.podDisruptionBudget }} diff --git a/operations/pyroscope/helm/pyroscope/templates/extra-manifests.yaml b/operations/pyroscope/helm/pyroscope/templates/extra-manifests.yaml new file mode 100644 index 0000000000..4ff426e1b4 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/templates/extra-manifests.yaml @@ -0,0 +1,8 @@ +{{ range .Values.extraObjects }} +--- +{{- if typeIs "string" . }} +{{ tpl . $ }} +{{- else }} +{{ tpl (. | toYaml) $ }} +{{- end }} +{{ end }} diff --git a/operations/pyroscope/helm/pyroscope/templates/httpRoute.yaml b/operations/pyroscope/helm/pyroscope/templates/httpRoute.yaml new file mode 100644 index 0000000000..03b613dd94 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/templates/httpRoute.yaml @@ -0,0 +1,104 @@ +{{- if .Values.httpRoute.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "pyroscope.fullname" . }}-http-route + namespace: {{ .Release.Namespace }} + labels: + {{- include "pyroscope.labels" . | nindent 4 }} + {{- with .Values.httpRoute.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + - name: {{ .Values.httpRoute.gateway.name }} + namespace: {{ .Values.httpRoute.gateway.namespace }} + {{- with .Values.httpRoute.gateway.sectionName }} + sectionName: {{ . }} + {{- end }} + hostnames: + {{- range .Values.httpRoute.hostnames }} + - {{ . | quote }} + {{- end }} + rules: + - matches: + - path: + type: PathPrefix + value: / + - path: + type: PathPrefix + value: /querier.v1.QuerierService/ + - path: + type: PathPrefix + value: /render + - path: + type: PathPrefix + value: /render-diff + backendRefs: + {{- if gt (len $.Values.pyroscope.components) 1}} + - name: {{ include "pyroscope.fullname" $ }}-query-frontend + port: {{ .Values.pyroscope.service.port }} + {{- else }} + - name: {{ include "pyroscope.fullname" $ }} + port: {{ .Values.pyroscope.service.port }} + {{- end }} + {{- with .Values.httpRoute.timeouts }} + timeouts: + {{- toYaml . | nindent 8 }} + {{- end }} + - matches: + - path: + type: PathPrefix + value: /push.v1.PusherService/ + - path: + type: PathPrefix + value: /ingest + backendRefs: + {{- if gt (len $.Values.pyroscope.components) 1}} + - name: {{ include "pyroscope.fullname" $ }}-distributor + port: {{ .Values.pyroscope.service.port }} + {{- else }} + - name: {{ include "pyroscope.fullname" $ }} + port: {{ .Values.pyroscope.service.port }} + {{- end }} + {{- with .Values.httpRoute.timeouts }} + timeouts: + {{- toYaml . | nindent 8 }} + {{- end }} + - matches: + - path: + type: PathPrefix + value: /settings.v1.SettingsService/ + backendRefs: + {{- if gt (len $.Values.pyroscope.components) 1}} + - name: {{ include "pyroscope.fullname" $ }}-tenant-settings + port: {{ .Values.pyroscope.service.port }} + {{- else }} + - name: {{ include "pyroscope.fullname" $ }} + port: {{ .Values.pyroscope.service.port }} + {{- end }} + {{- with .Values.httpRoute.timeouts }} + timeouts: + {{- toYaml . | nindent 8 }} + {{- end }} + - matches: + - path: + type: PathPrefix + value: /adhocprofiles.v1.AdHocProfileService/ + backendRefs: + {{- if gt (len $.Values.pyroscope.components) 1}} + - name: {{ include "pyroscope.fullname" $ }}-ad-hoc-profiles + port: {{ .Values.pyroscope.service.port }} + {{- else }} + - name: {{ include "pyroscope.fullname" $ }} + port: {{ .Values.pyroscope.service.port }} + {{- end }} + {{- with .Values.httpRoute.timeouts }} + timeouts: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/operations/pyroscope/helm/pyroscope/templates/ingress.yaml b/operations/pyroscope/helm/pyroscope/templates/ingress.yaml index 840fcc4f49..3ea75c4c51 100644 --- a/operations/pyroscope/helm/pyroscope/templates/ingress.yaml +++ b/operations/pyroscope/helm/pyroscope/templates/ingress.yaml @@ -6,6 +6,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "pyroscope.labels" . | nindent 4 }} + {{- with .Values.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} {{- with .Values.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} @@ -33,7 +36,7 @@ spec: port: number: {{ $.Values.pyroscope.service.port }} path: / - pathType: Prefix + pathType: {{ $.Values.ingress.pathType }} - backend: service: {{- if gt (len $.Values.pyroscope.components) 1}} @@ -44,7 +47,7 @@ spec: port: number: {{ $.Values.pyroscope.service.port }} path: /querier.v1.QuerierService/ - pathType: ImplementationSpecific + pathType: {{ $.Values.ingress.pathType }} - backend: service: {{- if gt (len $.Values.pyroscope.components) 1}} @@ -55,7 +58,7 @@ spec: port: number: {{ $.Values.pyroscope.service.port }} path: /render - pathType: Prefix + pathType: {{ $.Values.ingress.pathType }} - backend: service: {{- if gt (len $.Values.pyroscope.components) 1}} @@ -66,7 +69,7 @@ spec: port: number: {{ $.Values.pyroscope.service.port }} path: /render-diff - pathType: Prefix + pathType: {{ $.Values.ingress.pathType }} - backend: service: {{- if gt (len $.Values.pyroscope.components) 1}} @@ -77,7 +80,7 @@ spec: port: number: {{ $.Values.pyroscope.service.port }} path: /push.v1.PusherService/ - pathType: ImplementationSpecific + pathType: {{ $.Values.ingress.pathType }} - backend: service: {{- if gt (len $.Values.pyroscope.components) 1}} @@ -88,6 +91,28 @@ spec: port: number: {{ $.Values.pyroscope.service.port }} path: /ingest - pathType: Prefix + pathType: {{ $.Values.ingress.pathType }} + - backend: + service: + {{- if gt (len $.Values.pyroscope.components) 1}} + name: {{ include "pyroscope.fullname" $ }}-tenant-settings + {{- else }} + name: {{ include "pyroscope.fullname" $ }} + {{- end }} + port: + number: {{ $.Values.pyroscope.service.port }} + path: /settings.v1.SettingsService/ + pathType: {{ $.Values.ingress.pathType }} + - backend: + service: + {{- if gt (len $.Values.pyroscope.components) 1}} + name: {{ include "pyroscope.fullname" $ }}-ad-hoc-profiles + {{- else }} + name: {{ include "pyroscope.fullname" $ }} + {{- end }} + port: + number: {{ $.Values.pyroscope.service.port }} + path: /adhocprofiles.v1.AdHocProfileService/ + pathType: {{ $.Values.ingress.pathType }} {{- end }} {{- end }} diff --git a/operations/pyroscope/helm/pyroscope/templates/rbac-discovery.yaml b/operations/pyroscope/helm/pyroscope/templates/rbac-discovery.yaml new file mode 100644 index 0000000000..f3065587a6 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/templates/rbac-discovery.yaml @@ -0,0 +1,38 @@ +{{- $hasV2 := .Values.architecture.storage.v2 }} +{{- if and $hasV2 .Values.pyroscope.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "pyroscope.fullname" . }}-discovery + labels: + {{- include "pyroscope.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + - discovery.k8s.io + resources: + - endpointslices + - endpoints + - services + - pods + verbs: + - get + - watch + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "pyroscope.fullname" . }}-discovery + labels: + {{- include "pyroscope.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "pyroscope.fullname" . }}-discovery +subjects: +- kind: ServiceAccount + name: {{ include "pyroscope.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/operations/pyroscope/helm/pyroscope/templates/rbac.yaml b/operations/pyroscope/helm/pyroscope/templates/rbac.yaml deleted file mode 100644 index cb00d18f78..0000000000 --- a/operations/pyroscope/helm/pyroscope/templates/rbac.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- if .Values.pyroscope.rbac.create -}} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ .Release.Namespace }}-{{ include "pyroscope.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "pyroscope.labels" . | nindent 4 }} -rules: -- apiGroups: - - "" - resources: - - pods - verbs: - - list - - watch -- apiGroups: - - "" - resources: - - nodes - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ .Release.Namespace }}-{{ include "pyroscope.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "pyroscope.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ .Release.Namespace }}-{{ include "pyroscope.fullname" . }} -subjects: - - kind: ServiceAccount - name: {{ include "pyroscope.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} -{{- end }} diff --git a/operations/pyroscope/helm/pyroscope/templates/services.yaml b/operations/pyroscope/helm/pyroscope/templates/services.yaml index d20d2a5aae..b4acffe60b 100644 --- a/operations/pyroscope/helm/pyroscope/templates/services.yaml +++ b/operations/pyroscope/helm/pyroscope/templates/services.yaml @@ -1,7 +1,10 @@ {{- $global := . }} -{{- range $component, $cfg := (fromYaml (include "pyroscope.components" .)) }} +{{- $components := (fromYaml (include "pyroscope.components" .)) }} +{{- $hasV2 := $global.Values.architecture.storage.v2 }} +{{- range $component, $cfg := $components }} {{- with $global }} {{- $values := mustMergeOverwrite (deepCopy .Values.pyroscope ) ($cfg | default dict)}} +{{- $isMetastore := or (and (eq $component "all") ($hasV2)) (eq $component "metastore") }} --- apiVersion: v1 kind: Service @@ -22,6 +25,21 @@ spec: targetPort: {{ $values.service.port_name }} protocol: TCP name: {{ $values.service.port_name }} + {{- if $hasV2 }} + - port: {{ $values.grpc.port }} + targetPort: {{ $values.grpc.port_name }} + protocol: TCP + name: {{ $values.grpc.port_name }} + {{- end }} + {{- if $isMetastore }} + - port: {{ $values.metastore.port }} + targetPort: {{ $values.metastore.port_name }} + protocol: TCP + name: {{ $values.metastore.port_name }} + {{- end }} + {{- with $values.service.extraPorts }} + {{- toYaml . | nindent 4 }} + {{- end }} selector: {{- include "pyroscope.selectorLabels" . | nindent 4 }} app.kubernetes.io/component: {{ $component | quote }} @@ -34,9 +52,15 @@ metadata: labels: {{- include "pyroscope.labels" . | nindent 4 }} app.kubernetes.io/component: {{ $component | quote }} + {{- if or .Values.serviceMonitor.enabled $values.service.headlessAnnotations }} + annotations: {{- if .Values.serviceMonitor.enabled }} prometheus.io/service-monitor: "false" {{- end }} + {{- with $values.service.headlessAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} spec: type: ClusterIP clusterIP: None @@ -45,6 +69,24 @@ spec: targetPort: {{ $values.service.port_name }} protocol: TCP name: {{ $values.service.port_name }} + {{- if $hasV2 }} + - port: {{ $values.grpc.port }} + targetPort: {{ $values.grpc.port_name }} + protocol: TCP + name: {{ $values.grpc.port_name }} + {{- end }} + {{- if $isMetastore }} + - port: {{ $values.metastore.port }} + targetPort: {{ $values.metastore.port_name }} + protocol: TCP + name: {{ $values.metastore.port_name }} + {{- end }} + {{- with $values.service.extraPorts }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or $values.service.publishNotReadyAddresses $isMetastore }} + publishNotReadyAddresses: true + {{- end }} selector: {{- include "pyroscope.selectorLabels" . | nindent 4 }} app.kubernetes.io/component: {{ $component | quote }} diff --git a/operations/pyroscope/helm/pyroscope/templates/unified-services.yaml b/operations/pyroscope/helm/pyroscope/templates/unified-services.yaml new file mode 100644 index 0000000000..1116d0ab15 --- /dev/null +++ b/operations/pyroscope/helm/pyroscope/templates/unified-services.yaml @@ -0,0 +1,47 @@ +{{- $global := . }} +{{- $components := (fromYaml (include "pyroscope.components" .)) }} +{{- if $global.Values.architecture.deployUnifiedServices }} +{{- /* There services are useful wanting to switch from single binary to microservices without reconfiguring the endpoints */}} +{{- $hasDistributor := hasKey $components "distributor" }} +{{- $hasQueryFrontend := hasKey $components "query-frontend" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-write + namespace: {{ .Release.Namespace }} + labels: + {{- include "pyroscope.labels" . | nindent 4 }} +spec: + type: "ClusterIP" + ports: + - port: 80 + targetPort: {{ .Values.pyroscope.service.port_name }} + protocol: TCP + name: {{ .Values.pyroscope.service.port_name }} + selector: + {{- include "pyroscope.selectorLabels" . | nindent 4 }} + {{- if $hasDistributor }} + app.kubernetes.io/component: distributor + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-read + namespace: {{ .Release.Namespace }} + labels: + {{- include "pyroscope.labels" . | nindent 4 }} +spec: + type: "ClusterIP" + ports: + - port: 80 + targetPort: {{ .Values.pyroscope.service.port_name }} + protocol: TCP + name: {{ .Values.pyroscope.service.port_name }} + selector: + {{- include "pyroscope.selectorLabels" . | nindent 4 }} + {{- if $hasQueryFrontend }} + app.kubernetes.io/component: query-frontend + {{- end }} +{{- end }} diff --git a/operations/pyroscope/helm/pyroscope/values-micro-services.yaml b/operations/pyroscope/helm/pyroscope/values-micro-services.yaml index b51e8c51d2..9759973ab1 100644 --- a/operations/pyroscope/helm/pyroscope/values-micro-services.yaml +++ b/operations/pyroscope/helm/pyroscope/values-micro-services.yaml @@ -84,5 +84,23 @@ pyroscope: # Depending on this flag and the number of tenants + blocks that need to be synced on startup, pods can take # some time to become ready. This value can be used to ensure Kubernetes waits long enough and reduce errors. initialDelaySeconds: 60 + tenant-settings: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 4Gi + requests: + memory: 16Mi + cpu: 0.1 + ad-hoc-profiles: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 4Gi + requests: + memory: 16Mi + cpu: 0.1 minio: enabled: true diff --git a/operations/pyroscope/helm/pyroscope/values.yaml b/operations/pyroscope/helm/pyroscope/values.yaml index d1eb4b21a8..e38d4ccbdd 100644 --- a/operations/pyroscope/helm/pyroscope/values.yaml +++ b/operations/pyroscope/helm/pyroscope/values.yaml @@ -1,15 +1,22 @@ # Default values for pyroscope. # This is a YAML-formatted file. # Declare variables to be passed into your templates. +global: + # -- Overrides the Docker registry globally for all images + imageRegistry: null pyroscope: replicaCount: 1 + # -- Enable or disable Self profile push, useful to test + disableSelfProfile: true + # -- Kubernetes cluster domain suffix for DNS discovery cluster_domain: .cluster.local. image: + registry: '' repository: grafana/pyroscope pullPolicy: IfNotPresent # Allows to override the image tag, which defaults to the appVersion in the chart metadata @@ -25,16 +32,25 @@ pyroscope: # The following environment variables are set by the Helm chart. # JAEGER_AGENT_HOST: jaeger-agent.jaeger.svc.cluster.local. + extraCustomEnvVars: {} + # The following environment variables raw form. + # - name: MY_NODE_NAME + # valueFrom: + # fieldRef: + # fieldPath: spec.nodeName + # -- Environment variables from secrets or configmaps to add to the pods extraEnvFrom: [] imagePullSecrets: [] dnsPolicy: ClusterFirst initContainers: [] + extraContainers: [] nameOverride: "" fullnameOverride: "" rbac: + # -- Whether to create RBAC resources create: true serviceAccount: @@ -47,7 +63,7 @@ pyroscope: name: "" podAnnotations: - # Scrapes itself see https://grafana.com/docs/phlare/latest/operators-guide/deploy-kubernetes/#optional-scrape-your-own-workloads-profiles + # Scrapes itself see https://grafana.com/docs/pyroscope/latest/deploy-kubernetes/helm/#optional-scrape-your-own-workloads-profiles profiles.grafana.com/memory.scrape: "true" profiles.grafana.com/memory.port_name: http2 profiles.grafana.com/cpu.scrape: "true" @@ -81,11 +97,20 @@ pyroscope: port_name: http2 scheme: HTTP annotations: {} + headlessAnnotations: {} memberlist: port: 7946 port_name: memberlist + grpc: + port: 9095 + port_name: grpc + + metastore: + port: 9099 + port_name: raft + resources: {} # We usually recommend not to specify default resources and to leave this as a conscious @@ -110,9 +135,12 @@ pyroscope: nodeSelector: {} + # -- Topology Spread Constraints + topologySpreadConstraints: [] + ## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ ## If you set enabled as "True", you need : - ## - create a pv which above 10Gi and has same namespace with phlare + ## - create a pv which above 10Gi and has same namespace with pyroscope ## - keep storageClassName same with below setting persistence: enabled: false @@ -122,10 +150,14 @@ pyroscope: annotations: {} # selector: # matchLabels: - # app.kubernetes.io/name: phlare + # app.kubernetes.io/name: pyroscope # subPath: "" # existingClaim: + metastore: + # subPath to use of the data volume for the metastore persistence. + subPath: .metastore + extraVolumes: [] # - name: backup-volume @@ -145,13 +177,16 @@ pyroscope: affinity: {} + # Override the PodPriorityClass + # priorityClassName: high + # run specific components separately components: {} - # -- Allows to override Phlare's configuration using structured format. + # -- Allows to override Pyroscope's configuration using structured format. structuredConfig: {} - # -- Contains Phlare's configuration as a string. + # -- Contains Pyroscope's configuration as a string. # @default -- The config depends on other values been set, details can be found in [`values.yaml`](./values.yaml) config: | {{- if .Values.minio.enabled }} @@ -173,11 +208,272 @@ pyroscope: # ingestion_burst_size_mb: 2 # -- Grafana Agent Configuration. + +architecture: + storage: + # -- (bool) Enable v1 storage layer. + v1: false + # -- (bool) Enable v2 storage layer. + v2: true + + migration: + # -- (float) Specifies the fraction [0:1] that should be send to the v1 write path / ingester in combined mode. 0 means no traffics is sent to ingester. 1 means 100% of requests are sent to ingester. + ingesterWeight: 1.0 + # -- (float) Specifies the fraction [0:1] that should be send to the v2 write path / segment-writer in combined mode. 0 means no traffics is sent to segment-writer. 1 means 100% of requests are sent to segment-writer. + segmentWriterWeight: 1.0 + + # -- (string) Specify a time stamp from when the v2 read path should serve traffic. Defaults to "auto" which determines the split point from the metastore. + queryBackendFrom: auto + + # -- This flag is useful for testing, it will overwrite all pods resource statements with its contents + overwriteResources: + {} + # limits: {} + # requests: {} + + + # -- Deploy unified write/read services. These endpoints will can be used no matter if the helm chart is configured as single-binary or microservices + deployUnifiedServices: false + + microservices: + # -- (bool) Enable micro-services deployment mode. This is recommend for larger scale deployment and allow right size each aspect of Pyroscope. + enabled: false + + # -- (string) Memberlist cluster label that will be used for all members of this cluster + clusterLabelSuffix: -micro-services + + # -- @ignored + # Not useful to be indivually exposed + v1: + querier: + kind: Deployment + replicaCount: 3 + resources: + limits: + memory: 1Gi + requests: + memory: 256Mi + cpu: 1 + extraArgs: + store-gateway.sharding-ring.replication-factor: "3" + query-frontend: + kind: Deployment + replicaCount: 2 + resources: + limits: + memory: 1Gi + requests: + memory: 256Mi + cpu: 100m + query-scheduler: + kind: Deployment + replicaCount: 2 + resources: + limits: + memory: 1Gi + requests: + memory: 256Mi + cpu: 100m + distributor: + kind: Deployment + replicaCount: 2 + resources: + limits: + memory: 1Gi + requests: + memory: 256Mi + cpu: 500m + ingester: + kind: StatefulSet + replicaCount: 3 + terminationGracePeriodSeconds: 600 + resources: + limits: + memory: 16Gi + requests: + memory: 8Gi + cpu: 1 + compactor: + kind: StatefulSet + replicaCount: 3 + terminationGracePeriodSeconds: 1200 + persistence: + enabled: false + resources: + limits: + memory: 16Gi + requests: + memory: 8Gi + cpu: 1 + store-gateway: + kind: StatefulSet + replicaCount: 3 + persistence: + # The store-gateway needs not need persistent storage, but we still run it as a StatefulSet + # This is to avoid having blocks of data being + enabled: false + resources: + limits: + memory: 16Gi + requests: + memory: 8Gi + cpu: 1 + readinessProbe: + # The store gateway can be configured to wait on startup for ring stability to be reached before it becomes + # ready. See the `store-gateway.sharding-ring.wait-stability-min-duration` server argument for more information. + # + # Depending on this flag and the number of tenants + blocks that need to be synced on startup, pods can take + # some time to become ready. This value can be used to ensure Kubernetes waits long enough and reduce errors. + initialDelaySeconds: 60 + extraArgs: + store-gateway.sharding-ring.replication-factor: "3" + tenant-settings: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 4Gi + requests: + memory: 16Mi + cpu: 0.1 + ad-hoc-profiles: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 4Gi + requests: + memory: 16Mi + cpu: 0.1 + # -- @ignored + # Not useful to be indivually exposed + v2: + query-backend: + kind: Deployment + replicaCount: 3 + resources: + limits: + memory: 1Gi + requests: + memory: 256Mi + cpu: 1 + query-frontend: + kind: Deployment + replicaCount: 2 + resources: + limits: + memory: 1Gi + requests: + memory: 256Mi + cpu: 100m + distributor: + kind: Deployment + replicaCount: 2 + resources: + limits: + memory: 1Gi + requests: + memory: 256Mi + cpu: 500m + segment-writer: + kind: StatefulSet + replicaCount: 3 + terminationGracePeriodSeconds: 600 + resources: + limits: + memory: 4Gi + requests: + memory: 2Gi + cpu: 1 + compaction-worker: + kind: StatefulSet + replicaCount: 3 + terminationGracePeriodSeconds: 1200 + persistence: + enabled: false + resources: + limits: + memory: 2Gi + requests: + memory: 1Gi + cpu: 1 + metastore: + kind: StatefulSet + replicaCount: 3 + terminationGracePeriodSeconds: 1200 + persistence: + enabled: false + resources: + limits: + memory: 2Gi + requests: + memory: 1Gi + cpu: 1 + extraArgs: + # Expect 3 metastores + metastore.raft.bootstrap-expect-peers: 3 + # enable cleanup of blocks beyond retention + metastore.index.cleanup-interval: 1m + metastore.snapshot-compact-on-restore: true + tenant-settings: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 256Mi + requests: + memory: 16Mi + cpu: 0.1 + ad-hoc-profiles: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 256Mi + requests: + memory: 16Mi + cpu: 0.1 + admin: + kind: Deployment + replicaCount: 1 + resources: + limits: + memory: 256Mi + requests: + memory: 16Mi + cpu: 0.1 + +# ------------------------------------- +# Configuration for `alloy` child chart +# ------------------------------------- +alloy: + enabled: true + controller: + type: "statefulset" + replicas: 1 + podAnnotations: + profiles.grafana.com/memory.scrape: "true" + profiles.grafana.com/memory.port_name: "http-metrics" + profiles.grafana.com/cpu.scrape: "true" + profiles.grafana.com/cpu.port_name: "http-metrics" + profiles.grafana.com/goroutine.scrape: "true" + profiles.grafana.com/goroutine.port_name: "http-metrics" + profiles.grafana.com/service_repository: 'https://github.com/grafana/alloy' + profiles.grafana.com/service_git_ref: 'v1.8.1' + + alloy: + stabilityLevel: "public-preview" # This needs to be set for some of our resources until verison v1.2 is released + configMap: + create: false + name: alloy-config-pyroscope + clustering: + enabled: true + # ------------------------------------- # Configuration for `grafana-agent` child chart # ------------------------------------- agent: - enabled: true + enabled: false controller: type: "statefulset" replicas: 1 @@ -217,18 +513,38 @@ minio: requests: cpu: 100m memory: 128Mi - podAnnotations: - phlare.grafana.com/scrape: "true" - phlare.grafana.com/port: "9000" + podAnnotations: {} ingress: enabled: false className: "" + pathType: ImplementationSpecific + # Additional labels to add to the ingress resource + labels: {} + # Additional annotations to add to the ingress resource + annotations: {} # hosts: # - localhost # tls: # - secretName: certificate +httpRoute: + enabled: false + gateway: + name: "" + namespace: "" + # -- Optional to specify listener's name. + sectionName: null + # -- Additional labels to add to HTTPRoute resource. + labels: {} + # -- Additional annotations to add to HTTPRoute resource. + annotations: {} + hostnames: [] + # -- Timeout settings to add to each rule in HTTPRoute resource. + # https://gateway-api.sigs.k8s.io/reference/spec/#httproutetimeouts. + timeouts: {} + # request: 0s + # ServiceMonitor configuration serviceMonitor: # -- If enabled, ServiceMonitor resources for Prometheus Operator are created @@ -262,3 +578,18 @@ serviceMonitor: scheme: http # -- ServiceMonitor will use these tlsConfig settings to make the health check requests tlsConfig: null + +# -- Array of extra K8s manifests to deploy alongside the chart +extraObjects: [] +# extraObjects: +# - apiVersion: autoscaling.k8s.io/v1 +# kind: VerticalPodAutoscaler +# metadata: +# name: pyroscope-distributor +# spec: +# targetRef: +# apiVersion: apps/v1 +# kind: Deployment +# name: '{{ include "pyroscope.fullname" . }}-distributor' +# updatePolicy: +# updateMode: Auto diff --git a/operations/pyroscope/jsonnet/values-micro-services.json b/operations/pyroscope/jsonnet/values-micro-services.json index 19df46387c..38eaa78aa8 100644 --- a/operations/pyroscope/jsonnet/values-micro-services.json +++ b/operations/pyroscope/jsonnet/values-micro-services.json @@ -4,6 +4,19 @@ }, "pyroscope": { "components": { + "ad-hoc-profiles": { + "kind": "Deployment", + "replicaCount": 1, + "resources": { + "limits": { + "memory": "4Gi" + }, + "requests": { + "cpu": 0.1, + "memory": "16Mi" + } + } + }, "compactor": { "kind": "StatefulSet", "persistence": { @@ -105,6 +118,19 @@ "memory": "8Gi" } } + }, + "tenant-settings": { + "kind": "Deployment", + "replicaCount": 1, + "resources": { + "limits": { + "memory": "4Gi" + }, + "requests": { + "cpu": 0.1, + "memory": "16Mi" + } + } } }, "extraArgs": { diff --git a/operations/pyroscope/jsonnet/values.json b/operations/pyroscope/jsonnet/values.json index d0c4968b0c..26e3c67b00 100644 --- a/operations/pyroscope/jsonnet/values.json +++ b/operations/pyroscope/jsonnet/values.json @@ -21,11 +21,343 @@ "replicas": 1, "type": "statefulset" }, + "enabled": false + }, + "alloy": { + "alloy": { + "clustering": { + "enabled": true + }, + "configMap": { + "create": false, + "name": "alloy-config-pyroscope" + }, + "stabilityLevel": "public-preview" + }, + "controller": { + "podAnnotations": { + "profiles.grafana.com/cpu.port_name": "http-metrics", + "profiles.grafana.com/cpu.scrape": "true", + "profiles.grafana.com/goroutine.port_name": "http-metrics", + "profiles.grafana.com/goroutine.scrape": "true", + "profiles.grafana.com/memory.port_name": "http-metrics", + "profiles.grafana.com/memory.scrape": "true", + "profiles.grafana.com/service_git_ref": "v1.8.1", + "profiles.grafana.com/service_repository": "https://github.com/grafana/alloy" + }, + "replicas": 1, + "type": "statefulset" + }, "enabled": true }, + "architecture": { + "deployUnifiedServices": false, + "microservices": { + "clusterLabelSuffix": "-micro-services", + "enabled": false, + "v1": { + "ad-hoc-profiles": { + "kind": "Deployment", + "replicaCount": 1, + "resources": { + "limits": { + "memory": "4Gi" + }, + "requests": { + "cpu": 0.1, + "memory": "16Mi" + } + } + }, + "compactor": { + "kind": "StatefulSet", + "persistence": { + "enabled": false + }, + "replicaCount": 3, + "resources": { + "limits": { + "memory": "16Gi" + }, + "requests": { + "cpu": 1, + "memory": "8Gi" + } + }, + "terminationGracePeriodSeconds": 1200 + }, + "distributor": { + "kind": "Deployment", + "replicaCount": 2, + "resources": { + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": "500m", + "memory": "256Mi" + } + } + }, + "ingester": { + "kind": "StatefulSet", + "replicaCount": 3, + "resources": { + "limits": { + "memory": "16Gi" + }, + "requests": { + "cpu": 1, + "memory": "8Gi" + } + }, + "terminationGracePeriodSeconds": 600 + }, + "querier": { + "extraArgs": { + "store-gateway.sharding-ring.replication-factor": "3" + }, + "kind": "Deployment", + "replicaCount": 3, + "resources": { + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": 1, + "memory": "256Mi" + } + } + }, + "query-frontend": { + "kind": "Deployment", + "replicaCount": 2, + "resources": { + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": "100m", + "memory": "256Mi" + } + } + }, + "query-scheduler": { + "kind": "Deployment", + "replicaCount": 2, + "resources": { + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": "100m", + "memory": "256Mi" + } + } + }, + "store-gateway": { + "extraArgs": { + "store-gateway.sharding-ring.replication-factor": "3" + }, + "kind": "StatefulSet", + "persistence": { + "enabled": false + }, + "readinessProbe": { + "initialDelaySeconds": 60 + }, + "replicaCount": 3, + "resources": { + "limits": { + "memory": "16Gi" + }, + "requests": { + "cpu": 1, + "memory": "8Gi" + } + } + }, + "tenant-settings": { + "kind": "Deployment", + "replicaCount": 1, + "resources": { + "limits": { + "memory": "4Gi" + }, + "requests": { + "cpu": 0.1, + "memory": "16Mi" + } + } + } + }, + "v2": { + "ad-hoc-profiles": { + "kind": "Deployment", + "replicaCount": 1, + "resources": { + "limits": { + "memory": "256Mi" + }, + "requests": { + "cpu": 0.1, + "memory": "16Mi" + } + } + }, + "admin": { + "kind": "Deployment", + "replicaCount": 1, + "resources": { + "limits": { + "memory": "256Mi" + }, + "requests": { + "cpu": 0.1, + "memory": "16Mi" + } + } + }, + "compaction-worker": { + "kind": "StatefulSet", + "persistence": { + "enabled": false + }, + "replicaCount": 3, + "resources": { + "limits": { + "memory": "2Gi" + }, + "requests": { + "cpu": 1, + "memory": "1Gi" + } + }, + "terminationGracePeriodSeconds": 1200 + }, + "distributor": { + "kind": "Deployment", + "replicaCount": 2, + "resources": { + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": "500m", + "memory": "256Mi" + } + } + }, + "metastore": { + "extraArgs": { + "metastore.index.cleanup-interval": "1m", + "metastore.raft.bootstrap-expect-peers": 3, + "metastore.snapshot-compact-on-restore": true + }, + "kind": "StatefulSet", + "persistence": { + "enabled": false + }, + "replicaCount": 3, + "resources": { + "limits": { + "memory": "2Gi" + }, + "requests": { + "cpu": 1, + "memory": "1Gi" + } + }, + "terminationGracePeriodSeconds": 1200 + }, + "query-backend": { + "kind": "Deployment", + "replicaCount": 3, + "resources": { + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": 1, + "memory": "256Mi" + } + } + }, + "query-frontend": { + "kind": "Deployment", + "replicaCount": 2, + "resources": { + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": "100m", + "memory": "256Mi" + } + } + }, + "segment-writer": { + "kind": "StatefulSet", + "replicaCount": 3, + "resources": { + "limits": { + "memory": "4Gi" + }, + "requests": { + "cpu": 1, + "memory": "2Gi" + } + }, + "terminationGracePeriodSeconds": 600 + }, + "tenant-settings": { + "kind": "Deployment", + "replicaCount": 1, + "resources": { + "limits": { + "memory": "256Mi" + }, + "requests": { + "cpu": 0.1, + "memory": "16Mi" + } + } + } + } + }, + "overwriteResources": {}, + "storage": { + "migration": { + "ingesterWeight": 1, + "queryBackendFrom": "auto", + "segmentWriterWeight": 1 + }, + "v1": false, + "v2": true + } + }, + "extraObjects": [], + "global": { + "imageRegistry": null + }, + "httpRoute": { + "annotations": {}, + "enabled": false, + "gateway": { + "name": "", + "namespace": "", + "sectionName": null + }, + "hostnames": [], + "labels": {}, + "timeouts": {} + }, "ingress": { + "annotations": {}, "className": "", - "enabled": false + "enabled": false, + "labels": {}, + "pathType": "ImplementationSpecific" }, "minio": { "buckets": [ @@ -40,10 +372,7 @@ "persistence": { "size": "5Gi" }, - "podAnnotations": { - "phlare.grafana.com/port": "9000", - "phlare.grafana.com/scrape": "true" - }, + "podAnnotations": {}, "replicas": 1, "resources": { "requests": { @@ -59,18 +388,26 @@ "cluster_domain": ".cluster.local.", "components": {}, "config": "{{- if .Values.minio.enabled }}\nstorage:\n backend: s3\n s3:\n endpoint: \"{{ include \"pyroscope.fullname\" . }}-minio:9000\"\n bucket_name: {{(index .Values.minio.buckets 0).name | quote }}\n access_key_id: {{ .Values.minio.rootUser | quote }}\n secret_access_key: {{ .Values.minio.rootPassword | quote }}\n insecure: true\n{{- end }}\n", + "disableSelfProfile": true, "dnsPolicy": "ClusterFirst", "extraArgs": { "log.level": "debug" }, + "extraContainers": [], + "extraCustomEnvVars": {}, "extraEnvFrom": [], "extraEnvVars": {}, "extraLabels": {}, "extraVolumeMounts": [], "extraVolumes": [], "fullnameOverride": "", + "grpc": { + "port": 9095, + "port_name": "grpc" + }, "image": { "pullPolicy": "IfNotPresent", + "registry": "", "repository": "grafana/pyroscope", "tag": "" }, @@ -80,6 +417,10 @@ "port": 7946, "port_name": "memberlist" }, + "metastore": { + "port": 9099, + "port_name": "raft" + }, "nameOverride": "", "nodeSelector": {}, "persistence": { @@ -88,6 +429,9 @@ ], "annotations": {}, "enabled": false, + "metastore": { + "subPath": ".metastore" + }, "size": "10Gi" }, "podAnnotations": { @@ -115,6 +459,7 @@ "securityContext": {}, "service": { "annotations": {}, + "headlessAnnotations": {}, "port": 4040, "port_name": "http2", "scheme": "HTTP", @@ -127,7 +472,8 @@ }, "structuredConfig": {}, "tenantOverrides": {}, - "tolerations": [] + "tolerations": [], + "topologySpreadConstraints": [] }, "serviceMonitor": { "annotations": {}, diff --git a/operations/pyroscope/river_test.go b/operations/pyroscope/river_test.go deleted file mode 100644 index 31f15d3ec7..0000000000 --- a/operations/pyroscope/river_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package pyroscope - -import ( - "bytes" - "errors" - "fmt" - "io" - "os" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/grafana/river/diag" - "github.com/grafana/river/parser" - "github.com/grafana/river/printer" - "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" -) - -// Test_FormatAgentRiverConfig tests that the river config generated by helm is formatted correctly -func Test_FormatAgentRiverConfig(t *testing.T) { - fdata, err := os.Open("helm/pyroscope/rendered/single-binary.yaml") - require.NoError(t, err) - defer fdata.Close() - - values := map[string]interface{}{} - configString := `` - dec := yaml.NewDecoder(fdata) - for dec.Decode(&values) == nil { - if values["metadata"].(map[string]interface{})["name"] == "grafana-agent-config-pyroscope" { - configString = values["data"].(map[string]interface{})["config.river"].(string) - break - } - } - fileName := fmt.Sprintf("%s/config.river", t.TempDir()) - require.NoError(t, os.WriteFile(fileName, []byte(configString), 0o644)) - fi, err := os.Stat(fileName) - require.NoError(t, err) - f, err := os.Open(fileName) - require.NoError(t, err) - defer f.Close() - - err = format(fileName, fi, f, true) - var diags diag.Diagnostics - if errors.As(err, &diags) { - for _, diag := range diags { - fmt.Fprintln(os.Stderr, diag) - } - t.Error("encountered errors during formatting") - } - fmtData, err := os.ReadFile(fileName) - require.NoError(t, err) - if diff := cmp.Diff(string(fmtData), configString); diff != "" { - t.Errorf("Grafana Agent Helm River config file is not formatted mismatch (-want +got):\n%s", diff) - t.Log("You need to fixes formatting issues in operations/pyroscope/helm/pyroscope/templates/configmap-agent.yaml and run make helm/check.") - } -} - -func format(filename string, fi os.FileInfo, r io.Reader, write bool) error { - bb, err := io.ReadAll(r) - if err != nil { - return err - } - - f, err := parser.ParseFile(filename, bb) - if err != nil { - return err - } - - var buf bytes.Buffer - if err := printer.Fprint(&buf, f); err != nil { - return err - } - - // Add a newline at the end of the file. - _, _ = buf.Write([]byte{'\n'}) - - if !write { - _, err := io.Copy(os.Stdout, &buf) - return err - } - - wf, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, fi.Mode().Perm()) - if err != nil { - return err - } - defer wf.Close() - - _, err = io.Copy(wf, &buf) - return err -} diff --git a/package.json b/package.json deleted file mode 100644 index 4d4d34f943..0000000000 --- a/package.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "name": "grafana-pyroscope", - "version": "2.0.0", - "repository": "git@github.com:grafana/pyroscope.git", - "author": "Grafana Labs", - "license": "AGPL-3.0-only", - "private": true, - "scripts": { - "test": "jest", - "type-check": "tsc -p tsconfig.json --noEmit", - "build": "NODE_ENV=production webpack --progress --config scripts/webpack/webpack.prod.js", - "dev": "NODE_ENV=development webpack serve --progress --color --config scripts/webpack/webpack.dev.js", - "backend:dev": "make build run 'PARAMS=--config.file ./cmd/pyroscope/pyroscope.yaml'", - "cy": "cypress", - "lint": "eslint . --ext .js,.tsx,.ts --cache", - "lint:fix": "yarn lint --fix", - "format": "prettier --check .", - "format:fix": "prettier --write .", - "storybook": "start-storybook -p 6006", - "build-storybook": "build-storybook", - "prepare:manually": "husky install" - }, - "lint-staged": { - "*.{ts,tsx,scss}": "yarn format:fix" - }, - "devDependencies": { - "@babel/core": "^7.22.9", - "@emotion/react": "^11.10.6", - "@emotion/styled": "^11.10.6", - "@fortawesome/fontawesome-common-types": "~0.2.36", - "@grafana/eslint-config": "^5.1.0", - "@size-limit/file": "^6.0.3", - "@size-limit/time": "^6.0.3", - "@storybook/addon-actions": "~6.5.0", - "@storybook/addon-essentials": "~6.5.0", - "@storybook/addon-links": "~6.5.0", - "@storybook/builder-webpack5": "~6.5.0", - "@storybook/manager-webpack5": "~6.5.0", - "@storybook/react": "~6.5.0", - "@swc/core": "^1.3.74", - "@swc/jest": "^0.2.27", - "@testing-library/cypress": "^9.0.0", - "@testing-library/dom": "^9.3.1", - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^14.0.0", - "@testing-library/react-hooks": "^8.0.1", - "@testing-library/user-event": "^13.2.1", - "@types/color": "^3.0.2", - "@types/d3-scale": "^4.0.2", - "@types/d3-scale-chromatic": "^3.0.0", - "@types/flot": "^0.0.32", - "@types/history": "4.7.11", - "@types/jest": "^29.5.0", - "@types/jest-image-snapshot": "^4.3.1", - "@types/jquery": "^3.5.13", - "@types/lodash.debounce": "^4.0.6", - "@types/lodash.groupby": "^4.6.7", - "@types/lodash.map": "^4.6.13", - "@types/mocha": "^10.0.1", - "@types/prismjs": "^1.26.0", - "@types/react": "^18.0.0", - "@types/react-copy-to-clipboard": "^5.0.2", - "@types/react-datepicker": "^4.3.4", - "@types/react-dom": "^18.0.11", - "@types/react-helmet": "^6.1.5", - "@types/react-notifications-component": "~3.1.0", - "@types/react-outside-click-handler": "^1.3.1", - "@types/react-router-dom": "5.3.0", - "@types/testing-library__jest-dom": "^5.14.9", - "@typescript-eslint/eslint-plugin": "^5.59.5", - "@typescript-eslint/parser": "^5.59.5", - "canvas": "^2.8.0", - "canvas-to-buffer": "^1.1.1", - "clean-webpack-plugin": "^3.0.0", - "contributor-faces": "^1.1.0", - "conventional-changelog-cli": "^2.1.1", - "copy-webpack-plugin": "^11.0.0", - "cypress": "^12.11.0", - "cypress-image-snapshot": "^4.0.1", - "esbuild-loader": "^3.0.1", - "eslint": "^8.40.0", - "eslint-config-airbnb": "18.2.1", - "eslint-config-airbnb-typescript": "^14.0.0", - "eslint-config-airbnb-typescript-prettier": "^4.2.0", - "eslint-import-resolver-lerna": "^2.0.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-css-modules": "^2.11.0", - "eslint-plugin-cypress": "^2.12.1", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jest": "^25.3.4", - "eslint-plugin-jsdoc": "^44.2.2", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-prettier": "^3.3.1", - "eslint-plugin-react": "^7.33.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-unused-imports": "^2.0.0", - "expose-loader": "^4.1.0", - "html-webpack-plugin": "^5.5.0", - "husky": "^8.0.3", - "jest": "^27.5.1", - "jest-canvas-mock": "^2.3.1", - "jest-css-modules-transform": "^4.4.2", - "jest-environment-jsdom": "^27.5.1", - "jest-fetch-mock": "^3.0.3", - "lint-staged": "^15.0.2", - "mini-css-extract-plugin": "^2.7.5", - "msw": "^0.36.3", - "optimize-css-assets-webpack-plugin": "^6.0.1", - "prettier": "2.8.8", - "react-svg-loader": "^3.0.3", - "regenerator-runtime": "^0.13.9", - "replace-in-file-webpack-plugin": "^1.0.6", - "sass": "^1.60.0", - "size-limit": "^6.0.3", - "ts-jest": "^29.1.0", - "tsconfig-paths-webpack-plugin": "^4.0.1", - "typescript": "^4.5.2", - "typescript-plugin-css-modules": "^3.4.0", - "web-streams-polyfill": "^3.2.1", - "webpack": "^5.77.0", - "webpack-bundle-analyzer": "^4.4.2", - "webpack-cli": "^5.0.1", - "webpack-dev-server": "^4.13.1", - "webpack-livereload-plugin": "^3.0.2", - "webpack-merge": "^5.8.0" - }, - "dependencies": { - "@fortawesome/fontawesome-svg-core": "~1.2.30", - "@fortawesome/free-brands-svg-icons": "~5.15.1", - "@fortawesome/free-regular-svg-icons": "~5.15.2", - "@fortawesome/free-solid-svg-icons": "~5.14.0", - "@fortawesome/react-fontawesome": "~0.1.11", - "@grafana/data": "10.3.0-147665", - "@grafana/flamegraph": "10.3.0-147665", - "@grafana/ui": "10.3.0-147665", - "@hookform/resolvers": "^2.9.8", - "@mui/base": "5.0.0-alpha.98", - "@mui/material": "5.10.11", - "@mui/types": "7.2.0", - "@react-hook/resize-observer": "^1.2.6", - "@react-hook/window-size": "^3.1.1", - "@reduxjs/toolkit": "^1.6.2", - "@szhsin/react-menu": "3.5.2", - "@types/file-saver": "^2.0.5", - "color": "^3.1.3", - "compression-streams-polyfill": "^0.1.4", - "css-loader": "^4.0.0", - "d3": "^7.3.0", - "d3-scale": "^4.0.2", - "d3-scale-chromatic": "^3.0.0", - "file-saver": "^2.0.5", - "jquery": "^3.6.4", - "jquery.flot.tooltip": "^0.9.0", - "lodash.groupby": "^4.6.0", - "lodash.map": "^4.6.0", - "prismjs": "^1.27.0", - "protobufjs": "^7.2.5", - "react": "^18.2.0", - "react-copy-to-clipboard": "^5.0.4", - "react-datepicker": "^4.7.0", - "react-debounce-input": "^3.2.5", - "react-dom": "^18.2.0", - "react-dropzone": "^11.4.2", - "react-flatten-children": "^1.1.2", - "react-flot": "^1.3.0", - "react-helmet": "^6.1.0", - "react-hook-form": "^7.36.0", - "react-notifications-component": "~3.1.0", - "react-outside-click-handler": "^1.3.0", - "react-pro-sidebar": "^0.7.1", - "react-redux": "^7.2.1", - "react-router-dom": "5.3.0", - "react-svg-spinner": "^1.0.4", - "react-textarea-autosize": "8.3.0", - "redux-persist": "^6.0.0", - "redux-query-sync": "^0.1.10", - "sass-loader": "^9.0.2", - "sweetalert2": "^11.4.0, <11.4.9", - "sweetalert2-react-content": "^4.2.0", - "timezone-mock": "^1.3.0", - "true-myth": "~5.2.0", - "ts-custom-error": "^3.2.0", - "ts-essentials": "^9.0.0", - "zod": "^3.22.3" - }, - "optionalDependencies": { - "@pyroscope/nodejs": "^0.2.9" - }, - "resolutions": { - "jquery": "^3.6.4", - "braces": ">2.3.1", - "glob-parent": ">5.1.2", - "got": ">12.1.0", - "json5": ">2.2.2", - "loader-utils": "^1.4.1", - "mem": ">4.0.0", - "nth-check": "^2.0.1", - "postcss": ">8.2.13", - "tough-cookie": "^4.1.3", - "semver": "^7.5.2", - "trim": ">0.0.3", - "trim-newlines": ">4.0.1", - "yargs-parser": ">18.1.1" - } -} diff --git a/pkg/adhocprofiles/adhocprofiles.go b/pkg/adhocprofiles/adhocprofiles.go index d947940f36..361e0b0259 100644 --- a/pkg/adhocprofiles/adhocprofiles.go +++ b/pkg/adhocprofiles/adhocprofiles.go @@ -6,42 +6,82 @@ import ( "crypto/rand" "encoding/base64" "encoding/json" + "errors" + "fmt" "io" "slices" "strings" "time" "connectrpc.com/connect" + "github.com/dustin/go-humanize" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/services" "github.com/grafana/dskit/tenant" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" + "golang.org/x/sync/errgroup" v1 "github.com/grafana/pyroscope/api/gen/proto/go/adhocprofiles/v1" - "github.com/grafana/pyroscope/pkg/frontend" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer/convert" - "github.com/grafana/pyroscope/pkg/validation" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer/convert" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/validation" ) type AdHocProfiles struct { services.Service logger log.Logger - limits frontend.Limits + limits Limits bucket objstore.Bucket } +type Limits interface { + validation.FlameGraphLimits + MaxProfileSizeBytes(tenantID string) int +} + type AdHocProfile struct { Name string `json:"name"` Data string `json:"data"` UploadedAt time.Time `json:"uploadedAt"` } -func NewAdHocProfiles(bucket objstore.Bucket, logger log.Logger, limits frontend.Limits) *AdHocProfiles { +func validRunes(r rune) bool { + if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' || r == '.' || r == '-' || r == '_' { + return true + } + return false +} + +// check if the id is valid +func validID(id string) bool { + if len(id) == 0 { + return false + } + for _, r := range id { + if !validRunes(r) { + return false + } + } + return true +} + +// replaces invalid runes in the id with underscores +func replaceInvalidRunes(id string) string { + return strings.Map(func(r rune) rune { + if validRunes(r) { + return r + } + return '_' + }, id) +} + +func NewAdHocProfiles(bucket objstore.Bucket, logger log.Logger, limits Limits) *AdHocProfiles { a := &AdHocProfiles{ logger: logger, bucket: bucket, @@ -68,16 +108,26 @@ func (a *AdHocProfiles) Upload(ctx context.Context, c *connect.Request[v1.AdHocP UploadedAt: time.Now().UTC(), } - // TODO: Add per-tenant upload limits (number of files, total size, etc.) + // replace runes outside of [a-zA-Z0-9_-.] with underscores + adHocProfile.Name = replaceInvalidRunes(adHocProfile.Name) - maxNodes, err := validation.ValidateMaxNodes(a.limits, []string{tenantID}, c.Msg.GetMaxNodes()) + limits, err := a.newConvertLimits(tenantID, c.Msg.GetMaxNodes()) if err != nil { - return nil, errors.Wrapf(err, "could not determine max nodes") + return nil, err } - profile, profileTypes, err := parse(&adHocProfile, nil, maxNodes) + // TODO: Add more per-tenant upload limits (number of files, total size, etc.) + if limits.MaxProfileSizeBytes > 0 && len(adHocProfile.Data) > limits.MaxProfileSizeBytes { + return nil, connect.NewError(connect.CodeInvalidArgument, validation.NewErrorf(validation.ProfileSizeLimit, "profile payload size exceeds limit of %s", humanize.Bytes(uint64(limits.MaxProfileSizeBytes)))) + } + + profile, profileTypes, err := parse(&adHocProfile, nil, limits) if err != nil { - return nil, errors.Wrapf(err, "failed to parse profile") + dsErr := new(pprof.ErrDecompressedSizeExceedsLimit) + if errors.As(err, &dsErr) { + return nil, connect.NewError(connect.CodeInvalidArgument, validation.NewErrorf(validation.ProfileSizeLimit, "uncompressed profile payload size exceeds limit of %s", humanize.Bytes(uint64(dsErr.Limit)))) + } + return nil, fmt.Errorf("failed to parse profile: %w", err) } bucket := a.getBucket(tenantID) @@ -87,17 +137,17 @@ func (a *AdHocProfiles) Upload(ctx context.Context, c *connect.Request[v1.AdHocP dataToStore, err := json.Marshal(adHocProfile) if err != nil { - return nil, errors.Wrapf(err, "failed to upload profile") + return nil, fmt.Errorf("failed to upload profile: %w", err) } err = bucket.Upload(ctx, id, bytes.NewReader(dataToStore)) if err != nil { - return nil, errors.Wrapf(err, "failed to upload profile") + return nil, fmt.Errorf("failed to upload profile: %w", err) } jsonProfile, err := json.Marshal(profile) if err != nil { - return nil, errors.Wrapf(err, "failed to parse profile") + return nil, fmt.Errorf("failed to parse profile: %w", err) } return connect.NewResponse(&v1.AdHocProfilesGetResponse{ @@ -110,6 +160,18 @@ func (a *AdHocProfiles) Upload(ctx context.Context, c *connect.Request[v1.AdHocP }), nil } +func (a *AdHocProfiles) newConvertLimits(tenantID string, msgMaxNodes int64) (convert.Limits, error) { + maxNodes, err := validation.ValidateMaxNodes(a.limits, []string{tenantID}, msgMaxNodes) + if err != nil { + return convert.Limits{}, fmt.Errorf("could not determine max nodes: %w", err) + } + + return convert.Limits{ + MaxNodes: int(maxNodes), + MaxProfileSizeBytes: a.limits.MaxProfileSizeBytes(tenantID), + }, nil +} + func (a *AdHocProfiles) Get(ctx context.Context, c *connect.Request[v1.AdHocProfilesGetRequest]) (*connect.Response[v1.AdHocProfilesGetResponse], error) { tenantID, err := tenant.TenantID(ctx) if err != nil { @@ -118,35 +180,32 @@ func (a *AdHocProfiles) Get(ctx context.Context, c *connect.Request[v1.AdHocProf bucket := a.getBucket(tenantID) - reader, err := bucket.Get(ctx, c.Msg.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "failed to get profile") + id := c.Msg.GetId() + if !validID(id) { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("id '%s' is invalid: can only contain [a-zA-Z0-9_-.]", id)) } - adHocProfileBytes, err := io.ReadAll(reader) + adHocProfile, err := fetchProfile(ctx, bucket, id) if err != nil { - return nil, err + if objstore.IsNotExist(bucket, err) { + return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("profile %s not found", id)) + } + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to get profile: %w", err)) } - var adHocProfile AdHocProfile - err = json.Unmarshal(adHocProfileBytes, &adHocProfile) + limits, err := a.newConvertLimits(tenantID, c.Msg.GetMaxNodes()) if err != nil { return nil, err } - maxNodes, err := validation.ValidateMaxNodes(a.limits, []string{tenantID}, c.Msg.GetMaxNodes()) + profile, profileTypes, err := parse(adHocProfile, c.Msg.ProfileType, limits) if err != nil { - return nil, errors.Wrapf(err, "could not determine max nodes") - } - - profile, profileTypes, err := parse(&adHocProfile, c.Msg.ProfileType, maxNodes) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse profile") + return nil, fmt.Errorf("failed to parse profile: %w", err) } jsonProfile, err := json.Marshal(profile) if err != nil { - return nil, errors.Wrapf(err, "failed to parse profile") + return nil, fmt.Errorf("failed to parse profile: %w", err) } return connect.NewResponse(&v1.AdHocProfilesGetResponse{ @@ -167,6 +226,11 @@ func (a *AdHocProfiles) List(ctx context.Context, c *connect.Request[v1.AdHocPro profiles := make([]*v1.AdHocProfilesProfileMetadata, 0) err = bucket.Iter(ctx, "", func(s string) error { + // do not list elements with invalid ids + if !validID(s) { + return nil + } + separatorIndex := strings.IndexRune(s, '-') id, err := ulid.Parse(s[0:separatorIndex]) if err != nil { @@ -209,10 +273,172 @@ func (a *AdHocProfiles) getBucket(tenantID string) objstore.Bucket { return objstore.NewPrefixedBucket(a.bucket, tenantID+"/adhoc") } -func parse(p *AdHocProfile, profileType *string, maxNodes int64) (fg *flamebearer.FlamebearerProfile, profileTypes []string, err error) { +func (a *AdHocProfiles) Diff(ctx context.Context, c *connect.Request[v1.AdHocProfilesDiffRequest]) (*connect.Response[v1.AdHocProfilesDiffResponse], error) { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + bucket := a.getBucket(tenantID) + + leftID := c.Msg.GetLeftId() + rightID := c.Msg.GetRightId() + for _, id := range []string{leftID, rightID} { + if !validID(id) { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("id '%s' is invalid: can only contain [a-zA-Z0-9_-.]", id)) + } + } + + limits, err := a.newConvertLimits(tenantID, c.Msg.GetMaxNodes()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + var leftProfile, rightProfile AdHocProfile + var leftFetchErr, rightFetchErr error + g, gctx := errgroup.WithContext(ctx) + g.Go(func() error { + p, err := fetchProfile(gctx, bucket, leftID) + if err != nil { + leftFetchErr = err + return err + } + leftProfile = *p + return nil + }) + g.Go(func() error { + p, err := fetchProfile(gctx, bucket, rightID) + if err != nil { + rightFetchErr = err + return err + } + rightProfile = *p + return nil + }) + if err := g.Wait(); err != nil { + if leftFetchErr != nil { + if objstore.IsNotExist(bucket, leftFetchErr) { + return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("left profile %s not found", leftID)) + } + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to fetch left profile: %w", leftFetchErr)) + } + if rightFetchErr != nil { + if objstore.IsNotExist(bucket, rightFetchErr) { + return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("right profile %s not found", rightID)) + } + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to fetch right profile: %w", rightFetchErr)) + } + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to fetch profiles: %w", err)) + } + + leftFB, leftTypes, err := parse(&leftProfile, c.Msg.ProfileType, limits) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("failed to parse left profile: %w", err)) + } + rightFB, rightTypes, err := parse(&rightProfile, c.Msg.ProfileType, limits) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("failed to parse right profile: %w", err)) + } + + // Compute intersection of profile types. + rightSet := make(map[string]struct{}, len(rightTypes)) + for _, pt := range rightTypes { + rightSet[pt] = struct{}{} + } + var commonTypes []string + for _, pt := range leftTypes { + if _, ok := rightSet[pt]; ok { + commonTypes = append(commonTypes, pt) + } + } + if len(commonTypes) == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("no common profile types between left (%v) and right (%v)", leftTypes, rightTypes)) + } + + // Ensure both profiles have the same selected type to avoid comparing mismatched profile types. + if leftFB.Metadata.Name != rightFB.Metadata.Name { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("profile type mismatch: left profile uses '%s', right profile uses '%s'; please specify a profile type from the common types: %v", leftFB.Metadata.Name, rightFB.Metadata.Name, commonTypes)) + } + + leftTree, err := flamebearerToModelTree(leftFB) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert left profile to tree: %w", err)) + } + rightTree, err := flamebearerToModelTree(rightFB) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to convert right profile to tree: %w", err)) + } + + diff, err := model.NewFlamegraphDiff(leftTree, rightTree, int64(limits.MaxNodes)) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to compute diff: %w", err)) + } + + profileType := &typesv1.ProfileType{ + Name: leftFB.Metadata.Name, + SampleType: leftFB.Metadata.Name, + SampleUnit: string(leftFB.Metadata.Units), + } + + diffFB := model.ExportDiffToFlamebearer(diff, profileType) + jsonProfile, err := json.Marshal(diffFB) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to marshal diff profile: %w", err)) + } + + return connect.NewResponse(&v1.AdHocProfilesDiffResponse{ + ProfileTypes: commonTypes, + FlamebearerProfile: string(jsonProfile), + }), nil +} + +func fetchProfile(ctx context.Context, bucket objstore.Bucket, id string) (*AdHocProfile, error) { + reader, err := bucket.Get(ctx, id) + if err != nil { + return nil, fmt.Errorf("failed to get profile %s: %w", id, err) + } + defer func() { + _ = reader.Close() + }() + + data, err := io.ReadAll(reader) + if err != nil { + return nil, err + } + + var p AdHocProfile + if err := json.Unmarshal(data, &p); err != nil { + return nil, err + } + return &p, nil +} + +// flamebearerToModelTree converts a FlamebearerProfile (format: "single") to a *model.FunctionNameTree +// suitable for use with model.NewFlamegraphDiff. +func flamebearerToModelTree(fb *flamebearer.FlamebearerProfile) (*model.FunctionNameTree, error) { + ogTree, err := flamebearer.ProfileToTree(*fb) + if err != nil { + return nil, err + } + + t := new(model.FunctionNameTree) + ogTree.IterateStacks(func(_ string, self uint64, stack []string) { + // IterateStacks yields stacks in leaf-to-root order; + // model.Tree.InsertStack expects root-to-leaf. + slices.Reverse(stack) + names := make([]model.FunctionName, len(stack)) + for i, s := range stack { + names[i] = model.FunctionName(s) + } + t.InsertStack(int64(self), names...) + }) + return t, nil +} + +func parse(p *AdHocProfile, profileType *string, limits convert.Limits) (fg *flamebearer.FlamebearerProfile, profileTypes []string, err error) { base64decoded, err := base64.StdEncoding.DecodeString(p.Data) if err != nil { - return nil, nil, errors.Wrapf(err, "failed to upload profile") + return nil, nil, fmt.Errorf("failed to upload profile: %w", err) } f := convert.ProfileFile{ @@ -221,12 +447,12 @@ func parse(p *AdHocProfile, profileType *string, maxNodes int64) (fg *flamebeare Data: base64decoded, } - profiles, err := convert.FlamebearerFromFile(f, int(maxNodes)) + profiles, err := convert.FlamebearerFromFile(f, limits) if err != nil { return nil, nil, err } if len(profiles) == 0 { - return nil, nil, errors.Wrapf(err, "no profiles found after parsing") + return nil, nil, fmt.Errorf("no profiles found after parsing") } profileTypes = make([]string, 0) diff --git a/pkg/adhocprofiles/adhocprofiles_test.go b/pkg/adhocprofiles/adhocprofiles_test.go index d8f47a8559..e0c80434a5 100644 --- a/pkg/adhocprofiles/adhocprofiles_test.go +++ b/pkg/adhocprofiles/adhocprofiles_test.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "encoding/json" "os" + "strings" "testing" "connectrpc.com/connect" @@ -13,10 +14,10 @@ import ( thanosobjstore "github.com/thanos-io/objstore" v1 "github.com/grafana/pyroscope/api/gen/proto/go/adhocprofiles/v1" - phlareobjstore "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/validation" + phlareobjstore "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/validation" ) func TestAdHocProfiles_Get(t *testing.T) { @@ -115,7 +116,102 @@ func TestAdHocProfiles_List(t *testing.T) { require.Equal(t, connect.NewResponse(&v1.AdHocProfilesListResponse{Profiles: expected}), response) } +func TestAdHocProfiles_Diff(t *testing.T) { + bucket := phlareobjstore.NewBucket(thanosobjstore.NewInMemBucket()) + rawProfile, err := os.ReadFile("testdata/cpu.pprof") + require.NoError(t, err) + encodedProfile := base64.StdEncoding.EncodeToString(rawProfile) + + leftProfile := &AdHocProfile{Name: "left.pprof", Data: encodedProfile} + rightProfile := &AdHocProfile{Name: "right.pprof", Data: encodedProfile} + leftJSON, _ := json.Marshal(leftProfile) + rightJSON, _ := json.Marshal(rightProfile) + _ = bucket.Upload(context.Background(), "tenant/adhoc/left-profile", bytes.NewReader(leftJSON)) + _ = bucket.Upload(context.Background(), "tenant/adhoc/right-profile", bytes.NewReader(rightJSON)) + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + a := &AdHocProfiles{ + logger: util.Logger, + limits: validation.MockLimits{MaxFlameGraphNodesDefaultValue: 8192}, + bucket: bucket, + } + + t.Run("reject requests with missing tenant id", func(t *testing.T) { + _, err := a.Diff(context.Background(), connect.NewRequest(&v1.AdHocProfilesDiffRequest{ + LeftId: "left-profile", + RightId: "right-profile", + })) + require.Error(t, err) + }) + + t.Run("return error for invalid left id", func(t *testing.T) { + _, err := a.Diff(ctx, connect.NewRequest(&v1.AdHocProfilesDiffRequest{ + LeftId: "../../etc/passwd", + RightId: "right-profile", + })) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid") + }) + + t.Run("return error for non-existing profile", func(t *testing.T) { + _, err := a.Diff(ctx, connect.NewRequest(&v1.AdHocProfilesDiffRequest{ + LeftId: "non-existing-id", + RightId: "right-profile", + })) + require.Error(t, err) + require.Contains(t, err.Error(), "not found") + }) + + t.Run("return diff for valid profiles", func(t *testing.T) { + resp, err := a.Diff(ctx, connect.NewRequest(&v1.AdHocProfilesDiffRequest{ + LeftId: "left-profile", + RightId: "right-profile", + })) + require.NoError(t, err) + require.NotEmpty(t, resp.Msg.ProfileTypes) + require.NotEmpty(t, resp.Msg.FlamebearerProfile) + + var fb map[string]interface{} + require.NoError(t, json.Unmarshal([]byte(resp.Msg.FlamebearerProfile), &fb)) + metadata := fb["metadata"].(map[string]interface{}) + require.Equal(t, "double", metadata["format"]) + }) + + t.Run("return diff with explicit profile type", func(t *testing.T) { + // First, find available profile types. + getResp, err := a.Get(ctx, connect.NewRequest(&v1.AdHocProfilesGetRequest{Id: "left-profile"})) + require.NoError(t, err) + require.NotEmpty(t, getResp.Msg.ProfileTypes) + + pt := getResp.Msg.ProfileTypes[0] + resp, err := a.Diff(ctx, connect.NewRequest(&v1.AdHocProfilesDiffRequest{ + LeftId: "left-profile", + RightId: "right-profile", + ProfileType: &pt, + })) + require.NoError(t, err) + require.NotEmpty(t, resp.Msg.FlamebearerProfile) + + var fb map[string]interface{} + require.NoError(t, json.Unmarshal([]byte(resp.Msg.FlamebearerProfile), &fb)) + metadata := fb["metadata"].(map[string]interface{}) + require.Equal(t, "double", metadata["format"]) + }) +} + func TestAdHocProfiles_Upload(t *testing.T) { + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + defaults.MaxFlameGraphNodesDefault = 8192 + + l := validation.MockDefaultLimits() + l.MaxProfileSizeBytes = 16 + tenantLimits["tenant-16-bytes-limit"] = l + + l = validation.MockDefaultLimits() + l.MaxProfileSizeBytes = 1600 + tenantLimits["tenant-1600-bytes-limit"] = l + }) + bucket := phlareobjstore.NewBucket(thanosobjstore.NewInMemBucket()) rawProfile, err := os.ReadFile("testdata/cpu.pprof") require.NoError(t, err) @@ -125,9 +221,10 @@ func TestAdHocProfiles_Upload(t *testing.T) { c *connect.Request[v1.AdHocProfilesUploadRequest] } tests := []struct { - name string - args args - wantErr bool + name string + args args + wantErr string + expectedSuffix string }{ { name: "reject requests with missing tenant id", @@ -135,7 +232,7 @@ func TestAdHocProfiles_Upload(t *testing.T) { ctx: context.Background(), c: nil, }, - wantErr: true, + wantErr: "no org id", }, { name: "should reject an invalid profile", @@ -146,31 +243,78 @@ func TestAdHocProfiles_Upload(t *testing.T) { Profile: "123", }), }, - wantErr: true, + wantErr: "failed to parse profile", }, { name: "should store a valid profile", args: args{ ctx: tenant.InjectTenantID(context.Background(), "tenant"), c: connect.NewRequest(&v1.AdHocProfilesUploadRequest{ - Name: "test", + Name: "test.cpu.pb.gz", Profile: encodedProfile, }), }, - wantErr: false, + expectedSuffix: "-test.cpu.pb.gz", + }, + { + name: "should limit profile names to particular character set", + args: args{ + ctx: tenant.InjectTenantID(context.Background(), "tenant"), + c: connect.NewRequest(&v1.AdHocProfilesUploadRequest{ + Name: "test/../../../etc/passwd", + Profile: encodedProfile, + }), + }, + expectedSuffix: "-test_.._.._.._etc_passwd", + }, + { + name: "should enforce profile size", + args: args{ + ctx: tenant.InjectTenantID(context.Background(), "tenant-16-bytes-limit"), + c: connect.NewRequest(&v1.AdHocProfilesUploadRequest{ + Name: "compressed-too-big", + Profile: encodedProfile, + }), + }, + wantErr: "invalid_argument: profile payload size exceeds limit of 16 B", + }, + { + name: "should enforce profile size limit after decompression", + args: args{ + // 1580 is the profile size compressed + ctx: tenant.InjectTenantID(context.Background(), "tenant-1600-bytes-limit"), + c: connect.NewRequest(&v1.AdHocProfilesUploadRequest{ + Name: "decompressed-too-big", + Profile: encodedProfile, + }), + }, + wantErr: "invalid_argument: uncompressed profile payload size exceeds limit of 1.6 kB", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { a := &AdHocProfiles{ logger: util.Logger, - limits: validation.MockLimits{MaxFlameGraphNodesDefaultValue: 8192}, + limits: overrides, bucket: bucket, } _, err := a.Upload(tt.args.ctx, tt.args.c) - if (err != nil) != tt.wantErr { - t.Errorf("Upload() error = %v, wantErr %v", err, tt.wantErr) - return + if tt.wantErr == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tt.wantErr) + } + + if tt.expectedSuffix != "" { + found := false + err := bucket.Iter(tt.args.ctx, "tenant/adhoc", func(name string) error { + if strings.HasSuffix(name, tt.expectedSuffix) { + found = true + } + return nil + }) + require.NoError(t, err) + require.True(t, found) } }) } diff --git a/pkg/api/admin_server_test.go b/pkg/api/admin_server_test.go new file mode 100644 index 0000000000..c41d208ad6 --- /dev/null +++ b/pkg/api/admin_server_test.go @@ -0,0 +1,118 @@ +package api + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-kit/log" + "github.com/gorilla/mux" + "github.com/grafana/dskit/server" + grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// newTestAPI builds a minimal API wired to a gorilla mux, mirroring the pattern +// used in distributor_api_test.go. +func newTestAPIWithMode(t *testing.T, mode AdminServerMode) (*API, *mux.Router, *mux.Router) { + t.Helper() + + mainMux := mux.NewRouter() + serv := &server.Server{HTTP: mainMux} + + a, err := New(Config{}, serv, grpcgw.NewServeMux(), log.NewNopLogger()) + require.NoError(t, err) + + adminRouter := mux.NewRouter() + a.SetAdminRouter(adminRouter, mode) + + return a, mainMux, adminRouter +} + +// probe sends a GET to the given router and returns the status code. +func probe(t *testing.T, router http.Handler, path string) int { + t.Helper() + req := httptest.NewRequest(http.MethodGet, path, nil) + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + return rec.Code +} + +func TestRegisterInternalRoute_Disabled(t *testing.T) { + a, mainMux, adminRouter := newTestAPIWithMode(t, AdminServerDisabled) + + sentinel := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTeapot) + }) + a.registerAdminRoute("/test-route", sentinel, WithMethod("GET")) + + // Route must be reachable on the main mux. + assert.Equal(t, http.StatusTeapot, probe(t, mainMux, "/test-route")) + // Route must NOT be reachable on the internal router. + assert.Equal(t, http.StatusNotFound, probe(t, adminRouter, "/test-route")) +} + +func TestRegisterInternalRoute_Exclusive(t *testing.T) { + a, mainMux, adminRouter := newTestAPIWithMode(t, AdminServerExclusive) + + sentinel := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTeapot) + }) + a.registerAdminRoute("/test-route", sentinel, WithMethod("GET")) + + // Route must NOT be on the main mux. + assert.Equal(t, http.StatusNotFound, probe(t, mainMux, "/test-route")) + // Route must be reachable on the internal router. + assert.Equal(t, http.StatusTeapot, probe(t, adminRouter, "/test-route")) +} + +func TestRegisterInternalRoute_Additional(t *testing.T) { + a, mainMux, adminRouter := newTestAPIWithMode(t, AdminServerAdditional) + + sentinel := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTeapot) + }) + a.registerAdminRoute("/test-route", sentinel, WithMethod("GET")) + + // Route must be reachable on both muxes. + assert.Equal(t, http.StatusTeapot, probe(t, mainMux, "/test-route")) + assert.Equal(t, http.StatusTeapot, probe(t, adminRouter, "/test-route")) +} + +func TestRegisterInternalRoute_PathParameters(t *testing.T) { + // Verify that gorilla mux path parameters work correctly on the internal router + // (they would silently break with http.ServeMux). + a, _, adminRouter := newTestAPIWithMode(t, AdminServerExclusive) + + var capturedTenant string + a.registerAdminRoute("/ops/tenants/{tenant}/blocks", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + capturedTenant = mux.Vars(r)["tenant"] + w.WriteHeader(http.StatusOK) + }), WithMethod("GET")) + + req := httptest.NewRequest(http.MethodGet, "/ops/tenants/acme/blocks", nil) + rec := httptest.NewRecorder() + adminRouter.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, "acme", capturedTenant) +} + +func TestSetAdminRouter_NilSafe(t *testing.T) { + // When no internal router is set, registerAdminRoute should fall back to + // the main mux without panicking. + mainMux := mux.NewRouter() + serv := &server.Server{HTTP: mainMux} + a, err := New(Config{}, serv, grpcgw.NewServeMux(), log.NewNopLogger()) + require.NoError(t, err) + // adminRouter is nil, mode is "" (zero value = disabled path) + + sentinel := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTeapot) + }) + require.NotPanics(t, func() { + a.registerAdminRoute("/nil-safe-route", sentinel, WithMethod("GET")) + }) + assert.Equal(t, http.StatusTeapot, probe(t, mainMux, "/nil-safe-route")) +} diff --git a/pkg/api/api.go b/pkg/api/api.go index aa48d1f545..603ce0fc17 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -10,21 +10,23 @@ import ( "flag" "fmt" "net/http" - "strings" "connectrpc.com/connect" "github.com/felixge/fgprof" "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/gorilla/mux" "github.com/grafana/dskit/kv/memberlist" "github.com/grafana/dskit/middleware" "github.com/grafana/dskit/server" grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grafana/pyroscope/public" + "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect" + "github.com/grafana/pyroscope/v2/ui" + + "github.com/grafana/pyroscope/v2/pkg/validation" "github.com/grafana/pyroscope/api/gen/proto/go/adhocprofiles/v1/adhocprofilesv1connect" + "github.com/grafana/pyroscope/api/gen/proto/go/capabilities/v1/capabilitiesv1connect" "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1/ingesterv1connect" "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" @@ -34,23 +36,20 @@ import ( "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1/vcsv1connect" "github.com/grafana/pyroscope/api/gen/proto/go/version/v1/versionv1connect" "github.com/grafana/pyroscope/api/openapiv2" - "github.com/grafana/pyroscope/pkg/adhocprofiles" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/compactor" - "github.com/grafana/pyroscope/pkg/distributor" - "github.com/grafana/pyroscope/pkg/frontend" - "github.com/grafana/pyroscope/pkg/frontend/frontendpb/frontendpbconnect" - "github.com/grafana/pyroscope/pkg/ingester" - "github.com/grafana/pyroscope/pkg/ingester/pyroscope" - "github.com/grafana/pyroscope/pkg/operations" - "github.com/grafana/pyroscope/pkg/querier" - "github.com/grafana/pyroscope/pkg/scheduler" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb/schedulerpbconnect" - "github.com/grafana/pyroscope/pkg/settings" - "github.com/grafana/pyroscope/pkg/storegateway" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/gziphandler" - "github.com/grafana/pyroscope/pkg/validation/exporter" + "github.com/grafana/pyroscope/v2/pkg/adhocprofiles" + "github.com/grafana/pyroscope/v2/pkg/compactor" + "github.com/grafana/pyroscope/v2/pkg/distributor" + "github.com/grafana/pyroscope/v2/pkg/frontend" + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb/frontendpbconnect" + "github.com/grafana/pyroscope/v2/pkg/ingester" + "github.com/grafana/pyroscope/v2/pkg/ingester/otlp" + "github.com/grafana/pyroscope/v2/pkg/ingester/pyroscope" + "github.com/grafana/pyroscope/v2/pkg/querier" + "github.com/grafana/pyroscope/v2/pkg/scheduler" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb/schedulerpbconnect" + "github.com/grafana/pyroscope/v2/pkg/settings" + "github.com/grafana/pyroscope/v2/pkg/storegateway" + "github.com/grafana/pyroscope/v2/pkg/validation/exporter" ) type Config struct { @@ -64,15 +63,32 @@ type API struct { server *server.Server httpAuthMiddleware middleware.Interface grpcGatewayMux *grpcgw.ServeMux - grpcAuthMiddleware connect.Option - grpcLogMiddleware connect.Option - recoveryMiddleware connect.Option - cfg Config - logger log.Logger + // adminRouter and adminMode together control where operational routes + // (metrics, debug, admin, rings, config) are registered. + adminRouter *mux.Router + adminMode AdminServerMode + + cfg Config + logger log.Logger + + // indexPage is the main server's /admin index (UI, swagger, build info). indexPage *IndexPageContent + // adminIndexPage is the admin server's /admin index (rings, metrics, ops, config). + // When the admin server is disabled, operational links fall back to indexPage. + adminIndexPage *IndexPageContent } +// AdminServerMode mirrors the type defined in the pyroscope package; redeclared +// here so the api package has no import cycle back to the parent package. +type AdminServerMode = string + +const ( + AdminServerDisabled AdminServerMode = "disabled" + AdminServerAdditional AdminServerMode = "additional" + AdminServerExclusive AdminServerMode = "exclusive" +) + func New(cfg Config, s *server.Server, grpcGatewayMux *grpcgw.ServeMux, logger log.Logger) (*API, error) { api := &API{ cfg: cfg, @@ -80,10 +96,8 @@ func New(cfg Config, s *server.Server, grpcGatewayMux *grpcgw.ServeMux, logger l server: s, logger: logger, indexPage: NewIndexPageContent(), + adminIndexPage: NewIndexPageContent(), grpcGatewayMux: grpcGatewayMux, - grpcAuthMiddleware: cfg.GrpcAuthMiddleware, - grpcLogMiddleware: connect.WithInterceptors(util.NewLogInterceptor(logger)), - recoveryMiddleware: connect.WithInterceptors(util.RecoveryInterceptor), } // If no authentication middleware is present in the config, use the default authentication middleware. @@ -94,78 +108,106 @@ func New(cfg Config, s *server.Server, grpcGatewayMux *grpcgw.ServeMux, logger l return api, nil } -// RegisterRoute registers a single route enforcing HTTP methods. A single -// route is expected to be specific about which HTTP methods are supported. -func (a *API) RegisterRoute(path string, handler http.Handler, auth, gzipEnabled bool, method string, methods ...string) { - methods = append([]string{method}, methods...) - level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "path", path, "auth", auth, "gzip", gzipEnabled) - a.newRoute(path, handler, false, auth, gzipEnabled, methods...) +// SetAdminRouter configures the admin router and mode for operational +// (metrics, debug, admin, ring, config) routes. +func (a *API) SetAdminRouter(r *mux.Router, mode AdminServerMode) { + a.adminRouter = r + a.adminMode = mode } -func (a *API) RegisterRoutesWithPrefix(prefix string, handler http.Handler, auth, gzipEnabled bool, methods ...string) { - level.Debug(a.logger).Log("msg", "api: registering route", "methods", strings.Join(methods, ","), "prefix", prefix, "auth", auth, "gzip", gzipEnabled) - a.newRoute(prefix, handler, true, auth, gzipEnabled, methods...) +// addOperationalLinks adds index-page links to the correct page(s) based on mode: +// - disabled: main server indexPage only. +// - additional: both indexPage and adminIndexPage (links visible on both ports). +// - exclusive: adminIndexPage only (links removed from main port). +func (a *API) addOperationalLinks(weight int, groupDesc string, links []IndexPageLink) { + switch a.adminMode { + case AdminServerExclusive: + a.adminIndexPage.AddLinks(weight, groupDesc, links) + case AdminServerAdditional: + a.indexPage.AddLinks(weight, groupDesc, links) + a.adminIndexPage.AddLinks(weight, groupDesc, links) + default: + a.indexPage.AddLinks(weight, groupDesc, links) + } } -//nolint:unparam -func (a *API) newRoute(path string, handler http.Handler, isPrefix, auth, gzip bool, methods ...string) (route *mux.Route) { - if auth { - handler = a.httpAuthMiddleware.Wrap(handler) - } - if gzip { - handler = gziphandler.GzipHandler(handler) - } - if isPrefix { - route = a.server.HTTP.PathPrefix(path) - } else { - route = a.server.HTTP.Path(path) +// registerAdminRoute registers a handler according to the current admin +// server mode: +// - disabled: register only on the main server (default behaviour). +// - additional: register on both the admin router and the main server. +// - exclusive: register only on the admin router. +func (a *API) registerAdminRoute(path string, handler http.Handler, registerOpts ...RegisterOption) { + switch a.adminMode { + case AdminServerExclusive: + registerRoute(a.logger, a.adminRouter, path, handler, registerOpts...) + case AdminServerAdditional: + registerRoute(a.logger, a.adminRouter, path, handler, registerOpts...) + registerRoute(a.logger, a.server.HTTP, path, handler, registerOpts...) + default: + registerRoute(a.logger, a.server.HTTP, path, handler, registerOpts...) } - if len(methods) > 0 { - route = route.Methods(methods...) - } - route = route.Handler(handler) +} - return route +// registerRoute registers an HTTP handler with the main HTTP server. +// +// Register Options allow to filter the HTTP methods and apply middlewares. +func (a *API) RegisterRoute(path string, handler http.Handler, registerOpts ...RegisterOption) { + registerRoute(a.logger, a.server.HTTP, path, handler, registerOpts...) } // RegisterAPI registers the standard endpoints associated with a running Pyroscope. func (a *API) RegisterAPI(statusService statusv1.StatusServiceServer) error { - // register admin page - a.RegisterRoute("/admin", indexHandler("", a.indexPage), false, true, "GET") - // expose openapiv2 definition + // /admin on the main server always shows the main index (UI, swagger, build info). + registerRoute(a.logger, a.server.HTTP, "/admin", indexHandler("", a.indexPage), a.registerOptionsPublicAccess()...) + // /admin on the admin server (when enabled) shows the operational index. + if a.adminRouter != nil && a.adminMode != AdminServerDisabled { + registerRoute(a.logger, a.adminRouter, "/admin", indexHandler("", a.adminIndexPage), a.registerOptionsPublicAccess()...) + } + // expose openapiv2 definition — main server only (linked from the main /admin page) openapiv2Handler, err := openapiv2.Handler() if err != nil { return fmt.Errorf("unable to initialize openapiv2 handler: %w", err) } - a.RegisterRoute("/api/swagger.json", openapiv2Handler, false, true, "GET") + a.RegisterRoute("/api/swagger.json", openapiv2Handler, a.registerOptionsPublicAccess()...) a.indexPage.AddLinks(openAPIDefinitionWeight, "OpenAPI definition", []IndexPageLink{ {Desc: "Swagger JSON", Path: "/api/swagger.json"}, }) - // register grpc-gateway api - a.RegisterRoutesWithPrefix("/api", a.grpcGatewayMux, false, true, "GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS") - // register fgprof - a.RegisterRoute("/debug/fgprof", fgprof.Handler(), false, true, "GET") - // register static assets - a.RegisterRoutesWithPrefix("/static/", http.FileServer(http.FS(staticFiles)), false, true, "GET") - // register ui - uiAssets, err := public.Assets() + // grpc-gateway (status/config) — on admin server when available + publicAccessPrefixAllMethods := []RegisterOption{WithGzipMiddleware(), WithPrefix()} + a.registerAdminRoute("/api", a.grpcGatewayMux, publicAccessPrefixAllMethods...) + // register fgprof — on internal server when available + a.registerAdminRoute("/debug/fgprof", fgprof.Handler(), a.registerOptionsPublicAccess()...) + // register ui assets + uiAssets, err := ui.Assets() if err != nil { return fmt.Errorf("unable to initialize the ui: %w", err) } + uiFileServer := http.FileServer(uiAssets) + + // Static assets and /assets are needed on the admin server too — + // query-diagnostics pages reference /static/ CSS and /assets/admin.{css,js}. + a.RegisterRoute("/static/", http.FileServer(http.FS(staticFiles)), a.registerOptionsPrefixPublicAccess()...) + a.RegisterRoute("/assets/", uiFileServer, a.registerOptionsPrefixPublicAccess()...) + if a.adminRouter != nil && a.adminMode != AdminServerDisabled { + registerRoute(a.logger, a.adminRouter, "/static/", http.FileServer(http.FS(staticFiles)), a.registerOptionsPrefixPublicAccess()...) + registerRoute(a.logger, a.adminRouter, "/assets/", uiFileServer, a.registerOptionsPrefixPublicAccess()...) + } // The UI used to be at /ui, but now it's at /. - a.RegisterRoutesWithPrefix("/ui", http.RedirectHandler("/", http.StatusFound), false, true, "GET") - // All assets are served as static files - a.RegisterRoutesWithPrefix("/assets/", http.FileServer(uiAssets), false, true, "GET") + a.RegisterRoute("/ui", http.RedirectHandler("/", http.StatusFound), a.registerOptionsPrefixPublicAccess()...) + // Remaining UI asset prefixes — main server only + a.RegisterRoute("/icons/", uiFileServer, a.registerOptionsPrefixPublicAccess()...) + // @grafana/flamegraph hardcodes /public/ prefix; strip it to resolve to build/ + a.RegisterRoute("/public/", http.StripPrefix("/public", uiFileServer), a.registerOptionsPrefixPublicAccess()...) // register status service providing config and buildinfo at grpc gateway if err := statusv1.RegisterStatusServiceHandlerServer(context.Background(), a.grpcGatewayMux, statusService); err != nil { return err } - a.indexPage.AddLinks(buildInfoWeight, "Build information", []IndexPageLink{ + a.addOperationalLinks(buildInfoWeight, "Build information", []IndexPageLink{ {Desc: "Build information", Path: "/api/v1/status/buildinfo"}, }) - a.indexPage.AddLinks(configWeight, "Current config", []IndexPageLink{ + a.addOperationalLinks(configWeight, "Current config", []IndexPageLink{ {Desc: "Including the default values", Path: "/api/v1/status/config"}, {Desc: "Only values that differ from the defaults", Path: "/api/v1/status/config/diff"}, {Desc: "Default values", Path: "/api/v1/status/config/default"}, @@ -173,13 +215,21 @@ func (a *API) RegisterAPI(statusService statusv1.StatusServiceServer) error { return nil } +func (a *API) RegisterRedirectToAdmin() { + a.registerAdminRoute("/", http.RedirectHandler("/admin", http.StatusFound), a.registerOptionsPublicAccess()...) +} + func (a *API) RegisterCatchAll() error { - uiIndexHandler, err := public.NewIndexHandler(a.cfg.BaseURL) + uiIndexHandler, err := ui.NewIndexHandler(a.cfg.BaseURL) if err != nil { return fmt.Errorf("unable to initialize the ui: %w", err) } - // Serve index to all other pages - a.RegisterRoutesWithPrefix("/", uiIndexHandler, false, true, "GET") + + // Serve index to known paths + // This should be kept in sync with routes in public/app/pages/routes.ts + for _, path := range []string{"/", "/explore", "/comparison", "/comparison-diff"} { + a.RegisterRoute(path, uiIndexHandler, a.registerOptionsPublicAccess()...) + } a.indexPage.AddLinks(defaultWeight, "User interface", []IndexPageLink{ {Desc: "User interface", Path: "/"}, @@ -190,70 +240,90 @@ func (a *API) RegisterCatchAll() error { // RegisterRuntimeConfig registers the endpoints associates with the runtime configuration func (a *API) RegisterRuntimeConfig(runtimeConfigHandler http.HandlerFunc, userLimitsHandler http.HandlerFunc) { - a.RegisterRoute("/runtime_config", runtimeConfigHandler, false, true, "GET") - a.RegisterRoute("/api/v1/tenant_limits", userLimitsHandler, true, true, "GET") - a.indexPage.AddLinks(runtimeConfigWeight, "Current runtime config", []IndexPageLink{ + a.registerAdminRoute("/runtime_config", runtimeConfigHandler, a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/api/v1/tenant_limits", userLimitsHandler, a.registerOptionsTenantPath()...) + a.addOperationalLinks(runtimeConfigWeight, "Current runtime config", []IndexPageLink{ {Desc: "Entire runtime config (including overrides)", Path: "/runtime_config"}, {Desc: "Only values that differ from the defaults", Path: "/runtime_config?mode=diff"}, }) } func (a *API) RegisterTenantSettings(ts *settings.TenantSettings) { - settingsv1connect.RegisterSettingsServiceHandler(a.server.HTTP, ts, a.connectOptionsAuthRecovery()...) + connectOptions := a.connectOptionsAuthRecovery() + settingsv1connect.RegisterSettingsServiceHandler(a.server.HTTP, ts, connectOptions...) + + _, isUnimplemented := ts.RecordingRulesServiceHandler.(*settingsv1connect.UnimplementedRecordingRulesServiceHandler) + if !isUnimplemented { + settingsv1connect.RegisterRecordingRulesServiceHandler(a.server.HTTP, ts, connectOptions...) + } } // RegisterOverridesExporter registers the endpoints associated with the overrides exporter. func (a *API) RegisterOverridesExporter(oe *exporter.OverridesExporter) { - a.RegisterRoute("/overrides-exporter/ring", http.HandlerFunc(oe.RingHandler), false, true, "GET", "POST") - a.indexPage.AddLinks(defaultWeight, "Overrides-exporter", []IndexPageLink{ + a.registerAdminRoute("/overrides-exporter/ring", http.HandlerFunc(oe.RingHandler), a.registerOptionsRingPage()...) + a.addOperationalLinks(defaultWeight, "Overrides-exporter", []IndexPageLink{ {Desc: "Ring status", Path: "/overrides-exporter/ring"}, }) } +func (a *API) RegisterDebugInfo(svc debuginfov1alpha1connect.DebuginfoServiceHandler, uploadHandler http.Handler) { + debuginfov1alpha1connect.RegisterDebuginfoServiceHandler(a.server.HTTP, svc, a.connectOptionsDebugInfo()...) + a.RegisterRoute("/debuginfo.v1alpha1.DebuginfoService/Upload/{gnu_build_id}", uploadHandler, + a.WithAuthMiddleware(), WithMethod("POST")) +} + // RegisterDistributor registers the endpoints associated with the distributor. -func (a *API) RegisterDistributor(d *distributor.Distributor) { - pyroscopeHandler := pyroscope.NewPyroscopeIngestHandler(d, a.logger) - a.RegisterRoute("/ingest", pyroscopeHandler, true, true, "POST") - a.RegisterRoute("/pyroscope/ingest", pyroscopeHandler, true, true, "POST") - pushv1connect.RegisterPusherServiceHandler(a.server.HTTP, d, a.connectOptionsAuthRecovery()...) - a.RegisterRoute("/distributor/ring", d, false, true, "GET", "POST") - a.indexPage.AddLinks(defaultWeight, "Distributor", []IndexPageLink{ +func (a *API) RegisterDistributor(d *distributor.Distributor, limits *validation.Overrides, cfg server.Config) { + writePathOpts := a.registerOptionsWritePath(limits) + pyroscopeHandler := pyroscope.NewPyroscopeIngestHandler(d, limits, a.logger) + otlpHandler := otlp.NewOTLPIngestHandler(cfg, d, a.logger, limits) + + a.RegisterRoute("/ingest", pyroscopeHandler, writePathOpts...) + a.RegisterRoute("/pyroscope/ingest", pyroscopeHandler, writePathOpts...) + pushv1connect.RegisterPusherServiceHandler(a.server.HTTP, d, a.connectOptionsAuthDelayRecovery(limits)...) + a.registerAdminRoute("/distributor/ring", d, a.registerOptionsRingPage()...) + a.addOperationalLinks(defaultWeight, "Distributor", []IndexPageLink{ {Desc: "Ring status", Path: "/distributor/ring"}, }) + + a.RegisterRoute("/opentelemetry.proto.collector.profiles.v1development.ProfilesService/Export", otlpHandler, writePathOpts...) + a.RegisterRoute("/v1development/profiles", otlpHandler, writePathOpts...) + } // RegisterMemberlistKV registers the endpoints associated with the memberlist KV store. func (a *API) RegisterMemberlistKV(pathPrefix string, kvs *memberlist.KVInitService) { - a.RegisterRoute("/memberlist", MemberlistStatusHandler(pathPrefix, kvs), false, true, "GET") - a.indexPage.AddLinks(memberlistWeight, "Memberlist", []IndexPageLink{ + a.registerAdminRoute("/memberlist", MemberlistStatusHandler(pathPrefix, kvs), a.registerOptionsPublicAccess()...) + a.addOperationalLinks(memberlistWeight, "Memberlist", []IndexPageLink{ {Desc: "Status", Path: "/memberlist"}, }) } -// RegisterRing registers the ring UI page associated with the distributor for writes. -func (a *API) RegisterRing(r http.Handler) { - a.RegisterRoute("/ring", r, false, true, "GET", "POST") - a.indexPage.AddLinks(defaultWeight, "Ingester", []IndexPageLink{ +// RegisterIngesterRing registers the ring UI page associated with the distributor for writes. +func (a *API) RegisterIngesterRing(r http.Handler) { + a.registerAdminRoute("/ring", r, a.registerOptionsRingPage()...) + a.addOperationalLinks(defaultWeight, "Ingester", []IndexPageLink{ {Desc: "Ring status", Path: "/ring"}, }) } -type QuerierSvc interface { - querierv1connect.QuerierServiceHandler - vcsv1connect.VCSServiceHandler +func (a *API) RegisterQuerierServiceHandler(svc querierv1connect.QuerierServiceHandler) { + querierv1connect.RegisterQuerierServiceHandler(a.server.HTTP, svc, a.connectOptionsAuthLogDiagnosticsRecovery()...) } -// RegisterQuerier registers the endpoints associated with the querier. -func (a *API) RegisterQuerier(svc QuerierSvc) { - querierv1connect.RegisterQuerierServiceHandler(a.server.HTTP, svc, a.connectOptionsAuthLogRecovery()...) +func (a *API) RegisterVCSServiceHandler(svc vcsv1connect.VCSServiceHandler) { vcsv1connect.RegisterVCSServiceHandler(a.server.HTTP, svc, a.connectOptionsAuthLogRecovery()...) } +func (a *API) RegisterFeatureFlagsServiceHandler(svc capabilitiesv1connect.FeatureFlagsServiceHandler) { + capabilitiesv1connect.RegisterFeatureFlagsServiceHandler(a.server.HTTP, svc, a.connectOptionsAuthLogRecovery()...) +} + func (a *API) RegisterPyroscopeHandlers(client querierv1connect.QuerierServiceClient) { handlers := querier.NewHTTPHandlers(client) - a.RegisterRoute("/pyroscope/render", http.HandlerFunc(handlers.Render), true, true, "GET") - a.RegisterRoute("/pyroscope/render-diff", http.HandlerFunc(handlers.RenderDiff), true, true, "GET") - a.RegisterRoute("/pyroscope/label-values", http.HandlerFunc(handlers.LabelValues), true, true, "GET") + a.RegisterRoute("/pyroscope/render", http.HandlerFunc(handlers.Render), a.registerOptionsReadPath()...) + a.RegisterRoute("/pyroscope/render-diff", http.HandlerFunc(handlers.RenderDiff), a.registerOptionsReadPath()...) + a.RegisterRoute("/pyroscope/label-values", http.HandlerFunc(handlers.LabelValues), a.registerOptionsReadPath()...) } // RegisterIngester registers the endpoints associated with the ingester. @@ -261,28 +331,32 @@ func (a *API) RegisterIngester(svc *ingester.Ingester) { ingesterv1connect.RegisterIngesterServiceHandler(a.server.HTTP, svc, a.connectOptionsAuthRecovery()...) } +func (a *API) RegisterReadyHandler(handler http.Handler) { + a.registerAdminRoute("/ready", handler, WithMethod("GET")) +} + func (a *API) RegisterStoreGateway(svc *storegateway.StoreGateway) { storegatewayv1connect.RegisterStoreGatewayServiceHandler(a.server.HTTP, svc, a.connectOptionsAuthRecovery()...) - a.indexPage.AddLinks(defaultWeight, "Store-gateway", []IndexPageLink{ + a.addOperationalLinks(defaultWeight, "Store-gateway", []IndexPageLink{ {Desc: "Ring status", Path: "/store-gateway/ring"}, {Desc: "Tenants & Blocks", Path: "/store-gateway/tenants"}, }) - a.RegisterRoute("/store-gateway/ring", http.HandlerFunc(svc.RingHandler), false, true, "GET", "POST") - a.RegisterRoute("/store-gateway/tenants", http.HandlerFunc(svc.TenantsHandler), false, true, "GET") - a.RegisterRoute("/store-gateway/tenant/{tenant}/blocks", http.HandlerFunc(svc.BlocksHandler), false, true, "GET") + a.registerAdminRoute("/store-gateway/ring", http.HandlerFunc(svc.RingHandler), a.registerOptionsRingPage()...) + a.registerAdminRoute("/store-gateway/tenants", http.HandlerFunc(svc.TenantsHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/store-gateway/tenant/{tenant}/blocks", http.HandlerFunc(svc.BlocksHandler), a.registerOptionsPublicAccess()...) } // RegisterCompactor registers routes associated with the compactor. func (a *API) RegisterCompactor(c *compactor.MultitenantCompactor) { - a.indexPage.AddLinks(defaultWeight, "Compactor", []IndexPageLink{ + a.addOperationalLinks(defaultWeight, "Compactor", []IndexPageLink{ {Desc: "Ring status", Path: "/compactor/ring"}, }) - a.RegisterRoute("/compactor/ring", http.HandlerFunc(c.RingHandler), false, true, "GET", "POST") + a.registerAdminRoute("/compactor/ring", http.HandlerFunc(c.RingHandler), a.registerOptionsRingPage()...) } -// RegisterQueryFrontend registers the endpoints associated with the query frontend. -func (a *API) RegisterQueryFrontend(frontendSvc *frontend.Frontend) { +// RegisterFrontendForQuerierHandler registers the endpoints associated with the query frontend. +func (a *API) RegisterFrontendForQuerierHandler(frontendSvc *frontend.Frontend) { frontendpbconnect.RegisterFrontendForQuerierHandler(a.server.HTTP, frontendSvc, a.connectOptionsAuthRecovery()...) } @@ -299,31 +373,44 @@ func (a *API) RegisterQueryScheduler(s *scheduler.Scheduler) { // RegisterFlags registers api-related flags. func (cfg *Config) RegisterFlags(fs *flag.FlagSet) { - fs.StringVar(&cfg.BaseURL, "api.base-url", "", "base URL for when the server is behind a reverse proxy with a different path") + fs.StringVar( + &cfg.BaseURL, + "api.base-url", + "", + "base URL for when the server is behind a reverse proxy with a different path", + ) } -func (a *API) RegisterAdmin(ad *operations.Admin) { - a.RegisterRoute("/ops/object-store/tenants", http.HandlerFunc(ad.TenantsHandler), false, true, "GET") - a.RegisterRoute("/ops/object-store/tenants/{tenant}/blocks", http.HandlerFunc(ad.BlocksHandler), false, true, "GET") - a.RegisterRoute("/ops/object-store/tenants/{tenant}/blocks/{block}", http.HandlerFunc(ad.BlockHandler), false, true, "GET") +// AdminService is an interface for admin handlers (v1 and v2) +type AdminService interface { + TenantsHandler(w http.ResponseWriter, r *http.Request) + BlocksHandler(w http.ResponseWriter, r *http.Request) + BlockHandler(w http.ResponseWriter, r *http.Request) + DatasetHandler(w http.ResponseWriter, r *http.Request) + DatasetProfilesHandler(w http.ResponseWriter, r *http.Request) + ProfileDownloadHandler(w http.ResponseWriter, r *http.Request) + ProfileCallTreeHandler(w http.ResponseWriter, r *http.Request) + DatasetTSDBIndexHandler(w http.ResponseWriter, r *http.Request) + DatasetSymbolsHandler(w http.ResponseWriter, r *http.Request) +} - a.indexPage.AddLinks(defaultWeight, "Admin", []IndexPageLink{ +func (a *API) RegisterAdmin(ad AdminService) { + // Admin/ops routes are served on the internal server when available. + a.registerAdminRoute("/ops/object-store/tenants", http.HandlerFunc(ad.TenantsHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks", http.HandlerFunc(ad.BlocksHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks/{block}", http.HandlerFunc(ad.BlockHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks/{block}/datasets", http.HandlerFunc(ad.DatasetHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks/{block}/datasets/profiles", http.HandlerFunc(ad.DatasetProfilesHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks/{block}/datasets/profiles/download", http.HandlerFunc(ad.ProfileDownloadHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks/{block}/datasets/profiles/call-tree", http.HandlerFunc(ad.ProfileCallTreeHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks/{block}/datasets/index", http.HandlerFunc(ad.DatasetTSDBIndexHandler), a.registerOptionsPublicAccess()...) + a.registerAdminRoute("/ops/object-store/tenants/{tenant}/blocks/{block}/datasets/symbols", http.HandlerFunc(ad.DatasetSymbolsHandler), a.registerOptionsPublicAccess()...) + + a.addOperationalLinks(defaultWeight, "Admin", []IndexPageLink{ {Desc: "Object Storage Tenants & Blocks", Path: "/ops/object-store/tenants"}, }) } func (a *API) RegisterAdHocProfiles(ahp *adhocprofiles.AdHocProfiles) { - adhocprofilesv1connect.RegisterAdHocProfileServiceHandler(a.server.HTTP, ahp, a.connectOptionsAuthRecovery()...) -} - -func (a *API) connectOptionsRecovery() []connect.HandlerOption { - return append(connectapi.DefaultHandlerOptions(), a.recoveryMiddleware) -} - -func (a *API) connectOptionsAuthRecovery() []connect.HandlerOption { - return append(connectapi.DefaultHandlerOptions(), []connect.HandlerOption{a.grpcAuthMiddleware, a.recoveryMiddleware}...) -} - -func (a *API) connectOptionsAuthLogRecovery() []connect.HandlerOption { - return append(connectapi.DefaultHandlerOptions(), []connect.HandlerOption{a.grpcAuthMiddleware, a.grpcLogMiddleware, a.recoveryMiddleware}...) + adhocprofilesv1connect.RegisterAdHocProfileServiceHandler(a.server.HTTP, ahp, a.connectOptionsAuthLogRecovery()...) } diff --git a/pkg/api/api_experimental.go b/pkg/api/api_experimental.go new file mode 100644 index 0000000000..ac61d6c466 --- /dev/null +++ b/pkg/api/api_experimental.go @@ -0,0 +1,56 @@ +package api + +import ( + "net/http" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + metastoreadmin "github.com/grafana/pyroscope/v2/pkg/metastore/admin" + "github.com/grafana/pyroscope/v2/pkg/operations/v2/querydiagnostics" + "github.com/grafana/pyroscope/v2/pkg/querybackend" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter" +) + +// TODO(kolesnikovae): Recovery interceptor. + +func (a *API) RegisterSegmentWriter(svc *segmentwriter.SegmentWriterService) { + segmentwriterv1.RegisterSegmentWriterServiceServer(a.server.GRPC, svc) +} + +// RegisterSegmentWriterRing registers the ring UI page associated with the distributor for writes. +func (a *API) RegisterSegmentWriterRing(r http.Handler) { + a.registerAdminRoute("/ring-segment-writer", r, a.registerOptionsRingPage()...) + a.addOperationalLinks(defaultWeight, "Segment Writer", []IndexPageLink{ + {Desc: "Ring status", Path: "/ring-segment-writer"}, + }) +} + +func (a *API) RegisterQueryBackend(svc *querybackend.QueryBackend) { + queryv1.RegisterQueryBackendServiceServer(a.server.GRPC, svc) +} + +func (a *API) RegisterMetastoreAdmin(adm *metastoreadmin.Admin) { + a.registerAdminRoute("/metastore-nodes", adm.NodeListHandler(), a.registerOptionsRingPage()...) + a.registerAdminRoute("/metastore-client-test", adm.ClientTestHandler(), a.registerOptionsRingPage()...) + a.addOperationalLinks(defaultWeight, "Metastore", []IndexPageLink{ + {Desc: "Nodes", Path: "/metastore-nodes"}, + {Desc: "Client Test", Path: "/metastore-client-test"}, + }) +} + +func (a *API) RegisterQueryDiagnosticsAdmin(adm *querydiagnostics.Admin) { + a.registerAdminRoute("/query-diagnostics", adm.DiagnosticsHandler(), a.registerOptionsRingPage()...) + a.registerAdminRoute("/query-diagnostics/list", adm.DiagnosticsListHandler(), a.registerOptionsRingPage()...) + + // JSON API endpoints for React frontend + a.registerAdminRoute("/query-diagnostics/api/tenants", adm.TenantsAPIHandler(), a.registerOptionsRingPage()...) + a.registerAdminRoute("/query-diagnostics/api/diagnostics", adm.DiagnosticsListAPIHandler(), a.registerOptionsRingPage()...) + a.registerAdminRoute("/query-diagnostics/api/diagnostics/", adm.DiagnosticsGetAPIHandler(), WithGzipMiddleware(), WithMethod("GET"), WithPrefix()) + a.registerAdminRoute("/query-diagnostics/api/export/", adm.DiagnosticsExportAPIHandler(), WithMethod("GET"), WithPrefix()) + a.registerAdminRoute("/query-diagnostics/api/import", adm.DiagnosticsImportAPIHandler(), WithMethod("POST")) + + a.addOperationalLinks(defaultWeight, "Query Diagnostics", []IndexPageLink{ + {Desc: "Collect Diagnostics", Path: "/query-diagnostics"}, + {Desc: "View Stored Diagnostics", Path: "/query-diagnostics/list"}, + }) +} diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go deleted file mode 100644 index d4f698400b..0000000000 --- a/pkg/api/api_test.go +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/api/api_test.go -// Provenance-includes-license: Apache-2.0 -// Provenance-includes-copyright: The Cortex Authors. - -package api - -import ( - "fmt" - "net" - "net/http" - "strconv" - "testing" - - "github.com/go-kit/log" - "github.com/grafana/dskit/server" - grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/encoding/protojson" - - "github.com/grafana/pyroscope/pkg/util/gziphandler" -) - -func getHostnameAndRandomPort(t *testing.T) (string, int) { - listen, err := net.Listen("tcp", "localhost:0") - require.NoError(t, err) - - host, port, err := net.SplitHostPort(listen.Addr().String()) - require.NoError(t, err) - require.NoError(t, listen.Close()) - - portNum, err := strconv.Atoi(port) - require.NoError(t, err) - return host, portNum -} - -// Generates server config, with gRPC listening on random port. -func getServerConfig(t *testing.T) server.Config { - grpcHost, grpcPortNum := getHostnameAndRandomPort(t) - httpHost, httpPortNum := getHostnameAndRandomPort(t) - - cfg := server.Config{ - HTTPListenAddress: httpHost, - HTTPListenPort: httpPortNum, - - GRPCListenAddress: grpcHost, - GRPCListenPort: grpcPortNum, - - GRPCServerMaxRecvMsgSize: 1024, - } - require.NoError(t, cfg.LogLevel.Set("debug")) - return cfg -} - -func TestApiGzip(t *testing.T) { - cfg := Config{} - serverCfg := getServerConfig(t) - srv, err := server.New(serverCfg) - require.NoError(t, err) - go func() { _ = srv.Run() }() - t.Cleanup(srv.Stop) - - grpcGatewayMux := grpcgw.NewServeMux( - grpcgw.WithMarshalerOption("application/json+pretty", &grpcgw.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - Indent: " ", - Multiline: true, // Optional, implied by presence of "Indent". - }, - UnmarshalOptions: protojson.UnmarshalOptions{ - DiscardUnknown: true, - }, - }), - ) - - api, err := New(cfg, srv, grpcGatewayMux, log.NewNopLogger()) - require.NoError(t, err) - - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - size, err := strconv.Atoi(r.URL.Query().Get("respBodySize")) - if err != nil { - http.Error(w, fmt.Sprintf("respBodySize invalid: %s", err), http.StatusBadRequest) - return - } - w.WriteHeader(http.StatusOK) - _, _ = w.Write(make([]byte, size)) - }) - - api.RegisterRoute("/gzip_enabled", handler, false, true, http.MethodGet) - api.RegisterRoute("/gzip_disabled", handler, false, false, http.MethodGet) - - for _, tc := range []struct { - name string - endpoint string - respBodySize int - acceptEncodingHeader string - expectedGzip bool - }{ - { - name: "happy case gzip", - endpoint: "gzip_enabled", - respBodySize: gziphandler.DefaultMinSize + 1, - acceptEncodingHeader: "gzip", - expectedGzip: true, - }, - { - name: "gzip with priority header", - endpoint: "gzip_enabled", - respBodySize: gziphandler.DefaultMinSize + 1, - acceptEncodingHeader: "gzip;q=1", - expectedGzip: true, - }, - { - name: "gzip because any is accepted", - endpoint: "gzip_enabled", - respBodySize: gziphandler.DefaultMinSize + 1, - acceptEncodingHeader: "*", - expectedGzip: true, - }, - { - name: "no gzip because no header", - endpoint: "gzip_enabled", - respBodySize: gziphandler.DefaultMinSize + 1, - acceptEncodingHeader: "", - expectedGzip: false, - }, - { - name: "no gzip because not accepted", - endpoint: "gzip_enabled", - respBodySize: gziphandler.DefaultMinSize + 1, - acceptEncodingHeader: "identity", - expectedGzip: false, - }, - { - name: "no gzip because small payload", - endpoint: "gzip_enabled", - respBodySize: 1, - acceptEncodingHeader: "gzip", - expectedGzip: false, - }, - { - name: "forced gzip with small payload", - endpoint: "gzip_enabled", - respBodySize: 1, - acceptEncodingHeader: "gzip;q=1, *;q=0", - expectedGzip: true, - }, - { - name: "gzip disabled endpoint", - endpoint: "gzip_disabled", - respBodySize: gziphandler.DefaultMinSize + 1, - acceptEncodingHeader: "gzip", - expectedGzip: false, - }, - } { - t.Run(tc.name, func(t *testing.T) { - u := fmt.Sprintf("http://%s:%d/%s?respBodySize=%d", serverCfg.HTTPListenAddress, serverCfg.HTTPListenPort, tc.endpoint, tc.respBodySize) - req, err := http.NewRequest(http.MethodGet, u, nil) - require.NoError(t, err) - if tc.acceptEncodingHeader != "" { - req.Header.Set("Accept-Encoding", tc.acceptEncodingHeader) - } - - res, err := http.DefaultClient.Do(req) - require.NoError(t, err) - - require.Equal(t, http.StatusOK, res.StatusCode) - if tc.expectedGzip { - require.Equal(t, "gzip", res.Header.Get("Content-Encoding"), "Invalid Content-Encoding header value") - } else { - require.Empty(t, res.Header.Get("Content-Encoding"), "Invalid Content-Encoding header value") - } - }) - } - - t.Run("compressed with gzip", func(t *testing.T) { - }) -} diff --git a/pkg/api/connect_options.go b/pkg/api/connect_options.go new file mode 100644 index 0000000000..68c7a13e95 --- /dev/null +++ b/pkg/api/connect_options.go @@ -0,0 +1,69 @@ +package api + +import ( + "connectrpc.com/connect" + + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + querydiagnostics "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend/diagnostics" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/delayhandler" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func connectInterceptorRecovery() connect.HandlerOption { + return connect.WithInterceptors(util.RecoveryInterceptor) +} + +func (a *API) connectInterceptorAuth() connect.HandlerOption { + return a.cfg.GrpcAuthMiddleware +} + +func (a *API) connectInterceptorLog() connect.HandlerOption { + return connect.WithInterceptors(util.NewLogInterceptor(a.logger)) +} + +func (a *API) connectInterceptorDelay(limits delayhandler.Limits) connect.HandlerOption { + return connect.WithInterceptors(delayhandler.NewConnect(limits)) +} + +func (a *API) connectOptionsRecovery() []connect.HandlerOption { + return append(connectapi.DefaultHandlerOptions(), connectInterceptorRecovery()) +} + +func (a *API) connectOptionsAuthRecovery() []connect.HandlerOption { + return append(connectapi.DefaultHandlerOptions(), a.connectInterceptorAuth(), connectInterceptorRecovery()) +} + +func (a *API) connectOptionsAuthDelayRecovery(limits *validation.Overrides) []connect.HandlerOption { + // no per tenant overrides implemented for connect requests + messageLimit := int(limits.IngestionBodyLimitBytes(tenant.DefaultTenantID)) + return append(connectapi.DefaultHandlerOptions(), + a.connectInterceptorAuth(), + connect.WithReadMaxBytes(messageLimit), + a.connectInterceptorDelay(limits), + connectInterceptorRecovery(), + ) +} + +func (a *API) connectOptionsDebugInfo() []connect.HandlerOption { + messageLimit := 5 * 1024 * 1024 //todo + return append(connectapi.DefaultHandlerOptions(), + a.connectInterceptorAuth(), + connect.WithReadMaxBytes(messageLimit), + connectInterceptorRecovery(), + ) +} + +func (a *API) connectOptionsAuthLogRecovery() []connect.HandlerOption { + return append(connectapi.DefaultHandlerOptions(), a.connectInterceptorAuth(), a.connectInterceptorLog(), connectInterceptorRecovery()) +} + +func (a *API) connectOptionsAuthLogDiagnosticsRecovery() []connect.HandlerOption { + return append(connectapi.DefaultHandlerOptions(), + a.connectInterceptorAuth(), + a.connectInterceptorLog(), + connect.WithInterceptors(querydiagnostics.Interceptor), + connectInterceptorRecovery(), + ) +} diff --git a/pkg/api/index.go b/pkg/api/index.go index f7cda8fd50..9dd7dc2b0e 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -13,7 +13,7 @@ import ( "sort" "sync" - httputil "github.com/grafana/pyroscope/pkg/util/http" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) // List of weights to order link groups in the same order as weights are ordered here. diff --git a/pkg/api/index.gohtml b/pkg/api/index.gohtml index e555bb78e1..cbaaecf525 100644 --- a/pkg/api/index.gohtml +++ b/pkg/api/index.gohtml @@ -1,6 +1,6 @@ -{{- /*gotype: github.com/grafana/pyroscope/pkg/api.indexPageContents */ -}} +{{- /*gotype: github.com/grafana/pyroscope/v2/pkg/api.indexPageContents */ -}} - + @@ -8,9 +8,9 @@ Grafana Pyroscope - + - +
diff --git a/pkg/api/memberlist_status.gohtml b/pkg/api/memberlist_status.gohtml index 95128964a1..ab45656025 100644 --- a/pkg/api/memberlist_status.gohtml +++ b/pkg/api/memberlist_status.gohtml @@ -1,6 +1,6 @@ {{- /*gotype: github.com/grafana/dskit/kv/memberlist.StatusPageData */ -}} - + @@ -8,10 +8,10 @@ Memberlist: Grafana Pyroscope - + - +
diff --git a/pkg/api/register_options.go b/pkg/api/register_options.go new file mode 100644 index 0000000000..a9594a360b --- /dev/null +++ b/pkg/api/register_options.go @@ -0,0 +1,173 @@ +package api + +import ( + "net/http" + "strings" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/gorilla/mux" + "github.com/grafana/dskit/middleware" + + "github.com/grafana/pyroscope/v2/pkg/util/body" + "github.com/grafana/pyroscope/v2/pkg/util/delayhandler" + "github.com/grafana/pyroscope/v2/pkg/util/gziphandler" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +type registerMiddleware struct { + middleware.Interface + name string +} + +type registerParams struct { + methods []string + middlewares []registerMiddleware + isPrefix bool +} + +func (r *registerParams) logFields(path string) []interface{} { + gzip := false + auth := false + for _, m := range r.middlewares { + if m.name == "gzip" { + gzip = true + } + if m.name == "auth" { + auth = true + } + } + methods := strings.Join(r.methods, ",") + if len(r.methods) == 0 { + methods = "all" + } + + pathField := "path" + if r.isPrefix { + pathField = "prefix" + } + + return []interface{}{ + "methods", methods, + pathField, path, + "auth", auth, + "gzip", gzip, + } +} + +type RegisterOption func(*registerParams) + +func applyRegisterOptions(opts ...RegisterOption) *registerParams { + result := ®isterParams{} + for _, opt := range opts { + opt(result) + } + return result +} + +func WithMethod(method string) RegisterOption { + return func(r *registerParams) { + r.methods = append(r.methods, method) + } +} + +func WithPrefix() RegisterOption { + return func(r *registerParams) { + r.isPrefix = true + } +} + +func (a *API) WithAuthMiddleware() RegisterOption { + return func(r *registerParams) { + r.middlewares = append(r.middlewares, registerMiddleware{a.httpAuthMiddleware, "auth"}) + } +} + +func WithGzipMiddleware() RegisterOption { + return func(r *registerParams) { + r.middlewares = append(r.middlewares, registerMiddleware{middleware.Func(gziphandler.GzipHandler), "gzip"}) + } +} + +func (a *API) WithArtificialDelayMiddleware(limits delayhandler.Limits) RegisterOption { + return func(r *registerParams) { + r.middlewares = append(r.middlewares, registerMiddleware{middleware.Func(delayhandler.NewHTTP(limits)), "artificial_delay"}) + } +} + +func (a *API) WithBodySizeLimitMiddleware(limits body.Limits) RegisterOption { + return func(r *registerParams) { + r.middlewares = append(r.middlewares, registerMiddleware{middleware.Func(body.NewSizeLimitHandler(limits)), "body_size_limit"}) + } +} + +func (a *API) registerOptionsTenantPath() []RegisterOption { + return []RegisterOption{ + a.WithAuthMiddleware(), + WithGzipMiddleware(), + WithMethod("GET"), + } +} + +func (a *API) registerOptionsReadPath() []RegisterOption { + return a.registerOptionsTenantPath() +} + +func (a *API) registerOptionsWritePath(limits *validation.Overrides) []RegisterOption { + return []RegisterOption{ + a.WithAuthMiddleware(), + a.WithArtificialDelayMiddleware(limits), // This middleware relies on the auth middleware, to determine the user's override + a.WithBodySizeLimitMiddleware(limits), + WithGzipMiddleware(), + WithMethod("POST"), + } +} + +func (a *API) registerOptionsPublicAccess() []RegisterOption { + return []RegisterOption{ + WithGzipMiddleware(), + WithMethod("GET"), + } +} + +func (a *API) registerOptionsPrefixPublicAccess() []RegisterOption { + return []RegisterOption{ + WithGzipMiddleware(), + WithMethod("GET"), + WithPrefix(), + } +} + +func (a *API) registerOptionsRingPage() []RegisterOption { + return []RegisterOption{ + WithGzipMiddleware(), + WithMethod("GET"), + WithMethod("POST"), + } +} + +func registerRoute(logger log.Logger, mux *mux.Router, path string, handler http.Handler, registerOpts ...RegisterOption) { + opts := applyRegisterOptions(registerOpts...) + + level.Debug(logger).Log(append([]interface{}{ + "msg", "api: registering route"}, opts.logFields(path)...)...) + + // handle path prefixing + route := mux.Path(path) + if opts.isPrefix { + route = mux.PathPrefix(path) + } + + // limit the route to the given methods + if len(opts.methods) > 0 { + route = route.Methods(opts.methods...) + } + + // registering the middlewares in reverse order (similar like middleware.Merge) + for idx := range opts.middlewares { + mw := opts.middlewares[len(opts.middlewares)-idx-1] + handler = mw.Wrap(handler) + } + + route.Handler(handler) +} diff --git a/pkg/api/register_options_test.go b/pkg/api/register_options_test.go new file mode 100644 index 0000000000..437b94a87d --- /dev/null +++ b/pkg/api/register_options_test.go @@ -0,0 +1,70 @@ +package api + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-kit/log" + "github.com/gorilla/mux" + "github.com/grafana/dskit/middleware" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type contextKey uint8 + +const ( + contextKeyTest contextKey = iota +) + +func newTestMiddleware(name string) middleware.Interface { + return middleware.Func(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + middlewares, ok := ctx.Value(contextKeyTest).([]string) + if !ok { + middlewares = []string{} + } + middlewares = append(middlewares, name) + ctx = context.WithValue(ctx, contextKeyTest, middlewares) + next.ServeHTTP(w, r.WithContext(ctx)) + }) + }) + +} + +func Test_registerRoute(t *testing.T) { + router := mux.NewRouter() + registerRoute( + log.NewNopLogger(), + router, + "/test", + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + middlewares := r.Context().Value(contextKeyTest).([]string) + assert.Equal(t, []string{"outer", "middle", "inner"}, middlewares) + + w.WriteHeader(http.StatusOK) + }), + func(r *registerParams) { + r.middlewares = append(r.middlewares, registerMiddleware{newTestMiddleware("outer"), "outer"}) + }, + func(r *registerParams) { + r.middlewares = append(r.middlewares, registerMiddleware{newTestMiddleware("middle"), "middle"}) + }, + func(r *registerParams) { + r.middlewares = append(r.middlewares, registerMiddleware{newTestMiddleware("inner"), "inner"}) + }, + ) + + testServer := httptest.NewServer(router) + defer testServer.Close() + + req, err := http.NewRequest("GET", testServer.URL+"/test", nil) + require.NoError(t, err) + + resp, err := testServer.Client().Do(req) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) +} diff --git a/pkg/api/static/bootstrap-5.1.3.bundle.min.js b/pkg/api/static/bootstrap-5.1.3.bundle.min.js deleted file mode 100644 index cc0a25561d..0000000000 --- a/pkg/api/static/bootstrap-5.1.3.bundle.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/pkg/api/static/bootstrap-5.1.3.min.css b/pkg/api/static/bootstrap-5.1.3.min.css deleted file mode 100644 index 1472dec059..0000000000 --- a/pkg/api/static/bootstrap-5.1.3.min.css +++ /dev/null @@ -1,7 +0,0 @@ -@charset "UTF-8";/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:33,37,41;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + .5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:.2rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.3rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-bottom,.navbar-expand-sm .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-bottom,.navbar-expand-md .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-bottom,.navbar-expand-lg .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-bottom,.navbar-expand-xl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-bottom,.navbar-expand-xxl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-bottom,.navbar-expand .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{-webkit-animation:placeholder-glow 2s ease-in-out infinite;animation:placeholder-glow 2s ease-in-out infinite}@-webkit-keyframes placeholder-glow{50%{opacity:.2}}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;-webkit-animation:placeholder-wave 2s linear infinite;animation:placeholder-wave 2s linear infinite}@-webkit-keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:#6c757d!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/pkg/api/static/bootstrap-5.3.3.bundle.min.js b/pkg/api/static/bootstrap-5.3.3.bundle.min.js new file mode 100644 index 0000000000..04e9185bd6 --- /dev/null +++ b/pkg/api/static/bootstrap-5.3.3.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.3"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>n(t))).join(","):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",jt="collapsing",Mt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(jt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(jt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(jt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(Mt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function je(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const Me={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:je(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:je(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,jn=`hide${xn}`,Mn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,jn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,Mn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Mn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",js="Home",Ms="End",Fs="active",Hs="fade",Ws="show",Bs=".dropdown-toggle",zs=`:not(${Bs})`,Rs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',qs=`.nav-link${zs}, .list-group-item${zs}, [role="tab"]${zs}, ${Rs}`,Vs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Ks extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,js,Ms].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([js,Ms].includes(t.key))i=e[t.key===js?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Ks.getOrCreateInstance(i).show())}_getChildren(){return z.find(qs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Bs,Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(qs)?t:z.findOne(qs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Ks.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,Rs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Ks.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(Vs))Ks.getOrCreateInstance(t)})),m(Ks);const Qs=".bs.toast",Xs=`mouseover${Qs}`,Ys=`mouseout${Qs}`,Us=`focusin${Qs}`,Gs=`focusout${Qs}`,Js=`hide${Qs}`,Zs=`hidden${Qs}`,to=`show${Qs}`,eo=`shown${Qs}`,io="hide",no="show",so="showing",oo={animation:"boolean",autohide:"boolean",delay:"number"},ro={animation:!0,autohide:!0,delay:5e3};class ao extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return ro}static get DefaultType(){return oo}static get NAME(){return"toast"}show(){N.trigger(this._element,to).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(io),d(this._element),this._element.classList.add(no,so),this._queueCallback((()=>{this._element.classList.remove(so),N.trigger(this._element,eo),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Js).defaultPrevented||(this._element.classList.add(so),this._queueCallback((()=>{this._element.classList.add(io),this._element.classList.remove(so,no),N.trigger(this._element,Zs)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(no),super.dispose()}isShown(){return this._element.classList.contains(no)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Xs,(t=>this._onInteraction(t,!0))),N.on(this._element,Ys,(t=>this._onInteraction(t,!1))),N.on(this._element,Us,(t=>this._onInteraction(t,!0))),N.on(this._element,Gs,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ao.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ao),m(ao),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Ks,Toast:ao,Tooltip:cs}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/pkg/api/static/bootstrap-5.3.3.min.css b/pkg/api/static/bootstrap-5.3.3.min.css new file mode 100644 index 0000000000..39934146ff --- /dev/null +++ b/pkg/api/static/bootstrap-5.3.3.min.css @@ -0,0 +1,6 @@ +@charset "UTF-8";/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--bs-offcanvas-padding-y)) calc(-.5 * var(--bs-offcanvas-padding-x)) calc(-.5 * var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/pkg/api/version/version.go b/pkg/api/version/version.go index f98f9e9907..3e23852279 100644 --- a/pkg/api/version/version.go +++ b/pkg/api/version/version.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "math" + "net" + "strconv" "sync" "time" @@ -16,11 +18,10 @@ import ( "github.com/grafana/dskit/kv/memberlist" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" versionv1 "github.com/grafana/pyroscope/api/gen/proto/go/version/v1" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) // currentQuerierVersion is the current version of the querier API. @@ -175,10 +176,10 @@ type Service struct { func New(cfg util.CommonRingConfig, logger log.Logger, reg prometheus.Registerer) (*Service, error) { client, err := kv.NewClient(cfg.KVStore, GetCodec(), kv.RegistererWithKVName(reg, "versions"), logger) if err != nil { - return nil, errors.Wrap(err, "failed to initialize versions' KV store") + return nil, fmt.Errorf("failed to initialize versions' KV store: %w", err) } - instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger, false) + instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger, cfg.EnableIPv6) if err != nil { return nil, err } @@ -187,7 +188,7 @@ func New(cfg util.CommonRingConfig, logger log.Logger, reg prometheus.Registerer svc := &Service{ store: client, id: cfg.InstanceID, - addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), + addr: net.JoinHostPort(instanceAddr, strconv.Itoa(instancePort)), cfg: cfg, logger: log.With(logger, "component", "versions"), cancel: cancel, diff --git a/pkg/api/version/version_test.go b/pkg/api/version/version_test.go index 27bbb81ac7..9c90570c0e 100644 --- a/pkg/api/version/version_test.go +++ b/pkg/api/version/version_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/require" versionv1 "github.com/grafana/pyroscope/api/gen/proto/go/version/v1" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) type dnsProviderMock struct { diff --git a/pkg/block/block.go b/pkg/block/block.go new file mode 100644 index 0000000000..b1ea1ca81d --- /dev/null +++ b/pkg/block/block.go @@ -0,0 +1,83 @@ +package block + +import ( + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +const ( + DirNameSegment = "segments" + DirNameBlock = "blocks" + DirNameDLQ = "dlq" + DirNameAnonTenant = tenant.DefaultTenantID + + FileNameProfilesParquet = "profiles.parquet" + FileNameDataObject = "block.bin" + FileNameMetadataObject = "meta.pb" +) + +const ( + defaultObjectSizeLoadInMemory = 1 << 20 + defaultTenantDatasetSizeLoadInMemory = 1 << 20 + + maxRowsPerRowGroup = 10 << 10 + symbolsPrefetchSize = 32 << 10 +) + +func estimateReadBufferSize(s int64) int { + const minSize = 64 << 10 + const maxSize = 1 << 20 + // Parquet has global buffer map, where buffer size is key, + // so we want a low cardinality here. + e := nextPowerOfTwo(uint32(s / 10)) + if e < minSize { + return minSize + } + return int(min(e, maxSize)) +} + +// This is a verbatim copy of estimateReadBufferSize. +// It's kept for the sake of clarity and to avoid confusion. +func estimatePageBufferSize(s int64) int { + const minSize = 64 << 10 + const maxSize = 1 << 20 + e := nextPowerOfTwo(uint32(s / 10)) + if e < minSize { + return minSize + } + return int(min(e, maxSize)) +} + +func estimateFooterSize(size int64) int64 { + var s int64 + // as long as we don't keep the exact footer sizes in the meta estimate it + if size > 0 { + s = size / 10000 + } + // set a minimum footer size of 32KiB + if s < 32<<10 { + s = 32 << 10 + } + // set a maximum footer size of 512KiB + if s > 512<<10 { + s = 512 << 10 + } + // now check clamp it to the actual size of the whole object + if s > size { + s = size + } + return s +} + +func nextPowerOfTwo(n uint32) uint32 { + if n == 0 { + return 1 + } + n-- + n |= n >> 1 + n |= n >> 2 + n |= n >> 4 + n |= n >> 8 + n |= n >> 16 + n++ + return n +} diff --git a/pkg/block/compaction.go b/pkg/block/compaction.go new file mode 100644 index 0000000000..28e48fe495 --- /dev/null +++ b/pkg/block/compaction.go @@ -0,0 +1,631 @@ +package block + +import ( + "bytes" + "context" + "fmt" + "io" + "os" + "slices" + "sort" + "strings" + "sync" + + "github.com/grafana/dskit/multierror" + "github.com/parquet-go/parquet-go" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/storage" + "golang.org/x/sync/errgroup" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + memindex "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb/index" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +var ( + ErrNoBlocksToMerge = fmt.Errorf("no blocks to merge") + ErrShardMergeMismatch = fmt.Errorf("only blocks from the same shard can be merged") +) + +type CompactionOption func(*compactionConfig) + +func WithCompactionObjectOptions(options ...ObjectOption) CompactionOption { + return func(p *compactionConfig) { + p.objectOptions = append(p.objectOptions, options...) + } +} + +func WithCompactionTempDir(tempdir string) CompactionOption { + return func(p *compactionConfig) { + p.tempdir = tempdir + } +} + +func WithCompactionDestination(storage objstore.Bucket) CompactionOption { + return func(p *compactionConfig) { + p.destination = storage + } +} + +func WithSampleObserver(observer SampleObserver) CompactionOption { + return func(p *compactionConfig) { + p.sampleObserver = observer + } +} + +type compactionConfig struct { + objectOptions []ObjectOption + source objstore.BucketReader + destination objstore.Bucket + tempdir string + sampleObserver SampleObserver +} + +type SampleObserver interface { + symdb.SymbolsObserver + + // Evaluate is called before the compactor rewrites any symbols. + // An "observe" callback function is returned to be called after writing the resulting blocks. + // This method must not modify the entry. + Evaluate(ProfileEntry) (observe func()) +} + +func Compact( + ctx context.Context, + blocks []*metastorev1.BlockMeta, + storage objstore.Bucket, + options ...CompactionOption, +) (m []*metastorev1.BlockMeta, err error) { + c := &compactionConfig{ + source: storage, + destination: storage, + tempdir: os.TempDir(), + } + for _, option := range options { + option(c) + } + + objects := ObjectsFromMetas(storage, blocks, c.objectOptions...) + plan, err := PlanCompaction(objects) + if err != nil { + return nil, err + } + + if err = objects.Open(ctx); err != nil { + return nil, fmt.Errorf("objects.Open: %w", err) + } + defer func() { + _ = objects.Close() + }() + + compacted := make([]*metastorev1.BlockMeta, 0, len(plan)) + for _, p := range plan { + md, compactionErr := p.Compact(ctx, c.destination, c.tempdir, c.sampleObserver) + if compactionErr != nil { + return nil, compactionErr + } + compacted = append(compacted, md) + } + + return compacted, nil +} + +func PlanCompaction(objects Objects) ([]*CompactionPlan, error) { + if len(objects) == 0 { + // Even if there's just a single object, we still need to rewrite it. + return nil, ErrNoBlocksToMerge + } + + r := objects[0] + var level uint32 + for _, obj := range objects { + if r.meta.Shard != obj.meta.Shard { + return nil, ErrShardMergeMismatch + } + level = max(level, obj.meta.CompactionLevel) + } + level++ + + g := NewULIDGenerator(objects) + m := make(map[string]*CompactionPlan) + for _, obj := range objects { + for _, ds := range obj.meta.Datasets { + if ds.Name == 0 { + // Anonymous dataset is never compacted: + // it is rebuilt based on the actual block contents. + continue + } + tm, ok := m[obj.meta.StringTable[ds.Tenant]] + if !ok { + tm = newBlockCompaction( + g.ULID().String(), + obj.meta.StringTable[ds.Tenant], + r.meta.Shard, + level, + ) + m[obj.meta.StringTable[ds.Tenant]] = tm + } + // Bind objects to datasets. + sm := tm.addDataset(obj.meta, ds) + sm.append(NewDataset(ds, obj)) + } + } + + ordered := make([]*CompactionPlan, 0, len(m)) + for _, tm := range m { + ordered = append(ordered, tm) + slices.SortFunc(tm.datasets, func(a, b *datasetCompaction) int { + return strings.Compare(a.name, b.name) + }) + } + slices.SortFunc(ordered, func(a, b *CompactionPlan) int { + return strings.Compare(a.tenant, b.tenant) + }) + + return ordered, nil +} + +type CompactionPlan struct { + tenant string + path string + datasetMap map[int32]*datasetCompaction + datasets []*datasetCompaction + meta *metastorev1.BlockMeta + strings *metadata.StringTable + datasetIndex *DatasetIndexWriter + + // datasetIndex state for the compaction-time dedup of consecutive + // rows that share a fingerprint. The DatasetIndexWriter itself + // expects callers to add already-deduplicated series; compaction + // observes rows in series order, so we collapse runs of equal + // fingerprints here. + currentDatasetIdx uint32 + lastDatasetIndexFP model.Fingerprint +} + +func newBlockCompaction( + id string, + tenant string, + shard uint32, + compactionLevel uint32, +) *CompactionPlan { + p := &CompactionPlan{ + tenant: tenant, + datasetMap: make(map[int32]*datasetCompaction), + strings: metadata.NewStringTable(), + datasetIndex: NewDatasetIndexWriter(), + } + p.path = BuildObjectPath(tenant, shard, compactionLevel, id) + p.meta = &metastorev1.BlockMeta{ + FormatVersion: 1, + Id: id, + Tenant: p.strings.Put(tenant), + Shard: shard, + CompactionLevel: compactionLevel, + } + return p +} + +func (b *CompactionPlan) Compact( + ctx context.Context, + dst objstore.Bucket, + tempdir string, + observer SampleObserver, +) (m *metastorev1.BlockMeta, err error) { + w, err := NewBlockWriter(tempdir) + if err != nil { + return nil, fmt.Errorf("creating block writer: %w", err) + } + defer func() { + _ = w.Close() + }() + + // Datasets are compacted in a strict order. + for i, s := range b.datasets { + b.currentDatasetIdx = uint32(i) + s.registerSampleObserver(observer) + if err = s.compact(ctx, w); err != nil { + return nil, fmt.Errorf("compacting block: %w", err) + } + b.meta.Datasets = append(b.meta.Datasets, s.meta) + } + if err = b.writeDatasetIndex(w); err != nil { + return nil, fmt.Errorf("writing tenant index: %w", err) + } + b.meta.StringTable = b.strings.Strings + b.meta.MetadataOffset = w.Offset() + if err = metadata.Encode(w, b.meta); err != nil { + return nil, fmt.Errorf("writing metadata: %w", err) + } + b.meta.Size = w.Offset() + if err = w.Upload(ctx, dst, b.path); err != nil { + return nil, fmt.Errorf("uploading block: %w", err) + } + return b.meta, nil +} + +// addRowToDatasetIndex appends the row's series to the per-tenant +// dataset index, deduplicating runs of consecutive rows that share a +// fingerprint. Compaction iterates rows in series order, so runs of +// matching fingerprints belong to the same series. +func (b *CompactionPlan) addRowToDatasetIndex(r ProfileEntry) { + if b.lastDatasetIndexFP != r.Fingerprint || b.datasetIndex.Empty() { + b.datasetIndex.AddSeries(b.currentDatasetIdx, r.Labels, r.Fingerprint) + b.lastDatasetIndexFP = r.Fingerprint + } +} + +func (b *CompactionPlan) writeDatasetIndex(w *Writer) error { + defer b.datasetIndex.Close() + if b.datasetIndex.Empty() { + return nil + } + off := w.Offset() + n, err := b.datasetIndex.WriteTo(w) + if err != nil { + return err + } + // We annotate the dataset with the + // __tenant_dataset__ = "dataset_tsdb_index" label, + // so the dataset index metadata can be queried. + labels := metadata.NewLabelBuilder(b.strings). + WithLabelSet(metadata.LabelNameTenantDataset, metadata.LabelValueDatasetTSDBIndex). + Build() + b.meta.Datasets = append(b.meta.Datasets, &metastorev1.Dataset{ + Format: uint32(DatasetFormat1), + Tenant: b.meta.Tenant, + Name: 0, // Anonymous. + MinTime: b.meta.MinTime, + MaxTime: b.meta.MaxTime, + TableOfContents: []uint64{off}, + Size: uint64(n), + Labels: labels, + }) + return nil +} + +func (b *CompactionPlan) addDataset(md *metastorev1.BlockMeta, s *metastorev1.Dataset) *datasetCompaction { + name := b.strings.Put(md.StringTable[s.Name]) + tenant := b.strings.Put(md.StringTable[s.Tenant]) + sm, ok := b.datasetMap[name] + if !ok { + sm = b.newDatasetCompaction(tenant, name) + b.datasetMap[name] = sm + b.datasets = append(b.datasets, sm) + } + if b.meta.MinTime == 0 || s.MinTime < b.meta.MinTime { + b.meta.MinTime = s.MinTime + } + if s.MaxTime > b.meta.MaxTime { + b.meta.MaxTime = s.MaxTime + } + return sm +} + +type datasetCompaction struct { + // Dataset name. + name string + parent *CompactionPlan + meta *metastorev1.Dataset + labels *metadata.LabelBuilder + + datasets []*Dataset + + indexRewriter *indexRewriter + symbolsRewriter *symbolsRewriter + profilesWriter *profilesWriter + + samples uint64 + series uint64 + profiles uint64 + + flushOnce sync.Once + + observer SampleObserver +} + +func (b *CompactionPlan) newDatasetCompaction(tenant, name int32) *datasetCompaction { + return &datasetCompaction{ + parent: b, + name: b.strings.Strings[name], + labels: metadata.NewLabelBuilder(b.strings), + meta: &metastorev1.Dataset{ + Tenant: tenant, + Name: name, + // Updated at append. + MinTime: 0, + MaxTime: 0, + // Updated at writeTo. + TableOfContents: nil, + Size: 0, + Labels: nil, + }, + } +} + +func (m *datasetCompaction) append(s *Dataset) { + m.datasets = append(m.datasets, s) + if m.meta.MinTime == 0 || s.meta.MinTime < m.meta.MinTime { + m.meta.MinTime = s.meta.MinTime + } + if s.meta.MaxTime > m.meta.MaxTime { + m.meta.MaxTime = s.meta.MaxTime + } + m.labels.Put(s.meta.Labels, s.obj.meta.StringTable) +} + +func (m *datasetCompaction) compact(ctx context.Context, w *Writer) (err error) { + off := w.Offset() + m.meta.TableOfContents = make([]uint64, 0, 3) + m.meta.TableOfContents = append(m.meta.TableOfContents, w.Offset()) + + if err = m.open(ctx, w); err != nil { + return fmt.Errorf("failed to open sections for compaction: %w", err) + } + defer func() { + _ = m.close() + }() + + if err = m.merge(ctx); err != nil { + return fmt.Errorf("failed to merge datasets: %w", err) + } + if err = m.flush(); err != nil { + return fmt.Errorf("failed to flush compacted dataset: %w", err) + } + + m.meta.TableOfContents = append(m.meta.TableOfContents, w.Offset()) + if _, err = io.Copy(w, bytes.NewReader(m.indexRewriter.buf)); err != nil { + return fmt.Errorf("failed to read index: %w", err) + } + m.meta.TableOfContents = append(m.meta.TableOfContents, w.Offset()) + if _, err = io.Copy(w, bytes.NewReader(m.symbolsRewriter.buf.Bytes())); err != nil { + return fmt.Errorf("failed to read symbols: %w", err) + } + + m.meta.Size = w.Offset() - off + m.meta.Labels = m.labels.Build() + return nil +} + +func (m *datasetCompaction) registerSampleObserver(observer SampleObserver) { + m.observer = observer +} + +func (m *datasetCompaction) open(ctx context.Context, w io.Writer) (err error) { + var estimatedProfileTableSize int64 + for _, ds := range m.datasets { + estimatedProfileTableSize += ds.sectionSize(SectionProfiles) + } + pageBufferSize := estimatePageBufferSize(estimatedProfileTableSize) + m.profilesWriter = newProfileWriter(pageBufferSize, w) + + m.indexRewriter = newIndexRewriter() + m.symbolsRewriter = newSymbolsRewriter(m.observer) + + g, ctx := errgroup.WithContext(ctx) + for _, s := range m.datasets { + s := s + g.Go(util.RecoverPanic(func() error { + if openErr := s.Open(ctx, + SectionProfiles, + SectionTSDB, + SectionSymbols, + ); openErr != nil { + return fmt.Errorf("opening tenant dataset (block %s): %w", s.obj.path, openErr) + } + return nil + })) + } + if err = g.Wait(); err != nil { + merr := multierror.New(err) + for _, s := range m.datasets { + merr.Add(s.Close()) + } + return merr.Err() + } + return nil +} + +func (m *datasetCompaction) merge(ctx context.Context) (err error) { + rows, err := NewMergeRowProfileIterator(m.datasets) + if err != nil { + return err + } + defer func() { + err = multierror.New(err, rows.Close()).Err() + }() + var i int + for rows.Next() { + if i++; i%1000 == 0 { + if err = ctx.Err(); err != nil { + return err + } + } + if err = m.writeRow(rows.At()); err != nil { + return err + } + } + return rows.Err() +} + +func (m *datasetCompaction) writeRow(r ProfileEntry) (err error) { + if m.observer != nil { + observe := m.observer.Evaluate(r) + defer observe() + } + m.parent.addRowToDatasetIndex(r) + m.indexRewriter.rewriteRow(r) + if err = m.symbolsRewriter.rewriteRow(r); err != nil { + return err + } + return m.profilesWriter.writeRow(r) +} + +func (m *datasetCompaction) flush() (err error) { + m.flushOnce.Do(func() { + merr := multierror.New() + merr.Add(m.symbolsRewriter.Flush()) + merr.Add(m.indexRewriter.Flush()) + merr.Add(m.profilesWriter.Close()) + m.samples = m.symbolsRewriter.samples + m.series = m.indexRewriter.NumSeries() + m.profiles = m.profilesWriter.profiles + err = merr.Err() + }) + return err +} + +func (m *datasetCompaction) close() error { + err := m.flush() + m.symbolsRewriter = nil + m.indexRewriter = nil + m.profilesWriter = nil + m.datasets = nil + return err +} + +func newIndexRewriter() *indexRewriter { + return &indexRewriter{ + symbols: make(map[string]struct{}), + } +} + +type indexRewriter struct { + series []seriesLabels + symbols map[string]struct{} + chunks []index.ChunkMeta // one chunk per series + previousFp model.Fingerprint + buf []byte +} + +type seriesLabels struct { + labels phlaremodel.Labels + fingerprint model.Fingerprint +} + +func (rw *indexRewriter) rewriteRow(e ProfileEntry) { + if rw.previousFp != e.Fingerprint || len(rw.series) == 0 { + series := e.Labels.Clone() + for _, l := range series { + rw.symbols[l.Name] = struct{}{} + rw.symbols[l.Value] = struct{}{} + } + rw.series = append(rw.series, seriesLabels{ + labels: series, + fingerprint: e.Fingerprint, + }) + rw.chunks = append(rw.chunks, index.ChunkMeta{ + MinTime: e.Timestamp, + MaxTime: e.Timestamp, + SeriesIndex: uint32(len(rw.series) - 1), + }) + rw.previousFp = e.Fingerprint + } + rw.chunks[len(rw.chunks)-1].MaxTime = e.Timestamp + e.Row.SetSeriesIndex(rw.chunks[len(rw.chunks)-1].SeriesIndex) +} + +func (rw *indexRewriter) NumSeries() uint64 { return uint64(len(rw.series)) } + +func (rw *indexRewriter) Flush() error { + // TODO(kolesnikovae): + // * Estimate size. + // * Use buffer pool. + w, err := memindex.NewWriter(context.Background(), 256<<10) + if err != nil { + return err + } + + // Sort symbols + symbols := make([]string, 0, len(rw.symbols)) + for s := range rw.symbols { + symbols = append(symbols, s) + } + sort.Strings(symbols) + + // Add symbols + for _, symbol := range symbols { + if err = w.AddSymbol(symbol); err != nil { + return err + } + } + + // Add Series + for i, series := range rw.series { + if err = w.AddSeries(storage.SeriesRef(i), series.labels, series.fingerprint, rw.chunks[i]); err != nil { + return err + } + } + + err = w.Close() + rw.buf = w.ReleaseIndex() + return err +} + +type symbolsRewriter struct { + buf *bytes.Buffer + w *symdb.SymDB + rw map[*Dataset]*symdb.Rewriter + samples uint64 + observer SampleObserver + + stacktraces []uint32 +} + +func newSymbolsRewriter(observer SampleObserver) *symbolsRewriter { + // TODO(kolesnikovae): + // * Estimate size. + // * Use buffer pool. + buf := bytes.NewBuffer(make([]byte, 0, 1<<20)) + return &symbolsRewriter{ + buf: buf, + rw: make(map[*Dataset]*symdb.Rewriter), + w: symdb.NewSymDB(&symdb.Config{ + Version: symdb.FormatV3, + Writer: &nopWriteCloser{buf}, + }), + observer: observer, + } +} + +type nopWriteCloser struct{ io.Writer } + +func (*nopWriteCloser) Close() error { return nil } + +func (s *symbolsRewriter) rewriteRow(e ProfileEntry) (err error) { + rw := s.rewriterFor(e.Dataset) + e.Row.ForStacktraceIDsValues(func(values []parquet.Value) { + s.loadStacktraceIDs(values) + if err = rw.Rewrite(e.Row.StacktracePartitionID(), s.stacktraces); err != nil { + return + } + s.samples += uint64(len(values)) + for i, v := range values { + values[i] = parquet.Int64Value(int64(s.stacktraces[i])).Level(v.RepetitionLevel(), v.DefinitionLevel(), v.Column()) + } + }) + return err +} + +func (s *symbolsRewriter) rewriterFor(x *Dataset) *symdb.Rewriter { + rw, ok := s.rw[x] + if !ok { + rw = symdb.NewRewriter(s.w, x.Symbols(), s.observer) + s.rw[x] = rw + } + return rw +} + +func (s *symbolsRewriter) loadStacktraceIDs(values []parquet.Value) { + s.stacktraces = slices.Grow(s.stacktraces[0:], len(values))[:len(values)] + for i := range values { + s.stacktraces[i] = values[i].Uint32() + } +} + +func (s *symbolsRewriter) Flush() error { return s.w.Flush() } diff --git a/pkg/block/compaction_test.go b/pkg/block/compaction_test.go new file mode 100644 index 0000000000..78cd1615d8 --- /dev/null +++ b/pkg/block/compaction_test.go @@ -0,0 +1,343 @@ +package block_test + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + "testing" + + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/prompb" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/metrics" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetrics" +) + +func Test_CompactBlocks(t *testing.T) { + ctx := context.Background() + bucket, _ := testutil.NewFilesystemBucket(t, ctx, "testdata") + + var resp metastorev1.GetBlockMetadataResponse + raw, err := os.ReadFile("testdata/block-metas.json") + require.NoError(t, err) + err = protojson.Unmarshal(raw, &resp) + require.NoError(t, err) + + dst, tempdir := testutil.NewFilesystemBucket(t, ctx, t.TempDir()) + compactedBlocks, err := block.Compact(ctx, resp.Blocks, bucket, + block.WithCompactionDestination(dst), + block.WithCompactionTempDir(tempdir), + block.WithCompactionObjectOptions( + block.WithObjectDownload(filepath.Join(tempdir, "source")), + block.WithObjectMaxSizeLoadInMemory(0)), // Force download. + ) + + require.NoError(t, err) + require.Len(t, compactedBlocks, 1) + require.NotZero(t, compactedBlocks[0].Size) + require.Len(t, compactedBlocks[0].Datasets, 4) + + compactedJson, err := json.MarshalIndent(compactedBlocks, "", " ") + require.NoError(t, err) + expectedJson, err := os.ReadFile("testdata/compacted.golden") + require.NoError(t, err) + assert.Equal(t, string(expectedJson), string(compactedJson)) + + t.Run("Compact compacted blocks", func(t *testing.T) { + compactedBlocks, err = block.Compact(ctx, compactedBlocks, dst, + block.WithCompactionDestination(dst), + block.WithCompactionTempDir(tempdir), + block.WithCompactionObjectOptions( + block.WithObjectDownload(filepath.Join(tempdir, "source")), + block.WithObjectMaxSizeLoadInMemory(0)), // Force download. + ) + + require.NoError(t, err) + require.Len(t, compactedBlocks, 1) + require.NotZero(t, compactedBlocks[0].Size) + require.Len(t, compactedBlocks[0].Datasets, 4) + }) +} + +func Test_CompactBlocks_recordingRules(t *testing.T) { + ctx := context.Background() + bucket, _ := testutil.NewFilesystemBucket(t, ctx, "testdata") + + var resp metastorev1.GetBlockMetadataResponse + raw, err := os.ReadFile("testdata/block-metas.json") + require.NoError(t, err) + err = protojson.Unmarshal(raw, &resp) + require.NoError(t, err) + + exporter := &stringExporter{} + ruler := new(mockmetrics.MockRuler) + ruler.On("RecordingRules", mock.Anything).Return([]*phlaremodel.RecordingRule{ + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "goroutine:goroutine:count:goroutine:count"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_goroutines_total_count"}), + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:alloc_objects:count:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_alloc_total_count"}), + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:alloc_space:bytes:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_alloc_total_bytes"}), + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:inuse_objects:count:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_inuse_total_count"}), + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:inuse_space:bytes:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_inuse_total_bytes"}), + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_cpu_usage_total_nanoseconds"}), + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "process_cpu:samples:count:cpu:nanoseconds"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_cpu_usage_total_samples"}), + }, + // functions + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "goroutine:goroutine:count:goroutine:count"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_goroutines_function_total_servehttp_count"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:alloc_objects:count:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_alloc_function_total_servehttp_count"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:alloc_space:bytes:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_alloc_function_total_servehttp_bytes"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:inuse_objects:count:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_inuse_function_total_servehttp_count"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:inuse_space:bytes:space:bytes"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_inuse_function_total_servehttp_bytes"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_cpu_usage_function_total_servehttp_nanoseconds"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "process_cpu:samples:count:cpu:nanoseconds"), + }, + GroupBy: []string{"service_name"}, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_cpu_usage_function_total_servehttp_samples"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + }) + sampleObserver := metrics.NewSampleObserver(0, exporter, ruler, labels.EmptyLabels()) + + compactedBlocks, err := block.Compact(ctx, resp.Blocks, bucket, + block.WithSampleObserver(sampleObserver), + ) + // Close observer to flush export + sampleObserver.Close() + + require.NoError(t, err) + require.Len(t, compactedBlocks, 1) + require.NotZero(t, compactedBlocks[0].Size) + require.Len(t, compactedBlocks[0].Datasets, 4) + + expectedMetrics, err := os.ReadFile("testdata/profiles_recorded.txt") + require.NoError(t, err) + expectedMetricsArray := strings.Split(string(expectedMetrics), "\n") + sort.Strings(expectedMetricsArray) + actualMetricsArray := strings.Split(exporter.String(), "\n") + sort.Strings(actualMetricsArray) + assert.Equal(t, expectedMetricsArray, actualMetricsArray) + + compactedJson, err := json.MarshalIndent(compactedBlocks, "", " ") + require.NoError(t, err) + expectedJson, err := os.ReadFile("testdata/compacted.golden") + require.NoError(t, err) + assert.Equal(t, string(expectedJson), string(compactedJson)) +} + +func Test_CompactBlocks_recordingRules_shadowedSymbols(t *testing.T) { + ctx := context.Background() + bucket, _ := testutil.NewFilesystemBucket(t, ctx, "testdata") + + var resp metastorev1.GetBlockMetadataResponse + raw, err := os.ReadFile("testdata/block-metas.json") + require.NoError(t, err) + err = protojson.Unmarshal(raw, &resp) + require.NoError(t, err) + + exporter := &stringExporter{} + ruler := new(mockmetrics.MockRuler) + ruler.On("RecordingRules", mock.Anything).Return([]*phlaremodel.RecordingRule{ + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/ingester"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:alloc_space:bytes:space:bytes"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_alloc_total_pyroscope_ingester_Push_bytes"}), + FunctionName: "github.com/grafana/pyroscope/pkg/ingester.(*Ingester).Push", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/ingester"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:inuse_space:bytes:space:bytes"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_inuse_total_pyroscope_ingester_Push_bytes"}), + FunctionName: "github.com/grafana/pyroscope/pkg/ingester.(*Ingester).Push", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/ingester"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "process_cpu:samples:count:cpu:nanoseconds"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_cpu_usage_total_pyroscope_ingester_Push_samples"}), + FunctionName: "github.com/grafana/pyroscope/pkg/ingester.(*Ingester).Push", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/ingester"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:alloc_space:bytes:space:bytes"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_alloc_total_pyroscope_ingester_Serve_bytes"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/ingester"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:inuse_space:bytes:space:bytes"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_inuse_total_pyroscope_ingester_Serve_bytes"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/ingester"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "process_cpu:samples:count:cpu:nanoseconds"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_cpu_usage_total_pyroscope_ingester_Serve_samples"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/query-frontend"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:inuse_space:bytes:space:bytes"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_inuse_total_query_Serve_bytes"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "pyroscope-test/query-frontend"), + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory:alloc_space:bytes:space:bytes"), + }, + ExternalLabels: labels.New(labels.Label{Name: "__name__", Value: "profiles_recorded_mem_alloc_total_query_Serve_bytes"}), + FunctionName: "net/http.HandlerFunc.ServeHTTP", + }, + }) + sampleObserver := metrics.NewSampleObserver(0, exporter, ruler, labels.EmptyLabels()) + + compactedBlocks, err := block.Compact(ctx, resp.Blocks, bucket, + block.WithSampleObserver(sampleObserver), + ) + // Close observer to flush export + sampleObserver.Close() + + require.NoError(t, err) + require.Len(t, compactedBlocks, 1) + require.NotZero(t, compactedBlocks[0].Size) + require.Len(t, compactedBlocks[0].Datasets, 4) + + expectedMetrics, err := os.ReadFile("testdata/profiles_recorded_shadowed.txt") + require.NoError(t, err) + expectedMetricsArray := strings.Split(string(expectedMetrics), "\n") + sort.Strings(expectedMetricsArray) + actualMetricsArray := strings.Split(exporter.String(), "\n") + sort.Strings(actualMetricsArray) + assert.Equal(t, expectedMetricsArray, actualMetricsArray) + + compactedJson, err := json.MarshalIndent(compactedBlocks, "", " ") + require.NoError(t, err) + expectedJson, err := os.ReadFile("testdata/compacted.golden") + require.NoError(t, err) + assert.Equal(t, string(expectedJson), string(compactedJson)) +} + +type stringExporter struct { + output string +} + +func (e *stringExporter) Send(tenant string, series []prompb.TimeSeries) error { + for _, s := range series { + e.output += fmt.Sprintf("%s: %s\n", tenant, s.String()) + } + return nil +} + +func (*stringExporter) Flush() {} + +func (e *stringExporter) String() string { + return e.output +} diff --git a/pkg/block/dataset.go b/pkg/block/dataset.go new file mode 100644 index 0000000000..5866739928 --- /dev/null +++ b/pkg/block/dataset.go @@ -0,0 +1,306 @@ +package block + +import ( + "context" + "fmt" + + "github.com/grafana/dskit/multierror" + "github.com/parquet-go/parquet-go" + "golang.org/x/sync/errgroup" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/bufferpool" + "github.com/grafana/pyroscope/v2/pkg/util/refctr" +) + +type DatasetFormat uint32 + +const ( + DatasetFormat0 DatasetFormat = iota + DatasetFormat1 +) + +type Section uint32 + +const ( + SectionProfiles Section = iota + SectionTSDB + SectionSymbols + SectionDatasetIndex +) + +// DatasetWeight holds the section-level size breakdown of a dataset. +// For Format1 (tenant-wide TSDB index) datasets, IndexLookupCount is 1 +// and only TSDBBytes is set; the real profile and symbol sizes are +// unknown until the query backend resolves the datasets at runtime. +type DatasetWeight struct { + ProfilesBytes uint64 + TSDBBytes uint64 + SymbolsBytes uint64 + IndexLookupCount int +} + +// WeightOf computes the section size breakdown for a dataset from its +// table of contents. +func WeightOf(ds *metastorev1.Dataset) DatasetWeight { + toc := ds.TableOfContents + switch { + case len(toc) >= 3: // Format0: profiles, tsdb, symbols + return DatasetWeight{ + ProfilesBytes: toc[1] - toc[0], + TSDBBytes: toc[2] - toc[1], + SymbolsBytes: (toc[0] + ds.Size) - toc[2], + } + case len(toc) == 1: // Format1: tenant-wide dataset index + return DatasetWeight{ + TSDBBytes: ds.Size, + IndexLookupCount: 1, + } + } + return DatasetWeight{} +} + +// Add accumulates another DatasetWeight into this one. +func (w *DatasetWeight) Add(other DatasetWeight) { + w.ProfilesBytes += other.ProfilesBytes + w.TSDBBytes += other.TSDBBytes + w.SymbolsBytes += other.SymbolsBytes + w.IndexLookupCount += other.IndexLookupCount +} + +// Total returns the sum of all section bytes. +func (w DatasetWeight) Total() uint64 { + return w.ProfilesBytes + w.TSDBBytes + w.SymbolsBytes +} + +type sectionDesc struct { + // The section entry index in the table of contents. + index int + // The name is only used in log and error messages. + name string +} + +var ( + // Format: section => desc + sections = [...][]sectionDesc{ + DatasetFormat0: { + SectionProfiles: sectionDesc{index: 0, name: "profiles"}, + SectionTSDB: sectionDesc{index: 1, name: "tsdb"}, + SectionSymbols: sectionDesc{index: 2, name: "symbols"}, + }, + DatasetFormat1: { + // The dataset index can be used instead of the tsdb section of the + // dataset in cases where SeriesIndex is not used. Therefore, it has + // an alias record: if a query accesses the tsdb index of the dataset, + // it will access the tenant-wide dataset index. + SectionDatasetIndex: sectionDesc{index: 0, name: "dataset_tsdb_index"}, + SectionTSDB: sectionDesc{index: 0, name: "dataset_tsdb_index"}, + }, + } +) + +func (sc Section) open(ctx context.Context, s *Dataset) (err error) { + switch sc { + case SectionTSDB: + return openTSDB(ctx, s) + case SectionSymbols: + return openSymbols(ctx, s) + case SectionProfiles: + return openProfileTable(ctx, s) + case SectionDatasetIndex: + return openDatasetIndex(ctx, s) + default: + panic(fmt.Sprintf("bug: unknown section: %d", sc)) + } +} + +type Dataset struct { + tenant string + name string + + meta *metastorev1.Dataset + obj *Object + + refs refctr.Counter + buf *bufferpool.Buffer + err error + + tsdb *tsdbBuffer + symbols *symdb.Reader + profiles *ParquetFile + + memSize int +} + +func NewDataset(meta *metastorev1.Dataset, obj *Object) *Dataset { + return &Dataset{ + tenant: obj.meta.StringTable[meta.Tenant], + name: obj.meta.StringTable[meta.Name], + meta: meta, + obj: obj, + memSize: defaultTenantDatasetSizeLoadInMemory, + } +} + +type DatasetOption func(*Dataset) + +func WithDatasetMaxSizeLoadInMemory(size int) DatasetOption { + return func(s *Dataset) { + s.memSize = size + } +} + +// Open opens the dataset, initializing the sections specified. +// +// Open may be called multiple times concurrently, but the dataset +// is only initialized once. While it is possible to open the dataset +// repeatedly after close, the caller must pass the failure reason to +// the CloseWithError call, preventing further use, if applicable. +func (s *Dataset) Open(ctx context.Context, sections ...Section) error { + return s.refs.IncErr(func() error { + if err := s.open(ctx, sections...); err != nil { + return fmt.Errorf("%w (%s)", err, s.obj.meta.Id) + } + return nil + }) +} + +func (s *Dataset) open(ctx context.Context, sections ...Section) (err error) { + if s.err != nil { + // The dataset has already been closed with an error. + return s.err + } + if err = s.obj.Open(ctx); err != nil { + return fmt.Errorf("failed to open object: %w", err) + } + defer func() { + // Close the object here because the dataset won't be + // closed if it fails to open. + if err != nil { + _ = s.closeErr(err) + } + }() + if s.obj.buf == nil && s.meta.Size < uint64(s.memSize) { + s.buf = bufferpool.GetBuffer(int(s.meta.Size)) + off, size := int64(s.offset()), int64(s.meta.Size) + if err = objstore.ReadRange(ctx, s.buf, s.obj.path, s.obj.storage, off, size); err != nil { + return fmt.Errorf("loading sections into memory: %w", err) + } + } + g, ctx := errgroup.WithContext(ctx) + for _, sc := range sections { + sc := sc + g.Go(util.RecoverPanic(func() error { + if openErr := sc.open(ctx, s); openErr != nil { + return fmt.Errorf("opening section %v: %w", s.section(sc).name, openErr) + } + return nil + })) + } + return g.Wait() +} + +func (s *Dataset) Close() error { return s.CloseWithError(nil) } + +// CloseWithError closes the dataset and disposes all the resources +// associated with it. +// +// Any further attempts to open the dataset will return the provided error. +func (s *Dataset) CloseWithError(err error) (closeErr error) { + s.refs.Dec(func() { + closeErr = s.closeErr(err) + }) + return closeErr +} + +func (s *Dataset) closeErr(err error) error { + s.err = err + if s.buf != nil { + bufferpool.Put(s.buf) + s.buf = nil + } + var merr multierror.MultiError + if s.tsdb != nil { + merr.Add(s.tsdb.Close()) + } + if s.symbols != nil { + merr.Add(s.symbols.Close()) + } + if s.profiles != nil { + merr.Add(s.profiles.Close()) + } + if s.obj != nil { + merr.Add(s.obj.CloseWithError(err)) + } + return merr.Err() +} + +func (s *Dataset) TenantID() string { return s.tenant } + +func (s *Dataset) Name() string { return s.name } + +func (s *Dataset) Metadata() *metastorev1.Dataset { return s.meta } + +func (s *Dataset) Profiles() *ParquetFile { return s.profiles } + +func (s *Dataset) ProfileRowReader() parquet.RowReader { return s.profiles.RowReader() } + +func (s *Dataset) Symbols() symdb.SymbolsReader { return s.symbols } + +func (s *Dataset) Index() phlaredb.IndexReader { return s.tsdb.index } + +// Offset of the dataset section within the object. +func (s *Dataset) offset() uint64 { return s.meta.TableOfContents[0] } + +func (s *Dataset) section(sc Section) sectionDesc { + if int(s.meta.Format) >= len(sections) { + panic(fmt.Sprintf("bug: unknown dataset format: %d", s.meta.Format)) + } + f := sections[s.meta.Format] + if int(sc) >= len(f) { + panic(fmt.Sprintf("bug: invalid section index: %d", int(sc))) + } + return f[sc] +} + +func (s *Dataset) sectionOffset(sc Section) int64 { + return int64(s.meta.TableOfContents[s.section(sc).index]) +} + +func (s *Dataset) sectionSize(sc Section) int64 { + idx := s.section(sc).index + off := s.meta.TableOfContents[idx] + var next uint64 + if idx == len(s.meta.TableOfContents)-1 { + next = s.offset() + s.meta.Size + } else { + next = s.meta.TableOfContents[idx+1] + } + return int64(next - off) +} + +func (s *Dataset) inMemoryBuffer() []byte { + if s.obj.buf != nil { + // If the entire object is loaded into memory, + // return the dataset sub-slice. + lo := s.offset() + hi := lo + s.meta.Size + buf := s.obj.buf.B + return buf[lo:hi] + } + if s.buf != nil { + return s.buf.B + } + return nil +} + +func (s *Dataset) inMemoryBucket(buf []byte) objstore.Bucket { + bucket := memory.NewInMemBucket() + bucket.Set(s.obj.path, buf) + return objstore.NewBucket(bucket) +} diff --git a/pkg/block/dataset_index.go b/pkg/block/dataset_index.go new file mode 100644 index 0000000000..8b44f6bd1e --- /dev/null +++ b/pkg/block/dataset_index.go @@ -0,0 +1,134 @@ +package block + +import ( + "context" + "io" + "sort" + "sync" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/storage" + + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + memindex "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb/index" +) + +// datasetIndexEncBufferSize is the initial capacity hint for the +// underlying TSDB index writer's scratch encoding buffers. Dataset +// indexes have one entry per dataset within a tenant block, so a small +// hint is plenty; the buffers grow if needed. +const datasetIndexEncBufferSize = 1 << 14 + +// DatasetIndexWriter builds the per-tenant dataset TSDB index. +// +// The dataset index resembles the dataset (series) TSDB index, but uses +// the dataset position within the block (instead of the series ID) as the +// chunk SeriesIndex. The query backend uses this index to identify which +// datasets within a block match a given label selector without opening +// each dataset's TSDB index individually. +// +// Series are added one-at-a-time via AddSeries with an explicit dataset +// index. Callers that observe series row-by-row (e.g. compaction) are +// expected to deduplicate by fingerprint before calling AddSeries. +// +// Writers are pooled. Obtain one with NewDatasetIndexWriter and return +// it with Close once WriteTo has been called. +type DatasetIndexWriter struct { + series []seriesLabels + chunks []index.ChunkMeta + symbols map[string]struct{} +} + +var datasetIndexWriterPool = sync.Pool{ + New: func() any { + return &DatasetIndexWriter{symbols: make(map[string]struct{})} + }, +} + +// NewDatasetIndexWriter returns a DatasetIndexWriter ready for use, +// reusing one from a pool when possible. Callers must call Close to +// return it once they are done. +func NewDatasetIndexWriter() *DatasetIndexWriter { + return datasetIndexWriterPool.Get().(*DatasetIndexWriter) +} + +// Close returns the writer to the pool. After Close, the writer must +// not be used. +func (rw *DatasetIndexWriter) Close() { + rw.reset() + datasetIndexWriterPool.Put(rw) +} + +func (rw *DatasetIndexWriter) reset() { + rw.series = rw.series[:0] + rw.chunks = rw.chunks[:0] + clear(rw.symbols) +} + +// AddSeries adds a single series at the given dataset index. The caller +// is responsible for ensuring fingerprints are unique within the +// writer (e.g. by deduplicating consecutive rows with the same +// fingerprint at compaction time). +func (rw *DatasetIndexWriter) AddSeries(idx uint32, labels phlaremodel.Labels, fp model.Fingerprint) { + cloned := labels.Clone() + for _, l := range cloned { + rw.symbols[l.Name] = struct{}{} + rw.symbols[l.Value] = struct{}{} + } + rw.series = append(rw.series, seriesLabels{ + labels: cloned, + fingerprint: fp, + }) + rw.chunks = append(rw.chunks, index.ChunkMeta{ + SeriesIndex: idx, + }) +} + +// Empty reports whether the writer has no series. +func (rw *DatasetIndexWriter) Empty() bool { return len(rw.series) == 0 } + +// WriteTo encodes the accumulated series into a TSDB index and writes +// the encoded bytes directly to dst, returning the number of bytes +// written. After WriteTo, the accumulated state is reset; the writer +// can be reused for another tenant or returned to the pool via Close. +func (rw *DatasetIndexWriter) WriteTo(dst io.Writer) (int64, error) { + if len(rw.series) == 0 { + return 0, nil + } + + w, err := memindex.NewWriter(context.Background(), datasetIndexEncBufferSize) + if err != nil { + return 0, err + } + + symbols := make([]string, 0, len(rw.symbols)) + for s := range rw.symbols { + symbols = append(symbols, s) + } + sort.Strings(symbols) + + for _, symbol := range symbols { + if err = w.AddSymbol(symbol); err != nil { + return 0, err + } + } + + for i, series := range rw.series { + if err = w.AddSeries(storage.SeriesRef(i), series.labels, series.fingerprint, rw.chunks[i]); err != nil { + return 0, err + } + } + + if err = w.Close(); err != nil { + return 0, err + } + + bw := w.ReleaseIndexBuffer() + defer memindex.PutBufferWriterToPool(bw) + rw.reset() + + buf, _, _ := bw.Buffer() + n, err := dst.Write(buf) + return int64(n), err +} diff --git a/pkg/block/dataset_index_test.go b/pkg/block/dataset_index_test.go new file mode 100644 index 0000000000..d28851f12c --- /dev/null +++ b/pkg/block/dataset_index_test.go @@ -0,0 +1,43 @@ +package block + +import ( + "io" + "strconv" + "testing" + + "github.com/prometheus/common/model" + + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +func benchSeries(n int) []phlaremodel.Labels { + out := make([]phlaremodel.Labels, n) + for i := range out { + out[i] = phlaremodel.LabelsFromStrings( + phlaremodel.LabelNameServiceName, "svc", + "__name__", "process_cpu", + "pod", "pod-"+strconv.Itoa(i), + ) + } + return out +} + +func BenchmarkDatasetIndexWriter_WriteTo(b *testing.B) { + const datasetsPerTenant = 4 + const seriesPerDataset = 100 + series := benchSeries(seriesPerDataset) + + b.ReportAllocs() + for b.Loop() { + w := NewDatasetIndexWriter() + for d := range datasetsPerTenant { + for j, lbs := range series { + w.AddSeries(uint32(d), lbs, model.Fingerprint(uint64(d)<<32|uint64(j))) + } + } + if _, err := w.WriteTo(io.Discard); err != nil { + b.Fatal(err) + } + w.Close() + } +} diff --git a/pkg/block/metadata/metadata.go b/pkg/block/metadata/metadata.go new file mode 100644 index 0000000000..866dff3403 --- /dev/null +++ b/pkg/block/metadata/metadata.go @@ -0,0 +1,212 @@ +package metadata + +import ( + "encoding/binary" + "errors" + "fmt" + "hash/crc32" + "io" + "sync" + "time" + + "github.com/oklog/ulid/v2" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +var ErrMetadataInvalid = errors.New("metadata: invalid metadata") + +func Tenant(md *metastorev1.BlockMeta) string { + if md.Tenant <= 0 || int(md.Tenant) >= len(md.StringTable) { + return "" + } + return md.StringTable[md.Tenant] +} + +func Timestamp(md *metastorev1.BlockMeta) time.Time { + return time.UnixMilli(int64(ulid.MustParse(md.Id).Time())) +} + +func Sanitize(md *metastorev1.BlockMeta) error { + // TODO(kolesnikovae): Implement. + _, err := ulid.Parse(md.Id) + return err +} + +var stringTablePool = sync.Pool{ + New: func() any { return NewStringTable() }, +} + +type StringTable struct { + Dict map[string]int32 + Strings []string +} + +func NewStringTable() *StringTable { + var empty string + return &StringTable{ + Dict: map[string]int32{empty: 0}, + Strings: []string{empty}, + } +} + +func (t *StringTable) IsEmpty() bool { + if len(t.Strings) == 0 { + return true + } + return len(t.Strings) == 1 && t.Strings[0] == "" +} + +func (t *StringTable) Reset() { + clear(t.Dict) + t.Dict[""] = 0 + t.Strings[0] = "" + t.Strings = t.Strings[:1] +} + +func (t *StringTable) Clone() *StringTable { + n := &StringTable{ + Dict: make(map[string]int32, len(t.Dict)), + Strings: make([]string, len(t.Strings)), + } + for k, v := range t.Dict { + n.Dict[k] = v + } + copy(n.Strings, t.Strings) + return n +} + +func (t *StringTable) Put(s string) int32 { + if i, ok := t.Dict[s]; ok { + return i + } + i := int32(len(t.Strings)) + t.Strings = append(t.Strings, s) + t.Dict[s] = i + return i +} + +func (t *StringTable) Lookup(i int32) string { + if i < 0 || int(i) >= len(t.Strings) { + return "" + } + return t.Strings[i] +} + +func (t *StringTable) LookupString(s string) int32 { + if i, ok := t.Dict[s]; ok { + return i + } + return -1 +} + +// Import strings from the metadata entry and update the references. +func (t *StringTable) Import(src *metastorev1.BlockMeta) { + if len(src.StringTable) < 2 { + return + } + // TODO: Pool? + lut := make([]int32, len(src.StringTable)) + for i, s := range src.StringTable { + x := t.Put(s) + lut[i] = x + } + src.Tenant = lut[src.Tenant] + src.CreatedBy = lut[src.CreatedBy] + for _, ds := range src.Datasets { + ds.Tenant = lut[ds.Tenant] + ds.Name = lut[ds.Name] + var skip int + for i, v := range ds.Labels { + if i == skip { + skip += int(v)*2 + 1 + continue + } + ds.Labels[i] = lut[v] + } + } +} + +func (t *StringTable) Export(dst *metastorev1.BlockMeta) { + n := stringTablePool.Get().(*StringTable) + defer stringTablePool.Put(n) + dst.Tenant = n.Put(t.Lookup(dst.Tenant)) + dst.CreatedBy = n.Put(t.Lookup(dst.CreatedBy)) + for _, ds := range dst.Datasets { + ds.Tenant = n.Put(t.Lookup(ds.Tenant)) + ds.Name = n.Put(t.Lookup(ds.Name)) + var skip int + for i, v := range ds.Labels { + if i == skip { + skip += int(v)*2 + 1 + continue + } + ds.Labels[i] = n.Put(t.Lookup(ds.Labels[i])) + } + } + dst.StringTable = make([]string, len(n.Strings)) + copy(dst.StringTable, n.Strings) + n.Reset() +} + +func (t *StringTable) Load(x iter.Iterator[string]) error { + for x.Next() { + t.Put(x.At()) + } + return x.Err() +} + +func OpenStringTable(src *metastorev1.BlockMeta) *StringTable { + t := &StringTable{ + Dict: make(map[string]int32, len(src.StringTable)), + Strings: src.StringTable, + } + for i, s := range src.StringTable { + t.Dict[s] = int32(i) + } + return t +} + +var castagnoli = crc32.MakeTable(crc32.Castagnoli) + +// Encode writes the metadata to the writer in the following format: +// +// raw | protobuf-encoded metadata +// be_uint32 | size of the raw metadata +// be_uint32 | CRC32 of the raw metadata and size +func Encode(w io.Writer, md *metastorev1.BlockMeta) error { + crc := crc32.New(castagnoli) + w = io.MultiWriter(w, crc) + b, _ := md.MarshalVT() + n, err := w.Write(b) + if err != nil { + return err + } + if err = binary.Write(w, binary.BigEndian, uint32(n)); err != nil { + return err + } + return binary.Write(w, binary.BigEndian, crc.Sum32()) +} + +// Decode metadata encoded with Encode. +// +// Note that the metadata decoded from the object has zero Size field, +// as the block size is not known at the point the metadata is written. +// It is expected that the caller has access to the block object and +// can set the Size field after reading the metadata. +func Decode(b []byte, md *metastorev1.BlockMeta) error { + if len(b) <= 8 { + return fmt.Errorf("%w: invalid size", ErrMetadataInvalid) + } + crc := binary.BigEndian.Uint32(b[len(b)-4:]) + size := binary.BigEndian.Uint32(b[len(b)-8 : len(b)-4]) + off := len(b) - 8 - int(size) + if off < 0 { + return fmt.Errorf("%w: invalid size", ErrMetadataInvalid) + } + if crc32.Checksum(b[off:len(b)-4], castagnoli) != crc { + return fmt.Errorf("%w: invalid CRC", ErrMetadataInvalid) + } + return md.UnmarshalVT(b[off : len(b)-8]) +} diff --git a/pkg/block/metadata/metadata_labels.go b/pkg/block/metadata/metadata_labels.go new file mode 100644 index 0000000000..58e7b12e36 --- /dev/null +++ b/pkg/block/metadata/metadata_labels.go @@ -0,0 +1,414 @@ +package metadata + +import ( + goiter "iter" + "slices" + "strings" + "unsafe" + + "github.com/prometheus/prometheus/model/labels" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +// TODO(kolesnikovae): LabelBuilder pool. + +const ( + LabelNameTenantDataset = "__tenant_dataset__" + LabelValueDatasetTSDBIndex = "dataset_tsdb_index" + LabelNameUnsymbolized = "__unsymbolized__" +) + +type LabelBuilder struct { + strings *StringTable + labels []int32 + seen map[string]struct{} +} + +func NewLabelBuilder(strings *StringTable) *LabelBuilder { + return &LabelBuilder{strings: strings} +} + +func (lb *LabelBuilder) WithLabelSet(pairs ...string) *LabelBuilder { + if len(pairs)%2 == 1 { + panic("expected even number of values") + } + s := len(lb.labels) + lb.labels = slices.Grow(lb.labels, len(pairs)+1)[:s+len(pairs)+1] + lb.labels[s] = int32(len(pairs) / 2) + for i := range pairs { + lb.labels[s+i+1] = lb.strings.Put(pairs[i]) + } + return lb +} + +func (lb *LabelBuilder) Put(x []int32, strings []string) { + if len(x) == 0 { + return + } + if lb.seen == nil { + lb.seen = make(map[string]struct{}) + } + var skip int + for i, v := range x { + if i == skip { + skip += int(v)*2 + 1 + continue + } + x[i] = lb.strings.Put(strings[v]) + } + lb.labels = slices.Grow(lb.labels, len(x)) + pairs := LabelPairs(x) + for pairs.Next() { + lb.putPairs(pairs.At()) + } +} + +func (lb *LabelBuilder) putPairs(p []int32) { + if len(p) == 0 { + return + } + // We only copy the labels if this is the first time we see it. + // The fact that we assume that the order of labels is the same + // across all datasets is a precondition, therefore, we can + // use pairs as a key. + k := int32string(p) + if _, ok := lb.seen[k]; ok { + return + } + lb.labels = append(lb.labels, int32(len(p)/2)) + lb.labels = append(lb.labels, p...) + lb.seen[strings.Clone(k)] = struct{}{} +} + +func (lb *LabelBuilder) Build() []int32 { + c := make([]int32, len(lb.labels)) + copy(c, lb.labels) + lb.labels = lb.labels[:0] + clear(lb.seen) + return c +} + +func FindDatasets(md *metastorev1.BlockMeta, matchers ...*labels.Matcher) goiter.Seq[*metastorev1.Dataset] { + st := NewStringTable() + st.Import(md) + lm := NewLabelMatcher(st.Strings, matchers) + if !lm.IsValid() { + return func(func(*metastorev1.Dataset) bool) {} + } + return func(yield func(*metastorev1.Dataset) bool) { + for i := range md.Datasets { + ds := md.Datasets[i] + if !lm.Matches(ds.Labels) { + continue + } + if !yield(ds) { + return + } + } + } +} + +func LabelPairs(ls []int32) iter.Iterator[[]int32] { return &labelPairs{labels: ls} } + +type labelPairs struct { + labels []int32 + off int + len int +} + +func (p *labelPairs) Err() error { return nil } +func (p *labelPairs) Close() error { return nil } + +func (p *labelPairs) At() []int32 { return p.labels[p.off : p.off+p.len] } + +func (p *labelPairs) Next() bool { + if p.len > 0 { + p.off += p.len + } + if p.off >= len(p.labels) { + return false + } + p.len = int(p.labels[p.off]) * 2 + p.off++ + return p.off+p.len <= len(p.labels) +} + +type LabelMatcher struct { + eq []matcher + neq []matcher + keep []int32 + keepStr []string + + strings []string + checked map[string]bool + matched int32 + nomatch bool +} + +type matcher struct { + *labels.Matcher + name int32 +} + +func NewLabelMatcher(strings []string, matchers []*labels.Matcher, keep ...string) *LabelMatcher { + s := make(map[string]int32, len(matchers)*2+len(keep)) + for _, m := range matchers { + s[m.Name] = 0 + s[m.Value] = 0 + } + for _, k := range keep { + s[k] = 0 + } + for i, x := range strings { + if v, ok := s[x]; ok && v == 0 { + s[x] = int32(i) + } + } + lm := &LabelMatcher{ + eq: make([]matcher, 0, len(matchers)), + neq: make([]matcher, 0, len(matchers)), + keep: make([]int32, len(keep)), + keepStr: keep, + checked: make(map[string]bool), + strings: strings, + } + for _, m := range matchers { + if m.Name == "" { + continue + } + n := s[m.Name] + switch m.Type { + case labels.MatchEqual: + if v := s[m.Value]; m.Value != "" && (n < 1 || v < 1) { + lm.nomatch = true + return lm + } + lm.eq = append(lm.eq, matcher{Matcher: m, name: n}) + case labels.MatchRegexp: + lm.eq = append(lm.eq, matcher{Matcher: m, name: n}) + case labels.MatchNotEqual, labels.MatchNotRegexp: + lm.neq = append(lm.neq, matcher{Matcher: m, name: n}) + } + } + // Find the indices of the labels to keep. + // If the label is not found or is an empty string, + // it will always be an empty string at the output. + for i, k := range keep { + lm.keep[i] = s[k] + } + return lm +} + +func (lm *LabelMatcher) IsValid() bool { return !lm.nomatch } + +// Matches reports whether the given set of labels matches the matchers. +// Note that at least one labels set must satisfy matchers to return true. +// For negations, all labels sets must satisfy the matchers to return true. +// TODO(kolesnikovae): This might be really confusing; it's worth relaxing it. +func (lm *LabelMatcher) Matches(labels []int32) bool { + pairs := LabelPairs(labels) + var matches bool + for pairs.Next() { + if lm.MatchesPairs(pairs.At()) { + matches = true + // If no keep labels are specified, we can return early. + // Otherwise, we need to scan all the label sets to + // collect matching ones. + if len(lm.keep) == 0 { + return true + } + } + } + return matches +} + +// CollectMatches returns a new set of labels with only the labels +// that satisfy the match expressions and that are in the keep list. +func (lm *LabelMatcher) CollectMatches(dst, labels []int32) ([]int32, bool) { + pairs := LabelPairs(labels) + var matches bool + for pairs.Next() { + p := pairs.At() + if lm.MatchesPairs(p) { + matches = true + // If no keep labels are specified, we can return early. + // Otherwise, we need to scan all the label sets to + // collect matching ones. + if len(lm.keep) == 0 { + return dst, true + } + dst = lm.strip(dst, p) + } + } + return dst, matches +} + +// strip returns a new length-prefixed slice of pairs +// with only the labels that are in the keep list. +func (lm *LabelMatcher) strip(dst, pairs []int32) []int32 { + // Length-prefix stub: we only know it after we iterate + // over the pairs. + s := len(dst) + c := len(lm.keep) * 2 + dst = slices.Grow(dst, c+1) + dst = append(dst, 0) + var m int32 + for _, n := range lm.keep { + if n < 1 { + // Ignore not found labels. + continue + } + for k := 0; k < len(pairs); k += 2 { + if pairs[k] == n { + dst = append(dst, pairs[k], pairs[k+1]) + m++ + break + } + } + } + // Write the actual number of pairs as a prefix. + dst[s] = m + return dst +} + +func (lm *LabelMatcher) MatchesPairs(pairs []int32) bool { + k := int32string(pairs) + m, found := lm.checked[k] + if !found { + m = lm.checkMatches(pairs) + lm.checked[strings.Clone(k)] = m + if m { + lm.matched++ + } + } + return m +} + +func (lm *LabelMatcher) checkMatches(pairs []int32) bool { + if len(pairs)%2 == 1 { + // Invalid pairs. + return false + } + for _, m := range lm.eq { + var matches bool + for k := 0; k < len(pairs); k += 2 { + if pairs[k] != m.name { + continue + } + v := lm.strings[pairs[k+1]] + matches = m.Matches(v) + break + } + if !matches { + return false + } + } + // At this point, we know that all eq matchers have matched. + for _, m := range lm.neq { + for k := 0; k < len(pairs); k += 2 { + if pairs[k] != m.name { + continue + } + v := lm.strings[pairs[k+1]] + if !m.Matches(v) { + return false + } + break + } + } + return true +} + +type LabelsCollector struct { + strings *StringTable + dict map[string]struct{} + tmp []int32 + keys []int32 +} + +func NewLabelsCollector(labels ...string) *LabelsCollector { + s := &LabelsCollector{ + dict: make(map[string]struct{}), + strings: NewStringTable(), + } + s.keys = make([]int32, len(labels)) + s.tmp = make([]int32, len(labels)) + for i, k := range labels { + s.keys[i] = s.strings.Put(k) + } + return s +} + +// CollectMatches from the given matcher. +// +// The matcher and collect MUST be configured to keep the same +// set of labels, in the exact order. +// +// A single collector may collect labels from multiple matchers. +func (s *LabelsCollector) CollectMatches(lm *LabelMatcher) { + if len(lm.keep) == 0 || lm.nomatch || len(lm.checked) == 0 { + return + } + for set, match := range lm.checked { + if !match { + continue + } + // Project values of the keep labels to tmp, + // and resolve their strings. + clear(s.tmp) + p := int32s(set) + // Note that we're using the matcher's keep labels + // and not local 'keys'. + for i, n := range lm.keep { + for k := 0; k < len(p); k += 2 { + if p[k] == n { + s.tmp[i] = p[k+1] + break + } + } + } + for i := range s.tmp { + s.tmp[i] = s.strings.Put(lm.strings[s.tmp[i]]) + } + // Check if we already saw the label set. + x := int32string(s.tmp) + if _, ok := s.dict[x]; ok { + continue + } + s.dict[strings.Clone(x)] = struct{}{} + } +} + +func (s *LabelsCollector) Unique() goiter.Seq[*typesv1.Labels] { + return func(yield func(*typesv1.Labels) bool) { + for k := range s.dict { + l := &typesv1.Labels{Labels: make([]*typesv1.LabelPair, len(s.keys))} + for i, v := range int32s(k) { + l.Labels[i] = &typesv1.LabelPair{ + Name: s.strings.Strings[s.keys[i]], + Value: s.strings.Strings[v], + } + } + if !yield(l) { + return + } + } + } +} + +func int32string(data []int32) string { + if len(data) == 0 { + return "" + } + return unsafe.String((*byte)(unsafe.Pointer(&data[0])), len(data)*4) +} + +func int32s(s string) []int32 { + if len(s) == 0 { + return nil + } + return unsafe.Slice((*int32)(unsafe.Pointer(unsafe.StringData(s))), len(s)/4) +} diff --git a/pkg/block/metadata/metadata_labels_test.go b/pkg/block/metadata/metadata_labels_test.go new file mode 100644 index 0000000000..d976bc6f83 --- /dev/null +++ b/pkg/block/metadata/metadata_labels_test.go @@ -0,0 +1,276 @@ +package metadata + +import ( + "slices" + "testing" + + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +func TestLabelBuilder_Put(t *testing.T) { + strings := NewStringTable() + b := NewLabelBuilder(strings) + + // a=b, a=b; a=b, a=b; + b.Put([]int32{2, 1, 2, 1, 2, 2, 1, 2, 1, 2}, []string{"", "a", "b"}) + b.Put([]int32{2, 1, 2, 1, 2, 2, 1, 2, 1, 2}, []string{"", "a", "b"}) + + // c=d, c=d; c=d, c=d; + b.Put([]int32{2, 1, 2, 1, 2, 2, 1, 2, 1, 2}, []string{"", "c", "d"}) + b.Put([]int32{2, 1, 2, 1, 2}, []string{"", "c", "d"}) + + assert.Equal(t, []int32{ + 2, 1, 2, 1, 2, + 2, 3, 4, 3, 4, + }, b.Build()) +} + +func labelStrings(v []int32, s *StringTable) []string { + var ls []string + pairs := LabelPairs(v) + for pairs.Next() { + p := pairs.At() + var l string + for len(p) > 0 { + l += s.Lookup(p[0]) + "=" + s.Lookup(p[1]) + ";" + p = p[2:] + } + ls = append(ls, l) + } + return ls +} + +func TestLabelMatcher_Matches(t *testing.T) { + strings := NewStringTable() + setA := NewLabelBuilder(strings). + WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:a"). + WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:b"). + WithLabelSet("service_name", "service_a", "__profile_type__", "memory"). + Build() + assert.Equal(t, []string{ + "service_name=service_a;__profile_type__=cpu:a;", + "service_name=service_a;__profile_type__=cpu:b;", + "service_name=service_a;__profile_type__=memory;", + }, labelStrings(setA, strings)) + + setB := NewLabelBuilder(strings). + WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:a"). + WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:b"). + Build() + assert.Equal(t, []string{ + "service_name=service_b;__profile_type__=cpu:a;", + "service_name=service_b;__profile_type__=cpu:b;", + }, labelStrings(setB, strings)) + + keepLabels := []string{"service_name", "__profile_type__", "none"} + m := NewLabelMatcher(strings.Strings, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "cpu:a")}, + keepLabels...) + assert.True(t, m.IsValid()) + + expected := []bool{true, false, false, true, false} + matches := make([]bool, 0, len(expected)) + + pairs := LabelPairs(setA) + for pairs.Next() { + matches = append(matches, m.MatchesPairs(pairs.At())) + } + + pairs = LabelPairs(setB) + for pairs.Next() { + matches = append(matches, m.MatchesPairs(pairs.At())) + } + assert.Equal(t, expected, matches) + + t.Run("LabelCollector", func(t *testing.T) { + c := NewLabelsCollector(keepLabels...) + c.CollectMatches(m) + + collected := slices.Collect(c.Unique()) + slices.SortFunc(collected, model.CompareLabels) + + // The label order matches the input. + assert.Equal(t, []*typesv1.Labels{ + { + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service_a"}, + {Name: "__profile_type__", Value: "cpu:a"}, + {Name: "none", Value: ""}, + }, + }, + { + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service_b"}, + {Name: "__profile_type__", Value: "cpu:a"}, + {Name: "none", Value: ""}, + }, + }, + }, collected) + }) +} + +func TestLabelMatcher_Collect(t *testing.T) { + strings := NewStringTable() + setA := NewLabelBuilder(strings). + WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:a"). + WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:b"). + WithLabelSet("service_name", "service_a", "__profile_type__", "memory"). + Build() + + setB := NewLabelBuilder(strings). + WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:a"). + WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:b"). + Build() + + m := NewLabelMatcher(strings.Strings, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_a"), + labels.MustNewMatcher(labels.MatchRegexp, "__profile_type__", "cpu.*")}, + "service_name", + "none") + assert.True(t, m.IsValid()) + + matches, ok := m.CollectMatches(nil, setA) + assert.True(t, ok) + assert.Equal(t, []string{ + "service_name=service_a;", + "service_name=service_a;", + }, labelStrings(matches, strings)) + + matches = matches[:0] + matches, ok = m.CollectMatches(matches, setB) + assert.False(t, ok) + assert.Len(t, matches, 0) +} + +func Benchmark_LabelMatcher_Matches(b *testing.B) { + strings := NewStringTable() + + ls := NewLabelBuilder(strings). + WithLabelSet("service_name", "service_a", "__profile_type__", "cpu"). + Build() + + m := NewLabelMatcher(strings.Strings, + []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_a")}, + "service_name", "__profile_type__") + + assert.True(b, m.IsValid()) + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + pairs := LabelPairs(ls) + for pairs.Next() { + m.MatchesPairs(pairs.At()) + } + } +} + +func TestFindDatasets(t *testing.T) { + strings := NewStringTable() + setA := NewLabelBuilder(strings). + WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:a"). + WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:b"). + WithLabelSet("service_name", "service_a", "__profile_type__", "memory"). + Build() + + setB := NewLabelBuilder(strings). + WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:a"). + WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:b"). + Build() + + md := &metastorev1.BlockMeta{ + Datasets: []*metastorev1.Dataset{ + {Name: 3, Labels: setA}, + {Name: 4, Labels: setB}, + }, + StringTable: strings.Strings, + } + + for _, test := range []struct { + matchers []*labels.Matcher + expected []int32 + }{ + { + expected: []int32{3, 4}, + }, + { + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")}, + }, + { + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_b")}, + expected: []int32{4}, + }, + { + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchNotEqual, "service_name", "service_b")}, + expected: []int32{3}, + }, + { + matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "service_name", ".*")}, + expected: []int32{3, 4}, + }, + { + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory"), + }, + expected: []int32{3}, + }, + { + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory"), + labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_a"), + }, + expected: []int32{3}, + }, + { + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory"), + labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_b"), + }, + }, + } { + var actual []int32 + FindDatasets(md, test.matchers...)(func(v *metastorev1.Dataset) bool { + actual = append(actual, v.Name) + return true + }) + assert.Equal(t, test.expected, actual) + } +} + +func Test_LabelMatcher_Skip(t *testing.T) { + strings := []string{"", "foo", "bar", "baz", "qux"} + + type testCase struct { + valid bool + matches []*labels.Matcher + } + + for _, test := range []testCase{ + {true, []*labels.Matcher{}}, + {true, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), + }}, + {true, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchRegexp, "foo", "b.*"), + }}, + {true, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchRegexp, "fee", ""), + }}, + {true, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchNotEqual, "foo", ""), + }}, + {true, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchNotRegexp, "far", ""), + }}, + {false, []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), + labels.MustNewMatcher(labels.MatchEqual, "har", "bor"), + }}, + } { + assert.Equal(t, test.valid, NewLabelMatcher(strings, test.matches).IsValid()) + } +} diff --git a/pkg/block/metadata/metadata_test.go b/pkg/block/metadata/metadata_test.go new file mode 100644 index 0000000000..c5395dc0aa --- /dev/null +++ b/pkg/block/metadata/metadata_test.go @@ -0,0 +1,242 @@ +package metadata + +import ( + "bytes" + "testing" + + "github.com/oklog/ulid/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" +) + +func TestMetadata_New(t *testing.T) { + blockID := ulid.MustNew(123, bytes.NewReader([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})).String() + strings := NewStringTable() + md := &metastorev1.BlockMeta{ + FormatVersion: 0, + Id: blockID, + Tenant: 0, + Shard: 1, + CompactionLevel: 0, + MinTime: 123, + MaxTime: 456, + CreatedBy: strings.Put("ingester-a"), + Size: 567, + Datasets: nil, + StringTable: nil, + } + + b := NewLabelBuilder(strings) + for _, tenant := range []string{"tenant-a", "tenant-b"} { + for _, dataset := range []string{"service_a", "service_b"} { + ds := &metastorev1.Dataset{ + Tenant: strings.Put(tenant), + Name: strings.Put(dataset), + MinTime: 123, + MaxTime: 456, + TableOfContents: []uint64{1, 2, 3}, + Size: 567, + Labels: nil, + } + for _, n := range []string{"cpu", "memory"} { + b.WithLabelSet("service_name", dataset, "__profile_type__", n) + } + ds.Labels = b.Build() + md.Datasets = append(md.Datasets, ds) + } + } + md.StringTable = strings.Strings + + expected := &metastorev1.BlockMeta{ + FormatVersion: 0, + Id: "000000003V000G40R40M30E209", + Tenant: 0, + Shard: 1, + CompactionLevel: 0, + MinTime: 123, + MaxTime: 456, + CreatedBy: 1, + Size: 567, + Datasets: []*metastorev1.Dataset{ + { + Tenant: 2, + Name: 3, + MinTime: 123, + MaxTime: 456, + TableOfContents: []uint64{1, 2, 3}, + Size: 567, + Labels: []int32{2, 4, 3, 5, 6, 2, 4, 3, 5, 7}, + }, + { + Tenant: 2, + Name: 8, + MinTime: 123, + MaxTime: 456, + TableOfContents: []uint64{1, 2, 3}, + Size: 567, + Labels: []int32{2, 4, 8, 5, 6, 2, 4, 8, 5, 7}, + }, + { + Tenant: 9, + Name: 3, + MinTime: 123, + MaxTime: 456, + TableOfContents: []uint64{1, 2, 3}, + Size: 567, + Labels: []int32{2, 4, 3, 5, 6, 2, 4, 3, 5, 7}, + }, + { + Tenant: 9, + Name: 8, + MinTime: 123, + MaxTime: 456, + TableOfContents: []uint64{1, 2, 3}, + Size: 567, + Labels: []int32{2, 4, 8, 5, 6, 2, 4, 8, 5, 7}, + }, + }, + StringTable: []string{ + "", "ingester-a", + "tenant-a", "service_a", "service_name", "__profile_type__", "cpu", "memory", + "service_b", "tenant-b", + }, + } + + assert.Equal(t, expected, md) +} + +func TestMetadataStrings_Import(t *testing.T) { + md1 := &metastorev1.BlockMeta{ + Id: "block_id", + Tenant: 0, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{ + {Tenant: 2, Name: 3, Labels: []int32{2, 10, 3, 11, 4, 2, 10, 3, 11, 5, 2, 10, 3, 11, 6}}, + {Tenant: 7, Name: 8, Labels: []int32{2, 10, 8, 11, 5, 2, 10, 8, 11, 6, 2, 10, 8, 11, 9}}, + }, + StringTable: []string{ + "", "ingester", + "tenant-a", "dataset-a", "1", "2", "3", + "tenant-b", "dataset-b", "4", + "service_name", "__profile_type__", + }, + } + + table := NewStringTable() + md1c := md1.CloneVT() + table.Import(md1c) + assert.Equal(t, md1, md1c) + assert.Equal(t, table.Strings, md1.StringTable) + + // Exactly the same metadata. + md2 := md1.CloneVT() + table.Import(md2) + assert.Len(t, md2.StringTable, 12) + assert.Len(t, table.Strings, 12) + assert.Equal(t, table.Strings, md2.StringTable) + + md3 := &metastorev1.BlockMeta{ + Id: "block_id_3", + Tenant: 0, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{ + {Tenant: 2, Name: 3, Labels: []int32{2, 10, 3, 11, 4, 2, 10, 3, 11, 5, 2, 10, 3, 11, 6}}, + {Tenant: 7, Name: 8, Labels: []int32{2, 10, 8, 11, 4, 2, 10, 8, 11, 9}}, + }, + StringTable: []string{ + "", "ingester", + "tenant-a", "dataset-a", "1", "2", "3", + "tenant-c", "dataset-c", "5", + "service_name", "__profile_type__", + }, + } + + table.Import(md3) + expected := &metastorev1.BlockMeta{ + Id: "block_id_3", + Tenant: 0, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{ + {Tenant: 2, Name: 3, Labels: []int32{2, 10, 3, 11, 4, 2, 10, 3, 11, 5, 2, 10, 3, 11, 6}}, + {Tenant: 12, Name: 13, Labels: []int32{2, 10, 13, 11, 4, 2, 10, 13, 11, 14}}, + }, + StringTable: []string{ + "", "ingester", + "tenant-a", "dataset-a", "1", "2", "3", + "tenant-c", "dataset-c", "5", + "service_name", "__profile_type__", + }, + } + + assert.Equal(t, expected, md3) + assert.Len(t, table.Strings, 15) +} + +func TestMetadataStrings_Export(t *testing.T) { + table := NewStringTable() + for _, s := range []string{ + "", "x1", "x2", "x3", "x4", "x5", + "ingester", + "tenant-a", "dataset-a", "1", "2", "3", + "tenant-b", "dataset-b", "4", + "service_name", "__profile_type__", + } { + table.Put(s) + } + + md := &metastorev1.BlockMeta{ + Id: "1", + Tenant: 0, + CreatedBy: 6, + Datasets: []*metastorev1.Dataset{ + {Tenant: 7, Name: 8, Labels: []int32{2, 15, 8, 16, 9, 2, 15, 8, 16, 10, 2, 15, 8, 16, 11}}, + {Tenant: 12, Name: 13, Labels: []int32{2, 15, 13, 16, 10, 2, 15, 13, 16, 11, 2, 15, 13, 16, 14}}, + }, + } + + table.Export(md) + + expected := &metastorev1.BlockMeta{ + Id: "1", + Tenant: 0, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{ + {Tenant: 2, Name: 3, Labels: []int32{2, 4, 3, 5, 6, 2, 4, 3, 5, 7, 2, 4, 3, 5, 8}}, + {Tenant: 9, Name: 10, Labels: []int32{2, 4, 10, 5, 7, 2, 4, 10, 5, 8, 2, 4, 10, 5, 11}}, + }, + StringTable: []string{ + "", "ingester", + "tenant-a", "dataset-a", "service_name", "__profile_type__", "1", "2", "3", + "tenant-b", "dataset-b", "4", + }, + } + + assert.Equal(t, expected, md) +} + +func TestMetadata_EncodeDecode(t *testing.T) { + md := &metastorev1.BlockMeta{ + Id: "1", + Tenant: 0, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{ + {Tenant: 2, Name: 3, Labels: []int32{2, 4, 3, 5, 6, 2, 4, 3, 5, 7, 2, 4, 3, 5, 8}}, + {Tenant: 9, Name: 10, Labels: []int32{2, 4, 10, 5, 7, 2, 4, 10, 5, 8, 2, 4, 10, 5, 11}}, + }, + StringTable: []string{ + "", "ingester", + "tenant-a", "dataset-a", "service_name", "__profile_type__", "1", "2", "3", + "tenant-b", "dataset-b", "4", + }, + } + + var buf bytes.Buffer + require.NoError(t, Encode(&buf, md)) + + var d metastorev1.BlockMeta + raw := append([]byte("garbage"), buf.Bytes()...) + require.NoError(t, Decode(raw, &d)) + assert.Equal(t, md, &d) +} diff --git a/pkg/block/object.go b/pkg/block/object.go new file mode 100644 index 0000000000..bc9de7de35 --- /dev/null +++ b/pkg/block/object.go @@ -0,0 +1,334 @@ +package block + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + "path/filepath" + "strconv" + "strings" + + "github.com/grafana/dskit/multierror" + "github.com/oklog/ulid/v2" + "golang.org/x/sync/errgroup" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/bufferpool" + "github.com/grafana/pyroscope/v2/pkg/util/refctr" +) + +// TODO Next: +// - Separate storages for segments and compacted blocks. +// - Local cache? Useful for all-in-one deployments. +// - Distributed cache. + +// Object represents a block or a segment in the object storage. +type Object struct { + path string + meta *metastorev1.BlockMeta + storage objstore.BucketReader + local *objstore.ReadOnlyFile + + refs refctr.Counter + buf *bufferpool.Buffer + err error + + memSize int + downloadDir string +} + +type ObjectOption func(*Object) + +func WithObjectPath(path string) ObjectOption { + return func(obj *Object) { + obj.path = path + } +} + +func WithObjectMaxSizeLoadInMemory(size int) ObjectOption { + return func(obj *Object) { + obj.memSize = size + } +} + +func WithObjectDownload(dir string) ObjectOption { + return func(obj *Object) { + obj.downloadDir = dir + } +} + +func NewObjectFromPath(ctx context.Context, storage objstore.Bucket, path string, opts ...ObjectOption) (*Object, error) { + attrs, err := storage.Attributes(ctx, path) + if err != nil { + return nil, err + } + + defaultSize := int64(1 << 8) // 18) + offset := attrs.Size - defaultSize + if offset < 0 { + offset = 0 + } + size := attrs.Size - offset + + buf := bufferpool.GetBuffer(int(size)) + if err := objstore.ReadRange(ctx, buf, path, storage, offset, size); err != nil { + return nil, err + } + if size < 8 { + return nil, errors.New("invalid object too small") + } + + metaSize := int64(binary.BigEndian.Uint32(buf.B[len(buf.B)-8:len(buf.B)-4])) + 8 + if metaSize > size { + offset = attrs.Size - metaSize + + bufNew := bufferpool.GetBuffer(int(metaSize)) + if err := objstore.ReadRange(ctx, bufNew, path, storage, offset, metaSize-size); err != nil { + return nil, err + } + bufNew.B = append(bufNew.B, buf.B...) + buf = bufNew + + } + + var meta metastorev1.BlockMeta + if err := metadata.Decode(buf.B, &meta); err != nil { + return nil, err + } + meta.Size = uint64(attrs.Size) + + opts = append(opts, WithObjectPath(path)) + return NewObject(storage, &meta, opts...), nil +} + +func NewObject(storage objstore.Bucket, md *metastorev1.BlockMeta, opts ...ObjectOption) *Object { + o := &Object{ + storage: storage, + meta: md, + path: ObjectPath(md), + memSize: defaultObjectSizeLoadInMemory, + } + for _, opt := range opts { + opt(o) + } + return o +} + +func ObjectPath(md *metastorev1.BlockMeta) string { + return BuildObjectPath(metadata.Tenant(md), md.Shard, md.CompactionLevel, md.Id) +} + +func BuildObjectDir(tenant string, shard uint32) string { + topLevel := DirNameBlock + tenantDirName := tenant + if tenant == "" { + topLevel = DirNameSegment + tenantDirName = DirNameAnonTenant + } + var b strings.Builder + b.WriteString(topLevel) + b.WriteByte('/') + b.WriteString(strconv.Itoa(int(shard))) + b.WriteByte('/') + b.WriteString(tenantDirName) + b.WriteByte('/') + return b.String() +} + +func BuildObjectPath(tenant string, shard uint32, level uint32, block string) string { + topLevel := DirNameBlock + tenantDirName := tenant + if level == 0 { + topLevel = DirNameSegment + tenantDirName = DirNameAnonTenant + } + var b strings.Builder + b.WriteString(topLevel) + b.WriteByte('/') + b.WriteString(strconv.Itoa(int(shard))) + b.WriteByte('/') + b.WriteString(tenantDirName) + b.WriteByte('/') + b.WriteString(block) + b.WriteByte('/') + b.WriteString(FileNameDataObject) + return b.String() +} + +func MetadataDLQObjectPath(md *metastorev1.BlockMeta) string { + var b strings.Builder + tenantDirName := DirNameAnonTenant + if md.CompactionLevel > 0 { + tenantDirName = metadata.Tenant(md) + } + b.WriteString(DirNameDLQ) + b.WriteByte('/') + b.WriteString(strconv.Itoa(int(md.Shard))) + b.WriteByte('/') + b.WriteString(tenantDirName) + b.WriteByte('/') + b.WriteString(md.Id) + b.WriteByte('/') + b.WriteString(FileNameMetadataObject) + return b.String() +} + +func ParseBlockIDFromPath(path string) (ulid.ULID, error) { + tokens := strings.Split(path, "/") + if len(tokens) < 2 { + return ulid.ULID{}, fmt.Errorf("invalid path format: %s", path) + } + blockID, err := ulid.Parse(tokens[len(tokens)-2]) + if err != nil { + return ulid.ULID{}, fmt.Errorf("expected ULID: %s: %w", path, err) + } + return blockID, nil +} + +// Open opens the object, loading the data into memory if it's small enough. +// +// Open may be called multiple times concurrently, but the +// object is only initialized once. While it is possible to open +// the object repeatedly after close, the caller must pass the +// failure reason to the "CloseWithError" call, preventing further +// use, if applicable. +func (obj *Object) Open(ctx context.Context) error { + return obj.refs.IncErr(func() error { + return obj.open(ctx) + }) +} + +func (obj *Object) open(ctx context.Context) (err error) { + if obj.err != nil { + // In case if the object has been already closed with an error, + // and then released, return the error immediately. + return obj.err + } + if len(obj.meta.Datasets) == 0 { + return nil + } + // Estimate the size of the sections to process, and load the + // data into memory, if it's small enough. + if obj.meta.Size > uint64(obj.memSize) { + // Otherwise, download the object to the local directory, + // if it's specified, and use the local file. + if obj.downloadDir != "" { + return obj.Download(ctx) + } + // The object will be read from the storage directly. + return nil + } + obj.buf = bufferpool.GetBuffer(int(obj.meta.Size)) + defer func() { + if err != nil { + _ = obj.closeErr(err) + } + }() + if err = objstore.ReadRange(ctx, obj.buf, obj.path, obj.storage, 0, int64(obj.meta.Size)); err != nil { + return fmt.Errorf("loading object into memory %s: %w", obj.path, err) + } + return nil +} + +func (obj *Object) Close() error { + return obj.CloseWithError(nil) +} + +// CloseWithError closes the object, releasing all the acquired resources, +// once the last reference is released. If the provided error is not nil, +// the object will be marked as failed, preventing any further use. +func (obj *Object) CloseWithError(err error) (closeErr error) { + obj.refs.Dec(func() { + closeErr = obj.closeErr(err) + }) + return closeErr +} + +func (obj *Object) closeErr(err error) (closeErr error) { + obj.err = err + if obj.buf != nil { + bufferpool.Put(obj.buf) + obj.buf = nil + } + if obj.local != nil { + closeErr = obj.local.Close() + obj.local = nil + } + return closeErr +} + +func (obj *Object) Download(ctx context.Context) error { + dir := filepath.Join(obj.downloadDir, obj.meta.Id) + local, err := objstore.Download(ctx, obj.path, obj.storage, dir) + if err != nil { + return err + } + obj.storage = local + obj.local = local + return nil +} + +func (obj *Object) Metadata() *metastorev1.BlockMeta { return obj.meta } + +func (obj *Object) SetMetadata(md *metastorev1.BlockMeta) { obj.meta = md } + +// ReadMetadata fetches the full block metadata from the storage. +// It the object does not include the metadata offset, the method +// returns the metadata entry the object was opened with. +func (obj *Object) ReadMetadata(ctx context.Context) (*metastorev1.BlockMeta, error) { + if obj.meta.MetadataOffset == 0 { + return obj.meta, nil + } + offset := int64(obj.meta.MetadataOffset) + size := int64(obj.meta.Size) - offset + buf := bufferpool.GetBuffer(int(size)) + defer bufferpool.Put(buf) + if err := objstore.ReadRange(ctx, buf, obj.path, obj.storage, offset, size); err != nil { + return nil, fmt.Errorf("reading block metadata %s: %w", obj.path, err) + } + var meta metastorev1.BlockMeta + if err := metadata.Decode(buf.B, &meta); err != nil { + return nil, fmt.Errorf("decoding block metadata %s: %w", obj.path, err) + } + // Size is not stored in the metadata, so we need to preserve it. + meta.Size = obj.meta.Size + return &meta, nil +} + +func (obj *Object) IsNotExists(err error) bool { + return objstore.IsNotExist(obj.storage, err) +} + +// ObjectsFromMetas binds block metas to corresponding objects in the storage. +func ObjectsFromMetas(storage objstore.Bucket, blocks []*metastorev1.BlockMeta, options ...ObjectOption) Objects { + objects := make([]*Object, len(blocks)) + for i, m := range blocks { + objects[i] = NewObject(storage, m, options...) + } + return objects +} + +type Objects []*Object + +func (s Objects) Open(ctx context.Context) error { + g, ctx := errgroup.WithContext(ctx) + for i := range s { + i := i + g.Go(util.RecoverPanic(func() error { + return s[i].Open(ctx) + })) + } + return g.Wait() +} + +func (s Objects) Close() error { + var m multierror.MultiError + for i := range s { + m.Add(s[i].Close()) + } + return m.Err() +} diff --git a/pkg/block/section_profiles.go b/pkg/block/section_profiles.go new file mode 100644 index 0000000000..78cd346028 --- /dev/null +++ b/pkg/block/section_profiles.go @@ -0,0 +1,395 @@ +package block + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + + "github.com/parquet-go/parquet-go" + "github.com/prometheus/common/model" + + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/util/bufferpool" + "github.com/grafana/pyroscope/v2/pkg/util/build" + "github.com/grafana/pyroscope/v2/pkg/util/loser" +) + +func openProfileTable(_ context.Context, s *Dataset) (err error) { + offset := s.sectionOffset(SectionProfiles) + size := s.sectionSize(SectionProfiles) + if buf := s.inMemoryBuffer(); buf != nil { + offset -= int64(s.offset()) + s.profiles, err = openParquetFile( + s.inMemoryBucket(buf), s.obj.path, offset, size, + 0, // Do not prefetch the footer. + parquet.SkipBloomFilters(true), + parquet.FileReadMode(parquet.ReadModeSync), + parquet.ReadBufferSize(4<<10)) + } else { + s.profiles, err = openParquetFile( + s.obj.storage, s.obj.path, offset, size, + estimateFooterSize(size), + parquet.SkipBloomFilters(true), + parquet.FileReadMode(parquet.ReadModeAsync), + parquet.ReadBufferSize(estimateReadBufferSize(size))) + } + if err != nil { + return fmt.Errorf("opening profile parquet table: %w", err) + } + return nil +} + +type ParquetFile struct { + *parquet.File + + reader objstore.ReaderAtCloser + cancel context.CancelFunc + + storage objstore.BucketReader + path string + off int64 + size int64 +} + +func openParquetFile( + storage objstore.BucketReader, + path string, + offset, size, footerSize int64, + options ...parquet.FileOption, +) (p *ParquetFile, err error) { + // The context is used for GetRange calls and should not + // be canceled until the parquet file is closed. + ctx, cancel := context.WithCancel(context.Background()) + defer func() { + if err != nil { + cancel() + } + }() + + p = &ParquetFile{ + cancel: cancel, + storage: storage, + path: path, + off: offset, + size: size, + } + + r, err := storage.ReaderAt(ctx, path) + if err != nil { + return nil, fmt.Errorf("creating object reader: %w", err) + } + + var ra io.ReaderAt + ra = io.NewSectionReader(r, offset, size) + if footerSize > 0 { + buf := bufferpool.GetBuffer(int(footerSize)) + defer func() { + // Footer is not used after the file was opened. + bufferpool.Put(buf) + }() + if err = p.fetchFooter(ctx, buf, footerSize); err != nil { + return nil, err + } + rf := newReaderWithFooter(ra, buf.B, size) + defer rf.free() + ra = rf + } + + f, err := parquet.OpenFile(ra, size, options...) + if err != nil { + return nil, err + } + + p.reader = r + p.File = f + return p, nil +} + +func (f *ParquetFile) RowReader() parquet.RowReader { + return parquet.NewReader(f.File, schemav1.ProfilesSchema) +} + +func footerSize(buf []byte) int64 { + sb := buf[len(buf)-8 : len(buf)-4] + s := int64(binary.LittleEndian.Uint32(sb)) + s += 8 // Include the footer size itself and the magic signature. + return s +} + +func (f *ParquetFile) fetchFooter(ctx context.Context, buf *bufferpool.Buffer, estimatedSize int64) error { + if f.size < 8 { + return fmt.Errorf("file size is too small to contain a footer") + } + + // Ensure the footer is at least 8 bytes. + if estimatedSize < 8 { + estimatedSize = 8 + } + + // Ensure the footer is not bigger than the file. + if estimatedSize > f.size { + estimatedSize = f.size + } + + // Fetch the footer of estimated size at the estimated offset. + estimatedOffset := f.off + f.size - estimatedSize + if err := objstore.ReadRange(ctx, buf, f.path, f.storage, estimatedOffset, estimatedSize); err != nil { + return err + } + s := footerSize(buf.B) + if estimatedSize >= s { + // The footer has been fetched. + return nil + } + + // reset buffer + buf.B = buf.B[:0] + + // Fetch exact footer to buf for sure. + return objstore.ReadRange(ctx, buf, f.path, f.storage, f.off+f.size-s, s) +} + +func (f *ParquetFile) Close() error { + if f.cancel != nil { + f.cancel() + } + if f.reader != nil { + return f.reader.Close() + } + return nil +} + +func (f *ParquetFile) Column(ctx context.Context, columnName string, predicate query.Predicate) query.Iterator { + idx, _ := query.GetColumnIndexByPath(f.Root(), columnName) + if idx == -1 { + return query.NewErrIterator(fmt.Errorf("column '%s' not found in parquet table", columnName)) + } + return query.NewSyncIterator(ctx, f.RowGroups(), idx, columnName, 1<<10, predicate, columnName) +} + +type profilesWriter struct { + *parquet.GenericWriter[*schemav1.Profile] + buf []parquet.Row + profiles uint64 +} + +func newProfileWriter(pageBufferSize int, w io.Writer) *profilesWriter { + return &profilesWriter{ + buf: make([]parquet.Row, 1), + GenericWriter: parquet.NewGenericWriter[*schemav1.Profile](w, + parquet.CreatedBy("github.com/grafana/pyroscope/", build.Version, build.Revision), + parquet.PageBufferSize(pageBufferSize), + // Note that parquet keeps ALL RG pages in memory (ColumnPageBuffers). + parquet.MaxRowsPerRowGroup(maxRowsPerRowGroup), + schemav1.ProfilesSchema, + // parquet.ColumnPageBuffers(), + ), + } +} + +func (p *profilesWriter) writeRow(e ProfileEntry) error { + p.buf[0] = parquet.Row(e.Row) + _, err := p.WriteRows(p.buf) + p.profiles++ + return err +} + +type readerWithFooter struct { + reader io.ReaderAt + footer []byte + offset int64 + size int64 +} + +func newReaderWithFooter(r io.ReaderAt, footer []byte, size int64) *readerWithFooter { + footerSize := int64(len(footer)) + footerOffset := size - footerSize + return &readerWithFooter{ + reader: r, + footer: footer, + offset: footerOffset, + size: footerSize, + } +} + +func (f *readerWithFooter) hitsHeaderMagic(off, length int64) bool { + return off == 0 && length == 4 +} + +func (f *readerWithFooter) hitsFooter(off, length int64) bool { + return length <= f.size && off >= f.offset && off+length <= f.offset+f.size +} + +var parquetMagic = []byte("PAR1") + +func (f *readerWithFooter) free() { + f.footer = nil + f.size = -1 +} + +func (f *readerWithFooter) ReadAt(p []byte, off int64) (n int, err error) { + if f.hitsHeaderMagic(off, int64(len(p))) { + copy(p, parquetMagic) + return len(p), nil + } + if f.hitsFooter(off, int64(len(p))) { + copy(p, f.footer[off-f.offset:]) + return len(p), nil + } + return f.reader.ReadAt(p, off) +} + +type ProfileEntry struct { + Dataset *Dataset + + Timestamp int64 + Fingerprint model.Fingerprint + Labels phlaremodel.Labels + Row schemav1.ProfileRow +} + +func NewMergeRowProfileIterator(src []*Dataset) (iter.Iterator[ProfileEntry], error) { + its := make([]iter.Iterator[ProfileEntry], len(src)) + for i, s := range src { + it, err := NewProfileRowIterator(s) + if err != nil { + return nil, err + } + its[i] = it + } + if len(its) == 1 { + return its[0], nil + } + return &DedupeProfileRowIterator{ + Iterator: iter.NewTreeIterator(loser.New( + its, + ProfileEntry{ + Timestamp: math.MaxInt64, + }, + func(it iter.Iterator[ProfileEntry]) ProfileEntry { return it.At() }, + func(r1, r2 ProfileEntry) bool { + // first handle max profileRow if it's either r1 or r2 + if r1.Timestamp == math.MaxInt64 { + return false + } + if r2.Timestamp == math.MaxInt64 { + return true + } + // then handle normal profileRows + if cmp := phlaremodel.CompareLabelPairs(r1.Labels, r2.Labels); cmp != 0 { + return cmp < 0 + } + return r1.Timestamp < r2.Timestamp + }, + func(it iter.Iterator[ProfileEntry]) { _ = it.Close() }, + )), + }, nil +} + +type DedupeProfileRowIterator struct { + iter.Iterator[ProfileEntry] + + prevFP model.Fingerprint + prevTimeNanos int64 +} + +func (it *DedupeProfileRowIterator) Next() bool { + for { + if !it.Iterator.Next() { + return false + } + currentProfile := it.At() + if it.prevFP == currentProfile.Fingerprint && it.prevTimeNanos == currentProfile.Timestamp { + // skip duplicate profile + continue + } + it.prevFP = currentProfile.Fingerprint + it.prevTimeNanos = currentProfile.Timestamp + return true + } +} + +type profileRowIterator struct { + reader *Dataset + index phlaredb.IndexReader + profiles iter.Iterator[parquet.Row] + allPostings index.Postings + err error + + currentRow ProfileEntry + currentSeriesIdx uint32 + chunks []index.ChunkMeta +} + +func NewProfileRowIterator(s *Dataset) (iter.Iterator[ProfileEntry], error) { + k, v := index.AllPostingsKey() + tsdb := s.Index() + allPostings, err := tsdb.Postings(k, nil, v) + if err != nil { + return nil, err + } + return &profileRowIterator{ + reader: s, + index: tsdb, + profiles: phlareparquet.NewBufferedRowReaderIterator(s.ProfileRowReader(), 4), + allPostings: allPostings, + currentSeriesIdx: math.MaxUint32, + chunks: make([]index.ChunkMeta, 1), + }, nil +} + +func (p *profileRowIterator) At() ProfileEntry { + return p.currentRow +} + +func (p *profileRowIterator) Next() bool { + if !p.profiles.Next() { + return false + } + p.currentRow.Dataset = p.reader + p.currentRow.Row = schemav1.ProfileRow(p.profiles.At()) + seriesIndex := p.currentRow.Row.SeriesIndex() + p.currentRow.Timestamp = p.currentRow.Row.TimeNanos() + // do we have a new series? + if seriesIndex == p.currentSeriesIdx { + return true + } + p.currentSeriesIdx = seriesIndex + if !p.allPostings.Next() { + if err := p.allPostings.Err(); err != nil { + p.err = err + return false + } + p.err = errors.New("unexpected end of postings") + return false + } + + fp, err := p.index.Series(p.allPostings.At(), &p.currentRow.Labels, &p.chunks) + if err != nil { + p.err = err + return false + } + p.currentRow.Fingerprint = model.Fingerprint(fp) + return true +} + +func (p *profileRowIterator) Err() error { + if p.err != nil { + return p.err + } + return p.profiles.Err() +} + +func (p *profileRowIterator) Close() error { + return p.reader.Close() +} diff --git a/pkg/block/section_profiles_test.go b/pkg/block/section_profiles_test.go new file mode 100644 index 0000000000..47ee17aa59 --- /dev/null +++ b/pkg/block/section_profiles_test.go @@ -0,0 +1,109 @@ +package block + +import ( + "bytes" + "context" + "io" + "testing" + + "github.com/parquet-go/parquet-go" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" +) + +func createParquetFile[T any](t testing.TB, f io.Writer, rows []T, rowGroups int) { + perRG := len(rows) / rowGroups + + w := parquet.NewGenericWriter[T](f) + for i := 0; i < (rowGroups - 1); i++ { + _, err := w.Write(rows[0:perRG]) + require.NoError(t, err) + require.NoError(t, w.Flush()) + rows = rows[perRG:] + } + + _, err := w.Write(rows) + require.NoError(t, err) + require.NoError(t, w.Flush()) + + require.NoError(t, w.Close()) +} + +func createParquetTestFile(t testing.TB, f io.Writer, count int) { + type T struct{ A int } + + rows := []T{} + for i := 0; i < count; i++ { + rows = append(rows, T{i}) + } + + createParquetFile(t, f, rows, 4) +} + +func validateColumnIndex(t *testing.T, pf *parquet.File, count int) { + rgs := pf.RowGroups() + require.Equal(t, 4, len(rgs)) + + // check last row groups column index + ci, err := rgs[3].ColumnChunks()[0].ColumnIndex() + require.NoError(t, err) + + pages := ci.NumPages() + require.Equal(t, int64(count-1), ci.MaxValue(pages-1).Int64()) +} + +func Test_openParquetFile(t *testing.T) { + path := "test.parquet" + ctx := context.Background() + bucket, _ := testutil.NewFilesystemBucket(t, ctx, t.TempDir()) + + buf := bytes.NewBuffer(nil) + count := 100 + createParquetTestFile(t, buf, count) + + actualFooterSize := footerSize(buf.Bytes()) + + err := bucket.Upload(ctx, path, bytes.NewReader(buf.Bytes())) + require.NoError(t, err) + + pathOffset := "test.offset.parquet" + require.NoError(t, bucket.Upload(ctx, pathOffset, bytes.NewReader(append(bytes.Repeat([]byte{0xab}, 16), buf.Bytes()...)))) + + opts := []parquet.FileOption{ + parquet.SkipBloomFilters(true), + } + + t.Run("withFooterSizeSmallerThanEstimate", func(t *testing.T) { + pf, err := openParquetFile(bucket, path, 0, int64(buf.Len()), actualFooterSize*2, opts...) + require.NoError(t, err) + + validateColumnIndex(t, pf.File, count) + }) + + t.Run("withFooterSizeExactEstimate", func(t *testing.T) { + pf, err := openParquetFile(bucket, path, 0, int64(buf.Len()), actualFooterSize, opts...) + require.NoError(t, err) + + validateColumnIndex(t, pf.File, count) + }) + t.Run("withFooterSizeSmallerEstimate", func(t *testing.T) { + pf, err := openParquetFile(bucket, path, 0, int64(buf.Len()), 200, opts...) + require.NoError(t, err) + + validateColumnIndex(t, pf.File, count) + }) + t.Run("withFooterSizeVerySmall", func(t *testing.T) { + pf, err := openParquetFile(bucket, path, 0, int64(buf.Len()), 1, opts...) + require.NoError(t, err) + + validateColumnIndex(t, pf.File, count) + }) + + t.Run("withOffsetAndFooterSmallerThanEstimate", func(t *testing.T) { + pf, err := openParquetFile(bucket, pathOffset, 16, int64(buf.Len()), actualFooterSize*2, opts...) + require.NoError(t, err) + validateColumnIndex(t, pf.File, count) + }) + +} diff --git a/pkg/block/section_symbols.go b/pkg/block/section_symbols.go new file mode 100644 index 0000000000..49aee098bd --- /dev/null +++ b/pkg/block/section_symbols.go @@ -0,0 +1,24 @@ +package block + +import ( + "context" + "fmt" + + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" +) + +func openSymbols(ctx context.Context, s *Dataset) (err error) { + offset := s.sectionOffset(SectionSymbols) + size := s.sectionSize(SectionSymbols) + if buf := s.inMemoryBuffer(); buf != nil { + offset -= int64(s.offset()) + s.symbols, err = symdb.OpenObject(ctx, s.inMemoryBucket(buf), s.obj.path, offset, size) + } else { + s.symbols, err = symdb.OpenObject(ctx, s.obj.storage, s.obj.path, offset, size, + symdb.WithPrefetchSize(symbolsPrefetchSize)) + } + if err != nil { + return fmt.Errorf("opening symbols: %w", err) + } + return nil +} diff --git a/pkg/block/section_tsdb.go b/pkg/block/section_tsdb.go new file mode 100644 index 0000000000..64929852d2 --- /dev/null +++ b/pkg/block/section_tsdb.go @@ -0,0 +1,55 @@ +package block + +import ( + "context" + "fmt" + + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/util/bufferpool" +) + +func openDatasetIndex(ctx context.Context, s *Dataset) error { + return openTSDB(ctx, s) +} + +func openTSDB(ctx context.Context, s *Dataset) (err error) { + offset := s.sectionOffset(SectionTSDB) + size := s.sectionSize(SectionTSDB) + s.tsdb = new(tsdbBuffer) + defer func() { + if err != nil { + _ = s.tsdb.Close() + } + }() + if buf := s.inMemoryBuffer(); buf != nil { + offset -= int64(s.offset()) + s.tsdb.index, err = index.NewReader(index.RealByteSlice(buf[offset : offset+size])) + } else { + s.tsdb.buf = bufferpool.GetBuffer(int(size)) + if err = objstore.ReadRange(ctx, s.tsdb.buf, s.obj.path, s.obj.storage, offset, size); err == nil { + s.tsdb.index, err = index.NewReader(index.RealByteSlice(s.tsdb.buf.B)) + } + } + if err != nil { + return fmt.Errorf("opening tsdb: %w", err) + } + return nil +} + +type tsdbBuffer struct { + index *index.Reader + buf *bufferpool.Buffer +} + +func (b *tsdbBuffer) Close() (err error) { + if b.index != nil { + err = b.index.Close() + b.index = nil + } + if b.buf != nil { + bufferpool.Put(b.buf) + b.buf = nil + } + return err +} diff --git a/pkg/block/testdata/.gitignore b/pkg/block/testdata/.gitignore new file mode 100644 index 0000000000..7ad764b60f --- /dev/null +++ b/pkg/block/testdata/.gitignore @@ -0,0 +1 @@ +blocks/ diff --git a/pkg/block/testdata/block-metas.json b/pkg/block/testdata/block-metas.json new file mode 100644 index 0000000000..086191bd50 --- /dev/null +++ b/pkg/block/testdata/block-metas.json @@ -0,0 +1,267 @@ +{ + "blocks": [ + { + "id": "01J2VJR31PT3X4NDJC4Q2BHWQ1", + "minTime": "1721060035611", + "maxTime": "1721060035611", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060035611", + "maxTime": "1721060035611", + "tableOfContents": [ + "0", + "4549", + "7747" + ], + "size": "19471" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/query-frontend" + ] + }, + { + "id": "01J2VJQPYDC160REPAD2VN88XN", + "minTime": "1721060023235", + "maxTime": "1721060023235", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060023235", + "maxTime": "1721060023235", + "tableOfContents": [ + "0", + "3794", + "6281" + ], + "size": "22242" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/ingester" + ] + }, + { + "id": "01J2VJQRGBK8YFWVV8K1MPRRWM", + "minTime": "1721060010831", + "maxTime": "1721060010831", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060010831", + "maxTime": "1721060010831", + "tableOfContents": [ + "0", + "3949", + "6565" + ], + "size": "17664" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/alloy" + ] + }, + { + "id": "01J2VJQRTMSCY4VDYBP5N4N5JK", + "minTime": "1721060025159", + "maxTime": "1721060025159", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060025159", + "maxTime": "1721060025159", + "tableOfContents": [ + "0", + "3834", + "6029" + ], + "size": "21765" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/query-frontend" + ] + }, + { + "id": "01J2VJQTJ3PGF7KB39ARR1BX3Y", + "minTime": "1721060026913", + "maxTime": "1721060026913", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060026913", + "maxTime": "1721060026913", + "tableOfContents": [ + "0", + "4808", + "8321" + ], + "size": "28169" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/ingester" + ] + }, + { + "id": "01J2VJQV544TF571FDSK2H692P", + "minTime": "1721060013534", + "maxTime": "1721060013534", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060013534", + "maxTime": "1721060013534", + "tableOfContents": [ + "0", + "4201", + "6780" + ], + "size": "15785" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/query-frontend" + ] + }, + { + "id": "01J2VJQX8DYHSEBK7BAQSCJBMG", + "minTime": "1721060015603", + "maxTime": "1721060015603", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060015603", + "maxTime": "1721060015603", + "tableOfContents": [ + "0", + "4543", + "7406" + ], + "size": "27431" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/ingester" + ] + }, + { + "id": "01J2VJQYQVZTPZMMJKE7F2XC47", + "minTime": "1721060031203", + "maxTime": "1721060031203", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060031203", + "maxTime": "1721060031203", + "tableOfContents": [ + "0", + "5086", + "8600" + ], + "size": "36655" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/ingester" + ] + }, + { + "id": "01J2VJQZPARDJQ779S1JMV0XQA", + "minTime": "1721060032190", + "maxTime": "1721060032190", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060032190", + "maxTime": "1721060032190", + "tableOfContents": [ + "0", + "3825", + "6312" + ], + "size": "24273" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/ingester" + ] + }, + { + "id": "01J2VJR0R3NQS23SDADNA6XHCM", + "minTime": "1721060033248", + "maxTime": "1721060033802", + "shard": 1, + "datasets": [ + { + "tenant": 1, + "name": 2, + "minTime": "1721060033248", + "maxTime": "1721060033248", + "tableOfContents": [ + "0", + "4547", + "7152" + ], + "size": "27397" + }, + { + "tenant": 1, + "name": 3, + "minTime": "1721060033680", + "maxTime": "1721060033802", + "tableOfContents": [ + "27397", + "32839", + "37073" + ], + "size": "50561" + } + ], + "stringTable": [ + "", + "anonymous", + "pyroscope-test/alloy", + "pyroscope-test/ingester" + ] + } + ] +} diff --git a/pkg/block/testdata/compacted.golden b/pkg/block/testdata/compacted.golden new file mode 100644 index 0000000000..e3ae4bc3bf --- /dev/null +++ b/pkg/block/testdata/compacted.golden @@ -0,0 +1,75 @@ +[ + { + "format_version": 1, + "id": "01J2VJR31PJTT89RKM1ZG8BSB9", + "tenant": 1, + "shard": 1, + "compaction_level": 1, + "min_time": 1721060010831, + "max_time": 1721060035611, + "metadata_offset": 163604, + "size": 163931, + "datasets": [ + { + "tenant": 1, + "name": 4, + "min_time": 1721060010831, + "max_time": 1721060033248, + "table_of_contents": [ + 0, + 6099, + 9528 + ], + "size": 36467 + }, + { + "tenant": 1, + "name": 3, + "min_time": 1721060015603, + "max_time": 1721060033802, + "table_of_contents": [ + 36467, + 45548, + 52479 + ], + "size": 78336 + }, + { + "tenant": 1, + "name": 2, + "min_time": 1721060013534, + "max_time": 1721060035611, + "table_of_contents": [ + 114803, + 121291, + 125753 + ], + "size": 39490 + }, + { + "format": 1, + "tenant": 1, + "min_time": 1721060010831, + "max_time": 1721060035611, + "table_of_contents": [ + 154293 + ], + "size": 9311, + "labels": [ + 1, + 5, + 6 + ] + } + ], + "string_table": [ + "", + "anonymous", + "pyroscope-test/query-frontend", + "pyroscope-test/ingester", + "pyroscope-test/alloy", + "__tenant_dataset__", + "dataset_tsdb_index" + ] + } +] \ No newline at end of file diff --git a/pkg/block/testdata/profiles_recorded.txt b/pkg/block/testdata/profiles_recorded.txt new file mode 100644 index 0000000000..36e409eed4 --- /dev/null +++ b/pkg/block/testdata/profiles_recorded.txt @@ -0,0 +1,36 @@ +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples:<> +anonymous: labels: labels: samples: +anonymous: labels: labels: samples: +anonymous: labels: labels: samples:<> diff --git a/pkg/block/testdata/profiles_recorded_shadowed.txt b/pkg/block/testdata/profiles_recorded_shadowed.txt new file mode 100644 index 0000000000..3a333303d3 --- /dev/null +++ b/pkg/block/testdata/profiles_recorded_shadowed.txt @@ -0,0 +1,8 @@ +anonymous: labels: samples: +anonymous: labels: samples: +anonymous: labels: samples: +anonymous: labels: samples: +anonymous: labels: samples: +anonymous: labels: samples: +anonymous: labels: samples: +anonymous: labels: samples: diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQPYDC160REPAD2VN88XN/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQPYDC160REPAD2VN88XN/block.bin new file mode 100644 index 0000000000..871f44e7b8 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQPYDC160REPAD2VN88XN/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQRGBK8YFWVV8K1MPRRWM/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQRGBK8YFWVV8K1MPRRWM/block.bin new file mode 100644 index 0000000000..200595ac24 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQRGBK8YFWVV8K1MPRRWM/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQRTMSCY4VDYBP5N4N5JK/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQRTMSCY4VDYBP5N4N5JK/block.bin new file mode 100644 index 0000000000..429f6118eb Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQRTMSCY4VDYBP5N4N5JK/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQTJ3PGF7KB39ARR1BX3Y/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQTJ3PGF7KB39ARR1BX3Y/block.bin new file mode 100644 index 0000000000..99cabde890 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQTJ3PGF7KB39ARR1BX3Y/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQV544TF571FDSK2H692P/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQV544TF571FDSK2H692P/block.bin new file mode 100644 index 0000000000..697a9fcd38 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQV544TF571FDSK2H692P/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQX8DYHSEBK7BAQSCJBMG/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQX8DYHSEBK7BAQSCJBMG/block.bin new file mode 100644 index 0000000000..b5dec6d947 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQX8DYHSEBK7BAQSCJBMG/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQYQVZTPZMMJKE7F2XC47/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQYQVZTPZMMJKE7F2XC47/block.bin new file mode 100644 index 0000000000..d6ee393216 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQYQVZTPZMMJKE7F2XC47/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJQZPARDJQ779S1JMV0XQA/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJQZPARDJQ779S1JMV0XQA/block.bin new file mode 100644 index 0000000000..d10d1da8d3 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJQZPARDJQ779S1JMV0XQA/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJR0R3NQS23SDADNA6XHCM/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJR0R3NQS23SDADNA6XHCM/block.bin new file mode 100644 index 0000000000..2a53f1519c Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJR0R3NQS23SDADNA6XHCM/block.bin differ diff --git a/pkg/block/testdata/segments/1/anonymous/01J2VJR31PT3X4NDJC4Q2BHWQ1/block.bin b/pkg/block/testdata/segments/1/anonymous/01J2VJR31PT3X4NDJC4Q2BHWQ1/block.bin new file mode 100644 index 0000000000..f4ba460cc4 Binary files /dev/null and b/pkg/block/testdata/segments/1/anonymous/01J2VJR31PT3X4NDJC4Q2BHWQ1/block.bin differ diff --git a/pkg/block/ulid_generator.go b/pkg/block/ulid_generator.go new file mode 100644 index 0000000000..5d70741fb4 --- /dev/null +++ b/pkg/block/ulid_generator.go @@ -0,0 +1,50 @@ +package block + +import ( + "encoding/binary" + "io" + "math/rand" + "time" + + "github.com/cespare/xxhash/v2" + "github.com/oklog/ulid/v2" +) + +// ULIDGenerator generates deterministic ULIDs for blocks in an +// idempotent way: for the same set of objects, the generator +// will always produce the same set of ULIDs. +// +// We require block identifiers to be deterministic to ensure +// deduplication of the blocks. +type ULIDGenerator struct { + timestamp uint64 // Unix millis. + entropy io.Reader +} + +func NewULIDGenerator(objects Objects) *ULIDGenerator { + if len(objects) == 0 { + return &ULIDGenerator{ + timestamp: uint64(time.Now().UnixMilli()), + } + } + buf := make([]byte, 0, 1<<10) + for _, obj := range objects { + buf = append(buf, obj.meta.Id...) + // We also include the compaction level + // to allow for single-block compactions. + buf = binary.BigEndian.AppendUint32(buf, obj.meta.CompactionLevel) + } + seed := xxhash.Sum64(buf) + // Reference block. + // We're using its timestamp in all the generated ULIDs. + // Assuming that the first object is the oldest one. + r := objects[0] + return &ULIDGenerator{ + timestamp: ulid.MustParse(r.Metadata().Id).Time(), + entropy: rand.New(rand.NewSource(int64(seed))), + } +} + +func (g *ULIDGenerator) ULID() ulid.ULID { + return ulid.MustNew(g.timestamp, g.entropy) +} diff --git a/pkg/block/writer.go b/pkg/block/writer.go new file mode 100644 index 0000000000..103cc4c217 --- /dev/null +++ b/pkg/block/writer.go @@ -0,0 +1,55 @@ +package block + +import ( + "bufio" + "context" + "os" + "path/filepath" + + "github.com/grafana/pyroscope/v2/pkg/objstore" +) + +type Writer struct { + path string + f *os.File + w *bufio.Writer + off uint64 +} + +func NewBlockWriter(tmpdir string) (*Writer, error) { + var err error + if err = os.MkdirAll(tmpdir, 0755); err != nil { + return nil, err + } + w := &Writer{path: filepath.Join(tmpdir, FileNameDataObject)} + if w.f, err = os.Create(w.path); err != nil { + return nil, err + } + w.w = bufio.NewWriter(w.f) + return w, nil +} + +func (w *Writer) Write(p []byte) (n int, err error) { + n, err = w.w.Write(p) + w.off += uint64(n) + return n, err +} + +func (w *Writer) Offset() uint64 { return w.off } + +func (w *Writer) Upload(ctx context.Context, bucket objstore.Bucket, path string) error { + if err := w.w.Flush(); err != nil { + return err + } + if _, err := w.f.Seek(0, 0); err != nil { + return err + } + return bucket.Upload(ctx, path, w.f) +} + +func (w *Writer) Close() error { + err := w.f.Close() + w.f = nil + w.w = nil + return err +} diff --git a/pkg/buf.gen.yaml b/pkg/buf.gen.yaml index c739855ea0..f236fb6ec1 100644 --- a/pkg/buf.gen.yaml +++ b/pkg/buf.gen.yaml @@ -2,7 +2,7 @@ version: v1 managed: enabled: true go_package_prefix: - default: github.com/grafana/pyroscope/pkg/ + default: github.com/grafana/pyroscope/v2/pkg/ except: - buf.build/googleapis/googleapis @@ -16,7 +16,6 @@ plugins: opt: - paths=source_relative - features=marshal+unmarshal+size+pool+grpc+pool - - pool=github.com/grafana/pyroscope/pkg/og/storage/tree.Profile - name: connect-go out: . diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 1880215335..9cdb9e2a51 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -1,11 +1,11 @@ package cfg import ( + "errors" "flag" "reflect" "github.com/grafana/dskit/flagext" - "github.com/pkg/errors" ) // Source is a generic configuration source. This function may do whatever is @@ -21,6 +21,10 @@ type Cloneable interface { Clone() flagext.Registerer } +type SetFlagRecorder interface { + RecordSetFlag(name string) +} + var ( ErrNotPointer = errors.New("dst is not a pointer") ) diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 9256046fd4..00916f77ac 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -18,7 +18,7 @@ server: timeout: 60h tls: key: YAML -`)) +`), true) fs := flag.NewFlagSet(t.Name(), flag.PanicOnError) flagSource := dFlags(fs, []string{"-verbose", "-server.port=21"}) @@ -51,7 +51,7 @@ servers: timeoutz: 60h tls: keey: YAML -`)) +`), true) fs := flag.NewFlagSet(t.Name(), flag.PanicOnError) flagSource := dFlags(fs, []string{"-verbose", "-server.port=21"}) diff --git a/pkg/cfg/dynamic_test.go b/pkg/cfg/dynamic_test.go index b76cc2e79c..ee5d76f221 100644 --- a/pkg/cfg/dynamic_test.go +++ b/pkg/cfg/dynamic_test.go @@ -41,13 +41,13 @@ server: t.Run("parses defaults", func(t *testing.T) { data := testContext(nil, "", nil) - assert.Equal(t, 80, data.Server.Port) - assert.Equal(t, 60*time.Second, data.Server.Timeout) + assert.Equal(t, 80, data.Port) + assert.Equal(t, 60*time.Second, data.Timeout) }) t.Run("parses config from config.file", func(t *testing.T) { data := testContext(nil, defaultYamlConfig, nil) - assert.Equal(t, 8080, data.Server.Port) + assert.Equal(t, 8080, data.Port) }) t.Run("calls ApplyDynamicConfig on provided DynamicCloneable", func(t *testing.T) { @@ -73,26 +73,26 @@ server: data := testContext(mockApplyDynamicConfig, defaultYamlConfig, nil) assert.NotNil(t, data) assert.NotNil(t, configFromFile) - assert.Equal(t, 8080, configFromFile.Server.Port) + assert.Equal(t, 8080, configFromFile.Port) }) t.Run("config from file take precedence over config applied in ApplyDynamicConfig", func(t *testing.T) { mockApplyDynamicConfig := func(dst Cloneable) error { config, ok := dst.(*DynamicConfig) require.True(t, ok) - config.Server.Port = 9090 + config.Port = 9090 return nil } data := testContext(mockApplyDynamicConfig, defaultYamlConfig, nil) - assert.Equal(t, 8080, data.Server.Port) + assert.Equal(t, 8080, data.Port) }) t.Run("config from command line takes precedence over config applied in ApplyDynamicConfig and in file", func(t *testing.T) { mockApplyDynamicConfig := func(dst Cloneable) error { config, ok := dst.(*DynamicConfig) require.True(t, ok) - config.Server.Port = 9090 + config.Port = 9090 return nil } @@ -101,7 +101,7 @@ server: } data := testContext(mockApplyDynamicConfig, defaultYamlConfig, args) - assert.Equal(t, 7070, data.Server.Port) + assert.Equal(t, 7070, data.Port) }) } @@ -135,7 +135,7 @@ func (d *DynamicConfig) ApplyDynamicConfig() Source { } func (d *DynamicConfig) RegisterFlags(fs *flag.FlagSet) { - fs.IntVar(&d.Server.Port, "server.port", 80, "") - fs.DurationVar(&d.Server.Timeout, "server.timeout", 60*time.Second, "") + fs.IntVar(&d.Port, "server.port", 80, "") + fs.DurationVar(&d.Timeout, "server.timeout", 60*time.Second, "") fs.StringVar(&d.ConfigFile, "config.file", "", "yaml file to load") } diff --git a/pkg/cfg/files.go b/pkg/cfg/files.go index 77cd4afde0..e08d7149c3 100644 --- a/pkg/cfg/files.go +++ b/pkg/cfg/files.go @@ -9,8 +9,7 @@ import ( "strconv" "github.com/drone/envsubst" - "github.com/pkg/errors" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) // JSON returns a Source that opens the supplied `.json` file and loads it. @@ -26,7 +25,10 @@ func JSON(f *string) Source { } err = dJSON(j)(dst) - return errors.Wrap(err, *f) + if err != nil { + return fmt.Errorf("%s: %w", *f, err) + } + return nil } } @@ -41,6 +43,15 @@ func dJSON(y []byte) Source { // When expandEnvVars is true, variables in the supplied '.yaml\ file are expanded // using https://pkg.go.dev/github.com/drone/envsubst?tab=overview func YAML(f string, expandEnvVars bool) Source { + return yamlWithKnowFields(f, expandEnvVars, true) +} + +// Like YAML but ignores fields that are not known +func YAMLIgnoreUnknownFields(f string, expandEnvVars bool) Source { + return yamlWithKnowFields(f, expandEnvVars, false) +} + +func yamlWithKnowFields(f string, expandEnvVars bool, knownFields bool) Source { return func(dst Cloneable) error { y, err := os.ReadFile(f) if err != nil { @@ -53,19 +64,22 @@ func YAML(f string, expandEnvVars bool) Source { } y = []byte(s) } - err = dYAML(y)(dst) - return errors.Wrap(err, f) + err = dYAML(y, knownFields)(dst) + if err != nil { + return fmt.Errorf("%s: %w", f, err) + } + return nil } } // dYAML returns a YAML source and allows dependency injection -func dYAML(y []byte) Source { +func dYAML(y []byte, knownFields bool) Source { return func(dst Cloneable) error { if len(y) == 0 { return nil } dec := yaml.NewDecoder(bytes.NewReader(y)) - dec.KnownFields(true) + dec.KnownFields(knownFields) if err := dec.Decode(dst); err != nil { return err } diff --git a/pkg/cfg/flag.go b/pkg/cfg/flag.go index aeca1fe6b6..074beeb6b8 100644 --- a/pkg/cfg/flag.go +++ b/pkg/cfg/flag.go @@ -1,13 +1,13 @@ package cfg import ( + "errors" "flag" "fmt" "sort" "strings" "github.com/grafana/dskit/flagext" - "github.com/pkg/errors" "golang.org/x/text/cases" "golang.org/x/text/language" ) @@ -37,7 +37,17 @@ func Flags(args []string, fs *flag.FlagSet) Source { func dFlags(fs *flag.FlagSet, args []string) Source { return func(dst Cloneable) error { // parse the final flagset - return fs.Parse(args) + if err := fs.Parse(args); err != nil { + return err + } + + if recorder, ok := dst.(SetFlagRecorder); ok { + fs.Visit(func(f *flag.Flag) { + recorder.RecordSetFlag(f.Name) + }) + } + + return nil } } diff --git a/pkg/cfg/precedence_test.go b/pkg/cfg/precedence_test.go index af96c94573..bd56702dd2 100644 --- a/pkg/cfg/precedence_test.go +++ b/pkg/cfg/precedence_test.go @@ -28,7 +28,7 @@ func TestYAMLOverDefaults(t *testing.T) { fs := flag.NewFlagSet(t.Name(), flag.PanicOnError) err := Unmarshal(&data, Defaults(fs), - dYAML([]byte(y)), + dYAML([]byte(y), true), ) require.NoError(t, err) @@ -51,7 +51,7 @@ func TestFlagOverYAML(t *testing.T) { err := Unmarshal(&data, Defaults(fs), - dYAML([]byte(y)), + dYAML([]byte(y), true), dFlags(fs, []string{"-verbose=false", "-tls.cert=CLI"}), ) diff --git a/pkg/clientpool/ingester_client_pool.go b/pkg/clientpool/ingester_client_pool.go index e5511fea5b..75ae4a0928 100644 --- a/pkg/clientpool/ingester_client_pool.go +++ b/pkg/clientpool/ingester_client_pool.go @@ -16,7 +16,7 @@ import ( "google.golang.org/grpc/health/grpc_health_v1" "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1/ingesterv1connect" - "github.com/grafana/pyroscope/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) // PoolConfig is config for creating a Pool. @@ -60,7 +60,7 @@ func (f *ingesterPoolFactory) FromInstance(inst ring.InstanceDesc) (ring_client. return nil, err } - httpClient := util.InstrumentedDefaultHTTPClient(util.WithTracingTransport()) + httpClient := httputil.InstrumentedDefaultHTTPClient(httputil.WithTracingTransport(), httputil.WithBaggageTransport()) return &ingesterPoolClient{ IngesterServiceClient: ingesterv1connect.NewIngesterServiceClient(httpClient, "http://"+inst.Addr, f.options...), HealthClient: grpc_health_v1.NewHealthClient(conn), diff --git a/pkg/clientpool/store_gateway_client_pool.go b/pkg/clientpool/store_gateway_client_pool.go index a4a22c6856..fbe33982c7 100644 --- a/pkg/clientpool/store_gateway_client_pool.go +++ b/pkg/clientpool/store_gateway_client_pool.go @@ -15,7 +15,7 @@ import ( "google.golang.org/grpc/health/grpc_health_v1" "github.com/grafana/pyroscope/api/gen/proto/go/storegateway/v1/storegatewayv1connect" - "github.com/grafana/pyroscope/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) func NewStoreGatewayPool(ring ring.ReadRing, factory ring_client.PoolFactory, clientsMetric prometheus.Gauge, logger log.Logger, options ...connect.ClientOption) *ring_client.Pool { @@ -45,7 +45,7 @@ func (f *storeGatewayPoolFactory) FromInstance(inst ring.InstanceDesc) (ring_cli return nil, err } - httpClient := util.InstrumentedDefaultHTTPClient(util.WithTracingTransport()) + httpClient := httputil.InstrumentedDefaultHTTPClient(httputil.WithTracingTransport(), httputil.WithBaggageTransport()) return &storeGatewayPoolClient{ StoreGatewayServiceClient: storegatewayv1connect.NewStoreGatewayServiceClient(httpClient, "http://"+inst.Addr, f.options...), HealthClient: grpc_health_v1.NewHealthClient(conn), diff --git a/pkg/compactionworker/metrics.go b/pkg/compactionworker/metrics.go new file mode 100644 index 0000000000..0e8b163b76 --- /dev/null +++ b/pkg/compactionworker/metrics.go @@ -0,0 +1,66 @@ +package compactionworker + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type workerMetrics struct { + jobsInProgress *prometheus.GaugeVec + jobsCompleted *prometheus.CounterVec + jobDuration *prometheus.HistogramVec + timeToCompaction *prometheus.HistogramVec + blocksDeleted *prometheus.CounterVec +} + +func newMetrics(r prometheus.Registerer) *workerMetrics { + m := &workerMetrics{ + jobsInProgress: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "jobs_in_progress", + Help: "The number of active compaction jobs currently running.", + }, []string{"tenant", "level"}), + + jobsCompleted: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "jobs_completed_total", + Help: "Total number of compaction jobs completed.", + }, []string{"tenant", "level", "status"}), + + jobDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "job_duration_seconds", + Help: "Duration of compaction job runs", + + Buckets: prometheus.ExponentialBucketsRange(1, 300, 16), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"tenant", "level", "status"}), + + timeToCompaction: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "time_to_compaction_seconds", + Help: "The time elapsed since the oldest compacted block was created.", + + Buckets: prometheus.ExponentialBucketsRange(1, 14400, 16), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"tenant", "level"}), + + blocksDeleted: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "blocks_deleted_total", + Help: "Total number of block deletion attempts.", + }, []string{"status"}), + } + + util.Register(r, + m.jobsInProgress, + m.jobsCompleted, + m.jobDuration, + m.timeToCompaction, + m.blocksDeleted, + ) + + return m +} diff --git a/pkg/compactionworker/worker.go b/pkg/compactionworker/worker.go new file mode 100644 index 0000000000..e16a041ea2 --- /dev/null +++ b/pkg/compactionworker/worker.go @@ -0,0 +1,765 @@ +package compactionworker + +import ( + "context" + "encoding/binary" + "errors" + "flag" + "fmt" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/cespare/xxhash/v2" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/services" + "github.com/grafana/dskit/tracing" + "github.com/oklog/ulid/v2" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/model/labels" + thanosstore "github.com/thanos-io/objstore" + _ "go.uber.org/automaxprocs" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/metrics" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type Config struct { + JobConcurrency int `yaml:"job_capacity" category:"advanced"` + JobPollInterval time.Duration `yaml:"job_poll_interval" category:"advanced"` + SmallObjectSize int `yaml:"small_object_size_bytes" category:"advanced"` + TempDir string `yaml:"temp_dir" category:"advanced" doc:"default=/tmp"` + RequestTimeout time.Duration `yaml:"request_timeout" category:"advanced"` + CleanupMaxDuration time.Duration `yaml:"cleanup_max_duration" category:"advanced"` + MetricsExporter metrics.Config `yaml:"metrics_exporter" category:"advanced"` +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + const prefix = "compaction-worker." + f.IntVar(&cfg.JobConcurrency, prefix+"job-concurrency", 0, "Number of concurrent jobs compaction worker will run. Defaults to the number of CPU cores.") + f.DurationVar(&cfg.JobPollInterval, prefix+"job-poll-interval", 5*time.Second, "Interval between job requests") + f.DurationVar(&cfg.RequestTimeout, prefix+"request-timeout", 5*time.Second, "Job request timeout.") + f.DurationVar(&cfg.CleanupMaxDuration, prefix+"cleanup-max-duration", 15*time.Second, "Maximum duration of the cleanup operations.") + f.IntVar(&cfg.SmallObjectSize, prefix+"small-object-size-bytes", 8<<20, "Size of the object that can be loaded in memory.") + f.StringVar(&cfg.TempDir, prefix+"temp-dir", os.TempDir(), "Temporary directory for compaction jobs.") + cfg.MetricsExporter.RegisterFlags(f) +} + +type Worker struct { + service services.Service + + logger log.Logger + config Config + client MetastoreClient + storage objstore.Bucket + compactFn compactFunc + metrics *workerMetrics + + jobs map[string]*compactionJob + queue chan *compactionJob + threads int + capacity atomic.Int32 + + deleterPool *deleterPool + + stopped atomic.Bool + closeOnce sync.Once + wg sync.WaitGroup + + exporter metrics.Exporter + ruler metrics.Ruler +} + +type compactionJob struct { + *metastorev1.CompactionJob + + ctx context.Context + cancel context.CancelFunc + done atomic.Bool + + blocks []*metastorev1.BlockMeta + assignment *metastorev1.CompactionJobAssignment + compacted *metastorev1.CompactedBlocks +} + +type compactFunc func(context.Context, []*metastorev1.BlockMeta, objstore.Bucket, ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) + +type MetastoreClient interface { + metastorev1.CompactionServiceClient + metastorev1.IndexServiceClient +} + +func New( + logger log.Logger, + config Config, + client MetastoreClient, + storage objstore.Bucket, + reg prometheus.Registerer, + ruler metrics.Ruler, + exporter metrics.Exporter, +) (*Worker, error) { + config.TempDir = filepath.Join(filepath.Clean(config.TempDir), "pyroscope-compactor") + _ = os.RemoveAll(config.TempDir) + if err := os.MkdirAll(config.TempDir, 0o777); err != nil { + return nil, fmt.Errorf("failed to create compactor directory: %w", err) + } + w := &Worker{ + config: config, + logger: logger, + client: client, + storage: storage, + compactFn: block.Compact, + metrics: newMetrics(reg), + ruler: ruler, + exporter: exporter, + } + w.threads = config.JobConcurrency + if w.threads < 1 { + w.threads = runtime.GOMAXPROCS(-1) + } + w.queue = make(chan *compactionJob, 2*w.threads) + w.jobs = make(map[string]*compactionJob, 2*w.threads) + w.capacity.Store(int32(w.threads)) + w.deleterPool = newDeleterPool(16 * w.threads) + w.service = services.NewBasicService(w.starting, w.running, w.stopping) + return w, nil +} + +func (w *Worker) Service() services.Service { return w.service } + +func (w *Worker) starting(context.Context) (err error) { return nil } + +func (w *Worker) stopping(error) error { return nil } + +func (w *Worker) running(ctx context.Context) error { + ticker := time.NewTicker(w.config.JobPollInterval) + stopPolling := make(chan struct{}) + pollingDone := make(chan struct{}) + go func() { + defer close(pollingDone) + for { + select { + case <-stopPolling: + // Now that all the threads are done, we need to + // send the final status updates. + w.poll() + return + + case <-ticker.C: + w.poll() + } + } + }() + + w.wg.Add(w.threads) + for i := 0; i < w.threads; i++ { + go func() { + defer w.wg.Done() + level.Info(w.logger).Log("msg", "compaction worker thread started") + for job := range w.queue { + w.capacity.Add(-1) + util.Recover(func() { w.runCompaction(job) }) + job.done.Store(true) + w.capacity.Add(1) + } + }() + } + + <-ctx.Done() + // Wait for all threads to finish their work, continuing to report status + // updates about the in-progress jobs. First, signal to the poll loop that + // we're done with new jobs. + w.stopped.Store(true) + level.Info(w.logger).Log("msg", "waiting for all jobs to finish") + w.wg.Wait() + + // Now that all the threads are done, we stop the polling loop. + ticker.Stop() + close(stopPolling) + <-pollingDone + // Force exporter to send all staged samples (depends on the implementation) + // Must be a blocking call. + if w.exporter != nil { + w.exporter.Flush() + } + w.deleterPool.close() + return nil +} + +func (w *Worker) poll() { + // Check if we want to stop polling for new jobs. + // Close the queue if this is not the case. + var capacity uint32 + if w.stopped.Load() { + w.closeOnce.Do(func() { + level.Info(w.logger).Log("msg", "closing job queue") + close(w.queue) + }) + } else { + // We report the number of free workers in a hope to get more jobs. + // Note that cap(w.queue) - len(w.queue) will only report 0 when all + // the workers are busy and the queue is full (in fact, doubling the + // reported capacity). + if c := w.capacity.Load(); c > 0 { + capacity = uint32(c) + } + } + + updates := w.collectUpdates() + if len(updates) == 0 && capacity == 0 { + level.Info(w.logger).Log("msg", "skipping polling", "updates", len(updates), "capacity", capacity) + return + } + + level.Info(w.logger).Log("msg", "polling compaction jobs", "updates", len(updates), "capacity", capacity) + ctx, cancel := context.WithTimeout(context.Background(), w.config.RequestTimeout) + defer cancel() + resp, err := w.client.PollCompactionJobs(ctx, &metastorev1.PollCompactionJobsRequest{ + StatusUpdates: updates, + JobCapacity: capacity, + }) + if err != nil { + level.Error(w.logger).Log("msg", "failed to poll compaction jobs", "err", err) + return + } + + w.cleanup(updates) + newJobs := w.handleResponse(resp) + for _, job := range newJobs { + select { + case w.queue <- job: + default: + level.Warn(w.logger).Log("msg", "dropping job", "job_name", job.Name) + w.remove(job) + } + } +} + +func (w *Worker) collectUpdates() []*metastorev1.CompactionJobStatusUpdate { + updates := make([]*metastorev1.CompactionJobStatusUpdate, 0, len(w.jobs)) + for _, job := range w.jobs { + update := &metastorev1.CompactionJobStatusUpdate{ + Name: job.Name, + Token: job.assignment.Token, + } + + switch done := job.done.Load(); { + case done && job.compacted != nil: + level.Info(w.logger).Log("msg", "sending update for completed job", "job", job.Name) + update.Status = metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS + update.CompactedBlocks = job.compacted + updates = append(updates, update) + + case done && job.compacted == nil: + // We're not sending the status update for the job and expect that the + // assigment is to be revoked. The job is to be removed at the next + // poll response handling: all jobs without assignments are canceled + // and removed. + level.Warn(w.logger).Log("msg", "skipping update for abandoned job", "job", job.Name) + + default: + level.Info(w.logger).Log("msg", "sending update for in-progress job", "job", job.Name) + update.Status = metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS + updates = append(updates, update) + } + } + + return updates +} + +func (w *Worker) cleanup(updates []*metastorev1.CompactionJobStatusUpdate) { + for _, update := range updates { + if job := w.jobs[update.Name]; job != nil && job.done.Load() { + switch update.Status { + case metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS: + // In the vast majority of cases, we end up here. + w.remove(job) + + case metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS: + // It is possible that the job has been completed after we + // prepared the status update: keep the job for the next + // poll iteration. + + default: + // Workers never send other statuses. It's unexpected to get here. + level.Warn(w.logger).Log("msg", "unexpected job status transition; removing the job", "job", job.Name) + w.remove(job) + } + } + } +} + +func (w *Worker) remove(job *compactionJob) { + delete(w.jobs, job.Name) + job.cancel() +} + +func (w *Worker) handleResponse(resp *metastorev1.PollCompactionJobsResponse) (newJobs []*compactionJob) { + // Assignments by job name. + assignments := make(map[string]*metastorev1.CompactionJobAssignment, len(resp.Assignments)) + for _, assignment := range resp.Assignments { + assignments[assignment.Name] = assignment + } + + for _, job := range w.jobs { + if assignment, ok := assignments[job.assignment.Name]; ok { + // In theory, we should respect the lease expiration time. + // In practice, we have a static polling interval. + job.assignment = assignment + } else { + // The job is running without an assigment. + // We don't care how and when it ends. + level.Warn(w.logger).Log("msg", "job re-assigned to another worker; cancelling", "job", job.Name) + w.remove(job) + } + } + + for _, newJob := range resp.CompactionJobs { + if running, found := w.jobs[newJob.Name]; found { + level.Warn(w.logger).Log("msg", "job re-assigned to the same worker", "job", running.Name) + // We're free to choose what to do. For now, we update the + // assignment (in case the token has changed) and let the + // running job finish. + if running.assignment = assignments[running.Name]; running.assignment != nil { + continue + } + } + job := &compactionJob{CompactionJob: newJob} + if job.assignment = assignments[newJob.Name]; job.assignment == nil { + // That should not be possible, logging it here just in case. + level.Warn(w.logger).Log("msg", "found a job without assigment", "job", job.Name) + continue + } + job.ctx, job.cancel = context.WithCancel(context.Background()) + newJobs = append(newJobs, job) + w.jobs[job.Name] = job + } + + return newJobs +} + +// Status is only used in metrics and logging. +type status string + +const ( + statusSuccess status = "success" + statusFailure status = "failure" + statusCanceled status = "canceled" + statusMetadataNotFound status = "metadata_not_found" + statusBlockNotFound status = "block_not_found" +) + +func (w *Worker) runCompaction(job *compactionJob) { + start := time.Now() + metricLabels := []string{job.Tenant, strconv.Itoa(int(job.CompactionLevel))} + statusName := statusFailure + defer func() { + labelsWithStatus := append(metricLabels, string(statusName)) + w.metrics.jobDuration.WithLabelValues(labelsWithStatus...).Observe(time.Since(start).Seconds()) + w.metrics.jobsCompleted.WithLabelValues(labelsWithStatus...).Inc() + w.metrics.jobsInProgress.WithLabelValues(metricLabels...).Dec() + }() + + w.metrics.jobsInProgress.WithLabelValues(metricLabels...).Inc() + sp, ctx := tracing.StartSpanFromContext(job.ctx, "runCompaction") + sp.SetTag("Job", job.String()) + sp.SetTag("Tenant", job.Tenant) + sp.SetTag("Shard", job.Shard) + sp.SetTag("CompactionLevel", job.CompactionLevel) + sp.SetTag("SourceBlocks", len(job.SourceBlocks)) + sp.SetTag("Tombstones", len(job.Tombstones)) + defer sp.Finish() + + logger := log.With(w.logger, "job", job.Name) + level.Info(logger).Log("msg", "starting compaction job", "source_blocks", strings.Join(job.SourceBlocks, " ")) + + // FIXME(kolesnikovae): Read metadata from blocks: it's located in the + // blocks footer. The start offest and CRC are the last 8 bytes (BE). + // See metadata.Encode and metadata.Decode. + // We use metadata to download objects: in fact we need to know only + // tenant, shard, level, and ID: the information which we already have + // in the job. We definitely don't need the full metadata entry with + // datasets: this part can be set once we download the block and read + // meta locally. Or, we can just fetch the metadata from the objects + // directly, before downloading them. + if err := w.getBlockMetadata(logger, job); err != nil { + // The error is likely to be transient, therefore the job is not failed, + // but just abandoned – another worker will pick it up and try again. + return + } + + if len(job.Tombstones) > 0 { + // Handle tombstones asynchronously on the best effort basis: + // if deletion fails, leftovers will be cleaned up eventually. + // + // There are following reasons why we may not be able to delete: + // 1. General storage unavailability: compaction jobs will be + // retried either way, and the tombstones will be handled again. + // 2. Permission issues. In this case, retry will not help. + // 3. Worker crash: jobs will be retried. + // + // A worker is given a limited time to finish the cleanup. If worker + // didn't finish the cleanup before shutdown and after the compaction + // job was finished (so no retry is expected), the data will be deleted + // eventually due to time-based retention policy. However, if no more + // tombstones are created for the shard, the data will remain in the + // storage. This should be handled by the index cleaner: some garbage + // collection should happen in the background. + w.handleTombstones(logger, job.Tombstones...) + } + + if len(job.blocks) == 0 { + // This is a very bad situation that we do not expect, unless the + // metastore is restored from a snapshot: no metadata found for the + // job source blocks. There's no point in retrying or failing the + // job (which is likely to be retried by another worker), so we just + // skip it. The same for the situation when no block objects can be + // found in storage, which may happen if the blocks are deleted manually. + level.Error(logger).Log("msg", "no block metadata found; skipping") + job.compacted = &metastorev1.CompactedBlocks{SourceBlocks: new(metastorev1.BlockList)} + statusName = statusMetadataNotFound + return + } + + tempdir := filepath.Join(w.config.TempDir, job.Name) + sourcedir := filepath.Join(tempdir, "source") + options := []block.CompactionOption{ + block.WithCompactionTempDir(tempdir), + block.WithCompactionObjectOptions( + block.WithObjectMaxSizeLoadInMemory(w.config.SmallObjectSize), + block.WithObjectDownload(sourcedir), + ), + } + + if observer := w.buildSampleObserver(job.blocks[0]); observer != nil { + defer observer.Close() + options = append(options, block.WithSampleObserver(observer)) + } + + compacted, err := w.compactFn(ctx, job.blocks, w.storage, options...) + defer func() { + if err = os.RemoveAll(tempdir); err != nil { + level.Warn(logger).Log("msg", "failed to remove compaction directory", "path", tempdir, "err", err) + } + }() + + switch { + case err == nil: + level.Info(logger).Log( + "msg", "compaction finished successfully", + "input_blocks", len(job.SourceBlocks), + "output_blocks", len(compacted), + ) + for _, c := range compacted { + level.Debug(logger).Log( + "msg", "new compacted block", + "block_id", c.Id, + "block_tenant", metadata.Tenant(c), + "block_shard", c.Shard, + "block_compaction_level", c.CompactionLevel, + "block_min_time", c.MinTime, + "block_max_time", c.MaxTime, + "block_size", c.Size, + "datasets", len(c.Datasets), + ) + } + job.compacted = &metastorev1.CompactedBlocks{ + NewBlocks: compacted, + SourceBlocks: &metastorev1.BlockList{ + Tenant: job.Tenant, + Shard: job.Shard, + Blocks: job.SourceBlocks, + }, + } + + firstBlock := metadata.Timestamp(job.blocks[0]) + w.metrics.timeToCompaction.WithLabelValues(metricLabels...).Observe(time.Since(firstBlock).Seconds()) + statusName = statusSuccess + + case errors.Is(err, context.Canceled): + level.Warn(logger).Log("msg", "compaction cancelled") + statusName = statusCanceled + + case objstore.IsNotExist(w.storage, err): + level.Error(logger).Log("msg", "failed to find blocks", "err", err) + job.compacted = &metastorev1.CompactedBlocks{SourceBlocks: new(metastorev1.BlockList)} + statusName = statusBlockNotFound + + default: + level.Error(logger).Log("msg", "failed to compact blocks", "err", err) + statusName = statusFailure + } +} + +func (w *Worker) buildSampleObserver(md *metastorev1.BlockMeta) *metrics.SampleObserver { + if !w.config.MetricsExporter.Enabled || md.CompactionLevel > 0 { + return nil + } + recordingTime := int64(ulid.MustParse(md.Id).Time()) + pyroscopeInstanceLabel := labels.New(labels.Label{ + Name: "pyroscope_instance", + Value: pyroscopeInstanceHash(md.Shard, uint32(md.CreatedBy)), + }) + return metrics.NewSampleObserver(recordingTime, w.exporter, w.ruler, pyroscopeInstanceLabel) +} + +func pyroscopeInstanceHash(shard uint32, createdBy uint32) string { + buf := make([]byte, 8) + binary.BigEndian.PutUint32(buf[0:4], shard) + binary.BigEndian.PutUint32(buf[4:8], createdBy) + return fmt.Sprintf("%x", xxhash.Sum64(buf)) +} + +func (w *Worker) getBlockMetadata(logger log.Logger, job *compactionJob) error { + ctx, cancel := context.WithTimeout(job.ctx, w.config.RequestTimeout) + defer cancel() + + resp, err := w.client.GetBlockMetadata(ctx, &metastorev1.GetBlockMetadataRequest{ + Blocks: &metastorev1.BlockList{ + Tenant: job.Tenant, + Shard: job.Shard, + Blocks: job.SourceBlocks, + }, + }) + if err != nil { + level.Error(logger).Log("msg", "failed to get block metadata", "err", err) + return err + } + + job.blocks = resp.GetBlocks() + // Update the plan to reflect the actual compaction job state. + job.SourceBlocks = job.SourceBlocks[:0] + for _, b := range job.blocks { + job.SourceBlocks = append(job.SourceBlocks, b.Id) + } + + return nil +} + +func (w *Worker) handleTombstones(logger log.Logger, tombstones ...*metastorev1.Tombstones) { + for _, t := range tombstones { + w.deleterPool.add(w.newDeleter(logger, t), w.config.CleanupMaxDuration) + } +} + +func (w *Worker) newDeleter(logger log.Logger, tombstone *metastorev1.Tombstones) *deleter { + return &deleter{ + logger: logger, + bucket: w.storage, + metrics: w.metrics, + tombstone: tombstone, + } +} + +type deleter struct { + logger log.Logger + bucket objstore.Bucket + metrics *workerMetrics + tombstone *metastorev1.Tombstones + wg sync.WaitGroup +} + +func (d *deleter) run(ctx context.Context, p *deleterPool) { + if t := d.tombstone.GetBlocks(); t != nil { + d.handleBlockTombstones(ctx, p, t) + } + if t := d.tombstone.GetShard(); t != nil { + d.handleShardTombstone(ctx, p, t) + } +} + +func (d *deleter) wait() { d.wg.Wait() } + +func (d *deleter) handleBlockTombstones(ctx context.Context, pool *deleterPool, t *metastorev1.BlockTombstones) { + logger := log.With(d.logger, "tombstone_name", t.Name) + level.Info(logger).Log("msg", "deleting blocks", "blocks", strings.Join(t.Blocks, " ")) + for _, b := range t.Blocks { + d.wg.Add(1) + pool.run(func() { + defer d.wg.Done() + d.delete(ctx, block.BuildObjectPath(t.Tenant, t.Shard, t.CompactionLevel, b)) + }) + } +} + +func (d *deleter) handleShardTombstone(ctx context.Context, pool *deleterPool, t *metastorev1.ShardTombstone) { + // It's safe to delete blocks in the shard that are older than the + // maximum time specified in the tombstone. + minTime := time.Unix(0, t.Timestamp) + maxTime := minTime.Add(time.Duration(t.Duration)) + dir := block.BuildObjectDir(t.Tenant, t.Shard) + + logger := log.With(d.logger, "tombstone_name", t.Name) + level.Info(logger).Log("msg", "cleaning up shard", "max_time", maxTime, "dir", dir) + + // Workaround for MinIO/S3 ListObjects: if we stop consuming before cancelling, + // the producer goroutine can block on a final send. Cancel first and keep + // draining so the producer exits cleanly. Thanos Iter does not drain on early + // return, so we do it here. + // See: https://github.com/minio/minio-go/blame/f64cdbde257f48f1a44b0f5aeee0475bad7e0e8d/api-list.go#L784 + iterCtx, iterCancel := context.WithCancel(ctx) + defer iterCancel() + + deleteBlock := func(path string) error { + // After we cancel iterCtx, the provider (e.g., MinIO ListObjects) may do + // one final blocking send on its results channel. Returning nil here keeps + // draining without scheduling new work so the producer isn't left blocked. + if iterCtx.Err() != nil { + return nil + } + blockID, err := block.ParseBlockIDFromPath(path) + if err != nil { + level.Warn(logger).Log("msg", "failed to parse block ID from path", "path", path, "err", err) + return nil + } + // Note that although we could skip blocks that are older than the + // minimum time, we do not do it here: we want to make sure we deleted + // everything before the maximum time, as previous jobs could fail + // to do so. In the worst case, this may result in a competition between + // workers that try to clean up the same shard. This is not an issue + // in practice, because there are not so many cleanup jobs for the + // same shard are running concurrently, and the cleanup is fast. + blockTs := time.UnixMilli(int64(blockID.Time())) + if !blockTs.Before(maxTime) { + level.Debug(logger).Log("msg", "reached range end, exiting", "path", path) + // Cancel the iterator so the underlying producer exits promptly. + // Keep consuming to drain any buffered items and allow the producer's + // final send on ctx.Done() to be received. + iterCancel() + return nil + } + d.wg.Add(1) + pool.run(func() { + defer d.wg.Done() + d.delete(ctx, path) + }) + return nil + } + + if err := d.bucket.Iter(iterCtx, dir, deleteBlock, thanosstore.WithRecursiveIter()); err != nil { + if errors.Is(err, context.Canceled) { + // Expected when the iteration context is cancelled. + return + } + // It's only possible if the error is returned by the iterator itself. + level.Error(logger).Log("msg", "failed to cleanup shard", "err", err) + } +} + +func (d *deleter) delete(ctx context.Context, path string) { + var statusName status + switch err := d.bucket.Delete(ctx, path); { + case err == nil: + statusName = statusSuccess + + case objstore.IsNotExist(d.bucket, err): + level.Info(d.logger).Log("msg", "block not found while attempting to delete it", "path", path, "err", err) + statusName = statusBlockNotFound + + case errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded): + level.Warn(d.logger).Log("msg", "block delete attempt canceled", "path", path, "err", err) + statusName = statusCanceled + + default: + level.Error(d.logger).Log("msg", "failed to delete block", "path", path, "err", err) + statusName = statusFailure + } + + d.metrics.blocksDeleted.WithLabelValues(string(statusName)).Inc() +} + +type deleterPool struct { + deletersWg sync.WaitGroup + stop chan struct{} + + threadsWg sync.WaitGroup + queue chan func() +} + +func newDeleterPool(threads int) *deleterPool { + p := &deleterPool{ + queue: make(chan func(), threads), + stop: make(chan struct{}), + } + p.threadsWg.Add(threads) + for i := 0; i < threads; i++ { + go func() { + defer p.threadsWg.Done() + for fn := range p.queue { + fn() + } + }() + } + return p +} + +// If too many tombstones are created for the same tenant-shard, of if there +// are too many blocks to delete so a single worker does not cope up, multiple +// workers may end up deleting same blocks as they process the shard from the +// very beginning. The timeout aims to reduce the competition factor: at any +// time, the number of workers that cleanup the same shard is limited. This is +// difficult to achieve in practice, and may happen if the retention is enabled +// for the first time, and large number of blocks are deleted at once. +func (p *deleterPool) deleterContext(timeout time.Duration) (context.Context, context.CancelFunc) { + ctx := context.Background() + if timeout > 0 { + return context.WithTimeout(ctx, timeout) + } + return context.WithCancel(ctx) +} + +func (p *deleterPool) add(deleter *deleter, timeout time.Duration) { + ctx, cancel := p.deleterContext(timeout) + done := make(chan struct{}) + p.deletersWg.Add(1) + go func() { + deleter.run(ctx, p) + deleter.wait() + p.deletersWg.Done() + // Notify the other goroutine that the deleter is done + // and there's no need to wait for it anymore. + close(done) + }() + go func() { + // Wait for the deleter to finish or for the stop signal, + // or for the timeout to expire, whichever comes first. + defer cancel() + select { + case <-done: + case <-ctx.Done(): + case <-p.stop: + // We don't want to halt the deletion abruptly when + // the worker is stopped. In most cases, the deletion + // will be finished by the time the worker is stopped. + // Otherwise, we may wait up to CleanupMaxDuration. + select { + case <-done: + case <-ctx.Done(): + } + } + }() +} + +func (p *deleterPool) run(fn func()) { p.queue <- fn } + +// It is guaranteed that no [add] calls will be made at this point: +// all compaction jobs are done, and no new jobs can be queued. +func (p *deleterPool) close() { + // Wait for all the deleters to finish. + close(p.stop) + p.deletersWg.Wait() + // No new deletions can be queued. + // We can close the queue now. + close(p.queue) + p.threadsWg.Wait() +} diff --git a/pkg/compactionworker/worker_test.go b/pkg/compactionworker/worker_test.go new file mode 100644 index 0000000000..c1572fadf7 --- /dev/null +++ b/pkg/compactionworker/worker_test.go @@ -0,0 +1,527 @@ +package compactionworker + +import ( + "context" + "errors" + "path/filepath" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + thanosstore "github.com/thanos-io/objstore" + "google.golang.org/grpc" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" +) + +type MetastoreClientMock struct { + *mockmetastorev1.MockCompactionServiceClient + *mockmetastorev1.MockIndexServiceClient +} + +func createTestWorker(t *testing.T, client MetastoreClient, compactFn compactFunc, bucket objstore.Bucket) *Worker { + config := Config{ + JobConcurrency: 2, + JobPollInterval: 100 * time.Millisecond, + RequestTimeout: time.Second, + CleanupMaxDuration: time.Second, + TempDir: t.TempDir(), + } + + worker, err := New( + log.NewNopLogger(), + config, + client, + bucket, + prometheus.NewRegistry(), + nil, // ruler + nil, // exporter + ) + + require.NoError(t, err) + worker.compactFn = compactFn + return worker +} + +func runWorker(w *Worker) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + svc := w.Service() + _ = svc.StartAsync(ctx) + _ = svc.AwaitRunning(ctx) + time.Sleep(500 * time.Millisecond) + svc.StopAsync() + _ = svc.AwaitTerminated(ctx) + }() + + wg.Wait() +} + +func TestWorker_SuccessfulCompaction(t *testing.T) { + bucket := mockobjstore.NewMockBucket(t) + compactionClient := mockmetastorev1.NewMockCompactionServiceClient(t) + indexClient := mockmetastorev1.NewMockIndexServiceClient(t) + client := &MetastoreClientMock{ + MockCompactionServiceClient: compactionClient, + MockIndexServiceClient: indexClient, + } + + block1ID := test.ULID("2024-01-01T10:00:00Z") + block2ID := test.ULID("2024-01-01T11:00:00Z") + compactedBlockID := test.ULID("2024-01-01T12:00:00Z") + + compactFn := func(ctx context.Context, blocks []*metastorev1.BlockMeta, storage objstore.Bucket, options ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) { + require.Len(t, blocks, 2) + assert.Equal(t, block1ID, blocks[0].Id) + assert.Equal(t, block2ID, blocks[1].Id) + return []*metastorev1.BlockMeta{{Id: compactedBlockID, Tenant: 1, Shard: 1, CompactionLevel: 2}}, nil + } + + w := createTestWorker(t, client, compactFn, bucket) + + job := &metastorev1.CompactionJob{ + Name: "test-job", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + SourceBlocks: []string{block1ID, block2ID}, + } + assignment := &metastorev1.CompactionJobAssignment{ + Name: "test-job", + Token: 12345, + } + + metadata := []*metastorev1.BlockMeta{ + {Id: block1ID, Tenant: 1, Shard: 1}, + {Id: block2ID, Tenant: 1, Shard: 1}, + } + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return req.JobCapacity > 0 + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{ + CompactionJobs: []*metastorev1.CompactionJob{job}, + Assignments: []*metastorev1.CompactionJobAssignment{assignment}, + }, nil).Once() + + indexClient.EXPECT().GetBlockMetadata(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.GetBlockMetadataResponse{ + Blocks: metadata, + }, nil).Once() + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return len(req.StatusUpdates) > 0 && req.StatusUpdates[0].Status == metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Once() + + // Additional polls should return empty responses. + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Maybe() + + runWorker(w) +} + +func TestWorker_CompactionFailure(t *testing.T) { + bucket := mockobjstore.NewMockBucket(t) + compactionClient := mockmetastorev1.NewMockCompactionServiceClient(t) + indexClient := mockmetastorev1.NewMockIndexServiceClient(t) + client := &MetastoreClientMock{ + MockCompactionServiceClient: compactionClient, + MockIndexServiceClient: indexClient, + } + + block1ID := test.ULID("2024-01-01T10:00:00Z") + + compactFn := func(ctx context.Context, blocks []*metastorev1.BlockMeta, storage objstore.Bucket, options ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) { + return nil, errors.New("compaction failed") + } + + w := createTestWorker(t, client, compactFn, bucket) + + job := &metastorev1.CompactionJob{ + Name: "test-job", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + SourceBlocks: []string{block1ID}, + } + assignment := &metastorev1.CompactionJobAssignment{ + Name: "test-job", + Token: 12345, + } + + metadata := []*metastorev1.BlockMeta{ + {Id: block1ID, Tenant: 1, Shard: 1}, + } + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return req.JobCapacity > 0 + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{ + CompactionJobs: []*metastorev1.CompactionJob{job}, + Assignments: []*metastorev1.CompactionJobAssignment{assignment}, + }, nil).Once() + + indexClient.EXPECT().GetBlockMetadata(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.GetBlockMetadataResponse{ + Blocks: metadata, + }, nil).Once() + + bucket.EXPECT().IsObjNotFoundErr(mock.Anything).Return(false).Maybe() + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Maybe() + + runWorker(w) +} + +func TestWorker_JobCancellation(t *testing.T) { + bucket := mockobjstore.NewMockBucket(t) + compactionClient := mockmetastorev1.NewMockCompactionServiceClient(t) + indexClient := mockmetastorev1.NewMockIndexServiceClient(t) + client := &MetastoreClientMock{ + MockCompactionServiceClient: compactionClient, + MockIndexServiceClient: indexClient, + } + + block1ID := test.ULID("2024-01-01T10:00:00Z") + + compactFn := func(ctx context.Context, blocks []*metastorev1.BlockMeta, storage objstore.Bucket, options ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) { + return nil, context.Canceled + } + + w := createTestWorker(t, client, compactFn, bucket) + + job := &metastorev1.CompactionJob{ + Name: "test-job", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + SourceBlocks: []string{block1ID}, + } + assignment := &metastorev1.CompactionJobAssignment{ + Name: "test-job", + Token: 12345, + } + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return req.JobCapacity > 0 + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{ + CompactionJobs: []*metastorev1.CompactionJob{job}, + Assignments: []*metastorev1.CompactionJobAssignment{assignment}, + }, nil).Once() + + indexClient.EXPECT().GetBlockMetadata(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.GetBlockMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: block1ID, Tenant: 1, Shard: 1}}, + }, nil).Maybe() + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Maybe() + + runWorker(w) +} + +func TestWorker_TombstoneHandling(t *testing.T) { + bucket := mockobjstore.NewMockBucket(t) + compactionClient := mockmetastorev1.NewMockCompactionServiceClient(t) + indexClient := mockmetastorev1.NewMockIndexServiceClient(t) + client := &MetastoreClientMock{ + MockCompactionServiceClient: compactionClient, + MockIndexServiceClient: indexClient, + } + + sourceBlockID := test.ULID("2024-01-01T11:00:00Z") + compactedBlockID := test.ULID("2024-01-01T12:00:00Z") + oldBlock1ID := test.ULID("2024-01-01T08:00:00Z") + oldBlock2ID := test.ULID("2024-01-01T09:00:00Z") + + compactFn := func(ctx context.Context, blocks []*metastorev1.BlockMeta, storage objstore.Bucket, options ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) { + return []*metastorev1.BlockMeta{{Id: compactedBlockID, Tenant: 1, Shard: 1, CompactionLevel: 2}}, nil + } + + w := createTestWorker(t, client, compactFn, bucket) + + tombstones := []*metastorev1.Tombstones{{ + Blocks: &metastorev1.BlockTombstones{ + Name: "test-tombstone", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + Blocks: []string{oldBlock1ID, oldBlock2ID}, + }, + }} + + job := &metastorev1.CompactionJob{ + Name: "test-job", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + SourceBlocks: []string{sourceBlockID}, + Tombstones: tombstones, + } + assignment := &metastorev1.CompactionJobAssignment{ + Name: "test-job", + Token: 12345, + } + + metadata := []*metastorev1.BlockMeta{ + {Id: sourceBlockID, Tenant: 1, Shard: 1}, + } + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return req.JobCapacity > 0 + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{ + CompactionJobs: []*metastorev1.CompactionJob{job}, + Assignments: []*metastorev1.CompactionJobAssignment{assignment}, + }, nil).Once() + + indexClient.EXPECT().GetBlockMetadata(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.GetBlockMetadataResponse{ + Blocks: metadata, + }, nil).Once() + + bucket.EXPECT().Delete(mock.Anything, mock.MatchedBy(func(path string) bool { + return (strings.Contains(path, oldBlock1ID) || strings.Contains(path, oldBlock2ID)) && + strings.Contains(path, "test-tenant") + })).Return(nil).Times(2) + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return len(req.StatusUpdates) > 0 && req.StatusUpdates[0].Status == metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Once() + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Maybe() + + runWorker(w) +} + +func TestWorker_MetadataNotFound(t *testing.T) { + bucket := mockobjstore.NewMockBucket(t) + compactionClient := mockmetastorev1.NewMockCompactionServiceClient(t) + indexClient := mockmetastorev1.NewMockIndexServiceClient(t) + client := &MetastoreClientMock{ + MockCompactionServiceClient: compactionClient, + MockIndexServiceClient: indexClient, + } + + missingBlockID := test.ULID("2024-01-01T10:00:00Z") + + compactFn := func(ctx context.Context, blocks []*metastorev1.BlockMeta, storage objstore.Bucket, options ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) { + t.Error("compactFn should not be called when metadata is not found") + return nil, errors.New("should not be called") + } + + w := createTestWorker(t, client, compactFn, bucket) + + job := &metastorev1.CompactionJob{ + Name: "test-job", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + SourceBlocks: []string{missingBlockID}, + } + assignment := &metastorev1.CompactionJobAssignment{ + Name: "test-job", + Token: 12345, + } + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return req.JobCapacity > 0 + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{ + CompactionJobs: []*metastorev1.CompactionJob{job}, + Assignments: []*metastorev1.CompactionJobAssignment{assignment}, + }, nil).Once() + + indexClient.EXPECT().GetBlockMetadata(mock.Anything, mock.Anything, mock.Anything).Return((*metastorev1.GetBlockMetadataResponse)(nil), errors.New("metadata not found")).Once() + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Maybe() + + runWorker(w) +} + +func TestWorker_ShardTombstoneHandling(t *testing.T) { + bucket := mockobjstore.NewMockBucket(t) + compactionClient := mockmetastorev1.NewMockCompactionServiceClient(t) + indexClient := mockmetastorev1.NewMockIndexServiceClient(t) + client := &MetastoreClientMock{ + MockCompactionServiceClient: compactionClient, + MockIndexServiceClient: indexClient, + } + + sourceBlockID := test.ULID("2024-01-01T11:00:00Z") + compactedBlockID := test.ULID("2024-01-01T12:00:00Z") + oldBlock1ID := test.ULID("2024-01-01T08:00:00Z") + oldBlock2ID := test.ULID("2024-01-01T09:00:00Z") + newBlock1ID := test.ULID("2024-01-01T10:30:00Z") + newBlock2ID := test.ULID("2024-01-01T11:30:00Z") + + compactFn := func(ctx context.Context, blocks []*metastorev1.BlockMeta, storage objstore.Bucket, options ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) { + return []*metastorev1.BlockMeta{ + {Id: compactedBlockID, Tenant: 1, Shard: 1, CompactionLevel: 2}, + }, nil + } + + w := createTestWorker(t, client, compactFn, bucket) + + tombstoneTime := test.Time("2024-01-01T09:00:00Z") + duration := time.Hour + shardTombstone := &metastorev1.Tombstones{ + Shard: &metastorev1.ShardTombstone{ + Name: "test-shard-tombstone", + Tenant: "test-tenant", + Shard: 1, + Timestamp: tombstoneTime.UnixNano(), + Duration: int64(duration), + }, + } + + job := &metastorev1.CompactionJob{ + Name: "test-job", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + SourceBlocks: []string{sourceBlockID}, + Tombstones: []*metastorev1.Tombstones{shardTombstone}, + } + assignment := &metastorev1.CompactionJobAssignment{ + Name: "test-job", + Token: 12345, + } + + metadata := []*metastorev1.BlockMeta{ + {Id: sourceBlockID, Tenant: 1, Shard: 1}, + } + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return req.JobCapacity > 0 + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{ + CompactionJobs: []*metastorev1.CompactionJob{job}, + Assignments: []*metastorev1.CompactionJobAssignment{assignment}, + }, nil).Once() + + indexClient.EXPECT().GetBlockMetadata(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.GetBlockMetadataResponse{ + Blocks: metadata, + }, nil).Once() + + expectedDir := block.BuildObjectDir("test-tenant", 1) + bucket.EXPECT().Iter(mock.Anything, expectedDir, mock.Anything, mock.Anything).Run( + func(ctx context.Context, dir string, fn func(string) error, options ...thanosstore.IterOption) { + blockPaths := []string{ + block.BuildObjectPath("test-tenant", 1, 1, oldBlock1ID), // Should be deleted + block.BuildObjectPath("test-tenant", 1, 1, oldBlock2ID), // Should be deleted + block.BuildObjectPath("test-tenant", 1, 1, newBlock1ID), // SkipAll + block.BuildObjectPath("test-tenant", 1, 1, newBlock2ID), // + block.BuildObjectPath("test-tenant", 1, 1, sourceBlockID), // + } + for _, path := range blockPaths { + if err := fn(path); err != nil { + return // Return(filepath.SkipAll).Once() + } + } + }).Return(filepath.SkipAll).Once() + + bucket.EXPECT().Delete(mock.Anything, block.BuildObjectPath("test-tenant", 1, 1, oldBlock1ID)).Return(nil).Once() + bucket.EXPECT().Delete(mock.Anything, block.BuildObjectPath("test-tenant", 1, 1, oldBlock2ID)).Return(nil).Once() + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.MatchedBy(func(req *metastorev1.PollCompactionJobsRequest) bool { + return len(req.StatusUpdates) > 0 && req.StatusUpdates[0].Status == metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS + }), mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Once() + + compactionClient.EXPECT().PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything).Return(&metastorev1.PollCompactionJobsResponse{}, nil).Maybe() + + runWorker(w) +} + +var skipCompactionFn = func(context.Context, []*metastorev1.BlockMeta, objstore.Bucket, ...block.CompactionOption) ([]*metastorev1.BlockMeta, error) { + return nil, nil +} + +func TestWorker_CleanupMaxDurationAtShutdown(t *testing.T) { + bucket := mockobjstore.NewMockBucket(t) + compactionClient := mockmetastorev1.NewMockCompactionServiceClient(t) + indexClient := mockmetastorev1.NewMockIndexServiceClient(t) + client := &MetastoreClientMock{ + MockCompactionServiceClient: compactionClient, + MockIndexServiceClient: indexClient, + } + + config := Config{ + JobConcurrency: 1, + JobPollInterval: 100 * time.Millisecond, + RequestTimeout: time.Second, + CleanupMaxDuration: 15 * time.Second, + TempDir: t.TempDir(), + } + + worker, err := New( + log.NewNopLogger(), + config, + client, + bucket, + nil, // registry + nil, // ruler + nil, // exporter + ) + require.NoError(t, err) + worker.compactFn = skipCompactionFn + + job := &metastorev1.CompactionJob{Name: "test-job"} + assignment := &metastorev1.CompactionJobAssignment{Name: job.Name, Token: 12345} + job.Tombstones = []*metastorev1.Tombstones{{ + Blocks: &metastorev1.BlockTombstones{ + Name: "test-tombstone", + Tenant: "test-tenant", + Shard: 1, + CompactionLevel: 1, + Blocks: []string{"a", "b"}, + }, + }} + + var once sync.Once + done := make(chan struct{}) + triggerShutdown := func(context.Context, *metastorev1.PollCompactionJobsRequest, ...grpc.CallOption) { + once.Do(func() { close(done) }) + } + + compactionClient.EXPECT(). + PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything). + Run(triggerShutdown). + Return(&metastorev1.PollCompactionJobsResponse{ + CompactionJobs: []*metastorev1.CompactionJob{job}, + Assignments: []*metastorev1.CompactionJobAssignment{assignment}, + }, nil).Once() + + indexClient.EXPECT(). + GetBlockMetadata(mock.Anything, mock.Anything, mock.Anything). + Return(&metastorev1.GetBlockMetadataResponse{}, nil). + Once() + + var blocksDeleted atomic.Int32 + bucket.EXPECT(). + Delete(mock.Anything, mock.Anything). + Run(func(context.Context, string) { + blocksDeleted.Add(1) + time.Sleep(100 * time.Millisecond) + }).Return(nil).Times(2) + + compactionClient.EXPECT(). + PollCompactionJobs(mock.Anything, mock.Anything, mock.Anything). + Return(&metastorev1.PollCompactionJobsResponse{}, nil).Maybe() + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + svc := worker.Service() + assert.NoError(t, svc.StartAsync(ctx)) + assert.NoError(t, svc.AwaitRunning(ctx)) + + // Wait for the job to be polled and shutdown immediately. + <-done + svc.StopAsync() + assert.NoError(t, svc.AwaitTerminated(ctx)) + + require.Equal(t, 2, int(blocksDeleted.Load())) +} diff --git a/pkg/compactor/blocks_cleaner.go b/pkg/compactor/blocks_cleaner.go index 9045c96b2b..9ac3d1f1c0 100644 --- a/pkg/compactor/blocks_cleaner.go +++ b/pkg/compactor/blocks_cleaner.go @@ -7,6 +7,7 @@ package compactor import ( "context" + "errors" "fmt" "strconv" "strings" @@ -17,18 +18,17 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/concurrency" "github.com/grafana/dskit/services" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" thanos_objstore "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/bucket" - "github.com/grafana/pyroscope/pkg/phlaredb/bucketindex" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/validation" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucket" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucketindex" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/validation" ) const ( @@ -214,7 +214,7 @@ func (c *BlocksCleaner) instrumentFinishedCleanupRun(err error, logger log.Logge func (c *BlocksCleaner) refreshOwnedUsers(ctx context.Context) ([]string, map[string]bool, error) { users, deleted, err := c.tenantsScanner.ScanTenants(ctx) if err != nil { - return nil, nil, errors.Wrap(err, "failed to discover users from bucket") + return nil, nil, fmt.Errorf("failed to discover users from bucket: %w", err) } isActive := util.StringsMap(users) @@ -240,16 +240,27 @@ func (c *BlocksCleaner) refreshOwnedUsers(ctx context.Context) ([]string, map[st func (c *BlocksCleaner) cleanUsers(ctx context.Context, allUsers []string, isDeleted map[string]bool, logger log.Logger) error { return c.singleFlight.ForEachNotInFlight(ctx, allUsers, func(ctx context.Context, userID string) error { own, err := c.ownUser(userID) - if err != nil || !own { - // This returns error only if err != nil. ForEachUser keeps working for other users. - return errors.Wrap(err, "check own user") + if err != nil { + return fmt.Errorf("check own user: %w", err) + } + if !own { + return nil } userLogger := util.LoggerWithUserID(userID, logger) if isDeleted[userID] { - return errors.Wrapf(c.deleteUserMarkedForDeletion(ctx, userID, userLogger), "failed to delete user marked for deletion: %s", userID) + err = c.deleteUserMarkedForDeletion(ctx, userID, userLogger) + if err != nil { + return fmt.Errorf("failed to delete user marked for deletion: %s: %w", userID, err) + } + return nil } - return errors.Wrapf(c.cleanUser(ctx, userID, userLogger), "failed to delete blocks for user: %s", userID) + + err = c.cleanUser(ctx, userID, userLogger) + if err != nil { + return fmt.Errorf("failed to delete blocks for user: %s: %w", userID, err) + } + return nil }) } @@ -258,13 +269,13 @@ func (c *BlocksCleaner) cleanUsers(ctx context.Context, allUsers []string, isDel func (c *BlocksCleaner) deleteRemainingData(ctx context.Context, userBucket objstore.Bucket, userID string, userLogger log.Logger) error { // Delete bucket index if err := bucketindex.DeleteIndex(ctx, c.bucketClient, userID, c.cfgProvider); err != nil { - return errors.Wrap(err, "failed to delete bucket index file") + return fmt.Errorf("failed to delete bucket index file: %w", err) } level.Info(userLogger).Log("msg", "deleted bucket index for tenant with no blocks remaining") // Delete markers folder if deleted, err := objstore.DeletePrefix(ctx, userBucket, block.MarkersPathname, userLogger); err != nil { - return errors.Wrap(err, "failed to delete marker files") + return fmt.Errorf("failed to delete marker files: %w", err) } else if deleted > 0 { level.Info(userLogger).Log("msg", "deleted marker files for tenant with no blocks remaining", "count", deleted) } @@ -321,7 +332,7 @@ func (c *BlocksCleaner) deleteUserMarkedForDeletion(ctx context.Context, userID c.tenantMarkedBlocks.WithLabelValues(userID).Set(float64(failed)) c.tenantPartialBlocks.WithLabelValues(userID).Set(0) - return errors.Errorf("failed to delete %d blocks", failed) + return fmt.Errorf("failed to delete %d blocks", failed) } // Given all blocks have been deleted, we can also remove the metrics. @@ -335,7 +346,7 @@ func (c *BlocksCleaner) deleteUserMarkedForDeletion(ctx context.Context, userID mark, err := bucket.ReadTenantDeletionMark(ctx, c.bucketClient, userID) if err != nil { - return errors.Wrap(err, "failed to read tenant deletion mark") + return fmt.Errorf("failed to read tenant deletion mark: %w", err) } if mark == nil { return fmt.Errorf("cannot find tenant deletion mark anymore") @@ -347,7 +358,11 @@ func (c *BlocksCleaner) deleteUserMarkedForDeletion(ctx context.Context, userID if deletedBlocks > 0 || mark.FinishedTime == 0 { level.Info(userLogger).Log("msg", "updating finished time in tenant deletion mark") mark.FinishedTime = time.Now().Unix() - return errors.Wrap(bucket.WriteTenantDeletionMark(ctx, c.bucketClient, userID, c.cfgProvider, mark), "failed to update tenant deletion mark") + err = bucket.WriteTenantDeletionMark(ctx, c.bucketClient, userID, c.cfgProvider, mark) + if err != nil { + return fmt.Errorf("failed to update tenant deletion mark: %w", err) + } + return nil } if time.Since(time.Unix(mark.FinishedTime, 0)) < c.cfg.TenantCleanupDelay { @@ -358,7 +373,7 @@ func (c *BlocksCleaner) deleteUserMarkedForDeletion(ctx context.Context, userID // Let's do final cleanup of markers. if deleted, err := objstore.DeletePrefix(ctx, userBucket, block.MarkersPathname, userLogger); err != nil { - return errors.Wrap(err, "failed to delete marker files") + return fmt.Errorf("failed to delete marker files: %w", err) } else if deleted > 0 { level.Info(userLogger).Log("msg", "deleted marker files for tenant marked for deletion", "count", deleted) } @@ -617,7 +632,7 @@ func stalePartialBlockLastModifiedTime(ctx context.Context, blockID ulid.ULID, u } attrib, err := userBucket.Attributes(ctx, name) if err != nil { - return errors.Wrapf(err, "failed to get attributes for %s", name) + return fmt.Errorf("failed to get attributes for %s: %w", name, err) } if attrib.LastModified.After(partialDeletionCutoffTime) { return errStopIter @@ -626,7 +641,7 @@ func stalePartialBlockLastModifiedTime(ctx context.Context, blockID ulid.ULID, u lastModified = attrib.LastModified } return nil - }, thanos_objstore.WithRecursiveIter) + }, thanos_objstore.WithRecursiveIter()) if errors.Is(err, errStopIter) { return time.Time{}, nil diff --git a/pkg/compactor/blocks_cleaner_test.go b/pkg/compactor/blocks_cleaner_test.go index de4544306e..14f453883f 100644 --- a/pkg/compactor/blocks_cleaner_test.go +++ b/pkg/compactor/blocks_cleaner_test.go @@ -20,19 +20,19 @@ import ( "github.com/go-kit/log" "github.com/grafana/dskit/concurrency" "github.com/grafana/dskit/services" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/bucket" - "github.com/grafana/pyroscope/pkg/phlaredb/bucketindex" - "github.com/grafana/pyroscope/pkg/test" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/objstore" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucket" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucketindex" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/util" ) type testBlocksCleanerOptions struct { diff --git a/pkg/compactor/bucket_compactor.go b/pkg/compactor/bucket_compactor.go index 057fdadb3d..dfbc5aad87 100644 --- a/pkg/compactor/bucket_compactor.go +++ b/pkg/compactor/bucket_compactor.go @@ -20,21 +20,20 @@ import ( "github.com/grafana/dskit/concurrency" "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/prometheus/model/labels" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "go.uber.org/atomic" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) type DeduplicateFilter interface { @@ -75,9 +74,12 @@ func newSyncerMetrics(reg prometheus.Registerer, blocksMarkedForDeletion prometh Help: "Total number of failed garbage collection operations.", }) m.garbageCollectionDuration = promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ - Name: "thanos_compact_garbage_collection_duration_seconds", - Help: "Time it took to perform garbage collection iteration.", - Buckets: []float64{0.01, 0.1, 0.3, 0.6, 1, 3, 6, 9, 20, 30, 60, 90, 120, 240, 360, 720}, + Name: "thanos_compact_garbage_collection_duration_seconds", + Help: "Time it took to perform garbage collection iteration.", + Buckets: []float64{0.01, 0.1, 0.3, 0.6, 1, 3, 6, 9, 20, 30, 60, 90, 120, 240, 360, 720}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }) m.blocksMarkedForDeletion = blocksMarkedForDeletion @@ -103,7 +105,7 @@ func NewMetaSyncer(logger log.Logger, reg prometheus.Registerer, bkt objstore.Bu // SyncMetas synchronizes local state of block metas with what we have in the bucket. func (s *Syncer) SyncMetas(ctx context.Context) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SyncMetas") + sp, ctx := tracing.StartSpanFromContext(ctx, "SyncMetas") defer sp.Finish() s.mtx.Lock() defer s.mtx.Unlock() @@ -130,7 +132,7 @@ func (s *Syncer) Metas() map[ulid.ULID]*block.Meta { // block with a higher compaction level. // Call to SyncMetas function is required to populate duplicateIDs in duplicateBlocksFilter. func (s *Syncer) GarbageCollect(ctx context.Context) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "GarbageCollect") + sp, ctx := tracing.StartSpanFromContext(ctx, "GarbageCollect") defer sp.Finish() s.mtx.Lock() defer s.mtx.Unlock() @@ -156,7 +158,7 @@ func (s *Syncer) GarbageCollect(ctx context.Context) error { cancel() if err != nil { s.metrics.garbageCollectionFailures.Inc() - return errors.Wrapf(err, "mark block %s for deletion", id) + return fmt.Errorf("mark block %s for deletion: %w", id, err) } // Immediately update our in-memory state so no further call to SyncMetas is needed @@ -179,11 +181,11 @@ type Grouper interface { // DefaultGroupKey returns a unique identifier for the group the block belongs to, based on // the DefaultGrouper logic. It considers the downsampling resolution and the block's labels. func DefaultGroupKey(meta block.Meta) string { - return defaultGroupKey(meta.Downsample.Resolution, labels.FromMap(meta.Labels)) + return defaultGroupKey(meta.Resolution, labels.FromMap(meta.Labels)) } func defaultGroupKey(res int64, lbls labels.Labels) string { - return fmt.Sprintf("%d@%v", res, util.StableHash(lbls)) + return fmt.Sprintf("%d@%v", res, labels.StableHash(lbls)) } func minTime(metas []*block.Meta) time.Time { @@ -284,29 +286,44 @@ func newCompactorMetrics(r prometheus.Registerer) *CompactorMetrics { Help: "Total number of compactions done on overlapping blocks.", }) m.Duration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "pyroscope_compaction_duration_seconds", - Help: "Duration of compaction runs", - Buckets: prometheus.ExponentialBuckets(1, 2, 14), + Name: "pyroscope_compaction_duration_seconds", + Help: "Duration of compaction runs", + Buckets: prometheus.ExponentialBuckets(1, 2, 14), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"level"}) m.Size = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "pyroscope_compaction_size_bytes", - Help: "Final block size after compaction by level", - Buckets: prometheus.ExponentialBuckets(32, 1.5, 12), + Name: "pyroscope_compaction_size_bytes", + Help: "Final block size after compaction by level", + Buckets: prometheus.ExponentialBuckets(32, 1.5, 12), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"level"}) m.Samples = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "pyroscope_compaction_samples", - Help: "Final number of samples after compaction by level", - Buckets: prometheus.ExponentialBuckets(4, 1.5, 12), + Name: "pyroscope_compaction_samples", + Help: "Final number of samples after compaction by level", + Buckets: prometheus.ExponentialBuckets(4, 1.5, 12), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"level"}) m.Range = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "pyroscope_compaction_range_seconds", - Help: "Final time range after compaction by level.", - Buckets: prometheus.ExponentialBuckets(100, 4, 10), + Name: "pyroscope_compaction_range_seconds", + Help: "Final time range after compaction by level.", + Buckets: prometheus.ExponentialBuckets(100, 4, 10), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"level"}) m.Split = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "pyroscope_compaction_splits", - Help: "Compaction split factor by level.", - Buckets: []float64{1, 2, 4, 8, 16, 32, 64}, + Name: "pyroscope_compaction_splits", + Help: "Compaction split factor by level.", + Buckets: []float64{1, 2, 4, 8, 16, 32, 64}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"level"}) if r != nil { @@ -337,7 +354,7 @@ func (c *BlockCompactor) CompactWithSplitting(ctx context.Context, dest string, }, }, "local-compactor") if err != nil { - return nil, errors.Wrap(err, "create local bucket") + return nil, fmt.Errorf("create local bucket: %w", err) } defer localBucket.Close() @@ -353,18 +370,19 @@ func (c *BlockCompactor) CompactWithSplitting(ctx context.Context, dest string, }() err = func() error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "OpenBlocks", opentracing.Tag{Key: "concurrency", Value: c.blockOpenConcurrency}) + sp, ctx := tracing.StartSpanFromContext(ctx, "OpenBlocks") + sp.SetTag("concurrency", c.blockOpenConcurrency) defer sp.Finish() // Open all blocks return concurrency.ForEachJob(ctx, len(readers), c.blockOpenConcurrency, func(ctx context.Context, idx int) error { dir := dirs[idx] meta, err := block.ReadMetaFromDir(dir) if err != nil { - return errors.Wrapf(err, "failed to read meta the block dir %s", dir) + return fmt.Errorf("failed to read meta the block dir %s: %w", dir, err) } b := phlaredb.NewSingleBlockQuerierFromMeta(ctx, localBucket, meta) if err := b.Open(ctx); err != nil { - return errors.Wrapf(err, "open block %s", meta.ULID) + return fmt.Errorf("open block %s: %w", meta.ULID, err) } readers[idx] = b return nil @@ -381,9 +399,7 @@ func (c *BlockCompactor) CompactWithSplitting(ctx context.Context, dest string, } } currentLevel++ - if sp := opentracing.SpanFromContext(ctx); sp != nil { - sp.SetTag("compaction_level", currentLevel) - } + trace.SpanFromContext(ctx).SetAttributes(attribute.Int("compaction_level", currentLevel)) start := time.Now() defer func() { c.metrics.Duration.WithLabelValues(fmt.Sprintf("%d", currentLevel)).Observe(time.Since(start).Seconds()) @@ -403,7 +419,7 @@ func (c *BlockCompactor) CompactWithSplitting(ctx context.Context, dest string, Logger: c.logger, }) if err != nil { - return nil, errors.Wrapf(err, "compact blocks %v", dirs) + return nil, fmt.Errorf("compact blocks %v: %w", dirs, err) } for _, m := range metas { c.metrics.Range.WithLabelValues(fmt.Sprintf("%d", currentLevel)).Observe(float64(m.MaxTime-m.MinTime) / 1000) @@ -444,12 +460,12 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul }() if err := os.MkdirAll(subDir, 0o750); err != nil { - return false, nil, errors.Wrap(err, "create compaction job dir") + return false, nil, fmt.Errorf("create compaction job dir: %w", err) } toCompact, err := c.planner.Plan(ctx, job.metasByMinTime) if err != nil { - return false, nil, errors.Wrap(err, "plan compaction") + return false, nil, fmt.Errorf("plan compaction: %w", err) } if len(toCompact) == 0 { // Nothing to do. @@ -464,18 +480,17 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul level.Info(jobLogger).Log("msg", "compaction available and planned; downloading blocks", "blocks", len(toCompact), "plan", fmt.Sprintf("%v", toCompact)) - sp, ctx := opentracing.StartSpanFromContext(ctx, "CompactJob", - opentracing.Tag{Key: "GroupKey", Value: job.Key()}, - opentracing.Tag{Key: "Job", Value: job.String()}, - opentracing.Tag{Key: "Labels", Value: job.Labels().String()}, - opentracing.Tag{Key: "MinCompactionLevel", Value: job.MinCompactionLevel()}, - opentracing.Tag{Key: "Resolution", Value: job.Resolution()}, - opentracing.Tag{Key: "ShardKey", Value: job.ShardingKey()}, - opentracing.Tag{Key: "SplitStageSize", Value: job.SplitStageSize()}, - opentracing.Tag{Key: "UseSplitting", Value: job.UseSplitting()}, - opentracing.Tag{Key: "SplittingShards", Value: job.SplittingShards()}, - opentracing.Tag{Key: "BlockCount", Value: len(toCompact)}, - ) + sp, ctx := tracing.StartSpanFromContext(ctx, "CompactJob") + sp.SetTag("GroupKey", job.Key()) + sp.SetTag("Job", job.String()) + sp.SetTag("Labels", job.Labels().String()) + sp.SetTag("MinCompactionLevel", job.MinCompactionLevel()) + sp.SetTag("Resolution", job.Resolution()) + sp.SetTag("ShardKey", job.ShardingKey()) + sp.SetTag("SplitStageSize", job.SplitStageSize()) + sp.SetTag("UseSplitting", job.UseSplitting()) + sp.SetTag("SplittingShards", job.SplittingShards()) + sp.SetTag("BlockCount", len(toCompact)) defer sp.Finish() blocksToCompactDirs := make([]string, len(toCompact)) @@ -483,7 +498,7 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul downloadBegin := time.Now() err = func() error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "DownloadBlocks") + sp, ctx := tracing.StartSpanFromContext(ctx, "DownloadBlocks") defer func() { elapsed := time.Since(downloadBegin) level.Info(jobLogger).Log("msg", "downloaded and verified blocks; compacting blocks", "blocks", len(blocksToCompactDirs), "plan", fmt.Sprintf("%v", blocksToCompactDirs), "duration", elapsed, "duration_ms", elapsed.Milliseconds()) @@ -495,7 +510,7 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul // Must be the same as in blocksToCompactDirs. bdir := filepath.Join(subDir, meta.ULID.String()) if err := block.Download(ctx, jobLogger, c.bkt, meta.ULID, bdir); err != nil { - return errors.Wrapf(err, "download block %s", meta.ULID) + return fmt.Errorf("download block %s: %w", meta.ULID, err) } return nil @@ -509,12 +524,13 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul return nil }() if err != nil { - ext.LogError(sp, err) + sp.LogError(err) + sp.SetError() return false, nil, err } err = func() error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "CompactBlocks") + sp, ctx := tracing.StartSpanFromContext(ctx, "CompactBlocks") compactionBegin := time.Now() defer func() { sp.Finish() @@ -535,8 +551,9 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul return err }() if err != nil { - ext.LogError(sp, err) - return false, nil, errors.Wrapf(err, "compact blocks %v", blocksToCompactDirs) + sp.LogError(err) + sp.SetError() + return false, nil, fmt.Errorf("compact blocks %v: %w", blocksToCompactDirs, err) } if err = verifyCompactedBlocksTimeRanges(compIDs, toCompactMinTime.UnixMilli(), toCompactMaxTime.UnixMilli(), subDir); err != nil { @@ -546,12 +563,12 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul } // Spawn a new context so we always finish uploading and marking a block for deletion in full on shutdown. - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Minute) - ctx = opentracing.ContextWithSpan(ctx, sp) + ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 20*time.Minute) defer cancel() err = func() error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "Uploading blocks", opentracing.Tag{Key: "count", Value: len(compIDs)}) + sp, ctx := tracing.StartSpanFromContext(ctx, "Uploading blocks") + sp.SetTag("count", len(compIDs)) uploadBegin := time.Now() uploadedBlocks := atomic.NewInt64(0) defer func() { @@ -568,17 +585,17 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul newMeta, err := block.ReadMetaFromDir(bdir) if err != nil { - return errors.Wrapf(err, "failed to read meta the block dir %s", bdir) + return fmt.Errorf("failed to read meta the block dir %s: %w", bdir, err) } // Ensure the compacted block is valid. if err := phlaredb.ValidateLocalBlock(ctx, bdir); err != nil { - return errors.Wrapf(err, "invalid result block %s", bdir) + return fmt.Errorf("invalid result block %s: %w", bdir, err) } begin := time.Now() if err := block.Upload(ctx, jobLogger, c.bkt, bdir); err != nil { - return errors.Wrapf(err, "upload of %s failed", ulidToUpload) + return fmt.Errorf("upload of %s failed: %w", ulidToUpload, err) } elapsed := time.Since(begin) @@ -588,18 +605,20 @@ func (c *BucketCompactor) runCompactionJob(ctx context.Context, job *Job) (shoul }() if err != nil { - ext.LogError(sp, err) + sp.LogError(err) + sp.SetError() return false, nil, err } - sp, ctx = opentracing.StartSpanFromContext(ctx, "Deleting blocks", opentracing.Tag{Key: "count", Value: len(compIDs)}) + sp, ctx = tracing.StartSpanFromContext(ctx, "Deleting blocks") + sp.SetTag("count", len(compIDs)) defer sp.Finish() // Mark for deletion the blocks we just compacted from the job and bucket so they do not get included // into the next planning cycle. // Eventually the block we just uploaded should get synced into the job again (including sync-delay). for _, meta := range toCompact { if err := deleteBlock(ctx, c.bkt, meta.ULID, filepath.Join(subDir, meta.ULID.String()), jobLogger, c.metrics.blocksMarkedForDeletion); err != nil { - return false, nil, errors.Wrapf(err, "mark old block for deletion from bucket") + return false, nil, fmt.Errorf("mark old block for deletion from bucket: %w", err) } } @@ -621,7 +640,7 @@ func verifyCompactedBlocksTimeRanges(compIDs []ulid.ULID, sourceBlocksMinTime, s bdir := filepath.Join(subDir, compID.String()) meta, err := block.ReadMetaFromDir(bdir) if err != nil { - return errors.Wrapf(err, "failed to read meta.json from %s during block time range verification", bdir) + return fmt.Errorf("failed to read meta.json from %s during block time range verification: %w", bdir, err) } // Ensure compacted block min/maxTime within source blocks min/maxTime @@ -653,11 +672,11 @@ func verifyCompactedBlocksTimeRanges(compIDs []ulid.ULID, sourceBlocksMinTime, s func deleteBlock(ctx context.Context, bkt objstore.Bucket, id ulid.ULID, bdir string, logger log.Logger, blocksMarkedForDeletion prometheus.Counter) error { if err := os.RemoveAll(bdir); err != nil { - return errors.Wrapf(err, "remove old block dir %s", id) + return fmt.Errorf("remove old block dir %s: %w", id, err) } level.Info(logger).Log("msg", "marking compacted block for deletion", "old_block", id) if err := block.MarkForDeletion(ctx, logger, bkt, id, "source of compacted block", true, blocksMarkedForDeletion); err != nil { - return errors.Wrapf(err, "mark block %s for deletion from bucket", id) + return fmt.Errorf("mark block %s for deletion from bucket: %w", id, err) } return nil } @@ -704,9 +723,12 @@ func NewBucketCompactorMetrics(blocksMarkedForDeletion prometheus.Counter, reg p ConstLabels: prometheus.Labels{"reason": block.OutOfOrderChunksNoCompactReason}, }), blocksMaxTimeDelta: promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_compactor_block_max_time_delta_seconds", - Help: "Difference between now and the max time of a block being compacted in seconds.", - Buckets: prometheus.LinearBuckets(86400, 43200, 8), // 1 to 5 days, in 12 hour intervals + Name: "pyroscope_compactor_block_max_time_delta_seconds", + Help: "Difference between now and the max time of a block being compacted in seconds.", + Buckets: prometheus.LinearBuckets(86400, 43200, 8), // 1 to 5 days, in 12 hour intervals + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), } } @@ -752,7 +774,7 @@ func NewBucketCompactor( metrics *BucketCompactorMetrics, ) (*BucketCompactor, error) { if concurrency <= 0 { - return nil, errors.Errorf("invalid concurrency level (%d), concurrency level must be > 0", concurrency) + return nil, fmt.Errorf("invalid concurrency level (%d), concurrency level must be > 0", concurrency) } return &BucketCompactor{ logger: logger, @@ -774,10 +796,8 @@ func NewBucketCompactor( // Compact runs compaction over bucket. // If maxCompactionTime is positive then after this time no more new compactions are started. func (c *BucketCompactor) Compact(ctx context.Context, maxCompactionTime time.Duration) (rerr error) { - sp := opentracing.SpanFromContext(ctx) - if sp == nil { - sp, ctx = opentracing.StartSpanFromContext(ctx, "Compact") - } + sp, ctx := tracing.StartSpanFromContext(ctx, "Compact") + defer sp.Finish() sp.SetTag("max_compaction_time", maxCompactionTime) sp.SetTag("concurrency", c.concurrency) defer func() { @@ -847,7 +867,7 @@ func (c *BucketCompactor) Compact(ctx context.Context, maxCompactionTime time.Du // At this point the compaction has failed. c.metrics.groupCompactionRunsFailed.Inc() - errChan <- errors.Wrapf(err, "group %s", g.Key()) + errChan <- fmt.Errorf("group %s: %w", g.Key(), err) return } }() @@ -855,24 +875,30 @@ func (c *BucketCompactor) Compact(ctx context.Context, maxCompactionTime time.Du level.Info(c.logger).Log("msg", "start sync of metas") if err := c.sy.SyncMetas(ctx); err != nil { - ext.LogError(sp, err) - return errors.Wrap(err, "sync") + sp.LogError(err) + sp.SetError() + return fmt.Errorf("sync: %w", err) } level.Info(c.logger).Log("msg", "start of GC") // Blocks that were compacted are garbage collected after each Compaction. // However if compactor crashes we need to resolve those on startup. if err := c.sy.GarbageCollect(ctx); err != nil { - ext.LogError(sp, err) - return errors.Wrap(err, "blocks garbage collect") + sp.LogError(err) + sp.SetError() + return fmt.Errorf("blocks garbage collect: %w", err) } jobs, err := c.grouper.Groups(c.sy.Metas()) if err != nil { - ext.LogError(sp, err) - return errors.Wrap(err, "build compaction jobs") + sp.LogError(err) + sp.SetError() + return fmt.Errorf("build compaction jobs: %w", err) } - sp.LogKV("discovered_jobs", len(jobs)) + otelSpan := trace.SpanFromContext(ctx) + otelSpan.AddEvent("discovered compaction jobs", trace.WithAttributes( + attribute.Int("discovered_jobs", len(jobs)), + )) // There is another check just before we start processing the job, but we can avoid sending it // to the goroutine in the first place. @@ -880,7 +906,9 @@ func (c *BucketCompactor) Compact(ctx context.Context, maxCompactionTime time.Du if err != nil { return err } - sp.LogKV("own_jobs", len(jobs)) + otelSpan.AddEvent("filtered own jobs", trace.WithAttributes( + attribute.Int("own_jobs", len(jobs)), + )) // Record the difference between now and the max time for a block being compacted. This // is used to detect compactors not being able to keep up with the rate of blocks being @@ -892,7 +920,9 @@ func (c *BucketCompactor) Compact(ctx context.Context, maxCompactionTime time.Du // Skip jobs for which the wait period hasn't been honored yet. jobs = c.filterJobsByWaitPeriod(ctx, jobs) - sp.LogKV("filtered_jobs", len(jobs)) + otelSpan.AddEvent("filtered jobs by wait period", trace.WithAttributes( + attribute.Int("filtered_jobs", len(jobs)), + )) // Sort jobs based on the configured ordering algorithm. jobs = c.sortJobs(jobs) @@ -917,14 +947,15 @@ func (c *BucketCompactor) Compact(ctx context.Context, maxCompactionTime time.Du for _, g := range jobs { select { case jobErr := <-errChan: - ext.LogError(sp, jobErr) + sp.LogError(jobErr) + sp.SetError() jobErrs.Add(jobErr) break jobLoop case jobChan <- g: case <-maxCompactionTimeChan: maxCompactionTimeReached = true level.Info(c.logger).Log("msg", "max compaction time reached, no more compactions will be started") - sp.LogKV("msg", "max compaction time reached, no more compactions will be started") + trace.SpanFromContext(ctx).AddEvent("max compaction time reached, no more compactions will be started") break jobLoop } } @@ -969,7 +1000,7 @@ func (c *BucketCompactor) filterOwnJobs(jobs []*Job) ([]*Job, error) { for ix := 0; ix < len(jobs); { // Skip any job which doesn't belong to this compactor instance. if ok, err := c.ownJob(jobs[ix]); err != nil { - return nil, errors.Wrap(err, "ownJob") + return nil, fmt.Errorf("ownJob: %w", err) } else if !ok { jobs = append(jobs[:ix], jobs[ix+1:]...) } else { @@ -1048,7 +1079,7 @@ func (f *NoCompactionMarkFilter) Filter(ctx context.Context, metas map[ulid.ULID return nil }) if err != nil { - return errors.Wrap(err, "list block no-compact marks") + return fmt.Errorf("list block no-compact marks: %w", err) } f.noCompactMarkedMap = noCompactMarkedMap diff --git a/pkg/compactor/bucket_compactor_e2e_test.go b/pkg/compactor/bucket_compactor_e2e_test.go index 858a3e3ef8..8e5ee1463a 100644 --- a/pkg/compactor/bucket_compactor_e2e_test.go +++ b/pkg/compactor/bucket_compactor_e2e_test.go @@ -18,7 +18,7 @@ import ( "time" "github.com/go-kit/log" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" promtest "github.com/prometheus/client_golang/prometheus/testutil" @@ -27,10 +27,10 @@ import ( "github.com/stretchr/testify/require" "github.com/thanos-io/objstore" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) func TestSyncer_GarbageCollect_e2e(t *testing.T) { @@ -65,21 +65,21 @@ func TestSyncer_GarbageCollect_e2e(t *testing.T) { m1.ULID = ulid.MustNew(100, nil) m1.Compaction.Level = 2 m1.Compaction.Sources = ids[:4] - m1.Downsample.Resolution = 0 + m1.Resolution = 0 var m2 block.Meta m2.Version = 1 m2.ULID = ulid.MustNew(200, nil) m2.Compaction.Level = 2 m2.Compaction.Sources = ids[4:8] // last two source IDs is not part of a level 2 block. - m2.Downsample.Resolution = 0 + m2.Resolution = 0 var m3 block.Meta m3.Version = 1 m3.ULID = ulid.MustNew(300, nil) m3.Compaction.Level = 3 m3.Compaction.Sources = ids[:9] // last source ID is not part of level 3 block. - m3.Downsample.Resolution = 0 + m3.Resolution = 0 m3.MinTime = 0 m3.MaxTime = model.Time(2 * time.Hour.Milliseconds()) @@ -88,7 +88,7 @@ func TestSyncer_GarbageCollect_e2e(t *testing.T) { m4.ULID = ulid.MustNew(400, nil) m4.Compaction.Level = 2 m4.Compaction.Sources = ids[9:] // covers the last block but is a different resolution. Must not trigger deletion. - m4.Downsample.Resolution = 1000 + m4.Resolution = 1000 m4.MinTime = 0 m4.MaxTime = model.Time(2 * time.Hour.Milliseconds()) @@ -97,7 +97,7 @@ func TestSyncer_GarbageCollect_e2e(t *testing.T) { m5.ULID = ulid.MustNew(500, nil) m5.Compaction.Level = 2 m5.Compaction.Sources = ids[8:9] // built from block 8, but different resolution. Block 8 is already included in m3, can be deleted. - m5.Downsample.Resolution = 1000 + m5.Resolution = 1000 m5.MinTime = 0 m5.MaxTime = model.Time(2 * time.Hour.Milliseconds()) diff --git a/pkg/compactor/bucket_compactor_test.go b/pkg/compactor/bucket_compactor_test.go index d6eb654cf3..887b0bb4a5 100644 --- a/pkg/compactor/bucket_compactor_test.go +++ b/pkg/compactor/bucket_compactor_test.go @@ -14,7 +14,7 @@ import ( "time" "github.com/go-kit/log" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/testutil" @@ -23,10 +23,10 @@ import ( "github.com/stretchr/testify/require" "github.com/thanos-io/objstore" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/util/extprom" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/util/extprom" ) func TestGroupKey(t *testing.T) { diff --git a/pkg/compactor/compactor.go b/pkg/compactor/compactor.go index e2eb931efa..85041d29c0 100644 --- a/pkg/compactor/compactor.go +++ b/pkg/compactor/compactor.go @@ -6,6 +6,7 @@ package compactor import ( "context" + "errors" "flag" "fmt" "hash/fnv" @@ -23,18 +24,16 @@ import ( "github.com/grafana/dskit/kv" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/atomic" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/bucket" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucket" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -100,6 +99,7 @@ type Config struct { DeletionDelay time.Duration `yaml:"deletion_delay" category:"advanced"` TenantCleanupDelay time.Duration `yaml:"tenant_cleanup_delay" category:"advanced"` MaxCompactionTime time.Duration `yaml:"max_compaction_time" category:"advanced"` + ShutdownTimeout time.Duration `yaml:"shutdown_timeout" category:"advanced"` NoBlocksFileCleanupEnabled bool `yaml:"no_blocks_file_cleanup_enabled" category:"experimental"` DownsamplerEnabled bool `yaml:"downsampler_enabled" category:"advanced"` @@ -142,6 +142,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet, logger log.Logger) { f.StringVar(&cfg.DataDir, "compactor.data-dir", "./data-compactor", "Directory to temporarily store blocks during compaction. This directory is not required to be persisted between restarts.") f.DurationVar(&cfg.CompactionInterval, "compactor.compaction-interval", 30*time.Minute, "The frequency at which the compaction runs") f.DurationVar(&cfg.MaxCompactionTime, "compactor.max-compaction-time", time.Hour, "Max time for starting compactions for a single tenant. After this time no new compactions for the tenant are started before next compaction cycle. This can help in multi-tenant environments to avoid single tenant using all compaction time, but also in single-tenant environments to force new discovery of blocks more often. 0 = disabled.") + f.DurationVar(&cfg.ShutdownTimeout, "compactor.shutdown-timeout", 0, "Maximum time to wait for in-flight cleanup and ring operations to finish during shutdown. If the timeout is reached, the compactor will forcefully stop. 0 = no timeout (wait indefinitely).") f.IntVar(&cfg.CompactionRetries, "compactor.compaction-retries", 3, "How many times to retry a failed compaction within a single compaction run.") f.IntVar(&cfg.CompactionConcurrency, "compactor.compaction-concurrency", 1, "Max number of concurrent compactions running.") f.DurationVar(&cfg.CompactionWaitPeriod, "compactor.first-level-compaction-wait-period", 25*time.Minute, "How long the compactor waits before compacting first-level blocks that are uploaded by the ingesters. This configuration option allows for the reduction of cases where the compactor begins to compact blocks before all ingesters have uploaded their blocks to the storage.") @@ -164,12 +165,12 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet, logger log.Logger) { func (cfg *Config) Validate(maxBlockDuration time.Duration) error { if len(cfg.BlockRanges) > 0 && cfg.BlockRanges[0]%maxBlockDuration != 0 { - return errors.Errorf(errInvalidBlockDuration, cfg.BlockRanges[0].String(), maxBlockDuration.String()) + return fmt.Errorf(errInvalidBlockDuration, cfg.BlockRanges[0].String(), maxBlockDuration.String()) } // Each block range period should be divisible by the previous one. for i := 1; i < len(cfg.BlockRanges); i++ { if cfg.BlockRanges[i]%cfg.BlockRanges[i-1] != 0 { - return errors.Errorf(errInvalidBlockRanges, cfg.BlockRanges[i].String(), cfg.BlockRanges[i-1].String()) + return fmt.Errorf(errInvalidBlockRanges, cfg.BlockRanges[i].String(), cfg.BlockRanges[i-1].String()) } } @@ -293,7 +294,7 @@ func NewMultitenantCompactor(compactorCfg Config, bucketClient objstore.Bucket, c, err := newMultitenantCompactor(compactorCfg, bucketClient, cfgProvider, logger, registerer, blocksGrouperFactory, blocksCompactorFactory, blocksPlannerFactory) if err != nil { - return nil, errors.Wrap(err, "failed to create blocks compactor") + return nil, fmt.Errorf("failed to create blocks compactor: %w", err) } return c, nil @@ -428,19 +429,19 @@ func (c *MultitenantCompactor) starting(ctx context.Context) error { c.ringSubservices, err = services.NewManager(c.ringLifecycler, c.ring) if err != nil { - return errors.Wrap(err, "unable to create compactor ring dependencies") + return fmt.Errorf("unable to create compactor ring dependencies: %w", err) } c.ringSubservicesWatcher = services.NewFailureWatcher() c.ringSubservicesWatcher.WatchManager(c.ringSubservices) if err = c.ringSubservices.StartAsync(ctx); err != nil { - return errors.Wrap(err, "unable to start compactor ring dependencies") + return fmt.Errorf("unable to start compactor ring dependencies: %w", err) } ctxTimeout, cancel := context.WithTimeout(ctx, c.compactorCfg.ShardingRing.WaitActiveInstanceTimeout) defer cancel() if err = c.ringSubservices.AwaitHealthy(ctxTimeout); err != nil { - return errors.Wrap(err, "unable to start compactor ring dependencies") + return fmt.Errorf("unable to start compactor ring dependencies: %w", err) } // If sharding is enabled we should wait until this instance is ACTIVE within the ring. This @@ -448,7 +449,7 @@ func (c *MultitenantCompactor) starting(ctx context.Context) error { // the users scanner depends on the ring (to check whether a user belongs to this shard or not). level.Info(c.logger).Log("msg", "waiting until compactor is ACTIVE in the ring") if err = ring.WaitInstanceState(ctxTimeout, c.ring, c.ringLifecycler.GetInstanceID(), ring.ACTIVE); err != nil { - return errors.Wrap(err, "compactor failed to become ACTIVE in the ring") + return fmt.Errorf("compactor failed to become ACTIVE in the ring: %w", err) } level.Info(c.logger).Log("msg", "compactor is ACTIVE in the ring") @@ -485,7 +486,7 @@ func (c *MultitenantCompactor) starting(ctx context.Context) error { // Start blocks cleaner asynchronously, don't wait until initial cleanup is finished. if err := c.blocksCleaner.StartAsync(ctx); err != nil { c.ringSubservices.StopAsync() - return errors.Wrap(err, "failed to start the blocks cleaner") + return fmt.Errorf("failed to start the blocks cleaner: %w", err) } return nil @@ -495,12 +496,12 @@ func newRingAndLifecycler(cfg RingConfig, logger log.Logger, reg prometheus.Regi reg = prometheus.WrapRegistererWithPrefix("pyroscope_", reg) kvStore, err := kv.NewClient(cfg.Common.KVStore, ring.GetCodec(), kv.RegistererWithKVName(reg, "compactor-lifecycler"), logger) if err != nil { - return nil, nil, errors.Wrap(err, "failed to initialize compactors' KV store") + return nil, nil, fmt.Errorf("failed to initialize compactors' KV store: %w", err) } lifecyclerCfg, err := cfg.ToBasicLifecyclerConfig(logger) if err != nil { - return nil, nil, errors.Wrap(err, "failed to build compactors' lifecycler config") + return nil, nil, fmt.Errorf("failed to build compactors' lifecycler config: %w", err) } var delegate ring.BasicLifecyclerDelegate @@ -510,12 +511,12 @@ func newRingAndLifecycler(cfg RingConfig, logger log.Logger, reg prometheus.Regi compactorsLifecycler, err := ring.NewBasicLifecycler(lifecyclerCfg, "compactor", ringKey, kvStore, delegate, logger, reg) if err != nil { - return nil, nil, errors.Wrap(err, "failed to initialize compactors' lifecycler") + return nil, nil, fmt.Errorf("failed to initialize compactors' lifecycler: %w", err) } compactorsRing, err := ring.New(cfg.toRingConfig(), "compactor", ringKey, logger, reg) if err != nil { - return nil, nil, errors.Wrap(err, "failed to initialize compactors' ring client") + return nil, nil, fmt.Errorf("failed to initialize compactors' ring client: %w", err) } return compactorsRing, compactorsLifecycler, nil @@ -523,8 +524,15 @@ func newRingAndLifecycler(cfg RingConfig, logger log.Logger, reg prometheus.Regi func (c *MultitenantCompactor) stopping(_ error) error { ctx := context.Background() + if c.compactorCfg.ShutdownTimeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, c.compactorCfg.ShutdownTimeout) + defer cancel() + } - services.StopAndAwaitTerminated(ctx, c.blocksCleaner) //nolint:errcheck + if err := services.StopAndAwaitTerminated(ctx, c.blocksCleaner); err != nil { + level.Warn(c.logger).Log("msg", "error stopping blocks cleaner", "err", err) + } if c.ringSubservices != nil { return services.StopManagerAndAwaitStopped(ctx, c.ringSubservices) } @@ -545,13 +553,13 @@ func (c *MultitenantCompactor) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-c.ringSubservicesWatcher.Chan(): - return errors.Wrap(err, "compactor subservice failed") + return fmt.Errorf("compactor subservice failed: %w", err) } } } func (c *MultitenantCompactor) compactUsers(ctx context.Context) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "CompactUsers") + sp, ctx := tracing.StartSpanFromContext(ctx, "CompactUsers") defer sp.Finish() succeeded := false @@ -568,7 +576,7 @@ func (c *MultitenantCompactor) compactUsers(ctx context.Context) { } else { c.compactionRunsErred.Inc() } - sp.LogKV("error_count", compactionErrorCount) + sp.SetTag("error_count", compactionErrorCount) // Reset progress metrics once done. c.compactionRunDiscoveredTenants.Set(0) @@ -586,7 +594,7 @@ func (c *MultitenantCompactor) compactUsers(ctx context.Context) { } return } - sp.LogKV("discovered_user_count", len(users)) + sp.SetTag("discovered_user_count", len(users)) level.Info(c.logger).Log("msg", "discovered users from bucket", "users", len(users)) c.compactionRunDiscoveredTenants.Set(float64(len(users))) @@ -600,7 +608,7 @@ func (c *MultitenantCompactor) compactUsers(ctx context.Context) { // Keep track of users owned by this shard, so that we can delete the local files for all other users. ownedUsers := map[string]struct{}{} defer func() { - sp.LogKV("owned_user_count", len(ownedUsers)) + sp.SetTag("owned_user_count", len(ownedUsers)) }() for _, userID := range users { // Ensure the context has not been canceled (ie. compactor shutdown has been triggered). @@ -692,13 +700,15 @@ func (c *MultitenantCompactor) compactUserWithRetries(ctx context.Context, userI }) for retries.Ongoing() { - sp, ctx := opentracing.StartSpanFromContext(ctx, "CompactUser", opentracing.Tag{Key: "tenantID", Value: userID}) + sp, ctx := tracing.StartSpanFromContext(ctx, "CompactUser") + sp.SetTag("tenantID", userID) lastErr = c.compactUser(ctx, userID) if lastErr == nil { sp.Finish() return nil } - ext.LogError(sp, lastErr) + sp.LogError(lastErr) + sp.SetError() sp.Finish() retries.Wait() } @@ -745,13 +755,13 @@ func (c *MultitenantCompactor) compactUser(ctx context.Context, userID string) e c.blocksMarkedForDeletion, ) if err != nil { - return errors.Wrap(err, "failed to create syncer") + return fmt.Errorf("failed to create syncer: %w", err) } // Create blocks compactor dependencies. blocksCompactor, err := c.blocksCompactorFactory(ctx, c.compactorCfg, c.cfgProvider, userID, c.logger, c.compactorMetrics) if err != nil { - return errors.Wrap(err, "failed to initialize compactor dependencies") + return fmt.Errorf("failed to initialize compactor dependencies: %w", err) } compactor, err := NewBucketCompactor( @@ -770,18 +780,18 @@ func (c *MultitenantCompactor) compactUser(ctx context.Context, userID string) e c.bucketCompactorMetrics, ) if err != nil { - return errors.Wrap(err, "failed to create bucket compactor") + return fmt.Errorf("failed to create bucket compactor: %w", err) } if err := compactor.Compact(ctx, c.compactorCfg.MaxCompactionTime); err != nil { - return errors.Wrap(err, "compaction") + return fmt.Errorf("compaction: %w", err) } return nil } func (c *MultitenantCompactor) discoverUsersWithRetries(ctx context.Context) ([]string, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "DiscoverUsers") + sp, ctx := tracing.StartSpanFromContext(ctx, "DiscoverUsers") defer sp.Finish() var lastErr error diff --git a/pkg/compactor/compactor_http.go b/pkg/compactor/compactor_http.go index 3fd5190fdf..9ca444628a 100644 --- a/pkg/compactor/compactor_http.go +++ b/pkg/compactor/compactor_http.go @@ -13,7 +13,7 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/services" - util_log "github.com/grafana/pyroscope/pkg/util" + util_log "github.com/grafana/pyroscope/v2/pkg/util" ) var ( diff --git a/pkg/compactor/compactor_ring.go b/pkg/compactor/compactor_ring.go index 02813bc86d..7b79c192ac 100644 --- a/pkg/compactor/compactor_ring.go +++ b/pkg/compactor/compactor_ring.go @@ -7,13 +7,14 @@ package compactor import ( "flag" - "fmt" + "net" + "strconv" "time" "github.com/go-kit/log" "github.com/grafana/dskit/ring" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -64,7 +65,7 @@ func (cfg *RingConfig) ToBasicLifecyclerConfig(logger log.Logger) (ring.BasicLif return ring.BasicLifecyclerConfig{ ID: cfg.Common.InstanceID, - Addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), + Addr: net.JoinHostPort(instanceAddr, strconv.Itoa(instancePort)), HeartbeatPeriod: cfg.Common.HeartbeatPeriod, HeartbeatTimeout: cfg.Common.HeartbeatTimeout, TokensObservePeriod: cfg.ObservePeriod, diff --git a/pkg/compactor/compactor_test.go b/pkg/compactor/compactor_test.go index ba0b89dc26..9b00eaff8e 100644 --- a/pkg/compactor/compactor_test.go +++ b/pkg/compactor/compactor_test.go @@ -10,6 +10,7 @@ import ( "context" "crypto/rand" "encoding/json" + "errors" "flag" "fmt" "os" @@ -27,8 +28,7 @@ import ( "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" "github.com/grafana/dskit/test" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" "github.com/prometheus/common/model" @@ -36,15 +36,16 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/thanos-io/objstore" - "gopkg.in/yaml.v3" - - pyroscope_objstore "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/block/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/bucket" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" - "github.com/grafana/pyroscope/pkg/validation" + "go.yaml.in/yaml/v3" + + pyroscope_objstore "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucket" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" + "github.com/grafana/pyroscope/v2/pkg/validation" ) const ( @@ -112,7 +113,7 @@ func TestConfig_Validate(t *testing.T) { setup: func(cfg *Config) { cfg.BlockRanges = DurationList{2 * time.Hour, 12 * time.Hour, 24 * time.Hour, 30 * time.Hour} }, - expected: errors.Errorf(errInvalidBlockRanges, 30*time.Hour, 24*time.Hour).Error(), + expected: fmt.Errorf(errInvalidBlockRanges, 30*time.Hour, 24*time.Hour).Error(), maxBlock: 2 * time.Hour, }, "should fail on unknown compaction jobs order": { @@ -131,7 +132,7 @@ func TestConfig_Validate(t *testing.T) { setup: func(cfg *Config) { cfg.BlockRanges = DurationList{2 * time.Hour, 12 * time.Hour, 24 * time.Hour} }, - expected: errors.Errorf(errInvalidBlockDuration, (2 * time.Hour).String(), (15 * time.Hour).String()).Error(), + expected: fmt.Errorf(errInvalidBlockDuration, (2 * time.Hour).String(), (15 * time.Hour).String()).Error(), maxBlock: 15 * time.Hour, }, } @@ -155,7 +156,7 @@ func TestMultitenantCompactor_ShouldDoNothingOnNoUserBlocks(t *testing.T) { t.Parallel() // No user blocks stored in the bucket. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{}, nil) cfg := prepareConfig(t) c, _, _, logs, registry := prepare(t, cfg, bucketClient) @@ -290,7 +291,7 @@ func TestMultitenantCompactor_ShouldRetryCompactionOnFailureWhileDiscoveringUser t.Parallel() // Fail to iterate over the bucket while discovering users. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", nil, errors.New("failed to iterate the bucket")) c, _, _, logs, registry := prepare(t, prepareConfig(t), bucketClient) @@ -429,7 +430,7 @@ func TestMultitenantCompactor_ShouldIncrementCompactionErrorIfFailedToCompactASi t.Parallel() userID := "test-user" - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{userID}, nil) bucketClient.MockIter(userID+"/phlaredb/", []string{userID + "/phlaredb/01DTVP434PA9VFXSW2JKB3392D", userID + "/phlaredb/01DTW0ZCPDDNV4BV83Q2SV4QAZ"}, nil) bucketClient.MockIter(userID+"/phlaredb/markers/", nil, nil) @@ -478,7 +479,7 @@ func TestMultitenantCompactor_ShouldIncrementCompactionShutdownIfTheContextIsCan t.Parallel() userID := "test-user" - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{userID}, nil) bucketClient.MockIter(userID+"/phlaredb/markers/", nil, nil) bucketClient.MockIter(userID+"/phlaredb/", []string{userID + "/phlaredb/01DTVP434PA9VFXSW2JKB3392D", userID + "/phlaredb/01DTW0ZCPDDNV4BV83Q2SV4QAZ"}, nil) @@ -531,7 +532,7 @@ func TestMultitenantCompactor_ShouldIterateOverUsersAndRunCompaction(t *testing. t.Parallel() // Mock the bucket to contain two users, each one with two blocks (to make sure that grouper doesn't skip them). - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1", "user-2"}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb/", bucket.TenantDeletionMarkPath), false, nil) bucketClient.MockExists(path.Join("user-2", "phlaredb/", bucket.TenantDeletionMarkPath), false, nil) @@ -676,7 +677,7 @@ func TestMultitenantCompactor_ShouldStopCompactingTenantOnReachingMaxCompactionT // By using blocks with different labels, we get two compaction jobs. Only one of these jobs will be started, // and since its planning will take longer than maxCompactionTime, we stop compactions early. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1"}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb/", bucket.TenantDeletionMarkPath), false, nil) bucketClient.MockIter("user-1/phlaredb/", []string{"user-1/phlaredb/01DTVP434PA9VFXSW2JKB3392D", "user-1/phlaredb/01FN3VCQV5X342W2ZKMQQXAZRX", "user-1/phlaredb/01FS51A7GQ1RQWV35DBVYQM4KF", "user-1/phlaredb/01FRQGQB7RWQ2TS0VWA82QTPXE"}, nil) @@ -746,7 +747,7 @@ func TestMultitenantCompactor_ShouldNotCompactBlocksMarkedForDeletion(t *testing cfg.DeletionDelay = 10 * time.Minute // Delete block after 10 minutes // Mock the bucket to contain two users, each one with one block. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1"}, nil) bucketClient.MockIter("user-1/phlaredb/", []string{"user-1/phlaredb/01DTVP434PA9VFXSW2JKB3392D", "user-1/phlaredb/01DTW0ZCPDDNV4BV83Q2SV4QAZ"}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb/", bucket.TenantDeletionMarkPath), false, nil) @@ -864,7 +865,7 @@ func TestMultitenantCompactor_ShouldNotCompactBlocksMarkedForNoCompaction(t *tes cfg.DeletionDelay = 10 * time.Minute // Delete block after 10 minutes // Mock the bucket to contain one user with a block marked for no-compaction. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1"}, nil) bucketClient.MockIter("user-1/phlaredb/", []string{"user-1/phlaredb/01DTVP434PA9VFXSW2JKB3392D"}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb/", bucket.TenantDeletionMarkPath), false, nil) @@ -918,7 +919,7 @@ func TestMultitenantCompactor_ShouldNotCompactBlocksForUsersMarkedForDeletion(t cfg.TenantCleanupDelay = 10 * time.Minute // To make sure it's not 0. // Mock the bucket to contain two users, each one with one block. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1"}, nil) bucketClient.MockIter("user-1/phlaredb/", []string{"user-1/phlaredb/01DTVP434PA9VFXSW2JKB3392D"}, nil) bucketClient.MockGet(path.Join("user-1", "phlaredb/", bucket.TenantDeletionMarkPath), `{"deletion_time": 1}`, nil) @@ -1019,7 +1020,7 @@ func TestMultitenantCompactor_ShouldCompactAllUsersOnShardingEnabledButOnlyOneIn t.Parallel() // Mock the bucket to contain two users, each one with one block. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1", "user-2"}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb", bucket.TenantDeletionMarkPath), false, nil) bucketClient.MockExists(path.Join("user-2", "phlaredb", bucket.TenantDeletionMarkPath), false, nil) @@ -1156,7 +1157,7 @@ func TestMultitenantCompactor_ShouldCompactOnlyUsersOwnedByTheInstanceOnSharding } // Mock the bucket to contain all users, each one with one block. - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", userIDs, nil) for _, userID := range userIDs { bucketClient.MockIter(userID+"/phlaredb/", []string{userID + "/phlaredb/01DTVP434PA9VFXSW2JKB3392D"}, nil) @@ -1232,7 +1233,7 @@ func TestMultitenantCompactor_ShouldSkipCompactionForJobsNoMoreOwnedAfterPlannin // Mock the bucket to contain one user with two non-overlapping blocks (we expect two compaction jobs to be scheduled // for the splitting stage). - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1"}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb", bucket.TenantDeletionMarkPath), false, nil) bucketClient.MockIter("user-1/phlaredb/", []string{"user-1/phlaredb/01DTVP434PA9VFXSW2JK000001", "user-1/phlaredb/01DTVP434PA9VFXSW2JK000002"}, nil) @@ -1861,7 +1862,7 @@ func TestMultitenantCompactor_ShouldFailCompactionOnTimeout(t *testing.T) { t.Parallel() // Mock the bucket - bucketClient := &pyroscope_objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{}, nil) ringStore, closer := consul.NewInMemoryClient(ring.GetCodec(), log.NewNopLogger(), nil) diff --git a/pkg/compactor/job.go b/pkg/compactor/job.go index 162a846666..8df9ad8437 100644 --- a/pkg/compactor/job.go +++ b/pkg/compactor/job.go @@ -6,18 +6,18 @@ package compactor import ( "context" + "errors" "fmt" "math" "path" "sort" "time" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/prometheus/model/labels" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) // Job holds a compaction job, which consists of a group of blocks that should be compacted together. @@ -65,7 +65,7 @@ func (job *Job) AppendMeta(meta *block.Meta) error { if !labels.Equal(labelsWithout(job.labels.Map(), block.HostnameLabel), labelsWithout(meta.Labels, block.HostnameLabel)) { return errors.New("block and group labels do not match") } - if job.resolution != meta.Downsample.Resolution { + if job.resolution != meta.Resolution { return errors.New("block and group resolution do not match") } @@ -183,7 +183,7 @@ func jobWaitPeriodElapsed(ctx context.Context, job *Job, waitPeriod time.Duratio attrs, err := userBucket.Attributes(ctx, metaPath) if err != nil { - return false, meta, errors.Wrapf(err, "unable to get object attributes for %s", metaPath) + return false, meta, fmt.Errorf("unable to get object attributes for %s: %w", metaPath, err) } if attrs.LastModified.After(threshold) { diff --git a/pkg/compactor/job_sorting.go b/pkg/compactor/job_sorting.go index 738b067c64..17c3f6399c 100644 --- a/pkg/compactor/job_sorting.go +++ b/pkg/compactor/job_sorting.go @@ -47,11 +47,8 @@ func sortJobsBySmallestRangeOldestBlocksFirst(jobs []*Job) []*Job { return false } - checkLength := true + checkLength := !jobs[i].UseSplitting() || !jobs[j].UseSplitting() // Don't check length for splitting jobs. We want to the oldest split blocks to be first, no matter the length. - if jobs[i].UseSplitting() && jobs[j].UseSplitting() { - checkLength = false - } if checkLength { iLength := jobs[i].MaxTime() - jobs[i].MinTime() diff --git a/pkg/compactor/job_sorting_test.go b/pkg/compactor/job_sorting_test.go index 94e83a5475..3abdf4998a 100644 --- a/pkg/compactor/job_sorting_test.go +++ b/pkg/compactor/job_sorting_test.go @@ -8,11 +8,11 @@ package compactor import ( "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) func TestSortJobsBySmallestRangeOldestBlocksFirst(t *testing.T) { diff --git a/pkg/compactor/job_test.go b/pkg/compactor/job_test.go index 1aa37f990b..2498c9b35e 100644 --- a/pkg/compactor/job_test.go +++ b/pkg/compactor/job_test.go @@ -7,19 +7,19 @@ package compactor import ( "context" + "errors" "path" "testing" "time" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/prometheus/model/labels" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/thanos-io/objstore" - pyroscope_objstore "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" ) func TestJob_MinCompactionLevel(t *testing.T) { @@ -113,7 +113,7 @@ func TestJobWaitPeriodElapsed(t *testing.T) { require.NoError(t, job.AppendMeta(b.meta)) } - userBucket := &pyroscope_objstore.ClientMock{} + userBucket := &mockobjstore.MockBucket{} for _, b := range testData.jobBlocks { userBucket.MockAttributes(path.Join(b.meta.ULID.String(), block.MetaFilename), b.attrs, b.attrsErr) } diff --git a/pkg/compactor/label_remover_filter.go b/pkg/compactor/label_remover_filter.go index 435678c207..171b105dac 100644 --- a/pkg/compactor/label_remover_filter.go +++ b/pkg/compactor/label_remover_filter.go @@ -8,9 +8,9 @@ package compactor import ( "context" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) type LabelRemoverFilter struct { diff --git a/pkg/compactor/label_remover_filter_test.go b/pkg/compactor/label_remover_filter_test.go index 7142ac9f73..617efc912f 100644 --- a/pkg/compactor/label_remover_filter_test.go +++ b/pkg/compactor/label_remover_filter_test.go @@ -9,11 +9,11 @@ import ( "context" "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) func TestLabelRemoverFilter(t *testing.T) { diff --git a/pkg/compactor/shard_aware_deduplicate_filter.go b/pkg/compactor/shard_aware_deduplicate_filter.go index a42404bf5b..44f88dded1 100644 --- a/pkg/compactor/shard_aware_deduplicate_filter.go +++ b/pkg/compactor/shard_aware_deduplicate_filter.go @@ -9,10 +9,10 @@ import ( "context" "sort" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) const duplicateMeta = "duplicate" @@ -36,7 +36,7 @@ func (f *ShardAwareDeduplicateFilter) Filter(ctx context.Context, metas map[ulid metasByResolution := make(map[int64][]*block.Meta) for _, meta := range metas { - res := meta.Downsample.Resolution + res := meta.Resolution metasByResolution[res] = append(metasByResolution[res], meta) } diff --git a/pkg/compactor/shard_aware_deduplicate_filter_test.go b/pkg/compactor/shard_aware_deduplicate_filter_test.go index 9d7e42e3da..004145de66 100644 --- a/pkg/compactor/shard_aware_deduplicate_filter_test.go +++ b/pkg/compactor/shard_aware_deduplicate_filter_test.go @@ -10,14 +10,14 @@ import ( "fmt" "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" promtest "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" - "github.com/grafana/pyroscope/pkg/util/extprom" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/util/extprom" ) func ULID(i int) ulid.ULID { return ulid.MustNew(uint64(i), nil) } diff --git a/pkg/compactor/split_merge_compactor_test.go b/pkg/compactor/split_merge_compactor_test.go index ed8e9b530a..e89324f651 100644 --- a/pkg/compactor/split_merge_compactor_test.go +++ b/pkg/compactor/split_merge_compactor_test.go @@ -16,20 +16,20 @@ import ( "github.com/go-kit/log" "github.com/grafana/dskit/services" "github.com/grafana/dskit/test" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) func TestMultitenantCompactor_ShouldSupportSplitAndMergeCompactor(t *testing.T) { diff --git a/pkg/compactor/split_merge_grouper.go b/pkg/compactor/split_merge_grouper.go index faacb2cabe..3b483b9900 100644 --- a/pkg/compactor/split_merge_grouper.go +++ b/pkg/compactor/split_merge_grouper.go @@ -12,12 +12,11 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/prometheus/model/labels" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) type SplitAndMergeGrouper struct { @@ -64,7 +63,7 @@ func (g *SplitAndMergeGrouper) Groups(blocks map[ulid.ULID]*block.Meta) (res []* for _, job := range planCompaction(g.userID, flatBlocks, g.ranges, g.shardCount, g.splitGroupsCount) { // Sanity check: if splitting is disabled, we don't expect any job for the split stage. if g.shardCount <= 0 && job.stage == stageSplit { - return nil, errors.Errorf("unexpected split stage job because splitting is disabled: %s", job.String()) + return nil, fmt.Errorf("unexpected split stage job because splitting is disabled: %s", job.String()) } // The group key is used by the compactor as a unique identifier of the compaction job. @@ -78,7 +77,7 @@ func (g *SplitAndMergeGrouper) Groups(blocks map[ulid.ULID]*block.Meta) (res []* // All the blocks within the same group have the same downsample // resolution and external labels. - resolution := job.blocks[0].Downsample.Resolution + resolution := job.blocks[0].Resolution externalLabels := labels.FromMap(job.blocks[0].Labels) compactionJob := NewJob( @@ -94,7 +93,7 @@ func (g *SplitAndMergeGrouper) Groups(blocks map[ulid.ULID]*block.Meta) (res []* for _, m := range job.blocks { if err := compactionJob.AppendMeta(m); err != nil { - return nil, errors.Wrap(err, "add block to compaction group") + return nil, fmt.Errorf("add block to compaction group: %w", err) } } @@ -367,7 +366,7 @@ func getMaxTime(blocks []*block.Meta) int64 { // defaultGroupKeyWithoutShardID returns the default group key excluding ShardIDLabelName // when computing it. func defaultGroupKeyWithoutShardID(meta *block.Meta) string { - return defaultGroupKey(meta.Downsample.Resolution, labelsWithout(meta.Labels, sharding.CompactorShardIDLabel, block.HostnameLabel)) + return defaultGroupKey(meta.Resolution, labelsWithout(meta.Labels, sharding.CompactorShardIDLabel, block.HostnameLabel)) } // labelsWithout returns a copy of the input labels without the given labels. diff --git a/pkg/compactor/split_merge_grouper_test.go b/pkg/compactor/split_merge_grouper_test.go index ae292b243c..b86b23ab6c 100644 --- a/pkg/compactor/split_merge_grouper_test.go +++ b/pkg/compactor/split_merge_grouper_test.go @@ -9,12 +9,12 @@ import ( "testing" "time" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) func TestPlanCompaction(t *testing.T) { diff --git a/pkg/compactor/split_merge_job.go b/pkg/compactor/split_merge_job.go index 60c40e6c04..afb9890df1 100644 --- a/pkg/compactor/split_merge_job.go +++ b/pkg/compactor/split_merge_job.go @@ -13,8 +13,8 @@ import ( "github.com/prometheus/prometheus/model/labels" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) type compactionStage string diff --git a/pkg/compactor/split_merge_job_test.go b/pkg/compactor/split_merge_job_test.go index c99e1b4a16..e370537ba2 100644 --- a/pkg/compactor/split_merge_job_test.go +++ b/pkg/compactor/split_merge_job_test.go @@ -9,12 +9,12 @@ import ( "encoding/json" "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - sharding "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + sharding "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) func TestJob_conflicts(t *testing.T) { diff --git a/pkg/compactor/split_merge_planner.go b/pkg/compactor/split_merge_planner.go index c486a4f2c9..250592834d 100644 --- a/pkg/compactor/split_merge_planner.go +++ b/pkg/compactor/split_merge_planner.go @@ -9,7 +9,7 @@ import ( "context" "fmt" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) type SplitAndMergePlanner struct { diff --git a/pkg/compactor/split_merge_planner_test.go b/pkg/compactor/split_merge_planner_test.go index e52376fd43..c85a17a340 100644 --- a/pkg/compactor/split_merge_planner_test.go +++ b/pkg/compactor/split_merge_planner_test.go @@ -10,10 +10,10 @@ import ( "fmt" "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/stretchr/testify/assert" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) func TestSplitAndMergePlanner_Plan(t *testing.T) { diff --git a/pkg/compactor/syncer_metrics.go b/pkg/compactor/syncer_metrics.go index 9e860ae77e..1e1eb4f2f0 100644 --- a/pkg/compactor/syncer_metrics.go +++ b/pkg/compactor/syncer_metrics.go @@ -11,7 +11,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - util_log "github.com/grafana/pyroscope/pkg/util" + util_log "github.com/grafana/pyroscope/v2/pkg/util" ) // Copied from Mimir. diff --git a/pkg/debuginfo/store.go b/pkg/debuginfo/store.go new file mode 100644 index 0000000000..6e8f616de6 --- /dev/null +++ b/pkg/debuginfo/store.go @@ -0,0 +1,437 @@ +package debuginfo + +import ( + "bytes" + "context" + "errors" + "flag" + "fmt" + "io" + "net/http" + "path" + "regexp" + "strings" + "sync" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/gorilla/mux" + "github.com/thanos-io/objstore" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/timestamppb" + + debuginfov1alpha1 "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1" + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +type Config struct { + Enabled bool `yaml:"-" category:"advanced"` + MaxUploadSize int64 `yaml:"-" category:"advanced"` + UploadStalePeriod time.Duration `yaml:"-" category:"advanced"` + UploadTimeout time.Duration `yaml:"-" category:"advanced"` +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + f.BoolVar(&cfg.Enabled, "debug-info.enabled", true, "Enable debug info.") + f.Int64Var(&cfg.MaxUploadSize, "debug-info.max-upload-size", 1024*1024*1024, "Maximum size of a single debug info upload in bytes.") + f.DurationVar(&cfg.UploadStalePeriod, "debug-info.upload-stale-period", 5*time.Minute, "Period after which a pending upload is considered stale and can be retried.") + f.DurationVar(&cfg.UploadTimeout, "debug-info.upload-timeout", 2*time.Minute, "Timeout for a single debug info upload request. Overrides server HTTP write timeout for this handler.") +} + +type Store struct { + logger log.Logger + + bucket objstore.Bucket + + cfg Config +} + +// NewStore returns a new debug info store. +func NewStore( + logger log.Logger, + bucket objstore.Bucket, + cfg Config, +) (*Store, error) { + if cfg.Enabled && bucket == nil { + return nil, errors.New("enabled debug info requires a bucket") + } + if cfg.Enabled && cfg.UploadTimeout > cfg.UploadStalePeriod+2*time.Minute { + return nil, fmt.Errorf( + "debug info upload timeout %s exceeds stale threshold %s; increase debug-info.max-upload-duration or lower debug-info.upload-timeout", + cfg.UploadTimeout, + cfg.UploadStalePeriod+2*time.Minute, + ) + } + return &Store{ + logger: log.With(logger, "component", "debuginfo"), + bucket: bucket, + cfg: cfg, + }, nil +} + +const ( + listDebuginfoFetchConcurrency = 32 + + ReasonFirstTimeSeen = "First time we see this Build ID, therefore please upload!" + ReasonUploadStale = "A previous upload was started but not finished and is now stale, so it can be retried." + ReasonUploadInProgress = "A previous upload is still in-progress and not stale yet (only stale uploads can be retried)." + ReasonDebuginfoAlreadyExists = "Debuginfo already exists and is not marked as invalid, therefore no new upload is needed." + ReasonDisabled = "DebugInfo upload disabled" + ReasonEmptyBuildID = "Empty GNU build ID, therefore no upload is needed." +) + +func (s *Store) checkShouldInitiateUpload( + md *debuginfov1alpha1.ObjectMetadata, +) ( + *debuginfov1alpha1.ShouldInitiateUploadResponse, + error, +) { + if md == nil { + return &debuginfov1alpha1.ShouldInitiateUploadResponse{ + ShouldInitiateUpload: true, + Reason: ReasonFirstTimeSeen, + }, nil + } + + switch md.State { + case debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING: + if s.uploadIsStale(md) { + return &debuginfov1alpha1.ShouldInitiateUploadResponse{ + ShouldInitiateUpload: true, + Reason: ReasonUploadStale, + }, nil + } + + return &debuginfov1alpha1.ShouldInitiateUploadResponse{ + ShouldInitiateUpload: false, + Reason: ReasonUploadInProgress, + }, nil + case debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED: + return &debuginfov1alpha1.ShouldInitiateUploadResponse{ + ShouldInitiateUpload: false, + Reason: ReasonDebuginfoAlreadyExists, + }, nil + default: + return nil, fmt.Errorf("metadata inconsistency: unknown upload state") + } +} + +func (s *Store) ListDebuginfo(ctx context.Context, req *connect.Request[debuginfov1alpha1.ListDebuginfoRequest]) (*connect.Response[debuginfov1alpha1.ListDebuginfoResponse], error) { + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + dir := "debug-info/" + tenantID + "/" + + var buildIDs []*ValidGnuBuildID + + err = s.bucket.Iter(ctx, dir, func(name string) error { + if !strings.HasSuffix(name, objstore.DirDelim) { + return nil + } + + id, err := ValidateGnuBuildID(path.Base(name)) + if err != nil { + level.Warn(s.logger).Log("msg", "skipping debuginfo entry with invalid build ID", "name", name, "err", err) + return nil + } + buildIDs = append(buildIDs, id) + return nil + }) + + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + debugInfos := &debuginfov1alpha1.ListDebuginfoResponse{} + + var mu sync.Mutex + debugInfos.Object = make([]*debuginfov1alpha1.ObjectMetadata, 0, len(buildIDs)) + + g, gctx := errgroup.WithContext(ctx) + g.SetLimit(listDebuginfoFetchConcurrency) + + for _, buildID := range buildIDs { + g.Go(func() error { + objectMetadata, err := s.fetchMetadata(gctx, tenantID, buildID) + if err != nil { + return err + } + if objectMetadata != nil { + mu.Lock() + debugInfos.Object = append(debugInfos.Object, objectMetadata) + mu.Unlock() + } + return nil + }) + } + if err := g.Wait(); err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(debugInfos), nil +} + +func (s *Store) DeleteDebuginfo( + ctx context.Context, + req *connect.Request[debuginfov1alpha1.DeleteDebuginfoRequest], +) (*connect.Response[debuginfov1alpha1.DeleteDebuginfoResponse], error) { + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + id, err := ValidateGnuBuildID(req.Msg.GetGnuBuildId()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid gnu_build_id: %w", err)) + } + + for _, objectPath := range []string{MetadataObjectPath(tenantID, id), ObjectPath(tenantID, id)} { + err = s.bucket.Delete(ctx, objectPath) + switch { + case err == nil: + case s.bucket.IsObjNotFoundErr(err): + continue + default: + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to delete debuginfo object %q: %w", objectPath, err)) + } + } + + return connect.NewResponse(&debuginfov1alpha1.DeleteDebuginfoResponse{}), nil +} + +func (s *Store) ShouldInitiateUpload( + ctx context.Context, + req *connect.Request[debuginfov1alpha1.ShouldInitiateUploadRequest], +) (*connect.Response[debuginfov1alpha1.ShouldInitiateUploadResponse], error) { + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if !s.cfg.Enabled { + return connect.NewResponse(&debuginfov1alpha1.ShouldInitiateUploadResponse{ + ShouldInitiateUpload: false, + Reason: ReasonDisabled, + }), nil + } + + if req.Msg != nil && req.Msg.File != nil && req.Msg.File.GnuBuildId == "" { + return connect.NewResponse(&debuginfov1alpha1.ShouldInitiateUploadResponse{ + ShouldInitiateUpload: false, + Reason: ReasonEmptyBuildID, + }), nil + } + + id, err := validateInit(req.Msg) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid request: %w", err)) + } + + md, err := s.fetchMetadata(ctx, tenantID, id) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to fetch metadata: %w", err)) + } + + resp, err := s.checkShouldInitiateUpload(md) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed shouldInitiateUpload check: %w", err)) + } + + if resp.ShouldInitiateUpload { + md = &debuginfov1alpha1.ObjectMetadata{ + File: req.Msg.File, + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING, + StartedAt: timestamppb.New(time.Now()), + } + if err := s.writeMetadata(ctx, tenantID, id, md); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to write uploading metadata: %w", err)) + } + } + + return connect.NewResponse(resp), nil +} + +func (s *Store) UploadHTTPHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + if s.cfg.UploadTimeout > 0 { + now := time.Now() + rc := http.NewResponseController(w) + if err := rc.SetReadDeadline(now.Add(s.cfg.UploadTimeout)); err != nil { + _ = level.Warn(s.logger).Log("msg", "failed to set read deadline", "err", err) + } + if err := rc.SetWriteDeadline(now.Add(s.cfg.UploadTimeout + 30*time.Second)); err != nil { + _ = level.Warn(s.logger).Log("msg", "failed to set write deadline", "err", err) + } + + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, s.cfg.UploadTimeout) + defer cancel() + } + + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + gnuBuildIDStr := mux.Vars(r)["gnu_build_id"] + id, err := ValidateGnuBuildID(gnuBuildIDStr) + if err != nil { + http.Error(w, fmt.Sprintf("invalid gnu_build_id: %v", err), http.StatusBadRequest) + return + } + + l := log.With(s.logger, "gnu_build_id", id.gnuBuildID) + + md, err := s.fetchMetadata(ctx, tenantID, id) + if err != nil { + _ = level.Error(l).Log("msg", "failed to fetch metadata", "err", err) + http.Error(w, "internal error", http.StatusInternalServerError) + return + } + if md == nil || md.State != debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING { + http.Error(w, "no pending upload for this build ID", http.StatusPreconditionFailed) + return + } + + if s.cfg.MaxUploadSize > 0 { + r.Body = http.MaxBytesReader(w, r.Body, s.cfg.MaxUploadSize) + } + if err := s.bucket.Upload(ctx, ObjectPath(tenantID, id), r.Body); err != nil { + _ = level.Error(l).Log("msg", "failed to upload debuginfo", "err", err) + http.Error(w, "upload failed", http.StatusInternalServerError) + return + } + + _ = level.Debug(l).Log("msg", "debuginfo upload completed") + w.WriteHeader(http.StatusOK) + }) +} + +func (s *Store) UploadFinished( + ctx context.Context, + req *connect.Request[debuginfov1alpha1.UploadFinishedRequest], +) (*connect.Response[debuginfov1alpha1.UploadFinishedResponse], error) { + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + id, err := ValidateGnuBuildID(req.Msg.GnuBuildId) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid gnu_build_id: %w", err)) + } + + l := log.With(s.logger, "gnu_build_id", id.gnuBuildID) + + md, err := s.fetchMetadata(ctx, tenantID, id) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to fetch metadata: %w", err)) + } + if md == nil { + return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("no upload metadata found for build ID %s", req.Msg.GnuBuildId)) + } + if md.State != debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING { + return nil, connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("upload is not in uploading state")) + } + + attrs, err := s.bucket.Attributes(ctx, ObjectPath(tenantID, id)) + if err != nil { + if s.bucket.IsObjNotFoundErr(err) { + return nil, connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("no uploaded file found for build ID %s", req.Msg.GnuBuildId)) + } + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to check uploaded file: %w", err)) + } + + md.State = debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED + md.FinishedAt = timestamppb.New(time.Now()) + md.SizeBytes = attrs.Size + if err := s.writeMetadata(ctx, tenantID, id, md); err != nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to write uploaded metadata: %w", err)) + } + + _ = level.Debug(l).Log("msg", "debuginfo upload finished") + return connect.NewResponse(&debuginfov1alpha1.UploadFinishedResponse{}), nil +} + +func validateInit(init *debuginfov1alpha1.ShouldInitiateUploadRequest) (*ValidGnuBuildID, error) { + if init == nil { + return nil, fmt.Errorf("first message expected to be init") + } + if init.File == nil { + return nil, fmt.Errorf("init.File == nil") + } + switch init.File.Type { + case debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL: + return ValidateGnuBuildID(init.File.GnuBuildId) + case debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_NO_TEXT: + return ValidateGnuBuildID(init.File.GnuBuildId) + default: + return nil, fmt.Errorf("init.File.Type(%d) is not valid", init.File.Type) + } +} + +func (s *Store) uploadIsStale(upload *debuginfov1alpha1.ObjectMetadata) bool { + return upload.StartedAt.AsTime().Add(s.cfg.UploadStalePeriod + 2*time.Minute).Before(time.Now()) +} + +func (s *Store) fetchMetadata(ctx context.Context, tenantID string, id *ValidGnuBuildID) (*debuginfov1alpha1.ObjectMetadata, error) { + r, err := s.bucket.Get(ctx, MetadataObjectPath(tenantID, id)) + if err != nil { + if s.bucket.IsObjNotFoundErr(err) { + return nil, nil + } + return nil, fmt.Errorf("fetch debuginfo metadata from object storage: %w", err) + } + defer r.Close() + + content, err := io.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("read debuginfo metadata from object storage: %w", err) + } + + dbginfo := &debuginfov1alpha1.ObjectMetadata{} + if err := protojson.Unmarshal(content, dbginfo); err != nil { + return nil, fmt.Errorf("unmarshal debuginfo metadata: %w", err) + } + return dbginfo, nil +} + +func (s *Store) writeMetadata(ctx context.Context, tenantID string, id *ValidGnuBuildID, md *debuginfov1alpha1.ObjectMetadata) error { + bs, err := protojson.Marshal(md) + if err != nil { + return fmt.Errorf("marshal debuginfo metadata: %w", err) + } + + return s.bucket.Upload(ctx, MetadataObjectPath(tenantID, id), bytes.NewReader(bs)) +} + +var gnuRegex = regexp.MustCompile("^[a-fA-F0-9]{2,40}$") + +type ValidGnuBuildID struct { + gnuBuildID string +} + +func ValidateGnuBuildID(gnuBuildID string) (*ValidGnuBuildID, error) { + if !gnuRegex.MatchString(gnuBuildID) { + return nil, fmt.Errorf("invalid gnuBuildID %q", gnuBuildID) + } + + return &ValidGnuBuildID{gnuBuildID}, nil +} + +const bucketPrefix = "debug-info" + +func ObjectPath(tenantID string, id *ValidGnuBuildID) string { + return path.Join(bucketPrefix, tenantID, id.gnuBuildID, "exe") +} + +func MetadataObjectPath(tenantID string, id *ValidGnuBuildID) string { + return path.Join(bucketPrefix, tenantID, id.gnuBuildID, "metadata") +} diff --git a/pkg/debuginfo/store_test.go b/pkg/debuginfo/store_test.go new file mode 100644 index 0000000000..bb64a2b9e3 --- /dev/null +++ b/pkg/debuginfo/store_test.go @@ -0,0 +1,794 @@ +package debuginfo + +import ( + "bytes" + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/gorilla/mux" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/timestamppb" + + debuginfov1alpha1 "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1" + "github.com/grafana/pyroscope/api/gen/proto/go/debuginfo/v1alpha1/debuginfov1alpha1connect" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + "github.com/grafana/pyroscope/v2/pkg/tenant" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +func newTestStore(t *testing.T, cfg Config) (*Store, *memory.InMemBucket) { + t.Helper() + bucket := memory.NewInMemBucket() + s, err := NewStore(log.NewNopLogger(), bucket, cfg) + require.NoError(t, err) + return s, bucket +} + +func mustValidateGnuBuildID(t *testing.T, id string) *ValidGnuBuildID { + t.Helper() + v, err := ValidateGnuBuildID(id) + require.NoError(t, err) + return v +} + +func TestValidateGnuBuildID(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input string + wantErr bool + }{ + {name: "valid 2 chars (min boundary)", input: "ab", wantErr: false}, + {name: "valid 40 chars (max boundary)", input: strings.Repeat("ab", 20), wantErr: false}, + {name: "valid mixed case hex", input: "aAbBcCdDeEfF00112233", wantErr: false}, + {name: "valid lowercase hex", input: "deadbeef", wantErr: false}, + {name: "valid uppercase hex", input: "DEADBEEF", wantErr: false}, + {name: "empty string", input: "", wantErr: true}, + {name: "single char below min", input: "a", wantErr: true}, + {name: "41 chars above max", input: strings.Repeat("a", 41), wantErr: true}, + {name: "non-hex letter g", input: "abcg", wantErr: true}, + {name: "contains space", input: "ab cd", wantErr: true}, + {name: "contains dash", input: "ab-cd", wantErr: true}, + {name: "special characters", input: "ab!@#$", wantErr: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + id, err := ValidateGnuBuildID(tt.input) + if tt.wantErr { + require.Error(t, err) + assert.Nil(t, id) + } else { + require.NoError(t, err) + require.NotNil(t, id) + assert.Equal(t, tt.input, id.gnuBuildID) + } + }) + } +} + +func TestValidateInit(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + init *debuginfov1alpha1.ShouldInitiateUploadRequest + wantErr bool + errContain string + }{ + { + name: "nil init", + init: nil, + wantErr: true, + errContain: "first message expected to be init", + }, + { + name: "nil file", + init: &debuginfov1alpha1.ShouldInitiateUploadRequest{File: nil}, + wantErr: true, + errContain: "init.File == nil", + }, + { + name: "valid executable full", + init: &debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + }, + wantErr: false, + }, + { + name: "valid executable no text", + init: &debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_NO_TEXT, + }, + }, + wantErr: false, + }, + { + name: "invalid type", + init: &debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Type: debuginfov1alpha1.FileMetadata_Type(99), + }, + }, + wantErr: true, + errContain: "is not valid", + }, + { + name: "valid type invalid build id", + init: &debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "xyz", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + }, + wantErr: true, + errContain: "invalid gnuBuildID", + }, + { + name: "valid type empty build id", + init: &debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + }, + wantErr: true, + errContain: "invalid gnuBuildID", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + id, err := validateInit(tt.init) + if tt.wantErr { + require.Error(t, err) + assert.Nil(t, id) + if tt.errContain != "" { + assert.Contains(t, err.Error(), tt.errContain) + } + } else { + require.NoError(t, err) + require.NotNil(t, id) + assert.Equal(t, tt.init.File.GnuBuildId, id.gnuBuildID) + } + }) + } +} + +func TestNewStore(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + cfg Config + bucket func() *memory.InMemBucket + wantErr bool + errContain string + }{ + { + name: "enabled with bucket", + cfg: Config{Enabled: true}, + bucket: func() *memory.InMemBucket { return memory.NewInMemBucket() }, + }, + { + name: "enabled with upload timeout beyond stale threshold", + cfg: Config{ + Enabled: true, + UploadStalePeriod: time.Minute, + UploadTimeout: 4 * time.Minute, + }, + bucket: func() *memory.InMemBucket { return memory.NewInMemBucket() }, + wantErr: true, + errContain: "exceeds stale threshold", + }, + { + name: "enabled without bucket", + cfg: Config{Enabled: true}, + bucket: func() *memory.InMemBucket { return nil }, + wantErr: true, + errContain: "enabled debug info requires a bucket", + }, + { + name: "disabled without bucket", + cfg: Config{Enabled: false}, + bucket: func() *memory.InMemBucket { return nil }, + }, + { + name: "disabled with bucket", + cfg: Config{Enabled: false}, + bucket: func() *memory.InMemBucket { return memory.NewInMemBucket() }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + b := tt.bucket() + var s *Store + var err error + if b != nil { + s, err = NewStore(log.NewNopLogger(), b, tt.cfg) + } else { + s, err = NewStore(log.NewNopLogger(), nil, tt.cfg) + } + if tt.wantErr { + require.Error(t, err) + assert.Nil(t, s) + if tt.errContain != "" { + assert.Contains(t, err.Error(), tt.errContain) + } + } else { + require.NoError(t, err) + require.NotNil(t, s) + } + }) + } +} + +func TestObjectPath(t *testing.T) { + t.Parallel() + + id := mustValidateGnuBuildID(t, "aabbccdd") + assert.Equal(t, "debug-info/tenant-1/aabbccdd/exe", ObjectPath("tenant-1", id)) + assert.Equal(t, "debug-info/org-42/aabbccdd/exe", ObjectPath("org-42", id)) +} + +func TestMetadataObjectPath(t *testing.T) { + t.Parallel() + + id := mustValidateGnuBuildID(t, "aabbccdd") + assert.Equal(t, "debug-info/tenant-1/aabbccdd/metadata", MetadataObjectPath("tenant-1", id)) + assert.Equal(t, "debug-info/org-42/aabbccdd/metadata", MetadataObjectPath("org-42", id)) +} + +func TestShouldInitiateUpload(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + metadata *debuginfov1alpha1.ObjectMetadata + cfg Config + wantUpload bool + wantReason string + wantErr bool + }{ + { + name: "nil metadata first time seen", + metadata: nil, + cfg: Config{Enabled: true, UploadStalePeriod: time.Minute}, + wantUpload: true, + wantReason: ReasonFirstTimeSeen, + }, + { + name: "uploading state stale", + metadata: &debuginfov1alpha1.ObjectMetadata{ + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING, + StartedAt: timestamppb.New(time.Now().Add(-1 * time.Hour)), + }, + cfg: Config{Enabled: true, UploadStalePeriod: time.Minute}, + wantUpload: true, + wantReason: ReasonUploadStale, + }, + { + name: "uploading state not stale", + metadata: &debuginfov1alpha1.ObjectMetadata{ + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING, + StartedAt: timestamppb.New(time.Now()), + }, + cfg: Config{Enabled: true, UploadStalePeriod: time.Minute}, + wantUpload: false, + wantReason: ReasonUploadInProgress, + }, + { + name: "uploaded state", + metadata: &debuginfov1alpha1.ObjectMetadata{ + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED, + }, + cfg: Config{Enabled: true, UploadStalePeriod: time.Minute}, + wantUpload: false, + wantReason: ReasonDebuginfoAlreadyExists, + }, + { + name: "unknown state", + metadata: &debuginfov1alpha1.ObjectMetadata{ + State: debuginfov1alpha1.ObjectMetadata_State(99), + }, + cfg: Config{Enabled: true, UploadStalePeriod: time.Minute}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + s, _ := newTestStore(t, tt.cfg) + resp, err := s.checkShouldInitiateUpload(tt.metadata) + if tt.wantErr { + require.Error(t, err) + assert.Nil(t, resp) + } else { + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, tt.wantUpload, resp.ShouldInitiateUpload) + assert.Equal(t, tt.wantReason, resp.Reason) + } + }) + } +} + +func TestUploadIsStale(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + startedAt time.Time + maxUploadDuration time.Duration + wantStale bool + }{ + { + name: "stale started long ago", + startedAt: time.Now().Add(-1 * time.Hour), + maxUploadDuration: time.Minute, + wantStale: true, + }, + { + name: "not stale started now", + startedAt: time.Now(), + maxUploadDuration: time.Minute, + wantStale: false, + }, + { + name: "not stale within grace period", + startedAt: time.Now().Add(-(time.Minute + time.Minute)), + maxUploadDuration: time.Minute, + wantStale: false, + }, + { + name: "stale just past threshold", + startedAt: time.Now().Add(-(time.Minute + 2*time.Minute + time.Second)), + maxUploadDuration: time.Minute, + wantStale: true, + }, + { + name: "not stale with long max duration", + startedAt: time.Now().Add(-5 * time.Minute), + maxUploadDuration: 10 * time.Minute, + wantStale: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + s, _ := newTestStore(t, Config{Enabled: true, UploadStalePeriod: tt.maxUploadDuration}) + md := &debuginfov1alpha1.ObjectMetadata{ + StartedAt: timestamppb.New(tt.startedAt), + } + assert.Equal(t, tt.wantStale, s.uploadIsStale(md)) + }) + } +} + +func TestFetchMetadata(t *testing.T) { + t.Parallel() + + const tenantID = "test-tenant" + buildID := "aabbccdd" + + t.Run("not found returns nil", func(t *testing.T) { + t.Parallel() + s, _ := newTestStore(t, Config{Enabled: true}) + id := mustValidateGnuBuildID(t, buildID) + + md, err := s.fetchMetadata(context.Background(), tenantID, id) + require.NoError(t, err) + assert.Nil(t, md) + }) + + t.Run("valid metadata", func(t *testing.T) { + t.Parallel() + s, bucket := newTestStore(t, Config{Enabled: true}) + id := mustValidateGnuBuildID(t, buildID) + + original := &debuginfov1alpha1.ObjectMetadata{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: buildID, + Name: "test-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED, + StartedAt: timestamppb.New(time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)), + } + data, err := protojson.Marshal(original) + require.NoError(t, err) + bucket.Set(MetadataObjectPath(tenantID, id), data) + + md, err := s.fetchMetadata(context.Background(), tenantID, id) + require.NoError(t, err) + require.NotNil(t, md) + assert.Equal(t, debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED, md.State) + assert.Equal(t, buildID, md.File.GnuBuildId) + assert.Equal(t, "test-binary", md.File.Name) + }) + + t.Run("invalid json returns error", func(t *testing.T) { + t.Parallel() + s, bucket := newTestStore(t, Config{Enabled: true}) + id := mustValidateGnuBuildID(t, buildID) + + bucket.Set(MetadataObjectPath(tenantID, id), []byte("not valid json")) + + md, err := s.fetchMetadata(context.Background(), tenantID, id) + require.Error(t, err) + assert.Nil(t, md) + assert.Contains(t, err.Error(), "unmarshal") + }) +} + +func TestWriteMetadata(t *testing.T) { + t.Parallel() + + const tenantID = "test-tenant" + buildID := "aabbccdd" + + t.Run("write and verify bucket contents", func(t *testing.T) { + t.Parallel() + s, bucket := newTestStore(t, Config{Enabled: true}) + id := mustValidateGnuBuildID(t, buildID) + + md := &debuginfov1alpha1.ObjectMetadata{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: buildID, + Name: "my-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING, + StartedAt: timestamppb.New(time.Date(2025, 6, 15, 12, 0, 0, 0, time.UTC)), + } + + err := s.writeMetadata(context.Background(), tenantID, id, md) + require.NoError(t, err) + + objects := bucket.Objects() + raw, ok := objects[MetadataObjectPath(tenantID, id)] + require.True(t, ok, "metadata object should exist in bucket") + + var stored debuginfov1alpha1.ObjectMetadata + require.NoError(t, protojson.Unmarshal(raw, &stored)) + assert.Equal(t, debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING, stored.State) + assert.Equal(t, buildID, stored.File.GnuBuildId) + }) + + t.Run("write then fetch roundtrip", func(t *testing.T) { + t.Parallel() + s, _ := newTestStore(t, Config{Enabled: true}) + id := mustValidateGnuBuildID(t, buildID) + + original := &debuginfov1alpha1.ObjectMetadata{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: buildID, + Name: "roundtrip-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_NO_TEXT, + }, + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED, + StartedAt: timestamppb.New(time.Date(2025, 3, 1, 10, 0, 0, 0, time.UTC)), + FinishedAt: timestamppb.New(time.Date(2025, 3, 1, 10, 1, 0, 0, time.UTC)), + } + + err := s.writeMetadata(context.Background(), tenantID, id, original) + require.NoError(t, err) + + fetched, err := s.fetchMetadata(context.Background(), tenantID, id) + require.NoError(t, err) + require.NotNil(t, fetched) + assert.Equal(t, original.State, fetched.State) + assert.Equal(t, original.File.GnuBuildId, fetched.File.GnuBuildId) + assert.Equal(t, original.File.Name, fetched.File.Name) + assert.Equal(t, original.File.Type, fetched.File.Type) + assert.Equal(t, original.StartedAt.AsTime(), fetched.StartedAt.AsTime()) + assert.Equal(t, original.FinishedAt.AsTime(), fetched.FinishedAt.AsTime()) + }) +} + +type testServer struct { + client debuginfov1alpha1connect.DebuginfoServiceClient + srv *httptest.Server +} + +func startTestServer(t *testing.T, store *Store) testServer { + t.Helper() + router := mux.NewRouter() + debuginfov1alpha1connect.RegisterDebuginfoServiceHandler( + router, store, + connect.WithInterceptors(tenant.NewAuthInterceptor(true)), + ) + router.Handle( + "/debuginfo.v1alpha1.DebuginfoService/Upload/{gnu_build_id}", + httputil.AuthenticateUser(true).Wrap(store.UploadHTTPHandler()), + ).Methods("POST") + + srv := httptest.NewServer(router) + t.Cleanup(srv.Close) + client := debuginfov1alpha1connect.NewDebuginfoServiceClient( + srv.Client(), + srv.URL, + connect.WithInterceptors(tenant.NewAuthInterceptor(true)), + ) + return testServer{client: client, srv: srv} +} + +func (ts testServer) upload(t *testing.T, tenantID, gnuBuildID string, body []byte) *http.Response { + t.Helper() + req, err := http.NewRequest("POST", ts.srv.URL+"/debuginfo.v1alpha1.DebuginfoService/Upload/"+gnuBuildID, bytes.NewReader(body)) + require.NoError(t, err) + req.Header.Set("X-Scope-OrgID", tenantID) + resp, err := ts.srv.Client().Do(req) + require.NoError(t, err) + return resp +} + +func TestUploadE2E(t *testing.T) { + t.Parallel() + + t.Run("full upload flow", func(t *testing.T) { + t.Parallel() + store, bucket := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + + // Step 1: ShouldInitiateUpload. + resp, err := ts.client.ShouldInitiateUpload(ctx, connect.NewRequest(&debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Name: "my-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + })) + require.NoError(t, err) + assert.True(t, resp.Msg.ShouldInitiateUpload) + assert.Equal(t, ReasonFirstTimeSeen, resp.Msg.Reason) + + // Step 2: HTTP POST upload. + httpResp := ts.upload(t, "test-tenant", "aabbccdd", []byte("chunk-1-chunk-2-chunk-3")) + assert.Equal(t, http.StatusOK, httpResp.StatusCode) + httpResp.Body.Close() + + // Step 3: UploadFinished. + finResp, err := ts.client.UploadFinished(ctx, connect.NewRequest(&debuginfov1alpha1.UploadFinishedRequest{ + GnuBuildId: "aabbccdd", + })) + require.NoError(t, err) + require.NotNil(t, finResp) + + // Verify the debug info was stored in the bucket. + id := mustValidateGnuBuildID(t, "aabbccdd") + objects := bucket.Objects() + data, ok := objects[ObjectPath("test-tenant", id)] + require.True(t, ok, "debug info object should exist") + assert.Equal(t, "chunk-1-chunk-2-chunk-3", string(data)) + + // Verify metadata was written as STATE_UPLOADED. + mdRaw, ok := objects[MetadataObjectPath("test-tenant", id)] + require.True(t, ok, "metadata should exist") + var md debuginfov1alpha1.ObjectMetadata + require.NoError(t, protojson.Unmarshal(mdRaw, &md)) + assert.Equal(t, debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED, md.State) + assert.NotNil(t, md.StartedAt) + assert.NotNil(t, md.FinishedAt) + assert.Equal(t, int64(len("chunk-1-chunk-2-chunk-3")), md.SizeBytes) + }) + + t.Run("already uploaded returns should not initiate", func(t *testing.T) { + t.Parallel() + store, bucket := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + // Pre-populate metadata as already uploaded. + id := mustValidateGnuBuildID(t, "aabbccdd") + md := &debuginfov1alpha1.ObjectMetadata{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED, + StartedAt: timestamppb.New(time.Now().Add(-time.Hour)), + FinishedAt: timestamppb.New(time.Now().Add(-time.Hour + time.Minute)), + } + mdBytes, err := protojson.Marshal(md) + require.NoError(t, err) + bucket.Set(MetadataObjectPath("test-tenant", id), mdBytes) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + resp, err := ts.client.ShouldInitiateUpload(ctx, connect.NewRequest(&debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Name: "my-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + })) + require.NoError(t, err) + assert.False(t, resp.Msg.ShouldInitiateUpload) + assert.Equal(t, ReasonDebuginfoAlreadyExists, resp.Msg.Reason) + }) + + t.Run("empty build id returns should not initiate", func(t *testing.T) { + t.Parallel() + store, bucket := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + resp, err := ts.client.ShouldInitiateUpload(ctx, connect.NewRequest(&debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "", + Name: "my-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + })) + require.NoError(t, err) + assert.False(t, resp.Msg.ShouldInitiateUpload) + assert.Equal(t, ReasonEmptyBuildID, resp.Msg.Reason) + assert.Empty(t, bucket.Objects()) + }) + + t.Run("disabled service returns should not initiate", func(t *testing.T) { + t.Parallel() + store, _ := newTestStore(t, Config{Enabled: false, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + resp, err := ts.client.ShouldInitiateUpload(ctx, connect.NewRequest(&debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Name: "my-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + })) + require.NoError(t, err) + assert.False(t, resp.Msg.ShouldInitiateUpload) + assert.Equal(t, ReasonDisabled, resp.Msg.Reason) + }) + + t.Run("upload without prior ShouldInitiateUpload returns 412", func(t *testing.T) { + t.Parallel() + store, _ := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + httpResp := ts.upload(t, "test-tenant", "aabbccdd", []byte("some-data")) + assert.Equal(t, http.StatusPreconditionFailed, httpResp.StatusCode) + httpResp.Body.Close() + }) + + t.Run("UploadFinished without upload returns FailedPrecondition", func(t *testing.T) { + t.Parallel() + store, bucket := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + // Write metadata in STATE_UPLOADING but don't upload the actual file. + id := mustValidateGnuBuildID(t, "aabbccdd") + md := &debuginfov1alpha1.ObjectMetadata{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADING, + StartedAt: timestamppb.New(time.Now()), + } + mdBytes, err := protojson.Marshal(md) + require.NoError(t, err) + bucket.Set(MetadataObjectPath("test-tenant", id), mdBytes) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + _, err = ts.client.UploadFinished(ctx, connect.NewRequest(&debuginfov1alpha1.UploadFinishedRequest{ + GnuBuildId: "aabbccdd", + })) + require.Error(t, err) + assert.Equal(t, connect.CodeFailedPrecondition, connect.CodeOf(err)) + }) + + t.Run("UploadFinished for unknown build ID returns NotFound", func(t *testing.T) { + t.Parallel() + store, _ := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + _, err := ts.client.UploadFinished(ctx, connect.NewRequest(&debuginfov1alpha1.UploadFinishedRequest{ + GnuBuildId: "aabbccdd", + })) + require.Error(t, err) + assert.Equal(t, connect.CodeNotFound, connect.CodeOf(err)) + }) + + t.Run("upload exceeding max size fails", func(t *testing.T) { + t.Parallel() + store, _ := newTestStore(t, Config{Enabled: true, MaxUploadSize: 10, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + + // Step 1: ShouldInitiateUpload. + resp, err := ts.client.ShouldInitiateUpload(ctx, connect.NewRequest(&debuginfov1alpha1.ShouldInitiateUploadRequest{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Name: "my-binary", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + })) + require.NoError(t, err) + assert.True(t, resp.Msg.ShouldInitiateUpload) + + // Step 2: Upload body larger than 10 bytes. + httpResp := ts.upload(t, "test-tenant", "aabbccdd", []byte("this-is-way-too-large")) + assert.NotEqual(t, http.StatusOK, httpResp.StatusCode) + httpResp.Body.Close() + }) +} + +func TestDeleteDebuginfo(t *testing.T) { + t.Parallel() + + t.Run("deletes metadata and object", func(t *testing.T) { + t.Parallel() + store, bucket := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + + id := mustValidateGnuBuildID(t, "aabbccdd") + bucket.Set(ObjectPath("test-tenant", id), []byte("payload")) + + md := &debuginfov1alpha1.ObjectMetadata{ + File: &debuginfov1alpha1.FileMetadata{ + GnuBuildId: "aabbccdd", + Type: debuginfov1alpha1.FileMetadata_TYPE_EXECUTABLE_FULL, + }, + State: debuginfov1alpha1.ObjectMetadata_STATE_UPLOADED, + StartedAt: timestamppb.New(time.Now().Add(-time.Minute)), + FinishedAt: timestamppb.New(time.Now()), + } + mdBytes, err := protojson.Marshal(md) + require.NoError(t, err) + bucket.Set(MetadataObjectPath("test-tenant", id), mdBytes) + + _, err = ts.client.DeleteDebuginfo(ctx, connect.NewRequest(&debuginfov1alpha1.DeleteDebuginfoRequest{ + GnuBuildId: "aabbccdd", + })) + require.NoError(t, err) + + objects := bucket.Objects() + _, ok := objects[ObjectPath("test-tenant", id)] + assert.False(t, ok) + _, ok = objects[MetadataObjectPath("test-tenant", id)] + assert.False(t, ok) + }) + + t.Run("returns success when build id does not exist", func(t *testing.T) { + t.Parallel() + store, _ := newTestStore(t, Config{Enabled: true, UploadStalePeriod: time.Minute}) + ts := startTestServer(t, store) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + resp, err := ts.client.DeleteDebuginfo(ctx, connect.NewRequest(&debuginfov1alpha1.DeleteDebuginfoRequest{ + GnuBuildId: "aabbccdd", + })) + require.NoError(t, err) + require.NotNil(t, resp) + }) +} diff --git a/pkg/distributor/aggregator/aggregator_test.go b/pkg/distributor/aggregator/aggregator_test.go index 04c4615276..9fb13f9bbb 100644 --- a/pkg/distributor/aggregator/aggregator_test.go +++ b/pkg/distributor/aggregator/aggregator_test.go @@ -150,14 +150,43 @@ func Test_Aggregation_Error(t *testing.T) { assert.NoError(t, err) assert.False(t, ok) - r3, _, err := a.Aggregate(0, 2, func(i int) (int, error) { return 0, context.Canceled }) - assert.ErrorIs(t, err, context.Canceled) - r2, _, err := a.Aggregate(0, 1, fn) + r3, _, err := a.Aggregate(0, 2, func(int) (int, error) { + return 0, context.Canceled + }) assert.ErrorIs(t, err, context.Canceled) + var results []func() error + + // now a call into the same aggregation bucket is either failing or + // succeeding, depending if the aggregation has been removed in the meantime + for { + result, _, err := a.Aggregate(0, 1, fn) + if err == nil { + results = append(results, result.Wait) + break + } + + if err != nil { + assert.ErrorIs(t, err, context.Canceled) + results = append(results, result.Wait) + } + + // slow down + <-time.After(1 * time.Millisecond) + } + // Caller does not have to wait, actually. - // Testing it to make sure it is not blocking. - assert.Error(t, r2.Wait(), context.Canceled) + // Testing it backwards to make sure it is not blocking. + for idx := range results { + wait := results[len(results)-1-idx] + + if idx == 0 { + assert.NoError(t, wait(), context.Canceled) + continue + } + + assert.Error(t, wait(), context.Canceled) + } assert.Error(t, r3.Wait(), context.Canceled) assert.Equal(t, uint64(1), a.stats.errors.Load()) diff --git a/pkg/distributor/annotation/annotation.go b/pkg/distributor/annotation/annotation.go new file mode 100644 index 0000000000..b90848a145 --- /dev/null +++ b/pkg/distributor/annotation/annotation.go @@ -0,0 +1,10 @@ +package annotation + +const ( + ProfileAnnotationKeyThrottled = "pyroscope.ingest.throttled" + ProfileAnnotationKeySampled = "pyroscope.ingest.sampled" +) + +type ProfileAnnotation struct { + Body interface{} `json:"body"` +} diff --git a/pkg/distributor/annotation/sampling.go b/pkg/distributor/annotation/sampling.go new file mode 100644 index 0000000000..57425eedd9 --- /dev/null +++ b/pkg/distributor/annotation/sampling.go @@ -0,0 +1,20 @@ +package annotation + +import ( + "encoding/json" + + "github.com/grafana/pyroscope/v2/pkg/distributor/sampling" +) + +type SampledAnnotation struct { + Source *sampling.Source `json:"source"` +} + +func CreateProfileAnnotation(source *sampling.Source) ([]byte, error) { + a := &ProfileAnnotation{ + Body: SampledAnnotation{ + Source: source, + }, + } + return json.Marshal(a) +} diff --git a/pkg/distributor/annotation/throttling.go b/pkg/distributor/annotation/throttling.go new file mode 100644 index 0000000000..e960760601 --- /dev/null +++ b/pkg/distributor/annotation/throttling.go @@ -0,0 +1,48 @@ +package annotation + +import ( + "encoding/json" + "fmt" + + "github.com/grafana/pyroscope/v2/pkg/distributor/ingestlimits" +) + +type ThrottledAnnotation struct { + PeriodType string `json:"periodType"` + PeriodLimitMb int `json:"periodLimitMb"` + LimitResetTime int64 `json:"limitResetTime"` + SamplingPeriodSec int `json:"samplingPeriodSec"` + SamplingRequests int `json:"samplingRequests"` + UsageGroup string `json:"usageGroup"` +} + +func CreateTenantAnnotation(c *ingestlimits.Config) ([]byte, error) { + a := &ProfileAnnotation{ + Body: ThrottledAnnotation{ + PeriodType: c.PeriodType, + PeriodLimitMb: c.PeriodLimitMb, + LimitResetTime: c.LimitResetTime, + SamplingPeriodSec: int(c.Sampling.Period.Seconds()), + SamplingRequests: c.Sampling.NumRequests, + }, + } + return json.Marshal(a) +} + +func CreateUsageGroupAnnotation(c *ingestlimits.Config, usageGroup string) ([]byte, error) { + l, ok := c.UsageGroups[usageGroup] + if !ok { + return nil, fmt.Errorf("usageGroup %s not found", usageGroup) + } + a := &ProfileAnnotation{ + Body: ThrottledAnnotation{ + PeriodType: c.PeriodType, + PeriodLimitMb: l.PeriodLimitMb, + LimitResetTime: c.LimitResetTime, + SamplingPeriodSec: int(c.Sampling.Period.Seconds()), + SamplingRequests: c.Sampling.NumRequests, + UsageGroup: usageGroup, + }, + } + return json.Marshal(a) +} diff --git a/pkg/distributor/distributor.go b/pkg/distributor/distributor.go index 64d5592803..874936808e 100644 --- a/pkg/distributor/distributor.go +++ b/pkg/distributor/distributor.go @@ -4,53 +4,69 @@ import ( "bytes" "context" "encoding/json" + "errors" "expvar" "flag" "fmt" "hash/fnv" + "math/rand" "net/http" "sort" "sync" "time" "connectrpc.com/connect" + "go.uber.org/atomic" + "github.com/dustin/go-humanize" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/google/uuid" "github.com/grafana/dskit/kv" "github.com/grafana/dskit/limiter" + "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/ring" ring_client "github.com/grafana/dskit/ring/client" "github.com/grafana/dskit/services" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/common/model" - "go.uber.org/atomic" + "golang.org/x/sync/errgroup" - googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/clientpool" - "github.com/grafana/pyroscope/pkg/distributor/aggregator" - distributormodel "github.com/grafana/pyroscope/pkg/distributor/model" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/slices" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/usagestats" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/validation" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + "github.com/grafana/pyroscope/v2/pkg/distributor/aggregator" + "github.com/grafana/pyroscope/v2/pkg/distributor/ingestlimits" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/distributor/sampling" + "github.com/grafana/pyroscope/v2/pkg/distributor/writepath" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/pprofsplit" + "github.com/grafana/pyroscope/v2/pkg/model/relabel" + "github.com/grafana/pyroscope/v2/pkg/model/sampletype" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/usagestats" + "github.com/grafana/pyroscope/v2/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/util/spanlogger" + "github.com/grafana/pyroscope/v2/pkg/validation" ) type PushClient interface { Push(context.Context, *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) } +type SegmentWriterClient interface { + Push(context.Context, *segmentwriterv1.PushRequest) (*segmentwriterv1.PushResponse, error) + CheckReady(context.Context) error +} + const ( // distributorRingKey is the key under which we store the distributors ring in the KVStore. distributorRingKey = "distributor" @@ -68,7 +84,7 @@ type Config struct { PoolConfig clientpool.PoolConfig `yaml:"pool_config,omitempty"` // Distributors ring - DistributorRing util.CommonRingConfig `yaml:"ring" doc:"hidden"` + DistributorRing util.CommonRingConfig `yaml:"ring"` } // RegisterFlags registers distributor-related flags. @@ -96,6 +112,8 @@ type Distributor struct { ingestionRateLimiter *limiter.RateLimiter aggregator *aggregator.MultiTenantAggregator[*pprof.ProfileMerge] asyncRequests sync.WaitGroup + ingestionLimitsSampler *ingestlimits.Sampler + usageGroupEvaluator *validation.UsageGroupEvaluator subservices *services.Manager subservicesWatcher *services.FailureWatcher @@ -107,12 +125,20 @@ type Distributor struct { bytesReceivedTotalStats *usagestats.Counter profileReceivedStats *usagestats.MultiCounter profileSizeStats *usagestats.MultiStatistics + + router *writepath.Router + segmentWriter SegmentWriterClient } type Limits interface { IngestionRateBytes(tenantID string) float64 IngestionBurstSizeBytes(tenantID string) int + IngestionLimit(tenantID string) *ingestlimits.Config + IngestionBodyLimitBytes(tenantID string) int64 + DistributorSampling(tenantID string) *sampling.Config + KeepStrippedProfiles(tenantID string) bool IngestionTenantShardSize(tenantID string) int + PushMaxConcurrency(tenantID string) int MaxLabelNameLength(tenantID string) int MaxLabelValueLength(tenantID string) int MaxLabelNamesPerSeries(tenantID string) int @@ -123,14 +149,28 @@ type Limits interface { MaxProfileSymbolValueLength(tenantID string) int MaxSessionsPerSeries(tenantID string) int EnforceLabelsOrder(tenantID string) bool + DisableLabelSanitization(tenantID string) bool + IngestionRelabelingRules(tenantID string) []*relabel.Config + SampleTypeRelabelingRules(tenantID string) []*relabel.Config + DistributorUsageGroups(tenantID string) *validation.UsageGroupConfig + WritePathOverrides(tenantID string) writepath.Config validation.ProfileValidationLimits aggregator.Limits } -func New(cfg Config, ingestersRing ring.ReadRing, factory ring_client.PoolFactory, limits Limits, reg prometheus.Registerer, logger log.Logger, clientsOptions ...connect.ClientOption) (*Distributor, error) { - clientsOptions = append( +func New( + config Config, + ingesterRing ring.ReadRing, + ingesterClientFactory ring_client.PoolFactory, + limits Limits, + reg prometheus.Registerer, + logger log.Logger, + segmentWriter SegmentWriterClient, + ingesterClientsOptions ...connect.ClientOption, +) (*Distributor, error) { + ingesterClientsOptions = append( connectapi.DefaultClientOptions(), - clientsOptions..., + ingesterClientsOptions..., ) clients := promauto.With(reg).NewGauge(prometheus.GaugeOpts{ @@ -139,10 +179,11 @@ func New(cfg Config, ingestersRing ring.ReadRing, factory ring_client.PoolFactor Help: "The current number of ingester clients.", }) d := &Distributor{ - cfg: cfg, + cfg: config, logger: logger, - ingestersRing: ingestersRing, - pool: clientpool.NewIngesterPool(cfg.PoolConfig, ingestersRing, factory, clients, logger, clientsOptions...), + ingestersRing: ingesterRing, + pool: clientpool.NewIngesterPool(config.PoolConfig, ingesterRing, ingesterClientFactory, clients, logger, ingesterClientsOptions...), + segmentWriter: segmentWriter, metrics: newMetrics(reg), healthyInstancesCount: atomic.NewUint32(0), aggregator: aggregator.NewMultiTenantAggregator[*pprof.ProfileMerge](limits, reg), @@ -153,17 +194,24 @@ func New(cfg Config, ingestersRing ring.ReadRing, factory ring_client.PoolFactor profileReceivedStats: usagestats.NewMultiCounter("distributor_profiles_received", "lang"), profileSizeStats: usagestats.NewMultiStatistics("distributor_profile_sizes", "lang"), } - var err error + ingesterRoute := writepath.IngesterFunc(d.sendRequestsToIngester) + segmentWriterRoute := writepath.IngesterFunc(d.sendRequestsToSegmentWriter) + d.router = writepath.NewRouter(logger, reg, ingesterRoute, segmentWriterRoute) + + var err error subservices := []services.Service(nil) subservices = append(subservices, d.pool) - distributorsRing, distributorsLifecycler, err := newRingAndLifecycler(cfg.DistributorRing, d.healthyInstancesCount, logger, reg) + distributorsRing, distributorsLifecycler, err := newRingAndLifecycler(config.DistributorRing, d.healthyInstancesCount, logger, reg) if err != nil { return nil, err } - subservices = append(subservices, distributorsLifecycler, distributorsRing, d.aggregator) + d.ingestionLimitsSampler = ingestlimits.NewSampler(distributorsRing) + d.usageGroupEvaluator = validation.NewUsageGroupEvaluator(logger) + + subservices = append(subservices, distributorsLifecycler, distributorsRing, d.aggregator, d.ingestionLimitsSampler) d.ingestionRateLimiter = limiter.NewRateLimiter(newGlobalRateStrategy(newIngestionRateStrategy(limits), d), 10*time.Second) d.distributorsLifecycler = distributorsLifecycler @@ -171,14 +219,14 @@ func New(cfg Config, ingestersRing ring.ReadRing, factory ring_client.PoolFactor d.subservices, err = services.NewManager(subservices...) if err != nil { - return nil, errors.Wrap(err, "services manager") + return nil, fmt.Errorf("services manager: %w", err) } d.subservicesWatcher = services.NewFailureWatcher() d.subservicesWatcher.WatchManager(d.subservices) d.Service = services.NewBasicService(d.starting, d.running, d.stopping) - d.rfStats.Set(int64(ingestersRing.ReplicationFactor())) - d.metrics.replicationFactor.Set(float64(ingestersRing.ReplicationFactor())) + d.rfStats.Set(int64(ingesterRing.ReplicationFactor())) + d.metrics.replicationFactor.Set(float64(ingesterRing.ReplicationFactor())) return d, nil } @@ -191,7 +239,7 @@ func (d *Distributor) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-d.subservicesWatcher.Chan(): - return errors.Wrap(err, "distributor subservice failed") + return fmt.Errorf("distributor subservice failed: %w", err) } } @@ -200,247 +248,580 @@ func (d *Distributor) stopping(_ error) error { return services.StopManagerAndAwaitStopped(context.Background(), d.subservices) } -func (d *Distributor) Push(ctx context.Context, grpcReq *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { - req := &distributormodel.PushRequest{ - Series: make([]*distributormodel.ProfileSeries, 0, len(grpcReq.Msg.Series)), +// CheckReady reports whether the distributor is ready to serve requests. +// It verifies the destinations selected by the deployment default write path, +// so the distributor does not accept traffic before the relevant ring is +// populated during rollouts. +func (d *Distributor) CheckReady(ctx context.Context) error { + if s := d.State(); s != services.Running && s != services.Stopping { + return fmt.Errorf("distributor not ready: %v", s) } - for _, grpcSeries := range grpcReq.Msg.Series { - series := &distributormodel.ProfileSeries{ - Labels: grpcSeries.Labels, - Samples: make([]*distributormodel.ProfileSample, 0, len(grpcSeries.Samples)), + switch d.limits.WritePathOverrides("").WritePath { + case writepath.SegmentWriterPath: + return d.checkSegmentWriterReady(ctx) + case writepath.CombinedPath: + if err := d.checkIngesterRingReady(ctx); err != nil { + return fmt.Errorf("ingester write path: %w", err) + } + if err := d.checkSegmentWriterReady(ctx); err != nil { + return fmt.Errorf("segment-writer write path: %w", err) + } + return nil + default: + return d.checkIngesterRingReady(ctx) + } +} + +// checkIngesterRingReady reports whether the ingester ring has at least one +// healthy instance available for writes. +func (d *Distributor) checkIngesterRingReady(context.Context) error { + if d.ingestersRing == nil { + return errors.New("ingester ring not configured") + } + rs, err := d.ingestersRing.GetAllHealthy(ring.Write) + if err != nil { + return fmt.Errorf("ingester ring: %w", err) + } + if len(rs.Instances) == 0 { + return errors.New("ingester ring has no healthy instances") + } + return nil +} + +func (d *Distributor) checkSegmentWriterReady(ctx context.Context) error { + if d.segmentWriter == nil { + return errors.New("segment-writer client not configured") + } + return d.segmentWriter.CheckReady(ctx) +} + +func isKnownConnectError(err error) bool { + ce := new(connect.Error) + if !errors.As(err, &ce) { + return false + } + return ce.Code() != connect.CodeUnknown +} + +func isKnownValidationError(err error) bool { + return validation.ReasonOf(err) != validation.Unknown +} + +func (d *Distributor) Push(ctx context.Context, grpcReq *connect.Request[pushv1.PushRequest]) (_ *connect.Response[pushv1.PushResponse], err error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "Distributor.Push") + defer sp.Finish() + + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeUnauthenticated, err) + } + + defer func() { + if err == nil { + return + } + + // log error + sp.LogError(err) + sp.SetError() + level.Debug(util.LoggerWithContext(ctx, d.logger)).Log("msg", "failed to validate profile", "err", err) + + // wrap the errors with InvalidArgument code for profile validation errors, so they return 400 + if !isKnownConnectError(err) && isKnownValidationError(err) { + err = connect.NewError(connect.CodeInvalidArgument, err) } + }() + + maxProfileSizeBytes := int64(d.limits.MaxProfileSizeBytes(tenantID)) + maxRequestSizeBytes := d.limits.IngestionBodyLimitBytes(tenantID) + requestSizeUsed := int64(0) + requestProfileCount := 0 + + req := &distributormodel.PushRequest{ + Series: make([]*distributormodel.ProfileSeries, 0, len(grpcReq.Msg.Series)), + RawProfileType: distributormodel.RawProfileTypePPROF, + } + allErrors := multierror.New() + for _, grpcSeries := range grpcReq.Msg.Series { for _, grpcSample := range grpcSeries.Samples { - profile, err := pprof.RawFromBytes(grpcSample.RawProfile) + profile, err := pprof.RawFromBytesWithLimit(grpcSample.RawProfile, maxProfileSizeBytes) if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) + // check if decompression size has been exceeded + dsErr := new(pprof.ErrDecompressedSizeExceedsLimit) + if errors.As(err, &dsErr) { + validation.DiscardedBytes.WithLabelValues(string(validation.ProfileSizeLimit), tenantID).Add(float64(maxProfileSizeBytes)) + validation.DiscardedProfiles.WithLabelValues(string(validation.ProfileSizeLimit), tenantID).Add(float64(1)) + err = validation.NewErrorf(validation.ProfileSizeLimit, "uncompressed profile payload size exceeds limit of %s", humanize.Bytes(uint64(maxProfileSizeBytes))) + } + allErrors.Add(err) + continue + } + requestSizeUsed += int64(profile.RawSize()) + requestProfileCount += 1 + if maxRequestSizeBytes > 0 && requestSizeUsed > maxRequestSizeBytes { + validation.DiscardedBytes.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(float64(requestSizeUsed)) + validation.DiscardedProfiles.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(float64(requestProfileCount)) + return nil, validation.NewErrorf(validation.BodySizeLimit, "uncompressed batched profile payload size exceeds limit of %s", humanize.Bytes(uint64(maxRequestSizeBytes))) } - sample := &distributormodel.ProfileSample{ + series := &distributormodel.ProfileSeries{ + Labels: grpcSeries.Labels, Profile: profile, RawProfile: grpcSample.RawProfile, ID: grpcSample.ID, } - req.RawProfileSize += len(grpcSample.RawProfile) - series.Samples = append(series.Samples, sample) + req.Series = append(req.Series, series) } - req.Series = append(req.Series, series) } - resp, err := d.PushParsed(ctx, req) - if err != nil && validation.ReasonOf(err) != validation.Unknown { - if sp := opentracing.SpanFromContext(ctx); sp != nil { - ext.LogError(sp, err) - } - level.Debug(util.LoggerWithContext(ctx, d.logger)).Log("msg", "failed to validate profile", "err", err) - return resp, err + // If we have validation errors and no valid profiles, return the validation errors + // instead of calling PushBatch which would return "no profiles received" + if len(req.Series) == 0 && allErrors.Err() != nil { + return nil, allErrors.Err() } - return resp, err + if err := d.PushBatch(ctx, req); err != nil { + allErrors.Add(err) + } + err = allErrors.Err() + if err != nil { + return nil, err + } + return connect.NewResponse(new(pushv1.PushResponse)), err } func (d *Distributor) GetProfileLanguage(series *distributormodel.ProfileSeries) string { if series.Language != "" { return series.Language } - if len(series.Samples) == 0 { - return "unknown" - } lang := series.GetLanguage() if lang == "" { - lang = pprof.GetLanguage(series.Samples[0].Profile, d.logger) + lang = pprof.GetLanguage(series.Profile) } series.Language = lang return series.Language } -func (d *Distributor) PushParsed(ctx context.Context, req *distributormodel.PushRequest) (resp *connect.Response[pushv1.PushResponse], err error) { - now := model.Now() +func (d *Distributor) PushBatch(ctx context.Context, req *distributormodel.PushRequest) error { + sp, ctx := tracing.StartSpanFromContext(ctx, "Distributor.PushBatch") + defer sp.Finish() + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) if err != nil { - return nil, connect.NewError(connect.CodeUnauthenticated, err) + return connect.NewError(connect.CodeUnauthenticated, err) } + sp.SetTag("tenant_id", tenantID) - for _, series := range req.Series { - serviceName := phlaremodel.Labels(series.Labels).Get(phlaremodel.LabelNameServiceName) - if serviceName == "" { - series.Labels = append(series.Labels, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: "unspecified"}) - } - sort.Sort(phlaremodel.Labels(series.Labels)) + if len(req.Series) == 0 { + return noNewProfilesReceivedError() } - haveRawPprof := req.RawProfileType == distributormodel.RawProfileTypePPROF - d.bytesReceivedTotalStats.Inc(int64(req.RawProfileSize)) - d.bytesReceivedStats.Record(float64(req.RawProfileSize)) - if !haveRawPprof { + d.metrics.pushBatchSeries.WithLabelValues(tenantID).Observe(float64(len(req.Series))) + + d.bytesReceivedTotalStats.Inc(int64(req.ReceivedCompressedProfileSize)) + d.bytesReceivedStats.Record(float64(req.ReceivedCompressedProfileSize)) + if req.RawProfileType != distributormodel.RawProfileTypePPROF { // if a single profile contains multiple profile types/names (e.g. jfr) then there is no such thing as // compressed size per profile type as all profile types are compressed once together. So we can not count // compressed bytes per profile type. Instead we count compressed bytes per profile. profName := req.RawProfileType // use "jfr" as profile name - d.metrics.receivedCompressedBytes.WithLabelValues(string(profName), tenantID).Observe(float64(req.RawProfileSize)) + d.metrics.receivedCompressedBytes.WithLabelValues(string(profName), tenantID).Observe(float64(req.ReceivedCompressedProfileSize)) + level.Debug(d.logger).Log("msg", "non-pprof request body received", + "profile_type", profName, + "compressed_size", req.ReceivedCompressedProfileSize, + "decompressed_size", req.ReceivedDecompressedProfileSize, + ) } - if err := d.rateLimit(tenantID, req); err != nil { - return nil, err + if req.ParseDuration > 0 { + d.metrics.parseDuration.WithLabelValues(string(req.RawProfileType), tenantID).Observe(req.ParseDuration.Seconds()) } - for _, series := range req.Series { - profName := phlaremodel.Labels(series.Labels).Get(ProfileName) - profLanguage := d.GetProfileLanguage(series) - for _, raw := range series.Samples { - usagestats.NewCounter(fmt.Sprintf("distributor_profile_type_%s_received", profName)).Inc(1) - d.profileReceivedStats.Inc(1, profLanguage) - if haveRawPprof { - d.metrics.receivedCompressedBytes.WithLabelValues(profName, tenantID).Observe(float64(len(raw.RawProfile))) - } - p := raw.Profile - decompressedSize := p.SizeVT() - d.metrics.receivedDecompressedBytes.WithLabelValues(profName, tenantID).Observe(float64(decompressedSize)) - d.metrics.receivedSamples.WithLabelValues(profName, tenantID).Observe(float64(len(p.Sample))) - d.profileSizeStats.Record(float64(decompressedSize), profLanguage) - - if err = validation.ValidateProfile(d.limits, tenantID, p.Profile, decompressedSize, series.Labels, now); err != nil { - _ = level.Debug(d.logger).Log("msg", "invalid profile", "err", err) - validation.DiscardedProfiles.WithLabelValues(string(validation.ReasonOf(err)), tenantID).Add(float64(req.TotalProfiles)) - validation.DiscardedBytes.WithLabelValues(string(validation.ReasonOf(err)), tenantID).Add(float64(req.TotalBytesUncompressed)) - return nil, connect.NewError(connect.CodeInvalidArgument, err) + res := multierror.New() + errorsMutex := new(sync.Mutex) + // Bound the per-series fan-out. We use errgroup purely as a limited + // WaitGroup: the closures always return nil (errors are funneled into the + // multierror below), so a plain Group never cancels siblings and every + // series is attempted. The per-tenant limit <= 0 leaves it unbounded (legacy + // behavior); SetLimit(0) would block every Go call, so we skip SetLimit + // entirely rather than pass a non-positive limit. + g := new(errgroup.Group) + if limit := d.limits.PushMaxConcurrency(tenantID); limit > 0 { + g.SetLimit(limit) + } + for index, s := range req.Series { + g.Go(func() error { + itErr := util.RecoverPanic(func() error { + return d.pushSeries(ctx, s, req.RawProfileType, tenantID, req.ParseDuration) + })() + + if itErr != nil { + itErr = fmt.Errorf("push series with index %d and id %s failed: %w", index, s.ID, itErr) } + errorsMutex.Lock() + res.Add(itErr) + errorsMutex.Unlock() + return nil + }) + } + _ = g.Wait() + return res.Err() +} - symbolsSize, samplesSize := profileSizeBytes(p.Profile) - d.metrics.receivedSamplesBytes.WithLabelValues(profName, tenantID).Observe(float64(samplesSize)) - d.metrics.receivedSymbolsBytes.WithLabelValues(profName, tenantID).Observe(float64(symbolsSize)) - } +type lazyUsageGroups func() []validation.UsageGroupMatchName + +func (l lazyUsageGroups) String() string { + groups := l() + result := make([]string, len(groups)) + for pos := range groups { + result[pos] = groups[pos].String() } + return fmt.Sprintf("%v", result) +} - if req.TotalProfiles == 0 { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("no profiles received")) +type pushLog struct { + fields []any + lvl func(log.Logger) log.Logger + msg string +} + +func newPushLog(capacity int) *pushLog { + fields := make([]any, 2, (capacity+1)*2) + fields[0] = "msg" + return &pushLog{ + fields: fields, } +} - // Normalisation is quite an expensive operation, - // therefore it should be done after the rate limit check. - for _, series := range req.Series { - for _, sample := range series.Samples { - if series.Language == "go" { - sample.Profile.Profile = pprof.FixGoProfile(sample.Profile.Profile) - } - sample.Profile.Normalize() +func (p *pushLog) addFields(fields ...any) { + p.fields = append(p.fields, fields...) +} + +func (p *pushLog) log(logger log.Logger, err error) { + // determine log level + if p.lvl == nil { + if err != nil { + p.lvl = level.Warn + } else { + p.lvl = level.Debug } } - if err := injectMappingVersions(req.Series); err != nil { - _ = level.Warn(d.logger).Log("msg", "failed to inject mapping versions", "err", err) + if err != nil { + p.addFields("err", err) } - // If aggregation is configured for the tenant, we try to determine - // whether the profile is eligible for aggregation based on the series - // profile rate, and handle it asynchronously, if this is the case. - // - // NOTE(kolesnikovae): aggregated profiles are handled on best-effort - // basis (at-most-once delivery semantics): any error occurred will - // not be returned to the client, and it must not retry sending. - // - // Aggregation is only meant to be used for cases, when clients do not - // form individual series (e.g., server-less workload), and typically - // are ephemeral in its nature, and therefore retrying is not possible - // or desirable, as it prolongs life-time duration of the clients. - if len(req.Series) == 1 && len(req.Series[0].Samples) == 1 { - // Actually all series profiles can be merged before aggregation. - // However, it's not expected that a series has more than one profile. - series := req.Series[0] - profile := series.Samples[0].Profile.Profile - // maybeAggregate _may_ return a non-nil handler of the aggregated value, - // if the profile is aggregated indeed, and this is the first invocation. - aggregateHandler, ok, err := d.maybeAggregate(tenantID, series.Labels, profile) + // update message + if p.msg == "" { if err != nil { - return nil, err + p.msg = "profile rejected" + } else { + p.msg = "profile accepted" } - if ok { - if aggregateHandler != nil { - d.sendAggregatedProfile(ctx, req, tenantID, aggregateHandler) - } - return connect.NewResponse(&pushv1.PushResponse{}), nil + } + p.fields[1] = p.msg + p.lvl(logger).Log(p.fields...) +} + +func (d *Distributor) pushSeries(ctx context.Context, req *distributormodel.ProfileSeries, origin distributormodel.RawProfileType, tenantID string, parseDuration time.Duration) (err error) { + if req.Profile == nil { + return noNewProfilesReceivedError() + } + now := model.Now() + + logger := spanlogger.FromContext(ctx, log.With(d.logger, "tenant", tenantID)) + finalLog := newPushLog(13) + defer func() { + finalLog.log(logger, err) + }() + + req.TenantID = tenantID + serviceName := phlaremodel.Labels(req.Labels).Get(phlaremodel.LabelNameServiceName) + if serviceName == "" { + req.Labels = append(req.Labels, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: phlaremodel.AttrServiceNameFallback}) + } else { + finalLog.addFields("service_name", serviceName) + } + sort.Sort(phlaremodel.Labels(req.Labels)) + + if req.ID != "" { + finalLog.addFields("profile_id", req.ID) + } + + req.TotalProfiles = 1 + decompressedSize := req.Profile.SizeVT() + req.TotalBytesUncompressed = labelsSize(req.Labels) + int64(decompressedSize) + d.metrics.observeProfileSize(tenantID, StageReceived, req.TotalBytesUncompressed) + + if err := d.checkIngestLimit(req); err != nil { + finalLog.msg = "rejecting profile due to global ingest limit" + finalLog.lvl = level.Debug + validation.DiscardedProfiles.WithLabelValues(string(validation.IngestLimitReached), tenantID).Add(float64(req.TotalProfiles)) + validation.DiscardedBytes.WithLabelValues(string(validation.IngestLimitReached), tenantID).Add(float64(req.TotalBytesUncompressed)) + return err + } + + if err := d.rateLimit(tenantID, req); err != nil { + return err + } + + usageGroups := d.limits.DistributorUsageGroups(tenantID) + + profName := phlaremodel.Labels(req.Labels).Get(ProfileName) + finalLog.addFields("profile_type", profName) + + groups := d.usageGroupEvaluator.GetMatch(tenantID, usageGroups, req.Labels) + finalLog.addFields("matched_usage_groups", lazyUsageGroups(groups.Names)) + if err := d.checkUsageGroupsIngestLimit(req, groups.Names()); err != nil { + finalLog.msg = "rejecting profile due to usage group ingest limit" + finalLog.lvl = level.Debug + validation.DiscardedProfiles.WithLabelValues(string(validation.IngestLimitReached), tenantID).Add(float64(req.TotalProfiles)) + validation.DiscardedBytes.WithLabelValues(string(validation.IngestLimitReached), tenantID).Add(float64(req.TotalBytesUncompressed)) + groups.CountDiscardedBytes(string(validation.IngestLimitReached), req.TotalBytesUncompressed) + return err + } + + willSample, samplingSource := d.shouldSample(tenantID, groups.Names()) + if !willSample { + finalLog.addFields( + "usage_group", samplingSource.UsageGroup, + "probability", samplingSource.Probability, + ) + finalLog.msg = "skipping profile due to sampling" + validation.DiscardedProfiles.WithLabelValues(string(validation.SkippedBySamplingRules), tenantID).Add(float64(req.TotalProfiles)) + + if !d.limits.KeepStrippedProfiles(tenantID) { + validation.DiscardedBytes.WithLabelValues(string(validation.SkippedBySamplingRules), tenantID).Add(float64(req.TotalBytesUncompressed)) + groups.CountDiscardedBytes(string(validation.SkippedBySamplingRules), req.TotalBytesUncompressed) + return nil } + finalLog.msg = "stripping profile stacktraces, keeping samples and labels" + + // Language detection reads the string table, which is about to be + // stripped; the result is cached in the request. + d.GetProfileLanguage(req) + stripProfileToTotals(req.Profile.Profile) + req.Labels = phlaremodel.Labels(req.Labels).InsertSorted(phlaremodel.LabelNameSampled, "true") + + // The stripped part of the profile is discarded, and from here on + // the remainder is accounted for like a regular profile. + keptSize := req.Profile.SizeVT() + validation.DiscardedBytes.WithLabelValues(string(validation.SkippedBySamplingRules), tenantID).Add(float64(decompressedSize - keptSize)) + groups.CountDiscardedBytes(string(validation.SkippedBySamplingRules), int64(decompressedSize-keptSize)) + decompressedSize = keptSize + req.TotalBytesUncompressed = labelsSize(req.Labels) + int64(decompressedSize) } + if samplingSource != nil { + if err := req.MarkSampledRequest(samplingSource); err != nil { + return err + } + } + + profLanguage := d.GetProfileLanguage(req) + if profLanguage != "" { + finalLog.addFields("detected_language", profLanguage) + } + + usagestats.NewCounter(fmt.Sprintf("distributor_profile_type_%s_received", profName)).Inc(1) + d.profileReceivedStats.Inc(1, profLanguage) + if origin == distributormodel.RawProfileTypePPROF { + d.metrics.receivedCompressedBytes.WithLabelValues(profName, tenantID).Observe(float64(len(req.RawProfile))) + } + p := req.Profile + profTime := model.TimeFromUnixNano(p.TimeNanos).Time() + finalLog.addFields( + "profile_time", profTime, + "ingestion_delay", now.Time().Sub(profTime), + "decompressed_size", decompressedSize, + "sample_count", len(p.Sample), + "parse_duration", parseDuration, + ) + d.metrics.observeProfileSize(tenantID, StageSampled, int64(decompressedSize)) //todo use req.TotalBytesUncompressed to include labels siz + d.metrics.receivedDecompressedBytes.WithLabelValues(profName, tenantID).Observe(float64(decompressedSize)) // deprecated TODO remove + d.metrics.receivedSamples.WithLabelValues(profName, tenantID).Observe(float64(len(p.Sample))) + d.profileSizeStats.Record(float64(decompressedSize), profLanguage) + groups.CountReceivedBytes(profName, int64(decompressedSize)) + + validated, err := validation.ValidateProfile(d.limits, tenantID, p, decompressedSize, req.Labels, now) + if err != nil { + reason := string(validation.ReasonOf(err)) + finalLog.addFields("reason", reason) + validation.DiscardedProfiles.WithLabelValues(reason, tenantID).Add(float64(req.TotalProfiles)) + validation.DiscardedBytes.WithLabelValues(reason, tenantID).Add(float64(req.TotalBytesUncompressed)) + groups.CountDiscardedBytes(reason, req.TotalBytesUncompressed) + return connect.NewError(connect.CodeInvalidArgument, err) + } + + symbolsSize, samplesSize := profileSizeBytes(p.Profile, int64(decompressedSize)) + d.metrics.receivedSamplesBytes.WithLabelValues(profName, tenantID).Observe(float64(samplesSize)) + d.metrics.receivedSymbolsBytes.WithLabelValues(profName, tenantID).Observe(float64(symbolsSize)) - return d.sendRequests(ctx, req, tenantID) + // Normalisation is quite an expensive operation, + // therefore it should be done after the rate limit check. + if req.Language == "go" { + sp, _ := tracing.StartSpanFromContext(ctx, "pprof.FixGoProfile") + req.Profile.Profile = pprof.FixGoProfile(req.Profile.Profile) + sp.Finish() + } + { + sp, _ := tracing.StartSpanFromContext(ctx, "sampletype.Relabel") + sampleTypeRules := d.limits.SampleTypeRelabelingRules(req.TenantID) + sampletype.Relabel(validated, sampleTypeRules, req.Labels) + sp.Finish() + } + { + sp, _ := tracing.StartSpanFromContext(ctx, "Profile.Normalize") + req.Profile.Normalize() + sp.Finish() + finalLog.addFields("normalization_stats", req.Profile.Stats()) + d.metrics.observeProfileSize(tenantID, StageNormalized, calculateRequestSize(req)) + } + + if len(req.Profile.Sample) == 0 { + // TODO(kolesnikovae): + // Normalization may cause all profiles and series to be empty. + // We should report it as an error and account for discarded data. + // The check should be done after ValidateProfile and normalization. + return nil + } + + if err := injectMappingVersions(req); err != nil { + _ = level.Warn(logger).Log("msg", "failed to inject mapping versions", "err", err) + } + + // Reduce cardinality of the session_id label. + maxSessionsPerSeries := d.limits.MaxSessionsPerSeries(req.TenantID) + req.Labels = d.limitMaxSessionsPerSeries(maxSessionsPerSeries, req.Labels) + + aggregated, err := d.aggregate(ctx, req) + if err != nil { + return err + } + if aggregated { + return nil + } + + // Write path router directs the request to the ingester or segment + // writer, or both, depending on the configuration. + // The router uses sendRequestsToSegmentWriter and sendRequestsToIngester + // functions to send the request to the appropriate service; these are + // called independently, and may be called concurrently: the request is + // cloned in this case – the callee may modify the request safely. + config := d.limits.WritePathOverrides(req.TenantID) + return d.router.Send(ctx, req, config) +} + +func noNewProfilesReceivedError() *connect.Error { + return connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("no profiles received")) } -func (d *Distributor) sendAggregatedProfile(ctx context.Context, req *distributormodel.PushRequest, tenantID string, handler func() (*pprof.ProfileMerge, error)) { +// If aggregation is configured for the tenant, we try to determine +// whether the profile is eligible for aggregation based on the series +// profile rate, and handle it asynchronously, if this is the case. +// +// NOTE(kolesnikovae): aggregated profiles are handled on best-effort +// basis (at-most-once delivery semantics): any error occurred will +// not be returned to the client, and it must not retry sending. +// +// Aggregation is only meant to be used for cases, when clients do not +// form individual series (e.g., server-less workload), and typically +// are ephemeral in its nature, and therefore retrying is not possible +// or desirable, as it prolongs life-time duration of the clients. +func (d *Distributor) aggregate(ctx context.Context, req *distributormodel.ProfileSeries) (bool, error) { + a, ok := d.aggregator.AggregatorForTenant(req.TenantID) + if !ok { + // Aggregation is not configured for the tenant. + return false, nil + } + + series := req + + // First, we drop __session_id__ label to increase probability + // of aggregation, which is handled done per series. + profile := series.Profile.Profile + labels := phlaremodel.Labels(series.Labels) + if _, hasSessionID := labels.GetLabel(phlaremodel.LabelNameSessionID); hasSessionID { + labels = labels.Clone().Delete(phlaremodel.LabelNameSessionID) + } + r, ok, err := a.Aggregate(labels.Hash(), profile.TimeNanos, mergeProfile(profile)) + if err != nil { + return false, connect.NewError(connect.CodeInvalidArgument, err) + } + if !ok { + // Aggregation is not needed. + return false, nil + } + handler := r.Handler() + if handler == nil { + // Aggregation is handled in another goroutine. + return true, nil + } + + // Aggregation is needed, and we own the result handler. + // Note that the labels include the source series labels with + // session ID: this is required to ensure fair load distribution. d.asyncRequests.Add(1) - // We must not reuse the request in goroutine. - labels := phlaremodel.Labels(req.Series[0].Labels).Clone() + labels = phlaremodel.Labels(req.Labels).Clone() + annotations := req.Annotations go func() { defer d.asyncRequests.Done() - localCtx, cancel := context.WithTimeout(context.Background(), d.cfg.PushTimeout) - defer cancel() - localCtx = tenant.InjectTenantID(localCtx, tenantID) - if sp := opentracing.SpanFromContext(ctx); sp != nil { - localCtx = opentracing.ContextWithSpan(localCtx, sp) - } - // Obtain the aggregated profile. - p, err := handler() - if err != nil { - _ = level.Error(d.logger).Log("msg", "failed to aggregate profiles", "tenant", tenantID, "err", err) - return - } - req := &distributormodel.PushRequest{ - Series: []*distributormodel.ProfileSeries{{ - Labels: labels, - Samples: []*distributormodel.ProfileSample{{Profile: pprof.RawFromProto(p.Profile())}}, - }}, - } - if _, err = d.sendRequests(localCtx, req, tenantID); err != nil { - _ = level.Error(d.logger).Log("msg", "failed to ingest aggregated profile", "tenant", tenantID, "err", err) + sendErr := util.RecoverPanic(func() error { + localCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), d.cfg.PushTimeout) + defer cancel() + localCtx = tenant.InjectTenantID(localCtx, req.TenantID) + // Obtain the aggregated profile. + p, handleErr := handler() + if handleErr != nil { + return handleErr + } + aggregated := &distributormodel.ProfileSeries{ + TenantID: req.TenantID, + Labels: labels, + Profile: pprof.RawFromProto(p.Profile()), + Annotations: annotations, + } + config := d.limits.WritePathOverrides(req.TenantID) + return d.router.Send(localCtx, aggregated, config) + })() + if sendErr != nil { + _ = level.Error(d.logger).Log("msg", "failed to handle aggregation", "tenant", req.TenantID, "err", err) } }() + + return true, nil } -func (d *Distributor) sendRequests(ctx context.Context, req *distributormodel.PushRequest, tenantID string) (resp *connect.Response[pushv1.PushResponse], err error) { - // Reduce cardinality of session_id label. - maxSessionsPerSeries := d.limits.MaxSessionsPerSeries(tenantID) - for _, series := range req.Series { - series.Labels = d.limitMaxSessionsPerSeries(maxSessionsPerSeries, series.Labels) - } +// visitSampleSeriesForIngester creates a profile per unique label set in pprof labels. +func visitSampleSeriesForIngester(profile *profilev1.Profile, labels []*typesv1.LabelPair, rules []*relabel.Config, visitor *sampleSeriesVisitor) error { + return pprofsplit.VisitSampleSeries(profile, labels, rules, visitor) +} - // Next we split profiles by labels. - profileSeries := extractSampleSeries(req) - // Filter our series and profiles without samples. - for _, series := range profileSeries { - series.Samples = slices.RemoveInPlace(series.Samples, func(sample *distributormodel.ProfileSample, _ int) bool { - return len(sample.Profile.Sample) == 0 - }) +func (d *Distributor) sendRequestsToIngester(ctx context.Context, req *distributormodel.ProfileSeries) (resp *connect.Response[pushv1.PushResponse], err error) { + sampleSeries, err := d.visitSampleSeries(req, visitSampleSeriesForIngester) + if err != nil { + return nil, err } - profileSeries = slices.RemoveInPlace(profileSeries, func(series *distributormodel.ProfileSeries, i int) bool { - return len(series.Samples) == 0 - }) - if len(profileSeries) == 0 { + if len(sampleSeries) == 0 { return connect.NewResponse(&pushv1.PushResponse{}), nil } - // Validate the labels again and generate tokens for shuffle sharding. - keys := make([]uint32, len(profileSeries)) - enforceLabelsOrder := d.limits.EnforceLabelsOrder(tenantID) - for i, series := range profileSeries { - if enforceLabelsOrder { - series.Labels = phlaremodel.Labels(series.Labels).InsertSorted(phlaremodel.LabelNameOrder, phlaremodel.LabelOrderEnforced) + enforceLabelOrder := d.limits.EnforceLabelsOrder(req.TenantID) + keys := make([]uint32, len(sampleSeries)) + for i, s := range sampleSeries { + if enforceLabelOrder { + s.Labels = phlaremodel.Labels(s.Labels).InsertSorted(phlaremodel.LabelNameOrder, phlaremodel.LabelOrderEnforced) } - if err = validation.ValidateLabels(d.limits, tenantID, series.Labels); err != nil { - validation.DiscardedProfiles.WithLabelValues(string(validation.ReasonOf(err)), tenantID).Add(float64(req.TotalProfiles)) - validation.DiscardedBytes.WithLabelValues(string(validation.ReasonOf(err)), tenantID).Add(float64(req.TotalBytesUncompressed)) - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - keys[i] = TokenFor(tenantID, phlaremodel.LabelPairsString(series.Labels)) + keys[i] = TokenFor(req.TenantID, phlaremodel.LabelPairsString(s.Labels)) } - profiles := make([]*profileTracker, 0, len(profileSeries)) - for _, series := range profileSeries { - for _, raw := range series.Samples { - p := raw.Profile - // zip the data back into the buffer - bw := bytes.NewBuffer(raw.RawProfile[:0]) - if _, err = p.WriteTo(bw); err != nil { - return nil, err - } - raw.ID = uuid.NewString() - raw.RawProfile = bw.Bytes() + profiles := make([]*profileTracker, 0, len(sampleSeries)) + for _, series := range sampleSeries { + p := series.Profile + // zip the data back into the buffer + bw := bytes.NewBuffer(series.RawProfile[:0]) + if _, err = p.WriteTo(bw); err != nil { + return nil, err } + series.ID = uuid.NewString() + series.RawProfile = bw.Bytes() profiles = append(profiles, &profileTracker{profile: series}) } @@ -451,7 +832,7 @@ func (d *Distributor) sendRequests(ctx context.Context, req *distributormodel.Pu ingesterDescs := map[string]ring.InstanceDesc{} for i, key := range keys { // Get a subring if tenant has shuffle shard size configured. - subRing := d.ingestersRing.ShuffleShard(tenantID, d.limits.IngestionTenantShardSize(tenantID)) + subRing := d.ingestersRing.ShuffleShard(req.TenantID, d.limits.IngestionTenantShardSize(req.TenantID)) replicationSet, err := subRing.Get(key, ring.Write, descs[:0], nil, nil) if err != nil { @@ -472,12 +853,9 @@ func (d *Distributor) sendRequests(ctx context.Context, req *distributormodel.Pu for ingester, samples := range samplesByIngester { go func(ingester ring.InstanceDesc, samples []*profileTracker) { // Use a background context to make sure all ingesters get samples even if we return early - localCtx, cancel := context.WithTimeout(context.Background(), d.cfg.PushTimeout) + localCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), d.cfg.PushTimeout) defer cancel() - localCtx = tenant.InjectTenantID(localCtx, tenantID) - if sp := opentracing.SpanFromContext(ctx); sp != nil { - localCtx = opentracing.ContextWithSpan(localCtx, sp) - } + localCtx = tenant.InjectTenantID(localCtx, req.TenantID) d.sendProfiles(localCtx, ingester, samples, &tracker) }(ingesterDescs[ingester], samples) } @@ -491,15 +869,176 @@ func (d *Distributor) sendRequests(ctx context.Context, req *distributormodel.Pu } } -// profileSizeBytes returns the size of symbols and samples in bytes. -func profileSizeBytes(p *googlev1.Profile) (symbols, samples int64) { - fullSize := p.SizeVT() +// visitSampleSeriesForSegmentWriter creates a profile per service. +// Labels that are shared by all pprof samples are used as series labels. +// Unique sample labels (not present in series labels) are preserved: +// pprof split takes place in segment-writers. +func visitSampleSeriesForSegmentWriter(profile *profilev1.Profile, labels []*typesv1.LabelPair, rules []*relabel.Config, visitor *sampleSeriesVisitor) error { + return pprofsplit.VisitSampleSeriesBy(profile, labels, rules, visitor, phlaremodel.LabelNameServiceName) +} + +func (d *Distributor) sendRequestsToSegmentWriter(ctx context.Context, req *distributormodel.ProfileSeries) (*connect.Response[pushv1.PushResponse], error) { + // NOTE(kolesnikovae): if we return early, e.g., due to a validation error, + // or if there are no series, the write path router has already seen the + // request, and could have already accounted for the size, latency, etc. + serviceSeries, err := d.visitSampleSeries(req, visitSampleSeriesForSegmentWriter) + if err != nil { + return nil, err + } + if len(serviceSeries) == 0 { + return connect.NewResponse(&pushv1.PushResponse{}), nil + } + + // TODO(kolesnikovae): Add profiles per request histogram. + // In most cases, we only have a single profile. We should avoid + // batching multiple profiles into a single request: overhead of handling + // multiple profiles in a single request is substantial: we need to + // allocate memory for all profiles at once, and wait for multiple requests + // routed to different shards to complete is generally a bad idea because + // it's hard to reason about latencies, retries, and error handling. + config := d.limits.WritePathOverrides(req.TenantID) + requests := make([]*segmentwriterv1.PushRequest, 0, len(serviceSeries)*2) + for _, s := range serviceSeries { + buf, err := pprof.Marshal(s.Profile.Profile, config.Compression == writepath.CompressionGzip) + if err != nil { + panic(fmt.Sprintf("failed to marshal profile: %v", err)) + } + // Ideally, the ID should identify the whole request, and be + // deterministic (e.g, based on the request hash). In practice, + // the API allows batches, which makes it difficult to handle. + profileID := uuid.New() + requests = append(requests, &segmentwriterv1.PushRequest{ + TenantId: req.TenantID, + Labels: s.Labels, + Profile: buf, + ProfileId: profileID[:], + Annotations: s.Annotations, + }) + } + + if len(requests) == 1 { + if _, err := d.segmentWriter.Push(ctx, requests[0]); err != nil { + return nil, err + } + return connect.NewResponse(&pushv1.PushResponse{}), nil + } + + // Fallback. We should minimize probability of this branch. + g, ctx := errgroup.WithContext(ctx) + for _, r := range requests { + r := r + g.Go(func() error { + _, pushErr := d.segmentWriter.Push(ctx, r) + return pushErr + }) + } + if err := g.Wait(); err != nil { + return nil, err + } + + return connect.NewResponse(&pushv1.PushResponse{}), nil +} + +// stripProfileToTotals reduces the profile to one sample per distinct +// sample label set, each holding the summed values of its group: +// stacktraces and symbols are dropped, only the totals are kept. +// Sample labels survive so that span- and trace-attributed totals +// remain distinguishable. +func stripProfileToTotals(p *profilev1.Profile) { + kept := p.Sample[:0] + for _, s := range p.Sample { + // Mirror Normalize: non-string labels are unsupported, and samples + // it would drop (value length mismatch, negative values) must not + // contribute to the totals. + if len(s.Value) != len(p.SampleType) || hasNegativeValue(s) { + continue + } + s.Label = dropNonStringLabels(s.Label) + sort.Sort(pprof.LabelsByKeyValue(s.Label)) + kept = append(kept, s) + } + p.Sample = kept + sort.Sort(pprof.SamplesByLabels(p.Sample)) + groups := pprof.GroupSamplesByLabels(p) + totals := make([]*profilev1.Sample, len(groups)) + for i, g := range groups { + total := &profilev1.Sample{Value: make([]int64, len(p.SampleType)), Label: g.Labels} + for _, s := range g.Samples { + for j, v := range s.Value { + total.Value[j] += v + } + } + totals[i] = total + } + p.Sample = totals + + p.Location = nil + p.Function = nil + p.Mapping = nil + + oldStrings := p.StringTable + newStrings := []string{""} + remap := map[int64]int64{0: 0} + intern := func(old int64) int64 { + if n, ok := remap[old]; ok { + return n + } + n := int64(len(newStrings)) + newStrings = append(newStrings, oldStrings[old]) + remap[old] = n + return n + } + p.DropFrames = intern(p.DropFrames) + p.KeepFrames = intern(p.KeepFrames) + p.DefaultSampleType = intern(p.DefaultSampleType) + for _, vt := range p.SampleType { + vt.Type = intern(vt.Type) + vt.Unit = intern(vt.Unit) + } + if p.PeriodType != nil { + p.PeriodType.Type = intern(p.PeriodType.Type) + p.PeriodType.Unit = intern(p.PeriodType.Unit) + } + for i, c := range p.Comment { + p.Comment[i] = intern(c) + } + for _, s := range p.Sample { + for _, l := range s.Label { + l.Key = intern(l.Key) + l.Str = intern(l.Str) + l.NumUnit = intern(l.NumUnit) + } + } + p.StringTable = newStrings +} + +func dropNonStringLabels(labels []*profilev1.Label) []*profilev1.Label { + kept := labels[:0] + for _, l := range labels { + if l.Str != 0 { + kept = append(kept, l) + } + } + return kept +} + +func hasNegativeValue(s *profilev1.Sample) bool { + for _, v := range s.Value { + if v < 0 { + return true + } + } + return false +} + +// profileSizeBytes returns the size of symbols and samples in bytes from a given fullSize. +func profileSizeBytes(p *profilev1.Profile, fullSize int64) (symbols, samples int64) { // remove samples samplesSlice := p.Sample p.Sample = nil symbols = int64(p.SizeVT()) - samples = int64(fullSize) - symbols + samples = fullSize - symbols // count labels in samples samplesLabels := 0 @@ -516,30 +1055,12 @@ func profileSizeBytes(p *googlev1.Profile) (symbols, samples int64) { return } -func (d *Distributor) maybeAggregate(tenantID string, labels phlaremodel.Labels, profile *googlev1.Profile) (func() (*pprof.ProfileMerge, error), bool, error) { - a, ok := d.aggregator.AggregatorForTenant(tenantID) - if !ok { - return nil, false, nil - } - if _, hasSessionID := labels.GetLabel(phlaremodel.LabelNameSessionID); hasSessionID { - labels = labels.Clone().Delete(phlaremodel.LabelNameSessionID) - } - r, ok, err := a.Aggregate(labels.Hash(), profile.TimeNanos, mergeProfile(profile)) - if err != nil { - return nil, false, err - } - if !ok { - return nil, false, nil - } - return r.Handler(), true, nil -} - -func mergeProfile(profile *googlev1.Profile) aggregator.AggregateFn[*pprof.ProfileMerge] { +func mergeProfile(profile *profilev1.Profile) aggregator.AggregateFn[*pprof.ProfileMerge] { return func(m *pprof.ProfileMerge) (*pprof.ProfileMerge, error) { if m == nil { m = new(pprof.ProfileMerge) } - if err := m.Merge(profile); err != nil { + if err := m.Merge(profile, true); err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } return m, nil @@ -588,15 +1109,14 @@ func (d *Distributor) sendProfilesErr(ctx context.Context, ingester ring.Instanc for _, p := range profileTrackers { series := &pushv1.RawProfileSeries{ - Labels: p.profile.Labels, - Samples: make([]*pushv1.RawSample, 0, len(p.profile.Samples)), - } - for _, sample := range p.profile.Samples { - series.Samples = append(series.Samples, &pushv1.RawSample{ - RawProfile: sample.RawProfile, - ID: sample.ID, - }) + Labels: p.profile.Labels, + Samples: []*pushv1.RawSample{{ + RawProfile: p.profile.RawProfile, + ID: p.profile.ID, + }}, + Annotations: p.profile.Annotations, } + req.Msg.Series = append(req.Msg.Series, series) } @@ -620,7 +1140,7 @@ func (d *Distributor) ServeHTTP(w http.ResponseWriter, req *http.Request) {

Distributor is not running with global limits enabled

` - util.WriteHTMLResponse(w, ringNotEnabledPage) + httputil.WriteHTMLResponse(w, ringNotEnabledPage) } } @@ -633,45 +1153,6 @@ func (d *Distributor) HealthyInstancesCount() int { return int(d.healthyInstancesCount.Load()) } -func extractSampleSeries(req *distributormodel.PushRequest) []*distributormodel.ProfileSeries { - profileSeries := make([]*distributormodel.ProfileSeries, 0, len(req.Series)) - for _, series := range req.Series { - s := &distributormodel.ProfileSeries{ - Labels: series.Labels, - Samples: make([]*distributormodel.ProfileSample, 0, len(series.Samples)), - } - for _, raw := range series.Samples { - pprof.RenameLabel(raw.Profile.Profile, pprof.ProfileIDLabelName, pprof.SpanIDLabelName) - groups := pprof.GroupSamplesWithoutLabels(raw.Profile.Profile, pprof.SpanIDLabelName) - if len(groups) == 0 || (len(groups) == 1 && len(groups[0].Labels) == 0) { - // No sample labels in the profile. - // We do not modify the request. - s.Samples = append(s.Samples, raw) - continue - } - e := pprof.NewSampleExporter(raw.Profile.Profile) - for _, group := range groups { - // exportSamples creates a new profile with the samples provided. - // The samples are obtained via GroupSamples call, which means - // the underlying capacity is referenced by the source profile. - // Therefore, the slice has to be copied and samples zeroed to - // avoid ownership issues. - profile := exportSamples(e, group.Samples) - // Note that group.Labels reference strings from the source profile. - labels := mergeSeriesAndSampleLabels(raw.Profile.Profile, series.Labels, group.Labels) - profileSeries = append(profileSeries, &distributormodel.ProfileSeries{ - Labels: labels, - Samples: []*distributormodel.ProfileSample{{Profile: profile}}, - }) - } - } - if len(s.Samples) > 0 { - profileSeries = append(profileSeries, s) - } - } - return profileSeries -} - func (d *Distributor) limitMaxSessionsPerSeries(maxSessionsPerSeries int, labels phlaremodel.Labels) phlaremodel.Labels { if maxSessionsPerSeries == 0 { return labels.Delete(phlaremodel.LabelNameSessionID) @@ -689,19 +1170,7 @@ func (d *Distributor) limitMaxSessionsPerSeries(maxSessionsPerSeries int, labels return labels } -func (d *Distributor) rateLimit(tenantID string, req *distributormodel.PushRequest) error { - for _, series := range req.Series { - // include the labels in the size calculation - for _, lbs := range series.Labels { - req.TotalBytesUncompressed += int64(len(lbs.Name)) - req.TotalBytesUncompressed += int64(len(lbs.Value)) - } - for _, raw := range series.Samples { - req.TotalProfiles += 1 - req.TotalBytesUncompressed += int64(raw.Profile.SizeVT()) - } - } - // rate limit the request +func (d *Distributor) rateLimit(tenantID string, req *distributormodel.ProfileSeries) error { if !d.ingestionRateLimiter.AllowN(time.Now(), tenantID, int(req.TotalBytesUncompressed)) { validation.DiscardedProfiles.WithLabelValues(string(validation.RateLimited), tenantID).Add(float64(req.TotalProfiles)) validation.DiscardedBytes.WithLabelValues(string(validation.RateLimited), tenantID).Add(float64(req.TotalBytesUncompressed)) @@ -712,27 +1181,108 @@ func (d *Distributor) rateLimit(tenantID string, req *distributormodel.PushReque return nil } -// mergeSeriesAndSampleLabels merges sample labels with -// series labels. Series labels take precedence. -func mergeSeriesAndSampleLabels(p *googlev1.Profile, sl []*typesv1.LabelPair, pl []*googlev1.Label) []*typesv1.LabelPair { - m := phlaremodel.Labels(sl).Clone() - for _, l := range pl { - m = append(m, &typesv1.LabelPair{ - Name: p.StringTable[l.Key], - Value: p.StringTable[l.Str], - }) +func calculateRequestSize(req *distributormodel.ProfileSeries) int64 { + // include the labels in the size calculation + return labelsSize(req.Labels) + int64(req.Profile.SizeVT()) +} + +func labelsSize(lbs []*typesv1.LabelPair) int64 { + bs := int64(0) + for _, l := range lbs { + bs += int64(len(l.Name)) + bs += int64(len(l.Value)) } - sort.Stable(m) - return m.Unique() + return bs } -func exportSamples(e *pprof.SampleExporter, samples []*googlev1.Sample) *pprof.Profile { - samplesCopy := make([]*googlev1.Sample, len(samples)) - copy(samplesCopy, samples) - slices.Clear(samples) - n := pprof.NewProfile() - e.ExportSamples(n.Profile, samplesCopy) - return n +func (d *Distributor) checkIngestLimit(req *distributormodel.ProfileSeries) error { + l := d.limits.IngestionLimit(req.TenantID) + if l == nil { + return nil + } + + if l.LimitReached { + // we want to allow a very small portion of the traffic after reaching the limit + if d.ingestionLimitsSampler.AllowRequest(req.TenantID, l.Sampling) { + if err := req.MarkThrottledTenant(l); err != nil { + return err + } + return nil + } + limitResetTime := time.Unix(l.LimitResetTime, 0).UTC().Format(time.RFC3339) + return connect.NewError(connect.CodeResourceExhausted, + fmt.Errorf("limit of %s/%s reached, next reset at %s", humanize.IBytes(uint64(l.PeriodLimitMb*1024*1024)), l.PeriodType, limitResetTime)) + } + + return nil +} + +func (d *Distributor) checkUsageGroupsIngestLimit(req *distributormodel.ProfileSeries, groupsInRequest []validation.UsageGroupMatchName) error { + l := d.limits.IngestionLimit(req.TenantID) + if l == nil || len(l.UsageGroups) == 0 { + return nil + } + + for _, group := range groupsInRequest { + limit, ok := l.UsageGroups[group.ResolvedName] + if !ok { + limit, ok = l.UsageGroups[group.ConfiguredName] + } + if !ok || !limit.LimitReached { + continue + } + if d.ingestionLimitsSampler.AllowRequest(req.TenantID, l.Sampling) { + if err := req.MarkThrottledUsageGroup(l, group.ResolvedName); err != nil { + return err + } + return nil + } + limitResetTime := time.Unix(l.LimitResetTime, 0).UTC().Format(time.RFC3339) + return connect.NewError(connect.CodeResourceExhausted, + fmt.Errorf("limit of %s/%s reached for usage group %s, next reset at %s", humanize.IBytes(uint64(limit.PeriodLimitMb*1024*1024)), l.PeriodType, group, limitResetTime)) + } + + return nil +} + +// shouldSample returns true if the profile should be injected and optionally the usage group that was responsible for the decision. +func (d *Distributor) shouldSample(tenantID string, groupsInRequest []validation.UsageGroupMatchName) (bool, *sampling.Source) { + l := d.limits.DistributorSampling(tenantID) + if l == nil { + return true, nil + } + + samplingProbability := 1.0 + var match *validation.UsageGroupMatchName + for _, group := range groupsInRequest { + probabilityCfg, found := l.UsageGroups[group.ResolvedName] + if !found { + probabilityCfg, found = l.UsageGroups[group.ConfiguredName] + } + if !found { + continue + } + // a less specific group loses to a more specific one + if match != nil && match.IsMoreSpecificThan(&group) { + continue + } + // lower probability wins; when tied, the more specific group wins + if probabilityCfg.Probability <= samplingProbability { + samplingProbability = probabilityCfg.Probability + match = &group + } + } + + if match == nil { + return true, nil + } + + source := &sampling.Source{ + UsageGroup: match.ResolvedName, + Probability: samplingProbability, + } + + return rand.Float64() <= samplingProbability, source } type profileTracker struct { @@ -763,12 +1313,12 @@ func newRingAndLifecycler(cfg util.CommonRingConfig, instanceCount *atomic.Uint3 reg = prometheus.WrapRegistererWithPrefix("pyroscope_", reg) kvStore, err := kv.NewClient(cfg.KVStore, ring.GetCodec(), kv.RegistererWithKVName(reg, "distributor-lifecycler"), logger) if err != nil { - return nil, nil, errors.Wrap(err, "failed to initialize distributors' KV store") + return nil, nil, fmt.Errorf("failed to initialize distributors' KV store: %w", err) } lifecyclerCfg, err := toBasicLifecyclerConfig(cfg, logger) if err != nil { - return nil, nil, errors.Wrap(err, "failed to build distributors' lifecycler config") + return nil, nil, fmt.Errorf("failed to build distributors' lifecycler config: %w", err) } var delegate ring.BasicLifecyclerDelegate @@ -779,35 +1329,118 @@ func newRingAndLifecycler(cfg util.CommonRingConfig, instanceCount *atomic.Uint3 distributorsLifecycler, err := ring.NewBasicLifecycler(lifecyclerCfg, "distributor", distributorRingKey, kvStore, delegate, logger, reg) if err != nil { - return nil, nil, errors.Wrap(err, "failed to initialize distributors' lifecycler") + return nil, nil, fmt.Errorf("failed to initialize distributors' lifecycler: %w", err) } distributorsRing, err := ring.New(cfg.ToRingConfig(), "distributor", distributorRingKey, logger, reg) if err != nil { - return nil, nil, errors.Wrap(err, "failed to initialize distributors' ring client") + return nil, nil, fmt.Errorf("failed to initialize distributors' ring client: %w", err) } return distributorsRing, distributorsLifecycler, nil } // injectMappingVersions extract from the labels the mapping version and inject it into the profile's main mapping. (mapping[0]) -func injectMappingVersions(series []*distributormodel.ProfileSeries) error { - for _, s := range series { - version, ok := phlaremodel.ServiceVersionFromLabels(s.Labels) - if !ok { - continue - } - for _, sample := range s.Samples { - for _, m := range sample.Profile.Mapping { - version.BuildID = sample.Profile.StringTable[m.BuildId] - versionString, err := json.Marshal(version) - if err != nil { - return err - } - sample.Profile.StringTable = append(sample.Profile.StringTable, string(versionString)) - m.BuildId = int64(len(sample.Profile.StringTable) - 1) - } +func injectMappingVersions(s *distributormodel.ProfileSeries) error { + version, ok := phlaremodel.ServiceVersionFromLabels(s.Labels) + if !ok { + return nil + } + for _, m := range s.Profile.Mapping { + version.BuildID = s.Profile.StringTable[m.BuildId] + versionString, err := json.Marshal(version) + if err != nil { + return err } + s.Profile.StringTable = append(s.Profile.StringTable, string(versionString)) + m.BuildId = int64(len(s.Profile.StringTable) - 1) } return nil } + +type visitFunc func(*profilev1.Profile, []*typesv1.LabelPair, []*relabel.Config, *sampleSeriesVisitor) error + +func (d *Distributor) visitSampleSeries(s *distributormodel.ProfileSeries, visit visitFunc) ([]*distributormodel.ProfileSeries, error) { + relabelingRules := d.limits.IngestionRelabelingRules(s.TenantID) + usageConfig := d.limits.DistributorUsageGroups(s.TenantID) + var result []*distributormodel.ProfileSeries + usageGroups := d.usageGroupEvaluator.GetMatch(s.TenantID, usageConfig, s.Labels) + visitor := &sampleSeriesVisitor{ + tenantID: s.TenantID, + limits: d.limits, + profile: s.Profile, + logger: d.logger, + } + if err := visit(s.Profile.Profile, s.Labels, relabelingRules, visitor); err != nil { + validation.DiscardedProfiles.WithLabelValues(string(validation.ReasonOf(err)), s.TenantID).Add(float64(s.TotalProfiles)) + validation.DiscardedBytes.WithLabelValues(string(validation.ReasonOf(err)), s.TenantID).Add(float64(s.TotalBytesUncompressed)) + usageGroups.CountDiscardedBytes(string(validation.ReasonOf(err)), s.TotalBytesUncompressed) + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + for _, ss := range visitor.series { + ss.Annotations = s.Annotations + ss.Language = s.Language + result = append(result, ss) + } + s.DiscardedProfilesRelabeling += int64(visitor.discardedProfiles) + s.DiscardedBytesRelabeling += int64(visitor.discardedBytes) + if visitor.discardedBytes > 0 { + usageGroups.CountDiscardedBytes(string(validation.DroppedByRelabelRules), int64(visitor.discardedBytes)) + } + + if s.DiscardedBytesRelabeling > 0 { + validation.DiscardedBytes.WithLabelValues(string(validation.DroppedByRelabelRules), s.TenantID).Add(float64(s.DiscardedBytesRelabeling)) + } + if s.DiscardedProfilesRelabeling > 0 { + validation.DiscardedProfiles.WithLabelValues(string(validation.DroppedByRelabelRules), s.TenantID).Add(float64(s.DiscardedProfilesRelabeling)) + } + // todo should we do normalization after relabeling? + return result, nil +} + +type sampleSeriesVisitor struct { + tenantID string + limits Limits + profile *pprof.Profile + exp *pprof.SampleExporter + series []*distributormodel.ProfileSeries + logger log.Logger + + discardedBytes int + discardedProfiles int +} + +func (v *sampleSeriesVisitor) ValidateLabels(labels phlaremodel.Labels) (phlaremodel.Labels, error) { + return validation.ValidateLabels(v.limits, v.tenantID, labels, v.logger) +} + +func (v *sampleSeriesVisitor) VisitProfile(labels phlaremodel.Labels) { + v.series = append(v.series, &distributormodel.ProfileSeries{ + Profile: v.profile, + Labels: labels, + }) +} + +func (v *sampleSeriesVisitor) VisitSampleSeries(labels phlaremodel.Labels, samples []*profilev1.Sample) { + if v.exp == nil { + v.exp = pprof.NewSampleExporter(v.profile.Profile) + } + v.series = append(v.series, &distributormodel.ProfileSeries{ + Profile: exportSamples(v.exp, samples), + Labels: labels, + }) +} + +func (v *sampleSeriesVisitor) Discarded(profiles, bytes int) { + v.discardedProfiles += profiles + v.discardedBytes += bytes +} + +func exportSamples(e *pprof.SampleExporter, samples []*profilev1.Sample) *pprof.Profile { + samplesCopy := make([]*profilev1.Sample, len(samples)) + copy(samplesCopy, samples) + clear(samples) + n := pprof.NewProfile() + e.ExportSamples(n.Profile, samplesCopy) + return n +} diff --git a/pkg/distributor/distributor_api_test.go b/pkg/distributor/distributor_api_test.go new file mode 100644 index 0000000000..e1ea1faf4f --- /dev/null +++ b/pkg/distributor/distributor_api_test.go @@ -0,0 +1,753 @@ +package distributor_test + +import ( + "bytes" + "compress/gzip" + "context" + "fmt" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/gorilla/mux" + "github.com/grafana/dskit/server" + grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/require" + otlpcolv1 "go.opentelemetry.io/proto/otlp/collector/profiles/v1development" + otlpv1 "go.opentelemetry.io/proto/otlp/profiles/v1development" + "google.golang.org/protobuf/encoding/protojson" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/api" + "github.com/grafana/pyroscope/v2/pkg/distributor" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +type apiTest struct { + *api.API + HTTPMux *mux.Router + GRPCGWMux *grpcgw.ServeMux +} + +func newAPITest(t testing.TB, cfg api.Config, logger log.Logger) *apiTest { + a := &apiTest{ + HTTPMux: mux.NewRouter(), + GRPCGWMux: grpcgw.NewServeMux(), + } + + cfg.HTTPAuthMiddleware = httputil.AuthenticateUser(true) + cfg.GrpcAuthMiddleware = connect.WithInterceptors(tenant.NewAuthInterceptor(true)) + + serv := &server.Server{ + HTTP: a.HTTPMux, + } + + var err error + a.API, err = api.New( + cfg, + serv, + a.GRPCGWMux, + logger, + ) + if err != nil { + t.Error("failed to create api: ", err) + } + return a +} + +func defaultLimits() *validation.Overrides { + return validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionBodyLimitMB = 1 // 1 MB + l.IngestionRateMB = 10000 // 100 MB + tenantLimits["1mb-body-limit"] = l + + }) +} + +// generateProfileOfSize creates a valid pprof profile with approximately the target size in bytes. +// It creates a minimal profile and pads the string table to reach the desired size. +func generateProfileOfSize(targetSize int, compress bool) ([]byte, error) { + // Create a minimal valid profile + p := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100}}, + }, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + }, + Mapping: []*profilev1.Mapping{ + {Id: 1, Filename: 3}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 4, SystemName: 4, Filename: 3}, + }, + StringTable: []string{ + "", + "cpu", "nanoseconds", + "main.go", + "foo", + }, + PeriodType: &profilev1.ValueType{Type: 1, Unit: 2}, + TimeNanos: 1, + Period: 1, + } + + // Marshal to see the base size + baseData, err := pprof.Marshal(p, false) + if err != nil { + return nil, err + } + + // If we need more size, pad the string table + if len(baseData) < targetSize { + // Add a large padding string to reach target size + // Each character in the string table adds roughly 1 byte + paddingSize := targetSize - len(baseData) + p.StringTable[4] = "f" + strings.Repeat("o", paddingSize) + } + + return pprof.Marshal(p, compress) +} + +func pprofWithSize(t testing.TB, target int) []byte { + t.Helper() + uncompressed, err := generateProfileOfSize(target, false) + require.NoError(t, err) + require.Equal(t, target, len(uncompressed)) + return uncompressed +} + +func reqIngestGzPprof(data []byte) func(context.Context) *http.Request { + requestF := reqIngestPprof(data) + return func(ctx context.Context) *http.Request { + req := requestF(ctx) + req.Header.Set("Content-Encoding", "gzip") + return req + } +} + +func reqIngestPprof(data []byte) func(context.Context) *http.Request { + return func(ctx context.Context) *http.Request { + req, err := http.NewRequestWithContext( + ctx, "POST", "/ingest?name=testapp&format=pprof", + bytes.NewReader(data), + ) + if err != nil { + panic(err) + } + + return req + } +} + +func reqPushPprofJson(profiles ...[][]byte) func(context.Context) *http.Request { + req := &pushv1.PushRequest{} + + for pIdx, p := range profiles { + s := &pushv1.RawProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "fake_cpu"}, + {Name: "service_name", Value: "killer"}, + }, + } + for sIdx, sample := range p { + s.Samples = append(s.Samples, &pushv1.RawSample{ + ID: fmt.Sprintf("%d-%d", pIdx, sIdx), + RawProfile: sample, + }) + } + req.Series = append(req.Series, s) + } + + jsonData, err := protojson.Marshal(req) + if err != nil { + panic(err) + } + + return func(ctx context.Context) *http.Request { + req, err := http.NewRequestWithContext( + ctx, "POST", "/push.v1.PusherService/Push", + bytes.NewReader(jsonData), + ) + if err != nil { + panic(err) + } + req.Header.Set("Content-Type", "application/json") + return req + } +} + +func gzipper(t testing.TB, fn func(testing.TB, int) []byte, targetSize int) []byte { + t.Helper() + data := fn(t, targetSize) + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + _, err := io.Copy(zw, bytes.NewReader(data)) + require.NoError(t, err) + require.NoError(t, zw.Close()) // Must close to flush and write gzip trailer + return buf.Bytes() +} + +// otlpbuilder helps build OTLP profiles with controlled sizes +type otlpbuilder struct { + profile otlpv1.Profile + dictionary otlpv1.ProfilesDictionary + stringmap map[string]int32 +} + +func (o *otlpbuilder) addstr(s string) int32 { + if o.stringmap == nil { + o.stringmap = make(map[string]int32) + } + if idx, ok := o.stringmap[s]; ok { + return idx + } + idx := int32(len(o.stringmap)) + o.stringmap[s] = idx + o.dictionary.StringTable = append(o.dictionary.StringTable, s) + return idx +} + +func otlpJSONWithSize(t testing.TB, targetSize int) []byte { + t.Helper() + + b := new(otlpbuilder) + + fileNameIdx := b.addstr("foo") + + // Create minimal valid OTLP profile structure with cpu:nanoseconds type (maps to process_cpu) + b.dictionary.MappingTable = []*otlpv1.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x2000, + FilenameStrindex: fileNameIdx, + }} + b.dictionary.LocationTable = []*otlpv1.Location{{ + MappingIndex: 0, + Address: 0x1100, + }} + b.dictionary.StackTable = []*otlpv1.Stack{{ + LocationIndices: []int32{0}, + }} + // Use cpu:nanoseconds which will be recognized as a valid profile type + cpuIdx := b.addstr("cpu") + nanosIdx := b.addstr("nanoseconds") + b.profile.SampleType = &otlpv1.ValueType{ + TypeStrindex: cpuIdx, + UnitStrindex: nanosIdx, + } + b.profile.PeriodType = &otlpv1.ValueType{ + TypeStrindex: cpuIdx, + UnitStrindex: nanosIdx, + } + b.profile.Period = 10000000 + b.profile.Samples = []*otlpv1.Sample{{ + StackIndex: 0, + Values: []int64{100}, + }} + b.profile.TimeUnixNano = 1234567890 + + // Calculate current size + req := &otlpcolv1.ExportProfilesServiceRequest{ + ResourceProfiles: []*otlpv1.ResourceProfiles{{ + ScopeProfiles: []*otlpv1.ScopeProfiles{{ + Profiles: []*otlpv1.Profile{&b.profile}, + }}, + }}, + Dictionary: &b.dictionary, + } + jsonData, err := protojson.Marshal(req) + require.NoError(t, err) + baseSize := len(jsonData) + + // Pad string table to reach target size + if baseSize < targetSize { + paddingSize := targetSize - baseSize - 1 + b.dictionary.StringTable[fileNameIdx] += "f" + strings.Repeat("o", paddingSize) + } + + jsonData, err = protojson.Marshal(req) + require.NoError(t, err) + if len(jsonData) != targetSize { + panic(fmt.Sprintf("json size=%d is not matching targetSize=%d", len(jsonData), targetSize)) + } + + return jsonData +} + +func reqOTLPJson(data []byte) func(context.Context) *http.Request { + return func(ctx context.Context) *http.Request { + httpReq, err := http.NewRequestWithContext( + ctx, "POST", "/v1development/profiles", + bytes.NewReader(data), + ) + if err != nil { + panic(err) + } + httpReq.Header.Set("Content-Type", "application/json") + return httpReq + } +} + +func reqOTLPJsonGzip(data []byte) func(context.Context) *http.Request { + fn := reqOTLPJson(data) + return func(ctx context.Context) *http.Request { + req := fn(ctx) + req.Header.Set("Content-Encoding", "gzip") + return req + } +} + +const ( + underOneMb = (1024 - 10) * 1024 + oneMb = 1024 * 1024 + overOneMb = (1024 + 10) * 1024 +) + +func TestDistributorAPIBodySizeLimit(t *testing.T) { + const metricReason = validation.BodySizeLimit + + logger := log.NewNopLogger() + + limits := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionBodyLimitMB = 1 // 1 MB + l.IngestionRateMB = 10000 // set this high enough to not interfere + tenantLimits["1mb-body-limit"] = l + + }) + + d, err := distributor.NewTestDistributor(t, + logger, + defaultLimits(), + ) + require.NoError(t, err) + + a := newAPITest(t, api.Config{}, logger) + a.RegisterDistributor(d, limits, server.Config{}) + + // generate sample payloads + var ( + pprofUnderOneMb = pprofWithSize(t, underOneMb) + pprofOneMb = pprofWithSize(t, oneMb) + pprofOverOneMb = pprofWithSize(t, overOneMb) + pprofGzipUnderOneMb = gzipper(t, pprofWithSize, underOneMb) + pprofGzipOneMb = gzipper(t, pprofWithSize, oneMb) + pprofGzipOverOneMb = gzipper(t, pprofWithSize, overOneMb) + otlpJSONUnderOneMb = otlpJSONWithSize(t, underOneMb) + otlpJSONnOneMb = otlpJSONWithSize(t, oneMb) + otlpJSONOverOneMb = otlpJSONWithSize(t, overOneMb) + otlpJSONGzipUnderOneMb = gzipper(t, otlpJSONWithSize, underOneMb) + otlpJSONGzipOneMb = gzipper(t, otlpJSONWithSize, oneMb) + otlpJSONGzipOverOneMb = gzipper(t, otlpJSONWithSize, overOneMb) + ) + + testCases := []struct { + name string + skipMsg string + request func(context.Context) *http.Request + tenantID string + expectedStatus int + expectedErrorMsg string + expectDiscardedBytes float64 + expectDiscardedProfiles float64 + }{ + { + name: "ingest/uncompressed/within-limit", + request: reqIngestPprof(pprofUnderOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "ingest/uncompressed/exact-limit", + request: reqIngestPprof(pprofOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "ingest/uncompressed/exceeds-limit", + request: reqIngestPprof(pprofOverOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 413, + expectedErrorMsg: "request body too large", + expectDiscardedBytes: float64(oneMb), + expectDiscardedProfiles: 1, + }, + { + name: "ingest/gzip/within-limit", + request: reqIngestGzPprof(pprofGzipUnderOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "ingest/gzip/exact-limit", + request: reqIngestGzPprof(pprofGzipOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + // Note: /ingest endpoint does not support Content-Encoding: gzip header. + // Gzip decompression is handled at the pprof parsing layer, not HTTP layer. + { + name: "push-json/uncompressed/within-limit", + request: reqPushPprofJson([][]byte{pprofUnderOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "push-json/uncompressed/exact-limit", + request: reqPushPprofJson([][]byte{pprofOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "push-json/uncompressed/exceeds-limit", + request: reqPushPprofJson([][]byte{pprofOverOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 400, // grpc status codes used by connect have no mapping to 413 + expectedErrorMsg: "uncompressed batched profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(overOneMb), + expectDiscardedProfiles: 1, + }, + { + name: "push-json/uncompressed/exceeds-limit-with-two-profiles", + request: reqPushPprofJson([][]byte{pprofUnderOneMb}, [][]byte{pprofUnderOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 400, // grpc status codes used by connect have no mapping to 413 + expectedErrorMsg: "uncompressed batched profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(underOneMb * 2), + expectDiscardedProfiles: 2, + }, + { + name: "push-json/gzip/within-limit", + request: reqPushPprofJson([][]byte{pprofGzipUnderOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "push-json/gzip/exact-limit", + request: reqPushPprofJson([][]byte{pprofGzipOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "push-json/gzip/exceeds-limit", + request: reqPushPprofJson([][]byte{pprofGzipOverOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 400, // grpc status codes used by connect have no mapping to 413 + expectedErrorMsg: "uncompressed batched profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(overOneMb), + expectDiscardedProfiles: 1, + }, + { + name: "push-json/gzip/exceeds-limit-with-two-profiles", + request: reqPushPprofJson([][]byte{pprofGzipUnderOneMb}, [][]byte{pprofGzipUnderOneMb}), + tenantID: "1mb-body-limit", + expectedStatus: 400, // grpc status codes used by connect have no mapping to 413 + expectedErrorMsg: "uncompressed batched profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(underOneMb * 2), + expectDiscardedProfiles: 2, + }, + { + name: "otlp-json/uncompressed/within-limit", + request: reqOTLPJson(otlpJSONUnderOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "otlp-json/uncompressed/exact-limit", + request: reqOTLPJson(otlpJSONnOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "otlp-json/uncompressed/exceeds-limit", + request: reqOTLPJson(otlpJSONOverOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 413, + expectedErrorMsg: "profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(oneMb), + expectDiscardedProfiles: 1, + }, + { + name: "otlp-json/gzip/within-limit", + request: reqOTLPJsonGzip(otlpJSONGzipUnderOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "otlp-json/gzip/exact-limit", + request: reqOTLPJsonGzip(otlpJSONGzipOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 200, + }, + { + name: "otlp-json/gzip/exceeds-limit", + request: reqOTLPJsonGzip(otlpJSONGzipOverOneMb), + tenantID: "1mb-body-limit", + expectedStatus: 413, + expectedErrorMsg: "uncompressed profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(oneMb), + expectDiscardedProfiles: 1, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.skipMsg != "" { + t.Skip(tc.skipMsg) + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + req := tc.request(ctx) + req.Header.Set("X-Scope-OrgID", tc.tenantID) + + // Capture metrics before request if we expect them to change + var metricsBefore map[prometheus.Collector]float64 + if tc.expectDiscardedBytes > 0 || tc.expectDiscardedProfiles > 0 { + metricsBefore = map[prometheus.Collector]float64{ + validation.DiscardedBytes.WithLabelValues(string(metricReason), tc.tenantID): testutil.ToFloat64(validation.DiscardedBytes.WithLabelValues(string(metricReason), tc.tenantID)), + validation.DiscardedProfiles.WithLabelValues(string(metricReason), tc.tenantID): testutil.ToFloat64(validation.DiscardedProfiles.WithLabelValues(string(metricReason), tc.tenantID)), + } + } + + // Execute request through the mux + res := httptest.NewRecorder() + a.HTTPMux.ServeHTTP(res, req) + + // Assertions + require.Equal(t, tc.expectedStatus, res.Code, + "expected status %d, got %d. Response body: %s", + tc.expectedStatus, res.Code, res.Body.String()) + + if tc.expectedErrorMsg != "" { + require.Contains(t, res.Body.String(), tc.expectedErrorMsg) + } + + // Check metrics if expected + if tc.expectDiscardedBytes > 0 || tc.expectDiscardedProfiles > 0 { + bytesMetric := validation.DiscardedBytes.WithLabelValues(string(metricReason), tc.tenantID) + profilesMetric := validation.DiscardedProfiles.WithLabelValues(string(metricReason), tc.tenantID) + + bytesDelta := testutil.ToFloat64(bytesMetric) - metricsBefore[bytesMetric] + profilesDelta := testutil.ToFloat64(profilesMetric) - metricsBefore[profilesMetric] + + if tc.expectDiscardedBytes > 0 { + require.Equal(t, tc.expectDiscardedBytes, bytesDelta, "expected %f discarded bytes, got %f", tc.expectDiscardedBytes, bytesDelta) + } + if tc.expectDiscardedProfiles > 0 { + require.Equal(t, tc.expectDiscardedProfiles, profilesDelta, "expected %f discarded profiles, got %f", tc.expectDiscardedProfiles, profilesDelta) + } + } + }) + } + +} + +func TestDistributorAPIMaxProfileSizeBytes(t *testing.T) { + const metricReason = validation.ProfileSizeLimit + + logger := log.NewNopLogger() + + limits := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.MaxProfileSizeBytes = 1024 * 1024 // 1 MB + l.IngestionRateMB = 10000 // set this high enough to not interfere + tenantLimits["1mb-profile-limit"] = l + }) + + d, err := distributor.NewTestDistributor(t, + logger, + limits, + ) + require.NoError(t, err) + + a := newAPITest(t, api.Config{}, logger) + a.RegisterDistributor(d, limits, server.Config{}) + + // generate sample payloads + var ( + pprofUnderOneMb = pprofWithSize(t, underOneMb) + pprofOverOneMb = pprofWithSize(t, overOneMb) + pprofGzipUnderOneMb = gzipper(t, pprofWithSize, underOneMb) + pprofGzipOverOneMb = gzipper(t, pprofWithSize, overOneMb) + otlpJSONUnderOneMb = otlpJSONWithSize(t, underOneMb) + otlpJSONOverOneMb = otlpJSONWithSize(t, overOneMb) + otlpJSONGzipUnderOneMb = gzipper(t, otlpJSONWithSize, underOneMb) + otlpJSONGzipOverOneMb = gzipper(t, otlpJSONWithSize, overOneMb) + ) + + testCases := []struct { + name string + skipMsg string + request func(context.Context) *http.Request + tenantID string + expectedStatus int + expectedErrorMsg string + expectDiscardedBytes float64 + expectDiscardedProfiles float64 + }{ + { + name: "ingest/uncompressed/within-limit", + request: reqIngestPprof(pprofUnderOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "ingest/uncompressed/exact-limit", + request: reqIngestPprof(pprofWithSize(t, 1024*1024-8)), // Note the extra 8 byte are used up by added metadata + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "ingest/uncompressed/exceeds-limit", + request: reqIngestPprof(pprofOverOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 422, + expectedErrorMsg: "exceeds maximum allowed size", + }, + { + name: "ingest/gzip/within-limit", + request: reqIngestGzPprof(pprofGzipUnderOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "ingest/gzip/exact-limit", + request: reqIngestPprof(gzipper(t, pprofWithSize, 1024*1024-8)), // Note the extra 8 byte are used up by added metadata + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "ingest/gzip/exceeds-limit", + request: reqIngestGzPprof(pprofGzipOverOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 422, + expectedErrorMsg: "exceeds maximum allowed size", + }, + { + name: "push-json/uncompressed/within-limit", + request: reqPushPprofJson([][]byte{pprofUnderOneMb}), + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "push-json/uncompressed/exceeds-limit", + request: reqPushPprofJson([][]byte{pprofOverOneMb}), + tenantID: "1mb-profile-limit", + expectedStatus: 400, + expectedErrorMsg: "uncompressed profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(oneMb), + expectDiscardedProfiles: 1, + }, + { + name: "push-json/gzip/within-limit", + request: reqPushPprofJson([][]byte{pprofGzipUnderOneMb}), + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "push-json/gzip/exceeds-limit", + request: reqPushPprofJson([][]byte{pprofGzipOverOneMb}), + tenantID: "1mb-profile-limit", + expectedStatus: 400, + expectedErrorMsg: "uncompressed profile payload size exceeds limit of 1.0 MB", + expectDiscardedBytes: float64(oneMb), + expectDiscardedProfiles: 1, + }, + { + name: "otlp-json/uncompressed/within-limit", + request: reqOTLPJson(otlpJSONUnderOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "otlp-json/uncompressed/exceeds-limit", + request: reqOTLPJson(otlpJSONOverOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 400, + expectedErrorMsg: "exceeds the size limit", + expectDiscardedProfiles: 1, + // Note: Bytes not checked for OTLP as they're based on converted pprof size + }, + { + name: "otlp-json/gzip/within-limit", + request: reqOTLPJsonGzip(otlpJSONGzipUnderOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 200, + }, + { + name: "otlp-json/gzip/exceeds-limit", + request: reqOTLPJsonGzip(otlpJSONGzipOverOneMb), + tenantID: "1mb-profile-limit", + expectedStatus: 400, + expectedErrorMsg: "exceeds the size limit", + expectDiscardedProfiles: 1, + // Note: Bytes not checked for OTLP as they're based on converted pprof size + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.skipMsg != "" { + t.Skip(tc.skipMsg) + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + req := tc.request(ctx) + req.Header.Set("X-Scope-OrgID", tc.tenantID) + + // Capture metrics before request if we expect them to change + var metricsBefore map[prometheus.Collector]float64 + if tc.expectDiscardedBytes > 0 || tc.expectDiscardedProfiles > 0 { + metricsBefore = map[prometheus.Collector]float64{ + validation.DiscardedBytes.WithLabelValues(string(metricReason), tc.tenantID): testutil.ToFloat64(validation.DiscardedBytes.WithLabelValues(string(metricReason), tc.tenantID)), + validation.DiscardedProfiles.WithLabelValues(string(metricReason), tc.tenantID): testutil.ToFloat64(validation.DiscardedProfiles.WithLabelValues(string(metricReason), tc.tenantID)), + } + } + + // Execute request through the mux + res := httptest.NewRecorder() + a.HTTPMux.ServeHTTP(res, req) + + // Assertions + require.Equal(t, tc.expectedStatus, res.Code, + "expected status %d, got %d. Response body: %s", + tc.expectedStatus, res.Code, res.Body.String()) + + if tc.expectedErrorMsg != "" { + require.Contains(t, res.Body.String(), tc.expectedErrorMsg) + } + + // Check metrics if expected + if tc.expectDiscardedBytes > 0 || tc.expectDiscardedProfiles > 0 { + bytesMetric := validation.DiscardedBytes.WithLabelValues(string(metricReason), tc.tenantID) + profilesMetric := validation.DiscardedProfiles.WithLabelValues(string(metricReason), tc.tenantID) + + bytesDelta := testutil.ToFloat64(bytesMetric) - metricsBefore[bytesMetric] + profilesDelta := testutil.ToFloat64(profilesMetric) - metricsBefore[profilesMetric] + + if tc.expectDiscardedBytes > 0 { + require.Equal(t, tc.expectDiscardedBytes, bytesDelta, "expected %f discarded bytes, got %f", tc.expectDiscardedBytes, bytesDelta) + } + if tc.expectDiscardedProfiles > 0 { + require.Equal(t, tc.expectDiscardedProfiles, profilesDelta, "expected %f discarded profiles, got %f", tc.expectDiscardedProfiles, profilesDelta) + } + } + }) + } + +} diff --git a/pkg/distributor/distributor_pushbatch_test.go b/pkg/distributor/distributor_pushbatch_test.go new file mode 100644 index 0000000000..5ef4f80fd5 --- /dev/null +++ b/pkg/distributor/distributor_pushbatch_test.go @@ -0,0 +1,223 @@ +package distributor + +import ( + "context" + "fmt" + "sync/atomic" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/ring/client" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/distributor/writepath" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + pprof2 "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +// probeSegmentWriter is a SegmentWriterClient that observes the concurrency of +// PushBatch's per-series fan-out. Tests route every series through the segment +// writer (see newProbeDistributor), whose fast path calls Push synchronously +// inside the errgroup-bounded goroutine — so the number of concurrent Push +// calls equals the number of concurrently executing pushSeries. +// +// Push sleeps briefly while holding a slot so overlapping calls are observed; +// maxInFlight records the peak fan-out using atomics only (no channels, no +// timing windows). +type probeSegmentWriter struct { + inFlight atomic.Int64 + maxInFlight atomic.Int64 + pushed atomic.Int64 + + // failServices / panicServices select, by service_name, the calls that + // return an error or panic respectively. They are populated before PushBatch + // runs and only read afterwards, so concurrent reads are race-free. + failServices map[string]bool + panicServices map[string]bool +} + +func (p *probeSegmentWriter) CheckReady(context.Context) error { return nil } + +func (p *probeSegmentWriter) Push(_ context.Context, req *segmentwriterv1.PushRequest) (*segmentwriterv1.PushResponse, error) { + svc := phlaremodel.Labels(req.Labels).Get(phlaremodel.LabelNameServiceName) + + n := p.inFlight.Add(1) + for { + m := p.maxInFlight.Load() + if n <= m || p.maxInFlight.CompareAndSwap(m, n) { + break + } + } + // Hold the slot briefly so concurrent calls overlap and maxInFlight reflects + // the real peak fan-out. + time.Sleep(2 * time.Millisecond) + p.inFlight.Add(-1) + + if p.panicServices[svc] { + panic(fmt.Sprintf("probe panic for %s", svc)) + } + if p.failServices[svc] { + return nil, fmt.Errorf("probe failure for %s", svc) + } + p.pushed.Add(1) + return &segmentwriterv1.PushResponse{}, nil +} + +// newProbeDistributor builds a distributor whose write path routes every series +// to the segment-writer probe (synchronous fast path), with the fan-out bounded +// to maxConcurrency. +func newProbeDistributor(t *testing.T, sw SegmentWriterClient, maxConcurrency int) *Distributor { + t.Helper() + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.WritePathOverrides.WritePath = writepath.SegmentWriterPath + l.PushMaxConcurrency = maxConcurrency + tenantLimits["user-1"] = l + }) + d, err := New( + Config{DistributorRing: ringConfig}, + testhelper.NewMockRing([]ring.InstanceDesc{{Addr: "foo"}}, 3), + &poolFactory{f: func(addr string) (client.PoolClient, error) { return newFakeIngester(t, false), nil }}, + overrides, nil, log.NewNopLogger(), sw, + ) + require.NoError(t, err) + return d +} + +// probeProfileSeries builds n distinct-label series, each carrying a minimal +// valid profile that splits into exactly one segment-writer request (so PushBatch +// takes the synchronous fast path). Series i is tagged service_name=svc-i. +func probeProfileSeries(n int) []*distributormodel.ProfileSeries { + series := make([]*distributormodel.ProfileSeries, n) + for i := range series { + series[i] = &distributormodel.ProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: ProfileName, Value: "process_cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: fmt.Sprintf("svc-%d", i)}, + }, + Profile: newProbeProfile(), + } + } + return series +} + +// newProbeProfile returns a minimal, valid profile: one sample type, one sample +// with a non-zero value (survives normalization) and no sample labels (so the +// segment-writer split yields exactly one series/request). +func newProbeProfile() *pprof2.Profile { + return pprof2.RawFromProto(&profilev1.Profile{ + SampleType: []*profilev1.ValueType{{Type: 1, Unit: 2}}, + Sample: []*profilev1.Sample{{LocationId: []uint64{1}, Value: []int64{1}}}, + Mapping: []*profilev1.Mapping{{Id: 1, HasFunctions: true}}, + Location: []*profilev1.Location{{Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1}}}}, + Function: []*profilev1.Function{{Id: 1, Name: 3, SystemName: 3, Filename: 4}}, + StringTable: []string{"", "cpu", "nanoseconds", "main", "main.go"}, + }) +} + +// runPushBatchProbe pushes n distinct series through a probe distributor bounded +// to maxConcurrency and returns the probe for assertions. +func runPushBatchProbe(t *testing.T, maxConcurrency, n int) *probeSegmentWriter { + t.Helper() + probe := &probeSegmentWriter{} + d := newProbeDistributor(t, probe, maxConcurrency) + ctx := tenant.InjectTenantID(context.Background(), "user-1") + err := d.PushBatch(ctx, &distributormodel.PushRequest{ + RawProfileType: distributormodel.RawProfileTypePPROF, + Series: probeProfileSeries(n), + }) + require.NoError(t, err) + return probe +} + +// TestPushBatch_ConcurrencyCeiling: the fan-out never exceeds the configured +// bound, and every series is attempted. +func TestPushBatch_ConcurrencyCeiling(t *testing.T) { + t.Parallel() + const limit, n = 8, 50 + probe := runPushBatchProbe(t, limit, n) + assert.LessOrEqual(t, probe.maxInFlight.Load(), int64(limit), "fan-out must never exceed the bound") + assert.Equal(t, int64(n), probe.pushed.Load(), "all series attempted") +} + +// TestPushBatch_LimitOneSerializes: a bound of 1 serializes the fan-out (kill +// switch) — at most one series is ever in flight. +func TestPushBatch_LimitOneSerializes(t *testing.T) { + t.Parallel() + const n = 10 + probe := runPushBatchProbe(t, 1, n) + assert.LessOrEqual(t, probe.maxInFlight.Load(), int64(1), "limit=1 must serialize pushes") + assert.Equal(t, int64(n), probe.pushed.Load(), "all series attempted") +} + +// TestPushBatch_LimitZeroUnbounded: a bound of 0 is legacy/unbounded. The point +// is that a non-positive bound skips SetLimit rather than calling SetLimit(0), +// which would deadlock — so all N series must complete. +func TestPushBatch_LimitZeroUnbounded(t *testing.T) { + t.Parallel() + const n = 16 + probe := runPushBatchProbe(t, 0, n) + assert.Equal(t, int64(n), probe.pushed.Load(), "all series must complete (no SetLimit(0) deadlock)") +} + +// TestPushBatch_AggregatesAllErrors: every failing series is attempted and its +// error is aggregated into the multierror, each wrapped with its index; +// non-failing series still succeed. +func TestPushBatch_AggregatesAllErrors(t *testing.T) { + t.Parallel() + const n = 10 + failIdx := []int{2, 5, 8} + probe := &probeSegmentWriter{failServices: map[string]bool{}} + for _, i := range failIdx { + probe.failServices[fmt.Sprintf("svc-%d", i)] = true + } + d := newProbeDistributor(t, probe, 4) + ctx := tenant.InjectTenantID(context.Background(), "user-1") + + err := d.PushBatch(ctx, &distributormodel.PushRequest{ + RawProfileType: distributormodel.RawProfileTypePPROF, + Series: probeProfileSeries(n), + }) + require.Error(t, err) + msg := err.Error() + for _, i := range failIdx { + assert.Contains(t, msg, fmt.Sprintf("push series with index %d and", i), "aggregated error must include failing series %d", i) + assert.Contains(t, msg, fmt.Sprintf("probe failure for svc-%d", i)) + } + // Non-failing series must not surface as errors. + assert.NotContains(t, msg, "push series with index 0 and") + assert.NotContains(t, msg, "push series with index 9 and") + // Every non-failing series was still pushed. + assert.Equal(t, int64(n-len(failIdx)), probe.pushed.Load()) +} + +// TestPushBatch_PanicInOneSeriesDoesNotKillOthers: a panic in one series is +// recovered (util.RecoverPanic / router recovery) and surfaces as an aggregated +// error; the other series still complete. +func TestPushBatch_PanicInOneSeriesDoesNotKillOthers(t *testing.T) { + t.Parallel() + const n = 5 + probe := &probeSegmentWriter{panicServices: map[string]bool{"svc-1": true}} + d := newProbeDistributor(t, probe, 4) + ctx := tenant.InjectTenantID(context.Background(), "user-1") + + err := d.PushBatch(ctx, &distributormodel.PushRequest{ + RawProfileType: distributormodel.RawProfileTypePPROF, + Series: probeProfileSeries(n), + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "push series with index 1 and") + assert.Contains(t, err.Error(), "probe panic for svc-1") + // The panicking series is recovered; the other four still complete. + assert.Equal(t, int64(n-1), probe.pushed.Load()) +} diff --git a/pkg/distributor/distributor_readiness_test.go b/pkg/distributor/distributor_readiness_test.go new file mode 100644 index 0000000000..824804250b --- /dev/null +++ b/pkg/distributor/distributor_readiness_test.go @@ -0,0 +1,157 @@ +package distributor + +import ( + "context" + "flag" + "os" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/ring/client" + "github.com/grafana/dskit/services" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/clientpool" + "github.com/grafana/pyroscope/v2/pkg/distributor/writepath" + segmentwriterclient "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client" + "github.com/grafana/pyroscope/v2/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func newReadinessSegmentWriterClient(t *testing.T, ctx context.Context, logger log.Logger, r ring.ReadRing) *segmentwriterclient.Client { + t.Helper() + var grpcCfg grpcclient.Config + grpcCfg.RegisterFlags(flag.NewFlagSet("", flag.PanicOnError)) + + swClient, err := segmentwriterclient.NewSegmentWriterClient( + grpcCfg, logger, nil, r, nil, + ) + require.NoError(t, err) + require.NoError(t, services.StartAndAwaitRunning(ctx, swClient.Service())) + t.Cleanup(func() { + _ = services.StopAndAwaitTerminated(context.Background(), swClient.Service()) + }) + return swClient +} + +func newReadinessDistributor( + t *testing.T, + ctx context.Context, + logger log.Logger, + path writepath.WritePath, + ingesterRing ring.ReadRing, + swClient SegmentWriterClient, +) *Distributor { + t.Helper() + overrides := validation.MockOverrides(func(defaults *validation.Limits, _ map[string]*validation.Limits) { + defaults.WritePathOverrides.WritePath = path + }) + + d, err := New( + Config{ + DistributorRing: ringConfig, + PoolConfig: clientpool.PoolConfig{ClientCleanupPeriod: time.Second}, + }, + ingesterRing, + &poolFactory{f: func(string) (client.PoolClient, error) { + return newFakeIngester(t, false), nil + }}, + overrides, + nil, + logger, + swClient, + ) + require.NoError(t, err) + require.NoError(t, services.StartAndAwaitRunning(ctx, d)) + t.Cleanup(func() { + _ = services.StopAndAwaitTerminated(context.Background(), d) + }) + require.Equal(t, services.Running, d.State()) + return d +} + +func TestDistributor_CheckReady_V2SegmentWriterPath(t *testing.T) { + logger := log.NewLogfmtLogger(os.Stdout) + ctx := context.Background() + + tests := []struct { + name string + segmentWriterRing ring.ReadRing + wantErr bool + }{ + { + name: "ready when segment-writer ring has healthy instances", + segmentWriterRing: testhelper.NewMockRing([]ring.InstanceDesc{{Addr: "foo"}}, 1), + }, + { + name: "not ready when segment-writer ring is empty", + segmentWriterRing: testhelper.NewMockRing(nil, 1), + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + swClient := newReadinessSegmentWriterClient(t, ctx, logger, tt.segmentWriterRing) + d := newReadinessDistributor( + t, + ctx, + logger, + writepath.SegmentWriterPath, + testhelper.NewMockRing([]ring.InstanceDesc{{Addr: "foo"}}, 3), + swClient, + ) + + err := d.CheckReady(ctx) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestDistributor_CheckReady_V1IngesterPath(t *testing.T) { + logger := log.NewLogfmtLogger(os.Stdout) + ctx := context.Background() + + tests := []struct { + name string + ingesterRing ring.ReadRing + wantErr bool + }{ + { + name: "ready when ingester ring has healthy instances", + ingesterRing: testhelper.NewMockRing([]ring.InstanceDesc{{Addr: "foo"}}, 3), + }, + { + name: "not ready when ingester ring is empty", + ingesterRing: testhelper.NewMockRing(nil, 3), + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := newReadinessDistributor( + t, + ctx, + logger, + writepath.IngesterPath, + tt.ingesterRing, + nil, + ) + + err := d.CheckReady(ctx) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/pkg/distributor/distributor_recvmetric_test.go b/pkg/distributor/distributor_recvmetric_test.go new file mode 100644 index 0000000000..d6a3e0c929 --- /dev/null +++ b/pkg/distributor/distributor_recvmetric_test.go @@ -0,0 +1,179 @@ +package distributor + +import ( + "context" + "os" + "regexp" + "testing" + + "github.com/go-kit/log" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/ring/client" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/prometheus/common/expfmt" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func TestDistributorPushWithDifferentTenantStages(t *testing.T) { + const tenantId = "239" + + testCases := []struct { + name string + profilePath string + limitOverrides func(l *validation.Limits) + failIngester bool + expectErr bool + expectedErrMsg string + expectedMetrics []string + }{ + { + name: "successful push", + profilePath: "../../pkg/og/convert/testdata/cpu.pprof", + expectedMetrics: []string{ + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="normalized",tenant="239"} 2024`, + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="received",tenant="239"} 2198`, + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="sampled",tenant="239"} 2144`, + }, + }, + { + name: "rate limit - only received stage", + profilePath: "../../pkg/og/convert/testdata/cpu.pprof", + limitOverrides: func(l *validation.Limits) { + l.IngestionRateMB = 0.000001 + l.IngestionBurstSizeMB = 0.000001 + }, + expectErr: true, + expectedErrMsg: "rate limit", + expectedMetrics: []string{ + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="received",tenant="239"} 2198`, + }, + }, + + { + name: "invalid profile", + profilePath: "../../pkg/og/convert/testdata/cpu.pprof", + limitOverrides: func(l *validation.Limits) { + l.MaxProfileSizeBytes = 2 + }, + expectErr: true, + expectedErrMsg: "exceeds the size limit (max_profile_size_byte, actual: 2144, limit: 2)", + expectedMetrics: []string{ + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="received",tenant="239"} 2198`, + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="sampled",tenant="239"} 2144`, + }, + }, + { + name: "ingester fails", + profilePath: "../../pkg/og/convert/testdata/cpu.pprof", + failIngester: true, + expectErr: true, + expectedMetrics: []string{ + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="normalized",tenant="239"} 2024`, + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="received",tenant="239"} 2198`, + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="sampled",tenant="239"} 2144`, + }, + }, + { + name: "heap profile with sample type relabeling - keep only inuse_space", + profilePath: "../../pkg/pprof/testdata/heap", + limitOverrides: func(l *validation.Limits) { + l.SampleTypeRelabelingRules = []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__type__"}, + Regex: relabel.MustNewRegexp("inuse_space"), + Action: relabel.Keep, + }, + } + }, + expectedMetrics: []string{ + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="normalized",tenant="239"} 46234`, + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="received",tenant="239"} 847192`, + `pyroscope_distributor_received_decompressed_bytes_total_sum{stage="sampled",tenant="239"} 847138`, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + reg := prometheus.NewRegistry() + + ing := newFakeIngester(t, tc.failIngester) + + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + + if tc.limitOverrides != nil { + tc.limitOverrides(l) + } + + tenantLimits[tenantId] = l + }) + + d, err := New( + Config{DistributorRing: ringConfig}, + testhelper.NewMockRing([]ring.InstanceDesc{{Addr: "foo"}}, 3), + &poolFactory{func(addr string) (client.PoolClient, error) { + return ing, nil + }}, + overrides, + reg, + log.NewLogfmtLogger(os.Stdout), + nil, + ) + require.NoError(t, err) + + profileBytes, err := os.ReadFile(tc.profilePath) + require.NoError(t, err) + + parsedProfile, err := pprof.RawFromBytes(profileBytes) + require.NoError(t, err) + + ctx := tenant.InjectTenantID(context.Background(), tenantId) + req := &distributormodel.PushRequest{ + Series: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "cluster", Value: "test-cluster"}, + {Name: phlaremodel.LabelNameServiceName, Value: "test-service"}, + {Name: "__name__", Value: "cpu"}, + }, + RawProfile: profileBytes, + Profile: parsedProfile, + }, + }, + RawProfileType: distributormodel.RawProfileTypePPROF, + } + + err = d.PushBatch(ctx, req) + + if tc.expectErr { + require.Error(t, err) + if tc.expectedErrMsg != "" { + require.Contains(t, err.Error(), tc.expectedErrMsg) + } + } else { + require.NoError(t, err) + } + + bs, err := testutil.CollectAndFormat(reg, expfmt.TypeTextPlain, "pyroscope_distributor_received_decompressed_bytes_total") + require.NoError(t, err) + + sums := regexp.MustCompile("pyroscope_distributor_received_decompressed_bytes_total_sum.*"). + FindAllString(string(bs), -1) + + assert.Equal(t, tc.expectedMetrics, sums) + }) + } +} diff --git a/pkg/distributor/distributor_ring.go b/pkg/distributor/distributor_ring.go index a60f29a671..cc69ebe5d9 100644 --- a/pkg/distributor/distributor_ring.go +++ b/pkg/distributor/distributor_ring.go @@ -1,12 +1,13 @@ package distributor import ( - "fmt" + "net" + "strconv" "github.com/go-kit/log" "github.com/grafana/dskit/ring" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -17,7 +18,7 @@ const ( ) func toBasicLifecyclerConfig(cfg util.CommonRingConfig, logger log.Logger) (ring.BasicLifecyclerConfig, error) { - instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger, false) + instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger, cfg.EnableIPv6) if err != nil { return ring.BasicLifecyclerConfig{}, err } @@ -26,7 +27,7 @@ func toBasicLifecyclerConfig(cfg util.CommonRingConfig, logger log.Logger) (ring return ring.BasicLifecyclerConfig{ ID: cfg.InstanceID, - Addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), + Addr: net.JoinHostPort(instanceAddr, strconv.Itoa(instancePort)), HeartbeatPeriod: cfg.HeartbeatPeriod, HeartbeatTimeout: cfg.HeartbeatTimeout, TokensObservePeriod: 0, diff --git a/pkg/distributor/distributor_test.go b/pkg/distributor/distributor_test.go index acc0f9e5dd..d765fe9bbf 100644 --- a/pkg/distributor/distributor_test.go +++ b/pkg/distributor/distributor_test.go @@ -5,17 +5,22 @@ import ( "context" "errors" "fmt" + "math" "net/http" "net/http/httptest" "os" + "regexp" "runtime/pprof" "strconv" + "strings" "sync" "testing" "time" "connectrpc.com/connect" - "github.com/dustin/go-humanize" + "google.golang.org/grpc" + "google.golang.org/grpc/health/grpc_health_v1" + "github.com/go-kit/log" "github.com/grafana/dskit/kv" "github.com/grafana/dskit/ring" @@ -23,26 +28,29 @@ import ( "github.com/grafana/dskit/services" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - testhelper2 "github.com/grafana/pyroscope/pkg/pprof/testhelper" - profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - distributormodel "github.com/grafana/pyroscope/pkg/distributor/model" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - pprof2 "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/util" - pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/clientpool" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/testhelper" - "github.com/grafana/pyroscope/pkg/validation" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + "github.com/grafana/pyroscope/v2/pkg/distributor/annotation" + "github.com/grafana/pyroscope/v2/pkg/distributor/ingestlimits" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/distributor/sampling" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + pprof2 "github.com/grafana/pyroscope/v2/pkg/pprof" + pproftesthelper "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/validation" ) var ringConfig = util.CommonRingConfig{ @@ -66,8 +74,7 @@ func (pf *poolFactory) FromInstance(inst ring.InstanceDesc) (client.PoolClient, return pf.f(inst.Addr) } -func Test_ConnectPush(t *testing.T) { - mux := http.NewServeMux() +func newTestDistributor(t testing.TB, logger log.Logger, overrides *validation.Overrides) (*Distributor, *fakeIngester, error) { ing := newFakeIngester(t, false) d, err := New(Config{ DistributorRing: ringConfig, @@ -75,7 +82,21 @@ func Test_ConnectPush(t *testing.T) { {Addr: "foo"}, }, 3), &poolFactory{func(addr string) (client.PoolClient, error) { return ing, nil - }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout)) + }}, overrides, nil, logger, nil) + return d, ing, err +} + +func NewTestDistributor(t testing.TB, logger log.Logger, overrides *validation.Overrides) (*Distributor, error) { + d, _, err := newTestDistributor(t, logger, overrides) + return d, err +} + +func Test_ConnectPush(t *testing.T) { + mux := http.NewServeMux() + d, ing, err := newTestDistributor(t, + log.NewLogfmtLogger(os.Stdout), + newOverrides(t), + ) require.NoError(t, err) mux.Handle(pushv1connect.NewPusherServiceHandler(d, handlerOptions...)) @@ -133,7 +154,7 @@ func Test_Replication(t *testing.T) { {Addr: "3"}, }, 3), &poolFactory{f: func(addr string) (client.PoolClient, error) { return ingesters[addr], nil - }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout)) + }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout), nil) require.NoError(t, err) // only 1 ingester failing should be fine. resp, err := d.Push(ctx, req) @@ -155,7 +176,7 @@ func Test_Subservices(t *testing.T) { {Addr: "foo"}, }, 1), &poolFactory{f: func(addr string) (client.PoolClient, error) { return ing, nil - }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout)) + }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout), nil) require.NoError(t, err) require.NoError(t, d.StartAsync(context.Background())) @@ -180,12 +201,12 @@ func collectTestProfileBytes(t *testing.T) []byte { func hugeProfileBytes(t *testing.T) []byte { t.Helper() - b := testhelper2.NewProfileBuilderWithLabels(time.Now().UnixNano(), nil) + b := pproftesthelper.NewProfileBuilderWithLabels(time.Now().UnixNano(), nil) p := b.CPUProfile() for i := 0; i < 10_000; i++ { p.ForStacktraceString(fmt.Sprintf("my_%d", i), "other").AddSamples(1) } - bs, err := p.Profile.MarshalVT() + bs, err := p.MarshalVT() require.NoError(t, err) return bs } @@ -199,6 +220,10 @@ type fakeIngester struct { mtx sync.Mutex } +func (i *fakeIngester) List(ctx context.Context, in *grpc_health_v1.HealthListRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthListResponse, error) { + return nil, errors.New("not implemented") +} + func (i *fakeIngester) Push(_ context.Context, req *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { i.mtx.Lock() defer i.mtx.Unlock() @@ -214,12 +239,6 @@ func newFakeIngester(t testing.TB, fail bool) *fakeIngester { return &fakeIngester{t: t, fail: fail} } -func TestBuckets(t *testing.T) { - for _, r := range prometheus.ExponentialBucketsRange(minBytes, maxBytes, bucketsCount) { - t.Log(humanize.Bytes(uint64(r))) - } -} - func Test_Limits(t *testing.T) { type testCase struct { description string @@ -320,7 +339,7 @@ func Test_Limits(t *testing.T) { {Addr: "foo"}, }, 3), &poolFactory{f: func(addr string) (client.PoolClient, error) { return ing, nil - }}, tc.overrides, nil, log.NewLogfmtLogger(os.Stdout)) + }}, tc.overrides, nil, log.NewLogfmtLogger(os.Stdout), nil) require.NoError(t, err) @@ -412,7 +431,7 @@ func Test_Sessions_Limit(t *testing.T) { l := validation.MockDefaultLimits() l.MaxSessionsPerSeries = tc.maxSessions tenantLimits["user-1"] = l - }), nil, log.NewLogfmtLogger(os.Stdout)) + }), nil, log.NewLogfmtLogger(os.Stdout), nil) require.NoError(t, err) limit := d.limits.MaxSessionsPerSeries("user-1") @@ -421,250 +440,1384 @@ func Test_Sessions_Limit(t *testing.T) { } } -func Test_SampleLabels(t *testing.T) { +func Test_IngestLimits(t *testing.T) { type testCase struct { - description string - pushReq *distributormodel.PushRequest - series []*distributormodel.ProfileSeries + description string + pushReq *distributormodel.PushRequest + overrides *validation.Overrides + verifyExpectations func(t *testing.T, err error, req *distributormodel.PushRequest) } testCases := []testCase{ { - description: "no series labels, no sample labels", + description: "ingest_limit_reached_no_series", + pushReq: &distributormodel.PushRequest{}, + overrides: validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: 1737721086, + LimitReached: true, + Sampling: ingestlimits.SamplingConfig{ + NumRequests: 0, + Period: time.Minute, + }, + } + tenantLimits["user-1"] = l + }), + verifyExpectations: func(t *testing.T, err error, req *distributormodel.PushRequest) { + require.Error(t, err) + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }, + }, + { + description: "ingest_limit_reached_no_profile", + pushReq: &distributormodel.PushRequest{Series: []*distributormodel.ProfileSeries{{}}}, + overrides: validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: 1737721086, + LimitReached: true, + Sampling: ingestlimits.SamplingConfig{ + NumRequests: 0, + Period: time.Minute, + }, + } + tenantLimits["user-1"] = l + }), + verifyExpectations: func(t *testing.T, err error, req *distributormodel.PushRequest) { + require.Error(t, err) + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + }, + }, + { + description: "ingest_limit_reached", + pushReq: &distributormodel.PushRequest{Series: []*distributormodel.ProfileSeries{{ + Profile: pprof2.RawFromProto(testProfile(1)), + }}}, + overrides: validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: 1737721086, + LimitReached: true, + Sampling: ingestlimits.SamplingConfig{ + NumRequests: 0, + Period: time.Minute, + }, + } + tenantLimits["user-1"] = l + }), + verifyExpectations: func(t *testing.T, err error, req *distributormodel.PushRequest) { + require.Error(t, err) + require.Equal(t, connect.CodeResourceExhausted, connect.CodeOf(err)) + }, + }, + { + description: "ingest_limit_reached_sampling", pushReq: &distributormodel.PushRequest{ Series: []*distributormodel.ProfileSeries{ { - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - }}, - }), - }, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc"}, }, + Profile: pprof2.RawFromProto(testProfile(1)), }, }, }, - series: []*distributormodel.ProfileSeries{ - { - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - }}, - }), + overrides: validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: 1737721086, + LimitReached: true, + Sampling: ingestlimits.SamplingConfig{ + NumRequests: 1, + Period: time.Minute, + }, + } + tenantLimits["user-1"] = l + }), + verifyExpectations: func(t *testing.T, err error, req *distributormodel.PushRequest) { + require.NoError(t, err) + require.Equal(t, 1, len(req.Series[0].Annotations)) + // annotations are json encoded and contain some of the limit config fields + require.True(t, strings.Contains(req.Series[0].Annotations[0].Value, "\"periodLimitMb\":128")) + }, + }, + { + description: "ingest_limit_reached_with_sampling_error", + pushReq: &distributormodel.PushRequest{ + Series: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc"}, }, + Profile: pprof2.RawFromProto(testProfile(1)), }, }, }, + overrides: validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: 1737721086, + LimitReached: true, + Sampling: ingestlimits.SamplingConfig{ + NumRequests: 0, + Period: time.Minute, + }, + } + tenantLimits["user-1"] = l + }), + verifyExpectations: func(t *testing.T, err error, req *distributormodel.PushRequest) { + require.Error(t, err) + require.Equal(t, connect.CodeResourceExhausted, connect.CodeOf(err)) + require.Empty(t, req.Series[0].Annotations) + }, }, { - description: "has series labels, no sample labels", + description: "ingest_limit_reached_with_multiple_usage_groups", pushReq: &distributormodel.PushRequest{ Series: []*distributormodel.ProfileSeries{ { Labels: []*typesv1.LabelPair{ - {Name: "foo", Value: "bar"}, + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc1"}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - }}, - }), - }, + RawProfile: collectTestProfileBytes(t), + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + StringTable: []string{""}, + }), + }, + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc2"}, }, + Profile: pprof2.RawFromProto(testProfile(1)), }, }, }, - series: []*distributormodel.ProfileSeries{ - { - Labels: []*typesv1.LabelPair{ - {Name: "foo", Value: "bar"}, - }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - }}, - }), + overrides: validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: 1737721086, + LimitReached: false, + UsageGroups: map[string]ingestlimits.UsageGroup{ + "group-1": { + PeriodLimitMb: 64, + LimitReached: true, + }, + "group-2": { + PeriodLimitMb: 32, + LimitReached: true, }, }, - }, + } + usageGroupCfg, err := validation.NewUsageGroupConfig(map[string]string{ + "group-1": "{service_name=\"svc1\"}", + "group-2": "{service_name=\"svc2\"}", + }) + require.NoError(t, err) + l.DistributorUsageGroups = usageGroupCfg + tenantLimits["user-1"] = l + }), + verifyExpectations: func(t *testing.T, err error, req *distributormodel.PushRequest) { + require.Error(t, err) + require.Equal(t, connect.CodeResourceExhausted, connect.CodeOf(err)) + require.Empty(t, req.Series[0].Annotations) + require.Empty(t, req.Series[1].Annotations) }, }, { - description: "no series labels, all samples have identical label set", + description: "ingest_limit_reached_with_sampling_and_usage_groups", pushReq: &distributormodel.PushRequest{ Series: []*distributormodel.ProfileSeries{ { - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - StringTable: []string{"", "foo", "bar"}, - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - Label: []*profilev1.Label{ - {Key: 1, Str: 2}, - }, - }}, - }), - }, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc"}, }, + Profile: pprof2.RawFromProto(testProfile(1)), }, }, }, - series: []*distributormodel.ProfileSeries{ + overrides: validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: 1737721086, + LimitReached: true, + Sampling: ingestlimits.SamplingConfig{ + NumRequests: 100, + Period: time.Minute, + }, + UsageGroups: map[string]ingestlimits.UsageGroup{ + "group-1": { + PeriodLimitMb: 64, + LimitReached: true, + }, + }, + } + usageGroupCfg, err := validation.NewUsageGroupConfig(map[string]string{ + "group-1": "{service_name=\"svc\"}", + }) + require.NoError(t, err) + l.DistributorUsageGroups = usageGroupCfg + tenantLimits["user-1"] = l + }), + verifyExpectations: func(t *testing.T, err error, req *distributormodel.PushRequest) { + require.NoError(t, err) + require.Len(t, req.Series[0].Annotations, 2) + assert.Contains(t, req.Series[0].Annotations[0].Value, "\"periodLimitMb\":128") + assert.Contains(t, req.Series[0].Annotations[1].Value, "\"usageGroup\":\"group-1\"") + assert.Contains(t, req.Series[0].Annotations[1].Value, "\"periodLimitMb\":64") + }, + }, + } + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + ing := newFakeIngester(t, false) + d, err := New(Config{ + DistributorRing: ringConfig, + }, testhelper.NewMockRing([]ring.InstanceDesc{ + {Addr: "foo"}, + }, 3), &poolFactory{f: func(addr string) (client.PoolClient, error) { + return ing, nil + }}, tc.overrides, nil, log.NewLogfmtLogger(os.Stdout), nil) + require.NoError(t, err) + + err = d.PushBatch(tenant.InjectTenantID(context.Background(), "user-1"), tc.pushReq) + tc.verifyExpectations(t, err, tc.pushReq) + }) + } +} + +func Test_SampleLabels_Ingester(t *testing.T) { + o := validation.MockDefaultOverrides() + defaultRelabelConfigs := o.IngestionRelabelingRules("") + + type testCase struct { + description string + pushReq *distributormodel.ProfileSeries + expectedSeries []*distributormodel.ProfileSeries + relabelRules []*relabel.Config + expectBytesDropped float64 + expectProfilesDropped float64 + expectError error + } + const dummyTenantID = "tenant1" + + testCases := []testCase{ + { + description: "no series labels, no sample labels", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + expectError: connect.NewError(connect.CodeInvalidArgument, validation.NewErrorf(validation.MissingLabels, validation.MissingLabelsErrorMsg)), + }, + { + description: "validation error propagation and accounting", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + }, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + expectError: connect.NewError(connect.CodeInvalidArgument, fmt.Errorf(`invalid labels '{foo="bar"}' with error: invalid metric name`)), + }, + { + description: "has series labels, no sample labels", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "foo", Value: "bar"}, + }, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ { Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - StringTable: []string{"", "foo", "bar"}, - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - Label: []*profilev1.Label{}, - }}, - }), + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + }, + }, + { + description: "all samples have identical label set", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + }, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, }, + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, }, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }), }, }, }, { description: "has series labels, all samples have identical label set", - pushReq: &distributormodel.PushRequest{ - Series: []*distributormodel.ProfileSeries{ - { - Labels: []*typesv1.LabelPair{ - {Name: "baz", Value: "qux"}, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + }, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - StringTable: []string{"", "foo", "bar"}, - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - Label: []*profilev1.Label{ - {Key: 1, Str: 2}, - }, - }}, - }), + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, + }, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }), + }, + }, + }, + { + description: "has series labels, and the only sample label name overlaps with series label, creating overlapping groups", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "foo", Value: "bar"}, + {Name: "baz", Value: "qux"}, + }, + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, }, }, + { + Value: []int64{2}, + }, }, - }, + }), }, - series: []*distributormodel.ProfileSeries{ + expectedSeries: []*distributormodel.ProfileSeries{ { Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, {Name: "baz", Value: "qux"}, {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - StringTable: []string{"", "foo", "bar"}, - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - Label: []*profilev1.Label{}, - }}, - }), + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{3}, + Label: nil, + }, }, - }, + }), }, }, }, { description: "has series labels, samples have distinct label sets", - pushReq: &distributormodel.PushRequest{ - Series: []*distributormodel.ProfileSeries{ - { - Labels: []*typesv1.LabelPair{ - {Name: "baz", Value: "qux"}, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar", "waldo", "fred"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - StringTable: []string{"", "foo", "bar", "waldo", "fred"}, - Sample: []*profilev1.Sample{ - { - Value: []int64{1}, - Label: []*profilev1.Label{ - {Key: 1, Str: 2}, - }, - }, - { - Value: []int64{2}, - Label: []*profilev1.Label{ - {Key: 3, Str: 4}, - }, - }, - }, - }), + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 3, Str: 4}, }, }, }, - }, + }), }, - series: []*distributormodel.ProfileSeries{ + expectedSeries: []*distributormodel.ProfileSeries{ { + TenantID: dummyTenantID, Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, {Name: "baz", Value: "qux"}, {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - StringTable: []string{""}, - Sample: []*profilev1.Sample{{ - Value: []int64{1}, - Label: []*profilev1.Label{}, - }}, - }), - }, - }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }), }, { + TenantID: dummyTenantID, Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, {Name: "baz", Value: "qux"}, + {Name: "service_name", Value: "service"}, {Name: "waldo", Value: "fred"}, }, - Samples: []*distributormodel.ProfileSample{ + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }), + }, + }, + }, + { + description: "has series labels that should be renamed to no longer include godeltaprof", + relabelRules: defaultRelabelConfigs, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "godeltaprof_memory"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__delta__", Value: "false"}, + {Name: "__name__", Value: "memory"}, + {Name: "__name_replaced__", Value: "godeltaprof_memory"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }), + }, + }, + }, + { + description: "has series labels and sample label, which relabel rules drop", + relabelRules: []*relabel.Config{ + {Action: relabel.Drop, SourceLabels: []model.LabelName{"__name__", "span_name"}, Separator: "/", Regex: relabel.MustNewRegexp("unwanted/randomness")}, + }, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, { - Profile: pprof2.RawFromProto(&profilev1.Profile{ - StringTable: []string{""}, - Sample: []*profilev1.Sample{{ - Value: []int64{2}, - Label: []*profilev1.Label{}, - }}, - }), + Value: []int64{1}, }, }, + }), + }, + expectProfilesDropped: 0, + expectBytesDropped: 3, + expectedSeries: []*distributormodel.ProfileSeries{ + { + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), }, }, }, - } + { + description: "has series/sample labels, drops everything", + relabelRules: []*relabel.Config{ + {Action: relabel.Drop, Regex: relabel.MustNewRegexp(".*")}, + }, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, - for _, tc := range testCases { - tc := tc - t.Run(tc.description, func(t *testing.T) { - series := extractSampleSeries(tc.pushReq) - require.Len(t, series, len(tc.series)) + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }), + }, + expectProfilesDropped: 1, + expectBytesDropped: 6, + }, + { + description: "has series labels / sample rules, drops samples label", + relabelRules: []*relabel.Config{ + {Action: relabel.Replace, Regex: relabel.MustNewRegexp(".*"), Replacement: "", TargetLabel: "span_name"}, + }, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{3}, + }}, + }), + }, + }, + }, + { + description: "ensure only samples of same stacktraces get grouped", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar", "binary", "span_id", "aaaabbbbccccdddd", "__name__"}, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2}}}, + }, + Mapping: []*profilev1.Mapping{{}, {Id: 1, Filename: 3}}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1}, + {Id: 2, Name: 2}, + }, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 6, Str: 1}, // This __name__ label is expected to be removed as it overlaps with the series label name + + }, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{1}, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{4}, + Label: []*profilev1.Label{ + {Key: 4, Str: 5}, + }, + }, + { + Value: []int64{8}, + }, + { + Value: []int64{16}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + }, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{3}, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{4}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{8}, + }, + }, + }), + }, + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{16}, + Label: []*profilev1.Label{}, + }}, + }), + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + + // These are both required to be set to fulfill the usage group + // reporting. Neither are validated by the tests, nor do they influence + // test behavior in any way. + ug := &validation.UsageGroupConfig{} + + t.Run(tc.description, func(t *testing.T) { + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionRelabelingRules = tc.relabelRules + l.DistributorUsageGroups = ug + tenantLimits[dummyTenantID] = l + }) + d, err := New(Config{ + DistributorRing: ringConfig, + }, testhelper.NewMockRing([]ring.InstanceDesc{ + {Addr: "foo"}, + }, 3), &poolFactory{func(addr string) (client.PoolClient, error) { + return newFakeIngester(t, false), nil + }}, overrides, nil, log.NewLogfmtLogger(os.Stdout), nil) + require.NoError(t, err) + var series []*distributormodel.ProfileSeries + series, err = d.visitSampleSeries(tc.pushReq, visitSampleSeriesForIngester) + assert.Equal(t, tc.expectBytesDropped, float64(tc.pushReq.DiscardedBytesRelabeling)) + assert.Equal(t, tc.expectProfilesDropped, float64(tc.pushReq.DiscardedProfilesRelabeling)) + + if tc.expectError != nil { + assert.Error(t, err) + assert.Equal(t, tc.expectError.Error(), err.Error()) + return + } else { + assert.NoError(t, err) + } + + require.Len(t, series, len(tc.expectedSeries)) + for i, actualSeries := range series { + expectedSeries := tc.expectedSeries[i] + assert.Equal(t, expectedSeries.Labels, actualSeries.Labels) + expectedProfile := expectedSeries.Profile + assert.Equal(t, expectedProfile.Sample, actualSeries.Profile.Sample) + } + }) + } +} + +func Test_SampleLabels_SegmentWriter(t *testing.T) { + o := validation.MockDefaultOverrides() + defaultRelabelConfigs := o.IngestionRelabelingRules("") + + type testCase struct { + description string + pushReq *distributormodel.ProfileSeries + expectedSeries []*distributormodel.ProfileSeries + relabelRules []*relabel.Config + expectBytesDropped float64 + expectProfilesDropped float64 + expectError error + } + const dummyTenantID = "tenant1" + + testCases := []testCase{ + { + description: "no series labels, no sample labels", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + expectError: connect.NewError(connect.CodeInvalidArgument, validation.NewErrorf(validation.MissingLabels, validation.MissingLabelsErrorMsg)), + }, + { + description: "validation error propagation", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + expectError: connect.NewError(connect.CodeInvalidArgument, fmt.Errorf(`invalid labels '{foo="bar"}' with error: invalid metric name`)), + }, + { + description: "has series labels, no sample labels", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "foo", Value: "bar"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + }, + }, + { + description: "all samples have identical label set", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }), + }, + }, + }, + { + description: "has series labels, all samples have identical label set", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }), + }, + }, + }, + { + description: "has series labels, and the only sample label name overlaps with series label, creating overlapping groups", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "foo", Value: "bar"}, + {Name: "baz", Value: "qux"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{2}, + }, + }, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + {Name: "foo", Value: "bar"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{3}, + Label: nil, + }, + }, + }), + }, + }, + }, + { + description: "has series labels, samples have distinct label sets", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: "service"}, + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar", "waldo", "fred"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 3, Str: 4}, + }, + }, + }, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: "baz", Value: "qux"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar", "waldo", "fred"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 3, Str: 4}, + }, + }, + }, + }), + }, + }, + }, + { + description: "has series labels that should be renamed to no longer include godeltaprof", + relabelRules: defaultRelabelConfigs, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "godeltaprof_memory"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__delta__", Value: "false"}, + {Name: "__name__", Value: "memory"}, + {Name: "__name_replaced__", Value: "godeltaprof_memory"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }), + }, + }, + }, + { + description: "has series labels and sample label, which relabel rules drop", + relabelRules: []*relabel.Config{ + {Action: relabel.Drop, SourceLabels: []model.LabelName{"__name__", "span_name"}, Separator: "/", Regex: relabel.MustNewRegexp("unwanted/randomness")}, + }, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }), + }, + expectProfilesDropped: 0, + expectBytesDropped: 3, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }), + }, + }, + }, + { + description: "has series/sample labels, drops everything", + relabelRules: []*relabel.Config{ + {Action: relabel.Drop, Regex: relabel.MustNewRegexp(".*")}, + }, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }), + }, + expectProfilesDropped: 1, + expectBytesDropped: 6, + }, + { + description: "has series labels / sample rules, drops samples label", + relabelRules: []*relabel.Config{ + {Action: relabel.Replace, Regex: relabel.MustNewRegexp(".*"), Replacement: "", TargetLabel: "span_name"}, + }, + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{3}, + }}, + }), + }, + }, + }, + { + description: "ensure only samples of same stacktraces get grouped", + pushReq: &distributormodel.ProfileSeries{ + TenantID: dummyTenantID, + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "foo", "bar", "binary", "span_id", "aaaabbbbccccdddd", "__name__"}, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2}}}, + }, + Mapping: []*profilev1.Mapping{{}, {Id: 1, Filename: 3}}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1}, + {Id: 2, Name: 2}, + }, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 6, Str: 1}, + }, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{1}, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{4}, + Label: []*profilev1.Label{ + {Key: 4, Str: 5}, + }, + }, + { + Value: []int64{8}, + }, + { + Value: []int64{16}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + }, + }), + }, + expectedSeries: []*distributormodel.ProfileSeries{ + { + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + {Name: "service_name", Value: "service"}, + }, + + Profile: pprof2.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "span_id", "aaaabbbbccccdddd", "foo", "bar", "binary"}, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2}}}, + }, + Mapping: []*profilev1.Mapping{{Id: 1, Filename: 5}}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1}, + {Id: 2, Name: 2}, + }, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{3}, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{4}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{8}, + }, + { + Value: []int64{16}, + Label: []*profilev1.Label{ + {Key: 3, Str: 4}, + }, + }, + }, + }), + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + + // These are both required to be set to fulfill the usage group + // reporting. Neither are validated by the tests, nor do they influence + // test behavior in any way. + ug := &validation.UsageGroupConfig{} + + t.Run(tc.description, func(t *testing.T) { + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.IngestionRelabelingRules = tc.relabelRules + l.DistributorUsageGroups = ug + tenantLimits[dummyTenantID] = l + }) + d, err := New(Config{ + DistributorRing: ringConfig, + }, testhelper.NewMockRing([]ring.InstanceDesc{ + {Addr: "foo"}, + }, 3), &poolFactory{func(addr string) (client.PoolClient, error) { + return newFakeIngester(t, false), nil + }}, overrides, nil, log.NewLogfmtLogger(os.Stdout), nil) + + require.NoError(t, err) + var series []*distributormodel.ProfileSeries + series, err = d.visitSampleSeries(tc.pushReq, visitSampleSeriesForSegmentWriter) + assert.Equal(t, tc.expectBytesDropped, float64(tc.pushReq.DiscardedBytesRelabeling)) + assert.Equal(t, tc.expectProfilesDropped, float64(tc.pushReq.DiscardedProfilesRelabeling)) + + if tc.expectError != nil { + assert.Error(t, err) + assert.Equal(t, tc.expectError.Error(), err.Error()) + return + } else { + assert.NoError(t, err) + } + + require.Len(t, series, len(tc.expectedSeries)) for i, actualSeries := range series { - expectedSeries := tc.series[i] + expectedSeries := tc.expectedSeries[i] assert.Equal(t, expectedSeries.Labels, actualSeries.Labels) - require.Len(t, actualSeries.Samples, len(expectedSeries.Samples)) - for j, actualProfile := range actualSeries.Samples { - expectedProfile := expectedSeries.Samples[j] - assert.Equal(t, expectedProfile.Profile.Sample, actualProfile.Profile.Sample) - } + expectedProfile := expectedSeries.Profile + assert.Equal(t, expectedProfile.Sample, actualSeries.Profile.Sample) } }) } @@ -679,7 +1832,7 @@ func TestBadPushRequest(t *testing.T) { {Addr: "foo"}, }, 3), &poolFactory{f: func(addr string) (client.PoolClient, error) { return ing, nil - }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout)) + }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout), nil) require.NoError(t, err) mux.Handle(pushv1connect.NewPusherServiceHandler(d, handlerOptions...)) @@ -759,6 +1912,7 @@ func TestPush_ShuffleSharding(t *testing.T) { overrides, nil, log.NewLogfmtLogger(os.Stdout), + nil, ) require.NoError(t, err) @@ -772,10 +1926,12 @@ func TestPush_ShuffleSharding(t *testing.T) { // Empty profiles are discarded before sending to ingesters. var buf bytes.Buffer _, err = pprof2.RawFromProto(&profilev1.Profile{ + SampleType: []*profilev1.ValueType{{}}, Sample: []*profilev1.Sample{{ LocationId: []uint64{1}, Value: []int64{1}, }}, + StringTable: []string{""}, }).WriteTo(&buf) require.NoError(t, err) profileBytes := buf.Bytes() @@ -857,9 +2013,19 @@ func TestPush_Aggregation(t *testing.T) { l.DistributorAggregationPeriod = model.Duration(time.Second) l.DistributorAggregationWindow = model.Duration(time.Second) l.MaxSessionsPerSeries = maxSessions + l.IngestionLimit = &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: time.Now().Unix(), + LimitReached: true, + Sampling: ingestlimits.SamplingConfig{ + NumRequests: 100, + Period: time.Minute, + }, + } tenantLimits["user-1"] = l }), - nil, log.NewLogfmtLogger(os.Stdout), + nil, log.NewLogfmtLogger(os.Stdout), nil, ) require.NoError(t, err) ctx := tenant.InjectTenantID(context.Background(), "user-1") @@ -876,7 +2042,7 @@ func TestPush_Aggregation(t *testing.T) { go func() { defer wg.Done() for j := 0; j < requests; j++ { - _, err := d.PushParsed(ctx, &distributormodel.PushRequest{ + err := d.PushBatch(ctx, &distributormodel.PushRequest{ Series: []*distributormodel.ProfileSeries{ { Labels: []*typesv1.LabelPair{ @@ -888,12 +2054,9 @@ func TestPush_Aggregation(t *testing.T) { Value: phlaremodel.SessionID(i*j + i).String(), }, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: &pprof2.Profile{ - Profile: testProfile(0), - }, - }, + + Profile: &pprof2.Profile{ + Profile: testProfile(0), }, }, }, @@ -910,6 +2073,16 @@ func TestPush_Aggregation(t *testing.T) { sessions := make(map[string]struct{}) assert.GreaterOrEqual(t, len(ingesterClient.requests), 20) assert.Less(t, len(ingesterClient.requests), 100) + + // Verify that throttled requests have annotations + for i, req := range ingesterClient.requests { + for _, series := range req.Series { + require.Lenf(t, series.Annotations, 1, "failed request %d", i) + assert.Equal(t, annotation.ProfileAnnotationKeyThrottled, series.Annotations[0].Key) + assert.Contains(t, series.Annotations[0].Value, "\"periodLimitMb\":128") + } + } + for _, r := range ingesterClient.requests { for _, s := range r.Series { sessionID := phlaremodel.Labels(s.Labels).Get(phlaremodel.LabelNameSessionID) @@ -927,6 +2100,61 @@ func TestPush_Aggregation(t *testing.T) { assert.Equal(t, len(sessions), maxSessions) } +func TestPushBatch_SeriesHistogram(t *testing.T) { + reg := prometheus.NewRegistry() + ing := newFakeIngester(t, false) + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + tenantLimits["user-1"] = validation.MockDefaultLimits() + }) + d, err := New( + Config{DistributorRing: ringConfig}, + testhelper.NewMockRing([]ring.InstanceDesc{{Addr: "foo"}}, 3), + &poolFactory{func(addr string) (client.PoolClient, error) { return ing, nil }}, + overrides, + reg, + log.NewLogfmtLogger(os.Stdout), + nil, + ) + require.NoError(t, err) + + ctx := tenant.InjectTenantID(context.Background(), "user-1") + + // makeRequest builds a push request carrying the given number of series. + makeRequest := func(series int) *distributormodel.PushRequest { + req := &distributormodel.PushRequest{RawProfileType: distributormodel.RawProfileTypePPROF} + for i := 0; i < series; i++ { + req.Series = append(req.Series, &distributormodel.ProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: "cluster", Value: "us-central1"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc"}, + {Name: "__name__", Value: "cpu"}, + {Name: "series", Value: strconv.Itoa(i)}, + }, + Profile: &pprof2.Profile{Profile: testProfile(0)}, + }) + } + return req + } + + // Two non-empty calls: the histogram observes N per call, so sum = 3 + 1 + // and count = 2 (one observation per PushBatch call). + require.NoError(t, d.PushBatch(ctx, makeRequest(3))) + require.NoError(t, d.PushBatch(ctx, makeRequest(1))) + + // An empty request returns before the observation, so it is not counted. + require.Error(t, d.PushBatch(ctx, makeRequest(0))) + + bs, err := testutil.CollectAndFormat(reg, expfmt.TypeTextPlain, "pyroscope_distributor_push_batch_series") + require.NoError(t, err) + + got := regexp.MustCompile(`pyroscope_distributor_push_batch_series_(sum|count).*`). + FindAllString(string(bs), -1) + assert.Equal(t, []string{ + `pyroscope_distributor_push_batch_series_sum{tenant="user-1"} 4`, + `pyroscope_distributor_push_batch_series_count{tenant="user-1"} 2`, + }, got) +} + func testProfile(t int64) *profilev1.Profile { return &profilev1.Profile{ SampleType: []*profilev1.ValueType{ @@ -1035,60 +2263,52 @@ func TestInjectMappingVersions(t *testing.T) { in := []*distributormodel.ProfileSeries{ { Labels: []*typesv1.LabelPair{}, - Samples: []*distributormodel.ProfileSample{ - { - Profile: &pprof2.Profile{ - Profile: testProfile(1), - }, - }, + + Profile: &pprof2.Profile{ + Profile: testProfile(1), }, }, { Labels: []*typesv1.LabelPair{ {Name: phlaremodel.LabelNameServiceRepository, Value: "grafana/pyroscope"}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: &pprof2.Profile{ - Profile: testProfile(2), - }, - }, + + Profile: &pprof2.Profile{ + Profile: testProfile(2), }, }, { Labels: []*typesv1.LabelPair{ {Name: phlaremodel.LabelNameServiceRepository, Value: "grafana/pyroscope"}, {Name: phlaremodel.LabelNameServiceGitRef, Value: "foobar"}, + {Name: phlaremodel.LabelNameServiceRootPath, Value: "some-path"}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: &pprof2.Profile{ - Profile: testProfile(2), - }, - }, + + Profile: &pprof2.Profile{ + Profile: testProfile(2), }, }, { Labels: []*typesv1.LabelPair{ {Name: phlaremodel.LabelNameServiceRepository, Value: "grafana/pyroscope"}, {Name: phlaremodel.LabelNameServiceGitRef, Value: "foobar"}, + {Name: phlaremodel.LabelNameServiceRootPath, Value: "some-path"}, }, - Samples: []*distributormodel.ProfileSample{ - { - Profile: &pprof2.Profile{ - Profile: alreadyVersionned, - }, - }, + + Profile: &pprof2.Profile{ + Profile: alreadyVersionned, }, }, } + for _, s := range in { + err := injectMappingVersions(s) + require.NoError(t, err) + } - err := injectMappingVersions(in) - require.NoError(t, err) - require.Equal(t, "", in[0].Samples[0].Profile.StringTable[in[0].Samples[0].Profile.Mapping[0].BuildId]) - require.Equal(t, `{"repository":"grafana/pyroscope"}`, in[1].Samples[0].Profile.StringTable[in[1].Samples[0].Profile.Mapping[0].BuildId]) - require.Equal(t, `{"repository":"grafana/pyroscope","git_ref":"foobar"}`, in[2].Samples[0].Profile.StringTable[in[2].Samples[0].Profile.Mapping[0].BuildId]) - require.Equal(t, `{"repository":"grafana/pyroscope","git_ref":"foobar","build_id":"foo"}`, in[3].Samples[0].Profile.StringTable[in[3].Samples[0].Profile.Mapping[0].BuildId]) + require.Equal(t, "", in[0].Profile.StringTable[in[0].Profile.Mapping[0].BuildId]) + require.Equal(t, `{"repository":"grafana/pyroscope"}`, in[1].Profile.StringTable[in[1].Profile.Mapping[0].BuildId]) + require.Equal(t, `{"repository":"grafana/pyroscope","git_ref":"foobar","root_path":"some-path"}`, in[2].Profile.StringTable[in[2].Profile.Mapping[0].BuildId]) + require.Equal(t, `{"repository":"grafana/pyroscope","git_ref":"foobar","build_id":"foo","root_path":"some-path"}`, in[3].Profile.StringTable[in[3].Profile.Mapping[0].BuildId]) } func uncompressedProfileSize(t *testing.T, req *pushv1.PushRequest) int { @@ -1120,3 +2340,527 @@ func expectMetricsChange(t *testing.T, m1, m2, expectedChange map[prometheus.Col assert.Equal(t, expectedDelta, delta, "metric %s", counter) } } + +func TestPush_LabelRewrites(t *testing.T) { + ing := newFakeIngester(t, false) + d, err := New(Config{ + DistributorRing: ringConfig, + }, testhelper.NewMockRing([]ring.InstanceDesc{ + {Addr: "mock"}, + {Addr: "mock"}, + {Addr: "mock"}, + }, 3), &poolFactory{f: func(addr string) (client.PoolClient, error) { + return ing, nil + }}, newOverrides(t), nil, log.NewLogfmtLogger(os.Stdout), nil) + require.NoError(t, err) + + ctx := tenant.InjectTenantID(context.Background(), "user-1") + + for idx, tc := range []struct { + name string + series []*typesv1.LabelPair + expectedSeries string + }{ + { + name: "empty series", + series: []*typesv1.LabelPair{}, + expectedSeries: `{__name__="process_cpu", service_name="unknown_service"}`, + }, + { + name: "series with service_name labels", + series: []*typesv1.LabelPair{ + {Name: "service_name", Value: "my-service"}, + {Name: "cloud_region", Value: "my-region"}, + }, + expectedSeries: `{__name__="process_cpu", cloud_region="my-region", service_name="my-service"}`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ing.mtx.Lock() + ing.requests = ing.requests[:0] + ing.mtx.Unlock() + + p := pproftesthelper.NewProfileBuilderWithLabels(1000*int64(idx), tc.series).CPUProfile() + p.ForStacktraceString("world", "hello").AddSamples(1) + + data, err := p.MarshalVT() + require.NoError(t, err) + + _, err = d.Push(ctx, connect.NewRequest(&pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{ + { + Labels: p.Labels, + Samples: []*pushv1.RawSample{ + {RawProfile: data}, + }, + }, + }, + })) + require.NoError(t, err) + + ing.mtx.Lock() + require.Len(t, ing.requests, 1) + require.Greater(t, len(ing.requests[0].Series), 1) + actualSeries := phlaremodel.LabelPairsString(ing.requests[0].Series[0].Labels) + assert.Equal(t, tc.expectedSeries, actualSeries) + ing.mtx.Unlock() + }) + } +} + +func TestDistributor_shouldSample(t *testing.T) { + tests := []struct { + name string + groups []validation.UsageGroupMatchName + samplingConfig *sampling.Config + expected bool + expectedMatch *sampling.Source + }{ + { + name: "no sampling config - should accept", + groups: []validation.UsageGroupMatchName{}, + expected: true, + }, + { + name: "no matching groups - should accept", + groups: []validation.UsageGroupMatchName{{ConfiguredName: "group1", ResolvedName: "group1"}}, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "group2": {Probability: 0.5}, + }, + }, + expected: true, + }, + { + name: "matching group with 1.0 probability - should accept", + groups: []validation.UsageGroupMatchName{{ConfiguredName: "group1", ResolvedName: "group1"}}, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "group1": {Probability: 1.0}, + }, + }, + expected: true, + expectedMatch: &sampling.Source{ + UsageGroup: "group1", + Probability: 1.0, + }, + }, + { + name: "matching group with dynamic name - should accept", + groups: []validation.UsageGroupMatchName{{ConfiguredName: "configured-name", ResolvedName: "resolved-name"}}, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "configured-name": {Probability: 1.0}, + }, + }, + expected: true, + expectedMatch: &sampling.Source{ + UsageGroup: "resolved-name", + Probability: 1.0, + }, + }, + { + name: "matching group with 0.0 probability - should reject", + groups: []validation.UsageGroupMatchName{{ConfiguredName: "group1", ResolvedName: "group1"}}, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "group1": {Probability: 0.0}, + }, + }, + expected: false, + expectedMatch: &sampling.Source{ + UsageGroup: "group1", + Probability: 0.0, + }, + }, + { + name: "multiple matching groups - should use minimum probability", + groups: []validation.UsageGroupMatchName{ + {ConfiguredName: "group1", ResolvedName: "group1"}, + {ConfiguredName: "group2", ResolvedName: "group2"}, + }, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "group1": {Probability: 1.0}, + "group2": {Probability: 0.0}, + }, + }, + expected: false, + expectedMatch: &sampling.Source{ + UsageGroup: "group2", + Probability: 0.0, + }, + }, + { + name: "multiple matching groups - should prioritize specific group", + groups: []validation.UsageGroupMatchName{ + {ConfiguredName: "${labels.service_name}", ResolvedName: "test_service"}, + {ConfiguredName: "test_service", ResolvedName: "test_service"}, + }, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "${labels.service_name}": {Probability: 1.0}, + "test_service": {Probability: 0.0}, + }, + }, + expected: false, + expectedMatch: &sampling.Source{ + UsageGroup: "test_service", + Probability: 0.0, + }, + }, + { + name: "multiple matching groups - should prioritize specific group (reversed order)", + groups: []validation.UsageGroupMatchName{ + {ConfiguredName: "test_service", ResolvedName: "test_service"}, + {ConfiguredName: "${labels.service_name}", ResolvedName: "test_service"}, + }, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "${labels.service_name}": {Probability: 1.0}, + "test_service": {Probability: 0.0}, + }, + }, + expected: false, + expectedMatch: &sampling.Source{ + UsageGroup: "test_service", + Probability: 0.0, + }, + }, + { + name: "single usage group, multiple sampling rules - should prioritize specific rule", + groups: []validation.UsageGroupMatchName{ + {ConfiguredName: "${labels.service_name}", ResolvedName: "test_service"}, + }, + samplingConfig: &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "${labels.service_name}": {Probability: 1.0}, + "test_service": {Probability: 0.0}, + }, + }, + expected: false, + expectedMatch: &sampling.Source{ + UsageGroup: "test_service", + Probability: 0.0, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.DistributorSampling = tt.samplingConfig + tenantLimits["test-tenant"] = l + }) + d := &Distributor{ + limits: overrides, + } + + sample, match := d.shouldSample("test-tenant", tt.groups) + assert.Equal(t, tt.expected, sample) + assert.Equal(t, tt.expectedMatch, match) + }) + } +} + +func TestDistributor_shouldSample_Probability(t *testing.T) { + tests := []struct { + name string + probability float64 + usageGroups []validation.UsageGroupMatchName + }{ + { + name: "30% sampling rate", + probability: 0.3, + usageGroups: []validation.UsageGroupMatchName{{ConfiguredName: "${labels.service_name}", ResolvedName: "test-service-1"}}, + }, + { + name: "70% sampling rate", + probability: 0.7, + usageGroups: []validation.UsageGroupMatchName{{ConfiguredName: "${labels.service_name}", ResolvedName: "test-service-1"}}, + }, + { + name: "10% sampling rate", + probability: 0.1, + usageGroups: []validation.UsageGroupMatchName{{ConfiguredName: "${labels.service_name}", ResolvedName: "test-service-1"}}, + }, + { + name: "0% sampling rate for the baseline group", + probability: 0.0, + usageGroups: []validation.UsageGroupMatchName{{ConfiguredName: "${labels.service_name}", ResolvedName: "test-service-2"}}, + }, + } + + const iterations = 10000 + tenantID := "test-tenant" + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + samplingConfig := &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "${labels.service_name}": {Probability: 0.0}, // we drop all profiles by default + "test-service-1": {Probability: tt.probability}, + }, + } + + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.DistributorSampling = samplingConfig + tenantLimits[tenantID] = l + }) + d := &Distributor{ + limits: overrides, + } + + accepted := 0 + for i := 0; i < iterations; i++ { + if s, _ := d.shouldSample(tenantID, tt.usageGroups); s { + accepted++ + } + } + + actualRate := float64(accepted) / float64(iterations) + expectedRate := tt.probability + deviation := math.Abs(actualRate - expectedRate) + + tolerance := 0.05 + assert.True(t, deviation <= tolerance, + "Sampling rate %.3f is outside tolerance %.3f of expected rate %.3f (deviation: %.3f)", + actualRate, tolerance, expectedRate, deviation) + + t.Logf("Expected: %.3f, Actual: %.3f, Deviation: %.3f", expectedRate, actualRate, deviation) + }) + } +} + +// stripTestProfile returns a deterministic profile without sample labels, +// so it maps to a single series. The "app.py" filename makes language +// detection resolve to "python" while the symbols are present. +func stripTestProfile() *profilev1.Profile { + return &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + {Type: 3, Unit: 4}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1, 2}, Value: []int64{10, 1000}}, + {LocationId: []uint64{2}, Value: []int64{5, 500}}, + // Dropped by Normalize (negative value): must not count towards totals. + {LocationId: []uint64{1}, Value: []int64{-1, 100}}, + // Dropped by sanitization (value length mismatch): must not count either. + {LocationId: []uint64{1}, Value: []int64{7}}, + }, + Mapping: []*profilev1.Mapping{{Id: 1, HasFunctions: true}}, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2}}}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 5, SystemName: 5, Filename: 6}, + {Id: 2, Name: 7, SystemName: 7, Filename: 8}, + }, + StringTable: []string{ + "", + "samples", + "count", + "cpu", + "nanoseconds", + "func-a", + "app.py", + "func-b", + "path-b", + }, + TimeNanos: 1000000000, + DurationNanos: 10000000000, + PeriodType: &profilev1.ValueType{Type: 3, Unit: 4}, + Period: 10000000, + } +} + +// strippedTestProfile is what stripTestProfile must be reduced to when it +// is sampled out: a single sample with the totals and a string table that +// holds only the sample type units. +func strippedTestProfile() *profilev1.Profile { + return &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + {Type: 3, Unit: 4}, + }, + Sample: []*profilev1.Sample{{Value: []int64{15, 1500}}}, + StringTable: []string{"", "samples", "count", "cpu", "nanoseconds"}, + TimeNanos: 1000000000, + DurationNanos: 10000000000, + PeriodType: &profilev1.ValueType{Type: 3, Unit: 4}, + Period: 10000000, + } +} + +func TestStripProfileToTotals(t *testing.T) { + p := stripTestProfile() + stripProfileToTotals(p) + + want := strippedTestProfile() + require.Len(t, p.Sample, 1) + assert.Equal(t, want.Sample[0].Value, p.Sample[0].Value) + assert.Empty(t, p.Sample[0].LocationId) + assert.Empty(t, p.Sample[0].Label) + assert.Empty(t, p.Location) + assert.Empty(t, p.Function) + assert.Empty(t, p.Mapping) + assert.Equal(t, want.StringTable, p.StringTable) + assert.Equal(t, want.SampleType, p.SampleType) + assert.Equal(t, want.PeriodType, p.PeriodType) + assert.Equal(t, want.SizeVT(), p.SizeVT()) +} + +func TestStripProfileToTotals_NoSamples(t *testing.T) { + p := stripTestProfile() + p.Sample = nil + stripProfileToTotals(p) + assert.Empty(t, p.Sample) + assert.Empty(t, p.Location) +} + +func newStripTestDistributor(t *testing.T, keepStrippedProfiles bool) (*Distributor, *fakeIngester) { + t.Helper() + overrides := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + usageGroups, err := validation.NewUsageGroupConfig(map[string]string{ + "svc": `{service_name="svc"}`, + }) + require.NoError(t, err) + l.DistributorUsageGroups = usageGroups + l.DistributorSampling = &sampling.Config{ + UsageGroups: map[string]sampling.UsageGroupSampling{ + "svc": {Probability: 0}, + }, + } + l.KeepStrippedProfiles = keepStrippedProfiles + tenantLimits["user-1"] = l + }) + ing := newFakeIngester(t, false) + d, err := New(Config{ + DistributorRing: ringConfig, + }, testhelper.NewMockRing([]ring.InstanceDesc{ + {Addr: "foo"}, + }, 3), &poolFactory{f: func(addr string) (client.PoolClient, error) { + return ing, nil + }}, overrides, nil, log.NewLogfmtLogger(os.Stdout), nil) + require.NoError(t, err) + return d, ing +} + +func TestPushSeries_KeepStrippedProfiles(t *testing.T) { + d, ing := newStripTestDistributor(t, true) + + prof := stripTestProfile() + originalSize := prof.SizeVT() + keptSize := strippedTestProfile().SizeVT() + + req := &distributormodel.ProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc"}, + }, + Profile: pprof2.RawFromProto(prof), + } + + expectedMetricDelta := map[prometheus.Collector]float64{ + validation.DiscardedBytes.WithLabelValues(string(validation.SkippedBySamplingRules), "user-1"): float64(originalSize - keptSize), + validation.DiscardedProfiles.WithLabelValues(string(validation.SkippedBySamplingRules), "user-1"): 1, + } + before := metricsDump(expectedMetricDelta) + + err := d.pushSeries(context.Background(), req, distributormodel.RawProfileTypePPROF, "user-1", 0) + require.NoError(t, err) + + // The stripped part is discarded, the kept part continues as a regular profile. + expectMetricsChange(t, before, metricsDump(expectedMetricDelta), expectedMetricDelta) + + // Language detection ran before the symbols were stripped. + assert.Equal(t, "python", req.Language) + + ing.mtx.Lock() + defer ing.mtx.Unlock() + require.Len(t, ing.requests, 1) + require.NotEmpty(t, ing.requests[0].Series) + series := ing.requests[0].Series[0] + assert.Equal(t, "true", phlaremodel.Labels(series.Labels).Get(phlaremodel.LabelNameSampled)) + + received, err := pprof2.RawFromBytes(series.Samples[0].RawProfile) + require.NoError(t, err) + want := strippedTestProfile() + require.Len(t, received.Sample, 1) + assert.Equal(t, want.Sample[0].Value, received.Sample[0].Value) + assert.Empty(t, received.Sample[0].LocationId) + assert.Empty(t, received.Location) + assert.Empty(t, received.Function) + assert.Empty(t, received.Mapping) + assert.Equal(t, want.StringTable, received.StringTable) + assert.Equal(t, keptSize, received.SizeVT()) +} + +func TestPushSeries_DropSampledOutProfiles(t *testing.T) { + d, ing := newStripTestDistributor(t, false) + + prof := stripTestProfile() + labels := []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "svc"}, + } + req := &distributormodel.ProfileSeries{ + Labels: labels, + Profile: pprof2.RawFromProto(prof), + } + + expectedMetricDelta := map[prometheus.Collector]float64{ + validation.DiscardedBytes.WithLabelValues(string(validation.SkippedBySamplingRules), "user-1"): float64(labelsSize(labels) + int64(prof.SizeVT())), + validation.DiscardedProfiles.WithLabelValues(string(validation.SkippedBySamplingRules), "user-1"): 1, + } + before := metricsDump(expectedMetricDelta) + + err := d.pushSeries(context.Background(), req, distributormodel.RawProfileTypePPROF, "user-1", 0) + require.NoError(t, err) + + expectMetricsChange(t, before, metricsDump(expectedMetricDelta), expectedMetricDelta) + + ing.mtx.Lock() + defer ing.mtx.Unlock() + assert.Empty(t, ing.requests) +} + +func TestStripProfileToTotals_SampleLabels(t *testing.T) { + p := stripTestProfile() + // Indices into the extended string table: span_id=9, abc=10, def=11. + p.StringTable = append(p.StringTable, "span_id", "abc", "def") + p.Sample = []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{1, 10}, Label: []*profilev1.Label{{Key: 9, Str: 10}}}, + {LocationId: []uint64{2}, Value: []int64{2, 20}, Label: []*profilev1.Label{{Key: 9, Str: 10}}}, + {LocationId: []uint64{1}, Value: []int64{4, 40}, Label: []*profilev1.Label{{Key: 9, Str: 11}}}, + {LocationId: []uint64{2}, Value: []int64{8, 80}}, + // Numeric labels are dropped (as Normalize would do), so this + // sample must aggregate with the unlabeled one. + {LocationId: []uint64{1}, Value: []int64{16, 160}, Label: []*profilev1.Label{{Key: 9, Num: 42}}}, + } + + stripProfileToTotals(p) + + require.Len(t, p.Sample, 3) + assert.Equal(t, []int64{24, 240}, p.Sample[0].Value) + assert.Empty(t, p.Sample[0].Label) + assert.Equal(t, []int64{3, 30}, p.Sample[1].Value) + require.Len(t, p.Sample[1].Label, 1) + assert.Equal(t, "span_id", p.StringTable[p.Sample[1].Label[0].Key]) + assert.Equal(t, "abc", p.StringTable[p.Sample[1].Label[0].Str]) + assert.Equal(t, []int64{4, 40}, p.Sample[2].Value) + require.Len(t, p.Sample[2].Label, 1) + assert.Equal(t, "def", p.StringTable[p.Sample[2].Label[0].Str]) + for _, s := range p.Sample { + assert.Empty(t, s.LocationId) + } + assert.Empty(t, p.Location) + assert.Empty(t, p.Function) + assert.Empty(t, p.Mapping) + assert.Equal(t, []string{"", "samples", "count", "cpu", "nanoseconds", "span_id", "abc", "def"}, p.StringTable) +} diff --git a/pkg/distributor/ingestlimits/config.go b/pkg/distributor/ingestlimits/config.go new file mode 100644 index 0000000000..6e251e15b6 --- /dev/null +++ b/pkg/distributor/ingestlimits/config.go @@ -0,0 +1,32 @@ +package ingestlimits + +import "time" + +type Config struct { + // PeriodType provides the limit period / interval (e.g., "hour"). Used in error messages only. + PeriodType string `yaml:"period_type" json:"period_type"` + // PeriodLimitMb provides the limit that is being set in MB. Used in error messages only. + PeriodLimitMb int `yaml:"period_limit_mb" json:"period_limit_mb"` + // LimitResetTime provides the time (Unix seconds) when the limit will reset. Used in error messages only. + LimitResetTime int64 `yaml:"limit_reset_time" json:"limit_reset_time"` + // LimitReached instructs distributors to allow or reject profiles. + LimitReached bool `yaml:"limit_reached" json:"limit_reached"` + // Sampling controls the sampling parameters when the limit is reached. + Sampling SamplingConfig `yaml:"sampling" json:"sampling"` + // UsageGroups controls ingestion for pre-configured usage groups. + UsageGroups map[string]UsageGroup `yaml:"usage_groups" json:"usage_groups"` +} + +// SamplingConfig describes the params of a simple probabilistic sampling mechanism. +// +// Distributors should allow up to NumRequests requests through and then apply a cooldown (Period) after which +// more requests can be let through. +type SamplingConfig struct { + NumRequests int `yaml:"num_requests" json:"num_requests"` + Period time.Duration `yaml:"period" json:"period"` +} + +type UsageGroup struct { + PeriodLimitMb int `yaml:"period_limit_mb" json:"period_limit_mb"` + LimitReached bool `yaml:"limit_reached" json:"limit_reached"` +} diff --git a/pkg/distributor/ingestlimits/sampler.go b/pkg/distributor/ingestlimits/sampler.go new file mode 100644 index 0000000000..9a2d0106a4 --- /dev/null +++ b/pkg/distributor/ingestlimits/sampler.go @@ -0,0 +1,142 @@ +package ingestlimits + +import ( + "context" + "math/rand" + "sync" + "time" + + "github.com/grafana/dskit/services" +) + +type tenantTracker struct { + mu sync.Mutex + lastRequestTime time.Time + remainingRequests int +} + +// Sampler provides a very simple time-based probabilistic sampling, +// intended to be used when a tenant limit has been reached. +// +// The sampler will allow a number of requests in a time interval. +// Once the interval is over, the number of allowed requests resets. +// +// We introduce a probability function for a request to be allowed defined as 1 / num_replicas, +// to account for the size of the cluster and because tracking is done in memory. +type Sampler struct { + *services.BasicService + + mu sync.RWMutex + tenants map[string]*tenantTracker + + // needed for adjusting the probability function with the number of replicas + instanceCountProvider InstanceCountProvider + + // cleanup of the tenants map to prevent build-up + cleanupInterval time.Duration + maxAge time.Duration + closeOnce sync.Once + stop chan struct{} + done chan struct{} +} + +type InstanceCountProvider interface { + InstancesCount() int +} + +func NewSampler(instanceCount InstanceCountProvider) *Sampler { + s := &Sampler{ + tenants: make(map[string]*tenantTracker), + instanceCountProvider: instanceCount, + cleanupInterval: 1 * time.Hour, + maxAge: 24 * time.Hour, + stop: make(chan struct{}), + done: make(chan struct{}), + } + s.BasicService = services.NewBasicService( + s.starting, + s.running, + s.stopping, + ) + + return s +} + +func (s *Sampler) starting(_ context.Context) error { return nil } + +func (s *Sampler) stopping(_ error) error { + s.closeOnce.Do(func() { + close(s.stop) + <-s.done + }) + return nil +} + +func (s *Sampler) running(ctx context.Context) error { + t := time.NewTicker(s.cleanupInterval) + defer func() { + t.Stop() + close(s.done) + }() + for { + select { + case <-t.C: + s.removeStaleTenants() + case <-s.stop: + return nil + case <-ctx.Done(): + return nil + } + } +} + +func (s *Sampler) AllowRequest(tenantID string, config SamplingConfig) bool { + s.mu.Lock() + tracker, exists := s.tenants[tenantID] + if !exists { + tracker = &tenantTracker{ + lastRequestTime: time.Now(), + remainingRequests: config.NumRequests, + } + s.tenants[tenantID] = tracker + } + s.mu.Unlock() + + return tracker.AllowRequest(s.instanceCountProvider.InstancesCount(), config.Period, config.NumRequests) +} + +func (b *tenantTracker) AllowRequest(replicaCount int, windowDuration time.Duration, maxRequests int) bool { + b.mu.Lock() + defer b.mu.Unlock() + + now := time.Now() + + // reset tracking data if enough time has passed + if now.Sub(b.lastRequestTime) >= windowDuration { + b.lastRequestTime = now + b.remainingRequests = maxRequests + } + + if b.remainingRequests > 0 { + // random chance of allowing request, adjusting for the number of replicas + shouldAllow := rand.Float64() < float64(maxRequests)/float64(replicaCount) + + if shouldAllow { + b.remainingRequests-- + return true + } + } + + return false +} + +func (s *Sampler) removeStaleTenants() { + s.mu.Lock() + cutoff := time.Now().Add(-s.maxAge) + for tenantID, tracker := range s.tenants { + if tracker.lastRequestTime.Before(cutoff) { + delete(s.tenants, tenantID) + } + } + s.mu.Unlock() +} diff --git a/pkg/distributor/ingestlimits/sampler_test.go b/pkg/distributor/ingestlimits/sampler_test.go new file mode 100644 index 0000000000..157fbe39da --- /dev/null +++ b/pkg/distributor/ingestlimits/sampler_test.go @@ -0,0 +1,115 @@ +package ingestlimits + +import ( + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +// Mock ring for testing +type mockRing struct { + instanceCount int +} + +func (m *mockRing) InstancesCount() int { + return m.instanceCount +} + +func TestAllowRequest(t *testing.T) { + sampler := NewSampler(&mockRing{instanceCount: 1}) + + config := SamplingConfig{ + Period: 1 * time.Second, + NumRequests: 1, + } + + tenantID := "test-tenant" + allowed := sampler.AllowRequest(tenantID, config) + assert.True(t, allowed, "this request is brand new and should be allowed") + + allowed = sampler.AllowRequest(tenantID, config) + assert.Falsef(t, allowed, "this request should be within a second of the first and not be allowed") +} + +func TestTenantTrackerAllowRequest(t *testing.T) { + testCases := []struct { + name string + replicaCount int + windowDuration time.Duration + maxRequests int + requestCount int + expectAllowed int + }{ + { + name: "Within limit", + replicaCount: 2, + windowDuration: 5 * time.Second, + maxRequests: 5, + requestCount: 3, + expectAllowed: 3, + }, + { + name: "Exceed limit", + replicaCount: 2, + windowDuration: 5 * time.Second, + maxRequests: 3, + requestCount: 5, + expectAllowed: 3, + }, + { + name: "Random probability", + replicaCount: 100, + windowDuration: 5 * time.Second, + maxRequests: 5, + requestCount: 100, + expectAllowed: 5, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tracker := &tenantTracker{ + lastRequestTime: time.Now(), + remainingRequests: tc.maxRequests, + } + + allowedCnt := 0 + for i := 0; i < tc.requestCount; i++ { + if tracker.AllowRequest(tc.replicaCount, tc.windowDuration, tc.maxRequests) { + allowedCnt++ + } + } + assert.LessOrEqualf(t, allowedCnt, tc.expectAllowed, "request %d should match expected") + }) + } +} + +func TestConcurrentAccess(t *testing.T) { + sampler := NewSampler(&mockRing{instanceCount: 2}) + + config := SamplingConfig{ + Period: 5 * time.Second, + NumRequests: 10, + } + + var wg sync.WaitGroup + allowedCount := 0 + mu := sync.Mutex{} + + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + defer wg.Done() + if sampler.AllowRequest("concurrent-tenant", config) { + mu.Lock() + allowedCount++ + mu.Unlock() + } + }() + } + + wg.Wait() + assert.LessOrEqual(t, allowedCount, 10, "Should not exceed max requests") +} diff --git a/pkg/distributor/instance_count_test.go b/pkg/distributor/instance_count_test.go index 7cb2673337..2d51909d76 100644 --- a/pkg/distributor/instance_count_test.go +++ b/pkg/distributor/instance_count_test.go @@ -29,7 +29,7 @@ func (n nopDelegate) OnRingInstanceHeartbeat(lifecycler *ring.BasicLifecycler, r func TestHealthyInstanceDelegate_OnRingInstanceHeartbeat(t *testing.T) { // addInstance registers a new instance with the given ring and sets its last heartbeat timestamp addInstance := func(desc *ring.Desc, id string, state ring.InstanceState, timestamp int64) { - instance := desc.AddIngester(id, "127.0.0.1", "", []uint32{1}, state, time.Now()) + instance := desc.AddIngester(id, "127.0.0.1", "", []uint32{1}, state, time.Now(), false, time.Now(), ring.InstanceVersions{}) instance.Timestamp = timestamp desc.Ingesters[id] = instance } @@ -72,14 +72,14 @@ func TestHealthyInstanceDelegate_OnRingInstanceHeartbeat(t *testing.T) { expectedCount: 2, }, - "some instances healthy but timeout disabled all instances active": { + "all instances healthy with long timeout all instances active": { ringSetup: func(desc *ring.Desc) { now := time.Now() addInstance(desc, "distributor-1", ring.ACTIVE, now.Unix()) addInstance(desc, "distributor-2", ring.ACTIVE, now.Unix()) addInstance(desc, "distributor-3", ring.ACTIVE, now.Add(-5*time.Minute).Unix()) }, - heartbeatTimeout: 0, + heartbeatTimeout: 10 * time.Minute, expectedCount: 3, }, } diff --git a/pkg/distributor/metrics.go b/pkg/distributor/metrics.go index 9f3b2b03f6..acaf61f977 100644 --- a/pkg/distributor/metrics.go +++ b/pkg/distributor/metrics.go @@ -1,6 +1,9 @@ package distributor import ( + "fmt" + "time" + "github.com/prometheus/client_golang/prometheus" ) @@ -10,13 +13,34 @@ const ( bucketsCount = 30 ) +type ReceiveStage string + +const ( + // StageReceived is the earliest stage and as soon as we begin processing a profile, + // before any rate-limit/sampling checks + StageReceived ReceiveStage = "received" + // StageSampled is recorded after the profile is accepted by rate-limit/sampling checks + StageSampled ReceiveStage = "sampled" + // StageNormalized is recorded after the profile is validated and normalized. + StageNormalized ReceiveStage = "normalized" +) + +var allStages = fmt.Sprintf("%s, %s, %s", + StageReceived, + StageSampled, + StageNormalized, +) + type metrics struct { - receivedCompressedBytes *prometheus.HistogramVec - receivedDecompressedBytes *prometheus.HistogramVec - receivedSamples *prometheus.HistogramVec - receivedSamplesBytes *prometheus.HistogramVec - receivedSymbolsBytes *prometheus.HistogramVec - replicationFactor prometheus.Gauge + receivedCompressedBytes *prometheus.HistogramVec + receivedDecompressedBytes *prometheus.HistogramVec // deprecated TODO remove + receivedSamples *prometheus.HistogramVec + receivedSamplesBytes *prometheus.HistogramVec + receivedSymbolsBytes *prometheus.HistogramVec + replicationFactor prometheus.Gauge + receivedDecompressedBytesTotal *prometheus.HistogramVec + parseDuration *prometheus.HistogramVec + pushBatchSeries *prometheus.HistogramVec } func newMetrics(reg prometheus.Registerer) *metrics { @@ -28,10 +52,13 @@ func newMetrics(reg prometheus.Registerer) *metrics { }), receivedCompressedBytes: prometheus.NewHistogramVec( prometheus.HistogramOpts{ - Namespace: "pyroscope", - Name: "distributor_received_compressed_bytes", - Help: "The number of compressed bytes per profile received by the distributor.", - Buckets: prometheus.ExponentialBucketsRange(minBytes, maxBytes, bucketsCount), + Namespace: "pyroscope", + Name: "distributor_received_compressed_bytes", + Help: "The number of compressed bytes per profile received by the distributor.", + Buckets: prometheus.ExponentialBucketsRange(minBytes, maxBytes, bucketsCount), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"type", "tenant"}, ), @@ -39,38 +66,92 @@ func newMetrics(reg prometheus.Registerer) *metrics { prometheus.HistogramOpts{ Namespace: "pyroscope", Name: "distributor_received_decompressed_bytes", - Help: "The number of decompressed bytes per profiles received by the distributor.", - Buckets: prometheus.ExponentialBucketsRange(minBytes, maxBytes, bucketsCount), + Help: "The number of decompressed bytes per profiles received by the distributor after " + + "limits/sampling checks. distributor_received_decompressed_bytes is deprecated, use " + + "distributor_received_decompressed_bytes_total instead.", + Buckets: prometheus.ExponentialBucketsRange(minBytes, maxBytes, bucketsCount), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"type", "tenant"}, ), receivedSamples: prometheus.NewHistogramVec( prometheus.HistogramOpts{ - Namespace: "pyroscope", - Name: "distributor_received_samples", - Help: "The number of samples per profile name received by the distributor.", - Buckets: prometheus.ExponentialBucketsRange(100, 100000, 30), + Namespace: "pyroscope", + Name: "distributor_received_samples", + Help: "The number of samples per profile name received by the distributor.", + Buckets: prometheus.ExponentialBucketsRange(100, 100000, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"type", "tenant"}, ), receivedSamplesBytes: prometheus.NewHistogramVec( prometheus.HistogramOpts{ - Namespace: "pyroscope", - Name: "distributor_received_samples_bytes", - Help: "The size of samples without symbols received by the distributor.", - Buckets: prometheus.ExponentialBucketsRange(10*1024, 15*1024*1024, 30), + Namespace: "pyroscope", + Name: "distributor_received_samples_bytes", + Help: "The size of samples without symbols received by the distributor.", + Buckets: prometheus.ExponentialBucketsRange(10*1024, 15*1024*1024, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"type", "tenant"}, ), receivedSymbolsBytes: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "distributor_received_symbols_bytes", + Help: "The size of symbols received by the distributor.", + Buckets: prometheus.ExponentialBucketsRange(10*1024, 15*1024*1024, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, + []string{"type", "tenant"}, + ), + receivedDecompressedBytesTotal: prometheus.NewHistogramVec( prometheus.HistogramOpts{ Namespace: "pyroscope", - Name: "distributor_received_symbols_bytes", - Help: "The size of symbols received by the distributor.", - Buckets: prometheus.ExponentialBucketsRange(10*1024, 15*1024*1024, 30), + Name: "distributor_received_decompressed_bytes_total", + Help: "The total number of decompressed bytes per profile received by the distributor at different " + + "processing stages. Valid stages are: " + allStages, + Buckets: prometheus.ExponentialBucketsRange(minBytes, maxBytes, bucketsCount), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, + []string{ + "tenant", + "stage", + }, + ), + parseDuration: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "distributor_parse_duration_seconds", + Help: "Duration of profile parsing (JFR or pprof) per ingest request in the distributor.", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"type", "tenant"}, ), + pushBatchSeries: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "distributor_push_batch_series", + Help: "Number of series per batched push request (PushBatch call).", + Buckets: prometheus.ExponentialBuckets(1, 2, 13), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, + []string{"tenant"}, + ), } if reg != nil { reg.MustRegister( @@ -80,7 +161,14 @@ func newMetrics(reg prometheus.Registerer) *metrics { m.receivedSamplesBytes, m.receivedSymbolsBytes, m.replicationFactor, + m.receivedDecompressedBytesTotal, + m.parseDuration, + m.pushBatchSeries, ) } return m } + +func (m *metrics) observeProfileSize(tenant string, stage ReceiveStage, sz int64) { + m.receivedDecompressedBytesTotal.WithLabelValues(tenant, string(stage)).Observe(float64(sz)) +} diff --git a/pkg/distributor/model/push.go b/pkg/distributor/model/push.go index 64fb180ad3..7e49d61411 100644 --- a/pkg/distributor/model/push.go +++ b/pkg/distributor/model/push.go @@ -1,40 +1,56 @@ package model import ( + "time" + v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/distributor/annotation" + "github.com/grafana/pyroscope/v2/pkg/distributor/ingestlimits" + "github.com/grafana/pyroscope/v2/pkg/distributor/sampling" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) type RawProfileType string const RawProfileTypePPROF = RawProfileType("pprof") const RawProfileTypeJFR = RawProfileType("jfr") +const RawProfileTypeOTEL = RawProfileType("otel") type PushRequest struct { - RawProfileSize int - RawProfileType RawProfileType - Series []*ProfileSeries - TotalProfiles int64 - TotalBytesUncompressed int64 + ReceivedCompressedProfileSize int + ReceivedDecompressedProfileSize int + RawProfileType RawProfileType + ParseDuration time.Duration } -type ProfileSample struct { +// todo better name +type ProfileSeries struct { + // Caller provided, modified during processing + Labels []*v1.LabelPair Profile *pprof.Profile RawProfile []byte // may be nil if the Profile is composed not from pprof ( e.g. jfr) ID string -} -type ProfileSeries struct { - Labels []*v1.LabelPair - Samples []*ProfileSample + // todo split + // Transient state + TenantID string Language string + + Annotations []*v1.ProfileAnnotation + + // always 1 todo delete + TotalProfiles int64 + TotalBytesUncompressed int64 + + DiscardedProfilesRelabeling int64 + DiscardedBytesRelabeling int64 } -func (p *ProfileSeries) GetLanguage() string { - spyName := phlaremodel.Labels(p.Labels).Get(phlaremodel.LabelNamePyroscopeSpy) +func (req *ProfileSeries) GetLanguage() string { + spyName := phlaremodel.Labels(req.Labels).Get(phlaremodel.LabelNamePyroscopeSpy) if spyName != "" { lang := getProfileLanguageFromSpy(spyName) if lang != "" { @@ -66,3 +82,53 @@ func getProfileLanguageFromSpy(spyName string) string { return "rust" } } + +func (req *ProfileSeries) Clone() *ProfileSeries { + c := &ProfileSeries{ + TenantID: req.TenantID, + TotalBytesUncompressed: req.TotalBytesUncompressed, + Labels: phlaremodel.Labels(req.Labels).Clone(), + Profile: &pprof.Profile{Profile: req.Profile.CloneVT()}, + RawProfile: nil, + ID: req.ID, + Language: req.Language, + Annotations: req.Annotations, + } + return c +} + +func (req *ProfileSeries) MarkThrottledTenant(l *ingestlimits.Config) error { + a, err := annotation.CreateTenantAnnotation(l) + if err != nil { + return err + } + req.Annotations = append(req.Annotations, &v1.ProfileAnnotation{ + Key: annotation.ProfileAnnotationKeyThrottled, + Value: string(a), + }) + return nil +} + +func (req *ProfileSeries) MarkThrottledUsageGroup(l *ingestlimits.Config, usageGroup string) error { + a, err := annotation.CreateUsageGroupAnnotation(l, usageGroup) + if err != nil { + return err + } + req.Annotations = append(req.Annotations, &v1.ProfileAnnotation{ + Key: annotation.ProfileAnnotationKeyThrottled, + Value: string(a), + }) + return nil +} + +func (req *ProfileSeries) MarkSampledRequest(source *sampling.Source) error { + a, err := annotation.CreateProfileAnnotation(source) + if err != nil { + return err + } + req.Annotations = append(req.Annotations, &v1.ProfileAnnotation{ + Key: annotation.ProfileAnnotationKeySampled, + Value: string(a), + }) + return nil +} diff --git a/pkg/distributor/model/push_test.go b/pkg/distributor/model/push_test.go index ac1f23ba42..b781b15fb3 100644 --- a/pkg/distributor/model/push_test.go +++ b/pkg/distributor/model/push_test.go @@ -2,8 +2,14 @@ package model import ( "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/distributor/annotation" + "github.com/grafana/pyroscope/v2/pkg/distributor/ingestlimits" ) func TestProfileSeries_GetLanguage(t *testing.T) { @@ -28,3 +34,122 @@ func TestProfileSeries_GetLanguage(t *testing.T) { }) } } + +func TestMarkThrottledTenant(t *testing.T) { + tests := []struct { + name string + req *ProfileSeries + limit *ingestlimits.Config + expectError bool + verify func(t *testing.T, req *ProfileSeries) + }{ + { + name: "single series", + req: &ProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + }, + }, + limit: &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: time.Now().Unix(), + LimitReached: true, + }, + verify: func(t *testing.T, req *ProfileSeries) { + require.Len(t, req.Annotations, 1) + assert.Equal(t, annotation.ProfileAnnotationKeyThrottled, req.Annotations[0].Key) + assert.Contains(t, req.Annotations[0].Value, "\"periodLimitMb\":128") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.req.MarkThrottledTenant(tt.limit) + if tt.expectError { + assert.Error(t, err) + return + } + assert.NoError(t, err) + if tt.verify != nil { + tt.verify(t, tt.req) + } + }) + } +} + +func TestMarkThrottledUsageGroup(t *testing.T) { + tests := []struct { + name string + req *ProfileSeries + limit *ingestlimits.Config + usageGroup string + expectError bool + verify func(t *testing.T, req *ProfileSeries) + }{ + { + name: "single series with usage group", + req: &ProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + }, + }, + limit: &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: time.Now().Unix(), + LimitReached: true, + UsageGroups: map[string]ingestlimits.UsageGroup{ + "group-1": { + PeriodLimitMb: 64, + LimitReached: true, + }, + }, + }, + usageGroup: "group-1", + verify: func(t *testing.T, req *ProfileSeries) { + require.Len(t, req.Annotations, 1) + assert.Equal(t, annotation.ProfileAnnotationKeyThrottled, req.Annotations[0].Key) + assert.Contains(t, req.Annotations[0].Value, "\"periodLimitMb\":64") + assert.Contains(t, req.Annotations[0].Value, "\"usageGroup\":\"group-1\"") + }, + }, + { + name: "invalid usage group", + req: &ProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + }, + }, + limit: &ingestlimits.Config{ + PeriodType: "hour", + PeriodLimitMb: 128, + LimitResetTime: time.Now().Unix(), + LimitReached: true, + UsageGroups: map[string]ingestlimits.UsageGroup{ + "group-1": { + PeriodLimitMb: 64, + LimitReached: true, + }, + }, + }, + usageGroup: "nonexistent-group", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.req.MarkThrottledUsageGroup(tt.limit, tt.usageGroup) + if tt.expectError { + assert.Error(t, err) + return + } + assert.NoError(t, err) + if tt.verify != nil { + tt.verify(t, tt.req) + } + }) + } +} diff --git a/pkg/distributor/rate_strategy.go b/pkg/distributor/rate_strategy.go index c56d76b7f5..54905b62da 100644 --- a/pkg/distributor/rate_strategy.go +++ b/pkg/distributor/rate_strategy.go @@ -69,18 +69,3 @@ func (s *ingestionRateStrategy) Limit(tenantID string) float64 { func (s *ingestionRateStrategy) Burst(tenantID string) int { return s.limits.IngestionBurstSizeBytes(tenantID) } - -type infiniteStrategy struct{} - -func newInfiniteRateStrategy() limiter.RateLimiterStrategy { - return &infiniteStrategy{} -} - -func (s *infiniteStrategy) Limit(tenantID string) float64 { - return float64(rate.Inf) -} - -func (s *infiniteStrategy) Burst(tenantID string) int { - // Burst is ignored when limit = rate.Inf - return 0 -} diff --git a/pkg/distributor/rate_strategy_test.go b/pkg/distributor/rate_strategy_test.go index e99b3fc8fe..e02b21efae 100644 --- a/pkg/distributor/rate_strategy_test.go +++ b/pkg/distributor/rate_strategy_test.go @@ -11,9 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "golang.org/x/time/rate" - "github.com/grafana/pyroscope/pkg/validation" + "github.com/grafana/pyroscope/v2/pkg/validation" ) func TestIngestionRateStrategy(t *testing.T) { @@ -32,13 +31,6 @@ func TestIngestionRateStrategy(t *testing.T) { assert.Equal(t, strategy.Limit("test"), float64(1000*1024*1024/2)) assert.Equal(t, strategy.Burst("test"), 10000*1024*1024) }) - - t.Run("infinite rate limiter should return unlimited settings", func(t *testing.T) { - strategy := newInfiniteRateStrategy() - - assert.Equal(t, strategy.Limit("test"), float64(rate.Inf)) - assert.Equal(t, strategy.Burst("test"), 0) - }) } type readLifecyclerMock struct { diff --git a/pkg/distributor/sampling/config.go b/pkg/distributor/sampling/config.go new file mode 100644 index 0000000000..e9822c5017 --- /dev/null +++ b/pkg/distributor/sampling/config.go @@ -0,0 +1,15 @@ +package sampling + +type Config struct { + // UsageGroups controls sampling for pre-configured usage groups. + UsageGroups map[string]UsageGroupSampling `yaml:"usage_groups" json:"usage_groups"` +} + +type UsageGroupSampling struct { + Probability float64 `yaml:"probability" json:"probability"` +} + +type Source struct { + UsageGroup string `json:"usageGroup"` + Probability float64 `json:"probability"` +} diff --git a/pkg/distributor/writepath/router.go b/pkg/distributor/writepath/router.go new file mode 100644 index 0000000000..6aceab8c9e --- /dev/null +++ b/pkg/distributor/writepath/router.go @@ -0,0 +1,254 @@ +package writepath + +import ( + "context" + "errors" + "math/rand" + "net/http" + "sync" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/grafana/dskit/services" + "github.com/grafana/dskit/tracing" + "github.com/prometheus/client_golang/prometheus" + + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/delayhandler" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +type SegmentWriterClient interface { + Push(context.Context, *segmentwriterv1.PushRequest) (*segmentwriterv1.PushResponse, error) +} + +type IngesterClient interface { + Push(context.Context, *distributormodel.ProfileSeries) (*connect.Response[pushv1.PushResponse], error) +} + +type IngesterFunc func( + context.Context, + *distributormodel.ProfileSeries, +) (*connect.Response[pushv1.PushResponse], error) + +func (f IngesterFunc) Push( + ctx context.Context, + req *distributormodel.ProfileSeries, +) (*connect.Response[pushv1.PushResponse], error) { + return f(ctx, req) +} + +type Router struct { + service services.Service + inflight sync.WaitGroup + + logger log.Logger + metrics *metrics + + ingester IngesterClient + segwriter IngesterClient +} + +func NewRouter( + logger log.Logger, + registerer prometheus.Registerer, + ingester IngesterClient, + segwriter IngesterClient, +) *Router { + r := &Router{ + logger: logger, + metrics: newMetrics(registerer), + ingester: ingester, + segwriter: segwriter, + } + r.service = services.NewBasicService(r.starting, r.running, r.stopping) + return r +} + +func (m *Router) Service() services.Service { return m.service } + +func (m *Router) starting(context.Context) error { return nil } + +func (m *Router) stopping(_ error) error { + // We expect that no requests are routed after the stopping call. + m.inflight.Wait() + return nil +} + +func (m *Router) running(ctx context.Context) error { + <-ctx.Done() + return nil +} + +func (m *Router) Send(ctx context.Context, req *distributormodel.ProfileSeries, config Config) error { + sp, ctx := tracing.StartSpanFromContext(ctx, "Router.Send") + defer sp.Finish() + if config.AsyncIngest { + delayhandler.CancelDelay(ctx) + } + switch config.WritePath { + case SegmentWriterPath: + return m.sendToSegmentWriterOnly(ctx, req, &config) + case CombinedPath: + return m.sendToBoth(ctx, req, &config) + default: + return m.sendToIngesterOnly(ctx, req) + } +} + +func (m *Router) ingesterRoute() *route { + return &route{ + path: IngesterPath, + primary: true, // Ingester is always the primary route. + client: m.ingester, + } +} + +func (m *Router) segwriterRoute(primary bool) *route { + return &route{ + path: SegmentWriterPath, + primary: primary, + client: m.segwriter, + } +} + +func (m *Router) sendToBoth(ctx context.Context, req *distributormodel.ProfileSeries, config *Config) error { + r := rand.Float64() // [0.0, 1.0) + shouldIngester := config.IngesterWeight > 0.0 && config.IngesterWeight >= r + shouldSegwriter := config.SegmentWriterWeight > 0.0 && config.SegmentWriterWeight >= r + + // Client sees errors and latency of the primary write + // path, secondary write path does not affect the client. + var ingester, segwriter *route + if shouldIngester { + // If the request is sent to ingester (regardless of anything), + // the response is returned to the client immediately after the old + // write path returns. Failure of the new write path should be logged + // and counted in metrics but NOT returned to the client. + ingester = m.ingesterRoute() + if !shouldSegwriter { + return m.send(ingester)(ctx, req) + } + } + if shouldSegwriter { + segwriter = m.segwriterRoute(!shouldIngester) + if segwriter.primary && !config.AsyncIngest { + // The request is sent to segment-writer exclusively, and the client + // must block until the response returns. + // Failure of the new write is returned to the client. + // Failure of the old write path is NOT returned to the client. + return m.send(segwriter)(ctx, req) + } + // Request to the segment writer will be sent asynchronously. + } + + // No write routes. This is possible if the write path is configured + // to "combined" and both weights are set to 0.0. + if ingester == nil && segwriter == nil { + return nil + } + + if segwriter != nil && ingester != nil { + // The request is to be sent to both asynchronously, therefore we're + // cloning it. We do not wait for the secondary request to complete. + // On shutdown, however, we will wait for all inflight requests. + segwriter.client = m.detachedClient(ctx, req.Clone(), segwriter.client, config) + } + + if segwriter != nil { + m.sendAsync(ctx, req, segwriter) + } + + if ingester != nil { + select { + case err := <-m.sendAsync(ctx, req, ingester): + return err + case <-ctx.Done(): + return ctx.Err() + } + } + + return nil +} + +func (m *Router) sendToSegmentWriterOnly(ctx context.Context, req *distributormodel.ProfileSeries, config *Config) error { + r := m.segwriterRoute(true) + if !config.AsyncIngest { + return m.send(r)(ctx, req) + } + r.client = m.detachedClient(ctx, req, r.client, config) + m.sendAsync(ctx, req, r) + return nil +} + +func (m *Router) sendToIngesterOnly(ctx context.Context, req *distributormodel.ProfileSeries) error { + // NOTE(kolesnikovae): If we also want to support async requests to ingesters, + // we should implement it here and in sendToBoth. + return m.send(m.ingesterRoute())(ctx, req) +} + +type sendFunc func(context.Context, *distributormodel.ProfileSeries) error + +type route struct { + path WritePath // IngesterPath | SegmentWriterPath + client IngesterClient + primary bool +} + +// detachedClient creates a new IngesterFunc that wraps the call with a local context +// that has a timeout and tenant ID injected so it can be used for asynchronous requests. +func (m *Router) detachedClient(ctx context.Context, req *distributormodel.ProfileSeries, client IngesterClient, config *Config) IngesterFunc { + return func(context.Context, *distributormodel.ProfileSeries) (*connect.Response[pushv1.PushResponse], error) { + localCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), config.SegmentWriterTimeout) + localCtx = tenant.InjectTenantID(localCtx, req.TenantID) + defer cancel() + return client.Push(localCtx, req) + } +} + +func (m *Router) sendAsync(ctx context.Context, req *distributormodel.ProfileSeries, r *route) <-chan error { + c := make(chan error, 1) + m.inflight.Add(1) + go func() { + defer m.inflight.Done() + c <- m.send(r)(ctx, req) + }() + return c +} + +func (m *Router) send(r *route) sendFunc { + return func(ctx context.Context, req *distributormodel.ProfileSeries) (err error) { + start := time.Now() + defer func() { + if p := recover(); p != nil { + err = util.PanicError(p) + } + // Note that the upstream expects "connect" codes. + code := http.StatusOK // HTTP status code. + if err != nil { + var connectErr *connect.Error + if ok := errors.As(err, &connectErr); ok { + // connect errors are passed as is, we only + // identify the HTTP status code. + code = int(connectgrpc.CodeToHTTP(connectErr.Code())) + } else { + // We identify the HTTP status code based on the + // error and then convert the error to connect error. + code, _ = httputil.ClientHTTPStatusAndError(err) + err = connect.NewError(connectgrpc.HTTPToCode(int32(code)), err) + } + } + m.metrics.durationHistogram. + WithLabelValues(newDurationHistogramDims(r, code)...). + Observe(time.Since(start).Seconds()) + }() + _, err = r.client.Push(ctx, req) + return err + } +} diff --git a/pkg/distributor/writepath/router_metrics.go b/pkg/distributor/writepath/router_metrics.go new file mode 100644 index 0000000000..82a6586a3d --- /dev/null +++ b/pkg/distributor/writepath/router_metrics.go @@ -0,0 +1,38 @@ +package writepath + +import ( + "strconv" + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +type metrics struct { + durationHistogram *prometheus.HistogramVec +} + +func newMetrics(reg prometheus.Registerer) *metrics { + m := &metrics{ + durationHistogram: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pyroscope_write_path_downstream_request_duration_seconds", + Help: "Duration of downstream requests made by the write path router.", + + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"route", "primary", "status"}), + } + if reg != nil { + reg.MustRegister(m.durationHistogram) + } + return m +} + +func newDurationHistogramDims(r *route, code int) []string { + dims := []string{string(r.path), "1", strconv.Itoa(code)} + if !r.primary { + dims[1] = "0" + } + return dims +} diff --git a/pkg/distributor/writepath/write_path.go b/pkg/distributor/writepath/write_path.go new file mode 100644 index 0000000000..a72722acf7 --- /dev/null +++ b/pkg/distributor/writepath/write_path.go @@ -0,0 +1,105 @@ +package writepath + +import ( + "errors" + "flag" + "fmt" + "time" +) + +// WritePath controls the write path. +type WritePath string + +const ( + // IngesterPath specifies old write path the requests are sent to ingester. + IngesterPath WritePath = "ingester" + // SegmentWriterPath specifies the new write path: distributor sends + // the request to segment writers before profile split, using the new + // distribution algorithm and the segment-writer ring. + SegmentWriterPath = "segment-writer" + // CombinedPath specifies that each request should be sent to both write + // paths. For each request we decide on how a failure is handled: + // * If the request is sent to ingester (regardless of anything), + // the response is returned to the client immediately after the old + // write path returns. Failure of the new write path should be logged + // and counted in metrics but NOT returned to the client. + // * If the request is sent to segment-writer exclusively: the response + // returns to the client only when the new write path returns. + // Failure of the new write is returned to the client. + // Failure of the old write path is NOT returned to the client. + CombinedPath = "combined" +) + +var ErrInvalidWritePath = errors.New("invalid write path") + +var paths = []WritePath{ + IngesterPath, + SegmentWriterPath, + CombinedPath, +} + +const validWritePathOptionsString = "valid options: ingester, segment-writer, combined" + +func (m *WritePath) Set(text string) error { + x := WritePath(text) + for _, name := range paths { + if x == name { + *m = x + return nil + } + } + return fmt.Errorf("%w: %s; %s", ErrInvalidWritePath, x, validWritePathOptionsString) +} + +func (m *WritePath) String() string { return string(*m) } + +type Compression string + +const ( + CompressionNone Compression = "none" + CompressionGzip Compression = "gzip" +) + +var ErrInvalidCompression = errors.New("invalid write path compression") + +var compressions = []Compression{ + CompressionNone, + CompressionGzip, +} + +const validCompressionOptionsString = "valid compression options: none, gzip" + +func (m *Compression) Set(text string) error { + x := Compression(text) + for _, name := range compressions { + if x == name { + *m = x + return nil + } + } + return fmt.Errorf("%w: %s; %s", ErrInvalidCompression, x, validCompressionOptionsString) +} + +func (m *Compression) String() string { return string(*m) } + +type Config struct { + WritePath WritePath `yaml:"write_path" json:"write_path" doc:"hidden"` + IngesterWeight float64 `yaml:"write_path_ingester_weight" json:"write_path_ingester_weight" category:"advanced" doc:"hidden"` + SegmentWriterWeight float64 `yaml:"write_path_segment_writer_weight" json:"write_path_segment_writer_weight" category:"advanced" doc:"hidden"` + SegmentWriterTimeout time.Duration `yaml:"write_path_segment_writer_timeout" json:"write_path_segment_writer_timeout" category:"advanced" doc:"hidden"` + Compression Compression `yaml:"write_path_compression" json:"write_path_compression" category:"advanced" doc:"hidden"` + AsyncIngest bool `yaml:"async_ingest" json:"async_ingest" category:"advanced" doc:"hidden"` +} + +func (o *Config) RegisterFlags(f *flag.FlagSet) { + o.WritePath = SegmentWriterPath + o.Compression = CompressionNone + f.Var(&o.WritePath, "write-path", "Controls the write path route; "+validWritePathOptionsString+".") + f.Float64Var(&o.IngesterWeight, "write-path.ingester-weight", 1, + "Specifies the fraction [0:1] that should be send to ingester in combined mode. 0 means no traffics is sent to ingester. 1 means 100% of requests are sent to ingester.") + f.Float64Var(&o.SegmentWriterWeight, "write-path.segment-writer-weight", 0, + "Specifies the fraction [0:1] that should be send to segment-writer in combined mode. 0 means no traffics is sent to segment-writer. 1 means 100% of requests are sent to segment-writer.") + f.DurationVar(&o.SegmentWriterTimeout, "write-path.segment-writer-timeout", 5*time.Second, "Timeout for segment writer requests.") + f.Var(&o.Compression, "write-path.compression", "Compression algorithm to use for segment writer requests; "+validCompressionOptionsString+".") + f.BoolVar(&o.AsyncIngest, "async-ingest", false, "If true, the write path will not wait for the segment-writer to finish processing the request. Writes to ingester always synchronous.") +} diff --git a/pkg/distributor/writepath/write_path_test.go b/pkg/distributor/writepath/write_path_test.go new file mode 100644 index 0000000000..2c0b678ab8 --- /dev/null +++ b/pkg/distributor/writepath/write_path_test.go @@ -0,0 +1,318 @@ +package writepath + +import ( + "context" + "io" + "sync/atomic" + "testing" + + "connectrpc.com/connect" + + "github.com/go-kit/log" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockwritepath" + "github.com/grafana/pyroscope/v2/pkg/util/delayhandler" +) + +type routerTestSuite struct { + suite.Suite + + router *Router + logger log.Logger + registry *prometheus.Registry + ingester *mockwritepath.MockIngesterClient + segwriter *mockwritepath.MockIngesterClient + + request *distributormodel.ProfileSeries +} + +func (s *routerTestSuite) SetupTest() { + s.logger = log.NewLogfmtLogger(io.Discard) + s.registry = prometheus.NewRegistry() + s.ingester = new(mockwritepath.MockIngesterClient) + s.segwriter = new(mockwritepath.MockIngesterClient) + + s.request = &distributormodel.ProfileSeries{ + Labels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + {Name: "qux", Value: "zoo"}, + }, + Profile: &pprof.Profile{}, + + TenantID: "tenant-a", + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "foo", Value: "bar"}, + }, + } + + s.router = NewRouter( + s.logger, + s.registry, + s.ingester, + s.segwriter, + ) +} + +func (s *routerTestSuite) BeforeTest(_, _ string) { + svc := s.router.Service() + s.Require().NoError(svc.StartAsync(context.Background())) + s.Require().NoError(svc.AwaitRunning(context.Background())) + s.Require().Equal(services.Running, svc.State()) +} + +func (s *routerTestSuite) AfterTest(_, _ string) { + svc := s.router.Service() + svc.StopAsync() + s.Require().NoError(svc.AwaitTerminated(context.Background())) + s.Require().Equal(services.Terminated, svc.State()) + + s.ingester.AssertExpectations(s.T()) + s.segwriter.AssertExpectations(s.T()) +} + +func TestRouterSuite(t *testing.T) { suite.Run(t, new(routerTestSuite)) } + +func (s *routerTestSuite) Test_IngesterPath() { + config := Config{ + WritePath: IngesterPath, + } + + s.ingester.On("Push", mock.Anything, s.request). + Return(new(connect.Response[pushv1.PushResponse]), nil). + Once() + + s.Assert().NoError(s.router.Send(context.Background(), s.request, config)) +} + +func (s *routerTestSuite) Test_SegmentWriterPath() { + config := Config{ + WritePath: SegmentWriterPath, + } + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), nil). + Once() + + s.Assert().NoError(s.router.Send(context.Background(), s.request, config)) +} + +func (s *routerTestSuite) Test_CombinedPath() { + const ( + N = 100 + w = 10 // Concurrent workers. + f = 0.5 + d = 0.3 // Allowed delta: note that f is just a probability. + ) + + config := Config{ + WritePath: CombinedPath, + IngesterWeight: 1, + SegmentWriterWeight: f, + } + + var sentIngester atomic.Uint32 + s.ingester.On("Push", mock.Anything, mock.Anything). + Run(func(m mock.Arguments) { + sentIngester.Add(1) + // Assert that no race condition occurs: we delete series + // attempting to access it concurrently with segment writer + // that should convert the distributor request to a segment + // writer request. + m.Get(1).(*distributormodel.ProfileSeries).Profile = nil + }). + Return(new(connect.Response[pushv1.PushResponse]), nil) + + var sentSegwriter atomic.Uint32 + s.segwriter.On("Push", mock.Anything, mock.Anything). + Run(func(m mock.Arguments) { + sentSegwriter.Add(1) + m.Get(1).(*distributormodel.ProfileSeries).Profile = nil + }). + Return(new(connect.Response[pushv1.PushResponse]), nil) + + for i := 0; i < w; i++ { + for j := 0; j < N; j++ { + s.Assert().NoError(s.router.Send(context.Background(), s.request.Clone(), config)) + } + } + + s.router.inflight.Wait() + expected := N * f * w + delta := expected * d + s.Assert().Equal(N*w, int(sentIngester.Load())) + s.Assert().Greater(int(sentSegwriter.Load()), int(expected-delta)) + s.Assert().Less(int(sentSegwriter.Load()), int(expected+delta)) +} + +func (s *routerTestSuite) Test_UnspecifiedWriterPath() { + config := Config{} // Default should route to ingester + + s.ingester.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), nil). + Once() + + s.Assert().NoError(s.router.Send(context.Background(), s.request, config)) +} + +func (s *routerTestSuite) Test_CombinedPath_ZeroWeights() { + config := Config{ + WritePath: CombinedPath, + } + + s.Assert().NoError(s.router.Send(context.Background(), s.request, config)) +} + +func (s *routerTestSuite) Test_CombinedPath_IngesterError() { + config := Config{ + WritePath: CombinedPath, + // We ensure that request is sent to both. + IngesterWeight: 1, + SegmentWriterWeight: 1, + } + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), nil). + Once() + + s.ingester.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + s.Assert().Error(s.router.Send(context.Background(), s.request, config), context.Canceled) +} + +func (s *routerTestSuite) Test_CombinedPath_SegmentWriterError() { + config := Config{ + WritePath: CombinedPath, + // We ensure that request is sent to both. + IngesterWeight: 1, + SegmentWriterWeight: 1, + } + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + s.ingester.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), nil). + Once() + + s.Assert().NoError(s.router.Send(context.Background(), s.request, config)) +} + +func (s *routerTestSuite) Test_CombinedPath_Ingester_Exclusive_Error() { + config := Config{ + WritePath: CombinedPath, + // The request is only sent to ingester. + IngesterWeight: 1, + SegmentWriterWeight: 0, + } + + s.ingester.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + s.Assert().Error(s.router.Send(context.Background(), s.request, config), context.Canceled) +} + +func (s *routerTestSuite) Test_CombinedPath_SegmentWriter_Exclusive_Error() { + config := Config{ + WritePath: CombinedPath, + // The request is only sent to segment writer. + IngesterWeight: 0, + SegmentWriterWeight: 1, + } + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + s.Assert().Error(s.router.Send(context.Background(), s.request, config), context.Canceled) +} + +func (s *routerTestSuite) Test_AsyncIngest_Synchronous() { + config := Config{ + WritePath: SegmentWriterPath, + AsyncIngest: false, + } + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + err := s.router.Send(context.Background(), s.request, config) + s.Assert().Error(err) +} + +func (s *routerTestSuite) Test_AsyncIngest_Asynchronous() { + config := Config{ + WritePath: SegmentWriterPath, + AsyncIngest: true, + } + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + err := s.router.Send(context.Background(), s.request, config) + s.Assert().NoError(err) + + s.router.inflight.Wait() +} + +func (s *routerTestSuite) Test_AsyncIngest_CombinedPath() { + config := Config{ + WritePath: CombinedPath, + IngesterWeight: 1, + SegmentWriterWeight: 1, + AsyncIngest: true, + } + + s.ingester.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + err := s.router.Send(context.Background(), s.request, config) + s.Assert().Error(err) + + s.router.inflight.Wait() +} + +func (s *routerTestSuite) Test_AsyncIngest_DelayCanceled() { + config := Config{ + WritePath: CombinedPath, + IngesterWeight: 1, + SegmentWriterWeight: 1, + AsyncIngest: true, + } + + s.ingester.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + s.segwriter.On("Push", mock.Anything, mock.Anything). + Return(new(connect.Response[pushv1.PushResponse]), context.Canceled). + Once() + + var canceled atomic.Bool + ctx := delayhandler.WithDelayCancel(context.Background(), func() { + canceled.Store(true) + }) + + s.Assert().Error(s.router.Send(ctx, s.request, config)) + s.router.inflight.Wait() + + s.Assert().True(canceled.Load()) +} diff --git a/pkg/embedded/grafana/assets.go b/pkg/embedded/grafana/assets.go new file mode 100644 index 0000000000..ba93d7d0f5 --- /dev/null +++ b/pkg/embedded/grafana/assets.go @@ -0,0 +1,292 @@ +package grafana + +import ( + "archive/tar" + "archive/zip" + "compress/gzip" + "context" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "io/fs" + "net/http" + "os" + "path/filepath" + "strings" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" +) + +type CompressType int + +const ( + CompressTypeNone CompressType = iota + CompressTypeGzip + CompressTypeZip +) + +const ( + modeDir = 0755 + modeFile = 0644 +) + +type releaseArtifacts []releaseArtifact + +func (releases releaseArtifacts) selectBy(os, arch string) *releaseArtifact { + var nonArch *releaseArtifact + for idx, r := range releases { + if r.OS == "" && r.Arch == "" && nonArch == nil { + nonArch = &releases[idx] + continue + } + if r.OS == os && r.Arch == arch { + return &r + } + } + return nonArch +} + +type releaseArtifact struct { + URL string + Sha256Sum []byte + OS string + Arch string + CompressType CompressType + StripComponents int +} + +func (release *releaseArtifact) download(ctx context.Context, logger log.Logger, destPath string) (string, error) { + targetPath := filepath.Join(destPath, "assets", hex.EncodeToString(release.Sha256Sum)) + + // check if already exists + if len(release.Sha256Sum) > 0 { + stat, err := os.Stat(targetPath) + if err != nil { + if !os.IsNotExist(err) { + return "", err + } + } + if err == nil && stat.IsDir() { + level.Info(logger).Log("msg", "release exists already", "url", release.URL, "hash", hex.EncodeToString(release.Sha256Sum)) + return targetPath, nil + } + } + + level.Info(logger).Log("msg", "download new release", "url", release.URL) + req, err := http.NewRequestWithContext(ctx, "GET", release.URL, nil) + if err != nil { + return "", err + } + req.Header.Set("User-Agent", "pyroscope/embedded-grafana") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + file, err := os.CreateTemp("", "pyroscope-download") + if err != nil { + return "", err + } + defer os.Remove(file.Name()) + + hash := sha256.New() + r := io.TeeReader(resp.Body, hash) + + _, err = io.Copy(file, r) + if err != nil { + return "", err + } + + err = file.Close() + if err != nil { + return "", err + } + + actHashSum := hex.EncodeToString(hash.Sum(nil)) + if expHashSum := hex.EncodeToString(release.Sha256Sum); actHashSum != expHashSum { + return "", fmt.Errorf("hash mismatch: expected %s, got %s", expHashSum, actHashSum) + } + + switch release.CompressType { + case CompressTypeNone: + return targetPath, os.Rename(file.Name(), targetPath) + case CompressTypeGzip: + file, err = os.Open(file.Name()) + if err != nil { + return "", err + } + defer file.Close() + + err = extractTarGz(file, targetPath, release.StripComponents) + if err != nil { + return "", err + } + case CompressTypeZip: + file, err = os.Open(file.Name()) + if err != nil { + return "", err + } + defer file.Close() + + stat, err := file.Stat() + if err != nil { + return "", err + } + + err = extractZip(file, stat.Size(), targetPath, release.StripComponents) + if err != nil { + return "", err + } + } + + return targetPath, nil +} + +func clearPath(name string, destPath string, stripComponents int) (string, error) { + isSeparator := func(r rune) bool { + return r == os.PathSeparator + } + list := strings.FieldsFunc(name, isSeparator) + if len(list) > stripComponents { + list = list[stripComponents:] + } + cleaned := filepath.Join(append([]string{destPath}, list...)...) + // Ensure the resolved path is confined to destPath (zip-slip / tar-slip prevention). + absDestPath, err := filepath.Abs(destPath) + if err != nil { + return "", fmt.Errorf("clearPath: abs destPath: %w", err) + } + absCleaned, err := filepath.Abs(cleaned) + if err != nil { + return "", fmt.Errorf("clearPath: abs cleaned: %w", err) + } + if !strings.HasPrefix(absCleaned, absDestPath+string(os.PathSeparator)) && absCleaned != absDestPath { + return "", fmt.Errorf("clearPath: path %q escapes destination directory", name) + } + return cleaned, nil +} + +func extractZip(zipStream io.ReaderAt, size int64, destPath string, stripComponents int) error { + zipReader, err := zip.NewReader(zipStream, size) + if err != nil { + return fmt.Errorf("ExtractZip: NewReader failed: %s", err.Error()) + } + + for _, f := range zipReader.File { + p, err := clearPath(f.Name, destPath, stripComponents) + if err != nil { + return fmt.Errorf("ExtractZip: %w", err) + } + if f.FileInfo().IsDir() { + err := os.MkdirAll(p, modeDir) + if err != nil { + return fmt.Errorf("ExtractZip: MkdirAll() failed: %s", err.Error()) + } + continue + } + + dir, _ := filepath.Split(p) + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.MkdirAll(dir, modeDir); err != nil { + return fmt.Errorf("ExtractZip: MkdirAll() failed: %s", err.Error()) + } + } + + if err := extractZipFile(f, p); err != nil { + return fmt.Errorf("ExtractZip: %w", err) + } + } + + return nil + +} + +func extractTarGzFile(p string, src io.Reader, mode fs.FileMode) error { + outFile, err := os.OpenFile(p, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) + if err != nil { + return fmt.Errorf("OpenFile() failed: %s", err.Error()) + } + defer outFile.Close() + if _, err := io.Copy(outFile, src); err != nil { + return fmt.Errorf("Copy() failed: %s", err.Error()) + } + return nil +} + +func extractZipFile(f *zip.File, p string) error { + fileInArchive, err := f.Open() + if err != nil { + return fmt.Errorf("Open() failed: %s", err.Error()) + } + defer fileInArchive.Close() + + outFile, err := os.OpenFile(p, os.O_RDWR|os.O_CREATE|os.O_TRUNC, f.FileInfo().Mode()) + if err != nil { + return fmt.Errorf("OpenFile() failed: %s", err.Error()) + } + defer outFile.Close() + + if _, err := io.Copy(outFile, fileInArchive); err != nil { + return fmt.Errorf("Copy() failed: %s", err.Error()) + } + return nil +} + +func extractTarGz(gzipStream io.Reader, destPath string, stripComponents int) error { + uncompressedStream, err := gzip.NewReader(gzipStream) + if err != nil { + return errors.New("ExtractTarGz: NewReader failed") + } + + tarReader := tar.NewReader(uncompressedStream) + + for { + header, err := tarReader.Next() + + if err == io.EOF { + break + } + + if err != nil { + return fmt.Errorf("ExtractTarGz: Next() failed: %s", err.Error()) + } + + p, err := clearPath(header.Name, destPath, stripComponents) + if err != nil { + return fmt.Errorf("ExtractTarGz: %w", err) + } + switch header.Typeflag { + case tar.TypeDir: + if err := os.MkdirAll(p, modeDir); err != nil { + return fmt.Errorf("ExtractTarGz: Mkdir() failed: %s", err.Error()) + } + case tar.TypeReg: + dir, _ := filepath.Split(p) + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.MkdirAll(dir, modeDir); err != nil { + return fmt.Errorf("ExtractTarGz: MkdirAll() failed: %s", err.Error()) + } + } + if err := extractTarGzFile(p, tarReader, fs.FileMode(header.Mode)); err != nil { + return fmt.Errorf("ExtractTarGz: %w", err) + } + + default: + return fmt.Errorf( + "ExtractTarGz: unknown type: %v in %s", + header.Typeflag, + header.Name) + } + } + + return nil +} diff --git a/pkg/embedded/grafana/assets_test.go b/pkg/embedded/grafana/assets_test.go new file mode 100644 index 0000000000..2d31b2a6cf --- /dev/null +++ b/pkg/embedded/grafana/assets_test.go @@ -0,0 +1,268 @@ +package grafana + +import ( + "archive/tar" + "archive/zip" + "bytes" + "compress/gzip" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestClearPath(t *testing.T) { + t.Parallel() + + destPath := t.TempDir() + + tests := []struct { + name string + entryName string + stripComponents int + wantSuffix string // expected suffix relative to destPath + wantErr bool + errContains string + }{ + { + name: "simple file", + entryName: "dir/file.txt", + stripComponents: 0, + wantSuffix: "dir/file.txt", + }, + { + name: "strip one component", + entryName: "prefix/dir/file.txt", + stripComponents: 1, + wantSuffix: "dir/file.txt", + }, + { + // When stripComponents >= len(parts), len(list) > stripComponents is false + // so the list is left untouched and the full path is appended. + name: "strip equal to component count keeps full path", + entryName: "a/b", + stripComponents: 2, + wantSuffix: "a/b", + }, + { + name: "path traversal via ..", + entryName: "../../etc/passwd", + stripComponents: 0, + wantErr: true, + errContains: "escapes destination directory", + }, + { + name: "path traversal after strip", + entryName: "prefix/../../../etc/passwd", + stripComponents: 1, + wantErr: true, + errContains: "escapes destination directory", + }, + { + // /etc/passwd is split by FieldsFunc into ["etc","passwd"] (leading separator + // consumed), then joined under destPath — result is destPath/etc/passwd. + name: "absolute path is confined to destPath", + entryName: "/etc/passwd", + stripComponents: 0, + wantSuffix: "etc/passwd", + }, + { + name: "nested directory within dest", + entryName: "a/b/c/file.txt", + stripComponents: 0, + wantSuffix: "a/b/c/file.txt", + }, + { + name: "traversal with mixed separators", + entryName: "good/../../../evil", + stripComponents: 0, + wantErr: true, + errContains: "escapes destination directory", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := clearPath(tt.entryName, destPath, tt.stripComponents) + if tt.wantErr { + require.Error(t, err) + if tt.errContains != "" { + assert.Contains(t, err.Error(), tt.errContains) + } + return + } + require.NoError(t, err) + want := filepath.Join(destPath, filepath.FromSlash(tt.wantSuffix)) + assert.Equal(t, want, got) + }) + } +} + +type zipEntry struct { + name string + content string +} + +func buildZip(t *testing.T, entries []zipEntry) *bytes.Reader { + t.Helper() + var buf bytes.Buffer + w := zip.NewWriter(&buf) + for _, e := range entries { + if strings.HasSuffix(e.name, "/") || e.content == "" && strings.Contains(e.name, "/") && !strings.Contains(filepath.Base(e.name), ".") { + _, err := w.Create(e.name) + require.NoError(t, err) + } else { + f, err := w.Create(e.name) + require.NoError(t, err) + _, err = f.Write([]byte(e.content)) + require.NoError(t, err) + } + } + require.NoError(t, w.Close()) + return bytes.NewReader(buf.Bytes()) +} + +func TestExtractZip_Normal(t *testing.T) { + dest := t.TempDir() + r := buildZip(t, []zipEntry{ + {name: "prefix/subdir/hello.txt", content: "hello"}, + {name: "prefix/world.txt", content: "world"}, + }) + err := extractZip(r, int64(r.Len()), dest, 1 /* strip "prefix" */) + require.NoError(t, err) + + data, err := os.ReadFile(filepath.Join(dest, "subdir", "hello.txt")) + require.NoError(t, err) + assert.Equal(t, "hello", string(data)) + + data, err = os.ReadFile(filepath.Join(dest, "world.txt")) + require.NoError(t, err) + assert.Equal(t, "world", string(data)) +} + +func TestExtractZip_NoStrip(t *testing.T) { + dest := t.TempDir() + r := buildZip(t, []zipEntry{ + {name: "file.txt", content: "content"}, + }) + err := extractZip(r, int64(r.Len()), dest, 0) + require.NoError(t, err) + + data, err := os.ReadFile(filepath.Join(dest, "file.txt")) + require.NoError(t, err) + assert.Equal(t, "content", string(data)) +} + +func TestExtractZip_PathTraversal(t *testing.T) { + dest := t.TempDir() + escaped := filepath.Join(dest, "..", "..", "evil.txt") + t.Cleanup(func() { os.Remove(escaped) }) + + r := buildZip(t, []zipEntry{ + {name: "../../evil.txt", content: "malicious"}, + }) + err := extractZip(r, int64(r.Len()), dest, 0) + require.Error(t, err) + assert.Contains(t, err.Error(), "escapes destination directory") + + _, statErr := os.Stat(escaped) + assert.True(t, os.IsNotExist(statErr), "evil.txt must not be written outside destPath") +} + +type tarEntry struct { + name string + content string + isDir bool +} + +func buildTarGz(t *testing.T, entries []tarEntry) *bytes.Reader { + t.Helper() + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + tw := tar.NewWriter(gz) + + for _, e := range entries { + if e.isDir { + hdr := &tar.Header{ + Name: e.name, + Typeflag: tar.TypeDir, + Mode: 0755, + } + require.NoError(t, tw.WriteHeader(hdr)) + } else { + hdr := &tar.Header{ + Name: e.name, + Typeflag: tar.TypeReg, + Mode: 0644, + Size: int64(len(e.content)), + } + require.NoError(t, tw.WriteHeader(hdr)) + _, err := tw.Write([]byte(e.content)) + require.NoError(t, err) + } + } + require.NoError(t, tw.Close()) + require.NoError(t, gz.Close()) + return bytes.NewReader(buf.Bytes()) +} + +func TestExtractTarGz_Normal(t *testing.T) { + dest := t.TempDir() + r := buildTarGz(t, []tarEntry{ + {name: "prefix/", isDir: true}, + {name: "prefix/hello.txt", content: "hello"}, + }) + err := extractTarGz(r, dest, 1 /* strip "prefix" */) + require.NoError(t, err) + + data, err := os.ReadFile(filepath.Join(dest, "hello.txt")) + require.NoError(t, err) + assert.Equal(t, "hello", string(data)) +} + +func TestExtractTarGz_NestedDirs(t *testing.T) { + dest := t.TempDir() + r := buildTarGz(t, []tarEntry{ + {name: "a/", isDir: true}, + {name: "a/b/", isDir: true}, + {name: "a/b/file.txt", content: "deep"}, + }) + err := extractTarGz(r, dest, 0) + require.NoError(t, err) + + data, err := os.ReadFile(filepath.Join(dest, "a", "b", "file.txt")) + require.NoError(t, err) + assert.Equal(t, "deep", string(data)) +} + +func TestExtractTarGz_PathTraversal(t *testing.T) { + dest := t.TempDir() + escaped := filepath.Join(dest, "..", "..", "evil.txt") + t.Cleanup(func() { os.Remove(escaped) }) + + r := buildTarGz(t, []tarEntry{ + {name: "../../evil.txt", content: "malicious"}, + }) + err := extractTarGz(r, dest, 0) + require.Error(t, err) + assert.Contains(t, err.Error(), "escapes destination directory") + + _, statErr := os.Stat(escaped) + assert.True(t, os.IsNotExist(statErr), "evil.txt must not be written outside destPath") +} + +func TestExtractTarGz_SlipAfterStrip(t *testing.T) { + dest := t.TempDir() + r := buildTarGz(t, []tarEntry{ + // After stripping "prefix", the effective path becomes ../../evil.txt + {name: "prefix/../../evil.txt", content: "bad"}, + }) + err := extractTarGz(r, dest, 1) + require.Error(t, err) + assert.Contains(t, err.Error(), "escapes destination directory") +} diff --git a/pkg/embedded/grafana/grafana.go b/pkg/embedded/grafana/grafana.go new file mode 100644 index 0000000000..272ca43ea2 --- /dev/null +++ b/pkg/embedded/grafana/grafana.go @@ -0,0 +1,339 @@ +package grafana + +import ( + "bufio" + "context" + "encoding/hex" + "flag" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "syscall" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/services" + "go.yaml.in/yaml/v3" + "golang.org/x/sync/errgroup" +) + +func mustHexDecode(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +var exploreProfileReleases = releaseArtifacts{ + { + URL: "https://github.com/grafana/profiles-drilldown/releases/download/v1.10.0/grafana-pyroscope-app-1.10.0.zip", + Sha256Sum: mustHexDecode("d1e33d22a68db7e7b9611361a25415e645516560f48c3aa4ee938f4c264e0e69"), + CompressType: CompressTypeZip, + }, +} + +var grafanaReleases = releaseArtifacts{ + { + URL: "https://dl.grafana.com/oss/release/grafana-12.3.2.linux-amd64.tar.gz", + Sha256Sum: mustHexDecode("f8675fc07f43f38268bb9132bf4014a26a4f4956f93a697047046ba9268f9d9b"), + OS: "linux", + Arch: "amd64", + CompressType: CompressTypeGzip, + StripComponents: 1, + }, + { + URL: "https://dl.grafana.com/oss/release/grafana-12.3.2.linux-arm64.tar.gz", + Sha256Sum: mustHexDecode("af0d8288b0818c3a1d5b4b2fc9b4c567bf55fcb8e28035d49a8dd54661cc880b"), + OS: "linux", + Arch: "arm64", + CompressType: CompressTypeGzip, + StripComponents: 1, + }, + { + URL: "https://dl.grafana.com/oss/release/grafana-12.3.2.darwin-amd64.tar.gz", + Sha256Sum: mustHexDecode("7daa6d40893e91a1f8e2d426580e8402616ffb4fb1ff09af9a1bdd81598dcf06"), + OS: "darwin", + Arch: "amd64", + CompressType: CompressTypeGzip, + StripComponents: 1, + }, + { + URL: "https://dl.grafana.com/oss/release/grafana-12.3.2.darwin-arm64.tar.gz", + Sha256Sum: mustHexDecode("221b878196b68221fc4540ddef4bc9c4c43e05cd81662b15f4c6200f45b1d2a5"), + OS: "darwin", + Arch: "arm64", + CompressType: CompressTypeGzip, + StripComponents: 1, + }, +} + +type app struct { + cfg Config + logger log.Logger + + grafanaRelease *releaseArtifact + exploreProfileRelease *releaseArtifact + + dataPath string + pluginsPath string + provisioningPath string + + g *errgroup.Group +} + +type Config struct { + DataPath string `yaml:"data_path" json:"data_path"` + ListenPort int `yaml:"listen_port" json:"listen_port"` + PyroscopeURL string `yaml:"pyroscope_url" json:"pyroscope_url"` +} + +// RegisterFlags registers distributor-related flags. +func (cfg *Config) RegisterFlags(fs *flag.FlagSet) { + fs.StringVar(&cfg.DataPath, "embedded-grafana.data-path", "./data/__embedded_grafana/", "The directory where the Grafana data will be stored.") + fs.IntVar(&cfg.ListenPort, "embedded-grafana.listen-port", 4041, "The port on which the Grafana will listen.") + fs.StringVar(&cfg.PyroscopeURL, "embedded-grafana.pyroscope-url", "http://localhost:4040", "The URL of the Pyroscope instance to use for the Grafana datasources.") +} + +func New(cfg Config, logger log.Logger) (services.Service, error) { + var err error + cfg.DataPath, err = filepath.Abs(cfg.DataPath) + if err != nil { + return nil, err + } + + grafanaRelease := grafanaReleases.selectBy(runtime.GOOS, runtime.GOARCH) + if grafanaRelease == nil { + return nil, fmt.Errorf("no Grafana release found for %s/%s", runtime.GOOS, runtime.GOARCH) + } + + exploreProfileRelease := exploreProfileReleases.selectBy(runtime.GOOS, runtime.GOARCH) + if exploreProfileRelease == nil { + level.Warn(logger).Log("msg", fmt.Sprintf("no Explore Profile plugin release found for %s/%s", runtime.GOOS, runtime.GOARCH)) + } + + a := &app{ + cfg: cfg, + logger: logger, + grafanaRelease: grafanaRelease, + exploreProfileRelease: exploreProfileRelease, + + dataPath: filepath.Join(cfg.DataPath, "data"), + pluginsPath: filepath.Join(cfg.DataPath, "plugins"), + provisioningPath: filepath.Join(cfg.DataPath, "provisioning"), + } + return services.NewBasicService(a.starting, a.running, a.stopping), nil +} + +func (a *app) downloadExploreProfiles(ctx context.Context) error { + // download the explore-profiles plugin + pluginPath, err := a.exploreProfileRelease.download(ctx, a.logger, a.cfg.DataPath) + if err != nil { + return err + } + + // symlink the explore-profiles plugin to the plugins directory + err = os.MkdirAll(a.pluginsPath, modeDir) + if err != nil { + return err + } + + linkDest := filepath.Join(a.pluginsPath, "grafana-pyroscope-app") + linkSource, err := filepath.Rel(a.pluginsPath, filepath.Join(pluginPath, "grafana-pyroscope-app")) + if err != nil { + return err + } + + stat, err := os.Lstat(linkDest) + if err == nil { + if stat.Mode()&os.ModeSymlink == os.ModeSymlink { + // already existing and symlink + target, err := os.Readlink(filepath.Join(a.pluginsPath, "grafana-pyroscope-app")) + if err != nil { + return err + } + + if target == linkSource { + return nil + } + + // recreate the symlink if it points to a different path + err = os.Remove(linkDest) + if err != nil { + return err + } + } else { + return fmt.Errorf("file exists and is not a symlink: %+#v", stat) + } + } else if !os.IsNotExist(err) { + return err + } + + return os.Symlink(linkSource, linkDest) +} + +func writeYAML(logger log.Logger, path string, data interface{}) error { + err := os.MkdirAll(filepath.Dir(path), modeDir) + if err != nil { + return err + } + + f, err := os.Create(path) + defer func() { + err := f.Close() + if err != nil { + level.Error(logger).Log("msg", "failed to close file", "path", path, "err", err) + } + }() + if err != nil { + return err + } + + _, err = f.Write([]byte("# Note: Do not edit this file directly. It is managed by pyroscope.\n")) + if err != nil { + return err + } + + yamlData, err := yaml.Marshal(data) + if err != nil { + return err + } + + _, err = f.Write(yamlData) + return err + +} + +func (a *app) provisioningDatasource(_ context.Context) error { + return writeYAML( + a.logger, + filepath.Join(a.provisioningPath, "datasources", "embedded-grafana.yaml"), + map[string]interface{}{ + "apiVersion": 1, + "datasources": []interface{}{ + map[string]interface{}{ + "uid": "pyroscope", + "type": "grafana-pyroscope-datasource", + "name": "Pyroscope", + "url": a.cfg.PyroscopeURL, + "jsonData": map[string]interface{}{ + "keepCookies": []string{"pyroscope_git_session"}, + "overridesDefault": true, + }, + }, + }, + }, + ) +} + +func (a *app) provisioningPlugins(_ context.Context) error { + return writeYAML( + a.logger, + filepath.Join(a.provisioningPath, "plugins", "embedded-grafana.yaml"), + map[string]interface{}{ + "apiVersion": 1, + "apps": []interface{}{ + map[string]interface{}{ + "type": "grafana-pyroscope-app", + }, + }, + }, + ) +} + +func (a *app) starting(ctx context.Context) error { + if a.exploreProfileRelease != nil { + err := a.downloadExploreProfiles(ctx) + if err != nil { + return err + } + } + + err := a.provisioningDatasource(ctx) + if err != nil { + return err + } + + err = a.provisioningPlugins(ctx) + if err != nil { + return err + } + + grafanaPath, err := a.grafanaRelease.download(ctx, a.logger, a.cfg.DataPath) + if err != nil { + return err + } + + cmd := exec.Command( + filepath.Join(grafanaPath, "bin/grafana"), + "server", + "--homepath", + grafanaPath, + ) + cmd.Dir = a.cfg.DataPath + cmd.Env = os.Environ() + setIfNotExists := func(key, value string) { + if os.Getenv(key) == "" { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value)) + } + } + setIfNotExists("GF_PLUGINS_PREINSTALL_DISABLED", "true") // required so we can load the version we have bundled + setIfNotExists("GF_PATHS_DATA", a.dataPath) + setIfNotExists("GF_PATHS_PLUGINS", a.pluginsPath) + setIfNotExists("GF_PATHS_PROVISIONING", a.provisioningPath) + setIfNotExists("GF_AUTH_ANONYMOUS_ENABLED", "true") + setIfNotExists("GF_AUTH_ANONYMOUS_ORG_ROLE", "Admin") + setIfNotExists("GF_AUTH_DISABLE_LOGIN_FORM", "true") + setIfNotExists("GF_SERVER_HTTP_PORT", strconv.Itoa(a.cfg.ListenPort)) + setIfNotExists("GF_LOG_LEVEL", "error") + + a.g, _ = errgroup.WithContext(ctx) + + stdout, err := cmd.StdoutPipe() + if err != nil { + return err + } + a.g.Go(func() error { + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + level.Info(a.logger).Log("stream", "stdout", "msg", scanner.Text()) + } + return scanner.Err() + }) + + stderr, err := cmd.StderrPipe() + if err != nil { + return err + } + a.g.Go(func() error { + scanner := bufio.NewScanner(stderr) + for scanner.Scan() { + level.Info(a.logger).Log("stream", "stderr", "msg", scanner.Text()) + } + return scanner.Err() + }) + + if err = cmd.Start(); err != nil { + return err + } + + a.g.Go(func() error { + <-ctx.Done() + return cmd.Process.Signal(syscall.SIGINT) + }) + + a.g.Go(cmd.Wait) + + return nil +} + +func (a *app) stopping(failureCase error) error { + return nil +} + +func (a *app) running(ctx context.Context) error { + return a.g.Wait() +} diff --git a/pkg/featureflags/client_capability.go b/pkg/featureflags/client_capability.go new file mode 100644 index 0000000000..36ec47085c --- /dev/null +++ b/pkg/featureflags/client_capability.go @@ -0,0 +1,117 @@ +package featureflags + +import ( + "context" + "mime" + "net/http" + "strings" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/middleware" + "github.com/grafana/pyroscope/v2/pkg/util" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +const ( + // Capability names - update parseClientCapabilities below when new capabilities added + allowUtf8LabelNamesCapabilityName string = "allow-utf8-labelnames" +) + +// Define a custom context key type to avoid collisions +type contextKey struct{} + +type ClientCapabilities struct { + AllowUtf8LabelNames bool +} + +func WithClientCapabilities(ctx context.Context, clientCapabilities ClientCapabilities) context.Context { + return context.WithValue(ctx, contextKey{}, clientCapabilities) +} + +func GetClientCapabilities(ctx context.Context) (ClientCapabilities, bool) { + value, ok := ctx.Value(contextKey{}).(ClientCapabilities) + return value, ok +} + +func ClientCapabilitiesGRPCMiddleware() grpc.UnaryServerInterceptor { + return func( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, + ) (interface{}, error) { + // Extract metadata from context + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return handler(ctx, req) + } + + // Convert metadata to http.Header for reuse of existing parsing logic + httpHeader := make(http.Header) + for key, values := range md { + // gRPC metadata keys are lowercase, HTTP headers are case-insensitive + httpHeader[http.CanonicalHeaderKey(key)] = values + } + + // Reuse existing HTTP header parsing + clientCapabilities, err := parseClientCapabilities(httpHeader) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + enhancedCtx := WithClientCapabilities(ctx, clientCapabilities) + return handler(enhancedCtx, req) + } +} + +// ClientCapabilitiesHttpMiddleware creates middleware that extracts and parses the +// `Accept` header for capabilities the client supports +func ClientCapabilitiesHttpMiddleware() middleware.Interface { + return middleware.Func(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + clientCapabilities, err := parseClientCapabilities(r.Header) + if err != nil { + http.Error(w, "Invalid header format: "+err.Error(), http.StatusBadRequest) + return + } + + ctx := WithClientCapabilities(r.Context(), clientCapabilities) + next.ServeHTTP(w, r.WithContext(ctx)) + }) + }) +} + +func parseClientCapabilities(header http.Header) (ClientCapabilities, error) { + acceptHeaderValues := header.Values("Accept") + + var capabilities ClientCapabilities + + for _, acceptHeaderValue := range acceptHeaderValues { + if acceptHeaderValue != "" { + accepts := strings.Split(acceptHeaderValue, ",") + + for _, accept := range accepts { + if _, params, err := mime.ParseMediaType(accept); err != nil { + return capabilities, err + } else { + for k, v := range params { + switch k { + case allowUtf8LabelNamesCapabilityName: + if v == "true" { + capabilities.AllowUtf8LabelNames = true + } + default: + level.Debug(util.Logger).Log( + "msg", "unknown capability parsed from Accept header", + "acceptHeaderKey", k, + "acceptHeaderValue", v) + } + } + } + } + } + } + return capabilities, nil +} diff --git a/pkg/featureflags/client_capability_test.go b/pkg/featureflags/client_capability_test.go new file mode 100644 index 0000000000..85d284deca --- /dev/null +++ b/pkg/featureflags/client_capability_test.go @@ -0,0 +1,239 @@ +package featureflags + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_parseClientCapabilities(t *testing.T) { + tests := []struct { + Name string + Header http.Header + Want ClientCapabilities + WantError bool + ErrorMessage string + }{ + { + Name: "empty header returns default capabilities", + Header: http.Header{}, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + { + Name: "no Accept header returns default capabilities", + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + { + Name: "empty Accept header value returns default capabilities", + Header: http.Header{ + "Accept": []string{""}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + { + Name: "simple Accept header without capabilities", + Header: http.Header{ + "Accept": []string{"application/json"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + { + Name: "Accept header with utf8 label names capability true", + Header: http.Header{ + "Accept": []string{"*/*; allow-utf8-labelnames=true"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "Accept header with utf8 label names capability false", + Header: http.Header{ + "Accept": []string{"*/*; allow-utf8-labelnames=false"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + { + Name: "Accept header with utf8 label names capability invalid value", + Header: http.Header{ + "Accept": []string{"*/*; allow-utf8-labelnames=invalid"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + { + Name: "Accept header with unknown capability", + Header: http.Header{ + "Accept": []string{"*/*; unknown-capability=true"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + { + Name: "Accept header with multiple capabilities", + Header: http.Header{ + "Accept": []string{"*/*; allow-utf8-labelnames=true; unknown-capability=false"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "multiple Accept header values", + Header: http.Header{ + "Accept": []string{"application/json", "*/*; allow-utf8-labelnames=true"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "multiple Accept header values with different capabilities", + Header: http.Header{ + "Accept": []string{ + "application/json; allow-utf8-labelnames=false", + "*/*; allow-utf8-labelnames=true", + }, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "Accept header with quality values", + Header: http.Header{ + "Accept": []string{"text/html; q=0.9; allow-utf8-labelnames=true"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "complex Accept header", + Header: http.Header{ + "Accept": []string{ + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8;allow-utf8-labelnames=true", + }, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "multiple Accept header entries", + Header: http.Header{ + "Accept": []string{ + "application/json", + "text/plain; allow-utf8-labelnames=true", + "*/*; q=0.1", + }, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "invalid mime type in Accept header", + Header: http.Header{ + "Accept": []string{"invalid/mime/type/format"}, + }, + Want: ClientCapabilities{}, + WantError: true, + ErrorMessage: "mime: unexpected content after media subtype", + }, + { + Name: "Accept header with invalid syntax", + Header: http.Header{ + "Accept": []string{"text/html; invalid-parameter-syntax"}, + }, + Want: ClientCapabilities{}, + WantError: true, + ErrorMessage: "mime: invalid media parameter", + }, + { + Name: "mixed valid and invalid Accept header values", + Header: http.Header{ + "Accept": []string{ + "application/json", + "invalid/mime/type/format", + }, + }, + Want: ClientCapabilities{}, + WantError: true, + ErrorMessage: "mime: unexpected content after media subtype", + }, + { + // Parameter names are case-insensitive in mime.ParseMediaType + Name: "case sensitivity test for capability name", + Header: http.Header{ + "Accept": []string{"*/*; Allow-Utf8-Labelnames=true"}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "whitespace handling in Accept header", + Header: http.Header{ + "Accept": []string{" application/json ; allow-utf8-labelnames=true "}, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + + got, err := parseClientCapabilities(tt.Header) + + if tt.WantError { + require.Error(t, err) + if tt.ErrorMessage != "" { + require.Contains(t, err.Error(), tt.ErrorMessage) + } + return + } + + require.NoError(t, err) + require.Equal(t, tt.Want, got) + }) + } +} + +func Test_parseClientCapabilities_MultipleCapabilities(t *testing.T) { + // This test specifically checks that when the same capability appears + // multiple times with different values, the last "true" value wins + tests := []struct { + Name string + Header http.Header + Want ClientCapabilities + }{ + { + Name: "capability appears multiple times - last true wins", + Header: http.Header{ + "Accept": []string{ + "application/json; allow-utf8-labelnames=false", + "text/plain; allow-utf8-labelnames=true", + }, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "capability appears multiple times - last false loses to earlier true", + Header: http.Header{ + "Accept": []string{ + "application/json; allow-utf8-labelnames=true", + "text/plain; allow-utf8-labelnames=false", + }, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: true}, + }, + { + Name: "capability appears multiple times - all false", + Header: http.Header{ + "Accept": []string{ + "application/json; allow-utf8-labelnames=false", + "text/plain; allow-utf8-labelnames=false", + }, + }, + Want: ClientCapabilities{AllowUtf8LabelNames: false}, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + + got, err := parseClientCapabilities(tt.Header) + require.NoError(t, err) + require.Equal(t, tt.Want, got) + }) + } +} diff --git a/pkg/featureflags/feature_flags.go b/pkg/featureflags/feature_flags.go new file mode 100644 index 0000000000..d73ab26018 --- /dev/null +++ b/pkg/featureflags/feature_flags.go @@ -0,0 +1,93 @@ +package featureflags + +import ( + "context" + "sort" + + "connectrpc.com/connect" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + capabilitiesv1 "github.com/grafana/pyroscope/api/gen/proto/go/capabilities/v1" +) + +const ( + V2StorageLayer = "v2StorageLayer" + PyroscopeRuler = "pyroscopeRuler" + PyroscopeRulerFunctions = "pyroscopeRulerFunctions" + UTF8LabelNames = "utf8LabelNames" +) + +func stringPtr(s string) *string { + return &s +} + +var ( + allFeatureFlags = map[string]*capabilitiesv1.FeatureFlag{ + V2StorageLayer: { + Enabled: false, + Description: stringPtr("v2 storage layer"), + DocumentationUrl: stringPtr("https://github.com/grafana/pyroscope/blob/main/pkg/pyroscope/PYROSCOPE_V2.md"), + }, + PyroscopeRuler: { + Enabled: false, + Description: stringPtr("Supports the Pyroscope ruler, which exports Prometheus metrics from Profiling Data."), + }, + PyroscopeRulerFunctions: { + Enabled: false, + Description: stringPtr("Enables function support for the Pyroscope ruler, which allows to export resource usage on a per function level."), + }, + UTF8LabelNames: { + Enabled: false, + Description: stringPtr("Supports UTF-8 label names for Pyroscope read/write APIs."), + }, + } +) + +type FeatureFlags struct { + flags []*capabilitiesv1.FeatureFlag + infoMetric *prometheus.GaugeVec +} + +func (h *FeatureFlags) GetFeatureFlags( + ctx context.Context, + req *connect.Request[capabilitiesv1.GetFeatureFlagsRequest], +) (*connect.Response[capabilitiesv1.GetFeatureFlagsResponse], error) { + return &connect.Response[capabilitiesv1.GetFeatureFlagsResponse]{ + Msg: &capabilitiesv1.GetFeatureFlagsResponse{ + FeatureFlags: h.flags, + }, + }, nil +} + +func boolToFloat64(b bool) float64 { + if b { + return 1.0 + } + return 0.0 +} + +func NewFromEnabled(reg prometheus.Registerer, enabled map[string]bool) *FeatureFlags { + ff := &FeatureFlags{ + infoMetric: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Name: "pyroscope_feature_flags_enabled", + Help: "Shows the global feature flags", + }, []string{"name"}), + } + + ff.flags = make([]*capabilitiesv1.FeatureFlag, 0, len(allFeatureFlags)) + for name, flag := range allFeatureFlags { + flag := flag.CloneVT() + flag.Name = name + ff.flags = append(ff.flags, flag) + flag.Enabled = enabled[name] + enabled[name] = true + ff.infoMetric.WithLabelValues(flag.Name).Set(boolToFloat64(flag.Enabled)) + } + sort.Slice(ff.flags, func(i, j int) bool { + return ff.flags[i].Name < ff.flags[j].Name + + }) + + return ff +} diff --git a/pkg/frontend/async/coordinator.go b/pkg/frontend/async/coordinator.go new file mode 100644 index 0000000000..7e7ce1effb --- /dev/null +++ b/pkg/frontend/async/coordinator.go @@ -0,0 +1,147 @@ +package async + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/google/uuid" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +type Limits interface { + MaxAsyncQueryConcurrency(tenantID string) int +} + +// QueryResult is the result of a query execution sent over a channel. +// On success, Response carries the raw SelectMergeStacktracesResponse +// from the wrapped handler (its Async field is unset); the +// coordinator/store own request_id and status. +type QueryResult struct { + Response *querierv1.SelectMergeStacktracesResponse + Err error +} + +type Coordinator struct { + logger log.Logger + store *Store + limits Limits + + mu sync.Mutex + inFlight map[string]int // tenantID -> count + + asyncQueriesCurrent *prometheus.GaugeVec + asyncQueriesMax *prometheus.GaugeVec +} + +func NewCoordinator(logger log.Logger, store *Store, limits Limits, reg prometheus.Registerer) *Coordinator { + return &Coordinator{ + logger: logger, + store: store, + limits: limits, + inFlight: make(map[string]int), + asyncQueriesCurrent: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Name: "pyroscope_async_queries_in_progress", + Help: "Number of async queries currently in progress.", + }, []string{"tenant"}), + asyncQueriesMax: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Name: "pyroscope_async_queries_max", + Help: "Maximum number of concurrent async queries allowed per tenant.", + }, []string{"tenant"}), + } +} + +func (c *Coordinator) tryAcquire(tenantID string) error { + maxConcurrent := c.limits.MaxAsyncQueryConcurrency(tenantID) + c.asyncQueriesMax.WithLabelValues(tenantID).Set(float64(maxConcurrent)) + + if maxConcurrent <= 0 { + return fmt.Errorf("async queries are disabled for tenant %s", tenantID) + } + + c.mu.Lock() + defer c.mu.Unlock() + + if c.inFlight[tenantID] >= maxConcurrent { + return fmt.Errorf("tenant %s has reached the maximum number of concurrent async queries (%d)", tenantID, maxConcurrent) + } + c.inFlight[tenantID]++ + c.asyncQueriesCurrent.WithLabelValues(tenantID).Set(float64(c.inFlight[tenantID])) + return nil +} + +// Register reserves the per-tenant concurrency slot, persists the +// in-progress metadata, and starts watching resultCh. The caller is +// responsible for dispatching the query and sending its outcome on +// resultCh; the coordinator owns reads from the channel, store writes, +// and the heartbeat loop. Returns the assigned request ID, or an error +// if the slot could not be acquired. +func (c *Coordinator) Register(ctx context.Context, tenantID string, resultCh <-chan QueryResult) (string, error) { + if err := c.tryAcquire(tenantID); err != nil { + return "", err + } + + requestID := uuid.New().String() + + if err := c.store.create(ctx, tenantID, requestID); err != nil { + c.decrement(tenantID) + return "", fmt.Errorf("failed to create async query: %w", err) + } + + go c.awaitResult(tenantID, requestID, resultCh) + + return requestID, nil +} + +func (c *Coordinator) awaitResult(tenantID, requestID string, resultCh <-chan QueryResult) { + defer c.decrement(tenantID) + + ctx := tenant.InjectTenantID(context.Background(), tenantID) + + ticker := time.NewTicker(c.store.heartbeatInterval) + defer ticker.Stop() + + for { + select { + case res := <-resultCh: + if res.Err != nil { + level.Error(c.logger).Log("msg", "async query failed", "tenant", tenantID, "request_id", requestID, "err", res.Err) + if storeErr := c.store.fail(ctx, tenantID, requestID, res.Err); storeErr != nil { + level.Error(c.logger).Log("msg", "failed to store async query failure", "tenant", tenantID, "request_id", requestID, "err", storeErr) + } + return + } + if err := c.store.complete(ctx, tenantID, requestID, res.Response); err != nil { + level.Error(c.logger).Log("msg", "failed to store async query result", "tenant", tenantID, "request_id", requestID, "err", err) + } + return + case <-ticker.C: + if err := c.store.heartbeat(ctx, tenantID, requestID); err != nil { + level.Warn(c.logger).Log("msg", "failed to update heartbeat", "tenant", tenantID, "request_id", requestID, "err", err) + } + } + } +} + +func (c *Coordinator) decrement(tenantID string) { + c.mu.Lock() + c.inFlight[tenantID]-- + if c.inFlight[tenantID] <= 0 { + delete(c.inFlight, tenantID) + } + c.asyncQueriesCurrent.WithLabelValues(tenantID).Set(float64(c.inFlight[tenantID])) + c.mu.Unlock() +} + +// PollQuery checks the status of an async query for the given tenant. +// Returns nil if the request is not found (caller should return NotFound). +func (c *Coordinator) PollQuery(ctx context.Context, tenantID, requestID string) (*Result, error) { + return c.store.get(ctx, tenantID, requestID) +} diff --git a/pkg/frontend/async/handler.go b/pkg/frontend/async/handler.go new file mode 100644 index 0000000000..c04ab8e1c9 --- /dev/null +++ b/pkg/frontend/async/handler.go @@ -0,0 +1,135 @@ +package async + +import ( + "context" + "errors" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + "google.golang.org/protobuf/proto" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + pyrotenant "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +// Handler decorates a QuerierServiceHandler with async query support for +// SelectMergeStacktraces. All other RPCs pass through to the embedded +// handler unchanged. +type Handler struct { + querierv1connect.QuerierServiceHandler + coordinator *Coordinator +} + +func NewHandler(next querierv1connect.QuerierServiceHandler, coordinator *Coordinator) *Handler { + return &Handler{ + QuerierServiceHandler: next, + coordinator: coordinator, + } +} + +// SelectMergeStacktraces honors the request's optional Async field: +// - Async == nil or Type == DISABLED: run synchronously, return the +// wrapped handler's response unchanged (Async stays nil). +// - Async.RequestId != "": treat as a poll. All other request fields +// are ignored. The response carries only the Async metadata, plus +// the result payload on SUCCESS. +// - Async.Type == FORCE with empty RequestId: dispatch in the +// background and return a response carrying only the Async +// metadata in IN_PROGRESS. +func (h *Handler) SelectMergeStacktraces( + ctx context.Context, + req *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + async := req.Msg.GetAsync() + if async == nil || async.GetType() == querierv1.AsyncQueryType_ASYNC_QUERY_TYPE_DISABLED { + return h.QuerierServiceHandler.SelectMergeStacktraces(ctx, req) + } + + if h.coordinator == nil { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("async queries are disabled (set -query-frontend.async-queries-enabled=true)")) + } + + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + tenantID := tenant.JoinTenantIDs(tenantIDs) + + if async.GetRequestId() != "" { + return h.poll(ctx, tenantID, async.GetRequestId()) + } + return h.submit(ctx, tenantID, req.Msg) +} + +func (h *Handler) submit( + ctx context.Context, + tenantID string, + req *querierv1.SelectMergeStacktracesRequest, +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + queryCtx := pyrotenant.InjectTenantID(context.Background(), tenantID) + resultCh := make(chan QueryResult, 1) + + // Strip the Async marker before dispatching so the wrapped handler + // treats this as an ordinary sync request. + inner := proto.Clone(req).(*querierv1.SelectMergeStacktracesRequest) + inner.Async = nil + + // Reserve the concurrency slot before dispatching so a rejected + // submit never starts background work. + requestID, err := h.coordinator.Register(ctx, tenantID, resultCh) + if err != nil { + return nil, connect.NewError(connect.CodeResourceExhausted, err) + } + + go func() { + resp, err := h.QuerierServiceHandler.SelectMergeStacktraces(queryCtx, connect.NewRequest(inner)) + if err != nil { + resultCh <- QueryResult{Err: err} + return + } + resultCh <- QueryResult{Response: resp.Msg} + }() + + return connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Async: &querierv1.AsyncQueryResponse{ + RequestId: requestID, + Status: querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_IN_PROGRESS, + }, + }), nil +} + +func (h *Handler) poll( + ctx context.Context, + tenantID string, + requestID string, +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + result, err := h.coordinator.PollQuery(ctx, tenantID, requestID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + if result == nil { + return nil, connect.NewError(connect.CodeNotFound, errors.New("async query not found")) + } + + resp := &querierv1.SelectMergeStacktracesResponse{ + Async: &querierv1.AsyncQueryResponse{RequestId: requestID}, + } + switch result.Metadata.Status { + case StatusInProgress: + resp.Async.Status = querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_IN_PROGRESS + case StatusSuccess: + resp.Async.Status = querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_SUCCESS + if result.Response != nil { + resp.Flamegraph = result.Response.Flamegraph + resp.Tree = result.Response.Tree + resp.Dot = result.Response.Dot + resp.Pprof = result.Response.Pprof + } + case StatusFailure: + resp.Async.Status = querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_FAILURE + resp.Async.ErrorMessage = result.Metadata.ErrorMessage + } + + return connect.NewResponse(resp), nil +} diff --git a/pkg/frontend/async/handler_test.go b/pkg/frontend/async/handler_test.go new file mode 100644 index 0000000000..04ffcd03fc --- /dev/null +++ b/pkg/frontend/async/handler_test.go @@ -0,0 +1,35 @@ +package async + +import ( + "context" + "testing" + + "github.com/go-kit/log" + "github.com/stretchr/testify/require" + "github.com/thanos-io/objstore" + "google.golang.org/protobuf/proto" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" +) + +func TestHandlerPollCopiesPprofResponse(t *testing.T) { + ctx := context.Background() + store := NewStore(log.NewNopLogger(), objstore.NewInMemBucket()) + const ( + tenantID = "tenant-a" + requestID = "550e8400-e29b-41d4-a716-446655440000" + ) + require.NoError(t, store.create(ctx, tenantID, requestID)) + want := &profilev1.Profile{Sample: []*profilev1.Sample{{Value: []int64{1}}}} + require.NoError(t, store.complete(ctx, tenantID, requestID, &querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{Profile: want}, + })) + + handler := &Handler{coordinator: &Coordinator{store: store}} + resp, err := handler.poll(ctx, tenantID, requestID) + + require.NoError(t, err) + require.Equal(t, querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_SUCCESS, resp.Msg.GetAsync().GetStatus()) + require.True(t, proto.Equal(want, resp.Msg.GetPprof().GetProfile())) +} diff --git a/pkg/frontend/async/store.go b/pkg/frontend/async/store.go new file mode 100644 index 0000000000..c2be1557e1 --- /dev/null +++ b/pkg/frontend/async/store.go @@ -0,0 +1,279 @@ +package async + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "strings" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/google/uuid" + "github.com/grafana/dskit/services" + "github.com/thanos-io/objstore" + "google.golang.org/protobuf/proto" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" +) + +const ( + storagePrefix = "async-queries/" + defaultTTL = 30 * time.Minute + defaultHeartbeatInterval = 15 * time.Second + defaultHeartbeatTimeout = 45 * time.Second + cleanupInterval = 5 * time.Minute +) + +// Status represents the lifecycle state of an async query. +type Status string + +const ( + // StatusInProgress indicates the query is still executing. + StatusInProgress Status = "in_progress" + // StatusSuccess indicates the query completed and a result is available. + StatusSuccess Status = "success" + // StatusFailure indicates the query failed; ErrorMessage holds the reason. + StatusFailure Status = "failure" +) + +// Metadata describes the state of a single async query. It is persisted as +// metadata.json alongside the query's result in object storage. +type Metadata struct { + RequestID string `json:"request_id"` + TenantID string `json:"tenant_id"` + Status Status `json:"status"` + CreatedAt time.Time `json:"created_at"` + LastHeartbeat time.Time `json:"last_heartbeat,omitempty"` + ErrorMessage string `json:"error_message,omitempty"` +} + +// Result bundles a query's Metadata with its decoded Response. Response is only +// populated when Metadata.Status is StatusSuccess. +type Result struct { + Metadata Metadata + Response *querierv1.SelectMergeStacktracesResponse +} + +// Store persists async query state and results in object storage. It also runs +// as a dskit service that periodically removes expired entries. +type Store struct { + services.Service + logger log.Logger + bucket objstore.Bucket + ttl time.Duration + heartbeatInterval time.Duration + heartbeatTimeout time.Duration +} + +// NewStore returns a Store backed by the given bucket. The returned Store is a +// dskit service that, once started, periodically deletes entries older than the +// configured TTL; callers are responsible for starting and stopping it via its +// embedded Service. +func NewStore(logger log.Logger, bucket objstore.Bucket) *Store { + s := &Store{ + logger: logger, + bucket: bucket, + ttl: defaultTTL, + heartbeatInterval: defaultHeartbeatInterval, + heartbeatTimeout: defaultHeartbeatTimeout, + } + s.Service = services.NewBasicService(s.starting, s.running, s.stopping) + return s +} + +func (s *Store) basePath(tenantID, requestID string) string { + return storagePrefix + tenantID + "/" + requestID + "/" +} + +func (s *Store) create(ctx context.Context, tenantID, requestID string) error { + now := time.Now().UTC() + meta := &Metadata{ + RequestID: requestID, + TenantID: tenantID, + Status: StatusInProgress, + CreatedAt: now, + LastHeartbeat: now, + } + return s.saveJSON(ctx, s.basePath(tenantID, requestID)+"metadata.json", meta) +} + +func (s *Store) heartbeat(ctx context.Context, tenantID, requestID string) error { + base := s.basePath(tenantID, requestID) + var meta Metadata + if err := s.readJSON(ctx, base+"metadata.json", &meta); err != nil { + return err + } + meta.LastHeartbeat = time.Now().UTC() + return s.saveJSON(ctx, base+"metadata.json", &meta) +} + +func (s *Store) complete(ctx context.Context, tenantID, requestID string, resp *querierv1.SelectMergeStacktracesResponse) error { + base := s.basePath(tenantID, requestID) + + data, err := proto.Marshal(resp) + if err != nil { + return fmt.Errorf("failed to marshal response: %w", err) + } + if err := s.bucket.Upload(ctx, base+"result.pb", bytes.NewReader(data)); err != nil { + return fmt.Errorf("failed to upload result: %w", err) + } + + var meta Metadata + if err := s.readJSON(ctx, base+"metadata.json", &meta); err != nil { + return fmt.Errorf("failed to read metadata: %w", err) + } + meta.Status = StatusSuccess + meta.LastHeartbeat = time.Now().UTC() + return s.saveJSON(ctx, base+"metadata.json", &meta) +} + +func (s *Store) fail(ctx context.Context, tenantID, requestID string, queryErr error) error { + base := s.basePath(tenantID, requestID) + var meta Metadata + if err := s.readJSON(ctx, base+"metadata.json", &meta); err != nil { + return fmt.Errorf("failed to read metadata: %w", err) + } + meta.Status = StatusFailure + meta.ErrorMessage = queryErr.Error() + meta.LastHeartbeat = time.Now().UTC() + return s.saveJSON(ctx, base+"metadata.json", &meta) +} + +func (s *Store) get(ctx context.Context, tenantID, requestID string) (*Result, error) { + if _, err := uuid.Parse(requestID); err != nil { + return nil, fmt.Errorf("invalid request ID: %w", err) + } + + base := s.basePath(tenantID, requestID) + + var meta Metadata + if err := s.readJSON(ctx, base+"metadata.json", &meta); err != nil { + if s.bucket.IsObjNotFoundErr(err) { + return nil, nil + } + return nil, fmt.Errorf("failed to read metadata: %w", err) + } + + // Tenant isolation: the metadata must belong to the requesting tenant. + if meta.TenantID != tenantID { + return nil, nil + } + + if meta.Status == StatusInProgress && !meta.LastHeartbeat.IsZero() && time.Since(meta.LastHeartbeat) > s.heartbeatTimeout { + meta.Status = StatusFailure + meta.ErrorMessage = "query appears to have been orphaned (heartbeat timed out)" + } + + result := &Result{Metadata: meta} + + if meta.Status == StatusSuccess { + data, err := s.readRaw(ctx, base+"result.pb") + if err != nil { + return nil, fmt.Errorf("failed to read result: %w", err) + } + var resp querierv1.SelectMergeStacktracesResponse + if err := proto.Unmarshal(data, &resp); err != nil { + return nil, fmt.Errorf("failed to unmarshal result: %w", err) + } + result.Response = &resp + } + + return result, nil +} + +func (s *Store) cleanup(ctx context.Context) (int, error) { + cutoff := time.Now().Add(-s.ttl) + deleted := 0 + + err := s.bucket.Iter(ctx, storagePrefix, func(name string) error { + if strings.HasSuffix(name, "/") { + return nil + } + + attrs, err := s.bucket.Attributes(ctx, name) + if err != nil { + level.Warn(s.logger).Log("msg", "failed to get attributes", "object", name, "err", err) + return nil + } + + if attrs.LastModified.Before(cutoff) { + if err := s.bucket.Delete(ctx, name); err != nil { + level.Warn(s.logger).Log("msg", "failed to delete old async query result", "object", name, "err", err) + } else { + deleted++ + } + } + return nil + }, objstore.WithRecursiveIter()) + + if err != nil { + return deleted, fmt.Errorf("cleanup iteration failed: %w", err) + } + + return deleted, nil +} + +func (s *Store) saveJSON(ctx context.Context, path string, v any) error { + data, err := json.Marshal(v) + if err != nil { + return err + } + return s.bucket.Upload(ctx, path, bytes.NewReader(data)) +} + +func (s *Store) readJSON(ctx context.Context, path string, v any) error { + reader, err := s.bucket.Get(ctx, path) + if err != nil { + return err + } + defer reader.Close() + + data, err := io.ReadAll(reader) + if err != nil { + return fmt.Errorf("failed to read: %w", err) + } + + return json.Unmarshal(data, v) +} + +func (s *Store) readRaw(ctx context.Context, path string) ([]byte, error) { + reader, err := s.bucket.Get(ctx, path) + if err != nil { + return nil, err + } + defer reader.Close() + return io.ReadAll(reader) +} + +func (s *Store) starting(context.Context) error { return nil } +func (s *Store) stopping(error) error { return nil } + +func (s *Store) running(ctx context.Context) error { + ticker := time.NewTicker(cleanupInterval) + defer ticker.Stop() + + s.runCleanup(ctx) + + for { + select { + case <-ctx.Done(): + return nil + case <-ticker.C: + s.runCleanup(ctx) + } + } +} + +func (s *Store) runCleanup(ctx context.Context) { + deleted, err := s.cleanup(ctx) + if err != nil { + level.Warn(s.logger).Log("msg", "async query cleanup failed", "err", err) + return + } + if deleted > 0 { + level.Info(s.logger).Log("msg", "cleaned up old async query results", "deleted", deleted) + } +} diff --git a/pkg/frontend/dot/convert.go b/pkg/frontend/dot/convert.go new file mode 100644 index 0000000000..b89a739dfc --- /dev/null +++ b/pkg/frontend/dot/convert.go @@ -0,0 +1,37 @@ +package dot + +import ( + "bytes" + "io" + + "github.com/google/pprof/profile" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/dot/graph" + "github.com/grafana/pyroscope/v2/pkg/frontend/dot/report" +) + +// FromProfile converts a pprof profile to a DOT graph string. +func FromProfile(p *profilev1.Profile, maxNodes int) (string, error) { + var buf bytes.Buffer + if err := WriteFromProfile(&buf, p, maxNodes); err != nil { + return "", err + } + return buf.String(), nil +} + +// WriteFromProfile writes a pprof profile as a DOT graph to the given writer. +func WriteFromProfile(w io.Writer, p *profilev1.Profile, maxNodes int) error { + data, err := p.MarshalVT() + if err != nil { + return err + } + pr, err := profile.ParseData(data) + if err != nil { + return err + } + rpt := report.NewDefault(pr, report.Options{NodeCount: maxNodes}) + gr, cfg := report.GetDOT(rpt) + graph.ComposeDot(w, gr, &graph.DotAttributes{}, cfg) + return nil +} diff --git a/pkg/frontend/dot/graph/dotgraph.go b/pkg/frontend/dot/graph/dotgraph.go index 0de5532590..a39404e327 100644 --- a/pkg/frontend/dot/graph/dotgraph.go +++ b/pkg/frontend/dot/graph/dotgraph.go @@ -21,7 +21,7 @@ import ( "path/filepath" "strings" - "github.com/grafana/pyroscope/pkg/frontend/dot/measurement" + "github.com/grafana/pyroscope/v2/pkg/frontend/dot/measurement" ) // DotAttributes contains details about the graph itself, giving @@ -291,10 +291,10 @@ func (b *builder) addEdge(edge *Edge, from, to int, hasNodelets bool) { attr := fmt.Sprintf(`label=" %s%s"`, w, inline) if b.config.Total != 0 { // Note: edge.weight > b.config.Total is possible for profile diffs. - if weight := 1 + int(min64(abs64(edge.WeightValue()*100/b.config.Total), 100)); weight > 1 { + if weight := 1 + int(min(abs64(edge.WeightValue()*100/b.config.Total), 100)); weight > 1 { attr = fmt.Sprintf(`%s weight=%d`, attr, weight) } - if width := 1 + int(min64(abs64(edge.WeightValue()*5/b.config.Total), 5)); width > 1 { + if width := 1 + int(min(abs64(edge.WeightValue()*5/b.config.Total), 5)); width > 1 { attr = fmt.Sprintf(`%s penwidth=%d`, attr, width) } attr = fmt.Sprintf(`%s color="%s"`, attr, @@ -354,7 +354,7 @@ func dotColor(score float64, isBackground bool) string { } // Limit the score values to the range [-1.0, 1.0]. - score = math.Max(-1.0, math.Min(1.0, score)) + score = max(-1.0, min(1.0, score)) // Reduce saturation near score=0 (so it is colored grey, rather than yellow). if math.Abs(score) < 0.2 { @@ -384,11 +384,11 @@ func dotColor(score float64, isBackground bool) string { func multilinePrintableName(info *NodeInfo) string { infoCopy := *info infoCopy.Name = escapeForDot(ShortenFunctionName(infoCopy.Name)) - infoCopy.Name = strings.Replace(infoCopy.Name, "::", `\n`, -1) + infoCopy.Name = strings.ReplaceAll(infoCopy.Name, "::", `\n`) // Go type parameters are reported as "[...]" by Go pprof profiles. // Keep this ellipsis rather than replacing with newlines below. - infoCopy.Name = strings.Replace(infoCopy.Name, "[...]", "[…]", -1) - infoCopy.Name = strings.Replace(infoCopy.Name, ".", `\n`, -1) + infoCopy.Name = strings.ReplaceAll(infoCopy.Name, "[...]", "[…]") + infoCopy.Name = strings.ReplaceAll(infoCopy.Name, ".", `\n`) if infoCopy.File != "" { infoCopy.File = filepath.Base(infoCopy.File) } @@ -470,13 +470,6 @@ func (b *builder) tagGroupLabel(g []*Tag) (label string, flat, cum int64) { return measurement.Label(min.Value, min.Unit) + ".." + measurement.Label(max.Value, max.Unit), f, c } -func min64(a, b int64) int64 { - if a < b { - return a - } - return b -} - // escapeAllForDot applies escapeForDot to all strings in the given slice. func escapeAllForDot(in []string) []string { var out = make([]string, len(in)) diff --git a/pkg/frontend/dot/graph/graph.go b/pkg/frontend/dot/graph/graph.go index 7ddea47c47..c74fc80d5a 100644 --- a/pkg/frontend/dot/graph/graph.go +++ b/pkg/frontend/dot/graph/graph.go @@ -438,7 +438,7 @@ func newTree(prof *profile.Profile, o *Options) (g *Graph) { } } - nodes := make(Nodes, len(prof.Location)) + nodes := make(Nodes, 0, len(prof.Location)) for _, nm := range parentNodeMap { nodes = append(nodes, nm.nodes()...) } diff --git a/pkg/frontend/dot/report/report.go b/pkg/frontend/dot/report/report.go index 2c7ad740cb..fdff3fb59a 100644 --- a/pkg/frontend/dot/report/report.go +++ b/pkg/frontend/dot/report/report.go @@ -25,8 +25,8 @@ import ( "github.com/google/pprof/profile" - "github.com/grafana/pyroscope/pkg/frontend/dot/graph" - "github.com/grafana/pyroscope/pkg/frontend/dot/measurement" + "github.com/grafana/pyroscope/v2/pkg/frontend/dot/graph" + "github.com/grafana/pyroscope/v2/pkg/frontend/dot/measurement" ) // Options are the formatting and filtering options used to generate a diff --git a/pkg/frontend/frontend.go b/pkg/frontend/frontend.go index a55ae8f1b3..aa5aed280e 100644 --- a/pkg/frontend/frontend.go +++ b/pkg/frontend/frontend.go @@ -7,10 +7,13 @@ package frontend import ( "context" + "errors" "flag" "fmt" "math/rand" + "net" "net/http" + "strconv" "sync" "time" @@ -21,21 +24,22 @@ import ( "github.com/grafana/dskit/grpcclient" "github.com/grafana/dskit/netutil" "github.com/grafana/dskit/services" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "go.opentelemetry.io/otel" "go.uber.org/atomic" "github.com/grafana/dskit/tenant" - "github.com/grafana/pyroscope/pkg/frontend/frontendpb" - "github.com/grafana/pyroscope/pkg/querier/stats" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerdiscovery" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" - "github.com/grafana/pyroscope/pkg/util/httpgrpcutil" - "github.com/grafana/pyroscope/pkg/validation" + "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1/vcsv1connect" + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs" + "github.com/grafana/pyroscope/v2/pkg/querier/stats" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerdiscovery" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpcutil" + "github.com/grafana/pyroscope/v2/pkg/validation" ) // Config for a Frontend. @@ -45,12 +49,21 @@ type Config struct { WorkerConcurrency int `yaml:"scheduler_worker_concurrency" category:"advanced"` GRPCClientConfig grpcclient.Config `yaml:"grpc_client_config" doc:"description=Configures the gRPC client used to communicate between the query-frontends and the query-schedulers."` + // AsyncQueriesEnabled toggles the experimental async query path on + // SelectMergeStacktraces. Off by default; when false, the Async field + // on the request is rejected with Unimplemented. + AsyncQueriesEnabled bool `yaml:"async_queries_enabled" category:"experimental"` + // Used to find local IP address, that is sent to scheduler and querier-worker. - InfNames []string `yaml:"instance_interface_names" category:"advanced" doc:"default=[]"` + InfNames []string `yaml:"instance_interface_names" category:"advanced" doc:"default=[]"` + Addr string `yaml:"instance_addr" category:"advanced"` + EnableIPv6 bool `yaml:"instance_enable_ipv6" category:"advanced"` + Port int `yaml:"instance_port" category:"advanced"` - // If set, address is not computed from interfaces. - Addr string `yaml:"address" category:"advanced"` - Port int `yaml:"-"` + // For backward compatibility only. The parameter has a name that is + // inconsistent with the way address is specified in other places. + // The parameter is replaced with `instance_addr`. + AddrOld string `yaml:"address" category:"advanced" doc:"hidden"` // This configuration is injected internally. QuerySchedulerDiscovery schedulerdiscovery.Config `yaml:"-"` @@ -63,7 +76,9 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet, logger log.Logger) { cfg.InfNames = netutil.PrivateNetworkInterfacesWithFallback([]string{"eth0", "en0"}, logger) f.Var((*flagext.StringSlice)(&cfg.InfNames), "query-frontend.instance-interface-names", "List of network interface names to look up when finding the instance IP address. This address is sent to query-scheduler and querier, which uses it to send the query response back to query-frontend.") f.StringVar(&cfg.Addr, "query-frontend.instance-addr", "", "IP address to advertise to the querier (via scheduler) (default is auto-detected from network interfaces).") - + f.BoolVar(&cfg.EnableIPv6, "query-frontend.instance-enable-ipv6", false, "Enable using a IPv6 instance address. (default false)") + f.IntVar(&cfg.Port, "query-frontend.instance-port", 0, "Port to advertise to query-scheduler and querier (defaults to -server.http-listen-port).") + f.BoolVar(&cfg.AsyncQueriesEnabled, "query-frontend.async-queries-enabled", false, "Enable the experimental asynchronous query path on SelectMergeStacktraces (default false)") cfg.GRPCClientConfig.RegisterFlagsWithPrefix("query-frontend.grpc-client-config", f) } @@ -80,6 +95,8 @@ func (cfg *Config) Validate() error { type Frontend struct { services.Service connectgrpc.GRPCRoundTripper + vcsv1connect.VCSServiceHandler + frontendpb.UnimplementedFrontendForQuerierServer cfg Config log log.Logger @@ -93,7 +110,6 @@ type Frontend struct { schedulerWorkers *frontendSchedulerWorkers schedulerWorkersWatcher *services.FailureWatcher requests *requestsInProgress - frontendpb.UnimplementedFrontendForQuerierServer } type Limits interface { @@ -102,6 +118,9 @@ type Limits interface { MaxQueryLength(tenantID string) time.Duration MaxQueryLookback(tenantID string) time.Duration QueryAnalysisEnabled(string) bool + SymbolizerEnabled(string) bool + QuerySanitizeOnMerge(string) bool + QueryTreeEnabled(string) bool validation.FlameGraphLimits } @@ -137,7 +156,7 @@ type enqueueResult struct { func NewFrontend(cfg Config, limits Limits, log log.Logger, reg prometheus.Registerer) (*Frontend, error) { requestsCh := make(chan *frontendRequest) - schedulerWorkers, err := newFrontendSchedulerWorkers(cfg, fmt.Sprintf("%s:%d", cfg.Addr, cfg.Port), requestsCh, log, reg) + schedulerWorkers, err := newFrontendSchedulerWorkers(cfg, net.JoinHostPort(cfg.Addr, strconv.Itoa(cfg.Port)), requestsCh, log, reg) if err != nil { return nil, err } @@ -150,6 +169,7 @@ func NewFrontend(cfg Config, limits Limits, log log.Logger, reg prometheus.Regis schedulerWorkers: schedulerWorkers, schedulerWorkersWatcher: services.NewFailureWatcher(), requests: newRequestsInProgress(), + VCSServiceHandler: vcs.New(log, reg), } f.GRPCRoundTripper = &realFrontendRoundTripper{frontend: f} // Randomize to avoid getting responses from queries sent before restart, which could lead to mixing results @@ -178,7 +198,11 @@ func NewFrontend(cfg Config, limits Limits, log log.Logger, reg prometheus.Regis func (f *Frontend) starting(ctx context.Context) error { f.schedulerWorkersWatcher.WatchService(f.schedulerWorkers) - return errors.Wrap(services.StartAndAwaitRunning(ctx, f.schedulerWorkers), "failed to start frontend scheduler workers") + err := services.StartAndAwaitRunning(ctx, f.schedulerWorkers) + if err != nil { + return fmt.Errorf("failed to start frontend scheduler workers: %w", err) + } + return nil } func (f *Frontend) running(ctx context.Context) error { @@ -186,12 +210,16 @@ func (f *Frontend) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-f.schedulerWorkersWatcher.Chan(): - return errors.Wrap(err, "query-frontend subservice failed") + return fmt.Errorf("query-frontend subservice failed: %w", err) } } func (f *Frontend) stopping(_ error) error { - return errors.Wrap(services.StopAndAwaitTerminated(context.Background(), f.schedulerWorkers), "failed to stop frontend scheduler workers") + err := services.StopAndAwaitTerminated(context.Background(), f.schedulerWorkers) + if err != nil { + return fmt.Errorf("failed to stop frontend scheduler workers: %w", err) + } + return nil } // allow to test the frontend without the need of a real roundertripper @@ -214,13 +242,7 @@ func (rt *realFrontendRoundTripper) RoundTripGRPC(ctx context.Context, req *http userID := tenant.JoinTenantIDs(tenantIDs) // Propagate trace context in gRPC too - this will be ignored if using HTTP. - tracer, span := opentracing.GlobalTracer(), opentracing.SpanFromContext(ctx) - if tracer != nil && span != nil { - carrier := (*httpgrpcutil.HttpgrpcHeadersCarrier)(req) - if err := tracer.Inject(span.Context(), opentracing.HTTPHeaders, carrier); err != nil { - return nil, err - } - } + otel.GetTextMapPropagator().Inject(ctx, (*httpgrpcutil.HttpgrpcHeadersCarrier)(req)) ctx, cancel := context.WithCancel(ctx) defer cancel() diff --git a/pkg/frontend/frontend_analyze_query.go b/pkg/frontend/frontend_analyze_query.go index 531c556747..18f462092a 100644 --- a/pkg/frontend/frontend_analyze_query.go +++ b/pkg/frontend/frontend_analyze_query.go @@ -5,22 +5,19 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) AnalyzeQuery(ctx context.Context, - c *connect.Request[querierv1.AnalyzeQueryRequest]) ( - *connect.Response[querierv1.AnalyzeQueryResponse], error, -) { - opentracing.SpanFromContext(ctx) - +func (f *Frontend) AnalyzeQuery( + ctx context.Context, + c *connect.Request[querierv1.AnalyzeQueryRequest], +) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { tenantID, err := tenant.TenantID(ctx) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) diff --git a/pkg/frontend/frontend_diff.go b/pkg/frontend/frontend_diff.go index 1390770776..23493cd897 100644 --- a/pkg/frontend/frontend_diff.go +++ b/pkg/frontend/frontend_diff.go @@ -2,6 +2,7 @@ package frontend import ( "context" + "errors" "connectrpc.com/connect" "github.com/grafana/dskit/tenant" @@ -9,15 +10,15 @@ import ( querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) Diff(ctx context.Context, - c *connect.Request[querierv1.DiffRequest]) ( - *connect.Response[querierv1.DiffResponse], error, -) { +func (f *Frontend) Diff( + ctx context.Context, + c *connect.Request[querierv1.DiffRequest], +) (*connect.Response[querierv1.DiffResponse], error) { ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceDiffProcedure) g, ctx := errgroup.WithContext(ctx) tenantIDs, err := tenant.TenantIDs(ctx) @@ -25,6 +26,19 @@ func (f *Frontend) Diff(ctx context.Context, return nil, connect.NewError(connect.CodeInvalidArgument, err) } + if c.Msg.Left == nil { + c.Msg.Left = &querierv1.SelectMergeStacktracesRequest{} + } + + if c.Msg.Right == nil { + c.Msg.Right = &querierv1.SelectMergeStacktracesRequest{} + } + + // trace_id_selector is v2-only; the legacy diff path would drop it. + if len(c.Msg.Left.GetTraceIdSelector()) > 0 || len(c.Msg.Right.GetTraceIdSelector()) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("trace_id_selector is only supported with the v2 query backend")) + } + maxNodes := c.Msg.Left.GetMaxNodes() if n := c.Msg.Right.GetMaxNodes(); n > maxNodes { maxNodes = n @@ -36,7 +50,7 @@ func (f *Frontend) Diff(ctx context.Context, c.Msg.Left.MaxNodes = &maxNodes c.Msg.Right.MaxNodes = &maxNodes - var left, right *phlaremodel.Tree + var left, right *phlaremodel.FunctionNameTree g.Go(func() error { var leftErr error left, leftErr = f.selectMergeStacktracesTree(ctx, connect.NewRequest(c.Msg.Left)) diff --git a/pkg/frontend/frontend_diff_test.go b/pkg/frontend/frontend_diff_test.go index 7405b1945e..82c2a3b0a5 100644 --- a/pkg/frontend/frontend_diff_test.go +++ b/pkg/frontend/frontend_diff_test.go @@ -2,51 +2,22 @@ package frontend import ( "context" + "errors" + "slices" "testing" "time" "connectrpc.com/connect" "github.com/grafana/dskit/user" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" "github.com/stretchr/testify/require" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" - "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) -type mockLimits struct{} - -func (m *mockLimits) QuerySplitDuration(_ string) time.Duration { - return time.Hour -} - -func (m *mockLimits) MaxQueryParallelism(_ string) int { - return 100 -} - -func (m *mockLimits) MaxQueryLength(_ string) time.Duration { - return time.Hour -} - -func (m *mockLimits) MaxQueryLookback(_ string) time.Duration { - return time.Hour * 24 -} - -func (m *mockLimits) QueryAnalysisEnabled(_ string) bool { - return true -} - -func (m *mockLimits) MaxFlameGraphNodesDefault(_ string) int { - return 10_000 -} - -func (m *mockLimits) MaxFlameGraphNodesMax(_ string) int { - return 100_000 -} - type mockRoundTripper struct { callback func(ctx context.Context, req *httpgrpc.HTTPRequest) (*httpgrpc.HTTPResponse, error) } @@ -59,12 +30,19 @@ func (m *mockRoundTripper) RoundTripGRPC(ctx context.Context, req *httpgrpc.HTTP } func Test_Frontend_Diff(t *testing.T) { + limits := mockfrontend.NewMockLimits(t) + limits.On("MaxFlameGraphNodesDefault", "test").Return(10_000).Maybe() + limits.On("MaxFlameGraphNodesMax", "test").Return(100_000).Maybe() + limits.On("MaxQueryLookback", "test").Return(time.Hour * 24).Maybe() + limits.On("MaxQueryLength", "test").Return(time.Hour).Maybe() + limits.On("MaxQueryParallelism", "test").Return(100).Maybe() + limits.On("QuerySplitDuration", "test").Return(time.Hour).Maybe() + frontend := Frontend{ - limits: &mockLimits{}, + limits: limits, } ctx := user.InjectOrgID(context.Background(), "test") - _, ctx = opentracing.StartSpanFromContext(ctx, "test") now := time.Now().UnixMilli() profileType := "memory:inuse_space:bytes:space:byte" @@ -76,7 +54,7 @@ func Test_Frontend_Diff(t *testing.T) { Left: &querierv1.SelectMergeStacktracesRequest{ ProfileTypeID: profileType, LabelSelector: "{}", - Start: 0000, + Start: 1, End: 1000, }, Right: &querierv1.SelectMergeStacktracesRequest{ @@ -128,7 +106,7 @@ func Test_Frontend_Diff(t *testing.T) { frontend.GRPCRoundTripper = &mockRoundTripper{callback: func(ctx context.Context, req *httpgrpc.HTTPRequest) (*httpgrpc.HTTPResponse, error) { return connectgrpc.HandleUnary[querierv1.SelectMergeStacktracesRequest, querierv1.SelectMergeStacktracesResponse](ctx, req, func(ctx context.Context, req *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { - s := new(model.Tree) + s := new(model.FunctionNameTree) s.InsertStack(1, "foo", "bar") if req.Msg.Start == now { @@ -182,4 +160,44 @@ func Test_Frontend_Diff(t *testing.T) { ) }) + t.Run("span-filtered diff", func(t *testing.T) { + leftSpan := []string{"0000000000000001"} + rightSpan := []string{"0000000000000002"} + frontend.GRPCRoundTripper = &mockRoundTripper{callback: func(ctx context.Context, req *httpgrpc.HTTPRequest) (*httpgrpc.HTTPResponse, error) { + return connectgrpc.HandleUnary[querierv1.SelectMergeSpanProfileRequest, querierv1.SelectMergeSpanProfileResponse](ctx, req, func(_ context.Context, req *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + want := rightSpan + if req.Msg.Start == now { + want = leftSpan + } + if !slices.Equal(req.Msg.SpanSelector, want) { + return nil, errors.New("unexpected span selector") + } + tree := new(model.FunctionNameTree) + tree.InsertStack(1, "foo") + return connect.NewResponse(&querierv1.SelectMergeSpanProfileResponse{Tree: tree.Bytes(-1, nil)}), nil + }) + }} + + resp, err := frontend.Diff(ctx, connect.NewRequest(&querierv1.DiffRequest{ + Left: &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: profileType, + LabelSelector: "{}", + Start: now, + End: now + 1000, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + SpanSelector: leftSpan, + }, + Right: &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: profileType, + LabelSelector: "{}", + Start: now + 2000, + End: now + 3000, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_DOT, + SpanSelector: rightSpan, + }, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg.Flamegraph) + }) } diff --git a/pkg/frontend/frontend_get_profile_stats.go b/pkg/frontend/frontend_get_profile_stats.go index 0720379804..701d4cb63c 100644 --- a/pkg/frontend/frontend_get_profile_stats.go +++ b/pkg/frontend/frontend_get_profile_stats.go @@ -4,19 +4,16 @@ import ( "context" "connectrpc.com/connect" - "github.com/opentracing/opentracing-go" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" ) -func (f *Frontend) GetProfileStats(ctx context.Context, - c *connect.Request[typesv1.GetProfileStatsRequest]) ( - *connect.Response[typesv1.GetProfileStatsResponse], error, -) { - opentracing.SpanFromContext(ctx) - +func (f *Frontend) GetProfileStats( + ctx context.Context, + c *connect.Request[typesv1.GetProfileStatsRequest], +) (*connect.Response[typesv1.GetProfileStatsResponse], error) { ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceGetProfileStatsProcedure) res, err := connectgrpc.RoundTripUnary[typesv1.GetProfileStatsRequest, typesv1.GetProfileStatsResponse](ctx, f, c) return res, err diff --git a/pkg/frontend/frontend_label_names.go b/pkg/frontend/frontend_label_names.go index 4eda786cc6..68f03d41b4 100644 --- a/pkg/frontend/frontend_label_names.go +++ b/pkg/frontend/frontend_label_names.go @@ -5,22 +5,19 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) LabelNames(ctx context.Context, c *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()). - SetTag("matchers", c.Msg.Matchers) - +func (f *Frontend) LabelNames( + ctx context.Context, + c *connect.Request[typesv1.LabelNamesRequest], +) (*connect.Response[typesv1.LabelNamesResponse], error) { ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceLabelNamesProcedure) tenantIDs, err := tenant.TenantIDs(ctx) diff --git a/pkg/frontend/frontend_label_values.go b/pkg/frontend/frontend_label_values.go index 1378958441..06b8683c88 100644 --- a/pkg/frontend/frontend_label_values.go +++ b/pkg/frontend/frontend_label_values.go @@ -5,23 +5,19 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) LabelValues(ctx context.Context, c *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()). - SetTag("matchers", c.Msg.Matchers). - SetTag("name", c.Msg.Name) - +func (f *Frontend) LabelValues( + ctx context.Context, + c *connect.Request[typesv1.LabelValuesRequest], +) (*connect.Response[typesv1.LabelValuesResponse], error) { ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceLabelValuesProcedure) interval, ok := phlaremodel.GetTimeRange(c.Msg) diff --git a/pkg/frontend/frontend_profile_types.go b/pkg/frontend/frontend_profile_types.go index 752d7fae21..ca0e10b109 100644 --- a/pkg/frontend/frontend_profile_types.go +++ b/pkg/frontend/frontend_profile_types.go @@ -5,21 +5,19 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) ProfileTypes(ctx context.Context, c *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()) - +func (f *Frontend) ProfileTypes( + ctx context.Context, + c *connect.Request[querierv1.ProfileTypesRequest], +) (*connect.Response[querierv1.ProfileTypesResponse], error) { ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceProfileTypesProcedure) interval, ok := phlaremodel.GetTimeRange(c.Msg) diff --git a/pkg/frontend/frontend_scheduler_worker.go b/pkg/frontend/frontend_scheduler_worker.go index eac4b23644..9b5546d132 100644 --- a/pkg/frontend/frontend_scheduler_worker.go +++ b/pkg/frontend/frontend_scheduler_worker.go @@ -7,6 +7,8 @@ package frontend import ( "context" + "errors" + "fmt" "io" "math/rand" "net/http" @@ -17,16 +19,15 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/backoff" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "google.golang.org/grpc" - "github.com/grafana/pyroscope/pkg/frontend/frontendpb" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerdiscovery" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" - "github.com/grafana/pyroscope/pkg/util/servicediscovery" + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerdiscovery" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/servicediscovery" ) const ( @@ -91,7 +92,7 @@ func (f *frontendSchedulerWorkers) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-f.schedulerDiscoveryWatcher.Chan(): - return errors.Wrap(err, "query-frontend workers subservice failed") + return fmt.Errorf("query-frontend workers subservice failed: %w", err) } } @@ -194,7 +195,7 @@ func (f *frontendSchedulerWorkers) getWorkersCount() int { func (f *frontendSchedulerWorkers) connectToScheduler(ctx context.Context, address string) (*grpc.ClientConn, error) { // Because we only use single long-running method, it doesn't make sense to inject user ID, send over tracing or add metrics. - opts, err := f.cfg.GRPCClientConfig.DialOption(nil, nil) + opts, err := f.cfg.GRPCClientConfig.DialOption(nil, nil, nil) if err != nil { return nil, err } @@ -329,7 +330,7 @@ func (w *frontendSchedulerWorker) schedulerLoop(loop schedulerpb.SchedulerForFro if err != nil { return err } - return errors.Errorf("unexpected status received for init: %v", resp.Status) + return fmt.Errorf("unexpected status received for init: %v", resp.Status) } ctx, cancel := context.WithCancel(loop.Context()) @@ -430,7 +431,7 @@ func (w *frontendSchedulerWorker) schedulerLoop(loop schedulerpb.SchedulerForFro // Scheduler may be shutting down, report that. if resp.Status != schedulerpb.SchedulerToFrontendStatus_OK { - return errors.Errorf("unexpected status received for cancellation: %v", resp.Status) + return fmt.Errorf("unexpected status received for cancellation: %v", resp.Status) } } } diff --git a/pkg/frontend/frontend_select_merge_profile.go b/pkg/frontend/frontend_select_merge_profile.go index 7d331d2d81..7167f4580c 100644 --- a/pkg/frontend/frontend_select_merge_profile.go +++ b/pkg/frontend/frontend_select_merge_profile.go @@ -2,33 +2,32 @@ package frontend import ( "context" - "sync" + "errors" "time" "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" "golang.org/x/sync/errgroup" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - validationutil "github.com/grafana/pyroscope/pkg/util/validation" - "github.com/grafana/pyroscope/pkg/validation" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + validationutil "github.com/grafana/pyroscope/v2/pkg/util/validation" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) SelectMergeProfile(ctx context.Context, c *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[profilev1.Profile], error) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()). - SetTag("selector", c.Msg.LabelSelector). - SetTag("max_nodes", c.Msg.GetMaxNodes()). - SetTag("profile_type", c.Msg.ProfileTypeID) - +func (f *Frontend) SelectMergeProfile( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeProfileRequest], +) (*connect.Response[profilev1.Profile], error) { ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceSelectMergeProfileProcedure) + // trace_id_selector is v2-only; this legacy frontend would drop it on split. + if len(c.Msg.TraceIdSelector) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("trace_id_selector is only supported with the v2 query backend")) + } tenantIDs, err := tenant.TenantIDs(ctx) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) @@ -51,11 +50,25 @@ func (f *Frontend) SelectMergeProfile(ctx context.Context, c *connect.Request[qu interval := validationutil.MaxDurationOrZeroPerTenant(tenantIDs, f.limits.QuerySplitDuration) intervals := NewTimeIntervalIterator(time.UnixMilli(int64(validated.Start)), time.UnixMilli(int64(validated.End)), interval) - // NOTE: Max nodes limit is not set by default: - // the method is used for pprof export and - // truncation is not applicable for that. + // NOTE: Max nodes limit is off by default. SelectMergeProfile is primarily + // used for pprof export where truncation would result in incomplete profiles. + // This can be overridden per-tenant to enable enforcement if needed. + maxNodesEnabled := false + for _, tenantID := range tenantIDs { + if f.limits.MaxFlameGraphNodesOnSelectMergeProfile(tenantID) { + maxNodesEnabled = true + } + } + + maxNodes := c.Msg.MaxNodes + if maxNodesEnabled { + maxNodesV, err := validation.ValidateMaxNodes(f.limits, tenantIDs, c.Msg.GetMaxNodes()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + maxNodes = &maxNodesV + } - var lock sync.Mutex var m pprof.ProfileMerge for intervals.Next() { r := intervals.At() @@ -65,7 +78,7 @@ func (f *Frontend) SelectMergeProfile(ctx context.Context, c *connect.Request[qu LabelSelector: c.Msg.LabelSelector, Start: r.Start.UnixMilli(), End: r.End.UnixMilli(), - MaxNodes: c.Msg.MaxNodes, + MaxNodes: maxNodes, StackTraceSelector: c.Msg.StackTraceSelector, }) resp, err := connectgrpc.RoundTripUnary[ @@ -74,9 +87,7 @@ func (f *Frontend) SelectMergeProfile(ctx context.Context, c *connect.Request[qu if err != nil { return err } - lock.Lock() - defer lock.Unlock() - return m.Merge(resp.Msg) + return m.Merge(resp.Msg, f.limits.QuerySanitizeOnMerge(tenantIDs[0])) }) } diff --git a/pkg/frontend/frontend_select_merge_span_profile.go b/pkg/frontend/frontend_select_merge_span_profile.go index 85ac11ffc6..11721e5cd9 100644 --- a/pkg/frontend/frontend_select_merge_span_profile.go +++ b/pkg/frontend/frontend_select_merge_span_profile.go @@ -6,29 +6,21 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" "golang.org/x/sync/errgroup" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - validationutil "github.com/grafana/pyroscope/pkg/util/validation" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + validationutil "github.com/grafana/pyroscope/v2/pkg/util/validation" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) SelectMergeSpanProfile(ctx context.Context, - c *connect.Request[querierv1.SelectMergeSpanProfileRequest]) ( - *connect.Response[querierv1.SelectMergeSpanProfileResponse], error, -) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()). - SetTag("selector", c.Msg.LabelSelector). - SetTag("max_nodes", c.Msg.MaxNodes). - SetTag("profile_type", c.Msg.ProfileTypeID) - +func (f *Frontend) SelectMergeSpanProfile( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeSpanProfileRequest], +) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceSelectMergeSpanProfileProcedure) tenantIDs, err := tenant.TenantIDs(ctx) if err != nil { @@ -94,7 +86,7 @@ func (f *Frontend) SelectMergeSpanProfile(ctx context.Context, default: resp.Flamegraph = phlaremodel.NewFlameGraph(t, c.Msg.GetMaxNodes()) case querierv1.ProfileFormat_PROFILE_FORMAT_TREE: - resp.Tree = t.Bytes(c.Msg.GetMaxNodes()) + resp.Tree = t.Bytes(c.Msg.GetMaxNodes(), nil) } return connect.NewResponse(&resp), nil } diff --git a/pkg/frontend/frontend_select_merge_stacktraces.go b/pkg/frontend/frontend_select_merge_stacktraces.go index 1811318e04..0f9947d4d6 100644 --- a/pkg/frontend/frontend_select_merge_stacktraces.go +++ b/pkg/frontend/frontend_select_merge_stacktraces.go @@ -2,26 +2,40 @@ package frontend import ( "context" + "errors" "time" "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" "github.com/prometheus/common/model" "golang.org/x/sync/errgroup" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - validationutil "github.com/grafana/pyroscope/pkg/util/validation" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + validationutil "github.com/grafana/pyroscope/v2/pkg/util/validation" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func (f *Frontend) SelectMergeStacktraces(ctx context.Context, - c *connect.Request[querierv1.SelectMergeStacktracesRequest]) ( - *connect.Response[querierv1.SelectMergeStacktracesResponse], error, -) { +func (f *Frontend) SelectMergeStacktraces( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + if c.Msg.Format == querierv1.ProfileFormat_PROFILE_FORMAT_DOT { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("dot format is only supported with the v2 query backend")) + } + // trace_id_selector is v2-only; this legacy frontend would drop it on split. + if len(c.Msg.TraceIdSelector) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("trace_id_selector is only supported with the v2 query backend")) + } + if len(c.Msg.SpanSelector) > 0 && (c.Msg.StackTraceSelector != nil || len(c.Msg.ProfileIdSelector) > 0) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("combining span_selector with stack_trace_selector or profile_id_selector is only supported with the v2 query backend")) + } + if c.Msg.Format == querierv1.ProfileFormat_PROFILE_FORMAT_PPROF { + return f.selectMergeStacktracesPprof(ctx, c) + } t, err := f.selectMergeStacktracesTree(ctx, c) if err != nil { return nil, err @@ -31,21 +45,30 @@ func (f *Frontend) SelectMergeStacktraces(ctx context.Context, default: resp.Flamegraph = phlaremodel.NewFlameGraph(t, c.Msg.GetMaxNodes()) case querierv1.ProfileFormat_PROFILE_FORMAT_TREE: - resp.Tree = t.Bytes(c.Msg.GetMaxNodes()) + resp.Tree = t.Bytes(c.Msg.GetMaxNodes(), nil) } return connect.NewResponse(&resp), nil } -func (f *Frontend) selectMergeStacktracesTree(ctx context.Context, - c *connect.Request[querierv1.SelectMergeStacktracesRequest]) ( - *phlaremodel.Tree, error, -) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()). - SetTag("selector", c.Msg.LabelSelector). - SetTag("max_nodes", c.Msg.GetMaxNodes()). - SetTag("profile_type", c.Msg.ProfileTypeID) +func (f *Frontend) selectMergeStacktracesTree( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (*phlaremodel.FunctionNameTree, error) { + if len(c.Msg.SpanSelector) > 0 { + resp, err := f.SelectMergeSpanProfile(ctx, connect.NewRequest(&querierv1.SelectMergeSpanProfileRequest{ + ProfileTypeID: c.Msg.ProfileTypeID, + LabelSelector: c.Msg.LabelSelector, + SpanSelector: c.Msg.SpanSelector, + Start: c.Msg.Start, + End: c.Msg.End, + MaxNodes: c.Msg.MaxNodes, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_TREE, + })) + if err != nil { + return nil, err + } + return phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Msg.Tree) + } ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceSelectMergeStacktracesProcedure) tenantIDs, err := tenant.TenantIDs(ctx) @@ -58,7 +81,7 @@ func (f *Frontend) selectMergeStacktracesTree(ctx context.Context, return nil, connect.NewError(connect.CodeInvalidArgument, err) } if validated.IsEmpty { - return new(phlaremodel.Tree), nil + return new(phlaremodel.FunctionNameTree), nil } maxNodes, err := validation.ValidateMaxNodes(f.limits, tenantIDs, c.Msg.GetMaxNodes()) if err != nil { @@ -107,3 +130,39 @@ func (f *Frontend) selectMergeStacktracesTree(ctx context.Context, return m.Tree(), nil } + +func (f *Frontend) selectMergeStacktracesPprof( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + if len(c.Msg.SpanSelector) == 0 { + resp, err := f.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: c.Msg.ProfileTypeID, + LabelSelector: c.Msg.LabelSelector, + Start: c.Msg.Start, + End: c.Msg.End, + MaxNodes: c.Msg.MaxNodes, + StackTraceSelector: c.Msg.StackTraceSelector, + ProfileIdSelector: c.Msg.ProfileIdSelector, + TraceIdSelector: c.Msg.TraceIdSelector, + })) + if err != nil { + return nil, err + } + return connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{Profile: resp.Msg}, + }), nil + } + + tree, err := f.selectMergeStacktracesTree(ctx, c) + if err != nil { + return nil, err + } + profileType, err := phlaremodel.ParseProfileTypeSelector(c.Msg.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + return connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{Profile: pprof.FromTree(tree, profileType, c.Msg.End*1e6)}, + }), nil +} diff --git a/pkg/frontend/frontend_select_merge_stacktraces_test.go b/pkg/frontend/frontend_select_merge_stacktraces_test.go new file mode 100644 index 0000000000..17aada4557 --- /dev/null +++ b/pkg/frontend/frontend_select_merge_stacktraces_test.go @@ -0,0 +1,56 @@ +package frontend + +import ( + "context" + "errors" + "slices" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/grafana/dskit/user" + "github.com/stretchr/testify/require" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" +) + +func TestFrontend_SelectMergeStacktraces_SpanPprofUsesLegacySpanRPC(t *testing.T) { + limits := mockfrontend.NewMockLimits(t) + limits.On("MaxFlameGraphNodesDefault", "test").Return(10_000) + limits.On("MaxQueryLookback", "test").Return(time.Duration(0)) + limits.On("MaxQueryLength", "test").Return(time.Duration(0)) + limits.On("MaxQueryParallelism", "test").Return(100) + limits.On("QuerySplitDuration", "test").Return(time.Hour) + + spanSelector := []string{"0000000000000001"} + frontend := &Frontend{limits: limits} + frontend.GRPCRoundTripper = &mockRoundTripper{callback: func(ctx context.Context, req *httpgrpc.HTTPRequest) (*httpgrpc.HTTPResponse, error) { + return connectgrpc.HandleUnary[querierv1.SelectMergeSpanProfileRequest, querierv1.SelectMergeSpanProfileResponse](ctx, req, func(_ context.Context, req *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + if !slices.Equal(spanSelector, req.Msg.SpanSelector) { + return nil, errors.New("unexpected span selector") + } + tree := new(model.FunctionNameTree) + tree.InsertStack(1, "foo") + return connect.NewResponse(&querierv1.SelectMergeSpanProfileResponse{Tree: tree.Bytes(-1, nil)}), nil + }) + }} + + ctx := user.InjectOrgID(context.Background(), "test") + now := time.Now() + resp, err := frontend.SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + LabelSelector: "{}", + Start: now.UnixMilli(), + End: now.Add(time.Minute).UnixMilli(), + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + SpanSelector: spanSelector, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg.GetPprof().GetProfile()) + require.Len(t, resp.Msg.Pprof.Profile.Sample, 1) +} diff --git a/pkg/frontend/frontend_select_series.go b/pkg/frontend/frontend_select_series.go deleted file mode 100644 index a7cf37ac78..0000000000 --- a/pkg/frontend/frontend_select_series.go +++ /dev/null @@ -1,88 +0,0 @@ -package frontend - -import ( - "context" - "time" - - "connectrpc.com/connect" - "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" - "github.com/prometheus/common/model" - "golang.org/x/sync/errgroup" - - querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" - "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - validationutil "github.com/grafana/pyroscope/pkg/util/validation" - "github.com/grafana/pyroscope/pkg/validation" -) - -func (f *Frontend) SelectSeries(ctx context.Context, - c *connect.Request[querierv1.SelectSeriesRequest]) ( - *connect.Response[querierv1.SelectSeriesResponse], error, -) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()). - SetTag("selector", c.Msg.LabelSelector). - SetTag("step", c.Msg.Step). - SetTag("by", c.Msg.GroupBy). - SetTag("profile_type", c.Msg.ProfileTypeID) - - ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceSelectSeriesProcedure) - tenantIDs, err := tenant.TenantIDs(ctx) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - validated, err := validation.ValidateRangeRequest(f.limits, tenantIDs, model.Interval{Start: model.Time(c.Msg.Start), End: model.Time(c.Msg.End)}, model.Now()) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if validated.IsEmpty { - return connect.NewResponse(&querierv1.SelectSeriesResponse{}), nil - } - c.Msg.Start = int64(validated.Start) - c.Msg.End = int64(validated.End) - - g, ctx := errgroup.WithContext(ctx) - if maxConcurrent := validationutil.SmallestPositiveNonZeroIntPerTenant(tenantIDs, f.limits.MaxQueryParallelism); maxConcurrent > 0 { - g.SetLimit(maxConcurrent) - } - - m := phlaremodel.NewSeriesMerger(false) - interval := validationutil.MaxDurationOrZeroPerTenant(tenantIDs, f.limits.QuerySplitDuration) - intervals := NewTimeIntervalIterator(time.UnixMilli(c.Msg.Start), time.UnixMilli(c.Msg.End), interval, - WithAlignment(time.Second*time.Duration(c.Msg.Step))) - - for intervals.Next() { - r := intervals.At() - g.Go(func() error { - req := connectgrpc.CloneRequest(c, &querierv1.SelectSeriesRequest{ - ProfileTypeID: c.Msg.ProfileTypeID, - LabelSelector: c.Msg.LabelSelector, - Start: r.Start.UnixMilli(), - End: r.End.UnixMilli(), - GroupBy: c.Msg.GroupBy, - Step: c.Msg.Step, - Aggregation: c.Msg.Aggregation, - StackTraceSelector: c.Msg.StackTraceSelector, - }) - resp, err := connectgrpc.RoundTripUnary[ - querierv1.SelectSeriesRequest, - querierv1.SelectSeriesResponse](ctx, f, req) - if err != nil { - return err - } - m.MergeSeries(resp.Msg.Series) - return nil - }) - } - - if err = g.Wait(); err != nil { - return nil, err - } - - return connect.NewResponse(&querierv1.SelectSeriesResponse{Series: m.Series()}), nil -} diff --git a/pkg/frontend/frontend_select_time_series.go b/pkg/frontend/frontend_select_time_series.go new file mode 100644 index 0000000000..6f5796fc5f --- /dev/null +++ b/pkg/frontend/frontend_select_time_series.go @@ -0,0 +1,80 @@ +package frontend + +import ( + "context" + "time" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + "github.com/prometheus/common/model" + "golang.org/x/sync/errgroup" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + validationutil "github.com/grafana/pyroscope/v2/pkg/util/validation" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (f *Frontend) SelectSeries( + ctx context.Context, + c *connect.Request[querierv1.SelectSeriesRequest], +) (*connect.Response[querierv1.SelectSeriesResponse], error) { + ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceSelectSeriesProcedure) + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + validated, err := validation.ValidateRangeRequest(f.limits, tenantIDs, model.Interval{Start: model.Time(c.Msg.Start), End: model.Time(c.Msg.End)}, model.Now()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if validated.IsEmpty { + return connect.NewResponse(&querierv1.SelectSeriesResponse{}), nil + } + c.Msg.Start = int64(validated.Start) + c.Msg.End = int64(validated.End) + + g, ctx := errgroup.WithContext(ctx) + if maxConcurrent := validationutil.SmallestPositiveNonZeroIntPerTenant(tenantIDs, f.limits.MaxQueryParallelism); maxConcurrent > 0 { + g.SetLimit(maxConcurrent) + } + + m := timeseries.NewMerger(true) + interval := validationutil.MaxDurationOrZeroPerTenant(tenantIDs, f.limits.QuerySplitDuration) + intervals := NewTimeIntervalIterator(time.UnixMilli(c.Msg.Start), time.UnixMilli(c.Msg.End), interval, + WithAlignment(time.Second*time.Duration(c.Msg.Step))) + + for intervals.Next() { + r := intervals.At() + g.Go(func() error { + req := connectgrpc.CloneRequest(c, &querierv1.SelectSeriesRequest{ + ProfileTypeID: c.Msg.ProfileTypeID, + LabelSelector: c.Msg.LabelSelector, + Start: r.Start.UnixMilli(), + End: r.End.UnixMilli(), + GroupBy: c.Msg.GroupBy, + Step: c.Msg.Step, + Aggregation: c.Msg.Aggregation, + StackTraceSelector: c.Msg.StackTraceSelector, + }) + resp, err := connectgrpc.RoundTripUnary[ + querierv1.SelectSeriesRequest, + querierv1.SelectSeriesResponse](ctx, f, req) + if err != nil { + return err + } + m.MergeTimeSeries(resp.Msg.Series) + return nil + }) + } + + if err = g.Wait(); err != nil { + return nil, err + } + + series := m.Top(int(c.Msg.GetLimit())) + return connect.NewResponse(&querierv1.SelectSeriesResponse{Series: series}), nil +} diff --git a/pkg/frontend/frontend_series.go b/pkg/frontend/frontend_series.go deleted file mode 100644 index e38854445f..0000000000 --- a/pkg/frontend/frontend_series.go +++ /dev/null @@ -1,46 +0,0 @@ -package frontend - -import ( - "context" - - "connectrpc.com/connect" - "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" - "github.com/prometheus/common/model" - - querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" - "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" - "github.com/grafana/pyroscope/pkg/validation" -) - -func (f *Frontend) Series(ctx context.Context, c *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error) { - opentracing.SpanFromContext(ctx). - SetTag("start", model.Time(c.Msg.Start).Time().String()). - SetTag("end", model.Time(c.Msg.End).Time().String()). - SetTag("matchers", c.Msg.Matchers). - SetTag("label_names", c.Msg.LabelNames) - - ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceSeriesProcedure) - - tenantIDs, err := tenant.TenantIDs(ctx) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - interval, ok := phlaremodel.GetTimeRange(c.Msg) - if ok { - validated, err := validation.ValidateRangeRequest(f.limits, tenantIDs, interval, model.Now()) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if validated.IsEmpty { - return connect.NewResponse(&querierv1.SeriesResponse{}), nil - } - c.Msg.Start = int64(validated.Start) - c.Msg.End = int64(validated.End) - } - - return connectgrpc.RoundTripUnary[querierv1.SeriesRequest, querierv1.SeriesResponse](ctx, f, c) -} diff --git a/pkg/frontend/frontend_series_labels.go b/pkg/frontend/frontend_series_labels.go new file mode 100644 index 0000000000..578274ce03 --- /dev/null +++ b/pkg/frontend/frontend_series_labels.go @@ -0,0 +1,42 @@ +package frontend + +import ( + "context" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + "github.com/prometheus/common/model" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (f *Frontend) Series( + ctx context.Context, + c *connect.Request[querierv1.SeriesRequest], +) (*connect.Response[querierv1.SeriesResponse], error) { + ctx = connectgrpc.WithProcedure(ctx, querierv1connect.QuerierServiceSeriesProcedure) + + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + interval, ok := phlaremodel.GetTimeRange(c.Msg) + if ok { + validated, err := validation.ValidateRangeRequest(f.limits, tenantIDs, interval, model.Now()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if validated.IsEmpty { + return connect.NewResponse(&querierv1.SeriesResponse{}), nil + } + c.Msg.Start = int64(validated.Start) + c.Msg.End = int64(validated.End) + } + + return connectgrpc.RoundTripUnary[querierv1.SeriesRequest, querierv1.SeriesResponse](ctx, f, c) +} diff --git a/pkg/frontend/frontend_stubs.go b/pkg/frontend/frontend_stubs.go new file mode 100644 index 0000000000..46bcb2c91d --- /dev/null +++ b/pkg/frontend/frontend_stubs.go @@ -0,0 +1,19 @@ +package frontend + +import ( + "context" + "errors" + + "connectrpc.com/connect" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" +) + +var errNotAvailableInV1Frontend = connect.NewError(connect.CodeUnimplemented, errors.New("this endpoint is not available in v1 frontend")) + +func (f *Frontend) SelectHeatmap( + ctx context.Context, + c *connect.Request[querierv1.SelectHeatmapRequest], +) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + return nil, errNotAvailableInV1Frontend +} diff --git a/pkg/frontend/frontend_test.go b/pkg/frontend/frontend_test.go index a9f1b3e75e..d7290e24e6 100644 --- a/pkg/frontend/frontend_test.go +++ b/pkg/frontend/frontend_test.go @@ -6,6 +6,7 @@ package frontend import ( + "bytes" "context" "fmt" "net/http" @@ -25,24 +26,30 @@ import ( "github.com/grafana/dskit/flagext" "github.com/grafana/dskit/services" "github.com/grafana/dskit/test" + "github.com/grafana/dskit/tracing" "github.com/grafana/dskit/user" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/atomic" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" - - "github.com/grafana/pyroscope/pkg/frontend/frontendpb" - "github.com/grafana/pyroscope/pkg/frontend/frontendpb/frontendpbconnect" - "github.com/grafana/pyroscope/pkg/querier/stats" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerdiscovery" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb/schedulerpbconnect" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" - "github.com/grafana/pyroscope/pkg/util/servicediscovery" - "github.com/grafana/pyroscope/pkg/validation" + + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb" + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb/frontendpbconnect" + "github.com/grafana/pyroscope/v2/pkg/querier/stats" + "github.com/grafana/pyroscope/v2/pkg/querier/worker" + "github.com/grafana/pyroscope/v2/pkg/scheduler" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerdiscovery" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb/schedulerpbconnect" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + httpserver "github.com/grafana/pyroscope/v2/pkg/util/http/server" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/servicediscovery" + "github.com/grafana/pyroscope/v2/pkg/validation" ) const testFrontendWorkerConcurrency = 5 @@ -51,14 +58,8 @@ func setupFrontend(t *testing.T, reg prometheus.Registerer, schedulerReplyFunc f return setupFrontendWithConcurrencyAndServerOptions(t, reg, schedulerReplyFunc, testFrontendWorkerConcurrency) } -func setupFrontendWithConcurrencyAndServerOptions(t *testing.T, reg prometheus.Registerer, schedulerReplyFunc func(f *Frontend, msg *schedulerpb.FrontendToScheduler) *schedulerpb.SchedulerToFrontend, concurrency int) (*Frontend, *mockScheduler) { - s := httptest.NewUnstartedServer(nil) - mux := mux.NewRouter() - s.Config.Handler = h2c.NewHandler(mux, &http2.Server{}) - - s.Start() - - u, err := url.Parse(s.URL) +func cfgFromURL(t *testing.T, urlS string) Config { + u, err := url.Parse(urlS) require.NoError(t, err) port, err := strconv.Atoi(u.Port()) @@ -67,9 +68,20 @@ func setupFrontendWithConcurrencyAndServerOptions(t *testing.T, reg prometheus.R cfg := Config{} flagext.DefaultValues(&cfg) cfg.SchedulerAddress = u.Hostname() + ":" + u.Port() - cfg.WorkerConcurrency = concurrency cfg.Addr = u.Hostname() cfg.Port = port + return cfg +} + +func setupFrontendWithConcurrencyAndServerOptions(t *testing.T, reg prometheus.Registerer, schedulerReplyFunc func(f *Frontend, msg *schedulerpb.FrontendToScheduler) *schedulerpb.SchedulerToFrontend, concurrency int) (*Frontend, *mockScheduler) { + mux := mux.NewRouter() + s := httptest.NewUnstartedServer(mux) + httpserver.EnableHTTP2(s.Config) + + s.Start() + + cfg := cfgFromURL(t, s.URL) + cfg.WorkerConcurrency = concurrency logger := log.NewLogfmtLogger(os.Stdout) f, err := NewFrontend(cfg, validation.MockLimits{MaxQueryParallelismValue: 1}, logger, reg) @@ -181,6 +193,139 @@ func TestFrontendRequestsPerWorkerMetric(t *testing.T) { require.NoError(t, testutil.GatherAndCompare(reg, strings.NewReader(expectedMetrics), "pyroscope_query_frontend_workers_enqueued_requests_total")) } +func newFakeQuerierGRPCHandler() connectgrpc.GRPCHandler { + q := &fakeQuerier{} + mux := http.NewServeMux() + mux.Handle(querierv1connect.NewQuerierServiceHandler(q, connectapi.DefaultHandlerOptions()...)) + return connectgrpc.NewHandler(mux) +} + +type fakeQuerier struct { + querierv1connect.QuerierServiceHandler +} + +func (f *fakeQuerier) LabelNames(ctx context.Context, req *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { + return connect.NewResponse(&typesv1.LabelNamesResponse{ + Names: []string{"i", "have", "labels"}, + }), nil +} + +func headerToSlice(t testing.TB, header http.Header) []string { + buf := new(bytes.Buffer) + excludeHeaders := map[string]bool{"Content-Length": true, "Date": true} + require.NoError(t, header.WriteSubset(buf, excludeHeaders)) + sl := strings.Split(strings.ReplaceAll(buf.String(), "\r\n", "\n"), "\n") + if len(sl) > 0 && sl[len(sl)-1] == "" { + sl = sl[:len(sl)-1] + } + return sl +} + +// TestFrontendFullRoundtrip tests the full roundtrip of a request from the frontend to a fake querier and back, with using an actual scheduler. +func TestFrontendFullRoundtrip(t *testing.T) { + var ( + logger = log.NewNopLogger() + reg = prometheus.NewRegistry() + tenant = "tenant-a" + ) + if testing.Verbose() { + logger = log.NewLogfmtLogger(os.Stderr) + } + + // create server for frontend and scheduler + mux := mux.NewRouter() + // inject a span/tenant into the context + mux.Use(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := user.InjectOrgID(r.Context(), tenant) + _, ctx = tracing.StartSpanFromContext(ctx, "test") + next.ServeHTTP(w, r.WithContext(ctx)) + }) + }) + s := httptest.NewUnstartedServer(mux) + httpserver.EnableHTTP2(s.Config) + s.Start() + defer s.Close() + + // initialize the scheduler + schedCfg := scheduler.Config{} + flagext.DefaultValues(&schedCfg) + sched, err := scheduler.NewScheduler(schedCfg, validation.MockLimits{}, logger, reg) + require.NoError(t, err) + schedulerpbconnect.RegisterSchedulerForFrontendHandler(mux, sched) + schedulerpbconnect.RegisterSchedulerForQuerierHandler(mux, sched) + + // initialize the frontend + fCfg := cfgFromURL(t, s.URL) + f, err := NewFrontend(fCfg, validation.MockLimits{MaxQueryParallelismValue: 1}, logger, reg) + require.NoError(t, err) + frontendpbconnect.RegisterFrontendForQuerierHandler(mux, f) // probably not needed + querierv1connect.RegisterQuerierServiceHandler(mux, f) + + // create a querier worker + qWorkerCfg := worker.Config{} + flagext.DefaultValues(&qWorkerCfg) + qWorkerCfg.SchedulerAddress = fCfg.SchedulerAddress + qWorker, err := worker.NewQuerierWorker(qWorkerCfg, newFakeQuerierGRPCHandler(), log.NewLogfmtLogger(os.Stderr), prometheus.NewRegistry()) + require.NoError(t, err) + + // start services + svc, err := services.NewManager(sched, f, qWorker) + require.NoError(t, err) + require.NoError(t, svc.StartAsync(context.Background())) + require.NoError(t, svc.AwaitHealthy(context.Background())) + defer func() { + svc.StopAsync() + require.NoError(t, svc.AwaitStopped(context.Background())) + }() + + t.Run("using protocol grpc", func(t *testing.T) { + client := querierv1connect.NewQuerierServiceClient(http.DefaultClient, s.URL, connect.WithGRPC()) + + resp, err := client.LabelNames(context.Background(), connect.NewRequest(&typesv1.LabelNamesRequest{})) + require.NoError(t, err) + + require.Equal(t, []string{"i", "have", "labels"}, resp.Msg.Names) + + assert.Equal(t, []string{ + "Content-Type: application/grpc", + "Grpc-Accept-Encoding: gzip", + "Grpc-Encoding: gzip", + }, headerToSlice(t, resp.Header())) + }) + + t.Run("using protocol grpc-web", func(t *testing.T) { + client := querierv1connect.NewQuerierServiceClient(http.DefaultClient, s.URL, connect.WithGRPCWeb()) + + resp, err := client.LabelNames(context.Background(), connect.NewRequest(&typesv1.LabelNamesRequest{})) + require.NoError(t, err) + + require.Equal(t, []string{"i", "have", "labels"}, resp.Msg.Names) + + assert.Equal(t, []string{ + "Content-Type: application/grpc-web+proto", + "Grpc-Accept-Encoding: gzip", + "Grpc-Encoding: gzip", + }, headerToSlice(t, resp.Header())) + }) + + t.Run("using protocol json", func(t *testing.T) { + client := querierv1connect.NewQuerierServiceClient(http.DefaultClient, s.URL, connect.WithProtoJSON()) + + resp, err := client.LabelNames(context.Background(), connect.NewRequest(&typesv1.LabelNamesRequest{})) + require.NoError(t, err) + + require.Equal(t, []string{"i", "have", "labels"}, resp.Msg.Names) + + assert.Equal(t, []string{ + "Accept-Encoding: gzip", + "Content-Encoding: gzip", + "Content-Type: application/json", + }, headerToSlice(t, resp.Header())) + }) + +} + func TestFrontendRetryEnqueue(t *testing.T) { // Frontend uses worker concurrency to compute number of retries. We use one less failure. failures := atomic.NewInt64(testFrontendWorkerConcurrency - 1) diff --git a/pkg/frontend/frontend_vcs.go b/pkg/frontend/frontend_vcs.go deleted file mode 100644 index c74a86ff05..0000000000 --- a/pkg/frontend/frontend_vcs.go +++ /dev/null @@ -1,30 +0,0 @@ -package frontend - -import ( - "context" - - "connectrpc.com/connect" - - vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" -) - -func (f *Frontend) GithubApp(ctx context.Context, req *connect.Request[vcsv1.GithubAppRequest]) (*connect.Response[vcsv1.GithubAppResponse], error) { - return connectgrpc.RoundTripUnary[vcsv1.GithubAppRequest, vcsv1.GithubAppResponse](ctx, f, req) -} - -func (f *Frontend) GithubLogin(ctx context.Context, req *connect.Request[vcsv1.GithubLoginRequest]) (*connect.Response[vcsv1.GithubLoginResponse], error) { - return connectgrpc.RoundTripUnary[vcsv1.GithubLoginRequest, vcsv1.GithubLoginResponse](ctx, f, req) -} - -func (f *Frontend) GithubRefresh(ctx context.Context, req *connect.Request[vcsv1.GithubRefreshRequest]) (*connect.Response[vcsv1.GithubRefreshResponse], error) { - return connectgrpc.RoundTripUnary[vcsv1.GithubRefreshRequest, vcsv1.GithubRefreshResponse](ctx, f, req) -} - -func (f *Frontend) GetFile(ctx context.Context, req *connect.Request[vcsv1.GetFileRequest]) (*connect.Response[vcsv1.GetFileResponse], error) { - return connectgrpc.RoundTripUnary[vcsv1.GetFileRequest, vcsv1.GetFileResponse](ctx, f, req) -} - -func (f *Frontend) GetCommit(ctx context.Context, req *connect.Request[vcsv1.GetCommitRequest]) (*connect.Response[vcsv1.GetCommitResponse], error) { - return connectgrpc.RoundTripUnary[vcsv1.GetCommitRequest, vcsv1.GetCommitResponse](ctx, f, req) -} diff --git a/pkg/frontend/frontendpb/frontend.pb.go b/pkg/frontend/frontendpb/frontend.pb.go index 5741acb828..3f1fc6eafd 100644 --- a/pkg/frontend/frontendpb/frontend.pb.go +++ b/pkg/frontend/frontendpb/frontend.pb.go @@ -5,19 +5,20 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: frontend/frontendpb/frontend.proto package frontendpb import ( - stats "github.com/grafana/pyroscope/pkg/querier/stats" - httpgrpc "github.com/grafana/pyroscope/pkg/util/httpgrpc" + stats "github.com/grafana/pyroscope/v2/pkg/querier/stats" + httpgrpc "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -28,22 +29,19 @@ const ( ) type QueryResultRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + QueryID uint64 `protobuf:"varint,1,opt,name=queryID,proto3" json:"queryID,omitempty"` + HttpResponse *httpgrpc.HTTPResponse `protobuf:"bytes,2,opt,name=httpResponse,proto3" json:"httpResponse,omitempty"` + Stats *stats.Stats `protobuf:"bytes,3,opt,name=stats,proto3" json:"stats,omitempty"` unknownFields protoimpl.UnknownFields - - QueryID uint64 `protobuf:"varint,1,opt,name=queryID,proto3" json:"queryID,omitempty"` - HttpResponse *httpgrpc.HTTPResponse `protobuf:"bytes,2,opt,name=httpResponse,proto3" json:"httpResponse,omitempty"` - Stats *stats.Stats `protobuf:"bytes,3,opt,name=stats,proto3" json:"stats,omitempty"` + sizeCache protoimpl.SizeCache } func (x *QueryResultRequest) Reset() { *x = QueryResultRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_frontend_frontendpb_frontend_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_frontend_frontendpb_frontend_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *QueryResultRequest) String() string { @@ -54,7 +52,7 @@ func (*QueryResultRequest) ProtoMessage() {} func (x *QueryResultRequest) ProtoReflect() protoreflect.Message { mi := &file_frontend_frontendpb_frontend_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -91,18 +89,16 @@ func (x *QueryResultRequest) GetStats() *stats.Stats { } type QueryResultResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *QueryResultResponse) Reset() { *x = QueryResultResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_frontend_frontendpb_frontend_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_frontend_frontendpb_frontend_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *QueryResultResponse) String() string { @@ -113,7 +109,7 @@ func (*QueryResultResponse) ProtoMessage() {} func (x *QueryResultResponse) ProtoReflect() protoreflect.Message { mi := &file_frontend_frontendpb_frontend_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -130,58 +126,36 @@ func (*QueryResultResponse) Descriptor() ([]byte, []int) { var File_frontend_frontendpb_frontend_proto protoreflect.FileDescriptor -var file_frontend_frontendpb_frontend_proto_rawDesc = []byte{ - 0x0a, 0x22, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2f, 0x66, 0x72, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x64, 0x70, 0x62, 0x2f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x70, 0x62, - 0x1a, 0x19, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, - 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x75, 0x74, 0x69, - 0x6c, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8e, 0x01, 0x0a, 0x12, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x79, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x79, 0x49, 0x44, 0x12, 0x3a, 0x0a, 0x0c, 0x68, 0x74, - 0x74, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x54, 0x50, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0c, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x53, 0x74, - 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0x66, 0x0a, 0x12, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x46, 0x6f, 0x72, - 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x12, 0x50, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1e, 0x2e, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x64, 0x70, 0x62, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x64, 0x70, 0x62, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x9d, 0x01, 0x0a, 0x0e, 0x63, 0x6f, - 0x6d, 0x2e, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x70, 0x62, 0x42, 0x0d, 0x46, 0x72, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x34, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, - 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, - 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x64, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x46, 0x58, 0x58, 0xaa, 0x02, 0x0a, 0x46, 0x72, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x64, 0x70, 0x62, 0xca, 0x02, 0x0a, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x64, 0x70, 0x62, 0xe2, 0x02, 0x16, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x70, 0x62, - 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0a, 0x46, - 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} +const file_frontend_frontendpb_frontend_proto_rawDesc = "" + + "\n" + + "\"frontend/frontendpb/frontend.proto\x12\n" + + "frontendpb\x1a\x19querier/stats/stats.proto\x1a\x1cutil/httpgrpc/httpgrpc.proto\"\x8e\x01\n" + + "\x12QueryResultRequest\x12\x18\n" + + "\aqueryID\x18\x01 \x01(\x04R\aqueryID\x12:\n" + + "\fhttpResponse\x18\x02 \x01(\v2\x16.httpgrpc.HTTPResponseR\fhttpResponse\x12\"\n" + + "\x05stats\x18\x03 \x01(\v2\f.stats.StatsR\x05stats\"\x15\n" + + "\x13QueryResultResponse2f\n" + + "\x12FrontendForQuerier\x12P\n" + + "\vQueryResult\x12\x1e.frontendpb.QueryResultRequest\x1a\x1f.frontendpb.QueryResultResponse\"\x00B\xa0\x01\n" + + "\x0ecom.frontendpbB\rFrontendProtoP\x01Z7github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb\xa2\x02\x03FXX\xaa\x02\n" + + "Frontendpb\xca\x02\n" + + "Frontendpb\xe2\x02\x16Frontendpb\\GPBMetadata\xea\x02\n" + + "Frontendpbb\x06proto3" var ( file_frontend_frontendpb_frontend_proto_rawDescOnce sync.Once - file_frontend_frontendpb_frontend_proto_rawDescData = file_frontend_frontendpb_frontend_proto_rawDesc + file_frontend_frontendpb_frontend_proto_rawDescData []byte ) func file_frontend_frontendpb_frontend_proto_rawDescGZIP() []byte { file_frontend_frontendpb_frontend_proto_rawDescOnce.Do(func() { - file_frontend_frontendpb_frontend_proto_rawDescData = protoimpl.X.CompressGZIP(file_frontend_frontendpb_frontend_proto_rawDescData) + file_frontend_frontendpb_frontend_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_frontend_frontendpb_frontend_proto_rawDesc), len(file_frontend_frontendpb_frontend_proto_rawDesc))) }) return file_frontend_frontendpb_frontend_proto_rawDescData } var file_frontend_frontendpb_frontend_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_frontend_frontendpb_frontend_proto_goTypes = []interface{}{ +var file_frontend_frontendpb_frontend_proto_goTypes = []any{ (*QueryResultRequest)(nil), // 0: frontendpb.QueryResultRequest (*QueryResultResponse)(nil), // 1: frontendpb.QueryResultResponse (*httpgrpc.HTTPResponse)(nil), // 2: httpgrpc.HTTPResponse @@ -204,37 +178,11 @@ func file_frontend_frontendpb_frontend_proto_init() { if File_frontend_frontendpb_frontend_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_frontend_frontendpb_frontend_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryResultRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_frontend_frontendpb_frontend_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryResultResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_frontend_frontendpb_frontend_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_frontend_frontendpb_frontend_proto_rawDesc), len(file_frontend_frontendpb_frontend_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -245,7 +193,6 @@ func file_frontend_frontendpb_frontend_proto_init() { MessageInfos: file_frontend_frontendpb_frontend_proto_msgTypes, }.Build() File_frontend_frontendpb_frontend_proto = out.File - file_frontend_frontendpb_frontend_proto_rawDesc = nil file_frontend_frontendpb_frontend_proto_goTypes = nil file_frontend_frontendpb_frontend_proto_depIdxs = nil } diff --git a/pkg/frontend/frontendpb/frontend_vtproto.pb.go b/pkg/frontend/frontendpb/frontend_vtproto.pb.go index b2491af94d..2acb923212 100644 --- a/pkg/frontend/frontendpb/frontend_vtproto.pb.go +++ b/pkg/frontend/frontendpb/frontend_vtproto.pb.go @@ -7,8 +7,8 @@ package frontendpb import ( context "context" fmt "fmt" - stats "github.com/grafana/pyroscope/pkg/querier/stats" - httpgrpc "github.com/grafana/pyroscope/pkg/util/httpgrpc" + stats "github.com/grafana/pyroscope/v2/pkg/querier/stats" + httpgrpc "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" protohelpers "github.com/planetscale/vtprotobuf/protohelpers" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/pkg/frontend/frontendpb/frontendpbconnect/frontend.connect.go b/pkg/frontend/frontendpb/frontendpbconnect/frontend.connect.go index 73e6cbc0f8..5f242e9f83 100644 --- a/pkg/frontend/frontendpb/frontendpbconnect/frontend.connect.go +++ b/pkg/frontend/frontendpb/frontendpbconnect/frontend.connect.go @@ -13,7 +13,7 @@ import ( connect "connectrpc.com/connect" context "context" errors "errors" - frontendpb "github.com/grafana/pyroscope/pkg/frontend/frontendpb" + frontendpb "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb" http "net/http" strings "strings" ) @@ -43,12 +43,6 @@ const ( FrontendForQuerierQueryResultProcedure = "/frontendpb.FrontendForQuerier/QueryResult" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - frontendForQuerierServiceDescriptor = frontendpb.File_frontend_frontendpb_frontend_proto.Services().ByName("FrontendForQuerier") - frontendForQuerierQueryResultMethodDescriptor = frontendForQuerierServiceDescriptor.Methods().ByName("QueryResult") -) - // FrontendForQuerierClient is a client for the frontendpb.FrontendForQuerier service. type FrontendForQuerierClient interface { QueryResult(context.Context, *connect.Request[frontendpb.QueryResultRequest]) (*connect.Response[frontendpb.QueryResultResponse], error) @@ -63,11 +57,12 @@ type FrontendForQuerierClient interface { // http://api.acme.com or https://acme.com/grpc). func NewFrontendForQuerierClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) FrontendForQuerierClient { baseURL = strings.TrimRight(baseURL, "/") + frontendForQuerierMethods := frontendpb.File_frontend_frontendpb_frontend_proto.Services().ByName("FrontendForQuerier").Methods() return &frontendForQuerierClient{ queryResult: connect.NewClient[frontendpb.QueryResultRequest, frontendpb.QueryResultResponse]( httpClient, baseURL+FrontendForQuerierQueryResultProcedure, - connect.WithSchema(frontendForQuerierQueryResultMethodDescriptor), + connect.WithSchema(frontendForQuerierMethods.ByName("QueryResult")), connect.WithClientOptions(opts...), ), } @@ -94,10 +89,11 @@ type FrontendForQuerierHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewFrontendForQuerierHandler(svc FrontendForQuerierHandler, opts ...connect.HandlerOption) (string, http.Handler) { + frontendForQuerierMethods := frontendpb.File_frontend_frontendpb_frontend_proto.Services().ByName("FrontendForQuerier").Methods() frontendForQuerierQueryResultHandler := connect.NewUnaryHandler( FrontendForQuerierQueryResultProcedure, svc.QueryResult, - connect.WithSchema(frontendForQuerierQueryResultMethodDescriptor), + connect.WithSchema(frontendForQuerierMethods.ByName("QueryResult")), connect.WithHandlerOptions(opts...), ) return "/frontendpb.FrontendForQuerier/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/frontend/readpath/query_backend_from.go b/pkg/frontend/readpath/query_backend_from.go new file mode 100644 index 0000000000..3b266885eb --- /dev/null +++ b/pkg/frontend/readpath/query_backend_from.go @@ -0,0 +1,92 @@ +package readpath + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/grafana/dskit/flagext" + "go.yaml.in/yaml/v3" +) + +// QueryBackendFrom is a flag/config type that accepts either an RFC3339 +// timestamp or the special value "auto". When set to "auto", the split +// point is resolved at query time by looking up the tenant's oldest +// profile time in the metastore. +type QueryBackendFrom struct { + Auto bool + Time time.Time +} + +func (q QueryBackendFrom) IsZero() bool { + return !q.Auto && q.Time.IsZero() +} + +// Set implements flag.Value. +func (q *QueryBackendFrom) Set(s string) error { + if s == "auto" { + q.Auto = true + q.Time = time.Time{} + return nil + } + q.Auto = false + return (*flagext.Time)(&q.Time).Set(s) +} + +// String implements flag.Value. +func (q QueryBackendFrom) String() string { + if q.Auto { + return "auto" + } + return flagext.Time(q.Time).String() +} + +func (q QueryBackendFrom) MarshalJSON() ([]byte, error) { + return json.Marshal(q.String()) +} + +func (q *QueryBackendFrom) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + return q.Set(s) +} + +func (q QueryBackendFrom) MarshalYAML() (interface{}, error) { + return q.String(), nil +} + +func (q *QueryBackendFrom) UnmarshalYAML(value *yaml.Node) error { + if value.Value == "" { + return nil + } + return q.Set(value.Value) +} + +func (q QueryBackendFrom) MarshalText() ([]byte, error) { + return []byte(q.String()), nil +} + +func (q *QueryBackendFrom) UnmarshalText(data []byte) error { + s := string(data) + if s == "" { + return nil + } + return q.Set(s) +} + +// SplitTime returns the split timestamp for routing queries. +// For a fixed timestamp, it returns the time directly. +// For "auto" mode, it queries the metastore for the tenant's oldest profile time. +// Returns zero time if the split cannot be determined. +func (q QueryBackendFrom) SplitTime(tenantOldestProfileTime func() (time.Time, error)) (time.Time, error) { + if !q.Auto { + return q.Time, nil + } + t, err := tenantOldestProfileTime() + if err != nil { + return time.Time{}, fmt.Errorf("failed to resolve auto split time: %w", err) + } + return t, nil +} diff --git a/pkg/frontend/readpath/query_backend_from_test.go b/pkg/frontend/readpath/query_backend_from_test.go new file mode 100644 index 0000000000..d699dc1af8 --- /dev/null +++ b/pkg/frontend/readpath/query_backend_from_test.go @@ -0,0 +1,161 @@ +package readpath + +import ( + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.yaml.in/yaml/v3" +) + +func TestQueryBackendFrom_Set(t *testing.T) { + tests := []struct { + name string + input string + wantAuto bool + wantTime time.Time + wantErr bool + }{ + { + name: "auto", + input: "auto", + wantAuto: true, + }, + { + name: "RFC3339 timestamp", + input: "2025-01-15T10:30:00Z", + wantTime: time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC), + }, + { + name: "date only", + input: "2025-01-15", + wantTime: time.Date(2025, 1, 15, 0, 0, 0, 0, time.UTC), + }, + { + name: "zero", + input: "0", + wantTime: time.Time{}, + }, + { + name: "invalid", + input: "not-a-date", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var q QueryBackendFrom + err := q.Set(tt.input) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.wantAuto, q.Auto) + if !tt.wantAuto { + assert.True(t, tt.wantTime.Equal(q.Time), "expected %v, got %v", tt.wantTime, q.Time) + } + }) + } +} + +func TestQueryBackendFrom_String(t *testing.T) { + assert.Equal(t, "auto", QueryBackendFrom{Auto: true}.String()) + assert.Equal(t, "0", QueryBackendFrom{}.String()) +} + +func TestQueryBackendFrom_IsZero(t *testing.T) { + assert.True(t, QueryBackendFrom{}.IsZero()) + assert.False(t, QueryBackendFrom{Auto: true}.IsZero()) + assert.False(t, QueryBackendFrom{Time: time.Now()}.IsZero()) +} + +func TestQueryBackendFrom_JSON(t *testing.T) { + tests := []struct { + name string + value QueryBackendFrom + json string + }{ + { + name: "auto", + value: QueryBackendFrom{Auto: true}, + json: `"auto"`, + }, + { + name: "zero", + value: QueryBackendFrom{}, + json: `"0"`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := json.Marshal(tt.value) + require.NoError(t, err) + assert.Equal(t, tt.json, string(data)) + + var decoded QueryBackendFrom + err = json.Unmarshal(data, &decoded) + require.NoError(t, err) + assert.Equal(t, tt.value.Auto, decoded.Auto) + }) + } +} + +func TestQueryBackendFrom_YAML(t *testing.T) { + tests := []struct { + name string + value QueryBackendFrom + yaml string + }{ + { + name: "auto", + value: QueryBackendFrom{Auto: true}, + yaml: "auto\n", + }, + { + name: "zero", + value: QueryBackendFrom{}, + yaml: "\"0\"\n", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := yaml.Marshal(tt.value) + require.NoError(t, err) + assert.Equal(t, tt.yaml, string(data)) + + var decoded QueryBackendFrom + err = yaml.Unmarshal(data, &decoded) + require.NoError(t, err) + assert.Equal(t, tt.value.Auto, decoded.Auto) + }) + } +} + +func TestQueryBackendFrom_SplitTime(t *testing.T) { + t.Run("fixed time", func(t *testing.T) { + ts := time.Date(2025, 1, 15, 0, 0, 0, 0, time.UTC) + q := QueryBackendFrom{Time: ts} + result, err := q.SplitTime(func() (time.Time, error) { + t.Fatal("should not be called") + return time.Time{}, nil + }) + require.NoError(t, err) + assert.True(t, ts.Equal(result)) + }) + + t.Run("auto resolves from callback", func(t *testing.T) { + expected := time.Date(2025, 3, 1, 0, 0, 0, 0, time.UTC) + q := QueryBackendFrom{Auto: true} + result, err := q.SplitTime(func() (time.Time, error) { + return expected, nil + }) + require.NoError(t, err) + assert.True(t, expected.Equal(result)) + }) +} diff --git a/pkg/frontend/readpath/query_service_handler.go b/pkg/frontend/readpath/query_service_handler.go new file mode 100644 index 0000000000..fa410a0290 --- /dev/null +++ b/pkg/frontend/readpath/query_service_handler.go @@ -0,0 +1,304 @@ +package readpath + +import ( + "context" + "errors" + "slices" + + "connectrpc.com/connect" + "golang.org/x/sync/errgroup" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/pprof" +) + +var _ querierv1connect.QuerierServiceHandler = (*Router)(nil) + +func (r *Router) LabelValues( + ctx context.Context, + c *connect.Request[typesv1.LabelValuesRequest], +) (*connect.Response[typesv1.LabelValuesResponse], error) { + return Query[typesv1.LabelValuesRequest, typesv1.LabelValuesResponse](ctx, r, c, + func(_, _ *typesv1.LabelValuesRequest) {}, + func(a, b *typesv1.LabelValuesResponse) (*typesv1.LabelValuesResponse, error) { + m := phlaremodel.NewLabelMerger() + m.MergeLabelValues(a.Names) + m.MergeLabelValues(b.Names) + return &typesv1.LabelValuesResponse{Names: m.LabelValues()}, nil + }) +} + +func (r *Router) LabelNames( + ctx context.Context, + c *connect.Request[typesv1.LabelNamesRequest], +) (*connect.Response[typesv1.LabelNamesResponse], error) { + return Query[typesv1.LabelNamesRequest, typesv1.LabelNamesResponse](ctx, r, c, + func(_, _ *typesv1.LabelNamesRequest) {}, + func(a, b *typesv1.LabelNamesResponse) (*typesv1.LabelNamesResponse, error) { + m := phlaremodel.NewLabelMerger() + m.MergeLabelNames(a.Names) + m.MergeLabelNames(b.Names) + return &typesv1.LabelNamesResponse{Names: m.LabelNames()}, nil + }) +} + +func (r *Router) Series( + ctx context.Context, + c *connect.Request[querierv1.SeriesRequest], +) (*connect.Response[querierv1.SeriesResponse], error) { + return Query[querierv1.SeriesRequest, querierv1.SeriesResponse](ctx, r, c, + func(_, _ *querierv1.SeriesRequest) {}, + func(a, b *querierv1.SeriesResponse) (*querierv1.SeriesResponse, error) { + m := phlaremodel.NewLabelMerger() + m.MergeSeries(a.LabelsSet) + m.MergeSeries(b.LabelsSet) + return &querierv1.SeriesResponse{LabelsSet: m.Labels()}, nil + }) +} + +func (r *Router) SelectMergeStacktraces( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + if c.Msg.Format == querierv1.ProfileFormat_PROFILE_FORMAT_PPROF { + return Query[querierv1.SelectMergeStacktracesRequest, querierv1.SelectMergeStacktracesResponse](ctx, r, c, + func(_, _ *querierv1.SelectMergeStacktracesRequest) {}, + func(a, b *querierv1.SelectMergeStacktracesResponse) (*querierv1.SelectMergeStacktracesResponse, error) { + var m pprof.ProfileMerge + left := a.GetPprof().GetProfile() + if left == nil { + return nil, connect.NewError(connect.CodeInternal, errors.New("old read path returned no pprof profile")) + } + right := b.GetPprof().GetProfile() + if right == nil { + return nil, connect.NewError(connect.CodeInternal, errors.New("new read path returned no pprof profile")) + } + if err := m.Merge(left, false); err != nil { + return nil, err + } + if err := m.Merge(right, false); err != nil { + return nil, err + } + return &querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{Profile: m.Profile()}, + }, nil + }) + } + + // We always query data in the tree format and + // return it in the format requested by the client. + f := c.Msg.Format + c.Msg.Format = querierv1.ProfileFormat_PROFILE_FORMAT_TREE + resp, err := Query[querierv1.SelectMergeStacktracesRequest, querierv1.SelectMergeStacktracesResponse](ctx, r, c, + func(_, _ *querierv1.SelectMergeStacktracesRequest) {}, + func(a, b *querierv1.SelectMergeStacktracesResponse) (*querierv1.SelectMergeStacktracesResponse, error) { + m := phlaremodel.NewTreeMerger[phlaremodel.FunctionName, phlaremodel.FunctionNameI]() + if err := m.MergeTreeBytes(a.Tree); err != nil { + return nil, err + } + if err := m.MergeTreeBytes(b.Tree); err != nil { + return nil, err + } + tree := m.Tree().Bytes(c.Msg.GetMaxNodes(), nil) + return &querierv1.SelectMergeStacktracesResponse{Tree: tree}, nil + }, + ) + if err == nil && f != c.Msg.Format { + resp.Msg.Flamegraph = phlaremodel.NewFlameGraph( + phlaremodel.MustUnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Msg.Tree), + c.Msg.GetMaxNodes()) + } + return resp, err +} + +func (r *Router) SelectMergeSpanProfile( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeSpanProfileRequest], +) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + // We always query data in the tree format and + // return it in the format requested by the client. + f := c.Msg.Format + c.Msg.Format = querierv1.ProfileFormat_PROFILE_FORMAT_TREE + resp, err := Query[querierv1.SelectMergeSpanProfileRequest, querierv1.SelectMergeSpanProfileResponse](ctx, r, c, + func(_, _ *querierv1.SelectMergeSpanProfileRequest) {}, + func(a, b *querierv1.SelectMergeSpanProfileResponse) (*querierv1.SelectMergeSpanProfileResponse, error) { + m := phlaremodel.NewTreeMerger[phlaremodel.FunctionName, phlaremodel.FunctionNameI]() + if err := m.MergeTreeBytes(a.Tree); err != nil { + return nil, err + } + if err := m.MergeTreeBytes(b.Tree); err != nil { + return nil, err + } + tree := m.Tree().Bytes(c.Msg.GetMaxNodes(), nil) + return &querierv1.SelectMergeSpanProfileResponse{Tree: tree}, nil + }, + ) + if err == nil && f != c.Msg.Format { + resp.Msg.Flamegraph = phlaremodel.NewFlameGraph( + phlaremodel.MustUnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Msg.Tree), + c.Msg.GetMaxNodes()) + } + return resp, err +} + +func (r *Router) SelectMergeProfile( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeProfileRequest], +) (*connect.Response[profilev1.Profile], error) { + return Query[querierv1.SelectMergeProfileRequest, profilev1.Profile](ctx, r, c, + func(_, _ *querierv1.SelectMergeProfileRequest) {}, + func(a, b *profilev1.Profile) (*profilev1.Profile, error) { + var m pprof.ProfileMerge + if err := m.Merge(a, false); err != nil { + return nil, err + } + if err := m.Merge(b, false); err != nil { + return nil, err + } + return m.Profile(), nil + }) +} + +func (r *Router) SelectSeries( + ctx context.Context, + c *connect.Request[querierv1.SelectSeriesRequest], +) (*connect.Response[querierv1.SelectSeriesResponse], error) { + limit := int(c.Msg.GetLimit()) + return Query[querierv1.SelectSeriesRequest, querierv1.SelectSeriesResponse](ctx, r, c, + func(a, b *querierv1.SelectSeriesRequest) { + // If both frontends are queries, the limit must + // be applied after merging the time series, as + // the function is not associative. Otherwise, each + // frontend applies the limit independently. + if a != nil && b != nil && limit > 0 { + a.Limit = nil + b.Limit = nil + } + }, + func(a, b *querierv1.SelectSeriesResponse) (*querierv1.SelectSeriesResponse, error) { + m := timeseries.NewMerger(true) + m.MergeTimeSeries(a.Series) + m.MergeTimeSeries(b.Series) + return &querierv1.SelectSeriesResponse{Series: m.Top(limit)}, nil + }) +} + +func (r *Router) SelectHeatmap( + ctx context.Context, + c *connect.Request[querierv1.SelectHeatmapRequest], +) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + return Query[querierv1.SelectHeatmapRequest, querierv1.SelectHeatmapResponse](ctx, r, c, + func(_, _ *querierv1.SelectHeatmapRequest) {}, + func(a, b *querierv1.SelectHeatmapResponse) (*querierv1.SelectHeatmapResponse, error) { + // Merge the series from both responses + var allSeries []*typesv1.HeatmapSeries + if a != nil { + allSeries = append(allSeries, a.Series...) + } + if b != nil { + allSeries = append(allSeries, b.Series...) + } + return &querierv1.SelectHeatmapResponse{ + Series: allSeries, + }, nil + }) +} + +func (r *Router) Diff( + ctx context.Context, + c *connect.Request[querierv1.DiffRequest], +) (*connect.Response[querierv1.DiffResponse], error) { + g, ctx := errgroup.WithContext(ctx) + getTree := func(dst *phlaremodel.FunctionNameTree, req *querierv1.SelectMergeStacktracesRequest) func() error { + return func() error { + if req == nil { + req = &querierv1.SelectMergeStacktracesRequest{} + } else { + req = req.CloneVT() + } + req.Format = querierv1.ProfileFormat_PROFILE_FORMAT_TREE + resp, err := r.SelectMergeStacktraces(ctx, connect.NewRequest(req)) + if err != nil { + return err + } + tree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Msg.Tree) + if err != nil { + return err + } + *dst = *tree + return nil + } + } + + var left, right phlaremodel.FunctionNameTree + g.Go(getTree(&left, c.Msg.Left)) + g.Go(getTree(&right, c.Msg.Right)) + if err := g.Wait(); err != nil { + return nil, err + } + + diff, err := phlaremodel.NewFlamegraphDiff(&left, &right, 0) + if err != nil { + return nil, err + } + + return connect.NewResponse(&querierv1.DiffResponse{Flamegraph: diff}), nil +} + +// Stubs: these methods are not supposed to be implemented +// and only needed to satisfy interfaces. + +func (r *Router) AnalyzeQuery( + ctx context.Context, + req *connect.Request[querierv1.AnalyzeQueryRequest], +) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { + if r.oldFrontend != nil { + return r.oldFrontend.AnalyzeQuery(ctx, req) + } + return connect.NewResponse(&querierv1.AnalyzeQueryResponse{}), nil +} + +func (r *Router) GetProfileStats( + ctx context.Context, + c *connect.Request[typesv1.GetProfileStatsRequest], +) (*connect.Response[typesv1.GetProfileStatsResponse], error) { + return Query[typesv1.GetProfileStatsRequest, typesv1.GetProfileStatsResponse](ctx, r, c, + func(_, _ *typesv1.GetProfileStatsRequest) {}, + func(a, b *typesv1.GetProfileStatsResponse) (*typesv1.GetProfileStatsResponse, error) { + oldestProfileTime := a.OldestProfileTime + newestProfileTime := a.NewestProfileTime + if b.OldestProfileTime < oldestProfileTime { + oldestProfileTime = b.OldestProfileTime + } + if b.NewestProfileTime > newestProfileTime { + newestProfileTime = b.NewestProfileTime + } + return &typesv1.GetProfileStatsResponse{ + DataIngested: a.DataIngested || b.DataIngested, + OldestProfileTime: oldestProfileTime, + NewestProfileTime: newestProfileTime, + }, nil + }) +} + +func (r *Router) ProfileTypes( + ctx context.Context, + c *connect.Request[querierv1.ProfileTypesRequest], +) (*connect.Response[querierv1.ProfileTypesResponse], error) { + return Query[querierv1.ProfileTypesRequest, querierv1.ProfileTypesResponse](ctx, r, c, + func(_, _ *querierv1.ProfileTypesRequest) {}, + func(a, b *querierv1.ProfileTypesResponse) (*querierv1.ProfileTypesResponse, error) { + pTypes := a.ProfileTypes + for _, pType := range b.ProfileTypes { + if !slices.Contains(pTypes, pType) { + pTypes = append(pTypes, pType) + } + } + return &querierv1.ProfileTypesResponse{ProfileTypes: pTypes}, nil + }) +} diff --git a/pkg/frontend/readpath/queryfrontend/compat.go b/pkg/frontend/readpath/queryfrontend/compat.go new file mode 100644 index 0000000000..3be1402918 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/compat.go @@ -0,0 +1,90 @@ +package queryfrontend + +import ( + "context" + "fmt" + "strings" + + "connectrpc.com/connect" + "github.com/prometheus/prometheus/model/labels" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/querybackend" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +// querySingle is a helper method that expects a single report +// of the appropriate type in the response; this method in an +// adapter to the old query API. +func (q *QueryFrontend) querySingle( + ctx context.Context, + req *queryv1.QueryRequest, + backendF backendWrapper, +) (*queryv1.Report, error) { + if len(req.Query) != 1 { + // Nil report is a valid response. + return nil, nil + } + t := querybackend.QueryReportType(req.Query[0].QueryType) + resp, err := q.doQuery(ctx, req, backendF) + if err != nil { + code, sanitized := http.ClientHTTPStatusAndError(err) + return nil, connect.NewError(connectgrpc.HTTPToCode(int32(code)), sanitized) + } + var r *queryv1.Report + for _, x := range resp.Reports { + if x.ReportType == t { + r = x + break + } + } + return r, nil +} + +func buildLabelSelectorFromMatchers(matchers []string) (string, error) { + parsed, err := parseMatchers(matchers) + if err != nil { + return "", fmt.Errorf("parsing label selector: %w", err) + } + return matchersToLabelSelector(parsed), nil +} + +func buildLabelSelectorWithProfileType(labelSelector, profileTypeID string) (string, error) { + matchers, err := phlaremodel.ParseMetricSelector(labelSelector) + if err != nil { + return "", fmt.Errorf("parsing label selector %q: %w", labelSelector, err) + } + profileType, err := phlaremodel.ParseProfileTypeSelector(profileTypeID) + if err != nil { + return "", fmt.Errorf("parsing profile type ID %q: %w", profileTypeID, err) + } + matchers = append(matchers, phlaremodel.SelectorFromProfileType(profileType)) + return matchersToLabelSelector(matchers), nil +} + +func parseMatchers(matchers []string) ([]*labels.Matcher, error) { + parsed := make([]*labels.Matcher, 0, len(matchers)) + for _, m := range matchers { + s, err := phlaremodel.ParseMetricSelector(m) + if err != nil { + return nil, fmt.Errorf("failed to parse label selector %q: %w", s, err) + } + parsed = append(parsed, s...) + } + return parsed, nil +} + +func matchersToLabelSelector(matchers []*labels.Matcher) string { + var q strings.Builder + q.WriteByte('{') + for i, m := range matchers { + if i > 0 { + q.WriteByte(',') + } + q.WriteString(m.String()) + } + q.WriteByte('}') + return q.String() +} diff --git a/pkg/frontend/readpath/queryfrontend/compat_test.go b/pkg/frontend/readpath/queryfrontend/compat_test.go new file mode 100644 index 0000000000..a81def4d1c --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/compat_test.go @@ -0,0 +1,194 @@ +package queryfrontend + +import ( + "testing" + + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/require" +) + +func Test_matchersToLabelSelector(t *testing.T) { + tests := []struct { + name string + matchers []*labels.Matcher + expected string + }{ + { + name: "empty matchers", + matchers: []*labels.Matcher{}, + expected: "{}", + }, + { + name: "single standard label name with equals", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "my-service"), + }, + expected: `{service_name="my-service"}`, + }, + { + name: "label name with dots", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service.name", "test"), + }, + expected: `{"service.name"="test"}`, + }, + { + name: "label name with hyphen", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service-name", "value"), + }, + expected: `{"service-name"="value"}`, + }, + { + name: "label name with special character (√)", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "my√label", "value"), + }, + expected: `{"my√label"="value"}`, + }, + { + name: "label name with unicode (世界)", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "世界", "value"), + }, + expected: `{"世界"="value"}`, + }, + { + name: "label name starting with number", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "123label", "value"), + }, + expected: `{"123label"="value"}`, + }, + { + name: "not equal matcher", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchNotEqual, "service_name", "test"), + }, + expected: `{service_name!="test"}`, + }, + { + name: "regex match matcher", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchRegexp, "service_name", ".*test.*"), + }, + expected: `{service_name=~".*test.*"}`, + }, + { + name: "regex not match matcher", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchNotRegexp, "service_name", "test.*"), + }, + expected: `{service_name!~"test.*"}`, + }, + { + name: "multiple standard matchers", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "my-service"), + labels.MustNewMatcher(labels.MatchEqual, "environment", "production"), + labels.MustNewMatcher(labels.MatchEqual, "region", "us-west-2"), + }, + expected: `{service_name="my-service",environment="production",region="us-west-2"}`, + }, + { + name: "multiple matchers with special characters", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service.name", "my-service"), + labels.MustNewMatcher(labels.MatchEqual, "app-version", "v1.0"), + labels.MustNewMatcher(labels.MatchEqual, "my√label", "value"), + }, + expected: `{"service.name"="my-service","app-version"="v1.0","my√label"="value"}`, + }, + { + name: "mixed matcher types", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "service_name", "test"), + labels.MustNewMatcher(labels.MatchNotEqual, "environment", "dev"), + labels.MustNewMatcher(labels.MatchRegexp, "region", "us-.*"), + }, + expected: `{service_name="test",environment!="dev",region=~"us-.*"}`, + }, + { + name: "value with quotes needs escaping", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "label", `value"with"quotes`), + }, + expected: `{label="value\"with\"quotes"}`, + }, + { + name: "label name and value with special characters", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "label-name.special", "value/with\\special"), + }, + expected: `{"label-name.special"="value/with\\special"}`, + }, + { + name: "standard alphanumeric labels don't get quoted", + matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), + labels.MustNewMatcher(labels.MatchEqual, "foo123", "bar456"), + labels.MustNewMatcher(labels.MatchEqual, "__internal__", "value"), + }, + expected: `{foo="bar",foo123="bar456",__internal__="value"}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := matchersToLabelSelector(tt.matchers) + require.Equal(t, tt.expected, result, "matchersToLabelSelector output mismatch") + }) + } +} + +func Test_buildLabelSelectorFromMatchers(t *testing.T) { + tests := []struct { + name string + matchers []string + expected string + wantErr bool + }{ + { + name: "single matcher", + matchers: []string{`{service_name="test"}`}, + expected: `{service_name="test"}`, + wantErr: false, + }, + { + name: "matcher with special characters in label name", + matchers: []string{`{"service.name"="test"}`}, + expected: `{"service.name"="test"}`, + wantErr: false, + }, + { + name: "multiple matchers", + matchers: []string{`{service_name="test"}`, `{environment="prod"}`}, + expected: `{service_name="test",environment="prod"}`, + wantErr: false, + }, + { + name: "invalid matcher syntax", + matchers: []string{`{unclosed`}, + expected: "", + wantErr: true, + }, + { + name: "empty matchers", + matchers: []string{}, + expected: `{}`, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := buildLabelSelectorFromMatchers(tt.matchers) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, result) + } + }) + } +} diff --git a/pkg/frontend/readpath/queryfrontend/diagnostics/client_wrapper.go b/pkg/frontend/readpath/queryfrontend/diagnostics/client_wrapper.go new file mode 100644 index 0000000000..7229d45a4a --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/diagnostics/client_wrapper.go @@ -0,0 +1,174 @@ +package diagnostics + +import ( + "context" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + "google.golang.org/protobuf/proto" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +// Wrapper wraps a QuerierServiceClient to handle query diagnostics. +type Wrapper struct { + logger log.Logger + client querierv1connect.QuerierServiceClient + store Writer +} + +type Writer interface { + AddRequest(id string, method string, req any) + AddResponse(id string, resp any, responseSizeBytes int64, responseTimeMs int64) + Flush(ctx context.Context, tenantID string, id string) error +} + +func NewWrapper(logger log.Logger, client querierv1connect.QuerierServiceClient, writer Writer) *Wrapper { + return &Wrapper{ + logger: logger, + client: client, + store: writer, + } +} + +// flushDiagnostics flushes collected diagnostics to the store if collection is enabled. +func flushDiagnostics[Req, Resp any](w *Wrapper, ctx context.Context, method string, req *connect.Request[Req], resp *connect.Response[Resp]) { + diagCtx := From(ctx) + if diagCtx == nil || !diagCtx.Collect { + return + } + + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil || len(tenantIDs) == 0 { + level.Warn(w.logger).Log("msg", "failed to get tenant ID for diagnostics flush", "err", err) + return + } + + w.store.AddRequest(diagCtx.ID, method, req.Msg) + + if resp != nil { + var respMsg any = resp.Msg + var responseSizeBytes int64 + if respMsgProto, ok := respMsg.(proto.Message); ok { + responseSizeBytes = int64(proto.Size(respMsgProto)) + } + responseTimeMs := time.Since(diagCtx.startTime).Milliseconds() + w.store.AddResponse(diagCtx.ID, respMsg, responseSizeBytes, responseTimeMs) + resp.Header().Set(IdHeader, diagCtx.ID) + } + + // Flush asynchronously to avoid blocking the response. + // Use a detached context since the request context may be cancelled. + tenantID := tenantIDs[0] + diagID := diagCtx.ID + go func() { + if err := w.store.Flush(context.Background(), tenantID, diagID); err != nil { + level.Warn(w.logger).Log("msg", "failed to flush diagnostics", "id", diagID, "err", err) + } + }() +} + +func (w *Wrapper) ProfileTypes(ctx context.Context, req *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error) { + resp, err := w.client.ProfileTypes(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "ProfileTypes", req, resp) + } + return resp, err +} + +func (w *Wrapper) LabelValues(ctx context.Context, req *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { + resp, err := w.client.LabelValues(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "LabelValues", req, resp) + } + return resp, err +} + +func (w *Wrapper) LabelNames(ctx context.Context, req *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { + resp, err := w.client.LabelNames(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "LabelNames", req, resp) + } + return resp, err +} + +func (w *Wrapper) Series(ctx context.Context, req *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error) { + resp, err := w.client.Series(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "Series", req, resp) + } + return resp, err +} + +func (w *Wrapper) SelectMergeStacktraces(ctx context.Context, req *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + resp, err := w.client.SelectMergeStacktraces(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "SelectMergeStacktraces", req, resp) + } + return resp, err +} + +func (w *Wrapper) SelectMergeSpanProfile(ctx context.Context, req *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + resp, err := w.client.SelectMergeSpanProfile(ctx, req) //nolint:staticcheck // Required querier.v1 compatibility wrapper. + if resp != nil { + flushDiagnostics(w, ctx, "SelectMergeSpanProfile", req, resp) + } + return resp, err +} + +func (w *Wrapper) SelectMergeProfile(ctx context.Context, req *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[profilev1.Profile], error) { + resp, err := w.client.SelectMergeProfile(ctx, req) //nolint:staticcheck // Required querier.v1 compatibility wrapper. + if resp != nil { + flushDiagnostics(w, ctx, "SelectMergeProfile", req, resp) + } + return resp, err +} + +func (w *Wrapper) SelectSeries(ctx context.Context, req *connect.Request[querierv1.SelectSeriesRequest]) (*connect.Response[querierv1.SelectSeriesResponse], error) { + resp, err := w.client.SelectSeries(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "SelectSeries", req, resp) + } + return resp, err +} + +func (w *Wrapper) SelectHeatmap(ctx context.Context, req *connect.Request[querierv1.SelectHeatmapRequest]) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + resp, err := w.client.SelectHeatmap(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "SelectHeatmap", req, resp) + } + return resp, err +} + +func (w *Wrapper) Diff(ctx context.Context, req *connect.Request[querierv1.DiffRequest]) (*connect.Response[querierv1.DiffResponse], error) { + resp, err := w.client.Diff(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "Diff", req, resp) + } + return resp, err +} + +func (w *Wrapper) GetProfileStats(ctx context.Context, req *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) { + resp, err := w.client.GetProfileStats(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "GetProfileStats", req, resp) + } + return resp, err +} + +func (w *Wrapper) AnalyzeQuery(ctx context.Context, req *connect.Request[querierv1.AnalyzeQueryRequest]) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { + resp, err := w.client.AnalyzeQuery(ctx, req) + if resp != nil { + flushDiagnostics(w, ctx, "AnalyzeQuery", req, resp) + } + return resp, err +} + +// Ensure Wrapper implements the interface +var _ querierv1connect.QuerierServiceClient = (*Wrapper)(nil) diff --git a/pkg/frontend/readpath/queryfrontend/diagnostics/interceptor.go b/pkg/frontend/readpath/queryfrontend/diagnostics/interceptor.go new file mode 100644 index 0000000000..b533301411 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/diagnostics/interceptor.go @@ -0,0 +1,90 @@ +package diagnostics + +import ( + "context" + "strings" + "time" + + "connectrpc.com/connect" +) + +const ( + RequestHeader = "X-Pyroscope-Collect-Diagnostics" + IdHeader = "X-Pyroscope-Diagnostics-Id" +) + +// Context key for diagnostics context. +type contextKey struct{} + +// Context holds diagnostics collection state injected into the context. +type Context struct { + Collect bool + startTime time.Time + ID string +} + +// InjectCollectDiagnostics injects the diagnostics collection flag and start time into the context. +func InjectCollectDiagnostics(ctx context.Context, collect bool) context.Context { + id := "" + if collect { + id = generateUUID() + } + return context.WithValue(ctx, contextKey{}, &Context{ + Collect: collect, + startTime: time.Now(), + ID: id, + }) +} + +// From reads the diagnostics context from the context. +func From(ctx context.Context) *Context { + if v, ok := ctx.Value(contextKey{}).(*Context); ok { + return v + } + return nil +} + +// InjectCollectDiagnosticsFromHeader checks the request header and injects the flag into context. +func InjectCollectDiagnosticsFromHeader(ctx context.Context, headers map[string][]string) context.Context { + return InjectCollectDiagnostics(ctx, shouldCollectDiagnostics(headers)) +} + +// shouldCollectDiagnostics checks if a diagnostics collection was requested. +func shouldCollectDiagnostics(headers map[string][]string) bool { + values := headers[RequestHeader] + if len(values) == 0 { + values = headers[strings.ToLower(RequestHeader)] + } + for _, v := range values { + if v == "true" || v == "1" { + return true + } + } + return false +} + +// Interceptor is a connect interceptor that extracts the diagnostics +// collection flag from request headers and injects it into the context. +var Interceptor = &interceptor{} + +type interceptor struct{} + +func (i *interceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { + return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { + if !req.Spec().IsClient { + ctx = InjectCollectDiagnosticsFromHeader(ctx, req.Header()) + } + return next(ctx, req) + } +} + +func (i *interceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc { + return next +} + +func (i *interceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc { + return func(ctx context.Context, conn connect.StreamingHandlerConn) error { + ctx = InjectCollectDiagnosticsFromHeader(ctx, conn.RequestHeader()) + return next(ctx, conn) + } +} diff --git a/pkg/frontend/readpath/queryfrontend/diagnostics/store.go b/pkg/frontend/readpath/queryfrontend/diagnostics/store.go new file mode 100644 index 0000000000..cc946d1cc6 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/diagnostics/store.go @@ -0,0 +1,560 @@ +package diagnostics + +import ( + "archive/zip" + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "slices" + "sort" + "strings" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/google/uuid" + "github.com/grafana/dskit/services" + "github.com/thanos-io/objstore" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +const ( + // storagePrefix is the prefix for diagnostics objects in the bucket. + storagePrefix = "query-diagnostics/" + + // defaultTTL is how long diagnostics are kept before cleanup (7 days). + defaultTTL = 7 * 24 * time.Hour + + // cleanupInterval is how often the cleanup routine runs. + cleanupInterval = 1 * time.Hour +) + +// diagnosticFiles lists all files that make up a stored diagnostic. +var diagnosticFiles = []string{"metadata.json", "request.json", "response.json", "plan.json", "execution.json"} + +// StoredDiagnostics wraps the query diagnostics with metadata. +type StoredDiagnostics struct { + ID string `json:"id"` + CreatedAt time.Time `json:"created_at"` + TenantID string `json:"tenant_id"` + ResponseTimeMs int64 `json:"response_time_ms,omitempty"` + ResponseSizeBytes int64 `json:"response_size_bytes,omitempty"` + Method string `json:"method,omitempty"` + Request json.RawMessage `json:"request,omitempty"` + Response json.RawMessage `json:"response,omitempty"` + Plan *queryv1.QueryPlan `json:"plan,omitempty"` + Execution *queryv1.ExecutionNode `json:"execution,omitempty"` +} + +// storedMetadata is the structure saved in metadata.json +type storedMetadata struct { + ID string `json:"id"` + CreatedAt time.Time `json:"created_at"` + TenantID string `json:"tenant_id"` + ResponseTimeMs int64 `json:"response_time_ms,omitempty"` + ResponseSizeBytes int64 `json:"response_size_bytes,omitempty"` + Method string `json:"method,omitempty"` +} + +// Store manages query diagnostics storage and retrieval. +type Store struct { + services.Service + logger log.Logger + bucket objstore.Bucket + ttl time.Duration + + // inflightDiagnostics holds diagnostics in memory before flushing to bucket. + // Key is the diagnostics ID, value is *queryv1.Diagnostics. + inflightDiagnostics sync.Map +} + +// StoreOption is a functional option for configuring a Store. +type StoreOption func(*Store) + +// WithTTL sets the TTL for stored diagnostics. +func WithTTL(ttl time.Duration) StoreOption { + return func(s *Store) { + s.ttl = ttl + } +} + +// NewStore creates a new diagnostics store. +func NewStore(logger log.Logger, bucket objstore.Bucket, opts ...StoreOption) *Store { + s := &Store{ + logger: logger, + bucket: bucket, + ttl: defaultTTL, + } + for _, opt := range opts { + opt(s) + } + s.Service = services.NewBasicService(s.starting, s.running, s.stopping) + return s +} + +func (s *Store) run(ctx context.Context) error { + ticker := time.NewTicker(cleanupInterval) + defer ticker.Stop() + + s.runCleanup(ctx) + + for { + select { + case <-ctx.Done(): + return nil + case <-ticker.C: + s.runCleanup(ctx) + } + } +} + +func (s *Store) runCleanup(ctx context.Context) { + deleted, err := s.Cleanup(ctx) + if err != nil { + level.Warn(s.logger).Log("msg", "diagnostics cleanup failed", "err", err) + return + } + if deleted > 0 { + level.Info(s.logger).Log("msg", "cleaned up old diagnostics", "deleted", deleted) + } +} + +// inflightData holds request info and diagnostics for an in-progress request. +type inflightData struct { + Method string + Request any // The original request + Response any // The original response + ResponseSizeBytes int64 + ResponseTimeMs int64 + Diagnostics *queryv1.Diagnostics +} + +// Add stores diagnostics in memory for later flushing. +func (s *Store) Add(id string, diag *queryv1.Diagnostics) { + if id == "" || diag == nil { + return + } + val, _ := s.inflightDiagnostics.Load(id) + data, ok := val.(*inflightData) + if !ok { + data = &inflightData{} + } + data.Diagnostics = diag + s.inflightDiagnostics.Store(id, data) +} + +// AddRequest stores request related data for later flushing. +func (s *Store) AddRequest(id string, method string, request any) { + if id == "" { + return + } + val, _ := s.inflightDiagnostics.Load(id) + data, ok := val.(*inflightData) + if !ok { + data = &inflightData{} + } + data.Method = method + data.Request = request + s.inflightDiagnostics.Store(id, data) +} + +// AddResponse stores response related data for later flushing. +func (s *Store) AddResponse(id string, response any, sizeBytes int64, responseTimeMs int64) { + if id == "" { + return + } + val, _ := s.inflightDiagnostics.Load(id) + data, ok := val.(*inflightData) + if !ok { + data = &inflightData{} + } + data.Response = response + data.ResponseSizeBytes = sizeBytes + data.ResponseTimeMs = responseTimeMs +} + +// Flush saves the in-memory diagnostics to the bucket and removes from memory. +func (s *Store) Flush(ctx context.Context, tenantID, id string) error { + if id == "" || tenantID == "" { + return nil + } + + val, ok := s.inflightDiagnostics.LoadAndDelete(id) + if !ok { + level.Debug(s.logger).Log("msg", "no inflight diagnostics found", "id", id) + return nil + } + + data, ok := val.(*inflightData) + if !ok || data == nil { + return nil + } + + basePath := storagePrefix + tenantID + "/" + id + "/" + + metadata := &storedMetadata{ + ID: id, + CreatedAt: time.Now().UTC(), + TenantID: tenantID, + ResponseTimeMs: data.ResponseTimeMs, + ResponseSizeBytes: data.ResponseSizeBytes, + Method: data.Method, + } + if err := s.saveJSON(ctx, basePath+"metadata.json", metadata); err != nil { + return fmt.Errorf("failed to save metadata: %w", err) + } + + if data.Request != nil { + if err := s.saveJSON(ctx, basePath+"request.json", data.Request); err != nil { + return fmt.Errorf("failed to save request: %w", err) + } + } + + if data.Response != nil { + if err := s.saveJSON(ctx, basePath+"response.json", data.Response); err != nil { + return fmt.Errorf("failed to save response: %w", err) + } + } + + if data.Diagnostics != nil && data.Diagnostics.QueryPlan != nil && data.Diagnostics.QueryPlan.Root != nil { + if err := s.saveJSON(ctx, basePath+"plan.json", data.Diagnostics.QueryPlan); err != nil { + return fmt.Errorf("failed to save query plan: %w", err) + } + } + + if data.Diagnostics != nil && data.Diagnostics.ExecutionNode != nil { + if err := s.saveJSON(ctx, basePath+"execution.json", data.Diagnostics.ExecutionNode); err != nil { + return fmt.Errorf("failed to save execution trace: %w", err) + } + } + + level.Debug(s.logger).Log( + "msg", "stored query diagnostics", + "id", id, + "tenant_id", tenantID, + "method", data.Method, + "response_time_ms", data.ResponseTimeMs, + ) + + return nil +} + +func (s *Store) saveJSON(ctx context.Context, path string, v any) error { + data, err := json.Marshal(v) + if err != nil { + return err + } + return s.bucket.Upload(ctx, path, bytes.NewReader(data)) +} + +// Get retrieves diagnostics by tenant and ID. +func (s *Store) Get(ctx context.Context, tenantID, id string) (*StoredDiagnostics, error) { + if _, err := uuid.Parse(id); err != nil { + return nil, fmt.Errorf("invalid diagnostics ID: %s", err) + } + + basePath := storagePrefix + tenantID + "/" + id + "/" + + var metadata storedMetadata + if err := s.readJSON(ctx, basePath+"metadata.json", &metadata); err != nil { + if s.bucket.IsObjNotFoundErr(err) { + return nil, fmt.Errorf("diagnostics not found: %s", id) + } + return nil, fmt.Errorf("failed to get diagnostics: %w", err) + } + + stored := &StoredDiagnostics{ + ID: metadata.ID, + CreatedAt: metadata.CreatedAt, + TenantID: metadata.TenantID, + ResponseTimeMs: metadata.ResponseTimeMs, + ResponseSizeBytes: metadata.ResponseSizeBytes, + Method: metadata.Method, + } + + if data, err := s.readRaw(ctx, basePath+"request.json"); err == nil { + stored.Request = data + } + + var plan queryv1.QueryPlan + if err := s.readJSON(ctx, basePath+"plan.json", &plan); err == nil { + stored.Plan = &plan + } + + var execution queryv1.ExecutionNode + if err := s.readJSON(ctx, basePath+"execution.json", &execution); err == nil { + stored.Execution = &execution + } + + return stored, nil +} + +func (s *Store) readJSON(ctx context.Context, path string, v any) error { + reader, err := s.bucket.Get(ctx, path) + if err != nil { + return err + } + defer reader.Close() + + data, err := io.ReadAll(reader) + if err != nil { + return fmt.Errorf("failed to read: %w", err) + } + + return json.Unmarshal(data, v) +} + +func (s *Store) readRaw(ctx context.Context, path string) (json.RawMessage, error) { + reader, err := s.bucket.Get(ctx, path) + if err != nil { + return nil, err + } + defer reader.Close() + + data, err := io.ReadAll(reader) + if err != nil { + return nil, fmt.Errorf("failed to read: %w", err) + } + + return data, nil +} + +// Delete removes diagnostics by tenant and ID. +func (s *Store) Delete(ctx context.Context, tenantID, id string) error { + if _, err := uuid.Parse(id); err != nil { + return fmt.Errorf("invalid diagnostics ID: %s", err) + } + + basePath := storagePrefix + tenantID + "/" + id + "/" + + for _, file := range diagnosticFiles { + if err := s.bucket.Delete(ctx, basePath+file); err != nil { + if !s.bucket.IsObjNotFoundErr(err) { + return fmt.Errorf("failed to delete diagnostics file %s: %w", file, err) + } + } + } + + return nil +} + +// DiagnosticSummary contains minimal info for listing diagnostics. +type DiagnosticSummary struct { + ID string `json:"id"` + CreatedAt time.Time `json:"created_at"` + Method string `json:"method"` + ResponseTimeMs int64 `json:"response_time_ms"` + ResponseSizeBytes int64 `json:"response_size_bytes"` + Request json.RawMessage `json:"request,omitempty"` +} + +// ListByTenant returns all diagnostics for a given tenant. +func (s *Store) ListByTenant(ctx context.Context, tenant string) ([]*DiagnosticSummary, error) { + var summaries []*DiagnosticSummary + + prefix := storagePrefix + tenant + "/" + err := s.bucket.Iter(ctx, prefix, func(name string) error { + // Iter returns directory names with trailing slash (e.g., "query-diagnostics/tenant//") + if !strings.HasSuffix(name, "/") { + return nil + } + + // Extract the diagnostic ID from the directory name + rel := strings.TrimPrefix(name, prefix) + diagID := strings.TrimSuffix(rel, "/") + if diagID == "" { + return nil + } + + if _, err := uuid.Parse(diagID); err != nil { + return nil + } + + basePath := name + + var metadata storedMetadata + if err := s.readJSON(ctx, basePath+"metadata.json", &metadata); err != nil { + level.Warn(s.logger).Log("msg", "failed to read diagnostics metadata", "id", diagID, "err", err) + return nil + } + + summary := &DiagnosticSummary{ + ID: metadata.ID, + CreatedAt: metadata.CreatedAt, + Method: metadata.Method, + ResponseTimeMs: metadata.ResponseTimeMs, + ResponseSizeBytes: metadata.ResponseSizeBytes, + } + + if data, err := s.readRaw(ctx, basePath+"request.json"); err == nil { + summary.Request = data + } + + summaries = append(summaries, summary) + return nil + }) + + if err != nil { + return nil, fmt.Errorf("failed to list diagnostics: %w", err) + } + + // Sort by CreatedAt descending (newest first) + sort.Slice(summaries, func(i, j int) bool { + return summaries[i].CreatedAt.After(summaries[j].CreatedAt) + }) + + return summaries, nil +} + +// Cleanup removes diagnostics older than the TTL. +func (s *Store) Cleanup(ctx context.Context) (int, error) { + cutoff := time.Now().Add(-s.ttl) + deleted := 0 + + err := s.bucket.Iter(ctx, storagePrefix, func(name string) error { + if strings.HasSuffix(name, "/") { + return nil + } + if !strings.HasSuffix(name, ".json") { + return nil + } + + attrs, err := s.bucket.Attributes(ctx, name) + if err != nil { + level.Warn(s.logger).Log("msg", "failed to get attributes", "object", name, "err", err) + return nil + } + + if attrs.LastModified.Before(cutoff) { + if err := s.bucket.Delete(ctx, name); err != nil { + level.Warn(s.logger).Log("msg", "failed to delete old diagnostics", "object", name, "err", err) + } else { + deleted++ + } + } + return nil + }, objstore.WithRecursiveIter()) + + if err != nil { + return deleted, fmt.Errorf("cleanup iteration failed: %w", err) + } + + return deleted, nil +} + +// Export creates a zip archive containing all files for a diagnostic. +func (s *Store) Export(ctx context.Context, tenantID, id string) ([]byte, error) { + if _, err := uuid.Parse(id); err != nil { + return nil, fmt.Errorf("invalid diagnostics ID: %s", err) + } + + basePath := storagePrefix + tenantID + "/" + id + "/" + + var buf bytes.Buffer + zipWriter := zip.NewWriter(&buf) + defer zipWriter.Close() + + for _, file := range diagnosticFiles { + data, err := s.readRaw(ctx, basePath+file) + if err != nil { + if s.bucket.IsObjNotFoundErr(err) { + continue + } + return nil, fmt.Errorf("failed to read %s: %w", file, err) + } + + w, err := zipWriter.Create(file) + if err != nil { + return nil, fmt.Errorf("failed to create zip entry for %s: %w", file, err) + } + if _, err := w.Write(data); err != nil { + return nil, fmt.Errorf("failed to write %s to zip: %w", file, err) + } + } + + return buf.Bytes(), nil +} + +func generateUUID() string { + return uuid.New().String() +} + +// Import extracts a zip archive and stores the diagnostic files. +// The files are stored under the tenantID provided as an argument; the tenantID from the zip file is ignored. +func (s *Store) Import(ctx context.Context, tenantID string, newID string, zipData []byte) (string, error) { + if newID == "" { + newID = generateUUID() + } else if _, err := uuid.Parse(newID); err != nil { + return "", fmt.Errorf("invalid diagnostics ID: %s", err) + } + + zipReader, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData))) + if err != nil { + return "", fmt.Errorf("failed to read zip: %w", err) + } + + basePath := storagePrefix + tenantID + "/" + newID + "/" + + var hasMetadata bool + for _, file := range zipReader.File { + if !slices.Contains(diagnosticFiles, file.Name) { + continue + } + if file.Name == "metadata.json" { + hasMetadata = true + } + + rc, err := file.Open() + if err != nil { + return "", fmt.Errorf("failed to open %s from zip: %w", file.Name, err) + } + + data, err := io.ReadAll(rc) + rc.Close() + if err != nil { + return "", fmt.Errorf("failed to read %s from zip: %w", file.Name, err) + } + + // For metadata, update the ID and tenant to match the import + if file.Name == "metadata.json" { + var metadata storedMetadata + if err := json.Unmarshal(data, &metadata); err != nil { + return "", fmt.Errorf("failed to parse metadata: %w", err) + } + metadata.ID = newID + metadata.TenantID = tenantID + metadata.CreatedAt = time.Now().UTC() + data, err = json.Marshal(metadata) + if err != nil { + return "", fmt.Errorf("failed to marshal updated metadata: %w", err) + } + } + + if err := s.bucket.Upload(ctx, basePath+file.Name, bytes.NewReader(data)); err != nil { + return "", fmt.Errorf("failed to upload %s: %w", file.Name, err) + } + } + + if !hasMetadata { + return "", fmt.Errorf("zip archive must contain metadata.json") + } + + level.Info(s.logger).Log("msg", "imported diagnostics", "id", newID, "tenant_id", tenantID) + return newID, nil +} + +func (s *Store) starting(context.Context) error { + return nil +} + +func (s *Store) stopping(error) error { + return nil +} + +func (s *Store) running(ctx context.Context) error { + return s.run(ctx) +} diff --git a/pkg/frontend/readpath/queryfrontend/diagnostics/store_test.go b/pkg/frontend/readpath/queryfrontend/diagnostics/store_test.go new file mode 100644 index 0000000000..69bdb3f248 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/diagnostics/store_test.go @@ -0,0 +1,212 @@ +package diagnostics + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/thanos-io/objstore" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +func newTestStore(t *testing.T) *Store { + t.Helper() + bucket := objstore.NewInMemBucket() + return NewStore(log.NewNopLogger(), bucket) +} + +func TestStore_Get(t *testing.T) { + ctx := context.Background() + store := newTestStore(t) + + type testRequest struct { + Query string `json:"query"` + LabelFilter string `json:"label_filter"` + } + + request := &testRequest{ + Query: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + LabelFilter: `{service="test"}`, + } + + id := generateUUID() + store.AddRequest(id, "SelectMergeStacktraces", request) + err := store.Flush(ctx, "tenant-1", id) + require.NoError(t, err) + + stored, err := store.Get(ctx, "tenant-1", id) + require.NoError(t, err) + require.Equal(t, id, stored.ID) + require.Equal(t, "tenant-1", stored.TenantID) + require.Equal(t, "SelectMergeStacktraces", stored.Method) + require.NotNil(t, stored.Request) + + var storedRequest testRequest + require.NoError(t, json.Unmarshal(stored.Request, &storedRequest)) + require.Equal(t, request.LabelFilter, storedRequest.LabelFilter) +} + +func TestStore_GetNotFound(t *testing.T) { + ctx := context.Background() + store := newTestStore(t) + + _, err := store.Get(ctx, "tenant-1", "00000000000000000000000000000000") + require.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +func TestStore_GetInvalidID(t *testing.T) { + ctx := context.Background() + store := newTestStore(t) + + tests := []string{ + "", + "short", + "0000000000000000000000000000000g", // invalid hex char + } + + for _, id := range tests { + t.Run(id, func(t *testing.T) { + _, err := store.Get(ctx, "tenant-1", id) + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid") + }) + } +} + +func TestStore_Delete(t *testing.T) { + ctx := context.Background() + store := newTestStore(t) + + id := generateUUID() + store.AddRequest(id, "ProfileTypes", nil) + err := store.Flush(ctx, "tenant-1", id) + require.NoError(t, err) + + _, err = store.Get(ctx, "tenant-1", id) + require.NoError(t, err) + + err = store.Delete(ctx, "tenant-1", id) + require.NoError(t, err) + + _, err = store.Get(ctx, "tenant-1", id) + require.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +func TestStore_Cleanup(t *testing.T) { + ctx := context.Background() + bucket := objstore.NewInMemBucket() + store := NewStore(log.NewNopLogger(), bucket, WithTTL(1*time.Millisecond)) + + // Save some diagnostics + id1 := generateUUID() + store.AddRequest(id1, "ProfileTypes", nil) + err := store.Flush(ctx, "tenant-1", id1) + require.NoError(t, err) + + id2 := generateUUID() + store.AddRequest(id2, "ProfileTypes", nil) + err = store.Flush(ctx, "tenant-2", id2) + require.NoError(t, err) + + require.NoError(t, err) + + // Verify both exist + _, err = store.Get(ctx, "tenant-1", id1) + require.NoError(t, err) + _, err = store.Get(ctx, "tenant-2", id2) + require.NoError(t, err) + + // Wait for TTL to expire + time.Sleep(10 * time.Millisecond) + + deleted, err := store.Cleanup(ctx) + require.NoError(t, err) + assert.Equal(t, 2, deleted) + + _, err = store.Get(ctx, "tenant-1", id1) + require.Error(t, err) + assert.Contains(t, err.Error(), "not found") + + _, err = store.Get(ctx, "tenant-2", id2) + require.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +func TestStore_CleanupPreservesRecent(t *testing.T) { + ctx := context.Background() + bucket := objstore.NewInMemBucket() + store := NewStore(log.NewNopLogger(), bucket) + + // Use default TTL (7 days) - recent items should not be cleaned up + // Save some diagnostics + id := generateUUID() + store.AddRequest(id, "ProfileTypes", nil) + err := store.Flush(ctx, "tenant-1", id) + require.NoError(t, err) + + // Run cleanup immediately + deleted, err := store.Cleanup(ctx) + require.NoError(t, err) + assert.Equal(t, 0, deleted) + + // Verify it still exists + _, err = store.Get(ctx, "tenant-1", id) + require.NoError(t, err) +} + +func TestStore_AddAndFlush(t *testing.T) { + ctx := context.Background() + store := newTestStore(t) + + type testRequest struct { + Query string `json:"query"` + StartTime int64 `json:"start_time"` + EndTime int64 `json:"end_time"` + LabelFilter string `json:"label_filter"` + } + + request := &testRequest{ + Query: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + StartTime: 1000, + EndTime: 2000, + LabelFilter: `{service="test"}`, + } + + diag := &queryv1.Diagnostics{ + QueryPlan: &queryv1.QueryPlan{ + Root: &queryv1.QueryNode{ + Type: queryv1.QueryNode_READ, + }, + }, + ExecutionNode: &queryv1.ExecutionNode{ + Type: queryv1.QueryNode_READ, + Executor: "test-host", + }, + } + + id := "abcdef0123456789abcdef0123456789" + + store.AddRequest(id, "SelectMergeStacktraces", request) + store.Add(id, diag) + err := store.Flush(ctx, "tenant-1", id) + require.NoError(t, err) + + stored, err := store.Get(ctx, "tenant-1", id) + require.NoError(t, err) + assert.Equal(t, id, stored.ID) + assert.Equal(t, "SelectMergeStacktraces", stored.Method) + assert.NotNil(t, stored.Request) + + var storedRequest testRequest + require.NoError(t, json.Unmarshal(stored.Request, &storedRequest)) + assert.Equal(t, int64(1000), storedRequest.StartTime) + assert.NotNil(t, stored.Plan) + assert.NotNil(t, stored.Execution) +} diff --git a/pkg/frontend/readpath/queryfrontend/query_diff.go b/pkg/frontend/readpath/queryfrontend/query_diff.go new file mode 100644 index 0000000000..cba76566e9 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_diff.go @@ -0,0 +1,74 @@ +package queryfrontend + +import ( + "context" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + "golang.org/x/sync/errgroup" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) Diff( + ctx context.Context, + c *connect.Request[querierv1.DiffRequest], +) (*connect.Response[querierv1.DiffResponse], error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + if c.Msg.Left == nil { + c.Msg.Left = &querierv1.SelectMergeStacktracesRequest{} + } + + if c.Msg.Right == nil { + c.Msg.Right = &querierv1.SelectMergeStacktracesRequest{} + } + + maxNodes := c.Msg.Left.GetMaxNodes() + if n := c.Msg.Right.GetMaxNodes(); n > maxNodes { + maxNodes = n + } + maxNodes, err = validation.ValidateMaxNodes(q.limits, tenantIDs, maxNodes) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + c.Msg.Left.MaxNodes = &maxNodes + c.Msg.Right.MaxNodes = &maxNodes + + _, err = phlaremodel.ParseProfileTypeSelector(c.Msg.Left.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + _, err = phlaremodel.ParseProfileTypeSelector(c.Msg.Right.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + var left, right []byte + g, ctx := errgroup.WithContext(ctx) + g.Go(func() error { + var leftErr error + left, leftErr = q.selectMergeStacktracesTree(ctx, connect.NewRequest(c.Msg.Left)) + return leftErr + }) + g.Go(func() error { + var rightErr error + right, rightErr = q.selectMergeStacktracesTree(ctx, connect.NewRequest(c.Msg.Right)) + return rightErr + }) + if err = g.Wait(); err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + diff, err := phlaremodel.NewFlamegraphDiffFromBytes(left, right, maxNodes) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + return connect.NewResponse(&querierv1.DiffResponse{Flamegraph: diff}), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_diff_test.go b/pkg/frontend/readpath/queryfrontend/query_diff_test.go new file mode 100644 index 0000000000..06f62eaf61 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_diff_test.go @@ -0,0 +1,86 @@ +package queryfrontend + +import ( + "context" + "strings" + "sync" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockqueryfrontend" +) + +func TestDiff_ForwardsSpanSelectors(t *testing.T) { + leftSpan := []string{"0000000000000001"} + rightSpan := []string{"0000000000000002"} + tree := new(phlaremodel.FunctionNameTree) + tree.InsertStack(1, "foo") + treeBytes := tree.Bytes(-1, nil) + + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesDefault", smpTenant).Return(0) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + observed := make(map[string][]string) + var observedMu sync.Mutex + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + req := args.Get(1).(*queryv1.InvokeRequest) + side := "right" + if strings.Contains(req.LabelSelector, `side="left"`) { + side = "left" + } + observedMu.Lock() + observed[side] = req.Query[0].Tree.GetSpanSelector() + observedMu.Unlock() + }). + Return(func(context.Context, *queryv1.InvokeRequest) *queryv1.InvokeResponse { + return &queryv1.InvokeResponse{Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{Tree: treeBytes}, + }}} + }, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := tenant.InjectTenantID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + resp, err := qf.Diff(ctx, connect.NewRequest(&querierv1.DiffRequest{ + Left: &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: `{side="left"}`, + Start: start, + End: end, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + SpanSelector: leftSpan, + }, + Right: &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: `{side="right"}`, + Start: start, + End: end, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_DOT, + SpanSelector: rightSpan, + }, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg.Flamegraph) + require.Equal(t, leftSpan, observed["left"]) + require.Equal(t, rightSpan, observed["right"]) +} diff --git a/pkg/frontend/readpath/queryfrontend/query_frontend.go b/pkg/frontend/readpath/queryfrontend/query_frontend.go new file mode 100644 index 0000000000..12e1178ca7 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_frontend.go @@ -0,0 +1,351 @@ +package queryfrontend + +import ( + "context" + "fmt" + "math/rand" + "slices" + "strings" + "sync" + "time" + + "github.com/dustin/go-humanize" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + "github.com/grafana/dskit/tracing" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/model/labels" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/frontend" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend/diagnostics" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/querybackend/queryplan" + "github.com/grafana/pyroscope/v2/pkg/util/spanlogger" +) + +var _ querierv1connect.QuerierServiceClient = (*QueryFrontend)(nil) + +type QueryBackend interface { + Invoke(ctx context.Context, req *queryv1.InvokeRequest) (*queryv1.InvokeResponse, error) +} + +type Symbolizer interface { + SymbolizePprof(ctx context.Context, profile *googlev1.Profile) error +} + +// DiagnosticsStore provides the ability to store query diagnostics. +type DiagnosticsStore interface { + // Add stores diagnostics in memory for later flushing. + Add(id string, diag *queryv1.Diagnostics) +} + +type QueryFrontend struct { + logger log.Logger + limits frontend.Limits + + metadataQueryClient metastorev1.MetadataQueryServiceClient + tenantServiceClient metastorev1.TenantServiceClient + querybackend QueryBackend + symbolizer Symbolizer + diagnosticsStore DiagnosticsStore + now func() time.Time + + metrics *queryFrontendMetrics +} + +type queryFrontendMetrics struct { + fetchedBytesTotal *prometheus.CounterVec + estimationAccuracyRatio prometheus.Histogram +} + +func newQueryFrontendMetrics(reg prometheus.Registerer) *queryFrontendMetrics { + m := &queryFrontendMetrics{ + fetchedBytesTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Subsystem: "query_frontend", + Name: "fetched_bytes_total", + Help: "Total bytes fetched per tenant per source (object_storage, metastore).", + }, + []string{"tenant", "kind"}, + ), + // estimationAccuracyRatio records the ratio of the pre-execution + // metadata size estimate (weight.Total()) to the actual object-storage + // bytes fetched per query. A value of 1.0 means the estimate matched + // exactly; values below 1.0 mean the query fetched less than estimated + // (the common case, since the weight is an upper-bound derived from + // section offsets). Format1 index-lookup blocks have unknown + // profile/symbol sizes pre-execution, so queries that hit those blocks + // will tend to produce ratios below 1.0. + // Both classic explicit buckets and native-histogram parameters are set + // so that scrapers that support native histograms get higher resolution + // automatically. + estimationAccuracyRatio: prometheus.NewHistogram(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "query_frontend", + Name: "estimation_accuracy_ratio", + Help: "Ratio of the pre-execution metadata size estimate to actual object-storage bytes fetched per query (estimate / actual). 1.0 = perfect estimate; <1.0 = over-estimated; >1.0 = under-estimated.", + Buckets: []float64{0.1, 0.25, 0.5, 0.75, 0.9, 1.0, 1.1, 1.25, 1.5, 2, 5, 10}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: time.Hour, + }), + } + if reg != nil { + reg.MustRegister(m.fetchedBytesTotal, m.estimationAccuracyRatio) + } + return m +} + +func NewQueryFrontend( + logger log.Logger, + limits frontend.Limits, + metadataQueryClient metastorev1.MetadataQueryServiceClient, + tenantServiceClient metastorev1.TenantServiceClient, + querybackendClient QueryBackend, + sym Symbolizer, + diagnosticsStore DiagnosticsStore, + reg prometheus.Registerer, +) *QueryFrontend { + qf := &QueryFrontend{ + logger: logger, + limits: limits, + metadataQueryClient: metadataQueryClient, + tenantServiceClient: tenantServiceClient, + querybackend: querybackendClient, + symbolizer: sym, + diagnosticsStore: diagnosticsStore, + now: time.Now, + metrics: newQueryFrontendMetrics(reg), + } + return qf +} + +var xrand = rand.New(rand.NewSource(4349676827832284783)) +var xrandMutex = sync.Mutex{} // todo fix the race properly + +// backendCreator allows to modify behavior of a query after more about the dataset is learned from the QueryMetadata call. +// We currently use this mainly to change backend query, for symbolizing unsymbolized blocks. +// TODO: Once symbolization moves to the query-backend, the query-backend plan should incorporate the symbolize step +type backendWrapper = func(ctx context.Context, upstream QueryBackend, blocks []*metastorev1.BlockMeta) QueryBackend + +func (q *QueryFrontend) Query( + ctx context.Context, + req *queryv1.QueryRequest, +) (*queryv1.QueryResponse, error) { + return q.doQuery(ctx, req, nil) +} + +func (q *QueryFrontend) doQuery( + ctx context.Context, + req *queryv1.QueryRequest, + backendC backendWrapper, +) (*queryv1.QueryResponse, error) { + span, ctx := tracing.StartSpanFromContext(ctx, "QueryFrontend.doQuery") + defer span.Finish() + span.SetTag("start_time", req.StartTime) + span.SetTag("end_time", req.EndTime) + span.SetTag("label_selector", req.LabelSelector) + diagCtx := diagnostics.From(ctx) + collectDiagnostics := diagCtx != nil && diagCtx.Collect && q.diagnosticsStore != nil + if collectDiagnostics { + span.SetTag("diagnostics_id", diagCtx.ID) + } + + // This method is supposed to be the entry point of the read path + // in the future versions. Therefore, validation, overrides, and + // rest of the request handling should be moved here. + tenants, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + span.SetTag("tenant_ids", tenants) + + blocks, err := q.QueryMetadata(ctx, req) + if err != nil { + return nil, err + } + span.SetTag("block_count", len(blocks)) + if len(blocks) == 0 { + return new(queryv1.QueryResponse), nil + } + + // Measure bytes received from the metastore (serialized block metadata). + var metastoreBytes uint64 + for _, b := range blocks { + metastoreBytes += uint64(b.SizeVT()) + } + + var weight block.DatasetWeight + var datasetsCount int + blocksByLevel := make(map[uint32]int) + for _, b := range blocks { + datasetsCount += len(b.Datasets) + blocksByLevel[b.CompactionLevel]++ + for _, ds := range b.Datasets { + weight.Add(block.WeightOf(ds)) + } + } + span.SetTag("total_block_bytes", weight.Total()) + span.SetTag("profiles_bytes", weight.ProfilesBytes) + span.SetTag("tsdb_bytes", weight.TSDBBytes) + span.SetTag("symbols_bytes", weight.SymbolsBytes) + span.SetTag("datasets_count", datasetsCount) + span.SetTag("index_lookup_blocks", weight.IndexLookupCount) + startTime := time.UnixMilli(req.StartTime) + endTime := time.UnixMilli(req.EndTime) + queryWindow := endTime.Sub(startTime).Round(time.Second) + traceID, _ := tracing.ExtractTraceID(ctx) + logArgs := []interface{}{ + "msg", "query weight", + "trace_id", traceID, + "tenant", strings.Join(tenants, ","), + "blocks", len(blocks), + "total_block_bytes", humanize.Bytes(weight.Total()), + "profiles_bytes", humanize.Bytes(weight.ProfilesBytes), + "tsdb_bytes", humanize.Bytes(weight.TSDBBytes), + "symbols_bytes", humanize.Bytes(weight.SymbolsBytes), + "datasets", datasetsCount, + "index_lookup_blocks", weight.IndexLookupCount, + "start_time", startTime.UTC().Format(time.RFC3339), + "end_time", endTime.UTC().Format(time.RFC3339), + "query_window", queryWindow, + "label_selector", req.LabelSelector, + } + for lvl, count := range blocksByLevel { + logArgs = append(logArgs, fmt.Sprintf("blocks_level_%d", lvl), count) + } + level.Info(q.logger).Log(logArgs...) + + // Randomize the order of blocks to avoid hotspots. + xrandMutex.Lock() + xrand.Shuffle(len(blocks), func(i, j int) { + blocks[i], blocks[j] = blocks[j], blocks[i] + }) + xrandMutex.Unlock() + // TODO(kolesnikovae): Should be dynamic. + p := queryplan.Build(blocks, 4, 20) + + backend := q.querybackend + if backendC != nil { + backend = backendC(ctx, backend, blocks) + } + resp, err := backend.Invoke(ctx, &queryv1.InvokeRequest{ + Tenant: tenants, + StartTime: req.StartTime, + EndTime: req.EndTime, + LabelSelector: req.LabelSelector, + Options: &queryv1.InvokeOptions{ + SanitizeOnMerge: q.limits.QuerySanitizeOnMerge(tenants[0]), + CollectDiagnostics: collectDiagnostics, + }, + QueryPlan: p, + Query: req.Query, + }) + if err != nil { + return nil, err + } + + // Emit per-tenant bytes metrics. Object storage bytes come from the + // query-backend response; metastore bytes were measured above. + // Use dskit's JoinTenantIDs so the label matches the standard |-separated + // org ID format used elsewhere in the Grafana stack. + tenantLabel := tenant.JoinTenantIDs(tenants) + objectBytes := resp.GetDiagnostics().GetExecutionNode().GetStats().GetBytesFetched() + q.metrics.fetchedBytesTotal.WithLabelValues(tenantLabel, "object_storage").Add(float64(objectBytes)) + q.metrics.fetchedBytesTotal.WithLabelValues(tenantLabel, "metastore").Add(float64(metastoreBytes)) + // Record estimation accuracy: ratio of pre-execution weight to actual bytes + // fetched. Only observed when the backend fetched bytes to avoid division + // by zero (e.g. empty result sets). + if objectBytes > 0 { + q.metrics.estimationAccuracyRatio.Observe(float64(weight.Total()) / float64(objectBytes)) + } + if qs := spanlogger.QueryStatsFromContext(ctx); qs != nil { + qs.ObjectStorageBytes += objectBytes + qs.MetastoreBytes += metastoreBytes + qs.EstimatedBytes += weight.Total() + } + + if resp.Diagnostics == nil { + resp.Diagnostics = new(queryv1.Diagnostics) + } + + resp.Diagnostics.QueryPlan = p + + if collectDiagnostics { + q.diagnosticsStore.Add(diagCtx.ID, resp.Diagnostics) + } + + return &queryv1.QueryResponse{Reports: resp.Reports}, nil +} + +func (q *QueryFrontend) QueryMetadata( + ctx context.Context, + req *queryv1.QueryRequest, +) (blocks []*metastorev1.BlockMeta, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "QueryFrontend.QueryMetadata") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + span.SetTag("start_time", req.StartTime) + span.SetTag("end_time", req.EndTime) + span.SetTag("label_selector", req.LabelSelector) + + tenants, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + span.SetTag("tenant_ids", tenants) + + matchers, err := model.ParseMetricSelector(req.LabelSelector) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + query := &metastorev1.QueryMetadataRequest{ + TenantId: tenants, + StartTime: req.StartTime, + EndTime: req.EndTime, + Labels: []string{metadata.LabelNameUnsymbolized}, + } + + // Delete all matchers but service_name with strict match. If no matchers + // left, request the dataset index for query backend to lookup block datasets + // locally. + matchers = slices.DeleteFunc(matchers, func(m *labels.Matcher) bool { + return m.Name != model.LabelNameServiceName || m.Type != labels.MatchEqual + }) + if len(matchers) == 0 { + // We preserve the __tenant_dataset__= label: this is needed for the + // query backend to identify that the dataset is the tenant-wide index, + // and a dataset lookup is needed. + query.Labels = append(query.Labels, metadata.LabelNameTenantDataset) + matchers = []*labels.Matcher{{ + Name: metadata.LabelNameTenantDataset, + Value: metadata.LabelValueDatasetTSDBIndex, + Type: labels.MatchEqual, + }} + } + + query.Query = matchersToLabelSelector(matchers) + md, err := q.metadataQueryClient.QueryMetadata(ctx, query) + if err != nil { + return nil, err + } + span.SetTag("blocks_count", len(md.Blocks)) + + return md.Blocks, nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_frontend_test.go b/pkg/frontend/readpath/queryfrontend/query_frontend_test.go new file mode 100644 index 0000000000..66f0a1ee71 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_frontend_test.go @@ -0,0 +1,362 @@ +package queryfrontend + +import ( + "context" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/grafana/dskit/user" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/featureflags" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockqueryfrontend" +) + +const ( + smpProfileType = "memory:inuse_space:bytes:space:byte" +) + +func smpValidTimeRange() (int64, int64) { + now := time.Now().UnixMilli() + return now, now + time.Minute.Milliseconds() +} + +func Test_QueryFrontend_QueryMetadata(t *testing.T) { + for _, test := range []struct { + query *queryv1.QueryRequest + request *metastorev1.QueryMetadataRequest + response *metastorev1.QueryMetadataResponse + }{ + { + query: &queryv1.QueryRequest{LabelSelector: `{service_name="service-a"}`}, + request: &metastorev1.QueryMetadataRequest{ + TenantId: []string{"org"}, + Query: `{service_name="service-a"}`, + Labels: []string{metadata.LabelNameUnsymbolized}, + }, + response: &metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "block_id_a"}}, + }, + }, + { + query: &queryv1.QueryRequest{LabelSelector: `{service_name!="service-a"}`}, + request: &metastorev1.QueryMetadataRequest{ + TenantId: []string{"org"}, + Query: `{__tenant_dataset__="dataset_tsdb_index"}`, + Labels: []string{metadata.LabelNameUnsymbolized, "__tenant_dataset__"}, + }, + response: &metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "block_id_a"}}, + }, + }, + { + query: &queryv1.QueryRequest{LabelSelector: `{service_name=~".*"}`}, + request: &metastorev1.QueryMetadataRequest{ + TenantId: []string{"org"}, + Query: `{__tenant_dataset__="dataset_tsdb_index"}`, + Labels: []string{metadata.LabelNameUnsymbolized, "__tenant_dataset__"}, + }, + response: &metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "block_id_c"}}, + }, + }, + { + query: &queryv1.QueryRequest{LabelSelector: `{foo="bar"}`}, + request: &metastorev1.QueryMetadataRequest{ + TenantId: []string{"org"}, + Query: `{__tenant_dataset__="dataset_tsdb_index"}`, + Labels: []string{metadata.LabelNameUnsymbolized, "__tenant_dataset__"}, + }, + response: &metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "block_id_b"}}, + }, + }, + { + query: &queryv1.QueryRequest{LabelSelector: "{}"}, + request: &metastorev1.QueryMetadataRequest{ + TenantId: []string{"org"}, + Query: `{__tenant_dataset__="dataset_tsdb_index"}`, + Labels: []string{metadata.LabelNameUnsymbolized, "__tenant_dataset__"}, + }, + response: &metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "block_id_d"}}, + }, + }, + } { + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + ctx := user.InjectOrgID(context.Background(), "org") + f := &QueryFrontend{metadataQueryClient: mockMetadataClient} + + mockMetadataClient.On("QueryMetadata", mock.Anything, test.request). + Return(test.response, nil). + Once() + + blocks, err := f.QueryMetadata(ctx, test.query) + assert.NoError(t, err) + assert.Equal(t, test.response.Blocks, blocks) + } +} + +func Test_QueryFrontend_LabelNames_WithFiltering(t *testing.T) { + tests := []struct { + name string + allowUtf8LabelNames bool + setCapabilities bool + backendLabelNames []string + expectedLabelNames []string + }{ + { + name: "UTF8 labels allowed when enabled", + allowUtf8LabelNames: true, + setCapabilities: true, + backendLabelNames: []string{"foo", "bar", "世界"}, + expectedLabelNames: []string{"foo", "bar", "世界"}, + }, + { + name: "UTF8 labels filtered when disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + backendLabelNames: []string{"foo", "bar", "世界"}, + expectedLabelNames: []string{"foo", "bar"}, + }, + { + name: "invalid labels pass through when UTF8 enabled", + allowUtf8LabelNames: true, + setCapabilities: true, + backendLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + expectedLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + }, + { + name: "invalid labels filtered when UTF8 disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + backendLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + expectedLabelNames: []string{"valid_name"}, + }, + { + name: "filtering enabled when no capabilities set", + setCapabilities: false, + backendLabelNames: []string{"valid_name", "123invalid", "世界"}, + expectedLabelNames: []string{"valid_name"}, + }, + { + name: "labels with dots do not pass through", + allowUtf8LabelNames: false, + setCapabilities: true, + backendLabelNames: []string{"service.name", "app.version"}, + expectedLabelNames: []string{}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + mockQueryBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockQueryBackend.On("Invoke", mock.Anything, mock.Anything).Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{ + { + ReportType: queryv1.ReportType_REPORT_LABEL_NAMES, + LabelNames: &queryv1.LabelNamesReport{ + LabelNames: tc.backendLabelNames, + }, + }, + }, + }, nil) + + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", "test-tenant").Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", "test-tenant").Return(time.Duration(0)) + mockLimits.On("QuerySanitizeOnMerge", "test-tenant").Return(true) + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadataClient.On("QueryMetadata", mock.Anything, mock.Anything).Return(&metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "test-block"}}, + }, nil) + + qf := NewQueryFrontend( + log.NewNopLogger(), + mockLimits, + mockMetadataClient, + nil, + mockQueryBackend, + nil, + nil, + nil, + ) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + if tc.setCapabilities { + ctx = featureflags.WithClientCapabilities(ctx, featureflags.ClientCapabilities{ + AllowUtf8LabelNames: tc.allowUtf8LabelNames, + }) + } + + req := connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: 1000, + End: 2000, + }) + + resp, err := qf.LabelNames(ctx, req) + require.NoError(t, err) + require.Equal(t, tc.expectedLabelNames, resp.Msg.Names) + }) + } +} + +func Test_QueryFrontend_Series_WithLabelNameFiltering(t *testing.T) { + tests := []struct { + name string + allowUtf8LabelNames bool + setCapabilities bool + requestLabelNames []string + backendLabelNames []string // For empty request case + expectedQueryRequest []string // What should be passed to backend + }{ + { + name: "all label names pass through when UTF8 enabled", + allowUtf8LabelNames: true, + setCapabilities: true, + requestLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + expectedQueryRequest: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + }, + { + name: "invalid label names filtered when UTF8 disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + expectedQueryRequest: []string{"valid_name"}, + }, + { + name: "UTF8 labels filtered when UTF8 disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"foo", "bar", "世界", "日本語"}, + expectedQueryRequest: []string{"foo", "bar"}, + }, + { + name: "filtering enabled when no capabilities set", + setCapabilities: false, + requestLabelNames: []string{"foo", "123invalid", "世界"}, + expectedQueryRequest: []string{"foo"}, + }, + { + name: "all valid labels pass through", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"foo", "bar", "service_name"}, + expectedQueryRequest: []string{"foo", "bar", "service_name"}, + }, + { + name: "labels with dots do not pass through", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"service.name", "app.version"}, + expectedQueryRequest: []string{}, + }, + { + name: "empty label names with UTF8 disabled queries and filters all labels", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{}, + backendLabelNames: []string{"foo", "bar", "世界"}, + expectedQueryRequest: []string{"foo", "bar"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var capturedLabelNames []string + + mockQueryBackend := mockqueryfrontend.NewMockQueryBackend(t) + + // For empty label names case, we need to mock the LabelNames query first + if len(tc.requestLabelNames) == 0 { + mockQueryBackend.On("Invoke", mock.Anything, mock.MatchedBy(func(req *queryv1.InvokeRequest) bool { + return len(req.Query) > 0 && req.Query[0].QueryType == queryv1.QueryType_QUERY_LABEL_NAMES + })).Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{ + { + ReportType: queryv1.ReportType_REPORT_LABEL_NAMES, + LabelNames: &queryv1.LabelNamesReport{ + LabelNames: tc.backendLabelNames, + }, + }, + }, + }, nil).Once() + } + + // Mock the Series query specifically + mockQueryBackend.On("Invoke", mock.Anything, mock.MatchedBy(func(req *queryv1.InvokeRequest) bool { + return len(req.Query) > 0 && req.Query[0].QueryType == queryv1.QueryType_QUERY_SERIES_LABELS + })).Run(func(args mock.Arguments) { + invReq := args.Get(1).(*queryv1.InvokeRequest) + if len(invReq.Query) > 0 && invReq.Query[0].SeriesLabels != nil { + capturedLabelNames = invReq.Query[0].SeriesLabels.LabelNames + if capturedLabelNames == nil { + capturedLabelNames = []string{} + } + } + }).Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{ + { + ReportType: queryv1.ReportType_REPORT_SERIES_LABELS, + SeriesLabels: &queryv1.SeriesLabelsReport{ + SeriesLabels: []*typesv1.Labels{}, + }, + }, + }, + }, nil).Once() + + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", "test-tenant").Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", "test-tenant").Return(time.Duration(0)) + mockLimits.On("QuerySanitizeOnMerge", "test-tenant").Return(true) + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadataClient.On("QueryMetadata", mock.Anything, mock.Anything).Return(&metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "test-block"}}, + }, nil) + + qf := NewQueryFrontend( + log.NewNopLogger(), + mockLimits, + mockMetadataClient, + nil, + mockQueryBackend, + nil, + nil, + nil, + ) + + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + if tc.setCapabilities { + ctx = featureflags.WithClientCapabilities(ctx, featureflags.ClientCapabilities{ + AllowUtf8LabelNames: tc.allowUtf8LabelNames, + }) + } + + req := connect.NewRequest(&querierv1.SeriesRequest{ + Matchers: []string{`{service_name="test"}`}, + LabelNames: tc.requestLabelNames, + Start: 1000, + End: 2000, + }) + + _, err := qf.Series(ctx, req) + require.NoError(t, err) + + // Verify that the label names were filtered correctly before being sent to backend + require.Equal(t, tc.expectedQueryRequest, capturedLabelNames, + "Expected label names sent to backend to be %v, but got %v", tc.expectedQueryRequest, capturedLabelNames) + }) + } +} diff --git a/pkg/frontend/readpath/queryfrontend/query_get_profile_stats.go b/pkg/frontend/readpath/queryfrontend/query_get_profile_stats.go new file mode 100644 index 0000000000..2f71cef932 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_get_profile_stats.go @@ -0,0 +1,39 @@ +package queryfrontend + +import ( + "context" + "fmt" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +func (q *QueryFrontend) GetProfileStats( + ctx context.Context, + _ *connect.Request[typesv1.GetProfileStatsRequest], +) (*connect.Response[typesv1.GetProfileStatsResponse], error) { + tenants, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + if len(tenants) != 1 { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("expected 1 tenant, got %d", len(tenants))) + } + + resp, err := q.tenantServiceClient.GetTenant(ctx, &metastorev1.GetTenantRequest{ + TenantId: tenants[0], + }) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + stats := resp.GetStats() + return connect.NewResponse(&typesv1.GetProfileStatsResponse{ + DataIngested: stats.DataIngested, + OldestProfileTime: stats.OldestProfileTime, + NewestProfileTime: stats.NewestProfileTime, + }), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_heatmap.go b/pkg/frontend/readpath/queryfrontend/query_heatmap.go new file mode 100644 index 0000000000..09af3ec96b --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_heatmap.go @@ -0,0 +1,107 @@ +package queryfrontend + +import ( + "context" + "fmt" + "time" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/heatmap" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +const ( + // stepAdjustment is subtracted from the start time to ensure we capture + // data points that fall before the first time bucket boundary + stepAdjustment = 1 +) + +func (q *QueryFrontend) SelectHeatmap( + ctx context.Context, + c *connect.Request[querierv1.SelectHeatmapRequest], +) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + // Sub-millisecond step values truncate to 0 in the backend's millisecond + // arithmetic and would cause divide-by-zero / unbounded loop downstream; + // reject anything below 1ms. + if c.Msg.Step < 0.001 { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("step must be >= 1ms, got %f", c.Msg.Step)) + } + + // Validate limit if provided + if c.Msg.Limit != nil && *c.Msg.Limit < 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("limit must be non-negative, got %d", *c.Msg.Limit)) + } + + // Validate time range + if c.Msg.Start >= c.Msg.End { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("start time must be before end time, got start=%d end=%d", c.Msg.Start, c.Msg.End)) + } + + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &c.Msg.Start, &c.Msg.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return connect.NewResponse(&querierv1.SelectHeatmapResponse{}), nil + } + + _, err = phlaremodel.ParseProfileTypeSelector(c.Msg.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + stepMs := time.Duration(c.Msg.Step * float64(time.Second)).Milliseconds() + start := c.Msg.Start - (stepMs * stepAdjustment) + + labelSelector, err := buildLabelSelectorWithProfileType(c.Msg.LabelSelector, c.Msg.ProfileTypeID) + if err != nil { + return nil, err + } + report, err := q.querySingle(ctx, &queryv1.QueryRequest{ + StartTime: start, + EndTime: c.Msg.End, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_HEATMAP, + Heatmap: &queryv1.HeatmapQuery{ + Step: c.Msg.GetStep(), + GroupBy: c.Msg.GetGroupBy(), + QueryType: c.Msg.QueryType, + ExemplarType: c.Msg.GetExemplarType(), + Limit: c.Msg.GetLimit(), + }, + }}, + }, nil) + if err != nil { + return nil, err + } + if report == nil || report.Heatmap == nil { + return connect.NewResponse(&querierv1.SelectHeatmapResponse{}), nil + } + // Convert HeatmapReport to HeatmapSeries using RangeHeatmap + series := heatmap.RangeHeatmap( + []*queryv1.HeatmapReport{report.Heatmap}, + c.Msg.Start, // This uses the query parameter instead of the shifted "start". So the first time slot of the heatmap ends at start + c.Msg.End, + stepMs, + c.Msg.GetExemplarType(), + ) + + // Apply limit if specified + if c.Msg.GetLimit() > 0 { + series = heatmap.TopSeries(series, int(c.Msg.GetLimit())) + } + + return connect.NewResponse(&querierv1.SelectHeatmapResponse{ + Series: series, + }), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_label_names.go b/pkg/frontend/readpath/queryfrontend/query_label_names.go new file mode 100644 index 0000000000..3dcff6886f --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_label_names.go @@ -0,0 +1,68 @@ +package queryfrontend + +import ( + "context" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + "github.com/prometheus/common/model" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/featureflags" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) LabelNames( + ctx context.Context, + c *connect.Request[typesv1.LabelNamesRequest], +) (*connect.Response[typesv1.LabelNamesResponse], error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &c.Msg.Start, &c.Msg.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return connect.NewResponse(&typesv1.LabelNamesResponse{}), nil + } + + labelSelector, err := buildLabelSelectorFromMatchers(c.Msg.Matchers) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + report, err := q.querySingle(ctx, &queryv1.QueryRequest{ + StartTime: c.Msg.Start, + EndTime: c.Msg.End, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_LABEL_NAMES, + LabelNames: &queryv1.LabelNamesQuery{}, + }}, + }, nil) + if err != nil { + return nil, err + } + if report == nil { + return connect.NewResponse(&typesv1.LabelNamesResponse{}), nil + } + + labelNames := report.LabelNames.LabelNames + if capabilities, ok := featureflags.GetClientCapabilities(ctx); !ok || !capabilities.AllowUtf8LabelNames { + // Filter out label names not passing legacy validation if utf8 label names not enabled + filteredLabelNames := make([]string, 0, len(labelNames)) + for _, labelName := range labelNames { + if !model.LegacyValidation.IsValidLabelName(labelName) { + level.Debug(q.logger).Log("msg", "filtering out label", "label_name", labelName) + continue + } + filteredLabelNames = append(filteredLabelNames, labelName) + } + labelNames = filteredLabelNames + } + + return connect.NewResponse(&typesv1.LabelNamesResponse{Names: labelNames}), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_label_values.go b/pkg/frontend/readpath/queryfrontend/query_label_values.go new file mode 100644 index 0000000000..3efdab674e --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_label_values.go @@ -0,0 +1,55 @@ +package queryfrontend + +import ( + "context" + "errors" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) LabelValues( + ctx context.Context, + c *connect.Request[typesv1.LabelValuesRequest], +) (*connect.Response[typesv1.LabelValuesResponse], error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &c.Msg.Start, &c.Msg.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return connect.NewResponse(&typesv1.LabelValuesResponse{}), nil + } + + if c.Msg.Name == "" { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("name is required")) + } + + labelSelector, err := buildLabelSelectorFromMatchers(c.Msg.Matchers) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + report, err := q.querySingle(ctx, &queryv1.QueryRequest{ + StartTime: c.Msg.Start, + EndTime: c.Msg.End, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_LABEL_VALUES, + LabelValues: &queryv1.LabelValuesQuery{LabelName: c.Msg.Name}, + }}, + }, nil) + if err != nil { + return nil, err + } + if report == nil { + return connect.NewResponse(&typesv1.LabelValuesResponse{}), nil + } + return connect.NewResponse(&typesv1.LabelValuesResponse{Names: report.LabelValues.LabelValues}), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_profile_types.go b/pkg/frontend/readpath/queryfrontend/query_profile_types.go new file mode 100644 index 0000000000..0316a6d482 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_profile_types.go @@ -0,0 +1,75 @@ +package queryfrontend + +import ( + "context" + "slices" + "strings" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) ProfileTypes( + ctx context.Context, + req *connect.Request[querierv1.ProfileTypesRequest], +) (*connect.Response[querierv1.ProfileTypesResponse], error) { + tenants, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + // Note: Some ProfileTypes API clients rely on the ability to call it without start/end. + // See https://github.com/grafana/grafana/issues/110211 + // TODO: Consider removing this (breaking change) as part of the next major release. + if req.Msg.Start == 0 && req.Msg.End == 0 { + interval := phlaremodel.GetSafeTimeRange(q.now(), nil) + req.Msg.Start = int64(interval.Start) + req.Msg.End = int64(interval.End) + } + + empty, err := validation.SanitizeTimeRange(q.limits, tenants, &req.Msg.Start, &req.Msg.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return connect.NewResponse(&querierv1.ProfileTypesResponse{}), nil + } + + resp, err := q.metadataQueryClient.QueryMetadataLabels(ctx, &metastorev1.QueryMetadataLabelsRequest{ + TenantId: tenants, + StartTime: req.Msg.Start, + EndTime: req.Msg.End, + Query: "{}", + Labels: []string{phlaremodel.LabelNameProfileType}, + }) + + if err != nil { + return nil, err + } + + types := make([]*typesv1.ProfileType, 0, len(resp.Labels)) + for _, ls := range resp.Labels { + var typ *typesv1.ProfileType + if len(ls.Labels) == 1 && ls.Labels[0].Name == phlaremodel.LabelNameProfileType { + typ, err = phlaremodel.ParseProfileTypeSelector(ls.Labels[0].Value) + } + if err != nil || typ == nil { + level.Warn(q.logger).Log("msg", "malformed label set", "labels", phlaremodel.LabelPairsString(ls.Labels)) + continue + } + types = append(types, typ) + } + + slices.SortFunc(types, func(a, b *typesv1.ProfileType) int { + return strings.Compare(a.ID, b.ID) + }) + + return connect.NewResponse(&querierv1.ProfileTypesResponse{ProfileTypes: types}), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_profile_types_test.go b/pkg/frontend/readpath/queryfrontend/query_profile_types_test.go new file mode 100644 index 0000000000..4d820b96ba --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_profile_types_test.go @@ -0,0 +1,144 @@ +package queryfrontend + +import ( + "context" + "errors" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" +) + +func TestQueryFrontend_ProfileTypes(t *testing.T) { + now := time.Now() + const tenantID = "tenant1" + tests := []struct { + name string + request *querierv1.ProfileTypesRequest + expectedStart int64 + expectedEnd int64 + expectedProfileTypes []string + expectedError error + }{ + { + name: "success with start and end", + request: &querierv1.ProfileTypesRequest{ + Start: now.Add(-time.Hour * 2).UnixMilli(), + End: now.UnixMilli(), + }, + expectedProfileTypes: []string{ + "a:b:c:d:e:f", + "g:h:i:j:k:l", + }, + }, + { + name: "success without start and end", + expectedStart: now.Add(-time.Hour * 1).UnixMilli(), + expectedEnd: now.UnixMilli(), + request: &querierv1.ProfileTypesRequest{}, + expectedProfileTypes: []string{ + "a:b:c:d:e:f", + "g:h:i:j:k:l", + }, + }, + { + name: "failure without start time", + request: &querierv1.ProfileTypesRequest{ + Start: 0, + End: now.UnixMilli(), + }, + expectedError: errors.New("invalid_argument: missing time range in the query"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockLimits := mockfrontend.NewMockLimits(t) + // setup limits + mockLimits.On("MaxQueryLookback", tenantID).Return(time.Hour * 24 * 7).Maybe() + mockLimits.On("MaxQueryLength", tenantID).Return(time.Hour * 24 * 7).Maybe() + defer mockLimits.AssertExpectations(t) + + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + + // validate underlying calls using mock implmentation + var result = &metastorev1.QueryMetadataLabelsResponse{} + var resultErr error + mockMetadataClient.On("QueryMetadataLabels", mock.Anything, mock.Anything).Return(result, resultErr).Run(func(args mock.Arguments) { + req := args.Get(1).(*metastorev1.QueryMetadataLabelsRequest) + + start := tt.expectedStart + if start == 0 { + start = tt.request.Start + } + require.Equal(t, start, req.StartTime) + end := tt.expectedEnd + if end == 0 { + end = tt.request.End + } + require.Equal(t, end, req.EndTime) + + require.Equal(t, []string{tenantID}, req.TenantId) + require.Equal(t, "{}", req.Query) + require.Equal(t, []string{phlaremodel.LabelNameProfileType}, req.Labels) + + result.Labels = []*typesv1.Labels{ + { + Labels: []*typesv1.LabelPair{{ + Name: phlaremodel.LabelNameProfileType, + Value: "a:b:c:d:e:f", + }}, + }, + { + Labels: []*typesv1.LabelPair{{ + Name: phlaremodel.LabelNameProfileType, + Value: "g:h:i:j:k:l", + }}, + }, + } + resultErr = nil + }).Maybe() + defer mockMetadataClient.AssertExpectations(t) + + logger := log.NewNopLogger() + qf := &QueryFrontend{ + logger: logger, + metadataQueryClient: mockMetadataClient, + limits: mockLimits, + now: func() time.Time { return now }, + } + + ctx := tenant.InjectTenantID(context.Background(), tenantID) + + // Execute the method + req := connect.NewRequest(tt.request) + resp, err := qf.ProfileTypes(ctx, req) + + // check for expected error + if tt.expectedError != nil { + require.Error(t, err) + require.Equal(t, tt.expectedError.Error(), err.Error()) + return + } + + require.NoError(t, err) + require.NotNil(t, resp) + actualProfileTypes := make([]string, 0, len(resp.Msg.ProfileTypes)) + for _, pt := range resp.Msg.ProfileTypes { + actualProfileTypes = append(actualProfileTypes, pt.ID) + } + require.Equal(t, tt.expectedProfileTypes, actualProfileTypes) + }) + } +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_merge_profile.go b/pkg/frontend/readpath/queryfrontend/query_select_merge_profile.go new file mode 100644 index 0000000000..e088d3911d --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_merge_profile.go @@ -0,0 +1,265 @@ +package queryfrontend + +import ( + "context" + "fmt" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) SelectMergeProfile( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeProfileRequest], +) (*connect.Response[profilev1.Profile], error) { + p, err := q.selectMergeStacktracesPprof(ctx, &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: c.Msg.ProfileTypeID, + LabelSelector: c.Msg.LabelSelector, + Start: c.Msg.Start, + End: c.Msg.End, + MaxNodes: c.Msg.MaxNodes, + StackTraceSelector: c.Msg.StackTraceSelector, + ProfileIdSelector: c.Msg.ProfileIdSelector, + TraceIdSelector: c.Msg.TraceIdSelector, + }) + if err != nil { + return nil, err + } + return connect.NewResponse(p), nil +} + +func (q *QueryFrontend) selectMergeStacktracesPprof( + ctx context.Context, + req *querierv1.SelectMergeStacktracesRequest, +) (*profilev1.Profile, error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &req.Start, &req.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return &profilev1.Profile{}, nil + } + + profileType, err := phlaremodel.ParseProfileTypeSelector(req.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + // NOTE: Max nodes limit is off by default. SelectMergeProfile is primarily + // used for pprof export where truncation would result in incomplete profiles. + // This can be overridden per-tenant to enable enforcement if needed. + maxNodesEnabled := false + for _, tenantID := range tenantIDs { + if q.limits.MaxFlameGraphNodesOnSelectMergeProfile(tenantID) { + maxNodesEnabled = true + } + } + + maxNodes := req.GetMaxNodes() + if maxNodesEnabled { + maxNodes, err = validation.ValidateMaxNodes(q.limits, tenantIDs, req.GetMaxNodes()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + } + + labelSelector, err := buildLabelSelectorWithProfileType(req.LabelSelector, req.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + // TODO: Remove this path and answer all queries using the tree + // PGO queries always use the pprof path, as query tree doesn't support the truncation + useQueryTree := false + if req.StackTraceSelector.GetGoPgo() == nil { + for _, tenantID := range tenantIDs { + if q.limits.QueryTreeEnabled(tenantID) { + useQueryTree = true + break + } + } + } + + if !useQueryTree { + level.Info(q.logger).Log("msg", "use pprof query-backend based query") + shouldSymbolize := false + report, err := q.querySingle(ctx, + &queryv1.QueryRequest{ + StartTime: req.Start, + EndTime: req.End, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{ + MaxNodes: maxNodes, + StackTraceSelector: req.StackTraceSelector, + ProfileIdSelector: req.ProfileIdSelector, + TraceIdSelector: req.TraceIdSelector, + SpanSelector: req.SpanSelector, + }, + }}, + }, + // capture if this pprof needs symbolization + func(ctx context.Context, upstream QueryBackend, blocks []*metastorev1.BlockMeta) QueryBackend { + shouldSymbolize = q.shouldSymbolize(ctx, tenantIDs, blocks) + return upstream + }, + ) + if err != nil { + return nil, err + } + if report == nil { + return &profilev1.Profile{}, nil + } + var p profilev1.Profile + if err = pprof.Unmarshal(report.Pprof.Pprof, &p); err != nil { + return nil, err + } + if shouldSymbolize { + if err := q.symbolizer.SymbolizePprof(ctx, &p); err != nil { + return nil, fmt.Errorf("failed to symbolize profile: %w", err) + } + } + return &p, nil + } + + // From now on answer using the more experimental tree based approach + return q.selectMergeProfileTree(ctx, req, labelSelector, maxNodes, profileType, tenantIDs) +} + +func (q *QueryFrontend) selectMergeProfileTree( + ctx context.Context, + req *querierv1.SelectMergeStacktracesRequest, + labelSelector string, + maxNodes int64, + profileType *typesv1.ProfileType, + tenantIDs []string, +) (*profilev1.Profile, error) { + level.Info(q.logger).Log("msg", "use tree query-backend based query") + shouldSymbolize := false + report, err := q.querySingle(ctx, + &queryv1.QueryRequest{ + StartTime: req.Start, + EndTime: req.End, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{ + MaxNodes: maxNodes, + StackTraceSelector: req.StackTraceSelector, + ProfileIdSelector: req.ProfileIdSelector, + TraceIdSelector: req.TraceIdSelector, + SpanSelector: req.SpanSelector, + SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_FULL, + }, + }}, + }, + // capture if this pprof needs symbolization + func(ctx context.Context, upstream QueryBackend, blocks []*metastorev1.BlockMeta) QueryBackend { + shouldSymbolize = q.shouldSymbolize(ctx, tenantIDs, blocks) + return upstream + }, + ) + if err != nil { + return nil, err + } + if report == nil { + return &profilev1.Profile{}, nil + } + + var p profilev1.Profile + + if report.Tree.Symbols == nil { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("symbols not present in tree response")) + } + if len(report.Tree.Symbols.Mappings) < 1 || len(report.Tree.Symbols.Locations) < 1 || len(report.Tree.Symbols.Functions) < 1 { + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("incomplete symbols in tree response")) + } + + p.StringTable = report.Tree.Symbols.Strings + p.Mapping = report.Tree.Symbols.Mappings[1:] + p.Location = report.Tree.Symbols.Locations[1:] + p.Function = report.Tree.Symbols.Functions[1:] + + otherLocationID := uint64(0) + otherLocation := func() uint64 { + if otherLocationID != 0 { + return otherLocationID + } + stringRef := int64(len(p.StringTable)) + p.StringTable = append(p.StringTable, "other") + funcRef := uint64(len(p.Function) + 1) + p.Function = append(p.Function, &profilev1.Function{ + Id: funcRef, + Name: stringRef, + SystemName: stringRef, + }) + otherLocationID = uint64(len(p.Location) + 1) + p.Location = append(p.Location, &profilev1.Location{ + Id: otherLocationID, + Line: []*profilev1.Line{{ + FunctionId: funcRef, + }}, + }) + return otherLocationID + } + + t, err := phlaremodel.UnmarshalTree[phlaremodel.LocationRefName, phlaremodel.LocationRefNameI](report.Tree.Tree) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + // TODO(simonswine): Back this up with better data + p.Sample = make([]*profilev1.Sample, 0, len(report.Tree.Tree)/16) + + t.IterateStacks(func(_ phlaremodel.LocationRefName, self int64, stack []phlaremodel.LocationRefName) { + if self <= 0 { + return + } + locationIDs := make([]uint64, 0, len(stack)) + for idx, locID := range stack { + // when we hit an other, we need to reset the stack + if locID == phlaremodel.OtherLocationRef { + locationIDs = append(locationIDs, otherLocation()) + continue + } + // handle the sentinel location, when it is the root + if locID == phlaremodel.LocationRefName(0) { + if idx == len(stack)-1 { + break + } + panic("unexpected sentinel location") + } + locationIDs = append(locationIDs, uint64(locID)) + } + + p.Sample = append(p.Sample, &profilev1.Sample{ + LocationId: locationIDs, + Value: []int64{self}, + }) + }) + + pprof.SetProfileMetadata(&p, profileType, req.End*1e6, 0) + + if shouldSymbolize { + if err := q.symbolizer.SymbolizePprof(ctx, &p); err != nil { + return nil, fmt.Errorf("failed to symbolize profile: %w", err) + } + } + + return &p, nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_merge_profile_test.go b/pkg/frontend/readpath/queryfrontend/query_select_merge_profile_test.go new file mode 100644 index 0000000000..7b446e9cf2 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_merge_profile_test.go @@ -0,0 +1,709 @@ +package queryfrontend + +import ( + "context" + "fmt" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/grafana/dskit/user" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockqueryfrontend" +) + +const ( + smpTenant = "test" +) + +func newSMPQueryFrontend( + t *testing.T, + limits *mockfrontend.MockLimits, + metaClient *mockmetastorev1.MockMetadataQueryServiceClient, + backend *mockqueryfrontend.MockQueryBackend, +) *QueryFrontend { + t.Helper() + return NewQueryFrontend( + log.NewNopLogger(), + limits, + metaClient, + nil, // tenantServiceClient + backend, + nil, // symbolizer + nil, // diagnosticsStore + nil, // reg + ) +} + +func smpOneBlock() *metastorev1.QueryMetadataResponse { + return &metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{Id: "block-a"}}, + } +} + +// createProfile returns a serialised pprof profile with a single sample. +func createProfile(t *testing.T) []byte { + t.Helper() + p := &profilev1.Profile{ + Sample: []*profilev1.Sample{{Value: []int64{10}}}, + } + b, err := pprof.Marshal(p, true) + require.NoError(t, err) + return b +} + +func TestSelectMergeProfile_EmptyRangeReturnsEmptyProfile(t *testing.T) { + // MaxQueryLookback=24h and Start/End at 1ms/1s after epoch, which is well + // outside the lookback window. The frontend should return an empty profile + // without ever contacting the query backend. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Hour * 24) + + qf := newSMPQueryFrontend(t, mockLimits, + new(mockmetastorev1.MockMetadataQueryServiceClient), + new(mockqueryfrontend.MockQueryBackend)) + + ctx := user.InjectOrgID(context.Background(), smpTenant) + resp, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: 1, + End: 1000, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg) + require.Empty(t, resp.Msg.Sample) +} + +func TestSelectMergeProfile_InvalidProfileTypeReturnsError(t *testing.T) { + // SanitizeTimeRange is called first (needs MaxQueryLookback + MaxQueryLength), + // then ParseProfileTypeSelector fails and the function returns an error. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + + qf := newSMPQueryFrontend(t, mockLimits, + new(mockmetastorev1.MockMetadataQueryServiceClient), + new(mockqueryfrontend.MockQueryBackend)) + + ctx := user.InjectOrgID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + + _, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: "invalid", // not the required name:sampleType:sampleUnit:periodType:periodUnit form + LabelSelector: "{}", + Start: start, + End: end, + })) + + require.Error(t, err) + require.ErrorContains(t, err, "profile-type selection must be of the form") +} + +func TestSelectMergeProfile_PprofPath_NoBlocks(t *testing.T) { + // When QueryMetadata returns no blocks, querySingle returns nil and + // SelectMergeProfile must return an empty profile without error. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything). + Return(&metastorev1.QueryMetadataResponse{}, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, new(mockqueryfrontend.MockQueryBackend)) + + ctx := user.InjectOrgID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + + resp, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg) + require.Empty(t, resp.Msg.Sample) +} + +func TestSelectMergeProfile_PprofPath_ReturnsPprof(t *testing.T) { + // Happy path for the pprof query-backend path: the backend returns a + // serialised pprof report which is unmarshalled and forwarded. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(false) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything).Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_PPROF, + Pprof: &queryv1.PprofReport{Pprof: createProfile(t)}, + }}, + }, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := user.InjectOrgID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + + resp, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg) + // createProfile builds a profile with one sample. + require.Len(t, resp.Msg.Sample, 1) +} + +func TestSelectMergeProfile_PprofPath_SendsQueryPprof(t *testing.T) { + // Ensure the pprof path sends a QUERY_PPROF request to the backend (not QUERY_TREE). + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(false) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + var observedQueryType queryv1.QueryType + var observedTraceIDSelector []string + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + req := args.Get(1).(*queryv1.InvokeRequest) + if len(req.Query) > 0 { + observedQueryType = req.Query[0].QueryType + observedTraceIDSelector = req.Query[0].Pprof.GetTraceIdSelector() + } + }). + Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_PPROF, + Pprof: &queryv1.PprofReport{Pprof: createProfile(t)}, + }}, + }, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := user.InjectOrgID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + + traceID := "0123456789abcdef0123456789abcdef" + _, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + TraceIdSelector: []string{traceID}, + })) + + require.NoError(t, err) + assert.Equal(t, queryv1.QueryType_QUERY_PPROF, observedQueryType) + // The trace_id selector must reach the backend query plan; dropping it here + // would silently return an unfiltered profile. + assert.Equal(t, []string{traceID}, observedTraceIDSelector) +} + +func TestSelectMergeProfile_TreePath_NoBlocks(t *testing.T) { + // QueryTreeEnabled=true but no blocks found: must return empty profile without error. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(true) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything). + Return(&metastorev1.QueryMetadataResponse{}, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, new(mockqueryfrontend.MockQueryBackend)) + ctx := user.InjectOrgID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + + resp, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg) + require.Empty(t, resp.Msg.Sample) +} + +func TestSelectMergeProfile_TreePath_ReconstructsProfile(t *testing.T) { + // Happy path for the tree query-backend path: the backend returns a + // LocationRefName tree plus TreeSymbols; SelectMergeProfile must reconstruct + // a valid pprof profile from them. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(true) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + // Build a LocationRefNameTree with a single stack: 10 samples at location ref 1. + lrTree := new(phlaremodel.LocationRefNameTree) + lrTree.InsertStack(10, phlaremodel.LocationRefName(1)) + treeBytes := lrTree.Bytes(-1, func(n phlaremodel.LocationRefName) phlaremodel.LocationRefName { return n }) + + // Symbols table: index 0 is the sentinel, index 1 is the real entry. + symbols := &queryv1.TreeSymbols{ + Strings: []string{"", "funcname"}, + Mappings: []*profilev1.Mapping{{Id: 0}}, + Locations: []*profilev1.Location{ + {Id: 0}, + {Id: 1}, + }, + Functions: []*profilev1.Function{{Id: 0}}, + } + + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything).Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{ + Tree: treeBytes, + Symbols: symbols, + }, + }}, + }, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := user.InjectOrgID(context.Background(), smpTenant) + now := time.Now().UnixMilli() + + resp, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: now, + End: now + time.Minute.Milliseconds(), + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg) + + // One sample at location 1 with value 10. + require.Len(t, resp.Msg.Sample, 1) + require.Equal(t, int64(10), resp.Msg.Sample[0].Value[0]) + require.Equal(t, []uint64{1}, resp.Msg.Sample[0].LocationId) + + // Sentinel is stripped: p.Location = Symbols.Locations[1:] = [{Id:1}] + require.Len(t, resp.Msg.Location, 1) + require.Equal(t, uint64(1), resp.Msg.Location[0].Id) + + // The profile type components are appended to the string table. + require.Contains(t, resp.Msg.StringTable, "inuse_space") // SampleType + require.Contains(t, resp.Msg.StringTable, "bytes") // SampleUnit + require.Contains(t, resp.Msg.StringTable, "space") // PeriodType + + // SampleType and PeriodType point into the string table. + require.Len(t, resp.Msg.SampleType, 1) + require.NotNil(t, resp.Msg.PeriodType) +} + +func TestSelectMergeStacktraces_PprofTreePathForwardsSpanSelector(t *testing.T) { + // Ensure the tree-backed pprof path requests full symbols and forwards spans. + spanSelector := []string{"0000000000000001"} + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(true) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + lrTree := new(phlaremodel.LocationRefNameTree) + lrTree.InsertStack(5, phlaremodel.LocationRefName(1)) + treeBytes := lrTree.Bytes(-1, func(n phlaremodel.LocationRefName) phlaremodel.LocationRefName { return n }) + + symbols := &queryv1.TreeSymbols{ + Strings: []string{""}, + Mappings: []*profilev1.Mapping{{Id: 0}}, + Locations: []*profilev1.Location{{Id: 0}, {Id: 1}}, + Functions: []*profilev1.Function{{Id: 0}}, + } + + var capturedQuery *queryv1.Query + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + req := args.Get(1).(*queryv1.InvokeRequest) + if len(req.Query) > 0 { + capturedQuery = req.Query[0] + } + }). + Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{Tree: treeBytes, Symbols: symbols}, + }}, + }, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := user.InjectOrgID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + + resp, err := qf.SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + SpanSelector: spanSelector, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg.GetPprof().GetProfile()) + require.NotNil(t, capturedQuery) + assert.Equal(t, queryv1.QueryType_QUERY_TREE, capturedQuery.QueryType) + assert.Equal(t, queryv1.SymbolMode_SYMBOL_MODE_FULL, capturedQuery.Tree.GetSymbolMode(), "tree path must request full symbols") + assert.Equal(t, spanSelector, capturedQuery.Tree.GetSpanSelector()) +} + +func TestSelectMergeProfile_TreePath_OtherLocationRef(t *testing.T) { + // When a tree contains OtherLocationRef nodes (produced by node truncation), + // selectMergeProfileTree must synthesise a single "other" location/function + // and reference it from every affected sample. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(true) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + // Two stacks that both contain OtherLocationRef: + // stack A: [OtherLocationRef] self=3 (pure "other") + // stack B: [OtherLocationRef, LocationRef(1)] self=7 (mixed real + other) + lrTree := new(phlaremodel.LocationRefNameTree) + lrTree.InsertStack(3, phlaremodel.OtherLocationRef) + lrTree.InsertStack(7, phlaremodel.LocationRefName(1), phlaremodel.OtherLocationRef) + treeBytes := lrTree.Bytes(-1, func(n phlaremodel.LocationRefName) phlaremodel.LocationRefName { return n }) + + // Symbols contain one real location at index 1; index 0 is the sentinel. + symbols := &queryv1.TreeSymbols{ + Strings: []string{"", "funcname"}, + Mappings: []*profilev1.Mapping{{Id: 0}}, + Locations: []*profilev1.Location{ + {Id: 0}, + {Id: 1}, + }, + Functions: []*profilev1.Function{{Id: 0}}, + } + + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything).Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{Tree: treeBytes, Symbols: symbols}, + }}, + }, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := user.InjectOrgID(context.Background(), smpTenant) + now := time.Now().UnixMilli() + + resp, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: now, + End: now + time.Minute.Milliseconds(), + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg) + + // Exactly two samples, one per stack. + require.Len(t, resp.Msg.Sample, 2) + + // The synthetic "other" string is present exactly once. + otherCount := 0 + for _, s := range resp.Msg.StringTable { + if s == "other" { + otherCount++ + } + } + require.Equal(t, 1, otherCount, "synthetic 'other' string must be added exactly once") + + // Exactly one synthetic "other" Location was appended (Symbols.Locations[1:] has + // one entry, so after appending "other" there are two). + require.Len(t, resp.Msg.Location, 2) + otherLoc := resp.Msg.Location[1] + + // Exactly one synthetic "other" Function was appended (Symbols.Functions[1:] is + // empty, so there is exactly one entry afterwards). + require.Len(t, resp.Msg.Function, 1) + require.Len(t, otherLoc.Line, 1) + require.Equal(t, resp.Msg.Function[0].Id, otherLoc.Line[0].FunctionId) + + // Both samples reference the same synthetic "other" location ID. + for i, s := range resp.Msg.Sample { + found := false + for _, locID := range s.LocationId { + if locID == otherLoc.Id { + found = true + break + } + } + require.True(t, found, "sample %d should reference the synthetic other location", i) + } +} + +func TestSelectMergeProfile_PGOBypassesTreePath(t *testing.T) { + // When a GoPGO stack-trace selector is present, the pprof path must be used + // even when QueryTreeEnabled returns true. + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + // QueryTreeEnabled is NOT called when a PGO selector is present; the code + // short-circuits before checking it. + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + var observedQueryType queryv1.QueryType + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + req := args.Get(1).(*queryv1.InvokeRequest) + if len(req.Query) > 0 { + observedQueryType = req.Query[0].QueryType + } + }). + Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_PPROF, + Pprof: &queryv1.PprofReport{Pprof: createProfile(t)}, + }}, + }, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := user.InjectOrgID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + + _, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + StackTraceSelector: &typesv1.StackTraceSelector{ + GoPgo: &typesv1.GoPGO{}, + }, + })) + + require.NoError(t, err) + assert.Equal(t, queryv1.QueryType_QUERY_PPROF, observedQueryType, + "GoPGO selector must bypass the tree path and use QUERY_PPROF") +} + +func TestSelectMergeProfiles_Symbolization(t *testing.T) { + // Backend response for the pprof path. + pprofBackendResp := &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_PPROF, + Pprof: &queryv1.PprofReport{Pprof: createProfile(t)}, + }}, + } + + // Backend response for the tree path. + lrTree := new(phlaremodel.LocationRefNameTree) + lrTree.InsertStack(10, phlaremodel.LocationRefName(1)) + treeBytes := lrTree.Bytes(-1, func(n phlaremodel.LocationRefName) phlaremodel.LocationRefName { return n }) + treeBackendResp := &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{ + Tree: treeBytes, + Symbols: &queryv1.TreeSymbols{ + Strings: []string{"", "funcname"}, + Mappings: []*profilev1.Mapping{{Id: 0}, {Id: 1, HasFunctions: false}}, + Locations: []*profilev1.Location{{Id: 0}, {Id: 1, MappingId: 1}}, + Functions: []*profilev1.Function{{Id: 0}}, + }, + }, + }}, + } + + tests := []struct { + name string + tenantID string + useTree bool + hasUnsymbolized bool + setupMocks func(*mockfrontend.MockLimits, *mockqueryfrontend.MockSymbolizer) + verifyResult func(*testing.T, *mockqueryfrontend.MockSymbolizer, *connect.Response[profilev1.Profile]) + }{ + { + name: "pprof: enabled with unsymbolized profiles", + tenantID: "tenant1", + hasUnsymbolized: true, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant1").Return(true) + l.On("QuerySanitizeOnMerge", "tenant1").Return(false) + s.On("SymbolizePprof", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + p := args.Get(1).(*profilev1.Profile) + p.StringTable = append(p.StringTable, "symbolized") + }). + Return(nil).Once() + }, + verifyResult: func(t *testing.T, _ *mockqueryfrontend.MockSymbolizer, resp *connect.Response[profilev1.Profile]) { + require.Contains(t, resp.Msg.StringTable, "symbolized") + }, + }, + { + name: "pprof: disabled", + tenantID: "tenant2", + hasUnsymbolized: true, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant2").Return(false) + l.On("QuerySanitizeOnMerge", "tenant2").Return(false) + }, + verifyResult: func(t *testing.T, _ *mockqueryfrontend.MockSymbolizer, resp *connect.Response[profilev1.Profile]) { + require.NotContains(t, resp.Msg.StringTable, "symbolized") + }, + }, + { + name: "pprof: enabled but no unsymbolized profiles", + tenantID: "tenant3", + hasUnsymbolized: false, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant3").Return(true) + l.On("QuerySanitizeOnMerge", "tenant3").Return(false) + }, + verifyResult: func(t *testing.T, _ *mockqueryfrontend.MockSymbolizer, resp *connect.Response[profilev1.Profile]) { + require.NotContains(t, resp.Msg.StringTable, "symbolized") + }, + }, + { + name: "tree: enabled with unsymbolized profiles", + tenantID: "tenant4", + useTree: true, + hasUnsymbolized: true, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant4").Return(true) + l.On("QuerySanitizeOnMerge", "tenant4").Return(false) + s.On("SymbolizePprof", mock.Anything, mock.Anything).Return(nil).Once() + }, + verifyResult: func(t *testing.T, s *mockqueryfrontend.MockSymbolizer, _ *connect.Response[profilev1.Profile]) { + s.AssertCalled(t, "SymbolizePprof", mock.Anything, mock.Anything) + }, + }, + { + name: "tree: disabled", + tenantID: "tenant5", + useTree: true, + hasUnsymbolized: true, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant5").Return(false) + l.On("QuerySanitizeOnMerge", "tenant5").Return(false) + }, + verifyResult: func(t *testing.T, s *mockqueryfrontend.MockSymbolizer, _ *connect.Response[profilev1.Profile]) { + s.AssertNotCalled(t, "SymbolizePprof", mock.Anything, mock.Anything) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", tt.tenantID).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", tt.tenantID).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", tt.tenantID).Return(false) + mockLimits.On("QueryTreeEnabled", tt.tenantID).Return(tt.useTree) + mockSymbolizer := mockqueryfrontend.NewMockSymbolizer(t) + tt.setupMocks(mockLimits, mockSymbolizer) + + backendResp := pprofBackendResp + if tt.useTree { + backendResp = treeBackendResp + } + mockQueryBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockQueryBackend.On("Invoke", mock.Anything, mock.Anything).Return(backendResp, nil) + + unsymbolizedValue := fmt.Sprintf("%v", tt.hasUnsymbolized) + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadataClient.On("QueryMetadata", mock.Anything, mock.Anything). + Return(&metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{ + Id: "block_id", + Datasets: []*metastorev1.Dataset{{ + Labels: []int32{1, 1, 2}, + }}, + StringTable: []string{ + "", // First string is always empty by convention + metadata.LabelNameUnsymbolized, + unsymbolizedValue, + }, + }}, + }, nil). + Once() + + qf := NewQueryFrontend( + log.NewNopLogger(), + mockLimits, + mockMetadataClient, + nil, + mockQueryBackend, + mockSymbolizer, + nil, + nil, + ) + + ctx := tenant.InjectTenantID(context.Background(), tt.tenantID) + start, end := smpValidTimeRange() + resp, err := qf.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: `{service_name="test-service"}`, + Start: start, + End: end, + })) + + require.NoError(t, err) + tt.verifyResult(t, mockSymbolizer, resp) + + mockMetadataClient.AssertExpectations(t) + mockQueryBackend.AssertExpectations(t) + }) + } +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_merge_span_profile.go b/pkg/frontend/readpath/queryfrontend/query_select_merge_span_profile.go new file mode 100644 index 0000000000..8bc516ccb1 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_merge_span_profile.go @@ -0,0 +1,36 @@ +package queryfrontend + +import ( + "context" + + "connectrpc.com/connect" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" +) + +func (q *QueryFrontend) SelectMergeSpanProfile( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeSpanProfileRequest], +) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + format := c.Msg.Format + if format != querierv1.ProfileFormat_PROFILE_FORMAT_TREE { + // The deprecated RPC historically treated every non-tree format as a flamegraph. + format = querierv1.ProfileFormat_PROFILE_FORMAT_FLAMEGRAPH + } + resp, err := q.SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: c.Msg.ProfileTypeID, + LabelSelector: c.Msg.LabelSelector, + Start: c.Msg.Start, + End: c.Msg.End, + MaxNodes: c.Msg.MaxNodes, + Format: format, + SpanSelector: c.Msg.SpanSelector, + })) + if err != nil { + return nil, err + } + return connect.NewResponse(&querierv1.SelectMergeSpanProfileResponse{ + Flamegraph: resp.Msg.Flamegraph, + Tree: resp.Msg.Tree, + }), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_merge_span_profile_test.go b/pkg/frontend/readpath/queryfrontend/query_select_merge_span_profile_test.go new file mode 100644 index 0000000000..d2ca5f2f0c --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_merge_span_profile_test.go @@ -0,0 +1,203 @@ +package queryfrontend + +import ( + "context" + "fmt" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockqueryfrontend" +) + +func TestSelectMergeSpanProfile_Symbolization(t *testing.T) { + // pprofBytes contains a profile with one sample at location 1, where location 1 + // maps to function "original_func". backendTreeSymbolizer rewrites QUERY_TREE → + // QUERY_PPROF before calling the upstream backend, so the mock must return this + // pprof report. The symbolizer mock then renames the function to "symbolized_func", + // which must be visible in the resulting flamegraph. + pprofBytes := func() []byte { + p := &profilev1.Profile{ + StringTable: []string{"", "original_func"}, + Function: []*profilev1.Function{{Id: 1, Name: 1}}, + Location: []*profilev1.Location{{Id: 1, Line: []*profilev1.Line{{FunctionId: 1}}}}, + Mapping: []*profilev1.Mapping{{Id: 1}}, + Sample: []*profilev1.Sample{{LocationId: []uint64{1}, Value: []int64{10}}}, + } + b, err := pprof.Marshal(p, true) + require.NoError(t, err) + return b + }() + + spanSelector := []string{"span-abc123"} + + tests := []struct { + name string + tenantID string + hasUnsymbolized bool + backendResp *queryv1.InvokeResponse + expectSymbolized bool + setupMocks func(*mockfrontend.MockLimits, *mockqueryfrontend.MockSymbolizer) + checkInvokeReq func(*testing.T, *queryv1.InvokeRequest) + }{ + { + name: "symbolization enabled for tenant with native profiles", + tenantID: "tenant1", + hasUnsymbolized: true, + expectSymbolized: true, + // backendTreeSymbolizer rewrites QUERY_TREE -> QUERY_PPROF before calling + // the upstream backend, so the mock must return a pprof report. + backendResp: &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + Pprof: &queryv1.PprofReport{Pprof: pprofBytes}, + }}, + }, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant1").Return(true) + l.On("QuerySanitizeOnMerge", "tenant1").Return(false) + s.On("SymbolizePprof", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + p := args.Get(1).(*profilev1.Profile) + p.StringTable = append(p.StringTable, "symbolized_func") + p.Function[0].Name = int64(len(p.StringTable) - 1) + }). + Return(nil).Once() + }, + // backendTreeSymbolizer converts QUERY_TREE to QUERY_PPROF, preserving SpanSelector. + checkInvokeReq: func(t *testing.T, req *queryv1.InvokeRequest) { + require.Len(t, req.Query, 1) + assert.Equal(t, queryv1.QueryType_QUERY_PPROF, req.Query[0].QueryType) + require.NotNil(t, req.Query[0].Pprof) + assert.Equal(t, spanSelector, req.Query[0].Pprof.GetSpanSelector()) + }, + }, + { + name: "symbolization disabled for tenant", + tenantID: "tenant2", + hasUnsymbolized: true, + expectSymbolized: false, + // No backendTreeSymbolizer wrapping; backend receives the TREE query directly. + backendResp: &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{}, + }}, + }, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant2").Return(false) + l.On("QuerySanitizeOnMerge", "tenant2").Return(false) + }, + // No symbolizer wrapping: backend receives QUERY_TREE with SpanSelector intact. + checkInvokeReq: func(t *testing.T, req *queryv1.InvokeRequest) { + require.Len(t, req.Query, 1) + assert.Equal(t, queryv1.QueryType_QUERY_TREE, req.Query[0].QueryType) + assert.Equal(t, spanSelector, req.Query[0].Tree.GetSpanSelector()) + }, + }, + { + name: "symbolization enabled but no native profiles", + tenantID: "tenant3", + hasUnsymbolized: false, + expectSymbolized: false, + // No backendTreeSymbolizer wrapping; backend receives the TREE query directly. + backendResp: &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{}, + }}, + }, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant3").Return(true) + l.On("QuerySanitizeOnMerge", "tenant3").Return(false) + }, + // No symbolizer wrapping: backend receives QUERY_TREE with SpanSelector intact. + checkInvokeReq: func(t *testing.T, req *queryv1.InvokeRequest) { + require.Len(t, req.Query, 1) + assert.Equal(t, queryv1.QueryType_QUERY_TREE, req.Query[0].QueryType) + assert.Equal(t, spanSelector, req.Query[0].Tree.GetSpanSelector()) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", tt.tenantID).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", tt.tenantID).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesDefault", tt.tenantID).Return(0) + mockSymbolizer := mockqueryfrontend.NewMockSymbolizer(t) + tt.setupMocks(mockLimits, mockSymbolizer) + + checkInvokeReq := tt.checkInvokeReq + mockQueryBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockQueryBackend.On("Invoke", mock.Anything, mock.MatchedBy(func(req *queryv1.InvokeRequest) bool { + checkInvokeReq(t, req) + return true + })).Return(tt.backendResp, nil) + + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadataClient.On("QueryMetadata", mock.Anything, mock.Anything). + Return(&metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{ + Id: "block_id", + Datasets: []*metastorev1.Dataset{{ + Labels: []int32{1, 1, 2}, + }}, + StringTable: []string{ + "", // First string is always empty by convention + metadata.LabelNameUnsymbolized, + fmt.Sprintf("%v", tt.hasUnsymbolized), + }, + }}, + }, nil). + Once() + + qf := NewQueryFrontend( + log.NewNopLogger(), + mockLimits, + mockMetadataClient, + nil, + mockQueryBackend, + mockSymbolizer, + nil, + nil, + ) + + ctx := tenant.InjectTenantID(context.Background(), tt.tenantID) + start, end := smpValidTimeRange() + resp, err := qf.SelectMergeSpanProfile(ctx, connect.NewRequest(&querierv1.SelectMergeSpanProfileRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: `{service_name="test-service"}`, + Start: start, + End: end, + SpanSelector: spanSelector, + })) + + require.NoError(t, err) + names := resp.Msg.GetFlamegraph().GetNames() + if tt.expectSymbolized { + require.Contains(t, names, "symbolized_func") + require.NotContains(t, names, "original_func") + } else { + require.NotContains(t, names, "symbolized_func") + } + + mockMetadataClient.AssertExpectations(t) + mockQueryBackend.AssertExpectations(t) + }) + } +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_merge_stacktraces.go b/pkg/frontend/readpath/queryfrontend/query_select_merge_stacktraces.go new file mode 100644 index 0000000000..15e7a9fe57 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_merge_stacktraces.go @@ -0,0 +1,164 @@ +package queryfrontend + +import ( + "context" + "errors" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/dot" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) SelectMergeStacktraces( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + if len(c.Msg.SpanSelector) > 0 && len(c.Msg.TraceIdSelector) > 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("span_selector and trace_id_selector cannot be combined")) + } + + switch c.Msg.Format { + case querierv1.ProfileFormat_PROFILE_FORMAT_DOT: + return q.selectMergeStacktracesDot(ctx, c) + case querierv1.ProfileFormat_PROFILE_FORMAT_PPROF: + p, err := q.selectMergeStacktracesPprof(ctx, c.Msg) + if err != nil { + return nil, err + } + return connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{Profile: p}, + }), nil + } + + b, err := q.selectMergeStacktracesTree(ctx, c) + if err != nil { + return nil, err + } + var resp querierv1.SelectMergeStacktracesResponse + switch c.Msg.Format { + case querierv1.ProfileFormat_PROFILE_FORMAT_TREE: + resp.Tree = b + default: + t, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](b) + if err != nil { + return nil, err + } + resp.Flamegraph = phlaremodel.NewFlameGraph(t, c.Msg.GetMaxNodes()) + } + return connect.NewResponse(&resp), nil +} + +func (q *QueryFrontend) selectMergeStacktracesDot( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + // Use separate max nodes for source pprof fetch vs DOT rendering + const defaultSourceMaxNodes = int64(512) + const defaultDotMaxNodes = int64(100) + dotMaxNodes := defaultDotMaxNodes + sourceMaxNodes := defaultSourceMaxNodes + if c.Msg.MaxNodes != nil { + if v := c.Msg.GetMaxNodes(); v > 0 { + dotMaxNodes = v + } + if dotMaxNodes > sourceMaxNodes { + sourceMaxNodes = dotMaxNodes + } + } + + profile, err := q.selectMergeStacktracesPprof(ctx, &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: c.Msg.ProfileTypeID, + LabelSelector: c.Msg.LabelSelector, + Start: c.Msg.Start, + End: c.Msg.End, + MaxNodes: &sourceMaxNodes, + StackTraceSelector: c.Msg.StackTraceSelector, + ProfileIdSelector: c.Msg.ProfileIdSelector, + TraceIdSelector: c.Msg.TraceIdSelector, + SpanSelector: c.Msg.SpanSelector, + }) + if err != nil { + return nil, err + } + if profile == nil || len(profile.Sample) == 0 { + return connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{}), nil + } + + d, err := dot.FromProfile(profile, int(dotMaxNodes)) + if err != nil { + return nil, err + } + return connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{Dot: d}), nil +} + +func (q *QueryFrontend) selectMergeStacktracesTree( + ctx context.Context, + c *connect.Request[querierv1.SelectMergeStacktracesRequest], +) (tree []byte, err error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &c.Msg.Start, &c.Msg.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return nil, nil + } + + maxNodes, err := validation.ValidateMaxNodes(q.limits, tenantIDs, c.Msg.GetMaxNodes()) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + _, err = phlaremodel.ParseProfileTypeSelector(c.Msg.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + labelSelector, err := buildLabelSelectorWithProfileType(c.Msg.LabelSelector, c.Msg.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + report, err := q.querySingle(ctx, + &queryv1.QueryRequest{ + StartTime: c.Msg.Start, + EndTime: c.Msg.End, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{ + MaxNodes: maxNodes, + StackTraceSelector: c.Msg.StackTraceSelector, + ProfileIdSelector: c.Msg.ProfileIdSelector, + TraceIdSelector: c.Msg.TraceIdSelector, + SpanSelector: c.Msg.SpanSelector, + }, + }}, + }, + func(ctx context.Context, upstream QueryBackend, blocks []*metastorev1.BlockMeta) QueryBackend { + shouldSymbolize := q.shouldSymbolize(ctx, tenantIDs, blocks) + if !shouldSymbolize { + return upstream + } + return &backendTreeSymbolizer{ + upstream: upstream, + symbolizer: q.symbolizer, + } + }, + ) + if err != nil { + return nil, err + } + if report == nil { + return nil, nil + } + return report.Tree.Tree, nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_merge_stacktraces_test.go b/pkg/frontend/readpath/queryfrontend/query_select_merge_stacktraces_test.go new file mode 100644 index 0000000000..be41602ac6 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_merge_stacktraces_test.go @@ -0,0 +1,372 @@ +package queryfrontend + +import ( + "context" + "fmt" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockqueryfrontend" +) + +func TestSelectMergeStacktraces_RejectsSpanAndTraceSelectors(t *testing.T) { + qf := new(QueryFrontend) + resp, err := qf.SelectMergeStacktraces(context.Background(), connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + SpanSelector: []string{"0000000000000001"}, + TraceIdSelector: []string{"00000000000000000000000000000001"}, + })) + + require.Nil(t, resp) + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + require.ErrorContains(t, err, "span_selector and trace_id_selector cannot be combined") +} + +func TestSelectMergeStacktraces_SpanSelectorTreeFormats(t *testing.T) { + spanSelector := []string{"0000000000000001"} + tree := new(phlaremodel.FunctionNameTree) + tree.InsertStack(1, "foo") + treeBytes := tree.Bytes(-1, nil) + + tests := []struct { + name string + format querierv1.ProfileFormat + check func(*testing.T, *querierv1.SelectMergeStacktracesResponse) + }{ + { + name: "unspecified returns flamegraph", + check: func(t *testing.T, resp *querierv1.SelectMergeStacktracesResponse) { + require.NotNil(t, resp.Flamegraph) + require.Empty(t, resp.Tree) + require.Nil(t, resp.Pprof) + }, + }, + { + name: "flamegraph", + format: querierv1.ProfileFormat_PROFILE_FORMAT_FLAMEGRAPH, + check: func(t *testing.T, resp *querierv1.SelectMergeStacktracesResponse) { + require.NotNil(t, resp.Flamegraph) + require.Empty(t, resp.Tree) + require.Nil(t, resp.Pprof) + }, + }, + { + name: "tree", + format: querierv1.ProfileFormat_PROFILE_FORMAT_TREE, + check: func(t *testing.T, resp *querierv1.SelectMergeStacktracesResponse) { + require.Equal(t, treeBytes, resp.Tree) + require.Nil(t, resp.Flamegraph) + require.Nil(t, resp.Pprof) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesDefault", smpTenant).Return(0) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + req := args.Get(1).(*queryv1.InvokeRequest) + require.Equal(t, spanSelector, req.Query[0].Tree.GetSpanSelector()) + }). + Return(&queryv1.InvokeResponse{Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{Tree: treeBytes}, + }}}, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := tenant.InjectTenantID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + resp, err := qf.SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + Format: tt.format, + SpanSelector: spanSelector, + })) + + require.NoError(t, err) + tt.check(t, resp.Msg) + }) + } +} + +func TestSelectMergeStacktraces_SpanSelectorPprof(t *testing.T) { + spanSelector := []string{"0000000000000001"} + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", smpTenant).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", smpTenant).Return(false) + mockLimits.On("QueryTreeEnabled", smpTenant).Return(false) + mockLimits.On("QuerySanitizeOnMerge", smpTenant).Return(false) + + mockMetadata := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadata.On("QueryMetadata", mock.Anything, mock.Anything).Return(smpOneBlock(), nil) + + mockBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockBackend.On("Invoke", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + req := args.Get(1).(*queryv1.InvokeRequest) + require.Equal(t, queryv1.QueryType_QUERY_PPROF, req.Query[0].QueryType) + require.Equal(t, spanSelector, req.Query[0].Pprof.GetSpanSelector()) + }). + Return(&queryv1.InvokeResponse{Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_PPROF, + Pprof: &queryv1.PprofReport{Pprof: createProfile(t)}, + }}}, nil) + + qf := newSMPQueryFrontend(t, mockLimits, mockMetadata, mockBackend) + ctx := tenant.InjectTenantID(context.Background(), smpTenant) + start, end := smpValidTimeRange() + resp, err := qf.SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: "{}", + Start: start, + End: end, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + SpanSelector: spanSelector, + })) + + require.NoError(t, err) + require.NotNil(t, resp.Msg.GetPprof().GetProfile()) + require.Len(t, resp.Msg.Pprof.Profile.Sample, 1) + require.Nil(t, resp.Msg.Flamegraph) + require.Empty(t, resp.Msg.Tree) +} + +func TestSelectMergeStacktrace_Symbolization(t *testing.T) { + // pprofBytes contains a profile with one sample at location 1, where location 1 + // maps to function "original_func". backendTreeSymbolizer rewrites QUERY_TREE → + // QUERY_PPROF before calling the upstream backend, so the mock must return this + // pprof report. The symbolizer mock then renames the function to "symbolized_func", + // which must be visible in the resulting flamegraph. + pprofBytes := func() []byte { + p := &profilev1.Profile{ + StringTable: []string{"", "original_func"}, + Function: []*profilev1.Function{{Id: 1, Name: 1}}, + Location: []*profilev1.Location{{Id: 1, Line: []*profilev1.Line{{FunctionId: 1}}}}, + Mapping: []*profilev1.Mapping{{Id: 1}}, + Sample: []*profilev1.Sample{{LocationId: []uint64{1}, Value: []int64{10}}}, + } + b, err := pprof.Marshal(p, true) + require.NoError(t, err) + return b + }() + + tests := []struct { + name string + tenantID string + hasUnsymbolized bool + backendResp *queryv1.InvokeResponse + expectSymbolized bool + setupMocks func(*mockfrontend.MockLimits, *mockqueryfrontend.MockSymbolizer) + }{ + { + name: "symbolization enabled for tenant with native profiles", + tenantID: "tenant1", + hasUnsymbolized: true, + expectSymbolized: true, + // backendTreeSymbolizer rewrites QUERY_TREE -> QUERY_PPROF before calling + // the upstream backend, so the mock must return a pprof report. + backendResp: &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + Pprof: &queryv1.PprofReport{Pprof: pprofBytes}, + }}, + }, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant1").Return(true) + l.On("QuerySanitizeOnMerge", "tenant1").Return(false) + s.On("SymbolizePprof", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + p := args.Get(1).(*profilev1.Profile) + p.StringTable = append(p.StringTable, "symbolized_func") + p.Function[0].Name = int64(len(p.StringTable) - 1) + }). + Return(nil).Once() + }, + }, + { + name: "symbolization disabled for tenant", + tenantID: "tenant2", + hasUnsymbolized: true, + expectSymbolized: false, + // No backendTreeSymbolizer wrapping; backend receives the TREE query directly. + backendResp: &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{}, + }}, + }, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant2").Return(false) + l.On("QuerySanitizeOnMerge", "tenant2").Return(false) + }, + }, + { + name: "symbolization enabled but no native profiles", + tenantID: "tenant3", + hasUnsymbolized: false, + expectSymbolized: false, + // No backendTreeSymbolizer wrapping; backend receives the TREE query directly. + backendResp: &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_TREE, + Tree: &queryv1.TreeReport{}, + }}, + }, + setupMocks: func(l *mockfrontend.MockLimits, s *mockqueryfrontend.MockSymbolizer) { + l.On("SymbolizerEnabled", "tenant3").Return(true) + l.On("QuerySanitizeOnMerge", "tenant3").Return(false) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", tt.tenantID).Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", tt.tenantID).Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesDefault", tt.tenantID).Return(0) + mockSymbolizer := mockqueryfrontend.NewMockSymbolizer(t) + tt.setupMocks(mockLimits, mockSymbolizer) + + mockQueryBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockQueryBackend.On("Invoke", mock.Anything, mock.Anything).Return(tt.backendResp, nil) + + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadataClient.On("QueryMetadata", mock.Anything, mock.Anything). + Return(&metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{ + Id: "block_id", + Datasets: []*metastorev1.Dataset{{ + Labels: []int32{1, 1, 2}, + }}, + StringTable: []string{ + "", // First string is always empty by convention + metadata.LabelNameUnsymbolized, + fmt.Sprintf("%v", tt.hasUnsymbolized), + }, + }}, + }, nil). + Once() + + qf := NewQueryFrontend( + log.NewNopLogger(), + mockLimits, + mockMetadataClient, + nil, + mockQueryBackend, + mockSymbolizer, + nil, + nil, + ) + + ctx := tenant.InjectTenantID(context.Background(), tt.tenantID) + start, end := smpValidTimeRange() + resp, err := qf.SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: `{service_name="test-service"}`, + Start: start, + End: end, + })) + + require.NoError(t, err) + names := resp.Msg.GetFlamegraph().GetNames() + if tt.expectSymbolized { + require.Contains(t, names, "symbolized_func") + require.NotContains(t, names, "original_func") + } else { + require.NotContains(t, names, "symbolized_func") + } + + mockMetadataClient.AssertExpectations(t) + mockQueryBackend.AssertExpectations(t) + }) + } +} + +func TestSelectMergeStacktraces_DotFormat(t *testing.T) { + spanSelector := []string{"0000000000000001"} + p := &profilev1.Profile{ + StringTable: []string{"", "my_func", "samples", "count", "", ""}, + Function: []*profilev1.Function{{Id: 1, Name: 1}}, + Location: []*profilev1.Location{{Id: 1, Line: []*profilev1.Line{{FunctionId: 1}}}}, + Mapping: []*profilev1.Mapping{{Id: 1}}, + Sample: []*profilev1.Sample{{LocationId: []uint64{1}, Value: []int64{10}}}, + PeriodType: &profilev1.ValueType{Type: 2, Unit: 3}, + SampleType: []*profilev1.ValueType{{Type: 4, Unit: 5}}, + } + pprofBytes, err := pprof.Marshal(p, true) + require.NoError(t, err) + + mockLimits := mockfrontend.NewMockLimits(t) + mockLimits.On("MaxQueryLookback", "tenant1").Return(time.Duration(0)) + mockLimits.On("MaxQueryLength", "tenant1").Return(time.Duration(0)) + mockLimits.On("MaxFlameGraphNodesOnSelectMergeProfile", "tenant1").Return(false) + mockLimits.On("QueryTreeEnabled", "tenant1").Return(false) + mockLimits.On("QuerySanitizeOnMerge", "tenant1").Return(false) + + mockQueryBackend := mockqueryfrontend.NewMockQueryBackend(t) + mockQueryBackend.On("Invoke", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + req := args.Get(1).(*queryv1.InvokeRequest) + require.Equal(t, spanSelector, req.Query[0].Pprof.GetSpanSelector()) + }).Return(&queryv1.InvokeResponse{ + Reports: []*queryv1.Report{{ + ReportType: queryv1.ReportType_REPORT_PPROF, + Pprof: &queryv1.PprofReport{Pprof: pprofBytes}, + }}, + }, nil) + + mockMetadataClient := new(mockmetastorev1.MockMetadataQueryServiceClient) + mockMetadataClient.On("QueryMetadata", mock.Anything, mock.Anything). + Return(&metastorev1.QueryMetadataResponse{ + Blocks: []*metastorev1.BlockMeta{{ + Id: "block_id", + Datasets: []*metastorev1.Dataset{{Labels: []int32{1, 1, 2}}}, + StringTable: []string{"", metadata.LabelNameUnsymbolized, "false"}, + }}, + }, nil) + + qf := NewQueryFrontend(log.NewNopLogger(), mockLimits, mockMetadataClient, nil, mockQueryBackend, nil, nil, nil) + + ctx := tenant.InjectTenantID(context.Background(), "tenant1") + start, end := smpValidTimeRange() + resp, err := qf.SelectMergeStacktraces(ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: smpProfileType, + LabelSelector: `{service_name="test-service"}`, + Start: start, + End: end, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_DOT, + SpanSelector: spanSelector, + })) + + require.NoError(t, err) + require.NotEmpty(t, resp.Msg.Dot) + require.Contains(t, resp.Msg.Dot, "digraph") + require.Nil(t, resp.Msg.Flamegraph) + require.Empty(t, resp.Msg.Tree) +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_time_series.go b/pkg/frontend/readpath/queryfrontend/query_select_time_series.go new file mode 100644 index 0000000000..0a1d837a89 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_time_series.go @@ -0,0 +1,150 @@ +package queryfrontend + +import ( + "context" + "errors" + "time" + + "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/attributetable" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) SelectSeries( + ctx context.Context, + c *connect.Request[querierv1.SelectSeriesRequest], +) (*connect.Response[querierv1.SelectSeriesResponse], error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &c.Msg.Start, &c.Msg.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return connect.NewResponse(&querierv1.SelectSeriesResponse{}), nil + } + + _, err = phlaremodel.ParseProfileTypeSelector(c.Msg.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + // Sub-millisecond step values truncate to 0 in the backend's millisecond + // arithmetic and would cause an unbounded loop in RangeSeries; reject + // anything below 1ms. + if c.Msg.Step < 0.001 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("step must be >= 1ms")) + } + + stepMs := time.Duration(c.Msg.Step * float64(time.Second)).Milliseconds() + start := c.Msg.Start - stepMs + + labelSelector, err := buildLabelSelectorWithProfileType(c.Msg.LabelSelector, c.Msg.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + // TODO: Once queryCompact is fully rolled out, use it for all queries and remove queryStandard. + var series []*typesv1.Series + if c.Msg.GetExemplarType() == typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL { + series, err = q.queryCompact(ctx, start, c.Msg.End, labelSelector, c.Msg) + } else { + series, err = q.queryStandard(ctx, start, c.Msg.End, labelSelector, c.Msg) + } + if err != nil { + return nil, err + } + + series = timeseries.TopSeries(series, int(c.Msg.GetLimit())) + return connect.NewResponse(&querierv1.SelectSeriesResponse{Series: series}), nil +} + +func (q *QueryFrontend) queryStandard(ctx context.Context, start, end int64, labelSelector string, req *querierv1.SelectSeriesRequest) ([]*typesv1.Series, error) { + report, err := q.querySingle(ctx, &queryv1.QueryRequest{ + StartTime: start, + EndTime: end, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TIME_SERIES, + TimeSeries: &queryv1.TimeSeriesQuery{ + Step: req.GetStep(), + GroupBy: req.GetGroupBy(), + Limit: req.GetLimit(), + ExemplarType: req.GetExemplarType(), + }, + }}, + }, nil) + if err != nil { + return nil, err + } + if report == nil || report.TimeSeries == nil { + return nil, nil + } + return report.TimeSeries.TimeSeries, nil +} + +// queryCompact uses the compact time series format with attribute table interning. +// Currently only used for exemplar retrieval (EXEMPLAR_TYPE_INDIVIDUAL). +// The legacy queryStandard path is used for all other time series queries. +// TODO: Migrate all queries to use queryCompact and remove queryStandard. +func (q *QueryFrontend) queryCompact(ctx context.Context, start, end int64, labelSelector string, req *querierv1.SelectSeriesRequest) ([]*typesv1.Series, error) { + report, err := q.querySingle(ctx, &queryv1.QueryRequest{ + StartTime: start, + EndTime: end, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TIME_SERIES_COMPACT, + TimeSeriesCompact: &queryv1.TimeSeriesQuery{ + Step: req.GetStep(), + GroupBy: req.GetGroupBy(), + Limit: req.GetLimit(), + ExemplarType: req.GetExemplarType(), + }, + }}, + }, nil) + if err != nil { + return nil, err + } + if report == nil || report.TimeSeriesCompact == nil { + return nil, nil + } + + return expandQuerySeries(report.TimeSeriesCompact.TimeSeries, report.TimeSeriesCompact.AttributeTable), nil +} + +func expandQuerySeries(series []*queryv1.Series, table *queryv1.AttributeTable) []*typesv1.Series { + if len(series) == 0 { + return nil + } + if table == nil { + table = &queryv1.AttributeTable{} + } + + result := make([]*typesv1.Series, len(series)) + for i, s := range series { + points := make([]*typesv1.Point, len(s.Points)) + for j, p := range s.Points { + points[j] = &typesv1.Point{Value: p.Value, Timestamp: p.Timestamp} + if len(p.AnnotationRefs) > 0 { + points[j].Annotations = attributetable.ResolveAnnotations(p.AnnotationRefs, table) + } + if len(p.Exemplars) > 0 { + points[j].Exemplars = attributetable.ResolveExemplars(p.Exemplars, table) + } + } + result[i] = &typesv1.Series{ + Labels: attributetable.ResolveLabelPairs(s.AttributeRefs, table), + Points: points, + } + } + return result +} diff --git a/pkg/frontend/readpath/queryfrontend/query_select_time_series_test.go b/pkg/frontend/readpath/queryfrontend/query_select_time_series_test.go new file mode 100644 index 0000000000..19c359665c --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_select_time_series_test.go @@ -0,0 +1,72 @@ +package queryfrontend + +import ( + "context" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/stretchr/testify/require" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockfrontend" +) + +// Sub-millisecond step values truncate to 0 in the backend's millisecond +// arithmetic and would cause an unbounded loop in RangeSeries; the frontend +// must reject them with InvalidArgument before they reach the backend. +func TestSelectSeries_RejectsSubMillisecondStep(t *testing.T) { + for _, step := range []float64{0, 0.0001, 0.0005, 0.0009999} { + t.Run("step="+formatStep(step), func(t *testing.T) { + limits := mockfrontend.NewMockLimits(t) + limits.On("MaxQueryLookback", "test-tenant").Return(time.Duration(0)).Maybe() + limits.On("MaxQueryLength", "test-tenant").Return(time.Duration(0)).Maybe() + + qf := NewQueryFrontend(log.NewNopLogger(), limits, nil, nil, nil, nil, nil, nil) + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + + _, err := qf.SelectSeries(ctx, connect.NewRequest(&querierv1.SelectSeriesRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + LabelSelector: "{}", + Start: 1000, + End: 2000, + Step: step, + })) + + require.Error(t, err) + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + require.Contains(t, err.Error(), "step must be >= 1ms") + }) + } +} + +func TestSelectHeatmap_RejectsSubMillisecondStep(t *testing.T) { + for _, step := range []float64{0, 0.0001, 0.0005, 0.0009999} { + t.Run("step="+formatStep(step), func(t *testing.T) { + limits := mockfrontend.NewMockLimits(t) + qf := NewQueryFrontend(log.NewNopLogger(), limits, nil, nil, nil, nil, nil, nil) + ctx := tenant.InjectTenantID(context.Background(), "test-tenant") + + _, err := qf.SelectHeatmap(ctx, connect.NewRequest(&querierv1.SelectHeatmapRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + LabelSelector: "{}", + Start: 1000, + End: 2000, + Step: step, + })) + + require.Error(t, err) + require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) + require.Contains(t, err.Error(), "step must be >= 1ms") + }) + } +} + +func formatStep(s float64) string { + if s == 0 { + return "0" + } + return time.Duration(s * float64(time.Second)).String() +} diff --git a/pkg/frontend/readpath/queryfrontend/query_series_labels.go b/pkg/frontend/readpath/queryfrontend/query_series_labels.go new file mode 100644 index 0000000000..6e2831d647 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_series_labels.go @@ -0,0 +1,109 @@ +package queryfrontend + +import ( + "context" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + "github.com/prometheus/common/model" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/featureflags" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func (q *QueryFrontend) filterLabelNames( + ctx context.Context, + c *connect.Request[querierv1.SeriesRequest], + labelNames []string, + matchers []string, +) ([]string, error) { + if capabilities, ok := featureflags.GetClientCapabilities(ctx); ok && capabilities.AllowUtf8LabelNames { + return labelNames, nil + } + + toFilter := make([]string, len(labelNames)) + copy(toFilter, labelNames) + + // Filter out label names not passing legacy validation if utf8 label names not enabled + if len(labelNames) == 0 { + // Querying for all label names; must retrieve all label names to then filter out + response, err := q.LabelNames(ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: c.Msg.Start, + End: c.Msg.End, + Matchers: matchers, + })) + + if err != nil { + return nil, err + } + if response != nil { + toFilter = response.Msg.Names + } + } + + filtered := make([]string, 0, len(labelNames)) + for _, name := range toFilter { + if !model.LegacyValidation.IsValidLabelName(name) { + level.Debug(q.logger).Log("msg", "filtering out label", "label_name", name) + continue + } + filtered = append(filtered, name) + } + return filtered, nil +} + +func (q *QueryFrontend) Series( + ctx context.Context, + c *connect.Request[querierv1.SeriesRequest], +) (*connect.Response[querierv1.SeriesResponse], error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + empty, err := validation.SanitizeTimeRange(q.limits, tenantIDs, &c.Msg.Start, &c.Msg.End) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if empty { + return connect.NewResponse(&querierv1.SeriesResponse{}), nil + } + + if q.isProfileTypeQuery(c.Msg.LabelNames, c.Msg.Matchers) { + level.Debug(q.logger).Log("msg", "listing profile types from metadata as series labels") + return q.queryProfileTypeMetadataLabels(ctx, tenantIDs, c.Msg.Start, c.Msg.End, c.Msg.LabelNames) + } + + labelSelector, err := buildLabelSelectorFromMatchers(c.Msg.Matchers) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + labelNames, err := q.filterLabelNames(ctx, c, c.Msg.LabelNames, c.Msg.Matchers) + if err != nil { + return nil, err + } + + report, err := q.querySingle(ctx, &queryv1.QueryRequest{ + StartTime: c.Msg.Start, + EndTime: c.Msg.End, + LabelSelector: labelSelector, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_SERIES_LABELS, + SeriesLabels: &queryv1.SeriesLabelsQuery{ + LabelNames: labelNames, + }, + }}, + }, nil) + if err != nil { + return nil, err + } + if report == nil { + return connect.NewResponse(&querierv1.SeriesResponse{}), nil + } + + return connect.NewResponse(&querierv1.SeriesResponse{LabelsSet: report.SeriesLabels.SeriesLabels}), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_series_labels_compat.go b/pkg/frontend/readpath/queryfrontend/query_series_labels_compat.go new file mode 100644 index 0000000000..81c9144420 --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_series_labels_compat.go @@ -0,0 +1,126 @@ +package queryfrontend + +import ( + "context" + "errors" + "fmt" + "slices" + "sort" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +var ( + errMissingServiceName = errors.New("service name is missing") + errMissingProfileType = errors.New("profile type is missing") + errInvalidProfileType = errors.New("invalid profile type") +) + +var profileTypeLabels2 = []string{ + phlaremodel.LabelNameProfileType, + phlaremodel.LabelNameServiceName, +} + +var profileTypeLabels5 = []string{ + phlaremodel.LabelNameProfileName, + phlaremodel.LabelNameProfileType, + phlaremodel.LabelNameType, + "pyroscope_app", + phlaremodel.LabelNameServiceName, +} + +func (q *QueryFrontend) isProfileTypeQuery(labels, matchers []string) bool { + if len(matchers) > 0 { + return false + } + var s []string + switch len(labels) { + case 2: + s = profileTypeLabels2 + case 5: + s = profileTypeLabels5 + default: + return false + } + sort.Strings(labels) + return slices.Compare(s, labels) == 0 +} + +func (q *QueryFrontend) queryProfileTypeMetadataLabels( + ctx context.Context, + tenants []string, + startTime int64, + endTime int64, + labels []string, +) (*connect.Response[querierv1.SeriesResponse], error) { + meta, err := q.metadataQueryClient.QueryMetadataLabels(ctx, &metastorev1.QueryMetadataLabelsRequest{ + TenantId: tenants, + StartTime: startTime, + EndTime: endTime, + Query: "{}", + Labels: []string{ + phlaremodel.LabelNameServiceName, + phlaremodel.LabelNameProfileType, + }, + }) + if err != nil { + return nil, err + } + meta.Labels = q.buildProfileTypeMetadataLabels(meta.Labels, labels) + return connect.NewResponse(&querierv1.SeriesResponse{LabelsSet: meta.Labels}), nil +} + +func (q *QueryFrontend) buildProfileTypeMetadataLabels(labels []*typesv1.Labels, names []string) []*typesv1.Labels { + for _, ls := range labels { + if err := sanitizeProfileTypeMetadataLabels(ls, names); err != nil { + level.Warn(q.logger).Log("msg", "malformed label set", "labels", phlaremodel.LabelPairsString(ls.Labels), "err", err) + ls.Labels = nil + } + } + labels = slices.DeleteFunc(labels, func(ls *typesv1.Labels) bool { + return len(ls.Labels) == 0 + }) + slices.SortFunc(labels, func(a, b *typesv1.Labels) int { + return phlaremodel.CompareLabelPairs(a.Labels, b.Labels) + }) + return labels +} + +func sanitizeProfileTypeMetadataLabels(ls *typesv1.Labels, names []string) error { + var serviceName, profileType string + for _, l := range ls.Labels { + switch l.Name { + case phlaremodel.LabelNameServiceName: + serviceName = l.Value + case phlaremodel.LabelNameProfileType: + profileType = l.Value + } + } + if serviceName == "" { + return errMissingServiceName + } + if profileType == "" { + return errMissingProfileType + } + pt, err := phlaremodel.ParseProfileTypeSelector(profileType) + if err != nil { + return fmt.Errorf("%w: %w", errInvalidProfileType, err) + } + if len(names) == 5 { + // Replace the labels with the expected ones. + ls.Labels = append(ls.Labels[:0], []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameProfileType, Value: profileType}, + {Name: phlaremodel.LabelNameServiceName, Value: serviceName}, + {Name: phlaremodel.LabelNameProfileName, Value: pt.Name}, + {Name: phlaremodel.LabelNameType, Value: pt.SampleType}, + }...) + } + sort.Sort(phlaremodel.Labels(ls.Labels)) + return nil +} diff --git a/pkg/frontend/readpath/queryfrontend/query_stubs.go b/pkg/frontend/readpath/queryfrontend/query_stubs.go new file mode 100644 index 0000000000..befc32145c --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/query_stubs.go @@ -0,0 +1,18 @@ +package queryfrontend + +import ( + "context" + + "connectrpc.com/connect" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" +) + +// TODO(kolesnikovae): Decide whether we want to implement those. + +func (q *QueryFrontend) AnalyzeQuery( + context.Context, + *connect.Request[querierv1.AnalyzeQueryRequest], +) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { + return connect.NewResponse(&querierv1.AnalyzeQueryResponse{}), nil +} diff --git a/pkg/frontend/readpath/queryfrontend/symbolizer.go b/pkg/frontend/readpath/queryfrontend/symbolizer.go new file mode 100644 index 0000000000..f518f58dfb --- /dev/null +++ b/pkg/frontend/readpath/queryfrontend/symbolizer.go @@ -0,0 +1,146 @@ +package queryfrontend + +import ( + "context" + "fmt" + "slices" + + "github.com/grafana/dskit/tracing" + "github.com/prometheus/prometheus/model/labels" + "go.opentelemetry.io/otel/attribute" + oteltrace "go.opentelemetry.io/otel/trace" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" +) + +// TODO: Symbolization currently happens in the query frontend as a post-processing step. +// Eventually it should move into the query backends and become part of the query plan, +// so that symbolization can be distributed and executed closer to the data. + +// backendTreeSymbolizer allows to symbolize FunctionName Tree queries, by converting them into pprof queries, symbolize them and converting them back. +type backendTreeSymbolizer struct { + upstream QueryBackend + symbolizer Symbolizer +} + +func (b *backendTreeSymbolizer) Invoke(ctx context.Context, req *queryv1.InvokeRequest) (resp *queryv1.InvokeResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "backendTreeSymbolizer.Invoke") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + span.SetTag("query_count", len(req.Query)) + + modifiedReq := req.CloneVT() + + // check all queries for the ones using tree + for _, q := range modifiedReq.Query { + // If this is a TREE query, convert it to PPROF + if q.QueryType == queryv1.QueryType_QUERY_TREE { + q.QueryType = queryv1.QueryType_QUERY_PPROF + q.Pprof = &queryv1.PprofQuery{ + MaxNodes: q.Tree.GetMaxNodes(), + ProfileIdSelector: q.Tree.GetProfileIdSelector(), + StackTraceSelector: q.Tree.GetStackTraceSelector(), + SpanSelector: q.Tree.GetSpanSelector(), + TraceIdSelector: q.Tree.GetTraceIdSelector(), + } + q.Tree = nil + } + } + + // invoke modified request + resp, err = b.upstream.Invoke(ctx, modifiedReq) + if err != nil { + return nil, err + } + span.SetTag("report_count", len(resp.Reports)) + + if len(req.Query) != len(resp.Reports) { + return nil, fmt.Errorf("query/report count mismatch: %d queries but %d reports", + len(req.Query), len(resp.Reports)) + } + + for i, r := range resp.Reports { + if r.Pprof == nil || r.Pprof.Pprof == nil { + continue + } + + var prof googlev1.Profile + if err := pprof.Unmarshal(r.Pprof.Pprof, &prof); err != nil { + return nil, fmt.Errorf("failed to unmarshal profile: %w", err) + } + + if err := b.symbolizer.SymbolizePprof(ctx, &prof); err != nil { + return nil, fmt.Errorf("failed to symbolize profile: %w", err) + } + + // Convert back to tree if originally a tree + if i < len(req.Query) && req.Query[i].QueryType == queryv1.QueryType_QUERY_TREE { + treeBytes, err := model.TreeFromBackendProfile(&prof, req.Query[i].Tree.GetMaxNodes()) + if err != nil { + return nil, fmt.Errorf("failed to build tree: %w", err) + } + r.Tree = &queryv1.TreeReport{Tree: treeBytes} + r.ReportType = queryv1.ReportType_REPORT_TREE + r.Pprof = nil + } + } + + return resp, nil +} + +// hasUnsymbolizedProfiles checks if a block has unsymbolized profiles +func (q *QueryFrontend) hasUnsymbolizedProfiles(block *metastorev1.BlockMeta) bool { + matcher, err := labels.NewMatcher(labels.MatchEqual, metadata.LabelNameUnsymbolized, "true") + if err != nil { + return false + } + + return len(slices.Collect(metadata.FindDatasets(block, matcher))) > 0 +} + +// shouldSymbolize determines if we should symbolize profiles based on tenant settings +// and the unsymbolized label on the returned blocks. +// +// Limitation: queries without a strict service_name label selector fall back to the +// tenant-wide TSDB index blocks (see QueryMetadata). Those blocks do not carry +// per-dataset unsymbolized=true labels, so this function will return false and +// symbolization will be silently skipped for such queries even when unsymbolized +// profiles exist. +func (q *QueryFrontend) shouldSymbolize(ctx context.Context, tenants []string, blocks []*metastorev1.BlockMeta) bool { + otelSpan := oteltrace.SpanFromContext(ctx) + otelSpan.AddEvent("shouldSymbolize") + + if q.symbolizer == nil { + return false + } + + for _, t := range tenants { + if !q.limits.SymbolizerEnabled(t) { + return false + } + } + + blocksWithUnsymbolized := 0 + for _, block := range blocks { + if q.hasUnsymbolizedProfiles(block) { + blocksWithUnsymbolized++ + } + } + + otelSpan.SetAttributes( + attribute.Int("blocks_with_unsymbolized", blocksWithUnsymbolized), + attribute.Int("total_blocks", len(blocks)), + ) + + return blocksWithUnsymbolized > 0 +} diff --git a/pkg/frontend/readpath/read_path.go b/pkg/frontend/readpath/read_path.go new file mode 100644 index 0000000000..3ef95e1c5d --- /dev/null +++ b/pkg/frontend/readpath/read_path.go @@ -0,0 +1,23 @@ +package readpath + +import ( + "flag" +) + +type Config struct { + EnableQueryBackend bool `yaml:"enable_query_backend" json:"enable_query_backend" category:"advanced" doc:"hidden"` + EnableQueryBackendFrom QueryBackendFrom `yaml:"enable_query_backend_from" json:"enable_query_backend_from" doc:"hidden"` + QueryTreeEnabled bool `yaml:"query_tree_enabled" json:"query_tree_enabled" category:"experimental" doc:"hidden"` +} + +func (o *Config) RegisterFlags(f *flag.FlagSet) { + f.BoolVar(&o.EnableQueryBackend, "enable-query-backend", true, + "This parameter specifies whether the new query backend is enabled.") + o.EnableQueryBackendFrom = QueryBackendFrom{Auto: true} + f.Var(&o.EnableQueryBackendFrom, "enable-query-backend-from", + "This parameter specifies the point in time from which data is queried from the new query backend. "+ + "The value can be an RFC3339 timestamp (2020-10-20T00:00:00Z) or \"auto\" to automatically "+ + "determine the split point from the tenant's oldest profile time in the metastore.") + f.BoolVar(&o.QueryTreeEnabled, "querier.query-tree-enabled", false, + "Use the tree-based query path for SelectMergeProfile. Experimental.") +} diff --git a/pkg/frontend/readpath/read_path_test.go b/pkg/frontend/readpath/read_path_test.go new file mode 100644 index 0000000000..745669d8e5 --- /dev/null +++ b/pkg/frontend/readpath/read_path_test.go @@ -0,0 +1,444 @@ +package readpath + +import ( + "context" + "io" + "math" + "slices" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockquerierv1connect" +) + +type routerTestSuite struct { + suite.Suite + + router *Router + logger log.Logger + registry *prometheus.Registry + + overrides *mockOverrides + resolver *mockSplitTimeResolver + oldFrontend *mockquerierv1connect.MockQuerierServiceClient + newFrontend *mockquerierv1connect.MockQuerierServiceClient + + ctx context.Context +} + +type mockOverrides struct{ mock.Mock } + +func (m *mockOverrides) ReadPathOverrides(tenantID string) Config { + args := m.Called(tenantID) + return args.Get(0).(Config) +} + +type mockSplitTimeResolver struct{ mock.Mock } + +func (m *mockSplitTimeResolver) OldestProfileTime(ctx context.Context, tenantID string) (time.Time, error) { + args := m.Called(ctx, tenantID) + return args.Get(0).(time.Time), args.Error(1) +} + +func (s *routerTestSuite) SetupTest() { + s.logger = log.NewLogfmtLogger(io.Discard) + s.registry = prometheus.NewRegistry() + s.overrides = new(mockOverrides) + s.resolver = new(mockSplitTimeResolver) + s.oldFrontend = new(mockquerierv1connect.MockQuerierServiceClient) + s.newFrontend = new(mockquerierv1connect.MockQuerierServiceClient) + s.router = NewRouter( + s.logger, + s.overrides, + s.resolver, + s.oldFrontend, + s.newFrontend, + ) + s.ctx = tenant.InjectTenantID(context.Background(), "tenant-a") +} + +func (s *routerTestSuite) BeforeTest(_, _ string) {} + +func (s *routerTestSuite) AfterTest(_, _ string) { + s.overrides.AssertExpectations(s.T()) + s.resolver.AssertExpectations(s.T()) + s.oldFrontend.AssertExpectations(s.T()) + s.newFrontend.AssertExpectations(s.T()) +} + +func TestRouterSuite(t *testing.T) { suite.Run(t, new(routerTestSuite)) } + +func (s *routerTestSuite) Test_FrontendOnly() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{EnableQueryBackend: false}) + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + s.oldFrontend.On("LabelNames", mock.Anything, mock.Anything).Return(expected, nil).Once() + + resp, err := s.router.LabelNames(s.ctx, connect.NewRequest(&typesv1.LabelNamesRequest{})) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_NewFrontendOnly() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{EnableQueryBackend: true}) + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + s.newFrontend.On("LabelNames", mock.Anything, mock.Anything).Return(expected, nil).Once() + + resp, err := s.router.LabelNames(s.ctx, connect.NewRequest(&typesv1.LabelNamesRequest{})) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_Combined() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(20, 0)}, + }) + + req1 := connect.NewRequest(&typesv1.LabelNamesRequest{Start: 10, End: 19999}) + resp1 := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + s.oldFrontend.On("LabelNames", mock.Anything, req1).Return(resp1, nil).Once() + + req2 := connect.NewRequest(&typesv1.LabelNamesRequest{Start: 20000, End: math.MaxInt64}) + resp2 := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"baz", "foo", "qux"}}) + s.newFrontend.On("LabelNames", mock.Anything, req2).Return(resp2, nil).Once() + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"bar", "baz", "foo", "qux"}}) + resp, err := s.router.LabelNames(s.ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: 10, + End: math.MaxInt64, + })) + + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_Combined_BeforeSplit() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(20, 0)}, + }) + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + req := connect.NewRequest(&typesv1.LabelNamesRequest{Start: 10, End: 10000}) + s.oldFrontend.On("LabelNames", mock.Anything, req).Return(expected, nil).Once() + + resp, err := s.router.LabelNames(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_Combined_AfterSplit() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(20, 0)}, + }) + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + req := connect.NewRequest(&typesv1.LabelNamesRequest{Start: 30000, End: 40000}) + s.newFrontend.On("LabelNames", mock.Anything, req).Return(expected, nil).Once() + + resp, err := s.router.LabelNames(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_LabelNames() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(5, 0)}, + }) + + req := connect.NewRequest(&typesv1.LabelNamesRequest{Start: 10, End: 10000}) + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"bar", "foo"}}) + s.oldFrontend.On("LabelNames", mock.Anything, mock.Anything).Return(expected, nil).Once() + s.newFrontend.On("LabelNames", mock.Anything, mock.Anything).Return(expected, nil).Once() + + resp, err := s.router.LabelNames(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_LabelValues() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(5, 0)}, + }) + + req := connect.NewRequest(&typesv1.LabelValuesRequest{Start: 10, End: 10000}) + expected := connect.NewResponse(&typesv1.LabelValuesResponse{Names: []string{"bar", "foo"}}) + s.oldFrontend.On("LabelValues", mock.Anything, mock.Anything).Return(expected, nil).Once() + s.newFrontend.On("LabelValues", mock.Anything, mock.Anything).Return(expected, nil).Once() + + resp, err := s.router.LabelValues(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_Series() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(5, 0)}, + }) + + req := connect.NewRequest(&querierv1.SeriesRequest{Start: 10, End: 10000}) + expected := connect.NewResponse(&querierv1.SeriesResponse{ + LabelsSet: []*typesv1.Labels{ + {Labels: []*typesv1.LabelPair{{Name: "foo", Value: "bar"}}}, + }, + }) + + s.oldFrontend.On("Series", mock.Anything, mock.Anything).Return(expected, nil).Once() + s.newFrontend.On("Series", mock.Anything, mock.Anything).Return(expected, nil).Once() + + resp, err := s.router.Series(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_SelectMergeStacktraces_Pprof() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(5, 0)}, + }) + + profileType, err := model.ParseProfileTypeSelector("process_cpu:cpu:nanoseconds:cpu:nanoseconds") + s.Require().NoError(err) + makeProfile := func(value int64) *querierv1.SelectMergeStacktracesResponse { + tree := new(model.FunctionNameTree) + tree.InsertStack(value, "foo") + return &querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{Profile: pprof.FromTree(tree, profileType, 0)}, + } + } + + spanSelector := []string{"0000000000000001"} + matchRequest := mock.MatchedBy(func(req *connect.Request[querierv1.SelectMergeStacktracesRequest]) bool { + return req.Msg.Format == querierv1.ProfileFormat_PROFILE_FORMAT_PPROF && + slices.Equal(req.Msg.SpanSelector, spanSelector) + }) + s.oldFrontend.On("SelectMergeStacktraces", mock.Anything, matchRequest). + Return(connect.NewResponse(makeProfile(1)), nil).Once() + s.newFrontend.On("SelectMergeStacktraces", mock.Anything, matchRequest). + Return(connect.NewResponse(makeProfile(2)), nil).Once() + + resp, err := s.router.SelectMergeStacktraces(s.ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + Start: 10, + End: 10000, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + SpanSelector: spanSelector, + })) + + s.Require().NoError(err) + s.Require().NotNil(resp.Msg.GetPprof().GetProfile()) + s.Require().Len(resp.Msg.Pprof.Profile.Sample, 1) + s.Equal([]int64{3}, resp.Msg.Pprof.Profile.Sample[0].Value) +} + +func (s *routerTestSuite) Test_SelectMergeStacktraces_PprofRejectsMissingPayload() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(5, 0)}, + }) + + s.oldFrontend.On("SelectMergeStacktraces", mock.Anything, mock.Anything). + Return(connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Flamegraph: &querierv1.FlameGraph{}, + }), nil).Once() + s.newFrontend.On("SelectMergeStacktraces", mock.Anything, mock.Anything). + Return(connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{}, + }), nil).Once() + + _, err := s.router.SelectMergeStacktraces(s.ctx, connect.NewRequest(&querierv1.SelectMergeStacktracesRequest{ + Start: 10, + End: 10000, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_PPROF, + })) + + s.Require().ErrorContains(err, "old read path returned no pprof profile") +} + +func (s *routerTestSuite) Test_TimeSeries_Limit() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(5, 0)}, + }) + + one := int64(1) + req := connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 10, End: 10000, Limit: &one}) + expected := connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 3}}}, + }, + }) + + s.oldFrontend.On("SelectSeries", + mock.Anything, connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 10, End: 4999})). + Return(connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 2}}}, + }}), nil).Once() + + s.newFrontend.On("SelectSeries", + mock.Anything, connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 5000, End: 10000})). + Return(connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + }}), nil).Once() + + resp, err := s.router.SelectSeries(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_TimeSeries_Limit_NewFrontendOnly() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + }) + + one := int64(1) + req := connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 10, End: 10000, Limit: &one}) + expected := connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 3}}}, + }, + }) + + s.newFrontend.On("SelectSeries", mock.Anything, req).Return(expected, nil).Once() + resp, err := s.router.SelectSeries(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_TimeSeries_Limit_OldFrontendOnly() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{}) + + one := int64(1) + req := connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 10, End: 10000, Limit: &one}) + expected := connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 3}}}, + }, + }) + + s.oldFrontend.On("SelectSeries", mock.Anything, req).Return(expected, nil).Once() + resp, err := s.router.SelectSeries(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_TimeSeries_NoLimit() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Time: time.Unix(5, 0)}, + }) + + req := connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 10, End: 10000}) + expected := connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 3}}}, + {Labels: model.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 2}}}, + }, + }) + + s.oldFrontend.On("SelectSeries", + mock.Anything, connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 10, End: 4999})). + Return(connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 2}}}, + }}), nil).Once() + + s.newFrontend.On("SelectSeries", + mock.Anything, connect.NewRequest(&querierv1.SelectSeriesRequest{Start: 5000, End: 10000})). + Return(connect.NewResponse(&querierv1.SelectSeriesResponse{ + Series: []*typesv1.Series{ + {Labels: model.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + {Labels: model.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + }}), nil).Once() + + resp, err := s.router.SelectSeries(s.ctx, req) + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_Auto_ResolvesFromMetastore() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Auto: true}, + }) + s.resolver.On("OldestProfileTime", mock.Anything, "tenant-a").Return(time.Unix(20, 0), nil) + + req1 := connect.NewRequest(&typesv1.LabelNamesRequest{Start: 10, End: 19999}) + resp1 := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + s.oldFrontend.On("LabelNames", mock.Anything, req1).Return(resp1, nil).Once() + + req2 := connect.NewRequest(&typesv1.LabelNamesRequest{Start: 20000, End: math.MaxInt64}) + resp2 := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"baz", "foo", "qux"}}) + s.newFrontend.On("LabelNames", mock.Anything, req2).Return(resp2, nil).Once() + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"bar", "baz", "foo", "qux"}}) + resp, err := s.router.LabelNames(s.ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: 10, + End: math.MaxInt64, + })) + + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_Auto_FallbackOnError() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Auto: true}, + }) + s.resolver.On("OldestProfileTime", mock.Anything, "tenant-a"). + Return(time.Time{}, context.DeadlineExceeded) + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + s.oldFrontend.On("LabelNames", mock.Anything, mock.Anything).Return(expected, nil).Once() + + resp, err := s.router.LabelNames(s.ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: 10, + End: math.MaxInt64, + })) + + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} + +func (s *routerTestSuite) Test_Auto_NoV2Data_FallsBackToOldFrontend() { + s.overrides.On("ReadPathOverrides", "tenant-a").Return(Config{ + EnableQueryBackend: true, + EnableQueryBackendFrom: QueryBackendFrom{Auto: true}, + }) + s.resolver.On("OldestProfileTime", mock.Anything, "tenant-a"). + Return(time.Time{}, ErrNoV2Data) + + expected := connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}) + s.oldFrontend.On("LabelNames", mock.Anything, mock.Anything).Return(expected, nil).Once() + + resp, err := s.router.LabelNames(s.ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: 10, + End: math.MaxInt64, + })) + + s.Require().NoError(err) + s.Assert().Equal(expected, resp) +} diff --git a/pkg/frontend/readpath/router.go b/pkg/frontend/readpath/router.go new file mode 100644 index 0000000000..2bd35af51a --- /dev/null +++ b/pkg/frontend/readpath/router.go @@ -0,0 +1,196 @@ +package readpath + +import ( + "context" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + "github.com/prometheus/common/model" + "golang.org/x/sync/errgroup" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +type Overrides interface { + ReadPathOverrides(tenantID string) Config +} + +// SplitTimeResolver resolves the split time for a tenant in "auto" mode. +// It returns the oldest profile time known for the tenant in the v2 storage. +type SplitTimeResolver interface { + OldestProfileTime(ctx context.Context, tenantID string) (time.Time, error) +} + +// Router is a proxy that routes queries to the query frontend. +// +// If the query backend is enabled, it routes queries to the new +// query frontend, otherwise it routes queries to the old query +// frontend. +// +// If the query targets a time range that spans the enablement of +// the new query backend, it splits the query into two parts and +// sends them to the old and new query frontends. +type Router struct { + logger log.Logger + overrides Overrides + resolver SplitTimeResolver + + oldFrontend querierv1connect.QuerierServiceClient + newFrontend querierv1connect.QuerierServiceClient +} + +func NewRouter( + logger log.Logger, + overrides Overrides, + resolver SplitTimeResolver, + oldFrontend querierv1connect.QuerierServiceClient, + newFrontend querierv1connect.QuerierServiceClient, +) *Router { + return &Router{ + logger: logger, + overrides: overrides, + resolver: resolver, + oldFrontend: oldFrontend, + newFrontend: newFrontend, + } +} + +// Query routes a query to the appropriate query frontend. +// Before the call to the frontend is made, the requests +// are sanitized: any of the arguments can be nil, but not +// both. If the query was split, the responses are aggregated. +func Query[Req, Resp any]( + ctx context.Context, + router *Router, + req *connect.Request[Req], + sanitize func(a, b *Req), + aggregate func(a, b *Resp) (*Resp, error), +) (*connect.Response[Resp], error) { + tenantIDs, err := tenant.TenantIDs(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + if len(tenantIDs) != 1 { + level.Warn(router.logger).Log("msg", "ignoring inter-tenant query overrides", "tenants", tenantIDs) + } + tenantID := tenantIDs[0] + + // Verbose but explicit. Note that limits, error handling, etc., + // are delegated to the callee. + overrides := router.overrides.ReadPathOverrides(tenantID) + if !overrides.EnableQueryBackend { + sanitize(req.Msg, nil) + return query[Req, Resp](ctx, router.oldFrontend, req) + } + + splitTime, err := overrides.EnableQueryBackendFrom.SplitTime(func() (time.Time, error) { + return router.resolver.OldestProfileTime(ctx, tenantID) + }) + if err != nil { + level.Warn(router.logger).Log("msg", "failed to resolve split time, falling back to old frontend", "err", err) + sanitize(req.Msg, nil) + return query[Req, Resp](ctx, router.oldFrontend, req) + } + level.Debug(router.logger).Log("msg", "resolved split time for query backend routing", "split_time", splitTime.UTC().Format(time.RFC3339)) + + // Note: the old read path includes both start and end: [start, end]. + // The new read path does not include end: [start, end). + split := model.TimeFromUnixNano(splitTime.UnixNano()) + queryRange := phlaremodel.GetSafeTimeRange(time.Now(), req.Msg) + if split.After(queryRange.End) { + sanitize(req.Msg, nil) + return query[Req, Resp](ctx, router.oldFrontend, req) + } + if split.Before(queryRange.Start) { + sanitize(nil, req.Msg) + return query[Req, Resp](ctx, router.newFrontend, req) + } + + // We need to send requests both to the old and new read paths: + // [start, split](split, end), which translates to + // [start, split-1][split, end). + c, ok := (any)(req.Msg).(interface{ CloneVT() *Req }) + if !ok { + return nil, connect.NewError(connect.CodeUnimplemented, nil) + } + cloned := c.CloneVT() + phlaremodel.SetTimeRange(req.Msg, queryRange.Start, split-1) + phlaremodel.SetTimeRange(cloned, split, queryRange.End) + sanitize(req.Msg, cloned) + + var a, b *connect.Response[Resp] + g, ctx := errgroup.WithContext(ctx) + g.Go(func() error { + var err error + a, err = query[Req, Resp](ctx, router.oldFrontend, req) + return err + }) + g.Go(func() error { + var err error + b, err = query[Req, Resp](ctx, router.newFrontend, connect.NewRequest(cloned)) + return err + }) + if err = g.Wait(); err != nil { + return nil, err + } + + resp, err := aggregate(a.Msg, b.Msg) + if err != nil { + return nil, err + } + + return connect.NewResponse(resp), nil +} + +func query[Req, Resp any]( + ctx context.Context, + svc querierv1connect.QuerierServiceClient, + req *connect.Request[Req], +) (*connect.Response[Resp], error) { + var resp any + var err error + + switch r := (any)(req).(type) { + case *connect.Request[querierv1.ProfileTypesRequest]: + resp, err = svc.ProfileTypes(ctx, r) + case *connect.Request[typesv1.GetProfileStatsRequest]: + resp, err = svc.GetProfileStats(ctx, r) + case *connect.Request[querierv1.AnalyzeQueryRequest]: + resp, err = svc.AnalyzeQuery(ctx, r) + + case *connect.Request[typesv1.LabelNamesRequest]: + resp, err = svc.LabelNames(ctx, r) + case *connect.Request[typesv1.LabelValuesRequest]: + resp, err = svc.LabelValues(ctx, r) + case *connect.Request[querierv1.SeriesRequest]: + resp, err = svc.Series(ctx, r) + + case *connect.Request[querierv1.SelectMergeStacktracesRequest]: + resp, err = svc.SelectMergeStacktraces(ctx, r) + case *connect.Request[querierv1.SelectMergeSpanProfileRequest]: + resp, err = svc.SelectMergeSpanProfile(ctx, r) //nolint:staticcheck // Required querier.v1 compatibility routing. + case *connect.Request[querierv1.SelectMergeProfileRequest]: + resp, err = svc.SelectMergeProfile(ctx, r) //nolint:staticcheck // Required querier.v1 compatibility routing. + case *connect.Request[querierv1.SelectSeriesRequest]: + resp, err = svc.SelectSeries(ctx, r) + case *connect.Request[querierv1.SelectHeatmapRequest]: + resp, err = svc.SelectHeatmap(ctx, r) + case *connect.Request[querierv1.DiffRequest]: + resp, err = svc.Diff(ctx, r) + + default: + return nil, connect.NewError(connect.CodeUnimplemented, nil) + } + + if err != nil || resp == nil { + return nil, err + } + + return resp.(*connect.Response[Resp]), nil +} diff --git a/pkg/frontend/readpath/split_time_resolver.go b/pkg/frontend/readpath/split_time_resolver.go new file mode 100644 index 0000000000..560191aeef --- /dev/null +++ b/pkg/frontend/readpath/split_time_resolver.go @@ -0,0 +1,84 @@ +package readpath + +import ( + "context" + "errors" + "sync" + "time" + + "google.golang.org/grpc" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" +) + +// TenantServiceClient is the subset of the metastore client needed to resolve +// the oldest profile time for a tenant. +type TenantServiceClient interface { + GetTenant(ctx context.Context, in *metastorev1.GetTenantRequest, opts ...grpc.CallOption) (*metastorev1.GetTenantResponse, error) +} + +var ErrNoV2Data = errors.New("no v2 data ingested for tenant") + +// MetastoreSplitTimeResolver resolves the split time for "auto" mode by +// querying the metastore for each tenant's oldest profile time. Results +// are cached per tenant to avoid calling the metastore on every query. +type MetastoreSplitTimeResolver struct { + client TenantServiceClient + ttl time.Duration + + mu sync.RWMutex + cache map[string]cachedSplitTime +} + +type cachedSplitTime struct { + time time.Time + expiresAt time.Time + noData bool +} + +func NewMetastoreSplitTimeResolver(client TenantServiceClient, ttl time.Duration) *MetastoreSplitTimeResolver { + return &MetastoreSplitTimeResolver{ + client: client, + ttl: ttl, + cache: make(map[string]cachedSplitTime), + } +} + +func (r *MetastoreSplitTimeResolver) OldestProfileTime(ctx context.Context, tenantID string) (time.Time, error) { + now := time.Now() + r.mu.RLock() + if cached, ok := r.cache[tenantID]; ok && now.Before(cached.expiresAt) { + r.mu.RUnlock() + if cached.noData { + return time.Time{}, ErrNoV2Data + } + return cached.time, nil + } + r.mu.RUnlock() + + resp, err := r.client.GetTenant(ctx, &metastorev1.GetTenantRequest{TenantId: tenantID}) + if err != nil { + return time.Time{}, err + } + stats := resp.GetStats() + if stats == nil || !stats.DataIngested { + r.mu.Lock() + r.cache[tenantID] = cachedSplitTime{ + expiresAt: now.Add(r.ttl), + noData: true, + } + r.mu.Unlock() + return time.Time{}, ErrNoV2Data + } + + t := time.UnixMilli(stats.OldestProfileTime) + + r.mu.Lock() + r.cache[tenantID] = cachedSplitTime{ + time: t, + expiresAt: now.Add(r.ttl), + } + r.mu.Unlock() + + return t, nil +} diff --git a/pkg/frontend/split_by_interval.go b/pkg/frontend/split_by_interval.go index bc0c5ca28f..1cc14e90c4 100644 --- a/pkg/frontend/split_by_interval.go +++ b/pkg/frontend/split_by_interval.go @@ -2,8 +2,6 @@ package frontend import ( "time" - - "github.com/grafana/pyroscope/pkg/util/math" ) // TimeIntervalIterator splits a time range into non-overlapping sub-ranges, @@ -50,7 +48,7 @@ func NewTimeIntervalIterator(startTime, endTime time.Time, interval time.Duratio for _, option := range options { option(i) } - i.interval = math.Max(i.interval, i.alignment) + i.interval = max(i.interval, i.alignment) return i } diff --git a/pkg/frontend/split_by_interval_test.go b/pkg/frontend/split_by_interval_test.go index b25cf71db9..6390bd0513 100644 --- a/pkg/frontend/split_by_interval_test.go +++ b/pkg/frontend/split_by_interval_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/iter" ) func Test_TimeIntervalIterator(t *testing.T) { diff --git a/pkg/querier/vcs/client/client.go b/pkg/frontend/vcs/client/client.go similarity index 100% rename from pkg/querier/vcs/client/client.go rename to pkg/frontend/vcs/client/client.go diff --git a/pkg/frontend/vcs/client/github.go b/pkg/frontend/vcs/client/github.go new file mode 100644 index 0000000000..cbac51bfa6 --- /dev/null +++ b/pkg/frontend/vcs/client/github.go @@ -0,0 +1,146 @@ +package client + +import ( + "context" + "errors" + "fmt" + "net/http" + "time" + + "connectrpc.com/connect" + "github.com/google/go-github/v81/github" + "github.com/grafana/dskit/tracing" + "golang.org/x/oauth2" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" +) + +// GithubClient returns a github client. +func GithubClient(ctx context.Context, token *oauth2.Token, client *http.Client) (*githubClient, error) { + return &githubClient{ + repoService: github.NewClient(client).WithAuthToken(token.AccessToken).Repositories, + }, nil +} + +type repositoryService interface { + GetCommit(ctx context.Context, owner, repo, ref string, opts *github.ListOptions) (*github.RepositoryCommit, *github.Response, error) + GetContents(ctx context.Context, owner, repo, path string, opts *github.RepositoryContentGetOptions) (*github.RepositoryContent, []*github.RepositoryContent, *github.Response, error) +} + +type githubClient struct { + repoService repositoryService +} + +func (gh *githubClient) GetCommit(ctx context.Context, owner, repo, ref string) (*vcsv1.CommitInfo, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "githubClient.GetCommit") + defer sp.Finish() + sp.SetTag("owner", owner) + sp.SetTag("repo", repo) + sp.SetTag("ref", ref) + + commit, _, err := gh.repoService.GetCommit(ctx, owner, repo, ref, nil) + if err != nil { + var githubErr *github.ErrorResponse + if errors.As(err, &githubErr) { + code := connectgrpc.HTTPToCode(int32(githubErr.Response.StatusCode)) + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + sp.SetTag("http.status_code", githubErr.Response.StatusCode) + return nil, connect.NewError(code, err) + } + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + return nil, err + } + // error if message is nil + if commit.Commit == nil || commit.Commit.Message == nil { + err := connect.NewError(connect.CodeInternal, errors.New("commit contains no message")) + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + return nil, err + } + if commit.Commit == nil || commit.Commit.Author == nil || commit.Commit.Author.Date == nil { + err := connect.NewError(connect.CodeInternal, errors.New("commit contains no date")) + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + return nil, err + } + + commitInfo := &vcsv1.CommitInfo{ + Sha: toString(commit.SHA), + Message: toString(commit.Commit.Message), + Date: commit.Commit.Author.Date.Format(time.RFC3339), + } + + // add author if it exists + if commit.Author != nil && commit.Author.Login != nil && commit.Author.AvatarURL != nil { + commitInfo.Author = &vcsv1.CommitAuthor{ + Login: toString(commit.Author.Login), + AvatarURL: toString(commit.Author.AvatarURL), + } + } + + return commitInfo, nil +} + +func (gh *githubClient) GetFile(ctx context.Context, req FileRequest) (File, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "githubClient.GetFile") + defer sp.Finish() + sp.SetTag("owner", req.Owner) + sp.SetTag("repo", req.Repo) + sp.SetTag("path", req.Path) + sp.SetTag("ref", req.Ref) + + // We could abstract away git provider using git protocol + // git clone https://x-access-token:@github.com/owner/repo.git + // For now we use the github client. + + file, _, _, err := gh.repoService.GetContents(ctx, req.Owner, req.Repo, req.Path, &github.RepositoryContentGetOptions{Ref: req.Ref}) + if err != nil { + var githubErr *github.ErrorResponse + if errors.As(err, &githubErr) && githubErr.Response.StatusCode == http.StatusNotFound { + err := fmt.Errorf("%w: %s", ErrNotFound, err) + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + sp.SetTag("http.status_code", http.StatusNotFound) + return File{}, err + } + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + return File{}, err + } + + if file == nil { + sp.SetTag("error", true) + sp.SetTag("error.message", ErrNotFound.Error()) + return File{}, ErrNotFound + } + + // We only support files retrieval. + if file.Type != nil && *file.Type != "file" { + err := connect.NewError(connect.CodeInvalidArgument, errors.New("path is not a file")) + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + return File{}, err + } + + content, err := file.GetContent() + if err != nil { + sp.SetTag("error", true) + sp.SetTag("error.message", err.Error()) + return File{}, err + } + + return File{ + Content: content, + URL: toString(file.HTMLURL), + }, nil +} + +func toString(s *string) string { + if s == nil { + return "" + } + return *s +} diff --git a/pkg/frontend/vcs/client/github_test.go b/pkg/frontend/vcs/client/github_test.go new file mode 100644 index 0000000000..0930922ff1 --- /dev/null +++ b/pkg/frontend/vcs/client/github_test.go @@ -0,0 +1,109 @@ +package client + +import ( + "context" + "errors" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/google/go-github/v81/github" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + mockclient "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockclient" +) + +func TestGetCommit(t *testing.T) { + tests := []struct { + name string + mockCommit *github.RepositoryCommit + expected *vcsv1.CommitInfo + expectedError error + }{ + { + mockCommit: &github.RepositoryCommit{ + SHA: github.Ptr("abc123"), + Commit: &github.Commit{ + Message: github.Ptr("test commit message"), + Author: &github.CommitAuthor{ + Date: &github.Timestamp{Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + }, + Author: &github.User{ + Login: github.Ptr("test-user"), + AvatarURL: github.Ptr("https://example.com/avatar.png"), + }, + }, + expected: &vcsv1.CommitInfo{ + Sha: "abc123", + Message: "test commit message", + Author: &vcsv1.CommitAuthor{ + Login: "test-user", + AvatarURL: "https://example.com/avatar.png", + }, + Date: "2024-01-01T00:00:00Z", + }, + }, + { + name: "example without author", + mockCommit: &github.RepositoryCommit{ + SHA: github.Ptr("abc123"), + Commit: &github.Commit{ + Message: github.Ptr("test commit message"), + Author: &github.CommitAuthor{ + Date: &github.Timestamp{Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + }, + }, + expected: &vcsv1.CommitInfo{ + Sha: "abc123", + Message: "test commit message", + Date: "2024-01-01T00:00:00Z", + }, + }, + { + name: "fail without commit message", + mockCommit: &github.RepositoryCommit{ + Commit: &github.Commit{ + Author: &github.CommitAuthor{ + Date: &github.Timestamp{Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + }, + }, + expectedError: connect.NewError(connect.CodeInternal, errors.New("commit contains no message")), + }, + { + name: "fail without commit date message", + mockCommit: &github.RepositoryCommit{ + Commit: &github.Commit{ + Message: github.Ptr("test commit message"), + }, + }, + expectedError: connect.NewError(connect.CodeInternal, errors.New("commit contains no date")), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockRepoService := &mockclient.MockrepositoryService{} + // Create a mock GitHub client + mockClient := &githubClient{ + repoService: mockRepoService, + } + mockRepoService.EXPECT().GetCommit(mock.Anything, "my-owner", "my-repo", "my-ref", mock.Anything).Return(tt.mockCommit, nil, nil) + result, err := mockClient.GetCommit(context.Background(), "my-owner", "my-repo", "my-ref") + + if tt.expectedError != nil { + require.Error(t, err) + assert.ErrorContains(t, err, tt.expectedError.Error()) + return + } + + require.NoError(t, err) + assert.Equal(t, tt.expected, result) + }) + } +} diff --git a/pkg/frontend/vcs/client/metrics.go b/pkg/frontend/vcs/client/metrics.go new file mode 100644 index 0000000000..b51b53b17e --- /dev/null +++ b/pkg/frontend/vcs/client/metrics.go @@ -0,0 +1,87 @@ +package client + +import ( + "fmt" + "net/http" + "regexp" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +var ( + githubRouteMatchers = map[string]*regexp.Regexp{ + // Get repository contents. + // https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-repository-content + "/repos/{owner}/{repo}/contents/{path}": regexp.MustCompile(`^\/repos\/\S+\/\S+\/contents\/\S+$`), + + // Get a commit. + // https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#get-a-commit + "/repos/{owner}/{repo}/commits/{ref}": regexp.MustCompile(`^\/repos\/\S+\/\S+\/commits\/\S+$`), + + // Refresh auth token. + // https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens#refreshing-a-user-access-token-with-a-refresh-token + "/login/oauth/access_token": regexp.MustCompile(`^\/login\/oauth\/access_token$`), + } +) + +func InstrumentedHTTPClient(logger log.Logger, reg prometheus.Registerer) *http.Client { + apiDuration := util.RegisterOrGet(reg, prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "vcs_github_request_duration", + Help: "Duration of GitHub API requests in seconds", + Buckets: prometheus.ExponentialBucketsRange(0.1, 10, 8), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, + []string{"method", "route", "status_code"}, + )) + + defaultClient := &http.Client{ + Timeout: 10 * time.Second, + Transport: http.DefaultTransport, + } + client := httputil.InstrumentedHTTPClient(defaultClient, withGitHubMetricsTransport(logger, apiDuration)) + return client +} + +// withGitHubMetricsTransport wraps a transport with a client to track GitHub +// API usage. +func withGitHubMetricsTransport(logger log.Logger, hv *prometheus.HistogramVec) httputil.RoundTripperInstrumentFunc { + return func(next http.RoundTripper) http.RoundTripper { + return httputil.RoundTripperFunc(func(req *http.Request) (*http.Response, error) { + route := matchGitHubAPIRoute(req.URL.Path) + statusCode := "" + start := time.Now() + + res, err := next.RoundTrip(req) + if err == nil { + statusCode = fmt.Sprintf("%d", res.StatusCode) + } + + if route == "unknown_route" { + level.Warn(logger).Log("path", req.URL.Path, "msg", "unknown GitHub API route") + } + hv.WithLabelValues(req.Method, route, statusCode).Observe(time.Since(start).Seconds()) + + return res, err + }) + } +} + +func matchGitHubAPIRoute(path string) string { + for route, regex := range githubRouteMatchers { + if regex.MatchString(path) { + return route + } + } + + return "unknown_route" +} diff --git a/pkg/querier/vcs/client/metrics_test.go b/pkg/frontend/vcs/client/metrics_test.go similarity index 100% rename from pkg/querier/vcs/client/metrics_test.go rename to pkg/frontend/vcs/client/metrics_test.go diff --git a/pkg/frontend/vcs/commit.go b/pkg/frontend/vcs/commit.go new file mode 100644 index 0000000000..ce61d6732f --- /dev/null +++ b/pkg/frontend/vcs/commit.go @@ -0,0 +1,104 @@ +package vcs + +import ( + "context" + "fmt" + + "github.com/grafana/dskit/tracing" + "golang.org/x/sync/errgroup" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" +) + +const maxConcurrentRequests = 10 + +type gitHubCommitGetter interface { + GetCommit(context.Context, string, string, string) (*vcsv1.CommitInfo, error) +} + +// getCommits fetches multiple commits in parallel for a given repository. +// It attempts to retrieve commits for all provided refs and returns: +// 1. Successfully fetched commits +// 2. Errors for failed fetches +// 3. An overall error if no commits were successfully fetched +// This function provides partial success behavior, returning any commits +// that were successfully fetched along with errors for those that failed. +func getCommits(ctx context.Context, client gitHubCommitGetter, owner, repo string, refs []string) ([]*vcsv1.CommitInfo, []error, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "getCommits") + defer sp.Finish() + sp.SetTag("owner", owner) + sp.SetTag("repo", repo) + sp.SetTag("ref_count", len(refs)) + + type result struct { + commit *vcsv1.CommitInfo + err error + } + + resultsCh := make(chan result, maxConcurrentRequests) + g, ctx := errgroup.WithContext(ctx) + g.SetLimit(maxConcurrentRequests) + + for _, ref := range refs { + ref := ref + g.Go(func() error { + commit, err := tryGetCommit(ctx, client, owner, repo, ref) + select { + case resultsCh <- result{commit, err}: + case <-ctx.Done(): + return ctx.Err() + } + return nil + }) + } + + go func() { + _ = g.Wait() // ignore errors since they're handled in the `resultsCh`. + close(resultsCh) + }() + + var validCommits []*vcsv1.CommitInfo + var failedFetches []error + for r := range resultsCh { + if r.err != nil { + failedFetches = append(failedFetches, r.err) + } + if r.commit != nil { + validCommits = append(validCommits, r.commit) + } + } + + if len(validCommits) == 0 && len(failedFetches) > 0 { + return nil, failedFetches, fmt.Errorf("failed to fetch any commits") + } + + return validCommits, failedFetches, nil +} + +// tryGetCommit attempts to retrieve a commit using different ref formats (commit hash, branch, tag). +// It tries each format in order and returns the first successful result. +func tryGetCommit(ctx context.Context, client gitHubCommitGetter, owner, repo, ref string) (*vcsv1.CommitInfo, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "tryGetCommit") + defer sp.Finish() + sp.SetTag("owner", owner) + sp.SetTag("repo", repo) + sp.SetTag("ref", ref) + + refFormats := []string{ + ref, // Try as a commit hash + "heads/" + ref, // Try as a branch + "tags/" + ref, // Try as a tag + } + + var lastErr error + for _, format := range refFormats { + commit, err := client.GetCommit(ctx, owner, repo, format) + if err == nil { + return commit, nil + } + + lastErr = err + } + + return nil, lastErr +} diff --git a/pkg/frontend/vcs/commit_test.go b/pkg/frontend/vcs/commit_test.go new file mode 100644 index 0000000000..4fc57f8b05 --- /dev/null +++ b/pkg/frontend/vcs/commit_test.go @@ -0,0 +1,167 @@ +package vcs + +import ( + "context" + "errors" + "net/http" + "testing" + + "github.com/google/go-github/v81/github" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" +) + +type gitHubCommitGetterMock struct { + mock.Mock +} + +func (m *gitHubCommitGetterMock) GetCommit(ctx context.Context, owner, repo, ref string) (*vcsv1.CommitInfo, error) { + args := m.Called(ctx, owner, repo, ref) + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(*vcsv1.CommitInfo), args.Error(1) +} + +func TestGetCommits(t *testing.T) { + tests := []struct { + name string + refs []string + mockSetup func(*gitHubCommitGetterMock) + expectedCommits int + expectedErrors int + expectError bool + }{ + { + name: "All commits succeed", + refs: []string{"ref1", "ref2"}, + mockSetup: func(m *gitHubCommitGetterMock) { + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&vcsv1.CommitInfo{}, nil) + }, + expectedCommits: 2, + expectedErrors: 0, + expectError: false, + }, + { + name: "Partial fetch commits success", + refs: []string{"ref1", "ref2", "ref3"}, + mockSetup: func(m *gitHubCommitGetterMock) { + // ref1 succeeds on first try + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "ref1").Return(&vcsv1.CommitInfo{}, nil) + // ref2 fails on first try, succeeds with "heads/" prefix + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "ref2").Return(nil, errors.New("not found")) + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "heads/ref2").Return(&vcsv1.CommitInfo{}, nil) + // ref3 fails on all attempts + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "ref3").Return(nil, errors.New("not found")) + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "heads/ref3").Return(nil, errors.New("not found")) + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "tags/ref3").Return(nil, errors.New("not found")) + }, + expectedCommits: 2, + expectedErrors: 1, + expectError: false, + }, + { + name: "All commits fail to fetch", + refs: []string{"ref1", "ref2"}, + mockSetup: func(m *gitHubCommitGetterMock) { + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("not found")) + }, + expectedCommits: 0, + expectedErrors: 2, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockGetter := new(gitHubCommitGetterMock) + tt.mockSetup(mockGetter) + + commits, failedFetches, err := getCommits(context.Background(), mockGetter, "owner", "repo", tt.refs) + + assert.Len(t, commits, tt.expectedCommits) + assert.Len(t, failedFetches, tt.expectedErrors) + + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + + mockGetter.AssertExpectations(t) + }) + } +} + +func TestTryGetCommit(t *testing.T) { + tests := []struct { + name string + setupMock func(*gitHubCommitGetterMock) + ref string + wantErr bool + }{ + { + name: "Direct commit hash", + setupMock: func(m *gitHubCommitGetterMock) { + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&vcsv1.CommitInfo{}, nil) + }, + ref: "abcdef", + wantErr: false, + }, + { + name: "Branch reference with heads prefix", + setupMock: func(m *gitHubCommitGetterMock) { + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "main").Return(nil, errors.New("not found")) + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "heads/main").Return(&vcsv1.CommitInfo{}, nil) + }, + ref: "main", + wantErr: false, + }, + { + name: "Tag reference with tags prefix", + setupMock: func(m *gitHubCommitGetterMock) { + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(nil, assert.AnError).Times(2) + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, "tags/v1").Return(&vcsv1.CommitInfo{}, nil).Times(1) + }, + ref: "v1", + wantErr: false, + }, + { + name: "GitHub API returns not found error", + setupMock: func(m *gitHubCommitGetterMock) { + notFoundErr := &github.ErrorResponse{ + Response: &http.Response{StatusCode: http.StatusNotFound}, + } + m.On("GetCommit", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(nil, notFoundErr).Times(3) + }, + ref: "nonexistent", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockGetter := new(gitHubCommitGetterMock) + tt.setupMock(mockGetter) + + commit, err := tryGetCommit(context.Background(), mockGetter, "owner", "repo", tt.ref) + + if tt.wantErr { + assert.Error(t, err) + var githubErr *github.ErrorResponse + assert.True(t, errors.As(err, &githubErr), "Expected a GitHub error") + assert.Nil(t, commit) + } else { + assert.NoError(t, err) + assert.NotNil(t, commit) + } + + mockGetter.AssertExpectations(t) + }) + } +} diff --git a/pkg/frontend/vcs/config/config.go b/pkg/frontend/vcs/config/config.go new file mode 100644 index 0000000000..ab352235cd --- /dev/null +++ b/pkg/frontend/vcs/config/config.go @@ -0,0 +1,214 @@ +package config + +import ( + "errors" + "fmt" + "slices" + "strings" + + "go.yaml.in/yaml/v3" +) + +type Language string + +const ( + PyroscopeConfigPath = ".pyroscope.yaml" + + LanguageUnknown = Language("") + LanguageGo = Language("go") + LanguageJava = Language("java") + LanguagePython = Language("python") + LanguageJavaScript = Language("javascript") +) + +type Version string + +const ( + VersionUnknown = Version("") + VersionV1 = Version("v1") +) + +var validLanguages = []Language{ + LanguageGo, + LanguageJava, + LanguagePython, + LanguageJavaScript, +} + +// PyroscopeConfig represents the structure of .pyroscope.yaml configuration file +type PyroscopeConfig struct { + Version Version + SourceCode SourceCodeConfig `yaml:"source_code"` +} + +// SourceCodeConfig contains source code mapping configuration +type SourceCodeConfig struct { + Mappings []MappingConfig `yaml:"mappings"` +} + +// MappingConfig represents a single source code path mapping +type MappingConfig struct { + Path []Match `yaml:"path"` + FunctionName []Match `yaml:"function_name"` + Language string `yaml:"language"` + + Source Source `yaml:"source"` +} + +// Match represents how mappings a single source code path mapping +type Match struct { + Prefix string `yaml:"prefix"` +} + +// Source represents how mappings retrieve the source +type Source struct { + Local *LocalMappingConfig `yaml:"local,omitempty"` + GitHub *GitHubMappingConfig `yaml:"github,omitempty"` +} + +// LocalMappingConfig contains configuration for local path mappings +type LocalMappingConfig struct { + Path string `yaml:"path"` +} + +// GitHubMappingConfig contains configuration for GitHub repository mappings +type GitHubMappingConfig struct { + Owner string `yaml:"owner"` + Repo string `yaml:"repo"` + Ref string `yaml:"ref"` + Path string `yaml:"path"` +} + +// ParsePyroscopeConfig parses a configuration from bytes +func ParsePyroscopeConfig(data []byte) (*PyroscopeConfig, error) { + var config PyroscopeConfig + if err := yaml.Unmarshal(data, &config); err != nil { + return nil, fmt.Errorf("failed to parse pyroscope config: %w", err) + } + + // Validate the configuration + if err := config.Validate(); err != nil { + return nil, fmt.Errorf("invalid pyroscope config: %w", err) + } + + return &config, nil +} + +// Validate checks if the configuration is valid +func (c *PyroscopeConfig) Validate() error { + if c.Version == VersionUnknown { + c.Version = VersionV1 + } + + if c.Version != VersionV1 { + return fmt.Errorf("invalid version '%s', supported versions are '%s'", c.Version, VersionV1) + } + + var errs []error + for i, mapping := range c.SourceCode.Mappings { + if err := mapping.Validate(); err != nil { + errs = append(errs, fmt.Errorf("mapping[%d]: %w", i, err)) + } + } + return errors.Join(errs...) +} + +// Validate checks if a mapping configuration is valid +func (m *MappingConfig) Validate() error { + var errs []error + + if len(m.Path) == 0 && len(m.FunctionName) == 0 { + errs = append(errs, fmt.Errorf("at least one path or a function_name match is required")) + } + + if !slices.Contains(validLanguages, Language(m.Language)) { + errs = append(errs, fmt.Errorf("language '%s' unsupported, valid languages are %v", m.Language, validLanguages)) + } + + if err := m.Source.Validate(); err != nil { + errs = append(errs, err) + } + + return errors.Join(errs...) +} + +// Validate checks if a source configuration is valid +func (m *Source) Validate() error { + var ( + instances int + errs []error + ) + + if m.GitHub != nil { + instances++ + if err := m.GitHub.Validate(); err != nil { + errs = append(errs, err) + } + } + if m.Local != nil { + instances++ + if err := m.Local.Validate(); err != nil { + errs = append(errs, err) + } + } + + if instances == 0 { + errs = append(errs, errors.New("no source type supplied, you need to supply exactly one source type")) + } else if instances != 1 { + errs = append(errs, errors.New("more than one source type supplied, you need to supply exactly one source type")) + } + + return errors.Join(errs...) +} + +func (m *GitHubMappingConfig) Validate() error { + return nil +} + +func (m *LocalMappingConfig) Validate() error { + return nil +} + +type FileSpec struct { + Path string + FunctionName string +} + +// FindMapping finds a mapping configuration that matches the given FileSpec +// Returns nil if no matching mapping is found +func (c *PyroscopeConfig) FindMapping(file FileSpec) *MappingConfig { + if c == nil { + return nil + } + + // Find the longest matching prefix + var bestMatch *MappingConfig + var bestMatchLen = -1 + for _, m := range c.SourceCode.Mappings { + if result := m.Match(file); result > bestMatchLen { + bestMatch = &m + bestMatchLen = result + } + } + return bestMatch +} + +// Returns -1 if no match, otherwise the number of characters that matched +func (m *MappingConfig) Match(file FileSpec) int { + result := -1 + for _, fun := range m.FunctionName { + if strings.HasPrefix(file.FunctionName, fun.Prefix) { + if len(fun.Prefix) > result { + result = len(fun.Prefix) + } + } + } + for _, path := range m.Path { + if strings.HasPrefix(file.Path, path.Prefix) { + if len(path.Prefix) > result { + result = len(path.Prefix) + } + } + } + return result +} diff --git a/pkg/frontend/vcs/config/config_test.go b/pkg/frontend/vcs/config/config_test.go new file mode 100644 index 0000000000..559cc9348b --- /dev/null +++ b/pkg/frontend/vcs/config/config_test.go @@ -0,0 +1,337 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParsePyroscopeConfig(t *testing.T) { + t.Run("valid go config", func(t *testing.T) { + yaml := `source_code: + mappings: + - language: go + path: + - prefix: GOROOT + source: + github: + owner: golang + repo: go + ref: go1.24.8 + path: src +` + config, err := ParsePyroscopeConfig([]byte(yaml)) + require.NoError(t, err) + require.NotNil(t, config) + + require.Len(t, config.SourceCode.Mappings, 1) + + mapping := config.SourceCode.Mappings[0] + assert.Equal(t, "go", mapping.Language) + require.Len(t, mapping.Path, 1) + assert.Equal(t, "GOROOT", mapping.Path[0].Prefix) + require.NotNil(t, mapping.Source.GitHub) + assert.Equal(t, "golang", mapping.Source.GitHub.Owner) + assert.Equal(t, "go", mapping.Source.GitHub.Repo) + assert.Equal(t, "go1.24.8", mapping.Source.GitHub.Ref) + assert.Equal(t, "src", mapping.Source.GitHub.Path) + }) + + t.Run("valid java config with multiple mappings", func(t *testing.T) { + yaml := `source_code: + mappings: + - language: java + path: + - prefix: org/example/rideshare + source: + local: + path: src/main/java/org/example/rideshare + - language: java + path: + - prefix: java + source: + github: + owner: openjdk + repo: jdk + ref: jdk-17+0 + path: src/java.base/share/classes/java + - language: java + path: + - prefix: org/springframework/http + source: + github: + owner: spring-projects + repo: spring-framework + ref: v5.3.20 + path: spring-web/src/main/java/org/springframework/http +` + config, err := ParsePyroscopeConfig([]byte(yaml)) + require.NoError(t, err) + require.NotNil(t, config) + + require.Len(t, config.SourceCode.Mappings, 3) + + // Check first mapping (local) + mapping1 := config.SourceCode.Mappings[0] + assert.Equal(t, "java", mapping1.Language) + require.Len(t, mapping1.Path, 1) + assert.Equal(t, "org/example/rideshare", mapping1.Path[0].Prefix) + require.NotNil(t, mapping1.Source.Local) + assert.Equal(t, "src/main/java/org/example/rideshare", mapping1.Source.Local.Path) + + // Check second mapping (github) + mapping2 := config.SourceCode.Mappings[1] + assert.Equal(t, "java", mapping2.Language) + require.Len(t, mapping2.Path, 1) + assert.Equal(t, "java", mapping2.Path[0].Prefix) + require.NotNil(t, mapping2.Source.GitHub) + assert.Equal(t, "openjdk", mapping2.Source.GitHub.Owner) + + // Check third mapping (github) + mapping3 := config.SourceCode.Mappings[2] + assert.Equal(t, "java", mapping3.Language) + require.Len(t, mapping3.Path, 1) + assert.Equal(t, "org/springframework/http", mapping3.Path[0].Prefix) + require.NotNil(t, mapping3.Source.GitHub) + assert.Equal(t, "spring-projects", mapping3.Source.GitHub.Owner) + }) + + t.Run("valid javascript config", func(t *testing.T) { + yaml := `source_code: + mappings: + - language: javascript + path: + - prefix: /usr/src/app + source: + local: + path: src/paymentservice +` + config, err := ParsePyroscopeConfig([]byte(yaml)) + require.NoError(t, err) + require.NotNil(t, config) + + require.Len(t, config.SourceCode.Mappings, 1) + + mapping := config.SourceCode.Mappings[0] + assert.Equal(t, "javascript", mapping.Language) + require.Len(t, mapping.Path, 1) + assert.Equal(t, "/usr/src/app", mapping.Path[0].Prefix) + require.NotNil(t, mapping.Source.Local) + assert.Equal(t, "src/paymentservice", mapping.Source.Local.Path) + }) + + t.Run("invalid - missing language", func(t *testing.T) { + yaml := `source_code: + mappings: + - path: + - prefix: GOROOT + source: + github: + owner: golang + repo: go + ref: go1.24.8 + path: src +` + _, err := ParsePyroscopeConfig([]byte(yaml)) + require.Error(t, err) + assert.Contains(t, err.Error(), "language") + }) + + t.Run("invalid - missing source config", func(t *testing.T) { + yaml := `source_code: + mappings: + - language: go + path: + - prefix: GOROOT +` + _, err := ParsePyroscopeConfig([]byte(yaml)) + require.Error(t, err) + assert.Contains(t, err.Error(), "no source type supplied") + }) + + t.Run("invalid - missing path and function_name", func(t *testing.T) { + yaml := `source_code: + mappings: + - language: java + source: + local: + path: src/main/java +` + _, err := ParsePyroscopeConfig([]byte(yaml)) + require.Error(t, err) + assert.Contains(t, err.Error(), "at least one path or a function_name match is required") + }) + + t.Run("invalid - unsupported language", func(t *testing.T) { + yaml := `source_code: + mappings: + - language: rust + path: + - prefix: src + source: + github: + owner: rust-lang + repo: rust + ref: 1.75.0 + path: src +` + _, err := ParsePyroscopeConfig([]byte(yaml)) + require.Error(t, err) + assert.Contains(t, err.Error(), "unsupported") + }) + + t.Run("invalid yaml syntax", func(t *testing.T) { + yaml := `source_code: + mappings: + - language: go + path: + - prefix: GOROOT + source: + github: + owner: golang + repo: go + ref: go1.24.8 + path: src + github: + owner: duplicate +` + _, err := ParsePyroscopeConfig([]byte(yaml)) + require.Error(t, err) + }) + + t.Run("wrong version", func(t *testing.T) { + yaml := `version: v1alpha1 +` + _, err := ParsePyroscopeConfig([]byte(yaml)) + require.Error(t, err) + }) +} + +func TestFindMapping(t *testing.T) { + config := &PyroscopeConfig{ + SourceCode: SourceCodeConfig{ + Mappings: []MappingConfig{ + { + Language: "java", + Path: []Match{ + {Prefix: "org/example/rideshare"}, + }, + Source: Source{ + Local: &LocalMappingConfig{ + Path: "src/main/java/org/example/rideshare", + }, + }, + }, + { + Language: "java", + Path: []Match{ + {Prefix: "java"}, + }, + Source: Source{ + GitHub: &GitHubMappingConfig{ + Owner: "openjdk", + Repo: "jdk", + Ref: "jdk-17+0", + Path: "src/java.base/share/classes/java", + }, + }, + }, + { + Language: "java", + Path: []Match{ + {Prefix: "org/springframework/http"}, + }, + Source: Source{ + GitHub: &GitHubMappingConfig{ + Owner: "spring-projects", + Repo: "spring-framework", + Ref: "v5.3.20", + Path: "spring-web/src/main/java/org/springframework/http", + }, + }, + }, + }, + }, + } + + tests := []struct { + name string + fileSpec FileSpec + expectedPrefix string + expectedSource string // "local" or "github" + shouldBeNil bool + }{ + { + name: "exact match for local", + fileSpec: FileSpec{Path: "org/example/rideshare"}, + expectedPrefix: "org/example/rideshare", + expectedSource: "local", + }, + { + name: "subdirectory of local", + fileSpec: FileSpec{Path: "org/example/rideshare/App.java"}, + expectedPrefix: "org/example/rideshare", + expectedSource: "local", + }, + { + name: "exact match for java", + fileSpec: FileSpec{Path: "java"}, + expectedPrefix: "java", + expectedSource: "github", + }, + { + name: "subdirectory of java", + fileSpec: FileSpec{Path: "java/util/ArrayList.java"}, + expectedPrefix: "java", + expectedSource: "github", + }, + { + name: "exact match for springframework", + fileSpec: FileSpec{Path: "org/springframework/http"}, + expectedPrefix: "org/springframework/http", + expectedSource: "github", + }, + { + name: "subdirectory of springframework", + fileSpec: FileSpec{Path: "org/springframework/http/HttpStatus.java"}, + expectedPrefix: "org/springframework/http", + expectedSource: "github", + }, + { + name: "longest prefix match", + fileSpec: FileSpec{Path: "org/springframework/http/converter/HttpMessageConverter.java"}, + expectedPrefix: "org/springframework/http", + expectedSource: "github", + }, + { + name: "no match", + fileSpec: FileSpec{Path: "com/google/common/collect/Lists.java"}, + shouldBeNil: true, + }, + { + name: "partial prefix should not match", + fileSpec: FileSpec{Path: "organization/test/File.java"}, + shouldBeNil: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := config.FindMapping(tt.fileSpec) + if tt.shouldBeNil { + assert.Nil(t, result) + } else { + require.NotNil(t, result) + require.Len(t, result.Path, 1) + assert.Equal(t, tt.expectedPrefix, result.Path[0].Prefix) + switch tt.expectedSource { + case "local": + assert.NotNil(t, result.Source.Local) + case "github": + assert.NotNil(t, result.Source.GitHub) + } + } + }) + } +} diff --git a/pkg/frontend/vcs/encryption.go b/pkg/frontend/vcs/encryption.go new file mode 100644 index 0000000000..a7b142134d --- /dev/null +++ b/pkg/frontend/vcs/encryption.go @@ -0,0 +1,76 @@ +package vcs + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "encoding/json" + "errors" + "io" + + "golang.org/x/oauth2" +) + +func encryptToken(token *oauth2.Token, key []byte) (string, error) { + plaintext, err := json.Marshal(token) + if err != nil { + return "", err + } + + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err = io.ReadFull(rand.Reader, nonce); err != nil { + return "", err + } + + // Using nonce as Seal's dst argument results in it being the first + // chunk of bytes in the ciphertext. Decrypt retrieves the nonce/IV from this. + ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) + + return base64.StdEncoding.EncodeToString(ciphertext), nil +} + +func decryptToken(ciphertextBase64 string, key []byte) (*oauth2.Token, error) { + ciphertext, err := base64.StdEncoding.DecodeString(ciphertextBase64) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonceSize := gcm.NonceSize() + if len(ciphertext) < nonceSize { + return nil, errors.New("malformed token") + } + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] + + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + + var token oauth2.Token + if err = json.Unmarshal(plaintext, &token); err != nil { + return nil, err + } + + return &token, nil +} diff --git a/pkg/querier/vcs/encryption_test.go b/pkg/frontend/vcs/encryption_test.go similarity index 100% rename from pkg/querier/vcs/encryption_test.go rename to pkg/frontend/vcs/encryption_test.go diff --git a/pkg/frontend/vcs/github.go b/pkg/frontend/vcs/github.go new file mode 100644 index 0000000000..275e425a40 --- /dev/null +++ b/pkg/frontend/vcs/github.go @@ -0,0 +1,170 @@ +package vcs + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "os" + "time" + + "golang.org/x/oauth2" + "golang.org/x/oauth2/endpoints" +) + +const ( + githubRefreshURL = "https://github.com/login/oauth/access_token" + + // Duration of a GitHub refresh token. The original OAuth flow doesn't + // return the refresh token expiry, so we need to store it separately. + // GitHub docs state this value will never change: + // + // https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens + githubRefreshExpiryDuration = 15897600 * time.Second +) + +var ( + githubAppClientID = os.Getenv("GITHUB_CLIENT_ID") + githubAppClientSecret = os.Getenv("GITHUB_CLIENT_SECRET") + githubAppCallbackURL = os.Getenv("GITHUB_CALLBACK_URL") +) + +type githubAuthToken struct { + AccessToken string `json:"access_token"` + ExpiresIn time.Duration `json:"expires_in"` + RefreshToken string `json:"refresh_token"` + RefreshTokenExpiresIn time.Duration `json:"refresh_token_expires_in"` + Scope string `json:"scope"` + TokenType string `json:"token_type"` +} + +// toOAuthToken converts a githubAuthToken to an OAuth token. +func (t githubAuthToken) toOAuthToken() *oauth2.Token { + return &oauth2.Token{ + AccessToken: t.AccessToken, + TokenType: t.TokenType, + RefreshToken: t.RefreshToken, + Expiry: time.Now().Add(t.ExpiresIn), + } +} + +// githubOAuthConfig creates a GitHub OAuth config. +func githubOAuthConfig() (*oauth2.Config, error) { + if githubAppClientID == "" { + return nil, fmt.Errorf("missing GITHUB_CLIENT_ID environment variable") + } + if githubAppClientSecret == "" { + return nil, fmt.Errorf("missing GITHUB_CLIENT_SECRET environment variable") + } + return &oauth2.Config{ + ClientID: githubAppClientID, + ClientSecret: githubAppClientSecret, + Endpoint: endpoints.GitHub, + }, nil +} + +// refreshGithubToken sends a request configured for the GitHub API and marshals +// the response into a githubAuthToken. +func refreshGithubToken(req *http.Request, client *http.Client) (*githubAuthToken, error) { + res, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to make request: %w", err) + } + defer res.Body.Close() + + bytes, err := io.ReadAll(res.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + // The response body is application/x-www-form-urlencoded, so we parse it + // via url.ParseQuery. + payload, err := url.ParseQuery(string(bytes)) + if err != nil { + return nil, fmt.Errorf("failed to parse response body: %w", err) + } + + githubToken, err := githubAuthTokenFromFormURLEncoded(payload) + if err != nil { + return nil, err + } + + return githubToken, nil +} + +// buildGithubRefreshRequest builds a cancelable http.Request which is +// configured to hit the GitHub API's token refresh endpoint. +func buildGithubRefreshRequest(ctx context.Context, oldToken *oauth2.Token) (*http.Request, error) { + req, err := http.NewRequestWithContext(ctx, "POST", githubRefreshURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + query := req.URL.Query() + query.Add("client_id", githubAppClientID) + query.Add("client_secret", githubAppClientSecret) + query.Add("grant_type", "refresh_token") + query.Add("refresh_token", oldToken.RefreshToken) + + req.URL.RawQuery = query.Encode() + return req, nil +} + +// githubAuthTokenFromFormURLEncoded converts a url-encoded form to a +// githubAuthToken. +func githubAuthTokenFromFormURLEncoded(values url.Values) (*githubAuthToken, error) { + token := &githubAuthToken{} + var err error + + token.AccessToken, err = getStringValueFrom(values, "access_token") + if err != nil { + return nil, err + } + + token.ExpiresIn, err = getDurationValueFrom(values, "expires_in", time.Second) + if err != nil { + return nil, err + } + + token.RefreshToken, err = getStringValueFrom(values, "refresh_token") + if err != nil { + return nil, err + } + + token.RefreshTokenExpiresIn, err = getDurationValueFrom(values, "refresh_token_expires_in", time.Second) + if err != nil { + return nil, err + } + + token.Scope, err = getStringValueFrom(values, "scope") + if err != nil { + return nil, err + } + + token.TokenType, err = getStringValueFrom(values, "token_type") + if err != nil { + return nil, err + } + + return token, nil +} + +func isGitHubIntegrationConfigured() error { + var errs []error + + if githubAppClientID == "" { + errs = append(errs, fmt.Errorf("missing GITHUB_CLIENT_ID environment variable")) + } + + if githubAppClientSecret == "" { + errs = append(errs, fmt.Errorf("missing GITHUB_CLIENT_SECRET environment variable")) + } + + if len(githubSessionSecret) == 0 { + errs = append(errs, fmt.Errorf("missing GITHUB_SESSION_SECRET environment variable")) + } + + return errors.Join(errs...) +} diff --git a/pkg/querier/vcs/github_test.go b/pkg/frontend/vcs/github_test.go similarity index 100% rename from pkg/querier/vcs/github_test.go rename to pkg/frontend/vcs/github_test.go diff --git a/pkg/frontend/vcs/service.go b/pkg/frontend/vcs/service.go new file mode 100644 index 0000000000..fab19e1145 --- /dev/null +++ b/pkg/frontend/vcs/service.go @@ -0,0 +1,311 @@ +package vcs + +import ( + "context" + "errors" + "fmt" + "net/http" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/grafana/dskit/tracing" + giturl "github.com/kubescape/go-git-url" + "github.com/kubescape/go-git-url/apis" + "github.com/prometheus/client_golang/prometheus" + "golang.org/x/oauth2" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1/vcsv1connect" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/source" +) + +var _ vcsv1connect.VCSServiceHandler = (*Service)(nil) + +type Service struct { + logger log.Logger + httpClient *http.Client +} + +func New(logger log.Logger, reg prometheus.Registerer) *Service { + httpClient := client.InstrumentedHTTPClient(logger, reg) + + return &Service{ + logger: logger, + httpClient: httpClient, + } +} + +func (q *Service) GithubApp(ctx context.Context, req *connect.Request[vcsv1.GithubAppRequest]) (*connect.Response[vcsv1.GithubAppResponse], error) { + sp, _ := tracing.StartSpanFromContext(ctx, "GithubApp") + defer sp.Finish() + + err := isGitHubIntegrationConfigured() + if err != nil { + q.logger.Log("err", err, "msg", "GitHub integration is not configured") + return nil, connect.NewError(connect.CodeUnimplemented, fmt.Errorf("GitHub integration is not configured")) + } + + return connect.NewResponse(&vcsv1.GithubAppResponse{ + ClientID: githubAppClientID, + CallbackURL: githubAppCallbackURL, + }), nil +} + +func (q *Service) GithubLogin(ctx context.Context, req *connect.Request[vcsv1.GithubLoginRequest]) (*connect.Response[vcsv1.GithubLoginResponse], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "GithubLogin") + defer sp.Finish() + + cfg, err := githubOAuthConfig() + if err != nil { + q.logger.Log("err", err, "msg", "failed to get GitHub OAuth config") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to authorize with GitHub")) + } + + encryptionKey, err := deriveEncryptionKeyForContext(ctx) + if err != nil { + q.logger.Log("err", err, "msg", "failed to derive encryption key") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to authorize with GitHub")) + } + + token, err := cfg.Exchange(ctx, req.Msg.AuthorizationCode) + if err != nil { + q.logger.Log("err", err, "msg", "failed to exchange authorization code with GitHub") + return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("failed to authorize with GitHub")) + } + + cookie, err := encodeTokenInCookie(token, encryptionKey) + if err != nil { + q.logger.Log("err", err, "msg", "failed to encode deprecated GitHub OAuth token") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to authorize with GitHub")) + } + + encoded, err := encryptToken(token, encryptionKey) + if err != nil { + q.logger.Log("err", err, "msg", "failed to encode GitHub OAuth token") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to authorize with GitHub")) + } + + res := &vcsv1.GithubLoginResponse{ + Cookie: cookie.String(), + Token: encoded, + TokenExpiresAt: token.Expiry.UnixMilli(), + RefreshTokenExpiresAt: time.Now().Add(githubRefreshExpiryDuration).UnixMilli(), + } + return connect.NewResponse(res), nil +} + +func (q *Service) GithubRefresh(ctx context.Context, req *connect.Request[vcsv1.GithubRefreshRequest]) (*connect.Response[vcsv1.GithubRefreshResponse], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "GithubRefresh") + defer sp.Finish() + + token, err := tokenFromRequest(ctx, req) + if err != nil { + q.logger.Log("err", err, "msg", "failed to extract token from request") + return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("invalid token")) + } + + githubRequest, err := buildGithubRefreshRequest(ctx, token) + if err != nil { + q.logger.Log("err", err, "msg", "failed to extract token from request") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to refresh token")) + } + + githubToken, err := refreshGithubToken(githubRequest, q.httpClient) + if err != nil { + q.logger.Log("err", err, "msg", "failed to refresh token with GitHub") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to refresh token")) + } + + newToken := githubToken.toOAuthToken() + + derivedKey, err := deriveEncryptionKeyForContext(ctx) + if err != nil { + q.logger.Log("err", err, "msg", "failed to derive encryption key") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to process token")) + } + + cookie, err := encodeTokenInCookie(newToken, derivedKey) + if err != nil { + q.logger.Log("err", err, "msg", "failed to encode deprecated GitHub OAuth token") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to refresh token")) + } + + encoded, err := encryptToken(newToken, derivedKey) + if err != nil { + q.logger.Log("err", err, "msg", "failed to encode GitHub OAuth token") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to refresh token")) + } + + res := &vcsv1.GithubRefreshResponse{ + Cookie: cookie.String(), + Token: encoded, + TokenExpiresAt: token.Expiry.UnixMilli(), + RefreshTokenExpiresAt: time.Now().Add(githubRefreshExpiryDuration).UnixMilli(), + } + return connect.NewResponse(res), nil +} + +func (q *Service) GetFile(ctx context.Context, req *connect.Request[vcsv1.GetFileRequest]) (*connect.Response[vcsv1.GetFileResponse], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "GetFile") + defer sp.Finish() + sp.SetTag("repository_url", req.Msg.RepositoryURL) + sp.SetTag("local_path", req.Msg.LocalPath) + sp.SetTag("function_name", req.Msg.FunctionName) + sp.SetTag("root_path", req.Msg.RootPath) + sp.SetTag("ref", req.Msg.Ref) + + token, err := tokenFromRequest(ctx, req) + if err != nil { + q.logger.Log("err", err, "msg", "failed to extract token from request") + return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("invalid token")) + } + + err = rejectExpiredToken(token) + if err != nil { + return nil, err + } + + // initialize and parse the git repo URL + gitURL, err := giturl.NewGitURL(req.Msg.RepositoryURL) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + if gitURL.GetProvider() != apis.ProviderGitHub.String() { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("only GitHub repositories are supported")) + } + + // todo: we can support multiple provider: bitbucket, gitlab, etc. + ghClient, err := client.GithubClient(ctx, token, q.httpClient) + if err != nil { + return nil, err + } + + file, err := source.NewFileFinder( + ghClient, + gitURL, + config.FileSpec{ + Path: req.Msg.LocalPath, + FunctionName: req.Msg.FunctionName, + }, + req.Msg.RootPath, + req.Msg.Ref, + http.DefaultClient, + log.With(q.logger, "repo", gitURL.GetRepoName()), + ).Find(ctx) + if err != nil { + if errors.Is(err, client.ErrNotFound) { + return nil, connect.NewError(connect.CodeNotFound, err) + } + return nil, err + } + return connect.NewResponse(file), nil +} + +func (q *Service) GetCommit(ctx context.Context, req *connect.Request[vcsv1.GetCommitRequest]) (*connect.Response[vcsv1.GetCommitResponse], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "GetCommit") + defer sp.Finish() + sp.SetTag("repository_url", req.Msg.RepositoryURL) + sp.SetTag("ref", req.Msg.Ref) + + token, err := tokenFromRequest(ctx, req) + if err != nil { + q.logger.Log("err", err, "msg", "failed to extract token from request") + return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("invalid token")) + } + + err = rejectExpiredToken(token) + if err != nil { + return nil, err + } + + gitURL, err := giturl.NewGitURL(req.Msg.RepositoryURL) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + if gitURL.GetProvider() != apis.ProviderGitHub.String() { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("only GitHub repositories are supported")) + } + + ghClient, err := client.GithubClient(ctx, token, q.httpClient) + if err != nil { + return nil, err + } + + owner := gitURL.GetOwnerName() + repo := gitURL.GetRepoName() + ref := req.Msg.GetRef() + + commit, err := tryGetCommit(ctx, ghClient, owner, repo, ref) + if err != nil { + return nil, err + } + + return connect.NewResponse(&vcsv1.GetCommitResponse{ + Message: commit.GetMessage(), + Author: commit.GetAuthor(), + Date: commit.GetDate(), + Sha: commit.GetSha(), + URL: commit.GetURL(), + }), nil +} + +func (q *Service) GetCommits(ctx context.Context, req *connect.Request[vcsv1.GetCommitsRequest]) (*connect.Response[vcsv1.GetCommitsResponse], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "GetCommits") + defer sp.Finish() + + token, err := tokenFromRequest(ctx, req) + if err != nil { + q.logger.Log("err", err, "msg", "failed to extract token from request") + return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("invalid token")) + } + + err = rejectExpiredToken(token) + if err != nil { + return nil, err + } + + gitURL, err := giturl.NewGitURL(req.Msg.RepositoryUrl) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + if gitURL.GetProvider() != apis.ProviderGitHub.String() { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("only GitHub repositories are supported")) + } + + ghClient, err := client.GithubClient(ctx, token, q.httpClient) + if err != nil { + return nil, err + } + + owner := gitURL.GetOwnerName() + repo := gitURL.GetRepoName() + refs := req.Msg.Refs + + commits, failedFetches, err := getCommits(ctx, ghClient, owner, repo, refs) + if err != nil { + q.logger.Log("err", err, "msg", "failed to get any commits", "owner", owner, "repo", repo) + return nil, err + } + + if len(failedFetches) > 0 { + q.logger.Log("warn", "partial success fetching commits", "owner", owner, "repo", repo, "successCount", len(commits), "failureCount", len(failedFetches)) + for _, fetchErr := range failedFetches { + q.logger.Log("err", fetchErr, "msg", "failed to fetch commit") + } + } + + return connect.NewResponse(&vcsv1.GetCommitsResponse{Commits: commits}), nil +} + +func rejectExpiredToken(token *oauth2.Token) error { + if time.Now().After(token.Expiry) { + return connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("token is expired")) + } + return nil +} diff --git a/pkg/frontend/vcs/source/find.go b/pkg/frontend/vcs/source/find.go new file mode 100644 index 0000000000..7278c78770 --- /dev/null +++ b/pkg/frontend/vcs/source/find.go @@ -0,0 +1,213 @@ +package source + +import ( + "context" + "encoding/base64" + "fmt" + "io" + "net/http" + "path/filepath" + "strings" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + giturl "github.com/kubescape/go-git-url" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" +) + +type VCSClient interface { + GetFile(ctx context.Context, req client.FileRequest) (client.File, error) +} + +// FileFinder finds a file in a vcs repository. +type FileFinder struct { + file config.FileSpec + ref, rootPath string + repo giturl.IGitURL + + config *config.PyroscopeConfig + client VCSClient + httpClient *http.Client + logger log.Logger +} + +// NewFileFinder returns a new FileFinder. +func NewFileFinder(client VCSClient, repo giturl.IGitURL, file config.FileSpec, rootPath, ref string, httpClient *http.Client, logger log.Logger) *FileFinder { + if ref == "" { + ref = "HEAD" + } + return &FileFinder{ + client: client, + logger: logger, + repo: repo, + file: file, + rootPath: rootPath, + ref: ref, + httpClient: httpClient, + } +} + +// Find returns the file content and URL. +func (ff *FileFinder) Find(ctx context.Context) (*vcsv1.GetFileResponse, error) { + // first try to gather the config + ff.loadConfig(ctx) + + // without config we are done here + if ff.config == nil { + return ff.findFallback(ctx) + } + + // find matching mappings + mapping := ff.config.FindMapping(ff.file) + if mapping == nil { + return ff.findFallback(ctx) + } + + switch config.Language(mapping.Language) { + case config.LanguageGo: + return ff.findGoFile(ctx, mapping) + case config.LanguageJava: + return ff.findJavaFile(ctx, mapping) + case config.LanguagePython: + return ff.findPythonFile(ctx, mapping) + case config.LanguageJavaScript: + return ff.findJavaScriptFile(ctx, mapping) + default: + return ff.findFallback(ctx) + } +} + +func (ff FileFinder) findFallback(ctx context.Context) (*vcsv1.GetFileResponse, error) { + ext := filepath.Ext(ff.file.Path) + switch { + case ext == ExtGo: + return ff.findGoFile(ctx) + case ext == ExtPython: + return ff.findPythonFile(ctx) + case ext == ExtAsm: // Note: When adding wider language support this needs to be revisited + return ff.findGoFile(ctx) + case isJavaScriptExtension(ext): + return ff.findJavaScriptFile(ctx) + default: + // by default we return the file content at the given path without any processing. + return ff.fetchRepoFile(ctx, ff.file.Path, ff.ref) + } +} + +// loadConfig attempts to load .pyroscope.yaml from the repository root +func (ff *FileFinder) loadConfig(ctx context.Context) { + sp, ctx := tracing.StartSpanFromContext(ctx, "FileFinder.loadConfig") + defer sp.Finish() + + configPath := config.PyroscopeConfigPath + if ff.rootPath != "" { + configPath = filepath.Join(ff.rootPath, config.PyroscopeConfigPath) + } + + file, err := ff.client.GetFile(ctx, client.FileRequest{ + Owner: ff.repo.GetOwnerName(), + Repo: ff.repo.GetRepoName(), + Path: configPath, + Ref: ff.ref, + }) + if err != nil { + // Config is optional, so just log and continue + level.Debug(ff.logger).Log("msg", "no .pyroscope.yaml found", "path", configPath) + return + } + sp.SetTag("config.url", file.URL) + sp.SetTag("config", file.Content) + + cfg, err := config.ParsePyroscopeConfig([]byte(file.Content)) + if err != nil { + level.Warn(ff.logger).Log("msg", "failed to parse .pyroscope.yaml", "err", err) + return + } + + ff.config = cfg + level.Debug(ff.logger).Log("msg", "loaded .pyroscope.yaml", "url", file.URL, "mappings", len(cfg.SourceCode.Mappings)) + sp.SetTag("config.source_code.mappings_count", len(cfg.SourceCode.Mappings)) + +} + +// fetchRepoFile fetches the file content from the configured repository. +func (arg FileFinder) fetchRepoFile(ctx context.Context, path, ref string) (*vcsv1.GetFileResponse, error) { + if arg.rootPath != "" { + path = filepath.Join(arg.rootPath, path) + } + content, err := arg.client.GetFile(ctx, client.FileRequest{ + Owner: arg.repo.GetOwnerName(), + Repo: arg.repo.GetRepoName(), + Path: strings.TrimLeft(path, "/"), + Ref: ref, + }) + if err != nil { + return nil, err + } + return newFileResponse(content.Content, content.URL) +} + +// fetchURL fetches the file content from the given URL. +func (ff FileFinder) fetchURL(ctx context.Context, url string, decodeBase64 bool) (*vcsv1.GetFileResponse, error) { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return nil, err + } + resp, err := ff.httpClient.Do(req) // todo: use a custom client with timeout + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("failed to fetch %s: %s", url, resp.Status)) + } + content, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if !decodeBase64 { + return newFileResponse(string(content), url) + } + decoded, err := base64.StdEncoding.DecodeString(string(content)) + if err != nil { + return nil, err + } + return newFileResponse(string(decoded), url) +} + +func newFileResponse(content, url string) (*vcsv1.GetFileResponse, error) { + return &vcsv1.GetFileResponse{ + Content: base64.StdEncoding.EncodeToString([]byte(content)), + URL: url, + }, nil +} + +func (ff FileFinder) fetchMappingFile(ctx context.Context, m *config.MappingConfig, path string) (*vcsv1.GetFileResponse, error) { + if s := m.Source.Local; s != nil { + if s.Path != "" { + path = filepath.Join(s.Path, path) + } + return ff.fetchRepoFile(ctx, path, ff.ref) + } + if s := m.Source.GitHub; s != nil { + if s.Path != "" { + path = filepath.Join(s.Path, path) + } + content, err := ff.client.GetFile(ctx, client.FileRequest{ + Owner: s.Owner, + Repo: s.Repo, + Ref: s.Ref, + Path: path, + }) + if err != nil { + return nil, err + } + return newFileResponse(content.Content, content.URL) + } + return nil, fmt.Errorf("no supported source provided, file not resolvable") +} diff --git a/pkg/frontend/vcs/source/find_go.go b/pkg/frontend/vcs/source/find_go.go new file mode 100644 index 0000000000..8f2bbc9d96 --- /dev/null +++ b/pkg/frontend/vcs/source/find_go.go @@ -0,0 +1,233 @@ +package source + +import ( + "context" + "errors" + "fmt" + "path" + "path/filepath" + "strings" + "time" + + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/source/golang" +) + +const ( + ExtGo = ".go" + ExtAsm = ".s" // Assembler files in go +) + +// findGoFile finds a go file in a vcs repository. +func (ff FileFinder) findGoFile(ctx context.Context, mappings ...*config.MappingConfig) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "findGoFile") + defer sp.Finish() + sp.SetTag("file.path", ff.file.Path) + sp.SetTag("file.function_name", ff.file.FunctionName) + + // if we have mappings try those first + for _, m := range mappings { + pos := m.Match(ff.file) + if pos < 0 || pos > len(ff.file.Path) { + level.Warn(ff.logger).Log("msg", "mapping cut off out of bounds", "pos", pos, "file_path", ff.file.Path) + continue + } + resp, err := ff.fetchMappingFile(ctx, m, strings.TrimLeft(ff.file.Path[pos:], "/")) + if err != nil { + if errors.Is(err, client.ErrNotFound) { + continue + } + level.Warn(ff.logger).Log("msg", "failed to fetch mapping file", "err", err) + continue + } + return resp, nil + } + + if path, version, ok := golang.IsStandardLibraryPath(ff.file.Path); ok { + return ff.fetchGoStdlib(ctx, path, version) + } + + if relativePath, ok := golang.VendorRelativePath(ff.file.Path); ok { + return ff.fetchRepoFile(ctx, relativePath, ff.ref) + } + + modFile, ok := golang.ParseModuleFromPath(ff.file.Path) + if ok { + mainModule := module.Version{ + Path: path.Join(ff.repo.GetHostName(), ff.repo.GetOwnerName(), ff.repo.GetRepoName()), + Version: module.PseudoVersion("", "", time.Time{}, ff.ref), + } + modf, err := ff.fetchGoMod(ctx) + if err != nil { + level.Warn(ff.logger).Log("msg", "failed to fetch go.mod file", "err", err) + } + if err := modFile.Resolve(ctx, mainModule, modf, ff.httpClient); err != nil { + return nil, err + } + return ff.fetchGoDependencyFile(ctx, modFile) + } + return ff.tryFindGoFile(ctx, 30) +} + +func (ff FileFinder) fetchGoStdlib(ctx context.Context, path string, version string) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "fetchGoStdlib") + defer sp.Finish() + + // if there is no version detected, use the one from .pyroscope.yaml + if version == "" && ff.config != nil { + mapping := ff.config.FindMapping(config.FileSpec{Path: "$GOROOT/src"}) + if mapping != nil { + return ff.fetchMappingFile(ctx, mapping, path) + } + } + + // use master branch as fallback + ref := "master" + if version != "" { + ref = "go" + version + } + + content, err := ff.client.GetFile(ctx, client.FileRequest{ + Owner: "golang", + Repo: "go", + Path: filepath.Join("src", path), + Ref: ref, + }) + if err != nil { + return nil, err + } + return newFileResponse(content.Content, content.URL) +} + +func (ff FileFinder) fetchGoMod(ctx context.Context) (*modfile.File, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "fetchGoMod") + defer sp.Finish() + sp.SetTag("owner", ff.repo.GetOwnerName()) + sp.SetTag("repo", ff.repo.GetRepoName()) + sp.SetTag("ref", ff.ref) + + content, err := ff.client.GetFile(ctx, client.FileRequest{ + Owner: ff.repo.GetOwnerName(), + Repo: ff.repo.GetRepoName(), + Path: golang.GoMod, + Ref: ff.ref, + }) + if err != nil { + return nil, err + } + return modfile.Parse(golang.GoMod, []byte(content.Content), nil) +} + +func (ff FileFinder) fetchGoDependencyFile(ctx context.Context, module golang.Module) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "fetchGoDependencyFile") + defer sp.Finish() + sp.SetTag("module_path", module.Path) + + switch { + case module.IsGitHub(): + return ff.fetchGithubModuleFile(ctx, module) + case module.IsGoogleSource(): + return ff.fetchGoogleSourceDependencyFile(ctx, module) + } + return nil, fmt.Errorf("unsupported module path: %s", module.Path) +} + +func (ff FileFinder) fetchGithubModuleFile(ctx context.Context, mod golang.Module) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "fetchGithubModuleFile") + defer sp.Finish() + sp.SetTag("module_path", mod.Path) + + // todo: what if this is not a github repo? + // VSClient should support querying multiple repo providers. + githubFile, err := mod.GithubFile() + if err != nil { + return nil, err + } + sp.SetTag("owner", githubFile.Owner) + sp.SetTag("repo", githubFile.Repo) + sp.SetTag("path", githubFile.Path) + sp.SetTag("ref", githubFile.Ref) + + content, err := ff.client.GetFile(ctx, client.FileRequest{ + Owner: githubFile.Owner, + Repo: githubFile.Repo, + Path: githubFile.Path, + Ref: githubFile.Ref, + }) + if err != nil { + return nil, err + } + return newFileResponse(content.Content, content.URL) +} + +func (ff FileFinder) fetchGoogleSourceDependencyFile(ctx context.Context, mod golang.Module) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "fetchGoogleSourceDependencyFile") + defer sp.Finish() + sp.SetTag("module_path", mod.Path) + + url, err := mod.GoogleSourceURL() + if err != nil { + return nil, err + } + sp.SetTag("url", url) + return ff.fetchURL(ctx, url, true) +} + +// tryFindGoFile tries to find the go file in the repo, under the rootPath. +// It tries to find the file in the rootPath inside the repo by removing path segment after path segment. +// maxAttempts is the maximum number of attempts to try to find the file in case the file path is very long. +// For example, if the path is "github.com/grafana/grafana/pkg/infra/log/log.go" and rootPath is "path/to/module1", it +// will try to find the file at: +// - "path/to/module1/pkg/infra/log/log.go" +// - "path/to/module1/infra/log/log.go" +// - "path/to/module1/log/log.go" +// - "path/to/module1/log.go" +func (ff FileFinder) tryFindGoFile(ctx context.Context, maxAttempts int) (*vcsv1.GetFileResponse, error) { + if maxAttempts <= 0 { + return nil, errors.New("invalid max attempts") + } + + // trim repo path (e.g. "github.com/grafana/pyroscope/") in path + path := ff.file.Path + repoPath := strings.Join([]string{ff.repo.GetHostName(), ff.repo.GetOwnerName(), ff.repo.GetRepoName(), ""}, "/") + if pos := strings.Index(path, repoPath); pos != -1 { + path = path[len(repoPath)+pos:] + } + + // now try to find file in repo + path = strings.TrimLeft(path, "/") + attempts := 0 + for { + reqPath := path + if ff.rootPath != "" { + reqPath = strings.Join([]string{ff.rootPath, path}, "/") + } + content, err := ff.client.GetFile(ctx, client.FileRequest{ + Owner: ff.repo.GetOwnerName(), + Repo: ff.repo.GetRepoName(), + Path: reqPath, + Ref: ff.ref, + }) + attempts++ + if err != nil && errors.Is(err, client.ErrNotFound) && attempts < maxAttempts { + i := strings.Index(path, "/") + if i < 0 { + return nil, err + } + // remove the first path segment + path = path[i+1:] + continue + } + if err != nil { + return nil, err + } + return newFileResponse(content.Content, content.URL) + } +} diff --git a/pkg/frontend/vcs/source/find_go_test.go b/pkg/frontend/vcs/source/find_go_test.go new file mode 100644 index 0000000000..90bda3fd6a --- /dev/null +++ b/pkg/frontend/vcs/source/find_go_test.go @@ -0,0 +1,92 @@ +package source + +import ( + "context" + "testing" + + giturl "github.com/kubescape/go-git-url" + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" +) + +func Test_tryFindGoFile(t *testing.T) { + pyroscopeRepo, _ := giturl.NewGitURL("http://github.com/grafana/pyroscope") + tests := []struct { + name string + searchedPath string + rootPath string + repo giturl.IGitURL + clientMock *mockVCSClient + attempts int + expectedSearchedPaths []string + expectedError error + }{ + { + name: "happy case in root path", + searchedPath: "/var/service1/src/main.go", + rootPath: "", + repo: pyroscopeRepo, + clientMock: newMockVCSClient().addFiles(newFile("main.go")), + attempts: 5, + expectedSearchedPaths: []string{"var/service1/src/main.go", "service1/src/main.go", "src/main.go", "main.go"}, + expectedError: nil, + }, + { + name: "happy case in submodule", + searchedPath: "/src/main.go", + rootPath: "service/example", + repo: pyroscopeRepo, + clientMock: newMockVCSClient().addFiles(newFile("service/example/main.go")), + attempts: 5, + expectedSearchedPaths: []string{"service/example/src/main.go", "service/example/main.go"}, + expectedError: nil, + }, + { + name: "path with relative repository prefix", + searchedPath: "github.com/grafana/pyroscope/main.go", + rootPath: "", + repo: pyroscopeRepo, + clientMock: newMockVCSClient().addFiles(newFile("main.go")), + attempts: 1, + expectedSearchedPaths: []string{"main.go"}, + expectedError: nil, + }, + { + name: "path with absolute repository prefix", + searchedPath: "/Users/pyroscope/git/github.com/grafana/pyroscope/main.go", + rootPath: "", + repo: pyroscopeRepo, + clientMock: newMockVCSClient().addFiles(newFile("main.go")), + attempts: 1, + expectedSearchedPaths: []string{"main.go"}, + expectedError: nil, + }, + { + name: "not found, attempts exceeded", + searchedPath: "/var/service1/src/main.go", + rootPath: "", + repo: pyroscopeRepo, + clientMock: newMockVCSClient().addFiles(newFile("main.go")), + attempts: 3, + expectedSearchedPaths: []string{"var/service1/src/main.go", "service1/src/main.go", "src/main.go"}, + expectedError: client.ErrNotFound, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + sut := FileFinder{ + file: config.FileSpec{Path: tt.searchedPath}, + rootPath: tt.rootPath, + ref: defaultRef(""), + repo: tt.repo, + client: tt.clientMock, + } + _, err := sut.tryFindGoFile(ctx, tt.attempts) + assert.Equal(t, tt.expectedSearchedPaths, (*tt.clientMock).searchedSequence) + assert.Equal(t, tt.expectedError, err) + }) + } +} diff --git a/pkg/frontend/vcs/source/find_java.go b/pkg/frontend/vcs/source/find_java.go new file mode 100644 index 0000000000..0e08782f52 --- /dev/null +++ b/pkg/frontend/vcs/source/find_java.go @@ -0,0 +1,71 @@ +package source + +import ( + "context" + "errors" + "strings" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" +) + +const ( + ExtJava = ".java" +) + +func convertJavaFunctionNameToPath(functionName string) string { + pathSegments := strings.Split(functionName, "/") + last := len(pathSegments) - 1 + + // pos to cut from + pos := -1 + updatePos := func(v int) { + if v == -1 { + return + } + if pos == -1 || pos > v { + pos = v + } + } + + // find first dot in last segment + updatePos(strings.Index(pathSegments[last], ".")) + + // find first $ in last segment + updatePos(strings.Index(pathSegments[last], "$")) + + if pos > 0 { + pathSegments[last] = pathSegments[last][:pos] + } + + pathSegments[last] = pathSegments[last] + ExtJava + return strings.Join(pathSegments, "/") +} + +// findJavaFile finds a java file in a vcs repository. +func (ff FileFinder) findJavaFile(ctx context.Context, mappings ...*config.MappingConfig) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "findJavaFile") + defer sp.Finish() + sp.SetTag("file.function_name", ff.file.FunctionName) + sp.SetTag("file.path", ff.file.Path) + + javaPath := convertJavaFunctionNameToPath(ff.file.FunctionName) + for _, m := range mappings { + resp, err := ff.fetchMappingFile(ctx, m, javaPath) + if err != nil { + if errors.Is(err, client.ErrNotFound) { + continue + } + level.Warn(ff.logger).Log("msg", "failed to fetch mapping file", "err", err) + continue + } + return resp, nil + } + + return nil, connect.NewError(connect.CodeNotFound, errors.New("no mappings provided, file not resolvable")) +} diff --git a/pkg/frontend/vcs/source/find_java_test.go b/pkg/frontend/vcs/source/find_java_test.go new file mode 100644 index 0000000000..c29e248964 --- /dev/null +++ b/pkg/frontend/vcs/source/find_java_test.go @@ -0,0 +1,98 @@ +package source + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_convertJavaFunctionNameToPath(t *testing.T) { + tests := []struct { + name string + functionName string + expected string + }{ + { + name: "simple class name", + functionName: "com/example/MyClass", + expected: "com/example/MyClass.java", + }, + { + name: "class with method", + functionName: "com/example/MyClass.myMethod", + expected: "com/example/MyClass.java", + }, + { + name: "inner class with dollar sign", + functionName: "com/example/OuterClass$InnerClass", + expected: "com/example/OuterClass.java", + }, + { + name: "inner class with method", + functionName: "com/example/OuterClass$InnerClass.method", + expected: "com/example/OuterClass.java", + }, + { + name: "lambda or anonymous class", + functionName: "com/example/MyClass$1", + expected: "com/example/MyClass.java", + }, + { + name: "nested inner class", + functionName: "com/example/Outer$Inner$DeepInner", + expected: "com/example/Outer.java", + }, + { + name: "method with parameters in name", + functionName: "com/example/MyClass.method.withDots", + expected: "com/example/MyClass.java", + }, + { + name: "single segment with method", + functionName: "MyClass.method", + expected: "MyClass.java", + }, + { + name: "single segment with inner class", + functionName: "MyClass$Inner", + expected: "MyClass.java", + }, + { + name: "no package, just class", + functionName: "MyClass", + expected: "MyClass.java", + }, + { + name: "complex nested structure", + functionName: "org/springframework/boot/Application$Config$Bean.initialize", + expected: "org/springframework/boot/Application.java", + }, + { + name: "dollar sign before dot", + functionName: "com/example/Class$Inner.method", + expected: "com/example/Class.java", + }, + { + name: "dot before dollar sign", + functionName: "com/example/Class.method$1", + expected: "com/example/Class.java", + }, + { + name: "multiple dollar signs", + functionName: "com/example/Outer$Middle$Inner", + expected: "com/example/Outer.java", + }, + { + name: "multiple dots", + functionName: "com/example/Class.method.subMethod", + expected: "com/example/Class.java", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := convertJavaFunctionNameToPath(tt.functionName) + assert.Equal(t, tt.expected, result) + }) + } +} diff --git a/pkg/frontend/vcs/source/find_javascript.go b/pkg/frontend/vcs/source/find_javascript.go new file mode 100644 index 0000000000..1dd049d664 --- /dev/null +++ b/pkg/frontend/vcs/source/find_javascript.go @@ -0,0 +1,75 @@ +package source + +import ( + "context" + "errors" + "strings" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" +) + +const ( + ExtJS = ".js" + ExtMJS = ".mjs" + ExtCJS = ".cjs" + ExtTS = ".ts" + ExtJSX = ".jsx" + ExtTSX = ".tsx" +) + +// isJavaScriptExtension returns true if the file extension is a JavaScript/TypeScript extension. +func isJavaScriptExtension(ext string) bool { + switch ext { + case ExtJS, ExtMJS, ExtCJS, ExtTS, ExtJSX, ExtTSX: + return true + default: + return false + } +} + +// findJavaScriptFile finds a JavaScript/TypeScript file in a VCS repository. +// It supports path mappings from .pyroscope.yaml to map runtime paths to source paths. +func (ff FileFinder) findJavaScriptFile(ctx context.Context, mappings ...*config.MappingConfig) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "findJavaScriptFile") + defer sp.Finish() + sp.SetTag("file.function_name", ff.file.FunctionName) + sp.SetTag("file.path", ff.file.Path) + + for _, m := range mappings { + // Strip the matched prefix from the runtime path to get the relative + // path within the mapped source (e.g., "/usr/src/app/index.js" with + // prefix "/usr/src/app" yields "index.js"). + pos := m.Match(ff.file) + if pos < 0 || pos > len(ff.file.Path) { + level.Warn(ff.logger).Log("msg", "mapping match out of bounds", "pos", pos, "file_path", ff.file.Path) + continue + } + path := strings.TrimLeft(ff.file.Path[pos:], "/") + + resp, err := ff.fetchMappingFile(ctx, m, path) + if err != nil { + if errors.Is(err, client.ErrNotFound) { + continue + } + level.Warn(ff.logger).Log("msg", "failed to fetch mapping file", "err", err) + continue + } + return resp, nil + } + + // Fallback to relative file path matching + f, err := ff.fetchRepoFile(ctx, ff.file.Path, ff.ref) + if err != nil { + level.Warn(ff.logger).Log("msg", "failed to fetch relative file", "err", err) + } else { + return f, nil + } + + return nil, connect.NewError(connect.CodeNotFound, errors.New("no mappings matched and relative path not found, file not resolvable")) +} diff --git a/pkg/frontend/vcs/source/find_javascript_test.go b/pkg/frontend/vcs/source/find_javascript_test.go new file mode 100644 index 0000000000..c22498c898 --- /dev/null +++ b/pkg/frontend/vcs/source/find_javascript_test.go @@ -0,0 +1,73 @@ +package source + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_isJavaScriptExtension(t *testing.T) { + tests := []struct { + name string + ext string + expected bool + }{ + { + name: "JavaScript", + ext: ".js", + expected: true, + }, + { + name: "TypeScript", + ext: ".ts", + expected: true, + }, + { + name: "ES Module", + ext: ".mjs", + expected: true, + }, + { + name: "CommonJS", + ext: ".cjs", + expected: true, + }, + { + name: "JSX", + ext: ".jsx", + expected: true, + }, + { + name: "TSX", + ext: ".tsx", + expected: true, + }, + { + name: "Go file", + ext: ".go", + expected: false, + }, + { + name: "Python file", + ext: ".py", + expected: false, + }, + { + name: "Empty extension", + ext: "", + expected: false, + }, + { + name: "JSON file", + ext: ".json", + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isJavaScriptExtension(tt.ext) + assert.Equal(t, tt.expected, result) + }) + } +} diff --git a/pkg/frontend/vcs/source/find_python.go b/pkg/frontend/vcs/source/find_python.go new file mode 100644 index 0000000000..bae4e80161 --- /dev/null +++ b/pkg/frontend/vcs/source/find_python.go @@ -0,0 +1,115 @@ +package source + +import ( + "context" + "errors" + "path/filepath" + "regexp" + "strings" + + "connectrpc.com/connect" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + + vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" +) + +const ( + ExtPython = ".py" +) + +var ( + // stdLibRegex matches Python version directories and captures the version. + // Example: "python3.12/" → version="3.12" + stdLibRegex = regexp.MustCompile(`python(\d+\.\d{1,2})/`) +) + +func (ff FileFinder) fetchPythonStdlib(ctx context.Context, path string, version string) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "fetchPythonStdlib") + defer sp.Finish() + + // use main branch as fallback + ref := "main" + if version != "" { + ref = version + } + + content, err := ff.client.GetFile(ctx, client.FileRequest{ + Owner: "python", + Repo: "cpython", + Path: filepath.Join("Lib", path), + Ref: ref, + }) + if err != nil { + return nil, err + } + return newFileResponse(content.Content, content.URL) +} + +// isPythonStdlibPath returns the cleaned path of the standard library package with version, if detected. +// For example, given "/path/to/lib/python3.12/difflib.py", +// it returns ("difflib.py", "3.12", true). +// Note that minor versions are not captured in this path, so there are +// future improvements that can be made to this logic. +func isPythonStdlibPath(path string) (string, string, bool) { + matches := stdLibRegex.FindAllStringSubmatchIndex(path, -1) + if len(matches) == 0 { + return "", "", false + } + + // Take the last match to handle paths with multiple python version directories + m := matches[len(matches)-1] + version := path[m[2]:m[3]] + remaining := path[m[1]:] + if remaining == "" { + return "", "", false + } + return remaining, version, true +} + +// findPythonFile finds a python file in a vcs repository. +// Currently only supports Python stdlib +func (ff FileFinder) findPythonFile(ctx context.Context, mappings ...*config.MappingConfig) (*vcsv1.GetFileResponse, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "findPythonFile") + defer sp.Finish() + sp.SetTag("file.function_name", ff.file.FunctionName) + sp.SetTag("file.path", ff.file.Path) + + if path, version, ok := isPythonStdlibPath(ff.file.Path); ok { + return ff.fetchPythonStdlib(ctx, path, version) + } + + for _, m := range mappings { + // Strip the matched prefix from the runtime path to get the relative + // path within the mapped source (e.g., "/app/myproject/main.py" with + // prefix "/app/myproject" yields "main.py"). + pos := m.Match(ff.file) + if pos < 0 || pos > len(ff.file.Path) { + level.Warn(ff.logger).Log("msg", "mapping match out of bounds", "pos", pos, "file_path", ff.file.Path) + continue + } + path := strings.TrimLeft(ff.file.Path[pos:], "/") + + resp, err := ff.fetchMappingFile(ctx, m, path) + if err != nil { + if errors.Is(err, client.ErrNotFound) { + continue + } + level.Warn(ff.logger).Log("msg", "failed to fetch mapping file", "err", err) + continue + } + return resp, nil + } + + // Fallback to relative file path matching + f, err := ff.fetchRepoFile(ctx, ff.file.Path, ff.ref) + if err != nil { + level.Warn(ff.logger).Log("msg", "failed to fetch relative file", "err", err) + } else { + return f, nil + } + + return nil, connect.NewError(connect.CodeNotFound, errors.New("stdlib not detected and no mappings provided, file not resolvable")) +} diff --git a/pkg/frontend/vcs/source/find_python_test.go b/pkg/frontend/vcs/source/find_python_test.go new file mode 100644 index 0000000000..3414c62f94 --- /dev/null +++ b/pkg/frontend/vcs/source/find_python_test.go @@ -0,0 +1,119 @@ +package source + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_isPythonStdlibPath(t *testing.T) { + tests := []struct { + name string + path string + expectedPath string + expectedVersion string + expectedOk bool + }{ + { + name: "UV Python install", + path: "/Users/user/.local/share/uv/python/cpython-3.12.12-macos-aarch64-none/lib/python3.12/difflib.py", + expectedPath: "difflib.py", + expectedVersion: "3.12", + expectedOk: true, + }, + { + name: "pyenv install", + path: "/home/user/.pyenv/versions/3.11.4/lib/python3.11/json/decoder.py", + expectedPath: "json/decoder.py", + expectedVersion: "3.11", + expectedOk: true, + }, + { + name: "System Python", + path: "/usr/lib/python3.10/collections/__init__.py", + expectedPath: "collections/__init__.py", + expectedVersion: "3.10", + expectedOk: true, + }, + { + name: "Python 2.7", + path: "/usr/lib/python2.7/os.py", + expectedPath: "os.py", + expectedVersion: "2.7", + expectedOk: true, + }, + { + name: "Two-digit minor version", + path: "/lib/python3.99/test.py", + expectedPath: "test.py", + expectedVersion: "3.99", + expectedOk: true, + }, + { + name: "Not stdlib - user project", + path: "/app/myproject/main.py", + expectedPath: "", + expectedVersion: "", + expectedOk: false, + }, + { + name: "Not stdlib - no python prefix", + path: "/usr/lib/site-packages/requests/api.py", + expectedPath: "", + expectedVersion: "", + expectedOk: false, + }, + { + name: "Empty path", + path: "", + expectedPath: "", + expectedVersion: "", + expectedOk: false, + }, + { + name: "Ends at python version - no trailing slash", + path: "/lib/python3.12", + expectedPath: "", + expectedVersion: "", + expectedOk: false, + }, + { + name: "Ends at python version - with trailing slash only", + path: "/lib/python3.12/", + expectedPath: "", + expectedVersion: "", + expectedOk: false, + }, + { + name: "Nested stdlib path", + path: "/opt/python/lib/python3.9/email/mime/text.py", + expectedPath: "email/mime/text.py", + expectedVersion: "3.9", + expectedOk: true, + }, + { + name: "Windows-style path with forward slashes", + path: "C:/Python312/Lib/python3.12/asyncio/base_events.py", + expectedPath: "asyncio/base_events.py", + expectedVersion: "3.12", + expectedOk: true, + }, + { + name: "Multiple versions in path", + path: "/opt/python3.8/lib/python3.9/email/mime/text.py", + expectedPath: "email/mime/text.py", + // Should take last match + expectedVersion: "3.9", + expectedOk: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + path, version, ok := isPythonStdlibPath(tt.path) + assert.Equal(t, tt.expectedPath, path) + assert.Equal(t, tt.expectedVersion, version) + assert.Equal(t, tt.expectedOk, ok) + }) + } +} diff --git a/pkg/frontend/vcs/source/find_test.go b/pkg/frontend/vcs/source/find_test.go new file mode 100644 index 0000000000..740ccfd602 --- /dev/null +++ b/pkg/frontend/vcs/source/find_test.go @@ -0,0 +1,817 @@ +package source + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "net/http" + "path/filepath" + "sync" + "testing" + + "connectrpc.com/connect" + "github.com/go-kit/log" + giturl "github.com/kubescape/go-git-url" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/client" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/config" +) + +func newMockVCSClient() *mockVCSClient { + return &mockVCSClient{ + files: make(map[client.FileRequest]client.File), + } +} + +type mockFileResponse struct { + request client.FileRequest + content string +} + +func newFile(path string) mockFileResponse { + return mockFileResponse{ + request: client.FileRequest{ + Path: path, + }, + content: "# Content of " + path, + } +} + +func (f *mockFileResponse) url() string { + return fmt.Sprintf( + "https://github.com/%s/%s/blob/%s/%s", + f.request.Owner, + f.request.Repo, + f.request.Ref, + f.request.Path, + ) +} + +type mockVCSClient struct { + mtx sync.Mutex + files map[client.FileRequest]client.File + searchedSequence []string +} + +func (c *mockVCSClient) GetFile(ctx context.Context, req client.FileRequest) (client.File, error) { + c.mtx.Lock() + c.searchedSequence = append(c.searchedSequence, req.Path) + file, ok := c.files[req] + c.mtx.Unlock() + if ok { + return file, nil + } + return client.File{}, client.ErrNotFound +} + +func (c *mockVCSClient) addFiles(files ...mockFileResponse) *mockVCSClient { + c.mtx.Lock() + defer c.mtx.Unlock() + for _, file := range files { + file.request.Owner = defaultOwner(file.request.Owner) + file.request.Repo = defaultRepo(file.request.Repo) + file.request.Ref = defaultRef(file.request.Ref) + c.files[file.request] = client.File{ + Content: file.content, + URL: file.url(), + } + } + return c +} + +func defaultOwner(s string) string { + if s == "" { + return "grafana" + } + return s +} + +func defaultRepo(s string) string { + if s == "" { + return "pyroscope" + } + return s +} +func defaultRef(s string) string { + if s == "" { + return "main" + } + return s +} + +const javaPyroscopeYAML = `--- +source_code: + mappings: + - function_name: + - prefix: org/example/rideshare + language: java + source: + local: + path: src/main/java + - function_name: + - prefix: java + language: java + source: + github: + owner: openjdk + repo: jdk + ref: jdk-17+0 + path: src/java.base/share/classes + - function_name: + - prefix: org/springframework/http + - prefix: org/springframework/web + language: java + source: + github: + owner: spring-projects + repo: spring-framework + ref: v5.3.20 + path: spring-web/src/main/java + - function_name: + - prefix: org/springframework/web/servlet + language: java + source: + github: + owner: spring-projects + repo: spring-framework + ref: v5.3.20 + path: spring-webmvc/src/main/java +` + +const goPyroscopeYAML = `--- +source_code: + mappings: + - path: + - prefix: $GOROOT/src + language: go + source: + github: + owner: golang + repo: go + ref: go1.24.8 + path: src +` + +const goPyroscopeYAMLBazel = `--- +source_code: + mappings: + - path: + - prefix: external/gazelle++go_deps+com_github_stretchr_testify + language: go + source: + github: + owner: stretchr + repo: testify + ref: v1.10.0 +` + +const pythonPyroscopeYAML = `--- +source_code: + mappings: + - path: + - prefix: /app/myproject + language: python + source: + local: + path: src +` + +const javascriptPyroscopeYAML = `--- +source_code: + mappings: + - path: + - prefix: /usr/src/app + language: javascript + source: + local: + path: src/paymentservice +` + +// TestFileFinder_Find tests the complete happy path integration for find.go using table-driven tests +func TestFileFinder_Find(t *testing.T) { + tests := []struct { + name string + fileSpec config.FileSpec + owner string + repo string + ref string + rootPath string + pyroscopeYAML string + mockFiles []mockFileResponse + expectedContent string + expectedURL string + expectedError bool + }{ + // Java tests + { + name: "java/mapped-local-path", + fileSpec: config.FileSpec{ + FunctionName: "org/example/rideshare/RideShareController.orderCar", + }, + rootPath: "examples/language-sdk-instrumentation/java/rideshare", + ref: "main", + pyroscopeYAML: javaPyroscopeYAML, + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Repo: "pyroscope", + Path: "examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/RideShareController.java", + Ref: "main", + }, + content: "# CONTENT RideShareController.java", + }, + }, + expectedContent: "# CONTENT RideShareController.java", + expectedURL: "https://github.com/grafana/pyroscope/blob/main/examples/language-sdk-instrumentation/java/rideshare/src/main/java/org/example/rideshare/RideShareController.java", + expectedError: false, + }, + { + name: "java/mapped-dependency", + fileSpec: config.FileSpec{ + FunctionName: "java/lang/Math.floorMod", + }, + rootPath: "examples/language-sdk-instrumentation/java/rideshare", + ref: "main", + pyroscopeYAML: javaPyroscopeYAML, + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "openjdk", + Repo: "jdk", + Ref: "jdk-17+0", + Path: "src/java.base/share/classes/java/lang/Math.java", + }, + content: "# CONTENT Math.java", + }, + }, + expectedContent: "# CONTENT Math.java", + expectedURL: "https://github.com/openjdk/jdk/blob/jdk-17+0/src/java.base/share/classes/java/lang/Math.java", + expectedError: false, + }, + // Go tests + { + name: "go/not-mapped-local-path", + fileSpec: config.FileSpec{ + FunctionName: "github.com/grafana/pyroscope/v2/pkg/compactionworker.(*Worker).runCompaction", + Path: "/Users/christian/git/github.com/grafana/pyroscope/pkg/compactionworker/worker.go", + }, + ref: "main", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "pyroscope", + Ref: "main", + Path: "pkg/compactionworker/worker.go", + }, + content: "# CONTENT worker.go", + }, + }, + expectedContent: "# CONTENT worker.go", + expectedURL: "https://github.com/grafana/pyroscope/blob/main/pkg/compactionworker/worker.go", + expectedError: false, + }, + { + name: "go/not-mapped-dependency-gomod", + fileSpec: config.FileSpec{ + FunctionName: "github.com/parquet-go/parquet-go.(*bufferPool).newBuffer", + Path: "/Users/christian/.golang/packages/pkg/mod/github.com/parquet-go/parquet-go@v0.23.0/buffer.go", + }, + ref: "main", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Path: "go.mod", + }, + content: ` +module github.com/grafana/pyroscope + +go 1.24.6 + +toolchain go1.24.9 + +require ( + github.com/parquet-go/parquet-go v0.25.0 +) +`, + }, + { + request: client.FileRequest{ + Owner: "parquet-go", + Repo: "parquet-go", + Ref: "v0.25.0", + Path: "buffer.go", + }, + content: "# CONTENT buffer.go", + }, + }, + expectedContent: "# CONTENT buffer.go", + expectedURL: "https://github.com/parquet-go/parquet-go/blob/v0.25.0/buffer.go", + expectedError: false, + }, + { + name: "go/not-mapped-dependency-no-gomod-file", + fileSpec: config.FileSpec{ + FunctionName: "github.com/parquet-go/parquet-go.(*bufferPool).newBuffer", + // without go.mod file in the version of the dependency comes from the file path + Path: "/Users/christian/.golang/packages/pkg/mod/github.com/parquet-go/parquet-go@v0.23.0/buffer.go", + }, + ref: "main", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "parquet-go", + Repo: "parquet-go", + Ref: "v0.23.0", + Path: "buffer.go", + }, + content: "# CONTENT buffer.go", + }, + }, + expectedContent: "# CONTENT buffer.go", + expectedURL: "https://github.com/parquet-go/parquet-go/blob/v0.23.0/buffer.go", + expectedError: false, + }, + { + name: "go/not-mapped-dependency-vendor", + fileSpec: config.FileSpec{ + FunctionName: "github.com/grafana/loki/v3/pkg/iter/v2.(*PeekIter).cacheNext", + Path: "/src/enterprise-logs/vendor/github.com/grafana/loki/v3/pkg/iter/v2/iter.go", + }, + ref: "HEAD", + repo: "enterprise-logs", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "enterprise-logs", + Ref: "HEAD", + Path: "vendor/github.com/grafana/loki/v3/pkg/iter/v2/iter.go", + }, + content: "# CONTENT iter.go", + }, + }, + expectedContent: "# CONTENT iter.go", + expectedURL: "https://github.com/grafana/enterprise-logs/blob/HEAD/vendor/github.com/grafana/loki/v3/pkg/iter/v2/iter.go", + expectedError: false, + }, + { + name: "go/not-mapped-stdlib", + fileSpec: config.FileSpec{ + FunctionName: "bufio.(*Reader).ReadSlice", + Path: "/usr/local/go/src/bufio/bufio.go", + }, + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "golang", + Repo: "go", + Ref: "master", + Path: "src/bufio/bufio.go", + }, + content: "# CONTENT bufio.go", + }, + }, + expectedContent: "# CONTENT bufio.go", + expectedURL: "https://github.com/golang/go/blob/master/src/bufio/bufio.go", + expectedError: false, + }, + { + name: "go/mapped-stdlib", + fileSpec: config.FileSpec{ + FunctionName: "bufio.(*Reader).ReadSlice", + Path: "/usr/local/go/src/bufio/bufio.go", + }, + pyroscopeYAML: goPyroscopeYAML, + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "golang", + Repo: "go", + Ref: "go1.24.8", + Path: "src/bufio/bufio.go", + }, + content: "# CONTENT bufio.go", + }, + }, + expectedContent: "# CONTENT bufio.go", + expectedURL: "https://github.com/golang/go/blob/go1.24.8/src/bufio/bufio.go", + expectedError: false, + }, + { + name: "go/mapped-dependency-bazel", + fileSpec: config.FileSpec{ + FunctionName: "github.com/stretchr/testify/require.NoError", + Path: "external/gazelle++go_deps+com_github_stretchr_testify/require/require.go", + }, + pyroscopeYAML: goPyroscopeYAMLBazel, + owner: "bazel-contrib", + repo: "rules_go", + rootPath: "examples/basic_gazelle", + ref: "v0.59.0", + + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "stretchr", + Repo: "testify", + Ref: "v1.10.0", + Path: "require/require.go", + }, + content: "# CONTENT require.go", + }, + }, + expectedContent: "# CONTENT require.go", + expectedURL: "https://github.com/stretchr/testify/blob/v1.10.0/require/require.go", + expectedError: false, + }, + { + name: "python/stdlib", + fileSpec: config.FileSpec{ + FunctionName: "difflib.SequenceMatcher.find_longest_match", + Path: "/usr/lib/python3.12/difflib.py", + }, + ref: "main", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "python", + Repo: "cpython", + Ref: "3.12", + Path: "Lib/difflib.py", + }, + content: "# CONTENT difflib.py", + }, + }, + expectedContent: "# CONTENT difflib.py", + expectedURL: "https://github.com/python/cpython/blob/3.12/Lib/difflib.py", + expectedError: false, + }, + { + name: "python/mapped-local-path", + fileSpec: config.FileSpec{ + FunctionName: "myproject.main.run", + Path: "/app/myproject/module/main.py", + }, + rootPath: "examples/python-app", + ref: "main", + pyroscopeYAML: pythonPyroscopeYAML, + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "pyroscope", + Ref: "main", + Path: "examples/python-app/src/module/main.py", + }, + content: "# CONTENT main.py", + }, + }, + expectedContent: "# CONTENT main.py", + expectedURL: "https://github.com/grafana/pyroscope/blob/main/examples/python-app/src/module/main.py", + expectedError: false, + }, + { + name: "python/relative-path", + fileSpec: config.FileSpec{ + FunctionName: "ListRecommendations", + Path: "recommendation_server.py", + }, + rootPath: "examples/python-app", + ref: "main", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "pyroscope", + Ref: "main", + Path: "examples/python-app/recommendation_server.py", + }, + content: "# CONTENT recommendation_server.py", + }, + }, + expectedContent: "# CONTENT recommendation_server.py", + expectedURL: "https://github.com/grafana/pyroscope/blob/main/examples/python-app/recommendation_server.py", + expectedError: false, + }, + // JavaScript tests + { + name: "javascript/mapped-local-path", + fileSpec: config.FileSpec{ + FunctionName: "./index.js:chargeServiceHandler:47", + Path: "/usr/src/app/index.js", + }, + owner: "grafana", + repo: "pyroscope", + rootPath: "", + ref: "a35e42d4b114cfada7ef6d53c4a63d6ba44a72d9", + pyroscopeYAML: javascriptPyroscopeYAML, + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "pyroscope", + Ref: "a35e42d4b114cfada7ef6d53c4a63d6ba44a72d9", + Path: "src/paymentservice/index.js", + }, + content: "// CONTENT index.js\nfunction chargeServiceHandler() {}", + }, + }, + expectedContent: "// CONTENT index.js\nfunction chargeServiceHandler() {}", + expectedURL: "https://github.com/grafana/pyroscope/blob/a35e42d4b114cfada7ef6d53c4a63d6ba44a72d9/src/paymentservice/index.js", + expectedError: false, + }, + // TypeScript tests (uses language: javascript) + { + name: "typescript/mapped-local-path", + fileSpec: config.FileSpec{ + FunctionName: "./handler.ts:processPayment:123", + Path: "/usr/src/app/handler.ts", + }, + owner: "grafana", + repo: "pyroscope", + rootPath: "", + ref: "main", + pyroscopeYAML: javascriptPyroscopeYAML, + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "pyroscope", + Ref: "main", + Path: "src/paymentservice/handler.ts", + }, + content: "// CONTENT handler.ts\nexport function processPayment() {}", + }, + }, + expectedContent: "// CONTENT handler.ts\nexport function processPayment() {}", + expectedURL: "https://github.com/grafana/pyroscope/blob/main/src/paymentservice/handler.ts", + expectedError: false, + }, + { + name: "javascript/relative-path", + fileSpec: config.FileSpec{ + FunctionName: "./server.js:handleRequest:10", + Path: "server.js", + }, + rootPath: "examples/nodejs-app", + ref: "main", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "pyroscope", + Ref: "main", + Path: "examples/nodejs-app/server.js", + }, + content: "// CONTENT server.js", + }, + }, + expectedContent: "// CONTENT server.js", + expectedURL: "https://github.com/grafana/pyroscope/blob/main/examples/nodejs-app/server.js", + expectedError: false, + }, + { + name: "fallback/unknown-file-extension", + fileSpec: config.FileSpec{ + FunctionName: "some.function", + Path: "scripts/example.unknown_extension", + }, + ref: "main", + mockFiles: []mockFileResponse{ + { + request: client.FileRequest{ + Owner: "grafana", + Repo: "pyroscope", + Ref: "main", + Path: "scripts/example.unknown_extension", + }, + content: "# Python script content\nprint('hello')", + }, + }, + expectedContent: "# Python script content\nprint('hello')", + expectedURL: "https://github.com/grafana/pyroscope/blob/main/scripts/example.unknown_extension", + expectedError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + + // Setup mock VCS client + mockClient := newMockVCSClient() + + // Populate pyroscopeYAML content into first mock file (if present) + mockFiles := tt.mockFiles + if tt.pyroscopeYAML != "" { + mockFiles = append(mockFiles, mockFileResponse{ + request: client.FileRequest{ + Owner: tt.owner, + Repo: tt.repo, + Ref: tt.ref, + Path: filepath.Join(tt.rootPath, ".pyroscope.yaml"), + }, + content: tt.pyroscopeYAML, + }) + } + mockClient.addFiles(mockFiles...) + + // Setup repository URL + repoURL, err := giturl.NewGitURL(fmt.Sprintf("https://github.com/%s/%s", defaultOwner(tt.owner), defaultRepo(tt.repo))) + require.NoError(t, err) + + // Create HTTP client + httpClient := &http.Client{} + + // Create FileFinder + finder := NewFileFinder( + mockClient, + repoURL, + tt.fileSpec, + tt.rootPath, + defaultRef(tt.ref), + httpClient, + log.NewNopLogger(), + ) + + // Execute the Find method + response, err := finder.Find(ctx) + + // Assertions + if tt.expectedError { + require.Error(t, err) + } else { + require.NoError(t, err, "Find should succeed") + require.NotNil(t, response, "Response should not be nil") + + // Decode and verify content + decodedContent, err := base64.StdEncoding.DecodeString(response.Content) + require.NoError(t, err, "Content should be valid base64") + assert.Equal(t, tt.expectedContent, string(decodedContent), "Content should match expected file") + + // Verify URL + assert.Equal(t, tt.expectedURL, response.URL, "URL should point to correct location") + } + }) + } +} + +// TestFileFinder_Find_FileNotFound tests that Find returns client.ErrNotFound when files are not found +func TestFileFinder_Find_FileNotFound(t *testing.T) { + tests := []struct { + name string + fileSpec config.FileSpec + rootPath string + ref string + pyroscopeYAML string + }{ + { + name: "fallback/file-not-found", + fileSpec: config.FileSpec{ + FunctionName: "some.function", + Path: "nonexistent/file.txt", + }, + ref: "main", + }, + { + name: "go/local-file-not-found", + fileSpec: config.FileSpec{ + FunctionName: "github.com/grafana/pyroscope/pkg/foo.Bar", + Path: "/Users/christian/git/github.com/grafana/pyroscope/pkg/foo/bar.go", + }, + ref: "main", + }, + { + name: "go/stdlib-not-found", + fileSpec: config.FileSpec{ + FunctionName: "bufio.(*Reader).ReadSlice", + Path: "/usr/local/go/src/bufio/bufio.go", + }, + ref: "main", + }, + { + name: "python/stdlib-not-found", + fileSpec: config.FileSpec{ + FunctionName: "difflib.SequenceMatcher.find_longest_match", + Path: "/usr/lib/python3.12/difflib.py", + }, + ref: "main", + }, + { + name: "python/no-stdlib-no-mappings", + fileSpec: config.FileSpec{ + FunctionName: "myapp.module.function", + Path: "/app/myapp/module.py", + }, + ref: "main", + }, + { + name: "python/mappings-file-not-found", + fileSpec: config.FileSpec{ + FunctionName: "myproject.main.run", + Path: "/app/myproject/module/main.py", + }, + rootPath: "examples/python-app", + ref: "main", + pyroscopeYAML: pythonPyroscopeYAML, + }, + { + name: "java/no-mappings", + fileSpec: config.FileSpec{ + FunctionName: "org/example/MyClass.myMethod", + Path: "", + }, + ref: "main", + pyroscopeYAML: `--- +source_code: + mappings: + - function_name: + - prefix: org/example + language: java + source: + local: + path: src/main/java +`, + }, + { + name: "go/dependency-not-found", + fileSpec: config.FileSpec{ + FunctionName: "github.com/parquet-go/parquet-go.(*bufferPool).newBuffer", + Path: "/Users/christian/.golang/packages/pkg/mod/github.com/parquet-go/parquet-go@v0.23.0/buffer.go", + }, + ref: "main", + }, + { + name: "javascript/no-mappings", + fileSpec: config.FileSpec{ + FunctionName: "./app.js:handler:10", + Path: "/usr/src/app/app.js", + }, + ref: "main", + }, + { + name: "javascript/mappings-file-not-found", + fileSpec: config.FileSpec{ + FunctionName: "./missing.js:handler:10", + Path: "/usr/src/app/missing.js", + }, + ref: "main", + pyroscopeYAML: javascriptPyroscopeYAML, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + + // Setup mock VCS client with no files (everything returns ErrNotFound) + mockClient := newMockVCSClient() + + // Add pyroscope.yaml if provided (but no actual source files) + if tt.pyroscopeYAML != "" { + mockClient.addFiles(mockFileResponse{ + request: client.FileRequest{ + Ref: tt.ref, + Path: filepath.Join(tt.rootPath, ".pyroscope.yaml"), + }, + content: tt.pyroscopeYAML, + }) + } + + // Setup repository URL + repoURL, err := giturl.NewGitURL("https://github.com/grafana/pyroscope") + require.NoError(t, err) + + // Create FileFinder + finder := NewFileFinder( + mockClient, + repoURL, + tt.fileSpec, + tt.rootPath, + defaultRef(tt.ref), + &http.Client{}, + log.NewNopLogger(), + ) + + // Execute the Find method + response, err := finder.Find(ctx) + + // Assertions + require.Error(t, err, "Find should return an error when file is not found") + + // Check if error is a connect error with CodeNotFound + var connectErr *connect.Error + if errors.As(err, &connectErr) { + require.Equal(t, connect.CodeNotFound, connectErr.Code(), "Connect error should have CodeNotFound") + } else { + // Fallback check for client.ErrNotFound + require.ErrorIs(t, err, client.ErrNotFound, "Error should be client.ErrNotFound") + } + require.Nil(t, response, "Response should be nil when file is not found") + }) + } +} diff --git a/pkg/frontend/vcs/source/golang/gen.go b/pkg/frontend/vcs/source/golang/gen.go new file mode 100644 index 0000000000..aa626efb69 --- /dev/null +++ b/pkg/frontend/vcs/source/golang/gen.go @@ -0,0 +1,46 @@ +//go:build ignore + +package main + +import ( + "bytes" + "go/format" + "html/template" + "log" + "os" + + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs/source/golang" +) + +func main() { + // todo: In the future we might want to support more than one version + // Or even list all files from standard packages to improve matching. + packages, err := golang.StdPackages("") + if err != nil { + log.Fatal(err) + } + t := template.Must(template.New("packages").Parse(packagesTemplate)) + var buff bytes.Buffer + if err = t.Execute(&buff, packages); err != nil { + log.Fatal(err) + } + formatted, err := format.Source(buff.Bytes()) + if err != nil { + log.Fatal(err) + } + err = os.WriteFile("packages_gen.go", formatted, 0666) + if err != nil { + log.Fatal(err) + } +} + +var packagesTemplate = ` +package golang +// Code generated. DO NOT EDIT. + +var StandardPackages = map[string]struct{}{ + {{- range $key, $value := .}} + "{{$key}}": {}, + {{- end}} +} +` diff --git a/pkg/frontend/vcs/source/golang/golang.go b/pkg/frontend/vcs/source/golang/golang.go new file mode 100644 index 0000000000..a343b9d498 --- /dev/null +++ b/pkg/frontend/vcs/source/golang/golang.go @@ -0,0 +1,65 @@ +package golang + +import ( + "path/filepath" + "strings" + + "github.com/grafana/regexp" +) + +const ( + vendorPath = "vendor/" + stdLocal = "/usr/local/go/src/" + stdGoRoot = "$GOROOT/src/" +) + +var ( + stdLibRegex = regexp.MustCompile(`.*?\/go\/.*?(?P(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?).*?\/src\/(?P.*)`) + toolchainGoVersion = regexp.MustCompile(`-go(?P[0-9]+\.[0-9]+(?:\.[0-9]+)?(?:rc[0-9]+|beta[0-9]+)?)(?:\.|-)`) +) + +// IsStandardLibraryPath returns the cleaned path of the standard library package and a potential version if detected +func IsStandardLibraryPath(path string) (string, string, bool) { + if len(path) == 0 { + return "", "", false + } + + // match toolchain go mod paths + if modFile, ok := ParseModuleFromPath(path); ok && modFile.Path == "golang.org/toolchain" { + // figure out version + matches := toolchainGoVersion.FindStringSubmatch(modFile.Version.Version) + if len(matches) > 1 { + return strings.TrimPrefix(modFile.FilePath, "src/"), matches[1], true + } + } + + if stdLibRegex.MatchString(path) { + matches := stdLibRegex.FindStringSubmatch(path) + version := matches[stdLibRegex.SubexpIndex("version")] + path = matches[stdLibRegex.SubexpIndex("path")] + return path, version, true + } + + path = strings.TrimPrefix(path, stdLocal) + path = strings.TrimPrefix(path, stdGoRoot) + fileName := filepath.Base(path) + packageName := strings.TrimSuffix(path, "/"+fileName) + isStdVendor := strings.HasPrefix(packageName, vendorPath) + + if _, isStd := StandardPackages[packageName]; !isStdVendor && !isStd { + return "", "", false + } + return path, "", true +} + +// VendorRelativePath returns the relative path of the given path +// if it is a vendor path. +// For example: +// /drone/src/vendor/google.golang.org/protobuf/proto/merge.go -> /vendor/google.golang.org/protobuf/proto/merge.go +func VendorRelativePath(path string) (string, bool) { + idx := strings.Index(path, "/"+vendorPath) + if idx < 0 { + return "", false + } + return path[idx:], true +} diff --git a/pkg/frontend/vcs/source/golang/golang_test.go b/pkg/frontend/vcs/source/golang/golang_test.go new file mode 100644 index 0000000000..703b39b0fb --- /dev/null +++ b/pkg/frontend/vcs/source/golang/golang_test.go @@ -0,0 +1,106 @@ +package golang + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestIsStandardLibraryPath(t *testing.T) { + for _, tt := range []struct { + input string + expectedPath string + expectedVersion string + expectedOk bool + }{ + { + input: "github.com/grafana/grafana/pkg/frontend/vcs.go", + expectedOk: false, + }, + { + input: "/usr/local/go/src/bufio/bufio.go", + expectedPath: "bufio/bufio.go", + expectedOk: true, + }, + { + input: "$GOROOT/src/unicode/utf8/utf8.go", + expectedPath: "unicode/utf8/utf8.go", + expectedOk: true, + }, + { + input: "fmt/scan.go", + expectedPath: "fmt/scan.go", + expectedOk: true, + }, + { + input: "$GOROOT/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go", + expectedPath: "vendor/golang.org/x/crypto/cryptobyte/asn1.go", + expectedOk: true, + }, + { + input: "/usr/local/go/src/vendor/golang.org/x/net/http2/hpack/tables.go", + expectedPath: "vendor/golang.org/x/net/http2/hpack/tables.go", + expectedOk: true, + }, + { + input: "/usr/local/Cellar/go/1.21.3/libexec/src/runtime/netpoll_kqueue.go", + expectedPath: "runtime/netpoll_kqueue.go", + expectedVersion: "1.21.3", + expectedOk: true, + }, + { + input: "/opt/hostedtoolcache/go/1.21.6/x64/src/runtime/mgc.go", + expectedPath: "runtime/mgc.go", + expectedVersion: "1.21.6", + expectedOk: true, + }, + { + input: "/Users/pyroscope/.golang/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.24.6.darwin-arm64/src/runtime/proc.go", + expectedPath: "runtime/proc.go", + expectedVersion: "1.24.6", + expectedOk: true, + }, + { + input: "/Users/christian/.golang/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.25rc1.darwin-arm64/src/runtime/type.go", + expectedPath: "runtime/type.go", + expectedVersion: "1.25rc1", + expectedOk: true, + }, + } { + t.Run(tt.input, func(t *testing.T) { + actualPath, actualVersion, ok := IsStandardLibraryPath(tt.input) + if !tt.expectedOk { + require.False(t, ok) + } + require.Equal(t, tt.expectedPath, actualPath) + require.Equal(t, tt.expectedVersion, actualVersion) + }) + } +} + +func TestVendorRelativePath(t *testing.T) { + for _, tt := range []struct { + in string + expected string + expectedOk bool + }{ + { + in: "/drone/src/vendor/google.golang.org/protobuf/proto/merge.go", + expected: "/vendor/google.golang.org/protobuf/proto/merge.go", + expectedOk: true, + }, + { + in: "google.golang.org/protobuf/proto/merge.go", + expected: "", + expectedOk: false, + }, + } { + t.Run(tt.in, func(t *testing.T) { + actual, ok := VendorRelativePath(tt.in) + if !tt.expectedOk { + require.False(t, ok) + } + require.Equal(t, tt.expected, actual) + }) + } +} diff --git a/pkg/frontend/vcs/source/golang/modules.go b/pkg/frontend/vcs/source/golang/modules.go new file mode 100644 index 0000000000..9c937295f8 --- /dev/null +++ b/pkg/frontend/vcs/source/golang/modules.go @@ -0,0 +1,328 @@ +package golang + +import ( + "context" + "fmt" + "net/http" + "path/filepath" + "regexp" + "strings" + + "connectrpc.com/connect" + "github.com/PuerkitoBio/goquery" + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +const ( + GoMod = "go.mod" + + GitHubPath = "github.com/" + GooglePath = "go.googlesource.com/" + GoPkgInPath = "gopkg.in/" +) + +var versionSuffixRE = regexp.MustCompile(`/v[0-9]+[/]*`) + +// Module represents a go module with a file path in that module +type Module struct { + module.Version + FilePath string +} + +// ParseModuleFromPath parses the module from the given path. +func ParseModuleFromPath(path string) (Module, bool) { + parts := strings.Split(path, "@v") + if len(parts) != 2 { + return Module{}, false + } + first := strings.Index(parts[1], "/") + if first < 0 { + return Module{}, false + } + filePath := parts[1][first+1:] + modulePath := parts[0] + + // The go mod folder typically starts with "pkg/mod". If that segment can be found, shorten the module path, so no other folders with dots get accidentally picked up. + if pos := strings.Index(modulePath, "/pkg/mod/"); pos > 0 { + modulePath = modulePath[pos:] + } + + // searching for the first domain name + domainParts := strings.Split(modulePath, "/") + for i, part := range domainParts { + if strings.Contains(part, ".") { + return Module{ + Version: module.Version{ + Path: strings.Join(domainParts[i:], "/"), + Version: "v" + parts[1][:first], + }, + FilePath: filePath, + }, true + } + } + return Module{}, false +} + +func (m Module) IsGitHub() bool { + return strings.HasPrefix(m.Path, GitHubPath) +} + +func (m Module) IsGoogleSource() bool { + return strings.HasPrefix(m.Path, GooglePath) +} + +func (m Module) IsGoPkgIn() bool { + return strings.HasPrefix(m.Path, GoPkgInPath) +} + +func (m Module) String() string { + return fmt.Sprintf("%s@%s", m.Path, m.Version) +} + +type HttpClient interface { + Do(req *http.Request) (*http.Response, error) +} + +// Resolve resolves the module path to a canonical path. +func (module *Module) Resolve(ctx context.Context, mainModule module.Version, modfile *modfile.File, httpClient HttpClient) error { + if modfile != nil { + mainModule.Path = modfile.Module.Mod.Path + module.applyGoMod(mainModule, modfile) + } + if err := module.resolveVanityURL(ctx, httpClient); err != nil { + return err + } + // remove version suffix such as /v2 or /v11 ... + module.Path = versionSuffixRE.ReplaceAllString(module.Path, "") + return nil +} + +func (module *Module) resolveVanityURL(ctx context.Context, httpClient HttpClient) error { + switch { + // no need to resolve vanity URL + case module.IsGitHub(): + return nil + case module.IsGoPkgIn(): + return module.resolveGoPkgIn() + default: + return module.resolveGoGet(ctx, httpClient) + } +} + +// resolveGoGet resolves the module path using go-get meta tags. +// normally go-import meta tag should be used to resolve vanity. +// +// curl -v 'https://google.golang.org/protobuf?go-get=1' +// +// careful follow redirect see: curl -L -v 'connectrpc.com/connect?go-get=1' +// if go-source meta tag is present prefer it over go-import. +// see https://go.dev/ref/mod#vcs-find +func (module *Module) resolveGoGet(ctx context.Context, httpClient HttpClient) error { + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://%s?go-get=1", strings.TrimRight(module.Path, "/")), nil) + if err != nil { + return err + } + resp, err := httpClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return connect.NewError(connect.CodeNotFound, fmt.Errorf("failed to fetch go lib %s: %s", module.Path, resp.Status)) + } + + // look for go-source meta tag first + doc, err := goquery.NewDocumentFromReader(resp.Body) + if err != nil { + return err + } + var found bool + // + doc.Find("meta[name='go-source']").Each(func(i int, s *goquery.Selection) { + content, ok := s.Attr("content") + if !ok { + return + } + content = cleanWhiteSpace(content) + parts := strings.Split(content, " ") + if len(parts) < 2 { + return + } + + // prefer github if available in go-source + if !found && strings.Contains(module.Path, parts[0]) && strings.Contains(parts[1], "github.com/") { + found = true + subPath := strings.Replace(module.Path, parts[0], "", 1) + module.Path = filepath.Join(strings.TrimRight( + strings.TrimPrefix( + strings.TrimPrefix(parts[1], "https://"), + "http://", + ), "/"), + subPath, + ) + + } + }) + if found { + return nil + } + // + // + // + doc.Find("meta[name='go-import']").Each(func(i int, s *goquery.Selection) { + content, ok := s.Attr("content") + if !ok { + return + } + parts := strings.Split(cleanWhiteSpace(content), " ") + if len(parts) < 3 { + return + } + + if !found && strings.Contains(module.Path, parts[0]) && parts[1] == "git" { + found = true + subPath := strings.Replace(module.Path, parts[0], "", 1) + module.Path = filepath.Join(strings.TrimRight( + strings.TrimPrefix( + strings.TrimPrefix(parts[2], "https://"), + "http://", + ), "/"), + subPath, + ) + + } + }) + return nil +} + +// resolveGoPkgIn resolves the gopkg.in path to a github path. +// see https://labix.org/gopkg.in +// gopkg.in/pkg.v3 → github.com/go-pkg/pkg (branch/tag v3, v3.N, or v3.N.M) +// gopkg.in/user/pkg.v3 → github.com/user/pkg (branch/tag v3, v3.N, or v3.N.M) +func (module *Module) resolveGoPkgIn() error { + parts := strings.Split(module.Path, "/") + if len(parts) < 2 { + return fmt.Errorf("invalid gopkg.in path: %s", module.Path) + } + packageNameParts := strings.Split(parts[len(parts)-1], ".") + if len(packageNameParts) < 2 || packageNameParts[0] == "" { + return fmt.Errorf("invalid gopkg.in path: %s", module.Path) + } + switch len(parts) { + case 2: + module.Path = fmt.Sprintf("github.com/go-%s/%s", packageNameParts[0], packageNameParts[0]) + case 3: + module.Path = fmt.Sprintf("github.com/%s/%s", parts[1], packageNameParts[0]) + default: + return fmt.Errorf("invalid gopkg.in path: %s", module.Path) + } + return nil +} + +// applyGoMod applies the go.mod file to the module. +func (module *Module) applyGoMod(mainModule module.Version, modf *modfile.File) { + for _, req := range modf.Require { + if req.Mod.Path == module.Path { + module.Version.Version = req.Mod.Version + } + } + for _, req := range modf.Replace { + if req.Old.Path == module.Path { + module.Path = req.New.Path + module.Version.Version = req.New.Version + } + } + if strings.HasPrefix(module.Path, "./") { + module.Version.Version = mainModule.Version + module.Path = filepath.Join(mainModule.Path, module.Path) + } +} + +type GitHubFile struct { + Owner, Repo, Ref, Path string +} + +// GithubFile returns the github file information. +func (m Module) GithubFile() (GitHubFile, error) { + if !m.IsGitHub() { + return GitHubFile{}, fmt.Errorf("invalid github URL: %s", m.Path) + } + version, err := refFromVersion(m.Version.Version) + if err != nil { + return GitHubFile{}, err + } + if version == "" { + version = "main" + } + parts := strings.Split(m.Path, "/") + if len(parts) < 3 { + return GitHubFile{}, fmt.Errorf("invalid github URL: %s", m.Path) + } + return GitHubFile{ + // ! character is used for capitalization + // example: github.com/!f!zambia/eagle@v0.0.2/eagle.go + Owner: strings.ReplaceAll(parts[1], "!", ""), + Repo: parts[2], + Ref: version, + Path: filepath.Join(strings.Join(parts[3:], "/"), m.FilePath), + }, nil +} + +// GoogleSourceURL returns the URL of the file in the google source repository. +// Example https://go.googlesource.com/oauth2/+/4ce7bbb2ffdc6daed06e2ec28916fd08d96bc3ea/amazon/amazon.go +func (m Module) GoogleSourceURL() (string, error) { + if !m.IsGoogleSource() { + return "", fmt.Errorf("invalid google source path: %s", m.Path) + } + parts := strings.Split(strings.Trim(m.Path, "/"), "/") + if len(parts) < 2 { + return "", fmt.Errorf("invalid google source path: %s", m.Path) + } + projectName := parts[1] + filePath := m.FilePath + extraPath := strings.Join(parts[2:], "/") + if extraPath != "" { + filePath = filepath.Join(extraPath, filePath) + } + version, err := refFromVersion(m.Version.Version) + if err != nil { + return "", err + } + if version == "" { + version = "master" + } + return fmt.Sprintf("https://go.googlesource.com/%s/+/%s/%s?format=TEXT", projectName, version, filePath), nil +} + +// refFromVersion returns the git ref from the given module version. +func refFromVersion(version string) (string, error) { + if module.IsPseudoVersion(version) { + rev, err := module.PseudoVersionRev(version) + if err != nil { + return "", err + } + return rev, nil + } + if sem := semver.Canonical(version); sem != "" { + return sem, nil + } + + return version, nil +} + +// cleanWhiteSpace removes all white space characters from the given string. +func cleanWhiteSpace(s string) string { + space := false + return strings.Map(func(r rune) rune { + if r == '\n' || r == '\t' { + return -1 + } + if r == ' ' && space { + return -1 + } + space = r == ' ' + return r + }, s) +} diff --git a/pkg/querier/vcs/source/golang/modules_test.go b/pkg/frontend/vcs/source/golang/modules_test.go similarity index 95% rename from pkg/querier/vcs/source/golang/modules_test.go rename to pkg/frontend/vcs/source/golang/modules_test.go index 6c30f06107..6aefffc3ad 100644 --- a/pkg/querier/vcs/source/golang/modules_test.go +++ b/pkg/frontend/vcs/source/golang/modules_test.go @@ -104,6 +104,28 @@ func TestParseModulePath(t *testing.T) { false, Module{}, }, + { + "/Users/pyroscope/.golang/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.24.6.darwin-arm64/src/net/http/server.go", + true, + Module{ + Version: module.Version{ + Path: "golang.org/toolchain", + Version: "v0.0.1-go1.24.6.darwin-arm64", + }, + FilePath: "src/net/http/server.go", + }, + }, + { + "/Users/pyroscope/.golang/packages/pkg/mod/github.com/opentracing-contrib/go-stdlib@v1.0.0/nethttp/server.go", + true, + Module{ + Version: module.Version{ + Path: "github.com/opentracing-contrib/go-stdlib", + Version: "v1.0.0", + }, + FilePath: "nethttp/server.go", + }, + }, } { t.Run(tt.input, func(t *testing.T) { mod, ok := ParseModuleFromPath(tt.input) @@ -314,7 +336,7 @@ func Test_Resolve(t *testing.T) { { in: Module{ Version: module.Version{ - Path: "gopkg.in/alecthomas/kingpin.v2", + Path: "github.com/alecthomas/kingpin/v2", }, }, main: mainModule, diff --git a/pkg/querier/vcs/source/golang/packages.go b/pkg/frontend/vcs/source/golang/packages.go similarity index 100% rename from pkg/querier/vcs/source/golang/packages.go rename to pkg/frontend/vcs/source/golang/packages.go diff --git a/pkg/frontend/vcs/source/golang/packages_gen.go b/pkg/frontend/vcs/source/golang/packages_gen.go new file mode 100644 index 0000000000..d3532a03e5 --- /dev/null +++ b/pkg/frontend/vcs/source/golang/packages_gen.go @@ -0,0 +1,358 @@ +package golang + +// Code generated. DO NOT EDIT. + +var StandardPackages = map[string]struct{}{ + "archive/tar": {}, + "archive/zip": {}, + "bufio": {}, + "builtin": {}, + "bytes": {}, + "cmp": {}, + "compress/bzip2": {}, + "compress/flate": {}, + "compress/gzip": {}, + "compress/lzw": {}, + "compress/zlib": {}, + "container/heap": {}, + "container/list": {}, + "container/ring": {}, + "context": {}, + "crypto": {}, + "crypto/aes": {}, + "crypto/cipher": {}, + "crypto/des": {}, + "crypto/dsa": {}, + "crypto/ecdh": {}, + "crypto/ecdsa": {}, + "crypto/ed25519": {}, + "crypto/elliptic": {}, + "crypto/fips140": {}, + "crypto/hkdf": {}, + "crypto/hmac": {}, + "crypto/hpke": {}, + "crypto/internal/boring": {}, + "crypto/internal/boring/bbig": {}, + "crypto/internal/boring/bcache": {}, + "crypto/internal/boring/sig": {}, + "crypto/internal/constanttime": {}, + "crypto/internal/cryptotest": {}, + "crypto/internal/entropy": {}, + "crypto/internal/entropy/v1.0.0": {}, + "crypto/internal/fips140": {}, + "crypto/internal/fips140/aes": {}, + "crypto/internal/fips140/aes/gcm": {}, + "crypto/internal/fips140/alias": {}, + "crypto/internal/fips140/bigmod": {}, + "crypto/internal/fips140/check": {}, + "crypto/internal/fips140/check/checktest": {}, + "crypto/internal/fips140/drbg": {}, + "crypto/internal/fips140/ecdh": {}, + "crypto/internal/fips140/ecdsa": {}, + "crypto/internal/fips140/ed25519": {}, + "crypto/internal/fips140/edwards25519": {}, + "crypto/internal/fips140/edwards25519/field": {}, + "crypto/internal/fips140/hkdf": {}, + "crypto/internal/fips140/hmac": {}, + "crypto/internal/fips140/mldsa": {}, + "crypto/internal/fips140/mlkem": {}, + "crypto/internal/fips140/nistec": {}, + "crypto/internal/fips140/nistec/fiat": {}, + "crypto/internal/fips140/pbkdf2": {}, + "crypto/internal/fips140/rsa": {}, + "crypto/internal/fips140/sha256": {}, + "crypto/internal/fips140/sha3": {}, + "crypto/internal/fips140/sha512": {}, + "crypto/internal/fips140/ssh": {}, + "crypto/internal/fips140/subtle": {}, + "crypto/internal/fips140/tls12": {}, + "crypto/internal/fips140/tls13": {}, + "crypto/internal/fips140cache": {}, + "crypto/internal/fips140deps": {}, + "crypto/internal/fips140deps/byteorder": {}, + "crypto/internal/fips140deps/cpu": {}, + "crypto/internal/fips140deps/godebug": {}, + "crypto/internal/fips140deps/time": {}, + "crypto/internal/fips140hash": {}, + "crypto/internal/fips140only": {}, + "crypto/internal/impl": {}, + "crypto/internal/rand": {}, + "crypto/internal/randutil": {}, + "crypto/internal/sysrand": {}, + "crypto/internal/sysrand/internal/seccomp": {}, + "crypto/md5": {}, + "crypto/mlkem": {}, + "crypto/mlkem/mlkemtest": {}, + "crypto/pbkdf2": {}, + "crypto/rand": {}, + "crypto/rc4": {}, + "crypto/rsa": {}, + "crypto/sha1": {}, + "crypto/sha256": {}, + "crypto/sha3": {}, + "crypto/sha512": {}, + "crypto/subtle": {}, + "crypto/tls": {}, + "crypto/tls/internal/fips140tls": {}, + "crypto/x509": {}, + "crypto/x509/internal/macos": {}, + "crypto/x509/pkix": {}, + "database/sql": {}, + "database/sql/driver": {}, + "debug/buildinfo": {}, + "debug/dwarf": {}, + "debug/elf": {}, + "debug/gosym": {}, + "debug/macho": {}, + "debug/pe": {}, + "debug/plan9obj": {}, + "embed": {}, + "encoding": {}, + "encoding/ascii85": {}, + "encoding/asn1": {}, + "encoding/base32": {}, + "encoding/base64": {}, + "encoding/binary": {}, + "encoding/csv": {}, + "encoding/gob": {}, + "encoding/hex": {}, + "encoding/json": {}, + "encoding/json/jsontext": {}, + "encoding/json/v2": {}, + "encoding/pem": {}, + "encoding/xml": {}, + "errors": {}, + "expvar": {}, + "flag": {}, + "fmt": {}, + "go/ast": {}, + "go/build": {}, + "go/build/constraint": {}, + "go/constant": {}, + "go/doc": {}, + "go/doc/comment": {}, + "go/format": {}, + "go/importer": {}, + "go/internal/gccgoimporter": {}, + "go/internal/gcimporter": {}, + "go/internal/scannerhooks": {}, + "go/internal/srcimporter": {}, + "go/parser": {}, + "go/printer": {}, + "go/scanner": {}, + "go/token": {}, + "go/types": {}, + "go/version": {}, + "hash": {}, + "hash/adler32": {}, + "hash/crc32": {}, + "hash/crc64": {}, + "hash/fnv": {}, + "hash/maphash": {}, + "html": {}, + "html/template": {}, + "image": {}, + "image/color": {}, + "image/color/palette": {}, + "image/draw": {}, + "image/gif": {}, + "image/internal/imageutil": {}, + "image/jpeg": {}, + "image/png": {}, + "index/suffixarray": {}, + "internal/abi": {}, + "internal/asan": {}, + "internal/bisect": {}, + "internal/buildcfg": {}, + "internal/bytealg": {}, + "internal/byteorder": {}, + "internal/cfg": {}, + "internal/cgrouptest": {}, + "internal/chacha8rand": {}, + "internal/coverage": {}, + "internal/coverage/calloc": {}, + "internal/coverage/cfile": {}, + "internal/coverage/cformat": {}, + "internal/coverage/cmerge": {}, + "internal/coverage/decodecounter": {}, + "internal/coverage/decodemeta": {}, + "internal/coverage/encodecounter": {}, + "internal/coverage/encodemeta": {}, + "internal/coverage/pods": {}, + "internal/coverage/rtcov": {}, + "internal/coverage/slicereader": {}, + "internal/coverage/slicewriter": {}, + "internal/coverage/stringtab": {}, + "internal/coverage/uleb128": {}, + "internal/cpu": {}, + "internal/dag": {}, + "internal/diff": {}, + "internal/exportdata": {}, + "internal/filepathlite": {}, + "internal/fmtsort": {}, + "internal/fuzz": {}, + "internal/goarch": {}, + "internal/godebug": {}, + "internal/godebugs": {}, + "internal/goexperiment": {}, + "internal/goos": {}, + "internal/goroot": {}, + "internal/gover": {}, + "internal/goversion": {}, + "internal/lazyregexp": {}, + "internal/lazytemplate": {}, + "internal/msan": {}, + "internal/nettrace": {}, + "internal/obscuretestdata": {}, + "internal/oserror": {}, + "internal/pkgbits": {}, + "internal/platform": {}, + "internal/poll": {}, + "internal/profile": {}, + "internal/profilerecord": {}, + "internal/race": {}, + "internal/reflectlite": {}, + "internal/routebsd": {}, + "internal/runtime/atomic": {}, + "internal/runtime/cgobench": {}, + "internal/runtime/cgroup": {}, + "internal/runtime/exithook": {}, + "internal/runtime/gc": {}, + "internal/runtime/gc/internal/gen": {}, + "internal/runtime/gc/scan": {}, + "internal/runtime/maps": {}, + "internal/runtime/math": {}, + "internal/runtime/pprof/label": {}, + "internal/runtime/startlinetest": {}, + "internal/runtime/sys": {}, + "internal/runtime/syscall/linux": {}, + "internal/runtime/syscall/windows": {}, + "internal/saferio": {}, + "internal/singleflight": {}, + "internal/strconv": {}, + "internal/stringslite": {}, + "internal/sync": {}, + "internal/synctest": {}, + "internal/syscall/execenv": {}, + "internal/syscall/unix": {}, + "internal/syscall/windows": {}, + "internal/syscall/windows/registry": {}, + "internal/syscall/windows/sysdll": {}, + "internal/sysinfo": {}, + "internal/syslist": {}, + "internal/testenv": {}, + "internal/testhash": {}, + "internal/testlog": {}, + "internal/testpty": {}, + "internal/trace": {}, + "internal/trace/internal/testgen": {}, + "internal/trace/internal/tracev1": {}, + "internal/trace/raw": {}, + "internal/trace/testtrace": {}, + "internal/trace/tracev2": {}, + "internal/trace/traceviewer": {}, + "internal/trace/traceviewer/format": {}, + "internal/trace/version": {}, + "internal/txtar": {}, + "internal/types/errors": {}, + "internal/unsafeheader": {}, + "internal/xcoff": {}, + "internal/zstd": {}, + "io": {}, + "io/fs": {}, + "io/ioutil": {}, + "iter": {}, + "log": {}, + "log/internal": {}, + "log/slog": {}, + "log/slog/internal": {}, + "log/slog/internal/benchmarks": {}, + "log/slog/internal/buffer": {}, + "log/syslog": {}, + "maps": {}, + "math": {}, + "math/big": {}, + "math/big/internal/asmgen": {}, + "math/bits": {}, + "math/cmplx": {}, + "math/rand": {}, + "math/rand/v2": {}, + "mime": {}, + "mime/multipart": {}, + "mime/quotedprintable": {}, + "net": {}, + "net/http": {}, + "net/http/cgi": {}, + "net/http/cookiejar": {}, + "net/http/fcgi": {}, + "net/http/httptest": {}, + "net/http/httptrace": {}, + "net/http/httputil": {}, + "net/http/internal": {}, + "net/http/internal/ascii": {}, + "net/http/internal/httpcommon": {}, + "net/http/internal/testcert": {}, + "net/http/pprof": {}, + "net/internal/cgotest": {}, + "net/internal/socktest": {}, + "net/mail": {}, + "net/netip": {}, + "net/rpc": {}, + "net/rpc/jsonrpc": {}, + "net/smtp": {}, + "net/textproto": {}, + "net/url": {}, + "os": {}, + "os/exec": {}, + "os/exec/internal/fdtest": {}, + "os/signal": {}, + "os/user": {}, + "path": {}, + "path/filepath": {}, + "plugin": {}, + "reflect": {}, + "reflect/internal/example1": {}, + "reflect/internal/example2": {}, + "regexp": {}, + "regexp/syntax": {}, + "runtime": {}, + "runtime/cgo": {}, + "runtime/coverage": {}, + "runtime/debug": {}, + "runtime/metrics": {}, + "runtime/pprof": {}, + "runtime/race": {}, + "runtime/race/internal/amd64v1": {}, + "runtime/secret": {}, + "runtime/trace": {}, + "simd/archsimd": {}, + "slices": {}, + "sort": {}, + "strconv": {}, + "strings": {}, + "structs": {}, + "sync": {}, + "sync/atomic": {}, + "syscall": {}, + "syscall/js": {}, + "testing": {}, + "testing/cryptotest": {}, + "testing/fstest": {}, + "testing/internal/testdeps": {}, + "testing/iotest": {}, + "testing/quick": {}, + "testing/slogtest": {}, + "testing/synctest": {}, + "text/scanner": {}, + "text/tabwriter": {}, + "text/template": {}, + "text/template/parse": {}, + "time": {}, + "time/tzdata": {}, + "unicode": {}, + "unicode/utf16": {}, + "unicode/utf8": {}, + "unique": {}, + "unsafe": {}, + "weak": {}, +} diff --git a/pkg/frontend/vcs/token.go b/pkg/frontend/vcs/token.go new file mode 100644 index 0000000000..ec6fc30dc1 --- /dev/null +++ b/pkg/frontend/vcs/token.go @@ -0,0 +1,190 @@ +package vcs + +import ( + "context" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "strconv" + "time" + + "connectrpc.com/connect" + "golang.org/x/oauth2" + + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +const ( + sessionCookieName = "pyroscope_git_session" +) + +// Deprecated: this is the old format for encoded token inside a cookie +// Remove after completing https://github.com/grafana/explore-profiles/issues/187 +type deprecatedGitSessionTokenCookie struct { + Metadata string `json:"metadata"` + ExpiryTimestamp int64 `json:"expiry"` +} + +type gitSessionTokenCookie struct { + Token *string `json:"token"` +} + +const envVarGithubSessionSecret = "GITHUB_SESSION_SECRET" + +var githubSessionSecret = []byte(os.Getenv(envVarGithubSessionSecret)) + +// derives a per tenant key from the global session secret using sha256 +func deriveEncryptionKeyForContext(ctx context.Context) ([]byte, error) { + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return nil, err + } + if len(tenantID) == 0 { + return nil, errors.New("tenantID is empty") + } + + if len(githubSessionSecret) == 0 { + return nil, errors.New(envVarGithubSessionSecret + " is empty") + } + h := sha256.New() + h.Write(githubSessionSecret) + h.Write([]byte{':'}) + h.Write([]byte(tenantID)) + return h.Sum(nil), nil +} + +// getStringValueFrom gets a string value from url.Values. It will fail if the +// key is missing or the key's value is an empty string. +func getStringValueFrom(values url.Values, key string) (string, error) { + value := values.Get(key) + if value == "" { + return "", fmt.Errorf("missing key: %s", key) + } + return value, nil +} + +// getDurationValueFrom gets a duration value from url.Values. It will fail if +// the key is missing, the key's value is an empty string, or the key's value +// cannot be parsed into a duration. +func getDurationValueFrom(values url.Values, key string, scalar time.Duration) (time.Duration, error) { + if scalar < 1 { + return 0, fmt.Errorf("cannot use scalar less than 1") + } + + value, err := getStringValueFrom(values, key) + if err != nil { + return 0, err + } + + n, err := strconv.Atoi(value) + if err != nil { + return 0, fmt.Errorf("failed to parse %s: %w", key, err) + } + + return time.Duration(n) * scalar, nil +} + +// tokenFromRequest decodes an OAuth token from a request. +func tokenFromRequest(ctx context.Context, req connect.AnyRequest) (*oauth2.Token, error) { + cookie, err := (&http.Request{Header: req.Header()}).Cookie(sessionCookieName) + if err != nil { + return nil, fmt.Errorf("failed to read cookie %s: %w", sessionCookieName, err) + } + + derivedKey, err := deriveEncryptionKeyForContext(ctx) + if err != nil { + return nil, err + } + + token, err := decodeToken(cookie.Value, derivedKey) + if err != nil { + return nil, err + } + return token, nil +} + +// Deprecated: encodeTokenInCookie creates a cookie by encrypting then base64 encoding an OAuth token. +// In future version, the cookie that this function creates will be no longer sent by the backend. +// Instead, backend provides the necessary data so frontend can create its own GitHub session cookie. +// Remove after completing https://github.com/grafana/explore-profiles/issues/187 +func encodeTokenInCookie(token *oauth2.Token, key []byte) (*http.Cookie, error) { + encrypted, err := encryptToken(token, key) + if err != nil { + return nil, err + } + + bytes, err := json.Marshal(deprecatedGitSessionTokenCookie{ + Metadata: encrypted, + ExpiryTimestamp: token.Expiry.UnixMilli(), + }) + if err != nil { + return nil, err + } + + encoded := base64.StdEncoding.EncodeToString(bytes) + cookie := &http.Cookie{ + Name: sessionCookieName, + Value: encoded, + Expires: time.Now().Add(githubRefreshExpiryDuration), + HttpOnly: false, + Secure: true, + SameSite: http.SameSiteLaxMode, + } + return cookie, nil +} + +// decodeToken base64 decodes and decrypts a OAuth token. +func decodeToken(value string, key []byte) (*oauth2.Token, error) { + var token *oauth2.Token + + decoded, err := base64.StdEncoding.DecodeString(value) + if err != nil { + return nil, err + } + + sessionToken := gitSessionTokenCookie{} + err = json.Unmarshal(decoded, &sessionToken) + if err != nil || sessionToken.Token == nil { + // This may be a deprecated cookie. Deprecated cookies are base64 encoded deprecatedGitSessionTokenCookie objects. + token, innerErr := decodeDeprecatedToken(decoded, key) + if innerErr != nil { + // Deprecated fallback failed, return the original error if exists. + if err != nil { + return nil, err + } + return nil, innerErr + } + return token, nil + } + + token, err = decryptToken(*sessionToken.Token, key) + if err != nil { + return nil, err + } + + return token, nil +} + +// Deprecated: decodeDeprecatedToken decrypts a deprecatedGitSessionTokenCookie +// In future version, frontend won't send any deprecated cookies. +// Remove alongside encodeTokenInCookie, after completing https://github.com/grafana/explore-profiles/issues/187 +func decodeDeprecatedToken(value []byte, key []byte) (*oauth2.Token, error) { + var token *oauth2.Token + + sessionToken := &deprecatedGitSessionTokenCookie{} + err := json.Unmarshal(value, sessionToken) + if err != nil || sessionToken == nil { + return nil, err + } + + token, err = decryptToken(sessionToken.Metadata, key) + if err != nil { + return nil, err + } + return token, nil +} diff --git a/pkg/querier/vcs/token_test.go b/pkg/frontend/vcs/token_test.go similarity index 77% rename from pkg/querier/vcs/token_test.go rename to pkg/frontend/vcs/token_test.go index f1e51b06fb..4f6e8150d8 100644 --- a/pkg/querier/vcs/token_test.go +++ b/pkg/frontend/vcs/token_test.go @@ -3,8 +3,10 @@ package vcs import ( "context" "encoding/base64" + "encoding/json" "net/http" "net/url" + "strings" "testing" "time" @@ -13,7 +15,7 @@ import ( "golang.org/x/oauth2" vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" - "github.com/grafana/pyroscope/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) func Test_getStringValueFrom(t *testing.T) { @@ -159,9 +161,31 @@ func Test_tokenFromRequest(t *testing.T) { require.Equal(t, *wantToken, *gotToken) }) + t.Run("legacy token exists in request", func(t *testing.T) { + githubSessionSecret = []byte("16_byte_key_XXXX") + + derivedKey, err := deriveEncryptionKeyForContext(ctx) + require.NoError(t, err) + + wantToken := &oauth2.Token{ + AccessToken: "my_access_token", + TokenType: "my_token_type", + RefreshToken: "my_refresh_token", + Expiry: time.Unix(1713298947, 0).UTC(), // 2024-04-16T20:22:27.346Z + } + + // The type of request here doesn't matter. + req := connect.NewRequest(&vcsv1.GetFileRequest{}) + req.Header().Add("Cookie", testEncodeLegacyCookie(t, derivedKey, wantToken).String()) + + gotToken, err := tokenFromRequest(ctx, req) + require.NoError(t, err) + require.Equal(t, *wantToken, *gotToken) + }) + t.Run("token does not exist in request", func(t *testing.T) { githubSessionSecret = []byte("16_byte_key_XXXX") - wantErr := "failed to read cookie GitSession: http: named cookie not present" + wantErr := "failed to read cookie pyroscope_git_session: http: named cookie not present" // The type of request here doesn't matter. req := connect.NewRequest(&vcsv1.GetFileRequest{}) @@ -170,9 +194,29 @@ func Test_tokenFromRequest(t *testing.T) { require.Error(t, err) require.EqualError(t, err, wantErr) }) + + t.Run("token with garbage should fail", func(t *testing.T) { + githubSessionSecret = []byte("16_byte_key_XXXX") + + // a cookie with false metadata + cookieData, err := json.Marshal(map[string]interface{}{ + "metadata": base64.StdEncoding.EncodeToString([]byte(strings.Repeat("x", 128))), + "expiry": 1234, + }) + require.NoError(t, err) + + req := connect.NewRequest(&vcsv1.GetFileRequest{}) + req.Header().Add("Cookie", "pyroscope_git_session="+base64.RawStdEncoding.EncodeToString(cookieData)) + + token, err := tokenFromRequest(ctx, req) + require.Error(t, err) + require.EqualError(t, err, "cipher: message authentication failed") + require.Nil(t, token) + + }) } -func Test_encodeToken(t *testing.T) { +func Test_encodeTokenInCookie(t *testing.T) { githubSessionSecret = []byte("16_byte_key_XXXX") ctx := newTestContext() @@ -186,7 +230,7 @@ func Test_encodeToken(t *testing.T) { Expiry: time.Unix(1713298947, 0).UTC(), // 2024-04-16T20:22:27.346Z } - got, err := encodeToken(token, derivedKey) + got, err := encodeTokenInCookie(token, derivedKey) require.NoError(t, err) require.Equal(t, sessionCookieName, got.Name) require.NotEmpty(t, got.Value) @@ -258,10 +302,9 @@ func Test_tenantIsolation(t *testing.T) { derivedKeyA, err := deriveEncryptionKeyForContext(ctxA) require.NoError(t, err) - encodedTokenA, err := encodeToken(&oauth2.Token{ + encodedTokenA := testEncodeCookie(t, derivedKeyA, &oauth2.Token{ AccessToken: "so_secret", - }, derivedKeyA) - require.NoError(t, err) + }) req := connect.NewRequest(&vcsv1.GetFileRequest{}) req.Header().Add("Cookie", encodedTokenA.String()) @@ -275,12 +318,12 @@ func Test_tenantIsolation(t *testing.T) { } -func Test_StillCompatbile(t *testing.T) { +func Test_StillCompatible(t *testing.T) { githubSessionSecret = []byte("16_byte_key_XXXX") ctx := newTestContextWithTenantID("tenant_a") req := connect.NewRequest(&vcsv1.GetFileRequest{}) - req.Header().Add("Cookie", "GitSession=eyJtZXRhZGF0YSI6Im12N0d1OHlIanZxdWdQMmF5TnJaYXd1SXNyQXFmUUVIMVhGS1RkejVlZWtob1NRV1JUM3hVZGRuMndUemhQZ05oWktRVkpjcVh5SVJDSnFmTTV3WTJyNmR3R21rZkRhL2FORjhRZ0lJcU1oa1hPbGFEdXNwcFE9PSJ9Cg==") + req.Header().Add("Cookie", "pyroscope_git_session=eyJtZXRhZGF0YSI6Im12N0d1OHlIanZxdWdQMmF5TnJaYXd1SXNyQXFmUUVIMVhGS1RkejVlZWtob1NRV1JUM3hVZGRuMndUemhQZ05oWktRVkpjcVh5SVJDSnFmTTV3WTJyNmR3R21rZkRhL2FORjhRZ0lJcU1oa1hPbGFEdXNwcFE9PSJ9Cg==") realToken, err := tokenFromRequest(ctx, req) require.NoError(t, err) @@ -298,24 +341,32 @@ func newTestContextWithTenantID(tenantID string) context.Context { func testEncodeCookie(t *testing.T, key []byte, token *oauth2.Token) *http.Cookie { t.Helper() - encoded, err := encodeToken(token, key) + encrypted, err := encryptToken(token, key) require.NoError(t, err) - return encoded -} - -func testEncodeLegacyCookie(t *testing.T, key []byte, token *oauth2.Token) *http.Cookie { - t.Helper() + cookieValue := gitSessionTokenCookie{ + Token: &encrypted, + } - encrypted, err := encryptToken(token, key) + jsonString, err := json.Marshal(cookieValue) require.NoError(t, err) + encoded := base64.StdEncoding.EncodeToString(jsonString) return &http.Cookie{ Name: sessionCookieName, - Value: encrypted, + Value: encoded, Expires: token.Expiry, HttpOnly: false, Secure: true, SameSite: http.SameSiteLaxMode, } } + +func testEncodeLegacyCookie(t *testing.T, key []byte, token *oauth2.Token) *http.Cookie { + t.Helper() + + encoded, err := encodeTokenInCookie(token, key) + require.NoError(t, err) + + return encoded +} diff --git a/pkg/ingester/ingester.go b/pkg/ingester/ingester.go index 118e9460da..2e3df58f3c 100644 --- a/pkg/ingester/ingester.go +++ b/pkg/ingester/ingester.go @@ -2,8 +2,12 @@ package ingester import ( "context" + "errors" "flag" "fmt" + "io" + "os" + "path/filepath" "sync" "time" @@ -14,22 +18,21 @@ import ( "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingesterv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - phlareobjclient "github.com/grafana/pyroscope/pkg/objstore/client" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/usagestats" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/validation" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + phlareobjclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/pprof" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/usagestats" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/validation" ) var activeTenantsStats = usagestats.NewInt("ingester_active_tenants") @@ -65,8 +68,9 @@ type Ingester struct { instances map[string]*instance instancesMtx sync.RWMutex - limits Limits - reg prometheus.Registerer + limits Limits + reg prometheus.Registerer + usageGroupEvaluator *validation.UsageGroupEvaluator } type ingesterFlusherCompat struct { @@ -104,6 +108,8 @@ func New(phlarectx context.Context, cfg Config, dbConfig phlaredb.Config, storag return nil, err } + i.usageGroupEvaluator = validation.NewUsageGroupEvaluator(i.logger) + i.lifecycler, err = ring.NewLifecycler( cfg.LifecyclerConfig, &ingesterFlusherCompat{i}, @@ -137,7 +143,7 @@ func New(phlarectx context.Context, cfg Config, dbConfig phlaredb.Config, storag i.subservices, err = services.NewManager(i.lifecycler, dc) } if err != nil { - return nil, errors.Wrap(err, "services manager") + return nil, fmt.Errorf("services manager: %w", err) } i.subservicesWatcher = services.NewFailureWatcher() i.subservicesWatcher.WatchManager(i.subservices) @@ -170,7 +176,7 @@ func (i *Ingester) stopping(_ error) error { return errs.Err() } -func (i *Ingester) GetOrCreateInstance(tenantID string) (*instance, error) { //nolint:revive +func (i *Ingester) getOrCreateInstance(tenantID string) (*instance, error) { inst, ok := i.getInstanceByID(tenantID) if ok { return inst, nil @@ -192,6 +198,54 @@ func (i *Ingester) GetOrCreateInstance(tenantID string) (*instance, error) { //n return inst, nil } +func (i *Ingester) hasLocalBlocks(tenantID string) (bool, error) { + entries, err := os.ReadDir(filepath.Join(i.dbConfig.DataPath, tenantID, "local")) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, err + } + for _, entry := range entries { + if entry.IsDir() { + return true, nil + } + } + return false, nil +} + +func (i *Ingester) getOrOpenInstance(tenantID string) (*instance, error) { + inst, ok := i.getInstanceByID(tenantID) + if ok { + return inst, nil + } + + i.instancesMtx.Lock() + defer i.instancesMtx.Unlock() + inst, ok = i.instances[tenantID] + if ok { + return inst, nil + } + + hasLocalBlocks, err := i.hasLocalBlocks(tenantID) + if err != nil { + return nil, err + } + if !hasLocalBlocks { + return nil, nil + } + + limiter := NewLimiter(tenantID, i.limits, i.lifecycler, i.cfg.LifecyclerConfig.RingConfig.ReplicationFactor) + inst, err = newInstance(i.phlarectx, i.dbConfig, tenantID, i.localBucket, i.storageBucket, limiter) + if err != nil { + return nil, err + } + + i.instances[tenantID] = inst + activeTenantsStats.Set(int64(len(i.instances))) + return inst, nil +} + func (i *Ingester) getInstanceByID(id string) (*instance, bool) { i.instancesMtx.RLock() defer i.instancesMtx.RUnlock() @@ -200,30 +254,58 @@ func (i *Ingester) getInstanceByID(id string) (*instance, bool) { return inst, ok } -// forInstanceUnary executes the given function for the instance with the given tenant ID in the context. -func forInstanceUnary[T any](ctx context.Context, i *Ingester, f func(*instance) (T, error)) (T, error) { +func push[T any](ctx context.Context, i *Ingester, f func(*instance) (T, error)) (T, error) { var res T - err := i.forInstance(ctx, func(inst *instance) error { - r, err := f(inst) - if err == nil { - res = r - } - return err - }) - return res, err + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return res, connect.NewError(connect.CodeInvalidArgument, err) + } + instance, err := i.getOrCreateInstance(tenantID) + if err != nil { + return res, connect.NewError(connect.CodeInternal, err) + } + return f(instance) +} + +// forInstanceUnary executes the given function for the instance with the given tenant ID in the context. +func forInstanceUnary[T any](ctx context.Context, i *Ingester, f func(*instance) (*connect.Response[T], error)) (*connect.Response[T], error) { + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return connect.NewResponse[T](new(T)), connect.NewError(connect.CodeInvalidArgument, err) + } + instance, err := i.getOrOpenInstance(tenantID) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + if instance != nil { + return f(instance) + } + return connect.NewResponse[T](new(T)), nil } -// forInstance executes the given function for the instance with the given tenant ID in the context. -func (i *Ingester) forInstance(ctx context.Context, f func(*instance) error) error { +func forInstanceStream[Req, Resp any](ctx context.Context, i *Ingester, stream *connect.BidiStream[Req, Resp], f func(*instance) error) error { tenantID, err := tenant.ExtractTenantIDFromContext(ctx) if err != nil { return connect.NewError(connect.CodeInvalidArgument, err) } - instance, err := i.GetOrCreateInstance(tenantID) + instance, err := i.getOrOpenInstance(tenantID) if err != nil { return connect.NewError(connect.CodeInternal, err) } - return f(instance) + if instance != nil { + return f(instance) + } + // The client blocks awaiting the response. + if _, err = stream.Receive(); err != nil { + if errors.Is(err, io.EOF) { + return connect.NewError(connect.CodeCanceled, errors.New("client closed stream")) + } + return err + } + if err = stream.Send(new(Resp)); err != nil { + return err + } + return stream.Send(new(Resp)) } func (i *Ingester) evictBlock(tenantID string, b ulid.ULID, fn func() error) (err error) { @@ -252,19 +334,25 @@ func (i *Ingester) evictBlock(tenantID string, b ulid.ULID, fn func() error) (er } func (i *Ingester) Push(ctx context.Context, req *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { - return forInstanceUnary(ctx, i, func(instance *instance) (*connect.Response[pushv1.PushResponse], error) { + return push(ctx, i, func(instance *instance) (*connect.Response[pushv1.PushResponse], error) { + usageGroups := i.limits.DistributorUsageGroups(instance.tenantID) + for _, series := range req.Msg.Series { + groups := i.usageGroupEvaluator.GetMatch(instance.tenantID, usageGroups, series.Labels) + for _, sample := range series.Samples { err := pprof.FromBytes(sample.RawProfile, func(p *profilev1.Profile, size int) error { id, err := uuid.Parse(sample.ID) if err != nil { return err } - if err = instance.Ingest(ctx, p, id, series.Labels...); err != nil { + if err = instance.Ingest(ctx, p, id, series.Annotations, series.Labels...); err != nil { reason := validation.ReasonOf(err) if reason != validation.Unknown { validation.DiscardedProfiles.WithLabelValues(string(reason), instance.tenantID).Add(float64(1)) validation.DiscardedBytes.WithLabelValues(string(reason), instance.tenantID).Add(float64(size)) + groups.CountDiscardedBytes(string(reason), int64(size)) + switch validation.ReasonOf(err) { case validation.SeriesLimit: return connect.NewError(connect.CodeResourceExhausted, err) diff --git a/pkg/ingester/ingester_test.go b/pkg/ingester/ingester_test.go index 4443524975..b3b902acbe 100644 --- a/pkg/ingester/ingester_test.go +++ b/pkg/ingester/ingester_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "os" + "path/filepath" "runtime/pprof" "testing" "time" @@ -20,12 +21,12 @@ import ( pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/tenant" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) func defaultIngesterTestConfig(t testing.TB) Config { @@ -116,3 +117,125 @@ func Test_MultitenantReadWrite(t *testing.T) { require.NoError(t, services.StopAndAwaitTerminated(context.Background(), ing)) } + +func Test_Query_TenantNotFound(t *testing.T) { + dbPath := t.TempDir() + logger := log.NewJSONLogger(os.Stdout) + reg := prometheus.NewRegistry() + ctx := phlarecontext.WithLogger(context.Background(), logger) + ctx = phlarecontext.WithRegistry(ctx, reg) + cfg := client.Config{ + StorageBackendConfig: client.StorageBackendConfig{ + Backend: client.Filesystem, + Filesystem: filesystem.Config{ + Directory: dbPath, + }, + }, + } + + // set the localPath + localPath := t.TempDir() + + // foo has an empty local dir + fooLocalPath := filepath.Join(localPath, "foo", "local") + require.NoError(t, os.MkdirAll(fooLocalPath, 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(fooLocalPath, "shipper.json"), []byte(`{"version":1,"uploaded":null}`), 0o755)) + + fs, err := client.NewBucket(ctx, cfg, "storage") + require.NoError(t, err) + + ing, err := New(ctx, defaultIngesterTestConfig(t), phlaredb.Config{ + DataPath: localPath, + MaxBlockDuration: 30 * time.Hour, + }, fs, &fakeLimits{}, 0) + require.NoError(t, err) + require.NoError(t, services.StartAndAwaitRunning(context.Background(), ing)) + + labelsValues, err := ing.LabelValues(tenant.InjectTenantID(context.Background(), "foo"), connect.NewRequest(&typesv1.LabelValuesRequest{Name: "foo"})) + require.NoError(t, err) + require.Empty(t, labelsValues.Msg.Names) + + labelsNames, err := ing.LabelNames(tenant.InjectTenantID(context.Background(), "buzz"), connect.NewRequest(&typesv1.LabelNamesRequest{})) + require.NoError(t, err) + require.Empty(t, labelsNames.Msg.Names) + + // check that no tenant are initialized + ing.instancesMtx.RLock() + require.Len(t, ing.instances, 0) + ing.instancesMtx.RUnlock() + + require.NoError(t, services.StopAndAwaitTerminated(context.Background(), ing)) +} + +func Test_Query_TenantFound(t *testing.T) { + dbPath := t.TempDir() + logger := log.NewJSONLogger(os.Stdout) + phlareCtx := phlarecontext.WithLogger(context.Background(), logger) + + cfg := client.Config{ + StorageBackendConfig: client.StorageBackendConfig{ + Backend: client.Filesystem, + Filesystem: filesystem.Config{ + Directory: dbPath, + }, + }, + } + + fs, err := client.NewBucket(phlareCtx, cfg, "storage") + require.NoError(t, err) + + ing, err := New(phlareCtx, defaultIngesterTestConfig(t), phlaredb.Config{ + DataPath: dbPath, + MaxBlockDuration: 30 * time.Hour, + }, fs, &fakeLimits{}, 0) + require.NoError(t, err) + require.NoError(t, services.StartAndAwaitRunning(context.Background(), ing)) + + req := &connect.Request[pushv1.PushRequest]{ + Msg: &pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{ + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Samples: []*pushv1.RawSample{ + { + ID: uuid.NewString(), + RawProfile: testProfile(t), + }, + }, + }, + }, + }, + } + + ctx := tenant.InjectTenantID(context.Background(), "foo") + _, err = ing.Push(ctx, req) + require.NoError(t, err) + + query := &typesv1.LabelValuesRequest{ + Name: "foo", + Start: time.Now().Add(-1 * time.Hour).UnixMilli(), + End: time.Now().Add(time.Hour).UnixMilli(), + } + + labelsValues, err := ing.LabelValues(ctx, connect.NewRequest(query)) + require.NoError(t, err) + require.Equal(t, []string{"bar"}, labelsValues.Msg.Names) + + require.NoError(t, services.StopAndAwaitTerminated(context.Background(), ing)) + + // Open the ingester again and check if the data is + // available for queries before the first push request. + + ing, err = New(phlareCtx, defaultIngesterTestConfig(t), phlaredb.Config{ + DataPath: dbPath, + MaxBlockDuration: 30 * time.Hour, + }, fs, &fakeLimits{}, 0) + require.NoError(t, err) + require.NoError(t, services.StartAndAwaitRunning(context.Background(), ing)) + + labelsValues, err = ing.LabelValues(ctx, connect.NewRequest(query)) + require.NoError(t, err) + require.Equal(t, []string{"bar"}, labelsValues.Msg.Names) + + require.NoError(t, services.StopAndAwaitTerminated(context.Background(), ing)) +} diff --git a/pkg/ingester/instance.go b/pkg/ingester/instance.go index 6aefb5d46c..6ed0c52bad 100644 --- a/pkg/ingester/instance.go +++ b/pkg/ingester/instance.go @@ -10,11 +10,11 @@ import ( "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/shipper" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/shipper" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) type instance struct { @@ -103,7 +103,7 @@ func (i *instance) runShipper(ctx context.Context) { } func (i *instance) Stop() error { - err := i.PhlareDB.Close() + err := i.Close() i.cancel() i.wg.Wait() return err diff --git a/pkg/ingester/limiter.go b/pkg/ingester/limiter.go index 3802f0dac9..56bdda1b98 100644 --- a/pkg/ingester/limiter.go +++ b/pkg/ingester/limiter.go @@ -8,9 +8,9 @@ import ( "github.com/prometheus/common/model" "github.com/samber/lo" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/validation" ) var ( @@ -26,6 +26,7 @@ type Limits interface { MaxLocalSeriesPerTenant(tenantID string) int MaxGlobalSeriesPerTenant(tenantID string) int IngestionTenantShardSize(tenantID string) int + DistributorUsageGroups(tenantID string) *validation.UsageGroupConfig } type Limiter interface { diff --git a/pkg/ingester/limiter_test.go b/pkg/ingester/limiter_test.go index f27f5070de..9562ec207c 100644 --- a/pkg/ingester/limiter_test.go +++ b/pkg/ingester/limiter_test.go @@ -10,7 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/validation" ) type fakeLimits struct { @@ -31,6 +32,10 @@ func (f *fakeLimits) IngestionTenantShardSize(userID string) int { return f.ingestionTenantShardSize } +func (f *fakeLimits) DistributorUsageGroups(userID string) *validation.UsageGroupConfig { + return &validation.UsageGroupConfig{} +} + type fakeRingCount struct { healthyInstancesCount int } diff --git a/pkg/ingester/otlp/convert.go b/pkg/ingester/otlp/convert.go new file mode 100644 index 0000000000..2770ec61f1 --- /dev/null +++ b/pkg/ingester/otlp/convert.go @@ -0,0 +1,517 @@ +package otlp + +import ( + "encoding/hex" + "fmt" + "strings" + "time" + + otelProfile "go.opentelemetry.io/proto/otlp/profiles/v1development" + + googleProfile "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + pyromodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" +) + +const serviceNameKey = "service.name" + +type convertedProfile struct { + profile *googleProfile.Profile + name *typesv1.LabelPair +} + +func at[T any](arr []T, i int32) (T, error) { + if i >= 0 && int(i) < len(arr) { + return arr[i], nil + } + var zero T + return zero, fmt.Errorf("index %d out of bounds", i) +} + +// ConvertOtelToGoogle converts an OpenTelemetry profile to a Google profile. +func ConvertOtelToGoogle(src *otelProfile.Profile, dictionary *otelProfile.ProfilesDictionary) (map[string]convertedProfile, error) { + svc2Profile := make(map[string]*profileBuilder) + for _, sample := range src.Samples { + svc, err := serviceNameFromSample(sample, dictionary) + if err != nil { + return make(map[string]convertedProfile), nil + } + + p, ok := svc2Profile[svc] + if !ok { + p, err = newProfileBuilder(src, dictionary) + if err != nil { + return nil, err + } + svc2Profile[svc] = p + } + if _, err := p.convertSampleBack(sample, dictionary); err != nil { + return nil, err + } + } + + result := make(map[string]convertedProfile) + for svc, p := range svc2Profile { + result[svc] = convertedProfile{p.dst, p.name} + } + + return result, nil +} + +type sampleConversionType int + +const ( + sampleConversionTypeNone sampleConversionType = 0 + sampleConversionTypeSamplesToNanos sampleConversionType = 1 + sampleConversionTypeSumEvents sampleConversionType = 2 +) + +type profileBuilder struct { + src *otelProfile.Profile + dst *googleProfile.Profile + stringMap map[string]int64 + functionMap map[*otelProfile.Function]uint64 + unsymbolziedFuncNameMap map[string]uint64 + locationMap map[*otelProfile.Location]uint64 + mappingMap map[*otelProfile.Mapping]uint64 + + sampleProcessingTypes []sampleConversionType + name *typesv1.LabelPair +} + +func newProfileBuilder(src *otelProfile.Profile, dictionary *otelProfile.ProfilesDictionary) (*profileBuilder, error) { + res := &profileBuilder{ + src: src, + stringMap: make(map[string]int64), + functionMap: make(map[*otelProfile.Function]uint64), + locationMap: make(map[*otelProfile.Location]uint64), + mappingMap: make(map[*otelProfile.Mapping]uint64), + unsymbolziedFuncNameMap: make(map[string]uint64), + dst: &googleProfile.Profile{ + TimeNanos: int64(src.TimeUnixNano), + DurationNanos: int64(src.DurationNano), + Period: src.Period, + }, + } + res.addstr("") + + if src.SampleType == nil { + return nil, fmt.Errorf("sample type is missing") + } + sampleType, err := res.convertSampleTypeBack(src.SampleType, dictionary) + if err != nil { + return nil, err + } + res.dst.SampleType = []*googleProfile.ValueType{sampleType} + + periodType, err := res.convertValueTypeBack(src.PeriodType, dictionary) + if err != nil { + return nil, err + } + res.dst.PeriodType = periodType + + var defaultSampleTypeLabel string + if src.SampleType != nil { + defaultSampleType := src.SampleType + defaultSampleTypeLabel, err = at(dictionary.StringTable, defaultSampleType.TypeStrindex) + if err != nil { + return nil, fmt.Errorf("could not access default sample type label: %w", err) + } + } else { + defaultSampleTypeLabel = "samples" + } + res.dst.DefaultSampleType = res.addstr(defaultSampleTypeLabel) + + if len(res.dst.SampleType) == 0 { + res.dst.SampleType = []*googleProfile.ValueType{{ + Type: res.addstr(defaultSampleTypeLabel), + Unit: res.addstr("ms"), + }} + res.dst.DefaultSampleType = res.addstr(defaultSampleTypeLabel) + } + res.sampleProcessingTypes = make([]sampleConversionType, len(res.dst.SampleType)) + for i := 0; i < len(res.dst.SampleType); i++ { + profileType := res.profileType(i) + if profileType == "samples:count:cpu:nanoseconds" { + res.dst.SampleType[i] = &googleProfile.ValueType{ + Type: res.addstr("cpu"), + Unit: res.addstr("nanoseconds"), + } + if len(res.dst.SampleType) == 1 { + res.name = &typesv1.LabelPair{ + Name: pyromodel.LabelNameProfileName, + Value: "process_cpu", + } + } + res.sampleProcessingTypes[i] = sampleConversionTypeSamplesToNanos + } else if (profileType == "off_cpu:nanoseconds::") && len(res.dst.SampleType) == 1 { // Identify off-CPU profiles + + res.sampleProcessingTypes[i] = sampleConversionTypeSumEvents + res.name = &typesv1.LabelPair{ + Name: pyromodel.LabelNameProfileName, + Value: pyromodel.ProfileNameOffCpu, + } + } else { // Custom profile type + // Try to extract profile name from the type, e.g. "wall:time:cpu:milliseconds" -> "wall" + parts := strings.Split(profileType, `:`) + if len(parts) >= 3 { + res.name = &typesv1.LabelPair{ + Name: pyromodel.LabelNameProfileName, + Value: parts[2], + } + res.sampleProcessingTypes[i] = sampleConversionTypeNone + } + } + } + if res.name == nil { + res.name = &typesv1.LabelPair{ + Name: pyromodel.LabelNameProfileName, + Value: "process_cpu", // guess + } + } + + if res.dst.TimeNanos == 0 { + res.dst.TimeNanos = time.Now().UnixNano() + } + if res.dst.DurationNanos == 0 { + res.dst.DurationNanos = (time.Second * 10).Nanoseconds() + } + return res, nil +} + +func (p *profileBuilder) profileType(idx int) string { + var ( + periodType, periodUnit string + ) + if p.dst.PeriodType != nil && p.dst.Period != 0 { + periodType = p.dst.StringTable[p.dst.PeriodType.Type] + periodUnit = p.dst.StringTable[p.dst.PeriodType.Unit] + } + return fmt.Sprintf("%s:%s:%s:%s", + p.dst.StringTable[p.dst.SampleType[idx].Type], + p.dst.StringTable[p.dst.SampleType[idx].Unit], + periodType, + periodUnit, + ) +} + +func (p *profileBuilder) addstr(s string) int64 { + if i, ok := p.stringMap[s]; ok { + return i + } + idx := int64(len(p.dst.StringTable)) + p.stringMap[s] = idx + p.dst.StringTable = append(p.dst.StringTable, s) + return idx +} + +func serviceNameFromSample(sample *otelProfile.Sample, dictionary *otelProfile.ProfilesDictionary) (string, error) { + return getAttributeValueByKeyOrEmpty(sample.AttributeIndices, dictionary, serviceNameKey) +} + +func (p *profileBuilder) convertSampleTypeBack(ost *otelProfile.ValueType, dictionary *otelProfile.ProfilesDictionary) (*googleProfile.ValueType, error) { + gst, err := p.convertValueTypeBack(ost, dictionary) + if err != nil { + return nil, fmt.Errorf("could not process sample type: %w", err) + } + return gst, nil +} + +func (p *profileBuilder) convertValueTypeBack(ovt *otelProfile.ValueType, dictionary *otelProfile.ProfilesDictionary) (*googleProfile.ValueType, error) { + if ovt == nil { + return nil, nil + } + typeLabel, err := at(dictionary.StringTable, ovt.TypeStrindex) + if err != nil { + return nil, fmt.Errorf("could not access type string: %w", err) + } + unitLabel, err := at(dictionary.StringTable, ovt.UnitStrindex) + if err != nil { + return nil, fmt.Errorf("could not access unit string: %w", err) + } + return &googleProfile.ValueType{Type: p.addstr(typeLabel), Unit: p.addstr(unitLabel)}, nil +} + +func (p *profileBuilder) convertLocationBack(ol *otelProfile.Location, dictionary *otelProfile.ProfilesDictionary) (uint64, error) { + if i, ok := p.locationMap[ol]; ok { + return i, nil + } + lmi := ol.GetMappingIndex() + om, err := at(dictionary.MappingTable, lmi) + if err != nil { + return 0, fmt.Errorf("could not access mapping: %w", err) + } + + mappingId, ok := p.mappingMap[om] + if !ok { + return 0, fmt.Errorf("mapping not found in mappingMap") + } + gl := &googleProfile.Location{ + MappingId: mappingId, + Address: ol.Address, + Line: make([]*googleProfile.Line, len(ol.Lines)), + } + + for i, line := range ol.Lines { + gl.Line[i], err = p.convertLineBack(line, dictionary) + if err != nil { + return 0, fmt.Errorf("could not process line at index %d: %w", i, err) + } + } + + p.dst.Location = append(p.dst.Location, gl) + gl.Id = uint64(len(p.dst.Location)) + p.locationMap[ol] = gl.Id + return gl.Id, nil +} + +// convertLineBack converts an OpenTelemetry Line to a Google Line. +func (p *profileBuilder) convertLineBack(ol *otelProfile.Line, dictionary *otelProfile.ProfilesDictionary) (*googleProfile.Line, error) { + function, err := at(dictionary.FunctionTable, ol.FunctionIndex) + if err != nil { + return nil, fmt.Errorf("could not access function: %w", err) + } + functionId, err := p.convertFunctionBack(function, dictionary) + if err != nil { + return nil, err + } + return &googleProfile.Line{FunctionId: functionId, Line: ol.Line}, nil +} + +func (p *profileBuilder) convertFunctionBack(of *otelProfile.Function, dictionary *otelProfile.ProfilesDictionary) (uint64, error) { + if i, ok := p.functionMap[of]; ok { + return i, nil + } + nameLabel, err := at(dictionary.StringTable, of.NameStrindex) + if err != nil { + return 0, fmt.Errorf("could not access function name string: %w", err) + } + systemNameLabel, err := at(dictionary.StringTable, of.SystemNameStrindex) + if err != nil { + return 0, fmt.Errorf("could not access function system name string: %w", err) + } + filenameLabel, err := at(dictionary.StringTable, of.FilenameStrindex) + if err != nil { + return 0, fmt.Errorf("could not access function file name string: %w", err) + } + gf := &googleProfile.Function{ + Name: p.addstr(nameLabel), + SystemName: p.addstr(systemNameLabel), + Filename: p.addstr(filenameLabel), + StartLine: of.StartLine, + } + p.dst.Function = append(p.dst.Function, gf) + gf.Id = uint64(len(p.dst.Function)) + p.functionMap[of] = gf.Id + return gf.Id, nil +} + +func (p *profileBuilder) convertSampleBack(os *otelProfile.Sample, dictionary *otelProfile.ProfilesDictionary) (*googleProfile.Sample, error) { + gs := &googleProfile.Sample{ + Value: os.Values, + } + + // According to spec, samples can come without values, in which case we assume that each timestamp occurrence has value of 1. + // See: https://github.com/open-telemetry/opentelemetry-proto/blob/81d6676cdc30dddb0ec1f87d080e6dac07ab214f/opentelemetry/proto/profiles/v1development/profiles.proto#L351-L353 + if len(gs.Value) == 0 && len(os.TimestampsUnixNano) > 0 { + gs.Value = []int64{int64(len(os.TimestampsUnixNano))} + } + + if len(gs.Value) == 0 { + return nil, fmt.Errorf("sample value is required") + } + + for i, typ := range p.sampleProcessingTypes { + switch typ { + case sampleConversionTypeSamplesToNanos: + gs.Value[i] *= p.src.Period + case sampleConversionTypeSumEvents: + // For off-CPU profiles, aggregate all sample values into a single sum + // since pprof cannot represent variable-length sample values + sum := int64(0) + for _, v := range gs.Value { + sum += v + } + gs.Value = []int64{sum} + } + } + if p.dst.Period != 0 && p.dst.PeriodType != nil && len(gs.Value) != len(p.dst.SampleType) { + return nil, fmt.Errorf("sample values length mismatch %d %d", len(gs.Value), len(p.dst.SampleType)) + } + + err := p.convertSampleAttributesToLabelsBack(os, dictionary, gs) + if err != nil { + return nil, err + } + + stackIndex := os.GetStackIndex() + if stackIndex < 0 || int(stackIndex) >= len(dictionary.StackTable) { + return nil, fmt.Errorf("invalid stack index: %d", stackIndex) + } + stack := dictionary.StackTable[stackIndex] + + // First, gather map of locations pointing to each mapping + locationMap := make(map[*otelProfile.Mapping][]*otelProfile.Location) + + for _, locIdx := range stack.LocationIndices { + loc, err := at(dictionary.LocationTable, locIdx) + if err != nil { + return nil, fmt.Errorf("could not access location at index %d: %w", locIdx, err) + } + mapping, err := at(dictionary.MappingTable, loc.GetMappingIndex()) + if err != nil { + return nil, fmt.Errorf("could not access mapping at index %d: %w", loc.GetMappingIndex(), err) + } + locationMap[mapping] = append(locationMap[mapping], loc) + } + + // Now, convert each mapping, based on information from all locations that point to it + for mapping, locs := range locationMap { + _, err := p.convertMappingBack(locs, mapping, dictionary) + if err != nil { + return nil, err + } + } + + for _, olocIdx := range stack.LocationIndices { + oloc, err := at(dictionary.LocationTable, olocIdx) + if err != nil { + return nil, fmt.Errorf("could not access location at index %d: %w", olocIdx, err) + } + loc, err := p.convertLocationBack(oloc, dictionary) + if err != nil { + return nil, err + } + gs.LocationId = append(gs.LocationId, loc) + } + + p.dst.Sample = append(p.dst.Sample, gs) + + return gs, nil +} + +func (p *profileBuilder) convertSampleAttributesToLabelsBack(os *otelProfile.Sample, dictionary *otelProfile.ProfilesDictionary, gs *googleProfile.Sample) error { + gs.Label = make([]*googleProfile.Label, 0, len(os.AttributeIndices)) + for i, attributeIdx := range os.AttributeIndices { + attribute, err := at(dictionary.AttributeTable, attributeIdx) + if err != nil { + return fmt.Errorf("could not access attribute at index %d: %w", i, err) + } + if keyStr, err := at(dictionary.StringTable, attribute.KeyStrindex); err == nil && keyStr == serviceNameKey { + continue + } + if sv := stringValueFromAnyValue(attribute.Value); sv != "" { + keyStr, err := at(dictionary.StringTable, attribute.KeyStrindex) + if err != nil { + return fmt.Errorf("could not access attribute key: %w", err) + } + gs.Label = append(gs.Label, &googleProfile.Label{ + Key: p.addstr(keyStr), + Str: p.addstr(sv), + }) + } + } + + if os.GetLinkIndex() != 0 { + link, err := at(dictionary.LinkTable, os.GetLinkIndex()) + if err != nil { + return fmt.Errorf("could not access link at index %d: %w", os.GetLinkIndex(), err) + } + gs.Label = append(gs.Label, &googleProfile.Label{ + Key: p.addstr(pprof.SpanIDLabelName), + Str: p.addstr(hex.EncodeToString(link.GetSpanId())), + }) + if traceID := link.GetTraceId(); len(traceID) == 16 { + gs.Label = append(gs.Label, &googleProfile.Label{ + Key: p.addstr(pprof.TraceIDLabelName), + Str: p.addstr(hex.EncodeToString(traceID)), + }) + } + } + + return nil +} + +// convertMappingBack converts an OpenTelemetry Mapping to a Google Mapping taking into account availability +// of symbol data in all locations that point to this mapping. +func (p *profileBuilder) convertMappingBack(ols []*otelProfile.Location, om *otelProfile.Mapping, dictionary *otelProfile.ProfilesDictionary) (uint64, error) { + hasLines := true + hasFunctions := true + hasInlineFrames := true + hasFilenames := true + + /* + We survey all locations that point to this mapping to determine + whether the mapping has functions, filenames, line numbers, inline frames. + Note that even if a single location does not have symbol information, + the mapping is marked as not having that information. + */ + for _, ol := range ols { + // If at least one location belonging to mapping does not have lines, we must flag whole mapping as not having symbol info. + if len(ol.Lines) == 0 { + hasLines = false + hasFunctions = false + hasInlineFrames = false + hasFilenames = false + } + + // If by this point we know that mapping has no symbol info, we can stop checking other locations. + if !hasLines && !hasFunctions && !hasInlineFrames && !hasFilenames { + break + } + + for i, line := range ol.Lines { + hasFunctions = hasFunctions && line.FunctionIndex > 0 + hasLines = hasLines && line.Line > 0 + hasInlineFrames = hasInlineFrames && i >= 1 + + if line.FunctionIndex > 0 { + function, _ := at(dictionary.FunctionTable, line.FunctionIndex) + if function != nil { + hasFilenames = hasFilenames && function.FilenameStrindex > 0 + } + } + } + } + + buildID, _ := getAttributeValueByKeyOrEmpty(om.AttributeIndices, dictionary, "process.executable.build_id.gnu") + filenameLabel, err := at(dictionary.StringTable, om.FilenameStrindex) + if err != nil { + return 0, fmt.Errorf("could not access mapping file name string: %w", err) + } + gm := &googleProfile.Mapping{ + MemoryStart: om.MemoryStart, + MemoryLimit: om.MemoryLimit, + FileOffset: om.FileOffset, + Filename: p.addstr(filenameLabel), + BuildId: p.addstr(buildID), + HasFunctions: hasFunctions, + HasFilenames: hasFilenames, + HasLineNumbers: hasLines, + HasInlineFrames: hasInlineFrames, + } + p.dst.Mapping = append(p.dst.Mapping, gm) + gm.Id = uint64(len(p.dst.Mapping)) + p.mappingMap[om] = gm.Id + return gm.Id, nil +} + +// This function extracts the value of a specific attribute key from a list of attribute indices. +// TODO: build a map instead of iterating every time. +func getAttributeValueByKeyOrEmpty(attributeIndices []int32, dictionary *otelProfile.ProfilesDictionary, key string) (string, error) { + for i, attributeIndex := range attributeIndices { + attr, err := at(dictionary.AttributeTable, attributeIndex) + if err != nil { + return "", fmt.Errorf("attribute not found: %d: %w", i, err) + } + keyStr, err := at(dictionary.StringTable, attr.KeyStrindex) + if err != nil { + return "", fmt.Errorf("attribute key string not found %d: %w", i, err) + } + if keyStr == key { + return stringValueFromAnyValue(attr.Value), nil + } + } + return "", nil +} diff --git a/pkg/ingester/otlp/ingest_handler.go b/pkg/ingester/otlp/ingest_handler.go new file mode 100644 index 0000000000..65b343eee5 --- /dev/null +++ b/pkg/ingester/otlp/ingest_handler.go @@ -0,0 +1,408 @@ +package otlp + +import ( + "compress/gzip" + "context" + "errors" + "fmt" + "io" + "net/http" + "strconv" + "strings" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/keepalive" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + "connectrpc.com/connect" + "github.com/dustin/go-humanize" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/google/uuid" + "github.com/grafana/dskit/server" + "github.com/grafana/dskit/tenant" + pprofileotlp "go.opentelemetry.io/proto/otlp/collector/profiles/v1development" + v1 "go.opentelemetry.io/proto/otlp/common/v1" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +type ingestHandler struct { + pprofileotlp.UnimplementedProfilesServiceServer + svc PushService + log log.Logger + handler http.Handler + limits Limits +} + +type Handler interface { + http.Handler + pprofileotlp.ProfilesServiceServer +} + +type PushService interface { + PushBatch(ctx context.Context, req *distributormodel.PushRequest) error +} + +type Limits interface { + IngestionBodyLimitBytes(tenantID string) int64 +} + +func NewOTLPIngestHandler(cfg server.Config, svc PushService, l log.Logger, limits Limits) Handler { + h := &ingestHandler{ + svc: svc, + log: l, + limits: limits, + } + + grpcServer := newGrpcServer(cfg) + pprofileotlp.RegisterProfilesServiceServer(grpcServer, h) + + h.handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") { + grpcServer.ServeHTTP(w, r) + return + } + + // Handle HTTP/JSON and HTTP/Protobuf requests + contentType := r.Header.Get("Content-Type") + if contentType == "application/json" || contentType == "application/x-protobuf" || contentType == "application/protobuf" { + h.handleHTTPRequest(w, r) + return + } + + http.Error(w, fmt.Sprintf("Unsupported Content-Type: %s", contentType), http.StatusUnsupportedMediaType) + }) + + return h +} + +func newGrpcServer(cfg server.Config) *grpc.Server { + grpcKeepAliveOptions := keepalive.ServerParameters{ + MaxConnectionIdle: cfg.GRPCServerMaxConnectionIdle, + MaxConnectionAge: cfg.GRPCServerMaxConnectionAge, + MaxConnectionAgeGrace: cfg.GRPCServerMaxConnectionAgeGrace, + Time: cfg.GRPCServerTime, + Timeout: cfg.GRPCServerTimeout, + } + + grpcKeepAliveEnforcementPolicy := keepalive.EnforcementPolicy{ + MinTime: cfg.GRPCServerMinTimeBetweenPings, + PermitWithoutStream: cfg.GRPCServerPingWithoutStreamAllowed, + } + + grpcOptions := []grpc.ServerOption{ + grpc.KeepaliveParams(grpcKeepAliveOptions), + grpc.KeepaliveEnforcementPolicy(grpcKeepAliveEnforcementPolicy), + grpc.MaxRecvMsgSize(cfg.GRPCServerMaxRecvMsgSize), + grpc.MaxSendMsgSize(cfg.GRPCServerMaxSendMsgSize), + grpc.MaxConcurrentStreams(uint32(cfg.GRPCServerMaxConcurrentStreams)), + grpc.NumStreamWorkers(uint32(cfg.GRPCServerNumWorkers)), + } + + grpcOptions = append(grpcOptions, cfg.GRPCOptions...) + + return grpc.NewServer(grpcOptions...) +} + +func (h *ingestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.handler.ServeHTTP(w, r) +} + +func isHTTPRequestBodyTooLarge(err error) error { + herr := new(http.MaxBytesError) + if errors.As(err, &herr) { + return validation.NewErrorf(validation.BodySizeLimit, "profile payload size exceeds limit of %s", humanize.Bytes(uint64(herr.Limit))) + } + return nil +} + +func isKnownValidationError(err error) bool { + return validation.ReasonOf(err) != validation.Unknown +} + +func (h *ingestHandler) handleHTTPRequest(w http.ResponseWriter, r *http.Request) { + tenantID, err := tenant.TenantID(r.Context()) + if err != nil { + httputil.ErrorWithStatus(w, err, http.StatusUnauthorized) + return + } + maxBodyBytes := h.limits.IngestionBodyLimitBytes(tenantID) + + defer r.Body.Close() + + var ( + errMsgBodyRead = "failed to read request body" + reader = r.Body + ) + + if strings.EqualFold(r.Header.Get("Content-Encoding"), "gzip") { + gzipReader, gzipErr := gzip.NewReader(r.Body) + if gzipErr != nil { + level.Error(h.log).Log("msg", "failed to create gzip reader", "err", gzipErr) + http.Error(w, "Failed to read request body", http.StatusBadRequest) + return + } + defer gzipReader.Close() + errMsgBodyRead = "failed to read gzip-compressed request body" + + reader = gzipReader + // Limit after decompression size + if maxBodyBytes > 0 { + reader = io.NopCloser(io.LimitReader(reader, maxBodyBytes+1)) + } + } + + body, err := io.ReadAll(reader) + if maxBodyBytes > 0 && int64(len(body)) > maxBodyBytes { + validation.DiscardedBytes.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(float64(maxBodyBytes)) + validation.DiscardedProfiles.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(1) + err := validation.NewErrorf(validation.BodySizeLimit, "uncompressed profile payload size exceeds limit of %s", humanize.Bytes(uint64(maxBodyBytes))) + http.Error(w, err.Error(), http.StatusRequestEntityTooLarge) + return + } + if err != nil { + level.Error(h.log).Log("msg", errMsgBodyRead, "err", err) + // handle if body size limit is hit with correct status code + if herr := isHTTPRequestBodyTooLarge(err); herr != nil { + validation.DiscardedBytes.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(float64(maxBodyBytes)) + validation.DiscardedProfiles.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(1) + http.Error(w, herr.Error(), http.StatusRequestEntityTooLarge) + return + } + http.Error(w, errMsgBodyRead, http.StatusBadRequest) + return + } + + req := &pprofileotlp.ExportProfilesServiceRequest{} + + isJSONRequest := r.Header.Get("Content-Type") == "application/json" + if isJSONRequest { + if err := protojson.Unmarshal(body, req); err != nil { + level.Error(h.log).Log("msg", "failed to unmarshal JSON request", "err", err) + http.Error(w, "Failed to parse JSON request", http.StatusBadRequest) + return + } + } else { + if err := proto.Unmarshal(body, req); err != nil { + level.Error(h.log).Log("msg", "failed to unmarshal protobuf request", "err", err) + http.Error(w, "Failed to parse protobuf request", http.StatusBadRequest) + return + } + } + + resp, err := h.export(r.Context(), req) + if err != nil { + switch { + case isKnownValidationError(err): + level.Warn(h.log).Log("msg", "rejecting invalid profiles", "err", err) + http.Error(w, err.Error(), http.StatusBadRequest) + case connect.CodeOf(err) == connect.CodeResourceExhausted: + level.Warn(h.log).Log("msg", "rejecting profiles over ingestion limit", "err", err) + http.Error(w, err.Error(), http.StatusTooManyRequests) + default: + level.Error(h.log).Log("msg", "failed to process profiles", "err", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + respBytes, err := proto.Marshal(resp) + if err != nil { + level.Error(h.log).Log("msg", "failed to marshal response", "err", err) + http.Error(w, "Failed to marshal response", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/x-protobuf") + w.WriteHeader(http.StatusOK) + if _, err := w.Write(respBytes); err != nil { + level.Error(h.log).Log("msg", "failed to write response", "err", err) + } +} + +func (h *ingestHandler) Export(ctx context.Context, er *pprofileotlp.ExportProfilesServiceRequest) (*pprofileotlp.ExportProfilesServiceResponse, error) { + resp, err := h.export(ctx, er) + if err != nil { + return resp, toGRPCStatus(err) + } + return resp, nil +} + +// toGRPCStatus maps push errors that carry a Connect code (e.g. ResourceExhausted +// when a tenant exceeds its ingestion limit) to the matching gRPC status; errors +// that already carry a gRPC status pass through unchanged. +func toGRPCStatus(err error) error { + if _, ok := status.FromError(err); ok { + return err + } + return status.Error(codes.Code(connect.CodeOf(err)), err.Error()) +} + +func (h *ingestHandler) export(ctx context.Context, er *pprofileotlp.ExportProfilesServiceRequest) (*pprofileotlp.ExportProfilesServiceResponse, error) { + _, err := tenant.TenantID(ctx) + if err != nil { + return &pprofileotlp.ExportProfilesServiceResponse{}, status.Errorf(codes.Unauthenticated, "failed to extract tenant ID from context: %s", err.Error()) + } + + dc := er.Dictionary + if dc == nil { + return &pprofileotlp.ExportProfilesServiceResponse{}, status.Errorf(codes.InvalidArgument, "missing profile metadata dictionary") + } + + rps := er.ResourceProfiles + if rps == nil { + return &pprofileotlp.ExportProfilesServiceResponse{}, status.Errorf(codes.InvalidArgument, "missing resource profiles") + } + + req := &distributormodel.PushRequest{ + RawProfileType: distributormodel.RawProfileTypeOTEL, + } + + for _, rp := range rps { + serviceName := getServiceNameFromAttributes(rp.Resource.GetAttributes()) + for _, sp := range rp.ScopeProfiles { + for _, p := range sp.Profiles { + sz := proto.Size(p) + req.ReceivedCompressedProfileSize += sz + req.ReceivedDecompressedProfileSize += sz + + pprofProfiles, err := ConvertOtelToGoogle(p, dc) + if err != nil { + grpcError := status.Errorf(codes.InvalidArgument, "failed to convert otel profile: %s", err.Error()) + return &pprofileotlp.ExportProfilesServiceResponse{}, grpcError + } + + for samplesServiceName, pprofProfile := range pprofProfiles { + labels := getDefaultLabels() + labels = append(labels, pprofProfile.name) + processedKeys := map[string]bool{model.LabelNameProfileName: true} + labels = appendAttributesUnique(labels, rp.Resource.GetAttributes(), processedKeys) + labels = appendAttributesUnique(labels, sp.Scope.GetAttributes(), processedKeys) + svc := samplesServiceName + if svc == "" { + svc = serviceName + } + labels = append(labels, &typesv1.LabelPair{ + Name: model.LabelNameServiceName, + Value: svc, + }) + + s := &distributormodel.ProfileSeries{ + Labels: labels, + RawProfile: nil, + Profile: pprof.RawFromProto(pprofProfile.profile), + ID: uuid.New().String(), + } + req.Series = append(req.Series, s) + } + } + } + } + + if len(req.Series) == 0 { + return &pprofileotlp.ExportProfilesServiceResponse{}, nil + } + + if err := h.svc.PushBatch(ctx, req); err != nil { + h.log.Log("msg", "failed to push profile", "err", err) + // Note: Validation metrics are already tracked by the distributor for errors + // returned from PushBatch, so we don't track them here to avoid double-counting. + return &pprofileotlp.ExportProfilesServiceResponse{}, fmt.Errorf("failed to make a GRPC request: %w", err) + } + + return &pprofileotlp.ExportProfilesServiceResponse{}, nil +} + +// getServiceNameFromAttributes extracts service name from OTLP resource attributes. +// according to otel spec https://github.com/open-telemetry/opentelemetry-go/blob/ecfb73581f1b05af85fc393c3ce996a90cf2a5e2/semconv/v1.30.0/attribute_group.go#L10011-L10025 +// Returns "unknown_service:$process_name" if no service.name, but there is a process.executable.name +// Returns "unknown_service" if no service.name and no process.executable.name +func getServiceNameFromAttributes(attrs []*v1.KeyValue) string { + fallback := model.AttrServiceNameFallback + for _, attr := range attrs { + if attr.Key == string(model.AttrServiceName) { + if sv := stringValueFromAnyValue(attr.GetValue()); sv != "" { + return sv + } + } + if attr.Key == string(model.AttrProcessExecutableName) { + if sv := stringValueFromAnyValue(attr.GetValue()); sv != "" { + fallback += ":" + sv + } + } + + } + return fallback +} + +// getDefaultLabels returns the required base labels for Pyroscope profiles +func getDefaultLabels() []*typesv1.LabelPair { + return []*typesv1.LabelPair{ + { + Name: model.LabelNameDelta, + Value: "false", + }, + { + Name: model.LabelNameOTEL, + Value: "true", + }, + } +} + +func appendAttributesUnique(labels []*typesv1.LabelPair, attrs []*v1.KeyValue, processedKeys map[string]bool) []*typesv1.LabelPair { + for _, attr := range attrs { + // Skip if we've already seen this key at any level + if processedKeys[attr.Key] { + continue + } + + if sv := stringValueFromAnyValue(attr.GetValue()); sv != "" { + labels = append(labels, &typesv1.LabelPair{ + Name: attr.Key, + Value: sv, + }) + processedKeys[attr.Key] = true + } + } + return labels +} + +func decodeSingleAnyValue(v *v1.AnyValue) string { + if v == nil { + return "" + } + + switch value := v.Value.(type) { + case *v1.AnyValue_StringValue: + return value.StringValue + case *v1.AnyValue_IntValue: + return strconv.FormatInt(value.IntValue, 10) + default: + return "" + } +} + +func stringValueFromAnyValue(v *v1.AnyValue) string { + if v == nil { + return "" + } + if decoded := decodeSingleAnyValue(v); decoded != "" { + return decoded + } + if av := v.GetArrayValue(); av != nil { + values := av.GetValues() + if len(values) == 1 { + return decodeSingleAnyValue(values[0]) + } + } + return "" +} diff --git a/pkg/ingester/otlp/ingest_handler_test.go b/pkg/ingester/otlp/ingest_handler_test.go new file mode 100644 index 0000000000..2c8d7de123 --- /dev/null +++ b/pkg/ingester/otlp/ingest_handler_test.go @@ -0,0 +1,1414 @@ +package otlp + +import ( + "bytes" + "context" + "flag" + "fmt" + "net/http" + "net/http/httptest" + "os" + "sort" + "strings" + "testing" + + "connectrpc.com/connect" + "github.com/grafana/dskit/server" + "github.com/grafana/dskit/user" + "github.com/klauspost/compress/gzip" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + v1experimental2 "go.opentelemetry.io/proto/otlp/collector/profiles/v1development" + v1 "go.opentelemetry.io/proto/otlp/common/v1" + v1experimental "go.opentelemetry.io/proto/otlp/profiles/v1development" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/distributor/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/strprofile" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockotlp" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func TestGetServiceNameFromAttributes(t *testing.T) { + tests := []struct { + name string + attrs []*v1.KeyValue + expected string + }{ + { + name: "empty attributes", + attrs: []*v1.KeyValue{}, + expected: phlaremodel.AttrServiceNameFallback, + }, + { + name: "use executable name", + attrs: []*v1.KeyValue{ + { + Key: "process.executable.name", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "bash", + }, + }, + }, + }, + expected: phlaremodel.AttrServiceNameFallback + ":bash", + }, + { + name: "service name present", + attrs: []*v1.KeyValue{ + { + Key: "service.name", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "test-service", + }, + }, + }, + { + Key: "process.executable.name", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "test-executable", + }, + }, + }, + }, + expected: "test-service", + }, + { + name: "service name empty", + attrs: []*v1.KeyValue{ + { + Key: "service.name", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "", + }, + }, + }, + { + Key: "process.executable.name", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "", + }, + }, + }, + }, + expected: phlaremodel.AttrServiceNameFallback, + }, + { + name: "service name among other attributes", + attrs: []*v1.KeyValue{ + { + Key: "host.name", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "host1", + }, + }, + }, + { + Key: "service.name", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "test-service", + }, + }, + }, + }, + expected: "test-service", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := getServiceNameFromAttributes(tt.attrs) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestAppendAttributesUnique(t *testing.T) { + tests := []struct { + name string + existingAttrs []*typesv1.LabelPair + newAttrs []*v1.KeyValue + processedKeys map[string]bool + expected []*typesv1.LabelPair + }{ + { + name: "empty attributes", + existingAttrs: []*typesv1.LabelPair{}, + newAttrs: []*v1.KeyValue{}, + processedKeys: make(map[string]bool), + expected: []*typesv1.LabelPair{}, + }, + { + name: "new unique attributes", + existingAttrs: []*typesv1.LabelPair{ + {Name: "existing", Value: "value"}, + }, + newAttrs: []*v1.KeyValue{ + { + Key: "new", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "newvalue", + }, + }, + }, + }, + processedKeys: map[string]bool{"existing": true}, + expected: []*typesv1.LabelPair{ + {Name: "existing", Value: "value"}, + {Name: "new", Value: "newvalue"}, + }, + }, + { + name: "duplicate attributes", + existingAttrs: []*typesv1.LabelPair{ + {Name: "key1", Value: "value1"}, + }, + newAttrs: []*v1.KeyValue{ + { + Key: "key1", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "value2", + }, + }, + }, + }, + processedKeys: map[string]bool{"key1": true}, + expected: []*typesv1.LabelPair{ + {Name: "key1", Value: "value1"}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := appendAttributesUnique(tt.existingAttrs, tt.newAttrs, tt.processedKeys) + assert.Equal(t, tt.expected, result) + }) + } +} + +func readJSONFile(t *testing.T, filename string) string { + data, err := os.ReadFile(filename) + require.NoError(t, err, "filename: "+filename) + return string(data) +} + +func TestConversion(t *testing.T) { + + testdata := []struct { + name string + expectedJsonFile string + expectedError string + profile func() *otlpbuilder + }{ + { + name: "symbolized function names", + expectedJsonFile: "testdata/TestSymbolizedFunctionNames.json", + profile: func() *otlpbuilder { + b := new(otlpbuilder) + b.dictionary.MappingTable = []*v1experimental.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x1000, + FilenameStrindex: b.addstr("file1.so"), + }} + b.dictionary.LocationTable = []*v1experimental.Location{{ + MappingIndex: 0, + Address: 0x1e0, + Lines: nil, + }, { + MappingIndex: 0, + Address: 0x2f0, + Lines: nil, + }} + b.dictionary.StackTable = []*v1experimental.Stack{{ + LocationIndices: []int32{0, 1}, + }} + b.profile.SampleType = &v1experimental.ValueType{ + TypeStrindex: b.addstr("samples"), + UnitStrindex: b.addstr("ms"), + } + b.profile.Samples = []*v1experimental.Sample{{ + StackIndex: 0, + Values: []int64{0xef}, + }} + return b + }, + }, + { + name: "offcpu", + expectedJsonFile: "testdata/TestConversionOffCpu.json", + profile: func() *otlpbuilder { + b := new(otlpbuilder) + b.profile.SampleType = &v1experimental.ValueType{ + TypeStrindex: b.addstr("off_cpu"), + UnitStrindex: b.addstr("nanoseconds"), + } + b.dictionary.MappingTable = []*v1experimental.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x1000, + FilenameStrindex: b.addstr("file1.so"), + }} + b.dictionary.LocationTable = []*v1experimental.Location{{ + MappingIndex: 0, + Address: 0x1e0, + }, { + MappingIndex: 0, + Address: 0x2f0, + }, { + MappingIndex: 0, + Address: 0x3f0, + }} + b.dictionary.StackTable = []*v1experimental.Stack{{ + LocationIndices: []int32{0, 1}, + }, { + LocationIndices: []int32{2}, + }} + b.profile.Samples = []*v1experimental.Sample{{ + StackIndex: 0, + Values: []int64{0xef}, + }, { + StackIndex: 1, + Values: []int64{1, 2, 3, 4, 5, 6}, + }} + return b + }, + }, + { + name: "samples with different value sizes ", + expectedError: "sample values length mismatch", + profile: func() *otlpbuilder { + b := new(otlpbuilder) + b.profile.SampleType = &v1experimental.ValueType{ + TypeStrindex: b.addstr("wrote_type"), + UnitStrindex: b.addstr("wrong_unit"), + } + b.dictionary.MappingTable = []*v1experimental.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x1000, + FilenameStrindex: b.addstr("file1.so"), + }} + b.dictionary.LocationTable = []*v1experimental.Location{{ + MappingIndex: 0, + Address: 0x1e0, + }, { + MappingIndex: 0, + Address: 0x2f0, + }, { + MappingIndex: 0, + Address: 0x3f0, + }} + b.dictionary.StackTable = []*v1experimental.Stack{{ + LocationIndices: []int32{0, 1}, + }, { + LocationIndices: []int32{2}, + }} + b.profile.PeriodType = &v1experimental.ValueType{ + TypeStrindex: b.addstr("period_type"), + UnitStrindex: b.addstr("period_unit"), + } + b.profile.Period = 100 + b.profile.Samples = []*v1experimental.Sample{{ + StackIndex: 0, + Values: []int64{0xef}, + }, { + StackIndex: 1, + Values: []int64{1, 2, 3, 4, 5, 6}, // should be rejected because of that + }} + return b + }, + }, + } + + for _, td := range testdata { + td := td + + t.Run(td.name, func(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var profiles []*model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + c := (args.Get(1)).(*model.PushRequest) + profiles = append(profiles, c) + }).Return(nil, nil).Maybe() + b := td.profile() + b.profile.TimeUnixNano = 239 + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{{ + Profiles: []*v1experimental.Profile{ + &b.profile, + }}}}}, + Dictionary: &b.dictionary} + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + + if td.expectedError == "" { + require.NoError(t, err) + require.Equal(t, 1, len(profiles)) + + gp := profiles[0].Series[0].Profile.Profile + + jsonStr, err := strprofile.Stringify(gp, strprofile.Options{}) + assert.NoError(t, err) + expectedJSON := readJSONFile(t, td.expectedJsonFile) + assert.JSONEq(t, expectedJSON, jsonStr) + } else { + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), td.expectedError)) + } + }) + } + +} + +func TestSampleAttributes(t *testing.T) { + // Create a profile with two samples, with different sample attributes + // one process=firefox, the other process=chrome + // expect both of them to be present in the converted pprof as labels, but not series labels + svc := mockotlp.NewMockPushService(t) + var profiles []*model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + c := (args.Get(1)).(*model.PushRequest) + profiles = append(profiles, c) + }).Return(nil, nil) + + otlpb := new(otlpbuilder) + otlpb.dictionary.MappingTable = []*v1experimental.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x1000, + FilenameStrindex: otlpb.addstr("firefox.so"), + }, { + MemoryStart: 0x1000, + MemoryLimit: 0x1000, + FilenameStrindex: otlpb.addstr("chrome.so"), + }} + + otlpb.dictionary.LocationTable = []*v1experimental.Location{{ + MappingIndex: 0, + Address: 0x1e, + }, { + MappingIndex: 0, + Address: 0x2e, + }, { + MappingIndex: 1, + Address: 0x3e, + }, { + MappingIndex: 1, + Address: 0x4e, + }} + otlpb.dictionary.StackTable = []*v1experimental.Stack{{ + LocationIndices: []int32{0, 1}, + }, { + LocationIndices: []int32{2, 3}, + }} + otlpb.profile.Samples = []*v1experimental.Sample{{ + StackIndex: 0, + Values: []int64{0xef}, + AttributeIndices: []int32{0, 2}, + }, { + StackIndex: 1, + Values: []int64{0xefef}, + AttributeIndices: []int32{1, 3}, + }} + otlpb.dictionary.AttributeTable = []*v1experimental.KeyValueAndUnit{{ + KeyStrindex: otlpb.addstr("process"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "firefox", + }, + }, + }, { + KeyStrindex: otlpb.addstr("process"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "chrome", + }, + }, + }, { + KeyStrindex: otlpb.addstr("cpu.logical_number"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_IntValue{ + IntValue: 0, + }, + }, + }, { + KeyStrindex: otlpb.addstr("cpu.logical_number"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_IntValue{ + IntValue: 7, + }, + }, + }} + otlpb.profile.SampleType = &v1experimental.ValueType{ + TypeStrindex: otlpb.addstr("samples"), + UnitStrindex: otlpb.addstr("ms"), + } + otlpb.profile.TimeUnixNano = 239 + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{{ + Profiles: []*v1experimental.Profile{ + &otlpb.profile, + }}}}}, + Dictionary: &otlpb.dictionary} + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + assert.NoError(t, err) + require.Equal(t, 1, len(profiles)) + require.Equal(t, 1, len(profiles[0].Series)) + + seriesLabelsMap := make(map[string]string) + for _, label := range profiles[0].Series[0].Labels { + seriesLabelsMap[label.Name] = label.Value + } + assert.Equal(t, "", seriesLabelsMap["process"]) + assert.NotContains(t, seriesLabelsMap, "service.name") + + gp := profiles[0].Series[0].Profile.Profile + + jsonStr, err := strprofile.Stringify(gp, strprofile.Options{}) + assert.NoError(t, err) + expectedJSON := readJSONFile(t, "testdata/TestSampleAttributes.json") + assert.Equal(t, expectedJSON, jsonStr) + +} + +func TestSampleAttributesWithSliceValues(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var profiles []*model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + c := (args.Get(1)).(*model.PushRequest) + profiles = append(profiles, c) + }).Return(nil, nil) + + otlpb := new(otlpbuilder) + otlpb.dictionary.MappingTable = []*v1experimental.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x1000, + FilenameStrindex: otlpb.addstr("firefox.so"), + }, { + MemoryStart: 0x1000, + MemoryLimit: 0x1000, + FilenameStrindex: otlpb.addstr("chrome.so"), + }} + + otlpb.dictionary.LocationTable = []*v1experimental.Location{{ + MappingIndex: 0, + Address: 0x1e, + }, { + MappingIndex: 0, + Address: 0x2e, + }, { + MappingIndex: 1, + Address: 0x3e, + }, { + MappingIndex: 1, + Address: 0x4e, + }} + otlpb.dictionary.StackTable = []*v1experimental.Stack{{ + LocationIndices: []int32{0, 1}, + }, { + LocationIndices: []int32{2, 3}, + }} + otlpb.profile.Samples = []*v1experimental.Sample{{ + StackIndex: 0, + Values: []int64{0xef}, + AttributeIndices: []int32{0, 2}, + }, { + StackIndex: 1, + Values: []int64{0xefef}, + AttributeIndices: []int32{1, 3}, + }} + otlpb.dictionary.AttributeTable = []*v1experimental.KeyValueAndUnit{{ + KeyStrindex: otlpb.addstr("process"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{{ + Value: &v1.AnyValue_StringValue{ + StringValue: "firefox", + }, + }}, + }, + }, + }, + }, { + KeyStrindex: otlpb.addstr("process"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{{ + Value: &v1.AnyValue_StringValue{ + StringValue: "chrome", + }, + }}, + }, + }, + }, + }, { + KeyStrindex: otlpb.addstr("cpu.logical_number"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{{ + Value: &v1.AnyValue_IntValue{ + IntValue: 0, + }, + }}, + }, + }, + }, + }, { + KeyStrindex: otlpb.addstr("cpu.logical_number"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{{ + Value: &v1.AnyValue_IntValue{ + IntValue: 7, + }, + }}, + }, + }, + }, + }} + otlpb.profile.SampleType = &v1experimental.ValueType{ + TypeStrindex: otlpb.addstr("samples"), + UnitStrindex: otlpb.addstr("ms"), + } + otlpb.profile.TimeUnixNano = 239 + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{{ + Profiles: []*v1experimental.Profile{ + &otlpb.profile, + }}}}}, + Dictionary: &otlpb.dictionary} + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + assert.NoError(t, err) + require.Equal(t, 1, len(profiles)) + require.Equal(t, 1, len(profiles[0].Series)) + + seriesLabelsMap := make(map[string]string) + for _, label := range profiles[0].Series[0].Labels { + seriesLabelsMap[label.Name] = label.Value + } + assert.Equal(t, "", seriesLabelsMap["process"]) + assert.NotContains(t, seriesLabelsMap, "service.name") + + gp := profiles[0].Series[0].Profile.Profile + + jsonStr, err := strprofile.Stringify(gp, strprofile.Options{}) + assert.NoError(t, err) + expectedJSON := readJSONFile(t, "testdata/TestSampleAttributes.json") + assert.Equal(t, expectedJSON, jsonStr) +} + +func TestStringValueFromAnyValue(t *testing.T) { + tests := []struct { + name string + value *v1.AnyValue + expected string + }{ + { + name: "nil value", + value: nil, + expected: "", + }, + { + name: "scalar string", + value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{StringValue: "hello"}, + }, + expected: "hello", + }, + { + name: "single-element string slice", + value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{{ + Value: &v1.AnyValue_StringValue{StringValue: "hello"}, + }}, + }, + }, + }, + expected: "hello", + }, + { + name: "multi-element slice returns empty", + value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{ + {Value: &v1.AnyValue_StringValue{StringValue: "a"}}, + {Value: &v1.AnyValue_StringValue{StringValue: "b"}}, + }, + }, + }, + }, + expected: "", + }, + { + name: "empty slice returns empty", + value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{}, + }, + }, + }, + expected: "", + }, + { + name: "int value returns string", + value: &v1.AnyValue{ + Value: &v1.AnyValue_IntValue{IntValue: 42}, + }, + expected: "42", + }, + { + name: "zero int value returns string zero", + value: &v1.AnyValue{ + Value: &v1.AnyValue_IntValue{IntValue: 0}, + }, + expected: "0", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := stringValueFromAnyValue(tt.value) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestAppendAttributesUniqueWithSliceValues(t *testing.T) { + existingAttrs := []*typesv1.LabelPair{ + {Name: "existing", Value: "value"}, + } + newAttrs := []*v1.KeyValue{ + { + Key: "slice_attr", + Value: &v1.AnyValue{ + Value: &v1.AnyValue_ArrayValue{ + ArrayValue: &v1.ArrayValue{ + Values: []*v1.AnyValue{{ + Value: &v1.AnyValue_StringValue{ + StringValue: "unwrapped", + }, + }}, + }, + }, + }, + }, + } + processedKeys := map[string]bool{"existing": true} + result := appendAttributesUnique(existingAttrs, newAttrs, processedKeys) + assert.Equal(t, []*typesv1.LabelPair{ + {Name: "existing", Value: "value"}, + {Name: "slice_attr", Value: "unwrapped"}, + }, result) +} + +func TestDifferentServiceNames(t *testing.T) { + // Create a profile with two samples having different service.name attributes + // Expect them to be pushed as separate profiles + svc := mockotlp.NewMockPushService(t) + var profiles []*model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + c := (args.Get(1)).(*model.PushRequest) + for _, series := range c.Series { + sort.Sort(phlaremodel.Labels(series.Labels)) + } + profiles = append(profiles, c) + }).Return(nil, nil) + + otlpb := new(otlpbuilder) + otlpb.dictionary.MappingTable = []*v1experimental.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x2000, + FilenameStrindex: otlpb.addstr("service-a.so"), + }, { + MemoryStart: 0x2000, + MemoryLimit: 0x3000, + FilenameStrindex: otlpb.addstr("service-b.so"), + }, { + MemoryStart: 0x4000, + MemoryLimit: 0x5000, + FilenameStrindex: otlpb.addstr("service-c.so"), + }} + + otlpb.dictionary.LocationTable = []*v1experimental.Location{{ + MappingIndex: 0, // service-a.so + Address: 0x1100, + Lines: []*v1experimental.Line{{ + FunctionIndex: 0, + Line: 10, + }}, + }, { + MappingIndex: 0, // service-a.so + Address: 0x1200, + Lines: []*v1experimental.Line{{ + FunctionIndex: 1, + Line: 20, + }}, + }, { + MappingIndex: 1, // service-b.so + Address: 0x2100, + Lines: []*v1experimental.Line{{ + FunctionIndex: 2, + Line: 30, + }}, + }, { + MappingIndex: 1, // service-b.so + Address: 0x2200, + Lines: []*v1experimental.Line{{ + FunctionIndex: 3, + Line: 40, + }}, + }, { + MappingIndex: 2, // service-c.so + Address: 0xef0, + Lines: []*v1experimental.Line{{ + FunctionIndex: 4, + Line: 50, + }}, + }} + + otlpb.dictionary.FunctionTable = []*v1experimental.Function{{ + NameStrindex: otlpb.addstr("serviceA_func1"), + SystemNameStrindex: otlpb.addstr("serviceA_func1"), + FilenameStrindex: otlpb.addstr("service_a.go"), + }, { + NameStrindex: otlpb.addstr("serviceA_func2"), + SystemNameStrindex: otlpb.addstr("serviceA_func2"), + FilenameStrindex: otlpb.addstr("service_a.go"), + }, { + NameStrindex: otlpb.addstr("serviceB_func1"), + SystemNameStrindex: otlpb.addstr("serviceB_func1"), + FilenameStrindex: otlpb.addstr("service_b.go"), + }, { + NameStrindex: otlpb.addstr("serviceB_func2"), + SystemNameStrindex: otlpb.addstr("serviceB_func2"), + FilenameStrindex: otlpb.addstr("service_b.go"), + }, { + NameStrindex: otlpb.addstr("serviceC_func3"), + SystemNameStrindex: otlpb.addstr("serviceC_func3"), + FilenameStrindex: otlpb.addstr("service_c.go"), + }} + + otlpb.dictionary.StackTable = []*v1experimental.Stack{{ + LocationIndices: []int32{0, 1}, // Use first two locations + }, { + LocationIndices: []int32{2, 3}, + }, { + LocationIndices: []int32{4, 4}, + }} + + otlpb.profile.Samples = []*v1experimental.Sample{{ + StackIndex: 0, + Values: []int64{100}, + AttributeIndices: []int32{0}, + }, { + StackIndex: 1, + Values: []int64{200}, + AttributeIndices: []int32{1}, + }, { + StackIndex: 2, + Values: []int64{700}, + AttributeIndices: []int32{}, + }} + + otlpb.dictionary.AttributeTable = []*v1experimental.KeyValueAndUnit{{ + KeyStrindex: otlpb.addstr("service.name"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "service-a", + }, + }, + }, { + KeyStrindex: otlpb.addstr("service.name"), + Value: &v1.AnyValue{ + Value: &v1.AnyValue_StringValue{ + StringValue: "service-b", + }, + }, + }} + + otlpb.profile.SampleType = &v1experimental.ValueType{ + TypeStrindex: otlpb.addstr("samples"), + UnitStrindex: otlpb.addstr("count"), + } + otlpb.profile.PeriodType = &v1experimental.ValueType{ + TypeStrindex: otlpb.addstr("cpu"), + UnitStrindex: otlpb.addstr("nanoseconds"), + } + otlpb.profile.Period = 10000000 // 10ms + otlpb.profile.TimeUnixNano = 239 + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{{ + Profiles: []*v1experimental.Profile{ + &otlpb.profile, + }}}}}, + Dictionary: &otlpb.dictionary} + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + require.NoError(t, err) + + require.Equal(t, 1, len(profiles)) + require.Equal(t, 3, len(profiles[0].Series)) + + expectedProfiles := map[string]string{ + "{__delta__=\"false\", __name__=\"process_cpu\", __otel__=\"true\", service_name=\"service-a\"}": "testdata/TestDifferentServiceNames_service_a_profile.json", + "{__delta__=\"false\", __name__=\"process_cpu\", __otel__=\"true\", service_name=\"service-b\"}": "testdata/TestDifferentServiceNames_service_b_profile.json", + "{__delta__=\"false\", __name__=\"process_cpu\", __otel__=\"true\", service_name=\"unknown_service\"}": "testdata/TestDifferentServiceNames_unknown_profile.json", + } + + for _, s := range profiles[0].Series { + series := phlaremodel.Labels(s.Labels).ToPrometheusLabels().String() + assert.Contains(t, expectedProfiles, series) + expectedJsonPath := expectedProfiles[series] + expectedJson := readJSONFile(t, expectedJsonPath) + + gp := s.Profile.Profile + + require.Equal(t, 1, len(gp.SampleType)) + assert.Equal(t, "cpu", gp.StringTable[gp.SampleType[0].Type]) + assert.Equal(t, "nanoseconds", gp.StringTable[gp.SampleType[0].Unit]) + + require.NotNil(t, gp.PeriodType) + assert.Equal(t, "cpu", gp.StringTable[gp.PeriodType.Type]) + assert.Equal(t, "nanoseconds", gp.StringTable[gp.PeriodType.Unit]) + assert.Equal(t, int64(10000000), gp.Period) + + jsonStr, err := strprofile.Stringify(gp, strprofile.Options{}) + assert.NoError(t, err) + assert.JSONEq(t, expectedJson, jsonStr) + assert.NotContains(t, jsonStr, "service.name") + + } +} + +type otlpbuilder struct { + profile v1experimental.Profile + dictionary v1experimental.ProfilesDictionary + stringmap map[string]int32 +} + +func (o *otlpbuilder) addstr(s string) int32 { + if o.stringmap == nil { + o.stringmap = make(map[string]int32) + } + if idx, ok := o.stringmap[s]; ok { + return idx + } + idx := int32(len(o.stringmap)) + o.stringmap[s] = idx + o.dictionary.StringTable = append(o.dictionary.StringTable, s) + return idx +} + +func testConfig() server.Config { + cfg := server.Config{} + fs := flag.NewFlagSet("test", flag.PanicOnError) + cfg.RegisterFlags(fs) + return cfg +} + +func defaultLimits() validation.MockLimits { + return validation.MockLimits{ + IngestionBodyLimitBytesValue: 1024 * 1024 * 1024, // 1GB + } +} + +// createValidOTLPRequest creates a minimal valid OTLP profile export request for testing +func createValidOTLPRequest() *v1experimental2.ExportProfilesServiceRequest { + b := new(otlpbuilder) + b.dictionary.MappingTable = []*v1experimental.Mapping{{ + MemoryStart: 0x1000, + MemoryLimit: 0x2000, + FilenameStrindex: b.addstr("test.so"), + }} + b.dictionary.LocationTable = []*v1experimental.Location{{ + MappingIndex: 0, + Address: 0x1100, + }} + b.dictionary.StackTable = []*v1experimental.Stack{{ + LocationIndices: []int32{0}, + }} + b.profile.SampleType = &v1experimental.ValueType{ + TypeStrindex: b.addstr("samples"), + UnitStrindex: b.addstr("count"), + } + b.profile.Samples = []*v1experimental.Sample{{ + StackIndex: 0, + Values: []int64{100}, + }} + b.profile.TimeUnixNano = 1234567890 + + return &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{{ + Profiles: []*v1experimental.Profile{&b.profile}, + }}, + }}, + Dictionary: &b.dictionary, + } +} + +const otlpProfileJSON = `{ + "resourceProfiles": [{ + "scopeProfiles": [{ + "profiles": [{ + "sampleType": {"typeStrindex": 0, "unitStrindex": 1}, + "samples": [{"stackIndex": 0, "values": [100]}], + "timeUnixNano": "1234567890" + }] + }] + }], + "dictionary": { + "stringTable": ["samples", "count", "test.so"], + "mappingTable": [{"memoryStart": "4096", "memoryLimit": "8192", "filenameStrindex": 2}], + "locationTable": [{"mappingIndex": 0, "address": "4352"}], + "stackTable": [{"locationIndices": [0]}] + } + }` + +func TestHTTPRequestWithJSONAndTenantAccepted(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var capturedTenantID string + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + ctx := args.Get(0).(context.Context) + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + require.NoError(t, err) + capturedTenantID = tenantID + }).Return(nil, nil) + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + + httpReq := httptest.NewRequest("POST", "/otlp/v1/profiles", bytes.NewReader([]byte(otlpProfileJSON))) + httpReq.Header.Set("Content-Type", "application/json") + httpReq.Header.Set(user.OrgIDHeaderName, "json-tenant") + + w := httptest.NewRecorder() + httputil.AuthenticateUser(true).Wrap(h).ServeHTTP(w, httpReq) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "json-tenant", capturedTenantID) +} + +func TestHTTPExportErrorStatusCodes(t *testing.T) { + for _, tc := range []struct { + name string + pushErr error + wantStatus int + }{ + { + name: "tenant over ingestion limit is a client error (429)", + pushErr: connect.NewError(connect.CodeResourceExhausted, fmt.Errorf("limit of 0 B/month reached, next reset at 2026-08-01T00:00:00Z")), + wantStatus: http.StatusTooManyRequests, + }, + { + name: "validation failure is a client error (400)", + pushErr: validation.NewErrorf(validation.ProfileSizeLimit, "profile size exceeds limit"), + wantStatus: http.StatusBadRequest, + }, + { + name: "unexpected push failure is a server error (500)", + pushErr: fmt.Errorf("ingester unreachable"), + wantStatus: http.StatusInternalServerError, + }, + } { + t.Run(tc.name, func(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + svc.On("PushBatch", mock.Anything, mock.Anything).Return(tc.pushErr) + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + + httpReq := httptest.NewRequest("POST", "/otlp/v1/profiles", bytes.NewReader([]byte(otlpProfileJSON))) + httpReq.Header.Set("Content-Type", "application/json") + httpReq.Header.Set(user.OrgIDHeaderName, "tenant-a") + + w := httptest.NewRecorder() + httputil.AuthenticateUser(true).Wrap(h).ServeHTTP(w, httpReq) + + assert.Equal(t, tc.wantStatus, w.Code) + }) + } +} + +func TestExportGRPCStatusCodes(t *testing.T) { + req := &v1experimental2.ExportProfilesServiceRequest{} + require.NoError(t, protojson.Unmarshal([]byte(otlpProfileJSON), req)) + + for _, tc := range []struct { + name string + pushErr error + wantCode codes.Code + }{ + { + name: "tenant over ingestion limit maps to ResourceExhausted", + pushErr: connect.NewError(connect.CodeResourceExhausted, fmt.Errorf("limit of 0 B/month reached")), + wantCode: codes.ResourceExhausted, + }, + { + name: "unexpected push failure stays Unknown", + pushErr: fmt.Errorf("ingester unreachable"), + wantCode: codes.Unknown, + }, + } { + t.Run(tc.name, func(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + svc.On("PushBatch", mock.Anything, mock.Anything).Return(tc.pushErr) + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + + ctx := user.InjectOrgID(context.Background(), "tenant-a") + _, err := h.Export(ctx, req) + require.Error(t, err) + assert.Equal(t, tc.wantCode, status.Code(err)) + }) + } +} + +func TestExportSetsDecompressedSizeForOTLP(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var capturedReq *model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + capturedReq = args.Get(1).(*model.PushRequest) + }).Return(nil) + + req := createValidOTLPRequest() + expectedSize := proto.Size(req.ResourceProfiles[0].ScopeProfiles[0].Profiles[0]) + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + require.NoError(t, err) + require.NotNil(t, capturedReq) + assert.Equal(t, expectedSize, capturedReq.ReceivedDecompressedProfileSize) +} + +func TestHTTPRequestWithGzipCompression(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var capturedTenantID string + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + ctx := args.Get(0).(context.Context) + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + require.NoError(t, err) + capturedTenantID = tenantID + }).Return(nil, nil) + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + + req := createValidOTLPRequest() + reqBytes, err := proto.Marshal(req) + require.NoError(t, err) + + var gzipBuf bytes.Buffer + gzipWriter := gzip.NewWriter(&gzipBuf) + _, err = gzipWriter.Write(reqBytes) + require.NoError(t, err) + err = gzipWriter.Close() + require.NoError(t, err) + + httpReq := httptest.NewRequest("POST", "/otlp/v1/profiles", bytes.NewReader(gzipBuf.Bytes())) + httpReq.Header.Set("Content-Type", "application/x-protobuf") + httpReq.Header.Set("Content-Encoding", "gzip") + + w := httptest.NewRecorder() + httputil.AuthenticateUser(false).Wrap(h).ServeHTTP(w, httpReq) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, tenant.DefaultTenantID, capturedTenantID) +} + +func TestHTTPRequestWithGzipCompressionAndJSON(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var capturedTenantID string + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + ctx := args.Get(0).(context.Context) + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + require.NoError(t, err) + capturedTenantID = tenantID + }).Return(nil, nil) + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + + var gzipBuf bytes.Buffer + gzipWriter := gzip.NewWriter(&gzipBuf) + _, err := gzipWriter.Write([]byte(otlpProfileJSON)) + require.NoError(t, err) + err = gzipWriter.Close() + require.NoError(t, err) + + httpReq := httptest.NewRequest("POST", "/otlp/v1/profiles", bytes.NewReader(gzipBuf.Bytes())) + httpReq.Header.Set("Content-Type", "application/json") + httpReq.Header.Set("Content-Encoding", "gzip") + httpReq.Header.Set(user.OrgIDHeaderName, "gzip-json-tenant") + + w := httptest.NewRecorder() + httputil.AuthenticateUser(true).Wrap(h).ServeHTTP(w, httpReq) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Equal(t, "gzip-json-tenant", capturedTenantID) +} + +// TestExport_SinglePushBatchPerExport verifies that profiles spread across +// multiple ResourceProfiles/ScopeProfiles collapse into exactly one PushBatch +// call, with every converted profile accumulated into that single request. +func TestExport_SinglePushBatchPerExport(t *testing.T) { + svc, profiles := recordPushBatch(t) + + b := new(otlpbuilder) + p0 := newCPUProfile(b, 5, 100, 10) + p1 := newCPUProfile(b, 7, 200, 20) + p2 := newCPUProfile(b, 9, 300, 30) + + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{ + {Profiles: []*v1experimental.Profile{p0}}, + {Profiles: []*v1experimental.Profile{p1}}, + }, + }, { + ScopeProfiles: []*v1experimental.ScopeProfiles{ + {Profiles: []*v1experimental.Profile{p2}}, + }, + }}, + Dictionary: &b.dictionary, + } + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + require.NoError(t, err) + + require.Equal(t, 1, len(*profiles), "PushBatch must be called exactly once per export") + require.Equal(t, 3, len((*profiles)[0].Series), "every converted profile must accumulate into the single request") + assert.Equal(t, model.RawProfileTypeOTEL, (*profiles)[0].RawProfileType) +} + +// TestExport_SeriesCountEqualsConvertedProfiles verifies that N messages with +// distinct services produce N separate series in a single PushBatch call. +func TestExport_SeriesCountEqualsConvertedProfiles(t *testing.T) { + svc, profiles := recordPushBatch(t) + + services := []string{"svc-a", "svc-b", "svc-c"} + + b := new(otlpbuilder) + sps := make([]*v1experimental.ScopeProfiles, 0, len(services)) + for i, name := range services { + p := newCPUProfile(b, uint64(5+i), uint64(100+i*10), 10) + attrIdx := int32(len(b.dictionary.AttributeTable)) + b.dictionary.AttributeTable = append(b.dictionary.AttributeTable, &v1experimental.KeyValueAndUnit{ + KeyStrindex: b.addstr("service.name"), + Value: &v1.AnyValue{Value: &v1.AnyValue_StringValue{StringValue: name}}, + }) + p.Samples[0].AttributeIndices = []int32{attrIdx} + sps = append(sps, &v1experimental.ScopeProfiles{Profiles: []*v1experimental.Profile{p}}) + } + + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ScopeProfiles: sps}}, + Dictionary: &b.dictionary, + } + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + require.NoError(t, err) + + require.Equal(t, 1, len(*profiles), "PushBatch must be called exactly once") + require.Equal(t, len(services), len((*profiles)[0].Series), "series count must equal the number of converted profiles") + + got := map[string]bool{} + for _, s := range (*profiles)[0].Series { + for _, l := range s.Labels { + if l.Name == phlaremodel.LabelNameServiceName { + got[l.Value] = true + } + } + } + assert.Equal(t, map[string]bool{"svc-a": true, "svc-b": true, "svc-c": true}, got) +} + +// TestExport_SumsReceivedSizesAcrossMessages verifies that both +// Received{Compressed,Decompressed}ProfileSize equal the sum of proto.Size over +// every Profile message, measured before conversion (ConvertOtelToGoogle mutates +// the profile in place, so measuring after would misreport the size). +func TestExport_SumsReceivedSizesAcrossMessages(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var capturedReq *model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + capturedReq = args.Get(1).(*model.PushRequest) + }).Return(nil) + + b := new(otlpbuilder) + p0 := newCPUProfile(b, 5, 100, 10) + p1 := newCPUProfile(b, 7, 200, 20) + + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{{ + Profiles: []*v1experimental.Profile{p0, p1}, + }}, + }}, + Dictionary: &b.dictionary, + } + + // Measured before Export: ConvertOtelToGoogle mutates the profiles in place. + expectedSize := proto.Size(p0) + proto.Size(p1) + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + require.NoError(t, err) + require.NotNil(t, capturedReq) + assert.Equal(t, expectedSize, capturedReq.ReceivedDecompressedProfileSize) + assert.Equal(t, expectedSize, capturedReq.ReceivedCompressedProfileSize) +} + +// TestExport_EmptyRequest_NoPushBatch_Success verifies that a request whose +// profiles yield zero series does NOT call PushBatch and returns success (a +// zero-series PushBatch would otherwise be a spurious error). +func TestExport_EmptyRequest_NoPushBatch_Success(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + var profiles []*model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + profiles = append(profiles, args.Get(1).(*model.PushRequest)) + }).Return(nil).Maybe() + + b := new(otlpbuilder) + // A profile with no samples converts to zero series. + p := &v1experimental.Profile{TimeUnixNano: 239} + + req := &v1experimental2.ExportProfilesServiceRequest{ + ResourceProfiles: []*v1experimental.ResourceProfiles{{ + ScopeProfiles: []*v1experimental.ScopeProfiles{{ + Profiles: []*v1experimental.Profile{p}, + }}, + }}, + Dictionary: &b.dictionary, + } + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + require.NoError(t, err) + require.Equal(t, 0, len(profiles), "PushBatch must not be called when there are no series") +} + +// TestExport_PushBatchError_Propagates verifies that an error from PushBatch is +// propagated (wrapped) back out of Export. +func TestExport_PushBatchError_Propagates(t *testing.T) { + svc := mockotlp.NewMockPushService(t) + svc.On("PushBatch", mock.Anything, mock.Anything).Return(assert.AnError) + + req := createValidOTLPRequest() + + logger := test.NewTestingLogger(t) + h := NewOTLPIngestHandler(testConfig(), svc, logger, defaultLimits()) + _, err := h.Export(user.InjectOrgID(context.Background(), tenant.DefaultTenantID), req) + require.Error(t, err) + assert.ErrorContains(t, err, "failed to make a GRPC request") +} + +// recordPushBatch wires a mock PushService that records every PushRequest it +// receives (labels sorted for deterministic comparison). +func recordPushBatch(t *testing.T) (*mockotlp.MockPushService, *[]*model.PushRequest) { + t.Helper() + svc := mockotlp.NewMockPushService(t) + var profiles []*model.PushRequest + svc.On("PushBatch", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + c := (args.Get(1)).(*model.PushRequest) + for _, series := range c.Series { + sort.Sort(phlaremodel.Labels(series.Labels)) + } + profiles = append(profiles, c) + }).Return(nil) + return svc, &profiles +} + +// newCPUProfile builds a minimal profile that references the shared builder's +// dictionary. value is the single sample value; the SampleType/PeriodType are +// fixed to "samples"/"count" and "cpu"/"nanoseconds" so repeated calls share a +// label set. +func newCPUProfile(b *otlpbuilder, value, timeUnixNano, durationNanos uint64) *v1experimental.Profile { + stackIdx := int32(len(b.dictionary.StackTable)) + locIdx := int32(len(b.dictionary.LocationTable)) + mapIdx := int32(len(b.dictionary.MappingTable)) + funcIdx := int32(len(b.dictionary.FunctionTable)) + + b.dictionary.FunctionTable = append(b.dictionary.FunctionTable, &v1experimental.Function{ + NameStrindex: b.addstr("shared_func"), + SystemNameStrindex: b.addstr("shared_func"), + FilenameStrindex: b.addstr("shared.go"), + }) + b.dictionary.MappingTable = append(b.dictionary.MappingTable, &v1experimental.Mapping{ + MemoryStart: 0x1000, + MemoryLimit: 0x2000, + FilenameStrindex: b.addstr("shared.so"), + }) + b.dictionary.LocationTable = append(b.dictionary.LocationTable, &v1experimental.Location{ + MappingIndex: mapIdx, + Address: 0x1100, + Lines: []*v1experimental.Line{{ + FunctionIndex: funcIdx, + Line: 10, + }}, + }) + b.dictionary.StackTable = append(b.dictionary.StackTable, &v1experimental.Stack{ + LocationIndices: []int32{locIdx}, + }) + + return &v1experimental.Profile{ + SampleType: &v1experimental.ValueType{ + TypeStrindex: b.addstr("samples"), + UnitStrindex: b.addstr("count"), + }, + PeriodType: &v1experimental.ValueType{ + TypeStrindex: b.addstr("cpu"), + UnitStrindex: b.addstr("nanoseconds"), + }, + Period: 10000000, + TimeUnixNano: timeUnixNano, + DurationNano: durationNanos, + Samples: []*v1experimental.Sample{{ + StackIndex: stackIdx, + Values: []int64{int64(value)}, + }}, + } +} diff --git a/pkg/ingester/otlp/internal/cmd/otlp-profile-dump/main.go b/pkg/ingester/otlp/internal/cmd/otlp-profile-dump/main.go new file mode 100644 index 0000000000..f2e3dde9fd --- /dev/null +++ b/pkg/ingester/otlp/internal/cmd/otlp-profile-dump/main.go @@ -0,0 +1,117 @@ +package main + +import ( + "context" + "fmt" + "net" + "os" + "path/filepath" + "sync/atomic" + "time" + + "google.golang.org/grpc" + _ "google.golang.org/grpc/encoding/gzip" + "google.golang.org/grpc/keepalive" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + profilesv1 "go.opentelemetry.io/proto/otlp/collector/profiles/v1development" +) + +type dumpServer struct { + profilesv1.UnimplementedProfilesServiceServer + outDir string + counter atomic.Int64 +} + +func (s *dumpServer) Export(ctx context.Context, req *profilesv1.ExportProfilesServiceRequest) (*profilesv1.ExportProfilesServiceResponse, error) { + n := s.counter.Add(1) + ts := time.Now().Format("20060102-150405") + base := fmt.Sprintf("dump-%s-%04d", ts, n) + + binPath := filepath.Join(s.outDir, base+".pb.bin") + jsonPath := filepath.Join(s.outDir, base+".pb.json") + + bin, err := proto.Marshal(req) + if err != nil { + fmt.Fprintf(os.Stderr, "marshal binary: %v\n", err) + return &profilesv1.ExportProfilesServiceResponse{}, nil + } + if err := os.WriteFile(binPath, bin, 0644); err != nil { + fmt.Fprintf(os.Stderr, "write %s: %v\n", binPath, err) + return &profilesv1.ExportProfilesServiceResponse{}, nil + } + + jsonBytes, err := protojson.Marshal(req) + if err != nil { + fmt.Fprintf(os.Stderr, "marshal json: %v\n", err) + return &profilesv1.ExportProfilesServiceResponse{}, nil + } + if err := os.WriteFile(jsonPath, jsonBytes, 0644); err != nil { + fmt.Fprintf(os.Stderr, "write %s: %v\n", jsonPath, err) + return &profilesv1.ExportProfilesServiceResponse{}, nil + } + + // Print summary with sample types + nProfiles := 0 + dict := req.GetDictionary() + var sampleTypes []string + for _, rp := range req.GetResourceProfiles() { + for _, sp := range rp.GetScopeProfiles() { + nProfiles += len(sp.GetProfiles()) + for _, p := range sp.GetProfiles() { + if dict != nil && p.GetSampleType() != nil { + st := p.GetSampleType() + strTable := dict.GetStringTable() + typStr, unitStr := "", "" + if int(st.TypeStrindex) < len(strTable) { + typStr = strTable[st.TypeStrindex] + } + if int(st.UnitStrindex) < len(strTable) { + unitStr = strTable[st.UnitStrindex] + } + sampleTypes = append(sampleTypes, typStr+":"+unitStr) + } + } + } + } + fmt.Printf("[%04d] %s %d bytes %d profiles types=%v\n", n, base, len(bin), nProfiles, sampleTypes) + + return &profilesv1.ExportProfilesServiceResponse{}, nil +} + +func main() { + outDir := ".tmp/otlp-dumps" + listenAddr := ":11000" + if len(os.Args) > 1 { + listenAddr = os.Args[1] + } + if len(os.Args) > 2 { + outDir = os.Args[2] + } + + if err := os.MkdirAll(outDir, 0755); err != nil { + fmt.Fprintf(os.Stderr, "mkdir %s: %v\n", outDir, err) + os.Exit(1) + } + + lis, err := net.Listen("tcp", listenAddr) + if err != nil { + fmt.Fprintf(os.Stderr, "listen %s: %v\n", listenAddr, err) + os.Exit(1) + } + + srv := grpc.NewServer( + grpc.MaxRecvMsgSize(64*1024*1024), + grpc.KeepaliveParams(keepalive.ServerParameters{ + MaxConnectionIdle: 5 * time.Minute, + }), + ) + profilesv1.RegisterProfilesServiceServer(srv, &dumpServer{outDir: outDir}) + + fmt.Printf("OTLP profile dump server listening on %s, writing to %s\n", listenAddr, outDir) + if err := srv.Serve(lis); err != nil { + fmt.Fprintf(os.Stderr, "serve: %v\n", err) + os.Exit(1) + } +} diff --git a/pkg/ingester/otlp/testdata/TestConversionOffCpu.json b/pkg/ingester/otlp/testdata/TestConversionOffCpu.json new file mode 100644 index 0000000000..f9e175b1bf --- /dev/null +++ b/pkg/ingester/otlp/testdata/TestConversionOffCpu.json @@ -0,0 +1,35 @@ +{ + "sample_types": [ + { + "type": "off_cpu", + "unit": "nanoseconds" + } + ], + "samples": [ + { + "locations": [ + { + "address": "0x1e0", + "mapping": "0x1000-0x1000@0x0 file1.so()" + }, + { + "address": "0x2f0", + "mapping": "0x1000-0x1000@0x0 file1.so()" + } + ], + "values": "239" + }, + { + "locations": [ + { + "address": "0x3f0", + "mapping": "0x1000-0x1000@0x0 file1.so()" + } + ], + "values": "21" + } + ], + "time_nanos": "239", + "duration_nanos": "10000000000", + "period": "0" +} diff --git a/pkg/ingester/otlp/testdata/TestDifferentServiceNames_service_a_profile.json b/pkg/ingester/otlp/testdata/TestDifferentServiceNames_service_a_profile.json new file mode 100644 index 0000000000..df2c46afa6 --- /dev/null +++ b/pkg/ingester/otlp/testdata/TestDifferentServiceNames_service_a_profile.json @@ -0,0 +1,32 @@ +{ + "sample_types": [ + { + "type": "cpu", + "unit": "nanoseconds" + } + ], + "samples": [ + { + "locations": [ + { + "address": "0x1100", + "lines": [ + "serviceA_func1[serviceA_func1]@service_a.go:10" + ], + "mapping": "0x1000-0x2000@0x0 service-a.so()" + }, + { + "address": "0x1200", + "lines": [ + "serviceA_func2[serviceA_func2]@service_a.go:20" + ], + "mapping": "0x1000-0x2000@0x0 service-a.so()" + } + ], + "values": "1000000000" + } + ], + "time_nanos": "239", + "duration_nanos": "10000000000", + "period": "10000000" +} \ No newline at end of file diff --git a/pkg/ingester/otlp/testdata/TestDifferentServiceNames_service_b_profile.json b/pkg/ingester/otlp/testdata/TestDifferentServiceNames_service_b_profile.json new file mode 100644 index 0000000000..514a2647ee --- /dev/null +++ b/pkg/ingester/otlp/testdata/TestDifferentServiceNames_service_b_profile.json @@ -0,0 +1,32 @@ +{ + "sample_types": [ + { + "type": "cpu", + "unit": "nanoseconds" + } + ], + "samples": [ + { + "locations": [ + { + "address": "0x2100", + "lines": [ + "serviceB_func1[serviceB_func1]@service_b.go:30" + ], + "mapping": "0x2000-0x3000@0x0 service-b.so()" + }, + { + "address": "0x2200", + "lines": [ + "serviceB_func2[serviceB_func2]@service_b.go:40" + ], + "mapping": "0x2000-0x3000@0x0 service-b.so()" + } + ], + "values": "2000000000" + } + ], + "time_nanos": "239", + "duration_nanos": "10000000000", + "period": "10000000" +} \ No newline at end of file diff --git a/pkg/ingester/otlp/testdata/TestDifferentServiceNames_unknown_profile.json b/pkg/ingester/otlp/testdata/TestDifferentServiceNames_unknown_profile.json new file mode 100644 index 0000000000..cada8fe8bc --- /dev/null +++ b/pkg/ingester/otlp/testdata/TestDifferentServiceNames_unknown_profile.json @@ -0,0 +1,32 @@ +{ + "sample_types": [ + { + "type": "cpu", + "unit": "nanoseconds" + } + ], + "samples": [ + { + "locations": [ + { + "address": "0xef0", + "lines": [ + "serviceC_func3[serviceC_func3]@service_c.go:50" + ], + "mapping": "0x4000-0x5000@0x0 service-c.so()" + }, + { + "address": "0xef0", + "lines": [ + "serviceC_func3[serviceC_func3]@service_c.go:50" + ], + "mapping": "0x4000-0x5000@0x0 service-c.so()" + } + ], + "values": "7000000000" + } + ], + "time_nanos": "239", + "duration_nanos": "10000000000", + "period": "10000000" +} \ No newline at end of file diff --git a/pkg/ingester/otlp/testdata/TestSampleAttributes.json b/pkg/ingester/otlp/testdata/TestSampleAttributes.json new file mode 100644 index 0000000000..402815c099 --- /dev/null +++ b/pkg/ingester/otlp/testdata/TestSampleAttributes.json @@ -0,0 +1,41 @@ +{ + "sample_types": [ + { + "type": "samples", + "unit": "ms" + } + ], + "samples": [ + { + "locations": [ + { + "address": "0x1e", + "mapping": "0x1000-0x1000@0x0 firefox.so()" + }, + { + "address": "0x2e", + "mapping": "0x1000-0x1000@0x0 firefox.so()" + } + ], + "values": "239", + "labels": "cpu.logical_number=0,process=firefox" + }, + { + "locations": [ + { + "address": "0x3e", + "mapping": "0x1000-0x1000@0x0 chrome.so()" + }, + { + "address": "0x4e", + "mapping": "0x1000-0x1000@0x0 chrome.so()" + } + ], + "values": "61423", + "labels": "cpu.logical_number=7,process=chrome" + } + ], + "time_nanos": "239", + "duration_nanos": "10000000000", + "period": "0" +} \ No newline at end of file diff --git a/pkg/ingester/otlp/testdata/TestSymbolizedFunctionNames.json b/pkg/ingester/otlp/testdata/TestSymbolizedFunctionNames.json new file mode 100644 index 0000000000..8f4dcf21a5 --- /dev/null +++ b/pkg/ingester/otlp/testdata/TestSymbolizedFunctionNames.json @@ -0,0 +1,26 @@ +{ + "sample_types": [ + { + "type": "samples", + "unit": "ms" + } + ], + "samples": [ + { + "locations": [ + { + "address": "0x1e0", + "mapping": "0x1000-0x1000@0x0 file1.so()" + }, + { + "address": "0x2f0", + "mapping": "0x1000-0x1000@0x0 file1.so()" + } + ], + "values": "239" + } + ], + "time_nanos": "239", + "duration_nanos": "10000000000", + "period": "0" +} diff --git a/pkg/ingester/pyroscope/ingest_adapter.go b/pkg/ingester/pyroscope/ingest_adapter.go index 05c049e118..afe5e475ac 100644 --- a/pkg/ingester/pyroscope/ingest_adapter.go +++ b/pkg/ingester/pyroscope/ingest_adapter.go @@ -9,47 +9,54 @@ import ( "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/pkg/distributor/model" - "github.com/grafana/pyroscope/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/tenant" "connectrpc.com/connect" + "google.golang.org/protobuf/proto" + "github.com/go-kit/log" "github.com/google/uuid" - "github.com/prometheus/prometheus/model/labels" - "google.golang.org/protobuf/proto" + prommodel "github.com/prometheus/common/model" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage" - "github.com/grafana/pyroscope/pkg/og/storage/tree" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" ) type PushService interface { Push(ctx context.Context, req *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) - PushParsed(ctx context.Context, req *model.PushRequest) (*connect.Response[pushv1.PushResponse], error) + PushBatch(ctx context.Context, req *model.PushRequest) error +} + +type Limits interface { + MaxProfileSizeBytes(tenantID string) int + MaxProfileSymbolValueLength(tenantID string) int + MaxProfileStacktraceSamples(tenantID string) int } -func NewPyroscopeIngestHandler(svc PushService, logger log.Logger) http.Handler { +func NewPyroscopeIngestHandler(svc PushService, limits Limits, logger log.Logger) http.Handler { return NewIngestHandler( logger, - &pyroscopeIngesterAdapter{svc: svc, log: logger}, + &pyroscopeIngesterAdapter{svc: svc, limits: limits, log: logger}, ) } type pyroscopeIngesterAdapter struct { - svc PushService - log log.Logger + svc PushService + limits Limits + log log.Logger } func (p *pyroscopeIngesterAdapter) Ingest(ctx context.Context, in *ingestion.IngestInput) error { pprofable, ok := in.Profile.(ingestion.ParseableToPprof) if ok { return p.parseToPprof(ctx, in, pprofable) - } else { - return in.Profile.Parse(ctx, p, p, in.Metadata) } + return in.Profile.Parse(ctx, p, p, in.Metadata, p.limits) } const ( @@ -69,7 +76,7 @@ const ( ) func (p *pyroscopeIngesterAdapter) Put(ctx context.Context, pi *storage.PutInput) error { - if pi.Key.HasProfileID() { + if pi.LabelSet.HasProfileID() { return nil } metric, stType, stUnit, app, err := convertMetadata(pi) @@ -107,10 +114,10 @@ func (p *pyroscopeIngesterAdapter) Put(ctx context.Context, pi *storage.PutInput } req := &pushv1.PushRequest{} series := &pushv1.RawProfileSeries{ - Labels: make([]*typesv1.LabelPair, 0, 3+len(pi.Key.Labels())), + Labels: make([]*typesv1.LabelPair, 0, 3+len(pi.LabelSet.Labels())), } series.Labels = append(series.Labels, &typesv1.LabelPair{ - Name: labels.MetricName, + Name: string(prommodel.MetricNameLabel), Value: metric, }, &typesv1.LabelPair{ Name: phlaremodel.LabelNameDelta, @@ -123,7 +130,7 @@ func (p *pyroscopeIngesterAdapter) Put(ctx context.Context, pi *storage.PutInput }) } hasServiceName := false - for k, v := range pi.Key.Labels() { + for k, v := range pi.LabelSet.Labels() { if !phlaremodel.IsLabelAllowedForIngestion(k) { continue } @@ -142,10 +149,21 @@ func (p *pyroscopeIngesterAdapter) Put(ctx context.Context, pi *storage.PutInput Value: app, }) } else { - series.Labels = append(series.Labels, &typesv1.LabelPair{ - Name: "app_name", - Value: app, - }) + // Check if app_name already exists + hasAppName := false + for _, label := range series.Labels { + if label.Name == "app_name" { + hasAppName = true + break + } + } + + if !hasAppName { + series.Labels = append(series.Labels, &typesv1.LabelPair{ + Name: "app_name", + Value: app, + }) + } } series.Samples = []*pushv1.RawSample{{ RawProfile: b, @@ -163,19 +181,25 @@ func (p *pyroscopeIngesterAdapter) Evaluate(input *storage.PutInput) (storage.Sa return nil, false // noop } -func (p *pyroscopeIngesterAdapter) parseToPprof(ctx context.Context, in *ingestion.IngestInput, pprofable ingestion.ParseableToPprof) error { - plainReq, err := pprofable.ParseToPprof(ctx, in.Metadata) +func (p *pyroscopeIngesterAdapter) parseToPprof( + ctx context.Context, + in *ingestion.IngestInput, + pprofable ingestion.ParseableToPprof, +) error { + parseStart := time.Now() + plainReq, err := pprofable.ParseToPprof(ctx, in.Metadata, p.limits) if err != nil { return fmt.Errorf("parsing IngestInput-pprof failed %w", err) } + plainReq.ParseDuration = time.Since(parseStart) if len(plainReq.Series) == 0 { tenantID, _ := tenant.ExtractTenantIDFromContext(ctx) _ = level.Debug(p.log).Log("msg", "empty profile", - "application", in.Metadata.Key.AppName(), + "application", in.Metadata.LabelSet.ServiceName(), "orgID", tenantID) return nil } - _, err = p.svc.PushParsed(ctx, plainReq) + err = p.svc.PushBatch(ctx, plainReq) if err != nil { return fmt.Errorf("pushing IngestInput-pprof failed %w", err) } @@ -183,7 +207,7 @@ func (p *pyroscopeIngesterAdapter) parseToPprof(ctx context.Context, in *ingesti } func convertMetadata(pi *storage.PutInput) (metricName, stType, stUnit, app string, err error) { - app = pi.Key.AppName() + app = pi.LabelSet.ServiceName() parts := strings.Split(app, ".") if len(parts) <= 1 { stType = stTypeCPU @@ -267,6 +291,14 @@ func convertMetadata(pi *storage.PutInput) (metricName, stType, stUnit, app stri metricName = "exceptions" stType = stTypeSamples stUnit = stUnitCount + case "seconds", "nanoseconds", "microseconds", "milliseconds": + metricName = metricWall + stType = stTypeSamples + stUnit = stUnitCount + case "bytes": + metricName = metricMemory + stType = stTypeSamples + stUnit = stUnitBytes default: err = fmt.Errorf("unknown profile type: %s", stType) } diff --git a/pkg/ingester/pyroscope/ingest_adapter_test.go b/pkg/ingester/pyroscope/ingest_adapter_test.go new file mode 100644 index 0000000000..103a1c4a33 --- /dev/null +++ b/pkg/ingester/pyroscope/ingest_adapter_test.go @@ -0,0 +1,107 @@ +package pyroscope + +import ( + "context" + "testing" + "time" + + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + "github.com/grafana/pyroscope/api/model/labelset" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockpyroscope" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestPutLabelHandling(t *testing.T) { + tests := []struct { + name string + labels map[string]string + expectedLabels map[string]string + }{ + { + name: "No service_name adds service_name", + labels: map[string]string{ + "__name__": "testapp", + }, + expectedLabels: map[string]string{ + "service_name": "testapp", + }, + }, + { + name: "With service_name adds app_name", + labels: map[string]string{ + "__name__": "testapp", + "service_name": "custom-service", + }, + expectedLabels: map[string]string{ + "service_name": "custom-service", + "app_name": "testapp", + }, + }, + { + name: "With service_name and app_name doesn't duplicate app_name", + labels: map[string]string{ + "__name__": "testapp", + "service_name": "custom-service", + "app_name": "existing-app", + }, + expectedLabels: map[string]string{ + "service_name": "custom-service", + "app_name": "existing-app", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockService := mockpyroscope.NewMockPushService(t) + adapter := &pyroscopeIngesterAdapter{ + svc: mockService, + log: log.NewNopLogger(), + } + + mockService.On("Push", mock.Anything, mock.MatchedBy(func(req *connect.Request[pushv1.PushRequest]) bool { + if len(req.Msg.Series) > 0 { + labels := req.Msg.Series[0].Labels + + // Check expected labels + labelMap := make(map[string]string) + labelCounts := make(map[string]int) + for _, label := range labels { + labelMap[label.Name] = label.Value + labelCounts[label.Name]++ + } + + // Verify expected values + for key, val := range tt.expectedLabels { + assert.Equal(t, val, labelMap[key], "Label %s should have value %s", key, val) + } + + // Verify no duplicates + for name, count := range labelCounts { + assert.Equal(t, 1, count, "Label %s appears %d times, should appear exactly once", name, count) + } + } + return true + })).Return(&connect.Response[pushv1.PushResponse]{}, nil) + + ls := labelset.New(tt.labels) + putInput := &storage.PutInput{ + LabelSet: ls, + StartTime: time.Now(), + Val: tree.New(), + SampleRate: 100, + SpyName: "testapp", + } + + err := adapter.Put(context.Background(), putInput) + require.NoError(t, err) + }) + } +} diff --git a/pkg/ingester/pyroscope/ingest_handler.go b/pkg/ingester/pyroscope/ingest_handler.go index d650e01153..18ee0732c2 100644 --- a/pkg/ingester/pyroscope/ingest_handler.go +++ b/pkg/ingester/pyroscope/ingest_handler.go @@ -2,6 +2,8 @@ package pyroscope import ( "bytes" + "context" + "errors" "fmt" "io" "net/http" @@ -9,22 +11,28 @@ import ( "strings" "time" - "github.com/grafana/pyroscope/pkg/tenant" - httputil "github.com/grafana/pyroscope/pkg/util/http" + "connectrpc.com/connect" + "github.com/grafana/dskit/tracing" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" - "github.com/grafana/pyroscope/pkg/og/convert/speedscope" + "github.com/grafana/pyroscope/v2/pkg/tenant" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" + + "github.com/grafana/pyroscope/v2/pkg/og/convert/speedscope" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/pkg/og/agent/types" - "github.com/grafana/pyroscope/pkg/og/convert/jfr" - "github.com/grafana/pyroscope/pkg/og/convert/pprof" - "github.com/grafana/pyroscope/pkg/og/convert/profile" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/segment" - "github.com/grafana/pyroscope/pkg/og/util/attime" + "github.com/grafana/pyroscope/api/model/labelset" + "github.com/grafana/pyroscope/v2/pkg/og/agent/types" + "github.com/grafana/pyroscope/v2/pkg/og/convert/jfr" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof" + "github.com/grafana/pyroscope/v2/pkg/og/convert/profile" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/util/attime" ) // Copy-pasted from @@ -43,34 +51,77 @@ func NewIngestHandler(l log.Logger, p ingestion.Ingester) http.Handler { } func (h ingestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - tenantID, _ := tenant.ExtractTenantIDFromContext(r.Context()) - input, err := h.ingestInputFromRequest(r) + ctx := r.Context() + sp, ctx := tracing.StartSpanFromContext(ctx, "ingestHandler.ServeHTTP") + defer sp.Finish() + + otelSpan := trace.SpanFromContext(ctx) + tenantID, _ := tenant.ExtractTenantIDFromContext(ctx) + sp.SetTag("tenant_id", tenantID) + input, err := h.parseInputMetadataFromRequest(ctx, r) if err != nil { - _ = h.log.Log("msg", "bad request", "err", err, "orgID", tenantID) + msg := "failed to parse request metadata" + sp.LogError(err) + sp.SetError() + otelSpan.AddEvent(msg) + _ = h.log.Log("msg", msg, "err", err, "orgID", tenantID) httputil.ErrorWithStatus(w, err, http.StatusBadRequest) return } - err = h.ingester.Ingest(r.Context(), input) - if err != nil { - _ = h.log.Log("msg", "pyroscope ingest", "err", err, "orgID", tenantID) + if err := readInputRawDataFromRequest(ctx, r, input); err != nil { + var status int + var maxBytesError *http.MaxBytesError + switch { + case errors.As(err, &maxBytesError): + err = fmt.Errorf("request body too large: %w", err) + status = http.StatusRequestEntityTooLarge + validation.DiscardedBytes.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(float64(maxBytesError.Limit)) + validation.DiscardedProfiles.WithLabelValues(string(validation.BodySizeLimit), tenantID).Add(float64(1)) + default: + status = http.StatusRequestTimeout + } + + msg := "failed to read request body" + sp.LogError(err) + sp.SetError() + otelSpan.AddEvent(msg) + _ = h.log.Log("msg", msg, "err", err, "orgID", tenantID) + httputil.ErrorWithStatus(w, err, status) + return + } + err = h.ingester.Ingest(ctx, input) + if err != nil { if ingestion.IsIngestionError(err) { + msg := "failed to convert profile" + sp.LogError(err) + sp.SetError() + otelSpan.AddEvent(msg) + _ = h.log.Log("msg", msg, "err", err, "orgID", tenantID) httputil.Error(w, err) } else { - httputil.ErrorWithStatus(w, err, http.StatusUnprocessableEntity) + msg := "failed to ingest profile" + sp.LogError(err) + sp.SetError() + otelSpan.AddEvent(msg) + if connect.CodeOf(err) == connect.CodeResourceExhausted { + httputil.ErrorWithStatus(w, err, http.StatusTooManyRequests) + } else { + httputil.ErrorWithStatus(w, err, http.StatusUnprocessableEntity) + } } } } -func (h ingestHandler) ingestInputFromRequest(r *http.Request) (*ingestion.IngestInput, error) { +func (h ingestHandler) parseInputMetadataFromRequest(_ context.Context, r *http.Request) (*ingestion.IngestInput, error) { var ( q = r.URL.Query() input ingestion.IngestInput err error ) - input.Metadata.Key, err = segment.ParseKey(q.Get("name")) + input.Metadata.LabelSet, err = labelset.Parse(q.Get("name")) if err != nil { return nil, fmt.Errorf("name: %w", err) } @@ -89,7 +140,10 @@ func (h ingestHandler) ingestInputFromRequest(r *http.Request) (*ingestion.Inges if sr := q.Get("sampleRate"); sr != "" { sampleRate, err := strconv.Atoi(sr) - if err != nil { + if err != nil || sampleRate < 0 { + if err == nil { + err = fmt.Errorf("sample rate must be positive") + } _ = h.log.Log( "err", err, "msg", fmt.Sprintf("invalid sample rate: %q", sr), @@ -123,13 +177,29 @@ func (h ingestHandler) ingestInputFromRequest(r *http.Request) (*ingestion.Inges input.Metadata.AggregationType = metadata.SumAggregationType } - b, err := copyBody(r) + return &input, nil +} + +func readInputRawDataFromRequest(ctx context.Context, r *http.Request, input *ingestion.IngestInput) error { + var ( + otelSpan = trace.SpanFromContext(ctx) + format = r.URL.Query().Get("format") + contentType = r.Header.Get("Content-Type") + ) + otelSpan.SetAttributes( + attribute.String("format", format), + attribute.String("content_type", contentType), + ) + + buf := bytes.NewBuffer(make([]byte, 0, 64<<10)) + n, err := io.Copy(buf, r.Body) if err != nil { - return nil, err + return fmt.Errorf("error reading request body bytes_read %d: %w", n, err) } - format := q.Get("format") - contentType := r.Header.Get("Content-Type") + otelSpan.SetAttributes(attribute.Int64("content_length", n)) + b := buf.Bytes() + switch { default: input.Format = ingestion.FormatGroups @@ -172,14 +242,5 @@ func (h ingestHandler) ingestInputFromRequest(r *http.Request) (*ingestion.Inges RawData: b, } } - - return &input, nil -} - -func copyBody(r *http.Request) ([]byte, error) { - buf := bytes.NewBuffer(make([]byte, 0, 64<<10)) - if _, err := io.Copy(buf, r.Body); err != nil { - return nil, err - } - return buf.Bytes(), nil + return nil } diff --git a/pkg/ingester/pyroscope/ingest_handler_test.go b/pkg/ingester/pyroscope/ingest_handler_test.go index bc3a1ed14e..f3cadc586f 100644 --- a/pkg/ingester/pyroscope/ingest_handler_test.go +++ b/pkg/ingester/pyroscope/ingest_handler_test.go @@ -4,7 +4,9 @@ import ( "bytes" "context" "encoding/json" + "fmt" "mime/multipart" + "net/http" "net/http/httptest" "os" "slices" @@ -12,7 +14,9 @@ import ( "testing" "connectrpc.com/connect" + "github.com/go-kit/log" + prommodel "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -20,11 +24,14 @@ import ( profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/distributor/model" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - pprof2 "github.com/grafana/pyroscope/pkg/og/convert/pprof" - "github.com/grafana/pyroscope/pkg/og/convert/pprof/bench" - "github.com/grafana/pyroscope/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/distributor/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + pprof2 "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/bench" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util/body" + "github.com/grafana/pyroscope/v2/pkg/validation" ) type flatProfileSeries struct { @@ -39,21 +46,19 @@ type MockPushService struct { T testing.TB } -func (m *MockPushService) PushParsed(ctx context.Context, req *model.PushRequest) (*connect.Response[pushv1.PushResponse], error) { +func (m *MockPushService) PushBatch(ctx context.Context, req *model.PushRequest) error { if m.Keep { for _, series := range req.Series { - for _, sample := range series.Samples { - rawProfileCopy := make([]byte, len(sample.RawProfile)) - copy(rawProfileCopy, sample.RawProfile) - m.reqPprof = append(m.reqPprof, &flatProfileSeries{ - Labels: series.Labels, - Profile: sample.Profile.Profile.CloneVT(), - RawProfile: rawProfileCopy, - }) - } + rawProfileCopy := make([]byte, len(series.RawProfile)) + copy(rawProfileCopy, series.RawProfile) + m.reqPprof = append(m.reqPprof, &flatProfileSeries{ + Labels: series.Labels, + Profile: series.Profile.CloneVT(), + RawProfile: rawProfileCopy, + }) } } - return nil, nil + return nil } type DumpProfile struct { @@ -65,7 +70,7 @@ type Dump struct { Profiles []DumpProfile } -func (m *MockPushService) Push(ctx context.Context, req *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { +func (m *MockPushService) Push(_ context.Context, req *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { for _, series := range req.Msg.Series { for _, sample := range series.Samples { p, err := pprof.RawFromBytes(sample.RawProfile) @@ -74,19 +79,18 @@ func (m *MockPushService) Push(ctx context.Context, req *connect.Request[pushv1. } m.reqPprof = append(m.reqPprof, &flatProfileSeries{ Labels: series.Labels, - Profile: p.Profile.CloneVT(), + Profile: p.CloneVT(), }) } } return nil, nil } -func (m *MockPushService) selectActualProfile(ls labels.Labels, st string) DumpProfile { - sort.Sort(ls) +func (m *MockPushService) selectActualProfile(lsUnsorted []labels.Label, st string) DumpProfile { + ls := labels.New(lsUnsorted...) lss := ls.String() for _, p := range m.reqPprof { promLabels := phlaremodel.Labels(p.Labels).ToPrometheusLabels() - sort.Sort(promLabels) actualLabels := labels.NewBuilder(promLabels).Del("jfr_event").Labels() als := actualLabels.String() if als == lss { @@ -127,8 +131,8 @@ func (m *MockPushService) CompareDump(file string) { m.reqPprof = req for i := range expected.Profiles { - expectedLabels := labels.Labels{} - err := expectedLabels.UnmarshalJSON([]byte(expected.Profiles[i].Labels)) + expectedLabels := []labels.Label{} + err := json.Unmarshal([]byte(expected.Profiles[i].Labels), &expectedLabels) require.NoError(m.T, err) actual := m.selectActualProfile(expectedLabels, expected.Profiles[i].SampleType) @@ -151,7 +155,7 @@ func TestCorruptedJFR422(t *testing.T) { jfr[0] = 0 // corrupt jfr svc := &MockPushService{Keep: true, T: t} - h := NewPyroscopeIngestHandler(svc, l) + h := NewPyroscopeIngestHandler(svc, validation.MockLimits{}, l) res := httptest.NewRecorder() body, ct := createJFRRequestBody(t, jfr, nil) @@ -181,6 +185,49 @@ func createJFRRequestBody(t *testing.T, jfr, labels []byte) ([]byte, string) { return b.Bytes(), w.FormDataContentType() } +type errorPushService struct{ err error } + +func (s *errorPushService) PushBatch(context.Context, *model.PushRequest) error { return s.err } + +func (s *errorPushService) Push(context.Context, *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { + return nil, s.err +} + +func TestIngestPropagatesLimitStatus(t *testing.T) { + profile, err := os.ReadFile(repoRoot + "pkg/pprof/testdata/heap") + require.NoError(t, err) + reqBody, ct := createPProfRequest(t, profile, nil, nil) + + for _, tc := range []struct { + name string + pushErr error + wantStatus int + }{ + { + name: "tenant over ingestion limit (429)", + pushErr: connect.NewError(connect.CodeResourceExhausted, fmt.Errorf("limit of 0 B/month reached")), + wantStatus: http.StatusTooManyRequests, + }, + { + name: "other ingest failure keeps 422", + pushErr: fmt.Errorf("boom"), + wantStatus: http.StatusUnprocessableEntity, + }, + } { + t.Run(tc.name, func(t *testing.T) { + h := NewPyroscopeIngestHandler(&errorPushService{err: tc.pushErr}, validation.MockLimits{}, log.NewNopLogger()) + + ctx := tenant.InjectTenantID(context.Background(), "tenant-a") + req := httptest.NewRequestWithContext(ctx, "POST", "/ingest?name=pprof.test{qwe=asd}&spyName=foo239", bytes.NewReader(reqBody)) + req.Header.Set("Content-Type", ct) + res := httptest.NewRecorder() + + h.ServeHTTP(res, req) + assert.Equal(t, tc.wantStatus, res.Code) + }) + } +} + func BenchmarkIngestJFR(b *testing.B) { jfrs := []string{ "cortex-dev-01__kafka-0__cpu__0.jfr.gz", @@ -194,7 +241,7 @@ func BenchmarkIngestJFR(b *testing.B) { "cortex-dev-01__kafka-0__cpu_lock_alloc__3.jfr.gz", } l := log.NewSyncLogger(log.NewLogfmtLogger(os.Stderr)) - h := NewPyroscopeIngestHandler(&MockPushService{}, l) + h := NewPyroscopeIngestHandler(&MockPushService{}, validation.MockLimits{}, l) for _, jfr := range jfrs { b.Run(jfr, func(b *testing.B) { @@ -210,6 +257,45 @@ func BenchmarkIngestJFR(b *testing.B) { } } +func TestParseInputMetadataFromRequest_InvalidSampleRateDefaults(t *testing.T) { + t.Parallel() + + h := ingestHandler{log: log.NewNopLogger()} + + tests := []struct { + name string + sampleRate string + expect uint32 + }{ + {name: "negative", sampleRate: "-1", expect: 100}, + {name: "zero", sampleRate: "0", expect: 0}, + {name: "non numeric", sampleRate: "abc", expect: 100}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + req := httptest.NewRequest(http.MethodPost, "/ingest?name=test-app&sampleRate="+tt.sampleRate, nil) + + input, err := h.parseInputMetadataFromRequest(context.Background(), req) + require.NoError(t, err) + require.Equal(t, tt.expect, input.Metadata.SampleRate) + }) + } +} + +func TestParseInputMetadataFromRequest_ValidSampleRatePreserved(t *testing.T) { + t.Parallel() + + h := ingestHandler{log: log.NewNopLogger()} + req := httptest.NewRequest(http.MethodPost, "/ingest?name=test-app&sampleRate=97", nil) + + input, err := h.parseInputMetadataFromRequest(context.Background(), req) + require.NoError(t, err) + require.EqualValues(t, 97, input.Metadata.SampleRate) +} + func TestIngestPPROFFixtures(t *testing.T) { testdata := []struct { profile string @@ -338,14 +424,16 @@ func TestIngestPPROFFixtures(t *testing.T) { bs, ct := createPProfRequest(t, profile, prevProfile, sampleTypeConfig) svc := &MockPushService{Keep: true, T: t} - h := NewPyroscopeIngestHandler(svc, log.NewSyncLogger(log.NewLogfmtLogger(os.Stderr))) + h := NewPyroscopeIngestHandler(svc, validation.MockLimits{}, log.NewSyncLogger(log.NewLogfmtLogger(os.Stderr))) res := httptest.NewRecorder() spyName := "foo239" if testdatum.spyName != "" { spyName = testdatum.spyName } - req := httptest.NewRequest("POST", "/ingest?name=pprof.test{qwe=asd}&spyName="+spyName, bytes.NewReader(bs)) + ctx := context.Background() + ctx = tenant.InjectTenantID(ctx, "tenant-a") + req := httptest.NewRequestWithContext(ctx, "POST", "/ingest?name=pprof.test{qwe=asd}&spyName="+spyName, bytes.NewReader(bs)) req.Header.Set("Content-Type", ct) h.ServeHTTP(res, req) assert.Equal(t, testdatum.expectStatus, res.Code) @@ -354,7 +442,7 @@ func TestIngestPPROFFixtures(t *testing.T) { require.Equal(t, 1, len(svc.reqPprof)) actualReq := svc.reqPprof[0] ls := phlaremodel.Labels(actualReq.Labels) - require.Equal(t, testdatum.expectMetric, ls.Get(labels.MetricName)) + require.Equal(t, testdatum.expectMetric, ls.Get(string(prommodel.MetricNameLabel))) require.Equal(t, "asd", ls.Get("qwe")) require.Equal(t, spyName, ls.Get(phlaremodel.LabelNamePyroscopeSpy)) require.Equal(t, "pprof.test", ls.Get("service_name")) @@ -446,3 +534,66 @@ func mergeSeriesAndSampleLabels(p *profilev1.Profile, sl []*v1.LabelPair, pl []* sort.Stable(m) return m.Unique() } + +func TestBodySizeLimit(t *testing.T) { + l := log.NewSyncLogger(log.NewLogfmtLogger(os.Stderr)) + svc := &MockPushService{Keep: true, T: t} + + const sizeLimit = 64 << 20 // 64 MiB + + bodySizeLimiter := body.NewSizeLimitHandler(validation.MockLimits{ + IngestionBodyLimitBytesValue: sizeLimit, + }) + + h := bodySizeLimiter(NewPyroscopeIngestHandler(svc, validation.MockLimits{}, l)) + + // Create a body larger than the 64 MiB limit + largeBody := make([]byte, sizeLimit+1) // 1 byte over the limit + for i := range largeBody { + largeBody[i] = byte(i % 256) + } + + res := httptest.NewRecorder() + ctx := tenant.InjectTenantID(context.Background(), "any-tenant") + req := httptest.NewRequestWithContext(ctx, "POST", "/ingest?name=testapp&format=pprof", bytes.NewReader(largeBody)) + req.Header.Set("Content-Type", "application/octet-stream") + + h.ServeHTTP(res, req) + + // Should return 413 Request Entity Too Large status when body size limit is exceeded + require.Equal(t, 413, res.Code) + + // Verify the error message contains information about the body size limit + responseBody := res.Body.String() + assert.Contains(t, responseBody, "request body too large") + + // Verify no profiles were ingested + assert.Equal(t, 0, len(svc.reqPprof)) +} + +func TestBodySizeWithinLimit(t *testing.T) { + l := log.NewSyncLogger(log.NewLogfmtLogger(os.Stderr)) + svc := &MockPushService{Keep: true, T: t} + const sizeLimit = 64 << 20 // 64 MiB + + bodySizeLimiter := body.NewSizeLimitHandler(validation.MockLimits{ + IngestionBodyLimitBytesValue: sizeLimit, + }) + + h := bodySizeLimiter(NewPyroscopeIngestHandler(svc, validation.MockLimits{}, l)) + + // Use a valid small pprof profile for the test + profile, err := os.ReadFile(repoRoot + "pkg/og/convert/testdata/cpu.pprof") + require.NoError(t, err) + + // Create a request with the actual profile (much smaller than limit) + res := httptest.NewRecorder() + ctx := tenant.InjectTenantID(context.Background(), "any-tenant") + req := httptest.NewRequestWithContext(ctx, "POST", "/ingest?name=testapp&format=pprof", bytes.NewReader(profile)) + req.Header.Set("Content-Type", "application/octet-stream") + + h.ServeHTTP(res, req) + + // Should succeed with a valid profile within size limit + require.Equal(t, 200, res.Code) +} diff --git a/pkg/ingester/query.go b/pkg/ingester/query.go index df188cfe91..f14b0663b2 100644 --- a/pkg/ingester/query.go +++ b/pkg/ingester/query.go @@ -45,25 +45,25 @@ func (i *Ingester) BlockMetadata(ctx context.Context, req *connect.Request[inges } func (i *Ingester) MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesStacktracesRequest, ingestv1.MergeProfilesStacktracesResponse]) error { - return i.forInstance(ctx, func(instance *instance) error { + return forInstanceStream(ctx, i, stream, func(instance *instance) error { return instance.MergeProfilesStacktraces(ctx, stream) }) } func (i *Ingester) MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesLabelsRequest, ingestv1.MergeProfilesLabelsResponse]) error { - return i.forInstance(ctx, func(instance *instance) error { + return forInstanceStream(ctx, i, stream, func(instance *instance) error { return instance.MergeProfilesLabels(ctx, stream) }) } func (i *Ingester) MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesPprofRequest, ingestv1.MergeProfilesPprofResponse]) error { - return i.forInstance(ctx, func(instance *instance) error { + return forInstanceStream(ctx, i, stream, func(instance *instance) error { return instance.MergeProfilesPprof(ctx, stream) }) } func (i *Ingester) MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeSpanProfileRequest, ingestv1.MergeSpanProfileResponse]) error { - return i.forInstance(ctx, func(instance *instance) error { + return forInstanceStream(ctx, i, stream, func(instance *instance) error { return instance.MergeSpanProfile(ctx, stream) }) } diff --git a/pkg/ingester/query_test.go b/pkg/ingester/query_test.go index c3ab60ad37..690d30ab05 100644 --- a/pkg/ingester/query_test.go +++ b/pkg/ingester/query_test.go @@ -17,78 +17,14 @@ import ( ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/tenant" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) -// func Test_selectMerge(t *testing.T) { -// cfg := defaultIngesterTestConfig(t) -// profileStore, err := profilestore.New(log.NewNopLogger(), nil, trace.NewNoopTracerProvider(), defaultProfileStoreTestConfig(t)) -// require.NoError(t, err) - -// d, err := New(cfg, log.NewNopLogger(), nil, profileStore) -// require.NoError(t, err) -// resp, err := d.Push(context.Background(), connect.NewRequest(&pushv1.PushRequest{ -// Series: []*pushv1.RawProfileSeries{ -// { -// Labels: []*commonv1.LabelPair{ -// {Name: "__name__", Value: "memory"}, -// }, -// Samples: []*pushv1.RawSample{ -// { -// RawProfile: generateProfile( -// t, "inuse_space", "bytes", "space", "bytes", time.Now().Add(-1*time.Minute), -// []int64{1, 1}, -// [][]string{ -// {"bar", "foo"}, -// {"buzz", "foo"}, -// }, -// ), -// }, -// }, -// }, -// }, -// })) - -// require.NoError(t, err) -// require.NotNil(t, resp) -// f, err := d.selectMerge(context.Background(), profileQuery{ -// name: "memory", -// sampleType: "inuse_space", -// sampleUnit: "bytes", -// periodType: "space", -// periodUnit: "bytes", -// }, 0, int64(model.Latest)) -// require.NoError(t, err) - -// // aggregate plan have no guarantee of order so we sort the results -// sort.Strings(f.Flamebearer.Names) - -// require.Equal(t, []string{"bar", "buzz", "foo", "total"}, f.Flamebearer.Names) -// require.Equal(t, flamebearer.FlamebearerMetadataV1{ -// Format: "single", -// Units: "bytes", -// Name: "inuse_space", -// SampleRate: 100, -// }, f.Metadata) -// require.Equal(t, 2, f.Flamebearer.NumTicks) -// require.Equal(t, 1, f.Flamebearer.MaxSelf) -// require.Equal(t, []int{0, 2, 0, 0}, f.Flamebearer.Levels[0]) -// require.Equal(t, []int{0, 2, 0, 1}, f.Flamebearer.Levels[1]) -// require.Equal(t, []int{0, 1, 1}, f.Flamebearer.Levels[2][:3]) -// require.Equal(t, []int{0, 1, 1}, f.Flamebearer.Levels[2][4:7]) -// require.True(t, f.Flamebearer.Levels[2][3] == 3 || f.Flamebearer.Levels[2][3] == 2) -// require.True(t, f.Flamebearer.Levels[2][7] == 3 || f.Flamebearer.Levels[2][7] == 2) -// require.NoError( -// t, -// profileStore.Close(), -// ) -// } - func Test_QueryMetadata(t *testing.T) { dbPath := t.TempDir() logger := log.NewJSONLogger(os.Stdout) @@ -153,191 +89,3 @@ func Test_QueryMetadata(t *testing.T) { require.Equal(t, expectedTypes, ids) require.NoError(t, services.StopAndAwaitTerminated(context.Background(), ing)) } - -/* -func Test_selectProfiles(t *testing.T) { - cfg := defaultIngesterTestConfig(t) - logger := log.NewLogfmtLogger(os.Stdout) - storeCfg := defaultProfileStoreTestConfig(t) - profileStore, err := profilestore.New(logger, nil, trace.NewNoopTracerProvider(), storeCfg) - require.NoError(t, err) - - d, err := New(cfg, log.NewLogfmtLogger(os.Stdout), nil, profileStore) - require.NoError(t, err) - - resp, err := d.Push(context.Background(), connect.NewRequest(&pushv1.PushRequest{ - Series: []*pushv1.RawProfileSeries{ - { - Labels: []*commonv1.LabelPair{ - {Name: "__name__", Value: "memory"}, - {Name: "cluster", Value: "us-central1"}, - {Name: "foo", Value: "bar"}, - }, - Samples: []*pushv1.RawSample{ - { - RawProfile: generateProfile( - t, "inuse_space", "bytes", "space", "bytes", time.Unix(1, 0), - []int64{1, 2}, - [][]string{ - {"foo", "bar", "buzz"}, - {"buzz", "baz", "foo"}, - }, - ), - }, - }, - }, - { - Labels: []*commonv1.LabelPair{ - {Name: "__name__", Value: "memory"}, - {Name: "cluster", Value: "us-east1"}, - }, - Samples: []*pushv1.RawSample{ - { - RawProfile: generateProfile( - t, "inuse_space", "bytes", "space", "bytes", time.Unix(2, 0), - []int64{4, 5, 6}, - [][]string{ - {"foo", "bar", "buzz"}, - {"buzz", "baz", "foo"}, - {"1", "2", "3"}, - }, - ), - }, - }, - }, - }, - })) - require.NoError(t, err) - require.NotNil(t, resp) - - res, err := d.SelectProfiles(context.Background(), connect.NewRequest(&ingestv1.SelectProfilesRequest{ - LabelSelector: `{cluster=~".*"}`, - Type: &ingestv1.ProfileType{ - Name: "memory", - SampleType: "inuse_space", - SampleUnit: "bytes", - PeriodType: "space", - PeriodUnit: "bytes", - }, - Start: 0, - End: int64(model.Latest), - })) - require.NoError(t, err) - sort.Slice(res.Msg.Profiles, func(i, j int) bool { - return res.Msg.Profiles[i].Timestamp < res.Msg.Profiles[j].Timestamp - }) - require.Equal(t, 2, len(res.Msg.Profiles)) - require.Equal(t, 2, len(res.Msg.Profiles[0].Labels)) - require.Equal(t, 1, len(res.Msg.Profiles[1].Labels)) - - require.Equal(t, "cluster", res.Msg.Profiles[0].Labels[0].Name) - require.Equal(t, "us-central1", res.Msg.Profiles[0].Labels[0].Value) - require.Equal(t, "foo", res.Msg.Profiles[0].Labels[1].Name) - require.Equal(t, "bar", res.Msg.Profiles[0].Labels[1].Value) - require.Equal(t, "cluster", res.Msg.Profiles[1].Labels[0].Name) - require.Equal(t, "us-east1", res.Msg.Profiles[1].Labels[0].Value) - - require.Equal(t, 2, len(res.Msg.Profiles[0].Stacktraces)) - require.Equal(t, 3, len(res.Msg.Profiles[1].Stacktraces)) - - stackTracesID := [][]byte{} - for _, p := range res.Msg.Profiles { - for _, s := range p.Stacktraces { - stackTracesID = append(stackTracesID, s.ID) - } - } - - symbolsReponse, err := d.SymbolizeStacktraces(context.Background(), connect.NewRequest(&ingestv1.SymbolizeStacktraceRequest{Ids: stackTracesID})) - require.NoError(t, err) - - var stacktraces []string - for _, p := range symbolsReponse.Msg.Locations { - stracktrace := strings.Builder{} - for j, l := range p.Ids { - if j > 0 { - stracktrace.WriteString("|") - } - stracktrace.WriteString(symbolsReponse.Msg.FunctionNames[l]) - - } - stacktraces = append(stacktraces, stracktrace.String()) - - } - sort.Strings(stacktraces) - require.Equal(t, []string{"1|2|3", "buzz|baz|foo", "buzz|baz|foo", "foo|bar|buzz", "foo|bar|buzz"}, stacktraces) - require.Equal(t, 5, len(symbolsReponse.Msg.Locations)) -} - -func generateProfile( - t *testing.T, - sampleType, sampleUnit, periodType, periodUnit string, - ts time.Time, - values []int64, - locations [][]string, -) []byte { - t.Helper() - buf := bytes.NewBuffer(nil) - mapping := &profile.Mapping{ - ID: 1, - } - functionMap := map[string]uint64{} - locMap := map[string]*profile.Location{} - fns := []*profile.Function{} - locs := []*profile.Location{} - id := uint64(1) - for _, location := range locations { - for _, function := range location { - if _, ok := functionMap[function]; !ok { - functionMap[function] = id - fn := &profile.Function{ - ID: id, - Name: function, - StartLine: 1, - } - fns = append(fns, fn) - loc := &profile.Location{ - ID: id, - Address: 0, - Mapping: mapping, - Line: []profile.Line{ - {Function: fn, Line: 1}, - }, - } - locMap[function] = loc - locs = append(locs, loc) - id++ - } - } - } - var samples []*profile.Sample - for i, loc := range locations { - s := &profile.Sample{ - Value: []int64{values[i]}, - } - samples = append(samples, s) - for _, function := range loc { - s.Location = append(s.Location, locMap[function]) - } - } - p := &profile.Profile{ - SampleType: []*profile.ValueType{ - {Type: sampleType, Unit: sampleUnit}, - }, - PeriodType: &profile.ValueType{ - Type: periodType, - Unit: periodUnit, - }, - DurationNanos: 0, - Period: 3, - TimeNanos: ts.UnixNano(), - Sample: samples, - Mapping: []*profile.Mapping{ - mapping, - }, - Function: fns, - Location: locs, - } - require.NoError(t, p.Write(buf)) - return buf.Bytes() -} -*/ diff --git a/pkg/ingester/retention.go b/pkg/ingester/retention.go index 3427a158fb..92e8ba7b31 100644 --- a/pkg/ingester/retention.go +++ b/pkg/ingester/retention.go @@ -14,12 +14,12 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/services" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/shipper" - diskutil "github.com/grafana/pyroscope/pkg/util/disk" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/shipper" + diskutil "github.com/grafana/pyroscope/v2/pkg/util/disk" ) const ( diff --git a/pkg/ingester/retention_test.go b/pkg/ingester/retention_test.go index 53090feae8..a310147982 100644 --- a/pkg/ingester/retention_test.go +++ b/pkg/ingester/retention_test.go @@ -15,15 +15,15 @@ import ( "time" "github.com/go-kit/log" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/samber/lo" "github.com/spf13/afero" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/shipper" - diskutil "github.com/grafana/pyroscope/pkg/util/disk" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/shipper" + diskutil "github.com/grafana/pyroscope/v2/pkg/util/disk" ) func TestDiskCleaner_DeleteUploadedBlocks(t *testing.T) { diff --git a/pkg/iter/batch_async.go b/pkg/iter/batch_async.go index a158bd6175..fd243801f7 100644 --- a/pkg/iter/batch_async.go +++ b/pkg/iter/batch_async.go @@ -19,7 +19,7 @@ type batch[T any] struct { done chan struct{} } -const minBatchSize = 64 +const minBatchSize = 2 func NewAsyncBatchIterator[T, N any]( iterator Iterator[T], diff --git a/pkg/iter/iter.go b/pkg/iter/iter.go index 12a183426f..1460289246 100644 --- a/pkg/iter/iter.go +++ b/pkg/iter/iter.go @@ -163,6 +163,14 @@ func Slice[T any](it Iterator[T]) ([]T, error) { return result, it.Err() } +func MustSlice[T any](it Iterator[T]) []T { + s, err := Slice(it) + if err != nil { + panic(err) + } + return s +} + // CloneN returns N copy of the iterator. // The returned iterators are independent of the original iterator. // The original might be exhausted and should be discarded. diff --git a/pkg/iter/profiles.go b/pkg/iter/profiles.go deleted file mode 100644 index b4d00ea01b..0000000000 --- a/pkg/iter/profiles.go +++ /dev/null @@ -1,123 +0,0 @@ -package iter - -import ( - "github.com/grafana/dskit/multierror" - "github.com/prometheus/common/model" - - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util/loser" -) - -type Timestamp interface { - Timestamp() model.Time -} - -type Profile interface { - Labels() phlaremodel.Labels - Timestamp -} - -func lessProfile(p1, p2 Profile) bool { - if p1.Timestamp() == p2.Timestamp() { - // todo we could compare SeriesRef here - return phlaremodel.CompareLabelPairs(p1.Labels(), p2.Labels()) < 0 - } - return p1.Timestamp() < p2.Timestamp() -} - -type MergeIterator[P Profile] struct { - tree *loser.Tree[P, Iterator[P]] - closeErrs multierror.MultiError - current P - deduplicate bool -} - -// NewMergeIterator returns an iterator that k-way merges the given iterators. -// The given iterators must be sorted by timestamp and labels themselves. -// Optionally, the iterator can deduplicate profiles with the same timestamp and labels. -func NewMergeIterator[P Profile](max P, deduplicate bool, iters ...Iterator[P]) Iterator[P] { - if len(iters) == 0 { - return NewEmptyIterator[P]() - } - if len(iters) == 1 { - // No need to merge a single iterator. - // We should never allow a single iterator to be passed in because - return iters[0] - } - iter := &MergeIterator[P]{ - deduplicate: deduplicate, - current: max, - } - iter.tree = loser.New( - iters, - max, - func(s Iterator[P]) P { - return s.At() - }, - func(p1, p2 P) bool { - return lessProfile(p1, p2) - }, - func(s Iterator[P]) { - if err := s.Close(); err != nil { - iter.closeErrs.Add(err) - } - }) - return iter -} - -func (i *MergeIterator[P]) Next() bool { - for i.tree.Next() { - next := i.tree.Winner() - - if !i.deduplicate { - i.current = next.At() - return true - } - if next.At().Timestamp() != i.current.Timestamp() || - phlaremodel.CompareLabelPairs(next.At().Labels(), i.current.Labels()) != 0 { - i.current = next.At() - return true - } - - } - return false -} - -func (i *MergeIterator[P]) At() P { - return i.current -} - -func (i *MergeIterator[P]) Err() error { - return i.tree.Err() -} - -func (i *MergeIterator[P]) Close() error { - i.tree.Close() - return i.closeErrs.Err() -} - -type TimeRangedIterator[T Timestamp] struct { - Iterator[T] - min, max model.Time -} - -func NewTimeRangedIterator[T Timestamp](it Iterator[T], min, max model.Time) Iterator[T] { - return &TimeRangedIterator[T]{ - Iterator: it, - min: min, - max: max, - } -} - -func (it *TimeRangedIterator[T]) Next() bool { - for it.Iterator.Next() { - if it.At().Timestamp() < it.min { - continue - } - if it.At().Timestamp() > it.max { - return false - } - return true - } - return false -} diff --git a/pkg/iter/profiles_test.go b/pkg/iter/profiles_test.go deleted file mode 100644 index 22701efa27..0000000000 --- a/pkg/iter/profiles_test.go +++ /dev/null @@ -1,192 +0,0 @@ -package iter - -import ( - "math" - "testing" - - "github.com/prometheus/common/model" - "github.com/stretchr/testify/require" - "go.uber.org/goleak" - - phlaremodel "github.com/grafana/pyroscope/pkg/model" -) - -var ( - aLabels = phlaremodel.LabelsFromStrings("foo", "a") - bLabels = phlaremodel.LabelsFromStrings("foo", "b") - cLabels = phlaremodel.LabelsFromStrings("foo", "c") -) - -type profile struct { - labels phlaremodel.Labels - timestamp model.Time -} - -func (p profile) Labels() phlaremodel.Labels { - return p.labels -} - -func (p profile) Timestamp() model.Time { - return p.timestamp -} - -func TestMergeIterator(t *testing.T) { - for _, tt := range []struct { - name string - deduplicate bool - input [][]profile - expected []profile - }{ - { - name: "deduplicate exact", - deduplicate: true, - input: [][]profile{ - { - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - }, - { - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - }, - { - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - }, - }, - expected: []profile{ - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - }, - }, - { - name: "no deduplicate", - input: [][]profile{ - { - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - }, - { - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 3}, - }, - { - {labels: aLabels, timestamp: 2}, - }, - }, - expected: []profile{ - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - {labels: aLabels, timestamp: 3}, - }, - }, - { - name: "deduplicate and sort", - deduplicate: true, - input: [][]profile{ - { - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - {labels: aLabels, timestamp: 4}, - }, - { - {labels: aLabels, timestamp: 1}, - {labels: cLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - }, - { - {labels: aLabels, timestamp: 2}, - {labels: bLabels, timestamp: 4}, - }, - }, - expected: []profile{ - {labels: aLabels, timestamp: 1}, - {labels: aLabels, timestamp: 2}, - {labels: cLabels, timestamp: 2}, - {labels: aLabels, timestamp: 3}, - {labels: aLabels, timestamp: 4}, - {labels: bLabels, timestamp: 4}, - }, - }, - } { - tt := tt - t.Run(tt.name, func(t *testing.T) { - iters := make([]Iterator[profile], len(tt.input)) - for i, input := range tt.input { - iters[i] = NewSliceIterator(input) - } - it := NewMergeIterator( - profile{timestamp: math.MaxInt64}, - tt.deduplicate, - iters...) - actual := []profile{} - for it.Next() { - actual = append(actual, it.At()) - } - require.NoError(t, it.Err()) - require.NoError(t, it.Close()) - require.Equal(t, tt.expected, actual) - }) - } -} - -func Test_BufferedIterator(t *testing.T) { - for _, tc := range []struct { - name string - size int - in []profile - }{ - { - name: "empty", - size: 1, - in: nil, - }, - { - name: "smaller than buffer", - size: 1000, - in: generatesProfiles(t, 100), - }, - { - name: "bigger than buffer", - size: 10, - in: generatesProfiles(t, 100), - }, - } { - t.Run(tc.name, func(t *testing.T) { - actual, err := Slice( - NewBufferedIterator( - NewSliceIterator(tc.in), tc.size), - ) - require.NoError(t, err) - require.Equal(t, tc.in, actual) - }) - } -} - -func Test_BufferedIteratorClose(t *testing.T) { - defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) - - it := NewBufferedIterator( - NewSliceIterator(generatesProfiles(t, 100)), 10) - require.NoError(t, it.Close()) -} - -func generatesProfiles(t *testing.T, n int) []profile { - t.Helper() - profiles := make([]profile, n) - for i := range profiles { - profiles[i] = profile{labels: aLabels, timestamp: model.Time(i)} - } - return profiles -} - -// todo test timedRangeIterator diff --git a/pkg/iter/tree.go b/pkg/iter/tree.go index 44c73ba430..cecc53c181 100644 --- a/pkg/iter/tree.go +++ b/pkg/iter/tree.go @@ -1,7 +1,7 @@ package iter import ( - "github.com/grafana/pyroscope/pkg/util/loser" + "github.com/grafana/pyroscope/v2/pkg/util/loser" ) var _ Iterator[interface{}] = &TreeIterator[interface{}]{} diff --git a/pkg/metastore/admin/admin.go b/pkg/metastore/admin/admin.go new file mode 100644 index 0000000000..f996fc3b89 --- /dev/null +++ b/pkg/metastore/admin/admin.go @@ -0,0 +1,268 @@ +package admin + +import ( + "context" + "fmt" + "math" + "net/http" + "slices" + "strconv" + "strings" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/services" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + metastoreclient "github.com/grafana/pyroscope/v2/pkg/metastore/client" + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +type configChangeRequest struct { + serverId string + currentTerm uint64 +} + +type formActionHandler func(http.ResponseWriter, *http.Request, configChangeRequest) error + +type Admin struct { + service services.Service + + logger log.Logger + + servers []discovery.Server + leaderClient raftnodepb.RaftNodeServiceClient // used to make operational calls (e.g., removing nodes) + + metastoreClient *metastoreclient.Client // used to test the metastoreclient.Client implementation + + actionHandlers map[string]formActionHandler +} + +func (a *Admin) Service() services.Service { + return a.service +} + +type raftNodeServiceClient struct { + raftnodepb.RaftNodeServiceClient + conn *grpc.ClientConn +} + +func New( + client raftnodepb.RaftNodeServiceClient, + logger log.Logger, + metastoreAddress string, + metastoreClient *metastoreclient.Client, +) (*Admin, error) { + adm := &Admin{ + leaderClient: client, + logger: logger, + actionHandlers: make(map[string]formActionHandler), + metastoreClient: metastoreClient, + } + adm.addFormActionHandlers() + adm.service = services.NewIdleService(adm.starting, adm.stopping) + + disc, err := discovery.NewDiscovery(logger, metastoreAddress, nil) + if err != nil { + return nil, err + } + disc.Subscribe(adm) + + return adm, nil +} + +func (a *Admin) starting(context.Context) error { return nil } +func (a *Admin) stopping(error) error { return nil } + +func (a *Admin) Servers(servers []discovery.Server) { + a.servers = servers + slices.SortFunc(a.servers, func(a, b discovery.Server) int { + return strings.Compare(string(a.Raft.ID), string(b.Raft.ID)) + }) +} + +func (a *Admin) NodeListHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + for fieldName, handler := range a.actionHandlers { + field := r.FormValue(fieldName) + if field != "" { + changeRequest := configChangeRequest{ + serverId: field, + } + if currentTerm := r.FormValue("current-term"); currentTerm != "" { + parsedTerm, err := strconv.ParseUint(currentTerm, 10, 64) + if err == nil { + changeRequest.currentTerm = parsedTerm + } + } + if err := handler(w, r, changeRequest); err != nil { + httputil.Error(w, err) + return + } + w.Header().Set("Location", "#") + w.WriteHeader(http.StatusFound) + return + } + } + } + + raftState := a.fetchRaftState(r.Context()) + err := pageTemplates.nodesTemplate.Execute(w, nodesPageContent{ + DiscoveredServers: a.servers, + Raft: raftState, + Now: time.Now().UTC(), + }) + if err != nil { + httputil.Error(w, err) + } + }) +} + +func (a *Admin) fetchRaftState(ctx context.Context) *raftNodeState { + observedLeaders := make(map[string]int) + numRaftNodes := 0 + nodes := make([]*metastoreNode, 0, len(a.servers)) + + for _, s := range a.servers { + cl, err := newClient(s.ResolvedAddress) + if err != nil { + level.Warn(a.logger).Log("msg", "missing client for server", "server", s) + continue + } + node := &metastoreNode{ + DiscoveryServerId: string(s.Raft.ID), + ResolvedAddress: s.ResolvedAddress, + } + nodes = append(nodes, node) + + res, err := cl.NodeInfo(ctx, &raftnodepb.NodeInfoRequest{}) + _ = cl.conn.Close() + + if err != nil { + level.Warn(a.logger).Log("msg", "error fetching node info", "server", s, "err", err) + continue + } + nInfo := res.Node + + node.RaftServerId = nInfo.ServerId + node.Member = nInfo.LeaderId != "" + node.State = nInfo.State + node.LeaderId = nInfo.LeaderId + node.ConfigIndex = nInfo.ConfigurationIndex + node.NumPeers = len(nInfo.Peers) + node.CurrentTerm = nInfo.CurrentTerm + node.LastIndex = nInfo.LastIndex + node.CommitIndex = nInfo.CommitIndex + node.AppliedIndex = nInfo.AppliedIndex + node.BuildVersion = nInfo.BuildVersion + node.BuildRevision = nInfo.BuildRevision + node.Stats = make(map[string]string) + for i, n := range nInfo.Stats.Name { + node.Stats[n] = nInfo.Stats.Value[i] + } + + if node.Member { + numRaftNodes++ + observedLeaders[node.LeaderId]++ + } + } + + currentTerm := findCurrentTerm(nodes) + + return &raftNodeState{ + Nodes: nodes, + ObservedLeaders: observedLeaders, + CurrentTerm: currentTerm, + NumNodes: numRaftNodes, + } +} + +func findCurrentTerm(nodes []*metastoreNode) uint64 { + terms := make(map[uint64]int) + for _, node := range nodes { + if node.Member { + terms[node.CurrentTerm]++ + } + } + // TODO aleks-p: in case of a mismatch in reported current terms, we bypass any validation + term := uint64(math.MaxUint64) + if len(terms) == 1 { + for k := range terms { + term = k + } + } + return term +} + +func newClient(address string) (*raftNodeServiceClient, error) { + conn, err := grpc.NewClient(address, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, err + } + return &raftNodeServiceClient{ + RaftNodeServiceClient: raftnodepb.NewRaftNodeServiceClient(conn), + conn: conn, + }, nil +} + +func (a *Admin) addFormActionHandlers() { + a.actionHandlers["add"] = func(w http.ResponseWriter, r *http.Request, cr configChangeRequest) error { + _, err := a.leaderClient.AddNode(r.Context(), &raftnodepb.AddNodeRequest{ + ServerId: cr.serverId, + CurrentTerm: cr.currentTerm, + }) + return err + } + a.actionHandlers["remove"] = func(w http.ResponseWriter, r *http.Request, cr configChangeRequest) error { + _, err := a.leaderClient.RemoveNode(r.Context(), &raftnodepb.RemoveNodeRequest{ + ServerId: cr.serverId, + CurrentTerm: cr.currentTerm, + }) + return err + } + a.actionHandlers["promote"] = func(w http.ResponseWriter, r *http.Request, cr configChangeRequest) error { + _, err := a.leaderClient.PromoteToLeader(r.Context(), &raftnodepb.PromoteToLeaderRequest{ + ServerId: cr.serverId, + CurrentTerm: cr.currentTerm, + }) + return err + } + a.actionHandlers["demote"] = func(w http.ResponseWriter, r *http.Request, cr configChangeRequest) error { + _, err := a.leaderClient.DemoteLeader(r.Context(), &raftnodepb.DemoteLeaderRequest{ + ServerId: cr.serverId, + CurrentTerm: cr.currentTerm, + }) + return err + } +} + +func (a *Admin) ClientTestHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + raftState := a.fetchRaftState(r.Context()) + content := clientTestPageContent{ + Raft: raftState, + Now: time.Now().UTC(), + } + + if r.Method == http.MethodPost { + start := time.Now() + res, err := a.metastoreClient.ReadIndex(r.Context(), &raftnodepb.ReadIndexRequest{}) + content.TestResponseTime = time.Since(start) + if err != nil { + content.TestResponse = err.Error() + } else { + content.TestResponse = fmt.Sprintf("Success! (index: %d, term: %d)", res.CommitIndex, res.Term) + } + } + + err := pageTemplates.clientTestTemplate.Execute(w, content) + if err != nil { + httputil.Error(w, err) + } + }) +} diff --git a/pkg/metastore/admin/metastore.client.gohtml b/pkg/metastore/admin/metastore.client.gohtml new file mode 100644 index 0000000000..0fb09bcd1d --- /dev/null +++ b/pkg/metastore/admin/metastore.client.gohtml @@ -0,0 +1,140 @@ + + + + + + + + Metastore Admin - Client Test + + + + + + + + + +
+
+
+
+

Metastore: Grafana Pyroscope

+
+
+ + Pyroscope logo + +
+
+
+

Nodes

+
+ + {{ $numNodes := .Raft.NumNodes }} + {{ range $index, $node := .Raft.Nodes }} +
+
+
+ {{ $node.RaftServerId }} +
+
+
+
Resolved Address:
+
{{ $node.ResolvedAddress }}
+
+
+
Raft Member:
+
+ {{ if $node.Member }} + yes ({{ $node.State }}) + {{ else }} + no + {{ end }} +
+
+
+
Raft Server ID:
+
{{ $node.RaftServerId }}
+
+
+
Observed Leader:
+ {{ $leaderId := $node.LeaderId }} + {{ if eq $leaderId ""}} + {{ $leaderId = "n/a "}} + {{ end }} +
{{ $leaderId }} (term {{ $node.CurrentTerm }})
+
+
+
+
+ {{ end }} + +
+ +
+

Client Test

+
+
+
+ + +
+
+
+
Response
+
{{ .TestResponse }}
+
+
+
Response Time
+
{{ .TestResponseTime }}
+
+
+
+
+
+
+
+
+
+ Status @ {{ .Now.Format "2006-01-02 15:04:05.000" }} +
+
+ + + diff --git a/pkg/metastore/admin/metastore.nodes.gohtml b/pkg/metastore/admin/metastore.nodes.gohtml new file mode 100644 index 0000000000..b322d33ddb --- /dev/null +++ b/pkg/metastore/admin/metastore.nodes.gohtml @@ -0,0 +1,216 @@ + + + + + + + + Metastore Admin - Nodes + + + + + + + + + +
+
+
+
+

Metastore: Grafana Pyroscope

+
+
+ + Pyroscope logo + +
+
+
+

+ Observed Leaders + + + +

+ {{ range $server, $count := .Raft.ObservedLeaders }} +
+ +
+ {{ end }} +
+ +
+

Nodes

+
+ + {{ $numNodes := .Raft.NumNodes }} + {{ range $index, $node := .Raft.Nodes }} +
+
+
+ {{ $node.DiscoveryServerId }} +
+
+
+
Discovery Server ID:
+
{{ $node.DiscoveryServerId }}
+
+
+
Resolved Address:
+
{{ $node.ResolvedAddress }}
+
+
+
Build Version:
+
{{ $node.BuildVersion }} (revision {{ $node.BuildRevision }})
+
+
+
+
Raft Member:
+
+ {{ if $node.Member }} + yes ({{ $node.State }}) + {{ else }} + no + {{ end }} +
+
+
+
Raft Server ID:
+
{{ $node.RaftServerId }}
+
+
+
Observed Leader:
+ {{ $leaderId := $node.LeaderId }} + {{ if eq $leaderId ""}} + {{ $leaderId = "n/a "}} + {{ end }} +
{{ $leaderId }} (term {{ $node.CurrentTerm }})
+
+
+
Commit / Applied / Last Index:
+
{{ $node.CommitIndex }} / {{ $node.AppliedIndex }} / {{ $node.LastIndex }}
+
+
+
Peers:
+
{{ $node.NumPeers }} (config index {{ $node.ConfigIndex }})
+
+
+
Stats:
+
+

+ +

+
+
+

- Grafana Agent

- Documentation
- Examples +

+ Grafana Alloy

+ Documentation
+ Examples

Golang

@@ -85,10 +86,10 @@ To get started, choose one of the integrations below: Documentation
Examples

+

eBPF

- Documentation
- Examples + Documentation
+ Examples

Python

@@ -98,7 +99,7 @@ To get started, choose one of the integrations below:

- Dotnet

+ .NET
Documentation
Examples
+ + {{ range $k, $v := $node.Stats }} + + + + + {{ end }} + +
{{ $k }}{{ $v }}
+ + + + + + + + + {{ end }} + + + +
+

Discovery

+
+ + + + + + + + + + {{ range .DiscoveredServers }} + + + + + {{ end }} + +
ServerResolved Address
{{ .Raft.ID }}{{ .ResolvedAddress }}
+
+
+ + +
+
+ Status @ {{ .Now.Format "2006-01-02 15:04:05.000" }} +
+
+ + + diff --git a/pkg/metastore/admin/pages.go b/pkg/metastore/admin/pages.go new file mode 100644 index 0000000000..5e85fe8e56 --- /dev/null +++ b/pkg/metastore/admin/pages.go @@ -0,0 +1,75 @@ +package admin + +import ( + _ "embed" + "html/template" + "time" + + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" +) + +//go:embed metastore.nodes.gohtml +var nodesPageHtml string + +//go:embed metastore.client.gohtml +var clientTestPageHtml string + +type metastoreNode struct { + // from Discovery + DiscoveryServerId string + RaftServerId string + ResolvedAddress string + + // from Raft + Member bool + State string + CommitIndex uint64 + AppliedIndex uint64 + LastIndex uint64 + LeaderId string + ConfigIndex uint64 + NumPeers int + CurrentTerm uint64 + BuildVersion string + BuildRevision string + Stats map[string]string +} + +type raftNodeState struct { + Nodes []*metastoreNode + ObservedLeaders map[string]int + CurrentTerm uint64 + NumNodes int +} + +type nodesPageContent struct { + DiscoveredServers []discovery.Server + Raft *raftNodeState + Now time.Time +} + +type clientTestPageContent struct { + Raft *raftNodeState + Now time.Time + TestResponse string + TestResponseTime time.Duration +} + +type templates struct { + nodesTemplate *template.Template + clientTestTemplate *template.Template +} + +var pageTemplates = initTemplates() + +func initTemplates() *templates { + nodesTemplate := template.New("nodes") + template.Must(nodesTemplate.Parse(nodesPageHtml)) + clientTestTemplate := template.New("clientTest") + template.Must(clientTestTemplate.Parse(clientTestPageHtml)) + t := &templates{ + nodesTemplate: nodesTemplate, + clientTestTemplate: clientTestTemplate, + } + return t +} diff --git a/pkg/metastore/client/client.go b/pkg/metastore/client/client.go new file mode 100644 index 0000000000..c6dede63ad --- /dev/null +++ b/pkg/metastore/client/client.go @@ -0,0 +1,181 @@ +package metastoreclient + +import ( + "context" + "errors" + "fmt" + "io" + "sync" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/services" + "github.com/hashicorp/raft" + "google.golang.org/grpc" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +// TODO(kolesnikovae): Implement raft leader routing as a grpc load balancer or interceptor. + +type Client struct { + service services.Service + discovery discovery.Discovery + + mu sync.Mutex + leader raft.ServerID + servers map[raft.ServerID]*client + stopped bool + logger log.Logger + grpcClientConfig grpcclient.Config + dialOpts []grpc.DialOption +} + +type client struct { + metastorev1.IndexServiceClient + metastorev1.CompactionServiceClient + metastorev1.MetadataQueryServiceClient + metastorev1.TenantServiceClient + raftnodepb.RaftNodeServiceClient + + conn io.Closer + srv discovery.Server +} + +// todo +type instance interface { + metastorev1.IndexServiceClient + metastorev1.MetadataQueryServiceClient + metastorev1.TenantServiceClient + metastorev1.CompactionServiceClient + raftnodepb.RaftNodeServiceClient +} + +func New(logger log.Logger, grpcClientConfig grpcclient.Config, d discovery.Discovery, dialOpts ...grpc.DialOption) *Client { + var c Client + logger = log.With(logger, "component", "metastore-client") + c.service = services.NewIdleService(c.starting, c.stopping) + c.logger = logger + c.grpcClientConfig = grpcClientConfig + c.servers = make(map[raft.ServerID]*client) + c.discovery = d + c.dialOpts = dialOpts + + c.discovery.Subscribe(discovery.UpdateFunc(func(servers []discovery.Server) { + c.updateServers(servers) + })) + return &c +} + +func (c *Client) Service() services.Service { return c.service } +func (c *Client) starting(context.Context) error { return nil } +func (c *Client) stopping(error) error { + c.discovery.Close() + c.mu.Lock() + defer c.mu.Unlock() + c.stopped = true + + var errs []error + for _, srv := range c.servers { + err := srv.conn.Close() + level.Debug(c.logger).Log("msg", "connection closed", "resolved_address", srv.srv.ResolvedAddress, "raft_address", srv.srv.Raft.Address) + if err != nil { + errs = append(errs, err) + } + } + c.servers = nil + return errors.Join(errs...) +} + +func (c *Client) updateServers(servers []discovery.Server) { + level.Info(c.logger).Log("msg", "updating servers", "servers", fmt.Sprintf("%+v", servers)) + byID := make(map[raft.ServerID][]discovery.Server, len(servers)) + for _, srv := range servers { + id := stripPort(string(srv.Raft.ID)) + byID[id] = append(byID[id], srv) + } + for k, ss := range byID { + if len(ss) > 1 { + level.Warn(c.logger).Log("msg", "multiple servers with the same ID", "id", k, "servers", ss) + delete(byID, k) + } + } + + c.mu.Lock() + defer c.mu.Unlock() + if c.stopped { + return + } + newServers := make(map[raft.ServerID]*client, len(byID)) + clientSet := make(map[*client]struct{}) + for k, s := range byID { + prev, ok := c.servers[k] + if ok { + if prev.srv == s[0] { + newServers[k] = prev + clientSet[prev] = struct{}{} + level.Debug(c.logger).Log("msg", "server already exists", "id", k, "server", fmt.Sprintf("%+v", s[0])) + continue + } + } + cl, err := newClient(s[0], c.grpcClientConfig, c.dialOpts...) + if err != nil { + level.Error(c.logger).Log("msg", "failed to create client", "err", err) + continue + } + level.Info(c.logger).Log("msg", "new client created", "resolved_address", cl.srv.ResolvedAddress, "raft_address", cl.srv.Raft.Address) + newServers[k] = cl + clientSet[cl] = struct{}{} + } + for _, oldClient := range c.servers { + if _, ok := clientSet[oldClient]; !ok { + err := oldClient.conn.Close() + if err != nil { + level.Warn(c.logger).Log("msg", "failed to close connection", "err", err) + } else { + level.Debug(c.logger).Log("msg", "connection closed", "resolved_address", oldClient.srv.ResolvedAddress, "raft_address", oldClient.srv.Raft.Address) + } + } + } + c.servers = newServers +} + +func newClient(s discovery.Server, config grpcclient.Config, dialOpts ...grpc.DialOption) (*client, error) { + address := s.Raft.Address + if s.ResolvedAddress != "" { + address = raft.ServerAddress(s.ResolvedAddress) + } + conn, err := dial(string(address), config, dialOpts...) + if err != nil { + return nil, err + } + return &client{ + IndexServiceClient: metastorev1.NewIndexServiceClient(conn), + CompactionServiceClient: metastorev1.NewCompactionServiceClient(conn), + MetadataQueryServiceClient: metastorev1.NewMetadataQueryServiceClient(conn), + TenantServiceClient: metastorev1.NewTenantServiceClient(conn), + RaftNodeServiceClient: raftnodepb.NewRaftNodeServiceClient(conn), + conn: conn, + srv: s, + }, nil +} + +func dial(address string, grpcClientConfig grpcclient.Config, dialOpts ...grpc.DialOption) (*grpc.ClientConn, error) { + options, err := grpcClientConfig.DialOption(nil, nil, nil) + if err != nil { + return nil, err + } + // TODO: https://github.com/grpc/grpc-proto/blob/master/grpc/service_config/service_config.proto + options = append(options, grpc.WithDefaultServiceConfig(grpcServiceConfig)) + options = append(options, dialOpts...) + return grpc.Dial(address, options...) +} + +const grpcServiceConfig = `{ + "healthCheckConfig": { + "serviceName": "pyroscope.metastore" + } +}` diff --git a/pkg/metastore/client/client_test.go b/pkg/metastore/client/client_test.go new file mode 100644 index 0000000000..0dd0c1f7df --- /dev/null +++ b/pkg/metastore/client/client_test.go @@ -0,0 +1,111 @@ +package metastoreclient + +import ( + "context" + "sync" + "testing" + + "github.com/grafana/dskit/flagext" + "github.com/grafana/dskit/grpcclient" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockdiscovery" +) + +func TestUnavailable(t *testing.T) { + d := mockdiscovery.NewMockDiscovery(t) + d.On("Subscribe", mock.Anything).Return() + l := test.NewTestingLogger(t) + c := New(l, grpcclient.Config{}, d) + + d.On("Rediscover").Run(func(args mock.Arguments) { + }).Return() + + c.updateServers(createServers([]int{30030, 30031, 30032})) + res, err := c.AddBlock(context.Background(), &metastorev1.AddBlockRequest{}) + require.Error(t, err) + require.Nil(t, res) + +} + +func TestUnavailable_Rediscover_Wrong_Leader(t *testing.T) { + t.Run("AddBlock", func(t *testing.T) { + testRediscoverWrongLeader(t, func(c *Client) { + res, err := c.AddBlock(context.Background(), &metastorev1.AddBlockRequest{}) + require.NoError(t, err) + require.NotNil(t, res) + }) + }) + t.Run("QueryMetadata", func(t *testing.T) { + testRediscoverWrongLeader(t, func(c *Client) { + res, err := c.QueryMetadata(context.Background(), &metastorev1.QueryMetadataRequest{}) + require.NoError(t, err) + require.NotNil(t, res) + }) + }) + t.Run("PollCompactionJobs", func(t *testing.T) { + testRediscoverWrongLeader(t, func(c *Client) { + res, err := c.PollCompactionJobs(context.Background(), &metastorev1.PollCompactionJobsRequest{}) + require.NoError(t, err) + require.NotNil(t, res) + }) + }) + t.Run("GetProfileStats", func(t *testing.T) { + testRediscoverWrongLeader(t, func(c *Client) { + res, err := c.GetTenant(context.Background(), &metastorev1.GetTenantRequest{}) + require.NoError(t, err) + require.NotNil(t, res) + }) + }) +} + +func testRediscoverWrongLeader(t *testing.T, f func(c *Client)) { + d := mockdiscovery.NewMockDiscovery(t) + d.On("Subscribe", mock.Anything).Return() + l := test.NewTestingLogger(t) + config := &grpcclient.Config{} + flagext.DefaultValues(config) + + dServers1 := createServers([]int{30031, 30032, 30033}) + + dServers2 := createServers([]int{40031, 40032, 40033}) + mockServers2, dialOpts := createMockServers(t, l, dServers2) + defer mockServers2.Close() + + c := New(l, *config, d, dialOpts...) + m := sync.Mutex{} + verify := func() {} + initWrongLeaderCalled := false + d.On("Rediscover", mock.Anything).Run(func(args mock.Arguments) { + m.Lock() + defer m.Unlock() + if !initWrongLeaderCalled { + initWrongLeaderCalled = true + verify = mockServers2.InitWrongLeader() + // call updateServers twice + c.updateServers(dServers2) + c.updateServers(dServers2) + } + }).Return() + + c.updateServers(dServers1) + f(c) + verify() +} + +func TestServerError(t *testing.T) { + d := mockdiscovery.NewMockDiscovery(t) + d.On("Subscribe", mock.Anything).Return() + l := test.NewTestingLogger(t) + c := New(l, grpcclient.Config{}, d) + + d.On("Rediscover").Run(func(args mock.Arguments) { + }).Return() + + res, err := c.AddBlock(context.Background(), &metastorev1.AddBlockRequest{}) + require.Error(t, err) + require.Nil(t, res) +} diff --git a/pkg/metastore/client/methods.go b/pkg/metastore/client/methods.go new file mode 100644 index 0000000000..39f6f95ef0 --- /dev/null +++ b/pkg/metastore/client/methods.go @@ -0,0 +1,207 @@ +package metastoreclient + +import ( + "context" + "math/rand" + "strings" + "time" + + "github.com/go-kit/log/level" + "github.com/grafana/dskit/backoff" + "github.com/hashicorp/raft" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +func invoke[R any](ctx context.Context, cl *Client, + f func(ctx context.Context, instance instance) (*R, error), +) (*R, error) { + backoffConfig := backoff.Config{ + MinBackoff: 10 * time.Millisecond, + MaxBackoff: 100 * time.Millisecond, + MaxRetries: 50, + } + const ( + deadline = 20 * time.Second + ) + + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(deadline)) + defer cancel() + + var res *R + var err error + + attempt := func() (done bool) { + it := cl.selectInstance(false) + if it == nil { + cl.logger.Log("msg", "no instances available, backoff and retry") + return false + } + responseFromAttempt, errFromAttempt := f(ctx, it) + if errFromAttempt == nil { + res = responseFromAttempt + return true + } + cl.logger.Log( + "msg", "metastore client error", + "err", errFromAttempt, + "server_id", it.srv.Raft.ID, + "server_address", it.srv.Raft.Address, + "server_resolved_address", it.srv.ResolvedAddress, + ) + node, ok := raftnode.RaftLeaderFromStatusDetails(errFromAttempt) + if ok { + cl.mu.Lock() + if strings.Contains(string(it.srv.Raft.ID), string(cl.leader)) { + cl.logger.Log("msg", "changing metastore client leader", "current", cl.leader, "new", node.Id) + cl.leader = stripPort(node.Id) + } + cl.mu.Unlock() + } else { + // Some errors will not contain the Raft leader. This is a valid scenario, e.g., when a node gets removed + // for maintenance. We try to move to a different client instance. + cl.selectInstance(true) + } + // A workaround to prevent retries for specific error codes. This needs a larger refactoring later on. + switch status.Code(errFromAttempt) { + case codes.InvalidArgument: + cl.logger.Log("msg", "skip metastore retries", "err", err, "leader", cl.leader) + err = errFromAttempt + return true + } + return false + } + + b := backoff.New(ctx, backoffConfig) + + for b.Ongoing() { + if !attempt() { + b.Wait() + cl.discovery.Rediscover() + } else { + return res, err + } + } + + return nil, b.Err() +} + +func (c *Client) selectInstance(override bool) *client { + c.mu.Lock() + defer c.mu.Unlock() + + it := c.servers[c.leader] + if (it == nil || override) && len(c.servers) > 0 { + idx := rand.Intn(len(c.servers)) + j := 0 + for k, v := range c.servers { + if j == idx { + it = v + c.leader = k + level.Debug(c.logger).Log("msg", "selected a random metastore server", "new_leader", c.leader) + break + } + j++ + } + } + return it +} + +func stripPort(server string) raft.ServerID { + serverWithoutPort := server + if idx := strings.LastIndex(serverWithoutPort, ":"); idx != -1 { + serverWithoutPort = serverWithoutPort[:idx] + } + return raft.ServerID(serverWithoutPort) +} + +// TODO(kolesnikovae): Interceptor. + +func (c *Client) AddBlock(ctx context.Context, in *metastorev1.AddBlockRequest, opts ...grpc.CallOption) (*metastorev1.AddBlockResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.AddBlockResponse, error) { + return instance.AddBlock(ctx, in, opts...) + }) +} + +func (c *Client) GetBlockMetadata(ctx context.Context, in *metastorev1.GetBlockMetadataRequest, opts ...grpc.CallOption) (*metastorev1.GetBlockMetadataResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.GetBlockMetadataResponse, error) { + return instance.GetBlockMetadata(ctx, in, opts...) + }) +} + +func (c *Client) QueryMetadata(ctx context.Context, in *metastorev1.QueryMetadataRequest, opts ...grpc.CallOption) (*metastorev1.QueryMetadataResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.QueryMetadataResponse, error) { + return instance.QueryMetadata(ctx, in, opts...) + }) +} + +func (c *Client) QueryMetadataLabels(ctx context.Context, in *metastorev1.QueryMetadataLabelsRequest, opts ...grpc.CallOption) (*metastorev1.QueryMetadataLabelsResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.QueryMetadataLabelsResponse, error) { + return instance.QueryMetadataLabels(ctx, in, opts...) + }) +} + +func (c *Client) PollCompactionJobs(ctx context.Context, in *metastorev1.PollCompactionJobsRequest, opts ...grpc.CallOption) (*metastorev1.PollCompactionJobsResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.PollCompactionJobsResponse, error) { + return instance.PollCompactionJobs(ctx, in, opts...) + }) +} + +func (c *Client) GetTenants(ctx context.Context, in *metastorev1.GetTenantsRequest, opts ...grpc.CallOption) (*metastorev1.GetTenantsResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.GetTenantsResponse, error) { + return instance.GetTenants(ctx, in, opts...) + }) +} + +func (c *Client) GetTenant(ctx context.Context, in *metastorev1.GetTenantRequest, opts ...grpc.CallOption) (*metastorev1.GetTenantResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.GetTenantResponse, error) { + return instance.GetTenant(ctx, in, opts...) + }) +} + +func (c *Client) DeleteTenant(ctx context.Context, in *metastorev1.DeleteTenantRequest, opts ...grpc.CallOption) (*metastorev1.DeleteTenantResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*metastorev1.DeleteTenantResponse, error) { + return instance.DeleteTenant(ctx, in, opts...) + }) +} + +func (c *Client) ReadIndex(ctx context.Context, in *raftnodepb.ReadIndexRequest, opts ...grpc.CallOption) (*raftnodepb.ReadIndexResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*raftnodepb.ReadIndexResponse, error) { + return instance.ReadIndex(ctx, in, opts...) + }) +} + +func (c *Client) NodeInfo(ctx context.Context, in *raftnodepb.NodeInfoRequest, opts ...grpc.CallOption) (*raftnodepb.NodeInfoResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*raftnodepb.NodeInfoResponse, error) { + return instance.NodeInfo(ctx, in, opts...) + }) +} + +func (c *Client) RemoveNode(ctx context.Context, in *raftnodepb.RemoveNodeRequest, opts ...grpc.CallOption) (*raftnodepb.RemoveNodeResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*raftnodepb.RemoveNodeResponse, error) { + return instance.RemoveNode(ctx, in, opts...) + }) +} + +func (c *Client) AddNode(ctx context.Context, in *raftnodepb.AddNodeRequest, opts ...grpc.CallOption) (*raftnodepb.AddNodeResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*raftnodepb.AddNodeResponse, error) { + return instance.AddNode(ctx, in, opts...) + }) +} + +func (c *Client) DemoteLeader(ctx context.Context, in *raftnodepb.DemoteLeaderRequest, opts ...grpc.CallOption) (*raftnodepb.DemoteLeaderResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*raftnodepb.DemoteLeaderResponse, error) { + return instance.DemoteLeader(ctx, in, opts...) + }) +} + +func (c *Client) PromoteToLeader(ctx context.Context, in *raftnodepb.PromoteToLeaderRequest, opts ...grpc.CallOption) (*raftnodepb.PromoteToLeaderResponse, error) { + return invoke(ctx, c, func(ctx context.Context, instance instance) (*raftnodepb.PromoteToLeaderResponse, error) { + return instance.PromoteToLeader(ctx, in, opts...) + }) +} diff --git a/pkg/metastore/client/server_mock_test.go b/pkg/metastore/client/server_mock_test.go new file mode 100644 index 0000000000..7518d1cd55 --- /dev/null +++ b/pkg/metastore/client/server_mock_test.go @@ -0,0 +1,253 @@ +package metastoreclient + +import ( + "context" + "fmt" + "sync" + "testing" + + "github.com/go-kit/log" + "github.com/hashicorp/raft" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockraftnodepb" +) + +type mockServer struct { + metastore *mockmetastorev1.MockIndexServiceServer + compactor *mockmetastorev1.MockCompactionServiceServer + metadata *mockmetastorev1.MockMetadataQueryServiceServer + tenant *mockmetastorev1.MockTenantServiceServer + raftNode *mockraftnodepb.MockRaftNodeServiceServer + + metastorev1.UnsafeIndexServiceServer + metastorev1.UnsafeCompactionServiceServer + metastorev1.UnsafeMetadataQueryServiceServer + metastorev1.UnsafeTenantServiceServer + raftnodepb.UnsafeRaftNodeServiceServer + + srv *grpc.Server + id raft.ServerID + index int + address string +} + +func (m *mockServer) GetTenants(ctx context.Context, request *metastorev1.GetTenantsRequest) (*metastorev1.GetTenantsResponse, error) { + return m.tenant.GetTenants(ctx, request) +} + +func (m *mockServer) GetTenant(ctx context.Context, request *metastorev1.GetTenantRequest) (*metastorev1.GetTenantResponse, error) { + return m.tenant.GetTenant(ctx, request) +} + +func (m *mockServer) DeleteTenant(ctx context.Context, request *metastorev1.DeleteTenantRequest) (*metastorev1.DeleteTenantResponse, error) { + return m.tenant.DeleteTenant(ctx, request) +} + +func (m *mockServer) PollCompactionJobs(ctx context.Context, request *metastorev1.PollCompactionJobsRequest) (*metastorev1.PollCompactionJobsResponse, error) { + return m.compactor.PollCompactionJobs(ctx, request) +} + +func (m *mockServer) AddBlock(ctx context.Context, request *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error) { + return m.metastore.AddBlock(ctx, request) +} + +func (m *mockServer) GetBlockMetadata(ctx context.Context, request *metastorev1.GetBlockMetadataRequest) (*metastorev1.GetBlockMetadataResponse, error) { + return m.metastore.GetBlockMetadata(ctx, request) +} + +func (m *mockServer) QueryMetadata(ctx context.Context, request *metastorev1.QueryMetadataRequest) (*metastorev1.QueryMetadataResponse, error) { + return m.metadata.QueryMetadata(ctx, request) +} + +func (m *mockServer) QueryMetadataLabels(ctx context.Context, request *metastorev1.QueryMetadataLabelsRequest) (*metastorev1.QueryMetadataLabelsResponse, error) { + return m.metadata.QueryMetadataLabels(ctx, request) +} + +func (m *mockServer) ReadIndex(ctx context.Context, request *raftnodepb.ReadIndexRequest) (*raftnodepb.ReadIndexResponse, error) { + return m.raftNode.ReadIndex(ctx, request) +} + +func (m *mockServer) NodeInfo(ctx context.Context, request *raftnodepb.NodeInfoRequest) (*raftnodepb.NodeInfoResponse, error) { + return m.raftNode.NodeInfo(ctx, request) +} + +func (m *mockServer) RemoveNode(ctx context.Context, request *raftnodepb.RemoveNodeRequest) (*raftnodepb.RemoveNodeResponse, error) { + return m.raftNode.RemoveNode(ctx, request) +} + +func (m *mockServer) AddNode(ctx context.Context, request *raftnodepb.AddNodeRequest) (*raftnodepb.AddNodeResponse, error) { + return m.raftNode.AddNode(ctx, request) +} + +func (m *mockServer) DemoteLeader(ctx context.Context, request *raftnodepb.DemoteLeaderRequest) (*raftnodepb.DemoteLeaderResponse, error) { + return m.raftNode.DemoteLeader(ctx, request) +} + +func (m *mockServer) PromoteToLeader(ctx context.Context, request *raftnodepb.PromoteToLeaderRequest) (*raftnodepb.PromoteToLeaderResponse, error) { + return m.raftNode.PromoteToLeader(ctx, request) +} + +func createServers(ports []int) []discovery.Server { + var servers []discovery.Server + for i, p := range ports { + servers = append(servers, discovery.Server{ + Raft: raft.Server{ + ID: testServerId(i), + Address: raft.ServerAddress(fmt.Sprintf("server-%d", i)), + }, + ResolvedAddress: fmt.Sprintf("127.0.0.1:%d", p), + }) + } + return servers +} + +func testServerId(i int) raft.ServerID { + return raft.ServerID(fmt.Sprintf("id-%d", i)) +} + +var _ metastorev1.IndexServiceServer = (*mockServer)(nil) +var _ metastorev1.CompactionServiceServer = (*mockServer)(nil) + +type mockServers struct { + t *testing.T + l log.Logger + servers []*mockServer +} + +func (m *mockServers) Close() { + if m == nil { + return + } + for _, s := range m.servers { + s.srv.Stop() + } +} + +func (m *mockServers) InitWrongLeader() func() { + type wrongLeaderState struct { + m sync.Mutex + callNo int + leaderIndex int + leaderCalled int + } + s := new(wrongLeaderState) + s.leaderIndex = -1 + + nServers := len(m.servers) + for _, srv := range m.servers { + srv := srv + errf := func() error { + s.m.Lock() + defer s.m.Unlock() + s.callNo++ + m.l.Log("called", srv.index, "leader", s.leaderIndex, "callno", s.callNo) + if s.callNo == 1 { + s.leaderIndex = (srv.index + 1) % nServers + s, err := status.New(codes.Unavailable, fmt.Sprintf("test error not leader, leader is %s", testServerId(s.leaderIndex))). + WithDetails(&raftnodepb.RaftNode{ + Id: string(testServerId(s.leaderIndex)), + }) + assert.NoError(m.t, err) + return s.Err() + } + if s.callNo == 2 { + if srv.index != s.leaderIndex { + m.t.Errorf("expected leader %d to be called, but %d called", s.leaderIndex, srv.index) + } + s.leaderCalled++ + return nil + } + m.t.Errorf("unexpected call") + return fmt.Errorf("unexpected call") + } + srv.metastore.On("AddBlock", mock.Anything, mock.Anything).Maybe().Return(func(context.Context, *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error) { + return errOrT(&metastorev1.AddBlockResponse{}, errf) + }) + srv.metadata.On("QueryMetadata", mock.Anything, mock.Anything).Maybe().Return(func(context.Context, *metastorev1.QueryMetadataRequest) (*metastorev1.QueryMetadataResponse, error) { + return errOrT(&metastorev1.QueryMetadataResponse{}, errf) + }) + srv.raftNode.On("ReadIndex", mock.Anything, mock.Anything).Maybe().Return(func(context.Context, *raftnodepb.ReadIndexRequest) (*raftnodepb.ReadIndexResponse, error) { + return errOrT(&raftnodepb.ReadIndexResponse{}, errf) + }) + srv.compactor.On("PollCompactionJobs", mock.Anything, mock.Anything).Maybe().Return(func(context.Context, *metastorev1.PollCompactionJobsRequest) (*metastorev1.PollCompactionJobsResponse, error) { + return errOrT(&metastorev1.PollCompactionJobsResponse{}, errf) + }) + srv.tenant.On("GetTenant", mock.Anything, mock.Anything).Maybe().Return(func(context.Context, *metastorev1.GetTenantRequest) (*metastorev1.GetTenantResponse, error) { + return errOrT(&metastorev1.GetTenantResponse{}, errf) + }) + } + return func() { + s.m.Lock() + assert.Equal(m.t, 2, s.callNo) + assert.Equal(m.t, 1, s.leaderCalled) + s.m.Unlock() + } +} + +func errOrT[T any](t *T, f func() error) (*T, error) { + if err := f(); err != nil { + return nil, err + } + return t, nil +} + +// Returns the grpc.DialOptions needed for a client connection to the created mock servers. +func createMockServers(t *testing.T, l log.Logger, dServers []discovery.Server) (*mockServers, []grpc.DialOption) { + var servers []*mockServer + listeners, dialOpt := createInMemoryListeners(dServers) + for idx, dserv := range dServers { + s := newMockServer(t) + s.index = idx + s.id = testServerId(idx) + s.address = dserv.ResolvedAddress + go func() { + if err := s.srv.Serve(listeners[s.address]); err != nil { + assert.NoError(t, err) + } + }() + servers = append(servers, s) + } + + ms := &mockServers{ + servers: servers, + t: t, + l: l, + } + return ms, []grpc.DialOption{dialOpt} +} + +func createInMemoryListeners(dServers []discovery.Server) (map[string]*bufconn.Listener, grpc.DialOption) { + addrs := make([]string, 0, len(dServers)) + for _, ds := range dServers { + addrs = append(addrs, ds.ResolvedAddress) + } + return test.CreateInMemoryListeners(addrs) +} + +func newMockServer(t *testing.T) *mockServer { + res := &mockServer{ + srv: grpc.NewServer(), + metastore: mockmetastorev1.NewMockIndexServiceServer(t), + compactor: mockmetastorev1.NewMockCompactionServiceServer(t), + metadata: mockmetastorev1.NewMockMetadataQueryServiceServer(t), + tenant: mockmetastorev1.NewMockTenantServiceServer(t), + raftNode: mockraftnodepb.NewMockRaftNodeServiceServer(t), + } + metastorev1.RegisterIndexServiceServer(res.srv, res) + metastorev1.RegisterCompactionServiceServer(res.srv, res) + metastorev1.RegisterMetadataQueryServiceServer(res.srv, res) + metastorev1.RegisterTenantServiceServer(res.srv, res) + raftnodepb.RegisterRaftNodeServiceServer(res.srv, res) + return res +} diff --git a/pkg/metastore/compaction/README.md b/pkg/metastore/compaction/README.md new file mode 100644 index 0000000000..5ffbe77f8a --- /dev/null +++ b/pkg/metastore/compaction/README.md @@ -0,0 +1,320 @@ +# Block Compaction + +## Background + +The Pyroscope ingestion pipeline is designed to gather data in memory as small segments, which are periodically flushed +to object storage, along with the metadata entries being added to the metastore index. Depending on the configuration +and deployment scale, the number of segments created per second can increase significantly, reaching millions of objects +per hour or day. This can lead to performance degradation in the query path due to high read amplification caused by the +large number of small segments. In addition to read amplification, a high number of metadata entries can also lead to +performance degradation across the entire cluster, impacting the write path as well. + +The new background compaction process helps mitigate this by merging small segments into larger ones, aiming to reduce +the number of objects a query needs to fetch from object storage. + +# Compaction Service + +The compaction service is responsible for planning compaction jobs, scheduling their execution, and updating the +metastore index with the results. The compaction service resides within the metastore component, while the compaction +worker is a separate service designed to scale horizontally. + +The compaction service relies on the Raft protocol to guarantee consistency across the replicas. The diagram below +illustrates the interaction between the compaction worker and the compaction service: workers poll the service on a +regular basis to request new compaction jobs and report status updates. + +A status update is processed by the leader node in two steps, each of which is a Raft command committed to the log: +1. First, the leader prepares the plan update – compaction job state changes based on the reported status updates. +This is a read only operation that never modifies the node state. +2. The leader proposes the plan update: all the replicas must apply the planned changes to their state in an idempotent +way, if the proposal is accepted (committed to the Raft log). + +Critical sections are guaranteed to be executed serially in the context of the Raft state machine and by the same +leader (within the same *term*), and atomically from the cluster's perspective. If the prepared compaction plan update +is not accepted by the Raft log, the update plan is discarded, and the new leader will propose a new plan. + +The two-step process ensures that all the replicas use the same compaction plan, regardless of their internal state, +as long as the replicas can apply `UpdateCompactionPlan`change. This is true even in case the compaction algorithm +(the `GetCompactionPlanUpdate` step) changes across the replicas during the ongoing migration – version upgrade or +downgrade. + +> As of now, both steps are committed to the Raft log. However, as an optimization, the first step – preparation, +> can be implemented as a **Linearizable Read** through **Read Index** (which we already use in metadata queries) +> to avoid unnecessary replication of the read-only operation. This approach is already used by the metadata index +> cleaner: leader read with a follow-up proposal. +> +> However, unlike cleanup, compaction is a more complex operation, and the serialization guarantees provided +> by Raft command execution flow help avoid many potential issues with concurrent read/write access. + +```mermaid +sequenceDiagram + participant W as Compaction Worker + + box Compaction Service + participant H as Endpoint + participant R as Raft + end + + loop + W ->>+H: PollCompactionJobsRequest + + critical + critical FSM state read + H ->>R: GetCompactionPlanUpdate + create participant U as Plan Update + R ->>U: + U ->>+S: Job status updates + Note right of U: Job ownership is protected with
leases with fencing token + S ->>-U: Job state changes + U ->>+S: Assign jobs + S ->>-U: Job state changes + U ->>+P: Create jobs + Note right of U: New jobs are created if
workers have enough capacity + P ->>P: Dequeue blocks
and load tombstones + P ->>-U: New jobs + U ->>+S: Add jobs + S ->>-U: Job state changes + destroy U + U ->>R: CompactionPlanUpdate + R ->>H: CompactionPlanUpdate + end + + critical FSM state update + H ->>R: UpdateCompactionPlan + R ->>S: Update schedule
(new, completed, assigned, reassigned jobs) + R ->>P: Remove source blocks from the planner queue (new jobs) + R ->>I: Replace source blocks in the index (completed jobs)
and create tombstones for deleted + I ->>+C: Add new blocks + C ->>C: Enqueue + C ->>-I: + I ->>R: + R ->>H: CompactionPlanUpdate + end + end + + H ->> W: PollCompactionJobsResponse + end + + box FSM + participant C as Compactor + participant P as Planner + participant S as Scheduler + participant I as Metadata Index + end +``` + +--- + +# Job Planner + +The compactor is responsible for maintaining a queue of source blocks eligible for compaction. Currently, this queue +is a simple doubly-linked FIFO structure, populated with new block batches as they are added to the index. In the +current implementation, a new compaction job is created once the sufficient number of blocks have been enqueued. +Compaction jobs are planned on demand when requests are received from the compaction service. + +The queue is segmented by the `Tenant`, `Shard`, and `Level` attributes of the block metadata entries, meaning that +a block compaction never crosses these boundaries. This segmentation helps avoid unnecessary compactions of unrelated +blocks. However, the downside is that blocks are never compacted across different shards, which can lead to suboptimal +compaction results. Due to the dynamic data placement, it is possible for a tenant to be placed on a shard for only a +short period of time. As a result, the data in that shard may not be compacted with other data from the same tenant. + +Cross-shard compaction is to be implemented as a future enhancement. The observed impact of the limitation is moderate. + +## Data Layout + +Profiling data from each service (identified by the `service_name` label) is stored as a separate dataset within a block. + +The block layout is composed of a collection of non-overlapping, independent datasets, each containing distinct data. +At compaction, matching datasets from different blocks are merged: their tsdb index, symbols, and profile tables are +merged and rewritten to a new block, to optimize the data for efficient reading. + +--- + +# Job Scheduler + +The scheduler implements the basic **Small Job First** strategy: blocks of lower levels are considered smaller than +blocks of higher levels, and their compaction is prioritized. This is justifiable because the smaller blocks affect +read amplification more than the larger blocks, and the compaction of smaller blocks is more efficient. + +--- + +Compaction jobs are assigned to workers in the order of their priority. + +Internally, the scheduler maintains a priority queue of jobs for each compaction level. Jobs of lower levels are +assigned first, and the scheduler does not consider jobs of higher levels until all eligible jobs of lower levels are +assigned. + +The priority is determined by several factors: +1. Compaction level. +2. Status (enum order). + - `COMPACTION_STATUS_UNSPECIFIED`: unassigned jobs. + - `COMPACTION_STATUS_IN_PROGRESS`: in-progress jobs. The first job that can't be reassigned is a sentinel: + no more jobs are eligible for assignment at this level. +3. Failures: jobs with fewer failures are prioritized. +4. Lease expiration time: the job with the earliest lease expiration time is considered first. + +See [Job Status Description](#job-status-description) for more details. + +> The challenge is that we don't know the capacity of our worker fleet in advance, and we have no control over them; +they can appear and disappear at any time. Another problem is that in some failure modes, such as unavailability or +lack of compaction workers, or temporary unavailability of the metastore service, the number of blocks to be compacted +may reach significant levels (millions). +> +> Therefore, we use an adaptive approach to keep the scheduler's job queue short while ensuring the compaction +workers are fully utilized. In every request, the worker specifies how many free slots it has available for new jobs. +As the compaction procedure is a synchronous CPU-bound task, we use the number of logical CPU cores as the worker's max +capacity and decrement it for each in-progress compaction job. When a new request arrives, it specifies the current +worker's capacity, which serves as evidence that the entire worker fleet has enough resources to handle at least +this number of jobs. Thus, for every request, we try to enqueue a number of jobs equal to the reported capacity. +> +> Over time, this ensures good balance between the number of jobs in the queue and the worker capacity utilization, +even if there are millions of blocks to compact. + +--- + +## Job Ownership + +Distributed locking implementation is inspired by [The Chubby lock service](https://static.googleusercontent.com/media/research.google.com/en//archive/chubby-osdi06.pdf) +and [Leases: An Efficient Fault-Tolerant Mechanism +for Distributed File Cache Consistency](https://dl.acm.org/doi/pdf/10.1145/74851.74870). The implementation is based on +the Raft protocol. + +Ownership of a compaction job is granted to a compaction worker for a specified period – a *lease*: +> A lease is a contract that gives its holder specified rights over property for a limited period of time. + +The real-time clock of the worker and the scheduler cannot be used; instead, the timestamp of the Raft log entry, +assigned by the Raft leader when the entry is appended to the log, serves as the reference point in time. + +> The fact that leases are allocated by the current leader allows for spurious *lease invalidation* when the leader +> changes and the clock skew exceeds the lease duration. This is acceptable because jobs will be reassigned repeatedly, +> and the occurrence of the event should be very rare. However, the solution does not tolerate clock skews exceeding +> the job lease duration (which is 15 seconds by default). + +The log entry index is used as the [fencing token](https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html) +of protected resources (compaction jobs). + +The Raft log entry index is a monotonically increasing integer, guaranteed to be unique for each command. +Each time a job is assigned to a worker, the worker is provided with the current Raft log index as the fencing token, +which is also assigned to the job. For subsequent requests, the worker must provide the fencing token it was given at +assignment. The ownership of the job is confirmed if the provided token is greater than or equal to the job's token. +The job's token may change if the job is reassigned to another worker, and the new token is derived from the current +Raft log index, which is guaranteed to be greater. + +> Token authentication is not enforced in this design, as the system operates in a trusted environment with cooperative +> workers. However, m malicious workers can arbitrarily specify a token. In the future, we may consider implementing a +> basic authentication mechanism based on cryptographic signatures to further ensure the integrity of token usage. +> +> This is an advisory locking mechanism, meaning resources are not automatically restricted from access when the lock +> is not acquired. Consequently, a client might choose to delete source blocks associated with a compaction job or +> continue processing the job even without holding the lease. This behavior, however, should be avoided in the worker +> implementation. + +## Procedures + +### Assignment + +When a worker requests a new assignment, the scheduler must find the highest-priority job that is not assigned yet, +and assign it to the worker. When a job is assigned, the worker is given a lease with a deadline. +The worker should refresh the lease before it expires. + +### Lease Refresh + +The worker must send a status update to the scheduler to refresh the lease. +The scheduler must update the lease expiration time if the worker still owns the job. + +### Reassignment + +The scheduler may revoke a job if the worker does not send the status update within the lease duration. + +When a new assignment is requested by a worker, the scheduler inspects in-progress jobs and checks if the +lease duration has expired. If the lease has expired, the job is reassigned to the worker requested for a +new assignment. + +--- + +If the timestamp of the current Raft log entry (command) exceeds the job `lease_expires_at` timestamp, +the scheduler must revoke the job: +1. Set the status to `COMPACTION_STATUS_IN_PROGRESS`. +2. Allocate a new lease with an expiration period calculated starting from the current command timestamp. +3. Set the fencing token to the current command index (guaranteed to be higher than the job fencing token). + +--- + +The worker instance that has lost the job is not notified immediately. If the worker reports an update for a job that it +is not assigned to, or if the job is not found (for example, if it has been completed by another worker), the scheduler +does not allocate a new lease; the worker should stop processing. This mechanism prevents the worker from processing +jobs unnecessarily. + +If the worker is not capable of executing the job, it may abandon the job without further notifications. The scheduler +will eventually reassign the job to another worker. The lost job might be reassigned to the same worker instance if that +instance detects the loss before others do: abandoned jobs are assigned to the first worker that requests new +assignments when no unassigned jobs are available. + +There is no explicit mechanism for reporting a failure from the worker. In fact, the scheduler must not rely on error +reports from workers, as jobs that cause workers to crash would yield no reports at all. + +To avoid infinite reassignment loops, the scheduler keeps track of reassignments (failures) for each job. If the number +of failures exceeds a set threshold, the job is not reassigned and remains at the bottom of the queue. Once the cause of +failure is resolved, the error limit can be temporarily increased to reprocess these jobs. + +The scheduler queue has a size limit. Typically, the only scenario in which this limit is reached is when the compaction +process is not functioning correctly (e.g., due to a bug in the compaction procedure), preventing blocks from being +compacted and resulting in many jobs remaining in a failed state. Once the queue size limit is reached, failed jobs are +evicted, meaning the corresponding blocks will never be compacted. This may cause read amplification of the data queries +and bloat the metadata index. Therefore, the limit should be large enough. The recommended course of action is to roll +back or fix the bug and restart the compaction process, temporarily increasing the error limit if necessary. + +### Job Completion + +When the worker reports a successful completion of the job, the scheduler must remove the job from the schedule and +notify the planner about the completion. + +## Job Status Description + +The diagram below depicts the state machine of the job status. + +```mermaid +stateDiagram-v2 + [*] --> Unassigned : Create Job + Unassigned --> InProgress : Assign Job + InProgress --> Success : Job Completed + InProgress --> LeaseExpired: Job Lease Expires + LeaseExpired: Abandoned Job + + LeaseExpired --> Excluded: Failure Threshold Exceeded + Excluded: Faulty Job + + Success --> [*] : Remove Job from Schedule + LeaseExpired --> InProgress : Reassign Job + + Unassigned : COMPACTION_STATUS_UNSPECIFIED + InProgress : COMPACTION_STATUS_IN_PROGRESS + Success : COMPACTION_STATUS_SUCCESS + + LeaseExpired : COMPACTION_STATUS_IN_PROGRESS + Excluded: COMPACTION_STATUS_IN_PROGRESS +``` + +### Communication + +### Scheduler to Worker + +| Status | Description | +|---------------------------------|-------------------------------------------------------------------------------------| +| `COMPACTION_STATUS_UNSPECIFIED` | Not allowed. | +| `COMPACTION_STATUS_IN_PROGRESS` | Job lease refresh. The worker should refresh the new lease before the new deadline. | +| `COMPACTION_STATUS_SUCCESS` | Not allowed. | +| --- | No lease refresh from the scheduler. The worker should stop processing. | + +### Worker to Scheduler + +| Status | Description | +|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| `COMPACTION_STATUS_UNSPECIFIED` | Not allowed. | +| `COMPACTION_STATUS_IN_PROGRESS` | Job lease refresh. The scheduler must extend the lease of the job, if the worker still owns it. | +| `COMPACTION_STATUS_SUCCESS` | The job has been successfully completed. The scheduler must remove the job from the schedule and communicate the update to the planner. | + +### Notes + +* Job status `COMPACTION_STATUS_UNSPECIFIED` is never sent over the wire between the scheduler and workers. +* Job in `COMPACTION_STATUS_IN_PROGRESS` cannot be reassigned if its failure counter exceeds the threshold. +* Job in `COMPACTION_STATUS_SUCCESS` is removed from the schedule immediately. diff --git a/pkg/metastore/compaction/compaction.go b/pkg/metastore/compaction/compaction.go new file mode 100644 index 0000000000..6125a36f09 --- /dev/null +++ b/pkg/metastore/compaction/compaction.go @@ -0,0 +1,85 @@ +package compaction + +import ( + "github.com/hashicorp/raft" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" +) + +type Compactor interface { + // Compact enqueues a new block for compaction + Compact(*bbolt.Tx, BlockEntry) error +} + +type Planner interface { + // NewPlan is used to plan new jobs. The proposed changes will then be + // submitted for Raft consensus, with the leader's jobs being accepted + // as the final decision. + // Implementation: Plan must not change the state of the Planner. + NewPlan(*raft.Log) Plan + // UpdatePlan communicates the status of the compaction job to the planner. + // Implementation: This method must be idempotent. + UpdatePlan(*bbolt.Tx, *raft_log.CompactionPlanUpdate) error +} + +type Plan interface { + // CreateJob creates a plan for a new job. + CreateJob() (*raft_log.CompactionJobPlan, error) +} + +type Scheduler interface { + // NewSchedule is used to plan a schedule update. The proposed schedule + // will then be submitted for Raft consensus, with the leader's schedule + // being accepted as the final decision. + // Implementation: Schedule must not change the state of the Scheduler. + NewSchedule(*bbolt.Tx, *raft.Log) Schedule + // UpdateSchedule adds new jobs and updates the state of existing ones. + // Implementation: This method must be idempotent. + UpdateSchedule(*bbolt.Tx, *raft_log.CompactionPlanUpdate) error +} + +// Schedule prepares changes to the compaction plan based on status updates +// from compaction workers. The standard sequence assumes that job updates +// (including lease renewals and completion reports) occur first, followed by +// the assignment of new jobs to workers. Only after these updates are new +// compaction jobs planned. +type Schedule interface { + // UpdateJob is called on behalf of the worker to update the job status. + // A nil response should be interpreted as "no new lease": stop the work. + // The scheduler must validate that the worker is allowed to update the + // job by comparing the fencing token of the job. + // Refer to the documentation for details. + UpdateJob(*raft_log.CompactionJobStatusUpdate) *raft_log.CompactionJobState + // AssignJob is called on behalf of the worker to request a new job. + AssignJob() (*raft_log.AssignedCompactionJob, error) + // EvictJob is called on behalf of the planner to evict jobs that cannot + // be assigned to workers, and free up resources for new jobs. + EvictJob() *raft_log.CompactionJobState + // AddJob is called on behalf of the planner to add a new job to the schedule. + // The scheduler may decline the job by returning a nil state. + AddJob(*raft_log.CompactionJobPlan) *raft_log.CompactionJobState +} + +// BlockEntry represents a block metadata entry compaction operates on. +type BlockEntry struct { + Index uint64 + AppendedAt int64 + ID string + Tenant string + Shard uint32 + Level uint32 +} + +func NewBlockEntry(cmd *raft.Log, md *metastorev1.BlockMeta) BlockEntry { + return BlockEntry{ + Index: cmd.Index, + AppendedAt: cmd.AppendedAt.UnixNano(), + ID: md.Id, + Tenant: metadata.Tenant(md), + Shard: md.Shard, + Level: md.CompactionLevel, + } +} diff --git a/pkg/metastore/compaction/compactor/compaction_queue.go b/pkg/metastore/compaction/compactor/compaction_queue.go new file mode 100644 index 0000000000..62cfd42bd6 --- /dev/null +++ b/pkg/metastore/compaction/compactor/compaction_queue.go @@ -0,0 +1,501 @@ +package compactor + +import ( + "container/heap" + "slices" + "sync" + "sync/atomic" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +const defaultBlockBatchSize = 20 + +type compactionKey struct { + // Order of the fields is not important. + // Can be generalized. + tenant string + shard uint32 + level uint32 +} + +type compactionQueue struct { + config Config + registerer prometheus.Registerer + levels []*blockQueue + globalStats *globalQueueStats + statsCollector *globalQueueStatsCollector +} + +// blockQueue stages blocks as they are being added. Once a batch of blocks +// within the compaction key reaches a certain size or age, it is pushed to +// the linked list in the arrival order and to the compaction key queue. +// +// This allows to iterate over the blocks in the order of arrival within the +// compaction dimension, while maintaining an ability to remove blocks from the +// queue efficiently. +// +// No pop operation is needed for the block queue: the only way blocks leave +// the queue is through explicit removal. Batch and block iterators provide +// the read access. +type blockQueue struct { + config Config + registerer prometheus.Registerer + staged map[compactionKey]*stagedBlocks + globalStats *globalQueueStats + // Batches ordered by arrival. + head, tail *batch + // Priority queue by last update: we need to flush + // incomplete batches once they stop updating. + updates *priorityBlockQueue +} + +// stagedBlocks is a queue of blocks sharing the same compaction key. +type stagedBlocks struct { + key compactionKey + // Local queue (blocks sharing this compaction key). + head, tail *batch + // Parent block queue (global). + queue *blockQueue + // Incomplete batch of blocks. + batch *batch + // Map of block IDs to their locations in batches. + refs map[string]blockRef + stats *queueStats + collector *queueStatsCollector + // Parent block queue maintains a priority queue of + // incomplete batches by the last update time. + heapIndex int + updatedAt int64 +} + +type queueStats struct { + blocks atomic.Int32 + batches atomic.Int32 + rejected atomic.Int32 + missed atomic.Int32 +} + +// blockRef points to the block in the batch. +type blockRef struct { + batch *batch + index int +} + +type blockEntry struct { + id string // Block ID. + index uint64 // Index of the command in the raft log. +} + +type batch struct { + flush sync.Once + size uint32 + blocks []blockEntry + // Reference to the parent. + staged *stagedBlocks + // Links to the global batch queue items: + // the compaction key of batches may differ. + nextG, prevG *batch + // Links to the local batch queue items: + // batches that share the same compaction key. + next, prev *batch + createdAt int64 +} + +func newCompactionQueue(config Config, registerer prometheus.Registerer) *compactionQueue { + globalStats := newGlobalQueueStats(len(config.Levels)) + q := &compactionQueue{ + config: config, + registerer: registerer, + globalStats: globalStats, + } + if registerer != nil { + q.statsCollector = newGlobalQueueStatsCollector(q) + util.RegisterOrGet(registerer, q.statsCollector) + } + return q +} + +func (q *compactionQueue) reset() { + for _, level := range q.levels { + if level != nil { + for _, s := range level.staged { + level.removeStaged(s) + } + } + } + clear(q.levels) + q.levels = q.levels[:0] +} + +func (q *compactionQueue) push(e compaction.BlockEntry) bool { + level := q.blockQueue(e.Level) + staged := level.stagedBlocks(compactionKey{ + tenant: e.Tenant, + shard: e.Shard, + level: e.Level, + }) + staged.updatedAt = e.AppendedAt + pushed := staged.push(blockEntry{ + id: e.ID, + index: e.Index, + }) + heap.Fix(level.updates, staged.heapIndex) + level.flushOldest(e.AppendedAt) + return pushed +} + +func (q *compactionQueue) blockQueue(l uint32) *blockQueue { + s := l + 1 // Levels are 0-based. + if s > uint32(len(q.levels)) { + q.levels = slices.Grow(q.levels, int(s))[:s] + } + level := q.levels[l] + if level == nil { + level = newBlockQueue(q.config, q.registerer, q.globalStats) + q.levels[l] = level + } + return level +} + +func newBlockQueue(config Config, registerer prometheus.Registerer, globalStats *globalQueueStats) *blockQueue { + return &blockQueue{ + config: config, + registerer: registerer, + staged: make(map[compactionKey]*stagedBlocks), + globalStats: globalStats, + updates: new(priorityBlockQueue), + } +} + +func (q *blockQueue) stagedBlocks(k compactionKey) *stagedBlocks { + staged, ok := q.staged[k] + if !ok { + staged = &stagedBlocks{ + queue: q, + key: k, + refs: make(map[string]blockRef), + stats: new(queueStats), + } + staged.resetBatch() + q.staged[k] = staged + heap.Push(q.updates, staged) + q.globalStats.AddQueues(k, 1) + if q.registerer != nil { + staged.collector = newQueueStatsCollector(staged) + util.RegisterOrGet(q.registerer, staged.collector) + } + } + return staged +} + +func (q *blockQueue) removeStaged(s *stagedBlocks) { + if s.collector != nil { + q.registerer.Unregister(s.collector) + } + delete(q.staged, s.key) + if s.heapIndex < 0 || s.heapIndex >= q.updates.Len() { + panic("bug: attempt to delete compaction queue with an invalid priority index") + } + heap.Remove(q.updates, s.heapIndex) + q.globalStats.AddQueues(s.key, -1) +} + +func (s *stagedBlocks) push(block blockEntry) bool { + if _, found := s.refs[block.id]; found { + s.stats.rejected.Add(1) + return false + } + s.refs[block.id] = blockRef{batch: s.batch, index: len(s.batch.blocks)} + s.batch.blocks = append(s.batch.blocks, block) + if s.batch.size == 0 { + s.batch.createdAt = s.updatedAt + } + s.batch.size++ + s.stats.blocks.Add(1) + s.queue.globalStats.AddBlocks(s.key, 1) + if s.queue.config.exceedsMaxSize(s.batch) || + s.queue.config.exceedsMaxAge(s.batch, s.updatedAt) { + s.flush() + } + return true +} + +func (s *stagedBlocks) flush() { + var flushed bool + s.batch.flush.Do(func() { + if !s.queue.pushBatch(s.batch) { + panic("bug: attempt to detach the compaction queue head") + } + flushed = true + }) + if !flushed { + panic("bug: attempt to flush a compaction queue batch twice") + } + s.resetBatch() +} + +func (s *stagedBlocks) resetBatch() { + s.batch = &batch{ + blocks: make([]blockEntry, 0, defaultBlockBatchSize), + staged: s, + } +} + +var zeroBlockEntry blockEntry + +func (s *stagedBlocks) delete(block string) blockEntry { + ref, found := s.refs[block] + if !found { + s.stats.missed.Add(1) + return zeroBlockEntry + } + // We can't change the order of the blocks in the batch, + // because that would require updating all the block locations. + e := ref.batch.blocks[ref.index] + ref.batch.blocks[ref.index] = zeroBlockEntry + ref.batch.size-- + s.stats.blocks.Add(-1) + s.queue.globalStats.AddBlocks(s.key, -1) + if ref.batch.size == 0 { + if ref.batch != s.batch { + // We should never ever try to delete the staging batch from the + // queue: it has not been flushed and added to the queue yet. + // + // NOTE(kolesnikovae): + // It caused a problem because removeBatch mistakenly interpreted + // the batch as a head (s.batch.prev == nil), and detached it, + // replacing a valid head with s.batch.next, which is always nil + // at this point; it made the queue look empty for the reader, + // because the queue is read from the head. + // + // The only way we may end up here if blocks are removed from the + // staging batch. Typically, blocks are not supposed to be removed + // from there before they left the queue (i.e., flushed to the + // global queue). + // + // In practice, the compactor is distributed and has multiple + // replicas: the leader instance could have already decided to + // flush the blocks, and now they should be removed from all + // instances. Due to a bug in time-based flushing (when it stops + // working), it was possible that after the leader restarts and + // recovers time-based flushing locally, it would desire to flush + // the oldest batch. Consequently, the follower instances, where + // the batch is still in staging, would need to do the same. + if !s.queue.removeBatch(ref.batch) { + panic("bug: attempt to remove a batch that is not in the compaction queue") + } + } + } + delete(s.refs, block) + if len(s.refs) == 0 { + // This is the last block with the given compaction key, so we want to + // remove the staging structure. It's fine to delete it from the queue + // at any point: we guarantee that it does not reference any blocks in + // the queue, and we do not need to flush it anymore. + s.queue.removeStaged(s) + } + return e +} + +func (q *blockQueue) pushBatch(b *batch) bool { + if q.tail != nil { + q.tail.nextG = b + b.prevG = q.tail + } else if q.head == nil { + q.head = b + } else { + return false + } + q.tail = b + + // Same for the queue of batches + // with matching compaction key. + + if b.staged.tail != nil { + b.staged.tail.next = b + b.prev = b.staged.tail + } else if b.staged.head == nil { + b.staged.head = b + } else { + return false + } + b.staged.tail = b + + b.staged.stats.batches.Add(1) + q.globalStats.AddBatches(b.staged.key, 1) + return true +} + +func (q *blockQueue) removeBatch(b *batch) bool { + if b.prevG != nil { + b.prevG.nextG = b.nextG + } else if b == q.head { + // This is the head. + q.head = q.head.nextG + } else { + return false + } + if b.nextG != nil { + b.nextG.prevG = b.prevG + } else if b == q.tail { + // This is the tail. + q.tail = q.tail.prevG + } else { + return false + } + b.nextG = nil + b.prevG = nil + + // Same for the queue of batches + // with matching compaction key. + + if b.prev != nil { + b.prev.next = b.next + } else if b == b.staged.head { + // This is the head. + b.staged.head = b.staged.head.next + } else { + return false + } + if b.next != nil { + b.next.prev = b.prev + } else if b == b.staged.tail { + // This is the tail. + b.staged.tail = b.staged.tail.prev + } else { + return false + } + b.next = nil + b.prev = nil + + b.staged.stats.batches.Add(-1) + q.globalStats.AddBatches(b.staged.key, -1) + return true +} + +func (q *blockQueue) flushOldest(now int64) { + if q.updates.Len() == 0 { + panic("bug: compaction queue has empty priority queue") + } + // Peek the oldest staging batch in the priority queue (min-heap). + oldest := (*q.updates)[0] + if !q.config.exceedsMaxAge(oldest.batch, now) { + return + } + // It's possible that the staging batch is empty: it's only removed + // from the queue when the last block with the given compaction key is + // removed, including ones flushed to the global queue. Therefore, we + // should not pop it from the queue, but update its index in the heap. + // Otherwise, if the staging batch has not been removed from the queue + // yet i.e., references some blocks in the compaction queue (it's rare + // but not impossible), time-based flush will stop working for it. + if oldest.batch.size > 0 { + oldest.flush() + } + oldest.updatedAt = now + heap.Fix(q.updates, oldest.heapIndex) +} + +type priorityBlockQueue []*stagedBlocks + +func (pq priorityBlockQueue) Len() int { return len(pq) } + +func (pq priorityBlockQueue) Less(i, j int) bool { + return pq[i].updatedAt < pq[j].updatedAt +} + +func (pq priorityBlockQueue) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] + pq[i].heapIndex = i + pq[j].heapIndex = j +} + +func (pq *priorityBlockQueue) Push(x interface{}) { + n := len(*pq) + staged := x.(*stagedBlocks) + staged.heapIndex = n + *pq = append(*pq, staged) +} + +func (pq *priorityBlockQueue) Pop() interface{} { + old := *pq + n := len(old) + staged := old[n-1] + old[n-1] = nil + staged.heapIndex = -1 + *pq = old[0 : n-1] + return staged +} + +func newBatchIter(q *blockQueue) *batchIter { return &batchIter{batch: q.head} } + +// batchIter iterates over the batches in the queue, in the order of arrival. +type batchIter struct{ batch *batch } + +func (i *batchIter) next() (*batch, bool) { + if i.batch == nil { + return nil, false + } + b := i.batch + i.batch = i.batch.nextG + return b, b != nil +} + +func (i *batchIter) reset(b *batch) { i.batch = b } + +// batchIter iterates over the batches in the queue, in the order of arrival +// within the compaction key. It's guaranteed that returned blocks are unique +// across all batched. +type blockIter struct { + visited map[string]struct{} + batch *batch + i int +} + +func newBlockIter() *blockIter { + // Assuming that block IDs (16b ULID) are globally unique. + // We could achieve the same with more efficiency by marking visited + // batches. However, marking visited blocks seems to be more robust, + // and the size of the map is expected to be small. + visited := make(map[string]struct{}, 64) + visited[zeroBlockEntry.id] = struct{}{} + return &blockIter{visited: visited} +} + +func (it *blockIter) setBatch(b *batch) { + it.batch = b + it.i = 0 +} + +func (it *blockIter) more() bool { + if it.batch == nil { + return false + } + return it.i < len(it.batch.blocks) +} + +func (it *blockIter) peek() (string, bool) { + for it.batch != nil { + if it.i >= len(it.batch.blocks) { + it.setBatch(it.batch.next) + continue + } + entry := it.batch.blocks[it.i] + if _, visited := it.visited[entry.id]; visited { + it.i++ + continue + } + return entry.id, true + } + return "", false +} + +func (it *blockIter) advance() { + entry := it.batch.blocks[it.i] + it.visited[entry.id] = struct{}{} + it.i++ +} diff --git a/pkg/metastore/compaction/compactor/compaction_queue_bench_test.go b/pkg/metastore/compaction/compactor/compaction_queue_bench_test.go new file mode 100644 index 0000000000..fc11cc1215 --- /dev/null +++ b/pkg/metastore/compaction/compactor/compaction_queue_bench_test.go @@ -0,0 +1,41 @@ +package compactor + +import ( + "strconv" + "testing" + + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" +) + +func BenchmarkCompactionQueue_Push(b *testing.B) { + const ( + tenants = 1 + levels = 1 + shards = 64 + ) + + q := newCompactionQueue(DefaultConfig(), nil) + keys := make([]compactionKey, levels*tenants*shards) + for i := range keys { + keys[i] = compactionKey{ + tenant: strconv.Itoa(i % tenants), + shard: uint32(i % shards), + level: uint32(i % levels), + } + } + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + k := keys[i%len(keys)] + q.push(compaction.BlockEntry{ + Index: uint64(i), + AppendedAt: int64(i), + ID: strconv.Itoa(i), + Tenant: k.tenant, + Shard: k.shard, + Level: k.level, + }) + } +} diff --git a/pkg/metastore/compaction/compactor/compaction_queue_test.go b/pkg/metastore/compaction/compactor/compaction_queue_test.go new file mode 100644 index 0000000000..5d033c9fed --- /dev/null +++ b/pkg/metastore/compaction/compactor/compaction_queue_test.go @@ -0,0 +1,306 @@ +package compactor + +import ( + "fmt" + "math/rand" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" +) + +func testBlockEntry(id int) blockEntry { return blockEntry{id: strconv.Itoa(id)} } + +func testBlockQueue(cfg Config) *blockQueue { + stats := newGlobalQueueStats(len(cfg.Levels)) + return newBlockQueue(cfg, nil, stats) +} + +func TestBlockQueue_Push(t *testing.T) { + q := testBlockQueue(Config{Levels: []LevelConfig{{MaxBlocks: 3}}}) + key := compactionKey{tenant: "t", shard: 1} + + result := q.stagedBlocks(key).push(testBlockEntry(1)) + require.True(t, result) + require.Equal(t, 1, len(q.staged[key].batch.blocks)) + assert.Equal(t, testBlockEntry(1), q.staged[key].batch.blocks[0]) + + q.stagedBlocks(key).push(testBlockEntry(2)) + q.stagedBlocks(key).push(testBlockEntry(3)) // Staged blocks formed the first batch. + assert.Equal(t, 0, len(q.staged[key].batch.blocks)) + assert.Equal(t, []blockEntry{testBlockEntry(1), testBlockEntry(2), testBlockEntry(3)}, q.head.blocks) + + q.stagedBlocks(key).push(testBlockEntry(4)) + q.stagedBlocks(key).push(testBlockEntry(5)) + assert.Equal(t, 2, len(q.staged[key].batch.blocks)) + + remove(q, key, "1", "2") // Remove the first batch. + assert.Equal(t, []blockEntry{zeroBlockEntry, zeroBlockEntry, testBlockEntry(3)}, q.head.blocks) + remove(q, key, "3") + assert.Nil(t, q.head) + + q.stagedBlocks(key).push(testBlockEntry(6)) // Complete the second batch. + assert.Equal(t, 0, len(q.staged[key].batch.blocks)) + + q.stagedBlocks(key).push(testBlockEntry(7)) + assert.Equal(t, []blockEntry{testBlockEntry(4), testBlockEntry(5), testBlockEntry(6)}, q.head.blocks) + assert.Equal(t, 1, len(q.staged[key].batch.blocks)) +} + +func TestBlockQueue_DuplicateBlock(t *testing.T) { + q := testBlockQueue(Config{Levels: []LevelConfig{{MaxBlocks: 3}}}) + key := compactionKey{tenant: "t", shard: 1} + + require.True(t, q.stagedBlocks(key).push(testBlockEntry(1))) + require.False(t, q.stagedBlocks(key).push(testBlockEntry(1))) + + assert.Equal(t, 1, len(q.staged[key].batch.blocks)) +} + +func TestBlockQueue_Remove(t *testing.T) { + q := testBlockQueue(Config{Levels: []LevelConfig{{MaxBlocks: 3}}}) + key := compactionKey{tenant: "t", shard: 1} + q.stagedBlocks(key).push(testBlockEntry(1)) + q.stagedBlocks(key).push(testBlockEntry(2)) + + remove(q, key, "1") + require.Empty(t, q.staged[key].batch.blocks[0]) + + _, exists := q.staged[key].refs["1"] + assert.False(t, exists) + + remove(q, key, "2") + require.Nil(t, q.head) + require.Nil(t, q.tail) +} + +func TestBlockQueue_RemoveNotFound(t *testing.T) { + q := testBlockQueue(Config{Levels: []LevelConfig{{MaxBlocks: 3}}}) + key := compactionKey{tenant: "t", shard: 1} + remove(q, key, "1") + q.stagedBlocks(key).push(testBlockEntry(1)) + remove(q, key, "2") + q.stagedBlocks(key).push(testBlockEntry(2)) + q.stagedBlocks(key).push(testBlockEntry(3)) + + assert.Equal(t, []blockEntry{testBlockEntry(1), testBlockEntry(2), testBlockEntry(3)}, q.head.blocks) +} + +func TestBlockQueue_Linking(t *testing.T) { + q := testBlockQueue(Config{Levels: []LevelConfig{{MaxBlocks: 2}}}) + key := compactionKey{tenant: "t", shard: 1} + + q.stagedBlocks(key).push(testBlockEntry(1)) + q.stagedBlocks(key).push(testBlockEntry(2)) + head, tail := q.head, q.tail + require.NotNil(t, head) + assert.Equal(t, head, tail) + + q.stagedBlocks(key).push(testBlockEntry(3)) + assert.NotNil(t, q.tail) + assert.Equal(t, head, q.head) + assert.Equal(t, tail, q.tail) + assert.Equal(t, []blockEntry{testBlockEntry(1), testBlockEntry(2)}, q.head.blocks) + assert.Equal(t, q.tail.blocks, q.head.blocks) + + q.stagedBlocks(key).push(testBlockEntry(4)) + assert.NotNil(t, q.tail.prevG) + assert.NotNil(t, q.head.nextG) + + q.stagedBlocks(key).push(testBlockEntry(5)) + q.stagedBlocks(key).push(testBlockEntry(6)) + assert.NotNil(t, q.tail.prevG.prevG) + assert.NotNil(t, q.head.nextG.nextG) + + t.Run("iterator does not affect the queue", func(t *testing.T) { + expected := []string{"1", "2", "3", "4", "5", "6"} + for i := 0; i < 3; i++ { + collected := make([]string, 0, len(expected)) + iter := newBlockIter() + iter.setBatch(q.head) + for { + b, ok := iter.peek() + if !ok { + assert.Equal(t, expected, collected) + break + } + collected = append(collected, b) + iter.advance() + } + } + }) + + t.Run("remove staging batch from the queue", func(t *testing.T) { + q.stagedBlocks(key).push(testBlockEntry(7)) + // Block 7 is still staged: test that it can be + // removed without affecting the queue. + head, tail = q.head, q.tail + remove(q, key, "7") + assert.Equal(t, head, q.head) + assert.Equal(t, tail, q.tail) + }) + + t.Run("empty queue", func(t *testing.T) { + remove(q, key, "3", "2") + remove(q, key, "4", "1") + remove(q, key, "6") + remove(q, key, "5") + assert.Nil(t, q.head) + assert.Nil(t, q.tail) + }) +} + +func TestBlockQueue_EmptyQueue(t *testing.T) { + const ( + numKeys = 50 + numBlocksPerKey = 100 + ) + + q := testBlockQueue(Config{Levels: []LevelConfig{{MaxBlocks: 3}}}) + keys := make([]compactionKey, numKeys) + for i := 0; i < numKeys; i++ { + keys[i] = compactionKey{ + tenant: fmt.Sprint(i), + shard: uint32(i), + } + } + + blocks := make(map[compactionKey][]string) + for _, key := range keys { + for j := 0; j < numBlocksPerKey; j++ { + block := testBlockEntry(j) + require.True(t, q.stagedBlocks(key).push(block)) + blocks[key] = append(blocks[key], block.id) + } + } + + for key, s := range blocks { + rand.Shuffle(len(s), func(i, j int) { + s[i], s[j] = s[j], s[i] + }) + for _, b := range s { + staged, ok := q.staged[key] + if !ok { + return + } + assert.NotEmpty(t, staged.delete(b)) + } + } + + for key := range blocks { + require.Nil(t, q.staged[key]) + } + + assert.Nil(t, q.head) + assert.Nil(t, q.tail) +} + +func TestBlockQueue_FlushByAge(t *testing.T) { + s := Config{ + Levels: []LevelConfig{ + {MaxBlocks: 3, MaxAge: 1}, + {MaxBlocks: 5, MaxAge: 1}, + }, + } + + c := newCompactionQueue(s, nil) + blocks := []compaction.BlockEntry{ + {Tenant: "A", Shard: 1, Level: 1, Index: 1, AppendedAt: 5, ID: "1"}, + {Tenant: "A", Shard: 1, Level: 1, Index: 2, AppendedAt: 15, ID: "2"}, + {Tenant: "A", Shard: 0, Level: 1, Index: 3, AppendedAt: 30, ID: "3"}, + {Tenant: "A", Shard: 0, Level: 1, Index: 4, AppendedAt: 35, ID: "4"}, + {Tenant: "B", Shard: 0, Level: 1, Index: 5, AppendedAt: 40, ID: "5"}, + } + for _, e := range blocks { + c.push(e) + } + + batches := make([]blockEntry, 0, len(blocks)) + q := c.blockQueue(1) + iter := newBatchIter(q) + for { + b, ok := iter.next() + if !ok { + break + } + batches = append(batches, b.blocks...) + } + + expected := []blockEntry{{"1", 1}, {"2", 2}, {"3", 3}, {"4", 4}} + // "5" remains staged as we need another push to evict it. + assert.Equal(t, expected, batches) + + // We have 3 compaction queues (staging batches): + // A/1/1, A/0/1, B/0/1. + assert.Equal(t, 3, q.updates.Len()) + + staged := q.stagedBlocks(compactionKey{tenant: "B", shard: 0, level: 1}) + staged.delete("5") + // B/0/1 compaction queue is removed. + assert.Equal(t, 2, q.updates.Len()) + + staged = q.stagedBlocks(compactionKey{tenant: "A", shard: 0, level: 1}) + staged.delete("4") + // A/0/1 is still here. + assert.Equal(t, 2, q.updates.Len()) + staged.delete("3") + // A/0/1 compaction queue is removed. + assert.Equal(t, 1, q.updates.Len()) + + // A/1/1 compaction queue is removed. + staged = q.stagedBlocks(compactionKey{tenant: "A", shard: 1, level: 1}) + assert.NotEmpty(t, staged.delete("1")) + assert.Equal(t, 1, q.updates.Len()) + assert.NotEmpty(t, staged.delete("2")) + assert.Equal(t, 0, staged.queue.updates.Len()) +} + +func TestBlockQueue_BatchIterator(t *testing.T) { + q := testBlockQueue(Config{Levels: []LevelConfig{{MaxBlocks: 3}}}) + keys := []compactionKey{ + {tenant: "t-1", shard: 1}, + {tenant: "t-2", shard: 2}, + } + + for j := 0; j < 20; j++ { + q.stagedBlocks(keys[j%len(keys)]).push(testBlockEntry(j)) + } + + iter := newBatchIter(q) + for _, expected := range []struct { + key compactionKey + blocks []string + }{ + {key: keys[0], blocks: []string{"0", "2", "4"}}, + {key: keys[1], blocks: []string{"1", "3", "5"}}, + {key: keys[0], blocks: []string{"6", "8", "10"}}, + {key: keys[1], blocks: []string{"7", "9", "11"}}, + {key: keys[0], blocks: []string{"12", "14", "16"}}, + {key: keys[1], blocks: []string{"13", "15", "17"}}, + } { + b, ok := iter.next() + require.True(t, ok) + assert.Equal(t, expected.key, b.staged.key) + actual := make([]string, len(b.blocks)) + for i := range b.blocks { + actual[i] = b.blocks[i].id + } + assert.Equal(t, expected.blocks, actual) + } + + _, ok := iter.next() + assert.False(t, ok) +} + +func remove(q *blockQueue, key compactionKey, block ...string) { + staged, ok := q.staged[key] + if !ok { + return + } + for _, b := range block { + staged.delete(b) + } +} diff --git a/pkg/metastore/compaction/compactor/compactor.go b/pkg/metastore/compaction/compactor/compactor.go new file mode 100644 index 0000000000..ede81958fe --- /dev/null +++ b/pkg/metastore/compaction/compactor/compactor.go @@ -0,0 +1,124 @@ +package compactor + +import ( + "time" + + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction/compactor/store" +) + +var ( + _ compaction.Compactor = (*Compactor)(nil) + _ compaction.Planner = (*Compactor)(nil) +) + +type Tombstones interface { + ListTombstones(before time.Time) iter.Iterator[*metastorev1.Tombstones] +} + +type BlockQueueStore interface { + StoreEntry(*bbolt.Tx, compaction.BlockEntry) error + DeleteEntry(tx *bbolt.Tx, index uint64, id string) error + ListEntries(*bbolt.Tx) iter.Iterator[compaction.BlockEntry] + CreateBuckets(*bbolt.Tx) error +} + +type Compactor struct { + config Config + queue *compactionQueue + store BlockQueueStore + tombstones Tombstones +} + +func NewCompactor( + config Config, + store BlockQueueStore, + tombstones Tombstones, + reg prometheus.Registerer, +) *Compactor { + queue := newCompactionQueue(config, reg) + return &Compactor{ + config: config, + queue: queue, + store: store, + tombstones: tombstones, + } +} + +func NewStore() *store.BlockQueueStore { + return store.NewBlockQueueStore() +} + +func (c *Compactor) Compact(tx *bbolt.Tx, entry compaction.BlockEntry) error { + if int(entry.Level) >= len(c.config.Levels) { + return nil + } + if err := c.store.StoreEntry(tx, entry); err != nil { + return err + } + c.enqueue(entry) + return nil +} + +func (c *Compactor) enqueue(e compaction.BlockEntry) bool { + return c.queue.push(e) +} + +func (c *Compactor) NewPlan(cmd *raft.Log) compaction.Plan { + now := cmd.AppendedAt.UnixNano() + before := cmd.AppendedAt.Add(-c.config.CleanupDelay) + tombstones := c.tombstones.ListTombstones(before) + return &plan{ + compactor: c, + tombstones: tombstones, + blocks: newBlockIter(), + now: now, + } +} + +func (c *Compactor) UpdatePlan(tx *bbolt.Tx, plan *raft_log.CompactionPlanUpdate) error { + for _, job := range plan.NewJobs { + // Delete source blocks from the compaction queue. + k := compactionKey{ + tenant: job.Plan.Tenant, + shard: job.Plan.Shard, + level: job.Plan.CompactionLevel, + } + staged := c.queue.blockQueue(k.level).stagedBlocks(k) + for _, b := range job.Plan.SourceBlocks { + e := staged.delete(b) + if e == zeroBlockEntry { + continue + } + if err := c.store.DeleteEntry(tx, e.index, e.id); err != nil { + return err + } + } + } + + return nil +} + +func (c *Compactor) Init(tx *bbolt.Tx) error { + return c.store.CreateBuckets(tx) +} + +func (c *Compactor) Restore(tx *bbolt.Tx) error { + // Reset in-memory state before loading entries from the store. + c.queue.reset() + entries := c.store.ListEntries(tx) + defer func() { + _ = entries.Close() + }() + for entries.Next() { + c.enqueue(entries.At()) + } + return entries.Err() +} diff --git a/pkg/metastore/compaction/compactor/compactor_config.go b/pkg/metastore/compaction/compactor/compactor_config.go new file mode 100644 index 0000000000..62500c0cdf --- /dev/null +++ b/pkg/metastore/compaction/compactor/compactor_config.go @@ -0,0 +1,81 @@ +package compactor + +import ( + "flag" + "time" +) + +type Config struct { + Levels []LevelConfig + + CleanupBatchSize int32 + CleanupDelay time.Duration + CleanupJobMinLevel int32 + CleanupJobMaxLevel int32 +} + +type LevelConfig struct { + MaxBlocks uint + MaxAge int64 +} + +func DefaultConfig() Config { + return Config{ + Levels: []LevelConfig{ + {MaxBlocks: 20, MaxAge: int64(1 * 36 * time.Second)}, + {MaxBlocks: 10, MaxAge: int64(2 * 360 * time.Second)}, + {MaxBlocks: 10, MaxAge: int64(3 * 3600 * time.Second)}, + }, + + CleanupBatchSize: 2, + CleanupDelay: 15 * time.Minute, + CleanupJobMaxLevel: 1, + CleanupJobMinLevel: 0, + } +} + +func (c *Config) RegisterFlagsWithPrefix(string, *flag.FlagSet) { + // NOTE(kolesnikovae): I'm not sure if making this configurable + // is a good idea; however, we might want to add a flag to tune + // the parameters based on e.g., segment size or max duration. + *c = DefaultConfig() +} + +// exceedsSize is called after the block has been added to the batch. +// If the function returns true, the batch is flushed to the global +// queue and becomes available for compaction. +func (c *Config) exceedsMaxSize(b *batch) bool { + return uint(b.size) >= c.maxBlocks(b.staged.key.level) +} + +// exceedsAge reports whether the batch update time is older than the +// maximum age for the level threshold. The function is used in two +// cases: if the batch is not flushed to the global queue and is the +// oldest one, or if the batch is flushed (and available to the planner) +// but the job plan is not complete yet. +func (c *Config) exceedsMaxAge(b *batch, now int64) bool { + if m := c.maxAge(b.staged.key.level); m > 0 { + age := now - b.createdAt + return age > m + } + return false +} + +func (c *Config) maxBlocks(l uint32) uint { + if l < uint32(len(c.Levels)) { + return c.Levels[l].MaxBlocks + } + return 0 +} + +func (c *Config) maxAge(l uint32) int64 { + if l < uint32(len(c.Levels)) { + return c.Levels[l].MaxAge + } + return 0 +} + +func (c *Config) maxLevel() uint32 { + // Assuming that there is at least one level. + return uint32(len(c.Levels) - 1) +} diff --git a/pkg/metastore/compaction/compactor/compactor_test.go b/pkg/metastore/compaction/compactor/compactor_test.go new file mode 100644 index 0000000000..9d56c08517 --- /dev/null +++ b/pkg/metastore/compaction/compactor/compactor_test.go @@ -0,0 +1,128 @@ +package compactor + +import ( + "errors" + "strconv" + "testing" + "time" + + "github.com/hashicorp/raft" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockcompactor" +) + +func TestCompactor_Compact(t *testing.T) { + queueStore := new(mockcompactor.MockBlockQueueStore) + tombstones := new(mockcompactor.MockTombstones) + + e := compaction.BlockEntry{ + Index: 1, + AppendedAt: time.Unix(0, 0).UnixNano(), + ID: "1", + Tenant: "A", + } + + compactor := NewCompactor(testConfig, queueStore, tombstones, nil) + testErr := errors.New("x") + t.Run("fails if cannot store the entry", test.AssertIdempotentSubtest(t, func(t *testing.T) { + queueStore.On("StoreEntry", mock.Anything, mock.Anything).Return(testErr) + require.ErrorIs(t, compactor.Compact(nil, e), testErr) + })) + + queueStore.AssertExpectations(t) + tombstones.AssertExpectations(t) +} + +func TestCompactor_UpdatePlan(t *testing.T) { + const N = 10 + + tombstones := new(mockcompactor.MockTombstones) + queueStore := new(mockcompactor.MockBlockQueueStore) + queueStore.On("StoreEntry", mock.Anything, mock.Anything). + Return(nil).Times(N) + + compactor := NewCompactor(testConfig, queueStore, tombstones, nil) + now := time.Unix(0, 0) + for i := 0; i < N; i++ { + err := compactor.Compact(nil, compaction.BlockEntry{ + Index: 1, + AppendedAt: now.UnixNano(), + ID: strconv.Itoa(i), + Tenant: "A", + }) + require.NoError(t, err) + } + + planned := make([]*raft_log.CompactionJobPlan, 3) + test.AssertIdempotent(t, func(t *testing.T) { + tombstones.On("ListTombstones", mock.Anything). + Return(iter.NewEmptyIterator[*metastorev1.Tombstones](), nil) + + planner := compactor.NewPlan(&raft.Log{Index: uint64(2), AppendedAt: now}) + for i := range planned { + job, err := planner.CreateJob() + require.NoError(t, err) + require.NotNil(t, job) + planned[i] = job + } + + job, err := planner.CreateJob() + require.NoError(t, err) + require.Nil(t, job) + }) + + // UpdatePlan is mostly idempotent, except it won't + // DeleteEntry that is not loaded into memory. + queueStore.On("DeleteEntry", mock.Anything, mock.Anything, mock.Anything). + Return(nil).Times(9) + + test.AssertIdempotent(t, func(t *testing.T) { + newJobs := make([]*raft_log.NewCompactionJob, 3) + for i := range planned { + newJobs[i] = &raft_log.NewCompactionJob{Plan: planned[i]} + } + + update := &raft_log.CompactionPlanUpdate{NewJobs: newJobs} + require.NoError(t, compactor.UpdatePlan(nil, update)) + + planner := compactor.NewPlan(&raft.Log{Index: uint64(3), AppendedAt: now}) + job, err := planner.CreateJob() + require.NoError(t, err) + require.Nil(t, job) + }) + + queueStore.AssertExpectations(t) + tombstones.AssertExpectations(t) +} + +func TestCompactor_Restore(t *testing.T) { + queueStore := new(mockcompactor.MockBlockQueueStore) + queueStore.On("ListEntries", mock.Anything).Return(iter.NewSliceIterator([]compaction.BlockEntry{ + {Index: 0, ID: "0", Tenant: "A"}, + {Index: 1, ID: "1", Tenant: "A"}, + {Index: 2, ID: "2", Tenant: "A"}, + {Index: 3, ID: "3", Tenant: "A"}, + })) + + tombstones := new(mockcompactor.MockTombstones) + tombstones.On("ListTombstones", mock.Anything). + Return(iter.NewEmptyIterator[*metastorev1.Tombstones](), nil) + + compactor := NewCompactor(testConfig, queueStore, tombstones, nil) + require.NoError(t, compactor.Restore(nil)) + + planner := compactor.NewPlan(new(raft.Log)) + planned, err := planner.CreateJob() + require.NoError(t, err) + require.NotEmpty(t, planned) + + queueStore.AssertExpectations(t) + tombstones.AssertExpectations(t) +} diff --git a/pkg/metastore/compaction/compactor/metrics.go b/pkg/metastore/compaction/compactor/metrics.go new file mode 100644 index 0000000000..7547ccf906 --- /dev/null +++ b/pkg/metastore/compaction/compactor/metrics.go @@ -0,0 +1,151 @@ +package compactor + +import ( + "strconv" + "sync/atomic" + + "github.com/prometheus/client_golang/prometheus" +) + +type queueStatsCollector struct { + stats *queueStats + + blocks *prometheus.Desc + batches *prometheus.Desc + rejected *prometheus.Desc + missed *prometheus.Desc +} + +const blockQueueMetricsPrefix = "compaction_block_queue_" + +func newQueueStatsCollector(staged *stagedBlocks) *queueStatsCollector { + constLabels := map[string]string{ + "tenant": staged.key.tenant, + "shard": strconv.FormatUint(uint64(staged.key.shard), 10), + "level": strconv.FormatUint(uint64(staged.key.level), 10), + } + + return &queueStatsCollector{ + stats: staged.stats, + + blocks: prometheus.NewDesc( + blockQueueMetricsPrefix+"blocks", + "The total number of blocks in the queue.", + nil, constLabels, + ), + + batches: prometheus.NewDesc( + blockQueueMetricsPrefix+"batches", + "The total number of block batches in the queue.", + nil, constLabels, + ), + + rejected: prometheus.NewDesc( + blockQueueMetricsPrefix+"push_rejected_total", + "The total number of blocks rejected on push.", + nil, constLabels, + ), + + missed: prometheus.NewDesc( + blockQueueMetricsPrefix+"delete_missed_total", + "The total number of blocks missed on delete.", + nil, constLabels, + ), + } +} + +func (b *queueStatsCollector) Describe(c chan<- *prometheus.Desc) { + c <- b.blocks + c <- b.batches + c <- b.rejected + c <- b.missed +} + +func (b *queueStatsCollector) Collect(m chan<- prometheus.Metric) { + m <- prometheus.MustNewConstMetric(b.blocks, prometheus.GaugeValue, float64(b.stats.blocks.Load())) + m <- prometheus.MustNewConstMetric(b.batches, prometheus.GaugeValue, float64(b.stats.batches.Load())) + m <- prometheus.MustNewConstMetric(b.rejected, prometheus.CounterValue, float64(b.stats.rejected.Load())) + m <- prometheus.MustNewConstMetric(b.missed, prometheus.CounterValue, float64(b.stats.missed.Load())) +} + +type globalQueueStats struct { + blocksPerLevel []atomic.Int32 + queuesPerLevel []atomic.Int32 + batchesPerLevel []atomic.Int32 +} + +func newGlobalQueueStats(numLevels int) *globalQueueStats { + return &globalQueueStats{ + blocksPerLevel: make([]atomic.Int32, numLevels), + queuesPerLevel: make([]atomic.Int32, numLevels), + batchesPerLevel: make([]atomic.Int32, numLevels), + } +} + +func (g *globalQueueStats) AddBlocks(key compactionKey, delta int32) { + g.blocksPerLevel[key.level].Add(delta) +} + +func (g *globalQueueStats) AddQueues(key compactionKey, delta int32) { + g.queuesPerLevel[key.level].Add(delta) +} + +func (g *globalQueueStats) AddBatches(key compactionKey, delta int32) { + g.batchesPerLevel[key.level].Add(delta) +} + +type globalQueueStatsCollector struct { + compactionQueue *compactionQueue + + blocks *prometheus.Desc + queues *prometheus.Desc + batches *prometheus.Desc +} + +const globalQueueMetricsPrefix = "compaction_global_queue_" + +func newGlobalQueueStatsCollector(compactionQueue *compactionQueue) *globalQueueStatsCollector { + variableLabels := []string{"level"} + + return &globalQueueStatsCollector{ + compactionQueue: compactionQueue, + + blocks: prometheus.NewDesc( + globalQueueMetricsPrefix+"blocks_current", + "The current number of blocks across all queues, for a compaction level.", + variableLabels, nil, + ), + + queues: prometheus.NewDesc( + globalQueueMetricsPrefix+"queues_current", + "The current number of queues, for a compaction level.", + variableLabels, nil, + ), + + batches: prometheus.NewDesc( + globalQueueMetricsPrefix+"batches_current", + "The current number of batches (jobs that are not yet created), for a compaction level.", + variableLabels, nil, + ), + } +} + +func (c *globalQueueStatsCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- c.blocks + ch <- c.queues + ch <- c.batches +} + +func (c *globalQueueStatsCollector) Collect(ch chan<- prometheus.Metric) { + for levelIdx := range c.compactionQueue.config.Levels { + blocksAtLevel := c.compactionQueue.globalStats.blocksPerLevel[levelIdx].Load() + queuesAtLevel := c.compactionQueue.globalStats.queuesPerLevel[levelIdx].Load() + batchesAtLevel := c.compactionQueue.globalStats.batchesPerLevel[levelIdx].Load() + + levelLabel := strconv.Itoa(levelIdx) + + ch <- prometheus.MustNewConstMetric(c.blocks, prometheus.GaugeValue, float64(blocksAtLevel), levelLabel) + ch <- prometheus.MustNewConstMetric(c.queues, prometheus.GaugeValue, float64(queuesAtLevel), levelLabel) + ch <- prometheus.MustNewConstMetric(c.batches, prometheus.GaugeValue, float64(batchesAtLevel), levelLabel) + } +} diff --git a/pkg/metastore/compaction/compactor/metrics_test.go b/pkg/metastore/compaction/compactor/metrics_test.go new file mode 100644 index 0000000000..a0db476dae --- /dev/null +++ b/pkg/metastore/compaction/compactor/metrics_test.go @@ -0,0 +1,107 @@ +package compactor + +import ( + "testing" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" +) + +func TestCollectorRegistration(t *testing.T) { + reg := prometheus.NewRegistry() + for i := 0; i < 2; i++ { + entries := []compaction.BlockEntry{ + {Tenant: "A", Shard: 0, Level: 0}, + {Tenant: "A", Shard: 0, Level: 1}, + {Tenant: "A", Shard: 0, Level: 1}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "B", Shard: 0, Level: 0}, + } + c := NewCompactor(testConfig, nil, nil, reg) + for _, e := range entries { + c.enqueue(e) + } + c.queue.reset() + for _, e := range entries { + c.enqueue(e) + } + } +} + +func TestBlockQueueAggregatedMetrics(t *testing.T) { + reg := prometheus.NewRegistry() + c := NewCompactor(testConfig, nil, nil, reg) + + entries := []compaction.BlockEntry{ + {ID: "block1", Tenant: "A", Shard: 0, Level: 0}, + {ID: "block2", Tenant: "A", Shard: 0, Level: 0}, + {ID: "block3", Tenant: "A", Shard: 0, Level: 0}, + {ID: "block4", Tenant: "A", Shard: 1, Level: 0}, + {ID: "block5", Tenant: "B", Shard: 0, Level: 1}, + {ID: "block6", Tenant: "B", Shard: 0, Level: 1}, + {ID: "block7", Tenant: "B", Shard: 0, Level: 1}, + } + + for _, e := range entries { + c.enqueue(e) + } + + metrics, err := reg.Gather() + if err != nil { + t.Fatalf("failed to gather metrics: %v", err) + } + + var blocksTotal, queuesTotal, batchesTotal float64 + var foundBlocks, foundQueues, foundBatches bool + + for _, mf := range metrics { + if mf.GetName() == "compaction_global_queue_blocks_current" { + for _, m := range mf.GetMetric() { + blocksTotal += m.GetGauge().GetValue() + foundBlocks = true + } + } + if mf.GetName() == "compaction_global_queue_queues_current" { + for _, m := range mf.GetMetric() { + queuesTotal += m.GetGauge().GetValue() + foundQueues = true + } + } + + if mf.GetName() == "compaction_global_queue_batches_current" { + for _, m := range mf.GetMetric() { + batchesTotal += m.GetGauge().GetValue() + foundBatches = true + } + } + } + + if !foundBlocks { + t.Fatal("compaction_global_queue_blocks metric not found") + } + if !foundQueues { + t.Fatal("compaction_global_queue_queues metric not found") + } + if !foundBatches { + t.Fatal("compaction_global_queue_batches_current metric not found") + } + + if blocksTotal != 7 { + t.Errorf("expected 7 total blocks, got %v", blocksTotal) + } + + if queuesTotal != 3 { + t.Errorf("expected 3 total queues, got %v", queuesTotal) + } + + // testConfig.Levels[0].MaxBlocks = 3 + // testConfig.Levels[1].MaxBlocks = 2 + // (A,0): 3 blocks → 3/3 = 1 batch + // (A,1): 1 block → 1/2 = 0 batches + // (B,1): 3 blocks → 3/2 = 1 batch + // Total = 2 batches + if batchesTotal != 2 { + t.Errorf("expected 2 total batches, got %v", batchesTotal) + } +} diff --git a/pkg/metastore/compaction/compactor/plan.go b/pkg/metastore/compaction/compactor/plan.go new file mode 100644 index 0000000000..dbc777e89a --- /dev/null +++ b/pkg/metastore/compaction/compactor/plan.go @@ -0,0 +1,249 @@ +package compactor + +import ( + "fmt" + "math" + "strconv" + "strings" + + "github.com/cespare/xxhash/v2" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +// plan should be used to prepare the compaction plan update. +// The implementation must have no side effects or alter the +// Compactor in any way. +type plan struct { + level uint32 + // Read-only. + tombstones iter.Iterator[*metastorev1.Tombstones] + compactor *Compactor + batches *batchIter + blocks *blockIter + now int64 +} + +func (p *plan) CreateJob() (*raft_log.CompactionJobPlan, error) { + planned := p.nextJob() + if planned == nil { + return nil, nil + } + job := raft_log.CompactionJobPlan{ + Name: planned.name, + Shard: planned.shard, + Tenant: planned.tenant, + CompactionLevel: planned.level, + SourceBlocks: planned.blocks, + Tombstones: planned.tombstones, + } + return &job, nil +} + +type jobPlan struct { + compactionKey + config *Config + name string + minT int64 + maxT int64 + tombstones []*metastorev1.Tombstones + blocks []string +} + +// Plan compaction of the queued blocks. The algorithm is simple: +// - Iterate block queues from low levels to higher ones. +// - Find the oldest batch in the order of arrival and try to compact it. +// - A batch may not translate into a job (e.g., if some blocks have been +// removed). Therefore, we navigate to the next batch with the same +// compaction key in this case. +func (p *plan) nextJob() *jobPlan { + job := p.newJob() + for p.level < uint32(len(p.compactor.queue.levels)) { + if p.batches == nil { + level := p.compactor.queue.levels[p.level] + if level == nil { + p.level++ + continue + } + p.batches = newBatchIter(level) + } + + b, ok := p.batches.next() + if !ok { + // We've done with the current level: no more batches + // in the in-order queue. Move to the next level. + p.batches = nil + p.level++ + continue + } + + // We've found the oldest batch, it's time to plan a job. + // Job levels are zero based: L0 job means that it includes blocks + // with compaction level 0. This can be altered (1-based levels): + // job.level++ + job.reset(b.staged.key) + p.blocks.setBatch(b) + + var force bool + for { + // Peek the next block in the compaction queue with the same + // compaction key as the current batch. If there are no blocks + // in the current batch, or we have already visited all of them + // previously, the iterator will proceed to the next batch with + // this compaction key. The call to peek() will return false, if + // only no blocks eligible for compaction are left in the queue. + block, found := p.blocks.peek() + if !found { + // No more blocks with this compaction key at the level. + // We may want to force compaction even if the current job + // is incomplete: e.g., if the blocks remain in the queue for + // too long. Note that we do not check the block timestamps: + // we only care when the first (oldest) batch was created. + // We do want to check the _oldest_, not the _current_ batch + // here, because it could be relatively young. + force = p.compactor.config.exceedsMaxAge(b, p.now) + break + } + if !job.tryAdd(block) { + // We may not want to add a bock to the job if it extends the + // compacted block time range beyond the desired limit. + // In this case, we need to force compaction of incomplete job. + force = true + break + } + // If the block was added to the job, we advance the block iterator + // to the next block within the batch, remembering the current block + // as a visited one. + p.blocks.advance() + if job.isComplete() { + break + } + } + + if len(job.blocks) > 0 && (job.isComplete() || force) { + // Typically, we want to proceed to the next compaction key, + // but if the batch is not empty (i.e., we could not put all + // the blocks into the job), we must finish it first. + if p.blocks.more() { + // There are more blocks in the current batch: p.blocks.peek() + // reported a block is found, but we could not add it to the job. + // + // We need to reset the batch iterator to continue from the oldest + // batch that still has blocks to process: basically, we want + // p.batches.next() to return b. + // + // This ensures we don't skip blocks or process them out of order. + // Block iterator ensures that each block is only accessed once. + // + // If the queue that b points to has any unvisited blocks, + // p.blocks.peek() will return them. Otherwise, we continue + // iterating over the in-order queue of batches (different + // compaction queues have distinct compaction keys). + // + // We assume that we can re-iterate over the batch blocks next time, + // skipping the ones that have already been visited (it's done by + // iterator internally). + p.batches.reset(b) + } + p.getTombstones(job) + job.finalize() + return job + } + + // The job plan is canceled for the compaction key, and we need to + // continue with the next compaction key, or level. + } + + return nil +} + +func (p *plan) getTombstones(job *jobPlan) { + if int32(p.level) > p.compactor.config.CleanupJobMaxLevel { + return + } + if int32(p.level) < p.compactor.config.CleanupJobMinLevel { + return + } + s := int(p.compactor.config.CleanupBatchSize) + for i := 0; i < s && p.tombstones.Next(); i++ { + job.tombstones = append(job.tombstones, p.tombstones.At()) + } +} + +func (p *plan) newJob() *jobPlan { + return &jobPlan{ + config: &p.compactor.config, + blocks: make([]string, 0, defaultBlockBatchSize), + minT: math.MaxInt64, + maxT: math.MinInt64, + } +} + +func (job *jobPlan) reset(k compactionKey) { + job.compactionKey = k + job.blocks = job.blocks[:0] + job.minT = math.MaxInt64 + job.maxT = math.MinInt64 +} + +func (job *jobPlan) tryAdd(block string) bool { + t := util.ULIDStringUnixNano(block) + if len(job.blocks) > 0 && !job.isInAllowedTimeRange(t) { + return false + } + job.blocks = append(job.blocks, block) + job.maxT = max(job.maxT, t) + job.minT = min(job.minT, t) + return true +} + +func (job *jobPlan) isInAllowedTimeRange(t int64) bool { + if age := job.config.maxAge(job.config.maxLevel()); age > 0 { + // minT maxT + // --t------|===========|------t-- + // | |---------a--------| + // |---------b--------| + a := t - job.minT + b := job.maxT - t + if a > age || b > age { + return false + } + } + return true +} + +func (job *jobPlan) isComplete() bool { + return uint(len(job.blocks)) >= job.config.maxBlocks(job.level) +} + +func (job *jobPlan) finalize() { + nameJob(job) + job.minT = 0 + job.maxT = 0 + job.config = nil +} + +// Job name is a variable length string that should be globally unique +// and is used as a tiebreaker in the compaction job queue ordering. +func nameJob(plan *jobPlan) { + // Should be on stack; 16b per block; expected ~20 blocks. + buf := make([]byte, 0, 512) + for _, b := range plan.blocks { + buf = append(buf, b...) + } + var name strings.Builder + name.WriteString(fmt.Sprintf("%x", xxhash.Sum64(buf))) + name.WriteByte('-') + name.WriteByte('T') + name.WriteString(plan.tenant) + name.WriteByte('-') + name.WriteByte('S') + name.WriteString(strconv.FormatUint(uint64(plan.shard), 10)) + name.WriteByte('-') + name.WriteByte('L') + name.WriteString(strconv.FormatUint(uint64(plan.level), 10)) + plan.name = name.String() +} diff --git a/pkg/metastore/compaction/compactor/plan_test.go b/pkg/metastore/compaction/compactor/plan_test.go new file mode 100644 index 0000000000..286dcafa97 --- /dev/null +++ b/pkg/metastore/compaction/compactor/plan_test.go @@ -0,0 +1,415 @@ +package compactor + +import ( + "fmt" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +var testConfig = Config{ + Levels: []LevelConfig{ + {MaxBlocks: 3}, + {MaxBlocks: 2}, + {MaxBlocks: 2}, + }, +} + +func TestPlan_same_level(t *testing.T) { + c := NewCompactor(testConfig, nil, nil, nil) + + var i int // The index is used outside the loop. + for _, e := range []compaction.BlockEntry{ + {Tenant: "A", Shard: 0, Level: 0}, + {Tenant: "B", Shard: 2, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "B", Shard: 2, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, // TA-S1-L0 is ready + {Tenant: "B", Shard: 2, Level: 0}, // TB-S2-L0 + {Tenant: "A", Shard: 0, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "A", Shard: 0, Level: 0}, // TA-S0-L0 + {Tenant: "B", Shard: 2, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + } { + e.Index = uint64(i) + e.ID = strconv.Itoa(i) + c.enqueue(e) + i++ + } + + expected := []*jobPlan{ + { + compactionKey: compactionKey{tenant: "A", shard: 1, level: 0}, + name: "ffba6b12acb007e6-TA-S1-L0", + blocks: []string{"2", "3", "5"}, + }, + { + compactionKey: compactionKey{tenant: "B", shard: 2, level: 0}, + name: "3860b3ec2cf5bfa3-TB-S2-L0", + blocks: []string{"1", "4", "6"}, + }, + { + compactionKey: compactionKey{tenant: "A", shard: 0, level: 0}, + name: "6a1fee35d1568267-TA-S0-L0", + blocks: []string{"0", "7", "9"}, + }, + } + + p := &plan{compactor: c, blocks: newBlockIter()} + planned := make([]*jobPlan, 0, len(expected)) + for j := p.nextJob(); j != nil; j = p.nextJob() { + planned = append(planned, j) + } + assert.Equal(t, expected, planned) + + // Now we're adding some more blocks to produce more jobs, + // using the same queue. We expect all the previously planned + // jobs and new ones. + expected = append(expected, []*jobPlan{ + { + compactionKey: compactionKey{tenant: "A", shard: 1, level: 0}, + name: "34d4246acbf55d05-TA-S1-L0", + blocks: []string{"8", "11", "13"}, + }, + { + compactionKey: compactionKey{tenant: "B", shard: 2, level: 0}, + name: "5567ff0cdb349aaf-TB-S2-L0", + blocks: []string{"10", "12", "14"}, + }, + }...) + + for _, e := range []compaction.BlockEntry{ + {Tenant: "B", Shard: 2, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, // TA-S1-L0 is ready + {Tenant: "B", Shard: 2, Level: 0}, // TB-S2-L0 + } { + e.Index = uint64(i) + e.ID = strconv.Itoa(i) + c.enqueue(e) + i++ + } + + p = &plan{compactor: c, blocks: newBlockIter()} + planned = planned[:0] // Old jobs should be re-planned. + for j := p.nextJob(); j != nil; j = p.nextJob() { + planned = append(planned, j) + } + assert.Equal(t, expected, planned) +} + +func TestPlan_level_priority(t *testing.T) { + c := NewCompactor(testConfig, nil, nil, nil) + + // Lower level job should be planned first despite the arrival order. + var i int + for _, e := range []compaction.BlockEntry{ + {Tenant: "B", Shard: 2, Level: 1}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "B", Shard: 2, Level: 1}, // TB-S2-L1 is ready + {Tenant: "A", Shard: 1, Level: 0}, // TA-S1-L0 + } { + e.Index = uint64(i) + e.ID = strconv.Itoa(i) + c.enqueue(e) + i++ + } + + expected := []*jobPlan{ + { + compactionKey: compactionKey{tenant: "A", shard: 1, level: 0}, + name: "3567f9a8f34203a9-TA-S1-L0", + blocks: []string{"1", "2", "4"}, + }, + { + compactionKey: compactionKey{tenant: "B", shard: 2, level: 1}, + name: "3254788b90b8fafc-TB-S2-L1", + blocks: []string{"0", "3"}, + }, + } + + p := &plan{compactor: c, blocks: newBlockIter()} + planned := make([]*jobPlan, 0, len(expected)) + for j := p.nextJob(); j != nil; j = p.nextJob() { + planned = append(planned, j) + } + + assert.Equal(t, expected, planned) +} + +func TestPlan_empty_queue(t *testing.T) { + c := NewCompactor(testConfig, nil, nil, nil) + + p := &plan{compactor: c, blocks: newBlockIter()} + assert.Nil(t, p.nextJob()) + + c.enqueue(compaction.BlockEntry{ + Index: 0, + ID: "0", + Tenant: "A", + Shard: 1, + Level: 1, + }) + + // L0 queue is empty. + // L1 queue has one block. + p = &plan{compactor: c, blocks: newBlockIter()} + assert.Nil(t, p.nextJob()) + + c.enqueue(compaction.BlockEntry{ + Index: 1, + ID: "1", + Tenant: "A", + Shard: 1, + Level: 1, + }) + + // L0 queue is empty. + // L2 has blocks for a job. + p = &plan{compactor: c, blocks: newBlockIter()} + assert.NotNil(t, p.nextJob()) +} + +func TestPlan_deleted_blocks(t *testing.T) { + c := NewCompactor(testConfig, nil, nil, nil) + + var i int // The index is used outside the loop. + for _, e := range []compaction.BlockEntry{ + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "B", Shard: 2, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "B", Shard: 2, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, // TA-S1-L0 is ready + {Tenant: "B", Shard: 2, Level: 0}, // TB-S2-L0 + } { + e.Index = uint64(i) + e.ID = strconv.Itoa(i) + if !c.enqueue(e) { + t.Errorf("failed to enqueue: %v", e) + } + i++ + } + + // Invalidate TA-S1-L0 plan by removing some blocks. + remove(c.queue.levels[0], compactionKey{ + tenant: "A", + shard: 1, + level: 0, + }, "0", "4") + + // "0" - - - + // "1" {Tenant: "B", Shard: 2, Level: 0}, + // "2" {Tenant: "A", Shard: 1, Level: 0}, + // "3" {Tenant: "B", Shard: 2, Level: 0}, + // "4" - - - // TA-S1-L0 would be created here. + // "5" {Tenant: "B", Shard: 2, Level: 0}, // TB-S2-L0 is ready + expected := []*jobPlan{ + { + compactionKey: compactionKey{tenant: "B", shard: 2, level: 0}, + name: "5668d093d5b7cc2f-TB-S2-L0", + blocks: []string{"1", "3", "5"}, + }, + } + + p := &plan{compactor: c, blocks: newBlockIter()} + planned := make([]*jobPlan, 0, len(expected)) + for j := p.nextJob(); j != nil; j = p.nextJob() { + planned = append(planned, j) + } + assert.Equal(t, expected, planned) + + // Now we add some more blocks to make sure that the + // invalidated queue can still be compacted. + for _, e := range []compaction.BlockEntry{ + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + {Tenant: "A", Shard: 1, Level: 0}, + } { + e.Index = uint64(i) + e.ID = strconv.Itoa(i) + c.enqueue(e) + i++ + } + + expected = append([]*jobPlan{ + { + compactionKey: compactionKey{tenant: "A", shard: 1, level: 0}, + name: "69cebc117138be9-TA-S1-L0", + blocks: []string{"2", "6", "7"}, + }, + }, expected...) + + p = &plan{compactor: c, blocks: newBlockIter()} + planned = planned[:0] + for j := p.nextJob(); j != nil; j = p.nextJob() { + planned = append(planned, j) + } + assert.Equal(t, expected, planned) +} + +func TestPlan_deleted_batch(t *testing.T) { + c := NewCompactor(testConfig, nil, nil, nil) + + for i, e := range make([]compaction.BlockEntry, 3) { + e.Index = uint64(i) + e.ID = strconv.Itoa(i) + c.enqueue(e) + } + + remove(c.queue.levels[0], compactionKey{}, "0", "1", "2") + + p := &plan{compactor: c, blocks: newBlockIter()} + assert.Nil(t, p.nextJob()) +} + +func TestPlan_compact_by_time(t *testing.T) { + c := NewCompactor(Config{ + Levels: []LevelConfig{ + {MaxBlocks: 5, MaxAge: 5}, + {MaxBlocks: 5, MaxAge: 5}, + }, + }, nil, nil, nil) + + for _, e := range []compaction.BlockEntry{ + {Tenant: "A", Shard: 1, Level: 0, Index: 1, AppendedAt: 10, ID: "1"}, + {Tenant: "B", Shard: 0, Level: 0, Index: 2, AppendedAt: 20, ID: "2"}, + {Tenant: "A", Shard: 1, Level: 0, Index: 3, AppendedAt: 30, ID: "3"}, + } { + c.enqueue(e) + } + + // Third block remains in the queue as + // we need another push to evict it. + expected := []*jobPlan{ + { + compactionKey: compactionKey{tenant: "A", shard: 1, level: 0}, + name: "b7b41276360564d4-TA-S1-L0", + blocks: []string{"1"}, + }, + { + compactionKey: compactionKey{tenant: "B", shard: 0, level: 0}, + name: "6021b5621680598b-TB-S0-L0", + blocks: []string{"2"}, + }, + } + + p := &plan{ + compactor: c, + blocks: newBlockIter(), + now: 40, + } + + planned := make([]*jobPlan, 0, len(expected)) + for j := p.nextJob(); j != nil; j = p.nextJob() { + planned = append(planned, j) + } + + assert.Equal(t, expected, planned) +} + +func TestPlan_time_split(t *testing.T) { + s := DefaultConfig() + // To skip tombstones for simplicity. + s.CleanupBatchSize = 0 + c := NewCompactor(s, nil, nil, nil) + now := test.Time("2024-09-23T00:00:00Z") + + for i := 0; i < 10; i++ { + now = now.Add(15 * time.Second) + e := compaction.BlockEntry{ + Index: uint64(i), + AppendedAt: now.UnixNano(), + Tenant: "A", + Shard: 1, + Level: 0, + ID: test.ULID(now.Format(time.RFC3339)), + } + c.enqueue(e) + } + + now = now.Add(time.Hour * 6) + for i := 0; i < 5; i++ { + now = now.Add(15 * time.Second) + e := compaction.BlockEntry{ + Index: uint64(i), + AppendedAt: now.UnixNano(), + Tenant: "A", + Shard: 1, + Level: 0, + ID: test.ULID(now.Format(time.RFC3339)), + } + c.enqueue(e) + } + + p := &plan{ + compactor: c, + blocks: newBlockIter(), + now: now.UnixNano(), + } + + var i int + var n int + for j := p.nextJob(); j != nil; j = p.nextJob() { + i++ + n += len(j.blocks) + } + + assert.Equal(t, 2, i) + assert.Equal(t, 15, n) +} + +func TestPlan_remove_staged_batch_corrupts_queue(t *testing.T) { + c := NewCompactor(testConfig, nil, nil, nil) + + for i := 0; i < 3; i++ { + e := compaction.BlockEntry{ + Index: uint64(i), + ID: fmt.Sprint(i), + Tenant: "baseline", + Shard: 1, + Level: 0, + } + c.enqueue(e) + } + + p1 := &plan{compactor: c, blocks: newBlockIter()} + require.NotNil(t, p1.nextJob()) + require.Nil(t, p1.nextJob()) + + // Add and remove blocks before they got to the compaction + // queue, triggering removal of the staged batch. + for i := 10; i < 12; i++ { + e := compaction.BlockEntry{ + Index: uint64(i + 10), + ID: fmt.Sprint(i), + Tenant: "temp", + Shard: 1, + Level: 0, + } + c.enqueue(e) + } + + level0 := c.queue.levels[0] + tempKey := compactionKey{tenant: "temp", shard: 1, level: 0} + if tempStaged, exists := level0.staged[tempKey]; exists { + tempStaged.delete("10") + tempStaged.delete("11") + } else { + t.Fatal("Compaction queue not found") + } + + p2 := &plan{compactor: c, blocks: newBlockIter()} + if job := p2.nextJob(); job == nil { + t.Fatal("🐛🐛🐛: Corrupted compaction queue") + } + + require.Nil(t, p1.nextJob(), "A single job is expected.") +} diff --git a/pkg/metastore/compaction/compactor/store/block_queue_store.go b/pkg/metastore/compaction/compactor/store/block_queue_store.go new file mode 100644 index 0000000000..1a255cbc44 --- /dev/null +++ b/pkg/metastore/compaction/compactor/store/block_queue_store.go @@ -0,0 +1,110 @@ +package store + +import ( + "encoding/binary" + "errors" + + "go.etcd.io/bbolt" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" +) + +var ErrInvalidBlockEntry = errors.New("invalid block entry") + +var blockQueueBucketName = []byte("compaction_block_queue") + +// BlockQueueStore provides methods to store and retrieve block queues. +// The store is optimized for two cases: load the entire queue (preserving +// the original order) and remove an entry from the queue. +// +// Compactor maintains an in-memory queue of blocks to compact, therefore +// the store never reads individual entries. +// +// NOTE(kolesnikovae): We can leverage the fact that removed entries are +// always ordered in ascending order by index and use the same cursor when +// removing entries from the database: +// DeleteEntry(*bbolt.Tx, ...store.BlockEntry) error +type BlockQueueStore struct{ bucketName []byte } + +func NewBlockQueueStore() *BlockQueueStore { + return &BlockQueueStore{bucketName: blockQueueBucketName} +} + +func (s BlockQueueStore) CreateBuckets(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists(s.bucketName) + return err +} + +func (s BlockQueueStore) StoreEntry(tx *bbolt.Tx, entry compaction.BlockEntry) error { + e := marshalBlockEntry(entry) + return tx.Bucket(s.bucketName).Put(e.Key, e.Value) +} + +func (s BlockQueueStore) DeleteEntry(tx *bbolt.Tx, index uint64, id string) error { + return tx.Bucket(s.bucketName).Delete(marshalBlockEntryKey(index, id)) +} + +func (s BlockQueueStore) ListEntries(tx *bbolt.Tx) iter.Iterator[compaction.BlockEntry] { + return newBlockEntriesIterator(tx.Bucket(s.bucketName)) +} + +type blockEntriesIterator struct { + iter *store.CursorIterator + cur compaction.BlockEntry + err error +} + +func newBlockEntriesIterator(bucket *bbolt.Bucket) *blockEntriesIterator { + return &blockEntriesIterator{iter: store.NewCursorIter(bucket.Cursor())} +} + +func (x *blockEntriesIterator) Next() bool { + if x.err != nil || !x.iter.Next() { + return false + } + x.err = unmarshalBlockEntry(&x.cur, x.iter.At()) + return x.err == nil +} + +func (x *blockEntriesIterator) At() compaction.BlockEntry { return x.cur } + +func (x *blockEntriesIterator) Close() error { return x.iter.Close() } + +func (x *blockEntriesIterator) Err() error { + if err := x.iter.Err(); err != nil { + return err + } + return x.err +} + +func marshalBlockEntry(e compaction.BlockEntry) store.KV { + k := marshalBlockEntryKey(e.Index, e.ID) + b := make([]byte, 8+4+4+len(e.Tenant)) + binary.BigEndian.PutUint64(b[0:8], uint64(e.AppendedAt)) + binary.BigEndian.PutUint32(b[8:12], e.Level) + binary.BigEndian.PutUint32(b[12:16], e.Shard) + copy(b[16:], e.Tenant) + return store.KV{Key: k, Value: b} +} + +func marshalBlockEntryKey(index uint64, id string) []byte { + b := make([]byte, 8+len(id)) + binary.BigEndian.PutUint64(b, index) + copy(b[8:], id) + return b +} + +func unmarshalBlockEntry(dst *compaction.BlockEntry, e store.KV) error { + if len(e.Key) < 8 || len(e.Value) < 16 { + return ErrInvalidBlockEntry + } + dst.Index = binary.BigEndian.Uint64(e.Key) + dst.ID = string(e.Key[8:]) + dst.AppendedAt = int64(binary.BigEndian.Uint64(e.Value[0:8])) + dst.Level = binary.BigEndian.Uint32(e.Value[8:12]) + dst.Shard = binary.BigEndian.Uint32(e.Value[12:16]) + dst.Tenant = string(e.Value[16:]) + return nil +} diff --git a/pkg/metastore/compaction/compactor/store/block_queue_store_test.go b/pkg/metastore/compaction/compactor/store/block_queue_store_test.go new file mode 100644 index 0000000000..fb89603f76 --- /dev/null +++ b/pkg/metastore/compaction/compactor/store/block_queue_store_test.go @@ -0,0 +1,104 @@ +package store + +import ( + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestBlockQueueStore_StoreEntry(t *testing.T) { + db := test.BoltDB(t) + + s := NewBlockQueueStore() + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, s.CreateBuckets(tx)) + + entries := make([]compaction.BlockEntry, 1000) + for i := range entries { + entries[i] = compaction.BlockEntry{ + Index: uint64(i), + ID: strconv.Itoa(i), + AppendedAt: time.Now().UnixNano(), + Level: uint32(i % 3), + Shard: uint32(i % 8), + Tenant: strconv.Itoa(i % 4), + } + } + for i := range entries { + assert.NoError(t, s.StoreEntry(tx, entries[i])) + } + require.NoError(t, tx.Commit()) + + s = NewBlockQueueStore() + tx, err = db.Begin(false) + require.NoError(t, err) + iter := s.ListEntries(tx) + var i int + for iter.Next() { + assert.Less(t, i, len(entries)) + assert.Equal(t, entries[i], iter.At()) + i++ + } + assert.Nil(t, iter.Err()) + assert.Nil(t, iter.Close()) + require.NoError(t, tx.Rollback()) +} + +func TestBlockQueueStore_DeleteEntry(t *testing.T) { + db := test.BoltDB(t) + + s := NewBlockQueueStore() + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, s.CreateBuckets(tx)) + + entries := make([]compaction.BlockEntry, 1000) + for i := range entries { + entries[i] = compaction.BlockEntry{ + Index: uint64(i), + ID: strconv.Itoa(i), + AppendedAt: time.Now().UnixNano(), + Level: uint32(i % 3), + Shard: uint32(i % 8), + Tenant: strconv.Itoa(i % 4), + } + } + for i := range entries { + assert.NoError(t, s.StoreEntry(tx, entries[i])) + } + require.NoError(t, tx.Commit()) + + // Delete random 25%. + tx, err = db.Begin(true) + require.NoError(t, err) + for i := 0; i < len(entries); i += 4 { + assert.NoError(t, s.DeleteEntry(tx, entries[i].Index, entries[i].ID)) + } + require.NoError(t, tx.Commit()) + + // Check remaining entries. + s = NewBlockQueueStore() + tx, err = db.Begin(false) + require.NoError(t, err) + iter := s.ListEntries(tx) + var i int + for iter.Next() { + if i%4 == 0 { + // Skip deleted entries. + i++ + } + assert.Less(t, i, len(entries)) + assert.Equal(t, entries[i], iter.At()) + i++ + } + assert.Nil(t, iter.Err()) + assert.Nil(t, iter.Close()) + require.NoError(t, tx.Rollback()) +} diff --git a/pkg/metastore/compaction/scheduler/metrics.go b/pkg/metastore/compaction/scheduler/metrics.go new file mode 100644 index 0000000000..163acc2fef --- /dev/null +++ b/pkg/metastore/compaction/scheduler/metrics.go @@ -0,0 +1,137 @@ +package scheduler + +import ( + "strconv" + + "github.com/prometheus/client_golang/prometheus" +) + +type statsCollector struct { + s *Scheduler + + addedTotal *prometheus.Desc + completedTotal *prometheus.Desc + assignedTotal *prometheus.Desc + reassignedTotal *prometheus.Desc + evictedTotal *prometheus.Desc + + // Gauge showing the job queue status breakdown. + jobs *prometheus.Desc +} + +const schedulerQueueMetricsPrefix = "compaction_scheduler_queue_" + +func newStatsCollector(s *Scheduler) *statsCollector { + variableLabels := []string{"level"} + statusGaugeLabels := append(variableLabels, "status") + return &statsCollector{ + s: s, + + jobs: prometheus.NewDesc( + schedulerQueueMetricsPrefix+"jobs", + "The total number of jobs in the queue.", + statusGaugeLabels, nil, + ), + + addedTotal: prometheus.NewDesc( + schedulerQueueMetricsPrefix+"added_jobs_total", + "The total number of jobs added to the queue.", + variableLabels, nil, + ), + completedTotal: prometheus.NewDesc( + schedulerQueueMetricsPrefix+"completed_jobs_total", + "The total number of jobs completed.", + variableLabels, nil, + ), + assignedTotal: prometheus.NewDesc( + schedulerQueueMetricsPrefix+"assigned_jobs_total", + "The total number of jobs assigned.", + variableLabels, nil, + ), + reassignedTotal: prometheus.NewDesc( + schedulerQueueMetricsPrefix+"reassigned_jobs_total", + "The total number of jobs reassigned.", + variableLabels, nil, + ), + evictedTotal: prometheus.NewDesc( + schedulerQueueMetricsPrefix+"evicted_jobs_total", + "The total number of jobs evicted.", + variableLabels, nil, + ), + } +} + +func (c *statsCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- c.jobs + ch <- c.addedTotal + ch <- c.completedTotal + ch <- c.assignedTotal + ch <- c.reassignedTotal + ch <- c.evictedTotal +} + +func (c *statsCollector) Collect(ch chan<- prometheus.Metric) { + for _, m := range c.collectMetrics() { + ch <- m + } +} + +func (c *statsCollector) collectStats(fn func(level int, stats queueStats)) { + for i, q := range c.s.queue.levels { + // Note that some levels may be empty. + if q == nil || q.jobs == nil { + continue + } + var stats queueStats + for _, e := range *q.jobs { + switch { + case e.Status == 0: + stats.unassigned++ + case c.s.config.MaxFailures > 0 && uint64(e.Failures) >= c.s.config.MaxFailures: + stats.failed++ + case e.Failures > 0: + stats.reassigned++ + default: + stats.assigned++ + } + } + + // Update stored gauges. Those are not used at the moment, + // but can help planning schedule updates in the future. + q.stats.assigned = stats.assigned + q.stats.unassigned = stats.unassigned + q.stats.reassigned = stats.reassigned + q.stats.failed = stats.failed + + // Counters are updated on access. + stats.addedTotal = q.stats.addedTotal + stats.completedTotal = q.stats.completedTotal + stats.assignedTotal = q.stats.assignedTotal + stats.reassignedTotal = q.stats.reassignedTotal + stats.evictedTotal = q.stats.evictedTotal + + fn(i, stats) + } +} + +func (c *statsCollector) collectMetrics() []prometheus.Metric { + c.s.mu.Lock() + defer c.s.mu.Unlock() + + var metrics = make([]prometheus.Metric, 0, 8*len(c.s.queue.levels)) + c.collectStats(func(l int, stats queueStats) { + level := strconv.Itoa(l) + metrics = append(metrics, + prometheus.MustNewConstMetric(c.jobs, prometheus.GaugeValue, float64(stats.assigned), level, "assigned"), + prometheus.MustNewConstMetric(c.jobs, prometheus.GaugeValue, float64(stats.unassigned), level, "unassigned"), + prometheus.MustNewConstMetric(c.jobs, prometheus.GaugeValue, float64(stats.reassigned), level, "reassigned"), + prometheus.MustNewConstMetric(c.jobs, prometheus.GaugeValue, float64(stats.failed), level, "failed"), + prometheus.MustNewConstMetric(c.addedTotal, prometheus.CounterValue, float64(stats.addedTotal), level), + prometheus.MustNewConstMetric(c.completedTotal, prometheus.CounterValue, float64(stats.completedTotal), level), + prometheus.MustNewConstMetric(c.assignedTotal, prometheus.CounterValue, float64(stats.assignedTotal), level), + prometheus.MustNewConstMetric(c.reassignedTotal, prometheus.CounterValue, float64(stats.reassignedTotal), level), + prometheus.MustNewConstMetric(c.evictedTotal, prometheus.CounterValue, float64(stats.evictedTotal), level), + ) + }) + return metrics +} diff --git a/pkg/metastore/compaction/scheduler/metrics_test.go b/pkg/metastore/compaction/scheduler/metrics_test.go new file mode 100644 index 0000000000..c173f940bc --- /dev/null +++ b/pkg/metastore/compaction/scheduler/metrics_test.go @@ -0,0 +1,113 @@ +package scheduler + +import ( + "bytes" + "os" + "sync" + "testing" + "time" + + "github.com/grafana/dskit/multierror" + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction/scheduler/store" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestCollectorRegistration(t *testing.T) { + reg := prometheus.NewRegistry() + config := Config{ + MaxFailures: 5, + LeaseDuration: 15 * time.Second, + } + + for i := 0; i < 2; i++ { + sc := NewScheduler(config, nil, reg) + sc.queue.put(&raft_log.CompactionJobState{Name: "a"}) + sc.queue.put(&raft_log.CompactionJobState{ + Name: "b", CompactionLevel: 1, Token: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + }) + sc.queue.delete("a") + } +} + +func TestCollectorCollect(t *testing.T) { + reg := prometheus.NewRegistry() + config := Config{ + MaxFailures: 5, + LeaseDuration: 15 * time.Second, + } + + sc := NewScheduler(config, nil, reg) + sc.queue.put(&raft_log.CompactionJobState{ + Name: "a", CompactionLevel: 0, Token: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + }) + sc.queue.put(&raft_log.CompactionJobState{ + Name: "b", CompactionLevel: 2, Token: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + }) + sc.queue.delete("a") + + buf, err := os.ReadFile("testdata/metrics.txt") + require.NoError(t, err) + assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewReader(buf))) +} + +func TestCollectorCollectRace(t *testing.T) { + reg := prometheus.NewRegistry() + config := Config{ + MaxFailures: 5, + LeaseDuration: 15 * time.Second, + } + + var wg sync.WaitGroup + wg.Add(2) + + db := test.BoltDB(t) + go func() { + defer wg.Done() + s := store.NewJobStore() + sc := NewScheduler(config, s, reg) + for i := 0; i < 100; i++ { + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + var merr multierror.MultiError + merr.Add(s.CreateBuckets(tx)) + merr.Add(sc.UpdateSchedule(tx, &raft_log.CompactionPlanUpdate{ + NewJobs: []*raft_log.NewCompactionJob{{ + State: &raft_log.CompactionJobState{Name: "a", CompactionLevel: 0, Token: 1}, + Plan: &raft_log.CompactionJobPlan{Name: "a", CompactionLevel: 0}, + }}, + })) + assigned, err := sc.NewSchedule(tx, &raft.Log{}).AssignJob() + require.NoError(t, err) + require.NotNil(t, assigned) + require.Equal(t, "a", assigned.State.Name) + merr.Add(sc.UpdateSchedule(tx, &raft_log.CompactionPlanUpdate{ + CompletedJobs: []*raft_log.CompletedCompactionJob{ + {State: &raft_log.CompactionJobState{Name: "a", CompactionLevel: 0, Token: 1}}, + }, + })) + return merr.Err() + })) + } + }() + + go func() { + defer wg.Done() + for i := 0; i < 1000; i++ { + _, err := testutil.GatherAndCount(reg) + require.NoError(t, err) + } + }() + + wg.Wait() +} diff --git a/pkg/metastore/compaction/scheduler/schedule.go b/pkg/metastore/compaction/scheduler/schedule.go new file mode 100644 index 0000000000..30ed1e437a --- /dev/null +++ b/pkg/metastore/compaction/scheduler/schedule.go @@ -0,0 +1,226 @@ +package scheduler + +import ( + "container/heap" + "slices" + "time" + + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" +) + +// schedule should be used to prepare the compaction plan update. +// The implementation must have no side effects or alter the +// Scheduler in any way. +type schedule struct { + tx *bbolt.Tx + now time.Time + token uint64 + // Read-only. + scheduler *Scheduler + // Uncommitted schedule updates. + updates map[string]*raft_log.CompactionJobState + added int + evicted int + // Modified copy of the job queue. + copied []priorityJobQueue +} + +func (p *schedule) AssignJob() (*raft_log.AssignedCompactionJob, error) { + p.scheduler.mu.Lock() + defer p.scheduler.mu.Unlock() + state := p.nextAssignment() + if state == nil { + return nil, nil + } + plan, err := p.scheduler.store.GetJobPlan(p.tx, state.Name) + if err != nil { + return nil, err + } + p.updates[state.Name] = state + assigned := &raft_log.AssignedCompactionJob{ + State: state, + Plan: plan, + } + return assigned, nil +} + +func (p *schedule) UpdateJob(status *raft_log.CompactionJobStatusUpdate) *raft_log.CompactionJobState { + p.scheduler.mu.Lock() + defer p.scheduler.mu.Unlock() + state := p.newStateForStatusReport(status) + if state == nil { + return nil + } + // State changes should be taken into account when we assign jobs. + p.updates[status.Name] = state + return state +} + +// handleStatusReport reports the job state change caused by the status report +// from compaction worker. The function does not modify the actual job queue. +func (p *schedule) newStateForStatusReport(status *raft_log.CompactionJobStatusUpdate) *raft_log.CompactionJobState { + state := p.scheduler.queue.jobs[status.Name] + if state == nil { + // This may happen if the job has been reassigned + // and completed by another worker; we respond in + // the same way. + return nil + } + + if state.Token > status.Token { + // The job is not assigned to this worker. + return nil + } + + switch newState := state.CloneVT(); status.Status { + case metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS: + // A regular lease renewal. + newState.LeaseExpiresAt = p.allocateLease() + return newState + + case metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS: + newState.Status = status.Status + return newState + + default: + // Not allowed and unknown status updates can be safely ignored: + // eventually, the job will be reassigned. The same for status + // handlers: a nil state is returned, which is interpreted as + // "no new lease, stop the work". + } + + return nil +} + +func (p *schedule) EvictJob() *raft_log.CompactionJobState { + p.scheduler.mu.Lock() + defer p.scheduler.mu.Unlock() + limit := p.scheduler.config.MaxQueueSize + size := uint64(p.scheduler.queue.size() - p.evicted) + if limit == 0 || size <= limit { + return nil + } + for level := 0; level < len(p.scheduler.queue.levels); level++ { + // We evict the job from our copy of the queue: each job is only + // accessible once. + pq := p.queueLevelCopy(level) + if pq.Len() != 0 { + job := heap.Pop(pq).(*jobEntry) + if p.isFailed(job) { + p.evicted++ + return job.CompactionJobState + } + heap.Push(pq, job) + } + } + return nil +} + +// AddJob creates a state for the newly planned job. +// +// The method must be called after the last AssignJob and UpdateJob calls. +// It returns an empty state if the queue size limit is reached. +func (p *schedule) AddJob(plan *raft_log.CompactionJobPlan) *raft_log.CompactionJobState { + p.scheduler.mu.Lock() + defer p.scheduler.mu.Unlock() + if limit := p.scheduler.config.MaxQueueSize; limit > 0 { + if size := uint64(p.added + p.scheduler.queue.size()); size >= limit { + return nil + } + } + state := &raft_log.CompactionJobState{ + Name: plan.Name, + CompactionLevel: plan.CompactionLevel, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + AddedAt: p.now.UnixNano(), + Token: p.token, + } + p.updates[state.Name] = state + p.added++ + return state +} + +func (p *schedule) nextAssignment() *raft_log.CompactionJobState { + // We don't need to check the job ownership here: the worker asks + // for a job assigment (new ownership). + for level := 0; level < len(p.scheduler.queue.levels); { + // We evict the job from our copy of the queue: each job is only + // accessible once. When we reach the bottom of the queue (the first + // failed job, or the last job in the queue), we move to the next + // level. Note that we check all in-progress jobs if there are not + // enough unassigned jobs in the queue. + pq := p.queueLevelCopy(level) + if pq.Len() == 0 { + level++ + continue + } + + job := heap.Pop(pq).(*jobEntry) + if _, found := p.updates[job.Name]; found { + // We don't even consider own jobs: these are already + // assigned and are in-progress or have been completed. + // This, however, does not prevent from reassigning a + // job that the worker has abandoned in the past. + // Newly created jobs are not considered here as well. + continue + } + + switch job.Status { + case metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED: + return p.assignJob(job) + + case metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS: + if p.isFailed(job) { + // We reached the bottom of the queue: only failed jobs left. + heap.Push(pq, job) + level++ + continue + } + if p.isAbandoned(job) { + state := p.assignJob(job) + state.Failures++ + return state + } + } + } + + return nil +} + +func (p *schedule) allocateLease() int64 { + return p.now.Add(p.scheduler.config.LeaseDuration).UnixNano() +} + +func (p *schedule) assignJob(e *jobEntry) *raft_log.CompactionJobState { + job := e.CloneVT() + job.Status = metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS + job.LeaseExpiresAt = p.allocateLease() + job.Token = p.token + return job +} + +func (p *schedule) isAbandoned(job *jobEntry) bool { + return !p.isFailed(job) && p.now.UnixNano() > job.LeaseExpiresAt +} + +func (p *schedule) isFailed(job *jobEntry) bool { + limit := p.scheduler.config.MaxFailures + return limit > 0 && uint64(job.Failures) >= limit +} + +// The queue must not be modified by the assigner. Therefore, we're copying the +// queue levels lazily. The queue is supposed to be small (hundreds of jobs +// running concurrently); in the worst case, we have a ~24b alloc per entry. +func (p *schedule) queueLevelCopy(i int) *priorityJobQueue { + s := i + 1 // Levels are 0-based. + if s > len(p.copied) { + p.copied = slices.Grow(p.copied, s)[:s] + if p.copied[i] == nil { + p.copied[i] = p.scheduler.queue.level(uint32(i)).clone() + } + } + return &p.copied[i] +} diff --git a/pkg/metastore/compaction/scheduler/schedule_test.go b/pkg/metastore/compaction/scheduler/schedule_test.go new file mode 100644 index 0000000000..46f184b8aa --- /dev/null +++ b/pkg/metastore/compaction/scheduler/schedule_test.go @@ -0,0 +1,505 @@ +package scheduler + +import ( + "testing" + "time" + + "github.com/hashicorp/raft" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockscheduler" +) + +func TestSchedule_Update_LeaseRenewal(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + scheduler.queue.put(&raft_log.CompactionJobState{ + Name: "1", + CompactionLevel: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + Token: 1, + LeaseExpiresAt: 0, + }) + + t.Run("Owner", test.AssertIdempotentSubtest(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 0)}) + update := s.UpdateJob(&raft_log.CompactionJobStatusUpdate{ + Name: "1", + Token: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + }) + assert.Equal(t, &raft_log.CompactionJobState{ + Name: "1", + CompactionLevel: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + Token: 1, + LeaseExpiresAt: int64(config.LeaseDuration), + }, update) + })) + + t.Run("NotOwner", test.AssertIdempotentSubtest(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 0)}) + assert.Nil(t, s.UpdateJob(&raft_log.CompactionJobStatusUpdate{ + Name: "1", + Token: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + })) + })) + + t.Run("JobCompleted", test.AssertIdempotentSubtest(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 0)}) + assert.Nil(t, s.UpdateJob(&raft_log.CompactionJobStatusUpdate{ + Name: "0", + Token: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + })) + })) + + t.Run("WrongStatus", test.AssertIdempotentSubtest(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 0)}) + assert.Nil(t, s.UpdateJob(&raft_log.CompactionJobStatusUpdate{ + Name: "1", + Token: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + })) + })) +} + +func TestSchedule_Update_JobCompleted(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + scheduler.queue.put(&raft_log.CompactionJobState{ + Name: "1", + CompactionLevel: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + Token: 1, + }) + + t.Run("Owner", test.AssertIdempotentSubtest(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 0)}) + update := s.UpdateJob(&raft_log.CompactionJobStatusUpdate{ + Name: "1", + Token: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS, + }) + assert.Equal(t, &raft_log.CompactionJobState{ + Name: "1", + CompactionLevel: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS, + Token: 1, + }, update) + })) + + t.Run("NotOwner", test.AssertIdempotentSubtest(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 0)}) + assert.Nil(t, s.UpdateJob(&raft_log.CompactionJobStatusUpdate{ + Name: "1", + Token: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS, + })) + })) +} + +func TestSchedule_Assign(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + // The job plans are accessed when it's getting assigned. + // Their content is not important for the test. + plans := []*raft_log.CompactionJobPlan{ + {Name: "2", CompactionLevel: 0}, + {Name: "3", CompactionLevel: 0}, + {Name: "1", CompactionLevel: 1}, + } + for _, p := range plans { + store.On("GetJobPlan", mock.Anything, p.Name).Return(p, nil) + } + + states := []*raft_log.CompactionJobState{ + {Name: "1", CompactionLevel: 1, Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED}, + {Name: "2", CompactionLevel: 0, Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED}, + {Name: "3", CompactionLevel: 0, Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED}, + {Name: "4", CompactionLevel: 0, Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS}, + {Name: "5", CompactionLevel: 0, Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS}, + } + for _, s := range states { + scheduler.queue.put(s) + } + + test.AssertIdempotent(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 0)}) + for j := range plans { + update, err := s.AssignJob() + require.NoError(t, err) + assert.Equal(t, plans[j], update.Plan) + assert.Equal(t, metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, update.State.Status) + assert.Equal(t, int64(config.LeaseDuration), update.State.LeaseExpiresAt) + assert.Equal(t, uint64(1), update.State.Token) + } + + update, err := s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + }) +} + +func TestSchedule_ReAssign(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + plans := []*raft_log.CompactionJobPlan{ + {Name: "1"}, + {Name: "2"}, + {Name: "3"}, + {Name: "4"}, + {Name: "5"}, + {Name: "6"}, + } + for _, p := range plans { + store.On("GetJobPlan", mock.Anything, p.Name).Return(p, nil) + } + + now := int64(5) + states := []*raft_log.CompactionJobState{ + // Jobs with expired leases (now > LeaseExpiresAt). + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 1}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 1}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 1}, + // This job can't be reassigned as its lease is still valid. + {Name: "4", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 10}, + // The job has already failed in the past. + {Name: "5", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 1, Failures: 1}, + // The job has already failed in the past and exceeded the error threshold. + {Name: "6", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 1, Failures: 3}, + } + for _, s := range states { + scheduler.queue.put(s) + } + + lease := now + int64(config.LeaseDuration) + expected := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 2, LeaseExpiresAt: lease, Failures: 1}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 2, LeaseExpiresAt: lease, Failures: 1}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 2, LeaseExpiresAt: lease, Failures: 1}, + {Name: "5", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 2, LeaseExpiresAt: lease, Failures: 2}, + } + + test.AssertIdempotent(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, now)}) + assigned := make([]*raft_log.CompactionJobState, 0, len(expected)) + for { + update, err := s.AssignJob() + require.NoError(t, err) + if update == nil { + break + } + assigned = append(assigned, update.State) + } + + assert.Equal(t, expected, assigned) + }) +} + +func TestSchedule_UpdateAssign(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + plans := []*raft_log.CompactionJobPlan{ + {Name: "1"}, + {Name: "2"}, + {Name: "3"}, + } + for _, p := range plans { + store.On("GetJobPlan", mock.Anything, p.Name).Return(p, nil) + } + + states := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0}, + } + for _, s := range states { + scheduler.queue.put(s) + } + + // Lease is extended without reassignment if update arrives after the + // expiration, but this is the first worker requested assignment. + test.AssertIdempotent(t, func(t *testing.T) { + updates := []*raft_log.CompactionJobStatusUpdate{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1}, + } + + updatedAt := time.Second * 20 + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, int64(updatedAt))}) + for i := range updates { + update := s.UpdateJob(updates[i]) + assert.Equal(t, metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, update.Status) + assert.Equal(t, int64(updatedAt)+int64(config.LeaseDuration), update.LeaseExpiresAt) + assert.Equal(t, uint64(1), update.Token) // Token must not change. + } + + update, err := s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + }) + + // If the worker reports success status and its lease has expired but the + // job has not been reassigned, we accept the results. + test.AssertIdempotent(t, func(t *testing.T) { + updates := []*raft_log.CompactionJobStatusUpdate{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS, Token: 1}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS, Token: 1}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS, Token: 1}, + } + + updatedAt := time.Second * 20 + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, int64(updatedAt))}) + for i := range updates { + assert.NotNil(t, s.UpdateJob(updates[i])) + } + + update, err := s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + }) + + // The worker may be reassigned with the jobs it abandoned, + // if it requested assignments first. + test.AssertIdempotent(t, func(t *testing.T) { + updatedAt := time.Second * 20 + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, int64(updatedAt))}) + for range plans { + update, err := s.AssignJob() + require.NoError(t, err) + assert.NotNil(t, update.State) + assert.NotNil(t, update.Plan) + assert.Equal(t, int64(updatedAt)+int64(config.LeaseDuration), update.State.LeaseExpiresAt) + assert.Equal(t, uint64(2), update.State.Token) // Token must change. + } + + update, err := s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + }) +} + +func TestSchedule_Add(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + plans := []*raft_log.CompactionJobPlan{ + {Name: "1"}, + {Name: "2"}, + {Name: "3"}, + } + + states := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, AddedAt: 1, Token: 1}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, AddedAt: 1, Token: 1}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, AddedAt: 1, Token: 1}, + } + + test.AssertIdempotent(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 1)}) + for i := range plans { + assert.Equal(t, states[i], s.AddJob(plans[i])) + } + }) +} + +func TestSchedule_QueueSizeLimit(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxQueueSize: 2, + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + plans := []*raft_log.CompactionJobPlan{ + {Name: "1"}, + {Name: "2"}, + {Name: "3"}, + } + + states := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, AddedAt: 1, Token: 1}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, AddedAt: 1, Token: 1}, + } + + test.AssertIdempotent(t, func(t *testing.T) { + s := scheduler.NewSchedule(nil, &raft.Log{Index: 1, AppendedAt: time.Unix(0, 1)}) + assert.Equal(t, states[0], s.AddJob(plans[0])) + assert.Equal(t, states[1], s.AddJob(plans[1])) + assert.Nil(t, s.AddJob(plans[2])) + }) +} + +func TestSchedule_AssignEvict(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxQueueSize: 2, + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + plans := []*raft_log.CompactionJobPlan{ + {Name: "4"}, + } + for _, p := range plans { + store.On("GetJobPlan", mock.Anything, p.Name).Return(p, nil) + } + + states := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "4", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 0}, + } + for _, s := range states { + scheduler.queue.put(s) + } + + test.AssertIdempotent(t, func(t *testing.T) { + updatedAt := time.Second * 20 + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, int64(updatedAt))}) + // Eviction is only possible when no jobs are available for assignment. + assert.Nil(t, s.EvictJob()) + // Assign all the available jobs. + update, err := s.AssignJob() + require.NoError(t, err) + assert.Equal(t, "4", update.State.Name) + update, err = s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + // Now that no jobs can be assigned, we can try eviction. + assert.NotNil(t, s.EvictJob()) + assert.NotNil(t, s.EvictJob()) + // MaxQueueSize reached. + assert.Nil(t, s.EvictJob()) + }) +} + +func TestSchedule_Evict(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxQueueSize: 2, + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + states := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + } + for _, s := range states { + scheduler.queue.put(s) + } + + test.AssertIdempotent(t, func(t *testing.T) { + updatedAt := time.Second * 20 + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, int64(updatedAt))}) + // Eviction is only possible when no jobs are available for assignment. + update, err := s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + assert.NotNil(t, s.EvictJob()) + assert.Nil(t, s.EvictJob()) + }) +} + +func TestSchedule_NoEvict(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxQueueSize: 5, + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + states := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + } + for _, s := range states { + scheduler.queue.put(s) + } + + test.AssertIdempotent(t, func(t *testing.T) { + updatedAt := time.Second * 20 + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, int64(updatedAt))}) + // Eviction is only possible when no jobs are available for assignment. + update, err := s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + // Eviction is only possible when the queue size limit is reached. + assert.Nil(t, s.EvictJob()) + }) +} + +func TestSchedule_NoEvictNoQueueSizeLimit(t *testing.T) { + store := new(mockscheduler.MockJobStore) + config := Config{ + MaxQueueSize: 0, + MaxFailures: 3, + LeaseDuration: 10 * time.Second, + } + + scheduler := NewScheduler(config, store, nil) + states := []*raft_log.CompactionJobState{ + {Name: "1", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "2", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + {Name: "3", Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, Token: 1, LeaseExpiresAt: 0, Failures: 3}, + } + for _, s := range states { + scheduler.queue.put(s) + } + + test.AssertIdempotent(t, func(t *testing.T) { + updatedAt := time.Second * 20 + s := scheduler.NewSchedule(nil, &raft.Log{Index: 2, AppendedAt: time.Unix(0, int64(updatedAt))}) + // Eviction is only possible when no jobs are available for assignment. + update, err := s.AssignJob() + require.NoError(t, err) + assert.Nil(t, update) + // Eviction is not possible if the queue size limit is not set. + assert.Nil(t, s.EvictJob()) + }) +} diff --git a/pkg/metastore/compaction/scheduler/scheduler.go b/pkg/metastore/compaction/scheduler/scheduler.go new file mode 100644 index 0000000000..5cd2f26de2 --- /dev/null +++ b/pkg/metastore/compaction/scheduler/scheduler.go @@ -0,0 +1,166 @@ +package scheduler + +import ( + "flag" + "sync" + "time" + + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" + "go.etcd.io/bbolt" + + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction/scheduler/store" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +var _ compaction.Scheduler = (*Scheduler)(nil) + +// Compaction job scheduler. Jobs are prioritized by the compaction level, and +// the deadline time. +// +// Compaction workers own jobs while they are in progress. Ownership handling is +// implemented using lease deadlines and fencing tokens: +// https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html + +// JobStore does not really store jobs as they are: it explicitly +// distinguishes between the job and the job state. +// +// Implementation note: block metadata should never be stored in StoreJob: +// those are already stored in the metadata index. +type JobStore interface { + StoreJobPlan(*bbolt.Tx, *raft_log.CompactionJobPlan) error + GetJobPlan(tx *bbolt.Tx, name string) (*raft_log.CompactionJobPlan, error) + DeleteJobPlan(tx *bbolt.Tx, name string) error + + StoreJobState(*bbolt.Tx, *raft_log.CompactionJobState) error + DeleteJobState(tx *bbolt.Tx, name string) error + ListEntries(*bbolt.Tx) iter.Iterator[*raft_log.CompactionJobState] + + CreateBuckets(*bbolt.Tx) error +} + +type Config struct { + MaxFailures uint64 `yaml:"compaction_max_failures" category:"advanced" doc:""` + LeaseDuration time.Duration `yaml:"compaction_job_lease_duration" category:"advanced" doc:""` + MaxQueueSize uint64 `yaml:"compaction_max_job_queue_size" category:"advanced" doc:""` +} + +func (c *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.Uint64Var(&c.MaxFailures, prefix+"compaction-max-failures", 3, "") + f.DurationVar(&c.LeaseDuration, prefix+"compaction-job-lease-duration", 15*time.Second, "") + f.Uint64Var(&c.MaxQueueSize, prefix+"compaction-max-job-queue-size", 10000, "") +} + +type Scheduler struct { + config Config + store JobStore + // Although the job queue is only accessed synchronously, + // the mutex is needed to collect stats. + mu sync.Mutex + queue *schedulerQueue +} + +// NewScheduler creates a scheduler with the given lease duration. +// Typically, callers should update jobs at the interval not exceeding +// the half of the lease duration. +func NewScheduler(config Config, store JobStore, reg prometheus.Registerer) *Scheduler { + s := &Scheduler{ + config: config, + store: store, + queue: newJobQueue(), + } + collector := newStatsCollector(s) + util.RegisterOrGet(reg, collector) + return s +} + +func NewStore() *store.JobStore { + return store.NewJobStore() +} + +func (sc *Scheduler) NewSchedule(tx *bbolt.Tx, cmd *raft.Log) compaction.Schedule { + return &schedule{ + tx: tx, + token: cmd.Index, + now: cmd.AppendedAt, + scheduler: sc, + updates: make(map[string]*raft_log.CompactionJobState), + } +} + +func (sc *Scheduler) UpdateSchedule(tx *bbolt.Tx, update *raft_log.CompactionPlanUpdate) error { + sc.mu.Lock() + defer sc.mu.Unlock() + + for _, job := range update.EvictedJobs { + name := job.State.Name + if err := sc.store.DeleteJobPlan(tx, name); err != nil { + return err + } + if err := sc.store.DeleteJobState(tx, name); err != nil { + return err + } + sc.queue.evict(name) + } + + for _, job := range update.NewJobs { + if err := sc.store.StoreJobPlan(tx, job.Plan); err != nil { + return err + } + if err := sc.store.StoreJobState(tx, job.State); err != nil { + return err + } + sc.queue.put(job.State) + } + + for _, job := range update.UpdatedJobs { + if err := sc.store.StoreJobState(tx, job.State); err != nil { + return err + } + sc.queue.put(job.State) + } + + for _, job := range update.AssignedJobs { + if err := sc.store.StoreJobState(tx, job.State); err != nil { + return err + } + sc.queue.put(job.State) + } + + for _, job := range update.CompletedJobs { + name := job.State.Name + if err := sc.store.DeleteJobPlan(tx, name); err != nil { + return err + } + if err := sc.store.DeleteJobState(tx, name); err != nil { + return err + } + sc.queue.delete(name) + } + + return nil +} + +func (sc *Scheduler) Init(tx *bbolt.Tx) error { + return sc.store.CreateBuckets(tx) +} + +func (sc *Scheduler) Restore(tx *bbolt.Tx) error { + sc.mu.Lock() + defer sc.mu.Unlock() + // Reset in-memory state before loading entries from the store. + sc.queue.reset() + entries := sc.store.ListEntries(tx) + defer func() { + _ = entries.Close() + }() + for entries.Next() { + sc.queue.put(entries.At()) + } + // Zero all stats updated during Restore. + sc.queue.resetStats() + return entries.Err() +} diff --git a/pkg/metastore/compaction/scheduler/scheduler_queue.go b/pkg/metastore/compaction/scheduler/scheduler_queue.go new file mode 100644 index 0000000000..7f5c58d5bd --- /dev/null +++ b/pkg/metastore/compaction/scheduler/scheduler_queue.go @@ -0,0 +1,210 @@ +package scheduler + +import ( + "container/heap" + "slices" + "strings" + + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" +) + +type schedulerQueue struct { + jobs map[string]*jobEntry + // Sparse array of job queues, indexed by compaction level. + levels []*jobQueue +} + +func newJobQueue() *schedulerQueue { + return &schedulerQueue{ + jobs: make(map[string]*jobEntry), + } +} + +func (q *schedulerQueue) reset() { + clear(q.jobs) + clear(q.levels) + q.levels = q.levels[:0] +} + +func (q *schedulerQueue) put(state *raft_log.CompactionJobState) { + job, exists := q.jobs[state.Name] + level := q.level(state.CompactionLevel) + if exists { + level.update(job, state) + return + } + e := &jobEntry{CompactionJobState: state} + q.jobs[state.Name] = e + level.add(e) +} + +func (q *schedulerQueue) delete(name string) *raft_log.CompactionJobState { + if e, exists := q.jobs[name]; exists { + delete(q.jobs, name) + level := q.level(e.CompactionLevel) + level.delete(e) + level.stats.completedTotal++ + return e.CompactionJobState + } + return nil +} + +// evict is identical to delete, but it updates the eviction stats. +func (q *schedulerQueue) evict(name string) { + if e, exists := q.jobs[name]; exists { + delete(q.jobs, name) + level := q.level(e.CompactionLevel) + level.delete(e) + level.stats.evictedTotal++ + } +} + +func (q *schedulerQueue) size() int { + var size int + for _, level := range q.levels { + if level != nil { + size += level.jobs.Len() + } + } + return size +} + +func (q *schedulerQueue) level(x uint32) *jobQueue { + s := x + 1 // Levels are 0-based. + if s >= uint32(len(q.levels)) { + q.levels = slices.Grow(q.levels, int(s))[:s] + } + level := q.levels[x] + if level == nil { + level = &jobQueue{ + jobs: new(priorityJobQueue), + stats: new(queueStats), + } + q.levels[x] = level + } + return level +} + +func (q *schedulerQueue) resetStats() { + for _, level := range q.levels { + if level != nil { + level.stats.reset() + } + } +} + +type jobQueue struct { + jobs *priorityJobQueue + stats *queueStats +} + +type queueStats struct { + // Counters. Updated on access. + addedTotal uint32 + completedTotal uint32 + assignedTotal uint32 + reassignedTotal uint32 + evictedTotal uint32 + // Gauges. Updated periodically. + assigned uint32 + unassigned uint32 + reassigned uint32 + failed uint32 +} + +func (s *queueStats) reset() { + *s = queueStats{} +} + +type jobEntry struct { + index int // The index of the job in the heap. + *raft_log.CompactionJobState +} + +func (q *jobQueue) add(e *jobEntry) { + q.stats.addedTotal++ + heap.Push(q.jobs, e) +} + +func (q *jobQueue) update(e *jobEntry, state *raft_log.CompactionJobState) { + if e.Status == 0 && state.Status != 0 { + // Job given a status. + q.stats.assignedTotal++ + } + if e.Status != 0 && e.Token != state.Token { + // Token change. + q.stats.reassignedTotal++ + } + e.CompactionJobState = state + heap.Fix(q.jobs, e.index) +} + +func (q *jobQueue) delete(e *jobEntry) { + heap.Remove(q.jobs, e.index) +} + +func (q *jobQueue) clone() priorityJobQueue { + c := make(priorityJobQueue, q.jobs.Len()) + for j, job := range *q.jobs { + jobCopy := *job + c[j] = &jobCopy + } + return c +} + +// The function determines the scheduling order of the jobs. +func compareJobs(a, b *jobEntry) int { + // Pick jobs in the "initial" (unspecified) state first. + if a.Status != b.Status { + return int(a.Status) - int(b.Status) + } + // Faulty jobs should wait. Our aim is to put them at the + // end of the queue, after all the jobs we may consider + // for assigment. + if a.Failures != b.Failures { + return int(a.Failures) - int(b.Failures) + } + // Jobs with earlier deadlines should go first. + // A job that has been just added has no lease + // and will always go first. + if a.LeaseExpiresAt != b.LeaseExpiresAt { + return int(a.LeaseExpiresAt) - int(b.LeaseExpiresAt) + } + // Tiebreaker: the job name must not bias the order. + return strings.Compare(a.Name, b.Name) +} + +// TODO(kolesnikovae): container/heap is not very efficient, +// consider implementing own heap, specific to the case. +// A treap might be suitable as well. + +type priorityJobQueue []*jobEntry + +func (pq priorityJobQueue) Len() int { return len(pq) } + +func (pq priorityJobQueue) Less(i, j int) bool { + return compareJobs(pq[i], pq[j]) < 0 +} + +func (pq priorityJobQueue) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] + pq[i].index = i + pq[j].index = j +} + +func (pq *priorityJobQueue) Push(x interface{}) { + n := len(*pq) + job := x.(*jobEntry) + job.index = n + *pq = append(*pq, job) +} + +func (pq *priorityJobQueue) Pop() interface{} { + old := *pq + n := len(old) + job := old[n-1] + old[n-1] = nil + job.index = -1 + *pq = old[0 : n-1] + return job +} diff --git a/pkg/metastore/compaction/scheduler/scheduler_queue_test.go b/pkg/metastore/compaction/scheduler/scheduler_queue_test.go new file mode 100644 index 0000000000..09fae32f70 --- /dev/null +++ b/pkg/metastore/compaction/scheduler/scheduler_queue_test.go @@ -0,0 +1,151 @@ +package scheduler + +import ( + "container/heap" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" +) + +func TestJobQueue_order(t *testing.T) { + items := []*raft_log.CompactionJobState{ + { + Name: "job-6", + CompactionLevel: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + LeaseExpiresAt: 5, + Failures: 0, + }, + { + Name: "job-0", + CompactionLevel: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + LeaseExpiresAt: 2, + Failures: 0, + }, + { + Name: "job-1", + CompactionLevel: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + LeaseExpiresAt: 2, + Failures: 0, + }, + { + Name: "job-2", + CompactionLevel: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + LeaseExpiresAt: 2, + Failures: 0, + }, + { + Name: "job-5", + CompactionLevel: 1, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_UNSPECIFIED, + LeaseExpiresAt: 3, + Failures: 0, + }, + { + Name: "job-3", + CompactionLevel: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + LeaseExpiresAt: 2, + Failures: 5, + }, + { + Name: "job-4", + CompactionLevel: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + LeaseExpiresAt: 1, + Failures: 5, + }, + } + + test := func(items []*raft_log.CompactionJobState) { + q := newJobQueue() + for _, item := range items { + q.put(item) + } + + j3 := q.delete("job-1") + j1 := q.delete("job-3") + jx := q.delete("job-x") + assert.Nil(t, jx) + + q.put(j1) + q.put(j3) + q.put(j3) + q.put(j1) + + q.put(&raft_log.CompactionJobState{ + Name: "job-4", + CompactionLevel: 0, + Status: metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS, + LeaseExpiresAt: 3, // Should be after job-3. + Failures: 5, + }) + + expected := []string{"job-6", "job-2", "job-3", "job-4", "job-0", "job-1", "job-5"} + dequeued := make([]string, 0, len(items)) + for range items { + x := jobQueuePop(q) + assert.NotNil(t, x) + dequeued = append(dequeued, x.Name) + } + assert.Equal(t, expected, dequeued) + assert.Nil(t, jobQueuePop(q)) + } + + rnd := rand.New(rand.NewSource(123)) + for i := 0; i < 25; i++ { + rnd.Shuffle(len(items), func(i, j int) { + items[i], items[j] = items[j], items[i] + }) + test(items) + } +} + +func TestJobQueue_delete(t *testing.T) { + q := newJobQueue() + items := []*raft_log.CompactionJobState{ + {Name: "job-1"}, + {Name: "job-2"}, + {Name: "job-3"}, + {Name: "job-4"}, + } + + for _, item := range items { + q.put(item) + } + + for _, item := range items { + q.delete(item.Name) + } + + assert.Nil(t, jobQueuePop(q)) +} + +func TestJobQueue_empty(t *testing.T) { + q := newJobQueue() + q.delete("job-1") + assert.Nil(t, jobQueuePop(q)) + q.put(&raft_log.CompactionJobState{Name: "job-1"}) + q.delete("job-1") + assert.Nil(t, jobQueuePop(q)) +} + +// The function is for testing purposes only. +func jobQueuePop(q *schedulerQueue) *raft_log.CompactionJobState { + for i := range q.levels { + level := q.level(uint32(i)) + if level.jobs.Len() > 0 { + x := heap.Pop(level.jobs).(*jobEntry).CompactionJobState + delete(q.jobs, x.Name) + return x + } + } + return nil +} diff --git a/pkg/metastore/compaction/scheduler/scheduler_test.go b/pkg/metastore/compaction/scheduler/scheduler_test.go new file mode 100644 index 0000000000..25b1e81638 --- /dev/null +++ b/pkg/metastore/compaction/scheduler/scheduler_test.go @@ -0,0 +1,111 @@ +package scheduler + +import ( + "testing" + + "github.com/hashicorp/raft" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockscheduler" +) + +func TestScheduler_UpdateSchedule(t *testing.T) { + store := new(mockscheduler.MockJobStore) + store.On("StoreJobPlan", mock.Anything, &raft_log.CompactionJobPlan{Name: "1"}).Return(nil).Once() + store.On("StoreJobState", mock.Anything, &raft_log.CompactionJobState{Name: "1"}).Return(nil).Once() + store.On("StoreJobState", mock.Anything, &raft_log.CompactionJobState{Name: "2"}).Return(nil).Once() + store.On("DeleteJobPlan", mock.Anything, "3").Return(nil).Once() + store.On("DeleteJobPlan", mock.Anything, "4").Return(nil).Once() + store.On("DeleteJobState", mock.Anything, "3").Return(nil).Once() + store.On("DeleteJobState", mock.Anything, "4").Return(nil).Once() + + scheduler := NewScheduler(Config{}, store, nil) + for _, job := range []*raft_log.CompactionJobState{ + {Name: "1"}, + {Name: "2"}, + {Name: "3"}, + {Name: "4"}, + } { + scheduler.queue.put(job) + } + + update := &raft_log.CompactionPlanUpdate{ + NewJobs: []*raft_log.NewCompactionJob{{ + State: &raft_log.CompactionJobState{Name: "1"}, + Plan: &raft_log.CompactionJobPlan{Name: "1"}, + }}, + UpdatedJobs: []*raft_log.UpdatedCompactionJob{{ + State: &raft_log.CompactionJobState{Name: "2"}, + }}, + CompletedJobs: []*raft_log.CompletedCompactionJob{{ + State: &raft_log.CompactionJobState{Name: "3"}, + }}, + EvictedJobs: []*raft_log.EvictedCompactionJob{{ + State: &raft_log.CompactionJobState{Name: "4"}, + }}, + } + + require.NoError(t, scheduler.UpdateSchedule(nil, update)) + s := scheduler.NewSchedule(nil, &raft.Log{Index: 3}) + + store.On("GetJobPlan", mock.Anything, "1").Return(new(raft_log.CompactionJobPlan), nil).Once() + assigment, err := s.AssignJob() + require.NoError(t, err) + assert.NotNil(t, assigment) + + store.On("GetJobPlan", mock.Anything, "2").Return(new(raft_log.CompactionJobPlan), nil).Once() + assigment, err = s.AssignJob() + require.NoError(t, err) + assert.NotNil(t, assigment) + + assigment, err = s.AssignJob() + require.NoError(t, err) + assert.Nil(t, assigment) + + assert.Equal(t, jobQueuePop(scheduler.queue), update.NewJobs[0].State) + assert.Equal(t, jobQueuePop(scheduler.queue), update.UpdatedJobs[0].State) + assert.Nil(t, jobQueuePop(scheduler.queue)) + newStatsCollector(scheduler).collectStats(func(level int, stats queueStats) { + assert.Equal(t, 0, level) + assert.Equal(t, stats, queueStats{ + addedTotal: 4, + completedTotal: 1, + evictedTotal: 1, + }) + }) + + store.AssertExpectations(t) +} + +func TestScheduler_Restore(t *testing.T) { + store := new(mockscheduler.MockJobStore) + scheduler := NewScheduler(Config{}, store, nil) + + store.On("ListEntries", mock.Anything).Return(iter.NewSliceIterator([]*raft_log.CompactionJobState{ + {Name: "1", Token: 1}, + {Name: "2", Token: 1}, + })) + + require.NoError(t, scheduler.Restore(nil)) + s := scheduler.NewSchedule(nil, &raft.Log{Index: 3}) + + store.On("GetJobPlan", mock.Anything, "1").Return(new(raft_log.CompactionJobPlan), nil).Once() + assigment, err := s.AssignJob() + require.NoError(t, err) + assert.NotNil(t, assigment) + + store.On("GetJobPlan", mock.Anything, "2").Return(new(raft_log.CompactionJobPlan), nil).Once() + assigment, err = s.AssignJob() + require.NoError(t, err) + assert.NotNil(t, assigment) + + assigment, err = s.AssignJob() + require.NoError(t, err) + assert.Nil(t, assigment) + + store.AssertExpectations(t) +} diff --git a/pkg/metastore/compaction/scheduler/store/job_plan_store.go b/pkg/metastore/compaction/scheduler/store/job_plan_store.go new file mode 100644 index 0000000000..d934f89f2b --- /dev/null +++ b/pkg/metastore/compaction/scheduler/store/job_plan_store.go @@ -0,0 +1,47 @@ +package store + +import ( + "errors" + "fmt" + + "go.etcd.io/bbolt" + + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" +) + +var jobPlanBucketName = []byte("compaction_job_plan") + +var ErrInvalidJobPlan = errors.New("invalid job plan entry") + +type JobPlanStore struct{ bucketName []byte } + +func NewJobPlanStore() *JobPlanStore { + return &JobPlanStore{bucketName: jobPlanBucketName} +} + +func (s JobPlanStore) CreateBuckets(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists(s.bucketName) + return err +} + +func (s JobPlanStore) StoreJobPlan(tx *bbolt.Tx, plan *raft_log.CompactionJobPlan) error { + v, _ := plan.MarshalVT() + return tx.Bucket(s.bucketName).Put([]byte(plan.Name), v) +} + +func (s JobPlanStore) GetJobPlan(tx *bbolt.Tx, name string) (*raft_log.CompactionJobPlan, error) { + b := tx.Bucket(s.bucketName).Get([]byte(name)) + if b == nil { + return nil, fmt.Errorf("loading job plan %s: %w", name, store.ErrNotFound) + } + var v raft_log.CompactionJobPlan + if err := v.UnmarshalVT(b); err != nil { + return nil, fmt.Errorf("%w: %v", ErrInvalidJobPlan, err) + } + return &v, nil +} + +func (s JobPlanStore) DeleteJobPlan(tx *bbolt.Tx, name string) error { + return tx.Bucket(s.bucketName).Delete([]byte(name)) +} diff --git a/pkg/metastore/compaction/scheduler/store/job_plan_store_test.go b/pkg/metastore/compaction/scheduler/store/job_plan_store_test.go new file mode 100644 index 0000000000..0710f9bf1a --- /dev/null +++ b/pkg/metastore/compaction/scheduler/store/job_plan_store_test.go @@ -0,0 +1,46 @@ +package store + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestJobPlanStore(t *testing.T) { + db := test.BoltDB(t) + + s := NewJobStore() + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, s.CreateBuckets(tx)) + assert.NoError(t, s.StoreJobPlan(tx, &raft_log.CompactionJobPlan{Name: "1"})) + require.NoError(t, tx.Commit()) + + s = NewJobStore() + tx, err = db.Begin(false) + require.NoError(t, err) + state, err := s.GetJobPlan(tx, "2") + require.ErrorIs(t, err, store.ErrNotFound) + require.Nil(t, state) + state, err = s.GetJobPlan(tx, "1") + require.NoError(t, err) + assert.Equal(t, "1", state.Name) + require.NoError(t, tx.Rollback()) + + tx, err = db.Begin(true) + require.NoError(t, err) + require.NoError(t, s.DeleteJobPlan(tx, "1")) + require.NoError(t, tx.Commit()) + + tx, err = db.Begin(false) + require.NoError(t, err) + state, err = s.GetJobPlan(tx, "1") + require.ErrorIs(t, err, store.ErrNotFound) + require.Nil(t, state) + require.NoError(t, tx.Rollback()) +} diff --git a/pkg/metastore/compaction/scheduler/store/job_state_store.go b/pkg/metastore/compaction/scheduler/store/job_state_store.go new file mode 100644 index 0000000000..6efeea27a5 --- /dev/null +++ b/pkg/metastore/compaction/scheduler/store/job_state_store.go @@ -0,0 +1,88 @@ +package store + +import ( + "errors" + "fmt" + + "go.etcd.io/bbolt" + + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" +) + +var jobStateBucketName = []byte("compaction_job_state") + +var ErrInvalidJobState = errors.New("invalid job state entry") + +type JobStateStore struct{ bucketName []byte } + +func NewJobStateStore() *JobStateStore { + return &JobStateStore{bucketName: jobStateBucketName} +} + +func (s JobStateStore) CreateBuckets(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists(s.bucketName) + return err +} + +func (s JobStateStore) GetJobState(tx *bbolt.Tx, name string) (*raft_log.CompactionJobState, error) { + b := tx.Bucket(s.bucketName).Get([]byte(name)) + if b == nil { + return nil, fmt.Errorf("loading job state %s: %w", name, store.ErrNotFound) + } + var v raft_log.CompactionJobState + if err := v.UnmarshalVT(b); err != nil { + return nil, fmt.Errorf("%w: %v", ErrInvalidJobState, err) + } + return &v, nil +} + +func (s JobStateStore) StoreJobState(tx *bbolt.Tx, state *raft_log.CompactionJobState) error { + v, _ := state.MarshalVT() + return tx.Bucket(s.bucketName).Put([]byte(state.Name), v) +} + +func (s JobStateStore) DeleteJobState(tx *bbolt.Tx, name string) error { + return tx.Bucket(s.bucketName).Delete([]byte(name)) +} + +func (s JobStateStore) ListEntries(tx *bbolt.Tx) iter.Iterator[*raft_log.CompactionJobState] { + return newJobEntriesIterator(tx.Bucket(s.bucketName)) +} + +type jobEntriesIterator struct { + iter *store.CursorIterator + cur *raft_log.CompactionJobState + err error +} + +func newJobEntriesIterator(bucket *bbolt.Bucket) *jobEntriesIterator { + return &jobEntriesIterator{iter: store.NewCursorIter(bucket.Cursor())} +} + +func (x *jobEntriesIterator) Next() bool { + if x.err != nil || !x.iter.Next() { + return false + } + e := x.iter.At() + var s raft_log.CompactionJobState + x.err = s.UnmarshalVT(e.Value) + if x.err != nil { + x.err = fmt.Errorf("%w: %v", ErrInvalidJobState, x.err) + return false + } + x.cur = &s + return true +} + +func (x *jobEntriesIterator) At() *raft_log.CompactionJobState { return x.cur } + +func (x *jobEntriesIterator) Close() error { return x.iter.Close() } + +func (x *jobEntriesIterator) Err() error { + if err := x.iter.Err(); err != nil { + return err + } + return x.err +} diff --git a/pkg/metastore/compaction/scheduler/store/job_state_store_test.go b/pkg/metastore/compaction/scheduler/store/job_state_store_test.go new file mode 100644 index 0000000000..e1dacda765 --- /dev/null +++ b/pkg/metastore/compaction/scheduler/store/job_state_store_test.go @@ -0,0 +1,51 @@ +package store + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestJobStateStore(t *testing.T) { + db := test.BoltDB(t) + + s := NewJobStore() + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, s.CreateBuckets(tx)) + assert.NoError(t, s.StoreJobState(tx, &raft_log.CompactionJobState{Name: "1"})) + assert.NoError(t, s.StoreJobState(tx, &raft_log.CompactionJobState{Name: "2"})) + assert.NoError(t, s.StoreJobState(tx, &raft_log.CompactionJobState{Name: "3"})) + require.NoError(t, tx.Commit()) + + s = NewJobStore() + tx, err = db.Begin(true) + require.NoError(t, err) + state, err := s.GetJobState(tx, "2") + require.NoError(t, err) + assert.Equal(t, "2", state.Name) + require.NoError(t, s.DeleteJobState(tx, "2")) + state, err = s.GetJobState(tx, "2") + require.ErrorIs(t, err, store.ErrNotFound) + require.Nil(t, state) + require.NoError(t, tx.Commit()) + + tx, err = db.Begin(true) + require.NoError(t, err) + + iter := s.ListEntries(tx) + expected := []string{"1", "3"} + var i int + for iter.Next() { + assert.Equal(t, expected[i], iter.At().Name) + i++ + } + assert.Nil(t, iter.Err()) + assert.Nil(t, iter.Close()) + require.NoError(t, tx.Rollback()) +} diff --git a/pkg/metastore/compaction/scheduler/store/job_store.go b/pkg/metastore/compaction/scheduler/store/job_store.go new file mode 100644 index 0000000000..865b33a6b1 --- /dev/null +++ b/pkg/metastore/compaction/scheduler/store/job_store.go @@ -0,0 +1,27 @@ +package store + +import ( + "go.etcd.io/bbolt" +) + +type JobStore struct { + *JobStateStore + *JobPlanStore +} + +func NewJobStore() *JobStore { + return &JobStore{ + JobStateStore: NewJobStateStore(), + JobPlanStore: NewJobPlanStore(), + } +} + +func (s JobStore) CreateBuckets(tx *bbolt.Tx) error { + if err := s.JobStateStore.CreateBuckets(tx); err != nil { + return err + } + if err := s.JobPlanStore.CreateBuckets(tx); err != nil { + return err + } + return nil +} diff --git a/pkg/metastore/compaction/scheduler/testdata/metrics.txt b/pkg/metastore/compaction/scheduler/testdata/metrics.txt new file mode 100644 index 0000000000..eaa22e0996 --- /dev/null +++ b/pkg/metastore/compaction/scheduler/testdata/metrics.txt @@ -0,0 +1,30 @@ +# HELP compaction_scheduler_queue_added_jobs_total The total number of jobs added to the queue. +# TYPE compaction_scheduler_queue_added_jobs_total counter +compaction_scheduler_queue_added_jobs_total{level="0"} 1 +compaction_scheduler_queue_added_jobs_total{level="2"} 1 +# HELP compaction_scheduler_queue_assigned_jobs_total The total number of jobs assigned. +# TYPE compaction_scheduler_queue_assigned_jobs_total counter +compaction_scheduler_queue_assigned_jobs_total{level="0"} 0 +compaction_scheduler_queue_assigned_jobs_total{level="2"} 0 +# HELP compaction_scheduler_queue_completed_jobs_total The total number of jobs completed. +# TYPE compaction_scheduler_queue_completed_jobs_total counter +compaction_scheduler_queue_completed_jobs_total{level="0"} 1 +compaction_scheduler_queue_completed_jobs_total{level="2"} 0 +# HELP compaction_scheduler_queue_evicted_jobs_total The total number of jobs evicted. +# TYPE compaction_scheduler_queue_evicted_jobs_total counter +compaction_scheduler_queue_evicted_jobs_total{level="0"} 0 +compaction_scheduler_queue_evicted_jobs_total{level="2"} 0 +# HELP compaction_scheduler_queue_jobs The total number of jobs in the queue. +# TYPE compaction_scheduler_queue_jobs gauge +compaction_scheduler_queue_jobs{level="0",status="assigned"} 0 +compaction_scheduler_queue_jobs{level="0",status="failed"} 0 +compaction_scheduler_queue_jobs{level="0",status="reassigned"} 0 +compaction_scheduler_queue_jobs{level="0",status="unassigned"} 0 +compaction_scheduler_queue_jobs{level="2",status="assigned"} 0 +compaction_scheduler_queue_jobs{level="2",status="failed"} 0 +compaction_scheduler_queue_jobs{level="2",status="reassigned"} 0 +compaction_scheduler_queue_jobs{level="2",status="unassigned"} 1 +# HELP compaction_scheduler_queue_reassigned_jobs_total The total number of jobs reassigned. +# TYPE compaction_scheduler_queue_reassigned_jobs_total counter +compaction_scheduler_queue_reassigned_jobs_total{level="0"} 0 +compaction_scheduler_queue_reassigned_jobs_total{level="2"} 0 diff --git a/pkg/metastore/compaction_raft_handler.go b/pkg/metastore/compaction_raft_handler.go new file mode 100644 index 0000000000..47b27518fe --- /dev/null +++ b/pkg/metastore/compaction_raft_handler.go @@ -0,0 +1,237 @@ +package metastore + +import ( + "context" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/hashicorp/raft" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/metastore/tracing" +) + +type IndexReplacer interface { + ReplaceBlocks(*bbolt.Tx, *metastorev1.CompactedBlocks) error +} + +type CompactionCommandHandler struct { + logger log.Logger + index IndexReplacer + compactor compaction.Compactor + planner compaction.Planner + scheduler compaction.Scheduler + tombstones Tombstones +} + +func NewCompactionCommandHandler( + logger log.Logger, + index IndexReplacer, + compactor compaction.Compactor, + planner compaction.Planner, + scheduler compaction.Scheduler, + tombstones Tombstones, +) *CompactionCommandHandler { + return &CompactionCommandHandler{ + logger: logger, + index: index, + compactor: compactor, + planner: planner, + scheduler: scheduler, + tombstones: tombstones, + } +} + +func (h *CompactionCommandHandler) GetCompactionPlanUpdate( + ctx context.Context, tx *bbolt.Tx, cmd *raft.Log, req *raft_log.GetCompactionPlanUpdateRequest, +) (resp *raft_log.GetCompactionPlanUpdateResponse, err error) { + span, _ := tracing.StartSpanFromContext(ctx, "raft.GetCompactionPlanUpdate") + span.SetTag("status_updates", len(req.StatusUpdates)) + span.SetTag("assign_jobs_max", req.AssignJobsMax) + span.SetTag("raft_log_index", cmd.Index) + span.SetTag("raft_log_term", cmd.Term) + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + // We need to generate a plan of the update caused by the new status + // report from the worker. The plan will be used to update the schedule + // after the Raft consensus is reached. + planner := h.planner.NewPlan(cmd) + schedule := h.scheduler.NewSchedule(tx, cmd) + p := new(raft_log.CompactionPlanUpdate) + + // Any status update may translate to either a job lease refresh, or a + // completed job. Status update might be rejected, if the worker has + // lost the job. We treat revoked jobs as vacant slots for new + // assignments, therefore we try to update jobs' status first. + var revoked int + for _, status := range req.StatusUpdates { + switch state := schedule.UpdateJob(status); { + case state == nil: + // Nil state indicates that the job has been abandoned and + // reassigned, or the request is not valid. This may happen + // from time to time, and we should just ignore such requests. + revoked++ + + case state.Status == metastorev1.CompactionJobStatus_COMPACTION_STATUS_SUCCESS: + p.CompletedJobs = append(p.CompletedJobs, &raft_log.CompletedCompactionJob{State: state}) + + case state.Status == metastorev1.CompactionJobStatus_COMPACTION_STATUS_IN_PROGRESS: + p.UpdatedJobs = append(p.UpdatedJobs, &raft_log.UpdatedCompactionJob{State: state}) + + default: + // Unknown statuses are ignored. From the worker perspective, + // the job is re-assigned. + } + } + + // AssignJobsMax tells us how many free slots the worker has. We need to + // account for the revoked jobs, as they are freeing the worker slots. + capacity := int(req.AssignJobsMax) + revoked + + // Next, we need to create new jobs and assign existing + // + // NOTE(kolesnikovae): On one hand, if we assign first, we may violate the + // SJF principle. If we plan new jobs first, it may cause starvation of + // lower-priority jobs, when the compaction worker does not keep up with + // the high-priority job influx. As of now, we assign jobs before creating + // ones. If we change it, we need to make sure that the Schedule + // implementation allows doing this. + for assigned := 0; assigned < capacity; assigned++ { + job, err := schedule.AssignJob() + if err != nil { + level.Error(h.logger).Log("msg", "failed to assign compaction job", "err", err) + return nil, err + } + if job != nil { + p.AssignedJobs = append(p.AssignedJobs, job) + } + } + + for created := 0; created < capacity; created++ { + // Evict jobs that cannot be assigned to workers. + if evicted := schedule.EvictJob(); evicted != nil { + level.Debug(h.logger).Log("msg", "planning to evict failed job", "job", evicted.Name) + p.EvictedJobs = append(p.EvictedJobs, &raft_log.EvictedCompactionJob{ + State: evicted, + }) + } + plan, err := planner.CreateJob() + if err != nil { + level.Error(h.logger).Log("msg", "failed to create compaction job", "err", err) + return nil, err + } + if plan == nil { + // No more jobs to create. + break + } + state := schedule.AddJob(plan) + if state == nil { + // Scheduler declined the job. The only case when this may happen + // is when the scheduler queue is full; theoretically, this should + // not happen, because we evicted jobs before creating new ones. + // However, if all the jobs are healthy, we may end up here. + level.Warn(h.logger).Log("msg", "compaction job rejected by scheduler") + break + } + p.NewJobs = append(p.NewJobs, &raft_log.NewCompactionJob{ + State: state, + Plan: plan, + }) + } + + span.SetTag("assigned_jobs", len(p.AssignedJobs)) + span.SetTag("new_jobs", len(p.NewJobs)) + span.SetTag("evicted_jobs", len(p.EvictedJobs)) + return &raft_log.GetCompactionPlanUpdateResponse{Term: cmd.Term, PlanUpdate: p}, nil +} + +func (h *CompactionCommandHandler) UpdateCompactionPlan( + ctx context.Context, tx *bbolt.Tx, cmd *raft.Log, req *raft_log.UpdateCompactionPlanRequest, +) (resp *raft_log.UpdateCompactionPlanResponse, err error) { + span, _ := tracing.StartSpanFromContext(ctx, "raft.UpdateCompactionPlan") + span.SetTag("raft_log_index", cmd.Index) + span.SetTag("raft_log_term", cmd.Term) + span.SetTag("request_term", req.Term) + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + if req.Term != cmd.Term || req.GetPlanUpdate() == nil { + level.Warn(h.logger).Log( + "msg", "rejecting compaction plan update; term mismatch: leader has changed", + "current_term", cmd.Term, + "request_term", req.Term, + ) + return new(raft_log.UpdateCompactionPlanResponse), nil + } + + if err = h.planner.UpdatePlan(tx, req.PlanUpdate); err != nil { + level.Error(h.logger).Log("msg", "failed to update compaction planner", "err", err) + return nil, err + } + + if err = h.scheduler.UpdateSchedule(tx, req.PlanUpdate); err != nil { + level.Error(h.logger).Log("msg", "failed to update compaction schedule", "err", err) + return nil, err + } + + for _, job := range req.PlanUpdate.NewJobs { + if err = h.tombstones.DeleteTombstones(tx, cmd, job.Plan.Tombstones...); err != nil { + level.Error(h.logger).Log("msg", "failed to delete tombstones", "err", err) + return nil, err + } + } + + for _, job := range req.PlanUpdate.CompletedJobs { + compacted := job.GetCompactedBlocks() + if compacted == nil || compacted.SourceBlocks == nil || len(compacted.NewBlocks) == 0 { + level.Warn(h.logger).Log("msg", "compacted blocks are missing; skipping", "job", job.State.Name) + continue + } + if err = h.tombstones.AddTombstones(tx, cmd, blockTombstonesForCompletedJob(job)); err != nil { + level.Error(h.logger).Log("msg", "failed to add tombstones", "err", err) + return nil, err + } + for _, block := range compacted.NewBlocks { + if err = h.compactor.Compact(tx, compaction.NewBlockEntry(cmd, block)); err != nil { + level.Error(h.logger).Log("msg", "failed to compact block", "err", err) + return nil, err + } + } + if err = h.index.ReplaceBlocks(tx, compacted); err != nil { + level.Error(h.logger).Log("msg", "failed to replace blocks", "err", err) + return nil, err + } + } + + span.SetTag("new_jobs", len(req.PlanUpdate.NewJobs)) + span.SetTag("completed_jobs", len(req.PlanUpdate.CompletedJobs)) + span.SetTag("updated_jobs", len(req.PlanUpdate.UpdatedJobs)) + return &raft_log.UpdateCompactionPlanResponse{PlanUpdate: req.PlanUpdate}, nil +} + +func blockTombstonesForCompletedJob(job *raft_log.CompletedCompactionJob) *metastorev1.Tombstones { + source := job.CompactedBlocks.SourceBlocks + return &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{ + Name: job.State.Name, + Shard: source.Shard, + Tenant: source.Tenant, + CompactionLevel: job.State.CompactionLevel, + Blocks: source.Blocks, + }, + } +} diff --git a/pkg/metastore/compaction_service.go b/pkg/metastore/compaction_service.go new file mode 100644 index 0000000000..8b0b4253f1 --- /dev/null +++ b/pkg/metastore/compaction_service.go @@ -0,0 +1,177 @@ +package metastore + +import ( + "context" + "sync" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/fsm" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" +) + +type CompactionService struct { + metastorev1.CompactionServiceServer + + logger log.Logger + mu sync.Mutex + raft Raft +} + +func NewCompactionService( + logger log.Logger, + raft Raft, +) *CompactionService { + return &CompactionService{ + logger: logger, + raft: raft, + } +} + +func (svc *CompactionService) PollCompactionJobs( + ctx context.Context, + req *metastorev1.PollCompactionJobsRequest, +) (resp *metastorev1.PollCompactionJobsResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "CompactionService.PollCompactionJobs") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + span.SetTag("status_updates", len(req.GetStatusUpdates())) + span.SetTag("job_capacity", req.GetJobCapacity()) + + // This is a two-step process. To commit changes to the compaction plan, + // we need to ensure that all replicas apply exactly the same changes. + // Instead of relying on identical behavior across replicas and a + // reproducible compaction plan, we explicitly replicate the change. + // + // NOTE(kolesnikovae): We can use Leader Read optimization here. However, + // we would need to ensure synchronization between the compactor and the + // index, and unsure isolation at the data level. For now, we're using + // the raft log to guarantee serializable isolation level. + // + // Make sure that only one compaction plan update is in progress at a time. + // This lock does not introduce contention, as the raft log is synchronous. + svc.mu.Lock() + defer svc.mu.Unlock() + + // First, we ask the current leader to prepare the change. This is a read + // operation conducted through the raft log: at this stage, we only + // prepare changes; the command handler does not alter the state. + request := &raft_log.GetCompactionPlanUpdateRequest{ + StatusUpdates: make([]*raft_log.CompactionJobStatusUpdate, 0, len(req.StatusUpdates)), + AssignJobsMax: req.JobCapacity, + } + + // We only send the status updates (without job results) to minimize the + // traffic, but we want to include the results of compaction in the final + // proposal. If the status update is accepted, we trust the worker and + // don't need to load our own copy of the job. + compacted := make(map[string]*metastorev1.CompactionJobStatusUpdate, len(req.StatusUpdates)) + for _, update := range req.StatusUpdates { + if update.CompactedBlocks != nil { + compacted[update.Name] = update + } + request.StatusUpdates = append(request.StatusUpdates, &raft_log.CompactionJobStatusUpdate{ + Name: update.Name, + Token: update.Token, + Status: update.Status, + }) + } + + cmd := fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_GET_COMPACTION_PLAN_UPDATE) + proposeResp, err := svc.raft.Propose(ctx, cmd, req) + if err != nil { + if !raftnode.IsRaftLeadershipError(err) { + level.Error(svc.logger).Log("msg", "failed to prepare compaction plan", "err", err) + } + return nil, err + } + prepared := proposeResp.(*raft_log.GetCompactionPlanUpdateResponse) + planUpdate := prepared.GetPlanUpdate() + + // Copy plan updates to the worker response. The job plan is only sent for + // newly assigned jobs. Lease renewals do not require the plan to be sent. + workerResp := &metastorev1.PollCompactionJobsResponse{ + CompactionJobs: make([]*metastorev1.CompactionJob, 0, len(planUpdate.AssignedJobs)), + Assignments: make([]*metastorev1.CompactionJobAssignment, 0, len(planUpdate.UpdatedJobs)), + } + for _, updated := range planUpdate.UpdatedJobs { + update := updated.State + workerResp.Assignments = append(workerResp.Assignments, &metastorev1.CompactionJobAssignment{ + Name: update.Name, + Token: update.Token, + LeaseExpiresAt: update.LeaseExpiresAt, + }) + } + for _, assigned := range planUpdate.AssignedJobs { + assignment := assigned.State + workerResp.Assignments = append(workerResp.Assignments, &metastorev1.CompactionJobAssignment{ + Name: assignment.Name, + Token: assignment.Token, + LeaseExpiresAt: assignment.LeaseExpiresAt, + }) + job := assigned.Plan + workerResp.CompactionJobs = append(workerResp.CompactionJobs, &metastorev1.CompactionJob{ + Name: job.Name, + Shard: job.Shard, + Tenant: job.Tenant, + CompactionLevel: job.CompactionLevel, + SourceBlocks: job.SourceBlocks, + Tombstones: job.Tombstones, + }) + // Assigned jobs are not written to the raft log (only the assignments): + // from our perspective (scheduler and planner) these are just job updates. + assigned.Plan = nil + } + + // Include the compacted blocks in the final proposal. + for _, job := range planUpdate.CompletedJobs { + if update := compacted[job.State.Name]; update != nil { + job.CompactedBlocks = update.CompactedBlocks + } + } + + // Now that we have the plan, we need to propagate it through the + // raft log to ensure it is applied consistently across all replicas, + // regardless of their individual state or view of the plan. + cmd = fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_UPDATE_COMPACTION_PLAN) + + // We also include the current term of the planning step so that later + // we can verify that the leader has not changed, and the plan is still + // up-to-date. Otherwise, e.g., in the ABA case, when the current node + // loses leadership and gains is back in-between these two steps, we + // cannot guarantee that the proposed plan is still valid and up-to-date. + // The raft handler cannot return an error here (because this is a valid + // scenario, and we don't want to stop the node/cluster). Instead, an + // empty response would indicate that the plan is rejected. + proposal := &raft_log.UpdateCompactionPlanRequest{Term: prepared.Term, PlanUpdate: planUpdate} + if proposeResp, err = svc.raft.Propose(ctx, cmd, proposal); err != nil { + if !raftnode.IsRaftLeadershipError(err) { + level.Error(svc.logger).Log("msg", "failed to update compaction plan", "err", err) + } + return nil, err + } + accepted := proposeResp.(*raft_log.UpdateCompactionPlanResponse).GetPlanUpdate() + if accepted == nil { + level.Warn(svc.logger).Log("msg", "compaction plan update rejected") + return nil, status.Error(codes.FailedPrecondition, "failed to update compaction plan") + } + + // As of now, accepted plan always matches the proposed one, + // so our prepared worker response is still valid. + + span.SetTag("assigned_jobs", len(workerResp.GetCompactionJobs())) + span.SetTag("assignment_updates", len(workerResp.GetAssignments())) + return workerResp, nil +} diff --git a/pkg/metastore/discovery/discovery.go b/pkg/metastore/discovery/discovery.go new file mode 100644 index 0000000000..a05cf1d2d0 --- /dev/null +++ b/pkg/metastore/discovery/discovery.go @@ -0,0 +1,32 @@ +package discovery + +import ( + "fmt" + + "github.com/hashicorp/raft" +) + +type Updates interface { + Servers(servers []Server) +} + +type UpdateFunc func(servers []Server) + +func (f UpdateFunc) Servers(servers []Server) { + f(servers) +} + +type Server struct { + Raft raft.Server + ResolvedAddress string +} + +func (s *Server) String() string { + return fmt.Sprintf("Server{id: %s, Address %s ResolvedAddress: %v}", s.Raft.ID, s.Raft.Address, s.ResolvedAddress) +} + +type Discovery interface { + Subscribe(updates Updates) + Rediscover() + Close() +} diff --git a/pkg/metastore/discovery/dns.go b/pkg/metastore/discovery/dns.go new file mode 100644 index 0000000000..130d589098 --- /dev/null +++ b/pkg/metastore/discovery/dns.go @@ -0,0 +1,77 @@ +package discovery + +import ( + "context" + "fmt" + "sync" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/dns" + "github.com/hashicorp/raft" +) + +type DNSDiscovery struct { + logger log.Logger + addr string + provider *dns.Provider + m sync.Mutex + upd Updates + resolved []Server +} + +func NewDNSDiscovery(l log.Logger, addr string, p *dns.Provider) *DNSDiscovery { + d := &DNSDiscovery{ + logger: log.With(l, "addr", addr, "component", "dns-discovery"), + addr: addr, + provider: p, + } + + return d +} + +func (d *DNSDiscovery) Subscribe(updates Updates) { + d.m.Lock() + d.upd = updates + d.m.Unlock() + d.resolve() +} + +func (d *DNSDiscovery) Rediscover() { + d.resolve() +} + +func (d *DNSDiscovery) Close() { + +} + +func (d *DNSDiscovery) resolve() { + err := d.provider.Resolve(context.Background(), []string{d.addr}) + if err != nil { + level.Error(d.logger).Log("msg", "failed to resolve DNS", "addr", d.addr, "err", err) + return + } + addrs := d.provider.Addresses() + if len(addrs) == 0 { + level.Error(d.logger).Log("msg", "failed to resolve DNS", "addr", d.addr, "err", "no addresses") + return + } + level.Debug(d.logger).Log("msg", "resolved DNS", "addr", d.addr, "addrs", fmt.Sprintf("%+v", addrs)) + + servers := make([]Server, 0, len(addrs)) + for _, peer := range addrs { + servers = append(servers, Server{ + Raft: raft.Server{ + Suffrage: raft.Voter, + ID: raft.ServerID(peer), + Address: raft.ServerAddress(peer), + }, + }) + } + d.m.Lock() + defer d.m.Unlock() + d.resolved = servers + if d.upd != nil { + d.upd.Servers(servers) + } +} diff --git a/pkg/metastore/discovery/kuberesolver.go b/pkg/metastore/discovery/kuberesolver.go new file mode 100644 index 0000000000..406e9aa516 --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver.go @@ -0,0 +1,173 @@ +package discovery + +import ( + "fmt" + "net" + "net/url" + "strconv" + "strings" + "sync" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/hashicorp/raft" + "google.golang.org/grpc/resolver" + + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery/kuberesolver" +) + +type KubeDiscovery struct { + l log.Logger + resolver *kuberesolver.KResolver + ti targetInfo + + servers []Server + updLock sync.Mutex + upd Updates +} + +func (g *KubeDiscovery) Rediscover() { + +} + +func NewKubeResolverDiscovery(l log.Logger, target string, client kuberesolver.K8sClient) (*KubeDiscovery, error) { + var err error + l = log.With(l, "target", target, "component", "kuberesolver-discovery") + u, err := url.Parse(target) + if err != nil { + return nil, err + } + gt := resolver.Target{URL: *u} + ti, err := parseResolverTarget(gt) + if err != nil { + return nil, err + } + level.Info(l).Log("msg", "parsed target", "target_namespace", ti.namespace, "target_service", ti.service, "target_port", ti.port) + + res := &KubeDiscovery{ + l: l, + ti: ti, + } + ku := kuberesolver.ResolveUpdatesFunc(func(e kuberesolver.Endpoints) { + res.resolved(e) + }) + + r, err := kuberesolver.Build(l, client, ku, kuberesolver.TargetInfo{ + ServiceName: ti.service, + ServiceNamespace: ti.namespace, + }) + if err != nil { + return nil, err + } + + res.resolver = r + + return res, nil +} + +func (g *KubeDiscovery) Subscribe(upd Updates) { + g.updLock.Lock() + defer g.updLock.Unlock() + g.upd = upd + g.upd.Servers(g.servers) +} + +func (g *KubeDiscovery) Close() { + g.updLock.Lock() + defer g.updLock.Unlock() + g.upd = nil + g.resolver.Close() +} + +func (g *KubeDiscovery) resolved(e kuberesolver.Endpoints) { + for _, subset := range e.Subsets { + for _, addr := range subset.Addresses { + level.Debug(g.l).Log("msg", "resolved", "ip", addr.IP, "targetRef", fmt.Sprintf("%+v", addr.TargetRef)) + } + } + g.updLock.Lock() + defer g.updLock.Unlock() + g.servers = convertEndpoints(e, g.ti) + if g.upd != nil { + g.upd.Servers(g.servers) + } +} + +func convertEndpoints(e kuberesolver.Endpoints, ti targetInfo) []Server { + var servers []Server + for _, ep := range e.Subsets { + for _, addr := range ep.Addresses { + for _, port := range ep.Ports { + if fmt.Sprintf("%d", port.Port) != ti.port { + continue + } + podName := addr.TargetRef.Name + raftServerId := fmt.Sprintf("%s.%s.%s.svc.cluster.local.:%d", podName, ti.service, ti.namespace, port.Port) + + servers = append(servers, Server{ + ResolvedAddress: net.JoinHostPort(addr.IP, strconv.Itoa(port.Port)), + Raft: raft.Server{ + ID: raft.ServerID(raftServerId), + Address: raft.ServerAddress(raftServerId), + }, + }) + + } + } + } + return servers +} + +type targetInfo struct { + namespace, service, port string +} + +func parseResolverTarget(target resolver.Target) (targetInfo, error) { + var service, port, namespace string + if target.URL.Host == "" { + // kubernetes:///service.namespace:port + service, port, namespace = splitServicePortNamespace(target.Endpoint()) + } else if target.URL.Port() == "" && target.Endpoint() != "" { + // kubernetes://namespace/service:port + service, port, _ = splitServicePortNamespace(target.Endpoint()) + namespace = target.URL.Hostname() + } else { + // kubernetes://service.namespace:port + service, port, namespace = splitServicePortNamespace(target.URL.Host) + } + + if service == "" { + return targetInfo{}, fmt.Errorf("target %s must specify a service", &target.URL) + } + if namespace == "" { + return targetInfo{}, fmt.Errorf("target %s must specify a namespace", &target.URL) + } + if port == "" { + return targetInfo{}, fmt.Errorf("target %s must specify a port", &target.URL) + } + return targetInfo{ + service: service, + namespace: namespace, + port: port, + }, nil +} + +func splitServicePortNamespace(hpn string) (service, port, namespace string) { + service = hpn + + colon := strings.LastIndexByte(service, ':') + if colon != -1 { + service, port = service[:colon], service[colon+1:] + } + + // we want to split into the service name, namespace, and whatever else is left + // this will support fully qualified service names, e.g. {service-name}..svc.. + // Note that since we lookup the endpoints by service name and namespace, we don't care about the + // cluster-domain-name, only that we can parse out the service name and namespace properly. + parts := strings.SplitN(service, ".", 3) + if len(parts) >= 2 { + service, namespace = parts[0], parts[1] + } + + return +} diff --git a/pkg/metastore/discovery/kuberesolver/LICENSE b/pkg/metastore/discovery/kuberesolver/LICENSE new file mode 100644 index 0000000000..5ae44e510f --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Sercan Degirmenci + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/pkg/metastore/discovery/kuberesolver/README.md b/pkg/metastore/discovery/kuberesolver/README.md new file mode 100644 index 0000000000..4676be84ae --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver/README.md @@ -0,0 +1,4 @@ +# kuberesolver + +Copied from github.com/sercand/kuberesolver/v5 +Removed grpc specific bits \ No newline at end of file diff --git a/pkg/metastore/discovery/kuberesolver/builder.go b/pkg/metastore/discovery/kuberesolver/builder.go new file mode 100644 index 0000000000..3306efe323 --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver/builder.go @@ -0,0 +1,116 @@ +package kuberesolver + +import ( + "context" + "fmt" + "io" + "sync" + "time" + + "github.com/go-kit/log" +) + +const ( + defaultFreq = time.Minute * 30 +) + +type TargetInfo struct { + ServiceName string + ServiceNamespace string +} + +func Build(l log.Logger, k8sClient K8sClient, upd ResolveUpdates, target TargetInfo) (*KResolver, error) { + if k8sClient == nil { + return nil, fmt.Errorf("k8sClient is nil") + } + ti := target + if ti.ServiceNamespace == "" { + ti.ServiceNamespace = getCurrentNamespaceOrDefault() + } + ctx, cancel := context.WithCancel(context.Background()) + r := &KResolver{ + target: ti, + upd: upd, + l: l, + ctx: ctx, + cancel: cancel, + k8sClient: k8sClient, + t: time.NewTimer(defaultFreq), + freq: defaultFreq, + } + go until(func() { + err := r.watch() + if err != nil && err != io.EOF { + l.Log("msg", "watching ended with error, will reconnect again", "err", err) + } + }, time.Second, time.Second*30, ctx.Done()) + return r, nil +} + +type ResolveUpdates interface { + Resolved(e Endpoints) +} + +type ResolveUpdatesFunc func(e Endpoints) + +func (f ResolveUpdatesFunc) Resolved(e Endpoints) { + f(e) +} + +type KResolver struct { + target TargetInfo + ctx context.Context + cancel context.CancelFunc + k8sClient K8sClient + // wg is used to enforce Close() to return after the watcher() goroutine has finished. + wg sync.WaitGroup + t *time.Timer + freq time.Duration + upd ResolveUpdates + l log.Logger +} + +// Close closes the resolver. +func (k *KResolver) Close() { + k.cancel() + k.wg.Wait() +} + +func (k *KResolver) handle(e Endpoints) { + k.upd.Resolved(e) +} + +func (k *KResolver) resolve() { + e, err := getEndpoints(k.k8sClient, k.target.ServiceNamespace, k.target.ServiceName) + if err == nil { + k.handle(e) + } else { + k.l.Log("msg", "lookup endpoints failed", "err", err) + } + // Next lookup should happen after an interval defined by k.freq. + k.t.Reset(k.freq) +} + +func (k *KResolver) watch() error { + k.wg.Add(1) + defer k.wg.Done() + // watch endpoints lists existing endpoints at start + sw, err := watchEndpoints(k.ctx, k.k8sClient, k.target.ServiceNamespace, k.target.ServiceName) + if err != nil { + return err + } + for { + select { + case <-k.ctx.Done(): + return nil + case <-k.t.C: + k.resolve() + case up, hasMore := <-sw.ResultChan(): + if hasMore { + k.handle(up.Object) + } else { + return nil + } + } + } +} diff --git a/pkg/metastore/discovery/kuberesolver/kubernetes.go b/pkg/metastore/discovery/kuberesolver/kubernetes.go new file mode 100644 index 0000000000..f0fb899194 --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver/kubernetes.go @@ -0,0 +1,207 @@ +// nolint +package kuberesolver + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "net" + "net/http" + "net/url" + "os" + "strings" + "sync" + "time" + + "github.com/fsnotify/fsnotify" +) + +const ( + serviceAccountToken = "/var/run/secrets/kubernetes.io/serviceaccount/token" + serviceAccountCACert = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + kubernetesNamespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" + defaultNamespace = "default" +) + +// K8sClient is minimal kubernetes client interface +type K8sClient interface { + Do(req *http.Request) (*http.Response, error) + GetRequest(url string) (*http.Request, error) + Host() string +} + +type k8sClient struct { + host string + token string + tokenLck sync.RWMutex + httpClient *http.Client +} + +func (kc *k8sClient) GetRequest(url string) (*http.Request, error) { + if !strings.HasPrefix(url, kc.host) { + url = fmt.Sprintf("%s/%s", kc.host, url) + } + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + kc.tokenLck.RLock() + defer kc.tokenLck.RUnlock() + if len(kc.token) > 0 { + req.Header.Set("Authorization", "Bearer "+kc.token) + } + return req, nil +} + +func (kc *k8sClient) Do(req *http.Request) (*http.Response, error) { + return kc.httpClient.Do(req) +} + +func (kc *k8sClient) Host() string { + return kc.host +} + +func (kc *k8sClient) setToken(token string) { + kc.tokenLck.Lock() + defer kc.tokenLck.Unlock() + kc.token = token +} + +// NewInClusterK8sClient creates K8sClient if it is inside Kubernetes +func NewInClusterK8sClient() (K8sClient, error) { + host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT") + if len(host) == 0 || len(port) == 0 { + return nil, fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined") + } + token, err := os.ReadFile(serviceAccountToken) + if err != nil { + return nil, err + } + ca, err := os.ReadFile(serviceAccountCACert) + if err != nil { + return nil, err + } + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(ca) + transport := &http.Transport{TLSClientConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + RootCAs: certPool, + }} + httpClient := &http.Client{Transport: transport, Timeout: time.Nanosecond * 0} + + client := &k8sClient{ + host: "https://" + net.JoinHostPort(host, port), + token: string(token), + httpClient: httpClient, + } + + // Create a new file watcher to listen for new Service Account tokens + watcher, err := fsnotify.NewWatcher() + if err != nil { + return nil, err + } + + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + // k8s configmaps uses symlinks, we need this workaround. + // original configmap file is removed + if event.Op.Has(fsnotify.Remove) || event.Op.Has(fsnotify.Chmod) { + // remove watcher since the file is removed + watcher.Remove(event.Name) + // add a new watcher pointing to the new symlink/file + watcher.Add(serviceAccountToken) + token, err := os.ReadFile(serviceAccountToken) + if err == nil { + client.setToken(string(token)) + } + } + if event.Has(fsnotify.Write) { + token, err := os.ReadFile(serviceAccountToken) + if err == nil { + client.setToken(string(token)) + } + } + case _, ok := <-watcher.Errors: + if !ok { + return + } + } + } + }() + + err = watcher.Add(serviceAccountToken) + if err != nil { + return nil, err + } + + return client, nil +} + +// NewInsecureK8sClient creates an insecure k8s client which is suitable +// to connect kubernetes api behind proxy +func NewInsecureK8sClient(apiURL string) K8sClient { + return &k8sClient{ + host: apiURL, + httpClient: http.DefaultClient, + } +} + +func getEndpoints(client K8sClient, namespace, targetName string) (Endpoints, error) { + u, err := url.Parse(fmt.Sprintf("%s/api/v1/namespaces/%s/endpoints/%s", + client.Host(), namespace, targetName)) + if err != nil { + return Endpoints{}, err + } + req, err := client.GetRequest(u.String()) + if err != nil { + return Endpoints{}, err + } + resp, err := client.Do(req) + if err != nil { + return Endpoints{}, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return Endpoints{}, fmt.Errorf("invalid response code %d for service %s in namespace %s", resp.StatusCode, targetName, namespace) + } + result := Endpoints{} + err = json.NewDecoder(resp.Body).Decode(&result) + return result, err +} + +func watchEndpoints(ctx context.Context, client K8sClient, namespace, targetName string) (watchInterface, error) { + u, err := url.Parse(fmt.Sprintf("%s/api/v1/watch/namespaces/%s/endpoints/%s", + client.Host(), namespace, targetName)) + if err != nil { + return nil, err + } + req, err := client.GetRequest(u.String()) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + resp, err := client.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + defer resp.Body.Close() + return nil, fmt.Errorf("invalid response code %d for service %s in namespace %s", resp.StatusCode, targetName, namespace) + } + return newStreamWatcher(resp.Body), nil +} + +func getCurrentNamespaceOrDefault() string { + ns, err := os.ReadFile(kubernetesNamespaceFile) + if err != nil { + return defaultNamespace + } + return string(ns) +} diff --git a/pkg/metastore/discovery/kuberesolver/models.go b/pkg/metastore/discovery/kuberesolver/models.go new file mode 100644 index 0000000000..167e3613e7 --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver/models.go @@ -0,0 +1,50 @@ +package kuberesolver + +type EventType string + +const ( + Added EventType = "ADDED" + Modified EventType = "MODIFIED" + Deleted EventType = "DELETED" + Error EventType = "ERROR" +) + +// Event represents a single event to a watched resource. +type Event struct { + Type EventType `json:"type"` + Object Endpoints `json:"object"` +} + +type Endpoints struct { + Kind string `json:"kind"` + ApiVersion string `json:"apiVersion"` + Metadata Metadata `json:"metadata"` + Subsets []Subset `json:"subsets"` +} + +type Metadata struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + ResourceVersion string `json:"resourceVersion"` + Labels map[string]string `json:"labels"` +} + +type Subset struct { + Addresses []Address `json:"addresses"` + Ports []Port `json:"ports"` +} + +type Address struct { + IP string `json:"ip"` + TargetRef *ObjectReference `json:"targetRef,omitempty"` +} + +type ObjectReference struct { + Kind string `json:"kind"` + Name string `json:"name"` + Namespace string `json:"namespace"` +} +type Port struct { + Name string `json:"name"` + Port int `json:"port"` +} diff --git a/pkg/metastore/discovery/kuberesolver/stream.go b/pkg/metastore/discovery/kuberesolver/stream.go new file mode 100644 index 0000000000..4701aa95a0 --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver/stream.go @@ -0,0 +1,108 @@ +package kuberesolver + +import ( + "context" + "encoding/json" + "fmt" + "io" + "sync" + + "google.golang.org/grpc/grpclog" +) + +// Interface can be implemented by anything that knows how to watch and report changes. +type watchInterface interface { + // Stops watching. Will close the channel returned by ResultChan(). Releases + // any resources used by the watch. + Stop() + + // Returns a chan which will receive all the events. If an error occurs + // or Stop() is called, this channel will be closed, in which case the + // watch should be completely cleaned up. + ResultChan() <-chan Event +} + +// StreamWatcher turns any stream for which you can write a Decoder interface +// into a watch.Interface. +type streamWatcher struct { + result chan Event + r io.ReadCloser + decoder *json.Decoder + sync.Mutex + stopped bool +} + +// NewStreamWatcher creates a StreamWatcher from the given io.ReadClosers. +func newStreamWatcher(r io.ReadCloser) watchInterface { + sw := &streamWatcher{ + r: r, + decoder: json.NewDecoder(r), + result: make(chan Event), + } + go sw.receive() + return sw +} + +// ResultChan implements Interface. +func (sw *streamWatcher) ResultChan() <-chan Event { + return sw.result +} + +// Stop implements Interface. +func (sw *streamWatcher) Stop() { + sw.Lock() + defer sw.Unlock() + if !sw.stopped { + sw.stopped = true + sw.r.Close() + } +} + +// stopping returns true if Stop() was called previously. +func (sw *streamWatcher) stopping() bool { + sw.Lock() + defer sw.Unlock() + return sw.stopped +} + +// receive reads result from the decoder in a loop and sends down the result channel. +func (sw *streamWatcher) receive() { + defer close(sw.result) + defer sw.Stop() + for { + obj, err := sw.Decode() + if err != nil { + // Ignore expected error. + if sw.stopping() { + return + } + switch err { + case io.EOF: + // watch closed normally + case context.Canceled: + // canceled normally + case io.ErrUnexpectedEOF: + grpclog.Infof("kuberesolver: Unexpected EOF during watch stream event decoding: %v", err) + default: + grpclog.Infof("kuberesolver: Unable to decode an event from the watch stream: %v", err) + } + return + } + sw.result <- obj + } +} + +// Decode blocks until it can return the next object in the writer. Returns an error +// if the writer is closed or an object can't be decoded. +func (sw *streamWatcher) Decode() (Event, error) { + var got Event + if err := sw.decoder.Decode(&got); err != nil { + return Event{}, err + } + switch got.Type { + case Added, Modified, Deleted, Error: + return got, nil + default: + return Event{}, fmt.Errorf("got invalid watch event type: %v", got.Type) + } +} diff --git a/pkg/metastore/discovery/kuberesolver/util.go b/pkg/metastore/discovery/kuberesolver/util.go new file mode 100644 index 0000000000..dac68ab422 --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver/util.go @@ -0,0 +1,41 @@ +package kuberesolver + +import ( + "runtime/debug" + "time" + + "google.golang.org/grpc/grpclog" +) + +func until(f func(), initialPeriod, maxPeriod time.Duration, stopCh <-chan struct{}) { + select { + case <-stopCh: + return + default: + } + period := initialPeriod + for { + func() { + defer handleCrash() + f() + }() + select { + case <-stopCh: + return + case <-time.After(period): + if period*2 <= maxPeriod { + period *= 2 + } else { + period = initialPeriod + } + } + } +} + +// HandleCrash simply catches a crash and logs an error. Meant to be called via defer. +func handleCrash() { + if r := recover(); r != nil { + callers := string(debug.Stack()) + grpclog.Errorf("kuberesolver: recovered from panic: %#v (%v)\n%v", r, r, callers) + } +} diff --git a/pkg/metastore/discovery/kuberesolver_test.go b/pkg/metastore/discovery/kuberesolver_test.go new file mode 100644 index 0000000000..9d38979978 --- /dev/null +++ b/pkg/metastore/discovery/kuberesolver_test.go @@ -0,0 +1,117 @@ +package discovery + +import ( + "fmt" + "testing" + "time" + + "github.com/hashicorp/raft" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery/kuberesolver" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestDebugLocalhost(t *testing.T) { + t.Skip() + client := kuberesolver.NewInsecureK8sClient("http://localhost:8080") + target := "kubernetes:///pyroscope-metastore-headless.pyroscope-test:9095" + + discovery, err := NewKubeResolverDiscovery(test.NewTestingLogger(t), target, client) + require.NoError(t, err) + discovery.Subscribe(UpdateFunc(func(servers []Server) { + fmt.Printf("servers: %+v\n", servers) + })) + + defer discovery.Close() + time.Sleep(555 * time.Second) + +} + +func TestConvert(t *testing.T) { + e := kuberesolver.Endpoints{ + Kind: "Endpoints", + ApiVersion: "v1", + Metadata: kuberesolver.Metadata{ + Name: "pyroscope-metastore-headless", + Namespace: "pyroscope-test", + ResourceVersion: "1013720", + Labels: map[string]string{}, + }, + Subsets: []kuberesolver.Subset{ + { + Addresses: []kuberesolver.Address{ + { + IP: "10.244.1.5", + TargetRef: &kuberesolver.ObjectReference{ + Kind: "Pod", + Name: "pyroscope-metastore-0", + Namespace: "pyroscope-test", + }, + }, + { + IP: "10.244.2.7", + TargetRef: &kuberesolver.ObjectReference{ + Kind: "Pod", + Name: "pyroscope-metastore-1", + Namespace: "pyroscope-test", + }, + }, + { + IP: "10.244.3.7", + TargetRef: &kuberesolver.ObjectReference{ + Kind: "Pod", + Name: "pyroscope-metastore-2", + Namespace: "pyroscope-test", + }, + }, + }, + Ports: []kuberesolver.Port{ + { + Name: "http2", + Port: 4040, + }, + { + Name: "raft", + Port: 9099, + }, + { + Name: "grpc", + Port: 9095, + }, + }, + }, + }, + } + + servers := convertEndpoints(e, targetInfo{ + namespace: "pyroscope-test", + service: "pyroscope-metastore-headless", + port: "9095", + }) + expected := []Server{ + { + ResolvedAddress: "10.244.1.5:9095", + Raft: raft.Server{ + ID: raft.ServerID("pyroscope-metastore-0.pyroscope-metastore-headless.pyroscope-test.svc.cluster.local.:9095"), + Address: raft.ServerAddress("pyroscope-metastore-0.pyroscope-metastore-headless.pyroscope-test.svc.cluster.local.:9095"), + }, + }, + { + ResolvedAddress: "10.244.2.7:9095", + Raft: raft.Server{ + ID: raft.ServerID("pyroscope-metastore-1.pyroscope-metastore-headless.pyroscope-test.svc.cluster.local.:9095"), + Address: raft.ServerAddress("pyroscope-metastore-1.pyroscope-metastore-headless.pyroscope-test.svc.cluster.local.:9095"), + }, + }, + { + ResolvedAddress: "10.244.3.7:9095", + Raft: raft.Server{ + ID: raft.ServerID("pyroscope-metastore-2.pyroscope-metastore-headless.pyroscope-test.svc.cluster.local.:9095"), + Address: raft.ServerAddress("pyroscope-metastore-2.pyroscope-metastore-headless.pyroscope-test.svc.cluster.local.:9095"), + }, + }, + } + require.Equal(t, expected, servers) + +} diff --git a/pkg/metastore/discovery/parse.go b/pkg/metastore/discovery/parse.go new file mode 100644 index 0000000000..1181d8dda0 --- /dev/null +++ b/pkg/metastore/discovery/parse.go @@ -0,0 +1,76 @@ +package discovery + +import ( + "net" + "strings" + + "github.com/go-kit/log" + "github.com/grafana/dskit/dns" + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery/kuberesolver" +) + +func NewDiscovery(l log.Logger, address string, reg prometheus.Registerer) (Discovery, error) { + if strings.HasPrefix(address, "dnssrvnoa+") { + p := dns.NewProvider(dns.MiekgdnsResolverType, 2, l, + prometheus.WrapRegistererWithPrefix( + "pyroscope_metastore_client_", + reg, + )) + return NewDNSDiscovery(l, address, p), nil + } + if strings.HasPrefix(address, "kubernetes:///") { + kubeClient, err := kuberesolver.NewInClusterK8sClient() + if err != nil { + return nil, err + } + return NewKubeResolverDiscovery(l, address, kubeClient) + } + peers := ParsePeers(address) + srvs := make([]Server, 0, len(peers)) + for _, peer := range peers { + srvs = append(srvs, Server{ + Raft: peer, + ResolvedAddress: string(peer.Address), + }) + } + return NewStaticDiscovery(srvs), nil +} + +func ParsePeers(raw string) []raft.Server { + rpeers := strings.Split(raw, ",") + peers := make([]raft.Server, 0, len(rpeers)) + for _, rpeer := range rpeers { + peers = append(peers, ParsePeer(rpeer)) + } + return peers +} + +func ParsePeer(raw string) raft.Server { + // The string may be "{addr}" or "{addr}/{node_id}". + parts := strings.SplitN(raw, "/", 2) + var addr string + var node string + if len(parts) == 2 { + addr = parts[0] + node = parts[1] + } else { + addr = raw + } + host, _, err := net.SplitHostPort(addr) + if err != nil { + // No port specified. + host = addr + } + if node == "" { + // No node_id specified. + node = host + } + return raft.Server{ + Suffrage: raft.Voter, + ID: raft.ServerID(node), + Address: raft.ServerAddress(addr), + } +} diff --git a/pkg/metastore/discovery/static.go b/pkg/metastore/discovery/static.go new file mode 100644 index 0000000000..7a125a7c7a --- /dev/null +++ b/pkg/metastore/discovery/static.go @@ -0,0 +1,20 @@ +package discovery + +type StaticDiscovery struct { + servers []Server +} + +func NewStaticDiscovery(servers []Server) *StaticDiscovery { + return &StaticDiscovery{servers: servers} +} + +func (s *StaticDiscovery) Subscribe(updates Updates) { + updates.Servers(s.servers) +} + +func (s *StaticDiscovery) Rediscover() { +} + +func (s *StaticDiscovery) Close() { + +} diff --git a/pkg/metastore/fsm/boltdb.go b/pkg/metastore/fsm/boltdb.go new file mode 100644 index 0000000000..8a2e75b39a --- /dev/null +++ b/pkg/metastore/fsm/boltdb.go @@ -0,0 +1,240 @@ +package fsm + +import ( + "fmt" + "io" + "os" + "path/filepath" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "go.etcd.io/bbolt" +) + +// TODO(kolesnikovae): Parametrize. +const ( + boltDBFileName = "metastore.boltdb" + boltDBSnapshotName = "metastore_snapshot.boltdb" + boltDBCompactedName = "metastore_compacted.boltdb" + boltDBInitialMmapSize = 1 << 30 + + boltDBCompactionMaxTxnSize = 1 << 20 +) + +type boltdb struct { + logger log.Logger + metrics *metrics + boltdb *bbolt.DB + config Config + path string +} + +func newDB(logger log.Logger, metrics *metrics, config Config) *boltdb { + return &boltdb{ + logger: logger, + metrics: metrics, + config: config, + } +} + +// open creates a new or opens an existing boltdb database. +// +// The only case in which we open the database in read-only mode is when we +// restore it from a snapshot: before closing the database in use, we open +// the snapshot in read-only mode to verify its integrity. +// +// Read-only mode guarantees the snapshot won't be corrupted by the current +// process and allows loading the database more quickly (by skipping the +// free page list preload). +func (db *boltdb) open(readOnly bool) (err error) { + defer func() { + if err != nil { + // If the initialization fails, initialized components + // should be de-initialized gracefully. + db.shutdown() + } + }() + + if err = os.MkdirAll(db.config.DataDir, 0755); err != nil { + return fmt.Errorf("db dir: %w", err) + } + + if db.path == "" { + db.path = filepath.Join(db.config.DataDir, boltDBFileName) + } + + opts := *bbolt.DefaultOptions + // open is called with readOnly=true to verify the snapshot integrity. + opts.ReadOnly = readOnly + opts.PreLoadFreelist = !readOnly + if !readOnly { + // If we open the DB for restoration/compaction, we don't need + // a large mmap size as no writes are performed. + opts.InitialMmapSize = boltDBInitialMmapSize + } + // Because of the nature of the metastore, we do not need to sync + // the database: the state is always restored from the snapshot. + opts.NoSync = true + opts.NoGrowSync = true + opts.NoFreelistSync = true + opts.FreelistType = bbolt.FreelistMapType + if db.boltdb, err = bbolt.Open(db.path, 0644, &opts); err != nil { + return fmt.Errorf("failed to open db: %w", err) + } + + return nil +} + +func (db *boltdb) shutdown() { + if db.boltdb != nil { + if err := db.boltdb.Sync(); err != nil { + level.Error(db.logger).Log("msg", "failed to sync database", "err", err) + } + if err := db.boltdb.Close(); err != nil { + level.Error(db.logger).Log("msg", "failed to close database", "err", err) + } + } +} + +func (db *boltdb) restore(snapshot io.Reader) error { + start := time.Now() + defer func() { + db.metrics.boltDBRestoreSnapshotDuration.Observe(time.Since(start).Seconds()) + }() + + path, err := db.copySnapshot(snapshot) + if err != nil { + _ = os.RemoveAll(path) + return fmt.Errorf("failed to copy snapshot: %w", err) + } + + // Open in Read-Only mode to ensure the snapshot is not corrupted. + restored := &boltdb{ + logger: db.logger, + metrics: db.metrics, + config: db.config, + path: path, + } + if err = restored.open(true); err != nil { + restored.shutdown() + if removeErr := os.RemoveAll(restored.path); removeErr != nil { + level.Error(db.logger).Log("msg", "failed to remove compacted snapshot", "err", removeErr) + } + return fmt.Errorf("failed to open restored snapshot: %w", err) + } + + if !db.config.SnapshotCompactOnRestore { + restored.shutdown() + return db.openPath(path) + } + + // Snapshot is a full copy of the database, therefore we copy + // it on disk, compact, and use it instead of the current database. + // Compacting the snapshot is necessary to reclaim the space + // that the source database no longer has use for. This is rather + // wasteful to do it at restoration time, but it helps to reduce + // the footprint and latencies caused by the snapshot capturing. + // Ideally, this should be done in the background, outside the + // snapshot-restore path; however, this will require broad locks + // and will impact the transactions. + compacted, compactErr := restored.compact() + // Regardless of the compaction result, we need to close the restored + // db as we're going to either remove it (and use the compacted version), + // or move it and open for writes. + restored.shutdown() + if compactErr != nil { + // If compaction failed, we want to try the original snapshot. + // It's know that it is not corrupted, but it may be larger. + // For clarity: this step is not required (path == restored.path). + path = restored.path + level.Error(db.logger).Log("msg", "failed to compact boltdb; skipping compaction", "err", compactErr) + if compacted != nil { + level.Warn(db.logger).Log("msg", "trying to delete compacted snapshot", "path", compacted.path) + if removeErr := os.RemoveAll(compacted.path); removeErr != nil { + level.Error(db.logger).Log("msg", "failed to remove compacted snapshot", "err", removeErr) + } + } + } else { + // If compaction succeeded, we want to remove the restored snapshot. + path = compacted.path + if removeErr := os.RemoveAll(restored.path); removeErr != nil { + level.Error(db.logger).Log("msg", "failed to remove restored snapshot", "err", removeErr) + } + } + + return db.openPath(path) +} + +func (db *boltdb) copySnapshot(snapshot io.Reader) (path string, err error) { + path = filepath.Join(db.config.DataDir, boltDBSnapshotName) + level.Info(db.logger).Log("msg", "copying snapshot", "path", path) + snapFile, err := os.Create(path) + if err != nil { + return "", err + } + _, err = io.Copy(snapFile, snapshot) + if syncErr := syncFD(snapFile); err == nil { + err = syncErr + } + return path, err +} + +func (db *boltdb) compact() (compacted *boltdb, err error) { + level.Info(db.logger).Log("msg", "compacting snapshot") + src := db.boltdb + compacted = &boltdb{ + logger: db.logger, + metrics: db.metrics, + config: db.config, + path: filepath.Join(db.config.DataDir, boltDBCompactedName), + } + if err = os.RemoveAll(compacted.path); err != nil { + return nil, fmt.Errorf("compacted db path cannot be deleted: %w", err) + } + if err = compacted.open(false); err != nil { + return nil, fmt.Errorf("failed to create db for compaction: %w", err) + } + defer compacted.shutdown() + dst := compacted.boltdb + if err = bbolt.Compact(dst, src, boltDBCompactionMaxTxnSize); err != nil { + return nil, fmt.Errorf("failed to compact db: %w", err) + } + level.Info(db.logger).Log("msg", "boltdb compaction ratio", "ratio", float64(compacted.size())/float64(db.size())) + return compacted, nil +} + +func (db *boltdb) size() int64 { + fi, err := os.Stat(db.path) + if err != nil { + return 0 + } + return fi.Size() +} + +func (db *boltdb) openPath(path string) (err error) { + db.shutdown() + if err = os.Rename(path, db.path); err != nil { + return err + } + if err = syncPath(db.path); err != nil { + return err + } + return db.open(false) +} + +func syncPath(path string) (err error) { + d, err := os.Open(path) + if err != nil { + return err + } + return syncFD(d) +} + +func syncFD(f *os.File) (err error) { + err = f.Sync() + if closeErr := f.Close(); err == nil { + return closeErr + } + return err +} diff --git a/pkg/metastore/fsm/boltdb_test.go b/pkg/metastore/fsm/boltdb_test.go new file mode 100644 index 0000000000..167f168238 --- /dev/null +++ b/pkg/metastore/fsm/boltdb_test.go @@ -0,0 +1,104 @@ +package fsm + +import ( + "bytes" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/go-kit/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" +) + +func TestBoltDB_open_restore(t *testing.T) { + tempDir := t.TempDir() + buf := bytes.NewBuffer(nil) + db := newDB(log.NewLogfmtLogger(buf), newMetrics(nil), Config{DataDir: tempDir}) + require.NoError(t, db.open(false)) + + data := []string{ + "k1", "v1", + "k2", "v2", + "k3", "v3", + } + + snapshotSource := filepath.Join(tempDir, "snapshot_source") + require.NoError(t, createDB(t, snapshotSource, data).Close()) + s, err := os.ReadFile(snapshotSource) + require.NoError(t, err) + require.NoError(t, db.restore(bytes.NewReader(s))) + + collected := make([]string, 0, len(data)) + require.NoError(t, db.boltdb.View(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte("test")) + assert.NotNil(t, b) + return b.ForEach(func(k, v []byte) error { + collected = append(collected, string(k), string(v)) + return nil + }) + })) + + assert.Equal(t, data, collected) + assert.False(t, strings.Contains(buf.String(), "compacting snapshot")) +} + +func TestBoltDB_open_restore_compact(t *testing.T) { + tempDir := t.TempDir() + buf := bytes.NewBuffer(nil) + db := newDB(log.NewLogfmtLogger(buf), newMetrics(nil), Config{ + DataDir: tempDir, + SnapshotCompactOnRestore: true, + }) + require.NoError(t, db.open(false)) + + data := []string{ + "k1", "v1", + "k2", "v2", + "k3", "v3", + } + + snapshotSource := filepath.Join(tempDir, "snapshot_source") + require.NoError(t, createDB(t, snapshotSource, data).Close()) + s, err := os.ReadFile(snapshotSource) + require.NoError(t, err) + require.NoError(t, db.restore(bytes.NewReader(s))) + + collected := make([]string, 0, len(data)) + require.NoError(t, db.boltdb.View(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte("test")) + assert.NotNil(t, b) + return b.ForEach(func(k, v []byte) error { + collected = append(collected, string(k), string(v)) + return nil + }) + })) + + assert.Equal(t, data, collected) + assert.True(t, strings.Contains(buf.String(), "compacting snapshot")) +} + +func createDB(t *testing.T, path string, pairs []string) *bbolt.DB { + opts := bbolt.Options{ + NoGrowSync: true, + NoFreelistSync: true, + NoSync: true, + FreelistType: bbolt.FreelistMapType, + } + db, err := bbolt.Open(path, 0644, &opts) + require.NoError(t, err) + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + bucket, err := tx.CreateBucketIfNotExists([]byte("test")) + require.NoError(t, err) + for len(pairs) > 1 { + if err = bucket.Put([]byte(pairs[0]), []byte(pairs[1])); err != nil { + return err + } + pairs = pairs[2:] + } + return nil + })) + return db +} diff --git a/pkg/metastore/fsm/fsm.go b/pkg/metastore/fsm/fsm.go new file mode 100644 index 0000000000..e87959a311 --- /dev/null +++ b/pkg/metastore/fsm/fsm.go @@ -0,0 +1,394 @@ +package fsm + +import ( + "context" + "encoding/binary" + "flag" + "fmt" + "io" + "strconv" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" + "go.etcd.io/bbolt" + "go.etcd.io/bbolt/errors" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/proto" + + "github.com/grafana/pyroscope/v2/pkg/metastore/tracing" +) + +type ContextRegistry interface { + Retrieve(id string) (context.Context, bool) + Delete(id string) + Size() int +} + +// RaftHandler is a function that processes a Raft command. +// The implementation MUST be idempotent. +// The context parameter is used for tracing purposes and is only available on the leader. +type RaftHandler[Req, Resp proto.Message] func(context.Context, *bbolt.Tx, *raft.Log, Req) (Resp, error) + +// StateRestorer is called during the FSM initialization +// to restore the state from a snapshot. +// The implementation MUST be idempotent. +type StateRestorer interface { + // Init is provided with a write transaction to initialize the state. + // FSM guarantees that Init is called synchronously and has exclusive + // access to the database. + Init(*bbolt.Tx) error + // Restore is provided with a read transaction to restore the state. + // Restore might be called concurrently with other StateRestorer + // instances. + Restore(*bbolt.Tx) error +} + +type Config struct { + SnapshotCompression string `yaml:"snapshot_compression" category:"advanced"` + SnapshotRateLimit int `yaml:"snapshot_rate_limit" category:"advanced"` + SnapshotCompactOnRestore bool `yaml:"snapshot_compact_on_restore" category:"advanced"` + // Where the FSM BoltDB data is located. + // Does not have to be a persistent volume. + DataDir string `yaml:"data_dir"` +} + +func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.StringVar(&cfg.SnapshotCompression, prefix+"snapshot-compression", "zstd", "Compression algorithm to use for snapshots. Supported compressions: zstd.") + f.IntVar(&cfg.SnapshotRateLimit, prefix+"snapshot-rate-limit", 15, "Rate limit for snapshot writer in MB/s.") + f.BoolVar(&cfg.SnapshotCompactOnRestore, prefix+"snapshot-compact-on-restore", false, "Compact the database on restore.") + f.StringVar(&cfg.DataDir, prefix+"data-dir", "./data/v2/metastore/data", "Directory to store the data.") +} + +// FSM implements the raft.FSM interface. +type FSM struct { + logger log.Logger + config Config + contextRegistry ContextRegistry + metrics *metrics + + mu sync.RWMutex + txns sync.WaitGroup + db *boltdb + + handlers map[RaftLogEntryType]handler + restorers []StateRestorer + + appliedTerm uint64 + appliedIndex uint64 +} + +type handler func(ctx context.Context, tx *tracingTx, cmd *raft.Log, raw []byte) (proto.Message, error) + +func New(logger log.Logger, reg prometheus.Registerer, config Config, contextRegistry ContextRegistry) (*FSM, error) { + fsm := FSM{ + logger: logger, + config: config, + contextRegistry: contextRegistry, + metrics: newMetrics(reg), + handlers: make(map[RaftLogEntryType]handler), + } + db := newDB(logger, fsm.metrics, config) + if err := db.open(false); err != nil { + return nil, err + } + fsm.db = db + return &fsm, nil +} + +func (fsm *FSM) RegisterRestorer(r ...StateRestorer) { + fsm.restorers = append(fsm.restorers, r...) +} + +func RegisterRaftCommandHandler[Req, Resp proto.Message](fsm *FSM, t RaftLogEntryType, handler RaftHandler[Req, Resp]) { + fsm.handlers[t] = func(ctx context.Context, tx *tracingTx, cmd *raft.Log, raw []byte) (proto.Message, error) { + req, err := unmarshal[Req](raw) + if err != nil { + return nil, err + } + return handler(ctx, tx.Tx, cmd, req) + } +} + +// Init must be called after the FSM is created and all restorers are registered. +func (fsm *FSM) Init() error { + if err := fsm.init(); err != nil { + return fmt.Errorf("failed to initialize state: %w", err) + } + if err := fsm.restore(); err != nil { + return fmt.Errorf("failed to restore state: %w", err) + } + return nil +} + +func (fsm *FSM) init() (err error) { + tx, err := fsm.db.boltdb.Begin(true) + if err != nil { + return err + } + defer func() { + if err == nil { + err = tx.Commit() + } else { + _ = tx.Rollback() + } + }() + if err = fsm.initRaftBucket(tx); err != nil { + return fmt.Errorf("failed to init raft bucket: %w", err) + } + for _, r := range fsm.restorers { + if err = r.Init(tx); err != nil { + return err + } + } + return nil +} + +func (fsm *FSM) restore() error { + if err := fsm.db.boltdb.View(fsm.loadAppliedIndex); err != nil { + return fmt.Errorf("failed to load applied index: %w", err) + } + level.Info(fsm.logger).Log("msg", "restoring state", "term", fsm.appliedTerm, "applied_index", fsm.appliedIndex) + g, _ := errgroup.WithContext(context.Background()) + for _, r := range fsm.restorers { + g.Go(func() error { + return fsm.db.boltdb.View(r.Restore) + }) + } + return g.Wait() +} + +// Restore restores the FSM state from a snapshot. +func (fsm *FSM) Restore(snapshot io.ReadCloser) (err error) { + start := time.Now() + level.Info(fsm.logger).Log("msg", "restoring snapshot") + defer func() { + _ = snapshot.Close() + fsm.db.metrics.fsmRestoreSnapshotDuration.Observe(time.Since(start).Seconds()) + }() + + var r *snapshotReader + if r, err = newSnapshotReader(snapshot); err != nil { + level.Error(fsm.logger).Log("msg", "failed to create snapshot reader", "err", err) + return err + } + // The wrapper never returns errors on Close. + defer r.Close() + + // Block all new transactions until we restore the snapshot. + // TODO(kolesnikovae): set not-serving service status to not + // block incoming requests. + fsm.mu.Lock() + defer fsm.mu.Unlock() + fsm.txns.Wait() + if err = fsm.db.restore(r); err != nil { + level.Error(fsm.logger).Log("msg", "failed to restore database from snapshot", "err", err) + return err + } + // First we need to initialize the state: each restorer is called + // synchronously and has exclusive access to the database. + if err = fsm.init(); err != nil { + level.Error(fsm.logger).Log("msg", "failed to init state at restore", "err", err) + return err + } + // Then we restore the state: each restorer is given its own + // transaction and run concurrently with others. + if err = fsm.restore(); err != nil { + level.Error(fsm.logger).Log("msg", "failed to restore state from snapshot", "err", err) + return err + } + return nil +} + +type fsmError struct { + cmd *raft.Log + err error +} + +func errResponse(cmd *raft.Log, err error) Response { + return Response{Err: &fsmError{cmd: cmd, err: err}} +} + +func (e *fsmError) Error() string { + if e.err == nil { + return "" + } + if e.cmd == nil { + return e.err.Error() + } + return fmt.Sprintf("term: %d; index: %d; appended_at: %v; error: %v", + e.cmd.Index, e.cmd.Term, e.cmd.AppendedAt, e.err) +} + +func (fsm *FSM) Apply(log *raft.Log) any { + switch log.Type { + case raft.LogNoop: + case raft.LogBarrier: + case raft.LogConfiguration: + case raft.LogCommand: + return fsm.applyCommand(log) + default: + level.Warn(fsm.logger).Log("msg", "unexpected log entry, ignoring", "type", log.Type.String()) + } + return nil +} + +// applyCommand receives raw command from the raft log (FSM.Apply), +// and calls the corresponding handler on the _local_ FSM, based on +// the command type. +func (fsm *FSM) applyCommand(cmd *raft.Log) any { + start := time.Now() + var e RaftLogEntry + if err := e.UnmarshalBinary(cmd.Data); err != nil { + return errResponse(cmd, err) + } + + ctx := context.Background() + if ctxID := string(cmd.Extensions); ctxID != "" { + var found bool + if ctx, found = fsm.contextRegistry.Retrieve(ctxID); found { + defer fsm.contextRegistry.Delete(ctxID) + } + } + + span, ctx := tracing.StartSpanFromContext(ctx, "fsm.applyCommand") + defer span.Finish() + + if cmd.Index <= fsm.appliedIndex { + // Skip already applied commands at WAL restore. + // Note that the 0 index is a noop and is never applied to FSM. + return Response{} // todo this may result in nil deref if client does not exepect Response.Data to be nil , for example (svc *CompactionService) PollCompactionJobs + } + + cmdType := strconv.FormatUint(uint64(e.Type), 10) + fsm.db.metrics.fsmApplyCommandSize.WithLabelValues(cmdType).Observe(float64(len(cmd.Data))) + defer func() { + fsm.db.metrics.fsmApplyCommandDuration.WithLabelValues(cmdType).Observe(time.Since(start).Seconds()) + }() + + handle, ok := fsm.handlers[e.Type] + if !ok { + return errResponse(cmd, fmt.Errorf("unknown command type: %d", e.Type)) + } + + // Apply is never called concurrently with Restore, so we don't need + // to lock the FSM: db.boltdb is guaranteed to be in a consistent state. + rawTx, err := fsm.db.boltdb.Begin(true) + if err != nil { + panic(fmt.Sprint("failed to begin write transaction:", err)) + } + + txSpan, ctx := tracing.StartSpanFromContext(ctx, "boltdb.transaction") + txSpan.SetTag("writable", rawTx.Writable()) + tx := newTracingTx(rawTx, txSpan, ctx) + + data, err := handle(ctx, tx, cmd, e.Data) + if err != nil { + _ = tx.Rollback() + // NOTE(kolesnikovae): This has to be a hard failure as we assume + // that the in-memory state might have not been rolled back properly. + panic(fmt.Sprint("failed to apply command:", err)) + } + + if err = fsm.storeAppliedIndex(tx.Tx, cmd.Term, cmd.Index); err != nil { + panic(fmt.Sprint("failed to store applied index: %w", err)) + } + + // We can't do anything about the failure at the database level, so we + // panic here in a hope that other instances will handle the command. + if err = tx.Commit(); err != nil { + panic(fmt.Sprint("failed to commit transaction:", err)) + } + + return Response{Data: data, Err: err} +} + +func (fsm *FSM) Read(fn func(*bbolt.Tx)) error { + fsm.mu.RLock() + tx, err := fsm.db.boltdb.Begin(false) + fsm.txns.Add(1) + fsm.mu.RUnlock() + if err != nil { + fsm.txns.Done() + return fmt.Errorf("failed to begin read transaction: %w", err) + } + defer func() { + _ = tx.Rollback() + fsm.txns.Done() + }() + fn(tx) + return nil +} + +func (fsm *FSM) Snapshot() (raft.FSMSnapshot, error) { + // Snapshot should only capture a pointer to the state, and any + // expensive IO should happen as part of FSMSnapshot.Persist. + s := snapshotWriter{ + logger: fsm.logger, + metrics: fsm.metrics, + compression: fsm.config.SnapshotCompression, + rate: fsm.config.SnapshotRateLimit, + } + tx, err := fsm.db.boltdb.Begin(false) + if err != nil { + return nil, fmt.Errorf("failed to open a transaction for snapshot: %w", err) + } + s.tx = tx + return &s, nil +} + +func (fsm *FSM) Shutdown() { + if fsm.db.boltdb != nil { + fsm.db.shutdown() + } +} + +var ( + raftBucketName = []byte("raft") + appliedIndexKey = []byte("term.applied_index") + // Value is encoded as [8]term + [8]index. +) + +func (fsm *FSM) initRaftBucket(tx *bbolt.Tx) error { + b := tx.Bucket(raftBucketName) + if b != nil { + return nil + } + // If no bucket exists, we create a stub with 0 values. + if _, err := tx.CreateBucket(raftBucketName); err != nil { + return err + } + return fsm.storeAppliedIndex(tx, 0, 0) +} + +func (fsm *FSM) storeAppliedIndex(tx *bbolt.Tx, term, index uint64) error { + b := tx.Bucket(raftBucketName) + if b == nil { + return errors.ErrBucketNotFound + } + v := make([]byte, 16) + binary.BigEndian.PutUint64(v[0:8], term) + binary.BigEndian.PutUint64(v[8:16], index) + fsm.appliedTerm = term + fsm.appliedIndex = index + return b.Put(appliedIndexKey, v) +} + +var errAppliedIndexInvalid = fmt.Errorf("invalid applied index") + +func (fsm *FSM) loadAppliedIndex(tx *bbolt.Tx) error { + b := tx.Bucket(raftBucketName) + if b == nil { + return errors.ErrBucketNotFound + } + v := b.Get(appliedIndexKey) + if len(v) < 16 { + return errAppliedIndexInvalid + } + fsm.appliedTerm = binary.BigEndian.Uint64(v[0:8]) + fsm.appliedIndex = binary.BigEndian.Uint64(v[8:16]) + return nil +} diff --git a/pkg/metastore/fsm/log_entry.go b/pkg/metastore/fsm/log_entry.go new file mode 100644 index 0000000000..beffb7a2cc --- /dev/null +++ b/pkg/metastore/fsm/log_entry.go @@ -0,0 +1,84 @@ +package fsm + +import ( + "encoding/binary" + "fmt" + "reflect" + + "google.golang.org/protobuf/proto" +) + +var ErrInvalidCommand = fmt.Errorf("invalid command format; expected at least 4 bytes") + +type RaftLogEntryType uint32 + +type RaftLogEntry struct { + Type RaftLogEntryType + Data []byte +} + +type Response struct { + Data proto.Message + Err error +} + +func MarshalEntry(t RaftLogEntryType, payload proto.Message) ([]byte, error) { + b, err := marshal(payload) + if err != nil { + return nil, err + } + binary.BigEndian.PutUint32(b, uint32(t)) + return b, nil +} + +func (c *RaftLogEntry) UnmarshalBinary(b []byte) error { + if len(b) < 4 { + return ErrInvalidCommand + } + c.Type = RaftLogEntryType(binary.BigEndian.Uint32(b)) + c.Data = b[4:] + return nil +} + +type vtMarshaller interface { + MarshalToSizedBufferVT([]byte) (int, error) + SizeVT() int +} + +// marshal MUST allocate a buffer of size covering +// the whole message, including the entry header. +func marshal(v proto.Message) ([]byte, error) { + if m, ok := any(v).(vtMarshaller); ok { + size := m.SizeVT() + buf := make([]byte, size+4) + _, err := m.MarshalToSizedBufferVT(buf[4:]) + return buf, err + } + raw, err := proto.Marshal(v) + if err != nil { + return raw, err + } + buf := make([]byte, 4+len(raw)) + copy(buf[4:], raw) + return buf, err +} + +type vtUnmarshaler interface { + UnmarshalVT([]byte) error +} + +func newProto[T proto.Message]() T { + var msg T + msgType := reflect.TypeOf(msg).Elem() + return reflect.New(msgType).Interface().(T) +} + +func unmarshal[T proto.Message](b []byte) (v T, err error) { + v = newProto[T]() + if vt, ok := any(v).(vtUnmarshaler); ok { + err = vt.UnmarshalVT(b) + } else { + err = proto.Unmarshal(b, v) + } + return v, err +} diff --git a/pkg/metastore/fsm/metrics.go b/pkg/metastore/fsm/metrics.go new file mode 100644 index 0000000000..5f9751b343 --- /dev/null +++ b/pkg/metastore/fsm/metrics.go @@ -0,0 +1,76 @@ +package fsm + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type metrics struct { + boltDBPersistSnapshotDuration prometheus.Histogram + boltDBPersistSnapshotSize prometheus.Gauge + boltDBRestoreSnapshotDuration prometheus.Histogram + fsmRestoreSnapshotDuration prometheus.Histogram + fsmApplyCommandSize *prometheus.HistogramVec + fsmApplyCommandDuration *prometheus.HistogramVec +} + +func newMetrics(reg prometheus.Registerer) *metrics { + var dataTimingBuckets = prometheus.ExponentialBucketsRange(0.01, 20, 48) + m := &metrics{ + boltDBPersistSnapshotDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "boltdb_persist_snapshot_duration_seconds", + Buckets: dataTimingBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: time.Hour, + }), + + boltDBPersistSnapshotSize: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "boltdb_persist_snapshot_size_bytes", + }), + + boltDBRestoreSnapshotDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "boltdb_restore_snapshot_duration_seconds", + Buckets: dataTimingBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: time.Hour, + }), + + fsmRestoreSnapshotDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "fsm_restore_snapshot_duration_seconds", + Buckets: dataTimingBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: time.Hour, + }), + + fsmApplyCommandSize: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "fsm_apply_command_size_bytes", + Buckets: prometheus.ExponentialBucketsRange(8, 64<<10, 48), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"command"}), + + fsmApplyCommandDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "fsm_apply_command_duration_seconds", + Buckets: dataTimingBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"command"}), + } + if reg != nil { + util.RegisterOrGet(reg, m.boltDBPersistSnapshotSize) + util.RegisterOrGet(reg, m.boltDBPersistSnapshotDuration) + util.RegisterOrGet(reg, m.boltDBRestoreSnapshotDuration) + util.RegisterOrGet(reg, m.fsmRestoreSnapshotDuration) + util.RegisterOrGet(reg, m.fsmApplyCommandSize) + util.RegisterOrGet(reg, m.fsmApplyCommandDuration) + } + return m +} diff --git a/pkg/metastore/fsm/snapshot.go b/pkg/metastore/fsm/snapshot.go new file mode 100644 index 0000000000..02465caceb --- /dev/null +++ b/pkg/metastore/fsm/snapshot.go @@ -0,0 +1,136 @@ +package fsm + +import ( + "bufio" + "bytes" + "context" + "io" + "runtime/pprof" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/hashicorp/raft" + "github.com/klauspost/compress/zstd" + "go.etcd.io/bbolt" + + "github.com/grafana/pyroscope/v2/pkg/util/ratelimit" +) + +type snapshotWriter struct { + logger log.Logger + tx *bbolt.Tx + metrics *metrics + compression string + rate int +} + +func (s *snapshotWriter) Persist(sink raft.SnapshotSink) (err error) { + ctx := context.Background() + pprof.SetGoroutineLabels(pprof.WithLabels(ctx, pprof.Labels("metastore_op", "persist"))) + defer pprof.SetGoroutineLabels(ctx) + + start := time.Now() + level.Debug(s.logger).Log("msg", "persisting snapshot", "sink_id", sink.ID()) + defer func() { + s.metrics.boltDBPersistSnapshotDuration.Observe(time.Since(start).Seconds()) + if err == nil { + level.Info(s.logger).Log("msg", "persisted snapshot", "sink_id", sink.ID(), "duration", time.Since(start)) + if err = sink.Close(); err != nil { + level.Error(s.logger).Log("msg", "failed to close sink", "err", err) + } + return + } + level.Error(s.logger).Log("msg", "failed to persist snapshot", "err", err) + if err = sink.Cancel(); err != nil { + level.Error(s.logger).Log("msg", "failed to cancel snapshot sink", "err", err) + } + }() + + // Needed to measure the actual snapshot size written to the sink. + w := &writeCounter{Writer: sink} + var dst io.Writer = w + + // Optionally rate limit the snapshot writes to avoid overwhelming the disk. + // This is useful when the snapshot is written to the same disk as the WAL. + if s.rate > 0 { + const minRate = 10 // 10 MB/s + if s.rate < minRate { + s.rate = minRate + } + s.rate <<= 20 + dst = ratelimit.NewWriter(dst, ratelimit.NewLimiter(float64(s.rate))) + } + + if s.compression == "zstd" { + // We do not want to bog down the CPU with compression: we are fine with + // slowing down the snapshotting process, as it potentially may affect the + // WAL writes if they are located on the same disk. + var enc *zstd.Encoder + if enc, err = zstd.NewWriter(dst, zstd.WithEncoderConcurrency(1)); err != nil { + level.Error(s.logger).Log("msg", "failed to create zstd encoder", "err", err) + return err + } + defer func() { + if err = enc.Close(); err != nil { + level.Error(s.logger).Log("msg", "zstd compression failed", "err", err) + } + }() + // Wrap the writer with the encoder in the last turn: + // we want to apply the rate limiting to the sink, not + // the encoder. + dst = enc + } + + level.Info(s.logger).Log("msg", "persisting snapshot", "compression", s.compression, "rate_limit_mb", s.rate) + if _, err = s.tx.WriteTo(dst); err != nil { + level.Error(s.logger).Log("msg", "failed to write snapshot", "err", err) + return err + } + + s.metrics.boltDBPersistSnapshotSize.Set(float64(w.written)) + return nil +} + +type writeCounter struct { + io.Writer + written int64 +} + +func (w *writeCounter) Write(p []byte) (int, error) { + n, err := w.Writer.Write(p) + w.written += int64(n) + return n, err +} + +func (s *snapshotWriter) Release() { + if s.tx != nil { + // This is an in-memory rollback, no error expected. + _ = s.tx.Rollback() + } +} + +type snapshotReader struct { + io.ReadCloser +} + +var zstdMagic = []byte{0x28, 0xB5, 0x2F, 0xFD} + +func newSnapshotReader(snapshot io.ReadCloser) (*snapshotReader, error) { + b := bufio.NewReader(snapshot) + magic, err := b.Peek(4) + if err != nil { + return nil, err + } + + s := snapshotReader{ReadCloser: io.NopCloser(b)} + if bytes.Equal(magic, zstdMagic) { + var dec *zstd.Decoder + if dec, err = zstd.NewReader(b); err != nil { + return nil, err + } + s.ReadCloser = dec.IOReadCloser() + } + + return &s, nil +} diff --git a/pkg/metastore/fsm/tracing_tx.go b/pkg/metastore/fsm/tracing_tx.go new file mode 100644 index 0000000000..75de40b8fc --- /dev/null +++ b/pkg/metastore/fsm/tracing_tx.go @@ -0,0 +1,48 @@ +package fsm + +import ( + "context" + + "github.com/grafana/dskit/tracing" + "go.etcd.io/bbolt" +) + +// tracingTx wraps a BoltDB transaction to automatically trace transaction lifecycle. +// It holds a span that encompasses the entire transaction, providing visibility into +// transaction timing without requiring manual instrumentation. +// +// The span should be created by the caller and will be finished when the transaction +// is committed or rolled back. +type tracingTx struct { + *bbolt.Tx + span *tracing.Span + spanCtx context.Context // Context with the span, for child operations +} + +// newTracingTx creates a tracing transaction wrapper. +// The span parameter can be nil if no tracing is desired (e.g., on follower nodes). +func newTracingTx(tx *bbolt.Tx, span *tracing.Span, spanCtx context.Context) *tracingTx { + return &tracingTx{ + Tx: tx, + span: span, + spanCtx: spanCtx, + } +} + +// Commit commits the transaction and finishes the span. +func (t *tracingTx) Commit() error { + if t.span != nil { + defer t.span.Finish() + t.span.SetTag("operation", "commit") + } + return t.Tx.Commit() +} + +// Rollback rolls back the transaction and finishes the span. +func (t *tracingTx) Rollback() error { + if t.span != nil { + defer t.span.Finish() + t.span.SetTag("operation", "rollback") + } + return t.Tx.Rollback() +} diff --git a/pkg/metastore/index/README.md b/pkg/metastore/index/README.md new file mode 100644 index 0000000000..c06bfe5cd5 --- /dev/null +++ b/pkg/metastore/index/README.md @@ -0,0 +1,251 @@ +# Metadata Index + +The metadata index stores metadata entries for objects located in the data store. In essence, it is a document store built on top of a key-value database. + +It is implemented using BoltDB as the underlying key-value store, with Raft providing replication via consensus. BoltDB was chosen for its simplicity and efficiency in this use case – a single writer, concurrent readers, and ACID transactions. For better performance, the index database can be stored on an in-memory volume, as it's recovered from the Raft log and snapshot on startup, and durable storage is not required for the index itself. + +## Metadata entries + +Data objects, more widely called _blocks_ in the codebase, are stored in the data store (object storage) and are identified by a unique identifier (ULID). + +A block is a collection of _datasets_ that share certain properties, such as tenant and shard identifiers, time range, creation time, and more. Simplified, a metadata entry looks like this: + +```proto +struct BlockMeta { + uint32 format + string id + int32 tenant + uint32 shard + []Dataset datasets + []string string_table +} +``` + +```proto +struct Dataset { + uint32 format + int32 tenant + int32 name + []uint64 table_of_contents + []int32 labels +} +``` + +Datasets' content is defined by the `format` field, which indicates the binary format of the dataset. The `table_of_contents` field is a list of offsets that point to data sections within the dataset, allowing for efficient access to specific parts of the data. The table of contents is specific to the dataset format. + +Metadata labels allow specifying additional attributes than can be then used for filtering and querying. Labels are represented as a slice of `int32` values that refer to strings in the metadata entry's string table. The slice is a sequence of length-prefixed key-value (KV) pairs: + +``` +len(2) | k1 | v1 | k2 | v2 | len(3) | k1 | v3 | k2 | v4 | k3 | v5 +``` + +Refer to the [`BlockMeta`](../../../api/metastore/v1/types.proto) protobuf definition to learn more about the metadata format. + +The metadata entry is also included to the object itself, its offset is specified in the `metadata_offset` attribute. If the offset is not known, the metadata can be retrieved from the object using the footer structure: + +```it-is-not-meant-to-be-a-markdown-table +Offset | Size | Description +--------|------------|------------------------------------------ +0 | data | Object data +--------|------------|------------------------------------------ +data | metadata | Protobuf-encoded metadata +end-8 | be_uint32 | Size of the raw metadata +end-4 | be_uint32 | CRC32 of the raw metadata and size +``` + +## Structure + +The index is partitioned by time – each partition covers a 6-hour window. Within each partition, data is organized by tenant and shard: + +``` +Partition (6h window) +├── Tenant A +│ ├── Shard 0 +│ ├── Shard 1 +│ └── Shard N +└── Tenant B + ├── Shard 0 + └── Shard N +``` + +Metadata entries are stored in shard buckets as key-value pairs, where the key is the block ID (ULID) and the value is the serialized block metadata. The block identifier is a ULID, where the timestamp represents the block's creation time. However, blocks span data ranges defined by the actual timestamps of the data they contain (specified in the block metadata). When blocks are compacted together (merged), the output block identifier uses the timestamp of the oldest block in the input set and reflects the actual time range of the compacted data. + +Every block is assigned to a shard at [data distribution](../../ingester/client/distributor/README.md) time, and this assignment never changes. The assigned shard identifier is stored in the block metadata entry and is used to locate the block within the tenant bucket. + +Shard-level structures: +- To save space, strings in block metadata are deduplicated using a dictionary (`StringTable`). +- Each shard maintains a small index for efficient filtering (`ShardIndex`). + * The index indicates the time range of the shard's data (min and max timestamps). + +``` +Partition +└── Tenant + └── Shard + ├── .index + ├── .strings + ├── 01JYB4J3P5YFCZ80XRG11RMNEK => Block Metadata Entry + └── 01JYB4JNHARQZYPKR01W46EB54 => Block Metadata Entry +``` + +The index uses several caches for performance: +- The shard cache keeps shard indexes and string tables in memory. +- The block cache stores decoded metadata entries. + +## Index Writes + +Index writes are performed by the `segment-writer` service, which is responsible for writing metadata entries to the index. + +The write process spans multiple components and involves Raft consensus: + +```mermaid +sequenceDiagram + participant SW as segment-writer + + box Index Service + participant H as Endpoint + participant R as Raft + end + + box FSM + participant T as Tombstones + participant MI as Metadata Index + participant C as Compactor + end + + SW->>+H: AddBlock(BlockMeta) + H->>+R: Propose ADD_BLOCK_METADATA + R-->>+T: Exists? + Note over T: Reject if block was
already compacted + T-->>-R: + R->>MI: InsertBlock(BlockMeta) + MI-->>R: + R-->>+C: Compact + Note over C: Add block to
compaction queue + C-->>-R: + R-->>-H: + H-->>-SW: + +``` + +A tombstone check is necessary to prevent adding metadata for blocks that have already been compacted and removed from the index. This situation can occur if the writer fails to receive a response from the index, even though the entry was already added to a compaction and processed. During compaction, source objects are not removed immediately but only after a configured delay – long enough to cover the expected retry window. Refer to the [compaction](#compaction) paragraph for more details. + +### Dead Letter Queue + +If block metadata cannot be added to the index by the client, the metadata may be written to a DLQ in object storage. The recovery process scans for these entries every 15 seconds and attempts to re-add them to the index. Note that use of the DLQ may result in a "stale reads" phenomenon, in which a read fails to observe the effects of a completed write. If strongly consistent (linearizable) reads are required, the client should not use the DLQ. + +## Index Queries + +Queries access the index through the `ConsistentRead` API, which implements the _linearizable read_ pattern. This ensures that the replica reflects the most recent state agreed upon by the Raft consensus at the moment of access, and any previous writes are visible to the read operation. Refer to the [implementation](../raftnode/node_read.go) for details. The approach enables Raft _follower_ replicas to serve queries: in practice, both the leader and followers serve queries. + +Index queries are performed by the `query-frontend` service, which is responsible for locating data objects for a given query. + +```mermaid +sequenceDiagram + participant QF as query-frontend + + box Query Service + participant H as Endpoint + end + + box Raft + participant N as Local + participant L as Leader + end + + box FSM + participant MI as Metadata Index + end + + + QF->>+H: QueryMetadata(Query) + critical Liearizable Read + H->>N: ConsistentRead + N->>L: ReadIndex + Note over L: Leader check + L-->>N: CommitIndex + Term + Note over N: Wait CommitIndex applied + H->>+MI: QueryMetadata(Query) + Note over MI: Read state + MI-->>H: + N-->>H: + end + H-->>-QF: + +``` + +The `QueryService` offers two APIs: for metadata entry queries and for dataset label queries. + +The first API allows querying metadata entries based on various criteria, such as tenant, shard, time range, and labels with a Prometheus-like syntax. + +The second API provides a way to query dataset labels in the form of Prometheus series labels, without accessing the data objects themselves. For example, a typical query might list all dataset names or a subset of attributes. + +Example query: + +```go +query := MetadataQuery{ + Expr: `{service_name="frontend"}`, + StartTime: time.Now().Add(-time.Hour), + EndTime: time.Now(), + Tenant: []string{"tenant-1"}, + Labels: []string{"profile_type"} +} +``` + +The query will return all metadata entries with datasets that match the specified criteria and will preserve the `profile_type` label, if present. + +## Retention + +### Compaction + +Compaction is the process of merging multiple blocks into a single block to reduce the number of objects in the data store and improve query performance by consolidating data. This improves data locality and reduces the read amplification factor. Compaction is also crucial for the metadata index: without it, metastore performance quickly degrades over a short period of time (hours) and may become inoperable. Compaction is performed by the `compaction-worker` service, which is orchestrated by the Compaction Service implemented in the metastore. Refer to the [compaction documentation](../compaction/README.md) for more details. + +When compacted blocks are added to the index, metadata entries of the source blocks are replaced immediately, while the data objects are removed only after a configured delay to prevent interference with queries. Tombstone entries are created in the metastore to keep track of objects that need to be removed. Eventually, tombstones are included in a compaction job, and the compaction worker removes the source objects from the data store. + +### Retention Policies + +Retention policies are applied in a coarse-grained manner: individual blocks are not evaluated for deletion. Instead, entire partitions are removed when required by the retention configuration. A partition is identified by a key comprising its time range, tenant ID, and shard ID. + +#### Time-based Retention Policy + +Currently, only a time-based retention policy is implemented, which deletes partitions older than a specified duration. Retention is based on the block creation time to support data backfilling scenarios. However, data timestamps are also respected: a block is only removed if its upper boundary has passed the retention period. + +The time-based retention policies are tenant-specific and can be configured per tenant. + +### Cleanup + +The cleaner component, running on the Raft leader node, is responsible for enforcing the retention policies. It deletes partitions from the index and generates _tombstones_ that are handled later, during compaction. + +The diagram below illustrates the cleanup process: + +```mermaid +sequenceDiagram + participant C as cleaner + + box Index Service + participant H as Endpoint + participant R as Raft + end + + box FSM + participant MI as Metadata Index + participant T as Tombstones + end + + Note over C: Periodic cleanup trigger + C->>+H: TruncateIndex(policy) + critical + H->>MI: List partitions (ConsistentRead) + Note over MI: Read state + MI-->>H: + Note over H: Apply retention policy
Generate tombstones + H->>+R: Propose TRUNCATE_INDEX + R->>MI: Delete partitions + R->>T: Add tombstones + R-->>-H: + end + H-->>-C: +``` + +This is a two-phase process: + 1. The cleaner lists all partitions in the index and applies the retention policy to determine which partitions should be deleted. Unlike the `QueryService`, the cleaner can only read the local state, assuming that this is the Raft leader node: it still uses the `ConsistentRead` interface, however, it can only communicate with the local node. + 2. The cleaner proposes a Raft command to delete the partitions and generate _tombstones_ for the data objects that need to be removed. The proposal is rejected by followers if the leader has changed since the moment of the read operation. This ensures that the proposal reflects the most recent state of the index and was created by the acting leader, eliminating the possibility of conflicts. diff --git a/pkg/metastore/index/cleaner/cleaner.go b/pkg/metastore/index/cleaner/cleaner.go new file mode 100644 index 0000000000..f3878f91f7 --- /dev/null +++ b/pkg/metastore/index/cleaner/cleaner.go @@ -0,0 +1,118 @@ +package cleaner + +import ( + "context" + "errors" + "flag" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + + "github.com/grafana/pyroscope/v2/pkg/metastore/index/cleaner/retention" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" +) + +type Index interface { + TruncateIndex(context.Context, retention.Policy) error +} + +type Config struct { + CleanupMaxPartitions int `yaml:"cleanup_max_partitions" category:"advanced"` + CleanupGracePeriod time.Duration `yaml:"cleanup_grace_period" category:"advanced"` + CleanupInterval time.Duration `yaml:"cleanup_interval" category:"advanced"` +} + +const DefaultCleanupInterval = 15 * time.Minute + +func (c *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.DurationVar(&c.CleanupInterval, prefix+"cleanup-interval", DefaultCleanupInterval, "Interval for index cleanup check. 0 to disable.") + f.DurationVar(&c.CleanupGracePeriod, prefix+"cleanup-grace-period", time.Hour*6, "After a partition is eligible for deletion, it will be kept for this period before actually being evaluated. The period should cover the time difference between the block creation time and the data timestamps. Blocks are only deleted if all data in the block has passed the retention period, and the grace period delays the moment when the partition is evaluated for deletion.") + f.IntVar(&c.CleanupMaxPartitions, prefix+"cleanup-max-partitions", 32, "Maximum number of partitions to cleanup at once. A partition is qualified by partition key, tenant, and shard.") +} + +// Cleaner is responsible for periodically cleaning up +// the index by applying retention policies. As of now, +// it only applies the time-based retention policy. +type Cleaner struct { + logger log.Logger + overrides retention.Overrides + config Config + index Index + + started bool + cancel context.CancelFunc + mu sync.Mutex +} + +func NewCleaner(logger log.Logger, overrides retention.Overrides, config Config, index Index) *Cleaner { + return &Cleaner{ + logger: logger, + overrides: overrides, + config: config, + index: index, + } +} + +func (c *Cleaner) Start() { + if c.config.CleanupInterval == 0 { + return + } + c.mu.Lock() + defer c.mu.Unlock() + if c.started { + c.logger.Log("msg", "index cleaner already started") + return + } + ctx, cancel := context.WithCancel(context.Background()) + c.cancel = cancel + c.started = true + go c.loop(ctx) + c.logger.Log("msg", "index cleaner started") +} + +func (c *Cleaner) Stop() { + if c.config.CleanupInterval == 0 { + return + } + c.mu.Lock() + defer c.mu.Unlock() + if !c.started { + c.logger.Log("msg", "index cleaner already stopped") + return + } + if c.cancel != nil { + c.cancel() + } + c.started = false + c.logger.Log("msg", "index cleaner stopped") +} + +func (c *Cleaner) loop(ctx context.Context) { + ticker := time.NewTicker(c.config.CleanupInterval) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + rp := retention.NewTimeBasedRetentionPolicy( + log.With(c.logger, "component", "retention-policy"), + c.overrides, + c.config.CleanupMaxPartitions, + c.config.CleanupGracePeriod, + time.Now(), + ) + switch err := c.index.TruncateIndex(ctx, rp); { + case err == nil: + case errors.Is(err, context.Canceled): + return + case raftnode.IsRaftLeadershipError(err): + level.Warn(c.logger).Log("msg", "leadership change; cleanup interrupted", "err", err) + default: + level.Error(c.logger).Log("msg", "cleanup attempt failed", "err", err) + } + } + } +} diff --git a/pkg/metastore/index/cleaner/cleaner_test.go b/pkg/metastore/index/cleaner/cleaner_test.go new file mode 100644 index 0000000000..aa5da24347 --- /dev/null +++ b/pkg/metastore/index/cleaner/cleaner_test.go @@ -0,0 +1,27 @@ +package cleaner + +import ( + "flag" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestConfig_RegisterFlagsWithPrefix_DefaultCleanupInterval(t *testing.T) { + var cfg Config + fs := flag.NewFlagSet(t.Name(), flag.ContinueOnError) + cfg.RegisterFlagsWithPrefix("metastore.index.", fs) + + require.NoError(t, fs.Parse(nil)) + require.Equal(t, 15*time.Minute, cfg.CleanupInterval) +} + +func TestConfig_RegisterFlagsWithPrefix_ZeroCleanupIntervalDisablesCleanup(t *testing.T) { + var cfg Config + fs := flag.NewFlagSet(t.Name(), flag.ContinueOnError) + cfg.RegisterFlagsWithPrefix("metastore.index.", fs) + + require.NoError(t, fs.Parse([]string{"-metastore.index.cleanup-interval=0"})) + require.Zero(t, cfg.CleanupInterval) +} diff --git a/pkg/metastore/index/cleaner/retention/retention.go b/pkg/metastore/index/cleaner/retention/retention.go new file mode 100644 index 0000000000..c4c8390242 --- /dev/null +++ b/pkg/metastore/index/cleaner/retention/retention.go @@ -0,0 +1,306 @@ +package retention + +import ( + "flag" + "iter" + "math" + "slices" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/common/model" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" +) + +// Policy determines which parts of the index should be retained or deleted. +type Policy interface { + // CreateTombstones examines the provided partitions and returns tombstones + // for shards that should be deleted according to the policy. + CreateTombstones(*bbolt.Tx, iter.Seq[indexstore.Partition]) []*metastorev1.Tombstones +} + +type Config struct { + RetentionPeriod model.Duration `yaml:"retention_period" doc:"hidden"` +} + +type Overrides interface { + Retention() (defaults Config, overrides iter.Seq2[string, Config]) +} + +func (c *Config) RegisterFlags(f *flag.FlagSet) { + c.RetentionPeriod = model.Duration(time.Hour * 24 * 31) + f.Var(&c.RetentionPeriod, "retention-period", "Retention period for the data. 0 means data never deleted.") +} + +// TimeBasedRetentionPolicy implements a retention policy based on time. +type TimeBasedRetentionPolicy struct { + logger log.Logger + overrides map[string]*marker + gracePeriod time.Duration + maxTombstones int + + markers []*marker + defaultPeriod *marker + tombstones []*metastorev1.Tombstones +} + +type marker struct { + tenantID string + timestamp time.Time +} + +func NewTimeBasedRetentionPolicy( + logger log.Logger, + overrides Overrides, + maxTombstones int, + gracePeriod time.Duration, + now time.Time, +) *TimeBasedRetentionPolicy { + defaults, tenantOverrides := overrides.Retention() + rp := TimeBasedRetentionPolicy{ + logger: logger, + overrides: make(map[string]*marker), + tombstones: make([]*metastorev1.Tombstones, 0, maxTombstones), + maxTombstones: maxTombstones, + gracePeriod: gracePeriod, + } + // Markers indicate the time before which data should be deleted + // for a given tenant. + for tenantID, override := range tenantOverrides { + if defaults.RetentionPeriod == override.RetentionPeriod { + continue + } + // An override is defined for the tenant, so we need to adjust the + // retention period for it. By default, we assume that the retention + // period is not defined, i.e. is infinite. + var timestamp time.Time // zero value means no retention period. + if period := time.Duration(override.RetentionPeriod); period > 0 { + timestamp = now.Add(-period) + } + m := &marker{ + tenantID: tenantID, + timestamp: timestamp, + } + rp.markers = append(rp.markers, m) + rp.overrides[tenantID] = m + } + // The default retention period is handled separately: we won't create + // the marker if the retention period is not set. This allows us to avoid + // checking all partition tenant shards, and instead only check specific + // tenants that have a defined retention policy. + if defaults.RetentionPeriod > 0 { + rp.defaultPeriod = &marker{timestamp: now.Add(-time.Duration(defaults.RetentionPeriod))} + rp.markers = append(rp.markers, rp.defaultPeriod) + } + // It is fine if there are marker pointing to the same time: for example, + // if an override is set explicitly for a tenant, but it matches the + // default value. + slices.SortFunc(rp.markers, func(a, b *marker) int { + return a.timestamp.Compare(b.timestamp) + }) + + return &rp +} + +func (rp *TimeBasedRetentionPolicy) CreateTombstones(tx *bbolt.Tx, partitions iter.Seq[indexstore.Partition]) []*metastorev1.Tombstones { + if len(rp.markers) == 0 { + level.Debug(rp.logger).Log("msg", "no retention policies defined, skipping") + return nil + } + for _, m := range rp.markers { + level.Debug(rp.logger).Log("msg", "found retention marker", "tenant", m.tenantID, "timestamp", m.timestamp) + } + rp.tombstones = rp.tombstones[:0] + for p := range partitions { + if len(rp.tombstones) >= rp.maxTombstones { + break + } + if !rp.processPartition(tx, p) { + break + } + } + return rp.tombstones +} + +func (rp *TimeBasedRetentionPolicy) processPartition(tx *bbolt.Tx, p indexstore.Partition) bool { + // We want to find the markers that are before the partition end, i.e. the + // markers that indicate the time before which data should be deleted. For + // tenants D and E we need to inspect the partition. Otherwise, if there + // are no markers after the partition end, we stop. + // + // | partition | + // | start end | t + // ----------|----------------------x-------------> + // * * * * * + // markers: A B C D E + // + // Note that we also add a grace period to the partition end time, so that + // we won't be checking it for this period. Since tombstones are only + // created after the shard max time is before the marker timestamp, and the + // distance between them might be large (hours), we would be wasting time + // if were inspecting the partition right away. + partitionEnd := &marker{timestamp: p.EndTime().Add(rp.gracePeriod)} + logger := log.With(rp.logger, "partition", p.String()) + level.Debug(logger).Log( + "msg", "processing partition", + "partition_end_marker", partitionEnd.timestamp, + "retention_markers", len(rp.markers), + ) + + i, _ := slices.BinarySearchFunc(rp.markers, partitionEnd, func(a, b *marker) int { + return a.timestamp.Compare(b.timestamp) + }) + if i >= len(rp.markers) { + // All markers are before the partition end: it can't be deleted. + // We can stop here: no partitions after this one will have deletion + // markers that are before the partition end. + level.Debug(logger).Log("msg", "partition has not passed the retention period, skipping") + return false + } + + q := p.Query(tx) + if q == nil { + level.Warn(logger).Log("msg", "cannot find partition, skipping") + return true + } + + // The anonymous tenant is ignored here, we only collect tombstones for the + // specific tenants, which have a defined retention policy. + if rp.defaultPeriod == nil || rp.defaultPeriod.timestamp.Before(partitionEnd.timestamp) { + // Fast path for the case when there are markers very far in the future + // relatively the default marker, or no default marker at all. + // + // The default retention period has not expired yet, so we don't need + // to inspect all the tenants. Instead, we can just examine the markers + // that are after the partition end: these tenants have retention + // period shorter than the default one. This is useful in case if the + // tenant data is deleted by setting very short retention period: we + // won't check each and every partition tenant shard. + level.Debug(logger).Log("msg", "creating tombstones for tenant markers", "retention_markers", len(rp.markers[i:])) + rp.createTombstonesForMarkers(q, rp.markers[i:]) + } else { + // Otherwise, we need to inspect all the tenants in the partition. + // There's no point in checking the markers: either most of them + // will result in tombstones, or have already been deleted (e.g., + // there's one tenant with an infinite retention period). + level.Debug(logger).Log("msg", "creating tombstones for partition tenants") + rp.createTombstonesForTenants(q, partitionEnd) + } + + // Finally, we need to check if the anonymous tenant has any tombstones to + // collect. We only delete it if there are no other tenant shards in the + // partition: this guarantees that we don't delete data that is still + // needed, as we'd have the named tenant shards otherwise. Note that the + // tombstones we created this far are not resulted in the deletion of + // shards yet, so we will only delete the anonymous tenant on a second + // pass. + // + // NOTE(kolesnikovae): + // + // The approach may result in keeping the anonymous tenant data longer than + // necessary, but it should not be a problem in practice, as we assume that + // it contains no blocks: those are removed at L0 compaction. However, the + // shard-level structures such as tenant-shard buckets and string tables + // are not removed until the shard is deleted, which may also affect the + // index size. Ideally, we should seal partitions (create checkpoints) at + // some point that would protect it from modifications; then, we could + // delete the anon tenant shards safely, if there's no uncompacted data. + // + // An alternative approach would be to mark anon shards as we remove blocks + // from them, or create tombstones. We cannot do this as a side effect, to + // avoid state drift between the replicas (although this is arguable – such + // deletion is a side effect per se, and it only concerns the local state), + // but we can find the marks during the cleanup job. That could be + // implemented as a separate retention policy. + rp.createTombstonesForAnonTenant(q) + return len(rp.tombstones) < rp.maxTombstones +} + +func (rp *TimeBasedRetentionPolicy) createTombstonesForMarkers(q *indexstore.PartitionQuery, markers []*marker) { + for _, m := range markers { + if m.tenantID == "" { + continue + } + if !rp.createTombstones(q, m) { + return + } + } +} + +func (rp *TimeBasedRetentionPolicy) createTombstonesForTenants(q *indexstore.PartitionQuery, partitionEnd *marker) { + for tenantID := range q.Tenants() { + if tenantID == "" { + continue + } + var m *marker + if o, ok := rp.overrides[tenantID]; ok { + m = o + } else if rp.defaultPeriod != nil { + // Tenant-specific marker using the default retention period. + m = &marker{tenantID: tenantID, timestamp: rp.defaultPeriod.timestamp} + } else { + // No retention policy for this tenant, and no default: + // we retain the data indefinitely. + continue + } + if m.timestamp.After(partitionEnd.timestamp) { + if !rp.createTombstones(q, m) { + return + } + } + } +} + +func (rp *TimeBasedRetentionPolicy) createTombstonesForAnonTenant(q *indexstore.PartitionQuery) { + if rp.hasTenants(q) { + // We have at least one tenant other than the anonymous one. + // We cannot delete the anonymous tenant shard yet – continue. + return + } + // Once shard max time passes the partition end time, we can + // create tombstones for the anonymous tenant shard. + level.Debug(rp.logger).Log("msg", "creating tombstones for anonymous tenant") + // We want to bypass the timestamp check for the anonymous tenant: + // we know that if all the other tenants have been processed, it's + // safe to create tombstones for the anonymous tenant. + rp.createTombstones(q, &marker{timestamp: time.UnixMilli(math.MaxInt64)}) +} + +func (rp *TimeBasedRetentionPolicy) hasTenants(q *indexstore.PartitionQuery) bool { + var n int + for tenant := range q.Tenants() { + n++ + if n > 1 || tenant != "" { + return true + } + } + return false +} + +func (rp *TimeBasedRetentionPolicy) createTombstones(q *indexstore.PartitionQuery, m *marker) bool { + for shard := range q.Shards(m.tenantID) { + if len(rp.tombstones) >= rp.maxTombstones { + return false + } + maxTime := time.UnixMilli(shard.ShardIndex.MaxTime) + if maxTime.Before(m.timestamp) { + // The shard does not contain data after the marker. + name := shard.TombstoneName() + level.Debug(rp.logger).Log("msg", "creating tombstone", "name", name) + rp.tombstones = append(rp.tombstones, &metastorev1.Tombstones{ + Shard: &metastorev1.ShardTombstone{ + Name: name, + Timestamp: q.Timestamp.UnixNano(), + Duration: q.Duration.Nanoseconds(), + Shard: shard.Shard, + Tenant: shard.Tenant, + }, + }) + } + } + return true +} diff --git a/pkg/metastore/index/cleaner/retention/retention_test.go b/pkg/metastore/index/cleaner/retention/retention_test.go new file mode 100644 index 0000000000..33de0214ea --- /dev/null +++ b/pkg/metastore/index/cleaner/retention/retention_test.go @@ -0,0 +1,400 @@ +package retention + +import ( + "iter" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/prometheus/common/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +type mockOverrides struct { + defaultConfig Config + overrides map[string]Config +} + +func (m *mockOverrides) Retention() (Config, iter.Seq2[string, Config]) { + return m.defaultConfig, func(yield func(string, Config) bool) { + for k, v := range m.overrides { + if !yield(k, v) { + return + } + } + } +} + +type testBlock struct { + tenant string + shard uint32 + createdAt time.Time + minTime time.Time + maxTime time.Time +} + +func TestTimeBasedRetentionPolicy(t *testing.T) { + type testCase struct { + name string + defaultConfig Config + overrides map[string]Config + gracePeriod time.Duration + maxTombstones int + now time.Time + blocks []testBlock + expectedTombstones int + } + + now := test.Time("2024-01-01T00:00:00Z") + tests := []testCase{ + { + name: "no retention policies", + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 1, + createdAt: now.Add(-23 * time.Hour), + minTime: now.Add(-25 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + }, + }, + { + name: "no default retention policy but tenant override exists", + defaultConfig: Config{}, + overrides: map[string]Config{ + "tenant-1": {RetentionPeriod: model.Duration(12 * time.Hour)}, + }, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 1, + createdAt: now.Add(-23 * time.Hour), + minTime: now.Add(-25 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + { + tenant: "tenant-1", + shard: 2, + createdAt: now.Add(-22 * time.Hour), + minTime: now.Add(-24 * time.Hour), + maxTime: now.Add(-18 * time.Hour), + }, + { + tenant: "tenant-2", + shard: 1, + createdAt: now.Add(-25 * time.Hour), + minTime: now.Add(-26 * time.Hour), + maxTime: now.Add(-22 * time.Hour), + }, + }, + expectedTombstones: 2, + }, + { + name: "retention policy override shorter than partition", + defaultConfig: Config{RetentionPeriod: model.Duration(24 * time.Hour)}, + overrides: map[string]Config{ + "tenant-2": {RetentionPeriod: model.Duration(6 * time.Hour)}, + }, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-2", + shard: 1, + createdAt: now.Add(-9 * time.Hour), + minTime: now.Add(-9 * time.Hour), + maxTime: now.Add(-8 * time.Hour), + }, + }, + }, + { + name: "retention policy override shorter than default", + defaultConfig: Config{RetentionPeriod: model.Duration(24 * time.Hour)}, + overrides: map[string]Config{ + "tenant-2": {RetentionPeriod: model.Duration(4 * time.Hour)}, + }, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 2, + createdAt: now.Add(-18 * time.Hour), + minTime: now.Add(-18 * time.Hour), + maxTime: now.Add(-16 * time.Hour), + }, + { + tenant: "tenant-2", + shard: 1, + createdAt: now.Add(-12 * time.Hour), + minTime: now.Add(-12 * time.Hour), + maxTime: now.Add(-10 * time.Hour), + }, + }, + expectedTombstones: 1, + }, + { + name: "retention policy override longer than default", + defaultConfig: Config{RetentionPeriod: model.Duration(12 * time.Hour)}, + overrides: map[string]Config{ + "tenant-1": {RetentionPeriod: model.Duration(24 * time.Hour)}, + }, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", // Default. + shard: 1, + createdAt: now.Add(-16 * time.Hour), + minTime: now.Add(-16 * time.Hour), + maxTime: now.Add(-18 * time.Hour), + }, + }, + }, + { + name: "anonymous tenant retained due to other tenant shards", + defaultConfig: Config{RetentionPeriod: model.Duration(12 * time.Hour)}, + overrides: map[string]Config{ + "tenant-1": {RetentionPeriod: model.Duration(48 * time.Hour)}, + }, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 1, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + { + tenant: "tenant-2", // Default. + shard: 1, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + { + tenant: "", + shard: 1, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + }, + expectedTombstones: 1, + }, + { + name: "old partition with recent data is retained", + defaultConfig: Config{RetentionPeriod: model.Duration(12 * time.Hour)}, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 1, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-2 * time.Hour), + maxTime: now.Add(-time.Hour), + }, + }, + }, + { + name: "anonymous tenant deleted when no other tenant shards", + defaultConfig: Config{RetentionPeriod: model.Duration(12 * time.Hour)}, + overrides: map[string]Config{}, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "", + shard: 1, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + }, + expectedTombstones: 1, + }, + { + name: "max tombstones limit reached", + defaultConfig: Config{RetentionPeriod: model.Duration(12 * time.Hour)}, + overrides: map[string]Config{}, + gracePeriod: time.Hour, + maxTombstones: 2, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 1, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + { + tenant: "tenant-1", + shard: 2, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + { + tenant: "tenant-1", + shard: 3, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + }, + expectedTombstones: 2, + }, + { + name: "multiple tenant overrides with different retention periods", + defaultConfig: Config{RetentionPeriod: model.Duration(24 * time.Hour)}, + overrides: map[string]Config{ + "tenant-short": {RetentionPeriod: model.Duration(12 * time.Hour)}, + "tenant-infinite": {RetentionPeriod: 0}, + }, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-infinite", + shard: 1, + createdAt: now.Add(-180 * 24 * time.Hour), + minTime: now.Add(-180 * 24 * time.Hour), + maxTime: now.Add(-180*24*time.Hour + time.Hour), + }, + { + tenant: "tenant-short", + shard: 2, + createdAt: now.Add(-30 * time.Hour), + minTime: now.Add(-30 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + { + tenant: "default-tenant", + shard: 3, + createdAt: now.Add(-20 * time.Hour), + minTime: now.Add(-20 * time.Hour), + maxTime: now.Add(-18 * time.Hour), + }, + }, + expectedTombstones: 1, + }, + { + name: "zero retention period as override means infinite retention", + overrides: map[string]Config{ + "tenant-1": {RetentionPeriod: model.Duration(0)}, + }, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 1, + createdAt: now.Add(-23 * time.Hour), + minTime: now.Add(-25 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + }, + }, + { + name: "zero retention period as default means infinite retention", + defaultConfig: Config{RetentionPeriod: model.Duration(0)}, + gracePeriod: time.Hour, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "tenant-1", + shard: 1, + createdAt: now.Add(-23 * time.Hour), + minTime: now.Add(-25 * time.Hour), + maxTime: now.Add(-20 * time.Hour), + }, + }, + }, + { + name: "partition exactly at retention boundary", + defaultConfig: Config{RetentionPeriod: model.Duration(24 * time.Hour)}, + maxTombstones: 10, + now: now, + blocks: []testBlock{ + { + tenant: "default-tenant", + shard: 3, + createdAt: now.Add(-26 * time.Hour), + minTime: now.Add(-26 * time.Hour), + maxTime: now.Add(-24 * time.Hour), + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + db := test.BoltDB(t) + store := indexstore.NewIndexStore() + require.NoError(t, db.Update(store.CreateBuckets)) + defer db.Close() + + policy := NewTimeBasedRetentionPolicy( + log.NewNopLogger(), + &mockOverrides{ + defaultConfig: tc.defaultConfig, + overrides: tc.overrides, + }, + tc.maxTombstones, + tc.gracePeriod, + tc.now, + ) + + const partitionDuration = 6 * time.Hour + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + for _, block := range tc.blocks { + p := indexstore.NewPartition(block.createdAt.Truncate(partitionDuration), partitionDuration) + s := indexstore.NewShard(p, block.tenant, block.shard) + require.NoError(t, s.Store(tx, &metastorev1.BlockMeta{ + Id: test.ULID(block.createdAt.Format(time.RFC3339)), + Tenant: 1, + Shard: block.shard, + MinTime: block.minTime.UnixMilli(), + MaxTime: block.maxTime.UnixMilli(), + StringTable: []string{"", block.tenant}, + })) + } + return nil + })) + + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + // Multiple lines for better debugging. + partitions := store.Partitions(tx) + tombstones := policy.CreateTombstones(tx, partitions) + assert.Equal(t, tc.expectedTombstones, len(tombstones)) + return nil + })) + }) + } +} diff --git a/pkg/metastore/index/dlq/metrics.go b/pkg/metastore/index/dlq/metrics.go new file mode 100644 index 0000000000..b05e1c3cf6 --- /dev/null +++ b/pkg/metastore/index/dlq/metrics.go @@ -0,0 +1,29 @@ +package dlq + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type metrics struct { + recoveryAttempts *prometheus.CounterVec +} + +func newMetrics(reg prometheus.Registerer) *metrics { + m := &metrics{ + recoveryAttempts: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Subsystem: "metastore", + Name: "dlq_recovery_attempts_total", + Help: "Total number of DLQ block recovery attempts by status.", + }, + []string{"status"}, + ), + } + + if reg != nil { + reg.MustRegister(m.recoveryAttempts) + } + + return m +} diff --git a/pkg/metastore/index/dlq/recovery.go b/pkg/metastore/index/dlq/recovery.go new file mode 100644 index 0000000000..83e2f0ac69 --- /dev/null +++ b/pkg/metastore/index/dlq/recovery.go @@ -0,0 +1,181 @@ +package dlq + +import ( + "context" + "errors" + "flag" + "io" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" + "github.com/thanos-io/objstore" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" +) + +type Config struct { + CheckInterval time.Duration `yaml:"dlq_recovery_check_interval" category:"advanced"` +} + +func (c *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.DurationVar(&c.CheckInterval, prefix+"dlq-recovery-check-interval", 15*time.Second, "Dead Letter Queue check interval. 0 to disable.") +} + +type Metastore interface { + AddRecoveredBlock(context.Context, *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error) +} + +type Recovery struct { + config Config + logger log.Logger + metastore Metastore + bucket objstore.Bucket + metrics *metrics + + started bool + cancel func() + m sync.Mutex +} + +func NewRecovery(logger log.Logger, config Config, metastore Metastore, bucket objstore.Bucket, reg prometheus.Registerer) *Recovery { + return &Recovery{ + config: config, + logger: logger, + metastore: metastore, + bucket: bucket, + metrics: newMetrics(reg), + } +} + +func (r *Recovery) Start() { + if r.config.CheckInterval == 0 { + return + } + r.m.Lock() + defer r.m.Unlock() + if r.started { + r.logger.Log("msg", "recovery already started") + return + } + ctx, cancel := context.WithCancel(context.Background()) + r.cancel = cancel + r.started = true + go r.recoverLoop(ctx) + r.logger.Log("msg", "recovery started") +} + +func (r *Recovery) Stop() { + if r.config.CheckInterval == 0 { + return + } + r.m.Lock() + defer r.m.Unlock() + if !r.started { + r.logger.Log("msg", "recovery already stopped") + return + } + if r.cancel != nil { + r.cancel() + } + r.started = false + r.logger.Log("msg", "recovery stopped") +} + +func (r *Recovery) recoverLoop(ctx context.Context) { + ticker := time.NewTicker(r.config.CheckInterval) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + r.recoverTick(ctx) + } + } +} + +func (r *Recovery) recoverTick(ctx context.Context) { + err := r.bucket.Iter(ctx, block.DirNameDLQ, func(path string) error { + return r.recover(ctx, path) + }, objstore.WithRecursiveIter()) + if err != nil { + level.Error(r.logger).Log("msg", "failed to recover block metadata", "err", err) + } +} + +func (r *Recovery) recover(ctx context.Context, path string) (err error) { + defer func() { + if err == nil { + // In case we return no error, the block is considered recovered and will be deleted. + if delErr := r.bucket.Delete(ctx, path); delErr != nil { + level.Warn(r.logger).Log("msg", "failed to delete block metadata", "err", delErr, "path", path) + } + } + }() + + b, err := r.readObject(ctx, path) + switch { + case err == nil: + case errors.Is(err, context.Canceled): + r.metrics.recoveryAttempts.WithLabelValues("canceled").Inc() + return err + case r.bucket.IsObjNotFoundErr(err): + // This is somewhat opportunistic: the error is likely caused by a competing recovery + // process that has already recovered the block, before we've discovered that the + // leadership has changed. + r.metrics.recoveryAttempts.WithLabelValues("not_found").Inc() + level.Warn(r.logger).Log("msg", "block metadata not found; skipping", "path", path) + return nil + default: + // This is somewhat opportunistic, as we don't know if the error is transient or not. + // we should consider an explicit retry mechanism with backoff and a limit on the + // number of attempts. + r.metrics.recoveryAttempts.WithLabelValues("read_error").Inc() + level.Warn(r.logger).Log("msg", "failed to read block metadata; to be retried", "err", err, "path", path) + return err + } + + var meta metastorev1.BlockMeta + if err = meta.UnmarshalVT(b); err != nil { + r.metrics.recoveryAttempts.WithLabelValues("unmarshal_error").Inc() + level.Error(r.logger).Log("msg", "failed to unmarshal block metadata; skipping", "err", err, "path", path) + return nil + } + + switch _, err = r.metastore.AddRecoveredBlock(ctx, &metastorev1.AddBlockRequest{Block: &meta}); { + case err == nil: + r.metrics.recoveryAttempts.WithLabelValues("success").Inc() + level.Debug(r.logger).Log("msg", "successfully recovered block from DLQ", "block_id", meta.Id, "path", path) + return nil + case status.Code(err) == codes.InvalidArgument: + r.metrics.recoveryAttempts.WithLabelValues("invalid_metadata").Inc() + level.Error(r.logger).Log("msg", "block metadata rejected by metastore; skipping", "err", err, "block_id", meta.Id, "path", path) + return nil + case raftnode.IsRaftLeadershipError(err): + r.metrics.recoveryAttempts.WithLabelValues("leadership_change").Inc() + level.Warn(r.logger).Log("msg", "leadership change; recovery interrupted", "err", err, "path", path) + return err + default: + r.metrics.recoveryAttempts.WithLabelValues("metastore_error").Inc() + level.Error(r.logger).Log("msg", "failed to add block metadata; to be retried", "err", err, "path", path) + return err + } +} + +func (r *Recovery) readObject(ctx context.Context, path string) ([]byte, error) { + rc, err := r.bucket.Get(ctx, path) + if err != nil { + return nil, err + } + defer func() { + _ = rc.Close() + }() + return io.ReadAll(rc) +} diff --git a/pkg/metastore/index/dlq/recovery_test.go b/pkg/metastore/index/dlq/recovery_test.go new file mode 100644 index 0000000000..b2af6ac67c --- /dev/null +++ b/pkg/metastore/index/dlq/recovery_test.go @@ -0,0 +1,169 @@ +package dlq + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockdlq" +) + +func TestRecoverTick(t *testing.T) { + metas := []*metastorev1.BlockMeta{ + { + Id: test.ULID("2024-09-23T03:00:00Z"), + Shard: 2, + }, + { + Id: test.ULID("2024-09-23T01:00:00Z"), + Shard: 1, + }, + { + Id: test.ULID("2024-09-23T02:00:00Z"), + Shard: 2, + }, + } + + var actual []*metastorev1.BlockMeta + srv := mockdlq.NewMockMetastore(t) + srv.On("AddRecoveredBlock", mock.Anything, mock.Anything). + Times(3). + Run(func(args mock.Arguments) { + meta := args.Get(1).(*metastorev1.AddBlockRequest).Block + actual = append(actual, meta) + }). + Return(&metastorev1.AddBlockResponse{}, nil) + + bucket := memory.NewInMemBucket() + for _, meta := range metas { + addMeta(bucket, meta) + } + + r := NewRecovery(test.NewTestingLogger(t), Config{}, srv, bucket, prometheus.NewRegistry()) + r.recoverTick(context.Background()) + + expected := []*metastorev1.BlockMeta{ + metas[1], + metas[2], + metas[0], + } + + require.Equal(t, len(actual), len(expected)) + for i := range actual { + require.Equal(t, actual[i].Id, expected[i].Id) + require.Equal(t, actual[i].Shard, expected[i].Shard) + } + + assert.Equal(t, 3.0, testutil.ToFloat64(r.metrics.recoveryAttempts.WithLabelValues("success"))) + assert.Equal(t, 0.0, testutil.ToFloat64(r.metrics.recoveryAttempts.WithLabelValues("unmarshal_error"))) + assert.Equal(t, 0.0, testutil.ToFloat64(r.metrics.recoveryAttempts.WithLabelValues("invalid_metadata"))) +} + +func TestNotRaftLeader(t *testing.T) { + metas := []*metastorev1.BlockMeta{ + { + Id: test.ULID("2024-09-23T01:00:00Z"), + Shard: 2, + }, + } + + srv := mockdlq.NewMockMetastore(t) + s, _ := status.New(codes.Unavailable, "mock metastore error").WithDetails(&raftnodepb.RaftNode{ + Id: "foo", + Address: "bar", + }) + srv.On("AddRecoveredBlock", mock.Anything, mock.Anything). + Once(). + Return(nil, s.Err()) + + bucket := memory.NewInMemBucket() + for _, meta := range metas { + addMeta(bucket, meta) + } + + r := NewRecovery(test.NewTestingLogger(t), Config{}, srv, bucket, prometheus.NewRegistry()) + r.recoverTick(context.Background()) + + assert.Equal(t, 1, len(bucket.Objects())) + + assert.Equal(t, 1.0, testutil.ToFloat64(r.metrics.recoveryAttempts.WithLabelValues("metastore_error"))) + assert.Equal(t, 0.0, testutil.ToFloat64(r.metrics.recoveryAttempts.WithLabelValues("success"))) +} + +func TestStartStop(t *testing.T) { + metas := []*metastorev1.BlockMeta{ + { + Id: test.ULID("2024-09-23T03:00:00Z"), + Shard: 2, + }, + { + Id: test.ULID("2024-09-23T01:00:00Z"), + Shard: 1, + }, + { + Id: test.ULID("2024-09-23T02:00:00Z"), + Shard: 2, + }, + } + m := new(sync.Mutex) + + var actual []*metastorev1.BlockMeta + srv := mockdlq.NewMockMetastore(t) + srv.On("AddRecoveredBlock", mock.Anything, mock.Anything). + Times(3). + Run(func(args mock.Arguments) { + meta := args.Get(1).(*metastorev1.AddBlockRequest).Block + m.Lock() + actual = append(actual, meta) + m.Unlock() + }). + Return(&metastorev1.AddBlockResponse{}, nil) + + bucket := memory.NewInMemBucket() + for _, meta := range metas { + addMeta(bucket, meta) + } + + r := NewRecovery(test.NewTestingLogger(t), Config{CheckInterval: time.Millisecond * 10}, srv, bucket, prometheus.NewRegistry()) + r.Start() + defer r.Stop() + + require.Eventually(t, func() bool { + m.Lock() + defer m.Unlock() + return len(actual) == 3 + }, time.Second, time.Millisecond*100) + + expected := []*metastorev1.BlockMeta{ + metas[1], + metas[2], + metas[0], + } + + require.Equal(t, len(actual), len(expected)) + for i := range actual { + require.Equal(t, actual[i].Id, expected[i].Id) + require.Equal(t, actual[i].Shard, expected[i].Shard) + } + + assert.Equal(t, 3.0, testutil.ToFloat64(r.metrics.recoveryAttempts.WithLabelValues("success"))) +} + +func addMeta(bucket *memory.InMemBucket, meta *metastorev1.BlockMeta) { + data, _ := meta.MarshalVT() + bucket.Set(block.MetadataDLQObjectPath(meta), data) +} diff --git a/pkg/metastore/index/index.go b/pkg/metastore/index/index.go new file mode 100644 index 0000000000..00f071b625 --- /dev/null +++ b/pkg/metastore/index/index.go @@ -0,0 +1,300 @@ +package index + +import ( + "context" + "flag" + "fmt" + "iter" + "math" + "slices" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/oklog/ulid/v2" + "github.com/prometheus/client_golang/prometheus" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/cleaner" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/dlq" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +var ErrBlockExists = fmt.Errorf("block already exists") + +type Config struct { + ShardCacheSize int `yaml:"shard_cache_size" category:"advanced"` + BlockWriteCacheSize int `yaml:"block_write_cache_size" category:"advanced"` + BlockReadCacheSize int `yaml:"block_read_cache_size" category:"advanced"` + + Cleaner cleaner.Config `yaml:",inline"` + Recovery dlq.Config `yaml:",inline"` + + partitionDuration time.Duration + queryLookaroundPeriod time.Duration +} + +var DefaultConfig = Config{ + ShardCacheSize: 2000, // 128KB * 2000 = 256MB + BlockReadCacheSize: 100000, // 8KB blocks = 800MB + BlockWriteCacheSize: 10000, + + // FIXME(kolesnikovae): Do not modify, it will break the index. + // + // This parameter is not supported; used only for testing. + // Partition key MUST be an input parameter. + partitionDuration: 6 * time.Hour, + + // FIXME(kolesnikovae): Remove: build an interval tree. + // + // Currently, we do not use information about the time range of data each + // partition refers to. For example, it's possible – though very unlikely + // – for data from the past hour to be stored in a partition created a day + // ago. We need to be cautious: when querying, we must identify all + // partitions that may include the query time range. To ensure we catch + // such "misplaced" data, we extend the query time range using this period. + queryLookaroundPeriod: 24 * time.Hour, +} + +func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + cfg.Recovery.RegisterFlagsWithPrefix(prefix, f) + cfg.Cleaner.RegisterFlagsWithPrefix(prefix, f) + f.IntVar(&cfg.ShardCacheSize, prefix+"shard-cache-size", DefaultConfig.ShardCacheSize, "Maximum number of shards to keep in memory") + f.IntVar(&cfg.BlockWriteCacheSize, prefix+"block-write-cache-size", DefaultConfig.BlockWriteCacheSize, "Maximum number of written blocks to keep in memory") + f.IntVar(&cfg.BlockReadCacheSize, prefix+"block-read-cache-size", DefaultConfig.BlockReadCacheSize, "Maximum number of read blocks to keep in memory") + cfg.partitionDuration = DefaultConfig.partitionDuration + cfg.queryLookaroundPeriod = DefaultConfig.queryLookaroundPeriod +} + +type Store interface { + CreateBuckets(*bbolt.Tx) error + Partitions(tx *bbolt.Tx) iter.Seq[indexstore.Partition] + LoadShard(tx *bbolt.Tx, p indexstore.Partition, tenant string, shard uint32) (*indexstore.Shard, error) + LoadShardVersion(tx *bbolt.Tx, p indexstore.Partition, tenant string, shard uint32) (uint64, error) + DeleteShard(tx *bbolt.Tx, p indexstore.Partition, tenant string, shard uint32) error +} + +type Index struct { + logger log.Logger + config Config + store Store + shards *shardCache + blocks *blockCache +} + +func NewIndex(logger log.Logger, s Store, cfg Config, reg prometheus.Registerer) *Index { + m := newMetrics(reg) + return &Index{ + logger: logger, + config: cfg, + store: s, + shards: newShardCache(cfg.ShardCacheSize, s, m), + blocks: newBlockCache(cfg.BlockReadCacheSize, cfg.BlockWriteCacheSize, m), + } +} + +func NewStore() *indexstore.IndexStore { return indexstore.NewIndexStore() } + +func (i *Index) Init(tx *bbolt.Tx) error { return i.store.CreateBuckets(tx) } + +func (i *Index) Restore(tx *bbolt.Tx) error { + // See comment in DefaultConfig.queryLookaroundPeriod. + now := time.Now() + start := now.Add(-i.config.queryLookaroundPeriod) + end := now.Add(i.config.queryLookaroundPeriod) + for p := range i.store.Partitions(tx) { + if !p.Overlaps(start, end) { + continue + } + level.Info(i.logger).Log("msg", "loading partition in memory") + q := p.Query(tx) + if q == nil { + continue + } + for tenant := range q.Tenants() { + for shard := range q.Shards(tenant) { + if _, err := i.shards.getForWrite(tx, p, tenant, shard.Shard); err != nil { + level.Error(i.logger).Log( + "msg", "failed to load tenant partition shard", + "partition", p, + "tenant", tenant, + "shard", shard, + "err", err, + ) + return err + } + } + } + } + return nil +} + +func (i *Index) InsertBlock(tx *bbolt.Tx, b *metastorev1.BlockMeta) error { + p := i.partitionKeyForBlock(b.Id) + return i.shards.update(tx, p, metadata.Tenant(b), b.Shard, func(s *indexstore.Shard) error { + if err := s.Store(tx, b); err != nil { + return err + } + i.blocks.put(s, b) + return nil + }) +} + +func (i *Index) ReplaceBlocks(tx *bbolt.Tx, compacted *metastorev1.CompactedBlocks) error { + for _, b := range compacted.NewBlocks { + if err := i.InsertBlock(tx, b); err != nil { + return err + } + } + for p, list := range i.partitionedList(compacted.SourceBlocks) { + err := i.shards.update(tx, p, list.Tenant, list.Shard, func(s *indexstore.Shard) error { + if err := s.Delete(tx, list.Blocks...); err != nil { + return err + } + for _, b := range list.Blocks { + i.blocks.delete(s, b) + } + return nil + }) + if err != nil { + return err + } + } + return nil +} + +func (i *Index) GetBlocks(tx *bbolt.Tx, list *metastorev1.BlockList) ([]*metastorev1.BlockMeta, error) { + metas := make([]*metastorev1.BlockMeta, 0, len(list.Blocks)) + for k, partitioned := range i.partitionedList(list) { + version, err := i.store.LoadShardVersion(tx, k, partitioned.Tenant, partitioned.Shard) + if err != nil { + return nil, err + } + s, err := i.shards.getForReadAtVersion(tx, k, partitioned.Tenant, partitioned.Shard, version) + if err != nil { + return nil, err + } + for _, kv := range s.Find(tx, partitioned.Blocks...) { + b := i.blocks.getOrCreate(s, kv).CloneVT() + s.StringTable.Export(b) + metas = append(metas, b) + } + } + return metas, nil +} + +func (i *Index) Partitions(tx *bbolt.Tx) iter.Seq[indexstore.Partition] { + return i.store.Partitions(tx) +} + +func (i *Index) DeleteShard(tx *bbolt.Tx, key indexstore.Partition, tenant string, shard uint32) error { + if err := i.store.DeleteShard(tx, key, tenant, shard); err != nil { + return err + } + i.shards.delete(key, tenant, shard) + return nil +} + +func (i *Index) GetTenants(tx *bbolt.Tx) []string { + uniqueTenants := make(map[string]struct{}) + for p := range i.store.Partitions(tx) { + q := p.Query(tx) + if q == nil { + // Partition not found. + continue + } + for t := range q.Tenants() { + if t == "" { + continue + } + uniqueTenants[t] = struct{}{} + } + } + tenants := make([]string, 0, len(uniqueTenants)) + for t := range uniqueTenants { + tenants = append(tenants, t) + } + return tenants +} + +func (i *Index) GetTenantStats(tx *bbolt.Tx, tenant string) *metastorev1.TenantStats { + stats := &metastorev1.TenantStats{ + DataIngested: false, + OldestProfileTime: math.MaxInt64, + NewestProfileTime: math.MinInt64, + } + for p := range i.store.Partitions(tx) { + q := p.Query(tx) + if q == nil { + // Partition not found. + continue + } + for shard := range q.Shards(tenant) { + stats.DataIngested = true + oldest := shard.ShardIndex.MinTime + newest := shard.ShardIndex.MaxTime + if oldest < stats.OldestProfileTime { + stats.OldestProfileTime = oldest + } + if newest > stats.NewestProfileTime { + stats.NewestProfileTime = newest + } + } + } + if !stats.DataIngested { + return new(metastorev1.TenantStats) + } + return stats +} + +func (i *Index) QueryMetadata(tx *bbolt.Tx, ctx context.Context, query MetadataQuery) ([]*metastorev1.BlockMeta, error) { + q, err := newMetadataQuery(i, query) + if err != nil { + return nil, err + } + r, err := newBlockMetadataQuerier(tx, q).queryBlocks(ctx) + if err != nil { + return nil, err + } + return r, nil +} + +func (i *Index) QueryMetadataLabels(tx *bbolt.Tx, ctx context.Context, query MetadataQuery) ([]*typesv1.Labels, error) { + q, err := newMetadataQuery(i, query) + if err != nil { + return nil, err + } + c, err := newMetadataLabelQuerier(tx, q).queryLabels(ctx) + if err != nil { + return nil, err + } + l := slices.Collect(c.Unique()) + slices.SortFunc(l, model.CompareLabels) + return l, nil +} + +func (i *Index) partitionedList(list *metastorev1.BlockList) map[indexstore.Partition]*metastorev1.BlockList { + partitions := make(map[indexstore.Partition]*metastorev1.BlockList) + for _, b := range list.Blocks { + k := i.partitionKeyForBlock(b) + v := partitions[k] + if v == nil { + v = &metastorev1.BlockList{ + Shard: list.Shard, + Tenant: list.Tenant, + Blocks: make([]string, 0, len(list.Blocks)), + } + partitions[k] = v + } + v.Blocks = append(v.Blocks, b) + } + return partitions +} + +func (i *Index) partitionKeyForBlock(b string) indexstore.Partition { + return indexstore.NewPartition(ulid.Time(ulid.MustParse(b).Time()), i.config.partitionDuration) +} diff --git a/pkg/metastore/index/index_bench_test.go b/pkg/metastore/index/index_bench_test.go new file mode 100644 index 0000000000..799d382636 --- /dev/null +++ b/pkg/metastore/index/index_bench_test.go @@ -0,0 +1,113 @@ +package index + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +func BenchmarkIndex_GetTenantStats(b *testing.B) { + const ( + partitionDuration = 6 * time.Hour + numPartitions = 6 * 4 * 30 + numTenants = 100 + numShards = 1 + ) + + db := test.BoltDB(b) + defer func() { + require.NoError(b, db.Close()) + }() + + config := DefaultConfig + config.partitionDuration = partitionDuration + config.ShardCacheSize = 1000 + config.BlockReadCacheSize = 1000 + config.BlockWriteCacheSize = 1000 + + idx := NewIndex(util.Logger, NewStore(), config, nil) + require.NoError(b, db.Update(idx.Init)) + + startTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) + var blocks int + + for i := 0; i < numPartitions; i++ { + start := startTime.Add(time.Duration(i) * partitionDuration) + for j := 0; j < numTenants; j++ { + tenant := fmt.Sprintf("tenant-%03d", j) + for shard := 0; shard < numShards; shard++ { + ts := start.Add(time.Duration(shard) * time.Hour) + md := &metastorev1.BlockMeta{ + FormatVersion: 1, + Id: test.ULID(ts.Format(time.RFC3339)), + Tenant: 1, + Shard: uint32(shard), + MinTime: ts.UnixMilli(), + MaxTime: ts.Add(partitionDuration / 2).UnixMilli(), + StringTable: []string{"", tenant}, + } + err := db.Update(func(tx *bbolt.Tx) error { + return idx.InsertBlock(tx, md) + }) + require.NoError(b, err) + blocks++ + } + } + + if (i+1)%100 == 0 { + b.Logf("Created %d/%d partitions (%d blocks so far)", i+1, numPartitions, blocks) + } + } + + for _, tc := range []struct { + name string + tenant string + desc string + }{ + { + name: "ExistingTenant", + tenant: "tenant-000", + desc: "Tenant with data in all partitions", + }, + { + name: "MidTenant", + tenant: "tenant-050", + desc: "Tenant in the middle range", + }, + { + name: "LastTenant", + tenant: "tenant-099", + desc: "Last tenant in the range", + }, + { + name: "NonExistentTenant", + tenant: "tenant-999", + desc: "Tenant that doesn't exist", + }, + } { + b.Run(tc.name, func(b *testing.B) { + b.ResetTimer() + + for i := 0; i < b.N; i++ { + var stats *metastorev1.TenantStats + err := db.View(func(tx *bbolt.Tx) error { + stats = idx.GetTenantStats(tx, tc.tenant) + return nil + }) + require.NoError(b, err) + if tc.tenant != "tenant-999" { + require.True(b, stats.DataIngested) + require.NotEqual(b, int64(0), stats.OldestProfileTime) + require.NotEqual(b, int64(0), stats.NewestProfileTime) + } + } + }) + } +} diff --git a/pkg/metastore/index/index_cache.go b/pkg/metastore/index/index_cache.go new file mode 100644 index 0000000000..e83d68939c --- /dev/null +++ b/pkg/metastore/index/index_cache.go @@ -0,0 +1,266 @@ +package index + +import ( + "sync" + + lru "github.com/hashicorp/golang-lru/v2" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + kvstore "github.com/grafana/pyroscope/v2/pkg/metastore/store" +) + +// Shard cache. +// +// The cache helps us to avoid repeatedly reading the string table from +// the persistent store. Cached shards have a flag that indicates whether +// the shard was loaded for reads. Any write operation should invalidate +// the cached entry and reload it as it may violate transaction isolation. +// +// Writes are always sequential and never concurrent. Therefore, it's +// guaranteed that every write operation observes the latest state of +// the shard on disk. The cache introduces a possibility to observe +// a stale state in the cache, because of the concurrent reads that +// share the same cache. +// +// Reads are concurrent and may run in transactions that began before +// the ongoing write transaction. If a read transaction reads the shard +// state from the disk, its state is obsolete from the writer perspective, +// since it corresponds to an older transaction; if such state is cached, +// all participants may observe it. Therefore, we mark such shards as +// read-only to let the writer know about it. +// +// Reads may observe a state modified "in the future", by a write +// transaction that has started after the read transaction. This is fine, +// as "stale reads" are resolved at the raft level. It is not fine, +// however, if the write transaction uses the cached shard state, loaded +// by read transaction. +type shardCache struct { + mu sync.RWMutex + cache *lru.TwoQueueCache[shardCacheKey, *indexShardCached] + store Store + metrics *metrics +} + +type shardCacheKey struct { + partition indexstore.Partition + tenant string + shard uint32 +} + +type indexShardCached struct { + *indexstore.Shard + readOnly bool +} + +func newShardCache(size int, s Store, m *metrics) *shardCache { + if size <= 0 { + size = 1 + } + c, _ := lru.New2Q[shardCacheKey, *indexShardCached](size) + return &shardCache{cache: c, store: s, metrics: m} +} + +func (c *shardCache) update(tx *bbolt.Tx, p indexstore.Partition, tenant string, shard uint32, fn func(*indexstore.Shard) error) error { + c.mu.Lock() + defer c.mu.Unlock() + s, err := c.getForWriteUnsafe(tx, p, tenant, shard) + if err != nil { + return err + } + return fn(s) +} + +func (c *shardCache) getForWrite(tx *bbolt.Tx, p indexstore.Partition, tenant string, shard uint32) (*indexstore.Shard, error) { + c.mu.Lock() + defer c.mu.Unlock() + return c.getForWriteUnsafe(tx, p, tenant, shard) +} + +func (c *shardCache) getForWriteUnsafe(tx *bbolt.Tx, p indexstore.Partition, tenant string, shard uint32) (*indexstore.Shard, error) { + k := shardCacheKey{ + partition: p, + tenant: tenant, + shard: shard, + } + x, found := c.cache.Get(k) + if found && x != nil && !x.readOnly { + c.metrics.recordShardWriteHit() + return x.Shard, nil + } + c.metrics.recordShardWriteMiss() + // If the shard is not found, or it is loaded for reads, + // reload it and invalidate the cached version. + s, err := c.store.LoadShard(tx, p, tenant, shard) + if err != nil { + return nil, err + } + if s == nil { + s = indexstore.NewShard(p, tenant, shard) + } + c.cache.Add(k, &indexShardCached{ + Shard: s, + readOnly: false, + }) + return s, nil +} + +func (c *shardCache) getForReadAtVersion(tx *bbolt.Tx, p indexstore.Partition, tenant string, shard uint32, version uint64) (*indexstore.Shard, error) { + c.mu.Lock() + defer c.mu.Unlock() + k := shardCacheKey{ + partition: p, + tenant: tenant, + shard: shard, + } + x, found := c.cache.Get(k) + if found && x != nil { + // Write-cached shards are always safe to reuse because writes are + // serialized and observe the latest shard state. Read-cached shards are + // only safe when the caller has no version information (`version == 0`, + // for old on-disk shard indexes) or when the cached version is at least + // as new as the caller's transaction snapshot. Otherwise, reload from the + // current transaction to avoid mixing new block metadata with a stale + // string table loaded by an older read transaction. + if !x.readOnly || version == 0 || x.ShardIndex.Version >= version { + c.metrics.recordShardReadHit() + return x.ShallowCopy(), nil + } + } + c.metrics.recordShardReadMiss() + s, err := c.store.LoadShard(tx, p, tenant, shard) + if err != nil { + return nil, err + } + if s == nil { + // Returning an empty shard is fine, as this + // is a read operation. + return indexstore.NewShard(p, tenant, shard), nil + } + c.cache.Add(k, &indexShardCached{ + Shard: s, + readOnly: true, + }) + return s, nil +} + +func (c *shardCache) delete(p indexstore.Partition, tenant string, shard uint32) { + c.mu.Lock() + defer c.mu.Unlock() + k := shardCacheKey{partition: p, tenant: tenant, shard: shard} + c.cache.Remove(k) +} + +// Block cache. +// +// Metadata entries might be large, tens of kilobytes, depending on the number +// of datasets, labels, and other metadata. Therefore, we use block cache +// to avoid repeatedly decoding the serialized raw bytes. The cache does not +// require any special coordination, as it is accessed by keys, which are +// loaded from the disk in the current transaction. +// +// The cache is split into two parts: read and write. This is done to prevent +// cache pollution in case of compaction delays. +// +// The read cache is populated with blocks that are fully compacted and with +// blocks queried by the user. We use 2Q cache replacement strategy to ensure +// that the most recently read blocks are kept in memory, while frequently +// accessed older blocks are not evicted prematurely. +// +// The write cache is used to store blocks that are being written to the index. +// It is important because it's guaranteed that the block will be read soon for +// compaction. The write cache is accessed for reads if the read cache does not +// contain the block queried. +type blockCache struct { + mu sync.RWMutex + read *lru.TwoQueueCache[blockCacheKey, *metastorev1.BlockMeta] + write *lru.Cache[blockCacheKey, *metastorev1.BlockMeta] + metrics *metrics +} + +type blockCacheKey struct { + tenant string + shard uint32 + block string +} + +func newBlockCache(rcs, wcs int, m *metrics) *blockCache { + var c blockCache + if rcs <= 0 { + rcs = 1 + } + if wcs <= 0 { + wcs = 1 + } + c.read, _ = lru.New2Q[blockCacheKey, *metastorev1.BlockMeta](rcs) + c.write, _ = lru.New[blockCacheKey, *metastorev1.BlockMeta](wcs) + c.metrics = m + return &c +} + +func (c *blockCache) getOrCreate(shard *indexstore.Shard, block kvstore.KV) *metastorev1.BlockMeta { + k := blockCacheKey{ + tenant: shard.Tenant, + shard: shard.Shard, + block: string(block.Key), + } + c.mu.RLock() + v, ok := c.read.Get(k) + if ok { + c.mu.RUnlock() + c.metrics.recordBlockReadHit() + return v + } + v, ok = c.write.Get(k) + if ok { + c.mu.RUnlock() + c.metrics.recordBlockWriteHit() + return v + } + c.mu.RUnlock() + c.mu.Lock() + defer c.mu.Unlock() + v, ok = c.read.Get(k) + if ok { + c.metrics.recordBlockReadHit() + return v + } + v, ok = c.write.Get(k) + if ok { + c.metrics.recordBlockWriteHit() + return v + } + c.metrics.recordBlockMiss() + var md metastorev1.BlockMeta + if err := md.UnmarshalVT(block.Value); err != nil { + return &md + } + c.read.Add(k, &md) + return &md +} + +func (c *blockCache) put(shard *indexstore.Shard, md *metastorev1.BlockMeta) { + k := blockCacheKey{ + tenant: shard.Tenant, + shard: shard.Shard, + block: md.Id, + } + c.mu.Lock() + defer c.mu.Unlock() + if md.CompactionLevel >= 2 { + c.read.Add(k, md) + return + } + c.write.Add(k, md) +} + +func (c *blockCache) delete(shard *indexstore.Shard, block string) { + k := blockCacheKey{ + tenant: shard.Tenant, + shard: shard.Shard, + block: block, + } + c.write.Remove(k) + c.read.Remove(k) +} diff --git a/pkg/metastore/index/index_test.go b/pkg/metastore/index/index_test.go new file mode 100644 index 0000000000..85347cd117 --- /dev/null +++ b/pkg/metastore/index/index_test.go @@ -0,0 +1,413 @@ +package index + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +func TestIndex_PartitionList(t *testing.T) { + const testTenant = "tenant" + + t.Run("new shard", func(t *testing.T) { + db := test.BoltDB(t) + idx := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + require.NoError(t, db.Update(idx.Init)) + + shardID := uint32(42) + blockMeta := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-11T07:00:00.001Z"), + Tenant: 1, + Shard: shardID, + MinTime: test.UnixMilli("2024-09-11T07:00:00.000Z"), + MaxTime: test.UnixMilli("2024-09-11T09:00:00.000Z"), + CreatedBy: 1, + StringTable: []string{"", testTenant, "ingester"}, + } + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.InsertBlock(tx, blockMeta.CloneVT()) + })) + + p := indexstore.NewPartition(test.Time("2024-09-11T07:00:00.001Z"), idx.config.partitionDuration) + findPartition(t, db, idx, p) + shard := findShard(t, db, p, testTenant, shardID) + assert.Equal(t, blockMeta.MinTime, shard.ShardIndex.MinTime) + assert.Equal(t, blockMeta.MaxTime, shard.ShardIndex.MaxTime) + }) + + t.Run("shard update", func(t *testing.T) { + db := test.BoltDB(t) + idx := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + + p := indexstore.NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour) + tenant := testTenant + shardID := uint32(1) + + blockMeta := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-11T07:00:00.001Z"), + Tenant: 1, + Shard: shardID, + MinTime: test.UnixMilli("2024-09-11T07:00:00.000Z"), + MaxTime: test.UnixMilli("2024-09-11T09:00:00.000Z"), + CreatedBy: 1, + StringTable: []string{"", tenant, "ingester"}, + } + + require.NoError(t, db.Update(idx.Init)) + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.InsertBlock(tx, blockMeta.CloneVT()) + })) + + idx = NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + require.NoError(t, db.View(idx.Restore)) + + findPartition(t, db, idx, p) + shard := findShard(t, db, p, tenant, shardID) + assert.Equal(t, blockMeta.MinTime, shard.ShardIndex.MinTime) + assert.Equal(t, blockMeta.MaxTime, shard.ShardIndex.MaxTime) + + newBlockMeta := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-11T08:00:00.001Z"), + Tenant: 1, + Shard: shardID, + MinTime: test.UnixMilli("2024-09-11T06:30:00.000Z"), + MaxTime: test.UnixMilli("2024-09-11T10:00:00.000Z"), + CreatedBy: 1, + StringTable: []string{"", tenant, "ingester"}, + } + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.InsertBlock(tx, newBlockMeta.CloneVT()) + })) + + updated := findShard(t, db, p, tenant, shardID) + assert.Equal(t, newBlockMeta.MinTime, updated.ShardIndex.MinTime) + assert.Equal(t, newBlockMeta.MaxTime, updated.ShardIndex.MaxTime) + + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + s, err := idx.shards.getForReadAtVersion(tx, p, tenant, shardID, updated.ShardIndex.Version) + if err != nil { + return err + } + require.NotNil(t, s) + assert.Equal(t, s.ShardIndex.MinTime, updated.ShardIndex.MinTime) + assert.Equal(t, s.ShardIndex.MaxTime, updated.ShardIndex.MaxTime) + return nil + })) + }) +} + +func findPartition(t *testing.T, db *bbolt.DB, idx *Index, k indexstore.Partition) { + var p indexstore.Partition + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + for partition := range idx.Partitions(tx) { + if partition.Equal(k) { + p = partition + break + } + } + return nil + })) + assert.NotZero(t, p) +} + +func findShard(t *testing.T, db *bbolt.DB, partition indexstore.Partition, tenant string, shardID uint32) indexstore.Shard { + var s indexstore.Shard + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + for shard := range partition.Query(tx).Shards(tenant) { + if shard.Shard == shardID { + s = shard + break + } + } + return nil + })) + assert.NotZero(t, s) + return s +} + +func TestIndex_RestoreTimeBasedLoading(t *testing.T) { + db := test.BoltDB(t) + config := DefaultConfig + config.queryLookaroundPeriod = time.Hour + + idx := NewIndex(util.Logger, NewStore(), config, nil) + require.NoError(t, db.Update(idx.Init)) + + now := time.Now() + const testTenant = "test-tenant" + + t1 := now.Add(-30 * time.Minute) + t2 := now.Add(-25 * time.Hour) + t3 := now.Add(25 * time.Hour) + + blocks := []*metastorev1.BlockMeta{ + { + Id: test.ULID(t1.Format(time.RFC3339)), + Tenant: 1, + Shard: 1, + MinTime: t1.UnixMilli(), + MaxTime: now.Add(time.Hour).UnixMilli(), + StringTable: []string{"", testTenant}, + }, + + { + Id: test.ULID(t2.Format(time.RFC3339)), + Tenant: 1, + Shard: 2, + MinTime: t2.UnixMilli(), + MaxTime: t2.Add(time.Hour).UnixMilli(), + StringTable: []string{"", testTenant}, + }, + { + Id: test.ULID(t3.Format(time.RFC3339)), + Tenant: 1, + Shard: 3, + MinTime: t3.UnixMilli(), + MaxTime: t3.Add(time.Hour).UnixMilli(), + StringTable: []string{"", testTenant}, + }, + } + + for _, block := range blocks { + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.InsertBlock(tx, block) + })) + } + + idx = NewIndex(util.Logger, NewStore(), config, nil) + require.NoError(t, db.Update(idx.Restore)) + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + s, _ := idx.shards.cache.Get(shardCacheKey{indexstore.NewPartition(t1, config.partitionDuration), testTenant, 1}) + assert.NotNil(t, s) + s, _ = idx.shards.cache.Get(shardCacheKey{indexstore.NewPartition(t2, config.partitionDuration), testTenant, 2}) + assert.Nil(t, s) + s, _ = idx.shards.cache.Get(shardCacheKey{indexstore.NewPartition(t3, config.partitionDuration), testTenant, 3}) + assert.Nil(t, s) + return nil + })) +} + +func TestShardIterator_TimeFiltering(t *testing.T) { + db := test.BoltDB(t) + config := DefaultConfig + config.queryLookaroundPeriod = 0 + idx := NewIndex(util.Logger, NewStore(), config, nil) + require.NoError(t, db.Update(idx.Init)) + + tenant := "test" + blocks := []*metastorev1.BlockMeta{ + { + Id: test.ULID("2024-01-01T10:00:00.000Z"), + Tenant: 1, + Shard: 1, + MinTime: test.UnixMilli("2024-01-01T10:00:00.000Z"), + MaxTime: test.UnixMilli("2024-01-01T11:00:00.000Z"), + StringTable: []string{"", tenant}, + }, + { + Id: test.ULID("2024-01-01T12:00:00.000Z"), + Tenant: 1, + Shard: 2, + MinTime: test.UnixMilli("2024-01-01T12:00:00.000Z"), + MaxTime: test.UnixMilli("2024-01-01T13:00:00.000Z"), + StringTable: []string{"", tenant}, + }, + } + + for _, block := range blocks { + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { return idx.InsertBlock(tx, block) })) + } + + testCases := []struct { + name string + startTime string + endTime string + expected []uint32 + }{ + {"overlap first", "2024-01-01T10:30:00.000Z", "2024-01-01T10:45:00.000Z", []uint32{1}}, + {"overlap second", "2024-01-01T12:30:00.000Z", "2024-01-01T12:45:00.000Z", []uint32{2}}, + {"no overlap", "2024-01-01T15:00:00.000Z", "2024-01-01T16:00:00.000Z", []uint32{}}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var loaded []uint32 + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + iter := newShardIterator(tx, idx, test.Time(tc.startTime), test.Time(tc.endTime), tenant) + for iter.Next() { + loaded = append(loaded, iter.At().Shard) + } + return iter.Err() + })) + assert.ElementsMatch(t, tc.expected, loaded) + }) + } +} + +func TestIndex_DeleteShard(t *testing.T) { + const baseTime = "2024-01-01T10:00:00.000Z" + + createBlock := func(tenant string, shard uint32, offset time.Duration) *metastorev1.BlockMeta { + ts := test.Time(baseTime).Add(offset) + return &metastorev1.BlockMeta{ + Id: test.ULID(ts.Format(time.RFC3339)), + Tenant: 1, + Shard: shard, + MinTime: ts.UnixMilli(), + MaxTime: ts.Add(time.Hour).UnixMilli(), + StringTable: []string{"", tenant}, + } + } + + insertBlocks := func(t *testing.T, db *bbolt.DB, idx *Index, blocks []*metastorev1.BlockMeta) { + for _, block := range blocks { + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.InsertBlock(tx, block) + })) + } + } + + assertShard := func(t *testing.T, db *bbolt.DB, p indexstore.Partition, tenant string, shard uint32, exists bool) { + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + q := p.Query(tx) + if q == nil && !exists { + return nil + } + require.NotNil(t, q) + + var found bool + for s := range q.Shards(tenant) { + if s.Shard == shard { + found = true + break + } + } + + assert.Equal(t, exists, found) + return nil + })) + } + + t.Run("basic deletion", func(t *testing.T) { + db := test.BoltDB(t) + idx := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + require.NoError(t, db.Update(idx.Init)) + + tenant := "test-tenant" + blocks := []*metastorev1.BlockMeta{ + createBlock(tenant, 1, 0), + createBlock(tenant, 2, 30*time.Minute), + } + + insertBlocks(t, db, idx, blocks) + p := indexstore.NewPartition(test.Time(baseTime), idx.config.partitionDuration) + + assertShard(t, db, p, tenant, 1, true) + assertShard(t, db, p, tenant, 2, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.DeleteShard(tx, p, tenant, 1) + })) + + assertShard(t, db, p, tenant, 1, false) + assertShard(t, db, p, tenant, 2, true) + + k := shardCacheKey{partition: p, tenant: tenant, shard: 1} + cached, found := idx.shards.cache.Get(k) + assert.False(t, found) + assert.Nil(t, cached) + }) + + t.Run("delete non-existent shard", func(t *testing.T) { + db := test.BoltDB(t) + idx := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + require.NoError(t, db.Update(idx.Init)) + + p := indexstore.NewPartition(test.Time(baseTime), idx.config.partitionDuration) + err := db.Update(func(tx *bbolt.Tx) error { + return idx.DeleteShard(tx, p, "non-existent", 999) + }) + assert.NoError(t, err) + }) + + t.Run("multiple tenants isolation", func(t *testing.T) { + db := test.BoltDB(t) + idx := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + require.NoError(t, db.Update(idx.Init)) + + tenant1, tenant2 := "tenant-1", "tenant-2" + blocks := []*metastorev1.BlockMeta{ + createBlock(tenant1, 1, 0), + createBlock(tenant2, 1, 30*time.Minute), + } + + insertBlocks(t, db, idx, blocks) + p := indexstore.NewPartition(test.Time(baseTime), idx.config.partitionDuration) + + assertShard(t, db, p, tenant1, 1, true) + assertShard(t, db, p, tenant2, 1, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.DeleteShard(tx, p, tenant1, 1) + })) + + assertShard(t, db, p, tenant1, 1, false) + assertShard(t, db, p, tenant2, 1, true) + }) +} + +func TestIndex_GetTenantStats(t *testing.T) { + const ( + existingTenant = "tenant" + ) + var ( + minTime = test.UnixMilli("2024-09-11T07:00:00.000Z") + maxTime = test.UnixMilli("2024-09-11T09:00:00.000Z") + ) + + db := test.BoltDB(t) + idx := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + require.NoError(t, db.Update(idx.Init)) + + shardID := uint32(42) + blockMeta := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-11T07:00:00.001Z"), + Tenant: 1, + Shard: shardID, + MinTime: minTime, + MaxTime: maxTime, + CreatedBy: 1, + StringTable: []string{"", existingTenant, "ingester"}, + } + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idx.InsertBlock(tx, blockMeta.CloneVT()) + })) + + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + stats := idx.GetTenantStats(tx, existingTenant) + assert.Equal(t, true, stats.GetDataIngested()) + assert.Equal(t, minTime, stats.GetOldestProfileTime()) + assert.Equal(t, maxTime, stats.GetNewestProfileTime()) + return nil + })) + + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + stats := idx.GetTenantStats(tx, "tenant-never-sent") + assert.Equal(t, false, stats.GetDataIngested()) + assert.Equal(t, int64(0), stats.GetOldestProfileTime()) + assert.Equal(t, int64(0), stats.GetNewestProfileTime()) + return nil + })) + +} diff --git a/pkg/metastore/index/metrics.go b/pkg/metastore/index/metrics.go new file mode 100644 index 0000000000..5828b03b9a --- /dev/null +++ b/pkg/metastore/index/metrics.go @@ -0,0 +1,76 @@ +package index + +import "github.com/prometheus/client_golang/prometheus" + +type metrics struct { + cacheRequests *prometheus.CounterVec +} + +func newMetrics(reg prometheus.Registerer) *metrics { + m := &metrics{ + cacheRequests: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Subsystem: "metastore", + Name: "index_cache_requests_total", + Help: "Total number of metastore index cache lookups, partitioned by cache and result. " + + "The block cache has two tiers; result distinguishes which tier served the " + + "lookup (read_hit / write_hit) or whether both tiers missed.", + }, + []string{"cache", "result"}, + ), + } + if reg != nil { + reg.MustRegister(m.cacheRequests) + } + return m +} + +func (m *metrics) recordShardReadHit() { + if m == nil { + return + } + m.cacheRequests.WithLabelValues("shard_read", "hit").Inc() +} + +func (m *metrics) recordShardReadMiss() { + if m == nil { + return + } + m.cacheRequests.WithLabelValues("shard_read", "miss").Inc() +} + +func (m *metrics) recordShardWriteHit() { + if m == nil { + return + } + m.cacheRequests.WithLabelValues("shard_write", "hit").Inc() +} + +func (m *metrics) recordShardWriteMiss() { + if m == nil { + return + } + m.cacheRequests.WithLabelValues("shard_write", "miss").Inc() +} + +func (m *metrics) recordBlockReadHit() { + if m == nil { + return + } + m.cacheRequests.WithLabelValues("block", "read_hit").Inc() +} + +func (m *metrics) recordBlockWriteHit() { + if m == nil { + return + } + m.cacheRequests.WithLabelValues("block", "write_hit").Inc() +} + +func (m *metrics) recordBlockMiss() { + if m == nil { + return + } + m.cacheRequests.WithLabelValues("block", "miss").Inc() +} diff --git a/pkg/metastore/index/metrics_test.go b/pkg/metastore/index/metrics_test.go new file mode 100644 index 0000000000..daf577f04a --- /dev/null +++ b/pkg/metastore/index/metrics_test.go @@ -0,0 +1,117 @@ +package index + +import ( + "testing" + + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + kvstore "github.com/grafana/pyroscope/v2/pkg/metastore/store" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestCacheMetrics(t *testing.T) { + const ( + tenant = "tenant" + shardID uint32 = 1 + ) + + m := newMetrics(nil) + + db := test.BoltDB(t) + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return indexstore.NewIndexStore().CreateBuckets(tx) + })) + + p := indexstore.NewPartition(test.Time("2024-09-11T06:00:00.000Z"), DefaultConfig.partitionDuration) + + // Shard cache. + sc := newShardCache(DefaultConfig.ShardCacheSize, indexstore.NewIndexStore(), m) + + // First write lookup: cache empty == miss. + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + shard, err := sc.getForWrite(tx, p, tenant, shardID) + if err != nil { + return err + } + require.Equal(t, shardID, shard.Shard) + return nil + })) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("shard_write", "miss"))) + require.Equal(t, float64(0), testutil.ToFloat64(m.cacheRequests.WithLabelValues("shard_write", "hit"))) + + // Second write lookup: cached writable == hit. + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + shard, err := sc.getForWrite(tx, p, tenant, shardID) + if err != nil { + return err + } + require.Equal(t, shardID, shard.Shard) + return nil + })) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("shard_write", "hit"))) + + // Read lookup on the same key: writable entry counts as a read hit too. + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + _, err := sc.getForReadAtVersion(tx, p, tenant, shardID, 0) + return err + })) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("shard_read", "hit"))) + + // Read lookup on a new key: miss + entry inserted as read-only. + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + _, err := sc.getForReadAtVersion(tx, p, tenant, shardID+1, 0) + return err + })) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("shard_read", "miss"))) + + // Now a write lookup on that key: cached entry is read-only == miss + reload. + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + shard, err := sc.getForWrite(tx, p, tenant, shardID+1) + if err != nil { + return err + } + require.Equal(t, shardID+1, shard.Shard) + return nil + })) + require.Equal(t, float64(2), testutil.ToFloat64(m.cacheRequests.WithLabelValues("shard_write", "miss"))) + + // Block cache. + bc := newBlockCache(DefaultConfig.BlockReadCacheSize, DefaultConfig.BlockWriteCacheSize, m) + shard := indexstore.NewShard(p, tenant, shardID) + blockL0 := &metastorev1.BlockMeta{Id: test.ULID("2024-09-11T07:00:00.001Z"), CompactionLevel: 0} + blockL2 := &metastorev1.BlockMeta{Id: test.ULID("2024-09-11T08:00:00.001Z"), CompactionLevel: 2} + + // Put both into their respective tiers. + bc.put(shard, blockL0) + bc.put(shard, blockL2) + + // Encode KV for getOrCreate. + l0Bytes, err := blockL0.MarshalVT() + require.NoError(t, err) + l2Bytes, err := blockL2.MarshalVT() + require.NoError(t, err) + + // blockL0 was put in the write tier (CompactionLevel < 2): write tier serves the lookup. + bc.getOrCreate(shard, kvstore.KV{Key: []byte(blockL0.Id), Value: l0Bytes}) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("block", "write_hit"))) + require.Equal(t, float64(0), testutil.ToFloat64(m.cacheRequests.WithLabelValues("block", "read_hit"))) + require.Equal(t, float64(0), testutil.ToFloat64(m.cacheRequests.WithLabelValues("block", "miss"))) + + // blockL2 was put in the read tier (CompactionLevel >= 2): read tier serves the lookup. + bc.getOrCreate(shard, kvstore.KV{Key: []byte(blockL2.Id), Value: l2Bytes}) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("block", "read_hit"))) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("block", "write_hit"))) + require.Equal(t, float64(0), testutil.ToFloat64(m.cacheRequests.WithLabelValues("block", "miss"))) + + // Unknown block: both tiers miss == decoded fresh. + uncachedID := test.ULID("2024-09-11T09:00:00.001Z") + uncached := &metastorev1.BlockMeta{Id: uncachedID, CompactionLevel: 0} + uncachedBytes, err := uncached.MarshalVT() + require.NoError(t, err) + bc.getOrCreate(shard, kvstore.KV{Key: []byte(uncachedID), Value: uncachedBytes}) + require.Equal(t, float64(1), testutil.ToFloat64(m.cacheRequests.WithLabelValues("block", "miss"))) +} diff --git a/pkg/metastore/index/query.go b/pkg/metastore/index/query.go new file mode 100644 index 0000000000..ece8ff4fe4 --- /dev/null +++ b/pkg/metastore/index/query.go @@ -0,0 +1,338 @@ +package index + +import ( + "context" + "fmt" + "slices" + "sort" + "strings" + "time" + + "github.com/prometheus/prometheus/model/labels" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +type InvalidQueryError struct { + Query MetadataQuery + Err error +} + +func (e *InvalidQueryError) Error() string { + return fmt.Sprintf("invalid query: %v: %v", e.Query, e.Err) +} + +type MetadataQuery struct { + Expr string + StartTime time.Time + EndTime time.Time + Tenant []string + Labels []string +} + +func (q *MetadataQuery) String() string { + return fmt.Sprintf("start: %v, end: %v, tenants: %v, expr: %v", + q.StartTime, + q.EndTime, + strings.Join(q.Tenant, ","), + q.Expr) +} + +type metadataQuery struct { + startTime time.Time + endTime time.Time + tenants []string + tenantMap map[string]struct{} + matchers []*labels.Matcher + labels []string + index *Index +} + +func newMetadataQuery(index *Index, query MetadataQuery) (*metadataQuery, error) { + if len(query.Tenant) == 0 { + return nil, &InvalidQueryError{Query: query, Err: fmt.Errorf("tenant_id is required")} + } + matchers, err := phlaremodel.ParseMetricSelector(query.Expr) + if err != nil { + return nil, &InvalidQueryError{Query: query, Err: fmt.Errorf("failed to parse label matcher: %w", err)} + } + q := &metadataQuery{ + startTime: query.StartTime, + endTime: query.EndTime, + index: index, + matchers: matchers, + labels: query.Labels, + } + q.buildTenantMap(query.Tenant) + return q, nil +} + +func (q *metadataQuery) buildTenantMap(tenants []string) { + q.tenantMap = make(map[string]struct{}, len(tenants)+1) + for _, t := range tenants { + q.tenantMap[t] = struct{}{} + } + // Always query the anonymous blocks: tenant datasets will be filtered out later. + q.tenantMap[""] = struct{}{} + q.tenants = make([]string, 0, len(q.tenantMap)) + for t := range q.tenantMap { + q.tenants = append(q.tenants, t) + } + sort.Strings(q.tenants) +} + +func (q *metadataQuery) overlaps(start, end time.Time) bool { + if q.startTime.After(end) { + return false + } + if q.endTime.Before(start) { + return false + } + return true +} + +func (q *metadataQuery) overlapsUnixMilli(start, end int64) bool { + return q.overlaps(time.UnixMilli(start), time.UnixMilli(end)) +} + +func newBlockMetadataQuerier(tx *bbolt.Tx, q *metadataQuery) *blockMetadataQuerier { + return &blockMetadataQuerier{ + query: q, + shards: newShardIterator(tx, q.index, q.startTime, q.endTime, q.tenants...), + metas: make([]*metastorev1.BlockMeta, 0, 256), + } +} + +type blockMetadataQuerier struct { + query *metadataQuery + shards *shardIterator + metas []*metastorev1.BlockMeta +} + +func (q *blockMetadataQuerier) queryBlocks(ctx context.Context) ([]*metastorev1.BlockMeta, error) { + for q.shards.Next() && ctx.Err() == nil { + shard := q.shards.At() + offset := len(q.metas) + if err := q.collectBlockMetadata(shard); err != nil { + return nil, err + } + slices.SortFunc(q.metas[offset:], func(a, b *metastorev1.BlockMeta) int { + return strings.Compare(a.Id, b.Id) + }) + } + if err := ctx.Err(); err != nil { + return nil, err + } + return q.metas, q.shards.Err() +} + +func (q *blockMetadataQuerier) collectBlockMetadata(s *store.Shard) error { + matcher := metadata.NewLabelMatcher(s.StringTable.Strings, q.query.matchers, q.query.labels...) + if !matcher.IsValid() { + return nil + } + blocks := s.Blocks(q.shards.tx) + if blocks == nil { + return nil + } + for blocks.Next() { + md := q.shards.index.blocks.getOrCreate(s, blocks.At()) + if m := q.collectMatched(s.StringTable, matcher, md); m != nil { + q.metas = append(q.metas, m) + } + } + return nil +} + +func (q *blockMetadataQuerier) collectMatched( + s *metadata.StringTable, + m *metadata.LabelMatcher, + md *metastorev1.BlockMeta, +) *metastorev1.BlockMeta { + if !q.query.overlapsUnixMilli(md.MinTime, md.MaxTime) { + return nil + } + var mdCopy *metastorev1.BlockMeta + var ok bool + matches := make([]int32, 0, 8) + for _, ds := range md.Datasets { + if _, ok := q.query.tenantMap[s.Lookup(ds.Tenant)]; !ok { + continue + } + if !q.query.overlapsUnixMilli(ds.MinTime, ds.MaxTime) { + continue + } + matches = matches[:0] + if matches, ok = m.CollectMatches(matches, ds.Labels); ok { + if mdCopy == nil { + mdCopy = cloneBlockMetadataForQuery(md) + } + dsCopy := cloneDatasetMetadataForQuery(ds) + if len(matches) > 0 { + dsCopy.Labels = make([]int32, len(matches)) + copy(dsCopy.Labels, matches) + } + mdCopy.Datasets = append(mdCopy.Datasets, dsCopy) + } + } + if mdCopy != nil { + s.Export(mdCopy) + } + // May be nil. + return mdCopy +} + +func cloneBlockMetadataForQuery(b *metastorev1.BlockMeta) *metastorev1.BlockMeta { + return &metastorev1.BlockMeta{ + FormatVersion: b.FormatVersion, + Id: b.Id, + Tenant: b.Tenant, + Shard: b.Shard, + CompactionLevel: b.CompactionLevel, + MinTime: b.MinTime, + MaxTime: b.MaxTime, + CreatedBy: b.CreatedBy, + MetadataOffset: b.MetadataOffset, + Size: b.Size, + // Datasets: b.Datasets, + // StringTable: b.StringTable, + } +} + +func cloneDatasetMetadataForQuery(ds *metastorev1.Dataset) *metastorev1.Dataset { + return &metastorev1.Dataset{ + Format: ds.Format, + Tenant: ds.Tenant, + Name: ds.Name, + MinTime: ds.MinTime, + MaxTime: ds.MaxTime, + TableOfContents: ds.TableOfContents, + Size: ds.Size, + // Labels: ds.Labels, + } +} + +func newMetadataLabelQuerier(tx *bbolt.Tx, q *metadataQuery) *metadataLabelQuerier { + return &metadataLabelQuerier{ + query: q, + shards: newShardIterator(tx, q.index, q.startTime, q.endTime, q.tenants...), + labels: metadata.NewLabelsCollector(q.labels...), + } +} + +type metadataLabelQuerier struct { + query *metadataQuery + shards *shardIterator + labels *metadata.LabelsCollector +} + +func (q *metadataLabelQuerier) queryLabels(ctx context.Context) (*metadata.LabelsCollector, error) { + if len(q.query.labels) == 0 { + return q.labels, nil + } + for q.shards.Next() && ctx.Err() == nil { + shard := q.shards.At() + if err := q.collectLabels(shard); err != nil { + return nil, err + } + } + if err := ctx.Err(); err != nil { + return nil, err + } + return q.labels, q.shards.Err() +} + +func (q *metadataLabelQuerier) collectLabels(s *store.Shard) error { + matcher := metadata.NewLabelMatcher(s.StringTable.Strings, q.query.matchers, q.query.labels...) + if !matcher.IsValid() { + return nil + } + blocks := s.Blocks(q.shards.tx) + if blocks == nil { + return nil + } + for blocks.Next() { + md := q.shards.index.blocks.getOrCreate(s, blocks.At()) + if q.query.overlapsUnixMilli(md.MinTime, md.MaxTime) { + for _, ds := range md.Datasets { + if _, ok := q.query.tenantMap[s.StringTable.Lookup(ds.Tenant)]; !ok { + continue + } + if q.query.overlapsUnixMilli(ds.MinTime, ds.MaxTime) { + matcher.Matches(ds.Labels) + } + } + } + } + q.labels.CollectMatches(matcher) + return nil +} + +type shardIterator struct { + tx *bbolt.Tx + index *Index + tenants []string + shards []store.Shard + cur *store.Shard + err error + startTime time.Time + endTime time.Time +} + +func newShardIterator(tx *bbolt.Tx, index *Index, startTime, endTime time.Time, tenants ...string) *shardIterator { + // See comment in DefaultConfig.queryLookaroundPeriod. + startTime = startTime.Add(-index.config.queryLookaroundPeriod) + endTime = endTime.Add(index.config.queryLookaroundPeriod) + si := shardIterator{ + tx: tx, + tenants: tenants, + index: index, + startTime: startTime, + endTime: endTime, + } + for p := range index.store.Partitions(tx) { + if !p.Overlaps(startTime, endTime) { + continue + } + q := p.Query(tx) + if q == nil { + continue + } + for _, t := range si.tenants { + for s := range q.Shards(t) { + if s.ShardIndex.Overlaps(si.startTime, si.endTime) { + si.shards = append(si.shards, s) + } + } + } + } + slices.SortFunc(si.shards, compareShards) + si.shards = slices.Compact(si.shards) + return &si +} + +func (si *shardIterator) Err() error { return si.err } + +func (si *shardIterator) At() *store.Shard { return si.cur } + +func (si *shardIterator) Next() bool { + if si.err != nil || len(si.shards) == 0 { + return false + } + c := si.shards[0] + si.shards = si.shards[1:] + si.cur, si.err = si.index.shards.getForReadAtVersion(si.tx, c.Partition, c.Tenant, c.Shard, c.ShardIndex.Version) + return si.err == nil +} + +func compareShards(a, b store.Shard) int { + cmp := strings.Compare(a.Tenant, b.Tenant) + if cmp == 0 { + return int(a.Shard) - int(b.Shard) + } + return cmp +} diff --git a/pkg/metastore/index/query_test.go b/pkg/metastore/index/query_test.go new file mode 100644 index 0000000000..5054efacfd --- /dev/null +++ b/pkg/metastore/index/query_test.go @@ -0,0 +1,741 @@ +package index + +import ( + "context" + "crypto/rand" + "runtime" + "sync" + "testing" + "time" + + "github.com/oklog/ulid/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" + "go.uber.org/atomic" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +func TestIndex_Query(t *testing.T) { + db := test.BoltDB(t) + ctx := context.Background() + + minT := test.UnixMilli("2024-09-23T08:00:00.000Z") + maxT := test.UnixMilli("2024-09-23T09:00:00.000Z") + + md := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-23T08:00:00.001Z"), + Tenant: 0, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{ + {Tenant: 2, Name: 3, MinTime: minT, MaxTime: maxT, Labels: []int32{2, 4, 3, 5, 6}}, + {Tenant: 7, Name: 8, MinTime: minT, MaxTime: maxT, Labels: []int32{2, 4, 8, 5, 9}}, + }, + StringTable: []string{ + "", "ingester", + "tenant-a", "dataset-a", "service_name", "__profile_type__", "1", + "tenant-b", "dataset-b", "4", + }, + } + + md2 := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-23T08:00:00.002Z"), + Tenant: 1, + Shard: 1, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 2, + Datasets: []*metastorev1.Dataset{ + {Tenant: 1, Name: 3, MinTime: minT, MaxTime: maxT, Labels: []int32{2, 4, 3, 5, 6}}, + }, + StringTable: []string{ + "", "tenant-a", "ingester", "dataset-a", "service_name", "__profile_type__", "1", + }, + } + + md3 := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-23T08:30:00.003Z"), + Tenant: 1, + Shard: 1, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 2, + Datasets: []*metastorev1.Dataset{ + {Tenant: 1, Name: 3, MinTime: minT, MaxTime: maxT, Labels: []int32{2, 4, 3, 5, 6}}, + }, + StringTable: []string{ + "", "tenant-a", "ingester", "dataset-a", "service_name", "__profile_type__", "1", + }, + } + + query := func(t *testing.T, tx *bbolt.Tx, index *Index) { + t.Run("GetBlocks", func(t *testing.T) { + found, err := index.GetBlocks(tx, &metastorev1.BlockList{Blocks: []string{md.Id}}) + require.NoError(t, err) + require.NotEmpty(t, found) + require.Equal(t, md, found[0]) + + found, err = index.GetBlocks(tx, &metastorev1.BlockList{ + Tenant: "tenant-a", + Shard: 1, + Blocks: []string{md2.Id, md3.Id}, + }) + require.NoError(t, err) + require.NotEmpty(t, found) + require.Equal(t, md2, found[0]) + require.Equal(t, md3, found[1]) + + found, err = index.GetBlocks(tx, &metastorev1.BlockList{ + Tenant: "tenant-b", + Shard: 1, + Blocks: []string{md.Id}, + }) + require.NoError(t, err) + require.Empty(t, found) + + found, err = index.GetBlocks(tx, &metastorev1.BlockList{ + Shard: 1, + Blocks: []string{md.Id}, + }) + require.NoError(t, err) + require.Empty(t, found) + }) + + t.Run("DatasetFilter", func(t *testing.T) { + expected := []*metastorev1.BlockMeta{ + { + Id: md.Id, + Tenant: 0, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{{Tenant: 2, Name: 3, MinTime: minT, MaxTime: maxT}}, + StringTable: []string{"", "ingester", "tenant-a", "dataset-a"}, + }, + { + Id: md2.Id, + Tenant: 1, + Shard: 1, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 2, + Datasets: []*metastorev1.Dataset{{Tenant: 1, Name: 3, MinTime: minT, MaxTime: maxT}}, + StringTable: []string{"", "tenant-a", "ingester", "dataset-a"}, + }, + { + Id: md3.Id, + Tenant: 1, + Shard: 1, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 2, + Datasets: []*metastorev1.Dataset{{Tenant: 1, Name: 3, MinTime: minT, MaxTime: maxT}}, + StringTable: []string{"", "tenant-a", "ingester", "dataset-a"}, + }, + } + + found, err := index.QueryMetadata(tx, ctx, MetadataQuery{ + Expr: `{service_name=~"dataset-a"}`, + StartTime: time.UnixMilli(minT), + EndTime: time.UnixMilli(maxT), + Tenant: []string{"tenant-a", "tenant-b"}, + }) + require.NoError(t, err) + require.Equal(t, expected, found) + }) + + t.Run("DatasetTenantFilter", func(t *testing.T) { + expected := []*metastorev1.BlockMeta{ + { + Id: md.Id, + Tenant: 0, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{{Tenant: 2, Name: 3, MinTime: minT, MaxTime: maxT}}, + StringTable: []string{"", "ingester", "tenant-b", "dataset-b"}, + }, + } + + found, err := index.QueryMetadata(tx, ctx, MetadataQuery{ + Expr: `{}`, + StartTime: time.UnixMilli(minT), + EndTime: time.UnixMilli(maxT + 1), + Tenant: []string{"tenant-b"}, + }) + require.NoError(t, err) + require.Equal(t, expected, found) + }) + + t.Run("DatasetTenantFilterNotExisting", func(t *testing.T) { + found, err := index.QueryMetadata(tx, ctx, MetadataQuery{ + Expr: `{}`, + StartTime: time.UnixMilli(minT), + EndTime: time.UnixMilli(maxT + 1), + Tenant: []string{"tenant-not-found"}, + }) + require.NoError(t, err) + require.Empty(t, found) + }) + + t.Run("DatasetFilter_KeepLabels", func(t *testing.T) { + expected := []*metastorev1.BlockMeta{ + { + Id: md.Id, + Tenant: 0, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 1, + Datasets: []*metastorev1.Dataset{{ + Tenant: 2, + Name: 3, + MinTime: minT, + MaxTime: maxT, + Labels: []int32{1, 4, 3}, + }}, + StringTable: []string{"", "ingester", "tenant-a", "dataset-a", "service_name"}, + }, + { + Id: md2.Id, + Tenant: 1, + Shard: 1, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 2, + Datasets: []*metastorev1.Dataset{{ + Tenant: 1, + Name: 3, + MinTime: minT, + MaxTime: maxT, + Labels: []int32{1, 4, 3}, + }}, + StringTable: []string{"", "tenant-a", "ingester", "dataset-a", "service_name"}, + }, + { + Id: md3.Id, + Tenant: 1, + Shard: 1, + MinTime: minT, + MaxTime: maxT, + CreatedBy: 2, + Datasets: []*metastorev1.Dataset{{ + Tenant: 1, + Name: 3, + MinTime: minT, + MaxTime: maxT, + Labels: []int32{1, 4, 3}, + }}, + StringTable: []string{"", "tenant-a", "ingester", "dataset-a", "service_name"}, + }, + } + + found, err := index.QueryMetadata(tx, ctx, MetadataQuery{ + Expr: `{service_name=~"dataset-a"}`, + StartTime: time.UnixMilli(minT), + EndTime: time.UnixMilli(maxT), + Tenant: []string{"tenant-a", "tenant-b"}, + Labels: []string{"service_name"}, + }) + require.NoError(t, err) + require.Equal(t, expected, found) + }) + + t.Run("TimeRangeFilter", func(t *testing.T) { + found, err := index.QueryMetadata(tx, ctx, MetadataQuery{ + Expr: `{service_name=~"dataset-b"}`, + StartTime: time.UnixMilli(minT - 3), + EndTime: time.UnixMilli(minT - 1), // dataset-b starts at minT + Tenant: []string{"tenant-b"}, + }) + require.NoError(t, err) + require.Empty(t, found) + }) + + t.Run("Labels", func(t *testing.T) { + labels, err := index.QueryMetadataLabels(tx, ctx, MetadataQuery{ + Expr: `{service_name=~"dataset.*"}`, + StartTime: time.UnixMilli(minT), + EndTime: time.UnixMilli(maxT), + Tenant: []string{"tenant-a"}, + Labels: []string{ + model.LabelNameProfileType, + model.LabelNameServiceName, + }, + }) + require.NoError(t, err) + require.NotEmpty(t, labels) + assert.Equal(t, []*typesv1.Labels{{Labels: []*typesv1.LabelPair{ + {Name: model.LabelNameProfileType, Value: "1"}, + {Name: model.LabelNameServiceName, Value: "dataset-a"}, + }}}, labels) + }) + + t.Run("LabelsTenantFilter", func(t *testing.T) { + labels, err := index.QueryMetadataLabels(tx, ctx, MetadataQuery{ + Expr: "{}", + StartTime: time.UnixMilli(minT), + EndTime: time.UnixMilli(maxT), + Tenant: []string{"tenant-b"}, + Labels: []string{ + model.LabelNameProfileType, + model.LabelNameServiceName, + }, + }) + require.NoError(t, err) + require.NotEmpty(t, labels) + assert.Equal(t, []*typesv1.Labels{{Labels: []*typesv1.LabelPair{ + {Name: model.LabelNameProfileType, Value: "4"}, + {Name: model.LabelNameServiceName, Value: "dataset-b"}, + }}}, labels) + }) + } + + idx := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, idx.Init(tx)) + require.NoError(t, idx.InsertBlock(tx, md.CloneVT())) + require.NoError(t, idx.InsertBlock(tx, md2.CloneVT())) + require.NoError(t, idx.InsertBlock(tx, md3.CloneVT())) + require.NoError(t, tx.Commit()) + + t.Run("BeforeRestore", func(t *testing.T) { + tx, err := db.Begin(false) + require.NoError(t, err) + query(t, tx, idx) + require.NoError(t, tx.Rollback()) + }) + + t.Run("Restored", func(t *testing.T) { + idx = NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + tx, err = db.Begin(false) + defer func() { + require.NoError(t, tx.Rollback()) + }() + require.NoError(t, err) + require.NoError(t, idx.Restore(tx)) + query(t, tx, idx) + }) +} + +func TestIndex_QueryMetadata_StaleReadCacheReloadsShard(t *testing.T) { + db := test.BoltDB(t) + idxWriter := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + require.NoError(t, db.Update(idxWriter.Init)) + + const tenant = "tenant-a" + const shard = uint32(1) + minT := test.UnixMilli("2024-09-23T08:00:00.000Z") + maxT := test.UnixMilli("2024-09-23T09:00:00.000Z") + + base := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-23T08:00:00.001Z"), + Tenant: 1, + Shard: shard, + MinTime: minT, + MaxTime: maxT, + Datasets: []*metastorev1.Dataset{{ + Tenant: 1, + MinTime: minT, + MaxTime: maxT, + Labels: []int32{1, 2, 3}, + }}, + StringTable: []string{"", tenant, "service_name", "old"}, + } + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idxWriter.InsertBlock(tx, base.CloneVT()) + })) + + staleTx, err := db.Begin(false) + require.NoError(t, err) + defer func() { _ = staleTx.Rollback() }() + + newer := &metastorev1.BlockMeta{ + Id: test.ULID("2024-09-23T08:30:00.002Z"), + Tenant: 1, + Shard: shard, + MinTime: minT, + MaxTime: maxT, + Datasets: []*metastorev1.Dataset{{ + Tenant: 1, + MinTime: minT, + MaxTime: maxT, + Labels: []int32{1, 2, 4}, + }}, + StringTable: []string{"", tenant, "service_name", "old", "new"}, + } + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return idxWriter.InsertBlock(tx, newer.CloneVT()) + })) + + idxReader := NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + _, err = idxReader.GetBlocks(staleTx, &metastorev1.BlockList{ + Tenant: tenant, + Shard: shard, + Blocks: []string{base.Id}, + }) + require.NoError(t, err) + + var found []*metastorev1.BlockMeta + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + found, err = idxReader.QueryMetadata(tx, context.Background(), MetadataQuery{ + Expr: `{service_name=~".+"}`, + StartTime: time.UnixMilli(minT), + EndTime: time.UnixMilli(maxT), + Tenant: []string{tenant}, + Labels: []string{"service_name"}, + }) + return err + })) + require.NoError(t, err) + require.Len(t, found, 2) + assert.Equal(t, []string{base.Id, newer.Id}, []string{found[0].Id, found[1].Id}) + assert.Equal(t, []string{"old", "new"}, []string{ + found[0].StringTable[found[0].Datasets[0].Labels[2]], + found[1].StringTable[found[1].Datasets[0].Labels[2]], + }) +} + +func TestIndex_QueryConcurrency(t *testing.T) { + const N = 10 + for i := 0; i < N && !t.Failed(); i++ { + q := new(queryTestSuite) + q.run(t) + } +} + +type queryTestSuite struct { + db *bbolt.DB + idx *Index + blocks atomic.Pointer[metastorev1.BlockList] + + from string + tenant string + shard uint32 + + wg sync.WaitGroup + stop chan struct{} + doStop func() + + writes atomic.Int32 + queries atomic.Int32 +} + +// Possible invariants: +// 1. (001) No blocks are found. +// 2. (010) Only source blocks are found (1-10). +// 3. (100) Only compacted blocks are found (always 4). + +const ( + noBlocks = 1 << iota + sourceBlocks + compactedBlocks + + all = noBlocks | sourceBlocks | compactedBlocks +) + +func (s *queryTestSuite) setup(t *testing.T) { + var once sync.Once + s.stop = make(chan struct{}) + s.doStop = func() { + once.Do(func() { + close(s.stop) + }) + } + + s.from = "2024-09-23T08:00:00.000Z" + s.tenant = "tenant" + s.shard = 1 + s.blocks.Store(&metastorev1.BlockList{}) + + s.db = test.BoltDB(t) + s.idx = NewIndex(util.Logger, NewStore(), DefaultConfig, nil) + // Enforce aggressive cache evictions: + s.idx.config.partitionDuration = time.Minute * 30 + s.idx.config.ShardCacheSize = 3 + s.idx.config.BlockReadCacheSize = 3 + s.idx.config.BlockWriteCacheSize = 3 + require.NoError(t, s.db.Update(s.idx.Init)) +} + +func (s *queryTestSuite) teardown(t *testing.T) { + require.NoError(t, s.db.Close()) +} + +func (s *queryTestSuite) run(t *testing.T) { + s.setup(t) + defer s.teardown(t) + + done := make(chan struct{}) + go func() { + defer close(done) + for { + select { + case <-s.stop: + return + default: + s.writeBlocks(t) + } + } + }() + + ctx := context.Background() + s.runQuery(t, ctx, s.queryBlocks) + s.runQuery(t, ctx, s.queryLabels) + s.runQuery(t, ctx, s.getBlocks) + + go func() { + select { + case <-s.stop: + case <-time.After(30 * time.Second): + t.Error("test time out: query consistency not confirmed") + s.doStop() + } + }() + + s.wg.Wait() + // If we haven't failed the test, we can conclude that + // no races, no deadlocks, no inconsistencies were found. + s.doStop() + // Wait for the write goroutine to finish, so we can + // safely tear down the test. + <-done + t.Logf("writes: %d, queries: %d", s.writes.Load(), s.queries.Load()) +} + +func (s *queryTestSuite) createBlock(id ulid.ULID, dur time.Duration, tenant string, shard, level uint32) *metastorev1.BlockMeta { + minT := ulid.Time(id.Time()).UnixMilli() + maxT := minT + dur.Milliseconds() + tid := int32(0) + if level > 0 { + tid = 1 + } + return &metastorev1.BlockMeta{ + Id: id.String(), + Tenant: tid, + Shard: shard, + MinTime: minT, + MaxTime: maxT, + CompactionLevel: level, + Datasets: []*metastorev1.Dataset{{Tenant: 1, MinTime: minT, MaxTime: maxT, Labels: []int32{1, 2, 3}}}, + StringTable: []string{"", tenant, "service_name", "service"}, + } +} + +func (s *queryTestSuite) createBlocks(from time.Time, dur time.Duration, n int, tenant string, shard, level uint32) (blocks []*metastorev1.BlockMeta) { + cur := from + for i := 0; i < n; i++ { + b := s.createBlock(ulid.MustNew(ulid.Timestamp(cur), rand.Reader), dur, tenant, shard, level) + blocks = append(blocks, b) + cur = cur.Add(dur) + } + return blocks +} + +func (s *queryTestSuite) writeBlocks(t *testing.T) { + t.Helper() + + // Create source blocks. + source := s.createBlocks(test.Time(s.from), time.Minute*10, 10, s.tenant, s.shard, 0) + sourceList := &metastorev1.BlockList{ + // Tenant: s.tenant, // O level blocks are anonymous. + Shard: s.shard, + Blocks: make([]string, len(source)), + } + for i, b := range source { + sourceList.Blocks[i] = b.Id + } + // Blocks are inserted one by one, each within its own transaction. + for i := range source { + require.NoError(t, s.db.Update(func(tx *bbolt.Tx) error { + return s.idx.InsertBlock(tx, source[i]) + })) + s.writes.Inc() + } + + // We make the blocks visible to our test queries. + s.blocks.Store(sourceList) + // Give other goroutines a chance. + runtime.Gosched() + + // Replace with compacted. + compacted := s.createBlocks(test.Time(s.from), time.Minute*15, 4, s.tenant, s.shard, 1) + compactedList := &metastorev1.BlockList{ + Tenant: s.tenant, + Shard: s.shard, + Blocks: make([]string, len(compacted)), + } + for i, b := range compacted { + compactedList.Blocks[i] = b.Id + } + require.NoError(t, s.db.Update(func(tx *bbolt.Tx) error { + return s.idx.ReplaceBlocks(tx, &metastorev1.CompactedBlocks{ + SourceBlocks: sourceList, + NewBlocks: compacted, + }) + })) + s.writes.Inc() + + // After we replaced the source blocks with compacted blocks, + // we want our test queries to check them. + s.blocks.Store(compactedList) + runtime.Gosched() + + // Delete all blocks. + require.NoError(t, s.db.Update(func(tx *bbolt.Tx) error { + return s.idx.ReplaceBlocks(tx, &metastorev1.CompactedBlocks{ + SourceBlocks: compactedList, + }) + })) + s.writes.Inc() + + s.blocks.Store(&metastorev1.BlockList{}) + runtime.Gosched() +} + +func (s *queryTestSuite) runQuery(t *testing.T, ctx context.Context, q func(*testing.T, context.Context) int32) { + t.Helper() + + var ret int32 + s.wg.Add(1) + + go func() { + defer s.wg.Done() + for { + select { + case <-s.stop: + return + + default: + s.queries.Inc() + x := q(t, ctx) + if x < 0 { + s.doStop() + return + } + if ret |= x; ret == all { + return + } + } + } + }() +} + +func (s *queryTestSuite) queryBlocks(t *testing.T, ctx context.Context) (ret int32) { + var x []*metastorev1.BlockMeta + var err error + require.NoError(t, s.db.View(func(tx *bbolt.Tx) error { + x, err = s.idx.QueryMetadata(tx, ctx, MetadataQuery{ + Expr: `{service_name="service"}`, + StartTime: test.Time(s.from), + EndTime: test.Time(s.from).Add(2 * time.Hour), + Tenant: []string{s.tenant}, + Labels: []string{"service_name"}, + }) + return err + })) + + // It's expected that we may query the data before + // any blocks are written. + if len(x) == 0 { + return noBlocks + } + var c uint32 + for i := range x { + c += x[i].CompactionLevel + } + + if len(x) <= 10 && c == 0 { + // All of level 0: note that the source blocks + // may be seen while they are being inserted. + return sourceBlocks + } + + if len(x) == int(c) && c == 4 { + // All of level 1: note that compacted blocks + // should be added atomically. + return compactedBlocks + } + + t.Error("query blocks: inconsistent results") + for i := range x { + t.Log("\t", x[i]) + } + + return -1 +} + +func (s *queryTestSuite) queryLabels(t *testing.T, ctx context.Context) (ret int32) { + var x []*typesv1.Labels + var err error + require.NoError(t, s.db.View(func(tx *bbolt.Tx) error { + x, err = s.idx.QueryMetadataLabels(tx, ctx, MetadataQuery{ + Expr: `{service_name="service"}`, + StartTime: test.Time(s.from), + EndTime: test.Time(s.from).Add(2 * time.Hour), + Tenant: []string{s.tenant}, + Labels: []string{"service_name"}, + }) + return err + })) + + if len(x) == 0 { + return noBlocks + } + + // Inconsistent labels/strings. + assert.EqualValues(t, 1, len(x)) + assert.EqualValues(t, 1, len(x[0].Labels)) + assert.Equal(t, x[0].Labels[0].Name, "service_name") + assert.Equal(t, x[0].Labels[0].Value, "service") + + // We can't distinguish between source + // and compacted blocks here. + return sourceBlocks | compactedBlocks +} + +func (s *queryTestSuite) getBlocks(t *testing.T, _ context.Context) (ret int32) { + var x []*metastorev1.BlockMeta + var err error + // The writer ensures that the list is set after it finished writes. + // If we get the list within the transaction, we may observe partial + // source blocks [0-9]: this means the read transaction was open while + // not all the blocks were written. + blocks := s.blocks.Load() + require.NoError(t, s.db.View(func(tx *bbolt.Tx) error { + x, err = s.idx.GetBlocks(tx, blocks) + return err + })) + + // Same as queryBlocks except that we do not expect + // to see partial source blocks. + if len(x) == 0 { + return noBlocks + } + var c uint32 + for i := range x { + c += x[i].CompactionLevel + } + + if len(x) == 10 && c == 0 { + return sourceBlocks + } + + if len(x) == int(c) && c == 4 { + return compactedBlocks + } + + t.Error("find blocks: inconsistent results") + for i := range x { + t.Log("\t", x[i]) + } + + return -1 +} diff --git a/pkg/metastore/index/store/index_store.go b/pkg/metastore/index/store/index_store.go new file mode 100644 index 0000000000..fad7953408 --- /dev/null +++ b/pkg/metastore/index/store/index_store.go @@ -0,0 +1,132 @@ +package store + +import ( + "encoding/binary" + "errors" + "fmt" + goiter "iter" + + "go.etcd.io/bbolt" + bbolterrors "go.etcd.io/bbolt/errors" +) + +const ( + partitionBucketName = "partition" + emptyTenantBucketName = "-" +) + +var ( + partitionBucketNameBytes = []byte(partitionBucketName) + emptyTenantBucketNameBytes = []byte(emptyTenantBucketName) +) + +type IndexStore struct{} + +func tenantBucketName(tenant string) []byte { + if tenant == "" { + return emptyTenantBucketNameBytes + } + return []byte(tenant) +} + +func getPartitionsBucket(tx *bbolt.Tx) *bbolt.Bucket { + return tx.Bucket(partitionBucketNameBytes) +} + +func getOrCreateSubBucket(parent *bbolt.Bucket, name []byte) (*bbolt.Bucket, error) { + bucket := parent.Bucket(name) + if bucket == nil { + return parent.CreateBucket(name) + } + return bucket, nil +} + +func NewIndexStore() *IndexStore { + return &IndexStore{} +} + +func (m *IndexStore) CreateBuckets(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists(partitionBucketNameBytes) + return err +} + +func (m *IndexStore) Partitions(tx *bbolt.Tx) goiter.Seq[Partition] { + root := getPartitionsBucket(tx) + if root == nil { + return func(func(Partition) bool) {} + } + return func(yield func(Partition) bool) { + cursor := root.Cursor() + for partitionKey, _ := cursor.First(); partitionKey != nil; partitionKey, _ = cursor.Next() { + p := Partition{} + if err := p.UnmarshalBinary(partitionKey); err != nil { + continue + } + if !yield(p) { + return + } + } + } +} + +func (m *IndexStore) LoadShard(tx *bbolt.Tx, p Partition, tenant string, shard uint32) (*Shard, error) { + s, err := loadTenantShard(tx, p, tenant, shard) + if err != nil { + return nil, fmt.Errorf("error loading tenant shard %s/%d partition %q: %w", tenant, shard, p, err) + } + return s, nil +} + +func (m *IndexStore) LoadShardVersion(tx *bbolt.Tx, p Partition, tenant string, shard uint32) (uint64, error) { + shardBucket := getTenantShardBucket(tx, p, tenant, shard) + if shardBucket == nil { + return 0, nil + } + var idx ShardIndex + if b := shardBucket.Get(tenantShardIndexKeyNameBytes); len(b) > 0 { + if err := idx.UnmarshalBinary(b); err != nil { + return 0, fmt.Errorf("error loading tenant shard version %s/%d partition %q: %w", tenant, shard, p, err) + } + return idx.Version, nil + } + return 0, nil +} + +func (m *IndexStore) DeleteShard(tx *bbolt.Tx, p Partition, tenant string, shard uint32) error { + partitions := getPartitionsBucket(tx) + partitionKey := p.Bytes() + if partition := partitions.Bucket(partitionKey); partition != nil { + tenantKey := tenantBucketName(tenant) + if shards := partition.Bucket(tenantKey); shards != nil { + if err := shards.DeleteBucket(binary.BigEndian.AppendUint32(nil, shard)); err != nil { + if !errors.Is(err, bbolterrors.ErrBucketNotFound) { + return err + } + } + if isBucketEmpty(shards) { + if err := partition.DeleteBucket(tenantKey); err != nil { + if !errors.Is(err, bbolterrors.ErrBucketNotFound) { + return err + } + } + } + } + if isBucketEmpty(partition) { + if err := partitions.DeleteBucket(partitionKey); err != nil { + if !errors.Is(err, bbolterrors.ErrBucketNotFound) { + return err + } + } + } + } + return nil +} + +func isBucketEmpty(bucket *bbolt.Bucket) bool { + if bucket == nil { + return true + } + c := bucket.Cursor() + k, _ := c.First() + return k == nil +} diff --git a/pkg/metastore/index/store/index_store_test.go b/pkg/metastore/index/store/index_store_test.go new file mode 100644 index 0000000000..cb3844615b --- /dev/null +++ b/pkg/metastore/index/store/index_store_test.go @@ -0,0 +1,333 @@ +package store + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +const testTenant = "test-tenant" + +func TestShard_Overlaps(t *testing.T) { + db := test.BoltDB(t) + + store := NewIndexStore() + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.CreateBuckets(tx) + })) + + partitionKey := NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour) + shardID := uint32(1) + + blockMinTime := test.UnixMilli("2024-09-11T07:00:00.000Z") + blockMaxTime := test.UnixMilli("2024-09-11T09:00:00.000Z") + + blockMeta := &metastorev1.BlockMeta{ + FormatVersion: 1, + Id: "test-block-123", + Tenant: 1, // Index 1 in StringTable ("test-tenant") + Shard: shardID, + MinTime: blockMinTime, + MaxTime: blockMaxTime, + Datasets: []*metastorev1.Dataset{ + { + Tenant: 1, // Index 1 in StringTable ("test-tenant") + Name: 3, // Index 3 in StringTable ("test-dataset") + MinTime: blockMinTime, + MaxTime: blockMaxTime, + // Labels format: [count, name_idx, value_idx, name_idx, value_idx, ...] + // 2 labels: service_name="service", __profile_type__="cpu" + Labels: []int32{2, 3, 5, 4, 6}, + }, + }, + StringTable: []string{ + "", // Index 0 + "test-tenant", // Index 1 + "test-dataset", // Index 2 + "service_name", // Index 3 + "__profile_type__", // Index 4 + "service", // Index 5 + "cpu", // Index 6 + }, + } + + // store a block + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return NewShard(partitionKey, testTenant, shardID).Store(tx, blockMeta) + })) + + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + shard, err := store.LoadShard(tx, partitionKey, testTenant, shardID) + require.NoError(t, err) + require.NotNil(t, shard) + + assert.Equal(t, blockMinTime, shard.ShardIndex.MinTime) + assert.Equal(t, blockMaxTime, shard.ShardIndex.MaxTime) + + testCases := []struct { + name string + startTime time.Time + endTime time.Time + expected bool + }{ + { + name: "complete overlap - query contains block range", + startTime: test.Time("2024-09-11T06:30:00.000Z"), + endTime: test.Time("2024-09-11T10:00:00.000Z"), + expected: true, + }, + { + name: "block contains query range", + startTime: test.Time("2024-09-11T07:30:00.000Z"), + endTime: test.Time("2024-09-11T08:30:00.000Z"), + expected: true, + }, + { + name: "partial overlap - start before block, end within block", + startTime: test.Time("2024-09-11T06:30:00.000Z"), + endTime: test.Time("2024-09-11T08:00:00.000Z"), + expected: true, + }, + { + name: "partial overlap - start within block, end after block", + startTime: test.Time("2024-09-11T08:00:00.000Z"), + endTime: test.Time("2024-09-11T10:00:00.000Z"), + expected: true, + }, + { + name: "edge case - query ends exactly at block start", + startTime: test.Time("2024-09-11T06:00:00.000Z"), + endTime: test.Time("2024-09-11T07:00:00.000Z"), + expected: true, // Inclusive boundary check + }, + { + name: "edge case - query starts exactly at block end", + startTime: test.Time("2024-09-11T09:00:00.000Z"), + endTime: test.Time("2024-09-11T10:00:00.000Z"), + expected: true, // Inclusive boundary check + }, + { + name: "no overlap - query before block", + startTime: test.Time("2024-09-11T05:00:00.000Z"), + endTime: test.Time("2024-09-11T06:59:58.999Z"), + expected: false, + }, + { + name: "no overlap - query after block", + startTime: test.Time("2024-09-11T09:00:00.001Z"), + endTime: test.Time("2024-09-11T11:00:00.000Z"), + expected: false, + }, + { + name: "exact match - same start and end times", + startTime: test.Time("2024-09-11T07:00:00.000Z"), + endTime: test.Time("2024-09-11T09:00:00.000Z"), + expected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := shard.ShardIndex.Overlaps(tc.startTime, tc.endTime) + assert.Equal(t, tc.expected, result, + "Overlaps(%v, %v) = %v, expected %v", + tc.startTime, tc.endTime, result, tc.expected) + }) + } + + return nil + })) +} + +func TestIndexStore_DeleteShard(t *testing.T) { + createBlock := func(id, tenant string, shard uint32) *metastorev1.BlockMeta { + return &metastorev1.BlockMeta{ + Id: id, + Tenant: 1, + Shard: shard, + MinTime: test.UnixMilli("2024-01-01T10:00:00.000Z"), + MaxTime: test.UnixMilli("2024-01-01T11:00:00.000Z"), + StringTable: []string{"", tenant}, + } + } + + storeBlock := func(t *testing.T, db *bbolt.DB, p Partition, tenant string, shard uint32, block *metastorev1.BlockMeta) { + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return NewShard(p, tenant, shard).Store(tx, block) + })) + } + + assertShard := func(t *testing.T, db *bbolt.DB, store *IndexStore, p Partition, tenant string, shard uint32, exists bool) { + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + s, err := store.LoadShard(tx, p, tenant, shard) + if exists { + assert.NoError(t, err) + assert.NotNil(t, s) + } else { + assert.Nil(t, s) + } + return nil + })) + } + + assertPartition := func(t *testing.T, db *bbolt.DB, _ *IndexStore, p Partition, exists bool) { + require.NoError(t, db.View(func(tx *bbolt.Tx) error { + q := p.Query(tx) + if exists { + assert.NotNil(t, q) + } else { + assert.Nil(t, q) + } + return nil + })) + } + + t.Run("basic deletion", func(t *testing.T) { + db := test.BoltDB(t) + store := NewIndexStore() + require.NoError(t, db.Update(store.CreateBuckets)) + + p := NewPartition(test.Time("2024-01-01T10:00:00.000Z"), 6*time.Hour) + + storeBlock(t, db, p, testTenant, 1, createBlock("block1", testTenant, 1)) + storeBlock(t, db, p, testTenant, 2, createBlock("block2", testTenant, 2)) + + assertShard(t, db, store, p, testTenant, 1, true) + assertShard(t, db, store, p, testTenant, 2, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, testTenant, 1) + })) + + assertShard(t, db, store, p, testTenant, 1, false) + assertShard(t, db, store, p, testTenant, 2, true) + }) + + t.Run("delete non-existent shard", func(t *testing.T) { + db := test.BoltDB(t) + store := NewIndexStore() + require.NoError(t, db.Update(store.CreateBuckets)) + + p := NewPartition(test.Time("2024-01-01T10:00:00.000Z"), 6*time.Hour) + + err := db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, "non-existent", 999) + }) + assert.NoError(t, err) + }) + + t.Run("tenant bucket cleanup", func(t *testing.T) { + db := test.BoltDB(t) + store := NewIndexStore() + require.NoError(t, db.Update(store.CreateBuckets)) + + p := NewPartition(test.Time("2024-01-01T10:00:00.000Z"), 6*time.Hour) + + storeBlock(t, db, p, testTenant, 1, createBlock("block1", testTenant, 1)) + + assertShard(t, db, store, p, testTenant, 1, true) + assertPartition(t, db, store, p, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, testTenant, 1) + })) + + assertShard(t, db, store, p, testTenant, 1, false) + assertPartition(t, db, store, p, false) + }) + + t.Run("partition bucket cleanup with multiple tenants", func(t *testing.T) { + db := test.BoltDB(t) + store := NewIndexStore() + require.NoError(t, db.Update(store.CreateBuckets)) + + p := NewPartition(test.Time("2024-01-01T10:00:00.000Z"), 6*time.Hour) + tenant1, tenant2 := "tenant-1", "tenant-2" + + storeBlock(t, db, p, tenant1, 1, createBlock("block1", tenant1, 1)) + storeBlock(t, db, p, tenant2, 1, createBlock("block2", tenant2, 1)) + + assertShard(t, db, store, p, tenant1, 1, true) + assertShard(t, db, store, p, tenant2, 1, true) + assertPartition(t, db, store, p, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, tenant1, 1) + })) + + assertShard(t, db, store, p, tenant1, 1, false) + assertShard(t, db, store, p, tenant2, 1, true) + assertPartition(t, db, store, p, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, tenant2, 1) + })) + + assertShard(t, db, store, p, tenant1, 1, false) + assertShard(t, db, store, p, tenant2, 1, false) + assertPartition(t, db, store, p, false) + }) + + t.Run("multiple shards same tenant", func(t *testing.T) { + db := test.BoltDB(t) + store := NewIndexStore() + require.NoError(t, db.Update(store.CreateBuckets)) + + p := NewPartition(test.Time("2024-01-01T10:00:00.000Z"), 6*time.Hour) + + storeBlock(t, db, p, testTenant, 1, createBlock("block1", testTenant, 1)) + storeBlock(t, db, p, testTenant, 2, createBlock("block2", testTenant, 2)) + storeBlock(t, db, p, testTenant, 3, createBlock("block3", testTenant, 3)) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, testTenant, 2) + })) + + assertShard(t, db, store, p, testTenant, 1, true) + assertShard(t, db, store, p, testTenant, 2, false) + assertShard(t, db, store, p, testTenant, 3, true) + assertPartition(t, db, store, p, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, testTenant, 1) + })) + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p, testTenant, 3) + })) + + assertShard(t, db, store, p, testTenant, 1, false) + assertShard(t, db, store, p, testTenant, 2, false) + assertShard(t, db, store, p, testTenant, 3, false) + assertPartition(t, db, store, p, false) + }) + + t.Run("multiple partitions isolation", func(t *testing.T) { + db := test.BoltDB(t) + store := NewIndexStore() + require.NoError(t, db.Update(store.CreateBuckets)) + + p1 := NewPartition(test.Time("2024-01-01T10:00:00.000Z"), 6*time.Hour) + p2 := NewPartition(test.Time("2024-01-01T16:00:00.000Z"), 6*time.Hour) + + storeBlock(t, db, p1, testTenant, 1, createBlock("block1", testTenant, 1)) + storeBlock(t, db, p2, testTenant, 1, createBlock("block2", testTenant, 1)) + + assertShard(t, db, store, p1, testTenant, 1, true) + assertShard(t, db, store, p2, testTenant, 1, true) + + require.NoError(t, db.Update(func(tx *bbolt.Tx) error { + return store.DeleteShard(tx, p1, testTenant, 1) + })) + + assertShard(t, db, store, p1, testTenant, 1, false) + assertShard(t, db, store, p2, testTenant, 1, true) + assertPartition(t, db, store, p1, false) + assertPartition(t, db, store, p2, true) + }) +} diff --git a/pkg/metastore/index/store/partition.go b/pkg/metastore/index/store/partition.go new file mode 100644 index 0000000000..0965d88b34 --- /dev/null +++ b/pkg/metastore/index/store/partition.go @@ -0,0 +1,138 @@ +package store + +import ( + "bytes" + "encoding/binary" + "errors" + "iter" + "time" + + "go.etcd.io/bbolt" +) + +var ErrInvalidPartitionKey = errors.New("invalid partition key") + +type Partition struct { + Timestamp time.Time + Duration time.Duration +} + +func NewPartition(timestamp time.Time, duration time.Duration) Partition { + return Partition{Timestamp: timestamp.Truncate(duration), Duration: duration} +} + +func (p *Partition) Equal(x Partition) bool { + return p.Timestamp.Equal(x.Timestamp) && p.Duration == x.Duration +} + +func (p *Partition) StartTime() time.Time { return p.Timestamp } + +func (p *Partition) EndTime() time.Time { return p.Timestamp.Add(p.Duration) } + +func (p *Partition) Overlaps(start, end time.Time) bool { + if start.After(p.EndTime()) { + return false + } + if end.Before(p.StartTime()) { + return false + } + return true +} + +func (p *Partition) Bytes() []byte { + b, _ := p.MarshalBinary() + return b +} + +func (p *Partition) String() string { + b := make([]byte, 0, 32) + b = p.Timestamp.UTC().AppendFormat(b, time.DateTime) + b = append(b, ' ') + b = append(b, '(') + b = append(b, p.Duration.String()...) + b = append(b, ')') + return string(b) +} + +func (p *Partition) MarshalBinary() ([]byte, error) { + b := make([]byte, 12) + binary.BigEndian.PutUint64(b[0:8], uint64(p.Timestamp.UnixNano())) + binary.BigEndian.PutUint32(b[8:12], uint32(p.Duration/time.Second)) + return b, nil +} + +func (p *Partition) UnmarshalBinary(b []byte) error { + if len(b) != 12 { + return ErrInvalidPartitionKey + } + p.Timestamp = time.Unix(0, int64(binary.BigEndian.Uint64(b[0:8]))) + p.Duration = time.Duration(binary.BigEndian.Uint32(b[8:12])) * time.Second + return nil +} + +func (p *Partition) Query(tx *bbolt.Tx) *PartitionQuery { + b := getPartitionsBucket(tx).Bucket(p.Bytes()) + if b == nil { + return nil + } + return &PartitionQuery{ + tx: tx, + Partition: *p, + bucket: b, + } +} + +type PartitionQuery struct { + Partition + tx *bbolt.Tx + bucket *bbolt.Bucket +} + +func (q *PartitionQuery) Tenants() iter.Seq[string] { + return func(yield func(string) bool) { + cursor := q.bucket.Cursor() + for tenantKey, _ := cursor.First(); tenantKey != nil; tenantKey, _ = cursor.Next() { + tenantBucket := q.bucket.Bucket(tenantKey) + if tenantBucket == nil { + continue + } + tenant := string(tenantKey) + if bytes.Equal(tenantKey, emptyTenantBucketNameBytes) { + tenant = "" + } + if !yield(tenant) { + return + } + } + } +} + +func (q *PartitionQuery) Shards(tenant string) iter.Seq[Shard] { + tenantBucket := q.bucket.Bucket(tenantBucketName(tenant)) + if tenantBucket == nil { + return func(func(Shard) bool) {} + } + return func(yield func(Shard) bool) { + cursor := tenantBucket.Cursor() + for shardKey, _ := cursor.First(); shardKey != nil; shardKey, _ = cursor.Next() { + shardBucket := tenantBucket.Bucket(shardKey) + if shardBucket == nil { + continue + } + shard := Shard{ + Partition: q.Partition, + Tenant: tenant, + Shard: binary.BigEndian.Uint32(shardKey), + ShardIndex: ShardIndex{}, + } + if b := shardBucket.Get(tenantShardIndexKeyNameBytes); len(b) > 0 { + if err := shard.ShardIndex.UnmarshalBinary(b); err != nil { + continue + } + } + if !yield(shard) { + return + } + } + } +} diff --git a/pkg/metastore/index/store/partition_test.go b/pkg/metastore/index/store/partition_test.go new file mode 100644 index 0000000000..92f0b82889 --- /dev/null +++ b/pkg/metastore/index/store/partition_test.go @@ -0,0 +1,121 @@ +package store + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestPartition_Overlaps(t *testing.T) { + type args struct { + start time.Time + end time.Time + } + tests := []struct { + name string + key Partition + args args + want bool + }{ + { + name: "simple overlap", + key: NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-11T07:15:24.123Z"), + end: test.Time("2024-09-11T13:15:24.123Z"), + }, + want: true, + }, + { + name: "overlap at partition start", + key: NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-11T04:00:00.000Z"), + end: test.Time("2024-09-11T06:00:00.000Z"), + }, + want: true, + }, + { + name: "no overlap close to partition start", + key: NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-11T04:00:00.000Z"), + end: test.Time("2024-09-11T05:59:59.999Z"), + }, + want: false, + }, + { + name: "overlap at partition end", + key: NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-11T11:59:59.999Z"), + end: test.Time("2024-09-11T13:00:00.000Z"), + }, + want: true, + }, + { + name: "no overlap close to partition end", + key: NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-11T12:00:00.000Z"), + end: test.Time("2024-09-11T13:59:59.999Z"), + }, + want: true, + }, + { + name: "overlap around midnight", + key: NewPartition(test.Time("2024-09-11T00:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-10T19:00:00.000Z"), + end: test.Time("2024-09-11T00:01:01.999Z"), + }, + want: true, + }, + { + name: "partition fully contains interval", + key: NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-11T07:00:00.000Z"), + end: test.Time("2024-09-11T08:01:01.999Z"), + }, + want: true, + }, + { + name: "interval fully contains partition", + key: NewPartition(test.Time("2024-09-11T06:00:00.000Z"), 6*time.Hour), + args: args{ + start: test.Time("2024-09-11T02:00:00.000Z"), + end: test.Time("2024-09-11T13:01:01.999Z"), + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, tt.key.Overlaps(tt.args.start, tt.args.end), "overlaps(%v, %v)", tt.args.start, tt.args.end) + }) + } +} + +func TestPartitionKey_Equal(t *testing.T) { + k1 := NewPartition(test.Time("2024-09-11T02:00:00.000Z"), 2*time.Hour) + k2 := NewPartition(test.Time("2024-09-11T03:01:01.999Z"), 2*time.Hour) + assert.Equal(t, k1, k2) + + k1 = NewPartition(test.Time("2024-09-11T02:00:00.000Z"), time.Hour) + k2 = NewPartition(test.Time("2024-09-11T03:01:01.999Z"), time.Hour) + assert.NotEqual(t, k1, k2) +} + +func TestPartitionKey_Encoding(t *testing.T) { + k := NewPartition(time.Now(), time.Hour*6) + b, err := k.MarshalBinary() + assert.NoError(t, err) + var d Partition + err = d.UnmarshalBinary(b) + assert.NoError(t, err) + assert.Equal(t, k, d) +} diff --git a/pkg/metastore/index/store/shard.go b/pkg/metastore/index/store/shard.go new file mode 100644 index 0000000000..f66d01f5e1 --- /dev/null +++ b/pkg/metastore/index/store/shard.go @@ -0,0 +1,220 @@ +package store + +import ( + "encoding/binary" + "errors" + "fmt" + "strconv" + "strings" + + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" + multitenancy "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +const ( + tenantShardStringsBucketName = ".strings" + tenantShardIndexKeyName = ".index" +) + +var ( + ErrInvalidStringTable = errors.New("malformed string table") + ErrInvalidShardIndex = errors.New("malformed shard index") +) + +var ( + tenantShardIndexKeyNameBytes = []byte(tenantShardIndexKeyName) + tenantShardStringsBucketNameBytes = []byte(tenantShardStringsBucketName) + + blockCursorSkipPrefix = []byte{'.'} +) + +type Shard struct { + Partition Partition + Tenant string + Shard uint32 + ShardIndex ShardIndex + StringTable *metadata.StringTable + + // TODO(kolesnikovae): Build a skip index for labels. + // Labels *metadata.StringTable +} + +func NewShard(p Partition, tenant string, shard uint32) *Shard { + return &Shard{ + Partition: p, + Tenant: tenant, + Shard: shard, + StringTable: metadata.NewStringTable(), + ShardIndex: ShardIndex{}, + } +} + +func (s *Shard) Store(tx *bbolt.Tx, md *metastorev1.BlockMeta) error { + shardBucket, err := getOrCreateTenantShardBucket(tx, s.Partition, s.Tenant, s.Shard) + if err != nil { + return err + } + + n := len(s.StringTable.Strings) + s.StringTable.Import(md) + if added := s.StringTable.Strings[n:]; len(added) > 0 { + stringTable, err := getOrCreateSubBucket(shardBucket, tenantShardStringsBucketNameBytes) + if err != nil { + return err + } + k := binary.BigEndian.AppendUint32(nil, uint32(n)) + v := encodeStrings(added) + if err = stringTable.Put(k, v); err != nil { + return err + } + } + md.StringTable = nil + value, err := md.MarshalVT() + if err != nil { + return err + } + + s.ShardIndex.Version++ + if s.ShardIndex.MinTime == 0 || s.ShardIndex.MinTime > md.MinTime { + s.ShardIndex.MinTime = md.MinTime + } + if s.ShardIndex.MaxTime < md.MaxTime { + s.ShardIndex.MaxTime = md.MaxTime + } + if err = shardBucket.Put(tenantShardIndexKeyNameBytes, s.ShardIndex.MarshalBinary()); err != nil { + return err + } + + return shardBucket.Put([]byte(md.Id), value) +} + +func (s *Shard) Find(tx *bbolt.Tx, blocks ...string) []store.KV { + bucket := getTenantShardBucket(tx, s.Partition, s.Tenant, s.Shard) + if bucket == nil { + return nil + } + kv := make([]store.KV, 0, len(blocks)) + for _, b := range blocks { + k := []byte(b) + if v := bucket.Get(k); v != nil { + kv = append(kv, store.KV{Key: k, Value: v}) + } + } + return kv +} + +func (s *Shard) Blocks(tx *bbolt.Tx) *store.CursorIterator { + bucket := getTenantShardBucket(tx, s.Partition, s.Tenant, s.Shard) + if bucket == nil { + return nil + } + cursor := store.NewCursorIter(bucket.Cursor()) + cursor.SkipPrefix = blockCursorSkipPrefix + return cursor +} + +func (s *Shard) Delete(tx *bbolt.Tx, blocks ...string) error { + tenantShard := getTenantShardBucket(tx, s.Partition, s.Tenant, s.Shard) + if tenantShard == nil { + return nil + } + for _, b := range blocks { + if err := tenantShard.Delete([]byte(b)); err != nil { + return err + } + } + return nil +} + +func (s *Shard) TombstoneName() string { + var b strings.Builder + b.WriteString(s.Partition.String()) + b.WriteByte('-') + b.WriteByte('T') + if s.Tenant != "" { + b.WriteString(s.Tenant) + } else { + b.WriteString(multitenancy.DefaultTenantID) + } + b.WriteByte('-') + b.WriteByte('S') + b.WriteString(strconv.FormatUint(uint64(s.Shard), 10)) + return b.String() +} + +// ShallowCopy creates a shallow copy: no deep copy of the string table. +// The copy can be accessed safely by multiple readers, and it represents +// a snapshot of the shard including the string table. +// +// Strings added after the copy is made won't be visible to the reader. +// The writer MUST invalidate the cache before access: copies in-use can +// still be used (strings is a header copy of append-only slice). +func (s *Shard) ShallowCopy() *Shard { + return &Shard{ + Partition: s.Partition, + Tenant: s.Tenant, + Shard: s.Shard, + ShardIndex: s.ShardIndex, + StringTable: &metadata.StringTable{ + Strings: s.StringTable.Strings, + }, + } +} + +func getTenantShardBucket(tx *bbolt.Tx, p Partition, tenant string, shard uint32) *bbolt.Bucket { + if partition := getPartitionsBucket(tx).Bucket(p.Bytes()); partition != nil { + if shards := partition.Bucket(tenantBucketName(tenant)); shards != nil { + return shards.Bucket(binary.BigEndian.AppendUint32(nil, shard)) + } + } + return nil +} + +func getOrCreateTenantShardBucket(tx *bbolt.Tx, p Partition, tenant string, shard uint32) (*bbolt.Bucket, error) { + partition, err := getOrCreateSubBucket(getPartitionsBucket(tx), p.Bytes()) + if err != nil { + return nil, fmt.Errorf("error creating partition bucket for %s: %w", p, err) + } + shards, err := getOrCreateSubBucket(partition, tenantBucketName(tenant)) + if err != nil { + return nil, fmt.Errorf("error creating shard bucket for tenant %s in parititon %v: %w", tenant, p, err) + } + tenantShard, err := getOrCreateSubBucket(shards, binary.BigEndian.AppendUint32(nil, shard)) + if err != nil { + return nil, fmt.Errorf("error creating shard bucket for partiton %s and shard %d: %w", p, shard, err) + } + return tenantShard, nil +} + +func loadTenantShard(tx *bbolt.Tx, p Partition, tenant string, shard uint32) (*Shard, error) { + shardBucket := getTenantShardBucket(tx, p, tenant, shard) + if shardBucket == nil { + return nil, nil + } + + s := NewShard(p, tenant, shard) + stringTable := shardBucket.Bucket(tenantShardStringsBucketNameBytes) + if stringTable == nil { + return s, nil + } + stringsIter := newStringIter(store.NewCursorIter(stringTable.Cursor())) + defer func() { + _ = stringsIter.Close() + }() + var err error + if err = s.StringTable.Load(stringsIter); err != nil { + return nil, err + } + + if b := shardBucket.Get(tenantShardIndexKeyNameBytes); len(b) > 0 { + if err = s.ShardIndex.UnmarshalBinary(b); err != nil { + return nil, err + } + } + + return s, nil +} diff --git a/pkg/metastore/index/store/shard_index.go b/pkg/metastore/index/store/shard_index.go new file mode 100644 index 0000000000..b76edb4c7a --- /dev/null +++ b/pkg/metastore/index/store/shard_index.go @@ -0,0 +1,46 @@ +package store + +import ( + "encoding/binary" + "time" +) + +type ShardIndex struct { + MinTime int64 + MaxTime int64 + Version uint64 +} + +func (i *ShardIndex) UnmarshalBinary(data []byte) error { + if len(data) < 16 { + return ErrInvalidShardIndex + } + i.MinTime = int64(binary.BigEndian.Uint64(data[0:8])) + i.MaxTime = int64(binary.BigEndian.Uint64(data[8:16])) + if len(data) >= 24 { + i.Version = binary.BigEndian.Uint64(data[16:24]) + } + return nil +} + +func (i *ShardIndex) MarshalBinary() []byte { + b := make([]byte, 24) + binary.BigEndian.PutUint64(b[0:8], uint64(i.MinTime)) + binary.BigEndian.PutUint64(b[8:16], uint64(i.MaxTime)) + binary.BigEndian.PutUint64(b[16:24], i.Version) + return b +} + +func (i *ShardIndex) Overlaps(start, end time.Time) bool { + // For backward compatibility. + if i.MinTime == 0 || i.MaxTime == 0 { + return true + } + if start.After(time.UnixMilli(i.MaxTime)) { + return false + } + if end.Before(time.UnixMilli(i.MinTime)) { + return false + } + return true +} diff --git a/pkg/metastore/index/store/shard_strings.go b/pkg/metastore/index/store/shard_strings.go new file mode 100644 index 0000000000..039132551a --- /dev/null +++ b/pkg/metastore/index/store/shard_strings.go @@ -0,0 +1,82 @@ +package store + +import ( + "encoding/binary" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" +) + +type stringIterator struct { + iter.Iterator[store.KV] + batch []string + cur int + err error +} + +func newStringIter(i iter.Iterator[store.KV]) *stringIterator { + return &stringIterator{Iterator: i} +} + +func (i *stringIterator) Err() error { + if err := i.Iterator.Err(); err != nil { + return err + } + return i.err +} + +func (i *stringIterator) At() string { return i.batch[i.cur] } + +func (i *stringIterator) Next() bool { + if n := i.cur + 1; n < len(i.batch) { + i.cur = n + return true + } + i.cur = 0 + i.batch = i.batch[:0] + if !i.Iterator.Next() { + return false + } + var err error + if i.batch, err = decodeStrings(i.batch, i.Iterator.At().Value); err != nil { + i.err = err + return false + } + return len(i.batch) > 0 +} + +func encodeStrings(strings []string) []byte { + size := 4 + for _, s := range strings { + size += 4 + len(s) + } + data := make([]byte, 0, size) + data = binary.BigEndian.AppendUint32(data, uint32(len(strings))) + for _, s := range strings { + data = binary.BigEndian.AppendUint32(data, uint32(len(s))) + data = append(data, s...) + } + return data +} + +func decodeStrings(dst []string, data []byte) ([]string, error) { + offset := 0 + if len(data) < offset+4 { + return dst, ErrInvalidStringTable + } + n := binary.BigEndian.Uint32(data[offset:]) + offset += 4 + for i := uint32(0); i < n; i++ { + if len(data) < offset+4 { + return dst, ErrInvalidStringTable + } + size := binary.BigEndian.Uint32(data[offset:]) + offset += 4 + if len(data) < offset+int(size) { + return dst, ErrInvalidStringTable + } + dst = append(dst, string(data[offset:offset+int(size)])) + offset += int(size) + } + return dst, nil +} diff --git a/pkg/metastore/index/tombstones/metrics.go b/pkg/metastore/index/tombstones/metrics.go new file mode 100644 index 0000000000..148beee397 --- /dev/null +++ b/pkg/metastore/index/tombstones/metrics.go @@ -0,0 +1,50 @@ +package tombstones + +import ( + "github.com/prometheus/client_golang/prometheus" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type metrics struct { + tombstones *prometheus.GaugeVec +} + +func newMetrics(r prometheus.Registerer) *metrics { + m := &metrics{ + tombstones: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "index_tombstones", + Help: "The number of tombstones in the queue.", + }, []string{"tenant", "type"}), + } + + util.Register(r, + m.tombstones, + ) + + return m +} + +const ( + tombstoneTypeBlocks = "blocks" + tombstoneTypeShard = "shard" +) + +func (m *metrics) incrementTombstones(t *metastorev1.Tombstones) { + if t.Blocks != nil { + m.tombstones.WithLabelValues(t.Blocks.Tenant, tombstoneTypeBlocks).Inc() + } + if t.Shard != nil { + m.tombstones.WithLabelValues(t.Shard.Tenant, tombstoneTypeShard).Inc() + } +} + +func (m *metrics) decrementTombstones(t *metastorev1.Tombstones) { + if t.Blocks != nil { + m.tombstones.WithLabelValues(t.Blocks.Tenant, tombstoneTypeBlocks).Dec() + } + if t.Shard != nil { + m.tombstones.WithLabelValues(t.Shard.Tenant, tombstoneTypeShard).Dec() + } +} diff --git a/pkg/metastore/index/tombstones/store/tombstone_store.go b/pkg/metastore/index/tombstones/store/tombstone_store.go new file mode 100644 index 0000000000..c30917c855 --- /dev/null +++ b/pkg/metastore/index/tombstones/store/tombstone_store.go @@ -0,0 +1,127 @@ +package store + +import ( + "encoding/binary" + "errors" + "fmt" + + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/store" +) + +var ErrInvalidTombstoneEntry = errors.New("invalid tombstone entry") + +var tombstoneBucketName = []byte("tombstones") + +type TombstoneEntry struct { + // Key the entry was stored under. This is needed for backward + // compatibility: if the logic for generating keys changes, we + // will still be able to delete old entries. + key []byte + Index uint64 + AppendedAt int64 + *metastorev1.Tombstones +} + +func (e TombstoneEntry) Name() string { + switch { + case e.Blocks != nil: + return e.Blocks.Name + case e.Shard != nil: + return e.Shard.Name + default: + return "" + } +} + +type TombstoneStore struct{ bucketName []byte } + +func NewTombstoneStore() *TombstoneStore { + return &TombstoneStore{bucketName: tombstoneBucketName} +} + +func (s *TombstoneStore) CreateBuckets(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists(s.bucketName) + return err +} + +func (s *TombstoneStore) StoreTombstones(tx *bbolt.Tx, entry TombstoneEntry) error { + kv := marshalTombstoneEntry(entry) + return tx.Bucket(s.bucketName).Put(kv.Key, kv.Value) +} + +func (s *TombstoneStore) DeleteTombstones(tx *bbolt.Tx, entry TombstoneEntry) error { + return tx.Bucket(s.bucketName).Delete(marshalTombstoneEntryKey(entry)) +} + +func (s *TombstoneStore) ListEntries(tx *bbolt.Tx) iter.Iterator[TombstoneEntry] { + return newTombstoneEntriesIterator(tx.Bucket(s.bucketName)) +} + +type tombstoneEntriesIterator struct { + iter *store.CursorIterator + cur TombstoneEntry + err error +} + +func newTombstoneEntriesIterator(bucket *bbolt.Bucket) *tombstoneEntriesIterator { + return &tombstoneEntriesIterator{iter: store.NewCursorIter(bucket.Cursor())} +} + +func (x *tombstoneEntriesIterator) Next() bool { + if x.err != nil || !x.iter.Next() { + return false + } + x.err = unmarshalTombstoneEntry(&x.cur, x.iter.At()) + return x.err == nil +} + +func (x *tombstoneEntriesIterator) At() TombstoneEntry { return x.cur } + +func (x *tombstoneEntriesIterator) Close() error { return x.iter.Close() } + +func (x *tombstoneEntriesIterator) Err() error { + if err := x.iter.Err(); err != nil { + return err + } + return x.err +} + +func marshalTombstoneEntry(e TombstoneEntry) store.KV { + k := marshalTombstoneEntryKey(e) + b := make([]byte, e.SizeVT()) + _, _ = e.MarshalToSizedBufferVT(b) + return store.KV{Key: k, Value: b} +} + +func marshalTombstoneEntryKey(e TombstoneEntry) []byte { + if e.key != nil { + b := make([]byte, len(e.key)) + copy(b, e.key) + return b + } + name := e.Name() + b := make([]byte, 16+len(name)) + binary.BigEndian.PutUint64(b[0:8], e.Index) + binary.BigEndian.PutUint64(b[8:16], uint64(e.AppendedAt)) + copy(b[16:], name) + return b +} + +func unmarshalTombstoneEntry(e *TombstoneEntry, kv store.KV) error { + if len(kv.Key) < 16 { + return ErrInvalidTombstoneEntry + } + e.key = make([]byte, len(kv.Key)) + copy(e.key, kv.Key) + e.Index = binary.BigEndian.Uint64(kv.Key[0:8]) + e.AppendedAt = int64(binary.BigEndian.Uint64(kv.Key[8:16])) + e.Tombstones = new(metastorev1.Tombstones) + if err := e.UnmarshalVT(kv.Value); err != nil { + return fmt.Errorf("%w: %w", ErrInvalidTombstoneEntry, err) + } + return nil +} diff --git a/pkg/metastore/index/tombstones/store/tombstone_store_test.go b/pkg/metastore/index/tombstones/store/tombstone_store_test.go new file mode 100644 index 0000000000..ca0f06a0fe --- /dev/null +++ b/pkg/metastore/index/tombstones/store/tombstone_store_test.go @@ -0,0 +1,111 @@ +package store + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestBlockQueueStore_StoreEntry(t *testing.T) { + db := test.BoltDB(t) + + s := NewTombstoneStore() + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, s.CreateBuckets(tx)) + + entries := make([]TombstoneEntry, 1000) + for i := range entries { + entries[i] = TombstoneEntry{ + Index: uint64(i), + AppendedAt: time.Now().UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "a"}, + }, + } + } + for i := range entries { + assert.NoError(t, s.StoreTombstones(tx, entries[i])) + } + require.NoError(t, tx.Commit()) + + s = NewTombstoneStore() + tx, err = db.Begin(false) + require.NoError(t, err) + iter := s.ListEntries(tx) + var i int + for iter.Next() { + assert.Less(t, i, len(entries)) + actual := iter.At() + expected := entries[i] + assert.Equal(t, expected.Index, actual.Index) + assert.Equal(t, expected.AppendedAt, actual.AppendedAt) + assert.Equal(t, expected.Tombstones, actual.Tombstones) + assert.NotNil(t, actual.key) + i++ + } + assert.Nil(t, iter.Err()) + assert.Nil(t, iter.Close()) + require.NoError(t, tx.Rollback()) +} + +func TestTombstoneStore_DeleteQueuedEntries(t *testing.T) { + db := test.BoltDB(t) + + s := NewTombstoneStore() + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, s.CreateBuckets(tx)) + + entries := make([]TombstoneEntry, 1000) + for i := range entries { + entries[i] = TombstoneEntry{ + Index: uint64(i), + AppendedAt: time.Now().UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "a"}, + }, + } + } + for i := range entries { + assert.NoError(t, s.StoreTombstones(tx, entries[i])) + } + require.NoError(t, tx.Commit()) + + // Delete random 25%. + tx, err = db.Begin(true) + require.NoError(t, err) + for i := 0; i < len(entries); i += 4 { + assert.NoError(t, s.DeleteTombstones(tx, entries[i])) + } + require.NoError(t, tx.Commit()) + + // Check remaining entries. + s = NewTombstoneStore() + tx, err = db.Begin(false) + require.NoError(t, err) + iter := s.ListEntries(tx) + var i int + for iter.Next() { + if i%4 == 0 { + // Skip deleted entries. + i++ + } + assert.Less(t, i, len(entries)) + actual := iter.At() + expected := entries[i] + assert.Equal(t, expected.Index, actual.Index) + assert.Equal(t, expected.AppendedAt, actual.AppendedAt) + assert.Equal(t, expected.Tombstones, actual.Tombstones) + assert.NotNil(t, actual.key) + i++ + } + assert.Nil(t, iter.Err()) + assert.Nil(t, iter.Close()) + require.NoError(t, tx.Rollback()) +} diff --git a/pkg/metastore/index/tombstones/tombstone_queue.go b/pkg/metastore/index/tombstones/tombstone_queue.go new file mode 100644 index 0000000000..560f8d691f --- /dev/null +++ b/pkg/metastore/index/tombstones/tombstone_queue.go @@ -0,0 +1,86 @@ +package tombstones + +import ( + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/tombstones/store" +) + +type tombstoneQueue struct{ head, tail *tombstones } + +// The only requirement to tombstoneKey is that it must be +// unique and must be received from the raft log. +type tombstoneKey string + +func (k *tombstoneKey) set(t *metastorev1.Tombstones) bool { + switch { + case t.Blocks != nil: + *k = tombstoneKey(t.Blocks.Name) + case t.Shard != nil: + *k = tombstoneKey(t.Shard.Name) + } + return len(*k) > 0 +} + +type tombstones struct { + store.TombstoneEntry + next, prev *tombstones +} + +func newTombstoneQueue() *tombstoneQueue { return &tombstoneQueue{} } + +func (q *tombstoneQueue) push(e *tombstones) { + if q.tail != nil { + q.tail.next = e + e.prev = q.tail + } else if q.head == nil { + q.head = e + } else { + panic("bug: queue has head but tail is nil") + } + q.tail = e +} + +func (q *tombstoneQueue) delete(e *tombstones) *tombstones { + if e.prev != nil { + e.prev.next = e.next + } else if e == q.head { + // This is the head. + q.head = e.next + } else { + panic("bug: attempting to delete a tombstone that is not in the queue") + } + if e.next != nil { + e.next.prev = e.prev + } else if e == q.tail { + // This is the tail. + q.tail = e.prev + } else { + panic("bug: attempting to delete a tombstone that is not in the queue") + } + e.next = nil + e.prev = nil + return e +} + +type tombstoneIter struct { + head *tombstones + current *tombstones + before int64 +} + +func (t *tombstoneIter) Next() bool { + if t.head == nil { + return false + } + if t.current == nil { + t.current = t.head + } else { + t.current = t.current.next + } + return t.current != nil && t.current.AppendedAt < t.before +} + +func (t *tombstoneIter) At() *metastorev1.Tombstones { return t.current.Tombstones } + +func (t *tombstoneIter) Err() error { return nil } +func (t *tombstoneIter) Close() error { return nil } diff --git a/pkg/metastore/index/tombstones/tombstone_queue_test.go b/pkg/metastore/index/tombstones/tombstone_queue_test.go new file mode 100644 index 0000000000..69028a1497 --- /dev/null +++ b/pkg/metastore/index/tombstones/tombstone_queue_test.go @@ -0,0 +1,165 @@ +package tombstones + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/tombstones/store" +) + +func TestTombstoneIterator(t *testing.T) { + queue := newTombstoneQueue() + now := time.Now() + entries := []*tombstones{ + { + TombstoneEntry: store.TombstoneEntry{ + Index: 1, + AppendedAt: now.Add(-5 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "block-1"}, + }, + }, + }, + { + TombstoneEntry: store.TombstoneEntry{ + Index: 2, + AppendedAt: now.Add(-4 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "block-2"}, + }, + }, + }, + { + TombstoneEntry: store.TombstoneEntry{ + Index: 3, + AppendedAt: now.Add(-3 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "block-3"}, + }, + }, + }, + { + TombstoneEntry: store.TombstoneEntry{ + Index: 4, + AppendedAt: now.Add(-2 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "block-4"}, + }, + }, + }, + { + TombstoneEntry: store.TombstoneEntry{ + Index: 5, + AppendedAt: now.Add(-1 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "block-5"}, + }, + }, + }, + } + + for _, entry := range entries { + queue.push(entry) + } + + t.Run("all entries before current time", func(t *testing.T) { + iter := &tombstoneIter{ + head: queue.head, + before: now.UnixNano(), + } + count := 0 + for iter.Next() { + count++ + assert.Equal(t, entries[count-1].Tombstones, iter.At()) + } + assert.Equal(t, len(entries), count) + }) + + t.Run("entries before specific time", func(t *testing.T) { + cutoffTime := now.Add(-3 * time.Hour) + iter := &tombstoneIter{ + head: queue.head, + before: cutoffTime.UnixNano(), + } + expected := []string{"block-1", "block-2"} + var actual []string + for iter.Next() { + actual = append(actual, iter.At().Blocks.Name) + } + assert.Equal(t, expected, actual) + }) + + t.Run("empty queue", func(t *testing.T) { + emptyQueue := newTombstoneQueue() + iter := &tombstoneIter{ + head: emptyQueue.head, + before: now.UnixNano(), + } + assert.False(t, iter.Next()) + }) + + t.Run("no entries before cutoff time", func(t *testing.T) { + iter := &tombstoneIter{ + head: queue.head, + before: now.Add(-10 * time.Hour).UnixNano(), + } + assert.False(t, iter.Next()) + }) +} + +func TestQueueDelete(t *testing.T) { + queue := newTombstoneQueue() + now := time.Now() + + entry1 := &tombstones{ + TombstoneEntry: store.TombstoneEntry{ + Index: 1, + AppendedAt: now.Add(-3 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "tombstone-1"}, + }, + }, + } + entry2 := &tombstones{ + TombstoneEntry: store.TombstoneEntry{ + Index: 2, + AppendedAt: now.Add(-2 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "tombstone-2"}, + }, + }, + } + entry3 := &tombstones{ + TombstoneEntry: store.TombstoneEntry{ + Index: 3, + AppendedAt: now.Add(-1 * time.Hour).UnixNano(), + Tombstones: &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{Name: "tombstone-3"}, + }, + }, + } + + queue.push(entry1) + queue.push(entry2) + queue.push(entry3) + + assert.Equal(t, entry1, queue.head) + assert.Equal(t, entry3, queue.tail) + + deleted := queue.delete(entry3) + assert.Equal(t, entry3, deleted) + + assert.NotNil(t, queue.tail) + assert.Equal(t, entry2, queue.tail) + + var count int + iter := &tombstoneIter{head: queue.head, before: now.UnixNano()} + for iter.Next() { + count++ + } + + assert.Equal(t, 2, count) +} diff --git a/pkg/metastore/index/tombstones/tombstones.go b/pkg/metastore/index/tombstones/tombstones.go new file mode 100644 index 0000000000..9d886a54ea --- /dev/null +++ b/pkg/metastore/index/tombstones/tombstones.go @@ -0,0 +1,186 @@ +package tombstones + +import ( + "time" + + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/tombstones/store" +) + +type TombstoneStore interface { + StoreTombstones(*bbolt.Tx, store.TombstoneEntry) error + DeleteTombstones(*bbolt.Tx, store.TombstoneEntry) error + ListEntries(*bbolt.Tx) iter.Iterator[store.TombstoneEntry] + CreateBuckets(*bbolt.Tx) error +} + +type Tombstones struct { + metrics *metrics + tombstones map[tombstoneKey]*tombstones + blocks map[tenantBlockKey]*tenantBlocks + queue *tombstoneQueue + store TombstoneStore +} + +type tenantBlockKey struct { + tenant string + shard uint32 +} + +type tenantBlocks struct { + blocks map[string]struct{} +} + +func NewTombstones(store TombstoneStore, reg prometheus.Registerer) *Tombstones { + return &Tombstones{ + metrics: newMetrics(reg), + tombstones: make(map[tombstoneKey]*tombstones), + blocks: make(map[tenantBlockKey]*tenantBlocks), + queue: newTombstoneQueue(), + store: store, + } +} + +func NewStore() *store.TombstoneStore { + return store.NewTombstoneStore() +} + +func (x *Tombstones) Exists(tenant string, shard uint32, block string) bool { + t, exists := x.blocks[tenantBlockKey{tenant: tenant, shard: shard}] + if exists { + _, exists = t.blocks[block] + } + return exists +} + +func (x *Tombstones) ListTombstones(before time.Time) iter.Iterator[*metastorev1.Tombstones] { + return &tombstoneIter{ + head: x.queue.head, + before: before.UnixNano(), + } +} + +func (x *Tombstones) AddTombstones(tx *bbolt.Tx, cmd *raft.Log, t *metastorev1.Tombstones) error { + var k tombstoneKey + if !k.set(t) { + return nil + } + v := store.TombstoneEntry{ + Index: cmd.Index, + AppendedAt: cmd.AppendedAt.UnixNano(), + Tombstones: t, + } + if !x.put(k, v) { + return nil + } + return x.store.StoreTombstones(tx, v) +} + +func (x *Tombstones) DeleteTombstones(tx *bbolt.Tx, cmd *raft.Log, tombstones ...*metastorev1.Tombstones) error { + for _, t := range tombstones { + if err := x.deleteTombstones(tx, cmd, t); err != nil { + return err + } + } + return nil +} + +func (x *Tombstones) deleteTombstones(tx *bbolt.Tx, _ *raft.Log, t *metastorev1.Tombstones) error { + var k tombstoneKey + if !k.set(t) { + return nil + } + e := x.delete(k) + if e == nil { + return nil + } + return x.store.DeleteTombstones(tx, e.TombstoneEntry) +} + +func (x *Tombstones) put(k tombstoneKey, v store.TombstoneEntry) bool { + if _, found := x.tombstones[k]; found { + return false + } + e := &tombstones{TombstoneEntry: v} + x.tombstones[k] = e + x.queue.push(e) + x.metrics.incrementTombstones(v.Tombstones) + if v.Blocks != nil { + // Keep track of the blocks we enqueued. This is + // necessary to answer if the block has already + // been deleted (within a limited time window). + x.putBlockTombstones(v.Blocks) + } + return true +} + +func (x *Tombstones) delete(k tombstoneKey) (t *tombstones) { + e, found := x.tombstones[k] + if !found { + return nil + } + delete(x.tombstones, k) + x.metrics.decrementTombstones(e.Tombstones) + if t = x.queue.delete(e); t != nil { + if t.Blocks != nil { + x.deleteBlockTombstones(t.Blocks) + } + } + return t +} + +func (x *Tombstones) putBlockTombstones(t *metastorev1.BlockTombstones) { + bk := tenantBlockKey{ + tenant: t.Tenant, + shard: t.Shard, + } + m, ok := x.blocks[bk] + if !ok { + m = &tenantBlocks{blocks: make(map[string]struct{})} + x.blocks[bk] = m + } + for _, b := range t.Blocks { + m.blocks[b] = struct{}{} + } +} + +func (x *Tombstones) deleteBlockTombstones(t *metastorev1.BlockTombstones) { + bk := tenantBlockKey{ + tenant: t.Tenant, + shard: t.Shard, + } + m, found := x.blocks[bk] + if !found { + return + } + for _, b := range t.Blocks { + delete(m.blocks, b) + } +} + +func (x *Tombstones) Init(tx *bbolt.Tx) error { + return x.store.CreateBuckets(tx) +} + +func (x *Tombstones) Restore(tx *bbolt.Tx) error { + x.queue = newTombstoneQueue() + clear(x.tombstones) + clear(x.blocks) + x.metrics.tombstones.Reset() + entries := x.store.ListEntries(tx) + defer func() { + _ = entries.Close() + }() + for entries.Next() { + var k tombstoneKey + if v := entries.At(); k.set(v.Tombstones) { + x.put(k, v) + } + } + return entries.Err() +} diff --git a/pkg/metastore/index/tombstones/tombstones_restore_test.go b/pkg/metastore/index/tombstones/tombstones_restore_test.go new file mode 100644 index 0000000000..e5e795b4db --- /dev/null +++ b/pkg/metastore/index/tombstones/tombstones_restore_test.go @@ -0,0 +1,90 @@ +package tombstones + +import ( + "testing" + "time" + + "github.com/hashicorp/raft" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/tombstones/store" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestTombstonesRestore(t *testing.T) { + now := time.Now() + db := test.BoltDB(t) + tombstoneStore := store.NewTombstoneStore() + + ts := NewTombstones(tombstoneStore, nil) + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, ts.Init(tx)) + require.NoError(t, tx.Commit()) + + for _, tombstone := range []*metastorev1.Tombstones{ + { + Blocks: &metastorev1.BlockTombstones{ + Name: "x-1", + Tenant: "tenant-1", + Shard: 1, + Blocks: []string{"block-1-1", "block-1-2"}, + }, + }, + { + Blocks: &metastorev1.BlockTombstones{ + Name: "x-2", + Tenant: "tenant-1", + Shard: 1, + Blocks: []string{"block-2-1", "block-2-2"}, + }, + }, + { + Blocks: &metastorev1.BlockTombstones{ + Name: "x-3", + Tenant: "tenant-2", + Shard: 2, + Blocks: []string{"block-3-1", "block-3-2"}, + }, + }, + } { + tx, err := db.Begin(true) + require.NoError(t, err) + err = ts.AddTombstones(tx, &raft.Log{Index: 1, AppendedAt: now}, tombstone) + require.NoError(t, err) + require.NoError(t, tx.Commit()) + } + + assert.True(t, ts.Exists("tenant-1", 1, "block-1-1")) + assert.True(t, ts.Exists("tenant-1", 1, "block-1-2")) + assert.True(t, ts.Exists("tenant-1", 1, "block-2-1")) + assert.True(t, ts.Exists("tenant-1", 1, "block-2-2")) + assert.True(t, ts.Exists("tenant-2", 2, "block-3-1")) + assert.True(t, ts.Exists("tenant-2", 2, "block-3-2")) + assert.Equal(t, 3, countTombstones(ts)) + + restored := NewTombstones(tombstoneStore, nil) + tx, err = db.Begin(true) + require.NoError(t, err) + err = restored.Restore(tx) + require.NoError(t, err) + require.NoError(t, tx.Commit()) + + assert.True(t, restored.Exists("tenant-1", 1, "block-1-1")) + assert.True(t, restored.Exists("tenant-1", 1, "block-1-2")) + assert.True(t, restored.Exists("tenant-1", 1, "block-2-1")) + assert.True(t, restored.Exists("tenant-1", 1, "block-2-2")) + assert.True(t, restored.Exists("tenant-2", 2, "block-3-1")) + assert.True(t, restored.Exists("tenant-2", 2, "block-3-2")) + assert.Equal(t, 3, countTombstones(restored)) + + futureTime := now.Add(time.Hour) + iter := restored.ListTombstones(futureTime) + count := 0 + for iter.Next() { + count++ + } + assert.Equal(t, 3, count) +} diff --git a/pkg/metastore/index/tombstones/tombstones_test.go b/pkg/metastore/index/tombstones/tombstones_test.go new file mode 100644 index 0000000000..8b062c5f7c --- /dev/null +++ b/pkg/metastore/index/tombstones/tombstones_test.go @@ -0,0 +1,98 @@ +package tombstones + +import ( + "testing" + "time" + + "github.com/hashicorp/raft" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/tombstones/store" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestTombstonesIdempotence(t *testing.T) { + db := test.BoltDB(t) + tombstoneStore := store.NewTombstoneStore() + + ts := NewTombstones(tombstoneStore, nil) + tx, err := db.Begin(true) + require.NoError(t, err) + require.NoError(t, ts.Init(tx)) + require.NoError(t, tx.Commit()) + + now := time.Now() + cmd := &raft.Log{ + Index: 1, + Term: 1, + Type: raft.LogCommand, + Data: []byte("test"), + AppendedAt: now, + } + + x := &metastorev1.Tombstones{ + Blocks: &metastorev1.BlockTombstones{ + Name: "test-block", + Tenant: "test-tenant", + Shard: 1, + Blocks: []string{"block-1", "block-2"}, + }, + } + + t.Run("AddTombstones", func(t *testing.T) { + tx, err = db.Begin(true) + require.NoError(t, err) + err = ts.AddTombstones(tx, cmd, x) + require.NoError(t, err) + require.NoError(t, tx.Commit()) + + assert.True(t, ts.Exists("test-tenant", 1, "block-1")) + assert.True(t, ts.Exists("test-tenant", 1, "block-2")) + + count := countTombstones(ts) + + tx, err = db.Begin(true) + require.NoError(t, err) + err = ts.AddTombstones(tx, cmd, x) + require.NoError(t, err) + require.NoError(t, tx.Commit()) + assert.Equal(t, count, countTombstones(ts)) + + assert.True(t, ts.Exists("test-tenant", 1, "block-1")) + assert.True(t, ts.Exists("test-tenant", 1, "block-2")) + }) + + t.Run("DeleteTombstones", func(t *testing.T) { + tx, err := db.Begin(true) + require.NoError(t, err) + err = ts.DeleteTombstones(tx, cmd, x) + require.NoError(t, err) + require.NoError(t, tx.Commit()) + + assert.False(t, ts.Exists("test-tenant", 1, "block-1")) + assert.False(t, ts.Exists("test-tenant", 1, "block-2")) + + count := countTombstones(ts) + + tx, err = db.Begin(true) + require.NoError(t, err) + err = ts.DeleteTombstones(tx, cmd, x) + require.NoError(t, err) + require.NoError(t, tx.Commit()) + assert.Equal(t, count, countTombstones(ts)) + + assert.False(t, ts.Exists("test-tenant", 1, "block-1")) + assert.False(t, ts.Exists("test-tenant", 1, "block-2")) + }) +} + +func countTombstones(ts *Tombstones) int { + var c int + iter := ts.ListTombstones(time.Now().Add(time.Hour)) + for iter.Next() { + c++ + } + return c +} diff --git a/pkg/metastore/index_raft_handler.go b/pkg/metastore/index_raft_handler.go new file mode 100644 index 0000000000..ec8b0f106d --- /dev/null +++ b/pkg/metastore/index_raft_handler.go @@ -0,0 +1,148 @@ +package metastore + +import ( + "context" + "errors" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/hashicorp/raft" + "go.etcd.io/bbolt" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + "github.com/grafana/pyroscope/v2/pkg/metastore/index" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + "github.com/grafana/pyroscope/v2/pkg/metastore/tracing" +) + +type IndexInserter interface { + InsertBlock(*bbolt.Tx, *metastorev1.BlockMeta) error +} + +type IndexDeleter interface { + DeleteShard(tx *bbolt.Tx, partition indexstore.Partition, tenant string, shard uint32) error +} + +type IndexWriter interface { + IndexInserter + IndexDeleter +} + +type Tombstones interface { + AddTombstones(*bbolt.Tx, *raft.Log, *metastorev1.Tombstones) error + DeleteTombstones(*bbolt.Tx, *raft.Log, ...*metastorev1.Tombstones) error + Exists(tenant string, shard uint32, block string) bool +} + +type IndexCommandHandler struct { + logger log.Logger + index IndexWriter + tombstones Tombstones + compactor compaction.Compactor +} + +func NewIndexCommandHandler( + logger log.Logger, + index IndexWriter, + tombstones Tombstones, + compactor compaction.Compactor, +) *IndexCommandHandler { + return &IndexCommandHandler{ + logger: logger, + index: index, + tombstones: tombstones, + compactor: compactor, + } +} + +func (m *IndexCommandHandler) AddBlock(ctx context.Context, tx *bbolt.Tx, cmd *raft.Log, req *metastorev1.AddBlockRequest) (resp *metastorev1.AddBlockResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "raft.AddBlockMetadata") + span.SetTag("block_id", req.Block.GetId()) + span.SetTag("shard", req.Block.GetShard()) + span.SetTag("compaction_level", req.Block.GetCompactionLevel()) + span.SetTag("raft_log_index", cmd.Index) + span.SetTag("raft_log_term", cmd.Term) + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + e := compaction.NewBlockEntry(cmd, req.Block) + if m.tombstones.Exists(e.Tenant, e.Shard, e.ID) { + level.Warn(m.logger).Log("msg", "block already added and compacted", "block", e.ID) + return new(metastorev1.AddBlockResponse), nil + } + + insertSpan, _ := tracing.StartSpanFromContext(ctx, "index.InsertBlock") + if err = m.index.InsertBlock(tx, req.Block); err != nil { + if errors.Is(err, index.ErrBlockExists) { + level.Warn(m.logger).Log("msg", "block already added", "block", e.ID) + return new(metastorev1.AddBlockResponse), nil + } + insertSpan.LogError(err) + insertSpan.SetError() + insertSpan.Finish() + level.Error(m.logger).Log("msg", "failed to add block to index", "block", e.ID, "err", err) + return nil, err + } + insertSpan.Finish() + + compactSpan, _ := tracing.StartSpanFromContext(ctx, "compactor.Compact") + defer compactSpan.Finish() + if err = m.compactor.Compact(tx, e); err != nil { + level.Error(m.logger).Log("msg", "failed to add block to compaction", "block", e.ID, "err", err) + compactSpan.LogError(err) + compactSpan.SetError() + return nil, err + } + return new(metastorev1.AddBlockResponse), nil +} + +func (m *IndexCommandHandler) TruncateIndex(ctx context.Context, tx *bbolt.Tx, cmd *raft.Log, req *raft_log.TruncateIndexRequest) (resp *raft_log.TruncateIndexResponse, err error) { + span, _ := tracing.StartSpanFromContext(ctx, "raft.TruncateIndex") + span.SetTag("tombstone_count", len(req.Tombstones)) + span.SetTag("raft_log_index", cmd.Index) + span.SetTag("raft_log_term", cmd.Term) + span.SetTag("request_term", req.Term) + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + if req.Term != cmd.Term { + level.Warn(m.logger).Log( + "msg", "rejecting index truncation request; term mismatch: leader has changed", + "current_term", cmd.Term, + "request_term", req.Term, + ) + return new(raft_log.TruncateIndexResponse), nil + } + for _, tombstone := range req.Tombstones { + // Although it's not strictly necessary, we may pass any tombstones + // to TruncateIndex, and the Partition member may be missing. + if p := tombstone.Shard; p != nil { + pk := indexstore.Partition{ + Timestamp: time.Unix(0, p.Timestamp), + Duration: time.Duration(p.Duration), + } + if err = m.index.DeleteShard(tx, pk, p.Tenant, p.Shard); err != nil { + level.Error(m.logger).Log("msg", "failed to delete partition", "err", err) + return nil, err + } + } + if err = m.tombstones.AddTombstones(tx, cmd, tombstone); err != nil { + level.Error(m.logger).Log("msg", "failed to add partition tombstone", "err", err) + return nil, err + } + } + return new(raft_log.TruncateIndexResponse), nil +} diff --git a/pkg/metastore/index_service.go b/pkg/metastore/index_service.go new file mode 100644 index 0000000000..3c7f619d99 --- /dev/null +++ b/pkg/metastore/index_service.go @@ -0,0 +1,242 @@ +package metastore + +import ( + "context" + goiter "iter" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + "go.etcd.io/bbolt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/metastore/fsm" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/cleaner/retention" + indexstore "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" + placement "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" +) + +type PlacementStats interface { + RecordStats(iter.Iterator[placement.Sample]) +} + +type IndexBlockFinder interface { + GetBlocks(*bbolt.Tx, *metastorev1.BlockList) ([]*metastorev1.BlockMeta, error) +} + +type IndexPartitionLister interface { + // Partitions provide access to all partitions in the index. + // They are iterated in the order of their creation and are + // guaranteed to be thread-safe for reads. + Partitions(*bbolt.Tx) goiter.Seq[indexstore.Partition] +} + +type IndexReader interface { + IndexBlockFinder + IndexPartitionLister +} + +func NewIndexService( + logger log.Logger, + raft Raft, + state State, + index IndexReader, + stats PlacementStats, +) *IndexService { + return &IndexService{ + logger: logger, + raft: raft, + state: state, + index: index, + stats: stats, + } +} + +type IndexService struct { + metastorev1.IndexServiceServer + + logger log.Logger + raft Raft + state State + index IndexReader + stats PlacementStats +} + +func (svc *IndexService) AddBlock( + ctx context.Context, + req *metastorev1.AddBlockRequest, +) (resp *metastorev1.AddBlockResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "IndexService.AddBlock") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + if block := req.GetBlock(); block != nil { + span.SetTag("block_id", block.GetId()) + span.SetTag("shard", block.GetShard()) + span.SetTag("compaction_level", block.GetCompactionLevel()) + } + + defer func() { + if err == nil { + svc.stats.RecordStats(statsFromMetadata(req.Block)) + } + }() + + return svc.addBlockMetadata(ctx, req) +} + +func (svc *IndexService) AddRecoveredBlock( + ctx context.Context, + req *metastorev1.AddBlockRequest, +) (resp *metastorev1.AddBlockResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "IndexService.AddRecoveredBlock") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + if block := req.GetBlock(); block != nil { + span.SetTag("block_id", block.GetId()) + span.SetTag("shard", block.GetShard()) + span.SetTag("compaction_level", block.GetCompactionLevel()) + } + + return svc.addBlockMetadata(ctx, req) +} + +func (svc *IndexService) addBlockMetadata( + ctx context.Context, + req *metastorev1.AddBlockRequest, +) (resp *metastorev1.AddBlockResponse, err error) { + if err = metadata.Sanitize(req.Block); err != nil { + level.Warn(svc.logger).Log("invalid metadata", "block", req.Block.Id, "err", err) + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + _, err = svc.raft.Propose( + ctx, + fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_ADD_BLOCK_METADATA), + &raft_log.AddBlockMetadataRequest{Metadata: req.Block}, + ) + if err != nil { + if !raftnode.IsRaftLeadershipError(err) { + level.Error(svc.logger).Log("msg", "failed to add block", "block", req.Block.Id, "err", err) + } + return nil, err + } + return new(metastorev1.AddBlockResponse), nil +} + +func (svc *IndexService) GetBlockMetadata( + ctx context.Context, + req *metastorev1.GetBlockMetadataRequest, +) (resp *metastorev1.GetBlockMetadataResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "IndexService.GetBlockMetadata") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + if list := req.GetBlocks(); list != nil { + span.SetTag("tenant_id", list.GetTenant()) + span.SetTag("shard", list.GetShard()) + span.SetTag("requested_blocks", len(list.GetBlocks())) + } + + read := func(tx *bbolt.Tx, _ raftnode.ReadIndex) { + resp, err = svc.getBlockMetadata(tx, req.GetBlocks()) + } + if readErr := svc.state.ConsistentRead(ctx, read); readErr != nil { + return nil, status.Error(codes.Unavailable, readErr.Error()) + } + return resp, err +} + +func (svc *IndexService) getBlockMetadata(tx *bbolt.Tx, list *metastorev1.BlockList) (*metastorev1.GetBlockMetadataResponse, error) { + found, err := svc.index.GetBlocks(tx, list) + if err != nil { + return nil, err + } + return &metastorev1.GetBlockMetadataResponse{Blocks: found}, nil +} + +func statsFromMetadata(md *metastorev1.BlockMeta) iter.Iterator[placement.Sample] { + return &sampleIterator{md: md} +} + +type sampleIterator struct { + md *metastorev1.BlockMeta + cur int +} + +func (s *sampleIterator) Err() error { return nil } +func (s *sampleIterator) Close() error { return nil } + +func (s *sampleIterator) Next() bool { + if s.cur >= len(s.md.Datasets) { + return false + } + s.cur++ + return true +} + +func (s *sampleIterator) At() placement.Sample { + ds := s.md.Datasets[s.cur-1] + return placement.Sample{ + TenantID: s.md.StringTable[ds.Tenant], + DatasetName: s.md.StringTable[ds.Name], + ShardOwner: s.md.StringTable[s.md.CreatedBy], + ShardID: s.md.Shard, + Size: ds.Size, + } +} + +func (svc *IndexService) TruncateIndex(ctx context.Context, rp retention.Policy) (err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "IndexService.TruncateIndex") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + var req raft_log.TruncateIndexRequest + read := func(tx *bbolt.Tx, r raftnode.ReadIndex) { + req.Tombstones = rp.CreateTombstones(tx, svc.index.Partitions(tx)) + req.Term = r.Term // The leader may change after we read the index. + } + if readErr := svc.state.ConsistentRead(ctx, read); readErr != nil { + return status.Error(codes.Unavailable, readErr.Error()) + } + + span.SetTag("tombstone_count", len(req.Tombstones)) + span.SetTag("term", req.Term) + + if len(req.Tombstones) == 0 { + return nil + } + if _, err = svc.raft.Propose(ctx, fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_TRUNCATE_INDEX), &req); err != nil { + if !raftnode.IsRaftLeadershipError(err) { + level.Error(svc.logger).Log("msg", "failed to truncate index", "err", err) + } + return err + } + return nil +} diff --git a/pkg/metastore/metastore.go b/pkg/metastore/metastore.go new file mode 100644 index 0000000000..069b76319d --- /dev/null +++ b/pkg/metastore/metastore.go @@ -0,0 +1,296 @@ +package metastore + +import ( + "context" + "flag" + "fmt" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + "github.com/thanos-io/objstore" + "go.etcd.io/bbolt" + "google.golang.org/grpc" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction/compactor" + "github.com/grafana/pyroscope/v2/pkg/metastore/compaction/scheduler" + "github.com/grafana/pyroscope/v2/pkg/metastore/fsm" + "github.com/grafana/pyroscope/v2/pkg/metastore/index" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/cleaner" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/cleaner/retention" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/dlq" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/tombstones" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + "github.com/grafana/pyroscope/v2/pkg/metastore/tracing" + placement "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" + "github.com/grafana/pyroscope/v2/pkg/util/health" +) + +type Config struct { + Address string `yaml:"address" category:"advanced"` + GRPCClientConfig grpcclient.Config `yaml:"grpc_client_config" doc:"description=Configures the gRPC client used to communicate with the metastore."` + MinReadyDuration time.Duration `yaml:"min_ready_duration" category:"advanced"` + Raft raftnode.Config `yaml:"raft"` + FSM fsm.Config `yaml:",inline" category:"advanced"` + Index index.Config `yaml:"index" category:"advanced"` + Compactor compactor.Config `yaml:",inline" category:"advanced"` + Scheduler scheduler.Config `yaml:",inline" category:"advanced"` +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + const prefix = "metastore." + f.StringVar(&cfg.Address, prefix+"address", "localhost:9095", "") + f.DurationVar(&cfg.MinReadyDuration, prefix+"min-ready-duration", 15*time.Second, "Minimum duration to wait after the internal readiness checks have passed but before succeeding the readiness endpoint. This is used to slowdown deployment controllers (eg. Kubernetes) after an instance is ready and before they proceed with a rolling update, to give the rest of the cluster instances enough time to receive some (DNS?) updates.") + cfg.GRPCClientConfig.RegisterFlagsWithPrefix(prefix+"grpc-client-config", f) + cfg.Raft.RegisterFlagsWithPrefix(prefix+"raft.", f) + cfg.FSM.RegisterFlagsWithPrefix(prefix, f) + cfg.Compactor.RegisterFlagsWithPrefix(prefix, f) + cfg.Scheduler.RegisterFlagsWithPrefix(prefix, f) + cfg.Index.RegisterFlagsWithPrefix(prefix+"index.", f) +} + +func (cfg *Config) Validate() error { + if cfg.Address == "" { + return fmt.Errorf("metastore.address is required") + } + if err := cfg.GRPCClientConfig.Validate(); err != nil { + return err + } + return cfg.Raft.Validate() +} + +type Metastore struct { + service services.Service + + config Config + overrides Overrides + logger log.Logger + reg prometheus.Registerer + health health.Service + + raft *raftnode.Node + fsm *fsm.FSM + contextRegistry *tracing.ContextRegistry + raftNodeClient raftnodepb.RaftNodeServiceClient + + bucket objstore.Bucket + placement *placement.Manager + recovery *dlq.Recovery + cleaner *cleaner.Cleaner + + index *index.Index + indexHandler *IndexCommandHandler + indexService *IndexService + + tombstones *tombstones.Tombstones + compactor *compactor.Compactor + scheduler *scheduler.Scheduler + compactionHandler *CompactionCommandHandler + compactionService *CompactionService + + leaderRead *raftnode.StateReader[*bbolt.Tx] + followerRead *raftnode.StateReader[*bbolt.Tx] + tenantService *TenantService + queryService *QueryService + + readyOnce sync.Once + readySince time.Time +} + +type Overrides interface { + retention.Overrides +} + +func New( + config Config, + overrides Overrides, + logger log.Logger, + reg prometheus.Registerer, + healthService health.Service, + client raftnodepb.RaftNodeServiceClient, + bucket objstore.Bucket, + placementMgr *placement.Manager, +) (*Metastore, error) { + m := &Metastore{ + config: config, + overrides: overrides, + logger: logger, + reg: reg, + health: healthService, + bucket: bucket, + placement: placementMgr, + raftNodeClient: client, + contextRegistry: tracing.NewContextRegistry(reg), + } + + var err error + if m.fsm, err = fsm.New(m.logger, m.reg, m.config.FSM, m.contextRegistry); err != nil { + return nil, fmt.Errorf("failed to initialize store: %w", err) + } + + // Initialization of the base components. + m.index = index.NewIndex(m.logger, index.NewStore(), config.Index, m.reg) + m.tombstones = tombstones.NewTombstones(tombstones.NewStore(), m.reg) + m.compactor = compactor.NewCompactor(config.Compactor, compactor.NewStore(), m.tombstones, m.reg) + m.scheduler = scheduler.NewScheduler(config.Scheduler, scheduler.NewStore(), m.reg) + + // FSM handlers that utilize the components. + m.indexHandler = NewIndexCommandHandler(m.logger, m.index, m.tombstones, m.compactor) + fsm.RegisterRaftCommandHandler(m.fsm, + fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_ADD_BLOCK_METADATA), + m.indexHandler.AddBlock) + fsm.RegisterRaftCommandHandler(m.fsm, + fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_TRUNCATE_INDEX), + m.indexHandler.TruncateIndex) + + m.compactionHandler = NewCompactionCommandHandler(m.logger, m.index, m.compactor, m.compactor, m.scheduler, m.tombstones) + fsm.RegisterRaftCommandHandler(m.fsm, + fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_GET_COMPACTION_PLAN_UPDATE), + m.compactionHandler.GetCompactionPlanUpdate) + fsm.RegisterRaftCommandHandler(m.fsm, + fsm.RaftLogEntryType(raft_log.RaftCommand_RAFT_COMMAND_UPDATE_COMPACTION_PLAN), + m.compactionHandler.UpdateCompactionPlan) + + m.fsm.RegisterRestorer(m.tombstones) + m.fsm.RegisterRestorer(m.compactor) + m.fsm.RegisterRestorer(m.scheduler) + m.fsm.RegisterRestorer(m.index) + + // We are ready to start raft as our FSM is fully configured. + if err = m.buildRaftNode(); err != nil { + return nil, err + } + + // Create the read-only interfaces to the state. + m.followerRead = m.newFollowerReader(client, m.raft, m.fsm) + m.leaderRead = m.newLeaderReader(m.raft, m.fsm) + + // Services should be registered after FSM and Raft have been initialized. + // Services provide an interface to interact with the metastore components. + m.compactionService = NewCompactionService(m.logger, m.raft) + m.indexService = NewIndexService(m.logger, m.raft, m.leaderRead, m.index, m.placement) + m.tenantService = NewTenantService(m.logger, m.followerRead, m.index) + m.queryService = NewQueryService(m.logger, m.followerRead, m.index) + m.recovery = dlq.NewRecovery(logger, config.Index.Recovery, m.indexService, bucket, m.reg) + m.cleaner = cleaner.NewCleaner(m.logger, m.overrides, config.Index.Cleaner, m.indexService) + + // These are the services that only run on the raft leader. + // Keep in mind that the node may not be the leader at the moment the + // service is starting, so it should be able to handle conflicts. + m.raft.RunOnLeader(m.recovery) + m.raft.RunOnLeader(m.placement) + m.raft.RunOnLeader(m.cleaner) + + m.service = services.NewBasicService(m.starting, m.running, m.stopping) + return m, nil +} + +func (m *Metastore) buildRaftNode() (err error) { + // Raft is configured to always restore the state from the latest snapshot + // (via FSM.Restore), if it is present. Otherwise, when no snapshots + // available, the state must be initialized explicitly via FSM.Init before + // we call raft.Init, which starts applying the raft log. + if m.raft, err = raftnode.NewNode(m.logger, m.config.Raft, m.reg, m.fsm, m.contextRegistry, m.raftNodeClient); err != nil { + return fmt.Errorf("failed to create raft node: %w", err) + } + + // Newly created raft node is not yet initialized and does not alter our + // FSM in any way. However, it gives us access to the snapshot store, and + // we can check whether we need to initialize the state (expensive), or we + // can defer to raft snapshots. This is an optimization: we want to avoid + // restoring the state twice: once at Init, and then at Restore. + snapshots, err := m.raft.ListSnapshots() + if err != nil { + level.Error(m.logger).Log("msg", "failed to list snapshots", "err", err) + // We continue trying; in the worst case we will initialize the state + // and then restore a snapshot received from the leader. + } + + if len(snapshots) == 0 { + level.Info(m.logger).Log("msg", "no state snapshots found") + // FSM won't be restored by raft, so we need to initialize it manually. + // Otherwise, raft will restore the state from a snapshot using + // fsm.Restore, which will initialize the state as well. + if err = m.fsm.Init(); err != nil { + level.Error(m.logger).Log("msg", "failed to initialize state", "err", err) + return err + } + } else { + level.Info(m.logger).Log("msg", "skipping state initialization as snapshots found") + } + + if err = m.raft.Init(); err != nil { + return fmt.Errorf("failed to initialize raft: %w", err) + } + + return nil +} + +func (m *Metastore) Register(server *grpc.Server) { + metastorev1.RegisterIndexServiceServer(server, m.indexService) + metastorev1.RegisterCompactionServiceServer(server, m.compactionService) + metastorev1.RegisterMetadataQueryServiceServer(server, m.queryService) + metastorev1.RegisterTenantServiceServer(server, m.tenantService) + m.raft.Register(server) +} + +func (m *Metastore) Service() services.Service { return m.service } + +func (m *Metastore) starting(context.Context) error { return nil } + +func (m *Metastore) stopping(_ error) error { + // We let clients observe the leadership transfer: it's their + // responsibility to connect to the new leader. We only need to + // make sure that any error returned to clients includes details + // about the raft leader, if applicable. + if err := m.raft.TransferLeadership(); err == nil { + // We were the leader and managed to transfer leadership – wait a bit + // to let the new leader settle. During this period we're still serving + // requests, but return an error with the new leader address. + level.Info(m.logger).Log("msg", "waiting for leadership transfer to complete") + time.Sleep(m.config.MinReadyDuration) + } + + // Tell clients to stop sending requests to this node. There are no any + // guarantees that clients will see or obey this. Normally, we would have + // stopped the gRPC server here, but we can't: it's managed by the service + // framework. Because of that we sleep another MinReadyDuration to let new + // client to discover that the node is not serving anymore. + m.health.SetNotServing() + time.Sleep(m.config.MinReadyDuration) + + m.raft.Shutdown() + m.fsm.Shutdown() + if m.contextRegistry != nil { + m.contextRegistry.Shutdown() + } + return nil +} + +func (m *Metastore) running(ctx context.Context) error { + m.health.SetServing() + <-ctx.Done() + return nil +} + +// CheckReady verifies if the metastore is ready to serve requests by +// ensuring the node is up-to-date with the leader's commit index. +func (m *Metastore) CheckReady(ctx context.Context) error { + if _, err := m.followerRead.WaitLeaderCommitIndexApplied(ctx); err != nil { + return err + } + m.readyOnce.Do(func() { + m.readySince = time.Now() + }) + if w := m.config.MinReadyDuration - time.Since(m.readySince); w > 0 { + return fmt.Errorf("%v before reporting readiness", w) + } + return nil +} diff --git a/pkg/metastore/metastore_raft.go b/pkg/metastore/metastore_raft.go new file mode 100644 index 0000000000..226ae991c8 --- /dev/null +++ b/pkg/metastore/metastore_raft.go @@ -0,0 +1,91 @@ +package metastore + +import ( + "context" + "time" + + "go.etcd.io/bbolt" + "google.golang.org/protobuf/proto" + + "github.com/grafana/pyroscope/v2/pkg/metastore/fsm" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +// Raft represents a Raft consensus protocol interface. Any modifications to +// the state should be proposed through the Raft interface. +type Raft interface { + Propose(context.Context, fsm.RaftLogEntryType, proto.Message) (proto.Message, error) +} + +// State represents a consistent read-only view of the metastore. +// The write interface is provided through the FSM raft command handlers. +type State interface { + ConsistentRead(context.Context, func(*bbolt.Tx, raftnode.ReadIndex)) error +} + +// newFollowerReader creates a new follower reader – implementation of the +// Follower Read pattern. See raftnode.StateReader for details. +// The provided client is used to communicate with the leader node. +func (m *Metastore) newFollowerReader( + client raftnodepb.RaftNodeServiceClient, + node *raftnode.Node, + fsm *fsm.FSM, +) *raftnode.StateReader[*bbolt.Tx] { + return raftnode.NewStateReader[*bbolt.Tx]( + // NOTE(kolesnikovae): replace the client with the local + // raft node to implement Leader Read pattern. + &leaderNode{client: client, timeout: m.config.Raft.ApplyTimeout}, + &localNode{node: node, fsm: fsm}, + m.config.Raft.LogIndexCheckInterval, + m.config.Raft.ReadIndexMaxDistance, + ) +} + +// newLeaderReader creates a new leader reader – implementation of the +// Leader Read pattern. See raftnode.StateReader for details. +// The provided node is treated as the leader, attempt to read from +// the local node in follower state will fail. +func (m *Metastore) newLeaderReader( + node *raftnode.Node, + fsm *fsm.FSM, +) *raftnode.StateReader[*bbolt.Tx] { + return raftnode.NewStateReader[*bbolt.Tx]( + node, + &localNode{node: node, fsm: fsm}, + m.config.Raft.LogIndexCheckInterval, + m.config.Raft.ReadIndexMaxDistance, + ) +} + +// leaderNode is an implementation of raftnode.Leader interface that +// communicates with the leader using the RaftNode service client to +// acquire its commit index (ReadIndex). +type leaderNode struct { + client raftnodepb.RaftNodeServiceClient + timeout time.Duration +} + +func (l *leaderNode) ReadIndex() (read raftnode.ReadIndex, err error) { + ctx, cancel := context.WithTimeout(context.Background(), l.timeout) + defer cancel() + resp, err := l.client.ReadIndex(ctx, new(raftnodepb.ReadIndexRequest)) + if err != nil { + return read, err + } + read.CommitIndex = resp.CommitIndex + read.Term = resp.Term + return read, nil +} + +// localNode represents the state machine of the local node. +// In the current implementation, fsm.FSM does keep track of +// the applied index, therefore we consult to raft to get it. +type localNode struct { + node *raftnode.Node + fsm *fsm.FSM +} + +func (f *localNode) AppliedIndex() uint64 { return f.node.AppliedIndex() } + +func (f *localNode) Read(fn func(*bbolt.Tx)) error { return f.fsm.Read(fn) } diff --git a/pkg/metastore/query_service.go b/pkg/metastore/query_service.go new file mode 100644 index 0000000000..6fde46f6a5 --- /dev/null +++ b/pkg/metastore/query_service.go @@ -0,0 +1,169 @@ +package metastore + +import ( + "context" + "errors" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + "go.etcd.io/bbolt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/index" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" +) + +type IndexQuerier interface { + QueryMetadata(*bbolt.Tx, context.Context, index.MetadataQuery) ([]*metastorev1.BlockMeta, error) + QueryMetadataLabels(*bbolt.Tx, context.Context, index.MetadataQuery) ([]*typesv1.Labels, error) +} + +type QueryService struct { + metastorev1.MetadataQueryServiceServer + + logger log.Logger + state State + index IndexQuerier +} + +func NewQueryService( + logger log.Logger, + state State, + index IndexQuerier, +) *QueryService { + return &QueryService{ + logger: logger, + state: state, + index: index, + } +} + +func (svc *QueryService) QueryMetadata( + ctx context.Context, + req *metastorev1.QueryMetadataRequest, +) (resp *metastorev1.QueryMetadataResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "QueryService.QueryMetadata") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + span.SetTag("tenant_id", req.GetTenantId()) + span.SetTag("start_time", req.GetStartTime()) + span.SetTag("end_time", req.GetEndTime()) + span.SetTag("labels", len(req.GetLabels())) + if q := req.GetQuery(); q != "" { + span.SetTag("query", q) + } + + read := func(tx *bbolt.Tx, _ raftnode.ReadIndex) { + resp, err = svc.queryMetadata(ctx, tx, req) + } + if readErr := svc.state.ConsistentRead(ctx, read); readErr != nil { + return nil, status.Error(codes.Unavailable, readErr.Error()) + } + return resp, err +} + +func (svc *QueryService) queryMetadata( + ctx context.Context, + tx *bbolt.Tx, + req *metastorev1.QueryMetadataRequest, +) (resp *metastorev1.QueryMetadataResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "QueryService.indexQueryMetadata") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + metas, err := svc.index.QueryMetadata(tx, ctx, index.MetadataQuery{ + Tenant: req.TenantId, + StartTime: time.UnixMilli(req.StartTime), + EndTime: time.UnixMilli(req.EndTime), + Expr: req.Query, + Labels: req.Labels, + }) + if err == nil { + span.SetTag("result_count", len(metas)) + return &metastorev1.QueryMetadataResponse{Blocks: metas}, nil + } + var invalid *index.InvalidQueryError + if errors.As(err, &invalid) { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + level.Error(svc.logger).Log("msg", "failed to query metadata", "err", err) + return nil, status.Error(codes.Internal, err.Error()) +} + +func (svc *QueryService) QueryMetadataLabels( + ctx context.Context, + req *metastorev1.QueryMetadataLabelsRequest, +) (resp *metastorev1.QueryMetadataLabelsResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "QueryService.QueryMetadataLabels") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + span.SetTag("tenant_id", req.GetTenantId()) + span.SetTag("start_time", req.GetStartTime()) + span.SetTag("end_time", req.GetEndTime()) + span.SetTag("labels", len(req.GetLabels())) + if q := req.GetQuery(); q != "" { + span.SetTag("query", q) + } + + read := func(tx *bbolt.Tx, _ raftnode.ReadIndex) { + resp, err = svc.queryMetadataLabels(ctx, tx, req) + } + if readErr := svc.state.ConsistentRead(ctx, read); readErr != nil { + return nil, status.Error(codes.Unavailable, readErr.Error()) + } + return resp, err +} + +func (svc *QueryService) queryMetadataLabels( + ctx context.Context, + tx *bbolt.Tx, + req *metastorev1.QueryMetadataLabelsRequest, +) (resp *metastorev1.QueryMetadataLabelsResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "QueryService.indexQueryMetadataLabels") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + labels, err := svc.index.QueryMetadataLabels(tx, ctx, index.MetadataQuery{ + Tenant: req.TenantId, + StartTime: time.UnixMilli(req.StartTime), + EndTime: time.UnixMilli(req.EndTime), + Expr: req.Query, + Labels: req.Labels, + }) + if err == nil { + span.SetTag("result_count", len(labels)) + return &metastorev1.QueryMetadataLabelsResponse{Labels: labels}, nil + } + var invalid *index.InvalidQueryError + if errors.As(err, &invalid) { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + level.Error(svc.logger).Log("msg", "failed to query metadata labels", "err", err) + return nil, status.Error(codes.Internal, err.Error()) +} diff --git a/pkg/metastore/raftnode/errors.go b/pkg/metastore/raftnode/errors.go new file mode 100644 index 0000000000..cb9909dacf --- /dev/null +++ b/pkg/metastore/raftnode/errors.go @@ -0,0 +1,53 @@ +package raftnode + +import ( + "errors" + + "github.com/hashicorp/raft" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +func IsRaftLeadershipError(err error) bool { + return errors.Is(err, raft.ErrLeadershipLost) || + errors.Is(err, raft.ErrNotLeader) || + errors.Is(err, raft.ErrLeadershipTransferInProgress) || + errors.Is(err, raft.ErrRaftShutdown) +} + +type RaftLeaderLocator interface { + LeaderWithID() (raft.ServerAddress, raft.ServerID) +} + +func WithRaftLeaderStatusDetails(err error, raft RaftLeaderLocator) error { + if err == nil || !IsRaftLeadershipError(err) { + return err + } + serverAddress, serverID := raft.LeaderWithID() + s := status.New(codes.Unavailable, err.Error()) + if serverID != "" { + s, _ = s.WithDetails(&raftnodepb.RaftNode{ + Id: string(serverID), + Address: string(serverAddress), + }) + } + return s.Err() +} + +func RaftLeaderFromStatusDetails(err error) (*raftnodepb.RaftNode, bool) { + s, ok := status.FromError(err) + if !ok { + return nil, false + } + if s.Code() != codes.Unavailable { + return nil, false + } + for _, d := range s.Details() { + if n, ok := d.(*raftnodepb.RaftNode); ok { + return n, true + } + } + return nil, false +} diff --git a/pkg/metastore/raftnode/logstore.go b/pkg/metastore/raftnode/logstore.go new file mode 100644 index 0000000000..b51ec56e19 --- /dev/null +++ b/pkg/metastore/raftnode/logstore.go @@ -0,0 +1,94 @@ +package raftnode + +import ( + "fmt" + "time" + + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" +) + +// timeoutLogStore wraps a raft.LogStore with a deadline on write operations. +// If the underlying store takes longer than the configured timeout, the +// operation returns an error instead of blocking indefinitely. +// +// This prevents a stuck disk (high I/O wait) from permanently stalling +// the raft leader. Without this, a blocked StoreLogs call freezes the +// leader's main goroutine while heartbeats continue on separate goroutines, +// preventing followers from ever triggering an election. +type timeoutLogStore struct { + store raft.LogStore + timeout time.Duration + writeLatency prometheus.Histogram + timeouts prometheus.Counter +} + +func newTimeoutLogStore(store raft.LogStore, timeout time.Duration, writeLatency prometheus.Histogram, timeouts prometheus.Counter) raft.LogStore { + if timeout <= 0 { + return store + } + return &timeoutLogStore{ + store: store, + timeout: timeout, + writeLatency: writeLatency, + timeouts: timeouts, + } +} + +func (s *timeoutLogStore) FirstIndex() (uint64, error) { return s.store.FirstIndex() } +func (s *timeoutLogStore) LastIndex() (uint64, error) { return s.store.LastIndex() } +func (s *timeoutLogStore) GetLog(index uint64, log *raft.Log) error { + return s.store.GetLog(index, log) +} +func (s *timeoutLogStore) DeleteRange(min, max uint64) error { + return s.store.DeleteRange(min, max) +} + +// IsMonotonic implements raft.MonotonicLogStore by delegating to the +// underlying store. Without this, raft uses compactLogs (which retains +// TrailingLogs) instead of removeOldLogs after snapshot install on a +// follower — leaving stale WAL entries that cause non-monotonic index +// errors when the leader resumes replication. +func (s *timeoutLogStore) IsMonotonic() bool { + if m, ok := s.store.(raft.MonotonicLogStore); ok { + return m.IsMonotonic() + } + return false +} + +func (s *timeoutLogStore) StoreLog(log *raft.Log) error { + return s.withTimeout(func() error { + return s.store.StoreLog(log) + }) +} + +func (s *timeoutLogStore) StoreLogs(logs []*raft.Log) error { + return s.withTimeout(func() error { + return s.store.StoreLogs(logs) + }) +} + +func (s *timeoutLogStore) withTimeout(fn func() error) error { + start := time.Now() + done := make(chan error, 1) + go func() { + done <- fn() + }() + select { + case err := <-done: + s.writeLatency.Observe(time.Since(start).Seconds()) + return err + case <-time.After(s.timeout): + // Check if the operation completed concurrently with the timeout. + // Go's select picks randomly when multiple cases are ready. + select { + case err := <-done: + s.writeLatency.Observe(time.Since(start).Seconds()) + return err + default: + } + s.writeLatency.Observe(time.Since(start).Seconds()) + s.timeouts.Inc() + return fmt.Errorf("log store write timed out after %s", s.timeout) + } +} diff --git a/pkg/metastore/raftnode/node.go b/pkg/metastore/raftnode/node.go new file mode 100644 index 0000000000..5e30164271 --- /dev/null +++ b/pkg/metastore/raftnode/node.go @@ -0,0 +1,371 @@ +package raftnode + +import ( + "context" + "errors" + "flag" + "fmt" + "net" + "os" + "path/filepath" + "strings" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/google/uuid" + "github.com/grafana/dskit/flagext" + "github.com/grafana/dskit/tracing" + "github.com/hashicorp/raft" + raftwal "github.com/hashicorp/raft-wal" + "github.com/prometheus/client_golang/prometheus" + oteltrace "go.opentelemetry.io/otel/trace" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + + "github.com/grafana/pyroscope/v2/pkg/metastore/fsm" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +type ContextRegistry interface { + Store(id string, ctx context.Context) +} + +type Config struct { + Dir string `yaml:"dir"` + SnapshotsDir string `yaml:"snapshots_dir" doc:"hidden"` + SnapshotsImportDir string `yaml:"snapshots_import_dir" category:"advanced" doc:"hidden"` + + BootstrapPeers []string `yaml:"bootstrap_peers" category:"advanced"` + BootstrapExpectPeers int `yaml:"bootstrap_expect_peers" category:"advanced"` + AutoJoin bool `yaml:"auto_join" category:"advanced"` + + ServerID string `yaml:"server_id" category:"advanced"` + BindAddress string `yaml:"bind_address" category:"advanced"` + AdvertiseAddress string `yaml:"advertise_address" category:"advanced"` + + ApplyTimeout time.Duration `yaml:"apply_timeout" category:"advanced" doc:"hidden"` + LogIndexCheckInterval time.Duration `yaml:"log_index_check_interval" category:"advanced" doc:"hidden"` + ReadIndexMaxDistance uint64 `yaml:"read_index_max_distance" category:"advanced" doc:"hidden"` + + WALCacheEntries uint64 `yaml:"wal_cache_entries" category:"advanced" doc:"hidden"` + TrailingLogs uint64 `yaml:"trailing_logs" category:"advanced" doc:"hidden"` + SnapshotsRetain uint64 `yaml:"snapshots_retain" category:"advanced" doc:"hidden"` + SnapshotInterval time.Duration `yaml:"snapshot_interval" category:"advanced" doc:"hidden"` + SnapshotThreshold uint64 `yaml:"snapshot_threshold" category:"advanced" doc:"hidden"` + TransportConnPoolSize uint64 `yaml:"transport_conn_pool_size" category:"advanced" doc:"hidden"` + TransportTimeout time.Duration `yaml:"transport_timeout" category:"advanced" doc:"hidden"` + LogStoreTimeout time.Duration `yaml:"log_store_timeout" category:"advanced" doc:"hidden"` + + // If set, wraps the log store after construction. Used only for testing. + LogStoreMiddleware func(raft.LogStore) raft.LogStore `yaml:"-"` +} + +const ( + defaultRaftDir = "./data/v2/metastore/raft" + defaultSnapshotsDir = defaultRaftDir + + defaultWALCacheEntries = 512 + defaultTrailingLogs = 18 << 10 + defaultSnapshotsRetain = 3 + defaultSnapshotInterval = 180 * time.Second + defaultSnapshotThreshold = 8 << 10 + defaultTransportConnPoolSize = 10 + defaultTransportTimeout = 10 * time.Second + defaultLogStoreTimeout = 10 * time.Second +) + +func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.StringVar(&cfg.Dir, prefix+"dir", defaultRaftDir, "Directory to store WAL and raft state. It must be a persistent directory, not a tmpfs or similar.") + f.StringVar(&cfg.SnapshotsDir, prefix+"snapshots-dir", defaultSnapshotsDir, "Directory to store FSM snapshots. Raft creates 'snapshots' subdirectory in this directory. It must be a persistent directory, not a tmpfs or similar.") + f.StringVar(&cfg.SnapshotsImportDir, prefix+"snapshots-import-dir", "", "Directory to import snapshots from; the directory must contain 'snapshots' subdirectory. If not set, no import will be done.") + + f.Var((*flagext.StringSlice)(&cfg.BootstrapPeers), prefix+"bootstrap-peers", "") + f.IntVar(&cfg.BootstrapExpectPeers, prefix+"bootstrap-expect-peers", 1, "Expected number of peers including the local node.") + f.BoolVar(&cfg.AutoJoin, prefix+"auto-join", false, "If enabled, new nodes (without a state) will try to join an existing cluster on startup.") + + f.StringVar(&cfg.ServerID, prefix+"server-id", "localhost:9099", "") + f.StringVar(&cfg.BindAddress, prefix+"bind-address", "localhost:9099", "") + f.StringVar(&cfg.AdvertiseAddress, prefix+"advertise-address", "localhost:9099", "") + + f.DurationVar(&cfg.ApplyTimeout, prefix+"apply-timeout", 5*time.Second, "") + f.DurationVar(&cfg.LogIndexCheckInterval, prefix+"log-index-check-interval", 14*time.Millisecond, "") + f.Uint64Var(&cfg.ReadIndexMaxDistance, prefix+"read-index-max-distance", 10<<10, "") + + f.Uint64Var(&cfg.WALCacheEntries, prefix+"wal-cache-entries", defaultWALCacheEntries, "") + f.Uint64Var(&cfg.TrailingLogs, prefix+"trailing-logs", defaultTrailingLogs, "") + f.Uint64Var(&cfg.SnapshotsRetain, prefix+"snapshots-retain", defaultSnapshotsRetain, "") + f.DurationVar(&cfg.SnapshotInterval, prefix+"snapshot-interval", defaultSnapshotInterval, "") + f.Uint64Var(&cfg.SnapshotThreshold, prefix+"snapshot-threshold", defaultSnapshotThreshold, "") + f.Uint64Var(&cfg.TransportConnPoolSize, prefix+"transport-conn-pool-size", defaultTransportConnPoolSize, "") + f.DurationVar(&cfg.TransportTimeout, prefix+"transport-timeout", defaultTransportTimeout, "") + f.DurationVar(&cfg.LogStoreTimeout, prefix+"log-store-timeout", defaultLogStoreTimeout, "") +} + +func (cfg *Config) Validate() error { + // TODO(kolesnikovae): Check the params. + return nil +} + +type Node struct { + logger log.Logger + config Config + metrics *metrics + reg prometheus.Registerer + fsm raft.FSM + contextRegistry ContextRegistry + + walDir string + wal *raftwal.WAL + snapshots *raft.FileSnapshotStore + transport *raft.NetworkTransport + raft *raft.Raft + logStore raft.LogStore + stableStore raft.StableStore + snapshotStore raft.SnapshotStore + + observer *Observer + service *RaftNodeService + + raftNodeClient raftnodepb.RaftNodeServiceClient +} + +func NewNode( + logger log.Logger, + config Config, + reg prometheus.Registerer, + fsm raft.FSM, + contextRegistry ContextRegistry, + raftNodeClient raftnodepb.RaftNodeServiceClient, +) (_ *Node, err error) { + n := Node{ + logger: logger, + config: config, + metrics: newMetrics(reg), + reg: reg, + fsm: fsm, + contextRegistry: contextRegistry, + raftNodeClient: raftNodeClient, + } + + defer func() { + if err != nil { + // If the initialization fails, initialized components + // should be de-initialized gracefully. + n.Shutdown() + } + }() + + addr, err := net.ResolveTCPAddr("tcp", config.AdvertiseAddress) + if err != nil { + return nil, err + } + n.transport, err = raft.NewTCPTransport( + config.BindAddress, addr, + int(config.TransportConnPoolSize), + config.TransportTimeout, + os.Stderr) + if err != nil { + return nil, err + } + + if err = n.openStore(); err != nil { + return nil, err + } + + return &n, nil +} + +func (n *Node) Init() (err error) { + raftConfig := raft.DefaultConfig() + // TODO: Wrap gokit + // config.Logger + raftConfig.LogLevel = "debug" + + raftConfig.TrailingLogs = n.config.TrailingLogs + raftConfig.SnapshotThreshold = n.config.SnapshotThreshold + raftConfig.SnapshotInterval = n.config.SnapshotInterval + raftConfig.LocalID = raft.ServerID(n.config.ServerID) + + n.raft, err = raft.NewRaft(raftConfig, n.fsm, n.logStore, n.stableStore, n.snapshotStore, n.transport) + if err != nil { + return fmt.Errorf("starting raft node: %w", err) + } + n.observer = NewRaftStateObserver(n.logger, n.raft, n.metrics.state) + n.service = NewRaftNodeService(n) + + hasState, err := raft.HasExistingState(n.logStore, n.stableStore, n.snapshotStore) + if err != nil { + return fmt.Errorf("failed to check for existing state: %w", err) + } + if !hasState { + if n.config.AutoJoin { + level.Info(n.logger).Log("msg", "no existing state found and auto-join is enabled, trying to join existing raft cluster...") + if err = n.tryAutoJoin(); err != nil { + level.Warn(n.logger).Log("msg", "failed to auto-join raft cluster", "err", err) + } else { + level.Info(n.logger).Log("msg", "successfully joined existing raft cluster") + return nil + } + } + + level.Info(n.logger).Log("msg", "no existing state found and auto-join is disabled, bootstrapping raft cluster...") + if err = n.bootstrap(); err != nil { + return fmt.Errorf("failed to bootstrap cluster: %w", err) + } + } else { + level.Debug(n.logger).Log("msg", "restoring existing state, not bootstrapping") + } + + return nil +} + +func (n *Node) openStore() (err error) { + if err = n.createDirs(); err != nil { + return err + } + n.wal, err = raftwal.Open(n.walDir) + if err != nil { + return fmt.Errorf("failed to open WAL: %w", err) + } + if err = n.importSnapshots(); err != nil { + return fmt.Errorf("failed to copy snapshots: %w", err) + } + n.snapshots, err = raft.NewFileSnapshotStore(n.config.SnapshotsDir, int(n.config.SnapshotsRetain), os.Stderr) + if err != nil { + return fmt.Errorf("failed to open shapshot store: %w", err) + } + n.logStore = n.wal + n.logStore, _ = raft.NewLogCache(int(n.config.WALCacheEntries), n.logStore) + + // For testing purposes only. Needs to happen here, before wrapping the store. + if n.config.LogStoreMiddleware != nil { + n.logStore = n.config.LogStoreMiddleware(n.logStore) + } + + n.logStore = newTimeoutLogStore(n.logStore, n.config.LogStoreTimeout, n.metrics.logStoreWrite, n.metrics.logStoreTimeout) + n.stableStore = n.wal + n.snapshotStore = n.snapshots + return nil +} + +func (n *Node) createDirs() (err error) { + n.walDir = filepath.Join(n.config.Dir, "wal") + if err = os.MkdirAll(n.walDir, 0755); err != nil { + return fmt.Errorf("WAL dir: %w", err) + } + // Raft will create 'snapshots' subdirectory in the SnapshotsDir. + if err = os.MkdirAll(n.config.SnapshotsDir, 0755); err != nil { + return fmt.Errorf("snapshot directory: %w", err) + } + return nil +} + +func (n *Node) Shutdown() { + if n.raft != nil { + if err := n.raft.Shutdown().Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to shutdown raft", "err", err) + } + n.observer.Deregister() + } + if n.transport != nil { + if err := n.transport.Close(); err != nil { + level.Error(n.logger).Log("msg", "failed to close transport", "err", err) + } + } + if n.wal != nil { + if err := n.wal.Close(); err != nil { + level.Error(n.logger).Log("msg", "failed to close WAL", "err", err) + } + } +} + +func (n *Node) ListSnapshots() ([]*raft.SnapshotMeta, error) { + return n.snapshots.List() +} + +func (n *Node) Register(server *grpc.Server) { + raftnodepb.RegisterRaftNodeServiceServer(server, n.service) +} + +// LeaderActivity is started when the node becomes a leader and stopped +// when it stops being a leader. The implementation MUST be idempotent. +type LeaderActivity interface { + Start() + Stop() +} + +type leaderStateHandler struct{ activity LeaderActivity } + +func (h *leaderStateHandler) Observe(state raft.RaftState) { + if state == raft.Leader { + h.activity.Start() + } else { + h.activity.Stop() + } +} + +func (n *Node) RunOnLeader(a LeaderActivity) { + n.observer.RegisterHandler(&leaderStateHandler{activity: a}) +} + +func (n *Node) TransferLeadership() (err error) { + switch err = n.raft.LeadershipTransfer().Error(); { + case err == nil: + case errors.Is(err, raft.ErrNotLeader): + // Not a leader, nothing to do. + case strings.Contains(err.Error(), "cannot find peer"): + // No peers, nothing to do. + default: + level.Error(n.logger).Log("msg", "failed to transfer leadership", "err", err) + } + return err +} + +// Propose makes an attempt to apply the given command to the FSM. +// The function returns an error if node is not the leader. +func (n *Node) Propose(ctx context.Context, t fsm.RaftLogEntryType, m proto.Message) (resp proto.Message, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "node.Propose") + otelSpan := oteltrace.SpanFromContext(ctx) + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + ctxID := uuid.New().String() + n.contextRegistry.Store(ctxID, ctx) + + otelSpan.AddEvent("marshalling log entry") + + raw, err := fsm.MarshalEntry(t, m) + if err != nil { + return nil, err + } + + otelSpan.AddEvent("log entry marshalled") + timer := prometheus.NewTimer(n.metrics.apply) + defer timer.ObserveDuration() + + otelSpan.AddEvent("applying log entry") + + future := n.raft.ApplyLog(raft.Log{ + Data: raw, + Extensions: []byte(ctxID), + }, n.config.ApplyTimeout) + + otelSpan.AddEvent("waiting for apply result") + + if err = future.Error(); err != nil { + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + r := future.Response().(fsm.Response) + + otelSpan.AddEvent("apply result received") + if r.Data != nil { + resp = r.Data + } + return resp, r.Err +} diff --git a/pkg/metastore/raftnode/node_admin.go b/pkg/metastore/raftnode/node_admin.go new file mode 100644 index 0000000000..7742f8349c --- /dev/null +++ b/pkg/metastore/raftnode/node_admin.go @@ -0,0 +1,135 @@ +package raftnode + +import ( + "fmt" + + "github.com/go-kit/log/level" + "github.com/hashicorp/raft" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +func (n *Node) RemoveNode(request *raftnodepb.RemoveNodeRequest) (*raftnodepb.RemoveNodeResponse, error) { + level.Info(n.logger).Log("msg", "removing node", "id", request.ServerId) + + // Send a round of heartbeats to confirm we are the leader. If we are not, the request will be retried on the leader node. + if err := n.raft.VerifyLeader().Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to remove node, we are not the leader", "id", request.ServerId) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + // Verify that we are on the same term as the one in the request. Otherwise, the request could be operating on stale information. + err := n.verifyCurrentTerm(request.CurrentTerm) + if err != nil { + return nil, err + } + + // make sure we are not removing ourselves, we need to be demoted first + if n.config.ServerID == request.ServerId { + level.Error(n.logger).Log("msg", "failed to remove node, we cannot remove ourselves", "id", request.ServerId) + return nil, fmt.Errorf("leadership must be transferred first") + } + + if err := n.raft.RemoveServer(raft.ServerID(request.ServerId), 0, 0).Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to remove node, error from raft", "node", request.ServerId, "err", err) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + level.Info(n.logger).Log("msg", "node removed", "id", request.ServerId) + return &raftnodepb.RemoveNodeResponse{}, nil +} + +func (n *Node) AddNode(request *raftnodepb.AddNodeRequest) (*raftnodepb.AddNodeResponse, error) { + level.Info(n.logger).Log("msg", "adding node", "id", request.ServerId) + + // Send a round of heartbeats to confirm we are the leader. If we are not, the request will be retried on the leader node. + if err := n.raft.VerifyLeader().Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to add node, we are not the leader", "id", request.ServerId) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + // Verify that we are on the same term as the one in the request. Otherwise, the request could be operating on stale information. + err := n.verifyCurrentTerm(request.CurrentTerm) + if err != nil { + return nil, err + } + + if err := n.raft.AddVoter(raft.ServerID(request.ServerId), raft.ServerAddress(request.ServerId), 0, 0).Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to add node, error from raft", "node", request.ServerId, "err", err) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + level.Info(n.logger).Log("msg", "node added", "id", request.ServerId) + return &raftnodepb.AddNodeResponse{}, nil +} + +func (n *Node) DemoteLeader(request *raftnodepb.DemoteLeaderRequest) (*raftnodepb.DemoteLeaderResponse, error) { + level.Info(n.logger).Log("msg", "demoting node", "id", request.ServerId) + + // Send a round of heartbeats to confirm we are the leader. If we are not, the request will be retried on the leader node. + if err := n.raft.VerifyLeader().Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to demote node, we are not the leader", "id", request.ServerId) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + // Verify that we are on the same term as the one in the request. Otherwise, the request could be operating on stale information. + err := n.verifyCurrentTerm(request.CurrentTerm) + if err != nil { + return nil, err + } + + // Make sure we are demoting the node from the request (we can only demote ourselves) + if n.config.ServerID != request.ServerId { + level.Error(n.logger).Log("msg", "failed to demote node, the target node is not the leader", "id", request.ServerId) + return nil, fmt.Errorf("the target node is not the leader") + } + + if err := n.raft.LeadershipTransfer().Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to demote node, error from raft", "node", request.ServerId, "err", err) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + level.Info(n.logger).Log("msg", "node demoted", "id", request.ServerId) + return &raftnodepb.DemoteLeaderResponse{}, nil +} + +func (n *Node) PromoteToLeader(request *raftnodepb.PromoteToLeaderRequest) (*raftnodepb.PromoteToLeaderResponse, error) { + level.Info(n.logger).Log("msg", "promoting node", "id", request.ServerId) + + // Send a round of heartbeats to confirm we are the leader. If we are not, the request will be retried on the leader node. + if err := n.raft.VerifyLeader().Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to promote node, we are not the leader", "id", request.ServerId) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + // Verify that we are on the same term as the one in the request. Otherwise, the request could be operating on stale information. + err := n.verifyCurrentTerm(request.CurrentTerm) + if err != nil { + return nil, err + } + + // make sure we are not promoting ourselves + if n.config.ServerID == request.ServerId { + level.Error(n.logger).Log("msg", "failed to promote node, we cannot promote ourselves", "node", request.ServerId) + return nil, status.Error(codes.InvalidArgument, "a node cannot promote itself") + } + + if err := n.raft.LeadershipTransferToServer(raft.ServerID(request.ServerId), raft.ServerAddress(request.ServerId)).Error(); err != nil { + level.Error(n.logger).Log("msg", "failed to promote node, error from raft", "node", request.ServerId, "err", err) + return nil, WithRaftLeaderStatusDetails(err, n.raft) + } + + level.Info(n.logger).Log("msg", "node promoted", "id", request.ServerId) + return &raftnodepb.PromoteToLeaderResponse{}, nil +} + +func (n *Node) verifyCurrentTerm(requestTerm uint64) error { + currentTerm := n.raft.CurrentTerm() + if requestTerm < currentTerm { + level.Error(n.logger).Log("msg", "node change request invalid, request term lower than current term", "request_term", requestTerm, "raft_term", currentTerm) + return status.Error(codes.InvalidArgument, fmt.Sprintf("request term (%d) lower than raft term (%d)", requestTerm, currentTerm)) + } + return nil +} diff --git a/pkg/metastore/raftnode/node_bootstrap.go b/pkg/metastore/raftnode/node_bootstrap.go new file mode 100644 index 0000000000..d048440033 --- /dev/null +++ b/pkg/metastore/raftnode/node_bootstrap.go @@ -0,0 +1,161 @@ +package raftnode + +import ( + "context" + "errors" + "fmt" + "slices" + "strings" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/backoff" + "github.com/grafana/dskit/dns" + "github.com/hashicorp/raft" + + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +func (n *Node) bootstrap() error { + peers, err := n.bootstrapPeersWithRetries() + if err != nil { + return fmt.Errorf("failed to resolve peers: %w", err) + } + logger := log.With(n.logger, + "server_id", n.config.ServerID, + "advertise_address", n.config.AdvertiseAddress, + "peers", fmt.Sprint(peers)) + lastPeer := peers[len(peers)-1] + if raft.ServerAddress(n.config.AdvertiseAddress) != lastPeer.Address { + level.Info(logger).Log("msg", "not the bootstrap node, skipping") + return nil + } + level.Info(logger).Log("msg", "bootstrapping raft") + bootstrap := n.raft.BootstrapCluster(raft.Configuration{Servers: peers}) + if bootstrapErr := bootstrap.Error(); bootstrapErr != nil { + if !errors.Is(bootstrapErr, raft.ErrCantBootstrap) { + return fmt.Errorf("failed to bootstrap raft: %w", bootstrapErr) + } + } + return nil +} + +func (n *Node) bootstrapPeersWithRetries() (peers []raft.Server, err error) { + prov := dns.NewProvider(dns.MiekgdnsResolverType, 2, n.logger, n.reg) + attempt := func() bool { + peers, err = n.bootstrapPeers(prov) + level.Debug(n.logger).Log("msg", "resolving bootstrap peers", "peers", fmt.Sprint(peers), "err", err) + if err != nil { + _ = level.Error(n.logger).Log("msg", "failed to resolve bootstrap peers", "err", err) + return false + } + return true + } + backoffConfig := backoff.Config{ + MinBackoff: 1 * time.Second, + MaxBackoff: 10 * time.Second, + MaxRetries: 20, + } + backOff := backoff.New(context.Background(), backoffConfig) + for backOff.Ongoing() { + if !attempt() { + backOff.Wait() + } else { + return peers, nil + } + } + return nil, fmt.Errorf("failed to resolve bootstrap peers after %d retries %w", backOff.NumRetries(), err) +} + +const autoJoinTimeout = 10 * time.Second + +func (n *Node) tryAutoJoin() error { + // we can only auto-join if there is a real raft cluster running + ctx, cancel := context.WithTimeout(context.Background(), autoJoinTimeout) + defer cancel() + + readIndexResp, err := n.raftNodeClient.ReadIndex(ctx, &raftnodepb.ReadIndexRequest{}) + if err != nil { + return fmt.Errorf("failed to get current term for auto-join: %w", err) + } + + logger := log.With(n.logger, + "server_id", n.config.ServerID, + "advertise_address", n.config.AdvertiseAddress) + + // try to join the cluster via the leader + level.Info(logger).Log("msg", "attempting to join existing cluster", "current_term", readIndexResp.Term) + _, err = n.raftNodeClient.AddNode(ctx, &raftnodepb.AddNodeRequest{ + ServerId: n.config.AdvertiseAddress, + CurrentTerm: readIndexResp.Term, + }) + + if err != nil { + return fmt.Errorf("failed to auto-join cluster: %w", err) + } + + return nil +} + +func (n *Node) bootstrapPeers(prov *dns.Provider) ([]raft.Server, error) { + // The peer list always includes the local node. + peers := make([]raft.Server, 0, len(n.config.BootstrapPeers)+1) + peers = append(peers, raft.Server{ + Suffrage: raft.Voter, + ID: raft.ServerID(n.config.ServerID), + Address: raft.ServerAddress(n.config.AdvertiseAddress), + }) + // Note that raft requires stable node IDs, therefore we're using + // the node FQDN:port for both purposes: as the identifier and as the + // address. This requires a DNS SRV record lookup without further + // resolution of A records (dnssrvnoa+). + // + // Alternatively, peers may be specified explicitly in the + // "{addr}" format, where the node is the optional node + // identifier. + var resolve []string + for _, peer := range n.config.BootstrapPeers { + if strings.Contains(peer, "+") { + resolve = append(resolve, peer) + } else { + peers = append(peers, discovery.ParsePeer(peer)) + } + } + if len(resolve) > 0 { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := prov.Resolve(ctx, resolve); err != nil { + return nil, fmt.Errorf("failed to resolve bootstrap peers: %w", err) + } + resolvedPeers := prov.Addresses() + if len(resolvedPeers) == 0 { + // The local node is the only one in the cluster, but peers + // are expected to be present. Stop here to avoid bootstrapping + // a single-node cluster. + return nil, fmt.Errorf("bootstrap peers can't be resolved") + } + for _, peer := range resolvedPeers { + peers = append(peers, raft.Server{ + Suffrage: raft.Voter, + ID: raft.ServerID(peer), + Address: raft.ServerAddress(peer), + }) + } + } + // Finally, we sort and deduplicate the peers: the first one + // is to boostrap the cluster. If there are nodes with distinct + // IDs but the same address, bootstrapping will fail. + slices.SortFunc(peers, func(a, b raft.Server) int { + return strings.Compare(string(a.ID), string(b.ID)) + }) + peers = slices.CompactFunc(peers, func(a, b raft.Server) bool { + return a.ID == b.ID + }) + if len(peers) != n.config.BootstrapExpectPeers { + return nil, fmt.Errorf("expected number of bootstrap peers not reached: got %d, expected %d\n%+v", + len(peers), n.config.BootstrapExpectPeers, peers) + } + return peers, nil +} diff --git a/pkg/metastore/raftnode/node_info.go b/pkg/metastore/raftnode/node_info.go new file mode 100644 index 0000000000..2aa89f4dc5 --- /dev/null +++ b/pkg/metastore/raftnode/node_info.go @@ -0,0 +1,62 @@ +package raftnode + +import ( + "sort" + + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + "github.com/grafana/pyroscope/v2/pkg/util/build" +) + +func (n *Node) NodeInfo() (*raftnodepb.NodeInfo, error) { + configFuture := n.raft.GetConfiguration() + err := configFuture.Error() + if err != nil { + return nil, err + } + + config := configFuture.Configuration() + _, leaderID := n.raft.LeaderWithID() + + info := &raftnodepb.NodeInfo{ + ServerId: n.config.ServerID, + AdvertisedAddress: n.config.AdvertiseAddress, + State: n.raft.State().String(), + LeaderId: string(leaderID), + CommitIndex: n.raft.CommitIndex(), + AppliedIndex: n.raft.AppliedIndex(), + LastIndex: n.raft.LastIndex(), + Stats: statsProto(n.raft.Stats()), + Peers: make([]*raftnodepb.NodeInfo_Peer, len(config.Servers)), + ConfigurationIndex: configFuture.Index(), + CurrentTerm: n.raft.CurrentTerm(), + BuildVersion: build.Version, + BuildRevision: build.Revision, + } + + for i, server := range config.Servers { + info.Peers[i] = &raftnodepb.NodeInfo_Peer{ + ServerId: string(server.ID), + ServerAddress: string(server.Address), + Suffrage: server.Suffrage.String(), + } + } + + return info, nil +} + +func statsProto(m map[string]string) *raftnodepb.NodeInfo_Stats { + stats := &raftnodepb.NodeInfo_Stats{ + Name: make([]string, len(m)), + Value: make([]string, len(m)), + } + var i int + for name := range m { + stats.Name[i] = name + i++ + } + sort.Strings(stats.Name) + for j, name := range stats.Name { + stats.Value[j] = m[name] + } + return stats +} diff --git a/pkg/metastore/raftnode/node_metrics.go b/pkg/metastore/raftnode/node_metrics.go new file mode 100644 index 0000000000..75ff0cd14f --- /dev/null +++ b/pkg/metastore/raftnode/node_metrics.go @@ -0,0 +1,71 @@ +package raftnode + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type metrics struct { + apply prometheus.Histogram + read prometheus.Histogram + state *prometheus.GaugeVec + logStoreWrite prometheus.Histogram + logStoreTimeout prometheus.Counter +} + +func newMetrics(reg prometheus.Registerer) *metrics { + m := &metrics{ + apply: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "raft_apply_command_duration_seconds", + Help: "Duration of applying a command to the Raft log", + Buckets: prometheus.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + + read: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "raft_read_index_wait_duration_seconds", + Help: "Duration of the Raft log read index wait", + Buckets: prometheus.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + + state: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "raft_state", + Help: "Current Raft state", + }, + []string{"state"}, + ), + + logStoreWrite: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "raft_log_store_write_duration_seconds", + Help: "Duration of log store write operations", + Buckets: prometheus.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + + logStoreTimeout: prometheus.NewCounter(prometheus.CounterOpts{ + Name: "raft_log_store_write_timeouts_total", + Help: "Number of log store write operations that timed out", + }), + } + + if reg != nil { + util.RegisterOrGet(reg, m.apply) + util.RegisterOrGet(reg, m.read) + util.RegisterOrGet(reg, m.state) + util.RegisterOrGet(reg, m.logStoreWrite) + util.RegisterOrGet(reg, m.logStoreTimeout) + } + + return m +} diff --git a/pkg/metastore/raftnode/node_read.go b/pkg/metastore/raftnode/node_read.go new file mode 100644 index 0000000000..1d64a413e2 --- /dev/null +++ b/pkg/metastore/raftnode/node_read.go @@ -0,0 +1,269 @@ +package raftnode + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" +) + +var ( + ErrConsistentRead = errors.New("consistent read failed") + ErrLagBehind = errors.New("replica has fallen too far behind") + ErrAborted = errors.New("aborted") +) + +// ReadIndex is the lower bound for the state any query must operate against. +// However, it does not guarantee snapshot isolation or an upper bound (which +// is the applied index of the state machine being queried). +// +// Refer to https://web.stanford.edu/~ouster/cgi-bin/papers/OngaroPhD.pdf, +// paragraph 6.4, "Processing read-only queries more efficiently". +type ReadIndex struct { + // CommitIndex is the index of the last log entry that was committed by + // the leader and is guaranteed to be present on all followers. + CommitIndex uint64 + // Term the leader was in when the entry was committed. + Term uint64 +} + +type Leader interface { + ReadIndex() (ReadIndex, error) +} + +type FSM[Tx any] interface { + AppliedIndex() uint64 + Read(func(Tx)) error +} + +// StateReader represents the read-only state of the replicated state machine. +// It allows performing read-only transactions on the leader's and follower's +// state machines. +type StateReader[Tx any] struct { + leader Leader + fsm FSM[Tx] + checkInterval time.Duration + maxDistance uint64 +} + +// NewStateReader creates a new interface to query the replicated state. +// If the provided leader implementation is the local node, the interface +// implements the Leader Read pattern. Otherwise, it implements the Follower +// Read pattern. +// +// > This approach is more efficient than committing read-only queries as new +// > entries in the log, since it avoids synchronous disk writes. To improve +// > efficiency further, the leader can amortize the cost of confirming its +// > leadership: it can use a single round of heartbeats for any number of +// > read-only queries that it has accumulated. +// > +// > Followers could also help offload the processing of read-only queries. +// > This would improve the system’s read throughput, and it would also +// > divert load away from the leader, allowing the leader to process more +// > read-write requests. However, these reads would also run the risk of +// > returning stale data without additional precautions. For example, a +// > partitioned follower might not receive any new log entries from the leader +// > for long periods of time, or even if a follower received a heartbeat from +// > a leader, that leader might itself be deposed and not yet know it. +// > To serve reads safely, the follower could issue a request to the leader +// > that just asked for a current readIndex (the leader would execute steps +// > 1–3 above); the follower could then execute steps 4 and 5 on its own state +// > machine for any number of accumulated read-only queries. +// +// The applied index is checked on the configured interval. It the distance +// between the read index and the applied index exceeds the configured +// threshold, the operation fails with ErrLagBehind. Any error returned by +// the reader is wrapped with ErrConsistentRead. +func NewStateReader[Tx any]( + leader Leader, + fsm FSM[Tx], + checkInterval time.Duration, + maxDistance uint64, +) *StateReader[Tx] { + return &StateReader[Tx]{ + leader: leader, + fsm: fsm, + checkInterval: checkInterval, + maxDistance: maxDistance, + } +} + +// ConsistentRead performs a read-only operation on the state machine, whether +// it's a leader or a follower. +// +// The transaction passed to the provided function has read-only access to the +// most up-to-date data, reflecting the updates from all prior write operations +// that were successful. If the function returns an error, it's guaranteed that +// the state has not been accessed. These errors can and should be retried on +// another replica. +// +// Currently, each ConsistentRead requests the new read index from the leader. +// It's possible to "pipeline" such queries to minimize communications by +// obtaining the applied index with WaitLeaderCommitIndexApplied and checking +// the currently applied index every time entering the transaction. Take into +// account that the FSM state might be changed at any time (e.g., restored from +// a snapshot). +// +// It's caller's responsibility to handle errors encountered while using the +// provided transaction, such as I/O errors or logical inconsistencies. +func (r *StateReader[Tx]) ConsistentRead(ctx context.Context, read func(tx Tx, index ReadIndex)) error { + if err := r.consistentRead(ctx, read); err != nil { + return fmt.Errorf("%w: %w", ErrConsistentRead, err) + } + return nil +} + +func (r *StateReader[Tx]) consistentRead(ctx context.Context, read func(tx Tx, index ReadIndex)) error { + readIndex, err := r.WaitLeaderCommitIndexApplied(ctx) + if err != nil { + return err + } + var readErr error + fn := func(tx Tx) { + // Now that we've acquired access to the state after catch up with + // the leader, we can perform the read operation. However, there's a + // possibility that the FSM has been restored from a snapshot right + // after the index check and before the transaction begins (blocking + // state restore). We perform the check again to detect this, and + // abort the operation if this is the case. + if r.fsm.AppliedIndex() < readIndex.CommitIndex { + readErr = ErrAborted + return + } + // NOTE(kolesnikovae): The leader guarantees that the state observed is + // not older than its committed index but does not guarantee it is the + // latest possible state at the time of the read. + read(tx, readIndex) + } + if err = r.fsm.Read(fn); err != nil { + // The FSM might not be able to perform the read operation due to the + // underlying storage issues. In this case, we return the error before + // providing the transaction handle to the caller. + return err + } + return readErr +} + +// WaitLeaderCommitIndexApplied blocks until the local +// applied index reaches the leader read index +func (r *StateReader[tx]) WaitLeaderCommitIndexApplied(ctx context.Context) (ReadIndex, error) { + readIndex, err := r.leader.ReadIndex() + if err != nil { + return ReadIndex{}, err + } + return readIndex, waitIndexReached(ctx, + r.fsm.AppliedIndex, + readIndex.CommitIndex, + r.checkInterval, + int(r.maxDistance), + ) +} + +func (n *Node) ReadIndex() (ReadIndex, error) { + timer := prometheus.NewTimer(n.metrics.read) + defer timer.ObserveDuration() + v, err := n.readIndex() + return v, WithRaftLeaderStatusDetails(err, n.raft) +} + +func (n *Node) AppliedIndex() uint64 { return n.raft.AppliedIndex() } + +func (n *Node) readIndex() (ReadIndex, error) { + // > If the leader has not yet marked an entry from its current term + // > committed, it waits until it has done so. The Leader Completeness + // > Property guarantees that a leader has all committed entries, but + // > at the start of its term, it may not know which those are. To find + // > out, it needs to commit an entry from its term. Raft handles this + // > by having each leader commit a blank no-op entry into the log at + // > the start of its term. As soon as this no-op entry is committed, + // > the leader’s commit index will be at least as large as any other + // > servers’ during its term. + term := n.raft.CurrentTerm() + // See the "runLeader" and "dispatchLogs" implementation (hashicorp raft) + // for details: when the leader is elected, it issues a noop, we only need + // to ensure that the entry is committed before we access the current + // commit index. This may incur substantial latency, if replicas are slow, + // but it's the only way to ensure that the leader has all committed + // entries. We also keep track of the current term to ensure that the + // leader has not changed while we were waiting for the noop to be + // committed and heartbeat messages to be exchanged. + if err := n.waitLastIndexCommitted(); err != nil { + return ReadIndex{}, err + } + commitIndex := n.raft.CommitIndex() + // > The leader needs to make sure it has not been superseded by a newer + // > leader of which it is unaware. It issues a new round of heartbeats + // > and waits for their acknowledgments from a majority of the cluster. + // > Once these acknowledgments are received, the leader knows that there + // > could not have existed a leader for a greater term at the moment it + // > sent the heartbeats. Thus, the readIndex was, at the time, the + // > largest commit index ever seen by any server in the cluster. + if err := n.raft.VerifyLeader().Error(); err != nil { + // The error includes details about the actual leader the request + // should be directed to; the client should retry the operation. + return ReadIndex{}, err + } + // The CommitIndex and leader heartbeats must be in the same term. + // Otherwise, we can't guarantee that this is the leader's commit index + // (mind the ABA problem), and thus, we can't guarantee completeness. + if n.raft.CurrentTerm() != term { + // There's a chance that the leader has changed since we've checked + // the leader status. The client should retry the operation, to + // ensure correctness of the read index. + return ReadIndex{}, raft.ErrLeadershipLost + } + // The node was the leader before we saved readIndex, and no elections + // have occurred while we were confirming leadership. + return ReadIndex{CommitIndex: commitIndex, Term: term}, nil +} + +func (n *Node) waitLastIndexCommitted() error { + ctx, cancel := context.WithTimeout(context.Background(), n.config.ApplyTimeout) + defer cancel() + return waitIndexReached(ctx, + n.raft.CommitIndex, + n.raft.LastIndex(), + n.config.LogIndexCheckInterval, + int(n.config.ReadIndexMaxDistance), + ) +} + +// waitIndexReached blocks until a >= b. +// If b - a >= maxDistance, the function return ErrLagBehind. +// reached is guaranteed to be false, if err != nil. +func waitIndexReached( + ctx context.Context, + src func() uint64, + dst uint64, + interval time.Duration, + maxDistance int, +) error { + if reached, err := compareIndex(src, dst, maxDistance); err != nil || reached { + return err + } + t := time.NewTicker(interval) + defer t.Stop() + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-t.C: + if reached, err := compareIndex(src, dst, maxDistance); err != nil || reached { + return err + } + } + } +} + +func compareIndex(src func() uint64, dst uint64, maxDistance int) (bool, error) { + cur := src() + if maxDistance > 0 { + if delta := int(dst) - int(cur); delta > maxDistance { + return false, ErrLagBehind + } + } + return cur >= dst, nil +} diff --git a/pkg/metastore/raftnode/observer.go b/pkg/metastore/raftnode/observer.go new file mode 100644 index 0000000000..05c29eb764 --- /dev/null +++ b/pkg/metastore/raftnode/observer.go @@ -0,0 +1,91 @@ +package raftnode + +import ( + "sync" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" +) + +// StateHandler is called every time the +// Raft state change is observed. +type StateHandler interface { + Observe(raft.RaftState) +} + +type Observer struct { + logger log.Logger + raft *raft.Raft + observer *raft.Observer + state *prometheus.GaugeVec + mu sync.Mutex + handlers []StateHandler + c chan raft.Observation + stop chan struct{} + done chan struct{} +} + +func NewRaftStateObserver(logger log.Logger, r *raft.Raft, state *prometheus.GaugeVec) *Observer { + o := &Observer{ + logger: logger, + raft: r, + c: make(chan raft.Observation, 1), + stop: make(chan struct{}), + done: make(chan struct{}), + state: state, + } + level.Debug(o.logger).Log("msg", "registering raft state observer") + o.observer = raft.NewObserver(o.c, true, func(o *raft.Observation) bool { + _, ok := o.Data.(raft.RaftState) + return ok + }) + r.RegisterObserver(o.observer) + o.updateRaftState() + go o.run() + return o +} + +func (o *Observer) RegisterHandler(h StateHandler) { + o.mu.Lock() + o.handlers = append(o.handlers, h) + o.mu.Unlock() + o.updateRaftState() +} + +func (o *Observer) Deregister() { + level.Debug(o.logger).Log("msg", "deregistering raft observer") + o.raft.DeregisterObserver(o.observer) + close(o.stop) + <-o.done +} + +func (o *Observer) run() { + defer func() { + close(o.done) + }() + for { + select { + case <-o.c: + o.updateRaftState() + case <-o.stop: + return + } + } +} + +func (o *Observer) updateRaftState() { + state := o.raft.State() + level.Debug(o.logger).Log("msg", "raft state changed", "raft_state", state) + if o.state != nil { + o.state.Reset() + o.state.WithLabelValues(state.String()).Set(1) + } + o.mu.Lock() + handlers := o.handlers + o.mu.Unlock() + for _, h := range handlers { + h.Observe(state) + } +} diff --git a/pkg/metastore/raftnode/raftnodepb/raft_node.pb.go b/pkg/metastore/raftnode/raftnodepb/raft_node.pb.go new file mode 100644 index 0000000000..30cb22ff89 --- /dev/null +++ b/pkg/metastore/raftnode/raftnodepb/raft_node.pb.go @@ -0,0 +1,988 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: metastore/raftnode/raftnodepb/raft_node.proto + +package raftnodepb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type RaftNode struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RaftNode) Reset() { + *x = RaftNode{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RaftNode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RaftNode) ProtoMessage() {} + +func (x *RaftNode) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RaftNode.ProtoReflect.Descriptor instead. +func (*RaftNode) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{0} +} + +func (x *RaftNode) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RaftNode) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +type ReadIndexRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReadIndexRequest) Reset() { + *x = ReadIndexRequest{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadIndexRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadIndexRequest) ProtoMessage() {} + +func (x *ReadIndexRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadIndexRequest.ProtoReflect.Descriptor instead. +func (*ReadIndexRequest) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{1} +} + +type ReadIndexResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + CommitIndex uint64 `protobuf:"varint,1,opt,name=commit_index,json=commitIndex,proto3" json:"commit_index,omitempty"` + Term uint64 `protobuf:"varint,2,opt,name=term,proto3" json:"term,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReadIndexResponse) Reset() { + *x = ReadIndexResponse{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadIndexResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadIndexResponse) ProtoMessage() {} + +func (x *ReadIndexResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadIndexResponse.ProtoReflect.Descriptor instead. +func (*ReadIndexResponse) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{2} +} + +func (x *ReadIndexResponse) GetCommitIndex() uint64 { + if x != nil { + return x.CommitIndex + } + return 0 +} + +func (x *ReadIndexResponse) GetTerm() uint64 { + if x != nil { + return x.Term + } + return 0 +} + +type NodeInfoRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NodeInfoRequest) Reset() { + *x = NodeInfoRequest{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NodeInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeInfoRequest) ProtoMessage() {} + +func (x *NodeInfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeInfoRequest.ProtoReflect.Descriptor instead. +func (*NodeInfoRequest) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{3} +} + +type NodeInfoResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Node *NodeInfo `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NodeInfoResponse) Reset() { + *x = NodeInfoResponse{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NodeInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeInfoResponse) ProtoMessage() {} + +func (x *NodeInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeInfoResponse.ProtoReflect.Descriptor instead. +func (*NodeInfoResponse) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{4} +} + +func (x *NodeInfoResponse) GetNode() *NodeInfo { + if x != nil { + return x.Node + } + return nil +} + +type NodeInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerId string `protobuf:"bytes,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + AdvertisedAddress string `protobuf:"bytes,2,opt,name=advertised_address,json=advertisedAddress,proto3" json:"advertised_address,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + LeaderId string `protobuf:"bytes,4,opt,name=leader_id,json=leaderId,proto3" json:"leader_id,omitempty"` + CommitIndex uint64 `protobuf:"varint,5,opt,name=commit_index,json=commitIndex,proto3" json:"commit_index,omitempty"` + AppliedIndex uint64 `protobuf:"varint,6,opt,name=applied_index,json=appliedIndex,proto3" json:"applied_index,omitempty"` + LastIndex uint64 `protobuf:"varint,7,opt,name=last_index,json=lastIndex,proto3" json:"last_index,omitempty"` + Stats *NodeInfo_Stats `protobuf:"bytes,8,opt,name=stats,proto3" json:"stats,omitempty"` + Peers []*NodeInfo_Peer `protobuf:"bytes,9,rep,name=peers,proto3" json:"peers,omitempty"` + ConfigurationIndex uint64 `protobuf:"varint,10,opt,name=configuration_index,json=configurationIndex,proto3" json:"configuration_index,omitempty"` + CurrentTerm uint64 `protobuf:"varint,11,opt,name=current_term,json=currentTerm,proto3" json:"current_term,omitempty"` + BuildVersion string `protobuf:"bytes,12,opt,name=build_version,json=buildVersion,proto3" json:"build_version,omitempty"` + BuildRevision string `protobuf:"bytes,13,opt,name=build_revision,json=buildRevision,proto3" json:"build_revision,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NodeInfo) Reset() { + *x = NodeInfo{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NodeInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeInfo) ProtoMessage() {} + +func (x *NodeInfo) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeInfo.ProtoReflect.Descriptor instead. +func (*NodeInfo) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{5} +} + +func (x *NodeInfo) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + +func (x *NodeInfo) GetAdvertisedAddress() string { + if x != nil { + return x.AdvertisedAddress + } + return "" +} + +func (x *NodeInfo) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *NodeInfo) GetLeaderId() string { + if x != nil { + return x.LeaderId + } + return "" +} + +func (x *NodeInfo) GetCommitIndex() uint64 { + if x != nil { + return x.CommitIndex + } + return 0 +} + +func (x *NodeInfo) GetAppliedIndex() uint64 { + if x != nil { + return x.AppliedIndex + } + return 0 +} + +func (x *NodeInfo) GetLastIndex() uint64 { + if x != nil { + return x.LastIndex + } + return 0 +} + +func (x *NodeInfo) GetStats() *NodeInfo_Stats { + if x != nil { + return x.Stats + } + return nil +} + +func (x *NodeInfo) GetPeers() []*NodeInfo_Peer { + if x != nil { + return x.Peers + } + return nil +} + +func (x *NodeInfo) GetConfigurationIndex() uint64 { + if x != nil { + return x.ConfigurationIndex + } + return 0 +} + +func (x *NodeInfo) GetCurrentTerm() uint64 { + if x != nil { + return x.CurrentTerm + } + return 0 +} + +func (x *NodeInfo) GetBuildVersion() string { + if x != nil { + return x.BuildVersion + } + return "" +} + +func (x *NodeInfo) GetBuildRevision() string { + if x != nil { + return x.BuildRevision + } + return "" +} + +type RemoveNodeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerId string `protobuf:"bytes,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + CurrentTerm uint64 `protobuf:"varint,2,opt,name=current_term,json=currentTerm,proto3" json:"current_term,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RemoveNodeRequest) Reset() { + *x = RemoveNodeRequest{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RemoveNodeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveNodeRequest) ProtoMessage() {} + +func (x *RemoveNodeRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveNodeRequest.ProtoReflect.Descriptor instead. +func (*RemoveNodeRequest) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{6} +} + +func (x *RemoveNodeRequest) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + +func (x *RemoveNodeRequest) GetCurrentTerm() uint64 { + if x != nil { + return x.CurrentTerm + } + return 0 +} + +type RemoveNodeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RemoveNodeResponse) Reset() { + *x = RemoveNodeResponse{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RemoveNodeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveNodeResponse) ProtoMessage() {} + +func (x *RemoveNodeResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveNodeResponse.ProtoReflect.Descriptor instead. +func (*RemoveNodeResponse) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{7} +} + +type AddNodeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerId string `protobuf:"bytes,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + CurrentTerm uint64 `protobuf:"varint,2,opt,name=current_term,json=currentTerm,proto3" json:"current_term,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddNodeRequest) Reset() { + *x = AddNodeRequest{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddNodeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddNodeRequest) ProtoMessage() {} + +func (x *AddNodeRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddNodeRequest.ProtoReflect.Descriptor instead. +func (*AddNodeRequest) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{8} +} + +func (x *AddNodeRequest) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + +func (x *AddNodeRequest) GetCurrentTerm() uint64 { + if x != nil { + return x.CurrentTerm + } + return 0 +} + +type AddNodeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddNodeResponse) Reset() { + *x = AddNodeResponse{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddNodeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddNodeResponse) ProtoMessage() {} + +func (x *AddNodeResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddNodeResponse.ProtoReflect.Descriptor instead. +func (*AddNodeResponse) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{9} +} + +type DemoteLeaderRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerId string `protobuf:"bytes,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + CurrentTerm uint64 `protobuf:"varint,2,opt,name=current_term,json=currentTerm,proto3" json:"current_term,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DemoteLeaderRequest) Reset() { + *x = DemoteLeaderRequest{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DemoteLeaderRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DemoteLeaderRequest) ProtoMessage() {} + +func (x *DemoteLeaderRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DemoteLeaderRequest.ProtoReflect.Descriptor instead. +func (*DemoteLeaderRequest) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{10} +} + +func (x *DemoteLeaderRequest) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + +func (x *DemoteLeaderRequest) GetCurrentTerm() uint64 { + if x != nil { + return x.CurrentTerm + } + return 0 +} + +type DemoteLeaderResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DemoteLeaderResponse) Reset() { + *x = DemoteLeaderResponse{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DemoteLeaderResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DemoteLeaderResponse) ProtoMessage() {} + +func (x *DemoteLeaderResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DemoteLeaderResponse.ProtoReflect.Descriptor instead. +func (*DemoteLeaderResponse) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{11} +} + +type PromoteToLeaderRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerId string `protobuf:"bytes,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + CurrentTerm uint64 `protobuf:"varint,2,opt,name=current_term,json=currentTerm,proto3" json:"current_term,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PromoteToLeaderRequest) Reset() { + *x = PromoteToLeaderRequest{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromoteToLeaderRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromoteToLeaderRequest) ProtoMessage() {} + +func (x *PromoteToLeaderRequest) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromoteToLeaderRequest.ProtoReflect.Descriptor instead. +func (*PromoteToLeaderRequest) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{12} +} + +func (x *PromoteToLeaderRequest) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + +func (x *PromoteToLeaderRequest) GetCurrentTerm() uint64 { + if x != nil { + return x.CurrentTerm + } + return 0 +} + +type PromoteToLeaderResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PromoteToLeaderResponse) Reset() { + *x = PromoteToLeaderResponse{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PromoteToLeaderResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PromoteToLeaderResponse) ProtoMessage() {} + +func (x *PromoteToLeaderResponse) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PromoteToLeaderResponse.ProtoReflect.Descriptor instead. +func (*PromoteToLeaderResponse) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{13} +} + +type NodeInfo_Stats struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name []string `protobuf:"bytes,1,rep,name=name,proto3" json:"name,omitempty"` + Value []string `protobuf:"bytes,2,rep,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NodeInfo_Stats) Reset() { + *x = NodeInfo_Stats{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NodeInfo_Stats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeInfo_Stats) ProtoMessage() {} + +func (x *NodeInfo_Stats) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeInfo_Stats.ProtoReflect.Descriptor instead. +func (*NodeInfo_Stats) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *NodeInfo_Stats) GetName() []string { + if x != nil { + return x.Name + } + return nil +} + +func (x *NodeInfo_Stats) GetValue() []string { + if x != nil { + return x.Value + } + return nil +} + +type NodeInfo_Peer struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServerId string `protobuf:"bytes,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + ServerAddress string `protobuf:"bytes,2,opt,name=server_address,json=serverAddress,proto3" json:"server_address,omitempty"` + Suffrage string `protobuf:"bytes,3,opt,name=suffrage,proto3" json:"suffrage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NodeInfo_Peer) Reset() { + *x = NodeInfo_Peer{} + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NodeInfo_Peer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeInfo_Peer) ProtoMessage() {} + +func (x *NodeInfo_Peer) ProtoReflect() protoreflect.Message { + mi := &file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeInfo_Peer.ProtoReflect.Descriptor instead. +func (*NodeInfo_Peer) Descriptor() ([]byte, []int) { + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP(), []int{5, 1} +} + +func (x *NodeInfo_Peer) GetServerId() string { + if x != nil { + return x.ServerId + } + return "" +} + +func (x *NodeInfo_Peer) GetServerAddress() string { + if x != nil { + return x.ServerAddress + } + return "" +} + +func (x *NodeInfo_Peer) GetSuffrage() string { + if x != nil { + return x.Suffrage + } + return "" +} + +var File_metastore_raftnode_raftnodepb_raft_node_proto protoreflect.FileDescriptor + +const file_metastore_raftnode_raftnodepb_raft_node_proto_rawDesc = "" + + "\n" + + "-metastore/raftnode/raftnodepb/raft_node.proto\x12\traft_node\"4\n" + + "\bRaftNode\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x18\n" + + "\aaddress\x18\x02 \x01(\tR\aaddress\"\x12\n" + + "\x10ReadIndexRequest\"J\n" + + "\x11ReadIndexResponse\x12!\n" + + "\fcommit_index\x18\x01 \x01(\x04R\vcommitIndex\x12\x12\n" + + "\x04term\x18\x02 \x01(\x04R\x04term\"\x11\n" + + "\x0fNodeInfoRequest\";\n" + + "\x10NodeInfoResponse\x12'\n" + + "\x04node\x18\x01 \x01(\v2\x13.raft_node.NodeInfoR\x04node\"\x8c\x05\n" + + "\bNodeInfo\x12\x1b\n" + + "\tserver_id\x18\x01 \x01(\tR\bserverId\x12-\n" + + "\x12advertised_address\x18\x02 \x01(\tR\x11advertisedAddress\x12\x14\n" + + "\x05state\x18\x03 \x01(\tR\x05state\x12\x1b\n" + + "\tleader_id\x18\x04 \x01(\tR\bleaderId\x12!\n" + + "\fcommit_index\x18\x05 \x01(\x04R\vcommitIndex\x12#\n" + + "\rapplied_index\x18\x06 \x01(\x04R\fappliedIndex\x12\x1d\n" + + "\n" + + "last_index\x18\a \x01(\x04R\tlastIndex\x12/\n" + + "\x05stats\x18\b \x01(\v2\x19.raft_node.NodeInfo.StatsR\x05stats\x12.\n" + + "\x05peers\x18\t \x03(\v2\x18.raft_node.NodeInfo.PeerR\x05peers\x12/\n" + + "\x13configuration_index\x18\n" + + " \x01(\x04R\x12configurationIndex\x12!\n" + + "\fcurrent_term\x18\v \x01(\x04R\vcurrentTerm\x12#\n" + + "\rbuild_version\x18\f \x01(\tR\fbuildVersion\x12%\n" + + "\x0ebuild_revision\x18\r \x01(\tR\rbuildRevision\x1a1\n" + + "\x05Stats\x12\x12\n" + + "\x04name\x18\x01 \x03(\tR\x04name\x12\x14\n" + + "\x05value\x18\x02 \x03(\tR\x05value\x1af\n" + + "\x04Peer\x12\x1b\n" + + "\tserver_id\x18\x01 \x01(\tR\bserverId\x12%\n" + + "\x0eserver_address\x18\x02 \x01(\tR\rserverAddress\x12\x1a\n" + + "\bsuffrage\x18\x03 \x01(\tR\bsuffrage\"S\n" + + "\x11RemoveNodeRequest\x12\x1b\n" + + "\tserver_id\x18\x01 \x01(\tR\bserverId\x12!\n" + + "\fcurrent_term\x18\x02 \x01(\x04R\vcurrentTerm\"\x14\n" + + "\x12RemoveNodeResponse\"P\n" + + "\x0eAddNodeRequest\x12\x1b\n" + + "\tserver_id\x18\x01 \x01(\tR\bserverId\x12!\n" + + "\fcurrent_term\x18\x02 \x01(\x04R\vcurrentTerm\"\x11\n" + + "\x0fAddNodeResponse\"U\n" + + "\x13DemoteLeaderRequest\x12\x1b\n" + + "\tserver_id\x18\x01 \x01(\tR\bserverId\x12!\n" + + "\fcurrent_term\x18\x02 \x01(\x04R\vcurrentTerm\"\x16\n" + + "\x14DemoteLeaderResponse\"X\n" + + "\x16PromoteToLeaderRequest\x12\x1b\n" + + "\tserver_id\x18\x01 \x01(\tR\bserverId\x12!\n" + + "\fcurrent_term\x18\x02 \x01(\x04R\vcurrentTerm\"\x19\n" + + "\x17PromoteToLeaderResponse2\xe2\x03\n" + + "\x0fRaftNodeService\x12H\n" + + "\tReadIndex\x12\x1b.raft_node.ReadIndexRequest\x1a\x1c.raft_node.ReadIndexResponse\"\x00\x12E\n" + + "\bNodeInfo\x12\x1a.raft_node.NodeInfoRequest\x1a\x1b.raft_node.NodeInfoResponse\"\x00\x12K\n" + + "\n" + + "RemoveNode\x12\x1c.raft_node.RemoveNodeRequest\x1a\x1d.raft_node.RemoveNodeResponse\"\x00\x12B\n" + + "\aAddNode\x12\x19.raft_node.AddNodeRequest\x1a\x1a.raft_node.AddNodeResponse\"\x00\x12Q\n" + + "\fDemoteLeader\x12\x1e.raft_node.DemoteLeaderRequest\x1a\x1f.raft_node.DemoteLeaderResponse\"\x00\x12Z\n" + + "\x0fPromoteToLeader\x12!.raft_node.PromoteToLeaderRequest\x1a\".raft_node.PromoteToLeaderResponse\"\x00B\xa1\x01\n" + + "\rcom.raft_nodeB\rRaftNodeProtoP\x01ZAgithub.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb\xa2\x02\x03RXX\xaa\x02\bRaftNode\xca\x02\bRaftNode\xe2\x02\x14RaftNode\\GPBMetadata\xea\x02\bRaftNodeb\x06proto3" + +var ( + file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescOnce sync.Once + file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescData []byte +) + +func file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescGZIP() []byte { + file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescOnce.Do(func() { + file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_metastore_raftnode_raftnodepb_raft_node_proto_rawDesc), len(file_metastore_raftnode_raftnodepb_raft_node_proto_rawDesc))) + }) + return file_metastore_raftnode_raftnodepb_raft_node_proto_rawDescData +} + +var file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_metastore_raftnode_raftnodepb_raft_node_proto_goTypes = []any{ + (*RaftNode)(nil), // 0: raft_node.RaftNode + (*ReadIndexRequest)(nil), // 1: raft_node.ReadIndexRequest + (*ReadIndexResponse)(nil), // 2: raft_node.ReadIndexResponse + (*NodeInfoRequest)(nil), // 3: raft_node.NodeInfoRequest + (*NodeInfoResponse)(nil), // 4: raft_node.NodeInfoResponse + (*NodeInfo)(nil), // 5: raft_node.NodeInfo + (*RemoveNodeRequest)(nil), // 6: raft_node.RemoveNodeRequest + (*RemoveNodeResponse)(nil), // 7: raft_node.RemoveNodeResponse + (*AddNodeRequest)(nil), // 8: raft_node.AddNodeRequest + (*AddNodeResponse)(nil), // 9: raft_node.AddNodeResponse + (*DemoteLeaderRequest)(nil), // 10: raft_node.DemoteLeaderRequest + (*DemoteLeaderResponse)(nil), // 11: raft_node.DemoteLeaderResponse + (*PromoteToLeaderRequest)(nil), // 12: raft_node.PromoteToLeaderRequest + (*PromoteToLeaderResponse)(nil), // 13: raft_node.PromoteToLeaderResponse + (*NodeInfo_Stats)(nil), // 14: raft_node.NodeInfo.Stats + (*NodeInfo_Peer)(nil), // 15: raft_node.NodeInfo.Peer +} +var file_metastore_raftnode_raftnodepb_raft_node_proto_depIdxs = []int32{ + 5, // 0: raft_node.NodeInfoResponse.node:type_name -> raft_node.NodeInfo + 14, // 1: raft_node.NodeInfo.stats:type_name -> raft_node.NodeInfo.Stats + 15, // 2: raft_node.NodeInfo.peers:type_name -> raft_node.NodeInfo.Peer + 1, // 3: raft_node.RaftNodeService.ReadIndex:input_type -> raft_node.ReadIndexRequest + 3, // 4: raft_node.RaftNodeService.NodeInfo:input_type -> raft_node.NodeInfoRequest + 6, // 5: raft_node.RaftNodeService.RemoveNode:input_type -> raft_node.RemoveNodeRequest + 8, // 6: raft_node.RaftNodeService.AddNode:input_type -> raft_node.AddNodeRequest + 10, // 7: raft_node.RaftNodeService.DemoteLeader:input_type -> raft_node.DemoteLeaderRequest + 12, // 8: raft_node.RaftNodeService.PromoteToLeader:input_type -> raft_node.PromoteToLeaderRequest + 2, // 9: raft_node.RaftNodeService.ReadIndex:output_type -> raft_node.ReadIndexResponse + 4, // 10: raft_node.RaftNodeService.NodeInfo:output_type -> raft_node.NodeInfoResponse + 7, // 11: raft_node.RaftNodeService.RemoveNode:output_type -> raft_node.RemoveNodeResponse + 9, // 12: raft_node.RaftNodeService.AddNode:output_type -> raft_node.AddNodeResponse + 11, // 13: raft_node.RaftNodeService.DemoteLeader:output_type -> raft_node.DemoteLeaderResponse + 13, // 14: raft_node.RaftNodeService.PromoteToLeader:output_type -> raft_node.PromoteToLeaderResponse + 9, // [9:15] is the sub-list for method output_type + 3, // [3:9] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_metastore_raftnode_raftnodepb_raft_node_proto_init() } +func file_metastore_raftnode_raftnodepb_raft_node_proto_init() { + if File_metastore_raftnode_raftnodepb_raft_node_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_metastore_raftnode_raftnodepb_raft_node_proto_rawDesc), len(file_metastore_raftnode_raftnodepb_raft_node_proto_rawDesc)), + NumEnums: 0, + NumMessages: 16, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_metastore_raftnode_raftnodepb_raft_node_proto_goTypes, + DependencyIndexes: file_metastore_raftnode_raftnodepb_raft_node_proto_depIdxs, + MessageInfos: file_metastore_raftnode_raftnodepb_raft_node_proto_msgTypes, + }.Build() + File_metastore_raftnode_raftnodepb_raft_node_proto = out.File + file_metastore_raftnode_raftnodepb_raft_node_proto_goTypes = nil + file_metastore_raftnode_raftnodepb_raft_node_proto_depIdxs = nil +} diff --git a/pkg/metastore/raftnode/raftnodepb/raft_node.proto b/pkg/metastore/raftnode/raftnodepb/raft_node.proto new file mode 100644 index 0000000000..2307805fd6 --- /dev/null +++ b/pkg/metastore/raftnode/raftnodepb/raft_node.proto @@ -0,0 +1,84 @@ +syntax = "proto3"; + +package raft_node; + +message RaftNode { + string id = 1; + string address = 2; +} + +service RaftNodeService { + rpc ReadIndex(ReadIndexRequest) returns (ReadIndexResponse) {} + rpc NodeInfo(NodeInfoRequest) returns (NodeInfoResponse) {} + rpc RemoveNode(RemoveNodeRequest) returns (RemoveNodeResponse) {} + rpc AddNode(AddNodeRequest) returns (AddNodeResponse) {} + rpc DemoteLeader(DemoteLeaderRequest) returns (DemoteLeaderResponse) {} + rpc PromoteToLeader(PromoteToLeaderRequest) returns (PromoteToLeaderResponse) {} +} + +message ReadIndexRequest {} + +message ReadIndexResponse { + uint64 commit_index = 1; + uint64 term = 2; +} + +message NodeInfoRequest {} + +message NodeInfoResponse { + NodeInfo node = 1; +} + +message NodeInfo { + string server_id = 1; + string advertised_address = 2; + string state = 3; + string leader_id = 4; + uint64 commit_index = 5; + uint64 applied_index = 6; + uint64 last_index = 7; + + Stats stats = 8; + message Stats { + repeated string name = 1; + repeated string value = 2; + } + + repeated Peer peers = 9; + message Peer { + string server_id = 1; + string server_address = 2; + string suffrage = 3; + } + + uint64 configuration_index = 10; + uint64 current_term = 11; + string build_version = 12; + string build_revision = 13; +} + +message RemoveNodeRequest { + string server_id = 1; + uint64 current_term = 2; +} + +message RemoveNodeResponse {} + +message AddNodeRequest { + string server_id = 1; + uint64 current_term = 2; +} + +message AddNodeResponse {} + +message DemoteLeaderRequest { + string server_id = 1; + uint64 current_term = 2; +} +message DemoteLeaderResponse {} + +message PromoteToLeaderRequest { + string server_id = 1; + uint64 current_term = 2; +} +message PromoteToLeaderResponse {} diff --git a/pkg/metastore/raftnode/raftnodepb/raft_node_vtproto.pb.go b/pkg/metastore/raftnode/raftnodepb/raft_node_vtproto.pb.go new file mode 100644 index 0000000000..bb166a2405 --- /dev/null +++ b/pkg/metastore/raftnode/raftnodepb/raft_node_vtproto.pb.go @@ -0,0 +1,2987 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: metastore/raftnode/raftnodepb/raft_node.proto + +package raftnodepb + +import ( + context "context" + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// RaftNodeServiceClient is the client API for RaftNodeService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type RaftNodeServiceClient interface { + ReadIndex(ctx context.Context, in *ReadIndexRequest, opts ...grpc.CallOption) (*ReadIndexResponse, error) + NodeInfo(ctx context.Context, in *NodeInfoRequest, opts ...grpc.CallOption) (*NodeInfoResponse, error) + RemoveNode(ctx context.Context, in *RemoveNodeRequest, opts ...grpc.CallOption) (*RemoveNodeResponse, error) + AddNode(ctx context.Context, in *AddNodeRequest, opts ...grpc.CallOption) (*AddNodeResponse, error) + DemoteLeader(ctx context.Context, in *DemoteLeaderRequest, opts ...grpc.CallOption) (*DemoteLeaderResponse, error) + PromoteToLeader(ctx context.Context, in *PromoteToLeaderRequest, opts ...grpc.CallOption) (*PromoteToLeaderResponse, error) +} + +type raftNodeServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewRaftNodeServiceClient(cc grpc.ClientConnInterface) RaftNodeServiceClient { + return &raftNodeServiceClient{cc} +} + +func (c *raftNodeServiceClient) ReadIndex(ctx context.Context, in *ReadIndexRequest, opts ...grpc.CallOption) (*ReadIndexResponse, error) { + out := new(ReadIndexResponse) + err := c.cc.Invoke(ctx, "/raft_node.RaftNodeService/ReadIndex", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *raftNodeServiceClient) NodeInfo(ctx context.Context, in *NodeInfoRequest, opts ...grpc.CallOption) (*NodeInfoResponse, error) { + out := new(NodeInfoResponse) + err := c.cc.Invoke(ctx, "/raft_node.RaftNodeService/NodeInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *raftNodeServiceClient) RemoveNode(ctx context.Context, in *RemoveNodeRequest, opts ...grpc.CallOption) (*RemoveNodeResponse, error) { + out := new(RemoveNodeResponse) + err := c.cc.Invoke(ctx, "/raft_node.RaftNodeService/RemoveNode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *raftNodeServiceClient) AddNode(ctx context.Context, in *AddNodeRequest, opts ...grpc.CallOption) (*AddNodeResponse, error) { + out := new(AddNodeResponse) + err := c.cc.Invoke(ctx, "/raft_node.RaftNodeService/AddNode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *raftNodeServiceClient) DemoteLeader(ctx context.Context, in *DemoteLeaderRequest, opts ...grpc.CallOption) (*DemoteLeaderResponse, error) { + out := new(DemoteLeaderResponse) + err := c.cc.Invoke(ctx, "/raft_node.RaftNodeService/DemoteLeader", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *raftNodeServiceClient) PromoteToLeader(ctx context.Context, in *PromoteToLeaderRequest, opts ...grpc.CallOption) (*PromoteToLeaderResponse, error) { + out := new(PromoteToLeaderResponse) + err := c.cc.Invoke(ctx, "/raft_node.RaftNodeService/PromoteToLeader", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RaftNodeServiceServer is the server API for RaftNodeService service. +// All implementations must embed UnimplementedRaftNodeServiceServer +// for forward compatibility +type RaftNodeServiceServer interface { + ReadIndex(context.Context, *ReadIndexRequest) (*ReadIndexResponse, error) + NodeInfo(context.Context, *NodeInfoRequest) (*NodeInfoResponse, error) + RemoveNode(context.Context, *RemoveNodeRequest) (*RemoveNodeResponse, error) + AddNode(context.Context, *AddNodeRequest) (*AddNodeResponse, error) + DemoteLeader(context.Context, *DemoteLeaderRequest) (*DemoteLeaderResponse, error) + PromoteToLeader(context.Context, *PromoteToLeaderRequest) (*PromoteToLeaderResponse, error) + mustEmbedUnimplementedRaftNodeServiceServer() +} + +// UnimplementedRaftNodeServiceServer must be embedded to have forward compatible implementations. +type UnimplementedRaftNodeServiceServer struct { +} + +func (UnimplementedRaftNodeServiceServer) ReadIndex(context.Context, *ReadIndexRequest) (*ReadIndexResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReadIndex not implemented") +} +func (UnimplementedRaftNodeServiceServer) NodeInfo(context.Context, *NodeInfoRequest) (*NodeInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method NodeInfo not implemented") +} +func (UnimplementedRaftNodeServiceServer) RemoveNode(context.Context, *RemoveNodeRequest) (*RemoveNodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveNode not implemented") +} +func (UnimplementedRaftNodeServiceServer) AddNode(context.Context, *AddNodeRequest) (*AddNodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddNode not implemented") +} +func (UnimplementedRaftNodeServiceServer) DemoteLeader(context.Context, *DemoteLeaderRequest) (*DemoteLeaderResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DemoteLeader not implemented") +} +func (UnimplementedRaftNodeServiceServer) PromoteToLeader(context.Context, *PromoteToLeaderRequest) (*PromoteToLeaderResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PromoteToLeader not implemented") +} +func (UnimplementedRaftNodeServiceServer) mustEmbedUnimplementedRaftNodeServiceServer() {} + +// UnsafeRaftNodeServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to RaftNodeServiceServer will +// result in compilation errors. +type UnsafeRaftNodeServiceServer interface { + mustEmbedUnimplementedRaftNodeServiceServer() +} + +func RegisterRaftNodeServiceServer(s grpc.ServiceRegistrar, srv RaftNodeServiceServer) { + s.RegisterService(&RaftNodeService_ServiceDesc, srv) +} + +func _RaftNodeService_ReadIndex_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReadIndexRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RaftNodeServiceServer).ReadIndex(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/raft_node.RaftNodeService/ReadIndex", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RaftNodeServiceServer).ReadIndex(ctx, req.(*ReadIndexRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RaftNodeService_NodeInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NodeInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RaftNodeServiceServer).NodeInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/raft_node.RaftNodeService/NodeInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RaftNodeServiceServer).NodeInfo(ctx, req.(*NodeInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RaftNodeService_RemoveNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveNodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RaftNodeServiceServer).RemoveNode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/raft_node.RaftNodeService/RemoveNode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RaftNodeServiceServer).RemoveNode(ctx, req.(*RemoveNodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RaftNodeService_AddNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddNodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RaftNodeServiceServer).AddNode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/raft_node.RaftNodeService/AddNode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RaftNodeServiceServer).AddNode(ctx, req.(*AddNodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RaftNodeService_DemoteLeader_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DemoteLeaderRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RaftNodeServiceServer).DemoteLeader(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/raft_node.RaftNodeService/DemoteLeader", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RaftNodeServiceServer).DemoteLeader(ctx, req.(*DemoteLeaderRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RaftNodeService_PromoteToLeader_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PromoteToLeaderRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RaftNodeServiceServer).PromoteToLeader(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/raft_node.RaftNodeService/PromoteToLeader", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RaftNodeServiceServer).PromoteToLeader(ctx, req.(*PromoteToLeaderRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// RaftNodeService_ServiceDesc is the grpc.ServiceDesc for RaftNodeService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var RaftNodeService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "raft_node.RaftNodeService", + HandlerType: (*RaftNodeServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ReadIndex", + Handler: _RaftNodeService_ReadIndex_Handler, + }, + { + MethodName: "NodeInfo", + Handler: _RaftNodeService_NodeInfo_Handler, + }, + { + MethodName: "RemoveNode", + Handler: _RaftNodeService_RemoveNode_Handler, + }, + { + MethodName: "AddNode", + Handler: _RaftNodeService_AddNode_Handler, + }, + { + MethodName: "DemoteLeader", + Handler: _RaftNodeService_DemoteLeader_Handler, + }, + { + MethodName: "PromoteToLeader", + Handler: _RaftNodeService_PromoteToLeader_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "metastore/raftnode/raftnodepb/raft_node.proto", +} + +func (m *RaftNode) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RaftNode) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *RaftNode) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0x12 + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ReadIndexRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ReadIndexRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ReadIndexRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *ReadIndexResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ReadIndexResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ReadIndexResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Term != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Term)) + i-- + dAtA[i] = 0x10 + } + if m.CommitIndex != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CommitIndex)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *NodeInfoRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NodeInfoRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *NodeInfoRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *NodeInfoResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NodeInfoResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *NodeInfoResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Node != nil { + size, err := m.Node.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *NodeInfo_Stats) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NodeInfo_Stats) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *NodeInfo_Stats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Value) > 0 { + for iNdEx := len(m.Value) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Value[iNdEx]) + copy(dAtA[i:], m.Value[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Name) > 0 { + for iNdEx := len(m.Name) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Name[iNdEx]) + copy(dAtA[i:], m.Name[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *NodeInfo_Peer) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NodeInfo_Peer) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *NodeInfo_Peer) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Suffrage) > 0 { + i -= len(m.Suffrage) + copy(dAtA[i:], m.Suffrage) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Suffrage))) + i-- + dAtA[i] = 0x1a + } + if len(m.ServerAddress) > 0 { + i -= len(m.ServerAddress) + copy(dAtA[i:], m.ServerAddress) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServerAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ServerId) > 0 { + i -= len(m.ServerId) + copy(dAtA[i:], m.ServerId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *NodeInfo) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NodeInfo) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *NodeInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.BuildRevision) > 0 { + i -= len(m.BuildRevision) + copy(dAtA[i:], m.BuildRevision) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BuildRevision))) + i-- + dAtA[i] = 0x6a + } + if len(m.BuildVersion) > 0 { + i -= len(m.BuildVersion) + copy(dAtA[i:], m.BuildVersion) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BuildVersion))) + i-- + dAtA[i] = 0x62 + } + if m.CurrentTerm != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CurrentTerm)) + i-- + dAtA[i] = 0x58 + } + if m.ConfigurationIndex != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigurationIndex)) + i-- + dAtA[i] = 0x50 + } + if len(m.Peers) > 0 { + for iNdEx := len(m.Peers) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Peers[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x4a + } + } + if m.Stats != nil { + size, err := m.Stats.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x42 + } + if m.LastIndex != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.LastIndex)) + i-- + dAtA[i] = 0x38 + } + if m.AppliedIndex != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.AppliedIndex)) + i-- + dAtA[i] = 0x30 + } + if m.CommitIndex != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CommitIndex)) + i-- + dAtA[i] = 0x28 + } + if len(m.LeaderId) > 0 { + i -= len(m.LeaderId) + copy(dAtA[i:], m.LeaderId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LeaderId))) + i-- + dAtA[i] = 0x22 + } + if len(m.State) > 0 { + i -= len(m.State) + copy(dAtA[i:], m.State) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.State))) + i-- + dAtA[i] = 0x1a + } + if len(m.AdvertisedAddress) > 0 { + i -= len(m.AdvertisedAddress) + copy(dAtA[i:], m.AdvertisedAddress) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AdvertisedAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ServerId) > 0 { + i -= len(m.ServerId) + copy(dAtA[i:], m.ServerId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RemoveNodeRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RemoveNodeRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *RemoveNodeRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CurrentTerm != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CurrentTerm)) + i-- + dAtA[i] = 0x10 + } + if len(m.ServerId) > 0 { + i -= len(m.ServerId) + copy(dAtA[i:], m.ServerId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RemoveNodeResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RemoveNodeResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *RemoveNodeResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *AddNodeRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddNodeRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AddNodeRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CurrentTerm != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CurrentTerm)) + i-- + dAtA[i] = 0x10 + } + if len(m.ServerId) > 0 { + i -= len(m.ServerId) + copy(dAtA[i:], m.ServerId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddNodeResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddNodeResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *AddNodeResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *DemoteLeaderRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DemoteLeaderRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DemoteLeaderRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CurrentTerm != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CurrentTerm)) + i-- + dAtA[i] = 0x10 + } + if len(m.ServerId) > 0 { + i -= len(m.ServerId) + copy(dAtA[i:], m.ServerId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DemoteLeaderResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DemoteLeaderResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DemoteLeaderResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *PromoteToLeaderRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PromoteToLeaderRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PromoteToLeaderRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CurrentTerm != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CurrentTerm)) + i-- + dAtA[i] = 0x10 + } + if len(m.ServerId) > 0 { + i -= len(m.ServerId) + copy(dAtA[i:], m.ServerId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PromoteToLeaderResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PromoteToLeaderResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PromoteToLeaderResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + return len(dAtA) - i, nil +} + +func (m *RaftNode) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Address) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *ReadIndexRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *ReadIndexResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CommitIndex != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CommitIndex)) + } + if m.Term != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Term)) + } + n += len(m.unknownFields) + return n +} + +func (m *NodeInfoRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *NodeInfoResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Node != nil { + l = m.Node.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *NodeInfo_Stats) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Name) > 0 { + for _, s := range m.Name { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Value) > 0 { + for _, s := range m.Value { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *NodeInfo_Peer) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ServerId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.ServerAddress) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Suffrage) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *NodeInfo) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ServerId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.AdvertisedAddress) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.State) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.LeaderId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CommitIndex != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CommitIndex)) + } + if m.AppliedIndex != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.AppliedIndex)) + } + if m.LastIndex != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.LastIndex)) + } + if m.Stats != nil { + l = m.Stats.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Peers) > 0 { + for _, e := range m.Peers { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.ConfigurationIndex != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigurationIndex)) + } + if m.CurrentTerm != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CurrentTerm)) + } + l = len(m.BuildVersion) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.BuildRevision) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *RemoveNodeRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ServerId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CurrentTerm != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CurrentTerm)) + } + n += len(m.unknownFields) + return n +} + +func (m *RemoveNodeResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *AddNodeRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ServerId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CurrentTerm != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CurrentTerm)) + } + n += len(m.unknownFields) + return n +} + +func (m *AddNodeResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *DemoteLeaderRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ServerId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CurrentTerm != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CurrentTerm)) + } + n += len(m.unknownFields) + return n +} + +func (m *DemoteLeaderResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *PromoteToLeaderRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ServerId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.CurrentTerm != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CurrentTerm)) + } + n += len(m.unknownFields) + return n +} + +func (m *PromoteToLeaderResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += len(m.unknownFields) + return n +} + +func (m *RaftNode) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RaftNode: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RaftNode: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ReadIndexRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReadIndexRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReadIndexRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ReadIndexResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReadIndexResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReadIndexResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CommitIndex", wireType) + } + m.CommitIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CommitIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Term", wireType) + } + m.Term = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Term |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NodeInfoRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NodeInfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NodeInfoRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NodeInfoResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NodeInfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NodeInfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Node", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Node == nil { + m.Node = &NodeInfo{} + } + if err := m.Node.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NodeInfo_Stats) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NodeInfo_Stats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NodeInfo_Stats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = append(m.Name, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NodeInfo_Peer) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NodeInfo_Peer: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NodeInfo_Peer: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Suffrage", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Suffrage = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NodeInfo) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NodeInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NodeInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AdvertisedAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AdvertisedAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.State = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LeaderId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LeaderId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CommitIndex", wireType) + } + m.CommitIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CommitIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AppliedIndex", wireType) + } + m.AppliedIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AppliedIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastIndex", wireType) + } + m.LastIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Stats", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Stats == nil { + m.Stats = &NodeInfo_Stats{} + } + if err := m.Stats.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Peers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Peers = append(m.Peers, &NodeInfo_Peer{}) + if err := m.Peers[len(m.Peers)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ConfigurationIndex", wireType) + } + m.ConfigurationIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ConfigurationIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentTerm", wireType) + } + m.CurrentTerm = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentTerm |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BuildVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BuildVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BuildRevision", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BuildRevision = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RemoveNodeRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RemoveNodeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RemoveNodeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentTerm", wireType) + } + m.CurrentTerm = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentTerm |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RemoveNodeResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RemoveNodeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RemoveNodeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddNodeRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddNodeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddNodeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentTerm", wireType) + } + m.CurrentTerm = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentTerm |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddNodeResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddNodeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddNodeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DemoteLeaderRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DemoteLeaderRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DemoteLeaderRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentTerm", wireType) + } + m.CurrentTerm = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentTerm |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DemoteLeaderResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DemoteLeaderResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DemoteLeaderResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PromoteToLeaderRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PromoteToLeaderRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PromoteToLeaderRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentTerm", wireType) + } + m.CurrentTerm = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentTerm |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PromoteToLeaderResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PromoteToLeaderResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PromoteToLeaderResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/pkg/metastore/raftnode/raftnodepb/raftnodepbconnect/raft_node.connect.go b/pkg/metastore/raftnode/raftnodepb/raftnodepbconnect/raft_node.connect.go new file mode 100644 index 0000000000..297684b7e6 --- /dev/null +++ b/pkg/metastore/raftnode/raftnodepb/raftnodepbconnect/raft_node.connect.go @@ -0,0 +1,253 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: metastore/raftnode/raftnodepb/raft_node.proto + +package raftnodepbconnect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + raftnodepb "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // RaftNodeServiceName is the fully-qualified name of the RaftNodeService service. + RaftNodeServiceName = "raft_node.RaftNodeService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // RaftNodeServiceReadIndexProcedure is the fully-qualified name of the RaftNodeService's ReadIndex + // RPC. + RaftNodeServiceReadIndexProcedure = "/raft_node.RaftNodeService/ReadIndex" + // RaftNodeServiceNodeInfoProcedure is the fully-qualified name of the RaftNodeService's NodeInfo + // RPC. + RaftNodeServiceNodeInfoProcedure = "/raft_node.RaftNodeService/NodeInfo" + // RaftNodeServiceRemoveNodeProcedure is the fully-qualified name of the RaftNodeService's + // RemoveNode RPC. + RaftNodeServiceRemoveNodeProcedure = "/raft_node.RaftNodeService/RemoveNode" + // RaftNodeServiceAddNodeProcedure is the fully-qualified name of the RaftNodeService's AddNode RPC. + RaftNodeServiceAddNodeProcedure = "/raft_node.RaftNodeService/AddNode" + // RaftNodeServiceDemoteLeaderProcedure is the fully-qualified name of the RaftNodeService's + // DemoteLeader RPC. + RaftNodeServiceDemoteLeaderProcedure = "/raft_node.RaftNodeService/DemoteLeader" + // RaftNodeServicePromoteToLeaderProcedure is the fully-qualified name of the RaftNodeService's + // PromoteToLeader RPC. + RaftNodeServicePromoteToLeaderProcedure = "/raft_node.RaftNodeService/PromoteToLeader" +) + +// RaftNodeServiceClient is a client for the raft_node.RaftNodeService service. +type RaftNodeServiceClient interface { + ReadIndex(context.Context, *connect.Request[raftnodepb.ReadIndexRequest]) (*connect.Response[raftnodepb.ReadIndexResponse], error) + NodeInfo(context.Context, *connect.Request[raftnodepb.NodeInfoRequest]) (*connect.Response[raftnodepb.NodeInfoResponse], error) + RemoveNode(context.Context, *connect.Request[raftnodepb.RemoveNodeRequest]) (*connect.Response[raftnodepb.RemoveNodeResponse], error) + AddNode(context.Context, *connect.Request[raftnodepb.AddNodeRequest]) (*connect.Response[raftnodepb.AddNodeResponse], error) + DemoteLeader(context.Context, *connect.Request[raftnodepb.DemoteLeaderRequest]) (*connect.Response[raftnodepb.DemoteLeaderResponse], error) + PromoteToLeader(context.Context, *connect.Request[raftnodepb.PromoteToLeaderRequest]) (*connect.Response[raftnodepb.PromoteToLeaderResponse], error) +} + +// NewRaftNodeServiceClient constructs a client for the raft_node.RaftNodeService service. By +// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, +// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewRaftNodeServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) RaftNodeServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + raftNodeServiceMethods := raftnodepb.File_metastore_raftnode_raftnodepb_raft_node_proto.Services().ByName("RaftNodeService").Methods() + return &raftNodeServiceClient{ + readIndex: connect.NewClient[raftnodepb.ReadIndexRequest, raftnodepb.ReadIndexResponse]( + httpClient, + baseURL+RaftNodeServiceReadIndexProcedure, + connect.WithSchema(raftNodeServiceMethods.ByName("ReadIndex")), + connect.WithClientOptions(opts...), + ), + nodeInfo: connect.NewClient[raftnodepb.NodeInfoRequest, raftnodepb.NodeInfoResponse]( + httpClient, + baseURL+RaftNodeServiceNodeInfoProcedure, + connect.WithSchema(raftNodeServiceMethods.ByName("NodeInfo")), + connect.WithClientOptions(opts...), + ), + removeNode: connect.NewClient[raftnodepb.RemoveNodeRequest, raftnodepb.RemoveNodeResponse]( + httpClient, + baseURL+RaftNodeServiceRemoveNodeProcedure, + connect.WithSchema(raftNodeServiceMethods.ByName("RemoveNode")), + connect.WithClientOptions(opts...), + ), + addNode: connect.NewClient[raftnodepb.AddNodeRequest, raftnodepb.AddNodeResponse]( + httpClient, + baseURL+RaftNodeServiceAddNodeProcedure, + connect.WithSchema(raftNodeServiceMethods.ByName("AddNode")), + connect.WithClientOptions(opts...), + ), + demoteLeader: connect.NewClient[raftnodepb.DemoteLeaderRequest, raftnodepb.DemoteLeaderResponse]( + httpClient, + baseURL+RaftNodeServiceDemoteLeaderProcedure, + connect.WithSchema(raftNodeServiceMethods.ByName("DemoteLeader")), + connect.WithClientOptions(opts...), + ), + promoteToLeader: connect.NewClient[raftnodepb.PromoteToLeaderRequest, raftnodepb.PromoteToLeaderResponse]( + httpClient, + baseURL+RaftNodeServicePromoteToLeaderProcedure, + connect.WithSchema(raftNodeServiceMethods.ByName("PromoteToLeader")), + connect.WithClientOptions(opts...), + ), + } +} + +// raftNodeServiceClient implements RaftNodeServiceClient. +type raftNodeServiceClient struct { + readIndex *connect.Client[raftnodepb.ReadIndexRequest, raftnodepb.ReadIndexResponse] + nodeInfo *connect.Client[raftnodepb.NodeInfoRequest, raftnodepb.NodeInfoResponse] + removeNode *connect.Client[raftnodepb.RemoveNodeRequest, raftnodepb.RemoveNodeResponse] + addNode *connect.Client[raftnodepb.AddNodeRequest, raftnodepb.AddNodeResponse] + demoteLeader *connect.Client[raftnodepb.DemoteLeaderRequest, raftnodepb.DemoteLeaderResponse] + promoteToLeader *connect.Client[raftnodepb.PromoteToLeaderRequest, raftnodepb.PromoteToLeaderResponse] +} + +// ReadIndex calls raft_node.RaftNodeService.ReadIndex. +func (c *raftNodeServiceClient) ReadIndex(ctx context.Context, req *connect.Request[raftnodepb.ReadIndexRequest]) (*connect.Response[raftnodepb.ReadIndexResponse], error) { + return c.readIndex.CallUnary(ctx, req) +} + +// NodeInfo calls raft_node.RaftNodeService.NodeInfo. +func (c *raftNodeServiceClient) NodeInfo(ctx context.Context, req *connect.Request[raftnodepb.NodeInfoRequest]) (*connect.Response[raftnodepb.NodeInfoResponse], error) { + return c.nodeInfo.CallUnary(ctx, req) +} + +// RemoveNode calls raft_node.RaftNodeService.RemoveNode. +func (c *raftNodeServiceClient) RemoveNode(ctx context.Context, req *connect.Request[raftnodepb.RemoveNodeRequest]) (*connect.Response[raftnodepb.RemoveNodeResponse], error) { + return c.removeNode.CallUnary(ctx, req) +} + +// AddNode calls raft_node.RaftNodeService.AddNode. +func (c *raftNodeServiceClient) AddNode(ctx context.Context, req *connect.Request[raftnodepb.AddNodeRequest]) (*connect.Response[raftnodepb.AddNodeResponse], error) { + return c.addNode.CallUnary(ctx, req) +} + +// DemoteLeader calls raft_node.RaftNodeService.DemoteLeader. +func (c *raftNodeServiceClient) DemoteLeader(ctx context.Context, req *connect.Request[raftnodepb.DemoteLeaderRequest]) (*connect.Response[raftnodepb.DemoteLeaderResponse], error) { + return c.demoteLeader.CallUnary(ctx, req) +} + +// PromoteToLeader calls raft_node.RaftNodeService.PromoteToLeader. +func (c *raftNodeServiceClient) PromoteToLeader(ctx context.Context, req *connect.Request[raftnodepb.PromoteToLeaderRequest]) (*connect.Response[raftnodepb.PromoteToLeaderResponse], error) { + return c.promoteToLeader.CallUnary(ctx, req) +} + +// RaftNodeServiceHandler is an implementation of the raft_node.RaftNodeService service. +type RaftNodeServiceHandler interface { + ReadIndex(context.Context, *connect.Request[raftnodepb.ReadIndexRequest]) (*connect.Response[raftnodepb.ReadIndexResponse], error) + NodeInfo(context.Context, *connect.Request[raftnodepb.NodeInfoRequest]) (*connect.Response[raftnodepb.NodeInfoResponse], error) + RemoveNode(context.Context, *connect.Request[raftnodepb.RemoveNodeRequest]) (*connect.Response[raftnodepb.RemoveNodeResponse], error) + AddNode(context.Context, *connect.Request[raftnodepb.AddNodeRequest]) (*connect.Response[raftnodepb.AddNodeResponse], error) + DemoteLeader(context.Context, *connect.Request[raftnodepb.DemoteLeaderRequest]) (*connect.Response[raftnodepb.DemoteLeaderResponse], error) + PromoteToLeader(context.Context, *connect.Request[raftnodepb.PromoteToLeaderRequest]) (*connect.Response[raftnodepb.PromoteToLeaderResponse], error) +} + +// NewRaftNodeServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewRaftNodeServiceHandler(svc RaftNodeServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + raftNodeServiceMethods := raftnodepb.File_metastore_raftnode_raftnodepb_raft_node_proto.Services().ByName("RaftNodeService").Methods() + raftNodeServiceReadIndexHandler := connect.NewUnaryHandler( + RaftNodeServiceReadIndexProcedure, + svc.ReadIndex, + connect.WithSchema(raftNodeServiceMethods.ByName("ReadIndex")), + connect.WithHandlerOptions(opts...), + ) + raftNodeServiceNodeInfoHandler := connect.NewUnaryHandler( + RaftNodeServiceNodeInfoProcedure, + svc.NodeInfo, + connect.WithSchema(raftNodeServiceMethods.ByName("NodeInfo")), + connect.WithHandlerOptions(opts...), + ) + raftNodeServiceRemoveNodeHandler := connect.NewUnaryHandler( + RaftNodeServiceRemoveNodeProcedure, + svc.RemoveNode, + connect.WithSchema(raftNodeServiceMethods.ByName("RemoveNode")), + connect.WithHandlerOptions(opts...), + ) + raftNodeServiceAddNodeHandler := connect.NewUnaryHandler( + RaftNodeServiceAddNodeProcedure, + svc.AddNode, + connect.WithSchema(raftNodeServiceMethods.ByName("AddNode")), + connect.WithHandlerOptions(opts...), + ) + raftNodeServiceDemoteLeaderHandler := connect.NewUnaryHandler( + RaftNodeServiceDemoteLeaderProcedure, + svc.DemoteLeader, + connect.WithSchema(raftNodeServiceMethods.ByName("DemoteLeader")), + connect.WithHandlerOptions(opts...), + ) + raftNodeServicePromoteToLeaderHandler := connect.NewUnaryHandler( + RaftNodeServicePromoteToLeaderProcedure, + svc.PromoteToLeader, + connect.WithSchema(raftNodeServiceMethods.ByName("PromoteToLeader")), + connect.WithHandlerOptions(opts...), + ) + return "/raft_node.RaftNodeService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case RaftNodeServiceReadIndexProcedure: + raftNodeServiceReadIndexHandler.ServeHTTP(w, r) + case RaftNodeServiceNodeInfoProcedure: + raftNodeServiceNodeInfoHandler.ServeHTTP(w, r) + case RaftNodeServiceRemoveNodeProcedure: + raftNodeServiceRemoveNodeHandler.ServeHTTP(w, r) + case RaftNodeServiceAddNodeProcedure: + raftNodeServiceAddNodeHandler.ServeHTTP(w, r) + case RaftNodeServiceDemoteLeaderProcedure: + raftNodeServiceDemoteLeaderHandler.ServeHTTP(w, r) + case RaftNodeServicePromoteToLeaderProcedure: + raftNodeServicePromoteToLeaderHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedRaftNodeServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedRaftNodeServiceHandler struct{} + +func (UnimplementedRaftNodeServiceHandler) ReadIndex(context.Context, *connect.Request[raftnodepb.ReadIndexRequest]) (*connect.Response[raftnodepb.ReadIndexResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raft_node.RaftNodeService.ReadIndex is not implemented")) +} + +func (UnimplementedRaftNodeServiceHandler) NodeInfo(context.Context, *connect.Request[raftnodepb.NodeInfoRequest]) (*connect.Response[raftnodepb.NodeInfoResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raft_node.RaftNodeService.NodeInfo is not implemented")) +} + +func (UnimplementedRaftNodeServiceHandler) RemoveNode(context.Context, *connect.Request[raftnodepb.RemoveNodeRequest]) (*connect.Response[raftnodepb.RemoveNodeResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raft_node.RaftNodeService.RemoveNode is not implemented")) +} + +func (UnimplementedRaftNodeServiceHandler) AddNode(context.Context, *connect.Request[raftnodepb.AddNodeRequest]) (*connect.Response[raftnodepb.AddNodeResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raft_node.RaftNodeService.AddNode is not implemented")) +} + +func (UnimplementedRaftNodeServiceHandler) DemoteLeader(context.Context, *connect.Request[raftnodepb.DemoteLeaderRequest]) (*connect.Response[raftnodepb.DemoteLeaderResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raft_node.RaftNodeService.DemoteLeader is not implemented")) +} + +func (UnimplementedRaftNodeServiceHandler) PromoteToLeader(context.Context, *connect.Request[raftnodepb.PromoteToLeaderRequest]) (*connect.Response[raftnodepb.PromoteToLeaderResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raft_node.RaftNodeService.PromoteToLeader is not implemented")) +} diff --git a/pkg/metastore/raftnode/raftnodepb/raftnodepbconnect/raft_node.connect.mux.go b/pkg/metastore/raftnode/raftnodepb/raftnodepbconnect/raft_node.connect.mux.go new file mode 100644 index 0000000000..3baf0c0145 --- /dev/null +++ b/pkg/metastore/raftnode/raftnodepb/raftnodepbconnect/raft_node.connect.mux.go @@ -0,0 +1,52 @@ +// Code generated by protoc-gen-connect-go-mux. DO NOT EDIT. +// +// Source: metastore/raftnode/raftnodepb/raft_node.proto + +package raftnodepbconnect + +import ( + connect "connectrpc.com/connect" + mux "github.com/gorilla/mux" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +// RegisterRaftNodeServiceHandler register an HTTP handler to a mux.Router from the service +// implementation. +func RegisterRaftNodeServiceHandler(mux *mux.Router, svc RaftNodeServiceHandler, opts ...connect.HandlerOption) { + mux.Handle("/raft_node.RaftNodeService/ReadIndex", connect.NewUnaryHandler( + "/raft_node.RaftNodeService/ReadIndex", + svc.ReadIndex, + opts..., + )) + mux.Handle("/raft_node.RaftNodeService/NodeInfo", connect.NewUnaryHandler( + "/raft_node.RaftNodeService/NodeInfo", + svc.NodeInfo, + opts..., + )) + mux.Handle("/raft_node.RaftNodeService/RemoveNode", connect.NewUnaryHandler( + "/raft_node.RaftNodeService/RemoveNode", + svc.RemoveNode, + opts..., + )) + mux.Handle("/raft_node.RaftNodeService/AddNode", connect.NewUnaryHandler( + "/raft_node.RaftNodeService/AddNode", + svc.AddNode, + opts..., + )) + mux.Handle("/raft_node.RaftNodeService/DemoteLeader", connect.NewUnaryHandler( + "/raft_node.RaftNodeService/DemoteLeader", + svc.DemoteLeader, + opts..., + )) + mux.Handle("/raft_node.RaftNodeService/PromoteToLeader", connect.NewUnaryHandler( + "/raft_node.RaftNodeService/PromoteToLeader", + svc.PromoteToLeader, + opts..., + )) +} diff --git a/pkg/metastore/raftnode/service.go b/pkg/metastore/raftnode/service.go new file mode 100644 index 0000000000..0192ce4182 --- /dev/null +++ b/pkg/metastore/raftnode/service.go @@ -0,0 +1,80 @@ +package raftnode + +import ( + "context" + + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +type RaftNode interface { + ReadIndex() (ReadIndex, error) + NodeInfo() (*raftnodepb.NodeInfo, error) + RemoveNode(request *raftnodepb.RemoveNodeRequest) (*raftnodepb.RemoveNodeResponse, error) + AddNode(request *raftnodepb.AddNodeRequest) (*raftnodepb.AddNodeResponse, error) + DemoteLeader(request *raftnodepb.DemoteLeaderRequest) (*raftnodepb.DemoteLeaderResponse, error) + PromoteToLeader(request *raftnodepb.PromoteToLeaderRequest) (*raftnodepb.PromoteToLeaderResponse, error) +} + +type RaftNodeService struct { + raftnodepb.RaftNodeServiceServer + node RaftNode +} + +func NewRaftNodeService(node RaftNode) *RaftNodeService { + return &RaftNodeService{node: node} +} + +// ReadIndex returns the current commit index and verifies leadership. +func (svc *RaftNodeService) ReadIndex( + context.Context, + *raftnodepb.ReadIndexRequest, +) (*raftnodepb.ReadIndexResponse, error) { + read, err := svc.node.ReadIndex() + if err != nil { + return nil, err + } + resp := &raftnodepb.ReadIndexResponse{ + CommitIndex: read.CommitIndex, + Term: read.Term, + } + return resp, nil +} + +func (svc *RaftNodeService) NodeInfo( + context.Context, + *raftnodepb.NodeInfoRequest, +) (*raftnodepb.NodeInfoResponse, error) { + info, err := svc.node.NodeInfo() + if err != nil { + return nil, err + } + return &raftnodepb.NodeInfoResponse{Node: info}, nil +} + +func (svc *RaftNodeService) RemoveNode( + _ context.Context, + r *raftnodepb.RemoveNodeRequest, +) (*raftnodepb.RemoveNodeResponse, error) { + return svc.node.RemoveNode(r) +} + +func (svc *RaftNodeService) AddNode( + _ context.Context, + r *raftnodepb.AddNodeRequest, +) (*raftnodepb.AddNodeResponse, error) { + return svc.node.AddNode(r) +} + +func (svc *RaftNodeService) DemoteLeader( + _ context.Context, + r *raftnodepb.DemoteLeaderRequest, +) (*raftnodepb.DemoteLeaderResponse, error) { + return svc.node.DemoteLeader(r) +} + +func (svc *RaftNodeService) PromoteToLeader( + _ context.Context, + r *raftnodepb.PromoteToLeaderRequest, +) (*raftnodepb.PromoteToLeaderResponse, error) { + return svc.node.PromoteToLeader(r) +} diff --git a/pkg/metastore/raftnode/snapshot.go b/pkg/metastore/raftnode/snapshot.go new file mode 100644 index 0000000000..532de11e3b --- /dev/null +++ b/pkg/metastore/raftnode/snapshot.go @@ -0,0 +1,109 @@ +package raftnode + +import ( + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + + "github.com/go-kit/log/level" +) + +// importSnapshots moves snapshots from SnapshotsImportDir to SnapshotsDir. +// +// When initializing the snapshot store, Raft creates a "snapshots" subdirectory. +// To maintain consistency, this behavior is replicated here – so "snapshots" should +// not be included in the configured path. +// +// Note: the import process does not guarantee atomicity, as it may involve moving +// files across different file systems. If an error occurs during the import, +// both the source and destination directories may be left in an inconsistent state. +// The function does not attempt to recover from such a state, but it will try to +// continue copying on the next call. +func (n *Node) importSnapshots() error { + if n.config.SnapshotsImportDir == "" { + return nil + } + + importDir := filepath.Join(n.config.SnapshotsImportDir, "snapshots") + snapshotsDir := filepath.Join(n.config.SnapshotsDir, "snapshots") + + level.Info(n.logger).Log("msg", "importing snapshots") + entries, err := fs.ReadDir(os.DirFS(importDir), ".") + if err != nil { + return fmt.Errorf("failed to read dir: %w", err) + } + + for _, entry := range entries { + if !entry.IsDir() { + continue + } + dstDir := filepath.Join(snapshotsDir, entry.Name()) + srcDir := filepath.Join(importDir, entry.Name()) + if err = n.copySnapshot(srcDir, dstDir); err != nil { + return fmt.Errorf("failed to import snapshot %q: %w", entry.Name(), err) + } + } + + return nil +} + +func (n *Node) copySnapshot(srcDir, dstDir string) error { + entries, err := fs.ReadDir(os.DirFS(srcDir), ".") + if err != nil { + return fmt.Errorf("failed to read snapshot dir: %w", err) + } + var hasFiles bool + for _, entry := range entries { + if entry.IsDir() { + continue + } + hasFiles = true + break + } + if !hasFiles { + return nil + } + + level.Info(n.logger).Log("msg", "importing snapshot", "snapshot", srcDir) + if err = os.MkdirAll(dstDir, 0755); err != nil { + return fmt.Errorf("failed to create snapshot directory: %w", err) + } + + for _, entry := range entries { + srcPath := filepath.Join(srcDir, entry.Name()) + dstPath := filepath.Join(dstDir, entry.Name()) + if err = copyFile(srcPath, dstPath); err != nil { + return fmt.Errorf("failed to copy snapshot file %q: %w", entry.Name(), err) + } + if err = os.Remove(srcPath); err != nil { + level.Warn(n.logger).Log("msg", "failed to remove source file after copy", "file", srcPath, "err", err) + } + } + + return nil +} + +func copyFile(src, dst string) error { + sourceFile, err := os.Open(src) + if err != nil { + return fmt.Errorf("failed to open source file: %w", err) + } + defer func() { + _ = sourceFile.Close() + }() + sourceInfo, err := sourceFile.Stat() + if err != nil { + return fmt.Errorf("failed to stat source file: %w", err) + } + destFile, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, sourceInfo.Mode()) + if err != nil { + return fmt.Errorf("failed to create destination file: %w", err) + } + if _, err = io.Copy(destFile, sourceFile); err != nil { + _ = destFile.Close() + return fmt.Errorf("failed to copy file contents: %w", err) + } + return destFile.Close() +} diff --git a/pkg/metastore/raftnode/snapshot_test.go b/pkg/metastore/raftnode/snapshot_test.go new file mode 100644 index 0000000000..8d1270f2be --- /dev/null +++ b/pkg/metastore/raftnode/snapshot_test.go @@ -0,0 +1,50 @@ +package raftnode + +import ( + "bytes" + "fmt" + "path/filepath" + "strings" + "testing" + + "github.com/go-kit/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/test" +) + +func TestCopySnapshots(t *testing.T) { + tmp := t.TempDir() + snapshotsImportDir := filepath.Join(tmp, "src") + snapshotsDir := filepath.Join(tmp, "dst") + test.Copy(t, "testdata/snapshots", snapshotsImportDir+"/snapshots") + + buf := bytes.NewBuffer(nil) + n := &Node{ + logger: log.NewLogfmtLogger(buf), + config: Config{ + SnapshotsImportDir: snapshotsImportDir, + SnapshotsDir: snapshotsDir, + }, + } + + require.NoError(t, n.importSnapshots()) + require.NoError(t, n.importSnapshots()) + + actual := bytes.NewBuffer(nil) + for _, line := range []string{ + `level=info msg="importing snapshots"`, + `level=info msg="importing snapshot" snapshot=/tmp/src/snapshots/81-206944-1744474737935`, + `level=info msg="importing snapshot" snapshot=/tmp/src/snapshots/82-215276-1744546508773`, + `level=info msg="importing snapshot" snapshot=/tmp/src/snapshots/83-223473-1744577537873`, + `level=info msg="importing snapshots"`, + } { + _, _ = fmt.Fprintln(actual, line) + } + + assert.Equal(t, + strings.ReplaceAll(buf.String(), n.config.SnapshotsImportDir, "/tmp/src"), + actual.String(), + ) +} diff --git a/pkg/metastore/raftnode/testdata/snapshots/81-206944-1744474737935/meta.json b/pkg/metastore/raftnode/testdata/snapshots/81-206944-1744474737935/meta.json new file mode 100644 index 0000000000..8fcaa6a54a --- /dev/null +++ b/pkg/metastore/raftnode/testdata/snapshots/81-206944-1744474737935/meta.json @@ -0,0 +1 @@ +{"Version":1,"ID":"81-206944-1744474737935","Index":206944,"Term":81,"Peers":"ka5sb2NhbGhvc3Q6OTA5OQ==","Configuration":{"Servers":[{"Suffrage":0,"ID":"localhost:9099","Address":"localhost:9099"}]},"ConfigurationIndex":1,"Size":14125,"CRC":"gwhKlGf252o="} diff --git a/pkg/metastore/raftnode/testdata/snapshots/81-206944-1744474737935/state.bin b/pkg/metastore/raftnode/testdata/snapshots/81-206944-1744474737935/state.bin new file mode 100644 index 0000000000..8fcaa6a54a --- /dev/null +++ b/pkg/metastore/raftnode/testdata/snapshots/81-206944-1744474737935/state.bin @@ -0,0 +1 @@ +{"Version":1,"ID":"81-206944-1744474737935","Index":206944,"Term":81,"Peers":"ka5sb2NhbGhvc3Q6OTA5OQ==","Configuration":{"Servers":[{"Suffrage":0,"ID":"localhost:9099","Address":"localhost:9099"}]},"ConfigurationIndex":1,"Size":14125,"CRC":"gwhKlGf252o="} diff --git a/pkg/metastore/raftnode/testdata/snapshots/82-215276-1744546508773/meta.json b/pkg/metastore/raftnode/testdata/snapshots/82-215276-1744546508773/meta.json new file mode 100644 index 0000000000..8e6c3dcaf1 --- /dev/null +++ b/pkg/metastore/raftnode/testdata/snapshots/82-215276-1744546508773/meta.json @@ -0,0 +1 @@ +{"Version":1,"ID":"82-215276-1744546508773","Index":215276,"Term":82,"Peers":"ka5sb2NhbGhvc3Q6OTA5OQ==","Configuration":{"Servers":[{"Suffrage":0,"ID":"localhost:9099","Address":"localhost:9099"}]},"ConfigurationIndex":1,"Size":11912,"CRC":"3c6ZlpXOmFI="} diff --git a/pkg/metastore/raftnode/testdata/snapshots/82-215276-1744546508773/state.bin b/pkg/metastore/raftnode/testdata/snapshots/82-215276-1744546508773/state.bin new file mode 100644 index 0000000000..8e6c3dcaf1 --- /dev/null +++ b/pkg/metastore/raftnode/testdata/snapshots/82-215276-1744546508773/state.bin @@ -0,0 +1 @@ +{"Version":1,"ID":"82-215276-1744546508773","Index":215276,"Term":82,"Peers":"ka5sb2NhbGhvc3Q6OTA5OQ==","Configuration":{"Servers":[{"Suffrage":0,"ID":"localhost:9099","Address":"localhost:9099"}]},"ConfigurationIndex":1,"Size":11912,"CRC":"3c6ZlpXOmFI="} diff --git a/pkg/metastore/raftnode/testdata/snapshots/83-223473-1744577537873/meta.json b/pkg/metastore/raftnode/testdata/snapshots/83-223473-1744577537873/meta.json new file mode 100644 index 0000000000..b9f9c63ce4 --- /dev/null +++ b/pkg/metastore/raftnode/testdata/snapshots/83-223473-1744577537873/meta.json @@ -0,0 +1 @@ +{"Version":1,"ID":"83-223473-1744577537873","Index":223473,"Term":83,"Peers":"ka5sb2NhbGhvc3Q6OTA5OQ==","Configuration":{"Servers":[{"Suffrage":0,"ID":"localhost:9099","Address":"localhost:9099"}]},"ConfigurationIndex":1,"Size":14353,"CRC":"8Eyja9ULd/I="} diff --git a/pkg/metastore/raftnode/testdata/snapshots/83-223473-1744577537873/state.bin b/pkg/metastore/raftnode/testdata/snapshots/83-223473-1744577537873/state.bin new file mode 100644 index 0000000000..b9f9c63ce4 --- /dev/null +++ b/pkg/metastore/raftnode/testdata/snapshots/83-223473-1744577537873/state.bin @@ -0,0 +1 @@ +{"Version":1,"ID":"83-223473-1744577537873","Index":223473,"Term":83,"Peers":"ka5sb2NhbGhvc3Q6OTA5OQ==","Configuration":{"Servers":[{"Suffrage":0,"ID":"localhost:9099","Address":"localhost:9099"}]},"ConfigurationIndex":1,"Size":14353,"CRC":"8Eyja9ULd/I="} diff --git a/pkg/metastore/store/store.go b/pkg/metastore/store/store.go new file mode 100644 index 0000000000..d5c4c0f8a9 --- /dev/null +++ b/pkg/metastore/store/store.go @@ -0,0 +1,55 @@ +package store + +import ( + "bytes" + "errors" + + "go.etcd.io/bbolt" +) + +var ErrNotFound = errors.New("not found") + +type KV struct { + Key []byte + Value []byte +} + +func NewCursorIter(cursor *bbolt.Cursor) *CursorIterator { + return &CursorIterator{cursor: cursor} +} + +type CursorIterator struct { + cursor *bbolt.Cursor + seek bool + k, v []byte + + // Prefix that keys must start with. + Prefix []byte + // Keys that start with this prefix will be skipped. + SkipPrefix []byte +} + +func (c *CursorIterator) Next() bool { + if !c.seek { + c.k, c.v = c.cursor.Seek(c.Prefix) + c.seek = true + return c.valid() + } + for { + c.k, c.v = c.cursor.Next() + if !c.valid() { + return false + } + if len(c.SkipPrefix) == 0 || !bytes.HasPrefix(c.k, c.SkipPrefix) { + return true + } + } +} + +func (c *CursorIterator) valid() bool { + return c.k != nil && (len(c.Prefix) == 0 || bytes.HasPrefix(c.k, c.Prefix)) +} + +func (c *CursorIterator) At() KV { return KV{Key: c.k, Value: c.v} } +func (c *CursorIterator) Err() error { return nil } +func (c *CursorIterator) Close() error { return nil } diff --git a/pkg/metastore/tenant_service.go b/pkg/metastore/tenant_service.go new file mode 100644 index 0000000000..9cf1742091 --- /dev/null +++ b/pkg/metastore/tenant_service.go @@ -0,0 +1,101 @@ +package metastore + +import ( + "context" + + "github.com/go-kit/log" + "github.com/grafana/dskit/tracing" + "go.etcd.io/bbolt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" +) + +type TenantIndex interface { + GetTenants(tx *bbolt.Tx) []string + GetTenantStats(tx *bbolt.Tx, tenant string) *metastorev1.TenantStats +} + +type TenantService struct { + metastorev1.TenantServiceServer + + logger log.Logger + state State + index TenantIndex +} + +func NewTenantService( + logger log.Logger, + state State, + index TenantIndex, +) *TenantService { + return &TenantService{ + logger: logger, + state: state, + index: index, + } +} + +func (svc *TenantService) GetTenants( + ctx context.Context, + _ *metastorev1.GetTenantsRequest, +) (resp *metastorev1.GetTenantsResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "TenantService.GetTenants") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + read := func(tx *bbolt.Tx, _ raftnode.ReadIndex) { + resp = &metastorev1.GetTenantsResponse{TenantIds: svc.index.GetTenants(tx)} + } + if readErr := svc.state.ConsistentRead(ctx, read); readErr != nil { + return nil, status.Error(codes.Unavailable, readErr.Error()) + } + span.SetTag("tenant_count", len(resp.GetTenantIds())) + return resp, err +} + +func (svc *TenantService) GetTenant( + ctx context.Context, + req *metastorev1.GetTenantRequest, +) (resp *metastorev1.GetTenantResponse, err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "TenantService.GetTenant") + defer func() { + if err != nil { + span.LogError(err) + span.SetError() + } + span.Finish() + }() + + span.SetTag("tenant_id", req.GetTenantId()) + + read := func(tx *bbolt.Tx, _ raftnode.ReadIndex) { + resp = &metastorev1.GetTenantResponse{Stats: svc.index.GetTenantStats(tx, req.TenantId)} + } + if readErr := svc.state.ConsistentRead(ctx, read); readErr != nil { + return nil, status.Error(codes.Unavailable, readErr.Error()) + } + if stats := resp.GetStats(); stats != nil { + span.SetTag("data_ingested", stats.GetDataIngested()) + span.SetTag("oldest_profile_time", stats.GetOldestProfileTime()) + span.SetTag("newest_profile_time", stats.GetNewestProfileTime()) + } else { + span.SetTag("data_ingested", false) + } + return resp, err +} + +func (svc *TenantService) DeleteTenant( + context.Context, + *metastorev1.DeleteTenantRequest, +) (*metastorev1.DeleteTenantResponse, error) { + // TODO(kolesnikovae): Implement. + return new(metastorev1.DeleteTenantResponse), nil +} diff --git a/pkg/metastore/test/create.go b/pkg/metastore/test/create.go new file mode 100644 index 0000000000..9dd662bd21 --- /dev/null +++ b/pkg/metastore/test/create.go @@ -0,0 +1,185 @@ +package test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/services" + "github.com/hashicorp/raft" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/thanos-io/objstore" + "google.golang.org/grpc" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore" + metastoreclient "github.com/grafana/pyroscope/v2/pkg/metastore/client" + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + placement "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockdiscovery" + "github.com/grafana/pyroscope/v2/pkg/util/health" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func NewMetastoreSet(t *testing.T, cfg *metastore.Config, n int, bucket objstore.Bucket) MetastoreSet { + l := test.NewTestingLogger(t) + + grpcAddresses := make([]string, n) + raftAddresses := make([]string, n) + raftIds := make([]string, n) + bootstrapPeers := make([]string, n) + for i := 0; i < n; i++ { + grpcAddresses[i] = fmt.Sprintf("localhost:%d", 10500+i) + raftAddresses[i] = fmt.Sprintf("localhost:%d", 10500+2*i) + raftIds[i] = fmt.Sprintf("node-%d", i) + bootstrapPeers[i] = fmt.Sprintf("%s/%s", raftAddresses[i], raftIds[i]) + } + l.Log("grpcAddresses", fmt.Sprintf("%+v", grpcAddresses), "raftAddresses", fmt.Sprintf("%+v", raftAddresses)) + + configs := make([]metastore.Config, n) + for i := 0; i < n; i++ { + icfg := *cfg + icfg.MinReadyDuration = 0 + icfg.Address = grpcAddresses[i] + icfg.FSM.DataDir = t.TempDir() + icfg.Raft.ServerID = raftIds[i] + icfg.Raft.Dir = t.TempDir() + icfg.Raft.AdvertiseAddress = raftAddresses[i] + icfg.Raft.BindAddress = raftAddresses[i] + icfg.Raft.BootstrapPeers = bootstrapPeers + icfg.Raft.BootstrapExpectPeers = n + configs[i] = icfg + } + + servers := make([]discovery.Server, n) + for i := 0; i < n; i++ { + srv := discovery.Server{ + Raft: raft.Server{ + ID: raft.ServerID(raftIds[i]), + Address: raft.ServerAddress(raftAddresses[i]), + }, + ResolvedAddress: grpcAddresses[i], + } + servers[i] = srv + } + + listeners, dialOpt := test.CreateInMemoryListeners(grpcAddresses) + d := MockStaticDiscovery(t, servers) + client := metastoreclient.New(l, cfg.GRPCClientConfig, d, dialOpt) + err := client.Service().StartAsync(context.Background()) + require.NoError(t, err) + + res := MetastoreSet{ + t: t, + } + + for i := 0; i < n; i++ { + options, err := cfg.GRPCClientConfig.DialOption(nil, nil, nil) + require.NoError(t, err) + options = append(options, dialOpt) + cc, err := grpc.Dial(grpcAddresses[i], options...) + require.NoError(t, err) + logger := log.With(l, "idx", bootstrapPeers[i]) + server := grpc.NewServer() + registry := prometheus.NewRegistry() + placementManager := placement.NewManager( + logger, + registry, + placement.DefaultConfig(), + validation.MockDefaultOverrides(), + placement.NewStore(bucket), + ) + m, err := metastore.New(configs[i], validation.MockDefaultOverrides(), logger, registry, health.NoOpService, client, bucket, placementManager) + require.NoError(t, err) + m.Register(server) + + lis := listeners[grpcAddresses[i]] + go func() { + err := server.Serve(lis) + assert.NoError(t, err) + }() + res.Instances = append(res.Instances, MetastoreInstance{ + Config: configs[i], + Metastore: m, + Connection: cc, + Server: server, + + IndexServiceClient: metastorev1.NewIndexServiceClient(cc), + CompactionServiceClient: metastorev1.NewCompactionServiceClient(cc), + MetadataQueryServiceClient: metastorev1.NewMetadataQueryServiceClient(cc), + TenantServiceClient: metastorev1.NewTenantServiceClient(cc), + RaftNodeServiceClient: raftnodepb.NewRaftNodeServiceClient(cc), + }) + service := m.Service() + ctx := context.Background() + require.NoError(t, service.StartAsync(ctx)) + require.NoError(t, service.AwaitRunning(ctx)) + logger.Log("msg", "service started") + } + + require.Eventually(t, func() bool { + for i := 0; i < n; i++ { + if res.Instances[i].Metastore.Service().State() != services.Running { + return false + } + if res.Instances[i].Metastore.CheckReady(context.Background()) != nil { + return false + } + } + return true + }, 10*time.Second, 100*time.Millisecond) + + res.Client = client + + return res +} + +func MockStaticDiscovery(t *testing.T, servers []discovery.Server) *mockdiscovery.MockDiscovery { + d := mockdiscovery.NewMockDiscovery(t) + d.On("Subscribe", mock.Anything).Run(func(args mock.Arguments) { + upd := args.Get(0).(discovery.Updates) + upd.Servers(servers) + }) + d.On("Rediscover", mock.Anything).Return() + d.On("Close").Return(nil) + return d +} + +type MetastoreInstance struct { + Config metastore.Config + Metastore *metastore.Metastore + Server *grpc.Server + Connection *grpc.ClientConn + + metastorev1.IndexServiceClient + metastorev1.CompactionServiceClient + metastorev1.MetadataQueryServiceClient + metastorev1.TenantServiceClient + raftnodepb.RaftNodeServiceClient +} + +type MetastoreSet struct { + t *testing.T + Instances []MetastoreInstance + Client *metastoreclient.Client +} + +func (m *MetastoreSet) Close() { + for _, i := range m.Instances { + i.Metastore.Service().StopAsync() + err := i.Metastore.Service().AwaitTerminated(context.Background()) + require.NoError(m.t, err) + i.Connection.Close() + i.Server.Stop() + } + m.Client.Service().StopAsync() + err := m.Client.Service().AwaitTerminated(context.Background()) + require.NoError(m.t, err) +} diff --git a/pkg/metastore/test/metastore_disk_failure_test.go b/pkg/metastore/test/metastore_disk_failure_test.go new file mode 100644 index 0000000000..b47eaa2e67 --- /dev/null +++ b/pkg/metastore/test/metastore_disk_failure_test.go @@ -0,0 +1,207 @@ +package test + +import ( + "context" + "crypto/rand" + "fmt" + "sync" + "testing" + "time" + + "github.com/grafana/dskit/flagext" + "github.com/hashicorp/raft" + "github.com/oklog/ulid/v2" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" +) + +// TestMetastoreDiskFailure_ClusterRecovery verifies that a full Pyroscope +// metastore cluster recovers after the leader's disk becomes slow. It uses +// the LogStoreMiddleware hook to inject a blocking fault on the +// leader's log store, then verifies a new leader is elected and the cluster +// can serve both reads and writes. +func TestMetastoreDiskFailure_ClusterRecovery(t *testing.T) { + const clusterSize = 3 + + faults := make([]*faultInjector, clusterSize) + for i := range faults { + faults[i] = &faultInjector{} + } + + cfg := new(metastore.Config) + flagext.DefaultValues(cfg) + cfg.Raft.LogStoreTimeout = 2 * time.Second + + // Wire each node's log store through its fault injector. + // NewMetastoreSet creates nodes 0..n-1 in order, each calling + // LogStoreMiddleware during init. + var mu sync.Mutex + nodeIdx := 0 + cfg.Raft.LogStoreMiddleware = func(store raft.LogStore) raft.LogStore { + mu.Lock() + i := nodeIdx + nodeIdx++ + mu.Unlock() + faults[i].store = store + return faults[i] + } + + ms := NewMetastoreSet(t, cfg, clusterSize, memory.NewInMemBucket()) + defer func() { + for _, f := range faults { + f.Unblock() + } + ms.Close() + }() + + leaderIdx := findLeader(t, ms) + t.Logf("leader is node %d", leaderIdx) + + // Write a block through the leader to confirm the cluster is healthy. + block1ID := ulid.MustNew(1, rand.Reader).String() + _, err := ms.Instances[leaderIdx].AddBlock(context.Background(), &metastorev1.AddBlockRequest{ + Block: &metastorev1.BlockMeta{Id: block1ID}, + }) + require.NoError(t, err) + t.Logf("wrote block %s through leader", block1ID) + + // Inject blocking disk fault on the leader. + faults[leaderIdx].SetBlocked() + t.Log("injected blocking disk fault on leader") + + // Write to the faulted leader should fail (or hang until timeout). + writeCtx, writeCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer writeCancel() + _, err = ms.Instances[leaderIdx].AddBlock(writeCtx, &metastorev1.AddBlockRequest{ + Block: &metastorev1.BlockMeta{Id: ulid.MustNew(2, rand.Reader).String()}, + }) + require.Error(t, err) + t.Logf("write to faulted leader failed: %v", err) + + // Wait for a new leader to be elected. + var newLeaderIdx int + require.Eventually(t, func() bool { + for i := range ms.Instances { + if i == leaderIdx { + continue + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + info, infoErr := ms.Instances[i].NodeInfo(ctx, &raftnodepb.NodeInfoRequest{}) + cancel() + if infoErr != nil { + continue + } + if info.GetNode().GetState() == "Leader" { + newLeaderIdx = i + return true + } + } + return false + }, 30*time.Second, 500*time.Millisecond, + "a new leader should be elected after disk failure") + t.Logf("new leader elected: node %d", newLeaderIdx) + + // Unblock the faulted node so it can rejoin as a healthy follower. + // This stabilizes the cluster for subsequent operations. + faults[leaderIdx].Unblock() + t.Log("unblocked faulted node") + + // Write a new block through the new leader. + block2ID := ulid.MustNew(3, rand.Reader).String() + require.Eventually(t, func() bool { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + _, err := ms.Instances[newLeaderIdx].AddBlock(ctx, &metastorev1.AddBlockRequest{ + Block: &metastorev1.BlockMeta{Id: block2ID}, + }) + return err == nil + }, 15*time.Second, 200*time.Millisecond, + "should be able to write through new leader") + t.Logf("wrote block %s through new leader", block2ID) + + // Read back both blocks to verify data consistency. + var resp *metastorev1.GetBlockMetadataResponse + require.Eventually(t, func() bool { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + resp, err = ms.Instances[newLeaderIdx].GetBlockMetadata(ctx, &metastorev1.GetBlockMetadataRequest{ + Blocks: &metastorev1.BlockList{ + Blocks: []string{block1ID, block2ID}, + }, + }) + return err == nil && len(resp.Blocks) == 2 + }, 15*time.Second, 200*time.Millisecond, + "both blocks should be readable after recovery") + t.Log("cluster recovered: both blocks readable") +} + +func findLeader(t *testing.T, ms MetastoreSet) int { + t.Helper() + for i := range ms.Instances { + info, err := ms.Instances[i].NodeInfo(context.Background(), &raftnodepb.NodeInfoRequest{}) + if err != nil { + continue + } + if info.GetNode().GetState() == "Leader" { + return i + } + } + t.Fatal("no leader found") + return -1 +} + +// faultInjector wraps a raft.LogStore and can be switched to blocking mode. +type faultInjector struct { + store raft.LogStore + mu sync.RWMutex + blocked chan struct{} +} + +func (f *faultInjector) SetBlocked() { + f.mu.Lock() + f.blocked = make(chan struct{}) + f.mu.Unlock() +} + +func (f *faultInjector) Unblock() { + f.mu.Lock() + if f.blocked != nil { + close(f.blocked) + f.blocked = nil + } + f.mu.Unlock() +} + +func (f *faultInjector) checkFault() error { + f.mu.RLock() + ch := f.blocked + f.mu.RUnlock() + if ch != nil { + <-ch + return fmt.Errorf("simulated disk I/O error") + } + return nil +} + +func (f *faultInjector) FirstIndex() (uint64, error) { return f.store.FirstIndex() } +func (f *faultInjector) LastIndex() (uint64, error) { return f.store.LastIndex() } +func (f *faultInjector) GetLog(idx uint64, log *raft.Log) error { return f.store.GetLog(idx, log) } +func (f *faultInjector) DeleteRange(min, max uint64) error { return f.store.DeleteRange(min, max) } + +func (f *faultInjector) StoreLog(log *raft.Log) error { + if err := f.checkFault(); err != nil { + return err + } + return f.store.StoreLog(log) +} + +func (f *faultInjector) StoreLogs(logs []*raft.Log) error { + if err := f.checkFault(); err != nil { + return err + } + return f.store.StoreLogs(logs) +} diff --git a/pkg/metastore/test/metastore_leader_details_test.go b/pkg/metastore/test/metastore_leader_details_test.go new file mode 100644 index 0000000000..dd84338b5e --- /dev/null +++ b/pkg/metastore/test/metastore_leader_details_test.go @@ -0,0 +1,64 @@ +package test + +import ( + "context" + "crypto/rand" + "testing" + + "github.com/grafana/dskit/flagext" + "github.com/oklog/ulid/v2" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/metastore" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" +) + +func TestRaftDetailsAddBlock(t *testing.T) { + cfg := new(metastore.Config) + flagext.DefaultValues(cfg) + + ms := NewMetastoreSet(t, cfg, 3, memory.NewInMemBucket()) + defer ms.Close() + + errors := 0 + m := &metastorev1.BlockMeta{ + Id: ulid.MustNew(1, rand.Reader).String(), + } + for _, it := range ms.Instances { + _, err := it.AddBlock(context.Background(), &metastorev1.AddBlockRequest{ + Block: m, + }) + if err != nil { + requireRaftDetails(t, err) + errors++ + } + } + require.Equal(t, 2, errors) +} + +func TestRaftDetailsPullCompaction(t *testing.T) { + cfg := new(metastore.Config) + flagext.DefaultValues(cfg) + + ms := NewMetastoreSet(t, cfg, 3, memory.NewInMemBucket()) + defer ms.Close() + + errors := 0 + for _, it := range ms.Instances { + _, err := it.PollCompactionJobs(context.Background(), &metastorev1.PollCompactionJobsRequest{}) + if err != nil { + requireRaftDetails(t, err) + errors++ + } + } + require.Equal(t, 2, errors) +} + +func requireRaftDetails(t *testing.T, err error) { + t.Log("error", err) + leader, ok := raftnode.RaftLeaderFromStatusDetails(err) + require.True(t, ok) + t.Log("leader is", leader) +} diff --git a/pkg/metastore/tracing/context_registry.go b/pkg/metastore/tracing/context_registry.go new file mode 100644 index 0000000000..f2d4779a33 --- /dev/null +++ b/pkg/metastore/tracing/context_registry.go @@ -0,0 +1,150 @@ +package tracing + +import ( + "context" + "sync" + "time" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/util" +) + +// ContextRegistry maintains a mapping of IDs to contexts for tracing purposes. +// This allows us to propagate tracing context from HTTP handlers down to BoltDB transactions +// without persisting the context in Raft logs. +// +// The registry is only used on the leader node where Propose() is called. Followers will +// not have contexts available and will use context.Background() instead. +type ContextRegistry struct { + mu sync.RWMutex + entries map[string]*contextEntry + // cleanupInterval determines how often we scan for expired entries + cleanupInterval time.Duration + // entryTTL is the maximum age of an entry before it's considered expired + entryTTL time.Duration + stop chan struct{} + done chan struct{} + + // sizeMetric tracks the number of entries in the registry + sizeMetric prometheus.Gauge +} + +type contextEntry struct { + ctx context.Context + created time.Time +} + +const ( + defaultCleanupInterval = 10 * time.Second + defaultEntryTTL = 30 * time.Second +) + +// NewContextRegistry creates a new context registry with background cleanup. +func NewContextRegistry(reg prometheus.Registerer) *ContextRegistry { + return newContextRegistry(defaultCleanupInterval, defaultEntryTTL, reg) +} + +// newContextRegistry creates a new context registry with background cleanup. +func newContextRegistry(cleanupInterval, entryTTL time.Duration, reg prometheus.Registerer) *ContextRegistry { + if cleanupInterval <= 0 { + cleanupInterval = defaultCleanupInterval + } + if entryTTL <= 0 { + entryTTL = defaultEntryTTL + } + + sizeMetric := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "context_registry_size", + Help: "Number of contexts currently stored in the registry for tracing propagation", + }) + if reg != nil { + util.RegisterOrGet(reg, sizeMetric) + } + + r := &ContextRegistry{ + entries: make(map[string]*contextEntry), + cleanupInterval: cleanupInterval, + entryTTL: entryTTL, + stop: make(chan struct{}), + done: make(chan struct{}), + sizeMetric: sizeMetric, + } + + go r.cleanupLoop() + return r +} + +// Store saves a context for the given ID. +func (r *ContextRegistry) Store(id string, ctx context.Context) { + r.mu.Lock() + defer r.mu.Unlock() + r.entries[id] = &contextEntry{ + ctx: ctx, + created: time.Now(), + } +} + +// Retrieve gets the context for the given ID. +func (r *ContextRegistry) Retrieve(id string) (context.Context, bool) { + r.mu.RLock() + defer r.mu.RUnlock() + if entry, ok := r.entries[id]; ok { + return entry.ctx, true + } + return context.Background(), false +} + +// Delete removes the context for the given ID. +func (r *ContextRegistry) Delete(id string) { + r.mu.Lock() + defer r.mu.Unlock() + delete(r.entries, id) +} + +// cleanupLoop periodically removes expired entries from the registry. +func (r *ContextRegistry) cleanupLoop() { + defer close(r.done) + ticker := time.NewTicker(r.cleanupInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + r.cleanup() + case <-r.stop: + return + } + } +} + +// cleanup removes entries that are older than the TTL. +func (r *ContextRegistry) cleanup() { + r.mu.Lock() + defer r.mu.Unlock() + + now := time.Now() + for id, entry := range r.entries { + if now.Sub(entry.created) > r.entryTTL { + delete(r.entries, id) + } + } + + if r.sizeMetric != nil { + r.sizeMetric.Set(float64(len(r.entries))) + } +} + +// Shutdown stops the cleanup loop. +func (r *ContextRegistry) Shutdown() { + close(r.stop) + <-r.done +} + +// Size returns the current number of entries in the registry. +// This is primarily useful for metrics and testing. +func (r *ContextRegistry) Size() int { + r.mu.RLock() + defer r.mu.RUnlock() + return len(r.entries) +} diff --git a/pkg/metastore/tracing/context_registry_test.go b/pkg/metastore/tracing/context_registry_test.go new file mode 100644 index 0000000000..f1c45fc133 --- /dev/null +++ b/pkg/metastore/tracing/context_registry_test.go @@ -0,0 +1,120 @@ +package tracing + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type contextKey string + +func TestContextRegistry_StoreAndRetrieve(t *testing.T) { + r := newContextRegistry(1*time.Second, 5*time.Second, nil) + defer r.Shutdown() + + ctx := context.WithValue(context.Background(), contextKey("key"), "value") + r.Store("id-1", ctx) + + retrieved, found := r.Retrieve("id-1") + require.True(t, found) + assert.Equal(t, "value", retrieved.Value(contextKey("key"))) +} + +func TestContextRegistry_RetrieveNotFound(t *testing.T) { + r := newContextRegistry(1*time.Second, 5*time.Second, nil) + defer r.Shutdown() + + retrieved, found := r.Retrieve("nonexistent-id") + require.False(t, found) + assert.Equal(t, context.Background(), retrieved) +} + +func TestContextRegistry_Delete(t *testing.T) { + r := newContextRegistry(1*time.Second, 5*time.Second, nil) + defer r.Shutdown() + + ctx := context.WithValue(context.Background(), contextKey("key"), "value") + r.Store("id-1", ctx) + + _, found := r.Retrieve("id-1") + require.True(t, found) + + r.Delete("id-1") + + _, found = r.Retrieve("id-1") + require.False(t, found) +} + +func TestContextRegistry_Cleanup(t *testing.T) { + // Use short TTL for a faster test + r := newContextRegistry(100*time.Millisecond, 200*time.Millisecond, nil) + defer r.Shutdown() + + ctx := context.WithValue(context.Background(), contextKey("key"), "value") + r.Store("id-1", ctx) + + _, found := r.Retrieve("id-1") + require.True(t, found) + assert.Equal(t, 1, r.Size()) + + time.Sleep(400 * time.Millisecond) + + _, found = r.Retrieve("id-1") + require.False(t, found) + assert.Equal(t, 0, r.Size()) +} + +func TestContextRegistry_Size(t *testing.T) { + r := newContextRegistry(1*time.Second, 5*time.Second, nil) + defer r.Shutdown() + + assert.Equal(t, 0, r.Size()) + + ctx := context.Background() + r.Store("id-1", ctx) + r.Store("id-2", ctx) + r.Store("id-3", ctx) + + assert.Equal(t, 3, r.Size()) + + r.Delete("id-2") + assert.Equal(t, 2, r.Size()) +} + +func TestContextRegistry_ConcurrentAccess(t *testing.T) { + r := newContextRegistry(1*time.Second, 5*time.Second, nil) + defer r.Shutdown() + + done := make(chan bool) + + for i := 0; i < 10; i++ { + go func(id int) { + ctx := context.WithValue(context.Background(), contextKey("id"), id) + for j := 0; j < 100; j++ { + r.Store(fmt.Sprintf("%d-%d", id, j), ctx) + time.Sleep(1 * time.Millisecond) + } + done <- true + }(i) + } + + for i := 0; i < 10; i++ { + go func(id int) { + for j := 0; j < 100; j++ { + r.Retrieve(fmt.Sprintf("%d-%d", id, j)) + time.Sleep(1 * time.Millisecond) + } + done <- true + }(i) + } + + for i := 0; i < 20; i++ { + <-done + } + + assert.True(t, r.Size() > 0) +} diff --git a/pkg/metastore/tracing/util.go b/pkg/metastore/tracing/util.go new file mode 100644 index 0000000000..12bea0b433 --- /dev/null +++ b/pkg/metastore/tracing/util.go @@ -0,0 +1,18 @@ +package tracing + +import ( + "context" + + dskittracing "github.com/grafana/dskit/tracing" + oteltrace "go.opentelemetry.io/otel/trace" +) + +// StartSpanFromContext starts a new span from context only if the context +// already carries a parent span. This avoids creating orphaned root spans +// in places like metastore followers where no trace context is available. +func StartSpanFromContext(ctx context.Context, operationName string) (*dskittracing.Span, context.Context) { + if !oteltrace.SpanFromContext(ctx).SpanContext().IsValid() { + return &dskittracing.Span{}, ctx + } + return dskittracing.StartSpanFromContext(ctx, operationName) +} diff --git a/pkg/metrics/config.go b/pkg/metrics/config.go new file mode 100644 index 0000000000..828576d85a --- /dev/null +++ b/pkg/metrics/config.go @@ -0,0 +1,32 @@ +package metrics + +import ( + "errors" + "flag" +) + +type Config struct { + Enabled bool `yaml:"enabled" category:"advanced"` + RulesSource struct { + ClientAddress string `yaml:"client_address" category:"advanced"` + } `yaml:"rules_source"` + RemoteWriteAddress string `yaml:"remote_write_address" category:"advanced"` +} + +func (c *Config) Validate() error { + if !c.Enabled { + return nil + } + if c.RemoteWriteAddress == "" { + return errors.New("remote write address is required") + } + return nil +} + +func (c *Config) RegisterFlags(f *flag.FlagSet) { + const prefix = "compaction-worker.metrics-exporter." + + f.BoolVar(&c.Enabled, prefix+"enabled", false, "This parameter specifies whether the metrics exporter is enabled.") + f.StringVar(&c.RulesSource.ClientAddress, prefix+"rules-source.client-address", "", "The address to use for the recording rules client connection.") + f.StringVar(&c.RemoteWriteAddress, prefix+"remote-write-address", "", "The address to use for metrics tenant.") +} diff --git a/pkg/metrics/exporter.go b/pkg/metrics/exporter.go new file mode 100644 index 0000000000..6f13448fab --- /dev/null +++ b/pkg/metrics/exporter.go @@ -0,0 +1,181 @@ +package metrics + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strconv" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/gogo/protobuf/proto" + "github.com/grafana/dskit/instrument" + "github.com/klauspost/compress/snappy" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/config" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/prompb" + "github.com/prometheus/prometheus/storage/remote" + + pyroscopemodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +type StaticExporter struct { + client remote.WriteClient + wg sync.WaitGroup + + logger log.Logger + + metrics *clientMetrics +} + +const ( + metricsExporterUserAgent = "pyroscope-metrics-exporter" +) + +func NewExporter(remoteWriteAddress string, logger log.Logger, reg prometheus.Registerer) (Exporter, error) { + metrics := newMetrics(reg, remoteWriteAddress) + client, err := newClient(remoteWriteAddress, metrics) + if err != nil { + return nil, err + } + return &StaticExporter{ + client: client, + wg: sync.WaitGroup{}, + logger: logger, + metrics: metrics, + }, nil +} + +func (e *StaticExporter) Send(tenantId string, data []prompb.TimeSeries) error { + e.wg.Add(1) + go func(data []prompb.TimeSeries) { + defer e.wg.Done() + p := &prompb.WriteRequest{Timeseries: data} + buf := proto.NewBuffer(nil) + if err := buf.Marshal(p); err != nil { + level.Error(e.logger).Log("msg", "unable to marshal prompb.WriteRequest", "err", err) + return + } + + ctx := tenant.InjectTenantID(context.Background(), tenantId) + _, err := e.client.Store(ctx, snappy.Encode(nil, buf.Bytes()), 0) + if err != nil { + level.Error(e.logger).Log("msg", "unable to store prompb.WriteRequest", "err", err) + return + } + seriesByRuleID := make(map[string]int) + for _, ts := range data { + ruleID := "unknown" + for _, l := range ts.Labels { + if l.Name == pyroscopemodel.RuleIDLabel { + ruleID = l.Value + break + } + } + seriesByRuleID[ruleID]++ + } + for ruleID, count := range seriesByRuleID { + e.metrics.seriesSent.WithLabelValues(tenantId, ruleID).Add(float64(count)) + } + }(data) + return nil +} + +func (e *StaticExporter) Flush() { + e.wg.Wait() +} + +func newClient(remoteUrl string, m *clientMetrics) (remote.WriteClient, error) { + wURL, err := url.Parse(remoteUrl) + if err != nil { + return nil, err + } + + client, err := remote.NewWriteClient("exporter", &remote.ClientConfig{ + URL: &config.URL{URL: wURL}, + Timeout: model.Duration(time.Second * 10), + Headers: map[string]string{ + "User-Agent": metricsExporterUserAgent, + }, + RetryOnRateLimit: false, + }) + if err != nil { + return nil, err + } + t := client.(*remote.Client).Client.Transport + client.(*remote.Client).Client.Transport = &RoundTripper{m, t} + return client, nil +} + +type clientMetrics struct { + requestDuration *prometheus.HistogramVec + requestBodySize *prometheus.CounterVec + seriesSent *prometheus.CounterVec +} + +func newMetrics(reg prometheus.Registerer, remoteUrl string) *clientMetrics { + m := &clientMetrics{ + requestDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "metrics_exporter", + Name: "client_request_duration_seconds", + Help: "Time (in seconds) spent on remote_write", + Buckets: instrument.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"route", "status_code", "tenant"}), + requestBodySize: prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "pyroscope", + Subsystem: "metrics_exporter", + Name: "request_message_bytes_total", + Help: "Size (in bytes) of messages sent on remote_write.", + }, []string{"route", "status_code", "tenant"}), + seriesSent: prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "pyroscope", + Subsystem: "metrics_exporter", + Name: "series_sent_total", + Help: "Number of series sent on remote_write.", + }, []string{"tenant", "rule_id"}), + } + if reg != nil { + remoteUrlReg := prometheus.WrapRegistererWith(prometheus.Labels{"url": remoteUrl}, reg) + remoteUrlReg.MustRegister( + m.requestDuration, + m.requestBodySize, + m.seriesSent, + ) + } + return m +} + +type RoundTripper struct { + metrics *clientMetrics + next http.RoundTripper +} + +func (m *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + tenantId, err := tenant.ExtractTenantIDFromContext(req.Context()) + if err != nil { + return nil, fmt.Errorf("unable to get tenant ID from context: %w", err) + } + req.Header.Set("X-Scope-OrgId", tenantId) + + start := time.Now() + resp, err := m.next.RoundTrip(req) + duration := time.Since(start) + + statusCode := "" + if resp != nil { + statusCode = strconv.Itoa(resp.StatusCode) + } + + m.metrics.requestDuration.WithLabelValues(req.RequestURI, statusCode, tenantId).Observe(duration.Seconds()) + m.metrics.requestBodySize.WithLabelValues(req.RequestURI, statusCode, tenantId).Add(float64(req.ContentLength)) + return resp, err +} diff --git a/pkg/metrics/observer.go b/pkg/metrics/observer.go new file mode 100644 index 0000000000..04d9daaa57 --- /dev/null +++ b/pkg/metrics/observer.go @@ -0,0 +1,339 @@ +package metrics + +import ( + "github.com/parquet-go/parquet-go" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/prompb" + + "github.com/grafana/pyroscope/v2/pkg/block" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +type SampleObserver struct { + state *observerState + + recordingTime int64 + externalLabels labels.Labels + + exporter Exporter + ruler Ruler +} + +type observerState struct { + // tenant state + tenant string + recordings []*recording + + // dataset state + dataset string + targetRecordings []*recording + targetStrings map[string][]*recording + targetLocations map[uint32]map[*recording]struct{} + seenLocations int + targetStacktraces map[uint32]map[*recording]struct{} + + // series state + fingerprint model.Fingerprint + recordSymbols bool +} + +type recording struct { + rule *phlaremodel.RecordingRule + data map[model.Fingerprint]*prompb.TimeSeries + state *recordingState +} + +type recordingState struct { + matches bool + sample *prompb.Sample +} + +type Ruler interface { + // RecordingRules return a validated set of rules for a tenant, with the following guarantees: + // - a "__name__" label is present among ExternalLabels. It contains a valid prometheus metric name, and starts + // with `profiles_recorded_` + // - a "profiles_rule_id" label is present among ExternalLabels. It identifies the rule. + // - a matcher with name "__profile__type__" is present in Matchers + RecordingRules(tenant string) []*phlaremodel.RecordingRule +} + +type Exporter interface { + Send(tenant string, series []prompb.TimeSeries) error + Flush() +} + +func NewSampleObserver(recordingTime int64, exporter Exporter, ruler Ruler, labels labels.Labels) *SampleObserver { + return &SampleObserver{ + recordingTime: recordingTime, + externalLabels: labels, + exporter: exporter, + ruler: ruler, + state: &observerState{ + recordings: make([]*recording, 0), + targetRecordings: make([]*recording, 0), + targetStrings: make(map[string][]*recording), + targetLocations: make(map[uint32]map[*recording]struct{}), + targetStacktraces: make(map[uint32]map[*recording]struct{}), + }, + } +} + +func (o *SampleObserver) initTenantState(tenant string) { + o.state.tenant = tenant + recordingRules := o.ruler.RecordingRules(tenant) + + for _, rule := range recordingRules { + o.state.recordings = append(o.state.recordings, &recording{ + rule: rule, + data: make(map[model.Fingerprint]*prompb.TimeSeries), + state: &recordingState{}, + }) + } + + // force a dataset reset + o.state.dataset = "" +} + +func (o *SampleObserver) initDatasetState(dataset string) { + // New dataset imply new symbols, and new subset of rules that can target the dataset + o.state.targetStrings = make(map[string][]*recording) + o.state.targetLocations = make(map[uint32]map[*recording]struct{}) + o.state.targetStacktraces = make(map[uint32]map[*recording]struct{}) + o.state.seenLocations = 0 + o.state.dataset = dataset + o.state.targetRecordings = o.state.targetRecordings[:0] + for _, rec := range o.state.recordings { + // storing the subset of the recording that matter to this dataset: + if rec.matchesServiceName(dataset) { + o.state.targetRecordings = append(o.state.targetRecordings, rec) + if rec.rule.FunctionName != "" { + // create a lookup for functions names that matter + if _, exists := o.state.targetStrings[rec.rule.FunctionName]; !exists { + o.state.targetStrings[rec.rule.FunctionName] = make([]*recording, 0) + } + o.state.targetStrings[rec.rule.FunctionName] = append(o.state.targetStrings[rec.rule.FunctionName], rec) + } + } + } +} + +// Evaluate manages three kind of states. +// - Per tenant state: +// Gets initialized on new tenant. It fetches tenant's rules and creates a new recording for each rule. +// Data of old state is flushed to the exporter. +// - Per dataset state: +// Gets initialized on new dataset. It holds the subset of rules that matter to that dataset, and some set of +// pointers symbol-to-rule. +// - Per series (or batch of rows) state: +// Holds the fingerprint of the series (every batch of rows of the same fingerprint), and whether there's a matching +// rule that requires symbols to be observed. +// In addition, the state of every recording is computed, i.e. whether the rule matches the new batch of rows, and +// a reference of the sample to be aggregated to. (Note that every rule will eventually create multiple single-sample (aggregated) series, +// depending on the rule.GroupBy space. More info in initState). +// +// This call is not thread-safe +func (o *SampleObserver) Evaluate(row block.ProfileEntry) func() { + // Detect a tenant switch + tenant := row.Dataset.TenantID() + if o.state.tenant != row.Dataset.TenantID() { + // new tenant to observe, flush data of previous tenant and init new tenant state + o.flush() + o.initTenantState(tenant) + } + + // Detect a dataset switch + if o.state.dataset != row.Dataset.Name() { + o.initDatasetState(row.Dataset.Name()) + } + + // Detect a series switch + if o.state.fingerprint != row.Fingerprint { + // New series. Handle state. + o.initSeriesState(row) + } + return func() { + o.observe(row) + } +} + +func (o *SampleObserver) initSeriesState(row block.ProfileEntry) { + o.state.fingerprint = row.Fingerprint + o.state.recordSymbols = false + + sb := labels.NewScratchBuilder(len(row.Labels)) + for _, label := range row.Labels { + sb.Add(label.Name, label.Value) + } + sb.Sort() + blockLabels := sb.Labels() + lb := labels.NewBuilder(labels.EmptyLabels()) + for _, rec := range o.state.targetRecordings { + rec.initState(lb, blockLabels, o.externalLabels, o.recordingTime) + if rec.state.matches && rec.rule.FunctionName != "" { + o.state.recordSymbols = true + } + } +} + +// ObserveSymbols will observe symbols as soon as there's a function rule targeting this dataset. +// Symbols are observed only once, and the current rule may have symbols that a future matching rule needs. +// This is suboptimal as we may read more symbols than needed. However, the current interface does not let us do better, +// and a bigger refactor may be needed to address this issue. +// At the end of this process we'll have a map stacktraceId -> matching rule, so later we can get stacktraces from the +// row and quickly look up for matching rules +func (o *SampleObserver) ObserveSymbols(strings []string, functions []schemav1.InMemoryFunction, locations []schemav1.InMemoryLocation, stacktraceValues [][]int32, stacktraceIds []uint32) { + if len(o.state.targetStrings) == 0 { + return + } + + for ; o.state.seenLocations < len(locations); o.state.seenLocations++ { + for _, line := range locations[o.state.seenLocations].Line { + recs, hit := o.state.targetStrings[strings[functions[line.FunctionId].Name]] + if hit { + targetLocation, exists := o.state.targetLocations[uint32(o.state.seenLocations)] + if !exists { + targetLocation = make(map[*recording]struct{}) + o.state.targetLocations[uint32(o.state.seenLocations)] = targetLocation + } + for _, rec := range recs { + targetLocation[rec] = struct{}{} + } + } + } + } + if len(o.state.targetLocations) == 0 { + return + } + for i, stacktrace := range stacktraceValues { + for _, locationId := range stacktrace { + recs, hit := o.state.targetLocations[uint32(locationId)] + if hit { + targetStacktrace, exists := o.state.targetStacktraces[stacktraceIds[i]] + if !exists { + targetStacktrace = make(map[*recording]struct{}) + o.state.targetStacktraces[stacktraceIds[i]] = targetStacktrace + } + for rec := range recs { + targetStacktrace[rec] = struct{}{} + } + } + } + } +} + +func (o *SampleObserver) observe(row block.ProfileEntry) { + // Totals are computed as follows: for every rule that matches the series, we add the TotalValue + for _, rec := range o.state.targetRecordings { + if rec.state.matches && rec.rule.FunctionName == "" { + rec.state.sample.Value += float64(row.Row.TotalValue()) + } + } + // On the other hand, functions are computed from the lookup tables only if the series hit some rule. + if o.state.recordSymbols { + row.Row.ForStacktraceIdsAndValues(func(ids []parquet.Value, values []parquet.Value) { + for i, id := range ids { + for rec := range o.state.targetStacktraces[id.Uint32()] { + if rec.state.matches { + rec.state.sample.Value += float64(values[i].Int64()) + } + } + } + }) + } +} + +func (o *SampleObserver) flush() { + if len(o.state.recordings) == 0 { + return + } + timeSeries := make([]prompb.TimeSeries, 0) + for _, rec := range o.state.recordings { + for _, series := range rec.data { + timeSeries = append(timeSeries, *series) + } + } + if len(timeSeries) > 0 { + _ = o.exporter.Send(o.state.tenant, timeSeries) + } + o.state.recordings = o.state.recordings[:0] +} + +func (o *SampleObserver) Close() { + o.flush() +} + +// initState checks whether row matches the filters +// if filters match, then labels to export are computed, and fetch/create the series where the value needs to be +// aggregated. This state is hold for the following rows with the same fingerprint, so we can observe those faster +func (r *recording) initState(lb *labels.Builder, blockLabels labels.Labels, externalLabels labels.Labels, recordingTime int64) { + r.state.matches = r.matches(blockLabels) + if !r.state.matches { + return + } + + lblCount := setExportedLabels(lb, blockLabels, r, externalLabels) + exportedLabels := lb.Labels() + aggregatedFp := model.Fingerprint(exportedLabels.Hash()) + + series, ok := r.data[aggregatedFp] + if !ok { + series = newTimeSeries(exportedLabels, lblCount, recordingTime) + r.data[aggregatedFp] = series + } + r.state.sample = &series.Samples[0] +} + +func newTimeSeries(exportedLabels labels.Labels, exportedLabelCount int, recordingTime int64) *prompb.TimeSeries { + pbLabels := make([]prompb.Label, 0, exportedLabelCount) + pbLabels = prompb.FromLabels(exportedLabels, pbLabels) + series := &prompb.TimeSeries{ + Labels: pbLabels, + Samples: []prompb.Sample{ + { + Value: 0, Timestamp: recordingTime, + }, + }, + } + return series +} + +func setExportedLabels(lb *labels.Builder, blockLabels labels.Labels, rec *recording, externalLabels labels.Labels) int { + count := 0 + set := func(l labels.Label) { + count += 1 + lb.Set(l.Name, l.Value) + } + // reset label builder to contain both externalLabels + lb.Reset(labels.EmptyLabels()) + externalLabels.Range(set) + rec.rule.ExternalLabels.Range(set) + + // Keep the groupBy labels if present + for _, label := range rec.rule.GroupBy { + labelValue := blockLabels.Get(label) + if labelValue != "" { + set(labels.Label{Name: label, Value: labelValue}) + } + } + return count +} + +func (r *recording) matchesServiceName(dataset string) bool { + for _, matcher := range r.rule.Matchers { + if matcher.Name == "service_name" && !matcher.Matches(dataset) { + return false + } + } + return true +} + +func (r *recording) matches(lbls labels.Labels) bool { + for _, matcher := range r.rule.Matchers { + if !matcher.Matches(lbls.Get(matcher.Name)) { + return false + } + } + return true +} diff --git a/pkg/metrics/observer_test.go b/pkg/metrics/observer_test.go new file mode 100644 index 0000000000..1e0d9c2cbc --- /dev/null +++ b/pkg/metrics/observer_test.go @@ -0,0 +1,168 @@ +package metrics + +import ( + "reflect" + "sort" + "testing" + + "github.com/parquet-go/parquet-go" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/prompb" + "github.com/stretchr/testify/mock" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetrics" +) + +var ( + blockTime = int64(0) + profileTime = int64(1) +) + +func Test_Observer_observe(t *testing.T) { + exporter := new(mockmetrics.MockExporter) + ruler := new(mockmetrics.MockRuler) + ruler.On("RecordingRules", mock.Anything).Return([]*phlaremodel.RecordingRule{ + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "a", "1"), + labels.MustNewMatcher(labels.MatchEqual, "b", "1"), + }, + GroupBy: []string{"c"}, + ExternalLabels: labels.New(labels.Label{Name: "external1", Value: "external1"}), + }, + { + Matchers: []*labels.Matcher{ + labels.MustNewMatcher(labels.MatchEqual, "d", "1"), + }, + GroupBy: []string{}, + }, + }) + observer := NewSampleObserver(blockTime, exporter, ruler, labels.New(labels.Label{Name: "external2", Value: "external2"})) + entries := entriesOf([][]any{ + {"tenant1", [][]string{{"a", "0"}, {"b", "0"}, {"c", "0"}, {"d", "0"}}, int64(1) << 0}, + {"tenant1", [][]string{{"a", "0"}, {"b", "0"}, {"c", "0"}, {"d", "1"}}, int64(1) << 1}, + {"tenant1", [][]string{{"a", "0"}, {"b", "0"}, {"c", "1"}, {"d", "0"}}, int64(1) << 2}, + {"tenant1", [][]string{{"a", "0"}, {"b", "0"}, {"c", "1"}, {"d", "1"}}, int64(1) << 3}, + {"tenant1", [][]string{{"a", "0"}, {"b", "1"}, {"c", "0"}, {"d", "0"}}, int64(1) << 4}, + {"tenant1", [][]string{{"a", "0"}, {"b", "1"}, {"c", "0"}, {"d", "1"}}, int64(1) << 5}, + {"tenant1", [][]string{{"a", "0"}, {"b", "1"}, {"c", "1"}, {"d", "0"}}, int64(1) << 6}, + {"tenant1", [][]string{{"a", "0"}, {"b", "1"}, {"c", "1"}, {"d", "1"}}, int64(1) << 7}, + {"tenant1", [][]string{{"a", "1"}, {"b", "0"}, {"c", "0"}, {"d", "0"}}, int64(1) << 8}, + {"tenant1", [][]string{{"a", "1"}, {"b", "0"}, {"c", "0"}, {"d", "1"}}, int64(1) << 9}, + {"tenant1", [][]string{{"a", "1"}, {"b", "0"}, {"c", "1"}, {"d", "0"}}, int64(1) << 10}, + {"tenant1", [][]string{{"a", "1"}, {"b", "0"}, {"c", "1"}, {"d", "1"}}, int64(1) << 11}, + {"tenant1", [][]string{{"a", "1"}, {"b", "1"}, {"c", "0"}, {"d", "0"}}, int64(1) << 12}, + {"tenant1", [][]string{{"a", "1"}, {"b", "1"}, {"c", "0"}, {"d", "1"}}, int64(1) << 13}, + {"tenant1", [][]string{{"a", "1"}, {"b", "1"}, {"c", "1"}, {"d", "0"}}, int64(1) << 14}, + {"tenant1", [][]string{{"a", "1"}, {"b", "1"}, {"c", "1"}, {"d", "1"}}, int64(1) << 15}, + {"tenant2", [][]string{{"x", "1"}}, int64(1)}, + {"tenant3", [][]string{{"a", "1"}, {"b", "1"}, {"c", "1"}, {"d", "1"}}, int64(1) << 0}, + {"tenant3", [][]string{{"a", "1"}, {"b", "1"}, {"c", "1"}, {"d", "1"}}, int64(1) << 1}, + {"tenant3", [][]string{{"a", "1"}, {"b", "1"}, {"c", "1"}, {"d", "1"}}, int64(1) << 2}, + }) + + exporter.On("Send", "tenant1", + mock.MatchedBy(func(series []prompb.TimeSeries) bool { + return sameSeries(series, []prompb.TimeSeries{ + timeSeriesOf([]any{[][]string{{"c", "0"}, {"external1", "external1"}, {"external2", "external2"}}, 1<<12 + 1<<13, blockTime}), + timeSeriesOf([]any{[][]string{{"c", "1"}, {"external1", "external1"}, {"external2", "external2"}}, 1<<14 + 1<<15, blockTime}), + timeSeriesOf([]any{[][]string{{"external2", "external2"}}, 1<<1 + 1<<3 + 1<<5 + 1<<7 + 1<<9 + 1<<11 + 1<<13 + 1<<15, blockTime}), + }) + }), + ).Return(nil).Once() + + exporter.On("Send", "tenant3", + mock.MatchedBy(func(series []prompb.TimeSeries) bool { + return sameSeries(series, []prompb.TimeSeries{ + timeSeriesOf([]any{[][]string{{"c", "1"}, {"external1", "external1"}, {"external2", "external2"}}, 1<<0 + 1<<1 + 1<<2, blockTime}), + timeSeriesOf([]any{[][]string{{"external2", "external2"}}, 1<<0 + 1<<1 + 1<<2, blockTime}), + }) + }), + ).Return(nil).Once() + + for _, entry := range entries { + observe := observer.Evaluate(entry) + // TODO(alsoba13): Test observeSymbols + observe() + } + observer.Close() + + ruler.AssertExpectations(t) + exporter.AssertExpectations(t) + exporter.AssertNotCalled(t, "Send", "tenant2", mock.Anything) +} + +func sameSeries(series1 []prompb.TimeSeries, series2 []prompb.TimeSeries) bool { + for _, s := range series1 { + found := false + for _, s2 := range series2 { + found = reflect.DeepEqual(s, s2) + if found { + break + } + } + if !found { + return false + } + } + return true +} + +func timeSeriesOf(values []any) prompb.TimeSeries { + lbls := make([]prompb.Label, len(values[0].([][]string))) + for i, label := range values[0].([][]string) { + lbls[i] = prompb.Label{ + Name: label[0], + Value: label[1], + } + } + return prompb.TimeSeries{ + Labels: lbls, + Samples: []prompb.Sample{ + { + Value: float64(values[1].(int)), + Timestamp: values[2].(int64), + }, + }, + } +} + +func entriesOf(values [][]any) []block.ProfileEntry { + profileEntries := make([]block.ProfileEntry, len(values)) + for i, value := range values { + ls := make(phlaremodel.Labels, len(value[1].([][]string))) + for j, label := range value[1].([][]string) { + ls[j] = &typesv1.LabelPair{ + Name: label[0], + Value: label[1], + } + } + sort.Sort(ls) + row := make(v1.ProfileRow, 4) + row[3] = parquet.Int64Value(value[2].(int64)) + profileEntries[i] = block.ProfileEntry{ + Dataset: datasetForTenant(value[0].(string)), + Timestamp: profileTime, + Fingerprint: model.Fingerprint(ls.Hash()), + Labels: ls, + Row: row, + } + } + return profileEntries +} + +func datasetForTenant(tenant string) *block.Dataset { + return block.NewDataset( + &metastorev1.Dataset{}, + block.NewObject( + nil, + &metastorev1.BlockMeta{StringTable: []string{tenant}}, + ), + ) +} diff --git a/pkg/metrics/ruler.go b/pkg/metrics/ruler.go new file mode 100644 index 0000000000..d001ada37a --- /dev/null +++ b/pkg/metrics/ruler.go @@ -0,0 +1,126 @@ +package metrics + +import ( + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +const ( + rulesExpiryTime = time.Minute +) + +type StaticRuler struct { + overrides *validation.Overrides +} + +func NewStaticRulerFromOverrides(overrides *validation.Overrides) Ruler { + return &StaticRuler{ + overrides: overrides, + } +} + +func (ruler StaticRuler) RecordingRules(tenant string) []*model.RecordingRule { + rules := ruler.overrides.RecordingRules(tenant) + rs := make([]*model.RecordingRule, 0, len(rules)) + for _, rule := range rules { + // should never fail, overrides already validated + r, _ := model.NewRecordingRule(rule) + rs = append(rs, r) + } + return rs +} + +// CachedRemoteRuler is a thread-safe ruler that retrieves rules from an external service. +// It has a per-tenant cache: rulesPerTenant +type CachedRemoteRuler struct { + rulesPerTenant map[string]*tenantCache + mu sync.RWMutex + + client RecordingRulesClient + + logger log.Logger +} + +type RecordingRulesClient interface { + RecordingRules(tenant string) ([]*model.RecordingRule, error) +} + +func NewCachedRemoteRuler(client RecordingRulesClient, logger log.Logger) (Ruler, error) { + return &CachedRemoteRuler{ + rulesPerTenant: make(map[string]*tenantCache), + client: client, + logger: logger, + }, nil +} + +func (r *CachedRemoteRuler) RecordingRules(tenant string) []*model.RecordingRule { + // get the per-tenant cache + r.mu.RLock() + cache, ok := r.rulesPerTenant[tenant] + r.mu.RUnlock() + + // There's no cache for given tenant: init it + if !ok { + r.mu.Lock() + defer r.mu.Unlock() + + // only race-winner will initialize the per-tenant cache + cache, ok = r.rulesPerTenant[tenant] + if !ok { + cache = &tenantCache{ + initFunc: func() ([]*model.RecordingRule, error) { + return r.client.RecordingRules(tenant) + }, + logger: r.logger, + } + r.rulesPerTenant[tenant] = cache + } + } + + // get data from cache: + return cache.get() +} + +// tenantCache is a thread-safe cache that holds an expirable array of rules. +type tenantCache struct { + value []*model.RecordingRule + ttl time.Time + initFunc func() ([]*model.RecordingRule, error) + mu sync.RWMutex + logger log.Logger +} + +// get returns the stored value if present and not expired. +// Otherwise, a single call to initFunc will be performed to retrieve the value and hold it for future calls within +// the ttl. +func (c *tenantCache) get() []*model.RecordingRule { + c.mu.RLock() + if c.value != nil && time.Now().Before(c.ttl) { + defer c.mu.RUnlock() + // value exists and didn't expired + return c.value + } + c.mu.RUnlock() + + c.mu.Lock() + defer c.mu.Unlock() + + // only race-winner will fetch the data + if c.value == nil || time.Now().After(c.ttl) { + value, err := c.initFunc() + if err != nil { + // keep old value and ttl, just log an error + level.Error(c.logger).Log("msg", "failed to fetch recording rules", "err", err) + } else { + c.value = value + c.ttl = time.Now().Add(rulesExpiryTime) + } + } + return c.value +} diff --git a/pkg/metrics/ruler_test.go b/pkg/metrics/ruler_test.go new file mode 100644 index 0000000000..48aaf88f24 --- /dev/null +++ b/pkg/metrics/ruler_test.go @@ -0,0 +1,79 @@ +package metrics + +import ( + "testing" + + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +var ( + defaultRecordingRulesProto = []*settingsv1.RecordingRule{{ + Id: "some-id", + MetricName: "profiles_recorded_default_recording_rule", + Matchers: []string{"{__profile_type__=\"any-profile-type\"}"}, + }} + + defaultRecordingRules = []*model.RecordingRule{{ + ExternalLabels: labels.New(labels.Label{ + Name: "__name__", + Value: "profiles_recorded_default_recording_rule", + }, labels.Label{ + Name: "profiles_rule_id", + Value: "some-id", + }), + Matchers: []*labels.Matcher{{ + Type: labels.MatchEqual, + Name: "__profile_type__", + Value: "any-profile-type", + }}, + }} + + overriddenRecordingRulesProto = []*settingsv1.RecordingRule{{ + Id: "another-id", + MetricName: "profiles_recorded_rule", + Matchers: []string{"{__profile_type__=\"any-profile-type\", matcher1!=\"value\"}"}, + GroupBy: []string{"group_by_label"}, + ExternalLabels: []*typesv1.LabelPair{{Name: "foo", Value: "bar"}}, + }} + + overriddenRecordingRules = []*model.RecordingRule{{ + Matchers: []*labels.Matcher{ + {Type: labels.MatchEqual, Name: "__profile_type__", Value: "any-profile-type"}, + {Type: labels.MatchNotEqual, Name: "matcher1", Value: "value"}, + }, + GroupBy: []string{"group_by_label"}, + ExternalLabels: labels.New( + labels.Label{Name: "__name__", Value: "profiles_recorded_rule"}, + labels.Label{Name: "foo", Value: "bar"}, + labels.Label{Name: "profiles_rule_id", Value: "another-id"}, + ), + }} +) + +func Test_Ruler_happyPath(t *testing.T) { + overrides := newOverrides(t) + + ruler := NewStaticRulerFromOverrides(overrides) + + rules := ruler.RecordingRules("non-configured-tenant") + assert.Equal(t, defaultRecordingRules, rules) + + rules = ruler.RecordingRules("tenant-override") + assert.Equal(t, overriddenRecordingRules, rules) +} + +func newOverrides(t *testing.T) *validation.Overrides { + t.Helper() + return validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + defaults.RecordingRules = defaultRecordingRulesProto + l := validation.MockDefaultLimits() + l.RecordingRules = overriddenRecordingRulesProto + tenantLimits["tenant-override"] = l + }) +} diff --git a/pkg/model/attributetable/attributetable.go b/pkg/model/attributetable/attributetable.go new file mode 100644 index 0000000000..0556751da2 --- /dev/null +++ b/pkg/model/attributetable/attributetable.go @@ -0,0 +1,187 @@ +package attributetable + +import ( + "encoding/binary" + "encoding/hex" + "unique" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +type Key struct { + Key unique.Handle[string] + Value unique.Handle[string] +} + +// Table is used to store attribute key-value pairs for efficient lookup and deduplication. +// It maps attribute keys to integer references, allowing compact representation of labels. +type Table struct { + table map[Key]int64 + entries []Key +} + +func New() *Table { + return &Table{ + table: make(map[Key]int64), + } +} + +func (t *Table) LookupOrAdd(k Key) int64 { + ref, exists := t.table[k] + if !exists { + ref = int64(len(t.entries)) + t.entries = append(t.entries, k) + t.table[k] = ref + } + return ref +} + +func (t *Table) Refs(lbls model.Labels, refs []int64) []int64 { + if cap(refs) < len(lbls) { + refs = make([]int64, len(lbls)) + } else { + refs = refs[:len(lbls)] + } + for i, lbl := range lbls { + refs[i] = t.LookupOrAdd(Key{Key: unique.Make(lbl.Name), Value: unique.Make(lbl.Value)}) + } + return refs +} + +func (t *Table) AnnotationRefs(keys, values []string, refs []int64) []int64 { + if cap(refs) < len(keys) { + refs = make([]int64, len(keys)) + } else { + refs = refs[:len(keys)] + } + for i := range keys { + refs[i] = t.LookupOrAdd(Key{Key: unique.Make(keys[i]), Value: unique.Make(values[i])}) + } + return refs +} + +func (t *Table) Build(res *queryv1.AttributeTable) *queryv1.AttributeTable { + if res == nil { + res = &queryv1.AttributeTable{} + } + + if cap(res.Keys) < len(t.entries) { + res.Keys = make([]string, len(t.entries)) + } else { + res.Keys = res.Keys[:len(t.entries)] + } + if cap(res.Values) < len(t.entries) { + res.Values = make([]string, len(t.entries)) + } else { + res.Values = res.Values[:len(t.entries)] + } + + for idx, e := range t.entries { + res.Keys[idx] = e.Key.Value() + res.Values[idx] = e.Value.Value() + } + + return res +} + +// ResolveLabelPairs converts attribute references to label pairs. +func ResolveLabelPairs(refs []int64, table *queryv1.AttributeTable) []*typesv1.LabelPair { + if table == nil || len(refs) == 0 { + return nil + } + labels := make([]*typesv1.LabelPair, 0, len(refs)) + for _, ref := range refs { + if ref < 0 || ref >= int64(len(table.Keys)) { + continue + } + labels = append(labels, &typesv1.LabelPair{ + Name: table.Keys[ref], + Value: table.Values[ref], + }) + } + return labels +} + +// ResolveAnnotations converts attribute references to profile annotations. +func ResolveAnnotations(refs []int64, table *queryv1.AttributeTable) []*typesv1.ProfileAnnotation { + if table == nil || len(refs) == 0 { + return nil + } + annotations := make([]*typesv1.ProfileAnnotation, 0, len(refs)) + for _, ref := range refs { + if ref < 0 || ref >= int64(len(table.Keys)) { + continue + } + annotations = append(annotations, &typesv1.ProfileAnnotation{ + Key: table.Keys[ref], + Value: table.Values[ref], + }) + } + return annotations +} + +// SpanIDToHex converts a uint64 span ID to a hex string +func SpanIDToHex(spanID uint64) string { + if spanID == 0 { + return "" + } + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, spanID) + return hex.EncodeToString(b) +} + +// resolveExemplar is the shared implementation for converting to a public Exemplar. +// ProfileId, SpanId, and TraceId must already be resolved to strings by the caller. +func resolveExemplar(timestamp, value int64, profileID, spanID, traceID string, attributeRefs []int64, table *queryv1.AttributeTable) *typesv1.Exemplar { + labels := ResolveLabelPairs(attributeRefs, table) + if profileID == "" && spanID == "" && traceID == "" && len(labels) == 0 { + return nil + } + return &typesv1.Exemplar{ + Timestamp: timestamp, + ProfileId: profileID, + SpanId: spanID, + TraceId: traceID, + Value: value, + Labels: labels, + } +} + +// ResolveExemplars converts compact exemplars to public exemplars by resolving attribute refs. +func ResolveExemplars(exemplars []*queryv1.Exemplar, table *queryv1.AttributeTable) []*typesv1.Exemplar { + if len(exemplars) == 0 { + return nil + } + result := make([]*typesv1.Exemplar, 0, len(exemplars)) + for _, ex := range exemplars { + if e := resolveExemplar(ex.Timestamp, ex.Value, ex.ProfileId, ex.SpanId, "", ex.AttributeRefs, table); e != nil { + result = append(result, e) + } + } + return result +} + +// ResolveHeatmapExemplar converts a HeatmapPoint to a public Exemplar by resolving +// attribute refs, profile ID (table lookup), and span ID (hex encoding). +func ResolveHeatmapExemplar(point *queryv1.HeatmapPoint, table *queryv1.AttributeTable) *typesv1.Exemplar { + if point == nil || table == nil { + return nil + } + + profileID := "" + if point.ProfileId >= 0 && point.ProfileId < int64(len(table.Values)) { + profileID = table.Values[point.ProfileId] + } + + // TraceId is only populated when it round-trips through model.TraceID (16 bytes). + // Silently drop anything else (e.g. absent/empty) rather than emitting a + // malformed trace ID that wouldn't satisfy the documented 32-hex-char contract. + traceID := "" + if len(point.TraceId) == len(model.TraceID{}) { + traceID = hex.EncodeToString(point.TraceId) + } + + return resolveExemplar(point.Timestamp, point.Value, profileID, SpanIDToHex(point.SpanId), traceID, point.AttributeRefs, table) +} diff --git a/pkg/model/attributetable/attributetable_test.go b/pkg/model/attributetable/attributetable_test.go new file mode 100644 index 0000000000..83610f9c18 --- /dev/null +++ b/pkg/model/attributetable/attributetable_test.go @@ -0,0 +1,101 @@ +package attributetable + +import ( + "testing" + "unique" + + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +func TestTable_LookupOrAdd(t *testing.T) { + table := New() + + // Add first key + key1 := Key{Key: unique.Make("foo"), Value: unique.Make("bar")} + ref1 := table.LookupOrAdd(key1) + require.Equal(t, int64(0), ref1) + + // Add second key + key2 := Key{Key: unique.Make("baz"), Value: unique.Make("qux")} + ref2 := table.LookupOrAdd(key2) + require.Equal(t, int64(1), ref2) + + // Lookup existing key + ref1Again := table.LookupOrAdd(key1) + require.Equal(t, ref1, ref1Again) +} + +func TestTable_Refs(t *testing.T) { + table := New() + + labels := model.Labels{ + {Name: "foo", Value: "bar"}, + {Name: "baz", Value: "qux"}, + } + + refs := table.Refs(labels, nil) + require.Len(t, refs, 2) + require.Equal(t, int64(0), refs[0]) + require.Equal(t, int64(1), refs[1]) + + // Reuse same labels + refs2 := table.Refs(labels, refs[:0]) + require.Len(t, refs2, 2) + require.Equal(t, refs, refs2) +} + +func TestTable_Build(t *testing.T) { + table := New() + + key1 := Key{Key: unique.Make("service.name"), Value: unique.Make("my-service")} + key2 := Key{Key: unique.Make("environment"), Value: unique.Make("production")} + + table.LookupOrAdd(key1) + table.LookupOrAdd(key2) + + result := table.Build(nil) + + require.NotNil(t, result) + require.Len(t, result.Keys, 2) + require.Len(t, result.Values, 2) + + require.Equal(t, "service.name", result.Keys[0]) + require.Equal(t, "my-service", result.Values[0]) + require.Equal(t, "environment", result.Keys[1]) + require.Equal(t, "production", result.Values[1]) +} + +func TestTable_BuildReusesSlices(t *testing.T) { + table := New() + + key1 := Key{Key: unique.Make("foo"), Value: unique.Make("bar")} + table.LookupOrAdd(key1) + + // First build + result1 := &queryv1.AttributeTable{ + Keys: make([]string, 0, 10), + Values: make([]string, 0, 10), + } + result1 = table.Build(result1) + + // Verify capacity is reused + require.Equal(t, 10, cap(result1.Keys)) + require.Equal(t, 10, cap(result1.Values)) + require.Len(t, result1.Keys, 1) + require.Len(t, result1.Values, 1) +} + +func TestTable_EmptyLabels(t *testing.T) { + table := New() + + labels := model.Labels{} + refs := table.Refs(labels, nil) + require.Empty(t, refs) + + result := table.Build(nil) + require.Empty(t, result.Keys) + require.Empty(t, result.Values) +} diff --git a/pkg/model/attributetable/merger.go b/pkg/model/attributetable/merger.go new file mode 100644 index 0000000000..6c15fa6954 --- /dev/null +++ b/pkg/model/attributetable/merger.go @@ -0,0 +1,94 @@ +package attributetable + +import ( + "fmt" + "sync" + "unique" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +// Merger provides generic merging functionality for series with attribute tables. +type Merger struct { + mu sync.Mutex + table *Table +} + +// NewMerger creates a new generic merger. +func NewMerger() *Merger { + return &Merger{ + table: New(), + } +} + +type Remapper struct { + m map[int64]int64 +} + +// Refs remaps a slice of attribute refs. +func (r *Remapper) Refs(refs []int64) []int64 { + // if we are the first report, we don't have a m yet + if r.m == nil { + return refs + } + + for i, ref := range refs { + if newRef, ok := r.m[ref]; ok { + refs[i] = newRef + } else { + panic(fmt.Sprintf("attribute ref %d not found in attribute table", ref)) + } + } + return refs +} + +// Ref remaps a single attribute ref. +func (r *Remapper) Ref(ref int64) int64 { + // if we are the first report, we don't have a m yet + if r.m == nil { + return ref + } + + newRef, ok := r.m[ref] + if !ok { + panic(fmt.Sprintf("attribute ref %d not found in attribute table", ref)) + } + return newRef +} + +// Merge adds entries from the input attribute table to the merger's +// attribute table and returns a remapper, remapper only safe to use during callback +func (m *Merger) Merge(table *queryv1.AttributeTable, f func(*Remapper)) { + m.mu.Lock() + defer m.mu.Unlock() + + // Keys and Values must have the same length - this is a data corruption bug + if len(table.Keys) != len(table.Values) { + panic(fmt.Sprintf("attribute table corruption: Keys length (%d) != Values length (%d)", len(table.Keys), len(table.Values))) + } + + // only build the refMap if this is not the first report + var refMap map[int64]int64 + if len(table.Keys) > 0 { + refMap = make(map[int64]int64, len(table.Keys)) + } + for i := range table.Keys { + oldRef := int64(i) + key := unique.Make(table.Keys[i]) + value := unique.Make(table.Values[i]) + newRef := m.table.LookupOrAdd(Key{Key: key, Value: value}) + if refMap != nil { + refMap[oldRef] = newRef + } + } + + f(&Remapper{m: refMap}) +} + +// BuildAttributeTable builds the protobuf AttributeTable from the merger's table. +func (m *Merger) BuildAttributeTable(res *queryv1.AttributeTable) *queryv1.AttributeTable { + m.mu.Lock() + defer m.mu.Unlock() + + return m.table.Build(res) +} diff --git a/pkg/model/attributetable/merger_test.go b/pkg/model/attributetable/merger_test.go new file mode 100644 index 0000000000..1caf9cb014 --- /dev/null +++ b/pkg/model/attributetable/merger_test.go @@ -0,0 +1,244 @@ +package attributetable + +import ( + "testing" + + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +func TestMerger_Merge_SingleTable(t *testing.T) { + merger := NewMerger() + + table := &queryv1.AttributeTable{ + Keys: []string{"foo", "bar"}, + Values: []string{"val1", "val2"}, + } + + var remappedRefs []int64 + merger.Merge(table, func(r *Remapper) { + // First merge should have no remapping + remappedRefs = r.Refs([]int64{0, 1}) + }) + + require.Equal(t, []int64{0, 1}, remappedRefs) +} + +func TestMerger_Merge_MultipleTables(t *testing.T) { + merger := NewMerger() + + // First table + table1 := &queryv1.AttributeTable{ + Keys: []string{"foo"}, + Values: []string{"val1"}, + } + merger.Merge(table1, func(r *Remapper) { + refs := r.Refs([]int64{0}) + require.Equal(t, []int64{0}, refs) + }) + + // Second table with same key-value pair + table2 := &queryv1.AttributeTable{ + Keys: []string{"foo"}, + Values: []string{"val1"}, + } + merger.Merge(table2, func(r *Remapper) { + // Should map to the same ref + refs := r.Refs([]int64{0}) + require.Equal(t, []int64{0}, refs) + }) + + // Third table with different key-value pair + table3 := &queryv1.AttributeTable{ + Keys: []string{"bar"}, + Values: []string{"val2"}, + } + merger.Merge(table3, func(r *Remapper) { + // Should get a new ref + refs := r.Refs([]int64{0}) + require.Equal(t, []int64{1}, refs) + }) + + // Verify final table has 2 entries + result := merger.BuildAttributeTable(nil) + require.Len(t, result.Keys, 2) + require.Len(t, result.Values, 2) +} + +func TestMerger_Merge_ComplexRemapping(t *testing.T) { + merger := NewMerger() + + // First table with multiple entries + table1 := &queryv1.AttributeTable{ + Keys: []string{"foo", "bar", "baz"}, + Values: []string{"val1", "val2", "val3"}, + } + merger.Merge(table1, func(r *Remapper) { + refs := r.Refs([]int64{0, 1, 2}) + require.Equal(t, []int64{0, 1, 2}, refs) + }) + + // Second table with overlapping entries in different order + table2 := &queryv1.AttributeTable{ + Keys: []string{"baz", "foo", "new"}, + Values: []string{"val3", "val1", "val4"}, + } + merger.Merge(table2, func(r *Remapper) { + // table2[0] = "baz:val3" should map to table1[2] + // table2[1] = "foo:val1" should map to table1[0] + // table2[2] = "new:val4" should get a new ref (3) + refs := r.Refs([]int64{0, 1, 2}) + require.Equal(t, []int64{2, 0, 3}, refs) + }) + + // Verify final table has 4 entries + result := merger.BuildAttributeTable(nil) + require.Len(t, result.Keys, 4) + require.Len(t, result.Values, 4) + require.Equal(t, "foo", result.Keys[0]) + require.Equal(t, "val1", result.Values[0]) + require.Equal(t, "bar", result.Keys[1]) + require.Equal(t, "val2", result.Values[1]) + require.Equal(t, "baz", result.Keys[2]) + require.Equal(t, "val3", result.Values[2]) + require.Equal(t, "new", result.Keys[3]) + require.Equal(t, "val4", result.Values[3]) +} + +func TestMerger_Merge_EmptyTable(t *testing.T) { + merger := NewMerger() + + table := &queryv1.AttributeTable{ + Keys: []string{}, + Values: []string{}, + } + + merger.Merge(table, func(r *Remapper) { + refs := r.Refs([]int64{}) + require.Empty(t, refs) + }) + + result := merger.BuildAttributeTable(nil) + require.Empty(t, result.Keys) + require.Empty(t, result.Values) +} + +func TestMerger_Merge_AttributeTableCorruption(t *testing.T) { + merger := NewMerger() + + table := &queryv1.AttributeTable{ + Keys: []string{"foo", "bar"}, + Values: []string{"val1"}, // Mismatched length + } + + require.Panics(t, func() { + merger.Merge(table, func(r *Remapper) {}) + }) +} + +func TestRemapper_Ref_SingleValue(t *testing.T) { + merger := NewMerger() + + table := &queryv1.AttributeTable{ + Keys: []string{"foo", "bar", "baz"}, + Values: []string{"val1", "val2", "val3"}, + } + + merger.Merge(table, func(r *Remapper) { + require.Equal(t, int64(0), r.Ref(0)) + require.Equal(t, int64(1), r.Ref(1)) + require.Equal(t, int64(2), r.Ref(2)) + }) + + // Second merge with overlapping data + table2 := &queryv1.AttributeTable{ + Keys: []string{"bar"}, + Values: []string{"val2"}, + } + merger.Merge(table2, func(r *Remapper) { + // "bar:val2" should map to ref 1 from the first table + require.Equal(t, int64(1), r.Ref(0)) + }) +} + +func TestRemapper_Ref_Panic_UnknownRef(t *testing.T) { + merger := NewMerger() + + table := &queryv1.AttributeTable{ + Keys: []string{"foo"}, + Values: []string{"val1"}, + } + + // Second merge - should have a remapper with mapping + table2 := &queryv1.AttributeTable{ + Keys: []string{"bar"}, + Values: []string{"val2"}, + } + + merger.Merge(table, func(r *Remapper) {}) + + require.Panics(t, func() { + merger.Merge(table2, func(r *Remapper) { + // Try to remap a ref that doesn't exist in table2 + r.Ref(99) + }) + }) +} + +func TestMerger_BuildAttributeTable_ReuseSlices(t *testing.T) { + merger := NewMerger() + + table := &queryv1.AttributeTable{ + Keys: []string{"foo"}, + Values: []string{"val1"}, + } + merger.Merge(table, func(r *Remapper) {}) + + // Build with pre-allocated slices + result := &queryv1.AttributeTable{ + Keys: make([]string, 0, 10), + Values: make([]string, 0, 10), + } + result = merger.BuildAttributeTable(result) + + // Verify capacity is reused + require.Equal(t, 10, cap(result.Keys)) + require.Equal(t, 10, cap(result.Values)) + require.Len(t, result.Keys, 1) + require.Len(t, result.Values, 1) +} + +func TestMerger_Concurrency(t *testing.T) { + merger := NewMerger() + + // Add some initial data + table1 := &queryv1.AttributeTable{ + Keys: []string{"foo"}, + Values: []string{"val1"}, + } + merger.Merge(table1, func(r *Remapper) {}) + + // The merger should be safe to use from multiple goroutines + // as it uses a mutex internally + done := make(chan bool) + go func() { + table2 := &queryv1.AttributeTable{ + Keys: []string{"bar"}, + Values: []string{"val2"}, + } + merger.Merge(table2, func(r *Remapper) {}) + done <- true + }() + + go func() { + merger.BuildAttributeTable(nil) + done <- true + }() + + <-done + <-done + + result := merger.BuildAttributeTable(nil) + require.Len(t, result.Keys, 2) +} diff --git a/pkg/model/flamegraph.go b/pkg/model/flamegraph.go index 9838c3a5ca..94e83a1ca7 100644 --- a/pkg/model/flamegraph.go +++ b/pkg/model/flamegraph.go @@ -6,14 +6,14 @@ import ( "github.com/samber/lo" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" ) -func NewFlameGraph(t *Tree, maxNodes int64) *querierv1.FlameGraph { +func NewFlameGraph(t *FunctionNameTree, maxNodes int64) *querierv1.FlameGraph { var total, max int64 for _, node := range t.root { total += node.total @@ -32,7 +32,7 @@ func NewFlameGraph(t *Tree, maxNodes int64) *querierv1.FlameGraph { stack := stackNodePool.Get().(*Stack[stackNode]) defer stackNodePool.Put(stack) stack.Reset() - stack.Push(stackNode{xOffset: 0, level: 0, node: &node{children: t.root, total: total}}) + stack.Push(stackNode{xOffset: 0, level: 0, node: &node[FunctionName]{children: t.root, total: total}}) for { current, hasMoreNodes := stack.Pop() @@ -45,13 +45,14 @@ func NewFlameGraph(t *Tree, maxNodes int64) *querierv1.FlameGraph { var i int var ok bool name := current.node.name - if i, ok = nameLocationCache[name]; !ok { + nameStr := string(name) + if i, ok = nameLocationCache[nameStr]; !ok { i = len(names) if i == 0 { - name = "total" + nameStr = "total" } - nameLocationCache[name] = i - names = append(names, name) + nameLocationCache[nameStr] = i + names = append(names, nameStr) } if current.level == len(res) { @@ -81,7 +82,7 @@ func NewFlameGraph(t *Tree, maxNodes int64) *querierv1.FlameGraph { } } if otherTotal != 0 { - child := &node{ + child := &node[FunctionName]{ name: "other", parent: current.node, self: otherTotal, @@ -170,18 +171,18 @@ func ExportDiffToFlamebearer(fg *querierv1.FlameGraphDiff, profileType *typesv1. fb := ExportToFlamebearer(singleFlamegraph, profileType) fb.LeftTicks = uint64(fg.LeftTicks) fb.RightTicks = uint64(fg.RightTicks) - fb.FlamebearerProfileV1.Metadata.Format = "double" + fb.Metadata.Format = "double" return fb } type FlameGraphMerger struct { mu sync.Mutex - t *Tree + t *FunctionNameTree } func NewFlameGraphMerger() *FlameGraphMerger { - return &FlameGraphMerger{t: new(Tree)} + return &FlameGraphMerger{t: new(FunctionNameTree)} } // MergeFlameGraph adds the flame graph stack traces to the resulting @@ -192,6 +193,7 @@ func (m *FlameGraphMerger) MergeFlameGraph(src *querierv1.FlameGraph) { defer m.mu.Unlock() deltaDecoding(src.Levels, 0, 4) dst := make([]string, 0, len(src.Levels)) + stack := make([]FunctionName, 0, len(src.Levels)) for i, l := range src.Levels { if i == 0 { // Skip the root node ("total"). @@ -201,14 +203,19 @@ func (m *FlameGraphMerger) MergeFlameGraph(src *querierv1.FlameGraph) { self := l.Values[j+2] if self > 0 { dst = buildStack(dst, src, i, j) - m.t.InsertStack(self, dst...) + // Convert []string to []FuntionName + stack = stack[:0] + for _, s := range dst { + stack = append(stack, FunctionName(s)) + } + m.t.InsertStack(self, stack...) } } } } func (m *FlameGraphMerger) MergeTreeBytes(src []byte) error { - t, err := UnmarshalTree(src) + t, err := UnmarshalTree[FunctionName, FunctionNameI](src) if err != nil { return err } @@ -218,12 +225,12 @@ func (m *FlameGraphMerger) MergeTreeBytes(src []byte) error { return nil } -func (m *FlameGraphMerger) Tree() *Tree { return m.t } +func (m *FlameGraphMerger) Tree() *FunctionNameTree { return m.t } func (m *FlameGraphMerger) FlameGraph(maxNodes int64) *querierv1.FlameGraph { t := m.t if t == nil { - t = new(Tree) + t = new(FunctionNameTree) } return NewFlameGraph(t, maxNodes) } diff --git a/pkg/model/flamegraph_diff.go b/pkg/model/flamegraph_diff.go index 852aa90fbd..f013097cb6 100644 --- a/pkg/model/flamegraph_diff.go +++ b/pkg/model/flamegraph_diff.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - "github.com/grafana/pyroscope/pkg/og/structs/cappedarr" + "github.com/grafana/pyroscope/v2/pkg/util/minheap" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" ) @@ -23,7 +23,7 @@ import ( // i+4 = total , right tree // i+5 = self , right tree // i+6 = index in the names array -func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraphDiff, error) { +func NewFlamegraphDiff(left, right *FunctionNameTree, maxNodes int64) (*querierv1.FlameGraphDiff, error) { // The algorithm doesn't work properly with negative nodes // Although it's possible to silently drop these nodes // Let's fail early and analyze properly with real data when the issue happens @@ -65,15 +65,16 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph name := left.name if left.total >= minVal || rght.total >= minVal || name == "other" { - i, ok := nameLocationCache[name] + nameStr := string(name) + i, ok := nameLocationCache[nameStr] if !ok { i = len(res.Names) - nameLocationCache[name] = i + nameLocationCache[nameStr] = i if i == 0 { - name = "total" + nameStr = "total" } - res.Names = append(res.Names, name) + res.Names = append(res.Names, nameStr) } if level == len(res.Levels) { @@ -95,7 +96,8 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph int64(i), } - res.Levels[level].Values = append(values, res.Levels[level].Values...) + // We need to prepend values here, but this is expensive. We'll reverse the order later. + res.Levels[level].Values = append(res.Levels[level].Values, values...) xLeftOffset += left.self xRghtOffset += rght.self otherLeftTotal, otherRghtTotal := int64(0), int64(0) @@ -119,7 +121,7 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph if otherLeftTotal != 0 || otherRghtTotal != 0 { levels = prependInt(levels, level+1) { - leftNode := &node{ + leftNode := &node[FunctionName]{ name: "other", total: otherLeftTotal, self: otherLeftTotal, @@ -128,7 +130,7 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph leftNodes = prependTreeNode(leftNodes, leftNode) } { - rghtNode := &node{ + rghtNode := &node[FunctionName]{ name: "other", total: otherRghtTotal, self: otherRghtTotal, @@ -140,16 +142,33 @@ func NewFlamegraphDiff(left, right *Tree, maxNodes int64) (*querierv1.FlameGraph } } + // reverse each level's values since we appended values instead of prepending them + for _, level := range res.Levels { + reverseSliceInChunks(level.Values, 7) + } + deltaEncoding(res.Levels, 0, 7) deltaEncoding(res.Levels, 3, 7) return res, nil } +func NewFlamegraphDiffFromBytes(left, right []byte, maxNodes int64) (*querierv1.FlameGraphDiff, error) { + l, err := UnmarshalTree[FunctionName, FunctionNameI](left) + if err != nil { + return nil, err + } + r, err := UnmarshalTree[FunctionName, FunctionNameI](right) + if err != nil { + return nil, err + } + return NewFlamegraphDiff(l, r, maxNodes) +} + // combineTree aligns 2 trees by making them having the same structure with the // same number of nodes // It also makes the tree have a single root -func combineTree(leftTree, rightTree *Tree) (*Tree, *Tree) { +func combineTree(leftTree, rightTree *FunctionNameTree) (*FunctionNameTree, *FunctionNameTree) { leftTotal := int64(0) for _, l := range leftTree.root { leftTotal = leftTotal + l.total @@ -162,16 +181,16 @@ func combineTree(leftTree, rightTree *Tree) (*Tree, *Tree) { // differently from pyroscope, there could be multiple roots // so we add a fake root as expected - leftTree = &Tree{ - root: []*node{{ + leftTree = &FunctionNameTree{ + root: []*node[FunctionName]{{ children: leftTree.root, total: leftTotal, self: 0, }}, } - rightTree = &Tree{ - root: []*node{{ + rightTree = &FunctionNameTree{ + root: []*node[FunctionName]{{ children: rightTree.root, total: rightTotal, self: 0, @@ -198,10 +217,10 @@ func combineTree(leftTree, rightTree *Tree) (*Tree, *Tree) { // combineNodes makes 2 slices of nodes equal // by filling with non existing nodes // and sorting lexicographically -func combineNodes(leftNodes, rghtNodes []*node) ([]*node, []*node) { - size := nextPow2(maxInt(len(leftNodes), len(rghtNodes))) - leftResult := make([]*node, 0, size) - rghtResult := make([]*node, 0, size) +func combineNodes(leftNodes, rghtNodes []*node[FunctionName]) ([]*node[FunctionName], []*node[FunctionName]) { + size := nextPow2(max(len(leftNodes), len(rghtNodes))) + leftResult := make([]*node[FunctionName], 0, size) + rghtResult := make([]*node[FunctionName], 0, size) for len(leftNodes) != 0 && len(rghtNodes) != 0 { left, rght := leftNodes[0], rghtNodes[0] @@ -212,11 +231,11 @@ func combineNodes(leftNodes, rghtNodes []*node) ([]*node, []*node) { leftNodes, rghtNodes = leftNodes[1:], rghtNodes[1:] case -1: leftResult = append(leftResult, left) - rghtResult = append(rghtResult, &node{name: left.name}) + rghtResult = append(rghtResult, &node[FunctionName]{name: left.name}) leftNodes = leftNodes[1:] case 1: - leftResult = append(leftResult, &node{name: rght.name}) + leftResult = append(leftResult, &node[FunctionName]{name: rght.name}) rghtResult = append(rghtResult, rght) rghtNodes = rghtNodes[1:] } @@ -224,35 +243,14 @@ func combineNodes(leftNodes, rghtNodes []*node) ([]*node, []*node) { leftResult = append(leftResult, leftNodes...) rghtResult = append(rghtResult, rghtNodes...) for _, left := range leftNodes { - rghtResult = append(rghtResult, &node{name: left.name}) + rghtResult = append(rghtResult, &node[FunctionName]{name: left.name}) } for _, rght := range rghtNodes { - leftResult = append(leftResult, &node{name: rght.name}) + leftResult = append(leftResult, &node[FunctionName]{name: rght.name}) } return leftResult, rghtResult } -func maxUint64(a, b uint64) uint64 { - if a > b { - return a - } - return b -} - -func maxInt(a, b int) int { - if a > b { - return a - } - return b -} - -func max(a, b int64) int64 { - if a > b { - return a - } - return b -} - func nextPow2(a int) int { a-- a |= a >> 1 @@ -264,26 +262,37 @@ func nextPow2(a int) int { return a } -func combineMinValues(leftTree, rightTree *Tree, maxNodes int) uint64 { +func combineMinValues(leftTree, rightTree *FunctionNameTree, maxNodes int) uint64 { if maxNodes < 1 { return 0 } - // Trees are combined, meaning that their structures are - // identical, therefore the resulting tree can not have - // more nodes than any of them. - treeSize := leftTree.size(make([]*node, 0, defaultDFSSize)) + treeSize := leftTree.size(make([]*node[FunctionName], 0, defaultDFSSize)) if treeSize <= int64(maxNodes) { return 0 } - c := cappedarr.New(maxNodes) + + h := make([]int64, 0, maxNodes) combineIterateWithTotal(leftTree, rightTree, func(left uint64, right uint64) bool { - return c.Push(maxUint64(left, right)) + maxVal := int64(max(left, right)) + if len(h) >= maxNodes { + if maxVal > h[0] { + h = minheap.Pop(h) + h = minheap.Push(h, maxVal) + } + } else { + h = minheap.Push(h, maxVal) + } + return true }) - return c.MinValue() + + if len(h) < maxNodes { + return 0 + } + return uint64(h[0]) } // iterate both trees, both trees must be returned from combineTree -func combineIterateWithTotal(leftTree, rightTree *Tree, cb func(uint64, uint64) bool) { +func combineIterateWithTotal(leftTree, rightTree *FunctionNameTree, cb func(uint64, uint64) bool) { leftNodes, rghtNodes := leftTree.root, rightTree.root i := 0 for len(leftNodes) > 0 { @@ -300,8 +309,8 @@ func combineIterateWithTotal(leftTree, rightTree *Tree, cb func(uint64, uint64) } // isPositiveTree returns whether a tree only contain positive values -func isPositiveTree(t *Tree) bool { - stack := Stack[*node]{} +func isPositiveTree(t *FunctionNameTree) bool { + stack := Stack[*node[FunctionName]]{} for _, node := range t.root { stack.Push(node) } @@ -324,7 +333,7 @@ func isPositiveTree(t *Tree) bool { return true } -func assertPositiveTrees(left *Tree, right *Tree) error { +func assertPositiveTrees(left *FunctionNameTree, right *FunctionNameTree) error { leftRes := isPositiveTree(left) rightRes := isPositiveTree(right) @@ -367,9 +376,22 @@ func prependInt64(s []int64, x int64) []int64 { return s } -func prependTreeNode(s []*node, x *node) []*node { +func prependTreeNode(s []*node[FunctionName], x *node[FunctionName]) []*node[FunctionName] { s = append(s, nil) copy(s[1:], s) s[0] = x return s } + +// reverseSliceInChunks reverses a slice in chunks of the given size +func reverseSliceInChunks(slice []int64, chunkSize int) { + if len(slice) < chunkSize { + return + } + + for i, j := 0, len(slice)-chunkSize; i < j; i, j = i+chunkSize, j-chunkSize { + for k := 0; k < chunkSize; k++ { + slice[i+k], slice[j+k] = slice[j+k], slice[i+k] + } + } +} diff --git a/pkg/model/flamegraph_diff_bench_test.go b/pkg/model/flamegraph_diff_bench_test.go new file mode 100644 index 0000000000..2d0013a60c --- /dev/null +++ b/pkg/model/flamegraph_diff_bench_test.go @@ -0,0 +1,30 @@ +package model + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func Benchmark_NewFlamegraphDiff(b *testing.B) { + leftTreeBytes, err := os.ReadFile("testdata/diff_left_tree.bin") + require.NoError(b, err) + rightTreeBytes, err := os.ReadFile("testdata/diff_right_tree.bin") + require.NoError(b, err) + + leftTree, err := UnmarshalTree[FunctionName, FunctionNameI](leftTreeBytes) + require.NoError(b, err) + + rightTree, err := UnmarshalTree[FunctionName, FunctionNameI](rightTreeBytes) + require.NoError(b, err) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + diff, err := NewFlamegraphDiff(leftTree, rightTree, 163840) + require.NoError(b, err) + require.NotNil(b, diff) + } +} diff --git a/pkg/model/flamegraph_test.go b/pkg/model/flamegraph_test.go index cd89946e90..ef060103b7 100644 --- a/pkg/model/flamegraph_test.go +++ b/pkg/model/flamegraph_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" @@ -102,7 +102,7 @@ func BenchmarkFlamegraph(b *testing.B) { func Test_FlameGraphMerger(t *testing.T) { t.Run("two non-empty flamegraphs", func(t *testing.T) { m := NewFlameGraphMerger() - s := new(Tree) + s := new(FunctionNameTree) s.InsertStack(1, "foo", "bar") s.InsertStack(1, "foo", "bar", "baz") s.InsertStack(2, "foo", "qux") @@ -110,7 +110,7 @@ func Test_FlameGraphMerger(t *testing.T) { s.InsertStack(1, "fred", "other") m.MergeFlameGraph(NewFlameGraph(s, -1)) - s = new(Tree) + s = new(FunctionNameTree) s.InsertStack(1, "foo", "bar", "baz") s.InsertStack(1, "fred", "zoo") s.InsertStack(1, "fred", "zoo", "ward") @@ -119,7 +119,7 @@ func Test_FlameGraphMerger(t *testing.T) { s.InsertStack(1, "other") m.MergeFlameGraph(NewFlameGraph(s, -1)) - expected := new(Tree) + expected := new(FunctionNameTree) expected.InsertStack(1, "foo", "bar") expected.InsertStack(1, "foo", "bar", "baz") expected.InsertStack(2, "foo", "qux") @@ -137,7 +137,7 @@ func Test_FlameGraphMerger(t *testing.T) { t.Run("non-empty flamegraph result truncation", func(t *testing.T) { m := NewFlameGraphMerger() - s := new(Tree) + s := new(FunctionNameTree) s.InsertStack(1, "foo", "bar") s.InsertStack(1, "foo", "bar", "baz") s.InsertStack(2, "foo", "qux") @@ -149,7 +149,7 @@ func Test_FlameGraphMerger(t *testing.T) { m = NewFlameGraphMerger() m.MergeFlameGraph(fg) - expected := new(Tree) + expected := new(FunctionNameTree) expected.InsertStack(1, "foo", "bar") expected.InsertStack(1, "foo", "bar", "other") expected.InsertStack(2, "foo", "qux") @@ -160,12 +160,12 @@ func Test_FlameGraphMerger(t *testing.T) { t.Run("empty flamegraph", func(t *testing.T) { m := NewFlameGraphMerger() - m.MergeFlameGraph(NewFlameGraph(new(Tree), -1)) - require.Equal(t, new(Tree).String(), m.Tree().String()) + m.MergeFlameGraph(NewFlameGraph(new(FunctionNameTree), -1)) + require.Equal(t, new(FunctionNameTree).String(), m.Tree().String()) }) t.Run("no flamegraphs", func(t *testing.T) { m := NewFlameGraphMerger() - require.Equal(t, new(Tree).String(), m.Tree().String()) + require.Equal(t, new(FunctionNameTree).String(), m.Tree().String()) }) } diff --git a/pkg/model/heatmap/heatmap.go b/pkg/model/heatmap/heatmap.go new file mode 100644 index 0000000000..405bd78c68 --- /dev/null +++ b/pkg/model/heatmap/heatmap.go @@ -0,0 +1,107 @@ +package heatmap + +import ( + "slices" + "strings" + "unique" + + prommodel "github.com/prometheus/common/model" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/attributetable" +) + +type heatmapSeries struct { + labels model.Labels + pointsBuilder *pointsBuilder +} + +type labelKey string + +type Builder struct { + labelBuf []byte + + series map[labelKey]*heatmapSeries // by series + + by []string +} + +func NewBuilder(by []string) *Builder { + return &Builder{ + series: make(map[labelKey]*heatmapSeries), + by: by, + } +} + +func (h *Builder) newSeries(labels model.Labels) *heatmapSeries { + s := &heatmapSeries{ + labels: labels.WithLabels(h.by...), + pointsBuilder: newPointsBuilder(), + } + return s +} + +func (h *Builder) Add(fp prommodel.Fingerprint, labels model.Labels, ts int64, profileID string, spanID uint64, traceID model.TraceID, value int64) { + // TODO: Support annotations + if profileID == "" && spanID == 0 { + return + } + + h.labelBuf = labels.BytesWithLabels(h.labelBuf, h.by...) + seriesKey := labelKey(h.labelBuf) + + series, exists := h.series[seriesKey] + if !exists { + series = h.newSeries(labels) + h.series[seriesKey] = series + } + + pointLabels := labels.WithoutLabels(h.by...) + series.pointsBuilder.add(fp, pointLabels, ts, profileID, spanID, traceID, value) +} + +func (h *Builder) Build(report *queryv1.HeatmapReport) *queryv1.HeatmapReport { + if report == nil { + report = &queryv1.HeatmapReport{} + } + at := attributetable.New() + + var keys []labelKey + for k := range h.series { + keys = append(keys, k) + } + slices.SortFunc(keys, func(a, b labelKey) int { + return strings.Compare(string(a), string(b)) + }) + for _, k := range keys { + series := h.series[k] + + r := &queryv1.HeatmapSeries{} + r.AttributeRefs = at.Refs(series.labels, r.AttributeRefs) + + points := make([]queryv1.HeatmapPoint, series.pointsBuilder.count()) + r.Points = make([]*queryv1.HeatmapPoint, 0, series.pointsBuilder.count()) + idx := 0 + series.pointsBuilder.forEach(func(labels model.Labels, ts int64, profileID string, spanID uint64, traceID model.TraceID, value int64) { + p := &points[idx] + p.AttributeRefs = at.Refs(labels, p.AttributeRefs) + p.Timestamp = ts + p.ProfileId = at.LookupOrAdd(attributetable.Key{Key: unique.Make(""), Value: unique.Make(profileID)}) + p.SpanId = spanID + if traceID != (model.TraceID{}) { + p.TraceId = append(p.TraceId[:0], traceID[:]...) + } + p.Value = value + + r.Points = append(r.Points, p) + idx += 1 + }) + + report.HeatmapSeries = append(report.HeatmapSeries, r) + } + + report.AttributeTable = at.Build(report.AttributeTable) + + return report +} diff --git a/pkg/model/heatmap/heatmap_test.go b/pkg/model/heatmap/heatmap_test.go new file mode 100644 index 0000000000..ab21fcb4e3 --- /dev/null +++ b/pkg/model/heatmap/heatmap_test.go @@ -0,0 +1,757 @@ +package heatmap + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + prommodel "github.com/prometheus/common/model" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +func TestHeatmapBuilder(t *testing.T) { + tests := []struct { + name string + groupBy []string + input []testPoint + expected []testSeries + }{ + { + name: "adds single point", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}, {Name: "pod", Value: "pod1"}}, + timestamp: 1001, + profileID: "profile1", + spanID: 0xa, + value: 1, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}}, + timestamp: 1001, + profileID: "profile1", + spanID: 0xa, + value: 1, + }, + }, + }, + }, + }, + { + name: "adds two points, same series", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}, {Name: "pod", Value: "pod1"}}, + timestamp: 1001, + profileID: "profile1", + spanID: 0xa, + value: 1, + }, + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}, {Name: "pod", Value: "pod1"}}, + timestamp: 1002, + profileID: "profile2", + spanID: 0xb, + value: 2, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}}, + timestamp: 1001, + profileID: "profile1", + spanID: 0xa, + value: 1, + }, + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}}, + timestamp: 1002, + profileID: "profile2", + spanID: 0xb, + value: 2, + }, + }, + }, + }, + }, + { + name: "adds two points, two series", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}, {Name: "pod", Value: "pod1"}}, + timestamp: 1001, + profileID: "profile-1", + spanID: 0xa, + value: 1, + }, + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}, {Name: "pod", Value: "pod2"}}, + timestamp: 1002, + profileID: "profile-2", + spanID: 0xb, + value: 2, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}}, + timestamp: 1001, + profileID: "profile-1", + spanID: 0xa, + value: 1, + }, + }, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod2"}}, + points: []testPoint{ + { + labels: model.Labels{{Name: "namespace", Value: "namespace1"}}, + timestamp: 1002, + profileID: "profile-2", + spanID: 0xb, + value: 2, + }, + }, + }, + }, + }, + { + name: "adds multiple points with different timestamps", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1500, + profileID: "profile1", + spanID: 0xa, + value: 150, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{}, + timestamp: 1500, + profileID: "profile1", + spanID: 0xa, + value: 150, + }, + { + labels: model.Labels{}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + }, + }, + }, + }, + { + name: "merges points with same timestamp, profileID, and spanID", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 50, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 150, + }, + }, + }, + }, + }, + { + name: "handles different series with different fingerprints", + groupBy: []string{"common"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "common", Value: "value"}, {Name: "label1", Value: "value1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "common", Value: "value"}, {Name: "label1", Value: "value2"}, {Name: "random", Value: "stuff"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "common", Value: "value"}}, + points: []testPoint{ + { + // After filtering "common" (groupBy), labels are {label1:value1} and {label1:value2, random:stuff}. + // Intersection yields empty since label1 values differ and random is only in one. + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 300, + }, + }, + }, + }, + }, + { + name: "handles different profileIDs", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile2", + spanID: 0xa, + value: 200, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile2", + spanID: 0xa, + value: 200, + }, + }, + }, + }, + }, + { + name: "handles different spanIDs", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xb, + value: 200, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xb, + value: 200, + }, + }, + }, + }, + }, + { + name: "maintains sorted order with complex insertions", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 3000, + profileID: "profile1", + spanID: 0xa, + value: 300, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 5000, + profileID: "profile1", + spanID: 0xa, + value: 500, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 4000, + profileID: "profile1", + spanID: 0xa, + value: 400, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + { + labels: model.Labels{}, + timestamp: 3000, + profileID: "profile1", + spanID: 0xa, + value: 300, + }, + { + labels: model.Labels{}, + timestamp: 4000, + profileID: "profile1", + spanID: 0xa, + value: 400, + }, + { + labels: model.Labels{}, + timestamp: 5000, + profileID: "profile1", + spanID: 0xa, + value: 500, + }, + }, + }, + }, + }, + { + name: "reuses series when same fingerprint", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 3000, + profileID: "profile1", + spanID: 0xa, + value: 300, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + { + labels: model.Labels{}, + timestamp: 3000, + profileID: "profile1", + spanID: 0xa, + value: 300, + }, + }, + }, + }, + }, + { + name: "handles zero values", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 0, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 0, + }, + }, + }, + }, + }, + { + name: "handles empty labels", + groupBy: []string{}, + input: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + }, + }, + }, + }, + { + name: "handles multiple series with interleaved timestamps", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod2"}}, + timestamp: 1500, + profileID: "profile1", + spanID: 0xa, + value: 150, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod2"}}, + timestamp: 2500, + profileID: "profile1", + spanID: 0xa, + value: 250, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1000, + profileID: "profile1", + spanID: 0xa, + value: 100, + }, + { + labels: model.Labels{}, + timestamp: 2000, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + }, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod2"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1500, + profileID: "profile1", + spanID: 0xa, + value: 150, + }, + { + labels: model.Labels{}, + timestamp: 2500, + profileID: "profile1", + spanID: 0xa, + value: 250, + }, + }, + }, + }, + }, + { + name: "skips points with empty profileID and zero spanID", + groupBy: []string{"pod"}, + input: []testPoint{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1000, + profileID: "", + spanID: 0, + value: 100, + }, + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + timestamp: 1001, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + }, + expected: []testSeries{ + { + labels: model.Labels{{Name: "pod", Value: "pod1"}}, + points: []testPoint{ + { + labels: model.Labels{}, + timestamp: 1001, + profileID: "profile1", + spanID: 0xa, + value: 200, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + builder := NewBuilder(tt.groupBy) + + // Add all input points + for _, p := range tt.input { + fp := prommodel.Fingerprint(p.labels.Hash()) + builder.Add(fp, p.labels, p.timestamp, p.profileID, p.spanID, p.traceID, p.value) + } + + result := builder.Build(nil) + + // Convert result back to testSeries format + actual := resultToTestSeries(result) + + // Compare expected vs actual + require.Len(t, actual, len(tt.expected), "number of series mismatch") + + for i, expectedSeries := range tt.expected { + actualSeries := actual[i] + + // Compare series labels + assert.Equal(t, expectedSeries.labels, actualSeries.labels, + "series %d labels mismatch", i) + + // Compare points + require.Len(t, actualSeries.points, len(expectedSeries.points), + "series %d point count mismatch", i) + + for j, expectedPoint := range expectedSeries.points { + actualPoint := actualSeries.points[j] + + assert.Equal(t, expectedPoint.labels, actualPoint.labels, + "series %d point %d labels mismatch", i, j) + assert.Equal(t, expectedPoint.timestamp, actualPoint.timestamp, + "series %d point %d timestamp mismatch", i, j) + assert.Equal(t, expectedPoint.profileID, actualPoint.profileID, + "series %d point %d profileID mismatch", i, j) + assert.Equal(t, expectedPoint.spanID, actualPoint.spanID, + "series %d point %d spanID mismatch", i, j) + assert.Equal(t, expectedPoint.traceID, actualPoint.traceID, + "series %d point %d traceID mismatch", i, j) + assert.Equal(t, expectedPoint.value, actualPoint.value, + "series %d point %d value mismatch", i, j) + } + } + }) + } +} + +// testPoint represents a test data point +type testPoint struct { + labels model.Labels + timestamp int64 + profileID string + spanID uint64 + traceID model.TraceID + value int64 +} + +// testSeries represents a series with its points for testing +type testSeries struct { + labels model.Labels + points []testPoint +} + +// resultToTestSeries converts a HeatmapReport back to testSeries format for comparison +func resultToTestSeries(report *queryv1.HeatmapReport) []testSeries { + result := make([]testSeries, len(report.HeatmapSeries)) + + for i, series := range report.HeatmapSeries { + // Convert series labels + seriesLabels := make(model.Labels, len(series.AttributeRefs)) + for j, ref := range series.AttributeRefs { + seriesLabels[j] = &typesv1.LabelPair{ + Name: report.AttributeTable.Keys[ref], + Value: report.AttributeTable.Values[ref], + } + } + + // Convert points + points := make([]testPoint, len(series.Points)) + for j, p := range series.Points { + // Convert point labels + pointLabels := make(model.Labels, len(p.AttributeRefs)) + for k, ref := range p.AttributeRefs { + pointLabels[k] = &typesv1.LabelPair{ + Name: report.AttributeTable.Keys[ref], + Value: report.AttributeTable.Values[ref], + } + } + + var traceID model.TraceID + copy(traceID[:], p.TraceId) + points[j] = testPoint{ + labels: pointLabels, + timestamp: p.Timestamp, + profileID: report.AttributeTable.Values[p.ProfileId], + spanID: p.SpanId, + traceID: traceID, + value: p.Value, + } + } + + result[i] = testSeries{ + labels: seriesLabels, + points: points, + } + } + + return result +} diff --git a/pkg/model/heatmap/iterator.go b/pkg/model/heatmap/iterator.go new file mode 100644 index 0000000000..af0ef55555 --- /dev/null +++ b/pkg/model/heatmap/iterator.go @@ -0,0 +1,140 @@ +package heatmap + +import ( + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +// HeatmapValue represents a single heatmap point value +type HeatmapValue struct { + Timestamp int64 + Value int64 + ProfileId int64 + SpanId uint64 + AttributeRefs []int64 +} + +// HeatmapSeriesIterator iterates over points in a heatmap series +type HeatmapSeriesIterator struct { + points []*queryv1.HeatmapPoint + curr HeatmapValue +} + +// NewHeatmapSeriesIterator creates a new iterator for a heatmap series +func NewHeatmapSeriesIterator(points []*queryv1.HeatmapPoint) *HeatmapSeriesIterator { + return &HeatmapSeriesIterator{ + points: points, + } +} + +// Next advances the iterator to the next point +func (it *HeatmapSeriesIterator) Next() bool { + if len(it.points) == 0 { + return false + } + p := it.points[0] + it.points = it.points[1:] + it.curr.Timestamp = p.Timestamp + it.curr.Value = p.Value + it.curr.ProfileId = p.ProfileId + it.curr.SpanId = p.SpanId + it.curr.AttributeRefs = p.AttributeRefs + return true +} + +// At returns the current heatmap value +func (it *HeatmapSeriesIterator) At() HeatmapValue { + return it.curr +} + +// Err returns any error encountered during iteration +func (it *HeatmapSeriesIterator) Err() error { + return nil +} + +// Close closes the iterator +func (it *HeatmapSeriesIterator) Close() error { + return nil +} + +// NewHeatmapReportIterator creates an iterator from multiple heatmap reports +func NewHeatmapReportIterator(reports []*queryv1.HeatmapReport) iter.Iterator[HeatmapValue] { + if len(reports) == 0 { + return iter.NewEmptyIterator[HeatmapValue]() + } + + var iters []iter.Iterator[HeatmapValue] + for _, report := range reports { + if report == nil { + continue + } + for _, series := range report.HeatmapSeries { + if series != nil && len(series.Points) > 0 { + iters = append(iters, NewHeatmapSeriesIterator(series.Points)) + } + } + } + + if len(iters) == 0 { + return iter.NewEmptyIterator[HeatmapValue]() + } + + if len(iters) == 1 { + return iters[0] + } + + // Create a merge iterator that sorts by timestamp, then spanID, then profileID + return newHeatmapMergeIterator(iters...) +} + +func newHeatmapMergeIterator(iters ...iter.Iterator[HeatmapValue]) iter.Iterator[HeatmapValue] { + // For now, return a simple iterator if we only have one + // A full merge iterator implementation would be more complex + if len(iters) == 1 { + return iters[0] + } + + // TODO: Implement proper k-way merge using loser tree + // For now, concatenate iterators (not ideal for sorted merging) + return &concatenatingIterator{iters: iters} +} + +// concatenatingIterator concatenates multiple iterators +type concatenatingIterator struct { + iters []iter.Iterator[HeatmapValue] + current int +} + +func (it *concatenatingIterator) Next() bool { + for it.current < len(it.iters) { + if it.iters[it.current].Next() { + return true + } + it.current++ + } + return false +} + +func (it *concatenatingIterator) At() HeatmapValue { + if it.current < len(it.iters) { + return it.iters[it.current].At() + } + return HeatmapValue{} +} + +func (it *concatenatingIterator) Err() error { + if it.current < len(it.iters) { + return it.iters[it.current].Err() + } + return nil +} + +func (it *concatenatingIterator) Close() error { + var lastErr error + for _, iter := range it.iters { + if err := iter.Close(); err != nil { + lastErr = err + } + } + return lastErr +} diff --git a/pkg/model/heatmap/merger.go b/pkg/model/heatmap/merger.go new file mode 100644 index 0000000000..7c604b1998 --- /dev/null +++ b/pkg/model/heatmap/merger.go @@ -0,0 +1,202 @@ +package heatmap + +import ( + "bytes" + "slices" + "sort" + "strconv" + "strings" + "sync" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model/attributetable" +) + +type Merger struct { + mu sync.Mutex + atMerger *attributetable.Merger + sum bool + series map[string]*atHeatmapSeries +} + +// NewMerger creates a new heatmap merger. If sum is set, points +// with matching timestamps, profileIDs, and spanIDs have their values summed. +func NewMerger(sum bool) *Merger { + return &Merger{ + atMerger: attributetable.NewMerger(), + sum: sum, + series: make(map[string]*atHeatmapSeries), + } +} + +type atHeatmapSeries struct { + attributeRefs []int64 + points []*queryv1.HeatmapPoint +} + +// MergeHeatmap adds a heatmap report to the merger +func (m *Merger) MergeHeatmap(report *queryv1.HeatmapReport) { + m.mu.Lock() + defer m.mu.Unlock() + if report == nil || len(report.HeatmapSeries) == 0 { + return + } + + // Build a mapping from old attribute refs to new attribute refs + m.atMerger.Merge(report.AttributeTable, func(remapper *attributetable.Remapper) { + for _, s := range report.HeatmapSeries { + // Remap the series attribute refs + remappedSeriesRefs := remapper.Refs(s.AttributeRefs) + key := seriesKey(remappedSeriesRefs) + + existing, ok := m.series[key] + if !ok { + existing = &atHeatmapSeries{ + attributeRefs: remappedSeriesRefs, + } + m.series[key] = existing + } + + // Ensure slice is big enough to hold all the points + existing.points = slices.Grow(existing.points, len(s.Points)) + + // Remap and add points + for _, p := range s.Points { + remappedPoint := &queryv1.HeatmapPoint{ + Timestamp: p.Timestamp, + ProfileId: remapper.Ref(p.ProfileId), + SpanId: p.SpanId, + TraceId: p.TraceId, + Value: p.Value, + AttributeRefs: remapper.Refs(p.AttributeRefs), + } + existing.points = append(existing.points, remappedPoint) + } + } + + }) +} + +// IsEmpty returns true if no series have been merged +func (m *Merger) IsEmpty() bool { + m.mu.Lock() + defer m.mu.Unlock() + return len(m.series) == 0 +} + +// Build returns the merged heatmap report +func (m *Merger) Build() *queryv1.HeatmapReport { + m.mu.Lock() + defer m.mu.Unlock() + + if len(m.series) == 0 { + return &queryv1.HeatmapReport{} + } + + report := &queryv1.HeatmapReport{ + HeatmapSeries: make([]*queryv1.HeatmapSeries, 0, len(m.series)), + } + + // Get sorted keys for deterministic output + keys := make([]string, 0, len(m.series)) + for k := range m.series { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, key := range keys { + ms := m.series[key] + heatmapSeries := &queryv1.HeatmapSeries{ + AttributeRefs: ms.attributeRefs, + Points: ms.points[:m.mergePoints(ms.points)], + } + report.HeatmapSeries = append(report.HeatmapSeries, heatmapSeries) + } + + report.AttributeTable = m.atMerger.BuildAttributeTable(report.AttributeTable) + + return report +} + +// seriesKey creates a string key from attribute refs +func seriesKey(refs []int64) string { + var sb strings.Builder + for i, ref := range refs { + if i > 0 { + sb.WriteByte(',') + } + sb.WriteString(strconv.FormatInt(ref, 16)) + } + return sb.String() +} + +// mergePoints merges points with the same timestamp/profileID/spanID/traceID +func (m *Merger) mergePoints(points []*queryv1.HeatmapPoint) int { + l := len(points) + if l < 2 { + return l + } + + // Sort by timestamp, then spanID, traceID, and profileID. + slices.SortFunc(points, func(a, b *queryv1.HeatmapPoint) int { + if a.Timestamp != b.Timestamp { + return int(a.Timestamp - b.Timestamp) + } + if a.SpanId != b.SpanId { + return int(a.SpanId - b.SpanId) + } + if c := bytes.Compare(a.TraceId, b.TraceId); c != 0 { + return c + } + if a.ProfileId != b.ProfileId { + return int(a.ProfileId - b.ProfileId) + } + return 0 + }) + + var j int + for i := 1; i < l; i++ { + // Check if we should merge + if points[j].Timestamp != points[i].Timestamp || + points[j].ProfileId != points[i].ProfileId || + points[j].SpanId != points[i].SpanId || + !bytes.Equal(points[j].TraceId, points[i].TraceId) || + !m.sum { + j++ + points[j] = points[i] + continue + } + + // Sum the values and merge attribute refs + if m.sum { + points[j].Value += points[i].Value + points[j].AttributeRefs = mergeAttributeRefs(points[j].AttributeRefs, points[i].AttributeRefs) + } + } + + return j + 1 +} + +// mergeAttributeRefs merges two attribute ref slices, keeping unique refs +func mergeAttributeRefs(a, b []int64) []int64 { + if len(a) == 0 { + return b + } + if len(b) == 0 { + return a + } + + // Merge and deduplicate + merged := append(append([]int64{}, a...), b...) + slices.Sort(merged) + + j := 0 + for i := 1; i < len(merged); i++ { + if merged[j] != merged[i] { + j++ + merged[j] = merged[i] + } + } + + return merged[:j+1] +} diff --git a/pkg/model/heatmap/merger_test.go b/pkg/model/heatmap/merger_test.go new file mode 100644 index 0000000000..a55282ad89 --- /dev/null +++ b/pkg/model/heatmap/merger_test.go @@ -0,0 +1,60 @@ +package heatmap + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +func TestMerger_DoesNotMergeDifferentTraceIDs(t *testing.T) { + traceID1 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + traceID2 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2} + report := &queryv1.HeatmapReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{""}, + Values: []string{"profile-id"}, + }, + HeatmapSeries: []*queryv1.HeatmapSeries{{ + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, ProfileId: 0, SpanId: 123, TraceId: traceID1, Value: 1000}, + {Timestamp: 100, ProfileId: 0, SpanId: 123, TraceId: traceID2, Value: 2000}, + }, + }}, + } + + merger := NewMerger(true) + merger.MergeHeatmap(report) + result := merger.Build() + + require.Len(t, result.HeatmapSeries, 1) + require.Len(t, result.HeatmapSeries[0].Points, 2) + assert.Equal(t, traceID1, result.HeatmapSeries[0].Points[0].TraceId) + assert.Equal(t, traceID2, result.HeatmapSeries[0].Points[1].TraceId) +} + +func TestMerger_MergesMatchingTraceIDs(t *testing.T) { + traceID := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + report := &queryv1.HeatmapReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{""}, + Values: []string{"profile-id"}, + }, + HeatmapSeries: []*queryv1.HeatmapSeries{{ + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, ProfileId: 0, SpanId: 123, TraceId: traceID, Value: 1000}, + {Timestamp: 100, ProfileId: 0, SpanId: 123, TraceId: traceID, Value: 2000}, + }, + }}, + } + + merger := NewMerger(true) + merger.MergeHeatmap(report) + result := merger.Build() + + require.Len(t, result.HeatmapSeries, 1) + require.Len(t, result.HeatmapSeries[0].Points, 1) + assert.Equal(t, int64(3000), result.HeatmapSeries[0].Points[0].Value) +} diff --git a/pkg/model/heatmap/points_builder.go b/pkg/model/heatmap/points_builder.go new file mode 100644 index 0000000000..a9b0b0be74 --- /dev/null +++ b/pkg/model/heatmap/points_builder.go @@ -0,0 +1,116 @@ +package heatmap + +import ( + "bytes" + "slices" + "strings" + + prommodel "github.com/prometheus/common/model" + + "github.com/grafana/pyroscope/v2/pkg/model" +) + +// pointsBuilder builds exemplars for a single time series. +type pointsBuilder struct { + labelSetIndex map[uint64]int + labelSets []model.Labels + exemplars []exemplar +} + +type exemplar struct { + timestamp int64 + profileID string + spanID uint64 + traceID model.TraceID + labelSetRef int + value int64 +} + +// newPointsBuilder creates a new pointsBuilder. +func newPointsBuilder() *pointsBuilder { + return &pointsBuilder{ + labelSetIndex: make(map[uint64]int), + labelSets: make([]model.Labels, 0), + exemplars: make([]exemplar, 0), + } +} + +// Add adds an exemplar with its full labels. +func (pb *pointsBuilder) add(fp prommodel.Fingerprint, labels model.Labels, ts int64, profileID string, spanID uint64, traceID model.TraceID, value int64) { + if profileID == "" && spanID == 0 { + return + } + + e := exemplar{ + timestamp: ts, + profileID: profileID, + spanID: spanID, + traceID: traceID, + value: value, + } + + labelSetIdx, labelSetExists := pb.labelSetIndex[uint64(fp)] + + pos, exemplarExists := slices.BinarySearchFunc(pb.exemplars, e, cmpExemplar) + if exemplarExists { + matched := &pb.exemplars[pos] + // add my value + matched.value += e.value + + // check if label set matches + if labelSetExists && labelSetIdx == matched.labelSetRef { + return + } + + // build intersected label set, they are cloned so this is possible to do + pb.labelSets[matched.labelSetRef] = pb.labelSets[matched.labelSetRef].Intersect(labels) + + // point to new label set + pb.labelSetIndex[uint64(fp)] = matched.labelSetRef + + return + } + + if !labelSetExists { + e.labelSetRef = len(pb.labelSets) + pb.labelSets = append(pb.labelSets, labels.Clone()) + pb.labelSetIndex[uint64(fp)] = e.labelSetRef + } else { + // Use the existing label set for this fingerprint, but intersect with new labels + // This ensures only common labels across all exemplars with this fingerprint are kept + e.labelSetRef = labelSetIdx + pb.labelSets[e.labelSetRef] = pb.labelSets[e.labelSetRef].Intersect(labels) + } + + pb.exemplars = slices.Insert(pb.exemplars, pos, e) +} + +func cmpExemplar(a, b exemplar) int { + if a.timestamp < b.timestamp { + return -1 + } + if a.timestamp > b.timestamp { + return 1 + } + if a.spanID < b.spanID { + return -1 + } + if a.spanID > b.spanID { + return 1 + } + if c := bytes.Compare(a.traceID[:], b.traceID[:]); c != 0 { + return c + } + return strings.Compare(a.profileID, b.profileID) +} + +func (pb *pointsBuilder) forEach(f func(labels model.Labels, ts int64, profileID string, spanID uint64, traceID model.TraceID, value int64)) { + for _, exemplar := range pb.exemplars { + f(pb.labelSets[exemplar.labelSetRef], exemplar.timestamp, exemplar.profileID, exemplar.spanID, exemplar.traceID, exemplar.value) + } +} + +// Count returns the number of raw exemplars added. +func (pb *pointsBuilder) count() int { + return len(pb.exemplars) +} diff --git a/pkg/model/heatmap/points_builder_test.go b/pkg/model/heatmap/points_builder_test.go new file mode 100644 index 0000000000..19c5708c7f --- /dev/null +++ b/pkg/model/heatmap/points_builder_test.go @@ -0,0 +1,220 @@ +package heatmap + +import ( + "testing" + + "github.com/prometheus/common/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + pkgmodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +func TestPointsBuilder_SameFingerprintDifferentExemplars(t *testing.T) { + // Test that when multiple exemplars have the same fingerprint but different + // timestamps/profileIDs/spanIDs, they share a labelSet with only common labels + pb := newPointsBuilder() + + // Create labels with the same fingerprint but different values + commonLabels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + &typesv1.LabelPair{Name: "cluster", Value: "prod"}, + } + + labels1 := append(commonLabels, &typesv1.LabelPair{Name: "instance", Value: "host1"}) + labels2 := append(commonLabels, &typesv1.LabelPair{Name: "instance", Value: "host2"}) + labels3 := append(commonLabels, &typesv1.LabelPair{Name: "instance", Value: "host3"}) + + // All should have the same fingerprint (only common labels) + fp := model.Fingerprint(commonLabels.Hash()) + + // Add three exemplars with the same fingerprint but different timestamps + pb.add(fp, labels1, 100, "profile1", 0, pkgmodel.TraceID{}, 1000) + pb.add(fp, labels2, 200, "profile2", 0, pkgmodel.TraceID{}, 2000) + pb.add(fp, labels3, 300, "profile3", 0, pkgmodel.TraceID{}, 3000) + + // Verify we have 3 exemplars + assert.Equal(t, 3, pb.count()) + + // Verify they all share the same labelSet (only common labels) + var collectedLabels []pkgmodel.Labels + pb.forEach(func(labels pkgmodel.Labels, ts int64, profileID string, spanID uint64, traceID pkgmodel.TraceID, value int64) { + collectedLabels = append(collectedLabels, labels) + }) + + require.Len(t, collectedLabels, 3) + + // All exemplars should have the same labelSet with only common labels + expectedCommonLabels := commonLabels + for i, labels := range collectedLabels { + assert.Equal(t, expectedCommonLabels, labels, + "Exemplar %d should have only common labels", i) + } +} + +func TestPointsBuilder_DuplicateExemplarsSum(t *testing.T) { + // Test that duplicate exemplars (same timestamp/profileID/spanID) have their values summed + pb := newPointsBuilder() + + labels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + &typesv1.LabelPair{Name: "cluster", Value: "prod"}, + } + fp := model.Fingerprint(labels.Hash()) + + // Add the same exemplar 3 times + pb.add(fp, labels, 100, "profile1", 123, pkgmodel.TraceID{}, 1000) + pb.add(fp, labels, 100, "profile1", 123, pkgmodel.TraceID{}, 2000) + pb.add(fp, labels, 100, "profile1", 123, pkgmodel.TraceID{}, 3000) + + // Should only have 1 exemplar with summed value + assert.Equal(t, 1, pb.count()) + + var totalValue int64 + pb.forEach(func(labels pkgmodel.Labels, ts int64, profileID string, spanID uint64, traceID pkgmodel.TraceID, value int64) { + totalValue = value + }) + + assert.Equal(t, int64(6000), totalValue, "Values should be summed") +} + +func TestPointsBuilder_SameSpanDifferentTraceIDs(t *testing.T) { + pb := newPointsBuilder() + labels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + } + fp := model.Fingerprint(labels.Hash()) + traceID1 := pkgmodel.TraceID{15: 1} + traceID2 := pkgmodel.TraceID{15: 2} + + pb.add(fp, labels, 100, "profile1", 123, traceID1, 1000) + pb.add(fp, labels, 100, "profile1", 123, traceID2, 2000) + + require.Equal(t, 2, pb.count()) + var traceIDs []pkgmodel.TraceID + pb.forEach(func(labels pkgmodel.Labels, ts int64, profileID string, spanID uint64, traceID pkgmodel.TraceID, value int64) { + traceIDs = append(traceIDs, traceID) + }) + assert.Equal(t, []pkgmodel.TraceID{traceID1, traceID2}, traceIDs) +} + +func TestPointsBuilder_LabelIntersection(t *testing.T) { + // Test that when exemplars with the same fingerprint have different labels, + // only the intersection is kept + pb := newPointsBuilder() + + labels1 := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + &typesv1.LabelPair{Name: "cluster", Value: "prod"}, + &typesv1.LabelPair{Name: "instance", Value: "host1"}, + &typesv1.LabelPair{Name: "pod", Value: "pod-1"}, + } + + labels2 := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + &typesv1.LabelPair{Name: "cluster", Value: "prod"}, + &typesv1.LabelPair{Name: "instance", Value: "host2"}, + &typesv1.LabelPair{Name: "node", Value: "node-1"}, + } + + labels3 := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + &typesv1.LabelPair{Name: "cluster", Value: "prod"}, + &typesv1.LabelPair{Name: "node", Value: "node-2"}, + } + + // Use the same fingerprint for all (simulating same series) + fp := model.Fingerprint(12345) + + // Add exemplars with different labels + pb.add(fp, labels1, 100, "profile1", 0, pkgmodel.TraceID{}, 1000) + pb.add(fp, labels2, 200, "profile2", 0, pkgmodel.TraceID{}, 2000) + pb.add(fp, labels3, 300, "profile3", 0, pkgmodel.TraceID{}, 3000) + + // Verify we have 3 exemplars + assert.Equal(t, 3, pb.count()) + + // All should share the same labelSet with only common labels (service, cluster) + expectedCommonLabels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + &typesv1.LabelPair{Name: "cluster", Value: "prod"}, + } + + pb.forEach(func(labels pkgmodel.Labels, ts int64, profileID string, spanID uint64, traceID pkgmodel.TraceID, value int64) { + assert.Equal(t, expectedCommonLabels, labels, + "Should only contain labels common to all exemplars") + }) +} + +func TestPointsBuilder_EmptyProfileIDAndSpanID(t *testing.T) { + // Test that exemplars with empty profileID and zero spanID are not added + pb := newPointsBuilder() + + labels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + } + fp := model.Fingerprint(labels.Hash()) + + // Try to add exemplar with empty profileID and zero spanID + pb.add(fp, labels, 100, "", 0, pkgmodel.TraceID{}, 1000) + + // Should have no exemplars + assert.Equal(t, 0, pb.count()) +} + +func TestPointsBuilder_OnlyProfileID(t *testing.T) { + // Test that exemplars with only profileID (no spanID) are added + pb := newPointsBuilder() + + labels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + } + fp := model.Fingerprint(labels.Hash()) + + pb.add(fp, labels, 100, "profile1", 0, pkgmodel.TraceID{}, 1000) + + // Should have 1 exemplar + assert.Equal(t, 1, pb.count()) +} + +func TestPointsBuilder_OnlySpanID(t *testing.T) { + // Test that exemplars with only spanID (no profileID) are added + pb := newPointsBuilder() + + labels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + } + fp := model.Fingerprint(labels.Hash()) + + pb.add(fp, labels, 100, "", 123, pkgmodel.TraceID{}, 1000) + + // Should have 1 exemplar + assert.Equal(t, 1, pb.count()) +} + +func TestPointsBuilder_Sorting(t *testing.T) { + // Test that exemplars are sorted by timestamp, then spanID, then profileID + pb := newPointsBuilder() + + labels := pkgmodel.Labels{ + &typesv1.LabelPair{Name: "service", Value: "api"}, + } + fp := model.Fingerprint(labels.Hash()) + + // Add exemplars in non-sorted order + pb.add(fp, labels, 300, "profile3", 0, pkgmodel.TraceID{}, 3000) + pb.add(fp, labels, 100, "profile1", 0, pkgmodel.TraceID{}, 1000) + pb.add(fp, labels, 200, "profile2", 0, pkgmodel.TraceID{}, 2000) + + // Verify they come out sorted + var timestamps []int64 + pb.forEach(func(labels pkgmodel.Labels, ts int64, profileID string, spanID uint64, traceID pkgmodel.TraceID, value int64) { + timestamps = append(timestamps, ts) + }) + + require.Len(t, timestamps, 3) + assert.Equal(t, int64(100), timestamps[0]) + assert.Equal(t, int64(200), timestamps[1]) + assert.Equal(t, int64(300), timestamps[2]) +} diff --git a/pkg/model/heatmap/range.go b/pkg/model/heatmap/range.go new file mode 100644 index 0000000000..8ca2664b20 --- /dev/null +++ b/pkg/model/heatmap/range.go @@ -0,0 +1,252 @@ +package heatmap + +import ( + "math" + "sort" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model/attributetable" +) + +const ( + // DefaultYAxisBuckets is the default number of Y-axis buckets + DefaultYAxisBuckets = 20 +) + +// RangeHeatmap buckets heatmap points into time/value buckets for visualization +// Each input series produces a separate output series with labels preserved +// Y-axis buckets are calculated based on global min/max across all series +func RangeHeatmap( + reports []*queryv1.HeatmapReport, + start, end, step int64, + exemplarType typesv1.ExemplarType, +) []*typesv1.HeatmapSeries { + if len(reports) == 0 { + return nil + } + + // First pass: collect all series with their labels and find global min/max + type seriesData struct { + series *queryv1.HeatmapSeries + labels []*typesv1.LabelPair + } + var allSeries []seriesData + var globalMinValue, globalMaxValue int64 = math.MaxInt64, 0 + + for _, report := range reports { + if report == nil { + continue + } + + for _, series := range report.HeatmapSeries { + if series == nil || len(series.Points) == 0 { + continue + } + + // Resolve labels from attribute refs + labels := attributetable.ResolveLabelPairs(series.AttributeRefs, report.AttributeTable) + + // Track this series + allSeries = append(allSeries, seriesData{ + series: series, + labels: labels, + }) + + // Update global min/max + for _, point := range series.Points { + if point == nil { + continue + } + if point.Value < globalMinValue { + globalMinValue = point.Value + } + if point.Value > globalMaxValue { + globalMaxValue = point.Value + } + } + } + } + + if len(allSeries) == 0 || globalMinValue == math.MaxInt64 { + return nil + } + + // Handle edge case where all values are the same + if globalMinValue == globalMaxValue { + globalMaxValue = globalMinValue + 1 + } + + // Create Y-axis bucket boundaries based on global min/max + yBuckets := createYAxisBuckets(globalMinValue, globalMaxValue, DefaultYAxisBuckets) + + // Check if exemplars should be included + includeExemplars := exemplarType != typesv1.ExemplarType_EXEMPLAR_TYPE_NONE && + exemplarType != typesv1.ExemplarType_EXEMPLAR_TYPE_UNSPECIFIED + + // Get attribute table from first report for exemplar conversion + var attributeTable *queryv1.AttributeTable + if includeExemplars { + for _, report := range reports { + if report != nil && report.AttributeTable != nil { + attributeTable = report.AttributeTable + break + } + } + } + + // Second pass: process each series with the shared Y-axis buckets + var result []*typesv1.HeatmapSeries + + for _, sd := range allSeries { + // Create a map to track counts per (time, y-bucket) + type cellKey struct { + ts int64 + yIdx int + } + cellCounts := make(map[cellKey]int32) + cellBestPoint := make(map[cellKey]*queryv1.HeatmapPoint) // Track best exemplar per cell + + // First pass: count and track best exemplar per cell + for _, point := range sd.series.Points { + if point == nil { + continue + } + + // normalize timestamp + ts := normalizeTimestamp(point.Timestamp, start, end, step) + + // Find value bucket + yIdx := findValueBucket(point.Value, yBuckets) + if yIdx < 0 { + continue + } + + cell := cellKey{ts, yIdx} + cellCounts[cell]++ + + // Track highest-value point for this cell (for exemplar) + if includeExemplars { + if existing := cellBestPoint[cell]; existing == nil || point.Value > existing.Value { + cellBestPoint[cell] = point + } + } + } + + // Second pass: build slots with counts and exemplars + slotsMap := make(map[int64]*typesv1.HeatmapSlot) + for cell, count := range cellCounts { + timestamp := cell.ts + slot, ok := slotsMap[timestamp] + if !ok { + slot = &typesv1.HeatmapSlot{ + Timestamp: timestamp, + YMin: make([]float64, len(yBuckets)), + Counts: make([]int32, len(yBuckets)), + } + if includeExemplars { + slot.Exemplars = make([]*typesv1.Exemplar, 0, len(yBuckets)) + } + // Initialize Y bucket minimums + for i, bucket := range yBuckets { + slot.YMin[i] = float64(bucket.min) + } + slotsMap[timestamp] = slot + } + slot.Counts[cell.yIdx] = count + + // Attach exemplar for this Y-bucket + if includeExemplars { + if bestPoint := cellBestPoint[cell]; bestPoint != nil { + e := attributetable.ResolveHeatmapExemplar(bestPoint, attributeTable) + if e != nil { + slot.Exemplars = append(slot.Exemplars, e) + } + } + } + } + + // Convert map to sorted slice + var slots []*typesv1.HeatmapSlot + for _, slot := range slotsMap { + slots = append(slots, slot) + } + sort.Slice(slots, func(i, j int) bool { + return slots[i].Timestamp < slots[j].Timestamp + }) + + // Add this series to the result with its labels preserved + result = append(result, &typesv1.HeatmapSeries{ + Labels: sd.labels, + Slots: slots, + }) + } + + return result +} + +// yBucket represents a Y-axis bucket +type yBucket struct { + min int64 + max int64 +} + +// createYAxisBuckets creates evenly spaced Y-axis buckets +func createYAxisBuckets(minValue, maxValue int64, numBuckets int) []yBucket { + buckets := make([]yBucket, numBuckets) + valueRange := float64(maxValue - minValue) + bucketSize := valueRange / float64(numBuckets) + + for i := 0; i < numBuckets; i++ { + buckets[i] = yBucket{ + min: minValue + int64(float64(i)*bucketSize), + max: minValue + int64(float64(i+1)*bucketSize), + } + } + + // Ensure the last bucket includes the max value + buckets[numBuckets-1].max = maxValue + + return buckets +} + +func roundUpTimestamp(timestamp, start, step int64) int64 { + startMod := start % step + timestamp -= startMod + if timestamp%step != 0 { + timestamp = ((timestamp / step) + 1) * step + } + return timestamp + startMod +} + +// normalizeTimestamp calculates the timestamp (xMax) of the bucket the timestamp falls into. +// The buckets range from: +// (start-step, start], (start, start+step], (start+step, start+2*step], ... +func normalizeTimestamp(timestamp, start, end, step int64) int64 { + timestamp = roundUpTimestamp(timestamp, start, step) + end = roundUpTimestamp(end, start, step) + + if timestamp < start { + return start + } + + if timestamp > end { + return end + } + + return timestamp +} + +// findValueBucket finds the index of the Y-axis bucket for a given value +func findValueBucket(value int64, buckets []yBucket) int { + for i, bucket := range buckets { + if value >= bucket.min && value < bucket.max { + return i + } + } + // If value is at or beyond the last bucket max, put it in the last bucket + if len(buckets) > 0 && value >= buckets[len(buckets)-1].min { + return len(buckets) - 1 + } + return -1 +} diff --git a/pkg/model/heatmap/range_test.go b/pkg/model/heatmap/range_test.go new file mode 100644 index 0000000000..5924ca39e7 --- /dev/null +++ b/pkg/model/heatmap/range_test.go @@ -0,0 +1,458 @@ +package heatmap + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +func TestRangeHeatmap_EmptyInput(t *testing.T) { + series := RangeHeatmap(nil, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + assert.Nil(t, series) +} + +func TestRangeHeatmap_EmptyReport(t *testing.T) { + reports := []*queryv1.HeatmapReport{{}} + series := RangeHeatmap(reports, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + assert.Nil(t, series) +} + +func TestRangeHeatmap_SpanExemplarIncludesTraceID(t *testing.T) { + traceID := []byte{0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36} + reports := []*queryv1.HeatmapReport{{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{""}, + Values: []string{"profile-id"}, + }, + HeatmapSeries: []*queryv1.HeatmapSeries{{ + Points: []*queryv1.HeatmapPoint{{ + Timestamp: 500, + ProfileId: 0, + SpanId: 0x0102030405060708, + TraceId: traceID, + Value: 1000, + }}, + }}, + }} + + series := RangeHeatmap(reports, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_SPAN) + require.Len(t, series, 1) + require.Len(t, series[0].Slots, 1) + require.Len(t, series[0].Slots[0].Exemplars, 1) + exemplar := series[0].Slots[0].Exemplars[0] + assert.Equal(t, "4bf92f3577b34da6a3ce929d0e0e4736", exemplar.TraceId) + assert.Equal(t, "0807060504030201", exemplar.SpanId) +} + +func TestRangeHeatmap_SinglePoint(t *testing.T) { + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + { + Timestamp: 500, + Value: 1000, + }, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 1) + + // Should have at least one slot + require.NotEmpty(t, series[0].Slots) + + // Verify slot structure + slot := series[0].Slots[0] + assert.Equal(t, int64(500), slot.Timestamp) + assert.Len(t, slot.YMin, DefaultYAxisBuckets) + assert.Len(t, slot.Counts, DefaultYAxisBuckets) + + // At least one bucket should have a count + totalCount := int32(0) + for _, count := range slot.Counts { + totalCount += count + } + assert.Greater(t, totalCount, int32(0), "Expected at least one bucket to have a count") +} + +func TestRangeHeatmap_MultiplePoints_SameTimeBucket(t *testing.T) { + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 1000}, + {Timestamp: 150, Value: 1500}, + {Timestamp: 180, Value: 2000}, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 200, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 1) + + // All points should fall into one time bucket + require.Len(t, series[0].Slots, 1) + + slot := series[0].Slots[0] + + // Should have counts in multiple Y buckets (values are spread: 1000, 1500, 2000) + nonZeroBuckets := 0 + totalCount := int32(0) + for _, count := range slot.Counts { + if count > 0 { + nonZeroBuckets++ + totalCount += count + } + } + assert.Equal(t, nonZeroBuckets, 3, "Expected three bucket with counts") + assert.Equal(t, int32(3), totalCount, "Expected total count to match number of points") +} + +func TestRangeHeatmap_MultiplePoints_DifferentTimeBuckets(t *testing.T) { + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 1000}, + {Timestamp: 300, Value: 1500}, + {Timestamp: 500, Value: 2000}, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 200, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 1) + + // Points should fall into different time buckets + require.GreaterOrEqual(t, len(series[0].Slots), 2, "Expected at least 2 time buckets") + + // Verify slots are sorted by timestamp + for i := 1; i < len(series[0].Slots); i++ { + assert.Less(t, series[0].Slots[i-1].Timestamp, series[0].Slots[i].Timestamp, + "Slots should be sorted by timestamp") + } + + // Each slot should have the correct structure + for _, slot := range series[0].Slots { + assert.Len(t, slot.YMin, DefaultYAxisBuckets) + assert.Len(t, slot.Counts, DefaultYAxisBuckets) + } +} + +func TestRangeHeatmap_AllSameValue(t *testing.T) { + // Test edge case where all values are the same + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 1000}, + {Timestamp: 200, Value: 1000}, + {Timestamp: 300, Value: 1000}, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 200, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 1) + + // Should still create buckets even with identical values + require.NotEmpty(t, series[0].Slots) + + // All counts should be in the same Y bucket + for _, slot := range series[0].Slots { + nonZeroBuckets := 0 + for _, count := range slot.Counts { + if count > 0 { + nonZeroBuckets++ + } + } + // With identical values, they should all fall into the same Y bucket + assert.LessOrEqual(t, nonZeroBuckets, 2, + "With identical values, counts should be in at most 2 adjacent buckets") + } +} + +func TestRangeHeatmap_YBucketBoundaries(t *testing.T) { + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 0}, + {Timestamp: 100, Value: 10000}, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 1) + require.NotEmpty(t, series[0].Slots) + + slot := series[0].Slots[0] + + // Verify Y bucket boundaries are monotonically increasing + for i := 1; i < len(slot.YMin); i++ { + assert.Less(t, slot.YMin[i-1], slot.YMin[i], + "Y bucket boundaries should be monotonically increasing") + } + + // First bucket should start near the minimum value + assert.LessOrEqual(t, slot.YMin[0], 100.0, + "First Y bucket should start at or near minimum value") +} + +func TestRangeHeatmap_MultipleReports(t *testing.T) { + // Test that data from multiple reports produces separate series (not merged) + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 1000}, + {Timestamp: 200, Value: 2000}, + }, + }, + }, + }, + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 200, Value: 1500}, + {Timestamp: 300, Value: 2500}, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + // Each input series should produce a separate output series + require.Len(t, series, 2) + + // Verify first series has 2 points + totalCount1 := int32(0) + for _, slot := range series[0].Slots { + for _, count := range slot.Counts { + totalCount1 += count + } + } + assert.Equal(t, int32(2), totalCount1, "Expected first series to have 2 points") + + // Verify second series has 2 points + totalCount2 := int32(0) + for _, slot := range series[1].Slots { + for _, count := range slot.Counts { + totalCount2 += count + } + } + assert.Equal(t, int32(2), totalCount2, "Expected second series to have 2 points") +} + +func TestRangeHeatmap_LabelsPreserved(t *testing.T) { + // Test that labels are correctly resolved and preserved per series + // AttributeTable has parallel arrays: Keys[i] and Values[i] form a label pair + reports := []*queryv1.HeatmapReport{ + { + AttributeTable: &queryv1.AttributeTable{ + // Index 0: service=api + // Index 1: environment=production + // Index 2: service=web + // Index 3: environment=staging + Keys: []string{"service", "environment", "service", "environment"}, + Values: []string{"api", "production", "web", "staging"}, + }, + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + AttributeRefs: []int64{0, 1}, // refs to: service=api, environment=production + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 1000}, + }, + }, + { + AttributeRefs: []int64{2, 3}, // refs to: service=web, environment=staging + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 2000}, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 2, "Expected one series per input series") + + // Verify first series labels + require.Len(t, series[0].Labels, 2) + assert.Equal(t, "service", series[0].Labels[0].Name) + assert.Equal(t, "api", series[0].Labels[0].Value) + assert.Equal(t, "environment", series[0].Labels[1].Name) + assert.Equal(t, "production", series[0].Labels[1].Value) + + // Verify second series labels + require.Len(t, series[1].Labels, 2) + assert.Equal(t, "service", series[1].Labels[0].Name) + assert.Equal(t, "web", series[1].Labels[0].Value) + assert.Equal(t, "environment", series[1].Labels[1].Name) + assert.Equal(t, "staging", series[1].Labels[1].Value) +} + +func TestRangeHeatmap_NoLabels(t *testing.T) { + // Test that series without attribute refs work correctly + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 100, Value: 1000}, + }, + }, + }, + }, + } + + series := RangeHeatmap(reports, 0, 1000, 100, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 1) + + // Series should have no labels + assert.Nil(t, series[0].Labels) +} + +func TestRangeHeatmap_TimeBucketAlignment(t *testing.T) { + reports := []*queryv1.HeatmapReport{ + { + HeatmapSeries: []*queryv1.HeatmapSeries{ + { + Points: []*queryv1.HeatmapPoint{ + {Timestamp: 50, Value: 1000}, + {Timestamp: 250, Value: 2000}, + {Timestamp: 450, Value: 3000}, + }, + }, + }, + }, + } + + step := int64(200) + series := RangeHeatmap(reports, 0, 600, step, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE) + require.NotNil(t, series) + require.Len(t, series, 1) + + // Verify each slot timestamp aligns with the step + for _, slot := range series[0].Slots { + assert.True(t, slot.Timestamp >= 0 && slot.Timestamp <= 600, + "Slot timestamp should be within range") + } +} + +func TestNormalizeTimestamp(t *testing.T) { + tests := []struct { + name string + timestamp int64 + start int64 + end int64 + step int64 + want int64 + }{ + { + name: "timestamp before start - clamped to start", + timestamp: 50, + start: 200, + end: 1000, + step: 100, + want: 200, // clamped to start + }, + { + name: "timestamp at start", + timestamp: 100, + start: 100, + end: 1000, + step: 100, + want: 100, // (100-100) + ((100-100)%100) + 100 = 0 + 0 + 100 = 100 + }, + { + name: "timestamp in first bucket", + timestamp: 150, + start: 100, + end: 1000, + step: 100, + want: 200, + }, + { + name: "timestamp at second bucket boundary", + timestamp: 200, + start: 100, + end: 1000, + step: 100, + want: 200, + }, + { + name: "timestamp in middle bucket", + timestamp: 550, + start: 100, + end: 1000, + step: 100, + want: 600, + }, + { + name: "timestamp at end", + timestamp: 1000, + start: 100, + end: 1000, + step: 100, + want: 1000, + }, + { + name: "timestamp after end - clamped to end", + timestamp: 1001, + start: 100, + end: 1000, + step: 100, + want: 1000, // clamped to end + }, + { + name: "timestamp with odd start", + timestamp: 180, + start: 12, + end: 1000, + step: 200, + want: 212, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := normalizeTimestamp(tt.timestamp, tt.start, tt.end, tt.step) + assert.Equal(t, tt.want, got, "normalizeTimestamp(ts=%d, start=%d, end=%d, step=%d) = %d, want %d", + tt.timestamp, tt.start, tt.end, tt.step, got, tt.want) + }) + } +} diff --git a/pkg/model/heatmap/top.go b/pkg/model/heatmap/top.go new file mode 100644 index 0000000000..134e1fa44c --- /dev/null +++ b/pkg/model/heatmap/top.go @@ -0,0 +1,46 @@ +package heatmap + +import ( + "cmp" + "slices" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +// TopSeries returns the top k heatmap series by sum of counts. +func TopSeries(s []*typesv1.HeatmapSeries, k int) []*typesv1.HeatmapSeries { + if k <= 0 || len(s) <= k { + return s + } + + type series struct { + *typesv1.HeatmapSeries + sum int64 + } + + aggregated := make([]series, len(s)) + for i, x := range s { + var sum int64 + for _, slot := range x.Slots { + for _, count := range slot.Counts { + sum += int64(count) + } + } + aggregated[i] = series{HeatmapSeries: x, sum: sum} + } + + slices.SortFunc(aggregated, func(a, b series) int { + c := cmp.Compare(a.sum, b.sum) + if c == 0 { + return model.CompareLabelPairs(a.Labels, b.Labels) + } + return -c // Descending order + }) + + for i, a := range aggregated { + s[i] = a.HeatmapSeries + } + + return s[:k] +} diff --git a/pkg/model/labels.go b/pkg/model/labels.go index b4dd84f5c1..528123eccc 100644 --- a/pkg/model/labels.go +++ b/pkg/model/labels.go @@ -13,34 +13,55 @@ import ( "github.com/cespare/xxhash/v2" pmodel "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/promql/parser" + semconv "go.opentelemetry.io/otel/semconv/v1.27.0" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) -var seps = []byte{'\xff'} +var ( + seps = []byte{'\xff'} + promParser = parser.NewParser(parser.Options{}) +) + +// ParseMetricSelector parses the provided textual metric selector into a +// list of label matchers. +func ParseMetricSelector(input string) ([]*labels.Matcher, error) { + return promParser.ParseMetricSelector(input) +} const ( LabelNameProfileType = "__profile_type__" LabelNameServiceNamePrivate = "__service_name__" LabelNameDelta = "__delta__" + LabelNameOTEL = "__otel__" LabelNameProfileName = pmodel.MetricNameLabel LabelNamePeriodType = "__period_type__" LabelNamePeriodUnit = "__period_unit__" LabelNameSessionID = "__session_id__" LabelNameType = "__type__" LabelNameUnit = "__unit__" + LabelNameSampled = "__sampled__" LabelNameServiceGitRef = "service_git_ref" LabelNameServiceName = "service_name" LabelNameServiceRepository = "service_repository" + LabelNameServiceRootPath = "service_root_path" LabelNameOrder = "__order__" LabelOrderEnforced = "enforced" LabelNamePyroscopeSpy = "pyroscope_spy" + AttrProcessExecutableName = semconv.ProcessExecutableNameKey + + AttrServiceName = semconv.ServiceNameKey + AttrServiceNameFallback = "unknown_service" + labelSep = '\xfe' + + ProfileNameOffCpu = "off_cpu" // todo better name? ) // Labels is a sorted set of labels. Order has to be guaranteed upon @@ -51,6 +72,18 @@ func (ls Labels) Len() int { return len(ls) } func (ls Labels) Swap(i, j int) { ls[i], ls[j] = ls[j], ls[i] } func (ls Labels) Less(i, j int) bool { return ls[i].Name < ls[j].Name } +// Range calls f on each label. +func (ls Labels) Range(f func(l *typesv1.LabelPair)) { + for _, l := range ls { + f(l) + } +} + +// EmptyLabels returns n empty Labels value, for convenience. +func EmptyLabels() Labels { + return Labels{} +} + // LabelsEnforcedOrder is a sort order of labels, where profile type and // service name labels always go first. This is crucial for query performance // as labels determine the physical order of the profiling data. @@ -127,7 +160,7 @@ func (ls Labels) ToPrometheusLabels() labels.Labels { for i, l := range ls { res[i] = labels.Label{Name: l.Name, Value: l.Value} } - return res + return labels.New(res...) } func (ls Labels) WithoutPrivateLabels() Labels { @@ -197,6 +230,52 @@ func (ls Labels) Delete(name string) Labels { return ls } +func (ls Labels) Subtract(labels Labels) Labels { + var i, j, k int + for i < len(ls) && j < len(labels) { + cmp := CompareLabelPairs2(ls[i], labels[j]) + switch { + case cmp == 0: + i++ + j++ + case cmp < 0: + if i != k { + ls[k] = ls[i] + } + k++ + i++ + default: + j++ + } + } + for i < len(ls) { + if i != k { + ls[k] = ls[i] + } + k++ + i++ + } + return ls[:k] +} + +func (ls Labels) Intersect(labels Labels) Labels { + var i, j, k int + for i < len(ls) && j < len(labels) { + cmp := CompareLabelPairs2(ls[i], labels[j]) + if cmp == 0 { + ls[k] = ls[i] + k++ + i++ + j++ + } else if cmp < 0 { + i++ + } else { + j++ + } + } + return ls[:k] +} + // InsertSorted adds the given label to the set of labels. // It assumes the labels are sorted lexicographically. func (ls Labels) InsertSorted(name, value string) Labels { @@ -274,6 +353,16 @@ func LabelPairsString(lbs []*typesv1.LabelPair) string { return b.String() } +// LabelsFromMap returns new sorted Labels from the given map. +func LabelsFromMap(m map[string]string) Labels { + res := make(Labels, 0, len(m)) + for k, v := range m { + res = append(res, &typesv1.LabelPair{Name: k, Value: v}) + } + sort.Sort(res) + return res +} + // LabelsFromStrings creates new labels from pairs of strings. func LabelsFromStrings(ss ...string) Labels { if len(ss)%2 != 0 { @@ -290,7 +379,7 @@ func LabelsFromStrings(ss ...string) Labels { // CompareLabelPairs compares the two label sets. // The result will be 0 if a==b, <0 if a < b, and >0 if a > b. -func CompareLabelPairs(a []*typesv1.LabelPair, b []*typesv1.LabelPair) int { +func CompareLabelPairs(a, b []*typesv1.LabelPair) int { l := len(a) if len(b) < l { l = len(b) @@ -314,6 +403,24 @@ func CompareLabelPairs(a []*typesv1.LabelPair, b []*typesv1.LabelPair) int { return len(a) - len(b) } +func CompareLabels(a, b *typesv1.Labels) int { + return CompareLabelPairs(a.Labels, b.Labels) +} + +func CompareLabelPairs2(a, b *typesv1.LabelPair) int { + if a.Name < b.Name { + return -1 + } else if a.Name > b.Name { + return 1 + } + if a.Value < b.Value { + return -1 + } else if a.Value > b.Value { + return 1 + } + return 0 +} + // LabelsBuilder allows modifying Labels. type LabelsBuilder struct { base Labels @@ -373,6 +480,45 @@ func (b *LabelsBuilder) Set(n, v string) *LabelsBuilder { return b } +func (b *LabelsBuilder) Get(n string) string { + // Del() removes entries from .add but Set() does not remove from .del, so check .add first. + for _, a := range b.add { + if a.Name == n { + return a.Value + } + } + if slices.Contains(b.del, n) { + return "" + } + return b.base.Get(n) +} + +// Range calls f on each label in the Builder. +func (b *LabelsBuilder) Range(f func(l *typesv1.LabelPair)) { + // Stack-based arrays to avoid heap allocation in most cases. + var addStack [128]*typesv1.LabelPair + var delStack [128]string + // Take a copy of add and del, so they are unaffected by calls to Set() or Del(). + origAdd, origDel := append(addStack[:0], b.add...), append(delStack[:0], b.del...) + b.base.Range(func(l *typesv1.LabelPair) { + if !slices.Contains(origDel, l.Name) && !contains(origAdd, l.Name) { + f(l) + } + }) + for _, a := range origAdd { + f(a) + } +} + +func contains(s []*typesv1.LabelPair, n string) bool { + for _, a := range s { + if a.Name == n { + return true + } + } + return false +} + // Labels returns the labels from the builder. If no modifications // were made, the original labels are returned. func (b *LabelsBuilder) Labels() Labels { @@ -434,6 +580,7 @@ type ServiceVersion struct { Repository string `json:"repository,omitempty"` GitRef string `json:"git_ref,omitempty"` BuildID string `json:"build_id,omitempty"` + RootPath string `json:"root_path,omitempty"` } // ServiceVersionFromLabels Attempts to extract a service version from the given labels. @@ -441,8 +588,59 @@ type ServiceVersion struct { func ServiceVersionFromLabels(lbls Labels) (ServiceVersion, bool) { repo := lbls.Get(LabelNameServiceRepository) gitref := lbls.Get(LabelNameServiceGitRef) + rootPath := lbls.Get(LabelNameServiceRootPath) return ServiceVersion{ Repository: repo, GitRef: gitref, - }, repo != "" || gitref != "" + RootPath: rootPath, + }, repo != "" || gitref != "" || rootPath != "" +} + +// IntersectAll returns only the labels that are present in all label sets +// with the same value. Used for merging exemplars with dynamic labels. +// Reuses the existing Intersect method by iteratively intersecting all label sets. +func IntersectAll(labelSets []Labels) Labels { + if len(labelSets) == 0 { + return nil + } + if len(labelSets) == 1 { + return labelSets[0] + } + + result := labelSets[0].Clone() + for i := 1; i < len(labelSets); i++ { + result = result.Intersect(labelSets[i]) + if len(result) == 0 { + return nil + } + } + + if len(result) == 0 { + return nil + } + return result +} + +// WithoutLabels returns a new Labels with the specified label names removed. +func (ls Labels) WithoutLabels(names ...string) Labels { + if len(names) == 0 { + return ls + } + + toRemove := make(Labels, 0, len(names)) + for _, name := range names { + for _, l := range ls { + if l.Name == name { + toRemove = append(toRemove, l) + break + } + } + } + + if len(toRemove) == 0 { + return ls + } + + result := ls.Clone() + return result.Subtract(toRemove) } diff --git a/pkg/model/labels_merger.go b/pkg/model/labels_merger.go new file mode 100644 index 0000000000..b1d7e8760e --- /dev/null +++ b/pkg/model/labels_merger.go @@ -0,0 +1,109 @@ +package model + +import ( + "slices" + "sort" + "sync" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +type LabelMerger struct { + mu sync.Mutex + names map[string]struct{} + values map[string]struct{} + series map[uint64]*typesv1.Labels +} + +func NewLabelMerger() *LabelMerger { + return &LabelMerger{ + names: make(map[string]struct{}), + values: make(map[string]struct{}), + series: make(map[uint64]*typesv1.Labels), + } +} + +func (m *LabelMerger) MergeLabelNames(names []string) { + m.mu.Lock() + defer m.mu.Unlock() + for _, n := range names { + m.names[n] = struct{}{} + } +} + +func (m *LabelMerger) MergeLabelValues(values []string) { + m.mu.Lock() + defer m.mu.Unlock() + for _, v := range values { + m.values[v] = struct{}{} + } +} + +func (m *LabelMerger) HasNames() bool { + return len(m.names) > 0 +} + +func (m *LabelMerger) LabelNames() []string { + m.mu.Lock() + defer m.mu.Unlock() + s := make([]string, len(m.names)) + var i int + for n := range m.names { + s[i] = n + i++ + } + sort.Strings(s) + return s +} + +func (m *LabelMerger) HasValues() bool { + return len(m.values) > 0 +} + +func (m *LabelMerger) LabelValues() []string { + m.mu.Lock() + defer m.mu.Unlock() + s := make([]string, len(m.values)) + var i int + for v := range m.values { + s[i] = v + i++ + } + sort.Strings(s) + return s +} + +func (m *LabelMerger) MergeSeries(series []*typesv1.Labels) { + m.mu.Lock() + defer m.mu.Unlock() + for _, s := range series { + m.series[Labels(s.Labels).Hash()] = s + } +} + +func (m *LabelMerger) MergeLabels(ls []Labels) { + m.mu.Lock() + defer m.mu.Unlock() + for _, l := range ls { + m.series[l.Hash()] = &typesv1.Labels{Labels: l} + } +} + +func (m *LabelMerger) Labels() []*typesv1.Labels { + m.mu.Lock() + defer m.mu.Unlock() + s := make([]*typesv1.Labels, len(m.series)) + var i int + for _, v := range m.series { + s[i] = v + i++ + } + slices.SortFunc(s, func(a, b *typesv1.Labels) int { + return CompareLabelPairs(a.Labels, b.Labels) + }) + return s +} + +func (m *LabelMerger) HasSeries() bool { + return len(m.series) > 0 +} diff --git a/pkg/model/labels_test.go b/pkg/model/labels_test.go index 5e7fdcd26c..4a4f884362 100644 --- a/pkg/model/labels_test.go +++ b/pkg/model/labels_test.go @@ -68,6 +68,42 @@ func TestLabelsUnique(t *testing.T) { } } +func Test_LabelsBuilder_Unique(t *testing.T) { + tests := []struct { + name string + input Labels + add Labels + expected Labels + }{ + { + name: "duplicates in input are preserved", + input: Labels{ + {Name: "unique", Value: "yes"}, + {Name: "unique", Value: "no"}, + }, + add: Labels{ + {Name: "foo", Value: "bar"}, + {Name: "foo", Value: "baz"}, + }, + expected: Labels{ + {Name: "foo", Value: "baz"}, + {Name: "unique", Value: "yes"}, + {Name: "unique", Value: "no"}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + builder := NewLabelsBuilder(test.input) + for _, l := range test.add { + builder.Set(l.Name, l.Value) + } + assert.Equal(t, test.expected, builder.Labels()) + }) + } +} + func TestLabels_SessionID_Order(t *testing.T) { input := []Labels{ { @@ -281,3 +317,517 @@ func TestInsert(t *testing.T) { }) } } + +func Test_ServiceVersionFromLabels(t *testing.T) { + tests := []struct { + name string + input Labels + expectedVersion ServiceVersion + expectedOk bool + }{ + { + name: "all present", + input: Labels{ + {Name: LabelNameServiceRepository, Value: "repo"}, + {Name: LabelNameServiceGitRef, Value: "ref"}, + {Name: LabelNameServiceRootPath, Value: "some-path"}, + {Name: "any-other-label", Value: "any-value"}, + }, + expectedVersion: ServiceVersion{ + Repository: "repo", + GitRef: "ref", + RootPath: "some-path", + }, + expectedOk: true, + }, + { + name: "some present", + input: Labels{ + {Name: LabelNameServiceRepository, Value: "repo"}, + {Name: LabelNameServiceRootPath, Value: "some-path"}, + {Name: "any-other-label", Value: "any-value"}, + }, + expectedVersion: ServiceVersion{ + Repository: "repo", + GitRef: "", + RootPath: "some-path", + }, + expectedOk: true, + }, + { + name: "none present", + input: Labels{ + {Name: "any-label", Value: "any-value"}, + }, + expectedVersion: ServiceVersion{ + Repository: "", + GitRef: "", + RootPath: "", + }, + expectedOk: false, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + version, ok := ServiceVersionFromLabels(test.input) + assert.Equal(t, test.expectedVersion, version) + assert.Equal(t, test.expectedOk, ok) + }) + } +} + +func TestLabels_Subtract(t *testing.T) { + tests := []struct { + name string + labels Labels + input Labels + expected Labels + }{ + { + name: "Empty sets", + labels: Labels{}, + input: Labels{}, + expected: Labels{}, + }, + { + name: "Subtract from empty set", + labels: Labels{}, + input: Labels{ + {Name: "foo", Value: "bar"}, + {Name: "service", Value: "api"}, + }, + expected: Labels{}, + }, + { + name: "Subtract empty set", + labels: Labels{ + {Name: "foo", Value: "bar"}, + {Name: "service", Value: "api"}, + }, + input: Labels{}, + expected: Labels{ + {Name: "foo", Value: "bar"}, + {Name: "service", Value: "api"}, + }, + }, + { + name: "No overlap", + labels: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + input: Labels{ + {Name: "service", Value: "api"}, + {Name: "version", Value: "1.0"}, + }, + expected: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + }, + { + name: "Complete overlap", + labels: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + input: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + expected: Labels{}, + }, + { + name: "Partial overlap", + labels: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + {Name: "version", Value: "2.0"}, + }, + input: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + expected: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "version", Value: "2.0"}, + }, + }, + { + name: "Same name different value", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "frontend"}, + }, + input: Labels{ + {Name: "env", Value: "dev"}, + {Name: "service", Value: "api"}, + }, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "frontend"}, + }, + }, + { + name: "Single element sets", + labels: Labels{ + {Name: "foo", Value: "bar"}, + }, + input: Labels{ + {Name: "foo", Value: "bar"}, + }, + expected: Labels{}, + }, + { + name: "Larger set with multiple removals", + labels: Labels{ + {Name: "a", Value: "1"}, + {Name: "b", Value: "2"}, + {Name: "c", Value: "3"}, + {Name: "d", Value: "4"}, + {Name: "e", Value: "5"}, + }, + input: Labels{ + {Name: "b", Value: "2"}, + {Name: "d", Value: "4"}, + {Name: "f", Value: "6"}, + }, + expected: Labels{ + {Name: "a", Value: "1"}, + {Name: "c", Value: "3"}, + {Name: "e", Value: "5"}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expected, test.labels.Subtract(test.input)) + }) + } +} + +func TestLabels_Intersect(t *testing.T) { + tests := []struct { + name string + labels Labels + input Labels + expected Labels + }{ + { + name: "Empty sets", + labels: Labels{}, + input: Labels{}, + expected: Labels{}, + }, + { + name: "Intersect with empty set", + labels: Labels{ + {Name: "foo", Value: "bar"}, + {Name: "service", Value: "api"}, + }, + input: Labels{}, + expected: Labels{}, + }, + { + name: "Intersect empty set", + labels: Labels{}, + input: Labels{ + {Name: "foo", Value: "bar"}, + {Name: "service", Value: "api"}, + }, + expected: Labels{}, + }, + { + name: "No overlap", + labels: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + input: Labels{ + {Name: "service", Value: "api"}, + {Name: "version", Value: "1.0"}, + }, + expected: Labels{}, + }, + { + name: "Complete overlap", + labels: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + input: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + expected: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + }, + }, + { + name: "Partial overlap", + labels: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + {Name: "version", Value: "2.0"}, + }, + input: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + expected: Labels{ + {Name: "env", Value: "prod"}, + }, + }, + { + name: "Same name different value", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "frontend"}, + }, + input: Labels{ + {Name: "env", Value: "dev"}, + {Name: "service", Value: "api"}, + }, + expected: Labels{}, + }, + { + name: "Single element intersection", + labels: Labels{ + {Name: "foo", Value: "bar"}, + }, + input: Labels{ + {Name: "foo", Value: "bar"}, + }, + expected: Labels{ + {Name: "foo", Value: "bar"}, + }, + }, + { + name: "Multiple intersections", + labels: Labels{ + {Name: "a", Value: "1"}, + {Name: "b", Value: "2"}, + {Name: "c", Value: "3"}, + {Name: "d", Value: "4"}, + {Name: "e", Value: "5"}, + }, + input: Labels{ + {Name: "b", Value: "2"}, + {Name: "c", Value: "3"}, + {Name: "f", Value: "6"}, + {Name: "g", Value: "7"}, + }, + expected: Labels{ + {Name: "b", Value: "2"}, + {Name: "c", Value: "3"}, + }, + }, + { + name: "First set is subset of second", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "version", Value: "1.0"}, + }, + input: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + {Name: "version", Value: "1.0"}, + }, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "version", Value: "1.0"}, + }, + }, + { + name: "Second set is subset of first", + labels: Labels{ + {Name: "app", Value: "frontend"}, + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + {Name: "version", Value: "1.0"}, + }, + input: Labels{ + {Name: "env", Value: "prod"}, + {Name: "version", Value: "1.0"}, + }, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "version", Value: "1.0"}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expected, test.labels.Intersect(test.input)) + }) + } +} + +func TestLabels_IntersectAll(t *testing.T) { + tests := []struct { + name string + labelSets []Labels + expected Labels + }{ + { + name: "Empty input", + labelSets: []Labels{}, + expected: nil, + }, + { + name: "Single label set", + labelSets: []Labels{ + { + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + { + name: "Two sets with full overlap", + labelSets: []Labels{ + { + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + { + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + { + name: "Two sets with partial overlap", + labelSets: []Labels{ + { + {Name: "env", Value: "prod"}, + {Name: "pod", Value: "pod-1"}, + {Name: "region", Value: "us-east"}, + }, + { + {Name: "env", Value: "prod"}, + {Name: "pod", Value: "pod-2"}, + {Name: "region", Value: "us-east"}, + }, + }, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "region", Value: "us-east"}, + }, + }, + { + name: "No common labels", + labelSets: []Labels{ + { + {Name: "env", Value: "prod"}, + }, + { + {Name: "region", Value: "us-east"}, + }, + }, + expected: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := IntersectAll(test.labelSets) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestLabels_WithoutLabels(t *testing.T) { + tests := []struct { + name string + labels Labels + remove []string + expected Labels + }{ + { + name: "Remove nothing", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + remove: []string{}, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + { + name: "Remove single label", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "pod", Value: "pod-1"}, + {Name: "service", Value: "api"}, + }, + remove: []string{"pod"}, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + { + name: "Remove multiple labels", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "pod", Value: "pod-1"}, + {Name: "region", Value: "us-east"}, + {Name: "service", Value: "api"}, + }, + remove: []string{"pod", "region"}, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + { + name: "Remove non-existent label", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + remove: []string{"nonexistent"}, + expected: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + }, + { + name: "Remove all labels", + labels: Labels{ + {Name: "env", Value: "prod"}, + {Name: "service", Value: "api"}, + }, + remove: []string{"env", "service"}, + expected: Labels{}, + }, + { + name: "Empty labels", + labels: Labels{}, + remove: []string{"env"}, + expected: Labels{}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := test.labels.WithoutLabels(test.remove...) + assert.Equal(t, test.expected, result) + }) + } +} diff --git a/pkg/model/pprofsplit/pprof_split.go b/pkg/model/pprofsplit/pprof_split.go new file mode 100644 index 0000000000..1b526f3d89 --- /dev/null +++ b/pkg/model/pprofsplit/pprof_split.go @@ -0,0 +1,230 @@ +package pprofsplit + +import ( + "unsafe" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/relabel" + "github.com/grafana/pyroscope/v2/pkg/pprof" +) + +type SampleSeriesVisitor interface { + // VisitProfile is called when no sample labels are present in + // the profile, or if all the sample labels are identical. + // Provided labels are the series labels processed with relabeling rules. + VisitProfile(phlaremodel.Labels) + VisitSampleSeries(phlaremodel.Labels, []*profilev1.Sample) + // ValidateLabels is called to validate the labels before + // they are passed to the visitor. Returns the potentially modified + // labels slice (e.g., after sanitization) and any validation error. + ValidateLabels(phlaremodel.Labels) (phlaremodel.Labels, error) + Discarded(profiles, bytes int) +} + +func VisitSampleSeries( + profile *profilev1.Profile, + labels []*typesv1.LabelPair, + rules []*relabel.Config, + visitor SampleSeriesVisitor, +) error { + var profilesDiscarded, bytesDiscarded int + defer func() { + visitor.Discarded(profilesDiscarded, bytesDiscarded) + }() + + pprof.RenameLabel(profile, pprof.ProfileIDLabelName, pprof.SpanIDLabelName) + groups := pprof.GroupSamplesWithoutLabels(profile, pprof.TraceIDLabelName, pprof.SpanIDLabelName) + builder := phlaremodel.NewLabelsBuilder(nil) + + if len(groups) == 0 || (len(groups) == 1 && len(groups[0].Labels) == 0) { + // No sample labels in the profile. + // Relabel the series labels. + builder.Reset(labels) + if len(rules) > 0 { + keep := relabel.ProcessBuilder(builder, rules...) + if !keep { + // We drop the profile. + profilesDiscarded++ + bytesDiscarded += profile.SizeVT() + return nil + } + } + if len(profile.Sample) > 0 { + labels = builder.Labels() + var err error + labels, err = visitor.ValidateLabels(labels) + if err != nil { + return err + } + visitor.VisitProfile(labels) + } + return nil + } + + // iterate through groups relabel them and find relevant overlapping label sets. + groupsKept := newGroupsWithFingerprints() + for _, group := range groups { + builder.Reset(labels) + addSampleLabelsToLabelsBuilder(builder, profile, group.Labels) + if len(rules) > 0 { + keep := relabel.ProcessBuilder(builder, rules...) + if !keep { + bytesDiscarded += sampleSize(group.Samples) + continue + } + } + // add the group to the list. + groupsKept.add(profile.StringTable, builder.Labels(), group) + } + + if len(groupsKept.m) == 0 { + // no groups kept, count the whole profile as dropped + profilesDiscarded++ + return nil + } + + for _, idx := range groupsKept.order { + for _, group := range groupsKept.m[idx] { + if len(group.sampleGroup.Samples) > 0 { + var err error + group.labels, err = visitor.ValidateLabels(group.labels) + if err != nil { + return err + } + visitor.VisitSampleSeries(group.labels, group.sampleGroup.Samples) + } + } + } + + return nil +} + +// addSampleLabelsToLabelsBuilder: adds sample label that don't exists yet on the profile builder. So the existing labels take precedence. +func addSampleLabelsToLabelsBuilder(b *phlaremodel.LabelsBuilder, p *profilev1.Profile, pl []*profilev1.Label) { + var name string + for _, l := range pl { + name = p.StringTable[l.Key] + if l.Str <= 0 { + // skip if label value is not a string + continue + } + if b.Get(name) != "" { + // do nothing if label name already exists + continue + } + b.Set(name, p.StringTable[l.Str]) + } +} + +type sampleKey struct { + stacktrace string + // String table indices, kept so samples are not merged across traces/spans. + traceIDIdx int64 + spanIDIdx int64 +} + +func sampleKeyFromSample(stringTable []string, s *profilev1.Sample) sampleKey { + var k sampleKey + for _, l := range s.Label { + switch stringTable[int(l.Key)] { + case pprof.TraceIDLabelName: + k.traceIDIdx = l.Str + case pprof.SpanIDLabelName: + k.spanIDIdx = l.Str + } + } + if len(s.LocationId) > 0 { + k.stacktrace = unsafe.String( + (*byte)(unsafe.Pointer(&s.LocationId[0])), + len(s.LocationId)*8, + ) + } + return k +} + +type lazyGroup struct { + sampleGroup pprof.SampleGroup + // The map is only initialized when the group is being modified. Key is the + // string representation (unsafe) of the sample stack trace and its potential + // span ID. + sampleMap map[sampleKey]*profilev1.Sample + labels phlaremodel.Labels +} + +func (g *lazyGroup) addSampleGroup(stringTable []string, sg pprof.SampleGroup) { + if len(g.sampleGroup.Samples) == 0 { + g.sampleGroup.Labels = sg.Labels + g.sampleGroup.Samples = append(g.sampleGroup.Samples, sg.Samples...) + return + } + + // If the group is already initialized, we need to merge the samples. + if g.sampleMap == nil { + g.sampleMap = make(map[sampleKey]*profilev1.Sample) + for _, s := range g.sampleGroup.Samples { + g.sampleMap[sampleKeyFromSample(stringTable, s)] = s + } + } + + for _, s := range sg.Samples { + k := sampleKeyFromSample(stringTable, s) + if _, ok := g.sampleMap[k]; !ok { + g.sampleGroup.Samples = append(g.sampleGroup.Samples, s) + g.sampleMap[k] = s + } else { + // merge the samples + for idx := range s.Value { + g.sampleMap[k].Value[idx] += s.Value[idx] + } + } + } +} + +type groupsWithFingerprints struct { + m map[uint64][]*lazyGroup + order []uint64 +} + +func newGroupsWithFingerprints() *groupsWithFingerprints { + return &groupsWithFingerprints{ + m: make(map[uint64][]*lazyGroup), + } +} + +func (g *groupsWithFingerprints) add(stringTable []string, lbls phlaremodel.Labels, group pprof.SampleGroup) { + fp := lbls.Hash() + idxs, ok := g.m[fp] + if ok { + // fingerprint matches, check if the labels are the same + for _, idx := range idxs { + if phlaremodel.CompareLabelPairs(idx.labels, lbls) == 0 { + // append samples to the group + idx.addSampleGroup(stringTable, group) + return + } + } + } else { + g.order = append(g.order, fp) + } + + // add the labels to the list + g.m[fp] = append(g.m[fp], &lazyGroup{ + sampleGroup: pprof.SampleGroup{ + Labels: group.Labels, + // defensive copy, we don't want to modify the original slice + Samples: append([]*profilev1.Sample(nil), group.Samples...), + }, + labels: lbls, + }) +} + +// sampleSize returns the size of a samples in bytes. +func sampleSize(samples []*profilev1.Sample) int { + var size int + for _, s := range samples { + size += s.SizeVT() + } + return size +} diff --git a/pkg/model/pprofsplit/pprof_split_by.go b/pkg/model/pprofsplit/pprof_split_by.go new file mode 100644 index 0000000000..68d2282b65 --- /dev/null +++ b/pkg/model/pprofsplit/pprof_split_by.go @@ -0,0 +1,150 @@ +package pprofsplit + +import ( + "strings" + + "github.com/prometheus/prometheus/model/relabel" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +// VisitSampleSeriesBy visits samples in a profile, splitting them by the +// specified labels. Labels shared by all samples in a group (intersection) +// are passed to the visitor, while the rest of the labels are added to each +// sample. +func VisitSampleSeriesBy( + profile *profilev1.Profile, + labels phlaremodel.Labels, + rules []*relabel.Config, + visitor SampleSeriesVisitor, + names ...string, +) error { + m := &sampleSeriesMerger{ + visitor: visitor, + profile: profile, + names: names, + groups: make(map[string]*groupBy), + } + if err := VisitSampleSeries(profile, labels, rules, m); err != nil { + return err + } + if len(m.groups) == 0 { + return nil + } + for _, k := range m.order { + group := m.groups[k] + // For simplicity, we allocate a new slice of samples + // and delegate ownership to the visitor. + var size int + for _, s := range group.samples { + size += len(s.samples) + } + samples := make([]*profilev1.Sample, 0, size) + // All sample groups share group.labels: + // we use them as series labels. + for _, s := range group.samples { + s.labels = s.labels.Subtract(group.labels) + m.addLabelsToSamples(s) + samples = append(samples, s.samples...) + } + m.visitor.VisitSampleSeries(group.labels, samples) + } + return nil +} + +type sampleSeriesMerger struct { + visitor SampleSeriesVisitor + profile *profilev1.Profile + names []string + groups map[string]*groupBy + order []string + strings map[string]int64 +} + +type groupBy struct { + labels phlaremodel.Labels + samples []sampleGroup + init bool +} + +type sampleGroup struct { + labels phlaremodel.Labels + samples []*profilev1.Sample +} + +func (m *sampleSeriesMerger) ValidateLabels(labels phlaremodel.Labels) (phlaremodel.Labels, error) { + return m.visitor.ValidateLabels(labels) +} + +func (m *sampleSeriesMerger) VisitProfile(labels phlaremodel.Labels) { + m.visitor.VisitProfile(labels) +} + +func (m *sampleSeriesMerger) VisitSampleSeries(labels phlaremodel.Labels, samples []*profilev1.Sample) { + k := groupKey(labels, m.names...) + group, ok := m.groups[k] + if !ok { + group = &groupBy{labels: labels.Clone()} + m.order = append(m.order, k) + m.groups[k] = group + } else { + group.labels = group.labels.Intersect(labels) + } + group.samples = append(group.samples, sampleGroup{ + labels: labels, + samples: samples, + }) +} + +func (m *sampleSeriesMerger) Discarded(profiles, bytes int) { + m.visitor.Discarded(profiles, bytes) +} + +func groupKey(labels phlaremodel.Labels, by ...string) string { + var b strings.Builder + for _, name := range by { + for i := range labels { + if labels[i] != nil && labels[i].Name == name { + if b.Len() > 0 { + b.WriteByte(',') + } + b.WriteString(labels[i].Value) + break + } + } + } + return b.String() +} + +func (m *sampleSeriesMerger) addLabelsToSamples(s sampleGroup) { + sampleLabels := make([]*profilev1.Label, len(s.labels)) + for i, label := range s.labels { + sampleLabels[i] = &profilev1.Label{ + Key: m.string(label.Name), + Str: m.string(label.Value), + } + } + // We can't reuse labels here. + for _, sample := range s.samples { + for i := range sampleLabels { + sample.Label = append(sample.Label, sampleLabels[i].CloneVT()) + } + } +} + +func (m *sampleSeriesMerger) string(s string) int64 { + if m.strings == nil { + m.strings = make(map[string]int64, len(m.profile.StringTable)) + for i, str := range m.profile.StringTable { + m.strings[str] = int64(i) + } + } + i, ok := m.strings[s] + if !ok { + i = int64(len(m.profile.StringTable)) + m.strings[s] = i + m.profile.StringTable = append(m.profile.StringTable, s) + } + return i +} diff --git a/pkg/model/pprofsplit/pprof_split_by_test.go b/pkg/model/pprofsplit/pprof_split_by_test.go new file mode 100644 index 0000000000..94e4d2fd3c --- /dev/null +++ b/pkg/model/pprofsplit/pprof_split_by_test.go @@ -0,0 +1,958 @@ +package pprofsplit + +import ( + "fmt" + "strings" + "testing" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +type testSample struct { + labels string // "foo=bar,baz=qux" + value int64 +} + +type expectedSeries struct { + labels string // "foo=bar,baz=qux" + samples []testSample // samples with their labels +} + +func Test_VisitSampleSeriesBy(t *testing.T) { + // Test cases are mostly generated by AI. + // Some very specific cases were added manually. + testCases := []struct { + description string + seriesLabels string // Series-level labels. Label order matters. + samples []testSample // Input samples. Label order does not matter. + splitBy []string // Labels to split by. + rules []*relabel.Config // Relabel rules to apply. + expected []expectedSeries + }{ + { + description: "split profile by group by labels", + seriesLabels: "__name__=profile,foo=bar", + samples: []testSample{ + {labels: "service_name=web,endpoint=/users", value: 100}, + {labels: "service_name=api,endpoint=/users", value: 300}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,endpoint=/users,foo=bar,service_name=web", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,endpoint=/users,foo=bar,service_name=api", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + { + description: "group by labels are not overridden", + seriesLabels: "__name__=profile,foo=bar,service_name=app", + samples: []testSample{ + {labels: "service_name=web,endpoint=/users", value: 100}, + {labels: "service_name=api,endpoint=/orders", value: 300}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,foo=bar,service_name=app", + samples: []testSample{ + {labels: "endpoint=/users", value: 100}, + {labels: "endpoint=/orders", value: 300}, + }, + }, + }, + }, + { + description: "split by multiple labels", + seriesLabels: "__name__=profile,app=web", + samples: []testSample{ + {labels: "service_name=auth,region=us-east,endpoint=/login", value: 150}, + {labels: "service_name=auth,region=us-west,endpoint=/login", value: 200}, + {labels: "service_name=api,region=us-east,endpoint=/users", value: 250}, + {labels: "service_name=api,region=us-west,endpoint=/orders", value: 300}, + }, + splitBy: []string{"service_name", "region"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=web,endpoint=/login,region=us-east,service_name=auth", + samples: []testSample{ + {labels: "", value: 150}, + }, + }, + { + labels: "__name__=profile,app=web,endpoint=/login,region=us-west,service_name=auth", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,app=web,endpoint=/users,region=us-east,service_name=api", + samples: []testSample{ + {labels: "", value: 250}, + }, + }, + { + labels: "__name__=profile,app=web,endpoint=/orders,region=us-west,service_name=api", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + { + description: "split by non-existent label", + seriesLabels: "__name__=profile,app=test", + samples: []testSample{ + {labels: "service_name=web,endpoint=/users", value: 100}, + {labels: "service_name=api,endpoint=/orders", value: 200}, + }, + splitBy: []string{"missing_label"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=test", + samples: []testSample{ + {labels: "endpoint=/users,service_name=web", value: 100}, + {labels: "endpoint=/orders,service_name=api", value: 200}, + }, + }, + }, + }, + { + description: "samples with no labels", + seriesLabels: "__name__=profile,env=prod", + samples: []testSample{ + {labels: "", value: 500}, + {labels: "", value: 600}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{}, + }, + { + description: "split by label with empty value", + seriesLabels: "__name__=profile,app=web", + samples: []testSample{ + {labels: "service_name=,endpoint=/health", value: 75}, + {labels: "service_name=api,endpoint=/health", value: 125}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=web,endpoint=/health", + samples: []testSample{ + {labels: "", value: 75}, + }, + }, + { + labels: "__name__=profile,app=web,endpoint=/health,service_name=api", + samples: []testSample{ + {labels: "", value: 125}, + }, + }, + }, + }, + { + description: "no split by labels", + seriesLabels: "__name__=profile,env=test", + samples: []testSample{ + {labels: "service_name=web,endpoint=/users", value: 400}, + {labels: "service_name=api,endpoint=/orders", value: 500}, + }, + splitBy: []string{}, + expected: []expectedSeries{ + { + labels: "__name__=profile,env=test", + samples: []testSample{ + {labels: "endpoint=/users,service_name=web", value: 400}, + {labels: "endpoint=/orders,service_name=api", value: 500}, + }, + }, + }, + }, + { + description: "multiple samples with same split-by label value", + seriesLabels: "__name__=profile,version=1.0", + samples: []testSample{ + {labels: "service_name=web,method=GET", value: 100}, + {labels: "service_name=web,method=POST", value: 150}, + {labels: "service_name=api,method=GET", value: 200}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,service_name=web,version=1.0", + samples: []testSample{ + {labels: "method=GET", value: 100}, + {labels: "method=POST", value: 150}, + }, + }, + { + labels: "__name__=profile,method=GET,service_name=api,version=1.0", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + }, + }, + { + description: "partial overlap between series and sample labels", + seriesLabels: "__name__=profile,service_name=main,region=us-east", + samples: []testSample{ + {labels: "service_name=web,env=prod", value: 300}, + {labels: "region=eu-west,env=staging", value: 400}, + }, + splitBy: []string{"env"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,env=prod,region=us-east,service_name=main", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + { + labels: "__name__=profile,env=staging,region=us-east,service_name=main", + samples: []testSample{ + {labels: "", value: 400}, + }, + }, + }, + }, + { + description: "complex scenario with overlapping labels", + seriesLabels: "__name__=profile,app=frontend,env=prod", + samples: []testSample{ + {labels: "service_name=auth,env=staging,version=v1", value: 100}, + {labels: "service_name=auth,region=us-west,version=v2", value: 200}, + {labels: "service_name=api,env=dev,region=eu-central", value: 300}, + }, + splitBy: []string{"service_name", "version"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=frontend,env=prod,service_name=auth,version=v1", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,app=frontend,env=prod,region=us-west,service_name=auth,version=v2", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,app=frontend,env=prod,region=eu-central,service_name=api", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + { + description: "single sample with multiple labels", + seriesLabels: "__name__=profile,region=us-east", + samples: []testSample{ + {labels: "service_name=web,method=GET,status=200", value: 42}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,method=GET,region=us-east,service_name=web,status=200", + samples: []testSample{ + {labels: "", value: 42}, + }, + }, + }, + }, + { + description: "mixed samples - some with labels, some without", + seriesLabels: "__name__=profile,app=myapp", + samples: []testSample{ + {labels: "service_name=auth,endpoint=/login", value: 100}, + {labels: "", value: 200}, + {labels: "service_name=api", value: 300}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=myapp", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,app=myapp,endpoint=/login,service_name=auth", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,app=myapp,service_name=api", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + { + description: "split by multiple labels with partial matches", + seriesLabels: "__name__=profile,environment=prod", + samples: []testSample{ + {labels: "service_name=web,region=us-east,tier=frontend", value: 100}, + {labels: "service_name=web,tier=frontend", value: 150}, + {labels: "service_name=api,region=us-west", value: 200}, + {labels: "region=eu-central", value: 250}, + }, + splitBy: []string{"service_name", "region"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,environment=prod,region=us-east,service_name=web,tier=frontend", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,environment=prod,service_name=web,tier=frontend", + samples: []testSample{ + {labels: "", value: 150}, + }, + }, + { + labels: "__name__=profile,environment=prod,region=us-west,service_name=api", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,environment=prod,region=eu-central", + samples: []testSample{ + {labels: "", value: 250}, + }, + }, + }, + }, + { + description: "unicode and special characters in labels", + seriesLabels: "__name__=profile,app=测试应用", + samples: []testSample{ + {labels: "service_name=微服务-api,endpoint=/用户/登录", value: 100}, + {labels: "service_name=web-frontend,endpoint=/status", value: 200}, + }, + splitBy: []string{"service_name"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=测试应用,endpoint=/用户/登录,service_name=微服务-api", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,app=测试应用,endpoint=/status,service_name=web-frontend", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + }, + }, + { + description: "many labels with different combinations", + seriesLabels: "__name__=profile,cluster=prod-cluster", + samples: []testSample{ + {labels: "service=auth,method=POST,status=200,region=us-east,az=us-east-1a", value: 50}, + {labels: "service=auth,method=POST,status=200,region=us-east,az=us-east-1b", value: 75}, + {labels: "service=auth,method=GET,status=200,region=us-west,az=us-west-2a", value: 25}, + {labels: "service=api,method=POST,status=500,region=eu-central,az=eu-central-1a", value: 100}, + }, + splitBy: []string{"service", "method", "status"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,cluster=prod-cluster,method=POST,region=us-east,service=auth,status=200", + samples: []testSample{ + {labels: "az=us-east-1a", value: 50}, + {labels: "az=us-east-1b", value: 75}, + }, + }, + { + labels: "__name__=profile,az=us-west-2a,cluster=prod-cluster,method=GET,region=us-west,service=auth,status=200", + samples: []testSample{ + {labels: "", value: 25}, + }, + }, + { + labels: "__name__=profile,az=eu-central-1a,cluster=prod-cluster,method=POST,region=eu-central,service=api,status=500", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + }, + }, + { + description: "split by labels that exist in series labels", + seriesLabels: "__name__=profile,service_name=main-service,region=global", + samples: []testSample{ + {labels: "service_name=auth,endpoint=/login", value: 100}, + {labels: "region=us-east,endpoint=/health", value: 200}, + {labels: "method=GET", value: 300}, + }, + splitBy: []string{"service_name", "region"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,region=global,service_name=main-service", + samples: []testSample{ + {labels: "endpoint=/login", value: 100}, + {labels: "endpoint=/health", value: 200}, + {labels: "method=GET", value: 300}, + }, + }, + }, + }, + { + description: "empty string values in split-by labels", + seriesLabels: "__name__=profile,app=test-app", + samples: []testSample{ + {labels: "env=,version=v1.0,service=web", value: 100}, + {labels: "env=prod,version=,service=api", value: 200}, + {labels: "env=staging,version=v2.0,service=", value: 300}, + }, + splitBy: []string{"env", "version", "service"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=test-app,service=web,version=v1.0", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,app=test-app,env=prod,service=api", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,app=test-app,env=staging,version=v2.0", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + { + description: "duplicate split-by label values across different samples", + seriesLabels: "__name__=profile,datacenter=dc1", + samples: []testSample{ + {labels: "service=web,tier=frontend,instance=web-1", value: 100}, + {labels: "service=web,tier=frontend,instance=web-2", value: 150}, + {labels: "service=web,tier=backend,instance=web-3", value: 200}, + {labels: "service=api,tier=frontend,instance=api-1", value: 250}, + }, + splitBy: []string{"service", "tier"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,datacenter=dc1,service=web,tier=frontend", + samples: []testSample{ + {labels: "instance=web-1", value: 100}, + {labels: "instance=web-2", value: 150}, + }, + }, + { + labels: "__name__=profile,datacenter=dc1,instance=web-3,service=web,tier=backend", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,datacenter=dc1,instance=api-1,service=api,tier=frontend", + samples: []testSample{ + {labels: "", value: 250}, + }, + }, + }, + }, + { + description: "relabel rules drop entire profile", + seriesLabels: "__name__=profile,app=test", + samples: []testSample{ + {labels: "service=auth,env=prod", value: 100}, + {labels: "service=api,env=staging", value: 200}, + }, + splitBy: []string{"service"}, + rules: []*relabel.Config{ + { + Action: relabel.Drop, + Regex: relabel.MustNewRegexp("test"), + SourceLabels: []model.LabelName{"app"}, + }, + }, + expected: []expectedSeries{}, + }, + { + description: "relabel rules drop some sample groups", + seriesLabels: "__name__=profile,component=backend", + samples: []testSample{ + {labels: "service=auth,env=prod", value: 100}, + {labels: "service=api,env=staging", value: 200}, + {labels: "service=web,env=prod", value: 300}, + }, + splitBy: []string{"service"}, + rules: []*relabel.Config{ + { + Action: relabel.Drop, + Regex: relabel.MustNewRegexp("staging"), + SourceLabels: []model.LabelName{"env"}, + }, + }, + expected: []expectedSeries{ + { + labels: "__name__=profile,component=backend,env=prod,service=auth", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,component=backend,env=prod,service=web", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + { + description: "samples with same stack trace get merged", + seriesLabels: "__name__=profile,app=merger", + samples: []testSample{ + {labels: "service=auth,method=GET", value: 100}, + {labels: "service=auth,method=GET", value: 50}, // Same labels but different location IDs won't merge + {labels: "service=api,method=POST", value: 200}, + }, + splitBy: []string{"service"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=merger,method=GET,service=auth", + samples: []testSample{ + {labels: "", value: 100}, + {labels: "", value: 50}, // Separate samples since different location IDs + }, + }, + { + labels: "__name__=profile,app=merger,method=POST,service=api", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + }, + }, + { + description: "empty profile after all groups dropped by relabel rules", + seriesLabels: "__name__=profile,app=filter", + samples: []testSample{ + {labels: "drop=true,service=auth", value: 100}, + {labels: "drop=true,service=api", value: 200}, + }, + splitBy: []string{"service"}, + rules: []*relabel.Config{ + { + Action: relabel.Drop, + Regex: relabel.MustNewRegexp("true"), + SourceLabels: []model.LabelName{"drop"}, + }, + }, + expected: []expectedSeries{}, + }, + { + description: "complex sample merging with multiple values", + seriesLabels: "__name__=profile,cluster=main", + samples: []testSample{ + {labels: "service=web,endpoint=/api", value: 100}, + {labels: "service=web,endpoint=/api", value: 150}, // Same labels but different LocationIds + {labels: "service=web,endpoint=/health", value: 50}, + {labels: "service=web,endpoint=/api", value: 75}, // Same labels but different LocationIds + }, + splitBy: []string{"service"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,cluster=main,service=web", + samples: []testSample{ + {labels: "endpoint=/api", value: 100}, + {labels: "endpoint=/api", value: 150}, + {labels: "endpoint=/api", value: 75}, + {labels: "endpoint=/health", value: 50}, + }, + }, + }, + }, + { + description: "string table expansion with new label names and values", + seriesLabels: "__name__=profile,existing_label=existing_value", + samples: []testSample{ + {labels: "completely_new_label=completely_new_value", value: 100}, + {labels: "another_new_label=another_new_value", value: 200}, + }, + splitBy: []string{"completely_new_label"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,completely_new_label=completely_new_value,existing_label=existing_value", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,another_new_label=another_new_value,existing_label=existing_value", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + }, + }, + { + description: "samples with identical location IDs for merging", + seriesLabels: "__name__=profile,service=test", + samples: []testSample{ + {labels: "endpoint=/api,method=GET", value: 200}, + {labels: "endpoint=/api,method=GET", value: 300}, // Same labels but different location IDs + {labels: "endpoint=/health,method=GET", value: 100}, + }, + splitBy: []string{"endpoint"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,endpoint=/api,method=GET,service=test", + samples: []testSample{ + {labels: "", value: 200}, + {labels: "", value: 300}, // Separate samples due to different location IDs + }, + }, + { + labels: "__name__=profile,endpoint=/health,method=GET,service=test", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + }, + }, + { + description: "fingerprint collision with different label sets", + seriesLabels: "__name__=profile,cluster=test", + samples: []testSample{ + // These might create hash collisions but have different actual labels + {labels: "service=a,region=b", value: 100}, + {labels: "service=c,region=d", value: 200}, + {labels: "service=a,region=b", value: 50}, // Same labels but different location IDs + }, + splitBy: []string{"service"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,cluster=test,region=b,service=a", + samples: []testSample{ + {labels: "", value: 100}, + {labels: "", value: 50}, // Separate samples due to different location IDs + }, + }, + { + labels: "__name__=profile,cluster=test,region=d,service=c", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + }, + }, + { + description: "no samples in profile", + seriesLabels: "__name__=profile,app=empty", + samples: []testSample{}, + splitBy: []string{"service"}, + expected: []expectedSeries{}, + }, + { + description: "profile with only samples having empty values", + seriesLabels: "__name__=profile,app=zero", + samples: []testSample{ + {labels: "service=auth", value: 0}, + {labels: "service=api", value: 0}, + }, + splitBy: []string{"service"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=zero,service=auth", + samples: []testSample{ + {labels: "", value: 0}, + }, + }, + { + labels: "__name__=profile,app=zero,service=api", + samples: []testSample{ + {labels: "", value: 0}, + }, + }, + }, + }, + { + description: "force string table expansion during sample processing", + seriesLabels: "__name__=profile,app=test", + samples: []testSample{ + {labels: "service=auth", value: 100}, + {labels: "service=api", value: 200}, + }, + splitBy: []string{"service"}, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=test,service=auth", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,app=test,service=api", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + }, + }, + { + description: "relabel rules drop pprof labels", + seriesLabels: "__name__=profile,app=test", + samples: []testSample{ + {labels: "service=auth,internal_debug=true,endpoint=/login", value: 100}, + {labels: "service=api,internal_debug=false,endpoint=/users", value: 200}, + {labels: "service=web,temp_flag=remove_me,endpoint=/health", value: 300}, + }, + splitBy: []string{"service"}, + rules: []*relabel.Config{ + { + Action: relabel.LabelDrop, + Regex: relabel.MustNewRegexp("internal_.*|temp_.*"), + }, + }, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=test,endpoint=/login,service=auth", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,app=test,endpoint=/users,service=api", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,app=test,endpoint=/health,service=web", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + { + description: "relabel rules keep only labels without whitespace", + seriesLabels: "__name__=profile,app=filtertest,service=auth", + samples: []testSample{ + {labels: "bad label=value1,endpoint=/login,temp flag=debug", value: 100}, + {labels: "another bad=value2,endpoint=/users,good_label=keep", value: 200}, + {labels: "weird name=value3,endpoint=/health", value: 300}, + }, + splitBy: []string{"service"}, + rules: []*relabel.Config{ + { + Action: relabel.LabelKeep, + Regex: relabel.MustNewRegexp("^[^\\s]+$"), + }, + }, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=filtertest,service=auth", + samples: []testSample{ + {labels: "endpoint=/login", value: 100}, + {labels: "endpoint=/users,good_label=keep", value: 200}, + {labels: "endpoint=/health", value: 300}, + }, + }, + }, + }, + { + description: "relabel rules replace dots with underscores in label values", + seriesLabels: "__name__=profile,app=normalizer", + samples: []testSample{ + {labels: "service=com.example.auth,endpoint=/api/v1.0,version=1.2.3", value: 100}, + {labels: "service=org.service.api,endpoint=/health.check,version=2.0.1", value: 200}, + {labels: "service=net.frontend.web,endpoint=/home.page,version=1.0.0", value: 300}, + }, + splitBy: []string{"service"}, + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"service"}, + Regex: relabel.MustNewRegexp("([^.]*)\\.(.*)\\.(.*)"), + Replacement: "${1}_${2}_${3}", + TargetLabel: "service", + Action: relabel.Replace, + }, + { + SourceLabels: []model.LabelName{"endpoint"}, + Regex: relabel.MustNewRegexp("([^.]*)\\.(.*)"), + Replacement: "${1}_${2}", + TargetLabel: "endpoint", + Action: relabel.Replace, + }, + { + SourceLabels: []model.LabelName{"version"}, + Regex: relabel.MustNewRegexp("([^.]*)\\.(.*)\\.(.*)"), + Replacement: "${1}_${2}_${3}", + TargetLabel: "version", + Action: relabel.Replace, + }, + }, + expected: []expectedSeries{ + { + labels: "__name__=profile,app=normalizer,endpoint=/api/v1_0,service=com_example_auth,version=1_2_3", + samples: []testSample{ + {labels: "", value: 100}, + }, + }, + { + labels: "__name__=profile,app=normalizer,endpoint=/health_check,service=org_service_api,version=2_0_1", + samples: []testSample{ + {labels: "", value: 200}, + }, + }, + { + labels: "__name__=profile,app=normalizer,endpoint=/home_page,service=net_frontend_web,version=1_0_0", + samples: []testSample{ + {labels: "", value: 300}, + }, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + profile := &profilev1.Profile{ + StringTable: []string{""}, + Sample: make([]*profilev1.Sample, len(tc.samples)), + } + lookup := stringLookup(profile) + reverseLookup := stringReverseLookup(profile) + for i, s := range tc.samples { + profile.Sample[i] = &profilev1.Sample{ + LocationId: []uint64{uint64(i + 1)}, // unique location ID per sample + Value: []int64{s.value}, + Label: parseSampleLabels(t, lookup, s.labels), + } + } + + visitor := new(mockVisitor) + seriesLabels := parseLabels(t, tc.seriesLabels) + require.NoError(t, VisitSampleSeriesBy(profile, seriesLabels, tc.rules, visitor, tc.splitBy...)) + require.Len(t, visitor.series, len(tc.expected)) + + for i, actual := range visitor.series { + expected := tc.expected[i] + expectedLabels := parseLabels(t, expected.labels) + assert.Equal(t, expectedLabels, actual.labels, fmt.Sprintf("want: %s,\ngot: %s", + formatLabels(expectedLabels), + formatLabels(actual.labels))) + + require.Len(t, actual.samples, len(expected.samples)) + for j, actualSample := range actual.samples { + expectedSample := expected.samples[j] + assert.Equal(t, expectedSample.value, actualSample.Value[0]) + expectedSampleLabels := parseSampleLabels(t, lookup, expectedSample.labels) + assert.Equal(t, expectedSampleLabels, actualSample.Label, fmt.Sprintf("want: %s, got %s", + formatSampleLabels(reverseLookup, expectedSampleLabels), + formatSampleLabels(reverseLookup, actualSample.Label))) + } + } + }) + } +} + +func stringLookup(p *profilev1.Profile) func(string) int64 { + stringIndex := map[string]int64{"": 0} + return func(s string) int64 { + if idx, ok := stringIndex[s]; ok { + return idx + } + i := int64(len(p.StringTable)) + p.StringTable = append(p.StringTable, s) + stringIndex[s] = i + return i + } +} + +func stringReverseLookup(p *profilev1.Profile) func(int64) string { + return func(i int64) string { + return p.StringTable[i] + } +} + +func parseLabels(t *testing.T, s string) []*typesv1.LabelPair { + if s == "" { + // To simplify assertions we return an empty slice instead of nil. + return []*typesv1.LabelPair{} + } + var labels []*typesv1.LabelPair + for _, pair := range strings.Split(s, ",") { + parts := strings.SplitN(pair, "=", 2) + if len(parts) != 2 { + t.Fatal("invalid series labels:", s) + } + labels = append(labels, &typesv1.LabelPair{ + Name: parts[0], + Value: parts[1], + }) + } + return labels +} + +func formatLabels(labels []*typesv1.LabelPair) string { + var b strings.Builder + for i, label := range labels { + if i > 0 { + b.WriteByte(',') + } + b.WriteString(label.Name + "=" + label.Value) + } + return b.String() +} + +func parseSampleLabels(t *testing.T, str func(string) int64, s string) []*profilev1.Label { + if s == "" { + // To simplify assertions we return an empty slice instead of nil. + return []*profilev1.Label{} + } + var labels []*profilev1.Label + for _, pair := range strings.Split(s, ",") { + parts := strings.SplitN(pair, "=", 2) + if len(parts) != 2 { + t.Fatal("invalid sample labels:", s) + } + labels = append(labels, &profilev1.Label{ + Key: str(parts[0]), + Str: str(parts[1]), + }) + } + return labels +} + +func formatSampleLabels(lookup func(int64) string, labels []*profilev1.Label) string { + var b strings.Builder + for i, label := range labels { + if i > 0 { + b.WriteByte(',') + } + b.WriteString(lookup(label.Key) + "=" + lookup(label.Str)) + } + return b.String() +} diff --git a/pkg/model/pprofsplit/pprof_split_test.go b/pkg/model/pprofsplit/pprof_split_test.go new file mode 100644 index 0000000000..d6a450ecdb --- /dev/null +++ b/pkg/model/pprofsplit/pprof_split_test.go @@ -0,0 +1,638 @@ +package pprofsplit + +import ( + "fmt" + "math/rand" + "testing" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +type sampleSeries struct { + labels []*typesv1.LabelPair + samples []*profilev1.Sample +} + +type mockVisitor struct { + profile phlaremodel.Labels + series []sampleSeries + discardedBytes int + discardedProfiles int + err error +} + +func (m *mockVisitor) VisitProfile(labels phlaremodel.Labels) { + m.profile = labels +} + +func (m *mockVisitor) VisitSampleSeries(labels phlaremodel.Labels, samples []*profilev1.Sample) { + m.series = append(m.series, sampleSeries{ + labels: labels, + samples: samples, + }) +} + +func (m *mockVisitor) ValidateLabels(labels phlaremodel.Labels) (phlaremodel.Labels, error) { + return labels, m.err +} + +func (m *mockVisitor) Discarded(profiles, bytes int) { + m.discardedBytes += bytes + m.discardedProfiles += profiles +} + +func Test_VisitSampleSeries(t *testing.T) { + defaultRelabelConfigs := validation.MockDefaultOverrides().IngestionRelabelingRules("") + + type testCase struct { + description string + rules []*relabel.Config + labels []*typesv1.LabelPair + profile *profilev1.Profile + + expected []sampleSeries + expectNoSeries bool + expectLabels phlaremodel.Labels + + expectBytesDropped int + expectProfilesDropped int + } + + testCases := []testCase{ + { + description: "no series labels, no sample labels", + profile: &profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }, + expectNoSeries: true, + expectLabels: nil, + }, + { + description: "has series labels, no sample labels", + labels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + }, + profile: &profilev1.Profile{ + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }, + expectNoSeries: true, + expectLabels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + }, + }, + { + description: "no series labels, all samples have identical label set", + profile: &profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }}, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }, + }, + }, + { + description: "has series labels, all samples have identical label set", + labels: []*typesv1.LabelPair{ + {Name: "baz", Value: "qux"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }}, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "baz", Value: "qux"}, + {Name: "foo", Value: "bar"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }, + }, + }, + { + description: "has series labels, and the only sample label name overlaps with series label, creating overlapping groups", + labels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{"", "foo", "bar"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{2}, + }, + }, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + }, + samples: []*profilev1.Sample{ + { + Value: []int64{3}, + Label: nil, + }, + }, + }, + }, + }, + { + description: "has series labels, samples have distinct label sets", + labels: []*typesv1.LabelPair{ + {Name: "baz", Value: "qux"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{"", "foo", "bar", "waldo", "fred"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 3, Str: 4}, + }, + }, + }, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "baz", Value: "qux"}, + {Name: "foo", Value: "bar"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{1}, + Label: []*profilev1.Label{}, + }}, + }, + { + labels: []*typesv1.LabelPair{ + {Name: "baz", Value: "qux"}, + {Name: "waldo", Value: "fred"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }, + }, + }, + { + description: "has series labels that should be renamed to no longer include godeltaprof", + rules: defaultRelabelConfigs, + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "godeltaprof_memory"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{""}, + Sample: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "__delta__", Value: "false"}, + {Name: "__name__", Value: "memory"}, + {Name: "__name_replaced__", Value: "godeltaprof_memory"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{2}, + Label: []*profilev1.Label{}, + }}, + }, + }, + }, + { + description: "has series labels and sample label, which relabel rules drop", + rules: []*relabel.Config{ + { + Action: relabel.Drop, + SourceLabels: []model.LabelName{"__name__", "span_name"}, + Separator: "/", + Regex: relabel.MustNewRegexp("unwanted/randomness"), + }, + }, + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }, + expectProfilesDropped: 0, + expectBytesDropped: 3, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{1}, + }}, + }, + }, + }, + { + description: "has series/sample labels, drops everything", + rules: []*relabel.Config{ + { + Action: relabel.Drop, + Regex: relabel.MustNewRegexp(".*"), + }, + }, + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }, + expectProfilesDropped: 1, + expectBytesDropped: 6, + expected: []sampleSeries{}, + }, + { + description: "has series labels / sample rules, drops samples label", + rules: []*relabel.Config{ + { + Action: relabel.Replace, + Regex: relabel.MustNewRegexp(".*"), + Replacement: "", + TargetLabel: "span_name", + }, + }, + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{"", "span_name", "randomness"}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + { + Value: []int64{1}, + }, + }, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "unwanted"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{3}, + }}, + }, + }, + }, + { + description: "does not drop samples when a label is dropped", + rules: []*relabel.Config{ + { + Action: relabel.LabelDrop, + Regex: relabel.MustNewRegexp("^label_to_drop$"), + }, + }, + labels: []*typesv1.LabelPair{}, + profile: &profilev1.Profile{ + StringTable: []string{"", "label_to_drop", "value_1", "value_2"}, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{2}, + Label: []*profilev1.Label{{Key: 1, Str: 2}}, + }, + { + LocationId: []uint64{1, 3}, + Value: []int64{2}, + Label: []*profilev1.Label{{Key: 1, Str: 2}}, + }, + { + LocationId: []uint64{1, 3}, + Value: []int64{2}, + Label: []*profilev1.Label{{Key: 1, Str: 3}}, // will get merged with the previous one + }, + { + LocationId: []uint64{1, 4}, + Value: []int64{2}, + Label: []*profilev1.Label{{Key: 1, Str: 3}}, + }, + }, + }, + expectProfilesDropped: 0, + expectBytesDropped: 0, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{}, + samples: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Label: []*profilev1.Label{}, + Value: []int64{2}, + }, + { + LocationId: []uint64{1, 3}, + Label: []*profilev1.Label{}, + Value: []int64{4}, + }, + { + LocationId: []uint64{1, 4}, + Label: []*profilev1.Label{}, + Value: []int64{2}, + }, + }, + }, + }, + }, + { + description: "ensure only samples of same stacktraces get grouped", + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{"", "foo", "bar", "binary", "span_id", "aaaabbbbccccdddd", "__name__"}, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{2}, + Label: []*profilev1.Label{ + // This __name__ label is expected to be removed as it overlaps with the series label name + {Key: 6, Str: 1}, + }, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{1}, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{4}, + Label: []*profilev1.Label{ + {Key: 4, Str: 5}, + }, + }, + { + Value: []int64{8}, + }, + { + Value: []int64{16}, + Label: []*profilev1.Label{ + {Key: 1, Str: 2}, + }, + }, + }, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + }, + samples: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{3}, + }, + { + LocationId: []uint64{1, 2}, + Value: []int64{4}, + Label: []*profilev1.Label{ + {Key: 4, Str: 5}, + }, + }, + { + Value: []int64{8}, + }, + }, + }, + { + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + {Name: "foo", Value: "bar"}, + }, + samples: []*profilev1.Sample{{ + Value: []int64{16}, + Label: []*profilev1.Label{}, + }}, + }, + }, + }, + { + description: "merging groups after label drop should preserve all samples", + rules: []*relabel.Config{ + { + Action: relabel.LabelDrop, + Regex: relabel.MustNewRegexp("^drop_me$"), + }, + }, + labels: []*typesv1.LabelPair{}, + profile: &profilev1.Profile{ + StringTable: []string{"", "do_not_drop_me", "drop_me", "a"}, + Sample: []*profilev1.Sample{ + // Group 1: no labels + {LocationId: []uint64{1}, Value: []int64{100}, Label: []*profilev1.Label{}}, + {LocationId: []uint64{2}, Value: []int64{101}, Label: []*profilev1.Label{}}, + // Group 2: do_not_drop_me=a (should stay intact) + {LocationId: []uint64{3}, Value: []int64{200}, Label: []*profilev1.Label{{Key: 1, Str: 3}}}, + {LocationId: []uint64{4}, Value: []int64{201}, Label: []*profilev1.Label{{Key: 1, Str: 3}}}, + // Group 3: drop_me=a (should be merged with the first group) + {LocationId: []uint64{5}, Value: []int64{300}, Label: []*profilev1.Label{{Key: 2, Str: 3}}}, + {LocationId: []uint64{6}, Value: []int64{301}, Label: []*profilev1.Label{{Key: 2, Str: 3}}}, + }, + }, + // After merging, expect 2 groups containing all 6 samples + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{}, + samples: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100}, Label: []*profilev1.Label{}}, + {LocationId: []uint64{2}, Value: []int64{101}, Label: []*profilev1.Label{}}, + {LocationId: []uint64{5}, Value: []int64{300}, Label: []*profilev1.Label{}}, + {LocationId: []uint64{6}, Value: []int64{301}, Label: []*profilev1.Label{}}, + }, + }, + { + labels: []*typesv1.LabelPair{ + {Name: "do_not_drop_me", Value: "a"}, + }, + samples: []*profilev1.Sample{ + {LocationId: []uint64{3}, Value: []int64{200}, Label: []*profilev1.Label{}}, + {LocationId: []uint64{4}, Value: []int64{201}, Label: []*profilev1.Label{}}, + }, + }, + }, + }, + { + description: "trace_id and span_id stay at the sample level and are not promoted to series labels", + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + }, + profile: &profilev1.Profile{ + StringTable: []string{ + "", // 0 + "__name__", // 1 + "trace_id", // 2 + "span_id", // 3 + "aaaabbbbccccdddd11112222ffffeeee", // 4 trace A + "11112222333344445555666677778888", // 5 trace B + "aaaabbbbccccdddd", // 6 span X + "1111222233334444", // 7 span Y + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1, 2}, Value: []int64{1}, Label: []*profilev1.Label{{Key: 2, Str: 4}, {Key: 3, Str: 6}}}, + {LocationId: []uint64{1, 2}, Value: []int64{2}, Label: []*profilev1.Label{{Key: 2, Str: 5}, {Key: 3, Str: 7}}}, + }, + }, + expected: []sampleSeries{ + { + labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + }, + samples: []*profilev1.Sample{ + {LocationId: []uint64{1, 2}, Value: []int64{1}, Label: []*profilev1.Label{{Key: 2, Str: 4}, {Key: 3, Str: 6}}}, + {LocationId: []uint64{1, 2}, Value: []int64{2}, Label: []*profilev1.Label{{Key: 2, Str: 5}, {Key: 3, Str: 7}}}, + }, + }, + }, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.description, func(t *testing.T) { + v := new(mockVisitor) + require.NoError(t, VisitSampleSeries(tc.profile, tc.labels, tc.rules, v)) + assert.Equal(t, tc.expectBytesDropped, v.discardedBytes) + assert.Equal(t, tc.expectProfilesDropped, v.discardedProfiles) + + if tc.expectNoSeries { + assert.Nil(t, v.series) + assert.Equal(t, tc.expectLabels, v.profile) + return + } + + for i, actual := range v.series { + expected := tc.expected[i] + assert.Equal(t, expected.labels, actual.labels) + assert.Equal(t, expected.samples, actual.samples) + } + }) + } +} + +func Benchmark_VisitSampleSeries_HighCardinality(b *testing.B) { + defaultRelabelConfigs := validation.MockDefaultOverrides().IngestionRelabelingRules("") + defaultRelabelConfigs = append(defaultRelabelConfigs, &relabel.Config{ + Action: relabel.LabelDrop, + Regex: relabel.MustNewRegexp("^high_cardinality_label$"), + }) + + stringTable := []string{"", "foo", "bar", "binary", "span_id", "aaaabbbbccccdddd", "high_cardinality_label"} + highCardinalityOffset := int64(len(stringTable)) + for i := 0; i < 10000; i++ { + stringTable = append(stringTable, fmt.Sprintf("value_%d", i)) + } + + profile := &profilev1.Profile{ + StringTable: stringTable, + Location: []*profilev1.Location{{Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1}}}}, + Mapping: []*profilev1.Mapping{{}, {Id: 1, Filename: 3}}, + Function: []*profilev1.Function{{Id: 1, Name: 1}}, + } + + for i := 0; i < 30000; i++ { + labelValue := highCardinalityOffset + int64(i/10) + if rand.Float64() < 0.3 { + labelValue = highCardinalityOffset - 2 // lower the cardinality to create large groups + } + labels := []*profilev1.Label{ + {Key: highCardinalityOffset - 1, Str: labelValue}, + } + profile.Sample = append(profile.Sample, &profilev1.Sample{ + LocationId: []uint64{uint64(i + 1)}, + Value: []int64{2}, + Label: labels, + }) + } + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + visitor := new(mockVisitor) + err := VisitSampleSeries(profile, []*typesv1.LabelPair{ + {Name: "__name__", Value: "profile"}, + {Name: "foo", Value: "bar"}, + }, defaultRelabelConfigs, visitor) + require.NoError(b, err) + } +} diff --git a/pkg/model/profile.go b/pkg/model/profile.go index 6d4c00aac0..21dad72767 100644 --- a/pkg/model/profile.go +++ b/pkg/model/profile.go @@ -8,14 +8,12 @@ import ( "strings" "github.com/cespare/xxhash/v2" - "github.com/gogo/status" "github.com/prometheus/prometheus/model/labels" - "google.golang.org/grpc/codes" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) // CompareProfile compares the two profiles. @@ -31,7 +29,7 @@ func ParseProfileTypeSelector(id string) (*typesv1.ProfileType, error) { parts := strings.Split(id, ":") if len(parts) != 5 && len(parts) != 6 { - return nil, status.Errorf(codes.InvalidArgument, "profile-type selection must be of the form ::::(:delta), got(%d): %q", len(parts), id) + return nil, fmt.Errorf("profile-type selection must be of the form ::::(:delta), got(%d): %q", len(parts), id) } name, sampleType, sampleUnit, periodType, periodUnit := parts[0], parts[1], parts[2], parts[3], parts[4] return &typesv1.ProfileType{ @@ -53,6 +51,38 @@ func SelectorFromProfileType(profileType *typesv1.ProfileType) *labels.Matcher { } } +type TraceID [16]byte + +func DecodeTraceID(s string) (TraceID, error) { + var t TraceID + if len(s) != 32 { + return t, fmt.Errorf("invalid trace id length: %q", s) + } + if _, err := hex.Decode(t[:], []byte(s)); err != nil { + return t, err + } + return t, nil +} + +func (t TraceID) String() string { + return hex.EncodeToString(t[:]) +} + +// TraceSelector keys on the raw 128-bit TraceID, unlike SpanSelector's uint64. +type TraceSelector map[TraceID]struct{} + +func NewTraceSelector(traces []string) (TraceSelector, error) { + m := make(TraceSelector, len(traces)) + for _, s := range traces { + t, err := DecodeTraceID(s) + if err != nil { + return nil, err + } + m[t] = struct{}{} + } + return m, nil +} + type SpanSelector map[uint64]struct{} func NewSpanSelector(spans []string) (SpanSelector, error) { @@ -70,29 +100,26 @@ func NewSpanSelector(spans []string) (SpanSelector, error) { return m, nil } -func StacktracePartitionFromProfile(lbls []Labels, p *profilev1.Profile) uint64 { - return xxhash.Sum64String(stacktracePartitionKeyFromProfile(lbls, p)) +func SymbolsPartitionForProfile(ls Labels, partitionLabel string, p *profilev1.Profile) uint64 { + return xxhash.Sum64String(symbolsPartitionKeyForProfile(ls, partitionLabel, p)) } -func stacktracePartitionKeyFromProfile(lbls []Labels, p *profilev1.Profile) string { - // take the first mapping (which is the main binary's file basename) - if len(p.Mapping) > 0 { - if filenameID := p.Mapping[0].Filename; filenameID > 0 { - if filename := extractMappingFilename(p.StringTable[filenameID]); filename != "" { - return filename +func symbolsPartitionKeyForProfile(ls Labels, partitionLabel string, p *profilev1.Profile) string { + if partitionLabel == "" { + // Only use the main binary's file basename as the partition key + // if the partition label is not specified. + if len(p.Mapping) > 0 { + if filenameID := p.Mapping[0].Filename; filenameID > 0 { + if filename := extractMappingFilename(p.StringTable[filenameID]); filename != "" { + return filename + } } } + partitionLabel = LabelNameServiceName } - - // failing that look through the labels for the ServiceName - if len(lbls) > 0 { - for _, lbl := range lbls[0] { - if lbl.Name == LabelNameServiceName { - return lbl.Value - } - } + if value := ls.Get(partitionLabel); value != "" { + return value } - return "unknown" } @@ -102,7 +129,8 @@ func extractMappingFilename(filename string) string { if filename == "" || strings.HasPrefix(filename, "[") || strings.HasPrefix(filename, "linux-vdso") || - strings.HasPrefix(filename, "/dev/dri/") { + strings.HasPrefix(filename, "/dev/dri/") || + strings.HasPrefix(filename, "//anon") { return "" } // Like filepath.ToSlash but doesn't rely on OS. diff --git a/pkg/model/profile_test.go b/pkg/model/profile_test.go index c703e5e699..19c0f18c2a 100644 --- a/pkg/model/profile_test.go +++ b/pkg/model/profile_test.go @@ -4,9 +4,13 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" ) -func Test_filename_extraction(t *testing.T) { +func Test_extractMappingFilename(t *testing.T) { assert.Equal(t, "app", extractMappingFilename(`app`)) assert.Equal(t, "app", extractMappingFilename(`./app`)) assert.Equal(t, "app", extractMappingFilename(`/usr/bin/app`)) @@ -32,5 +36,380 @@ func Test_filename_extraction(t *testing.T) { assert.Equal(t, "", extractMappingFilename("")) assert.Equal(t, "", extractMappingFilename(`[vdso]`)) assert.Equal(t, "", extractMappingFilename(`[vsyscall]`)) + assert.Equal(t, "", extractMappingFilename(`//anon`)) assert.Equal(t, "not a path actually", extractMappingFilename(`not a path actually`)) } + +func Test_symbolsPartitionKeyForProfile(t *testing.T) { + tests := []struct { + name string + partitionLabel string + labels Labels + profile *profilev1.Profile + expected string + }{ + { + partitionLabel: "", + profile: &profilev1.Profile{Mapping: []*profilev1.Mapping{}}, + expected: "unknown", + }, + { + partitionLabel: "", + profile: &profilev1.Profile{Mapping: []*profilev1.Mapping{}}, + labels: Labels{{Name: LabelNameServiceName, Value: "service_foo"}}, + expected: "service_foo", + }, + { + partitionLabel: "", + profile: &profilev1.Profile{ + Mapping: []*profilev1.Mapping{{Filename: 1}}, + StringTable: []string{"", "filename"}, + }, + expected: "filename", + }, + { + partitionLabel: "partition", + profile: &profilev1.Profile{}, + labels: Labels{{Name: "partition", Value: "partitionValue"}}, + expected: "partitionValue", + }, + { // partition label is specified but not found: mapping is ignored. + partitionLabel: "partition", + profile: &profilev1.Profile{ + Mapping: []*profilev1.Mapping{{Filename: 1}}, + StringTable: []string{"", "valid_filename"}, + }, + expected: "unknown", + }, + { + partitionLabel: "partition", + profile: &profilev1.Profile{ + Mapping: []*profilev1.Mapping{{Filename: 1}}, + StringTable: []string{"", "valid_filename"}, + }, + expected: "partitionValue", + labels: Labels{{Name: "partition", Value: "partitionValue"}}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := symbolsPartitionKeyForProfile(tt.labels, tt.partitionLabel, tt.profile) + assert.Equal(t, tt.expected, actual) + }) + } +} + +func TestDecodeTraceID(t *testing.T) { + tests := []struct { + name string + input string + wantErr bool + }{ + {name: "valid", input: "0123456789abcdef0123456789abcdef"}, + {name: "too short", input: "0123456789abcdef", wantErr: true}, + {name: "too long", input: "0123456789abcdef0123456789abcdef00", wantErr: true}, + {name: "invalid hex", input: "0123456789abcdef0123456789abcdeg", wantErr: true}, + {name: "empty", input: "", wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tid, err := DecodeTraceID(tt.input) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + // Round-trip: hex string → TraceID → hex string + assert.Equal(t, tt.input, tid.String()) + // Verify raw bytes are correct + assert.Equal(t, + [16]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, + [16]byte(tid)) + } + }) + } +} + +func TestNewTraceSelector(t *testing.T) { + t.Run("decodes and dedups trace ids", func(t *testing.T) { + id := "0123456789abcdef0123456789abcdef" + sel, err := NewTraceSelector([]string{id, id}) + require.NoError(t, err) + require.Len(t, sel, 1) + want, err := DecodeTraceID(id) + require.NoError(t, err) + _, ok := sel[want] + assert.True(t, ok) + }) + + t.Run("empty input yields empty selector", func(t *testing.T) { + sel, err := NewTraceSelector(nil) + require.NoError(t, err) + assert.Empty(t, sel) + }) + + t.Run("invalid trace id returns error", func(t *testing.T) { + _, err := NewTraceSelector([]string{"tooshort"}) + require.Error(t, err) + }) +} + +func Test_ParseProfileTypeSelector(t *testing.T) { + tests := []struct { + Name string + ID string + Want *typesv1.ProfileType + WantErr string + }{ + { + Name: "block_contentions_count", + ID: "block:contentions:count:contentions:count", + Want: &typesv1.ProfileType{ + Name: "block", + ID: "block:contentions:count:contentions:count", + SampleType: "contentions", + SampleUnit: "count", + PeriodType: "contentions", + PeriodUnit: "count", + }, + }, + { + Name: "mutex_delay_nanoseconds", + ID: "mutex:delay:nanoseconds:contentions:count", + Want: &typesv1.ProfileType{ + Name: "mutex", + ID: "mutex:delay:nanoseconds:contentions:count", + SampleType: "delay", + SampleUnit: "nanoseconds", + PeriodType: "contentions", + PeriodUnit: "count", + }, + }, + { + Name: "memory_alloc_space_bytes", + ID: "memory:alloc_space:bytes:space:bytes", + Want: &typesv1.ProfileType{ + Name: "memory", + ID: "memory:alloc_space:bytes:space:bytes", + SampleType: "alloc_space", + SampleUnit: "bytes", + PeriodType: "space", + PeriodUnit: "bytes", + }, + }, + { + Name: "too_few_parts", + ID: "memory:alloc_space:bytes:space", + WantErr: `profile-type selection must be of the form ::::(:delta), got(4): "memory:alloc_space:bytes:space"`, + }, + { + Name: "too_many_parts", + ID: "memory:alloc_space:bytes:space:bytes:extra:part", + WantErr: `profile-type selection must be of the form ::::(:delta), got(7): "memory:alloc_space:bytes:space:bytes:extra:part"`, + }, + { + Name: "empty_string", + ID: "", + WantErr: `profile-type selection must be of the form ::::(:delta), got(1): ""`, + }, + { + Name: "valid_with_delta", + ID: "cpu:samples:count:cpu:nanoseconds:delta", + Want: &typesv1.ProfileType{ + Name: "cpu", + ID: "cpu:samples:count:cpu:nanoseconds:delta", + SampleType: "samples", + SampleUnit: "count", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + got, err := ParseProfileTypeSelector(tt.ID) + if tt.WantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.WantErr) + } else { + require.NoError(t, err) + require.Equal(t, tt.Want, got) + } + }) + } +} + +func Test_ParseProfileTypeSelector_ValidProfileTypes(t *testing.T) { + // Shamelessly copied from: https://github.com/grafana/profiles-drilldown/blob/4e261a8744034bddefdec757d5d2e1d8dc0ec2bb/src/shared/infrastructure/profile-metrics/profile-metrics.json#L93 + var validProfileTypes = map[string]*typesv1.ProfileType{ + "block:contentions:count:contentions:count": { + ID: "block:contentions:count:contentions:count", + Name: "block", + SampleType: "contentions", + SampleUnit: "count", + PeriodType: "contentions", + PeriodUnit: "count", + }, + "block:delay:nanoseconds:contentions:count": { + ID: "block:delay:nanoseconds:contentions:count", + Name: "block", + SampleType: "delay", + SampleUnit: "nanoseconds", + PeriodType: "contentions", + PeriodUnit: "count", + }, + "goroutine:goroutine:count:goroutine:count": { + ID: "goroutine:goroutine:count:goroutine:count", + Name: "goroutine", + SampleType: "goroutine", + SampleUnit: "count", + PeriodType: "goroutine", + PeriodUnit: "count", + }, + "goroutines:goroutine:count:goroutine:count": { + ID: "goroutines:goroutine:count:goroutine:count", + Name: "goroutines", + SampleType: "goroutine", + SampleUnit: "count", + PeriodType: "goroutine", + PeriodUnit: "count", + }, + "memory:alloc_in_new_tlab_bytes:bytes::": { + ID: "memory:alloc_in_new_tlab_bytes:bytes::", + Name: "memory", + SampleType: "alloc_in_new_tlab_bytes", + SampleUnit: "bytes", + PeriodType: "", + PeriodUnit: "", + }, + "memory:alloc_in_new_tlab_objects:count::": { + ID: "memory:alloc_in_new_tlab_objects:count::", + Name: "memory", + SampleType: "alloc_in_new_tlab_objects", + SampleUnit: "count", + PeriodType: "", + PeriodUnit: "", + }, + "memory:alloc_objects:count:space:bytes": { + ID: "memory:alloc_objects:count:space:bytes", + Name: "memory", + SampleType: "alloc_objects", + SampleUnit: "count", + PeriodType: "space", + PeriodUnit: "bytes", + }, + "memory:alloc_space:bytes:space:bytes": { + ID: "memory:alloc_space:bytes:space:bytes", + Name: "memory", + SampleType: "alloc_space", + SampleUnit: "bytes", + PeriodType: "space", + PeriodUnit: "bytes", + }, + "memory:inuse_objects:count:space:bytes": { + ID: "memory:inuse_objects:count:space:bytes", + Name: "memory", + SampleType: "inuse_objects", + SampleUnit: "count", + PeriodType: "space", + PeriodUnit: "bytes", + }, + "memory:inuse_space:bytes:space:bytes": { + ID: "memory:inuse_space:bytes:space:bytes", + Name: "memory", + SampleType: "inuse_space", + SampleUnit: "bytes", + PeriodType: "space", + PeriodUnit: "bytes", + }, + "mutex:contentions:count:contentions:count": { + ID: "mutex:contentions:count:contentions:count", + Name: "mutex", + SampleType: "contentions", + SampleUnit: "count", + PeriodType: "contentions", + PeriodUnit: "count", + }, + "mutex:delay:nanoseconds:contentions:count": { + ID: "mutex:delay:nanoseconds:contentions:count", + Name: "mutex", + SampleType: "delay", + SampleUnit: "nanoseconds", + PeriodType: "contentions", + PeriodUnit: "count", + }, + "process_cpu:alloc_samples:count:cpu:nanoseconds": { + ID: "process_cpu:alloc_samples:count:cpu:nanoseconds", + Name: "process_cpu", + SampleType: "alloc_samples", + SampleUnit: "count", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + "process_cpu:alloc_size:bytes:cpu:nanoseconds": { + ID: "process_cpu:alloc_size:bytes:cpu:nanoseconds", + Name: "process_cpu", + SampleType: "alloc_size", + SampleUnit: "bytes", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + "process_cpu:cpu:nanoseconds:cpu:nanoseconds": { + ID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + Name: "process_cpu", + SampleType: "cpu", + SampleUnit: "nanoseconds", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + "process_cpu:exception:count:cpu:nanoseconds": { + ID: "process_cpu:exception:count:cpu:nanoseconds", + Name: "process_cpu", + SampleType: "exception", + SampleUnit: "count", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + "process_cpu:lock_count:count:cpu:nanoseconds": { + ID: "process_cpu:lock_count:count:cpu:nanoseconds", + Name: "process_cpu", + SampleType: "lock_count", + SampleUnit: "count", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + "process_cpu:lock_time:nanoseconds:cpu:nanoseconds": { + ID: "process_cpu:lock_time:nanoseconds:cpu:nanoseconds", + Name: "process_cpu", + SampleType: "lock_time", + SampleUnit: "nanoseconds", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + "process_cpu:samples:count::milliseconds": { + ID: "process_cpu:samples:count::milliseconds", + Name: "process_cpu", + SampleType: "samples", + SampleUnit: "count", + PeriodType: "", + PeriodUnit: "milliseconds", + }, + "process_cpu:samples:count:cpu:nanoseconds": { + ID: "process_cpu:samples:count:cpu:nanoseconds", + Name: "process_cpu", + SampleType: "samples", + SampleUnit: "count", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + }, + } + + for id, want := range validProfileTypes { + t.Run(id, func(t *testing.T) { + got, err := ParseProfileTypeSelector(id) + require.NoError(t, err) + require.Equal(t, want, got) + }) + } +} diff --git a/pkg/model/profiles.go b/pkg/model/profiles.go new file mode 100644 index 0000000000..e5a18da2d7 --- /dev/null +++ b/pkg/model/profiles.go @@ -0,0 +1,123 @@ +package model + +import ( + "github.com/grafana/dskit/multierror" + "github.com/prometheus/common/model" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/util/loser" +) + +type Timestamp interface { + Timestamp() model.Time +} + +type Profile interface { + Labels() Labels + Timestamp +} + +func lessProfile(p1, p2 Profile) bool { + if p1.Timestamp() == p2.Timestamp() { + // todo we could compare SeriesRef here + return CompareLabelPairs(p1.Labels(), p2.Labels()) < 0 + } + return p1.Timestamp() < p2.Timestamp() +} + +type MergeIterator[P Profile] struct { + tree *loser.Tree[P, iter.Iterator[P]] + closeErrs multierror.MultiError + current P + deduplicate bool +} + +// NewMergeIterator returns an iterator that k-way merges the given iterators. +// The given iterators must be sorted by timestamp and labels themselves. +// Optionally, the iterator can deduplicate profiles with the same timestamp and labels. +func NewMergeIterator[P Profile](max P, deduplicate bool, iters ...iter.Iterator[P]) iter.Iterator[P] { + if len(iters) == 0 { + return iter.NewEmptyIterator[P]() + } + if len(iters) == 1 { + // No need to merge a single iterator. + // We should never allow a single iterator to be passed in because + return iters[0] + } + m := &MergeIterator[P]{ + deduplicate: deduplicate, + current: max, + } + m.tree = loser.New( + iters, + max, + func(s iter.Iterator[P]) P { + return s.At() + }, + func(p1, p2 P) bool { + return lessProfile(p1, p2) + }, + func(s iter.Iterator[P]) { + if err := s.Close(); err != nil { + m.closeErrs.Add(err) + } + }) + return m +} + +func (i *MergeIterator[P]) Next() bool { + for i.tree.Next() { + next := i.tree.Winner() + + if !i.deduplicate { + i.current = next.At() + return true + } + if next.At().Timestamp() != i.current.Timestamp() || + CompareLabelPairs(next.At().Labels(), i.current.Labels()) != 0 { + i.current = next.At() + return true + } + + } + return false +} + +func (i *MergeIterator[P]) At() P { + return i.current +} + +func (i *MergeIterator[P]) Err() error { + return i.tree.Err() +} + +func (i *MergeIterator[P]) Close() error { + i.tree.Close() + return i.closeErrs.Err() +} + +type TimeRangedIterator[T Timestamp] struct { + iter.Iterator[T] + min, max model.Time +} + +func NewTimeRangedIterator[T Timestamp](it iter.Iterator[T], min, max model.Time) iter.Iterator[T] { + return &TimeRangedIterator[T]{ + Iterator: it, + min: min, + max: max, + } +} + +func (it *TimeRangedIterator[T]) Next() bool { + for it.Iterator.Next() { + if it.At().Timestamp() < it.min { + continue + } + if it.At().Timestamp() > it.max { + return false + } + return true + } + return false +} diff --git a/pkg/model/profiles_test.go b/pkg/model/profiles_test.go new file mode 100644 index 0000000000..1c69fcc11e --- /dev/null +++ b/pkg/model/profiles_test.go @@ -0,0 +1,192 @@ +package model + +import ( + "math" + "testing" + + "github.com/prometheus/common/model" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +var ( + aLabels = LabelsFromStrings("foo", "a") + bLabels = LabelsFromStrings("foo", "b") + cLabels = LabelsFromStrings("foo", "c") +) + +type profile struct { + labels Labels + timestamp model.Time +} + +func (p profile) Labels() Labels { + return p.labels +} + +func (p profile) Timestamp() model.Time { + return p.timestamp +} + +func TestMergeIterator(t *testing.T) { + for _, tt := range []struct { + name string + deduplicate bool + input [][]profile + expected []profile + }{ + { + name: "deduplicate exact", + deduplicate: true, + input: [][]profile{ + { + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + }, + { + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + }, + { + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + }, + }, + expected: []profile{ + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + }, + }, + { + name: "no deduplicate", + input: [][]profile{ + { + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + }, + { + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 3}, + }, + { + {labels: aLabels, timestamp: 2}, + }, + }, + expected: []profile{ + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + {labels: aLabels, timestamp: 3}, + }, + }, + { + name: "deduplicate and sort", + deduplicate: true, + input: [][]profile{ + { + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + {labels: aLabels, timestamp: 4}, + }, + { + {labels: aLabels, timestamp: 1}, + {labels: cLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + }, + { + {labels: aLabels, timestamp: 2}, + {labels: bLabels, timestamp: 4}, + }, + }, + expected: []profile{ + {labels: aLabels, timestamp: 1}, + {labels: aLabels, timestamp: 2}, + {labels: cLabels, timestamp: 2}, + {labels: aLabels, timestamp: 3}, + {labels: aLabels, timestamp: 4}, + {labels: bLabels, timestamp: 4}, + }, + }, + } { + tt := tt + t.Run(tt.name, func(t *testing.T) { + iters := make([]iter.Iterator[profile], len(tt.input)) + for i, input := range tt.input { + iters[i] = iter.NewSliceIterator(input) + } + it := NewMergeIterator( + profile{timestamp: math.MaxInt64}, + tt.deduplicate, + iters...) + actual := []profile{} + for it.Next() { + actual = append(actual, it.At()) + } + require.NoError(t, it.Err()) + require.NoError(t, it.Close()) + require.Equal(t, tt.expected, actual) + }) + } +} + +func Test_BufferedIterator(t *testing.T) { + for _, tc := range []struct { + name string + size int + in []profile + }{ + { + name: "empty", + size: 1, + in: nil, + }, + { + name: "smaller than buffer", + size: 1000, + in: generatesProfiles(t, 100), + }, + { + name: "bigger than buffer", + size: 10, + in: generatesProfiles(t, 100), + }, + } { + t.Run(tc.name, func(t *testing.T) { + actual, err := iter.Slice( + iter.NewBufferedIterator( + iter.NewSliceIterator(tc.in), tc.size), + ) + require.NoError(t, err) + require.Equal(t, tc.in, actual) + }) + } +} + +func Test_BufferedIteratorClose(t *testing.T) { + defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) + + it := iter.NewBufferedIterator( + iter.NewSliceIterator(generatesProfiles(t, 100)), 10) + require.NoError(t, it.Close()) +} + +func generatesProfiles(t *testing.T, n int) []profile { + t.Helper() + profiles := make([]profile, n) + for i := range profiles { + profiles[i] = profile{labels: aLabels, timestamp: model.Time(i)} + } + return profiles +} + +// todo test timedRangeIterator diff --git a/pkg/model/recording_rule.go b/pkg/model/recording_rule.go new file mode 100644 index 0000000000..4a1bd356de --- /dev/null +++ b/pkg/model/recording_rule.go @@ -0,0 +1,124 @@ +package model + +import ( + "fmt" + "strings" + + prometheusmodel "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" +) + +type RecordingRule struct { + Matchers []*labels.Matcher + GroupBy []string + ExternalLabels labels.Labels + FunctionName string +} + +const ( + metricNamePrefix = "profiles_recorded_" + RuleIDLabel = "profiles_rule_id" +) + +var uniqueLabels = map[string]bool{ + RuleIDLabel: true, + prometheusmodel.MetricNameLabel: true, +} + +func NewRecordingRule(rule *settingsv1.RecordingRule) (*RecordingRule, error) { + sb := labels.NewScratchBuilder(len(rule.ExternalLabels) + 1) + return newRecordingRuleWithBuilder(rule, &sb) +} + +func newRecordingRuleWithBuilder(rule *settingsv1.RecordingRule, sb *labels.ScratchBuilder) (*RecordingRule, error) { + // validate metric name + if err := ValidateMetricName(rule.MetricName); err != nil { + return nil, err + } + + // ensure __profile_type__ matcher is present + matchers, err := parseMatchers(rule.Matchers) + if err != nil { + return nil, fmt.Errorf("failed to parse matchers: %w", err) + } + var profileTypeMatcher *labels.Matcher + for _, matcher := range matchers { + if matcher.Name == LabelNameProfileType { + profileTypeMatcher = matcher + break + } + } + if profileTypeMatcher == nil { + return nil, fmt.Errorf("no __profile_type__ matcher present") + } + if profileTypeMatcher.Type != labels.MatchEqual { + return nil, fmt.Errorf("__profile_type__ matcher is not an equality") + } + var functionName string + if rule.StacktraceFilter != nil { + if rule.StacktraceFilter.FunctionName != nil { + functionName = rule.StacktraceFilter.FunctionName.FunctionName + } + } + + // validate group_by label names for Prometheus compatibility + for _, labelName := range rule.GroupBy { + name := prometheusmodel.LabelName(labelName) + if !prometheusmodel.LegacyValidation.IsValidLabelName(string(name)) { + return nil, fmt.Errorf("group_by label %q must match %s", labelName, prometheusmodel.LabelNameRE.String()) + } + } + + sb.Reset() + for _, lbl := range rule.ExternalLabels { + // ensure no __name__ or profiles_rule_id labels already exist + if uniqueLabels[lbl.Name] { + // skip + continue + } + // validate external label names for Prometheus compatibility + name := prometheusmodel.LabelName(lbl.Name) + if !prometheusmodel.LegacyValidation.IsValidLabelName(string(name)) { + return nil, fmt.Errorf("external_labels name %q must match %s", lbl.Name, prometheusmodel.LabelNameRE.String()) + } + sb.Add(lbl.Name, lbl.Value) + } + + // trust rule.MetricName + sb.Add(prometheusmodel.MetricNameLabel, rule.MetricName) + // Inject recording rule Id + sb.Add(RuleIDLabel, rule.Id) + + sb.Sort() + + return &RecordingRule{ + Matchers: matchers, + GroupBy: rule.GroupBy, + ExternalLabels: sb.Labels(), + FunctionName: functionName, + }, nil +} + +func parseMatchers(matchers []string) ([]*labels.Matcher, error) { + parsed := make([]*labels.Matcher, 0, len(matchers)) + for _, m := range matchers { + s, err := ParseMetricSelector(m) + if err != nil { + return nil, err + } + parsed = append(parsed, s...) + } + return parsed, nil +} + +func ValidateMetricName(name string) error { + if !prometheusmodel.LegacyValidation.IsValidMetricName(name) { + return fmt.Errorf("invalid metric name: %s", name) + } + if !strings.HasPrefix(name, metricNamePrefix) { + return fmt.Errorf("metric name must start with %s", metricNamePrefix) + } + return nil +} diff --git a/pkg/model/recording_rule_test.go b/pkg/model/recording_rule_test.go new file mode 100644 index 0000000000..64966f90bf --- /dev/null +++ b/pkg/model/recording_rule_test.go @@ -0,0 +1,407 @@ +package model + +import ( + "testing" + + "github.com/stretchr/testify/require" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +func Test_NewRecordingRule_GroupByValidation(t *testing.T) { + tests := []struct { + name string + rule *settingsv1.RecordingRule + wantErr string + }{ + { + name: "valid group_by", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label", "another_valid"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "invalid group_by with dot", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"service.name"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `group_by label "service.name" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + name: "invalid group_by with UTF-8", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"世界"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `group_by label "世界" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + name: "invalid group_by starts with number", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"123invalid"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `group_by label "123invalid" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + name: "invalid group_by with hyphen", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"service-name"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `group_by label "service-name" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewRecordingRule(tt.rule) + if tt.wantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_NewRecordingRule_ExternalLabelsValidation(t *testing.T) { + tests := []struct { + name string + rule *settingsv1.RecordingRule + wantErr string + }{ + { + name: "valid external_labels", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "valid_label", Value: "value"}, + {Name: "another_valid", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "invalid external_labels with dot", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "service.name", Value: "foo"}, + }, + }, + wantErr: `external_labels name "service.name" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + name: "invalid external_labels with UTF-8", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "世界", Value: "value"}, + }, + }, + wantErr: `external_labels name "世界" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + name: "invalid external_labels starts with number", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "123invalid", Value: "value"}, + }, + }, + wantErr: `external_labels name "123invalid" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + name: "invalid external_labels with hyphen", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "service-name", Value: "value"}, + }, + }, + wantErr: `external_labels name "service-name" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + name: "valid external_labels UTF-8 value is allowed", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "valid_label", Value: "世界"}, + }, + }, + wantErr: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewRecordingRule(tt.rule) + if tt.wantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_NewRecordingRule_MetricNameValidation(t *testing.T) { + tests := []struct { + name string + rule *settingsv1.RecordingRule + wantErr string + }{ + { + name: "valid metric_name", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "valid metric_name with underscores and numbers", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test_123", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "invalid metric_name with dot", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded.test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `invalid metric name: profiles_recorded.test`, + }, + { + name: "invalid metric_name with UTF-8", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_世界", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `invalid metric name: profiles_recorded_世界`, + }, + { + name: "invalid metric_name with emoji", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test_😘", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `invalid metric name: profiles_recorded_test_😘`, + }, + { + name: "invalid metric_name starts with number", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "123_invalid", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `invalid metric name: 123_invalid`, + }, + { + name: "invalid metric_name with hyphen", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded-test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `invalid metric name: profiles_recorded-test`, + }, + { + name: "invalid metric_name with exclamation marks", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test!!!", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: `invalid metric name: profiles_recorded_test!!!`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewRecordingRule(tt.rule) + if tt.wantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_NewRecordingRule_MatchersValidation(t *testing.T) { + tests := []struct { + name string + rule *settingsv1.RecordingRule + wantErr string + }{ + { + name: "valid matchers with standard characters", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{__profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "valid matchers with UTF-8 characters", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{service_name="世界", __profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "valid matchers with UTF-8 label names (quoted)", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{"世界"="value", __profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "valid matchers with emojis in label names and values", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{"utf-8 matchers are fine 🔥"="we don't export them", __profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + { + name: "valid matchers with dots in label names", + rule: &settingsv1.RecordingRule{ + Id: "test", + MetricName: "profiles_recorded_test", + Matchers: []string{`{"service.name"="my-service", __profile_type__="cpu"}`}, + GroupBy: []string{"valid_label"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "external_label", Value: "value"}, + }, + }, + wantErr: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewRecordingRule(tt.rule) + if tt.wantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/pkg/model/relabel/relabel.go b/pkg/model/relabel/relabel.go new file mode 100644 index 0000000000..de2c7fe838 --- /dev/null +++ b/pkg/model/relabel/relabel.go @@ -0,0 +1,126 @@ +// Provenance-includes-location: https://github.com/prometheus/prometheus/blob/v2.51.2/model/relabel/relabel.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: Prometheus Authors + +package relabel + +import ( + "crypto/md5" + "encoding/binary" + "fmt" + "strconv" + "strings" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +type Config = relabel.Config + +// Process returns a relabeled version of the given label set. The relabel configurations +// are applied in order of input. +// There are circumstances where Process will modify the input label. +// If you want to avoid issues with the input label set being modified, at the cost of +// higher memory usage, you can use lbls.Copy(). +// If a label set is dropped, EmptyLabels and false is returned. +func Process(lbls phlaremodel.Labels, cfgs ...*relabel.Config) (ret phlaremodel.Labels, keep bool) { + lb := phlaremodel.NewLabelsBuilder(lbls) + if !ProcessBuilder(lb, cfgs...) { + return phlaremodel.EmptyLabels(), false + } + return lb.Labels(), true +} + +// ProcessBuilder is like Process, but the caller passes a labels.Builder +// containing the initial set of labels, which is mutated by the rules. +func ProcessBuilder(lb *phlaremodel.LabelsBuilder, cfgs ...*Config) (keep bool) { + for _, cfg := range cfgs { + keep = relabelBuilder(cfg, lb) + if !keep { + return false + } + } + return true +} + +func relabelBuilder(cfg *Config, lb *phlaremodel.LabelsBuilder) (keep bool) { + var va [16]string + values := va[:0] + if len(cfg.SourceLabels) > cap(values) { + values = make([]string, 0, len(cfg.SourceLabels)) + } + for _, ln := range cfg.SourceLabels { + values = append(values, lb.Get(string(ln))) + } + val := strings.Join(values, cfg.Separator) + + switch cfg.Action { + case relabel.Drop: + if cfg.Regex.MatchString(val) { + return false + } + case relabel.Keep: + if !cfg.Regex.MatchString(val) { + return false + } + case relabel.DropEqual: + if lb.Get(cfg.TargetLabel) == val { + return false + } + case relabel.KeepEqual: + if lb.Get(cfg.TargetLabel) != val { + return false + } + case relabel.Replace: + indexes := cfg.Regex.FindStringSubmatchIndex(val) + // If there is no match no replacement must take place. + if indexes == nil { + break + } + target := model.LabelName(cfg.Regex.ExpandString([]byte{}, cfg.TargetLabel, val, indexes)) + if !model.UTF8Validation.IsValidLabelName(string(target)) { + break + } + res := cfg.Regex.ExpandString([]byte{}, cfg.Replacement, val, indexes) + if len(res) == 0 { + lb.Del(string(target)) + break + } + lb.Set(string(target), string(res)) + case relabel.Lowercase: + lb.Set(cfg.TargetLabel, strings.ToLower(val)) + case relabel.Uppercase: + lb.Set(cfg.TargetLabel, strings.ToUpper(val)) + case relabel.HashMod: + hash := md5.Sum([]byte(val)) + // Use only the last 8 bytes of the hash to give the same result as earlier versions of this code. + mod := binary.BigEndian.Uint64(hash[8:]) % cfg.Modulus + lb.Set(cfg.TargetLabel, strconv.FormatUint(mod, 10)) + case relabel.LabelMap: + lb.Range(func(l *typesv1.LabelPair) { + if cfg.Regex.MatchString(l.Name) { + res := cfg.Regex.ReplaceAllString(l.Name, cfg.Replacement) + lb.Set(res, l.Value) + } + }) + case relabel.LabelDrop: + lb.Range(func(l *typesv1.LabelPair) { + if cfg.Regex.MatchString(l.Name) { + lb.Del(l.Name) + } + }) + case relabel.LabelKeep: + lb.Range(func(l *typesv1.LabelPair) { + if !cfg.Regex.MatchString(l.Name) { + lb.Del(l.Name) + } + }) + default: + panic(fmt.Errorf("relabel: unknown relabel action type %q", cfg.Action)) + } + + return true +} diff --git a/pkg/model/relabel/relabel_test.go b/pkg/model/relabel/relabel_test.go new file mode 100644 index 0000000000..c6508ffe96 --- /dev/null +++ b/pkg/model/relabel/relabel_test.go @@ -0,0 +1,591 @@ +// Provenance-includes-location: https://github.com/prometheus/prometheus/blob/v2.51.2/model/relabel/relabel_test.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: Prometheus Authors + +package relabel + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" + "github.com/prometheus/prometheus/util/testutil" + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +func TestRelabel(t *testing.T) { + tests := []struct { + input phlaremodel.Labels + relabel []*relabel.Config + output phlaremodel.Labels + drop bool + }{ + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b": "bar", + "c": "baz", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("f(.*)"), + TargetLabel: "d", + Separator: ";", + Replacement: "ch${1}-ch${1}", + Action: relabel.Replace, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b": "bar", + "c": "baz", + "d": "choo-choo", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b": "bar", + "c": "baz", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a", "b"}, + Regex: relabel.MustNewRegexp("f(.*);(.*)r"), + TargetLabel: "a", + Separator: ";", + Replacement: "b${1}${2}m", // boobam + Action: relabel.Replace, + }, + { + SourceLabels: model.LabelNames{"c", "a"}, + Regex: relabel.MustNewRegexp("(b).*b(.*)ba(.*)"), + TargetLabel: "d", + Separator: ";", + Replacement: "$1$2$2$3", + Action: relabel.Replace, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "boobam", + "b": "bar", + "c": "baz", + "d": "boooom", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp(".*o.*"), + Action: relabel.Drop, + }, { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("f(.*)"), + TargetLabel: "d", + Separator: ";", + Replacement: "ch$1-ch$1", + Action: relabel.Replace, + }, + }, + drop: true, + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b": "bar", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp(".*o.*"), + Action: relabel.Drop, + }, + }, + drop: true, + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "abc", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp(".*(b).*"), + TargetLabel: "d", + Separator: ";", + Replacement: "$1", + Action: relabel.Replace, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "abc", + "d": "b", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("no-match"), + Action: relabel.Drop, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("f|o"), + Action: relabel.Drop, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("no-match"), + Action: relabel.Keep, + }, + }, + drop: true, + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("f.*"), + Action: relabel.Keep, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + }, + { + // No replacement must be applied if there is no match. + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "boo", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("f"), + TargetLabel: "b", + Replacement: "bar", + Action: relabel.Replace, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "boo", + }), + }, + { + // Blank replacement should delete the label. + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "f": "baz", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("(f).*"), + TargetLabel: "$1", + Replacement: "$2", + Action: relabel.Replace, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b": "bar", + "c": "baz", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"c"}, + TargetLabel: "d", + Separator: ";", + Action: relabel.HashMod, + Modulus: 1000, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b": "bar", + "c": "baz", + "d": "976", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo\nbar", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + TargetLabel: "b", + Separator: ";", + Action: relabel.HashMod, + Modulus: 1000, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo\nbar", + "b": "734", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b1": "bar", + "b2": "baz", + }), + relabel: []*relabel.Config{ + { + Regex: relabel.MustNewRegexp("(b.*)"), + Replacement: "bar_${1}", + Action: relabel.LabelMap, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b1": "bar", + "b2": "baz", + "bar_b1": "bar", + "bar_b2": "baz", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "__meta_my_bar": "aaa", + "__meta_my_baz": "bbb", + "__meta_other": "ccc", + }), + relabel: []*relabel.Config{ + { + Regex: relabel.MustNewRegexp("__meta_(my.*)"), + Replacement: "${1}", + Action: relabel.LabelMap, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "__meta_my_bar": "aaa", + "__meta_my_baz": "bbb", + "__meta_other": "ccc", + "my_bar": "aaa", + "my_baz": "bbb", + }), + }, + { // valid case + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "some-name-value", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("some-([^-]+)-([^,]+)"), + Action: relabel.Replace, + Replacement: "${2}", + TargetLabel: "${1}", + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "some-name-value", + "name": "value", + }), + }, + { // invalid replacement "" + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "some-name-value", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("some-([^-]+)-([^,]+)"), + Action: relabel.Replace, + Replacement: "${3}", + TargetLabel: "${1}", + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "some-name-value", + }), + }, + { // invalid target_labels + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "some-name-0", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("some-([^-]+)-([^,]+)"), + Action: relabel.Replace, + Replacement: "${1}", + TargetLabel: "${3}", + }, + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("some-([^-]+)-([^,]+)"), + Action: relabel.Replace, + Replacement: "${1}", + TargetLabel: "${3}", + }, + { + SourceLabels: model.LabelNames{"a"}, + Regex: relabel.MustNewRegexp("some-([^-]+)(-[^,]+)"), + Action: relabel.Replace, + Replacement: "${1}", + TargetLabel: "${3}", + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "some-name-0", + }), + }, + { // more complex real-life like usecase + input: phlaremodel.LabelsFromMap(map[string]string{ + "__meta_sd_tags": "path:/secret,job:some-job,label:foo=bar", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"__meta_sd_tags"}, + Regex: relabel.MustNewRegexp("(?:.+,|^)path:(/[^,]+).*"), + Action: relabel.Replace, + Replacement: "${1}", + TargetLabel: "__metrics_path__", + }, + { + SourceLabels: model.LabelNames{"__meta_sd_tags"}, + Regex: relabel.MustNewRegexp("(?:.+,|^)job:([^,]+).*"), + Action: relabel.Replace, + Replacement: "${1}", + TargetLabel: "job", + }, + { + SourceLabels: model.LabelNames{"__meta_sd_tags"}, + Regex: relabel.MustNewRegexp("(?:.+,|^)label:([^=]+)=([^,]+).*"), + Action: relabel.Replace, + Replacement: "${2}", + TargetLabel: "${1}", + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "__meta_sd_tags": "path:/secret,job:some-job,label:foo=bar", + "__metrics_path__": "/secret", + "job": "some-job", + "foo": "bar", + }), + }, + { // From https://github.com/prometheus/prometheus/issues/12283 + input: phlaremodel.LabelsFromMap(map[string]string{ + "__meta_kubernetes_pod_container_port_name": "foo", + "__meta_kubernetes_pod_annotation_XXX_metrics_port": "9091", + }), + relabel: []*relabel.Config{ + { + Regex: relabel.MustNewRegexp("^__meta_kubernetes_pod_container_port_name$"), + Action: relabel.LabelDrop, + }, + { + SourceLabels: model.LabelNames{"__meta_kubernetes_pod_annotation_XXX_metrics_port"}, + Regex: relabel.MustNewRegexp("(.+)"), + Action: relabel.Replace, + Replacement: "metrics", + TargetLabel: "__meta_kubernetes_pod_container_port_name", + }, + { + SourceLabels: model.LabelNames{"__meta_kubernetes_pod_container_port_name"}, + Regex: relabel.MustNewRegexp("^metrics$"), + Action: relabel.Keep, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "__meta_kubernetes_pod_annotation_XXX_metrics_port": "9091", + "__meta_kubernetes_pod_container_port_name": "metrics", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b1": "bar", + "b2": "baz", + }), + relabel: []*relabel.Config{ + { + Regex: relabel.MustNewRegexp("(b.*)"), + Action: relabel.LabelKeep, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "b1": "bar", + "b2": "baz", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + "b1": "bar", + "b2": "baz", + }), + relabel: []*relabel.Config{ + { + Regex: relabel.MustNewRegexp("(b.*)"), + Action: relabel.LabelDrop, + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "a": "foo", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "foo": "bAr123Foo", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"foo"}, + Action: relabel.Uppercase, + TargetLabel: "foo_uppercase", + }, + { + SourceLabels: model.LabelNames{"foo"}, + Action: relabel.Lowercase, + TargetLabel: "foo_lowercase", + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "foo": "bAr123Foo", + "foo_lowercase": "bar123foo", + "foo_uppercase": "BAR123FOO", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "__tmp_port": "1234", + "__port1": "1234", + "__port2": "5678", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"__tmp_port"}, + Action: relabel.KeepEqual, + TargetLabel: "__port1", + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "__tmp_port": "1234", + "__port1": "1234", + "__port2": "5678", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "__tmp_port": "1234", + "__port1": "1234", + "__port2": "5678", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"__tmp_port"}, + Action: relabel.DropEqual, + TargetLabel: "__port1", + }, + }, + drop: true, + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "__tmp_port": "1234", + "__port1": "1234", + "__port2": "5678", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"__tmp_port"}, + Action: relabel.DropEqual, + TargetLabel: "__port2", + }, + }, + output: phlaremodel.LabelsFromMap(map[string]string{ + "__tmp_port": "1234", + "__port1": "1234", + "__port2": "5678", + }), + }, + { + input: phlaremodel.LabelsFromMap(map[string]string{ + "__tmp_port": "1234", + "__port1": "1234", + "__port2": "5678", + }), + relabel: []*relabel.Config{ + { + SourceLabels: model.LabelNames{"__tmp_port"}, + Action: relabel.KeepEqual, + TargetLabel: "__port2", + }, + }, + drop: true, + }, + } + + for _, test := range tests { + // Setting default fields, mimicking the behaviour in Prometheus. + for _, cfg := range test.relabel { + if cfg.Action == "" { + cfg.Action = relabel.DefaultRelabelConfig.Action + } + if cfg.Separator == "" { + cfg.Separator = relabel.DefaultRelabelConfig.Separator + } + if cfg.Regex.Regexp == nil || cfg.Regex.String() == "" { + cfg.Regex = relabel.DefaultRelabelConfig.Regex + } + if cfg.Replacement == "" { + cfg.Replacement = relabel.DefaultRelabelConfig.Replacement + } + require.NoError(t, cfg.Validate(model.UTF8Validation)) + } + + res, keep := Process(test.input, test.relabel...) + require.Equal(t, !test.drop, keep) + if keep { + testutil.RequireEqualWithOptions(t, test.output, res, []cmp.Option{cmpopts.IgnoreUnexported(typesv1.LabelPair{})}) + } + } +} diff --git a/pkg/model/sampletype/relabel.go b/pkg/model/sampletype/relabel.go new file mode 100644 index 0000000000..4b9d0d4f3d --- /dev/null +++ b/pkg/model/sampletype/relabel.go @@ -0,0 +1,35 @@ +package sampletype + +import ( + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/slices" + "github.com/grafana/pyroscope/v2/pkg/validation" + + "github.com/prometheus/prometheus/model/relabel" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + phlarerelabel "github.com/grafana/pyroscope/v2/pkg/model/relabel" +) + +func Relabel(p validation.ValidatedProfile, rules []*relabel.Config, labels []*typesv1.LabelPair) { + if len(rules) == 0 { + return + } + keeps := make([]bool, len(p.SampleType)) + for i, st := range p.SampleType { + lb := phlaremodel.NewLabelsBuilder(labels) + lb.Set("__type__", p.StringTable[st.Type]) + lb.Set("__unit__", p.StringTable[st.Unit]) + _, keep := phlarerelabel.Process(lb.Labels(), rules...) + keeps[i] = keep + } + p.SampleType = slices.RemoveInPlace(p.SampleType, func(_ *googlev1.ValueType, idx int) bool { + return !keeps[idx] + }) + for _, sample := range p.Sample { + sample.Value = slices.RemoveInPlace(sample.Value, func(_ int64, idx int) bool { + return !keeps[idx] + }) + } +} diff --git a/pkg/model/sampletype/relabel_test.go b/pkg/model/sampletype/relabel_test.go new file mode 100644 index 0000000000..2802a7644b --- /dev/null +++ b/pkg/model/sampletype/relabel_test.go @@ -0,0 +1,301 @@ +package sampletype + +import ( + "testing" + + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" + "github.com/stretchr/testify/assert" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func TestRelabelProfile(t *testing.T) { + tests := []struct { + name string + profile *googlev1.Profile + rules []*relabel.Config + expectedTypes []string + expectedValues [][]int64 + }{ + { + name: "drop alloc_objects and alloc_space from memory profile", + profile: &googlev1.Profile{ + StringTable: []string{"", "alloc_objects", "count", "alloc_space", "bytes", "inuse_objects", "inuse_space"}, + SampleType: []*googlev1.ValueType{ + {Type: 1, Unit: 2}, // alloc_objects, count + {Type: 3, Unit: 4}, // alloc_space, bytes + {Type: 5, Unit: 2}, // inuse_objects, count + {Type: 6, Unit: 4}, // inuse_space, bytes + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100, 2048, 50, 1024}}, + {LocationId: []uint64{2}, Value: []int64{200, 4096, 150, 3072}}, + }, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xef}, + {Id: 2, MappingId: 1, Address: 0xcafe000}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + }, + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__type__"}, + Regex: relabel.MustNewRegexp("alloc_.*"), + Action: relabel.Drop, + }, + }, + expectedTypes: []string{"inuse_objects", "inuse_space"}, + expectedValues: [][]int64{ + {50, 1024}, + {150, 3072}, + }, + }, + { + name: "keep only inuse_space", + profile: &googlev1.Profile{ + StringTable: []string{"", "alloc_objects", "count", "alloc_space", "bytes", "inuse_objects", "inuse_space"}, + SampleType: []*googlev1.ValueType{ + {Type: 1, Unit: 2}, // alloc_objects, count + {Type: 3, Unit: 4}, // alloc_space, bytes + {Type: 5, Unit: 2}, // inuse_objects, count + {Type: 6, Unit: 4}, // inuse_space, bytes + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100, 2048, 50, 1024}}, + {LocationId: []uint64{2}, Value: []int64{200, 4096, 150, 3072}}, + }, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xef}, + {Id: 2, MappingId: 1, Address: 0xcafe000}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + }, + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__type__"}, + Regex: relabel.MustNewRegexp("inuse_space"), + Action: relabel.Keep, + }, + }, + expectedTypes: []string{"inuse_space"}, + expectedValues: [][]int64{ + {1024}, + {3072}, + }, + }, + { + name: "drop by unit - drop count types", + profile: &googlev1.Profile{ + StringTable: []string{"", "alloc_objects", "count", "alloc_space", "bytes", "inuse_objects", "inuse_space"}, + SampleType: []*googlev1.ValueType{ + {Type: 1, Unit: 2}, // alloc_objects, count + {Type: 3, Unit: 4}, // alloc_space, bytes + {Type: 5, Unit: 2}, // inuse_objects, count + {Type: 6, Unit: 4}, // inuse_space, bytes + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100, 2048, 50, 1024}}, + }, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xef}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + }, + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__unit__"}, + Regex: relabel.MustNewRegexp("count"), + Action: relabel.Drop, + }, + }, + expectedTypes: []string{"alloc_space", "inuse_space"}, + expectedValues: [][]int64{ + {2048, 1024}, + }, + }, + { + name: "drop all sample types", + profile: &googlev1.Profile{ + StringTable: []string{"", "cpu", "nanoseconds"}, + SampleType: []*googlev1.ValueType{ + {Type: 1, Unit: 2}, // cpu, nanoseconds + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{1000}}, + }, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xef}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + }, + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__type__"}, + Regex: relabel.MustNewRegexp(".*"), + Action: relabel.Drop, + }, + }, + expectedTypes: []string{}, + expectedValues: [][]int64{}, + }, + { + name: "no rules - no changes", + profile: &googlev1.Profile{ + StringTable: []string{"", "cpu", "nanoseconds"}, + SampleType: []*googlev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{1000}}, + }, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xef}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + }, + rules: []*relabel.Config{}, + expectedTypes: []string{"cpu"}, + expectedValues: [][]int64{ + {1000}, + }, + }, + { + name: "complex relabeling with multiple rules", + profile: &googlev1.Profile{ + StringTable: []string{"", "samples", "count", "cpu", "nanoseconds", "wall", "goroutines"}, + SampleType: []*googlev1.ValueType{ + {Type: 1, Unit: 2}, // samples, count + {Type: 3, Unit: 4}, // cpu, nanoseconds + {Type: 5, Unit: 4}, // wall, nanoseconds + {Type: 6, Unit: 2}, // goroutines, count + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{10, 1000000, 2000000, 5}}, + {LocationId: []uint64{2}, Value: []int64{20, 3000000, 4000000, 8}}, + }, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xef}, + {Id: 2, MappingId: 1, Address: 0xcafe000}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + }, + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__type__"}, + Regex: relabel.MustNewRegexp("samples"), + Action: relabel.Drop, + }, + { + SourceLabels: []model.LabelName{"__type__", "__unit__"}, + Separator: "/", + Regex: relabel.MustNewRegexp("goroutines/count"), + Action: relabel.Drop, + }, + }, + expectedTypes: []string{"cpu", "wall"}, + expectedValues: [][]int64{ + {1000000, 2000000}, + {3000000, 4000000}, + }, + }, + { + name: "keep rule with no matches drops everything", + profile: &googlev1.Profile{ + StringTable: []string{"", "cpu", "nanoseconds", "wall"}, + SampleType: []*googlev1.ValueType{ + {Type: 1, Unit: 2}, // cpu, nanoseconds + {Type: 3, Unit: 2}, // wall, nanoseconds + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{1000, 2000}}, + }, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xef}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + }, + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__type__"}, + Regex: relabel.MustNewRegexp("memory"), + Action: relabel.Keep, + }, + }, + expectedTypes: []string{}, + expectedValues: [][]int64{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + check := func(t testing.TB) { + assert.Equal(t, len(tt.expectedTypes), len(tt.profile.SampleType), "sample type count mismatch") + for i, expectedType := range tt.expectedTypes { + actualType := tt.profile.StringTable[tt.profile.SampleType[i].Type] + assert.Equal(t, expectedType, actualType, "sample type at index %d", i) + } + if tt.expectedValues != nil { + assert.Equal(t, len(tt.expectedValues), len(tt.profile.Sample), "sample count mismatch") + for i, sample := range tt.profile.Sample { + if i < len(tt.expectedValues) { + assert.Equal(t, tt.expectedValues[i], sample.Value, "sample values at index %d", i) + } + } + } + } + + p := validation.ValidatedProfile{Profile: pprof.RawFromProto(tt.profile)} + + Relabel(p, tt.rules, nil) + + p.Normalize() + check(t) + }) + } +} + +func TestTestdata(t *testing.T) { + tests := []struct { + f string + rules []*relabel.Config + series phlaremodel.Labels + expectedSize int + expectedNormalizedSize int + }{ + { + f: "../../../pkg/pprof/testdata/heap", + rules: []*relabel.Config{ + { + SourceLabels: []model.LabelName{"__type__", "service_name"}, + Separator: ";", + Regex: relabel.MustNewRegexp("inuse_space;test_service_name"), + Action: relabel.Keep, + }, + }, + series: []*typesv1.LabelPair{{ + Name: "service_name", + Value: "test_service_name", + }}, + expectedSize: 847138, + expectedNormalizedSize: 46178, + }, + } + for _, td := range tests { + t.Run(td.f, func(t *testing.T) { + f, err := pprof.OpenFile(td.f) + require.NoError(t, err) + require.Equal(t, td.expectedSize, f.SizeVT()) + Relabel(validation.ValidatedProfile{Profile: f}, td.rules, td.series) + f.Normalize() + require.Equal(t, td.expectedNormalizedSize, f.SizeVT()) + }) + } +} diff --git a/pkg/model/series.go b/pkg/model/series.go deleted file mode 100644 index 5de5a8f2dd..0000000000 --- a/pkg/model/series.go +++ /dev/null @@ -1,89 +0,0 @@ -package model - -import ( - "sort" - "sync" - - typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" -) - -func MergeSeries(aggregation *typesv1.TimeSeriesAggregationType, series ...[]*typesv1.Series) []*typesv1.Series { - var m *SeriesMerger - if aggregation == nil || *aggregation == typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_SUM { - m = NewSeriesMerger(true) - } else { - m = NewSeriesMerger(false) - } - for _, s := range series { - m.MergeSeries(s) - } - return m.Series() -} - -type SeriesMerger struct { - mu sync.Mutex - series map[uint64]*typesv1.Series - sum bool -} - -// NewSeriesMerger creates a new series merger. If sum is set, samples -// with matching timestamps are summed, otherwise duplicates are retained. -func NewSeriesMerger(sum bool) *SeriesMerger { - return &SeriesMerger{ - series: make(map[uint64]*typesv1.Series), - sum: sum, - } -} - -func (m *SeriesMerger) MergeSeries(s []*typesv1.Series) { - m.mu.Lock() - defer m.mu.Unlock() - for _, x := range s { - h := Labels(x.Labels).Hash() - d, ok := m.series[h] - if !ok { - m.series[h] = x - continue - } - d.Points = append(d.Points, x.Points...) - } -} - -func (m *SeriesMerger) Series() []*typesv1.Series { - if len(m.series) == 0 { - return nil - } - r := make([]*typesv1.Series, len(m.series)) - var i int - for _, s := range m.series { - s.Points = s.Points[:m.mergePoints(s.Points)] - r[i] = s - i++ - } - sort.Slice(r, func(i, j int) bool { - return CompareLabelPairs(r[i].Labels, r[j].Labels) < 0 - }) - return r -} - -func (m *SeriesMerger) mergePoints(points []*typesv1.Point) int { - l := len(points) - if l < 2 { - return l - } - sort.Slice(points, func(i, j int) bool { - return points[i].Timestamp < points[j].Timestamp - }) - var j int - for i := 1; i < l; i++ { - if points[j].Timestamp != points[i].Timestamp || !m.sum { - j++ - points[j] = points[i] - continue - } - if m.sum { - points[j].Value += points[i].Value - } - } - return j + 1 -} diff --git a/pkg/model/series_test.go b/pkg/model/series_test.go deleted file mode 100644 index f947942cd0..0000000000 --- a/pkg/model/series_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package model - -import ( - "testing" - - typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/testhelper" -) - -func Test_SeriesMerger(t *testing.T) { - for _, tc := range []struct { - name string - in [][]*typesv1.Series - out []*typesv1.Series - }{ - { - name: "empty", - in: [][]*typesv1.Series{}, - out: []*typesv1.Series(nil), - }, - { - name: "merge two series", - in: [][]*typesv1.Series{ - { - {Labels: LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, - }, - { - {Labels: LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 2}}}, - }, - }, - out: []*typesv1.Series{ - {Labels: LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}}}, - }, - }, - { - name: "merge multiple series", - in: [][]*typesv1.Series{ - { - {Labels: LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, - {Labels: LabelsFromStrings("foor", "buzz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, - }, - { - {Labels: LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 2}}}, - {Labels: LabelsFromStrings("foor", "buzz"), Points: []*typesv1.Point{{Timestamp: 3, Value: 3}}}, - }, - }, - out: []*typesv1.Series{ - {Labels: LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}}}, - {Labels: LabelsFromStrings("foor", "buzz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 3, Value: 3}}}, - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - testhelper.EqualProto(t, tc.out, MergeSeries(nil, tc.in...)) - }) - } -} - -func Test_SeriesMerger_Overlap_Sum(t *testing.T) { - for _, tc := range []struct { - name string - in [][]*typesv1.Series - out []*typesv1.Series - }{ - { - name: "merge deduplicate overlapping series", - in: [][]*typesv1.Series{ - { - {Labels: LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, - {Labels: LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, - }, - { - {Labels: LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, - {Labels: LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, - }, - }, - out: []*typesv1.Series{ - {Labels: LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 1}}}, - {Labels: LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 1}}}, - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - testhelper.EqualProto(t, tc.out, MergeSeries(nil, tc.in...)) - }) - } -} diff --git a/pkg/model/stack.go b/pkg/model/stack.go index 4c6a64599f..43304f5aba 100644 --- a/pkg/model/stack.go +++ b/pkg/model/stack.go @@ -17,7 +17,7 @@ var stackNodePool = sync.Pool{ type stackNode struct { xOffset int level int - node *node + node *node[FunctionName] } // Stack is a stack of values. Pushing and popping values is O(1). diff --git a/pkg/model/stacktraces.go b/pkg/model/stacktraces.go index ca0d1fc203..2318bf6ca2 100644 --- a/pkg/model/stacktraces.go +++ b/pkg/model/stacktraces.go @@ -2,13 +2,13 @@ package model import ( "bytes" - "container/heap" "io" "sync" "unsafe" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - "github.com/grafana/pyroscope/pkg/og/util/varint" + "github.com/grafana/pyroscope/v2/pkg/og/util/varint" + "github.com/grafana/pyroscope/v2/pkg/util/minheap" ) // TODO(kolesnikovae): Remove support for StacktracesMergeFormat_MERGE_FORMAT_STACKTRACES. @@ -213,26 +213,24 @@ func (t *StacktraceTree) LookupLocations(dst []uint64, idx int32) []uint64 { // MinValue returns the minimum "total" value a node in a tree has to have. func (t *StacktraceTree) MinValue(maxNodes int64) int64 { - // TODO(kolesnikovae): Consider quickselect. if maxNodes < 1 || maxNodes >= int64(len(t.Nodes)) { return 0 } - s := make(minHeap, 0, maxNodes) - h := &s + h := make([]int64, 0, maxNodes) for _, n := range t.Nodes { - if h.Len() >= int(maxNodes) { - if n.Total > (*h)[0] { - heap.Pop(h) + if len(h) >= int(maxNodes) { + if n.Total > h[0] { + h = minheap.Pop(h) } else { continue } } - heap.Push(h, n.Total) + h = minheap.Push(h, n.Total) } - if h.Len() < int(maxNodes) { + if len(h) < int(maxNodes) { return 0 } - return (*h)[0] + return h[0] } type StacktraceTreeTraverseFn = func(index int32, children []int32) error @@ -315,40 +313,60 @@ func unsafeStringBytes(s string) []byte { return unsafe.Slice(unsafe.StringData(s), len(s)) } -func (t *StacktraceTree) Tree(maxNodes int64, names []string) *Tree { - if len(t.Nodes) < 2 || len(names) == 0 { +func (t *StacktraceTree) Tree(maxNodes int64, names []FunctionName) *FunctionNameTree { + if len(names) == 0 { + return new(FunctionNameTree) + } + lookup := func(i int32) FunctionName { + return names[i] + } + return TreeFromStacktraceTree[FunctionName, FunctionNameI](t, maxNodes, lookup) +} + +func TreeFromStacktraceTree[N NodeName, I NodeNameI[N]](t *StacktraceTree, maxNodes int64, lookup func(int32) N) *Tree[N, I] { + var initializer I + if len(t.Nodes) < 2 { // stack trace tree has root at 0: trees with less // than 2 nodes are considered empty. - return new(Tree) + return new(Tree[N, I]) } nodesSize := maxNodes if nodesSize < 1 || nodesSize > 10<<10 { nodesSize = 1 << 10 // Sane default. } - root := new(node) // Virtual root node. - nodes := make([]*node, 1, nodesSize) + root := new(node[N]) // Virtual root node. + nodes := make([]*node[N], 1, nodesSize) nodes[0] = root - var current *node + var current *node[N] + + nodeBuf := newNodeBuffer[N](int(nodesSize)) _ = t.Traverse(maxNodes, func(index int32, children []int32) error { current, nodes = nodes[len(nodes)-1], nodes[:len(nodes)-1] sn := &t.Nodes[index] - var name string + var name N if sn.Location < 0 { - name = truncatedNodeName + name = initializer.newOther() + sn.Total = sn.Value } else { - name = names[sn.Location] + name = lookup(sn.Location) } - n := current.insert(name) + n := current.insert(name, nodeBuf.newNode) n.self = sn.Value n.total = sn.Total - n.children = make([]*node, 0, len(children)) + n.children = make([]*node[N], 0, len(children)) for i := 0; i < len(children); i++ { nodes = append(nodes, n) } return nil }) - return &Tree{root: root.children[0].children} + // Roots should not have parents. + s := root.children[0].children + for _, n := range s { + n.parent.parent = nil + } + + return &Tree[N, I]{root: s} } diff --git a/pkg/model/stacktraces_test.go b/pkg/model/stacktraces_test.go index 637a5e09ca..c463d30437 100644 --- a/pkg/model/stacktraces_test.go +++ b/pkg/model/stacktraces_test.go @@ -13,7 +13,7 @@ func TestStackTraceMerger(t *testing.T) { name string in []*ingestv1.MergeProfilesStacktracesResult maxNodes int64 - expected *Tree + expected *FunctionNameTree }{ { name: "empty", @@ -140,7 +140,7 @@ func TestStackTraceMerger(t *testing.T) { m.MergeStackTraces(x.Stacktraces, x.FunctionNames) } yn := m.TreeBytes(tc.maxNodes) - actual, err := UnmarshalTree(yn) + actual, err := UnmarshalTree[FunctionName, FunctionNameI](yn) require.NoError(t, err) require.Equal(t, tc.expected.String(), actual.String()) }) diff --git a/pkg/model/symbolref/bench_test.go b/pkg/model/symbolref/bench_test.go new file mode 100644 index 0000000000..53a513bdc5 --- /dev/null +++ b/pkg/model/symbolref/bench_test.go @@ -0,0 +1,105 @@ +package symbolref_test + +// Benchmarks below cover Table's intern/merge throughput and +// ResultBuilder's marshal-time compaction. Rebuild's own memory/throughput +// benchmark, and a wire-size-vs-literal-encoding benchmark, are deferred +// until Rebuild is implemented. + +import ( + "fmt" + "testing" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/symbolref" +) + +// benchNames is the fixed set of resolved names every benchmark variant +// interns alongside its unresolved addresses, approximating a realistic +// resolved/unresolved mix. +var benchNames = []string{ + "main", "runtime.gopark", "runtime.mallocgc", "net/http.(*conn).serve", "runtime.selectgo", +} + +// buildBenchTree interns benchNames plus numAddresses addresses (spread +// across numBuildIDs build IDs, starting at addrBase) into table, and +// inserts one two-level stack per address (rooted at a name, cycling +// through benchNames) so every interned ref is referenced by the tree. +func buildBenchTree(table *symbolref.Table, numAddresses, numBuildIDs int, addrBase uint64) *model.LocationRefNameTree { + nameRefs := make([]model.LocationRefName, len(benchNames)) + for i, n := range benchNames { + nameRefs[i] = table.InternName(n) + } + tree := new(model.LocationRefNameTree) + for a := range numAddresses { + buildID := fmt.Sprintf("build-%d", a%numBuildIDs) + ref := table.InternUnresolved(buildID, "binary-"+buildID, addrBase+uint64(a)) + tree.InsertStack(1, nameRefs[a%len(nameRefs)], ref) + } + return tree +} + +// benchmarkInternAndAdd measures combined InternName+InternUnresolved+Add +// throughput at a given cardinality. +func benchmarkInternAndAdd(b *testing.B, numAddresses, numBuildIDs int) { + // Pre-build the "second table"'s wire form once: Add's cost scales with + // its size, not its content, so it need not vary per iteration. Its + // addresses are offset past dst's own range so each iteration's Add + // call grows dst by numAddresses new entries (a realistic mixed-dataset + // merge) rather than only exercising the dedup path. + source := buildPartial(func(table *symbolref.Table) *model.LocationRefNameTree { + return buildBenchTree(table, numAddresses, numBuildIDs, uint64(numAddresses)) + }) + + inputSize := numAddresses + b.ReportAllocs() + for b.Loop() { + dst := symbolref.NewTable() + for _, n := range benchNames { + dst.InternName(n) + } + for a := range numAddresses { + buildID := fmt.Sprintf("build-%d", a%numBuildIDs) + dst.InternUnresolved(buildID, "binary-"+buildID, uint64(a)) + } + if _, err := dst.Add(source.pb); err != nil { + b.Fatal(err) + } + } + + opsPerSec := float64(b.N*inputSize) / b.Elapsed().Seconds() + b.ReportMetric(opsPerSec, "ops/sec") + b.ReportMetric(float64(inputSize), "input_size") +} + +// BenchmarkInternAndAdd_small: single-dataset, lightly unsymbolized. +func BenchmarkInternAndAdd_small(b *testing.B) { benchmarkInternAndAdd(b, 100, 1) } + +// BenchmarkInternAndAdd_medium: typical mixed-language service. +func BenchmarkInternAndAdd_medium(b *testing.B) { benchmarkInternAndAdd(b, 10_000, 10) } + +// BenchmarkInternAndAdd_large: eBPF whole-host profile, worst case for +// deferred truncation. +func BenchmarkInternAndAdd_large(b *testing.B) { benchmarkInternAndAdd(b, 1_000_000, 100) } + +// BenchmarkResultBuilderBuild builds a 100,000-node LocationRefNameTree with +// a realistic resolved/unresolved mix, and measures +// tree.Bytes(0, rb.KeepRef) + rb.Build(pb) wall time and allocations. +func BenchmarkResultBuilderBuild(b *testing.B) { + const ( + numNodes = 100_000 + numBuildIDs = 10 + ) + table := symbolref.NewTable() + tree := buildBenchTree(table, numNodes, numBuildIDs, 0) + + b.ReportAllocs() + for b.Loop() { + rb := table.ResultBuilder() + tree.Bytes(0, rb.KeepRef) + pb := new(queryv1.SymbolRefTable) + rb.Build(pb) + } + + b.ReportMetric(float64(numNodes), "input_size") +} diff --git a/pkg/model/symbolref/doc.go b/pkg/model/symbolref/doc.go new file mode 100644 index 0000000000..12bb4a1de8 --- /dev/null +++ b/pkg/model/symbolref/doc.go @@ -0,0 +1,23 @@ +// Package symbolref implements symbol-aware tree references: a +// model.LocationRefNameTree node name can refer to either a resolved frame +// name or an unresolved native {buildID, address} location, sharing a +// single integer reference space (model.LocationRefName) alongside a side +// table (queryv1.SymbolRefTable). This lets a partial or merged tree carry +// unresolved locations through query-plan merges without leaving the +// native tree representation, deferring resolution and truncation until +// after the final merge. +// +// Responsibility boundary: +// +// Owns: the symbol-reference table (interning and deduplication), ref-space +// partitioning (resolved vs. unresolved vs. the truncation "other" +// sentinel), merge-time ref rebasing, marshal-time compaction and +// ordering, deferred-truncation bookkeeping, grouping unresolved +// references into per-build-ID resolution jobs, and rebuilding/truncating +// the final resolved tree. +// +// Does NOT own: the generic tree node/marshal format (pkg/model's Tree, +// reused unchanged), building per-dataset trees from block data +// (pkg/phlaredb/symdb, pkg/querybackend), fetching or resolving debug info +// (pkg/symbolizer), or query orchestration (pkg/frontend/...). +package symbolref diff --git a/pkg/model/symbolref/symbolref_test.go b/pkg/model/symbolref/symbolref_test.go new file mode 100644 index 0000000000..f7b96e31de --- /dev/null +++ b/pkg/model/symbolref/symbolref_test.go @@ -0,0 +1,574 @@ +package symbolref_test + +// Jobs and Rebuild are not implemented in this package yet; tests exercising +// them, and the parts of the tests below that would need them, are deferred +// to a follow-up change. + +import ( + "cmp" + "fmt" + "slices" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/symbolref" +) + +// identity renders ref as a string uniquely identifying the resolved name or +// (buildID, binaryName, address) location it stands for, for stack-shape +// comparisons that must survive a change of ref space. +func identity(t *testing.T, pb *queryv1.SymbolRefTable, ref model.LocationRefName) string { + t.Helper() + if ref == model.OtherLocationRef { + return "other" + } + names := pb.GetNames() + if int(ref) < len(names) { + return "name:" + names[ref] + } + i := int(ref) - len(names) + require.Less(t, i, len(pb.GetUnresolvedAddress()), "ref %d out of range", ref) + bi := pb.GetUnresolvedBuildId()[i] + require.Less(t, int(bi), len(pb.GetBuildIds()), "build id index %d out of range", bi) + return fmt.Sprintf("loc:%s|%s@%#x", pb.GetBuildIds()[bi], pb.GetBinaryNames()[bi], pb.GetUnresolvedAddress()[i]) +} + +// stacksByIdentity walks every stack in tree and sums self values keyed by +// the root-to-leaf sequence of identity() strings, so two trees using +// different (arbitrary) ref numbering can be compared for the same logical +// content. +func stacksByIdentity(t *testing.T, tree *model.LocationRefNameTree, pb *queryv1.SymbolRefTable) map[string]int64 { + t.Helper() + out := make(map[string]int64) + tree.IterateStacks(func(_ model.LocationRefName, self int64, stack []model.LocationRefName) { + slices.Reverse(stack) + ids := make([]string, len(stack)) + for i, ref := range stack { + ids[i] = identity(t, pb, ref) + } + out[strings.Join(ids, "/")] += self + }) + return out +} + +// marshalWire marshals tree via rb.KeepRef and unmarshals the result, +// returning both the marshaled bytes and a tree whose node names are in the +// wire encoding (matching whatever rb.Build subsequently writes), unlike +// tree's own (Table-internal) node names. +func marshalWire(t *testing.T, tree *model.LocationRefNameTree, rb *symbolref.ResultBuilder) ([]byte, *model.LocationRefNameTree) { + t.Helper() + b := tree.Bytes(0, rb.KeepRef) + out, err := model.UnmarshalTree[model.LocationRefName, model.LocationRefNameI](b) + require.NoError(t, err) + return b, out +} + +// testPartial is a marshaled (tree, table) pair, as a producer would send +// one over the wire in a queryv1.TreeReport. +type testPartial struct { + tree []byte + pb *queryv1.SymbolRefTable +} + +// buildPartial constructs a fresh Table, lets build populate a tree using +// the table's Intern* methods, and marshals both via ResultBuilder — the +// same sequence a real producer would follow. +func buildPartial(build func(*symbolref.Table) *model.LocationRefNameTree) testPartial { + table := symbolref.NewTable() + tree := build(table) + rb := table.ResultBuilder() + treeBytes := tree.Bytes(0, rb.KeepRef) + pb := new(queryv1.SymbolRefTable) + rb.Build(pb) + return testPartial{tree: treeBytes, pb: pb} +} + +// TestInternIdempotencyAndDedup verifies InternName and InternUnresolved are +// idempotent and content-addressed, and that the wire encoding they end up +// producing splits resolved and unresolved refs into disjoint ranges. +func TestInternIdempotencyAndDedup(t *testing.T) { + table := symbolref.NewTable() + + foo1 := table.InternName("foo") + bar := table.InternName("bar") + loc2000a := table.InternUnresolved("build1", "bin1", 0x2000) + foo2 := table.InternName("foo") + loc1000a := table.InternUnresolved("build1", "bin1", 0x1000) + foo3 := table.InternName("foo") + loc2000b := table.InternUnresolved("build1", "bin1", 0x2000) + loc1000b := table.InternUnresolved("build1", "bin1", 0x1000) + loc1000c := table.InternUnresolved("build1", "bin1", 0x1000) + loc1000renamed := table.InternUnresolved("build1", "bin1-renamed", 0x1000) + + require.Equal(t, foo1, foo2) + require.Equal(t, foo1, foo3) + require.Equal(t, loc1000a, loc1000b) + require.Equal(t, loc1000a, loc1000c) + require.Equal(t, loc2000a, loc2000b) + require.NotEqual(t, foo1, bar) + require.NotEqual(t, loc1000a, loc2000a) + require.NotEqual(t, loc1000a, loc1000renamed, + "same (buildID, addr) under a different binary name must be a distinct ref") + + tree := new(model.LocationRefNameTree) + tree.InsertStack(1, foo1) + tree.InsertStack(1, bar) + tree.InsertStack(1, loc1000a) + tree.InsertStack(1, loc2000a) + + // InternName/InternUnresolved's return values are Table's internal + // representation, meaningful only as tree node names; the resolved/ + // unresolved range split applies to the wire encoding + // ResultBuilder.KeepRef produces during a real marshal, so capture what + // it actually assigns each ref. + rb := table.ResultBuilder() + wireOf := make(map[model.LocationRefName]model.LocationRefName) + keepRef := func(ref model.LocationRefName) model.LocationRefName { + out := rb.KeepRef(ref) + wireOf[ref] = out + return out + } + tree.Bytes(0, keepRef) + pb := new(queryv1.SymbolRefTable) + rb.Build(pb) + + for _, resolved := range []model.LocationRefName{foo1, bar} { + require.Less(t, int(wireOf[resolved]), len(pb.GetNames()), "resolved ref %d must be < len(pb.Names)", resolved) + } + for _, unresolved := range []model.LocationRefName{loc1000a, loc2000a} { + require.GreaterOrEqual(t, int(wireOf[unresolved]), len(pb.GetNames()), "unresolved ref %d must be >= len(pb.Names)", unresolved) + } +} + +// TestAddRemapRoundTrip verifies Add's returned remap function, used with +// model.TreeMerger.MergeTreeBytes, preserves per-stack identity and values +// across a change of ref space. +func TestAddRemapRoundTrip(t *testing.T) { + src := symbolref.NewTable() + nameA := src.InternName("a") + nameB := src.InternName("b") + loc := src.InternUnresolved("build1", "bin1", 0x1000) + + srcTree := new(model.LocationRefNameTree) + srcTree.InsertStack(3, nameA, nameB) + srcTree.InsertStack(5, nameA, loc) + srcTree.InsertStack(2, loc) + + srcRB := src.ResultBuilder() + treeBytes, srcWireTree := marshalWire(t, srcTree, srcRB) + srcPB := new(queryv1.SymbolRefTable) + srcRB.Build(srcPB) + want := stacksByIdentity(t, srcWireTree, srcPB) + + dst := symbolref.NewTable() + remap, err := dst.Add(srcPB) + require.NoError(t, err) + + merger := model.NewTreeMerger[model.LocationRefName, model.LocationRefNameI]() + require.NoError(t, merger.MergeTreeBytes(treeBytes, model.WithTreeMergeFormatNodeNames(remap))) + + dstRB := dst.ResultBuilder() + _, dstWireTree := marshalWire(t, merger.Tree(), dstRB) + dstPB := new(queryv1.SymbolRefTable) + dstRB.Build(dstPB) + + got := stacksByIdentity(t, dstWireTree, dstPB) + require.Equal(t, want, got) +} + +// TestMergeDeterminismUnderPermutedArrival verifies that merging the same +// set of partials in any order produces the same per-stack values, the same +// set of resolved names, and the same unresolved wire encoding. +func TestMergeDeterminismUnderPermutedArrival(t *testing.T) { + partials := []testPartial{ + buildPartial(func(table *symbolref.Table) *model.LocationRefNameTree { + shared := table.InternName("shared_fn") + p1 := table.InternName("p1_fn") + loc := table.InternUnresolved("buildA", "binA", 0x100) + tree := new(model.LocationRefNameTree) + tree.InsertStack(3, shared, p1) + tree.InsertStack(1, shared, loc) + return tree + }), + buildPartial(func(table *symbolref.Table) *model.LocationRefNameTree { + shared := table.InternName("shared_fn") + p2 := table.InternName("p2_fn") + locA := table.InternUnresolved("buildA", "binA", 0x100) + locB := table.InternUnresolved("buildB", "binB", 0x200) + tree := new(model.LocationRefNameTree) + tree.InsertStack(4, shared, p2) + tree.InsertStack(2, shared, locA) + tree.InsertStack(6, p2, locB) + return tree + }), + buildPartial(func(table *symbolref.Table) *model.LocationRefNameTree { + p3 := table.InternName("p3_fn") + locB := table.InternUnresolved("buildB", "binB", 0x200) + // Same (buildID, addr) as partials 1 and 2, but stored under a + // renamed binary: the kept name must not depend on which partial + // arrives first. + locA := table.InternUnresolved("buildA", "binA-renamed", 0x100) + tree := new(model.LocationRefNameTree) + tree.InsertStack(5, p3, locB) + tree.InsertStack(7, p3, locA) + return tree + }), + } + + orderings := [][3]int{ + {0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}, + } + + // merge reports the merged result's logical content: per-stack values, + // the set of resolved names, and pb's content-sorted unresolved fields. + // tree.Bytes' raw output and pb.Names' order are deliberately not + // compared: both depend on the merged tree's sibling order, which + // pkg/model's Tree sorts by raw ref value — and that raw value depends + // on how many other names had already been interned in the destination + // table, which is arrival-order-dependent even though the underlying + // data is not. + type mergeResult struct { + stacks map[string]int64 + names map[string]struct{} + unresolved *queryv1.SymbolRefTable + } + + merge := func(ordering [3]int) mergeResult { + dst := symbolref.NewTable() + merger := model.NewTreeMerger[model.LocationRefName, model.LocationRefNameI]() + for _, i := range ordering { + remap, err := dst.Add(partials[i].pb) + require.NoError(t, err) + require.NoError(t, merger.MergeTreeBytes(partials[i].tree, model.WithTreeMergeFormatNodeNames(remap))) + } + rb := dst.ResultBuilder() + _, wire := marshalWire(t, merger.Tree(), rb) + pb := new(queryv1.SymbolRefTable) + rb.Build(pb) + + names := make(map[string]struct{}, len(pb.GetNames())) + for _, n := range pb.GetNames() { + names[n] = struct{}{} + } + return mergeResult{ + stacks: stacksByIdentity(t, wire, pb), + names: names, + unresolved: &queryv1.SymbolRefTable{ + BuildIds: pb.GetBuildIds(), + BinaryNames: pb.GetBinaryNames(), + UnresolvedBuildId: pb.GetUnresolvedBuildId(), + UnresolvedAddress: pb.GetUnresolvedAddress(), + }, + } + } + + want := merge(orderings[0]) + for _, ordering := range orderings[1:] { + got := merge(ordering) + require.Equal(t, want.stacks, got.stacks, "ordering %v produced different stack values", ordering) + require.Equal(t, want.names, got.names, "ordering %v produced a different set of resolved names", ordering) + require.True(t, proto.Equal(want.unresolved, got.unresolved), + "ordering %v produced different unresolved wire ordering (the (buildID, binaryName, address) sort should make this arrival-independent): %v vs %v", + ordering, want.unresolved, got.unresolved) + } +} + +// TestWireOrderingMultipleBuildIDs verifies unresolved wire entries are +// sorted by (buildID, binaryName, address) regardless of intern order, and +// that resolved names never contain a build ID string. +func TestWireOrderingMultipleBuildIDs(t *testing.T) { + table := symbolref.NewTable() + + n1 := table.InternName("n1") + locBbb2 := table.InternUnresolved("bbb", "bin-bbb", 0x2000) + n2 := table.InternName("n2") + locAaa1 := table.InternUnresolved("aaa", "bin-aaa", 0x1000) + locCcc1 := table.InternUnresolved("ccc", "bin-ccc", 0x1000) + locBbb1 := table.InternUnresolved("bbb", "bin-bbb", 0x1000) + locAaa2 := table.InternUnresolved("aaa", "bin-aaa", 0x2000) + // bbb again under a renamed binary, at an address between bbb's other + // two: must sort after both bin-bbb entries, not between them. + locBbbRenamed := table.InternUnresolved("bbb", "bin-bbb-renamed", 0x1500) + + tree := new(model.LocationRefNameTree) + for _, ref := range []model.LocationRefName{n1, n2, locBbb2, locAaa1, locCcc1, locBbb1, locAaa2, locBbbRenamed} { + tree.InsertStack(1, ref) + } + + rb := table.ResultBuilder() + tree.Bytes(0, rb.KeepRef) + pb := new(queryv1.SymbolRefTable) + rb.Build(pb) + + for _, name := range pb.GetNames() { + require.NotContains(t, []string{"aaa", "bbb", "ccc"}, name, "pb.Names must never contain an unresolved build ID") + } + + require.Equal(t, len(pb.GetUnresolvedBuildId()), len(pb.GetUnresolvedAddress())) + keyAt := func(i int) (string, string, uint64) { + row := pb.GetUnresolvedBuildId()[i] + return pb.GetBuildIds()[row], pb.GetBinaryNames()[row], pb.GetUnresolvedAddress()[i] + } + for i := 1; i < len(pb.GetUnresolvedAddress()); i++ { + prevBuildID, prevName, prevAddr := keyAt(i - 1) + buildID, name, addr := keyAt(i) + order := cmp.Or( + cmp.Compare(prevBuildID, buildID), + cmp.Compare(prevName, name), + cmp.Compare(prevAddr, addr), + ) + require.LessOrEqual(t, order, 0, "unresolved entries must be sorted by (buildID, binaryName, address); entry %d (%s, %s, %#x) sorts after (%s, %s, %#x)", + i, prevBuildID, prevName, prevAddr, buildID, name, addr) + } +} + +// TestBinaryNamesRetainedAsStored verifies the renamed-binary case: the same +// build ID stored under two binary names keeps both rows, exactly as stored, +// rather than collapsing to whichever name arrived first. +func TestBinaryNamesRetainedAsStored(t *testing.T) { + table := symbolref.NewTable() + require.Zero(t, table.UnresolvedCount()) + a := table.InternUnresolved("build1", "pyroscope", 0x100) + b := table.InternUnresolved("build1", "pyroscope-server", 0x100) + require.NotEqual(t, a, b) + require.Equal(t, 2, table.UnresolvedCount(), + "the same location under two binary names is two distinct unresolved entries") + + tree := new(model.LocationRefNameTree) + tree.InsertStack(1, a) + tree.InsertStack(1, b) + + rb := table.ResultBuilder() + tree.Bytes(0, rb.KeepRef) + pb := rb.Build(nil) + + require.Equal(t, []string{"build1", "build1"}, pb.GetBuildIds()) + require.Equal(t, []string{"pyroscope", "pyroscope-server"}, pb.GetBinaryNames()) + require.Equal(t, []uint32{0, 1}, pb.GetUnresolvedBuildId()) + require.Equal(t, []uint64{0x100, 0x100}, pb.GetUnresolvedAddress()) +} + +// TestNegativeRefPassthrough verifies model.OtherLocationRef is never +// remapped, reassigned, or dropped by ResultBuilder.KeepRef or by an +// Add-returned remap function. +func TestNegativeRefPassthrough(t *testing.T) { + table := symbolref.NewTable() + table.InternName("foo") + table.InternUnresolved("build1", "bin1", 0x1000) + + rb := table.ResultBuilder() + require.Equal(t, model.OtherLocationRef, rb.KeepRef(model.OtherLocationRef)) + + remap, err := table.Add(&queryv1.SymbolRefTable{ + Names: []string{"bar"}, + BuildIds: []string{"build2"}, + BinaryNames: []string{"bin2"}, + UnresolvedBuildId: []uint32{0}, + UnresolvedAddress: []uint64{0x2000}, + }) + require.NoError(t, err) + require.Equal(t, model.OtherLocationRef, remap(model.OtherLocationRef)) +} + +// TestEmptyTable verifies a fresh Table and its ResultBuilder behave safely +// with nothing interned. Jobs and Rebuild are not implemented in this +// package yet, so their behavior on an empty table is not covered here. +func TestEmptyTable(t *testing.T) { + table := symbolref.NewTable() + require.False(t, table.HasUnresolved()) + + rb := table.ResultBuilder() + built := rb.Build(nil) + require.NotNil(t, built) + require.Equal(t, []string{""}, built.GetNames()) + + pb := new(queryv1.SymbolRefTable) + symbolref.NewTable().ResultBuilder().Build(pb) + // Build writes the full name snapshot, which always includes the + // reserved ref-0 placeholder, so wire refs stay aligned with + // len(pb.Names) no matter which refs a marshaled tree keeps. + require.Equal(t, []string{""}, pb.GetNames()) + require.Empty(t, pb.GetBuildIds()) + require.Empty(t, pb.GetBinaryNames()) + require.Empty(t, pb.GetUnresolvedBuildId()) + require.Empty(t, pb.GetUnresolvedAddress()) +} + +// TestOnlyResolvedTable verifies a table built purely from InternName calls +// reports HasUnresolved() == false and produces no unresolved wire fields. +func TestOnlyResolvedTable(t *testing.T) { + table := symbolref.NewTable() + a := table.InternName("a") + b := table.InternName("b") + c := table.InternName("c") + require.False(t, table.HasUnresolved()) + + tree := new(model.LocationRefNameTree) + tree.InsertStack(1, a) + tree.InsertStack(1, b) + tree.InsertStack(1, c) + + rb := table.ResultBuilder() + // HasUnresolved() is false here, so real truncation (maxNodes > 0) is a + // legitimate use of this same ResultBuilder. + tree.Bytes(2, rb.KeepRef) + pb := new(queryv1.SymbolRefTable) + rb.Build(pb) + + require.False(t, table.HasUnresolved()) + require.Empty(t, pb.GetBuildIds()) + require.Empty(t, pb.GetBinaryNames()) + require.Empty(t, pb.GetUnresolvedBuildId()) + require.Empty(t, pb.GetUnresolvedAddress()) +} + +// TestAddRemapIsTotal verifies the remap Add returns is safe for any ref, +// not only those pb describes: the merge machinery invokes it on a synthetic +// zero-valued name (model.Tree.FormatNodeNames visits its virtual root node) +// even when pb is nil or empty, and a skewed +// peer can send a tree whose refs exceed its table or carry negatives other +// than OtherLocationRef — which would alias the destination table's internal +// unresolved encoding (-2-idx) if passed through. All must degrade to the +// reserved ref 0, not panic or alias. +func TestAddRemapIsTotal(t *testing.T) { + t.Run("nil and empty tables", func(t *testing.T) { + for name, pb := range map[string]*queryv1.SymbolRefTable{ + "nil": nil, + "empty": new(queryv1.SymbolRefTable), + } { + t.Run(name, func(t *testing.T) { + remap, err := symbolref.NewTable().Add(pb) + require.NoError(t, err) + require.Equal(t, model.LocationRefName(0), remap(0)) + require.Equal(t, model.LocationRefName(0), remap(7)) + require.Equal(t, model.OtherLocationRef, remap(model.OtherLocationRef)) + require.Equal(t, model.LocationRefName(0), remap(-2)) + }) + } + }) + + t.Run("ref beyond the table degrades", func(t *testing.T) { + p := buildPartial(func(table *symbolref.Table) *model.LocationRefNameTree { + n := table.InternName("fn") + tree := new(model.LocationRefNameTree) + tree.InsertStack(1, n) + return tree + }) + remap, err := symbolref.NewTable().Add(p.pb) + require.NoError(t, err) + outOfRange := model.LocationRefName(int32(len(p.pb.GetNames())) + int32(len(p.pb.GetUnresolvedAddress()))) + require.Equal(t, model.LocationRefName(0), remap(outOfRange)) + }) + + t.Run("negative wire ref other than OtherLocationRef degrades", func(t *testing.T) { + // The destination has an unresolved entry at internal ref -2; a wire + // ref -2 from a malformed tree must not alias it. + dst := symbolref.NewTable() + dst.InternUnresolved("buildA", "binA", 0x100) + remap, err := dst.Add(new(queryv1.SymbolRefTable)) + require.NoError(t, err) + require.Equal(t, model.LocationRefName(0), remap(-2)) + }) + + t.Run("merging tree bytes against an absent table does not panic", func(t *testing.T) { + p := buildPartial(func(table *symbolref.Table) *model.LocationRefNameTree { + n := table.InternName("fn") + tree := new(model.LocationRefNameTree) + tree.InsertStack(1, n) + return tree + }) + remap, err := symbolref.NewTable().Add(nil) + require.NoError(t, err) + merger := model.NewTreeMerger[model.LocationRefName, model.LocationRefNameI]() + require.NoError(t, merger.MergeTreeBytes(p.tree, model.WithTreeMergeFormatNodeNames(remap))) + }) +} + +// TestPlainFunctionNameAbsorption verifies a plain FunctionName-tree partial +// (as an old backend, or a fully-symbolized dataset, would produce) can be +// absorbed into the symbol-ref space via InternName and merged alongside a +// genuine unresolved partial without sample loss. The Rebuild-dependent +// assertion (that the absorbed samples also survive a final rebuild) is +// deferred: Rebuild is not implemented in this package yet. +func TestPlainFunctionNameAbsorption(t *testing.T) { + plainTree := new(model.FunctionNameTree) + plainTree.InsertStack(7, model.FunctionName("main"), model.FunctionName("plainFn")) + plainTreeBytes := plainTree.Bytes(0, nil) + + refTable := symbolref.NewTable() + locName := refTable.InternName("main") + locUnresolved := refTable.InternUnresolved("buildB", "binB", 0x9000) + refTree := new(model.LocationRefNameTree) + refTree.InsertStack(4, locName, locUnresolved) + refRB := refTable.ResultBuilder() + refTreeBytes := refTree.Bytes(0, refRB.KeepRef) + refPB := new(queryv1.SymbolRefTable) + refRB.Build(refPB) + + dst := symbolref.NewTable() + merger := model.NewTreeMerger[model.LocationRefName, model.LocationRefNameI]() + + // Unmarshal the plain partial and re-insert every stack into a + // LocationRefNameTree via InternName. + plain, err := model.UnmarshalTree[model.FunctionName, model.FunctionNameI](plainTreeBytes) + require.NoError(t, err) + absorbed := new(model.LocationRefNameTree) + plain.IterateStacks(func(_ model.FunctionName, self int64, stack []model.FunctionName) { + slices.Reverse(stack) + refs := make([]model.LocationRefName, len(stack)) + for i, n := range stack { + refs[i] = dst.InternName(string(n)) + } + absorbed.InsertStack(self, refs...) + }) + merger.MergeTree(absorbed) + + remap, err := dst.Add(refPB) + require.NoError(t, err) + require.NoError(t, merger.MergeTreeBytes(refTreeBytes, model.WithTreeMergeFormatNodeNames(remap))) + + require.True(t, dst.HasUnresolved()) + + rb := dst.ResultBuilder() + _, mergedWireTree := marshalWire(t, merger.Tree(), rb) + mergedPB := new(queryv1.SymbolRefTable) + rb.Build(mergedPB) + + stacks := stacksByIdentity(t, mergedWireTree, mergedPB) + require.Equal(t, int64(7), stacks["name:main/name:plainFn"], "partial A's stack must survive absorption with its original self value") +} + +// Wire refs must decode to the right SymbolRefTable rows regardless of +// which refs the marshaled tree keeps: a truncating marshal (or any keep +// set smaller than the table) must not shift unresolved refs relative to +// pb.Names, since the wire contract reads unresolved entry i as +// ref - len(names). +func TestResultBuilder_wireRefsIndependentOfKeptSet(t *testing.T) { + table := symbolref.NewTable() + dropped := table.InternName("dropped_by_truncation") + kept := table.InternName("kept") + droppedU := table.InternUnresolved("build-id-a", "liba.so", 0x10) + keptU := table.InternUnresolved("build-id-b", "libb.so", 0x20) + + rb := table.ResultBuilder() + keptWire := rb.KeepRef(kept) + keptUWire := rb.KeepRef(keptU) + pb := new(queryv1.SymbolRefTable) + rb.Build(pb) + + require.Less(t, int(keptWire), len(pb.Names)) + require.Equal(t, "kept", pb.Names[keptWire]) + + i := int(keptUWire) - len(pb.Names) + require.GreaterOrEqual(t, i, 0, "unresolved wire ref must be >= len(pb.Names)") + require.Less(t, i, len(pb.UnresolvedAddress)) + require.Equal(t, uint64(0x20), pb.UnresolvedAddress[i]) + require.Equal(t, "build-id-b", pb.BuildIds[pb.UnresolvedBuildId[i]]) + + _, _ = dropped, droppedU // interned but never kept: must not shift the wire encoding +} diff --git a/pkg/model/symbolref/table.go b/pkg/model/symbolref/table.go new file mode 100644 index 0000000000..767cddc0a7 --- /dev/null +++ b/pkg/model/symbolref/table.go @@ -0,0 +1,367 @@ +package symbolref + +import ( + "cmp" + "fmt" + "slices" + "sync" + + "github.com/cespare/xxhash/v2" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util/hashedslice" +) + +// Table is a content-addressed intern table pairing a model.LocationRefNameTree +// with the wire-format queryv1.SymbolRefTable it represents. Safe for +// concurrent use: every method locks an internal mutex before touching its +// state. +type Table struct { + mu sync.Mutex + core tableCore +} + +// tableCore is Table's lock-free state; it must only be reached through +// Table, which guards every access with its mutex. +type tableCore struct { + names *hashedslice.Slice[string] + binaries *hashedslice.Slice[binaryKey] + + unresolved map[unresolvedKey]int32 // (binary, addr) -> unresolved index + unresolvedBin []int32 // parallel slices, in intern order + unresolvedAd []uint64 +} + +// binaryKey identifies a binary exactly as stored in the profile data. The +// same build ID may appear under several binary names (e.g. a binary renamed +// between deployments); every (build ID, name) combination is a distinct +// row, so no arrival order can make one stored name overwrite another. +type binaryKey struct { + buildID string + name string +} + +func binaryKeyEq(a, b binaryKey) bool { return a == b } + +var binaryKeySep = []byte{0} + +func (k binaryKey) hash() uint64 { + var d xxhash.Digest + d.Reset() + _, _ = d.WriteString(k.buildID) + _, _ = d.Write(binaryKeySep) // so ("ab","c") and ("a","bc") hash apart + _, _ = d.WriteString(k.name) + return d.Sum64() +} + +// unresolvedKey identifies a distinct unresolved location by its interned +// binary row index and address. +type unresolvedKey struct { + binary int32 + addr uint64 +} + +// NewTable returns an empty table. Ref 0 is reserved as an unused sentinel: +// the tree-merge machinery invokes remap functions on synthetic zero-valued +// names (model.Tree.FormatNodeNames visits its virtual root node), and Add +// remaps refs its input does not describe to the reserved ref — so a real +// name must never land on ref 0. InternName's first call for real content +// returns 1, not 0. +func NewTable() *Table { + return &Table{core: newTableCore()} +} + +func newTableCore() tableCore { + c := tableCore{ + names: hashedslice.New(stringEq), + binaries: hashedslice.New(binaryKeyEq), + unresolved: make(map[unresolvedKey]int32), + } + c.internName("") + return c +} + +func stringEq(a, b string) bool { return a == b } + +// InternName idempotently interns a resolved frame name: the same name +// always returns the same ref, and a name not seen before is assigned a new +// one. +func (t *Table) InternName(name string) model.LocationRefName { + t.mu.Lock() + defer t.mu.Unlock() + return t.core.internName(name) +} + +func (c *tableCore) internName(name string) model.LocationRefName { + return model.LocationRefName(c.names.Add(xxhash.Sum64String(name), name)) +} + +// InternUnresolved idempotently interns an unresolved location, keyed on the +// (buildID, binaryName, addr) triple. The binary name is part of the key — +// the same build ID under two different names yields two distinct refs — so +// every name is retained exactly as stored and the table's content is +// independent of intern or merge arrival order. +func (t *Table) InternUnresolved(buildID, binaryName string, addr uint64) model.LocationRefName { + t.mu.Lock() + defer t.mu.Unlock() + return t.core.internUnresolved(buildID, binaryName, addr) +} + +func (c *tableCore) internUnresolved(buildID, binaryName string, addr uint64) model.LocationRefName { + bin := c.internBinary(binaryKey{buildID: buildID, name: binaryName}) + return c.internUnresolvedRef(bin, addr) +} + +// internUnresolvedRef interns (bin, addr), where bin is already an interned +// binary row index. +func (c *tableCore) internUnresolvedRef(bin int32, addr uint64) model.LocationRefName { + key := unresolvedKey{binary: bin, addr: addr} + if idx, ok := c.unresolved[key]; ok { + return c.unresolvedRef(idx) + } + idx := int32(len(c.unresolvedBin)) + c.unresolved[key] = idx + c.unresolvedBin = append(c.unresolvedBin, bin) + c.unresolvedAd = append(c.unresolvedAd, addr) + return c.unresolvedRef(idx) +} + +func (c *tableCore) internBinary(k binaryKey) int32 { + return c.binaries.Add(k.hash(), k) +} + +// unresolvedRef converts an unresolved entry's slot index into Table's +// internal ref representation, model.LocationRefName(-2-idx) — i.e. -2, -3, +// -4, ... — disjoint from resolved refs (always >= 0) and from +// model.OtherLocationRef (-1), and stable regardless of how many more names +// are interned afterward. This is Table's internal encoding; ResultBuilder +// translates it into the wire encoding once the table is frozen. +func (c *tableCore) unresolvedRef(idx int32) model.LocationRefName { + return model.LocationRefName(-2 - int(idx)) +} + +// HasUnresolved reports whether any unresolved entry has ever landed in t, +// whether via InternUnresolved directly or absorbed via Add. +func (t *Table) HasUnresolved() bool { + t.mu.Lock() + defer t.mu.Unlock() + return t.core.hasUnresolved() +} + +func (c *tableCore) hasUnresolved() bool { + return len(c.unresolvedBin) > 0 +} + +// UnresolvedCount reports the number of distinct unresolved locations +// interned in t, whether via InternUnresolved directly or absorbed via Add. +func (t *Table) UnresolvedCount() int { + t.mu.Lock() + defer t.mu.Unlock() + return len(t.core.unresolvedBin) +} + +// Add merges pb into t, returning a remap function from pb's ref space into +// t's ref space, suitable for model.WithTreeMergeFormatNodeNames. The +// returned remap passes model.OtherLocationRef through unchanged and maps +// every other ref pb does not describe — any other negative, or any +// non-negative when pb is nil or empty — to the reserved ref 0; err is +// non-nil only for structurally malformed input, never to signal "nothing +// to merge". +func (t *Table) Add(pb *queryv1.SymbolRefTable) (func(model.LocationRefName) model.LocationRefName, error) { + t.mu.Lock() + defer t.mu.Unlock() + return t.core.add(pb) +} + +func (c *tableCore) add(pb *queryv1.SymbolRefTable) (func(model.LocationRefName) model.LocationRefName, error) { + if err := validateSymbolRefTable(pb); err != nil { + return nil, err + } + + nameRemap := make([]int32, len(pb.GetNames())) + for i, name := range pb.GetNames() { + nameRemap[i] = c.names.Add(xxhash.Sum64String(name), name) + } + + binRemap := make([]int32, len(pb.GetBuildIds())) + binaryNames := pb.GetBinaryNames() + for i, buildID := range pb.GetBuildIds() { + binRemap[i] = c.internBinary(binaryKey{buildID: buildID, name: binaryNames[i]}) + } + + numNames := len(pb.GetNames()) + unresolvedAddr := pb.GetUnresolvedAddress() + unresolvedRemap := make([]model.LocationRefName, len(unresolvedAddr)) + for i, addr := range unresolvedAddr { + bin := binRemap[pb.GetUnresolvedBuildId()[i]] + unresolvedRemap[i] = c.internUnresolvedRef(bin, addr) + } + + return func(in model.LocationRefName) model.LocationRefName { + if in == model.OtherLocationRef { + return in + } + if in >= 0 && int(in) < numNames { + return model.LocationRefName(nameRemap[in]) + } + if u := int(in) - numNames; in >= 0 && u < len(unresolvedRemap) { + return unresolvedRemap[u] + } + // A ref pb does not describe degrades to the reserved ref 0: a + // non-negative ref beyond pb's ranges (nil/empty or truncated input + // from a skewed peer) would panic, and a negative ref other than + // OtherLocationRef would alias t's internal unresolved encoding. + return 0 + }, nil +} + +// validateSymbolRefTable rejects structurally malformed input: mismatched +// parallel-slice lengths or an out-of-range build ID index. +func validateSymbolRefTable(pb *queryv1.SymbolRefTable) error { + if pb == nil { + return nil + } + if len(pb.GetBinaryNames()) != len(pb.GetBuildIds()) { + return fmt.Errorf("symbolref: binary_names length %d does not match build_ids length %d", + len(pb.GetBinaryNames()), len(pb.GetBuildIds())) + } + if len(pb.GetUnresolvedBuildId()) != len(pb.GetUnresolvedAddress()) { + return fmt.Errorf("symbolref: unresolved_build_id length %d does not match unresolved_address length %d", + len(pb.GetUnresolvedBuildId()), len(pb.GetUnresolvedAddress())) + } + for _, bi := range pb.GetUnresolvedBuildId() { + if int(bi) >= len(pb.GetBuildIds()) { + return fmt.Errorf("symbolref: unresolved_build_id %d out of range (len=%d)", bi, len(pb.GetBuildIds())) + } + } + return nil +} + +// ResultBuilder returns a fresh ResultBuilder snapshotting t for one marshal +// pass. +func (t *Table) ResultBuilder() *ResultBuilder { + t.mu.Lock() + defer t.mu.Unlock() + return t.core.newResultBuilder() +} + +// newResultBuilder snapshots the state a ResultBuilder needs — including the +// (buildID, binaryName, address) sort order over every unresolved entry +// interned so far — so that ResultBuilder holds no reference back to +// tableCore and can safely be used without holding Table's lock. +func (c *tableCore) newResultBuilder() *ResultBuilder { + n := len(c.unresolvedBin) + sorted := make([]int32, n) + for i := range sorted { + sorted[i] = int32(i) + } + slices.SortFunc(sorted, func(a, b int32) int { + ka, kb := c.binaries.Values[c.unresolvedBin[a]], c.binaries.Values[c.unresolvedBin[b]] + return cmp.Or( + cmp.Compare(ka.buildID, kb.buildID), + cmp.Compare(ka.name, kb.name), + cmp.Compare(c.unresolvedAd[a], c.unresolvedAd[b]), + ) + }) + rank := make([]int32, n) + for pos, idx := range sorted { + rank[idx] = int32(pos) + } + + return &ResultBuilder{ + namesLen: c.names.Len(), + namesSl: c.names.Values, + binaries: c.binaries.Values, + unresolvedBin: c.unresolvedBin, + unresolvedAd: c.unresolvedAd, + sortedUnresolved: sorted, + rank: rank, + } +} + +// ResultBuilder encodes a Table's contents into a queryv1.SymbolRefTable at +// marshal time. It is built from a point-in-time snapshot of its Table's +// state, taken under the Table's lock (see tableCore.newResultBuilder); +// ResultBuilder itself holds no reference back to the Table and takes no +// lock of its own, so it is not safe for concurrent use — it is meant to be +// driven single-threaded, once, after every Add/Intern* call on its Table +// has completed. +type ResultBuilder struct { + namesLen int // snapshot of len(names) at construction; the resolved/unresolved dividing line + + namesSl []string // snapshot of the table's interned names + binaries []binaryKey // snapshot of the table's interned (build ID, binary name) rows + + unresolvedBin []int32 // snapshot: binary row index per unresolved entry + unresolvedAd []uint64 // snapshot: address per unresolved entry + + sortedUnresolved []int32 // permutation of [0, len(unresolvedBin)), sorted by (buildID, binaryName, address) + rank []int32 // rank[idx] = position of idx within sortedUnresolved +} + +// KeepRef returns ref's wire encoding, for use as the keepName callback to +// Tree.Bytes/MarshalTruncate. ref is Table's internal encoding (resolved: +// >= 0; model.OtherLocationRef (-1): passed through unchanged; unresolved: +// <= -2, see tableCore.unresolvedRef). +// +// Wire refs are assigned from the snapshot alone — resolved refs keep their +// table index, unresolved refs are offset by the snapshot's name count — +// and Build writes the full snapshot, so the encoding does not depend on +// which refs the marshaled tree keeps. Unresolved wire refs must be final +// the moment they are first returned, while the kept set is still unknown, +// so a kept-set-compacted encoding could not be assigned in this single +// pass without breaking the (buildID, binaryName, address) wire order. +func (rb *ResultBuilder) KeepRef(ref model.LocationRefName) model.LocationRefName { + switch { + case ref == model.OtherLocationRef: + return ref + case ref >= 0: + return ref + default: + idx := -2 - int(ref) + return model.LocationRefName(rb.namesLen + int(rb.rank[idx])) + } +} + +// Build writes pb.Names, pb.BuildIds, pb.BinaryNames, pb.UnresolvedBuildId +// and pb.UnresolvedAddress from the snapshot and returns pb, allocating the +// returned queryv1.SymbolRefTable when pb == nil. Every interned name is +// written, in intern order, so resolved wire refs are the table's own name +// indices and len(pb.Names) always equals the offset KeepRef applies to +// unresolved refs; unresolved entries are sorted by (buildID, binaryName, +// address), which is what makes the unresolved side of the wire encoding +// independent of intern or merge arrival order. Equal binary rows form one +// contiguous run each under that order, so build_ids/binary_names carry +// exactly one row per distinct (build ID, binary name) pair referenced. +func (rb *ResultBuilder) Build(pb *queryv1.SymbolRefTable) *queryv1.SymbolRefTable { + if pb == nil { + pb = &queryv1.SymbolRefTable{} + } + + pb.Names = make([]string, rb.namesLen) + copy(pb.Names, rb.namesSl) + + n := len(rb.sortedUnresolved) + // Reset any rows a reused pb may carry. + pb.BuildIds = nil + pb.BinaryNames = nil + pb.UnresolvedBuildId = make([]uint32, n) + pb.UnresolvedAddress = make([]uint64, n) + + last := int32(-1) + var row uint32 + for out, idx := range rb.sortedUnresolved { + if bin := rb.unresolvedBin[idx]; bin != last { + row = uint32(len(pb.BuildIds)) + b := rb.binaries[bin] + pb.BuildIds = append(pb.BuildIds, b.buildID) + pb.BinaryNames = append(pb.BinaryNames, b.name) + last = bin + } + pb.UnresolvedBuildId[out] = row + pb.UnresolvedAddress[out] = rb.unresolvedAd[idx] + } + + return pb +} diff --git a/pkg/model/testdata/diff_left_tree.bin b/pkg/model/testdata/diff_left_tree.bin new file mode 100644 index 0000000000..40809e2e1e Binary files /dev/null and b/pkg/model/testdata/diff_left_tree.bin differ diff --git a/pkg/model/testdata/diff_right_tree.bin b/pkg/model/testdata/diff_right_tree.bin new file mode 100644 index 0000000000..f4824884a1 Binary files /dev/null and b/pkg/model/testdata/diff_right_tree.bin differ diff --git a/pkg/model/time.go b/pkg/model/time.go index 21bb02f2c6..975684d091 100644 --- a/pkg/model/time.go +++ b/pkg/model/time.go @@ -1,6 +1,11 @@ package model -import "github.com/prometheus/common/model" +import ( + "reflect" + "time" + + "github.com/prometheus/common/model" +) // TimeRangeRequest is a request that has a time interval. type TimeRangeRequest interface { @@ -19,3 +24,34 @@ func GetTimeRange(req TimeRangeRequest) (model.Interval, bool) { End: model.Time(req.GetEnd()), }, true } + +func GetSafeTimeRange(now time.Time, req any) model.Interval { + if r, ok := req.(TimeRangeRequest); ok { + x, ok := GetTimeRange(r) + if ok { + return x + } + } + return model.Interval{ + Start: model.Time(now.Add(-time.Hour).UnixMilli()), + End: model.Time(now.UnixMilli()), + } +} + +func SetTimeRange(r interface{}, startTime, endTime model.Time) bool { + const startFieldName = "Start" + const endFieldName = "End" + defer func() { _ = recover() }() + v := reflect.ValueOf(r).Elem() + startField := v.FieldByName(startFieldName) + endField := v.FieldByName(endFieldName) + if !startField.IsValid() || !endField.IsValid() { + return false + } + if startField.Kind() != reflect.Int64 || endField.Kind() != reflect.Int64 { + return false + } + startField.SetInt(int64(startTime)) + endField.SetInt(int64(endTime)) + return true +} diff --git a/pkg/model/time_test.go b/pkg/model/time_test.go new file mode 100644 index 0000000000..c9957b6308 --- /dev/null +++ b/pkg/model/time_test.go @@ -0,0 +1,22 @@ +package model + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +func Test_SetTimeRange(t *testing.T) { + t.Run("Type has time range fields", func(t *testing.T) { + r := new(typesv1.LabelNamesRequest) + assert.True(t, SetTimeRange(r, 1, 2)) + assert.Equal(t, int64(1), r.Start) + assert.Equal(t, int64(2), r.End) + }) + t.Run("Type has no time range fields", func(t *testing.T) { + r := new(struct{}) + assert.False(t, SetTimeRange(r, 1, 2)) + }) +} diff --git a/pkg/model/timeseries/aggregator.go b/pkg/model/timeseries/aggregator.go new file mode 100644 index 0000000000..2cfac5ee4c --- /dev/null +++ b/pkg/model/timeseries/aggregator.go @@ -0,0 +1,123 @@ +package timeseries + +import ( + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +// DefaultMaxExemplarsPerPoint is the default maximum number of exemplars tracked per point. +// TODO: make it configurable via tenant limits. +const DefaultMaxExemplarsPerPoint = 1 + +type Aggregator interface { + Add(ts int64, point *Value) + GetAndReset() *typesv1.Point + IsEmpty() bool + GetTimestamp() int64 +} + +func NewAggregator(aggregation *typesv1.TimeSeriesAggregationType) Aggregator { + return NewAggregatorWithLimit(aggregation, DefaultMaxExemplarsPerPoint) +} + +func NewAggregatorWithLimit(aggregation *typesv1.TimeSeriesAggregationType, maxExemplarsPerPoint int) Aggregator { + if aggregation == nil { + return &sumAggregator{ts: -1, maxExemplarsPerPoint: maxExemplarsPerPoint} + } + if *aggregation == typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_AVERAGE { + return &avgAggregator{ts: -1, maxExemplarsPerPoint: maxExemplarsPerPoint} + } + return &sumAggregator{ts: -1, maxExemplarsPerPoint: maxExemplarsPerPoint} +} + +type sumAggregator struct { + ts int64 + sum float64 + annotations []*typesv1.ProfileAnnotation + exemplars []*typesv1.Exemplar + maxExemplarsPerPoint int +} + +func (a *sumAggregator) Add(ts int64, point *Value) { + a.ts = ts + a.sum += point.Value + a.annotations = append(a.annotations, point.Annotations...) + + if len(point.Exemplars) > 0 { + a.exemplars = mergeExemplars(a.exemplars, point.Exemplars) + } +} + +func (a *sumAggregator) GetAndReset() *typesv1.Point { + tsCopy := a.ts + sumCopy := a.sum + annotationsCopy := make([]*typesv1.ProfileAnnotation, len(a.annotations)) + copy(annotationsCopy, a.annotations) + + var exemplars []*typesv1.Exemplar + if len(a.exemplars) > 0 { + exemplars = selectTopNExemplarsProto(a.exemplars, a.maxExemplarsPerPoint) + } + + a.ts = -1 + a.sum = 0 + a.annotations = a.annotations[:0] + a.exemplars = nil + + return &typesv1.Point{ + Timestamp: tsCopy, + Value: sumCopy, + Annotations: annotationsCopy, + Exemplars: exemplars, + } +} + +func (a *sumAggregator) IsEmpty() bool { return a.ts == -1 } +func (a *sumAggregator) GetTimestamp() int64 { return a.ts } + +type avgAggregator struct { + ts int64 + sum float64 + count int64 + annotations []*typesv1.ProfileAnnotation + exemplars []*typesv1.Exemplar + maxExemplarsPerPoint int +} + +func (a *avgAggregator) Add(ts int64, point *Value) { + a.ts = ts + a.sum += point.Value + a.count++ + a.annotations = append(a.annotations, point.Annotations...) + + if len(point.Exemplars) > 0 { + a.exemplars = mergeExemplars(a.exemplars, point.Exemplars) + } +} + +func (a *avgAggregator) GetAndReset() *typesv1.Point { + avg := a.sum / float64(a.count) + tsCopy := a.ts + annotationsCopy := make([]*typesv1.ProfileAnnotation, len(a.annotations)) + copy(annotationsCopy, a.annotations) + + var exemplars []*typesv1.Exemplar + if len(a.exemplars) > 0 { + exemplars = selectTopNExemplarsProto(a.exemplars, a.maxExemplarsPerPoint) + } + + a.ts = -1 + a.sum = 0 + a.count = 0 + a.annotations = a.annotations[:0] + a.exemplars = nil + + return &typesv1.Point{ + Timestamp: tsCopy, + Value: avg, + Annotations: annotationsCopy, + Exemplars: exemplars, + } +} + +func (a *avgAggregator) IsEmpty() bool { return a.ts == -1 } +func (a *avgAggregator) GetTimestamp() int64 { return a.ts } diff --git a/pkg/model/timeseries/exemplar_builder.go b/pkg/model/timeseries/exemplar_builder.go new file mode 100644 index 0000000000..eba4c79f4b --- /dev/null +++ b/pkg/model/timeseries/exemplar_builder.go @@ -0,0 +1,111 @@ +package timeseries + +import ( + "sort" + + "github.com/prometheus/common/model" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +// exemplarBuilder builds exemplars for a single time series. +type exemplarBuilder struct { + labelSetIndex map[uint64]int + labelSets []phlaremodel.Labels + exemplars []exemplar +} + +type exemplar struct { + timestamp int64 + profileID string + labelSetRef int + value int64 +} + +// newExemplarBuilder creates a new exemplarBuilder. +func newExemplarBuilder() *exemplarBuilder { + return &exemplarBuilder{ + labelSetIndex: make(map[uint64]int), + labelSets: make([]phlaremodel.Labels, 0), + exemplars: make([]exemplar, 0), + } +} + +// Add adds an exemplar with its full labels. +func (eb *exemplarBuilder) Add(fp model.Fingerprint, labels phlaremodel.Labels, ts int64, profileID string, value int64) { + if profileID == "" { + return + } + + labelSetIdx, exists := eb.labelSetIndex[uint64(fp)] + if !exists { + eb.labelSets = append(eb.labelSets, labels.Clone()) + labelSetIdx = len(eb.labelSets) - 1 + eb.labelSetIndex[uint64(fp)] = labelSetIdx + } + + eb.exemplars = append(eb.exemplars, exemplar{ + timestamp: ts, + profileID: profileID, + labelSetRef: labelSetIdx, + value: value, + }) +} + +// Count returns the number of raw exemplars added. +func (eb *exemplarBuilder) Count() int { + return len(eb.exemplars) +} + +// Build returns the final exemplars, sorted and deduplicated. +// Exemplars with the same (profileID, timestamp) are merged by intersecting their labels. +func (eb *exemplarBuilder) Build() []*typesv1.Exemplar { + if len(eb.exemplars) == 0 { + return nil + } + + sort.Slice(eb.exemplars, func(i, j int) bool { + if eb.exemplars[i].timestamp != eb.exemplars[j].timestamp { + return eb.exemplars[i].timestamp < eb.exemplars[j].timestamp + } + return eb.exemplars[i].profileID < eb.exemplars[j].profileID + }) + + return eb.deduplicateAndIntersect() +} + +// deduplicateAndIntersect merges exemplars with the same profileID, timestamp by intersecting their label sets. +// When multiple exemplars exist for the same (profileID, timestamp), we sum their values. +func (eb *exemplarBuilder) deduplicateAndIntersect() []*typesv1.Exemplar { + result := make([]*typesv1.Exemplar, 0, len(eb.exemplars)) + + i := 0 + for i < len(eb.exemplars) { + curr := eb.exemplars[i] + + labelSetsToIntersect := []phlaremodel.Labels{eb.labelSets[curr.labelSetRef]} + sumValue := curr.value + j := i + 1 + for j < len(eb.exemplars) && + eb.exemplars[j].profileID == curr.profileID && + eb.exemplars[j].timestamp == curr.timestamp { + labelSetsToIntersect = append(labelSetsToIntersect, eb.labelSets[eb.exemplars[j].labelSetRef]) + sumValue += eb.exemplars[j].value + j++ + } + + finalLabels := phlaremodel.IntersectAll(labelSetsToIntersect) + + result = append(result, &typesv1.Exemplar{ + Timestamp: curr.timestamp, + ProfileId: curr.profileID, + Value: sumValue, + Labels: finalLabels, + }) + + i = j + } + + return result +} diff --git a/pkg/model/timeseries/iterator.go b/pkg/model/timeseries/iterator.go new file mode 100644 index 0000000000..9208f64a0a --- /dev/null +++ b/pkg/model/timeseries/iterator.go @@ -0,0 +1,65 @@ +package timeseries + +import ( + "math" + + "github.com/prometheus/common/model" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +type Value struct { + Ts int64 + Lbs []*typesv1.LabelPair + LabelsHash uint64 + Value float64 + Annotations []*typesv1.ProfileAnnotation + Exemplars []*typesv1.Exemplar +} + +func (p Value) Labels() phlaremodel.Labels { return p.Lbs } +func (p Value) Timestamp() model.Time { return model.Time(p.Ts) } + +type Iterator struct { + point []*typesv1.Point + curr Value +} + +func NewSeriesIterator(lbs []*typesv1.LabelPair, points []*typesv1.Point) *Iterator { + return &Iterator{ + point: points, + + curr: Value{ + Lbs: lbs, + LabelsHash: phlaremodel.Labels(lbs).Hash(), + }, + } +} + +func (s *Iterator) Next() bool { + if len(s.point) == 0 { + return false + } + p := s.point[0] + s.point = s.point[1:] + s.curr.Ts = p.Timestamp + s.curr.Value = p.Value + s.curr.Annotations = p.Annotations + + s.curr.Exemplars = p.Exemplars + return true +} + +func (s *Iterator) At() Value { return s.curr } +func (s *Iterator) Err() error { return nil } +func (s *Iterator) Close() error { return nil } + +func NewTimeSeriesMergeIterator(series []*typesv1.Series) iter.Iterator[Value] { + iters := make([]iter.Iterator[Value], 0, len(series)) + for _, s := range series { + iters = append(iters, NewSeriesIterator(s.Labels, s.Points)) + } + return phlaremodel.NewMergeIterator(Value{Ts: math.MaxInt64}, false, iters...) +} diff --git a/pkg/model/timeseries/merger.go b/pkg/model/timeseries/merger.go new file mode 100644 index 0000000000..d4762c8943 --- /dev/null +++ b/pkg/model/timeseries/merger.go @@ -0,0 +1,196 @@ +package timeseries + +import ( + "slices" + "sort" + "strings" + "sync" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +func MergeSeries(aggregation *typesv1.TimeSeriesAggregationType, series ...[]*typesv1.Series) []*typesv1.Series { + var m *Merger + if aggregation == nil || *aggregation == typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_SUM { + m = NewMerger(true) + } else { + m = NewMerger(false) + } + for _, s := range series { + m.MergeTimeSeries(s) + } + return m.TimeSeries() +} + +type Merger struct { + mu sync.Mutex + series map[uint64]*typesv1.Series + sum bool +} + +// NewMerger creates a new series merger. If sum is set, samples +// with matching timestamps are summed, otherwise duplicates are retained. +func NewMerger(sum bool) *Merger { + return &Merger{ + series: make(map[uint64]*typesv1.Series), + sum: sum, + } +} + +func (m *Merger) MergeTimeSeries(s []*typesv1.Series) { + m.mu.Lock() + defer m.mu.Unlock() + for _, x := range s { + h := phlaremodel.Labels(x.Labels).Hash() + d, ok := m.series[h] + if !ok { + m.series[h] = x + continue + } + d.Points = append(d.Points, x.Points...) + } +} + +func (m *Merger) IsEmpty() bool { + return len(m.series) == 0 +} + +func (m *Merger) TimeSeries() []*typesv1.Series { + r := m.mergeTimeSeries() + sort.Slice(r, func(i, j int) bool { + return phlaremodel.CompareLabelPairs(r[i].Labels, r[j].Labels) < 0 + }) + return r +} + +func (m *Merger) mergeTimeSeries() []*typesv1.Series { + if len(m.series) == 0 { + return nil + } + r := make([]*typesv1.Series, len(m.series)) + var i int + for _, s := range m.series { + s.Points = s.Points[:m.mergePoints(s.Points)] + r[i] = s + i++ + } + return r +} + +func (m *Merger) Top(n int) []*typesv1.Series { + return TopSeries(m.mergeTimeSeries(), n) +} + +func (m *Merger) mergePoints(points []*typesv1.Point) int { + l := len(points) + if l < 2 { + return l + } + sort.Slice(points, func(i, j int) bool { + return points[i].Timestamp < points[j].Timestamp + }) + var j int + for i := 1; i < l; i++ { + if points[j].Timestamp != points[i].Timestamp || !m.sum { + j++ + points[j] = points[i] + continue + } + if m.sum { + points[j].Value += points[i].Value + points[j].Annotations = mergeAnnotations(points[j].Annotations, points[i].Annotations) + points[j].Exemplars = mergeExemplars(points[j].Exemplars, points[i].Exemplars) + } + } + return j + 1 +} + +func compareAnnotations(a, b *typesv1.ProfileAnnotation) int { + if r := strings.Compare(a.Key, b.Key); r != 0 { + return r + } + return strings.Compare(a.Value, b.Value) +} + +func mergeAnnotations(a, b []*typesv1.ProfileAnnotation) []*typesv1.ProfileAnnotation { + if len(a) == 0 { + return b + } + if len(b) == 0 { + return a + } + + // Merge into a single slice + merged := append(a, b...) + + // Sort by key and value + slices.SortFunc(merged, compareAnnotations) + + // Remove duplicates in-place + j := 0 + for i := 1; i < len(merged); i++ { + // Only keep if different from the current unique element + if merged[j].Key != merged[i].Key || merged[j].Value != merged[i].Value { + j++ + merged[j] = merged[i] + } + } + + // Return the slice with only unique elements + return merged[:j+1] +} + +// mergeExemplars combines two exemplar lists. +// For exemplars with the same profileID, it keeps the highest value and intersects labels. +func mergeExemplars(a, b []*typesv1.Exemplar) []*typesv1.Exemplar { + if len(a) == 0 { + return b + } + if len(b) == 0 { + return a + } + + type exemplarGroup struct { + exemplar *typesv1.Exemplar + labelSets []phlaremodel.Labels + } + byProfileID := make(map[string]*exemplarGroup) + + for _, ex := range a { + byProfileID[ex.ProfileId] = &exemplarGroup{ + exemplar: ex, + labelSets: []phlaremodel.Labels{ex.Labels}, + } + } + + for _, ex := range b { + existing, found := byProfileID[ex.ProfileId] + if !found { + byProfileID[ex.ProfileId] = &exemplarGroup{ + exemplar: ex, + labelSets: []phlaremodel.Labels{phlaremodel.Labels(ex.Labels)}, + } + } else { + if ex.Value > existing.exemplar.Value { + existing.exemplar = ex + } + existing.labelSets = append(existing.labelSets, phlaremodel.Labels(ex.Labels)) + } + } + + result := make([]*typesv1.Exemplar, 0, len(byProfileID)) + for _, group := range byProfileID { + ex := group.exemplar + if len(group.labelSets) > 1 { + ex.Labels = phlaremodel.IntersectAll(group.labelSets) + } + result = append(result, ex) + } + + sort.Slice(result, func(i, j int) bool { + return result[i].ProfileId < result[j].ProfileId + }) + + return result +} diff --git a/pkg/model/timeseries/merger_test.go b/pkg/model/timeseries/merger_test.go new file mode 100644 index 0000000000..49390dc3b8 --- /dev/null +++ b/pkg/model/timeseries/merger_test.go @@ -0,0 +1,558 @@ +package timeseries + +import ( + "testing" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/testhelper" +) + +func Test_SeriesMerger(t *testing.T) { + for _, tc := range []struct { + name string + in [][]*typesv1.Series + out []*typesv1.Series + }{ + { + name: "empty", + in: [][]*typesv1.Series{}, + out: []*typesv1.Series(nil), + }, + { + name: "merge two series", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + }, + { + {Labels: phlaremodel.LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 2}}}, + }, + }, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}}}, + }, + }, + { + name: "merge multiple series", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foor", "buzz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}}}, + }, + { + {Labels: phlaremodel.LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foor", "buzz"), Points: []*typesv1.Point{{Timestamp: 3, Value: 3}}}, + }, + }, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foor", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foor", "buzz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 3, Value: 3}}}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + testhelper.EqualProto(t, tc.out, MergeSeries(nil, tc.in...)) + }) + } +} + +func Test_SeriesMerger_Annotations(t *testing.T) { + for _, tc := range []struct { + name string + in [][]*typesv1.Series + out []*typesv1.Series + }{ + { + name: "merge two distinct annotations", + in: [][]*typesv1.Series{ + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 1, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + }, + }, + }, + }, + }, + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 2, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value2"}, + }, + }, + }, + }, + }, + }, + out: []*typesv1.Series{ + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 3, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + {Key: "key1", Value: "value2"}, + }, + }, + }, + }, + }, + }, + { + name: "merge duplicate annotations", + in: [][]*typesv1.Series{ + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 1, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + {Key: "key2", Value: "value2"}, + }, + }, + }, + }, + }, + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 2, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + {Key: "key3", Value: "value3"}, + }, + }, + }, + }, + }, + }, + out: []*typesv1.Series{ + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 3, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + {Key: "key2", Value: "value2"}, + {Key: "key3", Value: "value3"}, + }, + }, + }, + }, + }, + }, + { + name: "merge all duplicate annotations", + in: [][]*typesv1.Series{ + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 1, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + {Key: "key2", Value: "value2"}, + }, + }, + }, + }, + }, + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 2, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + {Key: "key2", Value: "value2"}, + }, + }, + }, + }, + }, + }, + out: []*typesv1.Series{ + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 3, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + {Key: "key2", Value: "value2"}, + }, + }, + }, + }, + }, + }, + { + name: "annotations sorted by key then value", + in: [][]*typesv1.Series{ + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 1, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "z", Value: "last"}, + {Key: "a", Value: "first"}, + }, + }, + }, + }, + }, + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 2, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "m", Value: "middle"}, + }, + }, + }, + }, + }, + }, + out: []*typesv1.Series{ + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 3, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "a", Value: "first"}, + {Key: "m", Value: "middle"}, + {Key: "z", Value: "last"}, + }, + }, + }, + }, + }, + }, + { + name: "empty annotations on one side", + in: [][]*typesv1.Series{ + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 1, + Annotations: []*typesv1.ProfileAnnotation{}, + }, + }, + }, + }, + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 2, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + }, + }, + }, + }, + }, + }, + out: []*typesv1.Series{ + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 3, + Annotations: []*typesv1.ProfileAnnotation{ + {Key: "key1", Value: "value1"}, + }, + }, + }, + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + testhelper.EqualProto(t, tc.out, MergeSeries(nil, tc.in...)) + }) + } +} + +func Test_SeriesMerger_Overlap_Sum(t *testing.T) { + for _, tc := range []struct { + name string + in [][]*typesv1.Series + out []*typesv1.Series + }{ + { + name: "merge deduplicate overlapping series", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + }, + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, + }, + }, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 1}}}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + testhelper.EqualProto(t, tc.out, MergeSeries(nil, tc.in...)) + }) + } +} + +func Test_SeriesMerger_Top(t *testing.T) { + for _, tc := range []struct { + name string + in [][]*typesv1.Series + out []*typesv1.Series + top int + }{ + { + name: "top == len", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + }, + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 2}}}, + }, + }, + top: 2, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 1}}}, + }, + }, + { + name: "top < len", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + }, + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 2}}}, + }, + }, + top: 1, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 2}}}, + }, + }, + { + name: "top > len", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + }, + { + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 2}}}, + }, + }, + top: 3, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foo", "baz"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "bar"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 2}, {Timestamp: 3, Value: 1}}}, + }, + }, + { + name: "order", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foo", "d"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "e"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "c"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "a"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "b"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 3}}}, + }, + }, + top: 4, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foo", "b"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 3}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "a"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "c"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "d"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + }, + }, + { + name: "k == 0", + in: [][]*typesv1.Series{ + { + {Labels: phlaremodel.LabelsFromStrings("foo", "d"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "c"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "a"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "b"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 3}}}, + }, + }, + top: 0, + out: []*typesv1.Series{ + {Labels: phlaremodel.LabelsFromStrings("foo", "b"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 3}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "a"), Points: []*typesv1.Point{{Timestamp: 2, Value: 1}, {Timestamp: 3, Value: 2}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "c"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + {Labels: phlaremodel.LabelsFromStrings("foo", "d"), Points: []*typesv1.Point{{Timestamp: 1, Value: 1}, {Timestamp: 2, Value: 1}}}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + m := NewMerger(true) + for _, s := range tc.in { + m.MergeTimeSeries(s) + } + testhelper.EqualProto(t, tc.out, m.Top(tc.top)) + }) + } +} + +func Test_SeriesMerger_WithExemplars(t *testing.T) { + for _, tc := range []struct { + name string + in [][]*typesv1.Series + out []*typesv1.Series + }{ + { + name: "merge keeps highest value exemplar per profile ID", + in: [][]*typesv1.Series{ + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 10, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "prof-1", Value: 100, Timestamp: 1}, + }, + }, + }, + }, + }, + { + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 20, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "prof-1", Value: 500, Timestamp: 1}, + {ProfileId: "prof-2", Value: 200, Timestamp: 1}, + }, + }, + }, + }, + }, + }, + out: []*typesv1.Series{ + { + Labels: phlaremodel.LabelsFromStrings("foo", "bar"), + Points: []*typesv1.Point{ + { + Timestamp: 1, + Value: 30, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "prof-1", Value: 500, Timestamp: 1}, + {ProfileId: "prof-2", Value: 200, Timestamp: 1}, + }, + }, + }, + }, + }, + }, + { + name: "merge preserves exemplar labels", + in: [][]*typesv1.Series{ + { + { + Labels: phlaremodel.LabelsFromStrings("service_name", "api"), + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 100, + Exemplars: []*typesv1.Exemplar{ + { + ProfileId: "prof-1", + Value: 100, + Timestamp: 1000, + Labels: []*typesv1.LabelPair{}, // Simplified for test - merger tests don't need actual labels + }, + }, + }, + }, + }, + }, + }, + out: []*typesv1.Series{ + { + Labels: phlaremodel.LabelsFromStrings("service_name", "api"), + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 100, + Exemplars: []*typesv1.Exemplar{ + { + ProfileId: "prof-1", + Value: 100, + Timestamp: 1000, + Labels: []*typesv1.LabelPair{}, + }, + }, + }, + }, + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + testhelper.EqualProto(t, tc.out, MergeSeries(nil, tc.in...)) + }) + } +} diff --git a/pkg/model/timeseries/range.go b/pkg/model/timeseries/range.go new file mode 100644 index 0000000000..1ce3fc4101 --- /dev/null +++ b/pkg/model/timeseries/range.go @@ -0,0 +1,100 @@ +package timeseries + +import ( + "sort" + + "github.com/samber/lo" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +// RangeSeries aggregates profiles into series. +// Series contains points spaced by step from start to end. +// Profiles from the same step are aggregated into one point. +func RangeSeries(it iter.Iterator[Value], start, end, step int64, aggregation *typesv1.TimeSeriesAggregationType) []*typesv1.Series { + return rangeSeriesWithLimit(it, start, end, step, aggregation, DefaultMaxExemplarsPerPoint) +} + +// rangeSeriesWithLimit is an internal function that allows specifying maxExemplarsPerPoint. +func rangeSeriesWithLimit(it iter.Iterator[Value], start, end, step int64, aggregation *typesv1.TimeSeriesAggregationType, maxExemplarsPerPoint int) []*typesv1.Series { + defer it.Close() + seriesMap := make(map[uint64]*typesv1.Series) + aggregators := make(map[uint64]Aggregator) + + if !it.Next() { + return nil + } + + // advance from the start to the end, adding each step results to the map. +Outer: + for currentStep := start; currentStep <= end; currentStep += step { + for { + point := it.At() + aggregator, ok := aggregators[point.LabelsHash] + if !ok { + aggregator = NewAggregatorWithLimit(aggregation, maxExemplarsPerPoint) + aggregators[point.LabelsHash] = aggregator + } + if point.Ts > currentStep { + if !aggregator.IsEmpty() { + series := seriesMap[point.LabelsHash] + series.Points = append(series.Points, aggregator.GetAndReset()) + } + break // no more profiles for the currentStep + } + // find or create series + series, ok := seriesMap[point.LabelsHash] + if !ok { + seriesMap[point.LabelsHash] = &typesv1.Series{ + Labels: point.Lbs, + Points: []*typesv1.Point{}, + } + aggregator.Add(currentStep, &point) + if !it.Next() { + break Outer + } + continue + } + // Aggregate point if it is in the current step. + if aggregator.GetTimestamp() == currentStep { + aggregator.Add(currentStep, &point) + if !it.Next() { + break Outer + } + continue + } + // Next step is missing + if !aggregator.IsEmpty() { + series.Points = append(series.Points, aggregator.GetAndReset()) + } + aggregator.Add(currentStep, &point) + if !it.Next() { + break Outer + } + } + } + for lblHash, aggregator := range aggregators { + if !aggregator.IsEmpty() { + seriesMap[lblHash].Points = append(seriesMap[lblHash].Points, aggregator.GetAndReset()) + } + } + series := lo.Values(seriesMap) + sort.Slice(series, func(i, j int) bool { + return phlaremodel.CompareLabelPairs(series[i].Labels, series[j].Labels) < 0 + }) + return series +} + +// selectTopNExemplarsProto selects the top-N exemplars by value. +func selectTopNExemplarsProto(exemplars []*typesv1.Exemplar, maxExemplars int) []*typesv1.Exemplar { + if len(exemplars) <= maxExemplars { + return exemplars + } + + sort.Slice(exemplars, func(i, j int) bool { + return exemplars[i].Value > exemplars[j].Value + }) + return exemplars[:maxExemplars] +} diff --git a/pkg/model/timeseries/range_test.go b/pkg/model/timeseries/range_test.go new file mode 100644 index 0000000000..3dc0f27a2b --- /dev/null +++ b/pkg/model/timeseries/range_test.go @@ -0,0 +1,340 @@ +package timeseries + +import ( + "testing" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/testhelper" +) + +func Test_RangeSeriesSum(t *testing.T) { + seriesA := phlaremodel.NewLabelsBuilder(nil).Set("foo", "bar").Labels() + seriesB := phlaremodel.NewLabelsBuilder(nil).Set("foo", "buzz").Labels() + for _, tc := range []struct { + name string + in []Value + out []*typesv1.Series + }{ + { + name: "single series", + in: []Value{ + {Ts: 1, Value: 1}, + {Ts: 1, Value: 1}, + {Ts: 2, Value: 2}, + {Ts: 3, Value: 3}, + {Ts: 4, Value: 4}, + {Ts: 5, Value: 5, Annotations: []*typesv1.ProfileAnnotation{{Key: "foo", Value: "bar"}}}, + }, + out: []*typesv1.Series{ + { + Points: []*typesv1.Point{ + {Timestamp: 1, Value: 2, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 2, Value: 2, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 3, Value: 3, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 4, Value: 4, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 5, Value: 5, Annotations: []*typesv1.ProfileAnnotation{{Key: "foo", Value: "bar"}}}, + }, + }, + }, + }, + { + name: "multiple series", + in: []Value{ + {Ts: 1, Value: 1, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + {Ts: 1, Value: 1, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 2, Value: 1, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + {Ts: 3, Value: 1, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 3, Value: 1, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 4, Value: 4, Lbs: seriesB, LabelsHash: seriesB.Hash(), Annotations: []*typesv1.ProfileAnnotation{{Key: "foo", Value: "bar"}}}, + {Ts: 4, Value: 4, Lbs: seriesB, LabelsHash: seriesB.Hash(), Annotations: []*typesv1.ProfileAnnotation{{Key: "foo", Value: "buzz"}}}, + {Ts: 4, Value: 4, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + {Ts: 5, Value: 5, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + }, + out: []*typesv1.Series{ + { + Labels: seriesA, + Points: []*typesv1.Point{ + {Timestamp: 1, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 2, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 4, Value: 4, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 5, Value: 5, Annotations: []*typesv1.ProfileAnnotation{}}, + }, + }, + { + Labels: seriesB, + Points: []*typesv1.Point{ + {Timestamp: 1, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 3, Value: 2, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 4, Value: 8, Annotations: []*typesv1.ProfileAnnotation{ + {Key: "foo", Value: "bar"}, + {Key: "foo", Value: "buzz"}}}, + }, + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + in := iter.NewSliceIterator(tc.in) + out := RangeSeries(in, 1, 5, 1, nil) + testhelper.EqualProto(t, tc.out, out) + }) + } +} + +func Test_RangeSeriesAvg(t *testing.T) { + seriesA := phlaremodel.NewLabelsBuilder(nil).Set("foo", "bar").Labels() + seriesB := phlaremodel.NewLabelsBuilder(nil).Set("foo", "buzz").Labels() + for _, tc := range []struct { + name string + in []Value + out []*typesv1.Series + }{ + { + name: "single series", + in: []Value{ + {Ts: 1, Value: 1}, + {Ts: 1, Value: 2}, + {Ts: 2, Value: 2}, + {Ts: 2, Value: 3}, + {Ts: 3, Value: 4}, + {Ts: 4, Value: 5, Annotations: []*typesv1.ProfileAnnotation{{Key: "foo", Value: "bar"}}}, + }, + out: []*typesv1.Series{ + { + Points: []*typesv1.Point{ + {Timestamp: 1, Value: 1.5, Annotations: []*typesv1.ProfileAnnotation{}}, // avg of 1 and 2 + {Timestamp: 2, Value: 2.5, Annotations: []*typesv1.ProfileAnnotation{}}, // avg of 2 and 3 + {Timestamp: 3, Value: 4, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 4, Value: 5, Annotations: []*typesv1.ProfileAnnotation{{Key: "foo", Value: "bar"}}}, + }, + }, + }, + }, + { + name: "multiple series", + in: []Value{ + {Ts: 1, Value: 1, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + {Ts: 1, Value: 1, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 2, Value: 1, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + {Ts: 2, Value: 2, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + {Ts: 3, Value: 1, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 3, Value: 2, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 4, Value: 4, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 4, Value: 6, Lbs: seriesB, LabelsHash: seriesB.Hash()}, + {Ts: 4, Value: 4, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + {Ts: 5, Value: 5, Lbs: seriesA, LabelsHash: seriesA.Hash()}, + }, + out: []*typesv1.Series{ + { + Labels: seriesA, + Points: []*typesv1.Point{ + {Timestamp: 1, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 2, Value: 1.5, Annotations: []*typesv1.ProfileAnnotation{}}, // avg of 1 and 2 + {Timestamp: 4, Value: 4, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 5, Value: 5, Annotations: []*typesv1.ProfileAnnotation{}}, + }, + }, + { + Labels: seriesB, + Points: []*typesv1.Point{ + {Timestamp: 1, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 3, Value: 1.5, Annotations: []*typesv1.ProfileAnnotation{}}, // avg of 1 and 2 + {Timestamp: 4, Value: 5, Annotations: []*typesv1.ProfileAnnotation{}}, // avg of 4 and 6 + }, + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + in := iter.NewSliceIterator(tc.in) + aggregation := typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_AVERAGE + out := RangeSeries(in, 1, 5, 1, &aggregation) + testhelper.EqualProto(t, tc.out, out) + }) + } +} + +func Test_RangeSeriesWithExemplars(t *testing.T) { + sum := typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_SUM + + for _, tc := range []struct { + name string + series []*typesv1.Series + start int64 + end int64 + step int64 + aggregation *typesv1.TimeSeriesAggregationType + maxExemplars int // 0 means use default + out []*typesv1.Series + }{ + { + name: "exemplar timestamps preserved during aggregation", + series: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + {Timestamp: 947, Value: 100.0, Exemplars: []*typesv1.Exemplar{{ProfileId: "prof-1", Value: 100, Timestamp: 947}}}, + {Timestamp: 987, Value: 300.0, Exemplars: []*typesv1.Exemplar{{ProfileId: "prof-2", Value: 300, Timestamp: 987}}}, + {Timestamp: 1847, Value: 200.0, Exemplars: []*typesv1.Exemplar{{ProfileId: "prof-3", Value: 200, Timestamp: 1847}}}, + }, + }}, + start: 1000, + end: 3000, + step: 1000, + aggregation: &sum, + out: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + {Timestamp: 1000, Value: 400.0, Annotations: []*typesv1.ProfileAnnotation{}, Exemplars: []*typesv1.Exemplar{{ProfileId: "prof-2", Value: 300, Timestamp: 987}}}, + {Timestamp: 2000, Value: 200.0, Annotations: []*typesv1.ProfileAnnotation{}, Exemplars: []*typesv1.Exemplar{{ProfileId: "prof-3", Value: 200, Timestamp: 1847}}}, + }, + }}, + }, + { + name: "exemplar labels preserved through re-aggregation", + series: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 100.0, + Exemplars: []*typesv1.Exemplar{{ + ProfileId: "prof-1", + Value: 100, + Timestamp: 1000, + Labels: []*typesv1.LabelPair{}, + }}, + }, + }, + }}, + start: 1000, + end: 2000, + step: 1000, + aggregation: &sum, + out: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 100.0, + Annotations: []*typesv1.ProfileAnnotation{}, + Exemplars: []*typesv1.Exemplar{{ + ProfileId: "prof-1", + Value: 100, + Timestamp: 1000, + Labels: []*typesv1.LabelPair{}, + }}, + }, + }, + }}, + }, + { + name: "multi-block path supports top-2 exemplars", + series: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 100.0, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "prof-1", Value: 100, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "prof-2", Value: 200, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + }, + }, + { + Timestamp: 1000, + Value: 150.0, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "prof-3", Value: 300, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "prof-4", Value: 50, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + }, + }, + }, + }}, + start: 1000, + end: 2000, + step: 1000, + aggregation: &sum, + maxExemplars: 2, + out: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 250.0, + Annotations: []*typesv1.ProfileAnnotation{}, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "prof-3", Value: 300, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "prof-2", Value: 200, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + }, + }, + }, + }}, + }, + { + name: "same profileID across blocks - keeps highest value and intersects labels", + series: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 100.0, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "Profile-X", Value: 100, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "Profile-Y", Value: 60, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "Profile-Z", Value: 40, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + }, + }, + { + Timestamp: 1000, + Value: 140.0, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "Profile-X", Value: 20, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "Profile-Y", Value: 30, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "Profile-Z", Value: 90, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + }, + }, + { + Timestamp: 1000, + Value: 105.0, + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "Profile-X", Value: 10, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "Profile-Y", Value: 80, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + {ProfileId: "Profile-Z", Value: 15, Timestamp: 1000, Labels: []*typesv1.LabelPair{}}, + }, + }, + }, + }}, + start: 1000, + end: 2000, + step: 1000, + aggregation: &sum, + out: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "api"}}, + Points: []*typesv1.Point{ + { + Timestamp: 1000, + Value: 345.0, // 100+140+105 + Annotations: []*typesv1.ProfileAnnotation{}, + // Profile-X has highest value (100 from block A), but labels differ across blocks (A/B/C), so intersection is empty + Exemplars: []*typesv1.Exemplar{ + {ProfileId: "Profile-X", Value: 100, Timestamp: 1000, Labels: nil}, + }, + }, + }, + }}, + }, + } { + t.Run(tc.name, func(t *testing.T) { + iter := NewTimeSeriesMergeIterator(tc.series) + var result []*typesv1.Series + if tc.maxExemplars > 0 { + result = rangeSeriesWithLimit(iter, tc.start, tc.end, tc.step, tc.aggregation, tc.maxExemplars) + } else { + result = RangeSeries(iter, tc.start, tc.end, tc.step, tc.aggregation) + } + testhelper.EqualProto(t, tc.out, result) + }) + } +} diff --git a/pkg/model/timeseries/timeseries.go b/pkg/model/timeseries/timeseries.go new file mode 100644 index 0000000000..d8b69fa689 --- /dev/null +++ b/pkg/model/timeseries/timeseries.go @@ -0,0 +1,156 @@ +// Package timeseries provides types for building and aggregating time series data. +// +// NOTE: This is the old time series implementation using string labels. +// Currently used for all time series queries except exemplar retrieval. +// Over time, we want to migrate to pkg/model/timeseriescompact which uses +// attribute table interning for better performance, and remove this package. +package timeseries + +import ( + "sort" + + "github.com/prometheus/common/model" + "github.com/samber/lo" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +type Builder struct { + labelBuf []byte + by []string + + series seriesByLabels + + exemplarBuilders map[string]*exemplarBuilder +} + +func NewBuilder(by ...string) *Builder { + var b Builder + b.Init(by...) + return &b +} + +func (s *Builder) Init(by ...string) { + s.series = make(seriesByLabels) + s.labelBuf = make([]byte, 0, 1024) + s.by = by + s.exemplarBuilders = make(map[string]*exemplarBuilder) +} + +// Add adds a data point with full labels. +// The series is grouped by the 'by' labels, but exemplars retain full labels. +func (s *Builder) Add(fp model.Fingerprint, lbs phlaremodel.Labels, ts int64, value float64, annotations schemav1.Annotations, profileID string) { + s.labelBuf = lbs.BytesWithLabels(s.labelBuf, s.by...) + seriesKey := string(s.labelBuf) + + pAnnotations := make([]*typesv1.ProfileAnnotation, 0, len(annotations.Keys)) + for i := range len(annotations.Keys) { + pAnnotations = append(pAnnotations, &typesv1.ProfileAnnotation{ + Key: annotations.Keys[i], + Value: annotations.Values[i], + }) + } + + series, exists := s.series[seriesKey] + if !exists { + series = &typesv1.Series{ + Labels: lbs.WithLabels(s.by...), + Points: make([]*typesv1.Point, 0), + } + s.series[seriesKey] = series + } + + series.Points = append(series.Points, &typesv1.Point{ + Timestamp: ts, + Value: value, + Annotations: pAnnotations, + }) + + if profileID != "" { + if s.exemplarBuilders[seriesKey] == nil { + s.exemplarBuilders[seriesKey] = newExemplarBuilder() + } + exemplarLabels := lbs.WithoutLabels(s.by...) + s.exemplarBuilders[seriesKey].Add(fp, exemplarLabels, ts, profileID, int64(value)) + } +} + +// Build returns the time series without exemplars. +func (s *Builder) Build() []*typesv1.Series { + return s.series.normalize() +} + +// BuildWithExemplars returns the time series with exemplars attached. +func (s *Builder) BuildWithExemplars() []*typesv1.Series { + series := s.series.normalize() + s.attachExemplars(series) + return series +} + +// ExemplarCount returns the number of raw exemplars added (before deduplication). +func (s *Builder) ExemplarCount() int { + total := 0 + for _, builder := range s.exemplarBuilders { + total += builder.Count() + } + return total +} + +// attachExemplars attaches exemplars from exemplarBuilders to the corresponding points. +func (s *Builder) attachExemplars(series []*typesv1.Series) { + // Create a map from seriesKey to series for fast lookup + seriesMap := make(map[string]*typesv1.Series) + for _, ser := range series { + seriesKey := string(phlaremodel.Labels(ser.Labels).BytesWithLabels(nil, s.by...)) + seriesMap[seriesKey] = ser + } + + for seriesKey, exemplarBuilder := range s.exemplarBuilders { + ser, found := seriesMap[seriesKey] + if !found { + continue + } + + exemplars := exemplarBuilder.Build() + if len(exemplars) == 0 { + continue + } + + // Attach exemplars to points with matching timestamps + // Both exemplars and points are sorted by timestamp + exIdx := 0 + for _, point := range ser.Points { + // Skip exemplars with timestamp < point timestamp + for exIdx < len(exemplars) && exemplars[exIdx].Timestamp < point.Timestamp { + exIdx++ + } + + // Collect all exemplars with timestamp == point timestamp + var pointExemplars []*typesv1.Exemplar + for i := exIdx; i < len(exemplars) && exemplars[i].Timestamp == point.Timestamp; i++ { + pointExemplars = append(pointExemplars, exemplars[i]) + } + + if len(pointExemplars) > 0 { + point.Exemplars = pointExemplars + } + } + } +} + +type seriesByLabels map[string]*typesv1.Series + +func (m seriesByLabels) normalize() []*typesv1.Series { + result := lo.Values(m) + sort.Slice(result, func(i, j int) bool { + return phlaremodel.CompareLabelPairs(result[i].Labels, result[j].Labels) < 0 + }) + for _, s := range result { + sort.Slice(s.Points, func(i, j int) bool { + return s.Points[i].Timestamp < s.Points[j].Timestamp + }) + } + return result +} diff --git a/pkg/model/timeseries/timeseries_test.go b/pkg/model/timeseries/timeseries_test.go new file mode 100644 index 0000000000..1ff2fb74d2 --- /dev/null +++ b/pkg/model/timeseries/timeseries_test.go @@ -0,0 +1,263 @@ +package timeseries + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +func TestBuilder_NoExemplarsForEmptyProfileID(t *testing.T) { + builder := NewBuilder() + labels := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + {Name: "env", Value: "prod"}, + } + + builder.Add(1, labels, 1000, 100.0, schemav1.Annotations{}, "") + builder.Add(1, labels, 1000, 200.0, schemav1.Annotations{}, "") + + series := builder.BuildWithExemplars() + require.Len(t, series, 1) + require.Len(t, series[0].Points, 2) + + for _, point := range series[0].Points { + assert.Empty(t, point.Exemplars, "Empty profileID should not create exemplars") + } +} + +func TestBuilder_Build_NoExemplars(t *testing.T) { + builder := NewBuilder() + labels := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + } + + builder.Add(1, labels, 1000, 100.0, schemav1.Annotations{}, "profile-1") + + series := builder.Build() + require.Len(t, series, 1) + require.Len(t, series[0].Points, 1) + assert.Empty(t, series[0].Points[0].Exemplars, "Build() should not attach exemplars") +} + +func TestBuilder_BuildWithExemplars_AttachesExemplars(t *testing.T) { + builder := NewBuilder() + labels := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + {Name: "pod", Value: "pod-123"}, + } + + builder.Add(1, labels, 1000, 100.0, schemav1.Annotations{}, "profile-1") + + series := builder.BuildWithExemplars() + require.Len(t, series, 1) + require.Len(t, series[0].Points, 1) + require.Len(t, series[0].Points[0].Exemplars, 1) + + exemplar := series[0].Points[0].Exemplars[0] + assert.Equal(t, "profile-1", exemplar.ProfileId) + assert.Equal(t, int64(100), exemplar.Value) + assert.Equal(t, int64(1000), exemplar.Timestamp) + + assert.Len(t, exemplar.Labels, 2) + assert.Equal(t, "api", findLabelValue(exemplar.Labels, "service_name")) + assert.Equal(t, "pod-123", findLabelValue(exemplar.Labels, "pod")) +} + +func TestBuilder_MultipleExemplarsAtSameTimestamp(t *testing.T) { + builder := NewBuilder() + labels := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + } + + builder.Add(1, labels, 1000, 100.0, schemav1.Annotations{}, "profile-1") + builder.Add(1, labels, 1000, 200.0, schemav1.Annotations{}, "profile-2") + builder.Add(1, labels, 1000, 300.0, schemav1.Annotations{}, "profile-3") + + series := builder.BuildWithExemplars() + require.Len(t, series, 1) + require.Len(t, series[0].Points, 3) + + // All 3 points at timestamp 1000 should have all 3 exemplars + for _, point := range series[0].Points { + require.Len(t, point.Exemplars, 3) + profileIDs := make(map[string]bool) + for _, ex := range point.Exemplars { + profileIDs[ex.ProfileId] = true + } + assert.True(t, profileIDs["profile-1"]) + assert.True(t, profileIDs["profile-2"]) + assert.True(t, profileIDs["profile-3"]) + } +} + +func TestBuilder_GroupBy(t *testing.T) { + builder := NewBuilder("service_name") + labels1 := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + {Name: "pod", Value: "pod-1"}, + } + labels2 := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + {Name: "pod", Value: "pod-2"}, + } + + builder.Add(1, labels1, 1000, 100.0, schemav1.Annotations{}, "profile-1") + builder.Add(2, labels2, 1000, 200.0, schemav1.Annotations{}, "profile-2") + + series := builder.BuildWithExemplars() + + // Should be grouped into 1 series by service_name + require.Len(t, series, 1) + assert.Len(t, series[0].Labels, 1) + assert.Equal(t, "service_name", series[0].Labels[0].Name) + assert.Equal(t, "api", series[0].Labels[0].Value) + + require.Len(t, series[0].Points, 2) + + // Both exemplars should be at timestamp 1000, grouped together + point := series[0].Points[0] + require.Len(t, point.Exemplars, 2) + + // Exemplars should have only non-grouped labels (pod), not service_name + for _, ex := range point.Exemplars { + assert.Len(t, ex.Labels, 1) + assert.NotEmpty(t, findLabelValue(ex.Labels, "pod")) + assert.Empty(t, findLabelValue(ex.Labels, "service_name")) + } +} + +func TestBuilder_ExemplarDeduplication(t *testing.T) { + builder := NewBuilder() + labels := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + {Name: "pod", Value: "pod-1"}, + } + + builder.Add(1, labels, 1000, 100.0, schemav1.Annotations{}, "profile-dup") + builder.Add(1, labels, 1000, 200.0, schemav1.Annotations{}, "profile-dup") + + series := builder.BuildWithExemplars() + require.Len(t, series, 1) + require.Len(t, series[0].Points, 2) + + // Should deduplicate to 1 exemplar per point + for _, point := range series[0].Points { + require.Len(t, point.Exemplars, 1) + assert.Equal(t, "profile-dup", point.Exemplars[0].ProfileId) + } +} + +func TestExemplarBuilder_SameProfileIDDifferentValues(t *testing.T) { + builder := newExemplarBuilder() + + labels1 := phlaremodel.Labels{ + {Name: "pod", Value: "pod-1"}, + } + labels2 := phlaremodel.Labels{ + {Name: "pod", Value: "pod-1"}, + {Name: "span_name", Value: "POST"}, + } + + builder.Add(1, labels1, 1000, "profile-123", 12830000000) + builder.Add(2, labels2, 1000, "profile-123", 110000000) + + exemplars := builder.Build() + require.Len(t, exemplars, 1) + + exemplar := exemplars[0] + assert.Equal(t, "profile-123", exemplar.ProfileId) + assert.Equal(t, int64(1000), exemplar.Timestamp) + assert.Equal(t, int64(12940000000), exemplar.Value) + + // Labels should be intersected + assert.Len(t, exemplar.Labels, 1) + assert.Equal(t, "pod", exemplar.Labels[0].Name) + assert.Equal(t, "pod-1", exemplar.Labels[0].Value) +} + +func TestExemplarBuilder_DifferentProfileIDsNotSummed(t *testing.T) { + builder := newExemplarBuilder() + + labels1 := phlaremodel.Labels{ + {Name: "pod", Value: "pod-1"}, + {Name: "span_name", Value: "POST"}, + } + labels2 := phlaremodel.Labels{ + {Name: "pod", Value: "pod-2"}, + {Name: "span_name", Value: "POST"}, + } + + builder.Add(1, labels1, 1000, "profile-abc", 110000000) + builder.Add(2, labels2, 1000, "profile-def", 150000000) + + exemplars := builder.Build() + require.Len(t, exemplars, 2) + + // Sort by profile ID to ensure consistent ordering + sort.Slice(exemplars, func(i, j int) bool { + return exemplars[i].ProfileId < exemplars[j].ProfileId + }) + + // First exemplar + assert.Equal(t, "profile-abc", exemplars[0].ProfileId) + assert.Equal(t, int64(110000000), exemplars[0].Value) + + // Second exemplar + assert.Equal(t, "profile-def", exemplars[1].ProfileId) + assert.Equal(t, int64(150000000), exemplars[1].Value) +} + +func TestBuilder_MultipleSeries(t *testing.T) { + builder := NewBuilder("env") + labels1 := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + {Name: "env", Value: "prod"}, + } + labels2 := phlaremodel.Labels{ + {Name: "service_name", Value: "api"}, + {Name: "env", Value: "staging"}, + } + + builder.Add(1, labels1, 1000, 100.0, schemav1.Annotations{}, "prod-profile") + builder.Add(2, labels2, 1000, 200.0, schemav1.Annotations{}, "staging-profile") + + series := builder.BuildWithExemplars() + require.Len(t, series, 2) + + seriesByEnv := make(map[string]*typesv1.Series) + for _, s := range series { + for _, lp := range s.Labels { + if lp.Name == "env" { + seriesByEnv[lp.Value] = s + break + } + } + } + + prodSeries := seriesByEnv["prod"] + require.NotNil(t, prodSeries) + require.Len(t, prodSeries.Points, 1) + require.Len(t, prodSeries.Points[0].Exemplars, 1) + assert.Equal(t, "prod-profile", prodSeries.Points[0].Exemplars[0].ProfileId) + + stagingSeries := seriesByEnv["staging"] + require.NotNil(t, stagingSeries) + require.Len(t, stagingSeries.Points, 1) + require.Len(t, stagingSeries.Points[0].Exemplars, 1) + assert.Equal(t, "staging-profile", stagingSeries.Points[0].Exemplars[0].ProfileId) +} + +func findLabelValue(labels []*typesv1.LabelPair, name string) string { + for _, lp := range labels { + if lp.Name == name { + return lp.Value + } + } + return "" +} diff --git a/pkg/model/timeseries/top.go b/pkg/model/timeseries/top.go new file mode 100644 index 0000000000..9c5703d594 --- /dev/null +++ b/pkg/model/timeseries/top.go @@ -0,0 +1,43 @@ +package timeseries + +import ( + "cmp" + "slices" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +// TopSeries returns the top k series by sum of values. +// If k is zero, all series are returned. +// Note that even if len(c) <= k or k == 0, the returned +// series are sorted by value in descending order and then +// lexicographically (in ascending order). +func TopSeries(s []*typesv1.Series, k int) []*typesv1.Series { + type series struct { + *typesv1.Series + sum float64 + } + aggregated := make([]series, len(s)) + for i, x := range s { + var sum float64 + for _, p := range x.Points { + sum += p.Value + } + aggregated[i] = series{Series: x, sum: sum} + } + slices.SortFunc(aggregated, func(a, b series) int { + c := cmp.Compare(a.sum, b.sum) + if c == 0 { + return phlaremodel.CompareLabelPairs(a.Labels, b.Labels) + } + return -c // Invert to sort in descending order. + }) + for i, a := range aggregated { + s[i] = a.Series + } + if k > 0 && len(s) > k { + return s[:k] + } + return s +} diff --git a/pkg/model/timeseriescompact/aggregator.go b/pkg/model/timeseriescompact/aggregator.go new file mode 100644 index 0000000000..a766547fff --- /dev/null +++ b/pkg/model/timeseriescompact/aggregator.go @@ -0,0 +1,173 @@ +package timeseriescompact + +import ( + "slices" + "sort" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" +) + +// Aggregator aggregates compact points within a time step. +type Aggregator struct { + ts int64 + value float64 + annotationRefs []int64 + exemplars []*queryv1.Exemplar + hasData bool +} + +// Add adds a point to the aggregator. +func (a *Aggregator) Add(ts int64, v *CompactValue) { + a.ts = ts + a.value += v.Value + a.annotationRefs = append(a.annotationRefs, v.AnnotationRefs...) + if len(v.Exemplars) > 0 { + a.exemplars = MergeExemplars(a.exemplars, v.Exemplars) + } + a.hasData = true +} + +// GetAndReset returns the aggregated point and resets the aggregator. +func (a *Aggregator) GetAndReset() *queryv1.Point { + pt := &queryv1.Point{ + Timestamp: a.ts, + Value: a.value, + } + if len(a.annotationRefs) > 0 { + pt.AnnotationRefs = DedupeRefs(a.annotationRefs) + } + if len(a.exemplars) > 0 { + pt.Exemplars = SelectTopExemplars(a.exemplars, timeseries.DefaultMaxExemplarsPerPoint) + } + + // Reset + a.ts = 0 + a.value = 0 + a.annotationRefs = nil + a.exemplars = nil + a.hasData = false + + return pt +} + +// IsEmpty returns true if no data has been added. +func (a *Aggregator) IsEmpty() bool { return !a.hasData } + +// Timestamp returns the current timestamp. +func (a *Aggregator) Timestamp() int64 { return a.ts } + +// DedupeRefs removes duplicate refs and returns sorted unique refs. +func DedupeRefs(refs []int64) []int64 { + if len(refs) <= 1 { + return refs + } + slices.Sort(refs) + j := 0 + for i := 1; i < len(refs); i++ { + if refs[j] != refs[i] { + j++ + refs[j] = refs[i] + } + } + return refs[:j+1] +} + +// SelectTopExemplars selects the top N exemplars by value. +func SelectTopExemplars(exemplars []*queryv1.Exemplar, n int) []*queryv1.Exemplar { + if len(exemplars) <= n { + return exemplars + } + sort.Slice(exemplars, func(i, j int) bool { + return exemplars[i].Value > exemplars[j].Value + }) + return exemplars[:n] +} + +// MergeExemplars combines two exemplar lists. +// For exemplars with the same profileID, it keeps the highest value and intersects attribute refs. +func MergeExemplars(a, b []*queryv1.Exemplar) []*queryv1.Exemplar { + if len(a) == 0 { + return b + } + if len(b) == 0 { + return a + } + + type exemplarGroup struct { + exemplar *queryv1.Exemplar + refSets [][]int64 + } + byProfileID := make(map[string]*exemplarGroup, len(a)+len(b)) + + for _, ex := range a { + byProfileID[ex.ProfileId] = &exemplarGroup{ + exemplar: ex, + refSets: [][]int64{ex.AttributeRefs}, + } + } + + for _, ex := range b { + existing, found := byProfileID[ex.ProfileId] + if !found { + byProfileID[ex.ProfileId] = &exemplarGroup{ + exemplar: ex, + refSets: [][]int64{ex.AttributeRefs}, + } + } else { + if ex.Value > existing.exemplar.Value { + existing.exemplar = ex + } + existing.refSets = append(existing.refSets, ex.AttributeRefs) + } + } + + result := make([]*queryv1.Exemplar, 0, len(byProfileID)) + for _, group := range byProfileID { + ex := group.exemplar + if len(group.refSets) > 1 { + ex.AttributeRefs = IntersectRefs(group.refSets) + } + result = append(result, ex) + } + + sort.Slice(result, func(i, j int) bool { return result[i].ProfileId < result[j].ProfileId }) + return result +} + +// IntersectRefs returns the intersection of multiple ref slices. +func IntersectRefs(refSets [][]int64) []int64 { + if len(refSets) == 0 { + return nil + } + if len(refSets) == 1 { + return refSets[0] + } + + set := make(map[int64]struct{}, len(refSets[0])) + for _, ref := range refSets[0] { + set[ref] = struct{}{} + } + + // Intersect with remaining + for i := 1; i < len(refSets); i++ { + newSet := make(map[int64]struct{}) + for _, ref := range refSets[i] { + if _, ok := set[ref]; ok { + newSet[ref] = struct{}{} + } + } + set = newSet + } + + if len(set) == 0 { + return nil + } + + result := make([]int64, 0, len(set)) + for ref := range set { + result = append(result, ref) + } + slices.Sort(result) + return result +} diff --git a/pkg/model/timeseriescompact/aggregator_test.go b/pkg/model/timeseriescompact/aggregator_test.go new file mode 100644 index 0000000000..856349c58f --- /dev/null +++ b/pkg/model/timeseriescompact/aggregator_test.go @@ -0,0 +1,156 @@ +package timeseriescompact + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +func TestMergeExemplars_Empty(t *testing.T) { + assert.Nil(t, MergeExemplars(nil, nil)) + assert.Equal(t, []*queryv1.Exemplar{{ProfileId: "a"}}, MergeExemplars(nil, []*queryv1.Exemplar{{ProfileId: "a"}})) + assert.Equal(t, []*queryv1.Exemplar{{ProfileId: "a"}}, MergeExemplars([]*queryv1.Exemplar{{ProfileId: "a"}}, nil)) +} + +func TestMergeExemplars_DifferentProfiles(t *testing.T) { + a := []*queryv1.Exemplar{{ProfileId: "prof-1", Value: 100}} + b := []*queryv1.Exemplar{{ProfileId: "prof-2", Value: 200}} + + result := MergeExemplars(a, b) + require.Len(t, result, 2) + + // Sorted by profile ID + assert.Equal(t, "prof-1", result[0].ProfileId) + assert.Equal(t, "prof-2", result[1].ProfileId) +} + +func TestMergeExemplars_SameProfile_KeepsHigherValue(t *testing.T) { + a := []*queryv1.Exemplar{{ProfileId: "prof-1", Value: 100, AttributeRefs: []int64{1, 2}}} + b := []*queryv1.Exemplar{{ProfileId: "prof-1", Value: 200, AttributeRefs: []int64{1, 2}}} + + result := MergeExemplars(a, b) + require.Len(t, result, 1) + assert.Equal(t, "prof-1", result[0].ProfileId) + assert.Equal(t, int64(200), result[0].Value) // Higher value kept +} + +func TestMergeExemplars_SameProfile_IntersectsRefs(t *testing.T) { + // Same profile with different attribute refs should intersect + a := []*queryv1.Exemplar{{ProfileId: "prof-1", Value: 100, AttributeRefs: []int64{1, 2, 3}}} + b := []*queryv1.Exemplar{{ProfileId: "prof-1", Value: 50, AttributeRefs: []int64{2, 3, 4}}} + + result := MergeExemplars(a, b) + require.Len(t, result, 1) + + // Should keep higher value exemplar + assert.Equal(t, int64(100), result[0].Value) + + // Refs should be intersected: [1,2,3] ∩ [2,3,4] = [2,3] + assert.ElementsMatch(t, []int64{2, 3}, result[0].AttributeRefs) +} + +func TestMergeExemplars_SameProfile_NoCommonRefs(t *testing.T) { + a := []*queryv1.Exemplar{{ProfileId: "prof-1", Value: 100, AttributeRefs: []int64{1, 2}}} + b := []*queryv1.Exemplar{{ProfileId: "prof-1", Value: 50, AttributeRefs: []int64{3, 4}}} + + result := MergeExemplars(a, b) + require.Len(t, result, 1) + + // No common refs + assert.Empty(t, result[0].AttributeRefs) +} + +func TestIntersectRefs_Empty(t *testing.T) { + assert.Nil(t, IntersectRefs(nil)) + assert.Nil(t, IntersectRefs([][]int64{})) +} + +func TestIntersectRefs_SingleSet(t *testing.T) { + refs := [][]int64{{1, 2, 3}} + result := IntersectRefs(refs) + assert.Equal(t, []int64{1, 2, 3}, result) +} + +func TestIntersectRefs_TwoSets(t *testing.T) { + refs := [][]int64{ + {1, 2, 3, 4}, + {2, 3, 4, 5}, + } + result := IntersectRefs(refs) + assert.Equal(t, []int64{2, 3, 4}, result) +} + +func TestIntersectRefs_ThreeSets(t *testing.T) { + refs := [][]int64{ + {1, 2, 3, 4, 5}, + {2, 3, 4, 5, 6}, + {3, 4, 5, 6, 7}, + } + result := IntersectRefs(refs) + assert.Equal(t, []int64{3, 4, 5}, result) +} + +func TestIntersectRefs_NoCommon(t *testing.T) { + refs := [][]int64{ + {1, 2}, + {3, 4}, + } + result := IntersectRefs(refs) + assert.Nil(t, result) +} + +func TestIntersectRefs_SortedOutput(t *testing.T) { + refs := [][]int64{ + {5, 3, 1, 4, 2}, + {4, 2, 5, 1, 3}, + } + result := IntersectRefs(refs) + // Should be sorted + assert.Equal(t, []int64{1, 2, 3, 4, 5}, result) +} + +func TestDedupeRefs_Empty(t *testing.T) { + assert.Nil(t, DedupeRefs(nil)) + assert.Equal(t, []int64{}, DedupeRefs([]int64{})) +} + +func TestDedupeRefs_Single(t *testing.T) { + assert.Equal(t, []int64{1}, DedupeRefs([]int64{1})) +} + +func TestDedupeRefs_NoDuplicates(t *testing.T) { + result := DedupeRefs([]int64{3, 1, 2}) + assert.Equal(t, []int64{1, 2, 3}, result) // Sorted +} + +func TestDedupeRefs_WithDuplicates(t *testing.T) { + result := DedupeRefs([]int64{3, 1, 2, 1, 3, 2, 1}) + assert.Equal(t, []int64{1, 2, 3}, result) +} + +func TestSelectTopExemplars_LessThanN(t *testing.T) { + exemplars := []*queryv1.Exemplar{ + {ProfileId: "a", Value: 100}, + {ProfileId: "b", Value: 200}, + } + result := SelectTopExemplars(exemplars, 5) + assert.Len(t, result, 2) +} + +func TestSelectTopExemplars_MoreThanN(t *testing.T) { + exemplars := []*queryv1.Exemplar{ + {ProfileId: "a", Value: 100}, + {ProfileId: "b", Value: 300}, + {ProfileId: "c", Value: 200}, + {ProfileId: "d", Value: 400}, + } + result := SelectTopExemplars(exemplars, 2) + require.Len(t, result, 2) + + // Should keep top 2 by value (400, 300) + assert.Equal(t, int64(400), result[0].Value) + assert.Equal(t, int64(300), result[1].Value) +} diff --git a/pkg/model/timeseriescompact/iterator.go b/pkg/model/timeseriescompact/iterator.go new file mode 100644 index 0000000000..5053d7fb4c --- /dev/null +++ b/pkg/model/timeseriescompact/iterator.go @@ -0,0 +1,94 @@ +package timeseriescompact + +import ( + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +type seriesIterator struct { + series *compactSeries + idx int + curr CompactValue +} + +func newSeriesIterator(s *compactSeries) *seriesIterator { + return &seriesIterator{series: s, idx: -1} +} + +func (it *seriesIterator) Next() bool { + it.idx++ + if it.idx >= len(it.series.points) { + return false + } + p := it.series.points[it.idx] + it.curr = CompactValue{ + Ts: p.Timestamp, + SeriesKey: it.series.key, + SeriesRefs: it.series.refs, + Value: p.Value, + AnnotationRefs: p.AnnotationRefs, + Exemplars: p.Exemplars, + } + return true +} + +func (it *seriesIterator) At() CompactValue { return it.curr } +func (it *seriesIterator) Err() error { return nil } +func (it *seriesIterator) Close() error { return nil } + +// mergeIterator merges multiple series iterators by timestamp. +type mergeIterator struct { + iters []iter.Iterator[CompactValue] + heads []CompactValue + valid []bool + current CompactValue +} + +func newMergeIterator(iters []iter.Iterator[CompactValue]) *mergeIterator { + m := &mergeIterator{ + iters: iters, + heads: make([]CompactValue, len(iters)), + valid: make([]bool, len(iters)), + } + for i, it := range iters { + if it.Next() { + m.heads[i] = it.At() + m.valid[i] = true + } + } + return m +} + +func (m *mergeIterator) Next() bool { + // Find minimum timestamp among valid heads + minIdx := -1 + var minTs int64 + for i, v := range m.valid { + if v && (minIdx == -1 || m.heads[i].Ts < minTs) { + minIdx = i + minTs = m.heads[i].Ts + } + } + if minIdx == -1 { + return false + } + + m.current = m.heads[minIdx] + + // Advance the iterator we consumed from + if m.iters[minIdx].Next() { + m.heads[minIdx] = m.iters[minIdx].At() + } else { + m.valid[minIdx] = false + } + + return true +} + +func (m *mergeIterator) At() CompactValue { return m.current } +func (m *mergeIterator) Err() error { return nil } +func (m *mergeIterator) Close() error { + for _, it := range m.iters { + it.Close() + } + return nil +} diff --git a/pkg/model/timeseriescompact/merger.go b/pkg/model/timeseriescompact/merger.go new file mode 100644 index 0000000000..329a8c63ce --- /dev/null +++ b/pkg/model/timeseriescompact/merger.go @@ -0,0 +1,125 @@ +package timeseriescompact + +import ( + "slices" + "sort" + "strconv" + "strings" + "sync" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/model/attributetable" +) + +// Merger merges time series reports in compact format. +type Merger struct { + mu sync.Mutex + atMerger *attributetable.Merger + series map[string]*compactSeries +} + +type compactSeries struct { + key string + refs []int64 + points []*queryv1.Point +} + +// NewMerger creates a new compact time series merger. +func NewMerger() *Merger { + return &Merger{ + atMerger: attributetable.NewMerger(), + series: make(map[string]*compactSeries), + } +} + +// MergeReport adds a report to the merger, remapping attribute refs. +func (m *Merger) MergeReport(r *queryv1.TimeSeriesCompactReport) { + m.mu.Lock() + defer m.mu.Unlock() + + if r == nil || len(r.TimeSeries) == 0 { + return + } + + m.atMerger.Merge(r.AttributeTable, func(remap *attributetable.Remapper) { + for _, s := range r.TimeSeries { + refs := remap.Refs(s.AttributeRefs) + key := seriesKey(refs) + + existing, ok := m.series[key] + if !ok { + existing = &compactSeries{key: key, refs: refs} + m.series[key] = existing + } + + existing.points = slices.Grow(existing.points, len(s.Points)) + for _, p := range s.Points { + pt := &queryv1.Point{Timestamp: p.Timestamp, Value: p.Value} + if len(p.AnnotationRefs) > 0 { + pt.AnnotationRefs = remap.Refs(p.AnnotationRefs) + } + if len(p.Exemplars) > 0 { + pt.Exemplars = make([]*queryv1.Exemplar, len(p.Exemplars)) + for i, ex := range p.Exemplars { + pt.Exemplars[i] = &queryv1.Exemplar{ + Timestamp: ex.Timestamp, + ProfileId: ex.ProfileId, + SpanId: ex.SpanId, + Value: ex.Value, + AttributeRefs: remap.Refs(ex.AttributeRefs), + } + } + } + existing.points = append(existing.points, pt) + } + } + }) +} + +// Iterator returns an iterator over all merged series. +func (m *Merger) Iterator() iter.Iterator[CompactValue] { + m.mu.Lock() + defer m.mu.Unlock() + + if len(m.series) == 0 { + return iter.NewEmptyIterator[CompactValue]() + } + + // Sort series keys for deterministic output + keys := make([]string, 0, len(m.series)) + for k := range m.series { + keys = append(keys, k) + } + sort.Strings(keys) + + // Create iterators for each series + iters := make([]iter.Iterator[CompactValue], 0, len(keys)) + for _, k := range keys { + s := m.series[k] + sort.Slice(s.points, func(i, j int) bool { + return s.points[i].Timestamp < s.points[j].Timestamp + }) + iters = append(iters, newSeriesIterator(s)) + } + + return newMergeIterator(iters) +} + +// BuildAttributeTable returns the merged attribute table. +func (m *Merger) BuildAttributeTable() *queryv1.AttributeTable { + m.mu.Lock() + defer m.mu.Unlock() + return m.atMerger.BuildAttributeTable(nil) +} + +func seriesKey(refs []int64) string { + var sb strings.Builder + for i, ref := range refs { + if i > 0 { + sb.WriteByte(',') + } + sb.WriteString(strconv.FormatInt(ref, 16)) + } + return sb.String() +} diff --git a/pkg/model/timeseriescompact/merger_test.go b/pkg/model/timeseriescompact/merger_test.go new file mode 100644 index 0000000000..48dda4f8be --- /dev/null +++ b/pkg/model/timeseriescompact/merger_test.go @@ -0,0 +1,212 @@ +package timeseriescompact + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +func TestMerger_EmptyReport(t *testing.T) { + m := NewMerger() + m.MergeReport(nil) + m.MergeReport(&queryv1.TimeSeriesCompactReport{}) + + it := m.Iterator() + assert.False(t, it.Next()) +} + +func TestMerger_SingleReport(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 100}, + {Timestamp: 2000, Value: 200}, + }, + }}, + }) + + it := m.Iterator() + require.True(t, it.Next()) + v := it.At() + assert.Equal(t, int64(1000), v.Ts) + assert.Equal(t, 100.0, v.Value) + + require.True(t, it.Next()) + v = it.At() + assert.Equal(t, int64(2000), v.Ts) + assert.Equal(t, 200.0, v.Value) + + assert.False(t, it.Next()) +} + +func TestMerger_MultipleReports_SameSeries(t *testing.T) { + m := NewMerger() + + // Report 1 + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 100}, + }, + }}, + }) + + // Report 2 - same series, different timestamp + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 2000, Value: 200}, + }, + }}, + }) + + it := m.Iterator() + var points []CompactValue + for it.Next() { + points = append(points, it.At()) + } + + require.Len(t, points, 2) + assert.Equal(t, int64(1000), points[0].Ts) + assert.Equal(t, int64(2000), points[1].Ts) +} + +func TestMerger_MultipleReports_DifferentSeries(t *testing.T) { + m := NewMerger() + + // Report 1 - service=api + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 100}, + }, + }}, + }) + + // Report 2 - service=web + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"web"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 200}, + }, + }}, + }) + + it := m.Iterator() + var points []CompactValue + for it.Next() { + points = append(points, it.At()) + } + + // Two different series, both at timestamp 1000 + require.Len(t, points, 2) + // Both should have same timestamp (merge iterator returns in timestamp order) + assert.Equal(t, int64(1000), points[0].Ts) + assert.Equal(t, int64(1000), points[1].Ts) + // Different series keys + assert.NotEqual(t, points[0].SeriesKey, points[1].SeriesKey) +} + +func TestMerger_RemapsAttributeRefs(t *testing.T) { + m := NewMerger() + + // Report 1 - refs [0, 1] map to service=api, pod=a + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service", "pod"}, + Values: []string{"api", "a"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 100, AnnotationRefs: []int64{1}}, + }, + }}, + }) + + // Report 2 - refs [0, 1] map to pod=b, service=api (different order!) + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"pod", "service"}, + Values: []string{"b", "api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{1}, // service=api + Points: []*queryv1.Point{ + {Timestamp: 2000, Value: 200, AnnotationRefs: []int64{0}}, // pod=b + }, + }}, + }) + + // Both reports have same series (service=api), so should merge + it := m.Iterator() + var points []CompactValue + for it.Next() { + points = append(points, it.At()) + } + + require.Len(t, points, 2) + // Same series key (both service=api) + assert.Equal(t, points[0].SeriesKey, points[1].SeriesKey) + + // Verify attribute table has all unique entries + table := m.BuildAttributeTable() + assert.Len(t, table.Keys, 3) // service, pod(a), pod(b) +} + +func TestMerger_WithExemplars(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service", "pod"}, + Values: []string{"api", "a"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{ + Timestamp: 1000, + Value: 100, + Exemplars: []*queryv1.Exemplar{{ + ProfileId: "prof-1", + Value: 100, + AttributeRefs: []int64{1}, + }}, + }}, + }}, + }) + + it := m.Iterator() + require.True(t, it.Next()) + v := it.At() + require.Len(t, v.Exemplars, 1) + assert.Equal(t, "prof-1", v.Exemplars[0].ProfileId) +} diff --git a/pkg/model/timeseriescompact/range.go b/pkg/model/timeseriescompact/range.go new file mode 100644 index 0000000000..4cdac646f0 --- /dev/null +++ b/pkg/model/timeseriescompact/range.go @@ -0,0 +1,109 @@ +package timeseriescompact + +import ( + "sort" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +// RangeSeries aggregates compact points into time steps. +func RangeSeries(it iter.Iterator[CompactValue], start, end, step int64) []*queryv1.Series { + defer it.Close() + + seriesMap := make(map[string]*queryv1.Series) + aggregators := make(map[string]*Aggregator) + var seriesRefs map[string][]int64 + + if !it.Next() { + return nil + } + + seriesRefs = make(map[string][]int64) + + // Advance from start to end, aggregating each step +Outer: + for currentStep := start; currentStep <= end; currentStep += step { + for { + point := it.At() + key := point.SeriesKey + + agg, ok := aggregators[key] + if !ok { + agg = &Aggregator{} + aggregators[key] = agg + seriesRefs[key] = point.SeriesRefs + } + + if point.Ts > currentStep { + // Flush aggregators that have data + for k, a := range aggregators { + if !a.IsEmpty() { + s, exists := seriesMap[k] + if !exists { + s = &queryv1.Series{AttributeRefs: seriesRefs[k]} + seriesMap[k] = s + } + s.Points = append(s.Points, a.GetAndReset()) + } + } + break + } + + // Find or create series + if _, ok := seriesMap[key]; !ok { + seriesMap[key] = &queryv1.Series{ + AttributeRefs: point.SeriesRefs, + Points: []*queryv1.Point{}, + } + } + + // Aggregate point if in current step + if agg.Timestamp() == currentStep || agg.IsEmpty() { + agg.Add(currentStep, &point) + if !it.Next() { + break Outer + } + continue + } + + // Step changed, flush and start new + s := seriesMap[key] + if !agg.IsEmpty() { + s.Points = append(s.Points, agg.GetAndReset()) + } + agg.Add(currentStep, &point) + if !it.Next() { + break Outer + } + } + } + + // Flush remaining aggregators + for key, agg := range aggregators { + if !agg.IsEmpty() { + s, exists := seriesMap[key] + if !exists { + s = &queryv1.Series{AttributeRefs: seriesRefs[key]} + seriesMap[key] = s + } + s.Points = append(s.Points, agg.GetAndReset()) + } + } + + // Sort series by key for deterministic output + keys := make([]string, 0, len(seriesMap)) + for k := range seriesMap { + keys = append(keys, k) + } + sort.Strings(keys) + + result := make([]*queryv1.Series, 0, len(seriesMap)) + for _, k := range keys { + if s := seriesMap[k]; len(s.Points) > 0 { + result = append(result, s) + } + } + + return result +} diff --git a/pkg/model/timeseriescompact/range_test.go b/pkg/model/timeseriescompact/range_test.go new file mode 100644 index 0000000000..e19282399b --- /dev/null +++ b/pkg/model/timeseriescompact/range_test.go @@ -0,0 +1,232 @@ +package timeseriescompact + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +func TestRangeSeries_EmptyIterator(t *testing.T) { + it := iter.NewEmptyIterator[CompactValue]() + series := RangeSeries(it, 0, 1000, 100) + assert.Nil(t, series) +} + +func TestRangeSeries_SinglePoint(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{Timestamp: 500, Value: 100}}, + }}, + }) + + series := RangeSeries(m.Iterator(), 0, 1000, 1000) + require.Len(t, series, 1) + require.Len(t, series[0].Points, 1) + assert.Equal(t, int64(1000), series[0].Points[0].Timestamp) + assert.Equal(t, 100.0, series[0].Points[0].Value) +} + +func TestRangeSeries_AggregatesWithinStep(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 100, Value: 10}, + {Timestamp: 200, Value: 20}, + {Timestamp: 300, Value: 30}, + }, + }}, + }) + + // Step of 1000 should aggregate all points into one + series := RangeSeries(m.Iterator(), 0, 1000, 1000) + require.Len(t, series, 1) + require.Len(t, series[0].Points, 1) + assert.Equal(t, 60.0, series[0].Points[0].Value) +} + +func TestRangeSeries_MultipleSteps(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 100, Value: 10}, + {Timestamp: 500, Value: 50}, + {Timestamp: 1500, Value: 150}, + {Timestamp: 2500, Value: 250}, + }, + }}, + }) + + series := RangeSeries(m.Iterator(), 0, 3000, 1000) + require.Len(t, series, 1) + require.Len(t, series[0].Points, 3) + + // First step (0-1000): 10 + 50 = 60 + assert.Equal(t, int64(1000), series[0].Points[0].Timestamp) + assert.Equal(t, 60.0, series[0].Points[0].Value) + + // Second step (1000-2000): 150 + assert.Equal(t, int64(2000), series[0].Points[1].Timestamp) + assert.Equal(t, 150.0, series[0].Points[1].Value) + + // Third step (2000-3000): 250 + assert.Equal(t, int64(3000), series[0].Points[2].Timestamp) + assert.Equal(t, 250.0, series[0].Points[2].Value) +} + +func TestRangeSeries_MultipleSeries(t *testing.T) { + m := NewMerger() + + // Series 1: service=api + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"api"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{Timestamp: 500, Value: 100}}, + }}, + }) + + // Series 2: service=web + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service"}, + Values: []string{"web"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{Timestamp: 500, Value: 200}}, + }}, + }) + + series := RangeSeries(m.Iterator(), 0, 1000, 1000) + require.Len(t, series, 2) + + // Each series should have one point + for _, s := range series { + require.Len(t, s.Points, 1) + } + + // Total value across both series + total := series[0].Points[0].Value + series[1].Points[0].Value + assert.Equal(t, 300.0, total) +} + +func TestRangeSeries_WithAnnotations(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service", "error", "host"}, + Values: []string{"api", "true", "server-1"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 100, Value: 10, AnnotationRefs: []int64{1}}, + {Timestamp: 200, Value: 20, AnnotationRefs: []int64{2}}, + }, + }}, + }) + + series := RangeSeries(m.Iterator(), 0, 1000, 1000) + require.Len(t, series, 1) + require.Len(t, series[0].Points, 1) + + // Should have both annotations merged and deduped + point := series[0].Points[0] + assert.Len(t, point.AnnotationRefs, 2) +} + +func TestRangeSeries_WithExemplars(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service", "pod"}, + Values: []string{"api", "a"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + { + Timestamp: 100, + Value: 100, + Exemplars: []*queryv1.Exemplar{{ + ProfileId: "prof-1", + Value: 100, + AttributeRefs: []int64{1}, + }}, + }, + { + Timestamp: 200, + Value: 50, + Exemplars: []*queryv1.Exemplar{{ + ProfileId: "prof-2", + Value: 50, + AttributeRefs: []int64{1}, + }}, + }, + }, + }}, + }) + + series := RangeSeries(m.Iterator(), 0, 1000, 1000) + require.Len(t, series, 1) + require.Len(t, series[0].Points, 1) + + point := series[0].Points[0] + assert.Equal(t, 150.0, point.Value) // 100 + 50 + + // Should have top exemplar (highest value) + require.Len(t, point.Exemplars, 1) + assert.Equal(t, "prof-1", point.Exemplars[0].ProfileId) +} + +func TestRangeSeries_DifferentTimestampsNoCorruption(t *testing.T) { + m := NewMerger() + m.MergeReport(&queryv1.TimeSeriesCompactReport{ + AttributeTable: &queryv1.AttributeTable{ + Keys: []string{"service", "a", "b", "c"}, + Values: []string{"api", "1", "2", "3"}, + }, + TimeSeries: []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 100, AnnotationRefs: []int64{1}}, + {Timestamp: 2000, Value: 200, AnnotationRefs: []int64{2}}, + {Timestamp: 3000, Value: 300, AnnotationRefs: []int64{3}}, + }, + }}, + }) + + series := RangeSeries(m.Iterator(), 1000, 3000, 1000) + require.Len(t, series, 1) + require.Len(t, series[0].Points, 3) + + // Each point should have its own annotation, not corrupted + assert.Equal(t, []int64{1}, series[0].Points[0].AnnotationRefs) + assert.Equal(t, []int64{2}, series[0].Points[1].AnnotationRefs) + assert.Equal(t, []int64{3}, series[0].Points[2].AnnotationRefs) +} diff --git a/pkg/model/timeseriescompact/timeseriescompact.go b/pkg/model/timeseriescompact/timeseriescompact.go new file mode 100644 index 0000000000..40f4d89757 --- /dev/null +++ b/pkg/model/timeseriescompact/timeseriescompact.go @@ -0,0 +1,22 @@ +// Package timeseriescompact provides types and utilities for working with +// compact time series data using attribute table references instead of +// string labels. This format is optimized for efficient merging and +// aggregation across distributed query backends. +// +// Currently only used for exemplar retrieval. Over time, this package will +// replace pkg/model/timeseries for all time series queries. +package timeseriescompact + +import ( + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +// CompactValue represents a single data point during iteration. +type CompactValue struct { + Ts int64 + SeriesKey string + SeriesRefs []int64 + Value float64 + AnnotationRefs []int64 + Exemplars []*queryv1.Exemplar +} diff --git a/pkg/model/tree.go b/pkg/model/tree.go index 4ad11b04f8..9343f63986 100644 --- a/pkg/model/tree.go +++ b/pkg/model/tree.go @@ -2,48 +2,146 @@ package model import ( "bytes" - "container/heap" "fmt" "io" "sort" + "strconv" "strings" - "sync" - dvarint "github.com/dennwc/varint" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/xlab/treeprint" - "github.com/grafana/pyroscope/pkg/og/util/varint" - "github.com/grafana/pyroscope/pkg/slices" + "github.com/grafana/pyroscope/v2/pkg/og/util/varint" + "github.com/grafana/pyroscope/v2/pkg/slices" + "github.com/grafana/pyroscope/v2/pkg/util/minheap" ) -type Tree struct { - root []*node +const OtherFunctionName = FunctionName(truncatedNodeName) + +type FunctionName string + +type FunctionNameI struct { +} + +func (FunctionNameI) IsLocationTree() bool { + return false +} + +func (FunctionNameI) newOther() FunctionName { //nolint:unused + return OtherFunctionName +} + +func (FunctionNameI) marshalNode(w io.Writer, vw varint.Writer, n *node[FunctionName], _ func(FunctionName) FunctionName) error { //nolint:unused + if _, err := vw.Write(w, uint64(len(n.name))); err != nil { + return err + } + if _, err := w.Write(unsafeStringBytes(string(n.name))); err != nil { + return err + } + _, err := vw.Write(w, uint64(n.self)) + return err +} + +func (FunctionNameI) unmarshalNode(b []byte, offset int) (FunctionName, int64, int, error) { //nolint:unused + nameLen, o := varint.Uvarint(b[offset:]) + if o < 0 { + return "", 0, 0, errMalformedTreeBytes + } + offset += o + // Note that we allocate a string, instead of referencing b's capacity. + name := FunctionName(b[offset : offset+int(nameLen)]) + offset += int(nameLen) + value, o := varint.Uvarint(b[offset:]) + if o < 0 { + return "", 0, 0, errMalformedTreeBytes + } + offset += o + return name, int64(value), offset, nil +} + +const OtherLocationRef = LocationRefName(-1) + +type LocationRefName int + +type LocationRefNameI struct { +} + +func (LocationRefNameI) IsLocationTree() bool { + return true +} + +func (LocationRefNameI) newOther() LocationRefName { //nolint:unused + return OtherLocationRef +} + +func (LocationRefNameI) marshalNode(w io.Writer, vw varint.Writer, n *node[LocationRefName], keepName func(LocationRefName) LocationRefName) error { //nolint:unused + if _, err := vw.Write(w, uint64(keepName(n.name))); err != nil { + return err + } + _, err := vw.Write(w, uint64(n.self)) + return err +} + +func (LocationRefNameI) unmarshalNode(b []byte, offset int) (LocationRefName, int64, int, error) { //nolint:unused + name, o := varint.Uvarint(b[offset:]) + if o < 0 { + return 0, 0, 0, errMalformedTreeBytes + } + offset += o + + value, o := varint.Uvarint(b[offset:]) + if o < 0 { + return 0, 0, 0, errMalformedTreeBytes + } + offset += o + + return LocationRefName(name), int64(value), offset, nil +} + +type NodeName interface { + ~string | ~int +} + +type NodeNameI[N ~string | ~int] interface { + IsLocationTree() bool + newOther() N + marshalNode(io.Writer, varint.Writer, *node[N], func(N) N) error + unmarshalNode([]byte, int) (N, int64, int, error) } -type node struct { - parent *node - children []*node +type LocationRefNameTree = Tree[LocationRefName, LocationRefNameI] + +type FunctionNameTree = Tree[FunctionName, FunctionNameI] + +type Tree[N NodeName, I NodeNameI[N]] struct { + root []*node[N] +} + +type node[N NodeName] struct { + parent *node[N] + children []*node[N] self, total int64 - name string + name N } -func (t *Tree) String() string { +func (t *Tree[N, I]) String() string { type branch struct { - nodes []*node + nodes []*node[N] treeprint.Tree } tree := treeprint.New() for _, n := range t.root { - b := tree.AddBranch(fmt.Sprintf("%s: self %d total %d", n.name, n.self, n.total)) + b := tree.AddBranch(fmt.Sprintf("%v: self %d total %d", n.name, n.self, n.total)) remaining := append([]*branch{}, &branch{nodes: n.children, Tree: b}) for len(remaining) > 0 { current := remaining[0] remaining = remaining[1:] for _, n := range current.nodes { if len(n.children) > 0 { - remaining = append(remaining, &branch{nodes: n.children, Tree: current.Tree.AddBranch(fmt.Sprintf("%s: self %d total %d", n.name, n.self, n.total))}) + remaining = append(remaining, &branch{nodes: n.children, Tree: current.AddBranch(fmt.Sprintf("%v: self %d total %d", n.name, n.self, n.total))}) } else { - current.Tree.AddNode(fmt.Sprintf("%s: self %d total %d", n.name, n.self, n.total)) + current.AddNode(fmt.Sprintf("%v: self %d total %d", n.name, n.self, n.total)) } } } @@ -51,18 +149,18 @@ func (t *Tree) String() string { return tree.String() } -func (t *Tree) Total() (v int64) { +func (t *Tree[N, I]) Total() (v int64) { for _, n := range t.root { v += n.total } return v } -func (t *Tree) InsertStack(v int64, stack ...string) { +func (t *Tree[N, I]) InsertStack(v int64, stack ...N) { if v <= 0 { return } - r := &node{children: t.root} + r := &node[N]{children: t.root} n := r for s := range stack { name := stack[s] @@ -80,7 +178,7 @@ func (t *Tree) InsertStack(v int64, stack ...string) { if i < len(n.children) && n.children[i].name == name { n = n.children[i] } else { - child := &node{parent: n, name: name} + child := &node[N]{parent: n, name: name} n.children = append(n.children, child) copy(n.children[i+1:], n.children[i:]) n.children[i] = child @@ -93,16 +191,24 @@ func (t *Tree) InsertStack(v int64, stack ...string) { t.root = r.children } -func (t *Tree) WriteCollapsed(dst io.Writer) { - t.IterateStacks(func(_ string, self int64, stack []string) { +func (t *Tree[N, I]) WriteCollapsed(dst io.Writer) { + t.IterateStacks(func(_ N, self int64, stack []N) { slices.Reverse(stack) - _, _ = fmt.Fprintf(dst, "%s %d\n", strings.Join(stack, ";"), self) + stackStrs := make([]string, len(stack)) + for i, v := range stack { + stackStrs[i] = fmt.Sprint(v) + } + _, _ = fmt.Fprintf(dst, "%s %d\n", strings.Join(stackStrs, ";"), self) }) } -func (t *Tree) IterateStacks(cb func(name string, self int64, stack []string)) { - nodes := make([]*node, len(t.root), 1024) - stack := make([]string, 0, 64) +func (t *Tree[N, I]) IterateStacks(cb func(name N, self int64, stack []N)) { + s := 1024 + if s < len(t.root) { + s += len(t.root) + } + nodes := make([]*node[N], len(t.root), s) + stack := make([]N, 0, 64) copy(nodes, t.root) for len(nodes) > 0 { n := nodes[0] @@ -129,7 +235,7 @@ func (t *Tree) IterateStacks(cb func(name string, self int64, stack []string)) { // slice will grow to 1-4K nodes, depending on the trace branching. const defaultDFSSize = 128 -func (t *Tree) Merge(src *Tree) { +func (t *Tree[N, I]) Merge(src *Tree[N, I]) { if t.Total() == 0 && src.Total() > 0 { *t = *src return @@ -138,15 +244,17 @@ func (t *Tree) Merge(src *Tree) { return } - srcNodes := make([]*node, 0, defaultDFSSize) - srcRoot := &node{children: src.root} + nodeBuffer := newNodeBuffer[N](defaultDFSSize) + + srcNodes := make([]*node[N], 0, defaultDFSSize) + srcRoot := &node[N]{children: src.root} srcNodes = append(srcNodes, srcRoot) - dstNodes := make([]*node, 0, defaultDFSSize) - dstRoot := &node{children: t.root} + dstNodes := make([]*node[N], 0, defaultDFSSize) + dstRoot := &node[N]{children: t.root} dstNodes = append(dstNodes, dstRoot) - var st, dt *node + var st, dt *node[N] for len(srcNodes) > 0 { st, srcNodes = srcNodes[len(srcNodes)-1], srcNodes[:len(srcNodes)-1] dt, dstNodes = dstNodes[len(dstNodes)-1], dstNodes[:len(dstNodes)-1] @@ -156,7 +264,7 @@ func (t *Tree) Merge(src *Tree) { for _, srcChildNode := range st.children { // Note that we don't copy the name, but reference it. - dstChildNode := dt.insert(srcChildNode.name) + dstChildNode := dt.insert(srcChildNode.name, nodeBuffer.newNode) srcNodes = append(srcNodes, srcChildNode) dstNodes = append(dstNodes, dstChildNode) } @@ -165,10 +273,10 @@ func (t *Tree) Merge(src *Tree) { t.root = dstRoot.children } -func (t *Tree) FormatNodeNames(fn func(string) string) { - nodes := make([]*node, 0, defaultDFSSize) - nodes = append(nodes, &node{children: t.root}) - var n *node +func (t *Tree[N, I]) FormatNodeNames(fn func(N) N) { + nodes := make([]*node[N], 0, defaultDFSSize) + nodes = append(nodes, &node[N]{children: t.root}) + var n *node[N] var fix bool for len(nodes) > 0 { n, nodes = nodes[len(nodes)-1], nodes[:len(nodes)-1] @@ -186,17 +294,17 @@ func (t *Tree) FormatNodeNames(fn func(string) string) { } // Fix re-establishes order of nodes and merges duplicates. -func (t *Tree) Fix() { +func (t *Tree[N, I]) Fix() { if len(t.root) == 0 { return } - r := &node{children: t.root} + r := &node[N]{children: t.root} for _, n := range r.children { n.parent = r } - nodes := make([][]*node, 0, defaultDFSSize) + nodes := make([][]*node[N], 0, defaultDFSSize) nodes = append(nodes, r.children) - var n []*node + var n []*node[N] for len(nodes) > 0 { n, nodes = nodes[len(nodes)-1], nodes[:len(nodes)-1] if len(n) == 0 { @@ -230,11 +338,11 @@ func (t *Tree) Fix() { t.root = r.children } -func (n *node) String() string { - return fmt.Sprintf("{%s: self %d total %d}", n.name, n.self, n.total) +func (n *node[N]) String() string { + return fmt.Sprintf("{%v: self %d total %d}", n.name, n.self, n.total) } -func (n *node) insert(name string) *node { +func (n *node[N]) insert(name N, newNode func() *node[N]) *node[N] { i := sort.Search(len(n.children), func(i int) bool { return n.children[i].name >= name }) @@ -243,7 +351,14 @@ func (n *node) insert(name string) *node { } // We don't clone the name: it is caller responsibility // to maintain the memory ownership. - child := &node{parent: n, name: name} + var child *node[N] + if newNode == nil { + child = &node[N]{} + } else { + child = newNode() + } + child.parent = n + child.name = name n.children = append(n.children, child) copy(n.children[i+1:], n.children[i:]) n.children[i] = child @@ -252,48 +367,47 @@ func (n *node) insert(name string) *node { // minValue returns the minimum "total" value a node in a tree has to have to show up in // the resulting flamegraph -func (t *Tree) minValue(maxNodes int64) int64 { +func (t *Tree[N, I]) minValue(maxNodes int64) int64 { if maxNodes < 1 { return 0 } - nodes := make([]*node, 0, max(int64(len(t.root)), defaultDFSSize)) + nodes := make([]*node[N], 0, max(int64(len(t.root)), defaultDFSSize)) treeSize := t.size(nodes) if treeSize <= maxNodes { return 0 } - s := make(minHeap, 0, maxNodes) - h := &s + h := make([]int64, 0, maxNodes) nodes = append(nodes[:0], t.root...) - var n *node + var n *node[N] for len(nodes) > 0 { last := len(nodes) - 1 n, nodes = nodes[last], nodes[:last] - if h.Len() >= int(maxNodes) { - if n.total > (*h)[0] { - heap.Pop(h) + if len(h) >= int(maxNodes) { + if n.total > h[0] { + h = minheap.Pop(h) } else { continue } } - heap.Push(h, n.total) + h = minheap.Push(h, n.total) nodes = append(nodes, n.children...) } - if h.Len() < int(maxNodes) { + if len(h) < int(maxNodes) { return 0 } - return (*h)[0] + return h[0] } // size reports number of nodes the tree consists of. // Provided buffer used for DFS traversal. -func (t *Tree) size(buf []*node) int64 { +func (t *Tree[N, I]) size(buf []*node[N]) int64 { nodes := append(buf, t.root...) var s int64 - var n *node + var n *node[N] for len(nodes) > 0 { last := len(nodes) - 1 n, nodes = nodes[last], nodes[:last] @@ -303,36 +417,6 @@ func (t *Tree) size(buf []*node) int64 { return s } -// minHeap is a custom min-heap data structure that stores integers. -type minHeap []int64 - -// Len returns the number of elements in the min-heap. -func (h minHeap) Len() int { return len(h) } - -// Less returns true if the element at index i is less than the element at index j. -// This method is used by the container/heap package to maintain the min-heap property. -func (h minHeap) Less(i, j int) bool { return h[i] < h[j] } - -// Swap exchanges the elements at index i and index j. -// This method is used by the container/heap package to reorganize the min-heap during its operations. -func (h minHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } - -// Push adds an element (x) to the min-heap. -// This method is used by the container/heap package to grow the min-heap. -func (h *minHeap) Push(x interface{}) { - *h = append(*h, x.(int64)) -} - -// Pop removes and returns the smallest element (minimum) from the min-heap. -// This method is used by the container/heap package to shrink the min-heap. -func (h *minHeap) Pop() interface{} { - old := *h - n := len(old) - x := old[n-1] - *h = old[0 : n-1] - return x -} - const truncatedNodeName = "other" var truncatedNodeNameBytes = []byte(truncatedNodeName) @@ -340,43 +424,41 @@ var truncatedNodeNameBytes = []byte(truncatedNodeName) // Bytes returns marshaled tree byte representation; the number of nodes // is limited to maxNodes. The function modifies the tree: truncated nodes // are removed from the tree in place. -func (t *Tree) Bytes(maxNodes int64) []byte { +func (t *Tree[N, I]) Bytes(maxNodes int64, keepName func(N) N) []byte { var buf bytes.Buffer - _ = t.MarshalTruncate(&buf, maxNodes) + _ = t.MarshalTruncate(&buf, maxNodes, keepName) return buf.Bytes() } // MarshalTruncate writes tree byte representation to the writer provider, // the number of nodes is limited to maxNodes. The function modifies // the tree: truncated nodes are removed from the tree. -func (t *Tree) MarshalTruncate(w io.Writer, maxNodes int64) (err error) { +func (t *Tree[N, I]) MarshalTruncate(w io.Writer, maxNodes int64, keepName func(N) N) (err error) { if len(t.root) == 0 { return nil } + var initializer I + otherName := initializer.newOther() + vw := varint.NewWriter() minVal := t.minValue(maxNodes) - nodes := make([]*node, 1, defaultDFSSize) - nodes[0] = &node{children: t.root} // Virtual root node. - var n *node + nodes := make([]*node[N], 1, defaultDFSSize) + nodes[0] = &node[N]{children: t.root} // Virtual root node. + var n *node[N] for len(nodes) > 0 { last := len(nodes) - 1 n, nodes = nodes[last], nodes[:last] - if _, _ = vw.Write(w, uint64(len(n.name))); err != nil { - return err - } - if _, _ = w.Write(unsafeStringBytes(n.name)); err != nil { - return err - } - if _, err = vw.Write(w, uint64(n.self)); err != nil { + + if err := initializer.marshalNode(w, vw, n, keepName); err != nil { return err } var other int64 var j int for _, cn := range n.children { - if cn.total >= minVal || cn.name == truncatedNodeName { + if cn.total >= minVal || cn.name == otherName { n.children[j] = cn j++ } else { @@ -386,7 +468,7 @@ func (t *Tree) MarshalTruncate(w io.Writer, maxNodes int64) (err error) { n.children = n.children[:j] if other > 0 { - o := n.insert(truncatedNodeName) + o := n.insert(otherName, nil) o.total += other o.self += other } @@ -406,8 +488,41 @@ var errMalformedTreeBytes = fmt.Errorf("malformed tree bytes") const estimateBytesPerNode = 16 // Chosen empirically. -func UnmarshalTree(b []byte) (*Tree, error) { - t := new(Tree) +func MustUnmarshalTree[N NodeName, I NodeNameI[N]](b []byte) *Tree[N, I] { + if len(b) == 0 { + return new(Tree[N, I]) + } + t, err := UnmarshalTree[N, I](b) + if err != nil { + panic(err) + } + return t +} + +type nodeBuffer[N NodeName] struct { + size int + nodes []node[N] +} + +func newNodeBuffer[N NodeName](size int) *nodeBuffer[N] { + return &nodeBuffer[N]{ + size: size, + } +} + +func (nb *nodeBuffer[N]) newNode() *node[N] { + if len(nb.nodes) == 0 { + nb.nodes = make([]node[N], nb.size) + } + n := &nb.nodes[0] + nb.nodes = nb.nodes[1:] + return n + +} + +func UnmarshalTree[N NodeName, I NodeNameI[N]](b []byte) (*Tree[N, I], error) { + var initializer I + t := new(Tree[N, I]) if len(b) < 2 { return t, nil } @@ -415,37 +530,35 @@ func UnmarshalTree(b []byte) (*Tree, error) { if e := len(b) / estimateBytesPerNode; e > estimateBytesPerNode { size = e } - parents := make([]*node, 1, size) + parents := make([]*node[N], 1, size) // Virtual root node. - root := new(node) + root := new(node[N]) parents[0] = root - var parent *node + var parent *node[N] var offset int + nodeBuffer := newNodeBuffer[N](size) + for len(parents) > 0 { parent, parents = parents[len(parents)-1], parents[:len(parents)-1] - nameLen, o := dvarint.Uvarint(b[offset:]) - if o < 0 { - return nil, errMalformedTreeBytes - } - offset += o - // Note that we allocate a string, instead of referencing b's capacity. - name := string(b[offset : offset+int(nameLen)]) - offset += int(nameLen) - value, o := dvarint.Uvarint(b[offset:]) - if o < 0 { - return nil, errMalformedTreeBytes + // specific start + + name, value, o, err := initializer.unmarshalNode(b, offset) + if err != nil { + return nil, err } - offset += o - childrenLen, o := dvarint.Uvarint(b[offset:]) + offset = o + + // specific end + childrenLen, o := varint.Uvarint(b[offset:]) if o < 0 { return nil, errMalformedTreeBytes } offset += o - n := parent.insert(name) - n.children = make([]*node, 0, childrenLen) - n.self = int64(value) + n := parent.insert(name, nodeBuffer.newNode) + n.children = make([]*node[N], 0, childrenLen) + n.self = value pn := n for pn.parent != nil { @@ -458,42 +571,60 @@ func UnmarshalTree(b []byte) (*Tree, error) { } } - // Remove the virtual root. - t.root = root.children[0].children + // Remove the virtual root and detach it: parent-pointer walks + // (IterateStacks) must stop at the real roots instead of surfacing + // the marshal format's zero-valued node in every stack. + vr := root.children[0] + vr.parent = nil + t.root = vr.children return t, nil } -type TreeMerger struct { - mu sync.Mutex - t *Tree +// TreeFromBackendProfile is a wrapper... +func TreeFromBackendProfile(profile *profilev1.Profile, maxNodes int64) ([]byte, error) { + return TreeFromBackendProfileSampleType(profile, maxNodes, 0) } -func NewTreeMerger() *TreeMerger { - return new(TreeMerger) -} +// TreeFromBackendProfileSampleType converts a pprof profile to a tree format with maxNodes limit +func TreeFromBackendProfileSampleType(profile *profilev1.Profile, maxNodes int64, sampleType int) ([]byte, error) { + t := NewStacktraceTree(int(maxNodes * 2)) + stack := make([]int32, 0, 64) + m := make(map[uint64]int32) + + for i := range profile.Sample { + stack = stack[:0] + for j := range profile.Sample[i].LocationId { + locIdx := int(profile.Sample[i].LocationId[j]) - 1 + if locIdx < 0 || len(profile.Location) <= locIdx { + return nil, fmt.Errorf("invalid location ID %d in sample %d", profile.Sample[i].LocationId[j], i) + } -func (m *TreeMerger) MergeTreeBytes(b []byte) error { - // TODO(kolesnikovae): Ideally, we should not have - // the intermediate tree t but update m.t reading - // raw bytes b directly. - t, err := UnmarshalTree(b) - if err != nil { - return err - } - m.mu.Lock() - if m.t != nil { - m.t.Merge(t) - } else { - m.t = t - } - m.mu.Unlock() - return nil -} + loc := profile.Location[locIdx] + if len(loc.Line) > 0 { + for l := range loc.Line { + stack = append(stack, int32(profile.Function[loc.Line[l].FunctionId-1].Name)) + } + continue + } + addr, ok := m[loc.Address] + if !ok { + addr = int32(len(profile.StringTable)) + profile.StringTable = append(profile.StringTable, strconv.FormatInt(int64(loc.Address), 16)) + m[loc.Address] = addr + } + stack = append(stack, addr) + } -func (m *TreeMerger) Tree() *Tree { - if m.t == nil { - return new(Tree) + if sampleType < 0 || sampleType >= len(profile.Sample[i].Value) { + return nil, fmt.Errorf("invalid sampleType index %d for sample %d (len=%d)", sampleType, i, len(profile.Sample[i].Value)) + } + + t.Insert(stack, profile.Sample[i].Value[sampleType]) } - return m.t + + b := bytes.NewBuffer(nil) + b.Grow(100 << 10) + t.Bytes(b, maxNodes, profile.StringTable) + return b.Bytes(), nil } diff --git a/pkg/model/tree_merger.go b/pkg/model/tree_merger.go new file mode 100644 index 0000000000..f637ff2bb0 --- /dev/null +++ b/pkg/model/tree_merger.go @@ -0,0 +1,67 @@ +package model + +import ( + "sync" +) + +type TreeMerger[N NodeName, I NodeNameI[N]] struct { + mu sync.Mutex + t *Tree[N, I] +} + +func NewTreeMerger[N NodeName, I NodeNameI[N]]() *TreeMerger[N, I] { + return new(TreeMerger[N, I]) +} + +func (m *TreeMerger[N, I]) MergeTree(t *Tree[N, I]) { + m.mu.Lock() + defer m.mu.Unlock() + if m.t != nil { + m.t.Merge(t) + } else { + m.t = t + } +} + +type treeMergeOption[N any] struct { + formatNodeNames func(N) N +} + +type TreeMergeOption[N any] func(o *treeMergeOption[N]) + +func WithTreeMergeFormatNodeNames[N any](f func(N) N) TreeMergeOption[N] { + return func(o *treeMergeOption[N]) { + o.formatNodeNames = f + } +} + +func (m *TreeMerger[N, I]) MergeTreeBytes(b []byte, opts ...TreeMergeOption[N]) error { + var o = new(treeMergeOption[N]) + for _, f := range opts { + f(o) + } + + // TODO(kolesnikovae): Ideally, we should not have + // the intermediate tree t but update m.t reading + // raw bytes b directly. + t, err := UnmarshalTree[N, I](b) + if err != nil { + return err + } + if o.formatNodeNames != nil { + t.FormatNodeNames(o.formatNodeNames) + } + m.MergeTree(t) + return nil +} + +func (m *TreeMerger[N, I]) Tree() *Tree[N, I] { + if m.t == nil { + return new(Tree[N, I]) + } + return m.t +} + +func (m *TreeMerger[N, I]) IsEmpty() bool { + return m.t == nil +} diff --git a/pkg/model/tree_test.go b/pkg/model/tree_test.go index 75cd82271e..95575680cd 100644 --- a/pkg/model/tree_test.go +++ b/pkg/model/tree_test.go @@ -3,22 +3,27 @@ package model import ( "bytes" "math" + "slices" + "strconv" + "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ) func Test_Tree(t *testing.T) { for _, tc := range []struct { name string stacks []stacktraces - expected func() *Tree + expected func() *FunctionNameTree }{ { "empty", []stacktraces{}, - func() *Tree { return &Tree{} }, + func() *FunctionNameTree { return &FunctionNameTree{} }, }, { "double node single stack", @@ -32,9 +37,10 @@ func Test_Tree(t *testing.T) { value: 1, }, }, - func() *Tree { + func() *FunctionNameTree { tr := emptyTree() - tr.add("bar", 0, 2).add("buz", 2, 2) + bar := addNodeToTree(tr, "bar", 0, 2) + addNodeToNode(bar, "buz", 2, 2) return tr }, }, @@ -50,11 +56,13 @@ func Test_Tree(t *testing.T) { value: 2, }, }, - func() *Tree { + func() *FunctionNameTree { tr := emptyTree() - buz := tr.add("bar", 0, 3).add("buz", 0, 3) - buz.add("blip", 1, 1) - buz.add("blop", 0, 2).add("blap", 2, 2) + bar := addNodeToTree(tr, "bar", 0, 3) + buz := addNodeToNode(bar, "buz", 0, 3) + addNodeToNode(buz, "blip", 1, 1) + blop := addNodeToNode(buz, "blop", 0, 2) + addNodeToNode(blop, "blap", 2, 2) return tr }, }, @@ -86,17 +94,17 @@ func Test_Tree(t *testing.T) { value: 4, }, }, - func() *Tree { + func() *FunctionNameTree { tr := emptyTree() - bar := tr.add("bar", 0, 9) - bar.add("blip", 4, 4) + bar := addNodeToTree(tr, "bar", 0, 9) + addNodeToNode(bar, "blip", 4, 4) - buz := bar.add("buz", 2, 5) - buz.add("blop", 2, 2) - buz.add("foo", 1, 1) + buz := addNodeToNode(bar, "buz", 2, 5) + addNodeToNode(buz, "blop", 2, 2) + addNodeToNode(buz, "foo", 1, 1) - tr.add("buz", 1, 1) + addNodeToTree(tr, "buz", 1, 1) return tr }, }, @@ -112,7 +120,7 @@ func Test_Tree(t *testing.T) { func Test_TreeMerge(t *testing.T) { type testCase struct { description string - src, dst, expected *Tree + src, dst, expected *FunctionNameTree } testCases := func() []testCase { @@ -122,14 +130,14 @@ func Test_TreeMerge(t *testing.T) { dst: newTree([]stacktraces{ {locations: []string{"c", "b", "a"}, value: 1}, }), - src: new(Tree), + src: new(FunctionNameTree), expected: newTree([]stacktraces{ {locations: []string{"c", "b", "a"}, value: 1}, }), }, { description: "empty dst", - dst: new(Tree), + dst: new(FunctionNameTree), src: newTree([]stacktraces{ {locations: []string{"c", "b", "a"}, value: 1}, }), @@ -139,9 +147,9 @@ func Test_TreeMerge(t *testing.T) { }, { description: "empty both", - dst: new(Tree), - src: new(Tree), - expected: new(Tree), + dst: new(FunctionNameTree), + src: new(FunctionNameTree), + expected: new(FunctionNameTree), }, { description: "missing nodes in dst", @@ -222,10 +230,10 @@ func Test_Tree_minValue(t *testing.T) { func Test_Tree_MarshalUnmarshal(t *testing.T) { t.Run("empty tree", func(t *testing.T) { - expected := new(Tree) + expected := new(FunctionNameTree) var buf bytes.Buffer - require.NoError(t, expected.MarshalTruncate(&buf, -1)) - actual, err := UnmarshalTree(buf.Bytes()) + require.NoError(t, expected.MarshalTruncate(&buf, -1, nil)) + actual, err := UnmarshalTree[FunctionName, FunctionNameI](buf.Bytes()) require.NoError(t, err) require.Equal(t, expected.String(), actual.String()) }) @@ -244,8 +252,8 @@ func Test_Tree_MarshalUnmarshal(t *testing.T) { }) var buf bytes.Buffer - require.NoError(t, expected.MarshalTruncate(&buf, -1)) - actual, err := UnmarshalTree(buf.Bytes()) + require.NoError(t, expected.MarshalTruncate(&buf, -1, nil)) + actual, err := UnmarshalTree[FunctionName, FunctionNameI](buf.Bytes()) require.NoError(t, err) require.Equal(t, expected.String(), actual.String()) }) @@ -264,9 +272,9 @@ func Test_Tree_MarshalUnmarshal(t *testing.T) { }) var buf bytes.Buffer - require.NoError(t, fullTree.MarshalTruncate(&buf, 3)) + require.NoError(t, fullTree.MarshalTruncate(&buf, 3, nil)) - actual, err := UnmarshalTree(buf.Bytes()) + actual, err := UnmarshalTree[FunctionName, FunctionNameI](buf.Bytes()) require.NoError(t, err) expected := newTree([]stacktraces{ @@ -287,9 +295,11 @@ func Test_FormatNames(t *testing.T) { {locations: []string{"e1", "c1", "a1"}, value: 4}, {locations: []string{"e2", "c1", "a2"}, value: 4}, }) - x.FormatNodeNames(func(n string) string { - if len(n) > 0 { - n = n[:1] + x.FormatNodeNames(func(n FunctionName) FunctionName { + s := string(n) + if len(s) > 0 { + s = s[:1] + n = FunctionName(s) } return n }) @@ -303,11 +313,11 @@ func Test_FormatNames(t *testing.T) { require.Equal(t, expected.String(), x.String()) } -func emptyTree() *Tree { - return &Tree{} +func emptyTree() *FunctionNameTree { + return &FunctionNameTree{} } -func newTree(stacks []stacktraces) *Tree { +func newTree(stacks []stacktraces) *FunctionNameTree { t := emptyTree() for _, stack := range stacks { if stack.value == 0 { @@ -327,9 +337,9 @@ type stacktraces struct { value int64 } -func (t *Tree) add(name string, self, total int64) *node { - new := &node{ - name: name, +func addNodeToTree(t *FunctionNameTree, name string, self, total int64) *node[FunctionName] { + new := &node[FunctionName]{ + name: FunctionName(name), self: self, total: total, } @@ -337,10 +347,10 @@ func (t *Tree) add(name string, self, total int64) *node { return new } -func (n *node) add(name string, self, total int64) *node { - new := &node{ +func addNodeToNode(n *node[FunctionName], name string, self, total int64) *node[FunctionName] { + new := &node[FunctionName]{ parent: n, - name: name, + name: FunctionName(name), self: self, total: total, } @@ -348,15 +358,15 @@ func (n *node) add(name string, self, total int64) *node { return new } -func stackToTree(stack stacktraces) *Tree { +func stackToTree(stack stacktraces) *FunctionNameTree { t := emptyTree() if len(stack.locations) == 0 { return t } - current := &node{ + current := &node[FunctionName]{ self: stack.value, total: stack.value, - name: stack.locations[0], + name: FunctionName(stack.locations[0]), } if len(stack.locations) == 1 { t.root = append(t.root, current) @@ -379,14 +389,203 @@ func stackToTree(stack stacktraces) *Tree { // break // } - parent := &node{ - children: []*node{current}, + parent := &node[FunctionName]{ + children: []*node[FunctionName]{current}, total: current.total, - name: name, + name: FunctionName(name), } current.parent = parent current = parent } - t.root = []*node{current} + t.root = []*node[FunctionName]{current} return t } + +func Test_IterateStacks_LargeRootCount(t *testing.T) { + // Test for bug fix: when tree has more than 1024 root nodes, + // the initial capacity should be adjusted to avoid reallocation + tree := emptyTree() + + // Create a tree with 1500 root nodes (more than default capacity of 1024) + rootCount := 1500 + for i := 0; i < rootCount; i++ { + tree.InsertStack(1, FunctionName("root"+strconv.Itoa(i))) + } + + require.Equal(t, rootCount, len(tree.root), "should have %d root nodes", rootCount) + + // IterateStacks should handle this without issues + visitedCount := 0 + tree.IterateStacks(func(name FunctionName, self int64, stack []FunctionName) { + visitedCount++ + require.Equal(t, int64(1), self, "each node should have self=1") + require.Equal(t, 1, len(stack), "each stack should have length 1") + }) + + require.Equal(t, rootCount, visitedCount, "should visit all %d root nodes", rootCount) +} + +// Test_UnmarshalTree_IterateStacks_NoVirtualRootFrame verifies stacks from +// an unmarshaled tree match the stacks of the tree that was marshaled: the +// marshal format's virtual root node is removed from the tree structure and +// must also be detached from the parent chain, or IterateStacks' parent +// walk surfaces it as a spurious zero-valued root frame in every stack. +func Test_UnmarshalTree_IterateStacks_NoVirtualRootFrame(t *testing.T) { + src := emptyTree() + src.InsertStack(1, "a", "b") + src.InsertStack(2, "a", "c") + + collect := func(tr *Tree[FunctionName, FunctionNameI]) map[string]int64 { + out := make(map[string]int64) + tr.IterateStacks(func(_ FunctionName, self int64, stack []FunctionName) { + slices.Reverse(stack) + parts := make([]string, len(stack)) + for i, s := range stack { + parts[i] = string(s) + } + out[strings.Join(parts, "/")] += self + }) + return out + } + + want := collect(src) + require.Equal(t, map[string]int64{"a/b": 1, "a/c": 2}, want) + + unmarshaled, err := UnmarshalTree[FunctionName, FunctionNameI](src.Bytes(0, nil)) + require.NoError(t, err) + require.Equal(t, want, collect(unmarshaled)) + + // MergeTreeBytes adopts the unmarshaled tree wholesale on first merge, + // so it exercises the same parent-chain path. + m := NewTreeMerger[FunctionName, FunctionNameI]() + require.NoError(t, m.MergeTreeBytes(src.Bytes(0, nil))) + require.Equal(t, want, collect(m.Tree())) +} + +func Test_TreeFromBackendProfileSampleType(t *testing.T) { + profile := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + {Type: 3, Unit: 4}, + }, + StringTable: []string{ + "", + "samples", + "count", + "cpu", + "nanoseconds", + "main", + "foo", + "bar", + }, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, + Value: []int64{10, 20}, + }, + { + LocationId: []uint64{2, 3}, + Value: []int64{30, 60}, + }, + }, + Location: []*profilev1.Location{ + {Id: 1, Line: []*profilev1.Line{{FunctionId: 1}}}, + {Id: 2, Line: []*profilev1.Line{{FunctionId: 2}}}, + {Id: 3, Line: []*profilev1.Line{{FunctionId: 3}}}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 5}, + {Id: 2, Name: 6}, + {Id: 3, Name: 7}, + }, + } + + t.Run("using first sample type (index 0)", func(t *testing.T) { + treeBytes, err := TreeFromBackendProfileSampleType(profile, -1, 0) + require.NoError(t, err) + tree := MustUnmarshalTree[FunctionName, FunctionNameI](treeBytes) + assert.Equal(t, int64(40), tree.Total()) + }) + + t.Run("using second sample type (index 1)", func(t *testing.T) { + treeBytes, err := TreeFromBackendProfileSampleType(profile, -1, 1) + require.NoError(t, err) + tree := MustUnmarshalTree[FunctionName, FunctionNameI](treeBytes) + assert.Equal(t, int64(80), tree.Total()) + }) + + t.Run("validates sample type index bounds", func(t *testing.T) { + _, err := TreeFromBackendProfileSampleType(profile, -1, 99) + require.Error(t, err) + }) + + t.Run("handles profile with no samples", func(t *testing.T) { + emptyProfile := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + StringTable: []string{"", "samples", "count"}, + Sample: []*profilev1.Sample{}, + } + treeBytes, err := TreeFromBackendProfileSampleType(emptyProfile, -1, 0) + require.NoError(t, err) + tree := MustUnmarshalTree[FunctionName, FunctionNameI](treeBytes) + assert.Equal(t, int64(0), tree.Total()) + }) + + t.Run("handles profile with no sample types", func(t *testing.T) { + noSampleTypesProfile := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{}, + StringTable: []string{""}, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1}, + Value: []int64{10}, + }, + }, + } + _, err := TreeFromBackendProfileSampleType(noSampleTypesProfile, -1, 0) + require.Error(t, err) + }) + + t.Run("handles locations without line information (using addresses)", func(t *testing.T) { + addressProfile := &profilev1.Profile{ + StringTable: []string{ + "", + "samples", + "count", + }, + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Location: []*profilev1.Location{ + {Id: 1, Address: 0x1000, Line: []*profilev1.Line{}}, + {Id: 2, Address: 0x2000, Line: []*profilev1.Line{}}, + }, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1, 2}, // 0x1000 -> 0x2000 + Value: []int64{100}, // 100 samples + }, + }, + } + originalLen := len(addressProfile.StringTable) + + treeBytes, err := TreeFromBackendProfileSampleType(addressProfile, -1, 0) + require.NoError(t, err) + + tree := MustUnmarshalTree[FunctionName, FunctionNameI](treeBytes) + assert.Equal(t, int64(100), tree.Total()) + + assert.Greater(t, len(addressProfile.StringTable), originalLen) + + // Check for specific address strings in the string table + foundAddresses := 0 + for _, s := range addressProfile.StringTable { + if s == "1000" || s == "2000" { + foundAddresses++ + } + } + assert.Equal(t, 2, foundAddresses) + }) +} diff --git a/pkg/objstore/client/client_mock.go b/pkg/objstore/client/client_mock.go deleted file mode 100644 index 6c5c920cd7..0000000000 --- a/pkg/objstore/client/client_mock.go +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/storage/bucket/client_mock.go -// Provenance-includes-license: Apache-2.0 -// Provenance-includes-copyright: The Cortex Authors. - -package client - -import ( - "bytes" - "context" - "errors" - "io" - "time" - - "github.com/stretchr/testify/mock" - "github.com/thanos-io/objstore" -) - -// ErrObjectDoesNotExist is used in tests to simulate objstore.Bucket.IsObjNotFoundErr(). -var ErrObjectDoesNotExist = errors.New("object does not exist") - -// ClientMock mocks objstore.Bucket -type ClientMock struct { - mock.Mock -} - -// Upload mocks objstore.Bucket.Upload() -func (m *ClientMock) Upload(ctx context.Context, name string, r io.Reader) error { - args := m.Called(ctx, name, r) - return args.Error(0) -} - -func (m *ClientMock) MockUpload(name string, err error) { - m.On("Upload", mock.Anything, name, mock.Anything).Return(err) -} - -// Delete mocks objstore.Bucket.Delete() -func (m *ClientMock) Delete(ctx context.Context, name string) error { - args := m.Called(ctx, name) - return args.Error(0) -} - -// Name mocks objstore.Bucket.Name() -func (m *ClientMock) Name() string { - return "mock" -} - -// Iter mocks objstore.Bucket.Iter() -func (m *ClientMock) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { - args := m.Called(ctx, dir, f, options) - return args.Error(0) -} - -// MockIter is a convenient method to mock Iter() -func (m *ClientMock) MockIter(prefix string, objects []string, err error) { - m.MockIterWithCallback(prefix, objects, err, nil) -} - -// MockIterWithCallback is a convenient method to mock Iter() and get a callback called when the Iter -// API is called. -func (m *ClientMock) MockIterWithCallback(prefix string, objects []string, err error, cb func()) { - m.On("Iter", mock.Anything, prefix, mock.Anything, mock.Anything).Return(err).Run(func(args mock.Arguments) { - if cb != nil { - cb() - } - - f := args.Get(2).(func(string) error) - - for _, o := range objects { - if f(o) != nil { - break - } - } - }) -} - -// Get mocks objstore.Bucket.Get() -func (m *ClientMock) Get(ctx context.Context, name string) (io.ReadCloser, error) { - args := m.Called(ctx, name) - - // Allow to mock the Get() with a function which is called each time. - if fn, ok := args.Get(0).(func(ctx context.Context, name string) (io.ReadCloser, error)); ok { - return fn(ctx, name) - } - - val, err := args.Get(0), args.Error(1) - if val == nil { - return nil, err - } - return val.(io.ReadCloser), err -} - -// MockGet is a convenient method to mock Get() and Exists() -func (m *ClientMock) MockGet(name, content string, err error) { - if content != "" { - m.On("Exists", mock.Anything, name).Return(true, err) - m.On("Attributes", mock.Anything, name).Return(objstore.ObjectAttributes{ - Size: int64(len(content)), - LastModified: time.Now(), - }, nil) - - // Since we return an ReadCloser and it can be consumed only once, - // each time the mocked Get() is called we do create a new one, so - // that getting the same mocked object twice works as expected. - m.On("Get", mock.Anything, name).Return(func(_ context.Context, _ string) (io.ReadCloser, error) { - return io.NopCloser(bytes.NewReader([]byte(content))), err - }) - } else { - m.On("Exists", mock.Anything, name).Return(false, err) - m.On("Get", mock.Anything, name).Return(nil, ErrObjectDoesNotExist) - m.On("Attributes", mock.Anything, name).Return(nil, ErrObjectDoesNotExist) - } -} - -func (m *ClientMock) MockDelete(name string, err error) { - m.On("Delete", mock.Anything, name).Return(err) -} - -func (m *ClientMock) MockExists(name string, exists bool, err error) { - m.On("Exists", mock.Anything, name).Return(exists, err) -} - -// GetRange mocks objstore.Bucket.GetRange() -func (m *ClientMock) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { - args := m.Called(ctx, name, off, length) - return args.Get(0).(io.ReadCloser), args.Error(1) -} - -// Exists mocks objstore.Bucket.Exists() -func (m *ClientMock) Exists(ctx context.Context, name string) (bool, error) { - args := m.Called(ctx, name) - return args.Bool(0), args.Error(1) -} - -// IsObjNotFoundErr mocks objstore.Bucket.IsObjNotFoundErr() -func (m *ClientMock) IsObjNotFoundErr(err error) bool { - return errors.Is(err, ErrObjectDoesNotExist) -} - -// ObjectSize mocks objstore.Bucket.Attributes() -func (m *ClientMock) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { - args := m.Called(ctx, name) - return args.Get(0).(objstore.ObjectAttributes), args.Error(1) -} - -// Close mocks objstore.Bucket.Close() -func (m *ClientMock) Close() error { - return nil -} diff --git a/pkg/objstore/client/config.go b/pkg/objstore/client/config.go index 495abe359d..e7b585f719 100644 --- a/pkg/objstore/client/config.go +++ b/pkg/objstore/client/config.go @@ -4,19 +4,19 @@ import ( "errors" "flag" "fmt" - "regexp" "strings" "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/samber/lo" "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/objstore/providers/azure" - "github.com/grafana/pyroscope/pkg/objstore/providers/cos" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/objstore/providers/gcs" - "github.com/grafana/pyroscope/pkg/objstore/providers/s3" - "github.com/grafana/pyroscope/pkg/objstore/providers/swift" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/azure" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/cos" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/gcs" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/s3" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/swift" ) const ( @@ -40,18 +40,26 @@ const ( // Filesystem is the value for the filesystem storage backend. Filesystem = "filesystem" - - // validPrefixCharactersRegex allows only alphanumeric characters to prevent subtle bugs and simplify validation - validPrefixCharactersRegex = `^[\da-zA-Z]+$` ) var ( SupportedBackends = []string{S3, GCS, Azure, Swift, Filesystem, COS} - ErrUnsupportedStorageBackend = errors.New("unsupported storage backend") - ErrInvalidCharactersInStoragePrefix = errors.New("storage prefix contains invalid characters, it may only contain digits and English alphabet letters") + ErrUnsupportedStorageBackend = errors.New("unsupported storage backend") + ErrStoragePrefixStartsWithSlash = errors.New("storage prefix starts with a slash") + ErrStoragePrefixEmptyPathSegment = errors.New("storage prefix contains an empty path segment") + ErrStoragePrefixInvalidCharacters = errors.New("storage prefix contains invalid characters: only alphanumeric, hyphen, underscore, dot, and no segement should be '.' or '..'") + ErrStoragePrefixBothFlagsSet = errors.New("both storage.prefix and storage.storage-prefix are set, please use only storage.prefix, as storage.storage-prefix is deprecated") ) +type ErrInvalidCharactersInStoragePrefix struct { + Prefix string +} + +func (e *ErrInvalidCharactersInStoragePrefix) Error() string { + return fmt.Sprintf("storage prefix '%s' contains invalid characters", e.Prefix) +} + type StorageBackendConfig struct { Backend string `yaml:"backend"` @@ -70,25 +78,29 @@ func (cfg *StorageBackendConfig) supportedBackends() []string { } // RegisterFlags registers the backend storage config. -func (cfg *StorageBackendConfig) RegisterFlags(f *flag.FlagSet, logger log.Logger) { - cfg.RegisterFlagsWithPrefix("", f, logger) +func (cfg *StorageBackendConfig) RegisterFlags(f *flag.FlagSet) { + cfg.RegisterFlagsWithPrefix("", f) } -func (cfg *StorageBackendConfig) RegisterFlagsWithPrefixAndDefaultDirectory(prefix, dir string, f *flag.FlagSet, logger log.Logger) { +func (cfg *StorageBackendConfig) RegisterFlagsWithPrefixAndDefaultDirectory(prefix, dir string, f *flag.FlagSet) { cfg.S3.RegisterFlagsWithPrefix(prefix, f) cfg.GCS.RegisterFlagsWithPrefix(prefix, f) cfg.Azure.RegisterFlagsWithPrefix(prefix, f) cfg.Swift.RegisterFlagsWithPrefix(prefix, f) cfg.Filesystem.RegisterFlagsWithPrefixAndDefaultDirectory(prefix, dir, f) cfg.COS.RegisterFlagsWithPrefix(prefix, f) - f.StringVar(&cfg.Backend, prefix+"backend", None, fmt.Sprintf("Backend storage to use. Supported backends are: %s.", strings.Join(cfg.supportedBackends(), ", "))) + f.StringVar(&cfg.Backend, prefix+"backend", Filesystem, fmt.Sprintf("Backend storage to use. Supported backends are: %s.", strings.Join(cfg.supportedBackends(), ", "))) } -func (cfg *StorageBackendConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet, logger log.Logger) { - cfg.RegisterFlagsWithPrefixAndDefaultDirectory(prefix, "", f, logger) +func (cfg *StorageBackendConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + cfg.RegisterFlagsWithPrefixAndDefaultDirectory(prefix, "", f) } func (cfg *StorageBackendConfig) Validate() error { + if cfg.Backend == None { + return nil + } + if !lo.Contains(cfg.supportedBackends(), cfg.Backend) { return ErrUnsupportedStorageBackend } @@ -107,7 +119,8 @@ func (cfg *StorageBackendConfig) Validate() error { type Config struct { StorageBackendConfig `yaml:",inline"` - StoragePrefix string `yaml:"storage_prefix" category:"experimental"` + Prefix string `yaml:"prefix"` + DeprecatedStoragePrefix string `yaml:"storage_prefix" category:"experimental"` // Deprecated: use Prefix instead // Not used internally, meant to allow callers to wrap Buckets // created using this config @@ -115,26 +128,77 @@ type Config struct { } // RegisterFlags registers the backend storage config. -func (cfg *Config) RegisterFlags(f *flag.FlagSet, logger log.Logger) { - cfg.RegisterFlagsWithPrefix("", f, logger) +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + cfg.RegisterFlagsWithPrefix("", f) } -func (cfg *Config) RegisterFlagsWithPrefixAndDefaultDirectory(prefix, dir string, f *flag.FlagSet, logger log.Logger) { - cfg.StorageBackendConfig.RegisterFlagsWithPrefixAndDefaultDirectory(prefix, dir, f, logger) - f.StringVar(&cfg.StoragePrefix, prefix+"storage-prefix", "", "Prefix for all objects stored in the backend storage. For simplicity, it may only contain digits and English alphabet letters.") +func (cfg *Config) RegisterFlagsWithPrefixAndDefaultDirectory(prefix, dir string, f *flag.FlagSet) { + cfg.StorageBackendConfig.RegisterFlagsWithPrefixAndDefaultDirectory(prefix, dir, f) + f.StringVar(&cfg.Prefix, prefix+"prefix", "", "Prefix for all objects stored in the backend storage. For simplicity, it may only contain digits and English alphabet characters, hyphens, underscores, dots and forward slashes.") + f.StringVar(&cfg.DeprecatedStoragePrefix, prefix+"storage-prefix", "", "Deprecated: Use '"+prefix+".prefix' instead. Prefix for all objects stored in the backend storage. For simplicity, it may only contain digits and English alphabet characters, hyphens, underscores, dots and forward slashes.") } -func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet, logger log.Logger) { - cfg.RegisterFlagsWithPrefixAndDefaultDirectory(prefix, "./data-shared", f, logger) +func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + cfg.RegisterFlagsWithPrefixAndDefaultDirectory(prefix, "./data/v2/shared", f) } -func (cfg *Config) Validate() error { - if cfg.StoragePrefix != "" { - acceptablePrefixCharacters := regexp.MustCompile(validPrefixCharactersRegex) - if !acceptablePrefixCharacters.MatchString(cfg.StoragePrefix) { - return ErrInvalidCharactersInStoragePrefix +// alphanumeric, hyphen, underscore, dot, and must not be . or .. +func validStoragePrefixPart(part string) bool { + if part == "." || part == ".." { + return false + } + for i, b := range part { + if (b < 'a' || b > 'z') && (b < 'A' || b > 'Z') && b != '_' && b != '-' && b != '.' && (b < '0' || b > '9' || i == 0) { + return false } } + return true +} + +func validStoragePrefix(prefix string) error { + // without a prefix exit quickly + if prefix == "" { + return nil + } + + parts := strings.Split(prefix, "/") + + for idx, part := range parts { + if part == "" { + if idx == 0 { + return ErrStoragePrefixStartsWithSlash + } + if idx != len(parts)-1 { + return ErrStoragePrefixEmptyPathSegment + } + // slash at the end is fine + } + if !validStoragePrefixPart(part) { + return ErrStoragePrefixInvalidCharacters + } + } + + return nil +} + +func (cfg *Config) getPrefix() string { + if cfg.Prefix != "" { + return cfg.Prefix + } + + return cfg.DeprecatedStoragePrefix +} + +func (cfg *Config) Validate(logger log.Logger) error { + if cfg.DeprecatedStoragePrefix != "" { + if cfg.Prefix != "" { + return ErrStoragePrefixBothFlagsSet + } + level.Warn(logger).Log("msg", "bucket config has a deprecated storage.storage-prefix flag set. Please, use storage.prefix instead.") + } + if err := validStoragePrefix(cfg.getPrefix()); err != nil { + return err + } return cfg.StorageBackendConfig.Validate() } diff --git a/pkg/objstore/client/factory.go b/pkg/objstore/client/factory.go index 80632f5c71..e5fd6151fe 100644 --- a/pkg/objstore/client/factory.go +++ b/pkg/objstore/client/factory.go @@ -4,16 +4,17 @@ import ( "context" "github.com/thanos-io/objstore" - objtracing "github.com/thanos-io/objstore/tracing/opentracing" + objstoreotel "github.com/thanos-io/objstore/tracing/opentelemetry" + "go.opentelemetry.io/otel" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/objstore/providers/azure" - "github.com/grafana/pyroscope/pkg/objstore/providers/cos" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/objstore/providers/gcs" - "github.com/grafana/pyroscope/pkg/objstore/providers/s3" - "github.com/grafana/pyroscope/pkg/objstore/providers/swift" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/azure" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/cos" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/gcs" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/s3" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/swift" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) // NewBucket creates a new bucket client based on the configured backend @@ -24,6 +25,7 @@ func NewBucket(ctx context.Context, cfg Config, name string) (phlareobj.Bucket, ) logger := phlarecontext.Logger(ctx) reg := phlarecontext.Registry(ctx) + prefixPath := cfg.getPrefix() switch cfg.Backend { case S3: @@ -45,17 +47,17 @@ func NewBucket(ctx context.Context, cfg Config, name string) (phlareobj.Bucket, return objstore.WrapWithMetrics(b, reg, name), nil }, func(b objstore.Bucket) (objstore.Bucket, error) { - return objtracing.WrapWithTraces(b), nil + return objstoreotel.WrapWithTraces(b, otel.Tracer("objstore")), nil }, } fs, err := filesystem.NewBucket(cfg.Filesystem.Directory, append(middlewares, cfg.Middlewares...)...) if err != nil { return nil, err } - if cfg.StoragePrefix == "" { + if prefixPath == "" { return fs, nil } - return phlareobj.NewPrefixedBucket(fs, cfg.StoragePrefix), nil + return phlareobj.NewPrefixedBucket(fs, prefixPath), nil default: return nil, ErrUnsupportedStorageBackend } @@ -71,10 +73,10 @@ func NewBucket(ctx context.Context, cfg Config, name string) (phlareobj.Bucket, return nil, err } } - bkt := phlareobj.NewBucket(objtracing.WrapWithTraces(objstore.WrapWithMetrics(backendClient, reg, name))) + bkt := phlareobj.NewBucket(objstoreotel.WrapWithTraces(objstore.WrapWithMetrics(backendClient, reg, name), otel.Tracer("objstore"))) - if cfg.StoragePrefix != "" { - bkt = phlareobj.NewPrefixedBucket(bkt, cfg.StoragePrefix) + if prefixPath != "" { + bkt = phlareobj.NewPrefixedBucket(bkt, prefixPath) } return bkt, nil } diff --git a/pkg/objstore/client/factory_test.go b/pkg/objstore/client/factory_test.go index 376eb12d62..e22c1d3410 100644 --- a/pkg/objstore/client/factory_test.go +++ b/pkg/objstore/client/factory_test.go @@ -8,18 +8,17 @@ package client import ( "bytes" "context" - "io" "os" "path" - "sync" "testing" + "github.com/go-kit/log" "github.com/grafana/dskit/flagext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" ) const ( @@ -103,76 +102,103 @@ func TestNewClient(t *testing.T) { } } -func TestClientMock_MockGet(t *testing.T) { - expected := "body" - - m := ClientMock{} - m.MockGet("test", expected, nil) - - // Run many goroutines all requesting the same mocked object and - // ensure there's no race. - wg := sync.WaitGroup{} - for i := 0; i < 1000; i++ { - wg.Add(1) - go func() { - defer wg.Done() - - reader, err := m.Get(context.Background(), "test") - require.NoError(t, err) - - actual, err := io.ReadAll(reader) - require.NoError(t, err) - require.Equal(t, []byte(expected), actual) - - require.NoError(t, reader.Close()) - }() - } - - wg.Wait() -} - func TestClient_ConfigValidation(t *testing.T) { testCases := []struct { name string cfg Config expectedError error + expectedLog string }{ { - name: "valid storage_prefix", - cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, StoragePrefix: "helloworld"}, + name: "prefix/valid", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "helloWORLD123"}, + }, + { + name: "prefix/valid-subdir", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "hello/world/env"}, + }, + { + name: "prefix/valid-subdir-trailing-slash", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "hello/world/env/"}, + }, + { + name: "prefix/invalid-directory-up", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: ".."}, + expectedError: ErrStoragePrefixInvalidCharacters, }, { - name: "storage_prefix non-alphanumeric characters", - cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, StoragePrefix: "hello-world!"}, - expectedError: ErrInvalidCharactersInStoragePrefix, + name: "prefix/invalid-directory", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "."}, + expectedError: ErrStoragePrefixInvalidCharacters, }, { - name: "storage_prefix suffixed with a slash (non-alphanumeric)", - cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, StoragePrefix: "helloworld/"}, - expectedError: ErrInvalidCharactersInStoragePrefix, + name: "prefix/invalid-absolute-path", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "/hello/world"}, + expectedError: ErrStoragePrefixStartsWithSlash, }, { - name: "storage_prefix that has some character strings that have a meaning in unix paths (..)", - cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, StoragePrefix: ".."}, - expectedError: ErrInvalidCharactersInStoragePrefix, + name: "prefix/invalid-..-in-a-path-segement", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "hello/../test"}, + expectedError: ErrStoragePrefixInvalidCharacters, }, { - name: "storage_prefix that has some character strings that have a meaning in unix paths (.)", - cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, StoragePrefix: "."}, - expectedError: ErrInvalidCharactersInStoragePrefix, + name: "prefix/invalid-empty-path-segement", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "hello//test"}, + expectedError: ErrStoragePrefixEmptyPathSegment, + }, + { + name: "prefix/invalid-emoji", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "👋"}, + expectedError: ErrStoragePrefixInvalidCharacters, + }, + { + name: "prefix/invalid-exclamation-mark", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, Prefix: "hello!world"}, + expectedError: ErrStoragePrefixInvalidCharacters, }, { name: "unsupported backend", cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: "flash drive"}}, expectedError: ErrUnsupportedStorageBackend, }, + { + name: "prefix/valid-legacy-subdir-trailing-slash", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, DeprecatedStoragePrefix: "hello/world/env/"}, + expectedLog: "config has a deprecated storage.storage-prefix flag set", + }, + { + name: "prefix/deprecated-invalid-exclamation-mark", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, DeprecatedStoragePrefix: "hello!world"}, + expectedError: ErrStoragePrefixInvalidCharacters, + expectedLog: "config has a deprecated storage.storage-prefix flag set", + }, + { + name: "prefix/invalid-both-configs", + cfg: Config{StorageBackendConfig: StorageBackendConfig{Backend: Filesystem}, DeprecatedStoragePrefix: "hello-world1", Prefix: "hello-world2"}, + expectedError: ErrStoragePrefixBothFlagsSet, + }, } + logBuf := new(bytes.Buffer) + logger := log.NewLogfmtLogger(logBuf) + for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - actualErr := tc.cfg.Validate() - assert.ErrorIs(t, actualErr, tc.expectedError) + // Reset log buffer + logBuf.Reset() + + actualErr := tc.cfg.Validate(logger) + if tc.expectedError != nil { + assert.Equal(t, actualErr, tc.expectedError) + } else { + assert.NoError(t, actualErr) + } + if tc.expectedLog != "" { + assert.Contains(t, logBuf.String(), tc.expectedLog) + } else { + assert.Empty(t, logBuf.String()) + } }) } } @@ -188,7 +214,7 @@ func TestNewPrefixedBucketClient(t *testing.T) { Directory: tempDir, }, }, - StoragePrefix: "prefix", + Prefix: "prefix", } client, err := NewBucket(ctx, cfg, "test") diff --git a/pkg/objstore/client_mock.go b/pkg/objstore/client_mock.go deleted file mode 100644 index 4f4bd30b22..0000000000 --- a/pkg/objstore/client_mock.go +++ /dev/null @@ -1,176 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/storage/bucket/client_mock.go -// Provenance-includes-license: Apache-2.0 -// Provenance-includes-copyright: The Cortex Authors. - -package objstore - -import ( - "bytes" - "context" - "errors" - "io" - "time" - - "github.com/stretchr/testify/mock" - "github.com/thanos-io/objstore" -) - -// ErrObjectDoesNotExist is used in tests to simulate objstore.Bucket.IsObjNotFoundErr(). -var ErrObjectDoesNotExist = errors.New("object does not exist") - -// ClientMock mocks objstore.Bucket -type ClientMock struct { - mock.Mock -} - -// Upload mocks objstore.Bucket.Upload() -func (m *ClientMock) Upload(ctx context.Context, name string, r io.Reader) error { - args := m.Called(ctx, name, r) - return args.Error(0) -} - -func (m *ClientMock) MockUpload(name string, err error) { - m.On("Upload", mock.Anything, name, mock.Anything).Return(err) -} - -// Delete mocks objstore.Bucket.Delete() -func (m *ClientMock) Delete(ctx context.Context, name string) error { - args := m.Called(ctx, name) - return args.Error(0) -} - -// Name mocks objstore.Bucket.Name() -func (m *ClientMock) Name() string { - return "mock" -} - -// Iter mocks objstore.Bucket.Iter() -func (m *ClientMock) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { - args := m.Called(ctx, dir, f, options) - return args.Error(0) -} - -// MockIter is a convenient method to mock Iter() -func (m *ClientMock) MockIter(prefix string, objects []string, err error) { - m.MockIterWithCallback(prefix, objects, err, nil) -} - -// MockIterWithCallback is a convenient method to mock Iter() and get a callback called when the Iter -// API is called. -func (m *ClientMock) MockIterWithCallback(prefix string, objects []string, err error, cb func()) { - m.On("Iter", mock.Anything, prefix, mock.Anything, mock.Anything).Return(err).Run(func(args mock.Arguments) { - if cb != nil { - cb() - } - - f := args.Get(2).(func(string) error) - - for _, o := range objects { - if f(o) != nil { - break - } - } - }) -} - -// Get mocks objstore.Bucket.Get() -func (m *ClientMock) Get(ctx context.Context, name string) (io.ReadCloser, error) { - args := m.Called(ctx, name) - - // Allow to mock the Get() with a function which is called each time. - if fn, ok := args.Get(0).(func(ctx context.Context, name string) (io.ReadCloser, error)); ok { - return fn(ctx, name) - } - - val, err := args.Get(0), args.Error(1) - if val == nil { - return nil, err - } - return val.(io.ReadCloser), err -} - -func (m *ClientMock) ReaderAt(ctx context.Context, name string) (ReaderAtCloser, error) { - args := m.Called(ctx, name) - - // Allow to mock the ReaderAt() with a function which is called each time. - if fn, ok := args.Get(0).(func(ctx context.Context, name string) (ReaderAtCloser, error)); ok { - return fn(ctx, name) - } - - val, err := args.Get(0), args.Error(1) - if val == nil { - return nil, err - } - return val.(ReaderAtCloser), err -} - -// MockGet is a convenient method to mock Get() and Exists() -func (m *ClientMock) MockGet(name, content string, err error) { - m.MockGetAndLastModified(name, content, time.Now(), err) -} - -func (m *ClientMock) MockGetAndLastModified(name, content string, lastModified time.Time, err error) { - if content != "" { - m.On("Exists", mock.Anything, name).Return(true, err) - m.On("Attributes", mock.Anything, name).Return(objstore.ObjectAttributes{ - Size: int64(len(content)), - LastModified: lastModified, - }, nil) - - // Since we return an ReadCloser and it can be consumed only once, - // each time the mocked Get() is called we do create a new one, so - // that getting the same mocked object twice works as expected. - m.On("Get", mock.Anything, name).Return(func(_ context.Context, _ string) (io.ReadCloser, error) { - return io.NopCloser(bytes.NewReader([]byte(content))), err - }) - } else { - m.On("Exists", mock.Anything, name).Return(false, err) - m.On("Get", mock.Anything, name).Return(nil, ErrObjectDoesNotExist) - m.On("Attributes", mock.Anything, name).Return(nil, ErrObjectDoesNotExist) - } -} - -func (m *ClientMock) MockAttributes(name string, attrs objstore.ObjectAttributes, err error) { - m.On("Attributes", mock.Anything, name).Return(attrs, err) -} - -func (m *ClientMock) MockDelete(name string, err error) { - m.On("Delete", mock.Anything, name).Return(err) -} - -func (m *ClientMock) MockExists(name string, exists bool, err error) { - m.On("Exists", mock.Anything, name).Return(exists, err) -} - -// GetRange mocks objstore.Bucket.GetRange() -func (m *ClientMock) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { - args := m.Called(ctx, name, off, length) - return args.Get(0).(io.ReadCloser), args.Error(1) -} - -// Exists mocks objstore.Bucket.Exists() -func (m *ClientMock) Exists(ctx context.Context, name string) (bool, error) { - args := m.Called(ctx, name) - return args.Bool(0), args.Error(1) -} - -// IsObjNotFoundErr mocks objstore.Bucket.IsObjNotFoundErr() -func (m *ClientMock) IsObjNotFoundErr(err error) bool { - return errors.Is(err, ErrObjectDoesNotExist) -} - -func (m *ClientMock) IsAccessDeniedErr(_ error) bool { - return false -} - -// ObjectSize mocks objstore.Bucket.Attributes() -func (m *ClientMock) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { - args := m.Called(ctx, name) - return args.Get(0).(objstore.ObjectAttributes), args.Error(1) -} - -// Close mocks objstore.Bucket.Close() -func (m *ClientMock) Close() error { - return nil -} diff --git a/pkg/objstore/counting.go b/pkg/objstore/counting.go new file mode 100644 index 0000000000..46fdd4680d --- /dev/null +++ b/pkg/objstore/counting.go @@ -0,0 +1,90 @@ +package objstore + +import ( + "context" + "io" + "sync" + "sync/atomic" +) + +// CountingBucket wraps a Bucket and counts the bytes actually read via Get and +// GetRange calls. The counter is incremented as bytes are consumed from the +// returned ReadCloser, not when the call is issued, so short reads at EOF are +// not over-counted. Download is covered implicitly because objstore.Download +// calls Get internally. +// +// An internal WaitGroup tracks every open reader returned by Get and GetRange. +// Call Wait to block until all readers have been closed and their bytes fully +// counted. This is important when the bucket is used with async readers (e.g. +// parquet in ReadModeAsync) whose goroutines may still be draining a reader +// after the outer errgroup has returned. +// +// Attributes is not intercepted (it carries no payload bytes). +type CountingBucket struct { + Bucket + bytesRead *atomic.Uint64 + wg sync.WaitGroup +} + +func NewCountingBucket(bkt Bucket, counter *atomic.Uint64) *CountingBucket { + return &CountingBucket{Bucket: bkt, bytesRead: counter} +} + +// Wait blocks until every reader previously returned by Get or GetRange has +// been closed. Call this after all query goroutines have finished to ensure +// the byte counter is stable before reading it. +func (c *CountingBucket) Wait() { + c.wg.Wait() +} + +func (c *CountingBucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { + rc, err := c.Bucket.Get(ctx, name) + if err != nil { + return nil, err + } + c.wg.Add(1) + return &countingReadCloser{ReadCloser: rc, counter: c.bytesRead, wg: &c.wg}, nil +} + +func (c *CountingBucket) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + rc, err := c.Bucket.GetRange(ctx, name, off, length) + if err != nil { + return nil, err + } + c.wg.Add(1) + return &countingReadCloser{ReadCloser: rc, counter: c.bytesRead, wg: &c.wg}, nil +} + +// ReaderAt returns a ReaderAtCloser backed by this bucket's GetRange so that +// reads via ReaderAt are also counted. +func (c *CountingBucket) ReaderAt(ctx context.Context, name string) (ReaderAtCloser, error) { + return &ReaderAt{ + GetRangeReader: c, + name: name, + ctx: ctx, + }, nil +} + +// countingReadCloser wraps a ReadCloser and increments counter by the number +// of bytes returned from each Read call. It decrements the WaitGroup on Close +// so that CountingBucket.Wait can synchronise with async readers. +type countingReadCloser struct { + io.ReadCloser + counter *atomic.Uint64 + wg *sync.WaitGroup + once sync.Once +} + +func (r *countingReadCloser) Read(p []byte) (int, error) { + n, err := r.ReadCloser.Read(p) + if n > 0 { + r.counter.Add(uint64(n)) + } + return n, err +} + +func (r *countingReadCloser) Close() error { + err := r.ReadCloser.Close() + r.once.Do(r.wg.Done) + return err +} diff --git a/pkg/objstore/counting_test.go b/pkg/objstore/counting_test.go new file mode 100644 index 0000000000..abe1dfff39 --- /dev/null +++ b/pkg/objstore/counting_test.go @@ -0,0 +1,145 @@ +package objstore_test + +import ( + "bytes" + "context" + "io" + "sync/atomic" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" +) + +func Test_CountingBucket_Get(t *testing.T) { + inner := memory.NewInMemBucket() + ctx := context.Background() + data := []byte("hello world") + require.NoError(t, inner.Upload(ctx, "test", bytes.NewReader(data))) + + var counter atomic.Uint64 + bkt := objstore.NewCountingBucket(objstore.NewBucket(inner), &counter) + + rc, err := bkt.Get(ctx, "test") + require.NoError(t, err) + _, err = io.ReadAll(rc) + require.NoError(t, err) + require.NoError(t, rc.Close()) + require.Equal(t, uint64(len(data)), counter.Load()) + + // A failed Get must not increment the counter. + _, err = bkt.Get(ctx, "missing") + require.Error(t, err) + require.Equal(t, uint64(len(data)), counter.Load(), "failed reads must not count") +} + +func Test_CountingBucket_GetRange(t *testing.T) { + inner := memory.NewInMemBucket() + ctx := context.Background() + data := []byte("hello world") + require.NoError(t, inner.Upload(ctx, "test", bytes.NewReader(data))) + + var counter atomic.Uint64 + bkt := objstore.NewCountingBucket(objstore.NewBucket(inner), &counter) + + rc, err := bkt.GetRange(ctx, "test", 0, int64(len(data))) + require.NoError(t, err) + _, err = io.ReadAll(rc) + require.NoError(t, err) + require.NoError(t, rc.Close()) + require.Equal(t, uint64(len(data)), counter.Load()) + + // A failed GetRange must not increment the counter. + _, err = bkt.GetRange(ctx, "missing", 0, 5) + require.Error(t, err) + require.Equal(t, uint64(len(data)), counter.Load(), "failed reads must not count") +} + +func Test_CountingBucket_ReaderAt(t *testing.T) { + inner := memory.NewInMemBucket() + ctx := context.Background() + data := []byte("hello world") + require.NoError(t, inner.Upload(ctx, "test", bytes.NewReader(data))) + + var counter atomic.Uint64 + bkt := objstore.NewCountingBucket(objstore.NewBucket(inner), &counter) + + ra, err := bkt.ReaderAt(ctx, "test") + require.NoError(t, err) + defer func() { require.NoError(t, ra.Close()) }() + + buf := make([]byte, 5) + n, err := ra.ReadAt(buf, 0) + require.NoError(t, err) + require.Equal(t, 5, n) + require.Equal(t, uint64(5), counter.Load()) + + n, err = ra.ReadAt(buf, 6) + require.NoError(t, err) + require.Equal(t, 5, n) + require.Equal(t, uint64(10), counter.Load(), "second read must add to counter") +} + +func Test_CountingBucket_IndependentPerInvoke(t *testing.T) { + // Simulates the "retried calls do not accumulate" guarantee: each Invoke + // creates its own counter, so two independent invocations report their own + // bytes, not a running total. + inner := memory.NewInMemBucket() + ctx := context.Background() + data := []byte("hello world") + require.NoError(t, inner.Upload(ctx, "test", bytes.NewReader(data))) + + base := objstore.NewBucket(inner) + + invoke := func() uint64 { + var counter atomic.Uint64 + bkt := objstore.NewCountingBucket(base, &counter) + rc, err := bkt.GetRange(ctx, "test", 0, int64(len(data))) + require.NoError(t, err) + _, err = io.ReadAll(rc) + require.NoError(t, err) + require.NoError(t, rc.Close()) + return counter.Load() + } + + first := invoke() + second := invoke() + require.Equal(t, uint64(len(data)), first) + require.Equal(t, first, second, "independent invokes must report the same bytes") +} + +func Test_CountingBucket_Wait(t *testing.T) { + // Wait must block until all readers are closed, so the counter is + // stable before the caller samples it. + inner := memory.NewInMemBucket() + ctx := context.Background() + data := []byte("hello world") + require.NoError(t, inner.Upload(ctx, "test", bytes.NewReader(data))) + + var counter atomic.Uint64 + bkt := objstore.NewCountingBucket(objstore.NewBucket(inner), &counter) + + rc, err := bkt.GetRange(ctx, "test", 0, int64(len(data))) + require.NoError(t, err) + _, err = io.ReadAll(rc) + require.NoError(t, err) + // Do not close yet; Wait must still unblock once Close is called. + done := make(chan struct{}) + go func() { + bkt.Wait() + close(done) + }() + select { + case <-done: + t.Fatal("Wait returned before Close was called") + default: + } + require.NoError(t, rc.Close()) + <-done // must unblock now + require.Equal(t, uint64(len(data)), counter.Load()) +} + +// Ensure CountingBucket satisfies the Bucket interface at compile time. +var _ objstore.Bucket = (*objstore.CountingBucket)(nil) diff --git a/pkg/objstore/delayed_bucket_client.go b/pkg/objstore/delayed_bucket_client.go index 3bc568b6ef..6512920db8 100644 --- a/pkg/objstore/delayed_bucket_client.go +++ b/pkg/objstore/delayed_bucket_client.go @@ -32,11 +32,11 @@ func NewDelayedBucketClient(wrapped objstore.Bucket, minDelay, maxDelay time.Dur } } -func (m *DelayedBucketClient) Upload(ctx context.Context, name string, r io.Reader) error { +func (m *DelayedBucketClient) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { m.delay() defer m.delay() - return m.wrapped.Upload(ctx, name, r) + return m.wrapped.Upload(ctx, name, r, opts...) } func (m *DelayedBucketClient) Delete(ctx context.Context, name string) error { @@ -57,6 +57,16 @@ func (m *DelayedBucketClient) Iter(ctx context.Context, dir string, f func(strin return m.wrapped.Iter(ctx, dir, f, options...) } +func (m *DelayedBucketClient) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + m.delay() + defer m.delay() + return m.wrapped.IterWithAttributes(ctx, dir, f, options...) +} + +func (m *DelayedBucketClient) SupportedIterOptions() []objstore.IterOptionType { + return m.wrapped.SupportedIterOptions() +} + func (m *DelayedBucketClient) Get(ctx context.Context, name string) (io.ReadCloser, error) { m.delay() defer m.delay() @@ -97,6 +107,15 @@ func (m *DelayedBucketClient) Close() error { return m.wrapped.Close() } +func (m *DelayedBucketClient) Provider() objstore.ObjProvider { + return m.wrapped.Provider() +} + func (m *DelayedBucketClient) delay() { - time.Sleep(m.minDelay + time.Duration(rand.Int63n(m.maxDelay.Nanoseconds()-m.minDelay.Nanoseconds()))) + if m.minDelay == m.maxDelay { + time.Sleep(m.minDelay) + return + } + + time.Sleep(m.minDelay + time.Duration(rand.Int63n(int64(m.maxDelay-m.minDelay)))) } diff --git a/pkg/objstore/delayed_bucket_client_test.go b/pkg/objstore/delayed_bucket_client_test.go new file mode 100644 index 0000000000..81f18bf987 --- /dev/null +++ b/pkg/objstore/delayed_bucket_client_test.go @@ -0,0 +1,53 @@ +package objstore + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" +) + +func TestDelayedBucketClient_EqualDelaysDoNotPanic(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + minDelay time.Duration + maxDelay time.Duration + }{ + { + name: "zero delay", + minDelay: 0, + maxDelay: 0, + }, + { + name: "fixed non-zero delay", + minDelay: time.Millisecond, + maxDelay: time.Millisecond, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + bucket := NewDelayedBucketClient(memory.NewInMemBucket(), tt.minDelay, tt.maxDelay) + + require.NotPanics(t, func() { + _, err := bucket.Exists(context.Background(), "missing") + require.NoError(t, err) + }) + }) + } +} + +func TestNewDelayedBucketClient_InvalidConfigurationPanics(t *testing.T) { + t.Parallel() + + require.Panics(t, func() { + NewDelayedBucketClient(memory.NewInMemBucket(), time.Second, 0) + }) +} diff --git a/pkg/objstore/not_found.go b/pkg/objstore/not_found.go new file mode 100644 index 0000000000..c9821a7552 --- /dev/null +++ b/pkg/objstore/not_found.go @@ -0,0 +1,23 @@ +package objstore + +import ( + "errors" + + "github.com/thanos-io/objstore" +) + +func IsNotExist(b objstore.BucketReader, err error) bool { + // objstore relies on the Causer interface + // and does not understand wrapped errors. + return b.IsObjNotFoundErr(UnwrapErr(err)) +} + +func UnwrapErr(err error) error { + for { + unwrapped := errors.Unwrap(err) + if unwrapped == nil { + return err + } + err = unwrapped + } +} diff --git a/pkg/objstore/objstore.go b/pkg/objstore/objstore.go index ec22f935c8..25ab3734f4 100644 --- a/pkg/objstore/objstore.go +++ b/pkg/objstore/objstore.go @@ -50,7 +50,7 @@ func NewPrefixedBucket(bkt Bucket, prefix string) Bucket { } func validPrefix(prefix string) bool { - prefix = strings.Replace(prefix, "/", "", -1) + prefix = strings.ReplaceAll(prefix, "/", "") return len(prefix) > 0 } @@ -119,8 +119,8 @@ func (p PrefixedBucket) Attributes(ctx context.Context, name string) (objstore.O // Upload the contents of the reader as an object into the bucket. // Upload should be idempotent. -func (p *PrefixedBucket) Upload(ctx context.Context, name string, r io.Reader) error { - return p.Bucket.Upload(ctx, conditionalPrefix(p.prefix, name), r) +func (p *PrefixedBucket) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + return p.Bucket.Upload(ctx, conditionalPrefix(p.prefix, name), r, opts...) } // Delete removes the object with the given name. diff --git a/pkg/objstore/parquet/file.go b/pkg/objstore/parquet/file.go index 89a46d9187..35487fcc8e 100644 --- a/pkg/objstore/parquet/file.go +++ b/pkg/objstore/parquet/file.go @@ -6,8 +6,8 @@ import ( "github.com/parquet-go/parquet-go" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) type File struct { diff --git a/pkg/objstore/parquet/file_test.go b/pkg/objstore/parquet/file_test.go index 58507263df..541acc9358 100644 --- a/pkg/objstore/parquet/file_test.go +++ b/pkg/objstore/parquet/file_test.go @@ -9,9 +9,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) type readerAtCall struct { diff --git a/pkg/objstore/parquet/reader.go b/pkg/objstore/parquet/reader.go index 19bd8997cd..6b9625462d 100644 --- a/pkg/objstore/parquet/reader.go +++ b/pkg/objstore/parquet/reader.go @@ -6,8 +6,8 @@ import ( "fmt" "sync" - phlareobjstore "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + phlareobjstore "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) // bufferPool is a pool of bytes.Buffers. diff --git a/pkg/objstore/providers/azure/bucket_client.go b/pkg/objstore/providers/azure/bucket_client.go index 57a04f6fa2..de5bb2b6dc 100644 --- a/pkg/objstore/providers/azure/bucket_client.go +++ b/pkg/objstore/providers/azure/bucket_client.go @@ -6,6 +6,8 @@ package azure import ( + "net/http" + "github.com/go-kit/log" "github.com/thanos-io/objstore" "github.com/thanos-io/objstore/providers/azure" @@ -15,10 +17,13 @@ func NewBucketClient(cfg Config, name string, logger log.Logger) (objstore.Bucke return newBucketClient(cfg, name, logger, azure.NewBucketWithConfig) } -func newBucketClient(cfg Config, name string, logger log.Logger, factory func(log.Logger, azure.Config, string) (*azure.Bucket, error)) (objstore.Bucket, error) { +func newBucketClient(cfg Config, name string, logger log.Logger, factory func(log.Logger, azure.Config, string, func(http.RoundTripper) http.RoundTripper) (*azure.Bucket, error)) (objstore.Bucket, error) { // Start with default config to make sure that all parameters are set to sensible values, especially // HTTP Config field. bucketConfig := azure.DefaultConfig + bucketConfig.AzTenantID = cfg.AzTenantID + bucketConfig.ClientID = cfg.ClientID + bucketConfig.ClientSecret = cfg.ClientSecret.String() bucketConfig.StorageAccountName = cfg.StorageAccountName bucketConfig.StorageAccountKey = cfg.StorageAccountKey.String() bucketConfig.StorageConnectionString = cfg.StorageConnectionString.String() @@ -34,5 +39,5 @@ func newBucketClient(cfg Config, name string, logger log.Logger, factory func(lo bucketConfig.Endpoint = cfg.Endpoint } - return factory(logger, bucketConfig, name) + return factory(logger, bucketConfig, name, nil) } diff --git a/pkg/objstore/providers/azure/config.go b/pkg/objstore/providers/azure/config.go index d5ad0aa7a7..85e93fd58f 100644 --- a/pkg/objstore/providers/azure/config.go +++ b/pkg/objstore/providers/azure/config.go @@ -13,6 +13,9 @@ import ( // Config holds the config options for an Azure backend type Config struct { + AzTenantID string `yaml:"az_tenant_id"` + ClientID string `yaml:"client_id"` + ClientSecret flagext.Secret `yaml:"client_secret"` StorageAccountName string `yaml:"account_name"` StorageAccountKey flagext.Secret `yaml:"account_key"` StorageConnectionString flagext.Secret `yaml:"connection_string"` @@ -29,6 +32,9 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { // RegisterFlagsWithPrefix registers the flags for Azure storage func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.StringVar(&cfg.AzTenantID, prefix+"azure.az-tenant-id", "", "Azure Active Directory tenant ID. If set alongside `client-id` and `client-secret`, these values will be used for authentication via a client secret credential.") + f.StringVar(&cfg.ClientID, prefix+"azure.client-id", "", "Azure Active Directory client ID. If set alongside `az-tenant-id` and `client-secret`, these values will be used for authentication via a client secret credential.") + f.Var(&cfg.ClientSecret, prefix+"azure.client-secret", "Azure Active Directory client secret. If set alongside `az-tenant-id` and `client-id`, these values will be used for authentication via a client secret credential.") f.StringVar(&cfg.StorageAccountName, prefix+"azure.account-name", "", "Azure storage account name") f.Var(&cfg.StorageAccountKey, prefix+"azure.account-key", "Azure storage account key. If unset, Azure managed identities will be used for authentication instead.") f.Var(&cfg.StorageConnectionString, prefix+"azure.connection-string", "If `connection-string` is set, the value of `endpoint-suffix` will not be used. Use this method over `account-key` if you need to authenticate via a SAS token. Or if you use the Azurite emulator.") diff --git a/pkg/objstore/providers/cos/bucket_client.go b/pkg/objstore/providers/cos/bucket_client.go index c06bfe119b..82831d7899 100644 --- a/pkg/objstore/providers/cos/bucket_client.go +++ b/pkg/objstore/providers/cos/bucket_client.go @@ -6,7 +6,7 @@ import ( "github.com/thanos-io/objstore" "github.com/thanos-io/objstore/exthttp" "github.com/thanos-io/objstore/providers/cos" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) // NewBucketClient creates a bucket client for COS @@ -16,7 +16,7 @@ func NewBucketClient(cfg Config, name string, logger log.Logger) (objstore.Bucke Region: cfg.Region, AppId: cfg.AppID, Endpoint: cfg.Endpoint, - SecretKey: cfg.SecretKey, + SecretKey: cfg.SecretKey.String(), SecretId: cfg.SecretID, HTTPConfig: exthttp.HTTPConfig{ IdleConnTimeout: model.Duration(cfg.HTTP.IdleConnTimeout), @@ -36,5 +36,5 @@ func NewBucketClient(cfg Config, name string, logger log.Logger) (objstore.Bucke return nil, err } - return cos.NewBucket(logger, serializedConfig, name) + return cos.NewBucket(logger, serializedConfig, name, nil) } diff --git a/pkg/objstore/providers/cos/config.go b/pkg/objstore/providers/cos/config.go index 78d715a375..ff19d839a7 100644 --- a/pkg/objstore/providers/cos/config.go +++ b/pkg/objstore/providers/cos/config.go @@ -7,17 +7,19 @@ import ( "net/http" "net/url" "time" + + "github.com/grafana/dskit/flagext" ) // Config encapsulates the necessary config values to instantiate an cos client. type Config struct { - Bucket string `yaml:"bucket"` - Region string `yaml:"region"` - AppID string `yaml:"app_id"` - Endpoint string `yaml:"endpoint"` - SecretKey string `yaml:"secret_key"` - SecretID string `yaml:"secret_id"` - HTTP HTTPConfig `yaml:"http"` + Bucket string `yaml:"bucket"` + Region string `yaml:"region"` + AppID string `yaml:"app_id"` + Endpoint string `yaml:"endpoint"` + SecretKey flagext.Secret `yaml:"secret_key"` + SecretID string `yaml:"secret_id"` + HTTP HTTPConfig `yaml:"http"` } // Validate validates cos client config and returns error on failure @@ -27,13 +29,13 @@ func (c *Config) Validate() error { return fmt.Errorf("cos config: failed to parse endpoint: %w", err) } - if empty(c.SecretKey) || empty(c.SecretID) { + if empty(c.SecretKey.String()) || empty(c.SecretID) { return errors.New("secret id and secret key cannot be empty") } return nil } - if empty(c.Bucket) || empty(c.AppID) || empty(c.Region) || empty(c.SecretID) || empty(c.SecretKey) { + if empty(c.Bucket) || empty(c.AppID) || empty(c.Region) || empty(c.SecretID) || empty(c.SecretKey.String()) { return errors.New("invalid cos configuration, bucket, app_id, region, secret_id and secret_key must be set") } return nil @@ -55,7 +57,7 @@ func (c *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { f.StringVar(&c.AppID, prefix+"cos.app-id", "", "COS app id") f.StringVar(&c.Endpoint, prefix+"cos.endpoint", "", "COS storage endpoint") f.StringVar(&c.SecretID, prefix+"cos.secret-id", "", "COS secret id") - f.StringVar(&c.SecretKey, prefix+"cos.secret-key", "", "COS secret key") + f.Var(&c.SecretKey, prefix+"cos.secret-key", "COS secret key") c.HTTP.RegisterFlagsWithPrefix(prefix, f) } diff --git a/pkg/objstore/providers/cos/config_test.go b/pkg/objstore/providers/cos/config_test.go index 2123b8d784..1e628cccd7 100644 --- a/pkg/objstore/providers/cos/config_test.go +++ b/pkg/objstore/providers/cos/config_test.go @@ -1,6 +1,10 @@ package cos -import "testing" +import ( + "testing" + + "github.com/grafana/dskit/flagext" +) func TestConfig_Validate(t *testing.T) { type fields struct { @@ -8,7 +12,7 @@ func TestConfig_Validate(t *testing.T) { Region string AppID string Endpoint string - SecretKey string + SecretKey flagext.Secret SecretID string HTTP HTTPConfig } @@ -22,7 +26,7 @@ func TestConfig_Validate(t *testing.T) { fields: fields{ Endpoint: "http://bucket-123.cos.ap-beijing.myqcloud.com", SecretID: "sid", - SecretKey: "skey", + SecretKey: flagext.SecretWithValue("skey"), }, wantErr: false, }, @@ -33,7 +37,7 @@ func TestConfig_Validate(t *testing.T) { AppID: "123", Region: "ap-beijing", SecretID: "sid", - SecretKey: "skey", + SecretKey: flagext.SecretWithValue("skey"), }, wantErr: false, }, @@ -52,7 +56,7 @@ func TestConfig_Validate(t *testing.T) { AppID: "123", Region: "ap-beijing", SecretID: "sid", - SecretKey: "skey", + SecretKey: flagext.SecretWithValue("skey"), }, wantErr: true, }, diff --git a/pkg/objstore/providers/filesystem/bucket_client.go b/pkg/objstore/providers/filesystem/bucket_client.go index 0ae39e73f4..1903b746a1 100644 --- a/pkg/objstore/providers/filesystem/bucket_client.go +++ b/pkg/objstore/providers/filesystem/bucket_client.go @@ -2,17 +2,13 @@ package filesystem import ( "context" - "io" "os" "path/filepath" - "strings" - "github.com/grafana/dskit/runutil" - "github.com/pkg/errors" "github.com/thanos-io/objstore" "github.com/thanos-io/objstore/providers/filesystem" - phlareobjstore "github.com/grafana/pyroscope/pkg/objstore" + phlareobjstore "github.com/grafana/pyroscope/v2/pkg/objstore" ) type Bucket struct { @@ -48,95 +44,6 @@ func (b *Bucket) ReaderAt(ctx context.Context, filename string) (phlareobjstore. return &FileReaderAt{File: f}, nil } -func (b *Bucket) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { - params := objstore.ApplyIterOptions(options...) - if !params.WithoutAppendDirDelim || strings.HasSuffix(dir, objstore.DirDelim) { - if dir != "" { - dir = strings.TrimSuffix(dir, objstore.DirDelim) + objstore.DirDelim - } - return b.Bucket.Iter(ctx, dir, f, options...) - } - relDir := filepath.Dir(dir) - prefix := dir - return b.iterPrefix(ctx, filepath.Join(b.rootDir, relDir), relDir, prefix, f, options...) -} - -// iterPrefix calls f for each entry in the given directory matching the prefix. -func (b *Bucket) iterPrefix(ctx context.Context, absDir string, relDir string, prefix string, f func(string) error, options ...objstore.IterOption) error { - if ctx.Err() != nil { - return ctx.Err() - } - - params := objstore.ApplyIterOptions(options...) - info, err := os.Stat(absDir) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return errors.Wrapf(err, "stat %s", absDir) - } - if !info.IsDir() { - return nil - } - - files, err := os.ReadDir(absDir) - if err != nil { - return err - } - for _, file := range files { - name := filepath.Join(relDir, file.Name()) - if prefix != "" && !strings.HasPrefix(name, prefix) { - continue - } - - if file.IsDir() { - empty, err := isDirEmpty(filepath.Join(absDir, file.Name())) - if err != nil { - return err - } - - if empty { - // Skip empty directories. - continue - } - - name += objstore.DirDelim - - if params.Recursive { - // Recursively list files in the subdirectory. - if err := b.iterPrefix(ctx, filepath.Join(absDir, file.Name()), name, prefix, f, options...); err != nil { - return err - } - - // The callback f() has already been called for the subdirectory - // files so we should skip to next filesystem entry. - continue - } - } - if err := f(name); err != nil { - return err - } - } - return nil -} - -func isDirEmpty(name string) (ok bool, err error) { - f, err := os.Open(filepath.Clean(name)) - if os.IsNotExist(err) { - // The directory doesn't exist. We don't consider it an error and we treat it like empty. - return true, nil - } - if err != nil { - return false, err - } - defer runutil.CloseWithErrCapture(&err, f, "isDirEmpty") - - if _, err = f.Readdir(1); err == io.EOF || os.IsNotExist(err) { - return true, nil - } - return false, err -} - // ReaderWithExpectedErrs implements objstore.Bucket. func (b *Bucket) ReaderWithExpectedErrs(fn phlareobjstore.IsOpFailureExpectedFunc) phlareobjstore.BucketReader { return b.WithExpectedErrs(fn) diff --git a/pkg/objstore/providers/filesystem/bucket_client_test.go b/pkg/objstore/providers/filesystem/bucket_client_test.go index f24d0a24da..54c6fe59e2 100644 --- a/pkg/objstore/providers/filesystem/bucket_client_test.go +++ b/pkg/objstore/providers/filesystem/bucket_client_test.go @@ -9,6 +9,23 @@ import ( "github.com/thanos-io/objstore" ) +type testIterCase struct { + prefix string + expected []string + options []objstore.IterOption +} + +func (t testIterCase) name() string { + p := new(objstore.IterParams) + for _, opt := range t.options { + opt.Apply(p) + } + if p.Recursive { + return t.prefix + "#recursive" + } + return t.prefix +} + func TestIter(t *testing.T) { bkt, err := NewBucket(t.TempDir()) require.NoError(t, err) @@ -22,11 +39,7 @@ func TestIter(t *testing.T) { require.NoError(t, bkt.Upload(context.Background(), "foo/buzz5", buff)) require.NoError(t, bkt.Upload(context.Background(), "foo6", buff)) - for _, tc := range []struct { - prefix string - expected []string - options []objstore.IterOption - }{ + for _, tc := range []testIterCase{ { prefix: "foo/", expected: []string{"foo/ba/", "foo/bar/", "foo/buzz4", "foo/buzz5"}, @@ -35,21 +48,21 @@ func TestIter(t *testing.T) { { prefix: "foo/", expected: []string{"foo/ba/buzz3", "foo/bar/buz1", "foo/bar/buz2", "foo/buzz4", "foo/buzz5"}, - options: []objstore.IterOption{objstore.WithRecursiveIter}, + options: []objstore.IterOption{objstore.WithRecursiveIter()}, }, { prefix: "foo/ba", expected: []string{"foo/ba/buzz3"}, - options: []objstore.IterOption{objstore.WithRecursiveIter}, + options: []objstore.IterOption{objstore.WithRecursiveIter()}, }, { prefix: "foo/ba/", expected: []string{"foo/ba/buzz3"}, - options: []objstore.IterOption{objstore.WithRecursiveIter}, + options: []objstore.IterOption{objstore.WithRecursiveIter()}, }, { prefix: "foo/b", - options: []objstore.IterOption{objstore.WithRecursiveIter}, + options: []objstore.IterOption{objstore.WithRecursiveIter()}, }, { prefix: "foo", @@ -59,7 +72,7 @@ func TestIter(t *testing.T) { { prefix: "foo", expected: []string{"foo/ba/buzz3", "foo/bar/buz1", "foo/bar/buz2", "foo/buzz4", "foo/buzz5"}, - options: []objstore.IterOption{objstore.WithRecursiveIter}, + options: []objstore.IterOption{objstore.WithRecursiveIter()}, }, { prefix: "fo", @@ -67,7 +80,7 @@ func TestIter(t *testing.T) { }, { prefix: "fo", - options: []objstore.IterOption{objstore.WithRecursiveIter}, + options: []objstore.IterOption{objstore.WithRecursiveIter()}, }, { prefix: "", @@ -77,36 +90,10 @@ func TestIter(t *testing.T) { { prefix: "", expected: []string{"foo/ba/buzz3", "foo/bar/buz1", "foo/bar/buz2", "foo/buzz4", "foo/buzz5", "foo6"}, - options: []objstore.IterOption{objstore.WithRecursiveIter}, - }, - { - prefix: "foo", - expected: []string{"foo/", "foo6"}, - options: []objstore.IterOption{objstore.WithoutApendingDirDelim}, - }, - { - prefix: "f", - expected: []string{"foo/", "foo6"}, - options: []objstore.IterOption{objstore.WithoutApendingDirDelim}, - }, - { - prefix: "foo/ba", - expected: []string{"foo/ba/", "foo/bar/"}, - options: []objstore.IterOption{objstore.WithoutApendingDirDelim}, - }, - { - prefix: "foo/ba", - expected: []string{"foo/ba/buzz3", "foo/bar/buz1", "foo/bar/buz2"}, - options: []objstore.IterOption{objstore.WithoutApendingDirDelim, objstore.WithRecursiveIter}, - }, - { - prefix: "fo", - expected: []string{"foo/ba/buzz3", "foo/bar/buz1", "foo/bar/buz2", "foo/buzz4", "foo/buzz5", "foo6"}, - options: []objstore.IterOption{objstore.WithoutApendingDirDelim, objstore.WithRecursiveIter}, + options: []objstore.IterOption{objstore.WithRecursiveIter()}, }, } { - tc := tc - t.Run(tc.prefix, func(t *testing.T) { + t.Run(tc.name(), func(t *testing.T) { var keys []string err = bkt.Iter(context.Background(), tc.prefix, func(key string) error { keys = append(keys, key) diff --git a/pkg/objstore/providers/gcs/bucket_client.go b/pkg/objstore/providers/gcs/bucket_client.go index 53db52c6b5..01a258a753 100644 --- a/pkg/objstore/providers/gcs/bucket_client.go +++ b/pkg/objstore/providers/gcs/bucket_client.go @@ -9,9 +9,11 @@ import ( "context" "github.com/go-kit/log" + "github.com/prometheus/common/model" "github.com/thanos-io/objstore" + "github.com/thanos-io/objstore/exthttp" "github.com/thanos-io/objstore/providers/gcs" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) // NewBucketClient creates a new GCS bucket client @@ -19,6 +21,16 @@ func NewBucketClient(ctx context.Context, cfg Config, name string, logger log.Lo bucketConfig := gcs.Config{ Bucket: cfg.BucketName, ServiceAccount: cfg.ServiceAccount.String(), + HTTPConfig: exthttp.HTTPConfig{ + IdleConnTimeout: model.Duration(cfg.HTTP.IdleConnTimeout), + ResponseHeaderTimeout: model.Duration(cfg.HTTP.ResponseHeaderTimeout), + InsecureSkipVerify: cfg.HTTP.InsecureSkipVerify, + TLSHandshakeTimeout: model.Duration(cfg.HTTP.TLSHandshakeTimeout), + ExpectContinueTimeout: model.Duration(cfg.HTTP.ExpectContinueTimeout), + MaxIdleConns: cfg.HTTP.MaxIdleConns, + MaxIdleConnsPerHost: cfg.HTTP.MaxIdleConnsPerHost, + MaxConnsPerHost: cfg.HTTP.MaxConnsPerHost, + }, } // Thanos currently doesn't support passing the config as is, but expects a YAML, @@ -28,5 +40,5 @@ func NewBucketClient(ctx context.Context, cfg Config, name string, logger log.Lo return nil, err } - return gcs.NewBucket(ctx, logger, serialized, name) + return gcs.NewBucket(ctx, logger, serialized, name, nil) } diff --git a/pkg/objstore/providers/gcs/config.go b/pkg/objstore/providers/gcs/config.go index 97d40246a8..de40182134 100644 --- a/pkg/objstore/providers/gcs/config.go +++ b/pkg/objstore/providers/gcs/config.go @@ -7,6 +7,7 @@ package gcs import ( "flag" + "time" "github.com/grafana/dskit/flagext" ) @@ -15,6 +16,7 @@ import ( type Config struct { BucketName string `yaml:"bucket_name"` ServiceAccount flagext.Secret `yaml:"service_account" doc:"description_method=GCSServiceAccountLongDescription"` + HTTP HTTPConfig `yaml:"http"` } // RegisterFlags registers the flags for GCS storage @@ -26,6 +28,30 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { f.StringVar(&cfg.BucketName, prefix+"gcs.bucket-name", "", "GCS bucket name") f.Var(&cfg.ServiceAccount, prefix+"gcs.service-account", cfg.GCSServiceAccountShortDescription()) + cfg.HTTP.RegisterFlagsWithPrefix(prefix, f) +} + +type HTTPConfig struct { + IdleConnTimeout time.Duration `yaml:"idle_conn_timeout" category:"advanced"` + ResponseHeaderTimeout time.Duration `yaml:"response_header_timeout" category:"advanced"` + InsecureSkipVerify bool `yaml:"insecure_skip_verify" category:"advanced"` + TLSHandshakeTimeout time.Duration `yaml:"tls_handshake_timeout" category:"advanced"` + ExpectContinueTimeout time.Duration `yaml:"expect_continue_timeout" category:"advanced"` + MaxIdleConns int `yaml:"max_idle_conns" category:"advanced"` + MaxIdleConnsPerHost int `yaml:"max_idle_conns_per_host" category:"advanced"` + MaxConnsPerHost int `yaml:"max_conns_per_host" category:"advanced"` +} + +// RegisterFlagsWithPrefix registers the flags for s3 storage with the provided prefix +func (cfg *HTTPConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.DurationVar(&cfg.IdleConnTimeout, prefix+"gcs.http.idle-conn-timeout", 90*time.Second, "The time an idle connection will remain idle before closing.") + f.DurationVar(&cfg.ResponseHeaderTimeout, prefix+"gcs.http.response-header-timeout", 2*time.Minute, "The amount of time the client will wait for a servers response headers.") + f.BoolVar(&cfg.InsecureSkipVerify, prefix+"gcs.http.insecure-skip-verify", false, "If the client connects to GCS via HTTPS and this option is enabled, the client will accept any certificate and hostname.") + f.DurationVar(&cfg.TLSHandshakeTimeout, prefix+"gcs.tls-handshake-timeout", 10*time.Second, "Maximum time to wait for a TLS handshake. 0 means no limit.") + f.DurationVar(&cfg.ExpectContinueTimeout, prefix+"gcs.expect-continue-timeout", 1*time.Second, "The time to wait for a server's first response headers after fully writing the request headers if the request has an Expect header. 0 to send the request body immediately.") + f.IntVar(&cfg.MaxIdleConns, prefix+"gcs.max-idle-connections", 0, "Maximum number of idle (keep-alive) connections across all hosts. 0 means no limit.") + f.IntVar(&cfg.MaxIdleConnsPerHost, prefix+"gcs.max-idle-connections-per-host", 100, "Maximum number of idle (keep-alive) connections to keep per-host. If 0, a built-in default value is used.") + f.IntVar(&cfg.MaxConnsPerHost, prefix+"gcs.max-connections-per-host", 0, "Maximum number of connections per host. 0 means no limit.") } func (cfg *Config) GCSServiceAccountShortDescription() string { diff --git a/pkg/objstore/providers/memory/bucket_client.go b/pkg/objstore/providers/memory/bucket_client.go new file mode 100644 index 0000000000..fe63e80070 --- /dev/null +++ b/pkg/objstore/providers/memory/bucket_client.go @@ -0,0 +1,249 @@ +// Copyright (c) The Thanos Authors. +// Licensed under the Apache License 2.0. + +package memory + +import ( + "bytes" + "context" + "errors" + "io" + "sort" + "strings" + "sync" + "time" + + "github.com/thanos-io/objstore" +) + +var errNotFound = errors.New("inmem: object not found") + +var _ objstore.Bucket = &InMemBucket{} + +// InMemBucket implements the objstore.Bucket interfaces against local memory. +// Methods from Bucket interface are thread-safe. Objects are assumed to be immutable. +type InMemBucket struct { + mtx sync.RWMutex + objects map[string][]byte + attrs map[string]objstore.ObjectAttributes +} + +// NewInMemBucket returns a new in memory Bucket. +// NOTE: Returned bucket is just a naive in memory bucket implementation. For test use cases only. +func NewInMemBucket() *InMemBucket { + return &InMemBucket{ + objects: map[string][]byte{}, + attrs: map[string]objstore.ObjectAttributes{}, + } +} + +func (b *InMemBucket) Provider() objstore.ObjProvider { return objstore.MEMORY } + +// Objects returns a copy of the internally stored objects. +// NOTE: For assert purposes. +func (b *InMemBucket) Objects() map[string][]byte { + b.mtx.RLock() + defer b.mtx.RUnlock() + + objs := make(map[string][]byte) + for k, v := range b.objects { + objs[k] = v + } + + return objs +} + +// Iter calls f for each entry in the given directory. The argument to f is the full +// object name including the prefix of the inspected directory. +func (b *InMemBucket) Iter(_ context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { + unique := map[string]struct{}{} + params := objstore.ApplyIterOptions(options...) + + var dirPartsCount int + dirParts := strings.SplitAfter(dir, objstore.DirDelim) + for _, p := range dirParts { + if p == "" { + continue + } + dirPartsCount++ + } + + b.mtx.RLock() + for filename := range b.objects { + if !strings.HasPrefix(filename, dir) || dir == filename { + continue + } + + if params.Recursive { + // Any object matching the prefix should be included. + unique[filename] = struct{}{} + continue + } + + parts := strings.SplitAfter(filename, objstore.DirDelim) + unique[strings.Join(parts[:dirPartsCount+1], "")] = struct{}{} + } + b.mtx.RUnlock() + + var keys []string + for n := range unique { + keys = append(keys, n) + } + sort.Slice(keys, func(i, j int) bool { + if strings.HasSuffix(keys[i], objstore.DirDelim) && strings.HasSuffix(keys[j], objstore.DirDelim) { + return strings.Compare(keys[i], keys[j]) < 0 + } + if strings.HasSuffix(keys[i], objstore.DirDelim) { + return false + } + if strings.HasSuffix(keys[j], objstore.DirDelim) { + return true + } + + return strings.Compare(keys[i], keys[j]) < 0 + }) + + for _, k := range keys { + if err := f(k); err != nil { + return err + } + } + return nil +} + +func (i *InMemBucket) SupportedIterOptions() []objstore.IterOptionType { + return []objstore.IterOptionType{objstore.Recursive} +} + +func (b *InMemBucket) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + if err := objstore.ValidateIterOptions(b.SupportedIterOptions(), options...); err != nil { + return err + } + + return b.Iter(ctx, dir, func(name string) error { + return f(objstore.IterObjectAttributes{Name: name}) + + }, options...) +} + +// Get returns a reader for the given object name. +func (b *InMemBucket) Get(_ context.Context, name string) (io.ReadCloser, error) { + if name == "" { + return nil, errors.New("inmem: object name is empty") + } + + b.mtx.RLock() + file, ok := b.objects[name] + b.mtx.RUnlock() + if !ok { + return nil, errNotFound + } + + return io.NopCloser(bytes.NewReader(file)), nil +} + +// GetRange returns a new range reader for the given object name and range. +func (b *InMemBucket) GetRange(_ context.Context, name string, off, length int64) (io.ReadCloser, error) { + if name == "" { + return nil, errors.New("inmem: object name is empty") + } + + b.mtx.RLock() + file, ok := b.objects[name] + b.mtx.RUnlock() + if !ok { + return nil, errNotFound + } + + if int64(len(file)) < off { + return io.NopCloser(bytes.NewReader(nil)), nil + } + + if length == 0 { + return io.NopCloser(bytes.NewReader(nil)), nil + } + if length == -1 { + return io.NopCloser(bytes.NewReader(file[off:])), nil + } + + if int64(len(file)) <= off+length { + // Just return maximum of what we have. + length = int64(len(file)) - off + } + + return io.NopCloser(bytes.NewReader(file[off : off+length])), nil +} + +// Exists checks if the given directory exists in memory. +func (b *InMemBucket) Exists(_ context.Context, name string) (bool, error) { + b.mtx.RLock() + defer b.mtx.RUnlock() + _, ok := b.objects[name] + return ok, nil +} + +// Attributes returns information about the specified object. +func (b *InMemBucket) Attributes(_ context.Context, name string) (objstore.ObjectAttributes, error) { + b.mtx.RLock() + attrs, ok := b.attrs[name] + b.mtx.RUnlock() + if !ok { + return objstore.ObjectAttributes{}, errNotFound + } + return attrs, nil +} + +// Upload writes the file specified in src to into the memory. +func (b *InMemBucket) Upload(_ context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + b.mtx.Lock() + defer b.mtx.Unlock() + body, err := io.ReadAll(r) + if err != nil { + return err + } + b.objects[name] = body + b.attrs[name] = objstore.ObjectAttributes{ + Size: int64(len(body)), + LastModified: time.Now(), + } + return nil +} + +// Delete removes all data prefixed with the dir. +func (b *InMemBucket) Delete(_ context.Context, name string) error { + b.mtx.Lock() + defer b.mtx.Unlock() + if _, ok := b.objects[name]; !ok { + return errNotFound + } + delete(b.objects, name) + delete(b.attrs, name) + return nil +} + +// IsObjNotFoundErr returns true if error means that object is not found. Relevant to Get operations. +func (b *InMemBucket) IsObjNotFoundErr(err error) bool { + return errors.Is(err, errNotFound) +} + +// IsAccessDeniedErr returns true if access to object is denied. +func (b *InMemBucket) IsAccessDeniedErr(err error) bool { + return false +} + +func (b *InMemBucket) Close() error { return nil } + +// Name returns the bucket name. +func (b *InMemBucket) Name() string { + return "inmem" +} + +func (b *InMemBucket) Set(name string, data []byte) { + b.mtx.Lock() + defer b.mtx.Unlock() + b.objects[name] = data + b.attrs[name] = objstore.ObjectAttributes{ + Size: int64(len(data)), + LastModified: time.Now(), + } +} diff --git a/pkg/objstore/providers/s3/bucket_client.go b/pkg/objstore/providers/s3/bucket_client.go index 05630eddb3..f066b775d8 100644 --- a/pkg/objstore/providers/s3/bucket_client.go +++ b/pkg/objstore/providers/s3/bucket_client.go @@ -7,6 +7,7 @@ package s3 import ( "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus/common/model" "github.com/thanos-io/objstore" "github.com/thanos-io/objstore/providers/s3" @@ -19,7 +20,9 @@ func NewBucketClient(cfg Config, name string, logger log.Logger) (objstore.Bucke return nil, err } - return s3.NewBucketWithConfig(logger, s3Cfg, name) + warnForDeprecatedConfigFields(cfg, logger) + + return s3.NewBucketWithConfig(logger, s3Cfg, name, nil) } // NewBucketReaderClient creates a new S3 bucket client @@ -29,7 +32,9 @@ func NewBucketReaderClient(cfg Config, name string, logger log.Logger) (objstore return nil, err } - return s3.NewBucketWithConfig(logger, s3Cfg, name) + warnForDeprecatedConfigFields(cfg, logger) + + return s3.NewBucketWithConfig(logger, s3Cfg, name, nil) } func newS3Config(cfg Config) (s3.Config, error) { @@ -39,8 +44,10 @@ func newS3Config(cfg Config) (s3.Config, error) { } bucketLookupType := s3.AutoLookup - if cfg.ForcePathStyle { + if cfg.ForcePathStyle || cfg.BucketLookupType == PathStyleLookup { bucketLookupType = s3.PathLookup + } else if cfg.BucketLookupType == VirtualHostedStyleLookup { + bucketLookupType = s3.VirtualHostLookup } return s3.Config{ @@ -52,6 +59,7 @@ func newS3Config(cfg Config) (s3.Config, error) { Insecure: cfg.Insecure, SSEConfig: sseCfg, BucketLookupType: bucketLookupType, + AWSSDKAuth: cfg.NativeAWSAuthEnabled, HTTPConfig: s3.HTTPConfig{ IdleConnTimeout: model.Duration(cfg.HTTP.IdleConnTimeout), ResponseHeaderTimeout: model.Duration(cfg.HTTP.ResponseHeaderTimeout), @@ -67,3 +75,9 @@ func newS3Config(cfg Config) (s3.Config, error) { SignatureV2: cfg.SignatureVersion == SignatureVersionV2, }, nil } + +func warnForDeprecatedConfigFields(cfg Config, logger log.Logger) { + if cfg.ForcePathStyle { + level.Warn(logger).Log("msg", "S3 bucket client config has a deprecated s3.force-path-style flag set. Please, use s3.bucket-lookup-type instead.") + } +} diff --git a/pkg/objstore/providers/s3/config.go b/pkg/objstore/providers/s3/config.go index 1ef8147087..80e3d73d6d 100644 --- a/pkg/objstore/providers/s3/config.go +++ b/pkg/objstore/providers/s3/config.go @@ -7,6 +7,7 @@ package s3 import ( "encoding/json" + "errors" "flag" "fmt" "net/http" @@ -15,7 +16,6 @@ import ( "github.com/grafana/dskit/flagext" "github.com/minio/minio-go/v7/pkg/encrypt" - "github.com/pkg/errors" "github.com/samber/lo" "github.com/thanos-io/objstore/providers/s3" ) @@ -31,14 +31,25 @@ const ( // SSES3 config type constant to configure S3 server side encryption with AES-256 // https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html SSES3 = "SSE-S3" + + // https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access + PathStyleLookup = "path-style" + + // https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#virtual-hosted-style-access + VirtualHostedStyleLookup = "virtual-hosted-style" + + AutoLookup = "auto" ) var ( supportedSignatureVersions = []string{SignatureVersionV4, SignatureVersionV2} supportedSSETypes = []string{SSEKMS, SSES3} + supportedBucketLookupTypes = []string{PathStyleLookup, VirtualHostedStyleLookup, AutoLookup} errUnsupportedSignatureVersion = errors.New("unsupported signature version") errUnsupportedSSEType = errors.New("unsupported S3 SSE type") errInvalidSSEContext = errors.New("invalid S3 SSE encryption context") + errBucketLookupConfigConflict = errors.New("cannot use s3.force-path-style = true and s3.bucket-lookup-type = virtual-hosted-style at the same time") + errUnsupportedBucketLookupType = errors.New("invalid S3 bucket lookup type") ) // HTTPConfig stores the http.Transport configuration for the s3 minio client. @@ -63,21 +74,23 @@ func (cfg *HTTPConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { f.BoolVar(&cfg.InsecureSkipVerify, prefix+"s3.http.insecure-skip-verify", false, "If the client connects to S3 via HTTPS and this option is enabled, the client will accept any certificate and hostname.") f.DurationVar(&cfg.TLSHandshakeTimeout, prefix+"s3.tls-handshake-timeout", 10*time.Second, "Maximum time to wait for a TLS handshake. 0 means no limit.") f.DurationVar(&cfg.ExpectContinueTimeout, prefix+"s3.expect-continue-timeout", 1*time.Second, "The time to wait for a server's first response headers after fully writing the request headers if the request has an Expect header. 0 to send the request body immediately.") - f.IntVar(&cfg.MaxIdleConns, prefix+"s3.max-idle-connections", 100, "Maximum number of idle (keep-alive) connections across all hosts. 0 means no limit.") + f.IntVar(&cfg.MaxIdleConns, prefix+"s3.max-idle-connections", 0, "Maximum number of idle (keep-alive) connections across all hosts. 0 means no limit.") f.IntVar(&cfg.MaxIdleConnsPerHost, prefix+"s3.max-idle-connections-per-host", 100, "Maximum number of idle (keep-alive) connections to keep per-host. If 0, a built-in default value is used.") f.IntVar(&cfg.MaxConnsPerHost, prefix+"s3.max-connections-per-host", 0, "Maximum number of connections per host. 0 means no limit.") } // Config holds the config options for an S3 backend type Config struct { - Endpoint string `yaml:"endpoint"` - Region string `yaml:"region"` - BucketName string `yaml:"bucket_name"` - SecretAccessKey flagext.Secret `yaml:"secret_access_key"` - AccessKeyID string `yaml:"access_key_id"` - Insecure bool `yaml:"insecure" category:"advanced"` - SignatureVersion string `yaml:"signature_version" category:"advanced"` - ForcePathStyle bool `yaml:"force_path_style" category:"advanced"` + Endpoint string `yaml:"endpoint"` + Region string `yaml:"region"` + BucketName string `yaml:"bucket_name"` + SecretAccessKey flagext.Secret `yaml:"secret_access_key"` + AccessKeyID string `yaml:"access_key_id"` + Insecure bool `yaml:"insecure" category:"advanced"` + SignatureVersion string `yaml:"signature_version" category:"advanced"` + ForcePathStyle bool `yaml:"force_path_style" category:"advanced"` + BucketLookupType string `yaml:"bucket_lookup_type" category:"advanced"` + NativeAWSAuthEnabled bool `yaml:"native_aws_auth_enabled" category:"experimental"` SSE SSEConfig `yaml:"sse"` HTTP HTTPConfig `yaml:"http"` @@ -96,8 +109,10 @@ func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { f.StringVar(&cfg.Region, prefix+"s3.region", "", "S3 region. If unset, the client will issue a S3 GetBucketLocation API call to autodetect it.") f.StringVar(&cfg.Endpoint, prefix+"s3.endpoint", "", "The S3 bucket endpoint. It could be an AWS S3 endpoint listed at https://docs.aws.amazon.com/general/latest/gr/s3.html or the address of an S3-compatible service in hostname:port format.") f.BoolVar(&cfg.Insecure, prefix+"s3.insecure", false, "If enabled, use http:// for the S3 endpoint instead of https://. This could be useful in local dev/test environments while using an S3-compatible backend storage, like Minio.") - f.BoolVar(&cfg.ForcePathStyle, prefix+"s3.force-path-style", false, "Set this to `true` to force the bucket lookup to be using path-style.") + f.BoolVar(&cfg.ForcePathStyle, prefix+"s3.force-path-style", false, "Deprecated, use s3.bucket-lookup-type instead. Set this to `true` to force the bucket lookup to be using path-style.") + f.StringVar(&cfg.BucketLookupType, prefix+"s3.bucket-lookup-type", AutoLookup, fmt.Sprintf("S3 bucket lookup style, use one of: %v", supportedBucketLookupTypes)) f.StringVar(&cfg.SignatureVersion, prefix+"s3.signature-version", SignatureVersionV4, fmt.Sprintf("The signature version to use for authenticating against S3. Supported values are: %s.", strings.Join(supportedSignatureVersions, ", "))) + f.BoolVar(&cfg.NativeAWSAuthEnabled, prefix+"s3.native-aws-auth-enabled", false, "If enabled, it will use the default authentication methods of the AWS SDK for go based on known environment variables and known AWS config files.") cfg.SSE.RegisterFlagsWithPrefix(prefix+"s3.sse.", f) cfg.HTTP.RegisterFlagsWithPrefix(prefix, f) } @@ -108,6 +123,14 @@ func (cfg *Config) Validate() error { return errUnsupportedSignatureVersion } + if cfg.ForcePathStyle && cfg.BucketLookupType != AutoLookup && cfg.BucketLookupType != PathStyleLookup { + return errBucketLookupConfigConflict + } + + if !lo.Contains(supportedBucketLookupTypes, cfg.BucketLookupType) { + return errUnsupportedBucketLookupType + } + if err := cfg.SSE.Validate(); err != nil { return err } @@ -200,6 +223,9 @@ func parseKMSEncryptionContext(data string) (map[string]string, error) { } decoded := map[string]string{} - err := errors.Wrap(json.Unmarshal([]byte(data), &decoded), "unable to parse KMS encryption context") - return decoded, err + err := json.Unmarshal([]byte(data), &decoded) + if err != nil { + return nil, errors.New("unable to parse KMS encryption context") + } + return decoded, nil } diff --git a/pkg/objstore/providers/s3/config_test.go b/pkg/objstore/providers/s3/config_test.go index 3a1d4a81f2..a1fea8dd88 100644 --- a/pkg/objstore/providers/s3/config_test.go +++ b/pkg/objstore/providers/s3/config_test.go @@ -6,9 +6,16 @@ package s3 import ( + "context" "encoding/base64" + "io" "net/http" + "net/http/httptest" + "os" "testing" + "time" + + "github.com/go-kit/log" "github.com/grafana/dskit/flagext" "github.com/stretchr/testify/assert" @@ -117,3 +124,176 @@ func TestParseKMSEncryptionContext(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expected, actual) } + +func TestConfig_Validate(t *testing.T) { + tests := map[string]struct { + setup func() *Config + expected error + }{ + "should pass with default config": { + setup: func() *Config { + cfg := &Config{} + flagext.DefaultValues(cfg) + + return cfg + }, + }, + "should fail on invalid bucket lookup style": { + setup: func() *Config { + cfg := &Config{} + flagext.DefaultValues(cfg) + cfg.BucketLookupType = "invalid" + return cfg + }, + expected: errUnsupportedBucketLookupType, + }, + "should fail if force-path-style conflicts with bucket-lookup-type": { + setup: func() *Config { + cfg := &Config{} + flagext.DefaultValues(cfg) + cfg.ForcePathStyle = true + cfg.BucketLookupType = VirtualHostedStyleLookup + return cfg + }, + expected: errBucketLookupConfigConflict, + }, + "should pass with NativeAWSAuthEnabled true": { + setup: func() *Config { + cfg := &Config{} + flagext.DefaultValues(cfg) + cfg.NativeAWSAuthEnabled = true + return cfg + }, + }, + } + + for testName, testData := range tests { + t.Run(testName, func(t *testing.T) { + assert.Equal(t, testData.expected, testData.setup().Validate()) + }) + } +} + +type testRoundTripper struct { + roundTrip func(r *http.Request) (*http.Response, error) +} + +func (t *testRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + return t.roundTrip(r) +} + +func handleSTSRequest(t *testing.T, r *http.Request, w http.ResponseWriter) { + body, err := io.ReadAll(r.Body) + require.NoError(t, err) + + require.Contains(t, string(body), "RoleArn=arn%3Ahello-world") + require.Contains(t, string(body), "WebIdentityToken=my-web-token") + require.Contains(t, string(body), "Action=AssumeRoleWithWebIdentity") + + w.WriteHeader(200) + _, err = w.Write([]byte(` + + + + test-key + test-secret + test-token + ` + time.Now().Add(time.Hour).Format(time.RFC3339) + ` + + + + test-request-id + + `)) + require.NoError(t, err) + +} + +func overrideEnv(t testing.TB, kv ...string) { + old := make([]string, len(kv)) + for i := 0; i < len(kv); i += 2 { + k := kv[i] + v := kv[i+1] + old[i] = k + old[i+1] = os.Getenv(k) + os.Setenv(k, v) + } + t.Cleanup(func() { + for i := 0; i < len(old); i += 2 { + os.Setenv(old[i], old[i+1]) + } + }) +} + +func TestAWSSTSWebIdentity(t *testing.T) { + logger := log.NewNopLogger() + tmpDir := t.TempDir() + + // override env variables, will be cleaned up by t.Cleanup + overrideEnv(t, + "AWS_WEB_IDENTITY_TOKEN_FILE", tmpDir+"/token", + "AWS_ROLE_ARN", "arn:hello-world", + "AWS_DEFAULT_REGION", "eu-central-1", + "AWS_CONFIG_FILE", "/dev/null", // dont accidentally use real config + "AWS_ACCESS_KEY_ID", "", // dont use real credentials + "AWS_SECRET_ACCESS_KEY", "", // dont use real credentials + ) + + rt := &testRoundTripper{ + roundTrip: func(r *http.Request) (*http.Response, error) { + w := httptest.NewRecorder() + if r.Body != nil { + defer r.Body.Close() + } + switch r.URL.String() { + case "https://sts.amazonaws.com": + handleSTSRequest(t, r, w) + case "https://eu-central-1.amazonaws.com/pyroscope-test-bucket/test": + assert.Equal(t, "GET", r.Method) + assert.Contains(t, r.Header.Get("Authorization"), "AWS4-HMAC-SHA256 Credential=test-key") + w.Header().Set("Last-Modified", time.Now().Format("Mon, 2 Jan 2006 15:04:05 GMT")) + w.WriteHeader(200) + _, err := w.Write([]byte("test")) + require.NoError(t, err) + default: + w.WriteHeader(404) + _, err := w.Write([]byte("unexpected")) + require.NoError(t, err) + t.Errorf("unexpected request: %s", r.URL.Host) + t.FailNow() + } + return w.Result(), nil + }, + } + oldDefaultTransport := http.DefaultTransport + oldDefaultClient := http.DefaultClient + http.DefaultTransport = rt + http.DefaultClient = &http.Client{ + Transport: rt, + } + // restore default transport and client + t.Cleanup(func() { + http.DefaultTransport = oldDefaultTransport + http.DefaultClient = oldDefaultClient + }) + + // mock a web token + err := os.WriteFile(tmpDir+"/token", []byte("my-web-token"), 0644) + require.NoError(t, err) + + cfg := Config{ + SignatureVersion: SignatureVersionV4, + BucketName: "pyroscope-test-bucket", + Region: "eu-central-1", + Endpoint: "eu-central-1.amazonaws.com", + BucketLookupType: AutoLookup, + } + + cfg.HTTP.Transport = rt + r, err := NewBucketClient(cfg, "test", logger) + require.NoError(t, err) + + _, err = r.Get(context.Background(), "test") + require.NoError(t, err) + +} diff --git a/pkg/objstore/providers/swift/bucket_client.go b/pkg/objstore/providers/swift/bucket_client.go index cec2746494..8e483a68c7 100644 --- a/pkg/objstore/providers/swift/bucket_client.go +++ b/pkg/objstore/providers/swift/bucket_client.go @@ -10,7 +10,7 @@ import ( "github.com/prometheus/common/model" "github.com/thanos-io/objstore" "github.com/thanos-io/objstore/providers/swift" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) // NewBucketClient creates a new Swift bucket client @@ -47,5 +47,5 @@ func NewBucketClient(cfg Config, name string, logger log.Logger) (objstore.Bucke return nil, err } - return swift.NewContainer(logger, serialized) + return swift.NewContainer(logger, serialized, nil) } diff --git a/pkg/objstore/read_only_file.go b/pkg/objstore/read_only_file.go new file mode 100644 index 0000000000..0b0ec6f3c9 --- /dev/null +++ b/pkg/objstore/read_only_file.go @@ -0,0 +1,193 @@ +package objstore + +import ( + "context" + "fmt" + "io" + "os" + "path/filepath" + "sync" + "time" + + "github.com/grafana/dskit/multierror" + "github.com/thanos-io/objstore" + + "github.com/grafana/pyroscope/v2/pkg/util/bufferpool" +) + +var _ objstore.BucketReader = &ReadOnlyFile{} + +type ReadOnlyFile struct { + size int64 + name string + path string + mu sync.Mutex + readers []*fileReader +} + +func Download(ctx context.Context, name string, src BucketReader, dir string) (*ReadOnlyFile, error) { + f, err := download(ctx, name, src, dir) + if err != nil { + return nil, fmt.Errorf("downloading %s: %w", name, err) + } + return f, nil +} + +func download(ctx context.Context, name string, src BucketReader, dir string) (*ReadOnlyFile, error) { + r, err := src.Get(ctx, name) + if err != nil { + return nil, err + } + defer r.Close() + + path := filepath.Join(dir, filepath.Base(name)) + f := &ReadOnlyFile{ + name: name, + path: path, + } + if err = os.MkdirAll(dir, 0755); err != nil { + return nil, err + } + dst, err := os.Create(path) + if err != nil { + return nil, err + } + defer dst.Close() + + buf := bufferpool.GetBuffer(32 << 10) + defer bufferpool.Put(buf) + buf.B = buf.B[:cap(buf.B)] + n, err := io.CopyBuffer(dst, r, buf.B) + if err != nil { + _ = os.RemoveAll(path) + return nil, err + } + + f.size = n + return f, nil +} + +func (f *ReadOnlyFile) Close() error { + var m multierror.MultiError + for _, r := range f.readers { + m.Add(r.Close()) + } + m.Add(os.RemoveAll(f.path)) + f.readers = f.readers[:0] + return m.Err() +} + +func (f *ReadOnlyFile) Iter(context.Context, string, func(string) error, ...objstore.IterOption) error { + return nil +} + +func (f *ReadOnlyFile) IterWithAttributes(context.Context, string, func(attrs objstore.IterObjectAttributes) error, ...objstore.IterOption) error { + return nil +} + +func (f *ReadOnlyFile) SupportedIterOptions() []objstore.IterOptionType { + return nil +} + +func (f *ReadOnlyFile) Exists(_ context.Context, name string) (bool, error) { + return name == f.name, nil +} + +func (f *ReadOnlyFile) IsObjNotFoundErr(err error) bool { return os.IsNotExist(err) } + +func (f *ReadOnlyFile) IsAccessDeniedErr(err error) bool { return os.IsPermission(err) } + +func (f *ReadOnlyFile) Attributes(_ context.Context, name string) (attrs objstore.ObjectAttributes, err error) { + if name != f.name { + return attrs, os.ErrNotExist + } + return objstore.ObjectAttributes{ + Size: f.size, + LastModified: time.Unix(0, 0), // We don't care. + }, nil +} + +func (f *ReadOnlyFile) ReaderAt(_ context.Context, name string) (ReaderAtCloser, error) { + return f.borrowOrCreateReader(name) +} + +func (f *ReadOnlyFile) Get(_ context.Context, name string) (io.ReadCloser, error) { + r, err := f.borrowOrCreateReader(name) + if err != nil { + return nil, err + } + if _, err = r.Seek(0, io.SeekStart); err != nil { + _ = r.Close() + return nil, err + } + return r, nil +} + +func (f *ReadOnlyFile) GetRange(_ context.Context, name string, off, length int64) (io.ReadCloser, error) { + if off < 0 || length < 0 { + return nil, fmt.Errorf("%w: invalid offset", os.ErrInvalid) + } + r, err := f.borrowOrCreateReader(name) + if err != nil { + return nil, err + } + if _, err = r.Seek(off, io.SeekStart); err != nil { + _ = r.Close() + return nil, err + } + r.reader = io.LimitReader(r.reader, length) + return r, nil +} + +func (f *ReadOnlyFile) borrowOrCreateReader(name string) (*fileReader, error) { + if name != f.name { + return nil, os.ErrNotExist + } + f.mu.Lock() + defer f.mu.Unlock() + if len(f.readers) > 0 { + ff := f.readers[len(f.readers)-1] + f.readers = f.readers[:len(f.readers)-1] + ff.reader = ff.File + return ff, nil + } + return f.openReader() +} + +func (f *ReadOnlyFile) returnReader(r *fileReader) { + f.mu.Lock() + defer f.mu.Unlock() + f.readers = append(f.readers, r) +} + +func (f *ReadOnlyFile) openReader() (*fileReader, error) { + ff, err := os.Open(f.path) + if err != nil { + return nil, err + } + return &fileReader{ + parent: f, + File: ff, + reader: ff, + }, nil +} + +type fileReader struct { + parent *ReadOnlyFile + reader io.Reader + *os.File +} + +func (r *fileReader) Close() error { + r.reader = nil + r.parent.returnReader(r) + return nil +} + +func (r *fileReader) Read(p []byte) (int, error) { + return r.reader.Read(p) +} + +func (r *fileReader) Provider(p []byte) objstore.ObjProvider { + return objstore.ObjProvider("READONLYFILE") +} diff --git a/pkg/objstore/read_only_file_test.go b/pkg/objstore/read_only_file_test.go new file mode 100644 index 0000000000..33598c5504 --- /dev/null +++ b/pkg/objstore/read_only_file_test.go @@ -0,0 +1,25 @@ +package objstore_test + +import ( + "context" + "io" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" +) + +func TestReadOnlyFileError(t *testing.T) { + m := new(mockobjstore.MockBucket) + m.EXPECT().Get(mock.Anything, "test").Return(failReader{}, nil).Once() + _, err := objstore.Download(context.Background(), "test", m, t.TempDir()) + require.ErrorIs(t, err, io.ErrNoProgress) +} + +type failReader struct{} + +func (failReader) Read([]byte) (int, error) { return 0, io.ErrNoProgress } +func (failReader) Close() error { return nil } diff --git a/pkg/objstore/reader.go b/pkg/objstore/reader.go index 30cb96a6e1..5cf49af998 100644 --- a/pkg/objstore/reader.go +++ b/pkg/objstore/reader.go @@ -2,6 +2,7 @@ package objstore import ( "context" + "fmt" "io" "github.com/thanos-io/objstore" @@ -66,7 +67,7 @@ type ReaderAt struct { } func (b *ReaderAt) ReadAt(p []byte, off int64) (int, error) { - rc, err := b.GetRangeReader.GetRange(b.ctx, b.name, off, int64(len(p))) + rc, err := b.GetRange(b.ctx, b.name, off, int64(len(p))) if err != nil { return 0, err } @@ -91,3 +92,47 @@ func (b *ReaderAt) ReadAt(p []byte, off int64) (int, error) { func (b *ReaderAt) Close() error { return nil } + +func ReadRange(ctx context.Context, reader io.ReaderFrom, name string, storage objstore.BucketReader, off, size int64) error { + if size == 0 { + attrs, err := storage.Attributes(ctx, name) + if err != nil { + return err + } + size = attrs.Size + } + if size == 0 { + return nil + } + rc, err := storage.GetRange(ctx, name, off, size) + if err != nil { + return err + } + defer func() { + _ = rc.Close() + }() + n, err := reader.ReadFrom(io.LimitReader(rc, size)) + if err != nil { + return err + } + if n != size { + return fmt.Errorf("read %d bytes, expected %d", n, size) + } + return nil +} + +type BucketReaderWithOffset struct { + BucketReader + offset int64 +} + +func NewBucketReaderWithOffset(r BucketReader, offset int64) *BucketReaderWithOffset { + return &BucketReaderWithOffset{ + BucketReader: r, + offset: offset, + } +} + +func (r *BucketReaderWithOffset) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + return r.BucketReader.GetRange(ctx, name, r.offset+off, length) +} diff --git a/pkg/objstore/reader_test.go b/pkg/objstore/reader_test.go index f5ccba6080..786fcbb403 100644 --- a/pkg/objstore/reader_test.go +++ b/pkg/objstore/reader_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" ) func Test_FileSystem(t *testing.T) { @@ -21,7 +21,7 @@ func Test_FileSystem(t *testing.T) { Directory: testDir, }, }, - StoragePrefix: "testdata/", + Prefix: "testdata/", }, "foo") require.NoError(t, err) diff --git a/pkg/objstore/sse_bucket_client.go b/pkg/objstore/sse_bucket_client.go index ee7e5b7423..675bd16635 100644 --- a/pkg/objstore/sse_bucket_client.go +++ b/pkg/objstore/sse_bucket_client.go @@ -7,14 +7,14 @@ package objstore import ( "context" + "fmt" "io" "github.com/minio/minio-go/v7/pkg/encrypt" - "github.com/pkg/errors" "github.com/thanos-io/objstore" "github.com/thanos-io/objstore/providers/s3" - phlare_s3 "github.com/grafana/pyroscope/pkg/objstore/providers/s3" + phlare_s3 "github.com/grafana/pyroscope/v2/pkg/objstore/providers/s3" ) // TenantConfigProvider defines a per-tenant config provider. @@ -56,7 +56,7 @@ func (b *SSEBucketClient) ReaderAt(ctx context.Context, name string) (ReaderAtCl } // Upload the contents of the reader as an object into the bucket. -func (b *SSEBucketClient) Upload(ctx context.Context, name string, r io.Reader) error { +func (b *SSEBucketClient) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { if sse, err := b.getCustomS3SSEConfig(); err != nil { return err } else if sse != nil { @@ -65,7 +65,7 @@ func (b *SSEBucketClient) Upload(ctx context.Context, name string, r io.Reader) ctx = s3.ContextWithSSEConfig(ctx, sse) } - return b.bucket.Upload(ctx, name, r) + return b.bucket.Upload(ctx, name, r, opts...) } // Delete implements objstore.Bucket. @@ -97,7 +97,7 @@ func (b *SSEBucketClient) getCustomS3SSEConfig() (encrypt.ServerSide, error) { sse, err := cfg.BuildMinioConfig() if err != nil { - return nil, errors.Wrapf(err, "unable to customise S3 SSE config for tenant %s", b.userID) + return nil, fmt.Errorf("unable to customise S3 SSE config for tenant %s: %w", b.userID, err) } return sse, nil @@ -108,6 +108,14 @@ func (b *SSEBucketClient) Iter(ctx context.Context, dir string, f func(string) e return b.bucket.Iter(ctx, dir, f, options...) } +func (b *SSEBucketClient) IterWithAttributes(ctx context.Context, dir string, f func(attrs objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + return b.bucket.IterWithAttributes(ctx, dir, f, options...) +} + +func (b *SSEBucketClient) SupportedIterOptions() []objstore.IterOptionType { + return b.bucket.SupportedIterOptions() +} + // Get implements objstore.Bucket. func (b *SSEBucketClient) Get(ctx context.Context, name string) (io.ReadCloser, error) { return b.bucket.Get(ctx, name) @@ -155,3 +163,7 @@ func (b *SSEBucketClient) WithExpectedErrs(fn IsOpFailureExpectedFunc) Bucket { return b } + +func (b *SSEBucketClient) Provider() objstore.ObjProvider { + return b.bucket.Provider() +} diff --git a/pkg/objstore/sse_bucket_client_test.go b/pkg/objstore/sse_bucket_client_test.go index ee2f721cc3..88d16ae03e 100644 --- a/pkg/objstore/sse_bucket_client_test.go +++ b/pkg/objstore/sse_bucket_client_test.go @@ -19,7 +19,7 @@ import ( "github.com/stretchr/testify/require" "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/objstore/providers/s3" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/s3" ) func TestSSEBucketClient_Upload_ShouldInjectCustomSSEConfig(t *testing.T) { diff --git a/pkg/objstore/testutil/objstore.go b/pkg/objstore/testutil/objstore.go index 03f284e52b..275166808c 100644 --- a/pkg/objstore/testutil/objstore.go +++ b/pkg/objstore/testutil/objstore.go @@ -11,9 +11,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" ) func NewFilesystemBucket(t testing.TB, ctx context.Context, storageDir string) (objstore.Bucket, string) { diff --git a/pkg/og/agent/spy/spy.go b/pkg/og/agent/spy/spy.go index c1b4a5f12a..eaca98dacf 100644 --- a/pkg/og/agent/spy/spy.go +++ b/pkg/og/agent/spy/spy.go @@ -2,7 +2,7 @@ package spy import ( - "github.com/grafana/pyroscope/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" ) type ProfileType string diff --git a/pkg/og/convert/convert_suite_test.go b/pkg/og/convert/convert_suite_test.go deleted file mode 100644 index 573b79f2c9..0000000000 --- a/pkg/og/convert/convert_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package convert_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestConvert(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Convert Suite") -} diff --git a/pkg/og/convert/jfr/profile.go b/pkg/og/convert/jfr/profile.go index 1b577fe950..967b34e890 100644 --- a/pkg/og/convert/jfr/profile.go +++ b/pkg/og/convert/jfr/profile.go @@ -2,21 +2,23 @@ package jfr import ( "bytes" - "compress/gzip" + "github.com/klauspost/compress/gzip" "context" "fmt" "io" "mime/multipart" "strings" + "github.com/grafana/dskit/tenant" jfrPprof "github.com/grafana/jfr-parser/pprof" jfrPprofPyroscope "github.com/grafana/jfr-parser/pprof/pyroscope" - distributormodel "github.com/grafana/pyroscope/pkg/distributor/model" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage" - "github.com/grafana/pyroscope/pkg/og/util/form" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/util/form" ) type RawProfile struct { @@ -26,19 +28,24 @@ type RawProfile struct { func (p *RawProfile) Bytes() ([]byte, error) { return p.RawData, nil } -func (p *RawProfile) ParseToPprof(_ context.Context, md ingestion.Metadata) (*distributormodel.PushRequest, error) { +func (p *RawProfile) ParseToPprof(ctx context.Context, md ingestion.Metadata, limits ingestion.Limits) (*distributormodel.PushRequest, error) { input := jfrPprof.ParseInput{ StartTime: md.StartTime, EndTime: md.EndTime, SampleRate: int64(md.SampleRate), } + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, err + } + maxBytes := limits.MaxProfileSizeBytes(tenantID) + labels := new(jfrPprof.LabelsSnapshot) rawSize := len(p.RawData) var r = p.RawData - var err error if strings.Contains(p.FormDataContentType, "multipart/form-data") { - if r, labels, err = loadJFRFromForm(r, p.FormDataContentType); err != nil { + if r, labels, err = loadJFRFromForm(r, p.FormDataContentType, maxBytes); err != nil { return nil, err } } @@ -49,22 +56,25 @@ func (p *RawProfile) ParseToPprof(_ context.Context, md ingestion.Metadata) (*di } res := new(distributormodel.PushRequest) for _, req := range profiles.Profiles { - seriesLabels := jfrPprofPyroscope.Labels(md.Key.Labels(), profiles.JFREvent, req.Metric, md.Key.AppName(), md.SpyName) + seriesLabels := jfrPprofPyroscope.Labels( + md.LabelSet.Labels(), + profiles.JFREvent, + req.Metric, + md.LabelSet.ServiceName(), + md.SpyName, + ) res.Series = append(res.Series, &distributormodel.ProfileSeries{ - Labels: seriesLabels, - Samples: []*distributormodel.ProfileSample{ - { - Profile: pprof.RawFromProto(req.Profile), - }, - }, + Labels: seriesLabels, + Profile: pprof.RawFromProto(req.Profile), }) } - res.RawProfileSize = rawSize + res.ReceivedCompressedProfileSize = rawSize + res.ReceivedDecompressedProfileSize = len(r) res.RawProfileType = distributormodel.RawProfileTypeJFR return res, err } -func (p *RawProfile) Parse(ctx context.Context, putter storage.Putter, _ storage.MetricsExporter, md ingestion.Metadata) error { +func (p *RawProfile) Parse(ctx context.Context, putter storage.Putter, _ storage.MetricsExporter, md ingestion.Metadata, _ ingestion.Limits) error { return fmt.Errorf("parsing to Tree/storage.Putter is no longer supported") } @@ -75,7 +85,7 @@ func (p *RawProfile) ContentType() string { return p.FormDataContentType } -func loadJFRFromForm(r []byte, contentType string) ([]byte, *jfrPprof.LabelsSnapshot, error) { +func loadJFRFromForm(r []byte, contentType string, maxBytes int) ([]byte, *jfrPprof.LabelsSnapshot, error) { boundary, err := form.ParseBoundary(contentType) if err != nil { return nil, nil, err @@ -96,7 +106,7 @@ func loadJFRFromForm(r []byte, contentType string) ([]byte, *jfrPprof.LabelsSnap if jfrField == nil { return nil, nil, fmt.Errorf("jfr field is required") } - jfrField, err = decompress(jfrField) + jfrField, err = decompress(jfrField, maxBytes) if err != nil { return nil, nil, fmt.Errorf("loadJFRFromForm failed to decompress jfr: %w", err) } @@ -108,7 +118,7 @@ func loadJFRFromForm(r []byte, contentType string) ([]byte, *jfrPprof.LabelsSnap var labels = new(jfrPprof.LabelsSnapshot) if len(labelsField) > 0 { - labelsField, err = decompress(labelsField) + labelsField, err = decompress(labelsField, maxBytes) if err != nil { return nil, nil, fmt.Errorf("loadJFRFromForm failed to decompress labels: %w", err) } @@ -120,7 +130,7 @@ func loadJFRFromForm(r []byte, contentType string) ([]byte, *jfrPprof.LabelsSnap return jfrField, labels, nil } -func decompress(bs []byte) ([]byte, error) { +func decompress(bs []byte, maxBytes int) ([]byte, error) { var err error if len(bs) < 2 { return nil, fmt.Errorf("failed to read magic") @@ -131,10 +141,15 @@ func decompress(bs []byte) ([]byte, error) { if err != nil { return nil, fmt.Errorf("failed to read gzip header: %w", err) } + // Use maxBytes+1 to detect if limit is exceeded + limitReader := io.LimitReader(gzipr, int64(maxBytes+1)) buf := bytes.NewBuffer(nil) - if _, err = io.Copy(buf, gzipr); err != nil { + if _, err = io.Copy(buf, limitReader); err != nil { return nil, fmt.Errorf("failed to decompress jfr: %w", err) } + if buf.Len() > maxBytes { + return nil, fmt.Errorf("decompressed size exceeds maximum allowed size of %d bytes", maxBytes) + } return buf.Bytes(), nil } else { return bs, nil diff --git a/pkg/og/convert/jfr/profile_test.go b/pkg/og/convert/jfr/profile_test.go new file mode 100644 index 0000000000..4736853b22 --- /dev/null +++ b/pkg/og/convert/jfr/profile_test.go @@ -0,0 +1,81 @@ +package jfr + +import ( + "bytes" + "context" + "mime/multipart" + "os" + "testing" + + "github.com/grafana/dskit/user" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/api/model/labelset" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/bench" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" +) + +const testTenantID = "test-tenant" + +type fixedMaxProfileSize int + +func (l fixedMaxProfileSize) MaxProfileSizeBytes(_ string) int { return int(l) } +func (l fixedMaxProfileSize) MaxProfileSymbolValueLength(_ string) int { return 0 } +func (l fixedMaxProfileSize) MaxProfileStacktraceSamples(_ string) int { return 0 } + +func testContext() context.Context { + return user.InjectOrgID(context.Background(), testTenantID) +} + +func testMetadata() ingestion.Metadata { + return ingestion.Metadata{ + LabelSet: labelset.New(map[string]string{"__name__": "javaapp"}), + } +} + +// TestParseToPprof_PlainJFR_SizesSame verifies that when raw (uncompressed) JFR bytes are +// submitted directly, both ReceivedCompressedProfileSize and ReceivedDecompressedProfileSize +// equal len(RawData), since no decompression takes place. +func TestParseToPprof_PlainJFR_SizesSame(t *testing.T) { + rawJFR, err := bench.ReadGzipFile("testdata/cortex-dev-01__kafka-0__cpu__0.jfr.gz") + require.NoError(t, err) + + p := &RawProfile{RawData: rawJFR} + result, err := p.ParseToPprof(testContext(), testMetadata(), fixedMaxProfileSize(32<<20)) + require.NoError(t, err) + + assert.Equal(t, len(rawJFR), result.ReceivedCompressedProfileSize) + assert.Equal(t, len(rawJFR), result.ReceivedDecompressedProfileSize) +} + +// TestParseToPprof_MultipartGzipJFR_SizesDiffer verifies that when a gzip-compressed JFR +// file is submitted as a multipart form field, ReceivedCompressedProfileSize reflects the +// raw multipart body length and ReceivedDecompressedProfileSize reflects the decompressed +// JFR bytes length (which should be larger due to compression). +func TestParseToPprof_MultipartGzipJFR_SizesDiffer(t *testing.T) { + gzippedJFR, err := os.ReadFile("testdata/cortex-dev-01__kafka-0__cpu__0.jfr.gz") + require.NoError(t, err) + + rawJFR, err := bench.ReadGzipFile("testdata/cortex-dev-01__kafka-0__cpu__0.jfr.gz") + require.NoError(t, err) + + var b bytes.Buffer + w := multipart.NewWriter(&b) + jfrField, err := w.CreateFormFile("jfr", "jfr") + require.NoError(t, err) + _, err = jfrField.Write(gzippedJFR) + require.NoError(t, err) + require.NoError(t, w.Close()) + multipartBody := b.Bytes() + + p := &RawProfile{ + FormDataContentType: w.FormDataContentType(), + RawData: multipartBody, + } + result, err := p.ParseToPprof(testContext(), testMetadata(), fixedMaxProfileSize(32<<20)) + require.NoError(t, err) + + assert.Equal(t, len(multipartBody), result.ReceivedCompressedProfileSize) + assert.Equal(t, len(rawJFR), result.ReceivedDecompressedProfileSize) +} diff --git a/pkg/og/convert/parser.go b/pkg/og/convert/parser.go index 9793c26bdd..1d12c7a19c 100644 --- a/pkg/og/convert/parser.go +++ b/pkg/og/convert/parser.go @@ -3,14 +3,26 @@ package convert import ( "bufio" "bytes" + "context" "io" "strconv" - "github.com/grafana/pyroscope/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) -func ParseTreeNoDict(r io.Reader, cb func(name []byte, val int)) error { - t, err := tree.DeserializeNoDict(r) +func ParseTreeNoDict(ctx context.Context, r io.Reader, cb func(name []byte, val int), limits ingestion.Limits) error { + var maxNameLen, maxChildren int + if limits != nil { + tenantID, err := tenant.ExtractTenantIDFromContext(ctx) + if err != nil { + return err + } + maxNameLen = limits.MaxProfileSymbolValueLength(tenantID) + maxChildren = limits.MaxProfileStacktraceSamples(tenantID) + } + t, err := tree.DeserializeNoDict(r, maxNameLen, maxChildren) if err != nil { return err } diff --git a/pkg/og/convert/parser_test.go b/pkg/og/convert/parser_test.go index c8ad7a6778..460fe09769 100644 --- a/pkg/og/convert/parser_test.go +++ b/pkg/og/convert/parser_test.go @@ -3,31 +3,29 @@ package convert import ( "bytes" "fmt" + "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" ) -var _ = Describe("convert", func() { - Describe("ParseGroups", func() { - It("parses data correctly", func() { - r := bytes.NewReader([]byte("foo;bar 10\nfoo;baz 20\n")) - result := []string{} - ParseGroups(r, func(name []byte, val int) { - result = append(result, fmt.Sprintf("%s %d", name, val)) - }) - Expect(result).To(ConsistOf("foo;bar 10", "foo;baz 20")) +func TestParseGroups(t *testing.T) { + t.Run("parses data correctly", func(t *testing.T) { + r := bytes.NewReader([]byte("foo;bar 10\nfoo;baz 20\n")) + result := []string{} + ParseGroups(r, func(name []byte, val int) { + result = append(result, fmt.Sprintf("%s %d", name, val)) }) + assert.ElementsMatch(t, []string{"foo;bar 10", "foo;baz 20"}, result) }) +} - Describe("ParseIndividualLines", func() { - It("parses data correctly", func() { - r := bytes.NewReader([]byte("foo;bar\nfoo;baz\n")) - result := []string{} - ParseIndividualLines(r, func(name []byte, val int) { - result = append(result, fmt.Sprintf("%s %d", name, val)) - }) - Expect(result).To(ConsistOf("foo;bar 1", "foo;baz 1")) +func TestParseIndividualLines(t *testing.T) { + t.Run("parses data correctly", func(t *testing.T) { + r := bytes.NewReader([]byte("foo;bar\nfoo;baz\n")) + result := []string{} + ParseIndividualLines(r, func(name []byte, val int) { + result = append(result, fmt.Sprintf("%s %d", name, val)) }) + assert.ElementsMatch(t, []string{"foo;bar 1", "foo;baz 1"}, result) }) -}) +} diff --git a/pkg/og/convert/pprof/bench/utils.go b/pkg/og/convert/pprof/bench/utils.go index 500624176f..2fd5a46352 100644 --- a/pkg/og/convert/pprof/bench/utils.go +++ b/pkg/og/convert/pprof/bench/utils.go @@ -22,7 +22,6 @@ func ReadGzipFile(f string) ([]byte, error) { return nil, err } return io.ReadAll(g) - } func WriteGzipFile(f string, data []byte) error { @@ -39,7 +38,19 @@ func WriteGzipFile(f string, data []byte) error { return g.Close() } +type StackCollapseOptions struct { + ValueIdx int + Scale float64 + WithLabels bool +} + func StackCollapseProto(p *profilev1.Profile, valueIDX int, scale float64) []string { + return StackCollapseProtoWithOptions(p, StackCollapseOptions{ValueIdx: valueIDX, Scale: scale}) +} + +func StackCollapseProtoWithOptions(p *profilev1.Profile, opt StackCollapseOptions) []string { + var valueIDX int = opt.ValueIdx + var scale float64 = opt.Scale type stack struct { funcs string value int64 @@ -69,8 +80,17 @@ func StackCollapseProto(p *profilev1.Profile, valueIDX int, scale float64) []str if scale != 1 { v = int64(float64(v) * scale) } + + sls := "" + if opt.WithLabels { + ls := []string{} + for _, label := range s.Label { + ls = append(ls, fmt.Sprintf("(%s = %s)", p.StringTable[label.Key], p.StringTable[label.Str])) + } + sls = strings.Join(ls, ", ") + " ||| " + } ret = append(ret, stack{ - funcs: strings.Join(funcs, ";"), + funcs: sls + strings.Join(funcs, ";"), value: v, }) } @@ -92,7 +112,6 @@ func StackCollapseProto(p *profilev1.Profile, valueIDX int, scale float64) []str continue } unique = append(unique, s) - } res := []string{} diff --git a/pkg/og/convert/pprof/decoder.go b/pkg/og/convert/pprof/decoder.go deleted file mode 100644 index 34ce288dc1..0000000000 --- a/pkg/og/convert/pprof/decoder.go +++ /dev/null @@ -1,48 +0,0 @@ -package pprof - -import ( - "bufio" - "compress/gzip" - "fmt" - "io" - - "github.com/valyala/bytebufferpool" - - "github.com/grafana/pyroscope/pkg/og/storage/tree" -) - -var bufPool = bytebufferpool.Pool{} - -func Decode(r io.Reader, p *tree.Profile) error { - br := bufio.NewReader(r) - header, err := br.Peek(2) - if err != nil { - return fmt.Errorf("failed to read pprof profile header: %w", err) - } - if header[0] == 0x1f && header[1] == 0x8b { - gzipr, err := gzip.NewReader(br) - if err != nil { - return fmt.Errorf("failed to create pprof profile zip reader: %w", err) - } - r = gzipr - defer gzipr.Close() - } else { - r = br - } - buf := bufPool.Get() - defer bufPool.Put(buf) - if _, err = io.Copy(buf, r); err != nil { - return err - } - return p.UnmarshalVT(buf.Bytes()) -} - -func DecodePool(r io.Reader, fn func(*tree.Profile) error) error { - p := tree.ProfileFromVTPool() - defer p.ReturnToVTPool() - p.Reset() - if err := Decode(r, p); err != nil { - return err - } - return fn(p) -} diff --git a/pkg/og/convert/pprof/profile.go b/pkg/og/convert/pprof/profile.go index 047d42862c..7860e960a3 100644 --- a/pkg/og/convert/pprof/profile.go +++ b/pkg/og/convert/pprof/profile.go @@ -6,21 +6,23 @@ import ( "encoding/json" "fmt" "mime/multipart" + "path/filepath" "strings" "time" "connectrpc.com/connect" + "github.com/grafana/dskit/tenant" "github.com/prometheus/prometheus/model/labels" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - distributormodel "github.com/grafana/pyroscope/pkg/distributor/model" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage" - "github.com/grafana/pyroscope/pkg/og/storage/tree" - "github.com/grafana/pyroscope/pkg/og/util/form" - "github.com/grafana/pyroscope/pkg/pprof" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/og/util/form" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) type RawProfile struct { @@ -46,7 +48,7 @@ const ( ) // ParseToPprof is not doing much now. It parses the profile with no processing/splitting, adds labels. -func (p *RawProfile) ParseToPprof(_ context.Context, md ingestion.Metadata) (res *distributormodel.PushRequest, err error) { +func (p *RawProfile) ParseToPprof(ctx context.Context, md ingestion.Metadata, limits ingestion.Limits) (res *distributormodel.PushRequest, err error) { defer func() { r := recover() if r != nil { @@ -58,15 +60,21 @@ func (p *RawProfile) ParseToPprof(_ context.Context, md ingestion.Metadata) (res return nil, fmt.Errorf("failed to parse pprof /ingest multipart form %w", err) } res = &distributormodel.PushRequest{ - RawProfileSize: len(p.Profile), - RawProfileType: distributormodel.RawProfileTypePPROF, - Series: nil, + ReceivedCompressedProfileSize: len(p.Profile), + RawProfileType: distributormodel.RawProfileTypePPROF, + Series: nil, } if len(p.Profile) == 0 { return res, nil } - profile, err := pprof.RawFromBytes(p.Profile) + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, err + } + maxBytes := int64(limits.MaxProfileSizeBytes(tenantID)) + + profile, err := pprof.RawFromBytesWithLimit(p.Profile, maxBytes) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -79,11 +87,9 @@ func (p *RawProfile) ParseToPprof(_ context.Context, md ingestion.Metadata) (res } res.Series = []*distributormodel.ProfileSeries{{ - Labels: p.createLabels(profile, md), - Samples: []*distributormodel.ProfileSample{{ - Profile: profile, - RawProfile: p.Profile, - }}, + Labels: p.createLabels(profile, md), + Profile: profile, + RawProfile: p.Profile, }} return } @@ -106,8 +112,8 @@ func fixTime(profile *pprof.Profile, md ingestion.Metadata) { } } -func (p *RawProfile) Parse(_ context.Context, _ storage.Putter, _ storage.MetricsExporter, md ingestion.Metadata) error { - return fmt.Errorf("parsing pprof to tree/storage.Putter is nolonger ") +func (p *RawProfile) Parse(_ context.Context, _ storage.Putter, _ storage.MetricsExporter, md ingestion.Metadata, _ ingestion.Limits) error { + return fmt.Errorf("parsing pprof to tree/storage.Putter is no longer supported") } func (p *RawProfile) handleRawData() (err error) { @@ -200,21 +206,35 @@ func (p *RawProfile) metricName(profile *pprof.Profile) string { } func (p *RawProfile) createLabels(profile *pprof.Profile, md ingestion.Metadata) []*v1.LabelPair { - ls := make([]*v1.LabelPair, 0, len(md.Key.Labels())+4) + hasServiceName := false + for k := range md.LabelSet.Labels() { + if k == phlaremodel.LabelNameServiceName { + hasServiceName = true + break + } + } + + ls := make([]*v1.LabelPair, 0, len(md.LabelSet.Labels())+4) ls = append(ls, &v1.LabelPair{ Name: labels.MetricName, Value: p.metricName(profile), }, &v1.LabelPair{ Name: phlaremodel.LabelNameDelta, Value: "false", - }, &v1.LabelPair{ - Name: "service_name", - Value: md.Key.AppName(), }, &v1.LabelPair{ Name: phlaremodel.LabelNamePyroscopeSpy, Value: md.SpyName, }) - for k, v := range md.Key.Labels() { + + // Only add service_name if it doesn't exist + if !hasServiceName { + ls = append(ls, &v1.LabelPair{ + Name: phlaremodel.LabelNameServiceName, + Value: md.LabelSet.ServiceName(), + }) + } + + for k, v := range md.LabelSet.Labels() { if !phlaremodel.IsLabelAllowedForIngestion(k) { continue } @@ -275,10 +295,12 @@ func FixFunctionNamesForScriptingLanguages(p *pprof.Profile, md ingestion.Metada for _, location := range p.Location { for _, line := range location.Line { fn := p.Function[funcId2Index[line.FunctionId]] - name := fmt.Sprintf("%s:%d - %s", - p.StringTable[fn.Filename], - line.Line, - p.StringTable[fn.Name]) + filename := p.StringTable[fn.Filename] + // Skip rewriting for pyspy if the filename is an absolute path + if md.SpyName == "pyspy" && filepath.IsAbs(filename) { + continue + } + name := fmt.Sprintf("%s %s", filename, p.StringTable[fn.Name]) newFunc, ok := newFunctions[name] if !ok { maxId++ diff --git a/pkg/og/convert/pprof/profile_test.go b/pkg/og/convert/pprof/profile_test.go index effed00957..57e0654dcc 100644 --- a/pkg/og/convert/pprof/profile_test.go +++ b/pkg/og/convert/pprof/profile_test.go @@ -1,13 +1,17 @@ package pprof import ( - profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - "github.com/grafana/pyroscope/pkg/og/convert/pprof/bench" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/stretchr/testify/assert" "testing" - "github.com/grafana/pyroscope/pkg/og/ingestion" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/api/model/labelset" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/bench" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/pprof" + + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -22,7 +26,7 @@ func TestEmptyPPROF(t *testing.T) { "\r\n" + "--ae798a53dec9077a712cf18e2ebf54842f5c792cfed6a31b6f469cfd2684--\r\n"), } - profile, err := p.ParseToPprof(nil, ingestion.Metadata{}) + profile, err := p.ParseToPprof(nil, ingestion.Metadata{}, nil) require.NoError(t, err) require.Equal(t, 0, len(profile.Series)) } @@ -59,7 +63,7 @@ func TestFixFunctionNamesForScriptingLanguages(t *testing.T) { } md := ingestion.Metadata{ - SpyName: "pyspy", + SpyName: "scripting", } FixFunctionNamesForScriptingLanguages(profile, md) @@ -70,12 +74,137 @@ func TestFixFunctionNamesForScriptingLanguages(t *testing.T) { collapsed := bench.StackCollapseProto(profile.Profile, 0, 1) expected := []string{ - "qwe.py:242 - main;qwe.py:50 - func1 10", - "qwe.py:242 - main;qwe.py:8 - func2 13", + "qwe.py main;qwe.py func1 10", + "qwe.py main;qwe.py func2 13", } assert.Equal(t, expected, collapsed) - assert.Equal(t, "qwe.py:242 - main", functionNameFromLocation(profile.Location[0].Id)) - assert.Equal(t, "qwe.py:50 - func1", functionNameFromLocation(profile.Location[1].Id)) - assert.Equal(t, "qwe.py:8 - func2", functionNameFromLocation(profile.Location[2].Id)) + assert.Equal(t, "qwe.py main", functionNameFromLocation(profile.Location[0].Id)) + assert.Equal(t, "qwe.py func1", functionNameFromLocation(profile.Location[1].Id)) + assert.Equal(t, "qwe.py func2", functionNameFromLocation(profile.Location[2].Id)) +} + +func TestFixFunctionNamesForPyspyRelativePaths(t *testing.T) { + // pyspy with relative paths should have function names rewritten + profile := pprof.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "main", "func1", "qwe.py"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 3, SystemName: 1, StartLine: 1}, + {Id: 2, Name: 2, Filename: 3, SystemName: 2, StartLine: 10}, + }, + Location: []*profilev1.Location{ + {Id: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + {Id: 2, Line: []*profilev1.Line{{FunctionId: 2, Line: 10}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{2, 1}, Value: []int64{10, 1000}}, + }, + }) + + md := ingestion.Metadata{SpyName: "pyspy"} + FixFunctionNamesForScriptingLanguages(profile, md) + + collapsed := bench.StackCollapseProto(profile.Profile, 0, 1) + expected := []string{"qwe.py main;qwe.py func1 10"} + assert.Equal(t, expected, collapsed) +} + +func TestFixFunctionNamesForPyspyAbsolutePaths(t *testing.T) { + // pyspy with absolute paths should NOT have function names rewritten + profile := pprof.RawFromProto(&profilev1.Profile{ + StringTable: []string{"", "main", "func1", "/home/user/project/qwe.py"}, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 3, SystemName: 1, StartLine: 1}, + {Id: 2, Name: 2, Filename: 3, SystemName: 2, StartLine: 10}, + }, + Location: []*profilev1.Location{ + {Id: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + {Id: 2, Line: []*profilev1.Line{{FunctionId: 2, Line: 10}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{2, 1}, Value: []int64{10, 1000}}, + }, + }) + + md := ingestion.Metadata{SpyName: "pyspy"} + FixFunctionNamesForScriptingLanguages(profile, md) + + collapsed := bench.StackCollapseProto(profile.Profile, 0, 1) + // Function names should remain unchanged (not prefixed with filename) + expected := []string{"main;func1 10"} + assert.Equal(t, expected, collapsed) +} + +func TestCreateLabels(t *testing.T) { + testCases := []struct { + name string + labelMap map[string]string + expectedServiceName string + }{ + { + name: "with existing service_name", + labelMap: map[string]string{ + "service_name": "existing-service", + "region": "us-west", + }, + expectedServiceName: "existing-service", + }, + { + name: "without service_name uses __name__ value", + labelMap: map[string]string{ + "region": "us-west", + "__name__": "test-service", + }, + expectedServiceName: "test-service", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + p := RawProfile{ + SampleTypeConfig: map[string]*tree.SampleTypeConfig{ + "samples": { + DisplayName: "samples", + Units: "count", + }, + }, + } + + // Create a proper pprof.Profile with sample types + profile := &pprof.Profile{ + Profile: &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + { + Type: 1, + Unit: 2, + }, + }, + StringTable: []string{"", "samples", "count"}, + }, + } + + // Create metadata with LabelSet + md := ingestion.Metadata{ + LabelSet: labelset.New(tc.labelMap), + SpyName: "test-spy", + } + + // Call createLabels + labels := p.createLabels(profile, md) + + // Convert labels to a map for easier checking + labelMap := make(map[string]string) + for _, label := range labels { + labelMap[label.Name] = label.Value + } + + // Check that service_name has the expected value + assert.Equal(t, tc.expectedServiceName, labelMap["service_name"], "service_name should have the expected value") + + // Check that required labels are present + assert.Contains(t, labelMap, "__name__", "Should contain __name__ label") + assert.Contains(t, labelMap, phlaremodel.LabelNameDelta, "Should contain delta label") + assert.Contains(t, labelMap, phlaremodel.LabelNamePyroscopeSpy, "Should contain spy label") + }) + } } diff --git a/pkg/og/convert/pprof/strprofile/profile.go b/pkg/og/convert/pprof/strprofile/profile.go new file mode 100644 index 0000000000..4beac8a83a --- /dev/null +++ b/pkg/og/convert/pprof/strprofile/profile.go @@ -0,0 +1,385 @@ +package strprofile + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "sort" + "strconv" + "strings" + + "github.com/cespare/xxhash/v2" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" +) + +type Options struct { + NoPrettyPrint bool + NoDuration bool + NoTime bool + NoCompact bool + IncludeIDs bool +} + +type Location struct { + ID uint64 `json:"id,omitempty"` + Address string `json:"address,omitempty"` + Lines []Line `json:"lines,omitempty"` + Mapping *Mapping `json:"mapping,omitempty"` +} + +type Line struct { + Function *Function `json:"function"` + Line int64 `json:"line,omitempty"` +} + +type Function struct { + ID uint64 `json:"id,omitempty"` + Name string `json:"name"` + SystemName string `json:"system_name,omitempty"` + Filename string `json:"filename,omitempty"` + StartLine int64 `json:"start_line,omitempty"` +} + +type Mapping struct { + ID uint64 `json:"id,omitempty"` + Start string `json:"start"` + Limit string `json:"limit"` + Offset string `json:"offset,omitempty"` + Filename string `json:"filename,omitempty"` + BuildID string `json:"build_id,omitempty"` +} + +type SampleType struct { + Type string `json:"type"` + Unit string `json:"unit"` +} + +type Label struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type Sample struct { + Locations []Location `json:"locations,omitempty"` + Values []int64 `json:"values"` + Labels []Label `json:"labels,omitempty"` +} + +type Profile struct { + SampleTypes []SampleType `json:"sample_types"` + Samples []Sample `json:"samples"` + TimeNanos string `json:"time_nanos,omitempty"` + DurationNanos string `json:"duration_nanos,omitempty"` + Period string `json:"period,omitempty"` +} + +type CompactLocation struct { + ID uint64 `json:"id,omitempty"` + Address string `json:"address,omitempty"` + Lines []string `json:"lines,omitempty"` + Mapping string `json:"mapping,omitempty"` +} + +type CompactSample struct { + Locations []CompactLocation `json:"locations,omitempty"` + Values string `json:"values"` + Labels string `json:"labels,omitempty"` +} + +type CompactProfile struct { + SampleTypes []SampleType `json:"sample_types"` + Samples []CompactSample `json:"samples"` + TimeNanos string `json:"time_nanos,omitempty"` + DurationNanos string `json:"duration_nanos,omitempty"` + Period string `json:"period,omitempty"` +} + +func Stringify(p *profilev1.Profile, opts Options) (string, error) { + var err error + var sp interface{} + + if !opts.NoCompact { + sp = ToCompactProfile(p, opts) + } else { + sp = ToDetailedProfile(p, opts) + } + + var jsonData []byte + if !opts.NoPrettyPrint { + jsonData, err = json.MarshalIndent(sp, "", " ") + } else { + jsonData, err = json.Marshal(sp) + } + if err != nil { + return "", err + } + + return string(jsonData), nil +} + +func ToDetailedProfile(p *profilev1.Profile, opts Options) Profile { + sp := Profile{ + Period: fmt.Sprintf("%d", p.Period), + } + if !opts.NoTime { + sp.TimeNanos = fmt.Sprintf("%d", p.TimeNanos) + } + if !opts.NoDuration { + sp.DurationNanos = fmt.Sprintf("%d", p.DurationNanos) + } + + for _, st := range p.SampleType { + sp.SampleTypes = append(sp.SampleTypes, SampleType{ + Type: p.StringTable[st.Type], + Unit: p.StringTable[st.Unit], + }) + } + + // Create maps for quick lookups + functionMap := make(map[uint64]*profilev1.Function) + for _, f := range p.Function { + functionMap[f.Id] = f + } + + mappingMap := make(map[uint64]*profilev1.Mapping) + for _, m := range p.Mapping { + mappingMap[m.Id] = m + } + + for _, sample := range p.Sample { + ss := Sample{ + Values: sample.Value, + } + + for _, locID := range sample.LocationId { + loc := findLocation(p.Location, locID) + if loc == nil { + continue + } + + sLoc := Location{ + Address: fmt.Sprintf("0x%x", loc.Address), + } + if opts.IncludeIDs { + sLoc.ID = loc.Id + } + + if loc.MappingId != 0 { + if mapping := mappingMap[loc.MappingId]; mapping != nil { + m := &Mapping{ + Start: fmt.Sprintf("0x%x", mapping.MemoryStart), + Limit: fmt.Sprintf("0x%x", mapping.MemoryLimit), + Offset: fmt.Sprintf("0x%x", mapping.FileOffset), + Filename: p.StringTable[mapping.Filename], + BuildID: p.StringTable[mapping.BuildId], + } + if opts.IncludeIDs { + m.ID = mapping.Id + } + sLoc.Mapping = m + } + } + + for _, line := range loc.Line { + if fn := functionMap[line.FunctionId]; fn != nil { + f := &Function{ + Name: p.StringTable[fn.Name], + SystemName: p.StringTable[fn.SystemName], + Filename: p.StringTable[fn.Filename], + StartLine: fn.StartLine, + } + if opts.IncludeIDs { + f.ID = fn.Id + } + sLine := Line{ + Function: f, + Line: line.Line, + } + sLoc.Lines = append(sLoc.Lines, sLine) + } + } + + ss.Locations = append(ss.Locations, sLoc) + } + + if len(sample.Label) > 0 { + ss.Labels = make([]Label, 0, len(sample.Label)) + for _, label := range sample.Label { + key := p.StringTable[label.Key] + var value string + if label.Str != 0 { + value = p.StringTable[label.Str] + } else { + value = strconv.FormatInt(label.Num, 10) + } + ss.Labels = append(ss.Labels, Label{ + Key: key, + Value: value, + }) + } + } + + sp.Samples = append(sp.Samples, ss) + } + return sp +} + +func ToCompactProfile(p *profilev1.Profile, opts Options) CompactProfile { + sp := CompactProfile{ + Period: fmt.Sprintf("%d", p.Period), + } + if !opts.NoTime { + sp.TimeNanos = fmt.Sprintf("%d", p.TimeNanos) + } + if !opts.NoDuration { + sp.DurationNanos = fmt.Sprintf("%d", p.DurationNanos) + } + + for _, st := range p.SampleType { + sp.SampleTypes = append(sp.SampleTypes, SampleType{ + Type: p.StringTable[st.Type], + Unit: p.StringTable[st.Unit], + }) + } + + functionMap := make(map[uint64]*profilev1.Function) + for _, f := range p.Function { + functionMap[f.Id] = f + } + + mappingMap := make(map[uint64]*profilev1.Mapping) + for _, m := range p.Mapping { + mappingMap[m.Id] = m + } + + for _, sample := range p.Sample { + values := make([]string, len(sample.Value)) + for i, v := range sample.Value { + values[i] = strconv.FormatInt(v, 10) + } + + ss := CompactSample{ + Values: strings.Join(values, ","), + } + + for _, locID := range sample.LocationId { + loc := findLocation(p.Location, locID) + if loc == nil { + continue + } + + sLoc := CompactLocation{ + Address: fmt.Sprintf("0x%x", loc.Address), + } + if opts.IncludeIDs { + sLoc.ID = loc.Id + } + + if loc.MappingId != 0 { + if mapping := mappingMap[loc.MappingId]; mapping != nil { + idStr := "" + if opts.IncludeIDs { + idStr = fmt.Sprintf("[id=%d]", mapping.Id) + } + sLoc.Mapping = fmt.Sprintf("0x%x-0x%x@0x%x %s(%s)%s", + mapping.MemoryStart, + mapping.MemoryLimit, + mapping.FileOffset, + p.StringTable[mapping.Filename], + p.StringTable[mapping.BuildId], + idStr) + } + } + + for _, line := range loc.Line { + if fn := functionMap[line.FunctionId]; fn != nil { + idStr := "" + if opts.IncludeIDs { + idStr = fmt.Sprintf("[id=%d]", fn.Id) + } + lineStr := fmt.Sprintf("%s[%s]@%s:%d%s", + p.StringTable[fn.Name], + p.StringTable[fn.SystemName], + p.StringTable[fn.Filename], + line.Line, + idStr) + sLoc.Lines = append(sLoc.Lines, lineStr) + } + } + + ss.Locations = append(ss.Locations, sLoc) + } + + if len(sample.Label) > 0 { + labels := make([]string, 0, len(sample.Label)) + for _, label := range sample.Label { + key := p.StringTable[label.Key] + var value string + if label.Str != 0 { + value = p.StringTable[label.Str] + } else { + value = strconv.FormatInt(label.Num, 10) + } + labels = append(labels, fmt.Sprintf("%s=%s", key, value)) + } + sort.Strings(labels) + ss.Labels = strings.Join(labels, ",") + } + + sp.Samples = append(sp.Samples, ss) + } + return sp +} + +func findLocation(locations []*profilev1.Location, id uint64) *profilev1.Location { + for _, loc := range locations { + if loc.Id == id { + return loc + } + } + return nil +} + +func SortProfileSamples(p CompactProfile) { + h := xxhash.New() + s := &sortedSample{ + samples: p.Samples, + hashes: make([]uint64, len(p.Samples)), + } + for i := range s.samples { + s.hashes[i] = sampleHash(h, s.samples[i]) + } + sort.Sort(s) +} + +type sortedSample struct { + samples []CompactSample + hashes []uint64 +} + +func (s *sortedSample) Len() int { return len(s.samples) } + +func (s *sortedSample) Less(i, j int) bool { return s.hashes[i] < s.hashes[j] } + +func (s *sortedSample) Swap(i, j int) { + s.samples[i], s.samples[j] = s.samples[j], s.samples[i] + s.hashes[i], s.hashes[j] = s.hashes[j], s.hashes[i] +} + +func sampleHash(d *xxhash.Digest, s CompactSample) uint64 { + d.Reset() + tmp := make([]byte, 8) + _, _ = d.WriteString(s.Labels) + _, _ = d.WriteString(s.Values) + for i := range s.Locations { + binary.LittleEndian.PutUint64(tmp, s.Locations[i].ID) + _, _ = d.Write(tmp) + _, _ = d.WriteString(s.Locations[i].Address) + _, _ = d.WriteString(s.Locations[i].Mapping) + for j := range s.Locations[i].Lines { + _, _ = d.WriteString(s.Locations[i].Lines[j]) + } + } + return d.Sum64() +} diff --git a/pkg/og/convert/profile/profile.go b/pkg/og/convert/profile/profile.go index 031e586e52..fa33efbbf5 100644 --- a/pkg/og/convert/profile/profile.go +++ b/pkg/og/convert/profile/profile.go @@ -5,11 +5,11 @@ import ( "context" "fmt" - "github.com/grafana/pyroscope/pkg/og/convert" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage" - "github.com/grafana/pyroscope/pkg/og/storage/tree" - "github.com/grafana/pyroscope/pkg/og/structs/transporttrie" + "github.com/grafana/pyroscope/v2/pkg/og/convert" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/og/structs/transporttrie" ) type RawProfile struct { @@ -21,11 +21,11 @@ func (p *RawProfile) Bytes() ([]byte, error) { return p.RawData, nil } func (*RawProfile) ContentType() string { return "binary/octet-stream" } -func (p *RawProfile) Parse(ctx context.Context, putter storage.Putter, exporter storage.MetricsExporter, md ingestion.Metadata) error { +func (p *RawProfile) Parse(ctx context.Context, putter storage.Putter, exporter storage.MetricsExporter, md ingestion.Metadata, limits ingestion.Limits) error { input := &storage.PutInput{ StartTime: md.StartTime, EndTime: md.EndTime, - Key: md.Key, + LabelSet: md.LabelSet, SpyName: md.SpyName, SampleRate: md.SampleRate, Units: md.Units, @@ -40,7 +40,7 @@ func (p *RawProfile) Parse(ctx context.Context, putter storage.Putter, exporter case ingestion.FormatTrie: err = transporttrie.IterateRaw(r, make([]byte, 0, 256), cb) case ingestion.FormatTree: - err = convert.ParseTreeNoDict(r, cb) + err = convert.ParseTreeNoDict(ctx, r, cb, limits) case ingestion.FormatLines: err = convert.ParseIndividualLines(r, cb) case ingestion.FormatGroups: diff --git a/pkg/og/convert/profile/profile_suite_test.go b/pkg/og/convert/profile/profile_suite_test.go deleted file mode 100644 index bab8ef3730..0000000000 --- a/pkg/og/convert/profile/profile_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package profile_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestConvert(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Profile Suite") -} diff --git a/pkg/og/convert/profile/profile_test.go b/pkg/og/convert/profile/profile_test.go index 36a7987f8e..5d4b6fcd61 100644 --- a/pkg/og/convert/profile/profile_test.go +++ b/pkg/og/convert/profile/profile_test.go @@ -1,16 +1,28 @@ package profile import ( + "bytes" "context" + "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage" - "github.com/grafana/pyroscope/pkg/og/storage/segment" + "github.com/grafana/dskit/user" + + "github.com/grafana/pyroscope/api/model/labelset" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage" ) +type mockLimits struct { + maxSymbolLen int + maxSamples int +} + +func (m mockLimits) MaxProfileSizeBytes(_ string) int { return 0 } +func (m mockLimits) MaxProfileSymbolValueLength(_ string) int { return m.maxSymbolLen } +func (m mockLimits) MaxProfileStacktraceSamples(_ string) int { return m.maxSamples } + type mockIngester struct{ actual []*storage.PutInput } func (m *mockIngester) Put(_ context.Context, p *storage.PutInput) error { @@ -43,48 +55,74 @@ func (m *mockObserver) Observe(k []byte, v int) { m.values = append(m.values, v) } -var _ = Describe("metrics exporter", func() { - var ( - exporter *mockExporter - ingester *mockIngester +func runMetricsExporterTest(t *testing.T, observe bool) (*mockExporter, *mockIngester) { + t.Helper() + + exporter := newMockExporter(observe) + ingester := new(mockIngester) + md := ingestion.Metadata{LabelSet: new(labelset.LabelSet)} + p := RawProfile{ + Format: ingestion.FormatGroups, + RawData: []byte("foo;bar 1\nfoo;baz 2\n"), + } + + require.NoError(t, p.Parse(context.Background(), ingester, exporter, md, nil)) + return exporter, ingester +} + +func TestMetricsExporter(t *testing.T) { + t.Run("if evaluation successful", func(t *testing.T) { + exporter, ingester := runMetricsExporterTest(t, true) - md ingestion.Metadata - p RawProfile - ) + require.Equal(t, uint64(3), ingester.actual[0].Val.Samples()) + require.Equal(t, []string{"foo;bar", "foo;baz"}, exporter.observer.keys) + require.Equal(t, []int{1, 2}, exporter.observer.values) + }) - JustBeforeEach(func() { - ingester = new(mockIngester) - md = ingestion.Metadata{Key: new(segment.Key)} - p = RawProfile{ - Format: ingestion.FormatGroups, - RawData: []byte("foo;bar 1\nfoo;baz 2\n"), - } + t.Run("if evaluation unsuccessful", func(t *testing.T) { + exporter, ingester := runMetricsExporterTest(t, false) - Expect(p.Parse(context.Background(), ingester, exporter, md)).ToNot(HaveOccurred()) + require.Equal(t, uint64(3), ingester.actual[0].Val.Samples()) + require.Nil(t, exporter.observer) }) +} - ItIngestsTree := func() { - Expect(ingester.actual[0].Val.Samples()).To(Equal(uint64(3))) - } +// serializationExample is a valid tree-format payload (same fixture as serialize_nodict_test.go). +var serializationExample = []byte("\x00\x00\x01\x01a\x00\x02\x01b\x01\x00\x01c\x02\x00") + +func TestFormatTreeWithLimits(t *testing.T) { + t.Run("parses a valid tree payload and applies limits", func(t *testing.T) { + ingester := new(mockIngester) + md := ingestion.Metadata{LabelSet: new(labelset.LabelSet)} + ctx := user.InjectOrgID(context.Background(), "test-tenant") + p := RawProfile{Format: ingestion.FormatTree, RawData: serializationExample} + err := p.Parse(ctx, ingester, newMockExporter(false), md, mockLimits{maxSymbolLen: 65535, maxSamples: 16000}) + require.NoError(t, err) + require.Len(t, ingester.actual, 1) + }) - Context("if evaluation successful", func() { - BeforeEach(func() { - exporter = newMockExporter(true) - }) - It("ingests the tree", ItIngestsTree) - It("observes stack values", func() { - Expect(exporter.observer.keys).To(Equal([]string{"foo;bar", "foo;baz"})) - Expect(exporter.observer.values).To(Equal([]int{1, 2})) - }) + t.Run("rejects a payload with an oversized name length when limits are set", func(t *testing.T) { + // varint encoding of 0xFFFFFFFFFFFFFFFF — without bounds checks this panics + payload := bytes.Repeat([]byte{0xff}, 9) + payload = append(payload, 0x01) + ingester := new(mockIngester) + md := ingestion.Metadata{LabelSet: new(labelset.LabelSet)} + ctx := user.InjectOrgID(context.Background(), "test-tenant") + p := RawProfile{Format: ingestion.FormatTree, RawData: payload} + err := p.Parse(ctx, ingester, newMockExporter(false), md, mockLimits{maxSymbolLen: 65535, maxSamples: 16000}) + require.Error(t, err) + require.Contains(t, err.Error(), "exceeds maximum") }) - Context("if evaluation unsuccessful", func() { - BeforeEach(func() { - exporter = newMockExporter(false) - }) - It("ingests the tree", ItIngestsTree) - It("does not observe stack values", func() { - Expect(exporter.observer).To(BeNil()) - }) + t.Run("does not enforce limits when nil is passed", func(t *testing.T) { + // With nil limits the oversized varint reaches make([]byte, n) and panics + // without the serialize.go guard — the guard doesn't fire because maxNameLen=0 + // means disabled. This test confirms nil limits don't error on valid payloads. + ingester := new(mockIngester) + md := ingestion.Metadata{LabelSet: new(labelset.LabelSet)} + ctx := user.InjectOrgID(context.Background(), "test-tenant") + p := RawProfile{Format: ingestion.FormatTree, RawData: serializationExample} + err := p.Parse(ctx, ingester, newMockExporter(false), md, nil) + require.NoError(t, err) }) -}) +} diff --git a/pkg/og/convert/speedscope/parser.go b/pkg/og/convert/speedscope/parser.go index be2f462704..d57b146556 100644 --- a/pkg/og/convert/speedscope/parser.go +++ b/pkg/og/convert/speedscope/parser.go @@ -1,14 +1,17 @@ package speedscope import ( + "cmp" "context" "encoding/json" "fmt" + "slices" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" + "golang.org/x/exp/maps" ) // RawProfile implements ingestion.RawProfile for Speedscope format @@ -17,7 +20,7 @@ type RawProfile struct { } // Parse parses a profile -func (p *RawProfile) Parse(ctx context.Context, putter storage.Putter, _ storage.MetricsExporter, md ingestion.Metadata) error { +func (p *RawProfile) Parse(ctx context.Context, putter storage.Putter, _ storage.MetricsExporter, md ingestion.Metadata, _ ingestion.Limits) error { profiles, err := parseAll(p.RawData, md) if err != nil { return err @@ -49,9 +52,11 @@ func parseAll(rawData []byte, md ingestion.Metadata) ([]*storage.PutInput, error EndTime: md.EndTime, SpyName: md.SpyName, SampleRate: md.SampleRate, - Key: md.Key, + LabelSet: md.LabelSet, } + file.Profiles = mergeProfiles(file.Profiles) + for _, prof := range file.Profiles { putInput, err := parseOne(&prof, input, file.Shared.Frames, len(file.Profiles) > 1) if err != nil { @@ -62,18 +67,69 @@ func parseAll(rawData []byte, md ingestion.Metadata) ([]*storage.PutInput, error return results, nil } +// mergeProfiles combines profiles with the same mergeKey. +// This prevents situations downstream where two different +// profiles are deduped during congestion for having the +// same label set and timestamp. +func mergeProfiles(profiles []profile) []profile { + type mergeKey struct { + name string + t string + unit unit + startValue float64 + } + + merged := make(map[mergeKey]profile) + for _, prof := range profiles { + k := mergeKey{ + name: prof.Name, + t: prof.Type, + unit: prof.Unit, + startValue: prof.StartValue, + } + + if mergedProf, ok := merged[k]; ok { + mergedProf.Samples = append(mergedProf.Samples, prof.Samples...) + mergedProf.Events = append(mergedProf.Events, prof.Events...) + mergedProf.Weights = append(mergedProf.Weights, prof.Weights...) + merged[k] = mergedProf + } else { + merged[k] = prof + } + } + + m := maps.Values(merged) + slices.SortFunc(m, func(a, b profile) int { + return cmp.Compare(a.StartValue, b.StartValue) + }) + return m +} + func parseOne(prof *profile, putInput storage.PutInput, frames []frame, multi bool) (*storage.PutInput, error) { // Fixup some metadata putInput.Units = prof.Unit.chooseMetadataUnit() putInput.AggregationType = metadata.SumAggregationType if multi { - putInput.Key = prof.Unit.chooseKey(putInput.Key) + putInput.LabelSet = prof.Unit.chooseKey(putInput.LabelSet) } + // This label is important to prevent all speedscope profiles + // from the same ingestion upload being deduped during compaction. + // Currently, all profiles are associated with the same timestamp + // from `putInput`. Since profiles are deduped over label set + timestamp, + // this label prevents unintended downstream deduping. See also mergeProfiles + // which addresses the case where the profile names (and other relevant fields) + // are the same for multiple profiles. + putInput.LabelSet.Add("profile_name", prof.Name) + // TODO(petethepig): We need a way to tell if it's a default or a value set by user // See https://github.com/pyroscope-io/pyroscope/issues/1598 if putInput.SampleRate == 100 { - putInput.SampleRate = uint32(prof.Unit.defaultSampleRate()) + rate, err := prof.Unit.defaultSampleRate() + if err != nil { + return nil, fmt.Errorf("invalid profile unit: %w", err) + } + putInput.SampleRate = rate } var err error @@ -98,7 +154,10 @@ func parseEvented(tr *tree.Tree, prof *profile, frames []frame) error { last := prof.StartValue indexStack := []int{} nameStack := []string{} - precisionMultiplier := prof.Unit.precisionMultiplier() + precisionMultiplier, err := prof.Unit.precisionMultiplier() + if err != nil { + return fmt.Errorf("invalid profile unit: %w", err) + } for _, ev := range prof.Events { if ev.At < last { @@ -146,7 +205,10 @@ func parseSampled(tr *tree.Tree, prof *profile, frames []frame) error { return fmt.Errorf("Unequal lengths of samples and weights: %d != %d", len(prof.Samples), len(prof.Weights)) } - precisionMultiplier := prof.Unit.precisionMultiplier() + precisionMultiplier, err := prof.Unit.precisionMultiplier() + if err != nil { + return fmt.Errorf("invalid profile unit: %w", err) + } stack := []string{} for i, samp := range prof.Samples { weight := prof.Weights[i] diff --git a/pkg/og/convert/speedscope/speedscope_suite_test.go b/pkg/og/convert/speedscope/speedscope_suite_test.go deleted file mode 100644 index 1693849ccb..0000000000 --- a/pkg/og/convert/speedscope/speedscope_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package speedscope_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestConvert(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Speedscope Suite") -} diff --git a/pkg/og/convert/speedscope/speedscope_test.go b/pkg/og/convert/speedscope/speedscope_test.go index fb5970ba6b..a2422a2663 100644 --- a/pkg/og/convert/speedscope/speedscope_test.go +++ b/pkg/og/convert/speedscope/speedscope_test.go @@ -3,14 +3,14 @@ package speedscope import ( "context" "os" + "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/segment" + "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/og/storage" + "github.com/grafana/pyroscope/api/model/labelset" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" ) type mockIngester struct{ actual []*storage.PutInput } @@ -20,58 +20,143 @@ func (m *mockIngester) Put(_ context.Context, p *storage.PutInput) error { return nil } -var _ = Describe("Speedscope", func() { - It("Can parse an event-format profile", func() { +func findInputByLabel(inputs []*storage.PutInput, normalizedLabel string) *storage.PutInput { + for _, in := range inputs { + if in.LabelSet.Normalized() == normalizedLabel { + return in + } + } + return nil +} + +const expectedTreeResult = `a;b 500 +a;b;c 500 +a;b;d 400 +` + +func TestSpeedscope(t *testing.T) { + t.Run("Can parse an event-format profile", func(t *testing.T) { data, err := os.ReadFile("testdata/simple.speedscope.json") - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err) - key, err := segment.ParseKey("foo") - Expect(err).ToNot(HaveOccurred()) + key, err := labelset.Parse("foo") + require.NoError(t, err) ingester := new(mockIngester) profile := &RawProfile{RawData: data} - md := ingestion.Metadata{Key: key, SampleRate: 100} - err = profile.Parse(context.Background(), ingester, nil, md) - Expect(err).ToNot(HaveOccurred()) + md := ingestion.Metadata{LabelSet: key, SampleRate: 100} + err = profile.Parse(context.Background(), ingester, nil, md, nil) + require.NoError(t, err) - Expect(ingester.actual).To(HaveLen(1)) + require.Len(t, ingester.actual, 1) input := ingester.actual[0] - Expect(input.Units).To(Equal(metadata.SamplesUnits)) - Expect(input.Key.Normalized()).To(Equal("foo{}")) - expectedResult := `a;b 500 -a;b;c 500 -a;b;d 400 -` - Expect(input.Val.String()).To(Equal(expectedResult)) - Expect(input.SampleRate).To(Equal(uint32(10000))) + require.Equal(t, metadata.SamplesUnits, input.Units) + require.Equal(t, "foo{profile_name=simple.txt}", input.LabelSet.Normalized()) + require.Equal(t, expectedTreeResult, input.Val.String()) + require.Equal(t, uint32(10000), input.SampleRate) }) - It("Can parse a sample-format profile", func() { + t.Run("Can parse a sample-format profile", func(t *testing.T) { data, err := os.ReadFile("testdata/two-sampled.speedscope.json") - Expect(err).ToNot(HaveOccurred()) + require.NoError(t, err) + + key, err := labelset.Parse("foo{x=y}") + require.NoError(t, err) + + ingester := new(mockIngester) + profile := &RawProfile{RawData: data} + + md := ingestion.Metadata{LabelSet: key, SampleRate: 100} + err = profile.Parse(context.Background(), ingester, nil, md, nil) + require.NoError(t, err) + + require.Len(t, ingester.actual, 2) + + input := findInputByLabel(ingester.actual, "foo.seconds{profile_name=one,x=y}") + require.NotNil(t, input) + require.Equal(t, metadata.SamplesUnits, input.Units) + require.Equal(t, "foo.seconds{profile_name=one,x=y}", input.LabelSet.Normalized()) + require.Equal(t, expectedTreeResult, input.Val.String()) + require.Equal(t, uint32(100), input.SampleRate) + + input2 := findInputByLabel(ingester.actual, "foo.seconds{profile_name=two,x=y}") + require.NotNil(t, input2) + require.Equal(t, metadata.SamplesUnits, input2.Units) + require.Equal(t, "foo.seconds{profile_name=two,x=y}", input2.LabelSet.Normalized()) + require.Equal(t, expectedTreeResult, input2.Val.String()) + require.Equal(t, uint32(100), input2.SampleRate) + }) + + t.Run("Returns error for unknown unit in defaultSampleRate", func(t *testing.T) { + u := unit("UNKNOWN_UNIT") + _, err := u.defaultSampleRate() + require.Error(t, err) + require.Contains(t, err.Error(), "unknown unit") + }) + + t.Run("Returns error for unknown unit in precisionMultiplier", func(t *testing.T) { + u := unit("UNKNOWN_UNIT") + _, err := u.precisionMultiplier() + require.Error(t, err) + require.Contains(t, err.Error(), "unknown unit") + }) + + t.Run("Returns error instead of panicking for unknown unit in sampled profile", func(t *testing.T) { + data := []byte(`{"$schema":"https://www.speedscope.app/file-format-schema.json","shared":{"frames":[{"name":"main"}]},"profiles":[{"type":"sampled","unit":"TRIGGER_PANIC_UNKNOWN_UNIT","name":"poc","startValue":0,"endValue":1,"samples":[[0]],"weights":[1]}]}`) + + key, err := labelset.Parse("foo") + require.NoError(t, err) + + ingester := new(mockIngester) + profile := &RawProfile{RawData: data} + + md := ingestion.Metadata{LabelSet: key, SampleRate: 100} + err = profile.Parse(context.Background(), ingester, nil, md, nil) + require.Error(t, err) + require.Empty(t, ingester.actual) + }) - key, err := segment.ParseKey("foo{x=y}") - Expect(err).ToNot(HaveOccurred()) + t.Run("Returns error instead of panicking for unknown unit in evented profile", func(t *testing.T) { + data := []byte(`{"$schema":"https://www.speedscope.app/file-format-schema.json","shared":{"frames":[{"name":"a"}]},"profiles":[{"type":"evented","unit":"TRIGGER_PANIC_UNKNOWN_UNIT","name":"poc","startValue":0,"endValue":1,"events":[{"type":"O","frame":0,"at":0},{"type":"C","frame":0,"at":1}]}]}`) + + key, err := labelset.Parse("foo") + require.NoError(t, err) ingester := new(mockIngester) profile := &RawProfile{RawData: data} - md := ingestion.Metadata{Key: key, SampleRate: 100} - err = profile.Parse(context.Background(), ingester, nil, md) - Expect(err).ToNot(HaveOccurred()) + md := ingestion.Metadata{LabelSet: key, SampleRate: 100} + err = profile.Parse(context.Background(), ingester, nil, md, nil) + require.Error(t, err) + require.Empty(t, ingester.actual) + }) - Expect(ingester.actual).To(HaveLen(2)) + t.Run("Merges duplicate profiles", func(t *testing.T) { + data, err := os.ReadFile("testdata/duplicates.speedscope.json") + require.NoError(t, err) + + key, err := labelset.Parse("foo{x=y}") + require.NoError(t, err) + + ingester := new(mockIngester) + profile := &RawProfile{RawData: data} + + md := ingestion.Metadata{LabelSet: key, SampleRate: 100} + err = profile.Parse(context.Background(), ingester, nil, md, nil) + require.NoError(t, err) + + require.Len(t, ingester.actual, 1) input := ingester.actual[0] - Expect(input.Units).To(Equal(metadata.SamplesUnits)) - Expect(input.Key.Normalized()).To(Equal("foo.seconds{x=y}")) - expectedResult := `a;b 500 -a;b;c 500 -a;b;d 400 + require.Equal(t, metadata.SamplesUnits, input.Units) + require.Equal(t, "foo{profile_name=one,x=y}", input.LabelSet.Normalized()) + expectedResult := `a;b 1500 +a;b;c 1500 +a;b;d 1200 ` - Expect(input.Val.String()).To(Equal(expectedResult)) - Expect(input.SampleRate).To(Equal(uint32(100))) + require.Equal(t, expectedResult, input.Val.String()) + require.Equal(t, uint32(100), input.SampleRate) }) -}) +} diff --git a/pkg/og/convert/speedscope/testdata/duplicates.speedscope.json b/pkg/og/convert/speedscope/testdata/duplicates.speedscope.json new file mode 100644 index 0000000000..b168ae656a --- /dev/null +++ b/pkg/og/convert/speedscope/testdata/duplicates.speedscope.json @@ -0,0 +1,61 @@ +{ + "exporter": "speedscope@0.6.0", + "$schema": "https://www.speedscope.app/file-format-schema.json", + "name": "Two Duplicate Samples", + "activeProfileIndex": 1, + "profiles": [ + { + "type": "sampled", + "name": "one", + "unit": "seconds", + "startValue": 0, + "endValue": 14, + "samples": [ + [0, 1, 2], + [0, 1, 2], + [0, 1, 3], + [0, 1, 2], + [0, 1] + ], + "weights": [1, 1, 4, 3, 5] + }, + { + "type": "sampled", + "name": "one", + "unit": "seconds", + "startValue": 0, + "endValue": 14, + "samples": [ + [0, 1, 2], + [0, 1, 2], + [0, 1, 3], + [0, 1, 2], + [0, 1] + ], + "weights": [1, 1, 4, 3, 5] + }, + { + "type": "sampled", + "name": "one", + "unit": "seconds", + "startValue": 0, + "endValue": 52, + "samples": [ + [0, 1, 2], + [0, 1, 2], + [0, 1, 3], + [0, 1, 2], + [0, 1] + ], + "weights": [1, 1, 4, 3, 5] + } + ], + "shared": { + "frames": [ + { "name": "a" }, + { "name": "b" }, + { "name": "c" }, + { "name": "d" } + ] + } +} diff --git a/pkg/og/convert/speedscope/testdata/two-sampled-bytes.speedscope.json b/pkg/og/convert/speedscope/testdata/two-sampled-bytes.speedscope.json new file mode 100644 index 0000000000..939ae3e8b3 --- /dev/null +++ b/pkg/og/convert/speedscope/testdata/two-sampled-bytes.speedscope.json @@ -0,0 +1,46 @@ +{ + "exporter": "speedscope@0.6.0", + "$schema": "https://www.speedscope.app/file-format-schema.json", + "name": "Two Samples", + "activeProfileIndex": 1, + "profiles": [ + { + "type": "sampled", + "name": "one", + "unit": "bytes", + "startValue": 0, + "endValue": 14, + "samples": [ + [0, 1, 2], + [0, 1, 2], + [0, 1, 3], + [0, 1, 2], + [0, 1] + ], + "weights": [1, 1, 4, 3, 5] + }, + { + "type": "sampled", + "name": "two", + "unit": "bytes", + "startValue": 0, + "endValue": 14, + "samples": [ + [0, 1, 2], + [0, 1, 2], + [0, 1, 3], + [0, 1, 2], + [0, 1] + ], + "weights": [1, 1, 4, 3, 5] + } + ], + "shared": { + "frames": [ + { "name": "a" }, + { "name": "b" }, + { "name": "c" }, + { "name": "d" } + ] + } +} diff --git a/pkg/og/convert/speedscope/units.go b/pkg/og/convert/speedscope/units.go index 3ddf7e9623..6105ac74c7 100644 --- a/pkg/og/convert/speedscope/units.go +++ b/pkg/og/convert/speedscope/units.go @@ -3,8 +3,8 @@ package speedscope import ( "fmt" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/segment" + "github.com/grafana/pyroscope/api/model/labelset" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" ) type unit string @@ -22,42 +22,34 @@ const ( // from doubles to integers var timePrecisionMultiplier = 100 -func (u unit) defaultSampleRate() uint32 { +func (u unit) defaultSampleRate() (uint32, error) { switch u { case unitNanoseconds: - return uint32(timePrecisionMultiplier) * 1000 * 1000 * 1000 + return uint32(timePrecisionMultiplier) * 1000 * 1000 * 1000, nil case unitMicroseconds: - return uint32(timePrecisionMultiplier) * 1000 * 1000 + return uint32(timePrecisionMultiplier) * 1000 * 1000, nil case unitMilliseconds: - return uint32(timePrecisionMultiplier) * 1000 + return uint32(timePrecisionMultiplier) * 1000, nil case unitSeconds: - return uint32(timePrecisionMultiplier) + return uint32(timePrecisionMultiplier), nil case unitNone: // 100 is a common default value for sample rate - return uint32(timePrecisionMultiplier) * 100 + return uint32(timePrecisionMultiplier) * 100, nil case unitBytes: - return 0 + return 0, nil default: - panic("unknown unit " + u) + return 0, fmt.Errorf("unknown unit: %s", u) } } -func (u unit) precisionMultiplier() uint64 { +func (u unit) precisionMultiplier() (uint64, error) { switch u { - case unitNanoseconds: - return uint64(timePrecisionMultiplier) - case unitMicroseconds: - return uint64(timePrecisionMultiplier) - case unitMilliseconds: - return uint64(timePrecisionMultiplier) - case unitSeconds: - return uint64(timePrecisionMultiplier) - case unitNone: - return uint64(timePrecisionMultiplier) + case unitNanoseconds, unitMicroseconds, unitMilliseconds, unitSeconds, unitNone: + return uint64(timePrecisionMultiplier), nil case unitBytes: - return 1 + return 1, nil default: - panic("unknown unit " + u) + return 0, fmt.Errorf("unknown unit: %s", u) } } @@ -70,9 +62,9 @@ func (u unit) chooseMetadataUnit() metadata.Units { } } -func (u unit) chooseKey(orig *segment.Key) *segment.Key { +func (u unit) chooseKey(orig *labelset.LabelSet) *labelset.LabelSet { // This means we'll have duplicate keys if multiple profiles have the same units. Probably ok. - name := fmt.Sprintf("%s.%s", orig.AppName(), u) + name := fmt.Sprintf("%s.%s", orig.ServiceName(), u) result := orig.Clone() result.Add("__name__", name) return result diff --git a/pkg/og/flameql/error.go b/pkg/og/flameql/error.go deleted file mode 100644 index b910cc6658..0000000000 --- a/pkg/og/flameql/error.go +++ /dev/null @@ -1,45 +0,0 @@ -package flameql - -import ( - "errors" - "fmt" -) - -var ( - ErrInvalidQuerySyntax = errors.New("invalid query syntax") - ErrInvalidAppName = errors.New("invalid application name") - ErrInvalidMatchersSyntax = errors.New("invalid tag matchers syntax") - ErrInvalidTagKey = errors.New("invalid tag key") - ErrInvalidTagValueSyntax = errors.New("invalid tag value syntax") - - ErrAppNameIsRequired = errors.New("application name is required") - ErrTagKeyIsRequired = errors.New("tag key is required") - ErrTagKeyReserved = errors.New("tag key is reserved") - - ErrMatchOperatorIsRequired = errors.New("match operator is required") - ErrUnknownOp = errors.New("unknown tag match operator") -) - -type Error struct { - Inner error - Expr string - // TODO: add offset? -} - -func newErr(err error, expr string) *Error { return &Error{Inner: err, Expr: expr} } - -func (e *Error) Error() string { return e.Inner.Error() + ": " + e.Expr } - -func (e *Error) Unwrap() error { return e.Inner } - -func newInvalidTagKeyRuneError(k string, r rune) *Error { - return newInvalidRuneError(ErrInvalidTagKey, k, r) -} - -func newInvalidAppNameRuneError(k string, r rune) *Error { - return newInvalidRuneError(ErrInvalidAppName, k, r) -} - -func newInvalidRuneError(err error, k string, r rune) *Error { - return newErr(err, fmt.Sprintf("%s: character is not allowed: %q", k, r)) -} diff --git a/pkg/og/flameql/flameql.go b/pkg/og/flameql/flameql.go deleted file mode 100644 index 94eb15c1af..0000000000 --- a/pkg/og/flameql/flameql.go +++ /dev/null @@ -1,114 +0,0 @@ -package flameql - -import "regexp" - -type Query struct { - AppName string - Matchers []*TagMatcher - - q string // The original query string. -} - -func (q *Query) String() string { return q.q } - -type TagMatcher struct { - Key string - Value string - Op - - R *regexp.Regexp -} - -type Op int - -const ( - // The order should respect operator priority and cost. - // Negating operators go first. See IsNegation. - _ Op = iota - OpNotEqual // != - OpNotEqualRegex // !~ - OpEqual // = - OpEqualRegex // =~ -) - -const ( - ReservedTagKeyName = "__name__" -) - -var reservedTagKeys = []string{ - ReservedTagKeyName, -} - -// IsNegation reports whether the operator assumes negation. -func (o Op) IsNegation() bool { return o < OpEqual } - -// ByPriority is a supplemental type for sorting tag matchers. -type ByPriority []*TagMatcher - -func (p ByPriority) Len() int { return len(p) } -func (p ByPriority) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -func (p ByPriority) Less(i, j int) bool { return p[i].Op < p[j].Op } - -func (m *TagMatcher) Match(v string) bool { - switch m.Op { - case OpEqual: - return m.Value == v - case OpNotEqual: - return m.Value != v - case OpEqualRegex: - return m.R.Match([]byte(v)) - case OpNotEqualRegex: - return !m.R.Match([]byte(v)) - default: - panic("invalid match operator") - } -} - -// ValidateTagKey report an error if the given key k violates constraints. -// -// The function should be used to validate user input. The function returns -// ErrTagKeyReserved if the key is valid but reserved for internal use. -func ValidateTagKey(k string) error { - if len(k) == 0 { - return ErrTagKeyIsRequired - } - for _, r := range k { - if !IsTagKeyRuneAllowed(r) { - return newInvalidTagKeyRuneError(k, r) - } - } - if IsTagKeyReserved(k) { - return newErr(ErrTagKeyReserved, k) - } - return nil -} - -// ValidateAppName report an error if the given app name n violates constraints. -func ValidateAppName(n string) error { - if len(n) == 0 { - return ErrAppNameIsRequired - } - for _, r := range n { - if !IsAppNameRuneAllowed(r) { - return newInvalidAppNameRuneError(n, r) - } - } - return nil -} - -func IsTagKeyRuneAllowed(r rune) bool { - return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' -} - -func IsAppNameRuneAllowed(r rune) bool { - return r == '-' || r == '.' || IsTagKeyRuneAllowed(r) -} - -func IsTagKeyReserved(k string) bool { - for _, s := range reservedTagKeys { - if s == k { - return true - } - } - return false -} diff --git a/pkg/og/flameql/flameql_suite_test.go b/pkg/og/flameql/flameql_suite_test.go deleted file mode 100644 index 2a7c6a060c..0000000000 --- a/pkg/og/flameql/flameql_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package flameql_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestParser(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "FlameQL Suite") -} diff --git a/pkg/og/flameql/flameql_test.go b/pkg/og/flameql/flameql_test.go deleted file mode 100644 index 15219eebae..0000000000 --- a/pkg/og/flameql/flameql_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package flameql - -import ( - "errors" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("TagMatcher", func() { - It("matches", func() { - type testCase struct { - matcher string - value string - matches bool - } - - testCases := []testCase{ - {`foo="bar"`, "bar", true}, - {`foo="bar"`, "baz", false}, - {`foo!="bar"`, "bar", false}, - {`foo!="bar"`, "baz", true}, - {`foo=~"bar"`, "bar", true}, - {`foo=~"bar"`, "baz", false}, - {`foo!~"bar"`, "bar", false}, - {`foo!~"bar"`, "baz", true}, - } - - for _, tc := range testCases { - m, err := ParseMatchers(tc.matcher) - Expect(err).ToNot(HaveOccurred()) - Expect(m[0].Match(tc.value)).To(Equal(tc.matches)) - } - }) -}) - -var _ = Describe("ValidateTagKey", func() { - It("reports error if a key violates constraints", func() { - type testCase struct { - key string - err error - } - - testCases := []testCase{ - {"foo_BAR_12_baz_qux", nil}, - - {ReservedTagKeyName, ErrTagKeyReserved}, - {"", ErrTagKeyIsRequired}, - {"#", ErrInvalidTagKey}, - } - - for _, tc := range testCases { - err := ValidateTagKey(tc.key) - if tc.err != nil { - Expect(errors.Is(err, tc.err)).To(BeTrue()) - continue - } - Expect(err).To(BeNil()) - } - }) -}) - -var _ = Describe("ValidateAppName", func() { - It("reports error if an app name violates constraints", func() { - type testCase struct { - appName string - err error - } - - testCases := []testCase{ - {"foo.BAR-1.2_baz_qux", nil}, - - {"", ErrAppNameIsRequired}, - {"#", ErrInvalidAppName}, - } - - for _, tc := range testCases { - err := ValidateAppName(tc.appName) - if tc.err != nil { - Expect(errors.Is(err, tc.err)).To(BeTrue()) - continue - } - Expect(err).To(BeNil()) - } - }) -}) diff --git a/pkg/og/flameql/parse.go b/pkg/og/flameql/parse.go deleted file mode 100644 index 282091ba06..0000000000 --- a/pkg/og/flameql/parse.go +++ /dev/null @@ -1,174 +0,0 @@ -package flameql - -import ( - "regexp" - "sort" - "strings" -) - -// ParseQuery parses a string of $app_name<{<$tag_matchers>}> form. -func ParseQuery(s string) (*Query, error) { - s = strings.TrimSpace(s) - q := Query{q: s} - - for offset, c := range s { - switch c { - case '{': - if offset == 0 { - return nil, ErrAppNameIsRequired - } - if s[len(s)-1] != '}' { - return nil, newErr(ErrInvalidQuerySyntax, "expected } at the end") - } - m, err := ParseMatchers(s[offset+1 : len(s)-1]) - if err != nil { - return nil, err - } - q.AppName = s[:offset] - q.Matchers = m - return &q, nil - default: - if !IsAppNameRuneAllowed(c) { - return nil, newErr(ErrInvalidAppName, s[:offset+1]) - } - } - } - - if len(s) == 0 { - return nil, ErrAppNameIsRequired - } - - q.AppName = s - return &q, nil -} - -// ParseMatchers parses a string of $tag_matcher<,$tag_matchers> form. -func ParseMatchers(s string) ([]*TagMatcher, error) { - var matchers []*TagMatcher - for _, t := range split(s) { - if t == "" { - continue - } - m, err := ParseMatcher(strings.TrimSpace(t)) - if err != nil { - return nil, err - } - matchers = append(matchers, m) - } - if len(matchers) == 0 && len(s) != 0 { - return nil, newErr(ErrInvalidMatchersSyntax, s) - } - sort.Sort(ByPriority(matchers)) - return matchers, nil -} - -// ParseMatcher parses a string of $tag_key$op"$tag_value" form, -// where $op is one of the supported match operators. -func ParseMatcher(s string) (*TagMatcher, error) { - var tm TagMatcher - var offset int - var c rune - -loop: - for offset, c = range s { - r := len(s) - (offset + 1) - switch c { - case '=': - switch { - case r <= 2: - return nil, newErr(ErrInvalidTagValueSyntax, s) - case s[offset+1] == '"': - tm.Op = OpEqual - case s[offset+1] == '~': - if r <= 3 { - return nil, newErr(ErrInvalidTagValueSyntax, s) - } - tm.Op = OpEqualRegex - default: - // Just for more meaningful error message. - if s[offset+2] != '"' { - return nil, newErr(ErrInvalidTagValueSyntax, s) - } - return nil, newErr(ErrUnknownOp, s) - } - break loop - case '!': - if r <= 3 { - return nil, newErr(ErrInvalidTagValueSyntax, s) - } - switch s[offset+1] { - case '=': - tm.Op = OpNotEqual - case '~': - tm.Op = OpNotEqualRegex - default: - return nil, newErr(ErrUnknownOp, s) - } - break loop - default: - if !IsTagKeyRuneAllowed(c) { - return nil, newInvalidTagKeyRuneError(s, c) - } - } - } - - k := s[:offset] - if IsTagKeyReserved(k) { - return nil, newErr(ErrTagKeyReserved, k) - } - - var v string - var ok bool - switch tm.Op { - default: - return nil, newErr(ErrMatchOperatorIsRequired, s) - case OpEqual: - v, ok = unquote(s[offset+1:]) - case OpNotEqual, OpEqualRegex, OpNotEqualRegex: - v, ok = unquote(s[offset+2:]) - } - if !ok { - return nil, newErr(ErrInvalidTagValueSyntax, v) - } - - // Compile regex, if applicable. - switch tm.Op { - case OpEqualRegex, OpNotEqualRegex: - r, err := regexp.Compile(v) - if err != nil { - return nil, newErr(err, v) - } - tm.R = r - } - - tm.Key = k - tm.Value = v - return &tm, nil -} - -func unquote(s string) (string, bool) { - if s[0] != '"' || s[len(s)-1] != '"' { - return s, false - } - return s[1 : len(s)-1], true -} - -func split(s string) []string { - var r []string - var x int - var y bool - for i := 0; i < len(s); i++ { - switch { - case s[i] == ',' && !y: - r = append(r, s[x:i]) - x = i + 1 - case s[i] == '"': - if y && i > 0 && s[i-1] != '\\' { - y = false - continue - } - y = true - } - } - return append(r, s[x:]) -} diff --git a/pkg/og/flameql/parse_test.go b/pkg/og/flameql/parse_test.go deleted file mode 100644 index 4ce3a7c52f..0000000000 --- a/pkg/og/flameql/parse_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package flameql - -import ( - "errors" - "regexp" - "regexp/syntax" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("ParseQuery", func() { - It("parses queries", func() { - type testCase struct { - query string - err error - q *Query - } - - testCases := []testCase{ - {`app.name`, nil, &Query{AppName: "app.name", q: `app.name`}}, - {`app.name{}`, nil, &Query{AppName: "app.name", q: `app.name{}`}}, - {`app.name{foo="bar"}`, nil, - &Query{"app.name", []*TagMatcher{{"foo", "bar", OpEqual, nil}}, `app.name{foo="bar"}`}}, - {`app.name{foo="bar,baz"}`, nil, - &Query{"app.name", []*TagMatcher{{"foo", "bar,baz", OpEqual, nil}}, `app.name{foo="bar,baz"}`}}, - {`app.name{foo="bar",baz!="quo"}`, nil, - &Query{"app.name", []*TagMatcher{{"baz", "quo", OpNotEqual, nil}, {"foo", "bar", OpEqual, nil}}, `app.name{foo="bar",baz!="quo"}`}}, - - {"", ErrAppNameIsRequired, nil}, - {"{}", ErrAppNameIsRequired, nil}, - {`app.name{,}`, ErrInvalidMatchersSyntax, nil}, - {`app.name[foo="bar"]`, ErrInvalidAppName, nil}, - {`app=name{}"`, ErrInvalidAppName, nil}, - {`app.name{foo="bar"`, ErrInvalidQuerySyntax, nil}, - {`app.name{__name__="foo"}`, ErrTagKeyReserved, nil}, - } - - for _, tc := range testCases { - q, err := ParseQuery(tc.query) - if tc.err != nil { - Expect(errors.Is(err, tc.err)).To(BeTrue()) - } else { - Expect(err).To(BeNil()) - } - Expect(q).To(Equal(tc.q)) - } - }) -}) - -var _ = Describe("ParseMatcher", func() { - It("parses tag matchers", func() { - type testCase struct { - expr string - err error - m *TagMatcher - } - - testCases := []testCase{ - {expr: `foo="bar"`, m: &TagMatcher{"foo", "bar", OpEqual, nil}}, - {expr: `foo="z"`, m: &TagMatcher{"foo", "z", OpEqual, nil}}, - {expr: `foo=""`, err: ErrInvalidTagValueSyntax}, - {expr: `foo="`, err: ErrInvalidTagValueSyntax}, - {expr: `foo="z`, err: ErrInvalidTagValueSyntax}, - {expr: `foo=`, err: ErrInvalidTagValueSyntax}, - - {expr: `foo!="bar"`, m: &TagMatcher{"foo", "bar", OpNotEqual, nil}}, - {expr: `foo!="z"`, m: &TagMatcher{"foo", "z", OpNotEqual, nil}}, - {expr: `foo=~""`, err: ErrInvalidTagValueSyntax}, - {expr: `foo=~"`, err: ErrInvalidTagValueSyntax}, - {expr: `foo=~"z`, err: ErrInvalidTagValueSyntax}, - {expr: `foo=~`, err: ErrInvalidTagValueSyntax}, - - {expr: `foo=~"bar"`, m: &TagMatcher{"foo", "bar", OpEqualRegex, nil}}, - {expr: `foo=~"z"`, m: &TagMatcher{"foo", "z", OpEqualRegex, nil}}, - {expr: `foo!=""`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!="`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!="z`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!=`, err: ErrInvalidTagValueSyntax}, - - {expr: `foo!~"bar"`, m: &TagMatcher{"foo", "bar", OpNotEqualRegex, nil}}, - {expr: `foo!~"z"`, m: &TagMatcher{"foo", "z", OpNotEqualRegex, nil}}, - {expr: `foo!~""`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!~"`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!~"z`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!~`, err: ErrInvalidTagValueSyntax}, - - {expr: `foo="bar,baz"`, m: &TagMatcher{"foo", "bar,baz", OpEqual, nil}}, - {expr: `foo="bar\",\"baz"`, m: &TagMatcher{"foo", "bar\\\",\\\"baz", OpEqual, nil}}, - - {expr: `foo;bar="baz"`, err: ErrInvalidTagKey}, - {expr: `foo""`, err: ErrInvalidTagKey}, - {expr: `foo`, err: ErrMatchOperatorIsRequired}, - {expr: `foo!`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!!`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!~@b@"`, err: ErrInvalidTagValueSyntax}, - {expr: `foo=bar`, err: ErrInvalidTagValueSyntax}, - {expr: `foo!"bar"`, err: ErrUnknownOp}, - {expr: `foo!!"bar"`, err: ErrUnknownOp}, - {expr: `foo=="bar"`, err: ErrUnknownOp}, - } - - for _, tc := range testCases { - tm, err := ParseMatcher(tc.expr) - if tc.err != nil { - Expect(errors.Is(err, tc.err)).To(BeTrue()) - } else { - Expect(err).To(BeNil()) - } - if tm != nil { - tm.R = nil - } - Expect(tm).To(Equal(tc.m)) - } - }) - - It("matchers are properly sorted by operator priority", func() { - m, err := ParseMatchers(`3="x",4=~"x",1!="x",2!~"x"`) - Expect(err).ToNot(HaveOccurred()) - x := regexp.MustCompile("x") - Expect(m).To(Equal([]*TagMatcher{ - {"1", "x", OpNotEqual, nil}, - {"2", "x", OpNotEqualRegex, x}, - {"3", "x", OpEqual, nil}, - {"4", "x", OpEqualRegex, x}, - })) - }) -}) - -var _ = Describe("ParseMatcherRegex", func() { - It("parses tag matchers with regex", func() { - m, err := ParseMatcher(`foo=~".*_suffix"`) - Expect(err).To(BeNil()) - Expect(m).ToNot(BeNil()) - - m, err = ParseMatcher(`foo=~"["`) - Expect(m).To(BeNil()) - Expect(err).ToNot(BeNil()) - - var e1 *syntax.Error - Expect(errors.As(err, &e1)).To(BeTrue()) - - var e2 *Error - Expect(errors.As(err, &e2)).To(BeTrue()) - }) -}) diff --git a/pkg/og/ingestion/ingestion.go b/pkg/og/ingestion/ingestion.go index ad859061a7..f84bf369fc 100644 --- a/pkg/og/ingestion/ingestion.go +++ b/pkg/og/ingestion/ingestion.go @@ -1,55 +1,61 @@ package ingestion import ( - "context" - "errors" - "time" + "context" + "errors" + "time" - distributormodel "github.com/grafana/pyroscope/pkg/distributor/model" + "github.com/grafana/pyroscope/api/model/labelset" + distributormodel "github.com/grafana/pyroscope/v2/pkg/distributor/model" - "github.com/grafana/pyroscope/pkg/og/storage" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/segment" + "github.com/grafana/pyroscope/v2/pkg/og/storage" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" ) type Ingester interface { - Ingest(context.Context, *IngestInput) error + Ingest(context.Context, *IngestInput) error } type IngestInput struct { - Format Format - Profile RawProfile - Metadata Metadata + Format Format + Profile RawProfile + Metadata Metadata } type Format string const ( - FormatPprof Format = "pprof" - FormatJFR Format = "jfr" - FormatTrie Format = "trie" - FormatTree Format = "tree" - FormatLines Format = "lines" - FormatGroups Format = "groups" - FormatSpeedscope Format = "speedscope" + FormatPprof Format = "pprof" + FormatJFR Format = "jfr" + FormatTrie Format = "trie" + FormatTree Format = "tree" + FormatLines Format = "lines" + FormatGroups Format = "groups" + FormatSpeedscope Format = "speedscope" ) type RawProfile interface { - Parse(context.Context, storage.Putter, storage.MetricsExporter, Metadata) error + Parse(context.Context, storage.Putter, storage.MetricsExporter, Metadata, Limits) error +} + +type Limits interface { + MaxProfileSizeBytes(tenantID string) int + MaxProfileSymbolValueLength(tenantID string) int + MaxProfileStacktraceSamples(tenantID string) int } type ParseableToPprof interface { - ParseToPprof(context.Context, Metadata) (*distributormodel.PushRequest, error) + ParseToPprof(context.Context, Metadata, Limits) (*distributormodel.PushRequest, error) } type Metadata struct { - StartTime time.Time - EndTime time.Time - Key *segment.Key - SpyName string - SampleRate uint32 - Units metadata.Units - AggregationType metadata.AggregationType + StartTime time.Time + EndTime time.Time + LabelSet *labelset.LabelSet + SpyName string + SampleRate uint32 + Units metadata.Units + AggregationType metadata.AggregationType } type Error struct{ Err error } @@ -59,9 +65,9 @@ func (e Error) Error() string { return e.Err.Error() } func (e Error) Unwrap() error { return e.Err } func IsIngestionError(err error) bool { - if err == nil { - return false - } - var v Error - return errors.As(err, &v) + if err == nil { + return false + } + var v Error + return errors.As(err, &v) } diff --git a/pkg/og/storage/dict/dict.go b/pkg/og/storage/dict/dict.go deleted file mode 100644 index 8ee395b240..0000000000 --- a/pkg/og/storage/dict/dict.go +++ /dev/null @@ -1,92 +0,0 @@ -package dict - -import ( - "bytes" - "io" - "sync" - - "github.com/grafana/pyroscope/pkg/og/util/varint" - "github.com/valyala/bytebufferpool" -) - -type ( - Key []byte - Value []byte -) - -func New() *Dict { - return &Dict{ - root: newTrieNode([]byte{}), - } -} - -type Dict struct { - m sync.RWMutex - root *trieNode -} - -func (t *Dict) GetValue(key Key, value io.Writer) bool { - t.m.RLock() - defer t.m.RUnlock() - return t.readValue(key, value) -} - -func (t *Dict) Get(key Key) (Value, bool) { - t.m.RLock() - defer t.m.RUnlock() - var labelBuf bytes.Buffer - if t.readValue(key, &labelBuf) { - return labelBuf.Bytes(), true - } - return nil, false -} - -func (t *Dict) readValue(key Key, w io.Writer) bool { - r := bytes.NewReader(key) - tn := t.root - for { - v, err := varint.Read(r) - if err != nil { - return true - } - if int(v) >= len(tn.children) { - return false - } - - label := tn.children[v].label - _, _ = w.Write(label) - tn = tn.children[v] - - expectedLen, _ := varint.Read(r) - for len(label) < int(expectedLen) { - if len(tn.children) == 0 { - return false - } - label2 := tn.children[0].label - _, _ = w.Write(label2) - expectedLen -= uint64(len(label2)) - tn = tn.children[0] - } - } -} - -var writerPool = sync.Pool{New: func() any { return varint.NewWriter() }} - -func (t *Dict) PutValue(val Value, dst io.Writer) { - t.m.Lock() - defer t.m.Unlock() - vw := writerPool.Get().(varint.Writer) - defer writerPool.Put(vw) - t.root.findNodeAt(val, vw, dst) -} - -var bufferPool bytebufferpool.Pool - -func (t *Dict) Put(val Value) Key { - b := bufferPool.Get() - defer bufferPool.Put(b) - t.PutValue(val, b) - k := make([]byte, b.Len()) - copy(k, b.B) - return k -} diff --git a/pkg/og/storage/dict/dict_suite_test.go b/pkg/og/storage/dict/dict_suite_test.go deleted file mode 100644 index 40c2cb6f41..0000000000 --- a/pkg/og/storage/dict/dict_suite_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package dict_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - testing2 "github.com/grafana/pyroscope/pkg/og/testing" -) - -func TestTdict(t *testing.T) { - testing2.SetupLogging() - - RegisterFailHandler(Fail) - RunSpecs(t, "Tdict Suite") -} diff --git a/pkg/og/storage/dict/dict_test.go b/pkg/og/storage/dict/dict_test.go deleted file mode 100644 index f6ac517f33..0000000000 --- a/pkg/og/storage/dict/dict_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package dict - -import ( - "math/rand" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -// TODO: DRY -func randStr() []byte { - buf := make([]byte, 10) - for i := 0; i < 10; i++ { - buf[i] = byte(97) + byte(rand.Uint32()%10) - } - return buf -} - -var _ = Describe("dict package", func() { - Context("Put / Get", func() { - Context("Puts same value twice", func() { - It("Get returns things Put puts in", func() { - dict := New() - k1 := dict.Put([]byte("foo")) - k2 := dict.Put([]byte("aff")) - k3 := dict.Put([]byte("aff")) - v1, _ := dict.Get(k1) - Expect(v1).To(BeEquivalentTo([]byte("foo"))) - v2, _ := dict.Get(k2) - Expect(v2).To(BeEquivalentTo([]byte("aff"))) - v3, _ := dict.Get(k3) - Expect(v3).To(BeEquivalentTo([]byte("aff"))) - }) - }) - - Context("Random strings", func() { - It("Get returns things Put puts in", func() { - dict := New() - insertedData := [][][]byte{} - for i := 0; i < 10000; i++ { - expected := randStr() - key := dict.Put(expected) - insertedData = append(insertedData, [][]byte{key, expected}) - actual, ok := dict.Get(key) - Expect(ok).To(BeTrue()) - Expect(actual).To(BeEquivalentTo(expected)) - } - - for _, pair := range insertedData { - key := pair[0] - expected := pair[1] - actual, ok := dict.Get(key) - Expect(ok).To(BeTrue()) - Expect(actual).To(BeEquivalentTo(expected)) - } - }) - }) - }) -}) diff --git a/pkg/og/storage/dict/serialize.go b/pkg/og/storage/dict/serialize.go deleted file mode 100644 index cf2d540f48..0000000000 --- a/pkg/og/storage/dict/serialize.go +++ /dev/null @@ -1,97 +0,0 @@ -package dict - -import ( - "bufio" - "bytes" - "io" - - "github.com/grafana/pyroscope/pkg/og/util/varint" -) - -// serialization format version. it's not very useful right now, but it will be in the future -const currentVersion = 1 - -func (t *Dict) Serialize(w io.Writer) error { - t.m.RLock() - defer t.m.RUnlock() - - _, err := varint.Write(w, currentVersion) - if err != nil { - return err - } - - nodes := []*trieNode{t.root} - for len(nodes) > 0 { - tn := nodes[0] - nodes = nodes[1:] - - label := tn.label - _, err := varint.Write(w, uint64(len(label))) - if err != nil { - return err - } - _, err = w.Write(label) - if err != nil { - return err - } - - _, err = varint.Write(w, uint64(len(tn.children))) - if err != nil { - return err - } - - nodes = append(tn.children, nodes...) - } - return nil -} - -func Deserialize(r io.Reader) (*Dict, error) { - t := New() - br := bufio.NewReader(r) // TODO if it's already a bytereader skip - - // reads serialization format version, see comment at the top - _, err := varint.Read(br) - if err != nil { - return nil, err - } - - parents := []*trieNode{t.root} - for len(parents) > 0 { - parent := parents[0] - parents = parents[1:] - - nameLen, err := varint.Read(br) - nameBuf := make([]byte, nameLen) // TODO: maybe there are better ways to do this? - _, err = io.ReadAtLeast(br, nameBuf, int(nameLen)) - if err != nil { - return nil, err - } - tn := newTrieNode(nameBuf) - parent.insert(tn) - - childrenLen, err := varint.Read(br) - if err != nil { - return nil, err - } - - for i := uint64(0); i < childrenLen; i++ { - parents = append([]*trieNode{tn}, parents...) - } - } - - t.root = t.root.children[0] - - return t, nil -} - -func (t *Dict) Bytes() ([]byte, error) { - b := bytes.Buffer{} - if err := t.Serialize(&b); err != nil { - return nil, err - } - return b.Bytes(), nil -} - -func FromBytes(p []byte) (*Dict, error) { - return Deserialize(bytes.NewReader(p)) -} diff --git a/pkg/og/storage/dict/serialize_test.go b/pkg/og/storage/dict/serialize_test.go deleted file mode 100644 index e8f3c1e50c..0000000000 --- a/pkg/og/storage/dict/serialize_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package dict - -import ( - "bytes" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var serialized = []byte("\x01\x00\x02\x03foo\x01\x03bar\x00\x03bar\x00") - -var _ = Describe("dict", func() { - Describe("Serialize", func() { - It("returns correct results", func() { - dict := New() - Expect(dict.Put(Value("foo"))).To(Equal(Key{0, 3})) - Expect(dict.Put(Value("bar"))).To(Equal(Key{1, 3})) - Expect(dict.Put(Value("foobar"))).To(Equal(Key{0, 3, 0, 3})) - - var b bytes.Buffer - dict.Serialize(&b) - Expect(b.Bytes()).To(Equal(serialized)) - }) - }) - - Describe("Deserialize", func() { - // TODO: add a case with a real dictionary - It("returns correct results", func() { - r := bytes.NewReader(serialized) - d, err := Deserialize(r) - Expect(err).ToNot(HaveOccurred()) - v1, _ := d.Get(Key{0, 3}) - Expect(v1).To(Equal(Value("foo"))) - v2, _ := d.Get(Key{1, 3}) - Expect(v2).To(Equal(Value("bar"))) - v3, _ := d.Get(Key{0, 3, 0, 3}) - Expect(v3).To(Equal(Value("foobar"))) - }) - }) -}) diff --git a/pkg/og/storage/dict/trie.go b/pkg/og/storage/dict/trie.go deleted file mode 100644 index a00663af46..0000000000 --- a/pkg/og/storage/dict/trie.go +++ /dev/null @@ -1,125 +0,0 @@ -package dict - -import ( - "bytes" - "io" - - "github.com/grafana/pyroscope/pkg/og/util/varint" -) - -// this implementation is a copy of another trie implementation in this repo -// albeit slightly different -// TODO: maybe dedup them -type trieNode struct { - label []byte - children []*trieNode -} - -func newTrieNode(label []byte) *trieNode { - return &trieNode{ - label: label, - children: make([]*trieNode, 0), - } -} - -func (tn *trieNode) insert(t2 *trieNode) { - tn.children = append(tn.children, t2) -} - -// TODO: too complicated, need to refactor / document this -func (tn *trieNode) findNodeAt(key []byte, vw varint.Writer, w io.Writer) { - // log.Debug("findNodeAt") - key2 := make([]byte, len(key)) - // TODO: remove - copy(key2, key) - key = key2 - -OuterLoop: - for { - // log.Debug("findNodeAt, key", string(key)) - - if len(key) == 0 { - // fn(tn) - return - } - - // 4 options: - // trie: - // foo -> bar - // 1) no leads (baz) - // create a new child, call fn with it - // 2) lead, key matches (foo) - // call fn with existing child - // 3) lead, key matches, shorter (fo / fop) - // split existing child, set that as tn - // 4) lead, key matches, longer (fooo) - // go to existing child, set that as tn - - leadIndex := -1 - for k, v := range tn.children { - if v.label[0] == key[0] { - leadIndex = k - } - } - - if leadIndex == -1 { // 1 - // log.Debug("case 1") - newTn := newTrieNode(key) - tn.insert(newTn) - i := len(tn.children) - 1 - vw.Write(w, uint64(i)) - vw.Write(w, uint64(len(key))) - // fn(newTn) - return - } - - leadKey := tn.children[leadIndex].label - // log.Debug("lead key", string(leadKey)) - lk := len(key) - llk := len(leadKey) - for i := 0; i < lk; i++ { - if i == llk { // 4 fooo / foo i = 3 llk = 3 - // log.Debug("case 4") - tn = tn.children[leadIndex] - key = key[llk:] - vw.Write(w, uint64(leadIndex)) - vw.Write(w, uint64(llk)) - continue OuterLoop - } - if leadKey[i] != key[i] { // 3 - a := leadKey[:i] // ab - b := leadKey[i:] // c - newTn := newTrieNode(a) - newTn.children = []*trieNode{tn.children[leadIndex]} - tn.children[leadIndex].label = b - tn.children[leadIndex] = newTn - tn = newTn - key = key[i:] - - vw.Write(w, uint64(leadIndex)) - vw.Write(w, uint64(i)) - continue OuterLoop - } - } - // lk < llk - if !bytes.Equal(key, leadKey) { // 3 - a := leadKey[:lk] // ab - b := leadKey[lk:] // c - newTn := newTrieNode(a) - newTn.children = []*trieNode{tn.children[leadIndex]} - tn.children[leadIndex].label = b - tn.children[leadIndex] = newTn - tn = newTn - key = key[lk:] - - vw.Write(w, uint64(leadIndex)) - vw.Write(w, uint64(lk)) - continue OuterLoop - } - - // 2 - vw.Write(w, uint64(leadIndex)) - vw.Write(w, uint64(len(leadKey))) - return - } -} diff --git a/pkg/og/storage/segment/debug_vis.go b/pkg/og/storage/segment/debug_vis.go deleted file mode 100644 index c206ca1fae..0000000000 --- a/pkg/og/storage/segment/debug_vis.go +++ /dev/null @@ -1,145 +0,0 @@ -package segment - -import ( - "encoding/json" - "math/big" - "os" - "text/template" - "time" -) - -var visDebuggingEnabled = false - -type visualizeNode2 struct { - T1 time.Time - T2 time.Time - Depth int - HasTrie bool - Samples uint64 - M int - D int - Used bool -} - -type vis struct { - nodes []*visualizeNode2 -} - -// This is here for debugging -func newVis() *vis { - return &vis{nodes: []*visualizeNode2{}} -} - -func (v *vis) add(n *streeNode, r *big.Rat, used bool) { - if !visDebuggingEnabled { - return - } - v.nodes = append(v.nodes, &visualizeNode2{ - T1: n.time.UTC(), - T2: n.time.Add(durations[n.depth]).UTC(), - Depth: n.depth, - HasTrie: n.present, - Samples: n.samples, - M: int(r.Num().Int64()), - D: int(r.Denom().Int64()), - Used: used, - }) -} - -type TmpltVars struct { - Data string -} - -func (v *vis) print(name string) { - if !visDebuggingEnabled { - return - } - vizTmplt, _ := template.New("viz").Parse(vizTmplt) - - jsonBytes, _ := json.MarshalIndent(v.nodes, "", " ") - jsonStr := string(jsonBytes) - w, _ := os.Create(name) - vizTmplt.Execute(w, TmpltVars{Data: jsonStr}) -} - -var vizTmplt = ` - - - - - - - - - -
- - - -` diff --git a/pkg/og/storage/segment/fuzz_test.go b/pkg/og/storage/segment/fuzz_test.go deleted file mode 100644 index 3df605eb56..0000000000 --- a/pkg/og/storage/segment/fuzz_test.go +++ /dev/null @@ -1,280 +0,0 @@ -package segment - -import ( - "log" - "math/big" - "math/rand" - "sync" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/grafana/pyroscope/pkg/og/testing" -) - -type datapoint struct { - t time.Time - samples uint64 - r *big.Rat -} - -type storageMock struct { - resolution time.Duration - data []datapoint -} - -func newMock(resolution time.Duration) *storageMock { - return &storageMock{ - resolution: resolution, - data: []datapoint{}, - } -} - -func (sm *storageMock) Put(st, et time.Time, samples uint64) { - st, et = normalize(st, et) - fullDur := et.Sub(st) / sm.resolution - for t := st; t.Before(et); t = t.Add(sm.resolution) { - d := datapoint{ - t: t, - samples: samples, - r: big.NewRat(int64(samples), int64(fullDur)), - } - - sm.data = append(sm.data, d) - } -} - -func (sm *storageMock) Get(st, et time.Time, cb func(depth int, samples, writes uint64, t time.Time, r *big.Rat)) { - st, et = normalize(st, et) - for _, d := range sm.data { - if !d.t.Before(st) && !d.t.Add(sm.resolution).After(et) { - cb(0, 1, 1, d.t, d.r) - } - } -} - -// if you change something in this test make sure it doesn't change test coverage. -func fuzzTest(testWrites bool, writeSize func() int) { - s := New() - m := newMock(10 * time.Second) - - r := rand.New(rand.NewSource(1213)) - - for k := 0; k < 20; k++ { - maxStartTime := r.Intn(5000) - // for i := 0; i < 10; i++ { - for i := 0; i < r.Intn(200); i++ { - sti := r.Intn(maxStartTime) * 10 - st := testing.SimpleTime(sti) - et := testing.SimpleTime(sti + writeSize()) - dur := et.Sub(st) - - // samples := uint64(1+r.Intn(10)) * uint64(dur/(10*time.Second)) - samples := uint64(20) - - m.Put(st, et, samples) - s.Put(st, et, samples, func(depth int, t time.Time, r *big.Rat, addons []Addon) { - log.Println(depth, r, dur) - }) - } - mSum := big.NewRat(0, 1) - mWrites := big.NewRat(0, 1) - sSum := big.NewRat(0, 1) - sWrites := big.NewRat(0, 1) - for i := 0; i < r.Intn(100); i++ { - sti := r.Intn(100) * 10 - st := testing.SimpleTime(sti) - et := testing.SimpleTime(sti + r.Intn(100)*10) - - m.Get(st, et, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) { - rClone := big.NewRat(r.Num().Int64(), r.Denom().Int64()) - mSum.Add(mSum, rClone.Mul(rClone, big.NewRat(int64(samples), 1))) - log.Println("mWrites", samples, writes, r) - // if r.Num().Int64() > 0 { - // r = r.Inv(r) - w := big.NewRat(int64(writes), 1) - // mWrites.Add(mWrites, r.Mul(r, w)) - mWrites.Add(mWrites, w) - // } - }) - - s.Get(st, et, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) { - rClone := big.NewRat(r.Num().Int64(), r.Denom().Int64()) - sSum.Add(sSum, rClone.Mul(rClone, big.NewRat(int64(samples), 1))) - log.Println("sWrites", samples, writes, r) - // if r.Num().Int64() > 0 { - // r = r.Inv(r) - w := big.NewRat(int64(writes), 1) - // sWrites.Add(sWrites, r.Mul(r, w)) - sWrites.Add(sWrites, w) - // } - }) - } - mSumF, _ := mSum.Float64() - mWritesF, _ := mWrites.Float64() - log.Println("m:", mSum, mSumF, mWrites, mWritesF) - - sSumF, _ := sSum.Float64() - sWritesF, _ := sWrites.Float64() - log.Println("s:", sSum, sSumF, sWrites, sWritesF) - - Expect(mSum.Cmp(sSum)).To(Equal(0)) - if testWrites { - Expect(mWrites.Cmp(sWrites)).To(Equal(0)) - } - } -} - -// See https://github.com/pyroscope-io/pyroscope/issues/28 for more context -var _ = Describe("segment", func() { - Context("fuzz tests", func() { - Context("writes are 10 second long", func() { - It("works as expected", func() { - done := make(chan interface{}) - go func() { - fuzzTest(true, func() int { - return 10 - }) - close(done) - }() - Eventually(done, 5).Should(BeClosed()) - }) - }) - Context("writes are different lengths", func() { - It("works as expected", func() { - done := make(chan interface{}) - go func() { - fuzzTest(false, func() int { - return 20 - // return 1 + rand.Intn(10)*10 - }) - close(done) - }() - Eventually(done, 5).Should(BeClosed()) - }) - }) - Context("retention and sampling randomized test", func() { - It("works as expected", func() { - var ( - seed = 7332 - n = 1 - wg sync.WaitGroup - ) - wg.Add(n) - for i := 0; i < n; i++ { - go func(i int) { - fuzzDeleteNodesBefore(seed + i) - wg.Done() - }(i) - } - wg.Wait() - }) - }) - }) -}) - -func fuzzDeleteNodesBefore(seed int) { - defer GinkgoRecover() - - s := New() - r := rand.New(rand.NewSource(int64(seed))) - w := testSegWriter{ - n: 10e3, // Number of writes - r: r, - - samplesPerWrite: 100, - writeTimeSpanSec: 10, - startTimeMin: randInt(1000, 3000), - startTimeMax: randInt(7000, 100000), - - buckets: make([]*bucket, 10), - } - - w.write(s) - - for _, b := range w.buckets { - // Delete samples that fall within the time span of the bucket. - removed, err := s.DeleteNodesBefore(&RetentionPolicy{AbsoluteTime: b.time}) - Expect(err).ToNot(HaveOccurred()) - Expect(removed).To(BeFalse()) - // Ensure we have removed expected number of samples from the segment. - samples, writes := totalSamplesWrites(s, time.Time{}, testing.SimpleTime(w.startTimeMax*10)) - Expect(samples).To(Equal(b.samples)) - Expect(writes).To(Equal(b.writes)) - // Ensure no samples left outside the retention period. - samples, writes = totalSamplesWrites(s, b.time, testing.SimpleTime(w.startTimeMax*10)) - Expect(samples).To(Equal(b.samples)) - Expect(writes).To(Equal(b.writes)) - } - - st := testing.SimpleTime(w.startTimeMax * 10) - samples, writes := totalSamplesWrites(s, st, st.Add(time.Hour)) - Expect(samples).To(BeZero()) - Expect(writes).To(BeZero()) -} - -// testSegWriter inserts randomized data into the segment recording the -// samples distribution by time. Every bucket indicates the number of -// writes and samples that had been written before the bucket time mark. -type testSegWriter struct { - r *rand.Rand - n int - - samplesPerWrite int - writeTimeSpanSec int - expectedWrites int - - startTimeMin int - startTimeMax int - - buckets []*bucket -} - -type bucket struct { - time time.Time - samples int - writes int -} - -func (f testSegWriter) putStartEndTime() (st time.Time, et time.Time) { - st = testing.SimpleTime(randInt(f.startTimeMin, f.startTimeMax) * 10) - et = st.Add(time.Second * time.Duration(f.writeTimeSpanSec)) - return st, et -} - -func randInt(min, max int) int { return rand.Intn(max-min) + min } - -func (f testSegWriter) expectedSamples() int { return f.n * f.samplesPerWrite } - -func (f testSegWriter) write(s *Segment) { - // Initialize time buckets, if required: the whole time - // span is divided proportionally to the number of buckets. - if len(f.buckets) > 0 { - step := (f.startTimeMax - f.startTimeMin) / len(f.buckets) * 10 - for i := 0; i < len(f.buckets); i++ { - f.buckets[i] = &bucket{time: testing.SimpleTime(f.startTimeMin + step*i)} - } - } - for i := 0; i < f.n; i++ { - st, et := f.putStartEndTime() - err := s.Put(st, et, uint64(f.samplesPerWrite), putNoOp) - Expect(err).ToNot(HaveOccurred()) - for _, b := range f.buckets { - if et.After(b.time) { - b.samples += f.samplesPerWrite - b.writes++ - } - } - } -} - -func totalSamplesWrites(s *Segment, st, et time.Time) (samples, writes int) { - v := big.NewRat(0, 1) - s.Get(st, et, func(depth int, s, w uint64, t time.Time, r *big.Rat) { - x := big.NewRat(r.Num().Int64(), r.Denom().Int64()) - v.Add(v, x.Mul(x, big.NewRat(int64(s), 1))) - writes += int(w) - }) - return int(v.Num().Int64()), writes -} diff --git a/pkg/og/storage/segment/key.go b/pkg/og/storage/segment/key.go deleted file mode 100644 index a273297048..0000000000 --- a/pkg/og/storage/segment/key.go +++ /dev/null @@ -1,281 +0,0 @@ -package segment - -import ( - "bytes" - "errors" - "strconv" - "strings" - "sync" - "time" - - "github.com/grafana/pyroscope/pkg/og/flameql" - "github.com/grafana/pyroscope/pkg/og/structs/sortedmap" -) - -// TODO(kolesnikovae): -// Rename tags to labels -// Segment key -> LabelSet -// Segment key to be moved to /model package -// FlameQL to be split. - -type Key struct { - labels map[string]string -} - -type ParserState int - -const ( - nameParserState ParserState = iota - tagKeyParserState - tagValueParserState - doneParserState -) - -func NewKey(labels map[string]string) *Key { return &Key{labels: labels} } - -func ParseKey(name string) (*Key, error) { - k := &Key{labels: make(map[string]string)} - p := parserPool.Get().(*parser) - defer parserPool.Put(p) - p.reset() - var err error - for _, r := range name + "{" { - switch p.parserState { - case nameParserState: - err = p.nameParserCase(r, k) - case tagKeyParserState: - p.tagKeyParserCase(r) - case tagValueParserState: - err = p.tagValueParserCase(r, k) - } - if err != nil { - return nil, err - } - } - return k, nil -} - -func ValidateKey(k *Key) error { - if k == nil { - return flameql.ErrInvalidTagKey - } - - for key, v := range k.labels { - if key == "__name__" { - if err := flameql.ValidateAppName(v); err != nil { - return err - } - } else { - if err := flameql.ValidateTagKey(key); err != nil { - return err - } - } - } - return nil -} - -type parser struct { - parserState ParserState - key *bytes.Buffer - value *bytes.Buffer -} - -var parserPool = sync.Pool{ - New: func() any { - return &parser{ - parserState: nameParserState, - key: new(bytes.Buffer), - value: new(bytes.Buffer), - } - }, -} - -func (p *parser) reset() { - p.parserState = nameParserState - p.key.Reset() - p.value.Reset() -} - -// ParseKey's nameParserState switch case -func (p *parser) nameParserCase(r int32, k *Key) error { - switch r { - case '{': - p.parserState = tagKeyParserState - appName := strings.TrimSpace(p.value.String()) - if err := flameql.ValidateAppName(appName); err != nil { - return err - } - k.labels["__name__"] = appName - default: - p.value.WriteRune(r) - } - return nil -} - -// ParseKey's tagKeyParserState switch case -func (p *parser) tagKeyParserCase(r rune) { - switch r { - case '}': - p.parserState = doneParserState - case '=': - p.parserState = tagValueParserState - p.value.Reset() - default: - p.key.WriteRune(r) - } -} - -// ParseKey's tagValueParserState switch case -func (p *parser) tagValueParserCase(r rune, k *Key) error { - switch r { - case ',', '}': - p.parserState = tagKeyParserState - key := strings.TrimSpace(p.key.String()) - if !flameql.IsTagKeyReserved(key) { - if err := flameql.ValidateTagKey(key); err != nil { - return err - } - } - k.labels[key] = strings.TrimSpace(p.value.String()) - p.key.Reset() - default: - p.value.WriteRune(r) - } - return nil -} - -func (k *Key) SegmentKey() string { - return k.Normalized() -} - -const ProfileIDLabelName = "profile_id" - -func (k *Key) HasProfileID() bool { - v, ok := k.labels[ProfileIDLabelName] - return ok && v != "" -} - -func (k *Key) ProfileID() (string, bool) { - id, ok := k.labels[ProfileIDLabelName] - return id, ok -} - -func AppSegmentKey(appName string) string { return appName + "{}" } - -func TreeKey(k string, depth int, unixTime int64) string { - return k + ":" + strconv.Itoa(depth) + ":" + strconv.FormatInt(unixTime, 10) -} - -func (k *Key) TreeKey(depth int, t time.Time) string { - return TreeKey(k.Normalized(), depth, t.Unix()) -} - -var errKeyInvalid = errors.New("invalid key") - -// ParseTreeKey retrieves tree time and depth level from the given key. -func ParseTreeKey(k string) (time.Time, int, error) { - a := strings.Split(k, ":") - if len(a) < 3 { - return time.Time{}, 0, errKeyInvalid - } - level, err := strconv.Atoi(a[1]) - if err != nil { - return time.Time{}, 0, err - } - v, err := strconv.Atoi(a[2]) - if err != nil { - return time.Time{}, 0, err - } - return time.Unix(int64(v), 0), level, err -} - -func (k *Key) DictKey() string { - return k.labels["__name__"] -} - -// FromTreeToDictKey returns app name from tree key k: given tree key -// "foo{}:0:1234567890", the call returns "foo". -// -// Before tags support, segment key form (i.e. app name + tags: foo{key=value}) -// has been used to reference a dictionary (trie). -func FromTreeToDictKey(k string) string { - return k[0:strings.IndexAny(k, "{")] -} - -func (k *Key) Normalized() string { - var sb strings.Builder - - sortedMap := sortedmap.New() - for k, v := range k.labels { - if k == "__name__" { - sb.WriteString(v) - } else { - sortedMap.Put(k, v) - } - } - - sb.WriteString("{") - for i, k := range sortedMap.Keys() { - v := sortedMap.Get(k).(string) - if i != 0 { - sb.WriteString(",") - } - sb.WriteString(k) - sb.WriteString("=") - sb.WriteString(v) - } - sb.WriteString("}") - - return sb.String() -} - -func (k *Key) Clone() *Key { - newMap := make(map[string]string) - for k, v := range k.labels { - newMap[k] = v - } - return &Key{labels: newMap} -} - -func (k *Key) AppName() string { - return k.labels["__name__"] -} - -func (k *Key) Labels() map[string]string { - return k.labels -} - -func (k *Key) Add(key, value string) { - if value == "" { - delete(k.labels, key) - } else { - k.labels[key] = value - } -} - -// Match reports whether the key matches the query. -func (k *Key) Match(q *flameql.Query) bool { - if k.AppName() != q.AppName { - return false - } - for _, m := range q.Matchers { - var ok bool - for labelKey, labelValue := range k.labels { - if m.Key != labelKey { - continue - } - if m.Match(labelValue) { - if !m.IsNegation() { - ok = true - break - } - } else if m.IsNegation() { - return false - } - } - if !ok && !m.IsNegation() { - return false - } - } - return true -} diff --git a/pkg/og/storage/segment/key_bech_test.go b/pkg/og/storage/segment/key_bech_test.go deleted file mode 100644 index b254b1c0e0..0000000000 --- a/pkg/og/storage/segment/key_bech_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package segment - -import ( - "math/rand" - "testing" -) - -func BenchmarkKey_Parse(b *testing.B) { - const ( - labelsSize = 10 - minLen = 6 - maxLen = 16 - ) - - // Duplicates are okay. - labels := make(map[string]string, labelsSize+1) - for i := 0; i < labelsSize; i++ { - labels[randString(randInt(minLen, maxLen))] = randString(randInt(minLen, maxLen)) - } - - labels["__name__"] = "benchmark.key.parse" - keyStr := NewKey(labels).Normalized() - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - if _, err := ParseKey(keyStr); err != nil { - b.Fatal(err) - } - } -} - -// TODO(kolesnikovae): This is not near perfect way of generating strings. -// It makes sense to create a package for util functions like this. - -const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - -func randString(n int) string { - b := make([]byte, n) - for i := range b { - b[i] = letterBytes[rand.Intn(len(letterBytes))] - } - return string(b) -} diff --git a/pkg/og/storage/segment/key_test.go b/pkg/og/storage/segment/key_test.go deleted file mode 100644 index e5f6d8cedc..0000000000 --- a/pkg/og/storage/segment/key_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package segment - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/grafana/pyroscope/pkg/og/flameql" -) - -var _ = Describe("segment key", func() { - Context("ParseKey", func() { - It("no tags version works", func() { - k, err := ParseKey("foo") - Expect(err).ToNot(HaveOccurred()) - Expect(k.labels).To(Equal(map[string]string{"__name__": "foo"})) - }) - - It("simple values work", func() { - k, err := ParseKey("foo{bar=1,baz=2}") - Expect(err).ToNot(HaveOccurred()) - Expect(k.labels).To(Equal(map[string]string{"__name__": "foo", "bar": "1", "baz": "2"})) - }) - - It("simple values with spaces work", func() { - k, err := ParseKey(" foo { bar = 1 , baz = 2 } ") - Expect(err).ToNot(HaveOccurred()) - Expect(k.labels).To(Equal(map[string]string{"__name__": "foo", "bar": "1", "baz": "2"})) - }) - }) - - Context("Key", func() { - Context("Normalize", func() { - It("no tags version works", func() { - k, err := ParseKey("foo") - Expect(err).ToNot(HaveOccurred()) - Expect(k.Normalized()).To(Equal("foo{}")) - }) - - It("simple values work", func() { - k, err := ParseKey("foo{bar=1,baz=2}") - Expect(err).ToNot(HaveOccurred()) - Expect(k.Normalized()).To(Equal("foo{bar=1,baz=2}")) - }) - - It("unsorted values work", func() { - k, err := ParseKey("foo{baz=1,bar=2}") - Expect(err).ToNot(HaveOccurred()) - Expect(k.Normalized()).To(Equal("foo{bar=2,baz=1}")) - }) - }) - }) - - Context("Key", func() { - Context("Match", func() { - It("reports whether a segments key satisfies tag matchers", func() { - type evalTestCase struct { - query string - match bool - key string - } - - testCases := []evalTestCase{ - // No matchers specified except app name. - {`app.name`, true, `app.name{foo=bar}`}, - {`app.name{}`, true, `app.name{foo=bar}`}, - {`app.name`, false, `x.name{foo=bar}`}, - {`app.name{}`, false, `x.name{foo=bar}`}, - - {`app.name{foo="bar"}`, true, `app.name{foo=bar}`}, - {`app.name{foo!="bar"}`, true, `app.name{foo=baz}`}, - {`app.name{foo="bar"}`, false, `app.name{foo=baz}`}, - {`app.name{foo!="bar"}`, false, `app.name{foo=bar}`}, - - // Tag key not present. - {`app.name{foo="bar"}`, false, `app.name{bar=baz}`}, - {`app.name{foo!="bar"}`, true, `app.name{bar=baz}`}, - - {`app.name{foo="bar",baz="qux"}`, true, `app.name{foo=bar,baz=qux}`}, - {`app.name{foo="bar",baz!="qux"}`, true, `app.name{foo=bar,baz=fred}`}, - {`app.name{foo="bar",baz="qux"}`, false, `app.name{foo=bar}`}, - {`app.name{foo="bar",baz!="qux"}`, false, `app.name{foo=bar,baz=qux}`}, - {`app.name{foo="bar",baz!="qux"}`, false, `app.name{baz=fred,bar=baz}`}, - } - - for _, tc := range testCases { - qry, _ := flameql.ParseQuery(tc.query) - k, _ := ParseKey(tc.key) - if matched := k.Match(qry); matched != tc.match { - Expect(matched).To(Equal(tc.match), tc.query, tc.key) - } - } - }) - }) - }) -}) diff --git a/pkg/og/storage/segment/overlap.go b/pkg/og/storage/segment/overlap.go deleted file mode 100644 index 53d300f078..0000000000 --- a/pkg/og/storage/segment/overlap.go +++ /dev/null @@ -1,48 +0,0 @@ -package segment - -import ( - "math/big" - "time" -) - -func tmin(a, b time.Time) time.Time { - if a.Before(b) { - return a - } - return b -} - -func tmax(a, b time.Time) time.Time { - if a.After(b) { - return a - } - return b -} - -func dmax(a, b time.Duration) time.Duration { - if a > b { - return a - } - return b -} - -// relationship overlap read overlap write -// inside rel = iota // | S E | <1 1/1 -// match // matching ranges 1/1 1/1 -// outside // | | S E 0/1 0/1 -// overlap // | S | E <1 <1 -// contain // S | | E 1/1 <1 - -// t1, t2 represent segment node, st, et represent the read query time range -func overlapRead(t1, t2, st, et time.Time, dur time.Duration) *big.Rat { - m := int64(dmax(0, tmin(t2, et).Sub(tmax(t1, st))) / dur) - d := int64(t2.Sub(t1) / dur) - return big.NewRat(m, d) -} - -// t1, t2 represent segment node, st, et represent the write query time range -func overlapWrite(t1, t2, st, et time.Time, dur time.Duration) *big.Rat { - m := int64(dmax(0, tmin(t2, et).Sub(tmax(t1, st))) / dur) - d := int64(et.Sub(st) / dur) - return big.NewRat(m, d) -} diff --git a/pkg/og/storage/segment/overlap_test.go b/pkg/og/storage/segment/overlap_test.go deleted file mode 100644 index 8e2c2837e3..0000000000 --- a/pkg/og/storage/segment/overlap_test.go +++ /dev/null @@ -1,195 +0,0 @@ -package segment - -import ( - "math/big" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/grafana/pyroscope/pkg/og/testing" -) - -// relationship overlap read overlap write -// inside rel = iota // | S E | <1 1/1 -// match // matching ranges 1/1 1/1 -// outside // | | S E 0/1 0/1 -// overlap // | S | E <1 <1 -// contain // S | | E 1/1 <1 - -var _ = Describe("segment", func() { - Context("overlapRead", func() { - Context("match", func() { - It("returns correct values", func() { - Expect(overlapRead( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(0), testing.SimpleTime(100), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - }) - }) - Context("inside", func() { - It("returns correct values", func() { - Expect(overlapRead( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(10), testing.SimpleTime(90), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(8, 10).String())) - Expect(overlapRead( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(0), testing.SimpleTime(90), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(9, 10).String())) - Expect(overlapRead( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(10), testing.SimpleTime(100), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(9, 10).String())) - }) - }) - Context("contain", func() { - It("returns correct values", func() { - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(100), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(200), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - }) - }) - Context("overlap", func() { - It("returns correct values", func() { - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(110), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 10).String())) - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(190), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 10).String())) - }) - }) - Context("outside", func() { - It("returns correct values", func() { - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(100), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(80), testing.SimpleTime(90), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(200), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - Expect(overlapRead( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(210), testing.SimpleTime(220), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - }) - }) - }) - - Context("overlapWrite", func() { - Context("match", func() { - It("returns correct values", func() { - Expect(overlapWrite( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(0), testing.SimpleTime(100), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - }) - }) - Context("inside", func() { - It("returns correct values", func() { - Expect(overlapWrite( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(10), testing.SimpleTime(90), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - Expect(overlapWrite( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(0), testing.SimpleTime(90), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - Expect(overlapWrite( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(10), testing.SimpleTime(100), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 1).String())) - }) - }) - Context("contain", func() { - It("returns correct values", func() { - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(10, 12).String())) - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(100), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(10, 11).String())) - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(200), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(10, 11).String())) - }) - }) - Context("overlap", func() { - It("returns correct values", func() { - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(110), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 2).String())) - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(190), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(1, 2).String())) - }) - }) - Context("outside", func() { - It("returns correct values", func() { - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(100), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(80), testing.SimpleTime(90), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(200), testing.SimpleTime(210), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - Expect(overlapWrite( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(210), testing.SimpleTime(220), // st et - 10*time.Second, - ).String()).To(Equal(big.NewRat(0, 1).String())) - }) - }) - }) -}) diff --git a/pkg/og/storage/segment/relationship.go b/pkg/og/storage/segment/relationship.go deleted file mode 100644 index 627d6f5674..0000000000 --- a/pkg/og/storage/segment/relationship.go +++ /dev/null @@ -1,53 +0,0 @@ -package segment - -import ( - "time" -) - -type rel int - -const ( - // relationship overlap read overlap write - inside rel = iota // | S E | <1 1/1 - match // matching ranges 1/1 1/1 - outside // | | S E 0/1 0/1 - overlap // | S | E <1 <1 - contain // S | | E 1/1 <1 -) - -var overlapStrings map[rel]string - -// TODO: I bet there's a better way -func init() { - overlapStrings = make(map[rel]string) - overlapStrings[inside] = "inside" - overlapStrings[outside] = "outside" - overlapStrings[match] = "match" - overlapStrings[overlap] = "overlap" - overlapStrings[contain] = "contain" -} - -func (r rel) String() string { - return overlapStrings[r] -} - -// t1, t2 represent segment node, st, et represent the read/write query time range -func relationship(t1, t2, st, et time.Time) rel { - if t1.Equal(st) && t2.Equal(et) { - return match - } - if !t1.After(st) && !t2.Before(et) { - return inside - } - if !t1.Before(st) && !t2.After(et) { - return contain - } - if !t1.After(st) && !t2.After(st) { - return outside - } - if !t1.Before(et) && !t2.Before(et) { - return outside - } - - return overlap -} diff --git a/pkg/og/storage/segment/relationship_test.go b/pkg/og/storage/segment/relationship_test.go deleted file mode 100644 index d03137a5f3..0000000000 --- a/pkg/og/storage/segment/relationship_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package segment - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/grafana/pyroscope/pkg/og/testing" -) - -// relationship overlap read overlap write -// inside rel = iota // | S E | <1 1/1 -// match // matching ranges 1/1 1/1 -// outside // | | S E 0/1 0/1 -// overlap // | S | E <1 <1 -// contain // S | | E 1/1 <1 - -var _ = Describe("stree", func() { - Context("relationship", func() { - Context("match", func() { - It("returns correct values", func() { - Expect(relationship( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(0), testing.SimpleTime(100), // st et - ).String()).To(Equal("match")) - }) - }) - Context("inside", func() { - It("returns correct values", func() { - Expect(relationship( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(10), testing.SimpleTime(90), // st et - ).String()).To(Equal("inside")) - Expect(relationship( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(0), testing.SimpleTime(90), // st et - ).String()).To(Equal("inside")) - Expect(relationship( - testing.SimpleTime(0), testing.SimpleTime(100), // t1 t2 - testing.SimpleTime(10), testing.SimpleTime(100), // st et - ).String()).To(Equal("inside")) - }) - }) - Context("contain", func() { - It("returns correct values", func() { - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(210), // st et - ).String()).To(Equal("contain")) - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(100), testing.SimpleTime(210), // st et - ).String()).To(Equal("contain")) - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(200), // st et - ).String()).To(Equal("contain")) - }) - }) - Context("overlap", func() { - It("returns correct values", func() { - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(110), // st et - ).String()).To(Equal("overlap")) - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(190), testing.SimpleTime(210), // st et - ).String()).To(Equal("overlap")) - }) - }) - Context("outside", func() { - It("returns correct values", func() { - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(90), testing.SimpleTime(100), // st et - ).String()).To(Equal("outside")) - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(80), testing.SimpleTime(90), // st et - ).String()).To(Equal("outside")) - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(200), testing.SimpleTime(210), // st et - ).String()).To(Equal("outside")) - Expect(relationship( - testing.SimpleTime(100), testing.SimpleTime(200), // t1 t2 - testing.SimpleTime(210), testing.SimpleTime(220), // st et - ).String()).To(Equal("outside")) - }) - }) - }) -}) diff --git a/pkg/og/storage/segment/retention.go b/pkg/og/storage/segment/retention.go deleted file mode 100644 index 63b47fa2da..0000000000 --- a/pkg/og/storage/segment/retention.go +++ /dev/null @@ -1,81 +0,0 @@ -package segment - -import ( - "time" -) - -type RetentionPolicy struct { - now time.Time - - AbsoluteTime time.Time - Levels map[int]time.Time - - ExemplarsRetentionTime time.Time -} - -func NewRetentionPolicy() *RetentionPolicy { - return &RetentionPolicy{now: time.Now()} -} - -func (r RetentionPolicy) LowerTimeBoundary() time.Time { - if len(r.Levels) == 0 { - return r.AbsoluteTime - } - return r.Levels[0] -} - -func (r *RetentionPolicy) SetAbsolutePeriod(period time.Duration) *RetentionPolicy { - r.AbsoluteTime = r.periodToTime(period) - return r -} - -func (r *RetentionPolicy) SetExemplarsRetentionPeriod(period time.Duration) *RetentionPolicy { - r.ExemplarsRetentionTime = r.periodToTime(period) - return r -} - -func (r *RetentionPolicy) SetLevelPeriod(level int, period time.Duration) *RetentionPolicy { - if r.Levels == nil { - r.Levels = make(map[int]time.Time) - } - r.Levels[level] = r.periodToTime(period) - return r -} - -func (r *RetentionPolicy) SetLevels(levels ...time.Duration) *RetentionPolicy { - if r.Levels == nil { - r.Levels = make(map[int]time.Time) - } - for level, period := range levels { - if period != 0 { - r.Levels[level] = r.periodToTime(period) - } - } - return r -} - -func (r RetentionPolicy) isToBeDeleted(sn *streeNode) bool { - return sn.isBefore(r.AbsoluteTime) || sn.isBefore(r.levelMaxTime(sn.depth)) -} - -func (r RetentionPolicy) periodToTime(age time.Duration) time.Time { - if age == 0 { - return time.Time{} - } - return r.now.Add(-1 * age) -} - -func (r *RetentionPolicy) normalize() *RetentionPolicy { - r.AbsoluteTime = normalizeTime(r.AbsoluteTime) - for k, v := range r.Levels { - r.Levels[k] = normalizeTime(v) - } - return r -} - -func (r RetentionPolicy) levelMaxTime(depth int) time.Time { - if r.Levels == nil { - return time.Time{} - } - return r.Levels[depth] -} diff --git a/pkg/og/storage/segment/segment.go b/pkg/og/storage/segment/segment.go deleted file mode 100644 index b0eb4f961d..0000000000 --- a/pkg/og/storage/segment/segment.go +++ /dev/null @@ -1,460 +0,0 @@ -package segment - -import ( - "context" - "errors" - "fmt" - "math/big" - "os" - "path/filepath" - "runtime/trace" - "sync" - "time" - - "github.com/grafana/pyroscope/pkg/og/storage/metadata" -) - -type streeNode struct { - depth int - time time.Time - present bool - samples uint64 - writes uint64 - children []*streeNode -} - -func (sn *streeNode) replace(child *streeNode) { - i := child.time.Sub(sn.time) / durations[child.depth] - sn.children[i] = child -} - -func (sn *streeNode) relationship(st, et time.Time) rel { - t2 := sn.time.Add(durations[sn.depth]) - return relationship(sn.time, t2, st, et) -} - -func (sn *streeNode) isBefore(rt time.Time) bool { - t2 := sn.time.Add(durations[sn.depth]) - return !t2.After(rt) -} - -func (sn *streeNode) isAfter(rt time.Time) bool { - return sn.time.After(rt) -} - -func (sn *streeNode) endTime() time.Time { - return sn.time.Add(durations[sn.depth]) -} - -func (sn *streeNode) overlapRead(st, et time.Time) *big.Rat { - t2 := sn.time.Add(durations[sn.depth]) - return overlapRead(sn.time, t2, st, et, durations[0]) -} - -func (sn *streeNode) overlapWrite(st, et time.Time) *big.Rat { - t2 := sn.time.Add(durations[sn.depth]) - return overlapWrite(sn.time, t2, st, et, durations[0]) -} - -func (sn *streeNode) findAddons() []Addon { - res := []Addon{} - if sn.present { - res = append(res, Addon{ - Depth: sn.depth, - T: sn.time, - }) - } else { - for _, child := range sn.children { - if child != nil { - res = append(res, child.findAddons()...) - } - } - } - return res -} - -func (sn *streeNode) put(st, et time.Time, samples uint64, cb func(n *streeNode, depth int, dt time.Time, r *big.Rat, addons []Addon)) { - nodes := []*streeNode{sn} - - for len(nodes) > 0 { - sn = nodes[0] - nodes = nodes[1:] - - rel := sn.relationship(st, et) - if rel != outside { - childrenCount := 0 - createNewChildren := rel == inside || rel == overlap - for i, v := range sn.children { - if createNewChildren && v == nil { // maybe create a new child - childT := sn.time.Truncate(durations[sn.depth]).Add(time.Duration(i) * durations[sn.depth-1]) - - rel2 := relationship(childT, childT.Add(durations[sn.depth-1]), st, et) - if rel2 != outside { - sn.children[i] = newNode(childT, sn.depth-1, 10) - } - } - - if sn.children[i] != nil { - childrenCount++ - nodes = append(nodes, sn.children[i]) - } - } - var addons []Addon - - r := sn.overlapWrite(st, et) - fv, _ := r.Float64() - sn.samples += uint64(float64(samples) * fv) - sn.writes += uint64(1) - - // relationship overlap read overlap write - // inside rel = iota // | S E | <1 1/1 - // match // matching ranges 1/1 1/1 - // outside // | | S E 0/1 0/1 - // overlap // | S | E <1 <1 - // contain // S | | E 1/1 <1 - - if rel == match || rel == contain || childrenCount > 1 || sn.present { - if !sn.present { - addons = sn.findAddons() - } - - cb(sn, sn.depth, sn.time, r, addons) - sn.present = true - } - } - } -} - -func normalize(st, et time.Time) (time.Time, time.Time) { - st = st.Truncate(durations[0]) - et2 := et.Truncate(durations[0]) - if et2.Equal(et) && !st.Equal(et2) { - return st, et - } - return st, et2.Add(durations[0]) -} - -func normalizeTime(t time.Time) time.Time { - return t.Truncate(durations[0]) -} - -// get traverses through the tree searching for the nodes satisfying -// the given time range. If no nodes were found, the most precise -// down-sampling root node will be passed to the callback function, -// and relationship r will be proportional to the down-sampling factor. -// -// relationship overlap read overlap write -// inside rel = iota // | S E | <1 1/1 -// match // matching ranges 1/1 1/1 -// outside // | | S E 0/1 0/1 -// overlap // | S | E <1 <1 -// contain // S | | E 1/1 <1 -func (sn *streeNode) get(ctx context.Context, s *Segment, st, et time.Time, cb func(*streeNode, *big.Rat)) { - r := sn.relationship(st, et) - trace.Logf(ctx, traceCatNodeGet, "D=%d T=%v P=%v R=%v", sn.depth, sn.time.Unix(), sn.present, r) - switch r { - case outside: - return - case inside, overlap: - // Defer to children. - case contain, match: - // Take the node as is. - if sn.present { - cb(sn, big.NewRat(1, 1)) - return - } - } - trace.Log(ctx, traceCatNodeGet, "drill down") - // Whether child nodes are outside the retention period. - if sn.time.Before(s.watermarks.levels[sn.depth-1]) && sn.present { - trace.Log(ctx, traceCatNodeGet, "sampled") - // Create a sampled tree from the current node. - cb(sn, sn.overlapRead(st, et)) - return - } - // Traverse nodes recursively. - for _, v := range sn.children { - if v != nil { - v.get(ctx, s, st, et, cb) - } - } -} - -// deleteDataBefore returns true if the node should be deleted. -func (sn *streeNode) deleteNodesBefore(t *RetentionPolicy) (bool, error) { - if sn.isAfter(t.AbsoluteTime) && t.Levels == nil { - return false, nil - } - remove := t.isToBeDeleted(sn) - for i, v := range sn.children { - if v == nil { - continue - } - ok, err := v.deleteNodesBefore(t) - if err != nil { - return false, err - } - if ok { - sn.children[i] = nil - } - } - return remove, nil -} - -func (sn *streeNode) walkNodesToDelete(t *RetentionPolicy, cb func(depth int, t time.Time) error) (bool, error) { - if sn.isAfter(t.AbsoluteTime) && t.Levels == nil { - return false, nil - } - var err error - remove := t.isToBeDeleted(sn) - if remove { - if err = cb(sn.depth, sn.time); err != nil { - return false, err - } - } - for _, v := range sn.children { - if v == nil { - continue - } - if _, err = v.walkNodesToDelete(t, cb); err != nil { - return false, err - } - } - return remove, nil -} - -type Segment struct { - m sync.RWMutex - root *streeNode - - spyName string - sampleRate uint32 - units metadata.Units - aggregationType metadata.AggregationType - - watermarks -} - -type watermarks struct { - absoluteTime time.Time - levels map[int]time.Time -} - -func newNode(t time.Time, depth, multiplier int) *streeNode { - sn := &streeNode{ - depth: depth, - time: t, - } - if depth > 0 { - sn.children = make([]*streeNode, multiplier) - } - return sn -} - -func New() *Segment { - return &Segment{watermarks: watermarks{ - levels: make(map[int]time.Time), - }} -} - -// TODO: DRY -func maxTime(a, b time.Time) time.Time { - if a.After(b) { - return a - } - return b -} - -func minTime(a, b time.Time) time.Time { - if a.Before(b) { - return a - } - return b -} - -func (s *Segment) growTree(st, et time.Time) bool { - var prevVal *streeNode - if s.root != nil { - st = minTime(st, s.root.time) - et = maxTime(et, s.root.endTime()) - } else { - st = st.Truncate(durations[0]) - s.root = newNode(st, 0, multiplier) - } - - for { - rel := s.root.relationship(st, et) - - if rel == inside || rel == match { - break - } - - prevVal = s.root - newDepth := prevVal.depth + 1 - if newDepth >= len(durations) { - return false - } - s.root = newNode(prevVal.time.Truncate(durations[newDepth]), newDepth, multiplier) - if prevVal != nil { - s.root.samples = prevVal.samples - s.root.writes = prevVal.writes - s.root.replace(prevVal) - } - } - return true -} - -type Addon struct { - Depth int - T time.Time -} - -var errStartTimeBeforeEndTime = errors.New("start time cannot be after end time") -var errTreeMaxSize = errors.New("segment tree reached max size, check start / end time parameters") - -// TODO: simplify arguments -// TODO: validate st < et -func (s *Segment) Put(st, et time.Time, samples uint64, cb func(depth int, t time.Time, r *big.Rat, addons []Addon)) error { - s.m.Lock() - defer s.m.Unlock() - - st, et = normalize(st, et) - if st.After(et) { - return errStartTimeBeforeEndTime - } - - if !s.growTree(st, et) { - return errTreeMaxSize - } - v := newVis() - s.root.put(st, et, samples, func(sn *streeNode, depth int, tm time.Time, r *big.Rat, addons []Addon) { - v.add(sn, r, true) - cb(depth, tm, r, addons) - }) - v.print(filepath.Join(os.TempDir(), fmt.Sprintf("0-put-%s-%s.html", st.String(), et.String()))) - return nil -} - -const ( - traceRegionGet = "segment.Get" - traceCatGet = traceRegionGet - traceCatNodeGet = "node.get" -) - -//revive:disable-next-line:get-return callback -func (s *Segment) Get(st, et time.Time, cb func(depth int, samples, writes uint64, t time.Time, r *big.Rat)) { - // TODO: simplify arguments - // TODO: validate st < et - s.GetContext(context.Background(), st, et, cb) -} - -//revive:disable-next-line:get-return callback -func (s *Segment) GetContext(ctx context.Context, st, et time.Time, cb func(depth int, samples, writes uint64, t time.Time, r *big.Rat)) { - defer trace.StartRegion(ctx, traceRegionGet).End() - s.m.RLock() - defer s.m.RUnlock() - if st.Before(s.watermarks.absoluteTime) { - trace.Logf(ctx, traceCatGet, "start time %s is outside the retention period; set to %s", st, s.watermarks.absoluteTime) - st = s.watermarks.absoluteTime - } - st, et = normalize(st, et) - if s.root == nil { - trace.Log(ctx, traceCatGet, "empty") - return - } - // divider := int(et.Sub(st) / durations[0]) - v := newVis() - s.root.get(ctx, s, st, et, func(sn *streeNode, r *big.Rat) { - // TODO: pass m / d from .get() ? - v.add(sn, r, true) - cb(sn.depth, sn.samples, sn.writes, sn.time, r) - }) - v.print(filepath.Join(os.TempDir(), fmt.Sprintf("0-get-%s-%s.html", st.String(), et.String()))) -} - -func (s *Segment) DeleteNodesBefore(t *RetentionPolicy) (bool, error) { - s.m.Lock() - defer s.m.Unlock() - if s.root == nil { - return true, nil - } - ok, err := s.root.deleteNodesBefore(t.normalize()) - if err != nil { - return false, err - } - if ok { - s.root = nil - } - s.updateWatermarks(t) - return ok, nil -} - -func (s *Segment) updateWatermarks(t *RetentionPolicy) { - if t.AbsoluteTime.After(s.watermarks.absoluteTime) { - s.watermarks.absoluteTime = t.AbsoluteTime - } - for k, v := range t.Levels { - if level, ok := s.watermarks.levels[k]; ok && v.Before(level) { - continue - } - s.watermarks.levels[k] = v - } -} - -func (s *Segment) WalkNodesToDelete(t *RetentionPolicy, cb func(depth int, t time.Time) error) (bool, error) { - s.m.RLock() - defer s.m.RUnlock() - if s.root == nil { - return true, nil - } - return s.root.walkNodesToDelete(t.normalize(), cb) -} - -func (s *Segment) SetMetadata(md metadata.Metadata) { - s.m.Lock() - s.spyName = md.SpyName - s.sampleRate = md.SampleRate - s.units = md.Units - s.aggregationType = md.AggregationType - s.m.Unlock() -} - -func (s *Segment) GetMetadata() metadata.Metadata { - s.m.Lock() - md := metadata.Metadata{ - SpyName: s.spyName, - SampleRate: s.sampleRate, - Units: s.units, - AggregationType: s.aggregationType, - } - s.m.Unlock() - return md -} - -var zeroTime time.Time - -func (s *Segment) StartTime() time.Time { - if s.root == nil { - return zeroTime - } - n := s.root - - for { - if len(n.children) == 0 { - return n.time - } - - oldN := n - - for _, child := range n.children { - if child != nil { - n = child - break - } - } - - if n == oldN { - return n.time - } - } -} diff --git a/pkg/og/storage/segment/segment_suite_test.go b/pkg/og/storage/segment/segment_suite_test.go deleted file mode 100644 index 2b4e9e67c5..0000000000 --- a/pkg/og/storage/segment/segment_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package segment_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestSegment(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Segment Suite") -} diff --git a/pkg/og/storage/segment/segment_test.go b/pkg/og/storage/segment/segment_test.go deleted file mode 100644 index a3573d23b1..0000000000 --- a/pkg/og/storage/segment/segment_test.go +++ /dev/null @@ -1,482 +0,0 @@ -package segment - -import ( - "bufio" - "log" - "math/big" - "math/rand" - "os" - "strconv" - "strings" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/grafana/pyroscope/pkg/og/testing" -) - -var putNoOp = func(depth int, t time.Time, r *big.Rat, addons []Addon) {} - -func doGet(s *Segment, st, et time.Time) []time.Time { - res := []time.Time{} - s.Get(st, et, func(d int, samples, writes uint64, t time.Time, r *big.Rat) { - res = append(res, t) - }) - return res -} - -func strip(val string) string { - ret := "" - scanner := bufio.NewScanner(strings.NewReader(val)) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if len(line) > 0 { - ret += line + "\n" - } - } - return ret -} - -func expectChildrenSamplesAddUpToParentSamples(tn *streeNode) { - childrenSum := uint64(0) - if len(tn.children) == 0 { - return - } - for _, v := range tn.children { - if v != nil { - expectChildrenSamplesAddUpToParentSamples(v) - childrenSum += v.samples - } - } - Expect(childrenSum).To(Equal(tn.samples)) -} - -var _ = Describe("stree", func() { - Context("Get", func() { - Context("When there's no root", func() { - It("get doesn't fail", func() { - s := New() - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(39))).To(HaveLen(0)) - }) - }) - }) - - Context("StartTime", func() { - Context("empty segment", func() { - It("returns zero time", func() { - s := New() - Expect(s.StartTime().IsZero()).To(BeTrue()) - }) - }) - - Context("fuzz test", func() { - It("always returns the right values", func() { - r := rand.New(rand.NewSource(6231912)) - - // doesn't work with minTime = 0 - minTime := 1023886146 - maxTime := 1623886146 - - runs := 100 - maxInsertionsPerTree := 100 - - for i := 0; i < runs; i++ { - s := New() - minSt := maxTime - for j := 0; j < 1+r.Intn(maxInsertionsPerTree); j++ { - st := (minTime + r.Intn(maxTime-minTime)) / 10 * 10 - if st < minSt { - minSt = st - } - et := st + 10 + r.Intn(1000) - s.Put(testing.SimpleTime(st), testing.SimpleTime(et), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - } - - Expect(s.StartTime()).To(Equal(testing.SimpleTime(minSt))) - } - }) - }) - }) - - Context("DeleteDataBefore", func() { - Context("empty segment", func() { - It("returns true and no keys", func() { - s := New() - - keys := []string{} - rp := &RetentionPolicy{AbsoluteTime: testing.SimpleTime(19)} - r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))) - return nil - }) - - Expect(r).To(BeTrue()) - Expect(keys).To(BeEmpty()) - }) - }) - - Context("simple test 1", func() { - It("correctly deletes data", func() { - s := New() - s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - keys := []string{} - rp := &RetentionPolicy{AbsoluteTime: testing.SimpleUTime(21)} - r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))) - return nil - }) - - Expect(r).To(BeFalse()) - Expect(keys).To(ConsistOf([]string{ - "0:10", - })) - }) - }) - - Context("simple test 3", func() { - It("correctly deletes data", func() { - s := New() - s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleUTime(1020), testing.SimpleUTime(1029), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - keys := []string{} - rp := &RetentionPolicy{AbsoluteTime: testing.SimpleUTime(21)} - r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))) - return nil - }) - - Expect(r).To(BeFalse()) - Expect(keys).To(ConsistOf([]string{ - "0:10", - })) - }) - }) - - Context("simple test 2", func() { - It("correctly deletes data", func() { - s := New() - s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - keys := []string{} - rp := &RetentionPolicy{AbsoluteTime: testing.SimpleUTime(200)} - r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))) - return nil - }) - - Expect(r).To(BeTrue()) - Expect(keys).To(ConsistOf([]string{ - "1:0", - "0:10", - "0:20", - })) - }) - }) - - Context("level-based retention", func() { - It("correctly deletes data partially", func() { - s := New() - s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - keys := []string{} - rp := &RetentionPolicy{Levels: map[int]time.Time{0: time.Now()}} - r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))) - return nil - }) - - Expect(r).To(BeFalse()) - Expect(s.root).ToNot(BeNil()) - Expect(keys).To(ConsistOf([]string{ - "0:10", - "0:20", - })) - - removed, err := s.DeleteNodesBefore(rp) - Expect(err).ToNot(HaveOccurred()) - Expect(removed).To(BeFalse()) - }) - - It("correctly deletes data completely", func() { - s := New() - s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - var keys []string - rp := &RetentionPolicy{Levels: map[int]time.Time{0: time.Now(), 1: time.Now()}} - r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))) - return nil - }) - - Expect(r).To(BeTrue()) - Expect(keys).To(ConsistOf([]string{ - "1:0", - "0:10", - "0:20", - })) - - removed, err := s.DeleteNodesBefore(rp) - Expect(err).ToNot(HaveOccurred()) - Expect(removed).To(BeTrue()) - }) - - Context("Issue 715", func() { - // See https://github.com/pyroscope-io/pyroscope/issues/715 - It("does not return nodes affected by retention policy", func() { - b, err := os.Open("testdata/issue_715") - Expect(err).ToNot(HaveOccurred()) - s, err := Deserialize(b) - Expect(err).ToNot(HaveOccurred()) - - var keys []string - st := time.Date(2022, time.January, 12, 9, 40, 0, 0, time.UTC) - et := time.Date(2022, time.January, 12, 10, 40, 0, 0, time.UTC) - s.Get(st, et, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))+":"+r.String()) - }) - - Expect(keys).To(BeEmpty()) - }) - - It("correctly samples data", func() { - s := New() - st := time.Date(2021, time.December, 1, 0, 0, 0, 0, time.UTC) - et := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) - rp := &RetentionPolicy{AbsoluteTime: et} - - c := st - for c.Before(et) { - e := c.Add(time.Second * time.Duration(10)) - err := s.Put(c, e, 100, func(int, time.Time, *big.Rat, []Addon) {}) - Expect(err).ToNot(HaveOccurred()) - c = e - } - - r, err := s.DeleteNodesBefore(rp) - Expect(r).To(BeFalse()) - Expect(err).ToNot(HaveOccurred()) - - gSt := st.Add(-time.Hour) - gEt := et.Add(time.Hour) - - var keys []string - s.Get(gSt, gEt, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))+":"+r.String()) - }) - - Expect(keys).To(BeEmpty()) - }) - - It("correctly samples data with level retention period", func() { - s := New() - st := time.Date(2021, time.December, 1, 0, 0, 0, 0, time.UTC) - et := time.Date(2021, time.December, 2, 0, 0, 0, 0, time.UTC) - - c := st - for c.Before(et) { - e := c.Add(time.Second * time.Duration(10)) - err := s.Put(c, e, 100, func(int, time.Time, *big.Rat, []Addon) {}) - Expect(err).ToNot(HaveOccurred()) - c = e - } - - r, err := s.DeleteNodesBefore(&RetentionPolicy{Levels: map[int]time.Time{0: et}}) - Expect(r).To(BeFalse()) - Expect(err).ToNot(HaveOccurred()) - - gSt := time.Date(2021, time.December, 1, 10, 0, 0, 0, time.UTC) - gEt := gSt.Add(time.Second * 30) - - var keys []string - s.Get(gSt, gEt, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) { - keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))+":"+r.String()) - }) - - Expect(keys).To(ConsistOf([]string{ - "1:1638352800:3/10", - })) - }) - }) - }) - }) - - Context("Put", func() { - Context("When inserts are far apart", func() { - Context("When second insert is far in the future", func() { - It("sets root properly", func() { - log.Println("---") - s := New() - s.Put(testing.SimpleTime(1330), - testing.SimpleTime(1339), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - s.Put(testing.SimpleTime(1110), - testing.SimpleTime(1119), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - expectChildrenSamplesAddUpToParentSamples(s.root) - }) - }) - Context("When second insert is far in the past", func() { - It("sets root properly", func() { - log.Println("---") - s := New() - s.Put(testing.SimpleTime(2030), - testing.SimpleTime(2039), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - expectChildrenSamplesAddUpToParentSamples(s.root) - }) - }) - }) - - Context("When empty", func() { - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - }) - - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(0), - testing.SimpleTime(49), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - }) - - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(10), - testing.SimpleTime(109), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(2)) - }) - - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - expectChildrenSamplesAddUpToParentSamples(s.root) - }) - - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - s.Put(testing.SimpleTime(20), - testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - expectChildrenSamplesAddUpToParentSamples(s.root) - }) - - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 10, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - s.Put(testing.SimpleTime(20), - testing.SimpleTime(39), 10, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - expectChildrenSamplesAddUpToParentSamples(s.root) - }) - - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - - s.Put(testing.SimpleTime(20), - testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - - s.Put(testing.SimpleTime(30), - testing.SimpleTime(39), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - expectChildrenSamplesAddUpToParentSamples(s.root) - }) - - It("sets root properly", func() { - s := New() - s.Put(testing.SimpleTime(30), - testing.SimpleTime(39), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - - s.Put(testing.SimpleTime(20), - testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(39))).To(HaveLen(3)) - }) - - It("works with 3 mins", func() { - s := New() - s.Put(testing.SimpleTime(10), - testing.SimpleTime(70), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(1)) - // Expect(doGet(s, testing.SimpleTime(20, testing.SimpleTime(49))).To(HaveLen(3)) - }) - - It("sets trie properly, gets work", func() { - s := New() - - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(0)) - - s.Put(testing.SimpleTime(100), - testing.SimpleTime(109), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - expectChildrenSamplesAddUpToParentSamples(s.root) - Expect(s.root).ToNot(BeNil()) - Expect(s.root.depth).To(Equal(2)) - Expect(s.root.present).To(BeTrue()) - Expect(s.root.children[0]).ToNot(BeNil()) - Expect(s.root.children[0].present).ToNot(BeTrue()) - Expect(s.root.children[1]).ToNot(BeNil()) - Expect(s.root.children[1].present).ToNot(BeTrue()) - Expect(s.root.children[0].children[0].present).To(BeTrue()) - Expect(s.root.children[1].children[0].present).To(BeTrue()) - - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(9))).To(HaveLen(1)) - Expect(doGet(s, testing.SimpleTime(10), testing.SimpleTime(19))).To(HaveLen(0)) - Expect(doGet(s, testing.SimpleTime(100), testing.SimpleTime(109))).To(HaveLen(1)) - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(109))).To(HaveLen(2)) - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(999))).To(HaveLen(1)) - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(1000))).To(HaveLen(1)) - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(1001))).To(HaveLen(1)) - Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(989))).To(HaveLen(2)) - }) - }) - }) -}) diff --git a/pkg/og/storage/segment/serialization.go b/pkg/og/storage/segment/serialization.go deleted file mode 100644 index e484915b72..0000000000 --- a/pkg/og/storage/segment/serialization.go +++ /dev/null @@ -1,234 +0,0 @@ -package segment - -import ( - "bufio" - "bytes" - "errors" - "io" - "time" - - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/util/serialization" - "github.com/grafana/pyroscope/pkg/og/util/varint" -) - -// serialization format version. it's not very useful right now, but it will be in the future -const currentVersion = 3 - -func (s *Segment) populateFromMetadata(mdata map[string]interface{}) { - if v, ok := mdata["sampleRate"]; ok { - s.sampleRate = uint32(v.(float64)) - } - if v, ok := mdata["spyName"]; ok { - s.spyName = v.(string) - } - if v, ok := mdata["units"]; ok { - s.units = metadata.Units(v.(string)) - } - if v, ok := mdata["aggregationType"]; ok { - s.aggregationType = metadata.AggregationType(v.(string)) - } -} - -func (s *Segment) generateMetadata() map[string]interface{} { - return map[string]interface{}{ - "sampleRate": s.sampleRate, - "spyName": s.spyName, - "units": s.units, - "aggregationType": s.aggregationType, - } -} - -func (s *Segment) Serialize(w io.Writer) error { - s.m.RLock() - defer s.m.RUnlock() - - vw := varint.NewWriter() - if _, err := vw.Write(w, currentVersion); err != nil { - return err - } - if err := serialization.WriteMetadata(w, s.generateMetadata()); err != nil { - return err - } - - if s.root == nil { - return nil - } - - s.serialize(w, vw, s.root) - - return s.watermarks.serialize(w) -} - -func (s *Segment) serialize(w io.Writer, vw varint.Writer, n *streeNode) { - vw.Write(w, uint64(n.depth)) - vw.Write(w, uint64(n.time.Unix())) - vw.Write(w, n.samples) - vw.Write(w, n.writes) - p := uint64(0) - if n.present { - p = 1 - } - vw.Write(w, p) - - // depth - // time - // keyInChunks - // children - l := 0 - for _, v := range n.children { - if v != nil { - l++ - } - } - - vw.Write(w, uint64(l)) - for _, v := range n.children { - if v != nil { - s.serialize(w, vw, v) - } - } -} - -var errMaxDepth = errors.New("depth is too high") - -func Deserialize(r io.Reader) (*Segment, error) { - s := New() - br := bufio.NewReader(r) // TODO if it's already a bytereader skip - - // reads serialization format version, see comment at the top - version, err := varint.Read(br) - if err != nil { - return nil, err - } - - mdata, err := serialization.ReadMetadata(br) - if err != nil { - return nil, err - } - s.populateFromMetadata(mdata) - - // In some cases, there can be no nodes. - if br.Buffered() == 0 { - return s, nil - } - - parents := []*streeNode{nil} - for len(parents) > 0 { - depth, err := varint.Read(br) - if err != nil { - return nil, err - } - if int(depth) >= len(durations) { - return nil, errMaxDepth - } - timeVal, err := varint.Read(br) - if err != nil { - return nil, err - } - samplesVal, err := varint.Read(br) - if err != nil { - return nil, err - } - var writesVal uint64 - if version >= 2 { - writesVal, err = varint.Read(br) - if err != nil { - return nil, err - } - } - presentVal, err := varint.Read(br) - if err != nil { - return nil, err - } - node := newNode(time.Unix(int64(timeVal), 0), int(depth), multiplier) - if presentVal == 1 { - node.present = true - } - node.samples = samplesVal - node.writes = writesVal - if s.root == nil { - s.root = node - } - - parent := parents[0] - parents = parents[1:] - if parent != nil { - parent.replace(node) - } - childrenLen, err := varint.Read(br) - if err != nil { - return nil, err - } - - r := []*streeNode{} - for i := 0; i < int(childrenLen); i++ { - r = append(r, node) - } - parents = append(r, parents...) - } - - if version >= 3 { - if err = deserializeWatermarks(br, &s.watermarks); err != nil { - return nil, err - } - } - - return s, nil -} - -func (s *Segment) Bytes() ([]byte, error) { - b := bytes.Buffer{} - if err := s.Serialize(&b); err != nil { - return nil, err - } - return b.Bytes(), nil -} - -func FromBytes(p []byte) (*Segment, error) { - return Deserialize(bytes.NewReader(p)) -} - -func (w watermarks) serialize(dst io.Writer) error { - vw := varint.NewWriter() - if _, err := vw.Write(dst, uint64(w.absoluteTime.UTC().Unix())); err != nil { - return err - } - if _, err := vw.Write(dst, uint64(len(w.levels))); err != nil { - return err - } - for k, v := range w.levels { - if _, err := vw.Write(dst, uint64(k)); err != nil { - return err - } - if _, err := vw.Write(dst, uint64(v.UTC().Unix())); err != nil { - return err - } - } - return nil -} - -func deserializeWatermarks(r io.ByteReader, w *watermarks) error { - a, err := varint.Read(r) - if err != nil { - return err - } - w.absoluteTime = time.Unix(int64(a), 0).UTC() - l, err := varint.Read(r) - if err != nil { - return err - } - levels := int(l) - for i := 0; i < levels; i++ { - k, err := varint.Read(r) - if err != nil { - return err - } - v, err := varint.Read(r) - if err != nil { - return err - } - w.levels[int(k)] = time.Unix(int64(v), 0).UTC() - } - return nil -} diff --git a/pkg/og/storage/segment/serialization_bench_test.go b/pkg/og/storage/segment/serialization_bench_test.go deleted file mode 100644 index b4ae513397..0000000000 --- a/pkg/og/storage/segment/serialization_bench_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package segment - -import ( - "bytes" - "fmt" - "math/big" - "math/rand" - "testing" - "time" - - ptesting "github.com/grafana/pyroscope/pkg/og/testing" -) - -func serialize(s *Segment) []byte { - var buf bytes.Buffer - s.Serialize(&buf) - return buf.Bytes() -} - -func BenchmarkSerialize(b *testing.B) { - for k := 10; k <= 1000000; k *= 10 { - s := New() - for i := 0; i < k; i++ { - s.Put(ptesting.SimpleTime(i*10), ptesting.SimpleTime(i*10+9), uint64(rand.Intn(100)), func(de int, t time.Time, r *big.Rat, a []Addon) {}) - } - b.ResetTimer() - b.Run(fmt.Sprintf("serialize %d", k), func(b *testing.B) { - for i := 0; i < b.N; i++ { - _ = serialize(s) - } - }) - } -} diff --git a/pkg/og/storage/segment/serialization_test.go b/pkg/og/storage/segment/serialization_test.go deleted file mode 100644 index 9408fe3f6b..0000000000 --- a/pkg/og/storage/segment/serialization_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package segment - -import ( - "bytes" - "log" - "math/big" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/grafana/pyroscope/pkg/og/testing" -) - -var serializedExampleV1 = "\x01({\"sampleRate\":0,\"spyName\":\"\",\"units\":\"\"}" + - "\x01\x80\x92\xb8Ø\xfe\xff\xff\xff\x01\x03\x01\x03\x00\x80\x92\xb8Ø\xfe\xff\xff" + - "\xff\x01\x01\x01\x00\x00\x8a\x92\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x00\x00\x94\x92" + - "\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x00" - -var serializedExampleV2 = "\x02={\"aggregationType\":\"\",\"sampleRate\":0,\"spyName\":\"\",\"units\":\"\"}" + - "\x01\x80\x92\xb8Ø\xfe\xff\xff\xff\x01\x03\x03\x01\x03\x00\x80\x92\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x01\x00" + - "\x00\x8a\x92\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x01\x00\x00\x94\x92\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x01\x00" - -var serializedExampleV3 = "\x03={\"aggregationType\":\"\",\"sampleRate\":0,\"spyName\":\"\",\"units\":\"\"}" + - "\x01\x80\x92\xb8Ø\xfe\xff\xff\xff\x01\x03\x03\x01\x03\x00\x80\x92\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x01\x00" + - "\x00\x8a\x92\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x01\x00\x00\x94\x92\xb8Ø\xfe\xff\xff\xff\x01\x01\x01\x01\x00" + - "\x80\x92\xb8Ø\xfe\xff\xff\xff\x01\x00" - -var _ = Describe("stree", func() { - Context("Serialize / Deserialize", func() { - It("both functions work properly", func() { - s := New() - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(20), - testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - s.watermarks = watermarks{absoluteTime: testing.SimpleTime(100)} - - var buf bytes.Buffer - s.Serialize(&buf) - serialized := buf.Bytes() - log.Printf("%q", serialized) - - s, err := Deserialize(bytes.NewReader(serialized)) - Expect(err).ToNot(HaveOccurred()) - var buf2 bytes.Buffer - s.Serialize(&buf2) - serialized2 := buf2.Bytes() - Expect(string(serialized2)).To(Equal(string(serialized))) - }) - }) - - Context("Serialize", func() { - It("serializes segment tree properly", func() { - s := New() - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(20), - testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - var buf bytes.Buffer - s.Serialize(&buf) - serialized := buf.Bytes() - log.Printf("q: %q", string(serialized)) - Expect(string(serialized)).To(Equal(serializedExampleV3)) - }) - }) - - Context("Deserialize", func() { - Context("v1", func() { - It("deserializes v1 data", func() { - s, err := Deserialize(bytes.NewReader([]byte(serializedExampleV1))) - Expect(err).ToNot(HaveOccurred()) - Expect(s.root.children[0]).ToNot(BeNil()) - Expect(s.root.children[1]).ToNot(BeNil()) - Expect(s.root.children[2]).ToNot(BeNil()) - Expect(s.root.children[3]).To(BeNil()) - }) - }) - Context("v2", func() { - It("deserializes v2 data", func() { - s, err := Deserialize(bytes.NewReader([]byte(serializedExampleV2))) - Expect(err).ToNot(HaveOccurred()) - Expect(s.root.children[0]).ToNot(BeNil()) - Expect(s.root.children[1]).ToNot(BeNil()) - Expect(s.root.children[2]).ToNot(BeNil()) - Expect(s.root.children[3]).To(BeNil()) - Expect(s.root.writes).To(Equal(uint64(3))) - }) - }) - Context("v3", func() { - It("deserializes v3 data", func() { - s, err := Deserialize(bytes.NewReader([]byte(serializedExampleV3))) - Expect(err).ToNot(HaveOccurred()) - Expect(s.root.children[0]).ToNot(BeNil()) - Expect(s.root.children[1]).ToNot(BeNil()) - Expect(s.root.children[2]).ToNot(BeNil()) - Expect(s.root.children[3]).To(BeNil()) - Expect(s.root.writes).To(Equal(uint64(3))) - }) - }) - }) - - Context("watermarks serialize / deserialize", func() { - It("both functions work properly", func() { - w := watermarks{ - absoluteTime: testing.SimpleTime(100), - levels: map[int]time.Time{ - 0: testing.SimpleTime(100), - 1: testing.SimpleTime(1000), - }, - } - - var buf bytes.Buffer - err := w.serialize(&buf) - Expect(err).ToNot(HaveOccurred()) - - s := New() - err = deserializeWatermarks(bytes.NewReader(buf.Bytes()), &s.watermarks) - Expect(err).ToNot(HaveOccurred()) - Expect(w).To(Equal(s.watermarks)) - }) - }) -}) diff --git a/pkg/og/storage/segment/timeline.go b/pkg/og/storage/segment/timeline.go index cfb35d11fb..8d204868e6 100644 --- a/pkg/og/storage/segment/timeline.go +++ b/pkg/og/storage/segment/timeline.go @@ -32,107 +32,3 @@ type Timeline struct { // 4. Data before 1635506200 has resolution 10000s Watermarks map[int]int64 `json:"watermarks"` } - -func GenerateTimeline(st, et time.Time) *Timeline { - st, et = normalize(st, et) - totalDuration := et.Sub(st) - minDuration := totalDuration / time.Duration(1024) - delta := durations[0] - for _, d := range durations { - if d < 0 { - break - } - if d < minDuration { - delta = d - } - } - return &Timeline{ - st: st, - et: et, - StartTime: st.Unix(), - Samples: make([]uint64, totalDuration/delta), - durationDelta: delta, - DurationDeltaNormalized: int64(delta / time.Second), - Watermarks: make(map[int]int64), - } -} - -func (tl *Timeline) PopulateTimeline(s *Segment) { - s.m.Lock() - if s.root != nil { - s.root.populateTimeline(tl, s) - } - s.m.Unlock() -} - -func (sn streeNode) populateTimeline(tl *Timeline, s *Segment) { - if sn.relationship(tl.st, tl.et) == outside { - return - } - - var ( - currentDuration = durations[sn.depth] - levelWatermark time.Time - hasDataBefore bool - ) - - if sn.depth > 0 { - levelWatermark = s.watermarks.levels[sn.depth-1] - } - - if len(sn.children) > 0 && currentDuration >= tl.durationDelta { - for i, v := range sn.children { - if v != nil { - v.populateTimeline(tl, s) - hasDataBefore = true - continue - } - if hasDataBefore || levelWatermark.IsZero() || sn.isBefore(s.watermarks.absoluteTime) { - continue - } - if c := sn.createSampledChild(i); c.isBefore(levelWatermark) && c.isAfter(s.watermarks.absoluteTime) { - c.populateTimeline(tl, s) - if m := c.time.Add(durations[c.depth]); m.After(tl.st) { - tl.Watermarks[c.depth+1] = c.time.Add(durations[c.depth]).Unix() - } - } - } - return - } - - nodeTime := sn.time - if currentDuration < tl.durationDelta { - currentDuration = tl.durationDelta - nodeTime = nodeTime.Truncate(currentDuration) - } - - i := int(nodeTime.Sub(tl.st) / tl.durationDelta) - rightBoundary := i + int(currentDuration/tl.durationDelta) - - l := len(tl.Samples) - for i < rightBoundary { - if i >= 0 && i < l { - if tl.Samples[i] == 0 { - tl.Samples[i] = 1 - } - tl.Samples[i] += sn.samples - } - i++ - } -} - -func (sn *streeNode) createSampledChild(i int) *streeNode { - s := &streeNode{ - depth: sn.depth - 1, - time: sn.time.Add(time.Duration(i) * durations[sn.depth-1]), - samples: sn.samples / multiplier, - writes: sn.samples / multiplier, - } - if s.depth > 0 { - s.children = make([]*streeNode, multiplier) - for j := range s.children { - s.children[j] = s.createSampledChild(j) - } - } - return s -} diff --git a/pkg/og/storage/segment/timeline_test.go b/pkg/og/storage/segment/timeline_test.go deleted file mode 100644 index cffa425c82..0000000000 --- a/pkg/og/storage/segment/timeline_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package segment - -import ( - "math/big" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/grafana/pyroscope/pkg/og/testing" -) - -var _ = Describe("timeline", func() { - var ( - timeline *Timeline - st int - et int - ) - - BeforeEach(func() { - st = 0 - et = 40 - }) - JustBeforeEach(func() { - timeline = GenerateTimeline( - testing.SimpleTime(st), - testing.SimpleTime(et), - ) - }) - - Describe("PopulateTimeline", func() { - Context("empty segment", func() { - It("works as expected", func(done Done) { - s := New() - timeline.PopulateTimeline(s) - Expect(timeline.Samples).To(Equal([]uint64{ - 0, - 0, - 0, - 0, - })) - close(done) - }) - }) - Context("one level", func() { - It("works as expected", func() { - done := make(chan interface{}) - go func() { - s := New() - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 2, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 5, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(20), - testing.SimpleTime(29), 0, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - timeline.PopulateTimeline(s) - Expect(timeline.Samples).To(Equal([]uint64{ - 3, - 6, - 1, - 0, - })) - - close(done) - }() - Eventually(done, 5).Should(BeClosed()) - }) - }) - Context("multiple Levels", func() { - BeforeEach(func() { - st = 0 - et = 365 * 24 * 60 * 60 - }) - - It("works as expected", func() { - done := make(chan interface{}) - go func() { - s := New() - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 2, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 5, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(20), - testing.SimpleTime(29), 0, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - timeline.PopulateTimeline(s) - expected := make([]uint64, 3153) - expected[0] = 8 - Expect(timeline.Samples).To(Equal(expected)) - - close(done) - }() - Eventually(done, 5).Should(BeClosed()) - }) - }) - - Context("with threshold", func() { - BeforeEach(func() { - st = 0 - et = 365 * 24 * 60 * 60 - }) - - It("removed nodes are down-sampled", func() { - done := make(chan interface{}) - go func() { - s := New() - now := time.Now() - s.Put(testing.SimpleTime(0), - testing.SimpleTime(9), 2, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - s.Put(testing.SimpleTime(10), - testing.SimpleTime(19), 5, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - // To prevent segment root removal. - s.Put(now.Add(-10*time.Second), - now, 0, func(de int, t time.Time, r *big.Rat, a []Addon) {}) - - threshold := NewRetentionPolicy(). - SetLevelPeriod(0, time.Second). - SetLevelPeriod(1, time.Minute) - - _, err := s.DeleteNodesBefore(threshold) - Expect(err).ToNot(HaveOccurred()) - timeline.PopulateTimeline(s) - expected := make([]uint64, 3153) - expected[0] = 8 - Expect(timeline.Samples).To(Equal(expected)) - - close(done) - }() - Eventually(done, 5).Should(BeClosed()) - }) - }) - }) -}) diff --git a/pkg/og/storage/segment/visualize.go b/pkg/og/storage/segment/visualize.go deleted file mode 100644 index 81990fea75..0000000000 --- a/pkg/og/storage/segment/visualize.go +++ /dev/null @@ -1,44 +0,0 @@ -package segment - -import ( - "time" -) - -// var highchartsTemplate *template.Template - -func init() { -} - -type visualizeNode struct { - T1 time.Time - T2 time.Time - Depth int - HasTrie bool -} - -// This is here for debugging -func (s *Segment) Visualize() { - res := []*visualizeNode{} - if s.root != nil { - nodes := []*streeNode{s.root} - for len(nodes) != 0 { - n := nodes[0] - nodes = nodes[1:] - // log.Debug("node:", durations[n.depth]) - res = append(res, &visualizeNode{ - T1: n.time.UTC(), - T2: n.time.Add(durations[n.depth]).UTC(), - Depth: n.depth, - HasTrie: n.present, - }) - for _, v := range n.children { - if v != nil { - nodes = append(nodes, v) - } - } - } - } - - // jsonBytes, _ := json.MarshalIndent(res, "", " ") - // log.Debug(string(jsonBytes)) -} diff --git a/pkg/og/storage/tree/flamebearer_test.go b/pkg/og/storage/tree/flamebearer_test.go index a21d72bf03..3e831e2417 100644 --- a/pkg/og/storage/tree/flamebearer_test.go +++ b/pkg/og/storage/tree/flamebearer_test.go @@ -3,43 +3,37 @@ package tree import ( "fmt" "math/rand" + "testing" - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -var _ = Describe("FlamebearerStruct", func() { - Context("simple case", func() { - It("sets all attributes correctly", func() { - tree := New() - tree.Insert([]byte("a;b"), uint64(1)) - tree.Insert([]byte("a;c"), uint64(2)) +func TestFlamebearerStruct(t *testing.T) { + t.Run("simple case sets all attributes correctly", func(t *testing.T) { + tree := New() + tree.Insert([]byte("a;b"), uint64(1)) + tree.Insert([]byte("a;c"), uint64(2)) - f := tree.FlamebearerStruct(1024) - Expect(f.Names).To(Equal([]string{"total", "a", "c", "b"})) - Expect(f.Levels).To(Equal([][]int{ - // i+0 = x offset (delta encoded) - // i+1 = total - // i+2 = self - // i+3 = index in names array - {0, 3, 0, 0}, - {0, 3, 0, 1}, - {0, 1, 1, 3, 0, 2, 2, 2}, - })) - Expect(f.NumTicks).To(Equal(3)) - Expect(f.MaxSelf).To(Equal(2)) - }) + f := tree.FlamebearerStruct(1024) + require.Equal(t, []string{"total", "a", "c", "b"}, f.Names) + require.Equal(t, [][]int{ + {0, 3, 0, 0}, + {0, 3, 0, 1}, + {0, 1, 1, 3, 0, 2, 2, 2}, + }, f.Levels) + require.Equal(t, 3, f.NumTicks) + require.Equal(t, 2, f.MaxSelf) }) - Context("case with many nodes", func() { - It("groups nodes into a new \"other\" node", func() { - tree := New() - r := rand.New(rand.NewSource(123)) - for i := 0; i < 2048; i++ { - tree.Insert([]byte(fmt.Sprintf("foo;bar%d", i)), uint64(r.Intn(4000))) - } - f := tree.FlamebearerStruct(10) - Expect(f.Names).To(ContainElement("other")) - }) + t.Run("case with many nodes groups nodes into other", func(t *testing.T) { + tree := New() + r := rand.New(rand.NewSource(123)) + for i := 0; i < 2048; i++ { + tree.Insert([]byte(fmt.Sprintf("foo;bar%d", i)), uint64(r.Intn(4000))) + } + + f := tree.FlamebearerStruct(10) + assert.Contains(t, f.Names, "other") }) -}) +} diff --git a/pkg/og/storage/tree/labels_cache.go b/pkg/og/storage/tree/labels_cache.go deleted file mode 100644 index 66ec69bc2c..0000000000 --- a/pkg/og/storage/tree/labels_cache.go +++ /dev/null @@ -1,114 +0,0 @@ -package tree - -// sample type -> labels hash -> entry -type LabelsCache[T any] struct { - Map map[int64]map[uint64]*LabelsCacheEntry[T] - Factory func() *T -} - -func NewLabelsCache[T any](factory func() *T) LabelsCache[T] { - return LabelsCache[T]{ - Map: make(map[int64]map[uint64]*LabelsCacheEntry[T]), - Factory: factory, - } -} - -type LabelsCacheEntry[T any] struct { - Labels - Value *T -} - -func (c *LabelsCache[T]) NewCacheEntry(l Labels) *LabelsCacheEntry[T] { - return &LabelsCacheEntry[T]{ - Labels: CopyLabels(l), - Value: c.Factory(), - } -} - -func (c *LabelsCache[T]) GetOrCreateTree(sampleType int64, l Labels) *LabelsCacheEntry[T] { - p, ok := c.Map[sampleType] - if !ok { - e := c.NewCacheEntry(l) - c.Map[sampleType] = map[uint64]*LabelsCacheEntry[T]{l.Hash(): e} - return e - } - h := l.Hash() - e, found := p[h] - if !found { - e = c.NewCacheEntry(l) - p[h] = e - } - return e -} - -func (c *LabelsCache[T]) GetOrCreateTreeByHash(sampleType int64, l Labels, h uint64) *LabelsCacheEntry[T] { - p, ok := c.Map[sampleType] - if !ok { - e := c.NewCacheEntry(l) - c.Map[sampleType] = map[uint64]*LabelsCacheEntry[T]{h: e} - return e - } - e, found := p[h] - if !found { - e = c.NewCacheEntry(l) - p[h] = e - } - return e -} - -func (c *LabelsCache[T]) Get(sampleType int64, h uint64) (*LabelsCacheEntry[T], bool) { - p, ok := c.Map[sampleType] - if !ok { - return nil, false - } - x, ok := p[h] - return x, ok -} - -func (c *LabelsCache[T]) Put(sampleType int64, e *LabelsCacheEntry[T]) { - p, ok := c.Map[sampleType] - if !ok { - p = make(map[uint64]*LabelsCacheEntry[T]) - c.Map[sampleType] = p - } - p[e.Hash()] = e -} - -func (c *LabelsCache[T]) Remove(sampleType int64, h uint64) { - p, ok := c.Map[sampleType] - if !ok { - return - } - delete(p, h) - if len(p) == 0 { - delete(c.Map, sampleType) - } -} - -func CopyLabels(labels Labels) Labels { - l := make(Labels, len(labels)) - for i, v := range labels { - l[i] = CopyLabel(v) - } - return l -} - -// CutLabel creates a copy of labels without label i. -func CutLabel(labels Labels, i int) Labels { - c := make(Labels, 0, len(labels)-1) - for j, label := range labels { - if i != j { - c = append(c, CopyLabel(label)) - } - } - return c -} - -func CopyLabel(label *Label) *Label { - return &Label{ - Key: label.Key, - Str: label.Str, - Num: label.Num, - NumUnit: label.NumUnit, - } -} diff --git a/pkg/og/storage/tree/minval.go b/pkg/og/storage/tree/minval.go index 82414732c5..0fc43f167d 100644 --- a/pkg/og/storage/tree/minval.go +++ b/pkg/og/storage/tree/minval.go @@ -1,7 +1,7 @@ package tree import ( - "github.com/grafana/pyroscope/pkg/og/structs/cappedarr" + "github.com/grafana/pyroscope/v2/pkg/og/structs/cappedarr" ) func (t *Tree) minValue(maxNodes int) uint64 { diff --git a/pkg/og/storage/tree/pprof.go b/pkg/og/storage/tree/pprof.go index 731da6abfd..e0f3d78eb8 100644 --- a/pkg/og/storage/tree/pprof.go +++ b/pkg/og/storage/tree/pprof.go @@ -1,9 +1,10 @@ package tree import ( + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" "time" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" ) type SampleTypeConfig struct { @@ -84,7 +85,7 @@ type pprof struct { locations map[string]uint64 functions map[string]uint64 strings map[string]int64 - profile *Profile + profile *profilev1.Profile } type PprofMetadata struct { @@ -99,7 +100,7 @@ type PprofMetadata struct { const fakeMappingID = 1 -func (t *Tree) Pprof(mdata *PprofMetadata) *Profile { +func (t *Tree) Pprof(mdata *PprofMetadata) *profilev1.Profile { t.RLock() defer t.RUnlock() @@ -107,18 +108,18 @@ func (t *Tree) Pprof(mdata *PprofMetadata) *Profile { locations: make(map[string]uint64), functions: make(map[string]uint64), strings: make(map[string]int64), - profile: &Profile{ + profile: &profilev1.Profile{ StringTable: []string{""}, }, } - p.profile.Mapping = []*Mapping{{Id: fakeMappingID}} // a fake mapping - p.profile.SampleType = []*ValueType{{Type: p.newString(mdata.Type), Unit: p.newString(mdata.Unit)}} + p.profile.Mapping = []*profilev1.Mapping{{Id: fakeMappingID}} // a fake mapping + p.profile.SampleType = []*profilev1.ValueType{{Type: p.newString(mdata.Type), Unit: p.newString(mdata.Unit)}} p.profile.TimeNanos = mdata.StartTime.UnixNano() p.profile.DurationNanos = mdata.Duration.Nanoseconds() if mdata.Period != 0 && mdata.PeriodType != "" && mdata.PeriodUnit != "" { p.profile.Period = mdata.Period - p.profile.PeriodType = &ValueType{ + p.profile.PeriodType = &profilev1.ValueType{ Type: p.newString(mdata.PeriodType), Unit: p.newString(mdata.PeriodUnit), } @@ -130,7 +131,7 @@ func (t *Tree) Pprof(mdata *PprofMetadata) *Profile { for _, l := range stack { loc = append(loc, p.newLocation(l)) } - sample := &Sample{LocationId: loc, Value: value} + sample := &profilev1.Sample{LocationId: loc, Value: value} p.profile.Sample = append(p.profile.Sample, sample) }) @@ -151,9 +152,9 @@ func (p *pprof) newLocation(location string) uint64 { id, ok := p.locations[location] if !ok { id = uint64(len(p.profile.Location) + 1) - newLoc := &Location{ + newLoc := &profilev1.Location{ Id: id, - Line: []*Line{{FunctionId: p.newFunction(location)}}, + Line: []*profilev1.Line{{FunctionId: p.newFunction(location)}}, MappingId: fakeMappingID, } p.profile.Location = append(p.profile.Location, newLoc) @@ -167,7 +168,7 @@ func (p *pprof) newFunction(function string) uint64 { if !ok { id = uint64(len(p.profile.Function) + 1) name := p.newString(function) - newFn := &Function{ + newFn := &profilev1.Function{ Id: id, Name: name, SystemName: name, diff --git a/pkg/og/storage/tree/pprof_test.go b/pkg/og/storage/tree/pprof_test.go index aa2e49f236..47b9c1fd1d 100644 --- a/pkg/og/storage/tree/pprof_test.go +++ b/pkg/og/storage/tree/pprof_test.go @@ -1,157 +1,132 @@ package tree import ( + "testing" "time" - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" ) -var _ = Describe("tree", func() { - var tree *Tree - var profile *Profile - var fnNames []string - - Describe("pprof", func() { - BeforeEach(func() { - tree = New() - tree.Insert([]byte("main;foo;1;2;3;4;5"), uint64(15)) - tree.Insert([]byte("main;baz;1;2;3;4;5;6"), uint64(55)) - tree.Insert([]byte("main;baz;1;2;3;4;5;6;8"), uint64(25)) - tree.Insert([]byte("main;bar;1;2;3;4;5;6;8"), uint64(35)) - tree.Insert([]byte("main;foo;1;2;3;4;5;6"), uint64(20)) - tree.Insert([]byte("main;bar;1;2;3;4;5;6;9"), uint64(35)) - tree.Insert([]byte("main;baz;1;2;3;4;5;6;7"), uint64(30)) - tree.Insert([]byte("main;qux;1;2;3;4;5;6;7;8;9"), uint64(65)) - - profile = tree.Pprof(&PprofMetadata{ - Type: "cpu", - Unit: "samples", - StartTime: time.Date(2021, 1, 1, 10, 0, 1, 0, time.UTC), - Duration: time.Minute, - }) - fnNames = []string{ - "main", - "foo", - "bar", - "baz", - "qux", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", +func setupPprofTree(t *testing.T) (*Tree, *googlev1.Profile, []string) { + t.Helper() + + tr := New() + tr.Insert([]byte("main;foo;1;2;3;4;5"), uint64(15)) + tr.Insert([]byte("main;baz;1;2;3;4;5;6"), uint64(55)) + tr.Insert([]byte("main;baz;1;2;3;4;5;6;8"), uint64(25)) + tr.Insert([]byte("main;bar;1;2;3;4;5;6;8"), uint64(35)) + tr.Insert([]byte("main;foo;1;2;3;4;5;6"), uint64(20)) + tr.Insert([]byte("main;bar;1;2;3;4;5;6;9"), uint64(35)) + tr.Insert([]byte("main;baz;1;2;3;4;5;6;7"), uint64(30)) + tr.Insert([]byte("main;qux;1;2;3;4;5;6;7;8;9"), uint64(65)) + + profile := tr.Pprof(&PprofMetadata{ + Type: "cpu", + Unit: "samples", + StartTime: time.Date(2021, 1, 1, 10, 0, 1, 0, time.UTC), + Duration: time.Minute, + }) + fnNames := []string{ + "main", "foo", "bar", "baz", "qux", + "1", "2", "3", "4", "5", "6", "7", "8", "9", + } + return tr, profile, fnNames +} + +func TestPprof(t *testing.T) { + tree, profile, fnNames := setupPprofTree(t) + + t.Run("Should serialize correctly", func(t *testing.T) { + _, err := proto.Marshal(profile) + require.NoError(t, err) + }) + + t.Run("StringTable Should build correctly", func(t *testing.T) { + require.Len(t, profile.StringTable, 17) + assert.ElementsMatch(t, append(fnNames, "", "cpu", "samples"), profile.StringTable) + }) + + t.Run("StringTable Should have empty first element", func(t *testing.T) { + profile := tree.Pprof(&PprofMetadata{}) + require.Equal(t, "", profile.StringTable[0]) + }) + + t.Run("Metadata Should build correctly", func(t *testing.T) { + require.Equal(t, int64(1609495201000000000), profile.TimeNanos) + require.Equal(t, int64(60000000000), profile.DurationNanos) + require.Len(t, profile.SampleType, 1) + _type := profile.StringTable[profile.SampleType[0].Type] + unit := profile.StringTable[profile.SampleType[0].Unit] + require.Equal(t, "cpu", _type) + require.Equal(t, "samples", unit) + }) + + t.Run("Function Should build correctly", func(t *testing.T) { + require.Len(t, profile.Function, 14) + for _, fn := range profile.Function { + require.NotZero(t, fn.Id) + require.NotZero(t, fn.Name) + require.NotZero(t, fn.SystemName) + } + }) + + t.Run("Function Name Should have corresponding StringTable entries", func(t *testing.T) { + var names []string + for _, fn := range profile.Function { + names = append(names, profile.StringTable[fn.Name]) + } + assert.ElementsMatch(t, fnNames, names) + }) + + t.Run("Function SystemName Should have corresponding StringTable entries", func(t *testing.T) { + var names []string + for _, fn := range profile.Function { + names = append(names, profile.StringTable[fn.SystemName]) + } + assert.ElementsMatch(t, fnNames, names) + }) + + t.Run("Location Should build correctly", func(t *testing.T) { + require.Len(t, profile.Location, 14) + for _, l := range profile.Location { + require.NotZero(t, l.Id) + require.NotEmpty(t, l.Line) + require.NotZero(t, l.Line[0].FunctionId) + } + }) + + t.Run("Location Should have corresponding functions", func(t *testing.T) { + fnMap := make(map[uint64]*googlev1.Function) + for _, fn := range profile.Function { + fnMap[fn.Id] = fn + } + for _, l := range profile.Location { + _, ok := fnMap[l.Line[0].FunctionId] + require.True(t, ok) + } + }) + + t.Run("Sample Should build correctly", func(t *testing.T) { + require.Len(t, profile.Sample, 8) + for _, s := range profile.Sample { + require.NotEmpty(t, s.LocationId) + require.NotEmpty(t, s.Value) + } + }) + + t.Run("Sample Should have corresponding locations", func(t *testing.T) { + lMap := make(map[uint64]*googlev1.Location) + for _, l := range profile.Location { + lMap[l.Id] = l + } + for _, s := range profile.Sample { + for _, l := range s.LocationId { + _, ok := lMap[l] + require.True(t, ok) } - }) - It("Should serialize correctly", func() { - _, err := proto.Marshal(profile) - Expect(err).ToNot(HaveOccurred()) - }) - Describe("StringTable", func() { - It("Should build correctly", func() { - Expect(len(profile.StringTable)).To(Equal(17)) - Expect(profile.StringTable).To(ConsistOf( - append( - fnNames, - "", - "cpu", - "samples", - ), - )) - }) - It("Should have empty first element", func() { - profile = tree.Pprof(&PprofMetadata{}) - Expect(profile.StringTable[0]).To(Equal("")) - }) - }) - Describe("Metadata", func() { - It("Should build correctly", func() { - Expect(profile.TimeNanos).To(Equal(int64(1609495201000000000))) - Expect(profile.DurationNanos).To(Equal(int64(60000000000))) - Expect(len(profile.SampleType)).To(Equal(1)) - _type := profile.StringTable[profile.SampleType[0].Type] - unit := profile.StringTable[profile.SampleType[0].Unit] - - Expect(_type).To(Equal("cpu")) - Expect(unit).To(Equal("samples")) - }) - }) - Describe("Function", func() { - It("Should build correctly", func() { - Expect(len(profile.Function)).To(Equal(14)) - for _, fn := range profile.Function { - Expect(fn.Id).NotTo(BeZero()) - Expect(fn.Name).NotTo(BeZero()) - Expect(fn.SystemName).NotTo(BeZero()) - } - }) - Context("Name", func() { - It("Should have corresponding StringTable entries", func() { - var names []string - for _, fn := range profile.Function { - fnName := profile.StringTable[fn.Name] - names = append(names, fnName) - } - Expect(names).To(ConsistOf(fnNames)) - }) - }) - Context("SystemName", func() { - It("Should have corresponding StringTable entries", func() { - var names []string - for _, fn := range profile.Function { - fnName := profile.StringTable[fn.SystemName] - names = append(names, fnName) - } - Expect(names).To(ConsistOf(fnNames)) - }) - }) - }) - Describe("Location", func() { - It("Should build correctly", func() { - Expect(len(profile.Location)).To(Equal(14)) - for _, l := range profile.Location { - Expect(l.Id).NotTo(BeZero()) - Expect(l.Line).NotTo(BeZero()) - Expect(l.Line[0].FunctionId).NotTo(BeZero()) - } - }) - It("Should have corresponding functions", func() { - fnMap := make(map[uint64]*Function) - for _, fn := range profile.Function { - fnMap[fn.Id] = fn - } - for _, l := range profile.Location { - fnID := l.Line[0].FunctionId - _, ok := fnMap[fnID] - Expect(ok).To(BeTrue()) - } - }) - }) - Describe("Sample", func() { - It("Should build correctly", func() { - Expect(len(profile.Sample)).To(Equal(8)) - for _, s := range profile.Sample { - Expect(s.LocationId).NotTo(BeZero()) - Expect(s.Value).NotTo(BeZero()) - } - }) - It("Should have corresponding locations", func() { - lMap := make(map[uint64]*Location) - for _, l := range profile.Location { - lMap[l.Id] = l - } - for _, s := range profile.Sample { - for _, l := range s.LocationId { - _, ok := lMap[l] - Expect(ok).To(BeTrue()) - } - } - }) - }) + } }) -}) +} diff --git a/pkg/og/storage/tree/profile.pb.go b/pkg/og/storage/tree/profile.pb.go deleted file mode 100644 index fdf226a6f0..0000000000 --- a/pkg/og/storage/tree/profile.pb.go +++ /dev/null @@ -1,1116 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Profile is a common stacktrace profile format. -// -// Measurements represented with this format should follow the -// following conventions: -// -// - Consumers should treat unset optional fields as if they had been -// set with their default value. -// -// - When possible, measurements should be stored in "unsampled" form -// that is most useful to humans. There should be enough -// information present to determine the original sampled values. -// -// - On-disk, the serialized proto must be gzip-compressed. -// -// - The profile is represented as a set of samples, where each sample -// references a sequence of locations, and where each location belongs -// to a mapping. -// - There is a N->1 relationship from sample.location_id entries to -// locations. For every sample.location_id entry there must be a -// unique Location with that id. -// - There is an optional N->1 relationship from locations to -// mappings. For every nonzero Location.mapping_id there must be a -// unique Mapping with that id. - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.34.1 -// protoc (unknown) -// source: og/storage/tree/profile.proto - -package tree - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Profile struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // A description of the samples associated with each Sample.value. - // For a cpu profile this might be: - // - // [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]] - // - // For a heap profile, this might be: - // - // [["allocations","count"], ["space","bytes"]], - // - // If one of the values represents the number of events represented - // by the sample, by convention it should be at index 0 and use - // sample_type.unit == "count". - SampleType []*ValueType `protobuf:"bytes,1,rep,name=sample_type,json=sampleType,proto3" json:"sample_type,omitempty"` - // The set of samples recorded in this profile. - Sample []*Sample `protobuf:"bytes,2,rep,name=sample,proto3" json:"sample,omitempty"` - // Mapping from address ranges to the image/binary/library mapped - // into that address range. mapping[0] will be the main binary. - Mapping []*Mapping `protobuf:"bytes,3,rep,name=mapping,proto3" json:"mapping,omitempty"` - // Useful program location - Location []*Location `protobuf:"bytes,4,rep,name=location,proto3" json:"location,omitempty"` - // Functions referenced by locations - Function []*Function `protobuf:"bytes,5,rep,name=function,proto3" json:"function,omitempty"` - // A common table for strings referenced by various messages. - // string_table[0] must always be "". - StringTable []string `protobuf:"bytes,6,rep,name=string_table,json=stringTable,proto3" json:"string_table,omitempty"` - // frames with Function.function_name fully matching the following - // regexp will be dropped from the samples, along with their successors. - DropFrames int64 `protobuf:"varint,7,opt,name=drop_frames,json=dropFrames,proto3" json:"drop_frames,omitempty"` // Index into string table. - // frames with Function.function_name fully matching the following - // regexp will be kept, even if it matches drop_functions. - KeepFrames int64 `protobuf:"varint,8,opt,name=keep_frames,json=keepFrames,proto3" json:"keep_frames,omitempty"` // Index into string table. - // Time of collection (UTC) represented as nanoseconds past the epoch. - TimeNanos int64 `protobuf:"varint,9,opt,name=time_nanos,json=timeNanos,proto3" json:"time_nanos,omitempty"` - // Duration of the profile, if a duration makes sense. - DurationNanos int64 `protobuf:"varint,10,opt,name=duration_nanos,json=durationNanos,proto3" json:"duration_nanos,omitempty"` - // The kind of events between sampled ocurrences. - // e.g [ "cpu","cycles" ] or [ "heap","bytes" ] - PeriodType *ValueType `protobuf:"bytes,11,opt,name=period_type,json=periodType,proto3" json:"period_type,omitempty"` - // The number of events between sampled occurrences. - Period int64 `protobuf:"varint,12,opt,name=period,proto3" json:"period,omitempty"` - // Freeform text associated to the profile. - Comment []int64 `protobuf:"varint,13,rep,packed,name=comment,proto3" json:"comment,omitempty"` // Indices into string table. - // Index into the string table of the type of the preferred sample - // value. If unset, clients should default to the last sample value. - DefaultSampleType int64 `protobuf:"varint,14,opt,name=default_sample_type,json=defaultSampleType,proto3" json:"default_sample_type,omitempty"` -} - -func (x *Profile) Reset() { - *x = Profile{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Profile) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Profile) ProtoMessage() {} - -func (x *Profile) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Profile.ProtoReflect.Descriptor instead. -func (*Profile) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{0} -} - -func (x *Profile) GetSampleType() []*ValueType { - if x != nil { - return x.SampleType - } - return nil -} - -func (x *Profile) GetSample() []*Sample { - if x != nil { - return x.Sample - } - return nil -} - -func (x *Profile) GetMapping() []*Mapping { - if x != nil { - return x.Mapping - } - return nil -} - -func (x *Profile) GetLocation() []*Location { - if x != nil { - return x.Location - } - return nil -} - -func (x *Profile) GetFunction() []*Function { - if x != nil { - return x.Function - } - return nil -} - -func (x *Profile) GetStringTable() []string { - if x != nil { - return x.StringTable - } - return nil -} - -func (x *Profile) GetDropFrames() int64 { - if x != nil { - return x.DropFrames - } - return 0 -} - -func (x *Profile) GetKeepFrames() int64 { - if x != nil { - return x.KeepFrames - } - return 0 -} - -func (x *Profile) GetTimeNanos() int64 { - if x != nil { - return x.TimeNanos - } - return 0 -} - -func (x *Profile) GetDurationNanos() int64 { - if x != nil { - return x.DurationNanos - } - return 0 -} - -func (x *Profile) GetPeriodType() *ValueType { - if x != nil { - return x.PeriodType - } - return nil -} - -func (x *Profile) GetPeriod() int64 { - if x != nil { - return x.Period - } - return 0 -} - -func (x *Profile) GetComment() []int64 { - if x != nil { - return x.Comment - } - return nil -} - -func (x *Profile) GetDefaultSampleType() int64 { - if x != nil { - return x.DefaultSampleType - } - return 0 -} - -// ValueType describes the semantics and measurement units of a value. -type ValueType struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Type int64 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` // Index into string table. - Unit int64 `protobuf:"varint,2,opt,name=unit,proto3" json:"unit,omitempty"` // Index into string table. -} - -func (x *ValueType) Reset() { - *x = ValueType{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ValueType) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ValueType) ProtoMessage() {} - -func (x *ValueType) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ValueType.ProtoReflect.Descriptor instead. -func (*ValueType) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{1} -} - -func (x *ValueType) GetType() int64 { - if x != nil { - return x.Type - } - return 0 -} - -func (x *ValueType) GetUnit() int64 { - if x != nil { - return x.Unit - } - return 0 -} - -// Each Sample records values encountered in some program -// context. The program context is typically a stack trace, perhaps -// augmented with auxiliary information like the thread-id, some -// indicator of a higher level request being handled etc. -type Sample struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The ids recorded here correspond to a Profile.location.id. - // The leaf is at location_id[0]. - LocationId []uint64 `protobuf:"varint,1,rep,packed,name=location_id,json=locationId,proto3" json:"location_id,omitempty"` - // The type and unit of each value is defined by the corresponding - // entry in Profile.sample_type. All samples must have the same - // number of values, the same as the length of Profile.sample_type. - // When aggregating multiple samples into a single sample, the - // result has a list of values that is the element-wise sum of the - // lists of the originals. - Value []int64 `protobuf:"varint,2,rep,packed,name=value,proto3" json:"value,omitempty"` - // label includes additional context for this sample. It can include - // things like a thread id, allocation size, etc - Label []*Label `protobuf:"bytes,3,rep,name=label,proto3" json:"label,omitempty"` -} - -func (x *Sample) Reset() { - *x = Sample{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Sample) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Sample) ProtoMessage() {} - -func (x *Sample) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Sample.ProtoReflect.Descriptor instead. -func (*Sample) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{2} -} - -func (x *Sample) GetLocationId() []uint64 { - if x != nil { - return x.LocationId - } - return nil -} - -func (x *Sample) GetValue() []int64 { - if x != nil { - return x.Value - } - return nil -} - -func (x *Sample) GetLabel() []*Label { - if x != nil { - return x.Label - } - return nil -} - -type Label struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Key int64 `protobuf:"varint,1,opt,name=key,proto3" json:"key,omitempty"` // Index into string table - // At most one of the following must be present - Str int64 `protobuf:"varint,2,opt,name=str,proto3" json:"str,omitempty"` // Index into string table - Num int64 `protobuf:"varint,3,opt,name=num,proto3" json:"num,omitempty"` - // Should only be present when num is present. - // Specifies the units of num. - // Use arbitrary string (for example, "requests") as a custom count unit. - // If no unit is specified, consumer may apply heuristic to deduce the unit. - // Consumers may also interpret units like "bytes" and "kilobytes" as memory - // units and units like "seconds" and "nanoseconds" as time units, - // and apply appropriate unit conversions to these. - NumUnit int64 `protobuf:"varint,4,opt,name=num_unit,json=numUnit,proto3" json:"num_unit,omitempty"` // Index into string table -} - -func (x *Label) Reset() { - *x = Label{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Label) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Label) ProtoMessage() {} - -func (x *Label) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Label.ProtoReflect.Descriptor instead. -func (*Label) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{3} -} - -func (x *Label) GetKey() int64 { - if x != nil { - return x.Key - } - return 0 -} - -func (x *Label) GetStr() int64 { - if x != nil { - return x.Str - } - return 0 -} - -func (x *Label) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -func (x *Label) GetNumUnit() int64 { - if x != nil { - return x.NumUnit - } - return 0 -} - -type Mapping struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Unique nonzero id for the mapping. - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - // Address at which the binary (or DLL) is loaded into memory. - MemoryStart uint64 `protobuf:"varint,2,opt,name=memory_start,json=memoryStart,proto3" json:"memory_start,omitempty"` - // The limit of the address range occupied by this mapping. - MemoryLimit uint64 `protobuf:"varint,3,opt,name=memory_limit,json=memoryLimit,proto3" json:"memory_limit,omitempty"` - // Offset in the binary that corresponds to the first mapped address. - FileOffset uint64 `protobuf:"varint,4,opt,name=file_offset,json=fileOffset,proto3" json:"file_offset,omitempty"` - // The object this entry is loaded from. This can be a filename on - // disk for the main binary and shared libraries, or virtual - // abstractions like "[vdso]". - Filename int64 `protobuf:"varint,5,opt,name=filename,proto3" json:"filename,omitempty"` // Index into string table - // A string that uniquely identifies a particular program version - // with high probability. E.g., for binaries generated by GNU tools, - // it could be the contents of the .note.gnu.build-id field. - BuildId int64 `protobuf:"varint,6,opt,name=build_id,json=buildId,proto3" json:"build_id,omitempty"` // Index into string table - // The following fields indicate the resolution of symbolic info. - HasFunctions bool `protobuf:"varint,7,opt,name=has_functions,json=hasFunctions,proto3" json:"has_functions,omitempty"` - HasFilenames bool `protobuf:"varint,8,opt,name=has_filenames,json=hasFilenames,proto3" json:"has_filenames,omitempty"` - HasLineNumbers bool `protobuf:"varint,9,opt,name=has_line_numbers,json=hasLineNumbers,proto3" json:"has_line_numbers,omitempty"` - HasInlineFrames bool `protobuf:"varint,10,opt,name=has_inline_frames,json=hasInlineFrames,proto3" json:"has_inline_frames,omitempty"` -} - -func (x *Mapping) Reset() { - *x = Mapping{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Mapping) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Mapping) ProtoMessage() {} - -func (x *Mapping) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Mapping.ProtoReflect.Descriptor instead. -func (*Mapping) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{4} -} - -func (x *Mapping) GetId() uint64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Mapping) GetMemoryStart() uint64 { - if x != nil { - return x.MemoryStart - } - return 0 -} - -func (x *Mapping) GetMemoryLimit() uint64 { - if x != nil { - return x.MemoryLimit - } - return 0 -} - -func (x *Mapping) GetFileOffset() uint64 { - if x != nil { - return x.FileOffset - } - return 0 -} - -func (x *Mapping) GetFilename() int64 { - if x != nil { - return x.Filename - } - return 0 -} - -func (x *Mapping) GetBuildId() int64 { - if x != nil { - return x.BuildId - } - return 0 -} - -func (x *Mapping) GetHasFunctions() bool { - if x != nil { - return x.HasFunctions - } - return false -} - -func (x *Mapping) GetHasFilenames() bool { - if x != nil { - return x.HasFilenames - } - return false -} - -func (x *Mapping) GetHasLineNumbers() bool { - if x != nil { - return x.HasLineNumbers - } - return false -} - -func (x *Mapping) GetHasInlineFrames() bool { - if x != nil { - return x.HasInlineFrames - } - return false -} - -// Describes function and line table debug information. -type Location struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Unique nonzero id for the location. A profile could use - // instruction addresses or any integer sequence as ids. - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - // The id of the corresponding profile.Mapping for this location. - // It can be unset if the mapping is unknown or not applicable for - // this profile type. - MappingId uint64 `protobuf:"varint,2,opt,name=mapping_id,json=mappingId,proto3" json:"mapping_id,omitempty"` - // The instruction address for this location, if available. It - // should be within [Mapping.memory_start...Mapping.memory_limit] - // for the corresponding mapping. A non-leaf address may be in the - // middle of a call instruction. It is up to display tools to find - // the beginning of the instruction if necessary. - Address uint64 `protobuf:"varint,3,opt,name=address,proto3" json:"address,omitempty"` - // Multiple line indicates this location has inlined functions, - // where the last entry represents the caller into which the - // preceding entries were inlined. - // - // E.g., if memcpy() is inlined into printf: - // - // line[0].function_name == "memcpy" - // line[1].function_name == "printf" - Line []*Line `protobuf:"bytes,4,rep,name=line,proto3" json:"line,omitempty"` - // Provides an indication that multiple symbols map to this location's - // address, for example due to identical code folding by the linker. In that - // case the line information above represents one of the multiple - // symbols. This field must be recomputed when the symbolization state of the - // profile changes. - IsFolded bool `protobuf:"varint,5,opt,name=is_folded,json=isFolded,proto3" json:"is_folded,omitempty"` -} - -func (x *Location) Reset() { - *x = Location{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Location) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Location) ProtoMessage() {} - -func (x *Location) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Location.ProtoReflect.Descriptor instead. -func (*Location) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{5} -} - -func (x *Location) GetId() uint64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Location) GetMappingId() uint64 { - if x != nil { - return x.MappingId - } - return 0 -} - -func (x *Location) GetAddress() uint64 { - if x != nil { - return x.Address - } - return 0 -} - -func (x *Location) GetLine() []*Line { - if x != nil { - return x.Line - } - return nil -} - -func (x *Location) GetIsFolded() bool { - if x != nil { - return x.IsFolded - } - return false -} - -type Line struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The id of the corresponding profile.Function for this line. - FunctionId uint64 `protobuf:"varint,1,opt,name=function_id,json=functionId,proto3" json:"function_id,omitempty"` - // Line number in source code. - Line int64 `protobuf:"varint,2,opt,name=line,proto3" json:"line,omitempty"` -} - -func (x *Line) Reset() { - *x = Line{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Line) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Line) ProtoMessage() {} - -func (x *Line) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Line.ProtoReflect.Descriptor instead. -func (*Line) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{6} -} - -func (x *Line) GetFunctionId() uint64 { - if x != nil { - return x.FunctionId - } - return 0 -} - -func (x *Line) GetLine() int64 { - if x != nil { - return x.Line - } - return 0 -} - -type Function struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Unique nonzero id for the function. - Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - // Name of the function, in human-readable form if available. - Name int64 `protobuf:"varint,2,opt,name=name,proto3" json:"name,omitempty"` // Index into string table - // Name of the function, as identified by the system. - // For instance, it can be a C++ mangled name. - SystemName int64 `protobuf:"varint,3,opt,name=system_name,json=systemName,proto3" json:"system_name,omitempty"` // Index into string table - // Source file containing the function. - Filename int64 `protobuf:"varint,4,opt,name=filename,proto3" json:"filename,omitempty"` // Index into string table - // Line number in source file. - StartLine int64 `protobuf:"varint,5,opt,name=start_line,json=startLine,proto3" json:"start_line,omitempty"` -} - -func (x *Function) Reset() { - *x = Function{} - if protoimpl.UnsafeEnabled { - mi := &file_og_storage_tree_profile_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Function) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Function) ProtoMessage() {} - -func (x *Function) ProtoReflect() protoreflect.Message { - mi := &file_og_storage_tree_profile_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Function.ProtoReflect.Descriptor instead. -func (*Function) Descriptor() ([]byte, []int) { - return file_og_storage_tree_profile_proto_rawDescGZIP(), []int{7} -} - -func (x *Function) GetId() uint64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *Function) GetName() int64 { - if x != nil { - return x.Name - } - return 0 -} - -func (x *Function) GetSystemName() int64 { - if x != nil { - return x.SystemName - } - return 0 -} - -func (x *Function) GetFilename() int64 { - if x != nil { - return x.Filename - } - return 0 -} - -func (x *Function) GetStartLine() int64 { - if x != nil { - return x.StartLine - } - return 0 -} - -var File_og_storage_tree_profile_proto protoreflect.FileDescriptor - -var file_og_storage_tree_profile_proto_rawDesc = []byte{ - 0x0a, 0x1d, 0x6f, 0x67, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x72, 0x65, - 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x17, 0x70, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x22, 0x93, 0x05, 0x0a, 0x07, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x12, 0x43, 0x0a, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x65, 0x72, 0x66, - 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, - 0x72, 0x65, 0x65, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x73, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x65, 0x72, 0x66, - 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, - 0x72, 0x65, 0x65, 0x2e, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x06, 0x73, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x4d, 0x61, - 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3d, - 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, - 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, - 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, - 0x1f, 0x0a, 0x0b, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x72, 0x6f, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, - 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x4e, 0x61, 0x6e, 0x6f, 0x73, - 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, - 0x6f, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x43, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x69, 0x6f, - 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, - 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x0a, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x70, 0x65, - 0x72, 0x69, 0x6f, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, - 0x0d, 0x20, 0x03, 0x28, 0x03, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2e, - 0x0a, 0x13, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x33, - 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x75, - 0x6e, 0x69, 0x74, 0x22, 0x75, 0x0a, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1f, 0x0a, - 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x04, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0x58, 0x0a, 0x05, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x03, 0x73, 0x74, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, - 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, - 0x55, 0x6e, 0x69, 0x74, 0x22, 0xd7, 0x02, 0x0a, 0x07, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x69, 0x6c, - 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x23, - 0x0a, 0x0d, 0x68, 0x61, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x68, 0x61, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x68, 0x61, 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x68, 0x61, 0x73, 0x46, - 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x68, 0x61, 0x73, 0x5f, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x4c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x68, 0x61, 0x73, 0x5f, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, - 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x68, - 0x61, 0x73, 0x49, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xa3, - 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, - 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x31, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x4c, 0x69, 0x6e, - 0x65, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x66, 0x6f, - 0x6c, 0x64, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x46, 0x6f, - 0x6c, 0x64, 0x65, 0x64, 0x22, 0x3b, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, - 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x08, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x42, 0xdb, - 0x01, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x42, 0x0c, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, - 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x70, 0x6b, 0x67, - 0x2f, 0x6f, 0x67, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x72, 0x65, 0x65, - 0xa2, 0x02, 0x03, 0x50, 0x50, 0x54, 0xaa, 0x02, 0x17, 0x50, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, - 0x6c, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x54, 0x72, 0x65, 0x65, - 0xca, 0x02, 0x17, 0x50, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x5c, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5c, 0x54, 0x72, 0x65, 0x65, 0xe2, 0x02, 0x23, 0x50, 0x65, 0x72, - 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x5c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5c, - 0x54, 0x72, 0x65, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x19, 0x50, 0x65, 0x72, 0x66, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x3a, 0x3a, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x3a, 0x54, 0x72, 0x65, 0x65, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_og_storage_tree_profile_proto_rawDescOnce sync.Once - file_og_storage_tree_profile_proto_rawDescData = file_og_storage_tree_profile_proto_rawDesc -) - -func file_og_storage_tree_profile_proto_rawDescGZIP() []byte { - file_og_storage_tree_profile_proto_rawDescOnce.Do(func() { - file_og_storage_tree_profile_proto_rawDescData = protoimpl.X.CompressGZIP(file_og_storage_tree_profile_proto_rawDescData) - }) - return file_og_storage_tree_profile_proto_rawDescData -} - -var file_og_storage_tree_profile_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_og_storage_tree_profile_proto_goTypes = []interface{}{ - (*Profile)(nil), // 0: perftools.profiles.tree.Profile - (*ValueType)(nil), // 1: perftools.profiles.tree.ValueType - (*Sample)(nil), // 2: perftools.profiles.tree.Sample - (*Label)(nil), // 3: perftools.profiles.tree.Label - (*Mapping)(nil), // 4: perftools.profiles.tree.Mapping - (*Location)(nil), // 5: perftools.profiles.tree.Location - (*Line)(nil), // 6: perftools.profiles.tree.Line - (*Function)(nil), // 7: perftools.profiles.tree.Function -} -var file_og_storage_tree_profile_proto_depIdxs = []int32{ - 1, // 0: perftools.profiles.tree.Profile.sample_type:type_name -> perftools.profiles.tree.ValueType - 2, // 1: perftools.profiles.tree.Profile.sample:type_name -> perftools.profiles.tree.Sample - 4, // 2: perftools.profiles.tree.Profile.mapping:type_name -> perftools.profiles.tree.Mapping - 5, // 3: perftools.profiles.tree.Profile.location:type_name -> perftools.profiles.tree.Location - 7, // 4: perftools.profiles.tree.Profile.function:type_name -> perftools.profiles.tree.Function - 1, // 5: perftools.profiles.tree.Profile.period_type:type_name -> perftools.profiles.tree.ValueType - 3, // 6: perftools.profiles.tree.Sample.label:type_name -> perftools.profiles.tree.Label - 6, // 7: perftools.profiles.tree.Location.line:type_name -> perftools.profiles.tree.Line - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name -} - -func init() { file_og_storage_tree_profile_proto_init() } -func file_og_storage_tree_profile_proto_init() { - if File_og_storage_tree_profile_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_og_storage_tree_profile_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Profile); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_og_storage_tree_profile_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValueType); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_og_storage_tree_profile_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Sample); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_og_storage_tree_profile_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Label); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_og_storage_tree_profile_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Mapping); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_og_storage_tree_profile_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Location); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_og_storage_tree_profile_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Line); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_og_storage_tree_profile_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Function); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_og_storage_tree_profile_proto_rawDesc, - NumEnums: 0, - NumMessages: 8, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_og_storage_tree_profile_proto_goTypes, - DependencyIndexes: file_og_storage_tree_profile_proto_depIdxs, - MessageInfos: file_og_storage_tree_profile_proto_msgTypes, - }.Build() - File_og_storage_tree_profile_proto = out.File - file_og_storage_tree_profile_proto_rawDesc = nil - file_og_storage_tree_profile_proto_goTypes = nil - file_og_storage_tree_profile_proto_depIdxs = nil -} diff --git a/pkg/og/storage/tree/profile.proto b/pkg/og/storage/tree/profile.proto deleted file mode 100644 index df19b4ede9..0000000000 --- a/pkg/og/storage/tree/profile.proto +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Profile is a common stacktrace profile format. -// -// Measurements represented with this format should follow the -// following conventions: -// -// - Consumers should treat unset optional fields as if they had been -// set with their default value. -// -// - When possible, measurements should be stored in "unsampled" form -// that is most useful to humans. There should be enough -// information present to determine the original sampled values. -// -// - On-disk, the serialized proto must be gzip-compressed. -// -// - The profile is represented as a set of samples, where each sample -// references a sequence of locations, and where each location belongs -// to a mapping. -// - There is a N->1 relationship from sample.location_id entries to -// locations. For every sample.location_id entry there must be a -// unique Location with that id. -// - There is an optional N->1 relationship from locations to -// mappings. For every nonzero Location.mapping_id there must be a -// unique Mapping with that id. - -syntax = "proto3"; - -package perftools.profiles.tree; - -option go_package = "pkg/tree"; - -message Profile { - // A description of the samples associated with each Sample.value. - // For a cpu profile this might be: - // [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]] - // For a heap profile, this might be: - // [["allocations","count"], ["space","bytes"]], - // If one of the values represents the number of events represented - // by the sample, by convention it should be at index 0 and use - // sample_type.unit == "count". - repeated ValueType sample_type = 1; - // The set of samples recorded in this profile. - repeated Sample sample = 2; - // Mapping from address ranges to the image/binary/library mapped - // into that address range. mapping[0] will be the main binary. - repeated Mapping mapping = 3; - // Useful program location - repeated Location location = 4; - // Functions referenced by locations - repeated Function function = 5; - // A common table for strings referenced by various messages. - // string_table[0] must always be "". - repeated string string_table = 6; - // frames with Function.function_name fully matching the following - // regexp will be dropped from the samples, along with their successors. - int64 drop_frames = 7; // Index into string table. - // frames with Function.function_name fully matching the following - // regexp will be kept, even if it matches drop_functions. - int64 keep_frames = 8; // Index into string table. - - // The following fields are informational, do not affect - // interpretation of results. - - // Time of collection (UTC) represented as nanoseconds past the epoch. - int64 time_nanos = 9; - // Duration of the profile, if a duration makes sense. - int64 duration_nanos = 10; - // The kind of events between sampled ocurrences. - // e.g [ "cpu","cycles" ] or [ "heap","bytes" ] - ValueType period_type = 11; - // The number of events between sampled occurrences. - int64 period = 12; - // Freeform text associated to the profile. - repeated int64 comment = 13; // Indices into string table. - // Index into the string table of the type of the preferred sample - // value. If unset, clients should default to the last sample value. - int64 default_sample_type = 14; -} - -// ValueType describes the semantics and measurement units of a value. -message ValueType { - int64 type = 1; // Index into string table. - int64 unit = 2; // Index into string table. -} - -// Each Sample records values encountered in some program -// context. The program context is typically a stack trace, perhaps -// augmented with auxiliary information like the thread-id, some -// indicator of a higher level request being handled etc. -message Sample { - // The ids recorded here correspond to a Profile.location.id. - // The leaf is at location_id[0]. - repeated uint64 location_id = 1; - // The type and unit of each value is defined by the corresponding - // entry in Profile.sample_type. All samples must have the same - // number of values, the same as the length of Profile.sample_type. - // When aggregating multiple samples into a single sample, the - // result has a list of values that is the element-wise sum of the - // lists of the originals. - repeated int64 value = 2; - // label includes additional context for this sample. It can include - // things like a thread id, allocation size, etc - repeated Label label = 3; -} - -message Label { - int64 key = 1; // Index into string table - - // At most one of the following must be present - int64 str = 2; // Index into string table - int64 num = 3; - - // Should only be present when num is present. - // Specifies the units of num. - // Use arbitrary string (for example, "requests") as a custom count unit. - // If no unit is specified, consumer may apply heuristic to deduce the unit. - // Consumers may also interpret units like "bytes" and "kilobytes" as memory - // units and units like "seconds" and "nanoseconds" as time units, - // and apply appropriate unit conversions to these. - int64 num_unit = 4; // Index into string table -} - -message Mapping { - // Unique nonzero id for the mapping. - uint64 id = 1; - // Address at which the binary (or DLL) is loaded into memory. - uint64 memory_start = 2; - // The limit of the address range occupied by this mapping. - uint64 memory_limit = 3; - // Offset in the binary that corresponds to the first mapped address. - uint64 file_offset = 4; - // The object this entry is loaded from. This can be a filename on - // disk for the main binary and shared libraries, or virtual - // abstractions like "[vdso]". - int64 filename = 5; // Index into string table - // A string that uniquely identifies a particular program version - // with high probability. E.g., for binaries generated by GNU tools, - // it could be the contents of the .note.gnu.build-id field. - int64 build_id = 6; // Index into string table - - // The following fields indicate the resolution of symbolic info. - bool has_functions = 7; - bool has_filenames = 8; - bool has_line_numbers = 9; - bool has_inline_frames = 10; -} - -// Describes function and line table debug information. -message Location { - // Unique nonzero id for the location. A profile could use - // instruction addresses or any integer sequence as ids. - uint64 id = 1; - // The id of the corresponding profile.Mapping for this location. - // It can be unset if the mapping is unknown or not applicable for - // this profile type. - uint64 mapping_id = 2; - // The instruction address for this location, if available. It - // should be within [Mapping.memory_start...Mapping.memory_limit] - // for the corresponding mapping. A non-leaf address may be in the - // middle of a call instruction. It is up to display tools to find - // the beginning of the instruction if necessary. - uint64 address = 3; - // Multiple line indicates this location has inlined functions, - // where the last entry represents the caller into which the - // preceding entries were inlined. - // - // E.g., if memcpy() is inlined into printf: - // line[0].function_name == "memcpy" - // line[1].function_name == "printf" - repeated Line line = 4; - // Provides an indication that multiple symbols map to this location's - // address, for example due to identical code folding by the linker. In that - // case the line information above represents one of the multiple - // symbols. This field must be recomputed when the symbolization state of the - // profile changes. - bool is_folded = 5; -} - -message Line { - // The id of the corresponding profile.Function for this line. - uint64 function_id = 1; - // Line number in source code. - int64 line = 2; -} - -message Function { - // Unique nonzero id for the function. - uint64 id = 1; - // Name of the function, in human-readable form if available. - int64 name = 2; // Index into string table - // Name of the function, as identified by the system. - // For instance, it can be a C++ mangled name. - int64 system_name = 3; // Index into string table - // Source file containing the function. - int64 filename = 4; // Index into string table - // Line number in source file. - int64 start_line = 5; -} diff --git a/pkg/og/storage/tree/profile_extra.go b/pkg/og/storage/tree/profile_extra.go index 1c3be606ea..5ae260e92c 100644 --- a/pkg/og/storage/tree/profile_extra.go +++ b/pkg/og/storage/tree/profile_extra.go @@ -3,11 +3,10 @@ package tree // These functions are kept separately as profile.pb.go is a generated file import ( - "encoding/binary" "sort" - "github.com/cespare/xxhash/v2" - "github.com/grafana/pyroscope/pkg/og/agent/spy" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/v2/pkg/og/agent/spy" "github.com/valyala/bytebufferpool" ) @@ -27,7 +26,7 @@ func newCache() *cache { } } -func getCacheKey(l []*Label) cacheKey { +func getCacheKey(l []*profilev1.Label) cacheKey { r := []int64{} for _, x := range l { if x.Str != 0 { @@ -49,7 +48,7 @@ func eq(a, b []int64) bool { return true } -func (c *cache) pprofLabelsToSpyLabels(x *Profile, pprofLabels []*Label) *spy.Labels { +func (c *cache) pprofLabelsToSpyLabels(x *profilev1.Profile, pprofLabels []*profilev1.Label) *spy.Labels { k := getCacheKey(pprofLabels) for _, e := range c.data { if eq(e.key, k) { @@ -71,7 +70,7 @@ func (c *cache) pprofLabelsToSpyLabels(x *Profile, pprofLabels []*Label) *spy.La return l } -func (x *Profile) Get(sampleType string, cb func(labels *spy.Labels, name []byte, val int) error) error { +func Get(x *profilev1.Profile, sampleType string, cb func(labels *spy.Labels, name []byte, val int) error) error { valueIndex := 0 if sampleType != "" { for i, v := range x.SampleType { @@ -110,7 +109,7 @@ func (x *Profile) Get(sampleType string, cb func(labels *spy.Labels, name []byte return nil } -func (x *Profile) SampleTypes() []string { +func SampleTypes(x *profilev1.Profile) []string { r := []string{} for _, v := range x.SampleType { r = append(r, x.StringTable[v.Type]) @@ -118,7 +117,7 @@ func (x *Profile) SampleTypes() []string { return r } -func FindFunctionName(x *Profile, locID uint64) (string, bool) { +func FindFunctionName(x *profilev1.Profile, locID uint64) (string, bool) { if loc, ok := FindLocation(x, locID); ok { if len(loc.Line) <= 0 { return "", false @@ -131,7 +130,7 @@ func FindFunctionName(x *Profile, locID uint64) (string, bool) { return "", false } -func FindLocation(x *Profile, lid uint64) (*Location, bool) { +func FindLocation(x *profilev1.Profile, lid uint64) (*profilev1.Location, bool) { idx := sort.Search(len(x.Location), func(i int) bool { return x.Location[i].Id >= lid }) @@ -143,7 +142,7 @@ func FindLocation(x *Profile, lid uint64) (*Location, bool) { return nil, false } -func FindFunction(x *Profile, fid uint64) (*Function, bool) { +func FindFunction(x *profilev1.Profile, fid uint64) (*profilev1.Function, bool) { idx := sort.Search(len(x.Function), func(i int) bool { return x.Function[i].Id >= fid }) @@ -154,50 +153,3 @@ func FindFunction(x *Profile, fid uint64) (*Function, bool) { } return nil, false } - -func (x *Profile) ResolveLabels(l Labels) map[string]string { - m := make(map[string]string, len(l)) - for _, label := range l { - if label.Str != 0 { - m[x.StringTable[label.Key]] = x.StringTable[label.Str] - } - } - return m -} - -func (x *Profile) ResolveLabelName(l *Label) (string, bool) { - if l.Str > 0 && l.Key < int64(len(x.StringTable)) { - return x.StringTable[l.Key], true - } - return "", false -} - -func (x *Profile) ResolveSampleType(v int64) (*ValueType, bool) { - for _, vt := range x.SampleType { - if vt.Type == v { - return vt, true - } - } - return nil, false -} - -type Labels []*Label - -func (l Labels) Len() int { return len(l) } -func (l Labels) Less(i, j int) bool { return l[i].Key < l[j].Key } -func (l Labels) Swap(i, j int) { l[i], l[j] = l[j], l[i] } - -func (l Labels) Hash() uint64 { - h := xxhash.New() - t := make([]byte, 16) - sort.Sort(l) - for _, x := range l { - if x.Str == 0 { - continue - } - binary.LittleEndian.PutUint64(t[0:8], uint64(x.Key)) - binary.LittleEndian.PutUint64(t[8:16], uint64(x.Str)) - _, _ = h.Write(t) - } - return h.Sum64() -} diff --git a/pkg/og/storage/tree/profile_finder.go b/pkg/og/storage/tree/profile_finder.go deleted file mode 100644 index 8bd71b8ba6..0000000000 --- a/pkg/og/storage/tree/profile_finder.go +++ /dev/null @@ -1,169 +0,0 @@ -package tree - -import ( - "sort" -) - -// NewFinder creates an efficient finder for functions or locations in a profile. -// -// It exists to abstract the details of how functions and locations exist in a pprof profile, -// and make it easy to provide an efficient implementation depending on the actual profile format, -// as location and function finding is a recurrent operation while processing pprof profiles. -// -// The [pprof format description](https://github.com/google/pprof/tree/master/proto#general-structure-of-a-profile) -// describes that both locations and functions have unique nonzero ids. -// A [comment in the proto file](https://github.com/google/pprof/blob/master/proto/profile.proto#L164-L166) -// goes further: _A profile could use instruction addresses or any integer sequence as ids_. -// -// Based on this, any uint64 value (except 0) can appear as ids, and a map based cache can be used in that case. -// In practice, [go runtime](https://github.com/golang/go/blob/master/src/runtime/pprof/proto.go#L537) -// generates profiles where locations and functions use consecutive IDs starting from 1, -// making optimized access possible. -// -// Taking advantage of this, the finder will try to: -// - Use direct access to functions and locations indexed by IDs when possible -// (sorting location and function sequences if needed). -// - Use a map based cache otherwise. -func NewFinder(p *Profile) Finder { - return &finder{p: p, lf: nil, ff: nil} -} - -type Finder interface { - FunctionFinder - LocationFinder -} - -// Find location in a profile based on its ID -type LocationFinder interface { - FindLocation(id uint64) (*Location, bool) -} - -// Find function in a profile based on its ID -type FunctionFinder interface { - FindFunction(id uint64) (*Function, bool) -} - -type sliceLocationFinder []*Location - -func (f sliceLocationFinder) FindLocation(id uint64) (*Location, bool) { - if id == 0 || id > uint64(len(f)) { - return nil, false - } - return f[id-1], true -} - -type mapLocationFinder map[uint64]*Location - -func (f mapLocationFinder) FindLocation(id uint64) (*Location, bool) { - loc, ok := f[id] - return loc, ok -} - -type sliceFunctionFinder []*Function - -func (f sliceFunctionFinder) FindFunction(id uint64) (*Function, bool) { - if id == 0 || id > uint64(len(f)) { - return nil, false - } - return f[id-1], true -} - -type mapFunctionFinder map[uint64]*Function - -func (f mapFunctionFinder) FindFunction(id uint64) (*Function, bool) { - fun, ok := f[id] - return fun, ok -} - -// finder is a lazy implementation of Finder, that will be using the most efficient function and location finder. -type finder struct { - p *Profile - lf LocationFinder - ff FunctionFinder -} - -func (f *finder) FindLocation(id uint64) (*Location, bool) { - if f.lf == nil { - var ok bool - f.lf, ok = locationSlice(f.p) - if !ok { - f.lf = locationMap(f.p) - } - } - return f.lf.FindLocation(id) -} - -func (f *finder) FindFunction(id uint64) (*Function, bool) { - if f.ff == nil { - var ok bool - f.ff, ok = functionSlice(f.p) - if !ok { - f.ff = functionMap(f.p) - } - } - return f.ff.FindFunction(id) -} - -func locationSlice(p *Profile) (sliceLocationFinder, bool) { - // Check if it's already sorted first - max := uint64(0) - sorted := true - for i, l := range p.Location { - if l.Id != uint64(i+1) { - sorted = false - if l.Id > max { - max = l.Id - } - } - } - if max > uint64(len(p.Location)) { - // IDs are not consecutive numbers starting at 1, a slice is not good enough - return nil, false - } - if !sorted { - sort.Slice(p.Location, func(i, j int) bool { - return p.Location[i].Id < p.Location[j].Id - }) - } - return sliceLocationFinder(p.Location), true -} - -func locationMap(p *Profile) mapLocationFinder { - m := make(map[uint64]*Location, len(p.Location)) - for _, l := range p.Location { - m[l.Id] = l - } - return mapLocationFinder(m) -} - -func functionSlice(p *Profile) (sliceFunctionFinder, bool) { - // Check if it's already sorted first - max := uint64(0) - sorted := true - for i, f := range p.Function { - if f.Id != uint64(i+1) { - sorted = false - if f.Id > max { - max = f.Id - } - } - } - if max > uint64(len(p.Function)) { - // IDs are not consecutive numbers starting at one, this won't work - return nil, false - } - if !sorted { - sort.Slice(p.Function, func(i, j int) bool { - return p.Function[i].Id < p.Function[j].Id - }) - } - return sliceFunctionFinder(p.Function), true -} - -func functionMap(p *Profile) mapFunctionFinder { - m := make(map[uint64]*Function, len(p.Function)) - for _, f := range p.Function { - m[f.Id] = f - } - return m -} diff --git a/pkg/og/storage/tree/profile_finder_test.go b/pkg/og/storage/tree/profile_finder_test.go deleted file mode 100644 index 54163e8210..0000000000 --- a/pkg/og/storage/tree/profile_finder_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package tree - -import ( - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" -) - -var ( - loc1 = &Location{Id: 1} - loc2 = &Location{Id: 2} - loc3 = &Location{Id: 3} - fun1 = &Function{Id: 1} - fun2 = &Function{Id: 2} - fun3 = &Function{Id: 3} - sortedLocs = &Profile{Location: []*Location{loc1, loc2, loc3}} - unsortedLocs = &Profile{Location: []*Location{loc2, loc3, loc1}} - nonconsecutiveLocs = &Profile{Location: []*Location{loc1, loc3}} - sortedFuns = &Profile{Function: []*Function{fun1, fun2, fun3}} - unsortedFuns = &Profile{Function: []*Function{fun2, fun3, fun1}} - nonconsecutiveFuns = &Profile{Function: []*Function{fun1, fun3}} -) - -var _ = Describe("profile finder", func() { - Describe("Sorted consecutive locations", func() { - It("returns correct results", func() { - finder := NewFinder(sortedLocs) - loc, ok := finder.FindLocation(1) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc1)) - loc, ok = finder.FindLocation(2) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc2)) - loc, ok = finder.FindLocation(3) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc3)) - loc, ok = finder.FindLocation(0) - Expect(ok).To(BeFalse()) - loc, ok = finder.FindLocation(4) - Expect(ok).To(BeFalse()) - }) - }) - Describe("Unsorted consecutive locations", func() { - It("returns correct results", func() { - finder := NewFinder(unsortedLocs) - loc, ok := finder.FindLocation(1) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc1)) - loc, ok = finder.FindLocation(2) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc2)) - loc, ok = finder.FindLocation(3) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc3)) - loc, ok = finder.FindLocation(0) - Expect(ok).To(BeFalse()) - loc, ok = finder.FindLocation(4) - Expect(ok).To(BeFalse()) - }) - }) - Describe("Non-consecutive locations", func() { - It("returns correct results", func() { - finder := NewFinder(nonconsecutiveLocs) - loc, ok := finder.FindLocation(1) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc1)) - loc, ok = finder.FindLocation(2) - Expect(ok).To(BeFalse()) - loc, ok = finder.FindLocation(3) - Expect(ok).To(BeTrue()) - Expect(loc).To(BeIdenticalTo(loc3)) - loc, ok = finder.FindLocation(0) - Expect(ok).To(BeFalse()) - loc, ok = finder.FindLocation(4) - Expect(ok).To(BeFalse()) - }) - }) - Describe("Sorted consecutive functions", func() { - It("returns correct results", func() { - finder := NewFinder(sortedFuns) - fun, ok := finder.FindFunction(1) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun1)) - fun, ok = finder.FindFunction(2) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun2)) - fun, ok = finder.FindFunction(3) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun3)) - fun, ok = finder.FindFunction(0) - Expect(ok).To(BeFalse()) - fun, ok = finder.FindFunction(4) - Expect(ok).To(BeFalse()) - }) - }) - Describe("Unsorted consecutive functions", func() { - It("returns correct results", func() { - finder := NewFinder(unsortedFuns) - fun, ok := finder.FindFunction(1) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun1)) - fun, ok = finder.FindFunction(2) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun2)) - fun, ok = finder.FindFunction(3) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun3)) - fun, ok = finder.FindFunction(0) - Expect(ok).To(BeFalse()) - fun, ok = finder.FindFunction(4) - Expect(ok).To(BeFalse()) - }) - }) - Describe("Non-consecutive functions", func() { - It("returns correct results", func() { - finder := NewFinder(nonconsecutiveFuns) - fun, ok := finder.FindFunction(1) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun1)) - fun, ok = finder.FindFunction(2) - Expect(ok).To(BeFalse()) - fun, ok = finder.FindFunction(3) - Expect(ok).To(BeTrue()) - Expect(fun).To(BeIdenticalTo(fun3)) - fun, ok = finder.FindFunction(0) - Expect(ok).To(BeFalse()) - fun, ok = finder.FindFunction(4) - Expect(ok).To(BeFalse()) - }) - }) -}) diff --git a/pkg/og/storage/tree/profile_vtproto.pb.go b/pkg/og/storage/tree/profile_vtproto.pb.go deleted file mode 100644 index aa01fdf142..0000000000 --- a/pkg/og/storage/tree/profile_vtproto.pb.go +++ /dev/null @@ -1,2550 +0,0 @@ -// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. -// protoc-gen-go-vtproto version: v0.6.0 -// source: og/storage/tree/profile.proto - -package tree - -import ( - fmt "fmt" - protohelpers "github.com/planetscale/vtprotobuf/protohelpers" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - io "io" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -func (m *Profile) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Profile) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *Profile) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if m.DefaultSampleType != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.DefaultSampleType)) - i-- - dAtA[i] = 0x70 - } - if len(m.Comment) > 0 { - var pksize2 int - for _, num := range m.Comment { - pksize2 += protohelpers.SizeOfVarint(uint64(num)) - } - i -= pksize2 - j1 := i - for _, num1 := range m.Comment { - num := uint64(num1) - for num >= 1<<7 { - dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j1++ - } - dAtA[j1] = uint8(num) - j1++ - } - i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) - i-- - dAtA[i] = 0x6a - } - if m.Period != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Period)) - i-- - dAtA[i] = 0x60 - } - if m.PeriodType != nil { - size, err := m.PeriodType.MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0x5a - } - if m.DurationNanos != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.DurationNanos)) - i-- - dAtA[i] = 0x50 - } - if m.TimeNanos != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.TimeNanos)) - i-- - dAtA[i] = 0x48 - } - if m.KeepFrames != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.KeepFrames)) - i-- - dAtA[i] = 0x40 - } - if m.DropFrames != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.DropFrames)) - i-- - dAtA[i] = 0x38 - } - if len(m.StringTable) > 0 { - for iNdEx := len(m.StringTable) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.StringTable[iNdEx]) - copy(dAtA[i:], m.StringTable[iNdEx]) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StringTable[iNdEx]))) - i-- - dAtA[i] = 0x32 - } - } - if len(m.Function) > 0 { - for iNdEx := len(m.Function) - 1; iNdEx >= 0; iNdEx-- { - size, err := m.Function[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0x2a - } - } - if len(m.Location) > 0 { - for iNdEx := len(m.Location) - 1; iNdEx >= 0; iNdEx-- { - size, err := m.Location[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0x22 - } - } - if len(m.Mapping) > 0 { - for iNdEx := len(m.Mapping) - 1; iNdEx >= 0; iNdEx-- { - size, err := m.Mapping[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0x1a - } - } - if len(m.Sample) > 0 { - for iNdEx := len(m.Sample) - 1; iNdEx >= 0; iNdEx-- { - size, err := m.Sample[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0x12 - } - } - if len(m.SampleType) > 0 { - for iNdEx := len(m.SampleType) - 1; iNdEx >= 0; iNdEx-- { - size, err := m.SampleType[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *ValueType) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ValueType) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *ValueType) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if m.Unit != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Unit)) - i-- - dAtA[i] = 0x10 - } - if m.Type != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *Sample) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Sample) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *Sample) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if len(m.Label) > 0 { - for iNdEx := len(m.Label) - 1; iNdEx >= 0; iNdEx-- { - size, err := m.Label[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0x1a - } - } - if len(m.Value) > 0 { - var pksize2 int - for _, num := range m.Value { - pksize2 += protohelpers.SizeOfVarint(uint64(num)) - } - i -= pksize2 - j1 := i - for _, num1 := range m.Value { - num := uint64(num1) - for num >= 1<<7 { - dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j1++ - } - dAtA[j1] = uint8(num) - j1++ - } - i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) - i-- - dAtA[i] = 0x12 - } - if len(m.LocationId) > 0 { - var pksize4 int - for _, num := range m.LocationId { - pksize4 += protohelpers.SizeOfVarint(uint64(num)) - } - i -= pksize4 - j3 := i - for _, num := range m.LocationId { - for num >= 1<<7 { - dAtA[j3] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j3++ - } - dAtA[j3] = uint8(num) - j3++ - } - i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize4)) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *Label) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Label) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *Label) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if m.NumUnit != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.NumUnit)) - i-- - dAtA[i] = 0x20 - } - if m.Num != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Num)) - i-- - dAtA[i] = 0x18 - } - if m.Str != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Str)) - i-- - dAtA[i] = 0x10 - } - if m.Key != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Key)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *Mapping) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Mapping) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *Mapping) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if m.HasInlineFrames { - i-- - if m.HasInlineFrames { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x50 - } - if m.HasLineNumbers { - i-- - if m.HasLineNumbers { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x48 - } - if m.HasFilenames { - i-- - if m.HasFilenames { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x40 - } - if m.HasFunctions { - i-- - if m.HasFunctions { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x38 - } - if m.BuildId != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.BuildId)) - i-- - dAtA[i] = 0x30 - } - if m.Filename != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Filename)) - i-- - dAtA[i] = 0x28 - } - if m.FileOffset != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.FileOffset)) - i-- - dAtA[i] = 0x20 - } - if m.MemoryLimit != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemoryLimit)) - i-- - dAtA[i] = 0x18 - } - if m.MemoryStart != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemoryStart)) - i-- - dAtA[i] = 0x10 - } - if m.Id != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Id)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *Location) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Location) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *Location) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if m.IsFolded { - i-- - if m.IsFolded { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x28 - } - if len(m.Line) > 0 { - for iNdEx := len(m.Line) - 1; iNdEx >= 0; iNdEx-- { - size, err := m.Line[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) - i-- - dAtA[i] = 0x22 - } - } - if m.Address != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Address)) - i-- - dAtA[i] = 0x18 - } - if m.MappingId != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MappingId)) - i-- - dAtA[i] = 0x10 - } - if m.Id != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Id)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *Line) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Line) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *Line) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if m.Line != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Line)) - i-- - dAtA[i] = 0x10 - } - if m.FunctionId != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.FunctionId)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *Function) MarshalVT() (dAtA []byte, err error) { - if m == nil { - return nil, nil - } - size := m.SizeVT() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBufferVT(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Function) MarshalToVT(dAtA []byte) (int, error) { - size := m.SizeVT() - return m.MarshalToSizedBufferVT(dAtA[:size]) -} - -func (m *Function) MarshalToSizedBufferVT(dAtA []byte) (int, error) { - if m == nil { - return 0, nil - } - i := len(dAtA) - _ = i - var l int - _ = l - if m.unknownFields != nil { - i -= len(m.unknownFields) - copy(dAtA[i:], m.unknownFields) - } - if m.StartLine != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StartLine)) - i-- - dAtA[i] = 0x28 - } - if m.Filename != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Filename)) - i-- - dAtA[i] = 0x20 - } - if m.SystemName != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.SystemName)) - i-- - dAtA[i] = 0x18 - } - if m.Name != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Name)) - i-- - dAtA[i] = 0x10 - } - if m.Id != 0 { - i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Id)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -var vtprotoPool_Profile = sync.Pool{ - New: func() interface{} { - return &Profile{} - }, -} - -func (m *Profile) ResetVT() { - if m != nil { - for _, mm := range m.SampleType { - mm.Reset() - } - f0 := m.SampleType[:0] - for _, mm := range m.Sample { - mm.Reset() - } - f1 := m.Sample[:0] - for _, mm := range m.Mapping { - mm.Reset() - } - f2 := m.Mapping[:0] - for _, mm := range m.Location { - mm.Reset() - } - f3 := m.Location[:0] - for _, mm := range m.Function { - mm.Reset() - } - f4 := m.Function[:0] - f5 := m.StringTable[:0] - f6 := m.Comment[:0] - m.Reset() - m.SampleType = f0 - m.Sample = f1 - m.Mapping = f2 - m.Location = f3 - m.Function = f4 - m.StringTable = f5 - m.Comment = f6 - } -} -func (m *Profile) ReturnToVTPool() { - if m != nil { - m.ResetVT() - vtprotoPool_Profile.Put(m) - } -} -func ProfileFromVTPool() *Profile { - return vtprotoPool_Profile.Get().(*Profile) -} -func (m *Profile) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.SampleType) > 0 { - for _, e := range m.SampleType { - l = e.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - if len(m.Sample) > 0 { - for _, e := range m.Sample { - l = e.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - if len(m.Mapping) > 0 { - for _, e := range m.Mapping { - l = e.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - if len(m.Location) > 0 { - for _, e := range m.Location { - l = e.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - if len(m.Function) > 0 { - for _, e := range m.Function { - l = e.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - if len(m.StringTable) > 0 { - for _, s := range m.StringTable { - l = len(s) - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - if m.DropFrames != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.DropFrames)) - } - if m.KeepFrames != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.KeepFrames)) - } - if m.TimeNanos != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.TimeNanos)) - } - if m.DurationNanos != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.DurationNanos)) - } - if m.PeriodType != nil { - l = m.PeriodType.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - if m.Period != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Period)) - } - if len(m.Comment) > 0 { - l = 0 - for _, e := range m.Comment { - l += protohelpers.SizeOfVarint(uint64(e)) - } - n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l - } - if m.DefaultSampleType != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.DefaultSampleType)) - } - n += len(m.unknownFields) - return n -} - -func (m *ValueType) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Type != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Type)) - } - if m.Unit != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Unit)) - } - n += len(m.unknownFields) - return n -} - -func (m *Sample) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.LocationId) > 0 { - l = 0 - for _, e := range m.LocationId { - l += protohelpers.SizeOfVarint(uint64(e)) - } - n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l - } - if len(m.Value) > 0 { - l = 0 - for _, e := range m.Value { - l += protohelpers.SizeOfVarint(uint64(e)) - } - n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l - } - if len(m.Label) > 0 { - for _, e := range m.Label { - l = e.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - n += len(m.unknownFields) - return n -} - -func (m *Label) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Key != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Key)) - } - if m.Str != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Str)) - } - if m.Num != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Num)) - } - if m.NumUnit != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.NumUnit)) - } - n += len(m.unknownFields) - return n -} - -func (m *Mapping) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Id != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Id)) - } - if m.MemoryStart != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.MemoryStart)) - } - if m.MemoryLimit != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.MemoryLimit)) - } - if m.FileOffset != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.FileOffset)) - } - if m.Filename != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Filename)) - } - if m.BuildId != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.BuildId)) - } - if m.HasFunctions { - n += 2 - } - if m.HasFilenames { - n += 2 - } - if m.HasLineNumbers { - n += 2 - } - if m.HasInlineFrames { - n += 2 - } - n += len(m.unknownFields) - return n -} - -func (m *Location) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Id != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Id)) - } - if m.MappingId != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.MappingId)) - } - if m.Address != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Address)) - } - if len(m.Line) > 0 { - for _, e := range m.Line { - l = e.SizeVT() - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - } - if m.IsFolded { - n += 2 - } - n += len(m.unknownFields) - return n -} - -func (m *Line) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.FunctionId != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.FunctionId)) - } - if m.Line != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Line)) - } - n += len(m.unknownFields) - return n -} - -func (m *Function) SizeVT() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Id != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Id)) - } - if m.Name != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Name)) - } - if m.SystemName != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.SystemName)) - } - if m.Filename != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Filename)) - } - if m.StartLine != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.StartLine)) - } - n += len(m.unknownFields) - return n -} - -func (m *Profile) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Profile: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Profile: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SampleType", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if len(m.SampleType) == cap(m.SampleType) { - m.SampleType = append(m.SampleType, &ValueType{}) - } else { - m.SampleType = m.SampleType[:len(m.SampleType)+1] - if m.SampleType[len(m.SampleType)-1] == nil { - m.SampleType[len(m.SampleType)-1] = &ValueType{} - } - } - if err := m.SampleType[len(m.SampleType)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sample", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if len(m.Sample) == cap(m.Sample) { - m.Sample = append(m.Sample, &Sample{}) - } else { - m.Sample = m.Sample[:len(m.Sample)+1] - if m.Sample[len(m.Sample)-1] == nil { - m.Sample[len(m.Sample)-1] = &Sample{} - } - } - if err := m.Sample[len(m.Sample)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Mapping", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if len(m.Mapping) == cap(m.Mapping) { - m.Mapping = append(m.Mapping, &Mapping{}) - } else { - m.Mapping = m.Mapping[:len(m.Mapping)+1] - if m.Mapping[len(m.Mapping)-1] == nil { - m.Mapping[len(m.Mapping)-1] = &Mapping{} - } - } - if err := m.Mapping[len(m.Mapping)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Location", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if len(m.Location) == cap(m.Location) { - m.Location = append(m.Location, &Location{}) - } else { - m.Location = m.Location[:len(m.Location)+1] - if m.Location[len(m.Location)-1] == nil { - m.Location[len(m.Location)-1] = &Location{} - } - } - if err := m.Location[len(m.Location)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Function", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if len(m.Function) == cap(m.Function) { - m.Function = append(m.Function, &Function{}) - } else { - m.Function = m.Function[:len(m.Function)+1] - if m.Function[len(m.Function)-1] == nil { - m.Function[len(m.Function)-1] = &Function{} - } - } - if err := m.Function[len(m.Function)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StringTable", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.StringTable = append(m.StringTable, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DropFrames", wireType) - } - m.DropFrames = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.DropFrames |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field KeepFrames", wireType) - } - m.KeepFrames = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.KeepFrames |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TimeNanos", wireType) - } - m.TimeNanos = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TimeNanos |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DurationNanos", wireType) - } - m.DurationNanos = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.DurationNanos |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PeriodType", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.PeriodType == nil { - m.PeriodType = &ValueType{} - } - if err := m.PeriodType.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 12: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) - } - m.Period = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Period |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 13: - if wireType == 0 { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Comment = append(m.Comment, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.Comment) == 0 && cap(m.Comment) < elementCount { - m.Comment = make([]int64, 0, elementCount) - } - for iNdEx < postIndex { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Comment = append(m.Comment, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Comment", wireType) - } - case 14: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DefaultSampleType", wireType) - } - m.DefaultSampleType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.DefaultSampleType |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ValueType) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ValueType: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ValueType: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) - } - m.Type = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Type |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Unit", wireType) - } - m.Unit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Unit |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Sample) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Sample: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Sample: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType == 0 { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.LocationId = append(m.LocationId, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.LocationId) == 0 { - m.LocationId = make([]uint64, 0, elementCount) - } - for iNdEx < postIndex { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.LocationId = append(m.LocationId, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field LocationId", wireType) - } - case 2: - if wireType == 0 { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Value = append(m.Value, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - var count int - for _, integer := range dAtA[iNdEx:postIndex] { - if integer < 128 { - count++ - } - } - elementCount = count - if elementCount != 0 && len(m.Value) == 0 { - m.Value = make([]int64, 0, elementCount) - } - for iNdEx < postIndex { - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Value = append(m.Value, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Label = append(m.Label, &Label{}) - if err := m.Label[len(m.Label)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Label) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Label: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Label: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) - } - m.Key = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Key |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Str", wireType) - } - m.Str = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Str |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Num", wireType) - } - m.Num = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Num |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NumUnit", wireType) - } - m.NumUnit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.NumUnit |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Mapping) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Mapping: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Mapping: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) - } - m.Id = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Id |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MemoryStart", wireType) - } - m.MemoryStart = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MemoryStart |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MemoryLimit", wireType) - } - m.MemoryLimit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MemoryLimit |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FileOffset", wireType) - } - m.FileOffset = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.FileOffset |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Filename", wireType) - } - m.Filename = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Filename |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BuildId", wireType) - } - m.BuildId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BuildId |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HasFunctions", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.HasFunctions = bool(v != 0) - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HasFilenames", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.HasFilenames = bool(v != 0) - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HasLineNumbers", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.HasLineNumbers = bool(v != 0) - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HasInlineFrames", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.HasInlineFrames = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Location) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Location: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Location: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) - } - m.Id = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Id |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MappingId", wireType) - } - m.MappingId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MappingId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - m.Address = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Address |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Line", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Line = append(m.Line, &Line{}) - if err := m.Line[len(m.Line)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IsFolded", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.IsFolded = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Line) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Line: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Line: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FunctionId", wireType) - } - m.FunctionId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.FunctionId |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Line", wireType) - } - m.Line = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Line |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Function) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Function: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Function: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) - } - m.Id = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Id |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) - } - m.Name = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Name |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SystemName", wireType) - } - m.SystemName = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.SystemName |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Filename", wireType) - } - m.Filename = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Filename |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field StartLine", wireType) - } - m.StartLine = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.StartLine |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} diff --git a/pkg/og/storage/tree/serialize.go b/pkg/og/storage/tree/serialize.go index 733b96efb0..ecabfaeb1d 100644 --- a/pkg/og/storage/tree/serialize.go +++ b/pkg/og/storage/tree/serialize.go @@ -2,179 +2,38 @@ package tree import ( "bufio" - "bytes" - "encoding/base64" + "fmt" "io" - "github.com/grafana/pyroscope/pkg/og/storage/dict" - "github.com/grafana/pyroscope/pkg/og/util/varint" + "github.com/grafana/pyroscope/v2/pkg/og/util/varint" ) -// serialization format version. it's not very useful right now, but it will be in the future -const currentVersion = 1 - -var lostDuringSerializationName = []byte("other") - -// warning: this function modifies the tree -func (t *Tree) SerializeTruncate(d *dict.Dict, maxNodes int, w io.Writer) error { - t.Lock() - defer t.Unlock() - vw := varint.NewWriter() - var err error - if _, err = vw.Write(w, currentVersion); err != nil { - return err - } - - var b bytes.Buffer // Temporary buffer for dictionary keys. - minVal := t.minValue(maxNodes) - nodes := make([]*treeNode, 1, 128) - nodes[0] = t.root - for len(nodes) > 0 { - tn := nodes[0] - nodes = nodes[1:] - - b.Reset() - d.PutValue([]byte(tn.Name), &b) - if _, err = vw.Write(w, uint64(b.Len())); err != nil { - return err - } - if _, err = w.Write(b.Bytes()); err != nil { - return err - } - if _, err = vw.Write(w, tn.Self); err != nil { - return err - } - - cNodes := tn.ChildrenNodes - tn.ChildrenNodes = tn.ChildrenNodes[:0] - - other := uint64(0) - for _, cn := range cNodes { - isOtherNode := bytes.Equal(cn.Name, lostDuringSerializationName) - if cn.Total >= minVal || isOtherNode { - tn.ChildrenNodes = append(tn.ChildrenNodes, cn) - } else { - // Truncated children accounted as parent self. - other += cn.Total - } - } - - if other > 0 { - otherNode := tn.insert(lostDuringSerializationName) - otherNode.Self += other - otherNode.Total += other - } - - if len(tn.ChildrenNodes) > 0 { - nodes = append(tn.ChildrenNodes, nodes...) - } else { - tn.ChildrenNodes = nil // Just to make it eligible for GC. - } - if _, err = vw.Write(w, uint64(len(tn.ChildrenNodes))); err != nil { - return err - } - } - return nil -} - type parentNode struct { node *treeNode parent *parentNode } -func Deserialize(d *dict.Dict, r io.Reader) (*Tree, error) { +// used in the cloud +func DeserializeNoDict(r io.Reader, maxNameLen, maxChildren int) (*Tree, error) { t := New() - - type reader interface { - io.ByteReader - io.Reader - } - var br reader - switch x := r.(type) { - case *bytes.Buffer: - br = x - case *bytes.Reader: - br = x - case *bufio.Reader: - br = x - default: - br = bufio.NewReader(r) - } - - // reads serialization format version, see comment at the top - _, err := varint.Read(br) - if err != nil { - return nil, err - } + br := bufio.NewReader(r) // TODO if it's already a bytereader skip parents := []*parentNode{{t.root, nil}} j := 0 - var nameBuf bytes.Buffer for len(parents) > 0 { j++ parent := parents[0] parents = parents[1:] - labelLen, err := varint.Read(br) - labelLinkBuf := make([]byte, labelLen) // TODO: there are better ways to do this? - _, err = io.ReadAtLeast(br, labelLinkBuf, int(labelLen)) - if err != nil { - return nil, err - } - - nameBuf.Reset() - if !d.GetValue(labelLinkBuf, &nameBuf) { - // these strings has to be at least slightly different, hence base64 Addon - nameBuf.Reset() - nameBuf.WriteString("label not found " + base64.URLEncoding.EncodeToString(labelLinkBuf)) - } - tn := parent.node.insert(nameBuf.Bytes()) - tn.Self, err = varint.Read(br) - tn.Total = tn.Self - if err != nil { - return nil, err - } - - pn := parent - for pn != nil { - pn.node.Total += tn.Self - pn = pn.parent - } - - childrenLen, err := varint.Read(br) + nameLen, err := varint.Read(br) if err != nil { return nil, err } - - for i := uint64(0); i < childrenLen; i++ { - parents = append([]*parentNode{{tn, parent}}, parents...) + if maxNameLen > 0 && nameLen > uint64(maxNameLen) { + return nil, fmt.Errorf("tree node name length %d exceeds maximum %d", nameLen, maxNameLen) } - } - - t.root = t.root.ChildrenNodes[0] - - return t, nil -} - -// used in the cloud -func DeserializeNoDict(r io.Reader) (*Tree, error) { - t := New() - br := bufio.NewReader(r) // TODO if it's already a bytereader skip - - parents := []*parentNode{{t.root, nil}} - j := 0 - - for len(parents) > 0 { - j++ - parent := parents[0] - parents = parents[1:] - - nameLen, err := varint.Read(br) - // if err == io.EOF { - // return t, nil - // } - nameBuf := make([]byte, nameLen) // TODO: there are better ways to do this? + nameBuf := make([]byte, nameLen) _, err = io.ReadAtLeast(br, nameBuf, int(nameLen)) if err != nil { return nil, err @@ -197,6 +56,9 @@ func DeserializeNoDict(r io.Reader) (*Tree, error) { if err != nil { return nil, err } + if maxChildren > 0 && childrenLen > uint64(maxChildren) { + return nil, fmt.Errorf("tree node children count %d exceeds maximum %d", childrenLen, maxChildren) + } for i := uint64(0); i < childrenLen; i++ { parents = append([]*parentNode{{tn, parent}}, parents...) @@ -207,58 +69,3 @@ func DeserializeNoDict(r io.Reader) (*Tree, error) { return t, nil } - -// used in the cloud -// warning: this function modifies the tree -func (t *Tree) SerializeTruncateNoDict(maxNodes int, w io.Writer) error { - t.Lock() - defer t.Unlock() - vw := varint.NewWriter() - var err error - minVal := t.minValue(maxNodes) - nodes := make([]*treeNode, 1, 1024) - nodes[0] = t.root - for len(nodes) > 0 { - tn := nodes[0] - nodes = nodes[1:] - if _, err = vw.Write(w, uint64(len(tn.Name))); err != nil { - return err - } - if _, err = w.Write(tn.Name); err != nil { - return err - } - - if _, err = vw.Write(w, tn.Self); err != nil { - return err - } - cNodes := tn.ChildrenNodes - tn.ChildrenNodes = tn.ChildrenNodes[:0] - - other := uint64(0) - for _, cn := range cNodes { - isOtherNode := bytes.Equal(cn.Name, lostDuringSerializationName) - if cn.Total >= minVal || isOtherNode { - tn.ChildrenNodes = append(tn.ChildrenNodes, cn) - } else { - // Truncated children accounted as parent self. - other += cn.Total - } - } - - if other > 0 { - otherNode := tn.insert(lostDuringSerializationName) - otherNode.Self += other - otherNode.Total += other - } - - if len(tn.ChildrenNodes) > 0 { - nodes = append(tn.ChildrenNodes, nodes...) - } else { - tn.ChildrenNodes = nil // Just to make it eligible for GC. - } - if _, err = vw.Write(w, uint64(len(tn.ChildrenNodes))); err != nil { - return err - } - } - return nil -} diff --git a/pkg/og/storage/tree/serialize_nodict_test.go b/pkg/og/storage/tree/serialize_nodict_test.go index ad75566caa..30d6e61575 100644 --- a/pkg/og/storage/tree/serialize_nodict_test.go +++ b/pkg/og/storage/tree/serialize_nodict_test.go @@ -2,36 +2,44 @@ package tree import ( "bytes" + "testing" - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/require" ) var serializationExample = []byte("\x00\x00\x01\x01a\x00\x02\x01b\x01\x00\x01c\x02\x00") -var _ = Describe("tree package", func() { - Describe("SerializeNoDict", func() { - It("returns correct results", func() { - tree := New() - tree.Insert([]byte("a;b"), uint64(1)) - tree.Insert([]byte("a;c"), uint64(2)) +func TestDeserializeNoDict(t *testing.T) { + t.Run("returns correct results", func(t *testing.T) { + r := bytes.NewReader(serializationExample) + tr, err := DeserializeNoDict(r, 0, 0) + require.NoError(t, err) - var buf bytes.Buffer - tree.SerializeTruncateNoDict(1024, &buf) - Expect(buf.Bytes()).To(Equal(serializationExample)) - }) + require.Equal(t, "", string(tr.root.Name)) + require.Equal(t, "a", string(tr.root.ChildrenNodes[0].Name)) + require.Equal(t, "b", string(tr.root.ChildrenNodes[0].ChildrenNodes[0].Name)) + require.Equal(t, "c", string(tr.root.ChildrenNodes[0].ChildrenNodes[1].Name)) }) - Describe("DeserializeNoDict", func() { - It("returns correct results", func() { - r := bytes.NewReader(serializationExample) - t, err := DeserializeNoDict(r) - Expect(err).ToNot(HaveOccurred()) + t.Run("rejects oversized name length varint (CVE-style panic)", func(t *testing.T) { + // 10-byte payload: varint encoding of 0xFFFFFFFFFFFFFFFF (max uint64). + // Without bounds checking this causes: panic: makeslice: len out of range + payload := bytes.Repeat([]byte{0xff}, 9) + payload = append(payload, 0x01) + _, err := DeserializeNoDict(bytes.NewReader(payload), 65535, 0) + require.Error(t, err) + require.Contains(t, err.Error(), "exceeds maximum") + }) - Expect(string(t.root.Name)).To(Equal("")) - Expect(string(t.root.ChildrenNodes[0].Name)).To(Equal("a")) - Expect(string(t.root.ChildrenNodes[0].ChildrenNodes[0].Name)).To(Equal("b")) - Expect(string(t.root.ChildrenNodes[0].ChildrenNodes[1].Name)).To(Equal("c")) - }) + t.Run("rejects oversized children count", func(t *testing.T) { + // Craft a node with nameLen=0, self=0, childrenLen=varint(16001). + // uvarint(16001) = 0x81 0x7D + var buf bytes.Buffer + buf.WriteByte(0x00) // nameLen = 0 + buf.WriteByte(0x00) // self = 0 + buf.Write([]byte{0x81, 0x7D}) // childrenLen = 16001 + _, err := DeserializeNoDict(&buf, 0, 16000) + require.Error(t, err) + require.Contains(t, err.Error(), "exceeds maximum") }) -}) +} diff --git a/pkg/og/storage/tree/serialize_test.go b/pkg/og/storage/tree/serialize_test.go index fa29ce05f0..aff03f52d0 100644 --- a/pkg/og/storage/tree/serialize_test.go +++ b/pkg/og/storage/tree/serialize_test.go @@ -1,61 +1,15 @@ package tree import ( - "bytes" + "testing" - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" - "github.com/grafana/pyroscope/pkg/og/storage/dict" + "github.com/stretchr/testify/require" ) -var dictSerializeExample = []byte("\x01\x00\x00\x01\x02\x00\x01\x00\x02\x02\x01\x01\x01\x00\x02\x02\x01\x02\x00") +func TestInsert(t *testing.T) { + tree := New() + tree.Insert([]byte("a;b"), uint64(1)) + tree.Insert([]byte("a;c"), uint64(2)) -var _ = Describe("tree", func() { - Describe("Insert", func() { - tree := New() - tree.Insert([]byte("a;b"), uint64(1)) - tree.Insert([]byte("a;c"), uint64(2)) - - It("correctly sets children nodes", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - }) - }) - - Describe("SerializeTruncate", func() { - d := dict.New() - tree := New() - tree.Insert([]byte("a;b"), uint64(1)) - tree.Insert([]byte("a;c"), uint64(2)) - - It("serializes tree", func() { - var buf bytes.Buffer - tree.SerializeTruncate(d, 1024, &buf) - Expect(buf.Bytes()).To(Equal(dictSerializeExample)) - }) - - Context("Ran 1000000 times", func() { - var buf1 bytes.Buffer - tree.SerializeTruncate(d, 1024, &buf1) - It("returns the same result", func() { - var buf2 bytes.Buffer - tree.SerializeTruncate(d, 1024, &buf2) - Expect(buf2).To(Equal(buf1)) - }) - }) - }) - - Describe("Deserialize", func() { - // TODO: add a case with a real dictionary - It("returns a properly deserialized tree", func() { - d := dict.New() - r := bytes.NewReader(dictSerializeExample) - t, err := Deserialize(d, r) - Expect(err).ToNot(HaveOccurred()) - - Expect(string(t.root.Name)).To(Equal("")) - Expect(string(t.root.ChildrenNodes[0].Name)).To(Equal("label not found AAE=")) - Expect(string(t.root.ChildrenNodes[0].ChildrenNodes[0].Name)).To(Equal("label not found AQE=")) - Expect(string(t.root.ChildrenNodes[0].ChildrenNodes[1].Name)).To(Equal("label not found AgE=")) - }) - }) -}) + require.Len(t, tree.root.ChildrenNodes, 1) +} diff --git a/pkg/og/storage/tree/tree.go b/pkg/og/storage/tree/tree.go index e06b87f0fa..e5b3dcf2f8 100644 --- a/pkg/og/storage/tree/tree.go +++ b/pkg/og/storage/tree/tree.go @@ -8,9 +8,7 @@ import ( "sync" "unsafe" - "github.com/grafana/pyroscope/pkg/og/util/arenahelper" - - "github.com/grafana/pyroscope/pkg/og/structs/merge" + "github.com/grafana/pyroscope/v2/pkg/og/structs/merge" ) type jsonableSlice []byte @@ -50,8 +48,7 @@ const semicolon = byte(';') type Tree struct { sync.RWMutex - root *treeNode - arena arenahelper.ArenaWrapper + root *treeNode } func New() *Tree { diff --git a/pkg/og/storage/tree/tree_arenas_disabled.go b/pkg/og/storage/tree/tree_arenas_disabled.go deleted file mode 100644 index 7553fc7e99..0000000000 --- a/pkg/og/storage/tree/tree_arenas_disabled.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !goexperiment.arenas - -package tree - -func (t *Tree) InsertStackA(stack [][]byte, v uint64) { - t.InsertStack(stack, v) -} diff --git a/pkg/og/storage/tree/tree_arenas_enabled.go b/pkg/og/storage/tree/tree_arenas_enabled.go deleted file mode 100644 index 6c07bd5b41..0000000000 --- a/pkg/og/storage/tree/tree_arenas_enabled.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build goexperiment.arenas - -package tree - -import ( - "arena" - "bytes" - "github.com/grafana/pyroscope/pkg/og/util/arenahelper" - "sort" -) - -func (t *Tree) InsertStackA(stack [][]byte, v uint64) { - a := t.arena - if a == nil { - t.InsertStack(stack, v) - return - } - n := t.root - for j := range stack { - n.Total += v - n = n.insertA(a, stack[j]) - } - // Leaf. - n.Total += v - n.Self += v -} - -func (n *treeNode) insertA(a arenahelper.ArenaWrapper, targetLabel []byte) *treeNode { - i := sort.Search(len(n.ChildrenNodes), func(i int) bool { - return bytes.Compare(n.ChildrenNodes[i].Name, targetLabel) >= 0 - }) - if i > len(n.ChildrenNodes)-1 || !bytes.Equal(n.ChildrenNodes[i].Name, targetLabel) { - l := arena.MakeSlice[byte](a, len(targetLabel), len(targetLabel)) - copy(l, targetLabel) - child := newNodeA(a, l) - if len(n.ChildrenNodes) < cap(n.ChildrenNodes) { - n.ChildrenNodes = append(n.ChildrenNodes, child) - } else { - n.ChildrenNodes = arenahelper.AppendA(n.ChildrenNodes, child, a) - } - copy(n.ChildrenNodes[i+1:], n.ChildrenNodes[i:]) - n.ChildrenNodes[i] = child - } - return n.ChildrenNodes[i] -} - -func newNodeA(a arenahelper.ArenaWrapper, label []byte) *treeNode { - n := arena.New[treeNode](a) - n.Name = label - return n -} - -func NewA(a arenahelper.ArenaWrapper) *Tree { - t := arena.New[Tree](a) - t.root = newNodeA(a, nil) - t.arena = a - return t -} diff --git a/pkg/og/storage/tree/tree_suite_test.go b/pkg/og/storage/tree/tree_suite_test.go deleted file mode 100644 index cd91e9a2fa..0000000000 --- a/pkg/og/storage/tree/tree_suite_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package tree_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" - testing2 "github.com/grafana/pyroscope/pkg/og/testing" -) - -func TestTree(t *testing.T) { - testing2.SetupLogging() - RegisterFailHandler(Fail) - RunSpecs(t, "Tree Suite") -} diff --git a/pkg/og/storage/tree/tree_test.go b/pkg/og/storage/tree/tree_test.go index 5fe9729be2..62fbe15628 100644 --- a/pkg/og/storage/tree/tree_test.go +++ b/pkg/og/storage/tree/tree_test.go @@ -2,35 +2,31 @@ package tree import ( "bytes" - "encoding/json" "fmt" "strings" + "testing" - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" - "github.com/onsi/gomega/format" + "github.com/stretchr/testify/require" ) -var _ = Describe("tree package", func() { - Context("Insert", func() { +func TestTree(t *testing.T) { + t.Run("Insert properly sets up a tree", func(t *testing.T) { tree := New() tree.Insert([]byte("a;b"), uint64(1)) tree.Insert([]byte("a;c"), uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(2))) - Expect(tree.String()).To(Equal("a;b 1\na;c 2\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, "a;b 1\na;c 2\n", tree.String()) }) - Context("Diff", func() { + t.Run("Diff properly sets up a tree", func(t *testing.T) { a := New() a.Insert([]byte("a;b;c"), uint64(100)) a.Insert([]byte("a;b;c;d"), uint64(100)) @@ -49,271 +45,228 @@ var _ = Describe("tree package", func() { b.Insert([]byte("a;h"), uint64(170)) diff := a.Diff(b) - z, _ := json.MarshalIndent(diff, "", "\t") - fmt.Println(string(z)) - It("properly sets up a tree", func() { - Expect(diff).To(beTree([]stack{ - {"a;g", 20}, - {"a;h", 20}, - {"a;b;c", 20}, - {"a;b;d", 20}, - {"a;b;c;d", 20}, - })) - }) + requireTreeString(t, []stack{ + {"a;g", 20}, + {"a;h", 20}, + {"a;b;c", 20}, + {"a;b;d", 20}, + {"a;b;c;d", 20}, + }, diff) }) - Context("InsertStackString unsorted of length 1", func() { + t.Run("InsertStackString unsorted of length 1", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "b"}, uint64(1)) tree.InsertStackString([]string{"a", "a"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(1))) - Expect(tree.String()).To(Equal("a;a 2\na;b 1\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, "a;a 2\na;b 1\n", tree.String()) }) - Context("InsertStackString equal of length 1", func() { + t.Run("InsertStackString equal of length 1", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "b"}, uint64(1)) tree.InsertStackString([]string{"a", "b"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.String()).To(Equal("a;b 3\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 1) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, "a;b 3\n", tree.String()) }) - Context("InsertStackString sorted of length 1", func() { + t.Run("InsertStackString sorted of length 1", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "b"}, uint64(1)) tree.InsertStackString([]string{"a", "c"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(2))) - Expect(tree.String()).To(Equal("a;b 1\na;c 2\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, "a;b 1\na;c 2\n", tree.String()) }) - Context("InsertStackString sorted of different lengths", func() { + t.Run("InsertStackString sorted of different lengths", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "b"}, uint64(1)) tree.InsertStackString([]string{"a", "ba"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(2))) - Expect(tree.String()).To(Equal("a;b 1\na;ba 2\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, "a;b 1\na;ba 2\n", tree.String()) }) - Context("InsertStackString unsorted of different lengths", func() { + t.Run("InsertStackString unsorted of different lengths", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "ba"}, uint64(1)) tree.InsertStackString([]string{"a", "b"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(1))) - Expect(tree.String()).To(Equal("a;b 2\na;ba 1\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, "a;b 2\na;ba 1\n", tree.String()) }) - Context("InsertStackString unsorted of length 2", func() { + t.Run("InsertStackString unsorted of length 2", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "bb"}, uint64(1)) tree.InsertStackString([]string{"a", "ba"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(1))) - Expect(tree.String()).To(Equal("a;ba 2\na;bb 1\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, "a;ba 2\na;bb 1\n", tree.String()) }) - Context("InsertStackString equal of length 2", func() { + t.Run("InsertStackString equal of length 2", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "bb"}, uint64(1)) tree.InsertStackString([]string{"a", "bb"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.String()).To(Equal("a;bb 3\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 1) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, "a;bb 3\n", tree.String()) }) - Context("InsertStackString sorted of length 2", func() { + t.Run("InsertStackString sorted of length 2", func(t *testing.T) { tree := New() tree.InsertStackString([]string{"a", "bb"}, uint64(1)) tree.InsertStackString([]string{"a", "bc"}, uint64(2)) - It("properly sets up a tree", func() { - Expect(tree.root.ChildrenNodes).To(HaveLen(1)) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(tree.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(tree.root.ChildrenNodes[0].Total).To(Equal(uint64(3))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(2))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(1))) - Expect(tree.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(2))) - Expect(tree.String()).To(Equal("a;bb 1\na;bc 2\n")) - }) + require.Len(t, tree.root.ChildrenNodes, 1) + require.Len(t, tree.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), tree.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(3), tree.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(1), tree.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(2), tree.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, "a;bb 1\na;bc 2\n", tree.String()) }) - Context("Merge", func() { - Context("similar trees", func() { - treeA := New() - treeA.Insert([]byte("a;b"), uint64(1)) - treeA.Insert([]byte("a;c"), uint64(2)) - It("properly sets up tree A", func() { - Expect(treeA.String()).To(Equal(treeStr(`a;b 1|a;c 2|`))) - }) - - treeB := New() - treeB.Insert([]byte("a;b"), uint64(4)) - treeB.Insert([]byte("a;c"), uint64(8)) - It("properly sets up tree B", func() { - Expect(treeB.String()).To(Equal(treeStr(`a;b 4|a;c 8|`))) - }) - - It("properly merges", func() { - treeA.Merge(treeB) - - Expect(treeA.root.ChildrenNodes).To(HaveLen(1)) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(2)) - Expect(treeA.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(treeA.root.ChildrenNodes[0].Total).To(Equal(uint64(15))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(5))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(10))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(5))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(10))) - Expect(treeA.String()).To(Equal(treeStr(`a;b 5|a;c 10|`))) - }) - }) - - Context("tree with an extra node", func() { - treeA := New() - treeA.Insert([]byte("a;b"), uint64(1)) - treeA.Insert([]byte("a;c"), uint64(2)) - treeA.Insert([]byte("a;e"), uint64(3)) - It("properly sets up tree A", func() { - Expect(treeA.String()).To(Equal(treeStr(`a;b 1|a;c 2|a;e 3|`))) - }) - - treeB := New() - treeB.Insert([]byte("a;b"), uint64(4)) - treeB.Insert([]byte("a;d"), uint64(8)) - treeB.Insert([]byte("a;e"), uint64(12)) - It("properly sets up tree B", func() { - Expect(treeB.String()).To(Equal(treeStr(`a;b 4|a;d 8|a;e 12|`))) - }) - - It("properly merges", func() { - treeA.Merge(treeB) - - Expect(treeA.root.ChildrenNodes).To(HaveLen(1)) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes).To(HaveLen(4)) - Expect(treeA.root.ChildrenNodes[0].Self).To(Equal(uint64(0))) - Expect(treeA.root.ChildrenNodes[0].Total).To(Equal(uint64(30))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[0].Self).To(Equal(uint64(5))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[1].Self).To(Equal(uint64(2))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[2].Self).To(Equal(uint64(8))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[3].Self).To(Equal(uint64(15))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[0].Total).To(Equal(uint64(5))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[1].Total).To(Equal(uint64(2))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[2].Total).To(Equal(uint64(8))) - Expect(treeA.root.ChildrenNodes[0].ChildrenNodes[3].Total).To(Equal(uint64(15))) - Expect(treeA.String()).To(Equal(treeStr(`a;b 5|a;c 2|a;d 8|a;e 15|`))) - }) - }) - - Context("tree.scale", func() { - treeA := New() - treeA.Insert([]byte("a;b"), uint64(1)) - treeA.Insert([]byte("a;c"), uint64(2)) - treeA.Insert([]byte("a;e"), uint64(3)) - treeA.Insert([]byte("a"), uint64(4)) - treeA.Scale(3) - It("", func() { - Expect(treeA.String()).To(Equal(treeStr(`a 12|a;b 3|a;c 6|a;e 9|`))) - }) - }) + t.Run("Merge similar trees", func(t *testing.T) { + treeA := New() + treeA.Insert([]byte("a;b"), uint64(1)) + treeA.Insert([]byte("a;c"), uint64(2)) + require.Equal(t, treeStr(`a;b 1|a;c 2|`), treeA.String()) + + treeB := New() + treeB.Insert([]byte("a;b"), uint64(4)) + treeB.Insert([]byte("a;c"), uint64(8)) + require.Equal(t, treeStr(`a;b 4|a;c 8|`), treeB.String()) + + treeA.Merge(treeB) + + require.Len(t, treeA.root.ChildrenNodes, 1) + require.Len(t, treeA.root.ChildrenNodes[0].ChildrenNodes, 2) + require.Equal(t, uint64(0), treeA.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(15), treeA.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(5), treeA.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(10), treeA.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(5), treeA.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(10), treeA.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, treeStr(`a;b 5|a;c 10|`), treeA.String()) }) -}) + + t.Run("Merge tree with an extra node", func(t *testing.T) { + treeA := New() + treeA.Insert([]byte("a;b"), uint64(1)) + treeA.Insert([]byte("a;c"), uint64(2)) + treeA.Insert([]byte("a;e"), uint64(3)) + require.Equal(t, treeStr(`a;b 1|a;c 2|a;e 3|`), treeA.String()) + + treeB := New() + treeB.Insert([]byte("a;b"), uint64(4)) + treeB.Insert([]byte("a;d"), uint64(8)) + treeB.Insert([]byte("a;e"), uint64(12)) + require.Equal(t, treeStr(`a;b 4|a;d 8|a;e 12|`), treeB.String()) + + treeA.Merge(treeB) + + require.Len(t, treeA.root.ChildrenNodes, 1) + require.Len(t, treeA.root.ChildrenNodes[0].ChildrenNodes, 4) + require.Equal(t, uint64(0), treeA.root.ChildrenNodes[0].Self) + require.Equal(t, uint64(30), treeA.root.ChildrenNodes[0].Total) + require.Equal(t, uint64(5), treeA.root.ChildrenNodes[0].ChildrenNodes[0].Self) + require.Equal(t, uint64(2), treeA.root.ChildrenNodes[0].ChildrenNodes[1].Self) + require.Equal(t, uint64(8), treeA.root.ChildrenNodes[0].ChildrenNodes[2].Self) + require.Equal(t, uint64(15), treeA.root.ChildrenNodes[0].ChildrenNodes[3].Self) + require.Equal(t, uint64(5), treeA.root.ChildrenNodes[0].ChildrenNodes[0].Total) + require.Equal(t, uint64(2), treeA.root.ChildrenNodes[0].ChildrenNodes[1].Total) + require.Equal(t, uint64(8), treeA.root.ChildrenNodes[0].ChildrenNodes[2].Total) + require.Equal(t, uint64(15), treeA.root.ChildrenNodes[0].ChildrenNodes[3].Total) + require.Equal(t, treeStr(`a;b 5|a;c 2|a;d 8|a;e 15|`), treeA.String()) + }) + + t.Run("tree scale", func(t *testing.T) { + treeA := New() + treeA.Insert([]byte("a;b"), uint64(1)) + treeA.Insert([]byte("a;c"), uint64(2)) + treeA.Insert([]byte("a;e"), uint64(3)) + treeA.Insert([]byte("a"), uint64(4)) + treeA.Scale(3) + require.Equal(t, treeStr(`a 12|a;b 3|a;c 6|a;e 9|`), treeA.String()) + }) +} func treeStr(s string) string { return strings.ReplaceAll(s, "|", "\n") } -var _ = Describe("prepend", func() { - Context("prependTreeNode)", func() { - It("prepend elem", func() { - A, B, C, X := &treeNode{}, &treeNode{}, &treeNode{}, &treeNode{} - s := []*treeNode{A, B, C} - s = prependTreeNode(s, X) - Expect(s).To(HaveLen(4)) - Expect(s[0]).To(Equal(X)) - Expect(s[1]).To(Equal(A)) - Expect(s[2]).To(Equal(B)) - Expect(s[3]).To(Equal(C)) - }) - }) - Context("prependBytes", func() { - It("prepend elem", func() { - A, B, C, X := []byte("A"), []byte("B"), []byte("C"), []byte("X") - s := [][]byte{A, B, C} - s = prependBytes(s, X) - - out := bytes.Join(s, []byte(",")) - Expect(string(out)).To(Equal("X,A,B,C")) - }) +func TestPrepend(t *testing.T) { + t.Run("prependTreeNode", func(t *testing.T) { + A, B, C, X := &treeNode{}, &treeNode{}, &treeNode{}, &treeNode{} + s := []*treeNode{A, B, C} + s = prependTreeNode(s, X) + require.Len(t, s, 4) + require.Equal(t, X, s[0]) + require.Equal(t, A, s[1]) + require.Equal(t, B, s[2]) + require.Equal(t, C, s[3]) }) -}) -type BeTreeMatcher struct { - Expected string + t.Run("prependBytes", func(t *testing.T) { + A, B, C, X := []byte("A"), []byte("B"), []byte("C"), []byte("X") + s := [][]byte{A, B, C} + s = prependBytes(s, X) + + out := bytes.Join(s, []byte(",")) + require.Equal(t, "X,A,B,C", string(out)) + }) } type stack struct { @@ -321,26 +274,15 @@ type stack struct { Value int } -func beTree(stacks []stack) *BeTreeMatcher { +func treeStringFromStacks(stacks []stack) string { var b strings.Builder for _, s := range stacks { _, _ = fmt.Fprintf(&b, "%s %d\n", s.Name, s.Value) } - return &BeTreeMatcher{Expected: b.String()} -} - -func (m *BeTreeMatcher) Match(actual interface{}) (success bool, err error) { - t, ok := actual.(*Tree) - if !ok { - return false, nil - } - return t.String() == m.Expected, nil -} - -func (m *BeTreeMatcher) FailureMessage(actual interface{}) string { - return format.Message(actual.(*Tree).String(), "to be", m.Expected) + return b.String() } -func (m *BeTreeMatcher) NegatedFailureMessage(actual interface{}) string { - return format.Message(actual.(*Tree).String(), "not to be", m.Expected) +func requireTreeString(t *testing.T, stacks []stack, tr *Tree) { + t.Helper() + require.Equal(t, treeStringFromStacks(stacks), tr.String()) } diff --git a/pkg/og/storage/tree/treediff.go b/pkg/og/storage/tree/treediff.go deleted file mode 100644 index bdaff854f4..0000000000 --- a/pkg/og/storage/tree/treediff.go +++ /dev/null @@ -1,237 +0,0 @@ -package tree - -import ( - "bytes" - - "github.com/grafana/pyroscope/pkg/og/structs/cappedarr" -) - -// CombineTree aligns 2 trees by making them having the same structure with the -// same number of nodes -// TODO: create a new struct? -func CombineTree(leftTree, rightTree *Tree) (*Tree, *Tree) { - leftTree.Lock() - defer leftTree.Unlock() - rightTree.Lock() - defer rightTree.Unlock() - - leftNodes := []*treeNode{leftTree.root} - rghtNodes := []*treeNode{rightTree.root} - - for len(leftNodes) > 0 { - left, rght := leftNodes[0], rghtNodes[0] - leftNodes, rghtNodes = leftNodes[1:], rghtNodes[1:] - - left.ChildrenNodes, rght.ChildrenNodes = combineNodes(left.ChildrenNodes, rght.ChildrenNodes) - leftNodes = append(leftNodes, left.ChildrenNodes...) - rghtNodes = append(rghtNodes, rght.ChildrenNodes...) - } - return leftTree, rightTree -} - -func combineNodes(leftNodes, rghtNodes []*treeNode) ([]*treeNode, []*treeNode) { - size := nextPow2(max(len(leftNodes), len(rghtNodes))) - leftResult := make([]*treeNode, 0, size) - rghtResult := make([]*treeNode, 0, size) - - for len(leftNodes) != 0 && len(rghtNodes) != 0 { - left, rght := leftNodes[0], rghtNodes[0] - switch bytes.Compare(left.Name, rght.Name) { - case 0: - leftResult = append(leftResult, left) - rghtResult = append(rghtResult, rght) - leftNodes, rghtNodes = leftNodes[1:], rghtNodes[1:] - case -1: - leftResult = append(leftResult, left) - rghtResult = append(rghtResult, newNode(left.Name)) - leftNodes = leftNodes[1:] - case 1: - leftResult = append(leftResult, newNode(rght.Name)) - rghtResult = append(rghtResult, rght) - rghtNodes = rghtNodes[1:] - } - } - leftResult = append(leftResult, leftNodes...) - rghtResult = append(rghtResult, rghtNodes...) - for _, left := range leftNodes { - rghtResult = append(rghtResult, newNode(left.Name)) - } - for _, rght := range rghtNodes { - leftResult = append(leftResult, newNode(rght.Name)) - } - return leftResult, rghtResult -} - -// CombineToFlamebearerStruct generates the Flamebearer struct from 2 trees. -// They must be the response trees from CombineTree (i.e. all children nodes -// must be the same length). The Flamebearer struct returned from this function -// is different to the one returned from Tree.FlamebearerStruct(). It has the -// following structure: -// -// i+0 = x offset, left tree -// i+1 = total , left tree -// i+2 = self , left tree -// i+3 = x offset, right tree -// i+4 = total , right tree -// i+5 = self , right tree -// i+6 = index in the names array -func CombineToFlamebearerStruct(leftTree, rightTree *Tree, maxNodes int) *Flamebearer { - leftTree.RLock() - defer leftTree.RUnlock() - rightTree.RLock() - defer rightTree.RUnlock() - - res := Flamebearer{ - Names: []string{}, - Levels: [][]int{}, - NumTicks: int(leftTree.Samples() + rightTree.Samples()), - MaxSelf: int(0), - Format: FormatDouble, - } - - leftNodes, xLeftOffsets := []*treeNode{leftTree.root}, []int{0} - rghtNodes, xRghtOffsets := []*treeNode{rightTree.root}, []int{0} - levels := []int{0} - minVal := combineMinValues(leftTree, rightTree, maxNodes) - nameLocationCache := map[string]int{} - - for len(leftNodes) > 0 { - left, rght := leftNodes[0], rghtNodes[0] - leftNodes, rghtNodes = leftNodes[1:], rghtNodes[1:] - - xLeftOffset, xRghtOffset := xLeftOffsets[0], xRghtOffsets[0] - xLeftOffsets, xRghtOffsets = xLeftOffsets[1:], xRghtOffsets[1:] - - level := levels[0] - levels = levels[1:] - - // both left.Name and rght.Name must be the same - name := string(left.Name) - if left.Total >= minVal || rght.Total >= minVal || name == "other" { - i, ok := nameLocationCache[name] - if !ok { - i = len(res.Names) - nameLocationCache[name] = i - if i == 0 { - name = "total" - } - res.Names = append(res.Names, name) - } - - if level == len(res.Levels) { - res.Levels = append(res.Levels, []int{}) - } - res.MaxSelf = max(res.MaxSelf, int(left.Self)) - res.MaxSelf = max(res.MaxSelf, int(rght.Self)) - - // i+0 = x offset, left tree - // i+1 = total , left tree - // i+2 = self , left tree - // i+3 = x offset, right tree - // i+4 = total , right tree - // i+5 = self , right tree - // i+6 = index in the names array - values := []int{ - xLeftOffset, int(left.Total), int(left.Self), - xRghtOffset, int(rght.Total), int(rght.Self), - i, - } - res.Levels[level] = append(values, res.Levels[level]...) - - xLeftOffset += int(left.Self) - xRghtOffset += int(rght.Self) - otherLeftTotal, otherRghtTotal := uint64(0), uint64(0) - - // both left and right must have the same number of children nodes - for ni := range left.ChildrenNodes { - leftNode, rghtNode := left.ChildrenNodes[ni], rght.ChildrenNodes[ni] - if leftNode.Total >= minVal || rghtNode.Total >= minVal { - levels = prependInt(levels, level+1) - xLeftOffsets = prependInt(xLeftOffsets, xLeftOffset) - xRghtOffsets = prependInt(xRghtOffsets, xRghtOffset) - leftNodes = prependTreeNode(leftNodes, leftNode) - rghtNodes = prependTreeNode(rghtNodes, rghtNode) - xLeftOffset += int(leftNode.Total) - xRghtOffset += int(rghtNode.Total) - } else { - otherLeftTotal += leftNode.Total - otherRghtTotal += rghtNode.Total - } - } - if otherLeftTotal != 0 || otherRghtTotal != 0 { - levels = prependInt(levels, level+1) - { - leftNode := &treeNode{ - Name: jsonableSlice("other"), - Total: otherLeftTotal, - Self: otherLeftTotal, - } - xLeftOffsets = prependInt(xLeftOffsets, xLeftOffset) - leftNodes = prependTreeNode(leftNodes, leftNode) - } - { - rghtNode := &treeNode{ - Name: jsonableSlice("other"), - Total: otherRghtTotal, - Self: otherRghtTotal, - } - xRghtOffsets = prependInt(xRghtOffsets, xRghtOffset) - rghtNodes = prependTreeNode(rghtNodes, rghtNode) - } - } - } - } - - // delta encoding - deltaEncoding(res.Levels, 0, 7) - deltaEncoding(res.Levels, 3, 7) - return &res -} - -func combineMinValues(leftTree, rightTree *Tree, maxNodes int) uint64 { - c := cappedarr.New(maxNodes) - combineIterateWithTotal(leftTree, rightTree, func(left uint64, right uint64) bool { - return c.Push(maxUint64(left, right)) - }) - return c.MinValue() -} - -// iterate both trees, both trees must be returned from CombineTree -func combineIterateWithTotal(leftTree, rightTree *Tree, cb func(uint64, uint64) bool) { - leftNodes, rghtNodes := []*treeNode{leftTree.root}, []*treeNode{rightTree.root} - i := 0 - for len(leftNodes) > 0 { - leftNode, rghtNode := leftNodes[0], rghtNodes[0] - leftNodes, rghtNodes = leftNodes[1:], rghtNodes[1:] - i++ - if cb(leftNode.Total, rghtNode.Total) { - leftNodes = append(leftNode.ChildrenNodes, leftNodes...) - rghtNodes = append(rghtNode.ChildrenNodes, rghtNodes...) - } - } -} - -func maxUint64(a, b uint64) uint64 { - if a > b { - return a - } - return b -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func nextPow2(a int) int { - a-- - a |= a >> 1 - a |= a >> 2 - a |= a >> 4 - a |= a >> 8 - a |= a >> 16 - a++ - return a -} diff --git a/pkg/og/storage/tree/treediff_test.go b/pkg/og/storage/tree/treediff_test.go deleted file mode 100644 index 8694875b4a..0000000000 --- a/pkg/og/storage/tree/treediff_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package tree - -import ( - "fmt" - "math/rand" - - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" -) - -// StringWithEmpty is used for testing only, hence declared in this file. It's -// different to String() as it includes nodes with zero value. -func (t *Tree) StringWithEmpty() string { - t.RLock() - defer t.RUnlock() - - res := "" - t.Iterate(func(k []byte, v uint64) { - if len(k) >= 2 { - res += fmt.Sprintf("%q %d\n", k[2:], v) - } - }) - return res -} - -var _ = Describe("tree package", func() { - Context("diff", func() { - Context("similar trees", func() { - treeA := New() - treeA.Insert([]byte("a;b"), uint64(1)) - treeA.Insert([]byte("a;c"), uint64(2)) - It("properly sets up tree A", func() { - Expect(treeA.StringWithEmpty()).To(Equal(treeStr(`"a" 0|"a;b" 1|"a;c" 2|`))) - }) - - treeB := New() - treeB.Insert([]byte("a;b"), uint64(4)) - treeB.Insert([]byte("a;c"), uint64(8)) - It("properly sets up tree B", func() { - Expect(treeB.StringWithEmpty()).To(Equal(treeStr(`"a" 0|"a;b" 4|"a;c" 8|`))) - }) - - It("properly combine trees", func() { - CombineTree(treeA, treeB) - - Expect(treeA.StringWithEmpty()).To(Equal(treeStr(`"a" 0|"a;b" 1|"a;c" 2|`))) - Expect(treeB.StringWithEmpty()).To(Equal(treeStr(`"a" 0|"a;b" 4|"a;c" 8|`))) - }) - - It("properly combine trees to flamebearer", func() { - f := CombineToFlamebearerStruct(treeA, treeB, 1024) - - Expect(f.Names).To(ConsistOf("total", "a", "b", "c")) - Expect(f.Levels).To(Equal([][]int{ - // i+0 = x offset, left tree - // i+1 = total , left tree - // i+2 = self , left tree - // i+3 = x offset, right tree - // i+4 = total , right tree - // i+5 = self , right tree - // i+6 = index in the names array - {0, 3, 0, 0, 12, 0, 0}, - {0, 3, 0, 0, 12, 0, 1}, - {0, 1, 1, 0, 4, 4, 3, 0, 2, 2, 0, 8, 8, 2}, - })) - Expect(f.NumTicks).To(Equal(15)) - Expect(f.MaxSelf).To(Equal(8)) - }) - }) - - Context("tree with an extra node", func() { - treeA := New() - treeA.Insert([]byte("a;b"), uint64(1)) - treeA.Insert([]byte("a;c"), uint64(2)) - treeA.Insert([]byte("a;e"), uint64(3)) - It("properly sets up tree A", func() { - Expect(treeA.StringWithEmpty()).To(Equal(treeStr(`"a" 0|"a;b" 1|"a;c" 2|"a;e" 3|`))) - }) - - treeB := New() - treeB.Insert([]byte("a;b"), uint64(4)) - treeB.Insert([]byte("a;d"), uint64(8)) - treeB.Insert([]byte("a;e"), uint64(12)) - It("properly sets up tree B", func() { - Expect(treeB.StringWithEmpty()).To(Equal(treeStr(`"a" 0|"a;b" 4|"a;d" 8|"a;e" 12|`))) - }) - - It("properly combine trees", func() { - CombineTree(treeA, treeB) - - expectedA := `"a" 0|"a;b" 1|"a;c" 2|"a;d" 0|"a;e" 3|` - expectedB := `"a" 0|"a;b" 4|"a;c" 0|"a;d" 8|"a;e" 12|` - Expect(treeA.StringWithEmpty()).To(Equal(treeStr(expectedA))) - Expect(treeB.StringWithEmpty()).To(Equal(treeStr(expectedB))) - }) - - It("properly combine trees to flamebearer", func() { - f := CombineToFlamebearerStruct(treeA, treeB, 1024) - - Expect(f.Names).To(ConsistOf("total", "a", "b", "c", "d", "e")) - Expect(f.Levels).To(Equal([][]int{ - // i+0 = x offset, left tree - // i+1 = total , left tree - // i+2 = self , left tree - // i+3 = x offset, right tree - // i+4 = total , right tree - // i+5 = self , right tree - // i+6 = index in the names array - {0, 6, 0, 0, 24, 0, 0}, // total - {0, 6, 0, 0, 24, 0, 1}, // a - { - 0, 1, 1, 0, 4, 4, 5, // e - 0, 2, 2, 0, 0, 0, 4, // d - 0, 0, 0, 0, 8, 8, 3, // c - 0, 3, 3, 0, 12, 12, 2, // b - }, - })) - Expect(f.NumTicks).To(Equal(30)) - Expect(f.MaxSelf).To(Equal(12)) - }) - }) - - Context("tree with many nodes", func() { - It("groups nodes into a new \"other\" node", func() { - treeA, treeB := New(), New() - r := rand.New(rand.NewSource(123)) - for i := 0; i < 2048; i++ { - treeA.Insert([]byte(fmt.Sprintf("foo;bar%d", i)), uint64(r.Intn(4000))) - treeB.Insert([]byte(fmt.Sprintf("foo;bar%d", i)), uint64(r.Intn(4000))) - } - - f := CombineToFlamebearerStruct(treeA, treeB, 10) - Expect(f.Names).To(ContainElement("other")) - }) - }) - }) -}) diff --git a/pkg/og/storage/tree/truncation_test.go b/pkg/og/storage/tree/truncation_test.go deleted file mode 100644 index c5661500be..0000000000 --- a/pkg/og/storage/tree/truncation_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package tree - -import ( - "bytes" - - . "github.com/onsi/ginkgo/v2/dsl/core" - . "github.com/onsi/gomega" - "github.com/grafana/pyroscope/pkg/og/storage/dict" -) - -var _ = Describe("truncation", func() { - defer GinkgoRecover() - - BeforeEach(func() { - // we override these two to better see what's going on - lostDuringSerializationName = []byte("ls") - lostDuringRenderingName = jsonableSlice("lr") - }) - - AfterEach(func() { - lostDuringSerializationName = []byte("other") - lostDuringRenderingName = jsonableSlice("other") - }) - - Context("small tree", func() { - var treeA *Tree - // treeA := New() - BeforeEach(func() { - treeA = New() - treeA.Insert([]byte("a"), uint64(1)) - treeA.Insert([]byte("b"), uint64(2)) - treeA.Insert([]byte("c"), uint64(3)) - }) - - Context("with dictionary", func() { - d := dict.New() - It("after serialization drops node 'a'", func() { - buf := &bytes.Buffer{} - treeA.SerializeTruncate(d, 3, buf) - b := buf.Bytes() - treeB, err := Deserialize(d, bytes.NewReader(b)) - Expect(err).ToNot(HaveOccurred()) - Expect(treeB.StringWithEmpty()).To(Equal(treeStr(`"b" 2|"c" 3|"ls" 1|`))) - - treeA.Insert([]byte("d"), uint64(1)) - - buf = &bytes.Buffer{} - treeA.SerializeTruncate(d, 3, buf) - b = buf.Bytes() - - treeC, err := Deserialize(d, bytes.NewReader(b)) - Expect(err).ToNot(HaveOccurred()) - Expect(treeC.StringWithEmpty()).To(Equal(treeStr(`"b" 2|"c" 3|"ls" 2|`))) - Expect(treeC.StringWithEmpty()).To(Equal(treeA.StringWithEmpty())) - }) - }) - - Context("without dictionary", func() { - It("after serialization drops node 'a'", func() { - buf := &bytes.Buffer{} - treeA.SerializeTruncateNoDict(3, buf) - treeB, err := DeserializeNoDict(buf) - Expect(err).ToNot(HaveOccurred()) - Expect(treeB.StringWithEmpty()).To(Equal(treeStr(`"b" 2|"c" 3|"ls" 1|`))) - }) - }) - }) - - // TODO(petethepig): add more tests -}) diff --git a/pkg/og/storage/types.go b/pkg/og/storage/types.go index d522f852eb..0f2937ab07 100644 --- a/pkg/og/storage/types.go +++ b/pkg/og/storage/types.go @@ -6,9 +6,9 @@ import ( "context" "time" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/segment" - "github.com/grafana/pyroscope/pkg/og/storage/tree" + "github.com/grafana/pyroscope/api/model/labelset" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" ) // MetricsExporter exports values of particular stack traces sample from profiling @@ -32,7 +32,7 @@ type SampleObserver interface { type PutInput struct { StartTime time.Time EndTime time.Time - Key *segment.Key + LabelSet *labelset.LabelSet Val *tree.Tree SpyName string SampleRate uint32 diff --git a/pkg/og/structs/cappedarr/cappedarr_suite_test.go b/pkg/og/structs/cappedarr/cappedarr_suite_test.go deleted file mode 100644 index 2ad0fbc069..0000000000 --- a/pkg/og/structs/cappedarr/cappedarr_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package cappedarr_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestCappedarr(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Cappedarr Suite") -} diff --git a/pkg/og/structs/cappedarr/cappedarr_test.go b/pkg/og/structs/cappedarr/cappedarr_test.go index 967ed86220..b10355eb25 100644 --- a/pkg/og/structs/cappedarr/cappedarr_test.go +++ b/pkg/og/structs/cappedarr/cappedarr_test.go @@ -2,32 +2,27 @@ package cappedarr import ( "math/rand" + "testing" "time" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/require" ) -var _ = Describe("cappedarr", func() { - Describe("MinValue", func() { - defer GinkgoRecover() - Context("simple case", func() { - It("returns correct value", func() { - values := []uint64{1, 2, 3, 4, 5, 6} - for i := 0; i < 1000; i++ { - ca := New(4) - rand.Seed(time.Now().UnixNano()) - rand.Shuffle(len(values), func(i, j int) { - values[i], values[j] = values[j], values[i] - }) +func TestMinValue(t *testing.T) { + t.Run("simple case returns correct value", func(t *testing.T) { + values := []uint64{1, 2, 3, 4, 5, 6} + for i := 0; i < 1000; i++ { + ca := New(4) + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(values), func(i, j int) { + values[i], values[j] = values[j], values[i] + }) - for _, v := range values { - ca.Push(v) - } + for _, v := range values { + ca.Push(v) + } - Expect(ca.MinValue()).To(Equal(uint64(3))) - } - }) - }) + require.Equal(t, uint64(3), ca.MinValue()) + } }) -}) +} diff --git a/pkg/og/structs/flamebearer/convert/convert.go b/pkg/og/structs/flamebearer/convert/convert.go index 66ba930713..b47f1a7977 100644 --- a/pkg/og/structs/flamebearer/convert/convert.go +++ b/pkg/og/structs/flamebearer/convert/convert.go @@ -9,15 +9,16 @@ import ( "reflect" "strconv" "strings" - "time" "unicode" - "github.com/grafana/pyroscope/pkg/og/agent/spy" - "github.com/grafana/pyroscope/pkg/og/convert/perf" - "github.com/grafana/pyroscope/pkg/og/convert/pprof" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/tree" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/convert/perf" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) // ProfileFile represents content to be converted to flamebearer. @@ -46,7 +47,7 @@ const ( ProfileFileTypePerfScript ProfileFileType = "perf_script" ) -type ConverterFn func(b []byte, name string, maxNodes int) ([]*flamebearer.FlamebearerProfile, error) +type ConverterFn func(b []byte, name string, limits Limits) ([]*flamebearer.FlamebearerProfile, error) var formatConverters = map[ProfileFileType]ConverterFn{ ProfileFileTypeJSON: JSONToProfile, @@ -55,12 +56,17 @@ var formatConverters = map[ProfileFileType]ConverterFn{ ProfileFileTypePerfScript: PerfScriptToProfile, } -func FlamebearerFromFile(f ProfileFile, maxNodes int) ([]*flamebearer.FlamebearerProfile, error) { +type Limits struct { + MaxNodes int + MaxProfileSizeBytes int +} + +func FlamebearerFromFile(f ProfileFile, limits Limits) ([]*flamebearer.FlamebearerProfile, error) { convertFn, _, err := Converter(f) if err != nil { return nil, err } - return convertFn(f.Data, f.Name, maxNodes) + return convertFn(f.Data, f.Name, limits) } // Converter returns a ConverterFn that converts to @@ -70,8 +76,8 @@ func Converter(p ProfileFile) (ConverterFn, ProfileFileType, error) { if err != nil { return nil, "", err } - return func(b []byte, name string, maxNodes int) ([]*flamebearer.FlamebearerProfile, error) { - fbs, err := convertFn(b, name, maxNodes) + return func(b []byte, name string, limits Limits) ([]*flamebearer.FlamebearerProfile, error) { + fbs, err := convertFn(b, name, limits) if err != nil { return nil, fmt.Errorf("unable to process the profile. The profile was detected as %q: %w", converterToFormat(convertFn), err) @@ -157,7 +163,7 @@ func converter(p ProfileFile) (ConverterFn, error) { return CollapsedToProfile, nil } -func JSONToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.FlamebearerProfile, error) { +func JSONToProfile(b []byte, name string, limits Limits) ([]*flamebearer.FlamebearerProfile, error) { var profile flamebearer.FlamebearerProfile if err := json.Unmarshal(b, &profile); err != nil { return nil, fmt.Errorf("unable to unmarshall JSON: %w", err) @@ -174,7 +180,7 @@ func JSONToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.Flamebea pc := flamebearer.ProfileConfig{ Tree: t, Name: profile.Metadata.Name, - MaxNodes: maxNodes, + MaxNodes: limits.MaxNodes, Metadata: metadata.Metadata{ SpyName: profile.Metadata.SpyName, SampleRate: profile.Metadata.SampleRate, @@ -186,37 +192,105 @@ func JSONToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.Flamebea return []*flamebearer.FlamebearerProfile{&p}, nil } -func PprofToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.FlamebearerProfile, error) { - var p tree.Profile - if err := pprof.Decode(bytes.NewReader(b), &p); err != nil { +func getProfileType(name string, sampleType int, p *profilev1.Profile) (*typesv1.ProfileType, error) { + tp := &typesv1.ProfileType{ + Name: name, + } + + // check if the sampleID is valid + if sampleType < 0 || sampleType >= len(p.SampleType) { + return nil, fmt.Errorf("invalid sampleID: %d", sampleType) + } + + if p.PeriodType == nil { + return nil, fmt.Errorf("PeriodType is nil") + } + + invalidStr := func(i int) bool { + return i < 0 || i > len(p.StringTable) + } + if v := int(p.PeriodType.Type); invalidStr(v) { + return nil, fmt.Errorf("invalid PeriodType: %d", v) + } else { + tp.PeriodType = p.StringTable[v] + } + if v := int(p.PeriodType.Unit); invalidStr(v) { + return nil, fmt.Errorf("invalid PeriodUnit: %d", v) + } else { + tp.PeriodUnit = p.StringTable[v] + } + if v := int(p.SampleType[sampleType].Type); invalidStr(v) { + return nil, fmt.Errorf("invalid SampleType[%d]: %d", sampleType, v) + } else { + tp.SampleType = p.StringTable[v] + } + if v := int(p.SampleType[sampleType].Unit); invalidStr(v) { + return nil, fmt.Errorf("invalid SampleUnit[%d]: %d", sampleType, v) + } else { + tp.SampleUnit = p.StringTable[v] + } + + tp.ID = fmt.Sprintf("%s:%s:%s:%s:%s", name, tp.SampleType, tp.SampleUnit, tp.PeriodType, tp.PeriodUnit) + return tp, nil +} + +func PprofToProfile(b []byte, name string, limits Limits) ([]*flamebearer.FlamebearerProfile, error) { + prof, err := pprof.RawFromBytesWithLimit(b, int64(limits.MaxProfileSizeBytes)) + if err != nil { return nil, fmt.Errorf("parsing pprof: %w", err) } + p := prof.Profile + + t := model.NewStacktraceTree(int(limits.MaxNodes * 2)) + stack := make([]int32, 0, 64) + m := make(map[uint64]int32) + fbs := make([]*flamebearer.FlamebearerProfile, 0) - for _, stype := range p.SampleTypes() { - sampleRate := uint32(100) - units := metadata.SamplesUnits - if c, ok := tree.DefaultSampleTypeMapping[stype]; ok { - units = c.Units - if c.Sampled && p.Period > 0 { - sampleRate = uint32(time.Second / time.Duration(p.Period)) + for sampleType := range p.SampleType { + t.Reset() + + for i := range p.Sample { + stack = stack[:0] + for j := range p.Sample[i].LocationId { + locIdx := int(p.Sample[i].LocationId[j]) - 1 + if locIdx < 0 || len(p.Location) <= locIdx { + return nil, fmt.Errorf("invalid location ID %d in sample %d", p.Sample[i].LocationId[j], i) + } + + loc := p.Location[locIdx] + if len(loc.Line) > 0 { + for l := range loc.Line { + stack = append(stack, int32(p.Function[loc.Line[l].FunctionId-1].Name)) + } + continue + } + addr, ok := m[loc.Address] + if !ok { + addr = int32(len(p.StringTable)) + p.StringTable = append(p.StringTable, strconv.FormatInt(int64(loc.Address), 16)) + m[loc.Address] = addr + } + stack = append(stack, addr) } + + if sampleType < 0 || sampleType >= len(p.Sample[i].Value) { + return nil, fmt.Errorf("invalid sampleType index %d for sample %d (len=%d)", sampleType, i, len(p.Sample[i].Value)) + } + + t.Insert(stack, p.Sample[i].Value[sampleType]) + } + + tp, err := getProfileType(name, sampleType, p) + if err != nil { + return nil, err + } + + names := make([]model.FunctionName, len(p.StringTable)) + for i, s := range p.StringTable { + names[i] = model.FunctionName(s) } - t := tree.New() - p.Get(stype, func(_labels *spy.Labels, name []byte, val int) error { - t.Insert(name, uint64(val)) - return nil - }) - fb := flamebearer.NewProfile(flamebearer.ProfileConfig{ - Tree: t, - Name: stype, - MaxNodes: maxNodes, - Metadata: metadata.Metadata{ - SpyName: "unknown", - SampleRate: sampleRate, - Units: units, - }, - }) - fbs = append(fbs, &fb) + fg := model.NewFlameGraph(t.Tree(int64(limits.MaxNodes), names), int64(limits.MaxNodes)) + fbs = append(fbs, model.ExportToFlamebearer(fg, tp)) } if len(fbs) == 0 { return nil, errors.New("no supported sample type found") @@ -224,7 +298,7 @@ func PprofToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.Flamebe return fbs, nil } -func CollapsedToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.FlamebearerProfile, error) { +func CollapsedToProfile(b []byte, name string, limits Limits) ([]*flamebearer.FlamebearerProfile, error) { t := tree.New() for _, line := range bytes.Split(b, []byte("\n")) { if len(line) == 0 { @@ -243,7 +317,7 @@ func CollapsedToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.Fla fb := flamebearer.NewProfile(flamebearer.ProfileConfig{ Name: name, Tree: t, - MaxNodes: maxNodes, + MaxNodes: limits.MaxNodes, Metadata: metadata.Metadata{ SpyName: "unknown", SampleRate: 100, // We don't have this information, use the default @@ -252,7 +326,7 @@ func CollapsedToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.Fla return []*flamebearer.FlamebearerProfile{&fb}, nil } -func PerfScriptToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.FlamebearerProfile, error) { +func PerfScriptToProfile(b []byte, name string, limits Limits) ([]*flamebearer.FlamebearerProfile, error) { t := tree.New() p := perf.NewScriptParser(b) events, err := p.ParseEvents() @@ -265,7 +339,7 @@ func PerfScriptToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.Fl fb := flamebearer.NewProfile(flamebearer.ProfileConfig{ Name: name, Tree: t, - MaxNodes: maxNodes, + MaxNodes: limits.MaxNodes, Metadata: metadata.Metadata{ SpyName: "unknown", SampleRate: 100, // We don't have this information, use the default diff --git a/pkg/og/structs/flamebearer/convert/convert_bench_test.go b/pkg/og/structs/flamebearer/convert/convert_bench_test.go new file mode 100644 index 0000000000..a9fa93ef79 --- /dev/null +++ b/pkg/og/structs/flamebearer/convert/convert_bench_test.go @@ -0,0 +1,23 @@ +package convert + +import ( + "io" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func BenchmarkPprofToProfile(b *testing.B) { + f, err := os.Open("./testdata/cpu-unknown.pb.gz") + require.NoError(b, err) + defer f.Close() + data, err := io.ReadAll(f) + require.NoError(b, err) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + PprofToProfile(data, "test", Limits{MaxNodes: 16384}) + } + b.StopTimer() +} diff --git a/pkg/og/structs/flamebearer/convert/convert_suite_test.go b/pkg/og/structs/flamebearer/convert/convert_suite_test.go deleted file mode 100644 index 7d73600270..0000000000 --- a/pkg/og/structs/flamebearer/convert/convert_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package convert_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestServer(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Flamebearer Convert Suite") -} diff --git a/pkg/og/structs/flamebearer/convert/convert_test.go b/pkg/og/structs/flamebearer/convert/convert_test.go index cfe268cf45..d97143e4e9 100644 --- a/pkg/og/structs/flamebearer/convert/convert_test.go +++ b/pkg/og/structs/flamebearer/convert/convert_test.go @@ -1,704 +1,163 @@ package convert import ( - "io/ioutil" + "os" "reflect" + "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ) -var _ = Describe("Server", func() { - Describe("Detecting format", func() { - Context("with a valid pprof type", func() { - When("there's only type", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Type: "pprof", - } - }) - It("should return pprof as type is be enough to detect the type", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("there's pprof type and json filename", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.json", - Type: "pprof", - } - }) - It("should return pprof as type takes precedence over filename", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's pprof type and json profile contents", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte(`{"flamebearer":""}`), - Type: "pprof", - } - }) - It("should return pprof as type takes precedence over profile contents", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with no (valid) type and a valid pprof filename", func() { - When("there's pprof filename and json profile contents", func() { - var m ProfileFile - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.pprof", - Data: []byte(`{"flamebearer":""}`), - } - }) - - It("should return pprof as filename takes precedence over profile contents", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("there's pprof filename and an unsupported type", func() { - var m ProfileFile - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.pprof", - Type: "unsupported", - } - }) - - It("should return pprof as unsupported type is ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with no (valid) type and filename, a valid pprof profile", func() { - When("there's a profile with uncompressed pprof content", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte{0x0a, 0x04}, - } - }) - - It("should return pprof", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's a profile with compressed pprof content", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte{0x1f, 0x8b}, - } - }) - - It("should return pprof", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's a profile with compressed pprof content and an unsupported type", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte{0x1f, 0x8b}, - Type: "unsupported", - } - }) - - It("should return pprof as unsupported types are ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's a profile with compressed pprof content and unsupported filename", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.unsupported", - Data: []byte{0x1f, 0x8b}, - } - }) - - It("should return pprof as unsupported filenames are ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PprofToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with a valid json type", func() { - When("there's only type", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Type: "json", - } - }) - It("should return json as type is be enough to detect the type", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("there's json type and pprof filename", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.pprof", - Type: "json", - } - }) - It("should return json as type takes precedence over filename", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's json type and pprof profile contents", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte{0x1f, 0x8b}, - Type: "json", - } - }) - It("should return json as type takes precedence over profile contents", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with no (valid) type and a valid json filename", func() { - When("there's json filename and pprof profile contents", func() { - var m ProfileFile - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.json", - Data: []byte{0x1f, 0x8b}, - } - }) - - It("should return json as filename takes precedence over profile contents", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("there's json filename and an unsupported type", func() { - var m ProfileFile - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.json", - Type: "unsupported", - } - }) - - It("should return json as unsupported type is ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with no (valid) type and filename, a valid json profile", func() { - When("there's a profile with json content", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte(`{"flamebearer":""}`), - } - }) - - It("should return json", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's a profile with json content and an unsupported type", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte(`{"flamebearer":""}`), - Type: "unsupported", - } - }) - - It("should return json as unsupported types are ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's a profile with json content and unsupported filename", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.unsupported", - Data: []byte(`{"flamebearer":""}`), - } - }) - - It("should return json as unsupported filenames are ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(JSONToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with a valid collapsed type", func() { - When("there's only type", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Type: "collapsed", - } - }) - It("should return collapsed as type is be enough to detect the type", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("there's collapsed type and pprof filename", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.pprof", - Type: "collapsed", - } - }) - It("should return collapsed as type takes precedence over filename", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's json type and pprof profile contents", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte{0x1f, 0x8b}, - Type: "collapsed", - } - }) - It("should return collapsed as type takes precedence over profile contents", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with no (valid) type and a valid collapsed filename", func() { - When("there's collapsed filename and pprof profile contents", func() { - var m ProfileFile - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.collapsed", - Data: []byte{0x1f, 0x8b}, - } - }) - - It("should return collapsed as filename takes precedence over profile contents", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("there's collapsed filename and an unsupported type", func() { - var m ProfileFile - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.collapsed", - Type: "unsupported", - } - }) - - It("should return collapsed as unsupported type is ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's collapsed text filename and an unsupported type", func() { - var m ProfileFile - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.collapsed.txt", - Type: "unsupported", - } - }) - - It("should return collapsed as unsupported type is ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) - - Context("with no (valid) type and filename, a valid collapsed profile", func() { - When("there's a profile with collapsed content", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte("fn1 1\nfn2 2"), - } - }) - - It("should return collapsed", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - - When("there's a profile with collapsed content and an unsupported type", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte("fn1 1\nfn2 2"), - Type: "unsupported", - } - }) +func readFile(path string) []byte { + f, err := os.ReadFile(path) + if err != nil { + panic(err) + } + return f +} - It("should return collapsed as unsupported types are ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) +func requireConverter(t *testing.T, m ProfileFile, expected any) { + t.Helper() - When("there's a profile with collapsed content and unsupported filename", func() { - var m ProfileFile + f, err := converter(m) + require.NoError(t, err) + require.NotNil(t, f) + require.Equal(t, reflect.ValueOf(expected).Pointer(), reflect.ValueOf(f).Pointer()) +} - BeforeEach(func() { - m = ProfileFile{ - Name: "profile.unsupported", - Data: []byte("fn1 1\nfn2 2"), - } - }) +func TestConverterDetectingFormat(t *testing.T) { + perfScriptData := []byte("java 12688 [002] 6544038.708352: cpu-clock:\n\n") + + tests := []struct { + name string + file ProfileFile + expected any + wantErr bool + }{ + // pprof by type + {name: "pprof type only", file: ProfileFile{Type: "pprof"}, expected: PprofToProfile}, + {name: "pprof type over json filename", file: ProfileFile{Name: "profile.json", Type: "pprof"}, expected: PprofToProfile}, + {name: "pprof type over json content", file: ProfileFile{Data: []byte(`{"flamebearer":""}`), Type: "pprof"}, expected: PprofToProfile}, + // pprof by filename + {name: "pprof filename over json content", file: ProfileFile{Name: "profile.pprof", Data: []byte(`{"flamebearer":""}`)}, expected: PprofToProfile}, + {name: "pprof filename ignores unsupported type", file: ProfileFile{Name: "profile.pprof", Type: "unsupported"}, expected: PprofToProfile}, + // pprof by content + {name: "pprof uncompressed content", file: ProfileFile{Data: []byte{0x0a, 0x04}}, expected: PprofToProfile}, + {name: "pprof gzip content", file: ProfileFile{Data: []byte{0x1f, 0x8b}}, expected: PprofToProfile}, + {name: "pprof gzip ignores unsupported type", file: ProfileFile{Data: []byte{0x1f, 0x8b}, Type: "unsupported"}, expected: PprofToProfile}, + {name: "pprof gzip ignores unsupported filename", file: ProfileFile{Name: "profile.unsupported", Data: []byte{0x1f, 0x8b}}, expected: PprofToProfile}, + // json by type + {name: "json type only", file: ProfileFile{Type: "json"}, expected: JSONToProfile}, + {name: "json type over pprof filename", file: ProfileFile{Name: "profile.pprof", Type: "json"}, expected: JSONToProfile}, + {name: "json type over gzip content", file: ProfileFile{Data: []byte{0x1f, 0x8b}, Type: "json"}, expected: JSONToProfile}, + // json by filename + {name: "json filename over gzip content", file: ProfileFile{Name: "profile.json", Data: []byte{0x1f, 0x8b}}, expected: JSONToProfile}, + {name: "json filename ignores unsupported type", file: ProfileFile{Name: "profile.json", Type: "unsupported"}, expected: JSONToProfile}, + // json by content + {name: "json content", file: ProfileFile{Data: []byte(`{"flamebearer":""}`)}, expected: JSONToProfile}, + {name: "json content ignores unsupported type", file: ProfileFile{Data: []byte(`{"flamebearer":""}`), Type: "unsupported"}, expected: JSONToProfile}, + {name: "json content ignores unsupported filename", file: ProfileFile{Name: "profile.unsupported", Data: []byte(`{"flamebearer":""}`)}, expected: JSONToProfile}, + // collapsed by type + {name: "collapsed type only", file: ProfileFile{Type: "collapsed"}, expected: CollapsedToProfile}, + {name: "collapsed type over pprof filename", file: ProfileFile{Name: "profile.pprof", Type: "collapsed"}, expected: CollapsedToProfile}, + {name: "collapsed type over gzip content", file: ProfileFile{Data: []byte{0x1f, 0x8b}, Type: "collapsed"}, expected: CollapsedToProfile}, + // collapsed by filename + {name: "collapsed filename over gzip content", file: ProfileFile{Name: "profile.collapsed", Data: []byte{0x1f, 0x8b}}, expected: CollapsedToProfile}, + {name: "collapsed filename ignores unsupported type", file: ProfileFile{Name: "profile.collapsed", Type: "unsupported"}, expected: CollapsedToProfile}, + {name: "collapsed txt filename ignores unsupported type", file: ProfileFile{Name: "profile.collapsed.txt", Type: "unsupported"}, expected: CollapsedToProfile}, + // collapsed by content + {name: "collapsed content", file: ProfileFile{Data: []byte("fn1 1\nfn2 2")}, expected: CollapsedToProfile}, + {name: "collapsed content ignores unsupported type", file: ProfileFile{Data: []byte("fn1 1\nfn2 2"), Type: "unsupported"}, expected: CollapsedToProfile}, + {name: "collapsed content ignores unsupported filename", file: ProfileFile{Name: "profile.unsupported", Data: []byte("fn1 1\nfn2 2")}, expected: CollapsedToProfile}, + // perf script + {name: "perf script by content", file: ProfileFile{Data: perfScriptData}, expected: PerfScriptToProfile}, + {name: "perf script by txt extension", file: ProfileFile{Name: "foo.txt", Data: perfScriptData}, expected: PerfScriptToProfile}, + {name: "perf script by extension", file: ProfileFile{Name: "foo.perf_script", Data: []byte("foo;bar 239")}, expected: PerfScriptToProfile}, + // error + {name: "empty profile file", file: ProfileFile{}, wantErr: true}, + } - It("should return collapsed as unsupported filenames are ignored", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(CollapsedToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.wantErr { + _, err := converter(tt.file) + require.Error(t, err) + return + } + requireConverter(t, tt.file, tt.expected) }) + } +} - Context("perf script", func() { - When("detect by content", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Data: []byte("java 12688 [002] 6544038.708352: cpu-clock:\n\n"), - } - }) - - It("should return perf_script", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PerfScriptToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("detect by .txt extension and content", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Name: "foo.txt", - Data: []byte("java 12688 [002] 6544038.708352: cpu-clock:\n\n"), - } - }) - - It("should return perf_script", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PerfScriptToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - When("detect by .perf_script extension", func() { - var m ProfileFile - - BeforeEach(func() { - m = ProfileFile{ - Name: "foo.perf_script", - Data: []byte("foo;bar 239"), - } - }) +func TestConvert(t *testing.T) { + t.Run("converts malformed pprof", func(t *testing.T) { + m := ProfileFile{ + Type: "pprof", + Data: readFile("./testdata/cpu-unknown.pb.gz"), + } - It("should return perf_script", func() { - // We want to compare functions, which is not ideal. - expected := reflect.ValueOf(PerfScriptToProfile).Pointer() - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) - Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected)) - }) - }) - }) + f, err := converter(m) + require.NoError(t, err) + require.NotNil(t, f) - Context("with an empty ProfileFile", func() { - var m ProfileFile - It("should return an error", func() { - _, err := converter(m) - Expect(err).ToNot(Succeed()) - }) - }) + b, err := f(m.Data, "appname", Limits{MaxNodes: 1024}) + require.NoError(t, err) + require.NotNil(t, b) }) - Describe("Calling DiffV1", func() { - Context("with v1 profiles", func() { - var base, diff *flamebearer.FlamebearerProfile - - When("Diff is called with valid and equal base and diff profiles", func() { - BeforeEach(func() { - base = &flamebearer.FlamebearerProfile{ - Version: 1, - FlamebearerProfileV1: flamebearer.FlamebearerProfileV1{ - Metadata: flamebearer.FlamebearerMetadataV1{ - Format: "single", - }, - // Taken from flamebearer test - Flamebearer: flamebearer.FlamebearerV1{ - Names: []string{"total", "a", "c", "b"}, - Levels: [][]int{ - {0, 3, 0, 0}, - {0, 3, 0, 1}, - {0, 1, 1, 3, 0, 2, 2, 2}, - }, - NumTicks: 3, - MaxSelf: 2, - }, - }, - } - - diff = &flamebearer.FlamebearerProfile{ - Version: 1, - FlamebearerProfileV1: flamebearer.FlamebearerProfileV1{ - Metadata: flamebearer.FlamebearerMetadataV1{ - Format: "single", - }, - // Taken from flamebearer test - Flamebearer: flamebearer.FlamebearerV1{ - Names: []string{"total", "a", "c", "b"}, - Levels: [][]int{ - {0, 3, 0, 0}, - {0, 3, 0, 1}, - {0, 1, 1, 3, 0, 2, 2, 2}, - }, - NumTicks: 3, - MaxSelf: 2, - }, - }, - } - }) + t.Run("handles pprof invalid fields gracefully", func(t *testing.T) { + p := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100}}, + }, + Location: []*profilev1.Location{ + {Id: 1, Address: 0x1000, Line: []*profilev1.Line{{FunctionId: 1, Line: 10}}}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 1}, + }, + StringTable: []string{"", "cpu", "count", "main"}, + } - It("returns the diff profile", func() { - fb, err := flamebearer.Diff("name", base, diff, 1024) - Expect(err).To(Succeed()) - Expect(fb.Version).To(Equal(uint(1))) - Expect(fb.Metadata.Name).To(Equal("name")) - Expect(fb.Metadata.Format).To(Equal("double")) - Expect(fb.Flamebearer.Names).To(Equal([]string{"total", "a", "c", "b"})) - Expect(fb.Flamebearer.Levels).To(Equal([][]int{ - {0, 3, 0, 0, 3, 0, 0}, - {0, 3, 0, 0, 3, 0, 1}, - {0, 1, 1, 0, 1, 1, 3, 0, 2, 2, 0, 2, 2, 2}, - })) - Expect(fb.Flamebearer.NumTicks).To(Equal(6)) - Expect(fb.Flamebearer.MaxSelf).To(Equal(2)) - Expect(fb.LeftTicks).To(Equal(uint64(3))) - Expect(fb.RightTicks).To(Equal(uint64(3))) - }) - }) - }) - }) -}) + data, err := proto.Marshal(p) + require.NoError(t, err) -var _ = Describe("Convert", func() { - It("converts malformed pprof", func() { m := ProfileFile{ Type: "pprof", - Data: readFile("./testdata/cpu-unknown.pb.gz"), + Data: data, } f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) + require.NoError(t, err) + require.NotNil(t, f) - b, err := f(m.Data, "appname", 1024) - Expect(err).To(BeNil()) - Expect(b).ToNot(BeNil()) + b, err := f(m.Data, "test-profile", Limits{MaxNodes: 1024}) + require.Error(t, err) + assert.Contains(t, err.Error(), "PeriodType is nil") + require.Nil(t, b) }) - Describe("JSON", func() { - It("prunes tree", func() { - m := ProfileFile{ - Type: "json", - Data: readFile("./testdata/profile.json"), - } + t.Run("JSON prunes tree", func(t *testing.T) { + m := ProfileFile{ + Type: "json", + Data: readFile("./testdata/profile.json"), + } - f, err := converter(m) - Expect(err).To(BeNil()) - Expect(f).ToNot(BeNil()) + f, err := converter(m) + require.NoError(t, err) + require.NotNil(t, f) - b, err := f(m.Data, "appname", 1) - Expect(err).To(BeNil()) - Expect(b).ToNot(BeNil()) + b, err := f(m.Data, "appname", Limits{MaxNodes: 1}) + require.NoError(t, err) + require.NotNil(t, b) - // 1 + total - Expect(len(b[0].FlamebearerProfileV1.Flamebearer.Levels)).To(Equal(2)) - }) + require.Len(t, b[0].FlamebearerProfileV1.Flamebearer.Levels, 2) }) -}) - -func readFile(path string) []byte { - f, err := ioutil.ReadFile(path) - if err != nil { - panic(err) - } - return f } diff --git a/pkg/og/structs/flamebearer/flamebearer.go b/pkg/og/structs/flamebearer/flamebearer.go index 37505baac6..3b917702c6 100644 --- a/pkg/og/structs/flamebearer/flamebearer.go +++ b/pkg/og/structs/flamebearer/flamebearer.go @@ -1,14 +1,13 @@ package flamebearer import ( - "errors" "fmt" "sort" - "github.com/grafana/pyroscope/pkg/og/storage/heatmap" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/segment" - "github.com/grafana/pyroscope/pkg/og/storage/tree" + "github.com/grafana/pyroscope/v2/pkg/og/storage/heatmap" + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/storage/segment" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" ) //revive:disable:max-public-structs Config structs @@ -162,49 +161,6 @@ func convertGroups(v map[string]*segment.Timeline) map[string]*FlamebearerTimeli return res } -func NewCombinedProfile(base, diff ProfileConfig) (FlamebearerProfile, error) { - if base.Metadata.Units != diff.Metadata.Units { - // if one of them is empty, it still makes sense merging the profiles - if base.Metadata.Units != "" && diff.Metadata.Units != "" { - msg := fmt.Sprintf("left units (%s) does not match right units (%s)", base.Metadata.Units, diff.Metadata.Units) - return FlamebearerProfile{}, errors.New(msg) - } - } - - if base.Metadata.SampleRate != diff.Metadata.SampleRate { - // if one of them is empty, it still makes sense merging the profiles - if base.Metadata.SampleRate != 0 && diff.Metadata.SampleRate != 0 { - msg := fmt.Sprintf("left sample rate (%d) does not match right sample rate (%d)", base.Metadata.SampleRate, diff.Metadata.SampleRate) - return FlamebearerProfile{}, errors.New(msg) - } - } - - // Figure out the non empty one, since we will use its attributes - // Notice that this does not handle when both are empty, since there's nothing todo - output := base - if isEmpty(base) { - output = diff - } - - lt, rt := tree.CombineTree(base.Tree, diff.Tree) - fb := tree.CombineToFlamebearerStruct(lt, rt, base.MaxNodes) - return FlamebearerProfile{ - Version: 1, - FlamebearerProfileV1: FlamebearerProfileV1{ - Flamebearer: newFlambearer(fb), - Timeline: nil, - LeftTicks: lt.Samples(), - RightTicks: rt.Samples(), - Metadata: newMetadata(base.Name, fb.Format, metadata.Metadata{ - SpyName: output.Metadata.SpyName, - SampleRate: output.Metadata.SampleRate, - Units: output.Metadata.Units, - AggregationType: output.Metadata.AggregationType, - }), - }, - }, nil -} - func newFlambearer(fb *tree.Flamebearer) FlamebearerV1 { return FlamebearerV1{ Names: fb.Names, @@ -299,44 +255,6 @@ func (fb FlamebearerProfileV1) Validate() error { return nil } -func isEmpty(p ProfileConfig) bool { - return p.Metadata.SampleRate == 0 || p.Tree == nil || p.Tree.Samples() == 0 -} - -// Diff takes two single profiles and generates a diff profile -func Diff(name string, base, diff *FlamebearerProfile, maxNodes int) (FlamebearerProfile, error) { - var fb FlamebearerProfile - bt, err := ProfileToTree(*base) - if err != nil { - return fb, fmt.Errorf("unable to convert base profile to tree: %w", err) - } - dt, err := ProfileToTree(*diff) - if err != nil { - return fb, fmt.Errorf("unable to convert diff profile to tree: %w", err) - } - baseProfile := ProfileConfig{ - Name: name, - Tree: bt, - MaxNodes: maxNodes, - Metadata: metadata.Metadata{ - SpyName: base.Metadata.SpyName, - SampleRate: base.Metadata.SampleRate, - Units: base.Metadata.Units, - }, - } - diffProfile := ProfileConfig{ - Name: name, - Tree: dt, - MaxNodes: maxNodes, - Metadata: metadata.Metadata{ - SpyName: diff.Metadata.SpyName, - SampleRate: diff.Metadata.SampleRate, - Units: diff.Metadata.Units, - }, - } - return NewCombinedProfile(baseProfile, diffProfile) -} - // ProfileToTree converts a FlamebearerProfile into a Tree // It currently only supports Single profiles func ProfileToTree(fb FlamebearerProfile) (*tree.Tree, error) { diff --git a/pkg/og/structs/flamebearer/flamebearer_suite_test.go b/pkg/og/structs/flamebearer/flamebearer_suite_test.go deleted file mode 100644 index faa34d2c35..0000000000 --- a/pkg/og/structs/flamebearer/flamebearer_suite_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package flamebearer_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - testing2 "github.com/grafana/pyroscope/pkg/og/testing" -) - -func TestFlamebearer(t *testing.T) { - testing2.SetupLogging() - RegisterFailHandler(Fail) - RunSpecs(t, "Flambearer Suite") -} diff --git a/pkg/og/structs/flamebearer/flamebearer_test.go b/pkg/og/structs/flamebearer/flamebearer_test.go index f0e7245f51..6eaffa9842 100644 --- a/pkg/og/structs/flamebearer/flamebearer_test.go +++ b/pkg/og/structs/flamebearer/flamebearer_test.go @@ -1,12 +1,13 @@ package flamebearer import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "testing" - "github.com/grafana/pyroscope/pkg/og/storage/metadata" - "github.com/grafana/pyroscope/pkg/og/storage/segment" - "github.com/grafana/pyroscope/pkg/og/storage/tree" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/og/storage/metadata" + "github.com/grafana/pyroscope/v2/pkg/og/storage/segment" + "github.com/grafana/pyroscope/v2/pkg/og/storage/tree" ) var ( @@ -20,370 +21,159 @@ var ( units = metadata.Units("units") ) -var _ = Describe("FlamebearerProfile", func() { - Context("single", func() { - It("sets all attributes correctly", func() { - // taken from tree package tests - tree := tree.New() - tree.Insert([]byte("a;b"), uint64(1)) - tree.Insert([]byte("a;c"), uint64(2)) - - timeline := &segment.Timeline{ - StartTime: startTime, - Samples: samples, - DurationDeltaNormalized: durationDelta, - Watermarks: watermarks, - } - - p := NewProfile(ProfileConfig{ - Name: "name", - Tree: tree, - MaxNodes: maxNodes, - Timeline: timeline, - Metadata: metadata.Metadata{ - SpyName: spyName, - SampleRate: sampleRate, - Units: units, - }, - }) - - // Flamebearer - Expect(p.Flamebearer.Names).To(Equal([]string{"total", "a", "c", "b"})) - Expect(p.Flamebearer.Levels).To(Equal([][]int{ - {0, 3, 0, 0}, - {0, 3, 0, 1}, - {0, 1, 1, 3, 0, 2, 2, 2}, - })) - Expect(p.Flamebearer.NumTicks).To(Equal(3)) - Expect(p.Flamebearer.MaxSelf).To(Equal(2)) - - // Metadata - Expect(p.Metadata.Name).To(Equal("name")) - Expect(p.Metadata.Format).To(Equal("single")) - Expect(p.Metadata.SpyName).To(Equal(spyName)) - Expect(p.Metadata.SampleRate).To(Equal(sampleRate)) - Expect(p.Metadata.Units).To(Equal(units)) - - // Timeline - Expect(p.Timeline.StartTime).To(Equal(startTime)) - Expect(p.Timeline.Samples).To(Equal(samples)) - Expect(p.Timeline.DurationDelta).To(Equal(durationDelta)) - Expect(p.Timeline.Watermarks).To(Equal(watermarks)) - - // Ticks - Expect(p.LeftTicks).To(BeZero()) - Expect(p.RightTicks).To(BeZero()) - - // Validate - Expect(p.Validate()).To(BeNil()) - }) - }) -}) - -var _ = Describe("Diff", func() { - var treeA *tree.Tree - var treeB *tree.Tree - - BeforeEach(func() { - treeA = tree.New() - treeA.Insert([]byte("a;b"), uint64(1)) - treeA.Insert([]byte("a;c"), uint64(2)) - treeB = tree.New() - treeB.Insert([]byte("a;b"), uint64(4)) - treeB.Insert([]byte("a;c"), uint64(8)) +func TestFlamebearerProfile(t *testing.T) { + t.Run("single sets all attributes correctly", func(t *testing.T) { + tr := tree.New() + tr.Insert([]byte("a;b"), uint64(1)) + tr.Insert([]byte("a;c"), uint64(2)) + + timeline := &segment.Timeline{ + StartTime: startTime, + Samples: samples, + DurationDeltaNormalized: durationDelta, + Watermarks: watermarks, + } + + p := NewProfile(ProfileConfig{ + Name: "name", + Tree: tr, + MaxNodes: maxNodes, + Timeline: timeline, + Metadata: metadata.Metadata{ + SpyName: spyName, + SampleRate: sampleRate, + Units: units, + }, + }) + + require.Equal(t, []string{"total", "a", "c", "b"}, p.Flamebearer.Names) + require.Equal(t, [][]int{ + {0, 3, 0, 0}, + {0, 3, 0, 1}, + {0, 1, 1, 3, 0, 2, 2, 2}, + }, p.Flamebearer.Levels) + require.Equal(t, 3, p.Flamebearer.NumTicks) + require.Equal(t, 2, p.Flamebearer.MaxSelf) + + require.Equal(t, "name", p.Metadata.Name) + require.Equal(t, "single", p.Metadata.Format) + require.Equal(t, spyName, p.Metadata.SpyName) + require.Equal(t, sampleRate, p.Metadata.SampleRate) + require.Equal(t, units, p.Metadata.Units) + + require.Equal(t, startTime, p.Timeline.StartTime) + require.Equal(t, samples, p.Timeline.Samples) + require.Equal(t, durationDelta, p.Timeline.DurationDelta) + require.Equal(t, watermarks, p.Timeline.Watermarks) + + require.Zero(t, p.LeftTicks) + require.Zero(t, p.RightTicks) + + require.NoError(t, p.Validate()) }) - - Context("sampleRate does not match", func() { - When("they are both set", func() { - It("returns an error", func() { - left := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: 100}, - Tree: treeA, - MaxNodes: maxNodes, - } - right := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: 101}, - Tree: treeB, - MaxNodes: maxNodes, - } - _, err := NewCombinedProfile(left, right) - Expect(err).To(MatchError("left sample rate (100) does not match right sample rate (101)")) - }) - }) - - When("one of them is empty", func() { - It("does not return an error", func() { - left := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: 0}, - Tree: treeA, - MaxNodes: maxNodes, - } - right := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: 101}, - Tree: treeB, - MaxNodes: maxNodes, - } - - _, err := NewCombinedProfile(left, right) - Expect(err).ToNot(HaveOccurred()) - - _, err = NewCombinedProfile(right, left) - Expect(err).ToNot(HaveOccurred()) - }) - }) - }) - - Context("units does not match", func() { - When("they are both set", func() { - It("returns an error", func() { - left := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{Units: "unitA", SampleRate: sampleRate}, - Tree: treeA, - MaxNodes: maxNodes, - } - right := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{Units: "unitB", SampleRate: sampleRate}, - Tree: treeB, - MaxNodes: maxNodes, - } - _, err := NewCombinedProfile(left, right) - Expect(err).To(MatchError("left units (unitA) does not match right units (unitB)")) - }) - }) - - When("one of them is empty", func() { - It("does not return an error", func() { - left := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: sampleRate}, - Tree: treeA, - MaxNodes: maxNodes, - } - right := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: sampleRate, Units: "unitB"}, - Tree: treeB, - MaxNodes: maxNodes, - } - - _, err := NewCombinedProfile(left, right) - Expect(err).ToNot(HaveOccurred()) - - _, err = NewCombinedProfile(right, left) - Expect(err).ToNot(HaveOccurred()) - }) - }) - }) - - Context("diff", func() { - It("sets all attributes correctly", func() { - // taken from tree package tests - treeA := tree.New() - treeA.Insert([]byte("a;b"), uint64(1)) - treeA.Insert([]byte("a;c"), uint64(2)) - treeB := tree.New() - treeB.Insert([]byte("a;b"), uint64(4)) - treeB.Insert([]byte("a;c"), uint64(8)) - - left := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: sampleRate, Units: units}, - Tree: treeA, - MaxNodes: maxNodes, - } - right := ProfileConfig{ - Name: "name", - Metadata: metadata.Metadata{SampleRate: sampleRate, Units: units}, - Tree: treeB, - MaxNodes: maxNodes, - } - - p, err := NewCombinedProfile(left, right) - Expect(err).ToNot(HaveOccurred()) - - // Flamebearer - Expect(p.Flamebearer.Names).To(Equal([]string{"total", "a", "c", "b"})) - Expect(p.Flamebearer.Levels).To(Equal([][]int{ - {0, 3, 0, 0, 12, 0, 0}, - {0, 3, 0, 0, 12, 0, 1}, - {0, 1, 1, 0, 4, 4, 3, 0, 2, 2, 0, 8, 8, 2}, - })) - Expect(p.Flamebearer.NumTicks).To(Equal(15)) - Expect(p.Flamebearer.MaxSelf).To(Equal(8)) - - // Metadata - Expect(p.Metadata.Name).To(Equal("name")) - Expect(p.Metadata.Format).To(Equal("double")) - Expect(p.Metadata.SpyName).To(Equal("")) - Expect(p.Metadata.SampleRate).To(Equal(sampleRate)) - Expect(p.Metadata.Units).To(Equal(units)) - - // Timeline - Expect(p.Timeline).To(BeNil()) - - // Ticks - Expect(p.LeftTicks).To(Equal(uint64(3))) - Expect(p.RightTicks).To(Equal(uint64(12))) - - // Validate - Expect(p.Validate()).To(BeNil()) - }) - }) -}) - -var _ = Describe("Checking profile validation", func() { - When("the version is invalid", func() { - var fb FlamebearerProfile - BeforeEach(func() { - fb.Version = 2 - }) - - Context("and we validate the profile", func() { - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("unsupported version 2")) - }) - }) - }) - - When("the format is unsupported", func() { - var fb FlamebearerProfile - - Context("and we validate the profile", func() { - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("unsupported format ")) - }) - }) - }) - - When("there are no names", func() { - var fb FlamebearerProfile - BeforeEach(func() { - fb.Metadata.Format = "single" - }) - - Context("and we validate the profile", func() { - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("a profile must have at least one symbol name")) - }) - }) - }) - - When("there are no levels", func() { - var fb FlamebearerProfile - BeforeEach(func() { - fb.Metadata.Format = "single" - fb.Flamebearer.Names = []string{"name"} - }) - - Context("and we validate the profile", func() { - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("a profile must have at least one profiling level")) - }) - }) - }) - - When("the level size is invalid for the profile format", func() { - Context("and we validate a single profile", func() { - var fb FlamebearerProfile - BeforeEach(func() { +} + +func TestFlamebearerProfileValidation(t *testing.T) { + tests := []struct { + name string + setup func(*FlamebearerProfile) + wantErr string + }{ + { + name: "unsupported version", + setup: func(fb *FlamebearerProfile) { + fb.Version = 2 + }, + wantErr: "unsupported version 2", + }, + { + name: "unsupported format", + setup: func(_ *FlamebearerProfile) {}, + wantErr: "unsupported format ", + }, + { + name: "no names", + setup: func(fb *FlamebearerProfile) { + fb.Metadata.Format = "single" + }, + wantErr: "a profile must have at least one symbol name", + }, + { + name: "no levels", + setup: func(fb *FlamebearerProfile) { + fb.Metadata.Format = "single" + fb.Flamebearer.Names = []string{"name"} + }, + wantErr: "a profile must have at least one profiling level", + }, + { + name: "invalid level size for single", + setup: func(fb *FlamebearerProfile) { fb.Metadata.Format = "single" fb.Flamebearer.Names = []string{"name"} fb.Flamebearer.Levels = [][]int{{0, 0, 0, 0, 0, 0, 0}} - }) - - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("a profile level should have a multiple of 4 values, but there's a level with 7 values")) - }) - }) - - Context("and we validate a double profile", func() { - var fb FlamebearerProfile - BeforeEach(func() { + }, + wantErr: "a profile level should have a multiple of 4 values, but there's a level with 7 values", + }, + { + name: "invalid level size for double", + setup: func(fb *FlamebearerProfile) { fb.Metadata.Format = "double" fb.Flamebearer.Names = []string{"name"} fb.Flamebearer.Levels = [][]int{{0, 0, 0, 0}} - }) - - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("a profile level should have a multiple of 7 values, but there's a level with 4 values")) - }) - }) - }) - - When("the name index is invalid", func() { - Context("and we validate a single profile", func() { - var fb FlamebearerProfile - BeforeEach(func() { + }, + wantErr: "a profile level should have a multiple of 7 values, but there's a level with 4 values", + }, + { + name: "invalid name index single", + setup: func(fb *FlamebearerProfile) { fb.Metadata.Format = "single" fb.Flamebearer.Names = []string{"name"} fb.Flamebearer.Levels = [][]int{{0, 0, 0, 1}} - }) - - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("invalid name index 1, it should be smaller than 1")) - }) - }) - - Context("and we validate a double profile", func() { - var fb FlamebearerProfile - BeforeEach(func() { + }, + wantErr: "invalid name index 1, it should be smaller than 1", + }, + { + name: "invalid name index double", + setup: func(fb *FlamebearerProfile) { fb.Metadata.Format = "double" fb.Flamebearer.Names = []string{"name"} fb.Flamebearer.Levels = [][]int{{0, 0, 0, 0, 0, 0, 1}} - }) - - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("invalid name index 1, it should be smaller than 1")) - }) - }) - }) - - When("the name index is negative", func() { - Context("and we validate a single profile", func() { - var fb FlamebearerProfile - BeforeEach(func() { + }, + wantErr: "invalid name index 1, it should be smaller than 1", + }, + { + name: "negative name index", + setup: func(fb *FlamebearerProfile) { fb.Metadata.Format = "single" fb.Flamebearer.Names = []string{"name"} fb.Flamebearer.Levels = [][]int{{0, 0, 0, -1}} - }) - - It("returns an error", func() { - Expect(fb.Validate()).To(MatchError("invalid name index -1, it should be a non-negative value")) - }) - }) - }) + }, + wantErr: "invalid name index -1, it should be a non-negative value", + }, + } - When("everything is valid", func() { - Context("and we validate a single profile", func() { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { var fb FlamebearerProfile - BeforeEach(func() { - fb.Metadata.Format = "single" - fb.Flamebearer.Names = []string{"name"} - fb.Flamebearer.Levels = [][]int{{0, 0, 0, 0}} - }) - - It("returns no error", func() { - Expect(fb.Validate()).To(BeNil()) - }) + tt.setup(&fb) + require.EqualError(t, fb.Validate(), tt.wantErr) }) + } - Context("and we validate a double profile", func() { - var fb FlamebearerProfile - BeforeEach(func() { - fb.Metadata.Format = "double" - fb.Flamebearer.Names = []string{"name"} - fb.Flamebearer.Levels = [][]int{{0, 0, 0, 0, 0, 0, 0}} - }) + t.Run("valid single profile", func(t *testing.T) { + var fb FlamebearerProfile + fb.Metadata.Format = "single" + fb.Flamebearer.Names = []string{"name"} + fb.Flamebearer.Levels = [][]int{{0, 0, 0, 0}} + require.NoError(t, fb.Validate()) + }) - It("returns an error", func() { - Expect(fb.Validate()).To(BeNil()) - }) - }) + t.Run("valid double profile", func(t *testing.T) { + var fb FlamebearerProfile + fb.Metadata.Format = "double" + fb.Flamebearer.Names = []string{"name"} + fb.Flamebearer.Levels = [][]int{{0, 0, 0, 0, 0, 0, 0}} + require.NoError(t, fb.Validate()) }) -}) +} diff --git a/pkg/og/structs/flamebearer/html.go b/pkg/og/structs/flamebearer/html.go index 026a13bbf0..fcd4e8b544 100644 --- a/pkg/og/structs/flamebearer/html.go +++ b/pkg/og/structs/flamebearer/html.go @@ -9,7 +9,7 @@ import ( "regexp" "text/template" - "github.com/grafana/pyroscope/pkg/og/build" + "github.com/grafana/pyroscope/v2/pkg/og/build" ) // TODO(kolesnikovae): Refactor to ./convert? diff --git a/pkg/og/structs/merge/merge_suite_test.go b/pkg/og/structs/merge/merge_suite_test.go deleted file mode 100644 index 4e3c984450..0000000000 --- a/pkg/og/structs/merge/merge_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package merge_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestMerge(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Merge Suite") -} diff --git a/pkg/og/structs/sortedmap/sortedmap.go b/pkg/og/structs/sortedmap/sortedmap.go deleted file mode 100644 index 821d8642a0..0000000000 --- a/pkg/og/structs/sortedmap/sortedmap.go +++ /dev/null @@ -1,33 +0,0 @@ -package sortedmap - -import ( - "sort" -) - -type SortedMap struct { - data map[string]interface{} - keys []string -} - -func (s *SortedMap) Put(k string, v interface{}) { - s.data[k] = v - i := sort.Search(len(s.keys), func(i int) bool { return s.keys[i] >= k }) - s.keys = append(s.keys, "") - copy(s.keys[i+1:], s.keys[i:]) - s.keys[i] = k -} - -func (s *SortedMap) Get(k string) (v interface{}) { - return s.data[k] -} - -func (s *SortedMap) Keys() []string { - return s.keys -} - -func New() *SortedMap { - return &SortedMap{ - data: make(map[string]interface{}), - keys: make([]string, 0), - } -} diff --git a/pkg/og/structs/sortedmap/sortedmap_suite_test.go b/pkg/og/structs/sortedmap/sortedmap_suite_test.go deleted file mode 100644 index f93229071f..0000000000 --- a/pkg/og/structs/sortedmap/sortedmap_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package sortedmap_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestSortedmap(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Sortedmap Suite") -} diff --git a/pkg/og/structs/transporttrie/diff_test.go b/pkg/og/structs/transporttrie/diff_test.go index 91c3d6d7b4..33957a9c99 100644 --- a/pkg/og/structs/transporttrie/diff_test.go +++ b/pkg/og/structs/transporttrie/diff_test.go @@ -1,31 +1,30 @@ package transporttrie import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "testing" + + "github.com/stretchr/testify/require" ) -var _ = Describe("trie package", func() { - Context("trie.Diff()", func() { - It("diffs 2 tries", func() { - t1 := New() - t1.Insert([]byte("foo"), uint64(1)) - t1.Insert([]byte("bar"), uint64(2)) - t1.Insert([]byte("baz"), uint64(3)) +func TestTrieDiff(t *testing.T) { + t.Run("diffs 2 tries", func(t *testing.T) { + t1 := New() + t1.Insert([]byte("foo"), uint64(1)) + t1.Insert([]byte("bar"), uint64(2)) + t1.Insert([]byte("baz"), uint64(3)) - t2 := New() - t2.Insert([]byte("foo"), uint64(3)) - t2.Insert([]byte("bar"), uint64(2)) - t2.Insert([]byte("baz"), uint64(1)) + t2 := New() + t2.Insert([]byte("foo"), uint64(3)) + t2.Insert([]byte("bar"), uint64(2)) + t2.Insert([]byte("baz"), uint64(1)) - t4 := New() - t4.Insert([]byte("foo"), uint64(0)) - t4.Insert([]byte("bar"), uint64(0)) - t4.Insert([]byte("baz"), uint64(2)) + t4 := New() + t4.Insert([]byte("foo"), uint64(0)) + t4.Insert([]byte("bar"), uint64(0)) + t4.Insert([]byte("baz"), uint64(2)) - t3 := t1.Diff(t2) + t3 := t1.Diff(t2) - Expect(t3.String()).To(Equal(t4.String())) - }) + require.Equal(t, t4.String(), t3.String()) }) -}) +} diff --git a/pkg/og/structs/transporttrie/merge.go b/pkg/og/structs/transporttrie/merge.go deleted file mode 100644 index 9df7ae9900..0000000000 --- a/pkg/og/structs/transporttrie/merge.go +++ /dev/null @@ -1,27 +0,0 @@ -package transporttrie - -import "github.com/grafana/pyroscope/pkg/og/structs/merge" - -func (dstTrie *Trie) Merge(srcTrieI merge.Merger) { - srcTrie := srcTrieI.(*Trie) - srcNodes := []*trieNode{srcTrie.root} - dstNodes := []*trieNode{dstTrie.root} - - for len(srcNodes) > 0 { - st := srcNodes[0] - srcNodes = srcNodes[1:] - - dt := dstNodes[0] - dstNodes = dstNodes[1:] - - for _, srcChildNode := range st.children { - dt.findNodeAt(srcChildNode.name, func(dstChildNode *trieNode) { - if srcChildNode.value > 0 { - dstChildNode.value = mergeFunc(dstChildNode.value, srcChildNode.value, dstTrie, srcTrie) - } - srcNodes = append([]*trieNode{srcChildNode}, srcNodes...) - dstNodes = append([]*trieNode{dstChildNode}, dstNodes...) - }) - } - } -} diff --git a/pkg/og/structs/transporttrie/merge_test.go b/pkg/og/structs/transporttrie/merge_test.go deleted file mode 100644 index fbcd518b44..0000000000 --- a/pkg/og/structs/transporttrie/merge_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package transporttrie - -import ( - "bytes" - - "github.com/sirupsen/logrus" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("trie package", func() { - Context("trie.Merge()", func() { - It("merges 2 tries", func() { - t1 := New() - t1.Insert([]byte("abc"), uint64(1)) - t1.Insert([]byte("abd"), uint64(2)) - - t2 := New() - t2.Insert([]byte("abc"), uint64(1)) - t2.Insert([]byte("abd"), uint64(2)) - - t3 := New() - t3.Insert([]byte("abc"), uint64(2)) - t3.Insert([]byte("abd"), uint64(4)) - - var buf1 bytes.Buffer - var buf2 bytes.Buffer - t1.Serialize(&buf1) - t2.Serialize(&buf2) - - logrus.Debug("t1", t1) - logrus.Debug("t2", t2) - logrus.Debug("t3", t3) - - Expect(buf1.Bytes()).To(Equal(buf2.Bytes())) - t1.Merge(t2) - - logrus.Debug("t1+2", t1) - - var buf3 bytes.Buffer - var buf4 bytes.Buffer - t3.Serialize(&buf3) - t1.Serialize(&buf4) - Expect(buf4).To(Equal(buf3)) - }) - }) -}) diff --git a/pkg/og/structs/transporttrie/serialize.go b/pkg/og/structs/transporttrie/serialize.go index e934e05ca6..5cd8e529b8 100644 --- a/pkg/og/structs/transporttrie/serialize.go +++ b/pkg/og/structs/transporttrie/serialize.go @@ -6,7 +6,7 @@ import ( "errors" "io" - "github.com/grafana/pyroscope/pkg/og/util/varint" + "github.com/grafana/pyroscope/v2/pkg/og/util/varint" ) func (t *Trie) Serialize(w io.Writer) error { diff --git a/pkg/og/structs/transporttrie/transporttrie_suite_test.go b/pkg/og/structs/transporttrie/transporttrie_suite_test.go deleted file mode 100644 index b2d9b512ce..0000000000 --- a/pkg/og/structs/transporttrie/transporttrie_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package transporttrie_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestTransporttrie(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Transporttrie Suite") -} diff --git a/pkg/og/structs/transporttrie/trie_test.go b/pkg/og/structs/transporttrie/trie_test.go index 0168175cef..ec8970c64f 100644 --- a/pkg/og/structs/transporttrie/trie_test.go +++ b/pkg/og/structs/transporttrie/trie_test.go @@ -6,13 +6,11 @@ import ( "hash" "hash/fnv" "math/rand" + "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/og/structs/merge" - "github.com/grafana/pyroscope/pkg/og/util/varint" + "github.com/grafana/pyroscope/v2/pkg/og/util/varint" ) func randStr(l int) []byte { @@ -20,8 +18,6 @@ func randStr(l int) []byte { for i := 0; i < l; i++ { buf[i] = byte(97) + byte(rand.Uint32()%10) } - // rand.Read(buf) - return buf } @@ -50,256 +46,147 @@ func (t trieHash) sum() uint64 { return t.h.Sum64() } -var _ = Describe("trie package", func() { - serializationExample := []byte("\x00\x00\x01\x02ab\x00\x02\x01c\x01\x00\x01d\x02\x00") - Context("trie.Serialize()", func() { - trie := New() - trie.Insert([]byte("abc"), 1) - trie.Insert([]byte("abd"), 2) - logrus.Debug("trie abc abd", trie) +var serializationExample = []byte("\x00\x00\x01\x02ab\x00\x02\x01c\x01\x00\x01d\x02\x00") - It("returns correct results", func() { - var buf bytes.Buffer - trie.Serialize(&buf) - Expect(buf.Bytes()).To(Equal(serializationExample)) - }) - - Context("Ran 1000000 times", func() { - var buf1 bytes.Buffer - trie.Serialize(&buf1) - It("returns the same result", func() { - var buf2 bytes.Buffer - trie.Serialize(&buf2) - Expect(buf2).To(Equal(buf1)) - }) - }) +func TestTrieSerialize(t *testing.T) { + trie := New() + trie.Insert([]byte("abc"), 1) + trie.Insert([]byte("abd"), 2) + + t.Run("returns correct results", func(t *testing.T) { + var buf bytes.Buffer + trie.Serialize(&buf) + require.Equal(t, serializationExample, buf.Bytes()) }) - Context("Ser/Deserialize()", func() { - It("returns correct results", func() { - for j := 0; j < 10; j++ { - // logrus.Debug("---") - trie := New() - // trie.Insert([]byte("acc"), []byte{1}) - // trie.Insert([]byte("abc"), []byte{2}) - // trie.Insert([]byte("abd"), []byte{3}) - // trie.Insert([]byte("ab"), []byte{4}) - for i := 0; i < 10; i++ { - trie.Insert(randStr(10), uint64(i)) - } - // trie.Insert([]byte("abc"), []byte{1}, true) - // trie.Insert([]byte("abc"), []byte{3}, true) - // trie.Insert([]byte("bar"), []byte{5}) - // trie.Insert([]byte("abd"), []byte{2}) - // trie.Insert([]byte("abce"), []byte{3}) - // trie.Insert([]byte("ab"), []byte{4}) - // trie.Insert([]byte("abc"), []byte{2}) - - // trie.Insert([]byte("baze"), []byte{1}) - // trie.Insert([]byte("baz"), []byte{2}) - // trie.Insert([]byte("bat"), []byte{3}) - // trie.Insert([]byte("bata"), []byte{4}) - // trie.Insert([]byte("batb"), []byte{5}) - // trie.Insert([]byte("bad"), []byte{6}) - // trie.Insert([]byte("bae"), []byte{7}) - // trie.Insert([]byte("zyx"), []byte{1}) - // trie.Insert([]byte("zy"), []byte{2}) - // trie.Insert([]byte(""), []byte{1}) - // trie.Insert([]byte("a"), []byte{2}) - // trie.Insert([]byte("b"), []byte{3}) - - // trie.Insert([]byte("1234567"), []byte{1}) - // trie.Insert([]byte("1234667"), []byte{2}) - // trie.Insert([]byte("1234767"), []byte{3}) - logrus.Debug("a", trie.String()) - strA := "" - trie.Iterate(func(k []byte, v uint64) { - strA += fmt.Sprintf("%q %d\n", k, v) - }) - logrus.Debug("strA", strA) - - var buf bytes.Buffer - trie.Serialize(&buf) - - r := bytes.NewReader(buf.Bytes()) - t, e := Deserialize(r) - strB := "" - t.Iterate(func(k []byte, v uint64) { - strB += fmt.Sprintf("%q %d\n", k, v) - }) - logrus.Debug("b", t.String()) - logrus.Debug("strB", strB) - Expect(e).To(BeNil()) - Expect(trie.String()).To(Equal(t.String())) - Expect(strA).To(Equal(strB)) - logrus.Debug("---/") - } - }) + t.Run("returns the same result on repeated serialize", func(t *testing.T) { + var buf1 bytes.Buffer + trie.Serialize(&buf1) + + var buf2 bytes.Buffer + trie.Serialize(&buf2) + require.Equal(t, buf1, buf2) }) +} + +func TestSerDeserialize(t *testing.T) { + t.Run("returns correct results", func(t *testing.T) { + for j := 0; j < 10; j++ { + trie := New() + for i := 0; i < 10; i++ { + trie.Insert(randStr(10), uint64(i)) + } + + strA := "" + trie.Iterate(func(k []byte, v uint64) { + strA += fmt.Sprintf("%q %d\n", k, v) + }) - Context("IterateRaw()", func() { - compareWithRawIterator := func(t *Trie) { - h1 := newTrieHash() - t.Iterate(h1.addUint64) var buf bytes.Buffer - Expect(t.Serialize(&buf)).ToNot(HaveOccurred()) + trie.Serialize(&buf) r := bytes.NewReader(buf.Bytes()) - h2 := newTrieHash() - tmpBuf := make([]byte, 0, 256) - Expect(IterateRaw(r, tmpBuf, h2.addInt)).ToNot(HaveOccurred()) + deserialized, err := Deserialize(r) + require.NoError(t, err) - Expect(h2.sum()).To(Equal(h1.sum())) + strB := "" + deserialized.Iterate(func(k []byte, v uint64) { + strB += fmt.Sprintf("%q %d\n", k, v) + }) + require.Equal(t, trie.String(), deserialized.String()) + require.Equal(t, strA, strB) } + }) +} - It("returns correct results", func() { - type value struct { - k string - v uint64 - } +func TestIterateRaw(t *testing.T) { + compareWithRawIterator := func(t *testing.T, tr *Trie) { + t.Helper() - values := []value{ - {"foo;bar;baz", 1}, - {"foo;bar;baz;a", 1}, - {"foo;bar;baz;b", 1}, - {"foo;bar;baz;c", 1}, - {"foo;bar;bar", 1}, - {"foo;bar;qux", 1}, - {"foo;bax;bar", 1}, - {"zoo;boo", 1}, - {"zoo;bao", 1}, - } + h1 := newTrieHash() + tr.Iterate(h1.addUint64) + var buf bytes.Buffer + require.NoError(t, tr.Serialize(&buf)) - trie := New() - for _, v := range values { - trie.Insert([]byte(v.k), v.v) - } + r := bytes.NewReader(buf.Bytes()) + h2 := newTrieHash() + tmpBuf := make([]byte, 0, 256) + require.NoError(t, IterateRaw(r, tmpBuf, h2.addInt)) - compareWithRawIterator(trie) - }) + require.Equal(t, h1.sum(), h2.sum()) + } - It("handles random tries properly", func() { - for j := 0; j < 10; j++ { - trie := New() - for i := 0; i < 10; i++ { - trie.Insert(randStr(10), uint64(i)) - } + t.Run("returns correct results", func(t *testing.T) { + type value struct { + k string + v uint64 + } - h1 := newTrieHash() - trie.Iterate(h1.addUint64) + values := []value{ + {"foo;bar;baz", 1}, + {"foo;bar;baz;a", 1}, + {"foo;bar;baz;b", 1}, + {"foo;bar;baz;c", 1}, + {"foo;bar;bar", 1}, + {"foo;bar;qux", 1}, + {"foo;bax;bar", 1}, + {"zoo;boo", 1}, + {"zoo;bao", 1}, + } - var buf bytes.Buffer - err := trie.Serialize(&buf) - Expect(err).To(BeNil()) + trie := New() + for _, v := range values { + trie.Insert([]byte(v.k), v.v) + } - r := bytes.NewReader(buf.Bytes()) - h2 := newTrieHash() - err = IterateRaw(r, nil, h2.addInt) - Expect(err).To(BeNil()) + compareWithRawIterator(t, trie) + }) - Expect(h2.sum()).To(Equal(h1.sum())) + t.Run("handles random tries properly", func(t *testing.T) { + for j := 0; j < 10; j++ { + trie := New() + for i := 0; i < 10; i++ { + trie.Insert(randStr(10), uint64(i)) } - }) - }) - Context("Deserialize()", func() { - trie := New() - trie.Insert([]byte("abc"), 1) - trie.Insert([]byte("ab"), 2) - logrus.Debug(trie.String()) - - It("returns correct results", func() { - r := bytes.NewReader(serializationExample) - t, e := Deserialize(r) - logrus.Debug(t.String()) - Expect(e).To(BeNil()) + h1 := newTrieHash() + trie.Iterate(h1.addUint64) + var buf bytes.Buffer - t.Serialize(&buf) - Expect(buf.Bytes()).To(Equal(serializationExample)) - }) - - Context("Ran 1000000 times", func() { - var buf1 bytes.Buffer - trie.Serialize(&buf1) - It("returns the same result", func() { - var buf2 bytes.Buffer - trie.Serialize(&buf2) - Expect(buf2).To(Equal(buf1)) - }) - }) + err := trie.Serialize(&buf) + require.NoError(t, err) + + r := bytes.NewReader(buf.Bytes()) + h2 := newTrieHash() + err = IterateRaw(r, nil, h2.addInt) + require.NoError(t, err) + + require.Equal(t, h1.sum(), h2.sum()) + } }) +} - Context("MergeTriesConcurrently()", func() { - It("merges 2 tries", func(done Done) { - for s := 0; s < 1000; s++ { - rand.Seed(int64(s)) - // logrus.Debug(s) - t1 := New() - t2 := New() - t3 := New() - // logrus.Debug("---") - n := 2 - n2 := 4 - for i := 0; i < n; i++ { - str := randStr(n2) - t1.Insert(str, uint64(i)) - t3.Insert(str, uint64(i)) - } - for i := 0; i < n; i++ { - str := randStr(n2) - t2.Insert(str, uint64(n+i)) - t3.Insert(str, uint64(n+i), true) - } - - // t1 := New() - // t1.Insert([]byte("abc"), []byte{1}) - // t1.Insert([]byte("abd"), []byte{2}) - // t1.Insert([]byte("abe"), []byte{2}) - - // t2 := New() - // t2.Insert([]byte("abc"), []byte{1}) - // t2.Insert([]byte("abd"), []byte{2}) - // t2.Insert([]byte("abf"), []byte{3}) - // t2.Insert([]byte("abef"), []byte{5}) - // t2.Insert([]byte("a"), []byte{6}) - // t2.Insert([]byte("ac"), []byte{7}) - // t2.Insert([]byte("aa"), []byte{8}) - - // t3 := New() - // t3.Insert([]byte("a"), []byte{6}) - // t3.Insert([]byte("ac"), []byte{7}) - // t3.Insert([]byte("aa"), []byte{8}) - // t3.Insert([]byte("abc"), []byte{2}) - // t3.Insert([]byte("abd"), []byte{4}) - // t3.Insert([]byte("abe"), []byte{2}) - // t3.Insert([]byte("abf"), []byte{3}) - // t3.Insert([]byte("abef"), []byte{5}) - - var buf1 bytes.Buffer - var buf2 bytes.Buffer - t1.Serialize(&buf1) - t2.Serialize(&buf2) - - // logrus.Debug("t1\n", t1.String()) - // logrus.Debug("t2\n", t2.String()) - // logrus.Debug("t3\n", t3.String()) - - // Expect(buf1.Bytes()).To(Equal(buf2.Bytes())) - tries := []merge.Merger{t1, t2} - rand.Shuffle(len(tries), func(i, j int) { - tries[i], tries[j] = tries[j], tries[i] - }) - t1I := merge.MergeTriesSerially(1, tries...) - t1 = t1I.(*Trie) - // logrus.Debug("t1m\n", t1.String()) - - var buf3 bytes.Buffer - var buf4 bytes.Buffer - t3.Serialize(&buf3) - t1.Serialize(&buf4) - Expect(buf4).To(Equal(buf3)) - } - close(done) - }, 1.0) +func TestDeserialize(t *testing.T) { + trie := New() + trie.Insert([]byte("abc"), 1) + trie.Insert([]byte("ab"), 2) + + t.Run("returns correct results", func(t *testing.T) { + r := bytes.NewReader(serializationExample) + deserialized, err := Deserialize(r) + require.NoError(t, err) + + var buf bytes.Buffer + deserialized.Serialize(&buf) + require.Equal(t, serializationExample, buf.Bytes()) + }) + + t.Run("returns the same result on repeated serialize", func(t *testing.T) { + var buf1 bytes.Buffer + trie.Serialize(&buf1) + + var buf2 bytes.Buffer + trie.Serialize(&buf2) + require.Equal(t, buf1, buf2) }) -}) +} diff --git a/pkg/og/testing/fake_listener.go b/pkg/og/testing/fake_listener.go deleted file mode 100644 index 3a879ef0bb..0000000000 --- a/pkg/og/testing/fake_listener.go +++ /dev/null @@ -1,61 +0,0 @@ -package testing - -import ( - "errors" - "net" - "sync" -) - -// FakeListener implements net.Listener and has an extra method (Provide) that allows -// you to queue a connection to be consumed via Accept. -type FakeListener struct { - ch chan net.Conn - closed bool - mutex *sync.Mutex -} - -func NewFakeListener() *FakeListener { - return &FakeListener{ - ch: make(chan net.Conn), - mutex: &sync.Mutex{}, - } -} - -func (fl *FakeListener) Provide(conn net.Conn) error { - fl.mutex.Lock() - defer fl.mutex.Unlock() - - if fl.closed { - return errors.New("connection closed") - } - - fl.ch <- conn - return nil -} - -func (fl *FakeListener) Accept() (net.Conn, error) { - conn, more := <-fl.ch - if more { - return conn, nil - } - - return nil, errors.New("connection closed") -} - -func (fl *FakeListener) Close() error { - fl.mutex.Lock() - defer fl.mutex.Unlock() - - if fl.closed { - return errors.New("connection closed") - } - - fl.closed = true - close(fl.ch) - return nil -} - -func (*FakeListener) Addr() net.Addr { - a, _ := net.ResolveTCPAddr("tcp", "fake-listener:1111") - return a -} diff --git a/pkg/og/testing/logging.go b/pkg/og/testing/logging.go deleted file mode 100644 index e491a301f0..0000000000 --- a/pkg/og/testing/logging.go +++ /dev/null @@ -1,19 +0,0 @@ -package testing - -import ( - "os" - - golog "log" - - "github.com/sirupsen/logrus" -) - -func init() { - golog.SetFlags(golog.Lshortfile | golog.Ldate | golog.Ltime) -} - -func SetupLogging() { - // log.SetFormatter(&log.JSONFormatter{}) - logrus.SetOutput(os.Stdout) - logrus.SetLevel(logrus.DebugLevel) -} diff --git a/pkg/og/testing/profile.go b/pkg/og/testing/profile.go deleted file mode 100644 index 8c1e0b87b0..0000000000 --- a/pkg/og/testing/profile.go +++ /dev/null @@ -1,55 +0,0 @@ -package testing - -import ( - "fmt" - "os" - "os/exec" - "runtime/pprof" - "time" - - "github.com/sirupsen/logrus" - - "github.com/felixge/fgprof" -) - -func FProfile(name string, cb func()) time.Duration { - t := time.Now() - path := "/tmp/profile-" + name + ".folded" - pathSVG := "/tmp/profile-" + name + ".svg" - f, err := os.Create(path) - if err == nil { - endProfile := fgprof.Start(f, fgprof.FormatFolded) - defer func() { - endProfile() - cmd := fmt.Sprintf("cat '%s' | grep -v gopark | flamegraph.pl > '%s'", path, pathSVG) - logrus.Debug("cmd", cmd) - err := exec.Command("sh", "-c", cmd).Run() - if err != nil { - panic(err) - } - }() - } - cb() - d := time.Since(t) - return d -} - -func Profile(name string, cb func()) time.Duration { - t := time.Now() - cb() - d := time.Since(t) - logrus.Debugf("%q took %s", name, d) - return d -} - -func PProfile(name string, cb func()) time.Duration { - t := time.Now() - f, err := os.Create("/tmp/profile-" + name + ".prof") - if err = pprof.StartCPUProfile(f); err == nil { - defer pprof.StopCPUProfile() - } - cb() - d := time.Since(t) - logrus.Debug(name, d) - return d -} diff --git a/pkg/og/testing/time.go b/pkg/og/testing/time.go deleted file mode 100644 index 11ca446a35..0000000000 --- a/pkg/og/testing/time.go +++ /dev/null @@ -1,25 +0,0 @@ -package testing - -import "time" - -var format = "2006-01-02-15:04:05.999999999 MST" - -func ParseTime(str string) time.Time { - r, err := time.Parse(format, str+" UTC") - if err != nil { - panic(err) - } - return r.UTC() -} - -func SimpleTime(i int) time.Time { - return time.Time{}.Add(time.Duration(i) * time.Second).UTC() -} - -func SimpleUTime(i int) time.Time { - return time.Unix(int64(i), 0) -} - -func PrintTime(t time.Time) int { - return int(t.Sub(time.Time{}) / time.Second) -} diff --git a/pkg/og/testing/tmpdir.go b/pkg/og/testing/tmpdir.go deleted file mode 100644 index a767732624..0000000000 --- a/pkg/og/testing/tmpdir.go +++ /dev/null @@ -1,57 +0,0 @@ -package testing - -import ( - "os" - "path/filepath" - - "github.com/onsi/ginkgo/v2" - "github.com/grafana/pyroscope/pkg/og/util/bytesize" -) - -func DirStats(path string) (directories, files int, size bytesize.ByteSize) { - err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - directories++ - } else { - files++ - size += bytesize.ByteSize(info.Size()) - } - return nil - }) - if err != nil { - return -1, -1, -1 - } - - return directories, files, size -} - -func TmpDir(cb func(name string)) { - defer ginkgo.GinkgoRecover() - path, err := os.MkdirTemp("", "pyroscope-test-dir") - if err != nil { - panic(err) - } - defer os.RemoveAll(path) - - cb(path) -} - -type TmpDirectory struct { - Path string -} - -func (t *TmpDirectory) Close() { - os.RemoveAll(t.Path) -} - -func TmpDirSync() *TmpDirectory { - defer ginkgo.GinkgoRecover() - path, err := os.MkdirTemp("", "pyroscope-test-dir") - if err != nil { - panic(err) - } - return &TmpDirectory{Path: path} -} diff --git a/pkg/og/util/arenahelper/arenas_disabled.go b/pkg/og/util/arenahelper/arenas_disabled.go deleted file mode 100644 index 3d076833fe..0000000000 --- a/pkg/og/util/arenahelper/arenas_disabled.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build !goexperiment.arenas - -// Package arenahelper ... -package arenahelper - -type ArenaWrapper struct { -} - -func NewArenaWrapper() ArenaWrapper { - return ArenaWrapper{} -} -func Free(_ ArenaWrapper) { - -} -func MakeSlice[T any](_ ArenaWrapper, l, c int) []T { - return make([]T, l, c) -} -func AppendA[T any](data []T, v T, _ ArenaWrapper) []T { - return append(data, v) -} diff --git a/pkg/og/util/arenahelper/arenas_enabled.go b/pkg/og/util/arenahelper/arenas_enabled.go deleted file mode 100644 index 0a2a5b58c1..0000000000 --- a/pkg/og/util/arenahelper/arenas_enabled.go +++ /dev/null @@ -1,44 +0,0 @@ -//go:build goexperiment.arenas - -package arenahelper - -import "arena" - -type ArenaWrapper *arena.Arena - -func NewArenaWrapper() ArenaWrapper { - return arena.NewArena() -} - -func Free(a ArenaWrapper) { - if a == nil { - return - } - (*arena.Arena)(a).Free() -} - -func MakeSlice[T any](a ArenaWrapper, l, c int) []T { - if a == nil { - return make([]T, l, c) - } - return arena.MakeSlice[T](a, l, c) -} - -func AppendA[T any](data []T, v T, a ArenaWrapper) []T { - if a == nil { - return append(data, v) - } - if len(data) >= cap(data) { - c := 2 * len(data) - if c == 0 { - c = 1 - } - newData := arena.MakeSlice[T](a, len(data)+1, c) - copy(newData, data) - data = newData - data[len(data)-1] = v - } else { - data = append(data, v) - } - return data -} diff --git a/pkg/og/util/attime/attime.go b/pkg/og/util/attime/attime.go index cd20d34663..c3c7ccacdf 100644 --- a/pkg/og/util/attime/attime.go +++ b/pkg/og/util/attime/attime.go @@ -11,6 +11,8 @@ import ( var digitsOnly = regexp.MustCompile("^\\d+$") +var timeNow = time.Now + func Parse(s string) time.Time { s = strings.TrimSpace(s) // s = strings.ToLower(s) @@ -54,9 +56,8 @@ func Parse(s string) time.Time { } func parseTimeReference(_ string) time.Time { - now := time.Now() // TODO: implement - return now + return timeNow() } func parseTimeOffset(offset string) (d time.Duration) { diff --git a/pkg/og/util/attime/attime_suite_test.go b/pkg/og/util/attime/attime_suite_test.go deleted file mode 100644 index 960c499949..0000000000 --- a/pkg/og/util/attime/attime_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package attime_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestAttime(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Attime Suite") -} diff --git a/pkg/og/util/attime/attime_test.go b/pkg/og/util/attime/attime_test.go index fe032a3e2d..c471d7616d 100644 --- a/pkg/og/util/attime/attime_test.go +++ b/pkg/og/util/attime/attime_test.go @@ -1,33 +1,33 @@ package attime import ( + "testing" "time" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/require" ) -var _ = Describe("attime", func() { - Describe("Parse", func() { - Context("simple cases", func() { - It("works correctly", func() { - Expect(Parse("now")).To(BeTemporally("~", time.Now())) - Expect(Parse("now-1s")).To(BeTemporally("~", time.Now().Add(-1*time.Second))) - Expect(Parse("now+1s")).To(BeTemporally("~", time.Now().Add(1*time.Second))) - Expect(Parse("now-1min")).To(BeTemporally("~", time.Now().Add(-1*time.Minute))) - Expect(Parse("now-1h")).To(BeTemporally("~", time.Now().Add(-1*time.Hour))) - Expect(Parse("now-1d")).To(BeTemporally("~", time.Now().Add(-1*time.Hour*24))) - Expect(Parse("now-1w")).To(BeTemporally("~", time.Now().Add(-1*time.Hour*24*7))) - Expect(Parse("now-1mon")).To(BeTemporally("~", time.Now().Add(-1*time.Hour*24*30))) - Expect(Parse("now-1M")).To(BeTemporally("~", time.Now().Add(-1*time.Hour*24*30))) - Expect(Parse("now-1y")).To(BeTemporally("~", time.Now().Add(-1*time.Hour*24*365))) - Expect(Parse("now-1")).To(BeTemporally("~", time.Now())) - Expect(Parse("20200101")).To(BeTemporally("~", time.Unix(1577836800, 0))) - Expect(Parse("1577836800")).To(BeTemporally("~", time.Unix(1577836800, 0))) - Expect(Parse("1577836800001")).To(BeTemporally("~", time.Unix(1577836800, 1000000))) - Expect(Parse("1577836800000001")).To(BeTemporally("~", time.Unix(1577836800, 1000))) - Expect(Parse("1577836800000000001")).To(BeTemporally("~", time.Unix(1577836800, 1))) - }) - }) +func TestParse(t *testing.T) { + t.Run("simple cases", func(t *testing.T) { + now := time.Unix(1577836800, 0) + timeNow = func() time.Time { return now } + t.Cleanup(func() { timeNow = time.Now }) + + require.Equal(t, now, Parse("now")) + require.Equal(t, now.Add(-1*time.Second), Parse("now-1s")) + require.Equal(t, now.Add(1*time.Second), Parse("now+1s")) + require.Equal(t, now.Add(-1*time.Minute), Parse("now-1min")) + require.Equal(t, now.Add(-1*time.Hour), Parse("now-1h")) + require.Equal(t, now.Add(-1*time.Hour*24), Parse("now-1d")) + require.Equal(t, now.Add(-1*time.Hour*24*7), Parse("now-1w")) + require.Equal(t, now.Add(-1*time.Hour*24*30), Parse("now-1mon")) + require.Equal(t, now.Add(-1*time.Hour*24*30), Parse("now-1M")) + require.Equal(t, now.Add(-1*time.Hour*24*365), Parse("now-1y")) + require.Equal(t, now, Parse("now-1")) + require.Equal(t, time.Unix(1577836800, 0).UTC(), Parse("20200101")) + require.Equal(t, time.Unix(1577836800, 0), Parse("1577836800")) + require.Equal(t, time.Unix(1577836800, 1000000), Parse("1577836800001")) + require.Equal(t, time.Unix(1577836800, 1000), Parse("1577836800000001")) + require.Equal(t, time.Unix(1577836800, 1), Parse("1577836800000000001")) }) -}) +} diff --git a/pkg/og/util/bytesize/bytesize_suite_test.go b/pkg/og/util/bytesize/bytesize_suite_test.go deleted file mode 100644 index c7ec9ad76e..0000000000 --- a/pkg/og/util/bytesize/bytesize_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package bytesize_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestBytesize(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Bytesize Suite") -} diff --git a/pkg/og/util/bytesize/bytesize_test.go b/pkg/og/util/bytesize/bytesize_test.go index 88fe84d892..ecae59961e 100644 --- a/pkg/og/util/bytesize/bytesize_test.go +++ b/pkg/og/util/bytesize/bytesize_test.go @@ -1,30 +1,57 @@ package bytesize import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -var _ = Describe("bytesize package", func() { - Describe("Parse", func() { - It("works with valid values", func() { - Expect(Parse("1TB")).To(Equal(1 * TB)) - Expect(Parse("1 TB")).To(Equal(1 * TB)) - Expect(Parse(" 1 TB ")).To(Equal(1 * TB)) - Expect(Parse(" 1 TB ")).To(Equal(1 * TB)) - - Expect(Parse("1.0TB")).To(BeNumerically("~", 1*TB, GB)) - Expect(Parse("1.9TB")).To(BeNumerically("~", 1*TB+921*GB, GB)) - - Expect(Parse("1")).To(Equal(1 * Byte)) - Expect(Parse(" 1 ")).To(Equal(1 * Byte)) - - Expect(Parse("1mb")).To(Equal(1 * MB)) - Expect(Parse("1mB")).To(Equal(1 * MB)) - }) - It("returns error with invalid values", func() { - _, err := Parse("1UB") - Expect(err).To(MatchError("could not parse ByteSize")) - }) +func TestParse(t *testing.T) { + t.Run("works with valid values", func(t *testing.T) { + v, err := Parse("1TB") + require.NoError(t, err) + require.Equal(t, 1*TB, v) + + v, err = Parse("1 TB") + require.NoError(t, err) + require.Equal(t, 1*TB, v) + + v, err = Parse(" 1 TB ") + require.NoError(t, err) + require.Equal(t, 1*TB, v) + + v, err = Parse(" 1 TB ") + require.NoError(t, err) + require.Equal(t, 1*TB, v) + + v, err = Parse("1.0TB") + require.NoError(t, err) + assert.InDelta(t, float64(1*TB), float64(v), float64(GB)) + + v, err = Parse("1.9TB") + require.NoError(t, err) + assert.InDelta(t, float64(1*TB+921*GB), float64(v), float64(GB)) + + v, err = Parse("1") + require.NoError(t, err) + require.Equal(t, 1*Byte, v) + + v, err = Parse(" 1 ") + require.NoError(t, err) + require.Equal(t, 1*Byte, v) + + v, err = Parse("1mb") + require.NoError(t, err) + require.Equal(t, 1*MB, v) + + v, err = Parse("1mB") + require.NoError(t, err) + require.Equal(t, 1*MB, v) + }) + + t.Run("returns error with invalid values", func(t *testing.T) { + _, err := Parse("1UB") + require.EqualError(t, err, "could not parse ByteSize") }) -}) +} diff --git a/pkg/og/util/serialization/metadata.go b/pkg/og/util/serialization/metadata.go index ccbd64f26a..659db7537e 100644 --- a/pkg/og/util/serialization/metadata.go +++ b/pkg/og/util/serialization/metadata.go @@ -5,7 +5,7 @@ import ( "encoding/json" "io" - "github.com/grafana/pyroscope/pkg/og/util/varint" + "github.com/grafana/pyroscope/v2/pkg/og/util/varint" ) func WriteMetadata(w io.Writer, metadata map[string]interface{}) error { diff --git a/pkg/og/util/serialization/metadata_test.go b/pkg/og/util/serialization/metadata_test.go index 5aa71c8599..0227228f43 100644 --- a/pkg/og/util/serialization/metadata_test.go +++ b/pkg/og/util/serialization/metadata_test.go @@ -3,33 +3,29 @@ package serialization import ( "bufio" "bytes" + "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/require" ) -var _ = Describe("metadata", func() { +func TestMetadata(t *testing.T) { in := map[string]interface{}{ "foo": 1.0, "bar": "baz", } out := "\x15{\"bar\":\"baz\",\"foo\":1}" - Describe("WriteMetadata", func() { - It("serializes metadata", func() { - b := &bytes.Buffer{} - WriteMetadata(b, in) - Expect(b.String()).To(Equal(out)) - }) + t.Run("WriteMetadata serializes metadata", func(t *testing.T) { + b := &bytes.Buffer{} + WriteMetadata(b, in) + require.Equal(t, out, b.String()) }) - Describe("ReadMetadata", func() { - It("deserializes metadata", func() { - b := bufio.NewReader(bytes.NewReader([]byte(out))) - res, err := ReadMetadata(b) - Expect(err).ToNot(HaveOccurred()) - Expect(res["foo"]).To(Equal(in["foo"])) - Expect(res["bar"]).To(Equal(in["bar"])) - }) + t.Run("ReadMetadata deserializes metadata", func(t *testing.T) { + b := bufio.NewReader(bytes.NewReader([]byte(out))) + res, err := ReadMetadata(b) + require.NoError(t, err) + require.Equal(t, in["foo"], res["foo"]) + require.Equal(t, in["bar"], res["bar"]) }) -}) +} diff --git a/pkg/og/util/serialization/serialization_suite_test.go b/pkg/og/util/serialization/serialization_suite_test.go deleted file mode 100644 index b933e64613..0000000000 --- a/pkg/og/util/serialization/serialization_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package serialization_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestSerialization(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Serialization Suite") -} diff --git a/pkg/og/util/varint/varint.go b/pkg/og/util/varint/varint.go index f7cfc4db43..7fbc6d0ecc 100644 --- a/pkg/og/util/varint/varint.go +++ b/pkg/og/util/varint/varint.go @@ -25,3 +25,224 @@ func Write(w io.Writer, val uint64) (int, error) { func Read(r io.ByteReader) (uint64, error) { return binary.ReadUvarint(r) } + +// Uvarint decodes a uint64 from buf and returns that value and the +// number of bytes read (> 0). If an error occurred, the value is 0 +// and the number of bytes n is <= 0 meaning: +// +// n == 0: buf too small +// n < 0: value larger than 64 bits (overflow) +// and -n is the number of bytes read +// +// Copied from https://github.com/dennwc/varint +func Uvarint(buf []byte) (uint64, int) { + // Fully unrolled implementation of binary.Uvarint. + // + // It will also eliminate bound checks for buffers larger than 9 bytes. + sz := len(buf) + if sz == 0 { + return 0, 0 + } + const ( + step = 7 + bit = 1 << 7 + mask = bit - 1 + ) + if sz >= 10 { // no bound checks + // i == 0 + b := buf[0] + if b < bit { + return uint64(b), 1 + } + x := uint64(b & mask) + var s uint = step + + // i == 1 + b = buf[1] + if b < bit { + return x | uint64(b)< 1 { + return 0, -10 // overflow + } + return x | uint64(b)< 1 { + return 0, -10 // overflow + } + return x | uint64(b)< - + @@ -7,10 +7,10 @@ Bucket Blocks Explorer: Tenant {{ .User }}, Block {{ .Block.ID }} - + - +
diff --git a/pkg/operations/tool.blocks.index.gohtml b/pkg/operations/tool.blocks.index.gohtml index 0291a236c2..7060a12a0d 100644 --- a/pkg/operations/tool.blocks.index.gohtml +++ b/pkg/operations/tool.blocks.index.gohtml @@ -1,5 +1,5 @@ - + @@ -7,10 +7,10 @@ Bucket Blocks Explorer: Grafana Pyroscope - + - +
diff --git a/pkg/operations/tool.blocks.list.gohtml b/pkg/operations/tool.blocks.list.gohtml index 08c5b95e4a..b0022b0073 100644 --- a/pkg/operations/tool.blocks.list.gohtml +++ b/pkg/operations/tool.blocks.list.gohtml @@ -1,5 +1,5 @@ - + @@ -7,10 +7,10 @@ Bucket Blocks Tool - {{ .User }} - + - + + + +
+
+
+
+

Bucket Blocks Explorer (v2): TSDB Index

+
+
+ + Pyroscope logo + +
+
+
+

+ Back to dataset +

+ +
+
+
Dataset Information
+
+
+
    +
  • Dataset Name: {{ if .Dataset.Name }}{{ .Dataset.Name }}{{ else }}(empty){{ end }}
  • +
  • Dataset Tenant: {{ .Dataset.Tenant }}
  • +
  • Block ID: {{ .BlockID }}
  • +
  • Shard: {{ .Shard }}
  • +
+
+
+ + {{ if .TSDBIndex }} +
+
+
Index Summary
+
+
+
+
+

Time Range:

+
    +
  • From: {{ .TSDBIndex.From }}
  • +
  • Through: {{ .TSDBIndex.Through }}
  • +
+
+
+

Statistics:

+
    +
  • Number of Series: {{ len .TSDBIndex.Series }}
  • +
  • Number of Labels: {{ len .TSDBIndex.LabelValueSets }}
  • +
  • Number of Symbols: {{ len .TSDBIndex.Symbols }}
  • +
  • Checksum: {{ printf "%08x" .TSDBIndex.Checksum }}
  • +
+
+
+
+
+ +
+
+
Series
+
+
+ {{ if .TSDBIndex.Series }} +
+ + + + + + + + + + {{ range .TSDBIndex.Series }} + + + + + + {{ end }} + +
Series IndexSeries RefLabels
{{ .SeriesIndex }}{{ .SeriesRef }} + {{ if .Labels }} + {{ range $i, $label := .Labels }} + {{ if $i }}, {{ end }}{{ $label.Key }}={{ $label.Value }} + {{ end }} + {{ else }} + - + {{ end }} +
+
+ {{ else }} + + {{ end }} +
+
+ +
+
+
Labels
+
+
+ {{ if .TSDBIndex.LabelValueSets }} + {{ range .TSDBIndex.LabelValueSets }} +
+
+ {{ .LabelName }} + {{ len .LabelValues }} values +
+
+ {{ range .LabelValues }} +
{{ . }}
+ {{ end }} +
+
+ {{ end }} + {{ else }} + + {{ end }} +
+
+ +
+
+
Symbol Table
+
+
+ {{ if .TSDBIndex.Symbols }} +
+ {{ range .TSDBIndex.Symbols }} +
{{ . }}
+ {{ end }} +
+ {{ else }} + + {{ end }} +
+
+ {{ else }} + + {{ end }} +
+
+
+
+
+ Status @ {{ .Now }} +
+
+ + diff --git a/pkg/operations/v2/blocks/tool.blocks.dataset.profiles.gohtml b/pkg/operations/v2/blocks/tool.blocks.dataset.profiles.gohtml new file mode 100644 index 0000000000..9129ced41c --- /dev/null +++ b/pkg/operations/v2/blocks/tool.blocks.dataset.profiles.gohtml @@ -0,0 +1,120 @@ + + + + + + + + Bucket Blocks Explorer (v2): Dataset Profiles - {{ .Dataset.Name }} + + + + + + + +
+
+
+
+

Bucket Blocks Explorer (v2): Dataset Profiles

+
+
+ + Pyroscope logo + +
+
+
+

+ Back to dataset +

+ +
+
+
Dataset Information
+
+
+
    +
  • Dataset Name: {{ if .Dataset.Name }}{{ .Dataset.Name }}{{ else }}(empty){{ end }}
  • +
  • Dataset Tenant: {{ .Dataset.Tenant }}
  • +
  • Block ID: {{ .BlockID }}
  • +
  • Shard: {{ .Shard }}
  • +
+
+
+ +
+
Profiles
+
+ Total: {{ .TotalCount }} profiles + {{ if gt .TotalCount 0 }} + | Showing {{ add (mul (add .Page -1) .PageSize) 1 }}-{{ if lt (mul .Page .PageSize) .TotalCount }}{{ mul .Page .PageSize }}{{ else }}{{ .TotalCount }}{{ end }} + {{ end }} +
+
+ + {{ if .Profiles }} + {{ if gt .TotalPages 1 }} +
+ {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} +
+ {{ end }} + +
+ + + + + + + + + + + + {{ range .Profiles }} + + + + + + + + {{ end }} + +
TimestampSeries IndexProfile TypeSamplesActions
{{ .Timestamp }}{{ .SeriesIndex }}{{ if .ProfileType }}{{ .ProfileType }}{{ else }}-{{ end }}{{ .SampleCount }} + + Call Tree + + + Download + +
+
+ + {{ if gt .TotalPages 1 }} + {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} + {{ end }} + {{ else }} + + {{ end }} +
+
+
+
+
+ Status @ {{ .Now }} +
+
+ + diff --git a/pkg/operations/v2/blocks/tool.blocks.dataset.symbols.gohtml b/pkg/operations/v2/blocks/tool.blocks.dataset.symbols.gohtml new file mode 100644 index 0000000000..5f1a2f4bd9 --- /dev/null +++ b/pkg/operations/v2/blocks/tool.blocks.dataset.symbols.gohtml @@ -0,0 +1,294 @@ + + + + + + + + Bucket Blocks Explorer (v2): Dataset Symbols + + + + + + + +
+
+
+
+

Bucket Blocks Explorer (v2): Dataset Symbols

+
+
+ + Pyroscope logo + +
+
+
+

+ Back to dataset +

+ +
+
+
Dataset Information
+
+
+
    +
  • Dataset Name: {{ if .Dataset.Name }}{{ .Dataset.Name }}{{ else }}(empty){{ end }}
  • +
  • Dataset Tenant: {{ .Dataset.Tenant }}
  • +
  • Block ID: {{ .BlockID }}
  • +
  • Shard: {{ .Shard }}
  • +
+
+
+ + + +
+ {{ if eq .Tab "strings" }} +
+
+
Strings
+
+ {{ if gt .Symbols.TotalStrings 0 }} + Showing {{ add (mul (add .Page -1) .PageSize) 1 }}-{{ if lt (mul .Page .PageSize) .Symbols.TotalStrings }}{{ mul .Page .PageSize }}{{ else }}{{ .Symbols.TotalStrings }}{{ end }} of {{ .Symbols.TotalStrings }} + {{ end }} +
+
+ + {{ if gt .TotalPages 1 }} +
+ {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=strings" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} +
+ {{ end }} + +
+ + + + + + + + + {{ range .Symbols.Strings }} + + + + + {{ end }} + +
IndexString
{{ .Index }}{{ .Symbol }}
+
+ + {{ if gt .TotalPages 1 }} + {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=strings" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} + {{ end }} +
+ {{ end }} + + {{ if eq .Tab "functions" }} +
+
+
Functions
+
+ {{ if gt .Symbols.TotalFunctions 0 }} + Showing {{ add (mul (add .Page -1) .PageSize) 1 }}-{{ if lt (mul .Page .PageSize) .Symbols.TotalFunctions }}{{ mul .Page .PageSize }}{{ else }}{{ .Symbols.TotalFunctions }}{{ end }} of {{ .Symbols.TotalFunctions }} + {{ end }} +
+
+ + {{ if gt .TotalPages 1 }} +
+ {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=functions" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} +
+ {{ end }} + +
+ + + + + + + + + + + + + {{ range .Symbols.Functions }} + + + + + + + + + {{ end }} + +
IndexIDNameSystem NameFilenameLine
{{ .Index }}{{ .ID }}{{ .Name }}{{ .SystemName }}{{ .Filename }}{{ .StartLine }}
+
+ + {{ if gt .TotalPages 1 }} + {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=functions" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} + {{ end }} +
+ {{ end }} + + {{ if eq .Tab "locations" }} +
+
+
Locations
+
+ {{ if gt .Symbols.TotalLocations 0 }} + Showing {{ add (mul (add .Page -1) .PageSize) 1 }}-{{ if lt (mul .Page .PageSize) .Symbols.TotalLocations }}{{ mul .Page .PageSize }}{{ else }}{{ .Symbols.TotalLocations }}{{ end }} of {{ .Symbols.TotalLocations }} + {{ end }} +
+
+ + {{ if gt .TotalPages 1 }} +
+ {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=locations" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} +
+ {{ end }} + +
+ + + + + + + + + + + + {{ range .Symbols.Locations }} + + + + + + + + {{ end }} + +
IndexIDAddressMappingLines (Function @ Line)
{{ .Index }}{{ .ID }}0x{{ printf "%x" .Address }}{{ .MappingID }} + {{ if .Lines }} + {{ range $i, $line := .Lines }} + {{ if $i }}
{{ end }}{{ $line.FunctionName }}{{ if gt $line.Line 0 }} @ L{{ $line.Line }}{{ end }} + {{ end }} + {{ else }} + none + {{ end }} +
+
+ + {{ if gt .TotalPages 1 }} + {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=locations" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} + {{ end }} +
+ {{ end }} + + {{ if eq .Tab "mappings" }} +
+
+
Mappings
+
+ {{ if gt .Symbols.TotalMappings 0 }} + Showing {{ add (mul (add .Page -1) .PageSize) 1 }}-{{ if lt (mul .Page .PageSize) .Symbols.TotalMappings }}{{ mul .Page .PageSize }}{{ else }}{{ .Symbols.TotalMappings }}{{ end }} of {{ .Symbols.TotalMappings }} + {{ end }} +
+
+ + {{ if gt .TotalPages 1 }} +
+ {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=mappings" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} +
+ {{ end }} + +
+ + + + + + + + + + + + + {{ range .Symbols.Mappings }} + + + + + + + + + {{ end }} + +
IndexIDMemory RangeFile OffsetFilenameBuild ID
{{ .Index }}{{ .ID }}0x{{ printf "%x" .MemoryStart }}-0x{{ printf "%x" .MemoryLimit }}0x{{ printf "%x" .FileOffset }}{{ .Filename }}{{ .BuildID }}
+
+ + {{ if gt .TotalPages 1 }} + {{ $datasetName := "_empty" }} + {{ if .Dataset.Name }}{{ $datasetName = .Dataset.Name }}{{ end }} + {{ template "pagination" dict "BaseURL" (printf "?dataset=%s&shard=%d&block_tenant=%s&tab=mappings" $datasetName .Shard .BlockTenant) "Page" .Page "PageSize" .PageSize "TotalPages" .TotalPages "HasPrevPage" .HasPrevPage "HasNextPage" .HasNextPage }} + {{ end }} +
+ {{ end }} +
+
+
+
+
+
+ Status @ {{ .Now }} +
+
+ + diff --git a/pkg/operations/v2/blocks/tool.blocks.detail.gohtml b/pkg/operations/v2/blocks/tool.blocks.detail.gohtml new file mode 100644 index 0000000000..452584287e --- /dev/null +++ b/pkg/operations/v2/blocks/tool.blocks.detail.gohtml @@ -0,0 +1,107 @@ + + + + + + + + Bucket Blocks Explorer (v2): Tenant {{ .User }}, Block {{ .Block.ID }} + + + + + + + +
+
+
+
+

Bucket Blocks Explorer (v2): Block Details

+
+
+ + Pyroscope logo + +
+
+
+

+ Back to tenant +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tenant{{ .User }}
ID{{ .Block.ID }}
Min Time{{ .Block.MinTime }}
Max Time{{ .Block.MaxTime }}
Duration{{ .Block.FormattedDuration }}
Compaction Level{{ .Block.CompactionLevel }}
Shard{{ .Block.Shard }}
Size{{ .Block.Size }}
+ +

Datasets

+ {{ if .Block.Datasets }} + + + + + + + + + + + + + {{ range $ds := .Block.Datasets }} + + + + + + + + + {{ end }} + +
NameTenantTotal SizeProfiles SizeTSDB Index SizeSymbols Size
+ {{ if $ds.Name }}{{ $ds.Name }}{{ else }}(empty){{ end }} + {{ $ds.Tenant }}{{ $ds.Size }}{{ $ds.ProfilesSize }}{{ $ds.IndexSize }}{{ $ds.SymbolsSize }}
+ {{ else }} +

No datasets

+ {{ end }} +
+
+
+
+
+ Status @ {{ .Now }} +
+
+ + diff --git a/pkg/operations/v2/blocks/tool.blocks.index.gohtml b/pkg/operations/v2/blocks/tool.blocks.index.gohtml new file mode 100644 index 0000000000..6b340c8d81 --- /dev/null +++ b/pkg/operations/v2/blocks/tool.blocks.index.gohtml @@ -0,0 +1,58 @@ + + + + + + + + Bucket Blocks Explorer (v2): Grafana Pyroscope + + + + + + + +
+
+
+
+

Bucket Blocks Explorer (v2): Grafana Pyroscope

+
+
+ + Pyroscope logo + +
+
+
+
Tenants
+
+ + + + + + + + + {{ range $i, $ := .Users }} + + + + {{ end }} + +
Id
+ {{ . }} +
+
+
+
+
+
+
+ Status @ {{ .Now }} +
+
+ + diff --git a/pkg/operations/v2/blocks/tool.blocks.list.gohtml b/pkg/operations/v2/blocks/tool.blocks.list.gohtml new file mode 100644 index 0000000000..ea66afee2f --- /dev/null +++ b/pkg/operations/v2/blocks/tool.blocks.list.gohtml @@ -0,0 +1,161 @@ + + + + + + + + Bucket Blocks Tool (v2) - {{ .User }} + + + + + + + + +
+
+
+
+

Bucket Blocks Explorer (v2): Tenant {{ .User }}

+
+
+ + Pyroscope logo + +
+
+
+
+
+
+ + +
+
+ + +
+
+
+ + + +
+
+
+
+
+
{{ len $.SelectedBlocks.BlockGroups }} block groups found
+ {{ $user := .User }} + {{ if eq .Query.View "table"}} +
+ {{ range $i, $blockGroup := .SelectedBlocks.BlockGroups }} +
+

+ +

+
+
+
+ + + + + + + + + + + + + + {{ range $, $v := $blockGroup.Blocks }} + + + + + + + + + + {{ end }} + +
IDMin TimeMax TimeDurationCompaction LevelShardSize
+ + {{ $v.ID }} + + {{ $v.MinTime }}{{ $v.MaxTime }}{{ $v.FormattedDuration }}{{ $v.CompactionLevel }}{{ $v.Shard }}{{ $v.Size }}
+
+
+
+
+ {{ end }} +
+ {{ else }} +
+ {{ $groupDuration := .SelectedBlocks.GroupDurationMinutes}} + {{ $blockWidth := 20 }} + {{ $blockSpacing := 2 }} + {{ if gt .SelectedBlocks.MaxBlocksPerGroup 32 }} + {{ $blockWidth = 10 }} + {{ $blockSpacing = 1 }} + {{ end }} +
+
+ {{ range $i, $blockGroup := .SelectedBlocks.BlockGroups }} + {{ range $j, $block := $blockGroup.Blocks }} + {{ if lt $j 80 }} + {{ $height := mulf 5 (divf $block.Duration $groupDuration) }} + {{ $heightEm := format "%.1f" $height }} + {{ $top := addf (mulf (float $i) 5.0) (subf 5.0 $height) }} + {{ $topEm := format "%.1f" $top }} + {{ $color := "#d3d3d3" }} + {{ if eq 2 $block.CompactionLevel }} + {{ $color = "#ffa500"}} + {{ else if eq 3 $block.CompactionLevel }} + {{ $color = "#9acd32"}} + {{ else if gt $block.CompactionLevel 3 }} + {{ $color = "#008000"}} + {{ end }} + + + + {{ end}} + {{ end }} + {{ end }} +
+
+ {{ range $i, $blockGroup := .SelectedBlocks.BlockGroups }} +
+ {{ $blockGroup.FormattedMinTime }}: {{ len $blockGroup.Blocks }} blocks +
+ {{ end }} + {{ end }} +
+
+
+ + diff --git a/pkg/operations/v2/blocks/tool.blocks.profile.call.tree.gohtml b/pkg/operations/v2/blocks/tool.blocks.profile.call.tree.gohtml new file mode 100644 index 0000000000..38eb46a179 --- /dev/null +++ b/pkg/operations/v2/blocks/tool.blocks.profile.call.tree.gohtml @@ -0,0 +1,271 @@ + + + + + + + + Bucket Blocks Explorer (v2): Profile Call Tree + + + + + + + + + +
+
+
+
+

Bucket Blocks Explorer (v2): Profile Call Tree

+
+
+ + Pyroscope logo + +
+
+
+

+ Back to profiles +

+ +
+
+
+
+
Dataset Information
+
+
+
    +
  • Dataset Name: {{ if .Dataset.Name }}{{ .Dataset.Name }}{{ else }}(empty){{ end }}
  • +
  • Dataset Tenant: {{ .Dataset.Tenant }}
  • +
  • Block ID: {{ .BlockID }}
  • +
  • Shard: {{ .Shard }}
  • +
+
+
+
+ + {{ if .ProfileInfo }} +
+
+
+
Profile Information
+
+
+
+
+ Profile Type: + + {{ .ProfileInfo.ProfileType }} + +
+
+
+
+ Timestamp: + + {{ .Timestamp }} + +
+
+
+
+ Labels: + + {{ range $index, $label := .ProfileInfo.Labels }}{{ if $index }}, {{ end }}{{ $label.Key }}={{ $label.Value }}{{ end }} + +
+
+
+
+
+ {{ end }} +
+ +
+
+
Call Tree
+ Click [+]/[-] to expand/collapse nodes. +
+
+ {{ if .Tree }} +
+
    + {{ template "tree-node" dict "Node" .Tree "Level" 0 }} +
+
+ {{ else }} + + {{ end }} +
+
+
+
+
+
+
+ Status @ {{ .Now }} +
+
+ + + + + +{{ define "tree-node" }} + {{ $node := .Node }} + {{ $level := .Level }} +
  • + {{ if gt (len $node.Children) 0 }} +
    +
    + {{ if eq $level 0 }}[-]{{ else }}[+]{{ end }} + {{ $node.Name }} +
    +
    {{ $node.FormattedValue }}
    +
    {{ printf "%.2f" $node.Percent }}%
    +
    {{ if $node.Location }}{{ $node.Location }}{{ end }}
    +
    +
      + {{ range $node.Children }} + {{ template "tree-node" dict "Node" . "Level" (add $level 1) }} + {{ end }} +
    + {{ else }} +
    +
    + + {{ $node.Name }} +
    +
    {{ $node.FormattedValue }}
    +
    {{ printf "%.2f" $node.Percent }}%
    +
    {{ if $node.Location }}{{ $node.Location }}{{ end }}
    +
    + {{ end }} +
  • +{{ end }} diff --git a/pkg/operations/v2/blocks/tool.pagination.gohtml b/pkg/operations/v2/blocks/tool.pagination.gohtml new file mode 100644 index 0000000000..736bf271b0 --- /dev/null +++ b/pkg/operations/v2/blocks/tool.pagination.gohtml @@ -0,0 +1,55 @@ +{{/* + Required parameters (pass via dict): + - BaseURL: string - the base URL without query params (e.g., "?dataset=foo&shard=1") + - Page: int - current page number + - PageSize: int - items per page + - TotalPages: int - total number of pages + - HasPrevPage: bool - whether there's a previous page + - HasNextPage: bool - whether there's a next page +*/}} + +{{ define "pagination" }} + {{ $baseURL := .BaseURL }} + {{ $currentPage := .Page }} + {{ $pageSize := .PageSize }} + {{ $totalPages := .TotalPages }} + {{ $hasPrev := .HasPrevPage }} + {{ $hasNext := .HasNextPage }} + + +{{ end }} diff --git a/pkg/operations/v2/querydiagnostics/admin.go b/pkg/operations/v2/querydiagnostics/admin.go new file mode 100644 index 0000000000..6c35ab2e87 --- /dev/null +++ b/pkg/operations/v2/querydiagnostics/admin.go @@ -0,0 +1,270 @@ +package querydiagnostics + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend/diagnostics" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +type DiagnosticsStore interface { + ListByTenant(ctx context.Context, tenant string) ([]*diagnostics.DiagnosticSummary, error) + Get(ctx context.Context, tenant string, id string) (*diagnostics.StoredDiagnostics, error) + Export(ctx context.Context, tenant string, id string) ([]byte, error) + Import(ctx context.Context, tenant string, id string, data []byte) (string, error) +} + +type Admin struct { + logger log.Logger + + tenantService metastorev1.TenantServiceClient + diagnosticsStore DiagnosticsStore +} + +func New( + logger log.Logger, + tenantService metastorev1.TenantServiceClient, + diagnosticsStore DiagnosticsStore, +) *Admin { + adm := &Admin{ + logger: logger, + tenantService: tenantService, + diagnosticsStore: diagnosticsStore, + } + return adm +} + +// TenantsAPIHandler returns a JSON API handler for listing tenants. +func (a *Admin) TenantsAPIHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + var tenants []string + if a.tenantService != nil { + resp, err := a.tenantService.GetTenants(r.Context(), &metastorev1.GetTenantsRequest{}) + if err != nil { + level.Debug(a.logger).Log("msg", "failed to fetch tenants from tenant service", "err", err) + } else { + tenants = resp.TenantIds + } + } + + if tenants == nil { + tenants = []string{} + } + if err := json.NewEncoder(w).Encode(tenants); err != nil { + httputil.Error(w, err) + } + }) +} + +// DiagnosticsListAPIHandler returns a JSON API handler for listing diagnostics by tenant. +func (a *Admin) DiagnosticsListAPIHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + if a.diagnosticsStore == nil { + http.Error(w, `{"error":"diagnostics store not configured"}`, http.StatusServiceUnavailable) + return + } + + tenant := r.URL.Query().Get("tenant") + if tenant == "" { + http.Error(w, `{"error":"tenant parameter required"}`, http.StatusBadRequest) + return + } + + diagnosticsList, err := a.diagnosticsStore.ListByTenant(r.Context(), tenant) + if err != nil { + http.Error(w, fmt.Sprintf(`{"error":"failed to list diagnostics: %s"}`, err), http.StatusInternalServerError) + return + } + + if diagnosticsList == nil { + diagnosticsList = []*diagnostics.DiagnosticSummary{} + } + if err := json.NewEncoder(w).Encode(diagnosticsList); err != nil { + httputil.Error(w, err) + } + }) +} + +// DiagnosticsGetAPIHandler returns a JSON API handler for getting a single diagnostic. +func (a *Admin) DiagnosticsGetAPIHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + if a.diagnosticsStore == nil { + http.Error(w, `{"error":"diagnostics store not configured"}`, http.StatusServiceUnavailable) + return + } + + tenant := r.URL.Query().Get("tenant") + if tenant == "" { + http.Error(w, `{"error":"tenant parameter required"}`, http.StatusBadRequest) + return + } + + // Extract ID from path: /query-diagnostics/api/diagnostics/{id} + path := r.URL.Path + prefix := "/query-diagnostics/api/diagnostics/" + if !strings.HasPrefix(path, prefix) { + http.Error(w, `{"error":"invalid path"}`, http.StatusBadRequest) + return + } + id := strings.TrimPrefix(path, prefix) + if id == "" { + http.Error(w, `{"error":"id parameter required"}`, http.StatusBadRequest) + return + } + + stored, err := a.diagnosticsStore.Get(r.Context(), tenant, id) + if err != nil { + if strings.Contains(err.Error(), "not found") { + http.Error(w, fmt.Sprintf(`{"error":"diagnostic not found: %s"}`, id), http.StatusNotFound) + return + } + http.Error(w, fmt.Sprintf(`{"error":"failed to get diagnostic: %s"}`, err), http.StatusInternalServerError) + return + } + + if err := json.NewEncoder(w).Encode(stored); err != nil { + httputil.Error(w, err) + } + }) +} + +// DiagnosticsExportAPIHandler returns a handler for exporting a diagnostic as a zip file. +func (a *Admin) DiagnosticsExportAPIHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if a.diagnosticsStore == nil { + http.Error(w, `{"error":"diagnostics store not configured"}`, http.StatusServiceUnavailable) + return + } + + tenant := r.URL.Query().Get("tenant") + if tenant == "" { + http.Error(w, `{"error":"tenant parameter required"}`, http.StatusBadRequest) + return + } + + // Extract ID from path: /query-diagnostics/api/export/{id} + path := r.URL.Path + prefix := "/query-diagnostics/api/export/" + if !strings.HasPrefix(path, prefix) { + http.Error(w, `{"error":"invalid path"}`, http.StatusBadRequest) + return + } + id := strings.TrimPrefix(path, prefix) + if id == "" { + http.Error(w, `{"error":"id parameter required"}`, http.StatusBadRequest) + return + } + + zipData, err := a.diagnosticsStore.Export(r.Context(), tenant, id) + if err != nil { + if strings.Contains(err.Error(), "not found") { + http.Error(w, fmt.Sprintf(`{"error":"diagnostic not found: %s"}`, id), http.StatusNotFound) + return + } + http.Error(w, fmt.Sprintf(`{"error":"failed to export diagnostic: %s"}`, err), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/zip") + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"diagnostic-%s-%s.zip\"", tenant, id)) + _, _ = w.Write(zipData) + }) +} + +// DiagnosticsImportAPIHandler returns a handler for importing a diagnostic from a zip file. +func (a *Admin) DiagnosticsImportAPIHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + if a.diagnosticsStore == nil { + http.Error(w, `{"error":"diagnostics store not configured"}`, http.StatusServiceUnavailable) + return + } + + if r.Method != http.MethodPost { + http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) + return + } + + tenant := r.URL.Query().Get("tenant") + if tenant == "" { + http.Error(w, `{"error":"tenant parameter required"}`, http.StatusBadRequest) + return + } + + // Limit upload size to 100MB + r.Body = http.MaxBytesReader(w, r.Body, 100<<20) + + // Parse multipart form + if err := r.ParseMultipartForm(100 << 20); err != nil { + http.Error(w, fmt.Sprintf(`{"error":"failed to parse form: %s"}`, err), http.StatusBadRequest) + return + } + + file, _, err := r.FormFile("file") + if err != nil { + http.Error(w, fmt.Sprintf(`{"error":"failed to get file: %s"}`, err), http.StatusBadRequest) + return + } + defer file.Close() + + zipData, err := io.ReadAll(file) + if err != nil { + http.Error(w, fmt.Sprintf(`{"error":"failed to read file: %s"}`, err), http.StatusInternalServerError) + return + } + + newID, err := a.diagnosticsStore.Import(r.Context(), tenant, "", zipData) + if err != nil { + http.Error(w, fmt.Sprintf(`{"error":"failed to import diagnostic: %s"}`, err), http.StatusInternalServerError) + return + } + + level.Info(a.logger).Log("msg", "imported diagnostic", "id", newID, "tenant", tenant) + + response := map[string]string{"id": newID} + if err := json.NewEncoder(w).Encode(response); err != nil { + httputil.Error(w, err) + } + }) +} + +// DiagnosticsListHandler returns an HTTP handler for the stored diagnostics page shell. +func (a *Admin) DiagnosticsListHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + content := pageContent{ + Now: time.Now().UTC(), + } + if err := pageTemplates.diagnosticsListTemplate.Execute(w, content); err != nil { + httputil.Error(w, err) + } + }) +} + +// DiagnosticsHandler returns an HTTP handler for the query diagnostics page shell. +func (a *Admin) DiagnosticsHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + content := pageContent{ + Now: time.Now().UTC(), + } + if err := pageTemplates.diagnosticsTemplate.Execute(w, content); err != nil { + httputil.Error(w, err) + } + }) +} diff --git a/pkg/operations/v2/querydiagnostics/diagnostics_list.gohtml b/pkg/operations/v2/querydiagnostics/diagnostics_list.gohtml new file mode 100644 index 0000000000..9d46184762 --- /dev/null +++ b/pkg/operations/v2/querydiagnostics/diagnostics_list.gohtml @@ -0,0 +1,25 @@ + + + + + + + + Stored Diagnostics + + + + + + + + +
    + +
    +
    + Status @ {{ .Now.Format "2006-01-02 15:04:05.000" }} +
    +
    + + diff --git a/pkg/operations/v2/querydiagnostics/pages.go b/pkg/operations/v2/querydiagnostics/pages.go new file mode 100644 index 0000000000..d314838c88 --- /dev/null +++ b/pkg/operations/v2/querydiagnostics/pages.go @@ -0,0 +1,37 @@ +package querydiagnostics + +import ( + _ "embed" + "html/template" + "time" +) + +//go:embed query_diagnostics.gohtml +var diagnosticsPageHtml string + +//go:embed diagnostics_list.gohtml +var diagnosticsListPageHtml string + +type pageContent struct { + Now time.Time +} + +type templates struct { + diagnosticsTemplate *template.Template + diagnosticsListTemplate *template.Template +} + +var pageTemplates = initTemplates() + +func initTemplates() *templates { + diagnosticsTemplate := template.New("diagnostics") + template.Must(diagnosticsTemplate.Parse(diagnosticsPageHtml)) + + diagnosticsListTemplate := template.New("diagnostics-list") + template.Must(diagnosticsListTemplate.Parse(diagnosticsListPageHtml)) + + return &templates{ + diagnosticsTemplate: diagnosticsTemplate, + diagnosticsListTemplate: diagnosticsListTemplate, + } +} diff --git a/pkg/operations/v2/querydiagnostics/query_diagnostics.gohtml b/pkg/operations/v2/querydiagnostics/query_diagnostics.gohtml new file mode 100644 index 0000000000..ea6408fd42 --- /dev/null +++ b/pkg/operations/v2/querydiagnostics/query_diagnostics.gohtml @@ -0,0 +1,25 @@ + + + + + + + + Query Diagnostics + + + + + + + + +
    + +
    +
    + Status @ {{ .Now.Format "2006-01-02 15:04:05.000" }} +
    +
    + + diff --git a/pkg/parquet/group.go b/pkg/parquet/group.go index 023ac9d095..655aaa7113 100644 --- a/pkg/parquet/group.go +++ b/pkg/parquet/group.go @@ -24,6 +24,8 @@ func (g Group) String() string { return s.String() } +func (g Group) ID() int { return 0 } + func (g Group) Type() parquet.Type { return &groupType{} } func (g Group) Optional() bool { return false } diff --git a/pkg/parquet/row_reader.go b/pkg/parquet/row_reader.go index 7b51c95cd2..e86e2b9811 100644 --- a/pkg/parquet/row_reader.go +++ b/pkg/parquet/row_reader.go @@ -6,9 +6,9 @@ import ( "github.com/grafana/dskit/runutil" "github.com/parquet-go/parquet-go" - "github.com/grafana/pyroscope/pkg/iter" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/loser" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/loser" ) const ( @@ -77,10 +77,8 @@ func (it *IteratorRowReader) ReadRows(rows []parquet.Row) (int, error) { if len(rows) == 0 { return 0, nil } - for { - if n == len(rows) { - break - } + for n != len(rows) { + if !it.Next() { runutil.CloseWithLogOnErr(util.Logger, it.Iterator, "failed to close iterator") if it.Err() != nil { diff --git a/pkg/phlare/health.go b/pkg/phlare/health.go deleted file mode 100644 index e4af74e0f0..0000000000 --- a/pkg/phlare/health.go +++ /dev/null @@ -1,27 +0,0 @@ -package phlare - -import ( - "context" - - grpchealth "connectrpc.com/grpchealth" - "github.com/gorilla/mux" - "github.com/grafana/dskit/grpcutil" -) - -type checker struct { - checks []grpcutil.Check -} - -func RegisterHealthServer(mux *mux.Router, checks ...grpcutil.Check) { - prefix, handler := grpchealth.NewHandler(&checker{checks: checks}) - mux.NewRoute().PathPrefix(prefix).Handler(handler) -} - -func (c *checker) Check(ctx context.Context, req *grpchealth.CheckRequest) (*grpchealth.CheckResponse, error) { - for _, check := range c.checks { - if !check(ctx) { - return &grpchealth.CheckResponse{Status: grpchealth.StatusNotServing}, nil - } - } - return &grpchealth.CheckResponse{Status: grpchealth.StatusServing}, nil -} diff --git a/pkg/phlare/modules.go b/pkg/phlare/modules.go deleted file mode 100644 index 40ab95850a..0000000000 --- a/pkg/phlare/modules.go +++ /dev/null @@ -1,726 +0,0 @@ -package phlare - -import ( - "context" - "fmt" - "net/http" - "os" - "time" - - "connectrpc.com/connect" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/grafana/dskit/dns" - "github.com/grafana/dskit/kv/codec" - "github.com/grafana/dskit/kv/memberlist" - "github.com/grafana/dskit/middleware" - "github.com/grafana/dskit/ring" - "github.com/grafana/dskit/runtimeconfig" - "github.com/grafana/dskit/server" - "github.com/grafana/dskit/services" - grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/collectors/version" - objstoretracing "github.com/thanos-io/objstore/tracing/opentracing" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" - "google.golang.org/genproto/googleapis/api/httpbody" - "google.golang.org/protobuf/encoding/protojson" - "gopkg.in/yaml.v3" - - statusv1 "github.com/grafana/pyroscope/api/gen/proto/go/status/v1" - "github.com/grafana/pyroscope/pkg/adhocprofiles" - apiversion "github.com/grafana/pyroscope/pkg/api/version" - "github.com/grafana/pyroscope/pkg/compactor" - "github.com/grafana/pyroscope/pkg/distributor" - "github.com/grafana/pyroscope/pkg/frontend" - "github.com/grafana/pyroscope/pkg/ingester" - objstoreclient "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/operations" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/querier" - "github.com/grafana/pyroscope/pkg/querier/worker" - "github.com/grafana/pyroscope/pkg/scheduler" - "github.com/grafana/pyroscope/pkg/settings" - "github.com/grafana/pyroscope/pkg/storegateway" - "github.com/grafana/pyroscope/pkg/usagestats" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/build" - "github.com/grafana/pyroscope/pkg/validation" - "github.com/grafana/pyroscope/pkg/validation/exporter" -) - -// The various modules that make up Pyroscope. -const ( - All string = "all" - API string = "api" - Version string = "version" - Distributor string = "distributor" - Server string = "server" - Ring string = "ring" - Ingester string = "ingester" - MemberlistKV string = "memberlist-kv" - Querier string = "querier" - StoreGateway string = "store-gateway" - GRPCGateway string = "grpc-gateway" - Storage string = "storage" - UsageReport string = "usage-stats" - QueryFrontend string = "query-frontend" - QueryScheduler string = "query-scheduler" - RuntimeConfig string = "runtime-config" - Overrides string = "overrides" - OverridesExporter string = "overrides-exporter" - Compactor string = "compactor" - Admin string = "admin" - TenantSettings string = "tenant-settings" - AdHocProfiles string = "ad-hoc-profiles" - - // QueryFrontendTripperware string = "query-frontend-tripperware" - // IndexGateway string = "index-gateway" - // IndexGatewayRing string = "index-gateway-ring" -) - -var objectStoreTypeStats = usagestats.NewString("store_object_type") - -func (f *Phlare) initQueryFrontend() (services.Service, error) { - if f.Cfg.Frontend.Addr == "" { - addr, err := util.GetFirstAddressOf(f.Cfg.Frontend.InfNames) - if err != nil { - return nil, errors.Wrap(err, "failed to get frontend address") - } - - f.Cfg.Frontend.Addr = addr - } - - if f.Cfg.Frontend.Port == 0 { - f.Cfg.Frontend.Port = f.Cfg.Server.HTTPListenPort - } - - frontendSvc, err := frontend.NewFrontend(f.Cfg.Frontend, f.Overrides, log.With(f.logger, "component", "frontend"), f.reg) - if err != nil { - return nil, err - } - - f.API.RegisterPyroscopeHandlers(frontendSvc) - f.API.RegisterQueryFrontend(frontendSvc) - f.API.RegisterQuerier(frontendSvc) - - return frontendSvc, nil -} - -func (f *Phlare) initRuntimeConfig() (services.Service, error) { - if len(f.Cfg.RuntimeConfig.LoadPath) == 0 { - // no need to initialize module if load path is empty - return nil, nil - } - - f.Cfg.RuntimeConfig.Loader = loadRuntimeConfig - - // make sure to set default limits before we start loading configuration into memory - validation.SetDefaultLimitsForYAMLUnmarshalling(f.Cfg.LimitsConfig) - - serv, err := runtimeconfig.New(f.Cfg.RuntimeConfig, "pyroscope", prometheus.WrapRegistererWithPrefix("pyroscope_", f.reg), log.With(f.logger, "component", "runtime-config")) - if err == nil { - // TenantLimits just delegates to RuntimeConfig and doesn't have any state or need to do - // anything in the start/stopping phase. Thus we can create it as part of runtime config - // setup without any service instance of its own. - f.TenantLimits = newTenantLimits(serv) - } - - f.RuntimeConfig = serv - f.API.RegisterRuntimeConfig(runtimeConfigHandler(f.RuntimeConfig, f.Cfg.LimitsConfig), validation.TenantLimitsHandler(f.Cfg.LimitsConfig, f.TenantLimits)) - - return serv, err -} - -func (f *Phlare) initTenantSettings() (services.Service, error) { - var store settings.Store - var err error - - switch { - case f.storageBucket != nil: - store, err = settings.NewBucketStore(f.storageBucket) - default: - store, err = settings.NewMemoryStore() - level.Warn(f.logger).Log("msg", "using in-memory settings store, changes will be lost after shutdown") - } - if err != nil { - return nil, errors.Wrap(err, "failed to init settings store") - } - - settings, err := settings.New(store, log.With(f.logger, "component", TenantSettings)) - if err != nil { - return nil, errors.Wrap(err, "failed to init settings service") - } - - f.API.RegisterTenantSettings(settings) - return settings, nil -} - -func (f *Phlare) initAdHocProfiles() (services.Service, error) { - if f.storageBucket == nil { - level.Warn(f.logger).Log("msg", "no storage bucket configured, ad hoc profiles will not be loaded") - return nil, nil - } - - a := adhocprofiles.NewAdHocProfiles(f.storageBucket, f.logger, f.Overrides) - f.API.RegisterAdHocProfiles(a) - return a, nil -} - -func (f *Phlare) initOverrides() (serv services.Service, err error) { - f.Overrides, err = validation.NewOverrides(f.Cfg.LimitsConfig, f.TenantLimits) - // overrides don't have operational state, nor do they need to do anything more in starting/stopping phase, - // so there is no need to return any service. - return nil, err -} - -func (f *Phlare) initOverridesExporter() (services.Service, error) { - overridesExporter, err := exporter.NewOverridesExporter( - f.Cfg.OverridesExporter, - &f.Cfg.LimitsConfig, - f.TenantLimits, - log.With(f.logger, "component", "overrides-exporter"), - f.reg, - ) - if err != nil { - return nil, errors.Wrap(err, "failed to instantiate overrides-exporter") - } - if f.reg != nil { - f.reg.MustRegister(overridesExporter) - } - - f.API.RegisterOverridesExporter(overridesExporter) - - return overridesExporter, nil -} - -func (f *Phlare) initQueryScheduler() (services.Service, error) { - f.Cfg.QueryScheduler.ServiceDiscovery.SchedulerRing.ListenPort = f.Cfg.Server.HTTPListenPort - - s, err := scheduler.NewScheduler(f.Cfg.QueryScheduler, f.Overrides, log.With(f.logger, "component", "scheduler"), f.reg) - if err != nil { - return nil, errors.Wrap(err, "query-scheduler init") - } - - f.API.RegisterQueryScheduler(s) - - return s, nil -} - -func (f *Phlare) initCompactor() (serv services.Service, err error) { - f.Cfg.Compactor.ShardingRing.Common.ListenPort = f.Cfg.Server.HTTPListenPort - - if f.storageBucket == nil { - return nil, nil - } - - f.Compactor, err = compactor.NewMultitenantCompactor(f.Cfg.Compactor, f.storageBucket, f.Overrides, log.With(f.logger, "component", "compactor"), f.reg) - if err != nil { - return - } - - // Expose HTTP endpoints. - f.API.RegisterCompactor(f.Compactor) - return f.Compactor, nil -} - -// setupWorkerTimeout sets the max loop duration for the querier worker and frontend worker -// to 90% of the read or write http timeout, whichever is smaller. -// This is to ensure that the worker doesn't timeout before the http handler and that the connection -// is refreshed. -func (f *Phlare) setupWorkerTimeout() { - timeout := f.Cfg.Server.HTTPServerReadTimeout - if f.Cfg.Server.HTTPServerWriteTimeout < timeout { - timeout = f.Cfg.Server.HTTPServerWriteTimeout - } - - if timeout > 0 { - f.Cfg.Worker.MaxLoopDuration = time.Duration(float64(timeout) * 0.9) - f.Cfg.Frontend.MaxLoopDuration = time.Duration(float64(timeout) * 0.9) - } -} - -func (f *Phlare) initQuerier() (services.Service, error) { - newQuerierParams := &querier.NewQuerierParams{ - Cfg: f.Cfg.Querier, - StoreGatewayCfg: f.Cfg.StoreGateway, - Overrides: f.Overrides, - CfgProvider: f.Overrides, - StorageBucket: f.storageBucket, - IngestersRing: f.ring, - Reg: f.reg, - Logger: log.With(f.logger, "component", "querier"), - ClientOptions: []connect.ClientOption{f.auth}, - } - querierSvc, err := querier.New(newQuerierParams) - if err != nil { - return nil, err - } - - if !f.isModuleActive(QueryFrontend) { - f.API.RegisterPyroscopeHandlers(querierSvc) - f.API.RegisterQuerier(querierSvc) - } - qWorker, err := worker.NewQuerierWorker(f.Cfg.Worker, querier.NewGRPCHandler(querierSvc), log.With(f.logger, "component", "querier-worker"), f.reg) - if err != nil { - return nil, err - } - - sm, err := services.NewManager(querierSvc, qWorker) - if err != nil { - return nil, err - } - w := services.NewFailureWatcher() - w.WatchManager(sm) - - return services.NewBasicService(func(ctx context.Context) error { - err := sm.StartAsync(ctx) - if err != nil { - return err - } - return sm.AwaitHealthy(ctx) - }, func(ctx context.Context) error { - select { - case <-ctx.Done(): - return nil - case err := <-w.Chan(): - return err - } - }, func(failureCase error) error { - sm.StopAsync() - return sm.AwaitStopped(context.Background()) - }), nil -} - -func (f *Phlare) initGRPCGateway() (services.Service, error) { - f.grpcGatewayMux = grpcgw.NewServeMux( - grpcgw.WithMarshalerOption("application/json+pretty", &grpcgw.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - Indent: " ", - Multiline: true, // Optional, implied by presence of "Indent". - }, - UnmarshalOptions: protojson.UnmarshalOptions{ - DiscardUnknown: true, - }, - }), - ) - return nil, nil -} - -func (f *Phlare) initDistributor() (services.Service, error) { - f.Cfg.Distributor.DistributorRing.ListenPort = f.Cfg.Server.HTTPListenPort - d, err := distributor.New(f.Cfg.Distributor, f.ring, nil, f.Overrides, f.reg, log.With(f.logger, "component", "distributor"), f.auth) - if err != nil { - return nil, err - } - - f.API.RegisterDistributor(d) - return d, nil -} - -func (f *Phlare) initMemberlistKV() (services.Service, error) { - f.Cfg.MemberlistKV.Codecs = []codec.Codec{ - ring.GetCodec(), - usagestats.JSONCodec, - apiversion.GetCodec(), - } - - dnsProviderReg := prometheus.WrapRegistererWithPrefix( - "pyroscope_", - prometheus.WrapRegistererWith( - prometheus.Labels{"name": "memberlist"}, - f.reg, - ), - ) - dnsProvider := dns.NewProvider(f.logger, dnsProviderReg, dns.GolangResolverType) - - f.MemberlistKV = memberlist.NewKVInitService(&f.Cfg.MemberlistKV, f.logger, dnsProvider, f.reg) - - f.Cfg.Distributor.DistributorRing.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV - f.Cfg.Ingester.LifecyclerConfig.RingConfig.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV - f.Cfg.QueryScheduler.ServiceDiscovery.SchedulerRing.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV - f.Cfg.OverridesExporter.Ring.Ring.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV - f.Cfg.StoreGateway.ShardingRing.Ring.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV - f.Cfg.Compactor.ShardingRing.Common.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV - f.Cfg.Frontend.QuerySchedulerDiscovery = f.Cfg.QueryScheduler.ServiceDiscovery - f.Cfg.Worker.QuerySchedulerDiscovery = f.Cfg.QueryScheduler.ServiceDiscovery - - f.API.RegisterMemberlistKV("", f.MemberlistKV) - - return f.MemberlistKV, nil -} - -func (f *Phlare) initRing() (_ services.Service, err error) { - f.ring, err = ring.New(f.Cfg.Ingester.LifecyclerConfig.RingConfig, "ingester", "ring", log.With(f.logger, "component", "ring"), prometheus.WrapRegistererWithPrefix("pyroscope_", f.reg)) - if err != nil { - return nil, err - } - - f.API.RegisterRing(f.ring) - - return f.ring, nil -} - -func (f *Phlare) initStorage() (_ services.Service, err error) { - objectStoreTypeStats.Set(f.Cfg.Storage.Bucket.Backend) - if cfg := f.Cfg.Storage.Bucket; cfg.Backend != objstoreclient.None { - if cfg.Backend == objstoreclient.Filesystem { - level.Warn(f.logger).Log("msg", "when running with storage.backend 'filesystem' it is important that all replicas/components share the same filesystem") - } - b, err := objstoreclient.NewBucket( - f.context(), - cfg, - "storage", - ) - if err != nil { - return nil, errors.Wrap(err, "unable to initialise bucket") - } - f.storageBucket = b - } - - if f.Cfg.Target.String() != All && f.storageBucket == nil { - return nil, errors.New("storage bucket configuration is required when running in microservices mode") - } - - return nil, nil -} - -// TODO: This should be passed to all other services and could also be used to signal shutdown -func (f *Phlare) context() context.Context { - phlarectx := phlarecontext.WithLogger(context.Background(), f.logger) - return phlarecontext.WithRegistry(phlarectx, f.reg) -} - -func (f *Phlare) initIngester() (_ services.Service, err error) { - f.Cfg.Ingester.LifecyclerConfig.ListenPort = f.Cfg.Server.HTTPListenPort - - svc, err := ingester.New(f.context(), f.Cfg.Ingester, f.Cfg.PhlareDB, f.storageBucket, f.Overrides, f.Cfg.Querier.QueryStoreAfter) - if err != nil { - return nil, err - } - - f.API.RegisterIngester(svc) - - return svc, nil -} - -func (f *Phlare) initStoreGateway() (serv services.Service, err error) { - f.Cfg.StoreGateway.ShardingRing.Ring.ListenPort = f.Cfg.Server.HTTPListenPort - if f.storageBucket == nil { - return nil, nil - } - - svc, err := storegateway.NewStoreGateway(f.Cfg.StoreGateway, f.storageBucket, f.Overrides, f.logger, f.reg) - if err != nil { - return nil, err - } - f.API.RegisterStoreGateway(svc) - return svc, nil -} - -var objstoreTracerMiddleware = middleware.Func(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - if tracer := opentracing.GlobalTracer(); tracer != nil { - ctx = objstoretracing.ContextWithTracer(ctx, opentracing.GlobalTracer()) - } - next.ServeHTTP(w, r.WithContext(ctx)) - }) -}) - -func (f *Phlare) initServer() (services.Service, error) { - f.reg.MustRegister(version.NewCollector("pyroscope")) - f.reg.Unregister(collectors.NewGoCollector()) - // register collector with additional metrics - f.reg.MustRegister(collectors.NewGoCollector( - collectors.WithGoCollectorRuntimeMetrics(collectors.MetricsAll), - )) - DisableSignalHandling(&f.Cfg.Server) - f.Cfg.Server.Registerer = prometheus.WrapRegistererWithPrefix("pyroscope_", f.reg) - // Not all default middleware works with http2 so we'll add then manually. - // see https://github.com/grafana/pyroscope/issues/231 - f.Cfg.Server.DoNotAddDefaultHTTPMiddleware = true - - f.setupWorkerTimeout() - if f.isModuleActive(QueryScheduler) { - // to ensure that the query scheduler is always able to handle the request, we need to double the timeout - f.Cfg.Server.HTTPServerReadTimeout = 2 * f.Cfg.Server.HTTPServerReadTimeout - f.Cfg.Server.HTTPServerWriteTimeout = 2 * f.Cfg.Server.HTTPServerWriteTimeout - } - serv, err := server.New(f.Cfg.Server) - if err != nil { - return nil, err - } - - f.Server = serv - - servicesToWaitFor := func() []services.Service { - svs := []services.Service(nil) - for m, s := range f.serviceMap { - // Server should not wait for itself. - if m != Server { - svs = append(svs, s) - } - } - return svs - } - - httpMetric, err := util.NewHTTPMetricMiddleware(f.Server.HTTP, f.Cfg.Server.MetricsNamespace, f.Cfg.Server.Registerer) - if err != nil { - return nil, err - } - defaultHTTPMiddleware := []middleware.Interface{ - middleware.Tracer{ - RouteMatcher: f.Server.HTTP, - }, - util.Log{ - Log: f.Server.Log, - LogRequestAtInfoLevel: f.Cfg.Server.LogRequestAtInfoLevel, - }, - httpMetric, - objstoreTracerMiddleware, - } - f.Server.HTTPServer.Handler = middleware.Merge(defaultHTTPMiddleware...).Wrap(f.Server.HTTP) - - s := NewServerService(f.Server, servicesToWaitFor, f.logger) - // todo configure http2 - f.Server.HTTPServer.Handler = h2c.NewHandler(f.Server.HTTPServer.Handler, &http2.Server{}) - f.Server.HTTPServer.Handler = util.RecoveryHTTPMiddleware.Wrap(f.Server.HTTPServer.Handler) - - return s, nil -} - -func (f *Phlare) initUsageReport() (services.Service, error) { - if !f.Cfg.Analytics.Enabled { - return nil, nil - } - f.Cfg.Analytics.Leader = false - // ingester is the only component that can be a leader - if f.isModuleActive(Ingester) { - f.Cfg.Analytics.Leader = true - } - - usagestats.Target(f.Cfg.Target.String()) - - b := f.storageBucket - if f.storageBucket == nil { - if err := os.MkdirAll(f.Cfg.PhlareDB.DataPath, 0o777); err != nil { - return nil, fmt.Errorf("mkdir %s: %w", f.Cfg.PhlareDB.DataPath, err) - } - fs, err := filesystem.NewBucket(f.Cfg.PhlareDB.DataPath) - if err != nil { - return nil, err - } - b = fs - } - - if b == nil { - level.Warn(f.logger).Log("msg", "no storage bucket configured, usage report will not be sent") - return nil, nil - } - - ur, err := usagestats.NewReporter(f.Cfg.Analytics, f.Cfg.Ingester.LifecyclerConfig.RingConfig.KVStore, b, f.logger, f.reg) - if err != nil { - level.Info(f.logger).Log("msg", "failed to initialize usage report", "err", err) - return nil, nil - } - f.usageReport = ur - return ur, nil -} - -func (f *Phlare) initAdmin() (services.Service, error) { - if f.storageBucket == nil { - level.Warn(f.logger).Log("msg", "no storage bucket configured, the admin component will not be loaded") - return nil, nil - } - - a, err := operations.NewAdmin(f.storageBucket, f.logger, f.Cfg.PhlareDB.MaxBlockDuration) - if err != nil { - level.Info(f.logger).Log("msg", "failed to initialize admin", "err", err) - return nil, nil - } - f.admin = a - f.API.RegisterAdmin(a) - return a, nil -} - -type statusService struct { - statusv1.UnimplementedStatusServiceServer - defaultConfig *Config - actualConfig *Config -} - -func (s *statusService) GetBuildInfo(ctx context.Context, req *statusv1.GetBuildInfoRequest) (*statusv1.GetBuildInfoResponse, error) { - version := build.GetVersion() - return &statusv1.GetBuildInfoResponse{ - Status: "success", - Data: &statusv1.GetBuildInfoData{ - Version: version.Version, - Revision: build.Revision, - Branch: version.Branch, - GoVersion: version.GoVersion, - }, - }, nil -} - -const ( - // There is not standardised and generally used content-type for YAML, - // text/plain ensures the YAML is displayed in the browser instead of - // offered as a download - yamlContentType = "text/plain; charset=utf-8" -) - -func (s *statusService) GetConfig(ctx context.Context, req *statusv1.GetConfigRequest) (*httpbody.HttpBody, error) { - body, err := yaml.Marshal(s.actualConfig) - if err != nil { - return nil, err - } - - return &httpbody.HttpBody{ - ContentType: yamlContentType, - Data: body, - }, nil -} - -func (s *statusService) GetDefaultConfig(ctx context.Context, req *statusv1.GetConfigRequest) (*httpbody.HttpBody, error) { - body, err := yaml.Marshal(s.defaultConfig) - if err != nil { - return nil, err - } - - return &httpbody.HttpBody{ - ContentType: yamlContentType, - Data: body, - }, nil -} - -func (s *statusService) GetDiffConfig(ctx context.Context, req *statusv1.GetConfigRequest) (*httpbody.HttpBody, error) { - aBody, err := yaml.Marshal(s.actualConfig) - if err != nil { - return nil, err - } - aCfg := map[interface{}]interface{}{} - if err := yaml.Unmarshal(aBody, &aCfg); err != nil { - return nil, err - } - - dBody, err := yaml.Marshal(s.defaultConfig) - if err != nil { - return nil, err - } - dCfg := map[interface{}]interface{}{} - if err := yaml.Unmarshal(dBody, &dCfg); err != nil { - return nil, err - } - - diff, err := util.DiffConfig(dCfg, aCfg) - if err != nil { - return nil, err - } - - body, err := yaml.Marshal(diff) - if err != nil { - return nil, err - } - - return &httpbody.HttpBody{ - ContentType: yamlContentType, - Data: body, - }, nil -} - -func (f *Phlare) statusService() statusv1.StatusServiceServer { - return &statusService{ - actualConfig: &f.Cfg, - defaultConfig: newDefaultConfig(), - } -} - -func (f *Phlare) isModuleActive(m string) bool { - for _, target := range f.Cfg.Target { - if target == m { - return true - } - if f.recursiveIsModuleActive(target, m) { - return true - } - } - return false -} - -func (f *Phlare) recursiveIsModuleActive(target, m string) bool { - if targetDeps, ok := f.deps[target]; ok { - for _, dep := range targetDeps { - if dep == m { - return true - } - if f.recursiveIsModuleActive(dep, m) { - return true - } - } - } - return false -} - -// NewServerService constructs service from Server component. -// servicesToWaitFor is called when server is stopping, and should return all -// services that need to terminate before server actually stops. -// N.B.: this function is NOT Cortex specific, please let's keep it that way. -// Passed server should not react on signals. Early return from Run function is considered to be an error. -func NewServerService(serv *server.Server, servicesToWaitFor func() []services.Service, log log.Logger) services.Service { - serverDone := make(chan error, 1) - - runFn := func(ctx context.Context) error { - go func() { - defer close(serverDone) - serverDone <- serv.Run() - }() - - select { - case <-ctx.Done(): - return nil - case err := <-serverDone: - if err != nil { - return err - } - return fmt.Errorf("server stopped unexpectedly") - } - } - - stoppingFn := func(_ error) error { - // wait until all modules are done, and then shutdown server. - for _, s := range servicesToWaitFor() { - _ = s.AwaitTerminated(context.Background()) - } - - // shutdown HTTP and gRPC servers (this also unblocks Run) - serv.Shutdown() - - // if not closed yet, wait until server stops. - <-serverDone - level.Info(log).Log("msg", "server stopped") - return nil - } - - return services.NewBasicService(nil, runFn, stoppingFn) -} - -// DisableSignalHandling puts a dummy signal handler -func DisableSignalHandling(config *server.Config) { - config.SignalHandler = make(ignoreSignalHandler) -} - -type ignoreSignalHandler chan struct{} - -func (dh ignoreSignalHandler) Loop() { - <-dh -} - -func (dh ignoreSignalHandler) Stop() { - close(dh) -} diff --git a/pkg/phlare/phlare.go b/pkg/phlare/phlare.go deleted file mode 100644 index ca12ce448b..0000000000 --- a/pkg/phlare/phlare.go +++ /dev/null @@ -1,596 +0,0 @@ -package phlare - -import ( - "bytes" - "context" - "errors" - "flag" - "fmt" - "io" - "net/http" - "os" - "runtime" - "runtime/debug" - "sort" - "strings" - - "connectrpc.com/connect" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/gorilla/mux" - "github.com/grafana/dskit/flagext" - "github.com/grafana/dskit/grpcutil" - "github.com/grafana/dskit/kv/memberlist" - dslog "github.com/grafana/dskit/log" - "github.com/grafana/dskit/modules" - "github.com/grafana/dskit/ring" - "github.com/grafana/dskit/runtimeconfig" - "github.com/grafana/dskit/server" - "github.com/grafana/dskit/services" - "github.com/grafana/dskit/signals" - "github.com/grafana/dskit/spanprofiler" - wwtracing "github.com/grafana/dskit/tracing" - "github.com/grafana/pyroscope-go" - grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/opentracing/opentracing-go" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/common/version" - "github.com/samber/lo" - - "github.com/grafana/pyroscope/pkg/api" - apiversion "github.com/grafana/pyroscope/pkg/api/version" - "github.com/grafana/pyroscope/pkg/cfg" - "github.com/grafana/pyroscope/pkg/compactor" - "github.com/grafana/pyroscope/pkg/distributor" - "github.com/grafana/pyroscope/pkg/frontend" - "github.com/grafana/pyroscope/pkg/ingester" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - objstoreclient "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/operations" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/querier" - "github.com/grafana/pyroscope/pkg/querier/worker" - "github.com/grafana/pyroscope/pkg/scheduler" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerdiscovery" - "github.com/grafana/pyroscope/pkg/storegateway" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/tracing" - "github.com/grafana/pyroscope/pkg/usagestats" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/cli" - "github.com/grafana/pyroscope/pkg/validation" - "github.com/grafana/pyroscope/pkg/validation/exporter" -) - -type Config struct { - Target flagext.StringSliceCSV `yaml:"target,omitempty"` - API api.Config `yaml:"api"` - Server server.Config `yaml:"server,omitempty"` - Distributor distributor.Config `yaml:"distributor,omitempty"` - Querier querier.Config `yaml:"querier,omitempty"` - Frontend frontend.Config `yaml:"frontend,omitempty"` - Worker worker.Config `yaml:"frontend_worker"` - LimitsConfig validation.Limits `yaml:"limits"` - QueryScheduler scheduler.Config `yaml:"query_scheduler"` - Ingester ingester.Config `yaml:"ingester,omitempty"` - StoreGateway storegateway.Config `yaml:"store_gateway,omitempty"` - MemberlistKV memberlist.KVConfig `yaml:"memberlist"` - PhlareDB phlaredb.Config `yaml:"pyroscopedb,omitempty"` - Tracing tracing.Config `yaml:"tracing"` - OverridesExporter exporter.Config `yaml:"overrides_exporter" doc:"hidden"` - RuntimeConfig runtimeconfig.Config `yaml:"runtime_config"` - Compactor compactor.Config `yaml:"compactor"` - - Storage StorageConfig `yaml:"storage"` - SelfProfiling SelfProfilingConfig `yaml:"self_profiling,omitempty"` - - MultitenancyEnabled bool `yaml:"multitenancy_enabled,omitempty"` - Analytics usagestats.Config `yaml:"analytics"` - ShowBanner bool `yaml:"show_banner,omitempty"` - - ConfigFile string `yaml:"-"` - ConfigExpandEnv bool `yaml:"-"` -} - -func newDefaultConfig() *Config { - defaultConfig := &Config{} - defaultFS := flag.NewFlagSet("", flag.PanicOnError) - defaultConfig.RegisterFlags(defaultFS) - return defaultConfig -} - -type StorageConfig struct { - Bucket objstoreclient.Config `yaml:",inline"` -} - -func (c *StorageConfig) RegisterFlagsWithContext(ctx context.Context, f *flag.FlagSet) { - c.Bucket.RegisterFlagsWithPrefix("storage.", f, phlarecontext.Logger(ctx)) -} - -type SelfProfilingConfig struct { - DisablePush bool `yaml:"disable_push,omitempty"` - MutexProfileFraction int `yaml:"mutex_profile_fraction,omitempty"` - BlockProfileRate int `yaml:"block_profile_rate,omitempty"` -} - -func (c *SelfProfilingConfig) RegisterFlags(f *flag.FlagSet) { - // these are values that worked well in OG Pyroscope Cloud without adding much overhead - f.IntVar(&c.MutexProfileFraction, "self-profiling.mutex-profile-fraction", 5, "") - f.IntVar(&c.BlockProfileRate, "self-profiling.block-profile-rate", 5, "") - f.BoolVar(&c.DisablePush, "self-profiling.disable-push", false, "When running in single binary (--target=all) Pyroscope will push (Go SDK) profiles to itself. Set to true to disable self-profiling.") -} - -func (c *Config) RegisterFlags(f *flag.FlagSet) { - c.RegisterFlagsWithContext(context.Background(), f) -} - -// RegisterFlagsWithContext registers flag. -func (c *Config) RegisterFlagsWithContext(ctx context.Context, f *flag.FlagSet) { - // Set the default module list to 'all' - c.Target = []string{All} - f.StringVar(&c.ConfigFile, "config.file", "", "yaml file to load") - f.Var(&c.Target, "target", "Comma-separated list of Pyroscope modules to load. "+ - "The alias 'all' can be used in the list to load a number of core modules and will enable single-binary mode. ") - f.BoolVar(&c.MultitenancyEnabled, "auth.multitenancy-enabled", false, "When set to true, incoming HTTP requests must specify tenant ID in HTTP X-Scope-OrgId header. When set to false, tenant ID anonymous is used instead.") - f.BoolVar(&c.ConfigExpandEnv, "config.expand-env", false, "Expands ${var} in config according to the values of the environment variables.") - f.BoolVar(&c.ShowBanner, "config.show_banner", true, "Prints the application banner at startup.") - - c.registerServerFlagsWithChangedDefaultValues(f) - c.MemberlistKV.RegisterFlags(f) - c.Querier.RegisterFlags(f) - c.StoreGateway.RegisterFlags(f, util.Logger) - c.PhlareDB.RegisterFlags(f) - c.Tracing.RegisterFlags(f) - c.Storage.RegisterFlagsWithContext(ctx, f) - c.SelfProfiling.RegisterFlags(f) - c.RuntimeConfig.RegisterFlags(f) - c.Analytics.RegisterFlags(f) - c.LimitsConfig.RegisterFlags(f) - c.Compactor.RegisterFlags(f, log.NewLogfmtLogger(os.Stderr)) - c.API.RegisterFlags(f) -} - -// registerServerFlagsWithChangedDefaultValues registers *Config.Server flags, but overrides some defaults set by the weaveworks package. -func (c *Config) registerServerFlagsWithChangedDefaultValues(fs *flag.FlagSet) { - throwaway := flag.NewFlagSet("throwaway", flag.PanicOnError) - - // Register to throwaway flags first. Default values are remembered during registration and cannot be changed, - // but we can take values from throwaway flag set and reregister into supplied flags with new default values. - c.Server.RegisterFlags(throwaway) - c.Ingester.RegisterFlags(throwaway) - c.Distributor.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) - c.Frontend.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) - c.QueryScheduler.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) - c.Worker.RegisterFlags(throwaway) - c.OverridesExporter.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) - - throwaway.VisitAll(func(f *flag.Flag) { - // Ignore errors when setting new values. We have a test to verify that it works. - switch f.Name { - case "server.http-listen-port": - _ = f.Value.Set("4040") - case "distributor.replication-factor": - _ = f.Value.Set("1") - case "query-scheduler.service-discovery-mode": - _ = f.Value.Set(schedulerdiscovery.ModeRing) - } - fs.Var(f.Value, f.Name, f.Usage) - }) -} - -func (c *Config) Validate() error { - if len(c.Target) == 0 { - return errors.New("no modules specified") - } - if err := c.Compactor.Validate(c.PhlareDB.MaxBlockDuration); err != nil { - return err - } - return c.Ingester.Validate() -} - -func (c *Config) ApplyDynamicConfig() cfg.Source { - c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store = "memberlist" - c.Distributor.DistributorRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store - c.OverridesExporter.Ring.Ring.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store - c.Frontend.QuerySchedulerDiscovery.SchedulerRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store - c.Worker.QuerySchedulerDiscovery.SchedulerRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store - c.QueryScheduler.ServiceDiscovery.SchedulerRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store - c.StoreGateway.ShardingRing.Ring.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store - c.Compactor.ShardingRing.Common.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store - - return func(dst cfg.Cloneable) error { - return nil - } -} - -func (c *Config) Clone() flagext.Registerer { - return func(c Config) *Config { - return &c - }(*c) -} - -type Phlare struct { - Cfg Config - logger log.Logger - reg prometheus.Registerer - tracer io.Closer - - ModuleManager *modules.Manager - serviceMap map[string]services.Service - deps map[string][]string - - API *api.API - Server *server.Server - SignalHandler *signals.Handler - MemberlistKV *memberlist.KVInitService - ring *ring.Ring - usageReport *usagestats.Reporter - RuntimeConfig *runtimeconfig.Manager - Overrides *validation.Overrides - Compactor *compactor.MultitenantCompactor - admin *operations.Admin - versions *apiversion.Service - serviceManager *services.Manager - - TenantLimits validation.TenantLimits - - storageBucket phlareobj.Bucket - - grpcGatewayMux *grpcgw.ServeMux - - auth connect.Option -} - -func New(cfg Config) (*Phlare, error) { - logger := initLogger(cfg.Server.LogFormat, cfg.Server.LogLevel) - cfg.Server.Log = logger - usagestats.Edition("oss") - - phlare := &Phlare{ - Cfg: cfg, - logger: logger, - reg: prometheus.DefaultRegisterer, - } - if err := cfg.Validate(); err != nil { - return nil, err - } - if err := phlare.setupModuleManager(); err != nil { - return nil, err - } - - runtime.SetMutexProfileFraction(cfg.SelfProfiling.MutexProfileFraction) - runtime.SetBlockProfileRate(cfg.SelfProfiling.BlockProfileRate) - - if cfg.Tracing.Enabled { - // Setting the environment variable JAEGER_AGENT_HOST enables tracing - trace, err := wwtracing.NewFromEnv(fmt.Sprintf("pyroscope-%s", cfg.Target)) - if err != nil { - level.Error(logger).Log("msg", "error in initializing tracing. tracing will not be enabled", "err", err) - } - if cfg.Tracing.ProfilingEnabled { - opentracing.SetGlobalTracer(spanprofiler.NewTracer(opentracing.GlobalTracer())) - } - phlare.tracer = trace - } - - phlare.auth = connect.WithInterceptors(tenant.NewAuthInterceptor(cfg.MultitenancyEnabled)) - phlare.Cfg.API.HTTPAuthMiddleware = util.AuthenticateUser(cfg.MultitenancyEnabled) - phlare.Cfg.API.GrpcAuthMiddleware = phlare.auth - - return phlare, nil -} - -func (f *Phlare) setupModuleManager() error { - mm := modules.NewManager(f.logger) - - mm.RegisterModule(Storage, f.initStorage, modules.UserInvisibleModule) - mm.RegisterModule(GRPCGateway, f.initGRPCGateway, modules.UserInvisibleModule) - mm.RegisterModule(MemberlistKV, f.initMemberlistKV, modules.UserInvisibleModule) - mm.RegisterModule(Ring, f.initRing, modules.UserInvisibleModule) - mm.RegisterModule(RuntimeConfig, f.initRuntimeConfig, modules.UserInvisibleModule) - mm.RegisterModule(Overrides, f.initOverrides, modules.UserInvisibleModule) - mm.RegisterModule(OverridesExporter, f.initOverridesExporter) - mm.RegisterModule(Ingester, f.initIngester) - mm.RegisterModule(Server, f.initServer, modules.UserInvisibleModule) - mm.RegisterModule(API, f.initAPI, modules.UserInvisibleModule) - mm.RegisterModule(Version, f.initVersion, modules.UserInvisibleModule) - mm.RegisterModule(Distributor, f.initDistributor) - mm.RegisterModule(Querier, f.initQuerier) - mm.RegisterModule(StoreGateway, f.initStoreGateway) - mm.RegisterModule(UsageReport, f.initUsageReport) - mm.RegisterModule(QueryFrontend, f.initQueryFrontend) - mm.RegisterModule(QueryScheduler, f.initQueryScheduler) - mm.RegisterModule(Compactor, f.initCompactor) - mm.RegisterModule(Admin, f.initAdmin) - mm.RegisterModule(All, nil) - mm.RegisterModule(TenantSettings, f.initTenantSettings) - mm.RegisterModule(AdHocProfiles, f.initAdHocProfiles) - - // Add dependencies - deps := map[string][]string{ - All: {Ingester, Distributor, QueryScheduler, QueryFrontend, Querier, StoreGateway, Admin, TenantSettings, Compactor, AdHocProfiles}, - - Server: {GRPCGateway}, - API: {Server}, - Distributor: {Overrides, Ring, API, UsageReport}, - Querier: {Overrides, API, MemberlistKV, Ring, UsageReport, Version}, - QueryFrontend: {OverridesExporter, API, MemberlistKV, UsageReport, Version}, - QueryScheduler: {Overrides, API, MemberlistKV, UsageReport}, - Ingester: {Overrides, API, MemberlistKV, Storage, UsageReport, Version}, - StoreGateway: {API, Storage, Overrides, MemberlistKV, UsageReport, Admin, Version}, - Compactor: {API, Storage, Overrides, MemberlistKV, UsageReport}, - UsageReport: {Storage, MemberlistKV}, - Overrides: {RuntimeConfig}, - OverridesExporter: {Overrides, MemberlistKV}, - RuntimeConfig: {API}, - Ring: {API, MemberlistKV}, - MemberlistKV: {API}, - Admin: {API, Storage}, - Version: {API, MemberlistKV}, - TenantSettings: {API, Storage}, - AdHocProfiles: {API, Overrides, Storage}, - } - - for mod, targets := range deps { - if err := mm.AddDependency(mod, targets...); err != nil { - return err - } - } - - f.deps = deps - f.ModuleManager = mm - - return nil -} - -// made here https://patorjk.com/software/taag/#p=display&f=Doom&t=grafana%20pyroscope -// also needed to replace all ` with ' -var banner = ` - / _| - __ _ _ __ __ _| |_ __ _ _ __ __ _ _ __ _ _ _ __ ___ ___ ___ ___ _ __ ___ - / _' | '__/ _' | _/ _' | '_ \ / _' | | '_ \| | | | '__/ _ \/ __|/ __/ _ \| '_ \ / _ \ -| (_| | | | (_| | || (_| | | | | (_| | | |_) | |_| | | | (_) \__ \ (_| (_) | |_) | __/ - \__, |_| \__,_|_| \__,_|_| |_|\__,_| | .__/ \__, |_| \___/|___/\___\___/| .__/ \___| - __/ | | | __/ | | | - |___/ |_| |___/ |_| - ` - -func (f *Phlare) Run() error { - if f.Cfg.ShowBanner { - _ = cli.GradientBanner(banner, os.Stderr) - } - - serviceMap, err := f.ModuleManager.InitModuleServices(f.Cfg.Target...) - if err != nil { - return err - } - - f.serviceMap = serviceMap - var servs []services.Service - for _, s := range serviceMap { - servs = append(servs, s) - } - - sm, err := services.NewManager(servs...) - if err != nil { - return err - } - f.serviceManager = sm - - f.API.RegisterRoute("/ready", f.readyHandler(sm), false, false, "GET") - - RegisterHealthServer(f.Server.HTTP, grpcutil.WithManager(sm)) - healthy := func() { - level.Info(f.logger).Log("msg", "Pyroscope started", "version", version.Info()) - if os.Getenv("PYROSCOPE_PRINT_ROUTES") != "" { - printRoutes(f.Server.HTTP) - } - - // Start profiling when Pyroscope is ready - if !f.Cfg.SelfProfiling.DisablePush && f.Cfg.Target.String() == All { - _, err := pyroscope.Start(pyroscope.Config{ - ApplicationName: "pyroscope", - ServerAddress: fmt.Sprintf("http://%s:%d", "localhost", f.Cfg.Server.HTTPListenPort), - Tags: map[string]string{ - "hostname": os.Getenv("HOSTNAME"), - "target": "all", - "service_git_ref": serviceGitRef(), - "service_repository": "https://github.com/grafana/pyroscope", - }, - ProfileTypes: []pyroscope.ProfileType{ - pyroscope.ProfileCPU, - pyroscope.ProfileAllocObjects, - pyroscope.ProfileAllocSpace, - pyroscope.ProfileInuseObjects, - pyroscope.ProfileInuseSpace, - pyroscope.ProfileGoroutines, - pyroscope.ProfileMutexCount, - pyroscope.ProfileMutexDuration, - pyroscope.ProfileBlockCount, - pyroscope.ProfileBlockDuration, - }, - }) - if err != nil { - level.Warn(f.logger).Log("msg", "failed to start pyroscope", "err", err) - } - } - } - - if err = f.API.RegisterCatchAll(); err != nil { - return err - } - - serviceFailed := func(service services.Service) { - // if any service fails, stop entire Phlare - sm.StopAsync() - - // let's find out which module failed - for m, s := range serviceMap { - if s == service { - if service.FailureCase() == modules.ErrStopProcess { - level.Info(f.logger).Log("msg", "received stop signal via return error", "module", m, "error", service.FailureCase()) - } else { - level.Error(f.logger).Log("msg", "module failed", "module", m, "error", service.FailureCase()) - } - return - } - } - - level.Error(f.logger).Log("msg", "module failed", "module", "unknown", "error", service.FailureCase()) - } - - sm.AddListener(services.NewManagerListener(healthy, f.stopped, serviceFailed)) - - // Setup signal handler. If signal arrives, we stop the manager, which stops all the services. - f.SignalHandler = signals.NewHandler(f.Server.Log) - go func() { - f.SignalHandler.Loop() - sm.StopAsync() - }() - - // Start all services. This can really only fail if some service is already - // in other state than New, which should not be the case. - err = sm.StartAsync(context.Background()) - if err == nil { - // Wait until service manager stops. It can stop in two ways: - // 1) Signal is received and manager is stopped. - // 2) Any service fails. - err = sm.AwaitStopped(context.Background()) - } - if f.versions != nil { - f.versions.Shutdown() - } - // If there is no error yet (= service manager started and then stopped without problems), - // but any service failed, report that failure as an error to caller. - if err == nil { - if failed := sm.ServicesByState()[services.Failed]; len(failed) > 0 { - for _, f := range failed { - if f.FailureCase() != modules.ErrStopProcess { - // Details were reported via failure listener before - err = errors.New("failed services") - break - } - } - } - } - - return err -} - -func (f *Phlare) readyHandler(sm *services.Manager) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - if !sm.IsHealthy() { - msg := bytes.Buffer{} - msg.WriteString("Some services are not Running:\n") - - byState := map[services.State][]string{} - for name, svc := range f.serviceMap { - state := svc.State() - byState[state] = append(byState[state], name) - } - - states := lo.Keys(byState) - sort.Slice(states, func(i, j int) bool { return states[i] < states[j] }) - - for _, st := range states { - sort.Strings(byState[st]) - msg.WriteString(fmt.Sprintf("%v: %v\n", st, byState[st])) - } - - http.Error(w, msg.String(), http.StatusServiceUnavailable) - return - } - - util.WriteTextResponse(w, "ready") - } -} - -func (f *Phlare) Stop() func(context.Context) error { - if f.serviceManager == nil { - return func(context.Context) error { return nil } - } - f.serviceManager.StopAsync() - return f.serviceManager.AwaitStopped -} - -func (f *Phlare) stopped() { - level.Info(f.logger).Log("msg", "Pyroscope stopped") - if f.tracer != nil { - if err := f.tracer.Close(); err != nil { - level.Error(f.logger).Log("msg", "error closing tracing", "err", err) - } - } -} - -func initLogger(logFormat string, logLevel dslog.Level) log.Logger { - writer := log.NewSyncWriter(os.Stderr) - logger := dslog.NewGoKitWithWriter(logFormat, writer) - - // use UTC timestamps and skip 5 stack frames. - logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.Caller(5)) - - // Must put the level filter last for efficiency. - logger = level.NewFilter(logger, logLevel.Option) - - return logger -} - -func (f *Phlare) initAPI() (services.Service, error) { - a, err := api.New(f.Cfg.API, f.Server, f.grpcGatewayMux, f.Server.Log) - if err != nil { - return nil, err - } - f.API = a - - if err := f.API.RegisterAPI(f.statusService()); err != nil { - return nil, err - } - - return nil, nil -} - -func (f *Phlare) initVersion() (services.Service, error) { - var err error - f.versions, err = apiversion.New(f.Cfg.Distributor.DistributorRing, f.logger, f.reg) - if err != nil { - return nil, err - } - f.API.RegisterVersion(f.versions) - return f.versions, nil -} - -func printRoutes(r *mux.Router) { - err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { - path, err := route.GetPathRegexp() - if err != nil { - fmt.Printf("failed to get path regexp %s\n", err) - return nil - } - method, err := route.GetMethods() - if err != nil { - method = []string{"*"} - } - fmt.Printf("%s %s\n", strings.Join(method, ","), path) - return nil - }) - if err != nil { - fmt.Printf("failed to walk routes %s\n", err) - } -} - -// serviceGitRef attempts to find the git revision of the service. Default to HEAD. -func serviceGitRef() string { - if version.Revision != "" { - return version.Revision - } - buildInfo, ok := debug.ReadBuildInfo() - if ok { - for _, setting := range buildInfo.Settings { - if setting.Key == "vcs.revision" { - return setting.Value - } - } - } - return "HEAD" -} diff --git a/pkg/phlare/phlare_test.go b/pkg/phlare/phlare_test.go deleted file mode 100644 index c9a50b23bb..0000000000 --- a/pkg/phlare/phlare_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package phlare - -import ( - "bytes" - "context" - "flag" - "io" - "strings" - "testing" - - "github.com/stretchr/testify/require" - - statusv1 "github.com/grafana/pyroscope/api/gen/proto/go/status/v1" -) - -func TestFlagDefaults(t *testing.T) { - c := Config{} - - f := flag.NewFlagSet("test", flag.PanicOnError) - c.RegisterFlags(f) - - buf := bytes.Buffer{} - - f.SetOutput(&buf) - f.PrintDefaults() - - const delim = '\n' - // Because this is a short flag, it will be printed on the same line as the - // flag name. So we need to ignore this special case. - const ignoredHelpFlags = "-h\tPrint basic help." - - // Populate map with parsed default flags. - // Key is the flag and value is the default text. - gotFlags := make(map[string]string) - for { - line, err := buf.ReadString(delim) - if err == io.EOF { - break - } - require.NoError(t, err) - - if strings.Contains(line, ignoredHelpFlags) { - continue - } - - nextLine, err := buf.ReadString(delim) - require.NoError(t, err) - - trimmedLine := strings.Trim(line, " \n") - splittedLine := strings.Split(trimmedLine, " ")[0] - gotFlags[splittedLine] = nextLine - } - - flagToCheck := "-server.http-listen-port" - require.Contains(t, gotFlags, flagToCheck) - require.Equal(t, c.Server.HTTPListenPort, 4040) - require.Contains(t, gotFlags[flagToCheck], "(default 4040)") -} - -func TestConfigDiff(t *testing.T) { - defaultCfg := Config{} - f := flag.NewFlagSet("test", flag.PanicOnError) - defaultCfg.RegisterFlags(f) - require.NoError(t, f.Parse([]string{})) - phlare, err := New(defaultCfg) - require.NoError(t, err) - - t.Run("default config unchanged", func(t *testing.T) { - result, err := phlare.statusService().GetDiffConfig(context.Background(), &statusv1.GetConfigRequest{}) - require.NoError(t, err) - require.Equal(t, "text/plain; charset=utf-8", result.ContentType) - require.Equal(t, "{}\n", string(result.Data)) - }) - t.Run("change a limit", func(t *testing.T) { - phlare.Cfg.LimitsConfig.MaxLabelNameLength = 123 - - result, err := phlare.statusService().GetDiffConfig(context.Background(), &statusv1.GetConfigRequest{}) - require.NoError(t, err) - require.Equal(t, "text/plain; charset=utf-8", result.ContentType) - require.Equal(t, "limits:\n max_label_name_length: 123\n", string(result.Data)) - }) -} diff --git a/pkg/phlare/runtime_config.go b/pkg/phlare/runtime_config.go deleted file mode 100644 index 6195da8b45..0000000000 --- a/pkg/phlare/runtime_config.go +++ /dev/null @@ -1,123 +0,0 @@ -package phlare - -import ( - "fmt" - "io" - "net/http" - - "github.com/go-kit/log/level" - "github.com/grafana/dskit/runtimeconfig" - "gopkg.in/yaml.v3" - - "github.com/grafana/pyroscope/pkg/util" - httputil "github.com/grafana/pyroscope/pkg/util/http" - "github.com/grafana/pyroscope/pkg/validation" -) - -type runtimeConfigValues struct { - TenantLimits map[string]*validation.Limits `yaml:"overrides"` -} - -func (r runtimeConfigValues) validate() error { - for t, c := range r.TenantLimits { - if c == nil { - level.Warn(util.Logger).Log("msg", "skipping empty tenant limit definition", "tenant", t) - continue - } - - if err := c.Validate(); err != nil { - return fmt.Errorf("invalid override for tenant %s: %w", t, err) - } - } - return nil -} - -func loadRuntimeConfig(r io.Reader) (interface{}, error) { - overrides := &runtimeConfigValues{} - - decoder := yaml.NewDecoder(r) - decoder.KnownFields(true) - if err := decoder.Decode(&overrides); err != nil { - return nil, err - } - if err := overrides.validate(); err != nil { - return nil, err - } - return overrides, nil -} - -type tenantLimitsFromRuntimeConfig struct { - c *runtimeconfig.Manager -} - -func (t *tenantLimitsFromRuntimeConfig) AllByTenantID() map[string]*validation.Limits { - if t.c == nil { - return nil - } - - cfg, ok := t.c.GetConfig().(*runtimeConfigValues) - if cfg != nil && ok { - return cfg.TenantLimits - } - - return nil -} - -func (t *tenantLimitsFromRuntimeConfig) TenantLimits(userID string) *validation.Limits { - allByUserID := t.AllByTenantID() - if allByUserID == nil { - return nil - } - - return allByUserID[userID] -} - -func newTenantLimits(c *runtimeconfig.Manager) validation.TenantLimits { - return &tenantLimitsFromRuntimeConfig{c: c} -} - -func runtimeConfigHandler(runtimeCfgManager *runtimeconfig.Manager, defaultLimits validation.Limits) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - cfg, ok := runtimeCfgManager.GetConfig().(*runtimeConfigValues) - if !ok || cfg == nil { - util.WriteTextResponse(w, "runtime config file doesn't exist") - return - } - - var output interface{} - switch r.URL.Query().Get("mode") { - case "diff": - // Default runtime config is just empty struct, but to make diff work, - // we set defaultLimits for every tenant that exists in runtime config. - defaultCfg := runtimeConfigValues{} - defaultCfg.TenantLimits = map[string]*validation.Limits{} - for k, v := range cfg.TenantLimits { - if v != nil { - defaultCfg.TenantLimits[k] = &defaultLimits - } - } - - cfgYaml, err := util.YAMLMarshalUnmarshal(cfg) - if err != nil { - httputil.Error(w, err) - return - } - - defaultCfgYaml, err := util.YAMLMarshalUnmarshal(defaultCfg) - if err != nil { - httputil.Error(w, err) - return - } - - output, err = util.DiffConfig(defaultCfgYaml, cfgYaml) - if err != nil { - httputil.Error(w, err) - return - } - - default: - output = cfg - } - util.WriteYAMLResponse(w, output) - } -} diff --git a/pkg/phlaredb/block/block.go b/pkg/phlaredb/block/block.go index 55a49b4d73..eb4f60a589 100644 --- a/pkg/phlaredb/block/block.go +++ b/pkg/phlaredb/block/block.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "fmt" "io" "os" "path" @@ -14,14 +15,12 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/util/fnv32" + "github.com/grafana/pyroscope/v2/pkg/util/fnv32" ) const ( @@ -36,7 +35,7 @@ const ( func DownloadMeta(ctx context.Context, logger log.Logger, bkt objstore.Bucket, id ulid.ULID) (Meta, error) { rc, err := bkt.Get(ctx, path.Join(id.String(), MetaFilename)) if err != nil { - return Meta{}, errors.Wrapf(err, "meta.json bkt get for %s", id.String()) + return Meta{}, fmt.Errorf("meta.json bkt get for %s: %w", id.String(), err) } defer runutil.CloseWithLogOnErr(logger, rc, "download meta bucket client") @@ -44,11 +43,11 @@ func DownloadMeta(ctx context.Context, logger log.Logger, bkt objstore.Bucket, i obj, err := io.ReadAll(rc) if err != nil { - return Meta{}, errors.Wrapf(err, "read meta.json for block %s", id.String()) + return Meta{}, fmt.Errorf("read meta.json for block %s: %w", id.String(), err) } if err = json.Unmarshal(obj, &m); err != nil { - return Meta{}, errors.Wrapf(err, "unmarshal meta.json for block %s", id.String()) + return Meta{}, fmt.Errorf("unmarshal meta.json for block %s: %w", id.String(), err) } return m, nil @@ -56,11 +55,12 @@ func DownloadMeta(ctx context.Context, logger log.Logger, bkt objstore.Bucket, i // Download downloads directory that is meant to be block directory. func Download(ctx context.Context, logger log.Logger, bucket objstore.Bucket, id ulid.ULID, dst string, options ...objstore.DownloadOption) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "block.Download", opentracing.Tag{Key: "ULID", Value: id.String()}) + sp, ctx := tracing.StartSpanFromContext(ctx, "block.Download") + sp.SetTag("ULID", id.String()) defer sp.Finish() if err := os.MkdirAll(dst, 0o750); err != nil { - return errors.Wrap(err, "create dir") + return fmt.Errorf("create dir: %w", err) } if err := objstore.DownloadFile(ctx, logger, bucket, path.Join(id.String(), MetaFilename), filepath.Join(dst, MetaFilename)); err != nil { @@ -90,19 +90,19 @@ func upload(ctx context.Context, logger log.Logger, bkt objstore.Bucket, bdir st return err } if !df.IsDir() { - return errors.Errorf("%s is not a directory", bdir) + return fmt.Errorf("%s is not a directory", bdir) } // Verify dir. id, err := ulid.Parse(df.Name()) if err != nil { - return errors.Wrap(err, "not a block dir") + return fmt.Errorf("not a block dir: %w", err) } meta, err := ReadMetaFromDir(bdir) if err != nil { // No meta or broken meta file. - return errors.Wrap(err, "read meta") + return fmt.Errorf("read meta: %w", err) } // ensure labels are initialized @@ -117,17 +117,17 @@ func upload(ctx context.Context, logger log.Logger, bkt objstore.Bucket, bdir st metaEncoded := strings.Builder{} if err != nil { - return errors.Wrap(err, "gather meta file stats") + return fmt.Errorf("gather meta file stats: %w", err) } if _, err := meta.WriteTo(&metaEncoded); err != nil { - return errors.Wrap(err, "encode meta file") + return fmt.Errorf("encode meta file: %w", err) } // loop through files for _, file := range meta.Files { if err := objstore.UploadFile(ctx, logger, bkt, path.Join(bdir, file.RelPath), path.Join(id.String(), file.RelPath)); err != nil { - return cleanUp(logger, bkt, id, errors.Wrapf(err, "uploading file '%s'", file.RelPath)) + return cleanUp(logger, bkt, id, fmt.Errorf("uploading file '%s': %w", file.RelPath, err)) } } @@ -137,7 +137,7 @@ func upload(ctx context.Context, logger log.Logger, bkt objstore.Bucket, bdir st // and even though cleanUp will not see it yet, meta.json may appear in the bucket later. // (Eg. S3 is known to behave this way when it returns 503 "SlowDown" error). // If meta.json is not uploaded, this will produce partial blocks, but such blocks will be cleaned later. - return errors.Wrap(err, "upload meta file") + return fmt.Errorf("upload meta file: %w", err) } return nil @@ -146,10 +146,12 @@ func upload(ctx context.Context, logger log.Logger, bkt objstore.Bucket, bdir st // Upload uploads a TSDB block to the object storage. It verifies basic // features of Thanos block. func Upload(ctx context.Context, logger log.Logger, bkt objstore.Bucket, bdir string) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "block.Upload", opentracing.Tag{Key: "dir", Value: bdir}) + sp, ctx := tracing.StartSpanFromContext(ctx, "block.Upload") + sp.SetTag("dir", bdir) defer sp.Finish() if err := upload(ctx, logger, bkt, bdir); err != nil { - ext.LogError(sp, err) + sp.LogError(err) + sp.SetError() return err } return nil @@ -159,7 +161,7 @@ func cleanUp(logger log.Logger, bkt objstore.Bucket, id ulid.ULID, err error) er // Cleanup the dir with an uncancelable context. cleanErr := Delete(context.Background(), logger, bkt, id) if cleanErr != nil { - return errors.Wrapf(err, "failed to clean block after upload issue. Partial block in system. Err: %s", err.Error()) + return fmt.Errorf("failed to clean block after upload issue. Partial block in system. Err: %s: %w", err.Error(), err) } return err } @@ -169,11 +171,11 @@ func MarkForDeletion(ctx context.Context, logger log.Logger, bkt objstore.Bucket deletionMarkFile := path.Join(id.String(), DeletionMarkFilename) deletionMarkExists, err := bkt.Exists(ctx, deletionMarkFile) if err != nil { - return errors.Wrapf(err, "check exists %s in bucket", deletionMarkFile) + return fmt.Errorf("check exists %s in bucket: %w", deletionMarkFile, err) } if deletionMarkExists { if warnExist { - level.Warn(logger).Log("msg", "requested to mark for deletion, but file already exists; this should not happen; investigate", "err", errors.Errorf("file %s already exists in bucket", deletionMarkFile)) + level.Warn(logger).Log("msg", "requested to mark for deletion, but file already exists; this should not happen; investigate", "err", fmt.Errorf("file %s already exists in bucket", deletionMarkFile)) } return nil } @@ -185,11 +187,11 @@ func MarkForDeletion(ctx context.Context, logger log.Logger, bkt objstore.Bucket Details: details, }) if err != nil { - return errors.Wrap(err, "json encode deletion mark") + return fmt.Errorf("json encode deletion mark: %w", err) } if err := bkt.Upload(ctx, deletionMarkFile, bytes.NewBuffer(deletionMark)); err != nil { - return errors.Wrapf(err, "upload file %s to bucket", deletionMarkFile) + return fmt.Errorf("upload file %s to bucket: %w", deletionMarkFile, err) } markedForDeletion.Inc() level.Info(logger).Log("msg", "block has been marked for deletion", "block", id) @@ -209,12 +211,12 @@ func Delete(ctx context.Context, logger log.Logger, bkt objstore.Bucket, id ulid // Delete block meta file. ok, err := bkt.Exists(ctx, metaFile) if err != nil { - return errors.Wrapf(err, "stat %s", metaFile) + return fmt.Errorf("stat %s: %w", metaFile, err) } if ok { if err := bkt.Delete(ctx, metaFile); err != nil { - return errors.Wrapf(err, "delete %s", metaFile) + return fmt.Errorf("delete %s: %w", metaFile, err) } level.Debug(logger).Log("msg", "deleted file", "file", metaFile, "bucket", bkt.Name()) } @@ -232,12 +234,12 @@ func Delete(ctx context.Context, logger log.Logger, bkt objstore.Bucket, id ulid // Delete block deletion mark. ok, err = bkt.Exists(ctx, deletionMarkFile) if err != nil { - return errors.Wrapf(err, "stat %s", deletionMarkFile) + return fmt.Errorf("stat %s: %w", deletionMarkFile, err) } if ok { if err := bkt.Delete(ctx, deletionMarkFile); err != nil { - return errors.Wrapf(err, "delete %s", deletionMarkFile) + return fmt.Errorf("delete %s: %w", deletionMarkFile, err) } level.Debug(logger).Log("msg", "deleted file", "file", deletionMarkFile, "bucket", bkt.Name()) } @@ -269,10 +271,10 @@ func MarkForNoCompact(ctx context.Context, logger log.Logger, bkt objstore.Bucke m := path.Join(id.String(), NoCompactMarkFilename) noCompactMarkExists, err := bkt.Exists(ctx, m) if err != nil { - return errors.Wrapf(err, "check exists %s in bucket", m) + return fmt.Errorf("check exists %s in bucket: %w", m, err) } if noCompactMarkExists { - level.Warn(logger).Log("msg", "requested to mark for no compaction, but file already exists; this should not happen; investigate", "err", errors.Errorf("file %s already exists in bucket", m)) + level.Warn(logger).Log("msg", "requested to mark for no compaction, but file already exists; this should not happen; investigate", "err", fmt.Errorf("file %s already exists in bucket", m)) return nil } @@ -285,11 +287,11 @@ func MarkForNoCompact(ctx context.Context, logger log.Logger, bkt objstore.Bucke Details: details, }) if err != nil { - return errors.Wrap(err, "json encode no compact mark") + return fmt.Errorf("json encode no compact mark: %w", err) } if err := bkt.Upload(ctx, m, bytes.NewBuffer(noCompactMark)); err != nil { - return errors.Wrapf(err, "upload file %s to bucket", m) + return fmt.Errorf("upload file %s to bucket: %w", m, err) } markedForNoCompact.Inc() level.Info(logger).Log("msg", "block has been marked for no compaction", "block", id) diff --git a/pkg/phlaredb/block/block_test.go b/pkg/phlaredb/block/block_test.go index 058c9a31c2..39c0554806 100644 --- a/pkg/phlaredb/block/block_test.go +++ b/pkg/phlaredb/block/block_test.go @@ -9,6 +9,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "io" "os" "path" @@ -17,8 +18,7 @@ import ( "time" "github.com/go-kit/log" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" promtest "github.com/prometheus/client_golang/prometheus/testutil" @@ -26,11 +26,11 @@ import ( "github.com/thanos-io/objstore" "go.uber.org/goleak" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - block_testutil "github.com/grafana/pyroscope/pkg/phlaredb/block/testutil" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" - "github.com/grafana/pyroscope/pkg/test" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + block_testutil "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/test" ) func TestIsBlockDir(t *testing.T) { @@ -145,7 +145,7 @@ func objects(t *testing.T, bkt objstore.Bucket, id ulid.ULID) (objects []string) } objects = append(objects, name) return nil - }, objstore.WithRecursiveIter)) + }, objstore.WithRecursiveIter())) return } @@ -369,8 +369,8 @@ type errBucket struct { failSuffix string } -func (eb errBucket) Upload(ctx context.Context, name string, r io.Reader) error { - err := eb.Bucket.Upload(ctx, name, r) +func (eb errBucket) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + err := eb.Bucket.Upload(ctx, name, r, opts...) if err != nil { return err } diff --git a/pkg/phlaredb/block/fetcher.go b/pkg/phlaredb/block/fetcher.go index 2675ac4198..0632b74aa9 100644 --- a/pkg/phlaredb/block/fetcher.go +++ b/pkg/phlaredb/block/fetcher.go @@ -8,6 +8,8 @@ package block import ( "context" "encoding/json" + "errors" + "fmt" "io" "os" "path" @@ -20,14 +22,13 @@ import ( "github.com/golang/groupcache/singleflight" "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "golang.org/x/sync/errgroup" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/util/extprom" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/util/extprom" ) // FetcherMetrics holds metrics tracked by the metadata fetcher. This struct and its fields are exported @@ -85,10 +86,13 @@ func NewFetcherMetrics(reg prometheus.Registerer, syncedExtraLabels [][]string) Help: "Total blocks metadata synchronization failures", }) m.SyncDuration = promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ - Subsystem: fetcherSubSys, - Name: "sync_duration_seconds", - Help: "Duration of the blocks metadata synchronization in seconds", - Buckets: []float64{0.01, 1, 10, 100, 300, 600, 1000}, + Subsystem: fetcherSubSys, + Name: "sync_duration_seconds", + Help: "Duration of the blocks metadata synchronization in seconds", + Buckets: []float64{0.01, 1, 10, 100, 300, 600, 1000}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }) m.Synced = extprom.NewTxGaugeVec( reg, @@ -232,26 +236,26 @@ func (f *MetaFetcher) LoadMeta(ctx context.Context, id ulid.ULID) (*Meta, error) r, err := f.bkt.Get(ctx, metaFile) if f.bkt.IsObjNotFoundErr(err) { // Meta.json was deleted between bkt.Exists and here. - return nil, errors.Wrapf(ErrorSyncMetaNotFound, "%v", err) + return nil, fmt.Errorf("%v: %w", err, ErrorSyncMetaNotFound) } if err != nil { - return nil, errors.Wrapf(err, "get meta file: %v", metaFile) + return nil, fmt.Errorf("get meta file: %v: %w", metaFile, err) } defer runutil.CloseWithLogOnErr(f.logger, r, "close bkt meta get") metaContent, err := io.ReadAll(r) if err != nil { - return nil, errors.Wrapf(err, "read meta file: %v", metaFile) + return nil, fmt.Errorf("read meta file: %v: %w", metaFile, err) } m := &Meta{} if err := json.Unmarshal(metaContent, m); err != nil { - return nil, errors.Wrapf(ErrorSyncMetaCorrupted, "meta.json %v unmarshal: %v", metaFile, err) + return nil, fmt.Errorf("meta.json %v unmarshal: %v: %w", metaFile, err, ErrorSyncMetaCorrupted) } if !m.Version.IsValid() { - return nil, errors.Errorf("unexpected meta file: %s version: %d", metaFile, m.Version) + return nil, fmt.Errorf("unexpected meta file: %s version: %d", metaFile, m.Version) } // Best effort cache in local dir. @@ -315,11 +319,11 @@ func (f *MetaFetcher) fetchMetadata(ctx context.Context, excludeMarkedForDeletio continue } - if errors.Is(errors.Cause(err), ErrorSyncMetaNotFound) { + if errors.Is(err, ErrorSyncMetaNotFound) { mtx.Lock() resp.noMetasCount++ mtx.Unlock() - } else if errors.Is(errors.Cause(err), ErrorSyncMetaCorrupted) { + } else if errors.Is(err, ErrorSyncMetaCorrupted) { mtx.Lock() resp.corruptedMetasCount++ mtx.Unlock() @@ -364,7 +368,7 @@ func (f *MetaFetcher) fetchMetadata(ctx context.Context, excludeMarkedForDeletio }) if err := eg.Wait(); err != nil { - return nil, errors.Wrap(err, "MetaFetcher: iter bucket") + return nil, fmt.Errorf("MetaFetcher: iter bucket: %w", err) } if len(resp.metaErrs) > 0 { @@ -469,7 +473,7 @@ func (f *MetaFetcher) fetch(ctx context.Context, excludeMarkedForDeletion bool) for _, filter := range f.filters { // NOTE: filter can update synced metric accordingly to the reason of the exclude. if err := filter.Filter(ctx, metas, f.metrics.Synced); err != nil { - return nil, nil, errors.Wrap(err, "filter metas") + return nil, nil, fmt.Errorf("filter metas: %w", err) } } @@ -477,7 +481,7 @@ func (f *MetaFetcher) fetch(ctx context.Context, excludeMarkedForDeletion bool) f.metrics.Submit() if len(resp.metaErrs) > 0 { - return metas, resp.partial, errors.Wrap(resp.metaErrs.Err(), "incomplete view") + return metas, resp.partial, fmt.Errorf("incomplete view: %w", resp.metaErrs.Err()) } level.Info(f.logger).Log("msg", "successfully synchronized block metadata", "duration", time.Since(start).String(), "duration_ms", time.Since(start).Milliseconds(), "cached", f.countCached(), "returned", len(metas), "partial", len(resp.partial)) @@ -555,10 +559,10 @@ func (f *IgnoreDeletionMarkFilter) Filter(ctx context.Context, metas map[ulid.UL for id := range ch { m := &DeletionMark{} if err := ReadMarker(ctx, f.logger, f.bkt, id.String(), m); err != nil { - if errors.Is(errors.Cause(err), ErrorMarkerNotFound) { + if errors.Is(err, ErrorMarkerNotFound) { continue } - if errors.Is(errors.Cause(err), ErrorUnmarshalMarker) { + if errors.Is(err, ErrorUnmarshalMarker) { level.Warn(f.logger).Log("msg", "found partial deletion-mark.json; if we will see it happening often for the same block, consider manually deleting deletion-mark.json from the object storage", "block", id, "err", err) continue } @@ -599,7 +603,7 @@ func (f *IgnoreDeletionMarkFilter) Filter(ctx context.Context, metas map[ulid.UL }) if err := eg.Wait(); err != nil { - return errors.Wrap(err, "filter blocks marked for deletion") + return fmt.Errorf("filter blocks marked for deletion: %w", err) } f.mtx.Lock() diff --git a/pkg/phlaredb/block/fetcher_test.go b/pkg/phlaredb/block/fetcher_test.go index c93d30cb9e..81df8c2433 100644 --- a/pkg/phlaredb/block/fetcher_test.go +++ b/pkg/phlaredb/block/fetcher_test.go @@ -10,18 +10,18 @@ import ( "testing" "github.com/go-kit/log" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - block_testutil "github.com/grafana/pyroscope/pkg/phlaredb/block/testutil" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + block_testutil "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) func TestMetaFetcher_Fetch_ShouldReturnDiscoveredBlocksIncludingMarkedForDeletion(t *testing.T) { diff --git a/pkg/phlaredb/block/global_markers.go b/pkg/phlaredb/block/global_markers.go index 03028e36ba..f9e2ca86c5 100644 --- a/pkg/phlaredb/block/global_markers.go +++ b/pkg/phlaredb/block/global_markers.go @@ -12,10 +12,9 @@ import ( "path/filepath" "strings" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" - "github.com/grafana/pyroscope/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore" ) const ( @@ -84,6 +83,8 @@ func ListBlockDeletionMarks(ctx context.Context, bkt objstore.BucketReader) (map return nil }) - - return discovered, errors.Wrap(err, "list block deletion marks") + if err != nil { + return nil, fmt.Errorf("list block deletion marks: %w", err) + } + return discovered, nil } diff --git a/pkg/phlaredb/block/global_markers_bucket_client.go b/pkg/phlaredb/block/global_markers_bucket_client.go index 67caf8bdcf..c4fe6218cf 100644 --- a/pkg/phlaredb/block/global_markers_bucket_client.go +++ b/pkg/phlaredb/block/global_markers_bucket_client.go @@ -12,10 +12,10 @@ import ( "path" "github.com/grafana/dskit/multierror" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" thanosobjstore "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore" ) // globalMarkersBucket is a bucket client which stores markers (eg. block deletion marks) in a per-tenant @@ -33,10 +33,10 @@ func BucketWithGlobalMarkers(b objstore.Bucket) objstore.Bucket { } // Upload implements objstore.Bucket. -func (b *globalMarkersBucket) Upload(ctx context.Context, name string, r io.Reader) error { +func (b *globalMarkersBucket) Upload(ctx context.Context, name string, r io.Reader, opts ...thanosobjstore.ObjectUploadOption) error { globalMarkPath := getGlobalMarkPathFromBlockMark(name) if globalMarkPath == "" { - return b.parent.Upload(ctx, name, r) + return b.parent.Upload(ctx, name, r, opts...) } // Read the marker. @@ -46,12 +46,12 @@ func (b *globalMarkersBucket) Upload(ctx context.Context, name string, r io.Read } // Upload it to the original location. - if err := b.parent.Upload(ctx, name, bytes.NewBuffer(body)); err != nil { + if err := b.parent.Upload(ctx, name, bytes.NewBuffer(body), opts...); err != nil { return err } // Upload it to the global markers location too. - return b.parent.Upload(ctx, globalMarkPath, bytes.NewBuffer(body)) + return b.parent.Upload(ctx, globalMarkPath, bytes.NewBuffer(body), opts...) } // Delete implements objstore.Bucket. @@ -99,6 +99,14 @@ func (b *globalMarkersBucket) Iter(ctx context.Context, dir string, f func(strin return b.parent.Iter(ctx, dir, f, options...) } +func (b *globalMarkersBucket) IterWithAttributes(ctx context.Context, dir string, f func(attrs thanosobjstore.IterObjectAttributes) error, options ...thanosobjstore.IterOption) error { + return b.parent.IterWithAttributes(ctx, dir, f, options...) +} + +func (b *globalMarkersBucket) SupportedIterOptions() []thanosobjstore.IterOptionType { + return b.parent.SupportedIterOptions() +} + // Get implements objstore.Bucket. func (b *globalMarkersBucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { return b.parent.Get(ctx, name) @@ -164,6 +172,10 @@ func (b *globalMarkersBucket) WithExpectedErrs(fn objstore.IsOpFailureExpectedFu return b } +func (b *globalMarkersBucket) Provider() thanosobjstore.ObjProvider { + return b.parent.Provider() +} + // getGlobalMarkPathFromBlockMark returns path to global mark, if name points to a block-local mark file. If name // doesn't point to a block-local mark file, returns empty string. func getGlobalMarkPathFromBlockMark(name string) string { diff --git a/pkg/phlaredb/block/global_markers_bucket_client_test.go b/pkg/phlaredb/block/global_markers_bucket_client_test.go index cdf1325c09..91839873db 100644 --- a/pkg/phlaredb/block/global_markers_bucket_client_test.go +++ b/pkg/phlaredb/block/global_markers_bucket_client_test.go @@ -14,15 +14,15 @@ import ( "testing" "github.com/go-kit/log" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" + "github.com/grafana/pyroscope/v2/pkg/objstore" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) func TestGlobalMarkersBucket_Delete_ShouldSucceedIfDeletionMarkDoesNotExistInTheBlockButExistInTheGlobalLocation(t *testing.T) { diff --git a/pkg/phlaredb/block/global_markers_test.go b/pkg/phlaredb/block/global_markers_test.go index c7a7d636e4..4e07405cda 100644 --- a/pkg/phlaredb/block/global_markers_test.go +++ b/pkg/phlaredb/block/global_markers_test.go @@ -10,11 +10,11 @@ import ( "strings" "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" ) func TestDeletionMarkFilepath(t *testing.T) { diff --git a/pkg/phlaredb/block/list.go b/pkg/phlaredb/block/list.go index 1312926c74..174540329e 100644 --- a/pkg/phlaredb/block/list.go +++ b/pkg/phlaredb/block/list.go @@ -1,21 +1,12 @@ package block import ( - "context" - "fmt" "os" - "path" "path/filepath" "sort" "time" - "github.com/go-kit/log/level" - "github.com/oklog/ulid" - "github.com/thanos-io/objstore" - "golang.org/x/sync/errgroup" - - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/util" + "github.com/oklog/ulid/v2" ) func ListBlocks(path string, ulidMinTime time.Time) (map[ulid.ULID]*Meta, error) { @@ -45,112 +36,6 @@ func ListBlocks(path string, ulidMinTime time.Time) (map[ulid.ULID]*Meta, error) return result, nil } -// IterBlockMetas iterates over all block metas in the given time range. -// It calls the given function for each block meta. -// It returns the first error returned by the function. -// It returns nil if all calls succeed. -// The function is called concurrently. -func IterBlockMetas(ctx context.Context, bkt phlareobj.Bucket, from, to time.Time, fn func(*Meta)) error { - allIDs, err := listAllBlockByPrefixes(ctx, bkt, from, to) - if err != nil { - return err - } - g, ctx := errgroup.WithContext(ctx) - g.SetLimit(128) - - // fetch all meta.json - for _, ids := range allIDs { - for _, id := range ids { - id := id - g.Go(func() error { - r, err := bkt.Get(ctx, path.Join(id, MetaFilename)) - if err != nil { - if bkt.IsObjNotFoundErr(err) { - level.Info(util.Logger).Log("msg", "skipping block as meta.json not found", "id", id) - return nil - } - return err - } - - m, err := Read(r) - if err != nil { - return err - } - fn(m) - return nil - }) - } - } - return g.Wait() -} - -func listAllBlockByPrefixes(ctx context.Context, bkt phlareobj.Bucket, from, to time.Time) ([][]string, error) { - // todo: We should cache prefixes listing per tenants. - blockPrefixes, err := blockPrefixesFromTo(from, to, 4) - if err != nil { - return nil, err - } - ids := make([][]string, len(blockPrefixes)) - g, ctx := errgroup.WithContext(ctx) - g.SetLimit(64) - - for i, prefix := range blockPrefixes { - prefix := prefix - i := i - g.Go(func() error { - level.Debug(util.Logger).Log("msg", "listing blocks", "prefix", prefix, "i", i) - prefixIds := []string{} - err := bkt.Iter(ctx, prefix, func(name string) error { - if _, ok := IsBlockDir(name); ok { - prefixIds = append(prefixIds, name) - } - return nil - }, objstore.WithoutApendingDirDelim) - if err != nil { - return err - } - ids[i] = prefixIds - return nil - }) - } - if err := g.Wait(); err != nil { - return nil, err - } - return ids, nil -} - -// orderOfSplit is the number of bytes of the ulid id used for the split. The duration of the split is: -// 0: 1114y -// 1: 34.8y -// 2: 1y -// 3: 12.4d -// 4: 9h19m -// TODO: To needs to be adapted based on the MaxBlockDuration. -func blockPrefixesFromTo(from, to time.Time, orderOfSplit uint8) (prefixes []string, err error) { - var id ulid.ULID - - if orderOfSplit > 9 { - return nil, fmt.Errorf("order of split must be between 0 and 9") - } - - byteShift := (9 - orderOfSplit) * 5 - - ms := uint64(from.UnixMilli()) >> byteShift - ms = ms << byteShift - for ms <= uint64(to.UnixMilli()) { - if err := id.SetTime(ms); err != nil { - return nil, err - } - prefixes = append(prefixes, id.String()[:orderOfSplit+1]) - - ms = ms >> byteShift - ms += 1 - ms = ms << byteShift - } - - return prefixes, nil -} - func SortBlocks(metas map[ulid.ULID]*Meta) []*Meta { var blocks []*Meta diff --git a/pkg/phlaredb/block/list_test.go b/pkg/phlaredb/block/list_test.go deleted file mode 100644 index 8f93da44d3..0000000000 --- a/pkg/phlaredb/block/list_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package block - -import ( - "bytes" - "context" - "crypto/rand" - "path" - "testing" - "time" - - "github.com/oklog/ulid" - "github.com/prometheus/common/model" - "github.com/stretchr/testify/require" - - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" -) - -func TestIterBlockMetas(t *testing.T) { - bucketClient, _ := objstore_testutil.NewFilesystemBucket(t, context.Background(), t.TempDir()) - - u := ulid.MustNew(uint64(model.Now()), rand.Reader).String() - err := bucketClient.Upload(context.Background(), path.Join(u, "index"), bytes.NewBufferString("foo")) - require.NoError(t, err) - meta := Meta{ - Version: MetaVersion3, - ULID: ulid.MustNew(ulid.Now(), rand.Reader), - } - buf := bytes.NewBuffer(nil) - _, err = meta.WriteTo(buf) - require.NoError(t, err) - - err = bucketClient.Upload(context.Background(), path.Join(meta.ULID.String(), MetaFilename), buf) - require.NoError(t, err) - found := false - err = IterBlockMetas(context.Background(), bucketClient, time.Now().Add(-24*time.Hour), time.Now().Add(24*time.Hour), func(m *Meta) { - found = true - require.Equal(t, meta.ULID, m.ULID) - }) - require.NoError(t, err) - require.True(t, found, "expected to find block meta") -} diff --git a/pkg/phlaredb/block/markers.go b/pkg/phlaredb/block/markers.go index 6c5000ed1e..7f4d8325f5 100644 --- a/pkg/phlaredb/block/markers.go +++ b/pkg/phlaredb/block/markers.go @@ -8,16 +8,17 @@ package block import ( "context" "encoding/json" + "errors" + "fmt" "io" "path" "time" "github.com/go-kit/log" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" - "github.com/grafana/pyroscope/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore" ) const ( @@ -105,26 +106,26 @@ func ReadMarker(ctx context.Context, logger log.Logger, bkt objstore.BucketReade if bkt.IsObjNotFoundErr(err) { return ErrorMarkerNotFound } - return errors.Wrapf(err, "get file: %s", markerFile) + return fmt.Errorf("get file: %s: %w", markerFile, err) } defer runutil.CloseWithLogOnErr(logger, r, "close bkt marker reader") metaContent, err := io.ReadAll(r) if err != nil { - return errors.Wrapf(err, "read file: %s", markerFile) + return fmt.Errorf("read file: %s: %w", markerFile, err) } if err := json.Unmarshal(metaContent, marker); err != nil { - return errors.Wrapf(ErrorUnmarshalMarker, "file: %s; err: %v", markerFile, err.Error()) + return fmt.Errorf("file: %s; err: %v: %w", markerFile, err.Error(), ErrorUnmarshalMarker) } switch marker.markerFilename() { case NoCompactMarkFilename: if version := marker.(*NoCompactMark).Version; version != NoCompactMarkVersion1 { - return errors.Errorf("unexpected no-compact-mark file version %d, expected %d", version, NoCompactMarkVersion1) + return fmt.Errorf("unexpected no-compact-mark file version %d, expected %d", version, NoCompactMarkVersion1) } case DeletionMarkFilename: if version := marker.(*DeletionMark).Version; version != DeletionMarkVersion1 { - return errors.Errorf("unexpected deletion-mark file version %d, expected %d", version, DeletionMarkVersion1) + return fmt.Errorf("unexpected deletion-mark file version %d, expected %d", version, DeletionMarkVersion1) } } return nil diff --git a/pkg/phlaredb/block/metadata.go b/pkg/phlaredb/block/metadata.go index 3d9add4c16..98144dbc99 100644 --- a/pkg/phlaredb/block/metadata.go +++ b/pkg/phlaredb/block/metadata.go @@ -15,8 +15,7 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/tsdb" "github.com/prometheus/prometheus/tsdb/fileutil" @@ -268,7 +267,7 @@ func MetaFromDir(dir string) (*Meta, int64, error) { case MetaVersion2: case MetaVersion3: default: - return nil, 0, errors.Errorf("unexpected meta file version %d", m.Version) + return nil, 0, fmt.Errorf("unexpected meta file version %d", m.Version) } return &m, int64(len(b)), nil @@ -368,7 +367,7 @@ func (stats MetaStats) ConvertToBlockStats() *ingestv1.BlockStats { indexBytes = f.SizeBytes } else if f.RelPath == "profiles.parquet" { profileBytes += f.SizeBytes - } else if strings.HasPrefix(f.RelPath, "symbols") { + } else if strings.HasPrefix(f.RelPath, "symbols") || filepath.Ext(f.RelPath) == ".symdb" { symbolBytes += f.SizeBytes } } @@ -392,10 +391,10 @@ func ReadMetaFromDir(dir string) (*Meta, error) { return Read(f) } -func exhaustCloseWithErrCapture(err *error, r io.ReadCloser, format string) { +func exhaustCloseWithErrCapture(err *error, r io.ReadCloser, msg string) { _, copyErr := io.Copy(io.Discard, r) - runutil.CloseWithErrCapture(err, r, format) + runutil.CloseWithErrCapture(err, r, "%s", msg) // Prepend the io.Copy error. merr := multierror.MultiError{} @@ -419,7 +418,7 @@ func Read(rc io.ReadCloser) (_ *Meta, err error) { case MetaVersion2: case MetaVersion3: default: - return nil, errors.Errorf("unexpected meta file version %d", m.Version) + return nil, fmt.Errorf("unexpected meta file version %d", m.Version) } return &m, nil diff --git a/pkg/phlaredb/block/metadata_test.go b/pkg/phlaredb/block/metadata_test.go index 91c28ebc8d..dcd2eaa21b 100644 --- a/pkg/phlaredb/block/metadata_test.go +++ b/pkg/phlaredb/block/metadata_test.go @@ -3,7 +3,7 @@ package block import ( "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/stretchr/testify/require" ) diff --git a/pkg/phlaredb/block/testutil/create_block.go b/pkg/phlaredb/block/testutil/create_block.go index 882e16fa6b..f6386bce53 100644 --- a/pkg/phlaredb/block/testutil/create_block.go +++ b/pkg/phlaredb/block/testutil/create_block.go @@ -2,17 +2,25 @@ package testutil import ( "context" + "crypto/rand" + "encoding/json" + "os" "path/filepath" "testing" "time" + "github.com/oklog/ulid/v2" + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/prometheus/common/model" "github.com/stretchr/testify/require" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) type noLimit struct{} @@ -40,7 +48,7 @@ func CreateBlock(t testing.TB, generator func() []*testhelper.ProfileBuilder) (b // ingest. for _, p := range generator() { - require.NoError(t, h.Ingest(ctx, p.Profile, p.UUID, p.Labels...)) + require.NoError(t, h.Ingest(ctx, p.Profile, p.UUID, nil, p.Labels...)) } require.NoError(t, h.Flush(ctx)) @@ -56,3 +64,56 @@ func CreateBlock(t testing.TB, generator func() []*testhelper.ProfileBuilder) (b require.NotNil(t, meta) return *meta, localDir } + +func OpenBlockFromMemory(t *testing.T, dir string, minTime, maxTime model.Time, profiles, tsdb, symbols []byte) *phlaredb.BlockQuerier { + CreateBlockFromMemory(t, dir, minTime, maxTime, profiles, tsdb, symbols) + blockBucket, err := filesystem.NewBucket(dir) + require.NoError(t, err) + blockQuerier := phlaredb.NewBlockQuerier(context.Background(), blockBucket) + + err = blockQuerier.Sync(context.Background()) + require.NoError(t, err) + + return blockQuerier +} + +func CreateBlockFromMemory(t *testing.T, dir string, minTime, maxTime model.Time, profiles, tsdb, symbols []byte) *block.Meta { + blockid, err := ulid.New(uint64(maxTime), rand.Reader) + require.NoError(t, err) + blockDir := filepath.Join(dir, blockid.String()) + err = os.MkdirAll(blockDir, 0755) + assert.NoError(t, err) + err = os.WriteFile(filepath.Join(blockDir, "profiles.parquet"), profiles, 0644) + assert.NoError(t, err) + err = os.WriteFile(filepath.Join(blockDir, "index.tsdb"), tsdb, 0644) + assert.NoError(t, err) + err = os.WriteFile(filepath.Join(blockDir, "symbols.symdb"), symbols, 0644) + assert.NoError(t, err) + + blockMeta := &block.Meta{ + ULID: blockid, + MinTime: minTime, + MaxTime: maxTime, + Files: []block.File{ + { + RelPath: "profiles.parquet", + SizeBytes: uint64(len(profiles)), + }, + { + RelPath: "index.tsdb", + SizeBytes: uint64(len(tsdb)), + }, + { + RelPath: "symbols.symdb", + SizeBytes: uint64(len(symbols)), + }, + }, + Version: block.MetaVersion3, + } + blockMetaJson, err := json.Marshal(&blockMeta) + assert.NoError(t, err) + err = os.WriteFile(filepath.Join(blockDir, block.MetaFilename), blockMetaJson, 0644) + assert.NoError(t, err) + + return blockMeta +} diff --git a/pkg/phlaredb/block/testutil/mock_block.go b/pkg/phlaredb/block/testutil/mock_block.go index 0e4c3baf17..ab62bc2f66 100644 --- a/pkg/phlaredb/block/testutil/mock_block.go +++ b/pkg/phlaredb/block/testutil/mock_block.go @@ -14,12 +14,12 @@ import ( "testing" "time" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) func MockStorageBlock(t testing.TB, bucket objstore.Bucket, userID string, minT, maxT model.Time) block.Meta { diff --git a/pkg/phlaredb/block_querier.go b/pkg/phlaredb/block_querier.go index e5d45b5e35..07499dd600 100644 --- a/pkg/phlaredb/block_querier.go +++ b/pkg/phlaredb/block_querier.go @@ -3,6 +3,7 @@ package phlaredb import ( "bytes" "context" + "errors" "fmt" "io" "math" @@ -16,36 +17,35 @@ import ( "connectrpc.com/connect" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/gogo/status" "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" + "github.com/grafana/dskit/tracing" + "github.com/oklog/ulid/v2" "github.com/parquet-go/parquet-go" - "github.com/pkg/errors" "github.com/prometheus/common/model" - "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/storage" "github.com/samber/lo" + oteltrace "go.opentelemetry.io/otel/trace" "golang.org/x/sync/errgroup" "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - parquetobj "github.com/grafana/pyroscope/pkg/objstore/parquet" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + parquetobj "github.com/grafana/pyroscope/v2/pkg/objstore/parquet" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/pprof" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -159,6 +159,23 @@ func (b *BlockQuerier) BlockMetas(ctx context.Context) (metas []*block.Meta, _ e return metas[0 : pos+1], nil } +func (b *BlockQuerier) BlockMeta(ctx context.Context, name string) (meta *block.Meta, _ error) { + path := filepath.Join(name, block.MetaFilename) + metaReader, err := b.bkt.Get(ctx, path) + if err != nil { + level.Error(b.logger).Log("msg", "error reading block meta", "block", path, "err", err) + return nil, err + } + + meta, err = block.Read(metaReader) + if err != nil { + level.Error(b.logger).Log("msg", "error parsing block meta", "block", path, "err", err) + return nil, err + } + + return meta, nil +} + // Sync gradually scans the available blocks. If there are any changes to the // last run it will Open/Close new/no longer existing ones. func (b *BlockQuerier) Sync(ctx context.Context) error { @@ -346,7 +363,7 @@ func (b *singleBlockQuerier) Meta() block.Meta { } func (b *singleBlockQuerier) ProfileTypes(ctx context.Context, req *connect.Request[ingestv1.ProfileTypesRequest]) (*connect.Response[ingestv1.ProfileTypesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "ProfileTypes Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "ProfileTypes Block") defer sp.Finish() if err := b.Open(ctx); err != nil { @@ -376,7 +393,7 @@ func (b *singleBlockQuerier) ProfileTypes(ctx context.Context, req *connect.Requ } func (b *singleBlockQuerier) LabelValues(ctx context.Context, req *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelValues Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelValues Block") defer sp.Finish() params := req.Msg @@ -444,7 +461,7 @@ func (b *singleBlockQuerier) LabelValues(ctx context.Context, req *connect.Reque } func (b *singleBlockQuerier) LabelNames(ctx context.Context, req *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelNames Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelNames Block") defer sp.Finish() params := req.Msg @@ -566,16 +583,16 @@ type Querier interface { Open(ctx context.Context) error Sort([]Profile) []Profile - MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.Tree, error) - MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spans phlaremodel.SpanSelector) (*phlaremodel.Tree, error) + MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.FunctionNameTree, error) + MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spans phlaremodel.SpanSelector) (*phlaremodel.FunctionNameTree, error) MergeByLabels(ctx context.Context, rows iter.Iterator[Profile], s *typesv1.StackTraceSelector, by ...string) ([]*typesv1.Series, error) MergePprof(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64, s *typesv1.StackTraceSelector) (*profilev1.Profile, error) Series(ctx context.Context, params *ingestv1.SeriesRequest) ([]*typesv1.Labels, error) SelectMatchingProfiles(ctx context.Context, params *ingestv1.SelectProfilesRequest) (iter.Iterator[Profile], error) - SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (*phlaremodel.Tree, error) + SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (*phlaremodel.FunctionNameTree, error) SelectMergeByLabels(ctx context.Context, params *ingestv1.SelectProfilesRequest, s *typesv1.StackTraceSelector, by ...string) ([]*typesv1.Series, error) - SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.Tree, error) + SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.FunctionNameTree, error) SelectMergePprof(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64, s *typesv1.StackTraceSelector) (*profilev1.Profile, error) ProfileTypes(context.Context, *connect.Request[ingestv1.ProfileTypesRequest]) (*connect.Response[ingestv1.ProfileTypesResponse], error) @@ -633,11 +650,11 @@ func (queriers Queriers) SelectMatchingProfiles(ctx context.Context, params *ing if err != nil { return nil, err } - return iter.NewMergeIterator(maxBlockProfile, true, iters...), nil + return phlaremodel.NewMergeIterator(maxBlockProfile, true, iters...), nil } func (queriers Queriers) LabelValues(ctx context.Context, req *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { - blockGetter := queriers.forTimeRange + blockGetter := queriers.ForTimeRange _, hasTimeRange := phlaremodel.GetTimeRange(req.Msg) if !hasTimeRange { blockGetter = func(_ context.Context, _, _ model.Time, _ *ingestv1.Hints) (Queriers, error) { @@ -652,7 +669,7 @@ func (queriers Queriers) LabelValues(ctx context.Context, req *connect.Request[t } func (queriers Queriers) LabelNames(ctx context.Context, req *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { - blockGetter := queriers.forTimeRange + blockGetter := queriers.ForTimeRange _, hasTimeRange := phlaremodel.GetTimeRange(req.Msg) if !hasTimeRange { blockGetter = func(_ context.Context, _, _ model.Time, _ *ingestv1.Hints) (Queriers, error) { @@ -667,7 +684,7 @@ func (queriers Queriers) LabelNames(ctx context.Context, req *connect.Request[ty } func (queriers Queriers) ProfileTypes(ctx context.Context, req *connect.Request[ingestv1.ProfileTypesRequest]) (*connect.Response[ingestv1.ProfileTypesResponse], error) { - blockGetter := queriers.forTimeRange + blockGetter := queriers.ForTimeRange _, hasTimeRange := phlaremodel.GetTimeRange(req.Msg) if !hasTimeRange { blockGetter = func(_ context.Context, _, _ model.Time, _ *ingestv1.Hints) (Queriers, error) { @@ -683,7 +700,7 @@ func (queriers Queriers) ProfileTypes(ctx context.Context, req *connect.Request[ func (queriers Queriers) Series(ctx context.Context, req *connect.Request[ingestv1.SeriesRequest]) (*connect.Response[ingestv1.SeriesResponse], error) { // todo: verify empty timestamp request should return all series - blockGetter := queriers.forTimeRange + blockGetter := queriers.ForTimeRange // Legacy Series queries without a range should return all series from all head blocks. if req.Msg.Start == 0 || req.Msg.End == 0 { blockGetter = func(_ context.Context, _, _ model.Time, _ *ingestv1.Hints) (Queriers, error) { @@ -698,24 +715,24 @@ func (queriers Queriers) Series(ctx context.Context, req *connect.Request[ingest } func (queriers Queriers) MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesStacktracesRequest, ingestv1.MergeProfilesStacktracesResponse]) error { - return MergeProfilesStacktraces(ctx, stream, queriers.forTimeRange) + return MergeProfilesStacktraces(ctx, stream, queriers.ForTimeRange) } func (queriers Queriers) MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesLabelsRequest, ingestv1.MergeProfilesLabelsResponse]) error { - return MergeProfilesLabels(ctx, stream, queriers.forTimeRange) + return MergeProfilesLabels(ctx, stream, queriers.ForTimeRange) } func (queriers Queriers) MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesPprofRequest, ingestv1.MergeProfilesPprofResponse]) error { - return MergeProfilesPprof(ctx, stream, queriers.forTimeRange) + return MergeProfilesPprof(ctx, stream, queriers.ForTimeRange) } func (queriers Queriers) MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeSpanProfileRequest, ingestv1.MergeSpanProfileResponse]) error { - return MergeSpanProfile(ctx, stream, queriers.forTimeRange) + return MergeSpanProfile(ctx, stream, queriers.ForTimeRange) } type BlockGetter func(ctx context.Context, start, end model.Time, hints *ingestv1.Hints) (Queriers, error) -func (queriers Queriers) forTimeRange(_ context.Context, start, end model.Time, hints *ingestv1.Hints) (Queriers, error) { +func (queriers Queriers) ForTimeRange(_ context.Context, start, end model.Time, hints *ingestv1.Hints) (Queriers, error) { skipBlock := HintsToBlockSkipper(hints) result := make(Queriers, 0, len(queriers)) @@ -785,7 +802,7 @@ func SelectMatchingProfiles(ctx context.Context, request *ingestv1.SelectProfile } func MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesStacktracesRequest, ingestv1.MergeProfilesStacktracesResponse], blockGetter BlockGetter) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeProfilesStacktraces") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeProfilesStacktraces") defer sp.Finish() r, err := stream.Receive() @@ -800,13 +817,11 @@ func MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[in return connect.NewError(connect.CodeInvalidArgument, errors.New("missing initial select request")) } request := r.Request - sp.LogFields( - otlog.String("start", model.Time(request.Start).Time().String()), - otlog.String("end", model.Time(request.End).Time().String()), - otlog.String("selector", request.LabelSelector), - otlog.String("profile_id", request.Type.ID), - otlog.Object("hints", request.Hints), - ) + sp.SetTag("start", model.Time(request.Start).Time().String()) + sp.SetTag("end", model.Time(request.End).Time().String()) + sp.SetTag("selector", request.LabelSelector) + sp.SetTag("profile_id", request.Type.ID) + sp.SetTag("hints", request.Hints) queriers, err := blockGetter(ctx, model.Time(request.Start), model.Time(request.End), request.Hints) if err != nil { @@ -819,13 +834,13 @@ func MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[in } var m sync.Mutex - t := new(phlaremodel.Tree) + t := new(phlaremodel.FunctionNameTree) g, ctx := errgroup.WithContext(ctx) // depending on if new need deduplication or not there are two different code paths. if !deduplicationNeeded { // signal the end of the profile streaming by sending an empty response. - sp.LogFields(otlog.String("msg", "no profile streaming as no deduplication needed")) + oteltrace.SpanFromContext(ctx).AddEvent("no profile streaming as no deduplication needed") if err = stream.Send(&ingestv1.MergeProfilesStacktracesResponse{}); err != nil { return err } @@ -884,7 +899,7 @@ func MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[in // Signals the end of the profile streaming by sending an empty response. // This allows the client to not block other streaming ingesters. - sp.LogFields(otlog.String("msg", "signaling the end of the profile streaming")) + oteltrace.SpanFromContext(ctx).AddEvent("signaling the end of the profile streaming") if err = stream.Send(&ingestv1.MergeProfilesStacktracesResponse{}); err != nil { return err } @@ -895,11 +910,9 @@ func MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[in } // sends the final result to the client. - treeBytes := t.Bytes(r.GetMaxNodes()) - sp.LogFields( - otlog.String("msg", "sending the final result to the client"), - otlog.Int("tree_bytes", len(treeBytes)), - ) + treeBytes := t.Bytes(r.GetMaxNodes(), nil) + oteltrace.SpanFromContext(ctx).AddEvent("sending the final result to the client") + sp.SetTag("tree_bytes", len(treeBytes)) err = stream.Send(&ingestv1.MergeProfilesStacktracesResponse{ Result: &ingestv1.MergeProfilesStacktracesResult{ Format: ingestv1.StacktracesMergeFormat_MERGE_FORMAT_TREE, @@ -917,7 +930,7 @@ func MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[in } func MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeSpanProfileRequest, ingestv1.MergeSpanProfileResponse], blockGetter BlockGetter) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeSpanProfile") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeSpanProfile") defer sp.Finish() r, err := stream.Receive() @@ -932,13 +945,11 @@ func MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.M return connect.NewError(connect.CodeInvalidArgument, errors.New("missing initial select request")) } request := r.Request - sp.LogFields( - otlog.String("start", model.Time(request.Start).Time().String()), - otlog.String("end", model.Time(request.End).Time().String()), - otlog.String("selector", request.LabelSelector), - otlog.String("profile_type_id", request.Type.ID), - otlog.Object("hints", request.Hints), - ) + sp.SetTag("start", model.Time(request.Start).Time().String()) + sp.SetTag("end", model.Time(request.End).Time().String()) + sp.SetTag("selector", request.LabelSelector) + sp.SetTag("profile_type_id", request.Type.ID) + sp.SetTag("hints", request.Hints) spanSelector, err := phlaremodel.NewSpanSelector(request.SpanSelector) if err != nil { @@ -956,13 +967,13 @@ func MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.M } var m sync.Mutex - t := new(phlaremodel.Tree) + t := new(phlaremodel.FunctionNameTree) g, ctx := errgroup.WithContext(ctx) // depending on if new need deduplication or not there are two different code paths. if !deduplicationNeeded { // signal the end of the profile streaming by sending an empty response. - sp.LogFields(otlog.String("msg", "no profile streaming as no deduplication needed")) + oteltrace.SpanFromContext(ctx).AddEvent("no profile streaming as no deduplication needed") if err = stream.Send(&ingestv1.MergeSpanProfileResponse{}); err != nil { return err } @@ -1027,7 +1038,7 @@ func MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.M // Signals the end of the profile streaming by sending an empty response. // This allows the client to not block other streaming ingesters. - sp.LogFields(otlog.String("msg", "signaling the end of the profile streaming")) + oteltrace.SpanFromContext(ctx).AddEvent("signaling the end of the profile streaming") if err = stream.Send(&ingestv1.MergeSpanProfileResponse{}); err != nil { return err } @@ -1038,11 +1049,9 @@ func MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.M } // sends the final result to the client. - treeBytes := t.Bytes(r.GetMaxNodes()) - sp.LogFields( - otlog.String("msg", "sending the final result to the client"), - otlog.Int("tree_bytes", len(treeBytes)), - ) + treeBytes := t.Bytes(r.GetMaxNodes(), nil) + oteltrace.SpanFromContext(ctx).AddEvent("sending the final result to the client") + sp.SetTag("tree_bytes", len(treeBytes)) err = stream.Send(&ingestv1.MergeSpanProfileResponse{ Result: &ingestv1.MergeSpanProfileResult{ TreeBytes: treeBytes, @@ -1059,7 +1068,7 @@ func MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.M } func MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesLabelsRequest, ingestv1.MergeProfilesLabelsResponse], blockGetter BlockGetter) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeProfilesLabels") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeProfilesLabels") defer sp.Finish() r, err := stream.Receive() @@ -1076,13 +1085,11 @@ func MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv request := r.Request by := r.By sort.Strings(by) - sp.LogFields( - otlog.String("start", model.Time(request.Start).Time().String()), - otlog.String("end", model.Time(request.End).Time().String()), - otlog.String("selector", request.LabelSelector), - otlog.String("profile_id", request.Type.ID), - otlog.String("by", strings.Join(by, ",")), - ) + sp.SetTag("start", model.Time(request.Start).Time().String()) + sp.SetTag("end", model.Time(request.End).Time().String()) + sp.SetTag("selector", request.LabelSelector) + sp.SetTag("profile_id", request.Type.ID) + sp.SetTag("by", strings.Join(by, ",")) queriers, err := blockGetter(ctx, model.Time(request.Start), model.Time(request.End), request.Hints) if err != nil { @@ -1099,7 +1106,7 @@ func MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv if !deduplicationNeeded { // signal the end of the profile streaming by sending an empty response. - sp.LogFields(otlog.String("msg", "no profile streaming as no deduplication needed")) + oteltrace.SpanFromContext(ctx).AddEvent("no profile streaming as no deduplication needed") if err = stream.Send(&ingestv1.MergeProfilesLabelsResponse{}); err != nil { return err } @@ -1168,7 +1175,7 @@ func MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv // sends the final result to the client. err = stream.Send(&ingestv1.MergeProfilesLabelsResponse{ - Series: phlaremodel.MergeSeries(request.Aggregation, result...), + Series: timeseries.MergeSeries(request.Aggregation, result...), }) if err != nil { if errors.Is(err, io.EOF) { @@ -1181,7 +1188,7 @@ func MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv } func MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesPprofRequest, ingestv1.MergeProfilesPprofResponse], blockGetter BlockGetter) error { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeProfilesPprof") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeProfilesPprof") defer sp.Finish() r, err := stream.Receive() @@ -1197,12 +1204,12 @@ func MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1 } request := r.Request - sp.SetTag("start", model.Time(request.Start).Time().String()). - SetTag("end", model.Time(request.End).Time().String()). - SetTag("selector", request.LabelSelector). - SetTag("profile_type", request.Type.ID). - SetTag("max_nodes", r.GetMaxNodes()) - sp.LogFields(otlog.Object("hints", request.Hints)) + sp.SetTag("start", model.Time(request.Start).Time().String()) + sp.SetTag("end", model.Time(request.End).Time().String()) + sp.SetTag("selector", request.LabelSelector) + sp.SetTag("profile_type", request.Type.ID) + sp.SetTag("max_nodes", r.GetMaxNodes()) + sp.SetTag("hints", request.Hints) queriers, err := blockGetter(ctx, model.Time(request.Start), model.Time(request.End), request.Hints) if err != nil { @@ -1214,14 +1221,13 @@ func MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1 deduplicationNeeded = request.Hints.Block.Deduplication } - var lock sync.Mutex var result pprof.ProfileMerge g, ctx := errgroup.WithContext(ctx) // depending on if new need deduplication or not there are two different code paths. if !deduplicationNeeded { // signal the end of the profile streaming by sending an empty response. - sp.LogFields(otlog.String("msg", "no profile streaming as no deduplication needed")) + oteltrace.SpanFromContext(ctx).AddEvent("no profile streaming as no deduplication needed") if err = stream.Send(&ingestv1.MergeProfilesPprofResponse{}); err != nil { return err } @@ -1234,10 +1240,7 @@ func MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1 if err != nil { return err } - - lock.Lock() - defer lock.Unlock() - return result.Merge(p) + return result.Merge(p, true) })) } } else { @@ -1271,15 +1274,13 @@ func MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1 if err != nil { return err } - lock.Lock() - defer lock.Unlock() - return result.Merge(p) + return result.Merge(p, true) })) } // Signals the end of the profile streaming by sending an empty response. // This allows the client to not block other streaming ingesters. - sp.LogFields(otlog.String("msg", "signaling the end of the profile streaming")) + oteltrace.SpanFromContext(ctx).AddEvent("signaling the end of the profile streaming") if err = stream.Send(&ingestv1.MergeProfilesPprofResponse{}); err != nil { return err } @@ -1289,7 +1290,7 @@ func MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1 return err } - sp.LogFields(otlog.String("msg", "building pprof bytes")) + oteltrace.SpanFromContext(ctx).AddEvent("building pprof bytes") mergedProfile := result.Profile() pprof.SetProfileMetadata(mergedProfile, request.Type, model.Time(r.Request.End).UnixNano(), 0) @@ -1299,10 +1300,8 @@ func MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1 return err } // sends the final result to the client. - sp.LogFields( - otlog.String("msg", "sending the final result to the client"), - otlog.Int("tree_bytes", len(pprofBytes)), - ) + oteltrace.SpanFromContext(ctx).AddEvent("sending the final result to the client") + sp.SetTag("tree_bytes", len(pprofBytes)) err = stream.Send(&ingestv1.MergeProfilesPprofResponse{Result: pprofBytes}) if err != nil { if errors.Is(err, io.EOF) { @@ -1514,7 +1513,7 @@ type labelsInfo struct { } func (b *singleBlockQuerier) SelectMatchingProfiles(ctx context.Context, params *ingestv1.SelectProfilesRequest) (iter.Iterator[Profile], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMatchingProfiles - Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMatchingProfiles - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) @@ -1524,7 +1523,7 @@ func (b *singleBlockQuerier) SelectMatchingProfiles(ctx context.Context, params b.queries.Add(1) defer b.queries.Done() - matchers, err := parser.ParseMetricSelector(params.LabelSelector) + matchers, err := phlaremodel.ParseMetricSelector(params.LabelSelector) if err != nil { return nil, status.Error(codes.InvalidArgument, "failed to parse label selectors: "+err.Error()) } @@ -1611,7 +1610,7 @@ func (b *singleBlockQuerier) SelectMatchingProfiles(ctx context.Context, params iters = append(iters, iter.NewSliceIterator(currentSeriesSlice)) } - return iter.NewMergeIterator(maxBlockProfile, false, iters...), nil + return phlaremodel.NewMergeIterator(maxBlockProfile, false, iters...), nil } func (b *singleBlockQuerier) SelectMergeByLabels( @@ -1620,7 +1619,7 @@ func (b *singleBlockQuerier) SelectMergeByLabels( sts *typesv1.StackTraceSelector, by ...string, ) ([]*typesv1.Series, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeByLabels - Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeByLabels - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) ctx = query.AddMetricsToContext(ctx, b.metrics.query) @@ -1631,7 +1630,7 @@ func (b *singleBlockQuerier) SelectMergeByLabels( b.queries.Add(1) defer b.queries.Done() - matchers, err := parser.ParseMetricSelector(params.LabelSelector) + matchers, err := phlaremodel.ParseMetricSelector(params.LabelSelector) if err != nil { return nil, status.Error(codes.InvalidArgument, "failed to parse label selectors: "+err.Error()) } @@ -1699,8 +1698,8 @@ func (b *singleBlockQuerier) SelectMergeByLabels( return mergeByLabelsWithStackTraceSelector[Profile](ctx, profiles.file, rows, r, by...) } -func (b *singleBlockQuerier) SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (tree *phlaremodel.Tree, err error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeByStacktraces - Block") +func (b *singleBlockQuerier) SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (tree *phlaremodel.FunctionNameTree, err error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeByStacktraces - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) ctx = query.AddMetricsToContext(ctx, b.metrics.query) @@ -1711,7 +1710,7 @@ func (b *singleBlockQuerier) SelectMergeByStacktraces(ctx context.Context, param b.queries.Add(1) defer b.queries.Done() - matchers, err := parser.ParseMetricSelector(params.LabelSelector) + matchers, err := phlaremodel.ParseMetricSelector(params.LabelSelector) if err != nil { return nil, status.Error(codes.InvalidArgument, "failed to parse label selectors: "+err.Error()) } @@ -1768,8 +1767,8 @@ func (b *singleBlockQuerier) SelectMergeByStacktraces(ctx context.Context, param return r.Tree() } -func (b *singleBlockQuerier) SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeBySpans - Block") +func (b *singleBlockQuerier) SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeBySpans - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) ctx = query.AddMetricsToContext(ctx, b.metrics.query) @@ -1780,7 +1779,7 @@ func (b *singleBlockQuerier) SelectMergeBySpans(ctx context.Context, params *ing b.queries.Add(1) defer b.queries.Done() - matchers, err := parser.ParseMetricSelector(params.LabelSelector) + matchers, err := phlaremodel.ParseMetricSelector(params.LabelSelector) if err != nil { return nil, status.Error(codes.InvalidArgument, "failed to parse label selectors: "+err.Error()) } @@ -1837,7 +1836,7 @@ func (b *singleBlockQuerier) SelectMergeBySpans(ctx context.Context, params *ing } func (b *singleBlockQuerier) SelectMergePprof(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64, sts *typesv1.StackTraceSelector) (*profilev1.Profile, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergePprof - Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergePprof - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) ctx = query.AddMetricsToContext(ctx, b.metrics.query) @@ -1848,7 +1847,7 @@ func (b *singleBlockQuerier) SelectMergePprof(ctx context.Context, params *inges b.queries.Add(1) defer b.queries.Done() - matchers, err := parser.ParseMetricSelector(params.LabelSelector) + matchers, err := phlaremodel.ParseMetricSelector(params.LabelSelector) if err != nil { return nil, status.Error(codes.InvalidArgument, "failed to parse label selectors: "+err.Error()) } @@ -1912,7 +1911,7 @@ func (b *singleBlockQuerier) SelectMergePprof(ctx context.Context, params *inges // Note: It will select ALL the labels in the block, not necessarily just the // subset in the time range SeriesRequest.Start to SeriesRequest.End. func (b *singleBlockQuerier) Series(ctx context.Context, params *ingestv1.SeriesRequest) ([]*typesv1.Labels, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "Series Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "Series Block") defer sp.Finish() if err := b.Open(ctx); err != nil { @@ -2035,7 +2034,9 @@ func (q *singleBlockQuerier) openTSDBIndex(ctx context.Context) error { if err != nil { return fmt.Errorf("opening index.tsdb file: %w", err) } - + defer func() { + _ = f.Close() + }() var buf []byte var tsdbIndexFile block.File for _, mf := range q.meta.Files { @@ -2083,12 +2084,10 @@ func (q *singleBlockQuerier) Open(ctx context.Context) error { // openFiles opens the parquet and tsdb files so they are ready for usage. func (q *singleBlockQuerier) openFiles(ctx context.Context) error { start := time.Now() - sp, ctx := opentracing.StartSpanFromContext(ctx, "BlockQuerier - open") + sp, ctx := tracing.StartSpanFromContext(ctx, "BlockQuerier - open") defer func() { q.metrics.blockOpeningLatency.Observe(time.Since(start).Seconds()) - sp.LogFields( - otlog.String("block_ulid", q.meta.ULID.String()), - ) + sp.SetTag("block_ulid", q.meta.ULID.String()) sp.Finish() }() @@ -2214,7 +2213,7 @@ func (r *parquetReader[P]) relPath() string { } func (r *parquetReader[P]) columnIter(ctx context.Context, columnName string, predicate query.Predicate, alias string) query.Iterator { - index, _ := query.GetColumnIndexByPath(r.file.File.Root(), columnName) + index, _ := query.GetColumnIndexByPath(r.file.Root(), columnName) if index == -1 { return query.NewErrIterator(fmt.Errorf("column '%s' not found in parquet file '%s'", columnName, r.relPath())) } diff --git a/pkg/phlaredb/block_querier_symbols.go b/pkg/phlaredb/block_querier_symbols.go index a1046e8b59..822e55a41f 100644 --- a/pkg/phlaredb/block_querier_symbols.go +++ b/pkg/phlaredb/block_querier_symbols.go @@ -12,14 +12,14 @@ import ( "github.com/parquet-go/parquet-go" "golang.org/x/sync/errgroup" - "github.com/grafana/pyroscope/pkg/iter" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - parquetobj "github.com/grafana/pyroscope/pkg/objstore/parquet" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + parquetobj "github.com/grafana/pyroscope/v2/pkg/objstore/parquet" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/util" ) // TODO(kolesnikovae) Decouple from phlaredb and refactor to symdb/compat. @@ -191,10 +191,10 @@ func (p *symbolsPartition) Release() { } type inMemoryParquetTables struct { - strings inMemoryparquetReader[string, *schemav1.StringPersister] - functions inMemoryparquetReader[*schemav1.InMemoryFunction, *schemav1.FunctionPersister] - locations inMemoryparquetReader[*schemav1.InMemoryLocation, *schemav1.LocationPersister] - mappings inMemoryparquetReader[*schemav1.InMemoryMapping, *schemav1.MappingPersister] + strings inMemoryparquetReader[string, schemav1.StringPersister] + functions inMemoryparquetReader[schemav1.InMemoryFunction, schemav1.FunctionPersister] + locations inMemoryparquetReader[schemav1.InMemoryLocation, schemav1.LocationPersister] + mappings inMemoryparquetReader[schemav1.InMemoryMapping, schemav1.MappingPersister] } func openInMemoryParquetTables(ctx context.Context, r phlareobj.BucketReader, meta *block.Meta) (*inMemoryParquetTables, error) { @@ -278,7 +278,7 @@ func (r *inMemoryparquetReader[M, P]) readRG(dst []M, rg parquet.RowGroup) (err n, err := rr.ReadRows(buf) if n > 0 { for _, row := range buf[:n] { - _, v, err := r.persister.Reconstruct(row) + v, err := r.persister.Reconstruct(row) if err != nil { return err } diff --git a/pkg/phlaredb/block_querier_test.go b/pkg/phlaredb/block_querier_test.go index 4ce7732152..5251c424cd 100644 --- a/pkg/phlaredb/block_querier_test.go +++ b/pkg/phlaredb/block_querier_test.go @@ -11,7 +11,7 @@ import ( "time" "connectrpc.com/connect" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -19,16 +19,17 @@ import ( "golang.org/x/sync/errgroup" ingesterv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) +const testDataPath = "./block/testdata/" + func TestQuerierBlockEviction(t *testing.T) { type testCase struct { blocks []string @@ -105,7 +106,7 @@ func (p *profileCounter) Next() bool { } func TestBlockCompatability(t *testing.T) { - path := "./block/testdata/" + path := testDataPath bucket, err := filesystem.NewBucket(path) require.NoError(t, err) @@ -127,7 +128,7 @@ func TestBlockCompatability(t *testing.T) { t.Log(profileType) profileTypeParts := strings.Split(profileType, ":") - it, err := q.SelectMatchingProfiles(ctx, &ingestv1.SelectProfilesRequest{ + it, err := q.SelectMatchingProfiles(ctx, &ingesterv1.SelectProfilesRequest{ LabelSelector: "{}", Start: 0, End: time.Now().UnixMilli(), @@ -156,7 +157,7 @@ func TestBlockCompatability(t *testing.T) { } func TestBlockCompatability_SelectMergeSpans(t *testing.T) { - path := "./block/testdata/" + path := testDataPath bucket, err := filesystem.NewBucket(path) require.NoError(t, err) @@ -178,7 +179,7 @@ func TestBlockCompatability_SelectMergeSpans(t *testing.T) { t.Log(profileType) profileTypeParts := strings.Split(profileType, ":") - it, err := q.SelectMatchingProfiles(ctx, &ingestv1.SelectProfilesRequest{ + it, err := q.SelectMatchingProfiles(ctx, &ingesterv1.SelectProfilesRequest{ LabelSelector: "{}", Start: 0, End: time.Now().UnixMilli(), @@ -217,7 +218,7 @@ func (f *fakeQuerier) BlockID() string { return "block-id" } -func (f *fakeQuerier) SelectMatchingProfiles(ctx context.Context, params *ingestv1.SelectProfilesRequest) (iter.Iterator[Profile], error) { +func (f *fakeQuerier) SelectMatchingProfiles(ctx context.Context, params *ingesterv1.SelectProfilesRequest) (iter.Iterator[Profile], error) { // add some jitter time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) if f.doErr { @@ -248,7 +249,7 @@ func openSingleBlockQuerierIndex(t *testing.T, blockID string) *singleBlockQueri func TestSelectMatchingProfilesCleanUp(t *testing.T) { defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) - _, err := SelectMatchingProfiles(context.Background(), &ingestv1.SelectProfilesRequest{}, Queriers{ + _, err := SelectMatchingProfiles(context.Background(), &ingesterv1.SelectProfilesRequest{}, Queriers{ &fakeQuerier{}, &fakeQuerier{}, &fakeQuerier{}, @@ -302,7 +303,7 @@ func Test_singleBlockQuerier_Series(t *testing.T) { {Name: "__name__", Value: "process_cpu"}, }}, } - got, err := q.Series(ctx, &ingestv1.SeriesRequest{ + got, err := q.Series(ctx, &ingesterv1.SeriesRequest{ LabelNames: []string{ "__name__", }, @@ -318,7 +319,7 @@ func Test_singleBlockQuerier_Series(t *testing.T) { {Name: "__name__", Value: "block"}, }}, } - got, err := q.Series(ctx, &ingestv1.SeriesRequest{ + got, err := q.Series(ctx, &ingesterv1.SeriesRequest{ Matchers: []string{`{__name__="block"}`}, LabelNames: []string{"__name__"}, }) @@ -370,7 +371,7 @@ func Test_singleBlockQuerier_Series(t *testing.T) { {Name: "__type__", Value: "cpu"}, }}, } - got, err := q.Series(ctx, &ingestv1.SeriesRequest{ + got, err := q.Series(ctx, &ingesterv1.SeriesRequest{ LabelNames: []string{"__name__", "__type__"}, }) @@ -385,7 +386,7 @@ func Test_singleBlockQuerier_Series(t *testing.T) { {Name: "__type__", Value: "alloc_objects"}, }}, } - got, err := q.Series(ctx, &ingestv1.SeriesRequest{ + got, err := q.Series(ctx, &ingesterv1.SeriesRequest{ Matchers: []string{`{__name__="memory",__type__="alloc_objects"}`}, LabelNames: []string{"__name__", "__type__"}, }) @@ -612,7 +613,7 @@ func Test_singleBlockQuerier_Series(t *testing.T) { {Name: "service_name", Value: "simple.golang.app"}, }}, } - got, err := q.Series(ctx, &ingestv1.SeriesRequest{ + got, err := q.Series(ctx, &ingesterv1.SeriesRequest{ Matchers: []string{}, LabelNames: []string{}, }) @@ -714,7 +715,7 @@ func Test_singleBlockQuerier_Series(t *testing.T) { {Name: "service_name", Value: "simple.golang.app"}, }}, } - got, err := q.Series(ctx, &ingestv1.SeriesRequest{ + got, err := q.Series(ctx, &ingesterv1.SeriesRequest{ Matchers: []string{}, LabelNames: []string{ "pyroscope_app", @@ -1056,7 +1057,7 @@ func Test_singleBlockQuerier_ProfileTypes(t *testing.T) { }, } - got, err := q.ProfileTypes(ctx, &connect.Request[ingestv1.ProfileTypesRequest]{}) + got, err := q.ProfileTypes(ctx, &connect.Request[ingesterv1.ProfileTypesRequest]{}) assert.NoError(t, err) assert.Equal(t, want, got.Msg.ProfileTypes) } @@ -1077,7 +1078,7 @@ func Benchmark_singleBlockQuerier_Series(b *testing.B) { b.Run("multiple labels", func(b *testing.B) { for n := 0; n < b.N; n++ { - q.Series(ctx, &ingestv1.SeriesRequest{ //nolint:errcheck + q.Series(ctx, &ingesterv1.SeriesRequest{ //nolint:errcheck Matchers: []string{`{__name__="block"}`}, LabelNames: []string{"__name__"}, }) @@ -1086,7 +1087,7 @@ func Benchmark_singleBlockQuerier_Series(b *testing.B) { b.Run("multiple labels with matcher", func(b *testing.B) { for n := 0; n < b.N; n++ { - q.Series(ctx, &ingestv1.SeriesRequest{ //nolint:errcheck + q.Series(ctx, &ingesterv1.SeriesRequest{ //nolint:errcheck Matchers: []string{`{__name__="memory",__type__="alloc_objects"}`}, LabelNames: []string{"__name__", "__type__"}, }) @@ -1095,7 +1096,7 @@ func Benchmark_singleBlockQuerier_Series(b *testing.B) { b.Run("UI request", func(b *testing.B) { for n := 0; n < b.N; n++ { - q.Series(ctx, &ingestv1.SeriesRequest{ //nolint:errcheck + q.Series(ctx, &ingesterv1.SeriesRequest{ //nolint:errcheck Matchers: []string{}, LabelNames: []string{"pyroscope_app", "service_name", "__profile_type__", "__type__", "__name__"}, }) @@ -1165,7 +1166,7 @@ func TestSelectMergeStacktraces(t *testing.T) { End: int64(model.TimeFromUnixNano(math.MaxInt64)), }, 16<<10) require.NoError(t, err) - expected := phlaremodel.Tree{} + expected := phlaremodel.FunctionNameTree{} expected.InsertStack(1000, "baz", "bar", "foo") expected.InsertStack(1000, "buzz", "bar", "foo") expected.InsertStack(1000, "bar", "foo") @@ -1285,8 +1286,9 @@ func genPoints(count int) []*typesv1.Point { points := make([]*typesv1.Point, 0, count) for i := 1; i < count+1; i++ { points = append(points, &typesv1.Point{ - Timestamp: int64(model.TimeFromUnixNano(int64(time.Second * time.Duration(i)))), - Value: 1, + Timestamp: int64(model.TimeFromUnixNano(int64(time.Second * time.Duration(i)))), + Value: 1, + Annotations: []*typesv1.ProfileAnnotation{}, }) } return points @@ -1328,7 +1330,7 @@ func testSelectMergeByStacktracesRace(t testing.TB, times int) { err := querier.Open(ctx) require.NoError(t, err) g, ctx := errgroup.WithContext(ctx) - tree := new(phlaremodel.Tree) + tree := new(phlaremodel.FunctionNameTree) var m sync.Mutex if b, ok := t.(*testing.B); ok { @@ -1386,3 +1388,22 @@ func testSelectMergeByStacktracesRace(t testing.TB, times int) { require.NoError(t, g.Wait()) require.NoError(t, querier.Close()) } + +func TestBlockMeta_loadsMetasIndividually(t *testing.T) { + path := testDataPath + bucket, err := filesystem.NewBucket(path) + require.NoError(t, err) + + ctx := context.Background() + blockQuerier := NewBlockQuerier(ctx, bucket) + metas, err := blockQuerier.BlockMetas(ctx) + require.NoError(t, err) + require.NotEmpty(t, metas) + + for _, meta := range metas { + singleMeta, err := blockQuerier.BlockMeta(ctx, meta.ULID.String()) + require.NoError(t, err) + + require.Equal(t, meta, singleMeta) + } +} diff --git a/pkg/phlaredb/bucket/tenant_deletion_mark.go b/pkg/phlaredb/bucket/tenant_deletion_mark.go index 086ac688dc..a283ca22d3 100644 --- a/pkg/phlaredb/bucket/tenant_deletion_mark.go +++ b/pkg/phlaredb/bucket/tenant_deletion_mark.go @@ -9,14 +9,14 @@ import ( "bytes" "context" "encoding/json" + "fmt" "path" "time" "github.com/go-kit/log/level" - "github.com/pkg/errors" - "github.com/grafana/pyroscope/pkg/objstore" - util_log "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/objstore" + util_log "github.com/grafana/pyroscope/v2/pkg/util" ) // Relative to user-specific prefix. @@ -47,10 +47,14 @@ func WriteTenantDeletionMark(ctx context.Context, bkt objstore.Bucket, userID st data, err := json.Marshal(mark) if err != nil { - return errors.Wrap(err, "serialize tenant deletion mark") + return fmt.Errorf("serialize tenant deletion mark: %w", err) } - return errors.Wrap(bkt.Upload(ctx, TenantDeletionMarkPath, bytes.NewReader(data)), "upload tenant deletion mark") + err = bkt.Upload(ctx, TenantDeletionMarkPath, bytes.NewReader(data)) + if err != nil { + return fmt.Errorf("upload tenant deletion mark: %w", err) + } + return nil } // Returns tenant deletion mark for given user, if it exists. If it doesn't exist, returns nil mark, and no error. @@ -63,7 +67,7 @@ func ReadTenantDeletionMark(ctx context.Context, bkt objstore.BucketReader, user return nil, nil } - return nil, errors.Wrapf(err, "failed to read deletion mark object: %s", markerFile) + return nil, fmt.Errorf("failed to read deletion mark object: %s: %w", markerFile, err) } mark := &TenantDeletionMark{} @@ -75,7 +79,7 @@ func ReadTenantDeletionMark(ctx context.Context, bkt objstore.BucketReader, user } if err != nil { - return nil, errors.Wrapf(err, "failed to decode deletion mark object: %s", markerFile) + return nil, fmt.Errorf("failed to decode deletion mark object: %s: %w", markerFile, err) } return mark, nil diff --git a/pkg/phlaredb/bucket/tenant_deletion_mark_test.go b/pkg/phlaredb/bucket/tenant_deletion_mark_test.go index f7c2cf9e4a..7dc7f0889a 100644 --- a/pkg/phlaredb/bucket/tenant_deletion_mark_test.go +++ b/pkg/phlaredb/bucket/tenant_deletion_mark_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/thanos-io/objstore" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" ) func TestTenantDeletionMarkExists(t *testing.T) { diff --git a/pkg/phlaredb/bucket/tenant_scanner.go b/pkg/phlaredb/bucket/tenant_scanner.go index 413ae466fa..77c13be41b 100644 --- a/pkg/phlaredb/bucket/tenant_scanner.go +++ b/pkg/phlaredb/bucket/tenant_scanner.go @@ -11,7 +11,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/grafana/pyroscope/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore" ) // AllTenants returns true to each call and should be used whenever the UsersScanner should not filter out diff --git a/pkg/phlaredb/bucket/tenant_scanner_test.go b/pkg/phlaredb/bucket/tenant_scanner_test.go index dac967af96..cfce7499e7 100644 --- a/pkg/phlaredb/bucket/tenant_scanner_test.go +++ b/pkg/phlaredb/bucket/tenant_scanner_test.go @@ -15,11 +15,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" ) func TestUsersScanner_ScanUsers_ShouldReturnedOwnedUsersOnly(t *testing.T) { - bucketClient := &objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1", "user-2", "user-3", "user-4"}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb/", TenantDeletionMarkPath), false, nil) bucketClient.MockExists(path.Join("user-3", "phlaredb/", TenantDeletionMarkPath), true, nil) @@ -38,7 +38,7 @@ func TestUsersScanner_ScanUsers_ShouldReturnedOwnedUsersOnly(t *testing.T) { func TestUsersScanner_ScanUsers_ShouldReturnUsersForWhichOwnerCheckOrTenantDeletionCheckFailed(t *testing.T) { expected := []string{"user-1", "user-2"} - bucketClient := &objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", expected, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb/", TenantDeletionMarkPath), false, nil) bucketClient.MockExists(path.Join("user-2", "phlaredb/", TenantDeletionMarkPath), false, errors.New("fail")) @@ -55,7 +55,7 @@ func TestUsersScanner_ScanUsers_ShouldReturnUsersForWhichOwnerCheckOrTenantDelet } func TestUsersScanner_ScanUsers_ShouldNotReturnPrefixedUsedByPyroscopeInternals(t *testing.T) { - bucketClient := &objstore.ClientMock{} + bucketClient := mockobjstore.NewMockBucketWithHelper(t) bucketClient.MockIter("", []string{"user-1", "user-2", PyroscopeInternalsPrefix}, nil) bucketClient.MockExists(path.Join("user-1", "phlaredb/", TenantDeletionMarkPath), false, nil) bucketClient.MockExists(path.Join("user-2", "phlaredb/", TenantDeletionMarkPath), false, nil) diff --git a/pkg/phlaredb/bucketindex/index.go b/pkg/phlaredb/bucketindex/index.go index 578d564791..baad7880be 100644 --- a/pkg/phlaredb/bucketindex/index.go +++ b/pkg/phlaredb/bucketindex/index.go @@ -10,12 +10,12 @@ import ( "strings" "time" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( diff --git a/pkg/phlaredb/bucketindex/index_test.go b/pkg/phlaredb/bucketindex/index_test.go index de737c80f0..0de1f836c2 100644 --- a/pkg/phlaredb/bucketindex/index_test.go +++ b/pkg/phlaredb/bucketindex/index_test.go @@ -8,12 +8,12 @@ package bucketindex import ( "testing" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) func TestIndex_RemoveBlock(t *testing.T) { diff --git a/pkg/phlaredb/bucketindex/loader.go b/pkg/phlaredb/bucketindex/loader.go index 0faa5ed00e..9a70680639 100644 --- a/pkg/phlaredb/bucketindex/loader.go +++ b/pkg/phlaredb/bucketindex/loader.go @@ -7,19 +7,19 @@ package bucketindex import ( "context" + "errors" "sync" "time" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/atomic" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/util" ) type LoaderConfig struct { @@ -68,9 +68,12 @@ func NewLoader(cfg LoaderConfig, bucketClient objstore.Bucket, cfgProvider objst Help: "Total number of bucket index loading failures.", }), loadDuration: promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_bucket_index_load_duration_seconds", - Help: "Duration of the a single bucket index loading operation in seconds.", - Buckets: []float64{0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 1, 10}, + Name: "pyroscope_bucket_index_load_duration_seconds", + Help: "Duration of the a single bucket index loading operation in seconds.", + Buckets: []float64{0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 1, 10}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), } diff --git a/pkg/phlaredb/bucketindex/loader_test.go b/pkg/phlaredb/bucketindex/loader_test.go index ea81d1f6cf..f6f318842c 100644 --- a/pkg/phlaredb/bucketindex/loader_test.go +++ b/pkg/phlaredb/bucketindex/loader_test.go @@ -16,13 +16,13 @@ import ( "github.com/go-kit/log" "github.com/grafana/dskit/services" "github.com/grafana/dskit/test" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" ) func TestLoader_GetIndex_ShouldLazyLoadBucketIndex(t *testing.T) { @@ -432,27 +432,26 @@ func TestLoader_ShouldCacheIndexNotFoundOnBackgroundUpdates(t *testing.T) { // Delete the bucket index. require.NoError(t, DeleteIndex(ctx, bkt, "user-1", nil)) - // Wait until the next index load attempt occurs. - prevLoads := testutil.ToFloat64(loader.loadAttempts) - test.Poll(t, 3*time.Second, true, func() interface{} { - return testutil.ToFloat64(loader.loadAttempts) > prevLoads - }) - // We expect the bucket index is not considered loaded because of the error. - assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` + test.Poll(t, 3*time.Second, nil, func() any { + return testutil.GatherAndCompare(reg, bytes.NewBufferString(` # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. # TYPE pyroscope_bucket_index_loaded gauge pyroscope_bucket_index_loaded 0 `), - "pyroscope_bucket_index_loaded", - )) + "pyroscope_bucket_index_loaded", + ) + }) // Try to get the index again. We expect no load attempt because the error has been cached. - prevLoads = testutil.ToFloat64(loader.loadAttempts) - actualIdx, err = loader.GetIndex(ctx, "user-1") - assert.Equal(t, ErrIndexNotFound, err) - assert.Nil(t, actualIdx) - assert.Equal(t, prevLoads, testutil.ToFloat64(loader.loadAttempts)) + test.Poll(t, 3*time.Second, true, func() any { + prevLoads := testutil.ToFloat64(loader.loadAttempts) + actualIdx, err = loader.GetIndex(ctx, "user-1") + loadAttemps := testutil.ToFloat64(loader.loadAttempts) + assert.Equal(t, ErrIndexNotFound, err) + assert.Nil(t, actualIdx) + return prevLoads == loadAttemps + }) } func TestLoader_ShouldOffloadIndexIfNotFoundDuringBackgroundUpdates(t *testing.T) { diff --git a/pkg/phlaredb/bucketindex/storage.go b/pkg/phlaredb/bucketindex/storage.go index 4e7fd480fe..8411fc2b02 100644 --- a/pkg/phlaredb/bucketindex/storage.go +++ b/pkg/phlaredb/bucketindex/storage.go @@ -10,13 +10,14 @@ import ( "compress/gzip" "context" "encoding/json" + "errors" + "fmt" "time" "github.com/go-kit/log" "github.com/grafana/dskit/runutil" - "github.com/pkg/errors" - "github.com/grafana/pyroscope/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore" ) var ( @@ -39,7 +40,7 @@ func ReadIndex(ctx context.Context, bkt objstore.Bucket, userID string, cfgProvi if userBkt.IsObjNotFoundErr(err) { return nil, ErrIndexNotFound } - return nil, errors.Wrap(err, "read bucket index") + return nil, fmt.Errorf("read bucket index: %w", err) } defer runutil.CloseWithLogOnErr(logger, reader, "close bucket index reader") @@ -67,7 +68,7 @@ func WriteIndex(ctx context.Context, bkt objstore.Bucket, userID string, cfgProv // Marshal the index. content, err := json.Marshal(idx) if err != nil { - return errors.Wrap(err, "marshal bucket index") + return fmt.Errorf("marshal bucket index: %w", err) } // Compress it. @@ -76,15 +77,15 @@ func WriteIndex(ctx context.Context, bkt objstore.Bucket, userID string, cfgProv gzip.Name = IndexFilename if _, err := gzip.Write(content); err != nil { - return errors.Wrap(err, "gzip bucket index") + return fmt.Errorf("gzip bucket index: %w", err) } if err := gzip.Close(); err != nil { - return errors.Wrap(err, "close gzip bucket index") + return fmt.Errorf("close gzip bucket index: %w", err) } // Upload the index to the storage. if err := bkt.Upload(ctx, IndexCompressedFilename, &gzipContent); err != nil { - return errors.Wrap(err, "upload bucket index") + return fmt.Errorf("upload bucket index: %w", err) } return nil @@ -97,7 +98,7 @@ func DeleteIndex(ctx context.Context, bkt objstore.Bucket, userID string, cfgPro err := bkt.Delete(ctx, IndexCompressedFilename) if err != nil && !bkt.IsObjNotFoundErr(err) { - return errors.Wrap(err, "delete bucket index") + return fmt.Errorf("delete bucket index: %w", err) } return nil } diff --git a/pkg/phlaredb/bucketindex/storage_test.go b/pkg/phlaredb/bucketindex/storage_test.go index 915cd9526b..447c732c1f 100644 --- a/pkg/phlaredb/bucketindex/storage_test.go +++ b/pkg/phlaredb/bucketindex/storage_test.go @@ -16,9 +16,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - block_testutil "github.com/grafana/pyroscope/pkg/phlaredb/block/testutil" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + block_testutil "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" ) func TestReadIndex_ShouldReturnErrorIfIndexDoesNotExist(t *testing.T) { diff --git a/pkg/phlaredb/bucketindex/updater.go b/pkg/phlaredb/bucketindex/updater.go index 6f997dbb70..a49cff7a62 100644 --- a/pkg/phlaredb/bucketindex/updater.go +++ b/pkg/phlaredb/bucketindex/updater.go @@ -8,6 +8,8 @@ package bucketindex import ( "context" "encoding/json" + "errors" + "fmt" "io" "path" "time" @@ -15,11 +17,10 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) var ( @@ -84,7 +85,7 @@ func (w *Updater) updateBlocks(ctx context.Context, old []*Block) (blocks []*Blo return nil }) if err != nil { - return nil, nil, errors.Wrap(err, "list blocks") + return nil, nil, fmt.Errorf("list blocks: %w", err) } // Since blocks are immutable, all blocks already existing in the index can just be copied. @@ -138,23 +139,23 @@ func (w *Updater) updateBlockIndexEntry(ctx context.Context, id ulid.ULID) (*Blo return nil, ErrBlockMetaNotFound } if err != nil { - return nil, errors.Wrapf(err, "get block meta file: %v", metaFile) + return nil, fmt.Errorf("get block meta file: %v: %w", metaFile, err) } defer runutil.CloseWithLogOnErr(w.logger, r, "close get block meta file") metaContent, err := io.ReadAll(r) if err != nil { - return nil, errors.Wrapf(err, "read block meta file: %v", metaFile) + return nil, fmt.Errorf("read block meta file: %v: %w", metaFile, err) } // Unmarshal it. m := block.Meta{} if err := json.Unmarshal(metaContent, &m); err != nil { - return nil, errors.Wrapf(ErrBlockMetaCorrupted, "unmarshal block meta file %s: %v", metaFile, err) + return nil, fmt.Errorf("unmarshal block meta file %s: %v: %w", metaFile, err, ErrBlockMetaCorrupted) } if !m.Version.IsValid() { - return nil, errors.Errorf("unexpected block meta version: %s version: %d", metaFile, m.Version) + return nil, fmt.Errorf("unexpected block meta version: %s version: %d", metaFile, m.Version) } block := BlockFromMeta(m) @@ -162,7 +163,7 @@ func (w *Updater) updateBlockIndexEntry(ctx context.Context, id ulid.ULID) (*Blo // Get the meta.json attributes. attrs, err := w.bkt.Attributes(ctx, metaFile) if err != nil { - return nil, errors.Wrapf(err, "read meta file attributes: %v", metaFile) + return nil, fmt.Errorf("read meta file attributes: %v: %w", metaFile, err) } // Since the meta.json file is the last file of a block being uploaded and it's immutable @@ -221,10 +222,10 @@ func (w *Updater) updateBlockDeletionMarkIndexEntry(ctx context.Context, id ulid if err := block.ReadMarker(ctx, w.logger, w.bkt, id.String(), &m); err != nil { if errors.Is(err, block.ErrorMarkerNotFound) { - return nil, errors.Wrap(ErrBlockDeletionMarkNotFound, err.Error()) + return nil, fmt.Errorf("%s: %w", err.Error(), ErrBlockDeletionMarkNotFound) } if errors.Is(err, block.ErrorUnmarshalMarker) { - return nil, errors.Wrap(ErrBlockDeletionMarkCorrupted, err.Error()) + return nil, fmt.Errorf("%s: %w", err.Error(), ErrBlockDeletionMarkCorrupted) } return nil, err } diff --git a/pkg/phlaredb/bucketindex/updater_test.go b/pkg/phlaredb/bucketindex/updater_test.go index fe1cc05f4f..9eed6e6842 100644 --- a/pkg/phlaredb/bucketindex/updater_test.go +++ b/pkg/phlaredb/bucketindex/updater_test.go @@ -8,21 +8,21 @@ package bucketindex import ( "bytes" "context" + "errors" "path" "testing" "time" "github.com/go-kit/log" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - block_testutil "github.com/grafana/pyroscope/pkg/phlaredb/block/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/objstore" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + block_testutil "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) func TestUpdater_UpdateIndex(t *testing.T) { diff --git a/pkg/phlaredb/compact.go b/pkg/phlaredb/compact.go index f34edb30bb..99b67492ba 100644 --- a/pkg/phlaredb/compact.go +++ b/pkg/phlaredb/compact.go @@ -3,6 +3,7 @@ package phlaredb import ( "context" "crypto/rand" + "errors" "fmt" "io" "io/fs" @@ -15,25 +16,23 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" + "github.com/grafana/dskit/tracing" + "github.com/oklog/ulid/v2" "github.com/parquet-go/parquet-go" - "github.com/pkg/errors" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/storage" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - phlareparquet "github.com/grafana/pyroscope/pkg/parquet" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/downsample" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/loser" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/downsample" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/loser" ) type BlockReader interface { @@ -100,7 +99,7 @@ func CompactWithSplitting(ctx context.Context, opts CompactWithSplittingOpts) ( srcMetas[i] = b.Meta() } - symbolsCompactor := newSymbolsCompactor(opts.Dst) + symbolsCompactor := newSymbolsCompactor(opts.Dst, symdb.FormatV2) defer runutil.CloseWithLogOnErr(util.Logger, symbolsCompactor, "close symbols compactor") outMeta := compactMetas(srcMetas...) @@ -119,10 +118,12 @@ func CompactWithSplitting(ctx context.Context, opts CompactWithSplittingOpts) ( } } var metas []block.Meta - sp, ctx := opentracing.StartSpanFromContext(ctx, "compact.Stage", opentracing.Tag{Key: "stage", Value: stage}) + sp, ctx := tracing.StartSpanFromContext(ctx, "compact.Stage") + sp.SetTag("stage", stage) if metas, err = compact(ctx, writers, opts.Src, opts.SplitBy, opts.SplitCount); err != nil { + sp.LogError(err) + sp.SetError() sp.Finish() - ext.LogError(sp, err) return nil, err } sp.Finish() @@ -187,7 +188,7 @@ func compact(ctx context.Context, writers []*blockWriter, readers []BlockReader, if err = rowsIt.Err(); err != nil { return nil, err } - sp, ctx := opentracing.StartSpanFromContext(ctx, "compact.Close") + sp, ctx := tracing.StartSpanFromContext(ctx, "compact.Close") defer sp.Finish() // Close all blocks @@ -359,7 +360,7 @@ func newProfileWriter(path string) (*profilesWriter, error) { func (p *profilesWriter) WriteRow(r profileRow) error { p.buf[0] = parquet.Row(r.row) - _, err := p.GenericWriter.WriteRows(p.buf) + _, err := p.WriteRows(p.buf) if err != nil { return err } @@ -713,7 +714,7 @@ func (it *dedupeProfileRowIterator) Next() bool { if !it.Iterator.Next() { return false } - currentProfile := it.Iterator.At() + currentProfile := it.At() if it.prevFP == currentProfile.fp && it.prevTimeNanos == currentProfile.timeNanos { // skip duplicate profile continue @@ -725,6 +726,7 @@ func (it *dedupeProfileRowIterator) Next() bool { } type symbolsCompactor struct { + version symdb.FormatVersion rewriters map[BlockReader]*symdb.Rewriter w *symdb.SymDB stacktraces []uint32 @@ -733,14 +735,23 @@ type symbolsCompactor struct { flushed bool } -func newSymbolsCompactor(path string) *symbolsCompactor { +func newSymbolsCompactor(path string, version symdb.FormatVersion) *symbolsCompactor { + if version == symdb.FormatV3 { + return &symbolsCompactor{ + version: version, + w: symdb.NewSymDB(symdb.DefaultConfig(). + WithVersion(symdb.FormatV3). + WithDirectory(path)), + dst: path, + rewriters: make(map[BlockReader]*symdb.Rewriter), + } + } dst := filepath.Join(path, symdb.DefaultDirName) return &symbolsCompactor{ + version: symdb.FormatV2, w: symdb.NewSymDB(symdb.DefaultConfig(). - WithDirectory(dst). - WithParquetConfig(symdb.ParquetConfig{ - MaxBufferRowCount: defaultParquetConfig.MaxBufferRowCount, - })), + WithVersion(symdb.FormatV2). + WithDirectory(dst)), dst: dst, rewriters: make(map[BlockReader]*symdb.Rewriter), } @@ -769,10 +780,16 @@ func (s *symbolsRewriter) ReWriteRow(profile profileRow) error { } func (s *symbolsRewriter) Close() (uint64, error) { - if err := s.symbolsCompactor.Flush(); err != nil { + if err := s.Flush(); err != nil { return 0, err } - return s.numSamples, util.CopyDir(s.symbolsCompactor.dst, filepath.Join(s.dst, symdb.DefaultDirName)) + if s.version == symdb.FormatV3 { + dst := filepath.Join(s.dst, symdb.DefaultFileName) + src := filepath.Join(s.symbolsCompactor.dst, symdb.DefaultFileName) + return s.numSamples, util.CopyFile(src, dst) + } else { + return s.numSamples, util.CopyDir(s.symbolsCompactor.dst, filepath.Join(s.dst, symdb.DefaultDirName)) + } } func (s *symbolsCompactor) ReWriteRow(profile profileRow) (uint64, error) { @@ -784,7 +801,7 @@ func (s *symbolsCompactor) ReWriteRow(profile profileRow) (uint64, error) { s.loadStacktracesID(values) r, ok := s.rewriters[profile.blockReader] if !ok { - r = symdb.NewRewriter(s.w, profile.blockReader.Symbols()) + r = symdb.NewRewriter(s.w, profile.blockReader.Symbols(), nil) s.rewriters[profile.blockReader] = r } if err = r.Rewrite(profile.row.StacktracePartitionID(), s.stacktraces); err != nil { @@ -814,6 +831,9 @@ func (s *symbolsCompactor) Flush() error { } func (s *symbolsCompactor) Close() error { + if s.version == symdb.FormatV3 { + return os.RemoveAll(filepath.Join(s.dst, symdb.DefaultFileName)) + } return os.RemoveAll(s.dst) } diff --git a/pkg/phlaredb/compact_test.go b/pkg/phlaredb/compact_test.go index e2b5f0ad4e..cbc381ca11 100644 --- a/pkg/phlaredb/compact_test.go +++ b/pkg/phlaredb/compact_test.go @@ -11,7 +11,7 @@ import ( "time" "github.com/go-kit/log" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/parquet-go/parquet-go" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/storage" @@ -21,15 +21,15 @@ import ( ingesterv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) func TestCompact(t *testing.T) { @@ -45,7 +45,9 @@ func TestCompact(t *testing.T) { CPUProfile(). WithLabels( "job", "b", - ).ForStacktraceString("foo", "bar", "baz").AddSamples(1), + ). + WithAnnotations("test annotation"). + ForStacktraceString("foo", "bar", "baz").AddSamples(1), testhelper.NewProfileBuilder(int64(time.Second*3)). CPUProfile(). WithLabels( @@ -74,9 +76,22 @@ func TestCompact(t *testing.T) { series, err := querier.MergeByLabels(ctx, it, nil, "job") require.NoError(t, err) require.Equal(t, []*typesv1.Series{ - {Labels: phlaremodel.LabelsFromStrings("job", "a"), Points: []*typesv1.Point{{Value: float64(1), Timestamp: int64(1000)}}}, - {Labels: phlaremodel.LabelsFromStrings("job", "b"), Points: []*typesv1.Point{{Value: float64(1), Timestamp: int64(2000)}}}, - {Labels: phlaremodel.LabelsFromStrings("job", "c"), Points: []*typesv1.Point{{Value: float64(1), Timestamp: int64(3000)}}}, + { + Labels: phlaremodel.LabelsFromStrings("job", "a"), + Points: []*typesv1.Point{{Value: float64(1), Timestamp: int64(1000), Annotations: []*typesv1.ProfileAnnotation{}}}, + }, + { + Labels: phlaremodel.LabelsFromStrings("job", "b"), + Points: []*typesv1.Point{ + {Value: float64(1), Timestamp: int64(2000), Annotations: []*typesv1.ProfileAnnotation{ + {Key: "throttled", Value: "test annotation"}, + }}, + }, + }, + { + Labels: phlaremodel.LabelsFromStrings("job", "c"), + Points: []*typesv1.Point{{Value: float64(1), Timestamp: int64(3000), Annotations: []*typesv1.ProfileAnnotation{}}}, + }, }, series) it, err = querier.SelectMatchingProfiles(ctx, matchAll) @@ -85,7 +100,7 @@ func TestCompact(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - expected := new(phlaremodel.Tree) + expected := new(phlaremodel.FunctionNameTree) expected.InsertStack(3, "baz", "bar", "foo") require.Equal(t, expected.String(), res.String()) } @@ -103,7 +118,8 @@ func TestCompactWithDownsampling(t *testing.T) { CPUProfile(). WithLabels( "job", "b", - ).ForStacktraceString("foo", "bar", "baz").AddSamples(1), + ).WithAnnotations("test annotation"). + ForStacktraceString("foo", "bar", "baz").AddSamples(1), testhelper.NewProfileBuilder(int64(time.Hour+6*time.Minute)). CPUProfile(). WithLabels( @@ -141,9 +157,18 @@ func TestCompactWithDownsampling(t *testing.T) { series, err := querier.MergeByLabels(ctx, it, nil, "job") require.NoError(t, err) require.Equal(t, []*typesv1.Series{ - {Labels: phlaremodel.LabelsFromStrings("job", "a"), Points: []*typesv1.Point{{Value: float64(1), Timestamp: (time.Hour - time.Minute).Milliseconds()}}}, - {Labels: phlaremodel.LabelsFromStrings("job", "b"), Points: []*typesv1.Point{{Value: float64(1), Timestamp: (time.Hour + time.Minute).Milliseconds()}}}, - {Labels: phlaremodel.LabelsFromStrings("job", "c"), Points: []*typesv1.Point{{Value: float64(1), Timestamp: (time.Hour + 6*time.Minute).Milliseconds()}}}, + { + Labels: phlaremodel.LabelsFromStrings("job", "a"), + Points: []*typesv1.Point{{Value: float64(1), Timestamp: (time.Hour - time.Minute).Milliseconds(), Annotations: []*typesv1.ProfileAnnotation{}}}, + }, + { + Labels: phlaremodel.LabelsFromStrings("job", "b"), + Points: []*typesv1.Point{{Value: float64(1), Timestamp: (time.Hour + time.Minute).Milliseconds(), Annotations: []*typesv1.ProfileAnnotation{{Key: "throttled", Value: "test annotation"}}}}, + }, + { + Labels: phlaremodel.LabelsFromStrings("job", "c"), + Points: []*typesv1.Point{{Value: float64(1), Timestamp: (time.Hour + 6*time.Minute).Milliseconds(), Annotations: []*typesv1.ProfileAnnotation{}}}, + }, }, series) it, err = querier.SelectMatchingProfiles(ctx, matchAll) @@ -152,7 +177,7 @@ func TestCompactWithDownsampling(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - expected := new(phlaremodel.Tree) + expected := new(phlaremodel.FunctionNameTree) expected.InsertStack(3, "baz", "bar", "foo") require.Equal(t, expected.String(), res.String()) @@ -284,7 +309,7 @@ func TestCompactWithSplitting(t *testing.T) { res, err := queriers[1].MergeByStacktraces(ctx, it, 0) require.NoError(t, err) - expected := new(phlaremodel.Tree) + expected := new(phlaremodel.FunctionNameTree) expected.InsertStack(10, "baz", "bar", "foo") require.Equal(t, expected.String(), res.String()) } @@ -308,7 +333,7 @@ func generatePoints(t *testing.T, from, through model.Time) []*typesv1.Point { t.Helper() var points []*typesv1.Point for ts := from; ts.Before(through) || ts.Equal(through); ts = ts.Add(time.Second) { - points = append(points, &typesv1.Point{Timestamp: int64(ts), Value: 1}) + points = append(points, &typesv1.Point{Timestamp: int64(ts), Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}) } return points } @@ -654,7 +679,7 @@ func newBlock(t testing.TB, generator func() []*testhelper.ProfileBuilder) *sing // ingest. for _, p := range generator() { - require.NoError(t, h.Ingest(ctx, p.Profile, p.UUID, p.Labels...)) + require.NoError(t, h.Ingest(ctx, p.Profile, p.UUID, p.Annotations, p.Labels...)) } require.NoError(t, h.Flush(ctx)) @@ -667,7 +692,7 @@ func newBlock(t testing.TB, generator func() []*testhelper.ProfileBuilder) *sing Directory: dir, }, }, - StoragePrefix: "local", + Prefix: "local", }, "test") require.NoError(t, err) metaMap, err := block.ListBlocks(filepath.Join(dir, PathLocal), time.Time{}) @@ -692,12 +717,11 @@ func blockQuerierFromMeta(t *testing.T, dir string, m block.Meta) *singleBlockQu Directory: dir, }, }, - StoragePrefix: "", + Prefix: "", }, "test") require.NoError(t, err) blk := NewSingleBlockQuerierFromMeta(ctx, bkt, &m) require.NoError(t, blk.Open(ctx)) - // require.NoError(t, blk.symbols.Load(ctx)) return blk } @@ -895,7 +919,7 @@ func Benchmark_CompactSplit(b *testing.B) { Directory: "./testdata/", }, }, - StoragePrefix: "", + Prefix: "", }, "test") require.NoError(b, err) meta, err := block.ReadMetaFromDir("./testdata/01HHYG6245NWHZWVP27V8WJRT7") diff --git a/pkg/phlaredb/delta.go b/pkg/phlaredb/delta.go index d155f8b7d0..57f99a6f75 100644 --- a/pkg/phlaredb/delta.go +++ b/pkg/phlaredb/delta.go @@ -5,8 +5,8 @@ import ( "github.com/prometheus/common/model" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) const ( @@ -57,7 +57,7 @@ func (d *deltaProfiles) computeDelta(ps schemav1.InMemoryProfile) schemav1.Sampl // samples are sorted by stacktrace id. // we need to compute the delta for each stacktrace. if len(lastSamples) == 0 { - return ps.Samples.Compact(false) + return ps.Samples.Compact() } reset := deltaSamples(lastSamples, ps.Samples) @@ -68,7 +68,7 @@ func (d *deltaProfiles) computeDelta(ps schemav1.InMemoryProfile) schemav1.Sampl return schemav1.Samples{} } - return ps.Samples.Compact(false).Clone() + return ps.Samples.Compact().Clone() } func isDeltaSupported(lbs phlaremodel.Labels) bool { diff --git a/pkg/phlaredb/delta_test.go b/pkg/phlaredb/delta_test.go index 65b461f293..6f722c34de 100644 --- a/pkg/phlaredb/delta_test.go +++ b/pkg/phlaredb/delta_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - schemav1testhelper "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1/testhelper" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + schemav1testhelper "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1/testhelper" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) func TestComputeDelta(t *testing.T) { @@ -16,7 +16,7 @@ func TestComputeDelta(t *testing.T) { builder.ForStacktraceString("a", "b", "c").AddSamples(1, 2, 3, 4) builder.ForStacktraceString("a", "b", "c", "d").AddSamples(1, 2, 3, 4) - profiles, _ := schemav1testhelper.NewProfileSchema(builder.Profile, "memory") + profiles, _ := schemav1testhelper.NewProfileSchema(builder, "memory") samples := delta.computeDelta(profiles[0]) require.Empty(t, samples.StacktraceIDs) @@ -27,7 +27,7 @@ func TestComputeDelta(t *testing.T) { builder.ForStacktraceString("a", "b", "c").AddSamples(2, 4, 3, 4) builder.ForStacktraceString("a", "b", "c", "d").AddSamples(2, 4, 3, 4) - profiles, _ = schemav1testhelper.NewProfileSchema(builder.Profile, "memory") + profiles, _ = schemav1testhelper.NewProfileSchema(builder, "memory") samples = delta.computeDelta(profiles[0]) require.NotEmpty(t, samples.StacktraceIDs) samples = delta.computeDelta(profiles[1]) diff --git a/pkg/phlaredb/downsample/downsample.go b/pkg/phlaredb/downsample/downsample.go index 88a4d2bfae..76f7798967 100644 --- a/pkg/phlaredb/downsample/downsample.go +++ b/pkg/phlaredb/downsample/downsample.go @@ -5,6 +5,7 @@ import ( "io" "os" "path/filepath" + "time" "github.com/dolthub/swiss" "github.com/go-kit/log" @@ -14,9 +15,9 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/common/model" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/util/build" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/util/build" ) type interval struct { @@ -33,10 +34,12 @@ type state struct { currentRow parquet.Row currentTime int64 currentFp model.Fingerprint + currentPartition uint64 totalValue int64 profileCount int64 stackTraceIds []uint64 values []int64 + annotations schemav1.Annotations stackTraceIdToIndex *swiss.Map[uint64, int] } @@ -67,15 +70,21 @@ var ( configs = initConfigs() inputSamplesHistogram = promauto.NewHistogram( prometheus.HistogramOpts{ - Name: "pyroscope_downsampler_input_profile_samples", - Help: "The number of samples per profile before downsampling", - Buckets: prometheus.ExponentialBuckets(32, 2, 15), + Name: "pyroscope_downsampler_input_profile_samples", + Help: "The number of samples per profile before downsampling", + Buckets: prometheus.ExponentialBuckets(32, 2, 15), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }) outputSamplesHistogram = promauto.NewHistogramVec( prometheus.HistogramOpts{ - Name: "pyroscope_downsampler_output_profile_samples", - Help: "The number of samples per profile after downsampling", - Buckets: prometheus.ExponentialBuckets(32, 2, 15), + Name: "pyroscope_downsampler_output_profile_samples", + Help: "The number of samples per profile after downsampling", + Buckets: prometheus.ExponentialBuckets(32, 2, 15), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"interval"}) ) @@ -101,7 +110,7 @@ type profilesWriter struct { func (p *profilesWriter) WriteRow(r parquet.Row) error { p.buf[0] = r - _, err := p.GenericWriter.WriteRows(p.buf) + _, err := p.WriteRows(p.buf) if err != nil { return err } @@ -194,6 +203,32 @@ func (d *Downsampler) flush(s *state, w *profilesWriter, c downsampleConfig) err s.currentRow = append(s.currentRow, parquet.Int64Value(s.currentTime*1000*1000*1000).Level(0, 0, newCol())) + newCol() + if len(s.annotations.Keys) == 0 { + s.currentRow = append(s.currentRow, parquet.Value{}.Level(0, 0, col)) + } else { + repetition = -1 + for _, key := range s.annotations.Keys { + if repetition < 1 { + repetition++ + } + s.currentRow = append(s.currentRow, parquet.ByteArrayValue([]byte(key)).Level(repetition, 1, col)) + } + } + + newCol() + if len(s.annotations.Values) == 0 { + s.currentRow = append(s.currentRow, parquet.Value{}.Level(0, 0, col)) + } else { + repetition = -1 + for _, value := range s.annotations.Values { + if repetition < 1 { + repetition++ + } + s.currentRow = append(s.currentRow, parquet.ByteArrayValue([]byte(value)).Level(repetition, 1, col)) + } + } + err := w.WriteRow(s.currentRow) if err != nil { return err @@ -208,14 +243,14 @@ func (d *Downsampler) AddRow(row schemav1.ProfileRow, fp model.Fingerprint) erro s := d.states[i] aggregationTime := rowTimeSeconds / c.interval.durationSeconds * c.interval.durationSeconds if len(d.states[i].currentRow) == 0 { - d.initStateFromRow(s, row, aggregationTime, fp) + s.init(row, aggregationTime, fp) } - if s.currentTime != aggregationTime || s.currentFp != fp { + if !s.matches(aggregationTime, fp, row.StacktracePartitionID()) { err := d.flush(s, d.profileWriters[i], c) if err != nil { return err } - d.initStateFromRow(s, row, aggregationTime, fp) + s.init(row, aggregationTime, fp) } s.profileCount++ row.ForStacktraceIdsAndValues(func(stacktraceIds []parquet.Value, values []parquet.Value) { @@ -234,6 +269,14 @@ func (d *Downsampler) AddRow(row schemav1.ProfileRow, fp model.Fingerprint) erro } sourceSampleCount = len(values) }) + row.ForAnnotations(func(keys []parquet.Value, values []parquet.Value) { + for i := 0; i < len(keys); i++ { + key := keys[i].String() + value := values[i].String() + s.annotations.Keys = append(s.annotations.Keys, key) + s.annotations.Values = append(s.annotations.Values, value) + } + }) } inputSamplesHistogram.Observe(float64(sourceSampleCount)) return nil @@ -255,9 +298,10 @@ func (d *Downsampler) Close() error { return nil } -func (d *Downsampler) initStateFromRow(s *state, row schemav1.ProfileRow, aggregationTime int64, fp model.Fingerprint) { +func (s *state) init(row schemav1.ProfileRow, aggregationTime int64, fp model.Fingerprint) { s.currentTime = aggregationTime s.currentFp = fp + s.currentPartition = row.StacktracePartitionID() s.totalValue = 0 s.profileCount = 0 if s.values == nil { @@ -275,6 +319,13 @@ func (d *Downsampler) initStateFromRow(s *state, row schemav1.ProfileRow, aggreg } else { s.stackTraceIdToIndex.Clear() } + if s.annotations.Keys == nil { + s.annotations.Keys = make([]string, 0) + s.annotations.Values = make([]string, 0) + } else { + s.annotations.Keys = s.annotations.Keys[:0] + s.annotations.Values = s.annotations.Values[:0] + } var ( col = -1 newCol = func() int { @@ -290,3 +341,7 @@ func (d *Downsampler) initStateFromRow(s *state, row schemav1.ProfileRow, aggreg s.currentRow = append(s.currentRow, parquet.Int32Value(int32(row.SeriesIndex())).Level(0, 0, newCol())) s.currentRow = append(s.currentRow, parquet.Int64Value(int64(row.StacktracePartitionID())).Level(0, 0, newCol())) } + +func (s *state) matches(t int64, fp model.Fingerprint, sp uint64) bool { + return s.currentTime == t && s.currentFp == fp && s.currentPartition == sp +} diff --git a/pkg/phlaredb/downsample/downsample_test.go b/pkg/phlaredb/downsample/downsample_test.go index 3a7e725c54..da2432d5ae 100644 --- a/pkg/phlaredb/downsample/downsample_test.go +++ b/pkg/phlaredb/downsample/downsample_test.go @@ -1,6 +1,7 @@ package downsample import ( + "io" "os" "path/filepath" "testing" @@ -8,12 +9,13 @@ import ( "github.com/go-kit/log" "github.com/parquet-go/parquet-go" "github.com/prometheus/common/model" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - phlareparquet "github.com/grafana/pyroscope/pkg/parquet" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - schemav1testhelper "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1/testhelper" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + schemav1testhelper "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1/testhelper" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) func TestDownsampler_ProfileCounts(t *testing.T) { @@ -39,8 +41,8 @@ func TestDownsampler_ProfileCounts(t *testing.T) { err = d.Close() require.NoError(t, err) - verifyProfileCount(t, outDir, "profiles_5m_sum.parquet", 1867) - verifyProfileCount(t, outDir, "profiles_1h_sum.parquet", 1) + verifyProfileCount(t, outDir, "profiles_5m_sum.parquet", 1869) + verifyProfileCount(t, outDir, "profiles_1h_sum.parquet", 50) } func TestDownsampler_Aggregation(t *testing.T) { @@ -48,26 +50,28 @@ func TestDownsampler_Aggregation(t *testing.T) { builder := testhelper.NewProfileBuilder(1703853310000000000).CPUProfile() // 2023-12-29T12:35:10Z builder.ForStacktraceString("a", "b", "c").AddSamples(30) builder.ForStacktraceString("a", "b", "c", "d").AddSamples(20) - batch, _ := schemav1testhelper.NewProfileSchema(builder.Profile, "cpu") + builder.WithAnnotations("test annotation 1") + batch, _ := schemav1testhelper.NewProfileSchema(builder, "cpu") profiles = append(profiles, batch...) builder = testhelper.NewProfileBuilder(1703853559000000000).CPUProfile() // 2023-12-29T12:39:19Z builder.ForStacktraceString("a", "b", "c").AddSamples(40) builder.ForStacktraceString("a", "b", "c", "d").AddSamples(30) builder.ForStacktraceString("a", "b", "c", "d", "e").AddSamples(20) - batch, _ = schemav1testhelper.NewProfileSchema(builder.Profile, "cpu") + batch, _ = schemav1testhelper.NewProfileSchema(builder, "cpu") profiles = append(profiles, batch...) builder = testhelper.NewProfileBuilder(1703854209000000000).CPUProfile() // 2023-12-29T12:50:09Z builder.ForStacktraceString("a", "b", "c").AddSamples(40) builder.ForStacktraceString("a", "b", "c", "d").AddSamples(30) - batch, _ = schemav1testhelper.NewProfileSchema(builder.Profile, "cpu") + batch, _ = schemav1testhelper.NewProfileSchema(builder, "cpu") profiles = append(profiles, batch...) builder = testhelper.NewProfileBuilder(1703858409000000000).CPUProfile() // 2023-12-29T14:00:09Z builder.ForStacktraceString("a", "b", "c").AddSamples(30) builder.ForStacktraceString("a", "b", "c", "d").AddSamples(20) - batch, _ = schemav1testhelper.NewProfileSchema(builder.Profile, "cpu") + builder.WithAnnotations("test annotation 2") + batch, _ = schemav1testhelper.NewProfileSchema(builder, "cpu") profiles = append(profiles, batch...) reader := schemav1.NewInMemoryProfilesRowReader(profiles) @@ -95,6 +99,13 @@ func TestDownsampler_Aggregation(t *testing.T) { require.Equal(t, int64(20), values[2].Int64()) // a, b, c, d, e }) + annotations := make([]string, 0) + schemav1.DownsampledProfileRow(downsampledRows[0]).ForAnnotationValues(func(values []parquet.Value) { + annotations = append(annotations, values[0].String()) + }) + require.Equal(t, 1, len(annotations)) + require.Equal(t, "test annotation 1", annotations[0]) + downsampledRows = readDownsampledRows(t, filepath.Join(outDir, "profiles_1h_sum.parquet"), 2) schemav1.DownsampledProfileRow(downsampledRows[0]).ForValues(func(values []parquet.Value) { @@ -103,6 +114,17 @@ func TestDownsampler_Aggregation(t *testing.T) { require.Equal(t, int64(80), values[1].Int64()) // a, b, c, d require.Equal(t, int64(20), values[2].Int64()) // a, b, c, d, e }) + + annotations = make([]string, 0) + schemav1.DownsampledProfileRow(downsampledRows[0]).ForAnnotationValues(func(values []parquet.Value) { + annotations = append(annotations, values[0].String()) + }) + schemav1.DownsampledProfileRow(downsampledRows[1]).ForAnnotationValues(func(values []parquet.Value) { + annotations = append(annotations, values[0].String()) + }) + require.Equal(t, 2, len(annotations)) + require.Equal(t, "test annotation 1", annotations[0]) + require.Equal(t, "test annotation 2", annotations[1]) } func TestDownsampler_VaryingFingerprints(t *testing.T) { @@ -110,7 +132,7 @@ func TestDownsampler_VaryingFingerprints(t *testing.T) { for i := 0; i < 5; i++ { builder := testhelper.NewProfileBuilder(1703853310000000000).CPUProfile() // 2023-12-29T12:35:10Z builder.ForStacktraceString("a", "b", "c").AddSamples(30) - batch, _ := schemav1testhelper.NewProfileSchema(builder.Profile, "cpu") + batch, _ := schemav1testhelper.NewProfileSchema(builder, "cpu") profiles = append(profiles, batch...) } @@ -134,6 +156,53 @@ func TestDownsampler_VaryingFingerprints(t *testing.T) { verifyProfileCount(t, outDir, "profiles_1h_sum.parquet", 5) } +func TestDownsampler_VaryingPartition(t *testing.T) { + profiles := make([]schemav1.InMemoryProfile, 0) + builder := testhelper.NewProfileBuilder(1703853310000000000).CPUProfile() + builder.ForStacktraceString("a", "b", "c").AddSamples(30) + builder.ForStacktraceString("a", "b", "c", "d").AddSamples(20) + batch, _ := schemav1testhelper.NewProfileSchema(builder, "cpu") + profiles = append(profiles, batch...) + + builder = testhelper.NewProfileBuilder(1703853311000000000).CPUProfile() + builder.ForStacktraceString("a", "b", "c").AddSamples(30) + builder.ForStacktraceString("a", "b", "c", "d").AddSamples(20) + batch, _ = schemav1testhelper.NewProfileSchema(builder, "cpu") + profiles = append(profiles, batch...) + + reader := schemav1.NewInMemoryProfilesRowReader(profiles) + rows, err := phlareparquet.ReadAllWithBufferSize(reader, 5) + require.NoError(t, err) + + outDir := t.TempDir() + d, err := NewDownsampler(outDir, log.NewNopLogger()) + require.NoError(t, err) + + for i, row := range rows { + r := schemav1.ProfileRow(row) + r.SetStacktracePartitionID(uint64(i)) + err = d.AddRow(r, 1) + require.NoError(t, err) + } + + err = d.Close() + require.NoError(t, err) + + downsampledRows := readDownsampledRows(t, filepath.Join(outDir, "profiles_5m_sum.parquet"), 2) + schemav1.DownsampledProfileRow(downsampledRows[0]).ForValues(func(values []parquet.Value) { + assert.Equal(t, 2, len(values)) + assert.Equal(t, int64(30), values[0].Int64()) // a, b, c + assert.Equal(t, int64(20), values[1].Int64()) // a, b, c, d + }) + + downsampledRows = readDownsampledRows(t, filepath.Join(outDir, "profiles_1h_sum.parquet"), 2) + schemav1.DownsampledProfileRow(downsampledRows[0]).ForValues(func(values []parquet.Value) { + assert.Equal(t, 2, len(values)) + assert.Equal(t, int64(30), values[0].Int64()) // a, b, c + assert.Equal(t, int64(20), values[1].Int64()) // a, b, c, d + }) +} + func BenchmarkDownsampler_AddRow(b *testing.B) { f, err := os.Open("../testdata/01HHYG6245NWHZWVP27V8WJRT7/profiles.parquet") require.NoError(b, err) @@ -195,9 +264,9 @@ func readDownsampledRows(t *testing.T, path string, expectedRowCount int) []parq require.NoError(t, err) reader := parquet.NewReader(pf, schemav1.DownsampledProfilesSchema) - downsampledRows := make([]parquet.Row, 1000) + downsampledRows := make([]parquet.Row, reader.NumRows()) rowCount, err := reader.ReadRows(downsampledRows) - require.NoError(t, err) + require.ErrorIs(t, err, io.EOF) require.Equal(t, expectedRowCount, rowCount) return downsampledRows diff --git a/pkg/phlaredb/filter_profiles_bidi.go b/pkg/phlaredb/filter_profiles_bidi.go index 7cdf6dc131..73914ca865 100644 --- a/pkg/phlaredb/filter_profiles_bidi.go +++ b/pkg/phlaredb/filter_profiles_bidi.go @@ -2,16 +2,18 @@ package phlaredb import ( "context" + "errors" "io" "connectrpc.com/connect" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" "github.com/prometheus/common/model" + "go.opentelemetry.io/otel/attribute" + oteltrace "go.opentelemetry.io/otel/trace" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - "github.com/grafana/pyroscope/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) type BidiServerMerge[Res any, Req any] interface { @@ -61,7 +63,8 @@ func rewriteEOFError(err error) error { func filterProfiles[B BidiServerMerge[Res, Req], Res filterResponse, Req filterRequest]( ctx context.Context, profiles []iter.Iterator[Profile], batchProfileSize int, stream B, ) ([][]Profile, error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "filterProfiles") + sp, ctx := tracing.StartSpanFromContext(ctx, "filterProfiles") + otelSpan := oteltrace.SpanFromContext(ctx) defer sp.Finish() selection := make([][]Profile, len(profiles)) selectProfileResult := &ingestv1.ProfileSets{ @@ -76,14 +79,14 @@ func filterProfiles[B BidiServerMerge[Res, Req], Res filterResponse, Req filterR querierIndex: i, } } - if err := iter.ReadBatch(ctx, iter.NewMergeIterator(ProfileWithIndex{ + if err := iter.ReadBatch(ctx, phlaremodel.NewMergeIterator(ProfileWithIndex{ Profile: maxBlockProfile, Index: 0, }, true, its...), batchProfileSize, func(ctx context.Context, batch []ProfileWithIndex) error { - sp.LogFields( - otlog.Int("batch_len", len(batch)), - otlog.Int("batch_requested_size", batchProfileSize), - ) + otelSpan.AddEvent("processing batch", oteltrace.WithAttributes( + attribute.Int("batch_len", len(batch)), + attribute.Int("batch_requested_size", batchProfileSize), + )) seriesByFP := map[model.Fingerprint]int{} selectProfileResult.Profiles = selectProfileResult.Profiles[:0] @@ -105,7 +108,7 @@ func filterProfiles[B BidiServerMerge[Res, Req], Res filterResponse, Req filterR }) } - sp.LogFields(otlog.String("msg", "sending batch to client")) + otelSpan.AddEvent("sending batch to client") var err error switch s := BidiServerMerge[Res, Req](stream).(type) { case BidiServerMerge[*ingestv1.MergeProfilesStacktracesResponse, *ingestv1.MergeProfilesStacktracesRequest]: @@ -130,9 +133,9 @@ func filterProfiles[B BidiServerMerge[Res, Req], Res filterResponse, Req filterR if err != nil { return rewriteEOFError(err) } - sp.LogFields(otlog.String("msg", "batch sent to client")) + otelSpan.AddEvent("batch sent to client") - sp.LogFields(otlog.String("msg", "reading selection from client")) + otelSpan.AddEvent("reading selection from client") // handle response for the batch. var selected []bool @@ -162,7 +165,7 @@ func filterProfiles[B BidiServerMerge[Res, Req], Res filterResponse, Req filterR } selected = selectionResponse.Profiles } - sp.LogFields(otlog.String("msg", "selection received")) + otelSpan.AddEvent("selection received") for i, k := range selected { if k { selection[batch[i].Index] = append(selection[batch[i].Index], batch[i].Profile) diff --git a/pkg/phlaredb/filter_profiles_bidi_test.go b/pkg/phlaredb/filter_profiles_bidi_test.go index 1639ae2068..40d9a4eda1 100644 --- a/pkg/phlaredb/filter_profiles_bidi_test.go +++ b/pkg/phlaredb/filter_profiles_bidi_test.go @@ -11,10 +11,10 @@ import ( "github.com/stretchr/testify/require" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/testhelper" ) func TestFilterProfiles(t *testing.T) { diff --git a/pkg/phlaredb/head.go b/pkg/phlaredb/head.go index d5f18b3e2b..61d007d95c 100644 --- a/pkg/phlaredb/head.go +++ b/pkg/phlaredb/head.go @@ -12,28 +12,26 @@ import ( "connectrpc.com/connect" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/gogo/status" "github.com/google/uuid" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/samber/lo" "go.uber.org/atomic" "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - phlarelabels "github.com/grafana/pyroscope/pkg/phlaredb/labels" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + phlarelabels "github.com/grafana/pyroscope/v2/pkg/phlaredb/labels" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) var defaultParquetConfig = &ParquetConfig{ @@ -64,6 +62,7 @@ type Head struct { metaLock sync.RWMutex meta *block.Meta + config Config parquetConfig *ParquetConfig symdb *symdb.SymDB profiles *profileStore @@ -93,6 +92,7 @@ func NewHead(phlarectx context.Context, cfg Config, limiter TenantLimiter) (*Hea meta: block.NewMeta(), totalSamples: atomic.NewUint64(0), + config: cfg, parquetConfig: &parquetConfig, limiter: limiter, updatedAt: atomic.NewTime(time.Now()), @@ -124,11 +124,19 @@ func NewHead(phlarectx context.Context, cfg Config, limiter TenantLimiter) (*Hea } } - h.symdb = symdb.NewSymDB(symdb.DefaultConfig(). - WithDirectory(filepath.Join(h.headPath, symdb.DefaultDirName)). - WithParquetConfig(symdb.ParquetConfig{ + symdbConfig := symdb.DefaultConfig() + if cfg.SymDBFormat == symdb.FormatV3 { + symdbConfig.Version = symdb.FormatV3 + symdbConfig.Dir = h.headPath + } else { + symdbConfig.Version = symdb.FormatV2 + symdbConfig.Dir = filepath.Join(h.headPath, symdb.DefaultDirName) + symdbConfig.Parquet = symdb.ParquetConfig{ MaxBufferRowCount: h.parquetConfig.MaxBufferRowCount, - })) + } + } + + h.symdb = symdb.NewSymDB(symdbConfig) h.wg.Add(1) go h.loop() @@ -178,7 +186,7 @@ func (h *Head) isStale(maxT int64, now time.Time) bool { return now.After(time.Unix(0, maxT)) } -func (h *Head) Ingest(ctx context.Context, p *profilev1.Profile, id uuid.UUID, externalLabels ...*typesv1.LabelPair) error { +func (h *Head) Ingest(ctx context.Context, p *profilev1.Profile, id uuid.UUID, annotations []*typesv1.ProfileAnnotation, externalLabels ...*typesv1.LabelPair) error { if len(p.Sample) == 0 { level.Debug(h.logger).Log("msg", "profile has no samples", "labels", externalLabels) return nil @@ -187,22 +195,26 @@ func (h *Head) Ingest(ctx context.Context, p *profilev1.Profile, id uuid.UUID, e delta := phlaremodel.Labels(externalLabels).Get(phlaremodel.LabelNameDelta) != "false" externalLabels = phlaremodel.Labels(externalLabels).Delete(phlaremodel.LabelNameDelta) + otel := phlaremodel.Labels(externalLabels).Get(phlaremodel.LabelNameOTEL) == "true" + externalLabels = phlaremodel.Labels(externalLabels).Delete(phlaremodel.LabelNameOTEL) + enforceLabelOrder := phlaremodel.Labels(externalLabels).Get(phlaremodel.LabelNameOrder) == phlaremodel.LabelOrderEnforced externalLabels = phlaremodel.Labels(externalLabels).Delete(phlaremodel.LabelNameOrder) - lbls, seriesFingerprints := phlarelabels.CreateProfileLabels(enforceLabelOrder, p, externalLabels...) + metricName := phlaremodel.Labels(externalLabels).Get(model.MetricNameLabel) + symbolsPartitionLabel := h.config.SymbolsPartitionLabel + if otel && symbolsPartitionLabel == "" { + symbolsPartitionLabel = phlaremodel.LabelNameServiceName + } + partition := phlaremodel.SymbolsPartitionForProfile(externalLabels, symbolsPartitionLabel, p) + lbls, seriesFingerprints := phlarelabels.CreateProfileLabels(enforceLabelOrder, p, externalLabels...) for i, fp := range seriesFingerprints { if err := h.limiter.AllowProfile(fp, lbls[i], p.TimeNanos); err != nil { return err } } - // determine the stacktraces partition ID - partition := phlaremodel.StacktracePartitionFromProfile(lbls, p) - - metricName := phlaremodel.Labels(externalLabels).Get(model.MetricNameLabel) - var profileIngested bool for idxType, profile := range h.symdb.WriteProfileSymbols(partition, p) { profile.ID = id @@ -210,7 +222,7 @@ func (h *Head) Ingest(ctx context.Context, p *profilev1.Profile, id uuid.UUID, e if delta && isDeltaSupported(lbls[idxType]) { profile.Samples = h.delta.computeDelta(profile) } else { - profile.Samples = profile.Samples.Compact(false) + profile.Samples = profile.Samples.Compact() } profile.TotalValue = profile.Samples.Sum() @@ -220,6 +232,13 @@ func (h *Head) Ingest(ctx context.Context, p *profilev1.Profile, id uuid.UUID, e continue } + profile.Annotations.Keys = make([]string, 0, len(annotations)) + profile.Annotations.Values = make([]string, 0, len(annotations)) + for i := range annotations { + profile.Annotations.Keys = append(profile.Annotations.Keys, annotations[i].Key) + profile.Annotations.Values = append(profile.Annotations.Values, annotations[i].Value) + } + if err := h.profiles.ingest(ctx, []schemav1.InMemoryProfile{profile}, lbls[idxType], metricName); err != nil { return err } @@ -319,6 +338,15 @@ func (h *Head) LabelNames(ctx context.Context, req *connect.Request[typesv1.Labe }), nil } +func (h *Head) MustProfileTypeNames() []string { + ptypes, err := h.profiles.index.ix.LabelValues(phlaremodel.LabelNameProfileType, nil) + if err != nil { + panic(err) + } + sort.Strings(ptypes) + return ptypes +} + // ProfileTypes returns the possible profile types. func (h *Head) ProfileTypes(ctx context.Context, req *connect.Request[ingestv1.ProfileTypesRequest]) (*connect.Response[ingestv1.ProfileTypesResponse], error) { values, err := h.profiles.index.ix.LabelValues(phlaremodel.LabelNameProfileType, nil) @@ -429,7 +457,7 @@ type selectors [][]*labels.Matcher func parseSelectors(selectorStrings []string) (selectors, error) { sels := make([][]*labels.Matcher, 0, len(selectorStrings)) for _, m := range selectorStrings { - s, err := parser.ParseMetricSelector(m) + s, err := phlaremodel.ParseMetricSelector(m) if err != nil { return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to parse label selector: %v", err)) } @@ -539,7 +567,7 @@ func (h *Head) flush(ctx context.Context) error { for _, t := range h.tables { numRows, numRowGroups, err := t.Flush(ctx) if err != nil { - return errors.Wrapf(err, "flushing table %s", t.Name()) + return fmt.Errorf("flushing table %s: %w", t.Name(), err) } h.metrics.rowsWritten.WithLabelValues(t.Name()).Add(float64(numRows)) f := block.File{ @@ -550,7 +578,7 @@ func (h *Head) flush(ctx context.Context) error { }, } if err = t.Close(); err != nil { - return errors.Wrapf(err, "closing table %s", t.Name()) + return fmt.Errorf("closing table %s: %w", t.Name(), err) } if stat, err := os.Stat(filepath.Join(h.headPath, f.RelPath)); err == nil { f.SizeBytes = uint64(stat.Size()) @@ -562,11 +590,13 @@ func (h *Head) flush(ctx context.Context) error { // symdb if err := h.symdb.Flush(); err != nil { - return errors.Wrap(err, "flushing symdb") + return fmt.Errorf("flushing symdb: %w", err) } for _, file := range h.symdb.Files() { // Files' path is relative to the symdb dir. - file.RelPath = filepath.Join(symdb.DefaultDirName, file.RelPath) + if h.symdb.FormatVersion() == symdb.FormatV2 { + file.RelPath = filepath.Join(symdb.DefaultDirName, file.RelPath) + } files = append(files, file) blockSize += file.SizeBytes h.metrics.flushedFileSizeBytes.WithLabelValues(file.RelPath).Observe(float64(file.SizeBytes)) @@ -647,3 +677,11 @@ func (h *Head) GetMetaStats() block.MetaStats { defer h.metaLock.RUnlock() return h.meta.GetStats() } + +func (h *Head) Meta() *block.Meta { + return h.meta +} + +func (h *Head) LocalPathFor(relPath string) string { + return filepath.Join(h.localPath, relPath) +} diff --git a/pkg/phlaredb/head_queriers.go b/pkg/phlaredb/head_queriers.go index ac5233e45a..4d8b1b8985 100644 --- a/pkg/phlaredb/head_queriers.go +++ b/pkg/phlaredb/head_queriers.go @@ -2,23 +2,25 @@ package phlaredb import ( "context" + "errors" + "fmt" "sort" "connectrpc.com/connect" "github.com/go-kit/log/level" - "github.com/opentracing/opentracing-go" + "github.com/grafana/dskit/tracing" "github.com/parquet-go/parquet-go" - "github.com/pkg/errors" "github.com/prometheus/common/model" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" ) type headOnDiskQuerier struct { @@ -41,7 +43,7 @@ func (q *headOnDiskQuerier) BlockID() string { } func (q *headOnDiskQuerier) SelectMatchingProfiles(ctx context.Context, params *ingestv1.SelectProfilesRequest) (iter.Iterator[Profile], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMatchingProfiles - HeadOnDisk") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMatchingProfiles - HeadOnDisk") defer sp.Finish() // query the index for rows @@ -96,7 +98,7 @@ func (q *headOnDiskQuerier) SelectMatchingProfiles(ctx context.Context, params * }) } if err := pIt.Err(); err != nil { - return nil, errors.Wrap(pIt.Err(), "iterator error") + return nil, fmt.Errorf("iterator error: %w", pIt.Err()) } // Sort profiles by time, the slice is already sorted by series order @@ -111,8 +113,8 @@ func (q *headOnDiskQuerier) SelectMatchingProfiles(ctx context.Context, params * return iter.NewSliceIterator(profiles), nil } -func (q *headOnDiskQuerier) SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeByStacktraces - HeadOnDisk") +func (q *headOnDiskQuerier) SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeByStacktraces - HeadOnDisk") defer sp.Finish() // query the index for rows @@ -146,8 +148,8 @@ func (q *headOnDiskQuerier) SelectMergeByStacktraces(ctx context.Context, params return r.Tree() } -func (q *headOnDiskQuerier) SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeBySpans - HeadOnDisk") +func (q *headOnDiskQuerier) SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeBySpans - HeadOnDisk") defer sp.Finish() // query the index for rows @@ -192,7 +194,7 @@ func (q *headOnDiskQuerier) SelectMergeBySpans(ctx context.Context, params *inge } func (q *headOnDiskQuerier) SelectMergePprof(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64, sts *typesv1.StackTraceSelector) (*profilev1.Profile, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergePprof - HeadOnDisk") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergePprof - HeadOnDisk") defer sp.Finish() // query the index for rows @@ -245,8 +247,8 @@ func (q *headOnDiskQuerier) LabelNames(ctx context.Context, req *connect.Request return connect.NewResponse(&typesv1.LabelNamesResponse{}), nil } -func (q *headOnDiskQuerier) MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeByStacktraces") +func (q *headOnDiskQuerier) MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeByStacktraces") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb, symdb.WithResolverMaxNodes(maxNodes)) defer r.Release() @@ -257,7 +259,7 @@ func (q *headOnDiskQuerier) MergeByStacktraces(ctx context.Context, rows iter.It } func (q *headOnDiskQuerier) MergePprof(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64, sts *typesv1.StackTraceSelector) (*profilev1.Profile, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergePprof") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergePprof") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb, symdb.WithResolverMaxNodes(maxNodes), @@ -270,7 +272,7 @@ func (q *headOnDiskQuerier) MergePprof(ctx context.Context, rows iter.Iterator[P } func (q *headOnDiskQuerier) MergeByLabels(ctx context.Context, rows iter.Iterator[Profile], sts *typesv1.StackTraceSelector, by ...string) ([]*typesv1.Series, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeByLabels - HeadOnDisk") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeByLabels - HeadOnDisk") defer sp.Finish() if len(sts.GetCallSite()) == 0 { return mergeByLabels(ctx, q.rowGroup(), "TotalValue", rows, by...) @@ -282,7 +284,7 @@ func (q *headOnDiskQuerier) MergeByLabels(ctx context.Context, rows iter.Iterato } func (q *headOnDiskQuerier) SelectMergeByLabels(ctx context.Context, params *ingestv1.SelectProfilesRequest, sts *typesv1.StackTraceSelector, by ...string) ([]*typesv1.Series, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeByLabels - HeadOnDisk") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeByLabels - HeadOnDisk") defer sp.Finish() // query the index for rows @@ -324,8 +326,8 @@ func (q *headOnDiskQuerier) Series(ctx context.Context, params *ingestv1.SeriesR return []*typesv1.Labels{}, nil } -func (q *headOnDiskQuerier) MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spanSelector phlaremodel.SpanSelector) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeBySpans") +func (q *headOnDiskQuerier) MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spanSelector phlaremodel.SpanSelector) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeBySpans") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb) defer r.Release() @@ -362,7 +364,7 @@ func (q *headInMemoryQuerier) BlockID() string { } func (q *headInMemoryQuerier) SelectMatchingProfiles(ctx context.Context, params *ingestv1.SelectProfilesRequest) (iter.Iterator[Profile], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMatchingProfiles - HeadInMemory") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMatchingProfiles - HeadInMemory") defer sp.Finish() index := q.head.profiles.index @@ -395,16 +397,16 @@ func (q *headInMemoryQuerier) SelectMatchingProfiles(ctx context.Context, params NewSeriesIterator( profileSeries.lbs, profileSeries.fp, - iter.NewTimeRangedIterator(iter.NewSliceIterator(profiles), start, end), + phlaremodel.NewTimeRangedIterator(iter.NewSliceIterator(profiles), start, end), ), ) } - return iter.NewMergeIterator(maxBlockProfile, false, iters...), nil + return phlaremodel.NewMergeIterator(maxBlockProfile, false, iters...), nil } -func (q *headInMemoryQuerier) SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeByStacktraces - HeadInMemory") +func (q *headInMemoryQuerier) SelectMergeByStacktraces(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeByStacktraces - HeadInMemory") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb, symdb.WithResolverMaxNodes(maxNodes)) defer r.Release() @@ -442,8 +444,8 @@ func (q *headInMemoryQuerier) SelectMergeByStacktraces(ctx context.Context, para return r.Tree() } -func (q *headInMemoryQuerier) SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeBySpans - HeadInMemory") +func (q *headInMemoryQuerier) SelectMergeBySpans(ctx context.Context, params *ingestv1.SelectSpanProfileRequest) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeBySpans - HeadInMemory") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb) defer r.Release() @@ -494,7 +496,7 @@ func (q *headInMemoryQuerier) SelectMergeBySpans(ctx context.Context, params *in } func (q *headInMemoryQuerier) SelectMergePprof(ctx context.Context, params *ingestv1.SelectProfilesRequest, maxNodes int64, sts *typesv1.StackTraceSelector) (*profilev1.Profile, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergePprof - HeadInMemory") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergePprof - HeadInMemory") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb, symdb.WithResolverMaxNodes(maxNodes), @@ -551,8 +553,8 @@ func (q *headInMemoryQuerier) LabelNames(ctx context.Context, req *connect.Reque return q.head.LabelNames(ctx, req) } -func (q *headInMemoryQuerier) MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.Tree, error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "MergeByStacktraces - HeadInMemory") +func (q *headInMemoryQuerier) MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.FunctionNameTree, error) { + sp, _ := tracing.StartSpanFromContext(ctx, "MergeByStacktraces - HeadInMemory") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb, symdb.WithResolverMaxNodes(maxNodes)) defer r.Release() @@ -570,7 +572,7 @@ func (q *headInMemoryQuerier) MergeByStacktraces(ctx context.Context, rows iter. } func (q *headInMemoryQuerier) MergePprof(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64, sts *typesv1.StackTraceSelector) (*profilev1.Profile, error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "MergePprof - HeadInMemory") + sp, _ := tracing.StartSpanFromContext(ctx, "MergePprof - HeadInMemory") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb, symdb.WithResolverMaxNodes(maxNodes), @@ -595,19 +597,17 @@ func (q *headInMemoryQuerier) MergeByLabels( sts *typesv1.StackTraceSelector, by ...string, ) ([]*typesv1.Series, error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "MergeByLabels - HeadInMemory") + sp, _ := tracing.StartSpanFromContext(ctx, "MergeByLabels - HeadInMemory") defer sp.Finish() - seriesBuilder := seriesBuilder{} - seriesBuilder.init(by...) - + seriesBuilder := timeseries.NewBuilder(by...) if len(sts.GetCallSite()) == 0 { for rows.Next() { p, ok := rows.At().(ProfileWithLabels) if !ok { return nil, errors.New("expected ProfileWithLabels") } - seriesBuilder.add(p.Fingerprint(), p.Labels(), int64(p.Timestamp()), float64(p.Total())) + seriesBuilder.Add(p.Fingerprint(), p.Labels(), int64(p.Timestamp()), float64(p.Total()), p.Annotations(), "") } } else { r := symdb.NewResolver(ctx, q.head.symdb, @@ -622,7 +622,7 @@ func (q *headInMemoryQuerier) MergeByLabels( if err := r.CallSiteValues(&v, p.StacktracePartition(), p.Samples()); err != nil { return nil, err } - seriesBuilder.add(p.Fingerprint(), p.Labels(), int64(p.Timestamp()), float64(v.Total)) + seriesBuilder.Add(p.Fingerprint(), p.Labels(), int64(p.Timestamp()), float64(v.Total), p.Annotations(), "") } } @@ -630,7 +630,7 @@ func (q *headInMemoryQuerier) MergeByLabels( return nil, err } - return seriesBuilder.build(), nil + return seriesBuilder.Build(), nil } func (q *headInMemoryQuerier) SelectMergeByLabels( @@ -639,7 +639,7 @@ func (q *headInMemoryQuerier) SelectMergeByLabels( sts *typesv1.StackTraceSelector, by ...string, ) ([]*typesv1.Series, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeByLabels - HeadInMemory") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeByLabels - HeadInMemory") defer sp.Finish() index := q.head.profiles.index @@ -654,8 +654,7 @@ func (q *headInMemoryQuerier) SelectMergeByLabels( start = model.Time(params.Start) end = model.Time(params.End) ) - seriesBuilder := seriesBuilder{} - seriesBuilder.init(by...) + seriesBuilder := timeseries.NewBuilder(by...) index.mutex.RLock() defer index.mutex.RUnlock() @@ -673,7 +672,7 @@ func (q *headInMemoryQuerier) SelectMergeByLabels( if p.Timestamp() > end { break } - seriesBuilder.add(fp, profileSeries.lbs, int64(p.Timestamp()), float64(p.Total())) + seriesBuilder.Add(fp, profileSeries.lbs, int64(p.Timestamp()), float64(p.Total()), p.Annotations, "") } } } else { @@ -696,11 +695,11 @@ func (q *headInMemoryQuerier) SelectMergeByLabels( if err = r.CallSiteValues(&v, p.StacktracePartition, p.Samples); err != nil { return nil, err } - seriesBuilder.add(fp, profileSeries.lbs, int64(p.Timestamp()), float64(v.Total)) + seriesBuilder.Add(fp, profileSeries.lbs, int64(p.Timestamp()), float64(v.Total), p.Annotations, "") } } } - return seriesBuilder.build(), nil + return seriesBuilder.Build(), nil } func (q *headInMemoryQuerier) Series(ctx context.Context, params *ingestv1.SeriesRequest) ([]*typesv1.Labels, error) { @@ -711,8 +710,8 @@ func (q *headInMemoryQuerier) Series(ctx context.Context, params *ingestv1.Serie return res.Msg.LabelsSet, nil } -func (q *headInMemoryQuerier) MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spanSelector phlaremodel.SpanSelector) (*phlaremodel.Tree, error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "MergeBySpans - HeadInMemory") +func (q *headInMemoryQuerier) MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spanSelector phlaremodel.SpanSelector) (*phlaremodel.FunctionNameTree, error) { + sp, _ := tracing.StartSpanFromContext(ctx, "MergeBySpans - HeadInMemory") defer sp.Finish() r := symdb.NewResolver(ctx, q.head.symdb) defer r.Release() diff --git a/pkg/phlaredb/head_test.go b/pkg/phlaredb/head_test.go index 8d7232de77..f2edb63720 100644 --- a/pkg/phlaredb/head_test.go +++ b/pkg/phlaredb/head_test.go @@ -11,7 +11,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/parquet-go/parquet-go" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" @@ -21,12 +21,12 @@ import ( profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/pprof" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) type noLimit struct{} @@ -55,7 +55,7 @@ type testHead struct { func (t *testHead) Flush(ctx context.Context) error { defer func() { - t.t.Logf("flushing head of block %v", t.Head.meta.ULID) + t.t.Logf("flushing head of block %v", t.meta.ULID) }() return t.Head.Flush(ctx) } @@ -186,8 +186,8 @@ func newProfileBaz() *profilev1.Profile { func TestHeadLabelValues(t *testing.T) { head := newTestHead(t) - require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), &typesv1.LabelPair{Name: "job", Value: "foo"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) - require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), &typesv1.LabelPair{Name: "job", Value: "bar"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) + require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), nil, &typesv1.LabelPair{Name: "job", Value: "foo"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) + require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), nil, &typesv1.LabelPair{Name: "job", Value: "bar"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) res, err := head.LabelValues(context.Background(), connect.NewRequest(&typesv1.LabelValuesRequest{Name: "cluster"})) require.NoError(t, err) @@ -200,8 +200,8 @@ func TestHeadLabelValues(t *testing.T) { func TestHeadLabelNames(t *testing.T) { head := newTestHead(t) - require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), &typesv1.LabelPair{Name: "job", Value: "foo"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) - require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), &typesv1.LabelPair{Name: "job", Value: "bar"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) + require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), nil, &typesv1.LabelPair{Name: "job", Value: "foo"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) + require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), nil, &typesv1.LabelPair{Name: "job", Value: "bar"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) res, err := head.LabelNames(context.Background(), connect.NewRequest(&typesv1.LabelNamesRequest{})) require.NoError(t, err) @@ -212,8 +212,8 @@ func TestHeadSeries(t *testing.T) { head := newTestHead(t) fooLabels := phlaremodel.NewLabelsBuilder(nil).Set("namespace", "phlare").Set("job", "foo").Labels() barLabels := phlaremodel.NewLabelsBuilder(nil).Set("namespace", "phlare").Set("job", "bar").Labels() - require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), fooLabels...)) - require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), barLabels...)) + require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), nil, fooLabels...)) + require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), nil, barLabels...)) lblBuilder := phlaremodel.NewLabelsBuilder(nil). Set("namespace", "phlare"). @@ -242,8 +242,8 @@ func TestHeadSeries(t *testing.T) { func TestHeadProfileTypes(t *testing.T) { head := newTestHead(t) - require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), &typesv1.LabelPair{Name: "__name__", Value: "foo"}, &typesv1.LabelPair{Name: "job", Value: "foo"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) - require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), &typesv1.LabelPair{Name: "__name__", Value: "bar"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) + require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), nil, &typesv1.LabelPair{Name: "__name__", Value: "foo"}, &typesv1.LabelPair{Name: "job", Value: "foo"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) + require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), nil, &typesv1.LabelPair{Name: "__name__", Value: "bar"}, &typesv1.LabelPair{Name: "namespace", Value: "phlare"})) res, err := head.ProfileTypes(context.Background(), connect.NewRequest(&ingestv1.ProfileTypesRequest{})) require.NoError(t, err) @@ -283,7 +283,7 @@ func TestHead_SelectMatchingProfiles_Order(t *testing.T) { x := newProfileFoo() // Make sure some of our profiles have matching timestamps. x.TimeNanos = now.Add(time.Second * time.Duration(i-i%2)).UnixNano() - require.NoError(t, head.Ingest(ctx, x, uuid.UUID{}, []*typesv1.LabelPair{ + require.NoError(t, head.Ingest(ctx, x, uuid.UUID{}, nil, []*typesv1.LabelPair{ {Name: "job", Value: "foo"}, {Name: "x", Value: strconv.Itoa(i)}, }...)) @@ -332,7 +332,7 @@ func TestHeadFlush(t *testing.T) { for pos := range profilePaths { profile := parseProfile(t, profilePaths[pos]) - require.NoError(t, head.Ingest(ctx, profile, uuid.New())) + require.NoError(t, head.Ingest(ctx, profile, uuid.New(), nil)) } require.NoError(t, head.Flush(ctx)) @@ -540,6 +540,7 @@ func TestHead_ProfileOrder(t *testing.T) { context.Background(), p, u, + nil, &typesv1.LabelPair{Name: phlaremodel.LabelNameProfileName, Value: "memory"}, &typesv1.LabelPair{Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: "service-a"}, @@ -550,6 +551,7 @@ func TestHead_ProfileOrder(t *testing.T) { context.Background(), p, u, + nil, &typesv1.LabelPair{Name: phlaremodel.LabelNameProfileName, Value: "memory"}, &typesv1.LabelPair{Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: "service-b"}, @@ -561,6 +563,7 @@ func TestHead_ProfileOrder(t *testing.T) { context.Background(), p, u, + nil, &typesv1.LabelPair{Name: phlaremodel.LabelNameProfileName, Value: "memory"}, &typesv1.LabelPair{Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: "service-c"}, @@ -572,6 +575,7 @@ func TestHead_ProfileOrder(t *testing.T) { context.Background(), p, u, + nil, &typesv1.LabelPair{Name: phlaremodel.LabelNameProfileName, Value: "cpu"}, &typesv1.LabelPair{Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: "service-a"}, @@ -583,6 +587,7 @@ func TestHead_ProfileOrder(t *testing.T) { context.Background(), p, u, + nil, &typesv1.LabelPair{Name: phlaremodel.LabelNameProfileName, Value: "cpu"}, &typesv1.LabelPair{Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: "service-b"}, @@ -593,6 +598,7 @@ func TestHead_ProfileOrder(t *testing.T) { context.Background(), p, u, + nil, &typesv1.LabelPair{Name: phlaremodel.LabelNameProfileName, Value: "cpu"}, &typesv1.LabelPair{Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, &typesv1.LabelPair{Name: phlaremodel.LabelNameServiceName, Value: "service-b"}, @@ -626,7 +632,7 @@ func BenchmarkHeadIngestProfiles(t *testing.B) { for n := 0; n < t.N; n++ { for pos := range profilePaths { p := parseProfile(t, profilePaths[pos]) - require.NoError(t, head.Ingest(ctx, p, uuid.New())) + require.NoError(t, head.Ingest(ctx, p, uuid.New(), nil)) profileCount++ } } diff --git a/pkg/phlaredb/labels/labels.go b/pkg/phlaredb/labels/labels.go index 405955abde..c6e0596621 100644 --- a/pkg/phlaredb/labels/labels.go +++ b/pkg/phlaredb/labels/labels.go @@ -8,7 +8,7 @@ import ( profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) func CreateProfileLabels(enforceOrder bool, p *profilev1.Profile, externalLabels ...*typesv1.LabelPair) ([]phlaremodel.Labels, []model.Fingerprint) { @@ -60,6 +60,7 @@ func CreateProfileLabels(enforceOrder bool, p *profilev1.Profile, externalLabels } else { sort.Sort(lbs) } + lbs = lbs.Unique() profilesLabels[pos] = lbs seriesRefs[pos] = model.Fingerprint(lbs.Hash()) diff --git a/pkg/phlaredb/labels/labels_test.go b/pkg/phlaredb/labels/labels_test.go index aaf7786362..6ecb81e50d 100644 --- a/pkg/phlaredb/labels/labels_test.go +++ b/pkg/phlaredb/labels/labels_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) func TestLabelsForProfiles(t *testing.T) { diff --git a/pkg/phlaredb/metrics.go b/pkg/phlaredb/metrics.go index 0f9d686c3c..4ba00b49d8 100644 --- a/pkg/phlaredb/metrics.go +++ b/pkg/phlaredb/metrics.go @@ -2,12 +2,13 @@ package phlaredb import ( "context" + "time" "github.com/prometheus/client_golang/prometheus" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/util" ) type contextKey uint8 @@ -45,109 +46,137 @@ type headMetrics struct { } func newHeadMetrics(reg prometheus.Registerer) *headMetrics { + return newHeadMetricsWithPrefix(reg, "pyroscope") +} + +func newHeadMetricsWithPrefix(reg prometheus.Registerer, prefix string) *headMetrics { m := &headMetrics{ seriesCreated: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_tsdb_head_series_created_total", + Name: prefix + "_tsdb_head_series_created_total", Help: "Total number of series created in the head", }, []string{"profile_name"}), rowsWritten: prometheus.NewCounterVec( prometheus.CounterOpts{ - Name: "pyroscope_rows_written", + Name: prefix + "_rows_written", Help: "Number of rows written to a parquet table.", }, []string{"type"}), profilesCreated: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_head_profiles_created_total", + Name: prefix + "_head_profiles_created_total", Help: "Total number of profiles created in the head", }, []string{"profile_name"}), sampleValuesIngested: prometheus.NewCounterVec( prometheus.CounterOpts{ - Name: "pyroscope_head_ingested_sample_values_total", + Name: prefix + "_head_ingested_sample_values_total", Help: "Number of sample values ingested into the head per profile type.", }, []string{"profile_name"}), sampleValuesReceived: prometheus.NewCounterVec( prometheus.CounterOpts{ - Name: "pyroscope_head_received_sample_values_total", + Name: prefix + "_head_received_sample_values_total", Help: "Number of sample values received into the head per profile type.", }, []string{"profile_name"}), sizeBytes: prometheus.NewGaugeVec( prometheus.GaugeOpts{ - Name: "pyroscope_head_size_bytes", + Name: prefix + "_head_size_bytes", Help: "Size of a particular in memory store within the head phlaredb block.", }, []string{"type"}), series: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "pyroscope_tsdb_head_series", + Name: prefix + "_tsdb_head_series", Help: "Total number of series in the head block.", }), profiles: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "pyroscope_head_profiles", + Name: prefix + "_head_profiles", Help: "Total number of profiles in the head block.", }), flushedFileSizeBytes: prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: "pyroscope_head_flushed_table_size_bytes", + Name: prefix + "_head_flushed_table_size_bytes", Help: "Size of a flushed table in bytes.", // [2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB, 256MB, 512MB, 1GB, 2GB] - Buckets: prometheus.ExponentialBuckets(2*1024*1024, 2, 11), + Buckets: prometheus.ExponentialBuckets(2*1024*1024, 2, 11), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"name"}), flushedBlockSizeBytes: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_head_flushed_block_size_bytes", + Name: prefix + "_head_flushed_block_size_bytes", Help: "Size of a flushed block in bytes.", // [50MB, 75MB, 112.5MB, 168.75MB, 253.125MB, 379.688MB, 569.532MB, 854.298MB, 1.281MB, 1.922MB, 2.883MB] - Buckets: prometheus.ExponentialBuckets(50*1024*1024, 1.5, 11), + Buckets: prometheus.ExponentialBuckets(50*1024*1024, 1.5, 11), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), flushedBlockDurationSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_head_flushed_block_duration_seconds", + Name: prefix + "_head_flushed_block_duration_seconds", Help: "Time to flushed a block in seconds.", // [5s, 7.5s, 11.25s, 16.875s, 25.3125s, 37.96875s, 56.953125s, 85.4296875s, 128.14453125s, 192.216796875s] - Buckets: prometheus.ExponentialBuckets(5, 1.5, 10), + Buckets: prometheus.ExponentialBuckets(5, 1.5, 10), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), flushedBlockSeries: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_head_flushed_block_series", + Name: prefix + "_head_flushed_block_series", Help: "Number of series in a flushed block.", // [1k, 3k, 5k, 7k, 9k, 11k, 13k, 15k, 17k, 19k] - Buckets: prometheus.LinearBuckets(1000, 2000, 10), + Buckets: prometheus.LinearBuckets(1000, 2000, 10), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), flushedBlockSamples: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_head_flushed_block_samples", + Name: prefix + "_head_flushed_block_samples", Help: "Number of samples in a flushed block.", // [200k, 400k, 800k, 1.6M, 3.2M, 6.4M, 12.8M, 25.6M, 51.2M, 102.4M, 204.8M, 409.6M, 819.2M, 1.6384G, 3.2768G] - Buckets: prometheus.ExponentialBuckets(200_000, 2, 15), + Buckets: prometheus.ExponentialBuckets(200_000, 2, 15), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), flusehdBlockProfiles: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_head_flushed_block_profiles", + Name: prefix + "_head_flushed_block_profiles", Help: "Number of profiles in a flushed block.", // [20k, 40k, 80k, 160k, 320k, 640k, 1.28M, 2.56M, 5.12M, 10.24M] - Buckets: prometheus.ExponentialBuckets(20_000, 2, 10), + Buckets: prometheus.ExponentialBuckets(20_000, 2, 10), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), blockDurationSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_head_block_duration_seconds", + Name: prefix + "_head_block_duration_seconds", Help: "Duration of a block in seconds (the range it covers).", // [20m, 40m, 1h, 1h20, 1h40, 2h, 2h20, 2h40, 3h, 3h20, 3h40, 4h, 4h20, 4h40, 5h, 5h20, 5h40, 6h, 6h20, 6h40, 7h, 7h20, 7h40, 8h] - Buckets: prometheus.LinearBuckets(1200, 1200, 24), + Buckets: prometheus.LinearBuckets(1200, 1200, 24), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), flushedBlocks: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_head_flushed_blocks_total", + Name: prefix + "_head_flushed_blocks_total", Help: "Total number of blocks flushed.", }, []string{"status"}), flushedBlocksReasons: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_head_flushed_reason_total", + Name: prefix + "_head_flushed_reason_total", Help: "Total count of reasons why block has been flushed.", }, []string{"reason"}), writtenProfileSegments: prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "pyroscope_head_written_profile_segments_total", + Name: prefix + "_head_written_profile_segments_total", Help: "Total number and status of profile row groups segments written.", }, []string{"status"}), writtenProfileSegmentsBytes: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_head_written_profile_segments_size_bytes", + Name: prefix + "_head_written_profile_segments_size_bytes", Help: "Size of a flushed table in bytes.", // [512KB, 1MB, 2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB, 256MB, 512MB] - Buckets: prometheus.ExponentialBuckets(512*1024, 2, 11), + Buckets: prometheus.ExponentialBuckets(512*1024, 2, 11), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }), samples: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "pyroscope_head_samples", + Name: prefix + "_head_samples", Help: "Number of samples in the head.", }), } @@ -181,6 +210,10 @@ func (m *headMetrics) register(reg prometheus.Registerer) { m.writtenProfileSegmentsBytes = util.RegisterOrGet(reg, m.writtenProfileSegmentsBytes) } +func ContextWithHeadMetrics(ctx context.Context, reg prometheus.Registerer, prefix string) context.Context { + return contextWithHeadMetrics(ctx, newHeadMetricsWithPrefix(reg, prefix)) +} + func contextWithHeadMetrics(ctx context.Context, m *headMetrics) context.Context { return context.WithValue(ctx, headMetricsContextKey, m) } @@ -209,8 +242,11 @@ func NewBlocksMetrics(reg prometheus.Registerer) *BlocksMetrics { query: query.NewMetrics(reg), blockOpeningLatency: util.RegisterOrGet(reg, prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscopedb_block_opening_duration", - Help: "Latency of opening a block in seconds", + Name: "pyroscopedb_block_opening_duration", + Help: "Latency of opening a block in seconds", + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, })), blockOpened: util.RegisterOrGet(reg, prometheus.NewGauge(prometheus.GaugeOpts{ diff --git a/pkg/phlaredb/metrics_test.go b/pkg/phlaredb/metrics_test.go index d63aa00c1e..ae8e4e4440 100644 --- a/pkg/phlaredb/metrics_test.go +++ b/pkg/phlaredb/metrics_test.go @@ -11,7 +11,7 @@ import ( "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" ) func TestMultipleRegistrationMetrics(t *testing.T) { @@ -32,9 +32,9 @@ pyroscope_head_profiles_created_total{profile_name="test"} 2 func TestHeadMetrics(t *testing.T) { head := newTestHead(t) - require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New())) - require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New())) - require.NoError(t, head.Ingest(context.Background(), newProfileBaz(), uuid.New())) + require.NoError(t, head.Ingest(context.Background(), newProfileFoo(), uuid.New(), nil)) + require.NoError(t, head.Ingest(context.Background(), newProfileBar(), uuid.New(), nil)) + require.NoError(t, head.Ingest(context.Background(), newProfileBaz(), uuid.New(), nil)) head.updateSymbolsMemUsage(new(symdb.MemoryStats)) time.Sleep(time.Second) require.NoError(t, testutil.GatherAndCompare(head.reg, @@ -54,7 +54,7 @@ pyroscope_head_received_sample_values_total{profile_name=""} 3 pyroscope_head_size_bytes{type="functions"} 96 pyroscope_head_size_bytes{type="locations"} 152 pyroscope_head_size_bytes{type="mappings"} 96 -pyroscope_head_size_bytes{type="profiles"} 420 +pyroscope_head_size_bytes{type="profiles"} 564 pyroscope_head_size_bytes{type="stacktraces"} 96 pyroscope_head_size_bytes{type="strings"} 66 diff --git a/pkg/phlaredb/phlaredb.go b/pkg/phlaredb/phlaredb.go index a503c7769e..965adb24a4 100644 --- a/pkg/phlaredb/phlaredb.go +++ b/pkg/phlaredb/phlaredb.go @@ -19,19 +19,20 @@ import ( "github.com/google/uuid" "github.com/grafana/dskit/multierror" "github.com/grafana/dskit/services" - "github.com/oklog/ulid" - "github.com/opentracing/opentracing-go" + "github.com/grafana/dskit/tracing" + "github.com/oklog/ulid/v2" "github.com/prometheus/common/model" "github.com/samber/lo" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/util" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -47,9 +48,13 @@ type Config struct { MaxBlockDuration time.Duration `yaml:"max_block_duration,omitempty"` // TODO: docs - RowGroupTargetSize uint64 `yaml:"row_group_target_size"` + RowGroupTargetSize uint64 `yaml:"row_group_target_size"` + SymbolsPartitionLabel string `yaml:"symbols_partition_label"` - Parquet *ParquetConfig `yaml:"-"` // Those configs should not be exposed to the user, rather they should be determined by pyroscope itself. Currently, they are solely used for test cases. + // Those configs should not be exposed to the user, rather they should be determined by pyroscope itself. + // Currently, they are solely used for test cases. + Parquet *ParquetConfig `yaml:"-"` + SymDBFormat symdb.FormatVersion `yaml:"-"` MinFreeDisk uint64 `yaml:"min_free_disk_gb"` MinDiskAvailablePercentage float64 `yaml:"min_disk_available_percentage"` @@ -67,6 +72,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { f.StringVar(&cfg.DataPath, "pyroscopedb.data-path", "./data", "Directory used for local storage.") f.DurationVar(&cfg.MaxBlockDuration, "pyroscopedb.max-block-duration", 1*time.Hour, "Upper limit to the duration of a Pyroscope block.") f.Uint64Var(&cfg.RowGroupTargetSize, "pyroscopedb.row-group-target-size", 10*128*1024*1024, "How big should a single row group be uncompressed") // This should roughly be 128MiB compressed + f.StringVar(&cfg.SymbolsPartitionLabel, "pyroscopedb.symbols-partition-label", "", "Specifies the dimension by which symbols are partitioned. By default, the partitioning is determined automatically.") f.Uint64Var(&cfg.MinFreeDisk, "pyroscopedb.retention-policy-min-free-disk-gb", DefaultMinFreeDisk, "How much available disk space to keep in GiB") f.Float64Var(&cfg.MinDiskAvailablePercentage, "pyroscopedb.retention-policy-min-disk-available-percentage", DefaultMinDiskAvailablePercentage, "Which percentage of free disk space to keep") f.DurationVar(&cfg.EnforcementInterval, "pyroscopedb.retention-policy-enforcement-interval", DefaultRetentionPolicyEnforcementInterval, "How often to enforce disk retention") @@ -318,9 +324,9 @@ func (f *PhlareDB) headQueriers() Queriers { return res } -func (f *PhlareDB) Ingest(ctx context.Context, p *profilev1.Profile, id uuid.UUID, externalLabels ...*typesv1.LabelPair) (err error) { +func (f *PhlareDB) Ingest(ctx context.Context, p *profilev1.Profile, id uuid.UUID, annotations []*typesv1.ProfileAnnotation, externalLabels ...*typesv1.LabelPair) (err error) { return f.headForIngest(p.TimeNanos, func(head *Head) error { - return head.Ingest(ctx, p, id, externalLabels...) + return head.Ingest(ctx, p, id, annotations, externalLabels...) }) } @@ -381,7 +387,7 @@ const ( // LabelValues returns the possible label values for a given label name. func (f *PhlareDB) LabelValues(ctx context.Context, req *connect.Request[typesv1.LabelValuesRequest]) (resp *connect.Response[typesv1.LabelValuesResponse], err error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "PhlareDB LabelValues") + sp, ctx := tracing.StartSpanFromContext(ctx, "PhlareDB LabelValues") defer sp.Finish() f.headLock.RLock() @@ -396,7 +402,7 @@ func (f *PhlareDB) LabelValues(ctx context.Context, req *connect.Request[typesv1 // LabelNames returns the possible label names. func (f *PhlareDB) LabelNames(ctx context.Context, req *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "PhlareDB LabelNames") + sp, ctx := tracing.StartSpanFromContext(ctx, "PhlareDB LabelNames") defer sp.Finish() f.headLock.RLock() @@ -411,7 +417,7 @@ func (f *PhlareDB) LabelNames(ctx context.Context, req *connect.Request[typesv1. // ProfileTypes returns the possible profile types. func (f *PhlareDB) ProfileTypes(ctx context.Context, req *connect.Request[ingestv1.ProfileTypesRequest]) (resp *connect.Response[ingestv1.ProfileTypesResponse], err error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "PhlareDB ProfileTypes") + sp, ctx := tracing.StartSpanFromContext(ctx, "PhlareDB ProfileTypes") defer sp.Finish() f.headLock.RLock() @@ -426,7 +432,7 @@ func (f *PhlareDB) ProfileTypes(ctx context.Context, req *connect.Request[ingest // Series returns labels series for the given set of matchers. func (f *PhlareDB) Series(ctx context.Context, req *connect.Request[ingestv1.SeriesRequest]) (*connect.Response[ingestv1.SeriesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "PhlareDB Series") + sp, ctx := tracing.StartSpanFromContext(ctx, "PhlareDB Series") defer sp.Finish() f.headLock.RLock() @@ -529,7 +535,7 @@ func (f *PhlareDB) BlockMetadata(ctx context.Context, req *connect.Request[inges } func (f *PhlareDB) GetProfileStats(ctx context.Context, req *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "PhlareDB GetProfileStats") + sp, _ := tracing.StartSpanFromContext(ctx, "PhlareDB GetProfileStats") defer sp.Finish() minTimes := make([]model.Time, 0) @@ -583,7 +589,7 @@ func getProfileStatsFromBounds(minTimes, maxTimes []model.Time) (*typesv1.GetPro } func (f *PhlareDB) GetBlockStats(ctx context.Context, req *connect.Request[ingestv1.GetBlockStatsRequest]) (*connect.Response[ingestv1.GetBlockStatsResponse], error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "PhlareDB GetBlockStats") + sp, _ := tracing.StartSpanFromContext(ctx, "PhlareDB GetBlockStats") defer sp.Finish() res := &ingestv1.GetBlockStatsResponse{} diff --git a/pkg/phlaredb/phlaredb_test.go b/pkg/phlaredb/phlaredb_test.go index 603cbe112a..e0f836986b 100644 --- a/pkg/phlaredb/phlaredb_test.go +++ b/pkg/phlaredb/phlaredb_test.go @@ -2,6 +2,8 @@ package phlaredb import ( "context" + "errors" + "io" "math" "net/http" "os" @@ -11,7 +13,6 @@ import ( "connectrpc.com/connect" "github.com/google/pprof/profile" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,9 +23,9 @@ import ( "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1/ingesterv1connect" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/testhelper" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/testhelper" ) func TestCreateLocalDir(t *testing.T) { @@ -56,7 +57,7 @@ func ingestProfiles(b testing.TB, db *PhlareDB, generator func(tsNano int64, t t for i := from; i <= to; i += int64(step) { p, name := generator(i, b) require.NoError(b, db.Ingest( - context.Background(), p, uuid.New(), append(externalLabels, &typesv1.LabelPair{Name: model.MetricNameLabel, Value: name})...)) + context.Background(), p, uuid.New(), nil, append(externalLabels, &typesv1.LabelPair{Name: model.MetricNameLabel, Value: name})...)) } } @@ -84,7 +85,7 @@ func (q Queriers) ingesterClient() (ingesterv1connect.IngesterServiceClient, fun mux.Handle(ingesterv1connect.NewIngesterServiceHandler(&ingesterHandlerPhlareDB{q}, connectapi.DefaultHandlerOptions()...)) serv := testhelper.NewInMemoryServer(mux) - var httpClient *http.Client = serv.Client() + var httpClient = serv.Client() client := ingesterv1connect.NewIngesterServiceClient( httpClient, serv.URL(), connectapi.DefaultClientOptions()..., @@ -99,19 +100,19 @@ type ingesterHandlerPhlareDB struct { } func (i *ingesterHandlerPhlareDB) MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesStacktracesRequest, ingestv1.MergeProfilesStacktracesResponse]) error { - return MergeProfilesStacktraces(ctx, stream, i.forTimeRange) + return MergeProfilesStacktraces(ctx, stream, i.ForTimeRange) } func (i *ingesterHandlerPhlareDB) MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesLabelsRequest, ingestv1.MergeProfilesLabelsResponse]) error { - return MergeProfilesLabels(ctx, stream, i.forTimeRange) + return MergeProfilesLabels(ctx, stream, i.ForTimeRange) } func (i *ingesterHandlerPhlareDB) MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesPprofRequest, ingestv1.MergeProfilesPprofResponse]) error { - return MergeProfilesPprof(ctx, stream, i.forTimeRange) + return MergeProfilesPprof(ctx, stream, i.ForTimeRange) } func (i *ingesterHandlerPhlareDB) MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeSpanProfileRequest, ingestv1.MergeSpanProfileResponse]) error { - return MergeSpanProfile(ctx, stream, i.forTimeRange) + return MergeSpanProfile(ctx, stream, i.ForTimeRange) } func (i *ingesterHandlerPhlareDB) Push(context.Context, *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { @@ -212,7 +213,7 @@ func TestMergeProfilesStacktraces(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp.Result) - at, err := phlaremodel.UnmarshalTree(resp.Result.TreeBytes) + at, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Result.TreeBytes) require.NoError(t, err) require.Equal(t, int64(500000000), at.Total()) }) @@ -247,7 +248,15 @@ func TestMergeProfilesStacktraces(t *testing.T) { t.Run("empty request fails", func(t *testing.T) { bidi := client.MergeProfilesStacktraces(ctx) - require.NoError(t, bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{})) + // It is possible that the error returned by server side of the + // stream closes the net.Conn before bidi.Send has finished. The + // short timing for that to happen with real HTTP servers makes this + // unlikely, but it does happen with the synchronous in memory + // net.Pipe() that is used here. + // See https://github.com/grafana/pyroscope/issues/3549 for more details. + if err := bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{}); !errors.Is(err, io.EOF) { + require.NoError(t, err) + } _, err := bidi.Receive() require.EqualError(t, err, "invalid_argument: missing initial select request") @@ -281,6 +290,35 @@ func TestMergeProfilesStacktraces(t *testing.T) { }) } +// See https://github.com/grafana/pyroscope/pull/3356 +func Test_HeadFlush_DuplicateLabels(t *testing.T) { + defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) + + // ingest some sample data + var ( + ctx = testContext(t) + testDir = contextDataDir(ctx) + end = time.Unix(0, int64(time.Hour)) + start = end.Add(-time.Minute) + step = 15 * time.Second + ) + + db, err := New(ctx, Config{ + DataPath: testDir, + MaxBlockDuration: time.Duration(100000) * time.Minute, + }, NoLimit, ctx.localBucketClient) + require.NoError(t, err) + defer func() { + require.NoError(t, db.Close()) + }() + + ingestProfiles(t, db, cpuProfileGenerator, start.UnixNano(), end.UnixNano(), step, + &typesv1.LabelPair{Name: "namespace", Value: "my-namespace"}, + &typesv1.LabelPair{Name: "pod", Value: "my-pod"}, + &typesv1.LabelPair{Name: "pod", Value: "not-my-pod"}, + ) +} + func TestMergeProfilesPprof(t *testing.T) { defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) @@ -379,7 +417,15 @@ func TestMergeProfilesPprof(t *testing.T) { t.Run("empty request fails", func(t *testing.T) { bidi := client.MergeProfilesPprof(ctx) - require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{})) + // It is possible that the error returned by server side of the + // stream closes the net.Conn before bidi.Send has finished. The + // short timing for that to happen with real HTTP servers makes this + // unlikely, but it does happen with the synchronous in memory + // net.Pipe() that is used here. + // See https://github.com/grafana/pyroscope/issues/3549 for more details. + if err := bidi.Send(&ingestv1.MergeProfilesPprofRequest{}); !errors.Is(err, io.EOF) { + require.NoError(t, err) + } _, err := bidi.Receive() require.EqualError(t, err, "invalid_argument: missing initial select request") @@ -475,33 +521,49 @@ func Test_QueryNotInitializedHead(t *testing.T) { }) t.Run("MergeProfilesLabels", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) bidi := client.MergeProfilesLabels(ctx) require.NoError(t, bidi.Send(&ingestv1.MergeProfilesLabelsRequest{ Request: &ingestv1.SelectProfilesRequest{}, })) - cancel() + closeBidi(t, bidi) }) t.Run("MergeProfilesStacktraces", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) bidi := client.MergeProfilesStacktraces(ctx) require.NoError(t, bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{ Request: &ingestv1.SelectProfilesRequest{}, })) - cancel() + closeBidi(t, bidi) }) t.Run("MergeProfilesPprof", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) bidi := client.MergeProfilesPprof(ctx) require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{ Request: &ingestv1.SelectProfilesRequest{}, })) - cancel() + closeBidi(t, bidi) }) } +// closeBidi gracefully shuts down a connect bidi stream by signalling +// end-of-send and draining the response side until EOF. +// +// We can't just cancel the context: under -race on Go 1.25 that triggers +// a data race inside net/http. The HTTP/2 stream reset spawns a goroutine +// that calls (*readTrackingBody).Close() while the original roundTrip +// goroutine is still reading the same struct (transport.go:725 vs :765). +// Closing the stream on the normal codepath avoids the reset entirely. +func closeBidi[Req, Res any](t *testing.T, bidi *connect.BidiStreamForClient[Req, Res]) { + t.Helper() + require.NoError(t, bidi.CloseRequest()) + for { + if _, err := bidi.Receive(); err != nil { + break + } + } + require.NoError(t, bidi.CloseResponse()) +} + func Test_FlushNotInitializedHead(t *testing.T) { defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) diff --git a/pkg/phlaredb/profile_store.go b/pkg/phlaredb/profile_store.go index 931e3acca7..5e6256ddc8 100644 --- a/pkg/phlaredb/profile_store.go +++ b/pkg/phlaredb/profile_store.go @@ -14,16 +14,15 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/runutil" "github.com/parquet-go/parquet-go" - "github.com/pkg/errors" "go.uber.org/atomic" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - phlareparquet "github.com/grafana/pyroscope/pkg/parquet" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/util/build" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/util/build" ) const ( @@ -256,15 +255,15 @@ func (s *profileStore) cutRowGroup(count int) (err error) { n, err := parquet.CopyRows(s.writer, schemav1.NewInMemoryProfilesRowReader(s.flushBuffer)) if err != nil { - return errors.Wrap(err, "write row group segments to disk") + return fmt.Errorf("write row group segments to disk: %w", err) } if err := s.writer.Close(); err != nil { - return errors.Wrap(err, "close row group segment writer") + return fmt.Errorf("close row group segment writer: %w", err) } if err := f.Close(); err != nil { - return errors.Wrap(err, "closing row group segment file") + return fmt.Errorf("closing row group segment file: %w", err) } s.metrics.writtenProfileSegments.WithLabelValues("success").Inc() @@ -284,6 +283,8 @@ func (s *profileStore) cutRowGroup(count int) (err error) { // held for long as it only performs in-memory operations, // although blocking readers. s.rowsLock.Lock() + // After the lock is released, rows/profiles should be read from the disk. + defer s.rowsLock.Unlock() s.rowsFlushed += uint64(n) s.rowGroups = append(s.rowGroups, rowGroup) // Cutting the index is relatively quick op (no I/O). @@ -303,8 +304,6 @@ func (s *profileStore) cutRowGroup(count int) (err error) { level.Debug(s.logger).Log("msg", "cut row group segment", "path", path, "numProfiles", n) s.metrics.sizeBytes.WithLabelValues(s.Name()).Set(float64(currentSize)) - // After the lock is released, rows/profiles should be read from the disk. - s.rowsLock.Unlock() return nil } @@ -381,6 +380,9 @@ func (s *profileStore) writeRowGroups(path string, rowGroups []parquet.RowGroup) readers[i] = rg.Rows() } n, numRowGroups, err = phlareparquet.CopyAsRowGroups(s.writer, schemav1.NewMergeProfilesRowReader(readers), s.cfg.MaxBufferRowCount) + if err != nil { + return 0, 0, err + } if err := s.writer.Close(); err != nil { return 0, 0, err @@ -450,22 +452,22 @@ func newRowGroupOnDisk(path string) (*rowGroupOnDisk, error) { // now open the row group file, so we are able to read the row group back in r.file, err = os.Open(path) if err != nil { - return nil, errors.Wrapf(err, "opening row groups segment file %s", path) + return nil, fmt.Errorf("opening row groups segment file %s: %w", path, err) } stats, err := r.file.Stat() if err != nil { - return nil, errors.Wrapf(err, "getting stat of row groups segment file %s", path) + return nil, fmt.Errorf("getting stat of row groups segment file %s: %w", path, err) } segmentParquet, err := parquet.OpenFile(r.file, stats.Size()) if err != nil { - return nil, errors.Wrapf(err, "reading parquet of row groups segment file %s", path) + return nil, fmt.Errorf("reading parquet of row groups segment file %s: %w", path, err) } rowGroups := segmentParquet.RowGroups() if len(rowGroups) != 1 { - return nil, errors.Wrapf(err, "segement file expected to have exactly one row group (actual %d)", len(rowGroups)) + return nil, fmt.Errorf("segement file expected to have exactly one row group (actual %d)", len(rowGroups)) } r.RowGroup = rowGroups[0] @@ -495,7 +497,7 @@ func (r *rowGroupOnDisk) Close() error { } if err := os.Remove(r.file.Name()); err != nil { - return errors.Wrap(err, "deleting row group segment file") + return fmt.Errorf("deleting row group segment file: %w", err) } return nil @@ -513,6 +515,7 @@ type seriesIDRowsRewriter struct { parquet.Rows pos int64 seriesIndexes rowRangesWithSeriesIndex + searchHint int // speed up getSeriesIndex() } func (r *seriesIDRowsRewriter) SeekToRow(pos int64) error { @@ -534,19 +537,20 @@ var colIdxSeriesIndex = func() int { func (r *seriesIDRowsRewriter) ReadRows(rows []parquet.Row) (int, error) { n, err := r.Rows.ReadRows(rows) - if err != nil { + if err != nil && err != io.EOF { return n, err } - + // sh for next call of getSeriesIndex + sh := r.searchHint for pos, row := range rows[:n] { // actual row num rowNum := r.pos + int64(pos) - row[colIdxSeriesIndex] = parquet.ValueOf(r.seriesIndexes.getSeriesIndex(rowNum)).Level(0, 0, colIdxSeriesIndex) + row[colIdxSeriesIndex] = parquet.ValueOf(r.seriesIndexes.getSeriesIndex(rowNum, &sh)).Level(0, 0, colIdxSeriesIndex) } - + r.searchHint = sh r.pos += int64(n) - return n, nil + return n, err } func copySlice[T any](in []T) []T { diff --git a/pkg/phlaredb/profile_store_test.go b/pkg/phlaredb/profile_store_test.go index 4d677f4412..51d9f711bf 100644 --- a/pkg/phlaredb/profile_store_test.go +++ b/pkg/phlaredb/profile_store_test.go @@ -23,12 +23,12 @@ import ( profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - phlareobjclient "github.com/grafana/pyroscope/pkg/objstore/client" - phlarecontext "github.com/grafana/pyroscope/pkg/phlare/context" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + phlareobjclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" ) const ( @@ -356,7 +356,7 @@ func BenchmarkFlush(b *testing.B) { } } -func ingestThreeProfileStreams(ctx context.Context, i int, ingest func(context.Context, *profilev1.Profile, uuid.UUID, ...*typesv1.LabelPair) error) error { +func ingestThreeProfileStreams(ctx context.Context, i int, ingest func(context.Context, *profilev1.Profile, uuid.UUID, []*typesv1.ProfileAnnotation, ...*typesv1.LabelPair) error) error { p := testhelper.NewProfileBuilder(time.Second.Nanoseconds() * int64(i)) p.CPUProfile() p.WithLabels( @@ -367,7 +367,7 @@ func ingestThreeProfileStreams(ctx context.Context, i int, ingest func(context.C p.ForStacktraceString("func1", "func2").AddSamples(10) p.ForStacktraceString("func1").AddSamples(20) - return ingest(ctx, p.Profile, p.UUID, p.Labels...) + return ingest(ctx, p.Profile, p.UUID, nil, p.Labels...) } // TestProfileStore_Querying @@ -385,7 +385,7 @@ func TestProfileStore_Querying(t *testing.T) { head.profiles.cfg = &ParquetConfig{MaxRowGroupBytes: 128000, MaxBufferRowCount: 3} for i := 0; i < 9; i++ { - require.NoError(t, ingestThreeProfileStreams(ctx, i, func(ctx context.Context, p *profilev1.Profile, u uuid.UUID, lp ...*typesv1.LabelPair) error { + require.NoError(t, ingestThreeProfileStreams(ctx, i, func(ctx context.Context, p *profilev1.Profile, u uuid.UUID, a []*typesv1.ProfileAnnotation, lp ...*typesv1.LabelPair) error { defer func() { // wait for the profile to be flushed // todo(cyriltovena): We shouldn't need this, but when calling head.Queriers(), flushing row group and then querying using the queriers previously returned we will miss the new headDiskQuerier. @@ -393,7 +393,7 @@ func TestProfileStore_Querying(t *testing.T) { time.Sleep(time.Millisecond) } }() - return head.Ingest(ctx, p, u, lp...) + return head.Ingest(ctx, p, u, a, lp...) })) } @@ -521,10 +521,10 @@ func TestProfileStore_Querying(t *testing.T) { result, err := bidi.Receive() require.NoError(t, err) - at, err := phlaremodel.UnmarshalTree(result.Result.TreeBytes) + at, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](result.Result.TreeBytes) require.NoError(t, err) - et := new(phlaremodel.Tree) + et := new(phlaremodel.FunctionNameTree) et.InsertStack(90, "func2", "func1") et.InsertStack(180, "func1") diff --git a/pkg/phlaredb/profile_test.go b/pkg/phlaredb/profile_test.go index 19f309f7a3..9bb9a78758 100644 --- a/pkg/phlaredb/profile_test.go +++ b/pkg/phlaredb/profile_test.go @@ -15,10 +15,10 @@ import ( ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - v1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) func TestIndex(t *testing.T) { @@ -258,7 +258,7 @@ func TestProfileIndex_Add_OutOfOrder(t *testing.T) { "job", "a", ).ForStacktraceString("foo", "bar", "baz", fmt.Sprintf("iteration%d", idx)).AddSamples(1) - require.NoError(t, head.Ingest(ctx, p.Profile, uuid.New())) + require.NoError(t, head.Ingest(ctx, p.Profile, uuid.New(), nil)) } index := head.profiles.index @@ -279,3 +279,66 @@ func TestProfileIndex_Add_OutOfOrder(t *testing.T) { require.Equal(t, []int64{20, 50, 80, 100, 110}, tsOrder) } + +func Test_rowRangesWithSeriesIndex_getSeriesIndex(t *testing.T) { + testCases := []struct { + name string + ranges rowRangesWithSeriesIndex + rowNum int64 + searchHint int + expectSeriesIndex uint32 + expectPanic bool + }{ + { + name: "hit 1", + ranges: rowRangesWithSeriesIndex{ + {rowRange: &rowRange{rowNum: 0, length: 5}, seriesIndex: 1}, + {rowRange: &rowRange{rowNum: 5, length: 5}, seriesIndex: 2}, + }, + rowNum: 4, + searchHint: 0, + expectSeriesIndex: 1, + }, + { + name: "hit 2", + ranges: rowRangesWithSeriesIndex{ + {rowRange: &rowRange{rowNum: 0, length: 5}, seriesIndex: 1}, + {rowRange: &rowRange{rowNum: 5, length: 5}, seriesIndex: 2}, + }, + rowNum: 6, + searchHint: 1, + expectSeriesIndex: 2, + }, + { + name: "nil rowRange skipped", + ranges: rowRangesWithSeriesIndex{ + {rowRange: nil, seriesIndex: 1}, + {rowRange: &rowRange{rowNum: 10, length: 5}, seriesIndex: 2}, + }, + rowNum: 12, + searchHint: 0, + expectSeriesIndex: 2, + }, + { + name: "not found panics", + ranges: rowRangesWithSeriesIndex{{rowRange: &rowRange{rowNum: 0, length: 2}, seriesIndex: 1}}, + rowNum: 10, + searchHint: 0, + expectPanic: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + searchHint := tc.searchHint + if tc.expectPanic { + assert.Panics(t, func() { + _ = tc.ranges.getSeriesIndex(tc.rowNum, &searchHint) + }) + } else { + idx := tc.ranges.getSeriesIndex(tc.rowNum, &searchHint) + assert.Equal(t, tc.expectSeriesIndex, idx) + } + }) + } +} diff --git a/pkg/phlaredb/profiles.go b/pkg/phlaredb/profiles.go index e8445945ce..af4da1abd8 100644 --- a/pkg/phlaredb/profiles.go +++ b/pkg/phlaredb/profiles.go @@ -2,28 +2,27 @@ package phlaredb import ( "context" + "errors" "fmt" "sort" "sync" - "github.com/gogo/status" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/storage" "github.com/samber/lo" "go.uber.org/atomic" "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" ) // delta encoding for ranges @@ -40,13 +39,20 @@ type rowRangeWithSeriesIndex struct { // those need to be strictly ordered type rowRangesWithSeriesIndex []rowRangeWithSeriesIndex -func (s rowRangesWithSeriesIndex) getSeriesIndex(rowNum int64) uint32 { - for _, rg := range s { +// getSeriesIndex returns the series index for a given row number. +// searchHint is the hint for the index to start searching from, it should be passed to next call of this function. +func (s rowRangesWithSeriesIndex) getSeriesIndex(rowNum int64, searchHint *int) uint32 { + if *searchHint < 0 || *searchHint >= len(s) { + *searchHint = 0 + } + for i := *searchHint; i < len(s); i++ { + rg := s[i] // it is possible that the series is not existing if rg.rowRange == nil { continue } if rg.rowNum <= rowNum && rg.rowNum+int64(rg.length) > rowNum { + *searchHint = i return rg.seriesIndex } } @@ -209,9 +215,9 @@ func (pi *profilesIndex) Add(ps *schemav1.InMemoryProfile, lbs phlaremodel.Label } func (pi *profilesIndex) selectMatchingFPs(ctx context.Context, params *ingestv1.SelectProfilesRequest) ([]model.Fingerprint, error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "selectMatchingFPs - Index") + sp, _ := tracing.StartSpanFromContext(ctx, "selectMatchingFPs - Index") defer sp.Finish() - selectors, err := parser.ParseMetricSelector(params.LabelSelector) + selectors, err := phlaremodel.ParseMetricSelector(params.LabelSelector) if err != nil { return nil, status.Error(codes.InvalidArgument, "failed to parse label selectors: "+err.Error()) } @@ -260,7 +266,7 @@ func (pi *profilesIndex) selectMatchingRowRanges(ctx context.Context, params *in map[model.Fingerprint]phlaremodel.Labels, error, ) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "selectMatchingRowRanges - Index") + sp, ctx := tracing.StartSpanFromContext(ctx, "selectMatchingRowRanges - Index") defer sp.Finish() ids, err := pi.selectMatchingFPs(ctx, params) @@ -333,6 +339,10 @@ func (p ProfileWithLabels) Total() int64 { return int64(p.profile.TotalValue) } +func (p ProfileWithLabels) Annotations() schemav1.Annotations { + return p.profile.Annotations +} + type SeriesIterator struct { iter.Iterator[*schemav1.InMemoryProfile] curr ProfileWithLabels diff --git a/pkg/phlaredb/querier.go b/pkg/phlaredb/querier.go index f8a286950a..9a477f05fa 100644 --- a/pkg/phlaredb/querier.go +++ b/pkg/phlaredb/querier.go @@ -6,9 +6,9 @@ import ( "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" ) // IndexReader provides reading access of serialized index data. @@ -18,13 +18,9 @@ type IndexReader interface { Checksum() uint32 - // Symbols return an iterator over sorted string symbols that may occur in - // series' labels and indices. It is not safe to use the returned strings - // beyond the lifetime of the index reader. - Symbols() index.StringIter - - // SortedLabelValues returns sorted possible label values. - SortedLabelValues(name string, matchers ...*labels.Matcher) ([]string, error) + // SymbolTable returns all symbols in the index as owned strings safe to use + // beyond the reader's lifetime. + SymbolTable() ([]string, error) // LabelValues returns possible label values which may not be sorted. LabelValues(name string, matchers ...*labels.Matcher) ([]string, error) @@ -35,10 +31,16 @@ type IndexReader interface { // during background garbage collections. Input values must be sorted. Postings(name string, shard *index.ShardAnnotation, values ...string) (index.Postings, error) + // PostingsForLabelMatching returns merged postings for all values of label + // name for which match returns true. The YoloString passed to match aliases + // the index buffer and must not be retained beyond the call. + PostingsForLabelMatching(name string, shard *index.ShardAnnotation, match func(index.YoloString) bool) (index.Postings, error) + // Series populates the given labels and chunk metas for the series identified // by the reference. // Returns storage.ErrNotFound if the ref does not resolve to a known series. Series(ref storage.SeriesRef, lset *phlaremodel.Labels, chks *[]index.ChunkMeta) (uint64, error) + SeriesBy(ref storage.SeriesRef, lset *phlaremodel.Labels, chks *[]index.ChunkMeta, by ...string) (uint64, error) // LabelNames returns all the unique label names present in the index in sorted order. LabelNames(matchers ...*labels.Matcher) ([]string, error) @@ -157,54 +159,10 @@ func postingsForMatcher(ix IndexReader, shard *index.ShardAnnotation, m *labels. } } - vals, err := ix.LabelValues(m.Name) - if err != nil { - return nil, err - } - - var res []string - lastVal, isSorted := "", true - for _, val := range vals { - if m.Matches(val) { - res = append(res, val) - if isSorted && val < lastVal { - isSorted = false - } - lastVal = val - } - } - - if len(res) == 0 { - return index.EmptyPostings(), nil - } - - if !isSorted { - sort.Strings(res) - } - return ix.Postings(m.Name, shard, res...) + return ix.PostingsForLabelMatching(m.Name, shard, func(v index.YoloString) bool { return m.Matches(v.String) }) } // inversePostingsForMatcher returns the postings for the series with the label name set but not matching the matcher. func inversePostingsForMatcher(ix IndexReader, shard *index.ShardAnnotation, m *labels.Matcher) (index.Postings, error) { - vals, err := ix.LabelValues(m.Name) - if err != nil { - return nil, err - } - - var res []string - lastVal, isSorted := "", true - for _, val := range vals { - if !m.Matches(val) { - res = append(res, val) - if isSorted && val < lastVal { - isSorted = false - } - lastVal = val - } - } - - if !isSorted { - sort.Strings(res) - } - return ix.Postings(m.Name, shard, res...) + return ix.PostingsForLabelMatching(m.Name, shard, func(v index.YoloString) bool { return !m.Matches(v.String) }) } diff --git a/pkg/phlaredb/querier_test.go b/pkg/phlaredb/querier_test.go index 95c5124eec..6f1adc5785 100644 --- a/pkg/phlaredb/querier_test.go +++ b/pkg/phlaredb/querier_test.go @@ -13,9 +13,9 @@ import ( "github.com/stretchr/testify/require" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - v1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" ) func TestQueryIndex(t *testing.T) { diff --git a/pkg/phlaredb/query/iters.go b/pkg/phlaredb/query/iters.go index aa1801a354..c8e3ff24b2 100644 --- a/pkg/phlaredb/query/iters.go +++ b/pkg/phlaredb/query/iters.go @@ -10,11 +10,12 @@ import ( "sync" "github.com/grafana/dskit/multierror" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/log" + "github.com/grafana/dskit/tracing" "github.com/parquet-go/parquet-go" + "go.opentelemetry.io/otel/attribute" + oteltrace "go.opentelemetry.io/otel/trace" - "github.com/grafana/pyroscope/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/iter" ) const MaxDefinitionLevel = 5 @@ -445,68 +446,61 @@ func NewBinaryJoinIterator(definitionLevel int, left, right Iterator) *BinaryJoi } } -// nextOrSeek will use next if the iterator is exactly one row aways -func (bj *BinaryJoinIterator) nextOrSeek(to RowNumberWithDefinitionLevel, it Iterator) bool { - oldResult := it.At() - defer iteratorResultPoolPut(oldResult) - // Seek when definition level is higher then 0, there is not previous iteration or when the difference between current position and to is not 1 - if to.DefinitionLevel != 0 || oldResult == nil || to.RowNumber[0] != (oldResult.RowNumber[0]-1) { - return it.Seek(to) +// nextOrSeek advances it toward the target's position. +// If to is nil (not yet positioned), or to is at/behind it, it calls Next. +// If to is exactly one row ahead, it calls Next as an optimization. +// Otherwise, it calls Seek. +func (bj *BinaryJoinIterator) nextOrSeek(it Iterator, to *IteratorResult) bool { + from := it.At() + + var ok bool + switch { + // If to points nowhere, we can't seek, hence we need to next(). + case to == nil: + ok = it.Next() + // If from points nowhere, we directly seek towards to. + case from == nil: + ok = it.Seek(RowNumberWithDefinitionLevel{to.RowNumber, bj.definitionLevel}) + // Optimized to do next if we are just 1 position behind it (only for definitionLevels of 0). + case bj.definitionLevel == 0 && to.RowNumber[0] == from.RowNumber[0]+1: + ok = it.Next() + default: + ok = it.Seek(RowNumberWithDefinitionLevel{to.RowNumber, bj.definitionLevel}) } - return it.Next() + + // Return the old result to the pool if the iterator replaced it with a new one. + if from != nil && from != it.At() { + iteratorResultPoolPut(from) + } + return ok +} + +func (bj *BinaryJoinIterator) rowsMatch() bool { + l, r := bj.left.At(), bj.right.At() + return l != nil && r != nil && CompareRowNumbers(bj.definitionLevel, l.RowNumber, r.RowNumber) == 0 } func (bj *BinaryJoinIterator) makeResult() { + l, r := bj.left.At(), bj.right.At() bj.res.Reset() bj.res.RowNumber = EmptyRowNumber() - bj.res.RowNumber[0] = bj.left.At().RowNumber[0] - bj.res.Append(bj.left.At()) - bj.res.Append(bj.right.At()) + bj.res.RowNumber[0] = l.RowNumber[0] + bj.res.Append(l) + bj.res.Append(r) } func (bj *BinaryJoinIterator) Next() bool { - var r *IteratorResult + cur, other := bj.left, bj.right for { - if r != nil { - iteratorResultPoolPut(r) - } - r = bj.left.At() - if !bj.left.Next() { - bj.err = bj.left.Err() - return false - } - - // now seek the right iterator to the left position - if !bj.nextOrSeek(RowNumberWithDefinitionLevel{bj.left.At().RowNumber, bj.definitionLevel}, bj.right) { - bj.err = bj.right.Err() + if !bj.nextOrSeek(cur, other.At()) { + bj.err = cur.Err() return false } - - if cmp := CompareRowNumbers(bj.definitionLevel, bj.left.At().RowNumber, bj.right.At().RowNumber); cmp == 0 { - // we have a found an element + if bj.rowsMatch() { bj.makeResult() return true - } else if cmp < 0 { - // left is smaller, so we need to seek the left iterator to the right position - if !bj.nextOrSeek(RowNumberWithDefinitionLevel{bj.right.At().RowNumber, bj.definitionLevel}, bj.left) { - bj.err = bj.left.Err() - return false - } - - if cmp := CompareRowNumbers(bj.definitionLevel, bj.left.At().RowNumber, bj.right.At().RowNumber); cmp == 0 { - bj.makeResult() - return true - } - - } else { - panic(fmt.Sprintf( - "bug in iterator during join: the right iterator cannot be smaller than the left one, as it just has been Seeked beyond left=%v %T right=%v %T", - bj.left.At().RowNumber[0], - bj.left, - bj.right.At().RowNumber[0], - bj.right, - )) } + cur, other = other, cur } } @@ -519,17 +513,17 @@ func (bj *BinaryJoinIterator) Seek(to RowNumberWithDefinitionLevel) bool { bj.err = bj.left.Err() return false } + // move right to at least the row left is currently on + to.RowNumber = bj.left.At().RowNumber if !bj.right.Seek(to) { bj.err = bj.right.Err() return false } - // if there is a match right away return true if cmp := CompareRowNumbers(bj.definitionLevel, bj.left.At().RowNumber, bj.right.At().RowNumber); cmp == 0 { bj.makeResult() return true } - // if not look for the next match return bj.Next() } @@ -844,7 +838,7 @@ type SyncIterator struct { // Status ctx context.Context cancel func() - span opentracing.Span + span oteltrace.Span metrics *Metrics curr RowNumber currRowGroup parquet.RowGroup @@ -900,10 +894,12 @@ func NewSyncIterator(ctx context.Context, rgs []parquet.RowGroup, column int, co rn.Skip(rg.NumRows()) } - span, ctx := opentracing.StartSpanFromContext(ctx, "syncIterator", opentracing.Tags{ - "columnIndex": column, - "column": columnName, - }) + _, ctx = tracing.StartSpanFromContext(ctx, "syncIterator") + span := oteltrace.SpanFromContext(ctx) + span.SetAttributes( + attribute.Int("columnIndex", column), + attribute.String("column", columnName), + ) ctx, cancel := context.WithCancel(ctx) @@ -948,13 +944,18 @@ func (c *SyncIterator) Next() bool { // SeekTo moves this iterator to the next result that is greater than // or equal to the given row number (and based on the given definition level) func (c *SyncIterator) Seek(to RowNumberWithDefinitionLevel) bool { - if c.seekRowGroup(to.RowNumber, to.DefinitionLevel) { + done, err := c.seekRowGroup(to.RowNumber, to.DefinitionLevel) + if err != nil { + c.err = err + return false + } + if done { c.res = nil c.err = nil return false } - done, err := c.seekPages(to.RowNumber, to.DefinitionLevel) + done, err = c.seekPages(to.RowNumber, to.DefinitionLevel) if err != nil { c.res = nil c.err = err @@ -1007,7 +1008,7 @@ func (c *SyncIterator) popRowGroup() (parquet.RowGroup, RowNumber, RowNumber) { // seekRowGroup skips ahead to the row group that could contain the value at the // desired row number. Does nothing if the current row group is already the correct one. -func (c *SyncIterator) seekRowGroup(seekTo RowNumber, definitionLevel int) (done bool) { +func (c *SyncIterator) seekRowGroup(seekTo RowNumber, definitionLevel int) (done bool, err error) { if c.currRowGroup != nil && CompareRowNumbers(definitionLevel, seekTo, c.currRowGroupMax) >= 0 { // Done with this row group c.closeCurrRowGroup() @@ -1017,15 +1018,19 @@ func (c *SyncIterator) seekRowGroup(seekTo RowNumber, definitionLevel int) (done rg, min, max := c.popRowGroup() if rg == nil { - return true + return true, nil } if CompareRowNumbers(definitionLevel, seekTo, max) != -1 { continue } - cc := rg.ColumnChunks()[c.column] - if c.filter != nil && !c.filter.KeepColumnChunk(cc) { + ci, err := rg.ColumnChunks()[c.column].ColumnIndex() + if err != nil { + return true, err + } + + if c.filter != nil && !c.filter.KeepColumnChunk(ci) { continue } @@ -1033,7 +1038,7 @@ func (c *SyncIterator) seekRowGroup(seekTo RowNumber, definitionLevel int) (done c.setRowGroup(rg, min, max) } - return c.currRowGroup == nil + return c.currRowGroup == nil, nil } // seekPages skips ahead in the current row group to the page that could contain the value at @@ -1075,11 +1080,12 @@ func (c *SyncIterator) seekPages(seekTo RowNumber, definitionLevel int) (done bo return true, err } c.metrics.pageReadsTotal.WithLabelValues(c.table, c.columnName).Add(1) - c.span.LogFields( - log.String("msg", "reading page (seekPages)"), - log.Int64("page_num_values", pg.NumValues()), - log.Int64("page_size", pg.Size()), - ) + if c.span.IsRecording() { + c.span.AddEvent("reading page (seekPages)", oteltrace.WithAttributes( + attribute.Int64("page_num_values", pg.NumValues()), + attribute.Int64("page_size", pg.Size()), + )) + } // Skip based on row number? newRN := c.curr @@ -1125,8 +1131,11 @@ func (c *SyncIterator) next() (RowNumber, *parquet.Value, error) { return EmptyRowNumber(), nil, nil } - cc := rg.ColumnChunks()[c.column] - if c.filter != nil && !c.filter.KeepColumnChunk(cc) { + ci, err := rg.ColumnChunks()[c.column].ColumnIndex() + if err != nil { + return EmptyRowNumber(), nil, err + } + if c.filter != nil && !c.filter.KeepColumnChunk(ci) { continue } @@ -1144,11 +1153,12 @@ func (c *SyncIterator) next() (RowNumber, *parquet.Value, error) { return EmptyRowNumber(), nil, err } c.metrics.pageReadsTotal.WithLabelValues(c.table, c.columnName).Add(1) - c.span.LogFields( - log.String("msg", "reading page (next)"), - log.Int64("page_num_values", pg.NumValues()), - log.Int64("page_size", pg.Size()), - ) + if c.span.IsRecording() { + c.span.AddEvent("reading page (next)", oteltrace.WithAttributes( + attribute.Int64("page_num_values", pg.NumValues()), + attribute.Int64("page_size", pg.Size()), + )) + } if c.filter != nil && !c.filter.KeepPage(pg) { // This page filtered out @@ -1266,12 +1276,14 @@ func (c *SyncIterator) Close() error { c.cancel() c.closeCurrRowGroup() - c.span.SetTag("inspectedColumnChunks", c.filter.InspectedColumnChunks.Load()) - c.span.SetTag("inspectedPages", c.filter.InspectedPages.Load()) - c.span.SetTag("inspectedValues", c.filter.InspectedValues.Load()) - c.span.SetTag("keptColumnChunks", c.filter.KeptColumnChunks.Load()) - c.span.SetTag("keptPages", c.filter.KeptPages.Load()) - c.span.SetTag("keptValues", c.filter.KeptValues.Load()) - c.span.Finish() + c.span.SetAttributes( + attribute.Int64("inspectedColumnChunks", c.filter.InspectedColumnChunks.Load()), + attribute.Int64("inspectedPages", c.filter.InspectedPages.Load()), + attribute.Int64("inspectedValues", c.filter.InspectedValues.Load()), + attribute.Int64("keptColumnChunks", c.filter.KeptColumnChunks.Load()), + attribute.Int64("keptPages", c.filter.KeptPages.Load()), + attribute.Int64("keptValues", c.filter.KeptValues.Load()), + ) + c.span.End() return nil } diff --git a/pkg/phlaredb/query/iters_test.go b/pkg/phlaredb/query/iters_test.go index eb64a17b37..ae480fa509 100644 --- a/pkg/phlaredb/query/iters_test.go +++ b/pkg/phlaredb/query/iters_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/iter" ) type makeTestIterFn func(pf *parquet.File, idx int, filter Predicate, selectAs string) Iterator @@ -307,19 +307,19 @@ func createTestFile(t testing.TB, count int) *parquet.File { return pf } -func createProfileLikeFile(t testing.TB, count int) *parquet.File { - type T struct { - SeriesID uint32 - TimeNanos int64 - } +type SeriesIndexTimeNanosPair struct { + SeriesID uint32 + TimeNanos int64 +} +func createProfileLikeFile(t testing.TB, count int) (*parquet.File, []SeriesIndexTimeNanosPair) { // every row group is ordered by serieID and then time nanos // time is always increasing between rowgroups rowGroups := 10 series := 8 - rows := make([]T, count) + rows := make([]SeriesIndexTimeNanosPair, count) for i := range rows { rowsPerRowGroup := count / rowGroups @@ -327,14 +327,13 @@ func createProfileLikeFile(t testing.TB, count int) *parquet.File { rowGroupNum := i / rowsPerRowGroup seriesID := uint32(i % (count / rowGroups) / (rowsPerRowGroup / series)) - rows[i] = T{ + rows[i] = SeriesIndexTimeNanosPair{ SeriesID: seriesID, TimeNanos: int64(i%seriesPerRowGroup+rowGroupNum*seriesPerRowGroup) * 1000, } - } - return createFileWith[T](t, rows, rowGroups) + return createFileWith[SeriesIndexTimeNanosPair](t, rows, rowGroups), rows } func createFileWith[T any](t testing.TB, rows []T, rowGroups int) *parquet.File { @@ -369,7 +368,7 @@ func createFileWith[T any](t testing.TB, rows []T, rowGroups int) *parquet.File func TestBinaryJoinIterator(t *testing.T) { rowCount := 1600 - pf := createProfileLikeFile(t, rowCount) + pf, _ := createProfileLikeFile(t, rowCount) for _, tc := range []struct { name string @@ -433,8 +432,8 @@ func TestBinaryJoinIterator(t *testing.T) { reg := prometheus.NewRegistry() metrics := NewMetrics(reg) - metrics.pageReadsTotal.WithLabelValues("ts", "SeriesId").Add(0) - metrics.pageReadsTotal.WithLabelValues("ts", "TimeNanos").Add(0) + metrics.pageReadsTotal.WithLabelValues("seriesindextimenanospairs", "SeriesId").Add(0) + metrics.pageReadsTotal.WithLabelValues("seriesindextimenanospairs", "TimeNanos").Add(0) ctx = AddMetricsToContext(ctx, metrics) seriesIt := NewSyncIterator(ctx, pf.RowGroups(), 0, "SeriesId", 1000, tc.seriesPredicate, "SeriesId") @@ -460,13 +459,89 @@ func TestBinaryJoinIterator(t *testing.T) { ` # HELP pyroscopedb_page_reads_total Total number of pages read while querying # TYPE pyroscopedb_page_reads_total counter - pyroscopedb_page_reads_total{column="SeriesId",table="ts"} %d - pyroscopedb_page_reads_total{column="TimeNanos",table="ts"} %d + pyroscopedb_page_reads_total{column="SeriesId",table="seriesindextimenanospairs"} %d + pyroscopedb_page_reads_total{column="TimeNanos",table="seriesindextimenanospairs"} %d `, tc.seriesPageReads, tc.timePageReads))), "pyroscopedb_page_reads_total")) }) } } +func TestBinaryJoinIteratorMultiplePredicates(t *testing.T) { + // This test was failing for ~4% of samples with the previous BinaryJoinIterator implementation + rowCount := 1600 + pf, pairs := createProfileLikeFile(t, rowCount) + + t.Run("Double predicate, all possible pairs", func(t *testing.T) { + for _, pair := range pairs { + ctx, cancel := context.WithCancel(context.Background()) + + seriesPredicate := NewMapPredicate(map[int64]struct{}{int64(pair.SeriesID): {}}) + timePredicate := NewIntBetweenPredicate(pair.TimeNanos, pair.TimeNanos) + seriesIt := NewSyncIterator(ctx, pf.RowGroups(), 0, "SeriesId", 1000, seriesPredicate, "SeriesId") + timeIt := NewSyncIterator(ctx, pf.RowGroups(), 1, "TimeNanos", 1000, timePredicate, "TimeNanos") + + it := NewBinaryJoinIterator( + 0, + seriesIt, + timeIt, + ) + + results := 0 + for it.Next() { + results++ + } + require.NoError(t, it.Err()) + + require.NoError(t, it.Close()) + + require.Equal(t, 1, results, "pair=%v can't be found", pair) + cancel() + } + }) +} + +func TestBinaryJoinIteratorSeek(t *testing.T) { + // This test was failing with the previous BinaryJoinIterator implementation + rows := []SeriesIndexTimeNanosPair{ + {SeriesID: 1, TimeNanos: 1000}, + {SeriesID: 2, TimeNanos: 2000}, + {SeriesID: 3, TimeNanos: 3000}, + {SeriesID: 4, TimeNanos: 1000}, + {SeriesID: 1, TimeNanos: 1000}, + } + pf := createFileWith[SeriesIndexTimeNanosPair](t, rows, 1) + t.Run("Seek multiple predicates", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + seriesPredicate := NewMapPredicate(map[int64]struct{}{1: {}}) + timePredicate := NewIntBetweenPredicate(1000, 1000) + seriesIt := NewSyncIterator(ctx, pf.RowGroups(), 0, "SeriesId", 1000, seriesPredicate, "SeriesId") + timeIt := NewSyncIterator(ctx, pf.RowGroups(), 1, "TimeNanos", 1000, timePredicate, "TimeNanos") + + it := NewBinaryJoinIterator( + 0, + seriesIt, + timeIt, + ) + + results := 0 + if it.Next() { // Iterator at first (1, 1000) + results++ + } + require.NoError(t, it.Err()) + rowNumber := it.At().RowNumber + rowNumber[0] += 2 // seeking to (3, 3000) + if it.Seek(RowNumberWithDefinitionLevel{RowNumber: rowNumber}) { // Iterator at second (1, 1000) + results++ + } + require.NoError(t, it.Err()) + + require.Equal(t, 2, results) + require.NoError(t, it.Close()) + }) +} + type rowGetter int64 func (r rowGetter) RowNumber() int64 { diff --git a/pkg/phlaredb/query/metrics.go b/pkg/phlaredb/query/metrics.go index 1fc6452d3c..1004f01184 100644 --- a/pkg/phlaredb/query/metrics.go +++ b/pkg/phlaredb/query/metrics.go @@ -5,7 +5,7 @@ import ( "github.com/prometheus/client_golang/prometheus" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) type contextKey uint8 diff --git a/pkg/phlaredb/query/predicates.go b/pkg/phlaredb/query/predicates.go index 528464e01d..c00a7f4dd6 100644 --- a/pkg/phlaredb/query/predicates.go +++ b/pkg/phlaredb/query/predicates.go @@ -12,7 +12,7 @@ import ( // Predicate is a pushdown predicate that can be applied at // the chunk, page, and value levels. type Predicate interface { - KeepColumnChunk(cc pq.ColumnChunk) bool + KeepColumnChunk(ci pq.ColumnIndex) bool KeepPage(page pq.Page) bool KeepValue(pq.Value) bool } @@ -34,8 +34,8 @@ func NewStringInPredicate(ss []string) Predicate { return p } -func (p *StringInPredicate) KeepColumnChunk(cc pq.ColumnChunk) bool { - if ci := cc.ColumnIndex(); ci != nil { +func (p *StringInPredicate) KeepColumnChunk(ci pq.ColumnIndex) bool { + if ci != nil { for _, subs := range p.ss { for i := 0; i < ci.NumPages(); i++ { @@ -101,7 +101,7 @@ func NewSubstringPredicate(substring string) *SubstringPredicate { } } -func (p *SubstringPredicate) KeepColumnChunk(_ pq.ColumnChunk) bool { +func (p *SubstringPredicate) KeepColumnChunk(_ pq.ColumnIndex) bool { // Reset match cache on each row group change p.matches = make(map[string]bool, len(p.matches)) @@ -151,8 +151,8 @@ func NewIntBetweenPredicate(min, max int64) *IntBetweenPredicate { return &IntBetweenPredicate{min, max} } -func (p *IntBetweenPredicate) KeepColumnChunk(c pq.ColumnChunk) bool { - if ci := c.ColumnIndex(); ci != nil { +func (p *IntBetweenPredicate) KeepColumnChunk(ci pq.ColumnIndex) bool { + if ci != nil { for i := 0; i < ci.NumPages(); i++ { min := ci.MinValue(i).Int64() max := ci.MaxValue(i).Int64() @@ -184,8 +184,8 @@ func NewEqualInt64Predicate(value int64) EqualInt64Predicate { return EqualInt64Predicate(value) } -func (p EqualInt64Predicate) KeepColumnChunk(c pq.ColumnChunk) bool { - if ci := c.ColumnIndex(); ci != nil { +func (p EqualInt64Predicate) KeepColumnChunk(ci pq.ColumnIndex) bool { + if ci != nil { for i := 0; i < ci.NumPages(); i++ { min := ci.MinValue(i).Int64() max := ci.MaxValue(i).Int64() @@ -223,10 +223,10 @@ type InstrumentedPredicate struct { var _ Predicate = (*InstrumentedPredicate)(nil) -func (p *InstrumentedPredicate) KeepColumnChunk(c pq.ColumnChunk) bool { +func (p *InstrumentedPredicate) KeepColumnChunk(ci pq.ColumnIndex) bool { p.InspectedColumnChunks.Inc() - if p.pred == nil || p.pred.KeepColumnChunk(c) { + if p.pred == nil || p.pred.KeepColumnChunk(ci) { p.KeptColumnChunks.Inc() return true } @@ -282,8 +282,8 @@ func NewMapPredicate[K constraints.Integer, V any](m map[K]V) Predicate { } } -func (m *mapPredicate[K, V]) KeepColumnChunk(c pq.ColumnChunk) bool { - return m.inbetweenPred.KeepColumnChunk(c) +func (m *mapPredicate[K, V]) KeepColumnChunk(ci pq.ColumnIndex) bool { + return m.inbetweenPred.KeepColumnChunk(ci) } func (m *mapPredicate[K, V]) KeepPage(page pq.Page) bool { diff --git a/pkg/phlaredb/query/repeated.go b/pkg/phlaredb/query/repeated.go index 3c4929ba87..966a0ca842 100644 --- a/pkg/phlaredb/query/repeated.go +++ b/pkg/phlaredb/query/repeated.go @@ -9,12 +9,14 @@ import ( "time" "github.com/grafana/dskit/multierror" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" + "github.com/grafana/dskit/tracing" "github.com/parquet-go/parquet-go" "github.com/prometheus/client_golang/prometheus" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + oteltrace "go.opentelemetry.io/otel/trace" - "github.com/grafana/pyroscope/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/iter" ) type RepeatedRow[T any] struct { @@ -28,12 +30,6 @@ type repeatedRowIterator[T any] struct { } const ( - // Batch size specifies how many rows to be read - // from a column at once. Note that the batched rows - // are buffered in-memory, but not reference pages - // they were read from. - defaultRepeatedRowIteratorBatchSize = 32 - // The value specifies how many individual values to be // read (decoded) from the page. // @@ -44,6 +40,19 @@ const ( // // How many values we expect per a row, the upper boundary? repeatedRowColumnIteratorReadSize = 2 << 10 + + // Batch size specifies how many rows to read from a column at once. + // Note that the batched rows are buffered in-memory but do not reference + // the pages from which they were read. + // + // The default value is extremely conservative, as in most cases, rows are + // quite large (e.g., profile samples). Given that we run many queries + // concurrently, the memory waste outweighs the benefits of the "read-ahead" + // optimization that batching is intended to provide. + // + // However, in cases where the rows are small (such as in time series), + // the value should be increased significantly. + defaultBatchSize = 4 ) func NewRepeatedRowIterator[T any]( @@ -51,14 +60,26 @@ func NewRepeatedRowIterator[T any]( rows iter.Iterator[T], rowGroups []parquet.RowGroup, columns ...int, +) iter.Iterator[RepeatedRow[T]] { + return NewRepeatedRowIteratorBatchSize(ctx, rows, rowGroups, defaultBatchSize, columns...) +} + +func NewRepeatedRowIteratorBatchSize[T any]( + ctx context.Context, + rows iter.Iterator[T], + rowGroups []parquet.RowGroup, + batchSize int64, + columns ...int, ) iter.Iterator[RepeatedRow[T]] { rows, rowNumbers := iter.Tee(rows) return &repeatedRowIterator[T]{ rows: rows, columns: NewMultiColumnIterator(ctx, WrapWithRowNumber(rowNumbers), - defaultRepeatedRowIteratorBatchSize, - rowGroups, columns...), + int(batchSize), + rowGroups, + columns..., + ), } } @@ -174,7 +195,7 @@ var ErrSeekOutOfRange = fmt.Errorf("bug: south row is out of range") type repeatedRowColumnIterator struct { ctx context.Context - span opentracing.Span + span oteltrace.Span rows iter.Iterator[int64] rgs []parquet.RowGroup @@ -217,10 +238,12 @@ func NewRepeatedRowColumnIterator(ctx context.Context, rows iter.Iterator[int64] tableName := strings.ToLower(s.Name()) + "s" columnName := strings.Join(s.Columns()[column], ".") r.initMetrics(getMetricsFromContext(ctx), tableName, columnName) - r.span, r.ctx = opentracing.StartSpanFromContext(ctx, "RepeatedRowColumnIterator", opentracing.Tags{ - "table": tableName, - "column": columnName, - }) + _, r.ctx = tracing.StartSpanFromContext(ctx, "RepeatedRowColumnIterator") + r.span = oteltrace.SpanFromContext(r.ctx) + r.span.SetAttributes( + attribute.String("table", tableName), + attribute.String("column", columnName), + ) return &r } @@ -296,7 +319,8 @@ func (x *repeatedRowColumnIterator) readPage(rn int64) bool { readPageStart := time.Now() if x.page, x.err = x.pages.ReadPage(); x.err != nil { if x.err != io.EOF { - x.span.LogFields(otlog.Error(x.err)) + x.span.RecordError(x.err) + x.span.SetStatus(codes.Error, x.err.Error()) return false } x.err = nil @@ -317,14 +341,15 @@ func (x *repeatedRowColumnIterator) readPage(rn int64) bool { x.maxPageRowNum = rn + pageNumRows x.rowsFetched += pageNumRows x.vit.reset(x.page, x.readSize) - x.span.LogFields( - otlog.String("msg", "Page read"), - otlog.Int64("min_rg_row", x.minRGRowNum), - otlog.Int64("max_rg_row", x.maxRGRowNum), - otlog.Int64("seek_row", x.minRGRowNum+rn), - otlog.Int64("page_read_ms", pageReadDurationMs), - otlog.Int64("page_num_rows", pageNumRows), - ) + if x.span.IsRecording() { + x.span.AddEvent("Page read", oteltrace.WithAttributes( + attribute.Int64("min_rg_row", x.minRGRowNum), + attribute.Int64("max_rg_row", x.maxRGRowNum), + attribute.Int64("seek_row", x.minRGRowNum+rn), + attribute.Int64("page_read_ms", pageReadDurationMs), + attribute.Int64("page_num_rows", pageNumRows), + )) + } return true } @@ -335,12 +360,12 @@ func (x *repeatedRowColumnIterator) Close() (err error) { if x.pages != nil { err = x.pages.Close() } - x.span.LogFields( - otlog.Int64("page_bytes", x.pageBytes), - otlog.Int64("rows_fetched", x.rowsFetched), - otlog.Int64("rows_read", x.rowsRead), + x.span.SetAttributes( + attribute.Int64("page_bytes", x.pageBytes), + attribute.Int64("rows_fetched", x.rowsFetched), + attribute.Int64("rows_read", x.rowsRead), ) - x.span.Finish() + x.span.End() return err } diff --git a/pkg/phlaredb/query/repeated_test.go b/pkg/phlaredb/query/repeated_test.go index f187210424..b4ad677906 100644 --- a/pkg/phlaredb/query/repeated_test.go +++ b/pkg/phlaredb/query/repeated_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/iter" ) type repeatedTestRow struct { diff --git a/pkg/phlaredb/query/util.go b/pkg/phlaredb/query/util.go index c87288dea6..ac6cc39a52 100644 --- a/pkg/phlaredb/query/util.go +++ b/pkg/phlaredb/query/util.go @@ -1,6 +1,7 @@ package query import ( + "slices" "strings" "github.com/colega/zeropool" @@ -86,9 +87,7 @@ var parquetValuesPool = zeropool.New(func() []parquet.Value { return nil }) func CloneParquetValues(values []parquet.Value) []parquet.Value { p := parquetValuesPool.Get() - if l := len(values); cap(p) < l { - p = make([]parquet.Value, 0, 2*l) - } + p = slices.Grow(p, len(values)) p = p[:len(values)] for i, v := range values { p[i] = v.Clone() diff --git a/pkg/phlaredb/row_profile.go b/pkg/phlaredb/row_profile.go index a2520660cf..63d1d3c839 100644 --- a/pkg/phlaredb/row_profile.go +++ b/pkg/phlaredb/row_profile.go @@ -4,10 +4,10 @@ import ( "github.com/parquet-go/parquet-go" "github.com/prometheus/common/model" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) type rowProfile struct { diff --git a/pkg/phlaredb/sample_merge.go b/pkg/phlaredb/sample_merge.go index 411a10bf24..a45a86ae22 100644 --- a/pkg/phlaredb/sample_merge.go +++ b/pkg/phlaredb/sample_merge.go @@ -2,26 +2,24 @@ package phlaredb import ( "context" - "sort" "strings" "github.com/grafana/dskit/runutil" - "github.com/opentracing/opentracing-go" + "github.com/grafana/dskit/tracing" "github.com/parquet-go/parquet-go" - "github.com/prometheus/common/model" - "github.com/samber/lo" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/query" - v1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" ) -func (b *singleBlockQuerier) MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeByStacktraces - Block") +func (b *singleBlockQuerier) MergeByStacktraces(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeByStacktraces - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) @@ -41,7 +39,7 @@ func (b *singleBlockQuerier) MergeByStacktraces(ctx context.Context, rows iter.I } func (b *singleBlockQuerier) MergePprof(ctx context.Context, rows iter.Iterator[Profile], maxNodes int64, sts *typesv1.StackTraceSelector) (*profilev1.Profile, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergePprof - Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergePprof - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) @@ -63,7 +61,7 @@ func (b *singleBlockQuerier) MergePprof(ctx context.Context, rows iter.Iterator[ } func (b *singleBlockQuerier) MergeByLabels(ctx context.Context, rows iter.Iterator[Profile], sts *typesv1.StackTraceSelector, by ...string) ([]*typesv1.Series, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "MergeByLabels - Block") + sp, ctx := tracing.StartSpanFromContext(ctx, "MergeByLabels - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) @@ -87,8 +85,8 @@ func (b *singleBlockQuerier) MergeByLabels(ctx context.Context, rows iter.Iterat return mergeByLabelsWithStackTraceSelector(ctx, b.profileSourceTable().file, rows, r, by...) } -func (b *singleBlockQuerier) MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spanSelector phlaremodel.SpanSelector) (*phlaremodel.Tree, error) { - sp, _ := opentracing.StartSpanFromContext(ctx, "MergeBySpans - Block") +func (b *singleBlockQuerier) MergeBySpans(ctx context.Context, rows iter.Iterator[Profile], spanSelector phlaremodel.SpanSelector) (*phlaremodel.FunctionNameTree, error) { + sp, _ := tracing.StartSpanFromContext(ctx, "MergeBySpans - Block") defer sp.Finish() sp.SetTag("block ULID", b.meta.ULID.String()) @@ -114,7 +112,7 @@ type Source interface { func mergeByStacktraces[T interface{ StacktracePartition() uint64 }](ctx context.Context, profileSource Source, rows iter.Iterator[T], r *symdb.Resolver, ) (err error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "mergeByStacktraces") + sp, ctx := tracing.StartSpanFromContext(ctx, "mergeByStacktraces") defer sp.Finish() var columns v1.SampleColumns if err = columns.Resolve(profileSource.Schema()); err != nil { @@ -133,7 +131,7 @@ func mergeByStacktraces[T interface{ StacktracePartition() uint64 }](ctx context } func mergeBySpans[T interface{ StacktracePartition() uint64 }](ctx context.Context, profileSource Source, rows iter.Iterator[T], r *symdb.Resolver, spanSelector phlaremodel.SpanSelector) (err error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "mergeBySpans") + sp, ctx := tracing.StartSpanFromContext(ctx, "mergeBySpans") defer sp.Finish() var columns v1.SampleColumns if err = columns.Resolve(profileSource.Schema()); err != nil { @@ -150,86 +148,17 @@ func mergeBySpans[T interface{ StacktracePartition() uint64 }](ctx context.Conte defer runutil.CloseWithErrCapture(&err, profiles, "failed to close profile stream") for profiles.Next() { p := profiles.At() - partition := p.Row.StacktracePartition() - stacktraces := p.Values[0] - values := p.Values[1] - spans := p.Values[2] - r.WithPartitionSamples(partition, func(samples map[uint32]int64) { - for i, sid := range stacktraces { - spanID := spans[i].Uint64() - if spanID == 0 { - continue - } - if _, ok := spanSelector[spanID]; ok { - samples[sid.Uint32()] += values[i].Int64() - } - } - }) + r.AddSamplesWithSpanSelectorFromParquetRow( + p.Row.StacktracePartition(), + p.Values[0], + p.Values[1], + p.Values[2], + spanSelector, + ) } return profiles.Err() } -type seriesByLabels map[string]*typesv1.Series - -func (m seriesByLabels) normalize() []*typesv1.Series { - result := lo.Values(m) - sort.Slice(result, func(i, j int) bool { - return phlaremodel.CompareLabelPairs(result[i].Labels, result[j].Labels) < 0 - }) - // we have to sort the points in each series because labels reduction may have changed the order - for _, s := range result { - sort.Slice(s.Points, func(i, j int) bool { - return s.Points[i].Timestamp < s.Points[j].Timestamp - }) - } - return result -} - -type seriesBuilder struct { - labelsByFingerprint map[model.Fingerprint]string - labelBuf []byte - by []string - - series seriesByLabels -} - -func (s *seriesBuilder) init(by ...string) { - s.labelsByFingerprint = map[model.Fingerprint]string{} - s.series = make(seriesByLabels) - s.labelBuf = make([]byte, 0, 1024) - s.by = by -} - -func (s *seriesBuilder) add(fp model.Fingerprint, lbs phlaremodel.Labels, ts int64, value float64) { - labelsByString, ok := s.labelsByFingerprint[fp] - if !ok { - s.labelBuf = lbs.BytesWithLabels(s.labelBuf, s.by...) - labelsByString = string(s.labelBuf) - s.labelsByFingerprint[fp] = labelsByString - if _, ok := s.series[labelsByString]; !ok { - s.series[labelsByString] = &typesv1.Series{ - Labels: lbs.WithLabels(s.by...), - Points: []*typesv1.Point{ - { - Timestamp: ts, - Value: value, - }, - }, - } - return - } - } - series := s.series[labelsByString] - series.Points = append(series.Points, &typesv1.Point{ - Timestamp: ts, - Value: value, - }) -} - -func (s *seriesBuilder) build() []*typesv1.Series { - return s.series.normalize() -} - func mergeByLabels[T Profile]( ctx context.Context, profileSource Source, @@ -241,23 +170,50 @@ func mergeByLabels[T Profile]( if err != nil { return nil, err } - profiles := query.NewRepeatedRowIterator(ctx, rows, profileSource.RowGroups(), column.ColumnIndex) + + // these columns might not be present + annotationKeysColumn, _ := v1.ResolveColumnByPath(profileSource.Schema(), v1.AnnotationKeyColumnPath) + annotationValuesColumn, _ := v1.ResolveColumnByPath(profileSource.Schema(), v1.AnnotationValueColumnPath) + + profiles := query.NewRepeatedRowIterator( + ctx, + rows, + profileSource.RowGroups(), + column.ColumnIndex, + annotationKeysColumn.ColumnIndex, + annotationValuesColumn.ColumnIndex, + ) defer runutil.CloseWithErrCapture(&err, profiles, "failed to close profile stream") - seriesBuilder := seriesBuilder{} - seriesBuilder.init(by...) + seriesBuilder := timeseries.NewBuilder(by...) for profiles.Next() { values := profiles.At() p := values.Row var total int64 + annotations := v1.Annotations{ + Keys: make([]string, 0), + Values: make([]string, 0), + } for _, e := range values.Values { - total += e[0].Int64() + if e[0].Column() == column.ColumnIndex && e[0].Kind() == parquet.Int64 { + total += e[0].Int64() + } else if e[0].Column() == annotationKeysColumn.ColumnIndex && e[0].Kind() == parquet.ByteArray { + annotations.Keys = append(annotations.Keys, e[0].String()) + } else if e[0].Column() == annotationValuesColumn.ColumnIndex && e[0].Kind() == parquet.ByteArray { + annotations.Values = append(annotations.Values, e[0].String()) + } } - seriesBuilder.add(p.Fingerprint(), p.Labels(), int64(p.Timestamp()), float64(total)) - - } - return seriesBuilder.build(), profiles.Err() + seriesBuilder.Add( + p.Fingerprint(), + p.Labels(), + int64(p.Timestamp()), + float64(total), + annotations, + "", + ) + } + return seriesBuilder.Build(), profiles.Err() } func mergeByLabelsWithStackTraceSelector[T Profile]( @@ -276,8 +232,8 @@ func mergeByLabelsWithStackTraceSelector[T Profile]( columns.Value.ColumnIndex, ) - seriesBuilder := seriesBuilder{} - seriesBuilder.init(by...) + seriesBuilder := timeseries.Builder{} + seriesBuilder.Init(by...) defer runutil.CloseWithErrCapture(&err, profiles, "failed to close profile stream") var v symdb.CallSiteValues @@ -287,8 +243,9 @@ func mergeByLabelsWithStackTraceSelector[T Profile]( if err = r.CallSiteValuesParquet(&v, h.StacktracePartition(), row.Values[0], row.Values[1]); err != nil { return nil, err } - seriesBuilder.add(h.Fingerprint(), h.Labels(), int64(h.Timestamp()), float64(v.Total)) + // TODO aleks-p: add annotation support? + seriesBuilder.Add(h.Fingerprint(), h.Labels(), int64(h.Timestamp()), float64(v.Total), v1.Annotations{}, "") } - return seriesBuilder.build(), profiles.Err() + return seriesBuilder.Build(), profiles.Err() } diff --git a/pkg/phlaredb/sample_merge_test.go b/pkg/phlaredb/sample_merge_test.go index 3f3568c88c..8468195862 100644 --- a/pkg/phlaredb/sample_merge_test.go +++ b/pkg/phlaredb/sample_merge_test.go @@ -18,28 +18,28 @@ import ( googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/pprof" - pprofth "github.com/grafana/pyroscope/pkg/pprof/testhelper" - "github.com/grafana/pyroscope/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/pprof" + pprofth "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/testhelper" ) func TestMergeSampleByStacktraces(t *testing.T) { for _, tc := range []struct { name string - in func() ([]*pprofth.ProfileBuilder, *phlaremodel.Tree) + in func() ([]*pprofth.ProfileBuilder, *phlaremodel.FunctionNameTree) }{ { name: "single profile", - in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.Tree) { + in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.FunctionNameTree) { p := pprofth.NewProfileBuilder(int64(15 * time.Second)).CPUProfile() p.ForStacktraceString("my", "other").AddSamples(1) p.ForStacktraceString("my", "other").AddSamples(3) p.ForStacktraceString("my", "other", "stack").AddSamples(3) ps = append(ps, p) - tree = new(phlaremodel.Tree) + tree = new(phlaremodel.FunctionNameTree) tree.InsertStack(4, "other", "my") tree.InsertStack(3, "stack", "other", "my") return ps, tree @@ -47,7 +47,7 @@ func TestMergeSampleByStacktraces(t *testing.T) { }, { name: "multiple profiles", - in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.Tree) { + in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.FunctionNameTree) { for i := 0; i < 3000; i++ { p := pprofth.NewProfileBuilder(int64(15*time.Second)). CPUProfile().WithLabels("series", fmt.Sprintf("%d", i)) @@ -56,7 +56,7 @@ func TestMergeSampleByStacktraces(t *testing.T) { p.ForStacktraceString("my", "other", "stack").AddSamples(3) ps = append(ps, p) } - tree = new(phlaremodel.Tree) + tree = new(phlaremodel.FunctionNameTree) tree.InsertStack(12000, "other", "my") tree.InsertStack(9000, "stack", "other", "my") return ps, tree @@ -64,7 +64,7 @@ func TestMergeSampleByStacktraces(t *testing.T) { }, { name: "filtering multiple profiles", - in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.Tree) { + in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.FunctionNameTree) { for i := 0; i < 3000; i++ { p := pprofth.NewProfileBuilder(int64(15*time.Second)). MemoryProfile().WithLabels("series", fmt.Sprintf("%d", i)) @@ -81,7 +81,7 @@ func TestMergeSampleByStacktraces(t *testing.T) { p.ForStacktraceString("my", "other", "stack").AddSamples(3) ps = append(ps, p) } - tree = new(phlaremodel.Tree) + tree = new(phlaremodel.FunctionNameTree) tree.InsertStack(12000, "other", "my") tree.InsertStack(9000, "stack", "other", "my") return ps, tree @@ -99,7 +99,7 @@ func TestMergeSampleByStacktraces(t *testing.T) { input, expected := tc.in() for _, p := range input { - require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, p.Labels...)) + require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, nil, p.Labels...)) } require.NoError(t, db.Flush(context.Background(), true, "")) @@ -135,17 +135,17 @@ func TestMergeSampleByStacktraces(t *testing.T) { func TestHeadMergeSampleByStacktraces(t *testing.T) { for _, tc := range []struct { name string - in func() ([]*pprofth.ProfileBuilder, *phlaremodel.Tree) + in func() ([]*pprofth.ProfileBuilder, *phlaremodel.FunctionNameTree) }{ { name: "single profile", - in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.Tree) { + in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.FunctionNameTree) { p := pprofth.NewProfileBuilder(int64(15 * time.Second)).CPUProfile() p.ForStacktraceString("my", "other").AddSamples(1) p.ForStacktraceString("my", "other").AddSamples(3) p.ForStacktraceString("my", "other", "stack").AddSamples(3) ps = append(ps, p) - tree = new(phlaremodel.Tree) + tree = new(phlaremodel.FunctionNameTree) tree.InsertStack(4, "other", "my") tree.InsertStack(3, "stack", "other", "my") return ps, tree @@ -153,7 +153,7 @@ func TestHeadMergeSampleByStacktraces(t *testing.T) { }, { name: "multiple profiles", - in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.Tree) { + in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.FunctionNameTree) { for i := 0; i < 3000; i++ { p := pprofth.NewProfileBuilder(int64(15*time.Second)). CPUProfile().WithLabels("series", fmt.Sprintf("%d", i)) @@ -162,7 +162,7 @@ func TestHeadMergeSampleByStacktraces(t *testing.T) { p.ForStacktraceString("my", "other", "stack").AddSamples(3) ps = append(ps, p) } - tree = new(phlaremodel.Tree) + tree = new(phlaremodel.FunctionNameTree) tree.InsertStack(12000, "other", "my") tree.InsertStack(9000, "stack", "other", "my") return ps, tree @@ -170,7 +170,7 @@ func TestHeadMergeSampleByStacktraces(t *testing.T) { }, { name: "filtering multiple profiles", - in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.Tree) { + in: func() (ps []*pprofth.ProfileBuilder, tree *phlaremodel.FunctionNameTree) { for i := 0; i < 3000; i++ { p := pprofth.NewProfileBuilder(int64(15*time.Second)). MemoryProfile().WithLabels("series", fmt.Sprintf("%d", i)) @@ -187,7 +187,7 @@ func TestHeadMergeSampleByStacktraces(t *testing.T) { p.ForStacktraceString("my", "other", "stack").AddSamples(3) ps = append(ps, p) } - tree = new(phlaremodel.Tree) + tree = new(phlaremodel.FunctionNameTree) tree.InsertStack(12000, "other", "my") tree.InsertStack(9000, "stack", "other", "my") return ps, tree @@ -205,7 +205,7 @@ func TestHeadMergeSampleByStacktraces(t *testing.T) { input, expected := tc.in() for _, p := range input { - require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, p.Labels...)) + require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, nil, p.Labels...)) } profiles, err := db.queriers().SelectMatchingProfiles(ctx, &ingestv1.SelectProfilesRequest{ LabelSelector: `{}`, @@ -247,7 +247,7 @@ func TestMergeSampleByLabels(t *testing.T) { expected: []*typesv1.Series{ { Labels: []*typesv1.LabelPair{}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 7}}, + Points: []*typesv1.Point{{Timestamp: 15000, Value: 7, Annotations: []*typesv1.ProfileAnnotation{}}}, }, }, }, @@ -271,11 +271,13 @@ func TestMergeSampleByLabels(t *testing.T) { expected: []*typesv1.Series{ { Labels: []*typesv1.LabelPair{{Name: "foo", Value: "bar"}}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 1}, {Timestamp: 30000, Value: 1}}, + Points: []*typesv1.Point{ + {Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 30000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}}, }, { Labels: []*typesv1.LabelPair{{Name: "foo", Value: "buzz"}}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 1}}, + Points: []*typesv1.Point{{Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}}, }, }, }, @@ -299,7 +301,10 @@ func TestMergeSampleByLabels(t *testing.T) { expected: []*typesv1.Series{ { Labels: []*typesv1.LabelPair{}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 1}, {Timestamp: 15000, Value: 1}, {Timestamp: 30000, Value: 1}}, + Points: []*typesv1.Point{ + {Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 30000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}}, }, }, }, @@ -314,7 +319,7 @@ func TestMergeSampleByLabels(t *testing.T) { require.NoError(t, err) for _, p := range tc.in() { - require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, p.Labels...)) + require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, nil, p.Labels...)) } require.NoError(t, db.Flush(context.Background(), true, "")) @@ -371,7 +376,7 @@ func TestHeadMergeSampleByLabels(t *testing.T) { expected: []*typesv1.Series{ { Labels: []*typesv1.LabelPair{}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 7}}, + Points: []*typesv1.Point{{Timestamp: 15000, Value: 7, Annotations: []*typesv1.ProfileAnnotation{}}}, }, }, }, @@ -395,11 +400,13 @@ func TestHeadMergeSampleByLabels(t *testing.T) { expected: []*typesv1.Series{ { Labels: []*typesv1.LabelPair{{Name: "foo", Value: "bar"}}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 1}, {Timestamp: 30000, Value: 1}}, + Points: []*typesv1.Point{ + {Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 30000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}}, }, { Labels: []*typesv1.LabelPair{{Name: "foo", Value: "buzz"}}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 1}}, + Points: []*typesv1.Point{{Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}}, }, }, }, @@ -423,7 +430,10 @@ func TestHeadMergeSampleByLabels(t *testing.T) { expected: []*typesv1.Series{ { Labels: []*typesv1.LabelPair{}, - Points: []*typesv1.Point{{Timestamp: 15000, Value: 1}, {Timestamp: 15000, Value: 1}, {Timestamp: 30000, Value: 1}}, + Points: []*typesv1.Point{ + {Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 15000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}, + {Timestamp: 30000, Value: 1, Annotations: []*typesv1.ProfileAnnotation{}}}, }, }, }, @@ -438,7 +448,7 @@ func TestHeadMergeSampleByLabels(t *testing.T) { require.NoError(t, err) for _, p := range tc.in() { - require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, p.Labels...)) + require.NoError(t, db.Ingest(ctx, p.Profile, p.UUID, nil, p.Labels...)) } profileIt, err := db.queriers().SelectMatchingProfiles(ctx, &ingestv1.SelectProfilesRequest{ @@ -475,7 +485,7 @@ func TestMergePprof(t *testing.T) { require.NoError(t, err) for i := 0; i < 3; i++ { - require.NoError(t, db.Ingest(ctx, generateProfile(t, i*1000), uuid.New(), &typesv1.LabelPair{ + require.NoError(t, db.Ingest(ctx, generateProfile(t, i*1000), uuid.New(), nil, &typesv1.LabelPair{ Name: model.MetricNameLabel, Value: "process_cpu", })) @@ -533,7 +543,7 @@ func TestHeadMergePprof(t *testing.T) { require.NoError(t, err) for i := 0; i < 3; i++ { - require.NoError(t, db.Ingest(ctx, generateProfile(t, i*1000), uuid.New(), &typesv1.LabelPair{ + require.NoError(t, db.Ingest(ctx, generateProfile(t, i*1000), uuid.New(), nil, &typesv1.LabelPair{ Name: model.MetricNameLabel, Value: "process_cpu", })) @@ -581,7 +591,7 @@ func TestMergeSpans(t *testing.T) { }, NoLimit, ctx.localBucketClient) require.NoError(t, err) - require.NoError(t, db.Ingest(ctx, generateProfileWithSpans(t, 1000), uuid.New(), &typesv1.LabelPair{ + require.NoError(t, db.Ingest(ctx, generateProfileWithSpans(t, 1000), uuid.New(), nil, &typesv1.LabelPair{ Name: model.MetricNameLabel, Value: "process_cpu", })) @@ -617,7 +627,7 @@ func TestMergeSpans(t *testing.T) { result, err := q.queriers[0].MergeBySpans(ctx, iter.NewSliceIterator(profiles), spanSelector) require.NoError(t, err) - expected := new(phlaremodel.Tree) + expected := new(phlaremodel.FunctionNameTree) expected.InsertStack(1, "bar", "foo") expected.InsertStack(2, "foo") @@ -632,7 +642,7 @@ func TestHeadMergeSpans(t *testing.T) { }, NoLimit, ctx.localBucketClient) require.NoError(t, err) - require.NoError(t, db.Ingest(ctx, generateProfileWithSpans(t, 1000), uuid.New(), &typesv1.LabelPair{ + require.NoError(t, db.Ingest(ctx, generateProfileWithSpans(t, 1000), uuid.New(), nil, &typesv1.LabelPair{ Name: model.MetricNameLabel, Value: "process_cpu", })) @@ -660,7 +670,7 @@ func TestHeadMergeSpans(t *testing.T) { result, err := db.headQueriers()[0].MergeBySpans(ctx, iter.NewSliceIterator(profiles), spanSelector) require.NoError(t, err) - expected := new(phlaremodel.Tree) + expected := new(phlaremodel.FunctionNameTree) expected.InsertStack(1, "bar", "foo") expected.InsertStack(2, "foo") diff --git a/pkg/phlaredb/schemas/v1/functions.go b/pkg/phlaredb/schemas/v1/functions.go index 62d723fc7d..bdaac2f22e 100644 --- a/pkg/phlaredb/schemas/v1/functions.go +++ b/pkg/phlaredb/schemas/v1/functions.go @@ -10,13 +10,11 @@ var functionsSchema = parquet.SchemaOf(new(profilev1.Function)) type FunctionPersister struct{} -func (*FunctionPersister) Name() string { return "functions" } +func (FunctionPersister) Name() string { return "functions" } -func (*FunctionPersister) Schema() *parquet.Schema { return functionsSchema } +func (FunctionPersister) Schema() *parquet.Schema { return functionsSchema } -func (*FunctionPersister) SortingColumns() parquet.SortingOption { return parquet.SortingColumns() } - -func (*FunctionPersister) Deconstruct(row parquet.Row, _ uint64, fn *InMemoryFunction) parquet.Row { +func (FunctionPersister) Deconstruct(row parquet.Row, fn InMemoryFunction) parquet.Row { if cap(row) < 5 { row = make(parquet.Row, 0, 5) } @@ -29,7 +27,7 @@ func (*FunctionPersister) Deconstruct(row parquet.Row, _ uint64, fn *InMemoryFun return row } -func (*FunctionPersister) Reconstruct(row parquet.Row) (uint64, *InMemoryFunction, error) { +func (FunctionPersister) Reconstruct(row parquet.Row) (InMemoryFunction, error) { loc := InMemoryFunction{ Id: row[0].Uint64(), Name: row[1].Uint32(), @@ -37,7 +35,7 @@ func (*FunctionPersister) Reconstruct(row parquet.Row) (uint64, *InMemoryFunctio Filename: row[3].Uint32(), StartLine: row[4].Uint32(), } - return 0, &loc, nil + return loc, nil } type InMemoryFunction struct { @@ -54,7 +52,6 @@ type InMemoryFunction struct { StartLine uint32 } -func (f *InMemoryFunction) Clone() *InMemoryFunction { - n := *f - return &n +func (f InMemoryFunction) Clone() InMemoryFunction { + return f } diff --git a/pkg/phlaredb/schemas/v1/locations.go b/pkg/phlaredb/schemas/v1/locations.go index b9cbf91ba6..93b7967276 100644 --- a/pkg/phlaredb/schemas/v1/locations.go +++ b/pkg/phlaredb/schemas/v1/locations.go @@ -10,13 +10,11 @@ var locationsSchema = parquet.SchemaOf(new(profilev1.Location)) type LocationPersister struct{} -func (*LocationPersister) Name() string { return "locations" } +func (LocationPersister) Name() string { return "locations" } -func (*LocationPersister) Schema() *parquet.Schema { return locationsSchema } +func (LocationPersister) Schema() *parquet.Schema { return locationsSchema } -func (*LocationPersister) SortingColumns() parquet.SortingOption { return parquet.SortingColumns() } - -func (*LocationPersister) Deconstruct(row parquet.Row, _ uint64, loc *InMemoryLocation) parquet.Row { +func (LocationPersister) Deconstruct(row parquet.Row, loc InMemoryLocation) parquet.Row { var ( col = -1 newCol = func() int { @@ -61,7 +59,7 @@ func (*LocationPersister) Deconstruct(row parquet.Row, _ uint64, loc *InMemoryLo return row } -func (*LocationPersister) Reconstruct(row parquet.Row) (uint64, *InMemoryLocation, error) { +func (LocationPersister) Reconstruct(row parquet.Row) (InMemoryLocation, error) { loc := InMemoryLocation{ Id: row[0].Uint64(), MappingId: uint32(row[1].Uint64()), @@ -69,6 +67,10 @@ func (*LocationPersister) Reconstruct(row parquet.Row) (uint64, *InMemoryLocatio IsFolded: row[len(row)-1].Boolean(), } lines := row[3 : len(row)-1] + if len(lines) == 2 && lines[0].DefinitionLevel() == 0 { + loc.Line = make([]InMemoryLine, 0) + return loc, nil + } loc.Line = make([]InMemoryLine, len(lines)/2) for i, v := range lines[:len(lines)/2] { loc.Line[i].FunctionId = uint32(v.Uint64()) @@ -76,7 +78,7 @@ func (*LocationPersister) Reconstruct(row parquet.Row) (uint64, *InMemoryLocatio for i, v := range lines[len(lines)/2:] { loc.Line[i].Line = int32(v.Uint64()) } - return 0, &loc, nil + return loc, nil } type InMemoryLocation struct { @@ -110,11 +112,11 @@ type InMemoryLocation struct { Line []InMemoryLine } -func (l *InMemoryLocation) Clone() *InMemoryLocation { - x := *l +func (l InMemoryLocation) Clone() InMemoryLocation { + x := l x.Line = make([]InMemoryLine, len(l.Line)) copy(x.Line, l.Line) - return &x + return x } type InMemoryLine struct { diff --git a/pkg/phlaredb/schemas/v1/mappings.go b/pkg/phlaredb/schemas/v1/mappings.go index 0d5503f6cb..c8220dcbc6 100644 --- a/pkg/phlaredb/schemas/v1/mappings.go +++ b/pkg/phlaredb/schemas/v1/mappings.go @@ -10,13 +10,11 @@ var mappingsSchema = parquet.SchemaOf(new(profilev1.Mapping)) type MappingPersister struct{} -func (*MappingPersister) Name() string { return "mappings" } +func (MappingPersister) Name() string { return "mappings" } -func (*MappingPersister) Schema() *parquet.Schema { return mappingsSchema } +func (MappingPersister) Schema() *parquet.Schema { return mappingsSchema } -func (*MappingPersister) SortingColumns() parquet.SortingOption { return parquet.SortingColumns() } - -func (*MappingPersister) Deconstruct(row parquet.Row, _ uint64, m *InMemoryMapping) parquet.Row { +func (MappingPersister) Deconstruct(row parquet.Row, m InMemoryMapping) parquet.Row { if cap(row) < 10 { row = make(parquet.Row, 0, 10) } @@ -34,7 +32,7 @@ func (*MappingPersister) Deconstruct(row parquet.Row, _ uint64, m *InMemoryMappi return row } -func (*MappingPersister) Reconstruct(row parquet.Row) (uint64, *InMemoryMapping, error) { +func (MappingPersister) Reconstruct(row parquet.Row) (InMemoryMapping, error) { mapping := InMemoryMapping{ Id: row[0].Uint64(), MemoryStart: row[1].Uint64(), @@ -47,7 +45,7 @@ func (*MappingPersister) Reconstruct(row parquet.Row) (uint64, *InMemoryMapping, HasLineNumbers: row[8].Boolean(), HasInlineFrames: row[9].Boolean(), } - return 0, &mapping, nil + return mapping, nil } type InMemoryMapping struct { @@ -74,7 +72,6 @@ type InMemoryMapping struct { HasInlineFrames bool } -func (m *InMemoryMapping) Clone() *InMemoryMapping { - n := *m - return &n +func (m InMemoryMapping) Clone() InMemoryMapping { + return m } diff --git a/pkg/phlaredb/schemas/v1/models.go b/pkg/phlaredb/schemas/v1/models.go index 84fa49956b..2fdcf812b2 100644 --- a/pkg/phlaredb/schemas/v1/models.go +++ b/pkg/phlaredb/schemas/v1/models.go @@ -3,10 +3,10 @@ package v1 import googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" type Models interface { - *Profile | *InMemoryProfile | - *googlev1.Location | *InMemoryLocation | - *googlev1.Function | *InMemoryFunction | - *googlev1.Mapping | *InMemoryMapping | + *Profile | InMemoryProfile | + *googlev1.Location | InMemoryLocation | + *googlev1.Function | InMemoryFunction | + *googlev1.Mapping | InMemoryMapping | *Stacktrace | string } diff --git a/pkg/phlaredb/schemas/v1/profiles.go b/pkg/phlaredb/schemas/v1/profiles.go index 4ea8eb8606..a17e817427 100644 --- a/pkg/phlaredb/schemas/v1/profiles.go +++ b/pkg/phlaredb/schemas/v1/profiles.go @@ -13,15 +13,17 @@ import ( "github.com/prometheus/common/model" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - phlareparquet "github.com/grafana/pyroscope/pkg/parquet" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" ) const ( + IDColumnName = "ID" SeriesIndexColumnName = "SeriesIndex" TimeNanosColumnName = "TimeNanos" StacktracePartitionColumnName = "StacktracePartition" TotalValueColumnName = "TotalValue" SamplesColumnName = "Samples" + AnnotationsColumnName = "Annotations" ) var ( @@ -37,6 +39,7 @@ var ( phlareparquet.NewGroupField("Value", parquet.Encoded(parquet.Int(64), &parquet.DeltaBinaryPacked)), phlareparquet.NewGroupField("Labels", pprofLabels), phlareparquet.NewGroupField("SpanID", parquet.Optional(parquet.Encoded(parquet.Uint(64), &parquet.RLEDictionary))), + phlareparquet.NewGroupField("TraceID", parquet.Optional(parquet.Encoded(parquet.Leaf(parquet.FixedLenByteArrayType(16)), &parquet.RLEDictionary))), } ProfilesSchema = parquet.NewSchema("Profile", phlareparquet.Group{ phlareparquet.NewGroupField("ID", parquet.UUID()), @@ -51,6 +54,11 @@ var ( phlareparquet.NewGroupField("Period", parquet.Optional(parquet.Int(64))), phlareparquet.NewGroupField("Comments", parquet.List(stringRef)), phlareparquet.NewGroupField("DefaultSampleType", parquet.Optional(parquet.Int(64))), + phlareparquet.NewGroupField(AnnotationsColumnName, parquet.List( + phlareparquet.Group{ + phlareparquet.NewGroupField("Key", parquet.String()), + phlareparquet.NewGroupField("Value", parquet.String()), + })), }) DownsampledProfilesSchema = parquet.NewSchema("DownsampledProfile", phlareparquet.Group{ phlareparquet.NewGroupField(SeriesIndexColumnName, parquet.Encoded(parquet.Uint(32), &parquet.DeltaBinaryPacked)), @@ -62,11 +70,17 @@ var ( phlareparquet.NewGroupField("Value", parquet.Encoded(parquet.Int(64), &parquet.DeltaBinaryPacked)), })), phlareparquet.NewGroupField(TimeNanosColumnName, parquet.Timestamp(parquet.Nanosecond)), + phlareparquet.NewGroupField(AnnotationsColumnName, parquet.List( + phlareparquet.Group{ + phlareparquet.NewGroupField("Key", parquet.String()), + phlareparquet.NewGroupField("Value", parquet.String()), + })), }) sampleStacktraceIDColumnPath = strings.Split("Samples.list.element.StacktraceID", ".") SampleValueColumnPath = strings.Split("Samples.list.element.Value", ".") sampleSpanIDColumnPath = strings.Split("Samples.list.element.SpanID", ".") + sampleTraceIDColumnPath = strings.Split("Samples.list.element.TraceID", ".") maxProfileRow parquet.Row seriesIndexColIndex int @@ -74,8 +88,17 @@ var ( valueColIndex int timeNanoColIndex int stacktracePartitionColIndex int + totalValueColIndex int + + AnnotationKeyColumnPath = strings.Split("Annotations.list.element.Key", ".") + AnnotationValueColumnPath = strings.Split("Annotations.list.element.Value", ".") + annotationKeyColumnIndex int + annotationValueColumnIndex int - downsampledValueColIndex int + downsampledValueColIndex int + downsampledAnnotationValueColIndex int + + emptyTraceID [16]byte ErrColumnNotFound = fmt.Errorf("column path not found") ) @@ -110,18 +133,40 @@ func init() { panic(fmt.Errorf("StacktracePartition column not found")) } stacktracePartitionColIndex = stacktracePartitionCol.ColumnIndex + totalValueCol, ok := ProfilesSchema.Lookup(TotalValueColumnName) + if !ok { + panic(fmt.Errorf("TotalValue column not found")) + } + totalValueColIndex = totalValueCol.ColumnIndex downsampledValueCol, ok := DownsampledProfilesSchema.Lookup(SampleValueColumnPath...) if !ok { panic(fmt.Errorf("Sample.Value column not found")) } downsampledValueColIndex = downsampledValueCol.ColumnIndex + downsampledAnnotationValueCol, ok := DownsampledProfilesSchema.Lookup(AnnotationValueColumnPath...) + if !ok { + panic(fmt.Errorf("Annotation.Value column not found")) + } + downsampledAnnotationValueColIndex = downsampledAnnotationValueCol.ColumnIndex + + annotationKeyColumn, ok := ProfilesSchema.Lookup(AnnotationKeyColumnPath...) + if !ok { + panic(fmt.Errorf("annotation key column not found")) + } + annotationKeyColumnIndex = annotationKeyColumn.ColumnIndex + annotationValueColum, ok := ProfilesSchema.Lookup(AnnotationValueColumnPath...) + if !ok { + panic(fmt.Errorf("annotation value column not found")) + } + annotationValueColumnIndex = annotationValueColum.ColumnIndex } type SampleColumns struct { StacktraceID parquet.LeafColumn Value parquet.LeafColumn SpanID parquet.LeafColumn + TraceID parquet.LeafColumn } func (c *SampleColumns) Resolve(schema *parquet.Schema) error { @@ -134,6 +179,7 @@ func (c *SampleColumns) Resolve(schema *parquet.Schema) error { } // Optional. c.SpanID, _ = ResolveColumnByPath(schema, sampleSpanIDColumnPath) + c.TraceID, _ = ResolveColumnByPath(schema, sampleTraceIDColumnPath) return nil } @@ -141,6 +187,10 @@ func (c *SampleColumns) HasSpanID() bool { return c.SpanID.Node != nil } +func (c *SampleColumns) HasTraceID() bool { + return c.TraceID.Node != nil +} + func ResolveColumnByPath(schema *parquet.Schema, path []string) (parquet.LeafColumn, error) { if c, ok := schema.Lookup(path...); ok { return c, nil @@ -153,10 +203,11 @@ type Sample struct { Value int64 `parquet:",delta"` Labels []*profilev1.Label `parquet:",list"` SpanID uint64 `parquet:",optional"` + TraceID []byte `parquet:",optional"` } type Profile struct { - // A unique UUID per ingested profile + // A UUID per ingested profile ID uuid.UUID `parquet:",uuid"` // SeriesIndex references the underlying series and is generated when @@ -195,6 +246,19 @@ type Profile struct { // Index into the string table of the type of the preferred sample // value. If unset, clients should default to the last sample value. DefaultSampleType int64 `parquet:",optional"` + + // Additional metadata about the profile + Annotations []*Annotation `parquet:",list"` +} + +type Annotation struct { + Key string `parquet:","` + Value string `parquet:","` +} + +type Annotations struct { + Keys []string + Values []string } func (p Profile) Timestamp() model.Time { @@ -219,25 +283,17 @@ func (*ProfilePersister) Schema() *parquet.Schema { return ProfilesSchema } -func (*ProfilePersister) SortingColumns() parquet.SortingOption { - return parquet.SortingColumns( - parquet.Ascending("SeriesIndex"), - parquet.Ascending("TimeNanos"), - parquet.Ascending("Samples", "list", "element", "StacktraceID"), - ) -} - -func (*ProfilePersister) Deconstruct(row parquet.Row, id uint64, s *Profile) parquet.Row { +func (*ProfilePersister) Deconstruct(row parquet.Row, s *Profile) parquet.Row { row = ProfilesSchema.Deconstruct(row, s) return row } -func (*ProfilePersister) Reconstruct(row parquet.Row) (id uint64, s *Profile, err error) { +func (*ProfilePersister) Reconstruct(row parquet.Row) (s *Profile, err error) { var profile Profile if err := ProfilesSchema.Reconstruct(&profile, row); err != nil { - return 0, nil, err + return nil, err } - return 0, &profile, nil + return &profile, nil } type SliceRowReader[T any] struct { @@ -275,7 +331,7 @@ func (r *SliceRowReader[T]) ReadRows(rows []parquet.Row) (n int, err error) { } type InMemoryProfile struct { - // A unique UUID per ingested profile + // A UUID per ingested profile ID uuid.UUID // SeriesIndex references the underlying series and is generated when @@ -313,6 +369,8 @@ type InMemoryProfile struct { DefaultSampleType int64 Samples Samples + + Annotations Annotations } type Samples struct { @@ -321,16 +379,19 @@ type Samples struct { // Span associated with samples. // Optional: Spans == nil, if not present. Spans []uint64 + // Trace associated with samples. + // Optional: TraceIDs == nil, if not present. + TraceIDs [][16]byte } func NewSamples(size int) Samples { return Samples{ - StacktraceIDs: make([]uint32, 0, size), - Values: make([]uint64, 0, size), + StacktraceIDs: make([]uint32, size), + Values: make([]uint64, size), } } -func NewSamplesFromMap(m map[uint32]int64) Samples { +func NewSamplesFromMap(m map[uint32]uint64) Samples { s := Samples{ StacktraceIDs: make([]uint32, len(m)), Values: make([]uint64, len(m)), @@ -339,7 +400,7 @@ func NewSamplesFromMap(m map[uint32]int64) Samples { for k, v := range m { if k != 0 && v > 0 { s.StacktraceIDs[i] = k - s.Values[i] = uint64(v) + s.Values[i] = v i++ } } @@ -349,14 +410,11 @@ func NewSamplesFromMap(m map[uint32]int64) Samples { return s } -// Compact zero samples and optionally duplicates. -func (s Samples) Compact(dedupe bool) Samples { +// Compact removes zero and negative samples. +func (s Samples) Compact() Samples { if len(s.StacktraceIDs) == 0 { return s } - if dedupe { - s = trimDuplicateSamples(s) - } return trimZeroAndNegativeSamples(s) } @@ -364,22 +422,21 @@ func (s Samples) Clone() Samples { return cloneSamples(s) } -func trimDuplicateSamples(samples Samples) Samples { - sort.Sort(samples) - n := 0 - for j := 1; j < len(samples.StacktraceIDs); j++ { - if samples.StacktraceIDs[n] == samples.StacktraceIDs[j] { - samples.Values[n] += samples.Values[j] - } else { - n++ - samples.StacktraceIDs[n] = samples.StacktraceIDs[j] - samples.Values[n] = samples.Values[j] - } +func (s Samples) Range(n, m int) Samples { + if n < 0 || n > m || m > s.Len() { + return Samples{} } - return Samples{ - StacktraceIDs: samples.StacktraceIDs[:n+1], - Values: samples.Values[:n+1], + x := Samples{ + StacktraceIDs: s.StacktraceIDs[n:m], + Values: s.Values[n:m], + } + if len(s.Spans) > 0 { + x.Spans = s.Spans[n:m] } + if len(s.TraceIDs) > 0 { + x.TraceIDs = s.TraceIDs[n:m] + } + return x } func trimZeroAndNegativeSamples(samples Samples) Samples { @@ -391,6 +448,9 @@ func trimZeroAndNegativeSamples(samples Samples) Samples { if len(samples.Spans) > 0 { samples.Spans[n] = samples.Spans[j] } + if len(samples.TraceIDs) > 0 { + samples.TraceIDs[n] = samples.TraceIDs[j] + } n++ } } @@ -401,6 +461,9 @@ func trimZeroAndNegativeSamples(samples Samples) Samples { if len(samples.Spans) > 0 { s.Spans = samples.Spans[:n] } + if len(samples.TraceIDs) > 0 { + s.TraceIDs = samples.TraceIDs[:n] + } return s } @@ -409,6 +472,7 @@ func cloneSamples(samples Samples) Samples { StacktraceIDs: copySlice(samples.StacktraceIDs), Values: copySlice(samples.Values), Spans: copySlice(samples.Spans), + TraceIDs: copySlice(samples.TraceIDs), } } @@ -422,6 +486,9 @@ func (s Samples) Swap(i, j int) { if len(s.Spans) > 0 { s.Spans[i], s.Spans[j] = s.Spans[j], s.Spans[i] } + if len(s.TraceIDs) > 0 { + s.TraceIDs[i], s.TraceIDs[j] = s.TraceIDs[j], s.TraceIDs[i] + } } func (s Samples) Len() int { @@ -440,6 +507,9 @@ func (s SamplesBySpanID) Swap(i, j int) { if len(s.Spans) > 0 { s.Spans[i], s.Spans[j] = s.Spans[j], s.Spans[i] } + if len(s.TraceIDs) > 0 { + s.TraceIDs[i], s.TraceIDs[j] = s.TraceIDs[j], s.TraceIDs[i] + } } func (s SamplesBySpanID) Len() int { @@ -454,41 +524,6 @@ func (s Samples) Sum() uint64 { return sum } -// TODO(kolesnikovae): Consider map alternatives. - -// SampleMap is a map of partitioned samples structured -// as follows: partition => stacktrace_id => value -type SampleMap map[uint64]map[uint32]int64 - -func (m SampleMap) Partition(p uint64) map[uint32]int64 { - s, ok := m[p] - if !ok { - s = make(map[uint32]int64, 128) - m[p] = s - } - return s -} - -func (m SampleMap) AddSamples(partition uint64, samples Samples) { - p := m.Partition(partition) - for i, sid := range samples.StacktraceIDs { - p[sid] += int64(samples.Values[i]) - } -} - -func (m SampleMap) WriteSamples(partition uint64, dst *Samples) { - p, ok := m[partition] - if !ok { - return - } - dst.StacktraceIDs = dst.StacktraceIDs[:0] - dst.Values = dst.Values[:0] - for k, v := range p { - dst.StacktraceIDs = append(dst.StacktraceIDs, k) - dst.Values = append(dst.Values, uint64(v)) - } -} - const profileSize = uint64(unsafe.Sizeof(InMemoryProfile{})) func (p InMemoryProfile) Size() uint64 { @@ -532,8 +567,9 @@ func deconstructMemoryProfile(imp InMemoryProfile, row parquet.Row) parquet.Row col++ return col } - totalCols = 8 + (7 * len(imp.Samples.StacktraceIDs)) + len(imp.Comments) + totalCols = profileColumnCount(imp) ) + if cap(row) < totalCols { row = make(parquet.Row, 0, totalCols) } @@ -603,6 +639,31 @@ func deconstructMemoryProfile(imp InMemoryProfile, row parquet.Row) parquet.Row } } + newCol() + repetition = -1 + if len(imp.Samples.TraceIDs) == 0 { + if len(imp.Samples.Values) == 0 { + row = append(row, parquet.Value{}.Level(0, 0, col)) + } + for range imp.Samples.Values { + if repetition < 1 { + repetition++ + } + row = append(row, parquet.Value{}.Level(repetition, 1, col)) + } + } else { + for i := range imp.Samples.TraceIDs { + if repetition < 1 { + repetition++ + } + if imp.Samples.TraceIDs[i] == emptyTraceID { + row = append(row, parquet.Value{}.Level(repetition, 1, col)) + } else { + row = append(row, parquet.FixedLenByteArrayValue(imp.Samples.TraceIDs[i][:]).Level(repetition, 2, col)) + } + } + } + if imp.DropFrames == 0 { row = append(row, parquet.Value{}.Level(0, 0, newCol())) } else { @@ -640,9 +701,48 @@ func deconstructMemoryProfile(imp InMemoryProfile, row parquet.Row) parquet.Row } else { row = append(row, parquet.Int64Value(imp.DefaultSampleType).Level(0, 1, newCol())) } + + newCol() + if len(imp.Annotations.Keys) == 0 { + row = append(row, parquet.Value{}.Level(0, 0, col)) + } + repetition = -1 + for i := range imp.Annotations.Keys { + if repetition < 1 { + repetition++ + } + row = append(row, parquet.ByteArrayValue([]byte(imp.Annotations.Keys[i])).Level(repetition, 1, col)) + } + + newCol() + if len(imp.Annotations.Values) == 0 { + row = append(row, parquet.Value{}.Level(0, 0, col)) + } + repetition = -1 + for i := range imp.Annotations.Values { + if repetition < 1 { + repetition++ + } + row = append(row, parquet.ByteArrayValue([]byte(imp.Annotations.Values[i])).Level(repetition, 1, col)) + } + return row } +func profileColumnCount(imp InMemoryProfile) int { + var totalCols = 10 + (8 * len(imp.Samples.StacktraceIDs)) + len(imp.Comments) + 2*len(imp.Annotations.Keys) + if len(imp.Comments) == 0 { + totalCols++ + } + if len(imp.Samples.StacktraceIDs) == 0 { + totalCols += 8 + } + if len(imp.Annotations.Keys) == 0 { + totalCols += 2 + } + return totalCols +} + func NewMergeProfilesRowReader(rowGroups []parquet.RowReader) parquet.RowReader { if len(rowGroups) == 0 { return phlareparquet.EmptyRowReader @@ -686,6 +786,8 @@ func (p ProfileRow) StacktracePartitionID() uint64 { return p[stacktracePartitionColIndex].Uint64() } +func (p ProfileRow) TotalValue() int64 { return p[totalValueColIndex].Int64() } + func (p ProfileRow) TimeNanos() int64 { var ts int64 for i := len(p) - 1; i >= 0; i-- { @@ -697,10 +799,44 @@ func (p ProfileRow) TimeNanos() int64 { return ts } +func (p ProfileRow) ForAnnotations(fn func([]parquet.Value, []parquet.Value)) { + startKeys := -1 + endKeys := -1 + startValues := -1 + var i int + for i = 0; i < len(p); i++ { + col := p[i].Column() + if col == annotationKeyColumnIndex && p[i].DefinitionLevel() == 1 { + if startKeys == -1 { + startKeys = i + } + } + if col > annotationKeyColumnIndex && endKeys == -1 { + endKeys = i + } + if col == annotationValueColumnIndex && p[i].DefinitionLevel() == 1 { + if startValues == -1 { + startValues = i + } + } + if col > annotationValueColumnIndex { + break + } + } + + if startKeys != -1 && startValues != -1 { + fn(p[startKeys:endKeys], p[startValues:i]) + } +} + func (p ProfileRow) SetSeriesIndex(v uint32) { p[seriesIndexColIndex] = parquet.Int32Value(int32(v)).Level(0, 0, seriesIndexColIndex) } +func (p ProfileRow) SetStacktracePartitionID(v uint64) { + p[stacktracePartitionColIndex] = parquet.Int64Value(int64(v)).Level(0, 0, stacktracePartitionColIndex) +} + func (p ProfileRow) ForStacktraceIDsValues(fn func([]parquet.Value)) { start := -1 var i int @@ -771,3 +907,22 @@ func (p DownsampledProfileRow) ForValues(fn func([]parquet.Value)) { fn(p[start:i]) } } + +func (p DownsampledProfileRow) ForAnnotationValues(fn func([]parquet.Value)) { + start := -1 + var i int + for i = 0; i < len(p); i++ { + col := p[i].Column() + if col == downsampledAnnotationValueColIndex && p[i].DefinitionLevel() == 1 { + if start == -1 { + start = i + } + } + if col > downsampledAnnotationValueColIndex { + break + } + } + if start != -1 { + fn(p[start:i]) + } +} diff --git a/pkg/phlaredb/schemas/v1/profiles_test.go b/pkg/phlaredb/schemas/v1/profiles_test.go index 2c3d8b23ee..4a176c9bc6 100644 --- a/pkg/phlaredb/schemas/v1/profiles_test.go +++ b/pkg/phlaredb/schemas/v1/profiles_test.go @@ -2,9 +2,10 @@ package v1 import ( "bytes" + "crypto/rand" "fmt" "io" - "math/rand" + mathrand "math/rand" "sort" "testing" @@ -13,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - phlareparquet "github.com/grafana/pyroscope/pkg/parquet" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" ) func TestInMemoryProfilesRowReader(t *testing.T) { @@ -105,7 +106,7 @@ func TestRoundtripProfile(t *testing.T) { profiles := generateProfiles(1) for _, p := range profiles { for _, x := range p.Samples { - x.SpanID = rand.Uint64() + x.SpanID = mathrand.Uint64() } } inMemoryProfiles := generateMemoryProfiles(1) @@ -122,21 +123,36 @@ func TestRoundtripProfile(t *testing.T) { require.NoError(t, err) require.Equal(t, expected, actual) }) + t.Run("SampleTraceID", func(t *testing.T) { + profiles := generateProfiles(1) + for _, p := range profiles { + for _, x := range p.Samples { + x.TraceID = make([]byte, 16) + _, err := rand.Read(x.TraceID) + require.NoError(t, err) + } + } + inMemoryProfiles := generateMemoryProfiles(1) + for i := range inMemoryProfiles { + traceIDs := make([][16]byte, len(inMemoryProfiles[i].Samples.Values)) + for j := range traceIDs { + copy(traceIDs[j][:], profiles[i].Samples[j].TraceID) + } + inMemoryProfiles[i].Samples.TraceIDs = traceIDs + } + expected, err := phlareparquet.ReadAll(NewProfilesRowReader(profiles)) + require.NoError(t, err) + actual, err := phlareparquet.ReadAll(NewInMemoryProfilesRowReader(inMemoryProfiles)) + require.NoError(t, err) + require.Equal(t, expected, actual) + }) } func TestCompactSamples(t *testing.T) { - require.Equal(t, Samples{ - StacktraceIDs: []uint32{1, 2, 3, 2, 5, 1, 7, 7, 1}, - Values: []uint64{1, 1, 1, 1, 1, 3, 1, 0, 1}, - }.Compact(true), Samples{ - StacktraceIDs: []uint32{1, 2, 3, 5, 7}, - Values: []uint64{5, 2, 1, 1, 1}, - }) - require.Equal(t, Samples{ StacktraceIDs: []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9}, Values: []uint64{1, 0, 1, 1, 1, 0, 1, 1, 0}, - }.Compact(false), Samples{ + }.Compact(), Samples{ StacktraceIDs: []uint32{1, 3, 4, 5, 7, 8}, Values: []uint64{1, 1, 1, 1, 1, 1}, }) @@ -144,7 +160,7 @@ func TestCompactSamples(t *testing.T) { require.Equal(t, Samples{ StacktraceIDs: []uint32{1, 2, 3}, Values: []uint64{1, 2, 3}, - }.Compact(false), Samples{ + }.Compact(), Samples{ StacktraceIDs: []uint32{1, 2, 3}, Values: []uint64{1, 2, 3}, }) @@ -317,7 +333,7 @@ func Benchmark_SpanID_Encoding(b *testing.B) { inMemoryProfiles := generateMemoryProfiles(profilesN) for j := range inMemoryProfiles { for i := range randomSpanIDs { - randomSpanIDs[i] = rand.Uint64() + randomSpanIDs[i] = mathrand.Uint64() } spans := make([]uint64, len(inMemoryProfiles[j].Samples.Values)) for o := range spans { @@ -443,13 +459,183 @@ func generateSamples(n int) []*Sample { } func Test_SamplesFromMap(t *testing.T) { - m := map[uint32]int64{ + m := map[uint32]uint64{ 1: 2, 0: 0, 2: 3, - 3: -1, + 3: 0, } samples := NewSamplesFromMap(m) assert.Equal(t, len(m), cap(samples.Values)) assert.Equal(t, 2, len(samples.Values)) } + +func Test_SamplesRange(t *testing.T) { + tests := []struct { + name string + input Samples + n, m int + expected Samples + }{ + { + name: "empty spans", + input: Samples{ + StacktraceIDs: []uint32{1, 2, 3, 4, 5}, + Values: []uint64{10, 20, 30, 40, 50}, + }, + n: 1, + m: 3, + expected: Samples{ + StacktraceIDs: []uint32{2, 3}, + Values: []uint64{20, 30}, + }, + }, + { + name: "non-empty Spans", + input: Samples{ + StacktraceIDs: []uint32{1, 2, 3, 4, 5}, + Values: []uint64{10, 20, 30, 40, 50}, + Spans: []uint64{100, 200, 300, 400, 500}, + }, + n: 1, + m: 4, + expected: Samples{ + StacktraceIDs: []uint32{2, 3, 4}, + Values: []uint64{20, 30, 40}, + Spans: []uint64{200, 300, 400}, + }, + }, + { + name: "all", + input: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{10, 20, 30}, + Spans: []uint64{100, 200, 300}, + }, + n: 0, + m: 3, + expected: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{10, 20, 30}, + Spans: []uint64{100, 200, 300}, + }, + }, + { + name: "oob: n < 0", + input: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{10, 20, 30}, + }, + n: -1, + m: 3, + }, + { + name: "oob: m > n", + input: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{10, 20, 30}, + }, + n: 3, + m: 1, + }, + { + name: "oob: m > len", + input: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{10, 20, 30}, + }, + n: 3, + m: 5, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.input.Range(tt.n, tt.m) + assert.Equal(t, tt.expected.StacktraceIDs, result.StacktraceIDs) + assert.Equal(t, tt.expected.Values, result.Values) + assert.Equal(t, tt.expected.Spans, result.Spans) + }) + } +} + +func TestColumnCount(t *testing.T) { + profiles := []InMemoryProfile{{ + SeriesIndex: 1, + TimeNanos: 2, + Samples: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{1, 2, 3}, + }, + }, + { + SeriesIndex: 1, + TimeNanos: 2, + Samples: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{1, 2, 3}, + Spans: []uint64{1, 2, 3}, + }, + }, + { + SeriesIndex: 1, + TimeNanos: 2, + Samples: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{1, 2, 3}, + Spans: []uint64{1, 2, 3}, + }, + Comments: []int64{1, 2, 3}, + }, + { + SeriesIndex: 1, + TimeNanos: 2, + Samples: Samples{ + StacktraceIDs: []uint32{1, 2, 3}, + Values: []uint64{1, 2, 3}, + Spans: []uint64{1, 2, 3}, + TraceIDs: [][16]byte{{1}, {2}, {3}}, + }, + }, + } + for _, profile := range profiles { + count := profileColumnCount(profile) + + row := deconstructMemoryProfile(profile, nil) + assert.Equal(t, len(row), count) + assert.Equal(t, cap(row), count) + } +} + +func TestSampleColumnsHasTraceID(t *testing.T) { + t.Run("new schema has TraceID", func(t *testing.T) { + var columns SampleColumns + err := columns.Resolve(ProfilesSchema) + require.NoError(t, err) + assert.True(t, columns.HasSpanID()) + assert.True(t, columns.HasTraceID()) + }) + + t.Run("old schema without TraceID", func(t *testing.T) { + // Simulate an old schema that doesn't have TraceID + oldSampleField := phlareparquet.Group{ + phlareparquet.NewGroupField("StacktraceID", parquet.Encoded(parquet.Uint(64), &parquet.DeltaBinaryPacked)), + phlareparquet.NewGroupField("Value", parquet.Encoded(parquet.Int(64), &parquet.DeltaBinaryPacked)), + phlareparquet.NewGroupField("Labels", pprofLabels), + phlareparquet.NewGroupField("SpanID", parquet.Optional(parquet.Encoded(parquet.Uint(64), &parquet.RLEDictionary))), + } + oldSchema := parquet.NewSchema("Profile", phlareparquet.Group{ + phlareparquet.NewGroupField("ID", parquet.UUID()), + phlareparquet.NewGroupField(SeriesIndexColumnName, parquet.Encoded(parquet.Uint(32), &parquet.DeltaBinaryPacked)), + phlareparquet.NewGroupField(StacktracePartitionColumnName, parquet.Encoded(parquet.Uint(64), &parquet.DeltaBinaryPacked)), + phlareparquet.NewGroupField(TotalValueColumnName, parquet.Encoded(parquet.Uint(64), &parquet.DeltaBinaryPacked)), + phlareparquet.NewGroupField(SamplesColumnName, parquet.List(oldSampleField)), + phlareparquet.NewGroupField(TimeNanosColumnName, parquet.Timestamp(parquet.Nanosecond)), + }) + var columns SampleColumns + err := columns.Resolve(oldSchema) + require.NoError(t, err) + assert.True(t, columns.HasSpanID()) + assert.False(t, columns.HasTraceID()) + }) +} diff --git a/pkg/phlaredb/schemas/v1/read_writer.go b/pkg/phlaredb/schemas/v1/read_writer.go index ed81af36ab..098cb0bf19 100644 --- a/pkg/phlaredb/schemas/v1/read_writer.go +++ b/pkg/phlaredb/schemas/v1/read_writer.go @@ -1,9 +1,6 @@ package v1 import ( - "io" - "sort" - "github.com/parquet-go/parquet-go" ) @@ -14,60 +11,6 @@ type PersisterName interface { type Persister[T any] interface { PersisterName Schema() *parquet.Schema - Deconstruct(parquet.Row, uint64, T) parquet.Row - Reconstruct(parquet.Row) (uint64, T, error) - SortingColumns() parquet.SortingOption -} - -type ReadWriter[T any, P Persister[T]] struct{} - -func (*ReadWriter[T, P]) WriteParquetFile(file io.Writer, elements []T) error { - var ( - persister P - rows = make([]parquet.Row, len(elements)) - ) - - buffer := parquet.NewBuffer(persister.Schema(), parquet.SortingRowGroupConfig(persister.SortingColumns())) - - for pos := range rows { - rows[pos] = persister.Deconstruct(rows[pos], uint64(pos), elements[pos]) - } - - if _, err := buffer.WriteRows(rows); err != nil { - return err - } - sort.Sort(buffer) - - writer := parquet.NewWriter(file, persister.Schema()) - if _, err := parquet.CopyRows(writer, buffer.Rows()); err != nil { - return err - } - - return writer.Close() -} - -func (*ReadWriter[T, P]) ReadParquetFile(file io.ReaderAt) ([]T, error) { - var ( - persister P - reader = parquet.NewReader(file, persister.Schema()) - ) - defer reader.Close() - - rows := make([]parquet.Row, reader.NumRows()) - if _, err := reader.ReadRows(rows); err != nil { - return nil, err - } - - var ( - elements = make([]T, reader.NumRows()) - err error - ) - for pos := range elements { - _, elements[pos], err = persister.Reconstruct(rows[pos]) - if err != nil { - return nil, err - } - } - - return elements, nil + Deconstruct(parquet.Row, T) parquet.Row + Reconstruct(parquet.Row) (T, error) } diff --git a/pkg/phlaredb/schemas/v1/schema_test.go b/pkg/phlaredb/schemas/v1/schema_test.go index b79106c39b..e424d2924f 100644 --- a/pkg/phlaredb/schemas/v1/schema_test.go +++ b/pkg/phlaredb/schemas/v1/schema_test.go @@ -2,6 +2,7 @@ package v1 import ( "bytes" + "io" "strings" "testing" @@ -24,6 +25,15 @@ func TestSchemaMatch(t *testing.T) { "optional group element", "required group element", ) + // []byte produces "optional binary TraceID" but our schema uses + // fixed_len_byte_array(16). We use []byte because parquet-go panics + // with [16]byte on null optional FixedLenByteArray values. + profilesStructSchema = strings.Replace( + profilesStructSchema, + "optional binary TraceID;", + "optional fixed_len_byte_array(16) TraceID;", + 1, + ) require.Equal(t, profilesStructSchema, ProfilesSchema.String()) @@ -68,7 +78,7 @@ func newStrings() []string { func TestStringsRoundTrip(t *testing.T) { var ( s = newStrings() - w = &ReadWriter[string, *StringPersister]{} + w = &ReadWriter[string, StringPersister]{} buf bytes.Buffer ) @@ -99,7 +109,8 @@ func newProfiles() []*Profile { }, }, }, - Comments: []int64{}, + Comments: []int64{}, + Annotations: []*Annotation{}, }, { ID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), @@ -119,7 +130,8 @@ func newProfiles() []*Profile { }, }, }, - Comments: []int64{}, + Comments: []int64{}, + Annotations: []*Annotation{}, }, { ID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), @@ -132,7 +144,8 @@ func newProfiles() []*Profile { Labels: []*profilev1.Label{}, }, }, - Comments: []int64{}, + Comments: []int64{}, + Annotations: []*Annotation{{Key: "key", Value: "test annotation"}}, }, { ID: uuid.MustParse("00000000-0000-0000-0000-000000000002"), @@ -145,7 +158,8 @@ func newProfiles() []*Profile { Labels: []*profilev1.Label{}, }, }, - Comments: []int64{}, + Comments: []int64{}, + Annotations: []*Annotation{}, }, } } @@ -198,9 +212,24 @@ func TestLocationsRoundTrip(t *testing.T) { }, IsFolded: false, }, + { + Id: 10, + Address: 11, + MappingId: 12, + // both pprofLocationPersister and LocationPersister deserialize as empty slice, not nil + Line: nil, + IsFolded: false, + }, + { + Id: 10, + Address: 11, + MappingId: 12, + Line: make([]*profilev1.Line, 0), + IsFolded: false, + }, } - mem := []*InMemoryLocation{ + mem := []InMemoryLocation{ { Id: 8, Address: 9, @@ -233,44 +262,84 @@ func TestLocationsRoundTrip(t *testing.T) { }, IsFolded: false, }, + { + Id: 10, + Address: 11, + MappingId: 12, + // both pprofLocationPersister and LocationPersister deserialize as empty slice, not nil + Line: nil, + IsFolded: false, + }, + { + Id: 10, + Address: 11, + MappingId: 12, + Line: make([]InMemoryLine, 0), + IsFolded: false, + }, + } + + expectedMem := func() []InMemoryLocation { + res := make([]InMemoryLocation, len(mem)) + for i, loc := range mem { + if loc.Line == nil { + loc.Line = make([]InMemoryLine, 0) + } + res[i] = loc + } + return res + } + + expectedRaw := func() []*profilev1.Location { + res := make([]*profilev1.Location, len(raw)) + for i, loc := range raw { + cloned := loc.CloneVT() + if cloned.Line == nil { + cloned.Line = make([]*profilev1.Line, 0) + } + res[i] = cloned + } + return res } var buf bytes.Buffer - require.NoError(t, new(ReadWriter[*profilev1.Location, *pprofLocationPersister]).WriteParquetFile(&buf, raw)) - actual, err := new(ReadWriter[*InMemoryLocation, *LocationPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) + require.NoError(t, new(ReadWriter[*profilev1.Location, pprofLocationPersister]).WriteParquetFile(&buf, raw)) + actualMem, err := new(ReadWriter[InMemoryLocation, LocationPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) require.NoError(t, err) - assert.Equal(t, mem, actual) + assert.Equal(t, expectedMem(), actualMem) buf.Reset() - require.NoError(t, new(ReadWriter[*InMemoryLocation, *LocationPersister]).WriteParquetFile(&buf, mem)) - actual, err = new(ReadWriter[*InMemoryLocation, *LocationPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) + require.NoError(t, new(ReadWriter[InMemoryLocation, LocationPersister]).WriteParquetFile(&buf, mem)) + actualMem, err = new(ReadWriter[InMemoryLocation, LocationPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) require.NoError(t, err) - assert.Equal(t, mem, actual) + assert.Equal(t, expectedMem(), actualMem) + + buf.Reset() + require.NoError(t, new(ReadWriter[*profilev1.Location, pprofLocationPersister]).WriteParquetFile(&buf, raw)) + actualRaw, err := new(ReadWriter[*profilev1.Location, pprofLocationPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) + require.NoError(t, err) + assert.Equal(t, expectedRaw(), actualRaw) } var protoLocationsSchema = parquet.SchemaOf(&profilev1.Location{}) type pprofLocationPersister struct{} -func (*pprofLocationPersister) Name() string { return "locations" } - -func (*pprofLocationPersister) Schema() *parquet.Schema { return protoLocationsSchema } +func (pprofLocationPersister) Name() string { return "locations" } -func (*pprofLocationPersister) SortingColumns() parquet.SortingOption { - return parquet.SortingColumns() -} +func (pprofLocationPersister) Schema() *parquet.Schema { return protoLocationsSchema } -func (*pprofLocationPersister) Deconstruct(row parquet.Row, _ uint64, loc *profilev1.Location) parquet.Row { +func (pprofLocationPersister) Deconstruct(row parquet.Row, loc *profilev1.Location) parquet.Row { row = protoLocationsSchema.Deconstruct(row, loc) return row } -func (*pprofLocationPersister) Reconstruct(row parquet.Row) (uint64, *profilev1.Location, error) { +func (pprofLocationPersister) Reconstruct(row parquet.Row) (*profilev1.Location, error) { var loc profilev1.Location if err := protoLocationsSchema.Reconstruct(&loc, row); err != nil { - return 0, nil, err + return nil, err } - return 0, &loc, nil + return &loc, nil } func TestFunctionsRoundTrip(t *testing.T) { @@ -291,7 +360,7 @@ func TestFunctionsRoundTrip(t *testing.T) { }, } - mem := []*InMemoryFunction{ + mem := []InMemoryFunction{ { Id: 6, Name: 7, @@ -310,13 +379,13 @@ func TestFunctionsRoundTrip(t *testing.T) { var buf bytes.Buffer require.NoError(t, new(ReadWriter[*profilev1.Function, *pprofFunctionPersister]).WriteParquetFile(&buf, raw)) - actual, err := new(ReadWriter[*InMemoryFunction, *FunctionPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) + actual, err := new(ReadWriter[InMemoryFunction, FunctionPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) require.NoError(t, err) assert.Equal(t, mem, actual) buf.Reset() - require.NoError(t, new(ReadWriter[*InMemoryFunction, *FunctionPersister]).WriteParquetFile(&buf, mem)) - actual, err = new(ReadWriter[*InMemoryFunction, *FunctionPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) + require.NoError(t, new(ReadWriter[InMemoryFunction, FunctionPersister]).WriteParquetFile(&buf, mem)) + actual, err = new(ReadWriter[InMemoryFunction, FunctionPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) require.NoError(t, err) assert.Equal(t, mem, actual) } @@ -329,21 +398,17 @@ func (*pprofFunctionPersister) Name() string { return "functions" } func (*pprofFunctionPersister) Schema() *parquet.Schema { return protoFunctionSchema } -func (*pprofFunctionPersister) SortingColumns() parquet.SortingOption { - return parquet.SortingColumns() -} - -func (*pprofFunctionPersister) Deconstruct(row parquet.Row, _ uint64, loc *profilev1.Function) parquet.Row { +func (*pprofFunctionPersister) Deconstruct(row parquet.Row, loc *profilev1.Function) parquet.Row { row = protoFunctionSchema.Deconstruct(row, loc) return row } -func (*pprofFunctionPersister) Reconstruct(row parquet.Row) (uint64, *profilev1.Function, error) { +func (*pprofFunctionPersister) Reconstruct(row parquet.Row) (*profilev1.Function, error) { var fn profilev1.Function if err := protoFunctionSchema.Reconstruct(&fn, row); err != nil { - return 0, nil, err + return nil, err } - return 0, &fn, nil + return &fn, nil } func TestMappingsRoundTrip(t *testing.T) { @@ -374,7 +439,7 @@ func TestMappingsRoundTrip(t *testing.T) { }, } - mem := []*InMemoryMapping{ + mem := []InMemoryMapping{ { Id: 7, MemoryStart: 8, @@ -403,7 +468,7 @@ func TestMappingsRoundTrip(t *testing.T) { var buf bytes.Buffer require.NoError(t, new(ReadWriter[*profilev1.Mapping, *pprofMappingPersister]).WriteParquetFile(&buf, raw)) - actual, err := new(ReadWriter[*InMemoryMapping, *MappingPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) + actual, err := new(ReadWriter[InMemoryMapping, MappingPersister]).ReadParquetFile(bytes.NewReader(buf.Bytes())) require.NoError(t, err) assert.Equal(t, mem, actual) @@ -422,17 +487,67 @@ func (*pprofMappingPersister) Name() string { return "mappings" } func (*pprofMappingPersister) Schema() *parquet.Schema { return protoMappingSchema } -func (*pprofMappingPersister) SortingColumns() parquet.SortingOption { return parquet.SortingColumns() } - -func (*pprofMappingPersister) Deconstruct(row parquet.Row, _ uint64, loc *profilev1.Mapping) parquet.Row { +func (*pprofMappingPersister) Deconstruct(row parquet.Row, loc *profilev1.Mapping) parquet.Row { row = protoMappingSchema.Deconstruct(row, loc) return row } -func (*pprofMappingPersister) Reconstruct(row parquet.Row) (uint64, *profilev1.Mapping, error) { +func (*pprofMappingPersister) Reconstruct(row parquet.Row) (*profilev1.Mapping, error) { var m profilev1.Mapping if err := protoMappingSchema.Reconstruct(&m, row); err != nil { - return 0, nil, err + return nil, err } - return 0, &m, nil + return &m, nil +} + +type ReadWriter[T any, P Persister[T]] struct{} + +func (r *ReadWriter[T, P]) WriteParquetFile(file io.Writer, elements []T) error { + var ( + persister P + rows = make([]parquet.Row, len(elements)) + ) + + buffer := parquet.NewBuffer(persister.Schema()) + + for pos := range rows { + rows[pos] = persister.Deconstruct(rows[pos], elements[pos]) + } + + if _, err := buffer.WriteRows(rows); err != nil { + return err + } + + writer := parquet.NewWriter(file, persister.Schema()) + if _, err := parquet.CopyRows(writer, buffer.Rows()); err != nil { + return err + } + + return writer.Close() +} + +func (*ReadWriter[T, P]) ReadParquetFile(file io.ReaderAt) ([]T, error) { + var ( + persister P + reader = parquet.NewReader(file, persister.Schema()) + ) + defer reader.Close() + + rows := make([]parquet.Row, reader.NumRows()) + if _, err := reader.ReadRows(rows); err != nil && err != io.EOF { + return nil, err + } + + var ( + elements = make([]T, reader.NumRows()) + err error + ) + for pos := range elements { + elements[pos], err = persister.Reconstruct(rows[pos]) + if err != nil { + return nil, err + } + } + + return elements, nil } diff --git a/pkg/phlaredb/schemas/v1/stacktraces.go b/pkg/phlaredb/schemas/v1/stacktraces.go index ae07c0c14f..448d96acdc 100644 --- a/pkg/phlaredb/schemas/v1/stacktraces.go +++ b/pkg/phlaredb/schemas/v1/stacktraces.go @@ -3,7 +3,7 @@ package v1 import ( "github.com/parquet-go/parquet-go" - phlareparquet "github.com/grafana/pyroscope/pkg/parquet" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" ) var stacktracesSchema = parquet.NewSchema("Stacktrace", phlareparquet.Group{ @@ -30,25 +30,17 @@ func (*StacktracePersister) Schema() *parquet.Schema { return stacktracesSchema } -func (*StacktracePersister) SortingColumns() parquet.SortingOption { - return parquet.SortingColumns( - parquet.Ascending("ID"), - parquet.Ascending("LocationIDs", "list", "element"), - ) -} - -func (*StacktracePersister) Deconstruct(row parquet.Row, id uint64, s *Stacktrace) parquet.Row { +func (*StacktracePersister) Deconstruct(row parquet.Row, s *Stacktrace) parquet.Row { var stored storedStacktrace - stored.ID = id stored.LocationIDs = s.LocationIDs row = stacktracesSchema.Deconstruct(row, &stored) return row } -func (*StacktracePersister) Reconstruct(row parquet.Row) (id uint64, s *Stacktrace, err error) { +func (*StacktracePersister) Reconstruct(row parquet.Row) (s *Stacktrace, err error) { var stored storedStacktrace if err := stacktracesSchema.Reconstruct(&stored, row); err != nil { - return 0, nil, err + return nil, err } - return stored.ID, &Stacktrace{LocationIDs: stored.LocationIDs}, nil + return &Stacktrace{LocationIDs: stored.LocationIDs}, nil } diff --git a/pkg/phlaredb/schemas/v1/strings.go b/pkg/phlaredb/schemas/v1/strings.go index 844aa460dc..ff9476e187 100644 --- a/pkg/phlaredb/schemas/v1/strings.go +++ b/pkg/phlaredb/schemas/v1/strings.go @@ -3,7 +3,7 @@ package v1 import ( "github.com/parquet-go/parquet-go" - phlareparquet "github.com/grafana/pyroscope/pkg/parquet" + phlareparquet "github.com/grafana/pyroscope/v2/pkg/parquet" ) var stringsSchema = parquet.NewSchema("String", phlareparquet.Group{ @@ -13,22 +13,20 @@ var stringsSchema = parquet.NewSchema("String", phlareparquet.Group{ type StringPersister struct{} -func (*StringPersister) Name() string { return "strings" } +func (StringPersister) Name() string { return "strings" } -func (*StringPersister) Schema() *parquet.Schema { return stringsSchema } +func (StringPersister) Schema() *parquet.Schema { return stringsSchema } -func (*StringPersister) SortingColumns() parquet.SortingOption { return parquet.SortingColumns() } - -func (*StringPersister) Deconstruct(row parquet.Row, id uint64, s string) parquet.Row { +func (StringPersister) Deconstruct(row parquet.Row, s string) parquet.Row { if cap(row) < 2 { row = make(parquet.Row, 0, 2) } row = row[:0] - row = append(row, parquet.Int64Value(int64(id)).Level(0, 0, 0)) + row = append(row, parquet.Int64Value(int64(0)).Level(0, 0, 0)) row = append(row, parquet.ByteArrayValue([]byte(s)).Level(0, 0, 1)) return row } -func (*StringPersister) Reconstruct(row parquet.Row) (id uint64, s string, err error) { - return 0, row[1].String(), nil +func (StringPersister) Reconstruct(row parquet.Row) (s string, err error) { + return row[1].String(), nil } diff --git a/pkg/phlaredb/schemas/v1/testhelper/profile.go b/pkg/phlaredb/schemas/v1/testhelper/profile.go index 5829b44476..efb33f1689 100644 --- a/pkg/phlaredb/schemas/v1/testhelper/profile.go +++ b/pkg/phlaredb/schemas/v1/testhelper/profile.go @@ -4,16 +4,17 @@ import ( "github.com/google/uuid" "github.com/prometheus/common/model" - profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/labels" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/pprof" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/labels" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) -func NewProfileSchema(p *profilev1.Profile, name string) ([]schemav1.InMemoryProfile, []phlaremodel.Labels) { +func NewProfileSchema(builder *testhelper.ProfileBuilder, name string) ([]schemav1.InMemoryProfile, []phlaremodel.Labels) { var ( + p = builder.Profile lbls, seriesRefs = labels.CreateProfileLabels(true, p, &typesv1.LabelPair{Name: model.MetricNameLabel, Value: name}) ps = make([]schemav1.InMemoryProfile, len(lbls)) ) @@ -27,6 +28,10 @@ func NewProfileSchema(p *profilev1.Profile, name string) ([]schemav1.InMemoryPro KeepFrames: p.KeepFrames, Period: p.Period, DefaultSampleType: p.DefaultSampleType, + Annotations: schemav1.Annotations{ + Keys: make([]string, 0), + Values: make([]string, 0), + }, } hashes := pprof.SampleHasher{}.Hashes(p.Sample) ps[idxType].Samples = schemav1.Samples{ @@ -39,6 +44,10 @@ func NewProfileSchema(p *profilev1.Profile, name string) ([]schemav1.InMemoryPro } ps[idxType].SeriesFingerprint = seriesRefs[idxType] + for _, a := range builder.Annotations { + ps[idxType].Annotations.Keys = append(ps[idxType].Annotations.Keys, a.Key) + ps[idxType].Annotations.Values = append(ps[idxType].Annotations.Values, a.Value) + } } return ps, lbls } diff --git a/pkg/phlaredb/sharding/label.go b/pkg/phlaredb/sharding/label.go index d9db0df453..c072ad8646 100644 --- a/pkg/phlaredb/sharding/label.go +++ b/pkg/phlaredb/sharding/label.go @@ -7,7 +7,6 @@ import ( "strconv" "strings" - "github.com/pkg/errors" "github.com/prometheus/prometheus/model/labels" ) @@ -86,20 +85,20 @@ func ParseShardIDLabelValue(val string) (index, shardCount uint64, _ error) { // If we fail to parse shardID, we better not consider this block fully included in successors. matches := strings.Split(val, "_") if len(matches) != 3 || matches[1] != "of" { - return 0, 0, errors.Errorf("invalid shard ID: %q", val) + return 0, 0, fmt.Errorf("invalid shard ID: %q", val) } index, err := strconv.ParseUint(matches[0], 10, 64) if err != nil { - return 0, 0, errors.Errorf("invalid shard ID: %q: %v", val, err) + return 0, 0, fmt.Errorf("invalid shard ID: %q: %v", val, err) } count, err := strconv.ParseUint(matches[2], 10, 64) if err != nil { - return 0, 0, errors.Errorf("invalid shard ID: %q: %v", val, err) + return 0, 0, fmt.Errorf("invalid shard ID: %q: %v", val, err) } if index == 0 || count == 0 || index > count { - return 0, 0, errors.Errorf("invalid shard ID: %q", val) + return 0, 0, fmt.Errorf("invalid shard ID: %q", val) } return index - 1, count, nil diff --git a/pkg/phlaredb/sharding/label_test.go b/pkg/phlaredb/sharding/label_test.go index 2ce1e6b239..112f74abad 100644 --- a/pkg/phlaredb/sharding/label_test.go +++ b/pkg/phlaredb/sharding/label_test.go @@ -7,6 +7,7 @@ import ( "math/rand" "testing" + prommodel "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -82,18 +83,18 @@ func TestRemoveShardFromMatchers(t *testing.T) { "should return no shard on empty label matchers": {}, "should return no shard on no shard label matcher": { input: []*labels.Matcher{ - labels.MustNewMatcher(labels.MatchEqual, labels.MetricName, "test"), + labels.MustNewMatcher(labels.MatchEqual, string(prommodel.MetricNameLabel), "test"), labels.MustNewMatcher(labels.MatchRegexp, "foo", "bar.*"), }, expectedShard: nil, expectedMatchers: []*labels.Matcher{ - labels.MustNewMatcher(labels.MatchEqual, labels.MetricName, "test"), + labels.MustNewMatcher(labels.MatchEqual, string(prommodel.MetricNameLabel), "test"), labels.MustNewMatcher(labels.MatchRegexp, "foo", "bar.*"), }, }, "should return matching shard and filter out its matcher": { input: []*labels.Matcher{ - labels.MustNewMatcher(labels.MatchEqual, labels.MetricName, "test"), + labels.MustNewMatcher(labels.MatchEqual, string(prommodel.MetricNameLabel), "test"), labels.MustNewMatcher(labels.MatchEqual, ShardLabel, ShardSelector{ShardIndex: 1, ShardCount: 8}.LabelValue()), labels.MustNewMatcher(labels.MatchRegexp, "foo", "bar.*"), }, @@ -102,7 +103,7 @@ func TestRemoveShardFromMatchers(t *testing.T) { ShardCount: 8, }, expectedMatchers: []*labels.Matcher{ - labels.MustNewMatcher(labels.MatchEqual, labels.MetricName, "test"), + labels.MustNewMatcher(labels.MatchEqual, string(prommodel.MetricNameLabel), "test"), labels.MustNewMatcher(labels.MatchRegexp, "foo", "bar.*"), }, }, diff --git a/pkg/phlaredb/shipper/shipper.go b/pkg/phlaredb/shipper/shipper.go index 7fbf0f641e..402c4fd568 100644 --- a/pkg/phlaredb/shipper/shipper.go +++ b/pkg/phlaredb/shipper/shipper.go @@ -11,6 +11,7 @@ package shipper import ( "context" "encoding/json" + "fmt" "math" "os" "path" @@ -20,8 +21,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/runutil" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/common/model" @@ -29,7 +29,7 @@ import ( "github.com/prometheus/prometheus/tsdb/fileutil" "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) type metrics struct { @@ -122,7 +122,7 @@ func (s *Shipper) Timestamps() (minTime, maxSyncTime model.Time, err error) { ctx := context.Background() meta, err := ReadMetaFile(s.blockLister.LocalDataPath()) if err != nil { - return 0, 0, errors.Wrap(err, "read shipper meta file") + return 0, 0, fmt.Errorf("read shipper meta file: %w", err) } // Build a map of blocks we already uploaded. hasUploaded := make(map[ulid.ULID]struct{}, len(meta.Uploaded)) @@ -188,7 +188,7 @@ func (c *lazyOverlapChecker) sync(ctx context.Context) error { return nil }); err != nil { - return errors.Wrap(err, "get all block meta.") + return fmt.Errorf("get all block meta.: %w", err) } c.synced = true @@ -210,7 +210,7 @@ func (c *lazyOverlapChecker) IsOverlapping(ctx context.Context, newMeta tsdb.Blo }) if o := tsdb.OverlappingBlocks(metas); len(o) > 0 { // TODO(bwplotka): Consider checking if overlaps relates to block in concern? - return errors.Errorf("shipping compacted block %s is blocked; overlap spotted: %s", newMeta.ULID, o.String()) + return fmt.Errorf("shipping compacted block %s is blocked; overlap spotted: %s", newMeta.ULID, o.String()) } return nil } @@ -269,7 +269,7 @@ func (s *Shipper) Sync(ctx context.Context) (uploaded int, err error) { // Check against bucket if the meta file for this block exists. ok, err := s.bucket.Exists(ctx, path.Join(m.ULID.String(), block.MetaFilename)) if err != nil { - return 0, errors.Wrap(err, "check exists") + return 0, fmt.Errorf("check exists: %w", err) } if ok { meta.Uploaded = append(meta.Uploaded, m.ULID) @@ -279,13 +279,13 @@ func (s *Shipper) Sync(ctx context.Context) (uploaded int, err error) { // Skip overlap check if out of order uploads is enabled. if m.Compaction.Level > 1 && !s.allowOutOfOrderUploads { if err := checker.IsOverlapping(ctx, m.TSDBBlockMeta()); err != nil { - return 0, errors.Errorf("Found overlap or error during sync, cannot upload compacted block, details: %v", err) + return 0, fmt.Errorf("found overlap or error during sync, cannot upload compacted block, details: %w", err) } } if err := s.upload(ctx, m); err != nil { if !s.allowOutOfOrderUploads { - return 0, errors.Wrapf(err, "upload %v", m.ULID) + return 0, fmt.Errorf("upload %v: %w", m.ULID, err) } // No error returned, just log line. This is because we want other blocks to be uploaded even @@ -305,7 +305,7 @@ func (s *Shipper) Sync(ctx context.Context) (uploaded int, err error) { s.metrics.dirSyncs.Inc() if uploadErrs > 0 { s.metrics.uploadFailures.Add(float64(uploadErrs)) - return uploaded, errors.Errorf("failed to sync %v blocks", uploadErrs) + return uploaded, fmt.Errorf("failed to sync %v blocks", uploadErrs) } if s.uploadCompacted { @@ -323,7 +323,7 @@ func (s *Shipper) upload(ctx context.Context, meta *block.Meta) error { meta.Source = s.source if _, err := meta.WriteToFile(s.logger, updir); err != nil { - return errors.Wrap(err, "write meta file") + return fmt.Errorf("write meta file: %w", err) } return block.Upload(ctx, s.logger, s.bucket, updir) } @@ -378,7 +378,7 @@ func ReadMetaFile(dir string) (*Meta, error) { return nil, err } if m.Version != MetaVersion1 { - return nil, errors.Errorf("unexpected meta file version %d", m.Version) + return nil, fmt.Errorf("unexpected meta file version %d", m.Version) } return &m, nil diff --git a/pkg/phlaredb/symdb/block_reader.go b/pkg/phlaredb/symdb/block_reader.go index 636115be32..6a89c9605c 100644 --- a/pkg/phlaredb/symdb/block_reader.go +++ b/pkg/phlaredb/symdb/block_reader.go @@ -1,9 +1,9 @@ +//nolint:unused package symdb import ( "bufio" "context" - "errors" "fmt" "hash/crc32" "io" @@ -12,75 +12,246 @@ import ( "sync" "github.com/grafana/dskit/multierror" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" - "github.com/parquet-go/parquet-go" + "github.com/grafana/dskit/tracing" "golang.org/x/sync/errgroup" - "github.com/grafana/pyroscope/pkg/objstore" - parquetobj "github.com/grafana/pyroscope/pkg/objstore/parquet" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/util/refctr" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/util/bufferpool" + "github.com/grafana/pyroscope/v2/pkg/util/refctr" ) type Reader struct { bucket objstore.BucketReader - files map[string]block.File - meta *block.Meta + file block.File + index IndexFile + footer Footer - chunkFetchBufferSize int - - index IndexFile partitions []*partition partitionsMap map[uint64]*partition - locations parquetobj.File - mappings parquetobj.File - functions parquetobj.File - strings parquetobj.File + // Not used in v3; left for compatibility. + meta *block.Meta + files map[string]block.File + parquetFiles *parquetFiles + + prefetchSize uint64 +} + +type Option func(*Reader) + +func WithPrefetchSize(size uint64) Option { + return func(r *Reader) { + r.prefetchSize = size + } } -const defaultChunkFetchBufferSize = 4096 +func OpenObject(ctx context.Context, b objstore.BucketReader, name string, offset, size int64, options ...Option) (*Reader, error) { + f := block.File{ + RelPath: name, + SizeBytes: uint64(size), + } + r := &Reader{ + bucket: objstore.NewBucketReaderWithOffset(b, offset), + file: f, + } + for _, opt := range options { + opt(r) + } + + var err error + if r.prefetchSize > 0 { + err = r.openIndexWithPrefetch(ctx) + } else { + err = r.openIndex(ctx) + } + if err != nil { + return nil, fmt.Errorf("opening index section: %w", err) + } + + if err = r.buildPartitions(); err != nil { + return nil, err + } + + return r, nil +} + +func (r *Reader) openIndexWithPrefetch(ctx context.Context) (err error) { + prefetchSize := r.prefetchSize + if prefetchSize > r.file.SizeBytes { + prefetchSize = r.file.SizeBytes + } + n, err := r.prefetchIndex(ctx, prefetchSize) + if err == nil && n != 0 { + _, err = r.prefetchIndex(ctx, prefetchSize) + } + return err +} + +func (r *Reader) prefetchIndex(ctx context.Context, size uint64) (n uint64, err error) { + if size < uint64(FooterSize) { + size = uint64(FooterSize) + } + prefetchOffset := r.file.SizeBytes - size + buf := bufferpool.GetBuffer(int(size)) + defer bufferpool.Put(buf) + if err = objstore.ReadRange(ctx, buf, r.file.RelPath, r.bucket, int64(prefetchOffset), int64(size)); err != nil { + return 0, fmt.Errorf("fetching index: %w", err) + } + footerOffset := size - uint64(FooterSize) + if err = r.footer.UnmarshalBinary(buf.B[footerOffset:]); err != nil { + return 0, fmt.Errorf("unmarshaling footer: %w", err) + } + if prefetchOffset > (r.footer.IndexOffset) { + return r.file.SizeBytes - r.footer.IndexOffset, nil + } + // prefetch offset is less that or equal to the index offset. + indexOffset := r.footer.IndexOffset - prefetchOffset + if r.index, err = OpenIndex(buf.B[indexOffset:footerOffset]); err != nil { + return 0, fmt.Errorf("opening index: %w", err) + } + return 0, nil +} func Open(ctx context.Context, b objstore.BucketReader, m *block.Meta) (*Reader, error) { - r := Reader{ + r := &Reader{ bucket: b, meta: m, files: make(map[string]block.File), - - chunkFetchBufferSize: defaultChunkFetchBufferSize, + file: block.File{RelPath: DefaultFileName}, + } + for _, f := range r.meta.Files { + r.files[filepath.Base(f.RelPath)] = f } if err := r.open(ctx); err != nil { return nil, err } - return &r, nil + if err := r.buildPartitions(); err != nil { + return nil, err + } + return r, nil } func (r *Reader) open(ctx context.Context) (err error) { - for _, f := range r.meta.Files { - r.files[filepath.Base(f.RelPath)] = f + if r.file, err = r.lookupFile(r.file.RelPath); err == nil { + if err = r.openIndex(ctx); err != nil { + return fmt.Errorf("opening index section: %w", err) + } + return nil } - if err = r.openIndexFile(ctx); err != nil { + if err = r.openIndexV12(ctx); err != nil { return fmt.Errorf("opening index file: %w", err) } if r.index.Header.Version == FormatV2 { - if err = r.openParquetFiles(ctx); err != nil { - return err + if err = openParquetFiles(ctx, r); err != nil { + return fmt.Errorf("opening parquet files: %w", err) } } + return nil +} + +func (r *Reader) buildPartitions() (err error) { r.partitionsMap = make(map[uint64]*partition, len(r.index.PartitionHeaders)) r.partitions = make([]*partition, len(r.index.PartitionHeaders)) for i, h := range r.index.PartitionHeaders { - ph := r.partitionReader(h) - r.partitionsMap[h.Partition] = ph - r.partitions[i] = ph + var p *partition + if p, err = r.partitionReader(h); err != nil { + return err + } + r.partitionsMap[h.Partition] = p + r.partitions[i] = p + } + // Cleanup the index to not retain unused objects. + r.index = IndexFile{ + Header: IndexHeader{ + Version: r.index.Header.Version, + }, } return nil } -func (r *Reader) openIndexFile(ctx context.Context) error { - f, err := r.file(IndexFileName) +func (r *Reader) partitionReader(h *PartitionHeader) (*partition, error) { + p := &partition{reader: r} + switch r.index.Header.Version { + case FormatV1: + p.initEmptyTables(h) + case FormatV2: + p.initParquetTables(h) + case FormatV3: + if err := p.initTables(h); err != nil { + return nil, err + } + } + p.initStacktraces(h.Stacktraces) + return p, nil +} + +// openIndex locates footer and loads the index section from +// the file into the memory. +func (r *Reader) openIndex(ctx context.Context) error { + if r.file.SizeBytes == 0 { + attrs, err := r.bucket.Attributes(ctx, r.file.RelPath) + if err != nil { + return fmt.Errorf("fetching file attributes: %w", err) + } + r.file.SizeBytes = uint64(attrs.Size) + } + // Read footer. + offset := int64(r.file.SizeBytes) - int64(FooterSize) + if offset < int64(IndexHeaderSize) { + return fmt.Errorf("%w: footer offset: %d", ErrInvalidSize, offset) + } + if err := r.readFooter(ctx, offset, int64(FooterSize)); err != nil { + return err + } + indexSize := offset - int64(r.footer.IndexOffset) + if indexSize < int64(IndexHeaderSize) { + return fmt.Errorf("%w: index section size: %d", ErrInvalidSize, indexSize) + } + return r.readIndexSection(ctx, int64(r.footer.IndexOffset), indexSize) +} + +func (r *Reader) readFooter(ctx context.Context, offset, size int64) error { + o, err := r.bucket.GetRange(ctx, r.file.RelPath, offset, size) + if err != nil { + return fmt.Errorf("fetching footer: %w", err) + } + defer func() { + _ = o.Close() + }() + buf := make([]byte, size) + if _, err = io.ReadFull(o, buf); err != nil { + return fmt.Errorf("reading footer: %w", err) + } + if err = r.footer.UnmarshalBinary(buf); err != nil { + return fmt.Errorf("unmarshaling footer: %w", err) + } + return nil +} + +func (r *Reader) readIndexSection(ctx context.Context, offset, size int64) error { + o, err := r.bucket.GetRange(ctx, r.file.RelPath, offset, size) + if err != nil { + return fmt.Errorf("fetching index: %w", err) + } + defer func() { + _ = o.Close() + }() + buf := make([]byte, int(size)) + if _, err = io.ReadFull(o, buf); err != nil { + return fmt.Errorf("reading index: %w", err) + } + r.index, err = OpenIndex(buf) + if err != nil { + return fmt.Errorf("opening index: %w", err) + } + return nil +} + +func (r *Reader) openIndexV12(ctx context.Context) error { + f, err := r.lookupFile(IndexFileName) if err != nil { return err } @@ -88,48 +259,18 @@ func (r *Reader) openIndexFile(ctx context.Context) error { if err != nil { return err } + defer func() { + _ = o.Close() + }() b, err := io.ReadAll(o) if err != nil { return err } - r.index, err = ReadIndexFile(b) + r.index, err = OpenIndex(b) return err } -const parquetReadBufferSize = 256 << 10 // 256KB - -func (r *Reader) openParquetFiles(ctx context.Context) error { - options := []parquet.FileOption{ - parquet.SkipBloomFilters(true), // we don't use bloom filters - parquet.FileReadMode(parquet.ReadModeAsync), - parquet.ReadBufferSize(parquetReadBufferSize), - } - - m := map[string]*parquetobj.File{ - new(schemav1.LocationPersister).Name() + block.ParquetSuffix: &r.locations, - new(schemav1.MappingPersister).Name() + block.ParquetSuffix: &r.mappings, - new(schemav1.FunctionPersister).Name() + block.ParquetSuffix: &r.functions, - new(schemav1.StringPersister).Name() + block.ParquetSuffix: &r.strings, - } - g, ctx := errgroup.WithContext(ctx) - for n, fp := range m { - n := n - fp := fp - g.Go(func() error { - fm, err := r.file(n) - if err != nil { - return err - } - if err = fp.Open(ctx, r.bucket, fm, options...); err != nil { - return fmt.Errorf("openning file %q: %w", n, err) - } - return nil - }) - } - return g.Wait() -} - -func (r *Reader) file(name string) (block.File, error) { +func (r *Reader) lookupFile(name string) (block.File, error) { f, ok := r.files[name] if !ok { return block.File{}, fmt.Errorf("%q: %w", name, os.ErrNotExist) @@ -137,44 +278,14 @@ func (r *Reader) file(name string) (block.File, error) { return f, nil } -func (r *Reader) partitionReader(h *PartitionHeader) *partition { - p := &partition{ - reader: r, - locations: parquetTableRange[*schemav1.InMemoryLocation, *schemav1.LocationPersister]{ - bucket: r.bucket, - headers: h.Locations, - file: &r.locations, - }, - mappings: parquetTableRange[*schemav1.InMemoryMapping, *schemav1.MappingPersister]{ - bucket: r.bucket, - headers: h.Mappings, - file: &r.mappings, - }, - functions: parquetTableRange[*schemav1.InMemoryFunction, *schemav1.FunctionPersister]{ - bucket: r.bucket, - headers: h.Functions, - file: &r.functions, - }, - strings: parquetTableRange[string, *schemav1.StringPersister]{ - bucket: r.bucket, - headers: h.Strings, - file: &r.strings, - }, - } - p.setStacktracesChunks(h.StacktraceChunks) - return p -} - func (r *Reader) Close() error { if r == nil { return nil } - return multierror.New( - r.locations.Close(), - r.mappings.Close(), - r.functions.Close(), - r.strings.Close()). - Err() + if r.parquetFiles != nil { + return r.parquetFiles.Close() + } + return nil } var ErrPartitionNotFound = fmt.Errorf("partition not found") @@ -192,7 +303,7 @@ func (r *Reader) partition(ctx context.Context, partition uint64) (*partition, e if !ok { return nil, ErrPartitionNotFound } - if err := p.init(ctx); err != nil { + if err := p.fetch(ctx); err != nil { return nil, err } return p, nil @@ -201,14 +312,19 @@ func (r *Reader) partition(ctx context.Context, partition uint64) (*partition, e type partition struct { reader *Reader - stacktraceChunks []*stacktraceChunkReader - locations parquetTableRange[*schemav1.InMemoryLocation, *schemav1.LocationPersister] - mappings parquetTableRange[*schemav1.InMemoryMapping, *schemav1.MappingPersister] - functions parquetTableRange[*schemav1.InMemoryFunction, *schemav1.FunctionPersister] - strings parquetTableRange[string, *schemav1.StringPersister] + stacktraces []*stacktraceBlock + locations table[schemav1.InMemoryLocation] + mappings table[schemav1.InMemoryMapping] + functions table[schemav1.InMemoryFunction] + strings table[string] } -func (p *partition) init(ctx context.Context) (err error) { +type table[T any] interface { + fetchable + slice() []T +} + +func (p *partition) fetch(ctx context.Context) (err error) { return p.tx().fetch(ctx) } @@ -217,68 +333,140 @@ func (p *partition) Release() { } func (p *partition) tx() *fetchTx { - tx := make(fetchTx, 0, len(p.stacktraceChunks)+4) - for _, c := range p.stacktraceChunks { + tx := make(fetchTx, 0, len(p.stacktraces)+4) + for _, c := range p.stacktraces { tx.append(c) } if p.reader.index.Header.Version > FormatV1 { - tx.append(&p.locations) - tx.append(&p.mappings) - tx.append(&p.functions) - tx.append(&p.strings) + tx.append(p.locations) + tx.append(p.mappings) + tx.append(p.functions) + tx.append(p.strings) } return &tx } +// Format V1. +func (p *partition) initEmptyTables(*PartitionHeader) { + p.locations = emptyTable[schemav1.InMemoryLocation]{} + p.mappings = emptyTable[schemav1.InMemoryMapping]{} + p.functions = emptyTable[schemav1.InMemoryFunction]{} + p.strings = emptyTable[string]{} +} + +// Format V2. +func (p *partition) initParquetTables(h *PartitionHeader) { + p.locations = &parquetTable[schemav1.InMemoryLocation, schemav1.LocationPersister]{ + bucket: p.reader.bucket, + headers: h.V2.Locations, + file: &p.reader.parquetFiles.locations, + } + p.mappings = &parquetTable[schemav1.InMemoryMapping, schemav1.MappingPersister]{ + bucket: p.reader.bucket, + headers: h.V2.Mappings, + file: &p.reader.parquetFiles.mappings, + } + p.functions = &parquetTable[schemav1.InMemoryFunction, schemav1.FunctionPersister]{ + bucket: p.reader.bucket, + headers: h.V2.Functions, + file: &p.reader.parquetFiles.functions, + } + p.strings = &parquetTable[string, schemav1.StringPersister]{ + bucket: p.reader.bucket, + headers: h.V2.Strings, + file: &p.reader.parquetFiles.strings, + } +} + +// Format V3. +func (p *partition) initTables(h *PartitionHeader) (err error) { + locations := &rawTable[schemav1.InMemoryLocation]{ + reader: p.reader, + header: h.V3.Locations, + } + if locations.dec, err = newLocationsDecoder(h.V3.Locations); err != nil { + return err + } + p.locations = locations + + mappings := &rawTable[schemav1.InMemoryMapping]{ + reader: p.reader, + header: h.V3.Mappings, + } + if mappings.dec, err = newMappingsDecoder(h.V3.Mappings); err != nil { + return err + } + p.mappings = mappings + + functions := &rawTable[schemav1.InMemoryFunction]{ + reader: p.reader, + header: h.V3.Functions, + } + if functions.dec, err = newFunctionsDecoder(h.V3.Functions); err != nil { + return err + } + p.functions = functions + + strings := &rawTable[string]{ + reader: p.reader, + header: h.V3.Strings, + } + if strings.dec, err = newStringsDecoder(h.V3.Strings); err != nil { + return err + } + p.strings = strings + return nil +} + func (p *partition) Symbols() *Symbols { return &Symbols{ Stacktraces: p, - Locations: p.locations.s, - Mappings: p.mappings.s, - Functions: p.functions.s, - Strings: p.strings.s, + Locations: p.locations.slice(), + Mappings: p.mappings.slice(), + Functions: p.functions.slice(), + Strings: p.strings.slice(), } } func (p *partition) WriteStats(s *PartitionStats) { var nodes uint32 - for _, c := range p.stacktraceChunks { + for _, c := range p.stacktraces { s.StacktracesTotal += int(c.header.Stacktraces) nodes += c.header.StacktraceNodes } s.MaxStacktraceID = int(nodes) - s.LocationsTotal = len(p.locations.s) - s.MappingsTotal = len(p.mappings.s) - s.FunctionsTotal = len(p.functions.s) - s.StringsTotal = len(p.strings.s) + s.LocationsTotal = len(p.locations.slice()) + s.MappingsTotal = len(p.mappings.slice()) + s.FunctionsTotal = len(p.functions.slice()) + s.StringsTotal = len(p.strings.slice()) } var ErrInvalidStacktraceRange = fmt.Errorf("invalid range: stack traces can't be resolved") func (p *partition) LookupLocations(dst []uint64, stacktraceID uint32) []uint64 { dst = dst[:0] - if len(p.stacktraceChunks) == 0 { + if len(p.stacktraces) == 0 { return dst } - nodesPerChunk := p.stacktraceChunks[0].header.StacktraceMaxNodes + nodesPerChunk := p.stacktraces[0].header.StacktraceMaxNodes chunkID := stacktraceID / nodesPerChunk localSID := stacktraceID % nodesPerChunk - if localSID == 0 || int(chunkID) > len(p.stacktraceChunks) { + if localSID == 0 || int(chunkID) > len(p.stacktraces) { return dst } - return p.stacktraceChunks[chunkID].t.resolveUint64(dst, localSID) + return p.stacktraces[chunkID].t.resolveUint64(dst, localSID) } func (p *partition) ResolveStacktraceLocations(ctx context.Context, dst StacktraceInserter, s []uint32) (err error) { if len(s) == 0 { return nil } - if len(p.stacktraceChunks) == 0 { + if len(p.stacktraces) == 0 { return ErrInvalidStacktraceRange } // First, we determine the chunks needed for the range. // All chunks in a block must have the same StacktraceMaxNodes. - sr := SplitStacktraces(s, p.stacktraceChunks[0].header.StacktraceMaxNodes) + sr := SplitStacktraces(s, p.stacktraces[0].header.StacktraceMaxNodes) for _, c := range sr { if err = p.lookupStacktraces(ctx, dst, c).do(); err != nil { return err @@ -287,24 +475,40 @@ func (p *partition) ResolveStacktraceLocations(ctx context.Context, dst Stacktra return nil } -func (p *partition) setStacktracesChunks(chunks []StacktraceChunkHeader) { - p.stacktraceChunks = make([]*stacktraceChunkReader, len(chunks)) +func (p *partition) SplitStacktraceIDRanges(appender *SampleAppender) iter.Iterator[*StacktraceIDRange] { + if len(p.stacktraces) == 0 { + return iter.NewEmptyIterator[*StacktraceIDRange]() + } + var n int + samples := appender.Samples() + ranges := SplitStacktraces(samples.StacktraceIDs, p.stacktraces[0].header.StacktraceMaxNodes) + for _, sr := range ranges { + c := p.stacktraces[sr.chunk] + sr.ParentPointerTree = c.t + sr.Samples = samples.Range(n, n+len(sr.IDs)) + n += len(sr.IDs) + } + return iter.NewSliceIterator(ranges) +} + +func (p *partition) initStacktraces(chunks []StacktraceBlockHeader) { + p.stacktraces = make([]*stacktraceBlock, len(chunks)) for i, c := range chunks { - p.stacktraceChunks[i] = &stacktraceChunkReader{ + p.stacktraces[i] = &stacktraceBlock{ reader: p.reader, header: c, } } } -func (p *partition) stacktraceChunkReader(i uint32) *stacktraceChunkReader { - if int(i) < len(p.stacktraceChunks) { - return p.stacktraceChunks[i] +func (p *partition) stacktraceChunkReader(i uint32) *stacktraceBlock { + if int(i) < len(p.stacktraces) { + return p.stacktraces[i] } return nil } -func (p *partition) lookupStacktraces(ctx context.Context, dst StacktraceInserter, c StacktracesRange) *stacktracesLookup { +func (p *partition) lookupStacktraces(ctx context.Context, dst StacktraceInserter, c *StacktraceIDRange) *stacktracesLookup { return &stacktracesLookup{ ctx: ctx, dst: dst, @@ -317,7 +521,7 @@ func (p *partition) lookupStacktraces(ctx context.Context, dst StacktraceInserte type stacktracesLookup struct { ctx context.Context dst StacktraceInserter - c StacktracesRange + c *StacktraceIDRange r *partition } @@ -328,8 +532,8 @@ func (r *stacktracesLookup) do() error { } s := stacktraceLocations.get() // Restore the original stacktrace ID. - off := r.c.offset() - for _, sid := range r.c.ids { + off := r.c.Offset() + for _, sid := range r.c.IDs { s = cr.t.resolve(s, sid) r.dst.InsertStacktrace(off+sid, s) } @@ -337,40 +541,50 @@ func (r *stacktracesLookup) do() error { return nil } -type stacktraceChunkReader struct { +type stacktraceBlock struct { reader *Reader - header StacktraceChunkHeader + header StacktraceBlockHeader r refctr.Counter t *parentPointerTree } -func (c *stacktraceChunkReader) fetch(ctx context.Context) error { - span, ctx := opentracing.StartSpanFromContext(ctx, "stacktraceChunkReader.fetch") - span.LogFields( - otlog.Int64("size", c.header.Size), - otlog.Uint32("nodes", c.header.StacktraceNodes), - otlog.Uint32("stacks", c.header.Stacktraces), - ) +func (c *stacktraceBlock) fetch(ctx context.Context) error { + span, ctx := tracing.StartSpanFromContext(ctx, "stacktraceBlock.fetch") + span.SetTag("size", c.header.Size) + span.SetTag("nodes", c.header.StacktraceNodes) + span.SetTag("stacks", c.header.Stacktraces) defer span.Finish() return c.r.Inc(func() error { - f, err := c.reader.file(StacktracesFileName) + path, err := c.stacktracesFile() if err != nil { return err } - rc, err := c.reader.bucket.GetRange(ctx, f.RelPath, c.header.Offset, c.header.Size) + rc, err := c.reader.bucket.GetRange(ctx, path, c.header.Offset, c.header.Size) if err != nil { return err } + r := getFetchBufReader(rc) defer func() { + putFetchBufReader(r) err = multierror.New(err, rc.Close()).Err() }() - // Consider pooling the buffer. - return c.readFrom(bufio.NewReaderSize(rc, c.reader.chunkFetchBufferSize)) + return c.readFrom(r) }) } -func (c *stacktraceChunkReader) readFrom(r io.Reader) error { +func (c *stacktraceBlock) stacktracesFile() (string, error) { + f := c.reader.file + if c.reader.index.Header.Version < 3 { + var err error + if f, err = c.reader.lookupFile(StacktracesFileName); err != nil { + return "", err + } + } + return f.RelPath, nil +} + +func (c *stacktraceBlock) readFrom(r *bufio.Reader) error { // NOTE(kolesnikovae): Pool of node chunks could reduce // the alloc size, but it may affect memory locality. // Although, properly aligned chunks of, say, 1-4K nodes @@ -393,109 +607,82 @@ func (c *stacktraceChunkReader) readFrom(r io.Reader) error { return nil } -func (c *stacktraceChunkReader) release() { +func (c *stacktraceBlock) release() { c.r.Dec(func() { c.t = nil }) } -type parquetTableRange[M schemav1.Models, P schemav1.Persister[M]] struct { - headers []RowRangeReference - bucket objstore.BucketReader - persister P - - file *parquetobj.File - - r refctr.Counter - s []M +type rawTable[T any] struct { + reader *Reader + header SymbolsBlockHeader + dec *symbolsDecoder[T] + r refctr.Counter + s []T } -// parquet.CopyRows uses hardcoded buffer size: -// defaultRowBufferSize = 42 -const inMemoryReaderRowsBufSize = 1 << 10 - -func (t *parquetTableRange[M, P]) fetch(ctx context.Context) (err error) { - span, _ := opentracing.StartSpanFromContext(ctx, "parquetTableRange.fetch", opentracing.Tags{ - "table_name": t.persister.Name(), - "row_groups": len(t.headers), - }) +func (t *rawTable[T]) fetch(ctx context.Context) error { + span, ctx := tracing.StartSpanFromContext(ctx, "symbolsTable.fetch") + span.SetTag("size", t.header.Size) + span.SetTag("length", t.header.Length) defer span.Finish() return t.r.Inc(func() error { - var s uint32 - for _, h := range t.headers { - s += h.Rows - } - buf := make([]parquet.Row, inMemoryReaderRowsBufSize) - t.s = make([]M, s) - var offset int - // TODO(kolesnikovae): Row groups could be fetched in parallel. - rgs := t.file.RowGroups() - for _, h := range t.headers { - span.LogFields( - otlog.Uint32("row_group", h.RowGroup), - otlog.Uint32("index_row", h.Index), - otlog.Uint32("rows", h.Rows), - ) - rg := rgs[h.RowGroup] - rows := rg.Rows() - if err := rows.SeekToRow(int64(h.Index)); err != nil { - return err - } - dst := t.s[offset : offset+int(h.Rows)] - if err := t.readRows(dst, buf, rows); err != nil { - return fmt.Errorf("reading row group from parquet file %q: %w", t.file.Path(), err) - } - offset += int(h.Rows) + rc, err := t.reader.bucket.GetRange(ctx, + t.reader.file.RelPath, + int64(t.header.Offset), + int64(t.header.Size)) + if err != nil { + return err } - return nil + r := getFetchBufReader(rc) + defer func() { + putFetchBufReader(r) + err = multierror.New(err, rc.Close()).Err() + }() + return t.readFrom(r) }) } -func (t *parquetTableRange[M, P]) readRows(dst []M, buf []parquet.Row, rows parquet.Rows) (err error) { - defer func() { - err = multierror.New(err, rows.Close()).Err() - }() - for i := 0; i < len(dst); { - n, err := rows.ReadRows(buf) - if n > 0 { - for _, row := range buf[:n] { - if i == len(dst) { - return nil - } - _, v, err := t.persister.Reconstruct(row) - if err != nil { - return err - } - dst[i] = v - i++ - } - } - if err != nil { - if errors.Is(err, io.EOF) { - return nil - } - return err - } +func (t *rawTable[T]) readFrom(r *bufio.Reader) error { + crc := crc32.New(castagnoli) + tee := io.TeeReader(r, crc) + t.s = make([]T, t.header.Length) + if err := t.dec.decode(t.s, tee); err != nil { + return fmt.Errorf("failed to decode symbols: %w", err) + } + if t.header.CRC != crc.Sum32() { + return ErrInvalidCRC } return nil } -func (t *parquetTableRange[M, P]) release() { +func (t *rawTable[T]) slice() []T { return t.s } + +func (t *rawTable[T]) release() { t.r.Dec(func() { t.s = nil }) } +// This is a stub for versions without tables in the block (format v1). +type emptyTable[T any] struct{} + +func (emptyTable[T]) fetch(context.Context) error { return nil } + +func (emptyTable[T]) release() {} + +func (emptyTable[T]) slice() []T { return nil } + // fetchTx facilitates fetching multiple objects in a transactional manner: // if one of the objects has failed, all the remaining ones are released. -type fetchTx []fetch +type fetchTx []fetchable -type fetch interface { +type fetchable interface { fetch(context.Context) error release() } -func (tx *fetchTx) append(x fetch) { *tx = append(*tx, x) } +func (tx *fetchTx) append(x fetchable) { *tx = append(*tx, x) } func (tx *fetchTx) fetch(ctx context.Context) (err error) { defer func() { @@ -532,3 +719,22 @@ func (tx *fetchTx) release() { } wg.Wait() } + +const defaultFetchBufferSize = 64 << 10 + +var fetchBufReaderPool = sync.Pool{ + New: func() any { + return bufio.NewReaderSize(nil, defaultFetchBufferSize) + }, +} + +func getFetchBufReader(r io.Reader) *bufio.Reader { + b := fetchBufReaderPool.Get().(*bufio.Reader) + b.Reset(r) + return b +} + +func putFetchBufReader(b *bufio.Reader) { + b.Reset(nil) + fetchBufReaderPool.Put(b) +} diff --git a/pkg/phlaredb/symdb/block_reader_parquet.go b/pkg/phlaredb/symdb/block_reader_parquet.go new file mode 100644 index 0000000000..9b2920b84a --- /dev/null +++ b/pkg/phlaredb/symdb/block_reader_parquet.go @@ -0,0 +1,167 @@ +//nolint:unused +package symdb + +import ( + "context" + "errors" + "fmt" + "io" + + "github.com/grafana/dskit/multierror" + "github.com/grafana/dskit/tracing" + "github.com/parquet-go/parquet-go" + "go.opentelemetry.io/otel/attribute" + oteltrace "go.opentelemetry.io/otel/trace" + "golang.org/x/sync/errgroup" + + "github.com/grafana/pyroscope/v2/pkg/objstore" + parquetobj "github.com/grafana/pyroscope/v2/pkg/objstore/parquet" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/util/refctr" +) + +// Used in v2. Left for compatibility. + +type parquetTable[M schemav1.Models, P schemav1.Persister[M]] struct { + headers []RowRangeReference + bucket objstore.BucketReader + persister P + + file *parquetobj.File + + r refctr.Counter + s []M +} + +const ( + // parquet.CopyRows uses hardcoded buffer size: + // defaultRowBufferSize = 42 + inMemoryReaderRowsBufSize = 1 << 10 + parquetReadBufferSize = 256 << 10 // 256KB +) + +func (t *parquetTable[M, P]) fetch(ctx context.Context) (err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "parquetTable.fetch") + span.SetTag("table_name", t.persister.Name()) + span.SetTag("row_groups", len(t.headers)) + defer span.Finish() + return t.r.Inc(func() error { + var s uint32 + for _, h := range t.headers { + s += h.Rows + } + buf := make([]parquet.Row, inMemoryReaderRowsBufSize) + t.s = make([]M, s) + var offset int + // TODO(kolesnikovae): Row groups could be fetched in parallel. + rgs := t.file.RowGroups() + otelSpan := oteltrace.SpanFromContext(ctx) + for _, h := range t.headers { + otelSpan.AddEvent("fetch row group", oteltrace.WithAttributes( + attribute.Int("row_group", int(h.RowGroup)), + attribute.Int("index_row", int(h.Index)), + attribute.Int("rows", int(h.Rows)), + )) + rg := rgs[h.RowGroup] + rows := rg.Rows() + if err := rows.SeekToRow(int64(h.Index)); err != nil { + return err + } + dst := t.s[offset : offset+int(h.Rows)] + if err := t.readRows(dst, buf, rows); err != nil { + return fmt.Errorf("reading row group from parquet file %q: %w", t.file.Path(), err) + } + offset += int(h.Rows) + } + return nil + }) +} + +func (t *parquetTable[M, P]) readRows(dst []M, buf []parquet.Row, rows parquet.Rows) (err error) { + defer func() { + err = multierror.New(err, rows.Close()).Err() + }() + for i := 0; i < len(dst); { + n, err := rows.ReadRows(buf) + if n > 0 { + for _, row := range buf[:n] { + if i == len(dst) { + return nil + } + v, err := t.persister.Reconstruct(row) + if err != nil { + return err + } + dst[i] = v + i++ + } + } + if err != nil { + if errors.Is(err, io.EOF) { + return nil + } + return err + } + } + return nil +} + +func (t *parquetTable[M, P]) slice() []M { return t.s } + +func (t *parquetTable[M, P]) release() { + t.r.Dec(func() { + t.s = nil + }) +} + +type parquetFiles struct { + locations parquetobj.File + mappings parquetobj.File + functions parquetobj.File + strings parquetobj.File +} + +func (f *parquetFiles) Close() error { + return multierror.New( + f.locations.Close(), + f.mappings.Close(), + f.functions.Close(), + f.strings.Close()). + Err() +} + +func openParquetFiles(ctx context.Context, r *Reader) error { + options := []parquet.FileOption{ + parquet.SkipBloomFilters(true), + parquet.FileReadMode(parquet.ReadModeAsync), + parquet.ReadBufferSize(parquetReadBufferSize), + } + files := new(parquetFiles) + m := map[string]*parquetobj.File{ + new(schemav1.LocationPersister).Name() + block.ParquetSuffix: &files.locations, + new(schemav1.MappingPersister).Name() + block.ParquetSuffix: &files.mappings, + new(schemav1.FunctionPersister).Name() + block.ParquetSuffix: &files.functions, + new(schemav1.StringPersister).Name() + block.ParquetSuffix: &files.strings, + } + g, ctx := errgroup.WithContext(ctx) + for n, fp := range m { + n := n + fp := fp + g.Go(func() error { + fm, err := r.lookupFile(n) + if err != nil { + return err + } + if err = fp.Open(ctx, r.bucket, fm, options...); err != nil { + return fmt.Errorf("opening file %q: %w", n, err) + } + return nil + }) + } + if err := g.Wait(); err != nil { + return err + } + r.parquetFiles = files + return nil +} diff --git a/pkg/phlaredb/symdb/block_reader_test.go b/pkg/phlaredb/symdb/block_reader_test.go index f4e5b2cdaf..87a8a66aef 100644 --- a/pkg/phlaredb/symdb/block_reader_test.go +++ b/pkg/phlaredb/symdb/block_reader_test.go @@ -1,26 +1,131 @@ package symdb import ( + "bytes" "context" + "os" "testing" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + pystore "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) -var testBlockMeta = &block.Meta{ - Files: []block.File{ - {RelPath: IndexFileName}, - {RelPath: StacktracesFileName}, - {RelPath: "locations.parquet"}, - {RelPath: "mappings.parquet"}, - {RelPath: "functions.parquet"}, - {RelPath: "strings.parquet"}, - }, +var ( + testBlockMeta = &block.Meta{ + Files: []block.File{ + {RelPath: DefaultFileName}, + }, + } + + testBlockMetaV1 = &block.Meta{ + Files: []block.File{ + {RelPath: IndexFileName}, + {RelPath: StacktracesFileName}, + }, + } + + testBlockMetaV2 = &block.Meta{ + Files: []block.File{ + {RelPath: IndexFileName}, + {RelPath: StacktracesFileName}, + {RelPath: "locations.parquet"}, + {RelPath: "mappings.parquet"}, + {RelPath: "functions.parquet"}, + {RelPath: "strings.parquet"}, + }, + } +) + +func Test_write_block_fixture(t *testing.T) { + t.Skip() + b := newBlockSuite(t, [][]string{ + {"testdata/profile.pb.gz"}, + {"testdata/profile.pb.gz"}, + }) + const fixtureDir = "testdata/symbols/v3" + require.NoError(t, os.RemoveAll(fixtureDir)) + require.NoError(t, os.Rename(b.config.Dir, fixtureDir)) +} + +func Test_Reader_Open_v3(t *testing.T) { + // The block contains two partitions (0 and 1), each partition + // stores symbols of the testdata/profile.pb.gz profile + b, err := filesystem.NewBucket("testdata/symbols/v3") + require.NoError(t, err) + x, err := Open(context.Background(), b, testBlockMeta) + require.NoError(t, err) + + r := NewResolver(context.Background(), x) + defer r.Release() + r.AddSamples(0, schemav1.Samples{ + StacktraceIDs: []uint32{1, 2, 3, 4, 5}, + Values: []uint64{1, 1, 1, 1, 1}, + }) + r.AddSamples(1, schemav1.Samples{ + StacktraceIDs: []uint32{1, 2, 3, 4, 5}, + Values: []uint64{1, 1, 1, 1, 1}, + }) + + resolved, err := r.Tree() + require.NoError(t, err) + expected := `. +├── github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots: self 2 total 8 +│ └── github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot: self 2 total 6 +│ └── github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof: self 0 total 4 +│ └── io/ioutil.ReadAll: self 2 total 4 +│ └── io.ReadAll: self 2 total 2 +└── net/http.(*conn).serve: self 2 total 2 +` + + require.Equal(t, expected, resolved.String()) +} + +func Test_Reader_Open_v3_fuzz(t *testing.T) { + // Make sure the test is valid. + corpus, err := os.ReadFile("testdata/symbols/v3/symbols.symdb") + require.NoError(t, err) + ctx := context.Background() + + bucket := pystore.NewBucket(objstore.NewInMemBucket()) + require.NoError(t, bucket.Upload(ctx, DefaultFileName, bytes.NewReader(corpus))) + b, err := Open(ctx, bucket, testBlockMeta) + require.NoError(t, err) + + r := NewResolver(context.Background(), b) + defer r.Release() + r.AddSamples(0, schemav1.Samples{}) + r.AddSamples(1, schemav1.Samples{}) + _, err = r.Pprof() + require.NoError(t, err) +} + +func Fuzz_Reader_Open_v3(f *testing.F) { + corpus, err := os.ReadFile("testdata/symbols/v3/symbols.symdb") + require.NoError(f, err) + ctx := context.Background() + + f.Add(corpus) + f.Fuzz(func(t *testing.T, data []byte) { + bucket := pystore.NewBucket(objstore.NewInMemBucket()) + require.NoError(t, bucket.Upload(ctx, DefaultFileName, bytes.NewReader(data))) + + b, err := Open(context.Background(), bucket, testBlockMeta) + if err != nil { + return + } + + r := NewResolver(context.Background(), b) + defer r.Release() + r.AddSamples(0, schemav1.Samples{}) + r.AddSamples(1, schemav1.Samples{}) + _, _ = r.Pprof() + }) } func Test_Reader_Open_v2(t *testing.T) { @@ -28,7 +133,7 @@ func Test_Reader_Open_v2(t *testing.T) { // stores symbols of the testdata/profile.pb.gz profile b, err := filesystem.NewBucket("testdata/symbols/v2") require.NoError(t, err) - x, err := Open(context.Background(), b, testBlockMeta) + x, err := Open(context.Background(), b, testBlockMetaV2) require.NoError(t, err) r := NewResolver(context.Background(), x) @@ -58,7 +163,7 @@ func Test_Reader_Open_v2(t *testing.T) { func Test_Reader_Open_v1(t *testing.T) { b, err := filesystem.NewBucket("testdata/symbols/v1") require.NoError(t, err) - x, err := Open(context.Background(), b, testBlockMeta) + x, err := Open(context.Background(), b, testBlockMetaV1) require.NoError(t, err) r, err := x.partition(context.Background(), 1) require.NoError(t, err) @@ -74,8 +179,45 @@ func Test_Reader_Open_v1(t *testing.T) { require.NoError(t, err) } +func Fuzz_ReadIndexFile_v12(f *testing.F) { + files := []string{ + "testdata/symbols/v2/index.symdb", + "testdata/symbols/v1/index.symdb", + } + for _, path := range files { + data, err := os.ReadFile(path) + require.NoError(f, err) + f.Add(data) + } + f.Fuzz(func(_ *testing.T, b []byte) { + _, _ = OpenIndex(b) + }) +} + type mockStacktraceInserter struct{ mock.Mock } func (m *mockStacktraceInserter) InsertStacktrace(stacktraceID uint32, locations []int32) { m.Called(stacktraceID, locations) } + +func Benchmark_Reader_ResolvePprof(b *testing.B) { + ctx := context.Background() + s := memSuite{t: b, files: [][]string{{"testdata/big-profile.pb.gz"}}} + s.config = DefaultConfig().WithDirectory(b.TempDir()) + s.init() + bs := blockSuite{memSuite: &s} + bs.flush() + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + r := NewResolver(ctx, bs.reader) + r.AddSamples(0, schemav1.Samples{}) + _, err := r.Pprof() + require.NoError(b, err) + r.Release() + } + + b.ReportMetric(float64(bs.getRangeCount.Load())/float64(b.N), "get_range_calls/op") + b.ReportMetric(float64(bs.getRangeSize.Load())/float64(b.N), "get_range_bytes/op") +} diff --git a/pkg/phlaredb/symdb/block_writer.go b/pkg/phlaredb/symdb/block_writer.go index 101d5e3e6b..270964878a 100644 --- a/pkg/phlaredb/symdb/block_writer.go +++ b/pkg/phlaredb/symdb/block_writer.go @@ -2,193 +2,16 @@ package symdb import ( "bufio" - "context" - "fmt" - "hash/crc32" "io" "os" "path/filepath" - "github.com/grafana/dskit/multierror" - "github.com/parquet-go/parquet-go" - "golang.org/x/sync/errgroup" - - "github.com/grafana/pyroscope/pkg/phlaredb/block" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/util/build" - "github.com/grafana/pyroscope/pkg/util/math" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) -type writer struct { - config *Config - - index IndexFile - indexWriter *fileWriter - stacktraces *fileWriter - files []block.File - - // Parquet tables. - mappings parquetWriter[*schemav1.InMemoryMapping, *schemav1.MappingPersister] - functions parquetWriter[*schemav1.InMemoryFunction, *schemav1.FunctionPersister] - locations parquetWriter[*schemav1.InMemoryLocation, *schemav1.LocationPersister] - strings parquetWriter[string, *schemav1.StringPersister] -} - -func newWriter(c *Config) *writer { - return &writer{ - config: c, - index: IndexFile{ - Header: Header{ - Magic: symdbMagic, - Version: FormatV2, - }, - }, - } -} - -func (w *writer) writePartitions(partitions []*PartitionWriter) error { - g, _ := errgroup.WithContext(context.Background()) - g.Go(func() (err error) { - if w.stacktraces, err = w.newFile(StacktracesFileName); err != nil { - return err - } - for _, partition := range partitions { - if err = w.writeStacktraces(partition); err != nil { - return err - } - } - return w.stacktraces.Close() - }) - - g.Go(func() (err error) { - if err = w.strings.init(w.config.Dir, w.config.Parquet); err != nil { - return err - } - for _, partition := range partitions { - if partition.header.Strings, err = w.strings.readFrom(partition.strings.slice); err != nil { - return err - } - } - return w.strings.Close() - }) - - g.Go(func() (err error) { - if err = w.functions.init(w.config.Dir, w.config.Parquet); err != nil { - return err - } - for _, partition := range partitions { - if partition.header.Functions, err = w.functions.readFrom(partition.functions.slice); err != nil { - return err - } - } - return w.functions.Close() - }) - - g.Go(func() (err error) { - if err = w.mappings.init(w.config.Dir, w.config.Parquet); err != nil { - return err - } - for _, partition := range partitions { - if partition.header.Mappings, err = w.mappings.readFrom(partition.mappings.slice); err != nil { - return err - } - } - return w.mappings.Close() - }) - - g.Go(func() (err error) { - if err = w.locations.init(w.config.Dir, w.config.Parquet); err != nil { - return err - } - for _, partition := range partitions { - if partition.header.Locations, err = w.locations.readFrom(partition.locations.slice); err != nil { - return err - } - } - return w.locations.Close() - }) - - if err := g.Wait(); err != nil { - return err - } - - for _, partition := range partitions { - w.index.PartitionHeaders = append(w.index.PartitionHeaders, &partition.header) - } - - return nil -} - -func (w *writer) Flush() (err error) { - if err = w.writeIndexFile(); err != nil { - return err - } - w.files = []block.File{ - w.indexWriter.meta(), - w.stacktraces.meta(), - w.locations.meta(), - w.mappings.meta(), - w.functions.meta(), - w.strings.meta(), - } - return nil -} - -func (w *writer) writeStacktraces(partition *PartitionWriter) (err error) { - for ci, c := range partition.stacktraces.chunks { - stacks := c.stacks - if stacks == 0 { - stacks = uint32(len(partition.stacktraces.hashToIdx)) - } - h := StacktraceChunkHeader{ - Offset: w.stacktraces.w.offset, - Size: 0, // Set later. - Partition: partition.header.Partition, - ChunkIndex: uint16(ci), - ChunkEncoding: ChunkEncodingGroupVarint, - Stacktraces: stacks, - StacktraceNodes: c.tree.len(), - StacktraceMaxDepth: 0, // TODO - StacktraceMaxNodes: c.partition.maxNodesPerChunk, - CRC: 0, // Set later. - } - crc := crc32.New(castagnoli) - if h.Size, err = c.WriteTo(io.MultiWriter(crc, w.stacktraces)); err != nil { - return fmt.Errorf("writing stacktrace chunk data: %w", err) - } - h.CRC = crc.Sum32() - partition.header.StacktraceChunks = append(partition.header.StacktraceChunks, h) - } - return nil -} - -func (w *writer) createDir() error { - if err := os.MkdirAll(w.config.Dir, 0o755); err != nil { - return fmt.Errorf("failed to create directory %q: %w", w.config.Dir, err) - } - return nil -} - -func (w *writer) writeIndexFile() (err error) { - // Write the index file only after all the files were flushed. - if w.indexWriter, err = w.newFile(IndexFileName); err != nil { - return err - } - defer func() { - err = multierror.New(err, w.indexWriter.Close()).Err() - }() - if _, err = w.index.WriteTo(w.indexWriter); err != nil { - return fmt.Errorf("failed to write index file: %w", err) - } - return err -} - -func (w *writer) newFile(path string) (f *fileWriter, err error) { - path = filepath.Join(w.config.Dir, path) - if f, err = newFileWriter(path); err != nil { - return nil, fmt.Errorf("failed to create %q: %w", path, err) - } - return f, err +type blockWriter interface { + writePartitions(partitions []*PartitionWriter) error + meta() []block.File } type fileWriter struct { @@ -206,7 +29,7 @@ func newFileWriter(path string) (*fileWriter, error) { // There is no particular reason to use // a buffer larger than the default 4K. b := bufio.NewWriterSize(f, 4096) - w := withWriterOffset(b, 0) + w := withWriterOffset(b) fw := fileWriter{ path: path, buf: b, @@ -220,15 +43,8 @@ func (f *fileWriter) Write(p []byte) (n int, err error) { return f.w.Write(p) } -func (f *fileWriter) sync() (err error) { - if err = f.buf.Flush(); err != nil { - return err - } - return f.f.Sync() -} - func (f *fileWriter) Close() (err error) { - if err = f.sync(); err != nil { + if err = f.buf.Flush(); err != nil { return err } return f.f.Close() @@ -248,8 +64,8 @@ type writerOffset struct { err error } -func withWriterOffset(w io.Writer, base int64) *writerOffset { - return &writerOffset{Writer: w, offset: base} +func withWriterOffset(w io.Writer) *writerOffset { + return &writerOffset{Writer: w} } func (w *writerOffset) write(p []byte) { @@ -265,122 +81,3 @@ func (w *writerOffset) Write(p []byte) (n int, err error) { w.offset += int64(n) return n, err } - -type parquetWriter[M schemav1.Models, P schemav1.Persister[M]] struct { - persister P - config ParquetConfig - - currentRowGroup uint32 - currentRows uint32 - rowsTotal uint64 - - buffer *parquet.Buffer - rowsBatch []parquet.Row - - writer *parquet.GenericWriter[P] - file *os.File - path string -} - -func (s *parquetWriter[M, P]) init(dir string, c ParquetConfig) (err error) { - s.config = c - s.path = filepath.Join(dir, s.persister.Name()+block.ParquetSuffix) - s.file, err = os.OpenFile(s.path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o644) - if err != nil { - return err - } - s.rowsBatch = make([]parquet.Row, 0, 128) - s.buffer = parquet.NewBuffer(s.persister.Schema(), parquet.ColumnBufferCapacity(s.config.MaxBufferRowCount)) - s.writer = parquet.NewGenericWriter[P](s.file, s.persister.Schema(), - parquet.CreatedBy("github.com/grafana/pyroscope/", build.Version, build.Revision), - parquet.PageBufferSize(3*1024*1024), - ) - return nil -} - -func (s *parquetWriter[M, P]) readFrom(values []M) (ranges []RowRangeReference, err error) { - for len(values) > 0 { - var r RowRangeReference - if r, err = s.writeRows(values); err != nil { - return nil, err - } - ranges = append(ranges, r) - values = values[r.Rows:] - } - return ranges, nil -} - -func (s *parquetWriter[M, P]) writeRows(values []M) (r RowRangeReference, err error) { - r.RowGroup = s.currentRowGroup - r.Index = s.currentRows - if len(values) == 0 { - return r, nil - } - var n int - for len(values) > 0 && int(s.currentRows) < s.config.MaxBufferRowCount { - s.fillBatch(values) - if n, err = s.buffer.WriteRows(s.rowsBatch); err != nil { - return r, err - } - s.currentRows += uint32(n) - r.Rows += uint32(n) - values = values[n:] - } - if int(s.currentRows)+cap(s.rowsBatch) >= s.config.MaxBufferRowCount { - if err = s.flushBuffer(); err != nil { - return r, err - } - } - return r, nil -} - -func (s *parquetWriter[M, P]) fillBatch(values []M) int { - m := math.Min(len(values), cap(s.rowsBatch)) - s.rowsBatch = s.rowsBatch[:m] - for i := 0; i < m; i++ { - row := s.rowsBatch[i][:0] - s.rowsBatch[i] = s.persister.Deconstruct(row, 0, values[i]) - } - return m -} - -func (s *parquetWriter[M, P]) flushBuffer() error { - if _, err := s.writer.WriteRowGroup(s.buffer); err != nil { - return err - } - s.rowsTotal += uint64(s.buffer.NumRows()) - s.currentRowGroup++ - s.currentRows = 0 - s.buffer.Reset() - return nil -} - -func (s *parquetWriter[M, P]) meta() block.File { - f := block.File{ - // Note that the path is relative to the symdb root dir. - RelPath: filepath.Base(s.path), - Parquet: &block.ParquetFile{ - NumRows: s.rowsTotal, - }, - } - if f.Parquet.NumRows > 0 { - f.Parquet.NumRowGroups = uint64(s.currentRowGroup + 1) - } - if stat, err := os.Stat(s.path); err == nil { - f.SizeBytes = uint64(stat.Size()) - } - return f -} - -func (s *parquetWriter[M, P]) Close() error { - if err := s.flushBuffer(); err != nil { - return fmt.Errorf("flushing parquet buffer: %w", err) - } - if err := s.writer.Close(); err != nil { - return fmt.Errorf("closing parquet writer: %w", err) - } - if err := s.file.Close(); err != nil { - return fmt.Errorf("closing parquet file: %w", err) - } - return nil -} diff --git a/pkg/phlaredb/symdb/block_writer_v2.go b/pkg/phlaredb/symdb/block_writer_v2.go new file mode 100644 index 0000000000..24fdfb0fd2 --- /dev/null +++ b/pkg/phlaredb/symdb/block_writer_v2.go @@ -0,0 +1,306 @@ +package symdb + +import ( + "context" + "fmt" + "hash/crc32" + "io" + "math" + "os" + "path/filepath" + + "github.com/grafana/dskit/multierror" + "github.com/parquet-go/parquet-go" + "golang.org/x/sync/errgroup" + + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/util/build" +) + +type writerV2 struct { + config *Config + + index IndexFile + indexWriter *fileWriter + stacktraces *fileWriter + files []block.File + + // Parquet tables. + mappings parquetWriter[schemav1.InMemoryMapping, schemav1.MappingPersister] + functions parquetWriter[schemav1.InMemoryFunction, schemav1.FunctionPersister] + locations parquetWriter[schemav1.InMemoryLocation, schemav1.LocationPersister] + strings parquetWriter[string, schemav1.StringPersister] +} + +func newWriterV2(c *Config) *writerV2 { + return &writerV2{ + config: c, + index: IndexFile{ + Header: IndexHeader{ + Magic: symdbMagic, + Version: FormatV2, + }, + }, + } +} + +func (w *writerV2) writePartitions(partitions []*PartitionWriter) error { + if err := w.createDir(); err != nil { + return err + } + + g, _ := errgroup.WithContext(context.Background()) + g.Go(func() (err error) { + if w.stacktraces, err = w.newFile(StacktracesFileName); err != nil { + return err + } + for _, partition := range partitions { + if err = w.writeStacktraces(partition); err != nil { + return err + } + } + return w.stacktraces.Close() + }) + + g.Go(func() (err error) { + if err = w.strings.init(w.config.Dir, w.config.Parquet); err != nil { + return err + } + for _, partition := range partitions { + if partition.header.V2.Strings, err = w.strings.readFrom(partition.strings.slice); err != nil { + return err + } + } + return w.strings.Close() + }) + + g.Go(func() (err error) { + if err = w.functions.init(w.config.Dir, w.config.Parquet); err != nil { + return err + } + for _, partition := range partitions { + if partition.header.V2.Functions, err = w.functions.readFrom(partition.functions.slice); err != nil { + return err + } + } + return w.functions.Close() + }) + + g.Go(func() (err error) { + if err = w.mappings.init(w.config.Dir, w.config.Parquet); err != nil { + return err + } + for _, partition := range partitions { + if partition.header.V2.Mappings, err = w.mappings.readFrom(partition.mappings.slice); err != nil { + return err + } + } + return w.mappings.Close() + }) + + g.Go(func() (err error) { + if err = w.locations.init(w.config.Dir, w.config.Parquet); err != nil { + return err + } + for _, partition := range partitions { + if partition.header.V2.Locations, err = w.locations.readFrom(partition.locations.slice); err != nil { + return err + } + } + return w.locations.Close() + }) + + if err := g.Wait(); err != nil { + return err + } + + for _, partition := range partitions { + w.index.PartitionHeaders = append(w.index.PartitionHeaders, &partition.header) + } + + return w.Flush() +} + +func (w *writerV2) Flush() (err error) { + if err = w.writeIndexFile(); err != nil { + return err + } + w.files = []block.File{ + w.indexWriter.meta(), + w.stacktraces.meta(), + w.locations.meta(), + w.mappings.meta(), + w.functions.meta(), + w.strings.meta(), + } + return nil +} + +func (w *writerV2) writeStacktraces(partition *PartitionWriter) (err error) { + h := StacktraceBlockHeader{ + Offset: w.stacktraces.w.offset, + Partition: partition.header.Partition, + Encoding: StacktraceEncodingGroupVarint, + Stacktraces: uint32(len(partition.stacktraces.hashToIdx)), + StacktraceNodes: partition.stacktraces.tree.len(), + StacktraceMaxNodes: math.MaxUint32, + } + crc := crc32.New(castagnoli) + if h.Size, err = partition.stacktraces.WriteTo(io.MultiWriter(crc, w.stacktraces)); err != nil { + return fmt.Errorf("writing stacktrace chunk data: %w", err) + } + h.CRC = crc.Sum32() + partition.header.Stacktraces = append(partition.header.Stacktraces, h) + return nil +} + +func (w *writerV2) createDir() error { + if err := os.MkdirAll(w.config.Dir, 0o755); err != nil { + return fmt.Errorf("failed to create directory %q: %w", w.config.Dir, err) + } + return nil +} + +func (w *writerV2) writeIndexFile() (err error) { + // Write the index file only after all the files were flushed. + if w.indexWriter, err = w.newFile(IndexFileName); err != nil { + return err + } + defer func() { + err = multierror.New(err, w.indexWriter.Close()).Err() + }() + if _, err = w.index.WriteTo(w.indexWriter); err != nil { + return fmt.Errorf("failed to write index file: %w", err) + } + return err +} + +func (w *writerV2) newFile(path string) (f *fileWriter, err error) { + path = filepath.Join(w.config.Dir, path) + if f, err = newFileWriter(path); err != nil { + return nil, fmt.Errorf("failed to create %q: %w", path, err) + } + return f, err +} + +func (w *writerV2) meta() []block.File { return w.files } + +type parquetWriter[M schemav1.Models, P schemav1.Persister[M]] struct { + persister P + config ParquetConfig + + currentRowGroup uint32 + currentRows uint32 + rowsTotal uint64 + + buffer *parquet.Buffer + rowsBatch []parquet.Row + + writer *parquet.GenericWriter[P] + file *os.File + path string +} + +func (s *parquetWriter[M, P]) init(dir string, c ParquetConfig) (err error) { + s.config = c + s.path = filepath.Join(dir, s.persister.Name()+block.ParquetSuffix) + s.file, err = os.OpenFile(s.path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o644) + if err != nil { + return err + } + s.rowsBatch = make([]parquet.Row, 0, 128) + s.buffer = parquet.NewBuffer(s.persister.Schema()) + s.writer = parquet.NewGenericWriter[P](s.file, s.persister.Schema(), + parquet.CreatedBy("github.com/grafana/pyroscope/", build.Version, build.Revision), + parquet.PageBufferSize(3*1024*1024), + ) + return nil +} + +func (s *parquetWriter[M, P]) readFrom(values []M) (ranges []RowRangeReference, err error) { + for len(values) > 0 { + var r RowRangeReference + if r, err = s.writeRows(values); err != nil { + return nil, err + } + ranges = append(ranges, r) + values = values[r.Rows:] + } + return ranges, nil +} + +func (s *parquetWriter[M, P]) writeRows(values []M) (r RowRangeReference, err error) { + r.RowGroup = s.currentRowGroup + r.Index = s.currentRows + if len(values) == 0 { + return r, nil + } + var n int + for len(values) > 0 && int(s.currentRows) < s.config.MaxBufferRowCount { + s.fillBatch(values) + if n, err = s.buffer.WriteRows(s.rowsBatch); err != nil { + return r, err + } + s.currentRows += uint32(n) + r.Rows += uint32(n) + values = values[n:] + } + if int(s.currentRows)+cap(s.rowsBatch) >= s.config.MaxBufferRowCount { + if err = s.flushBuffer(); err != nil { + return r, err + } + } + return r, nil +} + +func (s *parquetWriter[M, P]) fillBatch(values []M) int { + m := min(len(values), cap(s.rowsBatch)) + s.rowsBatch = s.rowsBatch[:m] + for i := 0; i < m; i++ { + row := s.rowsBatch[i][:0] + s.rowsBatch[i] = s.persister.Deconstruct(row, values[i]) + } + return m +} + +func (s *parquetWriter[M, P]) flushBuffer() error { + if _, err := s.writer.WriteRowGroup(s.buffer); err != nil { + return err + } + s.rowsTotal += uint64(s.buffer.NumRows()) + s.currentRowGroup++ + s.currentRows = 0 + s.buffer.Reset() + return nil +} + +func (s *parquetWriter[M, P]) meta() block.File { + f := block.File{ + // Note that the path is relative to the symdb root dir. + RelPath: filepath.Base(s.path), + Parquet: &block.ParquetFile{ + NumRows: s.rowsTotal, + }, + } + if f.Parquet.NumRows > 0 { + f.Parquet.NumRowGroups = uint64(s.currentRowGroup + 1) + } + if stat, err := os.Stat(s.path); err == nil { + f.SizeBytes = uint64(stat.Size()) + } + return f +} + +func (s *parquetWriter[M, P]) Close() error { + if err := s.flushBuffer(); err != nil { + return fmt.Errorf("flushing parquet buffer: %w", err) + } + if err := s.writer.Close(); err != nil { + return fmt.Errorf("closing parquet writer: %w", err) + } + if err := s.file.Close(); err != nil { + return fmt.Errorf("closing parquet file: %w", err) + } + return nil +} diff --git a/pkg/phlaredb/symdb/block_writer_v3.go b/pkg/phlaredb/symdb/block_writer_v3.go new file mode 100644 index 0000000000..e3394bc945 --- /dev/null +++ b/pkg/phlaredb/symdb/block_writer_v3.go @@ -0,0 +1,179 @@ +package symdb + +import ( + "fmt" + "hash/crc32" + "io" + "math" + "os" + "path/filepath" + + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +type writerV3 struct { + config *Config + index IndexFile + footer Footer + files []block.File + encodersV3 +} + +type encodersV3 struct { + stringsEncoder *symbolsEncoder[string] + mappingsEncoder *symbolsEncoder[v1.InMemoryMapping] + functionsEncoder *symbolsEncoder[v1.InMemoryFunction] + locationsEncoder *symbolsEncoder[v1.InMemoryLocation] +} + +func newWriterV3(c *Config) *writerV3 { + return &writerV3{ + config: c, + index: newIndexFileV3(), + footer: newFooterV3(), + encodersV3: newEncodersV3(), + } +} + +func newIndexFileV3() IndexFile { + return IndexFile{ + Header: IndexHeader{ + Magic: symdbMagic, + Version: FormatV3, + }, + } +} + +func newFooterV3() Footer { + return Footer{ + Magic: symdbMagic, + Version: FormatV3, + } +} + +func newEncodersV3() encodersV3 { + return encodersV3{ + stringsEncoder: newStringsEncoder(), + mappingsEncoder: newMappingsEncoder(), + functionsEncoder: newFunctionsEncoder(), + locationsEncoder: newLocationsEncoder(), + } +} + +func (w *writerV3) writePartitions(partitions []*PartitionWriter) (err error) { + if dst := w.config.Writer; dst != nil { + defer func() { + _ = w.config.Writer.Close() + }() + return w.writePartitionsWithWriter(withWriterOffset(dst), partitions) + } + if err = os.MkdirAll(w.config.Dir, 0o755); err != nil { + return fmt.Errorf("failed to create directory %q: %w", w.config.Dir, err) + } + var f *fileWriter + f, err = w.newFile(DefaultFileName) + if err != nil { + return err + } + defer func() { + _ = f.Close() + w.files = []block.File{f.meta()} + }() + return w.writePartitionsWithWriter(f.w, partitions) +} + +func (w *writerV3) writePartitionsWithWriter(f *writerOffset, partitions []*PartitionWriter) (err error) { + for _, p := range partitions { + if err = writePartitionV3(f, &w.encodersV3, p); err != nil { + return fmt.Errorf("failed to write partition: %w", err) + } + w.index.PartitionHeaders = append(w.index.PartitionHeaders, &p.header) + } + w.footer.IndexOffset = uint64(f.offset) + if _, err = w.index.WriteTo(f); err != nil { + return fmt.Errorf("failed to write index: %w", err) + } + if _, err = f.Write(w.footer.MarshalBinary()); err != nil { + return fmt.Errorf("failed to write footer: %w", err) + } + return nil +} + +func (w *writerV3) meta() []block.File { return w.files } + +func (w *writerV3) newFile(path string) (f *fileWriter, err error) { + path = filepath.Join(w.config.Dir, path) + if f, err = newFileWriter(path); err != nil { + return nil, fmt.Errorf("failed to create %q: %w", path, err) + } + return f, err +} + +func writePartitionV3(w *writerOffset, e *encodersV3, p *PartitionWriter) (err error) { + if p.header.V3.Strings, err = writeSymbolsBlock(w, p.strings.slice, e.stringsEncoder); err != nil { + return err + } + if p.header.V3.Mappings, err = writeSymbolsBlock(w, p.mappings.slice, e.mappingsEncoder); err != nil { + return err + } + if p.header.V3.Functions, err = writeSymbolsBlock(w, p.functions.slice, e.functionsEncoder); err != nil { + return err + } + if p.header.V3.Locations, err = writeSymbolsBlock(w, p.locations.slice, e.locationsEncoder); err != nil { + return err + } + + h := StacktraceBlockHeader{ + Offset: w.offset, + Partition: p.header.Partition, + Encoding: StacktraceEncodingGroupVarint, + Stacktraces: uint32(len(p.stacktraces.hashToIdx)), + StacktraceNodes: p.stacktraces.tree.len(), + StacktraceMaxNodes: math.MaxUint32, + } + crc := crc32.New(castagnoli) + if h.Size, err = p.stacktraces.WriteTo(io.MultiWriter(crc, w)); err != nil { + return fmt.Errorf("writing stacktrace chunk data: %w", err) + } + h.CRC = crc.Sum32() + p.header.Stacktraces = append(p.header.Stacktraces, h) + + return nil +} + +func writeSymbolsBlock[T any](w *writerOffset, s []T, e *symbolsEncoder[T]) (h SymbolsBlockHeader, err error) { + h.Offset = uint64(w.offset) + crc := crc32.New(castagnoli) + mw := io.MultiWriter(crc, w) + if err = e.encode(mw, s); err != nil { + return h, err + } + h.Size = uint32(w.offset) - uint32(h.Offset) + h.CRC = crc.Sum32() + h.Length = uint32(len(s)) + h.BlockSize = uint32(e.blockSize) + h.BlockHeaderSize = uint16(e.blockEncoder.headerSize()) + h.Format = e.blockEncoder.format() + return h, nil +} + +func WritePartition(p *PartitionWriter, dst io.Writer) error { + index := newIndexFileV3() + footer := newFooterV3() + encoders := newEncodersV3() + w := withWriterOffset(dst) + + if err := writePartitionV3(w, &encoders, p); err != nil { + return fmt.Errorf("failed to write partition: %w", err) + } + index.PartitionHeaders = append(index.PartitionHeaders, &p.header) + footer.IndexOffset = uint64(w.offset) + if _, err := index.WriteTo(w); err != nil { + return fmt.Errorf("failed to write index: %w", err) + } + if _, err := w.Write(footer.MarshalBinary()); err != nil { + return fmt.Errorf("failed to write footer: %w", err) + } + return nil +} diff --git a/pkg/phlaredb/symdb/dedup_slice.go b/pkg/phlaredb/symdb/dedup_slice.go index f2a2a91fc4..e65fdb09eb 100644 --- a/pkg/phlaredb/symdb/dedup_slice.go +++ b/pkg/phlaredb/symdb/dedup_slice.go @@ -4,6 +4,7 @@ package symdb import ( "fmt" "hash/maphash" + stdslices "slices" "sort" "sync" "unsafe" @@ -12,9 +13,9 @@ import ( "go.uber.org/atomic" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/slices" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/slices" ) // Refactored as is from the phlaredb package. @@ -33,12 +34,13 @@ func (p *PartitionWriter) WriteProfileSymbols(profile *profilev1.Profile) []sche rewrites := &rewriter{} spans := pprof.ProfileSpans(profile) + traceIDs := pprof.ProfileTraceIDs(profile) pprof.ZeroLabelStrings(profile) p.strings.ingest(profile.StringTable, rewrites) - mappings := make([]*schemav1.InMemoryMapping, len(profile.Mapping)) + mappings := make([]schemav1.InMemoryMapping, len(profile.Mapping)) for i, v := range profile.Mapping { - mappings[i] = &schemav1.InMemoryMapping{ + mappings[i] = schemav1.InMemoryMapping{ Id: v.Id, MemoryStart: v.MemoryStart, MemoryLimit: v.MemoryLimit, @@ -53,9 +55,9 @@ func (p *PartitionWriter) WriteProfileSymbols(profile *profilev1.Profile) []sche } p.mappings.ingest(mappings, rewrites) - funcs := make([]*schemav1.InMemoryFunction, len(profile.Function)) + funcs := make([]schemav1.InMemoryFunction, len(profile.Function)) for i, v := range profile.Function { - funcs[i] = &schemav1.InMemoryFunction{ + funcs[i] = schemav1.InMemoryFunction{ Id: v.Id, Name: uint32(v.Name), SystemName: uint32(v.SystemName), @@ -65,9 +67,9 @@ func (p *PartitionWriter) WriteProfileSymbols(profile *profilev1.Profile) []sche } p.functions.ingest(funcs, rewrites) - locs := make([]*schemav1.InMemoryLocation, len(profile.Location)) + locs := make([]schemav1.InMemoryLocation, len(profile.Location)) for i, v := range profile.Location { - x := &schemav1.InMemoryLocation{ + x := schemav1.InMemoryLocation{ Id: v.Id, Address: v.Address, MappingId: uint32(v.MappingId), @@ -84,7 +86,7 @@ func (p *PartitionWriter) WriteProfileSymbols(profile *profilev1.Profile) []sche } p.locations.ingest(locs, rewrites) - samplesPerType := p.convertSamples(rewrites, profile.Sample, spans) + samplesPerType := p.convertSamples(rewrites, profile.Sample, spans, traceIDs) profiles := make([]schemav1.InMemoryProfile, len(samplesPerType)) for idxType := range samplesPerType { @@ -103,7 +105,7 @@ func (p *PartitionWriter) WriteProfileSymbols(profile *profilev1.Profile) []sche return profiles } -func (p *PartitionWriter) convertSamples(r *rewriter, in []*profilev1.Sample, spans []uint64) []schemav1.Samples { +func (p *PartitionWriter) convertSamples(r *rewriter, in []*profilev1.Sample, spans []uint64, traceIDs [][16]byte) []schemav1.Samples { if len(in) == 0 { return nil } @@ -123,6 +125,10 @@ func (p *PartitionWriter) convertSamples(r *rewriter, in []*profilev1.Sample, sp s.Spans = make([]uint64, len(spans)) copy(s.Spans, spans) } + if len(traceIDs) > 0 { + s.TraceIDs = make([][16]byte, len(traceIDs)) + copy(s.TraceIDs, traceIDs) + } samplesByType[i] = s } @@ -147,7 +153,7 @@ func (p *PartitionWriter) convertSamples(r *rewriter, in []*profilev1.Sample, sp for i := range samples.StacktraceIDs { samples.StacktraceIDs[i] = stacktracesIds[i] } - samples = samples.Compact(false) + samples = samples.Compact() sort.Sort(samples) samplesByType[idxType] = samples } @@ -213,7 +219,7 @@ type rewriter struct { type storeHelper[M schemav1.Models] interface { // some Models contain their own IDs within the struct, this allows to set them and keep track of the preexisting ID. It should return the oldID that is supposed to be rewritten. - setID(existingSliceID uint64, newID uint64, element M) uint64 + setID(existingSliceID uint64, newID uint64, element *M) uint64 // size returns a (rough estimation) of the size of a single element M size(M) uint64 @@ -221,7 +227,7 @@ type storeHelper[M schemav1.Models] interface { // clone copies parts that are not optimally sized from protobuf parsing clone(M) M - rewrite(*rewriter, M) error + rewrite(*rewriter, *M) error } type Helper[M schemav1.Models, K comparable] interface { @@ -254,13 +260,13 @@ func (s *deduplicatingSlice[M, K, H]) Size() uint64 { func (s *deduplicatingSlice[M, K, H]) ingest(elems []M, rewriter *rewriter) { var ( - rewritingMap = make(map[int64]int64) + rewritingMap = make(map[int64]int64, len(elems)) missing = int64SlicePool.Get() ) missing = missing[:0] // rewrite elements for pos := range elems { - _ = s.helper.rewrite(rewriter, elems[pos]) + _ = s.helper.rewrite(rewriter, &elems[pos]) } // try to find if element already exists in slice, when supposed to deduplicate @@ -268,7 +274,7 @@ func (s *deduplicatingSlice[M, K, H]) ingest(elems []M, rewriter *rewriter) { for pos := range elems { k := s.helper.key(elems[pos]) if posSlice, exists := s.lookup[k]; exists { - rewritingMap[int64(s.helper.setID(uint64(pos), uint64(posSlice), elems[pos]))] = posSlice + rewritingMap[int64(s.helper.setID(uint64(pos), uint64(posSlice), &elems[pos]))] = posSlice } else { missing = append(missing, int64(pos)) } @@ -279,18 +285,19 @@ func (s *deduplicatingSlice[M, K, H]) ingest(elems []M, rewriter *rewriter) { if len(missing) > 0 { s.lock.Lock() posSlice := int64(len(s.slice)) + s.slice = stdslices.Grow(s.slice, len(missing)) for _, pos := range missing { // check again if element exists k := s.helper.key(elems[pos]) if posSlice, exists := s.lookup[k]; exists { - rewritingMap[int64(s.helper.setID(uint64(pos), uint64(posSlice), elems[pos]))] = posSlice + rewritingMap[int64(s.helper.setID(uint64(pos), uint64(posSlice), &elems[pos]))] = posSlice continue } // add element to slice/map s.slice = append(s.slice, s.helper.clone(elems[pos])) s.lookup[k] = posSlice - rewritingMap[int64(s.helper.setID(uint64(pos), uint64(posSlice), elems[pos]))] = posSlice + rewritingMap[int64(s.helper.setID(uint64(pos), uint64(posSlice), &elems[pos]))] = posSlice posSlice++ s.size.Add(s.helper.size(elems[pos])) } @@ -380,7 +387,7 @@ func (*stringsHelper) addToRewriter(r *rewriter, m idConversionTable) { } // nolint unused -func (*stringsHelper) rewrite(*rewriter, string) error { +func (*stringsHelper) rewrite(*rewriter, *string) error { return nil } @@ -388,7 +395,7 @@ func (*stringsHelper) size(s string) uint64 { return uint64(len(s)) } -func (*stringsHelper) setID(oldID, newID uint64, s string) uint64 { +func (*stringsHelper) setID(oldID, newID uint64, s *string) uint64 { return oldID } @@ -409,7 +416,7 @@ const ( type locationsHelper struct{} -func (*locationsHelper) key(l *schemav1.InMemoryLocation) locationsKey { +func (*locationsHelper) key(l schemav1.InMemoryLocation) locationsKey { return locationsKey{ Address: l.Address, MappingId: l.MappingId, @@ -458,15 +465,15 @@ func (*locationsHelper) setID(_, newID uint64, l *schemav1.InMemoryLocation) uin return oldID } -func (*locationsHelper) size(l *schemav1.InMemoryLocation) uint64 { +func (*locationsHelper) size(l schemav1.InMemoryLocation) uint64 { return uint64(len(l.Line))*lineSize + locationSize } -func (*locationsHelper) clone(l *schemav1.InMemoryLocation) *schemav1.InMemoryLocation { - x := *l +func (*locationsHelper) clone(l schemav1.InMemoryLocation) schemav1.InMemoryLocation { + x := l x.Line = make([]schemav1.InMemoryLine, len(l.Line)) copy(x.Line, l.Line) - return &x + return x } type mappingsHelper struct{} @@ -485,7 +492,7 @@ type mappingsKey struct { HasInlineFrames bool } -func (*mappingsHelper) key(m *schemav1.InMemoryMapping) mappingsKey { +func (*mappingsHelper) key(m schemav1.InMemoryMapping) mappingsKey { return mappingsKey{ MemoryStart: m.MemoryStart, MemoryLimit: m.MemoryLimit, @@ -516,13 +523,12 @@ func (*mappingsHelper) setID(_, newID uint64, m *schemav1.InMemoryMapping) uint6 return oldID } -func (*mappingsHelper) size(_ *schemav1.InMemoryMapping) uint64 { +func (*mappingsHelper) size(_ schemav1.InMemoryMapping) uint64 { return mappingSize } -func (*mappingsHelper) clone(m *schemav1.InMemoryMapping) *schemav1.InMemoryMapping { - x := *m - return &x +func (*mappingsHelper) clone(m schemav1.InMemoryMapping) schemav1.InMemoryMapping { + return m } type functionsKey struct { @@ -536,7 +542,7 @@ type functionsHelper struct{} const functionSize = uint64(unsafe.Sizeof(schemav1.InMemoryFunction{})) -func (*functionsHelper) key(f *schemav1.InMemoryFunction) functionsKey { +func (*functionsHelper) key(f schemav1.InMemoryFunction) functionsKey { return functionsKey{ Name: f.Name, SystemName: f.SystemName, @@ -562,11 +568,10 @@ func (*functionsHelper) setID(_, newID uint64, f *schemav1.InMemoryFunction) uin return oldID } -func (*functionsHelper) size(_ *schemav1.InMemoryFunction) uint64 { +func (*functionsHelper) size(_ schemav1.InMemoryFunction) uint64 { return functionSize } -func (*functionsHelper) clone(f *schemav1.InMemoryFunction) *schemav1.InMemoryFunction { - x := *f - return &x +func (*functionsHelper) clone(f schemav1.InMemoryFunction) schemav1.InMemoryFunction { + return f } diff --git a/pkg/phlaredb/symdb/format.go b/pkg/phlaredb/symdb/format.go index 781ed86832..a5fb8d2585 100644 --- a/pkg/phlaredb/symdb/format.go +++ b/pkg/phlaredb/symdb/format.go @@ -1,3 +1,4 @@ +//nolint:unused package symdb import ( @@ -7,51 +8,83 @@ import ( "hash/crc32" "io" "unsafe" + + "github.com/parquet-go/parquet-go/encoding/delta" + + "github.com/grafana/pyroscope/v2/pkg/slices" ) +// V1 and V2: +// // The database is a collection of files. The only file that is guaranteed // to be present is the index file: it indicates the version of the format, // and the structure of the database contents. The file is supposed to be -// read into memory entirely and opened with a ReadIndexFile call. -// -// Big endian order is used unless otherwise noted. +// read into memory entirely and opened with an OpenIndex call. + +// V3: // -// Layout of the index file (single-pass write): +// The database is a single file. The file consists of the following sections: +// [Data ] +// [Index ] +// [Footer] // -// [Header] Header defines the format version and denotes the content type. +// The file is supposed to be open with Open call: it reads the footer, locates +// index section, and fetches it into memory. // -// [TOC] Table of contents. Its entries refer to the Data section. -// It is of a fixed size for a given version (number of entries). +// Data section is version specific. +// v3: Partitions. // -// [Data] Data is an arbitrary structured section. The exact structure is -// defined by the TOC and Header (version, flags, etc). +// Index section is structured in the following way: // -// [CRC32] Checksum. +// [IndexHeader] Header defines the format version and denotes the content type. +// [TOC ] Table of contents. Its entries refer to the Data section. +// It is of a fixed size for a given version (number of entries). +// [Data ] Data is an arbitrary structured section. The exact structure is +// defined by the TOC and Header (version, flags, etc). +// v1: StacktraceChunkHeaders. +// v2: PartitionHeadersV2. +// v3: PartitionHeadersV3. +// [CRC32 ] Checksum. // +// Footer section is version agnostic and is only needed to locate +// the index offset within the file. + +// In all version big endian order is used unless otherwise noted. const ( - DefaultDirName = "symbols" + DefaultFileName = "symbols.symdb" // Added in v3. + + // Pre-v3 assets. Left for compatibility reasons. + DefaultDirName = "symbols" IndexFileName = "index.symdb" StacktracesFileName = "stacktraces.symdb" ) -const HeaderSize = int(unsafe.Sizeof(Header{})) +type FormatVersion uint32 const ( - _ = iota + // Within a database, the same format version + // must be used in all places. + _ FormatVersion = iota FormatV1 FormatV2 + FormatV3 unknownVersion ) const ( // TOC entries are version-specific. + // The constants point to the entry index in the TOC. tocEntryStacktraceChunkHeaders = 0 tocEntryPartitionHeaders = 0 - tocEntries = 1 + + // Total number of entries in the current version. + // TODO(kolesnikovae): TOC size is version specific, + // but at the moment, all versions have the same size: 1. + tocEntriesTotal = 1 ) // https://en.wikipedia.org/wiki/List_of_file_signatures @@ -78,43 +111,86 @@ func (e *FormatError) Error() string { } type IndexFile struct { - Header Header + Header IndexHeader TOC TOC - // Version-specific parts. + // Version-specific. PartitionHeaders PartitionHeaders - CRC uint32 + CRC uint32 // Checksum of the index. } -type Header struct { - Magic [4]byte - Version uint32 - Reserved [8]byte // Reserved for future use. +// NOTE(kolesnikovae): IndexHeader is rudimentary and is left for compatibility. + +type IndexHeader struct { + Magic [4]byte + Version FormatVersion + _ [4]byte // Reserved for future use. + _ [4]byte // Reserved for future use. } -func (h *Header) MarshalBinary() ([]byte, error) { - b := make([]byte, HeaderSize) +const IndexHeaderSize = int(unsafe.Sizeof(IndexHeader{})) + +func (h *IndexHeader) MarshalBinary() []byte { + b := make([]byte, IndexHeaderSize) copy(b[0:4], h.Magic[:]) - binary.BigEndian.PutUint32(b[4:8], h.Version) - binary.BigEndian.PutUint32(b[HeaderSize-4:], crc32.Checksum(b[:HeaderSize-4], castagnoli)) - return b, nil + binary.BigEndian.PutUint32(b[4:8], uint32(h.Version)) + return b } -func (h *Header) UnmarshalBinary(b []byte) error { - if len(b) != HeaderSize { +func (h *IndexHeader) UnmarshalBinary(b []byte) error { + if len(b) != IndexHeaderSize { return ErrInvalidSize } if copy(h.Magic[:], b[0:4]); !bytes.Equal(h.Magic[:], symdbMagic[:]) { return ErrInvalidMagic } - // Reserved space may change from version to version. - if h.Version = binary.BigEndian.Uint32(b[4:8]); h.Version >= unknownVersion { + h.Version = FormatVersion(binary.BigEndian.Uint32(b[4:8])) + if h.Version >= unknownVersion { return ErrUnknownVersion } return nil } +type Footer struct { + Magic [4]byte + Version FormatVersion + IndexOffset uint64 // Index header offset in the file. + _ [4]byte // Reserved for future use. + CRC uint32 // CRC of the footer. +} + +const FooterSize = int(unsafe.Sizeof(Footer{})) + +func (f *Footer) MarshalBinary() []byte { + b := make([]byte, FooterSize) + copy(b[0:4], f.Magic[:]) + binary.BigEndian.PutUint32(b[4:8], uint32(f.Version)) + binary.BigEndian.PutUint64(b[8:16], f.IndexOffset) + binary.BigEndian.PutUint32(b[16:20], 0) + binary.BigEndian.PutUint32(b[20:24], crc32.Checksum(b[0:20], castagnoli)) + return b +} + +func (f *Footer) UnmarshalBinary(b []byte) error { + if len(b) != FooterSize { + return ErrInvalidSize + } + if copy(f.Magic[:], b[0:4]); !bytes.Equal(f.Magic[:], symdbMagic[:]) { + return ErrInvalidMagic + } + f.Version = FormatVersion(binary.BigEndian.Uint32(b[4:8])) + if f.Version >= unknownVersion { + return ErrUnknownVersion + } + f.IndexOffset = binary.BigEndian.Uint64(b[8:16]) + f.CRC = binary.BigEndian.Uint32(b[20:24]) + if crc32.Checksum(b[0:20], castagnoli) != f.CRC { + return ErrInvalidCRC + } + return nil +} + // Table of contents. const tocEntrySize = int(unsafe.Sizeof(TOCEntry{})) @@ -123,13 +199,15 @@ type TOC struct { Entries []TOCEntry } +// TOCEntry refers to a section within the index. +// Offset is relative to the header offset. type TOCEntry struct { Offset int64 Size int64 } func (toc *TOC) Size() int { - return tocEntrySize * tocEntries + return tocEntrySize * tocEntriesTotal } func (toc *TOC) MarshalBinary() ([]byte, error) { @@ -167,12 +245,10 @@ type PartitionHeaders []*PartitionHeader type PartitionHeader struct { Partition uint64 - - StacktraceChunks []StacktraceChunkHeader - Locations []RowRangeReference - Mappings []RowRangeReference - Functions []RowRangeReference - Strings []RowRangeReference + // TODO(kolesnikovae): Switch to SymbolsBlock encoding. + Stacktraces []StacktraceBlockHeader + V2 *PartitionHeaderV2 + V3 *PartitionHeaderV3 } func (h *PartitionHeaders) Size() int64 { @@ -183,8 +259,21 @@ func (h *PartitionHeaders) Size() int64 { return s } -func (h *PartitionHeaders) WriteTo(dst io.Writer) (_ int64, err error) { - w := withWriterOffset(dst, 0) +func (h *PartitionHeaders) MarshalV3To(dst io.Writer) (_ int64, err error) { + w := withWriterOffset(dst) + buf := make([]byte, 4, 128) + binary.BigEndian.PutUint32(buf, uint32(len(*h))) + w.write(buf) + for _, p := range *h { + buf = slices.GrowLen(buf, int(p.Size())) + p.marshalV3(buf) + w.write(buf) + } + return w.offset, w.err +} + +func (h *PartitionHeaders) MarshalV2To(dst io.Writer) (_ int64, err error) { + w := withWriterOffset(dst) buf := make([]byte, 4, 128) binary.BigEndian.PutUint32(buf, uint32(len(*h))) w.write(buf) @@ -194,19 +283,44 @@ func (h *PartitionHeaders) WriteTo(dst io.Writer) (_ int64, err error) { buf = make([]byte, s) } buf = buf[:s] - p.marshal(buf) + p.marshalV2(buf) w.write(buf) } return w.offset, w.err } -func (h *PartitionHeaders) Unmarshal(b []byte) error { +func (h *PartitionHeaders) UnmarshalV1(b []byte) error { + s := len(b) + if s%stacktraceBlockHeaderSize > 0 { + return ErrInvalidSize + } + chunks := make([]StacktraceBlockHeader, s/stacktraceBlockHeaderSize) + for i := range chunks { + off := i * stacktraceBlockHeaderSize + chunks[i].unmarshal(b[off : off+stacktraceBlockHeaderSize]) + } + var p *PartitionHeader + for _, c := range chunks { + if p == nil || p.Partition != c.Partition { + p = &PartitionHeader{Partition: c.Partition} + *h = append(*h, p) + } + p.Stacktraces = append(p.Stacktraces, c) + } + return nil +} + +func (h *PartitionHeaders) UnmarshalV2(b []byte) error { return h.unmarshal(b, FormatV2) } + +func (h *PartitionHeaders) UnmarshalV3(b []byte) error { return h.unmarshal(b, FormatV3) } + +func (h *PartitionHeaders) unmarshal(b []byte, version FormatVersion) error { partitions := binary.BigEndian.Uint32(b[0:4]) b = b[4:] *h = make(PartitionHeaders, partitions) for i := range *h { var p PartitionHeader - if err := p.unmarshal(b); err != nil { + if err := p.unmarshal(b, version); err != nil { return err } b = b[p.Size():] @@ -215,59 +329,216 @@ func (h *PartitionHeaders) Unmarshal(b []byte) error { return nil } -func (h *PartitionHeaders) fromChunks(b []byte) error { - s := len(b) - if s%stacktraceChunkHeaderSize > 0 { - return ErrInvalidSize +func (h *PartitionHeader) marshalV2(buf []byte) { + binary.BigEndian.PutUint64(buf[0:8], h.Partition) + binary.BigEndian.PutUint32(buf[8:12], uint32(len(h.Stacktraces))) + binary.BigEndian.PutUint32(buf[12:16], uint32(len(h.V2.Locations))) + binary.BigEndian.PutUint32(buf[16:20], uint32(len(h.V2.Mappings))) + binary.BigEndian.PutUint32(buf[20:24], uint32(len(h.V2.Functions))) + binary.BigEndian.PutUint32(buf[24:28], uint32(len(h.V2.Strings))) + n := 28 + for i := range h.Stacktraces { + h.Stacktraces[i].marshal(buf[n:]) + n += stacktraceBlockHeaderSize } - chunks := make([]StacktraceChunkHeader, s/stacktraceChunkHeaderSize) - for i := range chunks { - off := i * stacktraceChunkHeaderSize - chunks[i].unmarshal(b[off : off+stacktraceChunkHeaderSize]) + n += marshalRowRangeReferences(buf[n:], h.V2.Locations) + n += marshalRowRangeReferences(buf[n:], h.V2.Mappings) + n += marshalRowRangeReferences(buf[n:], h.V2.Functions) + marshalRowRangeReferences(buf[n:], h.V2.Strings) +} + +func (h *PartitionHeader) marshalV3(buf []byte) { + binary.BigEndian.PutUint64(buf[0:8], h.Partition) + binary.BigEndian.PutUint32(buf[8:12], uint32(len(h.Stacktraces))) + n := 12 + for i := range h.Stacktraces { + h.Stacktraces[i].marshal(buf[n:]) + n += stacktraceBlockHeaderSize } - var p *PartitionHeader - for _, c := range chunks { - if p == nil || p.Partition != c.Partition { - p = &PartitionHeader{Partition: c.Partition} - *h = append(*h, p) + n += marshalSymbolsBlockReferences(buf[n:], h.V3.Locations) + n += marshalSymbolsBlockReferences(buf[n:], h.V3.Mappings) + n += marshalSymbolsBlockReferences(buf[n:], h.V3.Functions) + marshalSymbolsBlockReferences(buf[n:], h.V3.Strings) +} + +func (h *PartitionHeader) unmarshal(buf []byte, version FormatVersion) (err error) { + h.Partition = binary.BigEndian.Uint64(buf[0:8]) + h.Stacktraces = make([]StacktraceBlockHeader, int(binary.BigEndian.Uint32(buf[8:12]))) + switch version { + case FormatV2: + h.V2 = new(PartitionHeaderV2) + h.V2.Locations = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[12:16]))) + h.V2.Mappings = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[16:20]))) + h.V2.Functions = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[20:24]))) + h.V2.Strings = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[24:28]))) + buf = buf[28:] + stacktracesSize := len(h.Stacktraces) * stacktraceBlockHeaderSize + if err = h.unmarshalStacktraceBlockHeaders(buf[:stacktracesSize]); err != nil { + return err + } + err = h.V2.unmarshal(buf[stacktracesSize:]) + case FormatV3: + buf = buf[12:] + stacktracesSize := len(h.Stacktraces) * stacktraceBlockHeaderSize + if err = h.unmarshalStacktraceBlockHeaders(buf[:stacktracesSize]); err != nil { + return err } - p.StacktraceChunks = append(p.StacktraceChunks, c) + h.V3 = new(PartitionHeaderV3) + err = h.V3.unmarshal(buf[stacktracesSize:]) + default: + return fmt.Errorf("bug: unsupported version: %d", version) } + // TODO(kolesnikovae): Validate headers. + return err +} + +func (h *PartitionHeader) Size() int64 { + s := 12 // Partition 8b + number of stacktrace blocks. + s += len(h.Stacktraces) * stacktraceBlockHeaderSize + if h.V3 != nil { + s += h.V3.size() + } + if h.V2 != nil { + s += h.V2.size() + } + return int64(s) +} + +type PartitionHeaderV3 struct { + Locations SymbolsBlockHeader + Mappings SymbolsBlockHeader + Functions SymbolsBlockHeader + Strings SymbolsBlockHeader +} + +const partitionHeaderV3Size = int(unsafe.Sizeof(PartitionHeaderV3{})) + +func (h *PartitionHeaderV3) size() int { return partitionHeaderV3Size } + +func (h *PartitionHeaderV3) unmarshal(buf []byte) (err error) { + if len(buf) < symbolsBlockReferenceSize { + return ErrInvalidSize + } + h.Locations.unmarshal(buf[:symbolsBlockReferenceSize]) + buf = buf[symbolsBlockReferenceSize:] + h.Mappings.unmarshal(buf[:symbolsBlockReferenceSize]) + buf = buf[symbolsBlockReferenceSize:] + h.Functions.unmarshal(buf[:symbolsBlockReferenceSize]) + buf = buf[symbolsBlockReferenceSize:] + h.Strings.unmarshal(buf[:symbolsBlockReferenceSize]) return nil } -func (h *PartitionHeader) marshal(buf []byte) { - binary.BigEndian.PutUint64(buf[0:8], h.Partition) - binary.BigEndian.PutUint32(buf[8:12], uint32(len(h.StacktraceChunks))) - binary.BigEndian.PutUint32(buf[12:16], uint32(len(h.Locations))) - binary.BigEndian.PutUint32(buf[16:20], uint32(len(h.Mappings))) - binary.BigEndian.PutUint32(buf[20:24], uint32(len(h.Functions))) - binary.BigEndian.PutUint32(buf[24:28], uint32(len(h.Strings))) - n := 28 - for i := range h.StacktraceChunks { - h.StacktraceChunks[i].marshal(buf[n:]) - n += stacktraceChunkHeaderSize +func (h *PartitionHeader) unmarshalStacktraceBlockHeaders(b []byte) error { + s := len(b) + if s%stacktraceBlockHeaderSize > 0 { + return ErrInvalidSize } - n += marshalRowRangeReferences(buf[n:], h.Locations) - n += marshalRowRangeReferences(buf[n:], h.Mappings) - n += marshalRowRangeReferences(buf[n:], h.Functions) - marshalRowRangeReferences(buf[n:], h.Strings) + for i := range h.Stacktraces { + off := i * stacktraceBlockHeaderSize + h.Stacktraces[i].unmarshal(b[off : off+stacktraceBlockHeaderSize]) + } + return nil } -func (h *PartitionHeader) unmarshal(buf []byte) (err error) { - h.Partition = binary.BigEndian.Uint64(buf[0:8]) - h.StacktraceChunks = make([]StacktraceChunkHeader, int(binary.BigEndian.Uint32(buf[8:12]))) - h.Locations = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[12:16]))) - h.Mappings = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[16:20]))) - h.Functions = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[20:24]))) - h.Strings = make([]RowRangeReference, int(binary.BigEndian.Uint32(buf[24:28]))) - - buf = buf[28:] - stacktracesSize := len(h.StacktraceChunks) * stacktraceChunkHeaderSize - if err = h.unmarshalStacktraceChunks(buf[:stacktracesSize]); err != nil { +// SymbolsBlockHeader describes a collection of elements encoded in a +// content-specific way: symbolic information such as locations, functions, +// mappings, and strings is represented as Array of Structures in memory, +// and is encoded as Structure of Arrays when written on disk. +type SymbolsBlockHeader struct { + // Offset in the data file. + Offset uint64 + // Size of the section. + Size uint32 + // Checksum of the section. + CRC uint32 + // Length denotes the total number of items encoded. + Length uint32 + // BlockSize denotes the number of items per block. + BlockSize uint32 + // BlockHeaderSize denotes the encoder block header size in bytes. + // This enables forward compatibility within the same format version: + // as long as fields are not removed or reordered, and the encoding + // scheme does not change, the format can be extended without updating + // the format version. Decoder is able to read the whole header and + // skip unknown fields. + BlockHeaderSize uint16 + // Format of the encoded data. + // Change of the format _version_ may break forward compatibility. + Format SymbolsBlockFormat +} + +type SymbolsBlockFormat uint16 + +const ( + _ SymbolsBlockFormat = iota + BlockLocationsV1 + BlockFunctionsV1 + BlockMappingsV1 + BlockStringsV1 +) + +type headerUnmarshaler interface { + unmarshal([]byte) + checksum() uint32 +} + +func readSymbolsBlockHeader(buf []byte, r io.Reader, v headerUnmarshaler) error { + if _, err := io.ReadFull(r, buf); err != nil { return err } - buf = buf[stacktracesSize:] + v.unmarshal(buf) + if crc32.Checksum(buf[:len(buf)-checksumSize], castagnoli) != v.checksum() { + return ErrInvalidCRC + } + return nil +} + +const symbolsBlockReferenceSize = int(unsafe.Sizeof(SymbolsBlockHeader{})) + +func (h *SymbolsBlockHeader) marshal(b []byte) { + binary.BigEndian.PutUint64(b[0:8], h.Offset) + binary.BigEndian.PutUint32(b[8:12], h.Size) + binary.BigEndian.PutUint32(b[12:16], h.CRC) + binary.BigEndian.PutUint32(b[16:20], h.Length) + binary.BigEndian.PutUint32(b[20:24], h.BlockSize) + binary.BigEndian.PutUint16(b[24:26], h.BlockHeaderSize) + binary.BigEndian.PutUint16(b[26:28], uint16(h.Format)) +} + +func (h *SymbolsBlockHeader) unmarshal(b []byte) { + h.Offset = binary.BigEndian.Uint64(b[0:8]) + h.Size = binary.BigEndian.Uint32(b[8:12]) + h.CRC = binary.BigEndian.Uint32(b[12:16]) + h.Length = binary.BigEndian.Uint32(b[16:20]) + h.BlockSize = binary.BigEndian.Uint32(b[20:24]) + h.BlockHeaderSize = binary.BigEndian.Uint16(b[24:26]) + h.Format = SymbolsBlockFormat(binary.BigEndian.Uint16(b[26:28])) +} + +func marshalSymbolsBlockReferences(b []byte, refs ...SymbolsBlockHeader) int { + var off int + for i := range refs { + refs[i].marshal(b[off : off+symbolsBlockReferenceSize]) + off += symbolsBlockReferenceSize + } + return off +} + +type PartitionHeaderV2 struct { + Locations []RowRangeReference + Mappings []RowRangeReference + Functions []RowRangeReference + Strings []RowRangeReference +} + +func (h *PartitionHeaderV2) size() int { + s := 16 // Length of row ranges per type. + r := len(h.Locations) + len(h.Mappings) + len(h.Functions) + len(h.Strings) + return s + rowRangeReferenceSize*r +} + +func (h *PartitionHeaderV2) unmarshal(buf []byte) (err error) { locationsSize := len(h.Locations) * rowRangeReferenceSize if err = h.unmarshalRowRangeReferences(h.Locations, buf[:locationsSize]); err != nil { return err @@ -287,31 +558,10 @@ func (h *PartitionHeader) unmarshal(buf []byte) (err error) { if err = h.unmarshalRowRangeReferences(h.Strings, buf[:stringsSize]); err != nil { return err } - return nil } -func (h *PartitionHeader) Size() int64 { - s := 28 - s += len(h.StacktraceChunks) * stacktraceChunkHeaderSize - r := len(h.Locations) + len(h.Mappings) + len(h.Functions) + len(h.Strings) - s += r * rowRangeReferenceSize - return int64(s) -} - -func (h *PartitionHeader) unmarshalStacktraceChunks(b []byte) error { - s := len(b) - if s%stacktraceChunkHeaderSize > 0 { - return ErrInvalidSize - } - for i := range h.StacktraceChunks { - off := i * stacktraceChunkHeaderSize - h.StacktraceChunks[i].unmarshal(b[off : off+stacktraceChunkHeaderSize]) - } - return nil -} - -func (h *PartitionHeader) unmarshalRowRangeReferences(refs []RowRangeReference, b []byte) error { +func (h *PartitionHeaderV2) unmarshalRowRangeReferences(refs []RowRangeReference, b []byte) error { s := len(b) if s%rowRangeReferenceSize > 0 { return ErrInvalidSize @@ -352,16 +602,103 @@ func (r *RowRangeReference) unmarshal(b []byte) { r.Rows = binary.BigEndian.Uint32(b[8:12]) } -const stacktraceChunkHeaderSize = int(unsafe.Sizeof(StacktraceChunkHeader{})) +func OpenIndex(b []byte) (f IndexFile, err error) { + s := len(b) + if !f.assertSizeIsValid(b) { + return f, ErrInvalidSize + } + f.CRC = binary.BigEndian.Uint32(b[s+indexChecksumOffset:]) + if f.CRC != crc32.Checksum(b[:s+indexChecksumOffset], castagnoli) { + return f, ErrInvalidCRC + } + if err = f.Header.UnmarshalBinary(b[:IndexHeaderSize]); err != nil { + return f, fmt.Errorf("unmarshal header: %w", err) + } + if err = f.TOC.UnmarshalBinary(b[IndexHeaderSize:f.dataOffset()]); err != nil { + return f, fmt.Errorf("unmarshal table of contents: %w", err) + } + + // TODO: validate TOC + + // Version-specific data section. + switch f.Header.Version { + default: + return f, fmt.Errorf("bug: unsupported version: %d", f.Header.Version) + + case FormatV1: + sch := f.TOC.Entries[tocEntryStacktraceChunkHeaders] + if err = f.PartitionHeaders.UnmarshalV1(b[sch.Offset : sch.Offset+sch.Size]); err != nil { + return f, fmt.Errorf("unmarshal stacktraces: %w", err) + } + + case FormatV2: + ph := f.TOC.Entries[tocEntryPartitionHeaders] + if err = f.PartitionHeaders.UnmarshalV2(b[ph.Offset : ph.Offset+ph.Size]); err != nil { + return f, fmt.Errorf("reading partition headers: %w", err) + } + + case FormatV3: + ph := f.TOC.Entries[tocEntryPartitionHeaders] + if err = f.PartitionHeaders.UnmarshalV3(b[ph.Offset : ph.Offset+ph.Size]); err != nil { + return f, fmt.Errorf("reading partition headers: %w", err) + } + } + + return f, nil +} + +func (f *IndexFile) assertSizeIsValid(b []byte) bool { + return len(b) >= IndexHeaderSize+f.TOC.Size()+checksumSize +} + +func (f *IndexFile) dataOffset() int { + return IndexHeaderSize + f.TOC.Size() +} + +func (f *IndexFile) WriteTo(dst io.Writer) (n int64, err error) { + checksum := crc32.New(castagnoli) + w := withWriterOffset(io.MultiWriter(dst, checksum)) + if _, err = w.Write(f.Header.MarshalBinary()); err != nil { + return w.offset, fmt.Errorf("header write: %w", err) + } -type StacktraceChunkHeader struct { + toc := TOC{Entries: make([]TOCEntry, tocEntriesTotal)} + toc.Entries[tocEntryPartitionHeaders] = TOCEntry{ + Offset: int64(f.dataOffset()), + Size: f.PartitionHeaders.Size(), + } + tocBytes, _ := toc.MarshalBinary() + if _, err = w.Write(tocBytes); err != nil { + return w.offset, fmt.Errorf("toc write: %w", err) + } + + switch f.Header.Version { + case FormatV3: + _, err = f.PartitionHeaders.MarshalV3To(w) + default: + _, err = f.PartitionHeaders.MarshalV2To(w) + } + if err != nil { + return w.offset, fmt.Errorf("partitions headers: %w", err) + } + + f.CRC = checksum.Sum32() + if err = binary.Write(dst, binary.BigEndian, f.CRC); err != nil { + return w.offset, fmt.Errorf("checksum write: %w", err) + } + + return w.offset, nil +} + +type StacktraceBlockHeader struct { Offset int64 Size int64 - Partition uint64 - ChunkIndex uint16 - ChunkEncoding ChunkEncoding - _ [5]byte // Reserved. + Partition uint64 // Used in v1. + BlockIndex uint16 // Used in v1. + + Encoding ChunkEncoding + _ [5]byte // Reserved. Stacktraces uint32 // Number of unique stack traces in the chunk. StacktraceNodes uint32 // Number of nodes in the stacktrace tree. @@ -372,19 +709,21 @@ type StacktraceChunkHeader struct { CRC uint32 // Checksum of the chunk data [Offset:Size). } +const stacktraceBlockHeaderSize = int(unsafe.Sizeof(StacktraceBlockHeader{})) + type ChunkEncoding byte const ( _ ChunkEncoding = iota - ChunkEncodingGroupVarint + StacktraceEncodingGroupVarint ) -func (h *StacktraceChunkHeader) marshal(b []byte) { +func (h *StacktraceBlockHeader) marshal(b []byte) { binary.BigEndian.PutUint64(b[0:8], uint64(h.Offset)) binary.BigEndian.PutUint64(b[8:16], uint64(h.Size)) binary.BigEndian.PutUint64(b[16:24], h.Partition) - binary.BigEndian.PutUint16(b[24:26], h.ChunkIndex) - b[27] = byte(h.ChunkEncoding) + binary.BigEndian.PutUint16(b[24:26], h.BlockIndex) + b[27] = byte(h.Encoding) // 5 bytes reserved. binary.BigEndian.PutUint32(b[32:36], h.Stacktraces) binary.BigEndian.PutUint32(b[36:40], h.StacktraceNodes) @@ -394,12 +733,12 @@ func (h *StacktraceChunkHeader) marshal(b []byte) { binary.BigEndian.PutUint32(b[60:64], h.CRC) } -func (h *StacktraceChunkHeader) unmarshal(b []byte) { +func (h *StacktraceBlockHeader) unmarshal(b []byte) { h.Offset = int64(binary.BigEndian.Uint64(b[0:8])) h.Size = int64(binary.BigEndian.Uint64(b[8:16])) h.Partition = binary.BigEndian.Uint64(b[16:24]) - h.ChunkIndex = binary.BigEndian.Uint16(b[24:26]) - h.ChunkEncoding = ChunkEncoding(b[27]) + h.BlockIndex = binary.BigEndian.Uint16(b[24:26]) + h.Encoding = ChunkEncoding(b[27]) // 5 bytes reserved. h.Stacktraces = binary.BigEndian.Uint32(b[32:36]) h.StacktraceNodes = binary.BigEndian.Uint32(b[36:40]) @@ -409,78 +748,91 @@ func (h *StacktraceChunkHeader) unmarshal(b []byte) { h.CRC = binary.BigEndian.Uint32(b[60:64]) } -func ReadIndexFile(b []byte) (f IndexFile, err error) { - s := len(b) - if !f.assertSizeIsValid(b) { - return f, ErrInvalidSize - } - f.CRC = binary.BigEndian.Uint32(b[s+indexChecksumOffset:]) - if f.CRC != crc32.Checksum(b[:s+indexChecksumOffset], castagnoli) { - return f, ErrInvalidCRC - } - if err = f.Header.UnmarshalBinary(b[:HeaderSize]); err != nil { - return f, fmt.Errorf("unmarshal header: %w", err) - } - if err = f.TOC.UnmarshalBinary(b[HeaderSize:f.dataOffset()]); err != nil { - return f, fmt.Errorf("unmarshal table of contents: %w", err) - } +type symbolsBlockEncoder[T any] interface { + encode(w io.Writer, block []T) error + format() SymbolsBlockFormat + headerSize() uintptr +} - // Version-specific data section. - switch f.Header.Version { - default: - // Must never happen: the version is verified - // when the file header is read. - panic("bug: invalid version") +type symbolsEncoder[T any] struct { + blockEncoder symbolsBlockEncoder[T] + blockSize int +} - case FormatV1: - sch := f.TOC.Entries[tocEntryStacktraceChunkHeaders] - if err = f.PartitionHeaders.fromChunks(b[sch.Offset : sch.Offset+sch.Size]); err != nil { - return f, fmt.Errorf("unmarshal stacktraces: %w", err) - } +const defaultSymbolsBlockSize = 1 << 10 - case FormatV2: - ph := f.TOC.Entries[tocEntryPartitionHeaders] - if err = f.PartitionHeaders.Unmarshal(b[ph.Offset : ph.Offset+ph.Size]); err != nil { - return f, fmt.Errorf("reading partition headers: %w", err) +func newSymbolsEncoder[T any](e symbolsBlockEncoder[T]) *symbolsEncoder[T] { + return &symbolsEncoder[T]{blockEncoder: e, blockSize: defaultSymbolsBlockSize} +} + +func (e *symbolsEncoder[T]) encode(w io.Writer, items []T) (err error) { + l := len(items) + for i := 0; i < l; i += e.blockSize { + block := items[i:min(i+e.blockSize, l)] + if err = e.blockEncoder.encode(w, block); err != nil { + return err } } - - return f, nil + return nil } -func (f *IndexFile) assertSizeIsValid(b []byte) bool { - return len(b) >= HeaderSize+f.TOC.Size()+checksumSize +type symbolsBlockDecoder[T any] interface { + decode(r io.Reader, dst []T) error } -func (f *IndexFile) dataOffset() int { - return HeaderSize + f.TOC.Size() +type symbolsDecoder[T any] struct { + h SymbolsBlockHeader + d symbolsBlockDecoder[T] } -func (f *IndexFile) WriteTo(dst io.Writer) (n int64, err error) { - checksum := crc32.New(castagnoli) - w := withWriterOffset(io.MultiWriter(dst, checksum), 0) - headerBytes, _ := f.Header.MarshalBinary() - if _, err = w.Write(headerBytes); err != nil { - return w.offset, fmt.Errorf("header write: %w", err) - } +func newSymbolsDecoder[T any](h SymbolsBlockHeader, d symbolsBlockDecoder[T]) *symbolsDecoder[T] { + return &symbolsDecoder[T]{h: h, d: d} +} - toc := TOC{Entries: make([]TOCEntry, tocEntries)} - toc.Entries[tocEntryPartitionHeaders] = TOCEntry{ - Offset: int64(f.dataOffset()), - Size: f.PartitionHeaders.Size(), +func (d *symbolsDecoder[T]) decode(dst []T, r io.Reader) error { + if d.h.BlockSize == 0 || d.h.Length == 0 { + return nil } - tocBytes, _ := toc.MarshalBinary() - if _, err = w.Write(tocBytes); err != nil { - return w.offset, fmt.Errorf("toc write: %w", err) + if len(dst) < int(d.h.Length) { + return fmt.Errorf("decoder buffer too short (format %d)", d.h.Format) } - if _, err = f.PartitionHeaders.WriteTo(w); err != nil { - return w.offset, fmt.Errorf("partitions headers: %w", err) + blocks := int((d.h.Length + d.h.BlockSize - 1) / d.h.BlockSize) + for i := 0; i < blocks; i++ { + lo := i * int(d.h.BlockSize) + hi := min(lo+int(d.h.BlockSize), int(d.h.Length)) + block := dst[lo:hi] + if err := d.d.decode(r, block); err != nil { + return fmt.Errorf("malformed block (format %d): %w", d.h.Format, err) + } } + return nil +} - f.CRC = checksum.Sum32() - if err = binary.Write(dst, binary.BigEndian, f.CRC); err != nil { - return w.offset, fmt.Errorf("checksum write: %w", err) +// NOTE(kolesnikovae): delta.BinaryPackedEncoding may +// silently fail on malformed data, producing empty slice. + +func decodeBinaryPackedInt32(dst []int32, data []byte, length int) ([]int32, error) { + var enc delta.BinaryPackedEncoding + var err error + dst, err = enc.DecodeInt32(dst, data) + if err != nil { + return dst, err + } + if len(dst) != length { + return dst, fmt.Errorf("%w: binary packed: expected %d, got %d", ErrInvalidSize, length, len(dst)) } + return dst, nil +} - return w.offset, nil +func decodeBinaryPackedInt64(dst []int64, data []byte, length int) ([]int64, error) { + var enc delta.BinaryPackedEncoding + var err error + dst, err = enc.DecodeInt64(dst, data) + if err != nil { + return dst, err + } + if len(dst) != length { + return dst, fmt.Errorf("%w: binary packed: expected %d, got %d", ErrInvalidSize, length, len(dst)) + } + return dst, nil } diff --git a/pkg/phlaredb/symdb/functions.go b/pkg/phlaredb/symdb/functions.go new file mode 100644 index 0000000000..657f9dd61d --- /dev/null +++ b/pkg/phlaredb/symdb/functions.go @@ -0,0 +1,205 @@ +//nolint:unused +package symdb + +import ( + "bytes" + "encoding/binary" + "fmt" + "hash/crc32" + "io" + "unsafe" + + "github.com/parquet-go/parquet-go/encoding/delta" + + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/slices" +) + +var ( + _ symbolsBlockEncoder[v1.InMemoryFunction] = (*functionsBlockEncoder)(nil) + _ symbolsBlockDecoder[v1.InMemoryFunction] = (*functionsBlockDecoder)(nil) +) + +type functionsBlockHeader struct { + FunctionsLen uint32 + NameSize uint32 + SystemNameSize uint32 + FileNameSize uint32 + StartLineSize uint32 + CRC uint32 +} + +func (h *functionsBlockHeader) marshal(b []byte) { + binary.BigEndian.PutUint32(b[0:4], h.FunctionsLen) + binary.BigEndian.PutUint32(b[4:8], h.NameSize) + binary.BigEndian.PutUint32(b[8:12], h.SystemNameSize) + binary.BigEndian.PutUint32(b[12:16], h.FileNameSize) + binary.BigEndian.PutUint32(b[16:20], h.StartLineSize) + // Fields can be added here in the future. + // CRC must be the last four bytes. + h.CRC = crc32.Checksum(b[0:20], castagnoli) + binary.BigEndian.PutUint32(b[20:24], h.CRC) +} + +func (h *functionsBlockHeader) unmarshal(b []byte) { + h.FunctionsLen = binary.BigEndian.Uint32(b[0:4]) + h.NameSize = binary.BigEndian.Uint32(b[4:8]) + h.SystemNameSize = binary.BigEndian.Uint32(b[8:12]) + h.FileNameSize = binary.BigEndian.Uint32(b[12:16]) + h.StartLineSize = binary.BigEndian.Uint32(b[16:20]) + // In future versions, new fields are decoded here; + // if pos < len(b)-checksumSize, then there are more fields. + h.CRC = binary.BigEndian.Uint32(b[len(b)-checksumSize:]) +} + +func (h *functionsBlockHeader) checksum() uint32 { return h.CRC } + +type functionsBlockEncoder struct { + header functionsBlockHeader + + tmp []byte + buf bytes.Buffer + ints []int32 +} + +func newFunctionsEncoder() *symbolsEncoder[v1.InMemoryFunction] { + return newSymbolsEncoder[v1.InMemoryFunction](new(functionsBlockEncoder)) +} + +func (e *functionsBlockEncoder) format() SymbolsBlockFormat { return BlockFunctionsV1 } + +func (e *functionsBlockEncoder) headerSize() uintptr { return unsafe.Sizeof(functionsBlockHeader{}) } + +func (e *functionsBlockEncoder) encode(w io.Writer, functions []v1.InMemoryFunction) error { + e.initWrite(len(functions)) + var enc delta.BinaryPackedEncoding + + for i, f := range functions { + e.ints[i] = int32(f.Name) + } + e.tmp, _ = enc.EncodeInt32(e.tmp, e.ints) + e.header.NameSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + + for i, f := range functions { + e.ints[i] = int32(f.SystemName) + } + e.tmp, _ = enc.EncodeInt32(e.tmp, e.ints) + e.header.SystemNameSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + + for i, f := range functions { + e.ints[i] = int32(f.Filename) + } + e.tmp, _ = enc.EncodeInt32(e.tmp, e.ints) + e.header.FileNameSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + + for i, f := range functions { + e.ints[i] = int32(f.StartLine) + } + e.tmp, _ = enc.EncodeInt32(e.tmp, e.ints) + e.header.StartLineSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + + e.tmp = slices.GrowLen(e.tmp, int(e.headerSize())) + e.header.marshal(e.tmp) + if _, err := w.Write(e.tmp); err != nil { + return err + } + _, err := e.buf.WriteTo(w) + return err +} + +func (e *functionsBlockEncoder) initWrite(functions int) { + e.buf.Reset() + // Actual estimate is ~7 bytes per function. + e.buf.Grow(functions * 8) + *e = functionsBlockEncoder{ + header: functionsBlockHeader{FunctionsLen: uint32(functions)}, + + tmp: slices.GrowLen(e.tmp, functions*2), + ints: slices.GrowLen(e.ints, functions), + buf: e.buf, + } +} + +type functionsBlockDecoder struct { + headerSize uint16 + header functionsBlockHeader + + ints []int32 + buf []byte +} + +func newFunctionsDecoder(h SymbolsBlockHeader) (*symbolsDecoder[v1.InMemoryFunction], error) { + if h.Format == BlockFunctionsV1 { + headerSize := max(functionsBlockHeaderMinSize, h.BlockHeaderSize) + return newSymbolsDecoder[v1.InMemoryFunction](h, &functionsBlockDecoder{headerSize: headerSize}), nil + } + return nil, fmt.Errorf("%w: unknown functions format: %d", ErrUnknownVersion, h.Format) +} + +// In early versions, block header size is not specified. Must not change. +const functionsBlockHeaderMinSize = 24 + +func (d *functionsBlockDecoder) decode(r io.Reader, functions []v1.InMemoryFunction) (err error) { + d.buf = slices.GrowLen(d.buf, int(d.headerSize)) + if err = readSymbolsBlockHeader(d.buf, r, &d.header); err != nil { + return err + } + if d.header.FunctionsLen > uint32(len(functions)) { + return fmt.Errorf("functions buffer is too short") + } + + d.ints = slices.GrowLen(d.ints, int(d.header.FunctionsLen)) + d.buf = slices.GrowLen(d.buf, int(d.header.NameSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints, err = decodeBinaryPackedInt32(d.ints, d.buf, int(d.header.FunctionsLen)) + if err != nil { + return err + } + for i, v := range d.ints { + functions[i].Name = uint32(v) + } + + d.buf = slices.GrowLen(d.buf, int(d.header.SystemNameSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints, err = decodeBinaryPackedInt32(d.ints, d.buf, int(d.header.FunctionsLen)) + if err != nil { + return err + } + for i, v := range d.ints { + functions[i].SystemName = uint32(v) + } + + d.buf = slices.GrowLen(d.buf, int(d.header.FileNameSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints, err = decodeBinaryPackedInt32(d.ints, d.buf, int(d.header.FunctionsLen)) + if err != nil { + return err + } + for i, v := range d.ints { + functions[i].Filename = uint32(v) + } + + d.buf = slices.GrowLen(d.buf, int(d.header.StartLineSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints, err = decodeBinaryPackedInt32(d.ints, d.buf, int(d.header.FunctionsLen)) + if err != nil { + return err + } + for i, v := range d.ints { + functions[i].StartLine = uint32(v) + } + + return nil +} diff --git a/pkg/phlaredb/symdb/functions_test.go b/pkg/phlaredb/symdb/functions_test.go new file mode 100644 index 0000000000..8909e78ea9 --- /dev/null +++ b/pkg/phlaredb/symdb/functions_test.go @@ -0,0 +1,62 @@ +package symdb + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +func Test_FunctionsEncoding(t *testing.T) { + type testCase struct { + description string + funcs []v1.InMemoryFunction + } + + testCases := []testCase{ + { + description: "empty", + funcs: []v1.InMemoryFunction{}, + }, + { + description: "zero", + funcs: []v1.InMemoryFunction{{}}, + }, + { + description: "single function", + funcs: []v1.InMemoryFunction{ + {Name: 1, SystemName: 2, Filename: 3, StartLine: 4}, + }, + }, + { + description: "multiline blocks", + funcs: []v1.InMemoryFunction{ + {Name: 1, SystemName: 2, Filename: 3, StartLine: 4}, + {Name: 5, SystemName: 6, Filename: 7, StartLine: 8}, + {Name: 9, SystemName: 10, Filename: 11}, + {}, + {Name: 13, SystemName: 14, Filename: 15, StartLine: 16}, + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + w := newTestFileWriter(&buf) + e := newFunctionsEncoder() + e.blockSize = 3 + h, err := writeSymbolsBlock(w, tc.funcs, e) + require.NoError(t, err) + + d, err := newFunctionsDecoder(h) + require.NoError(t, err) + out := make([]v1.InMemoryFunction, h.Length) + require.NoError(t, d.decode(out, &buf)) + require.Equal(t, tc.funcs, out) + }) + } +} diff --git a/pkg/phlaredb/symdb/locations.go b/pkg/phlaredb/symdb/locations.go new file mode 100644 index 0000000000..1bb4292eef --- /dev/null +++ b/pkg/phlaredb/symdb/locations.go @@ -0,0 +1,299 @@ +//nolint:unused +package symdb + +import ( + "bytes" + "encoding/binary" + "fmt" + "hash/crc32" + "io" + "unsafe" + + "github.com/parquet-go/parquet-go/encoding/delta" + + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/slices" +) + +const maxLocationLines = 255 + +var ( + _ symbolsBlockEncoder[v1.InMemoryLocation] = (*locationsBlockEncoder)(nil) + _ symbolsBlockDecoder[v1.InMemoryLocation] = (*locationsBlockDecoder)(nil) +) + +type locationsBlockHeader struct { + LocationsLen uint32 // Number of locations + MappingSize uint32 // Size of the encoded slice of mapping_ids + LinesLen uint32 // Number of lines per location + LinesSize uint32 // Size of the encoded lines + // Optional, might be empty. + AddrSize uint32 // Size of the encoded slice of addresses + IsFoldedSize uint32 // Size of the encoded slice of is_folded + CRC uint32 // Header CRC. +} + +func (h *locationsBlockHeader) marshal(b []byte) { + binary.BigEndian.PutUint32(b[0:4], h.LocationsLen) + binary.BigEndian.PutUint32(b[4:8], h.MappingSize) + binary.BigEndian.PutUint32(b[8:12], h.LinesLen) + binary.BigEndian.PutUint32(b[12:16], h.LinesSize) + binary.BigEndian.PutUint32(b[16:20], h.AddrSize) + binary.BigEndian.PutUint32(b[20:24], h.IsFoldedSize) + // Fields can be added here in the future. + // CRC must be the last four bytes. + h.CRC = crc32.Checksum(b[0:24], castagnoli) + binary.BigEndian.PutUint32(b[24:28], h.CRC) +} + +func (h *locationsBlockHeader) unmarshal(b []byte) { + h.LocationsLen = binary.BigEndian.Uint32(b[0:4]) + h.MappingSize = binary.BigEndian.Uint32(b[4:8]) + h.LinesLen = binary.BigEndian.Uint32(b[8:12]) + h.LinesSize = binary.BigEndian.Uint32(b[12:16]) + h.AddrSize = binary.BigEndian.Uint32(b[16:20]) + h.IsFoldedSize = binary.BigEndian.Uint32(b[20:24]) + // In future versions, new fields are decoded here; + // if pos < len(b)-checksumSize, then there are more fields. + h.CRC = binary.BigEndian.Uint32(b[24:28]) +} + +func (h *locationsBlockHeader) checksum() uint32 { return h.CRC } + +type locationsBlockEncoder struct { + header locationsBlockHeader + + mapping []int32 + // Assuming there are no locations with more than 255 lines. + // We could even use a nibble (4 bits), but there are locations + // with 10 and more functions, therefore there is a change that + // capacity of 2^4 is not enough in all cases. + lineCount []byte + lines []int32 + // Optional. + addr []int64 + folded []bool + + tmp []byte + buf bytes.Buffer +} + +func newLocationsEncoder() *symbolsEncoder[v1.InMemoryLocation] { + return newSymbolsEncoder[v1.InMemoryLocation](new(locationsBlockEncoder)) +} + +func (e *locationsBlockEncoder) format() SymbolsBlockFormat { return BlockLocationsV1 } + +func (e *locationsBlockEncoder) headerSize() uintptr { return unsafe.Sizeof(locationsBlockHeader{}) } + +func (e *locationsBlockEncoder) encode(w io.Writer, locations []v1.InMemoryLocation) error { + e.initWrite(len(locations)) + var addr uint64 + var folded bool + for i, loc := range locations { + e.mapping[i] = int32(loc.MappingId) + e.lineCount[i] = byte(len(loc.Line)) + for j := 0; j < len(loc.Line) && j < maxLocationLines; j++ { + e.lines = append(e.lines, + int32(loc.Line[j].FunctionId), + loc.Line[j].Line) + } + addr |= loc.Address + e.addr[i] = int64(loc.Address) + folded = folded || loc.IsFolded + e.folded[i] = loc.IsFolded + } + + // Mapping and line count per location. + var enc delta.BinaryPackedEncoding + e.tmp, _ = enc.EncodeInt32(e.tmp, e.mapping) + e.header.MappingSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + // Line count size and length is deterministic. + e.buf.Write(e.lineCount) // Without any encoding. + + // Lines slice size and length (in lines, not int32s). + e.tmp, _ = enc.EncodeInt32(e.tmp, e.lines) + e.header.LinesLen = uint32(len(e.lines) / 2) + e.header.LinesSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + + if addr > 0 { + e.tmp, _ = enc.EncodeInt64(e.tmp, e.addr) + e.header.AddrSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + } + + if folded { + e.tmp = slices.GrowLen(e.tmp, len(e.folded)/8+1) + encodeBoolean(e.tmp, e.folded) + e.header.IsFoldedSize = uint32(len(e.tmp)) + e.buf.Write(e.tmp) + } + + e.tmp = slices.GrowLen(e.tmp, int(e.headerSize())) + e.header.marshal(e.tmp) + if _, err := w.Write(e.tmp); err != nil { + return err + } + _, err := e.buf.WriteTo(w) + return err +} + +func (e *locationsBlockEncoder) initWrite(locations int) { + // Actual estimate is ~6 bytes per location. + // In a large data set, the most expensive member + // is FunctionID, and it's about 2 bytes per location. + e.buf.Reset() + e.buf.Grow(locations * 8) + *e = locationsBlockEncoder{ + header: locationsBlockHeader{LocationsLen: uint32(locations)}, + + mapping: slices.GrowLen(e.mapping, locations), + lineCount: slices.GrowLen(e.lineCount, locations), + lines: e.lines[:0], // Appendable. + addr: slices.GrowLen(e.addr, locations), + folded: slices.GrowLen(e.folded, locations), + + buf: e.buf, + tmp: slices.GrowLen(e.tmp, 2*locations), + } +} + +type locationsBlockDecoder struct { + headerSize uint16 + header locationsBlockHeader + + mappings []int32 + lineCount []byte + lines []int32 + + address []int64 + folded []bool + + buf []byte +} + +func newLocationsDecoder(h SymbolsBlockHeader) (*symbolsDecoder[v1.InMemoryLocation], error) { + if h.Format == BlockLocationsV1 { + headerSize := max(locationsBlockHeaderMinSize, h.BlockHeaderSize) + return newSymbolsDecoder[v1.InMemoryLocation](h, &locationsBlockDecoder{headerSize: headerSize}), nil + } + return nil, fmt.Errorf("%w: unknown locations format: %d", ErrUnknownVersion, h.Format) +} + +// In early versions, block header size is not specified. Must not change. +const locationsBlockHeaderMinSize = 28 + +func (d *locationsBlockDecoder) decode(r io.Reader, locations []v1.InMemoryLocation) (err error) { + d.buf = slices.GrowLen(d.buf, int(d.headerSize)) + if err = readSymbolsBlockHeader(d.buf, r, &d.header); err != nil { + return err + } + if d.header.LocationsLen != uint32(len(locations)) { + return fmt.Errorf("locations buffer: %w", ErrInvalidSize) + } + + // First we decode mapping_id and assign them to locations. + d.buf = slices.GrowLen(d.buf, int(d.header.MappingSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.mappings, err = decodeBinaryPackedInt32(d.mappings, d.buf, int(d.header.LocationsLen)) + if err != nil { + return err + } + + // Line count per location. + // One byte per location. + d.lineCount = slices.GrowLen(d.lineCount, int(d.header.LocationsLen)) + if _, err = io.ReadFull(r, d.lineCount); err != nil { + return err + } + + // Lines. A single slice backs all the location line + // sub-slices. But it has to be allocated as we can't + // reference d.lines, which is reusable. + lines := make([]v1.InMemoryLine, d.header.LinesLen) + d.buf = slices.GrowLen(d.buf, int(d.header.LinesSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + // Lines are encoded as pairs of uint32 (function_id and line number). + d.lines, err = decodeBinaryPackedInt32(d.lines, d.buf, int(d.header.LinesLen)*2) + if err != nil { + return err + } + copy(lines, *(*[]v1.InMemoryLine)(unsafe.Pointer(&d.lines))) + + // In most cases we end up here. + if d.header.AddrSize == 0 && d.header.IsFoldedSize == 0 { + var o int // Offset within the lines slice. + // In case if the block is malformed, an invalid + // line count may cause an out-of-bounds panic. + maxLines := len(lines) + for i := 0; i < len(locations); i++ { + locations[i].MappingId = uint32(d.mappings[i]) + n := o + int(d.lineCount[i]) + if n > maxLines { + return fmt.Errorf("%w: location lines out of bounds", ErrInvalidSize) + } + locations[i].Line = lines[o:n] + o = n + } + return nil + } + + // Otherwise, inspect all the optional fields. + d.address = slices.GrowLen(d.address, int(d.header.LocationsLen)) + d.folded = slices.GrowLen(d.folded, int(d.header.LocationsLen)) + if int(d.header.AddrSize) > 0 { + d.buf = slices.GrowLen(d.buf, int(d.header.AddrSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.address, err = decodeBinaryPackedInt64(d.address, d.buf, int(d.header.LocationsLen)) + if err != nil { + return err + } + } + if int(d.header.IsFoldedSize) > 0 { + d.buf = slices.GrowLen(d.buf, int(d.header.IsFoldedSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + decodeBoolean(d.folded, d.buf) + } + + var o int // Offset within the lines slice. + for i := uint32(0); i < d.header.LocationsLen; i++ { + locations[i].MappingId = uint32(d.mappings[i]) + n := o + int(d.lineCount[i]) + locations[i].Line = lines[o:n] + o = n + locations[i].Address = uint64(d.address[i]) + locations[i].IsFolded = d.folded[i] + } + + return nil +} + +func encodeBoolean(dst []byte, src []bool) { + for i := range dst { + dst[i] = 0 + } + for i, b := range src { + if b { + dst[i>>3] |= 1 << i & 7 + } + } +} + +func decodeBoolean(dst []bool, src []byte) { + for i := range dst { + dst[i] = false + } + for i := range dst { + dst[i] = src[i>>3]&(1< uint32(len(mappings)) { + return fmt.Errorf("mappings buffer is too short") + } + + d.ints = slices.GrowLen(d.ints, int(d.header.MappingsLen)) + + d.buf = slices.GrowLen(d.buf, int(d.header.FileNameSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints, err = decodeBinaryPackedInt32(d.ints, d.buf, int(d.header.MappingsLen)) + if err != nil { + return err + } + for i, v := range d.ints { + mappings[i].Filename = uint32(v) + } + + d.buf = slices.GrowLen(d.buf, int(d.header.BuildIDSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints, err = decodeBinaryPackedInt32(d.ints, d.buf, int(d.header.MappingsLen)) + if err != nil { + return err + } + for i, v := range d.ints { + mappings[i].BuildId = uint32(v) + } + + d.buf = slices.GrowLen(d.buf, int(d.header.FlagsSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints, err = decodeBinaryPackedInt32(d.ints, d.buf, int(d.header.MappingsLen)) + if err != nil { + return err + } + for i, v := range d.ints { + mappings[i].HasFunctions = v&(1<<3) > 0 + mappings[i].HasFilenames = v&(1<<2) > 0 + mappings[i].HasLineNumbers = v&(1<<1) > 0 + mappings[i].HasInlineFrames = v&1 > 0 + } + + if d.header.MemoryStartSize > 0 { + d.buf = slices.GrowLen(d.buf, int(d.header.MemoryStartSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints64, err = decodeBinaryPackedInt64(d.ints64, d.buf, int(d.header.MappingsLen)) + if err != nil { + return err + } + for i, v := range d.ints64 { + mappings[i].MemoryStart = uint64(v) + } + } + if d.header.MemoryLimitSize > 0 { + d.buf = slices.GrowLen(d.buf, int(d.header.MemoryLimitSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints64, err = decodeBinaryPackedInt64(d.ints64, d.buf, int(d.header.MappingsLen)) + if err != nil { + return err + } + for i, v := range d.ints64 { + mappings[i].MemoryLimit = uint64(v) + } + } + if d.header.FileOffsetSize > 0 { + d.buf = slices.GrowLen(d.buf, int(d.header.FileOffsetSize)) + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + d.ints64, err = decodeBinaryPackedInt64(d.ints64, d.buf, int(d.header.MappingsLen)) + if err != nil { + return err + } + for i, v := range d.ints64 { + mappings[i].FileOffset = uint64(v) + } + } + + return nil +} diff --git a/pkg/phlaredb/symdb/mappings_test.go b/pkg/phlaredb/symdb/mappings_test.go new file mode 100644 index 0000000000..4eb11aba38 --- /dev/null +++ b/pkg/phlaredb/symdb/mappings_test.go @@ -0,0 +1,109 @@ +package symdb + +import ( + "bytes" + "math" + "testing" + + "github.com/stretchr/testify/require" + + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +func Test_MappingsEncoding(t *testing.T) { + type testCase struct { + description string + mappings []v1.InMemoryMapping + } + + testCases := []testCase{ + { + description: "empty", + mappings: []v1.InMemoryMapping{}, + }, + { + description: "zero", + mappings: []v1.InMemoryMapping{{}}, + }, + { + description: "single mapping", + mappings: []v1.InMemoryMapping{ + { + MemoryStart: math.MaxUint64, + MemoryLimit: math.MaxUint64, + FileOffset: math.MaxUint64, + Filename: 1, + BuildId: 2, + HasFunctions: true, + HasFilenames: false, + HasLineNumbers: false, + HasInlineFrames: false, + }, + }, + }, + { + description: "optional fields mix", + mappings: []v1.InMemoryMapping{ + // Block size == 3 + {MemoryStart: math.MaxUint64}, + {}, + {}, + + {}, + {MemoryLimit: math.MaxUint64}, + {}, + + {}, + {}, + {FileOffset: math.MaxUint64}, + + {MemoryStart: math.MaxUint64}, + {MemoryLimit: math.MaxUint64}, + {FileOffset: math.MaxUint64}, + + {}, + {}, + {}, + }, + }, + { + description: "flag combinations", + mappings: []v1.InMemoryMapping{ + {HasFunctions: false, HasFilenames: false, HasLineNumbers: false, HasInlineFrames: false}, + {HasFunctions: false, HasFilenames: false, HasLineNumbers: false, HasInlineFrames: true}, + {HasFunctions: false, HasFilenames: false, HasLineNumbers: true, HasInlineFrames: false}, + {HasFunctions: false, HasFilenames: false, HasLineNumbers: true, HasInlineFrames: true}, + {HasFunctions: false, HasFilenames: true, HasLineNumbers: false, HasInlineFrames: false}, + {HasFunctions: false, HasFilenames: true, HasLineNumbers: false, HasInlineFrames: true}, + {HasFunctions: false, HasFilenames: true, HasLineNumbers: true, HasInlineFrames: false}, + {HasFunctions: false, HasFilenames: true, HasLineNumbers: true, HasInlineFrames: true}, + {HasFunctions: true, HasFilenames: false, HasLineNumbers: false, HasInlineFrames: false}, + {HasFunctions: true, HasFilenames: false, HasLineNumbers: false, HasInlineFrames: true}, + {HasFunctions: true, HasFilenames: false, HasLineNumbers: true, HasInlineFrames: false}, + {HasFunctions: true, HasFilenames: false, HasLineNumbers: true, HasInlineFrames: true}, + {HasFunctions: true, HasFilenames: true, HasLineNumbers: false, HasInlineFrames: false}, + {HasFunctions: true, HasFilenames: true, HasLineNumbers: false, HasInlineFrames: true}, + {HasFunctions: true, HasFilenames: true, HasLineNumbers: true, HasInlineFrames: false}, + {HasFunctions: true, HasFilenames: true, HasLineNumbers: true, HasInlineFrames: true}, + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + w := newTestFileWriter(&buf) + e := newMappingsEncoder() + e.blockSize = 3 + h, err := writeSymbolsBlock(w, tc.mappings, e) + require.NoError(t, err) + + d, err := newMappingsDecoder(h) + require.NoError(t, err) + out := make([]v1.InMemoryMapping, h.Length) + require.NoError(t, d.decode(out, &buf)) + require.Equal(t, tc.mappings, out) + }) + } +} diff --git a/pkg/phlaredb/symdb/partition_memory.go b/pkg/phlaredb/symdb/partition_memory.go index 0a127fcff5..ab687b297b 100644 --- a/pkg/phlaredb/symdb/partition_memory.go +++ b/pkg/phlaredb/symdb/partition_memory.go @@ -5,17 +5,17 @@ import ( "io" "sync" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) type PartitionWriter struct { header PartitionHeader - stacktraces *stacktracesPartition + stacktraces *stacktraces strings deduplicatingSlice[string, string, *stringsHelper] - mappings deduplicatingSlice[*schemav1.InMemoryMapping, mappingsKey, *mappingsHelper] - functions deduplicatingSlice[*schemav1.InMemoryFunction, functionsKey, *functionsHelper] - locations deduplicatingSlice[*schemav1.InMemoryLocation, locationsKey, *locationsHelper] + mappings deduplicatingSlice[schemav1.InMemoryMapping, mappingsKey, *mappingsHelper] + functions deduplicatingSlice[schemav1.InMemoryFunction, functionsKey, *functionsHelper] + locations deduplicatingSlice[schemav1.InMemoryLocation, locationsKey, *locationsHelper] } func (p *PartitionWriter) AppendStacktraces(dst []uint32, s []*schemav1.Stacktrace) { @@ -23,98 +23,44 @@ func (p *PartitionWriter) AppendStacktraces(dst []uint32, s []*schemav1.Stacktra } func (p *PartitionWriter) ResolveStacktraceLocations(_ context.Context, dst StacktraceInserter, stacktraces []uint32) error { - // TODO(kolesnikovae): Add option to do resolve concurrently. - // Depends on StacktraceInserter implementation. if len(stacktraces) == 0 { return nil } return p.stacktraces.resolve(dst, stacktraces) } -func (p *PartitionWriter) ResolveChunk(dst StacktraceInserter, sr StacktracesRange) error { - return p.stacktraces.ResolveChunk(dst, sr) -} - func (p *PartitionWriter) LookupLocations(dst []uint64, stacktraceID uint32) []uint64 { dst = dst[:0] - if len(p.stacktraces.chunks) == 0 { - return dst - } - chunkID := stacktraceID / p.stacktraces.maxNodesPerChunk - localSID := stacktraceID % p.stacktraces.maxNodesPerChunk - if localSID == 0 || int(chunkID) > len(p.stacktraces.chunks) { + if stacktraceID == 0 { return dst } - return p.stacktraces.chunks[chunkID].tree.resolveUint64(dst, localSID) + return p.stacktraces.tree.resolveUint64(dst, stacktraceID) } -type stacktracesPartition struct { - maxNodesPerChunk uint32 +func newStacktraces() *stacktraces { + p := &stacktraces{ + hashToIdx: make(map[uint64]uint32), + tree: newStacktraceTree(defaultStacktraceTreeSize), + } + return p +} +type stacktraces struct { m sync.RWMutex hashToIdx map[uint64]uint32 - chunks []*stacktraceChunk - header []StacktraceChunkHeader -} - -func newStacktracesPartition(maxNodesPerChunk uint32) *stacktracesPartition { - p := &stacktracesPartition{ - maxNodesPerChunk: maxNodesPerChunk, - hashToIdx: make(map[uint64]uint32, defaultStacktraceTreeSize/2), - } - p.chunks = append(p.chunks, &stacktraceChunk{ - tree: newStacktraceTree(defaultStacktraceTreeSize), - partition: p, - }) - return p + tree *stacktraceTree + stacks uint32 } -func (p *stacktracesPartition) size() uint64 { +func (p *stacktraces) size() uint64 { p.m.RLock() // TODO: map footprint isn't accounted - v := len(p.header) * stacktraceChunkHeaderSize - for _, c := range p.chunks { - v += stacktraceTreeNodeSize * cap(c.tree.nodes) - } + v := stacktraceTreeNodeSize * cap(p.tree.nodes) p.m.RUnlock() return uint64(v) } -// stacktraceChunkForInsert returns a chunk for insertion: -// if the existing one has capacity, or a new one, if the former is full. -// Must be called with the stracktraces mutex write lock held. -func (p *stacktracesPartition) stacktraceChunkForInsert(x int) *stacktraceChunk { - c := p.currentStacktraceChunk() - if n := c.tree.len() + uint32(x); p.maxNodesPerChunk > 0 && n >= p.maxNodesPerChunk { - // Calculate number of stacks in the chunk. - s := uint32(len(p.hashToIdx)) - c.stacks = s - c.stacks - c = &stacktraceChunk{ - partition: p, - tree: newStacktraceTree(defaultStacktraceTreeSize), - stid: c.stid + p.maxNodesPerChunk, - stacks: s, - } - p.chunks = append(p.chunks, c) - } - return c -} - -// stacktraceChunkForRead returns a chunk for reads. -// Must be called with the stracktraces mutex read lock held. -func (p *stacktracesPartition) stacktraceChunkForRead(i int) (*stacktraceChunk, bool) { - if i < len(p.chunks) { - return p.chunks[i], true - } - return nil, false -} - -func (p *stacktracesPartition) currentStacktraceChunk() *stacktraceChunk { - // Assuming there is at least one chunk. - return p.chunks[len(p.chunks)-1] -} - -func (p *stacktracesPartition) append(dst []uint32, s []*schemav1.Stacktrace) { +func (p *stacktraces) append(dst []uint32, s []*schemav1.Stacktrace) { if len(s) == 0 { return } @@ -150,29 +96,16 @@ func (p *stacktracesPartition) append(dst []uint32, s []*schemav1.Stacktrace) { p.m.Lock() defer p.m.Unlock() - chunk := p.currentStacktraceChunk() - - m := int(p.maxNodesPerChunk) - t, j := chunk.tree, chunk.stid for i, v := range dst[:len(s)] { if v != 0 { // Already resolved. ID 0 is reserved // as it is the tree root. continue } - x := s[i].LocationIDs - if m > 0 && len(t.nodes)+len(x) >= m { - // If we're close to the max nodes limit and can - // potentially exceed it, we take the next chunk, - // even if there are some space. - chunk = p.stacktraceChunkForInsert(len(x)) - t, j = chunk.tree, chunk.stid - } - // Tree insertion is idempotent, // we don't need to check the map. - id = t.insert(x) + j + id = p.tree.insert(x) h := hashLocations(x) p.hashToIdx[h] = id dst[i] = id @@ -195,30 +128,9 @@ func (p *stacktraceLocationsPool) put(x []int32) { stacktraceLocations.Put(x) } -func (p *stacktracesPartition) resolve(dst StacktraceInserter, stacktraces []uint32) (err error) { - for _, sr := range SplitStacktraces(stacktraces, p.maxNodesPerChunk) { - if err = p.ResolveChunk(dst, sr); err != nil { - return err - } - } - return nil -} - -// NOTE(kolesnikovae): -// Caller is able to split a range of stacktrace IDs into chunks -// with SplitStacktraces, and then resolve them concurrently: -// StacktraceInserter could be implemented as a dense set, map, -// slice, or an n-ary tree: the stacktraceTree should be one of -// the options, the package provides. - -func (p *stacktracesPartition) ResolveChunk(dst StacktraceInserter, sr StacktracesRange) error { +func (p *stacktraces) resolve(dst StacktraceInserter, stacktraces []uint32) (err error) { p.m.RLock() - c, found := p.stacktraceChunkForRead(int(sr.chunk)) - if !found { - p.m.RUnlock() - return ErrInvalidStacktraceRange - } - t := stacktraceTree{nodes: c.tree.nodes} + t := stacktraceTree{nodes: p.tree.nodes} // tree.resolve is thread safe: only the parent node index (p) // and the reference to location (r) node fields are accessed, // which are never modified after insertion. @@ -229,97 +141,27 @@ func (p *stacktracesPartition) ResolveChunk(dst StacktraceInserter, sr Stacktrac // the call. p.m.RUnlock() s := stacktraceLocations.get() - // Restore the original stacktrace ID. - off := sr.offset() - for _, sid := range sr.ids { + for _, sid := range stacktraces { s = t.resolve(s, sid) - dst.InsertStacktrace(off+sid, s) + dst.InsertStacktrace(sid, s) } stacktraceLocations.put(s) return nil } -type stacktraceChunk struct { - partition *stacktracesPartition - tree *stacktraceTree - stid uint32 // Initial stack trace ID. - stacks uint32 // -} - -func (s *stacktraceChunk) WriteTo(dst io.Writer) (int64, error) { - return s.tree.WriteTo(dst) -} - -type StacktracesRange struct { - ids []uint32 - chunk uint32 // Chunk index. - m uint32 // Max nodes per chunk. -} - -func (r StacktracesRange) offset() uint32 { return r.m * r.chunk } - -// SplitStacktraces splits the range of stack trace IDs by limit n into -// sub-ranges matching to the corresponding chunks and shifts the values -// accordingly. Note that the input s is modified in place. -// -// stack trace ID 0 is reserved and is not expected at the input. -// stack trace ID % max_nodes == 0 is not expected as well. -func SplitStacktraces(s []uint32, n uint32) []StacktracesRange { - if s[len(s)-1] < n || n == 0 { - // Fast path, just one chunk: the highest stack trace ID - // is less than the chunk size, or the size is not limited. - // It's expected that in most cases we'll end up here. - return []StacktracesRange{{m: n, ids: s}} - } - - var ( - loi int - lov = (s[0] / n) * n // Lowest possible value for the current chunk. - hiv = lov + n // Highest possible value for the current chunk. - p uint32 // Previous value (to derive chunk index). - // 16 chunks should be more than enough in most cases. - cs = make([]StacktracesRange, 0, 16) - ) - - for i, v := range s { - if v < hiv { - // The stack belongs to the current chunk. - s[i] -= lov - p = v - continue - } - lov = (v / n) * n - hiv = lov + n - s[i] -= lov - cs = append(cs, StacktracesRange{ - chunk: p / n, - ids: s[loi:i], - m: n, - }) - loi = i - p = v - } - - if t := s[loi:]; len(t) > 0 { - cs = append(cs, StacktracesRange{ - chunk: p / n, - ids: t, - m: n, - }) - } - - return cs +func (p *stacktraces) WriteTo(dst io.Writer) (int64, error) { + return p.tree.WriteTo(dst) } -func (p *PartitionWriter) AppendLocations(dst []uint32, locations []*schemav1.InMemoryLocation) { +func (p *PartitionWriter) AppendLocations(dst []uint32, locations []schemav1.InMemoryLocation) { p.locations.append(dst, locations) } -func (p *PartitionWriter) AppendMappings(dst []uint32, mappings []*schemav1.InMemoryMapping) { +func (p *PartitionWriter) AppendMappings(dst []uint32, mappings []schemav1.InMemoryMapping) { p.mappings.append(dst, mappings) } -func (p *PartitionWriter) AppendFunctions(dst []uint32, functions []*schemav1.InMemoryFunction) { +func (p *PartitionWriter) AppendFunctions(dst []uint32, functions []schemav1.InMemoryFunction) { p.functions.append(dst, functions) } @@ -339,8 +181,7 @@ func (p *PartitionWriter) Symbols() *Symbols { func (p *PartitionWriter) WriteStats(s *PartitionStats) { p.stacktraces.m.RLock() - c := p.stacktraces.currentStacktraceChunk() - s.MaxStacktraceID = int(c.stid + c.tree.len()) + s.MaxStacktraceID = int(p.stacktraces.tree.len()) s.StacktracesTotal = len(p.stacktraces.hashToIdx) p.stacktraces.m.RUnlock() diff --git a/pkg/phlaredb/symdb/partition_memory_test.go b/pkg/phlaredb/symdb/partition_memory_test.go index 5820852115..a03eb288ca 100644 --- a/pkg/phlaredb/symdb/partition_memory_test.go +++ b/pkg/phlaredb/symdb/partition_memory_test.go @@ -9,152 +9,23 @@ import ( "github.com/stretchr/testify/require" googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/pprof" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) -func Test_StacktraceAppender_shards(t *testing.T) { - t.Run("WithMaxStacktraceTreeNodesPerChunk", func(t *testing.T) { - db := NewSymDB(&Config{ - Stacktraces: StacktracesConfig{ - MaxNodesPerChunk: 7, - }, - }) - - w := db.PartitionWriter(0) - sids := make([]uint32, 4) - w.AppendStacktraces(sids, []*schemav1.Stacktrace{ - {LocationIDs: []uint64{3, 2, 1}}, - {LocationIDs: []uint64{2, 1}}, - {LocationIDs: []uint64{4, 3, 2, 1}}, - {LocationIDs: []uint64{3, 1}}, - }) - assert.Equal(t, []uint32{3, 2, 11, 16}, sids) - - w.AppendStacktraces(sids[:3], []*schemav1.Stacktrace{ - {LocationIDs: []uint64{3, 2, 1}}, - {LocationIDs: []uint64{2, 1}}, - {LocationIDs: []uint64{4, 3, 2, 1}}, - }) - // Same input. Note that len(sids) > len(schemav1.Stacktrace) - assert.Equal(t, []uint32{3, 2, 11}, sids[:3]) - - w.AppendStacktraces(sids[:1], []*schemav1.Stacktrace{ - {LocationIDs: []uint64{5, 2, 1}}, - }) - assert.Equal(t, []uint32{18}, sids[:1]) - - require.Len(t, db.partitions, 1) - m := db.partitions[0] - require.Len(t, m.stacktraces.chunks, 3) - - c1 := m.stacktraces.chunks[0] - assert.Equal(t, uint32(0), c1.stid) - assert.Equal(t, uint32(4), c1.tree.len()) - - c2 := m.stacktraces.chunks[1] - assert.Equal(t, uint32(7), c2.stid) - assert.Equal(t, uint32(5), c2.tree.len()) - - c3 := m.stacktraces.chunks[2] - assert.Equal(t, uint32(14), c3.stid) - assert.Equal(t, uint32(5), c3.tree.len()) - }) - - t.Run("WithoutMaxStacktraceTreeNodesPerChunk", func(t *testing.T) { - db := NewSymDB(new(Config)) - w := db.PartitionWriter(0) - sids := make([]uint32, 5) - w.AppendStacktraces(sids, []*schemav1.Stacktrace{ - {LocationIDs: []uint64{3, 2, 1}}, - {LocationIDs: []uint64{2, 1}}, - {LocationIDs: []uint64{4, 3, 2, 1}}, - {LocationIDs: []uint64{3, 1}}, - {LocationIDs: []uint64{5, 3, 2, 1}}, - }) - assert.Equal(t, []uint32{3, 2, 4, 5, 6}, sids) - - require.Len(t, db.partitions, 1) - m := db.partitions[0] - require.Len(t, m.stacktraces.chunks, 1) - - c1 := m.stacktraces.chunks[0] - assert.Equal(t, uint32(0), c1.stid) - assert.Equal(t, uint32(7), c1.tree.len()) - }) -} +func Test_Stacktrace_append_empty(t *testing.T) { + db := NewSymDB(new(Config)) + w := db.PartitionWriter(0) -func Test_StacktraceResolver_stacktraces_split(t *testing.T) { - type testCase struct { - description string - maxNodes uint32 - stacktraces []uint32 - expected []StacktracesRange - } + sids := make([]uint32, 2) + w.AppendStacktraces(sids, nil) + assert.Equal(t, []uint32{0, 0}, sids) - testCases := []testCase{ - { - description: "no limit", - stacktraces: []uint32{234, 1234, 2345}, - expected: []StacktracesRange{ - {ids: []uint32{234, 1234, 2345}}, - }, - }, - { - description: "one chunk", - maxNodes: 4, - stacktraces: []uint32{1, 2, 3}, - expected: []StacktracesRange{ - {m: 4, chunk: 0, ids: []uint32{1, 2, 3}}, - }, - }, - { - description: "one chunk shifted", - maxNodes: 4, - stacktraces: []uint32{401, 402}, - expected: []StacktracesRange{ - {m: 4, chunk: 100, ids: []uint32{1, 2}}, - }, - }, - { - description: "multiple shards", - maxNodes: 4, - stacktraces: []uint32{1, 2, 5, 7, 11, 13, 14, 15, 17, 41, 42, 43, 83, 85, 86}, - // : []uint32{1, 2, 1, 3, 3, 1, 2, 3, 1, 1, 2, 3, 3, 1, 2}, - // : []uint32{0, 0, 1, 1, 2, 3, 3, 3, 4, 10, 10, 10, 20, 21, 21}, - expected: []StacktracesRange{ - {m: 4, chunk: 0, ids: []uint32{1, 2}}, - {m: 4, chunk: 1, ids: []uint32{1, 3}}, - {m: 4, chunk: 2, ids: []uint32{3}}, - {m: 4, chunk: 3, ids: []uint32{1, 2, 3}}, - {m: 4, chunk: 4, ids: []uint32{1}}, - {m: 4, chunk: 10, ids: []uint32{1, 2, 3}}, - {m: 4, chunk: 20, ids: []uint32{3}}, - {m: 4, chunk: 21, ids: []uint32{1, 2}}, - }, - }, - { - description: "multiple shards exact", - maxNodes: 4, - stacktraces: []uint32{1, 2, 5, 7, 11, 13, 14, 15, 17, 41, 42, 43, 83, 85, 86, 87}, - expected: []StacktracesRange{ - {m: 4, chunk: 0, ids: []uint32{1, 2}}, - {m: 4, chunk: 1, ids: []uint32{1, 3}}, - {m: 4, chunk: 2, ids: []uint32{3}}, - {m: 4, chunk: 3, ids: []uint32{1, 2, 3}}, - {m: 4, chunk: 4, ids: []uint32{1}}, - {m: 4, chunk: 10, ids: []uint32{1, 2, 3}}, - {m: 4, chunk: 20, ids: []uint32{3}}, - {m: 4, chunk: 21, ids: []uint32{1, 2, 3}}, - }, - }, - } + w.AppendStacktraces(sids, []*schemav1.Stacktrace{}) + assert.Equal(t, []uint32{0, 0}, sids) - for _, tc := range testCases { - t.Run(tc.description, func(t *testing.T) { - assert.Equal(t, tc.expected, SplitStacktraces(tc.stacktraces, tc.maxNodes)) - }) - } + w.AppendStacktraces(sids, []*schemav1.Stacktrace{{}}) + assert.Equal(t, []uint32{0, 0}, sids) } func Test_Stacktrace_append_existing(t *testing.T) { @@ -174,144 +45,6 @@ func Test_Stacktrace_append_existing(t *testing.T) { assert.Equal(t, []uint32{5, 6}, sids) } -func Test_Stacktrace_append_empty(t *testing.T) { - db := NewSymDB(new(Config)) - w := db.PartitionWriter(0) - - sids := make([]uint32, 2) - w.AppendStacktraces(sids, nil) - assert.Equal(t, []uint32{0, 0}, sids) - - w.AppendStacktraces(sids, []*schemav1.Stacktrace{}) - assert.Equal(t, []uint32{0, 0}, sids) - - w.AppendStacktraces(sids, []*schemav1.Stacktrace{{}}) - assert.Equal(t, []uint32{0, 0}, sids) -} - -func Test_Stacktraces_append_resolve(t *testing.T) { - ctx := context.Background() - - t.Run("single chunk", func(t *testing.T) { - db := NewSymDB(new(Config)) - w := db.PartitionWriter(0) - - sids := make([]uint32, 5) - w.AppendStacktraces(sids, []*schemav1.Stacktrace{ - {LocationIDs: []uint64{3, 2, 1}}, - {LocationIDs: []uint64{2, 1}}, - {LocationIDs: []uint64{4, 3, 2, 1}}, - {LocationIDs: []uint64{3, 1}}, - {LocationIDs: []uint64{5, 2, 1}}, - }) - - r, ok := db.lookupPartition(0) - require.True(t, ok) - dst := new(mockStacktraceInserter) - dst.On("InsertStacktrace", uint32(2), []int32{2, 1}) - dst.On("InsertStacktrace", uint32(3), []int32{3, 2, 1}) - dst.On("InsertStacktrace", uint32(4), []int32{4, 3, 2, 1}) - dst.On("InsertStacktrace", uint32(5), []int32{3, 1}) - dst.On("InsertStacktrace", uint32(6), []int32{5, 2, 1}) - require.NoError(t, r.ResolveStacktraceLocations(ctx, dst, []uint32{2, 3, 4, 5, 6})) - }) - - t.Run("multiple chunks", func(t *testing.T) { - db := NewSymDB(&Config{ - Stacktraces: StacktracesConfig{ - MaxNodesPerChunk: 7, - }, - }) - - w := db.PartitionWriter(0) - stacktraces := []*schemav1.Stacktrace{ // ID, Chunk ID: - {LocationIDs: []uint64{3, 2, 1}}, // 3 0 - {LocationIDs: []uint64{2, 1}}, // 2 0 - {LocationIDs: []uint64{4, 3, 2, 1}}, // 11 1 - {LocationIDs: []uint64{3, 1}}, // 16 2 - {LocationIDs: []uint64{5, 2, 1}}, // 18 2 - {LocationIDs: []uint64{13, 12, 11}}, // 24 3 - {LocationIDs: []uint64{12, 11}}, // 23 3 - {LocationIDs: []uint64{14, 13, 12, 11}}, // 32 4 - {LocationIDs: []uint64{13, 11}}, // 37 5 - {LocationIDs: []uint64{15, 12, 11}}, // 39 5 - } - /* - // TODO(kolesnikovae): Add test cases: - // Invariants: - // 0 - // 1 - // 1 0 - // 2 - // 2 0 - // 2 1 - // 2 1 0 - // 3 - // 3 0 - // 3 1 - // 3 1 0 - // 3 2 - // 3 2 0 - // 3 2 1 - // 3 2 1 0 - */ - sids := make([]uint32, len(stacktraces)) - w.AppendStacktraces(sids, stacktraces) - require.Len(t, db.partitions[0].stacktraces.chunks, 6) - - t.Run("adjacent shards at beginning", func(t *testing.T) { - r, _ := db.lookupPartition(0) - dst := new(mockStacktraceInserter) - dst.On("InsertStacktrace", uint32(2), []int32{2, 1}) - dst.On("InsertStacktrace", uint32(3), []int32{3, 2, 1}) - dst.On("InsertStacktrace", uint32(11), []int32{4, 3, 2, 1}) - dst.On("InsertStacktrace", uint32(16), []int32{3, 1}) - dst.On("InsertStacktrace", uint32(18), []int32{5, 2, 1}) - require.NoError(t, r.ResolveStacktraceLocations(ctx, dst, []uint32{2, 3, 11, 16, 18})) - }) - - t.Run("adjacent shards at end", func(t *testing.T) { - r, _ := db.lookupPartition(0) - dst := new(mockStacktraceInserter) - dst.On("InsertStacktrace", uint32(23), []int32{12, 11}) - dst.On("InsertStacktrace", uint32(24), []int32{13, 12, 11}) - dst.On("InsertStacktrace", uint32(32), []int32{14, 13, 12, 11}) - dst.On("InsertStacktrace", uint32(37), []int32{13, 11}) - dst.On("InsertStacktrace", uint32(39), []int32{15, 12, 11}) - require.NoError(t, r.ResolveStacktraceLocations(ctx, dst, []uint32{23, 24, 32, 37, 39})) - }) - - t.Run("non-adjacent shards", func(t *testing.T) { - r, _ := db.lookupPartition(0) - dst := new(mockStacktraceInserter) - dst.On("InsertStacktrace", uint32(11), []int32{4, 3, 2, 1}) - dst.On("InsertStacktrace", uint32(32), []int32{14, 13, 12, 11}) - require.NoError(t, r.ResolveStacktraceLocations(ctx, dst, []uint32{11, 32})) - }) - }) -} - -func Test_hashLocations(t *testing.T) { - t.Run("hashLocations is thread safe", func(t *testing.T) { - b := []uint64{123, 234, 345, 456, 567} - h := hashLocations(b) - const N, M = 10, 10 << 10 - var wg sync.WaitGroup - wg.Add(N) - for i := 0; i < N; i++ { - go func() { - defer wg.Done() - for j := 0; j < M; j++ { - if hashLocations(b) != h { - panic("hash mismatch") - } - } - }() - } - wg.Wait() - }) -} - func Test_Stacktraces_memory_resolve_pprof(t *testing.T) { p, err := pprof.OpenFile("testdata/profile.pb.gz") require.NoError(t, err) @@ -338,12 +71,7 @@ func Test_Stacktraces_memory_resolve_chunked(t *testing.T) { stacktraces := pprofSampleToStacktrace(p.Sample) sids := make([]uint32, len(stacktraces)) - cfg := &Config{ - Stacktraces: StacktracesConfig{ - MaxNodesPerChunk: 256, - }, - } - db := NewSymDB(cfg) + db := NewSymDB(new(Config)) w := db.PartitionWriter(0) w.AppendStacktraces(sids, stacktraces) @@ -369,15 +97,9 @@ func Test_Stacktraces_memory_resolve_concurrency(t *testing.T) { require.NoError(t, err) stacktraces := pprofSampleToStacktrace(p.Sample) - cfg := &Config{ - Stacktraces: StacktracesConfig{ - MaxNodesPerChunk: 256, - }, - } - // Allocate stacktrace IDs. sids := make([]uint32, len(stacktraces)) - db := NewSymDB(cfg) + db := NewSymDB(new(Config)) w := db.PartitionWriter(0) w.AppendStacktraces(sids, stacktraces) @@ -390,7 +112,7 @@ func Test_Stacktraces_memory_resolve_concurrency(t *testing.T) { runTest := func(t *testing.T) { t.Helper() - db := NewSymDB(cfg) + db := NewSymDB(new(Config)) var wg sync.WaitGroup wg.Add(appenders) diff --git a/pkg/phlaredb/symdb/resolver.go b/pkg/phlaredb/symdb/resolver.go index 6049ed0528..1afecf3387 100644 --- a/pkg/phlaredb/symdb/resolver.go +++ b/pkg/phlaredb/symdb/resolver.go @@ -5,15 +5,17 @@ import ( "runtime" "sync" - "github.com/opentracing/opentracing-go" + "github.com/grafana/dskit/tracing" "github.com/parquet-go/parquet-go" "golang.org/x/sync/errgroup" googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/model" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/util" ) // Resolver converts stack trace samples to one of the profile @@ -26,7 +28,7 @@ import ( type Resolver struct { ctx context.Context cancel context.CancelFunc - span opentracing.Span + span *tracing.Span s SymbolsReader g *errgroup.Group @@ -34,8 +36,9 @@ type Resolver struct { m sync.RWMutex p map[uint64]*lazyPartition - maxNodes int64 - sts *typesv1.StackTraceSelector + maxNodes int64 + sts *typesv1.StackTraceSelector + sanitizeOnMerge bool } type ResolverOption func(*Resolver) @@ -66,11 +69,17 @@ func WithResolverStackTraceSelector(sts *typesv1.StackTraceSelector) ResolverOpt } } +func WithResolverSanitizeOnMerge(sanitizeOnMerge bool) ResolverOption { + return func(r *Resolver) { + r.sanitizeOnMerge = sanitizeOnMerge + } +} + type lazyPartition struct { id uint64 m sync.Mutex - samples map[uint32]int64 + samples *SampleAppender fetchOnce sync.Once resolver *Resolver @@ -98,7 +107,7 @@ func NewResolver(ctx context.Context, s SymbolsReader, opts ...ResolverOption) * for _, opt := range opts { opt(&r) } - r.span, r.ctx = opentracing.StartSpanFromContext(ctx, "NewResolver") + r.span, r.ctx = tracing.StartSpanFromContext(ctx, "NewResolver") r.ctx, r.cancel = context.WithCancel(r.ctx) r.g, r.ctx = errgroup.WithContext(r.ctx) return &r @@ -129,36 +138,68 @@ func (r *Resolver) Release() { // AddSamples adds a collection of stack trace samples to the resolver. // Samples can be added to partitions concurrently. func (r *Resolver) AddSamples(partition uint64, s schemav1.Samples) { - r.WithPartitionSamples(partition, func(samples map[uint32]int64) { + r.withPartitionSamples(partition, func(samples *SampleAppender) { + samples.AppendMany(s.StacktraceIDs, s.Values) + }) +} + +func (r *Resolver) AddSamplesWithSpanSelector(partition uint64, s schemav1.Samples, spanSelector model.SpanSelector) { + r.withPartitionSamples(partition, func(samples *SampleAppender) { for i, sid := range s.StacktraceIDs { - if sid > 0 { - samples[sid] += int64(s.Values[i]) + if _, ok := spanSelector[s.Spans[i]]; ok && sid > 0 { + samples.Append(sid, s.Values[i]) } } }) } func (r *Resolver) AddSamplesFromParquetRow(partition uint64, stacktraceIDs, values []parquet.Value) { - r.WithPartitionSamples(partition, func(samples map[uint32]int64) { + r.withPartitionSamples(partition, func(samples *SampleAppender) { for i, sid := range stacktraceIDs { if s := sid.Uint32(); s > 0 { - samples[s] += values[i].Int64() + samples.Append(s, values[i].Uint64()) } } }) } -func (r *Resolver) AddSamplesWithSpanSelector(partition uint64, s schemav1.Samples, spanSelector model.SpanSelector) { - r.WithPartitionSamples(partition, func(samples map[uint32]int64) { - for i, sid := range s.StacktraceIDs { - if _, ok := spanSelector[s.Spans[i]]; ok && sid > 0 { - samples[sid] += int64(s.Values[i]) +func (r *Resolver) AddSamplesWithSpanSelectorFromParquetRow(partition uint64, stacktraces, values, spans []parquet.Value, spanSelector model.SpanSelector) { + r.withPartitionSamples(partition, func(samples *SampleAppender) { + for i, sid := range stacktraces { + spanID := spans[i].Uint64() + stackID := sid.Uint32() + if spanID == 0 || stackID == 0 { + continue + } + if _, ok := spanSelector[spanID]; ok { + samples.Append(stackID, values[i].Uint64()) + } + } + }) +} + +func (r *Resolver) AddSamplesWithTraceSelectorFromParquetRow(partition uint64, stacktraces, values, traces []parquet.Value, traceSelector model.TraceSelector) { + r.withPartitionSamples(partition, func(samples *SampleAppender) { + for i, sid := range stacktraces { + stackID := sid.Uint32() + if stackID == 0 { + continue + } + b := traces[i].ByteArray() + if len(b) != len(model.TraceID{}) { + // Null (no trace id on this sample): cannot match. + continue + } + var t model.TraceID + copy(t[:], b) + if _, ok := traceSelector[t]; ok { + samples.Append(stackID, values[i].Uint64()) } } }) } -func (r *Resolver) WithPartitionSamples(partition uint64, fn func(map[uint32]int64)) { +func (r *Resolver) withPartitionSamples(partition uint64, fn func(*SampleAppender)) { p := r.partition(partition) p.m.Lock() defer p.m.Unlock() @@ -203,27 +244,71 @@ func (r *Resolver) partition(partition uint64) *lazyPartition { } p = &lazyPartition{ id: partition, - samples: make(map[uint32]int64), + samples: NewSampleAppender(), resolver: r, } r.p[partition] = p r.m.Unlock() // Fetch partition in the background, not blocking the caller. // p.reader must be accessed only after p.fetch returns. - r.g.Go(func() error { + r.g.Go(util.RecoverPanic(func() error { return p.fetch(r.ctx) - }) + })) // r.g.Wait() is called at Resolver.Release. return p } -func (r *Resolver) Tree() (*model.Tree, error) { - span, ctx := opentracing.StartSpanFromContext(r.ctx, "Resolver.Tree") +type ResultBuilder interface { + KeepSymbol(model.LocationRefName) model.LocationRefName + Build(*queryv1.TreeSymbols) +} + +func (r *Resolver) LocationRefNameTree() (*model.LocationRefNameTree, ResultBuilder, error) { + span, ctx := tracing.StartSpanFromContext(r.ctx, "Resolver.LocationRefNameTree") + defer span.Finish() + sym := NewSymbolMerger() + var lock sync.Mutex + tree := new(model.LocationRefNameTree) + err := r.withSymbols(ctx, func(symbols *Symbols, appender *SampleAppender) error { + locMap := make(map[uint32]struct{}) + lookup := func(locID int32) model.LocationRefName { + locMap[uint32(locID)] = struct{}{} + return model.LocationRefName(locID) + } + resolved, err := symbols.LocationRefNameTree(ctx, appender, r.maxNodes, SelectStackTraces(symbols, r.sts), lookup) + if err != nil { + return err + } + + locIDs := sortedList(locMap, nil) + + // merge symbols + cb, err := sym.addSymbols(symbols, locIDs) + if err != nil { + return err + } + resolved.FormatNodeNames(cb) + + lock.Lock() + tree.Merge(resolved) + lock.Unlock() + return nil + }) + tree.Total() + return tree, sym.ResultBuilder(), err +} + +func (r *Resolver) Tree() (*model.FunctionNameTree, error) { + span, ctx := tracing.StartSpanFromContext(r.ctx, "Resolver.Tree") defer span.Finish() var lock sync.Mutex - tree := new(model.Tree) - err := r.withSymbols(ctx, func(symbols *Symbols, samples schemav1.Samples) error { - resolved, err := symbols.Tree(ctx, samples, r.maxNodes) + + tree := new(model.FunctionNameTree) + err := r.withSymbols(ctx, func(symbols *Symbols, appender *SampleAppender) error { + lookup := func(i int32) model.FunctionName { + return model.FunctionName(symbols.Strings[i]) + } + resolved, err := symbols.Tree(ctx, appender, r.maxNodes, SelectStackTraces(symbols, r.sts), lookup) if err != nil { return err } @@ -236,18 +321,40 @@ func (r *Resolver) Tree() (*model.Tree, error) { } func (r *Resolver) Pprof() (*googlev1.Profile, error) { - span, ctx := opentracing.StartSpanFromContext(r.ctx, "Resolver.Pprof") + span, ctx := tracing.StartSpanFromContext(r.ctx, "Resolver.Pprof") defer span.Finish() - var lock sync.Mutex + + if r.canSkipProfileMerge() { + // this is the same as the block below, without the profile merge + var p *googlev1.Profile + err := r.withSymbols(ctx, func(symbols *Symbols, appender *SampleAppender) error { + resolved, err := symbols.Pprof(ctx, appender, r.maxNodes, SelectStackTraces(symbols, r.sts)) + if err != nil { + return err + } + p = resolved + return nil + }) + if err != nil { + return nil, err + } + if p == nil { // for consistency with the return value when using the merge path + return &googlev1.Profile{ + SampleType: []*googlev1.ValueType{new(googlev1.ValueType)}, + PeriodType: new(googlev1.ValueType), + StringTable: []string{""}, + }, nil + } + return p, nil + } + var p pprof.ProfileMerge - err := r.withSymbols(ctx, func(symbols *Symbols, samples schemav1.Samples) error { - resolved, err := symbols.Pprof(ctx, samples, r.maxNodes, SelectStackTraces(symbols, r.sts)) + err := r.withSymbols(ctx, func(symbols *Symbols, appender *SampleAppender) error { + resolved, err := symbols.Pprof(ctx, appender, r.maxNodes, SelectStackTraces(symbols, r.sts)) if err != nil { return err } - lock.Lock() - defer lock.Unlock() - return p.Merge(resolved) + return p.Merge(resolved, r.sanitizeOnMerge) }) if err != nil { return nil, err @@ -255,102 +362,58 @@ func (r *Resolver) Pprof() (*googlev1.Profile, error) { return p.Profile(), nil } -func (r *Resolver) withSymbols(ctx context.Context, fn func(*Symbols, schemav1.Samples) error) error { +func (r *Resolver) withSymbols(ctx context.Context, fn func(*Symbols, *SampleAppender) error) error { g, _ := errgroup.WithContext(ctx) g.SetLimit(r.c) for _, p := range r.p { p := p - g.Go(func() error { + g.Go(util.RecoverPanic(func() error { if err := p.fetch(ctx); err != nil { return err } - m := schemav1.NewSamplesFromMap(p.samples) - return fn(p.reader.Symbols(), m) - }) + return fn(p.reader.Symbols(), p.samples) + })) } return g.Wait() } -type pprofBuilder interface { - StacktraceInserter - init(*Symbols, schemav1.Samples) - buildPprof() *googlev1.Profile +func (r *Resolver) canSkipProfileMerge() bool { + if len(r.p) > 1 { + return false + } + if r.sts != nil && r.sts.GoPgo != nil && r.sts.GoPgo.AggregateCallees { + // we rely on merges to implement GoPgo.AggregateCallees + return false + } + + return true } func (r *Symbols) Pprof( ctx context.Context, - samples schemav1.Samples, + appender *SampleAppender, maxNodes int64, selection *SelectedStackTraces, ) (*googlev1.Profile, error) { - // By default, we use a builder that's optimized - // for the simplest case: we take all the source - // stack traces unchanged. - var b pprofBuilder = new(pprofProtoSymbols) - // If a stack trace selector is specified, - // check if such a profile can exist at all. - if !selection.IsValid() { - // Build an empty profile. - return b.buildPprof(), nil - } - // Truncation is applicable when there is an explicit - // limit on the number of the nodes in the profile, or - // if stack traces should be filtered. - if maxNodes > 0 || len(selection.callSite) > 0 { - b = &pprofProtoTruncatedSymbols{ - maxNodes: maxNodes, - selection: selection, - } - } - b.init(r, samples) - if err := r.Stacktraces.ResolveStacktraceLocations(ctx, b, samples.StacktraceIDs); err != nil { - return nil, err - } - return b.buildPprof(), nil + return buildPprof(ctx, r, appender.Samples(), maxNodes, selection) } func (r *Symbols) Tree( ctx context.Context, - samples schemav1.Samples, + appender *SampleAppender, maxNodes int64, -) (*model.Tree, error) { - t := treeSymbolsFromPool() - defer t.reset() - t.init(r, samples) - if err := r.Stacktraces.ResolveStacktraceLocations(ctx, t, samples.StacktraceIDs); err != nil { - return nil, err - } - return t.tree.Tree(maxNodes, t.symbols.Strings), nil + selection *SelectedStackTraces, + lookup func(int32) model.FunctionName, +) (*model.FunctionNameTree, error) { + return buildTree[model.FunctionName, model.FunctionNameI](ctx, r, appender, maxNodes, selection, lookup) } -// findCallSite returns the stack trace of the call site -// where each element in the stack trace is represented by -// the function ID. Call site is the last element. -// TODO(kolesnikovae): Location should also include the line number. -func findCallSite(symbols *Symbols, locations []*typesv1.Location) []uint32 { - if len(locations) == 0 { - return nil - } - m := make(map[string]uint32, len(locations)) - for _, loc := range locations { - m[loc.Name] = 0 - } - c := len(m) // Only count unique names. - for f := 0; f < len(symbols.Functions) && c > 0; f++ { - s := symbols.Strings[symbols.Functions[f].Name] - if _, ok := m[s]; ok { - // We assume that no functions have the same name. - // Otherwise, the last one takes precedence. - m[s] = uint32(f) // f is FunctionId - c-- - } - } - if c > 0 { - return nil - } - callSite := make([]uint32, len(locations)) - for i, loc := range locations { - callSite[i] = m[loc.Name] - } - return callSite +func (r *Symbols) LocationRefNameTree( + ctx context.Context, + appender *SampleAppender, + maxNodes int64, + selection *SelectedStackTraces, + lookup func(int32) model.LocationRefName, +) (*model.LocationRefNameTree, error) { + return buildTree[model.LocationRefName, model.LocationRefNameI](ctx, r, appender, maxNodes, selection, lookup) } diff --git a/pkg/phlaredb/symdb/resolver_pprof.go b/pkg/phlaredb/symdb/resolver_pprof.go index f6541c4d77..e90ed452b9 100644 --- a/pkg/phlaredb/symdb/resolver_pprof.go +++ b/pkg/phlaredb/symdb/resolver_pprof.go @@ -1,46 +1,51 @@ package symdb import ( + "context" + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/slices" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/slices" ) -type pprofProtoSymbols struct { - profile googlev1.Profile - symbols *Symbols - samples *schemav1.Samples - lut []uint32 - cur int -} - -func (r *pprofProtoSymbols) init(symbols *Symbols, samples schemav1.Samples) { - r.symbols = symbols - r.samples = &samples - r.profile.Sample = make([]*googlev1.Sample, samples.Len()) +type pprofBuilder interface { + StacktraceInserter + init(*Symbols, schemav1.Samples) + buildPprof() *googlev1.Profile } -func (r *pprofProtoSymbols) InsertStacktrace(_ uint32, locations []int32) { - s := &googlev1.Sample{ - LocationId: make([]uint64, len(locations)), - Value: []int64{int64(r.samples.Values[r.cur])}, +func buildPprof( + ctx context.Context, + symbols *Symbols, + samples schemav1.Samples, + maxNodes int64, + selection *SelectedStackTraces, +) (*googlev1.Profile, error) { + // By default, we use a builder that's optimized for the most + // basic case: we take all the source stack traces unchanged. + var b pprofBuilder = new(pprofFull) + switch { + // Go PGO selector; the stack traces are trimmed in the way + // that only the first KeepLocations are retained. Optionally, + // samples are aggregated by the callee, ignoring the leaf + // location line number. + case selection.gopgo != nil: + b = &pprofGoPGO{pgo: selection.gopgo} + // If a stack trace selector is specified, check if such a + // profile can exist. Otherwise, build an empty profile. + case !selection.HasValidCallSite(): + return b.buildPprof(), nil + // Truncation is applicable when there is an explicit + // limit on the number of the nodes in the profile, or + // if stack traces should be filtered by the call site. + case maxNodes > 0 || len(selection.callSite) > 0: + b = &pprofTree{maxNodes: maxNodes, selection: selection} } - for i, v := range locations { - s.LocationId[i] = uint64(v) - } - r.profile.Sample[r.cur] = s - r.cur++ -} - -func (r *pprofProtoSymbols) buildPprof() *googlev1.Profile { - createSampleTypeStub(&r.profile) - if r.symbols != nil { - copyLocations(&r.profile, r.symbols, r.lut) - copyFunctions(&r.profile, r.symbols, r.lut) - copyMappings(&r.profile, r.symbols, r.lut) - copyStrings(&r.profile, r.symbols, r.lut) + b.init(symbols, samples) + if err := symbols.Stacktraces.ResolveStacktraceLocations(ctx, b, samples.StacktraceIDs); err != nil { + return nil, err } - return &r.profile + return b.buildPprof(), nil } func createSampleTypeStub(profile *googlev1.Profile) { diff --git a/pkg/phlaredb/symdb/resolver_pprof_full.go b/pkg/phlaredb/symdb/resolver_pprof_full.go new file mode 100644 index 0000000000..aef40b6ede --- /dev/null +++ b/pkg/phlaredb/symdb/resolver_pprof_full.go @@ -0,0 +1,43 @@ +package symdb + +import ( + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +type pprofFull struct { + profile googlev1.Profile + symbols *Symbols + samples *schemav1.Samples + lut []uint32 + cur int +} + +func (r *pprofFull) init(symbols *Symbols, samples schemav1.Samples) { + r.symbols = symbols + r.samples = &samples + r.profile.Sample = make([]*googlev1.Sample, samples.Len()) +} + +func (r *pprofFull) InsertStacktrace(_ uint32, locations []int32) { + s := &googlev1.Sample{ + LocationId: make([]uint64, len(locations)), + Value: []int64{int64(r.samples.Values[r.cur])}, + } + for i, v := range locations { + s.LocationId[i] = uint64(v) + } + r.profile.Sample[r.cur] = s + r.cur++ +} + +func (r *pprofFull) buildPprof() *googlev1.Profile { + createSampleTypeStub(&r.profile) + if r.symbols != nil { + copyLocations(&r.profile, r.symbols, r.lut) + copyFunctions(&r.profile, r.symbols, r.lut) + copyMappings(&r.profile, r.symbols, r.lut) + copyStrings(&r.profile, r.symbols, r.lut) + } + return &r.profile +} diff --git a/pkg/phlaredb/symdb/resolver_pprof_go_pgo.go b/pkg/phlaredb/symdb/resolver_pprof_go_pgo.go new file mode 100644 index 0000000000..5fda7e50aa --- /dev/null +++ b/pkg/phlaredb/symdb/resolver_pprof_go_pgo.go @@ -0,0 +1,96 @@ +package symdb + +import ( + "strings" + "unsafe" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +type pprofGoPGO struct { + profile googlev1.Profile + symbols *Symbols + samples *schemav1.Samples + pgo *typesv1.GoPGO + stacks map[string]*googlev1.Sample + lut []uint32 + cur int +} + +func (r *pprofGoPGO) init(symbols *Symbols, samples schemav1.Samples) { + r.symbols = symbols + r.samples = &samples + // It's expected that after trimmed, most of + // the stack traces will be deduplicated. + r.stacks = make(map[string]*googlev1.Sample, samples.Len()/50) +} + +func (r *pprofGoPGO) InsertStacktrace(_ uint32, locations []int32) { + if len(locations) == 0 { + r.cur++ + return + } + if n := int(r.pgo.KeepLocations); n > 0 && len(locations) > n { + locations = locations[:n] + } + // Trimming implies that many samples will have the same + // stack trace (the expected value for keepLocs is 5). + // Therefore, the map is read-intensive: we speculatively + // reuse capacity of the locations slice as the key, and + // only copy it, if the insertion into the map is required. + k := int32sliceString(locations) + sample, ok := r.stacks[k] + if !ok { + sample = &googlev1.Sample{ + LocationId: make([]uint64, len(locations)), + Value: []int64{0}, + } + for i, v := range locations { + sample.LocationId[i] = uint64(v) + } + // Do not retain the input slice. + r.stacks[strings.Clone(k)] = sample + } + sample.Value[0] += int64(r.samples.Values[r.cur]) + r.cur++ +} + +func int32sliceString(u []int32) string { + return unsafe.String((*byte)(unsafe.Pointer(&u[0])), len(u)*4) +} + +func (r *pprofGoPGO) buildPprof() *googlev1.Profile { + createSampleTypeStub(&r.profile) + r.appendSamples() + if r.symbols != nil { + copyLocations(&r.profile, r.symbols, r.lut) + copyFunctions(&r.profile, r.symbols, r.lut) + copyMappings(&r.profile, r.symbols, r.lut) + copyStrings(&r.profile, r.symbols, r.lut) + } + if r.pgo.AggregateCallees { + // Actual aggregation occurs at pprof.Merge call after + // the profile is built. All unreferenced objects are + // to be removed from the profile, and samples with + // matching stack traces are to be merged. + r.clearCalleeLineNumber() + } + return &r.profile +} + +func (r *pprofGoPGO) appendSamples() { + r.profile.Sample = make([]*googlev1.Sample, len(r.stacks)) + var i int + for _, s := range r.stacks { + r.profile.Sample[i] = s + i++ + } +} + +func (r *pprofGoPGO) clearCalleeLineNumber() { + for _, s := range r.profile.Sample { + r.profile.Location[s.LocationId[0]-1].Line[0].Line = 0 + } +} diff --git a/pkg/phlaredb/symdb/resolver_pprof_test.go b/pkg/phlaredb/symdb/resolver_pprof_test.go index 207cf92ea3..6a4ee6515f 100644 --- a/pkg/phlaredb/symdb/resolver_pprof_test.go +++ b/pkg/phlaredb/symdb/resolver_pprof_test.go @@ -11,7 +11,7 @@ import ( googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - v1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) func Test_memory_Resolver_ResolvePprof(t *testing.T) { @@ -141,6 +141,79 @@ func Test_Pprof_subtree(t *testing.T) { require.Equal(t, expected, actual) } +func Test_Pprof_subtree_multiple_versions(t *testing.T) { + profile := &googlev1.Profile{ + StringTable: []string{"", "a", "b", "c", "d"}, + Function: []*googlev1.Function{ + {Id: 1, Name: 1}, // a + {Id: 2, Name: 2}, // b + {Id: 3, Name: 3}, // c + {Id: 4, Name: 4, StartLine: 1}, // d + {Id: 5, Name: 4, StartLine: 2}, // d(2) + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 1, Line: 1}}}, // a + {Id: 2, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 1}}}, // b:1 + {Id: 3, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 2}}}, // b:2 + {Id: 4, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 3, Line: 1}}}, // c + {Id: 5, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 4, Line: 1}}}, // d + {Id: 6, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 5, Line: 1}}}, // d(2) + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{5, 4, 2, 1}, Value: []int64{1}}, // a, b:1, c, d + {LocationId: []uint64{6, 4, 3, 1}, Value: []int64{1}}, // a, b:2, c, d(2) + {LocationId: []uint64{3, 1}, Value: []int64{1}}, // a, b:2 + {LocationId: []uint64{4, 1}, Value: []int64{1}}, // a, c + {LocationId: []uint64{5}, Value: []int64{1}}, // d + {LocationId: []uint64{6}, Value: []int64{1}}, // d (2) + }, + } + + db := NewSymDB(DefaultConfig().WithDirectory(t.TempDir())) + w := db.WriteProfileSymbols(0, profile) + r := NewResolver(context.Background(), db, + WithResolverStackTraceSelector(&typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{{Name: "a"}, {Name: "b"}, {Name: "c"}, {Name: "d"}}, + })) + + r.AddSamples(0, w[0].Samples) + actual, err := r.Pprof() + require.NoError(t, err) + // Sample order is not deterministic. + sort.Slice(actual.Sample, func(i, j int) bool { + return slices.Compare(actual.Sample[i].LocationId, actual.Sample[j].LocationId) >= 0 + }) + + expected := &googlev1.Profile{ + PeriodType: &googlev1.ValueType{}, + SampleType: []*googlev1.ValueType{{}}, + StringTable: []string{"", "a", "b", "c", "d"}, + Function: []*googlev1.Function{ + {Id: 1, Name: 1}, // a + {Id: 2, Name: 2}, // b + {Id: 3, Name: 3}, // c + {Id: 4, Name: 4, StartLine: 1}, // d + {Id: 5, Name: 4, StartLine: 2}, // d(2) + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 1, Line: 1}}}, // a + {Id: 2, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 1}}}, // b:1 + {Id: 3, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 2}}}, // b:2 + {Id: 4, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 3, Line: 1}}}, // c + {Id: 5, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 4, Line: 1}}}, // d + {Id: 6, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 5, Line: 1}}}, // d(2) + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{6, 4, 3, 1}, Value: []int64{1}}, // a, b:2, c, d(2) + {LocationId: []uint64{5, 4, 2, 1}, Value: []int64{1}}, // a, b:1, c, d + }, + } + + require.Equal(t, expected, actual) +} + func Test_Resolver_pprof_options(t *testing.T) { s := newMemSuite(t, [][]string{{"testdata/profile.pb.gz"}}) samples := s.indexed[0][0].Samples @@ -219,6 +292,62 @@ func Test_Resolver_pprof_options(t *testing.T) { }), }, }, + { + name: "StackTraceSelector GoPGO empty", + expected: samplesTotal, + options: []ResolverOption{ + WithResolverStackTraceSelector(&typesv1.StackTraceSelector{ + GoPgo: &typesv1.GoPGO{}, + }), + }, + }, + { + name: "StackTraceSelector GoPGO takes precedence", + expected: 414, + options: []ResolverOption{ + WithResolverMaxNodes(10), + WithResolverStackTraceSelector(&typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{{Name: "runtime.main"}}, + GoPgo: &typesv1.GoPGO{ + KeepLocations: 5, + }, + }), + }, + }, + { + name: "GoPGO KeepLocations 5", + expected: 414, + options: []ResolverOption{ + WithResolverStackTraceSelector(&typesv1.StackTraceSelector{ + GoPgo: &typesv1.GoPGO{ + KeepLocations: 5, + }, + }), + }, + }, + { + name: "GoPGO AggregateCallees", + expected: 442, + options: []ResolverOption{ + WithResolverStackTraceSelector(&typesv1.StackTraceSelector{ + GoPgo: &typesv1.GoPGO{ + AggregateCallees: true, + }, + }), + }, + }, + { + name: "GoPGO AggregateCallees KeepLocations 5", + expected: 316, + options: []ResolverOption{ + WithResolverStackTraceSelector(&typesv1.StackTraceSelector{ + GoPgo: &typesv1.GoPGO{ + KeepLocations: 5, + AggregateCallees: true, + }, + }), + }, + }, } for _, tc := range testCases { diff --git a/pkg/phlaredb/symdb/resolver_pprof_tree.go b/pkg/phlaredb/symdb/resolver_pprof_tree.go new file mode 100644 index 0000000000..d3a9544c97 --- /dev/null +++ b/pkg/phlaredb/symdb/resolver_pprof_tree.go @@ -0,0 +1,281 @@ +package symdb + +import ( + "unsafe" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/slices" +) + +const ( + truncationMark = 1 << 30 + truncatedNodeName = "other" +) + +type pprofTree struct { + symbols *Symbols + samples *schemav1.Samples + profile googlev1.Profile + lut []uint32 + cur int + + maxNodes int64 + truncated int + + functionTree *model.StacktraceTree + stacktraces []truncatedStacktraceSample + // Two buffers are needed as we handle both function and location + // stacks simultaneously. + functionsBuf []int32 + locationsBuf []uint64 + + selection *SelectedStackTraces + fnNames func(locations []int32) ([]int32, bool) + + // After truncation many samples will have the same stack trace. + // The map is used to deduplicate them. The key is sample.LocationId + // slice turned into a string: the underlying memory must not change. + sampleMap map[string]*googlev1.Sample + // As an optimisation, we merge all the stack trace samples that were + // fully truncated to a single sample. + fullyTruncated int64 +} + +type truncatedStacktraceSample struct { + stacktraceID uint32 + functionNodeIdx int32 + value int64 +} + +func (r *pprofTree) init(symbols *Symbols, samples schemav1.Samples) { + r.symbols = symbols + r.samples = &samples + // We optimistically assume that each stacktrace has only + // 2 unique nodes. For pathological cases it may exceed 10. + r.functionTree = model.NewStacktraceTree(samples.Len() * 2) + r.stacktraces = make([]truncatedStacktraceSample, 0, samples.Len()) + r.sampleMap = make(map[string]*googlev1.Sample, samples.Len()) + if r.selection != nil && len(r.selection.callSite) > 0 { + r.fnNames = r.locFunctionsFiltered + } else { + r.fnNames = r.locFunctions + } +} + +func (r *pprofTree) InsertStacktrace(stacktraceID uint32, locations []int32) { + value := int64(r.samples.Values[r.cur]) + r.cur++ + functions, ok := r.fnNames(locations) + if ok { + functionNodeIdx := r.functionTree.Insert(functions, value) + r.stacktraces = append(r.stacktraces, truncatedStacktraceSample{ + stacktraceID: stacktraceID, + functionNodeIdx: functionNodeIdx, + value: value, + }) + } +} + +func (r *pprofTree) locFunctions(locations []int32) ([]int32, bool) { + r.functionsBuf = r.functionsBuf[:0] + for i := 0; i < len(locations); i++ { + lines := r.symbols.Locations[locations[i]].Line + for j := 0; j < len(lines); j++ { + r.functionsBuf = append(r.functionsBuf, int32(lines[j].FunctionId)) + } + } + return r.functionsBuf, true +} + +func (r *pprofTree) locFunctionsFiltered(locations []int32) ([]int32, bool) { + r.functionsBuf = r.functionsBuf[:0] + var pos int + pathLen := int(r.selection.depth) + // Even if len(locations) < pathLen, we still + // need to inspect locations line by line. + for i := len(locations) - 1; i >= 0; i-- { + lines := r.symbols.Locations[locations[i]].Line + for j := len(lines) - 1; j >= 0; j-- { + f := lines[j].FunctionId + if pos < pathLen { + if r.selection.callSite[pos] != r.selection.funcNames[f] { + return nil, false + } + pos++ + } + r.functionsBuf = append(r.functionsBuf, int32(f)) + } + } + if pos < pathLen { + return nil, false + } + slices.Reverse(r.functionsBuf) + return r.functionsBuf, true +} + +func (r *pprofTree) buildPprof() *googlev1.Profile { + r.markNodesForTruncation() + for _, n := range r.stacktraces { + r.addSample(n) + } + r.createSamples() + createSampleTypeStub(&r.profile) + copyLocations(&r.profile, r.symbols, r.lut) + copyFunctions(&r.profile, r.symbols, r.lut) + copyMappings(&r.profile, r.symbols, r.lut) + copyStrings(&r.profile, r.symbols, r.lut) + if r.truncated > 0 || r.fullyTruncated > 0 { + createLocationStub(&r.profile) + } + return &r.profile +} + +func (r *pprofTree) markNodesForTruncation() { + minValue := r.functionTree.MinValue(r.maxNodes) + if minValue == 0 { + return + } + for i := range r.functionTree.Nodes { + if r.functionTree.Nodes[i].Total < minValue { + r.functionTree.Nodes[i].Location |= truncationMark + r.truncated++ + } + } +} + +func (r *pprofTree) addSample(n truncatedStacktraceSample) { + // Find the original stack trace and remove truncated + // locations based on the truncated functions. + var off int + r.functionsBuf, off = r.buildFunctionsStack(r.functionsBuf, n.functionNodeIdx) + if off < 0 { + // The stack has no functions without the truncation mark. + r.fullyTruncated += n.value + return + } + r.locationsBuf = r.symbols.Stacktraces.LookupLocations(r.locationsBuf, n.stacktraceID) + if off > 0 { + // Some functions were truncated. + r.locationsBuf = truncateLocations(r.locationsBuf, r.functionsBuf, off, r.symbols) + // Otherwise, if the offset is zero, the stack can be taken as is. + } + // Truncation may result in vast duplication of stack traces. + // Even if a particular stack trace is not truncated, we still + // remember it, as there might be another truncated stack trace + // that fully matches it. + // Note that this is safe to take locationsBuf memory for the + // map key lookup as it is not retained. + if s, dup := r.sampleMap[uint64sliceString(r.locationsBuf)]; dup { + s.Value[0] += n.value + return + } + // If this is a new stack trace, copy locations, create + // the sample, and add the stack trace to the map. + // TODO(kolesnikovae): Do not allocate new slices per sample. + // Instead, pre-allocated slabs and reference samples from them. + locationsCopy := make([]uint64, len(r.locationsBuf)) + copy(locationsCopy, r.locationsBuf) + s := &googlev1.Sample{LocationId: locationsCopy, Value: []int64{n.value}} + r.profile.Sample = append(r.profile.Sample, s) + r.sampleMap[uint64sliceString(locationsCopy)] = s +} + +func (r *pprofTree) buildFunctionsStack(funcs []int32, idx int32) ([]int32, int) { + offset := -1 + funcs = funcs[:0] + for i := idx; i > 0; i = r.functionTree.Nodes[i].Parent { + n := r.functionTree.Nodes[i] + if offset < 0 && n.Location&truncationMark == 0 { + // Remember the first node to keep. + offset = len(funcs) + } + funcs = append(funcs, n.Location&^truncationMark) + } + return funcs, offset +} + +func (r *pprofTree) createSamples() { + samples := len(r.sampleMap) + r.profile.Sample = make([]*googlev1.Sample, samples, samples+1) + var i int + for _, s := range r.sampleMap { + r.profile.Sample[i] = s + i++ + } + if r.fullyTruncated > 0 { + r.createStubSample() + } +} + +func truncateLocations(locations []uint64, functions []int32, offset int, symbols *Symbols) []uint64 { + if offset < 1 { + return locations + } + f := len(functions) + l := len(locations) + for ; l > 0 && f >= offset; l-- { + location := symbols.Locations[locations[l-1]] + for j := len(location.Line) - 1; j >= 0; j-- { + f-- + } + } + if l > 0 { + locations[0] = truncationMark + return append(locations[:1], locations[l:]...) + } + return locations[l:] +} + +func uint64sliceString(u []uint64) string { + if len(u) == 0 { + return "" + } + p := (*byte)(unsafe.Pointer(&u[0])) + return unsafe.String(p, len(u)*8) +} + +func (r *pprofTree) createStubSample() { + r.profile.Sample = append(r.profile.Sample, &googlev1.Sample{ + LocationId: []uint64{truncationMark}, + Value: []int64{r.fullyTruncated}, + }) +} + +func createLocationStub(profile *googlev1.Profile) { + var stubNodeNameIdx int64 + for i, s := range profile.StringTable { + if s == truncatedNodeName { + stubNodeNameIdx = int64(i) + break + } + } + if stubNodeNameIdx == 0 { + stubNodeNameIdx = int64(len(profile.StringTable)) + profile.StringTable = append(profile.StringTable, truncatedNodeName) + } + stubFn := &googlev1.Function{ + Id: uint64(len(profile.Function) + 1), + Name: stubNodeNameIdx, + SystemName: stubNodeNameIdx, + } + profile.Function = append(profile.Function, stubFn) + // in the case there is no mapping, we need to create one + if len(profile.Mapping) == 0 { + profile.Mapping = append(profile.Mapping, &googlev1.Mapping{Id: 1}) + } + stubLoc := &googlev1.Location{ + Id: uint64(len(profile.Location) + 1), + Line: []*googlev1.Line{{FunctionId: stubFn.Id}}, + MappingId: 1, + } + profile.Location = append(profile.Location, stubLoc) + for _, s := range profile.Sample { + for i, loc := range s.LocationId { + if loc == truncationMark { + s.LocationId[i] = stubLoc.Id + } + } + } +} diff --git a/pkg/phlaredb/symdb/resolver_pprof_truncate.go b/pkg/phlaredb/symdb/resolver_pprof_truncate.go deleted file mode 100644 index d22c379228..0000000000 --- a/pkg/phlaredb/symdb/resolver_pprof_truncate.go +++ /dev/null @@ -1,279 +0,0 @@ -package symdb - -import ( - "unsafe" - - googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - "github.com/grafana/pyroscope/pkg/model" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/slices" -) - -const ( - truncationMark = 1 << 30 - truncatedNodeName = "other" -) - -type pprofProtoTruncatedSymbols struct { - symbols *Symbols - samples *schemav1.Samples - profile googlev1.Profile - lut []uint32 - cur int - - maxNodes int64 - truncated int - - functionTree *model.StacktraceTree - stacktraces []truncatedStacktraceSample - // Two buffers are needed as we handle both function and location - // stacks simultaneously. - functionsBuf []int32 - locationsBuf []uint64 - - selection *SelectedStackTraces - fnNames func(locations []int32) ([]int32, bool) - - // After truncation many samples will have the same stack trace. - // The map is used to deduplicate them. The key is sample.LocationId - // slice turned into a string: the underlying memory must not change. - sampleMap map[string]*googlev1.Sample - // As an optimisation, we merge all the stack trace samples that were - // fully truncated to a single sample. - fullyTruncated int64 -} - -type truncatedStacktraceSample struct { - stacktraceID uint32 - functionNodeIdx int32 - value int64 -} - -func (r *pprofProtoTruncatedSymbols) init(symbols *Symbols, samples schemav1.Samples) { - r.symbols = symbols - r.samples = &samples - // We optimistically assume that each stacktrace has only - // 2 unique nodes. For pathological cases it may exceed 10. - r.functionTree = model.NewStacktraceTree(samples.Len() * 2) - r.stacktraces = make([]truncatedStacktraceSample, 0, samples.Len()) - r.sampleMap = make(map[string]*googlev1.Sample, samples.Len()) - if r.selection != nil && len(r.selection.callSite) > 0 { - r.fnNames = r.locFunctionsFiltered - } else { - r.fnNames = r.locFunctions - } -} - -func (r *pprofProtoTruncatedSymbols) InsertStacktrace(stacktraceID uint32, locations []int32) { - value := int64(r.samples.Values[r.cur]) - r.cur++ - functions, ok := r.fnNames(locations) - if ok { - functionNodeIdx := r.functionTree.Insert(functions, value) - r.stacktraces = append(r.stacktraces, truncatedStacktraceSample{ - stacktraceID: stacktraceID, - functionNodeIdx: functionNodeIdx, - value: value, - }) - } -} - -func (r *pprofProtoTruncatedSymbols) locFunctions(locations []int32) ([]int32, bool) { - r.functionsBuf = r.functionsBuf[:0] - for i := 0; i < len(locations); i++ { - lines := r.symbols.Locations[locations[i]].Line - for j := 0; j < len(lines); j++ { - r.functionsBuf = append(r.functionsBuf, int32(lines[j].FunctionId)) - } - } - return r.functionsBuf, true -} - -func (r *pprofProtoTruncatedSymbols) locFunctionsFiltered(locations []int32) ([]int32, bool) { - r.functionsBuf = r.functionsBuf[:0] - var pos int - pathLen := len(r.selection.callSite) - // Even if len(locations) < pathLen, we still - // need to inspect locations line by line. - for i := len(locations) - 1; i >= 0; i-- { - lines := r.symbols.Locations[locations[i]].Line - for j := len(lines) - 1; j >= 0; j-- { - f := lines[j].FunctionId - if pos < pathLen { - if r.selection.callSite[pos] != f { - return nil, false - } - pos++ - } - r.functionsBuf = append(r.functionsBuf, int32(f)) - } - } - if pos < pathLen { - return nil, false - } - slices.Reverse(r.functionsBuf) - return r.functionsBuf, true -} - -func (r *pprofProtoTruncatedSymbols) buildPprof() *googlev1.Profile { - r.markNodesForTruncation() - for _, n := range r.stacktraces { - r.addSample(n) - } - r.createSamples() - createSampleTypeStub(&r.profile) - copyLocations(&r.profile, r.symbols, r.lut) - copyFunctions(&r.profile, r.symbols, r.lut) - copyMappings(&r.profile, r.symbols, r.lut) - copyStrings(&r.profile, r.symbols, r.lut) - if r.truncated > 0 || r.fullyTruncated > 0 { - createLocationStub(&r.profile) - } - return &r.profile -} - -func (r *pprofProtoTruncatedSymbols) markNodesForTruncation() { - minValue := r.functionTree.MinValue(r.maxNodes) - if minValue == 0 { - return - } - for i := range r.functionTree.Nodes { - if r.functionTree.Nodes[i].Total < minValue { - r.functionTree.Nodes[i].Location |= truncationMark - r.truncated++ - } - } -} - -func (r *pprofProtoTruncatedSymbols) addSample(n truncatedStacktraceSample) { - // Find the original stack trace and remove truncated - // locations based on the truncated functions. - var off int - r.functionsBuf, off = r.buildFunctionsStack(r.functionsBuf, n.functionNodeIdx) - if off < 0 { - // The stack has no functions without the truncation mark. - r.fullyTruncated += n.value - return - } - r.locationsBuf = r.symbols.Stacktraces.LookupLocations(r.locationsBuf, n.stacktraceID) - if off > 0 { - // Some functions were truncated. - r.locationsBuf = truncateLocations(r.locationsBuf, r.functionsBuf, off, r.symbols) - // Otherwise, if the offset is zero, the stack can be taken as is. - } - // Truncation may result in vast duplication of stack traces. - // Even if a particular stack trace is not truncated, we still - // remember it, as there might be another truncated stack trace - // that fully matches it. - // Note that this is safe to take locationsBuf memory for the - // map key lookup as it is not retained. - if s, dup := r.sampleMap[uint64sliceString(r.locationsBuf)]; dup { - s.Value[0] += n.value - return - } - // If this is a new stack trace, copy locations, create - // the sample, and add the stack trace to the map. - locationsCopy := make([]uint64, len(r.locationsBuf)) - copy(locationsCopy, r.locationsBuf) - s := &googlev1.Sample{LocationId: locationsCopy, Value: []int64{n.value}} - r.profile.Sample = append(r.profile.Sample, s) - r.sampleMap[uint64sliceString(locationsCopy)] = s -} - -func (r *pprofProtoTruncatedSymbols) buildFunctionsStack(funcs []int32, idx int32) ([]int32, int) { - offset := -1 - funcs = funcs[:0] - for i := idx; i > 0; i = r.functionTree.Nodes[i].Parent { - n := r.functionTree.Nodes[i] - if offset < 0 && n.Location&truncationMark == 0 { - // Remember the first node to keep. - offset = len(funcs) - } - funcs = append(funcs, n.Location&^truncationMark) - } - return funcs, offset -} - -func (r *pprofProtoTruncatedSymbols) createSamples() { - samples := len(r.sampleMap) - r.profile.Sample = make([]*googlev1.Sample, samples, samples+1) - var i int - for _, s := range r.sampleMap { - r.profile.Sample[i] = s - i++ - } - if r.fullyTruncated > 0 { - r.createStubSample() - } -} - -func truncateLocations(locations []uint64, functions []int32, offset int, symbols *Symbols) []uint64 { - if offset < 1 { - return locations - } - f := len(functions) - l := len(locations) - for ; l > 0 && f >= offset; l-- { - location := symbols.Locations[locations[l-1]] - for j := len(location.Line) - 1; j >= 0; j-- { - f-- - } - } - if l > 0 { - locations[0] = truncationMark - return append(locations[:1], locations[l:]...) - } - return locations[l:] -} - -func uint64sliceString(u []uint64) string { - if len(u) == 0 { - return "" - } - p := (*byte)(unsafe.Pointer(&u[0])) - return unsafe.String(p, len(u)*8) -} - -func (r *pprofProtoTruncatedSymbols) createStubSample() { - r.profile.Sample = append(r.profile.Sample, &googlev1.Sample{ - LocationId: []uint64{truncationMark}, - Value: []int64{r.fullyTruncated}, - }) -} - -func createLocationStub(profile *googlev1.Profile) { - var stubNodeNameIdx int64 - for i, s := range profile.StringTable { - if s == truncatedNodeName { - stubNodeNameIdx = int64(i) - break - } - } - if stubNodeNameIdx == 0 { - stubNodeNameIdx = int64(len(profile.StringTable)) - profile.StringTable = append(profile.StringTable, truncatedNodeName) - } - stubFn := &googlev1.Function{ - Id: uint64(len(profile.Function) + 1), - Name: stubNodeNameIdx, - SystemName: stubNodeNameIdx, - } - profile.Function = append(profile.Function, stubFn) - // in the case there is no mapping, we need to create one - if len(profile.Mapping) == 0 { - profile.Mapping = append(profile.Mapping, &googlev1.Mapping{Id: 1}) - } - stubLoc := &googlev1.Location{ - Id: uint64(len(profile.Location) + 1), - Line: []*googlev1.Line{{FunctionId: stubFn.Id}}, - MappingId: 1, - } - profile.Location = append(profile.Location, stubLoc) - for _, s := range profile.Sample { - for i, loc := range s.LocationId { - if loc == truncationMark { - s.LocationId[i] = stubLoc.Id - } - } - } -} diff --git a/pkg/phlaredb/symdb/resolver_stacktraces.go b/pkg/phlaredb/symdb/resolver_stacktraces.go deleted file mode 100644 index 04a30c54bb..0000000000 --- a/pkg/phlaredb/symdb/resolver_stacktraces.go +++ /dev/null @@ -1,171 +0,0 @@ -package symdb - -import ( - "github.com/parquet-go/parquet-go" - - typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" -) - -// CallSiteValues represents statistics associated with a call tree node. -type CallSiteValues struct { - // Flat is the sum of sample values directly attributed to the node. - Flat uint64 - // Total is the total sum of sample values attributed to the node and - // its descendants. - Total uint64 - // LocationFlat is the sum of sample values directly attributed to the - // node location, irrespectively of the call chain. - LocationFlat uint64 - // LocationTotal is the total sum of sample values attributed to the - // node location and its descendants, irrespectively of the call chain. - LocationTotal uint64 -} - -// stackTraceLocationRelation represents the relation between a stack trace -// and a location, according to the stack trace selector parameters. -type stackTraceLocationRelation uint8 - -const ( - // relationSubtree indicates whether the stack trace belongs - // to the callSite specified by the stack trace selector. - relationSubtree stackTraceLocationRelation = 1 << iota - // relationLeaf specifies that the stack trace leaf is the - // location specified by the stack trace selector, - // irrespectively of the call chain. - relationLeaf - // relationNode specifies that the stack trace includes - // the location specified by the stack trace selector, - // irrespectively of the call chain. - relationNode -) - -type SelectedStackTraces struct { - symbols *Symbols - selector []*typesv1.Location - relations map[uint32]stackTraceLocationRelation - callSite []uint32 // stack trace of the call site - location uint32 // stack trace leaf - depth uint32 - buf []uint64 -} - -func SelectStackTraces(symbols *Symbols, selector *typesv1.StackTraceSelector) *SelectedStackTraces { - x := &SelectedStackTraces{ - symbols: symbols, - selector: selector.GetCallSite(), - } - x.callSite = findCallSite(symbols, x.selector) - if x.depth = uint32(len(x.callSite)); x.depth > 0 { - x.location = x.callSite[x.depth-1] - } - return x -} - -// IsValid reports whether any stack traces match the selector. -// An empty selector results in a valid empty selection. -func (x *SelectedStackTraces) IsValid() bool { - return len(x.selector) == 0 || len(x.selector) != 0 && len(x.callSite) != 0 -} - -// CallSiteValues writes the call site statistics for -// the selected stack traces and the given set of samples. -func (x *SelectedStackTraces) CallSiteValues(values *CallSiteValues, samples schemav1.Samples) { - *values = CallSiteValues{} - if x.depth == 0 { - return - } - if x.relations == nil { - // relations will grow to the size of the number of stack traces: - // if a stack trace does not belong to the selection, we still - // have to memoize the negative result. - x.relations = make(map[uint32]stackTraceLocationRelation, len(x.symbols.Locations)) - } - for i, sid := range samples.StacktraceIDs { - v := samples.Values[i] - r, ok := x.relations[sid] - if !ok { - x.buf = x.symbols.Stacktraces.LookupLocations(x.buf, sid) - r = x.appendStackTrace(x.buf) - x.relations[sid] = r - } - x.write(values, v, r) - } -} - -// CallSiteValuesParquet is identical to CallSiteValues -// but accepts raw parquet values instead of samples. -func (x *SelectedStackTraces) CallSiteValuesParquet(values *CallSiteValues, stacktraceID, value []parquet.Value) { - *values = CallSiteValues{} - if x.depth == 0 { - return - } - if x.relations == nil { - // relations will grow to the size of the number of stack traces: - // if a stack trace does not belong to the selection, we still - // have to memoize the negative result. - x.relations = make(map[uint32]stackTraceLocationRelation, len(x.symbols.Locations)) - } - for i, pv := range stacktraceID { - sid := pv.Uint32() - v := value[i].Uint64() - r, ok := x.relations[sid] - if !ok { - x.buf = x.symbols.Stacktraces.LookupLocations(x.buf, sid) - r = x.appendStackTrace(x.buf) - x.relations[sid] = r - } - x.write(values, v, r) - } -} - -func (x *SelectedStackTraces) write(m *CallSiteValues, v uint64, r stackTraceLocationRelation) { - s := uint64(r & relationSubtree) - l := uint64(r&relationLeaf) >> 1 - n := uint64(r&relationNode) >> 2 - m.LocationTotal += v * (n | l) - m.LocationFlat += v * l - m.Total += v * s - m.Flat += v * s * l -} - -func (x *SelectedStackTraces) appendStackTrace(locations []uint64) stackTraceLocationRelation { - if len(locations) == 0 { - return 0 - } - var n uint32 // Number of times callSite root function seen. - var pos uint32 - var l uint32 - for i := len(locations) - 1; i >= 0; i-- { - lines := x.symbols.Locations[locations[i]].Line - for j := len(lines) - 1; j >= 0; j-- { - f := lines[j].FunctionId - n += eq(x.location, f) - if pos < x.depth && pos == l { - pos += eq(x.callSite[pos], f) - } - l++ - } - } - if n == 0 { - return 0 - } - leaf := x.symbols.Locations[locations[0]].Line[0] - isLeaf := eq(x.location, leaf.FunctionId) - inSubtree := ge(pos, x.depth) - return stackTraceLocationRelation(inSubtree | isLeaf<<1 | (1-isLeaf)<<2) -} - -func eq(a, b uint32) uint32 { - if a == b { - return 1 - } - return 0 -} - -func ge(a, b uint32) uint32 { - if a >= b { - return 1 - } - return 0 -} diff --git a/pkg/phlaredb/symdb/resolver_stacktraces_test.go b/pkg/phlaredb/symdb/resolver_stacktraces_test.go deleted file mode 100644 index 6d96534056..0000000000 --- a/pkg/phlaredb/symdb/resolver_stacktraces_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package symdb - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/slices" -) - -func Test_StackTraceFilter(t *testing.T) { - profile := &googlev1.Profile{ - StringTable: []string{"", "foo", "bar", "baz", "qux"}, - Function: []*googlev1.Function{ - {Id: 1, Name: 1}, - {Id: 2, Name: 2}, - {Id: 3, Name: 3}, - {Id: 4, Name: 4}, - }, - Mapping: []*googlev1.Mapping{{Id: 1}}, - Location: []*googlev1.Location{ - {Id: 1, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 1, Line: 1}}}, // foo - {Id: 2, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 1}}}, // bar:1 - {Id: 3, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 2}}}, // bar:2 - {Id: 4, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 3, Line: 1}}}, // baz - {Id: 5, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 4, Line: 1}}}, // qux - }, - Sample: []*googlev1.Sample{ - {LocationId: []uint64{4, 2, 1}, Value: []int64{1}}, // foo, bar:1, baz - {LocationId: []uint64{3, 1}, Value: []int64{1}}, // foo, bar:2 - {LocationId: []uint64{4, 1}, Value: []int64{1}}, // foo, baz - {LocationId: []uint64{5}, Value: []int64{1}}, // qux - - {LocationId: []uint64{2}, Value: []int64{1}}, // bar:1 - {LocationId: []uint64{1, 2}, Value: []int64{1}}, // bar:1, foo - {LocationId: []uint64{3}, Value: []int64{1}}, // bar:2 - {LocationId: []uint64{1, 3}, Value: []int64{1}}, // bar:2, foo - }, - } - - db := NewSymDB(DefaultConfig().WithDirectory(t.TempDir())) - w := db.WriteProfileSymbols(0, profile) - - p, err := db.Partition(context.Background(), 0) - require.NoError(t, err) - symbols := p.Symbols() - - type testCase struct { - selector *typesv1.StackTraceSelector - expected CallSiteValues - } - - testCases := []testCase{ - { - selector: &typesv1.StackTraceSelector{ - CallSite: []*typesv1.Location{{Name: "foo"}}, - }, - expected: CallSiteValues{ - Flat: 0, - Total: 3, - LocationFlat: 2, - LocationTotal: 5, - }, - }, - { - selector: &typesv1.StackTraceSelector{ - CallSite: []*typesv1.Location{{Name: "bar"}}, - }, - expected: CallSiteValues{ - Flat: 2, - Total: 4, - LocationFlat: 3, - LocationTotal: 6, - }, - }, - { - selector: &typesv1.StackTraceSelector{ - CallSite: []*typesv1.Location{{Name: "foo"}, {Name: "bar"}}, - }, - expected: CallSiteValues{ - Flat: 1, - Total: 2, - LocationFlat: 3, - LocationTotal: 6, - }, - }, - { - selector: &typesv1.StackTraceSelector{ - CallSite: []*typesv1.Location{{Name: "foo"}, {Name: "bar"}, {Name: "baz"}}, - }, - expected: CallSiteValues{ - Flat: 1, - Total: 1, - LocationFlat: 2, - LocationTotal: 2, - }, - }, - { - selector: &typesv1.StackTraceSelector{ - CallSite: []*typesv1.Location{{Name: "foo"}, {Name: "bar"}, {Name: "baz"}, {Name: "qux"}}, - }, - expected: CallSiteValues{ - Flat: 0, - Total: 0, - LocationFlat: 1, - LocationTotal: 1, - }, - }, - {selector: &typesv1.StackTraceSelector{}}, - {}, - } - - for _, tc := range testCases { - selection := SelectStackTraces(symbols, tc.selector) - var values CallSiteValues - selection.CallSiteValues(&values, w[0].Samples) - assert.Equal(t, tc.expected, values, "selector: %+v", tc.selector) - } -} - -func Benchmark_StackTraceFilter(b *testing.B) { - s := memSuite{t: b, files: [][]string{{"testdata/big-profile.pb.gz"}}} - s.config = DefaultConfig().WithDirectory(b.TempDir()) - s.init() - samples := s.indexed[0][0].Samples - - prt, err := s.db.Partition(context.Background(), 0) - require.NoError(b, err) - symbols := prt.Symbols() - - p := s.profiles[0] - stack := p.Sample[len(p.Sample)/3].LocationId - selector := buildStackTraceSelector(p, stack[len(stack)/10:]) - var values CallSiteValues - - b.ReportAllocs() - b.ResetTimer() - - selection := SelectStackTraces(symbols, selector) - for i := 0; i < b.N; i++ { - selection.CallSiteValues(&values, samples) - } -} - -func buildStackTraceSelector(p *googlev1.Profile, locs []uint64) *typesv1.StackTraceSelector { - var selector typesv1.StackTraceSelector - for _, n := range locs { - for _, l := range p.Location[n-1].Line { - fn := p.Function[l.FunctionId-1] - selector.CallSite = append(selector.CallSite, &typesv1.Location{ - Name: p.StringTable[fn.Name], - }) - } - } - slices.Reverse(selector.CallSite) - return &selector -} diff --git a/pkg/phlaredb/symdb/resolver_test.go b/pkg/phlaredb/symdb/resolver_test.go index cbeef9875d..05c55b63b0 100644 --- a/pkg/phlaredb/symdb/resolver_test.go +++ b/pkg/phlaredb/symdb/resolver_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) func Test_Resolver_Unreleased_Failed_Partition(t *testing.T) { diff --git a/pkg/phlaredb/symdb/resolver_trace_test.go b/pkg/phlaredb/symdb/resolver_trace_test.go new file mode 100644 index 0000000000..9ca629457a --- /dev/null +++ b/pkg/phlaredb/symdb/resolver_trace_test.go @@ -0,0 +1,77 @@ +package symdb + +import ( + "context" + "testing" + + "github.com/parquet-go/parquet-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/v2/pkg/model" +) + +func sumPprofValues(p *googlev1.Profile) int64 { + var total int64 + for _, s := range p.Sample { + for _, v := range s.Value { + total += v + } + } + return total +} + +// Test_Resolver_AddSamplesWithTraceSelectorFromParquetRow drives the trace_id +// sample filter end to end: samples are tagged with synthetic 16-byte trace IDs +// (matching, non-matching, and null) and the resolved pprof must contain only +// the values whose trace ID is in the selector. +func Test_Resolver_AddSamplesWithTraceSelectorFromParquetRow(t *testing.T) { + s := newMemSuite(t, [][]string{{"testdata/profile.pb.gz"}}) + samples := s.indexed[0][0].Samples + require.NotZero(t, len(samples.StacktraceIDs)) + + matching := model.TraceID{0x01} + other := model.TraceID{0x02} + + stacktraces := make([]parquet.Value, len(samples.StacktraceIDs)) + values := make([]parquet.Value, len(samples.StacktraceIDs)) + traces := make([]parquet.Value, len(samples.StacktraceIDs)) + var wantMatching int64 + for i, sid := range samples.StacktraceIDs { + stacktraces[i] = parquet.Int32Value(int32(sid)) + values[i] = parquet.Int64Value(int64(samples.Values[i])) + switch i % 3 { + case 0: + traces[i] = parquet.FixedLenByteArrayValue(matching[:]) + if sid > 0 { + wantMatching += int64(samples.Values[i]) + } + case 1: + traces[i] = parquet.FixedLenByteArrayValue(other[:]) + default: + // No trace id on this sample (optional column null). + traces[i] = parquet.NullValue() + } + } + require.NotZero(t, wantMatching, "fixture must contain at least one matching sample") + + t.Run("matching trace filters to its samples", func(t *testing.T) { + r := NewResolver(context.Background(), s.db) + defer r.Release() + r.AddSamplesWithTraceSelectorFromParquetRow(0, stacktraces, values, traces, model.TraceSelector{matching: {}}) + resolved, err := r.Pprof() + require.NoError(t, err) + assert.Equal(t, wantMatching, sumPprofValues(resolved)) + }) + + t.Run("non-matching trace returns empty", func(t *testing.T) { + r := NewResolver(context.Background(), s.db) + defer r.Release() + absent := model.TraceID{0xff} + r.AddSamplesWithTraceSelectorFromParquetRow(0, stacktraces, values, traces, model.TraceSelector{absent: {}}) + resolved, err := r.Pprof() + require.NoError(t, err) + assert.Zero(t, sumPprofValues(resolved)) + }) +} diff --git a/pkg/phlaredb/symdb/resolver_tree.go b/pkg/phlaredb/symdb/resolver_tree.go index 9deac35547..4acfacf3b6 100644 --- a/pkg/phlaredb/symdb/resolver_tree.go +++ b/pkg/phlaredb/symdb/resolver_tree.go @@ -1,18 +1,79 @@ package symdb import ( + "context" + "strconv" "sync" - "github.com/grafana/pyroscope/pkg/model" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + "golang.org/x/sync/errgroup" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/minheap" ) +func buildTree[N model.NodeName, I model.NodeNameI[N]]( + ctx context.Context, + symbols *Symbols, + appender *SampleAppender, + maxNodes int64, + selection *SelectedStackTraces, + lookup func(int32) N, +) (*model.Tree[N, I], error) { + if !selection.HasValidCallSite() { + // TODO(bryan) Maybe return an error here? buildPprof returns a blank + // profile. So mimicking that behavior for now. + return &model.Tree[N, I]{}, nil + } + + // If the number of samples is large (> 128K) and the StacktraceResolver + // implements the range iterator, we will be building the tree based on + // the parent pointer tree of the partition (a copy of). The only exception + // is when the number of nodes is not limited, or is close to the number of + // nodes in the original tree: the optimization is still beneficial in terms + // of CPU, but is very expensive in terms of memory. + iterator, ok := symbols.Stacktraces.(StacktraceIDRangeIterator) + if ok && shouldCopyTree(appender, maxNodes) { + ranges := iterator.SplitStacktraceIDRanges(appender) + return buildTreeFromParentPointerTrees[N, I](ctx, ranges, symbols, maxNodes, selection, lookup) + } + // Otherwise, use the basic approach: resolve each stack trace + // and insert them into the new tree one by one. The method + // performs best on small sample sets. + + // Select insert method depending on type + var treeI I + + samples := appender.Samples() + t := treeSymbolsFromPool() + defer t.reset() + t.init(symbols, samples, selection, treeI.IsLocationTree()) + if err := symbols.Stacktraces.ResolveStacktraceLocations(ctx, t, samples.StacktraceIDs); err != nil { + return nil, err + } + return model.TreeFromStacktraceTree[N, I](t.tree, maxNodes, lookup), nil +} + +func shouldCopyTree(appender *SampleAppender, maxNodes int64) bool { + const copyThreshold = 128 << 10 + expensiveTruncation := maxNodes <= 0 || maxNodes > int64(appender.Len()) + return appender.Len() > copyThreshold && !expensiveTruncation +} + type treeSymbols struct { symbols *Symbols samples *schemav1.Samples tree *model.StacktraceTree lines []int32 + locID []int32 // only used when addLocation is true cur int + + addLocation bool + + selection *SelectedStackTraces + funcNamesMatcher func(funcNames []int32) bool } var treeSymbolsPool = sync.Pool{ @@ -28,28 +89,398 @@ func (r *treeSymbols) reset() { r.samples = nil r.tree.Reset() r.lines = r.lines[:0] + r.locID = r.locID[:0] r.cur = 0 treeSymbolsPool.Put(r) } -func (r *treeSymbols) init(symbols *Symbols, samples schemav1.Samples) { +func (r *treeSymbols) init(symbols *Symbols, samples schemav1.Samples, selection *SelectedStackTraces, addLocation bool) { r.symbols = symbols r.samples = &samples + r.selection = selection + r.addLocation = addLocation + if r.tree == nil { // Branching factor. r.tree = model.NewStacktraceTree(samples.Len() * 2) } + if r.selection != nil && len(r.selection.callSite) > 0 { + r.funcNamesMatcher = r.funcNamesMatchSelection + } } func (r *treeSymbols) InsertStacktrace(_ uint32, locations []int32) { - r.lines = r.lines[:0] + needLines := !r.addLocation || r.funcNamesMatcher != nil // lines needed lines should be insered or we have a funNamesMatcher + needLocs := r.addLocation // locs needed when requested + + if needLines { + r.lines = r.lines[:0] + } + if needLocs { + r.locID = r.locID[:0] + } + for i := 0; i < len(locations); i++ { - lines := r.symbols.Locations[locations[i]].Line - for j := 0; j < len(lines); j++ { - f := r.symbols.Functions[lines[j].FunctionId] - r.lines = append(r.lines, int32(f.Name)) + if needLines { + r.lines = addFunctionNames(r.lines, locations[i], r.symbols) + } + if needLocs { + r.locID = addLocationID(r.locID, locations[i], r.symbols) + } + } + if r.funcNamesMatcher == nil || r.funcNamesMatcher(r.lines) { + if needLocs { + r.tree.Insert(r.locID, int64(r.samples.Values[r.cur])) + } else { + r.tree.Insert(r.lines, int64(r.samples.Values[r.cur])) } } - r.tree.Insert(r.lines, int64(r.samples.Values[r.cur])) r.cur++ } + +// funcNamesMatchSelection checks if the funcNames match the selection. +// Note funcNames is a slice of function name references and is reversed. The first item is the last function in the stack trace. +func (r *treeSymbols) funcNamesMatchSelection(funcNames []int32) bool { + if len(funcNames) < int(r.selection.depth) { + return false + } + + for i := 0; i < int(r.selection.depth); i++ { + if r.symbols.Strings[funcNames[len(funcNames)-1-i]] != r.selection.callSite[i] { + return false + } + } + return true +} + +func buildTreeFromParentPointerTrees[N model.NodeName, I model.NodeNameI[N]]( + ctx context.Context, + ranges iter.Iterator[*StacktraceIDRange], + symbols *Symbols, + maxNodes int64, + selection *SelectedStackTraces, + lookup func(int32) N, +) (*model.Tree[N, I], error) { + m := model.NewTreeMerger[N, I]() + g, _ := errgroup.WithContext(ctx) + for ranges.Next() { + sr := ranges.At() + g.Go(util.RecoverPanic(func() error { + m.MergeTree(buildTreeForStacktraceIDRange[N, I](sr, symbols, maxNodes, selection, lookup)) + return nil + })) + } + if err := g.Wait(); err != nil { + return nil, err + } + return m.Tree(), nil +} + +type nodeResult int64 + +const ( + nodeResultUnknown nodeResult = iota + nodeResultMatch + nodeResultDescendant + nodeResultAncestor + nodeResultNoMatch +) + +func markNAncestors(idx int, nodes []Node, result nodeResult, depth int) { + count := 0 + for idx != sentinel { + if depth > 0 && count >= depth { + break + } + if nodes[idx].Value != int64(nodeResultUnknown) { + break + } + nodes[idx].Value = int64(result) + idx = int(nodes[idx].Parent) + count++ + } +} + +type selectedNodeMarker struct { + symbols *Symbols + selection *SelectedStackTraces + nodes []Node + + leaf int // node we started with + current int // current node index + depth int // current stack depth + selectionIdx int // references which callsite is need to be matched next +} + +// markAncestors marks the ancestors of the leaf node we started with with the given result +// will only mark the ancestors that are not already marked +func (m *selectedNodeMarker) markAncestors(result nodeResult) { + markNAncestors(m.leaf, m.nodes, result, -1) +} + +// markMatch marks the match node and its ancestors and descendants +func (m *selectedNodeMarker) markMatch() { + // get to the match node + matchNode := m.leaf + for i := 0; i < m.depth-int(m.selection.depth); i++ { + matchNode = int(m.nodes[matchNode].Parent) + } + // first mark the match node's ancestors + markNAncestors(matchNode, m.nodes, nodeResultAncestor, -1) + // mark the match node as a match + m.nodes[matchNode].Value = int64(nodeResultMatch) + // mark the match node's descendants + markNAncestors(matchNode, m.nodes, nodeResultDescendant, -1) +} + +func (m *selectedNodeMarker) reset(idx int) { + m.leaf = idx + m.current = idx + m.depth = 0 + m.selectionIdx = m.firstSelection() +} + +func (m *selectedNodeMarker) firstSelection() int { + return int(m.selection.depth) - 1 +} + +// nodeMatch checks if the current node matches the selection and update m.selectionIdx to reflect the next selection to match +// If it is -1 the full stack has been matched +func (m *selectedNodeMarker) matchNode() { + for _, l := range m.symbols.Locations[m.nodes[m.current].Location].Line { + if m.selectionIdx < 0 { + m.selectionIdx = m.firstSelection() + return + } + if m.selection.callSite[m.selectionIdx] != m.selection.funcNames[l.FunctionId] { + m.selectionIdx = m.firstSelection() + return + } + m.selectionIdx-- + } +} + +// markStack marks the stack from the left node to the root node +func (m *selectedNodeMarker) markStack(leaf int) { + m.reset(leaf) + for { + // if node result is known, we can mark nodes right away + currentResult := nodeResult(m.nodes[m.current].Value) + if currentResult != nodeResultUnknown { + switch currentResult { + case nodeResultDescendant, nodeResultMatch: + m.markAncestors(nodeResultDescendant) + case nodeResultAncestor, nodeResultNoMatch: + m.markAncestors(nodeResultNoMatch) + default: + panic("unhandled node result: " + strconv.Itoa(int(currentResult))) + } + return + } + + // check if the functionNames on this node, match the selector + m.matchNode() + + // if the next node is the root or we are on the root node already break + if next := m.nodes[m.current].Parent; next == sentinel || m.nodes[next].Parent == sentinel { + if m.selectionIdx == -1 { + // we found the match + m.markMatch() + return + } + + // mark everything that is deepeer than the selection as no match + if m.depth > int(m.selection.depth) { + markNAncestors(m.leaf, m.nodes, nodeResultNoMatch, m.depth-int(m.selection.depth)) + } + return + } + + m.current = int(m.nodes[m.current].Parent) + m.depth++ + } +} + +// markSelectedNodes marks the nodes that are matched by the StacktraceSelector +// When processing the nodes from the parent pointer tree, it will temporarily use the values field to keep track of the state of each node. +// After the nodes are processed, the values field set to 0 and the truncation mark is used to mark the nodes that are not matched. +func markSelectedNodes( + symbols *Symbols, + selection *SelectedStackTraces, + nodes []Node, +) []Node { + m := &selectedNodeMarker{ + symbols: symbols, + selection: selection, + nodes: nodes, + } + + // iterate over all nodes and check if they or their descendants match the selection + for idx := range m.nodes { + m.markStack(idx) + } + + // iterate once again over all nodes and mark the nodes that are not matched as truncated + for idx := range m.nodes { + if nodes[idx].Value != int64(nodeResultDescendant) && nodes[idx].Value != int64(nodeResultMatch) { + // mark them as truncated + nodes[idx].Location |= truncationMark + } + // reset the value + nodes[idx].Value = 0 + } + + return m.nodes +} + +func buildTreeForStacktraceIDRange[N model.NodeName, I model.NodeNameI[N]]( + stacktraces *StacktraceIDRange, + symbols *Symbols, + maxNodes int64, + selection *SelectedStackTraces, + lookup func(int32) N, +) *model.Tree[N, I] { + // Get the parent pointer tree for the range. The tree is + // not specific to the samples we've collected and includes + // all the stack traces. + nodes := stacktraces.Nodes() + // Filter stacktrace filter + if selection != nil && len(selection.callSite) > 0 { + nodes = markSelectedNodes(symbols, selection, nodes) + } + + // SetNodeValues sets values to the nodes that match the + // samples we've collected; those are not always leaves: + // a node may have its own value (self) and children. + stacktraces.SetNodeValues(nodes) + // Propagate the values to the parent nodes. This is required + // to identify the nodes that should be removed from the tree. + // For each node, the value should be a sum of all the child + // nodes (total). + propagateNodeValues(nodes) + // Next step is truncation: we need to mark leaf nodes of the + // stack traces we want to keep, and ensure that their values + // reflect their own weight (total for truncated leaves, self + // for the true leaves). + // We preserve more nodes than requested to preserve more + // locations with inlined functions. The multiplier is + // chosen empirically; it should be roughly equal to the + // ratio of nodes in the location tree to the nodes in the + // function tree (after truncation). + markNodesForTruncation(nodes, maxNodes*4) + // We now build an intermediate tree from the marked stack + // traces. The reason is that the intermediate tree is + // substantially bigger than the final one. The intermediate + // tree is optimized for inserts and lookups, while the output + // tree is optimized for merge operations. + t := model.NewStacktraceTree(int(maxNodes)) + + // Select insert method depending on type + var treeI I + if treeI.IsLocationTree() { + insertStacktraces(t, nodes, symbols, addLocationID) + } else { + insertStacktraces(t, nodes, symbols, addFunctionNames) + } + + // Finally, we convert the stack trace tree into the function + // tree, dropping insignificant functions, and symbolizing the + // nodes (function names). + return model.TreeFromStacktraceTree[N, I](t, maxNodes, lookup) +} + +func propagateNodeValues(nodes []Node) { + for i := len(nodes) - 1; i >= 1; i-- { + if p := nodes[i].Parent; p > 0 { + nodes[p].Value += nodes[i].Value + } + } +} + +func markNodesForTruncation(nodes []Node, maxNodes int64) { + m := minValue(nodes, maxNodes) + for i := 1; i < len(nodes); i++ { + p := nodes[i].Parent + v := nodes[i].Value + // Remove previous truncation mark, potential set by the stacktrace filter + nodes[i].Location &= ^truncationMark + if v < m { + nodes[i].Location |= truncationMark + // Preserve values of truncated locations. The weight + // of the truncated chain is accounted in the parent. + if p >= 0 && nodes[p].Location&truncationMark != 0 { + continue + } + } + // Subtract the value of the location from the parent: + // by doing so we ensure that the transient nodes have zero + // weight, and then will be ignored by the tree builder. + if p >= 0 { + nodes[p].Value -= v + } + } +} + +func insertStacktraces(t *model.StacktraceTree, nodes []Node, symbols *Symbols, addLocationF addLocationFunc) { + l := int32(len(nodes)) + s := make([]int32, 0, 64) + for i := int32(1); i < l; i++ { + p := nodes[i].Parent + v := nodes[i].Value + if v > 0 && nodes[p].Location&truncationMark == 0 { + s = resolveStack(s, nodes, i, addLocationF, symbols) + t.Insert(s, v) + } + } +} + +type addLocationFunc func([]int32, int32, *Symbols) []int32 + +func addFunctionNames(dst []int32, locID int32, symbols *Symbols) []int32 { + loc := symbols.Locations[locID] + for l := 0; l < len(loc.Line); l++ { + dst = append(dst, int32(symbols.Functions[loc.Line[l].FunctionId].Name)) + } + return dst +} + +func addLocationID(dst []int32, locID int32, symbols *Symbols) []int32 { + dst = append(dst, locID) + return dst +} + +func resolveStack(dst []int32, nodes []Node, i int32, addLocationF addLocationFunc, symbols *Symbols) []int32 { + dst = dst[:0] + for i > 0 { + j := nodes[i].Location + if j&truncationMark > 0 { + dst = append(dst, sentinel) + } else { + dst = addLocationF(dst, j, symbols) + } + i = nodes[i].Parent + } + return dst +} + +func minValue(nodes []Node, maxNodes int64) int64 { + if maxNodes < 1 || maxNodes >= int64(len(nodes)) { + return 0 + } + h := make([]int64, 0, maxNodes) + for i := range nodes { + v := nodes[i].Value + if len(h) >= int(maxNodes) { + if v > h[0] { + h = minheap.Pop(h) + } else { + continue + } + } + h = minheap.Push(h, v) + } + if len(h) < int(maxNodes) { + return 0 + } + return h[0] +} diff --git a/pkg/phlaredb/symdb/resolver_tree_test.go b/pkg/phlaredb/symdb/resolver_tree_test.go index 75baf98de8..497f1200d9 100644 --- a/pkg/phlaredb/symdb/resolver_tree_test.go +++ b/pkg/phlaredb/symdb/resolver_tree_test.go @@ -4,20 +4,104 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - v1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) func Test_memory_Resolver_ResolveTree(t *testing.T) { s := newMemSuite(t, [][]string{{"testdata/profile.pb.gz"}}) expectedFingerprint := pprofFingerprint(s.profiles[0], 0) - r := NewResolver(context.Background(), s.db) - defer r.Release() - r.AddSamples(0, s.indexed[0][0].Samples) - resolved, err := r.Tree() - require.NoError(t, err) - require.Equal(t, expectedFingerprint, treeFingerprint(resolved)) + + t.Run("default", func(t *testing.T) { + r := NewResolver(context.Background(), s.db) + defer r.Release() + r.AddSamples(0, s.indexed[0][0].Samples) + resolved, err := r.Tree() + require.NoError(t, err) + require.Equal(t, expectedFingerprint, treeFingerprint(resolved)) + }) + + for _, tc := range []struct { + name string + callsite []string + stacktraceCount int + total int + }{ + { + name: "multiple stacks", + callsite: []string{ + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*scrapeLoop).run", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*Target).report", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*scrapeLoop).scrape", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*pprofWriter).writeProfile", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*cache).writeProfiles", + "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Insert", + }, + stacktraceCount: 4, + total: 2752628, + }, + { + name: "single stack", + callsite: []string{ + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*scrapeLoop).run", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*Target).report", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*scrapeLoop).scrape", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*pprofWriter).writeProfile", + "github.com/pyroscope-io/pyroscope/pkg/scrape.(*cache).writeProfiles", + "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Insert", + "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).findNodeAt", + "github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.newTrieNode", + }, + stacktraceCount: 1, + total: 417817, + }, + { + name: "no match", + callsite: []string{ + "github.com/no-match/no-match.main", + }, + stacktraceCount: 0, + total: 0, + }, + } { + t.Run("with stack trace selector/"+tc.name, func(t *testing.T) { + sts := &typesv1.StackTraceSelector{ + CallSite: make([]*typesv1.Location, len(tc.callsite)), + } + for i, name := range tc.callsite { + sts.CallSite[i] = &typesv1.Location{ + Name: name, + } + } + + r := NewResolver(context.Background(), s.db, WithResolverStackTraceSelector(sts), WithResolverMaxNodes(10)) + defer r.Release() + r.AddSamples(0, s.indexed[0][0].Samples) + resolved, err := r.Tree() + require.NoError(t, err) + + stacktraceCount := 0 + total := 0 + + resolved.IterateStacks(func(name phlaremodel.FunctionName, self int64, stack []phlaremodel.FunctionName) { + stacktraceCount++ + total += int(self) + + prefix := make([]string, len(tc.callsite)) + for i := range prefix { + prefix[i] = string(stack[len(stack)-1-i]) + } + require.Equal(t, tc.callsite, prefix, "stack prefix doesn't match") + }) + assert.Equal(t, tc.stacktraceCount, stacktraceCount) + assert.Equal(t, tc.total, total) + }) + } } func Test_block_Resolver_ResolveTree(t *testing.T) { @@ -41,9 +125,7 @@ func Benchmark_Resolver_ResolveTree_Small(b *testing.B) { } func Benchmark_Resolver_ResolveTree_Big(b *testing.B) { - s := memSuite{t: b, files: [][]string{{"testdata/big-profile.pb.gz"}}} - s.config = DefaultConfig().WithDirectory(b.TempDir()) - s.init() + s := newMemSuite(b, [][]string{{"testdata/big-profile.pb.gz"}}) samples := s.indexed[0][0].Samples b.Run("0", benchmarkResolverResolveTree(s.db, samples, 0)) b.Run("8K", benchmarkResolverResolveTree(s.db, samples, 8<<10)) @@ -63,3 +145,172 @@ func benchmarkResolverResolveTree(sym SymbolsReader, samples v1.Samples, n int64 } } } + +func Test_memory_Resolver_ResolveTree_copied_nodes(t *testing.T) { + s := newMemSuite(t, [][]string{{"testdata/big-profile.pb.gz"}}) + samples := s.indexed[0][0].Samples + + resolve := func(options ...ResolverOption) (nodes, total int64) { + r := NewResolver(context.Background(), s.db, options...) + defer r.Release() + r.AddSamples(0, samples) + resolved, err := r.Tree() + require.NoError(t, err) + resolved.FormatNodeNames(func(s phlaremodel.FunctionName) phlaremodel.FunctionName { + nodes++ + return s + }) + return nodes, resolved.Total() + } + + const maxNodes int64 = 16 << 10 + nodesFull, totalFull := resolve() + nodesTrunc, totalTrunc := resolve(WithResolverMaxNodes(maxNodes)) + // The only reason we perform this assertion is to make sure that + // truncation did take place, and the number of nodes is close to + // the target (we actually keep all nodes with top 16K values). + assert.Equal(t, int64(1585462), nodesFull) + assert.Equal(t, int64(22461), nodesTrunc) + require.Equal(t, totalFull, totalTrunc) +} + +func Test_buildTreeFromParentPointerTrees(t *testing.T) { + // The profile has the following samples: + // + // a b c f f1 f2 f3 f4 f5 + // 1 2 3 4 5 6 7 8 9 + // + // 4: a b c f + // 5: a b c f1 + // 6: a b c f1 f2 + // 8: a b c f3 f4 + // 9: a b c f3 f4 f5 + // + expectedSamples := v1.Samples{ + StacktraceIDs: []uint32{4, 5, 6, 8, 9}, + Values: []uint64{1, 1, 1, 1, 1}, + } + + // After the truncation, we expect to see the following tree + // (function f, f2, and f5 are replaced with "other"): + const maxNodes = 6 + expectedTruncatedTree := `. +└── a: self 0 total 5 + └── b: self 0 total 5 + └── c: self 0 total 5 + ├── f1: self 1 total 2 + │ └── other: self 1 total 1 + ├── f3: self 0 total 2 + │ └── f4: self 1 total 2 + │ └── other: self 1 total 1 + └── other: self 1 total 1 +` + + p := &profilev1.Profile{ + Sample: []*profilev1.Sample{ + {LocationId: []uint64{4, 3, 2, 1}, Value: []int64{1}}, + {LocationId: []uint64{5, 3, 2, 1}, Value: []int64{1}}, + {LocationId: []uint64{6, 5, 3, 2, 1}, Value: []int64{1}}, + {LocationId: []uint64{8, 7, 3, 2, 1}, Value: []int64{1}}, + {LocationId: []uint64{9, 8, 7, 3, 2, 1}, Value: []int64{1}}, + }, + StringTable: []string{ + "", "a", "b", "c", "f", "f1", "f2", "f3", "f4", "f5", + }, + } + + names := uint64(len(p.StringTable)) + for i := uint64(1); i < names; i++ { + p.Location = append(p.Location, &profilev1.Location{ + Id: i, Line: []*profilev1.Line{{FunctionId: i}}, + }) + p.Function = append(p.Function, &profilev1.Function{ + Id: i, Name: int64(i), + }) + } + + s := newMemSuite(t, nil) + const partition = 0 + indexed := s.db.WriteProfileSymbols(partition, p) + assert.Equal(t, expectedSamples, indexed[partition].Samples) + b := blockSuite{memSuite: s} + b.flush() + pr, err := b.reader.Partition(context.Background(), partition) + require.NoError(t, err) + symbols := pr.Symbols() + iterator, ok := symbols.Stacktraces.(StacktraceIDRangeIterator) + require.True(t, ok) + + for _, tc := range []struct { + name string + selector *typesv1.StackTraceSelector + expected string + }{ + { + name: "without selection", + selector: nil, + expected: expectedTruncatedTree, + }, + { + name: "with common prefix selection", + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{ + {Name: "a"}, + {Name: "b"}, + {Name: "c"}, + }, + }, + expected: expectedTruncatedTree, + }, + { + name: "with focus on truncated callsite last shown", + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{ + {Name: "a"}, + {Name: "b"}, + {Name: "c"}, + {Name: "f1"}, + }, + }, + expected: `. +└── a: self 0 total 2 + └── b: self 0 total 2 + └── c: self 0 total 2 + └── f1: self 1 total 2 + └── f2: self 1 total 1 +`, + }, + { + name: "with focus on truncated callsite", + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{ + {Name: "a"}, + {Name: "b"}, + {Name: "c"}, + {Name: "f1"}, + {Name: "f2"}, + }, + }, + expected: `. +└── a: self 0 total 1 + └── b: self 0 total 1 + └── c: self 0 total 1 + └── f1: self 0 total 1 + └── f2: self 1 total 1 +`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + appender := NewSampleAppender() + appender.AppendMany(expectedSamples.StacktraceIDs, expectedSamples.Values) + ranges := iterator.SplitStacktraceIDRanges(appender) + lookup := func(i int32) phlaremodel.FunctionName { + return phlaremodel.FunctionName(symbols.Strings[i]) + } + resolved, err := buildTreeFromParentPointerTrees[phlaremodel.FunctionName, phlaremodel.FunctionNameI](context.Background(), ranges, symbols, maxNodes, SelectStackTraces(symbols, tc.selector), lookup) + require.NoError(t, err) + + require.Equal(t, tc.expected, resolved.String()) + }) + } +} diff --git a/pkg/phlaredb/symdb/rewriter.go b/pkg/phlaredb/symdb/rewriter.go index 0216bb7bc5..503c9f4ec9 100644 --- a/pkg/phlaredb/symdb/rewriter.go +++ b/pkg/phlaredb/symdb/rewriter.go @@ -7,20 +7,29 @@ import ( lru "github.com/hashicorp/golang-lru/v2" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/slices" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/slices" ) type Rewriter struct { symdb *SymDB source SymbolsReader partitions *lru.Cache[uint64, *partitionRewriter] + observer SymbolsObserver } -func NewRewriter(w *SymDB, r SymbolsReader) *Rewriter { +type SymbolsObserver interface { + // ObserveSymbols is called once new symbols have been rewritten. This method must not modify the symbols. + // When using within a SampleObserver, Evaluate should be called first + ObserveSymbols(strings []string, functions []schemav1.InMemoryFunction, locations []schemav1.InMemoryLocation, + stacktraceValues [][]int32, stacktraceIds []uint32) +} + +func NewRewriter(w *SymDB, r SymbolsReader, o SymbolsObserver) *Rewriter { return &Rewriter{ - source: r, - symdb: w, + source: r, + symdb: w, + observer: o, } } @@ -75,10 +84,11 @@ func (r *Rewriter) newRewriter(p uint64) (*partitionRewriter, error) { var stats PartitionStats reader.WriteStats(&stats) n.stacktraces = newLookupTable[[]int32](stats.MaxStacktraceID) - n.locations = newLookupTable[*schemav1.InMemoryLocation](stats.LocationsTotal) - n.mappings = newLookupTable[*schemav1.InMemoryMapping](stats.MappingsTotal) - n.functions = newLookupTable[*schemav1.InMemoryFunction](stats.FunctionsTotal) + n.locations = newLookupTable[schemav1.InMemoryLocation](stats.LocationsTotal) + n.mappings = newLookupTable[schemav1.InMemoryMapping](stats.MappingsTotal) + n.functions = newLookupTable[schemav1.InMemoryFunction](stats.FunctionsTotal) n.strings = newLookupTable[string](stats.StringsTotal) + n.observer = r.observer return n, nil } @@ -89,11 +99,13 @@ type partitionRewriter struct { reader PartitionReader stacktraces *lookupTable[[]int32] - locations *lookupTable[*schemav1.InMemoryLocation] - mappings *lookupTable[*schemav1.InMemoryMapping] - functions *lookupTable[*schemav1.InMemoryFunction] + locations *lookupTable[schemav1.InMemoryLocation] + mappings *lookupTable[schemav1.InMemoryMapping] + functions *lookupTable[schemav1.InMemoryFunction] strings *lookupTable[string] current []*schemav1.Stacktrace + + observer SymbolsObserver } func (p *partitionRewriter) reset() { @@ -128,8 +140,15 @@ func (p *partitionRewriter) populateUnresolved(stacktraceIDs []uint32) error { for unresolvedLocs.Next() { location := p.src.Locations[unresolvedLocs.At()] location.MappingId = p.mappings.tryLookup(location.MappingId) - for j, line := range location.Line { - location.Line[j].FunctionId = p.functions.tryLookup(line.FunctionId) + if len(p.src.Functions) == 0 { + // Line records cannot reference any function and are dropped, + // but the location itself must be kept: not-yet-symbolized + // native partitions consist entirely of line-less locations. + location.Line = nil + } else { + for j, line := range location.Line { + location.Line[j].FunctionId = p.functions.tryLookup(line.FunctionId) + } } unresolvedLocs.setValue(location) } @@ -164,25 +183,25 @@ func (p *partitionRewriter) appendRewrite(stacktraces []uint32) error { p.dst.AppendStrings(p.strings.buf, p.strings.values) p.strings.updateResolved() - for _, v := range p.functions.values { - v.Name = p.strings.lookupResolved(v.Name) - v.Filename = p.strings.lookupResolved(v.Filename) - v.SystemName = p.strings.lookupResolved(v.SystemName) + for i := range p.functions.values { + p.functions.values[i].Name = p.strings.lookupResolved(p.functions.values[i].Name) + p.functions.values[i].Filename = p.strings.lookupResolved(p.functions.values[i].Filename) + p.functions.values[i].SystemName = p.strings.lookupResolved(p.functions.values[i].SystemName) } p.dst.AppendFunctions(p.functions.buf, p.functions.values) p.functions.updateResolved() - for _, v := range p.mappings.values { - v.BuildId = p.strings.lookupResolved(v.BuildId) - v.Filename = p.strings.lookupResolved(v.Filename) + for i := range p.mappings.values { + p.mappings.values[i].BuildId = p.strings.lookupResolved(p.mappings.values[i].BuildId) + p.mappings.values[i].Filename = p.strings.lookupResolved(p.mappings.values[i].Filename) } p.dst.AppendMappings(p.mappings.buf, p.mappings.values) p.mappings.updateResolved() - for _, v := range p.locations.values { - v.MappingId = p.mappings.lookupResolved(v.MappingId) - for j, line := range v.Line { - v.Line[j].FunctionId = p.functions.lookupResolved(line.FunctionId) + for i := range p.locations.values { + p.locations.values[i].MappingId = p.mappings.lookupResolved(p.locations.values[i].MappingId) + for j, line := range p.locations.values[i].Line { + p.locations.values[i].Line[j].FunctionId = p.functions.lookupResolved(line.FunctionId) } } p.dst.AppendLocations(p.locations.buf, p.locations.values) @@ -200,6 +219,10 @@ func (p *partitionRewriter) appendRewrite(stacktraces []uint32) error { stacktraces[i] = p.stacktraces.lookupResolved(v) } + if p.observer != nil { + p.observer.ObserveSymbols(p.dst.strings.slice, p.dst.functions.slice, p.dst.locations.slice, p.stacktraces.values, p.stacktraces.buf) + } + return nil } @@ -249,9 +272,9 @@ func (p *partitionRewriter) InsertStacktrace(stacktrace uint32, locations []int3 func cloneSymbolsPartially(x *Symbols) *Symbols { n := Symbols{ Stacktraces: x.Stacktraces, - Locations: make([]*schemav1.InMemoryLocation, len(x.Locations)), - Mappings: make([]*schemav1.InMemoryMapping, len(x.Mappings)), - Functions: make([]*schemav1.InMemoryFunction, len(x.Functions)), + Locations: make([]schemav1.InMemoryLocation, len(x.Locations)), + Mappings: make([]schemav1.InMemoryMapping, len(x.Mappings)), + Functions: make([]schemav1.InMemoryFunction, len(x.Functions)), Strings: x.Strings, } for i, l := range x.Locations { diff --git a/pkg/phlaredb/symdb/rewriter_test.go b/pkg/phlaredb/symdb/rewriter_test.go index 812a6458e6..05da7fbc94 100644 --- a/pkg/phlaredb/symdb/rewriter_test.go +++ b/pkg/phlaredb/symdb/rewriter_test.go @@ -1,9 +1,14 @@ package symdb import ( + "context" + "slices" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ) func Test_lookupTable(t *testing.T) { @@ -98,3 +103,88 @@ func Test_lookupTable(t *testing.T) { assert.Len(t, dst, 7) assert.NotContains(t, dst, "seven") } + +// Location addresses must survive the rewrite: a partition with an empty +// functions table — a native profile that has not been symbolized, where +// every location is line-less — used to have all its locations rewritten +// as zero values, permanently losing the addresses at compaction. +func Test_Rewriter_location_addresses(t *testing.T) { + for _, tc := range []struct { + description string + profile *profilev1.Profile + expected []uint64 + }{ + { + description: "partition without functions", + profile: linelessLocationsProfile(), + expected: []uint64{0x1500, 0x3c5a}, + }, + { + description: "line-less location in a partition with functions", + profile: mixedLocationsProfile(), + expected: []uint64{0x3c5a}, + }, + } { + t.Run(tc.description, func(t *testing.T) { + src := newMemSuite(t, nil) + indexed := src.db.WriteProfileSymbols(0, tc.profile) + require.NotEmpty(t, indexed) + + dst := NewSymDB(nil) + rw := NewRewriter(dst, src.db, nil) + for _, p := range indexed { + ids := slices.Clone(p.Samples.StacktraceIDs) + require.NoError(t, rw.Rewrite(0, ids)) + } + + pr, err := dst.Partition(context.Background(), 0) + require.NoError(t, err) + addresses := make([]uint64, 0, len(pr.Symbols().Locations)) + for _, loc := range pr.Symbols().Locations { + addresses = append(addresses, loc.Address) + } + for _, addr := range tc.expected { + assert.Contains(t, addresses, addr) + } + }) + } +} + +func linelessLocationsProfile() *profilev1.Profile { + return &profilev1.Profile{ + StringTable: []string{"", "libfoo.so", "build-id-f00"}, + Mapping: []*profilev1.Mapping{ + {Id: 1, MemoryLimit: 0x1000000, Filename: 1, BuildId: 2}, + }, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Address: 0x1500}, + {Id: 2, MappingId: 1, Address: 0x3c5a}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100}}, + {LocationId: []uint64{2}, Value: []int64{200}}, + {LocationId: []uint64{1, 2}, Value: []int64{3}}, + }, + SampleType: []*profilev1.ValueType{{Type: 0, Unit: 0}}, + } +} + +func mixedLocationsProfile() *profilev1.Profile { + return &profilev1.Profile{ + StringTable: []string{"", "libfoo.so", "build-id-f00", "main", "main.go"}, + Mapping: []*profilev1.Mapping{ + {Id: 1, MemoryLimit: 0x1000000, Filename: 1, BuildId: 2}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 3, Filename: 4}, + }, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 5}}}, + {Id: 2, MappingId: 1, Address: 0x3c5a}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{2, 1}, Value: []int64{77}}, + }, + SampleType: []*profilev1.ValueType{{Type: 0, Unit: 0}}, + } +} diff --git a/pkg/phlaredb/symdb/sample_appender.go b/pkg/phlaredb/symdb/sample_appender.go new file mode 100644 index 0000000000..32033a3c26 --- /dev/null +++ b/pkg/phlaredb/symdb/sample_appender.go @@ -0,0 +1,165 @@ +package symdb + +import ( + "slices" + + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +// SampleAppender is a dynamic data structure that accumulates +// samples, by summing them up by stack trace ID. +// +// It has two underlying implementations: +// - map: a hash table is used for small sparse data sets (16k by default). +// This representation is optimal for small profiles, like span profile, +// or a short time range profile of a specific service/series. +// - chunked sparse set: stack trace IDs serve as indices in a sparse set. +// Provided that the stack trace IDs are dense (as they point to the node +// index in the parent pointer tree), this representation is significantly +// more performant, but may require more space, if the stack trace IDs set +// is very sparse. In order to reduce memory consumption, the set is split +// into chunks (16k by default), that are allocated once at least one ID +// matches the chunk range. In addition, values are ordered by stack trace +// ID without being sorted explicitly. +type SampleAppender struct { + // Max number of elements in the map. + // Once the limit is exceeded, values + // are migrated to the chunked set. + maxMapSize uint32 + hashmap map[uint32]uint64 + chunkSize uint32 // Must be a power of 2. + chunks [][]uint64 + size int + + Append func(stacktrace uint32, value uint64) + AppendMany func(stacktraces []uint32, values []uint64) +} + +// Hashmap is used for small data sets (<= 16k elements, be default). +// Once the limit is exceeded, the data is migrated to the chunked set. +// Chunk size is 16k (128KiB) by default. +const ( + defaultSampleAppenderSize = 16 << 10 + defaultChunkSize = 16 << 10 +) + +func NewSampleAppender() *SampleAppender { + return NewSampleAppenderSize(defaultSampleAppenderSize, defaultChunkSize) +} + +func NewSampleAppenderSize(maxMapSize, chunkSize uint32) *SampleAppender { + if chunkSize == 0 || (chunkSize&(chunkSize-1)) != 0 { + panic("chunk size must be a power of 2") + } + s := &SampleAppender{ + chunkSize: chunkSize, + maxMapSize: maxMapSize, + hashmap: make(map[uint32]uint64), + } + s.Append = s.mapAppend + s.AppendMany = s.mapAppendMany + return s +} + +func (s *SampleAppender) mapAppend(stacktrace uint32, value uint64) { + if len(s.hashmap) < int(s.maxMapSize) { + s.hashmap[stacktrace] += value + return + } + s.migrate() + s.Append(stacktrace, value) +} + +func (s *SampleAppender) mapAppendMany(stacktraces []uint32, values []uint64) { + if len(s.hashmap)+len(stacktraces) < int(s.maxMapSize) { + for i, stacktrace := range stacktraces { + if v := values[i]; v != 0 && stacktrace != 0 { + s.hashmap[stacktrace] += v + } + } + return + } + s.migrate() + s.AppendMany(stacktraces, values) +} + +func (s *SampleAppender) migrate() { + s.Append = s.setAppend + s.AppendMany = s.setAppendMany + for k, v := range s.hashmap { + s.Append(k, v) + } + s.hashmap = nil +} + +func (s *SampleAppender) setAppend(stacktrace uint32, value uint64) { + if value == 0 || stacktrace == 0 { + return + } + ci := stacktrace / s.chunkSize + vi := stacktrace & (s.chunkSize - 1) // stacktrace % s.chunkSize + if x := int(ci) + 1; x > len(s.chunks) { + s.chunks = slices.Grow(s.chunks, x) + s.chunks = s.chunks[:x] + } + c := s.chunks[ci] + if cap(c) == 0 { + c = make([]uint64, s.chunkSize) + s.chunks[ci] = c + } + v := c[vi] + c[vi] += value + if v == 0 { + s.size++ + } +} + +func (s *SampleAppender) setAppendMany(stacktraces []uint32, values []uint64) { + // Inlined Append. + for i, stacktrace := range stacktraces { + value := values[i] + if value == 0 || stacktrace == 0 { + continue + } + ci := stacktrace / s.chunkSize + vi := stacktrace & (s.chunkSize - 1) // stacktrace % s.chunkSize + if x := int(ci) + 1; x > len(s.chunks) { + s.chunks = slices.Grow(s.chunks, x) + s.chunks = s.chunks[:x] + } + c := s.chunks[ci] + if cap(c) == 0 { + c = make([]uint64, s.chunkSize) + s.chunks[ci] = c + } + v := c[vi] + c[vi] += value + if v == 0 { + s.size++ + } + } +} + +func (s *SampleAppender) Len() int { return s.size + len(s.hashmap) } + +func (s *SampleAppender) Samples() v1.Samples { + if len(s.hashmap) > 0 { + return v1.NewSamplesFromMap(s.hashmap) + } + samples := v1.NewSamples(s.Len()) + chunks := uint32(len(s.chunks)) + x := 0 + for i := uint32(0); i < chunks; i++ { + values := uint32(len(s.chunks[i])) + for j := uint32(0); j < values; j++ { + if v := s.chunks[i][j]; v != 0 { + if sid := i*s.chunkSize + j; sid > 0 { + samples.StacktraceIDs[x] = sid + samples.Values[x] = v + } + x++ + } + } + } + return samples +} diff --git a/pkg/phlaredb/symdb/sample_appender_test.go b/pkg/phlaredb/symdb/sample_appender_test.go new file mode 100644 index 0000000000..3cc75ed5ac --- /dev/null +++ b/pkg/phlaredb/symdb/sample_appender_test.go @@ -0,0 +1,57 @@ +package symdb + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +func Test_SampleAppender(t *testing.T) { + for _, test := range []struct { + description string + assert func(*testing.T, *SampleAppender) + }{ + { + description: "empty appender", + assert: func(t *testing.T, a *SampleAppender) { + assert.Equal(t, 0, a.Len()) + }, + }, + { + description: "hashtable", + assert: func(t *testing.T, a *SampleAppender) { + a.Append(1, 1) + a.AppendMany([]uint32{1337, 42}, []uint64{1, 1}) + a.Append(1337, 1) + assert.Equal(t, 3, a.Len()) + assert.Equal(t, 3, len(a.hashmap)) + assert.Equal(t, schemav1.Samples{ + StacktraceIDs: []uint32{1, 42, 1337}, + Values: []uint64{1, 1, 2}, + }, a.Samples()) + }, + }, + { + description: "sparse", + assert: func(t *testing.T, a *SampleAppender) { + a.Append(4, 1) + a.Append(1, 1) + a.AppendMany([]uint32{20, 40}, []uint64{1, 1}) + a.Append(10, 1) + a.Append(40, 1) + assert.Equal(t, 5, a.Len()) + assert.Equal(t, 0, len(a.hashmap)) + assert.Equal(t, 11, len(a.chunks)) + assert.Equal(t, schemav1.Samples{ + StacktraceIDs: []uint32{1, 4, 10, 20, 40}, + Values: []uint64{1, 1, 1, 1, 2}, + }, a.Samples()) + }, + }, + } { + a := NewSampleAppenderSize(4, 4) + test.assert(t, a) + } +} diff --git a/pkg/phlaredb/symdb/stacktrace_range.go b/pkg/phlaredb/symdb/stacktrace_range.go new file mode 100644 index 0000000000..00678f9321 --- /dev/null +++ b/pkg/phlaredb/symdb/stacktrace_range.go @@ -0,0 +1,92 @@ +package symdb + +import ( + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +// StacktraceIDRange represents a range of stack trace +// identifiers, sharing the same parent pointer tree. +type StacktraceIDRange struct { + // Stack trace identifiers that belong to the range. + // Identifiers are relative to the range Offset(). + IDs []uint32 + chunk uint32 // Chunk index. + m uint32 // Max nodes per chunk. + // Parent pointer tree, the stack traces refer to. + // A stack trace identifier is the index of the node + // in the tree. Optional. + ParentPointerTree + // Samples matching the stack trace range. Optional. + schemav1.Samples + // TODO(kolesnikovae): use SampleAppender instead of Samples. + // This will allow to avoid copying the samples. +} + +// SetNodeValues sets the values of the provided Samples to the matching +// parent pointer tree nodes. +func (r *StacktraceIDRange) SetNodeValues(dst []Node) { + for i := 0; i < len(r.IDs); i++ { + x := r.StacktraceIDs[i] + v := int64(r.Values[i]) + if x > 0 && v > 0 && dst[x].Location&truncationMark == 0 { + dst[x].Value = v + } + } +} + +// Offset returns the lowest identifier of the range. +// Identifiers are relative to the range offset. +func (r *StacktraceIDRange) Offset() uint32 { return r.m * r.chunk } + +// SplitStacktraces splits the range of stack trace IDs by limit n into +// sub-ranges matching to the corresponding chunks and shifts the values +// accordingly. Note that the input s is modified in place. +// +// stack trace ID 0 is reserved and is not expected at the input. +// stack trace ID % max_nodes == 0 is not expected as well. +func SplitStacktraces(s []uint32, n uint32) []*StacktraceIDRange { + if s[len(s)-1] < n || n == 0 { + // Fast path, just one chunk: the highest stack trace ID + // is less than the chunk size, or the size is not limited. + // It's expected that in most cases we'll end up here. + return []*StacktraceIDRange{{m: n, IDs: s}} + } + + var ( + loi int + lov = (s[0] / n) * n // Lowest possible value for the current chunk. + hiv = lov + n // Highest possible value for the current chunk. + p uint32 // Previous value (to derive chunk index). + // 16 chunks should be more than enough in most cases. + cs = make([]*StacktraceIDRange, 0, 16) + ) + + for i, v := range s { + if v < hiv { + // The stack belongs to the current chunk. + s[i] -= lov + p = v + continue + } + lov = (v / n) * n + hiv = lov + n + s[i] -= lov + cs = append(cs, &StacktraceIDRange{ + chunk: p / n, + IDs: s[loi:i], + m: n, + }) + loi = i + p = v + } + + if t := s[loi:]; len(t) > 0 { + cs = append(cs, &StacktraceIDRange{ + chunk: p / n, + IDs: t, + m: n, + }) + } + + return cs +} diff --git a/pkg/phlaredb/symdb/stacktrace_range_test.go b/pkg/phlaredb/symdb/stacktrace_range_test.go new file mode 100644 index 0000000000..77dcea4f6f --- /dev/null +++ b/pkg/phlaredb/symdb/stacktrace_range_test.go @@ -0,0 +1,80 @@ +package symdb + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_SplitStacktraces(t *testing.T) { + type testCase struct { + description string + maxNodes uint32 + stacktraces []uint32 + expected []*StacktraceIDRange + } + + testCases := []testCase{ + { + description: "no limit", + stacktraces: []uint32{234, 1234, 2345}, + expected: []*StacktraceIDRange{ + {IDs: []uint32{234, 1234, 2345}}, + }, + }, + { + description: "one chunk", + maxNodes: 4, + stacktraces: []uint32{1, 2, 3}, + expected: []*StacktraceIDRange{ + {m: 4, chunk: 0, IDs: []uint32{1, 2, 3}}, + }, + }, + { + description: "one chunk shifted", + maxNodes: 4, + stacktraces: []uint32{401, 402}, + expected: []*StacktraceIDRange{ + {m: 4, chunk: 100, IDs: []uint32{1, 2}}, + }, + }, + { + description: "multiple shards", + maxNodes: 4, + stacktraces: []uint32{1, 2, 5, 7, 11, 13, 14, 15, 17, 41, 42, 43, 83, 85, 86}, + // : []uint32{1, 2, 1, 3, 3, 1, 2, 3, 1, 1, 2, 3, 3, 1, 2}, + // : []uint32{0, 0, 1, 1, 2, 3, 3, 3, 4, 10, 10, 10, 20, 21, 21}, + expected: []*StacktraceIDRange{ + {m: 4, chunk: 0, IDs: []uint32{1, 2}}, + {m: 4, chunk: 1, IDs: []uint32{1, 3}}, + {m: 4, chunk: 2, IDs: []uint32{3}}, + {m: 4, chunk: 3, IDs: []uint32{1, 2, 3}}, + {m: 4, chunk: 4, IDs: []uint32{1}}, + {m: 4, chunk: 10, IDs: []uint32{1, 2, 3}}, + {m: 4, chunk: 20, IDs: []uint32{3}}, + {m: 4, chunk: 21, IDs: []uint32{1, 2}}, + }, + }, + { + description: "multiple shards exact", + maxNodes: 4, + stacktraces: []uint32{1, 2, 5, 7, 11, 13, 14, 15, 17, 41, 42, 43, 83, 85, 86, 87}, + expected: []*StacktraceIDRange{ + {m: 4, chunk: 0, IDs: []uint32{1, 2}}, + {m: 4, chunk: 1, IDs: []uint32{1, 3}}, + {m: 4, chunk: 2, IDs: []uint32{3}}, + {m: 4, chunk: 3, IDs: []uint32{1, 2, 3}}, + {m: 4, chunk: 4, IDs: []uint32{1}}, + {m: 4, chunk: 10, IDs: []uint32{1, 2, 3}}, + {m: 4, chunk: 20, IDs: []uint32{3}}, + {m: 4, chunk: 21, IDs: []uint32{1, 2, 3}}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + assert.Equal(t, tc.expected, SplitStacktraces(tc.stacktraces, tc.maxNodes)) + }) + } +} diff --git a/pkg/phlaredb/symdb/stacktrace_selection.go b/pkg/phlaredb/symdb/stacktrace_selection.go new file mode 100644 index 0000000000..c3bbe6b5d8 --- /dev/null +++ b/pkg/phlaredb/symdb/stacktrace_selection.go @@ -0,0 +1,186 @@ +package symdb + +import ( + "github.com/parquet-go/parquet-go" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +// CallSiteValues represents statistics associated with a call tree node. +type CallSiteValues struct { + // Flat is the sum of sample values directly attributed to the node. + Flat uint64 + // Total is the total sum of sample values attributed to the node and + // its descendants. + Total uint64 + // LocationFlat is the sum of sample values directly attributed to the + // node location, irrespectively of the call chain. + LocationFlat uint64 + // LocationTotal is the total sum of sample values attributed to the + // node location and its descendants, irrespectively of the call chain. + LocationTotal uint64 +} + +// stackTraceLocationRelation represents the relation between a stack trace +// and a location, according to the stack trace selector parameters. +type stackTraceLocationRelation uint8 + +const ( + // relationSubtree indicates whether the stack trace belongs + // to the callSite specified by the stack trace selector. + relationSubtree stackTraceLocationRelation = 1 << iota + // relationLeaf specifies that the stack trace leaf is the + // location specified by the stack trace selector, + // irrespectively of the call chain. + relationLeaf + // relationNode specifies that the stack trace includes + // the location specified by the stack trace selector, + // irrespectively of the call chain. + relationNode +) + +type SelectedStackTraces struct { + symbols *Symbols + // Go PGO filter. + gopgo *typesv1.GoPGO + // Call site filter + relations map[uint32]stackTraceLocationRelation + callSiteSelector []*typesv1.Location + callSite []string // call site strings in the original order. + location string // stack trace leaf function. + depth uint32 + buf []uint64 + // Function ID => name. The lookup table is used to + // avoid unnecessary indirect accesses through the + // strings[functions[id].Name] path. Instead, the + // name can be resolved directly funcNames[id]. + funcNames []string +} + +func SelectStackTraces(symbols *Symbols, selector *typesv1.StackTraceSelector) *SelectedStackTraces { + x := &SelectedStackTraces{ + symbols: symbols, + callSiteSelector: selector.GetCallSite(), + gopgo: selector.GetGoPgo(), + } + x.callSite = callSiteFunctions(x.callSiteSelector) + if x.depth = uint32(len(x.callSite)); x.depth > 0 { + x.location = x.callSite[x.depth-1] + } + x.funcNames = make([]string, len(symbols.Functions)) + for i, f := range symbols.Functions { + x.funcNames[i] = symbols.Strings[f.Name] + } + return x +} + +// HasValidCallSite reports whether any stack traces match the selector. +// An empty selector results in a valid empty selection. +func (x *SelectedStackTraces) HasValidCallSite() bool { + return len(x.callSiteSelector) == 0 || len(x.callSiteSelector) != 0 && len(x.callSite) != 0 +} + +// CallSiteValues writes the call site statistics for +// the selected stack traces and the given set of samples. +func (x *SelectedStackTraces) CallSiteValues(values *CallSiteValues, samples schemav1.Samples) { + *values = CallSiteValues{} + if x.depth == 0 { + return + } + if x.relations == nil { + // relations will grow to the size of the number of stack traces: + // if a stack trace does not belong to the selection, we still + // have to memoize the negative result. + x.relations = make(map[uint32]stackTraceLocationRelation, len(x.symbols.Locations)) + } + for i, sid := range samples.StacktraceIDs { + v := samples.Values[i] + r, ok := x.relations[sid] + if !ok { + x.buf = x.symbols.Stacktraces.LookupLocations(x.buf, sid) + r = x.appendStackTrace(x.buf) + x.relations[sid] = r + } + x.write(values, v, r) + } +} + +// CallSiteValuesParquet is identical to CallSiteValues +// but accepts raw parquet values instead of samples. +func (x *SelectedStackTraces) CallSiteValuesParquet(values *CallSiteValues, stacktraceID, value []parquet.Value) { + *values = CallSiteValues{} + if x.depth == 0 { + return + } + if x.relations == nil { + // relations will grow to the size of the number of stack traces: + // if a stack trace does not belong to the selection, we still + // have to memoize the negative result. + x.relations = make(map[uint32]stackTraceLocationRelation, len(x.symbols.Locations)) + } + for i, pv := range stacktraceID { + sid := pv.Uint32() + v := value[i].Uint64() + r, ok := x.relations[sid] + if !ok { + x.buf = x.symbols.Stacktraces.LookupLocations(x.buf, sid) + r = x.appendStackTrace(x.buf) + x.relations[sid] = r + } + x.write(values, v, r) + } +} + +func (x *SelectedStackTraces) write(m *CallSiteValues, v uint64, r stackTraceLocationRelation) { + s := uint64(r & relationSubtree) + l := uint64(r&relationLeaf) >> 1 + n := uint64(r&relationNode) >> 2 + m.LocationTotal += v * (n | l) + m.LocationFlat += v * l + m.Total += v * s + m.Flat += v * s * l +} + +func (x *SelectedStackTraces) appendStackTrace(locations []uint64) stackTraceLocationRelation { + if len(locations) == 0 { + return 0 + } + var n uint32 // Number of times callSite root function seen. + var pos uint32 + var l uint32 + for i := len(locations) - 1; i >= 0; i-- { + lines := x.symbols.Locations[locations[i]].Line + for j := len(lines) - 1; j >= 0; j-- { + f := lines[j].FunctionId + if x.location == x.funcNames[f] { + n++ + } + if pos < x.depth && pos == l && x.callSite[pos] == x.funcNames[f] { + pos++ + } + l++ + } + } + if n == 0 { + return 0 + } + var isLeaf uint32 + leaf := x.symbols.Locations[locations[0]].Line[0] + if x.location == x.funcNames[leaf.FunctionId] { + isLeaf = 1 + } + var inSubtree uint32 + if pos >= x.depth { + inSubtree = 1 + } + return stackTraceLocationRelation(inSubtree | isLeaf<<1 | (1-isLeaf)<<2) +} + +func callSiteFunctions(locations []*typesv1.Location) []string { + callSite := make([]string, len(locations)) + for i, loc := range locations { + callSite[i] = loc.Name + } + return callSite +} diff --git a/pkg/phlaredb/symdb/stacktrace_selection_test.go b/pkg/phlaredb/symdb/stacktrace_selection_test.go new file mode 100644 index 0000000000..8d2882727b --- /dev/null +++ b/pkg/phlaredb/symdb/stacktrace_selection_test.go @@ -0,0 +1,161 @@ +package symdb + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/slices" +) + +func Test_StackTraceFilter(t *testing.T) { + profile := &googlev1.Profile{ + StringTable: []string{"", "foo", "bar", "baz", "qux"}, + Function: []*googlev1.Function{ + {Id: 1, Name: 1}, + {Id: 2, Name: 2}, + {Id: 3, Name: 3}, + {Id: 4, Name: 4}, + }, + Mapping: []*googlev1.Mapping{{Id: 1}}, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 1, Line: 1}}}, // foo + {Id: 2, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 1}}}, // bar:1 + {Id: 3, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 2, Line: 2}}}, // bar:2 + {Id: 4, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 3, Line: 1}}}, // baz + {Id: 5, MappingId: 1, Line: []*googlev1.Line{{FunctionId: 4, Line: 1}}}, // qux + }, + Sample: []*googlev1.Sample{ + {LocationId: []uint64{4, 2, 1}, Value: []int64{1}}, // foo, bar:1, baz + {LocationId: []uint64{3, 1}, Value: []int64{1}}, // foo, bar:2 + {LocationId: []uint64{4, 1}, Value: []int64{1}}, // foo, baz + {LocationId: []uint64{5}, Value: []int64{1}}, // qux + + {LocationId: []uint64{2}, Value: []int64{1}}, // bar:1 + {LocationId: []uint64{1, 2}, Value: []int64{1}}, // bar:1, foo + {LocationId: []uint64{3}, Value: []int64{1}}, // bar:2 + {LocationId: []uint64{1, 3}, Value: []int64{1}}, // bar:2, foo + }, + } + + db := NewSymDB(DefaultConfig().WithDirectory(t.TempDir())) + w := db.WriteProfileSymbols(0, profile) + + p, err := db.Partition(context.Background(), 0) + require.NoError(t, err) + symbols := p.Symbols() + + type testCase struct { + selector *typesv1.StackTraceSelector + expected CallSiteValues + } + + testCases := []testCase{ + { + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{{Name: "foo"}}, + }, + expected: CallSiteValues{ + Flat: 0, + Total: 3, + LocationFlat: 2, + LocationTotal: 5, + }, + }, + { + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{{Name: "bar"}}, + }, + expected: CallSiteValues{ + Flat: 2, + Total: 4, + LocationFlat: 3, + LocationTotal: 6, + }, + }, + { + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{{Name: "foo"}, {Name: "bar"}}, + }, + expected: CallSiteValues{ + Flat: 1, + Total: 2, + LocationFlat: 3, + LocationTotal: 6, + }, + }, + { + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{{Name: "foo"}, {Name: "bar"}, {Name: "baz"}}, + }, + expected: CallSiteValues{ + Flat: 1, + Total: 1, + LocationFlat: 2, + LocationTotal: 2, + }, + }, + { + selector: &typesv1.StackTraceSelector{ + CallSite: []*typesv1.Location{{Name: "foo"}, {Name: "bar"}, {Name: "baz"}, {Name: "qux"}}, + }, + expected: CallSiteValues{ + Flat: 0, + Total: 0, + LocationFlat: 1, + LocationTotal: 1, + }, + }, + {selector: &typesv1.StackTraceSelector{}}, + {}, + } + + for _, tc := range testCases { + selection := SelectStackTraces(symbols, tc.selector) + var values CallSiteValues + selection.CallSiteValues(&values, w[0].Samples) + assert.Equal(t, tc.expected, values, "selector: %+v", tc.selector) + } +} + +func Benchmark_StackTraceFilter(b *testing.B) { + s := memSuite{t: b, files: [][]string{{"testdata/big-profile.pb.gz"}}} + s.config = DefaultConfig().WithDirectory(b.TempDir()) + s.init() + samples := s.indexed[0][0].Samples + + prt, err := s.db.Partition(context.Background(), 0) + require.NoError(b, err) + symbols := prt.Symbols() + + p := s.profiles[0] + stack := p.Sample[len(p.Sample)/3].LocationId + selector := buildStackTraceSelector(p, stack[len(stack)/10:]) + var values CallSiteValues + + b.ReportAllocs() + b.ResetTimer() + + selection := SelectStackTraces(symbols, selector) + for i := 0; i < b.N; i++ { + selection.CallSiteValues(&values, samples) + } +} + +func buildStackTraceSelector(p *googlev1.Profile, locs []uint64) *typesv1.StackTraceSelector { + var selector typesv1.StackTraceSelector + for _, n := range locs { + for _, l := range p.Location[n-1].Line { + fn := p.Function[l.FunctionId-1] + selector.CallSite = append(selector.CallSite, &typesv1.Location{ + Name: p.StringTable[fn.Name], + }) + } + } + slices.Reverse(selector.CallSite) + return &selector +} diff --git a/pkg/phlaredb/symdb/stacktrace_tree.go b/pkg/phlaredb/symdb/stacktrace_tree.go index d4cc9ef749..8a3c7e44ac 100644 --- a/pkg/phlaredb/symdb/stacktrace_tree.go +++ b/pkg/phlaredb/symdb/stacktrace_tree.go @@ -6,8 +6,6 @@ import ( "unsafe" "github.com/dgryski/go-groupvarint" - - "github.com/grafana/pyroscope/pkg/util/math" ) const ( @@ -116,6 +114,14 @@ func (t *stacktraceTree) resolveUint64(dst []uint64, id uint32) []uint64 { return dst } +func (t *stacktraceTree) Nodes() []Node { + dst := make([]Node, len(t.nodes)) + for i := 0; i < len(dst) && i < len(t.nodes); i++ { // BCE + dst[i] = Node{Parent: t.nodes[i].p, Location: t.nodes[i].r} + } + return dst +} + const ( maxGroupSize = 17 // 4 * uint32 + control byte // minGroupSize = 5 // 4 * byte + control byte @@ -145,10 +151,10 @@ func newParentPointerTree(size uint32) *parentPointerTree { } func (t *parentPointerTree) resolve(dst []int32, id uint32) []int32 { + dst = dst[:0] if id >= uint32(len(t.nodes)) { return dst } - dst = dst[:0] n := t.nodes[id] for n.p >= 0 { dst = append(dst, n.r) @@ -158,10 +164,10 @@ func (t *parentPointerTree) resolve(dst []int32, id uint32) []int32 { } func (t *parentPointerTree) resolveUint64(dst []uint64, id uint32) []uint64 { + dst = dst[:0] if id >= uint32(len(t.nodes)) { return dst } - dst = dst[:0] n := t.nodes[id] for n.p >= 0 { dst = append(dst, uint64(n.r)) @@ -170,6 +176,45 @@ func (t *parentPointerTree) resolveUint64(dst []uint64, id uint32) []uint64 { return dst } +func (t *parentPointerTree) Nodes() []Node { + dst := make([]Node, len(t.nodes)) + for i := 0; i < len(dst) && i < len(t.nodes); i++ { // BCE + dst[i] = Node{Parent: t.nodes[i].p, Location: t.nodes[i].r} + } + return dst +} + +func (t *parentPointerTree) toStacktraceTree() *stacktraceTree { + l := int32(len(t.nodes)) + x := stacktraceTree{nodes: make([]node, l)} + x.nodes[0] = node{ + p: sentinel, + fc: sentinel, + ns: sentinel, + } + lc := make([]int32, len(t.nodes)) + var s int32 + for i := int32(1); i < l; i++ { + n := t.nodes[i] + x.nodes[i] = node{ + p: n.p, + r: n.r, + fc: sentinel, + ns: sentinel, + } + // Swap the last child of the parent with self. + // If this is the first child, update the parent. + // Otherwise, update the sibling. + s, lc[n.p] = lc[n.p], i + if s == 0 { + x.nodes[n.p].fc = i + } else { + x.nodes[s].ns = i + } + } + return &x +} + // ReadFrom decodes parent pointer tree from the reader. // The tree must have enough nodes. func (t *parentPointerTree) ReadFrom(r io.Reader) (int64, error) { @@ -260,6 +305,9 @@ func (d *treeDecoder) unmarshal(t *parentPointerTree, r io.Reader) error { } eof = true } + // len(b) is always >= b.Buffered(), + // therefore Discard does not invalidate + // the buffer. if _, err = buf.Discard(len(b)); err != nil { return err } @@ -271,13 +319,15 @@ func (d *treeDecoder) unmarshal(t *parentPointerTree, r io.Reader) error { // group buffer, whichever is smaller. xn := len(t.nodes) - np // remaining nodes // Note that g should always be a multiple of 4. - g = g[:math.Min((xn+xn%2)*2, d.groupBuffer)] - var gp int - + g = g[:min((xn+xn%2)*2, d.groupBuffer)] + if len(g)%4 != 0 { + return io.ErrUnexpectedEOF + } // Check if there is a remainder. If this is the case, // decode the group and advance gp. + var gp int if len(rb) > 0 { - // It's expected that r contains a single complete group. + // It's expected that rb contains a single complete group. m := groupvarint.BytesUsed[rb[0]] - len(rb) if m >= (len(b) + len(rb)) { return io.ErrUnexpectedEOF @@ -295,12 +345,15 @@ func (d *treeDecoder) unmarshal(t *parentPointerTree, r io.Reader) error { // Re-fill g. gi, n, rn := decodeU32Groups(g[gp:], b[read:]) gp += gi - read += n + rn // Mark remainder bytes as read, we copy them. + read += n + rn // Mark the remaining bytes as read; we copy them. if rn > 0 { // If there is a remainder, it is copied and decoded on // the next Peek. This should not be possible with eof. rb = append(rb, b[len(b)-rn:]...) } + if len(g) == 0 && len(rb) == 0 { + break + } // g is full, or no more data in buf. for i := 0; i < len(g[:gp])-1; i += 2 { diff --git a/pkg/phlaredb/symdb/stacktrace_tree_test.go b/pkg/phlaredb/symdb/stacktrace_tree_test.go index 83b2dd09f2..8747823827 100644 --- a/pkg/phlaredb/symdb/stacktrace_tree_test.go +++ b/pkg/phlaredb/symdb/stacktrace_tree_test.go @@ -3,12 +3,13 @@ package symdb import ( "bytes" "math/rand" + "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) func Test_stacktrace_tree_encoding(t *testing.T) { @@ -88,7 +89,6 @@ func Test_stacktrace_tree_encoding_group(t *testing.T) { } func Test_stacktrace_tree_encoding_rand(t *testing.T) { - // TODO: Fuzzing. nodes := make([]node, 1<<20) for i := range nodes { nodes[i] = node{ @@ -116,6 +116,16 @@ func Test_stacktrace_tree_encoding_rand(t *testing.T) { } } +func Test_stacktrace_tree_pprof_locations_(t *testing.T) { + x := newStacktraceTree(0) + assert.Len(t, x.resolve([]int32{0, 1, 2, 3}, 42), 0) + assert.Len(t, x.resolveUint64([]uint64{0, 1, 2, 3}, 42), 0) + + p := newParentPointerTree(0) + assert.Len(t, p.resolve([]int32{0, 1, 2, 3}, 42), 0) + assert.Len(t, p.resolveUint64([]uint64{0, 1, 2, 3}, 42), 0) +} + func Test_stacktrace_tree_pprof_locations(t *testing.T) { p, err := pprof.OpenFile("testdata/profile.pb.gz") require.NoError(t, err) @@ -165,6 +175,44 @@ func Test_stacktrace_tree_pprof_locations(t *testing.T) { } } +// The test is helpful for debugging. +func Test_parentPointerTree_toStacktraceTree(t *testing.T) { + x := newStacktraceTree(10) + for _, stack := range [][]uint64{ + {5, 4, 3, 2, 1}, + {6, 4, 3, 2, 1}, + {4, 3, 2, 1}, + {3, 2, 1}, + {4, 2, 1}, + {7, 2, 1}, + {2, 1}, + {1}, + } { + x.insert(stack) + } + assertRestoredStacktraceTree(t, x) +} + +func Test_parentPointerTree_toStacktraceTree_profile(t *testing.T) { + p, err := pprof.OpenFile("testdata/profile.pb.gz") + require.NoError(t, err) + x := newStacktraceTree(defaultStacktraceTreeSize) + for _, s := range p.Sample { + x.insert(s.LocationId) + } + assertRestoredStacktraceTree(t, x) +} + +func assertRestoredStacktraceTree(t *testing.T, x *stacktraceTree) { + var b bytes.Buffer + _, _ = x.WriteTo(&b) + ppt := newParentPointerTree(x.len()) + _, err := ppt.ReadFrom(bytes.NewBuffer(b.Bytes())) + require.NoError(t, err) + restored := ppt.toStacktraceTree() + assert.Equal(t, x.nodes, restored.nodes) +} + func Benchmark_stacktrace_tree_insert(b *testing.B) { p, err := pprof.OpenFile("testdata/profile.pb.gz") require.NoError(b, err) @@ -173,9 +221,36 @@ func Benchmark_stacktrace_tree_insert(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - x := newStacktraceTree(0) + x := newStacktraceTree(defaultStacktraceTreeSize) for j := range p.Sample { x.insert(p.Sample[j].LocationId) } } } + +func Benchmark_stacktrace_tree_insert_default_sizes(b *testing.B) { + p, err := pprof.OpenFile("testdata/profile.pb.gz") + require.NoError(b, err) + + b.ResetTimer() + + for _, size := range []int{0, 10, 1024, 2048, 4096, 8192} { + b.Run("size="+strconv.Itoa(size), func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + x := newStacktraceTree(size) + for j := range p.Sample { + x.insert(p.Sample[j].LocationId) + } + + if testing.Verbose() { + c := float64(cap(x.nodes)) + b.ReportMetric(c, "cap") + b.ReportMetric(c*float64(stacktraceTreeNodeSize), "size") + b.ReportMetric(float64(x.len())/float64(c)*100, "fill") + } + } + }) + } +} diff --git a/pkg/phlaredb/symdb/strings.go b/pkg/phlaredb/symdb/strings.go new file mode 100644 index 0000000000..c45eaf4f1f --- /dev/null +++ b/pkg/phlaredb/symdb/strings.go @@ -0,0 +1,177 @@ +//nolint:unused +package symdb + +import ( + "bytes" + "encoding/binary" + "fmt" + "hash/crc32" + "io" + "unsafe" + + "github.com/grafana/pyroscope/v2/pkg/slices" +) + +const maxStringLen = 1<<16 - 1 + +var ( + _ symbolsBlockEncoder[string] = (*stringsBlockEncoder)(nil) + _ symbolsBlockDecoder[string] = (*stringsBlockDecoder)(nil) +) + +type stringsBlockHeader struct { + StringsLen uint32 + BlockEncoding byte + _ [3]byte + CRC uint32 +} + +func (h *stringsBlockHeader) marshal(b []byte) { + binary.BigEndian.PutUint32(b[0:4], h.StringsLen) + b[5], b[6], b[7], b[8] = h.BlockEncoding, 0, 0, 0 + // Fields can be added here in the future. + // CRC must be the last four bytes. + h.CRC = crc32.Checksum(b[0:8], castagnoli) + binary.BigEndian.PutUint32(b[8:12], h.CRC) +} + +func (h *stringsBlockHeader) unmarshal(b []byte) { + h.StringsLen = binary.BigEndian.Uint32(b[0:4]) + h.BlockEncoding = b[5] + // In future versions, new fields are decoded here; + // if pos < len(b)-checksumSize, then there are more fields. + h.CRC = binary.BigEndian.Uint32(b[8:12]) +} + +func (h *stringsBlockHeader) checksum() uint32 { return h.CRC } + +type stringsBlockEncoder struct { + header stringsBlockHeader + buf bytes.Buffer + tmp []byte +} + +func newStringsEncoder() *symbolsEncoder[string] { + return newSymbolsEncoder[string](new(stringsBlockEncoder)) +} + +func (e *stringsBlockEncoder) format() SymbolsBlockFormat { return BlockStringsV1 } + +func (e *stringsBlockEncoder) headerSize() uintptr { return unsafe.Sizeof(stringsBlockHeader{}) } + +func (e *stringsBlockEncoder) encode(w io.Writer, strings []string) error { + e.initWrite(len(strings)) + e.header.BlockEncoding = e.blockEncoding(strings) + switch e.header.BlockEncoding { + case 8: + for j, s := range strings { + e.tmp[j] = byte(len(s)) + } + case 16: + for j, s := range strings { + binary.BigEndian.PutUint16(e.tmp[j*2:], uint16(len(s))) + } + } + if _, err := e.buf.Write(e.tmp[:len(strings)*int(e.header.BlockEncoding)/8]); err != nil { + return err + } + for _, s := range strings { + if len(s) > maxStringLen { + s = s[:maxStringLen] + } + if _, err := e.buf.Write(*((*[]byte)(unsafe.Pointer(&s)))); err != nil { + return err + } + } + e.tmp = slices.GrowLen(e.tmp, int(e.headerSize())) + e.header.marshal(e.tmp) + if _, err := w.Write(e.tmp); err != nil { + return err + } + _, err := e.buf.WriteTo(w) + return err +} + +func (e *stringsBlockEncoder) blockEncoding(b []string) byte { + for _, s := range b { + if len(s) > 255 { + return 16 + } + } + return 8 +} + +func (e *stringsBlockEncoder) initWrite(strings int) { + e.buf.Reset() + e.buf.Grow(strings * 16) + *e = stringsBlockEncoder{ + header: stringsBlockHeader{StringsLen: uint32(strings)}, + tmp: slices.GrowLen(e.tmp, strings*2), + buf: e.buf, + } +} + +type stringsBlockDecoder struct { + headerSize uint16 + header stringsBlockHeader + buf []byte +} + +func newStringsDecoder(h SymbolsBlockHeader) (*symbolsDecoder[string], error) { + if h.Format == BlockStringsV1 { + headerSize := max(stringsBlockHeaderMinSize, h.BlockHeaderSize) + return newSymbolsDecoder[string](h, &stringsBlockDecoder{headerSize: headerSize}), nil + } + return nil, fmt.Errorf("%w: unknown strings format: %d", ErrUnknownVersion, h.Format) +} + +// In early versions, block header size is not specified. Must not change. +const stringsBlockHeaderMinSize = 12 + +func (d *stringsBlockDecoder) decode(r io.Reader, strings []string) (err error) { + d.buf = slices.GrowLen(d.buf, int(d.headerSize)) + if err = readSymbolsBlockHeader(d.buf, r, &d.header); err != nil { + return err + } + if d.header.BlockEncoding != 8 && d.header.BlockEncoding != 16 { + return fmt.Errorf("invalid string block encoding: %d", d.header.BlockEncoding) + } + if d.header.StringsLen != uint32(len(strings)) { + return fmt.Errorf("invalid string buffer size") + } + if d.header.BlockEncoding == 8 { + return d.decodeStrings8(r, strings) + } + return d.decodeStrings16(r, strings) +} + +func (d *stringsBlockDecoder) decodeStrings8(r io.Reader, dst []string) (err error) { + d.buf = slices.GrowLen(d.buf, len(dst)) // 1 byte per string. + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + for i := 0; i < len(dst); i++ { + s := make([]byte, d.buf[i]) + if _, err = io.ReadFull(r, s); err != nil { + return err + } + dst[i] = *(*string)(unsafe.Pointer(&s)) + } + return err +} + +func (d *stringsBlockDecoder) decodeStrings16(r io.Reader, dst []string) (err error) { + d.buf = slices.GrowLen(d.buf, len(dst)*2) // 2 bytes per string. + if _, err = io.ReadFull(r, d.buf); err != nil { + return err + } + for i := 0; i < len(dst); i++ { + l := binary.BigEndian.Uint16(d.buf[i*2:]) + s := make([]byte, l) + if _, err = io.ReadFull(r, s); err != nil { + return err + } + dst[i] = *(*string)(unsafe.Pointer(&s)) + } + return err +} diff --git a/pkg/phlaredb/symdb/strings_test.go b/pkg/phlaredb/symdb/strings_test.go new file mode 100644 index 0000000000..ca95b03afa --- /dev/null +++ b/pkg/phlaredb/symdb/strings_test.go @@ -0,0 +1,88 @@ +package symdb + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_StringsEncoding(t *testing.T) { + type testCase struct { + description string + strings []string + } + + testCases := []testCase{ + { + description: "empty", + strings: []string{}, + }, + { + description: "less than block size", + strings: []string{ + "a", + "b", + }, + }, + { + description: "exact block size", + strings: []string{ + "a", + "bc", + "cde", + "def", + }, + }, + { + description: "greater than block size", + strings: []string{ + "a", + "bc", + "cde", + "def", + "e", + }, + }, + { + description: "mixed encoding", + strings: []string{ + "a", + "bcd", + strings.Repeat("e", 256), + }, + }, + { + description: "mixed encoding exact block", + strings: []string{ + "a", + "b", + "c", + "d", + strings.Repeat("e", 256), + strings.Repeat("f", 256), + strings.Repeat("j", 256), + strings.Repeat("h", 256), + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + w := newTestFileWriter(&buf) + e := newStringsEncoder() + e.blockSize = 4 + h, err := writeSymbolsBlock(w, tc.strings, e) + require.NoError(t, err) + + d, err := newStringsDecoder(h) + require.NoError(t, err) + out := make([]string, h.Length) + require.NoError(t, d.decode(out, &buf)) + require.Equal(t, tc.strings, out) + }) + } +} diff --git a/pkg/phlaredb/symdb/symbol_merger.go b/pkg/phlaredb/symdb/symbol_merger.go new file mode 100644 index 0000000000..b139884068 --- /dev/null +++ b/pkg/phlaredb/symdb/symbol_merger.go @@ -0,0 +1,603 @@ +package symdb + +import ( + "encoding/binary" + "fmt" + "slices" + "sync" + + "github.com/cespare/xxhash/v2" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/util/hashedslice" +) + +var hashZero = xxhash.New().Sum64() + +func (sm *SymbolMerger) hashMapping(h *xxhash.Digest, m *schemav1.InMemoryMapping, buf []byte) error { + binary.LittleEndian.PutUint64(buf, m.MemoryStart) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, m.MemoryLimit) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, sm.strings.Hashes[m.Filename]) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, sm.strings.Hashes[m.BuildId]) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, m.FileOffset) + if _, err := h.Write(buf); err != nil { + return err + } + + // Hash the boolean flags as a single byte + var flags byte + if m.HasFunctions { + flags |= 1 << 0 + } + if m.HasFilenames { + flags |= 1 << 1 + } + if m.HasLineNumbers { + flags |= 1 << 2 + } + if m.HasInlineFrames { + flags |= 1 << 3 + } + if _, err := h.Write([]byte{flags}); err != nil { + return err + } + + return nil +} + +func (sm *SymbolMerger) hashFunction(h *xxhash.Digest, f *schemav1.InMemoryFunction, buf []byte) error { + binary.LittleEndian.PutUint64(buf, sm.strings.Hashes[f.Name]) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, sm.strings.Hashes[f.SystemName]) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, sm.strings.Hashes[f.Filename]) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, uint64(f.StartLine)) + if _, err := h.Write(buf); err != nil { + return err + } + + return nil +} + +func (sm *SymbolMerger) hashLocation(h *xxhash.Digest, loc *schemav1.InMemoryLocation, buf []byte) error { + binary.LittleEndian.PutUint64(buf, loc.Address) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, sm.mappings.Hashes[loc.MappingId]) + if _, err := h.Write(buf); err != nil { + return err + } + + // Hash IsFolded flag + var isFolded byte + if loc.IsFolded { + isFolded = 1 + } + if _, err := h.Write([]byte{isFolded}); err != nil { + return err + } + + // Hash all lines + for _, line := range loc.Line { + binary.LittleEndian.PutUint64(buf, sm.functions.Hashes[line.FunctionId]) + if _, err := h.Write(buf); err != nil { + return err + } + binary.LittleEndian.PutUint64(buf, uint64(line.Line)) + if _, err := h.Write(buf); err != nil { + return err + } + } + + return nil +} + +type SymbolMerger struct { + mu sync.Mutex + + strings *hashedslice.Slice[string] + mappings *hashedslice.Slice[schemav1.InMemoryMapping] + functions *hashedslice.Slice[schemav1.InMemoryFunction] + locations *hashedslice.Slice[schemav1.InMemoryLocation] +} + +func NewSymbolMerger() *SymbolMerger { + m := &SymbolMerger{} + m.strings = hashedslice.New(func(a, b string) bool { return a == b }) + m.mappings = hashedslice.New(func(a, b schemav1.InMemoryMapping) bool { + return a.MemoryStart == b.MemoryStart && + a.MemoryLimit == b.MemoryLimit && + a.FileOffset == b.FileOffset && + a.Filename == b.Filename && + a.BuildId == b.BuildId && + a.HasFunctions == b.HasFunctions && + a.HasFilenames == b.HasFilenames && + a.HasLineNumbers == b.HasLineNumbers && + a.HasInlineFrames == b.HasInlineFrames + }) + m.functions = hashedslice.New(func(a, b schemav1.InMemoryFunction) bool { + return a.Name == b.Name && + a.SystemName == b.SystemName && + a.Filename == b.Filename && + a.StartLine == b.StartLine + }) + m.locations = hashedslice.New(func(a, b schemav1.InMemoryLocation) bool { + if a.Address != b.Address || + a.MappingId != b.MappingId || + a.IsFolded != b.IsFolded || + len(a.Line) != len(b.Line) { + return false + } + for i := range a.Line { + if a.Line[i].FunctionId != b.Line[i].FunctionId || + a.Line[i].Line != b.Line[i].Line { + return false + } + } + return true + }) + + // make sure the first string is the empty string + m.strings.Add(hashZero, "") + m.mappings.Add(hashZero, schemav1.InMemoryMapping{}) + m.locations.Add(hashZero, schemav1.InMemoryLocation{}) + m.functions.Add(hashZero, schemav1.InMemoryFunction{}) + + return m +} + +func sortedList[A any](m map[uint32]A, lst []int32) []int32 { + if cap(lst) < len(m) { + lst = make([]int32, 0, len(m)) + } else { + lst = lst[:0] + } + for id := range m { + lst = append(lst, int32(id)) + } + slices.Sort(lst) + return lst +} + +func sortedListInt32[A any](m map[int32]A, lst []int32) []int32 { + if cap(lst) < len(m) { + lst = make([]int32, 0, len(m)) + } else { + lst = lst[:0] + } + for id := range m { + lst = append(lst, id) + } + slices.Sort(lst) + return lst +} + +type remapper struct { + mappings map[int32]int32 + functions map[int32]int32 + strings map[int32]int32 +} + +func newRemapper() *remapper { + return &remapper{ + mappings: make(map[int32]int32), + functions: make(map[int32]int32), + strings: make(map[int32]int32), + } +} + +func (rm *remapper) resolveLocationIDs( + locationIDs []int32, + locations []schemav1.InMemoryLocation, + mappings []schemav1.InMemoryMapping, + functions []schemav1.InMemoryFunction, +) { + // Seed index 0 as sentinels. In pprof, ID 0 means "unset" (e.g. a + // location with no mapping, or a line with no function). We pre-populate + // the remapper so that these zero-IDs survive the remap unchanged. + // When the source Mappings or Functions slice is empty (no-mapping or + // unsymbolized profiles), the sentinel references an index beyond the + // slice bounds — the bounds checks below allow ID 0 to skip safely. + rm.strings[0] = 0 + rm.mappings[0] = 0 + rm.functions[0] = 0 + + // go through location ids collect mappings/functions that are used + for _, locID := range locationIDs { + rm.discoverLocation(&locations[locID]) + } + + // go through mappings collect strings used + mappingIDs := rm.mappingIDs() + for _, mapID := range mappingIDs { + if int(mapID) >= len(mappings) { + // ID 0 is the "unset" sentinel — safe to skip when there are no mappings. + if mapID == 0 { + continue + } + panic(fmt.Sprintf("mapping ID %d out of range (len=%d)", mapID, len(mappings))) + } + rm.discoverMapping(&mappings[mapID]) + } + + // go through functions collect strings used + functionIDs := rm.functionIDs() + for _, funcID := range functionIDs { + if int(funcID) >= len(functions) { + // ID 0 is the "unset" sentinel — safe to skip when there are no functions. + if funcID == 0 { + continue + } + panic(fmt.Sprintf("function ID %d out of range (len=%d)", funcID, len(functions))) + } + rm.discoverFunction(&functions[funcID]) + } +} + +func (rm *remapper) discoverLocation(loc *schemav1.InMemoryLocation) { + rm.mappings[int32(loc.MappingId)] = -1 + for _, l := range loc.Line { + rm.functions[int32(l.FunctionId)] = -1 + } +} + +func (rm *remapper) updateLocation(loc *schemav1.InMemoryLocation) { + loc.MappingId = uint32(rm.mappings[int32(loc.MappingId)]) + for idx := range loc.Line { + loc.Line[idx].FunctionId = uint32(rm.functions[int32(loc.Line[idx].FunctionId)]) + } +} + +func (rm *remapper) discoverMapping(mapping *schemav1.InMemoryMapping) { + rm.strings[int32(mapping.Filename)] = -1 + rm.strings[int32(mapping.BuildId)] = -1 +} + +func (rm *remapper) updateMapping(mapping *schemav1.InMemoryMapping) { + mapping.Filename = uint32(rm.strings[int32(mapping.Filename)]) + mapping.BuildId = uint32(rm.strings[int32(mapping.BuildId)]) +} + +func (rm *remapper) discoverFunction(function *schemav1.InMemoryFunction) { + rm.strings[int32(function.Name)] = -1 + rm.strings[int32(function.SystemName)] = -1 + rm.strings[int32(function.Filename)] = -1 +} + +func (rm *remapper) updateFunction(function *schemav1.InMemoryFunction) { + function.Name = uint32(rm.strings[int32(function.Name)]) + function.SystemName = uint32(rm.strings[int32(function.SystemName)]) + function.Filename = uint32(rm.strings[int32(function.Filename)]) +} + +func (rm *remapper) mappingIDs() []int32 { + return sortedListInt32(rm.mappings, nil) +} + +func (rm *remapper) functionIDs() []int32 { + return sortedListInt32(rm.functions, nil) +} + +func (rm *remapper) stringIDs() []int32 { + return sortedListInt32(rm.strings, nil) +} + +// addSymbols first determines which symbols are needed (from the locationsID slice) +func (sm *SymbolMerger) addSymbols(symbols *Symbols, locationIDs []int32) (func(model.LocationRefName) model.LocationRefName, error) { + rm := newRemapper() + + rm.resolveLocationIDs(locationIDs, symbols.Locations, symbols.Mappings, symbols.Functions) + + sm.mu.Lock() + defer sm.mu.Unlock() + + // add the strings to the merger + stringIDs := rm.stringIDs() + sm.strings.Grow(len(stringIDs)) + h := xxhash.New() + for _, sID := range stringIDs { + s := symbols.Strings[sID] + h.Reset() + _, err := h.WriteString(s) + if err != nil { + return nil, err + } + rm.strings[sID] = sm.strings.Add(h.Sum64(), s) + } + + // add the functions to the merger + var f schemav1.InMemoryFunction + functionIDs := rm.functionIDs() + sm.functions.Grow(len(functionIDs)) + buf := make([]byte, 8) + for _, fID := range functionIDs { + if int(fID) >= len(symbols.Functions) { + // ID 0 is the "unset" sentinel — remap to 0 and skip when there are no functions. + if fID == 0 { + rm.functions[fID] = 0 + continue + } + panic(fmt.Sprintf("function ID %d out of range (len=%d)", fID, len(symbols.Functions))) + } + h.Reset() + f = symbols.Functions[fID] + rm.updateFunction(&f) + if err := sm.hashFunction(h, &f, buf); err != nil { + return nil, err + } + rm.functions[fID] = sm.functions.Add(h.Sum64(), f) + } + + // add the mappings to the merger + var mp schemav1.InMemoryMapping + mappingIDs := rm.mappingIDs() + sm.mappings.Grow(len(mappingIDs)) + for _, mID := range mappingIDs { + if int(mID) >= len(symbols.Mappings) { + // ID 0 is the "unset" sentinel — remap to 0 and skip when there are no mappings. + if mID == 0 { + rm.mappings[mID] = 0 + continue + } + panic(fmt.Sprintf("mapping ID %d out of range (len=%d)", mID, len(symbols.Mappings))) + } + h.Reset() + mp = symbols.Mappings[mID] + rm.updateMapping(&mp) + if err := sm.hashMapping(h, &mp, buf); err != nil { + return nil, err + } + rm.mappings[mID] = sm.mappings.Add(h.Sum64(), mp) + } + + // add the locations to the merger + var loc schemav1.InMemoryLocation + locationRemap := make(map[int32]int32, len(locationIDs)) + for _, lID := range locationIDs { + h.Reset() + loc = symbols.Locations[lID] + rm.updateLocation(&loc) + if err := sm.hashLocation(h, &loc, buf); err != nil { + return nil, err + } + locationRemap[lID] = sm.locations.Add(h.Sum64(), loc) + } + + // Return a remap function + return func(in model.LocationRefName) model.LocationRefName { + if in < 0 { + return in + } + return model.LocationRefName(locationRemap[int32(in)]) + }, nil +} + +// Add adds symbols from a TreeSymbols protobuf message to the merger. +// It returns a mapping function that can be used to remap LocationRefName values. +func (sm *SymbolMerger) Add(ts *queryv1.TreeSymbols) (func(model.LocationRefName) model.LocationRefName, error) { + rm := newRemapper() + + // Note: We do not resolve the location IDs, as this should have happened at the previous level. + sm.mu.Lock() + defer sm.mu.Unlock() + + // add the strings to the merger + for idx, s := range ts.Strings { + sm.strings.Grow(len(ts.Strings)) + rm.strings[int32(idx)] = sm.strings.Add(ts.StringHashes[idx], s) + } + + // add the functions to the merger + { + var f schemav1.InMemoryFunction + sm.functions.Grow(len(ts.Functions)) + for idx, orig := range ts.Functions { + f.StartLine = uint32(orig.StartLine) + f.Name = uint32(orig.Name) + f.SystemName = uint32(orig.SystemName) + f.Filename = uint32(orig.Filename) + rm.updateFunction(&f) + rm.functions[int32(idx)] = sm.functions.Add(ts.FunctionHashes[idx], f) + } + } + + // add the mappings to the merger + { + var m schemav1.InMemoryMapping + sm.mappings.Grow(len(ts.Mappings)) + for idx, orig := range ts.Mappings { + m.MemoryStart = orig.MemoryStart + m.MemoryLimit = orig.MemoryLimit + m.FileOffset = orig.FileOffset + m.Filename = uint32(orig.Filename) + m.BuildId = uint32(orig.BuildId) + m.HasFunctions = orig.HasFunctions + m.HasFilenames = orig.HasFilenames + m.HasLineNumbers = orig.HasLineNumbers + m.HasInlineFrames = orig.HasInlineFrames + rm.updateMapping(&m) + rm.mappings[int32(idx)] = sm.mappings.Add(ts.MappingHashes[idx], m) + } + } + + // add the locations to the merger + var loc schemav1.InMemoryLocation + sm.locations.Grow(len(ts.Locations)) + locationRemap := make(map[int32]int32, len(ts.Locations)) + for idx, orig := range ts.Locations { + loc.Address = orig.Address + loc.MappingId = uint32(orig.MappingId) + loc.IsFolded = orig.IsFolded + loc.Line = make([]schemav1.InMemoryLine, len(orig.Line)) + for lineIdx, line := range orig.Line { + loc.Line[lineIdx] = schemav1.InMemoryLine{ + FunctionId: uint32(line.FunctionId), + Line: int32(line.Line), + } + } + rm.updateLocation(&loc) + locationRemap[int32(idx)] = sm.locations.Add(ts.LocationHashes[idx], loc) + } + + // Return a remap function + return func(in model.LocationRefName) model.LocationRefName { + if in < 0 { + return in + } + return model.LocationRefName(locationRemap[int32(in)]) + }, nil +} + +// ResultBuilder creates a result builder that can be used to build the final TreeSymbols +// after all symbols have been added via Add() or addSymbols(). +func (sm *SymbolMerger) ResultBuilder() *symbolResultBuilder { + return &symbolResultBuilder{ + merger: sm, + locationsLookup: map[int32]int32{0: 0}, + locationsRef: make([]int32, 1, sm.locations.Len()), + } +} + +type symbolResultBuilder struct { + merger *SymbolMerger + + locationsLookup map[int32]int32 // map from merged location index to result index + locationsRef []int32 // ordered list of merged location indices to include in result +} + +func (m *symbolResultBuilder) KeepSymbol(in model.LocationRefName) model.LocationRefName { + if in < 0 { + return in + } + + idx := int32(in) + + // Check if we've already marked this location to keep + if resultIdx, ok := m.locationsLookup[idx]; ok { + return model.LocationRefName(resultIdx) + } + + // Add to the list of locations to keep + resultIdx := int32(len(m.locationsRef)) + m.locationsLookup[idx] = resultIdx + m.locationsRef = append(m.locationsRef, idx) + return model.LocationRefName(resultIdx) +} + +// Build constructs the final TreeSymbols protobuf message from the merged symbols. +// This should append strings, mappings, functions, locations to the TreeSymbols, ensuring via maps that each element is unique. +func (m *symbolResultBuilder) Build(r *queryv1.TreeSymbols) { + // TODO: Quick path when nothing is truncated + rm := newRemapper() + + if r == nil { + r = &queryv1.TreeSymbols{} + } + + rm.resolveLocationIDs(m.locationsRef, m.merger.locations.Values, m.merger.mappings.Values, m.merger.functions.Values) + + // add the strings to the result + { + stringIDs := rm.stringIDs() + r.Strings = make([]string, len(stringIDs)) + r.StringHashes = make([]uint64, len(stringIDs)) + for idx, sID := range stringIDs { + r.Strings[idx] = m.merger.strings.Values[sID] + r.StringHashes[idx] = m.merger.strings.Hashes[sID] + rm.strings[sID] = int32(idx) + } + } + + // add the functions to the result + { + functionIDs := rm.functionIDs() + functions := make([]profilev1.Function, len(functionIDs)) + r.Functions = make([]*profilev1.Function, len(functionIDs)) + r.FunctionHashes = make([]uint64, len(functionIDs)) + for idx, fID := range functionIDs { + orig := m.merger.functions.Values[fID] + rm.updateFunction(&orig) + functions[idx].Id = uint64(idx) + functions[idx].Name = int64(orig.Name) + functions[idx].SystemName = int64(orig.SystemName) + functions[idx].Filename = int64(orig.Filename) + functions[idx].StartLine = int64(orig.StartLine) + r.Functions[idx] = &functions[idx] + r.FunctionHashes[idx] = m.merger.functions.Hashes[fID] + rm.functions[fID] = int32(idx) + } + } + + // add the mappings to the result + { + mappingIDs := rm.mappingIDs() + mappings := make([]profilev1.Mapping, len(mappingIDs)) + r.Mappings = make([]*profilev1.Mapping, len(mappingIDs)) + r.MappingHashes = make([]uint64, len(mappingIDs)) + for idx, mID := range mappingIDs { + orig := m.merger.mappings.Values[mID] + rm.updateMapping(&orig) + mappings[idx].Id = uint64(idx) + mappings[idx].MemoryStart = orig.MemoryStart + mappings[idx].MemoryLimit = orig.MemoryLimit + mappings[idx].FileOffset = orig.FileOffset + mappings[idx].Filename = int64(orig.Filename) + mappings[idx].BuildId = int64(orig.BuildId) + mappings[idx].HasFunctions = orig.HasFunctions + mappings[idx].HasFilenames = orig.HasFilenames + mappings[idx].HasLineNumbers = orig.HasLineNumbers + mappings[idx].HasInlineFrames = orig.HasInlineFrames + r.Mappings[idx] = &mappings[idx] + r.MappingHashes[idx] = m.merger.mappings.Hashes[mID] + rm.mappings[mID] = int32(idx) + } + } + + // add the locations to the result + { + locations := make([]profilev1.Location, len(m.locationsRef)) + r.Locations = make([]*profilev1.Location, len(m.locationsRef)) + r.LocationHashes = make([]uint64, len(m.locationsRef)) + for idx, lID := range m.locationsRef { + orig := m.merger.locations.Values[lID] + rm.updateLocation(&orig) + locations[idx].Id = uint64(idx) + locations[idx].Address = orig.Address + locations[idx].MappingId = uint64(orig.MappingId) + locations[idx].IsFolded = orig.IsFolded + locations[idx].Line = make([]*profilev1.Line, len(orig.Line)) + for lineIdx := range orig.Line { + locations[idx].Line[lineIdx] = &profilev1.Line{ + FunctionId: uint64(orig.Line[lineIdx].FunctionId), + Line: int64(orig.Line[lineIdx].Line), + } + } + r.Locations[idx] = &locations[idx] + r.LocationHashes[idx] = m.merger.locations.Hashes[lID] + } + } + +} diff --git a/pkg/phlaredb/symdb/symbol_merger_test.go b/pkg/phlaredb/symdb/symbol_merger_test.go new file mode 100644 index 0000000000..59d1c2731e --- /dev/null +++ b/pkg/phlaredb/symdb/symbol_merger_test.go @@ -0,0 +1,610 @@ +package symdb + +import ( + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +const expectedTreeSymbols = ` +{ + "mappings": [ + {}, + { + "id": "1", + "filename": "3", + "memoryLimit": "8192", + "memoryStart": "4096" + } + ], + "locations": [ + {}, + { + "id": "1", + "address": "4660", + "mappingId": "1", + "line": [ + { + "functionId": "1", + "line": "42" + } + ] + }, + { + "address": "22136", + "mappingId": "1", + "id": "2" + } + ], + "functions": [ + {}, + { + "filename": "2", + "id": "1", + "name": "1", + "startLine": "10", + "systemName": "1" + } + ], + "strings": [ + "", + "main", + "/path/to/file.go", + "executable" + ], + "mappingHashes": [ + "17241709254077376921", + "17123522043250476816" + ], + "locationHashes": [ + "17241709254077376921", + "2168997802985953269", + "18320325443818765556" + ], + "functionHashes": [ + "17241709254077376921", + "3093208752845406239" + ], + "stringHashes": [ + "17241709254077376921", + "1164858042786835974", + "16187834116879249968", + "1384254427617264253" + ] +} +` + +func createTestSymbols() *Symbols { + return &Symbols{ + Locations: []schemav1.InMemoryLocation{ + { + MappingId: 0, + Address: 0x1234, + Line: []schemav1.InMemoryLine{ + {FunctionId: 0, Line: 42}, + }, + }, + { + Address: 0x5678, + }, + }, + Mappings: []schemav1.InMemoryMapping{ + { + MemoryStart: 0x1000, + MemoryLimit: 0x2000, + FileOffset: 0, + Filename: 3, + BuildId: 0, + }, + }, + Functions: []schemav1.InMemoryFunction{ + {Name: 1, SystemName: 1, Filename: 2, StartLine: 10}, + }, + Strings: []string{"", "main", "/path/to/file.go", "executable"}, + } +} + +func TestSymbolMerger(t *testing.T) { + // Create a merger and add test symbols + merger := NewSymbolMerger() + ts := createTestSymbols() + + locIDs := []int32{0, 1} + + keepAll := func(f func(model.LocationRefName) model.LocationRefName) { + for _, locID := range locIDs { + require.Equal(t, model.LocationRefName(locID+1), f(model.LocationRefName(locID+1))) + } + } + + adder, err := merger.addSymbols(ts, locIDs) + require.NoError(t, err) + // adder renumbers from 0 to 1 + for _, locID := range locIDs { + require.Equal(t, model.LocationRefName(locID+1), adder(model.LocationRefName(locID))) + } + + // Build the result, keeping all locations + builder := merger.ResultBuilder() + keepAll(builder.KeepSymbol) + + result := &queryv1.TreeSymbols{} + builder.Build(result) + + // compare TreeSymbols + b, err := protojson.Marshal(result) + require.NoError(t, err) + require.JSONEq(t, expectedTreeSymbols, string(b)) + + // now merge them twice + merger = NewSymbolMerger() + _, err = merger.Add(result) + require.NoError(t, err) + adder, err = merger.Add(result) + require.NoError(t, err) + keepAll(adder) + adder, err = merger.Add(result) + require.NoError(t, err) + keepAll(adder) + + // Build the result, keeping all locations + builder = merger.ResultBuilder() + keepAll(builder.KeepSymbol) + + result = &queryv1.TreeSymbols{} + builder.Build(result) + + // compare TreeSymbols + b, err = protojson.Marshal(result) + require.NoError(t, err) + require.JSONEq(t, expectedTreeSymbols, string(b)) +} + +func createUnsymbolizedTestSymbols() *Symbols { + return &Symbols{ + Locations: []schemav1.InMemoryLocation{ + {MappingId: 0, Address: 0x1500}, + {MappingId: 0, Address: 0x3c5a}, + }, + Mappings: []schemav1.InMemoryMapping{ + { + MemoryStart: 0x1000, + MemoryLimit: 0x5000, + FileOffset: 0, + Filename: 1, + BuildId: 2, + HasFunctions: false, + }, + }, + Functions: []schemav1.InMemoryFunction{}, + Strings: []string{"", "libfoo.so", "2fa2055ef20fabc972d5751147e093275514b142"}, + } +} + +// TestSymbolMerger_UnsymbolizedProfile is a regression test for a panic that occurs +// when merging profiles where symbols.Functions is empty (HasFunctions=false). +// resolveLocationIDs unconditionally adds functions[0] = 0 as a sentinel and then +// calls discoverFunction(&functions[0]), which panics with an index-out-of-bounds. +// The same panic occurs in addSymbols when it indexes symbols.Functions[fID] for fID=0. +func TestSymbolMerger_UnsymbolizedProfile(t *testing.T) { + merger := NewSymbolMerger() + ts := createUnsymbolizedTestSymbols() + locIDs := []int32{0, 1} + + adder, err := merger.addSymbols(ts, locIDs) + require.NoError(t, err) // panics before fix + + // adder renumbers 0-based input indices → 1-based merged indices + for _, locID := range locIDs { + require.Equal(t, model.LocationRefName(locID+1), adder(model.LocationRefName(locID))) + } + + builder := merger.ResultBuilder() + for _, locID := range locIDs { + builder.KeepSymbol(adder(model.LocationRefName(locID))) + } + + result := &queryv1.TreeSymbols{} + builder.Build(result) + + require.Len(t, result.Functions, 1) // sentinel only — no function data + require.Len(t, result.Locations, 3) // sentinel + 2 unsymbolized locations + require.Len(t, result.Mappings, 2) // sentinel + 1 mapping + require.Len(t, result.Strings, 3) // "", "libfoo.so", build-id + + // Verify locations carry the right addresses. + require.Equal(t, uint64(0x1500), result.Locations[1].Address) + require.Equal(t, uint64(0x3c5a), result.Locations[2].Address) + // Both locations reference the single mapping. + require.Equal(t, uint64(1), result.Locations[1].MappingId) + require.Equal(t, uint64(1), result.Locations[2].MappingId) +} + +// TestSymbolMerger_UnsymbolizedProfile_RoundTrip verifies that the result of +// addSymbols+Build can be fed back into Add+Build and produce identical output. +func TestSymbolMerger_UnsymbolizedProfile_RoundTrip(t *testing.T) { + ts := createUnsymbolizedTestSymbols() + locIDs := []int32{0, 1} + + // First pass: addSymbols → Build → result1 + merger1 := NewSymbolMerger() + adder, err := merger1.addSymbols(ts, locIDs) + require.NoError(t, err) + + builder1 := merger1.ResultBuilder() + for _, locID := range locIDs { + builder1.KeepSymbol(adder(model.LocationRefName(locID))) + } + result1 := &queryv1.TreeSymbols{} + builder1.Build(result1) + + // Second pass: Add(result1) → Build → result2 + merger2 := NewSymbolMerger() + adder2, err := merger2.Add(result1) + require.NoError(t, err) + + builder2 := merger2.ResultBuilder() + // Skip index 0 (sentinel); keep the real locations. + for i := int32(1); i < int32(len(result1.Locations)); i++ { + builder2.KeepSymbol(adder2(model.LocationRefName(i))) + } + result2 := &queryv1.TreeSymbols{} + builder2.Build(result2) + + b1, err := protojson.Marshal(result1) + require.NoError(t, err) + b2, err := protojson.Marshal(result2) + require.NoError(t, err) + require.JSONEq(t, string(b1), string(b2)) +} + +// TestSymbolMerger_UnsymbolizedProfile_Deduplication verifies that merging the same +// unsymbolized symbols twice produces no duplicate entries in the result. +func TestSymbolMerger_UnsymbolizedProfile_Deduplication(t *testing.T) { + ts := createUnsymbolizedTestSymbols() + locIDs := []int32{0, 1} + + merger := NewSymbolMerger() + + adder1, err := merger.addSymbols(ts, locIDs) + require.NoError(t, err) + adder2, err := merger.addSymbols(ts, locIDs) + require.NoError(t, err) + + builder := merger.ResultBuilder() + for _, locID := range locIDs { + builder.KeepSymbol(adder1(model.LocationRefName(locID))) + builder.KeepSymbol(adder2(model.LocationRefName(locID))) + } + + result := &queryv1.TreeSymbols{} + builder.Build(result) + + // Same counts as a single add — the merger must deduplicate. + require.Len(t, result.Functions, 1) // sentinel only + require.Len(t, result.Locations, 3) // sentinel + 2 unique locations + require.Len(t, result.Mappings, 2) // sentinel + 1 unique mapping + require.Len(t, result.Strings, 3) // "", "libfoo.so", build-id +} + +func createNoMappingsTestSymbols() *Symbols { + return &Symbols{ + Locations: []schemav1.InMemoryLocation{ + {MappingId: 0, Address: 0, Line: []schemav1.InMemoryLine{{FunctionId: 0, Line: 0}}}, + {MappingId: 0, Address: 0, Line: []schemav1.InMemoryLine{{FunctionId: 1, Line: 0}}}, + }, + Mappings: []schemav1.InMemoryMapping{}, + Functions: []schemav1.InMemoryFunction{ + {Name: 3, SystemName: 3, Filename: 0, StartLine: 0}, + {Name: 4, SystemName: 4, Filename: 0, StartLine: 0}, + }, + Strings: []string{"", "cpu", "nanoseconds", "main", "foo"}, + } +} + +// TestSymbolMerger_NoMappings is a regression test for a panic that occurs +// when merging profiles where symbols.Mappings is empty (locations carry +// MappingId 0 meaning "unset"). resolveLocationIDs unconditionally adds +// mappings[0] = 0 as a sentinel and then calls discoverMapping(&mappings[0]), +// which panics with an index-out-of-bounds when the slice is empty. +// The same panic occurs in addSymbols when it indexes symbols.Mappings[mID]. +func TestSymbolMerger_NoMappings(t *testing.T) { + merger := NewSymbolMerger() + ts := createNoMappingsTestSymbols() + locIDs := []int32{0, 1} + + adder, err := merger.addSymbols(ts, locIDs) + require.NoError(t, err) // panics before fix + + // adder renumbers 0-based input indices → 1-based merged indices + for _, locID := range locIDs { + require.Equal(t, model.LocationRefName(locID+1), adder(model.LocationRefName(locID))) + } + + builder := merger.ResultBuilder() + for _, locID := range locIDs { + builder.KeepSymbol(adder(model.LocationRefName(locID))) + } + + result := &queryv1.TreeSymbols{} + builder.Build(result) + + require.Len(t, result.Mappings, 1) // sentinel only — no mapping data + require.Len(t, result.Locations, 3) // sentinel + 2 locations + require.Len(t, result.Functions, 3) // sentinel + 2 functions (main, foo) + + // Verify locations carry no mapping reference. + require.Equal(t, uint64(0), result.Locations[1].MappingId) + require.Equal(t, uint64(0), result.Locations[2].MappingId) + + // Verify function names are preserved. + funcNames := make([]string, len(result.Functions)) + for i, f := range result.Functions { + funcNames[i] = result.Strings[f.Name] + } + require.Contains(t, funcNames, "main") + require.Contains(t, funcNames, "foo") +} + +func TestSymbolMerger_HashCollision(t *testing.T) { + sm := NewSymbolMerger() + + const sameHash = uint64(0xdeadbeefcafebabe) + + // Add "foo" – placed at index 1 (index 0 is the sentinel empty string). + idxFoo := sm.strings.Add(sameHash, "foo") + // Add "bar" with the same hash – linear probing must resolve the collision. + idxBar := sm.strings.Add(sameHash, "bar") + + // Both values must get distinct indices. + require.NotEqual(t, idxFoo, idxBar) + require.Equal(t, int32(1), idxFoo) + require.Equal(t, int32(2), idxBar) + + // Slice contains sentinel + the two colliding values. + require.Equal(t, []string{"", "foo", "bar"}, sm.strings.Values) + + // The original hash (not the probe offset) is stored for both entries. + require.Equal(t, sameHash, sm.strings.Hashes[idxFoo]) + require.Equal(t, sameHash, sm.strings.Hashes[idxBar]) + + // Re-adding "foo" or "bar" with the same hash must return the original index (deduplication). + idxFooAgain := sm.strings.Add(sameHash, "foo") + require.Equal(t, idxFoo, idxFooAgain) + idxBarAgain := sm.strings.Add(sameHash, "bar") + require.Equal(t, idxBar, idxBarAgain) +} + +func BenchmarkSymbolMerger(b *testing.B) { + s := newMemSuite(b, [][]string{{"testdata/big-profile.pb.gz"}}) + + b.Run("addSymbols", func(b *testing.B) { + // Get symbols from the profile + symbols := extractSymbolsFromProfile(b, s.profiles[0]) + + // Collect all location IDs + locationIDs := make([]int32, len(symbols.Locations)) + for i := range symbols.Locations { + locationIDs[i] = int32(i) + } + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + merger := NewSymbolMerger() + _, err := merger.addSymbols(symbols, locationIDs) + if err != nil { + b.Fatal(err) + } + } + }) + + b.Run("addSymbols_and_build", func(b *testing.B) { + // Get symbols from the profile + symbols := extractSymbolsFromProfile(b, s.profiles[0]) + + // Collect all location IDs + locationIDs := make([]int32, len(symbols.Locations)) + for i := range symbols.Locations { + locationIDs[i] = int32(i) + } + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + merger := NewSymbolMerger() + remap, err := merger.addSymbols(symbols, locationIDs) + if err != nil { + b.Fatal(err) + } + + builder := merger.ResultBuilder() + for _, locID := range locationIDs { + builder.KeepSymbol(remap(model.LocationRefName(locID))) + } + + result := &queryv1.TreeSymbols{} + builder.Build(result) + } + }) + + b.Run("merge_multiple", func(b *testing.B) { + // Get symbols from the profile + symbols := extractSymbolsFromProfile(b, s.profiles[0]) + + // Collect all location IDs + locationIDs := make([]int32, len(symbols.Locations)) + for i := range symbols.Locations { + locationIDs[i] = int32(i) + } + + // Pre-create TreeSymbols for merging + merger := NewSymbolMerger() + remap, err := merger.addSymbols(symbols, locationIDs) + require.NoError(b, err) + + builder := merger.ResultBuilder() + for _, locID := range locationIDs { + builder.KeepSymbol(remap(model.LocationRefName(locID))) + } + + treeSymbols := &queryv1.TreeSymbols{} + builder.Build(treeSymbols) + + b.Run("2_sources", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + merger := NewSymbolMerger() + _, err := merger.Add(treeSymbols) + if err != nil { + b.Fatal(err) + } + _, err = merger.Add(treeSymbols) + if err != nil { + b.Fatal(err) + } + + builder := merger.ResultBuilder() + for j := int32(0); j < int32(len(treeSymbols.Locations)); j++ { + builder.KeepSymbol(model.LocationRefName(j)) + } + + result := &queryv1.TreeSymbols{} + builder.Build(result) + } + }) + + b.Run("4_sources", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + merger := NewSymbolMerger() + for j := 0; j < 4; j++ { + _, err := merger.Add(treeSymbols) + if err != nil { + b.Fatal(err) + } + } + + builder := merger.ResultBuilder() + for j := int32(0); j < int32(len(treeSymbols.Locations)); j++ { + builder.KeepSymbol(model.LocationRefName(j)) + } + + result := &queryv1.TreeSymbols{} + builder.Build(result) + } + }) + + b.Run("8_sources", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + merger := NewSymbolMerger() + for j := 0; j < 8; j++ { + _, err := merger.Add(treeSymbols) + if err != nil { + b.Fatal(err) + } + } + + builder := merger.ResultBuilder() + for j := int32(0); j < int32(len(treeSymbols.Locations)); j++ { + builder.KeepSymbol(model.LocationRefName(j)) + } + + result := &queryv1.TreeSymbols{} + builder.Build(result) + } + }) + }) +} + +func extractSymbolsFromProfile(tb testing.TB, profile *googlev1.Profile) *Symbols { + tb.Helper() + + // Build location mapping + locationMap := make(map[uint64]int32) + for i, loc := range profile.Location { + locationMap[loc.Id] = int32(i) + } + + // Build mapping + mappingMap := make(map[uint64]int32) + for i, m := range profile.Mapping { + mappingMap[m.Id] = int32(i) + } + + // Build function mapping + functionMap := make(map[uint64]int32) + for i, f := range profile.Function { + functionMap[f.Id] = int32(i) + } + + symbols := &Symbols{ + Strings: profile.StringTable, + Locations: make([]schemav1.InMemoryLocation, len(profile.Location)), + Mappings: make([]schemav1.InMemoryMapping, len(profile.Mapping)), + Functions: make([]schemav1.InMemoryFunction, len(profile.Function)), + } + + // Convert mappings + for i, m := range profile.Mapping { + symbols.Mappings[i] = schemav1.InMemoryMapping{ + MemoryStart: m.MemoryStart, + MemoryLimit: m.MemoryLimit, + FileOffset: m.FileOffset, + Filename: uint32(m.Filename), + BuildId: uint32(m.BuildId), + HasFunctions: m.HasFunctions, + HasFilenames: m.HasFilenames, + HasLineNumbers: m.HasLineNumbers, + HasInlineFrames: m.HasInlineFrames, + } + } + + // Convert functions + for i, f := range profile.Function { + symbols.Functions[i] = schemav1.InMemoryFunction{ + Name: uint32(f.Name), + SystemName: uint32(f.SystemName), + Filename: uint32(f.Filename), + StartLine: uint32(f.StartLine), + } + } + + // Convert locations + for i, loc := range profile.Location { + mappingID := uint32(0) + if loc.MappingId != 0 { + mappingID = uint32(mappingMap[loc.MappingId]) + } + + lines := make([]schemav1.InMemoryLine, len(loc.Line)) + for j, line := range loc.Line { + functionID := uint32(0) + if line.FunctionId != 0 { + functionID = uint32(functionMap[line.FunctionId]) + } + lines[j] = schemav1.InMemoryLine{ + FunctionId: functionID, + Line: int32(line.Line), + } + } + + symbols.Locations[i] = schemav1.InMemoryLocation{ + MappingId: mappingID, + Address: loc.Address, + IsFolded: loc.IsFolded, + Line: lines, + } + } + + return symbols +} diff --git a/pkg/phlaredb/symdb/symdb.go b/pkg/phlaredb/symdb/symdb.go index a41a237dd3..24aa765226 100644 --- a/pkg/phlaredb/symdb/symdb.go +++ b/pkg/phlaredb/symdb/symdb.go @@ -2,14 +2,16 @@ package symdb import ( "context" - "fmt" + "io" + "math" "sort" "sync" "time" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - schemav1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" ) // SymbolsReader provides access to a symdb partition. @@ -25,9 +27,9 @@ type PartitionReader interface { type Symbols struct { Stacktraces StacktraceResolver - Locations []*schemav1.InMemoryLocation - Mappings []*schemav1.InMemoryMapping - Functions []*schemav1.InMemoryFunction + Locations []schemav1.InMemoryLocation + Mappings []schemav1.InMemoryMapping + Functions []schemav1.InMemoryFunction Strings []string } @@ -51,6 +53,25 @@ type StacktraceResolver interface { // Stacktraces slice might be modified during the call. ResolveStacktraceLocations(ctx context.Context, dst StacktraceInserter, stacktraces []uint32) error LookupLocations(dst []uint64, stacktraceID uint32) []uint64 + + // Optional: + // StacktraceIDRangeIterator +} + +// StacktraceIDRangeIterator provides low level access +// to stack traces, stored in painter point trees. +type StacktraceIDRangeIterator interface { + SplitStacktraceIDRanges(*SampleAppender) iter.Iterator[*StacktraceIDRange] +} + +type ParentPointerTree interface { + Nodes() []Node +} + +type Node struct { + Parent int32 + Location int32 + Value int64 } // StacktraceInserter accepts resolved locations for a given stack @@ -64,8 +85,8 @@ type StacktraceInserter interface { } type SymDB struct { - config *Config - writer *writer + config Config + writer blockWriter stats MemoryStats m sync.RWMutex @@ -76,9 +97,19 @@ type SymDB struct { } type Config struct { - Dir string + Version FormatVersion + // Output writer. Optional, V3 only. + Writer io.WriteCloser + + // DEPRECATED: the parameter is not used and + // will be removed in the future versions. + Dir string + // DEPRECATED: the parameter is not used and + // will be removed in the future versions. Stacktraces StacktracesConfig - Parquet ParquetConfig + // DEPRECATED: the parameter is not used and + // will be removed in the future versions. + Parquet ParquetConfig } type StacktracesConfig struct { @@ -86,6 +117,8 @@ type StacktracesConfig struct { } type ParquetConfig struct { + // DEPRECATED: the parameter is not used and + // will be removed in the future versions. MaxBufferRowCount int } @@ -109,16 +142,7 @@ const statsUpdateInterval = 5 * time.Second func DefaultConfig() *Config { return &Config{ - Dir: DefaultDirName, - Stacktraces: StacktracesConfig{ - // At the moment chunks are loaded in memory at once. - // Due to the fact that chunking causes some duplication, - // it's better to keep them large. - MaxNodesPerChunk: 4 << 20, - }, - Parquet: ParquetConfig{ - MaxBufferRowCount: 100 << 10, - }, + Version: FormatV2, } } @@ -127,8 +151,8 @@ func (c *Config) WithDirectory(dir string) *Config { return c } -func (c *Config) WithParquetConfig(pc ParquetConfig) *Config { - c.Parquet = pc +func (c *Config) WithVersion(v FormatVersion) *Config { + c.Version = v return c } @@ -136,12 +160,20 @@ func NewSymDB(c *Config) *SymDB { if c == nil { c = DefaultConfig() } + c.Parquet.MaxBufferRowCount = math.MaxInt + c.Stacktraces.MaxNodesPerChunk = math.MaxUint32 db := &SymDB{ - config: c, - writer: newWriter(c), + config: *c, partitions: make(map[uint64]*PartitionWriter), stop: make(chan struct{}), } + switch c.Version { + case FormatV3: + db.writer = newWriterV3(c) + default: + db.config.Version = FormatV2 + db.writer = newWriterV2(c) + } db.wg.Add(1) go db.updateStatsLoop() return db @@ -157,16 +189,22 @@ func (s *SymDB) PartitionWriter(partition uint64) *PartitionWriter { s.m.Unlock() return p } - p = s.newPartition(partition) + p = NewPartitionWriter(partition, &s.config) s.partitions[partition] = p s.m.Unlock() return p } -func (s *SymDB) newPartition(partition uint64) *PartitionWriter { +func NewPartitionWriter(partition uint64, config *Config) *PartitionWriter { p := PartitionWriter{ header: PartitionHeader{Partition: partition}, - stacktraces: newStacktracesPartition(s.config.Stacktraces.MaxNodesPerChunk), + stacktraces: newStacktraces(), + } + switch config.Version { + case FormatV2: + p.header.V2 = new(PartitionHeaderV2) + case FormatV3: + p.header.V3 = new(PartitionHeaderV3) } p.strings.init() p.mappings.init() @@ -262,15 +300,13 @@ func (s *SymDB) Flush() error { sort.Slice(partitions, func(i, j int) bool { return partitions[i].header.Partition < partitions[j].header.Partition }) - if err := s.writer.createDir(); err != nil { - return err - } - if err := s.writer.writePartitions(partitions); err != nil { - return fmt.Errorf("writing partitions: %w", err) - } - return s.writer.Flush() + return s.writer.writePartitions(partitions) } func (s *SymDB) Files() []block.File { - return s.writer.files + return s.writer.meta() +} + +func (s *SymDB) FormatVersion() FormatVersion { + return s.config.Version } diff --git a/pkg/phlaredb/symdb/symdb_test.go b/pkg/phlaredb/symdb/symdb_test.go index d304e30459..019a075dd3 100644 --- a/pkg/phlaredb/symdb/symdb_test.go +++ b/pkg/phlaredb/symdb/symdb_test.go @@ -1,25 +1,37 @@ package symdb import ( + "bytes" "context" + "io" "sort" + "sync/atomic" "testing" + "time" + + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + pprofth "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" "github.com/cespare/xxhash/v2" "github.com/stretchr/testify/require" + "github.com/thanos-io/objstore" googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - v1 "github.com/grafana/pyroscope/pkg/phlaredb/schemas/v1" - "github.com/grafana/pyroscope/pkg/pprof" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) type memSuite struct { t testing.TB - config *Config - db *SymDB + config *Config + db *SymDB + + // partition => sample type index => object files [][]string profiles map[uint64]*googlev1.Profile indexed map[uint64][]v1.InMemoryProfile @@ -28,6 +40,7 @@ type memSuite struct { type blockSuite struct { *memSuite reader *Reader + testBucket } func newMemSuite(t testing.TB, files [][]string) *memSuite { @@ -44,15 +57,7 @@ func newBlockSuite(t testing.TB, files [][]string) *blockSuite { func (s *memSuite) init() { if s.config == nil { - s.config = &Config{ - Dir: s.t.TempDir(), - Stacktraces: StacktracesConfig{ - MaxNodesPerChunk: 1 << 10, - }, - Parquet: ParquetConfig{ - MaxBufferRowCount: 512, - }, - } + s.config = DefaultConfig().WithDirectory(s.t.TempDir()) } if s.db == nil { s.db = NewSymDB(s.config) @@ -69,7 +74,7 @@ func (s *memSuite) init() { func (s *memSuite) writeProfileFromFile(p uint64, f string) { x, err := pprof.OpenFile(f) require.NoError(s.t, err) - s.profiles[p] = x.Profile.CloneVT() + s.profiles[p] = x.CloneVT() x.Normalize() w := s.db.PartitionWriter(p) s.indexed[p] = w.WriteProfileSymbols(x.Profile) @@ -77,9 +82,12 @@ func (s *memSuite) writeProfileFromFile(p uint64, f string) { func (s *blockSuite) flush() { require.NoError(s.t, s.db.Flush()) - b, err := filesystem.NewBucket(s.config.Dir) + b, err := filesystem.NewBucket(s.config.Dir, func(x objstore.Bucket) (objstore.Bucket, error) { + s.Bucket = x + return &s.testBucket, nil + }) require.NoError(s.t, err) - s.reader, err = Open(context.Background(), b, testBlockMeta) + s.reader, err = Open(context.Background(), b, &block.Meta{Files: s.db.Files()}) require.NoError(s.t, err) } @@ -87,6 +95,22 @@ func (s *blockSuite) teardown() { require.NoError(s.t, s.reader.Close()) } +type testBucket struct { + getRangeCount atomic.Int64 + getRangeSize atomic.Int64 + objstore.Bucket +} + +func (b *testBucket) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { + b.getRangeCount.Add(1) + b.getRangeSize.Add(length) + return b.Bucket.GetRange(ctx, name, off, length) +} + +func newTestFileWriter(w io.Writer) *writerOffset { + return &writerOffset{Writer: w} +} + //nolint:unparam func pprofFingerprint(p *googlev1.Profile, typ int) [][2]uint64 { m := make(map[uint64]uint64, len(p.Sample)) @@ -113,13 +137,13 @@ func pprofFingerprint(p *googlev1.Profile, typ int) [][2]uint64 { return s } -func treeFingerprint(t *phlaremodel.Tree) [][2]uint64 { +func treeFingerprint(t *phlaremodel.FunctionNameTree) [][2]uint64 { m := make([][2]uint64, 0, 1<<10) h := xxhash.New() - t.IterateStacks(func(_ string, self int64, stack []string) { + t.IterateStacks(func(_ phlaremodel.FunctionName, self int64, stack []phlaremodel.FunctionName) { h.Reset() for _, loc := range stack { - _, _ = h.WriteString(loc) + _, _ = h.WriteString(string(loc)) } m = append(m, [2]uint64{h.Sum64(), uint64(self)}) }) @@ -162,3 +186,64 @@ func Test_Stats(t *testing.T) { } require.Equal(t, expected, actual) } + +func TestWritePartition(t *testing.T) { + p := NewPartitionWriter(0, &Config{ + Version: FormatV3, + Stacktraces: StacktracesConfig{ + MaxNodesPerChunk: 4 << 20, + }, + Parquet: ParquetConfig{ + MaxBufferRowCount: 100 << 10, + }, + }) + profile := pprofth.NewProfileBuilder(time.Now().UnixNano()). + CPUProfile(). + WithLabels(phlaremodel.LabelNameServiceName, "svc"). + ForStacktraceString("foo", "bar"). + AddSamples(1). + ForStacktraceString("qwe", "foo", "bar"). + AddSamples(2) + + profiles := p.WriteProfileSymbols(profile.Profile) + symdbBlob := bytes.NewBuffer(nil) + err := WritePartition(p, symdbBlob) + require.NoError(t, err) + + bucket := phlareobj.NewBucket(memory.NewInMemBucket()) + require.NoError(t, bucket.Upload(context.Background(), DefaultFileName, bytes.NewReader(symdbBlob.Bytes()))) + reader, err := Open(context.Background(), bucket, testBlockMeta) + require.NoError(t, err) + + r := NewResolver(context.Background(), reader) + defer r.Release() + r.AddSamples(0, profiles[0].Samples) + resolved, err := r.Tree() + require.NoError(t, err) + expected := `. +└── bar: self 0 total 3 + └── foo: self 1 total 3 + └── qwe: self 2 total 2 +` + require.Equal(t, expected, resolved.String()) +} + +func BenchmarkPartitionWriter_WriteProfileSymbols(b *testing.B) { + b.ReportAllocs() + + p, err := pprof.OpenFile("testdata/profile.pb.gz") + require.NoError(b, err) + p.Normalize() + cfg := DefaultConfig().WithDirectory(b.TempDir()) + + db := NewSymDB(cfg) + + for i := 0; i < b.N; i++ { + b.StopTimer() + newP := p.CloneVT() + pw := db.PartitionWriter(uint64(i)) + b.StartTimer() + + pw.WriteProfileSymbols(newP) + } +} diff --git a/pkg/phlaredb/symdb/testdata/big-profile.pb.gz b/pkg/phlaredb/symdb/testdata/big-profile.pb.gz index 1e33ddeff2..fbb51202f4 100644 Binary files a/pkg/phlaredb/symdb/testdata/big-profile.pb.gz and b/pkg/phlaredb/symdb/testdata/big-profile.pb.gz differ diff --git a/pkg/phlaredb/symdb/testdata/symbols/v3/symbols.symdb b/pkg/phlaredb/symdb/testdata/symbols/v3/symbols.symdb new file mode 100644 index 0000000000..a58190c627 Binary files /dev/null and b/pkg/phlaredb/symdb/testdata/symbols/v3/symbols.symdb differ diff --git a/pkg/phlaredb/tsdb/bitprefix.go b/pkg/phlaredb/tsdb/bitprefix.go index de5ec9b4f7..0514539246 100644 --- a/pkg/phlaredb/tsdb/bitprefix.go +++ b/pkg/phlaredb/tsdb/bitprefix.go @@ -8,9 +8,9 @@ import ( "github.com/prometheus/prometheus/model/labels" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/shard" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/shard" ) // BitPrefixInvertedIndex is another inverted index implementation @@ -26,7 +26,7 @@ type BitPrefixInvertedIndex struct { func ValidateBitPrefixShardFactor(factor uint32) error { if requiredBits := index.NewShard(0, factor).RequiredBits(); 1< 0 { diff --git a/pkg/phlaredb/tsdb/index/index.go b/pkg/phlaredb/tsdb/index/index.go index 38c1527f54..1526efc27a 100644 --- a/pkg/phlaredb/tsdb/index/index.go +++ b/pkg/phlaredb/tsdb/index/index.go @@ -26,9 +26,9 @@ import ( "os" "path/filepath" "sort" + "strings" "unsafe" - "github.com/pkg/errors" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" @@ -36,9 +36,9 @@ import ( "github.com/prometheus/prometheus/tsdb/fileutil" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/encoding" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/encoding" ) const ( @@ -183,7 +183,7 @@ func NewTOCFromByteSlice(bs ByteSlice) (*TOC, error) { expCRC := binary.BigEndian.Uint32(b[len(b)-4:]) d := encoding.DecWrap(tsdb_enc.Decbuf{B: b[:len(b)-4]}) if d.Crc32(castagnoliTable) != expCRC { - return nil, errors.Wrap(tsdb_enc.ErrInvalidChecksum, "read TOC") + return nil, fmt.Errorf("read TOC: %w", tsdb_enc.ErrInvalidChecksum) } if err := d.Err(); err != nil { @@ -208,6 +208,10 @@ func NewTOCFromByteSlice(bs ByteSlice) (*TOC, error) { // NewWriter returns a new Writer to the given filename. It serializes data in format version 2. func NewWriter(ctx context.Context, fn string) (*Writer, error) { + return NewWriterSize(ctx, fn, 4<<20) +} + +func NewWriterSize(ctx context.Context, fn string, bufferSize int) (*Writer, error) { dir := filepath.Dir(fn) df, err := fileutil.OpenDir(dir) @@ -217,26 +221,26 @@ func NewWriter(ctx context.Context, fn string) (*Writer, error) { defer df.Close() // Close for platform windows. if err := os.RemoveAll(fn); err != nil { - return nil, errors.Wrap(err, "remove any existing index at path") + return nil, fmt.Errorf("remove any existing index at path: %w", err) } // Main index file we are building. - f, err := NewFileWriter(fn) + f, err := NewFileWriter(fn, bufferSize) if err != nil { return nil, err } // Temporary file for postings. - fP, err := NewFileWriter(fn + "_tmp_p") + fP, err := NewFileWriter(fn+"_tmp_p", bufferSize) if err != nil { return nil, err } // Temporary file for posting offset table. - fPO, err := NewFileWriter(fn + "_tmp_po") + fPO, err := NewFileWriter(fn+"_tmp_po", bufferSize) if err != nil { return nil, err } if err := df.Sync(); err != nil { - return nil, errors.Wrap(err, "sync dir") + return nil, fmt.Errorf("sync dir: %w", err) } iw := &Writer{ @@ -247,8 +251,8 @@ func NewWriter(ctx context.Context, fn string) (*Writer, error) { stage: idxStageNone, // Reusable memory. - buf1: encoding.EncWrap(tsdb_enc.Encbuf{B: make([]byte, 0, 1<<22)}), - buf2: encoding.EncWrap(tsdb_enc.Encbuf{B: make([]byte, 0, 1<<22)}), + buf1: encoding.EncWrap(tsdb_enc.Encbuf{B: make([]byte, 0, bufferSize)}), + buf2: encoding.EncWrap(tsdb_enc.Encbuf{B: make([]byte, 0, bufferSize)}), symbolCache: make(map[string]symbolCacheEntry, 1<<8), labelNames: make(map[string]uint64, 1<<8), @@ -279,14 +283,14 @@ type FileWriter struct { name string } -func NewFileWriter(name string) (*FileWriter, error) { +func NewFileWriter(name string, bufferSize int) (*FileWriter, error) { f, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR, 0o666) if err != nil { return nil, err } return &FileWriter{ f: f, - fbuf: bufio.NewWriterSize(f, 1<<22), + fbuf: bufio.NewWriterSize(f, bufferSize), pos: 0, name: name, }, nil @@ -308,7 +312,7 @@ func (fw *FileWriter) Write(bufs ...[]byte) error { // Once we move to compressed/varint representations in those areas, this limitation // can be lifted. if fw.pos > 16*math.MaxUint32 { - return errors.Errorf("%q exceeding max size of 64GiB", fw.name) + return fmt.Errorf("%q exceeding max size of 64GiB", fw.name) } } return nil @@ -335,7 +339,7 @@ func (fw *FileWriter) AddPadding(size int) error { p = uint64(size) - p if err := fw.Write(make([]byte, p)); err != nil { - return errors.Wrap(err, "add padding") + return fmt.Errorf("add padding: %w", err) } return nil } @@ -373,7 +377,7 @@ func (w *Writer) ensureStage(s indexWriterStage) error { } } if w.stage > s { - return errors.Errorf("invalid stage %q, currently at %q", s, w.stage) + return fmt.Errorf("invalid stage %q, currently at %q", s, w.stage) } // Mark start of sections in table of contents. @@ -454,16 +458,16 @@ func (w *Writer) AddSeries(ref storage.SeriesRef, lset phlaremodel.Labels, fp mo labelHash := uint64(fp) if ref < w.lastRef && len(w.lastSeries) != 0 { - return errors.Errorf("series with reference greater than %d already added", ref) + return fmt.Errorf("series with reference greater than %d already added", ref) } // We add padding to 16 bytes to increase the addressable space we get through 4 byte // series references. if err := w.addPadding(16); err != nil { - return errors.Errorf("failed to write padding bytes: %v", err) + return fmt.Errorf("failed to write padding bytes: %v", err) } if w.f.pos%16 != 0 { - return errors.Errorf("series write not 16-byte aligned at %d", w.f.pos) + return fmt.Errorf("series write not 16-byte aligned at %d", w.f.pos) } w.buf2.Reset() @@ -477,7 +481,7 @@ func (w *Writer) AddSeries(ref storage.SeriesRef, lset phlaremodel.Labels, fp mo if !ok { nameIndex, err = w.symbols.ReverseLookup(l.Name) if err != nil { - return errors.Errorf("symbol entry for %q does not exist, %v", l.Name, err) + return fmt.Errorf("symbol entry for %q does not exist, %v", l.Name, err) } } w.labelNames[l.Name]++ @@ -487,7 +491,7 @@ func (w *Writer) AddSeries(ref storage.SeriesRef, lset phlaremodel.Labels, fp mo if !ok || cacheEntry.lastValue != l.Value { valueIndex, err = w.symbols.ReverseLookup(l.Value) if err != nil { - return errors.Errorf("symbol entry for %q does not exist, %v", l.Value, err) + return fmt.Errorf("symbol entry for %q does not exist, %v", l.Value, err) } w.symbolCache[l.Name] = symbolCacheEntry{ index: nameIndex, @@ -540,7 +544,7 @@ func (w *Writer) AddSeries(ref storage.SeriesRef, lset phlaremodel.Labels, fp mo } if err := w.write(w.buf1.Get(), w.buf2.Get()); err != nil { - return errors.Wrap(err, "write series data") + return fmt.Errorf("write series data: %w", err) } return nil @@ -558,7 +562,7 @@ func (w *Writer) AddSymbol(sym string) error { return err } if w.numSymbols != 0 && sym <= w.lastSymbol { - return errors.Errorf("symbol %q out-of-order", sym) + return fmt.Errorf("symbol %q out-of-order", sym) } w.lastSymbol = sym w.numSymbols++ @@ -571,7 +575,7 @@ func (w *Writer) finishSymbols() error { symbolTableSize := w.f.pos - w.toc.Symbols - 4 // The symbol table's part is 4 bytes. So the total symbol table size must be less than or equal to 2^32-1 if symbolTableSize > math.MaxUint32 { - return errors.Errorf("symbol table size exceeds 4 bytes: %d", symbolTableSize) + return fmt.Errorf("symbol table size exceeds 4 bytes: %d", symbolTableSize) } // Write out the length and symbol count. @@ -584,7 +588,7 @@ func (w *Writer) finishSymbols() error { hashPos := w.f.pos // Leave space for the hash. We can only calculate it - // now that the number of symbols is known, so mmap and do it from there. + // now that the number of symbols is known, so seek back and write it. if err := w.write([]byte("hash")); err != nil { return err } @@ -605,9 +609,9 @@ func (w *Writer) finishSymbols() error { } // Load in the symbol table efficiently for the rest of the index writing. - w.symbols, err = NewSymbols(RealByteSlice(w.symbolFile.Bytes()), FormatV2, int(w.toc.Symbols)) + w.symbols, err = NewSymbols(RealByteSlice(w.symbolFile.Bytes()), int(w.toc.Symbols)) if err != nil { - return errors.Wrap(err, "read symbols") + return fmt.Errorf("read symbols: %w", err) } return nil } @@ -704,7 +708,7 @@ func (w *Writer) writeLabelIndex(name string, values []uint32) error { w.buf1.Reset() l := w.f.pos - startPos - 4 if l > math.MaxUint32 { - return errors.Errorf("label index size exceeds 4 bytes: %d", l) + return fmt.Errorf("label index size exceeds 4 bytes: %d", l) } w.buf1.PutBE32int(int(l)) if err := w.writeAt(w.buf1.Get(), startPos); err != nil { @@ -748,7 +752,7 @@ func (w *Writer) writeLabelIndexesOffsetTable() error { w.buf1.Reset() l := w.f.pos - startPos - 4 if l > math.MaxUint32 { - return errors.Errorf("label indexes offset table size exceeds 4 bytes: %d", l) + return fmt.Errorf("label indexes offset table size exceeds 4 bytes: %d", l) } w.buf1.PutBE32int(int(l)) if err := w.writeAt(w.buf1.Get(), startPos); err != nil { @@ -829,7 +833,7 @@ func (w *Writer) writePostingsOffsetTable() error { w.buf1.Reset() l := w.f.pos - startPos - 4 if l > math.MaxUint32 { - return errors.Errorf("postings offset table size exceeds 4 bytes: %d", l) + return fmt.Errorf("postings offset table size exceeds 4 bytes: %d", l) } w.buf1.PutBE32int(int(l)) if err := w.writeAt(w.buf1.Get(), startPos); err != nil { @@ -858,7 +862,7 @@ func (w *Writer) writeFingerprintOffsetsTable() error { // TODO(owen-d): can remove the uint32 cast in the future // Had to uint32 wrap these for arm32 builds, which we'll remove in the future. if uint32(ln) > uint32(math.MaxUint32) { - return errors.Errorf("fingerprint offset size exceeds 4 bytes: %d", ln) + return fmt.Errorf("fingerprint offset size exceeds 4 bytes: %d", ln) } w.buf2.PutBE32int(ln) @@ -869,7 +873,7 @@ func (w *Writer) writeFingerprintOffsetsTable() error { // write offsets+checksum w.buf1.PutHash(w.crc32) if err := w.write(w.buf1.Get()); err != nil { - return errors.Wrap(err, "failure writing fingerprint offsets") + return fmt.Errorf("failure writing fingerprint offsets: %w", err) } return nil } @@ -920,7 +924,7 @@ func (w *Writer) writePostingsToTmpFiles() error { d.ConsumePadding() startPos := w.toc.LabelIndices - uint64(d.Len()) if startPos%16 != 0 { - return errors.Errorf("series not 16-byte aligned at %d", startPos) + return fmt.Errorf("series not 16-byte aligned at %d", startPos) } offsets = append(offsets, uint32(startPos/16)) // Skip to next series. @@ -942,7 +946,10 @@ func (w *Writer) writePostingsToTmpFiles() error { // using more memory than a single label name can. for len(names) > 0 { if w.labelNames[names[0]]+c > maxPostings { - break + if c > 0 { + break + } + return fmt.Errorf("corruption detected when writing postings to index: label %q has %d uses, but maxPostings is %d", names[0], w.labelNames[names[0]], maxPostings) } batchNames = append(batchNames, names[0]) c += w.labelNames[names[0]] @@ -1016,7 +1023,6 @@ func (w *Writer) writePostingsToTmpFiles() error { return w.ctx.Err() default: } - } return nil } @@ -1043,7 +1049,7 @@ func (w *Writer) writePosting(name, value string, offs []uint32) error { for _, off := range offs { if off > (1<<32)-1 { - return errors.Errorf("series offset %d exceeds 4 bytes", off) + return fmt.Errorf("series offset %d exceeds 4 bytes", off) } w.buf1.PutBE32(off) } @@ -1052,7 +1058,7 @@ func (w *Writer) writePosting(name, value string, offs []uint32) error { l := w.buf1.Len() // We convert to uint to make code compile on 32-bit systems, as math.MaxUint32 doesn't fit into int there. if uint(l) > math.MaxUint32 { - return errors.Errorf("posting size exceeds 4 bytes: %d", l) + return fmt.Errorf("posting size exceeds 4 bytes: %d", l) } w.buf2.PutBE32int(l) w.buf1.PutHash(w.crc32) @@ -1074,12 +1080,13 @@ func (w *Writer) writePostings() error { return err } // Don't need to calculate a checksum, so can copy directly. - n, err := io.CopyBuffer(w.f.fbuf, w.fP.f, make([]byte, 1<<20)) + buf := w.buf1.B[:cap(w.buf1.B)] + n, err := io.CopyBuffer(w.f.fbuf, w.fP.f, buf) if err != nil { return err } if uint64(n) != w.fP.pos { - return errors.Errorf("wrote %d bytes to posting temporary file, but only read back %d", w.fP.pos, n) + return fmt.Errorf("wrote %d bytes to posting temporary file, but only read back %d", w.fP.pos, n) } w.f.pos += uint64(n) @@ -1151,8 +1158,6 @@ type Reader struct { // Map of LabelName to a list of some LabelValues's position in the offset table. // The first and last values for each name are always present. postings map[string][]postingOffset - // For the v1 format, labelname -> labelvalue -> offset. - postingsV1 map[string]map[string]uint64 symbols *Symbols nameSymbols map[uint32]string // Cache of the label name symbol lookups, @@ -1161,8 +1166,6 @@ type Reader struct { fingerprintOffsets FingerprintOffsets dec *Decoder - - version int } type postingOffset struct { @@ -1223,86 +1226,73 @@ func newReader(b ByteSlice, c io.Closer) (*Reader, error) { // Verify header. if r.b.Len() < HeaderLen { - return nil, errors.Wrap(tsdb_enc.ErrInvalidSize, "index header") + return nil, fmt.Errorf("index header: %w", tsdb_enc.ErrInvalidSize) } if m := binary.BigEndian.Uint32(r.b.Range(0, 4)); m != MagicIndex { - return nil, errors.Errorf("invalid magic number %x", m) + return nil, fmt.Errorf("invalid magic number %x", m) } - r.version = int(r.b.Range(4, 5)[0]) + version := int(r.b.Range(4, 5)[0]) - if r.version != FormatV1 && r.version != FormatV2 { - return nil, errors.Errorf("unknown index file version %d", r.version) + if version != FormatV2 { + return nil, fmt.Errorf("unknown index file version %d", version) } var err error r.toc, err = NewTOCFromByteSlice(b) if err != nil { - return nil, errors.Wrap(err, "read TOC") + return nil, fmt.Errorf("read TOC: %w", err) } - r.symbols, err = NewSymbols(r.b, r.version, int(r.toc.Symbols)) + r.symbols, err = NewSymbols(r.b, int(r.toc.Symbols)) if err != nil { - return nil, errors.Wrap(err, "read symbols") - } - - if r.version == FormatV1 { - // Earlier V1 formats don't have a sorted postings offset table, so - // load the whole offset table into memory. - r.postingsV1 = map[string]map[string]uint64{} - if err := ReadOffsetTable(r.b, r.toc.PostingsTable, func(key []string, off uint64, _ int) error { - if len(key) != 2 { - return errors.Errorf("unexpected key length for posting table %d", len(key)) - } - if _, ok := r.postingsV1[key[0]]; !ok { - r.postingsV1[key[0]] = map[string]uint64{} - r.postings[key[0]] = nil // Used to get a list of labelnames in places. - } - r.postingsV1[key[0]][key[1]] = off - return nil - }); err != nil { - return nil, errors.Wrap(err, "read postings table") - } - } else { - var lastKey []string - lastOff := 0 - valueCount := 0 - // For the postings offset table we keep every label name but only every nth - // label value (plus the first and last one), to save memory. - if err := ReadOffsetTable(r.b, r.toc.PostingsTable, func(key []string, _ uint64, off int) error { - if len(key) != 2 { - return errors.Errorf("unexpected key length for posting table %d", len(key)) - } - if _, ok := r.postings[key[0]]; !ok { - // Next label name. - r.postings[key[0]] = []postingOffset{} - if lastKey != nil { - // Always include last value for each label name. - r.postings[lastKey[0]] = append(r.postings[lastKey[0]], postingOffset{value: lastKey[1], off: lastOff}) - } - lastKey = nil - valueCount = 0 - } - if valueCount%symbolFactor == 0 { - r.postings[key[0]] = append(r.postings[key[0]], postingOffset{value: key[1], off: off}) - lastKey = nil - } else { - lastKey = key - lastOff = off + return nil, fmt.Errorf("read symbols: %w", err) + } + + // lastNameB/lastValueB alias the underlying buffer and are only converted + // to owned strings if the entry turns out to be the final one for its label. + var lastNameB, lastValueB []byte + lastOff := 0 + valueCount := 0 + // For the postings offset table we keep every label name but only every nth + // label value (plus the first and last one), to save memory. + if err := readPostingsOffsetTable(r.b, r.toc.PostingsTable, func(name, value []byte, _ uint64, off int) error { + // yoloString aliases the buffer — safe for map lookup (no allocation). + if _, ok := r.postings[yoloString(name)]; !ok { + // First entry for a new label name: flush the deferred "last" entry + // from the previous label, then allocate an owned key string. + if lastNameB != nil { + ln := string(lastNameB) + r.postings[ln] = append(r.postings[ln], postingOffset{value: string(lastValueB), off: lastOff}) } - valueCount++ - return nil - }); err != nil { - return nil, errors.Wrap(err, "read postings table") - } - if lastKey != nil { - r.postings[lastKey[0]] = append(r.postings[lastKey[0]], postingOffset{value: lastKey[1], off: lastOff}) - } - // Trim any extra space in the slices. - for k, v := range r.postings { - l := make([]postingOffset, len(v)) - copy(l, v) - r.postings[k] = l + lastNameB = nil + valueCount = 0 + r.postings[string(name)] = []postingOffset{} + } + if valueCount%symbolFactor == 0 { + // Sampled entry: allocate owned strings only for what we keep. + ln := string(name) + r.postings[ln] = append(r.postings[ln], postingOffset{value: string(value), off: off}) + lastNameB = nil + } else { + // Discard this entry for now; remember it as a candidate "last". + lastNameB = name + lastValueB = value + lastOff = off } + valueCount++ + return nil + }); err != nil { + return nil, fmt.Errorf("read postings table: %w", err) + } + if lastNameB != nil { + ln := string(lastNameB) + r.postings[ln] = append(r.postings[ln], postingOffset{value: string(lastValueB), off: lastOff}) + } + // Trim any extra space in the slices. + for k, v := range r.postings { + l := make([]postingOffset, len(v)) + copy(l, v) + r.postings[k] = l } r.nameSymbols = make(map[uint32]string, len(r.postings)) @@ -1312,14 +1302,14 @@ func newReader(b ByteSlice, c io.Closer) (*Reader, error) { } off, err := r.symbols.ReverseLookup(k) if err != nil { - return nil, errors.Wrap(err, "reverse symbol lookup") + return nil, fmt.Errorf("reverse symbol lookup: %w", err) } r.nameSymbols[off] = k } r.fingerprintOffsets, err = readFingerprintOffsetsTable(r.b, r.toc.FingerprintOffsets) if err != nil { - return nil, errors.Wrap(err, "loading fingerprint offsets") + return nil, fmt.Errorf("loading fingerprint offsets: %w", err) } r.dec = &Decoder{LookupSymbol: r.lookupSymbol} @@ -1329,7 +1319,7 @@ func newReader(b ByteSlice, c io.Closer) (*Reader, error) { // Version returns the file format version of the underlying index. func (r *Reader) Version() int { - return r.version + return FormatV2 } // FileInfo returns some general stats about the underlying file @@ -1361,29 +1351,25 @@ type Range struct { // for all postings lists. func (r *Reader) PostingsRanges() (map[labels.Label]Range, error) { m := map[labels.Label]Range{} - if err := ReadOffsetTable(r.b, r.toc.PostingsTable, func(key []string, off uint64, _ int) error { - if len(key) != 2 { - return errors.Errorf("unexpected key length for posting table %d", len(key)) - } + if err := readPostingsOffsetTable(r.b, r.toc.PostingsTable, func(name, value []byte, off uint64, _ int) error { d := encoding.DecWrap(tsdb_enc.NewDecbufAt(r.b, int(off), castagnoliTable)) if d.Err() != nil { return d.Err() } - m[labels.Label{Name: key[0], Value: key[1]}] = Range{ + m[labels.Label{Name: string(name), Value: string(value)}] = Range{ Start: int64(off) + 4, End: int64(off) + 4 + int64(d.Len()), } return nil }); err != nil { - return nil, errors.Wrap(err, "read postings table") + return nil, fmt.Errorf("read postings table: %w", err) } return m, nil } type Symbols struct { - bs ByteSlice - version int - off int + bs ByteSlice + off int offsets []int seen int @@ -1392,11 +1378,10 @@ type Symbols struct { const symbolFactor = 32 // NewSymbols returns a Symbols object for symbol lookups. -func NewSymbols(bs ByteSlice, version, off int) (*Symbols, error) { +func NewSymbols(bs ByteSlice, off int) (*Symbols, error) { s := &Symbols{ - bs: bs, - version: version, - off: off, + bs: bs, + off: off, } d := encoding.DecWrap(tsdb_enc.NewDecbufAt(bs, off, castagnoliTable)) var ( @@ -1423,17 +1408,13 @@ func (s Symbols) Lookup(o uint32) (string, error) { B: s.bs.Range(0, s.bs.Len()), }) - if s.version == FormatV2 { - if int(o) >= s.seen { - return "", errors.Errorf("unknown symbol offset %d", o) - } - d.Skip(s.offsets[int(o/symbolFactor)]) - // Walk until we find the one we want. - for i := o - (o / symbolFactor * symbolFactor); i > 0; i-- { - d.UvarintBytes() - } - } else { - d.Skip(int(o)) + if int(o) >= s.seen { + return "", fmt.Errorf("unknown symbol offset %d", o) + } + d.Skip(s.offsets[int(o/symbolFactor)]) + // Walk until we find the one we want. + for i := o - (o / symbolFactor * symbolFactor); i > 0; i-- { + d.UvarintBytes() } sym := d.UvarintStr() if d.Err() != nil { @@ -1444,7 +1425,7 @@ func (s Symbols) Lookup(o uint32) (string, error) { func (s Symbols) ReverseLookup(sym string) (uint32, error) { if len(s.offsets) == 0 { - return 0, errors.Errorf("unknown symbol %q - no symbols", sym) + return 0, fmt.Errorf("unknown symbol %q - no symbols", sym) } i := sort.Search(len(s.offsets), func(i int) bool { // Any decoding errors here will be lost, however @@ -1463,10 +1444,8 @@ func (s Symbols) ReverseLookup(sym string) (uint32, error) { } d.Skip(s.offsets[i]) res := i * symbolFactor - var lastLen int var lastSymbol string for d.Err() == nil && res <= s.seen { - lastLen = d.Len() lastSymbol = yoloString(d.UvarintBytes()) if lastSymbol >= sym { break @@ -1477,12 +1456,9 @@ func (s Symbols) ReverseLookup(sym string) (uint32, error) { return 0, d.Err() } if lastSymbol != sym { - return 0, errors.Errorf("unknown symbol %q", sym) - } - if s.version == FormatV2 { - return uint32(res), nil + return 0, fmt.Errorf("unknown symbol %q", sym) } - return uint32(s.bs.Len() - lastLen), nil + return uint32(res), nil } func (s Symbols) Size() int { @@ -1522,29 +1498,27 @@ func (s *symbolsIter) Next() bool { func (s symbolsIter) At() string { return s.cur } func (s symbolsIter) Err() error { return s.err } -// ReadOffsetTable reads an offset table and at the given position calls f for each -// found entry. If f returns an error it stops decoding and returns the received error. -func ReadOffsetTable(bs ByteSlice, off uint64, f func([]string, uint64, int) error) error { +// readPostingsOffsetTable reads the postings offset table at off and calls f for +// every entry. The name and value byte slices passed to f alias the underlying +// buffer (no per-entry allocation); convert with string(...) if you need to +// retain them. labelOffset is the position of the entry within the table. +func readPostingsOffsetTable(bs ByteSlice, off uint64, f func(name, value []byte, postingsOffset uint64, labelOffset int) error) error { d := encoding.DecWrap(tsdb_enc.NewDecbufAt(bs, int(off), castagnoliTable)) startLen := d.Len() cnt := d.Be32() for d.Err() == nil && d.Len() > 0 && cnt > 0 { offsetPos := startLen - d.Len() - keyCount := d.Uvarint() - // The Postings offset table takes only 2 keys per entry (name and value of label), - // and the LabelIndices offset table takes only 1 key per entry (a label name). - // Hence setting the size to max of both, i.e. 2. - keys := make([]string, 0, 2) - - for i := 0; i < keyCount; i++ { - keys = append(keys, d.UvarintStr()) + if keyCount := d.Uvarint(); keyCount != 2 { + return fmt.Errorf("unexpected number of keys for postings offset table %d", keyCount) } + name := d.UvarintBytes() + value := d.UvarintBytes() o := d.Uvarint64() if d.Err() != nil { break } - if err := f(keys, o, offsetPos); err != nil { + if err := f(name, value, o, offsetPos); err != nil { return err } cnt-- @@ -1585,9 +1559,15 @@ func (r *Reader) Checksum() uint32 { return r.toc.Metadata.Checksum } -// Symbols returns an iterator over the symbols that exist within the index. -func (r *Reader) Symbols() StringIter { - return r.symbols.Iter() +// SymbolTable returns all symbols in the index as owned strings safe to use +// beyond the reader's lifetime. +func (r *Reader) SymbolTable() ([]string, error) { + iter := r.symbols.Iter() + syms := make([]string, 0, r.symbols.seen) + for iter.Next() { + syms = append(syms, strings.Clone(iter.At())) + } + return syms, iter.Err() } // SymbolTableSize returns the symbol table size in bytes. @@ -1595,38 +1575,12 @@ func (r *Reader) SymbolTableSize() uint64 { return uint64(r.symbols.Size()) } -// SortedLabelValues returns value tuples that exist for the given label name. -// It is not safe to use the return value beyond the lifetime of the byte slice -// passed into the Reader. -func (r *Reader) SortedLabelValues(name string, matchers ...*labels.Matcher) ([]string, error) { - values, err := r.LabelValues(name, matchers...) - if err == nil && r.version == FormatV1 { - sort.Strings(values) - } - return values, err -} - // LabelValues returns value tuples that exist for the given label name. -// It is not safe to use the return value beyond the lifetime of the byte slice -// passed into the Reader. -// TODO(replay): Support filtering by matchers func (r *Reader) LabelValues(name string, matchers ...*labels.Matcher) ([]string, error) { if len(matchers) > 0 { - return nil, errors.Errorf("matchers parameter is not implemented: %+v", matchers) + return nil, fmt.Errorf("matchers parameter is not implemented: %+v", matchers) } - if r.version == FormatV1 { - e, ok := r.postingsV1[name] - if !ok { - return nil, nil - } - values := make([]string, 0, len(e)) - for k := range e { - values = append(values, k) - } - return values, nil - - } e, ok := r.postings[name] if !ok { return nil, nil @@ -1652,7 +1606,7 @@ func (r *Reader) LabelValues(name string, matchers ...*labels.Matcher) ([]string } else { d.Skip(skip) } - s := yoloString(d.UvarintBytes()) // Label value. + s := string(d.UvarintBytes()) // Label value — owned copy, safe beyond reader lifetime. values = append(values, s) if s == lastVal { break @@ -1660,7 +1614,7 @@ func (r *Reader) LabelValues(name string, matchers ...*labels.Matcher) ([]string d.Uvarint64() // Offset. } if d.Err() != nil { - return nil, errors.Wrap(d.Err(), "get postings offset entry") + return nil, fmt.Errorf("get postings offset entry: %w", d.Err()) } return values, nil } @@ -1671,22 +1625,18 @@ func (r *Reader) LabelNamesFor(ids ...storage.SeriesRef) ([]string, error) { // Gather offsetsMap the name offsetsMap in the symbol table first offsetsMap := make(map[uint32]struct{}) for _, id := range ids { - offset := id - // In version 2 series IDs are no longer exact references but series are 16-byte padded - // and the ID is the multiple of 16 of the actual position. - if r.version == FormatV2 { - offset = id * 16 - } + // Series IDs are 16-byte padded; the ID is the multiple of 16 of the actual position. + offset := id * 16 d := encoding.DecWrap(tsdb_enc.NewDecbufUvarintAt(r.b, int(offset), castagnoliTable)) buf := d.Get() if d.Err() != nil { - return nil, errors.Wrap(d.Err(), "get buffer for series") + return nil, fmt.Errorf("get buffer for series: %w", d.Err()) } offsets, err := r.dec.LabelNamesOffsetsFor(buf) if err != nil { - return nil, errors.Wrap(err, "get label name offsets") + return nil, fmt.Errorf("get label name offsets: %w", err) } for _, off := range offsets { offsetsMap[off] = struct{}{} @@ -1698,7 +1648,7 @@ func (r *Reader) LabelNamesFor(ids ...storage.SeriesRef) ([]string, error) { for off := range offsetsMap { name, err := r.lookupSymbol(off) if err != nil { - return nil, errors.Wrap(err, "lookup symbol in LabelNamesFor") + return nil, fmt.Errorf("lookup symbol in LabelNamesFor: %w", err) } names = append(names, name) } @@ -1710,16 +1660,12 @@ func (r *Reader) LabelNamesFor(ids ...storage.SeriesRef) ([]string, error) { // LabelValueFor returns label value for the given label name in the series referred to by ID. func (r *Reader) LabelValueFor(id storage.SeriesRef, label string) (string, error) { - offset := id - // In version 2 series IDs are no longer exact references but series are 16-byte padded - // and the ID is the multiple of 16 of the actual position. - if r.version == FormatV2 { - offset = id * 16 - } + // Series IDs are 16-byte padded; the ID is the multiple of 16 of the actual position. + offset := id * 16 d := encoding.DecWrap(tsdb_enc.NewDecbufUvarintAt(r.b, int(offset), castagnoliTable)) buf := d.Get() if d.Err() != nil { - return "", errors.Wrap(d.Err(), "label values for") + return "", fmt.Errorf("label values for: %w", d.Err()) } value, err := r.dec.LabelValueFor(buf, label) @@ -1736,12 +1682,8 @@ func (r *Reader) LabelValueFor(id storage.SeriesRef, label string) (string, erro // Series reads the series with the given ID and writes its labels and chunks into lbls and chks. func (r *Reader) Series(id storage.SeriesRef, lbls *phlaremodel.Labels, chks *[]ChunkMeta) (uint64, error) { - offset := id - // In version 2 series IDs are no longer exact references but series are 16-byte padded - // and the ID is the multiple of 16 of the actual position. - if r.version == FormatV2 { - offset = id * 16 - } + // Series IDs are 16-byte padded; the ID is the multiple of 16 of the actual position. + offset := id * 16 d := encoding.DecWrap(tsdb_enc.NewDecbufUvarintAt(r.b, int(offset), castagnoliTable)) if d.Err() != nil { return 0, d.Err() @@ -1749,19 +1691,15 @@ func (r *Reader) Series(id storage.SeriesRef, lbls *phlaremodel.Labels, chks *[] fprint, err := r.dec.Series(d.Get(), lbls, chks, false) if err != nil { - return 0, errors.Wrap(err, "read series") + return 0, fmt.Errorf("read series: %w", err) } return fprint, nil } // SeriesBy is like Series but allows to group labels by name. This avoid looking up all label symbols for requested series. func (r *Reader) SeriesBy(id storage.SeriesRef, lbls *phlaremodel.Labels, chks *[]ChunkMeta, by ...string) (uint64, error) { - offset := id - // In version 2 series IDs are no longer exact references but series are 16-byte padded - // and the ID is the multiple of 16 of the actual position. - if r.version == FormatV2 { - offset = id * 16 - } + // Series IDs are 16-byte padded; the ID is the multiple of 16 of the actual position. + offset := id * 16 d := encoding.DecWrap(tsdb_enc.NewDecbufUvarintAt(r.b, int(offset), castagnoliTable)) if d.Err() != nil { return 0, d.Err() @@ -1769,34 +1707,12 @@ func (r *Reader) SeriesBy(id storage.SeriesRef, lbls *phlaremodel.Labels, chks * fprint, err := r.dec.Series(d.Get(), lbls, chks, true, by...) if err != nil { - return 0, errors.Wrap(err, "read series") + return 0, fmt.Errorf("read series: %w", err) } return fprint, nil } func (r *Reader) Postings(name string, shard *ShardAnnotation, values ...string) (Postings, error) { - if r.version == FormatV1 { - e, ok := r.postingsV1[name] - if !ok { - return EmptyPostings(), nil - } - res := make([]Postings, 0, len(values)) - for _, v := range values { - postingsOff, ok := e[v] - if !ok { - continue - } - // Read from the postings table. - d := encoding.DecWrap(tsdb_enc.NewDecbufAt(r.b, int(postingsOff), castagnoliTable)) - _, p, err := r.dec.Postings(d.Get()) - if err != nil { - return nil, errors.Wrap(err, "decode postings") - } - res = append(res, p) - } - return Merge(res...), nil - } - e, ok := r.postings[name] if !ok { return EmptyPostings(), nil @@ -1851,7 +1767,7 @@ func (r *Reader) Postings(name string, shard *ShardAnnotation, values ...string) d2 := encoding.DecWrap(tsdb_enc.NewDecbufAt(r.b, int(postingsOff), castagnoliTable)) _, p, err := r.dec.Postings(d2.Get()) if err != nil { - return nil, errors.Wrap(err, "decode postings") + return nil, fmt.Errorf("decode postings: %w", err) } res = append(res, p) } @@ -1867,7 +1783,7 @@ func (r *Reader) Postings(name string, shard *ShardAnnotation, values ...string) } } if d.Err() != nil { - return nil, errors.Wrap(d.Err(), "get postings offset entry") + return nil, fmt.Errorf("get postings offset entry: %w", d.Err()) } } @@ -1879,6 +1795,62 @@ func (r *Reader) Postings(name string, shard *ShardAnnotation, values ...string) return merged, nil } +// PostingsForLabelMatching returns the merged postings for all values of label +// name for which match returns true. It is equivalent to calling LabelValues +// followed by Postings but avoids allocating an intermediate string slice and +// never lets the label value strings escape the index buffer. +func (r *Reader) PostingsForLabelMatching(name string, shard *ShardAnnotation, match func(YoloString) bool) (Postings, error) { + e, ok := r.postings[name] + if !ok { + return EmptyPostings(), nil + } + if len(e) == 0 { + return EmptyPostings(), nil + } + + d := encoding.DecWrap(tsdb_enc.NewDecbufAt(r.b, int(r.toc.PostingsTable), nil)) + d.Skip(e[0].off) + lastVal := e[len(e)-1].value + + var res []Postings + skip := 0 + for d.Err() == nil { + if skip == 0 { + skip = d.Len() + d.Uvarint() // Keycount. + d.UvarintBytes() // Label name. + skip -= d.Len() + } else { + d.Skip(skip) + } + v := d.UvarintBytes() // Label value — zero-copy slice into buffer. + postingsOff := d.Uvarint64() + if d.Err() != nil { + break + } + if match(YoloString{String: yoloString(v)}) { + d2 := encoding.DecWrap(tsdb_enc.NewDecbufAt(r.b, int(postingsOff), castagnoliTable)) + _, p, err := r.dec.Postings(d2.Get()) + if err != nil { + return nil, fmt.Errorf("decode postings: %w", err) + } + res = append(res, p) + } + if yoloString(v) == lastVal { + break + } + } + if d.Err() != nil { + return nil, fmt.Errorf("get postings offset entry: %w", d.Err()) + } + + merged := Merge(res...) + if shard != nil { + return NewShardedPostings(merged, *shard, r.fingerprintOffsets), nil + } + return merged, nil +} + // Size returns the size of an index file. func (r *Reader) Size() int64 { return int64(r.b.Len()) @@ -1888,7 +1860,7 @@ func (r *Reader) Size() int64 { // TODO(twilkie) implement support for matchers func (r *Reader) LabelNames(matchers ...*labels.Matcher) ([]string, error) { if len(matchers) > 0 { - return nil, errors.Errorf("matchers parameter is not implemented: %+v", matchers) + return nil, fmt.Errorf("matchers parameter is not implemented: %+v", matchers) } labelNames := make([]string, 0, len(r.postings)) @@ -1938,7 +1910,7 @@ func (dec *Decoder) LabelNamesOffsetsFor(b []byte) ([]uint32, error) { _ = d.Uvarint() // skip the label value if d.Err() != nil { - return nil, errors.Wrap(d.Err(), "read series label offsets") + return nil, fmt.Errorf("read series label offsets: %w", d.Err()) } } @@ -1956,18 +1928,18 @@ func (dec *Decoder) LabelValueFor(b []byte, label string) (string, error) { lvo := uint32(d.Uvarint()) if d.Err() != nil { - return "", errors.Wrap(d.Err(), "read series label offsets") + return "", fmt.Errorf("read series label offsets: %w", d.Err()) } ln, err := dec.LookupSymbol(lno) if err != nil { - return "", errors.Wrap(err, "lookup label name") + return "", fmt.Errorf("lookup label name: %w", err) } if ln == label { lv, err := dec.LookupSymbol(lvo) if err != nil { - return "", errors.Wrap(err, "lookup label value") + return "", fmt.Errorf("lookup label value: %w", err) } return lv, nil @@ -1994,7 +1966,7 @@ func (dec *Decoder) Series(b []byte, lbls *phlaremodel.Labels, chks *[]ChunkMeta lvo := uint32(d.Uvarint()) if d.Err() != nil { - return 0, errors.Wrap(d.Err(), "read series label offsets") + return 0, fmt.Errorf("read series label offsets: %w", d.Err()) } if lbls == nil { continue @@ -2005,7 +1977,7 @@ func (dec *Decoder) Series(b []byte, lbls *phlaremodel.Labels, chks *[]ChunkMeta } ln, err := dec.LookupSymbol(lno) if err != nil { - return 0, errors.Wrap(err, "lookup label name") + return 0, fmt.Errorf("lookup label name: %w", err) } if group { var found bool @@ -2021,7 +1993,7 @@ func (dec *Decoder) Series(b []byte, lbls *phlaremodel.Labels, chks *[]ChunkMeta } lv, err := dec.LookupSymbol(lvo) if err != nil { - return 0, errors.Wrap(err, "lookup label value") + return 0, fmt.Errorf("lookup label value: %w", err) } *lbls = append(*lbls, &typesv1.LabelPair{Name: ln, Value: lv}) @@ -2060,7 +2032,7 @@ func (dec *Decoder) Series(b []byte, lbls *phlaremodel.Labels, chks *[]ChunkMeta t0 = maxt if d.Err() != nil { - return 0, errors.Wrapf(d.Err(), "read meta for chunk %d", i) + return 0, fmt.Errorf("read meta for chunk %d: %w", i, d.Err()) } *chks = append(*chks, ChunkMeta{ @@ -2074,6 +2046,10 @@ func (dec *Decoder) Series(b []byte, lbls *phlaremodel.Labels, chks *[]ChunkMeta return fprint, d.Err() } +// YoloString is a string that aliases the index buffer and is only valid for +// the duration of the call that produced it. Never store or escape it. +type YoloString struct{ String string } + func yoloString(b []byte) string { return *((*string)(unsafe.Pointer(&b))) } diff --git a/pkg/phlaredb/tsdb/index/index_test.go b/pkg/phlaredb/tsdb/index/index_test.go index d420937217..14d2bf37f5 100644 --- a/pkg/phlaredb/tsdb/index/index_test.go +++ b/pkg/phlaredb/tsdb/index/index_test.go @@ -15,6 +15,7 @@ package index import ( "context" + "errors" "fmt" "hash/crc32" "math/rand" @@ -23,7 +24,6 @@ import ( "sort" "testing" - "github.com/pkg/errors" "github.com/stretchr/testify/require" "go.uber.org/goleak" @@ -34,8 +34,8 @@ import ( "github.com/prometheus/prometheus/util/testutil" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) func TestMain(m *testing.M) { @@ -77,7 +77,7 @@ func (m mockIndex) Symbols() (map[string]struct{}, error) { func (m mockIndex) AddSeries(ref storage.SeriesRef, l phlaremodel.Labels, chunks ...ChunkMeta) error { if _, ok := m.series[ref]; ok { - return errors.Errorf("series with reference %d already added", ref) + return fmt.Errorf("series with reference %d already added", ref) } for _, lbl := range l { m.symbols[lbl.Name] = struct{}{} @@ -227,27 +227,32 @@ func TestIndexRW_Postings(t *testing.T) { // The label indices are no longer used, so test them by hand here. labelIndices := map[string][]string{} - require.NoError(t, ReadOffsetTable(ir.b, ir.toc.LabelIndicesTable, func(key []string, off uint64, _ int) error { - if len(key) != 1 { - return errors.Errorf("unexpected key length for label indices table %d", len(key)) - } - - d := encoding.NewDecbufAt(ir.b, int(off), castagnoliTable) - vals := []string{} - nc := d.Be32int() - if nc != 1 { - return errors.Errorf("unexpected number of label indices table names %d", nc) - } - for i := d.Be32(); i > 0; i-- { - v, err := ir.lookupSymbol(d.Be32()) - if err != nil { - return err + { + d := encoding.NewDecbufAt(ir.b, int(ir.toc.LabelIndicesTable), castagnoliTable) + cnt := d.Be32() + for d.Err() == nil && d.Len() > 0 && cnt > 0 { + if keyCount := d.Uvarint(); keyCount != 1 { + require.Failf(t, "label indices table", "unexpected key count %d", keyCount) } - vals = append(vals, v) + name := string(d.UvarintBytes()) + off := d.Uvarint64() + require.NoError(t, d.Err()) + + d2 := encoding.NewDecbufAt(ir.b, int(off), castagnoliTable) + vals := []string{} + nc := d2.Be32int() + require.Equal(t, 1, nc, "unexpected number of label indices table names") + for i := d2.Be32(); i > 0; i-- { + v, err := ir.lookupSymbol(d2.Be32()) + require.NoError(t, err) + vals = append(vals, v) + } + require.NoError(t, d2.Err()) + labelIndices[name] = vals + cnt-- } - labelIndices[key[0]] = vals - return d.Err() - })) + require.NoError(t, d.Err()) + } require.Equal(t, map[string][]string{ "a": {"1"}, "b": {"1", "2", "3", "4"}, @@ -350,7 +355,7 @@ func TestPostingsMany(t *testing.T) { // sort expected values by label hash instead of lexicographically by labelset sort.Slice(exp, func(i, j int) bool { - return labels.FromStrings("i", exp[i], "foo", "bar").Hash() < labels.FromStrings("i", exp[j], "foo", "bar").Hash() + return labels.StableHash(labels.FromStrings("i", exp[i], "foo", "bar")) < labels.StableHash(labels.FromStrings("i", exp[j], "foo", "bar")) }) require.Equal(t, exp, got, fmt.Sprintf("input: %v", c.in)) @@ -365,10 +370,10 @@ func TestPersistence_index_e2e(t *testing.T) { flbls := make([]phlaremodel.Labels, len(lbls)) for i, ls := range lbls { - flbls[i] = make(phlaremodel.Labels, 0, len(ls)) - for _, l := range ls { + flbls[i] = make(phlaremodel.Labels, 0, ls.Len()) + ls.Range(func(l labels.Label) { flbls[i] = append(flbls[i], &typesv1.LabelPair{Name: l.Name, Value: l.Value}) - } + }) } // Sort labels as the index writer expects series in sorted order by fingerprint. @@ -378,13 +383,13 @@ func TestPersistence_index_e2e(t *testing.T) { symbols := map[string]struct{}{} for _, lset := range lbls { - for _, l := range lset { + lset.Range(func(l labels.Label) { symbols[l.Name] = struct{}{} symbols[l.Value] = struct{}{} - } + }) } - var input indexWriterSeriesSlice + var input IndexWriterSeriesSlice // Generate ChunkMetas for every label set. for i, lset := range flbls { @@ -397,9 +402,9 @@ func TestPersistence_index_e2e(t *testing.T) { Checksum: rand.Uint32(), }) } - input = append(input, &indexWriterSeries{ - labels: lset, - chunks: metas, + input = append(input, &IndexWriterSeries{ + Labels: lset, + Chunks: metas, }) } @@ -424,11 +429,11 @@ func TestPersistence_index_e2e(t *testing.T) { mi := newMockIndex() for i, s := range input { - err = iw.AddSeries(storage.SeriesRef(i), s.labels, model.Fingerprint(s.labels.Hash()), s.chunks...) + err = iw.AddSeries(storage.SeriesRef(i), s.Labels, model.Fingerprint(s.Labels.Hash()), s.Chunks...) require.NoError(t, err) - require.NoError(t, mi.AddSeries(storage.SeriesRef(i), s.labels, s.chunks...)) + require.NoError(t, mi.AddSeries(storage.SeriesRef(i), s.Labels, s.Chunks...)) - for _, l := range s.labels { + for _, l := range s.Labels { valset, ok := values[l.Name] if !ok { valset = map[string]struct{}{} @@ -436,7 +441,7 @@ func TestPersistence_index_e2e(t *testing.T) { } valset[l.Value] = struct{}{} } - postings.Add(storage.SeriesRef(i), s.labels) + postings.Add(storage.SeriesRef(i), s.Labels) } err = iw.Close() @@ -479,8 +484,9 @@ func TestPersistence_index_e2e(t *testing.T) { for k, v := range labelPairs { sort.Strings(v) - res, err := ir.SortedLabelValues(k) + res, err := ir.LabelValues(k) require.NoError(t, err) + sort.Strings(res) require.Equal(t, len(v), len(res)) for i := 0; i < len(v); i++ { @@ -488,12 +494,9 @@ func TestPersistence_index_e2e(t *testing.T) { } } - gotSymbols := []string{} - it := ir.Symbols() - for it.Next() { - gotSymbols = append(gotSymbols, it.At()) - } - require.NoError(t, it.Err()) + gotSymbols, err := ir.SymbolTable() + require.NoError(t, err) + sort.Strings(gotSymbols) expSymbols := []string{} for s := range mi.symbols { expSymbols = append(expSymbols, s) @@ -549,7 +552,7 @@ func TestSymbols(t *testing.T) { checksum := crc32.Checksum(buf.Get()[symbolsStart+4:], castagnoliTable) buf.PutBE32(checksum) // Check sum at the end. - s, err := NewSymbols(RealByteSlice(buf.Get()), FormatV2, symbolsStart) + s, err := NewSymbols(RealByteSlice(buf.Get()), symbolsStart) require.NoError(t, err) // We store only 4 offsets to symbols. @@ -584,3 +587,80 @@ func TestDecoder_Postings_WrongInput(t *testing.T) { _, _, err := (&Decoder{}).Postings([]byte("the cake is a lie")) require.Error(t, err) } + +// BenchmarkNewReader measures the cost of opening an index file, dominated by +// the postings-offset-table scan in newReader. The fixture uses several label +// names with > symbolFactor (32) values each so the sampling logic is exercised. +func BenchmarkNewReader(b *testing.B) { + dir := b.TempDir() + fn := filepath.Join(dir, IndexFilename) + + iw, err := NewWriter(context.Background(), fn) + require.NoError(b, err) + + const ( + numNames = 10 + numValues = 200 + numSeries = numNames * numValues + nameFormat = "label_%02d" + valFormat = "value_%04d" + ) + + symbolSet := map[string]struct{}{} + for n := 0; n < numNames; n++ { + symbolSet[fmt.Sprintf(nameFormat, n)] = struct{}{} + } + for v := 0; v < numValues; v++ { + symbolSet[fmt.Sprintf(valFormat, v)] = struct{}{} + } + syms := make([]string, 0, len(symbolSet)) + for s := range symbolSet { + syms = append(syms, s) + } + sort.Strings(syms) + for _, s := range syms { + require.NoError(b, iw.AddSymbol(s)) + } + + series := make([]phlaremodel.Labels, 0, numSeries) + for n := 0; n < numNames; n++ { + name := fmt.Sprintf(nameFormat, n) + for v := 0; v < numValues; v++ { + series = append(series, phlaremodel.LabelsFromStrings(name, fmt.Sprintf(valFormat, v))) + } + } + sort.Slice(series, func(i, j int) bool { + return series[i].Hash() < series[j].Hash() + }) + for i, s := range series { + require.NoError(b, iw.AddSeries(storage.SeriesRef(i), s, model.Fingerprint(s.Hash()))) + } + require.NoError(b, iw.Close()) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + r, err := NewFileReader(fn) + if err != nil { + b.Fatal(err) + } + if err := r.Close(); err != nil { + b.Fatal(err) + } + } +} + +func TestWriter_ShouldReturnErrorOnSeriesWithDuplicatedLabelNames(t *testing.T) { + w, err := NewWriter(context.Background(), filepath.Join(t.TempDir(), "index")) + require.NoError(t, err) + + require.NoError(t, w.AddSymbol("__name__")) + require.NoError(t, w.AddSymbol("metric_1")) + require.NoError(t, w.AddSymbol("metric_2")) + + require.NoError(t, w.AddSeries(0, phlaremodel.LabelsFromStrings("__name__", "metric_1", "__name__", "metric_2"), 0)) + + err = w.Close() + require.Error(t, err) + require.ErrorContains(t, err, "corruption detected when writing postings to index") +} diff --git a/pkg/phlaredb/tsdb/index/postings.go b/pkg/phlaredb/tsdb/index/postings.go index a63bfb7b7d..0500f6a754 100644 --- a/pkg/phlaredb/tsdb/index/postings.go +++ b/pkg/phlaredb/tsdb/index/postings.go @@ -24,8 +24,8 @@ import ( "github.com/prometheus/prometheus/storage" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) var allPostingsKey = &typesv1.LabelPair{} @@ -730,6 +730,10 @@ type bigEndianPostings struct { cur uint32 } +func NewBigEndianPostings(list []byte) Postings { + return newBigEndianPostings(list) +} + func newBigEndianPostings(list []byte) *bigEndianPostings { return &bigEndianPostings{list: list} } diff --git a/pkg/phlaredb/tsdb/index/postings_test.go b/pkg/phlaredb/tsdb/index/postings_test.go index fc740cf493..77cb8496ae 100644 --- a/pkg/phlaredb/tsdb/index/postings_test.go +++ b/pkg/phlaredb/tsdb/index/postings_test.go @@ -24,8 +24,8 @@ import ( "github.com/prometheus/prometheus/storage" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) func TestMemPostings_addFor(t *testing.T) { diff --git a/pkg/phlaredb/tsdb/index/test_utils.go b/pkg/phlaredb/tsdb/index/test_utils.go index 9c66ad34d2..8fd9d8ab2e 100644 --- a/pkg/phlaredb/tsdb/index/test_utils.go +++ b/pkg/phlaredb/tsdb/index/test_utils.go @@ -1,19 +1,19 @@ package index import ( - phlaremodel "github.com/grafana/pyroscope/pkg/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) -type indexWriterSeries struct { - labels phlaremodel.Labels - chunks []ChunkMeta // series file offset of chunks +type IndexWriterSeries struct { + Labels phlaremodel.Labels + Chunks []ChunkMeta // series file offset of chunks } -type indexWriterSeriesSlice []*indexWriterSeries +type IndexWriterSeriesSlice []*IndexWriterSeries -func (s indexWriterSeriesSlice) Len() int { return len(s) } -func (s indexWriterSeriesSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s IndexWriterSeriesSlice) Len() int { return len(s) } +func (s IndexWriterSeriesSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s indexWriterSeriesSlice) Less(i, j int) bool { - return phlaremodel.CompareLabelPairs(s[i].labels, s[j].labels) < 0 +func (s IndexWriterSeriesSlice) Less(i, j int) bool { + return phlaremodel.CompareLabelPairs(s[i].Labels, s[j].Labels) < 0 } diff --git a/pkg/phlaredb/tsdb/index_test.go b/pkg/phlaredb/tsdb/index_test.go index d060bacaf5..51fe4647d3 100644 --- a/pkg/phlaredb/tsdb/index_test.go +++ b/pkg/phlaredb/tsdb/index_test.go @@ -6,8 +6,8 @@ import ( "testing" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/shard" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/shard" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" diff --git a/pkg/phlaredb/tsdb/shard/shard.go b/pkg/phlaredb/tsdb/shard/shard.go index ec67b51885..8fe1b9d2e9 100644 --- a/pkg/phlaredb/tsdb/shard/shard.go +++ b/pkg/phlaredb/tsdb/shard/shard.go @@ -6,11 +6,10 @@ import ( "strconv" "strings" - "github.com/pkg/errors" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" - "github.com/grafana/pyroscope/pkg/phlaredb/tsdb/index" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" ) const ( @@ -26,7 +25,7 @@ var ShardLabelRE = regexp.MustCompile("^[0-9]+_of_[0-9]+$") // ParseShard will extract the shard information encoded in ShardLabelFmt func ParseShard(input string) (parsed Annotation, err error) { if !ShardLabelRE.MatchString(input) { - return parsed, errors.Errorf("Invalid ShardLabel value: [%s]", input) + return parsed, fmt.Errorf("invalid ShardLabel value: [%s]", input) } matches := strings.Split(input, "_") @@ -40,7 +39,7 @@ func ParseShard(input string) (parsed Annotation, err error) { } if x >= of { - return parsed, errors.Errorf("Shards out of bounds: [%d] >= [%d]", x, of) + return parsed, fmt.Errorf("shards out of bounds: [%d] >= [%d]", x, of) } return Annotation{ Shard: x, diff --git a/pkg/phlaredb/validate.go b/pkg/phlaredb/validate.go index a7890d55f6..8d4ab81337 100644 --- a/pkg/phlaredb/validate.go +++ b/pkg/phlaredb/validate.go @@ -6,10 +6,10 @@ import ( "github.com/grafana/dskit/runutil" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/util" ) // ValidateLocalBlock validates the block in the given directory is readable. diff --git a/pkg/phlaredb/validate_test.go b/pkg/phlaredb/validate_test.go index 1237e979d9..ee9bb36e5c 100644 --- a/pkg/phlaredb/validate_test.go +++ b/pkg/phlaredb/validate_test.go @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/block/testutil" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) func Test_ValidateBlock(t *testing.T) { diff --git a/pkg/pprof/fix_go_profile.go b/pkg/pprof/fix_go_profile.go index adf6715de0..4098f0dd6c 100644 --- a/pkg/pprof/fix_go_profile.go +++ b/pkg/pprof/fix_go_profile.go @@ -1,7 +1,6 @@ package pprof import ( - "regexp" "strings" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" @@ -56,24 +55,55 @@ func DropGoTypeParameters(p *profilev1.Profile) *profilev1.Profile { var m ProfileMerge // We safely ignore the error as the only case when it can // happen is when merged profiles are of different types. - _ = m.Merge(p) + _ = m.Merge(p, true) return m.Profile() } -var goStructTypeParameterRegex = regexp.MustCompile(`\[go\.shape\..*\]`) +const goShapePrefix = "[go.shape." func dropGoTypeParameters(input string) string { - matchesIndices := goStructTypeParameterRegex.FindAllStringIndex(input, -1) - if len(matchesIndices) == 0 { + if !strings.Contains(input, goShapePrefix) { return input } - var modified strings.Builder - prevEnd := 0 - for _, indices := range matchesIndices { - start, end := indices[0], indices[1] - modified.WriteString(input[prevEnd:start] + "[...]") - prevEnd = end + + var result strings.Builder + i := 0 + + for i < len(input) { + // Find next type parameter section + start := strings.Index(input[i:], goShapePrefix) + if start < 0 { + // No more type parameters, write the rest + result.WriteString(input[i:]) + break + } + + // Write everything before this type parameter + result.WriteString(input[i : i+start]) + + // Find matching closing bracket by tracking depth + depth := 0 + j := i + start + for j < len(input) { + if input[j] == '[' { + depth++ + } else if input[j] == ']' { + depth-- + if depth == 0 { + // Found matching closing bracket, skip to after it + i = j + 1 + break + } + } + j++ + } + + if depth != 0 { + // No matching bracket found, keep rest as-is + result.WriteString(input[i:]) + break + } } - modified.WriteString(input[prevEnd:]) - return modified.String() + + return result.String() } diff --git a/pkg/pprof/fix_go_profile_test.go b/pkg/pprof/fix_go_profile_test.go index 6fa8d48e8f..b6ef3fa3bb 100644 --- a/pkg/pprof/fix_go_profile_test.go +++ b/pkg/pprof/fix_go_profile_test.go @@ -57,3 +57,84 @@ func Test_DropGoTypeParameters(t *testing.T) { require.NoError(t, expected.Err()) require.False(t, expected.Scan()) } + +func Test_dropGoTypeParameters(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "no type parameters", + input: "github.com/grafana/pyroscope/v2/pkg/distributor.(*Distributor).Push", + expected: "github.com/grafana/pyroscope/v2/pkg/distributor.(*Distributor).Push", + }, + { + name: "empty string", + input: "", + expected: "", + }, + { + name: "simple type parameter", + input: "pkg.Func[go.shape.int]", + expected: "pkg.Func", + }, + { + name: "type parameter with suffix", + input: "pkg.(*T[go.shape.int]).Method", + expected: "pkg.(*T).Method", + }, + { + name: "multiple type parameters", + input: "pkg.Func[go.shape.int,go.shape.string]", + expected: "pkg.Func", + }, + { + name: "nested brackets in type parameter", + input: "pkg.(*T[go.shape.struct { F []uint8 }]).Method", + expected: "pkg.(*T).Method", + }, + { + name: "bracket without go.shape prefix", + input: "pkg.Func[int]", + expected: "pkg.Func[int]", + }, + { + name: "go.shape prefix without opening bracket", + input: "go.shape.int", + expected: "go.shape.int", + }, + { + name: "multiple separate type parameter sections", + input: "pkg.Func[go.shape.int].Method[go.shape.string]", + expected: "pkg.Func.Method", + }, + { + name: "multiple type parameter sections with nested brackets", + input: "pkg.Func[go.shape.struct { F []uint8 }].Method[go.shape.int]", + expected: "pkg.Func.Method", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, dropGoTypeParameters(tt.input)) + }) + } +} + +func Benchmark_dropGoTypeParameters(b *testing.B) { + withParams := `github.com/bufbuild/connect-go.(*Client[go.shape.struct { github.com/grafana/pyroscope/api/gen/proto/go/push/v1.state google.golang.org/protobuf/internal/impl.MessageState; github.com/grafana/pyroscope/api/gen/proto/go/push/v1.sizeCache int32; github.com/grafana/pyroscope/api/gen/proto/go/push/v1.unknownFields []uint8; Series []*github.com/grafana/pyroscope/api/gen/proto/go/push/v1.RawProfileSeries "protobuf:\"bytes,1,rep,name=series,proto3\" json:\"series,omitempty\"" },go.shape.struct { github.com/grafana/pyroscope/api/gen/proto/go/push/v1.state google.golang.org/protobuf/internal/impl.MessageState; github.com/grafana/pyroscope/api/gen/proto/go/push/v1.sizeCache int32; github.com/grafana/pyroscope/api/gen/proto/go/push/v1.unknownFields []uint8 }]).CallUnary` + withoutParams := "github.com/grafana/pyroscope/v2/pkg/distributor.(*Distributor).Push" + + b.Run("with_type_params", func(b *testing.B) { + for b.Loop() { + dropGoTypeParameters(withParams) + } + }) + b.Run("without_type_params", func(b *testing.B) { + for b.Loop() { + dropGoTypeParameters(withoutParams) + } + }) +} diff --git a/pkg/pprof/fix_go_truncated_test.go b/pkg/pprof/fix_go_truncated_test.go index cd6c15af64..959f286846 100644 --- a/pkg/pprof/fix_go_truncated_test.go +++ b/pkg/pprof/fix_go_truncated_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) func Benchmark_RepairGoTruncatedStacktraces(b *testing.B) { @@ -50,7 +50,7 @@ func Test_RepairGoTruncatedStacktraces(t *testing.T) { // ensure all stacktraces start with the same 8 location ids stacks := make([]uint64, 8) - for idx, sample := range b.Profile.Sample { + for idx, sample := range b.Sample { first8Stacks := sample.LocationId[len(sample.LocationId)-8:] if idx == 0 { copy(stacks, first8Stacks) diff --git a/pkg/pprof/merge.go b/pkg/pprof/merge.go index b0da12f061..639b6a4656 100644 --- a/pkg/pprof/merge.go +++ b/pkg/pprof/merge.go @@ -4,9 +4,12 @@ import ( "fmt" "hash/maphash" "sort" + "sync" + + "github.com/dolthub/swiss" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - "github.com/grafana/pyroscope/pkg/slices" + "github.com/grafana/pyroscope/v2/pkg/slices" ) // TODO(kolesnikovae): @@ -23,6 +26,8 @@ import ( // reused and the number of allocs decreased. type ProfileMerge struct { + mu sync.Mutex + profile *profilev1.Profile tmp []uint32 @@ -35,12 +40,18 @@ type ProfileMerge struct { // Merge adds p to the profile merge, cloning new objects. // Profile p is modified in place but not retained by the function. -func (m *ProfileMerge) Merge(p *profilev1.Profile) error { +func (m *ProfileMerge) Merge(p *profilev1.Profile, sanitize bool) error { + m.mu.Lock() + defer m.mu.Unlock() + if p == nil || len(p.Sample) == 0 || len(p.StringTable) < 2 { return nil } - sanitizeProfile(p) + if sanitize { + var stats sanitizeStats + sanitizeProfile(p, &stats) + } var initial bool if m.profile == nil { m.init(p) @@ -89,6 +100,14 @@ func (m *ProfileMerge) Merge(p *profilev1.Profile) error { return nil } +func (m *ProfileMerge) MergeBytes(b []byte, sanitize bool) error { + var p profilev1.Profile + if err := Unmarshal(b, &p); err != nil { + return err + } + return m.Merge(&p, sanitize) +} + func (m *ProfileMerge) Profile() *profilev1.Profile { if m.profile == nil { return &profilev1.Profile{ @@ -201,6 +220,10 @@ func compatible(a, b *profilev1.Profile) error { // equalValueType returns true if the two value types are semantically // equal. It ignores the internal fields used during encode/decode. func equalValueType(st1, st2 *profilev1.ValueType) bool { + if st1 == nil && st2 == nil { + // Two absent value types agree — there is nothing to disagree about. + return true + } if st1 == nil || st2 == nil { return false } @@ -384,7 +407,7 @@ func hashLabels(s []*profilev1.Label) uint64 { type RewriteTable[K comparable, V, M any] struct { k func(V) K v func(V) M - t map[K]uint32 + t *swiss.Map[K, uint32] s []M } @@ -396,7 +419,7 @@ func NewRewriteTable[K comparable, V, M any]( return RewriteTable[K, V, M]{ k: k, v: v, - t: make(map[K]uint32, size), + t: swiss.NewMap[K, uint32](uint32(size)), s: make([]M, 0, size), } } @@ -404,11 +427,11 @@ func NewRewriteTable[K comparable, V, M any]( func (t *RewriteTable[K, V, M]) Index(dst []uint32, values []V) { for i, value := range values { k := t.k(value) - n, found := t.t[k] + n, found := t.t.Get(k) if !found { n = uint32(len(t.s)) t.s = append(t.s, t.v(value)) - t.t[k] = n + t.t.Put(k, n) } dst[i] = n } @@ -419,7 +442,7 @@ func (t *RewriteTable[K, V, M]) Append(values []V) { k := t.k(value) n := uint32(len(t.s)) t.s = append(t.s, t.v(value)) - t.t[k] = n + t.t.Put(k, n) } } diff --git a/pkg/pprof/merge_test.go b/pkg/pprof/merge_test.go index e10e1002f4..4b38e2af04 100644 --- a/pkg/pprof/merge_test.go +++ b/pkg/pprof/merge_test.go @@ -17,16 +17,18 @@ import ( "github.com/stretchr/testify/require" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - "github.com/grafana/pyroscope/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/testhelper" ) func Test_Merge_Single(t *testing.T) { p, err := OpenFile("testdata/go.cpu.labels.pprof") require.NoError(t, err) var m ProfileMerge - require.NoError(t, m.Merge(p.Profile.CloneVT())) + require.NoError(t, m.Merge(p.CloneVT(), true)) sortLabels(p.Profile) - testhelper.EqualProto(t, p.Profile, m.Profile()) + act := m.Profile() + exp := p.Profile + testhelper.EqualProto(t, exp, act) } func sortLabels(p *profilev1.Profile) { @@ -179,7 +181,7 @@ func Fuzz_Merge_Single(f *testing.F) { eventWrite(t, []byte{byte(fuzzEventPostDecode)}) var m ProfileMerge - err = m.Merge(&p) + err = m.Merge(&p, true) if err != nil { return } @@ -191,8 +193,8 @@ func Test_Merge_Self(t *testing.T) { p, err := OpenFile("testdata/go.cpu.labels.pprof") require.NoError(t, err) var m ProfileMerge - require.NoError(t, m.Merge(p.Profile.CloneVT())) - require.NoError(t, m.Merge(p.Profile.CloneVT())) + require.NoError(t, m.Merge(p.CloneVT(), true)) + require.NoError(t, m.Merge(p.CloneVT(), true)) for i := range p.Sample { s := p.Sample[i] for j := range s.Value { @@ -208,19 +210,19 @@ func Test_Merge_Halves(t *testing.T) { p, err := OpenFile("testdata/go.cpu.labels.pprof") require.NoError(t, err) - a := p.Profile.CloneVT() - b := p.Profile.CloneVT() + a := p.CloneVT() + b := p.CloneVT() n := len(p.Sample) / 2 a.Sample = a.Sample[:n] b.Sample = b.Sample[n:] var m ProfileMerge - require.NoError(t, m.Merge(a)) - require.NoError(t, m.Merge(b)) + require.NoError(t, m.Merge(a, true)) + require.NoError(t, m.Merge(b, true)) // Merge with self for normalisation. var sm ProfileMerge - require.NoError(t, sm.Merge(p.Profile.CloneVT())) + require.NoError(t, sm.Merge(p.CloneVT(), true)) p.DurationNanos *= 2 sortLabels(p.Profile) @@ -536,8 +538,8 @@ func Test_Merge_Sample(t *testing.T) { } var m ProfileMerge - require.NoError(t, m.Merge(a)) - require.NoError(t, m.Merge(b)) + require.NoError(t, m.Merge(a, true)) + require.NoError(t, m.Merge(b, true)) testhelper.EqualProto(t, expected, m.Profile()) } @@ -557,7 +559,7 @@ func TestMergeEmpty(t *testing.T) { Unit: 1, }, StringTable: []string{"", "nanoseconds", "cpu"}, - }) + }, true) require.NoError(t, err) err = m.Merge(&profilev1.Profile{ Sample: []*profilev1.Sample{ @@ -595,7 +597,7 @@ func TestMergeEmpty(t *testing.T) { }, }, StringTable: []string{"", "bar", "nanoseconds", "cpu"}, - }) + }, true) require.NoError(t, err) } @@ -611,7 +613,7 @@ func Benchmark_Merge_self(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { var m ProfileMerge - require.NoError(b, m.Merge(p.Profile.CloneVT())) + require.NoError(b, m.Merge(p.CloneVT(), true)) } }) @@ -625,3 +627,68 @@ func Benchmark_Merge_self(b *testing.B) { } }) } + +// nilPeriodTypeProfile builds a minimal profile with a nil PeriodType and a +// single sample carrying the given value on a single-location stack. This +// mirrors the common OTLP/eBPF shape where the source profile omits PeriodType. +func nilPeriodTypeProfile(value int64) *profilev1.Profile { + return &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 2, Unit: 1}, // samples / count + }, + PeriodType: nil, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1}, + Value: []int64{value}, + }, + }, + Location: []*profilev1.Location{ + { + Id: 1, + MappingId: 1, + Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}, + }, + }, + Mapping: []*profilev1.Mapping{ + {Id: 1, HasFunctions: true}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 3}, + }, + StringTable: []string{"", "count", "samples", "fn"}, + } +} + +func Test_Merge_NilPeriodType_Compatible(t *testing.T) { + var m ProfileMerge + require.NoError(t, m.Merge(nilPeriodTypeProfile(5), true)) + require.NoError(t, m.Merge(nilPeriodTypeProfile(7), true)) + + out := m.Profile() + require.Nil(t, out.PeriodType, "nil PeriodType must be preserved") + require.Len(t, out.Sample, 1) + require.Equal(t, []int64{12}, out.Sample[0].Value, "values must be summed") +} + +func Test_Merge_NilVsNonNilPeriodType_Incompatible(t *testing.T) { + var m ProfileMerge + require.NoError(t, m.Merge(nilPeriodTypeProfile(5), true)) + + withPeriod := nilPeriodTypeProfile(7) + withPeriod.PeriodType = &profilev1.ValueType{Type: 2, Unit: 1} + + err := m.Merge(withPeriod, true) + require.Error(t, err, "present-vs-absent period type must stay incompatible") + require.Contains(t, err.Error(), "incompatible period types") +} + +func Test_Merge_NilPeriodType_Single(t *testing.T) { + var m ProfileMerge + require.NoError(t, m.Merge(nilPeriodTypeProfile(3), true)) + + out := m.Profile() + require.Nil(t, out.PeriodType) + require.Len(t, out.Sample, 1) + require.Equal(t, []int64{3}, out.Sample[0].Value) +} diff --git a/pkg/pprof/pprof.go b/pkg/pprof/pprof.go index ec104a809e..6f66146981 100644 --- a/pkg/pprof/pprof.go +++ b/pkg/pprof/pprof.go @@ -4,9 +4,11 @@ import ( "bytes" "encoding/binary" "encoding/hex" + "fmt" "io" "os" "sort" + "strconv" "strings" "sync" "time" @@ -14,17 +16,15 @@ import ( "github.com/cespare/xxhash/v2" "github.com/colega/zeropool" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/google/pprof/profile" "github.com/klauspost/compress/gzip" - "github.com/pkg/errors" "github.com/samber/lo" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/slices" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/slices" + "github.com/grafana/pyroscope/v2/pkg/util" ) var ( @@ -71,7 +71,7 @@ func (r *gzipReader) openBytes(input []byte) (io.Reader, error) { r.reader.Reset(input) return r.reader, nil } else if err != nil { - return nil, errors.Wrap(err, "gzip reset") + return nil, fmt.Errorf("gzip reset: %w", err) } return r.gzip, nil @@ -86,6 +86,21 @@ func RawFromProto(pbp *profilev1.Profile) *Profile { } func RawFromBytes(input []byte) (_ *Profile, err error) { + return RawFromBytesWithLimit(input, 0) +} + +type ErrDecompressedSizeExceedsLimit struct { + Limit int64 +} + +func (e *ErrDecompressedSizeExceedsLimit) Error() string { + return fmt.Sprintf("decompressed size exceeds maximum allowed size of %d bytes", e.Limit) +} + +// RawFromBytesWithLimit reads a profile from bytes with an optional size limit. +// maxSize limits the decompressed size in bytes. Use 0 for no limit. +// This prevents zip bomb attacks where small compressed data expands to huge sizes. +func RawFromBytesWithLimit(input []byte, maxSize int64) (_ *Profile, err error) { gzipReader := gzipReaderPool.Get().(*gzipReader) buf := bufPool.Get().(*bytes.Buffer) defer func() { @@ -99,8 +114,19 @@ func RawFromBytes(input []byte) (_ *Profile, err error) { return nil, err } + // Apply size limit if specified (maxSize >= 0) + // maxSize == 0 means no limit (unlimited decompression) + if maxSize > 0 { + r = io.LimitReader(r, maxSize+1) // +1 to detect if limit is exceeded + } + if _, err = io.Copy(buf, r); err != nil { - return nil, errors.Wrap(err, "copy to buffer") + return nil, fmt.Errorf("copy to buffer: %w", err) + } + + // Check if we hit the size limit + if maxSize > 0 && int64(buf.Len()) > maxSize { + return nil, &ErrDecompressedSizeExceedsLimit{Limit: maxSize} } rawSize := buf.Len() @@ -116,7 +142,14 @@ func RawFromBytes(input []byte) (_ *Profile, err error) { } func FromBytes(input []byte, fn func(*profilev1.Profile, int) error) error { - p, err := RawFromBytes(input) + return FromBytesWithLimit(input, 0, fn) +} + +// FromBytesWithLimit reads a profile from bytes with an optional size limit and calls fn with the result. +// maxSize limits the decompressed size in bytes. Use 0 for no limit. +// This prevents zip bomb attacks where small compressed data expands to huge sizes. +func FromBytesWithLimit(input []byte, maxSize int64, fn func(*profilev1.Profile, int) error) error { + p, err := RawFromBytesWithLimit(input, maxSize) if err != nil { return err } @@ -265,6 +298,99 @@ func FromProfile(p *profile.Profile) (*profilev1.Profile, error) { return &r, nil } +type pprofFromTreeBuilder struct { + locations map[string]uint64 + functions map[string]uint64 + strings map[string]int64 + mappingId uint64 + profile *profilev1.Profile +} + +func (b *pprofFromTreeBuilder) newString(value string) int64 { + id, ok := b.strings[value] + if !ok { + id = int64(len(b.profile.StringTable)) + b.profile.StringTable = append(b.profile.StringTable, value) + b.strings[value] = id + } + return id +} + +func (b *pprofFromTreeBuilder) newFunction(function string) uint64 { + id, ok := b.functions[function] + if !ok { + id = uint64(len(b.profile.Function) + 1) + name := b.newString(function) + newFn := &profilev1.Function{ + Id: id, + Name: name, + SystemName: name, + } + b.functions[function] = id + b.profile.Function = append(b.profile.Function, newFn) + } + return id +} + +func (b *pprofFromTreeBuilder) newLocation(location string) uint64 { + id, ok := b.locations[location] + if !ok { + id = uint64(len(b.profile.Location) + 1) + newLoc := &profilev1.Location{ + Id: id, + Line: []*profilev1.Line{{FunctionId: b.newFunction(location)}}, + MappingId: b.mappingId, + } + b.profile.Location = append(b.profile.Location, newLoc) + b.locations[location] = newLoc.Id + } + return id +} + +func FromTree(t *model.FunctionNameTree, ty *typesv1.ProfileType, timeNanos int64) *profilev1.Profile { + const fakeMappingID = 1 + b := &pprofFromTreeBuilder{ + locations: make(map[string]uint64), + functions: make(map[string]uint64), + strings: make(map[string]int64), + mappingId: fakeMappingID, + profile: &profilev1.Profile{ + StringTable: []string{""}, + Mapping: []*profilev1.Mapping{{Id: fakeMappingID}}, + TimeNanos: timeNanos, + }, + } + + // Add strings beforehand so SetProfileMetadata can find them + b.newString(ty.SampleType) + b.newString(ty.SampleUnit) + b.newString(ty.PeriodType) + b.newString(ty.PeriodUnit) + + SetProfileMetadata(b.profile, ty, timeNanos, 0) + + t.IterateStacks(func(name model.FunctionName, self int64, stack []model.FunctionName) { + if self <= 0 { + return + } + locationIds := make([]uint64, 0, len(stack)) + for _, locName := range stack { + if locName == "" { + continue + } + locationIds = append(locationIds, b.newLocation(string(locName))) + } + + sample := &profilev1.Sample{ + LocationId: locationIds, + Value: []int64{self}, + } + b.profile.Sample = append(b.profile.Sample, sample) + }) + + return b.profile +} + func addString(strings map[string]int, s string) int64 { i, ok := strings[s] if !ok { @@ -286,9 +412,15 @@ func OpenFile(path string) (*Profile, error) { type Profile struct { *profilev1.Profile hasher SampleHasher + stats sanitizeStats rawSize int } +// RawSize of the profile +func (p *Profile) RawSize() int { + return p.rawSize +} + // WriteTo writes the profile to the given writer. func (p *Profile) WriteTo(w io.Writer) (int64, error) { buf := bufPool.Get().(*bytes.Buffer) @@ -314,10 +446,10 @@ func (p *Profile) WriteTo(w io.Writer) (int64, error) { written, err := gzipWriter.Write(data) if err != nil { - return 0, errors.Wrap(err, "gzip write") + return 0, fmt.Errorf("gzip write: %w", err) } if err := gzipWriter.Close(); err != nil { - return 0, errors.Wrap(err, "gzip close") + return 0, fmt.Errorf("gzip close: %w", err) } return int64(written), nil } @@ -355,6 +487,8 @@ var currentTime = time.Now // - Converts identifiers to indices. // - Ensures that string_table[0] is "". func (p *Profile) Normalize() { + p.stats.samplesTotal = len(p.Sample) + // if the profile has no time, set it to now if p.TimeNanos == 0 { p.TimeNanos = currentTime().UnixNano() @@ -367,6 +501,26 @@ func (p *Profile) Normalize() { }) } + // Remove samples. + var removedSamples []*profilev1.Sample + p.Sample = slices.RemoveInPlace(p.Sample, func(s *profilev1.Sample, i int) bool { + for j := 0; j < len(s.Value); j++ { + if s.Value[j] < 0 { + removedSamples = append(removedSamples, s) + p.stats.sampleValueNegative++ + return true + } + } + for j := 0; j < len(s.Value); j++ { + if s.Value[j] > 0 { + return false + } + } + p.stats.sampleValueZero++ + removedSamples = append(removedSamples, s) + return true + }) + // first we sort the samples. hashes := p.hasher.Hashes(p.Sample) ss := &sortedSample{samples: p.Sample, hashes: hashes} @@ -374,9 +528,6 @@ func (p *Profile) Normalize() { p.Sample = ss.samples hashes = ss.hashes - // Remove samples. - var removedSamples []*profilev1.Sample - p.Sample = slices.RemoveInPlace(p.Sample, func(s *profilev1.Sample, i int) bool { // if the next sample has the same hash and labels, we can remove this sample but add the value to the next sample. if i < len(p.Sample)-1 && hashes[i] == hashes[i+1] { @@ -385,22 +536,14 @@ func (p *Profile) Normalize() { p.Sample[i+1].Value[j] += s.Value[j] } removedSamples = append(removedSamples, s) + p.stats.sampleDuplicate++ return true } - for j := 0; j < len(s.Value); j++ { - if s.Value[j] > 0 { - // we found a non-zero value, so we can keep this sample. - return false - } - } - // all values are 0, remove the sample. - removedSamples = append(removedSamples, s) - return true + return false }) - // Remove references to removed samples. p.clearSampleReferences(removedSamples) - sanitizeProfile(p.Profile) + sanitizeProfile(p.Profile, &p.stats) p.clearAddresses() } @@ -414,6 +557,9 @@ func (p *Profile) clearAddresses() { } } for _, l := range p.Location { + if l.MappingId == 0 || int(l.MappingId) > len(p.Mapping) { + continue + } if p.Mapping[l.MappingId-1].HasFunctions { l.Address = 0 } @@ -527,7 +673,7 @@ func (p *Profile) visitAllNameReferences(fn func(*int64)) { for _, s := range p.Sample { for _, l := range s.Label { fn(&l.Key) - fn(&l.Num) + fn(&l.Str) fn(&l.NumUnit) } } @@ -613,6 +759,10 @@ func (l LabelsByKeyValue) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +// SampleGroup refers to a group of samples that share the same +// labels. Note that the Span ID label is handled in a special +// way and is not included in the Labels member but is kept as +// as a sample label. type SampleGroup struct { Labels []*profilev1.Label Samples []*profilev1.Sample @@ -662,6 +812,7 @@ func GroupSamplesWithoutLabelsByKey(p *profilev1.Profile, keys []int64) []Sample // We hide labels matching the keys to the end // of the slice, after len() boundary. s.Label = LabelsWithout(s.Label, keys) + sort.Sort(LabelsByKeyValue(s.Label)) // TODO: Find a way to avoid this. } // Sorting and grouping accounts only for labels kept. sort.Sort(SamplesByLabels(p.Sample)) @@ -677,7 +828,7 @@ func GroupSamplesWithoutLabelsByKey(p *profilev1.Profile, keys []int64) []Sample func restoreRemovedLabels(labels []*profilev1.Label) []*profilev1.Label { labels = labels[len(labels):cap(labels)] for i, l := range labels { - if l == nil { + if l == nil { // labels had extra capacity in sample labels labels = labels[:i] break } @@ -949,6 +1100,7 @@ var uint32SlicePool zeropool.Pool[[]uint32] const ( ProfileIDLabelName = "profile_id" // For compatibility with the existing clients. SpanIDLabelName = "span_id" // Will be supported in the future. + TraceIDLabelName = "trace_id" ) func LabelID(p *profilev1.Profile, name string) int64 { @@ -962,12 +1114,12 @@ func LabelID(p *profilev1.Profile, name string) int64 { func ProfileSpans(p *profilev1.Profile) []uint64 { if i := LabelID(p, SpanIDLabelName); i > 0 { - return profileSpans(i, p) + return Spans(p, i) } return nil } -func profileSpans(spanIDLabelIdx int64, p *profilev1.Profile) []uint64 { +func Spans(p *profilev1.Profile, spanIDLabelIdx int64) []uint64 { tmp := make([]byte, 8) s := make([]uint64, len(p.Sample)) for i, sample := range p.Sample { @@ -996,6 +1148,37 @@ func decodeSpanID(tmp []byte, s string) bool { return err == nil } +func ProfileTraceIDs(p *profilev1.Profile) [][16]byte { + if i := LabelID(p, TraceIDLabelName); i > 0 { + return TraceIDs(p, i) + } + return nil +} + +func TraceIDs(p *profilev1.Profile, traceIDLabelIdx int64) [][16]byte { + s := make([][16]byte, len(p.Sample)) + for i, sample := range p.Sample { + s[i] = traceIDFromLabels(traceIDLabelIdx, p.StringTable, sample.Label) + } + return s +} + +func traceIDFromLabels(labelIdx int64, stringTable []string, labels []*profilev1.Label) [16]byte { + var id [16]byte + for _, x := range labels { + if x.Key != labelIdx { + continue + } + s := stringTable[x.Str] + if len(s) == 32 { + if _, err := hex.Decode(id[:], util.YoloBuf(s)); err == nil { + return id + } + } + } + return id +} + func RenameLabel(p *profilev1.Profile, oldName, newName string) { var oi, ni int64 for i, s := range p.StringTable { @@ -1057,23 +1240,27 @@ func ZeroLabelStrings(p *profilev1.Profile) { } } -var languageMatchers = map[string][]string{ - "go": {".go", "/usr/local/go/"}, - "java": {"java/", "sun/"}, - "ruby": {".rb", "gems/"}, - "nodejs": {"./node_modules/", ".js"}, - "dotnet": {"System.", "Microsoft."}, - "python": {".py"}, - "rust": {"main.rs", "core.rs"}, +// languageMatchers is an ordered list so that per-symbol iteration is cheap +// and the result is deterministic when a symbol matches several languages. +var languageMatchers = []struct { + language string + patterns []string +}{ + {"go", []string{".go", "/usr/local/go/"}}, + {"java", []string{"java/", "sun/"}}, + {"ruby", []string{".rb", "gems/"}}, + {"nodejs", []string{"./node_modules/", ".js"}}, + {"dotnet", []string{"System.", "Microsoft."}}, + {"python", []string{".py"}}, + {"rust", []string{"main.rs", "core.rs"}}, } -func GetLanguage(profile *Profile, logger log.Logger) string { +func GetLanguage(profile *Profile) string { for _, symbol := range profile.StringTable { - for lang, matcherPatterns := range languageMatchers { - for _, pattern := range matcherPatterns { + for _, m := range languageMatchers { + for _, pattern := range m.patterns { if strings.HasPrefix(symbol, pattern) || strings.HasSuffix(symbol, pattern) { - level.Debug(logger).Log("msg", "found profile language", "lang", lang, "symbol", symbol) - return lang + return m.language } } } @@ -1084,18 +1271,23 @@ func GetLanguage(profile *Profile, logger log.Logger) string { // SetProfileMetadata sets the metadata on the profile. func SetProfileMetadata(p *profilev1.Profile, ty *typesv1.ProfileType, timeNanos int64, period int64) { m := map[string]int64{ - ty.SampleUnit: 0, - ty.SampleType: 0, - ty.PeriodType: 0, - ty.PeriodUnit: 0, + ty.SampleUnit: -1, + ty.SampleType: -1, + ty.PeriodType: -1, + ty.PeriodUnit: -1, } for i, s := range p.StringTable { - if _, ok := m[s]; !ok { + if _, ok := m[s]; ok { m[s] = int64(i) } } - for k, v := range m { - if v == 0 { + for _, k := range []string{ + ty.SampleUnit, + ty.SampleType, + ty.PeriodType, + ty.PeriodUnit, + } { + if m[k] == -1 { i := int64(len(p.StringTable)) p.StringTable = append(p.StringTable, k) m[k] = i @@ -1151,7 +1343,22 @@ func Marshal(p *profilev1.Profile, compress bool) ([]byte, error) { return buf.Bytes(), nil } +func MustMarshal(p *profilev1.Profile, compress bool) []byte { + b, err := Marshal(p, compress) + if err != nil { + panic(err) + } + return b +} + func Unmarshal(data []byte, p *profilev1.Profile) error { + return UnmarshalWithLimit(data, p, 0) +} + +// UnmarshalWithLimit unmarshals a profile from bytes with an optional size limit. +// maxSize limits the decompressed size in bytes. Use 0 for no limit. +// This prevents zip bomb attacks where small compressed data expands to huge sizes. +func UnmarshalWithLimit(data []byte, p *profilev1.Profile, maxSize int64) error { gr := gzipReaderPool.Get().(*gzipReader) defer gzipReaderPool.Put(gr) r, err := gr.openBytes(data) @@ -1164,16 +1371,32 @@ func Unmarshal(data []byte, p *profilev1.Profile) error { bufPool.Put(buf) }() buf.Grow(len(data) * 2) + + // Apply size limit if specified (maxSize >= 0) + // maxSize == 0 means no limit (unlimited decompression) + if maxSize > 0 { + r = io.LimitReader(r, maxSize+1) // +1 to detect if limit is exceeded + } + if _, err = io.Copy(buf, r); err != nil { return err } + + // Check if we hit the size limit + if maxSize > 0 && int64(buf.Len()) > maxSize { + return &ErrDecompressedSizeExceedsLimit{Limit: maxSize} + } + return p.UnmarshalVT(buf.Bytes()) } -func sanitizeProfile(p *profilev1.Profile) { +func sanitizeProfile(p *profilev1.Profile, stats *sanitizeStats) { if p == nil { return } + if stats.samplesTotal == 0 { + stats.samplesTotal = len(p.Sample) + } ms := int64(len(p.StringTable)) // Handle the case when "" is not present, // or is not at string_table[0]. @@ -1213,6 +1436,7 @@ func sanitizeProfile(p *profilev1.Profile) { p.SampleType = slices.RemoveInPlace(p.SampleType, func(x *profilev1.ValueType, _ int) bool { if x == nil { + stats.sampleTypeNil++ return true } x.Type = str(x.Type) @@ -1234,14 +1458,10 @@ func sanitizeProfile(p *profilev1.Profile) { // Sanitize mappings and references to them. // Locations with invalid references are removed. t := make(map[uint64]uint64, len(p.Location)) - clearMap := func() { - for k := range t { - delete(t, k) - } - } j := uint64(1) p.Mapping = slices.RemoveInPlace(p.Mapping, func(x *profilev1.Mapping, _ int) bool { if x == nil { + stats.mappingNil++ return true } x.BuildId = str(x.BuildId) @@ -1257,6 +1477,11 @@ func sanitizeProfile(p *profilev1.Profile) { var mapping *profilev1.Mapping p.Location = slices.RemoveInPlace(p.Location, func(x *profilev1.Location, _ int) bool { if x == nil { + stats.locationNil++ + return true + } + if len(x.Line) == 0 && x.Address == 0 { + stats.locationEmpty++ return true } if x.MappingId == 0 { @@ -1268,15 +1493,20 @@ func sanitizeProfile(p *profilev1.Profile) { return false } x.MappingId = t[x.MappingId] - return x.MappingId == 0 + if x.MappingId == 0 { + stats.locationMappingInvalid++ + return true + } + return false }) // Sanitize functions and references to them. // Locations with invalid references are removed. - clearMap() + clear(t) j = 1 p.Function = slices.RemoveInPlace(p.Function, func(x *profilev1.Function, _ int) bool { if x == nil { + stats.functionNil++ return true } x.Name = str(x.Name) @@ -1290,6 +1520,7 @@ func sanitizeProfile(p *profilev1.Profile) { p.Location = slices.RemoveInPlace(p.Location, func(x *profilev1.Location, _ int) bool { for _, line := range x.Line { if line.FunctionId = t[line.FunctionId]; line.FunctionId == 0 { + stats.locationFunctionInvalid++ return true } } @@ -1298,7 +1529,7 @@ func sanitizeProfile(p *profilev1.Profile) { // Sanitize locations and references to them. // Samples with invalid references are removed. - clearMap() + clear(t) j = 1 for _, x := range p.Location { x.Id, t[x.Id] = j, j @@ -1308,18 +1539,22 @@ func sanitizeProfile(p *profilev1.Profile) { vs := len(p.SampleType) p.Sample = slices.RemoveInPlace(p.Sample, func(x *profilev1.Sample, _ int) bool { if x == nil { + stats.sampleNil++ return true } if len(x.Value) != vs { + stats.sampleValueMismatch++ return true } for i := range x.LocationId { if x.LocationId[i] = t[x.LocationId[i]]; x.LocationId[i] == 0 { + stats.sampleLocationInvalid++ return true } } for _, l := range x.Label { if l == nil { + stats.sampleLabelNil++ return true } l.Key = str(l.Key) @@ -1329,3 +1564,65 @@ func sanitizeProfile(p *profilev1.Profile) { return false }) } + +type sanitizeStats struct { + samplesTotal int + sampleTypeNil int + + mappingNil int + functionNil int + locationNil int + locationEmpty int + locationMappingInvalid int + locationFunctionInvalid int + + sampleNil int + sampleLabelNil int + sampleLocationInvalid int + sampleValueMismatch int + sampleValueNegative int + sampleValueZero int + sampleDuplicate int +} + +func (s *sanitizeStats) pretty() string { + var b strings.Builder + b.WriteString("samples_total=") + b.WriteString(strconv.Itoa(s.samplesTotal)) + put := func(k string, v int) { + if v > 0 { + b.WriteString(" ") + b.WriteString(k) + b.WriteString("=") + b.WriteString(strconv.Itoa(v)) + } + } + put("sample_type_nil", s.sampleTypeNil) + put("mapping_nil", s.mappingNil) + put("function_nil", s.functionNil) + put("location_nil", s.locationNil) + put("location_empty", s.locationEmpty) + put("location_mapping_invalid", s.locationMappingInvalid) + put("location_function_invalid", s.locationFunctionInvalid) + put("sample_nil", s.sampleNil) + put("sample_label_nil", s.sampleLabelNil) + put("sample_location_invalid", s.sampleLocationInvalid) + put("sample_value_mismatch", s.sampleValueMismatch) + put("sample_value_negative", s.sampleValueNegative) + put("sample_value_zero", s.sampleValueZero) + put("sample_duplicate", s.sampleDuplicate) + return b.String() +} + +func (p *Profile) DebugString() string { + bs, _ := p.MarshalVT() + gp, _ := profile.ParseData(bs) + if gp == nil { + return "" + } + return gp.String() +} + +func (p *Profile) Stats() string { + return p.stats.pretty() +} diff --git a/pkg/pprof/pprof_test.go b/pkg/pprof/pprof_test.go index c906600dc6..552100b506 100644 --- a/pkg/pprof/pprof_test.go +++ b/pkg/pprof/pprof_test.go @@ -8,14 +8,15 @@ import ( "testing" "time" - "github.com/go-kit/log" "github.com/google/pprof/profile" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) func TestNormalizeProfile(t *testing.T) { @@ -104,6 +105,74 @@ func TestNormalizeProfile(t *testing.T) { }, pf.Profile) } +func TestNormalizeProfile_NegativeSample(t *testing.T) { + currentTime = func() time.Time { + t, _ := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z") + return t + } + defer func() { + currentTime = time.Now + }() + + p := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{2, 1}, Value: []int64{10}, Label: []*profilev1.Label{{Str: 5, Key: 5}, {Str: 5, Key: 6}}}, + {LocationId: []uint64{2, 1}, Value: []int64{10}, Label: []*profilev1.Label{{Str: 5, Key: 5}, {Str: 5, Key: 7}}}, + {LocationId: []uint64{2, 1}, Value: []int64{10}, Label: []*profilev1.Label{{Str: 5, Key: 5}, {Str: 5, Key: 7}}}, + {LocationId: []uint64{2, 1}, Value: []int64{-10}, Label: []*profilev1.Label{{Str: 5, Key: 5}, {Str: 5, Key: 7}}}, + {LocationId: []uint64{2, 1}, Value: []int64{0}, Label: []*profilev1.Label{{Str: 5, Key: 5}, {Str: 5, Key: 7}}}, + }, + Mapping: []*profilev1.Mapping{{Id: 1, HasFunctions: true, MemoryStart: 100, MemoryLimit: 200, FileOffset: 200}}, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Address: 5, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + {Id: 2, MappingId: 1, Address: 2, Line: []*profilev1.Line{{FunctionId: 2, Line: 1}}}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 3, SystemName: 3, Filename: 4, StartLine: 1}, + {Id: 2, Name: 5, SystemName: 5, Filename: 4, StartLine: 1}, + }, + StringTable: []string{ + "", + "cpu", "nanoseconds", + "main", "main.go", + "foo", "bar", "baz", + }, + PeriodType: &profilev1.ValueType{Type: 1, Unit: 2}, + } + + pf := &Profile{Profile: p} + pf.Normalize() + require.Equal(t, pf.Profile, &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{2, 1}, Value: []int64{10}, Label: []*profilev1.Label{{Str: 5, Key: 5}, {Str: 5, Key: 6}}}, + {LocationId: []uint64{2, 1}, Value: []int64{20}, Label: []*profilev1.Label{{Str: 5, Key: 5}, {Str: 5, Key: 7}}}, + }, + Mapping: []*profilev1.Mapping{{Id: 1, HasFunctions: true}}, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2, Line: 1}}}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 3, SystemName: 3, Filename: 4, StartLine: 1}, + {Id: 2, Name: 5, SystemName: 5, Filename: 4, StartLine: 1}, + }, + StringTable: []string{ + "", + "cpu", "nanoseconds", + "main", "main.go", + "foo", "bar", "baz", + }, + PeriodType: &profilev1.ValueType{Type: 1, Unit: 2}, + TimeNanos: 1577836800000000000, + }) +} + func TestNormalizeProfile_SampleLabels(t *testing.T) { currentTime = func() time.Time { t, _ := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z") @@ -170,6 +239,81 @@ func TestNormalizeProfile_SampleLabels(t *testing.T) { }) } +// TestNormalizeProfile_LabelStrShiftedAfterFunctionRemoval specifically tests the +// case where unused functions cause string table compaction that must shift label.Str. +func TestNormalizeProfile_LabelStrShiftedAfterFunctionRemoval(t *testing.T) { + // Build a profile where: + // - Sample 1 uses location 1 (function "kept_func") and has label Str pointing to "label_val" + // - Sample 2 uses location 2 (function "removed_func") and is a zero-value sample (will be removed) + // - "removed_func" string is between "kept_func" and "label_val" in the string table + // + // When sample 2 is removed, location 2 and function 2 become unused. + // "removed_func" (index 4) is removed from the string table. + // "label_val" was at index 7; after removal it should shift to index 6. + // If label.Str is not updated, it still points to index 7 which is now other_func. + p := &profilev1.Profile{ + StringTable: []string{ + "", // 0 + "cpu", // 1 + "nanoseconds", // 2 + "kept_func", // 3 + "removed_func", // 4 -- only used by the removed function + "src.go", // 5 + "tag_name", // 6 + "label_val", // 7 -- should become 6 after removal of index 4 + "other_func", // 8 -- should become 7 after removal of index 4 + }, + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + PeriodType: &profilev1.ValueType{Type: 1, Unit: 2}, + Sample: []*profilev1.Sample{ + { + LocationId: []uint64{1}, + Value: []int64{100}, + Label: []*profilev1.Label{{Key: 6, Str: 7}}, + }, + { + // Zero-value sample — will be removed during normalization. + LocationId: []uint64{2}, + Value: []int64{0}, + }, + }, + Mapping: []*profilev1.Mapping{ + {Id: 1, HasFunctions: true}, + }, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2, Line: 1}}}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 3, SystemName: 3, Filename: 5, StartLine: 1}, + {Id: 2, Name: 4, SystemName: 4, Filename: 5, StartLine: 1}, + }, + } + + pf := &Profile{Profile: p} + pf.Normalize() + + // After normalization: + // - Sample 2 (zero value) is removed + // - Location 2 and Function 2 are removed (unused) + // - "removed_func" (was at index 4) is removed from string table + // - All string indices > 4 should be shifted down by 1 + // + // The surviving sample's label must still correctly point to "label_val". + require.Len(t, pf.Sample, 1, "expected exactly one sample after normalization") + require.Len(t, pf.Sample[0].Label, 1, "expected exactly one label on the sample") + + label := pf.Sample[0].Label[0] + keyStr := pf.StringTable[label.Key] + valStr := pf.StringTable[label.Str] + require.Equal(t, "tag_name", keyStr, "label key should be 'tag_name'") + require.Equal(t, "label_val", valStr, + "label value corrupted after string table compaction: got %q at Str index %d, string_table=%v", + valStr, label.Str, pf.StringTable) +} + func Test_sanitizeReferences(t *testing.T) { type testCase struct { name string @@ -279,9 +423,9 @@ func Test_sanitizeReferences(t *testing.T) { {LocationId: []uint64{3, 2, 1}}, }, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, - {Id: 3, MappingId: 5}, - {Id: 2, MappingId: 0}, + {Id: 1, MappingId: 1, Address: 1}, + {Id: 3, MappingId: 5, Address: 2}, + {Id: 2, MappingId: 0, Address: 3}, }, Mapping: []*profilev1.Mapping{ {Id: 1}, @@ -292,8 +436,8 @@ func Test_sanitizeReferences(t *testing.T) { {LocationId: []uint64{2, 1}}, }, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, - {Id: 2, MappingId: 2}, + {Id: 1, MappingId: 1, Address: 1}, + {Id: 2, MappingId: 2, Address: 3}, }, Mapping: []*profilev1.Mapping{ {Id: 1}, @@ -310,14 +454,14 @@ func Test_sanitizeReferences(t *testing.T) { {LocationId: []uint64{5}}, }, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, - {Id: 0, MappingId: 0}, + {Id: 1, MappingId: 1, Address: 0xa}, + {Id: 0, MappingId: 0, Address: 0xa}, }, }, expected: &profilev1.Profile{ Sample: []*profilev1.Sample{}, Location: []*profilev1.Location{ - {Id: 1, MappingId: 1}, + {Id: 1, MappingId: 1, Address: 0xa}, }, Mapping: []*profilev1.Mapping{ {Id: 1}, @@ -430,7 +574,7 @@ func Test_sanitizeReferences(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - sanitizeProfile(tc.profile) + sanitizeProfile(tc.profile, new(sanitizeStats)) assert.Equal(t, tc.expected, tc.profile) }) } @@ -444,17 +588,20 @@ func Test_sanitize_fixtures(t *testing.T) { case filepath.Ext(path) == ".txt": return nil case d.IsDir(): - if d.Name() == "fuzz" { + switch d.Name() { + case "fuzz": + case "malformed": return fs.SkipDir + default: + return nil } - return nil } t.Run(path, func(t *testing.T) { f, err := OpenFile(path) require.NoError(t, err) c := f.CloneVT() - sanitizeProfile(f.Profile) + sanitizeProfile(f.Profile, new(sanitizeStats)) assert.Equal(t, len(c.Sample), len(f.Sample)) assert.Equal(t, len(c.Location), len(f.Location)) assert.Equal(t, len(c.Function), len(f.Function)) @@ -538,6 +685,34 @@ func TestEmptyMappingJava(t *testing.T) { } } +func TestClearAddresses_InvalidMappingIDsDoNotPanic(t *testing.T) { + p := &Profile{Profile: &profilev1.Profile{ + Mapping: []*profilev1.Mapping{{ + Id: 1, + HasFunctions: true, + MemoryStart: 0x1000, + MemoryLimit: 0x2000, + FileOffset: 0x3000, + }}, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Address: 0x10}, + {Id: 2, MappingId: 0, Address: 0x20}, + {Id: 3, MappingId: 5, Address: 0x30}, + }, + }} + + require.NotPanics(t, func() { + p.clearAddresses() + }) + + require.Equal(t, uint64(0), p.Mapping[0].MemoryStart) + require.Equal(t, uint64(0), p.Mapping[0].MemoryLimit) + require.Equal(t, uint64(0), p.Mapping[0].FileOffset) + require.Equal(t, uint64(0), p.Location[0].Address) + require.Equal(t, uint64(0x20), p.Location[1].Address) + require.Equal(t, uint64(0x30), p.Location[2].Address) +} + func countSampleDuplicates(p *Profile) int { hashes := p.hasher.Hashes(p.Sample) uniq := map[uint64][]*profilev1.Sample{} @@ -871,6 +1046,17 @@ func Test_GroupSamplesWithout(t *testing.T) { input: new(profilev1.Profile), expected: nil, }, + { + description: "no sample labels", + input: &profilev1.Profile{ + Sample: []*profilev1.Sample{{}, {}}, + }, + expected: []SampleGroup{ + { + Samples: []*profilev1.Sample{{}, {}}, + }, + }, + }, { description: "without all, single label set", input: &profilev1.Profile{ @@ -930,16 +1116,16 @@ func Test_GroupSamplesWithout(t *testing.T) { }, }, { - Labels: []*profilev1.Label{{Key: 1, Str: 3}}, + Labels: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 2, Str: 2}}, Samples: []*profilev1.Sample{ {Label: []*profilev1.Label{}}, + {Label: []*profilev1.Label{}}, }, }, { - Labels: []*profilev1.Label{{Key: 2, Str: 2}, {Key: 1, Str: 1}}, + Labels: []*profilev1.Label{{Key: 1, Str: 3}}, Samples: []*profilev1.Sample{ {Label: []*profilev1.Label{}}, - {Label: []*profilev1.Label{}}, }, }, }, @@ -970,14 +1156,14 @@ func Test_GroupSamplesWithout(t *testing.T) { }, }, { - Labels: []*profilev1.Label{{Key: 3, Str: 3}, {Key: 1, Str: 1}}, + Labels: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 3, Str: 3}}, Samples: []*profilev1.Sample{ {Label: []*profilev1.Label{{Key: 2, Str: 100}}}, {Label: []*profilev1.Label{{Key: 2, Str: 101}}}, }, }, { - Labels: []*profilev1.Label{{Key: 3, Str: 4}, {Key: 1, Str: 1}}, + Labels: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 3, Str: 4}}, Samples: []*profilev1.Sample{ {Label: []*profilev1.Label{{Key: 2, Str: 102}}}, }, @@ -1008,7 +1194,7 @@ func Test_GroupSamplesWithout(t *testing.T) { }, }, { - Labels: []*profilev1.Label{{Key: 3, Str: 3}, {Key: 2, Str: 2}, {Key: 1, Str: 1}}, + Labels: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 2, Str: 2}, {Key: 3, Str: 3}}, Samples: []*profilev1.Sample{ {Label: []*profilev1.Label{}}, }, @@ -1047,12 +1233,57 @@ func Test_GroupSamplesWithout(t *testing.T) { }, }, }, + { + description: "without single existent, single group", + input: &profilev1.Profile{ + Sample: []*profilev1.Sample{ + {Label: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 2, Str: 100}, {Key: 3, Str: 3}}}, + {Label: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 3, Str: 3}}}, + }, + }, + without: []int64{2}, + expected: []SampleGroup{ + { + Labels: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 3, Str: 3}}, + Samples: []*profilev1.Sample{ + {Label: []*profilev1.Label{{Key: 2, Str: 100}}}, + {Label: []*profilev1.Label{}}, + }, + }, + }, + }, + { + description: "Testcase for extra labels capacity (restoreRemovedLabels nil check)", + input: &profilev1.Profile{ + Sample: []*profilev1.Sample{ + {Label: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 2, Str: 100}, {Key: 3, Str: 3}, nil, nil}[:3]}, + {Label: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 3, Str: 3}}}, + }[:2], + }, + without: []int64{2}, + expected: []SampleGroup{ + { + Labels: []*profilev1.Label{{Key: 1, Str: 1}, {Key: 3, Str: 3}}, + Samples: []*profilev1.Sample{ + {Label: []*profilev1.Label{{Key: 2, Str: 100}}}, + {Label: []*profilev1.Label{}}, + }, + }, + }, + }, } for _, tc := range testCases { tc := tc t.Run(tc.description, func(t *testing.T) { require.Equal(t, tc.expected, GroupSamplesWithoutLabelsByKey(tc.input, tc.without)) + for _, g := range tc.expected { + for _, sample := range g.Samples { + for _, label := range sample.Label { + assert.NotNil(t, label) + } + } + } }) } } @@ -1314,6 +1545,40 @@ func Test_SampleExporter_Partial(t *testing.T) { requireProfilesEqual(t, expected, n) } +func Test_Tree_Pprof_conversion(t *testing.T) { + // take a real pprof + p, err := OpenFile("testdata/go.cpu.labels.pprof") + require.NoError(t, err) + + profileType := typesv1.ProfileType{ + ID: "", + Name: "process_cpu", + SampleType: "cpu", + SampleUnit: "nanoseconds", + PeriodType: "cpu", + PeriodUnit: "nanoseconds", + } + maxNodes := int64(1000000) + timeNanos := int64(1234) + + // getting tree from pprof - losing data (mappings, lines, inline functions, etc) + bytes, err := model.TreeFromBackendProfile(p.Profile, maxNodes) + require.NoError(t, err) + treeFromPprof, err := model.UnmarshalTree[model.FunctionName, model.FunctionNameI](bytes) + require.NoError(t, err) + pprofFromTree := FromTree(treeFromPprof, &profileType, timeNanos) + + // repeat the process + bytes, err = model.TreeFromBackendProfile(pprofFromTree, maxNodes) + require.NoError(t, err) + treeFromPprofFromTree, err := model.UnmarshalTree[model.FunctionName, model.FunctionNameI](bytes) + require.NoError(t, err) + pprofFromTreeFromTree := FromTree(treeFromPprofFromTree, &profileType, timeNanos) + + // FromTree <-> model.TreeFromBackendProfile should be immutable: + requireProfilesEqual(t, pprofFromTree, pprofFromTreeFromTree) +} + func Test_GroupSamplesWithout_Go_CPU_profile(t *testing.T) { p, err := OpenFile("testdata/go.cpu.labels.pprof") require.NoError(t, err) @@ -1324,10 +1589,10 @@ func Test_GroupSamplesWithout_Go_CPU_profile(t *testing.T) { assert.Equal(t, groups[0].Labels, []*profilev1.Label{{Key: 18, Str: 19}}) assert.Equal(t, len(groups[0].Samples), 5) - assert.Equal(t, groups[1].Labels, []*profilev1.Label{{Key: 22, Str: 23}, {Key: 18, Str: 19}}) + assert.Equal(t, groups[1].Labels, []*profilev1.Label{{Key: 18, Str: 19}, {Key: 22, Str: 23}}) assert.Equal(t, len(groups[1].Samples), 325) - assert.Equal(t, groups[2].Labels, []*profilev1.Label{{Key: 22, Str: 27}, {Key: 18, Str: 19}}) + assert.Equal(t, groups[2].Labels, []*profilev1.Label{{Key: 18, Str: 19}, {Key: 22, Str: 27}}) assert.Equal(t, len(groups[2].Samples), 150) } @@ -1337,14 +1602,29 @@ func Test_GroupSamplesWithout_dotnet_profile(t *testing.T) { groups := GroupSamplesWithoutLabels(p.Profile, ProfileIDLabelName) require.Len(t, groups, 1) - assert.Equal(t, groups[0].Labels, []*profilev1.Label{{Key: 66, Str: 67}, {Key: 64, Str: 65}}) + assert.Equal(t, groups[0].Labels, []*profilev1.Label{{Key: 64, Str: 65}, {Key: 66, Str: 67}}) +} + +func Test_GroupSamplesWithout_single_group_with_optional_span_id(t *testing.T) { + // pprof.Do(context.Background(), pprof.Labels("function", "slow", "qwe", "asd", "asdasd", "zxczxc"), func(c context.Context) { + // work(40000) + // pprof.Do(c, pprof.Labels("span_id", "239"), func(c context.Context) { + // work(40000) + // }) + // }) + p, err := OpenFile("testdata/single_group_with_optional_span_id.pb.gz") + require.NoError(t, err) + + groups := GroupSamplesWithoutLabels(p.Profile, SpanIDLabelName) + require.Len(t, groups, 1) + assert.Equal(t, groups[0].Labels, []*profilev1.Label{{Key: 5, Str: 6}, {Key: 7, Str: 8}, {Key: 9, Str: 10}}) } func Test_GetProfileLanguage_go_cpu_profile(t *testing.T) { p, err := OpenFile("testdata/go.cpu.labels.pprof") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "go", language) } @@ -1352,7 +1632,7 @@ func Test_GetProfileLanguage_go_heap_profile(t *testing.T) { p, err := OpenFile("testdata/heap") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "go", language) } @@ -1360,7 +1640,7 @@ func Test_GetProfileLanguage_dotnet_profile(t *testing.T) { p, err := OpenFile("testdata/dotnet.labels.pprof") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "dotnet", language) } @@ -1368,7 +1648,7 @@ func Test_GetProfileLanguage_java_profile(t *testing.T) { p, err := OpenFile("testdata/profile_java") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "java", language) } @@ -1376,7 +1656,7 @@ func Test_GetProfileLanguage_python_profile(t *testing.T) { p, err := OpenFile("testdata/profile_python") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "python", language) } @@ -1384,7 +1664,7 @@ func Test_GetProfileLanguage_ruby_profile(t *testing.T) { p, err := OpenFile("testdata/profile_ruby") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "ruby", language) } @@ -1392,7 +1672,7 @@ func Test_GetProfileLanguage_nodejs_profile(t *testing.T) { p, err := OpenFile("testdata/profile_nodejs") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "nodejs", language) } @@ -1400,7 +1680,7 @@ func Test_GetProfileLanguage_rust_profile(t *testing.T) { p, err := OpenFile("testdata/profile_rust") require.NoError(t, err) - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) assert.Equal(t, "rust", language) } @@ -1424,7 +1704,7 @@ func Benchmark_GetProfileLanguage(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - language := GetLanguage(p, log.NewNopLogger()) + language := GetLanguage(p) if language == "unknown" { b.Fatal() } @@ -1432,3 +1712,240 @@ func Benchmark_GetProfileLanguage(b *testing.B) { }) } } + +func Test_SetProfileMetadata(t *testing.T) { + p := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{{}}, + StringTable: []string{"", "qux"}, + PeriodType: &profilev1.ValueType{}, + } + pt := &typesv1.ProfileType{ + ID: "alfa", + Name: "bravo", + SampleType: "foo", + SampleUnit: "bar", + PeriodType: "baz", + PeriodUnit: "qux", + } + SetProfileMetadata(p, pt, 1, 2) + expected := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{{ + Type: 3, // foo + Unit: 2, // bar + }}, + StringTable: []string{"", "qux", "bar", "foo", "baz"}, + PeriodType: &profilev1.ValueType{ + Type: 4, // baz + Unit: 1, // qux + }, + TimeNanos: 1, + Period: 1, + DefaultSampleType: 3, // foo + } + require.Equal(t, expected.String(), p.String()) +} + +func Test_pprof_zero_addr_no_line_locations(t *testing.T) { + b, err := OpenFile("testdata/malformed/no_addr_no_line.pb.gz") + require.NoError(t, err) + + var found bool + for _, loc := range b.Location { + if len(loc.Line) == 0 && loc.Address == 0 { + found = true + break + } + } + if !found { + t.Fatal("invalid fixture") + } + + b.Normalize() + for _, loc := range b.Location { + if len(loc.Line) == 0 && loc.Address == 0 { + t.Fatal("found location without lines and address") + } + } + + expected := "samples_total=2 location_empty=1 sample_location_invalid=1" + assert.Equal(t, expected, b.stats.pretty()) +} + +func TestRawFromBytesWithLimit(t *testing.T) { + // Create a simple profile + p := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100}}, + {LocationId: []uint64{2}, Value: []int64{200}}, + }, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2, Line: 1}}}, + }, + Mapping: []*profilev1.Mapping{ + {Id: 1, Filename: 3}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 4, SystemName: 4, Filename: 3}, + {Id: 2, Name: 5, SystemName: 5, Filename: 3}, + }, + StringTable: []string{ + "", + "cpu", "nanoseconds", + "main.go", + "foo", "bar", + }, + PeriodType: &profilev1.ValueType{Type: 1, Unit: 2}, + TimeNanos: 1, + Period: 1, + } + + // Marshal the profile to bytes (compressed) + data, err := Marshal(p, true) + require.NoError(t, err) + require.NotEmpty(t, data) + + // Get the actual decompressed size + normalProfile, err := RawFromBytesWithLimit(data, -1) + require.NoError(t, err) + require.NotNil(t, normalProfile) + decompressedSize := normalProfile.rawSize + + t.Logf("Compressed size: %d bytes, Decompressed size: %d bytes", len(data), decompressedSize) + + t.Run("unlimited", func(t *testing.T) { + // Test with -1 (no limit) - should succeed + profile, err := RawFromBytesWithLimit(data, -1) + require.NoError(t, err) + require.NotNil(t, profile) + require.Equal(t, 2, len(profile.Sample)) + }) + + t.Run("limit_exceeded", func(t *testing.T) { + // Test with a limit smaller than decompressed size - should fail + _, err := RawFromBytesWithLimit(data, int64(decompressedSize/2)) + require.Error(t, err) + require.Contains(t, err.Error(), "decompressed size exceeds maximum allowed size") + }) + + t.Run("limit_sufficient", func(t *testing.T) { + // Test with a limit larger than decompressed size - should succeed + profile, err := RawFromBytesWithLimit(data, int64(decompressedSize*2)) + require.NoError(t, err) + require.NotNil(t, profile) + require.Equal(t, 2, len(profile.Sample)) + }) + + t.Run("limit_exact", func(t *testing.T) { + // Test with limit exactly equal to decompressed size - should succeed + profile, err := RawFromBytesWithLimit(data, int64(decompressedSize)) + require.NoError(t, err) + require.NotNil(t, profile) + require.Equal(t, 2, len(profile.Sample)) + }) +} + +func TestUnmarshalWithLimit(t *testing.T) { + // Create a simple profile + p := &profilev1.Profile{ + SampleType: []*profilev1.ValueType{ + {Type: 1, Unit: 2}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{1}, Value: []int64{100}}, + }, + Location: []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 1}}}, + }, + Mapping: []*profilev1.Mapping{ + {Id: 1, Filename: 3}, + }, + Function: []*profilev1.Function{ + {Id: 1, Name: 4, SystemName: 4, Filename: 3}, + }, + StringTable: []string{ + "", + "cpu", "nanoseconds", + "main.go", + "foo", + }, + PeriodType: &profilev1.ValueType{Type: 1, Unit: 2}, + TimeNanos: 1, + Period: 1, + } + + // Marshal the profile to bytes (compressed) + data, err := Marshal(p, true) + require.NoError(t, err) + + // Get the actual decompressed size + testProfile := &profilev1.Profile{} + err = UnmarshalWithLimit(data, testProfile, -1) + require.NoError(t, err) + decompressedSize, err := testProfile.MarshalVT() + require.NoError(t, err) + + t.Run("unlimited", func(t *testing.T) { + result := &profilev1.Profile{} + err := UnmarshalWithLimit(data, result, -1) + require.NoError(t, err) + require.Equal(t, 1, len(result.Sample)) + }) + + t.Run("limit_exceeded", func(t *testing.T) { + result := &profilev1.Profile{} + err := UnmarshalWithLimit(data, result, int64(len(decompressedSize)/2)) + require.Error(t, err) + require.Contains(t, err.Error(), "decompressed size exceeds maximum allowed size") + }) + + t.Run("limit_sufficient", func(t *testing.T) { + result := &profilev1.Profile{} + err := UnmarshalWithLimit(data, result, int64(len(decompressedSize)*2)) + require.NoError(t, err) + require.Equal(t, 1, len(result.Sample)) + }) +} + +func TestProfileTraceIDs(t *testing.T) { + t.Run("no trace_id label", func(t *testing.T) { + p := &profilev1.Profile{ + StringTable: []string{"", SpanIDLabelName, "abc123"}, + Sample: []*profilev1.Sample{ + {Label: []*profilev1.Label{{Key: 1, Str: 2}}}, + }, + } + assert.Nil(t, ProfileTraceIDs(p)) + }) + + t.Run("with trace_id labels", func(t *testing.T) { + p := &profilev1.Profile{ + StringTable: []string{"", TraceIDLabelName, "0123456789abcdef0123456789abcdef", "fedcba9876543210fedcba9876543210"}, + Sample: []*profilev1.Sample{ + {Label: []*profilev1.Label{{Key: 1, Str: 2}}}, + {Label: []*profilev1.Label{{Key: 1, Str: 3}}}, + {Label: []*profilev1.Label{}}, + }, + } + traceIDs := ProfileTraceIDs(p) + require.Len(t, traceIDs, 3) + assert.Equal(t, [16]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, traceIDs[0]) + assert.Equal(t, [16]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, traceIDs[1]) + assert.Equal(t, [16]byte{}, traceIDs[2]) + }) + + t.Run("invalid trace_id ignored", func(t *testing.T) { + p := &profilev1.Profile{ + StringTable: []string{"", TraceIDLabelName, "tooshort"}, + Sample: []*profilev1.Sample{ + {Label: []*profilev1.Label{{Key: 1, Str: 2}}}, + }, + } + traceIDs := ProfileTraceIDs(p) + require.Len(t, traceIDs, 1) + assert.Equal(t, [16]byte{}, traceIDs[0]) + }) +} diff --git a/pkg/pprof/testdata/go_type_parameters.expected.txt b/pkg/pprof/testdata/go_type_parameters.expected.txt index d07b2b9fcd..a093c0c412 100644 --- a/pkg/pprof/testdata/go_type_parameters.expected.txt +++ b/pkg/pprof/testdata/go_type_parameters.expected.txt @@ -1,11 +1,11 @@ -github.com/bufbuild/connect-go.(*Client[...]).CallUnary -github.com/bufbuild/connect-go.(*Request[...]).setRequestMethod -github.com/bufbuild/connect-go.(*Response[...]).Header -github.com/bufbuild/connect-go.NewClient[...].func2 -github.com/bufbuild/connect-go.NewRequest[...] -github.com/bufbuild/connect-go.NewResponse[...] -github.com/bufbuild/connect-go.NewUnaryHandler[...].func2 -github.com/grafana/pyroscope/pkg/util/loser.(*Tree[...]).Next -runtime/internal/atomic.(*Pointer[...]).Load -sync/atomic.(*Pointer[...]).Store -github.com/grafana/pyroscope/pkg/phlaredb/symdb.(*deduplicatingSlice[...]).ingest +github.com/bufbuild/connect-go.(*Client).CallUnary +github.com/bufbuild/connect-go.(*Request).setRequestMethod +github.com/bufbuild/connect-go.(*Response).Header +github.com/bufbuild/connect-go.NewClient.func2 +github.com/bufbuild/connect-go.NewRequest +github.com/bufbuild/connect-go.NewResponse +github.com/bufbuild/connect-go.NewUnaryHandler.func2 +github.com/grafana/pyroscope/pkg/util/loser.(*Tree).Next +runtime/internal/atomic.(*Pointer).Load +sync/atomic.(*Pointer).Store +github.com/grafana/pyroscope/pkg/phlaredb/symdb.(*deduplicatingSlice).ingest diff --git a/pkg/pprof/testdata/malformed/no_addr_no_line.pb.gz b/pkg/pprof/testdata/malformed/no_addr_no_line.pb.gz new file mode 100644 index 0000000000..7c13dc4431 Binary files /dev/null and b/pkg/pprof/testdata/malformed/no_addr_no_line.pb.gz differ diff --git a/pkg/pprof/testdata/single_group_with_optional_span_id.pb.gz b/pkg/pprof/testdata/single_group_with_optional_span_id.pb.gz new file mode 100644 index 0000000000..45928c6b2b Binary files /dev/null and b/pkg/pprof/testdata/single_group_with_optional_span_id.pb.gz differ diff --git a/pkg/pprof/testhelper/profile_builder.go b/pkg/pprof/testhelper/profile_builder.go index 5d45903713..c53b48f0c5 100644 --- a/pkg/pprof/testhelper/profile_builder.go +++ b/pkg/pprof/testhelper/profile_builder.go @@ -10,7 +10,7 @@ import ( profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) type ProfileBuilder struct { @@ -18,7 +18,8 @@ type ProfileBuilder struct { strings map[string]int uuid.UUID - Labels []*typesv1.LabelPair + Labels []*typesv1.LabelPair + Annotations []*typesv1.ProfileAnnotation externalFunctionID2LocationId map[uint32]uint64 externalSampleID2SampleIndex map[sampleID]uint32 @@ -63,7 +64,7 @@ func (m *ProfileBuilder) MemoryProfile() *ProfileBuilder { Unit: m.addString("bytes"), Type: m.addString("space"), } - m.Profile.SampleType = []*profilev1.ValueType{ + m.SampleType = []*profilev1.ValueType{ { Unit: m.addString("count"), Type: m.addString("alloc_objects"), @@ -81,7 +82,7 @@ func (m *ProfileBuilder) MemoryProfile() *ProfileBuilder { Type: m.addString("inuse_space"), }, } - m.Profile.DefaultSampleType = m.addString("alloc_space") + m.DefaultSampleType = m.addString("alloc_space") m.Labels = append(m.Labels, &typesv1.LabelPair{ Name: model.MetricNameLabel, @@ -109,6 +110,16 @@ Outer: return m } +func (m *ProfileBuilder) WithAnnotations(annotationValues ...string) *ProfileBuilder { + for _, a := range annotationValues { + m.Annotations = append(m.Annotations, &typesv1.ProfileAnnotation{ + Key: "throttled", + Value: a, + }) + } + return m +} + func (m *ProfileBuilder) Name() string { for _, lbl := range m.Labels { if lbl.Name == model.MetricNameLabel { @@ -119,7 +130,7 @@ func (m *ProfileBuilder) Name() string { } func (m *ProfileBuilder) AddSampleType(typ, unit string) { - m.Profile.SampleType = append(m.Profile.SampleType, &profilev1.ValueType{ + m.SampleType = append(m.SampleType, &profilev1.ValueType{ Type: m.addString(typ), Unit: m.addString(unit), }) @@ -141,7 +152,7 @@ func (m *ProfileBuilder) PeriodType(periodType string, periodUnit string) { func (m *ProfileBuilder) CustomProfile(name, typ, unit, periodType, periodUnit string) { m.AddSampleType(typ, unit) - m.Profile.DefaultSampleType = m.addString(typ) + m.DefaultSampleType = m.addString(typ) m.PeriodType(periodType, periodUnit) @@ -197,6 +208,10 @@ func (m *ProfileBuilder) ForStacktraceString(stacktraces ...string) *StacktraceB } } +func (m *ProfileBuilder) AddString(s string) int64 { + return m.addString(s) +} + func (m *ProfileBuilder) addString(s string) int64 { i, ok := m.strings[s] if !ok { @@ -245,8 +260,8 @@ func (m *ProfileBuilder) AddExternalSampleWithLabels(locs []uint64, values []int if m.externalSampleID2SampleIndex == nil { m.externalSampleID2SampleIndex = map[sampleID]uint32{} } - m.externalSampleID2SampleIndex[sampleID{locationsID: locationsID, labelsID: labelsID}] = uint32(len(m.Profile.Sample)) - m.Profile.Sample = append(m.Profile.Sample, sample) + m.externalSampleID2SampleIndex[sampleID{locationsID: locationsID, labelsID: labelsID}] = uint32(len(m.Sample)) + m.Sample = append(m.Sample, sample) if len(labels) > 0 { sample.Label = make([]*profilev1.Label, 0, len(labels)) for _, label := range labels { @@ -263,7 +278,7 @@ func (m *ProfileBuilder) FindExternalSampleWithLabels(locationsID, labelsID uint if !ok { return nil } - sample := m.Profile.Sample[sampleIndex] + sample := m.Sample[sampleIndex] return sample } @@ -273,10 +288,10 @@ type StacktraceBuilder struct { } func (s *StacktraceBuilder) AddSamples(samples ...int64) *ProfileBuilder { - if exp, act := len(s.Profile.SampleType), len(samples); exp != act { + if exp, act := len(s.SampleType), len(samples); exp != act { panic(fmt.Sprintf("profile expects %d sample(s), there was actually %d sample(s) given.", exp, act)) } - s.Profile.Sample = append(s.Profile.Sample, &profilev1.Sample{ + s.Sample = append(s.Sample, &profilev1.Sample{ LocationId: s.locationID, Value: samples, }) diff --git a/pkg/pyroscope/PYROSCOPE_V2.md b/pkg/pyroscope/PYROSCOPE_V2.md new file mode 100644 index 0000000000..ab900277a7 --- /dev/null +++ b/pkg/pyroscope/PYROSCOPE_V2.md @@ -0,0 +1,151 @@ +# Pyroscope v2 + +**Pyroscope v2** is a complete architectural redesign of Pyroscope focused on improving scalability, performance, +and cost-efficiency. It is nearing official release. + +The biggest change in Pyroscope v2 is how it handles storage: data is now written directly to object storage, +removing the need for local disks in ingesters. For single-node deployments, local file systems can still be used +as object storage, but this setup isn't supported in the microservice mode. + +The **write and query paths are fully decoupled**. Each path can scale independently, so even the heaviest queries +won't interfere with ingestion performance. The read path can scale to hundreds of instances instantly. Compaction +has also been overhauled – the new design supports significantly higher throughput and scalability, allowing hundreds +of tenants to ingest thousands of profiles per second without compromising performance. + +This is made possible by a dedicated control plane that orchestrates data placement and compaction. To ensure high +availability and fault tolerance, the control plane uses Raft consensus and is the only component that requires +persistent local storage. + +# Architecture Overview + +Pyroscope is designed to be a scalable and cost-effective solution for storing and querying profiling data. +The architecture is built around the following goals: + - High write throughput + - Cost-effective storage + - Scalable query performance + - Low operational overhead + +In order to achieve these goals, Pyroscope uses a distributed architecture consisting of several components that work +together to ingest, store, and query profiling data. We aim to minimize the number of stateful components and design +the data storage to operate without local disks, relying entirely on object storage. + +The high-level components of the architecture include: + +```mermaid +graph TD + +%% Entry Points %% + subgraph entry_points[" "] + ingest_entry["Ingest Path"]:::entry_ingest --> distributor + query_entry["Query Path"]:::entry_query --> query_frontend + end + +%% Components %% + + distributor -->|writes to| segment_writer + segment_writer -->|updates| metastore + segment_writer -->|creates segments| object_storage + + metastore -->|coordinates| compaction_worker + compaction_worker -->|compacts| object_storage + + query_frontend -->|invokes| query_backend + query_backend -->|reads from| object_storage + query_frontend -->|queries| metastore + + distributor["distributor"] + segment_writer["segment-writer"] + metastore["metastore"] + compaction_worker["compaction-worker"] + query_backend["query-backend"] + query_frontend["query-frontend"] + +%% Object Storage %% + subgraph object_storage["object storage"] + segments + blocks + end + +%% Data Flow Colors %% + linkStyle 0 stroke:#a855f7,stroke-width:2px %% Dashed entry for ingest + linkStyle 1 stroke:#3b82f6,stroke-width:2px %% Dashed entry for query + + linkStyle 2,3,4 stroke:#a855f7,stroke-width:2px %% Purple: ingestion path + linkStyle 6 stroke:#a855f7,stroke-width:2px %% Purple: compaction process + linkStyle 7,8,9 stroke:#3b82f6,stroke-width:2px %% Blue: query path + +%% Styling %% + classDef entry_ingest stroke:#a855f7,stroke-width:2px,font-weight:bold + classDef entry_query stroke:#3b82f6,stroke-width:2px,font-weight:bold +``` + +## Ingestion + +Profiles are ingested through the Push RPC API and HTTP `/ingest` API to distributors. The write path includes +distributor and segment-writer services: both are stateless, disk-less, and scale horizontally with high efficiency. + +Profile ingest requests are randomly distributed among distributors, which then route them to segment-writers +to co-locate profiles from the same application. This ensures that profiles likely to be queried +together are stored together. You can find a detailed description of the distribution algorithm in the distributor documentation. + +The segment-writer service accumulates profiles in small blocks (segments) and writes them to object storage while +updating the block index with metadata of newly added objects. Each writer produces a _single object per shard_ +containing data of _all tenant services_ per shard; this approach minimizes the number of write operations to the +object storage, optimizing the cost of the solution. + +Ingestion clients are blocked until data is durably stored in object storage and an entry for the object is +created in the metadata index. By default, ingestion is synchronous, with median latency expected to be +less than 500ms using default settings and popular object storage providers such as Amazon S3, Google Cloud Storage, and +Azure Blob Storage. + +You can learn more about the write path in the [distributor documentation](../segmentwriter/client/distributor/README.md). + +## Metastore + +The metastore service is responsible for maintaining the metadata index and coordinating the compaction process. +This is the only stateful component in the architecture, and it uses local disk as durable storage: even a large-scale +cluster only needs a few gigabytes of disk space for the metadata index. The metastore service uses the Raft protocol +for consensus and replication. + +The metadata index includes information about data objects stored in object storage and their contents, such +as time ranges and datasets containing profiling data for particular services. + +The metastore service is designed to be highly available and fault-tolerant. In a cluster of three nodes, it can +tolerate the loss of a single node, and in a cluster of five nodes, it can tolerate the loss of two nodes. + +You can learn more about the metadata index in the [metastore index documentation](../metastore/index/README.md). + +## Compaction + +The number of objects created in storage can reach millions per hour. This can severely degrade query performance due +to high read amplification and excessive calls to object storage. Additionally, a high number of metadata entries can +degrade performance across the entire cluster, impacting the write path as well. + +To ensure high query performance, data objects are compacted in the background. The compaction-worker service is +responsible for merging small segments into larger blocks, which are then written back to object storage. Compaction +workers compact data as soon as possible after it's written to object storage, with median time to the +first compaction not exceeding 15 seconds. + +Compaction workers are coordinated by the metastore service, which maintains the metadata index and schedules compaction +jobs. Compaction workers are stateless and do not require any local storage. + +You can learn more about the compaction process in the [compaction documentation](../metastore/compaction/README.md). + +## Querying + +Profiling data is queried through the Query API available in the query-frontend service. + +A regular flame graph query users see in the UI may require fetching many gigabytes of data from storage. Moreover, the +raw profiling data needs very expensive post-processing to be displayed in flame graph format. Pyroscope addresses +this challenge through adaptive data placement that minimizes the number of objects that need to be read to satisfy a +query, and high parallelism in query execution. + +The query frontend is responsible for preliminary query planning and routing the query to the query backend service. +Data objects are located using the metastore service, which maintains the metadata index. + +Queries are executed by the query-backend service with high parallelism. Query execution is represented as a graph +where the results of sub-queries are combined and optimized. This minimizes network overhead and enables horizontal +scalability of the read path without needing traditional disk-based solutions or even a caching layer. + +Both query-frontend and query-backend are stateless services that can scale out to hundreds of instances. +In future versions, we plan to add a serverless query-backend option. diff --git a/pkg/pyroscope/admin_server_test.go b/pkg/pyroscope/admin_server_test.go new file mode 100644 index 0000000000..6fb4cc30d8 --- /dev/null +++ b/pkg/pyroscope/admin_server_test.go @@ -0,0 +1,124 @@ +package pyroscope + +import ( + "flag" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAdminServerMode_FlagDefault(t *testing.T) { + cfg := Config{} + fs := flag.NewFlagSet("test", flag.ContinueOnError) + cfg.RegisterFlags(fs) + + assert.Equal(t, AdminServerDisabled, cfg.AdminServer.Mode) + assert.Equal(t, "localhost", cfg.AdminServer.HTTPAddress) + assert.Equal(t, 4042, cfg.AdminServer.HTTPPort) +} + +func TestAdminServerMode_Set(t *testing.T) { + tests := []struct { + value string + want AdminServerMode + wantErr bool + }{ + {"disabled", AdminServerDisabled, false}, + {"additional", AdminServerAdditional, false}, + {"exclusive", AdminServerExclusive, false}, + {"bogus", "", true}, + {"", "", true}, + } + + for _, tt := range tests { + t.Run(tt.value, func(t *testing.T) { + var m AdminServerMode + err := m.Set(tt.value) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, tt.want, m) + } + }) + } +} + +func TestAdminServerMode_IsEnabled(t *testing.T) { + assert.False(t, AdminServerDisabled.IsEnabled()) + assert.True(t, AdminServerAdditional.IsEnabled()) + assert.True(t, AdminServerExclusive.IsEnabled()) +} + +func TestAdminServerMode_FlagParsing(t *testing.T) { + tests := []struct { + name string + args []string + want AdminServerMode + wantErr bool + }{ + {"default", nil, AdminServerDisabled, false}, + {"disabled", []string{"-admin-server.mode=disabled"}, AdminServerDisabled, false}, + {"additional", []string{"-admin-server.mode=additional"}, AdminServerAdditional, false}, + {"exclusive", []string{"-admin-server.mode=exclusive"}, AdminServerExclusive, false}, + {"invalid", []string{"-admin-server.mode=bad"}, "", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := Config{} + fs := flag.NewFlagSet("test", flag.ContinueOnError) + c.RegisterFlags(fs) + err := fs.Parse(tt.args) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, c.AdminServer.Mode) + }) + } +} + +func TestAdminServerMode_RegisterInstrumentation(t *testing.T) { + // In exclusive mode the primary dskit server should have RegisterInstrumentation + // disabled so /metrics and /debug/pprof are not served on the main port. + // In other modes the primary server keeps them. + tests := []struct { + mode AdminServerMode + wantRegisterInstrumentation bool + }{ + {AdminServerDisabled, true}, + {AdminServerAdditional, true}, + {AdminServerExclusive, false}, + } + + for _, tt := range tests { + t.Run(string(tt.mode), func(t *testing.T) { + cfg := newTestConfig(t, nil) + cfg.AdminServer.Mode = tt.mode + // Use port 0 so the OS picks a free port; avoids conflicts across subtests. + cfg.AdminServer.HTTPPort = 0 + + f := &Pyroscope{Cfg: cfg} + require.NoError(t, f.setupModuleManager()) + + // Simulate what initServer does: initialise the admin router first + // (sets f.adminRouter), then check RegisterInstrumentation. + svc, err := f.initAdminServer() + require.NoError(t, err) + if svc != nil { + t.Cleanup(func() { svc.StopAsync() }) + } + + // Replicate the guard from initServer. + f.Cfg.Server.RegisterInstrumentation = true // dskit default + if f.Cfg.AdminServer.Mode == AdminServerExclusive { + f.Cfg.Server.RegisterInstrumentation = false + } + + assert.Equal(t, tt.wantRegisterInstrumentation, f.Cfg.Server.RegisterInstrumentation) + }) + } +} diff --git a/pkg/phlare/context/context.go b/pkg/pyroscope/context/context.go similarity index 100% rename from pkg/phlare/context/context.go rename to pkg/pyroscope/context/context.go diff --git a/pkg/pyroscope/feature_flags.go b/pkg/pyroscope/feature_flags.go new file mode 100644 index 0000000000..ac7cfa9313 --- /dev/null +++ b/pkg/pyroscope/feature_flags.go @@ -0,0 +1,23 @@ +package pyroscope + +import ( + "github.com/grafana/dskit/services" + + "github.com/grafana/pyroscope/v2/pkg/featureflags" +) + +func (c *Config) getFeatureFlags() map[string]bool { + rulerEnabled := c.CompactionWorker.MetricsExporter.Enabled + return map[string]bool{ + featureflags.V2StorageLayer: c.ArchitectureStorage == V1V2Dual || c.ArchitectureStorage == V2, + featureflags.PyroscopeRuler: rulerEnabled, + featureflags.PyroscopeRulerFunctions: rulerEnabled, + featureflags.UTF8LabelNames: false, // not supported yet + } +} + +func (f *Pyroscope) initFeatureFlags() (services.Service, error) { + ff := featureflags.NewFromEnabled(f.reg, f.Cfg.getFeatureFlags()) + f.API.RegisterFeatureFlagsServiceHandler(ff) + return nil, nil +} diff --git a/pkg/pyroscope/health.go b/pkg/pyroscope/health.go new file mode 100644 index 0000000000..49509cdae2 --- /dev/null +++ b/pkg/pyroscope/health.go @@ -0,0 +1,27 @@ +package pyroscope + +import ( + "context" + + "connectrpc.com/grpchealth" + "github.com/gorilla/mux" + "github.com/grafana/dskit/grpcutil" +) + +type checker struct { + checks []grpcutil.Check +} + +func RegisterHealthServer(mux *mux.Router, checks ...grpcutil.Check) { + prefix, handler := grpchealth.NewHandler(&checker{checks: checks}) + mux.NewRoute().PathPrefix(prefix).Handler(handler) +} + +func (c *checker) Check(ctx context.Context, req *grpchealth.CheckRequest) (*grpchealth.CheckResponse, error) { + for _, check := range c.checks { + if !check(ctx) { + return &grpchealth.CheckResponse{Status: grpchealth.StatusNotServing}, nil + } + } + return &grpchealth.CheckResponse{Status: grpchealth.StatusServing}, nil +} diff --git a/pkg/pyroscope/modules.go b/pkg/pyroscope/modules.go new file mode 100644 index 0000000000..bda71a9649 --- /dev/null +++ b/pkg/pyroscope/modules.go @@ -0,0 +1,858 @@ +package pyroscope + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "net/http" + "os" + "slices" + "strings" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + gorillaMux "github.com/gorilla/mux" + "github.com/grafana/dskit/dns" + "github.com/grafana/dskit/kv/codec" + "github.com/grafana/dskit/kv/memberlist" + "github.com/grafana/dskit/middleware" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/runtimeconfig" + "github.com/grafana/dskit/server" + "github.com/grafana/dskit/services" + grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/collectors/version" + "github.com/prometheus/client_golang/prometheus/promhttp" + "go.yaml.in/yaml/v3" + "google.golang.org/genproto/googleapis/api/httpbody" + "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/protobuf/encoding/protojson" + + statusv1 "github.com/grafana/pyroscope/api/gen/proto/go/status/v1" + "github.com/grafana/pyroscope/v2/pkg/adhocprofiles" + apiversion "github.com/grafana/pyroscope/v2/pkg/api/version" + "github.com/grafana/pyroscope/v2/pkg/compactor" + "github.com/grafana/pyroscope/v2/pkg/debuginfo" + "github.com/grafana/pyroscope/v2/pkg/distributor" + "github.com/grafana/pyroscope/v2/pkg/embedded/grafana" + "github.com/grafana/pyroscope/v2/pkg/featureflags" + "github.com/grafana/pyroscope/v2/pkg/ingester" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/operations" + blocksv2 "github.com/grafana/pyroscope/v2/pkg/operations/v2/blocks" + phlarecontext "github.com/grafana/pyroscope/v2/pkg/pyroscope/context" + "github.com/grafana/pyroscope/v2/pkg/querier" + "github.com/grafana/pyroscope/v2/pkg/querier/worker" + "github.com/grafana/pyroscope/v2/pkg/querybackend" + "github.com/grafana/pyroscope/v2/pkg/scheduler" + "github.com/grafana/pyroscope/v2/pkg/settings" + "github.com/grafana/pyroscope/v2/pkg/storegateway" + "github.com/grafana/pyroscope/v2/pkg/usagestats" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/build" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + httpserver "github.com/grafana/pyroscope/v2/pkg/util/http/server" + "github.com/grafana/pyroscope/v2/pkg/validation" + "github.com/grafana/pyroscope/v2/pkg/validation/exporter" +) + +// The various modules that make up Pyroscope. +const ( + All string = "all" + API string = "api" + Version string = "version" + Distributor string = "distributor" + Server string = "server" + IngesterRing string = "ring" + Ingester string = "ingester" + MemberlistKV string = "memberlist-kv" + Querier string = "querier" + StoreGateway string = "store-gateway" + GRPCGateway string = "grpc-gateway" + Storage string = "storage" + UsageReport string = "usage-stats" + QueryFrontend string = "query-frontend" + QueryScheduler string = "query-scheduler" + RuntimeConfig string = "runtime-config" + Overrides string = "overrides" + OverridesExporter string = "overrides-exporter" + Compactor string = "compactor" + Admin string = "admin" + TenantSettings string = "tenant-settings" + AdHocProfiles string = "ad-hoc-profiles" + EmbeddedGrafana string = "embedded-grafana" + FeatureFlags string = "feature-flags" + + // V2 modules. + + Metastore string = "metastore" + MetastoreClient string = "metastore-client" + MetastoreAdmin string = "metastore-admin" + SegmentWriter string = "segment-writer" + SegmentWriterRing string = "segment-writer-ring" + SegmentWriterClient string = "segment-writer-client" + QueryBackend string = "query-backend" + QueryBackendClient string = "query-backend-client" + CompactionWorker string = "compaction-worker" + PlacementAgent string = "placement-agent" + PlacementManager string = "placement-manager" + HealthServer string = "health-server" + AdminServer string = "admin-server" + RecordingRulesClient string = "recording-rules-client" + Symbolizer string = "symbolizer" + QueryDiagnosticsStore string = "query-diagnostics-store" + QueryDiagnosticsAdmin string = "query-diagnostics-admin" + AsyncQueryStore string = "async-query-store" +) + +var objectStoreTypeStats = usagestats.NewString("store_object_type") + +func (f *Pyroscope) initRuntimeConfig() (services.Service, error) { + if len(f.Cfg.RuntimeConfig.LoadPath) == 0 { + // no need to initialize module if load path is empty + return nil, nil + } + + f.Cfg.RuntimeConfig.Loader = func(r io.Reader) (interface{}, error) { + return validation.LoadRuntimeConfig(r) + } + + // make sure to set default limits before we start loading configuration into memory + validation.SetDefaultLimitsForYAMLUnmarshalling(f.Cfg.LimitsConfig) + + serv, err := runtimeconfig.New( + f.Cfg.RuntimeConfig, + "pyroscope", + prometheus.WrapRegistererWithPrefix("pyroscope_", f.reg), + log.With(f.logger, "component", "runtime-config"), + ) + if err == nil { + // TenantLimits just delegates to RuntimeConfig and doesn't have any state or need to do + // anything in the start/stopping phase. Thus we can create it as part of runtime config + // setup without any service instance of its own. + f.TenantLimits = newTenantLimits(serv) + } + + f.RuntimeConfig = serv + f.API.RegisterRuntimeConfig( + runtimeConfigHandler(f.RuntimeConfig, f.Cfg.LimitsConfig), + validation.TenantLimitsHandler(f.Cfg.LimitsConfig, f.TenantLimits), + ) + + return serv, err +} + +func (f *Pyroscope) initTenantSettings() (services.Service, error) { + settings, err := settings.New(f.Cfg.TenantSettings, f.storageBucket, log.With(f.logger, "component", TenantSettings), f.Overrides) + if err != nil { + return nil, fmt.Errorf("failed to init settings service: %w", err) + } + + f.API.RegisterTenantSettings(settings) + return settings, nil +} + +func (f *Pyroscope) initAdHocProfiles() (services.Service, error) { + if f.storageBucket == nil { + level.Warn(f.logger).Log("msg", "no storage bucket configured, ad hoc profiles will not be loaded") + return nil, nil + } + + a := adhocprofiles.NewAdHocProfiles(f.storageBucket, f.logger, f.Overrides) + f.API.RegisterAdHocProfiles(a) + return a, nil +} + +func (f *Pyroscope) initOverrides() (serv services.Service, err error) { + f.Overrides, err = validation.NewOverrides(f.Cfg.LimitsConfig, f.TenantLimits) + // overrides don't have operational state, nor do they need to do anything more in starting/stopping phase, + // so there is no need to return any service. + return nil, err +} + +func (f *Pyroscope) initOverridesExporter() (services.Service, error) { + overridesExporter, err := exporter.NewOverridesExporter( + f.Cfg.OverridesExporter, + &f.Cfg.LimitsConfig, + f.TenantLimits, + log.With(f.logger, "component", "overrides-exporter"), + f.reg, + ) + if err != nil { + return nil, fmt.Errorf("failed to instantiate overrides-exporter: %w", err) + } + if f.reg != nil { + f.reg.MustRegister(overridesExporter) + } + + f.API.RegisterOverridesExporter(overridesExporter) + + return overridesExporter, nil +} + +func (f *Pyroscope) initQueryScheduler() (services.Service, error) { + f.Cfg.QueryScheduler.ServiceDiscovery.SchedulerRing.ListenPort = f.Cfg.Server.HTTPListenPort + + s, err := scheduler.NewScheduler(f.Cfg.QueryScheduler, f.Overrides, log.With(f.logger, "component", "scheduler"), f.reg) + if err != nil { + return nil, fmt.Errorf("query-scheduler init: %w", err) + } + + f.API.RegisterQueryScheduler(s) + + return s, nil +} + +func (f *Pyroscope) initCompactor() (serv services.Service, err error) { + f.Cfg.Compactor.ShardingRing.Common.ListenPort = f.Cfg.Server.HTTPListenPort + + if f.storageBucket == nil { + return nil, nil + } + + f.Compactor, err = compactor.NewMultitenantCompactor( + f.Cfg.Compactor, + f.storageBucket, + f.Overrides, + log.With(f.logger, "component", "compactor"), + f.reg, + ) + if err != nil { + return + } + + // Expose HTTP endpoints. + f.API.RegisterCompactor(f.Compactor) + return f.Compactor, nil +} + +// setupWorkerTimeout sets the max loop duration for the querier worker and frontend worker +// to 90% of the read or write http timeout, whichever is smaller. +// This is to ensure that the worker doesn't timeout before the http handler and that the connection +// is refreshed. +func (f *Pyroscope) setupWorkerTimeout() { + timeout := f.Cfg.Server.HTTPServerReadTimeout + if f.Cfg.Server.HTTPServerWriteTimeout < timeout { + timeout = f.Cfg.Server.HTTPServerWriteTimeout + } + + if timeout > 0 { + f.Cfg.Worker.MaxLoopDuration = time.Duration(float64(timeout) * 0.9) + f.Cfg.Frontend.MaxLoopDuration = time.Duration(float64(timeout) * 0.9) + } +} + +func (f *Pyroscope) initQuerier() (services.Service, error) { + newQuerierParams := &querier.NewQuerierParams{ + Cfg: f.Cfg.Querier, + StoreGatewayCfg: f.Cfg.StoreGateway, + Overrides: f.Overrides, + CfgProvider: f.Overrides, + StorageBucket: f.storageBucket, + IngestersRing: f.ingesterRing, + Reg: f.reg, + Logger: log.With(f.logger, "component", "querier"), + ClientOptions: []connect.ClientOption{f.auth}, + } + querierSvc, err := querier.New(newQuerierParams) + if err != nil { + return nil, err + } + + if !f.isModuleActive(QueryFrontend) { + f.API.RegisterPyroscopeHandlers(querierSvc) + f.API.RegisterQuerierServiceHandler(querierSvc) + } + + qWorker, err := worker.NewQuerierWorker( + f.Cfg.Worker, + querier.NewGRPCHandler(querierSvc, f.Cfg.SelfProfiling.UseK6Middleware), + log.With(f.logger, "component", "querier-worker"), + f.reg, + ) + if err != nil { + return nil, err + } + + sm, err := services.NewManager(querierSvc, qWorker) + if err != nil { + return nil, err + } + w := services.NewFailureWatcher() + w.WatchManager(sm) + + return services.NewBasicService(func(ctx context.Context) error { + err := sm.StartAsync(ctx) + if err != nil { + return err + } + return sm.AwaitHealthy(ctx) + }, func(ctx context.Context) error { + select { + case <-ctx.Done(): + return nil + case err := <-w.Chan(): + return err + } + }, func(failureCase error) error { + sm.StopAsync() + return sm.AwaitStopped(context.Background()) + }), nil +} + +func (f *Pyroscope) initGRPCGateway() (services.Service, error) { + f.grpcGatewayMux = grpcgw.NewServeMux( + grpcgw.WithMarshalerOption("application/json+pretty", &grpcgw.JSONPb{ + MarshalOptions: protojson.MarshalOptions{ + Indent: " ", + Multiline: true, // Optional, implied by presence of "Indent". + }, + UnmarshalOptions: protojson.UnmarshalOptions{ + DiscardUnknown: true, + }, + }), + ) + return nil, nil +} + +func (f *Pyroscope) initDistributor() (services.Service, error) { + f.Cfg.Distributor.DistributorRing.ListenPort = f.Cfg.Server.HTTPListenPort + logger := log.With(f.logger, "component", "distributor") + var swClient distributor.SegmentWriterClient + if f.segmentWriterClient != nil { + swClient = f.segmentWriterClient + } + d, err := distributor.New(f.Cfg.Distributor, f.ingesterRing, nil, f.Overrides, f.reg, logger, swClient, f.auth) + if err != nil { + return nil, err + } + f.distributor = d + f.API.RegisterDistributor(d, f.Overrides, f.Cfg.Server) + + if store, err := debuginfo.NewStore(f.logger, f.storageBucket, f.Cfg.DebugInfo); err != nil { + return nil, err + } else { + f.API.RegisterDebugInfo(store, store.UploadHTTPHandler()) + } + return d, nil +} + +func (f *Pyroscope) initMemberlistKV() (services.Service, error) { + f.Cfg.MemberlistKV.Codecs = []codec.Codec{ + ring.GetCodec(), + usagestats.JSONCodec, + apiversion.GetCodec(), + } + + dnsProviderReg := prometheus.WrapRegistererWithPrefix( + "pyroscope_", + prometheus.WrapRegistererWith( + prometheus.Labels{"name": "memberlist"}, + f.reg, + ), + ) + dnsProvider := dns.NewProvider(dns.GolangResolverType, 2, f.logger, dnsProviderReg) + + f.Cfg.MemberlistKV.MetricsNamespace = "pyroscope" + f.MemberlistKV = memberlist.NewKVInitService(&f.Cfg.MemberlistKV, f.logger, dnsProvider, f.reg) + + f.Cfg.Distributor.DistributorRing.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV + f.Cfg.Ingester.LifecyclerConfig.RingConfig.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV + f.Cfg.SegmentWriter.LifecyclerConfig.RingConfig.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV + f.Cfg.QueryScheduler.ServiceDiscovery.SchedulerRing.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV + f.Cfg.OverridesExporter.Ring.Ring.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV + f.Cfg.StoreGateway.ShardingRing.Ring.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV + f.Cfg.Compactor.ShardingRing.Common.KVStore.MemberlistKV = f.MemberlistKV.GetMemberlistKV + f.Cfg.Frontend.QuerySchedulerDiscovery = f.Cfg.QueryScheduler.ServiceDiscovery + f.Cfg.Worker.QuerySchedulerDiscovery = f.Cfg.QueryScheduler.ServiceDiscovery + + f.API.RegisterMemberlistKV("", f.MemberlistKV) + + return f.MemberlistKV, nil +} + +func (f *Pyroscope) initIngesterRing() (_ services.Service, err error) { + f.ingesterRing, err = ring.New( + f.Cfg.Ingester.LifecyclerConfig.RingConfig, + "ingester", + "ring", + log.With(f.logger, "component", "ring"), + prometheus.WrapRegistererWithPrefix("pyroscope_", f.reg), + ) + if err != nil { + return nil, err + } + f.API.RegisterIngesterRing(f.ingesterRing) + return f.ingesterRing, nil +} + +func (f *Pyroscope) initStorage() (_ services.Service, err error) { + objectStoreTypeStats.Set(f.Cfg.Storage.Bucket.Backend) + if cfg := f.Cfg.Storage.Bucket; cfg.Backend != objstoreclient.None { + if cfg.Backend == objstoreclient.Filesystem { + level.Warn(f.logger). + Log("msg", "when running with storage.backend 'filesystem' it is important that all replicas/components share the same filesystem") + } + b, err := objstoreclient.NewBucket( + f.context(), + cfg, + "storage", + ) + if err != nil { + return nil, fmt.Errorf("unable to initialise bucket: %w", err) + } + f.storageBucket = b + } + + if !slices.Contains(f.Cfg.Target, All) && f.storageBucket == nil { + return nil, errors.New("storage bucket configuration is required when running in microservices mode") + } + + return nil, nil +} + +// TODO: This should be passed to all other services and could also be used to signal shutdown +func (f *Pyroscope) context() context.Context { + phlarectx := phlarecontext.WithLogger(context.Background(), f.logger) + return phlarecontext.WithRegistry(phlarectx, f.reg) +} + +func (f *Pyroscope) initIngester() (_ services.Service, err error) { + f.Cfg.Ingester.LifecyclerConfig.ListenPort = f.Cfg.Server.HTTPListenPort + + svc, err := ingester.New( + f.context(), + f.Cfg.Ingester, + f.Cfg.PhlareDB, + f.storageBucket, + f.Overrides, + f.Cfg.Querier.QueryStoreAfter, + ) + if err != nil { + return nil, err + } + + f.API.RegisterIngester(svc) + f.ingester = svc + + return svc, nil +} + +func (f *Pyroscope) initStoreGateway() (serv services.Service, err error) { + f.Cfg.StoreGateway.ShardingRing.Ring.ListenPort = f.Cfg.Server.HTTPListenPort + if f.storageBucket == nil { + return nil, nil + } + + svc, err := storegateway.NewStoreGateway(f.Cfg.StoreGateway, f.storageBucket, f.Overrides, f.logger, f.reg) + if err != nil { + return nil, err + } + f.API.RegisterStoreGateway(svc) + return svc, nil +} + +func (f *Pyroscope) initServer() (services.Service, error) { + f.reg.MustRegister(version.NewCollector("pyroscope")) + f.reg.Unregister(collectors.NewGoCollector()) + // register collector with additional metrics + f.reg.MustRegister(collectors.NewGoCollector( + collectors.WithGoCollectorRuntimeMetrics(collectors.MetricsAll), + )) + DisableSignalHandling(&f.Cfg.Server) + f.Cfg.Server.Registerer = prometheus.WrapRegistererWithPrefix("pyroscope_", f.reg) + // Not all default middleware works with http2 so we'll add then manually. + // see https://github.com/grafana/pyroscope/issues/231 + f.Cfg.Server.DoNotAddDefaultHTTPMiddleware = true + f.Cfg.Server.ExcludeRequestInLog = true // gRPC-specific. + f.Cfg.Server.GRPCMiddleware = append(f.Cfg.Server.GRPCMiddleware, + util.RecoveryInterceptorGRPC, + featureflags.ClientCapabilitiesGRPCMiddleware(), + ) + + if f.Cfg.ArchitectureStorage != V1 { + f.Cfg.Server.MetricsNativeHistogramFactor = 1.1 // 10% increase from bucket to bucket + if slices.Contains(f.Cfg.Target, QueryBackend) { + concurrencyInterceptor, err := querybackend.CreateConcurrencyInterceptor(f.logger) + if err != nil { + return nil, err + } + f.Cfg.Server.GRPCMiddleware = append(f.Cfg.Server.GRPCMiddleware, concurrencyInterceptor) + } + } + + // In exclusive mode, operational endpoints (/metrics, /debug/pprof) move to the + // admin server only; remove them from the main port. + if f.Cfg.AdminServer.Mode == AdminServerExclusive { + f.Cfg.Server.RegisterInstrumentation = false + } + + f.setupWorkerTimeout() + if f.isModuleActive(QueryScheduler) || f.isModuleActive(QueryFrontend) { + // to ensure that the query scheduler is always able to handle the request, we need to double the timeout + f.Cfg.Server.HTTPServerReadTimeout = 2 * f.Cfg.Server.HTTPServerReadTimeout + f.Cfg.Server.HTTPServerWriteTimeout = 2 * f.Cfg.Server.HTTPServerWriteTimeout + } + var err error + if f.Server, err = server.New(f.Cfg.Server); err != nil { + return nil, err + } + + if f.healthServer != nil { + grpc_health_v1.RegisterHealthServer(f.Server.GRPC, f.healthServer) + } + + servicesToWaitFor := func() []services.Service { + svs := []services.Service(nil) + for m, s := range f.serviceMap { + // Server should not wait for itself. + if m != Server { + svs = append(svs, s) + } + } + return svs + } + + httpMetric, err := httputil.NewHTTPMetricMiddleware(f.Server.HTTP, f.Cfg.Server.MetricsNamespace, f.Cfg.Server.Registerer) + if err != nil { + return nil, err + } + defaultHTTPMiddleware := []middleware.Interface{ + middleware.Tracer{}, + // https://github.com/grafana/dskit/pull/527 + middleware.RouteInjector{ + RouteMatcher: f.Server.HTTP, + }, + &httputil.Log{ + Log: f.Server.Log, + LogRequestAtInfoLevel: f.Cfg.Server.LogRequestAtInfoLevel, + LogRequestHeaders: f.Cfg.Server.LogRequestHeaders, + LogRequestExcludeHeaders: strings.Split(f.Cfg.Server.LogRequestExcludeHeadersList, ","), + }, + httpMetric, + httputil.K6Middleware(), + featureflags.ClientCapabilitiesHttpMiddleware(), + } + if f.Cfg.SelfProfiling.UseK6Middleware { + defaultHTTPMiddleware = append(defaultHTTPMiddleware, httputil.K6Middleware()) + } + + f.Server.HTTPServer.Handler = middleware.Merge(defaultHTTPMiddleware...).Wrap(f.Server.HTTP) + + s := NewServerService(f.Server, servicesToWaitFor, f.logger) + httpserver.EnableHTTP2(f.Server.HTTPServer) + f.Server.HTTPServer.Handler = util.RecoveryHTTPMiddleware.Wrap(f.Server.HTTPServer.Handler) + + return s, nil +} + +func (f *Pyroscope) initAdminServer() (services.Service, error) { + // Always create the router so route-registration calls in API are safe to call + // regardless of mode; they just won't be reachable if no listener is started. + router := gorillaMux.NewRouter() + f.adminRouter = router + + if !f.Cfg.AdminServer.Mode.IsEnabled() { + return nil, nil + } + + // /metrics + router.Handle("/metrics", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{ + EnableOpenMetrics: true, + })).Methods("GET") + // /debug/pprof — net/http/pprof registers its handlers on http.DefaultServeMux, + // so we just forward the whole prefix there. + router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux) + router.Handle("/debug/pprof", http.DefaultServeMux) + + addr := net.JoinHostPort(f.Cfg.AdminServer.HTTPAddress, fmt.Sprintf("%d", f.Cfg.AdminServer.HTTPPort)) + + ln, err := net.Listen("tcp", addr) + if err != nil { + return nil, fmt.Errorf("admin server: listen %s: %w", addr, err) + } + + srv := &http.Server{ + Handler: router, + } + + return services.NewIdleService( + func(_ context.Context) error { + level.Info(f.logger).Log("msg", "admin server listening on addresses", "http", addr) + go func() { + if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed { + level.Error(f.logger).Log("msg", "admin server error", "err", err) + } + }() + return nil + }, + func(_ error) error { + return srv.Shutdown(context.Background()) + }, + ), nil +} + +func (f *Pyroscope) initUsageReport() (services.Service, error) { + if !f.Cfg.Analytics.Enabled { + return nil, nil + } + f.Cfg.Analytics.Leader = false + // ingester is the only component that can be a leader + if f.isModuleActive(Ingester) { + f.Cfg.Analytics.Leader = true + } + + usagestats.Target(f.Cfg.Target.String()) + + b := f.storageBucket + if f.storageBucket == nil { + if err := os.MkdirAll(f.Cfg.PhlareDB.DataPath, 0o777); err != nil { + return nil, fmt.Errorf("mkdir %s: %w", f.Cfg.PhlareDB.DataPath, err) + } + fs, err := filesystem.NewBucket(f.Cfg.PhlareDB.DataPath) + if err != nil { + return nil, err + } + b = fs + } + + if b == nil { + level.Warn(f.logger).Log("msg", "no storage bucket configured, usage report will not be sent") + return nil, nil + } + + ur, err := usagestats.NewReporter(f.Cfg.Analytics, f.Cfg.Ingester.LifecyclerConfig.RingConfig.KVStore, b, f.logger, f.reg) + if err != nil { + level.Info(f.logger).Log("msg", "failed to initialize usage report", "err", err) + return nil, nil + } + f.usageReport = ur + return ur, nil +} + +func (f *Pyroscope) initAdmin() (services.Service, error) { + if f.Cfg.ArchitectureStorage == V1 { + return f.initLegacyAdmin() + } + if f.metastoreClient == nil { + level.Warn(f.logger).Log("msg", "v2 enabled but no metastore client configured, the admin component will not be loaded") + return nil, nil + } + level.Info(f.logger).Log("msg", "initializing v2 admin (metastore-based)") + + a, err := blocksv2.NewAdmin(f.metastoreClient, f.storageBucket, f.logger) + if err != nil { + level.Info(f.logger).Log("msg", "failed to initialize v2 admin", "err", err) + return nil, nil + } + f.admin = a + f.API.RegisterAdmin(a) + return a, nil +} + +func (f *Pyroscope) initLegacyAdmin() (services.Service, error) { + if f.storageBucket == nil { + level.Warn(f.logger).Log("msg", "no storage bucket configured, the admin component will not be loaded") + return nil, nil + } + + a, err := operations.NewAdmin(f.storageBucket, f.logger, f.Cfg.PhlareDB.MaxBlockDuration) + if err != nil { + level.Info(f.logger).Log("msg", "failed to initialize admin", "err", err) + return nil, nil + } + f.admin = a + f.API.RegisterAdmin(a) + return a, nil + +} + +func (f *Pyroscope) initEmbeddedGrafana() (services.Service, error) { + return grafana.New(f.Cfg.EmbeddedGrafana, f.logger) +} + +type statusService struct { + statusv1.UnimplementedStatusServiceServer + defaultConfig *Config + actualConfig *Config +} + +func (s *statusService) GetBuildInfo( + ctx context.Context, + req *statusv1.GetBuildInfoRequest, +) (*statusv1.GetBuildInfoResponse, error) { + version := build.GetVersion() + return &statusv1.GetBuildInfoResponse{ + Status: "success", + Data: &statusv1.GetBuildInfoData{ + Version: version.Version, + Revision: build.Revision, + Branch: version.Branch, + GoVersion: version.GoVersion, + }, + }, nil +} + +const ( + // There is not standardised and generally used content-type for YAML, + // text/plain ensures the YAML is displayed in the browser instead of + // offered as a download + yamlContentType = "text/plain; charset=utf-8" +) + +func (s *statusService) GetConfig(ctx context.Context, req *statusv1.GetConfigRequest) (*httpbody.HttpBody, error) { + body, err := yaml.Marshal(s.actualConfig) + if err != nil { + return nil, err + } + + return &httpbody.HttpBody{ + ContentType: yamlContentType, + Data: body, + }, nil +} + +func (s *statusService) GetDefaultConfig(ctx context.Context, req *statusv1.GetConfigRequest) (*httpbody.HttpBody, error) { + body, err := yaml.Marshal(s.defaultConfig) + if err != nil { + return nil, err + } + + return &httpbody.HttpBody{ + ContentType: yamlContentType, + Data: body, + }, nil +} + +func (s *statusService) GetDiffConfig(ctx context.Context, req *statusv1.GetConfigRequest) (*httpbody.HttpBody, error) { + aBody, err := yaml.Marshal(s.actualConfig) + if err != nil { + return nil, err + } + aCfg := map[interface{}]interface{}{} + if err := yaml.Unmarshal(aBody, &aCfg); err != nil { + return nil, err + } + + dBody, err := yaml.Marshal(s.defaultConfig) + if err != nil { + return nil, err + } + dCfg := map[interface{}]interface{}{} + if err := yaml.Unmarshal(dBody, &dCfg); err != nil { + return nil, err + } + + diff, err := util.DiffConfig(dCfg, aCfg) + if err != nil { + return nil, err + } + + body, err := yaml.Marshal(diff) + if err != nil { + return nil, err + } + + return &httpbody.HttpBody{ + ContentType: yamlContentType, + Data: body, + }, nil +} + +func (f *Pyroscope) statusService() statusv1.StatusServiceServer { + return &statusService{ + actualConfig: &f.Cfg, + defaultConfig: newDefaultConfig(), + } +} + +func (f *Pyroscope) isModuleActive(m string) bool { + for _, target := range f.Cfg.Target { + if target == m { + return true + } + if f.recursiveIsModuleActive(target, m) { + return true + } + } + return false +} + +func (f *Pyroscope) recursiveIsModuleActive(target, m string) bool { + if targetDeps, ok := f.deps[target]; ok { + for _, dep := range targetDeps { + if dep == m { + return true + } + if f.recursiveIsModuleActive(dep, m) { + return true + } + } + } + return false +} + +// NewServerService constructs service from Server component. +// servicesToWaitFor is called when server is stopping, and should return all +// services that need to terminate before server actually stops. +// N.B.: this function is NOT Cortex specific, please let's keep it that way. +// Passed server should not react on signals. Early return from Run function is considered to be an error. +func NewServerService(serv *server.Server, servicesToWaitFor func() []services.Service, log log.Logger) services.Service { + serverDone := make(chan error, 1) + + runFn := func(ctx context.Context) error { + go func() { + defer close(serverDone) + serverDone <- serv.Run() + }() + + select { + case <-ctx.Done(): + return nil + case err := <-serverDone: + if err != nil { + return fmt.Errorf("server stopped unexpectedly: %w", err) + } + return nil + } + } + + stoppingFn := func(_ error) error { + // wait until all modules are done, and then shutdown server. + for _, s := range servicesToWaitFor() { + _ = s.AwaitTerminated(context.Background()) + } + + // shutdown HTTP and gRPC servers (this also unblocks Run) + serv.Shutdown() + + // if not closed yet, wait until server stops. + <-serverDone + level.Info(log).Log("msg", "server stopped") + return nil + } + + return services.NewBasicService(nil, runFn, stoppingFn) +} + +// DisableSignalHandling puts a dummy signal handler +func DisableSignalHandling(config *server.Config) { + config.SignalHandler = make(ignoreSignalHandler) +} + +type ignoreSignalHandler chan struct{} + +func (dh ignoreSignalHandler) Loop() { + <-dh +} + +func (dh ignoreSignalHandler) Stop() { + close(dh) +} diff --git a/pkg/pyroscope/modules_experimental.go b/pkg/pyroscope/modules_experimental.go new file mode 100644 index 0000000000..a82f64bfd8 --- /dev/null +++ b/pkg/pyroscope/modules_experimental.go @@ -0,0 +1,527 @@ +package pyroscope + +import ( + "context" + "fmt" + "slices" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/middleware" + "github.com/grafana/dskit/netutil" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "google.golang.org/grpc" + grpchealth "google.golang.org/grpc/health" + + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + "github.com/grafana/pyroscope/v2/pkg/compactionworker" + "github.com/grafana/pyroscope/v2/pkg/frontend" + asyncquery "github.com/grafana/pyroscope/v2/pkg/frontend/async" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend/diagnostics" + "github.com/grafana/pyroscope/v2/pkg/frontend/vcs" + "github.com/grafana/pyroscope/v2/pkg/metastore" + metastoreadmin "github.com/grafana/pyroscope/v2/pkg/metastore/admin" + metastoreclient "github.com/grafana/pyroscope/v2/pkg/metastore/client" + "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" + "github.com/grafana/pyroscope/v2/pkg/metrics" + "github.com/grafana/pyroscope/v2/pkg/operations/v2/querydiagnostics" + "github.com/grafana/pyroscope/v2/pkg/querybackend" + querybackendclient "github.com/grafana/pyroscope/v2/pkg/querybackend/client" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter" + segmentwriterclient "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client" + placement "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" + recordingrulesclient "github.com/grafana/pyroscope/v2/pkg/settings/recording/client" + "github.com/grafana/pyroscope/v2/pkg/symbolizer" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/health" + "github.com/grafana/pyroscope/v2/pkg/util/spanlogger" +) + +func (f *Pyroscope) initQueryFrontend() (services.Service, error) { + var err error + if f.Cfg.Frontend.Addr, err = f.getFrontendAddress(); err != nil { + return nil, fmt.Errorf("failed to get frontend address: %w", err) + } + if f.Cfg.Frontend.Port == 0 { + f.Cfg.Frontend.Port = f.Cfg.Server.HTTPListenPort + } + switch f.Cfg.ArchitectureStorage { + case V1: + return f.initQueryFrontendV1() + case V2: + return f.initQueryFrontendV2() + case V1V2Dual: + // Both fixed timestamps and "auto" mode use the hybrid frontend: + // fixed timestamps are resolved immediately, while "auto" queries + // the metastore at request time. + return f.initQueryFrontendV12() + default: + return nil, fmt.Errorf("invalid architecture storage configuration: %v", f.Cfg.ArchitectureStorage) + } +} + +func (f *Pyroscope) initQueryFrontendV1() (services.Service, error) { + queryFrontendLogger := log.With(f.logger, "component", "frontend") + var err error + f.frontend, err = frontend.NewFrontend(f.Cfg.Frontend, f.Overrides, queryFrontendLogger, f.reg) + if err != nil { + return nil, err + } + handler := spanlogger.NewLogSpanParametersWrapper(f.frontend, queryFrontendLogger) + f.API.RegisterFrontendForQuerierHandler(f.frontend) + f.API.RegisterQuerierServiceHandler(handler) + f.API.RegisterPyroscopeHandlers(handler) + f.API.RegisterVCSServiceHandler(f.frontend) + return f.frontend, nil +} + +func (f *Pyroscope) initQueryFrontendV2() (services.Service, error) { + queryFrontendLogger := log.With(f.logger, "component", "query-frontend") + + f.queryFrontend = queryfrontend.NewQueryFrontend( + queryFrontendLogger, + f.Overrides, + f.metastoreClient, + f.metastoreClient, + f.queryBackendClient, + f.symbolizer, + f.queryDiagnosticsStore, + f.reg, + ) + + // Wrap the query frontend: diagnostics wrapper -> spanlogger wrapper -> query frontend + handler := diagnostics.NewWrapper( + log.With(f.logger, "component", "diagnostics-wrapper"), + spanlogger.NewLogSpanParametersWrapper(f.queryFrontend, queryFrontendLogger), + f.queryDiagnosticsStore, + ) + + querierHandler := querierv1connect.QuerierServiceHandler(handler) + if f.Cfg.Frontend.AsyncQueriesEnabled && f.asyncQueryStore != nil { + coordinator := asyncquery.NewCoordinator( + log.With(f.logger, "component", "async-query-coordinator"), + f.asyncQueryStore, + f.Overrides, + f.reg, + ) + querierHandler = asyncquery.NewHandler(querierHandler, coordinator) + } + + vcsService := vcs.New( + log.With(f.logger, "component", "vcs-service"), + f.reg, + ) + + f.API.RegisterQuerierServiceHandler(querierHandler) + f.API.RegisterPyroscopeHandlers(handler) + f.API.RegisterVCSServiceHandler(vcsService) + + // New query frontend does not have any state. + // For simplicity, we return a no-op service. + svc := services.NewIdleService( + func(context.Context) error { return nil }, + func(error) error { return nil }, + ) + + return svc, nil +} + +func (f *Pyroscope) initQueryFrontendV12() (services.Service, error) { + var err error + f.frontend, err = frontend.NewFrontend(f.Cfg.Frontend, f.Overrides, log.With(f.logger, "component", "frontend"), f.reg) + if err != nil { + return nil, err + } + + queryFrontendLogger := log.With(f.logger, "component", "query-frontend") + f.queryFrontend = queryfrontend.NewQueryFrontend( + queryFrontendLogger, + f.Overrides, + f.metastoreClient, + f.metastoreClient, + f.queryBackendClient, + f.symbolizer, + nil, + f.reg, + ) + + resolver := readpath.NewMetastoreSplitTimeResolver(f.metastoreClient, time.Minute) + + handler := readpath.NewRouter( + log.With(f.logger, "component", "read-path-router"), + f.Overrides, + resolver, + f.frontend, + f.queryFrontend, + ) + + wrappedHandler := spanlogger.NewLogSpanParametersWrapper(handler, queryFrontendLogger) + + querierHandler := querierv1connect.QuerierServiceHandler(wrappedHandler) + if f.Cfg.Frontend.AsyncQueriesEnabled && f.asyncQueryStore != nil { + coordinator := asyncquery.NewCoordinator( + log.With(f.logger, "component", "async-query-coordinator"), + f.asyncQueryStore, + f.Overrides, + f.reg, + ) + querierHandler = asyncquery.NewHandler(querierHandler, coordinator) + } + + vcsService := vcs.New( + log.With(f.logger, "component", "vcs-service"), + f.reg, + ) + + f.API.RegisterFrontendForQuerierHandler(f.frontend) + f.API.RegisterQuerierServiceHandler(querierHandler) + f.API.RegisterPyroscopeHandlers(wrappedHandler) + f.API.RegisterVCSServiceHandler(vcsService) + + return f.frontend, nil +} + +func (f *Pyroscope) getFrontendAddress() (addr string, err error) { + addr = f.Cfg.Frontend.Addr + if f.Cfg.Frontend.AddrOld != "" { + addr = f.Cfg.Frontend.AddrOld + } + if addr != "" { + return addr, nil + } + return netutil.GetFirstAddressOf(f.Cfg.Frontend.InfNames, f.logger, f.Cfg.Frontend.EnableIPv6) +} + +func (f *Pyroscope) initAsyncQueryStore() (services.Service, error) { + if !f.Cfg.Frontend.AsyncQueriesEnabled { + return nil, nil + } + if f.storageBucket == nil { + return nil, nil + } + f.asyncQueryStore = asyncquery.NewStore( + log.With(f.logger, "component", "async-query-store"), + f.storageBucket, + ) + return f.asyncQueryStore, nil +} + +func (f *Pyroscope) initSegmentWriterRing() (_ services.Service, err error) { + if err = f.Cfg.SegmentWriter.Validate(); err != nil { + return nil, err + } + logger := log.With(f.logger, "component", "segment-writer-ring") + reg := prometheus.WrapRegistererWithPrefix("pyroscope_", f.reg) + f.segmentWriterRing, err = ring.New( + f.Cfg.SegmentWriter.LifecyclerConfig.RingConfig, + segmentwriter.RingName, + segmentwriter.RingKey, + logger, reg, + ) + if err != nil { + return nil, err + } + f.API.RegisterSegmentWriterRing(f.segmentWriterRing) + return f.segmentWriterRing, nil +} + +func (f *Pyroscope) initSegmentWriter() (services.Service, error) { + f.Cfg.SegmentWriter.LifecyclerConfig.ListenPort = f.Cfg.Server.GRPCListenPort + if err := f.Cfg.SegmentWriter.Validate(); err != nil { + return nil, err + } + + logger := log.With(f.logger, "component", "segment-writer") + healthService := health.NewGRPCHealthService(f.healthServer, logger, "pyroscope.segment-writer") + segmentWriter, err := segmentwriter.New( + f.reg, + logger, + f.Cfg.SegmentWriter, + f.Overrides, + healthService, + f.storageBucket, + f.metastoreClient, + ) + if err != nil { + return nil, err + } + + f.segmentWriter = segmentWriter + f.API.RegisterSegmentWriter(segmentWriter) + return f.segmentWriter, nil +} + +func (f *Pyroscope) initSegmentWriterClient() (_ services.Service, err error) { + f.Cfg.SegmentWriter.GRPCClientConfig.Middleware = f.grpcClientInterceptors() + // Validation of the config is not required since + // it's already validated in initSegmentWriterRing. + logger := log.With(f.logger, "component", "segment-writer-client") + placement := f.placementAgent.Placement() + client, err := segmentwriterclient.NewSegmentWriterClient( + f.Cfg.SegmentWriter.GRPCClientConfig, + logger, f.reg, + f.segmentWriterRing, + placement, + grpc.WithStatsHandler(otelgrpc.NewClientHandler()), + ) + if err != nil { + return nil, err + } + f.segmentWriterClient = client + return client.Service(), nil +} + +func (f *Pyroscope) initCompactionWorker() (svc services.Service, err error) { + logger := log.With(f.logger, "component", "compaction-worker") + registerer := prometheus.WrapRegistererWithPrefix("pyroscope_compaction_worker_", f.reg) + + var ruler metrics.Ruler + var exporter metrics.Exporter + if f.Cfg.CompactionWorker.MetricsExporter.Enabled { + if f.recordingRulesClient != nil { + ruler, err = metrics.NewCachedRemoteRuler(f.recordingRulesClient, f.logger) + if err != nil { + return nil, err + } + } else { + ruler = metrics.NewStaticRulerFromOverrides(f.Overrides) + } + + exporter, err = metrics.NewExporter(f.Cfg.CompactionWorker.MetricsExporter.RemoteWriteAddress, f.logger, f.reg) + if err != nil { + return nil, err + } + } + + w, err := compactionworker.New( + logger, + f.Cfg.CompactionWorker, + f.metastoreClient, + f.storageBucket, + registerer, + ruler, + exporter, + ) + if err != nil { + return nil, err + } + f.compactionWorker = w + return w.Service(), nil +} + +func (f *Pyroscope) initMetastore() (services.Service, error) { + if err := f.Cfg.Metastore.Validate(); err != nil { + return nil, err + } + + logger := log.With(f.logger, "component", "metastore") + healthService := health.NewGRPCHealthService(f.healthServer, logger, "pyroscope.metastore") + registerer := prometheus.WrapRegistererWithPrefix("pyroscope_metastore_", f.reg) + m, err := metastore.New( + f.Cfg.Metastore, + f.Overrides, + logger, + registerer, + healthService, + f.metastoreClient, + f.storageBucket, + f.placementManager, + ) + if err != nil { + return nil, err + } + + m.Register(f.Server.GRPC) + f.metastore = m + return m.Service(), nil +} + +func (f *Pyroscope) initMetastoreClient() (services.Service, error) { + if err := f.Cfg.Metastore.Validate(); err != nil { + return nil, err + } + + disc, err := discovery.NewDiscovery(f.logger, f.Cfg.Metastore.Address, f.reg) + if err != nil { + return nil, fmt.Errorf("failed to create discovery: %w %s", err, f.Cfg.Metastore.Address) + } + + f.Cfg.Metastore.GRPCClientConfig.Middleware = f.grpcClientInterceptors() + f.metastoreClient = metastoreclient.New( + f.logger, + f.Cfg.Metastore.GRPCClientConfig, + disc, + grpc.WithStatsHandler(otelgrpc.NewClientHandler()), + ) + return f.metastoreClient.Service(), nil +} + +func (f *Pyroscope) initMetastoreAdmin() (services.Service, error) { + level.Info(f.logger).Log("msg", "initializing metastore admin") + if err := f.Cfg.Metastore.Validate(); err != nil { + return nil, err + } + + var err error + f.metastoreAdmin, err = metastoreadmin.New(f.metastoreClient, f.logger, f.Cfg.Metastore.Address, f.metastoreClient) + if err != nil { + return nil, err + } + level.Info(f.logger).Log("msg", "registering metastore admin routes") + f.API.RegisterMetastoreAdmin(f.metastoreAdmin) + return f.metastoreAdmin.Service(), nil +} + +func (f *Pyroscope) initQueryBackend() (services.Service, error) { + if err := f.Cfg.QueryBackend.Validate(); err != nil { + return nil, err + } + logger := log.With(f.logger, "component", "query-backend") + blockReader := querybackend.NewBlockReader(f.logger, f.storageBucket, f.reg, f.Overrides) + b, err := querybackend.New( + f.Cfg.QueryBackend, + logger, + f.reg, + f.queryBackendClient, + blockReader, + ) + if err != nil { + return nil, err + } + f.API.RegisterQueryBackend(b) + return b.Service(), nil +} + +func (f *Pyroscope) initQueryBackendClient() (services.Service, error) { + if err := f.Cfg.QueryBackend.Validate(); err != nil { + return nil, err + } + f.Cfg.QueryBackend.GRPCClientConfig.Middleware = f.grpcClientInterceptors() + c, err := querybackendclient.New( + f.Cfg.QueryBackend.Address, + f.Cfg.QueryBackend.GRPCClientConfig, + f.Cfg.QueryBackend.ClientTimeout, + grpc.WithStatsHandler(otelgrpc.NewClientHandler()), + ) + if err != nil { + return nil, err + } + f.queryBackendClient = c + return c.Service(), nil +} + +func (f *Pyroscope) initRecordingRulesClient() (services.Service, error) { + if err := f.Cfg.CompactionWorker.MetricsExporter.Validate(); err != nil { + return nil, err + } + if !f.Cfg.CompactionWorker.MetricsExporter.Enabled || + f.Cfg.CompactionWorker.MetricsExporter.RulesSource.ClientAddress == "" { + return nil, nil + } + c, err := recordingrulesclient.NewClient(f.Cfg.CompactionWorker.MetricsExporter.RulesSource.ClientAddress, f.logger, f.auth) + if err != nil { + return nil, err + } + f.recordingRulesClient = c + return c.Service(), nil +} + +func (f *Pyroscope) initSymbolizer() (services.Service, error) { + + sym, err := symbolizer.New( + f.logger, + f.Cfg.Symbolizer, + f.reg, + f.storageBucket, + f.Overrides, + ) + if err != nil { + return nil, fmt.Errorf("failed to create symbolizer: %w", err) + } + + f.symbolizer = sym + + return nil, nil +} + +func (f *Pyroscope) initQueryDiagnosticsStore() (services.Service, error) { + if f.storageBucket == nil { + return nil, nil + } + f.queryDiagnosticsStore = diagnostics.NewStore( + log.With(f.logger, "component", "query-diagnostics-store"), + f.storageBucket, + ) + return f.queryDiagnosticsStore, nil +} + +func (f *Pyroscope) initQueryDiagnosticsAdmin() (services.Service, error) { + if f.queryDiagnosticsStore == nil { + return nil, nil + } + f.queryDiagnosticsAdmin = querydiagnostics.New( + log.With(f.logger, "component", "query-diagnostics-admin"), + f.metastoreClient, + f.queryDiagnosticsStore, + ) + f.API.RegisterQueryDiagnosticsAdmin(f.queryDiagnosticsAdmin) + return nil, nil +} + +func (f *Pyroscope) initPlacementAgent() (services.Service, error) { + f.placementAgent = placement.NewAgent( + f.logger, + f.reg, + f.Cfg.AdaptivePlacement, + f.Overrides, + f.adaptivePlacementStore(), + ) + return f.placementAgent.Service(), nil +} + +func (f *Pyroscope) initPlacementManager() (services.Service, error) { + f.placementManager = placement.NewManager( + f.logger, + f.reg, + f.Cfg.AdaptivePlacement, + f.Overrides, + f.adaptivePlacementStore(), + ) + return f.placementManager.Service(), nil +} + +func (f *Pyroscope) adaptivePlacementStore() placement.Store { + if slices.Contains(f.Cfg.Target, All) { + // Disables sharding in all-in-one scenario. + return placement.NewEmptyStore() + } + return placement.NewStore(f.storageBucket) +} + +func (f *Pyroscope) initHealthServer() (services.Service, error) { + f.healthServer = grpchealth.NewServer() + return nil, nil +} + +func (f *Pyroscope) grpcClientInterceptors() []grpc.UnaryClientInterceptor { + requestDuration := util.RegisterOrGet(f.reg, prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "grpc_client", + Name: "request_duration_seconds", + Help: "Time (in seconds) spent waiting for gRPC response.", + Buckets: prometheus.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"method", "status_code"})) + + return []grpc.UnaryClientInterceptor{ + middleware.UnaryClientInstrumentInterceptor(requestDuration, middleware.ReportGRPCStatusOption), + } +} diff --git a/pkg/pyroscope/pyroscope.go b/pkg/pyroscope/pyroscope.go new file mode 100644 index 0000000000..3a256b73b8 --- /dev/null +++ b/pkg/pyroscope/pyroscope.go @@ -0,0 +1,1030 @@ +package pyroscope + +import ( + "bytes" + "context" + "errors" + "flag" + "fmt" + "io" + "net/http" + "os" + "runtime" + "runtime/debug" + "slices" + "sort" + "strings" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/gorilla/mux" + "github.com/grafana/dskit/flagext" + "github.com/grafana/dskit/grpcutil" + "github.com/grafana/dskit/kv/memberlist" + dslog "github.com/grafana/dskit/log" + "github.com/grafana/dskit/modules" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/runtimeconfig" + "github.com/grafana/dskit/server" + "github.com/grafana/dskit/services" + "github.com/grafana/dskit/signals" + "github.com/grafana/dskit/spanlogger" + "github.com/grafana/pyroscope-go" + grpcgw "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/version" + "github.com/samber/lo" + "google.golang.org/grpc/health" + + "github.com/grafana/pyroscope/v2/pkg/api" + apiversion "github.com/grafana/pyroscope/v2/pkg/api/version" + "github.com/grafana/pyroscope/v2/pkg/cfg" + "github.com/grafana/pyroscope/v2/pkg/compactionworker" + "github.com/grafana/pyroscope/v2/pkg/compactor" + "github.com/grafana/pyroscope/v2/pkg/debuginfo" + "github.com/grafana/pyroscope/v2/pkg/distributor" + "github.com/grafana/pyroscope/v2/pkg/distributor/writepath" + "github.com/grafana/pyroscope/v2/pkg/embedded/grafana" + "github.com/grafana/pyroscope/v2/pkg/frontend" + asyncquery "github.com/grafana/pyroscope/v2/pkg/frontend/async" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath/queryfrontend/diagnostics" + "github.com/grafana/pyroscope/v2/pkg/ingester" + "github.com/grafana/pyroscope/v2/pkg/metastore" + metastoreadmin "github.com/grafana/pyroscope/v2/pkg/metastore/admin" + metastoreclient "github.com/grafana/pyroscope/v2/pkg/metastore/client" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/operations/v2/querydiagnostics" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/querier" + "github.com/grafana/pyroscope/v2/pkg/querier/worker" + "github.com/grafana/pyroscope/v2/pkg/querybackend" + querybackendclient "github.com/grafana/pyroscope/v2/pkg/querybackend/client" + "github.com/grafana/pyroscope/v2/pkg/scheduler" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerdiscovery" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter" + segmentwriterclient "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client" + placement "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" + "github.com/grafana/pyroscope/v2/pkg/settings" + recordingrulesclient "github.com/grafana/pyroscope/v2/pkg/settings/recording/client" + "github.com/grafana/pyroscope/v2/pkg/storegateway" + "github.com/grafana/pyroscope/v2/pkg/symbolizer" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/tracing" + "github.com/grafana/pyroscope/v2/pkg/usagestats" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/cli" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" + "github.com/grafana/pyroscope/v2/pkg/validation/exporter" +) + +type Config struct { + Target flagext.StringSliceCSV `yaml:"target,omitempty"` + API api.Config `yaml:"api"` + Server server.Config `yaml:"server,omitempty"` + Metastore metastore.Config `yaml:"metastore"` + Distributor distributor.Config `yaml:"distributor,omitempty"` + Frontend frontend.Config `yaml:"frontend,omitempty"` + QueryBackend querybackend.Config `yaml:"query_backend"` + AdaptivePlacement placement.Config `yaml:"adaptive_placement"` + Symbolizer symbolizer.Config `yaml:"symbolizer"` + Worker worker.Config `yaml:"frontend_worker"` + LimitsConfig validation.Limits `yaml:"limits"` + SegmentWriter segmentwriter.Config `yaml:"segment_writer"` + MemberlistKV memberlist.KVConfig `yaml:"memberlist"` + PhlareDB phlaredb.Config `yaml:"pyroscopedb,omitempty"` + Tracing tracing.Config `yaml:"tracing"` + OverridesExporter exporter.Config `yaml:"overrides_exporter"` + RuntimeConfig runtimeconfig.Config `yaml:"runtime_config"` + CompactionWorker compactionworker.Config `yaml:"compaction_worker"` + TenantSettings settings.Config `yaml:"tenant_settings"` + + Storage StorageConfig `yaml:"storage"` + SelfProfiling SelfProfilingConfig `yaml:"self_profiling,omitempty"` + + MultitenancyEnabled bool `yaml:"multitenancy_enabled,omitempty"` + Analytics usagestats.Config `yaml:"analytics"` + ShowBanner bool `yaml:"show_banner,omitempty"` + ShutdownDelay time.Duration `yaml:"shutdown_delay,omitempty"` + ArchitectureStorage StorageLayer `yaml:"architecture_storage,omitempty"` + + AdminServer AdminServerConfig `yaml:"admin_server,omitempty"` + EmbeddedGrafana grafana.Config `yaml:"embedded_grafana,omitempty"` + + ConfigFile string `yaml:"-"` + ConfigExpandEnv bool `yaml:"-"` + + DebugInfo debuginfo.Config `yaml:"-"` + SetFlags map[string]struct{} `yaml:"-"` + + // Legacy v1 + Querier querier.Config `yaml:"querier,omitempty"` + Ingester ingester.Config `yaml:"ingester,omitempty"` + Compactor compactor.Config `yaml:"compactor"` + StoreGateway storegateway.Config `yaml:"store_gateway,omitempty"` + QueryScheduler scheduler.Config `yaml:"query_scheduler"` +} + +func newDefaultConfig() *Config { + defaultConfig := &Config{} + defaultFS := flag.NewFlagSet("", flag.PanicOnError) + defaultConfig.RegisterFlags(defaultFS) + return defaultConfig +} + +type StorageConfig struct { + Bucket objstoreclient.Config `yaml:",inline"` +} + +func (c *StorageConfig) RegisterFlags(f *flag.FlagSet) { + c.Bucket.RegisterFlagsWithPrefix("storage.", f) +} + +// AdminServerMode controls how the optional admin HTTP server behaves. +type AdminServerMode string + +const ( + // AdminServerDisabled is the default: no secondary server, all routes on the main port. + AdminServerDisabled AdminServerMode = "disabled" + // AdminServerAdditional starts the admin server and registers operational + // routes on both ports (main port keeps them too). + AdminServerAdditional AdminServerMode = "additional" + // AdminServerExclusive starts the admin server and moves operational routes + // exclusively to it, removing them from the main port. + AdminServerExclusive AdminServerMode = "exclusive" +) + +func (m AdminServerMode) IsEnabled() bool { + return m == AdminServerAdditional || m == AdminServerExclusive +} + +func (m *AdminServerMode) String() string { return string(*m) } +func (m *AdminServerMode) Set(v string) error { + switch AdminServerMode(v) { + case AdminServerDisabled, AdminServerAdditional, AdminServerExclusive: + *m = AdminServerMode(v) + return nil + default: + return fmt.Errorf("invalid admin-server mode %q: must be disabled, additional, or exclusive", v) + } +} + +// AdminServerConfig configures an optional secondary HTTP server that exposes +// metrics, pprof/debug and admin/ops endpoints on a separate port so they can be +// firewalled independently from the public-facing API port. +type AdminServerConfig struct { + Mode AdminServerMode `yaml:"mode"` + HTTPAddress string `yaml:"http_listen_address"` + HTTPPort int `yaml:"http_listen_port"` +} + +func (c *AdminServerConfig) RegisterFlags(f *flag.FlagSet) { + c.Mode = AdminServerDisabled + f.Var(&c.Mode, "admin-server.mode", + "Controls the admin server for metrics, pprof and admin endpoints. "+ + "'disabled': all routes on the main port (default). "+ + "'additional': admin server started, operational routes served on both ports. "+ + "'exclusive': admin server started, operational routes removed from main port.") + f.StringVar(&c.HTTPAddress, "admin-server.http-listen-address", "localhost", + "Address for the admin HTTP server. Defaults to localhost so the port is not exposed externally. Use :: or 0.0.0.0 to listen on all interfaces.") + f.IntVar(&c.HTTPPort, "admin-server.http-listen-port", 4042, + "Port for the admin HTTP server (metrics, pprof, admin).") +} + +type SelfProfilingConfig struct { + DisablePush bool `yaml:"disable_push,omitempty"` + MutexProfileFraction int `yaml:"mutex_profile_fraction,omitempty"` + BlockProfileRate int `yaml:"block_profile_rate,omitempty"` + UseK6Middleware bool `yaml:"use_k6_middleware,omitempty"` + TenantID string `yaml:"tenant_id,omitempty"` +} + +func (c *SelfProfilingConfig) RegisterFlags(f *flag.FlagSet) { + // these are values that worked well in OG Pyroscope Cloud without adding much overhead + f.IntVar(&c.MutexProfileFraction, "self-profiling.mutex-profile-fraction", 5, "") + f.IntVar(&c.BlockProfileRate, "self-profiling.block-profile-rate", 5, "") + f.BoolVar( + &c.DisablePush, + "self-profiling.disable-push", + false, + "When running in single binary (--target=all) Pyroscope will push (Go SDK) profiles to itself. Set to true to disable self-profiling.", + ) + f.BoolVar( + &c.UseK6Middleware, + "self-profiling.use-k6-middleware", + false, + "Read k6 labels from request headers and set them as dynamic profile tags.", + ) + f.StringVar( + &c.TenantID, + "self-profiling.tenant-id", + "", + "Tenant ID for self-profiling data. If empty, no tenant header is sent (anonymous).", + ) +} + +func (c *Config) RegisterFlags(f *flag.FlagSet) { + c.RegisterFlagsWithContext(f) +} + +// RegisterFlagsWithContext registers flag. +func (c *Config) RegisterFlagsWithContext(f *flag.FlagSet) { + // Set the default module list to 'all' + c.Target = []string{All} + f.StringVar(&c.ConfigFile, "config.file", "", "yaml file to load") + f.Var(&c.Target, "target", "Comma-separated list of Pyroscope modules to load. "+ + "The alias 'all' can be used in the list to load a number of core modules and will enable single-binary mode. ") + f.BoolVar( + &c.MultitenancyEnabled, + "auth.multitenancy-enabled", + false, + "When set to true, incoming HTTP requests must specify tenant ID in HTTP X-Scope-OrgId header. When set to false, tenant ID anonymous is used instead.", + ) + f.BoolVar( + &c.ConfigExpandEnv, + "config.expand-env", + false, + "Expands ${var} in config according to the values of the environment variables.", + ) + f.BoolVar(&c.ShowBanner, "config.show_banner", true, "Prints the application banner at startup.") + f.DurationVar(&c.ShutdownDelay, "shutdown-delay", 0, "Wait time before shutting down after a termination signal.") + c.ArchitectureStorage = V1V2Dual + f.Var(&c.ArchitectureStorage, "architecture.storage", "Storage architecture layer. Use 'v1' to use legacy ingester-based storage, 'v2' for new storage, and 'v1-v2-dual' to use new storage while being able to query old data.") + + c.registerServerFlagsWithChangedDefaultValues(f) + c.MemberlistKV.RegisterFlags(f) + c.PhlareDB.RegisterFlags(f) + c.Tracing.RegisterFlags(f) + c.SelfProfiling.RegisterFlags(f) + c.RuntimeConfig.RegisterFlags(f) + c.Analytics.RegisterFlags(f) + c.LimitsConfig.RegisterFlags(f) + c.API.RegisterFlags(f) + c.AdminServer.RegisterFlags(f) + c.EmbeddedGrafana.RegisterFlags(f) + c.TenantSettings.RegisterFlags(f) + + // Legacy flags + c.StoreGateway.RegisterFlags(f, util.Logger) + c.Querier.RegisterFlags(f) + c.Compactor.RegisterFlags(f, log.NewLogfmtLogger(os.Stderr)) + markV1StorageOnlyFlagUsage(f) +} + +const v1StorageOnlyFlagUsagePrefix = "[v1 storage only] " + +var v1StorageOnlyFlagPrefixes = []string{ + "compactor.", + "ingester.", + "pyroscopedb.", +} + +func markV1StorageOnlyFlagUsage(f *flag.FlagSet) { + f.VisitAll(func(flag *flag.Flag) { + for _, prefix := range v1StorageOnlyFlagPrefixes { + if strings.HasPrefix(flag.Name, prefix) { + if !strings.HasPrefix(flag.Usage, v1StorageOnlyFlagUsagePrefix) { + flag.Usage = v1StorageOnlyFlagUsagePrefix + flag.Usage + } + return + } + } + }) +} + +func (c *Config) RecordSetFlag(name string) { + if c.SetFlags == nil { + c.SetFlags = map[string]struct{}{} + } + c.SetFlags[name] = struct{}{} +} + +func (c *Config) setV1StorageOnlyFlags() []string { + var flags []string + for flagName := range c.SetFlags { + for _, prefix := range v1StorageOnlyFlagPrefixes { + if strings.HasPrefix(flagName, prefix) { + flags = append(flags, flagName) + break + } + } + } + sort.Strings(flags) + return flags +} + +func (c *Config) warnAboutV1StorageOnlyFlags(logger log.Logger) { + if c.ArchitectureStorage != V2 { + return + } + for _, flagName := range c.setV1StorageOnlyFlags() { + level.Warn(logger).Log( + "msg", "v1 storage only flag is set while using v2 storage architecture; flag has no effect", + "flag", flagName, + ) + } +} + +// registerServerFlagsWithChangedDefaultValues registers *Config.Server flags, but overrides some defaults set by the dskit package. +func (c *Config) registerServerFlagsWithChangedDefaultValues(fs *flag.FlagSet) { + throwaway := flag.NewFlagSet("throwaway", flag.PanicOnError) + + // Register to throwaway flags first. Default values are remembered during registration and cannot be changed, + // but we can take values from throwaway flag set and reregister into supplied flags with new default values. + c.Storage.RegisterFlags(throwaway) + c.Server.RegisterFlags(throwaway) + c.Distributor.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) + c.Frontend.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) + c.Worker.RegisterFlags(throwaway) + c.OverridesExporter.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) + c.Metastore.RegisterFlags(throwaway) + c.SegmentWriter.RegisterFlags(throwaway) + c.QueryBackend.RegisterFlags(throwaway) + c.CompactionWorker.RegisterFlags(throwaway) + c.AdaptivePlacement.RegisterFlags(throwaway) + c.LimitsConfig.WritePathOverrides.RegisterFlags(throwaway) + c.LimitsConfig.ReadPathOverrides.RegisterFlags(throwaway) + c.LimitsConfig.AdaptivePlacementLimits.RegisterFlags(throwaway) + c.LimitsConfig.Retention.RegisterFlags(throwaway) + c.LimitsConfig.RecordingRules.RegisterFlags(throwaway) + c.LimitsConfig.Symbolizer.RegisterFlags(throwaway) + c.Symbolizer.RegisterFlags(throwaway) + c.DebugInfo.RegisterFlags(throwaway) + + // Legacy modules + c.QueryScheduler.RegisterFlags(throwaway, log.NewLogfmtLogger(os.Stderr)) + c.Ingester.RegisterFlags(throwaway) + + overrides := map[string]string{ + "server.http-listen-port": "4040", + "server.grpc-max-recv-msg-size-bytes": "104857600", + "server.grpc-max-send-msg-size-bytes": "104857600", + "server.grpc.keepalive.min-time-between-pings": "1s", + "segment-writer.grpc-client-config.connect-timeout": "1s", + "segment-writer.num-tokens": "4", + "segment-writer.heartbeat-timeout": "1m", + "segment-writer.unregister-on-shutdown": "false", + "segment-writer.min-ready-duration": "30s", + "storage.s3.http.idle-conn-timeout": "10m", + "storage.s3.max-idle-connections-per-host": "1000", + "storage.gcs.http.idle-conn-timeout": "10m", + "storage.gcs.max-idle-connections-per-host": "1000", + "compaction-worker.metrics-exporter.rules-source.static": "[]", + // Legacy overrides + "distributor.replication-factor": "1", + "query-scheduler.service-discovery-mode": schedulerdiscovery.ModeRing, + } + + throwaway.VisitAll(func(f *flag.Flag) { + if v, ok := overrides[f.Name]; ok { + // Ignore errors when setting new values. We have a test to verify that it works. + _ = f.Value.Set(v) + } + fs.Var(f.Value, f.Name, f.Usage) + }) +} + +func (c *Config) Validate() error { + if len(c.Target) == 0 { + return errors.New("no modules specified") + } + + if err := c.Frontend.Validate(); err != nil { + return err + } + + if err := c.Worker.Validate(util.Logger); err != nil { + return err + } + + if err := c.LimitsConfig.Validate(); err != nil { + return err + } + + if err := c.QueryScheduler.Validate(); err != nil { + return err + } + + if err := c.Ingester.Validate(); err != nil { + return err + } + + if err := c.StoreGateway.Validate(c.LimitsConfig); err != nil { + return err + } + + if err := c.OverridesExporter.Validate(); err != nil { + return err + } + + if c.usesV1Storage() { + if err := c.Compactor.Validate(c.PhlareDB.MaxBlockDuration); err != nil { + return err + } + } + + if err := c.Storage.Bucket.Validate(util.Logger); err != nil { + return err + } + + if err := c.TenantSettings.Validate(); err != nil { + return err + } + + // Validate that V2 storage layers have a storage backend configured. + if c.ArchitectureStorage != V1 && c.Storage.Bucket.Backend == objstoreclient.None { + return fmt.Errorf("storage.backend is required for %s storage layer", c.ArchitectureStorage) + } + + // Validate that write-path matches the storage layer. + storageLayerRequirements := map[StorageLayer]writepath.WritePath{ + V1: writepath.IngesterPath, + V2: writepath.SegmentWriterPath, + } + for layer, path := range storageLayerRequirements { + if layer == c.ArchitectureStorage && c.LimitsConfig.WritePathOverrides.WritePath != path { + return fmt.Errorf("write-path=%s is required for %s storage layer", path, layer) + } + } + + return nil +} + +func (c *Config) usesV1Storage() bool { + return c.ArchitectureStorage == V1 || c.ArchitectureStorage == V1V2Dual +} + +func (c *Config) ApplyDynamicConfig() cfg.Source { + c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store = "memberlist" + c.SegmentWriter.LifecyclerConfig.RingConfig.KVStore.Store = "memberlist" + c.Distributor.DistributorRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store + c.OverridesExporter.Ring.Ring.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store + c.Frontend.QuerySchedulerDiscovery.SchedulerRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store + c.Worker.QuerySchedulerDiscovery.SchedulerRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store + c.QueryScheduler.ServiceDiscovery.SchedulerRing.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store + c.StoreGateway.ShardingRing.Ring.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store + c.Compactor.ShardingRing.Common.KVStore.Store = c.Ingester.LifecyclerConfig.RingConfig.KVStore.Store + + return func(dst cfg.Cloneable) error { + return nil + } +} + +func (c *Config) Clone() flagext.Registerer { + return func(c Config) *Config { + return &c + }(*c) +} + +type Pyroscope struct { + Cfg Config + reg prometheus.Registerer + logger *logger + tracer io.Closer + + ModuleManager *modules.Manager + serviceMap map[string]services.Service + deps map[string][]string + + API *api.API + Server *server.Server + adminRouter *mux.Router + SignalHandler *signals.Handler + MemberlistKV *memberlist.KVInitService + ingesterRing *ring.Ring + usageReport *usagestats.Reporter + RuntimeConfig *runtimeconfig.Manager + Overrides *validation.Overrides + Compactor *compactor.MultitenantCompactor + admin api.AdminService + versions *apiversion.Service + serviceManager *services.Manager + + TenantLimits validation.TenantLimits + + storageBucket phlareobj.Bucket + + grpcGatewayMux *grpcgw.ServeMux + + auth connect.Option + frontend *frontend.Frontend + distributor *distributor.Distributor + + segmentWriter *segmentwriter.SegmentWriterService + segmentWriterClient *segmentwriterclient.Client + segmentWriterRing *ring.Ring + placementAgent *placement.Agent + placementManager *placement.Manager + metastore *metastore.Metastore + metastoreClient *metastoreclient.Client + metastoreAdmin *metastoreadmin.Admin + queryFrontend *queryfrontend.QueryFrontend + queryBackendClient *querybackendclient.Client + compactionWorker *compactionworker.Worker + healthServer *health.Server + recordingRulesClient *recordingrulesclient.Client + symbolizer *symbolizer.Symbolizer + queryDiagnosticsStore *diagnostics.Store + queryDiagnosticsAdmin *querydiagnostics.Admin + asyncQueryStore *asyncquery.Store + + // legacy modules. + ingester *ingester.Ingester +} + +func New(cfg Config) (*Pyroscope, error) { + logger := initLogger(cfg.Server.LogFormat, cfg.Server.LogLevel) + cfg.Server.Log = logger + cfg.warnAboutV1StorageOnlyFlags(logger) + usagestats.Edition("oss") + + phlare := &Pyroscope{ + Cfg: cfg, + logger: logger, + reg: prometheus.DefaultRegisterer, + } + if err := cfg.Validate(); err != nil { + return nil, err + } + if err := phlare.setupModuleManager(); err != nil { + return nil, err + } + + runtime.SetMutexProfileFraction(cfg.SelfProfiling.MutexProfileFraction) + runtime.SetBlockProfileRate(cfg.SelfProfiling.BlockProfileRate) + + if cfg.Tracing.Enabled { + name := os.Getenv("OTEL_SERVICE_NAME") + if name == "" { + name = os.Getenv("JAEGER_SERVICE_NAME") + } + if name == "" { + name = fmt.Sprintf("pyroscope-%s", cfg.Target) + } + trace, err := initTracing(name, logger, cfg.Tracing.ProfilingEnabled) + if err != nil { + level.Error(logger).Log("msg", "error in initializing tracing. tracing will not be enabled", "err", err) + } + phlare.tracer = trace + } + + phlare.auth = connect.WithInterceptors(tenant.NewAuthInterceptor(cfg.MultitenancyEnabled)) + phlare.Cfg.API.HTTPAuthMiddleware = httputil.AuthenticateUser(cfg.MultitenancyEnabled) + phlare.Cfg.API.GrpcAuthMiddleware = phlare.auth + + return phlare, nil +} + +func (f *Pyroscope) setupModuleManager() error { + mm := modules.NewManager(f.logger) + + mm.RegisterModule(Storage, f.initStorage, modules.UserInvisibleModule) + mm.RegisterModule(GRPCGateway, f.initGRPCGateway, modules.UserInvisibleModule) + mm.RegisterModule(MemberlistKV, f.initMemberlistKV, modules.UserInvisibleModule) + mm.RegisterModule(IngesterRing, f.initIngesterRing, modules.UserInvisibleModule) + mm.RegisterModule(RuntimeConfig, f.initRuntimeConfig, modules.UserInvisibleModule) + mm.RegisterModule(Overrides, f.initOverrides, modules.UserInvisibleModule) + mm.RegisterModule(OverridesExporter, f.initOverridesExporter) + mm.RegisterModule(Server, f.initServer, modules.UserInvisibleModule) + mm.RegisterModule(AdminServer, f.initAdminServer, modules.UserInvisibleModule) + mm.RegisterModule(API, f.initAPI, modules.UserInvisibleModule) + mm.RegisterModule(Version, f.initVersion, modules.UserInvisibleModule) + mm.RegisterModule(Metastore, f.initMetastore) + mm.RegisterModule(MetastoreClient, f.initMetastoreClient, modules.UserInvisibleModule) + mm.RegisterModule(MetastoreAdmin, f.initMetastoreAdmin, modules.UserInvisibleModule) + mm.RegisterModule(Distributor, f.initDistributor) + mm.RegisterModule(PlacementAgent, f.initPlacementAgent, modules.UserInvisibleModule) + mm.RegisterModule(PlacementManager, f.initPlacementManager, modules.UserInvisibleModule) + mm.RegisterModule(SegmentWriter, f.initSegmentWriter) + mm.RegisterModule(SegmentWriterRing, f.initSegmentWriterRing, modules.UserInvisibleModule) + mm.RegisterModule(SegmentWriterClient, f.initSegmentWriterClient, modules.UserInvisibleModule) + mm.RegisterModule(CompactionWorker, f.initCompactionWorker) + mm.RegisterModule(UsageReport, f.initUsageReport) + mm.RegisterModule(QueryFrontend, f.initQueryFrontend) + mm.RegisterModule(QueryBackend, f.initQueryBackend) + mm.RegisterModule(QueryBackendClient, f.initQueryBackendClient, modules.UserInvisibleModule) + mm.RegisterModule(Symbolizer, f.initSymbolizer) + mm.RegisterModule(Admin, f.initAdmin) + mm.RegisterModule(All, nil) + mm.RegisterModule(TenantSettings, f.initTenantSettings) + mm.RegisterModule(AdHocProfiles, f.initAdHocProfiles) + mm.RegisterModule(EmbeddedGrafana, f.initEmbeddedGrafana) + mm.RegisterModule(FeatureFlags, f.initFeatureFlags) + mm.RegisterModule(HealthServer, f.initHealthServer, modules.UserInvisibleModule) + mm.RegisterModule(RecordingRulesClient, f.initRecordingRulesClient, modules.UserInvisibleModule) + mm.RegisterModule(QueryDiagnosticsStore, f.initQueryDiagnosticsStore, modules.UserInvisibleModule) + mm.RegisterModule(QueryDiagnosticsAdmin, f.initQueryDiagnosticsAdmin, modules.UserInvisibleModule) + mm.RegisterModule(AsyncQueryStore, f.initAsyncQueryStore, modules.UserInvisibleModule) + + // Add dependencies + deps := map[string][]string{ + All: { + Metastore, + Distributor, + SegmentWriter, + CompactionWorker, + QueryFrontend, + QueryBackend, + Admin, + TenantSettings, + AdHocProfiles, + }, + + Server: {GRPCGateway, HealthServer}, + AdminServer: {}, + API: {Server, AdminServer}, + Metastore: {Overrides, API, MetastoreClient, Storage, PlacementManager}, + MetastoreAdmin: {API, MetastoreClient}, + Distributor: {Overrides, SegmentWriterClient, API, UsageReport, Storage, IngesterRing}, + PlacementAgent: {Overrides, API, Storage}, + PlacementManager: {Overrides, API, Storage}, + SegmentWriter: {Overrides, API, MemberlistKV, Storage, UsageReport, MetastoreClient}, + SegmentWriterRing: {Overrides, API, MemberlistKV}, + SegmentWriterClient: {Overrides, API, SegmentWriterRing, PlacementAgent}, + CompactionWorker: {Overrides, API, Storage, MetastoreClient, RecordingRulesClient}, + QueryFrontend: {OverridesExporter, API, MemberlistKV, UsageReport, Version, FeatureFlags, MetastoreClient, QueryBackendClient, Symbolizer, QueryDiagnosticsStore, AsyncQueryStore}, + QueryBackend: {Overrides, API, Storage, QueryBackendClient}, + QueryDiagnosticsStore: {Storage}, + QueryDiagnosticsAdmin: {QueryDiagnosticsStore, API, MetastoreClient}, + Symbolizer: {Overrides, Storage}, + UsageReport: {Storage, MemberlistKV}, + Overrides: {RuntimeConfig}, + OverridesExporter: {Overrides, MemberlistKV}, + RuntimeConfig: {API}, + IngesterRing: {API, MemberlistKV}, + MemberlistKV: {API}, + Admin: {API, Storage, MetastoreAdmin, QueryDiagnosticsAdmin}, + Version: {API, MemberlistKV}, + TenantSettings: {API, Overrides, Storage}, + AdHocProfiles: {API, Overrides, Storage}, + EmbeddedGrafana: {API}, + FeatureFlags: {API}, + AsyncQueryStore: {Storage}, + } + + if f.Cfg.ArchitectureStorage == V1V2Dual || f.Cfg.ArchitectureStorage == V1 { + // add v1 modules if legacy or dual storage mode + mm.RegisterModule(Ingester, f.initIngester) + mm.RegisterModule(Compactor, f.initCompactor) + mm.RegisterModule(Querier, f.initQuerier) + mm.RegisterModule(StoreGateway, f.initStoreGateway) + mm.RegisterModule(QueryScheduler, f.initQueryScheduler) + + legacyModules := map[string][]string{ + Ingester: {Overrides, API, MemberlistKV, Storage, UsageReport, Version}, + Compactor: {API, Storage, Overrides, MemberlistKV, UsageReport}, + QueryScheduler: {Overrides, API, MemberlistKV, UsageReport}, + Querier: {Overrides, API, MemberlistKV, IngesterRing, UsageReport, Version, FeatureFlags}, + StoreGateway: {API, Storage, Overrides, MemberlistKV, UsageReport, Admin, Version}, + } + for k, v := range legacyModules { + deps[k] = v + } + + deps[All] = append(deps[All], Ingester, Compactor, QueryScheduler, Querier, StoreGateway) + } + if f.Cfg.ArchitectureStorage == V1 { + // disable v2 features + f.Cfg.DebugInfo.Enabled = false + + // remove v2 modules if using legacy storage + v2Modules := []string{QueryBackend, SegmentWriter, CompactionWorker, Metastore} + deps[All] = slices.DeleteFunc(deps[All], func(s string) bool { + return slices.Contains(v2Modules, s) + }) + deps[Admin] = []string{API, Storage} + deps[Distributor] = []string{Overrides, API, UsageReport, Storage, IngesterRing} + deps[QueryFrontend] = []string{OverridesExporter, API, MemberlistKV, UsageReport, Version, FeatureFlags} + } + + for mod, targets := range deps { + if err := mm.AddDependency(mod, targets...); err != nil { + return err + } + } + + f.deps = deps + f.ModuleManager = mm + + return nil +} + +// made here https://patorjk.com/software/taag/#p=display&f=Doom&t=grafana%20pyroscope +// also needed to replace all ` with ' +var banner = ` + __ + / _| + __ _ _ __ __ _| |_ __ _ _ __ __ _ _ __ _ _ _ __ ___ ___ ___ ___ _ __ ___ + / _' | '__/ _' | _/ _' | '_ \ / _' | | '_ \| | | | '__/ _ \/ __|/ __/ _ \| '_ \ / _ \ +| (_| | | | (_| | || (_| | | | | (_| | | |_) | |_| | | | (_) \__ \ (_| (_) | |_) | __/ + \__, |_| \__,_|_| \__,_|_| |_|\__,_| | .__/ \__, |_| \___/|___/\___\___/| .__/ \___| + __/ | | | __/ | | | + |___/ |_| |___/ |_| + ` + +func (f *Pyroscope) Run() error { + if f.Cfg.ShowBanner { + _ = cli.GradientBanner(banner, os.Stderr) + } + + serviceMap, err := f.ModuleManager.InitModuleServices(f.Cfg.Target...) + if err != nil { + return err + } + + f.serviceMap = serviceMap + var servs []services.Service + for _, s := range serviceMap { + servs = append(servs, s) + } + + sm, err := services.NewManager(servs...) + if err != nil { + return err + } + f.serviceManager = sm + + f.API.RegisterReadyHandler(f.readyHandler(sm)) + RegisterHealthServer(f.Server.HTTP, grpcutil.WithManager(sm)) + healthy := func() { + level.Info(f.logger).Log("msg", "Pyroscope started", "version", version.Info()) + if os.Getenv("PYROSCOPE_PRINT_ROUTES") != "" { + printRoutes(f.Server.HTTP) + } + + // Start profiling when Pyroscope is ready + if !f.Cfg.SelfProfiling.DisablePush && slices.Contains(f.Cfg.Target, All) { + _, err := pyroscope.Start(pyroscope.Config{ + ApplicationName: "pyroscope", + ServerAddress: fmt.Sprintf("http://%s:%d", "localhost", f.Cfg.Server.HTTPListenPort), + TenantID: f.Cfg.SelfProfiling.TenantID, + Tags: map[string]string{ + "hostname": os.Getenv("HOSTNAME"), + "target": "all", + "service_git_ref": serviceGitRef(), + "service_repository": "https://github.com/grafana/pyroscope", + }, + ProfileTypes: []pyroscope.ProfileType{ + pyroscope.ProfileCPU, + pyroscope.ProfileAllocObjects, + pyroscope.ProfileAllocSpace, + pyroscope.ProfileInuseObjects, + pyroscope.ProfileInuseSpace, + pyroscope.ProfileGoroutines, + pyroscope.ProfileMutexCount, + pyroscope.ProfileMutexDuration, + pyroscope.ProfileBlockCount, + pyroscope.ProfileBlockDuration, + }, + }) + if err != nil { + level.Warn(f.logger).Log("msg", "failed to start pyroscope", "err", err) + } + } + } + + // only query-frontend, query-backend, querier and target all should register the UI + if slices.Contains(f.Cfg.Target, All) || + slices.Contains(f.Cfg.Target, QueryFrontend) || + slices.Contains(f.Cfg.Target, QueryBackend) || + slices.Contains(f.Cfg.Target, Querier) { + + if err = f.API.RegisterCatchAll(); err != nil { + return err + } + } else { + f.API.RegisterRedirectToAdmin() + } + + serviceFailed := func(service services.Service) { + // if any service fails, stop entire Pyroscope + sm.StopAsync() + + // let's find out which module failed + for m, s := range serviceMap { + if s == service { + if service.FailureCase() == modules.ErrStopProcess { + level.Info(f.logger). + Log("msg", "received stop signal via return error", "module", m, "error", service.FailureCase()) + } else { + level.Error(f.logger).Log("msg", "module failed", "module", m, "error", service.FailureCase()) + } + return + } + } + + level.Error(f.logger).Log("msg", "module failed", "module", "unknown", "error", service.FailureCase()) + } + + sm.AddListener(services.NewManagerListener(healthy, f.stopped, serviceFailed)) + + // Setup signal handler. If signal arrives, we stop the manager, which stops all the services. + f.SignalHandler = signals.NewHandler(f.Server.Log) + go func() { + f.SignalHandler.Loop() + if f.Cfg.ShutdownDelay > 0 { + level.Info(f.logger).Log("msg", "shutdown delayed", "delay", f.Cfg.ShutdownDelay) + time.Sleep(f.Cfg.ShutdownDelay) + } + sm.StopAsync() + }() + + // Start all services. This can really only fail if some service is already + // in other state than New, which should not be the case. + err = sm.StartAsync(context.Background()) + if err == nil { + // Wait until service manager stops. It can stop in two ways: + // 1) Signal is received and manager is stopped. + // 2) Any service fails. + err = sm.AwaitStopped(context.Background()) + } + if f.versions != nil { + f.versions.Shutdown() + } + // If there is no error yet (= service manager started and then stopped without problems), + // but any service failed, report that failure as an error to caller. + if err == nil { + if failed := sm.ServicesByState()[services.Failed]; len(failed) > 0 { + for _, f := range failed { + if f.FailureCase() != modules.ErrStopProcess { + // Details were reported via failure listener before + err = errors.New("failed services") + break + } + } + } + } + + return err +} + +func (f *Pyroscope) readyHandler(sm *services.Manager) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !sm.IsHealthy() { + msg := bytes.Buffer{} + msg.WriteString("Some services are not Running:\n") + + byState := map[services.State][]string{} + for name, svc := range f.serviceMap { + state := svc.State() + byState[state] = append(byState[state], name) + } + + states := lo.Keys(byState) + sort.Slice(states, func(i, j int) bool { return states[i] < states[j] }) + + for _, st := range states { + sort.Strings(byState[st]) + msg.WriteString(fmt.Sprintf("%v: %v\n", st, byState[st])) + } + + http.Error(w, msg.String(), http.StatusServiceUnavailable) + return + } + + if f.metastore != nil { + if err := f.metastore.CheckReady(r.Context()); err != nil { + http.Error(w, "Metastore not ready: "+err.Error(), http.StatusServiceUnavailable) + return + } + } + + if f.ingester != nil { + if err := f.ingester.CheckReady(r.Context()); err != nil { + http.Error(w, "Ingester not ready: "+err.Error(), http.StatusServiceUnavailable) + return + } + } + + if f.segmentWriter != nil { + if err := f.segmentWriter.CheckReady(r.Context()); err != nil { + http.Error(w, "Segment Writer not ready: "+err.Error(), http.StatusServiceUnavailable) + return + } + } + + if f.frontend != nil { + if err := f.frontend.CheckReady(r.Context()); err != nil { + http.Error(w, "Query Frontend not ready: "+err.Error(), http.StatusServiceUnavailable) + return + } + } + + if f.distributor != nil { + if err := f.distributor.CheckReady(r.Context()); err != nil { + http.Error(w, "Distributor not ready: "+err.Error(), http.StatusServiceUnavailable) + return + } + } + + httputil.WriteTextResponse(w, "ready") + } +} + +func (f *Pyroscope) Stop() func(context.Context) error { + if f.serviceManager == nil { + return func(context.Context) error { return nil } + } + f.serviceManager.StopAsync() + return f.serviceManager.AwaitStopped +} + +func (f *Pyroscope) stopped() { + level.Info(f.logger).Log("msg", "Pyroscope stopped") + if f.tracer != nil { + if err := f.tracer.Close(); err != nil { + level.Error(f.logger).Log("msg", "error closing tracing", "err", err) + } + } + if err := f.logger.w.Close(); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "error closing log writer: %v\n", err) + } +} + +func initLogger(logFormat string, logLevel dslog.Level) *logger { + w := util.NewAsyncWriter(os.Stderr, // Flush after: + 256<<10, 20, // 256KiB buffer is full (keep 20 buffers). + 1<<10, // 1K writes or 100ms. + 100*time.Millisecond, + ) + + // Use UTC timestamps and skip 5 stack frames. + l := dslog.NewGoKitWithWriter(logFormat, w) + l = log.With(l, "ts", log.DefaultTimestampUTC, "caller", spanlogger.Caller(5)) + + // Must put the level filter last for efficiency. + l = level.NewFilter(l, logLevel.Option) + + return &logger{w: w, Logger: l} +} + +type logger struct { + w io.WriteCloser + log.Logger +} + +func (f *Pyroscope) initAPI() (services.Service, error) { + a, err := api.New(f.Cfg.API, f.Server, f.grpcGatewayMux, f.Server.Log) + if err != nil { + return nil, err + } + if f.adminRouter != nil { + a.SetAdminRouter(f.adminRouter, string(f.Cfg.AdminServer.Mode)) + } + f.API = a + + if err := f.API.RegisterAPI(f.statusService()); err != nil { + return nil, err + } + + return nil, nil +} + +func (f *Pyroscope) initVersion() (services.Service, error) { + var err error + f.versions, err = apiversion.New(f.Cfg.Distributor.DistributorRing, f.logger, f.reg) + if err != nil { + return nil, err + } + f.API.RegisterVersion(f.versions) + return f.versions, nil +} + +func printRoutes(r *mux.Router) { + err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { + path, err := route.GetPathRegexp() + if err != nil { + fmt.Printf("failed to get path regexp %s\n", err) + return nil + } + method, err := route.GetMethods() + if err != nil { + method = []string{"*"} + } + fmt.Printf("%s %s\n", strings.Join(method, ","), path) + return nil + }) + if err != nil { + fmt.Printf("failed to walk routes %s\n", err) + } +} + +// serviceGitRef attempts to find the git revision of the service. Default to HEAD. +func serviceGitRef() string { + if version.Revision != "" { + return version.Revision + } + buildInfo, ok := debug.ReadBuildInfo() + if ok { + for _, setting := range buildInfo.Settings { + if setting.Key == "vcs.revision" { + return setting.Value + } + } + } + return "HEAD" +} diff --git a/pkg/pyroscope/pyroscope_test.go b/pkg/pyroscope/pyroscope_test.go new file mode 100644 index 0000000000..e7816d5963 --- /dev/null +++ b/pkg/pyroscope/pyroscope_test.go @@ -0,0 +1,298 @@ +package pyroscope + +import ( + "bytes" + "context" + "flag" + "io" + "slices" + "strings" + "testing" + + "github.com/go-kit/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + statusv1 "github.com/grafana/pyroscope/api/gen/proto/go/status/v1" + configpkg "github.com/grafana/pyroscope/v2/pkg/cfg" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" +) + +func TestFlagDefaults(t *testing.T) { + c := Config{} + + f := flag.NewFlagSet("test", flag.PanicOnError) + c.RegisterFlags(f) + + buf := bytes.Buffer{} + + f.SetOutput(&buf) + f.PrintDefaults() + + const delim = '\n' + // Because this is a short flag, it will be printed on the same line as the + // flag name. So we need to ignore this special case. + const ignoredHelpFlags = "-h\tPrint basic help." + + // Populate map with parsed default flags. + // LabelSet is the flag and value is the default text. + gotFlags := make(map[string]string) + for { + line, err := buf.ReadString(delim) + if err == io.EOF { + break + } + require.NoError(t, err) + + if strings.Contains(line, ignoredHelpFlags) { + continue + } + + nextLine, err := buf.ReadString(delim) + require.NoError(t, err) + + trimmedLine := strings.Trim(line, " \n") + splittedLine := strings.Split(trimmedLine, " ")[0] + gotFlags[splittedLine] = nextLine + } + + flagToCheck := "-server.http-listen-port" + require.Contains(t, gotFlags, flagToCheck) + require.Equal(t, c.Server.HTTPListenPort, 4040) + require.Contains(t, gotFlags[flagToCheck], "(default 4040)") +} + +// newTestConfig creates a Config with flags registered and parsed. +func newTestConfig(t *testing.T, args []string) Config { + t.Helper() + cfg := Config{} + fs := flag.NewFlagSet(t.Name(), flag.ContinueOnError) + cfg.RegisterFlags(fs) + require.NoError(t, fs.Parse(args)) + return cfg +} + +func TestSetupModuleManager_V2_ExcludesV1Components(t *testing.T) { + t.Run("excludes V1 by default", func(t *testing.T) { + cfg := newTestConfig(t, []string{"-architecture.storage=v2"}) + f := &Pyroscope{Cfg: cfg} + require.NoError(t, f.setupModuleManager()) + + allDeps := f.deps[All] + for _, mod := range []string{Ingester, Compactor, Querier, QueryScheduler, StoreGateway} { + assert.False(t, slices.Contains(allDeps, mod), "%s should not be in All deps", mod) + } + for _, mod := range []string{SegmentWriter, Metastore, CompactionWorker, QueryBackend} { + assert.True(t, slices.Contains(allDeps, mod), "%s should be in All deps", mod) + } + }) + + t.Run("includes all components when dual mode is enabled", func(t *testing.T) { + cfg := newTestConfig(t, []string{"-architecture.storage=v1-v2-dual"}) + f := &Pyroscope{Cfg: cfg} + require.NoError(t, f.setupModuleManager()) + + allDeps := f.deps[All] + for _, mod := range []string{Ingester, Compactor, Querier, QueryScheduler, StoreGateway} { + assert.True(t, slices.Contains(allDeps, mod), "%s should be in All deps", mod) + } + for _, mod := range []string{SegmentWriter, Metastore, CompactionWorker, QueryBackend} { + assert.True(t, slices.Contains(allDeps, mod), "%s should be in All deps", mod) + } + }) + + t.Run("exclude V2 when legacy storage", func(t *testing.T) { + cfg := newTestConfig(t, []string{"-architecture.storage=v1"}) + f := &Pyroscope{Cfg: cfg} + require.NoError(t, f.setupModuleManager()) + + allDeps := f.deps[All] + for _, mod := range []string{Ingester, Compactor, Querier, QueryScheduler, StoreGateway} { + assert.True(t, slices.Contains(allDeps, mod), "%s should be in All deps", mod) + } + for _, mod := range []string{SegmentWriter, Metastore, CompactionWorker, QueryBackend} { + assert.False(t, slices.Contains(allDeps, mod), "%s should not be in All deps", mod) + } + }) +} + +func TestRegisterServerFlagsWithChangedDefaultValues_V2(t *testing.T) { + t.Run("registers default v2 architecture flag with default value", func(t *testing.T) { + cfg := newTestConfig(t, []string{}) + fs := flag.NewFlagSet("test", flag.ContinueOnError) + cfg.RegisterFlagsWithContext(fs) + + archStorage := fs.Lookup("architecture.storage") + require.NotNil(t, archStorage) + assert.Equal(t, "v1-v2-dual", archStorage.DefValue) + }) + + t.Run("V2 applies additional default overrides", func(t *testing.T) { + cfg := newTestConfig(t, []string{}) + fs := flag.NewFlagSet("test", flag.ContinueOnError) + cfg.RegisterFlagsWithContext(fs) + + grpcRecv := fs.Lookup("server.grpc-max-recv-msg-size-bytes") + require.NotNil(t, grpcRecv) + assert.Equal(t, "104857600", grpcRecv.DefValue) + }) +} + +func TestRegisterFlags_MarksV1StorageOnlyFlags(t *testing.T) { + cfg := Config{} + fs := flag.NewFlagSet("test", flag.PanicOnError) + cfg.RegisterFlags(fs) + + seenPrefixes := make(map[string]bool, len(v1StorageOnlyFlagPrefixes)) + fs.VisitAll(func(f *flag.Flag) { + for _, prefix := range v1StorageOnlyFlagPrefixes { + if strings.HasPrefix(f.Name, prefix) { + seenPrefixes[prefix] = true + assert.Contains(t, f.Usage, v1StorageOnlyFlagUsagePrefix, "flag %s should be marked as V1-only", f.Name) + } + } + }) + + for _, prefix := range v1StorageOnlyFlagPrefixes { + assert.True(t, seenPrefixes[prefix], "expected at least one registered flag with prefix %s", prefix) + } +} + +func TestDynamicUnmarshalRecordsSetFlags(t *testing.T) { + var cfg Config + fs := flag.NewFlagSet("test", flag.ContinueOnError) + + require.NoError(t, configpkg.DynamicUnmarshal(&cfg, []string{ + "-architecture.storage=v2", + "-compactor.data-dir=/tmp/compactor", + "-pyroscopedb.data-path=/tmp/pyroscopedb", + }, fs)) + + assert.Contains(t, cfg.SetFlags, "architecture.storage") + assert.Contains(t, cfg.SetFlags, "compactor.data-dir") + assert.Contains(t, cfg.SetFlags, "pyroscopedb.data-path") + assert.ElementsMatch(t, []string{"compactor.data-dir", "pyroscopedb.data-path"}, cfg.setV1StorageOnlyFlags()) +} + +func TestConfig_WarnAboutV1StorageOnlyFlags(t *testing.T) { + t.Run("warns when v1-only flags are set with v2 storage", func(t *testing.T) { + cfg := Config{ArchitectureStorage: V2} + cfg.RecordSetFlag("compactor.data-dir") + cfg.RecordSetFlag("pyroscopedb.data-path") + cfg.RecordSetFlag("query-frontend.max-async-query-concurrency") + + var buf bytes.Buffer + cfg.warnAboutV1StorageOnlyFlags(log.NewLogfmtLogger(&buf)) + + output := buf.String() + assert.Contains(t, output, "flag=compactor.data-dir") + assert.Contains(t, output, "flag=pyroscopedb.data-path") + assert.NotContains(t, output, "query-frontend.max-async-query-concurrency") + }) + + t.Run("does not warn when v1 storage is active", func(t *testing.T) { + cfg := Config{ArchitectureStorage: V1} + cfg.RecordSetFlag("compactor.data-dir") + + var buf bytes.Buffer + cfg.warnAboutV1StorageOnlyFlags(log.NewLogfmtLogger(&buf)) + + assert.Empty(t, buf.String()) + }) +} + +func TestConfigDiff(t *testing.T) { + defaultCfg := Config{} + f := flag.NewFlagSet("test", flag.PanicOnError) + defaultCfg.RegisterFlags(f) + require.NoError(t, f.Parse([]string{})) + phlare, err := New(defaultCfg) + require.NoError(t, err) + + t.Run("default config unchanged", func(t *testing.T) { + result, err := phlare.statusService().GetDiffConfig(context.Background(), &statusv1.GetConfigRequest{}) + require.NoError(t, err) + require.Equal(t, "text/plain; charset=utf-8", result.ContentType) + require.Equal(t, "{}\n", string(result.Data)) + }) + t.Run("change a limit", func(t *testing.T) { + phlare.Cfg.LimitsConfig.MaxLabelNameLength = 123 + + result, err := phlare.statusService().GetDiffConfig(context.Background(), &statusv1.GetConfigRequest{}) + require.NoError(t, err) + require.Equal(t, "text/plain; charset=utf-8", result.ContentType) + require.Equal(t, "limits:\n max_label_name_length: 123\n", string(result.Data)) + }) +} + +func TestConfigValidate_StorageBackendRequired(t *testing.T) { + tests := []struct { + name string + args []string + wantErr bool + wantErrContain string + }{ + { + name: "v2 with no backend errors", + args: []string{"-architecture.storage=v2", "-storage.backend=", "-write-path=segment-writer"}, + wantErr: true, + wantErrContain: "storage.backend is required", + }, + { + name: "v1-v2-dual with no backend errors", + args: []string{"-architecture.storage=v1-v2-dual", "-storage.backend=", "-write-path=segment-writer"}, + wantErr: true, + wantErrContain: "storage.backend is required", + }, + { + name: "v1 with no backend is allowed", + args: []string{"-architecture.storage=v1", "-storage.backend=", "-write-path=ingester"}, + wantErr: false, + }, + { + name: "v2 with filesystem backend is valid", + args: []string{"-architecture.storage=v2", "-storage.backend=" + objstoreclient.Filesystem, "-write-path=segment-writer"}, + wantErr: false, + }, + { + name: "v1-v2-dual with filesystem backend is valid", + args: []string{"-architecture.storage=v1-v2-dual", "-storage.backend=" + objstoreclient.Filesystem, "-write-path=segment-writer"}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := newTestConfig(t, tt.args) + err := cfg.Validate() + if tt.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.wantErrContain) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestConfigValidate_V2IgnoresV1OnlyCompactorConfig(t *testing.T) { + t.Run("v2 ignores invalid V1 compactor block range", func(t *testing.T) { + cfg := newTestConfig(t, []string{ + "-architecture.storage=v2", + "-storage.backend=" + objstoreclient.Filesystem, + "-write-path=segment-writer", + "-compactor.block-ranges=30m", + }) + + require.NoError(t, cfg.Validate()) + }) + + t.Run("v1 validates invalid V1 compactor block range", func(t *testing.T) { + cfg := newTestConfig(t, []string{ + "-architecture.storage=v1", + "-write-path=ingester", + "-compactor.block-ranges=30m", + }) + + require.Error(t, cfg.Validate()) + }) +} diff --git a/pkg/pyroscope/runtime_config.go b/pkg/pyroscope/runtime_config.go new file mode 100644 index 0000000000..253d8b8c67 --- /dev/null +++ b/pkg/pyroscope/runtime_config.go @@ -0,0 +1,95 @@ +package pyroscope + +import ( + "net/http" + + "github.com/grafana/dskit/runtimeconfig" + + "github.com/grafana/pyroscope/v2/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +type tenantLimitsFromRuntimeConfig struct { + c *runtimeconfig.Manager +} + +func (t *tenantLimitsFromRuntimeConfig) AllByTenantID() map[string]*validation.Limits { + if t.c == nil { + return nil + } + + cfg, ok := t.c.GetConfig().(*validation.RuntimeConfigValues) + if cfg != nil && ok { + return cfg.TenantLimits + } + + return nil +} + +func (t *tenantLimitsFromRuntimeConfig) TenantLimits(userID string) *validation.Limits { + allByUserID := t.AllByTenantID() + if allByUserID == nil { + return nil + } + + return allByUserID[userID] +} + +func newTenantLimits(c *runtimeconfig.Manager) validation.TenantLimits { + return &tenantLimitsFromRuntimeConfig{c: c} +} + +func runtimeConfigHandler(runtimeCfgManager *runtimeconfig.Manager, defaultLimits validation.Limits) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cfg, ok := runtimeCfgManager.GetConfig().(*validation.RuntimeConfigValues) + if !ok || cfg == nil { + httputil.WriteTextResponse(w, "runtime config file doesn't exist") + return + } + + var output interface{} + switch r.URL.Query().Get("mode") { + case "diff": + // Default runtime config is just empty struct, but to make diff work, + // we set defaultLimits for every tenant that exists in runtime config. + defaultCfg := validation.RuntimeConfigValues{} + defaultCfg.TenantLimits = map[string]*validation.Limits{} + for k, v := range cfg.TenantLimits { + if v != nil { + defaultCfg.TenantLimits[k] = &defaultLimits + } + } + + cfgYaml, err := util.YAMLMarshalUnmarshal(cfg) + if err != nil { + httputil.Error(w, err) + return + } + + defaultCfgYaml, err := util.YAMLMarshalUnmarshal(defaultCfg) + if err != nil { + httputil.Error(w, err) + return + } + + output, err = util.DiffConfig(defaultCfgYaml, cfgYaml) + if err != nil { + httputil.Error(w, err) + return + } + + default: + output = cfg + } + httputil.WriteYAMLResponse(w, output) + } +} + +func (t *tenantLimitsFromRuntimeConfig) RuntimeConfig() *validation.RuntimeConfigValues { + cfg, ok := t.c.GetConfig().(*validation.RuntimeConfigValues) + if cfg != nil && ok { + return cfg + } + return nil +} diff --git a/pkg/pyroscope/storage_layer.go b/pkg/pyroscope/storage_layer.go new file mode 100644 index 0000000000..2b054089d7 --- /dev/null +++ b/pkg/pyroscope/storage_layer.go @@ -0,0 +1,41 @@ +package pyroscope + +import ( + "errors" + "fmt" +) + +type StorageLayer string + +const ( + V1 StorageLayer = "v1" + V1V2Dual StorageLayer = "v1-v2-dual" + V2 StorageLayer = "v2" +) + +var ErrInvalidStorageLayer = errors.New("invalid storage layer") + +var storageLayers = []StorageLayer{ + V1, + V1V2Dual, + V2, +} + +const validStorageLayerOptionsString = "valid options: v1, v1-v2-dual, v2" + +func (m *StorageLayer) Set(text string) error { + x := StorageLayer(text) + for _, name := range storageLayers { + if x == name { + *m = x + return nil + } + } + return fmt.Errorf("%w: %s; %s", ErrInvalidStorageLayer, x, validStorageLayerOptionsString) +} + +func (m *StorageLayer) String() string { return string(*m) } + +func (m *StorageLayer) UnmarshalText(text []byte) error { + return m.Set(string(text)) +} diff --git a/pkg/pyroscope/tracing.go b/pkg/pyroscope/tracing.go new file mode 100644 index 0000000000..9511f69c6e --- /dev/null +++ b/pkg/pyroscope/tracing.go @@ -0,0 +1,92 @@ +package pyroscope + +import ( + "context" + "io" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + wwtracing "github.com/grafana/dskit/tracing" + otelpyroscope "github.com/grafana/otel-profiling-go" + "go.opentelemetry.io/contrib/exporters/autoexport" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + tracesdk "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" +) + +// initTracing initializes the OTel TracerProvider. +// +// It delegates to dskit's NewOTelOrJaegerFromEnv, which also handles +// legacy JAEGER_* env vars. If dskit init fails (e.g. due to a +// resource schema URL conflict between OTel SDK versions), it falls +// back to a direct OTel SDK initialization. +func initTracing(serviceName string, logger log.Logger, profilingEnabled bool) (io.Closer, error) { + var opts []wwtracing.OTelOption + if !profilingEnabled { + opts = append(opts, wwtracing.WithPyroscopeDisabled()) + } + closer, err := wwtracing.NewOTelOrJaegerFromEnv(serviceName, logger, opts...) + if err == nil { + return closer, nil + } + level.Warn(logger).Log("msg", "dskit tracing init failed, falling back to direct OTel SDK init", "err", err) + closer, fallbackErr := initTracingDirect(serviceName, logger, profilingEnabled) + if fallbackErr != nil { + level.Warn(logger).Log("msg", "direct OTel SDK init also failed", "fallback_err", fallbackErr) + // Return the original error as it is likely more informative. + return nil, err + } + return closer, nil +} + +// initTracingDirect creates the OTel TracerProvider directly, bypassing +// dskit's NewResource which may fail due to schema URL conflicts between +// the OTel SDK's bundled semconv and dskit's imported semconv version. +func initTracingDirect(serviceName string, logger log.Logger, profilingEnabled bool) (io.Closer, error) { + exp, err := autoexport.NewSpanExporter(context.Background()) + if err != nil { + return nil, err + } + + res, err := resource.Merge( + resource.Default(), + resource.NewSchemaless(attribute.String("service.name", serviceName)), + ) + if err != nil { + return nil, err + } + + tpsdk := tracesdk.NewTracerProvider( + tracesdk.WithBatcher(exp), + tracesdk.WithResource(res), + ) + + var tp trace.TracerProvider = tpsdk + if profilingEnabled { + tp = otelpyroscope.NewTracerProvider(tp) + } + + otel.SetTracerProvider(tp) + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(wwtracing.OTelPropagatorsFromEnv()...)) + otel.SetErrorHandler(otelErrorHandler{logger: logger}) + + return &tracerProviderCloser{tp: tpsdk}, nil +} + +type otelErrorHandler struct{ logger log.Logger } + +func (h otelErrorHandler) Handle(err error) { + level.Error(h.logger).Log("msg", "OpenTelemetry.ErrorHandler", "err", err) +} + +type tracerProviderCloser struct{ tp *tracesdk.TracerProvider } + +func (c *tracerProviderCloser) Close() error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + return c.tp.Shutdown(ctx) +} diff --git a/pkg/querier/analyze_query.go b/pkg/querier/analyze_query.go index ba640ad488..8d3baf25f4 100644 --- a/pkg/querier/analyze_query.go +++ b/pkg/querier/analyze_query.go @@ -5,14 +5,13 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" + "github.com/grafana/dskit/tracing" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/promql/parser" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" ) type queryScope struct { @@ -22,10 +21,13 @@ type queryScope struct { } func (q *Querier) AnalyzeQuery(ctx context.Context, req *connect.Request[querierv1.AnalyzeQueryRequest]) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "AnalyzeQuery") + sp, ctx := tracing.StartSpanFromContext(ctx, "AnalyzeQuery") defer sp.Finish() plan, err := q.blockSelect(ctx, model.Time(req.Msg.Start), model.Time(req.Msg.End)) + if err != nil { + return nil, err + } ingesterQueryScope, storeGatewayQueryScope, deduplicationNeeded := getDataFromPlan(plan) blockStatsFromReplicas, err := q.getBlockStatsFromIngesters(ctx, plan, ingesterQueryScope.blockIds) @@ -107,7 +109,7 @@ func (q *Querier) getBlockStatsFromStoreGateways(ctx context.Context, plan block } return stats.Msg, err }) - return blockStatsFromReplicas, nil + return blockStatsFromReplicas, err } func addBlockStatsToQueryScope(blockStatsFromReplicas []ResponseFromReplica[*ingestv1.GetBlockStatsResponse], queryScope *queryScope) { @@ -150,7 +152,7 @@ func createMatchersFromQuery(query string) ([]string, error) { var matchers []*labels.Matcher var err error if query != "" { - matchers, err = parser.ParseMetricSelector(query) + matchers, err = phlaremodel.ParseMetricSelector(query) if err != nil { return nil, err } diff --git a/pkg/querier/grpc_handler.go b/pkg/querier/grpc_handler.go index be32c05282..5265171617 100644 --- a/pkg/querier/grpc_handler.go +++ b/pkg/querier/grpc_handler.go @@ -4,19 +4,23 @@ import ( "net/http" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - vcsv1connect "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1/vcsv1connect" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) type QuerierSvc interface { querierv1connect.QuerierServiceHandler - vcsv1connect.VCSServiceHandler } -func NewGRPCHandler(svc QuerierSvc) connectgrpc.GRPCHandler { +func NewGRPCHandler(svc QuerierSvc, useK6Middleware bool) connectgrpc.GRPCHandler { mux := http.NewServeMux() mux.Handle(querierv1connect.NewQuerierServiceHandler(svc, connectapi.DefaultHandlerOptions()...)) - mux.Handle(vcsv1connect.NewVCSServiceHandler(svc, connectapi.DefaultHandlerOptions()...)) + + if useK6Middleware { + httpMiddleware := httputil.K6Middleware() + return connectgrpc.NewHandler(httpMiddleware.Wrap(mux)) + } + return connectgrpc.NewHandler(mux) } diff --git a/pkg/querier/grpc_roundtripper.go b/pkg/querier/grpc_roundtripper.go index 3b3d1f76eb..5e2caeb90c 100644 --- a/pkg/querier/grpc_roundtripper.go +++ b/pkg/querier/grpc_roundtripper.go @@ -4,8 +4,8 @@ import ( "connectrpc.com/connect" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" ) func NewGRPCRoundTripper(transport connectgrpc.GRPCRoundTripper) querierv1connect.QuerierServiceHandler { diff --git a/pkg/querier/http.go b/pkg/querier/http.go index 695787f34e..248e03149d 100644 --- a/pkg/querier/http.go +++ b/pkg/querier/http.go @@ -4,31 +4,25 @@ import ( "encoding/json" "errors" "fmt" - "io" "net/http" "strconv" "strings" + "time" "connectrpc.com/connect" - "github.com/gogo/status" - "github.com/google/pprof/profile" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/promql/parser" "golang.org/x/sync/errgroup" - "google.golang.org/grpc/codes" - profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/frontend/dot/graph" - "github.com/grafana/pyroscope/pkg/frontend/dot/report" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" - "github.com/grafana/pyroscope/pkg/og/util/attime" - "github.com/grafana/pyroscope/pkg/querier/timeline" - httputil "github.com/grafana/pyroscope/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/frontend/dot" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/og/util/attime" + "github.com/grafana/pyroscope/v2/pkg/querier/timeline" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) func NewHTTPHandlers(client querierv1connect.QuerierServiceClient) *QueryHandlers { @@ -160,7 +154,7 @@ func (q *QueryHandlers) Render(w http.ResponseWriter, req *http.Request) { sourceProfileMaxNodes = dotProfileMaxNodes } } - resp, err := q.client.SelectMergeProfile(req.Context(), connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + resp, err := q.client.SelectMergeProfile(req.Context(), connect.NewRequest(&querierv1.SelectMergeProfileRequest{ //nolint:staticcheck // Legacy querier.v1 render path. Start: selectParams.Start, End: selectParams.End, ProfileTypeID: selectParams.ProfileTypeID, @@ -168,21 +162,27 @@ func (q *QueryHandlers) Render(w http.ResponseWriter, req *http.Request) { MaxNodes: &sourceProfileMaxNodes, })) if err != nil { - httputil.Error(w, connect.NewError(connect.CodeInternal, err)) + httputil.Error(w, err) + return + } + // Check if profile has any data - return empty string if no data + if resp.Msg == nil || len(resp.Msg.Sample) == 0 { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) return } - if err = pprofToDotProfile(w, resp.Msg, int(dotProfileMaxNodes)); err != nil { - httputil.Error(w, connect.NewError(connect.CodeInternal, err)) + if err = dot.WriteFromProfile(w, resp.Msg, int(dotProfileMaxNodes)); err != nil { + httputil.Error(w, err) } return } var resFlame *connect.Response[querierv1.SelectMergeStacktracesResponse] - g, ctx := errgroup.WithContext(req.Context()) + g, gCtx := errgroup.WithContext(req.Context()) selectParamsClone := selectParams.CloneVT() g.Go(func() error { var err error - resFlame, err = q.client.SelectMergeStacktraces(ctx, connect.NewRequest(selectParamsClone)) + resFlame, err = q.client.SelectMergeStacktraces(gCtx, connect.NewRequest(selectParamsClone)) return err }) @@ -240,21 +240,6 @@ func (q *QueryHandlers) Render(w http.ResponseWriter, req *http.Request) { } } -func pprofToDotProfile(w io.Writer, p *profilev1.Profile, maxNodes int) error { - data, err := p.MarshalVT() - if err != nil { - return connect.NewError(connect.CodeInternal, err) - } - pr, err := profile.ParseData(data) - if err != nil { - return connect.NewError(connect.CodeInternal, err) - } - rpt := report.NewDefault(pr, report.Options{NodeCount: maxNodes}) - gr, cfg := report.GetDOT(rpt) - graph.ComposeDot(w, gr, &graph.DotAttributes{}, cfg) - return nil -} - type renderRequestFieldNames struct { query string from string @@ -277,9 +262,17 @@ func parseSelectProfilesRequest(fieldNames renderRequestFieldNames, req *http.Re v := req.URL.Query() - // parse time using pyroscope's attime parser - start := model.TimeFromUnixNano(attime.Parse(v.Get(fieldNames.from)).UnixNano()) - end := model.TimeFromUnixNano(attime.Parse(v.Get(fieldNames.until)).UnixNano()) + from := time.Now() + if f := v.Get(fieldNames.from); f != "" { + from = attime.Parse(f) + } + until := time.Now() + if u := v.Get(fieldNames.until); u != "" { + until = attime.Parse(u) + } + + start := model.TimeFromUnixNano(from.UnixNano()) + end := model.TimeFromUnixNano(until.UnixNano()) p := &querierv1.SelectMergeStacktracesRequest{ Start: int64(start), @@ -303,30 +296,30 @@ func parseSelectProfilesRequest(fieldNames renderRequestFieldNames, req *http.Re func parseQuery(fieldName string, req *http.Request) (string, *typesv1.ProfileType, error) { q := req.Form.Get(fieldName) if q == "" { - return "", nil, fmt.Errorf("'%s' is required", fieldName) + return "", nil, fmt.Errorf("%q is required", fieldName) } - parsedSelector, err := parser.ParseMetricSelector(q) + parsedSelector, err := phlaremodel.ParseMetricSelector(q) if err != nil { - return "", nil, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to parse '%s'", fieldName)) + return "", nil, fmt.Errorf("failed to parse %q: %w", fieldName, err) } sel := make([]*labels.Matcher, 0, len(parsedSelector)) var nameLabel *labels.Matcher for _, matcher := range parsedSelector { - if matcher.Name == labels.MetricName { + if matcher.Name == string(model.MetricNameLabel) { nameLabel = matcher } else { sel = append(sel, matcher) } } if nameLabel == nil { - return "", nil, status.Error(codes.InvalidArgument, fmt.Sprintf("'%s' must contain a profile-type selection", fieldName)) + return "", nil, fmt.Errorf("%q must contain a profile-type selection", fieldName) } profileSelector, err := phlaremodel.ParseProfileTypeSelector(nameLabel.Value) if err != nil { - return "", nil, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to parse '%s'", fieldName)) + return "", nil, fmt.Errorf("failed to parse %q", fieldName) } return convertMatchersToString(sel), profileSelector, nil } diff --git a/pkg/querier/http_test.go b/pkg/querier/http_test.go index 877592737d..afc4f39b44 100644 --- a/pkg/querier/http_test.go +++ b/pkg/querier/http_test.go @@ -1,15 +1,20 @@ package querier import ( + "context" "fmt" "net/http" + "net/http/httptest" "net/url" "testing" "time" + "connectrpc.com/connect" "github.com/prometheus/common/model" "github.com/stretchr/testify/require" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" ) @@ -40,3 +45,155 @@ func Test_ParseQuery(t *testing.T) { require.Equal(t, `{foo="bar",bar=~"buzz"}`, queryRequest.LabelSelector) } + +func Test_ParseSelectProfilesRequest_DefaultFromUntil(t *testing.T) { + tests := []struct { + name string + queryParams url.Values + expectedStart time.Time + expectedEnd time.Time + }{ + { + name: "both from and until missing defaults to now", + queryParams: url.Values{ + "query": []string{`memory:alloc_space:bytes:space:bytes{}`}, + }, + expectedStart: time.Now(), + expectedEnd: time.Now(), + }, + { + name: "from missing defaults to now", + queryParams: url.Values{ + "query": []string{`memory:alloc_space:bytes:space:bytes{}`}, + "until": []string{"now-1h"}, + }, + expectedStart: time.Now(), + expectedEnd: time.Now().Add(-1 * time.Hour), + }, + { + name: "until missing defaults to now", + queryParams: url.Values{ + "query": []string{`memory:alloc_space:bytes:space:bytes{}`}, + "from": []string{"now-6h"}, + }, + expectedStart: time.Now().Add(-6 * time.Hour), + expectedEnd: time.Now(), + }, + { + name: "both provided uses provided values", + queryParams: url.Values{ + "query": []string{`memory:alloc_space:bytes:space:bytes{}`}, + "from": []string{"now-6h"}, + "until": []string{"now-1h"}, + }, + expectedStart: time.Now().Add(-6 * time.Hour), + expectedEnd: time.Now().Add(-1 * time.Hour), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost/render/render?%s", tt.queryParams.Encode()), nil) + require.NoError(t, err) + require.NoError(t, req.ParseForm()) + + queryRequest, _, err := parseSelectProfilesRequest(renderRequestFieldNames{}, req) + require.NoError(t, err) + + require.WithinDuration(t, tt.expectedStart, model.Time(queryRequest.Start).Time(), 1*time.Minute) + require.WithinDuration(t, tt.expectedEnd, model.Time(queryRequest.End).Time(), 1*time.Minute) + }) + } +} + +// mockQuerierClient is a mock implementation of QuerierServiceClient +type mockQuerierClient struct { + selectMergeProfileFunc func(context.Context, *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[profilev1.Profile], error) +} + +func (m *mockQuerierClient) ProfileTypes(context.Context, *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) LabelValues(context.Context, *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) LabelNames(context.Context, *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) Series(context.Context, *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) SelectMergeStacktraces(context.Context, *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) SelectMergeSpanProfile(context.Context, *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) SelectMergeProfile(ctx context.Context, req *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[profilev1.Profile], error) { + if m.selectMergeProfileFunc != nil { + return m.selectMergeProfileFunc(ctx, req) + } + return nil, nil +} + +func (m *mockQuerierClient) SelectSeries(context.Context, *connect.Request[querierv1.SelectSeriesRequest]) (*connect.Response[querierv1.SelectSeriesResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) Diff(context.Context, *connect.Request[querierv1.DiffRequest]) (*connect.Response[querierv1.DiffResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) GetProfileStats(context.Context, *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) AnalyzeQuery(context.Context, *connect.Request[querierv1.AnalyzeQueryRequest]) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { + return nil, nil +} + +func (m *mockQuerierClient) SelectHeatmap(context.Context, *connect.Request[querierv1.SelectHeatmapRequest]) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + return nil, nil +} + +func Test_RenderDotFormatEmptyProfile(t *testing.T) { + // Create a mock client that returns an empty profile + mockClient := &mockQuerierClient{ + selectMergeProfileFunc: func(ctx context.Context, req *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[profilev1.Profile], error) { + // Return an empty profile (no samples) + return connect.NewResponse(&profilev1.Profile{ + Sample: []*profilev1.Sample{}, // Empty samples + }), nil + }, + } + + handlers := NewHTTPHandlers(mockClient) + + // Create a request with format=dot + q := url.Values{ + "query": []string{`memory:alloc_space:bytes:space:bytes{}`}, + "from": []string{"now-1h"}, + "until": []string{"now"}, + "format": []string{"dot"}, + } + + req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost/render?%s", q.Encode()), nil) + require.NoError(t, err) + + // Create a response recorder + rr := httptest.NewRecorder() + + // Call the handler + handlers.Render(rr, req) + + // Verify we get a 200 OK with empty body instead of 500 (Internal Server Error) + require.Equal(t, http.StatusOK, rr.Code, "Expected 200 OK for empty profile, got %d", rr.Code) + require.Equal(t, "", rr.Body.String(), "Expected empty body for empty profile") + require.Equal(t, "text/plain", rr.Header().Get("Content-Type"), "Expected text/plain content type") +} diff --git a/pkg/querier/ingester_querier.go b/pkg/querier/ingester_querier.go index ab2a78fc43..a407ac94bd 100644 --- a/pkg/querier/ingester_querier.go +++ b/pkg/querier/ingester_querier.go @@ -6,33 +6,30 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/ring" ring_client "github.com/grafana/dskit/ring/client" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" - "github.com/prometheus/prometheus/promql/parser" + "github.com/grafana/dskit/tracing" "golang.org/x/sync/errgroup" googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingesterv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/clientpool" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util" ) type IngesterQueryClient interface { LabelValues(context.Context, *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) LabelNames(context.Context, *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) - ProfileTypes(context.Context, *connect.Request[ingestv1.ProfileTypesRequest]) (*connect.Response[ingestv1.ProfileTypesResponse], error) - Series(ctx context.Context, req *connect.Request[ingestv1.SeriesRequest]) (*connect.Response[ingestv1.SeriesResponse], error) + ProfileTypes(context.Context, *connect.Request[ingesterv1.ProfileTypesRequest]) (*connect.Response[ingesterv1.ProfileTypesResponse], error) + Series(ctx context.Context, req *connect.Request[ingesterv1.SeriesRequest]) (*connect.Response[ingesterv1.SeriesResponse], error) MergeProfilesStacktraces(context.Context) clientpool.BidiClientMergeProfilesStacktraces MergeProfilesLabels(ctx context.Context) clientpool.BidiClientMergeProfilesLabels MergeProfilesPprof(ctx context.Context) clientpool.BidiClientMergeProfilesPprof MergeSpanProfile(ctx context.Context) clientpool.BidiClientMergeSpanProfile - BlockMetadata(ctx context.Context, req *connect.Request[ingestv1.BlockMetadataRequest]) (*connect.Response[ingestv1.BlockMetadataResponse], error) + BlockMetadata(ctx context.Context, req *connect.Request[ingesterv1.BlockMetadataRequest]) (*connect.Response[ingesterv1.BlockMetadataResponse], error) GetProfileStats(ctx context.Context, req *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) - GetBlockStats(ctx context.Context, req *connect.Request[ingestv1.GetBlockStatsRequest]) (*connect.Response[ingestv1.GetBlockStatsResponse], error) + GetBlockStats(ctx context.Context, req *connect.Request[ingesterv1.GetBlockStatsRequest]) (*connect.Response[ingesterv1.GetBlockStatsResponse], error) } // IngesterQuerier helps with querying the ingesters. @@ -58,13 +55,15 @@ func forAllIngesters[T any](ctx context.Context, ingesterQuerier *IngesterQuerie if err != nil { return nil, err } - return forGivenReplicationSet(ctx, func(addr string) (IngesterQueryClient, error) { + + clientFactoryFn := func(addr string) (IngesterQueryClient, error) { client, err := ingesterQuerier.pool.GetClientFor(addr) if err != nil { return nil, err } return client.(IngesterQueryClient), nil - }, replicationSet, f) + } + return forGivenReplicationSet(ctx, clientFactoryFn, replicationSet, f) } // forAllPlannedIngesters runs f, in parallel, for all ingesters part of the plan @@ -83,14 +82,14 @@ func forAllPlannedIngesters[T any](ctx context.Context, ingesterQuerier *Ingeste }, replicationSet, f) } -func (q *Querier) selectTreeFromIngesters(ctx context.Context, req *querierv1.SelectMergeStacktracesRequest, plan blockPlan) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectTree Ingesters") +func (q *Querier) selectTreeFromIngesters(ctx context.Context, req *querierv1.SelectMergeStacktracesRequest, plan blockPlan) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectTree Ingesters") defer sp.Finish() profileType, err := phlaremodel.ParseProfileTypeSelector(req.ProfileTypeID) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } - _, err = parser.ParseMetricSelector(req.LabelSelector) + _, err = phlaremodel.ParseMetricSelector(req.LabelSelector) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -99,7 +98,7 @@ func (q *Querier) selectTreeFromIngesters(ctx context.Context, req *querierv1.Se var responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesStacktraces] if plan != nil { - responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, ic IngesterQueryClient, hints *ingestv1.Hints) (clientpool.BidiClientMergeProfilesStacktraces, error) { + responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, ic IngesterQueryClient, hints *ingesterv1.Hints) (clientpool.BidiClientMergeProfilesStacktraces, error) { return ic.MergeProfilesStacktraces(ctx), nil }) } else { @@ -111,7 +110,7 @@ func (q *Querier) selectTreeFromIngesters(ctx context.Context, req *querierv1.Se return nil, connect.NewError(connect.CodeInternal, err) } // send the first initial request to all ingesters. - g, gCtx := errgroup.WithContext(ctx) + g, _ := errgroup.WithContext(ctx) for idx := range responses { r := responses[idx] blockHints, err := BlockHints(plan, r.addr) @@ -120,13 +119,13 @@ func (q *Querier) selectTreeFromIngesters(ctx context.Context, req *querierv1.Se } g.Go(util.RecoverPanic(func() error { - return r.response.Send(&ingestv1.MergeProfilesStacktracesRequest{ - Request: &ingestv1.SelectProfilesRequest{ + return r.response.Send(&ingesterv1.MergeProfilesStacktracesRequest{ + Request: &ingesterv1.SelectProfilesRequest{ LabelSelector: req.LabelSelector, Start: req.Start, End: req.End, Type: profileType, - Hints: &ingestv1.Hints{Block: blockHints}, + Hints: &ingesterv1.Hints{Block: blockHints}, }, MaxNodes: req.MaxNodes, }) @@ -137,17 +136,17 @@ func (q *Querier) selectTreeFromIngesters(ctx context.Context, req *querierv1.Se } // merge all profiles - return selectMergeTree(gCtx, responses) + return selectMergeTree(ctx, responses) } func (q *Querier) selectProfileFromIngesters(ctx context.Context, req *querierv1.SelectMergeProfileRequest, plan blockPlan) (*googlev1.Profile, error) { - span, ctx := opentracing.StartSpanFromContext(ctx, "SelectProfile Ingesters") + span, ctx := tracing.StartSpanFromContext(ctx, "SelectProfile Ingesters") defer span.Finish() profileType, err := phlaremodel.ParseProfileTypeSelector(req.ProfileTypeID) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } - _, err = parser.ParseMetricSelector(req.LabelSelector) + _, err = phlaremodel.ParseMetricSelector(req.LabelSelector) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -156,7 +155,7 @@ func (q *Querier) selectProfileFromIngesters(ctx context.Context, req *querierv1 var responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesPprof] if plan != nil { - responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, ic IngesterQueryClient, hints *ingestv1.Hints) (clientpool.BidiClientMergeProfilesPprof, error) { + responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, ic IngesterQueryClient, hints *ingesterv1.Hints) (clientpool.BidiClientMergeProfilesPprof, error) { return ic.MergeProfilesPprof(ctx), nil }) } else { @@ -168,7 +167,7 @@ func (q *Querier) selectProfileFromIngesters(ctx context.Context, req *querierv1 return nil, connect.NewError(connect.CodeInternal, err) } // send the first initial request to all ingesters. - g, gCtx := errgroup.WithContext(ctx) + g, _ := errgroup.WithContext(ctx) for idx := range responses { r := responses[idx] blockHints, err := BlockHints(plan, r.addr) @@ -177,13 +176,13 @@ func (q *Querier) selectProfileFromIngesters(ctx context.Context, req *querierv1 } g.Go(util.RecoverPanic(func() error { - return r.response.Send(&ingestv1.MergeProfilesPprofRequest{ - Request: &ingestv1.SelectProfilesRequest{ + return r.response.Send(&ingesterv1.MergeProfilesPprofRequest{ + Request: &ingesterv1.SelectProfilesRequest{ LabelSelector: req.LabelSelector, Start: req.Start, End: req.End, Type: profileType, - Hints: &ingestv1.Hints{Block: blockHints}, + Hints: &ingesterv1.Hints{Block: blockHints}, }, MaxNodes: req.MaxNodes, StackTraceSelector: req.StackTraceSelector, @@ -195,18 +194,18 @@ func (q *Querier) selectProfileFromIngesters(ctx context.Context, req *querierv1 } // merge all profiles - span.LogFields(otlog.String("msg", "selectMergePprofProfile")) - return selectMergePprofProfile(gCtx, profileType, responses) + span.SetTag("msg", "selectMergePprofProfile") + return selectMergePprofProfile(ctx, profileType, responses) } func (q *Querier) selectSeriesFromIngesters(ctx context.Context, req *ingesterv1.MergeProfilesLabelsRequest, plan map[string]*blockPlanEntry) ([]ResponseFromReplica[clientpool.BidiClientMergeProfilesLabels], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectSeries Ingesters") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectSeries Ingesters") defer sp.Finish() var responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesLabels] var err error if plan != nil { - responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, q IngesterQueryClient, hint *ingestv1.Hints) (clientpool.BidiClientMergeProfilesLabels, error) { + responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, q IngesterQueryClient, hint *ingesterv1.Hints) (clientpool.BidiClientMergeProfilesLabels, error) { return q.MergeProfilesLabels(ctx), nil }) } else { @@ -227,7 +226,7 @@ func (q *Querier) selectSeriesFromIngesters(ctx context.Context, req *ingesterv1 } g.Go(util.RecoverPanic(func() error { req := req.CloneVT() - req.Request.Hints = &ingestv1.Hints{Block: blockHints} + req.Request.Hints = &ingesterv1.Hints{Block: blockHints} return r.response.Send(req) })) } @@ -238,7 +237,7 @@ func (q *Querier) selectSeriesFromIngesters(ctx context.Context, req *ingesterv1 } func (q *Querier) labelValuesFromIngesters(ctx context.Context, req *typesv1.LabelValuesRequest) ([]ResponseFromReplica[[]string], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelValues Ingesters") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelValues Ingesters") defer sp.Finish() responses, err := forAllIngesters(ctx, q.ingesterQuerier, func(childCtx context.Context, ic IngesterQueryClient) ([]string, error) { @@ -255,7 +254,7 @@ func (q *Querier) labelValuesFromIngesters(ctx context.Context, req *typesv1.Lab } func (q *Querier) labelNamesFromIngesters(ctx context.Context, req *typesv1.LabelNamesRequest) ([]ResponseFromReplica[[]string], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelNames Ingesters") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelNames Ingesters") defer sp.Finish() responses, err := forAllIngesters(ctx, q.ingesterQuerier, func(childCtx context.Context, ic IngesterQueryClient) ([]string, error) { @@ -272,11 +271,11 @@ func (q *Querier) labelNamesFromIngesters(ctx context.Context, req *typesv1.Labe } func (q *Querier) seriesFromIngesters(ctx context.Context, req *ingesterv1.SeriesRequest) ([]ResponseFromReplica[[]*typesv1.Labels], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "Series Ingesters") + sp, ctx := tracing.StartSpanFromContext(ctx, "Series Ingesters") defer sp.Finish() responses, err := forAllIngesters(ctx, q.ingesterQuerier, func(childCtx context.Context, ic IngesterQueryClient) ([]*typesv1.Labels, error) { - res, err := ic.Series(childCtx, connect.NewRequest(&ingestv1.SeriesRequest{ + res, err := ic.Series(childCtx, connect.NewRequest(&ingesterv1.SeriesRequest{ Matchers: req.Matchers, LabelNames: req.LabelNames, Start: req.Start, @@ -293,14 +292,14 @@ func (q *Querier) seriesFromIngesters(ctx context.Context, req *ingesterv1.Serie return responses, nil } -func (q *Querier) selectSpanProfileFromIngesters(ctx context.Context, req *querierv1.SelectMergeSpanProfileRequest, plan map[string]*blockPlanEntry) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeSpanProfile Ingesters") +func (q *Querier) selectSpanProfileFromIngesters(ctx context.Context, req *querierv1.SelectMergeSpanProfileRequest, plan map[string]*blockPlanEntry) (*phlaremodel.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeSpanProfile Ingesters") defer sp.Finish() profileType, err := phlaremodel.ParseProfileTypeSelector(req.ProfileTypeID) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } - _, err = parser.ParseMetricSelector(req.LabelSelector) + _, err = phlaremodel.ParseMetricSelector(req.LabelSelector) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -309,7 +308,7 @@ func (q *Querier) selectSpanProfileFromIngesters(ctx context.Context, req *queri var responses []ResponseFromReplica[clientpool.BidiClientMergeSpanProfile] if plan != nil { - responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, ic IngesterQueryClient, hints *ingestv1.Hints) (clientpool.BidiClientMergeSpanProfile, error) { + responses, err = forAllPlannedIngesters(ctx, q.ingesterQuerier, plan, func(ctx context.Context, ic IngesterQueryClient, hints *ingesterv1.Hints) (clientpool.BidiClientMergeSpanProfile, error) { return ic.MergeSpanProfile(ctx), nil }) } else { @@ -321,7 +320,7 @@ func (q *Querier) selectSpanProfileFromIngesters(ctx context.Context, req *queri return nil, connect.NewError(connect.CodeInternal, err) } // send the first initial request to all ingesters. - g, gCtx := errgroup.WithContext(ctx) + g, _ := errgroup.WithContext(ctx) for idx := range responses { r := responses[idx] blockHints, err := BlockHints(plan, r.addr) @@ -330,14 +329,14 @@ func (q *Querier) selectSpanProfileFromIngesters(ctx context.Context, req *queri } g.Go(util.RecoverPanic(func() error { - return r.response.Send(&ingestv1.MergeSpanProfileRequest{ - Request: &ingestv1.SelectSpanProfileRequest{ + return r.response.Send(&ingesterv1.MergeSpanProfileRequest{ + Request: &ingesterv1.SelectSpanProfileRequest{ LabelSelector: req.LabelSelector, Start: req.Start, End: req.End, Type: profileType, SpanSelector: req.SpanSelector, - Hints: &ingestv1.Hints{Block: blockHints}, + Hints: &ingesterv1.Hints{Block: blockHints}, }, MaxNodes: req.MaxNodes, }) @@ -348,15 +347,15 @@ func (q *Querier) selectSpanProfileFromIngesters(ctx context.Context, req *queri } // merge all profiles - return selectMergeSpanProfile(gCtx, responses) + return selectMergeSpanProfile(ctx, responses) } -func (q *Querier) blockSelectFromIngesters(ctx context.Context, req *ingestv1.BlockMetadataRequest) ([]ResponseFromReplica[[]*typesv1.BlockInfo], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "blockSelectFromIngesters") +func (q *Querier) blockSelectFromIngesters(ctx context.Context, req *ingesterv1.BlockMetadataRequest) ([]ResponseFromReplica[[]*typesv1.BlockInfo], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "blockSelectFromIngesters") defer sp.Finish() responses, err := forAllIngesters(ctx, q.ingesterQuerier, func(childCtx context.Context, ic IngesterQueryClient) ([]*typesv1.BlockInfo, error) { - res, err := ic.BlockMetadata(childCtx, connect.NewRequest(&ingestv1.BlockMetadataRequest{ + res, err := ic.BlockMetadata(childCtx, connect.NewRequest(&ingesterv1.BlockMetadataRequest{ Start: req.Start, End: req.End, })) diff --git a/pkg/querier/querier.go b/pkg/querier/querier.go index 78977b9b2f..f55619ad02 100644 --- a/pkg/querier/querier.go +++ b/pkg/querier/querier.go @@ -2,6 +2,7 @@ package querier import ( "context" + "errors" "flag" "fmt" "math" @@ -17,33 +18,29 @@ import ( ring_client "github.com/grafana/dskit/ring/client" "github.com/grafana/dskit/services" "github.com/grafana/dskit/tenant" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/common/model" - "github.com/prometheus/prometheus/promql/parser" "github.com/samber/lo" "golang.org/x/sync/errgroup" + "github.com/grafana/pyroscope/v2/pkg/featureflags" + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1/vcsv1connect" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/clientpool" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/bucketindex" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/querier/vcs" - "github.com/grafana/pyroscope/pkg/storegateway" - pmath "github.com/grafana/pyroscope/pkg/util/math" - "github.com/grafana/pyroscope/pkg/util/spanlogger" - "github.com/grafana/pyroscope/pkg/validation" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucketindex" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/storegateway" + "github.com/grafana/pyroscope/v2/pkg/util/spanlogger" + "github.com/grafana/pyroscope/v2/pkg/validation" ) type Config struct { @@ -72,8 +69,6 @@ type Querier struct { ingesterQuerier *IngesterQuerier storeGatewayQuerier *StoreGatewayQuerier - vcsv1connect.VCSServiceHandler - storageBucket phlareobj.Bucket tenantConfigProvider phlareobj.TenantConfigProvider @@ -134,7 +129,6 @@ func New(params *NewQuerierParams) (*Querier, error) { params.IngestersRing, ), storeGatewayQuerier: storeGatewayQuerier, - VCSServiceHandler: vcs.New(params.Logger, params.Reg), storageBucket: params.StorageBucket, tenantConfigProvider: params.CfgProvider, limits: params.Overrides, @@ -147,7 +141,7 @@ func New(params *NewQuerierParams) (*Querier, error) { // should we watch for the ring module status ? q.subservices, err = services.NewManager(svcs...) if err != nil { - return nil, errors.Wrap(err, "services manager") + return nil, fmt.Errorf("services manager: %w", err) } q.subservicesWatcher = services.NewFailureWatcher() q.subservicesWatcher.WatchManager(q.subservices) @@ -164,7 +158,7 @@ func (q *Querier) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-q.subservicesWatcher.Chan(): - return errors.Wrap(err, "querier subservice failed") + return fmt.Errorf("querier subservice failed: %w", err) } } @@ -173,7 +167,7 @@ func (q *Querier) stopping(_ error) error { } func (q *Querier) ProfileTypes(ctx context.Context, req *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "ProfileTypes") + sp, ctx := tracing.StartSpanFromContext(ctx, "ProfileTypes") defer sp.Finish() lblReq := connect.NewRequest(&typesv1.LabelValuesRequest{ @@ -208,17 +202,19 @@ func (q *Querier) ProfileTypes(ctx context.Context, req *connect.Request[querier } func (q *Querier) LabelValues(ctx context.Context, req *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelValues") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelValues") defer sp.Finish() _, hasTimeRange := phlaremodel.GetTimeRange(req.Msg) - sp.LogFields( - otlog.Bool("legacy_request", !hasTimeRange), - otlog.String("name", req.Msg.Name), - otlog.String("matchers", strings.Join(req.Msg.Matchers, ",")), - otlog.Int64("start", req.Msg.Start), - otlog.Int64("end", req.Msg.End), - ) + sp.SetTag("legacy_request", !hasTimeRange) + sp.SetTag("name", req.Msg.Name) + sp.SetTag("matchers", strings.Join(req.Msg.Matchers, ",")) + sp.SetTag("start", req.Msg.Start) + sp.SetTag("end", req.Msg.End) + + if req.Msg.Name == "" { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("name is required")) + } if q.storeGatewayQuerier == nil || !hasTimeRange { responses, err := q.labelValuesFromIngesters(ctx, req.Msg) @@ -238,11 +234,11 @@ func (q *Querier) LabelValues(ctx context.Context, req *connect.Request[typesv1. var responses []ResponseFromReplica[[]string] var lock sync.Mutex - group, ctx := errgroup.WithContext(ctx) + group, gCtx := errgroup.WithContext(ctx) if storeQueries.ingester.shouldQuery { group.Go(func() error { - ir, err := q.labelValuesFromIngesters(ctx, storeQueries.ingester.LabelValuesRequest(req.Msg)) + ir, err := q.labelValuesFromIngesters(gCtx, storeQueries.ingester.LabelValuesRequest(req.Msg)) if err != nil { return err } @@ -256,7 +252,7 @@ func (q *Querier) LabelValues(ctx context.Context, req *connect.Request[typesv1. if storeQueries.storeGateway.shouldQuery { group.Go(func() error { - ir, err := q.labelValuesFromStoreGateway(ctx, storeQueries.storeGateway.LabelValuesRequest(req.Msg)) + ir, err := q.labelValuesFromStoreGateway(gCtx, storeQueries.storeGateway.LabelValuesRequest(req.Msg)) if err != nil { return err } @@ -278,25 +274,42 @@ func (q *Querier) LabelValues(ctx context.Context, req *connect.Request[typesv1. }), nil } +func filterLabelNames(labelNames []string) []string { + filtered := make([]string, 0, len(labelNames)) + // Filter out label names not passing legacy validation if utf8 label names not enabled + for _, labelName := range labelNames { + if !model.LegacyValidation.IsValidLabelName(labelName) { + continue + } + filtered = append(filtered, labelName) + } + return filtered +} + func (q *Querier) LabelNames(ctx context.Context, req *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelNames") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelNames") defer sp.Finish() _, hasTimeRange := phlaremodel.GetTimeRange(req.Msg) - sp.LogFields( - otlog.Bool("legacy_request", !hasTimeRange), - otlog.String("matchers", strings.Join(req.Msg.Matchers, ",")), - otlog.Int64("start", req.Msg.Start), - otlog.Int64("end", req.Msg.End), - ) + sp.SetTag("legacy_request", !hasTimeRange) + sp.SetTag("matchers", strings.Join(req.Msg.Matchers, ",")) + sp.SetTag("start", req.Msg.Start) + sp.SetTag("end", req.Msg.End) if q.storeGatewayQuerier == nil || !hasTimeRange { responses, err := q.labelNamesFromIngesters(ctx, req.Msg) if err != nil { return nil, err } + + labelNames := uniqueSortedStrings(responses) + if capabilities, ok := featureflags.GetClientCapabilities(ctx); !ok || !capabilities.AllowUtf8LabelNames { + level.Debug(q.logger).Log("msg", "filtering out non-valid labels") + labelNames = filterLabelNames(labelNames) + } + return connect.NewResponse(&typesv1.LabelNamesResponse{ - Names: uniqueSortedStrings(responses), + Names: labelNames, }), nil } @@ -308,11 +321,11 @@ func (q *Querier) LabelNames(ctx context.Context, req *connect.Request[typesv1.L var responses []ResponseFromReplica[[]string] var lock sync.Mutex - group, ctx := errgroup.WithContext(ctx) + group, gCtx := errgroup.WithContext(ctx) if storeQueries.ingester.shouldQuery { group.Go(func() error { - ir, err := q.labelNamesFromIngesters(ctx, storeQueries.ingester.LabelNamesRequest(req.Msg)) + ir, err := q.labelNamesFromIngesters(gCtx, storeQueries.ingester.LabelNamesRequest(req.Msg)) if err != nil { return err } @@ -326,7 +339,7 @@ func (q *Querier) LabelNames(ctx context.Context, req *connect.Request[typesv1.L if storeQueries.storeGateway.shouldQuery { group.Go(func() error { - ir, err := q.labelNamesFromStoreGateway(ctx, storeQueries.storeGateway.LabelNamesRequest(req.Msg)) + ir, err := q.labelNamesFromStoreGateway(gCtx, storeQueries.storeGateway.LabelNamesRequest(req.Msg)) if err != nil { return err } @@ -343,19 +356,23 @@ func (q *Querier) LabelNames(ctx context.Context, req *connect.Request[typesv1.L return nil, err } + labelNames := uniqueSortedStrings(responses) + if capabilities, ok := featureflags.GetClientCapabilities(ctx); !ok || !capabilities.AllowUtf8LabelNames { + level.Debug(q.logger).Log("msg", "filtering out non-valid labels") + labelNames = filterLabelNames(labelNames) + } + return connect.NewResponse(&typesv1.LabelNamesResponse{ - Names: uniqueSortedStrings(responses), + Names: labelNames, }), nil } func (q *Querier) blockSelect(ctx context.Context, start, end model.Time) (blockPlan, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "blockSelect") + sp, ctx := tracing.StartSpanFromContext(ctx, "blockSelect") defer sp.Finish() - sp.LogFields( - otlog.String("start", start.Time().String()), - otlog.String("end", end.Time().String()), - ) + sp.SetTag("start", start.Time().String()) + sp.SetTag("end", end.Time().String()) ingesterReq := &ingestv1.BlockMetadataRequest{ Start: int64(start), @@ -385,18 +402,61 @@ func (q *Querier) blockSelect(ctx context.Context, start, end model.Time) (block return results.blockPlan(ctx), nil } +// filterLabelNames filters out non-legacy (see model.LegacyValidation.IsValidLabelName) +// label names by default. If no label names are passed in the req, all label names +// are fetched and then filtered. Otherwise, the label names in the req are filtered. +// If the `AllowUtf8LabelNames` client capability is enabled, this function is a no-op. +func (q *Querier) filterLabelNames( + ctx context.Context, + req *connect.Request[querierv1.SeriesRequest], +) ([]string, error) { + if capabilities, ok := featureflags.GetClientCapabilities(ctx); ok && capabilities.AllowUtf8LabelNames { + return req.Msg.LabelNames, nil + } + + if len(req.Msg.LabelNames) == 0 { + // Querying for all label names; must retrieve all label names to then filter out + response, err := q.LabelNames(ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Matchers: req.Msg.Matchers, + Start: req.Msg.Start, + End: req.Msg.End, + })) + if err != nil { + return nil, err + } + return response.Msg.Names, nil + } + + // Filter out label names in request if not passing legacy validation + filtered := make([]string, 0, len(req.Msg.LabelNames)) + for _, name := range req.Msg.LabelNames { + if !model.LegacyValidation.IsValidLabelName(name) { + level.Debug(q.logger).Log("msg", "filtering out label", "label_name", name) + continue + } + filtered = append(filtered, name) + } + return filtered, nil +} + func (q *Querier) Series(ctx context.Context, req *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "Series") + sp, ctx := tracing.StartSpanFromContext(ctx, "Series") defer sp.Finish() _, hasTimeRange := phlaremodel.GetTimeRange(req.Msg) - sp.LogFields( - otlog.Bool("legacy_request", !hasTimeRange), - otlog.String("matchers", strings.Join(req.Msg.Matchers, ",")), - otlog.String("label_names", strings.Join(req.Msg.LabelNames, ",")), - otlog.Int64("start", req.Msg.Start), - otlog.Int64("end", req.Msg.End), - ) + sp.SetTag("legacy_request", !hasTimeRange) + sp.SetTag("matchers", strings.Join(req.Msg.Matchers, ",")) + sp.SetTag("label_names", strings.Join(req.Msg.LabelNames, ",")) + sp.SetTag("start", req.Msg.Start) + sp.SetTag("end", req.Msg.End) + + // Update LabelNames + filteredLabelNames, err := q.filterLabelNames(ctx, req) + if err != nil { + return nil, err + } + req.Msg.LabelNames = filteredLabelNames + // no store gateways configured so just query the ingesters if q.storeGatewayQuerier == nil || !hasTimeRange { responses, err := q.seriesFromIngesters(ctx, &ingestv1.SeriesRequest{ @@ -428,11 +488,11 @@ func (q *Querier) Series(ctx context.Context, req *connect.Request[querierv1.Ser var responses []ResponseFromReplica[[]*typesv1.Labels] var lock sync.Mutex - group, ctx := errgroup.WithContext(ctx) + group, gCtx := errgroup.WithContext(ctx) if storeQueries.ingester.shouldQuery { group.Go(func() error { - ir, err := q.seriesFromIngesters(ctx, storeQueries.ingester.SeriesRequest(req.Msg)) + ir, err := q.seriesFromIngesters(gCtx, storeQueries.ingester.SeriesRequest(req.Msg)) if err != nil { return err } @@ -446,7 +506,7 @@ func (q *Querier) Series(ctx context.Context, req *connect.Request[querierv1.Ser if storeQueries.storeGateway.shouldQuery { group.Go(func() error { - ir, err := q.seriesFromStoreGateway(ctx, storeQueries.storeGateway.SeriesRequest(req.Msg)) + ir, err := q.seriesFromStoreGateway(gCtx, storeQueries.storeGateway.SeriesRequest(req.Msg)) if err != nil { return err } @@ -458,7 +518,7 @@ func (q *Querier) Series(ctx context.Context, req *connect.Request[querierv1.Ser }) } - err := group.Wait() + err = group.Wait() if err != nil { return nil, err } @@ -477,23 +537,26 @@ func (q *Querier) Series(ctx context.Context, req *connect.Request[querierv1.Ser // FIXME(kolesnikovae): The method is never used and should be removed. func (q *Querier) Diff(ctx context.Context, req *connect.Request[querierv1.DiffRequest]) (*connect.Response[querierv1.DiffResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "Diff") + sp, ctx := tracing.StartSpanFromContext(ctx, "Diff") defer func() { - sp.LogFields( - otlog.String("leftStart", model.Time(req.Msg.Left.Start).Time().String()), - otlog.String("leftEnd", model.Time(req.Msg.Left.End).Time().String()), - // Assume are the same - otlog.String("selector", req.Msg.Left.LabelSelector), - otlog.String("profile_id", req.Msg.Left.ProfileTypeID), - ) + sp.SetTag("leftStart", model.Time(req.Msg.Left.Start).Time().String()) + sp.SetTag("leftEnd", model.Time(req.Msg.Left.End).Time().String()) + // Assume are the same + sp.SetTag("selector", req.Msg.Left.LabelSelector) + sp.SetTag("profile_id", req.Msg.Left.ProfileTypeID) sp.Finish() }() - var leftTree, rightTree *phlaremodel.Tree + // trace_id_selector is v2-only; selectTree would drop it. + if len(req.Msg.Left.GetTraceIdSelector()) > 0 || len(req.Msg.Right.GetTraceIdSelector()) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("trace_id_selector is only supported with the v2 query backend")) + } + + var leftTree, rightTree *phlaremodel.FunctionNameTree g, gCtx := errgroup.WithContext(ctx) g.Go(func() error { - res, err := q.selectTree(gCtx, req.Msg.Left) + res, err := q.selectStacktracesTree(gCtx, req.Msg.Left) if err != nil { return err } @@ -503,7 +566,7 @@ func (q *Querier) Diff(ctx context.Context, req *connect.Request[querierv1.DiffR }) g.Go(func() error { - res, err := q.selectTree(gCtx, req.Msg.Right) + res, err := q.selectStacktracesTree(gCtx, req.Msg.Right) if err != nil { return err } @@ -526,7 +589,7 @@ func (q *Querier) Diff(ctx context.Context, req *connect.Request[querierv1.DiffR } func (q *Querier) GetProfileStats(ctx context.Context, req *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "GetProfileStats") + sp, ctx := tracing.StartSpanFromContext(ctx, "GetProfileStats") defer sp.Finish() responses, err := forAllIngesters(ctx, q.ingesterQuerier, func(childCtx context.Context, ic IngesterQueryClient) (*typesv1.GetProfileStatsResponse, error) { @@ -583,7 +646,7 @@ func (q *Querier) GetProfileStats(ctx context.Context, req *connect.Request[type } func (q *Querier) SelectMergeStacktraces(ctx context.Context, req *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeStacktraces") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeStacktraces") level.Info(spanlogger.FromContext(ctx, q.logger)).Log( "start", model.Time(req.Msg.Start).Time().String(), "end", model.Time(req.Msg.End).Time().String(), @@ -594,12 +657,43 @@ func (q *Querier) SelectMergeStacktraces(ctx context.Context, req *connect.Reque sp.Finish() }() + if len(req.Msg.ProfileIdSelector) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("profile_id_selector is only supported with the v2 query backend")) + } + + if len(req.Msg.TraceIdSelector) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("trace_id_selector is only supported with the v2 query backend")) + } + + if req.Msg.Format == querierv1.ProfileFormat_PROFILE_FORMAT_DOT { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("dot format is only supported with the v2 query backend")) + } + if len(req.Msg.SpanSelector) > 0 && req.Msg.StackTraceSelector != nil { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("combining span_selector with stack_trace_selector is only supported with the v2 query backend")) + } + if req.Msg.Format == querierv1.ProfileFormat_PROFILE_FORMAT_PPROF && len(req.Msg.SpanSelector) == 0 { + resp, err := q.SelectMergeProfile(ctx, connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: req.Msg.ProfileTypeID, + LabelSelector: req.Msg.LabelSelector, + Start: req.Msg.Start, + End: req.Msg.End, + MaxNodes: req.Msg.MaxNodes, + StackTraceSelector: req.Msg.StackTraceSelector, + })) + if err != nil { + return nil, err + } + return connect.NewResponse(&querierv1.SelectMergeStacktracesResponse{ + Pprof: &querierv1.PprofProfile{Profile: resp.Msg}, + }), nil + } + if req.Msg.MaxNodes == nil || *req.Msg.MaxNodes == 0 { mn := maxNodesDefault req.Msg.MaxNodes = &mn } - t, err := q.selectTree(ctx, req.Msg) + t, err := q.selectStacktracesTree(ctx, req.Msg) if err != nil { return nil, err } @@ -609,13 +703,19 @@ func (q *Querier) SelectMergeStacktraces(ctx context.Context, req *connect.Reque default: resp.Flamegraph = phlaremodel.NewFlameGraph(t, req.Msg.GetMaxNodes()) case querierv1.ProfileFormat_PROFILE_FORMAT_TREE: - resp.Tree = t.Bytes(req.Msg.GetMaxNodes()) + resp.Tree = t.Bytes(req.Msg.GetMaxNodes(), nil) + case querierv1.ProfileFormat_PROFILE_FORMAT_PPROF: + profileType, err := phlaremodel.ParseProfileTypeSelector(req.Msg.ProfileTypeID) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + resp.Pprof = &querierv1.PprofProfile{Profile: pprof.FromTree(t, profileType, req.Msg.End*1e6)} } return connect.NewResponse(&resp), nil } func (q *Querier) SelectMergeSpanProfile(ctx context.Context, req *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeSpanProfile") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeSpanProfile") level.Info(spanlogger.FromContext(ctx, q.logger)).Log( "start", model.Time(req.Msg.Start).Time().String(), "end", model.Time(req.Msg.End).Time().String(), @@ -641,7 +741,7 @@ func (q *Querier) SelectMergeSpanProfile(ctx context.Context, req *connect.Reque default: resp.Flamegraph = phlaremodel.NewFlameGraph(t, req.Msg.GetMaxNodes()) case querierv1.ProfileFormat_PROFILE_FORMAT_TREE: - resp.Tree = t.Bytes(req.Msg.GetMaxNodes()) + resp.Tree = t.Bytes(req.Msg.GetMaxNodes(), nil) } return connect.NewResponse(&resp), nil } @@ -659,7 +759,7 @@ func isEndpointNotExistingErr(err error) bool { return err.Error() == "405 Method Not Allowed" } -func (q *Querier) selectTree(ctx context.Context, req *querierv1.SelectMergeStacktracesRequest) (*phlaremodel.Tree, error) { +func (q *Querier) selectTree(ctx context.Context, req *querierv1.SelectMergeStacktracesRequest) (*phlaremodel.FunctionNameTree, error) { // determine the block hints plan, err := q.blockSelect(ctx, model.Time(req.Start), model.Time(req.End)) if isEndpointNotExistingErr(err) { @@ -691,11 +791,11 @@ func (q *Querier) selectTree(ctx context.Context, req *querierv1.SelectMergeStac return q.selectTreeFromIngesters(ctx, storeQueries.ingester.MergeStacktracesRequest(req), plan) } - g, ctx := errgroup.WithContext(ctx) - var ingesterTree, storegatewayTree *phlaremodel.Tree + g, gCtx := errgroup.WithContext(ctx) + var ingesterTree, storegatewayTree *phlaremodel.FunctionNameTree g.Go(func() error { var err error - ingesterTree, err = q.selectTreeFromIngesters(ctx, storeQueries.ingester.MergeStacktracesRequest(req), plan) + ingesterTree, err = q.selectTreeFromIngesters(gCtx, storeQueries.ingester.MergeStacktracesRequest(req), plan) if err != nil { return err } @@ -716,6 +816,24 @@ func (q *Querier) selectTree(ctx context.Context, req *querierv1.SelectMergeStac return storegatewayTree, nil } +func (q *Querier) selectStacktracesTree(ctx context.Context, req *querierv1.SelectMergeStacktracesRequest) (*phlaremodel.FunctionNameTree, error) { + if len(req.SpanSelector) == 0 { + return q.selectTree(ctx, req) + } + if req.StackTraceSelector != nil || len(req.ProfileIdSelector) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("combining span_selector with stack_trace_selector or profile_id_selector is only supported with the v2 query backend")) + } + return q.selectSpanProfile(ctx, &querierv1.SelectMergeSpanProfileRequest{ + ProfileTypeID: req.ProfileTypeID, + LabelSelector: req.LabelSelector, + SpanSelector: req.SpanSelector, + Start: req.Start, + End: req.End, + MaxNodes: req.MaxNodes, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_TREE, + }) +} + type storeQuery struct { start, end model.Time shouldQuery bool @@ -832,10 +950,10 @@ func splitQueryToStores(start, end model.Time, now model.Time, queryStoreAfter t queries.queryStoreAfter = queryStoreAfter cutOff := now.Add(-queryStoreAfter) if start.Before(cutOff) { - queries.storeGateway = storeQuery{shouldQuery: true, start: start, end: pmath.Min(cutOff, end)} + queries.storeGateway = storeQuery{shouldQuery: true, start: start, end: min(cutOff, end)} } if end.After(cutOff) { - queries.ingester = storeQuery{shouldQuery: true, start: pmath.Max(cutOff, start), end: end} + queries.ingester = storeQuery{shouldQuery: true, start: max(cutOff, start), end: end} // Note that the ranges must not overlap. if queries.storeGateway.shouldQuery { queries.ingester.start++ @@ -845,14 +963,18 @@ func splitQueryToStores(start, end model.Time, now model.Time, queryStoreAfter t } func (q *Querier) SelectMergeProfile(ctx context.Context, req *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[googlev1.Profile], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectMergeProfile") - sp.SetTag("start", model.Time(req.Msg.Start).Time().String()). - SetTag("end", model.Time(req.Msg.End).Time().String()). - SetTag("selector", req.Msg.LabelSelector). - SetTag("max_nodes", req.Msg.GetMaxNodes()). - SetTag("profile_type", req.Msg.ProfileTypeID) + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectMergeProfile") + sp.SetTag("start", model.Time(req.Msg.Start).Time().String()) + sp.SetTag("end", model.Time(req.Msg.End).Time().String()) + sp.SetTag("selector", req.Msg.LabelSelector) + sp.SetTag("max_nodes", req.Msg.GetMaxNodes()) + sp.SetTag("profile_type", req.Msg.ProfileTypeID) defer sp.Finish() + if len(req.Msg.TraceIdSelector) > 0 { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("trace_id_selector is only supported with the v2 query backend")) + } + profile, err := q.selectProfile(ctx, req.Msg) if err != nil { return nil, err @@ -894,26 +1016,21 @@ func (q *Querier) selectProfile(ctx context.Context, req *querierv1.SelectMergeP return q.selectProfileFromIngesters(ctx, storeQueries.ingester.MergeProfileRequest(req), plan) } - g, ctx := errgroup.WithContext(ctx) - var lock sync.Mutex + g, gCtx := errgroup.WithContext(ctx) var merge pprof.ProfileMerge g.Go(func() error { - ingesterProfile, err := q.selectProfileFromIngesters(ctx, storeQueries.ingester.MergeProfileRequest(req), plan) + ingesterProfile, err := q.selectProfileFromIngesters(gCtx, storeQueries.ingester.MergeProfileRequest(req), plan) if err != nil { return err } - lock.Lock() - defer lock.Unlock() - return merge.Merge(ingesterProfile) + return merge.Merge(ingesterProfile, true) }) g.Go(func() error { - storegatewayProfile, err := q.selectProfileFromStoreGateway(ctx, storeQueries.storeGateway.MergeProfileRequest(req), plan) + storegatewayProfile, err := q.selectProfileFromStoreGateway(gCtx, storeQueries.storeGateway.MergeProfileRequest(req), plan) if err != nil { return err } - lock.Lock() - defer lock.Unlock() - return merge.Merge(storegatewayProfile) + return merge.Merge(storegatewayProfile, true) }) if err := g.Wait(); err != nil { return nil, err @@ -923,20 +1040,18 @@ func (q *Querier) selectProfile(ctx context.Context, req *querierv1.SelectMergeP } func (q *Querier) SelectSeries(ctx context.Context, req *connect.Request[querierv1.SelectSeriesRequest]) (*connect.Response[querierv1.SelectSeriesResponse], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectSeries") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectSeries") defer func() { - sp.LogFields( - otlog.String("start", model.Time(req.Msg.Start).Time().String()), - otlog.String("end", model.Time(req.Msg.End).Time().String()), - otlog.String("selector", req.Msg.LabelSelector), - otlog.String("profile_id", req.Msg.ProfileTypeID), - otlog.String("group_by", strings.Join(req.Msg.GroupBy, ",")), - otlog.Float64("step", req.Msg.Step), - ) + sp.SetTag("start", model.Time(req.Msg.Start).Time().String()) + sp.SetTag("end", model.Time(req.Msg.End).Time().String()) + sp.SetTag("selector", req.Msg.LabelSelector) + sp.SetTag("profile_id", req.Msg.ProfileTypeID) + sp.SetTag("group_by", strings.Join(req.Msg.GroupBy, ",")) + sp.SetTag("step", req.Msg.Step) sp.Finish() }() - _, err := parser.ParseMetricSelector(req.Msg.LabelSelector) + _, err := phlaremodel.ParseMetricSelector(req.Msg.LabelSelector) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -945,8 +1060,16 @@ func (q *Querier) SelectSeries(ctx context.Context, req *connect.Request[querier return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("start must be before end")) } - if req.Msg.Step == 0 { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("step must be non-zero")) + // Sub-millisecond step values truncate to 0 in stepMs and would cause an + // unbounded loop in RangeSeries; reject anything below 1ms. + if req.Msg.Step < 0.001 { + return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("step must be >= 1ms")) + } + + // SelectSeries (v1 API) does not support exemplars + if req.Msg.ExemplarType == typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL || + req.Msg.ExemplarType == typesv1.ExemplarType_EXEMPLAR_TYPE_SPAN { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("exemplars are not supported in SelectSeries API, use the v2 query API instead")) } stepMs := time.Duration(req.Msg.Step * float64(time.Second)).Milliseconds() @@ -975,7 +1098,7 @@ func (q *Querier) SelectSeries(ctx context.Context, req *connect.Request[querier return nil, connect.NewError(connect.CodeInternal, err) } - result := rangeSeries(it, req.Msg.Start, req.Msg.End, stepMs, req.Msg.Aggregation) + result := timeseries.RangeSeries(it, req.Msg.Start, req.Msg.End, stepMs, req.Msg.Aggregation) if it.Err() != nil { return nil, connect.NewError(connect.CodeInternal, it.Err()) } @@ -985,6 +1108,10 @@ func (q *Querier) SelectSeries(ctx context.Context, req *connect.Request[querier }), nil } +func (q *Querier) SelectHeatmap(ctx context.Context, req *connect.Request[querierv1.SelectHeatmapRequest]) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("SelectHeatmap not implemented in old querier")) +} + func (q *Querier) selectSeries(ctx context.Context, req *connect.Request[querierv1.SelectSeriesRequest], plan map[string]*blockPlanEntry) ([]ResponseFromReplica[clientpool.BidiClientMergeProfilesLabels], error) { stepMs := time.Duration(req.Msg.Step * float64(time.Second)).Milliseconds() sort.Strings(req.Msg.GroupBy) @@ -1040,77 +1167,6 @@ func (q *Querier) selectSeries(ctx context.Context, req *connect.Request[querier return responses, nil } -// rangeSeries aggregates profiles into series. -// Series contains points spaced by step from start to end. -// Profiles from the same step are aggregated into one point. -func rangeSeries(it iter.Iterator[ProfileValue], start, end, step int64, aggregation *typesv1.TimeSeriesAggregationType) []*typesv1.Series { - defer it.Close() - seriesMap := make(map[uint64]*typesv1.Series) - aggregators := make(map[uint64]TimeSeriesAggregator) - - if !it.Next() { - return nil - } - - // advance from the start to the end, adding each step results to the map. -Outer: - for currentStep := start; currentStep <= end; currentStep += step { - for { - aggregator, ok := aggregators[it.At().LabelsHash] - if !ok { - aggregator = NewTimeSeriesAggregator(aggregation) - aggregators[it.At().LabelsHash] = aggregator - } - if it.At().Ts > currentStep { - if !aggregator.IsEmpty() { - series := seriesMap[it.At().LabelsHash] - series.Points = append(series.Points, aggregator.GetAndReset()) - } - break // no more profiles for the currentStep - } - // find or create series - series, ok := seriesMap[it.At().LabelsHash] - if !ok { - seriesMap[it.At().LabelsHash] = &typesv1.Series{ - Labels: it.At().Lbs, - Points: []*typesv1.Point{}, - } - aggregator.Add(currentStep, it.At().Value) - if !it.Next() { - break Outer - } - continue - } - // Aggregate point if it is in the current step. - if aggregator.GetTimestamp() == currentStep { - aggregator.Add(currentStep, it.At().Value) - if !it.Next() { - break Outer - } - continue - } - // Next step is missing - if !aggregator.IsEmpty() { - series.Points = append(series.Points, aggregator.GetAndReset()) - } - aggregator.Add(currentStep, it.At().Value) - if !it.Next() { - break Outer - } - } - } - for lblHash, aggregator := range aggregators { - if !aggregator.IsEmpty() { - seriesMap[lblHash].Points = append(seriesMap[lblHash].Points, aggregator.GetAndReset()) - } - } - series := lo.Values(seriesMap) - sort.Slice(series, func(i, j int) bool { - return phlaremodel.CompareLabelPairs(series[i].Labels, series[j].Labels) < 0 - }) - return series -} - func uniqueSortedStrings(responses []ResponseFromReplica[[]string]) []string { total := 0 for _, r := range responses { @@ -1130,7 +1186,7 @@ func uniqueSortedStrings(responses []ResponseFromReplica[[]string]) []string { return result } -func (q *Querier) selectSpanProfile(ctx context.Context, req *querierv1.SelectMergeSpanProfileRequest) (*phlaremodel.Tree, error) { +func (q *Querier) selectSpanProfile(ctx context.Context, req *querierv1.SelectMergeSpanProfileRequest) (*phlaremodel.FunctionNameTree, error) { // determine the block hints plan, err := q.blockSelect(ctx, model.Time(req.Start), model.Time(req.End)) if isEndpointNotExistingErr(err) { @@ -1162,11 +1218,11 @@ func (q *Querier) selectSpanProfile(ctx context.Context, req *querierv1.SelectMe return q.selectSpanProfileFromIngesters(ctx, storeQueries.ingester.MergeSpanProfileRequest(req), plan) } - g, ctx := errgroup.WithContext(ctx) - var ingesterTree, storegatewayTree *phlaremodel.Tree + g, gCtx := errgroup.WithContext(ctx) + var ingesterTree, storegatewayTree *phlaremodel.FunctionNameTree g.Go(func() error { var err error - ingesterTree, err = q.selectSpanProfileFromIngesters(ctx, storeQueries.ingester.MergeSpanProfileRequest(req), plan) + ingesterTree, err = q.selectSpanProfileFromIngesters(gCtx, storeQueries.ingester.MergeSpanProfileRequest(req), plan) if err != nil { return err } @@ -1174,7 +1230,7 @@ func (q *Querier) selectSpanProfile(ctx context.Context, req *querierv1.SelectMe }) g.Go(func() error { var err error - storegatewayTree, err = q.selectSpanProfileFromStoreGateway(ctx, storeQueries.storeGateway.MergeSpanProfileRequest(req), plan) + storegatewayTree, err = q.selectSpanProfileFromStoreGateway(gCtx, storeQueries.storeGateway.MergeSpanProfileRequest(req), plan) if err != nil { return err } @@ -1186,87 +1242,3 @@ func (q *Querier) selectSpanProfile(ctx context.Context, req *querierv1.SelectMe storegatewayTree.Merge(ingesterTree) return storegatewayTree, nil } - -type TimeSeriesAggregator interface { - Add(ts int64, value float64) - GetAndReset() *typesv1.Point - IsEmpty() bool - GetTimestamp() int64 -} - -func NewTimeSeriesAggregator(aggregation *typesv1.TimeSeriesAggregationType) TimeSeriesAggregator { - if aggregation == nil { - return &sumTimeSeriesAggregator{ - ts: -1, - } - } - if *aggregation == typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_AVERAGE { - return &avgTimeSeriesAggregator{ - ts: -1, - } - } - return &sumTimeSeriesAggregator{ - ts: -1, - } -} - -type sumTimeSeriesAggregator struct { - ts int64 - sum float64 -} - -func (a *sumTimeSeriesAggregator) Add(ts int64, value float64) { - a.ts = ts - a.sum += value -} - -func (a *sumTimeSeriesAggregator) GetAndReset() *typesv1.Point { - tsCopy := a.ts - sumCopy := a.sum - a.ts = -1 - a.sum = 0 - return &typesv1.Point{ - Timestamp: tsCopy, - Value: sumCopy, - } -} - -func (a *sumTimeSeriesAggregator) IsEmpty() bool { - return a.ts == -1 -} - -func (a *sumTimeSeriesAggregator) GetTimestamp() int64 { - return a.ts -} - -type avgTimeSeriesAggregator struct { - ts int64 - sum float64 - count int64 -} - -func (a *avgTimeSeriesAggregator) Add(ts int64, value float64) { - a.ts = ts - a.sum += value - a.count++ -} - -func (a *avgTimeSeriesAggregator) GetAndReset() *typesv1.Point { - avg := a.sum / float64(a.count) - tsCopy := a.ts - a.ts = -1 - a.sum = 0 - a.count = 0 - return &typesv1.Point{ - Timestamp: tsCopy, - Value: avg, - } -} - -func (a *avgTimeSeriesAggregator) IsEmpty() bool { - return a.ts == -1 -} - -func (a *avgTimeSeriesAggregator) GetTimestamp() int64 { - return a.ts -} diff --git a/pkg/querier/querier_test.go b/pkg/querier/querier_test.go index 0183acbc8f..c65084e6b5 100644 --- a/pkg/querier/querier_test.go +++ b/pkg/querier/querier_test.go @@ -9,6 +9,7 @@ import ( "os" "path" "sort" + "sync" "testing" "time" @@ -23,23 +24,25 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/health/grpc_health_v1" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/clientpool" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - objstoreclient "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb/bucketindex" - "github.com/grafana/pyroscope/pkg/pprof" - pprofth "github.com/grafana/pyroscope/pkg/pprof/testhelper" - "github.com/grafana/pyroscope/pkg/storegateway" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/testhelper" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + "github.com/grafana/pyroscope/v2/pkg/featureflags" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucketindex" + "github.com/grafana/pyroscope/v2/pkg/pprof" + pprofth "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/storegateway" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/util" ) type poolFactory struct { @@ -169,6 +172,205 @@ func Test_QueryLabelNames(t *testing.T) { require.Equal(t, []string{"bar", "buzz", "foo"}, out.Msg.Names) } +func Test_filterLabelNames(t *testing.T) { + tests := []struct { + name string + labelNames []string + want []string + }{ + { + name: "empty slice", + labelNames: []string{}, + want: []string{}, + }, + { + name: "nil slice", + labelNames: nil, + want: []string{}, + }, + { + name: "all valid label names", + labelNames: []string{"foo", "bar", "service_name", "ServiceName123"}, + want: []string{"foo", "bar", "service_name", "ServiceName123"}, + }, + { + name: "all invalid label names", + labelNames: []string{"123service", "service-name", "service name", "世界"}, + want: []string{}, + }, + { + name: "mix of valid and invalid label names", + labelNames: []string{"foo", "123invalid", "bar", "invalid-name", "buzz", "世界"}, + want: []string{"foo", "bar", "buzz"}, + }, + { + name: "label names with dots", + labelNames: []string{"service.name", "app.version", "valid_label"}, + want: []string{"valid_label"}, + }, + { + name: "single valid label", + labelNames: []string{"service"}, + want: []string{"service"}, + }, + { + name: "single invalid label", + labelNames: []string{"123invalid"}, + want: []string{}, + }, + { + name: "labels with underscores", + labelNames: []string{"_", "__a", "__a__", "_service_name_"}, + want: []string{"_", "__a", "__a__", "_service_name_"}, + }, + { + name: "mixed labels with dots and underscores", + labelNames: []string{"a.b.c", "a_b_c", "a.b_c.d"}, + want: []string{"a_b_c"}, + }, + { + name: "labels starting with dots", + labelNames: []string{".abc", "..def", ".g.h.i"}, + want: []string{}, + }, + { + name: "labels starting with invalid characters", + labelNames: []string{"-abc", "0abc", "123xyz"}, + want: []string{}, + }, + { + name: "empty string in slice (invalid)", + labelNames: []string{"foo", "", "bar"}, + want: []string{"foo", "bar"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := filterLabelNames(tt.labelNames) + require.Equal(t, tt.want, got) + }) + } +} + +func Test_QueryLabelNames_WithFiltering(t *testing.T) { + req := connect.NewRequest(&typesv1.LabelNamesRequest{}) + + tests := []struct { + name string + allowUtf8LabelNames bool + setCapabilities bool + ingesterLabelNames map[string][]string + expectedLabelNames []string + }{ + { + name: "UTF8 labels allowed when enabled", + allowUtf8LabelNames: true, + setCapabilities: true, + ingesterLabelNames: map[string][]string{ + "1": {"foo", "bar", "世界"}, + "2": {"foo", "bar", "世界"}, + "3": {"foo", "bar", "世界"}, + }, + // UTF8 labels pass through when UTF8 is enabled + expectedLabelNames: []string{"bar", "foo", "世界"}, + }, + { + name: "UTF8 labels filtered when disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + ingesterLabelNames: map[string][]string{ + "1": {"foo", "bar", "世界"}, + "2": {"foo", "bar", "世界"}, + "3": {"foo", "bar", "世界"}, + }, + // Only legacy-valid labels pass through (UTF8 filtered out) + expectedLabelNames: []string{"bar", "foo"}, + }, + { + name: "all labels pass through when UTF8 enabled including invalid ones", + allowUtf8LabelNames: true, + setCapabilities: true, + ingesterLabelNames: map[string][]string{ + "1": {"foo", "123invalid"}, + "2": {"foo", "123invalid"}, + "3": {"foo", "123invalid"}, + }, + // When UTF8 is enabled, NO filtering happens - even invalid labels pass through + expectedLabelNames: []string{"123invalid", "foo"}, + }, + { + name: "filtering enabled when no capabilities set", + setCapabilities: false, + ingesterLabelNames: map[string][]string{ + "1": {"valid_name", "123invalid", "世界"}, + "2": {"valid_name", "123invalid", "世界"}, + "3": {"valid_name", "123invalid", "世界"}, + }, + // No capabilities means legacy-only mode - UTF8 and invalid labels filtered + expectedLabelNames: []string{"valid_name"}, + }, + { + name: "all valid legacy labels pass through when filtering enabled", + allowUtf8LabelNames: false, + setCapabilities: true, + ingesterLabelNames: map[string][]string{ + "1": {"foo", "bar"}, + "2": {"bar", "buzz"}, + "3": {"buzz", "foo"}, + }, + expectedLabelNames: []string{"bar", "buzz", "foo"}, + }, + { + name: "labels with dots filtered when disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + ingesterLabelNames: map[string][]string{ + "1": {"service.name", "app.version"}, + "2": {"host.name", "service.name"}, + "3": {"app.version", "host.name"}, + }, + expectedLabelNames: []string{}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + querier, err := New(&NewQuerierParams{ + Cfg: Config{ + PoolConfig: clientpool.PoolConfig{ClientCleanupPeriod: 1 * time.Millisecond}, + }, + IngestersRing: testhelper.NewMockRing([]ring.InstanceDesc{ + {Addr: "1"}, + {Addr: "2"}, + {Addr: "3"}, + }, 3), + PoolFactory: &poolFactory{f: func(addr string) (client.PoolClient, error) { + q := newFakeQuerier() + if labelNames, ok := tc.ingesterLabelNames[addr]; ok { + q.On("LabelNames", mock.Anything, mock.Anything).Return( + connect.NewResponse(&typesv1.LabelNamesResponse{Names: labelNames}), nil) + } + return q, nil + }}, + Logger: log.NewLogfmtLogger(os.Stdout), + }) + require.NoError(t, err) + + ctx := context.Background() + if tc.setCapabilities { + ctx = featureflags.WithClientCapabilities(ctx, featureflags.ClientCapabilities{ + AllowUtf8LabelNames: tc.allowUtf8LabelNames, + }) + } + + out, err := querier.LabelNames(ctx, req) + require.NoError(t, err) + require.Equal(t, tc.expectedLabelNames, out.Msg.Names) + }) + } +} + func Test_Series(t *testing.T) { foobarlabels := phlaremodel.NewLabelsBuilder(nil).Set("foo", "bar") foobuzzlabels := phlaremodel.NewLabelsBuilder(nil).Set("foo", "buzz") @@ -190,10 +392,13 @@ func Test_Series(t *testing.T) { q := newFakeQuerier() switch addr { case "1": + q.On("LabelNames", mock.Anything, mock.Anything).Return(connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}), nil) q.On("Series", mock.Anything, mock.Anything).Return(ingesterResponse, nil) case "2": + q.On("LabelNames", mock.Anything, mock.Anything).Return(connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}), nil) q.On("Series", mock.Anything, mock.Anything).Return(ingesterResponse, nil) case "3": + q.On("LabelNames", mock.Anything, mock.Anything).Return(connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar"}}), nil) q.On("Series", mock.Anything, mock.Anything).Return(ingesterResponse, nil) } return q, nil @@ -210,6 +415,139 @@ func Test_Series(t *testing.T) { }, out.Msg.LabelsSet) } +func Test_Series_WithLabelNameFiltering(t *testing.T) { + tests := []struct { + name string + allowUtf8LabelNames bool + setCapabilities bool + requestLabelNames []string + expectedLabelNames []string + }{ + { + name: "all label names pass through when UTF8 enabled", + allowUtf8LabelNames: true, + setCapabilities: true, + requestLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + expectedLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + }, + { + name: "invalid label names filtered when UTF8 disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"valid_name", "123invalid", "invalid-hyphen", "世界"}, + expectedLabelNames: []string{"valid_name"}, + }, + { + name: "UTF8 labels filtered when UTF8 disabled", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"foo", "bar", "世界", "日本語"}, + expectedLabelNames: []string{"foo", "bar"}, + }, + { + name: "filtering enabled when no capabilities set", + setCapabilities: false, + requestLabelNames: []string{"foo", "123invalid", "世界"}, + expectedLabelNames: []string{"foo"}, + }, + { + name: "all valid labels pass through", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"foo", "bar", "service_name"}, + expectedLabelNames: []string{"foo", "bar", "service_name"}, + }, + { + name: "labels with dots do not pass through", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{"service.name", "app.version", "foo"}, + expectedLabelNames: []string{"foo"}, + }, + { + name: "empty label names with UTF8 disabled queries all labels and filters", + allowUtf8LabelNames: false, + setCapabilities: true, + requestLabelNames: []string{}, + expectedLabelNames: []string{"bar", "foo"}, + }, + { + name: "empty label names with UTF8 enabled returns ingester labels without filtering", + allowUtf8LabelNames: true, + setCapabilities: true, + requestLabelNames: []string{}, + expectedLabelNames: []string{"日本語", "bar"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ingesterLabels := []string{"日本語", "bar"} + var capturedLabelNames []string + var capturedMutex sync.Mutex + + querier, err := New(&NewQuerierParams{ + Cfg: Config{ + PoolConfig: clientpool.PoolConfig{ClientCleanupPeriod: 1 * time.Millisecond}, + }, + IngestersRing: testhelper.NewMockRing([]ring.InstanceDesc{ + {Addr: "1"}, + {Addr: "2"}, + {Addr: "3"}, + }, 3), + PoolFactory: &poolFactory{f: func(addr string) (client.PoolClient, error) { + q := newFakeQuerier() + + q.On("Series", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + req := args.Get(1).(*connect.Request[ingestv1.SeriesRequest]) + capturedMutex.Lock() + defer capturedMutex.Unlock() + + // If no labels passed to ingester series request, + // ingester returns all ingester labels + if len(req.Msg.LabelNames) == 0 { + capturedLabelNames = ingesterLabels + } else { + capturedLabelNames = req.Msg.LabelNames + } + }).Return(connect.NewResponse(&ingestv1.SeriesResponse{}), nil) + + if len(tc.requestLabelNames) == 0 { + q.On("LabelNames", mock.Anything, mock.Anything).Return( + connect.NewResponse(&typesv1.LabelNamesResponse{Names: []string{"foo", "bar", "世界"}}), nil) + } + + return q, nil + }}, + Logger: log.NewLogfmtLogger(os.Stdout), + }) + require.NoError(t, err) + + ctx := context.Background() + if tc.setCapabilities { + ctx = featureflags.WithClientCapabilities(ctx, featureflags.ClientCapabilities{ + AllowUtf8LabelNames: tc.allowUtf8LabelNames, + }) + } + + req := connect.NewRequest(&querierv1.SeriesRequest{ + Matchers: []string{`{foo="bar"}`}, + LabelNames: tc.requestLabelNames, + }) + + _, err = querier.Series(ctx, req) + require.NoError(t, err) + + // Verify that the label names were filtered correctly before being sent to ingester + capturedMutex.Lock() + actualLabelNames := capturedLabelNames + capturedMutex.Unlock() + require.Equal(t, tc.expectedLabelNames, actualLabelNames, + "Expected label names sent to ingester to be %v, but got %v", tc.expectedLabelNames, actualLabelNames) + }) + } +} + func newBlockMeta(ulids ...string) *connect.Response[ingestv1.BlockMetadataResponse] { resp := &ingestv1.BlockMetadataResponse{} @@ -531,7 +869,7 @@ func TestSelectSeries(t *testing.T) { {Timestamp: 2, LabelIndex: 0}, }, }, - }, &typesv1.Series{Labels: foobarlabels, Points: []*typesv1.Point{{Value: 1, Timestamp: 1}, {Value: 2, Timestamp: 2}}}) + }, &typesv1.Series{Labels: foobarlabels, Points: []*typesv1.Point{{Value: 1, Timestamp: 1, Annotations: []*typesv1.ProfileAnnotation{}}, {Value: 2, Timestamp: 2, Annotations: []*typesv1.ProfileAnnotation{}}}}) bidi2 := newFakeBidiClientSeries([]*ingestv1.ProfileSets{ { LabelsSets: []*typesv1.Labels{ @@ -548,7 +886,7 @@ func TestSelectSeries(t *testing.T) { {Timestamp: 2, LabelIndex: 1}, }, }, - }, &typesv1.Series{Labels: foobarlabels, Points: []*typesv1.Point{{Value: 1, Timestamp: 1}, {Value: 2, Timestamp: 2}}}) + }, &typesv1.Series{Labels: foobarlabels, Points: []*typesv1.Point{{Value: 1, Timestamp: 1, Annotations: []*typesv1.ProfileAnnotation{}}, {Value: 2, Timestamp: 2, Annotations: []*typesv1.ProfileAnnotation{}}}}) bidi3 := newFakeBidiClientSeries([]*ingestv1.ProfileSets{ { LabelsSets: []*typesv1.Labels{ @@ -565,7 +903,7 @@ func TestSelectSeries(t *testing.T) { {Timestamp: 2, LabelIndex: 0}, }, }, - }, &typesv1.Series{Labels: foobarlabels, Points: []*typesv1.Point{{Value: 1, Timestamp: 1}, {Value: 2, Timestamp: 2}}}) + }, &typesv1.Series{Labels: foobarlabels, Points: []*typesv1.Point{{Value: 1, Timestamp: 1, Annotations: []*typesv1.ProfileAnnotation{}}, {Value: 2, Timestamp: 2, Annotations: []*typesv1.ProfileAnnotation{}}}}) querier, err := New(&NewQuerierParams{ Cfg: Config{ PoolConfig: clientpool.PoolConfig{ClientCleanupPeriod: 1 * time.Millisecond}, @@ -594,7 +932,7 @@ func TestSelectSeries(t *testing.T) { require.NoError(t, err) // Only 2 results are used since the 3rd not required because of replication. testhelper.EqualProto(t, []*typesv1.Series{ - {Labels: foobarlabels, Points: []*typesv1.Point{{Value: 2, Timestamp: 1}, {Value: 4, Timestamp: 2}}}, + {Labels: foobarlabels, Points: []*typesv1.Point{{Value: 2, Timestamp: 1, Annotations: []*typesv1.ProfileAnnotation{}}, {Value: 4, Timestamp: 2, Annotations: []*typesv1.ProfileAnnotation{}}}}, }, res.Msg.Series) var selected []testProfile selected = append(selected, bidi1.kept...) @@ -627,6 +965,10 @@ func newFakeQuerier() *fakeQuerierIngester { return &fakeQuerierIngester{} } +func (f *fakeQuerierIngester) List(ctx context.Context, in *grpc_health_v1.HealthListRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthListResponse, error) { + return nil, errors.New("not implemented") +} + func (f *fakeQuerierIngester) mockMergeStacktraces(bidi *fakeBidiClientStacktraces, blocks []string, blockSelect bool) { if blockSelect { f.On("BlockMetadata", mock.Anything, mock.Anything).Once().Return(newBlockMeta(blocks...), nil) @@ -828,7 +1170,7 @@ func (f *fakeBidiClientStacktraces) Receive() (*ingestv1.MergeProfilesStacktrace func (f *fakeBidiClientStacktraces) CloseRequest() error { return nil } func (f *fakeBidiClientStacktraces) CloseResponse() error { return nil } -func requireFakeMergeProfilesStacktracesResultTree(t *testing.T, r *phlaremodel.Tree) { +func requireFakeMergeProfilesStacktracesResultTree(t *testing.T, r *phlaremodel.FunctionNameTree) { flame := phlaremodel.NewFlameGraph(r, -1) sort.Strings(flame.Names) require.Equal(t, []string{"bar", "buzz", "foo", "total"}, flame.Names) @@ -1005,147 +1347,6 @@ func (f *fakeQuerierIngester) MergeProfilesPprof(ctx context.Context) clientpool return res } -func Test_RangeSeriesSum(t *testing.T) { - for _, tc := range []struct { - name string - in []ProfileValue - out []*typesv1.Series - }{ - { - name: "single series", - in: []ProfileValue{ - {Ts: 1, Value: 1}, - {Ts: 1, Value: 1}, - {Ts: 2, Value: 2}, - {Ts: 3, Value: 3}, - {Ts: 4, Value: 4}, - {Ts: 5, Value: 5}, - }, - out: []*typesv1.Series{ - { - Points: []*typesv1.Point{ - {Timestamp: 1, Value: 2}, - {Timestamp: 2, Value: 2}, - {Timestamp: 3, Value: 3}, - {Timestamp: 4, Value: 4}, - {Timestamp: 5, Value: 5}, - }, - }, - }, - }, - { - name: "multiple series", - in: []ProfileValue{ - {Ts: 1, Value: 1, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - {Ts: 1, Value: 1, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 2, Value: 1, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - {Ts: 3, Value: 1, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 3, Value: 1, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 4, Value: 4, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 4, Value: 4, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 4, Value: 4, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - {Ts: 5, Value: 5, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - }, - out: []*typesv1.Series{ - { - Labels: foobarlabels, - Points: []*typesv1.Point{ - {Timestamp: 1, Value: 1}, - {Timestamp: 2, Value: 1}, - {Timestamp: 4, Value: 4}, - {Timestamp: 5, Value: 5}, - }, - }, - { - Labels: foobuzzlabels, - Points: []*typesv1.Point{ - {Timestamp: 1, Value: 1}, - {Timestamp: 3, Value: 2}, - {Timestamp: 4, Value: 8}, - }, - }, - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - in := iter.NewSliceIterator(tc.in) - out := rangeSeries(in, 1, 5, 1, nil) - testhelper.EqualProto(t, tc.out, out) - }) - } -} - -func Test_RangeSeriesAvg(t *testing.T) { - for _, tc := range []struct { - name string - in []ProfileValue - out []*typesv1.Series - }{ - { - name: "single series", - in: []ProfileValue{ - {Ts: 1, Value: 1}, - {Ts: 1, Value: 2}, - {Ts: 2, Value: 2}, - {Ts: 2, Value: 3}, - {Ts: 3, Value: 4}, - {Ts: 4, Value: 5}, - }, - out: []*typesv1.Series{ - { - Points: []*typesv1.Point{ - {Timestamp: 1, Value: 1.5}, // avg of 1 and 2 - {Timestamp: 2, Value: 2.5}, // avg of 2 and 3 - {Timestamp: 3, Value: 4}, - {Timestamp: 4, Value: 5}, - }, - }, - }, - }, - { - name: "multiple series", - in: []ProfileValue{ - {Ts: 1, Value: 1, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - {Ts: 1, Value: 1, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 2, Value: 1, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - {Ts: 2, Value: 2, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - {Ts: 3, Value: 1, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 3, Value: 2, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 4, Value: 4, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 4, Value: 6, Lbs: foobuzzlabels, LabelsHash: foobuzzlabels.Hash()}, - {Ts: 4, Value: 4, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - {Ts: 5, Value: 5, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, - }, - out: []*typesv1.Series{ - { - Labels: foobarlabels, - Points: []*typesv1.Point{ - {Timestamp: 1, Value: 1}, - {Timestamp: 2, Value: 1.5}, // avg of 1 and 2 - {Timestamp: 4, Value: 4}, - {Timestamp: 5, Value: 5}, - }, - }, - { - Labels: foobuzzlabels, - Points: []*typesv1.Point{ - {Timestamp: 1, Value: 1}, - {Timestamp: 3, Value: 1.5}, // avg of 1 and 2 - {Timestamp: 4, Value: 5}, // avg of 4 and 6 - }, - }, - }, - }, - } { - t.Run(tc.name, func(t *testing.T) { - in := iter.NewSliceIterator(tc.in) - aggregation := typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_AVERAGE - out := rangeSeries(in, 1, 5, 1, &aggregation) - testhelper.EqualProto(t, tc.out, out) - }) - } -} - func Test_splitQueryToStores(t *testing.T) { for _, tc := range []struct { name string @@ -1392,7 +1593,7 @@ func Test_GetProfileStats(t *testing.T) { Directory: dbPath, }, }, - StoragePrefix: "testdata", + Prefix: "testdata", }, "") require.NoError(t, err) diff --git a/pkg/querier/replication.go b/pkg/querier/replication.go index fce35368ce..ad77882560 100644 --- a/pkg/querier/replication.go +++ b/pkg/querier/replication.go @@ -10,16 +10,15 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/ring" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" + "github.com/grafana/dskit/tracing" "github.com/samber/lo" "golang.org/x/sync/errgroup" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/spanlogger" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/spanlogger" ) type ResponseFromReplica[T any] struct { @@ -89,7 +88,12 @@ func forGivenReplicationSet[Result any, Querier any](ctx context.Context, client } // forGivenPlan runs f, in parallel, for given plan. -func forGivenPlan[Result any, Querier any](ctx context.Context, plan map[string]*blockPlanEntry, clientFactory func(string) (Querier, error), replicationSet ring.ReplicationSet, f QueryReplicaWithHintsFn[Result, Querier]) ([]ResponseFromReplica[Result], error) { +func forGivenPlan[Result any, Querier any]( + ctx context.Context, + plan map[string]*blockPlanEntry, + clientFactory func(string) (Querier, error), + replicationSet ring.ReplicationSet, f QueryReplicaWithHintsFn[Result, Querier], +) ([]ResponseFromReplica[Result], error) { g, _ := errgroup.WithContext(ctx) var ( @@ -343,7 +347,7 @@ func (p blockPlan) String() string { } func (r *replicasPerBlockID) blockPlan(ctx context.Context) map[string]*blockPlanEntry { - sp, _ := opentracing.StartSpanFromContext(ctx, "blockPlan") + sp, _ := tracing.StartSpanFromContext(ctx, "blockPlan") defer sp.Finish() var ( @@ -461,12 +465,10 @@ func (r *replicasPerBlockID) blockPlan(ctx context.Context) map[string]*blockPla } } - sp.LogFields( - otlog.Bool("deduplicate", deduplicate), - otlog.Int32("smallest_compaction_level", smallestCompactionLevel), - otlog.Int("planned_blocks_ingesters", plannedIngesterBlocks), - otlog.Int("planned_blocks_store_gateways", plannedStoreGatewayBlocks), - ) + sp.SetTag("deduplicate", deduplicate) + sp.SetTag("smallest_compaction_level", smallestCompactionLevel) + sp.SetTag("planned_blocks_ingesters", plannedIngesterBlocks) + sp.SetTag("planned_blocks_store_gateways", plannedStoreGatewayBlocks) level.Debug(spanlogger.FromContext(ctx, r.logger)).Log( "msg", "block plan created", diff --git a/pkg/querier/replication_test.go b/pkg/querier/replication_test.go index ea452181ca..c834b423e0 100644 --- a/pkg/querier/replication_test.go +++ b/pkg/querier/replication_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/phlaredb/sharding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/sharding" ) type blockInfo struct { diff --git a/pkg/querier/select_merge.go b/pkg/querier/select_merge.go index e4bb2a48c6..f299a716ea 100644 --- a/pkg/querier/select_merge.go +++ b/pkg/querier/select_merge.go @@ -8,21 +8,22 @@ import ( "time" "github.com/grafana/dskit/multierror" - "github.com/opentracing/opentracing-go" - otlog "github.com/opentracing/opentracing-go/log" - "github.com/prometheus/common/model" + "github.com/grafana/dskit/tracing" "github.com/samber/lo" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "golang.org/x/sync/errgroup" googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/clientpool" - "github.com/grafana/pyroscope/pkg/iter" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/loser" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/loser" ) type ProfileWithLabels struct { @@ -249,7 +250,7 @@ func (s *mergeIterator[R, Req, Res]) Close() error { // skipDuplicates iterates through the iterator and skip duplicates. func skipDuplicates(ctx context.Context, its []MergeIterator) error { - span, _ := opentracing.StartSpanFromContext(ctx, "skipDuplicates") + span, _ := tracing.StartSpanFromContext(ctx, "skipDuplicates") defer span.Finish() var errors multierror.MultiError tree := loser.New(its, @@ -281,7 +282,7 @@ func skipDuplicates(ctx context.Context, its []MergeIterator) error { total++ fingerprint := profile.Fingerprint if fingerprint == 0 && len(profile.Labels) > 0 { - fingerprint = profile.Labels.Hash() + fingerprint = profile.Hash() } if fingerprints.keep(profile.Timestamp, fingerprint) { next.Keep() @@ -289,8 +290,8 @@ func skipDuplicates(ctx context.Context, its []MergeIterator) error { } duplicates++ } - span.LogFields(otlog.Int("duplicates", duplicates)) - span.LogFields(otlog.Int("total", total)) + span.SetTag("duplicates", duplicates) + span.SetTag("total", total) if err := tree.Err(); err != nil { errors.Add(err) } @@ -336,8 +337,8 @@ func (p *timestampedFingerprints) fingerprintSeen(fingerprint uint64) (seen bool // selectMergeTree selects the profile from each ingester by deduping them and // returns merge of stacktrace samples represented as a tree. -func selectMergeTree(ctx context.Context, responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesStacktraces]) (*phlaremodel.Tree, error) { - span, ctx := opentracing.StartSpanFromContext(ctx, "selectMergeTree") +func selectMergeTree(ctx context.Context, responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesStacktraces]) (*phlaremodel.FunctionNameTree, error) { + span, ctx := tracing.StartSpanFromContext(ctx, "selectMergeTree") defer span.Finish() mergeResults := make([]MergeResult[*ingestv1.MergeProfilesStacktracesResult], len(responses)) @@ -363,9 +364,9 @@ func selectMergeTree(ctx context.Context, responses []ResponseFromReplica[client } // Collects the results in parallel. - span.LogFields(otlog.String("msg", "collecting merge results")) + trace.SpanFromContext(ctx).AddEvent("collecting merge results") g, _ := errgroup.WithContext(ctx) - m := phlaremodel.NewTreeMerger() + m := phlaremodel.NewTreeMerger[phlaremodel.FunctionName, phlaremodel.FunctionNameI]() sm := phlaremodel.NewStackTraceMerger() for _, iter := range mergeResults { iter := iter @@ -396,7 +397,7 @@ func selectMergeTree(ctx context.Context, responses []ResponseFromReplica[client } } - span.LogFields(otlog.String("msg", "building tree")) + trace.SpanFromContext(ctx).AddEvent("building tree") return m.Tree(), nil } @@ -424,9 +425,7 @@ func selectMergePprofProfile(ctx context.Context, ty *typesv1.ProfileType, respo return nil, err } - span := opentracing.SpanFromContext(ctx) - // Collects the results in parallel. - var lock sync.Mutex + otelSpan := trace.SpanFromContext(ctx) var pprofMerge pprof.ProfileMerge g, _ := errgroup.WithContext(ctx) for _, iter := range mergeResults { @@ -437,19 +436,17 @@ func selectMergePprofProfile(ctx context.Context, ty *typesv1.ProfileType, respo if err != nil || result == nil { return err } - if span != nil { - span.LogFields( - otlog.Int("profile_size", len(result)), - otlog.Int64("took_ms", time.Since(start).Milliseconds()), - ) - } + otelSpan.AddEvent("profile merged", + trace.WithAttributes( + attribute.Int("profile_size", len(result)), + attribute.Int64("took_ms", time.Since(start).Milliseconds()), + ), + ) var p googlev1.Profile if err = pprof.Unmarshal(result, &p); err != nil { return err } - lock.Lock() - defer lock.Unlock() - return pprofMerge.Merge(&p) + return pprofMerge.Merge(&p, true) })) } if err := g.Wait(); err != nil { @@ -463,23 +460,8 @@ func selectMergePprofProfile(ctx context.Context, ty *typesv1.ProfileType, respo return p, nil } -type ProfileValue struct { - Ts int64 - Lbs []*typesv1.LabelPair - LabelsHash uint64 - Value float64 -} - -func (p ProfileValue) Labels() phlaremodel.Labels { - return p.Lbs -} - -func (p ProfileValue) Timestamp() model.Time { - return model.Time(p.Ts) -} - // selectMergeSeries selects the profile from each ingester by deduping them and request merges of total values. -func selectMergeSeries(ctx context.Context, aggregation *typesv1.TimeSeriesAggregationType, responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesLabels]) (iter.Iterator[ProfileValue], error) { +func selectMergeSeries(ctx context.Context, aggregation *typesv1.TimeSeriesAggregationType, responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesLabels]) (iter.Iterator[timeseries.Value], error) { mergeResults := make([]MergeResult[[]*typesv1.Series], len(responses)) iters := make([]MergeIterator, len(responses)) var wg sync.WaitGroup @@ -522,20 +504,20 @@ func selectMergeSeries(ctx context.Context, aggregation *typesv1.TimeSeriesAggre if err := g.Wait(); err != nil { return nil, err } - var series = phlaremodel.MergeSeries(aggregation, results...) + var series = timeseries.MergeSeries(aggregation, results...) - seriesIters := make([]iter.Iterator[ProfileValue], 0, len(series)) + seriesIters := make([]iter.Iterator[timeseries.Value], 0, len(series)) for _, s := range series { s := s - seriesIters = append(seriesIters, newSeriesIterator(s.Labels, s.Points)) + seriesIters = append(seriesIters, timeseries.NewSeriesIterator(s.Labels, s.Points)) } - return iter.NewMergeIterator(ProfileValue{Ts: math.MaxInt64}, false, seriesIters...), nil + return phlaremodel.NewMergeIterator(timeseries.Value{Ts: math.MaxInt64}, false, seriesIters...), nil } // selectMergeSpanProfile selects the profile from each ingester by deduping them and // returns merge of stacktrace samples represented as a tree. -func selectMergeSpanProfile(ctx context.Context, responses []ResponseFromReplica[clientpool.BidiClientMergeSpanProfile]) (*phlaremodel.Tree, error) { - span, ctx := opentracing.StartSpanFromContext(ctx, "selectMergeSpanProfile") +func selectMergeSpanProfile(ctx context.Context, responses []ResponseFromReplica[clientpool.BidiClientMergeSpanProfile]) (*phlaremodel.FunctionNameTree, error) { + span, ctx := tracing.StartSpanFromContext(ctx, "selectMergeSpanProfile") defer span.Finish() mergeResults := make([]MergeResult[*ingestv1.MergeSpanProfileResult], len(responses)) @@ -561,9 +543,9 @@ func selectMergeSpanProfile(ctx context.Context, responses []ResponseFromReplica } // Collects the results in parallel. - span.LogFields(otlog.String("msg", "collecting merge results")) + trace.SpanFromContext(ctx).AddEvent("collecting merge results") g, _ := errgroup.WithContext(ctx) - m := phlaremodel.NewTreeMerger() + m := phlaremodel.NewTreeMerger[phlaremodel.FunctionName, phlaremodel.FunctionNameI]() for _, iter := range mergeResults { iter := iter g.Go(util.RecoverPanic(func() error { @@ -578,46 +560,6 @@ func selectMergeSpanProfile(ctx context.Context, responses []ResponseFromReplica return nil, err } - span.LogFields(otlog.String("msg", "building tree")) + trace.SpanFromContext(ctx).AddEvent("building tree") return m.Tree(), nil } - -type seriesIterator struct { - point []*typesv1.Point - - curr ProfileValue -} - -func newSeriesIterator(lbs []*typesv1.LabelPair, points []*typesv1.Point) *seriesIterator { - return &seriesIterator{ - point: points, - - curr: ProfileValue{ - Lbs: lbs, - LabelsHash: phlaremodel.Labels(lbs).Hash(), - }, - } -} - -func (s *seriesIterator) Next() bool { - if len(s.point) == 0 { - return false - } - p := s.point[0] - s.point = s.point[1:] - s.curr.Ts = p.Timestamp - s.curr.Value = p.Value - return true -} - -func (s *seriesIterator) At() ProfileValue { - return s.curr -} - -func (s *seriesIterator) Err() error { - return nil -} - -func (s *seriesIterator) Close() error { - return nil -} diff --git a/pkg/querier/select_merge_test.go b/pkg/querier/select_merge_test.go index 6431a4ceac..4f59c1d5f6 100644 --- a/pkg/querier/select_merge_test.go +++ b/pkg/querier/select_merge_test.go @@ -10,17 +10,14 @@ import ( ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/clientpool" - "github.com/grafana/pyroscope/pkg/iter" - "github.com/grafana/pyroscope/pkg/model" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/testhelper" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/testhelper" ) -var ( - foobarlabels = phlaremodel.Labels([]*typesv1.LabelPair{{Name: "foo", Value: "bar"}}) - foobuzzlabels = phlaremodel.Labels([]*typesv1.LabelPair{{Name: "foo", Value: "buzz"}}) -) +var foobarlabels = model.Labels([]*typesv1.LabelPair{{Name: "foo", Value: "bar"}}) func TestSelectMergeStacktraces(t *testing.T) { resp1 := newFakeBidiClientStacktraces([]*ingestv1.ProfileSets{ @@ -202,7 +199,7 @@ func TestSelectMergeByLabels(t *testing.T) { }) values, err := iter.Slice(res) require.NoError(t, err) - require.Equal(t, []ProfileValue{ + require.Equal(t, []timeseries.Value{ {Ts: 1, Value: 1.0, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, {Ts: 2, Value: 2.0, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, {Ts: 3, Value: 3.0, Lbs: foobarlabels, LabelsHash: foobarlabels.Hash()}, diff --git a/pkg/querier/stats/stats.go b/pkg/querier/stats/stats.go index 10f2615ad7..4d27535818 100644 --- a/pkg/querier/stats/stats.go +++ b/pkg/querier/stats/stats.go @@ -10,7 +10,7 @@ import ( "sync/atomic" //lint:ignore faillint we can't use go.uber.org/atomic with a protobuf struct without wrapping it. "time" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) type contextKey int diff --git a/pkg/querier/stats/stats.pb.go b/pkg/querier/stats/stats.pb.go index 8919f1e9fa..57cc1bd124 100644 --- a/pkg/querier/stats/stats.pb.go +++ b/pkg/querier/stats/stats.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: querier/stats/stats.proto @@ -16,6 +16,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -26,10 +27,7 @@ const ( ) type Stats struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The sum of all wall time spent in the querier to execute the query. WallTime int64 `protobuf:"varint,1,opt,name=wall_time,json=wallTime,proto3" json:"wall_time,omitempty"` // The number of series fetched for the query @@ -44,15 +42,15 @@ type Stats struct { SplitQueries uint32 `protobuf:"varint,6,opt,name=split_queries,json=splitQueries,proto3" json:"split_queries,omitempty"` // The number of index bytes fetched on the store-gateway for the query FetchedIndexBytes uint64 `protobuf:"varint,7,opt,name=fetched_index_bytes,json=fetchedIndexBytes,proto3" json:"fetched_index_bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Stats) Reset() { *x = Stats{} - if protoimpl.UnsafeEnabled { - mi := &file_querier_stats_stats_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_querier_stats_stats_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Stats) String() string { @@ -63,7 +61,7 @@ func (*Stats) ProtoMessage() {} func (x *Stats) ProtoReflect() protoreflect.Message { mi := &file_querier_stats_stats_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -129,53 +127,34 @@ func (x *Stats) GetFetchedIndexBytes() uint64 { var File_querier_stats_stats_proto protoreflect.FileDescriptor -var file_querier_stats_stats_proto_rawDesc = []byte{ - 0x0a, 0x19, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, - 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x73, 0x22, 0xb6, 0x02, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, - 0x77, 0x61, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x08, 0x77, 0x61, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x65, 0x74, - 0x63, 0x68, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x66, 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, - 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x66, - 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x66, 0x65, 0x74, 0x63, 0x68, 0x65, - 0x64, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x66, - 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x5f, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x66, 0x65, 0x74, 0x63, 0x68, - 0x65, 0x64, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x0a, - 0x0f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x65, 0x64, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x73, 0x68, 0x61, 0x72, 0x64, 0x65, 0x64, 0x51, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x73, - 0x70, 0x6c, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x66, - 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x66, 0x65, 0x74, 0x63, 0x68, 0x65, - 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x7b, 0x0a, 0x09, 0x63, - 0x6f, 0x6d, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x42, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x73, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, - 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, - 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x05, 0x53, - 0x74, 0x61, 0x74, 0x73, 0xca, 0x02, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0xe2, 0x02, 0x11, 0x53, - 0x74, 0x61, 0x74, 0x73, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_querier_stats_stats_proto_rawDesc = "" + + "\n" + + "\x19querier/stats/stats.proto\x12\x05stats\"\xb6\x02\n" + + "\x05Stats\x12\x1b\n" + + "\twall_time\x18\x01 \x01(\x03R\bwallTime\x120\n" + + "\x14fetched_series_count\x18\x02 \x01(\x04R\x12fetchedSeriesCount\x12.\n" + + "\x13fetched_chunk_bytes\x18\x03 \x01(\x04R\x11fetchedChunkBytes\x120\n" + + "\x14fetched_chunks_count\x18\x04 \x01(\x04R\x12fetchedChunksCount\x12'\n" + + "\x0fsharded_queries\x18\x05 \x01(\rR\x0eshardedQueries\x12#\n" + + "\rsplit_queries\x18\x06 \x01(\rR\fsplitQueries\x12.\n" + + "\x13fetched_index_bytes\x18\a \x01(\x04R\x11fetchedIndexBytesB~\n" + + "\tcom.statsB\n" + + "StatsProtoP\x01Z1github.com/grafana/pyroscope/v2/pkg/querier/stats\xa2\x02\x03SXX\xaa\x02\x05Stats\xca\x02\x05Stats\xe2\x02\x11Stats\\GPBMetadata\xea\x02\x05Statsb\x06proto3" var ( file_querier_stats_stats_proto_rawDescOnce sync.Once - file_querier_stats_stats_proto_rawDescData = file_querier_stats_stats_proto_rawDesc + file_querier_stats_stats_proto_rawDescData []byte ) func file_querier_stats_stats_proto_rawDescGZIP() []byte { file_querier_stats_stats_proto_rawDescOnce.Do(func() { - file_querier_stats_stats_proto_rawDescData = protoimpl.X.CompressGZIP(file_querier_stats_stats_proto_rawDescData) + file_querier_stats_stats_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_querier_stats_stats_proto_rawDesc), len(file_querier_stats_stats_proto_rawDesc))) }) return file_querier_stats_stats_proto_rawDescData } var file_querier_stats_stats_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_querier_stats_stats_proto_goTypes = []interface{}{ +var file_querier_stats_stats_proto_goTypes = []any{ (*Stats)(nil), // 0: stats.Stats } var file_querier_stats_stats_proto_depIdxs = []int32{ @@ -191,25 +170,11 @@ func file_querier_stats_stats_proto_init() { if File_querier_stats_stats_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_querier_stats_stats_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Stats); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_querier_stats_stats_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_querier_stats_stats_proto_rawDesc), len(file_querier_stats_stats_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -220,7 +185,6 @@ func file_querier_stats_stats_proto_init() { MessageInfos: file_querier_stats_stats_proto_msgTypes, }.Build() File_querier_stats_stats_proto = out.File - file_querier_stats_stats_proto_rawDesc = nil file_querier_stats_stats_proto_goTypes = nil file_querier_stats_stats_proto_depIdxs = nil } diff --git a/pkg/querier/store_gateway_querier.go b/pkg/querier/store_gateway_querier.go index 9bddf24626..12f88c9141 100644 --- a/pkg/querier/store_gateway_querier.go +++ b/pkg/querier/store_gateway_querier.go @@ -2,6 +2,7 @@ package querier import ( "context" + "fmt" "connectrpc.com/connect" "github.com/go-kit/log" @@ -9,23 +10,20 @@ import ( "github.com/grafana/dskit/ring" ring_client "github.com/grafana/dskit/ring/client" "github.com/grafana/dskit/services" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" + "github.com/grafana/dskit/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/prometheus/prometheus/promql/parser" "golang.org/x/sync/errgroup" googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" ingesterv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" - ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/clientpool" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/storegateway" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/clientpool" + model "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/storegateway" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util" ) type StoreGatewayQueryClient interface { @@ -33,12 +31,12 @@ type StoreGatewayQueryClient interface { MergeProfilesLabels(ctx context.Context) clientpool.BidiClientMergeProfilesLabels MergeProfilesPprof(ctx context.Context) clientpool.BidiClientMergeProfilesPprof MergeSpanProfile(ctx context.Context) clientpool.BidiClientMergeSpanProfile - ProfileTypes(context.Context, *connect.Request[ingestv1.ProfileTypesRequest]) (*connect.Response[ingestv1.ProfileTypesResponse], error) + ProfileTypes(context.Context, *connect.Request[ingesterv1.ProfileTypesRequest]) (*connect.Response[ingesterv1.ProfileTypesResponse], error) LabelValues(context.Context, *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) LabelNames(context.Context, *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) - Series(context.Context, *connect.Request[ingestv1.SeriesRequest]) (*connect.Response[ingestv1.SeriesResponse], error) - BlockMetadata(ctx context.Context, req *connect.Request[ingestv1.BlockMetadataRequest]) (*connect.Response[ingestv1.BlockMetadataResponse], error) - GetBlockStats(ctx context.Context, req *connect.Request[ingestv1.GetBlockStatsRequest]) (*connect.Response[ingestv1.GetBlockStatsResponse], error) + Series(context.Context, *connect.Request[ingesterv1.SeriesRequest]) (*connect.Response[ingesterv1.SeriesResponse], error) + BlockMetadata(ctx context.Context, req *connect.Request[ingesterv1.BlockMetadataRequest]) (*connect.Response[ingesterv1.BlockMetadataResponse], error) + GetBlockStats(ctx context.Context, req *connect.Request[ingesterv1.GetBlockStatsRequest]) (*connect.Response[ingesterv1.GetBlockStatsResponse], error) } type StoreGatewayLimits interface { @@ -72,11 +70,11 @@ func newStoreGatewayQuerier( logger, ) if err != nil { - return nil, errors.Wrap(err, "failed to create store-gateway ring backend") + return nil, fmt.Errorf("failed to create store-gateway ring backend: %w", err) } storesRing, err := ring.NewWithStoreClientAndStrategy(storesRingCfg, storegateway.RingNameForClient, storegateway.RingKey, storesRingBackend, ring.NewIgnoreUnhealthyInstancesReplicationStrategy(), prometheus.WrapRegistererWithPrefix("pyroscope_", reg), logger) if err != nil { - return nil, errors.Wrap(err, "failed to create store-gateway ring client") + return nil, fmt.Errorf("failed to create store-gateway ring client: %w", err) } // Disable compression for querier -> store-gateway connections clientsMetrics := promauto.With(reg).NewGauge(prometheus.GaugeOpts{ @@ -107,7 +105,7 @@ func (s *StoreGatewayQuerier) starting(ctx context.Context) error { s.subservicesWatcher.WatchManager(s.subservices) if err := services.StartManagerAndAwaitHealthy(ctx, s.subservices); err != nil { - return errors.Wrap(err, "unable to start store gateway querier set subservices") + return fmt.Errorf("unable to start store gateway querier set subservices: %w", err) } return nil @@ -119,7 +117,7 @@ func (s *StoreGatewayQuerier) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-s.subservicesWatcher.Chan(): - return errors.Wrap(err, "store gateway querier set subservice failed") + return fmt.Errorf("store gateway querier set subservice failed: %w", err) } } } @@ -174,14 +172,14 @@ func GetShuffleShardingSubring(ring ring.ReadRing, userID string, limits StoreGa return ring.ShuffleShard(userID, shardSize) } -func (q *Querier) selectTreeFromStoreGateway(ctx context.Context, req *querierv1.SelectMergeStacktracesRequest, plan map[string]*blockPlanEntry) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectTree StoreGateway") +func (q *Querier) selectTreeFromStoreGateway(ctx context.Context, req *querierv1.SelectMergeStacktracesRequest, plan map[string]*blockPlanEntry) (*model.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectTree StoreGateway") defer sp.Finish() - profileType, err := phlaremodel.ParseProfileTypeSelector(req.ProfileTypeID) + profileType, err := model.ParseProfileTypeSelector(req.ProfileTypeID) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } - _, err = parser.ParseMetricSelector(req.LabelSelector) + _, err = model.ParseMetricSelector(req.LabelSelector) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -194,7 +192,7 @@ func (q *Querier) selectTreeFromStoreGateway(ctx context.Context, req *querierv1 var responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesStacktraces] if plan != nil { - responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingestv1.Hints) (clientpool.BidiClientMergeProfilesStacktraces, error) { + responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingesterv1.Hints) (clientpool.BidiClientMergeProfilesStacktraces, error) { return ic.MergeProfilesStacktraces(ctx), nil }) } else { @@ -206,7 +204,7 @@ func (q *Querier) selectTreeFromStoreGateway(ctx context.Context, req *querierv1 return nil, connect.NewError(connect.CodeInternal, err) } // send the first initial request to all ingesters. - g, gCtx := errgroup.WithContext(ctx) + g, _ := errgroup.WithContext(ctx) for _, r := range responses { r := r blockHints, err := BlockHints(plan, r.addr) @@ -214,13 +212,13 @@ func (q *Querier) selectTreeFromStoreGateway(ctx context.Context, req *querierv1 return nil, connect.NewError(connect.CodeInternal, err) } g.Go(util.RecoverPanic(func() error { - return r.response.Send(&ingestv1.MergeProfilesStacktracesRequest{ - Request: &ingestv1.SelectProfilesRequest{ + return r.response.Send(&ingesterv1.MergeProfilesStacktracesRequest{ + Request: &ingesterv1.SelectProfilesRequest{ LabelSelector: req.LabelSelector, Start: req.Start, End: req.End, Type: profileType, - Hints: &ingestv1.Hints{Block: blockHints}, + Hints: &ingesterv1.Hints{Block: blockHints}, }, MaxNodes: req.MaxNodes, }) @@ -231,17 +229,17 @@ func (q *Querier) selectTreeFromStoreGateway(ctx context.Context, req *querierv1 } // merge all profiles - return selectMergeTree(gCtx, responses) + return selectMergeTree(ctx, responses) } func (q *Querier) selectProfileFromStoreGateway(ctx context.Context, req *querierv1.SelectMergeProfileRequest, plan map[string]*blockPlanEntry) (*googlev1.Profile, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectProfile StoreGateway") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectProfile StoreGateway") defer sp.Finish() - profileType, err := phlaremodel.ParseProfileTypeSelector(req.ProfileTypeID) + profileType, err := model.ParseProfileTypeSelector(req.ProfileTypeID) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } - _, err = parser.ParseMetricSelector(req.LabelSelector) + _, err = model.ParseMetricSelector(req.LabelSelector) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -254,7 +252,7 @@ func (q *Querier) selectProfileFromStoreGateway(ctx context.Context, req *querie var responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesPprof] if plan != nil { - responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingestv1.Hints) (clientpool.BidiClientMergeProfilesPprof, error) { + responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingesterv1.Hints) (clientpool.BidiClientMergeProfilesPprof, error) { return ic.MergeProfilesPprof(ctx), nil }) } else { @@ -266,7 +264,7 @@ func (q *Querier) selectProfileFromStoreGateway(ctx context.Context, req *querie return nil, connect.NewError(connect.CodeInternal, err) } // send the first initial request to all ingesters. - g, gCtx := errgroup.WithContext(ctx) + g, _ := errgroup.WithContext(ctx) for _, r := range responses { r := r blockHints, err := BlockHints(plan, r.addr) @@ -274,13 +272,13 @@ func (q *Querier) selectProfileFromStoreGateway(ctx context.Context, req *querie return nil, connect.NewError(connect.CodeInternal, err) } g.Go(util.RecoverPanic(func() error { - return r.response.Send(&ingestv1.MergeProfilesPprofRequest{ - Request: &ingestv1.SelectProfilesRequest{ + return r.response.Send(&ingesterv1.MergeProfilesPprofRequest{ + Request: &ingesterv1.SelectProfilesRequest{ LabelSelector: req.LabelSelector, Start: req.Start, End: req.End, Type: profileType, - Hints: &ingestv1.Hints{Block: blockHints}, + Hints: &ingesterv1.Hints{Block: blockHints}, }, MaxNodes: req.MaxNodes, StackTraceSelector: req.StackTraceSelector, @@ -292,11 +290,11 @@ func (q *Querier) selectProfileFromStoreGateway(ctx context.Context, req *querie } // merge all profiles - return selectMergePprofProfile(gCtx, profileType, responses) + return selectMergePprofProfile(ctx, profileType, responses) } func (q *Querier) selectSeriesFromStoreGateway(ctx context.Context, req *ingesterv1.MergeProfilesLabelsRequest, plan map[string]*blockPlanEntry) ([]ResponseFromReplica[clientpool.BidiClientMergeProfilesLabels], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectSeries StoreGateway") + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectSeries StoreGateway") defer sp.Finish() tenantID, err := tenant.ExtractTenantIDFromContext(ctx) if err != nil { @@ -304,7 +302,7 @@ func (q *Querier) selectSeriesFromStoreGateway(ctx context.Context, req *ingeste } var responses []ResponseFromReplica[clientpool.BidiClientMergeProfilesLabels] if plan != nil { - responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingestv1.Hints) (clientpool.BidiClientMergeProfilesLabels, error) { + responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingesterv1.Hints) (clientpool.BidiClientMergeProfilesLabels, error) { return ic.MergeProfilesLabels(ctx), nil }) } else { @@ -326,7 +324,7 @@ func (q *Querier) selectSeriesFromStoreGateway(ctx context.Context, req *ingeste } g.Go(util.RecoverPanic(func() error { req := req.CloneVT() - req.Request.Hints = &ingestv1.Hints{Block: blockHints} + req.Request.Hints = &ingesterv1.Hints{Block: blockHints} return r.response.Send(req) })) } @@ -337,7 +335,7 @@ func (q *Querier) selectSeriesFromStoreGateway(ctx context.Context, req *ingeste } func (q *Querier) labelValuesFromStoreGateway(ctx context.Context, req *typesv1.LabelValuesRequest) ([]ResponseFromReplica[[]string], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelValues StoreGateway") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelValues StoreGateway") defer sp.Finish() tenantID, err := tenant.ExtractTenantIDFromContext(ctx) @@ -359,7 +357,7 @@ func (q *Querier) labelValuesFromStoreGateway(ctx context.Context, req *typesv1. } func (q *Querier) labelNamesFromStoreGateway(ctx context.Context, req *typesv1.LabelNamesRequest) ([]ResponseFromReplica[[]string], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "LabelNames StoreGateway") + sp, ctx := tracing.StartSpanFromContext(ctx, "LabelNames StoreGateway") defer sp.Finish() tenantID, err := tenant.ExtractTenantIDFromContext(ctx) @@ -380,8 +378,8 @@ func (q *Querier) labelNamesFromStoreGateway(ctx context.Context, req *typesv1.L return responses, nil } -func (q *Querier) seriesFromStoreGateway(ctx context.Context, req *ingestv1.SeriesRequest) ([]ResponseFromReplica[[]*typesv1.Labels], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "Series StoreGateway") +func (q *Querier) seriesFromStoreGateway(ctx context.Context, req *ingesterv1.SeriesRequest) ([]ResponseFromReplica[[]*typesv1.Labels], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "Series StoreGateway") defer sp.Finish() tenantID, err := tenant.ExtractTenantIDFromContext(ctx) @@ -402,14 +400,14 @@ func (q *Querier) seriesFromStoreGateway(ctx context.Context, req *ingestv1.Seri return responses, nil } -func (q *Querier) selectSpanProfileFromStoreGateway(ctx context.Context, req *querierv1.SelectMergeSpanProfileRequest, plan map[string]*blockPlanEntry) (*phlaremodel.Tree, error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "SelectSpanProfile StoreGateway") +func (q *Querier) selectSpanProfileFromStoreGateway(ctx context.Context, req *querierv1.SelectMergeSpanProfileRequest, plan map[string]*blockPlanEntry) (*model.FunctionNameTree, error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "SelectSpanProfile StoreGateway") defer sp.Finish() - profileType, err := phlaremodel.ParseProfileTypeSelector(req.ProfileTypeID) + profileType, err := model.ParseProfileTypeSelector(req.ProfileTypeID) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } - _, err = parser.ParseMetricSelector(req.LabelSelector) + _, err = model.ParseMetricSelector(req.LabelSelector) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) } @@ -422,7 +420,7 @@ func (q *Querier) selectSpanProfileFromStoreGateway(ctx context.Context, req *qu var responses []ResponseFromReplica[clientpool.BidiClientMergeSpanProfile] if plan != nil { - responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingestv1.Hints) (clientpool.BidiClientMergeSpanProfile, error) { + responses, err = forAllPlannedStoreGateways(ctx, tenantID, q.storeGatewayQuerier, plan, func(ctx context.Context, ic StoreGatewayQueryClient, hints *ingesterv1.Hints) (clientpool.BidiClientMergeSpanProfile, error) { return ic.MergeSpanProfile(ctx), nil }) } else { @@ -434,7 +432,7 @@ func (q *Querier) selectSpanProfileFromStoreGateway(ctx context.Context, req *qu return nil, connect.NewError(connect.CodeInternal, err) } // send the first initial request to all ingesters. - g, gCtx := errgroup.WithContext(ctx) + g, _ := errgroup.WithContext(ctx) for _, r := range responses { r := r blockHints, err := BlockHints(plan, r.addr) @@ -442,14 +440,14 @@ func (q *Querier) selectSpanProfileFromStoreGateway(ctx context.Context, req *qu return nil, connect.NewError(connect.CodeInternal, err) } g.Go(util.RecoverPanic(func() error { - return r.response.Send(&ingestv1.MergeSpanProfileRequest{ - Request: &ingestv1.SelectSpanProfileRequest{ + return r.response.Send(&ingesterv1.MergeSpanProfileRequest{ + Request: &ingesterv1.SelectSpanProfileRequest{ LabelSelector: req.LabelSelector, Start: req.Start, End: req.End, Type: profileType, SpanSelector: req.SpanSelector, - Hints: &ingestv1.Hints{Block: blockHints}, + Hints: &ingesterv1.Hints{Block: blockHints}, }, MaxNodes: req.MaxNodes, }) @@ -460,11 +458,11 @@ func (q *Querier) selectSpanProfileFromStoreGateway(ctx context.Context, req *qu } // merge all profiles - return selectMergeSpanProfile(gCtx, responses) + return selectMergeSpanProfile(ctx, responses) } -func (q *Querier) blockSelectFromStoreGateway(ctx context.Context, req *ingestv1.BlockMetadataRequest) ([]ResponseFromReplica[[]*typesv1.BlockInfo], error) { - sp, ctx := opentracing.StartSpanFromContext(ctx, "blockSelect StoreGateway") +func (q *Querier) blockSelectFromStoreGateway(ctx context.Context, req *ingesterv1.BlockMetadataRequest) ([]ResponseFromReplica[[]*typesv1.BlockInfo], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "blockSelect StoreGateway") defer sp.Finish() tenantID, err := tenant.ExtractTenantIDFromContext(ctx) diff --git a/pkg/querier/timeline/calculator_test.go b/pkg/querier/timeline/calculator_test.go index 509f114d87..659844ec2a 100644 --- a/pkg/querier/timeline/calculator_test.go +++ b/pkg/querier/timeline/calculator_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/grafana/pyroscope/pkg/querier/timeline" + "github.com/grafana/pyroscope/v2/pkg/querier/timeline" ) func Test_CalcPointInterval(t *testing.T) { diff --git a/pkg/querier/timeline/timeline.go b/pkg/querier/timeline/timeline.go index f4b64f931f..0de4ae910c 100644 --- a/pkg/querier/timeline/timeline.go +++ b/pkg/querier/timeline/timeline.go @@ -1,7 +1,7 @@ package timeline import ( - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" v1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" ) diff --git a/pkg/querier/timeline/timeline_test.go b/pkg/querier/timeline/timeline_test.go index 857b3bb581..b0935c4b71 100644 --- a/pkg/querier/timeline/timeline_test.go +++ b/pkg/querier/timeline/timeline_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/querier/timeline" + "github.com/grafana/pyroscope/v2/pkg/querier/timeline" ) const timelineStepSec = 10 diff --git a/pkg/querier/vcs/client/github.go b/pkg/querier/vcs/client/github.go deleted file mode 100644 index 1ccf9578a7..0000000000 --- a/pkg/querier/vcs/client/github.go +++ /dev/null @@ -1,84 +0,0 @@ -package client - -import ( - "context" - "errors" - "fmt" - "net/http" - "time" - - "connectrpc.com/connect" - "github.com/google/go-github/v58/github" - "golang.org/x/oauth2" - - vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" -) - -// GithubClient returns a github client. -func GithubClient(ctx context.Context, token *oauth2.Token, client *http.Client) (*githubClient, error) { - return &githubClient{ - client: github.NewClient(client).WithAuthToken(token.AccessToken), - }, nil -} - -type githubClient struct { - client *github.Client -} - -func (gh *githubClient) GetCommit(ctx context.Context, owner, repo, ref string) (*vcsv1.GetCommitResponse, error) { - commit, _, err := gh.client.Repositories.GetCommit(ctx, owner, repo, ref, nil) - if err != nil { - return nil, err - } - - return &vcsv1.GetCommitResponse{ - Sha: toString(commit.SHA), - Message: toString(commit.Commit.Message), - Author: &vcsv1.CommitAuthor{ - Login: toString(commit.Author.Login), - AvatarURL: toString(commit.Author.AvatarURL), - }, - Date: commit.Commit.Author.Date.Format(time.RFC3339), - }, nil -} - -func (gh *githubClient) GetFile(ctx context.Context, req FileRequest) (File, error) { - // We could abstract away git provider using git protocol - // git clone https://x-access-token:@github.com/owner/repo.git - // For now we use the github client. - - file, _, _, err := gh.client.Repositories.GetContents(ctx, req.Owner, req.Repo, req.Path, &github.RepositoryContentGetOptions{Ref: req.Ref}) - if err != nil { - var githubErr *github.ErrorResponse - if errors.As(err, &githubErr) && githubErr.Response.StatusCode == http.StatusNotFound { - return File{}, fmt.Errorf("%w: %s", ErrNotFound, err) - } - return File{}, err - } - - if file == nil { - return File{}, ErrNotFound - } - - // We only support files retrieval. - if file.Type != nil && *file.Type != "file" { - return File{}, connect.NewError(connect.CodeInvalidArgument, errors.New("path is not a file")) - } - - content, err := file.GetContent() - if err != nil { - return File{}, err - } - - return File{ - Content: content, - URL: toString(file.HTMLURL), - }, nil -} - -func toString(s *string) string { - if s == nil { - return "" - } - return *s -} diff --git a/pkg/querier/vcs/client/metrics.go b/pkg/querier/vcs/client/metrics.go deleted file mode 100644 index f8b28c95ef..0000000000 --- a/pkg/querier/vcs/client/metrics.go +++ /dev/null @@ -1,84 +0,0 @@ -package client - -import ( - "fmt" - "net/http" - "regexp" - "time" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - - "github.com/grafana/pyroscope/pkg/util" -) - -var ( - githubRouteMatchers = map[string]*regexp.Regexp{ - // Get repository contents. - // https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-repository-content - "/repos/{owner}/{repo}/contents/{path}": regexp.MustCompile(`^\/repos\/\S+\/\S+\/contents\/\S+$`), - - // Get a commit. - // https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#get-a-commit - "/repos/{owner}/{repo}/commits/{ref}": regexp.MustCompile(`^\/repos\/\S+\/\S+\/commits\/\S+$`), - - // Refresh auth token. - // https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens#refreshing-a-user-access-token-with-a-refresh-token - "/login/oauth/access_token": regexp.MustCompile(`^\/login\/oauth\/access_token$`), - } -) - -func InstrumentedHTTPClient(logger log.Logger, reg prometheus.Registerer) *http.Client { - apiDuration := promauto.With(reg).NewHistogramVec( - prometheus.HistogramOpts{ - Namespace: "pyroscope", - Name: "vcs_github_request_duration", - Help: "Duration of GitHub API requests in seconds", - Buckets: prometheus.ExponentialBucketsRange(0.1, 10, 8), - }, - []string{"method", "route", "status_code"}, - ) - - defaultClient := &http.Client{ - Timeout: 10 * time.Second, - Transport: http.DefaultTransport, - } - client := util.InstrumentedHTTPClient(defaultClient, withGitHubMetricsTransport(logger, apiDuration)) - return client -} - -// withGitHubMetricsTransport wraps a transport with a client to track GitHub -// API usage. -func withGitHubMetricsTransport(logger log.Logger, hv *prometheus.HistogramVec) util.RoundTripperInstrumentFunc { - return func(next http.RoundTripper) http.RoundTripper { - return util.RoundTripperFunc(func(req *http.Request) (*http.Response, error) { - route := matchGitHubAPIRoute(req.URL.Path) - statusCode := "" - start := time.Now() - - res, err := next.RoundTrip(req) - if err == nil { - statusCode = fmt.Sprintf("%d", res.StatusCode) - } - - if route == "unknown_route" { - level.Warn(logger).Log("path", req.URL.Path, "msg", "unknown GitHub API route") - } - hv.WithLabelValues(req.Method, route, statusCode).Observe(time.Since(start).Seconds()) - - return res, err - }) - } -} - -func matchGitHubAPIRoute(path string) string { - for route, regex := range githubRouteMatchers { - if regex.MatchString(path) { - return route - } - } - - return "unknown_route" -} diff --git a/pkg/querier/vcs/encryption.go b/pkg/querier/vcs/encryption.go deleted file mode 100644 index b5152efd9a..0000000000 --- a/pkg/querier/vcs/encryption.go +++ /dev/null @@ -1,53 +0,0 @@ -package vcs - -import ( - "encoding/base64" - "encoding/json" - "errors" - - "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption" - "golang.org/x/oauth2" -) - -const gcmNonceSize = 12 - -func encryptToken(token *oauth2.Token, key []byte) (string, error) { - cipher, err := encryption.NewGCMCipher(key) - if err != nil { - return "", err - } - textBytes, err := json.Marshal(token) - if err != nil { - return "", err - } - enc, err := cipher.Encrypt(textBytes) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(enc), nil -} - -func decryptToken(encodedText string, key []byte) (*oauth2.Token, error) { - encryptedData, err := base64.StdEncoding.DecodeString(encodedText) - if err != nil { - return nil, err - } - - if len(encryptedData) < gcmNonceSize { - return nil, errors.New("malformed token") - } - - cipher, err := encryption.NewGCMCipher(key) - if err != nil { - return nil, err - } - - plaintext, err := cipher.Decrypt(encryptedData) - if err != nil { - return nil, err - } - - var token oauth2.Token - err = json.Unmarshal(plaintext, &token) - return &token, err -} diff --git a/pkg/querier/vcs/github.go b/pkg/querier/vcs/github.go deleted file mode 100644 index fee935ebb0..0000000000 --- a/pkg/querier/vcs/github.go +++ /dev/null @@ -1,169 +0,0 @@ -package vcs - -import ( - "context" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "os" - "time" - - "golang.org/x/oauth2" - "golang.org/x/oauth2/endpoints" -) - -const ( - githubRefreshURL = "https://github.com/login/oauth/access_token" - - // Duration of a GitHub refresh token. The original OAuth flow doesn't - // return the refresh token expiry, so we need to store it separately. - // GitHub docs state this value will never change: - // - // https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens - githubRefreshExpiryDuration = 15897600 * time.Second -) - -var ( - githubAppClientID = os.Getenv("GITHUB_CLIENT_ID") - githubAppClientSecret = os.Getenv("GITHUB_CLIENT_SECRET") -) - -type githubAuthToken struct { - AccessToken string `json:"access_token"` - ExpiresIn time.Duration `json:"expires_in"` - RefreshToken string `json:"refresh_token"` - RefreshTokenExpiresIn time.Duration `json:"refresh_token_expires_in"` - Scope string `json:"scope"` - TokenType string `json:"token_type"` -} - -// toOAuthToken converts a githubAuthToken to an OAuth token. -func (t githubAuthToken) toOAuthToken() *oauth2.Token { - return &oauth2.Token{ - AccessToken: t.AccessToken, - TokenType: t.TokenType, - RefreshToken: t.RefreshToken, - Expiry: time.Now().Add(t.ExpiresIn), - } -} - -// githubOAuthConfig creates a GitHub OAuth config. -func githubOAuthConfig() (*oauth2.Config, error) { - if githubAppClientID == "" { - return nil, fmt.Errorf("missing GITHUB_CLIENT_ID environment variable") - } - if githubAppClientSecret == "" { - return nil, fmt.Errorf("missing GITHUB_CLIENT_SECRET environment variable") - } - return &oauth2.Config{ - ClientID: githubAppClientID, - ClientSecret: githubAppClientSecret, - Endpoint: endpoints.GitHub, - }, nil -} - -// refreshGithubToken sends a request configured for the GitHub API and marshals -// the response into a githubAuthToken. -func refreshGithubToken(req *http.Request, client *http.Client) (*githubAuthToken, error) { - res, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to make request: %w", err) - } - defer res.Body.Close() - - bytes, err := io.ReadAll(res.Body) - if err != nil { - return nil, fmt.Errorf("failed to read response body: %w", err) - } - - // The response body is application/x-www-form-urlencoded, so we parse it - // via url.ParseQuery. - payload, err := url.ParseQuery(string(bytes)) - if err != nil { - return nil, fmt.Errorf("failed to parse response body: %w", err) - } - - githubToken, err := githubAuthTokenFromFormURLEncoded(payload) - if err != nil { - return nil, err - } - - return githubToken, nil -} - -// buildGithubRefreshRequest builds a cancelable http.Request which is -// configured to hit the GitHub API's token refresh endpoint. -func buildGithubRefreshRequest(ctx context.Context, oldToken *oauth2.Token) (*http.Request, error) { - req, err := http.NewRequestWithContext(ctx, "POST", githubRefreshURL, nil) - if err != nil { - return nil, fmt.Errorf("failed to create request: %w", err) - } - - query := req.URL.Query() - query.Add("client_id", githubAppClientID) - query.Add("client_secret", githubAppClientSecret) - query.Add("grant_type", "refresh_token") - query.Add("refresh_token", oldToken.RefreshToken) - - req.URL.RawQuery = query.Encode() - return req, nil -} - -// githubAuthTokenFromFormURLEncoded converts a url-encoded form to a -// githubAuthToken. -func githubAuthTokenFromFormURLEncoded(values url.Values) (*githubAuthToken, error) { - token := &githubAuthToken{} - var err error - - token.AccessToken, err = getStringValueFrom(values, "access_token") - if err != nil { - return nil, err - } - - token.ExpiresIn, err = getDurationValueFrom(values, "expires_in", time.Second) - if err != nil { - return nil, err - } - - token.RefreshToken, err = getStringValueFrom(values, "refresh_token") - if err != nil { - return nil, err - } - - token.RefreshTokenExpiresIn, err = getDurationValueFrom(values, "refresh_token_expires_in", time.Second) - if err != nil { - return nil, err - } - - token.Scope, err = getStringValueFrom(values, "scope") - if err != nil { - return nil, err - } - - token.TokenType, err = getStringValueFrom(values, "token_type") - if err != nil { - return nil, err - } - - return token, nil -} - -func isGitHubIntegrationConfigured() error { - var errs []error - - if githubAppClientID == "" { - errs = append(errs, fmt.Errorf("missing GITHUB_CLIENT_ID environment variable")) - } - - if githubAppClientSecret == "" { - errs = append(errs, fmt.Errorf("missing GITHUB_CLIENT_SECRET environment variable")) - } - - if len(githubSessionSecret) == 0 { - errs = append(errs, fmt.Errorf("missing GITHUB_SESSION_SECRET environment variable")) - } - - return errors.Join(errs...) -} diff --git a/pkg/querier/vcs/service.go b/pkg/querier/vcs/service.go deleted file mode 100644 index 7113985dde..0000000000 --- a/pkg/querier/vcs/service.go +++ /dev/null @@ -1,204 +0,0 @@ -package vcs - -import ( - "context" - "errors" - "fmt" - "net/http" - "time" - - "connectrpc.com/connect" - "github.com/go-kit/log" - giturl "github.com/kubescape/go-git-url" - "github.com/kubescape/go-git-url/apis" - "github.com/prometheus/client_golang/prometheus" - "golang.org/x/oauth2" - - vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" - vcsv1connect "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1/vcsv1connect" - client "github.com/grafana/pyroscope/pkg/querier/vcs/client" - "github.com/grafana/pyroscope/pkg/querier/vcs/source" -) - -var _ vcsv1connect.VCSServiceHandler = (*Service)(nil) - -type Service struct { - logger log.Logger - httpClient *http.Client -} - -func New(logger log.Logger, reg prometheus.Registerer) *Service { - httpClient := client.InstrumentedHTTPClient(logger, reg) - - return &Service{ - logger: logger, - httpClient: httpClient, - } -} - -func (q *Service) GithubApp(ctx context.Context, req *connect.Request[vcsv1.GithubAppRequest]) (*connect.Response[vcsv1.GithubAppResponse], error) { - err := isGitHubIntegrationConfigured() - if err != nil { - q.logger.Log("err", err, "msg", "GitHub integration is not configured") - return nil, connect.NewError(connect.CodeUnimplemented, fmt.Errorf("GitHub integration is not configured")) - } - - return connect.NewResponse(&vcsv1.GithubAppResponse{ - ClientID: githubAppClientID, - }), nil -} - -func (q *Service) GithubLogin(ctx context.Context, req *connect.Request[vcsv1.GithubLoginRequest]) (*connect.Response[vcsv1.GithubLoginResponse], error) { - cfg, err := githubOAuthConfig() - if err != nil { - q.logger.Log("err", err, "msg", "failed to get GitHub OAuth config") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to authorize with GitHub")) - } - - encryptionKey, err := deriveEncryptionKeyForContext(ctx) - if err != nil { - q.logger.Log("err", err, "msg", "failed to derive encryption key") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to authorize with GitHub")) - } - - token, err := cfg.Exchange(ctx, req.Msg.AuthorizationCode) - if err != nil { - q.logger.Log("err", err, "msg", "failed to exchange authorization code with GitHub") - return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("failed to authorize with GitHub")) - } - - cookie, err := encodeToken(token, encryptionKey) - if err != nil { - q.logger.Log("err", err, "msg", "failed to encode GitHub OAuth token") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to authorize with GitHub")) - } - - res := &vcsv1.GithubLoginResponse{ - Cookie: cookie.String(), - } - return connect.NewResponse(res), nil -} - -func (q *Service) GithubRefresh(ctx context.Context, req *connect.Request[vcsv1.GithubRefreshRequest]) (*connect.Response[vcsv1.GithubRefreshResponse], error) { - token, err := tokenFromRequest(ctx, req) - if err != nil { - q.logger.Log("err", err, "msg", "failed to extract token from request") - return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("invalid token")) - } - - githubRequest, err := buildGithubRefreshRequest(ctx, token) - if err != nil { - q.logger.Log("err", err, "msg", "failed to extract token from request") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to refresh token")) - } - - githubToken, err := refreshGithubToken(githubRequest, q.httpClient) - if err != nil { - q.logger.Log("err", err, "msg", "failed to refresh token with GitHub") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to refresh token")) - } - - newToken := githubToken.toOAuthToken() - - derivedKey, err := deriveEncryptionKeyForContext(ctx) - if err != nil { - q.logger.Log("err", err, "msg", "failed to derive encryption key") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to process token")) - } - - cookie, err := encodeToken(newToken, derivedKey) - if err != nil { - q.logger.Log("err", err, "msg", "failed to encode GitHub OAuth token") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to refresh token")) - } - - res := &vcsv1.GithubRefreshResponse{ - Cookie: cookie.String(), - } - return connect.NewResponse(res), nil -} - -func (q *Service) GetFile(ctx context.Context, req *connect.Request[vcsv1.GetFileRequest]) (*connect.Response[vcsv1.GetFileResponse], error) { - token, err := tokenFromRequest(ctx, req) - if err != nil { - q.logger.Log("err", err, "msg", "failed to extract token from request") - return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("invalid token")) - } - - err = rejectExpiredToken(token) - if err != nil { - return nil, err - } - - // initialize and parse the git repo URL - gitURL, err := giturl.NewGitURL(req.Msg.RepositoryURL) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - if gitURL.GetProvider() != apis.ProviderGitHub.String() { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("only GitHub repositories are supported")) - } - - // todo: we can support multiple provider: bitbucket, gitlab, etc. - ghClient, err := client.GithubClient(ctx, token, q.httpClient) - if err != nil { - return nil, err - } - - file, err := source.NewFileFinder( - ghClient, - gitURL, - req.Msg.LocalPath, - req.Msg.Ref, - http.DefaultClient, - log.With(q.logger, "repo", gitURL.GetRepoName()), - ).Find(ctx) - if err != nil { - if errors.Is(err, client.ErrNotFound) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, err - } - return connect.NewResponse(file), nil -} - -func (q *Service) GetCommit(ctx context.Context, req *connect.Request[vcsv1.GetCommitRequest]) (*connect.Response[vcsv1.GetCommitResponse], error) { - token, err := tokenFromRequest(ctx, req) - if err != nil { - q.logger.Log("err", err, "msg", "failed to extract token from request") - return nil, connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("invalid token")) - } - - err = rejectExpiredToken(token) - if err != nil { - return nil, err - } - - gitURL, err := giturl.NewGitURL(req.Msg.RepositoryURL) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - if gitURL.GetProvider() != apis.ProviderGitHub.String() { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("only GitHub repositories are supported")) - } - - ghClient, err := client.GithubClient(ctx, token, q.httpClient) - if err != nil { - return nil, err - } - - commit, err := ghClient.GetCommit(ctx, gitURL.GetOwnerName(), gitURL.GetRepoName(), req.Msg.Ref) - if err != nil { - return nil, err - } - return connect.NewResponse(commit), nil -} - -func rejectExpiredToken(token *oauth2.Token) error { - if time.Now().After(token.Expiry) { - return connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("token is expired")) - } - return nil -} diff --git a/pkg/querier/vcs/source/find.go b/pkg/querier/vcs/source/find.go deleted file mode 100644 index 5805e7d4e2..0000000000 --- a/pkg/querier/vcs/source/find.go +++ /dev/null @@ -1,111 +0,0 @@ -package source - -import ( - "context" - "encoding/base64" - "fmt" - "io" - "net/http" - "path/filepath" - - "connectrpc.com/connect" - "github.com/go-kit/log" - giturl "github.com/kubescape/go-git-url" - - vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" - "github.com/grafana/pyroscope/pkg/querier/vcs/client" -) - -type VCSClient interface { - GetFile(ctx context.Context, req client.FileRequest) (client.File, error) -} - -// FileFinder finds a file in a vcs repository. -type FileFinder struct { - path, ref string - repo giturl.IGitURL - - client VCSClient - httpClient *http.Client - logger log.Logger -} - -// NewFileFinder returns a new FileFinder. -func NewFileFinder(client VCSClient, repo giturl.IGitURL, path, ref string, httpClient *http.Client, logger log.Logger) *FileFinder { - if ref == "" { - ref = "HEAD" - } - return &FileFinder{ - client: client, - logger: logger, - repo: repo, - path: path, - ref: ref, - httpClient: httpClient, - } -} - -// Find returns the file content and URL. -func (ff FileFinder) Find(ctx context.Context) (*vcsv1.GetFileResponse, error) { - switch filepath.Ext(ff.path) { - case ExtGo: - return ff.findGoFile(ctx) - // todo: add more languages support - default: - // by default we return the file content at the given path without any processing. - content, err := ff.fetchRepoFile(ctx, ff.path, ff.ref) - if err != nil { - return nil, err - } - return newFileResponse(content.Content, content.URL) - } -} - -// fetchRepoFile fetches the file content from the configured repository. -func (arg FileFinder) fetchRepoFile(ctx context.Context, path, ref string) (*vcsv1.GetFileResponse, error) { - content, err := arg.client.GetFile(ctx, client.FileRequest{ - Owner: arg.repo.GetOwnerName(), - Repo: arg.repo.GetRepoName(), - Path: path, - Ref: ref, - }) - if err != nil { - return nil, err - } - return newFileResponse(content.Content, content.URL) -} - -// fetchURL fetches the file content from the given URL. -func (ff FileFinder) fetchURL(ctx context.Context, url string, decodeBase64 bool) (*vcsv1.GetFileResponse, error) { - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) - if err != nil { - return nil, err - } - resp, err := ff.httpClient.Do(req) // todo: use a custom client with timeout - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("failed to fetch %s: %s", url, resp.Status)) - } - content, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - if !decodeBase64 { - return newFileResponse(string(content), url) - } - decoded, err := base64.StdEncoding.DecodeString(string(content)) - if err != nil { - return nil, err - } - return newFileResponse(string(decoded), url) -} - -func newFileResponse(content, url string) (*vcsv1.GetFileResponse, error) { - return &vcsv1.GetFileResponse{ - Content: base64.StdEncoding.EncodeToString([]byte(content)), - URL: url, - }, nil -} diff --git a/pkg/querier/vcs/source/find_go.go b/pkg/querier/vcs/source/find_go.go deleted file mode 100644 index e932b2432c..0000000000 --- a/pkg/querier/vcs/source/find_go.go +++ /dev/null @@ -1,142 +0,0 @@ -package source - -import ( - "context" - "errors" - "fmt" - "path" - "strings" - "time" - - "github.com/go-kit/log/level" - "golang.org/x/mod/modfile" - "golang.org/x/mod/module" - - vcsv1 "github.com/grafana/pyroscope/api/gen/proto/go/vcs/v1" - "github.com/grafana/pyroscope/pkg/querier/vcs/client" - "github.com/grafana/pyroscope/pkg/querier/vcs/source/golang" -) - -const ( - ExtGo = ".go" -) - -// findGoFile finds a go file in a vcs repository. -func (ff FileFinder) findGoFile(ctx context.Context) (*vcsv1.GetFileResponse, error) { - if url, ok := golang.StandardLibraryURL(ff.path); ok { - return ff.fetchURL(ctx, url, false) - } - - if relativePath, ok := golang.VendorRelativePath(ff.path); ok { - return ff.fetchRepoFile(ctx, relativePath, ff.ref) - } - - modFile, ok := golang.ParseModuleFromPath(ff.path) - if ok { - mainModule := module.Version{ - Path: path.Join(ff.repo.GetHostName(), ff.repo.GetOwnerName(), ff.repo.GetRepoName()), - Version: module.PseudoVersion("", "", time.Time{}, ff.ref), - } - modf, err := ff.fetchGoMod(ctx) - if err != nil { - level.Warn(ff.logger).Log("msg", "failed to fetch go.mod file", "err", err) - } - if err := modFile.Resolve(ctx, mainModule, modf, ff.httpClient); err != nil { - return nil, err - } - return ff.fetchGoDependencyFile(ctx, modFile) - } - return ff.tryFindGoFile(ctx, 30) -} - -func (ff FileFinder) fetchGoMod(ctx context.Context) (*modfile.File, error) { - content, err := ff.client.GetFile(ctx, client.FileRequest{ - Owner: ff.repo.GetOwnerName(), - Repo: ff.repo.GetRepoName(), - Path: golang.GoMod, - Ref: ff.ref, - }) - if err != nil { - return nil, err - } - return modfile.Parse(golang.GoMod, []byte(content.Content), nil) -} - -func (ff FileFinder) fetchGoDependencyFile(ctx context.Context, module golang.Module) (*vcsv1.GetFileResponse, error) { - switch { - case module.IsGitHub(): - return ff.fetchGithubModuleFile(ctx, module) - case module.IsGoogleSource(): - return ff.fetchGoogleSourceDependencyFile(ctx, module) - } - return nil, fmt.Errorf("unsupported module path: %s", module.Path) -} - -func (ff FileFinder) fetchGithubModuleFile(ctx context.Context, mod golang.Module) (*vcsv1.GetFileResponse, error) { - // todo: what if this is not a github repo? - // VSClient should support querying multiple repo providers. - githubFile, err := mod.GithubFile() - if err != nil { - return nil, err - } - content, err := ff.client.GetFile(ctx, client.FileRequest{ - Owner: githubFile.Owner, - Repo: githubFile.Repo, - Path: githubFile.Path, - Ref: githubFile.Ref, - }) - if err != nil { - return nil, err - } - return newFileResponse(content.Content, content.URL) -} - -func (ff FileFinder) fetchGoogleSourceDependencyFile(ctx context.Context, mod golang.Module) (*vcsv1.GetFileResponse, error) { - url, err := mod.GoogleSourceURL() - if err != nil { - return nil, err - } - return ff.fetchURL(ctx, url, true) -} - -// tryFindGoFile tries to find the go file in the repo. -// It tries to find the file in the repo by removing path segment after path segment. -// maxAttempts is the maximum number of attempts to try to find the file in case the file path is very long. -// For example, if the path is "github.com/grafana/grafana/pkg/infra/log/log.go", it will try to find the file at: -// - github.com/grafana/grafana/pkg/infra/log/log.go -// - grafana/grafana/pkg/infra/log/log.go -// - pkg/infra/log/log.go -// - infra/log/log.go -// - log/log.go -// - log.go -func (ff FileFinder) tryFindGoFile(ctx context.Context, maxAttempts int) (*vcsv1.GetFileResponse, error) { - if maxAttempts <= 0 { - return nil, errors.New("invalid max attempts") - } - // Try to find the file in the repo. - path := strings.TrimPrefix(ff.path, strings.Join([]string{ff.repo.GetHostName(), ff.repo.GetOwnerName(), ff.repo.GetRepoName()}, "/")) - path = strings.TrimLeft(path, "/") - attempts := 0 - for { - content, err := ff.client.GetFile(ctx, client.FileRequest{ - Owner: ff.repo.GetOwnerName(), - Repo: ff.repo.GetRepoName(), - Path: path, - Ref: ff.ref, - }) - attempts++ - if err != nil && errors.Is(err, client.ErrNotFound) && attempts < maxAttempts { - i := strings.Index(path, "/") - if i < 0 { - return nil, err - } - // remove the first path segment - path = path[i+1:] - continue - } - if err != nil { - return nil, err - } - return newFileResponse(content.Content, content.URL) - } -} diff --git a/pkg/querier/vcs/source/golang/gen.go b/pkg/querier/vcs/source/golang/gen.go deleted file mode 100644 index 11c0b5e2e8..0000000000 --- a/pkg/querier/vcs/source/golang/gen.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build ignore - -package main - -import ( - "bytes" - "context" - "html/template" - "io" - "log" - "os" - - "github.com/github/go-pipe/pipe" - - "github.com/grafana/pyroscope/pkg/querier/golang" -) - -func main() { - // todo: In the future we might want to support more than one version - // Or even list all files from standard packages to improve matching. - packages, err := golang.StdPackages("") - if err != nil { - log.Fatal(err) - } - t := template.Must(template.New("packages").Parse(packagesTemplate)) - var buff bytes.Buffer - p := pipe.New(pipe.WithStdout(&buff)) - p.Add( - pipe.Function("", func(ctx context.Context, env pipe.Env, stdin io.Reader, stdout io.Writer) error { - err = t.Execute(stdout, packages) - if err != nil { - log.Fatal(err) - } - return nil - }), - // This might be a bit overkill, but it's nice to have a consistent format. - // todo: We could use "go/format" package only that will simplify the code but also remove the needs - // for expected installed binaries. - pipe.Command("gofmt"), - pipe.Command("goimports"), - ) - p.Run(context.Background()) - err = os.WriteFile("packages_gen.go", buff.Bytes(), 0666) - if err != nil { - log.Fatal(err) - } -} - -var packagesTemplate = ` -package golang -// Code generated. DO NOT EDIT. - -var StandardPackages = map[string]struct{}{ - {{- range $key, $value := .}} - "{{$key}}": {}, - {{- end}} -} -` diff --git a/pkg/querier/vcs/source/golang/golang.go b/pkg/querier/vcs/source/golang/golang.go deleted file mode 100644 index 8d641c5edc..0000000000 --- a/pkg/querier/vcs/source/golang/golang.go +++ /dev/null @@ -1,60 +0,0 @@ -package golang - -import ( - "fmt" - "path/filepath" - "strings" - - "github.com/grafana/regexp" -) - -const ( - vendorPath = "vendor/" - stdLocal = "/usr/local/go/src/" - stdGoRoot = "$GOROOT/src/" -) - -var stdLibRegex = regexp.MustCompile(`.*?\/go\/.*?(?P(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?).*?\/src\/(?P.*)`) - -// StandardLibraryURL returns the URL of the standard library package -// from the given local path if it exists. -func StandardLibraryURL(path string) (string, bool) { - if len(path) == 0 { - return "", false - } - - if stdLibRegex.MatchString(path) { - matches := stdLibRegex.FindStringSubmatch(path) - version := matches[stdLibRegex.SubexpIndex("version")] - path = matches[stdLibRegex.SubexpIndex("path")] - return fmt.Sprintf(`https://raw.githubusercontent.com/golang/go/go%s/src/%s`, version, path), true - } - - path = strings.TrimPrefix(path, stdLocal) - path = strings.TrimPrefix(path, stdGoRoot) - fileName := filepath.Base(path) - packageName := strings.TrimSuffix(path, "/"+fileName) - // Todo: Send more metadata from SDK to fetch the correct version of Go std packages. - // For this we should use arbitrary k/v metadata in our request so that we don't need to change the API. - // I thought about using go.mod go version but it's a min and doesn't guarantee it hasn't been built with a higher version. - // Alternatively we could interpret the build system and use the version of the go compiler. - ref := "master" - isStdVendor := strings.HasPrefix(packageName, vendorPath) - - if _, isStd := StandardPackages[packageName]; !isStdVendor && !isStd { - return "", false - } - return fmt.Sprintf(`https://raw.githubusercontent.com/golang/go/%s/src/%s`, ref, path), true -} - -// VendorRelativePath returns the relative path of the given path -// if it is a vendor path. -// For example: -// /drone/src/vendor/google.golang.org/protobuf/proto/merge.go -> /vendor/google.golang.org/protobuf/proto/merge.go -func VendorRelativePath(path string) (string, bool) { - idx := strings.Index(path, "/"+vendorPath) - if idx < 0 { - return "", false - } - return path[idx:], true -} diff --git a/pkg/querier/vcs/source/golang/golang_test.go b/pkg/querier/vcs/source/golang/golang_test.go deleted file mode 100644 index 28db9dede1..0000000000 --- a/pkg/querier/vcs/source/golang/golang_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package golang - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestStandardLibraryURL(t *testing.T) { - for _, tt := range []struct { - input string - expected string - expectedOk bool - }{ - { - input: "github.com/grafana/grafana/pkg/querier/vcs.go", - expected: "", - expectedOk: false, - }, - { - input: "/usr/local/go/src/bufio/bufio.go", - expected: "https://raw.githubusercontent.com/golang/go/master/src/bufio/bufio.go", - expectedOk: true, - }, - { - input: "$GOROOT/src/unicode/utf8/utf8.go", - expected: "https://raw.githubusercontent.com/golang/go/master/src/unicode/utf8/utf8.go", - expectedOk: true, - }, - { - input: "fmt/scan.go", - expected: "https://raw.githubusercontent.com/golang/go/master/src/fmt/scan.go", - expectedOk: true, - }, - { - input: "$GOROOT/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go", - expected: "https://raw.githubusercontent.com/golang/go/master/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go", - expectedOk: true, - }, - { - input: "/usr/local/go/src/vendor/golang.org/x/net/http2/hpack/tables.go", - expected: "https://raw.githubusercontent.com/golang/go/master/src/vendor/golang.org/x/net/http2/hpack/tables.go", - expectedOk: true, - }, - { - input: "/usr/local/Cellar/go/1.21.3/libexec/src/runtime/netpoll_kqueue.go", - expected: "https://raw.githubusercontent.com/golang/go/go1.21.3/src/runtime/netpoll_kqueue.go", - expectedOk: true, - }, - { - input: "/opt/hostedtoolcache/go/1.21.6/x64/src/runtime/mgc.go", - expected: "https://raw.githubusercontent.com/golang/go/go1.21.6/src/runtime/mgc.go", - expectedOk: true, - }, - } { - t.Run(tt.input, func(t *testing.T) { - actual, ok := StandardLibraryURL(tt.input) - if !tt.expectedOk { - require.False(t, ok) - } - require.Equal(t, tt.expected, actual) - }) - } -} - -func TestVendorRelativePath(t *testing.T) { - for _, tt := range []struct { - in string - expected string - expectedOk bool - }{ - { - in: "/drone/src/vendor/google.golang.org/protobuf/proto/merge.go", - expected: "/vendor/google.golang.org/protobuf/proto/merge.go", - expectedOk: true, - }, - { - in: "google.golang.org/protobuf/proto/merge.go", - expected: "", - expectedOk: false, - }, - } { - t.Run(tt.in, func(t *testing.T) { - actual, ok := VendorRelativePath(tt.in) - if !tt.expectedOk { - require.False(t, ok) - } - require.Equal(t, tt.expected, actual) - }) - } -} diff --git a/pkg/querier/vcs/source/golang/modules.go b/pkg/querier/vcs/source/golang/modules.go deleted file mode 100644 index a3bab2a90e..0000000000 --- a/pkg/querier/vcs/source/golang/modules.go +++ /dev/null @@ -1,322 +0,0 @@ -package golang - -import ( - "context" - "fmt" - "net/http" - "path/filepath" - "regexp" - "strings" - - "connectrpc.com/connect" - "github.com/PuerkitoBio/goquery" - "golang.org/x/mod/modfile" - "golang.org/x/mod/module" - "golang.org/x/mod/semver" -) - -const ( - GoMod = "go.mod" - - GitHubPath = "github.com/" - GooglePath = "go.googlesource.com/" - GoPkgInPath = "gopkg.in/" -) - -var versionSuffixRE = regexp.MustCompile(`/v[0-9]+[/]*`) - -// Module represents a go module with a file path in that module -type Module struct { - module.Version - FilePath string -} - -// ParseModuleFromPath parses the module from the given path. -func ParseModuleFromPath(path string) (Module, bool) { - parts := strings.Split(path, "@v") - if len(parts) != 2 { - return Module{}, false - } - first := strings.Index(parts[1], "/") - if first < 0 { - return Module{}, false - } - filePath := parts[1][first+1:] - modulePath := parts[0] - // searching for the first domain name - domainParts := strings.Split(modulePath, "/") - for i, part := range domainParts { - if strings.Contains(part, ".") { - return Module{ - Version: module.Version{ - Path: strings.Join(domainParts[i:], "/"), - Version: "v" + parts[1][:first], - }, - FilePath: filePath, - }, true - } - } - return Module{}, false -} - -func (m Module) IsGitHub() bool { - return strings.HasPrefix(m.Path, GitHubPath) -} - -func (m Module) IsGoogleSource() bool { - return strings.HasPrefix(m.Path, GooglePath) -} - -func (m Module) IsGoPkgIn() bool { - return strings.HasPrefix(m.Path, GoPkgInPath) -} - -func (m Module) String() string { - return fmt.Sprintf("%s@%s", m.Path, m.Version) -} - -type HttpClient interface { - Do(req *http.Request) (*http.Response, error) -} - -// Resolve resolves the module path to a canonical path. -func (module *Module) Resolve(ctx context.Context, mainModule module.Version, modfile *modfile.File, httpClient HttpClient) error { - if modfile != nil { - mainModule.Path = modfile.Module.Mod.Path - module.applyGoMod(mainModule, modfile) - } - if err := module.resolveVanityURL(ctx, httpClient); err != nil { - return err - } - // remove version suffix such as /v2 or /v11 ... - module.Path = versionSuffixRE.ReplaceAllString(module.Path, "") - return nil -} - -func (module *Module) resolveVanityURL(ctx context.Context, httpClient HttpClient) error { - switch { - // no need to resolve vanity URL - case module.IsGitHub(): - return nil - case module.IsGoPkgIn(): - return module.resolveGoPkgIn() - default: - return module.resolveGoGet(ctx, httpClient) - } -} - -// resolveGoGet resolves the module path using go-get meta tags. -// normally go-import meta tag should be used to resolve vanity. -// -// curl -v 'https://google.golang.org/protobuf?go-get=1' -// -// careful follow redirect see: curl -L -v 'connectrpc.com/connect?go-get=1' -// if go-source meta tag is present prefer it over go-import. -// see https://go.dev/ref/mod#vcs-find -func (module *Module) resolveGoGet(ctx context.Context, httpClient HttpClient) error { - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://%s?go-get=1", strings.TrimRight(module.Path, "/")), nil) - if err != nil { - return err - } - resp, err := httpClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return connect.NewError(connect.CodeNotFound, fmt.Errorf("failed to fetch go lib %s: %s", module.Path, resp.Status)) - } - - // look for go-source meta tag first - doc, err := goquery.NewDocumentFromReader(resp.Body) - if err != nil { - return err - } - var found bool - // - doc.Find("meta[name='go-source']").Each(func(i int, s *goquery.Selection) { - content, ok := s.Attr("content") - if !ok { - return - } - content = cleanWhiteSpace(content) - parts := strings.Split(content, " ") - if len(parts) < 2 { - return - } - - // prefer github if available in go-source - if !found && strings.Contains(module.Path, parts[0]) && strings.Contains(parts[1], "github.com/") { - found = true - subPath := strings.Replace(module.Path, parts[0], "", 1) - module.Path = filepath.Join(strings.TrimRight( - strings.TrimPrefix( - strings.TrimPrefix(parts[1], "https://"), - "http://", - ), "/"), - subPath, - ) - - } - }) - if found { - return nil - } - // - // - // - doc.Find("meta[name='go-import']").Each(func(i int, s *goquery.Selection) { - content, ok := s.Attr("content") - if !ok { - return - } - parts := strings.Split(cleanWhiteSpace(content), " ") - if len(parts) < 3 { - return - } - - if !found && strings.Contains(module.Path, parts[0]) && parts[1] == "git" { - found = true - subPath := strings.Replace(module.Path, parts[0], "", 1) - module.Path = filepath.Join(strings.TrimRight( - strings.TrimPrefix( - strings.TrimPrefix(parts[2], "https://"), - "http://", - ), "/"), - subPath, - ) - - } - }) - return nil -} - -// resolveGoPkgIn resolves the gopkg.in path to a github path. -// see https://labix.org/gopkg.in -// gopkg.in/pkg.v3 → github.com/go-pkg/pkg (branch/tag v3, v3.N, or v3.N.M) -// gopkg.in/user/pkg.v3 → github.com/user/pkg (branch/tag v3, v3.N, or v3.N.M) -func (module *Module) resolveGoPkgIn() error { - parts := strings.Split(module.Path, "/") - if len(parts) < 2 { - return fmt.Errorf("invalid gopkg.in path: %s", module.Path) - } - packageNameParts := strings.Split(parts[len(parts)-1], ".") - if len(packageNameParts) < 2 || packageNameParts[0] == "" { - return fmt.Errorf("invalid gopkg.in path: %s", module.Path) - } - switch len(parts) { - case 2: - module.Path = fmt.Sprintf("github.com/go-%s/%s", packageNameParts[0], packageNameParts[0]) - case 3: - module.Path = fmt.Sprintf("github.com/%s/%s", parts[1], packageNameParts[0]) - default: - return fmt.Errorf("invalid gopkg.in path: %s", module.Path) - } - return nil -} - -// applyGoMod applies the go.mod file to the module. -func (module *Module) applyGoMod(mainModule module.Version, modf *modfile.File) { - for _, req := range modf.Require { - if req.Mod.Path == module.Path { - module.Version.Version = req.Mod.Version - } - } - for _, req := range modf.Replace { - if req.Old.Path == module.Path { - module.Path = req.New.Path - module.Version.Version = req.New.Version - } - } - if strings.HasPrefix(module.Path, "./") { - module.Version.Version = mainModule.Version - module.Path = filepath.Join(mainModule.Path, module.Path) - } -} - -type GitHubFile struct { - Owner, Repo, Ref, Path string -} - -// GithubFile returns the github file information. -func (m Module) GithubFile() (GitHubFile, error) { - if !m.IsGitHub() { - return GitHubFile{}, fmt.Errorf("invalid github URL: %s", m.Path) - } - version, err := refFromVersion(m.Version.Version) - if err != nil { - return GitHubFile{}, err - } - if version == "" { - version = "main" - } - parts := strings.Split(m.Path, "/") - if len(parts) < 3 { - return GitHubFile{}, fmt.Errorf("invalid github URL: %s", m.Path) - } - return GitHubFile{ - // ! character is used for capitalization - // example: github.com/!f!zambia/eagle@v0.0.2/eagle.go - Owner: strings.ReplaceAll(parts[1], "!", ""), - Repo: parts[2], - Ref: version, - Path: filepath.Join(strings.Join(parts[3:], "/"), m.FilePath), - }, nil -} - -// GoogleSourceURL returns the URL of the file in the google source repository. -// Example https://go.googlesource.com/oauth2/+/4ce7bbb2ffdc6daed06e2ec28916fd08d96bc3ea/amazon/amazon.go -func (m Module) GoogleSourceURL() (string, error) { - if !m.IsGoogleSource() { - return "", fmt.Errorf("invalid google source path: %s", m.Path) - } - parts := strings.Split(strings.Trim(m.Path, "/"), "/") - if len(parts) < 2 { - return "", fmt.Errorf("invalid google source path: %s", m.Path) - } - projectName := parts[1] - filePath := m.FilePath - extraPath := strings.Join(parts[2:], "/") - if extraPath != "" { - filePath = filepath.Join(extraPath, filePath) - } - version, err := refFromVersion(m.Version.Version) - if err != nil { - return "", err - } - if version == "" { - version = "master" - } - return fmt.Sprintf("https://go.googlesource.com/%s/+/%s/%s?format=TEXT", projectName, version, filePath), nil -} - -// refFromVersion returns the git ref from the given module version. -func refFromVersion(version string) (string, error) { - if module.IsPseudoVersion(version) { - rev, err := module.PseudoVersionRev(version) - if err != nil { - return "", err - } - return rev, nil - } - if sem := semver.Canonical(version); sem != "" { - return sem, nil - } - - return version, nil -} - -// cleanWhiteSpace removes all white space characters from the given string. -func cleanWhiteSpace(s string) string { - space := false - return strings.Map(func(r rune) rune { - if r == '\n' || r == '\t' { - return -1 - } - if r == ' ' && space { - return -1 - } - space = r == ' ' - return r - }, s) -} diff --git a/pkg/querier/vcs/source/golang/packages_gen.go b/pkg/querier/vcs/source/golang/packages_gen.go deleted file mode 100644 index 07f71d7e07..0000000000 --- a/pkg/querier/vcs/source/golang/packages_gen.go +++ /dev/null @@ -1,267 +0,0 @@ -package golang - -// Code generated. DO NOT EDIT. - -var StandardPackages = map[string]struct{}{ - "archive/tar": {}, - "archive/zip": {}, - "bufio": {}, - "builtin": {}, - "bytes": {}, - "cmp": {}, - "compress/bzip2": {}, - "compress/flate": {}, - "compress/gzip": {}, - "compress/lzw": {}, - "compress/zlib": {}, - "container/heap": {}, - "container/list": {}, - "container/ring": {}, - "context": {}, - "crypto": {}, - "crypto/aes": {}, - "crypto/cipher": {}, - "crypto/des": {}, - "crypto/dsa": {}, - "crypto/ecdh": {}, - "crypto/ecdsa": {}, - "crypto/ed25519": {}, - "crypto/elliptic": {}, - "crypto/hmac": {}, - "crypto/internal/alias": {}, - "crypto/internal/bigmod": {}, - "crypto/internal/boring": {}, - "crypto/internal/boring/bbig": {}, - "crypto/internal/boring/bcache": {}, - "crypto/internal/boring/sig": {}, - "crypto/internal/edwards25519": {}, - "crypto/internal/edwards25519/field": {}, - "crypto/internal/nistec": {}, - "crypto/internal/nistec/fiat": {}, - "crypto/internal/randutil": {}, - "crypto/md5": {}, - "crypto/rand": {}, - "crypto/rc4": {}, - "crypto/rsa": {}, - "crypto/sha1": {}, - "crypto/sha256": {}, - "crypto/sha512": {}, - "crypto/subtle": {}, - "crypto/tls": {}, - "crypto/x509": {}, - "crypto/x509/internal/macos": {}, - "crypto/x509/pkix": {}, - "database/sql": {}, - "database/sql/driver": {}, - "debug/buildinfo": {}, - "debug/dwarf": {}, - "debug/elf": {}, - "debug/gosym": {}, - "debug/macho": {}, - "debug/pe": {}, - "debug/plan9obj": {}, - "embed": {}, - "encoding": {}, - "encoding/ascii85": {}, - "encoding/asn1": {}, - "encoding/base32": {}, - "encoding/base64": {}, - "encoding/binary": {}, - "encoding/csv": {}, - "encoding/gob": {}, - "encoding/hex": {}, - "encoding/json": {}, - "encoding/pem": {}, - "encoding/xml": {}, - "errors": {}, - "expvar": {}, - "flag": {}, - "fmt": {}, - "go/ast": {}, - "go/build": {}, - "go/build/constraint": {}, - "go/constant": {}, - "go/doc": {}, - "go/doc/comment": {}, - "go/format": {}, - "go/importer": {}, - "go/internal/gccgoimporter": {}, - "go/internal/gcimporter": {}, - "go/internal/srcimporter": {}, - "go/internal/typeparams": {}, - "go/parser": {}, - "go/printer": {}, - "go/scanner": {}, - "go/token": {}, - "go/types": {}, - "hash": {}, - "hash/adler32": {}, - "hash/crc32": {}, - "hash/crc64": {}, - "hash/fnv": {}, - "hash/maphash": {}, - "html": {}, - "html/template": {}, - "image": {}, - "image/color": {}, - "image/color/palette": {}, - "image/draw": {}, - "image/gif": {}, - "image/internal/imageutil": {}, - "image/jpeg": {}, - "image/png": {}, - "index/suffixarray": {}, - "internal/abi": {}, - "internal/bisect": {}, - "internal/buildcfg": {}, - "internal/bytealg": {}, - "internal/cfg": {}, - "internal/coverage": {}, - "internal/coverage/calloc": {}, - "internal/coverage/cformat": {}, - "internal/coverage/cmerge": {}, - "internal/coverage/decodecounter": {}, - "internal/coverage/decodemeta": {}, - "internal/coverage/encodecounter": {}, - "internal/coverage/encodemeta": {}, - "internal/coverage/pods": {}, - "internal/coverage/rtcov": {}, - "internal/coverage/slicereader": {}, - "internal/coverage/slicewriter": {}, - "internal/coverage/stringtab": {}, - "internal/coverage/uleb128": {}, - "internal/cpu": {}, - "internal/dag": {}, - "internal/diff": {}, - "internal/fmtsort": {}, - "internal/fuzz": {}, - "internal/goarch": {}, - "internal/godebug": {}, - "internal/godebugs": {}, - "internal/goexperiment": {}, - "internal/goos": {}, - "internal/goroot": {}, - "internal/goversion": {}, - "internal/intern": {}, - "internal/itoa": {}, - "internal/lazyregexp": {}, - "internal/lazytemplate": {}, - "internal/nettrace": {}, - "internal/obscuretestdata": {}, - "internal/oserror": {}, - "internal/pkgbits": {}, - "internal/platform": {}, - "internal/poll": {}, - "internal/profile": {}, - "internal/race": {}, - "internal/reflectlite": {}, - "internal/safefilepath": {}, - "internal/saferio": {}, - "internal/singleflight": {}, - "internal/syscall/execenv": {}, - "internal/syscall/unix": {}, - "internal/syscall/windows": {}, - "internal/syscall/windows/registry": {}, - "internal/syscall/windows/sysdll": {}, - "internal/sysinfo": {}, - "internal/testenv": {}, - "internal/testlog": {}, - "internal/testpty": {}, - "internal/trace": {}, - "internal/txtar": {}, - "internal/types/errors": {}, - "internal/unsafeheader": {}, - "internal/xcoff": {}, - "internal/zstd": {}, - "io": {}, - "io/fs": {}, - "io/ioutil": {}, - "log": {}, - "log/internal": {}, - "log/slog": {}, - "log/slog/internal": {}, - "log/slog/internal/benchmarks": {}, - "log/slog/internal/buffer": {}, - "log/slog/internal/slogtest": {}, - "log/syslog": {}, - "maps": {}, - "math": {}, - "math/big": {}, - "math/bits": {}, - "math/cmplx": {}, - "math/rand": {}, - "mime": {}, - "mime/multipart": {}, - "mime/quotedprintable": {}, - "net": {}, - "net/http": {}, - "net/http/cgi": {}, - "net/http/cookiejar": {}, - "net/http/fcgi": {}, - "net/http/httptest": {}, - "net/http/httptrace": {}, - "net/http/httputil": {}, - "net/http/internal": {}, - "net/http/internal/ascii": {}, - "net/http/internal/testcert": {}, - "net/http/pprof": {}, - "net/internal/socktest": {}, - "net/mail": {}, - "net/netip": {}, - "net/rpc": {}, - "net/rpc/jsonrpc": {}, - "net/smtp": {}, - "net/textproto": {}, - "net/url": {}, - "os": {}, - "os/exec": {}, - "os/exec/internal/fdtest": {}, - "os/signal": {}, - "os/user": {}, - "path": {}, - "path/filepath": {}, - "plugin": {}, - "reflect": {}, - "reflect/internal/example1": {}, - "reflect/internal/example2": {}, - "regexp": {}, - "regexp/syntax": {}, - "runtime": {}, - "runtime/cgo": {}, - "runtime/coverage": {}, - "runtime/debug": {}, - "runtime/internal/atomic": {}, - "runtime/internal/math": {}, - "runtime/internal/startlinetest": {}, - "runtime/internal/sys": {}, - "runtime/internal/syscall": {}, - "runtime/metrics": {}, - "runtime/pprof": {}, - "runtime/race": {}, - "runtime/race/internal/amd64v1": {}, - "runtime/trace": {}, - "slices": {}, - "sort": {}, - "strconv": {}, - "strings": {}, - "sync": {}, - "sync/atomic": {}, - "syscall": {}, - "syscall/js": {}, - "testing": {}, - "testing/fstest": {}, - "testing/internal/testdeps": {}, - "testing/iotest": {}, - "testing/quick": {}, - "testing/slogtest": {}, - "text/scanner": {}, - "text/tabwriter": {}, - "text/template": {}, - "text/template/parse": {}, - "time": {}, - "time/tzdata": {}, - "unicode": {}, - "unicode/utf16": {}, - "unicode/utf8": {}, - "unsafe": {}, -} diff --git a/pkg/querier/vcs/token.go b/pkg/querier/vcs/token.go deleted file mode 100644 index eb80982245..0000000000 --- a/pkg/querier/vcs/token.go +++ /dev/null @@ -1,160 +0,0 @@ -package vcs - -import ( - "context" - "crypto/sha256" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "os" - "strconv" - "time" - - "connectrpc.com/connect" - "golang.org/x/oauth2" - - "github.com/grafana/pyroscope/pkg/tenant" -) - -const ( - sessionCookieName = "GitSession" -) - -type gitSessionTokenCookie struct { - Metadata string `json:"metadata"` - ExpiryTimestamp int64 `json:"expiry"` -} - -const envVarGithubSessionSecret = "GITHUB_SESSION_SECRET" - -var githubSessionSecret = []byte(os.Getenv(envVarGithubSessionSecret)) - -// derives a per tenant key from the global session secret using sha256 -func deriveEncryptionKeyForContext(ctx context.Context) ([]byte, error) { - tenantID, err := tenant.ExtractTenantIDFromContext(ctx) - if err != nil { - return nil, err - } - if len(tenantID) == 0 { - return nil, errors.New("tenantID is empty") - } - - if len(githubSessionSecret) == 0 { - return nil, errors.New(envVarGithubSessionSecret + " is empty") - } - h := sha256.New() - h.Write(githubSessionSecret) - h.Write([]byte{':'}) - h.Write([]byte(tenantID)) - return h.Sum(nil), nil -} - -// getStringValueFrom gets a string value from url.Values. It will fail if the -// key is missing or the key's value is an empty string. -func getStringValueFrom(values url.Values, key string) (string, error) { - value := values.Get(key) - if value == "" { - return "", fmt.Errorf("missing key: %s", key) - } - return value, nil -} - -// getDurationValueFrom gets a duration value from url.Values. It will fail if -// the key is missing, the key's value is an empty string, or the key's value -// cannot be parsed into a duration. -func getDurationValueFrom(values url.Values, key string, scalar time.Duration) (time.Duration, error) { - if scalar < 1 { - return 0, fmt.Errorf("cannot use scalar less than 1") - } - - value, err := getStringValueFrom(values, key) - if err != nil { - return 0, err - } - - n, err := strconv.Atoi(value) - if err != nil { - return 0, fmt.Errorf("failed to parse %s: %w", key, err) - } - - return time.Duration(n) * scalar, nil -} - -// tokenFromRequest decodes an OAuth token from a request. -func tokenFromRequest(ctx context.Context, req connect.AnyRequest) (*oauth2.Token, error) { - cookie, err := (&http.Request{Header: req.Header()}).Cookie(sessionCookieName) - if err != nil { - return nil, fmt.Errorf("failed to read cookie %s: %w", sessionCookieName, err) - } - - derivedKey, err := deriveEncryptionKeyForContext(ctx) - if err != nil { - return nil, err - } - - token, err := decodeToken(cookie.Value, derivedKey) - if err != nil { - return nil, err - } - return token, nil -} - -// encodeToken encrypts then base64 encodes an OAuth token. -func encodeToken(token *oauth2.Token, key []byte) (*http.Cookie, error) { - encrypted, err := encryptToken(token, key) - if err != nil { - return nil, err - } - - bytes, err := json.Marshal(gitSessionTokenCookie{ - Metadata: encrypted, - ExpiryTimestamp: token.Expiry.UnixMilli(), - }) - if err != nil { - return nil, err - } - - encoded := base64.StdEncoding.EncodeToString(bytes) - cookie := &http.Cookie{ - Name: sessionCookieName, - Value: encoded, - Expires: time.Now().Add(githubRefreshExpiryDuration), - HttpOnly: false, - Secure: true, - SameSite: http.SameSiteLaxMode, - } - return cookie, nil -} - -// decodeToken base64 decodes and decrypts a OAuth token. -func decodeToken(value string, key []byte) (*oauth2.Token, error) { - var token *oauth2.Token - - decoded, err := base64.StdEncoding.DecodeString(value) - if err != nil { - return nil, err - } - - sessionToken := gitSessionTokenCookie{} - err = json.Unmarshal(decoded, &sessionToken) - if err != nil { - // This may be a legacy cookie. Legacy cookies aren't base64 encoded - // JSON objects, but rather a base64 encoded crypto hash. - var innerErr error - token, innerErr = decryptToken(value, key) - if innerErr != nil { - // Legacy fallback failed, return the original error. - return nil, err - } - return token, nil - } - - token, err = decryptToken(sessionToken.Metadata, key) - if err != nil { - return nil, err - } - return token, nil -} diff --git a/pkg/querier/worker/scheduler_processor.go b/pkg/querier/worker/scheduler_processor.go index 8430d3a9d2..c572007c16 100644 --- a/pkg/querier/worker/scheduler_processor.go +++ b/pkg/querier/worker/scheduler_processor.go @@ -15,28 +15,28 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/gogo/status" "github.com/grafana/dskit/backoff" "github.com/grafana/dskit/grpcclient" "github.com/grafana/dskit/middleware" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/ring/client" "github.com/grafana/dskit/services" + "github.com/grafana/dskit/tracing" "github.com/grafana/dskit/user" - otgrpc "github.com/opentracing-contrib/go-grpc" - "github.com/opentracing/opentracing-go" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.uber.org/atomic" "google.golang.org/grpc" "google.golang.org/grpc/health/grpc_health_v1" - - "github.com/grafana/pyroscope/pkg/frontend/frontendpb" - querier_stats "github.com/grafana/pyroscope/pkg/querier/stats" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb" - util_log "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" - "github.com/grafana/pyroscope/pkg/util/httpgrpcutil" + "google.golang.org/grpc/status" + + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb" + querier_stats "github.com/grafana/pyroscope/v2/pkg/querier/stats" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb" + util_log "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpcutil" ) var processorBackoffConfig = backoff.Config{ @@ -58,9 +58,12 @@ func newSchedulerProcessor(cfg Config, handler RequestHandler, log log.Logger, r }, frontendClientRequestDuration: promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{ - Name: "pyroscope_querier_query_frontend_request_duration_seconds", - Help: "Time spend doing requests to frontend.", - Buckets: prometheus.ExponentialBuckets(0.001, 4, 6), + Name: "pyroscope_querier_query_frontend_request_duration_seconds", + Help: "Time spend doing requests to frontend.", + Buckets: prometheus.ExponentialBuckets(0.001, 4, 6), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }, []string{"operation", "status_code"}), } @@ -194,18 +197,14 @@ func (sp *schedulerProcessor) querierLoop(parentCtx context.Context, schedulerCl go func() { defer inflightQuery.Store(false) + // Extract trace context from HTTP headers and graft it onto the + // stream context so that cancellation is propagated when the + // stream closes. + ctx := httpgrpcutil.GetParentContextForRequest(c.Context(), request.HttpRequest) // We need to inject user into context for sending response back. - ctx := user.InjectOrgID(c.Context(), request.UserID) - - tracer := opentracing.GlobalTracer() - // Ignore errors here. If we cannot get parent span, we just don't create new one. - parentSpanContext, _ := httpgrpcutil.GetParentSpanForRequest(tracer, request.HttpRequest) - if parentSpanContext != nil { - queueSpan, spanCtx := opentracing.StartSpanFromContextWithTracer(ctx, tracer, "querier_processor_runRequest", opentracing.ChildOf(parentSpanContext)) - defer queueSpan.Finish() - - ctx = spanCtx - } + ctx = user.InjectOrgID(ctx, request.UserID) + queueSpan, ctx := tracing.StartSpanFromContext(ctx, "querier_processor_runRequest") + defer queueSpan.Finish() logger := util_log.LoggerWithContext(ctx, sp.log) sp.runRequest(ctx, logger, request.QueryID, request.FrontendAddress, request.StatsEnabled, request.HttpRequest) @@ -294,11 +293,15 @@ func (f *frontendClientFactory) FromInstance(inst ring.InstanceDesc) (client.Poo func (sp *schedulerProcessor) frontendClientFactory() client.PoolFactory { return newFrontendClientFactory(func() ([]grpc.DialOption, error) { - return sp.grpcConfig.DialOption([]grpc.UnaryClientInterceptor{ - otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer()), + opts, err := sp.grpcConfig.DialOption([]grpc.UnaryClientInterceptor{ middleware.ClientUserHeaderInterceptor, middleware.UnaryClientInstrumentInterceptor(sp.frontendClientRequestDuration), - }, nil) + }, nil, nil) + if err != nil { + return nil, err + } + opts = append(opts, grpc.WithStatsHandler(otelgrpc.NewClientHandler())) + return opts, nil }) } diff --git a/pkg/querier/worker/scheduler_processor_test.go b/pkg/querier/worker/scheduler_processor_test.go index 87c605e256..782ef5b8a5 100644 --- a/pkg/querier/worker/scheduler_processor_test.go +++ b/pkg/querier/worker/scheduler_processor_test.go @@ -8,7 +8,6 @@ import ( "time" "github.com/go-kit/log" - "github.com/gogo/status" "github.com/grafana/dskit/concurrency" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -17,9 +16,10 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) func TestSchedulerProcessor_processQueriesOnSingleStream(t *testing.T) { diff --git a/pkg/querier/worker/worker.go b/pkg/querier/worker/worker.go index c377400a8a..3a3ce851ed 100644 --- a/pkg/querier/worker/worker.go +++ b/pkg/querier/worker/worker.go @@ -7,6 +7,7 @@ package worker import ( "context" + "errors" "flag" "fmt" "os" @@ -17,13 +18,12 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/grpcclient" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "google.golang.org/grpc" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerdiscovery" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" - "github.com/grafana/pyroscope/pkg/util/servicediscovery" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerdiscovery" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/servicediscovery" ) type Config struct { @@ -99,7 +99,7 @@ func NewQuerierWorker(cfg Config, handler RequestHandler, log log.Logger, reg pr if cfg.QuerierID == "" { hostname, err := os.Hostname() if err != nil { - return nil, errors.Wrap(err, "failed to get hostname for configuring querier ID") + return nil, fmt.Errorf("failed to get hostname for configuring querier ID: %w", err) } cfg.QuerierID = hostname } @@ -147,7 +147,7 @@ func newQuerierWorkerWithProcessor(cfg Config, log log.Logger, processor process if len(servs) > 0 { subservices, err := services.NewManager(servs...) if err != nil { - return nil, errors.Wrap(err, "querier worker subservices") + return nil, fmt.Errorf("querier worker subservices: %w", err) } f.subservices = subservices @@ -172,7 +172,7 @@ func (w *querierWorker) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-w.subservicesWatcher.Chan(): // The channel will be nil if w.subservicesWatcher is not set. - return errors.Wrap(err, "querier worker subservice failed") + return fmt.Errorf("querier worker subservice failed: %w", err) } } @@ -343,7 +343,7 @@ func (w *querierWorker) getDesiredConcurrency() map[string]int { func (w *querierWorker) connect(ctx context.Context, address string) (*grpc.ClientConn, error) { // Because we only use single long-running method, it doesn't make sense to inject user ID, send over tracing or add metrics. - opts, err := w.cfg.GRPCClientConfig.DialOption(nil, nil) + opts, err := w.cfg.GRPCClientConfig.DialOption(nil, nil, nil) if err != nil { return nil, err } diff --git a/pkg/querier/worker/worker_test.go b/pkg/querier/worker/worker_test.go index 1973339edf..4feadc9140 100644 --- a/pkg/querier/worker/worker_test.go +++ b/pkg/querier/worker/worker_test.go @@ -19,8 +19,8 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/grpc" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerdiscovery" - "github.com/grafana/pyroscope/pkg/util/servicediscovery" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerdiscovery" + "github.com/grafana/pyroscope/v2/pkg/util/servicediscovery" ) func TestConfig_Validate(t *testing.T) { diff --git a/pkg/querybackend/backend.go b/pkg/querybackend/backend.go new file mode 100644 index 0000000000..c863e5c4da --- /dev/null +++ b/pkg/querybackend/backend.go @@ -0,0 +1,208 @@ +package querybackend + +import ( + "context" + "flag" + "fmt" + "os" + "sync" + "sync/atomic" + "time" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/services" + "github.com/grafana/dskit/tracing" + "github.com/prometheus/client_golang/prometheus" + "golang.org/x/sync/errgroup" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type Config struct { + Address string `yaml:"address" category:"advanced"` + GRPCClientConfig grpcclient.Config `yaml:"grpc_client_config" doc:"description=Configures the gRPC client used to communicate between the query-frontends and the query-schedulers."` + ClientTimeout time.Duration `yaml:"client_timeout" category:"advanced"` +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + f.StringVar(&cfg.Address, "query-backend.address", "localhost:9095", "") + f.DurationVar(&cfg.ClientTimeout, "query-backend.client-timeout", 30*time.Second, "Timeout for query-backend client requests.") + cfg.GRPCClientConfig.RegisterFlagsWithPrefix("query-backend.grpc-client-config", f) +} + +func (cfg *Config) Validate() error { + if cfg.Address == "" { + return fmt.Errorf("query-backend.address is required") + } + return cfg.GRPCClientConfig.Validate() +} + +type QueryHandler interface { + Invoke(context.Context, *queryv1.InvokeRequest) (*queryv1.InvokeResponse, error) +} + +type QueryBackend struct { + service services.Service + queryv1.QueryBackendServiceServer + + config Config + logger log.Logger + reg prometheus.Registerer + + backendClient QueryHandler + blockReader QueryHandler + hostname string +} + +func New( + config Config, + logger log.Logger, + reg prometheus.Registerer, + backendClient QueryHandler, + blockReader QueryHandler, +) (*QueryBackend, error) { + hostname, _ := os.Hostname() + q := QueryBackend{ + config: config, + logger: logger, + reg: reg, + backendClient: backendClient, + blockReader: blockReader, + hostname: hostname, + } + q.service = services.NewIdleService(q.starting, q.stopping) + return &q, nil +} + +func (q *QueryBackend) Service() services.Service { return q.service } +func (q *QueryBackend) starting(context.Context) error { return nil } +func (q *QueryBackend) stopping(error) error { return nil } + +func (q *QueryBackend) Invoke( + ctx context.Context, + req *queryv1.InvokeRequest, +) (*queryv1.InvokeResponse, error) { + span, ctx := tracing.StartSpanFromContext(ctx, "QueryBackend.Invoke") + defer span.Finish() + + collectDiag := req.Options != nil && req.Options.CollectDiagnostics + startTime := time.Now() + + var resp *queryv1.InvokeResponse + var err error + var childNodes []*queryv1.ExecutionNode + var mergeBytes uint64 + + // Capture the node type before merge() sets QueryPlan to nil. + root := req.QueryPlan.Root + nodeType := root.Type + + switch nodeType { + case queryv1.QueryNode_MERGE: + resp, childNodes, mergeBytes, err = q.merge(ctx, req, root.Children, collectDiag) + case queryv1.QueryNode_READ: + resp, err = q.read(ctx, req, root.Blocks) + default: + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("query plan: unknown node type %v", nodeType)) + } + + if err != nil { + return nil, err + } + + // For MERGE nodes, unconditionally expose the summed BytesFetched so the + // query-frontend counter is correct even when diagnostics are not collected + // (the common production case). For READ nodes, BlockReader already set + // the ExecutionNode. + if nodeType == queryv1.QueryNode_MERGE { + if resp.Diagnostics == nil { + resp.Diagnostics = &queryv1.Diagnostics{} + } + stats := &queryv1.ExecutionStats{BytesFetched: mergeBytes} + if collectDiag { + resp.Diagnostics.ExecutionNode = &queryv1.ExecutionNode{ + Type: nodeType, + Executor: q.hostname, + StartTimeNs: startTime.UnixNano(), + EndTimeNs: time.Now().UnixNano(), + Children: childNodes, + Stats: stats, + } + } else { + resp.Diagnostics.ExecutionNode = &queryv1.ExecutionNode{ + Stats: stats, + } + } + } + + return resp, nil +} + +func (q *QueryBackend) merge( + ctx context.Context, + request *queryv1.InvokeRequest, + children []*queryv1.QueryNode, + collectDiag bool, +) (*queryv1.InvokeResponse, []*queryv1.ExecutionNode, uint64, error) { + request.QueryPlan = nil + m := newAggregator(request) + g, ctx := errgroup.WithContext(ctx) + + childExecNodes := make([]*queryv1.ExecutionNode, len(children)) + var mu sync.Mutex + var totalBytesFetched atomic.Uint64 + + for i, child := range children { + idx := i + req := request.CloneVT() + req.QueryPlan = &queryv1.QueryPlan{ + Root: child, + } + g.Go(util.RecoverPanic(func() error { + // TODO: Speculative retry. + resp, err := q.backendClient.Invoke(ctx, req) + if err != nil { + return err + } + // Always accumulate bytes regardless of collectDiag so the + // query-frontend counter is correct in the common (non-diagnostic) path. + totalBytesFetched.Add(resp.GetDiagnostics().GetExecutionNode().GetStats().GetBytesFetched()) + if collectDiag && resp.Diagnostics != nil && resp.Diagnostics.ExecutionNode != nil { + mu.Lock() + childExecNodes[idx] = resp.Diagnostics.ExecutionNode + mu.Unlock() + } + return m.aggregateResponse(resp, nil) + })) + } + if err := g.Wait(); err != nil { + return nil, nil, 0, err + } + + var executionNodes []*queryv1.ExecutionNode + for _, n := range childExecNodes { + if n != nil { + executionNodes = append(executionNodes, n) + } + } + + resp := m.response() + return resp, executionNodes, totalBytesFetched.Load(), nil +} + +func (q *QueryBackend) read( + ctx context.Context, + request *queryv1.InvokeRequest, + blocks []*metastorev1.BlockMeta, +) (*queryv1.InvokeResponse, error) { + request.QueryPlan = &queryv1.QueryPlan{ + Root: &queryv1.QueryNode{ + Blocks: blocks, + }, + } + return q.blockReader.Invoke(ctx, request) +} diff --git a/pkg/querybackend/block_reader.go b/pkg/querybackend/block_reader.go new file mode 100644 index 0000000000..f8cee5dd67 --- /dev/null +++ b/pkg/querybackend/block_reader.go @@ -0,0 +1,311 @@ +package querybackend + +import ( + "context" + "fmt" + "os" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/dustin/go-humanize" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/multierror" + "github.com/grafana/dskit/tracing" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/util" + validationutil "github.com/grafana/pyroscope/v2/pkg/util/validation" +) + +// BlockReader reads blocks from object storage. Each block is represented by +// a single object, which consists of datasets – regions within the object +// that contain tenant data. +// +// A single Invoke request may span multiple blocks (objects). +// Querying an object could involve processing multiple datasets in parallel. +// Multiple parallel queries can be executed on the same tenant dataset. +// +// object-a dataset-a query-a +// query-b +// dataset-b query-a +// query-b +// object-b dataset-a query-a +// query-b +// dataset-b query-a +// query-b +// + +type Overrides interface { + IncludeStrippedProfiles(tenantID string) bool +} + +type BlockReader struct { + log log.Logger + storage objstore.Bucket + + metrics *metrics + hostname string + + Overrides Overrides + + // TODO: + // - Use a worker pool instead of the errgroup. + // - Reusable query context. + // - Query pipelining: currently, queries share the same context, + // and reuse resources, but the data is processed independently. + // Instead, they should share the processing pipeline, if possible. +} + +func NewBlockReader(logger log.Logger, storage objstore.Bucket, reg prometheus.Registerer, overrides Overrides) *BlockReader { + hostname, _ := os.Hostname() + return &BlockReader{ + log: logger, + storage: storage, + metrics: newMetrics(reg), + hostname: hostname, + Overrides: overrides, + } +} + +func (b *BlockReader) Invoke( + ctx context.Context, + req *queryv1.InvokeRequest, +) (*queryv1.InvokeResponse, error) { + span, ctx := tracing.StartSpanFromContext(ctx, "BlockReader.Invoke") + defer span.Finish() + + collectDiag := req.Options != nil && req.Options.CollectDiagnostics + startTime := time.Now() + + r, err := validateRequest(req) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "request validation failed: %v", err) + } + r.setTraceTags(span) + + g, ctx := errgroup.WithContext(ctx) + agg := newAggregator(req) + + tenantMap := make(map[string]struct{}) + for _, tenant := range req.Tenant { + tenantMap[tenant] = struct{}{} + } + + includeStripped := validationutil.AllTruePerTenant(req.Tenant, b.Overrides.IncludeStrippedProfiles) + + var blockExecCollector *blockExecutionCollector + if collectDiag { + blockExecCollector = &blockExecutionCollector{} + } + + weightCollector := &queryWeightCollector{} + + // Per-invocation byte counter: only the successful response carries the + // total, so retried calls from the query-frontend never double-count. + var fetchedBytes atomic.Uint64 + countingStorage := objstore.NewCountingBucket(b.storage, &fetchedBytes) + + var blocksCount, datasetsCount int64 + for _, md := range req.QueryPlan.Root.Blocks { + md.Datasets, err = filterNotOwnedDatasets(md, tenantMap) + if err != nil { + b.metrics.datasetTenantIsolationFailure.Inc() + traceId, _ := tracing.ExtractTraceID(ctx) + level.Error(b.log).Log("msg", "trying to query datasets of other tenants", "valid-tenant", strings.Join(req.Tenant, ","), "block", md.Id, "err", err, "traceId", traceId) + } + if len(md.Datasets) == 0 { + continue + } + blocksCount++ + datasetsCount += int64(len(md.Datasets)) + obj := block.NewObject(countingStorage, md) + g.Go(util.RecoverPanic((&blockContext{ + ctx: ctx, + log: b.log, + req: r, + agg: agg, + obj: obj, + grp: g, + execCollector: blockExecCollector, + weightCollector: weightCollector, + includeStripped: includeStripped, + }).execute)) + } + + if err = g.Wait(); err != nil { + return nil, err + } + + // Wait for any async readers (e.g. parquet ReadModeAsync goroutines) that + // may still be draining a GetRange reader after the errgroup returned. + // This ensures fetchedBytes is stable before we sample it below. + countingStorage.Wait() + + if weightCollector.datasetsCount > 0 { + traceID, _ := tracing.ExtractTraceID(ctx) + level.Info(b.log).Log( + "msg", "query weight (index lookup resolved)", + "trace_id", traceID, + "tenant", strings.Join(req.Tenant, ","), + "blocks", blocksCount, + "datasets", weightCollector.datasetsCount, + "profiles_bytes", humanize.Bytes(weightCollector.weight.ProfilesBytes), + "tsdb_bytes", humanize.Bytes(weightCollector.weight.TSDBBytes), + "symbols_bytes", humanize.Bytes(weightCollector.weight.SymbolsBytes), + "total_bytes", humanize.Bytes(weightCollector.weight.Total()), + ) + span.SetTag("index_lookup_resolved", true) + span.SetTag("resolved_profiles_bytes", weightCollector.weight.ProfilesBytes) + span.SetTag("resolved_tsdb_bytes", weightCollector.weight.TSDBBytes) + span.SetTag("resolved_symbols_bytes", weightCollector.weight.SymbolsBytes) + span.SetTag("resolved_total_bytes", weightCollector.weight.Total()) + span.SetTag("resolved_datasets_count", weightCollector.datasetsCount) + } + + resp := agg.response() + + if resp.Diagnostics == nil { + resp.Diagnostics = &queryv1.Diagnostics{} + } + stats := &queryv1.ExecutionStats{ + BytesFetched: fetchedBytes.Load(), + } + if collectDiag { + stats.BlocksRead = blocksCount + stats.DatasetsProcessed = datasetsCount + stats.BlockExecutions = blockExecCollector.collect() + resp.Diagnostics.ExecutionNode = &queryv1.ExecutionNode{ + Type: queryv1.QueryNode_READ, + Executor: b.hostname, + StartTimeNs: startTime.UnixNano(), + EndTimeNs: time.Now().UnixNano(), + Stats: stats, + } + } else { + resp.Diagnostics.ExecutionNode = &queryv1.ExecutionNode{ + Stats: stats, + } + } + + return resp, nil +} + +type request struct { + src *queryv1.InvokeRequest + matchers []*labels.Matcher + startTime int64 // Unix nano. + endTime int64 // Unix nano. +} + +func (r *request) setTraceTags(span *tracing.Span) { + if r.src == nil { + return + } + span.SetTag("start_time", model.Time(r.src.StartTime).Time().String()) + span.SetTag("end_time", model.Time(r.src.EndTime).Time().String()) + span.SetTag("matchers", r.src.LabelSelector) + + if len(r.src.Query) > 0 { + queryTypes := make([]string, 0, len(r.src.Query)) + for _, q := range r.src.Query { + queryTypes = append(queryTypes, q.QueryType.String()) + } + span.SetTag("query_types", queryTypes) + } +} + +func validateRequest(req *queryv1.InvokeRequest) (*request, error) { + if len(req.Query) == 0 { + return nil, fmt.Errorf("no query provided") + } + if req.QueryPlan == nil || len(req.QueryPlan.Root.Blocks) == 0 { + return nil, fmt.Errorf("no blocks to query") + } + if len(req.Tenant) == 0 { + return nil, fmt.Errorf("no tenant provided") + } + matchers, err := phlaremodel.ParseMetricSelector(req.LabelSelector) + if err != nil { + return nil, fmt.Errorf("label selection is invalid: %w", err) + } + r := request{ + src: req, + matchers: matchers, + startTime: model.Time(req.StartTime).UnixNano(), + endTime: model.Time(req.EndTime).UnixNano(), + } + return &r, nil +} + +// While the metastore is expected to already filter datasets of other tenants, we do an additional check to avoid +// processing blocks or datasets belonging to the wrong tenant. +func filterNotOwnedDatasets(b *metastorev1.BlockMeta, tenantMap map[string]struct{}) ([]*metastorev1.Dataset, error) { + errs := multierror.New() + datasets := make([]*metastorev1.Dataset, 0) + for _, dataset := range b.Datasets { + datasetTenant := b.StringTable[dataset.Tenant] + _, ok := tenantMap[datasetTenant] + if ok { + datasets = append(datasets, dataset) + } else { + errs.Add(fmt.Errorf(`dataset "%s" belongs to tenant "%s"`, b.StringTable[dataset.Name], datasetTenant)) + } + } + return datasets, errs.Err() +} + +// queryWeightCollector accumulates dataset section sizes across all blocks in a query, +// including Format1 blocks whose datasets are resolved at runtime. +type queryWeightCollector struct { + mu sync.Mutex + weight block.DatasetWeight + datasetsCount int64 +} + +func (c *queryWeightCollector) addDatasets(datasets []*metastorev1.Dataset) { + var w block.DatasetWeight + for _, ds := range datasets { + w.Add(block.WeightOf(ds)) + } + c.mu.Lock() + c.weight.Add(w) + c.datasetsCount += int64(len(datasets)) + c.mu.Unlock() +} + +// blockExecutionCollector collects per-block execution stats in a thread-safe manner. +type blockExecutionCollector struct { + mu sync.Mutex + executions []*queryv1.BlockExecution +} + +func (c *blockExecutionCollector) record(exec *queryv1.BlockExecution) { + if c == nil { + return + } + c.mu.Lock() + c.executions = append(c.executions, exec) + c.mu.Unlock() +} + +func (c *blockExecutionCollector) collect() []*queryv1.BlockExecution { + if c == nil { + return nil + } + c.mu.Lock() + defer c.mu.Unlock() + return c.executions +} diff --git a/pkg/querybackend/block_reader_test.go b/pkg/querybackend/block_reader_test.go new file mode 100644 index 0000000000..b39313f239 --- /dev/null +++ b/pkg/querybackend/block_reader_test.go @@ -0,0 +1,922 @@ +package querybackend + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "errors" + "os" + "path/filepath" + "slices" + "testing" + "time" + + "github.com/stretchr/testify/suite" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/querybackend/queryplan" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +type testSuite struct { + suite.Suite + dir string + + ctx context.Context + logger *test.TestingLogger + bucket *memory.InMemBucket + blocks []*metastorev1.BlockMeta + + reader *BlockReader + meta []*metastorev1.BlockMeta + plan *queryv1.QueryPlan + tenant []string +} + +func (s *testSuite) SetupSuite() { + s.bucket = memory.NewInMemBucket() + s.loadFromDir(s.dir) +} + +func (s *testSuite) SetupTest() { + s.ctx = context.Background() + s.logger = test.NewTestingLogger(s.T()) + s.reader = NewBlockReader(s.logger, &objstore.ReaderAtBucket{Bucket: s.bucket}, nil, validation.MockDefaultOverrides()) + s.meta = make([]*metastorev1.BlockMeta, len(s.blocks)) + for i, b := range s.blocks { + s.meta[i] = b.CloneVT() + } + s.sanitizeMetadata() + s.plan = queryplan.Build(s.meta, 10, 10) + s.tenant = make([]string, 0) + for _, b := range s.plan.Root.Blocks { + for _, d := range b.Datasets { + s.tenant = append(s.tenant, b.StringTable[d.Tenant]) + } + } +} + +func (s *testSuite) loadFromDir(dir string) { + s.Require().NoError(filepath.WalkDir(dir, s.visitPath)) +} + +func (s *testSuite) visitPath(path string, e os.DirEntry, err error) error { + if err != nil || e.IsDir() { + return err + } + b, err := os.ReadFile(path) + if err != nil { + return err + } + var md metastorev1.BlockMeta + if err = metadata.Decode(b, &md); err != nil { + return err + } + md.Size = uint64(len(b)) + s.blocks = append(s.blocks, &md) + return s.bucket.Upload(context.Background(), block.ObjectPath(&md), bytes.NewReader(b)) +} + +func (s *testSuite) sanitizeMetadata() { + // We read the whole block metadata, including all the datasets. + // In practice, this is never the case – metadata queries either + // return the datasets to be read or the dataset index. + hasIndex := 0 + total := 0 + for _, m := range s.meta { + for _, d := range m.Datasets { + total++ + if block.DatasetFormat(d.Format) == block.DatasetFormat1 { + m.Datasets = slices.DeleteFunc(m.Datasets, func(x *metastorev1.Dataset) bool { + return x.Format == 0 + }) + hasIndex++ + break + } + } + } + // We ensure that there are both cases. + s.Assert().NotZero(total) + s.Assert().NotZero(hasIndex) +} + +func (s *testSuite) BeforeTest(_, _ string) {} + +func (s *testSuite) AfterTest(_, _ string) {} + +func TestSuite(t *testing.T) { suite.Run(t, &testSuite{dir: "testdata/samples"}) } + +func (s *testSuite) Test_QueryTree_All() { + + expected, err := os.ReadFile("testdata/fixtures/tree_16.txt") + s.Require().NoError(err) + + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + tree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + s.Assert().Equal(string(expected), tree.String()) +} + +func (s *testSuite) Test_QueryTree_Filter() { + expected, err := os.ReadFile("testdata/fixtures/tree_16_slow.txt") + s.Require().NoError(err) + + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: `{service_name="test-app",function="slow"}`, + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + tree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + s.Assert().Equal(string(expected), tree.String()) +} + +func (s *testSuite) Test_QueryPprof_Metadata() { + selector := `{service_name="test-app",__profile_type__="process_cpu:cpu:nanoseconds:cpu:nanoseconds"}` + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: selector, + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{}, + }}, + Tenant: s.tenant, + }) + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + + var p profilev1.Profile + s.Require().NoError(pprof.Unmarshal(resp.Reports[0].Pprof.Pprof, &p)) + + s.Assert().Len(p.SampleType, 1) + s.Assert().Equal("cpu", p.StringTable[p.SampleType[0].Type]) + s.Assert().Equal("nanoseconds", p.StringTable[p.SampleType[0].Unit]) + + s.Assert().NotNil(p.PeriodType) + s.Assert().Equal("cpu", p.StringTable[p.PeriodType.Type]) + s.Assert().Equal("nanoseconds", p.StringTable[p.PeriodType.Unit]) +} + +func (s *testSuite) Test_DatasetIndex_SeriesLabels_GroupBy() { + selector := `{service_repository="https://github.com/grafana/pyroscope"}` + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: selector, + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_SERIES_LABELS, + SeriesLabels: &queryv1.SeriesLabelsQuery{ + LabelNames: []string{"service_name", "__profile_type__"}, + }, + }}, + Tenant: s.tenant, + }) + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + + expected, err := os.ReadFile("testdata/fixtures/series_labels_by.json") + s.Require().NoError(err) + actual, _ := json.Marshal(resp.Reports[0].SeriesLabels) + s.Assert().JSONEq(string(expected), string(actual)) +} + +func (s *testSuite) Test_SeriesLabels() { + selector := `{service_name="pyroscope"}` + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: selector, + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_SERIES_LABELS, + SeriesLabels: &queryv1.SeriesLabelsQuery{}, + }}, + Tenant: s.tenant, + }) + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + + expected, err := os.ReadFile("testdata/fixtures/series_labels.json") + s.Require().NoError(err) + actual, _ := json.Marshal(resp.Reports[0].SeriesLabels) + s.Assert().JSONEq(string(expected), string(actual)) +} + +var startTime = time.Unix(1739263329, 0) + +const ( + fixtureMatchingSpanID = "0000000000000001" + fixtureNonMatchingSpanID = "ffffffffffffffff" + + spanSelectorWantBaseline = "baseline" + spanSelectorWantEmpty = "empty" + spanSelectorWantFiltered = "filtered" +) + +func (s *testSuite) Test_QueryTimeSeries() { + query := &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_TIME_SERIES, + TimeSeries: &queryv1.TimeSeriesQuery{ + GroupBy: []string{"service_name"}, + Step: 30.0, + }, + } + + req := &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(time.Hour).UnixMilli(), + Query: []*queryv1.Query{query}, + QueryPlan: s.plan, + LabelSelector: "{}", + Tenant: s.tenant, + } + + resp, err := s.reader.Invoke(s.ctx, req) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + s.Require().NotNil(resp.Reports[0].TimeSeries) + + actual, _ := json.Marshal(resp.Reports[0].TimeSeries.TimeSeries) + expected, err := os.ReadFile("testdata/fixtures/time_series.json") + s.Require().NoError(err) + s.Assert().JSONEq(string(expected), string(actual)) +} + +// When there is only one report we don't run the aggregate method. This check ensures that the timeseries, is still correctly formatted. +func (s *testSuite) Test_QueryTimeSeriesOneReport() { + query := &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_TIME_SERIES, + TimeSeries: &queryv1.TimeSeriesQuery{ + GroupBy: []string{"service_name"}, + Step: 30.0, + }, + } + + // shorten plan so there is only one report + shorterPlan := s.plan.CloneVT() + shorterPlan.Root = s.plan.Root.CloneVT() + shorterPlan.Root.Blocks = s.plan.Root.Blocks[:1] + + req := &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(time.Hour).UnixMilli(), + Query: []*queryv1.Query{query}, + QueryPlan: shorterPlan, + LabelSelector: "{}", + Tenant: s.tenant, + } + + resp, err := s.reader.Invoke(s.ctx, req) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + s.Require().NotNil(resp.Reports[0].TimeSeries) + + actual, _ := json.Marshal(resp.Reports[0].TimeSeries.TimeSeries) + expected, err := os.ReadFile("testdata/fixtures/time_series_first_block.json") + s.Require().NoError(err) + s.Assert().JSONEq(string(expected), string(actual)) +} + +func (s *testSuite) Test_QueryTree_All_Tenant_Isolation() { + queryTenant := "some-tenant" + + s.Require().NotContains(s.tenant, queryTenant) + + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: []string{queryTenant}, + }) + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 0) +} + +func (s *testSuite) Test_ProfileIDSelector() { + // Get a real profile ID for valid test case + validProfileID := s.getProfileIDFromExemplars(s.T()) + + // Load baseline fixture for tree comparison + baselineTree, err := os.ReadFile("testdata/fixtures/tree_16.txt") + s.Require().NoError(err) + + // Get baseline tree for comparison + allTreeResp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + allTree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](allTreeResp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + // Get baseline pprof for comparison + allPprofResp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(5 * time.Minute).UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + var allProfile profilev1.Profile + err = pprof.Unmarshal(allPprofResp.Reports[0].Pprof.Pprof, &allProfile) + s.Require().NoError(err) + + tests := []struct { + queryType queryv1.QueryType + name string + profileIDSelector []string + wantErr bool + expectBaseline bool + expectFiltered bool + expectEmpty bool + }{ + // Tree query tests + {queryv1.QueryType_QUERY_TREE, "tree/invalid UUID returns error", []string{"invalid-uuid"}, true, false, false, false}, + {queryv1.QueryType_QUERY_TREE, "tree/empty selector returns baseline", []string{}, false, true, false, false}, + {queryv1.QueryType_QUERY_TREE, "tree/nil selector returns baseline", nil, false, true, false, false}, + {queryv1.QueryType_QUERY_TREE, "tree/non-existent UUID returns empty result", []string{"00000000-0000-0000-0000-000000000000"}, false, false, false, true}, + {queryv1.QueryType_QUERY_TREE, "tree/valid UUID filters to single profile", []string{validProfileID}, false, false, true, false}, + + // Pprof query tests + {queryv1.QueryType_QUERY_PPROF, "pprof/invalid UUID returns error", []string{"not-a-uuid"}, true, false, false, false}, + {queryv1.QueryType_QUERY_PPROF, "pprof/empty selector returns baseline", []string{}, false, true, false, false}, + {queryv1.QueryType_QUERY_PPROF, "pprof/nil selector returns baseline", nil, false, true, false, false}, + {queryv1.QueryType_QUERY_PPROF, "pprof/non-existent UUID returns empty result", []string{"00000000-0000-0000-0000-000000000000"}, false, false, false, true}, + {queryv1.QueryType_QUERY_PPROF, "pprof/valid UUID filters to single profile", []string{validProfileID}, false, false, true, false}, + } + + for _, tt := range tests { + s.Run(tt.name, func() { + var query *queryv1.Query + var reqStartTime, reqEndTime int64 + + if tt.queryType == queryv1.QueryType_QUERY_TREE { + reqEndTime = time.Now().UnixMilli() + query = &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{ + MaxNodes: 16, + ProfileIdSelector: tt.profileIDSelector, + }, + } + } else { + reqStartTime = startTime.UnixMilli() + reqEndTime = startTime.Add(5 * time.Minute).UnixMilli() + query = &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{ + ProfileIdSelector: tt.profileIDSelector, + }, + } + } + + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: reqStartTime, + EndTime: reqEndTime, + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{query}, + Tenant: s.tenant, + }) + + if tt.wantErr { + s.Require().Error(err) + s.Require().Nil(resp) + return + } + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + + if tt.queryType == queryv1.QueryType_QUERY_TREE { + tree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + if tt.expectBaseline { + s.Assert().Equal(string(baselineTree), tree.String()) + } + if tt.expectEmpty { + s.Assert().Zero(tree.Total()) + } + if tt.expectFiltered { + s.Assert().Less(tree.Total(), allTree.Total()) + s.Assert().NotZero(tree.Total()) + } + } else { + var profile profilev1.Profile + err = pprof.Unmarshal(resp.Reports[0].Pprof.Pprof, &profile) + s.Require().NoError(err) + + if tt.expectBaseline { + s.Assert().Equal(len(allProfile.Sample), len(profile.Sample)) + } + if tt.expectEmpty { + s.Assert().Zero(len(profile.Sample)) + } + if tt.expectFiltered { + s.Assert().Less(len(profile.Sample), len(allProfile.Sample)) + s.Assert().NotZero(len(profile.Sample)) + } + } + }) + } +} + +func (s *testSuite) Test_BytesFetched_Populated() { + // BytesFetched must always be populated in the response regardless of + // whether diagnostics collection is enabled, and must be > 0 for any + // query that actually reads block data. + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().NotNil(resp.Diagnostics) + s.Require().NotNil(resp.Diagnostics.ExecutionNode) + s.Require().NotNil(resp.Diagnostics.ExecutionNode.Stats) + s.Assert().Greater(resp.Diagnostics.ExecutionNode.Stats.BytesFetched, uint64(0)) +} + +func (s *testSuite) Test_BytesFetched_ConsistentAcrossInvocations() { + // Two independent Invoke calls with identical inputs must return a similar + // BytesFetched value: the counter is scoped to a single invocation, so + // neither retries from a higher layer nor shared bucket state can grossly + // inflate it (which would roughly double the value). + // + // Exact byte equality is not achievable: the async parquet reader + // (ReadModeAsync, used for blocks > 1 MB) spawns goroutines that issue + // prefetch/read-ahead GetRange calls whose count and size are + // timing-dependent. Two otherwise-identical invocations therefore read a + // slightly different total number of physical bytes. A 10% relative + // tolerance is ample to detect gross double-counting while tolerating + // normal prefetch variance (~1-2% in practice). + // + // Use a fixed end time and clone the plan for each call: BlockReader.Invoke + // mutates QueryPlan.Root.Blocks[i].Datasets in place (filterNotOwnedDatasets), + // so sharing a plan across calls would cause different datasets to be processed + // on the second invocation. + endTime := time.Now().UnixMilli() + invoke := func() uint64 { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: endTime, + LabelSelector: "{}", + QueryPlan: s.plan.CloneVT(), + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + return resp.Diagnostics.ExecutionNode.Stats.BytesFetched + } + first := invoke() + second := invoke() + s.Assert().Greater(first, uint64(0)) + // Two identical queries must fetch a similar number of bytes (within 10%). + s.Assert().InEpsilon(float64(first), float64(second), 0.10) +} + +func (s *testSuite) Test_SpanAndTraceSelector_Combined_Errors() { + // No public RPC sets both; both being set is an internal-plan bug. + span := []string{fixtureMatchingSpanID} + trace := []string{"0123456789abcdef0123456789abcdef"} + + for _, tt := range []struct { + name string + query *queryv1.Query + }{ + {"tree", &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16, SpanSelector: span, TraceIdSelector: trace}, + }}, + {"pprof", &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{SpanSelector: span, TraceIdSelector: trace}, + }}, + } { + s.Run(tt.name, func() { + _, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(5 * time.Minute).UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{tt.query}, + Tenant: s.tenant, + }) + s.Require().Error(err) + s.Require().Contains(err.Error(), "span_selector and trace_id_selector cannot be combined") + }) + } +} + +func (s *testSuite) Test_SpanSelector() { + // Capture baselines used to verify that an empty/nil selector returns + // the full (unfiltered) result. + baselineTree, err := os.ReadFile("testdata/fixtures/tree_16.txt") + s.Require().NoError(err) + + allTreeResp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + allTree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](allTreeResp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + allPprofResp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(5 * time.Minute).UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + var allProfile profilev1.Profile + s.Require().NoError(pprof.Unmarshal(allPprofResp.Reports[0].Pprof.Pprof, &allProfile)) + + tests := []struct { + queryType queryv1.QueryType + name string + spanSelector []string + wantErr error + want string + }{ + // Tree tests + {queryv1.QueryType_QUERY_TREE, "tree/invalid span ID returns error", []string{"tooshort"}, errors.New(`invalid span id length: "tooshort"`), ""}, + {queryv1.QueryType_QUERY_TREE, "tree/empty selector returns baseline", []string{}, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_TREE, "tree/nil selector returns baseline", nil, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_TREE, "tree/non-matching span returns empty", []string{fixtureNonMatchingSpanID}, nil, spanSelectorWantEmpty}, + {queryv1.QueryType_QUERY_TREE, "tree/matching span filters result", []string{fixtureMatchingSpanID}, nil, spanSelectorWantFiltered}, + + // Pprof tests + {queryv1.QueryType_QUERY_PPROF, "pprof/invalid span ID returns error", []string{"tooshort"}, errors.New(`invalid span id length: "tooshort"`), ""}, + {queryv1.QueryType_QUERY_PPROF, "pprof/empty selector returns baseline", []string{}, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_PPROF, "pprof/nil selector returns baseline", nil, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_PPROF, "pprof/non-matching span returns empty", []string{fixtureNonMatchingSpanID}, nil, spanSelectorWantEmpty}, + {queryv1.QueryType_QUERY_PPROF, "pprof/matching span filters result", []string{fixtureMatchingSpanID}, nil, spanSelectorWantFiltered}, + } + + for _, tt := range tests { + s.Run(tt.name, func() { + var ( + query *queryv1.Query + reqStartTime, reqEndTime int64 + ) + + if tt.queryType == queryv1.QueryType_QUERY_TREE { + reqEndTime = time.Now().UnixMilli() + query = &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{ + MaxNodes: 16, + SpanSelector: tt.spanSelector, + }, + } + } else { + reqStartTime = startTime.UnixMilli() + reqEndTime = startTime.Add(5 * time.Minute).UnixMilli() + query = &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{ + SpanSelector: tt.spanSelector, + }, + } + } + + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: reqStartTime, + EndTime: reqEndTime, + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{query}, + Tenant: s.tenant, + }) + + if tt.wantErr != nil { + s.Require().Error(err) + s.Require().EqualError(err, tt.wantErr.Error()) + s.Require().Nil(resp) + return + } + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + + if tt.queryType == queryv1.QueryType_QUERY_TREE { + tree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + switch tt.want { + case spanSelectorWantBaseline: + s.Assert().Equal(string(baselineTree), tree.String()) + case spanSelectorWantEmpty: + s.Assert().Zero(tree.Total()) + case spanSelectorWantFiltered: + s.Assert().NotZero(tree.Total()) + s.Assert().Less(tree.Total(), allTree.Total()) + default: + s.Require().Fail("unknown span selector expectation", tt.want) + } + } else { + var profile profilev1.Profile + s.Require().NoError(pprof.Unmarshal(resp.Reports[0].Pprof.Pprof, &profile)) + + switch tt.want { + case spanSelectorWantBaseline: + s.Assert().Equal(len(allProfile.Sample), len(profile.Sample)) + case spanSelectorWantEmpty: + s.Assert().Zero(len(profile.Sample)) + case spanSelectorWantFiltered: + s.Assert().NotZero(len(profile.Sample)) + s.Assert().Less(len(profile.Sample), len(allProfile.Sample)) + default: + s.Require().Fail("unknown span selector expectation", tt.want) + } + } + }) + } +} + +func (s *testSuite) getProfileIDFromExemplars(t *testing.T) string { + t.Helper() + + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(5 * time.Minute).UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TIME_SERIES, + TimeSeries: &queryv1.TimeSeriesQuery{ + Step: 30.0, + ExemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL, + }, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().NotNil(resp) + + // Find first exemplar with a profile ID + for _, serie := range resp.Reports[0].TimeSeries.TimeSeries { + for _, point := range serie.Points { + if len(point.Exemplars) > 0 && point.Exemplars[0].ProfileId != "" { + return point.Exemplars[0].ProfileId + } + } + } + s.Require().FailNow("no profile ID found in exemplars") + return "" +} + +const ( + fixtureMatchingTraceID = "00000000000000000000000000000001" + fixtureNonMatchingTraceID = "ffffffffffffffffffffffffffffffff" +) + +func (s *testSuite) Test_SpanHeatmapIncludesTraceID() { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(5 * time.Minute).UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_HEATMAP, + Heatmap: &queryv1.HeatmapQuery{ + QueryType: querierv1.HeatmapQueryType_HEATMAP_QUERY_TYPE_SPAN, + ExemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_SPAN, + }, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().Len(resp.Reports, 1) + + for _, series := range resp.Reports[0].Heatmap.HeatmapSeries { + for _, point := range series.Points { + if hex.EncodeToString(point.TraceId) == fixtureMatchingTraceID { + s.Require().NotZero(point.SpanId) + return + } + } + } + s.Fail("span heatmap did not include the fixture trace ID") +} + +func (s *testSuite) Test_TraceSelector() { + baselineTree, err := os.ReadFile("testdata/fixtures/tree_16.txt") + s.Require().NoError(err) + + allTreeResp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + allTree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](allTreeResp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + allPprofResp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: startTime.Add(5 * time.Minute).UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + var allProfile profilev1.Profile + s.Require().NoError(pprof.Unmarshal(allPprofResp.Reports[0].Pprof.Pprof, &allProfile)) + + tests := []struct { + queryType queryv1.QueryType + name string + traceSelector []string + wantErr error + want string + }{ + // Tree tests + {queryv1.QueryType_QUERY_TREE, "tree/invalid trace ID returns error", []string{"tooshort"}, errors.New(`invalid trace id length: "tooshort"`), ""}, + {queryv1.QueryType_QUERY_TREE, "tree/empty selector returns baseline", []string{}, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_TREE, "tree/nil selector returns baseline", nil, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_TREE, "tree/non-matching trace returns empty", []string{fixtureNonMatchingTraceID}, nil, spanSelectorWantEmpty}, + {queryv1.QueryType_QUERY_TREE, "tree/matching trace filters result", []string{fixtureMatchingTraceID}, nil, spanSelectorWantFiltered}, + + // Pprof tests + {queryv1.QueryType_QUERY_PPROF, "pprof/invalid trace ID returns error", []string{"tooshort"}, errors.New(`invalid trace id length: "tooshort"`), ""}, + {queryv1.QueryType_QUERY_PPROF, "pprof/empty selector returns baseline", []string{}, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_PPROF, "pprof/nil selector returns baseline", nil, nil, spanSelectorWantBaseline}, + {queryv1.QueryType_QUERY_PPROF, "pprof/non-matching trace returns empty", []string{fixtureNonMatchingTraceID}, nil, spanSelectorWantEmpty}, + {queryv1.QueryType_QUERY_PPROF, "pprof/matching trace filters result", []string{fixtureMatchingTraceID}, nil, spanSelectorWantFiltered}, + } + + for _, tt := range tests { + s.Run(tt.name, func() { + var ( + query *queryv1.Query + reqStartTime, reqEndTime int64 + ) + + if tt.queryType == queryv1.QueryType_QUERY_TREE { + reqEndTime = time.Now().UnixMilli() + query = &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{ + MaxNodes: 16, + TraceIdSelector: tt.traceSelector, + }, + } + } else { + reqStartTime = startTime.UnixMilli() + reqEndTime = startTime.Add(5 * time.Minute).UnixMilli() + query = &queryv1.Query{ + QueryType: queryv1.QueryType_QUERY_PPROF, + Pprof: &queryv1.PprofQuery{ + TraceIdSelector: tt.traceSelector, + }, + } + } + + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + StartTime: reqStartTime, + EndTime: reqEndTime, + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{query}, + Tenant: s.tenant, + }) + + if tt.wantErr != nil { + s.Require().Error(err) + s.Require().EqualError(err, tt.wantErr.Error()) + s.Require().Nil(resp) + return + } + + s.Require().NoError(err) + s.Require().NotNil(resp) + s.Require().Len(resp.Reports, 1) + + if tt.queryType == queryv1.QueryType_QUERY_TREE { + tree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Reports[0].Tree.Tree) + s.Require().NoError(err) + + switch tt.want { + case spanSelectorWantBaseline: + s.Assert().Equal(string(baselineTree), tree.String()) + case spanSelectorWantEmpty: + s.Assert().Zero(tree.Total()) + case spanSelectorWantFiltered: + s.Assert().NotZero(tree.Total()) + s.Assert().Less(tree.Total(), allTree.Total()) + default: + s.Require().Fail("unknown trace selector expectation", tt.want) + } + } else { + var profile profilev1.Profile + s.Require().NoError(pprof.Unmarshal(resp.Reports[0].Pprof.Pprof, &profile)) + + switch tt.want { + case spanSelectorWantBaseline: + s.Assert().Equal(len(allProfile.Sample), len(profile.Sample)) + case spanSelectorWantEmpty: + s.Assert().Zero(len(profile.Sample)) + case spanSelectorWantFiltered: + s.Assert().NotZero(len(profile.Sample)) + s.Assert().Less(len(profile.Sample), len(allProfile.Sample)) + default: + s.Require().Fail("unknown trace selector expectation", tt.want) + } + } + }) + } +} diff --git a/pkg/querybackend/client/client.go b/pkg/querybackend/client/client.go new file mode 100644 index 0000000000..5e7ded5357 --- /dev/null +++ b/pkg/querybackend/client/client.go @@ -0,0 +1,71 @@ +package querybackendclient + +import ( + "context" + "fmt" + "time" + + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/services" + "google.golang.org/grpc" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +type Client struct { + service services.Service + grpcClient queryv1.QueryBackendServiceClient +} + +func New(address string, grpcClientConfig grpcclient.Config, timeout time.Duration, dialOpts ...grpc.DialOption) (*Client, error) { + conn, err := dial(address, grpcClientConfig, timeout, dialOpts...) + if err != nil { + return nil, err + } + var c Client + c.grpcClient = queryv1.NewQueryBackendServiceClient(conn) + c.service = services.NewIdleService(c.starting, c.stopping) + return &c, nil +} + +func dial(address string, grpcClientConfig grpcclient.Config, timeout time.Duration, dialOpts ...grpc.DialOption) (*grpc.ClientConn, error) { + options, err := grpcClientConfig.DialOption(nil, nil, nil) + if err != nil { + return nil, err + } + // TODO: https://github.com/grpc/grpc-proto/blob/master/grpc/service_config/service_config.proto + serviceConfig := fmt.Sprintf(grpcServiceConfigTemplate, timeout.Seconds()) + options = append(options, + grpc.WithDefaultServiceConfig(serviceConfig), + grpc.WithMaxCallAttempts(500), + ) + options = append(options, dialOpts...) + return grpc.NewClient(address, options...) +} + +func (b *Client) Service() services.Service { return b.service } +func (b *Client) starting(context.Context) error { return nil } +func (b *Client) stopping(error) error { return nil } + +func (b *Client) Invoke(ctx context.Context, req *queryv1.InvokeRequest) (*queryv1.InvokeResponse, error) { + return b.grpcClient.Invoke(ctx, req) +} + +const grpcServiceConfigTemplate = `{ + "loadBalancingPolicy":"round_robin", + "methodConfig": [{ + "name": [{"service": ""}], + "waitForReady": true, + "retryPolicy": { + "MaxAttempts": 500, + "InitialBackoff": "1s", + "MaxBackoff": "2s", + "BackoffMultiplier": 1.1, + "RetryableStatusCodes": [ + "UNAVAILABLE", + "RESOURCE_EXHAUSTED" + ] + }, + "timeout": "%.0fs" + }] +}` diff --git a/pkg/querybackend/client/client_test.go b/pkg/querybackend/client/client_test.go new file mode 100644 index 0000000000..3fa9c83391 --- /dev/null +++ b/pkg/querybackend/client/client_test.go @@ -0,0 +1,143 @@ +package querybackendclient + +import ( + "context" + "flag" + "fmt" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/grpcclient" + "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc" + "google.golang.org/grpc/resolver" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/querybackend" + "github.com/grafana/pyroscope/v2/pkg/querybackend/queryplan" + "github.com/grafana/pyroscope/v2/pkg/test" +) + +const ( + nServers = 12 + nServerResponseTime = 200 * time.Millisecond + + nBlocksInQuery = 4000 + nConcurrentQueries = 5 +) + +type QueryHandler struct { +} + +func (q QueryHandler) Invoke(ctx context.Context, request *queryv1.InvokeRequest) (*queryv1.InvokeResponse, error) { + time.Sleep(nServerResponseTime) + return &queryv1.InvokeResponse{}, nil +} + +type multiResolverBuilder struct { + targets []string +} + +func (b *multiResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { + r := &multiResolver{ + cc: cc, + address: b.targets, + } + r.updateState() + return r, nil +} + +func (b *multiResolverBuilder) Scheme() string { + return "multi" +} + +// Resolves all DNS queries to a given set of IPs +// +// Ignores the name being resolved. +type multiResolver struct { + cc resolver.ClientConn + address []string +} + +func (r *multiResolver) updateState() { + addresses := make([]resolver.Address, len(r.address)) + for i, addr := range r.address { + addresses[i] = resolver.Address{Addr: addr} + } + _ = r.cc.UpdateState(resolver.State{Addresses: addresses}) +} + +func (r *multiResolver) ResolveNow(resolver.ResolveNowOptions) {} + +func (r *multiResolver) Close() {} + +// Test_Concurrency tests the concurrent invocation of queries against multiple backend servers. +// +// This test sets up a simulated environment with `nServers` gRPC servers, each acting as a +// query backend. It uses `bufconn.Listener` for in-memory gRPC communication to avoid +// actual network I/O. +func Test_Concurrency(t *testing.T) { + addresses := make([]string, 0, nServers) + for i := 0; i < nServers; i++ { + address := fmt.Sprintf("localhost:%d", 10004+i) + addresses = append(addresses, address) + } + + listeners, dialOpt := test.CreateInMemoryListeners(addresses) + + grpcClientCfg := grpcclient.Config{} + grpcClientCfg.RegisterFlags(flag.NewFlagSet("", flag.PanicOnError)) + + resolver.Register(&multiResolverBuilder{targets: addresses}) + backendAddress := "multi:///" + + cl, err := New(backendAddress, grpcClientCfg, 30*time.Second, dialOpt) + require.NoError(t, err) + + for i := 0; i < nServers; i++ { + gclInterceptor, err := querybackend.CreateConcurrencyInterceptor(log.NewNopLogger()) + require.NoError(t, err) + + b, err := querybackend.New(querybackend.Config{ + Address: backendAddress, + GRPCClientConfig: grpcClientCfg, + }, test.NewTestingLogger(t), nil, cl, QueryHandler{}) + require.NoError(t, err) + + grpcOptions := []grpc.ServerOption{ + grpc.ChainUnaryInterceptor(gclInterceptor), + } + serv := grpc.NewServer(grpcOptions...) + require.NoError(t, err) + + queryv1.RegisterQueryBackendServiceServer(serv, b) + + go func() { + require.NoError(t, serv.Serve(listeners[addresses[i]])) + }() + } + + blocks := make([]*metastorev1.BlockMeta, 0, nBlocksInQuery) + for i := 0; i < nBlocksInQuery; i++ { + blocks = append(blocks, &metastorev1.BlockMeta{ + Id: fmt.Sprintf("block-%d", i), + }) + } + + g, ctx := errgroup.WithContext(context.Background()) + for i := 0; i < nConcurrentQueries; i++ { + g.Go(func() error { + resp, err := cl.Invoke(ctx, &queryv1.InvokeRequest{ + QueryPlan: queryplan.Build(blocks, 4, 20), + }) + require.NoError(t, err) + require.NotNil(t, resp) + return err + }) + } + err = g.Wait() + require.NoError(t, err) +} diff --git a/pkg/querybackend/concurrency.go b/pkg/querybackend/concurrency.go new file mode 100644 index 0000000000..8b8742c25b --- /dev/null +++ b/pkg/querybackend/concurrency.go @@ -0,0 +1,77 @@ +package querybackend + +import ( + "context" + "fmt" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/platinummonkey/go-concurrency-limits/core" + gclGrpc "github.com/platinummonkey/go-concurrency-limits/grpc" + "github.com/platinummonkey/go-concurrency-limits/limit" + "github.com/platinummonkey/go-concurrency-limits/limiter" + "github.com/platinummonkey/go-concurrency-limits/strategy" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +const ( + // gradient2 limit + minLimit = 50 + maxLimit = 100 + initialLimit = 50 + smoothing = 0.2 + longWindow = 600 + + // limiter + minWindowTime = 1 + maxWindowTime = 1000 + minRTTThreshold = 1e6 + windowSize = 100 +) + +var ( + queueSizeFn = func(limit int) int { + return 10 + } +) + +func CreateConcurrencyInterceptor(logger log.Logger) (grpc.UnaryServerInterceptor, error) { + gclLog := newGclLogger(logger) + // TODO(aleks-p): Implement metric registry + serverLimit, err := limit.NewGradient2Limit("query-backend-concurrency-limit", minLimit, maxLimit, initialLimit, queueSizeFn, smoothing, longWindow, gclLog, nil) + if err != nil { + return nil, err + } + + serverLimiter, err := limiter.NewDefaultLimiter(serverLimit, minWindowTime, maxWindowTime, minRTTThreshold, windowSize, strategy.NewSimpleStrategy(initialLimit), gclLog, nil) + if err != nil { + return nil, err + } + + options := []gclGrpc.InterceptorOption{ + gclGrpc.WithName("gcl-interceptor"), + gclGrpc.WithLimiter(serverLimiter), + gclGrpc.WithLimitExceededResponseClassifier(func(ctx context.Context, method string, req interface{}, l core.Limiter) (interface{}, codes.Code, error) { + return nil, codes.ResourceExhausted, fmt.Errorf("concurrency limit exceeded") + })} + gclInterceptor := gclGrpc.UnaryServerInterceptor(options...) + + return gclInterceptor, err +} + +type gclLogger struct { + logger log.Logger +} + +func (g gclLogger) Debugf(msg string, params ...interface{}) { + level.Debug(g.logger).Log("msg", fmt.Sprintf(msg, params...)) +} + +func (g gclLogger) IsDebugEnabled() bool { + return true +} + +func newGclLogger(logger log.Logger) *gclLogger { + return &gclLogger{logger: logger} +} diff --git a/pkg/querybackend/metrics.go b/pkg/querybackend/metrics.go new file mode 100644 index 0000000000..5b8448f890 --- /dev/null +++ b/pkg/querybackend/metrics.go @@ -0,0 +1,22 @@ +package querybackend + +import "github.com/prometheus/client_golang/prometheus" + +type metrics struct { + datasetTenantIsolationFailure prometheus.Counter +} + +func newMetrics(reg prometheus.Registerer) *metrics { + m := &metrics{ + datasetTenantIsolationFailure: prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Subsystem: "query_backend", + Name: "dataset_tenant_isolation_failure_total", + }), + } + if reg != nil { + reg.MustRegister(m.datasetTenantIsolationFailure) + } + return m +} diff --git a/pkg/querybackend/query.go b/pkg/querybackend/query.go new file mode 100644 index 0000000000..ee300eacdd --- /dev/null +++ b/pkg/querybackend/query.go @@ -0,0 +1,311 @@ +package querybackend + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + "go.opentelemetry.io/otel/attribute" + oteltrace "go.opentelemetry.io/otel/trace" + "golang.org/x/sync/errgroup" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +// TODO(kolesnikovae): We have a procedural definition of our queries, +// thus we have handlers. Instead, in order to enable pipelining and +// reduce the boilerplate, we should define query execution plans. + +const ( + // maxProfileIDsToLog is the maximum number of profile IDs to log in trace spans. + maxProfileIDsToLog = 10 +) + +var ( + handlerMutex = new(sync.RWMutex) + queryHandlers = map[queryv1.QueryType]queryHandler{} +) + +type queryHandler func(*queryContext, *queryv1.Query) (*queryv1.Report, error) + +func registerQueryHandler(t queryv1.QueryType, h queryHandler) { + handlerMutex.Lock() + defer handlerMutex.Unlock() + if _, ok := queryHandlers[t]; ok { + panic(fmt.Sprintf("%s: handler already registered", t)) + } + queryHandlers[t] = h +} + +func getQueryHandler(t queryv1.QueryType) (queryHandler, error) { + handlerMutex.RLock() + defer handlerMutex.RUnlock() + handler, ok := queryHandlers[t] + if !ok { + return nil, fmt.Errorf("unknown query type %s", t) + } + return handler, nil +} + +var ( + depMutex = new(sync.RWMutex) + queryDependencies = map[queryv1.QueryType][]block.Section{} +) + +func registerQueryDependencies(t queryv1.QueryType, deps ...block.Section) { + depMutex.Lock() + defer depMutex.Unlock() + if _, ok := queryDependencies[t]; ok { + panic(fmt.Sprintf("%s: dependencies already registered", t)) + } + queryDependencies[t] = deps +} + +func registerQueryType( + qt queryv1.QueryType, + rt queryv1.ReportType, + q queryHandler, + a aggregatorProvider, + alwaysAggregate bool, // this option will always call the aggregate method for this report type, so it will also run when there is only one report + deps ...block.Section, +) { + registerQueryReportType(qt, rt) + registerQueryHandler(qt, q) + registerQueryDependencies(qt, deps...) + registerAggregator(rt, a, alwaysAggregate) +} + +type blockContext struct { + ctx context.Context + log log.Logger + req *request + agg *reportAggregator + obj *block.Object + grp *errgroup.Group + execCollector *blockExecutionCollector + weightCollector *queryWeightCollector + includeStripped bool +} + +func (b *blockContext) execute() error { + startTime := time.Now() + + var span *tracing.Span + span, b.ctx = tracing.StartSpanFromContext(b.ctx, "blockContext.execute") + defer span.Finish() + + if idxs := b.datasetIndices(); len(idxs) > 0 { + if err := b.lookupDatasets(idxs); err != nil { + if b.obj.IsNotExists(err) { + level.Warn(b.log).Log("msg", "object not found", "err", err) + return nil + } + return fmt.Errorf("failed to lookup datasets: %w", err) + } + // Only accumulate datasets resolved from the index lookup; Format0 + // datasets were already counted by the query frontend at planning time. + b.weightCollector.addDatasets(b.obj.Metadata().Datasets) + } + + md := b.obj.Metadata() + for _, ds := range md.Datasets { + q := b.newQueryContext(ds) + for _, query := range b.req.src.Query { + q.grp.Go(util.RecoverPanic(func() error { + return q.execute(query) + })) + } + if err := q.grp.Wait(); err != nil { + return err + } + } + + if b.execCollector != nil { + b.execCollector.record(&queryv1.BlockExecution{ + BlockId: md.Id, + StartTimeNs: startTime.UnixNano(), + EndTimeNs: time.Now().UnixNano(), + DatasetsProcessed: int64(len(md.Datasets)), + Size: md.Size, + Shard: md.Shard, + CompactionLevel: md.CompactionLevel, + }) + } + + return nil +} + +// datasetIndices returns the Format1 (dataset_tsdb_index) pseudo-datasets +// in the block metadata that need to be resolved into concrete datasets +// before the query can be executed. It returns nil when no resolution +// is needed: either the metadata already lists explicit (Format0) +// datasets, or the query is index-only and can be served directly from +// the dataset_index TSDB section. +// +// Multiple Format1 datasets may be present in a single block when a +// segment writer covers more than one tenant: it emits a per-tenant +// dataset_index pseudo-dataset, and the metastore returns all matching +// pseudo-datasets to the query backend. In that case all of their +// indices must be looked up so the union of resolved datasets is +// considered. +func (b *blockContext) datasetIndices() []*metastorev1.Dataset { + md := b.obj.Metadata() + var indices []*metastorev1.Dataset + for _, ds := range md.Datasets { + if block.DatasetFormat(ds.Format) == block.DatasetFormat1 { + indices = append(indices, ds) + } + } + if len(indices) == 0 { + // The block's metadata explicitly lists datasets to be queried. + return nil + } + if len(indices) != len(md.Datasets) { + // The metastore is expected to return a uniform set of datasets + // (either all Format0 explicit datasets matched by service_name, + // or all Format1 pseudo-datasets matched by __tenant_dataset__). + // A mixed set is not expected; bail on the lookup so the query + // runs against the explicitly-listed datasets only. + return nil + } + + // If the query only requires TSDB data, we can serve it directly + // from each Format1 dataset's TSDB section (which is aliased to the + // dataset_index) without resolving real datasets. + s := (&queryContext{blockContext: b}).sections() + indexOnly := len(s) == 1 && s[0] == block.SectionTSDB + if indexOnly { + oteltrace.SpanFromContext(b.ctx).SetAttributes(attribute.Bool("dataset_index_query_index_only", indexOnly)) + return nil + } + + return indices +} + +func (b *blockContext) lookupDatasets(indices []*metastorev1.Dataset) error { + oteltrace.SpanFromContext(b.ctx).SetAttributes(attribute.Bool("dataset_index_query", true)) + oteltrace.SpanFromContext(b.ctx).SetAttributes(attribute.Int("dataset_index_count", len(indices))) + + // As query execution has not started yet, + // we can safely open datasets. + datasets := make([]*block.Dataset, len(indices)) + for i, ds := range indices { + datasets[i] = block.NewDataset(ds, b.obj) + } + defer func() { + for _, d := range datasets { + _ = d.Close() + } + }() + + g, ctx := errgroup.WithContext(b.ctx) + var md *metastorev1.BlockMeta + g.Go(func() (err error) { + md, err = b.obj.ReadMetadata(ctx) + return err + }) + for _, d := range datasets { + g.Go(func() error { + return d.Open(ctx, block.SectionDatasetIndex) + }) + } + if err := g.Wait(); err != nil { + return err + } + + // Each per-tenant dataset_index encodes its tenant's real datasets + // using their global position within the block as the chunk + // SeriesIndex (see segment writer and compaction). Therefore IDs + // from different per-tenant indices are disjoint and a simple union + // across tenants is correct. + datasetIDs := make(map[uint32]struct{}) + for _, d := range datasets { + ids, err := getSeriesIDs(d.Index(), b.req.matchers...) + if err != nil { + return err + } + for id := range ids { + datasetIDs[id] = struct{}{} + } + } + + var j int + for i := range md.Datasets { + if _, ok := datasetIDs[uint32(i)]; ok { + md.Datasets[j] = md.Datasets[i] + j++ + } + } + md.Datasets = md.Datasets[:j] + b.obj.SetMetadata(md) + + oteltrace.SpanFromContext(b.ctx).AddEvent("dataset tsdb index lookup complete") + + return nil +} + +func (b *blockContext) newQueryContext(ds *metastorev1.Dataset) *queryContext { + q := &queryContext{blockContext: b, ds: block.NewDataset(ds, b.obj)} + q.grp, q.ctx = errgroup.WithContext(b.ctx) + return q +} + +type queryContext struct { + *blockContext + ctx context.Context + grp *errgroup.Group + ds *block.Dataset +} + +func (q *queryContext) execute(query *queryv1.Query) error { + var span *tracing.Span + span, q.ctx = tracing.StartSpanFromContext(q.ctx, "executeQuery."+util.ToCamel(query.QueryType.String())) + defer span.Finish() + handle, err := getQueryHandler(query.QueryType) + if err != nil { + return err + } + + if err = q.ds.Open(q.ctx, q.sections()...); err != nil { + if q.obj.IsNotExists(err) { + level.Warn(q.log).Log("msg", "object not found", "err", err) + return nil + } + return fmt.Errorf("failed to initialize query context: %w", err) + } + defer func() { + _ = q.ds.CloseWithError(err) + }() + + r, err := handle(q, query) + if err != nil { + return err + } + if r != nil { + r.ReportType = QueryReportType(query.QueryType) + return q.agg.aggregateReport(r) + } + + return nil +} + +func (q *queryContext) sections() []block.Section { + sections := make(map[block.Section]struct{}, 3) + for _, qt := range q.req.src.Query { + for _, s := range queryDependencies[qt.QueryType] { + sections[s] = struct{}{} + } + } + unique := make([]block.Section, 0, len(sections)) + for s := range sections { + unique = append(unique, s) + } + return unique +} diff --git a/pkg/querybackend/query_heatmap.go b/pkg/querybackend/query_heatmap.go new file mode 100644 index 0000000000..237a2fa0e0 --- /dev/null +++ b/pkg/querybackend/query_heatmap.go @@ -0,0 +1,222 @@ +package querybackend + +import ( + "fmt" + "strings" + "sync" + + "github.com/grafana/dskit/runutil" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/heatmap" + parquetquery "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +func init() { + registerQueryType( + queryv1.QueryType_QUERY_HEATMAP, + queryv1.ReportType_REPORT_HEATMAP, + queryHeatmap, + newHeatmapAggregator, + true, + []block.Section{ + block.SectionTSDB, + block.SectionProfiles, + }..., + ) +} + +func rowsIndividual(q *queryContext, b *heatmap.Builder) error { + entries, err := profileEntryIterator(q, withAllLabels(), withFetchPartition(false), withFetchProfileIDs(true), withExcludeSampled()) + if err != nil { + return err + } + defer runutil.CloseWithErrCapture(&err, entries, "failed to close profile entry iterator") + + totalValue, err := schemav1.ResolveColumnByPath(q.ds.Profiles().Schema(), strings.Split("TotalValue", ".")) + if err != nil { + return err + } + + rows := parquetquery.NewRepeatedRowIteratorBatchSize( + q.ctx, + entries, + q.ds.Profiles().RowGroups(), + bigBatchSize, + totalValue.ColumnIndex, + ) + defer runutil.CloseWithErrCapture(&err, rows, "failed to close column iterator") + + for rows.Next() { + row := rows.At() + b.Add( + row.Row.Fingerprint, + row.Row.Labels, + int64(row.Row.Timestamp), + row.Row.ID, + 0, + model.TraceID{}, + row.Values[0][0].Int64(), + ) + } + if err = rows.Err(); err != nil { + return err + } + + return nil +} + +func rowsSpans(q *queryContext, b *heatmap.Builder) (err error) { + entries, err := profileEntryIterator(q, withAllLabels(), withFetchPartition(false), withExcludeSampled()) + if err != nil { + return err + } + + defer runutil.CloseWithErrCapture(&err, entries, "failed to close profile entry iterator") + var columns schemav1.SampleColumns + if err := columns.Resolve(q.ds.Profiles().Schema()); err != nil { + return err + } + + // no span column + if !columns.HasSpanID() { + return nil + } + + indices := []int{ + columns.SpanID.ColumnIndex, + columns.Value.ColumnIndex, + } + if columns.HasTraceID() { + indices = append(indices, columns.TraceID.ColumnIndex) + } + + rows := parquetquery.NewRepeatedRowIteratorBatchSize( + q.ctx, + entries, + q.ds.Profiles().RowGroups(), + bigBatchSize, + indices..., + ) + defer runutil.CloseWithErrCapture(&err, rows, "failed to close column iterator") + + for rows.Next() { + row := rows.At() + + for idx := range row.Values[0] { + var traceID model.TraceID + if columns.HasTraceID() { + traceIDBytes := row.Values[2][idx].Bytes() + if len(traceIDBytes) == len(traceID) { + copy(traceID[:], traceIDBytes) + } + } + b.Add( + row.Row.Fingerprint, + row.Row.Labels, + int64(row.Row.Timestamp), + "", + row.Values[0][idx].Uint64(), + traceID, + row.Values[1][idx].Int64(), + ) + } + + } + if err = rows.Err(); err != nil { + return err + } + + return nil +} + +func queryHeatmap(q *queryContext, query *queryv1.Query) (r *queryv1.Report, err error) { + // Determine if exemplars should be included based on type + var includeExemplars bool + switch query.Heatmap.ExemplarType { + case typesv1.ExemplarType_EXEMPLAR_TYPE_UNSPECIFIED, + typesv1.ExemplarType_EXEMPLAR_TYPE_NONE: + includeExemplars = false + case typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL: + if query.Heatmap.QueryType != querierv1.HeatmapQueryType_HEATMAP_QUERY_TYPE_INDIVIDUAL { + return nil, fmt.Errorf("individual exemplars only available for individual query type") + } + includeExemplars = true + case typesv1.ExemplarType_EXEMPLAR_TYPE_SPAN: + if query.Heatmap.QueryType != querierv1.HeatmapQueryType_HEATMAP_QUERY_TYPE_SPAN { + return nil, fmt.Errorf("span exemplars only available for span query type") + } + includeExemplars = true + default: + return nil, fmt.Errorf("unknown exemplar type: %v", query.Heatmap.ExemplarType) + } + + otelSpan := trace.SpanFromContext(q.ctx) + otelSpan.SetAttributes( + attribute.Bool("exemplars.enabled", includeExemplars), + attribute.String("exemplars.type", query.Heatmap.ExemplarType.String()), + ) + + b := heatmap.NewBuilder(query.Heatmap.GroupBy) + + // Select the appropriate row iterator based on query type + switch query.Heatmap.QueryType { + case querierv1.HeatmapQueryType_HEATMAP_QUERY_TYPE_INDIVIDUAL: + if err := rowsIndividual(q, b); err != nil { + return nil, err + } + case querierv1.HeatmapQueryType_HEATMAP_QUERY_TYPE_SPAN: + if err := rowsSpans(q, b); err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("valid heatmap query type must be specified") + } + + resp := &queryv1.Report{} + resp.Heatmap = b.Build(resp.Heatmap) + + return resp, nil +} + +type heatmapAggregator struct { + init sync.Once + startTime int64 + endTime int64 + query *queryv1.HeatmapQuery + heatmap *heatmap.Merger +} + +func newHeatmapAggregator(req *queryv1.InvokeRequest) aggregator { + return &heatmapAggregator{ + startTime: req.StartTime, + endTime: req.EndTime, + } +} + +func (a *heatmapAggregator) aggregate(report *queryv1.Report) error { + r := report.Heatmap + a.init.Do(func() { + a.heatmap = heatmap.NewMerger(true) + a.query = r.Query.CloneVT() + }) + a.heatmap.MergeHeatmap(r) + return nil +} + +func (a *heatmapAggregator) build() *queryv1.Report { + // Get the merged heatmap report + mergedReport := a.heatmap.Build() + mergedReport.Query = a.query + + return &queryv1.Report{ + Heatmap: mergedReport, + } +} diff --git a/pkg/querybackend/query_label_names.go b/pkg/querybackend/query_label_names.go new file mode 100644 index 0000000000..8d6307b3a0 --- /dev/null +++ b/pkg/querybackend/query_label_names.go @@ -0,0 +1,101 @@ +package querybackend + +import ( + "sort" + "sync" + + "github.com/prometheus/prometheus/model/labels" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" +) + +func init() { + registerQueryType( + queryv1.QueryType_QUERY_LABEL_NAMES, + queryv1.ReportType_REPORT_LABEL_NAMES, + queryLabelNames, + newLabelNameAggregator, + false, + []block.Section{block.SectionTSDB}..., + ) +} + +func queryLabelNames(q *queryContext, query *queryv1.Query) (*queryv1.Report, error) { + var names []string + var err error + if len(q.req.matchers) == 0 { + names, err = q.ds.Index().LabelNames() + } else { + names, err = labelNamesForMatchers(q.ds.Index(), q.req.matchers) + } + if err != nil { + return nil, err + } + resp := &queryv1.Report{ + LabelNames: &queryv1.LabelNamesReport{ + Query: query.LabelNames.CloneVT(), + LabelNames: names, + }, + } + return resp, nil +} + +func labelNamesForMatchers(reader phlaredb.IndexReader, matchers []*labels.Matcher) ([]string, error) { + postings, err := phlaredb.PostingsForMatchers(reader, nil, matchers...) + if err != nil { + return nil, err + } + l := make(map[string]struct{}) + for postings.Next() { + var n []string + if n, err = reader.LabelNamesFor(postings.At()); err != nil { + return nil, err + } + for _, name := range n { + l[name] = struct{}{} + } + } + if err = postings.Err(); err != nil { + return nil, err + } + names := make([]string, len(l)) + var i int + for name := range l { + names[i] = name + i++ + } + sort.Strings(names) + return names, nil +} + +type labelNameAggregator struct { + init sync.Once + query *queryv1.LabelNamesQuery + names *model.LabelMerger +} + +func newLabelNameAggregator(*queryv1.InvokeRequest) aggregator { + return new(labelNameAggregator) +} + +func (m *labelNameAggregator) aggregate(report *queryv1.Report) error { + r := report.LabelNames + m.init.Do(func() { + m.query = r.Query.CloneVT() + m.names = model.NewLabelMerger() + }) + m.names.MergeLabelNames(r.LabelNames) + return nil +} + +func (m *labelNameAggregator) build() *queryv1.Report { + return &queryv1.Report{ + LabelNames: &queryv1.LabelNamesReport{ + Query: m.query, + LabelNames: m.names.LabelNames(), + }, + } +} diff --git a/pkg/querybackend/query_label_values.go b/pkg/querybackend/query_label_values.go new file mode 100644 index 0000000000..b63f917999 --- /dev/null +++ b/pkg/querybackend/query_label_values.go @@ -0,0 +1,104 @@ +package querybackend + +import ( + "errors" + "sort" + "sync" + + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/storage" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" +) + +func init() { + registerQueryType( + queryv1.QueryType_QUERY_LABEL_VALUES, + queryv1.ReportType_REPORT_LABEL_VALUES, + queryLabelValues, + newLabelValueAggregator, + false, + []block.Section{block.SectionTSDB}..., + ) +} + +func queryLabelValues(q *queryContext, query *queryv1.Query) (*queryv1.Report, error) { + var values []string + var err error + if len(q.req.matchers) == 0 { + values, err = q.ds.Index().LabelValues(query.LabelValues.LabelName) + } else { + values, err = labelValuesForMatchers(q.ds.Index(), query.LabelValues.LabelName, q.req.matchers) + } + if err != nil { + return nil, err + } + resp := &queryv1.Report{ + LabelValues: &queryv1.LabelValuesReport{ + Query: query.LabelValues.CloneVT(), + LabelValues: values, + }, + } + return resp, nil +} + +func labelValuesForMatchers(reader phlaredb.IndexReader, name string, matchers []*labels.Matcher) ([]string, error) { + postings, err := phlaredb.PostingsForMatchers(reader, nil, matchers...) + if err != nil { + return nil, err + } + l := make(map[string]struct{}) + for postings.Next() { + var v string + if v, err = reader.LabelValueFor(postings.At(), name); err != nil { + if errors.Is(err, storage.ErrNotFound) { + continue + } + return nil, err + } + l[v] = struct{}{} + } + if err = postings.Err(); err != nil { + return nil, err + } + values := make([]string, len(l)) + var i int + for v := range l { + values[i] = v + i++ + } + sort.Strings(values) + return values, nil +} + +type labelValueAggregator struct { + init sync.Once + query *queryv1.LabelValuesQuery + values *model.LabelMerger +} + +func newLabelValueAggregator(*queryv1.InvokeRequest) aggregator { + return new(labelValueAggregator) +} + +func (m *labelValueAggregator) aggregate(report *queryv1.Report) error { + r := report.LabelValues + m.init.Do(func() { + m.query = r.Query.CloneVT() + m.values = model.NewLabelMerger() + }) + m.values.MergeLabelValues(r.LabelValues) + return nil +} + +func (m *labelValueAggregator) build() *queryv1.Report { + return &queryv1.Report{ + LabelValues: &queryv1.LabelValuesReport{ + Query: m.query, + LabelValues: m.values.LabelValues(), + }, + } +} diff --git a/pkg/querybackend/query_label_values_test.go b/pkg/querybackend/query_label_values_test.go new file mode 100644 index 0000000000..4f2371c366 --- /dev/null +++ b/pkg/querybackend/query_label_values_test.go @@ -0,0 +1,97 @@ +package querybackend + +import ( + "fmt" + "sync" + "time" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +// Test_LabelValues_NoMatcher_BufferReuse verifies that label values returned +// by the no-matcher fast path remain valid after the dataset's TSDB buffer has +// been recycled to bufferpool. +// +// Reader.LabelValues (empty matchers) produces strings via +// yoloString(d.UvarintBytes()), which aliases the pooled TSDB buffer. +// When the dataset is closed the buffer is returned to bufferpool.Put. +// A concurrent request can then receive the same buffer from +// bufferpool.GetBuffer and overwrite it while the first request's strings are +// still in use (e.g. being inserted into the LabelMerger map or sorted during +// aggregation), resulting in a data race. +// +// Run with -race to exercise the race detector. Without the strings.Clone fix +// in queryLabelValues the detector catches the concurrent read (aggregator) vs +// write (bufferpool reuse) on the same backing array. With the fix each value +// is a heap copy independent of the buffer lifetime. +func (s *testSuite) Test_LabelValues_NoMatcher_BufferReuse() { + endTime := time.Now().UnixMilli() + + // baseReq returns a fresh InvokeRequest with its own cloned QueryPlan. + // BlockReader.Invoke mutates QueryPlan.Root.Blocks[i].Datasets in place + // (filterNotOwnedDatasets), so concurrent callers must not share a plan. + baseReq := func() *queryv1.InvokeRequest { + return &queryv1.InvokeRequest{ + EndTime: endTime, + LabelSelector: "{}", + QueryPlan: s.plan.CloneVT(), + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_LABEL_VALUES, + LabelValues: &queryv1.LabelValuesQuery{ + LabelName: "service_name", + }, + }}, + Tenant: s.tenant, + } + } + + // Sequential reference call to establish the expected label values. + refResp, err := s.reader.Invoke(s.ctx, baseReq()) + s.Require().NoError(err) + s.Require().Len(refResp.Reports, 1) + want := refResp.Reports[0].LabelValues.LabelValues + s.Require().NotEmpty(want, "test requires at least one service_name label value in the fixture data") + + const ( + workers = 20 + iterations = 20 + ) + + type callResult struct { + got []string + err error + } + // Buffered so goroutines never block on send. + results := make(chan callResult, workers*iterations) + + var wg sync.WaitGroup + wg.Add(workers) + for range workers { + go func() { + defer wg.Done() + for range iterations { + resp, err := s.reader.Invoke(s.ctx, baseReq()) + if err != nil { + results <- callResult{err: err} + return + } + if len(resp.Reports) == 0 { + results <- callResult{err: fmt.Errorf("no reports returned")} + return + } + // Reading the strings here races with concurrent buffer + // recycling if yoloString aliases were not cloned. + results <- callResult{got: resp.Reports[0].LabelValues.LabelValues} + } + }() + } + wg.Wait() + close(results) + + // Check all results in the test goroutine (s.Require/Assert are not + // safe to call from non-test goroutines). + for r := range results { + s.Require().NoError(r.err) + s.Assert().Equal(want, r.got) + } +} diff --git a/pkg/querybackend/query_pprof.go b/pkg/querybackend/query_pprof.go new file mode 100644 index 0000000000..5688bbd2a0 --- /dev/null +++ b/pkg/querybackend/query_pprof.go @@ -0,0 +1,202 @@ +package querybackend + +import ( + "fmt" + "strings" + "sync" + + "github.com/grafana/dskit/runutil" + "github.com/prometheus/prometheus/model/labels" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + parquetquery "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/pprof" +) + +func init() { + registerQueryType( + queryv1.QueryType_QUERY_PPROF, + queryv1.ReportType_REPORT_PPROF, + queryPprof, + newPprofAggregator, + false, + []block.Section{ + block.SectionTSDB, + block.SectionProfiles, + block.SectionSymbols, + }..., + ) +} + +func queryPprof(q *queryContext, query *queryv1.Query) (*queryv1.Report, error) { + otelSpan := trace.SpanFromContext(q.ctx) + + profileOpts := []profileIteratorOption{withExcludeSampled()} + if len(query.Pprof.ProfileIdSelector) > 0 { + opt, err := withProfileIDSelector(query.Pprof.ProfileIdSelector...) + if err != nil { + return nil, err + } + profileOpts = append(profileOpts, opt) + otelSpan.SetAttributes(attribute.Int("profile_id_selector.count", len(query.Pprof.ProfileIdSelector))) + if len(query.Pprof.ProfileIdSelector) <= maxProfileIDsToLog { + otelSpan.SetAttributes(attribute.String("profile_ids", strings.Join(query.Pprof.ProfileIdSelector, ","))) + } + } + + entries, err := profileEntryIterator(q, profileOpts...) + if err != nil { + return nil, err + } + defer runutil.CloseWithErrCapture(&err, entries, "failed to close profile entry iterator") + + spanSelector, err := phlaremodel.NewSpanSelector(query.Pprof.SpanSelector) + if err != nil { + return nil, err + } + + traceSelector, err := phlaremodel.NewTraceSelector(query.Pprof.TraceIdSelector) + if err != nil { + return nil, err + } + + // Mutually exclusive: no public RPC sets both, so reject an internal query + // plan that does rather than silently apply one and drop the other. + if len(spanSelector) > 0 && len(traceSelector) > 0 { + return nil, fmt.Errorf("span_selector and trace_id_selector cannot be combined") + } + + var columns v1.SampleColumns + if err = columns.Resolve(q.ds.Profiles().Schema()); err != nil { + return nil, err + } + + indices := []int{ + columns.StacktraceID.ColumnIndex, + columns.Value.ColumnIndex, + } + switch { + case len(spanSelector) > 0: + if !columns.HasSpanID() { + // Block has no SpanID column: no samples can match the span selector. + return &queryv1.Report{Pprof: &queryv1.PprofReport{Query: query.Pprof.CloneVT()}}, nil + } + indices = append(indices, columns.SpanID.ColumnIndex) + case len(traceSelector) > 0: + if !columns.HasTraceID() { + // Block has no TraceID column: no samples can match the trace selector. + return &queryv1.Report{Pprof: &queryv1.PprofReport{Query: query.Pprof.CloneVT()}}, nil + } + indices = append(indices, columns.TraceID.ColumnIndex) + } + + profiles := parquetquery.NewRepeatedRowIterator(q.ctx, entries, q.ds.Profiles().RowGroups(), indices...) + defer runutil.CloseWithErrCapture(&err, profiles, "failed to close profile stream") + + resolverOptions := make([]symdb.ResolverOption, 0) + resolverOptions = append(resolverOptions, symdb.WithResolverMaxNodes(query.Pprof.MaxNodes)) + if query.Pprof.StackTraceSelector != nil { + resolverOptions = append( + resolverOptions, + symdb.WithResolverStackTraceSelector(query.Pprof.StackTraceSelector), + symdb.WithResolverSanitizeOnMerge(q.req.src.Options.SanitizeOnMerge)) + } + + resolver := symdb.NewResolver(q.ctx, q.ds.Symbols(), resolverOptions...) + defer resolver.Release() + + switch { + case len(spanSelector) > 0: + for profiles.Next() { + p := profiles.At() + resolver.AddSamplesWithSpanSelectorFromParquetRow( + p.Row.Partition, + p.Values[0], + p.Values[1], + p.Values[2], + spanSelector, + ) + } + case len(traceSelector) > 0: + for profiles.Next() { + p := profiles.At() + resolver.AddSamplesWithTraceSelectorFromParquetRow( + p.Row.Partition, + p.Values[0], + p.Values[1], + p.Values[2], + traceSelector, + ) + } + default: + for profiles.Next() { + p := profiles.At() + resolver.AddSamplesFromParquetRow(p.Row.Partition, p.Values[0], p.Values[1]) + } + } + if err = profiles.Err(); err != nil { + return nil, err + } + + profile, err := resolver.Pprof() + if err != nil { + return nil, err + } + + for _, m := range q.req.matchers { + if m.Name == phlaremodel.LabelNameProfileType && m.Type == labels.MatchEqual { + if t, err := phlaremodel.ParseProfileTypeSelector(m.Value); err == nil { + pprof.SetProfileMetadata(profile, t, q.req.endTime, 0) + break + } + } + } + + resp := &queryv1.Report{ + Pprof: &queryv1.PprofReport{ + Query: query.Pprof.CloneVT(), + Pprof: pprof.MustMarshal(profile, true), + }, + } + + return resp, nil +} + +type pprofAggregator struct { + init sync.Once + query *queryv1.PprofQuery + profile pprof.ProfileMerge + sanitize bool +} + +func newPprofAggregator(req *queryv1.InvokeRequest) aggregator { + if req.Options != nil { + return &pprofAggregator{ + sanitize: req.Options.SanitizeOnMerge, + } + } + return &pprofAggregator{} +} + +func (a *pprofAggregator) aggregate(report *queryv1.Report) error { + r := report.Pprof + a.init.Do(func() { + a.query = r.Query.CloneVT() + }) + return a.profile.MergeBytes(r.Pprof, a.sanitize) +} + +func (a *pprofAggregator) build() *queryv1.Report { + return &queryv1.Report{ + Pprof: &queryv1.PprofReport{ + Query: a.query, + Pprof: pprof.MustMarshal(a.profile.Profile(), true), + }, + } +} diff --git a/pkg/querybackend/query_profile_entry.go b/pkg/querybackend/query_profile_entry.go new file mode 100644 index 0000000000..b2e832b767 --- /dev/null +++ b/pkg/querybackend/query_profile_entry.go @@ -0,0 +1,317 @@ +package querybackend + +import ( + "slices" + "strings" + + "github.com/google/uuid" + "github.com/parquet-go/parquet-go" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + parquetquery "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" +) + +// As we expect rows to be very small, we want to fetch a bigger +// batch of rows at once to amortize the latency of reading. +const bigBatchSize = 2 << 10 + +type ProfileEntry struct { + RowNum int64 + Timestamp model.Time + Fingerprint model.Fingerprint + Labels phlaremodel.Labels + Partition uint64 + ID string +} + +func (e ProfileEntry) RowNumber() int64 { return e.RowNum } + +type profileIteratorOption struct { + iterator func(*iteratorOpts) + series func(*seriesOpts) +} + +func withAllLabels() profileIteratorOption { + return profileIteratorOption{ + series: func(opts *seriesOpts) { + opts.allLabels = true + }, + } +} + +func withGroupByLabels(by ...string) profileIteratorOption { + return profileIteratorOption{ + series: func(opts *seriesOpts) { + opts.groupBy = by + }, + } +} + +func withFetchPartition(v bool) profileIteratorOption { + return profileIteratorOption{ + iterator: func(opts *iteratorOpts) { + opts.fetchPartition = v + }, + } +} + +func withFetchProfileIDs(v bool) profileIteratorOption { + return profileIteratorOption{ + iterator: func(opts *iteratorOpts) { + opts.fetchProfileIDs = v + }, + } +} + +func withExcludeSampled() profileIteratorOption { + return profileIteratorOption{ + iterator: func(opts *iteratorOpts) { + opts.excludeSampled = true + }, + } +} + +func withProfileIDSelector(ids ...string) (profileIteratorOption, error) { + // convert profile ids into uuids + uuids := make([]string, 0, len(ids)) + for _, id := range ids { + u, err := uuid.Parse(id) + if err != nil { + return profileIteratorOption{}, err + } + uuids = append(uuids, string(u[:])) + } + + return profileIteratorOption{ + iterator: func(opts *iteratorOpts) { + opts.profileIDSelector = uuids + }, + }, nil +} + +type iteratorOpts struct { + profileIDSelector []string // this is a slice of the byte form of the UUID + fetchProfileIDs bool + fetchPartition bool + excludeSampled bool +} + +func iteratorOptsFromOptions(options []profileIteratorOption) iteratorOpts { + opts := iteratorOpts{ + fetchPartition: true, + } + for _, f := range options { + if f.iterator != nil { + f.iterator(&opts) + } + } + return opts +} + +type queryColumn struct { + name string + predicate parquetquery.Predicate + priority int +} + +type queryColumns []queryColumn + +func (c queryColumns) names() []string { + result := make([]string, len(c)) + for idx := range result { + result[idx] = c[idx].name + } + return result +} + +func (c queryColumns) join(q *queryContext) parquetquery.Iterator { + var result parquetquery.Iterator + + // sort columns by priority, without modifying queryColumn slice + order := make([]int, len(c)) + for idx := range order { + order[idx] = idx + } + slices.SortFunc(order, func(a, b int) int { + if r := c[a].priority - c[b].priority; r != 0 { + return r + } + return strings.Compare(c[a].name, c[b].name) + }) + + for _, idx := range order { + it := q.ds.Profiles().Column(q.ctx, c[idx].name, c[idx].predicate) + if result == nil { + result = it + continue + } + result = parquetquery.NewBinaryJoinIterator(0, + result, + it, + ) + } + return result +} + +func profileEntryIterator(q *queryContext, options ...profileIteratorOption) (iter.Iterator[ProfileEntry], error) { + opts := iteratorOptsFromOptions(options) + + matchers := q.req.matchers + if opts.excludeSampled { + matchers = append(matchers[:len(matchers):len(matchers)], + labels.MustNewMatcher(labels.MatchNotEqual, phlaremodel.LabelNameSampled, "true")) + } + series, err := getSeries(q.ds.Index(), matchers, options...) + if err != nil { + return nil, err + } + + columns := queryColumns{ + {schemav1.SeriesIndexColumnName, parquetquery.NewMapPredicate(series), 10}, + {schemav1.TimeNanosColumnName, parquetquery.NewIntBetweenPredicate(q.req.startTime, q.req.endTime), 15}, + } + processor := []func([][]parquet.Value, *ProfileEntry){} + + // fetch partition if requested + if opts.fetchPartition { + offset := len(columns) + columns = append( + columns, + queryColumn{schemav1.StacktracePartitionColumnName, nil, 20}, + ) + processor = append(processor, func(buf [][]parquet.Value, e *ProfileEntry) { + e.Partition = buf[offset][0].Uint64() + }) + } + // fetch profile id if requested or part of the predicate + if opts.fetchProfileIDs || len(opts.profileIDSelector) > 0 { + var ( + predicate parquetquery.Predicate + priority = 20 + ) + if len(opts.profileIDSelector) > 0 { + predicate = parquetquery.NewStringInPredicate(opts.profileIDSelector) + priority = 5 + } + offset := len(columns) + columns = append( + columns, + queryColumn{schemav1.IDColumnName, predicate, priority}, + ) + var u uuid.UUID + processor = append(processor, func(buf [][]parquet.Value, e *ProfileEntry) { + b := buf[offset][0].Bytes() + if len(b) != 16 { + return + } + copy(u[:], b) + e.ID = u.String() + }) + } + + buf := make([][]parquet.Value, len(columns)) + columnNames := columns.names() + + entries := iter.NewAsyncBatchIterator[*parquetquery.IteratorResult, ProfileEntry]( + columns.join(q), bigBatchSize, + func(r *parquetquery.IteratorResult) ProfileEntry { + buf = r.Columns(buf, columnNames...) + x := series[buf[0][0].Uint32()] + e := ProfileEntry{ + RowNum: r.RowNumber[0], + Timestamp: model.TimeFromUnixNano(buf[1][0].Int64()), + Fingerprint: x.fingerprint, + Labels: x.labels, + } + for _, proc := range processor { + proc(buf, &e) + } + return e + }, + func([]ProfileEntry) {}, + ) + return entries, nil +} + +type series struct { + fingerprint model.Fingerprint + labels phlaremodel.Labels +} + +type seriesOpts struct { + allLabels bool // when this is true, groupBy is ignored + groupBy []string +} + +func getSeries(reader phlaredb.IndexReader, matchers []*labels.Matcher, options ...profileIteratorOption) (map[uint32]series, error) { + var opts seriesOpts + for _, f := range options { + if f.series != nil { + f.series(&opts) + } + } + + postings, err := getPostings(reader, matchers...) + if err != nil { + return nil, err + } + chunks := make([]index.ChunkMeta, 1) + s := make(map[uint32]series) + l := make(phlaremodel.Labels, 0, 6) + for postings.Next() { + var fp uint64 + if opts.allLabels { + fp, err = reader.Series(postings.At(), &l, &chunks) + } else { + fp, err = reader.SeriesBy(postings.At(), &l, &chunks, opts.groupBy...) + } + if err != nil { + return nil, err + } + _, ok := s[chunks[0].SeriesIndex] + if ok { + continue + } + s[chunks[0].SeriesIndex] = series{ + fingerprint: model.Fingerprint(fp), + labels: l.Clone(), + } + } + return s, postings.Err() +} + +func getPostings(reader phlaredb.IndexReader, matchers ...*labels.Matcher) (index.Postings, error) { + if len(matchers) == 0 { + k, v := index.AllPostingsKey() + return reader.Postings(k, nil, v) + } + return phlaredb.PostingsForMatchers(reader, nil, matchers...) +} + +func getSeriesIDs(reader phlaredb.IndexReader, matchers ...*labels.Matcher) (map[uint32]struct{}, error) { + postings, err := getPostings(reader, matchers...) + if err != nil { + return nil, err + } + defer func() { + _ = postings.Close() + }() + visited := make(map[uint32]struct{}) + chunks := make([]index.ChunkMeta, 1) + for postings.Next() { + if _, err = reader.Series(postings.At(), nil, &chunks); err != nil { + return nil, err + } + visited[chunks[0].SeriesIndex] = struct{}{} + } + if err = postings.Err(); err != nil { + return nil, err + } + return visited, nil +} diff --git a/pkg/querybackend/query_series_labels.go b/pkg/querybackend/query_series_labels.go new file mode 100644 index 0000000000..a85c4235ce --- /dev/null +++ b/pkg/querybackend/query_series_labels.go @@ -0,0 +1,129 @@ +package querybackend + +import ( + "errors" + "slices" + "sync" + + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/storage" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" +) + +func init() { + registerQueryType( + queryv1.QueryType_QUERY_SERIES_LABELS, + queryv1.ReportType_REPORT_SERIES_LABELS, + querySeriesLabels, + newSeriesLabelsAggregator, + false, + []block.Section{block.SectionTSDB}..., + ) +} + +func querySeriesLabels(q *queryContext, query *queryv1.Query) (*queryv1.Report, error) { + series, err := getSeriesLabels(q.ds.Index(), q.req.matchers, query.SeriesLabels.LabelNames...) + if err != nil { + return nil, err + } + resp := &queryv1.Report{ + SeriesLabels: &queryv1.SeriesLabelsReport{ + Query: query.SeriesLabels.CloneVT(), + SeriesLabels: series, + }, + } + return resp, nil +} + +type seriesLabelsAggregator struct { + init sync.Once + query *queryv1.SeriesLabelsQuery + series *phlaremodel.LabelMerger +} + +func newSeriesLabelsAggregator(*queryv1.InvokeRequest) aggregator { + return new(seriesLabelsAggregator) +} + +func (a *seriesLabelsAggregator) aggregate(report *queryv1.Report) error { + r := report.SeriesLabels + a.init.Do(func() { + a.query = r.Query.CloneVT() + a.series = phlaremodel.NewLabelMerger() + }) + a.series.MergeSeries(r.SeriesLabels) + return nil +} + +func (a *seriesLabelsAggregator) build() *queryv1.Report { + return &queryv1.Report{ + SeriesLabels: &queryv1.SeriesLabelsReport{ + Query: a.query, + SeriesLabels: a.series.Labels(), + }, + } +} + +func getSeriesLabels(reader phlaredb.IndexReader, matchers []*labels.Matcher, by ...string) ([]*typesv1.Labels, error) { + names, err := reader.LabelNames() + if err != nil { + return nil, err + } + if len(by) > 0 { + names = slices.DeleteFunc(names, func(n string) bool { + for j := 0; j < len(by); j++ { + if by[j] == n { + return false + } + } + return true + }) + if len(names) == 0 { + return nil, nil + } + } + + postings, err := getPostings(reader, matchers...) + if err != nil { + return nil, err + } + + visited := make(map[uint64]struct{}) + sets := make([]*typesv1.Labels, 0, 32) + ls := make(phlaremodel.Labels, len(names)) + for i := range names { + ls[i] = new(typesv1.LabelPair) + } + + for postings.Next() { + var j int + var v string + for i := range names { + v, err = reader.LabelValueFor(postings.At(), names[i]) + switch { + case err == nil: + case errors.Is(err, storage.ErrNotFound): + default: + return nil, err + } + if v != "" { + ls[j].Name = names[i] + ls[j].Value = v + j++ + } + } + set := ls[:j] + h := set.Hash() + if _, ok := visited[h]; !ok { + visited[h] = struct{}{} + sets = append(sets, &typesv1.Labels{Labels: set.Clone()}) + } + } + + return sets, postings.Err() +} diff --git a/pkg/querybackend/query_time_series.go b/pkg/querybackend/query_time_series.go new file mode 100644 index 0000000000..795c69a569 --- /dev/null +++ b/pkg/querybackend/query_time_series.go @@ -0,0 +1,301 @@ +package querybackend + +import ( + "strings" + "sync" + "time" + + "github.com/grafana/dskit/runutil" + "github.com/parquet-go/parquet-go" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/attributetable" + "github.com/grafana/pyroscope/v2/pkg/model/timeseries" + "github.com/grafana/pyroscope/v2/pkg/model/timeseriescompact" + parquetquery "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +func init() { + registerQueryType( + queryv1.QueryType_QUERY_TIME_SERIES, + queryv1.ReportType_REPORT_TIME_SERIES, + queryTimeSeries, + newTimeSeriesAggregator, + true, + []block.Section{ + block.SectionTSDB, + block.SectionProfiles, + }..., + ) + registerQueryType( + queryv1.QueryType_QUERY_TIME_SERIES_COMPACT, + queryv1.ReportType_REPORT_TIME_SERIES_COMPACT, + queryTimeSeriesCompact, + newTimeSeriesCompactAggregator, + true, + []block.Section{ + block.SectionTSDB, + block.SectionProfiles, + }..., + ) +} + +type timeSeriesQueryResult struct { + series []*typesv1.Series + exemplarCount int +} + +// executeTimeSeriesQuery is shared by both query types to avoid duplication. +func executeTimeSeriesQuery(q *queryContext, groupBy []string, exemplarType typesv1.ExemplarType) (*timeSeriesQueryResult, error) { + includeExemplars, err := validateExemplarType(exemplarType) + if err != nil { + return nil, err + } + + otelSpan := trace.SpanFromContext(q.ctx) + otelSpan.SetAttributes( + attribute.Bool("exemplars.enabled", includeExemplars), + attribute.String("exemplars.type", exemplarType.String()), + ) + + opts := []profileIteratorOption{withFetchPartition(false)} + if includeExemplars { + opts = append(opts, withAllLabels(), withFetchProfileIDs(true)) + } else { + opts = append(opts, withGroupByLabels(groupBy...)) + } + if !q.includeStripped { + opts = append(opts, withExcludeSampled()) + } + + entries, err := profileEntryIterator(q, opts...) + if err != nil { + return nil, err + } + defer runutil.CloseWithErrCapture(&err, entries, "failed to close profile entry iterator") + + column, err := schemav1.ResolveColumnByPath(q.ds.Profiles().Schema(), strings.Split("TotalValue", ".")) + if err != nil { + return nil, err + } + + annotationKeysColumn, _ := schemav1.ResolveColumnByPath(q.ds.Profiles().Schema(), schemav1.AnnotationKeyColumnPath) + annotationValuesColumn, _ := schemav1.ResolveColumnByPath(q.ds.Profiles().Schema(), schemav1.AnnotationValueColumnPath) + + rows := parquetquery.NewRepeatedRowIteratorBatchSize(q.ctx, entries, q.ds.Profiles().RowGroups(), bigBatchSize, column.ColumnIndex, annotationKeysColumn.ColumnIndex, annotationValuesColumn.ColumnIndex) + defer runutil.CloseWithErrCapture(&err, rows, "failed to close column iterator") + + builder := timeseries.NewBuilder(groupBy...) + for rows.Next() { + row := rows.At() + annotations := schemav1.Annotations{Keys: make([]string, 0), Values: make([]string, 0)} + stripped := row.Row.Labels.Get(phlaremodel.LabelNameSampled) == "true" + for _, e := range row.Values { + if e[0].Column() == annotationKeysColumn.ColumnIndex && e[0].Kind() == parquet.ByteArray { + annotations.Keys = append(annotations.Keys, e[0].String()) + } + if e[0].Column() == annotationValuesColumn.ColumnIndex && e[0].Kind() == parquet.ByteArray { + annotations.Values = append(annotations.Values, e[0].String()) + } + } + exemplarID := row.Row.ID + if stripped { + exemplarID = "" + } + builder.Add( + row.Row.Fingerprint, + row.Row.Labels, + int64(row.Row.Timestamp), + float64(row.Values[0][0].Int64()), + annotations, + exemplarID, + ) + } + if err = rows.Err(); err != nil { + return nil, err + } + + var series []*typesv1.Series + if includeExemplars { + series = builder.BuildWithExemplars() + } else { + series = builder.Build() + } + + return &timeSeriesQueryResult{series: series, exemplarCount: builder.ExemplarCount()}, nil +} + +func queryTimeSeries(q *queryContext, query *queryv1.Query) (r *queryv1.Report, err error) { + result, err := executeTimeSeriesQuery(q, query.TimeSeries.GroupBy, query.TimeSeries.ExemplarType) + if err != nil { + return nil, err + } + + if result.exemplarCount > 0 { + trace.SpanFromContext(q.ctx).SetAttributes(attribute.Int("exemplars.raw_count", result.exemplarCount)) + } + + return &queryv1.Report{ + TimeSeries: &queryv1.TimeSeriesReport{ + Query: query.TimeSeries.CloneVT(), + TimeSeries: result.series, + }, + }, nil +} + +func queryTimeSeriesCompact(q *queryContext, query *queryv1.Query) (r *queryv1.Report, err error) { + result, err := executeTimeSeriesQuery(q, query.TimeSeriesCompact.GroupBy, query.TimeSeriesCompact.ExemplarType) + if err != nil { + return nil, err + } + + if result.exemplarCount > 0 { + trace.SpanFromContext(q.ctx).SetAttributes(attribute.Int("exemplars.raw_count", result.exemplarCount)) + } + + at := attributetable.New() + series := make([]*queryv1.Series, len(result.series)) + for i, s := range result.series { + series[i] = &queryv1.Series{ + AttributeRefs: at.Refs(phlaremodel.Labels(s.Labels), nil), + Points: convertPoints(s.Points, at), + } + } + + return &queryv1.Report{ + TimeSeriesCompact: &queryv1.TimeSeriesCompactReport{ + Query: query.TimeSeriesCompact.CloneVT(), + TimeSeries: series, + AttributeTable: at.Build(nil), + }, + }, nil +} + +func convertPoints(points []*typesv1.Point, at *attributetable.Table) []*queryv1.Point { + result := make([]*queryv1.Point, len(points)) + for i, p := range points { + result[i] = &queryv1.Point{Value: p.Value, Timestamp: p.Timestamp} + if len(p.Annotations) > 0 { + keys := make([]string, len(p.Annotations)) + values := make([]string, len(p.Annotations)) + for j, a := range p.Annotations { + keys[j] = a.Key + values[j] = a.Value + } + result[i].AnnotationRefs = at.AnnotationRefs(keys, values, nil) + } + if len(p.Exemplars) > 0 { + result[i].Exemplars = make([]*queryv1.Exemplar, len(p.Exemplars)) + for j, ex := range p.Exemplars { + result[i].Exemplars[j] = &queryv1.Exemplar{ + Timestamp: ex.Timestamp, + ProfileId: ex.ProfileId, + SpanId: ex.SpanId, + Value: ex.Value, + AttributeRefs: at.Refs(phlaremodel.Labels(ex.Labels), nil), + } + } + } + } + return result +} + +type timeSeriesAggregator struct { + init sync.Once + startTime int64 + endTime int64 + query *queryv1.TimeSeriesQuery + series *timeseries.Merger +} + +func newTimeSeriesAggregator(req *queryv1.InvokeRequest) aggregator { + return &timeSeriesAggregator{ + startTime: req.StartTime, + endTime: req.EndTime, + } +} + +func (a *timeSeriesAggregator) aggregate(report *queryv1.Report) error { + r := report.TimeSeries + a.init.Do(func() { + a.series = timeseries.NewMerger(true) + a.query = r.Query.CloneVT() + }) + a.series.MergeTimeSeries(r.TimeSeries) + return nil +} + +func (a *timeSeriesAggregator) build() *queryv1.Report { + // TODO(kolesnikovae): Average aggregation should be implemented in + // the way that it can be distributed (count + sum), and should be done + // at "aggregate" call. + sum := typesv1.TimeSeriesAggregationType_TIME_SERIES_AGGREGATION_TYPE_SUM + stepMilli := time.Duration(a.query.GetStep() * float64(time.Second)).Milliseconds() + seriesIterator := timeseries.NewTimeSeriesMergeIterator(a.series.TimeSeries()) + series := timeseries.RangeSeries(seriesIterator, a.startTime+stepMilli, a.endTime, stepMilli, &sum) + return &queryv1.Report{ + TimeSeries: &queryv1.TimeSeriesReport{ + Query: a.query, + TimeSeries: series, + }, + } +} + +type timeSeriesCompactAggregator struct { + init sync.Once + startTime int64 + endTime int64 + query *queryv1.TimeSeriesQuery + merger *timeseriescompact.Merger +} + +func newTimeSeriesCompactAggregator(req *queryv1.InvokeRequest) aggregator { + return &timeSeriesCompactAggregator{ + startTime: req.StartTime, + endTime: req.EndTime, + } +} + +func (a *timeSeriesCompactAggregator) aggregate(report *queryv1.Report) error { + r := report.TimeSeriesCompact + a.init.Do(func() { + a.merger = timeseriescompact.NewMerger() + a.query = r.Query.CloneVT() + }) + a.merger.MergeReport(r) + return nil +} + +func (a *timeSeriesCompactAggregator) build() *queryv1.Report { + stepMilli := time.Duration(a.query.GetStep() * float64(time.Second)).Milliseconds() + seriesIterator := a.merger.Iterator() + series := timeseriescompact.RangeSeries(seriesIterator, a.startTime+stepMilli, a.endTime, stepMilli) + return &queryv1.Report{ + TimeSeriesCompact: &queryv1.TimeSeriesCompactReport{ + Query: a.query, + TimeSeries: series, + AttributeTable: a.merger.BuildAttributeTable(), + }, + } +} + +func validateExemplarType(exemplarType typesv1.ExemplarType) (bool, error) { + switch exemplarType { + case typesv1.ExemplarType_EXEMPLAR_TYPE_UNSPECIFIED, typesv1.ExemplarType_EXEMPLAR_TYPE_NONE: + return false, nil + case typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL: + return true, nil + case typesv1.ExemplarType_EXEMPLAR_TYPE_SPAN: + return false, status.Error(codes.Unimplemented, "exemplar type span is not implemented") + default: + return false, status.Errorf(codes.InvalidArgument, "unknown exemplar type: %v", exemplarType) + } +} diff --git a/pkg/querybackend/query_time_series_test.go b/pkg/querybackend/query_time_series_test.go new file mode 100644 index 0000000000..052b93a479 --- /dev/null +++ b/pkg/querybackend/query_time_series_test.go @@ -0,0 +1,552 @@ +package querybackend + +import ( + "bytes" + "context" + "os" + "path/filepath" + "slices" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + "github.com/grafana/pyroscope/v2/pkg/querybackend/queryplan" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func TestValidateExemplarType(t *testing.T) { + tests := []struct { + name string + exemplarType typesv1.ExemplarType + expectedInclude bool + expectedErrorMsg string + expectedCode codes.Code + }{ + { + name: "UNSPECIFIED returns false, no error", + exemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_UNSPECIFIED, + expectedInclude: false, + }, + { + name: "NONE returns false, no error", + exemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_NONE, + expectedInclude: false, + }, + { + name: "INDIVIDUAL returns true, no error", + exemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL, + expectedInclude: true, + }, + { + name: "SPAN returns error with Unimplemented code", + exemplarType: typesv1.ExemplarType_EXEMPLAR_TYPE_SPAN, + expectedInclude: false, + expectedErrorMsg: "exemplar type span is not implemented", + expectedCode: codes.Unimplemented, + }, + { + name: "Unknown type returns error with InvalidArgument code", + exemplarType: typesv1.ExemplarType(999), + expectedInclude: false, + expectedErrorMsg: "unknown exemplar type", + expectedCode: codes.InvalidArgument, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + include, err := validateExemplarType(tt.exemplarType) + if tt.expectedErrorMsg != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.expectedErrorMsg) + st, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, tt.expectedCode, st.Code()) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expectedInclude, include) + } + }) + } +} + +func newTestCompactAggregator(startTime, endTime int64) (*timeSeriesCompactAggregator, *queryv1.TimeSeriesQuery) { + query := &queryv1.TimeSeriesQuery{ + GroupBy: []string{"service_name"}, + Step: 1.0, + } + req := &queryv1.InvokeRequest{ + StartTime: startTime, + EndTime: endTime, + Query: []*queryv1.Query{{ + TimeSeriesCompact: query, + }}, + } + return newTimeSeriesCompactAggregator(req).(*timeSeriesCompactAggregator), query +} + +func makeCompactReport(query *queryv1.TimeSeriesQuery, table *queryv1.AttributeTable, series []*queryv1.Series) *queryv1.Report { + return &queryv1.Report{ + TimeSeriesCompact: &queryv1.TimeSeriesCompactReport{ + Query: query, + TimeSeries: series, + AttributeTable: table, + }, + } +} + +func resolveRefs(refs []int64, table *queryv1.AttributeTable) []string { + result := make([]string, len(refs)) + for i, ref := range refs { + result[i] = table.Keys[ref] + "=" + table.Values[ref] + } + return result +} + +func TestTimeSeriesCompactAggregator(t *testing.T) { + agg, query := newTestCompactAggregator(0, 2000) + + // Report 1: exemplar with 3 attributes (pod, version, region) at timestamp 1000 + report1 := makeCompactReport(query, &queryv1.AttributeTable{ + Keys: []string{"service_name", "pod", "version", "region"}, + Values: []string{"api", "a", "1.0", "us-east-1"}, + }, []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{ + Timestamp: 1000, + Value: 100, + Exemplars: []*queryv1.Exemplar{{ + ProfileId: "prof-1", + Value: 100, + Timestamp: 1000, + AttributeRefs: []int64{1, 2, 3}, + }}, + }}, + }}) + + // Report 2: exemplar with 2 attributes at timestamp 2000 + report2 := makeCompactReport(query, &queryv1.AttributeTable{ + Keys: []string{"service_name", "pod", "version"}, + Values: []string{"api", "b", "1.0"}, + }, []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{ + Timestamp: 2000, + Value: 200, + Exemplars: []*queryv1.Exemplar{{ + ProfileId: "prof-2", + Value: 200, + Timestamp: 2000, + AttributeRefs: []int64{1, 2}, + }}, + }}, + }}) + + // Report 3: same timestamp as report1, lower value exemplar (tests highest-value selection) + report3 := makeCompactReport(query, &queryv1.AttributeTable{ + Keys: []string{"service_name", "pod", "version", "region"}, + Values: []string{"api", "a", "1.0", "us-east-1"}, + }, []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{ + Timestamp: 1000, + Value: 50, + Exemplars: []*queryv1.Exemplar{{ + ProfileId: "prof-3", + Value: 50, + Timestamp: 1000, + AttributeRefs: []int64{1, 2, 3}, + }}, + }}, + }}) + + require.NoError(t, agg.aggregate(report1)) + require.NoError(t, agg.aggregate(report2)) + require.NoError(t, agg.aggregate(report3)) + + result := agg.build() + require.NotNil(t, result.TimeSeriesCompact) + require.NotNil(t, result.TimeSeriesCompact.AttributeTable) + require.Len(t, result.TimeSeriesCompact.TimeSeries, 1) + + series := result.TimeSeriesCompact.TimeSeries[0] + attrTable := result.TimeSeriesCompact.AttributeTable + require.Len(t, series.Points, 2, "Should have 2 points (different timestamps)") + + // Point 1: timestamp 1000 - should keep prof-1 (value=100) not prof-3 (value=50) + point1 := series.Points[0] + require.Equal(t, int64(1000), point1.Timestamp) + require.Len(t, point1.Exemplars, 1) + assert.Equal(t, "prof-1", point1.Exemplars[0].ProfileId) + assert.Equal(t, int64(100), point1.Exemplars[0].Value) + assert.ElementsMatch(t, []string{"pod=a", "version=1.0", "region=us-east-1"}, + resolveRefs(point1.Exemplars[0].AttributeRefs, attrTable)) + + // Point 2: timestamp 2000 - should have prof-2 + point2 := series.Points[1] + require.Equal(t, int64(2000), point2.Timestamp) + require.Len(t, point2.Exemplars, 1) + assert.Equal(t, "prof-2", point2.Exemplars[0].ProfileId) + assert.ElementsMatch(t, []string{"pod=b", "version=1.0"}, + resolveRefs(point2.Exemplars[0].AttributeRefs, attrTable)) + + // Verify attribute table has deduplicated entries + assert.Len(t, attrTable.Keys, 5) +} + +func TestTimeSeriesCompactAnnotations(t *testing.T) { + t.Run("same_timestamp_merges_annotations", func(t *testing.T) { + agg, query := newTestCompactAggregator(0, 2000) + + // Report 1: annotations error=true, host=server-1 + report1 := makeCompactReport(query, &queryv1.AttributeTable{ + Keys: []string{"service_name", "error", "host"}, + Values: []string{"api", "true", "server-1"}, + }, []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{ + Timestamp: 1000, + Value: 100, + AnnotationRefs: []int64{1, 2}, + }}, + }}) + + // Report 2: annotation error=false at same timestamp + report2 := makeCompactReport(query, &queryv1.AttributeTable{ + Keys: []string{"service_name", "error"}, + Values: []string{"api", "false"}, + }, []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{{ + Timestamp: 1000, + Value: 50, + AnnotationRefs: []int64{1}, + }}, + }}) + + require.NoError(t, agg.aggregate(report1)) + require.NoError(t, agg.aggregate(report2)) + + result := agg.build() + series := result.TimeSeriesCompact.TimeSeries[0] + require.Len(t, series.Points, 1) + + point := series.Points[0] + assert.Equal(t, int64(1000), point.Timestamp) + assert.Equal(t, 150.0, point.Value) // 100 + 50 + assert.ElementsMatch(t, []string{"error=true", "host=server-1", "error=false"}, + resolveRefs(point.AnnotationRefs, result.TimeSeriesCompact.AttributeTable)) + }) + + t.Run("different_timestamps_no_corruption", func(t *testing.T) { + // annotations at different timestamps should not be corrupted by later points. + agg, query := newTestCompactAggregator(0, 3000) + + report := makeCompactReport(query, &queryv1.AttributeTable{ + Keys: []string{"service_name", "error", "host", "region"}, + Values: []string{"api", "true", "server-1", "us-east"}, + }, []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 100, AnnotationRefs: []int64{1}}, + {Timestamp: 2000, Value: 200, AnnotationRefs: []int64{2}}, + {Timestamp: 3000, Value: 300, AnnotationRefs: []int64{3}}, + }, + }}) + + require.NoError(t, agg.aggregate(report)) + + result := agg.build() + series := result.TimeSeriesCompact.TimeSeries[0] + attrTable := result.TimeSeriesCompact.AttributeTable + require.Len(t, series.Points, 3) + + // Each point should have its own annotations, not corrupted by later points + assert.ElementsMatch(t, []string{"error=true"}, resolveRefs(series.Points[0].AnnotationRefs, attrTable)) + assert.ElementsMatch(t, []string{"host=server-1"}, resolveRefs(series.Points[1].AnnotationRefs, attrTable)) + assert.ElementsMatch(t, []string{"region=us-east"}, resolveRefs(series.Points[2].AnnotationRefs, attrTable)) + }) +} + +func TestTimeSeriesCompactAggregator_FirstSampleNotLost(t *testing.T) { + agg, query := newTestCompactAggregator(1000, 5000) + + report := makeCompactReport(query, &queryv1.AttributeTable{ + Keys: []string{"service_name"}, + Values: []string{"test-svc"}, + }, []*queryv1.Series{{ + AttributeRefs: []int64{0}, + Points: []*queryv1.Point{ + {Timestamp: 1000, Value: 100}, + {Timestamp: 2500, Value: 200}, + {Timestamp: 3500, Value: 300}, + }, + }}) + + require.NoError(t, agg.aggregate(report)) + result := agg.build() + + require.NotNil(t, result.TimeSeriesCompact) + require.Len(t, result.TimeSeriesCompact.TimeSeries, 1) + + series := result.TimeSeriesCompact.TimeSeries[0] + + require.Len(t, series.Points, 3, "all three samples should produce visible points; first sample at Ts==startTime must not be lost") + assert.Equal(t, int64(2000), series.Points[0].Timestamp) + assert.Equal(t, 100.0, series.Points[0].Value) + assert.Equal(t, int64(3000), series.Points[1].Timestamp) + assert.Equal(t, 200.0, series.Points[1].Value) + assert.Equal(t, int64(4000), series.Points[2].Timestamp) + assert.Equal(t, 300.0, series.Points[2].Value) +} + +func TestTimeSeriesAggregator_FirstSampleNotLost(t *testing.T) { + query := &queryv1.TimeSeriesQuery{ + GroupBy: []string{"service_name"}, + Step: 1.0, + } + req := &queryv1.InvokeRequest{ + StartTime: 1000, + EndTime: 5000, + Query: []*queryv1.Query{{ + TimeSeries: query, + }}, + } + agg := newTimeSeriesAggregator(req).(*timeSeriesAggregator) + + report := &queryv1.Report{ + TimeSeries: &queryv1.TimeSeriesReport{ + Query: query, + TimeSeries: []*typesv1.Series{{ + Labels: []*typesv1.LabelPair{{Name: "service_name", Value: "test-svc"}}, + Points: []*typesv1.Point{ + {Timestamp: 1000, Value: 100}, + {Timestamp: 2500, Value: 200}, + {Timestamp: 3500, Value: 300}, + }, + }}, + }, + } + + require.NoError(t, agg.aggregate(report)) + result := agg.build() + + require.NotNil(t, result.TimeSeries) + require.Len(t, result.TimeSeries.TimeSeries, 1) + + series := result.TimeSeries.TimeSeries[0] + require.Len(t, series.Points, 3, "all three samples should produce visible points; first sample at Ts==startTime must not be lost") + assert.Equal(t, int64(2000), series.Points[0].Timestamp) + assert.Equal(t, 100.0, series.Points[0].Value) + assert.Equal(t, int64(3000), series.Points[1].Timestamp) + assert.Equal(t, 200.0, series.Points[1].Value) + assert.Equal(t, int64(4000), series.Points[2].Timestamp) + assert.Equal(t, 300.0, series.Points[2].Value) +} + +type benchmarkFixture struct { + ctx context.Context + reader *BlockReader + plan *queryv1.QueryPlan + tenant []string + startTime time.Time +} + +func setupBenchmarkFixture(b *testing.B) *benchmarkFixture { + b.Helper() + + bucket := memory.NewInMemBucket() + var blocks []*metastorev1.BlockMeta + + err := filepath.WalkDir("testdata/samples", func(path string, e os.DirEntry, err error) error { + if err != nil || e.IsDir() { + return err + } + data, err := os.ReadFile(path) + if err != nil { + return err + } + var md metastorev1.BlockMeta + if err = metadata.Decode(data, &md); err != nil { + return err + } + md.Size = uint64(len(data)) + blocks = append(blocks, &md) + return bucket.Upload(context.Background(), block.ObjectPath(&md), bytes.NewReader(data)) + }) + if err != nil { + b.Fatalf("failed to load test data: %v", err) + } + + logger := test.NewTestingLogger(b) + reader := NewBlockReader(logger, &objstore.ReaderAtBucket{Bucket: bucket}, nil, validation.MockDefaultOverrides()) + + meta := make([]*metastorev1.BlockMeta, len(blocks)) + for i, block := range blocks { + meta[i] = block.CloneVT() + } + sanitizeMetadata(meta) + + plan := queryplan.Build(meta, 10, 10) + + var tenant []string + for _, b := range plan.Root.Blocks { + for _, d := range b.Datasets { + tenant = append(tenant, b.StringTable[d.Tenant]) + } + } + + var minTime int64 = -1 + for _, block := range blocks { + if minTime == -1 || block.MinTime < minTime { + minTime = block.MinTime + } + } + + return &benchmarkFixture{ + ctx: context.Background(), + reader: reader, + plan: plan, + tenant: tenant, + startTime: time.UnixMilli(minTime), + } +} + +func sanitizeMetadata(meta []*metastorev1.BlockMeta) { + for _, m := range meta { + for _, d := range m.Datasets { + if block.DatasetFormat(d.Format) == block.DatasetFormat1 { + m.Datasets = slices.DeleteFunc(m.Datasets, func(x *metastorev1.Dataset) bool { + return x.Format == 0 + }) + break + } + } + } +} + +func (f *benchmarkFixture) runTimeSeriesQuery(b *testing.B, req *queryv1.InvokeRequest) { + b.Helper() + resp, err := f.reader.Invoke(f.ctx, req) + if err != nil { + b.Fatalf("query failed: %v", err) + } + for _, r := range resp.Reports { + if r.ReportType != queryv1.ReportType_REPORT_TIME_SERIES { + continue + } + for _, s := range r.TimeSeries.TimeSeries { + for _, p := range s.Points { + if p.Value > 0 { + return + } + } + } + } + panic("no data found") +} + +func (f *benchmarkFixture) makeTimeSeriesRequest( + startTime, endTime time.Time, + labelSelector string, + groupBy []string, + exemplarType typesv1.ExemplarType, +) *queryv1.InvokeRequest { + return &queryv1.InvokeRequest{ + StartTime: startTime.UnixMilli(), + EndTime: endTime.UnixMilli(), + LabelSelector: labelSelector, + QueryPlan: f.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TIME_SERIES, + TimeSeries: &queryv1.TimeSeriesQuery{ + Step: 60.0, + GroupBy: groupBy, + ExemplarType: exemplarType, + }, + }}, + Tenant: f.tenant, + } +} + +func BenchmarkTimeSeriesQuery(b *testing.B) { + fixture := setupBenchmarkFixture(b) + + benchmarks := []struct { + name string + exemplarType typesv1.ExemplarType + }{ + {"NoExemplars", typesv1.ExemplarType_EXEMPLAR_TYPE_NONE}, + {"WithExemplars", typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL}, + } + + for _, bm := range benchmarks { + b.Run(bm.name, func(b *testing.B) { + req := fixture.makeTimeSeriesRequest( + fixture.startTime, fixture.startTime.Add(time.Hour), + "{}", + []string{"service_name"}, + bm.exemplarType, + ) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + fixture.runTimeSeriesQuery(b, req) + } + }) + } +} + +func BenchmarkTimeSeriesQuery_TimeRange(b *testing.B) { + fixture := setupBenchmarkFixture(b) + + timeRanges := []struct { + name string + duration time.Duration + }{ + {"1Minute", 1 * time.Minute}, + {"5Minutes", 5 * time.Minute}, + {"15Minutes", 15 * time.Minute}, + {"1Hour", 1 * time.Hour}, + } + + exemplarTypes := []struct { + name string + typ typesv1.ExemplarType + }{ + {"NoExemplars", typesv1.ExemplarType_EXEMPLAR_TYPE_NONE}, + {"WithExemplars", typesv1.ExemplarType_EXEMPLAR_TYPE_INDIVIDUAL}, + } + + for _, tr := range timeRanges { + b.Run(tr.name, func(b *testing.B) { + for _, et := range exemplarTypes { + b.Run(et.name, func(b *testing.B) { + req := fixture.makeTimeSeriesRequest( + fixture.startTime, fixture.startTime.Add(tr.duration), + "{}", + []string{"service_name"}, + et.typ, + ) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + fixture.runTimeSeriesQuery(b, req) + } + }) + } + }) + } +} diff --git a/pkg/querybackend/query_tree.go b/pkg/querybackend/query_tree.go new file mode 100644 index 0000000000..6261a30ca3 --- /dev/null +++ b/pkg/querybackend/query_tree.go @@ -0,0 +1,263 @@ +package querybackend + +import ( + "fmt" + "strings" + "sync" + + "github.com/grafana/dskit/runutil" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/model" + parquetquery "github.com/grafana/pyroscope/v2/pkg/phlaredb/query" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" +) + +func init() { + registerQueryType( + queryv1.QueryType_QUERY_TREE, + queryv1.ReportType_REPORT_TREE, + queryTree, + newTreeAggregator, + false, + []block.Section{ + block.SectionTSDB, + block.SectionProfiles, + block.SectionSymbols, + }..., + ) +} + +// treeSymbolMode resolves the symbol output requested by a tree query. When +// symbol_mode is unset it falls back to the deprecated full_symbols bool for +// wire compatibility; setting both is rejected, as is any mode this backend +// does not implement. +func treeSymbolMode(t *queryv1.TreeQuery) (queryv1.SymbolMode, error) { + mode := t.GetSymbolMode() + if t.GetFullSymbols() { //nolint:staticcheck // bridges the deprecated full_symbols bool + if mode != queryv1.SymbolMode_SYMBOL_MODE_UNSPECIFIED { + return 0, fmt.Errorf("full_symbols must not be combined with symbol_mode") + } + return queryv1.SymbolMode_SYMBOL_MODE_FULL, nil + } + switch mode { + case queryv1.SymbolMode_SYMBOL_MODE_UNSPECIFIED: + return queryv1.SymbolMode_SYMBOL_MODE_NAME, nil + case queryv1.SymbolMode_SYMBOL_MODE_NAME, queryv1.SymbolMode_SYMBOL_MODE_FULL: + return mode, nil + default: + // SYMBOL_MODE_REFS is schema-defined but not implemented here yet. + return 0, fmt.Errorf("unsupported symbol_mode %s", mode) + } +} + +func queryTree(q *queryContext, query *queryv1.Query) (*queryv1.Report, error) { + mode, err := treeSymbolMode(query.Tree) + if err != nil { + return nil, err + } + + otelSpan := trace.SpanFromContext(q.ctx) + + profileOpts := []profileIteratorOption{withExcludeSampled()} + if len(query.Tree.ProfileIdSelector) > 0 { + opt, err := withProfileIDSelector(query.Tree.ProfileIdSelector...) + if err != nil { + return nil, err + } + profileOpts = append(profileOpts, opt) + otelSpan.SetAttributes(attribute.Int("profile_id_selector.count", len(query.Tree.ProfileIdSelector))) + if len(query.Tree.ProfileIdSelector) <= maxProfileIDsToLog { + otelSpan.SetAttributes(attribute.String("profile_ids", strings.Join(query.Tree.ProfileIdSelector, ","))) + } + } + + entries, err := profileEntryIterator(q, profileOpts...) + if err != nil { + return nil, err + } + defer runutil.CloseWithErrCapture(&err, entries, "failed to close profile entry iterator") + + spanSelector, err := model.NewSpanSelector(query.Tree.SpanSelector) + if err != nil { + return nil, err + } + + traceSelector, err := model.NewTraceSelector(query.Tree.TraceIdSelector) + if err != nil { + return nil, err + } + + // Mutually exclusive: no public RPC sets both, so reject an internal query + // plan that does rather than silently apply one and drop the other. + if len(spanSelector) > 0 && len(traceSelector) > 0 { + return nil, fmt.Errorf("span_selector and trace_id_selector cannot be combined") + } + + var columns v1.SampleColumns + if err = columns.Resolve(q.ds.Profiles().Schema()); err != nil { + return nil, err + } + + indices := []int{ + columns.StacktraceID.ColumnIndex, + columns.Value.ColumnIndex, + } + switch { + case len(spanSelector) > 0: + if !columns.HasSpanID() { + // Block has no SpanID column: no samples can match the span selector. + return &queryv1.Report{Tree: &queryv1.TreeReport{Query: query.Tree.CloneVT()}}, nil + } + indices = append(indices, columns.SpanID.ColumnIndex) + case len(traceSelector) > 0: + if !columns.HasTraceID() { + // Block has no TraceID column: no samples can match the trace selector. + return &queryv1.Report{Tree: &queryv1.TreeReport{Query: query.Tree.CloneVT()}}, nil + } + indices = append(indices, columns.TraceID.ColumnIndex) + } + + resolverOptions := []symdb.ResolverOption{ + symdb.WithResolverMaxNodes(query.Tree.MaxNodes), + } + if query.Tree.StackTraceSelector != nil { + resolverOptions = append(resolverOptions, symdb.WithResolverStackTraceSelector(query.Tree.StackTraceSelector)) + } + + profiles := parquetquery.NewRepeatedRowIterator(q.ctx, entries, q.ds.Profiles().RowGroups(), indices...) + defer runutil.CloseWithErrCapture(&err, profiles, "failed to close profile stream") + + resolver := symdb.NewResolver(q.ctx, q.ds.Symbols(), resolverOptions...) + defer resolver.Release() + + switch { + case len(spanSelector) > 0: + for profiles.Next() { + p := profiles.At() + resolver.AddSamplesWithSpanSelectorFromParquetRow( + p.Row.Partition, + p.Values[0], + p.Values[1], + p.Values[2], + spanSelector, + ) + } + case len(traceSelector) > 0: + for profiles.Next() { + p := profiles.At() + resolver.AddSamplesWithTraceSelectorFromParquetRow( + p.Row.Partition, + p.Values[0], + p.Values[1], + p.Values[2], + traceSelector, + ) + } + default: + for profiles.Next() { + p := profiles.At() + resolver.AddSamplesFromParquetRow(p.Row.Partition, p.Values[0], p.Values[1]) + } + } + + if err = profiles.Err(); err != nil { + return nil, err + } + + // output full pprof tree if that's requested + if mode == queryv1.SymbolMode_SYMBOL_MODE_FULL { + tree, symbolBuilder, err := resolver.LocationRefNameTree() + if err != nil { + return nil, err + } + resp := &queryv1.Report{ + Tree: &queryv1.TreeReport{ + Query: query.Tree.CloneVT(), + Tree: tree.Bytes(query.Tree.GetMaxNodes(), symbolBuilder.KeepSymbol), + Symbols: new(queryv1.TreeSymbols), + }, + } + symbolBuilder.Build(resp.Tree.Symbols) + return resp, nil + } + + tree, err := resolver.Tree() + if err != nil { + return nil, err + } + + resp := &queryv1.Report{ + Tree: &queryv1.TreeReport{ + Query: query.Tree.CloneVT(), + Tree: tree.Bytes(query.Tree.GetMaxNodes(), nil), + }, + } + return resp, nil +} + +type treeAggregator struct { + init sync.Once + mode queryv1.SymbolMode + query *queryv1.TreeQuery + tree *model.TreeMerger[model.FunctionName, model.FunctionNameI] + + lrTree *model.TreeMerger[model.LocationRefName, model.LocationRefNameI] + symbolLock sync.Mutex + symbolMerger *symdb.SymbolMerger +} + +func newTreeAggregator(*queryv1.InvokeRequest) aggregator { return new(treeAggregator) } + +func (a *treeAggregator) aggregate(report *queryv1.Report) error { + r := report.Tree + mode, err := treeSymbolMode(r.Query) + if err != nil { + return err + } + if mode == queryv1.SymbolMode_SYMBOL_MODE_FULL { + a.init.Do(func() { + a.mode = mode + a.lrTree = model.NewTreeMerger[model.LocationRefName, model.LocationRefNameI]() + a.query = r.Query.CloneVT() + a.symbolMerger = symdb.NewSymbolMerger() + }) + a.symbolLock.Lock() + defer a.symbolLock.Unlock() + adder, err := a.symbolMerger.Add(r.Symbols) + if err != nil { + return err + } + return a.lrTree.MergeTreeBytes(r.Tree, model.WithTreeMergeFormatNodeNames(adder)) + } + + a.init.Do(func() { + a.mode = mode + a.tree = model.NewTreeMerger[model.FunctionName, model.FunctionNameI]() + a.query = r.Query.CloneVT() + }) + return a.tree.MergeTreeBytes(r.Tree) +} + +func (a *treeAggregator) build() *queryv1.Report { + result := &queryv1.Report{ + Tree: &queryv1.TreeReport{ + Query: a.query, + }, + } + + if a.mode == queryv1.SymbolMode_SYMBOL_MODE_FULL { + builder := a.symbolMerger.ResultBuilder() + result.Tree.Tree = a.lrTree.Tree().Bytes(a.query.GetMaxNodes(), builder.KeepSymbol) + result.Tree.Symbols = new(queryv1.TreeSymbols) + builder.Build(result.Tree.Symbols) + return result + } + + result.Tree.Tree = a.tree.Tree().Bytes(a.query.GetMaxNodes(), nil) + return result +} diff --git a/pkg/querybackend/query_tree_test.go b/pkg/querybackend/query_tree_test.go new file mode 100644 index 0000000000..c28662b6a5 --- /dev/null +++ b/pkg/querybackend/query_tree_test.go @@ -0,0 +1,229 @@ +package querybackend + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +// Test_QueryTree_FullSymbols_Basic verifies that a tree query with FullSymbols=true +// returns a populated symbol table whose slice lengths are consistent. +func (s *testSuite) Test_QueryTree_FullSymbols_Basic() { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_FULL}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().Len(resp.Reports, 1) + + report := resp.Reports[0].Tree + sym := report.Symbols + s.Require().NotNil(sym, "Symbols must be non-nil when FullSymbols=true") + + // Index 0 is the sentinel; we must have real entries beyond it. + s.Assert().Greater(len(sym.Strings), 1) + s.Assert().Len(sym.StringHashes, len(sym.Strings)) + s.Assert().Greater(len(sym.Locations), 1) + s.Assert().Len(sym.LocationHashes, len(sym.Locations)) + s.Assert().Greater(len(sym.Functions), 1) + s.Assert().Len(sym.FunctionHashes, len(sym.Functions)) + + tree, err := phlaremodel.UnmarshalTree[phlaremodel.LocationRefName, phlaremodel.LocationRefNameI](report.Tree) + s.Require().NoError(err) + s.Assert().Greater(tree.Total(), int64(0)) +} + +// Test_QueryTree_FullSymbols_NotSetByDefault ensures that the Symbols field is nil +// when FullSymbols is not requested. +func (s *testSuite) Test_QueryTree_FullSymbols_NotSetByDefault() { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{MaxNodes: 16}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().Len(resp.Reports, 1) + s.Assert().Nil(resp.Reports[0].Tree.Symbols) +} + +// Test_QueryTree_FullSymbols_TotalsMatchNonFullSymbols verifies that the full-symbols +// path (LocationRefName tree) and the standard path (FuntionName tree) produce the +// same total sample count for identical queries, since both resolve the same samples. +func (s *testSuite) Test_QueryTree_FullSymbols_TotalsMatchNonFullSymbols() { + invoke := func(mode queryv1.SymbolMode) *queryv1.TreeReport { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{SymbolMode: mode}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().Len(resp.Reports, 1) + return resp.Reports[0].Tree + } + + lrTree, err := phlaremodel.UnmarshalTree[phlaremodel.LocationRefName, phlaremodel.LocationRefNameI](invoke(queryv1.SymbolMode_SYMBOL_MODE_FULL).Tree) + s.Require().NoError(err) + fnTree, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](invoke(queryv1.SymbolMode_SYMBOL_MODE_NAME).Tree) + s.Require().NoError(err) + + s.Assert().Equal(fnTree.Total(), lrTree.Total()) +} + +// Test_QueryTree_FullSymbols_SymbolConsistency verifies that every location ID +// referenced in the serialised tree is a valid index into Symbols.Locations, and +// that every function ID within those locations is valid in Symbols.Functions. +func (s *testSuite) Test_QueryTree_FullSymbols_SymbolConsistency() { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_FULL}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().Len(resp.Reports, 1) + + report := resp.Reports[0].Tree + sym := report.Symbols + nLocations := len(sym.Locations) + nFunctions := len(sym.Functions) + + tree, err := phlaremodel.UnmarshalTree[phlaremodel.LocationRefName, phlaremodel.LocationRefNameI](report.Tree) + s.Require().NoError(err) + + tree.IterateStacks(func(_ phlaremodel.LocationRefName, _ int64, stack []phlaremodel.LocationRefName) { + for _, locID := range stack { + if locID == phlaremodel.OtherLocationRef || locID == 0 { + continue + } + idx := int(locID) + s.Require().Less(idx, nLocations, "location ID %d out of bounds (have %d locations)", idx, nLocations) + for _, line := range sym.Locations[idx].Line { + s.Require().Less(int(line.FunctionId), nFunctions, "function ID %d out of bounds (have %d functions)", line.FunctionId, nFunctions) + } + } + }) +} + +// Test_QueryTree_FullSymbols_NoDuplicateStrings verifies that the SymbolMerger +// deduplicates the string table correctly when merging results from multiple blocks: +// each unique string must appear exactly once. +func (s *testSuite) Test_QueryTree_FullSymbols_NoDuplicateStrings() { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: "{}", + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_FULL}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().Len(resp.Reports, 1) + + sym := resp.Reports[0].Tree.Symbols + seen := make(map[string]struct{}, len(sym.Strings)) + for _, str := range sym.Strings { + _, already := seen[str] + s.Assert().False(already, "duplicate string %q in merged symbol table", str) + seen[str] = struct{}{} + } +} + +// Test_QueryTree_FullSymbols_Filter verifies that a label-selector filter produces +// a smaller total sample count and a smaller symbol table than an unfiltered query. +func (s *testSuite) Test_QueryTree_FullSymbols_Filter() { + invoke := func(selector string) *queryv1.TreeReport { + resp, err := s.reader.Invoke(s.ctx, &queryv1.InvokeRequest{ + EndTime: time.Now().UnixMilli(), + LabelSelector: selector, + QueryPlan: s.plan, + Query: []*queryv1.Query{{ + QueryType: queryv1.QueryType_QUERY_TREE, + Tree: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_FULL}, + }}, + Tenant: s.tenant, + }) + s.Require().NoError(err) + s.Require().Len(resp.Reports, 1) + return resp.Reports[0].Tree + } + + all := invoke("{}") + filtered := invoke(`{service_name="test-app",function="slow"}`) + + allTree, err := phlaremodel.UnmarshalTree[phlaremodel.LocationRefName, phlaremodel.LocationRefNameI](all.Tree) + s.Require().NoError(err) + filteredTree, err := phlaremodel.UnmarshalTree[phlaremodel.LocationRefName, phlaremodel.LocationRefNameI](filtered.Tree) + s.Require().NoError(err) + + s.Assert().Greater(allTree.Total(), filteredTree.Total()) + s.Assert().Less(len(filtered.Symbols.Locations), len(all.Symbols.Locations)) +} + +func TestTreeSymbolMode(t *testing.T) { + for _, tc := range []struct { + name string + query *queryv1.TreeQuery + want queryv1.SymbolMode + wantErr string + }{ + {name: "unset defaults to name", query: &queryv1.TreeQuery{}, want: queryv1.SymbolMode_SYMBOL_MODE_NAME}, + {name: "name", query: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_NAME}, want: queryv1.SymbolMode_SYMBOL_MODE_NAME}, + {name: "full", query: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_FULL}, want: queryv1.SymbolMode_SYMBOL_MODE_FULL}, + { + name: "deprecated full_symbols maps to full", + query: &queryv1.TreeQuery{FullSymbols: true}, //nolint:staticcheck // exercises the deprecated bridge + want: queryv1.SymbolMode_SYMBOL_MODE_FULL, + }, + { + name: "full_symbols combined with symbol_mode is rejected", + query: &queryv1.TreeQuery{FullSymbols: true, SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_FULL}, //nolint:staticcheck // exercises the deprecated bridge + wantErr: "must not be combined", + }, + { + name: "refs is not implemented yet", + query: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode_SYMBOL_MODE_REFS}, + wantErr: "unsupported symbol_mode", + }, + { + name: "unknown mode is rejected", + query: &queryv1.TreeQuery{SymbolMode: queryv1.SymbolMode(99)}, + wantErr: "unsupported symbol_mode", + }, + } { + t.Run(tc.name, func(t *testing.T) { + mode, err := treeSymbolMode(tc.query) + if tc.wantErr != "" { + require.ErrorContains(t, err, tc.wantErr) + return + } + require.NoError(t, err) + require.Equal(t, tc.want, mode) + }) + } +} diff --git a/pkg/querybackend/queryplan/query_plan.go b/pkg/querybackend/queryplan/query_plan.go new file mode 100644 index 0000000000..475585d9d0 --- /dev/null +++ b/pkg/querybackend/queryplan/query_plan.go @@ -0,0 +1,79 @@ +package queryplan + +import ( + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +// Build creates a query plan from the list of block metadata. +// +// NOTE(kolesnikovae): At this point it only groups blocks into uniform ranges, +// and builds a DAG of reads and merges. In practice, however, we may want to +// implement more sophisticated strategies. For example, it would be beneficial +// to group blocks based on the tenant services to ensure that a single read +// covers exactly one service, and does not have to deal with stack trace +// cardinality issues. Another example is grouping by shards to minimize the +// number of unique series (assuming the shards are still built based on the +// series labels) a reader or merger should handle. In general, the strategy +// should depend on the query type. +func Build( + blocks []*metastorev1.BlockMeta, + maxReads, maxMerges int, +) *queryv1.QueryPlan { + if len(blocks) == 0 { + return new(queryv1.QueryPlan) + } + + if maxReads < 1 { + return new(queryv1.QueryPlan) + } + + if maxMerges < 2 { + return new(queryv1.QueryPlan) + } + + // create leaf nodes and spread the blocks in a uniform way + leafNodeCount := (len(blocks) + maxReads - 1) / maxReads + nodes := allocateContiguous[queryv1.QueryNode](leafNodeCount) + for start, idx := 0, 0; start < len(blocks); start, idx = start+maxReads, idx+1 { + end := start + maxReads + if end > len(blocks) { + end = len(blocks) + } + nodes[idx].Type = queryv1.QueryNode_READ + nodes[idx].Blocks = blocks[start:end] + } + + // create merge nodes until we reach a single root node + for len(nodes) > 1 { + mergeNodeCount := (len(nodes) + maxMerges - 1) / maxMerges + mergeNodes := allocateContiguous[queryv1.QueryNode](mergeNodeCount) + + for start, idx := 0, 0; start < len(nodes); start, idx = start+maxMerges, idx+1 { + end := start + maxMerges + if end > len(nodes) { + end = len(nodes) + } + mergeNodes[idx].Type = queryv1.QueryNode_MERGE + mergeNodes[idx].Children = nodes[start:end:end] + } + + nodes = mergeNodes + } + + return &queryv1.QueryPlan{ + Root: nodes[0], + } +} + +// allocateContiguous returns a []*T of length size where every element points +// into a single backing []T allocation. This avoids the per-element heap +// allocations from N separate &T{} expressions. +func allocateContiguous[T any](size int) []*T { + values := make([]T, size) + pointers := make([]*T, size) + for i := range values { + pointers[i] = &values[i] + } + return pointers +} diff --git a/pkg/querybackend/queryplan/query_plan_test.go b/pkg/querybackend/queryplan/query_plan_test.go new file mode 100644 index 0000000000..318238bbdc --- /dev/null +++ b/pkg/querybackend/queryplan/query_plan_test.go @@ -0,0 +1,114 @@ +package queryplan + +import ( + "bytes" + "flag" + "fmt" + "io" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +var update = flag.Bool("update", false, "rewrite golden files in testdata/ from the current plan output") + +// Test_Build verifies the shape of query plans produced by Build against +// golden files in testdata/. Each subtest's golden file is named after the +// subtest. E.g. Test_Build/single_block reads testdata/single_block.txt. +// +// To regenerate all golden files: +// +// go test ./pkg/querybackend/queryplan/ -update +// +// To regenerate a specific golden file: +// +// go test ./pkg/querybackend/queryplan/ -run Test_Build/ -update +func Test_Build(t *testing.T) { + tests := []struct { + name string + blocks int + maxReads int + maxMerges int + }{ + {name: "empty", blocks: 0, maxReads: 2, maxMerges: 3}, + {name: "invalid_max_reads", blocks: 10, maxReads: 0, maxMerges: 3}, + {name: "invalid_max_merges", blocks: 10, maxReads: 2, maxMerges: 1}, + {name: "single_block", blocks: 1, maxReads: 2, maxMerges: 3}, + {name: "exact_one_leaf", blocks: 2, maxReads: 2, maxMerges: 3}, + {name: "two_leaves", blocks: 3, maxReads: 2, maxMerges: 3}, + {name: "full_depth_2", blocks: 6, maxReads: 2, maxMerges: 3}, + {name: "just_over_depth_2", blocks: 7, maxReads: 2, maxMerges: 3}, + {name: "twenty_five_blocks", blocks: 25, maxReads: 2, maxMerges: 3}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + blocks := makeBlocks(tt.blocks) + p := Build(blocks, tt.maxReads, tt.maxMerges) + + var buf bytes.Buffer + writePlan(t, &buf, "", p.Root) + + // Ensure that the plan has not been modified during traversal. + assert.Equal(t, Build(blocks, tt.maxReads, tt.maxMerges), p) + + if *update { + require.NoError(t, os.WriteFile(goldenFile(t), buf.Bytes(), 0o644)) + return + } + + expected, err := os.ReadFile(goldenFile(t)) + require.NoError(t, err) + assert.Equal(t, string(expected), buf.String()) + }) + } +} + +// makeBlocks creates n BlockMeta with sequential string IDs starting at "1". +func makeBlocks(n int) []*metastorev1.BlockMeta { + blocks := make([]*metastorev1.BlockMeta, n) + for i := 0; i < n; i++ { + blocks[i] = &metastorev1.BlockMeta{Id: strconv.Itoa(i + 1)} + } + return blocks +} + +// goldenFile returns the testdata path for the current (sub)test. The file +// name is the last segment of t.Name(). For `Test_Build/single_block` it +// returns `testdata/single_block.txt`. +func goldenFile(t *testing.T) string { + t.Helper() + parts := strings.Split(t.Name(), "/") + return filepath.Join("testdata", parts[len(parts)-1]+".txt") +} + +// writePlan writes an indented textual representation of the plan rooted at +// n to w. A nil root produces no output. The test fails on malformed nodes. +func writePlan(t *testing.T, w io.Writer, pad string, n *queryv1.QueryNode) { + t.Helper() + if n == nil { + return + } + fmt.Fprintf(w, pad+"%s {children: %d, blocks: %d}\n", + n.Type, len(n.Children), len(n.Blocks)) + switch n.Type { + case queryv1.QueryNode_MERGE: + for _, child := range n.Children { + writePlan(t, w, pad+"\t", child) + } + case queryv1.QueryNode_READ: + for _, md := range n.Blocks { + fmt.Fprintf(w, pad+"\t"+"id:\"%s\"\n", md.Id) + } + default: + t.Fatalf("unknown node type: %v", n.Type) + } +} diff --git a/ebpf/symtab/elf/testdata/.gitignore b/pkg/querybackend/queryplan/testdata/empty.txt similarity index 100% rename from ebpf/symtab/elf/testdata/.gitignore rename to pkg/querybackend/queryplan/testdata/empty.txt diff --git a/pkg/querybackend/queryplan/testdata/exact_one_leaf.txt b/pkg/querybackend/queryplan/testdata/exact_one_leaf.txt new file mode 100644 index 0000000000..a680a080ca --- /dev/null +++ b/pkg/querybackend/queryplan/testdata/exact_one_leaf.txt @@ -0,0 +1,3 @@ +READ {children: 0, blocks: 2} + id:"1" + id:"2" diff --git a/pkg/querybackend/queryplan/testdata/full_depth_2.txt b/pkg/querybackend/queryplan/testdata/full_depth_2.txt new file mode 100644 index 0000000000..bdb06b694c --- /dev/null +++ b/pkg/querybackend/queryplan/testdata/full_depth_2.txt @@ -0,0 +1,10 @@ +MERGE {children: 3, blocks: 0} + READ {children: 0, blocks: 2} + id:"1" + id:"2" + READ {children: 0, blocks: 2} + id:"3" + id:"4" + READ {children: 0, blocks: 2} + id:"5" + id:"6" diff --git a/og/webapp/javascript/services/base.ts b/pkg/querybackend/queryplan/testdata/invalid_max_merges.txt similarity index 100% rename from og/webapp/javascript/services/base.ts rename to pkg/querybackend/queryplan/testdata/invalid_max_merges.txt diff --git a/pkg/querybackend/queryplan/testdata/invalid_max_reads.txt b/pkg/querybackend/queryplan/testdata/invalid_max_reads.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pkg/querybackend/queryplan/testdata/just_over_depth_2.txt b/pkg/querybackend/queryplan/testdata/just_over_depth_2.txt new file mode 100644 index 0000000000..c3a0e9529a --- /dev/null +++ b/pkg/querybackend/queryplan/testdata/just_over_depth_2.txt @@ -0,0 +1,14 @@ +MERGE {children: 2, blocks: 0} + MERGE {children: 3, blocks: 0} + READ {children: 0, blocks: 2} + id:"1" + id:"2" + READ {children: 0, blocks: 2} + id:"3" + id:"4" + READ {children: 0, blocks: 2} + id:"5" + id:"6" + MERGE {children: 1, blocks: 0} + READ {children: 0, blocks: 1} + id:"7" diff --git a/pkg/querybackend/queryplan/testdata/single_block.txt b/pkg/querybackend/queryplan/testdata/single_block.txt new file mode 100644 index 0000000000..e0e4cf04c2 --- /dev/null +++ b/pkg/querybackend/queryplan/testdata/single_block.txt @@ -0,0 +1,2 @@ +READ {children: 0, blocks: 1} + id:"1" diff --git a/pkg/querybackend/queryplan/testdata/twenty_five_blocks.txt b/pkg/querybackend/queryplan/testdata/twenty_five_blocks.txt new file mode 100644 index 0000000000..b851f1731e --- /dev/null +++ b/pkg/querybackend/queryplan/testdata/twenty_five_blocks.txt @@ -0,0 +1,46 @@ +MERGE {children: 2, blocks: 0} + MERGE {children: 3, blocks: 0} + MERGE {children: 3, blocks: 0} + READ {children: 0, blocks: 2} + id:"1" + id:"2" + READ {children: 0, blocks: 2} + id:"3" + id:"4" + READ {children: 0, blocks: 2} + id:"5" + id:"6" + MERGE {children: 3, blocks: 0} + READ {children: 0, blocks: 2} + id:"7" + id:"8" + READ {children: 0, blocks: 2} + id:"9" + id:"10" + READ {children: 0, blocks: 2} + id:"11" + id:"12" + MERGE {children: 3, blocks: 0} + READ {children: 0, blocks: 2} + id:"13" + id:"14" + READ {children: 0, blocks: 2} + id:"15" + id:"16" + READ {children: 0, blocks: 2} + id:"17" + id:"18" + MERGE {children: 2, blocks: 0} + MERGE {children: 3, blocks: 0} + READ {children: 0, blocks: 2} + id:"19" + id:"20" + READ {children: 0, blocks: 2} + id:"21" + id:"22" + READ {children: 0, blocks: 2} + id:"23" + id:"24" + MERGE {children: 1, blocks: 0} + READ {children: 0, blocks: 1} + id:"25" diff --git a/pkg/querybackend/queryplan/testdata/two_leaves.txt b/pkg/querybackend/queryplan/testdata/two_leaves.txt new file mode 100644 index 0000000000..f6ade3b1e9 --- /dev/null +++ b/pkg/querybackend/queryplan/testdata/two_leaves.txt @@ -0,0 +1,6 @@ +MERGE {children: 2, blocks: 0} + READ {children: 0, blocks: 2} + id:"1" + id:"2" + READ {children: 0, blocks: 1} + id:"3" diff --git a/pkg/querybackend/report_aggregator.go b/pkg/querybackend/report_aggregator.go new file mode 100644 index 0000000000..9c8fa8757c --- /dev/null +++ b/pkg/querybackend/report_aggregator.go @@ -0,0 +1,173 @@ +package querybackend + +import ( + "fmt" + "sync" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +var ( + aggregatorMutex = new(sync.RWMutex) + aggregators = map[queryv1.ReportType]aggregatorProvider{} + alwaysAggregate = map[queryv1.ReportType]struct{}{} + queryReportType = map[queryv1.QueryType]queryv1.ReportType{} +) + +type aggregatorProvider func(*queryv1.InvokeRequest) aggregator + +type aggregator interface { + // The method is called concurrently. + aggregate(*queryv1.Report) error + // build the aggregation result. It's guaranteed that aggregate() + // was called at least once before report() is called. + build() *queryv1.Report +} + +func registerAggregator(t queryv1.ReportType, ap aggregatorProvider, always bool) { + aggregatorMutex.Lock() + defer aggregatorMutex.Unlock() + _, ok := aggregators[t] + if ok { + panic(fmt.Sprintf("%s: aggregator already registered", t)) + } + aggregators[t] = ap + + if always { + _, ok := alwaysAggregate[t] + if ok { + panic(fmt.Sprintf("%s: aggregator already registered to always aggregat", t)) + } + alwaysAggregate[t] = struct{}{} + } +} + +func isAlwaysAggregate(t queryv1.ReportType) bool { + aggregatorMutex.RLock() + defer aggregatorMutex.RUnlock() + _, result := alwaysAggregate[t] + return result +} + +func getAggregator(r *queryv1.InvokeRequest, x *queryv1.Report) (aggregator, error) { + aggregatorMutex.RLock() + defer aggregatorMutex.RUnlock() + a, ok := aggregators[x.ReportType] + if !ok { + return nil, fmt.Errorf("unknown build type %s", x.ReportType) + } + return a(r), nil +} + +func registerQueryReportType(q queryv1.QueryType, r queryv1.ReportType) { + aggregatorMutex.Lock() + defer aggregatorMutex.Unlock() + v, ok := queryReportType[q] + if ok { + panic(fmt.Sprintf("%s: handler already registered (%s)", q, v)) + } + queryReportType[q] = r +} + +func QueryReportType(q queryv1.QueryType) queryv1.ReportType { + aggregatorMutex.RLock() + defer aggregatorMutex.RUnlock() + r, ok := queryReportType[q] + if !ok { + panic(fmt.Sprintf("unknown build type %s", q)) + } + return r +} + +type reportAggregator struct { + request *queryv1.InvokeRequest + sm sync.Mutex + staged map[queryv1.ReportType]*queryv1.Report + aggregators map[queryv1.ReportType]aggregator +} + +func newAggregator(request *queryv1.InvokeRequest) *reportAggregator { + return &reportAggregator{ + request: request, + staged: make(map[queryv1.ReportType]*queryv1.Report), + aggregators: make(map[queryv1.ReportType]aggregator), + } +} + +func (ra *reportAggregator) aggregateResponse(resp *queryv1.InvokeResponse, err error) error { + if err != nil { + return err + } + for _, r := range resp.Reports { + if err = ra.aggregateReport(r); err != nil { + return err + } + } + return nil +} + +func (ra *reportAggregator) aggregateReport(r *queryv1.Report) (err error) { + if r == nil { + return nil + } + ra.sm.Lock() + v, found := ra.staged[r.ReportType] + if !found { + // For most ReportTypes we delay aggregation until we have at least two + // reports of the same type. In case there is only one we will + // return it as is. + if !isAlwaysAggregate(r.ReportType) { + ra.staged[r.ReportType] = r + ra.sm.Unlock() + return nil + } + + // Some ReportTypes need to call the aggregator for correctness even when + // there is only single instance, in that case call the aggregator right + // away and mark the report type appropriately in the staged map. + err = ra.aggregateReportNoCheck(r) + ra.staged[r.ReportType] = nil + ra.sm.Unlock() + return err + } + // Found a staged report of the same type. + if v != nil { + // It should be aggregated and removed from the table. + err = ra.aggregateReportNoCheck(v) + ra.staged[r.ReportType] = nil + } + ra.sm.Unlock() + if err != nil { + return err + } + return ra.aggregateReportNoCheck(r) +} + +func (ra *reportAggregator) aggregateReportNoCheck(report *queryv1.Report) (err error) { + a, ok := ra.aggregators[report.ReportType] + if !ok { + a, err = getAggregator(ra.request, report) + if err != nil { + return err + } + ra.aggregators[report.ReportType] = a + } + return a.aggregate(report) +} + +func (ra *reportAggregator) response() *queryv1.InvokeResponse { + // if there are staged reports, we can just add them, no need to aggregate because there is one per type + reports := make([]*queryv1.Report, 0, len(ra.staged)) + for _, st := range ra.staged { + if st != nil { + reports = append(reports, st) + } + } + // build and add reports from already performed aggregations + for t, a := range ra.aggregators { + r := a.build() + r.ReportType = t + reports = append(reports, r) + } + return &queryv1.InvokeResponse{Reports: reports} +} diff --git a/pkg/querybackend/report_aggregator_test.go b/pkg/querybackend/report_aggregator_test.go new file mode 100644 index 0000000000..2d8b326b4d --- /dev/null +++ b/pkg/querybackend/report_aggregator_test.go @@ -0,0 +1,296 @@ +package querybackend + +import ( + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +type mockAggregator struct { + reports []*queryv1.Report + mu sync.Mutex +} + +func (m *mockAggregator) aggregate(r *queryv1.Report) error { + m.mu.Lock() + defer m.mu.Unlock() + m.reports = append(m.reports, r) + return nil +} + +func (m *mockAggregator) build() *queryv1.Report { + m.mu.Lock() + defer m.mu.Unlock() + + if len(m.reports) == 0 { + return &queryv1.Report{} + } + + result := &queryv1.Report{ + ReportType: m.reports[0].ReportType, + } + return result +} + +func (m *mockAggregator) getReportCount() int { + m.mu.Lock() + defer m.mu.Unlock() + return len(m.reports) +} + +func mockAggregatorProvider(req *queryv1.InvokeRequest) aggregator { + return &mockAggregator{ + reports: make([]*queryv1.Report, 0), + } +} + +func TestReportAggregator_SingleReport(t *testing.T) { + reportType := queryv1.ReportType(999) // use a high number that won't conflict with other registrations + registerAggregator(reportType, mockAggregatorProvider, false) + defer func() { + aggregatorMutex.Lock() + delete(aggregators, reportType) + aggregatorMutex.Unlock() + }() + + request := &queryv1.InvokeRequest{} + ra := newAggregator(request) + + report := &queryv1.Report{ReportType: reportType} + err := ra.aggregateReport(report) + require.NoError(t, err) + + // a single report should be staged and no aggregators should be created + assert.Len(t, ra.staged, 1) + assert.Len(t, ra.aggregators, 0) + assert.Equal(t, report, ra.staged[reportType]) + + // the response should contain the single report + resp := ra.response() + require.Len(t, resp.Reports, 1) + assert.Equal(t, report, resp.Reports[0]) +} + +func TestReportAggregator_TwoReports(t *testing.T) { + reportType := queryv1.ReportType(999) + registerAggregator(reportType, mockAggregatorProvider, false) + defer func() { + aggregatorMutex.Lock() + delete(aggregators, reportType) + aggregatorMutex.Unlock() + }() + + request := &queryv1.InvokeRequest{} + ra := newAggregator(request) + + // the first report should be staged + report1 := &queryv1.Report{ReportType: reportType} + err := ra.aggregateReport(report1) + require.NoError(t, err) + assert.Len(t, ra.staged, 1) + assert.Len(t, ra.aggregators, 0) + + // the second report should trigger aggregation + report2 := &queryv1.Report{ReportType: reportType} + err = ra.aggregateReport(report2) + require.NoError(t, err) + assert.Len(t, ra.aggregators, 1) + assert.Nil(t, ra.staged[reportType]) // staged entry should be nil after aggregation + agg := ra.aggregators[reportType].(*mockAggregator) + assert.Equal(t, 2, agg.getReportCount()) + + // the response should contain the aggregated result + resp := ra.response() + require.Len(t, resp.Reports, 1) + assert.Equal(t, reportType, resp.Reports[0].ReportType) +} + +func TestReportAggregator_MultipleTypes(t *testing.T) { + type1 := queryv1.ReportType(999) + type2 := queryv1.ReportType(998) + + registerAggregator(type1, mockAggregatorProvider, false) + registerAggregator(type2, mockAggregatorProvider, false) + defer func() { + aggregatorMutex.Lock() + delete(aggregators, type1) + delete(aggregators, type2) + aggregatorMutex.Unlock() + }() + + request := &queryv1.InvokeRequest{} + ra := newAggregator(request) + + report1Type1 := &queryv1.Report{ReportType: type1} + report2Type2 := &queryv1.Report{ReportType: type2} + report3Type1 := &queryv1.Report{ReportType: type1} + + err := ra.aggregateReport(report1Type1) + require.NoError(t, err) + err = ra.aggregateReport(report2Type2) + require.NoError(t, err) + err = ra.aggregateReport(report3Type1) + require.NoError(t, err) + + // should have one staged report and one aggregator + assert.Equal(t, report2Type2, ra.staged[type2]) + assert.Nil(t, ra.staged[type1]) + assert.Len(t, ra.aggregators, 1) + + resp := ra.response() + require.Len(t, resp.Reports, 2) + + reportTypes := make(map[queryv1.ReportType]bool) + for _, r := range resp.Reports { + reportTypes[r.ReportType] = true + } + assert.True(t, reportTypes[type1]) + assert.True(t, reportTypes[type2]) +} + +func TestReportAggregator_NilReport(t *testing.T) { + request := &queryv1.InvokeRequest{} + ra := newAggregator(request) + + err := ra.aggregateReport(nil) + require.NoError(t, err) + assert.Len(t, ra.staged, 0) + assert.Len(t, ra.aggregators, 0) +} + +func TestReportAggregator_AggregateResponse(t *testing.T) { + reportType := queryv1.ReportType(999) + registerAggregator(reportType, mockAggregatorProvider, false) + defer func() { + aggregatorMutex.Lock() + delete(aggregators, reportType) + aggregatorMutex.Unlock() + }() + + request := &queryv1.InvokeRequest{} + ra := newAggregator(request) + + resp := &queryv1.InvokeResponse{ + Reports: []*queryv1.Report{ + {ReportType: reportType}, + {ReportType: reportType}, + }, + } + + err := ra.aggregateResponse(resp, nil) + require.NoError(t, err) + + assert.Len(t, ra.aggregators, 1) + agg := ra.aggregators[reportType].(*mockAggregator) + assert.Equal(t, 2, agg.getReportCount()) +} + +func TestReportAggregator_ConcurrentAccess(t *testing.T) { + reportType := queryv1.ReportType(999) + registerAggregator(reportType, mockAggregatorProvider, false) + defer func() { + aggregatorMutex.Lock() + delete(aggregators, reportType) + aggregatorMutex.Unlock() + }() + + request := &queryv1.InvokeRequest{} + ra := newAggregator(request) + + const numGoroutines = 10 + const reportsPerGoroutine = 5 + + var wg sync.WaitGroup + wg.Add(numGoroutines) + + for i := 0; i < numGoroutines; i++ { + go func() { + defer wg.Done() + for j := 0; j < reportsPerGoroutine; j++ { + report := &queryv1.Report{ReportType: reportType} + err := ra.aggregateReport(report) + assert.NoError(t, err) + } + }() + } + + wg.Wait() + + resp := ra.response() + assert.Len(t, resp.Reports, 1) +} + +func TestGetAggregator(t *testing.T) { + reportType := queryv1.ReportType(999) + registerAggregator(reportType, mockAggregatorProvider, false) + defer func() { + aggregatorMutex.Lock() + delete(aggregators, reportType) + aggregatorMutex.Unlock() + }() + + request := &queryv1.InvokeRequest{} + report := &queryv1.Report{ReportType: reportType} + + agg, err := getAggregator(request, report) + require.NoError(t, err) + assert.NotNil(t, agg) +} + +func TestGetAggregator_UnknownReportType(t *testing.T) { + request := &queryv1.InvokeRequest{} + unknownReport := &queryv1.Report{ReportType: queryv1.ReportType(996)} + _, err := getAggregator(request, unknownReport) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unknown build type") +} + +func TestRegisterAggregator_Duplicate(t *testing.T) { + reportType := queryv1.ReportType(999) + + registerAggregator(reportType, mockAggregatorProvider, false) + assert.Panics(t, func() { + registerAggregator(reportType, mockAggregatorProvider, false) + }) + + aggregatorMutex.Lock() + delete(aggregators, reportType) + aggregatorMutex.Unlock() +} + +func TestQueryReportType(t *testing.T) { + queryType := queryv1.QueryType(999) + reportType := queryv1.ReportType(999) + + registerQueryReportType(queryType, reportType) + defer func() { + aggregatorMutex.Lock() + delete(queryReportType, queryType) + aggregatorMutex.Unlock() + }() + + result := QueryReportType(queryType) + assert.Equal(t, reportType, result) + + assert.Panics(t, func() { + QueryReportType(queryv1.QueryType(889)) // Use an unregistered query type + }) +} + +func TestRegisterQueryReportType_Duplicate(t *testing.T) { + queryType := queryv1.QueryType(999) + reportType := queryv1.ReportType(999) + + registerQueryReportType(queryType, reportType) + assert.Panics(t, func() { + registerQueryReportType(queryType, queryv1.ReportType_REPORT_PPROF) + }) + + aggregatorMutex.Lock() + delete(queryReportType, queryType) + aggregatorMutex.Unlock() +} diff --git a/pkg/querybackend/testdata/fixtures/series_labels.json b/pkg/querybackend/testdata/fixtures/series_labels.json new file mode 100644 index 0000000000..684d25b24a --- /dev/null +++ b/pkg/querybackend/testdata/fixtures/series_labels.json @@ -0,0 +1,577 @@ +{ + "query": {}, + "series_labels": [ + { + "labels": [ + { + "name": "__name__", + "value": "block" + }, + { + "name": "__period_type__", + "value": "contentions" + }, + { + "name": "__period_unit__", + "value": "count" + }, + { + "name": "__profile_type__", + "value": "block:contentions:count:contentions:count" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "contentions" + }, + { + "name": "__unit__", + "value": "count" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "block" + }, + { + "name": "__period_type__", + "value": "contentions" + }, + { + "name": "__period_unit__", + "value": "count" + }, + { + "name": "__profile_type__", + "value": "block:delay:nanoseconds:contentions:count" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "delay" + }, + { + "name": "__unit__", + "value": "nanoseconds" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "goroutines" + }, + { + "name": "__period_type__", + "value": "goroutine" + }, + { + "name": "__period_unit__", + "value": "count" + }, + { + "name": "__profile_type__", + "value": "goroutines:goroutine:count:goroutine:count" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "goroutine" + }, + { + "name": "__unit__", + "value": "count" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "memory" + }, + { + "name": "__period_type__", + "value": "space" + }, + { + "name": "__period_unit__", + "value": "bytes" + }, + { + "name": "__profile_type__", + "value": "memory:alloc_objects:count:space:bytes" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "alloc_objects" + }, + { + "name": "__unit__", + "value": "count" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "memory" + }, + { + "name": "__period_type__", + "value": "space" + }, + { + "name": "__period_unit__", + "value": "bytes" + }, + { + "name": "__profile_type__", + "value": "memory:alloc_space:bytes:space:bytes" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "alloc_space" + }, + { + "name": "__unit__", + "value": "bytes" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "memory" + }, + { + "name": "__period_type__", + "value": "space" + }, + { + "name": "__period_unit__", + "value": "bytes" + }, + { + "name": "__profile_type__", + "value": "memory:inuse_objects:count:space:bytes" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "inuse_objects" + }, + { + "name": "__unit__", + "value": "count" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "memory" + }, + { + "name": "__period_type__", + "value": "space" + }, + { + "name": "__period_unit__", + "value": "bytes" + }, + { + "name": "__profile_type__", + "value": "memory:inuse_space:bytes:space:bytes" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "inuse_space" + }, + { + "name": "__unit__", + "value": "bytes" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "mutex" + }, + { + "name": "__period_type__", + "value": "contentions" + }, + { + "name": "__period_unit__", + "value": "count" + }, + { + "name": "__profile_type__", + "value": "mutex:contentions:count:contentions:count" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "contentions" + }, + { + "name": "__unit__", + "value": "count" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "mutex" + }, + { + "name": "__period_type__", + "value": "contentions" + }, + { + "name": "__period_unit__", + "value": "count" + }, + { + "name": "__profile_type__", + "value": "mutex:delay:nanoseconds:contentions:count" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "delay" + }, + { + "name": "__unit__", + "value": "nanoseconds" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "process_cpu" + }, + { + "name": "__period_type__", + "value": "cpu" + }, + { + "name": "__period_unit__", + "value": "nanoseconds" + }, + { + "name": "__profile_type__", + "value": "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "cpu" + }, + { + "name": "__unit__", + "value": "nanoseconds" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + }, + { + "labels": [ + { + "name": "__name__", + "value": "process_cpu" + }, + { + "name": "__period_type__", + "value": "cpu" + }, + { + "name": "__period_unit__", + "value": "nanoseconds" + }, + { + "name": "__profile_type__", + "value": "process_cpu:samples:count:cpu:nanoseconds" + }, + { + "name": "__service_name__", + "value": "pyroscope" + }, + { + "name": "__type__", + "value": "samples" + }, + { + "name": "__unit__", + "value": "count" + }, + { + "name": "pyroscope_spy", + "value": "gospy" + }, + { + "name": "service_git_ref", + "value": "6389652c7" + }, + { + "name": "service_name", + "value": "pyroscope" + }, + { + "name": "service_repository", + "value": "https://github.com/grafana/pyroscope" + }, + { + "name": "target", + "value": "all" + } + ] + } + ] +} diff --git a/pkg/querybackend/testdata/fixtures/series_labels_by.json b/pkg/querybackend/testdata/fixtures/series_labels_by.json new file mode 100644 index 0000000000..014f400d63 --- /dev/null +++ b/pkg/querybackend/testdata/fixtures/series_labels_by.json @@ -0,0 +1,142 @@ +{ + "query": { + "label_names": [ + "service_name", + "__profile_type__" + ] + }, + "series_labels": [ + { + "labels": [ + { + "name": "__profile_type__", + "value": "block:contentions:count:contentions:count" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "block:delay:nanoseconds:contentions:count" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "goroutines:goroutine:count:goroutine:count" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "memory:alloc_objects:count:space:bytes" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "memory:alloc_space:bytes:space:bytes" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "memory:inuse_objects:count:space:bytes" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "memory:inuse_space:bytes:space:bytes" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "mutex:contentions:count:contentions:count" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "mutex:delay:nanoseconds:contentions:count" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + }, + { + "labels": [ + { + "name": "__profile_type__", + "value": "process_cpu:samples:count:cpu:nanoseconds" + }, + { + "name": "service_name", + "value": "pyroscope" + } + ] + } + ] +} diff --git a/pkg/querybackend/testdata/fixtures/time_series.json b/pkg/querybackend/testdata/fixtures/time_series.json new file mode 100644 index 0000000000..7912de611e --- /dev/null +++ b/pkg/querybackend/testdata/fixtures/time_series.json @@ -0,0 +1,158 @@ +[ + { + "labels": [ + { + "name": "service_name", + "value": "pyroscope" + } + ], + "points": [ + { + "value": 635460859340, + "timestamp": 1739263359000 + }, + { + "value": 3596227770441, + "timestamp": 1739263389000 + }, + { + "value": 3292115355100, + "timestamp": 1739263419000 + }, + { + "value": 3117194222351, + "timestamp": 1739263449000 + }, + { + "value": 3334880121438, + "timestamp": 1739263479000 + }, + { + "value": 4004142845972, + "timestamp": 1739263509000 + }, + { + "value": 3784707490611, + "timestamp": 1739263539000 + }, + { + "value": 3948517814712, + "timestamp": 1739263569000 + }, + { + "value": 3855556351880, + "timestamp": 1739263599000 + }, + { + "value": 3783064769056, + "timestamp": 1739263629000 + }, + { + "value": 2118809970223, + "timestamp": 1739263659000 + }, + { + "value": 1200000120, + "timestamp": 1739264019000 + }, + { + "value": 4561295991965, + "timestamp": 1739264049000 + }, + { + "value": 3767958932068, + "timestamp": 1739264079000 + }, + { + "value": 3152613326092, + "timestamp": 1739264109000 + }, + { + "value": 4331520617166, + "timestamp": 1739264139000 + }, + { + "value": 3848956851919, + "timestamp": 1739264169000 + }, + { + "value": 3648049166680, + "timestamp": 1739264199000 + } + ] + }, + { + "labels": [ + { + "name": "service_name", + "value": "test-app" + } + ], + "points": [ + { + "value": 349200034920, + "timestamp": 1739263509000 + }, + { + "value": 436500043650, + "timestamp": 1739263539000 + }, + { + "value": 261900026190, + "timestamp": 1739263569000 + }, + { + "value": 261900026190, + "timestamp": 1739263599000 + }, + { + "value": 261900026190, + "timestamp": 1739263629000 + }, + { + "value": 261900026190, + "timestamp": 1739263659000 + }, + { + "value": 261900026190, + "timestamp": 1739263689000 + }, + { + "value": 261900026190, + "timestamp": 1739263719000 + }, + { + "value": 261900026190, + "timestamp": 1739263749000 + }, + { + "value": 261900026190, + "timestamp": 1739263779000 + }, + { + "value": 261900026190, + "timestamp": 1739263809000 + }, + { + "value": 261900026190, + "timestamp": 1739263839000 + }, + { + "value": 261900026190, + "timestamp": 1739263869000 + }, + { + "value": 174600017460, + "timestamp": 1739263899000 + }, + { + "value": 8730000873, + "timestamp": 1739264709000 + }, + { + "value": 17460001746, + "timestamp": 1739264739000 + } + ] + } +] diff --git a/pkg/querybackend/testdata/fixtures/time_series_first_block.json b/pkg/querybackend/testdata/fixtures/time_series_first_block.json new file mode 100644 index 0000000000..8ca003ce2a --- /dev/null +++ b/pkg/querybackend/testdata/fixtures/time_series_first_block.json @@ -0,0 +1,56 @@ +[ + { + "labels": [ + { + "name": "service_name", + "value": "pyroscope" + } + ], + "points": [ + { + "value": 635460859340, + "timestamp": 1739263359000 + }, + { + "value": 3596227770441, + "timestamp": 1739263389000 + }, + { + "value": 3292115355100, + "timestamp": 1739263419000 + }, + { + "value": 3117194222351, + "timestamp": 1739263449000 + }, + { + "value": 3334880121438, + "timestamp": 1739263479000 + }, + { + "value": 4004142845972, + "timestamp": 1739263509000 + }, + { + "value": 3784707490611, + "timestamp": 1739263539000 + }, + { + "value": 3948517814712, + "timestamp": 1739263569000 + }, + { + "value": 3855556351880, + "timestamp": 1739263599000 + }, + { + "value": 3783064769056, + "timestamp": 1739263629000 + }, + { + "value": 2118809970223, + "timestamp": 1739263659000 + } + ] + } +] diff --git a/pkg/querybackend/testdata/fixtures/tree_16.txt b/pkg/querybackend/testdata/fixtures/tree_16.txt new file mode 100644 index 0000000000..82eacb1efa --- /dev/null +++ b/pkg/querybackend/testdata/fixtures/tree_16.txt @@ -0,0 +1,24 @@ +. +├── github.com/grafana/dskit/services.(*BasicService).main: self 0 total 15001402250499 +│ └── other: self 15001402250499 total 15001402250499 +├── github.com/grafana/pyroscope/pkg/experiment/ingester.(*workerPool).run.func1: self 0 total 4711233881080 +│ ├── other: self 1376550158 total 1376550158 +│ └── runtime.chanrecv2: self 4709857330602 total 4709857330922 +│ └── other: self 320 total 320 +├── golang.org/x/net/http2.(*serverConn).runHandler: self 0 total 4279149508270 +│ ├── net/http.HandlerFunc.ServeHTTP: self 0 total 4279148683177 +│ │ └── github.com/opentracing-contrib/go-stdlib/nethttp.MiddlewareFunc.func5: self 0 total 4279148683177 +│ │ └── other: self 4279148683177 total 4279148683177 +│ └── other: self 825093 total 825093 +├── other: self 34790486817285 total 34790486817285 +└── runtime.main: self 0 total 3867390386739 + └── main.main: self 0 total 3867390386739 + └── github.com/pyroscope-io/client/pyroscope.TagWrapper: self 0 total 3867390386739 + └── runtime/pprof.Do: self 0 total 3867390386739 + └── github.com/pyroscope-io/client/pyroscope.TagWrapper.func1: self 0 total 3867390386739 + └── main.main.func2: self 0 total 3867390386739 + ├── main.slowFunction: self 0 total 3083280308328 + │ ├── other: self 93030009303 total 93030009303 + │ └── runtime/pprof.Do: self 0 total 2990250299025 + │ └── other: self 2990250299025 total 2990250299025 + └── other: self 784110078411 total 784110078411 diff --git a/pkg/querybackend/testdata/fixtures/tree_16_slow.txt b/pkg/querybackend/testdata/fixtures/tree_16_slow.txt new file mode 100644 index 0000000000..63a318770a --- /dev/null +++ b/pkg/querybackend/testdata/fixtures/tree_16_slow.txt @@ -0,0 +1,12 @@ +. +└── runtime.main: self 0 total 2985820298582 + └── main.main: self 0 total 2985820298582 + └── github.com/pyroscope-io/client/pyroscope.TagWrapper: self 0 total 2985820298582 + └── runtime/pprof.Do: self 0 total 2985820298582 + └── github.com/pyroscope-io/client/pyroscope.TagWrapper.func1: self 0 total 2985820298582 + └── main.main.func2: self 0 total 2985820298582 + └── main.slowFunction: self 0 total 2985820298582 + └── runtime/pprof.Do: self 0 total 2985820298582 + └── main.slowFunction.func1: self 0 total 2985820298582 + └── main.work: self 2875070287507 total 2985820298582 + └── runtime.asyncPreempt: self 110750011075 total 110750011075 diff --git a/pkg/querybackend/testdata/samples/01JKT2S01VXGG0YS6TG8QC2JWD/block.bin b/pkg/querybackend/testdata/samples/01JKT2S01VXGG0YS6TG8QC2JWD/block.bin new file mode 100644 index 0000000000..4e51c0ce03 Binary files /dev/null and b/pkg/querybackend/testdata/samples/01JKT2S01VXGG0YS6TG8QC2JWD/block.bin differ diff --git a/pkg/querybackend/testdata/samples/01JKT2XEGT4VA4HHR0EC8668MM/block.bin b/pkg/querybackend/testdata/samples/01JKT2XEGT4VA4HHR0EC8668MM/block.bin new file mode 100644 index 0000000000..17ae23ff18 Binary files /dev/null and b/pkg/querybackend/testdata/samples/01JKT2XEGT4VA4HHR0EC8668MM/block.bin differ diff --git a/pkg/querybackend/testdata/samples/01JKT2XEGT9M0S3P8Y8Q3E7SQ2/block.bin b/pkg/querybackend/testdata/samples/01JKT2XEGT9M0S3P8Y8Q3E7SQ2/block.bin new file mode 100644 index 0000000000..350cbc1641 Binary files /dev/null and b/pkg/querybackend/testdata/samples/01JKT2XEGT9M0S3P8Y8Q3E7SQ2/block.bin differ diff --git a/pkg/querybackend/testdata/samples/01JKT3DJRETWN25NKEFZNEP1V0/block.bin b/pkg/querybackend/testdata/samples/01JKT3DJRETWN25NKEFZNEP1V0/block.bin new file mode 100644 index 0000000000..9a8b720b1c Binary files /dev/null and b/pkg/querybackend/testdata/samples/01JKT3DJRETWN25NKEFZNEP1V0/block.bin differ diff --git a/pkg/querybackend/testdata/samples/01JKT426996H1XWCX1M1ZQFRJ6/block.bin b/pkg/querybackend/testdata/samples/01JKT426996H1XWCX1M1ZQFRJ6/block.bin new file mode 100644 index 0000000000..5225ef84c9 Binary files /dev/null and b/pkg/querybackend/testdata/samples/01JKT426996H1XWCX1M1ZQFRJ6/block.bin differ diff --git a/pkg/querybackend/testdata/samples/01JKT4333784C9PCQ6VM8VNAWC/block.bin b/pkg/querybackend/testdata/samples/01JKT4333784C9PCQ6VM8VNAWC/block.bin new file mode 100644 index 0000000000..c0f8e89d01 Binary files /dev/null and b/pkg/querybackend/testdata/samples/01JKT4333784C9PCQ6VM8VNAWC/block.bin differ diff --git a/pkg/scheduler/queue/queue.go b/pkg/scheduler/queue/queue.go index 83c40fa69c..c746dea870 100644 --- a/pkg/scheduler/queue/queue.go +++ b/pkg/scheduler/queue/queue.go @@ -7,11 +7,11 @@ package queue import ( "context" + "errors" "sync" "time" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "go.uber.org/atomic" ) diff --git a/pkg/scheduler/queue/queue_test.go b/pkg/scheduler/queue/queue_test.go index 1653d51a41..b7a6f3840f 100644 --- a/pkg/scheduler/queue/queue_test.go +++ b/pkg/scheduler/queue/queue_test.go @@ -294,7 +294,7 @@ func assertChanReceived(t *testing.T, c chan struct{}, timeout time.Duration, ms select { case <-c: case <-time.After(timeout): - t.Fatalf(msg) + t.Fatalf("%s", msg) } } @@ -303,7 +303,7 @@ func assertChanNotReceived(t *testing.T, c chan struct{}, wait time.Duration, ms select { case <-c: - t.Fatalf(msg) + t.Fatal(msg) case <-time.After(wait): // OK! } diff --git a/pkg/scheduler/queue/user_queues.go b/pkg/scheduler/queue/user_queues.go index 918bdb19e7..6b4821175d 100644 --- a/pkg/scheduler/queue/user_queues.go +++ b/pkg/scheduler/queue/user_queues.go @@ -11,7 +11,7 @@ import ( "sort" "time" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) // querier holds information about a querier registered in the queue. diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go index 309401b2b9..64b35c64fb 100644 --- a/pkg/scheduler/scheduler.go +++ b/pkg/scheduler/scheduler.go @@ -7,7 +7,9 @@ package scheduler import ( "context" + "errors" "flag" + "fmt" "io" "net/http" "sync" @@ -21,22 +23,22 @@ import ( "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" "github.com/grafana/dskit/tenant" + "github.com/grafana/dskit/tracing" "github.com/grafana/dskit/user" - otgrpc "github.com/opentracing-contrib/go-grpc" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" - "github.com/grafana/pyroscope/pkg/frontend/frontendpb" - "github.com/grafana/pyroscope/pkg/scheduler/queue" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerdiscovery" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" - "github.com/grafana/pyroscope/pkg/util/httpgrpcutil" - "github.com/grafana/pyroscope/pkg/util/validation" + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb" + "github.com/grafana/pyroscope/v2/pkg/scheduler/queue" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerdiscovery" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb" + "github.com/grafana/pyroscope/v2/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpcutil" + "github.com/grafana/pyroscope/v2/pkg/util/validation" ) // Scheduler is responsible for queueing and dispatching queries to Queriers. @@ -97,6 +99,10 @@ type Config struct { QuerierForgetDelay time.Duration `yaml:"querier_forget_delay" category:"experimental"` GRPCClientConfig grpcclient.Config `yaml:"grpc_client_config" doc:"description=This configures the gRPC client used to report errors back to the query-frontend."` ServiceDiscovery schedulerdiscovery.Config `yaml:",inline"` + + // Dial options used to initiate outgoing gRPC connections. + // Intended to be used by tests to use in-memory network connections. + DialOpts []grpc.DialOption `yaml:"-"` } func (cfg *Config) RegisterFlags(f *flag.FlagSet, logger log.Logger) { @@ -140,9 +146,12 @@ func NewScheduler(cfg Config, limits Limits, log log.Logger, registerer promethe s.requestQueue = queue.NewRequestQueue(cfg.MaxOutstandingPerTenant, cfg.QuerierForgetDelay, s.queueLength, s.discardedRequests) s.queueDuration = promauto.With(registerer).NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_query_scheduler_queue_duration_seconds", - Help: "Time spend by requests in queue before getting picked up by a querier.", - Buckets: prometheus.DefBuckets, + Name: "pyroscope_query_scheduler_queue_duration_seconds", + Help: "Time spend by requests in queue before getting picked up by a querier.", + Buckets: prometheus.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }) s.connectedQuerierClients = promauto.With(registerer).NewGaugeFunc(prometheus.GaugeOpts{ Name: "pyroscope_query_scheduler_connected_querier_clients", @@ -200,10 +209,10 @@ type schedulerRequest struct { ctx context.Context ctxCancel context.CancelFunc - queueSpan opentracing.Span + queueSpan *tracing.Span // This is only used for testing. - parentSpanContext opentracing.SpanContext + parentCtx context.Context } // FrontendLoop handles connection from frontend. @@ -320,11 +329,7 @@ func (s *Scheduler) enqueueRequest(frontendContext context.Context, frontendAddr // Extract tracing information from headers in HTTP request. FrontendContext doesn't have the correct tracing // information, since that is a long-running request. - tracer := opentracing.GlobalTracer() - parentSpanContext, err := httpgrpcutil.GetParentSpanForRequest(tracer, msg.HttpRequest) - if err != nil { - return err - } + tracedCtx := httpgrpcutil.GetParentContextForRequest(ctx, msg.HttpRequest) userID := msg.GetUserID() @@ -338,8 +343,8 @@ func (s *Scheduler) enqueueRequest(frontendContext context.Context, frontendAddr now := time.Now() - req.parentSpanContext = parentSpanContext - req.queueSpan, req.ctx = opentracing.StartSpanFromContextWithTracer(ctx, tracer, "queued", opentracing.ChildOf(parentSpanContext)) + req.parentCtx = tracedCtx + req.queueSpan, req.ctx = tracing.StartSpanFromContext(tracedCtx, "queued") req.enqueueTime = now req.ctxCancel = cancel @@ -527,15 +532,16 @@ func (s *Scheduler) forwardRequestToQuerier(querier *BidiStreamCloser[schedulerp func (s *Scheduler) forwardErrorToFrontend(ctx context.Context, req *schedulerRequest, requestErr error) { opts, err := s.cfg.GRPCClientConfig.DialOption([]grpc.UnaryClientInterceptor{ - otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer()), middleware.ClientUserHeaderInterceptor, }, - nil) + nil, nil) if err != nil { level.Warn(s.log).Log("msg", "failed to create gRPC options for the connection to frontend to report error", "frontend", req.frontendAddress, "err", err, "requestErr", requestErr) return } + opts = append(opts, grpc.WithStatsHandler(otelgrpc.NewClientHandler())) + opts = append(opts, s.cfg.DialOpts...) conn, err := grpc.DialContext(ctx, req.frontendAddress, opts...) if err != nil { level.Warn(s.log).Log("msg", "failed to create gRPC connection to frontend to report error", "frontend", req.frontendAddress, "err", err, "requestErr", requestErr) @@ -577,7 +583,7 @@ func (s *Scheduler) starting(ctx context.Context) error { s.subservicesWatcher.WatchManager(s.subservices) if err := services.StartManagerAndAwaitHealthy(ctx, s.subservices); err != nil { - return errors.Wrap(err, "unable to start scheduler subservices") + return fmt.Errorf("unable to start scheduler subservices: %w", err) } return nil @@ -602,7 +608,7 @@ func (s *Scheduler) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-s.subservicesWatcher.Chan(): - return errors.Wrap(err, "scheduler subservice failed") + return fmt.Errorf("scheduler subservice failed: %w", err) } } } @@ -649,5 +655,5 @@ func (s *Scheduler) RingHandler(w http.ResponseWriter, req *http.Request) {

    Query-scheduler hash ring is disabled.

    ` - util.WriteHTMLResponse(w, ringDisabledPage) + httputil.WriteHTMLResponse(w, ringDisabledPage) } diff --git a/pkg/scheduler/scheduler_test.go b/pkg/scheduler/scheduler_test.go index 32f484a92b..0dad998dd1 100644 --- a/pkg/scheduler/scheduler_test.go +++ b/pkg/scheduler/scheduler_test.go @@ -12,7 +12,6 @@ import ( "net" "net/http" "net/http/httptest" - "net/url" "strings" "sync" "testing" @@ -24,42 +23,53 @@ import ( "github.com/grafana/dskit/flagext" "github.com/grafana/dskit/services" "github.com/grafana/dskit/test" - "github.com/opentracing/opentracing-go" + "github.com/grafana/dskit/tracing" "github.com/prometheus/client_golang/prometheus" promtest "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" - "github.com/uber/jaeger-client-go/config" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - - "github.com/grafana/pyroscope/pkg/frontend/frontendpb" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb" - "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb/schedulerpbconnect" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" - "github.com/grafana/pyroscope/pkg/util/httpgrpcutil" + "google.golang.org/grpc/test/bufconn" + + "github.com/grafana/pyroscope/v2/pkg/frontend/frontendpb" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb" + "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb/schedulerpbconnect" + "github.com/grafana/pyroscope/v2/pkg/util" + httpserver "github.com/grafana/pyroscope/v2/pkg/util/http/server" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpcutil" ) const testMaxOutstandingPerTenant = 5 -func setupScheduler(t *testing.T, reg prometheus.Registerer, opts ...connect.HandlerOption) (*Scheduler, schedulerpb.SchedulerForFrontendClient, schedulerpb.SchedulerForQuerierClient) { - cfg := Config{} +type schedulerArgs struct { + reg prometheus.Registerer + handlerOpts []connect.HandlerOption + dialOpts []grpc.DialOption +} + +func setupScheduler(t *testing.T, args schedulerArgs) (*Scheduler, schedulerpb.SchedulerForFrontendClient, schedulerpb.SchedulerForQuerierClient) { + cfg := Config{ + DialOpts: args.dialOpts, + } flagext.DefaultValues(&cfg) cfg.MaxOutstandingPerTenant = testMaxOutstandingPerTenant - s, err := NewScheduler(cfg, &limits{queriers: 2}, log.NewNopLogger(), reg) + s, err := NewScheduler(cfg, &limits{queriers: 2}, log.NewNopLogger(), args.reg) + require.NoError(t, err) - server := httptest.NewUnstartedServer(nil) mux := mux.NewRouter() - server.Config.Handler = h2c.NewHandler(mux, &http2.Server{}) + server := httptest.NewUnstartedServer(mux) + httpserver.EnableHTTP2(server.Config) + server.Start() - u, err := url.Parse(server.URL) - require.NoError(t, err) - schedulerpbconnect.RegisterSchedulerForFrontendHandler(mux, s, opts...) - schedulerpbconnect.RegisterSchedulerForQuerierHandler(mux, s, opts...) + schedulerpbconnect.RegisterSchedulerForFrontendHandler(mux, s, args.handlerOpts...) + schedulerpbconnect.RegisterSchedulerForQuerierHandler(mux, s, args.handlerOpts...) require.NoError(t, services.StartAndAwaitRunning(context.Background(), s)) t.Cleanup(func() { @@ -67,7 +77,11 @@ func setupScheduler(t *testing.T, reg prometheus.Registerer, opts ...connect.Han server.Close() }) - c, err := grpc.Dial(u.Hostname()+":"+u.Port(), grpc.WithTransportCredentials(insecure.NewCredentials())) + c, err := grpc.NewClient( + server.Listener.Addr().String(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + require.NoError(t, err) t.Cleanup(func() { @@ -77,9 +91,14 @@ func setupScheduler(t *testing.T, reg prometheus.Registerer, opts ...connect.Han return s, schedulerpb.NewSchedulerForFrontendClient(c), schedulerpb.NewSchedulerForQuerierClient(c) } -func Test_Timeout(t *testing.T) { - s, _, querierClient := setupScheduler(t, nil, connect.WithInterceptors(util.WithTimeout(1*time.Second))) +func setupSchedulerWithHandlerOpts(t *testing.T, handlerOpts ...connect.HandlerOption) (*Scheduler, schedulerpb.SchedulerForFrontendClient, schedulerpb.SchedulerForQuerierClient) { + return setupScheduler(t, schedulerArgs{ + handlerOpts: handlerOpts, + }) +} +func Test_Timeout(t *testing.T) { + s, _, querierClient := setupSchedulerWithHandlerOpts(t, connect.WithInterceptors(util.WithTimeout(1*time.Second))) ql, err := querierClient.QuerierLoop(context.Background()) require.NoError(t, err) require.NoError(t, ql.Send(&schedulerpb.QuerierToScheduler{QuerierID: "querier-1"})) @@ -88,7 +107,7 @@ func Test_Timeout(t *testing.T) { } func TestSchedulerBasicEnqueue(t *testing.T) { - scheduler, frontendClient, querierClient := setupScheduler(t, nil) + scheduler, frontendClient, querierClient := setupScheduler(t, schedulerArgs{}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") frontendToScheduler(t, frontendLoop, &schedulerpb.FrontendToScheduler{ @@ -116,7 +135,7 @@ func TestSchedulerBasicEnqueue(t *testing.T) { } func TestSchedulerEnqueueWithCancel(t *testing.T) { - scheduler, frontendClient, querierClient := setupScheduler(t, nil) + scheduler, frontendClient, querierClient := setupScheduler(t, schedulerArgs{}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") frontendToScheduler(t, frontendLoop, &schedulerpb.FrontendToScheduler{ @@ -146,7 +165,7 @@ func initQuerierLoop(t *testing.T, querierClient schedulerpb.SchedulerForQuerier } func TestSchedulerEnqueueByMultipleFrontendsWithCancel(t *testing.T) { - scheduler, frontendClient, querierClient := setupScheduler(t, nil) + scheduler, frontendClient, querierClient := setupScheduler(t, schedulerArgs{}) frontendLoop1 := initFrontendLoop(t, frontendClient, "frontend-1") frontendLoop2 := initFrontendLoop(t, frontendClient, "frontend-2") @@ -187,7 +206,7 @@ func TestSchedulerEnqueueByMultipleFrontendsWithCancel(t *testing.T) { } func TestSchedulerEnqueueWithFrontendDisconnect(t *testing.T) { - scheduler, frontendClient, querierClient := setupScheduler(t, nil) + scheduler, frontendClient, querierClient := setupScheduler(t, schedulerArgs{}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") frontendToScheduler(t, frontendLoop, &schedulerpb.FrontendToScheduler{ @@ -217,7 +236,7 @@ func TestSchedulerEnqueueWithFrontendDisconnect(t *testing.T) { } func TestCancelRequestInProgress(t *testing.T) { - scheduler, frontendClient, querierClient := setupScheduler(t, nil) + scheduler, frontendClient, querierClient := setupScheduler(t, schedulerArgs{}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") frontendToScheduler(t, frontendLoop, &schedulerpb.FrontendToScheduler{ @@ -238,8 +257,12 @@ func TestCancelRequestInProgress(t *testing.T) { // Simulate frontend disconnect. require.NoError(t, frontendLoop.CloseSend()) - // Add a little sleep to make sure that scheduler notices frontend disconnect. - time.Sleep(500 * time.Millisecond) + // Wait until the scheduler notices the frontend disconnect before sending + // a response. If we send too early, it completes the normal request cycle + // in forwardRequestToQuerier and the context cancellation is never triggered. + test.Poll(t, time.Second, float64(0), func() interface{} { + return promtest.ToFloat64(scheduler.connectedFrontendClients) + }) // Report back end of request processing. This should return error, since the QuerierLoop call has finished on scheduler. // Note: testing on querierLoop.Context() cancellation didn't work :( @@ -249,13 +272,14 @@ func TestCancelRequestInProgress(t *testing.T) { } func TestTracingContext(t *testing.T) { - scheduler, frontendClient, _ := setupScheduler(t, nil) + scheduler, frontendClient, _ := setupScheduler(t, schedulerArgs{}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") - closer, err := config.Configuration{}.InitGlobalTracer("test") - require.NoError(t, err) - defer closer.Close() + tp := sdktrace.NewTracerProvider() + defer func() { _ = tp.Shutdown(context.Background()) }() + otel.SetTracerProvider(tp) + otel.SetTextMapPropagator(propagation.TraceContext{}) req := &schedulerpb.FrontendToScheduler{ Type: schedulerpb.FrontendToSchedulerType_ENQUEUE, @@ -265,8 +289,10 @@ func TestTracingContext(t *testing.T) { FrontendAddress: "frontend-12345", } - sp, _ := opentracing.StartSpanFromContext(context.Background(), "client") - _ = opentracing.GlobalTracer().Inject(sp.Context(), opentracing.HTTPHeaders, (*httpgrpcutil.HttpgrpcHeadersCarrier)(req.HttpRequest)) + sp, ctx := tracing.StartSpanFromContext(context.Background(), "test") + defer sp.Finish() + carrier := (*httpgrpcutil.HttpgrpcHeadersCarrier)(req.HttpRequest) + otel.GetTextMapPropagator().Inject(ctx, carrier) frontendToScheduler(t, frontendLoop, req) @@ -275,12 +301,12 @@ func TestTracingContext(t *testing.T) { require.Equal(t, 1, len(scheduler.pendingRequests)) for _, r := range scheduler.pendingRequests { - require.NotNil(t, r.parentSpanContext) + require.True(t, trace.SpanFromContext(r.parentCtx).SpanContext().IsValid()) } } func TestSchedulerShutdown_FrontendLoop(t *testing.T) { - scheduler, frontendClient, _ := setupScheduler(t, nil) + scheduler, frontendClient, _ := setupScheduler(t, schedulerArgs{}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") @@ -301,7 +327,7 @@ func TestSchedulerShutdown_FrontendLoop(t *testing.T) { } func TestSchedulerShutdown_QuerierLoop(t *testing.T) { - scheduler, frontendClient, querierClient := setupScheduler(t, nil) + scheduler, frontendClient, querierClient := setupScheduler(t, schedulerArgs{}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") frontendToScheduler(t, frontendLoop, &schedulerpb.FrontendToScheduler{ @@ -333,7 +359,7 @@ func TestSchedulerShutdown_QuerierLoop(t *testing.T) { } func TestSchedulerMaxOutstandingRequests(t *testing.T) { - _, frontendClient, _ := setupScheduler(t, nil) + _, frontendClient, _ := setupScheduler(t, schedulerArgs{}) for i := 0; i < testMaxOutstandingPerTenant; i++ { // coming from different frontends @@ -365,32 +391,32 @@ func TestSchedulerMaxOutstandingRequests(t *testing.T) { } func TestSchedulerForwardsErrorToFrontend(t *testing.T) { - _, frontendClient, querierClient := setupScheduler(t, nil) + + l := bufconn.Listen(256 << 10) + _, frontendClient, querierClient := setupScheduler(t, schedulerArgs{ + // Have the scheduler use the in-memory connection to call back into the frontend. + dialOpts: []grpc.DialOption{ + grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return l.Dial() }), + }, + }) fm := &frontendMock{resp: map[uint64]*httpgrpc.HTTPResponse{}} - frontendAddress := "" // Setup frontend grpc server { frontendGrpcServer := grpc.NewServer() frontendpb.RegisterFrontendForQuerierServer(frontendGrpcServer, fm) - l, err := net.Listen("tcp", "127.0.0.1:") - require.NoError(t, err) - - frontendAddress = l.Addr().String() - go func() { _ = frontendGrpcServer.Serve(l) }() - t.Cleanup(func() { _ = l.Close() }) } // After preparations, start frontend and querier. - frontendLoop := initFrontendLoop(t, frontendClient, frontendAddress) + frontendLoop := initFrontendLoop(t, frontendClient, "irrelevant://because-we-use-in-memory-connection") frontendToScheduler(t, frontendLoop, &schedulerpb.FrontendToScheduler{ Type: schedulerpb.FrontendToSchedulerType_ENQUEUE, QueryID: 100, @@ -427,7 +453,7 @@ func TestSchedulerForwardsErrorToFrontend(t *testing.T) { func TestSchedulerMetrics(t *testing.T) { reg := prometheus.NewPedanticRegistry() - scheduler, frontendClient, _ := setupScheduler(t, reg) + scheduler, frontendClient, _ := setupScheduler(t, schedulerArgs{reg: reg}) frontendLoop := initFrontendLoop(t, frontendClient, "frontend-12345") frontendToScheduler(t, frontendLoop, &schedulerpb.FrontendToScheduler{ diff --git a/pkg/scheduler/schedulerdiscovery/config.go b/pkg/scheduler/schedulerdiscovery/config.go index 399255b64e..c23c6855ec 100644 --- a/pkg/scheduler/schedulerdiscovery/config.go +++ b/pkg/scheduler/schedulerdiscovery/config.go @@ -10,7 +10,7 @@ import ( "github.com/go-kit/log" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( diff --git a/pkg/scheduler/schedulerdiscovery/discovery.go b/pkg/scheduler/schedulerdiscovery/discovery.go index 9680f07131..07a1464d8d 100644 --- a/pkg/scheduler/schedulerdiscovery/discovery.go +++ b/pkg/scheduler/schedulerdiscovery/discovery.go @@ -9,7 +9,7 @@ import ( "github.com/grafana/dskit/services" "github.com/prometheus/client_golang/prometheus" - "github.com/grafana/pyroscope/pkg/util/servicediscovery" + "github.com/grafana/pyroscope/v2/pkg/util/servicediscovery" ) func New(cfg Config, schedulerAddress string, lookupPeriod time.Duration, component string, receiver servicediscovery.Notifications, logger log.Logger, reg prometheus.Registerer) (services.Service, error) { diff --git a/pkg/scheduler/schedulerdiscovery/ring.go b/pkg/scheduler/schedulerdiscovery/ring.go index 68fee4cb05..043501bb6d 100644 --- a/pkg/scheduler/schedulerdiscovery/ring.go +++ b/pkg/scheduler/schedulerdiscovery/ring.go @@ -4,14 +4,15 @@ package schedulerdiscovery import ( "fmt" + "net" + "strconv" "github.com/go-kit/log" "github.com/grafana/dskit/kv" "github.com/grafana/dskit/ring" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -33,7 +34,7 @@ const ( // toBasicLifecyclerConfig returns a ring.BasicLifecyclerConfig based on the query-scheduler ring config. func toBasicLifecyclerConfig(cfg util.CommonRingConfig, logger log.Logger) (ring.BasicLifecyclerConfig, error) { - instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger, false) + instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger, cfg.EnableIPv6) if err != nil { return ring.BasicLifecyclerConfig{}, err } @@ -42,7 +43,7 @@ func toBasicLifecyclerConfig(cfg util.CommonRingConfig, logger log.Logger) (ring return ring.BasicLifecyclerConfig{ ID: cfg.InstanceID, - Addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), + Addr: net.JoinHostPort(instanceAddr, strconv.Itoa(instancePort)), HeartbeatPeriod: cfg.HeartbeatPeriod, HeartbeatTimeout: cfg.HeartbeatTimeout, TokensObservePeriod: 0, @@ -56,12 +57,12 @@ func NewRingLifecycler(cfg util.CommonRingConfig, logger log.Logger, reg prometh reg = prometheus.WrapRegistererWithPrefix("pyroscope_", reg) kvStore, err := kv.NewClient(cfg.KVStore, ring.GetCodec(), kv.RegistererWithKVName(reg, "query-scheduler-lifecycler"), logger) if err != nil { - return nil, errors.Wrap(err, "failed to initialize query-schedulers' KV store") + return nil, fmt.Errorf("failed to initialize query-schedulers' KV store: %w", err) } lifecyclerCfg, err := toBasicLifecyclerConfig(cfg, logger) if err != nil { - return nil, errors.Wrap(err, "failed to build query-schedulers' lifecycler config") + return nil, fmt.Errorf("failed to build query-schedulers' lifecycler config: %w", err) } var delegate ring.BasicLifecyclerDelegate @@ -71,7 +72,7 @@ func NewRingLifecycler(cfg util.CommonRingConfig, logger log.Logger, reg prometh lifecycler, err := ring.NewBasicLifecycler(lifecyclerCfg, "query-scheduler", ringKey, kvStore, delegate, logger, reg) if err != nil { - return nil, errors.Wrap(err, "failed to initialize query-schedulers' lifecycler") + return nil, fmt.Errorf("failed to initialize query-schedulers' lifecycler: %w", err) } return lifecycler, nil @@ -81,7 +82,7 @@ func NewRingLifecycler(cfg util.CommonRingConfig, logger log.Logger, reg prometh func NewRingClient(cfg util.CommonRingConfig, component string, logger log.Logger, reg prometheus.Registerer) (*ring.Ring, error) { client, err := ring.New(cfg.ToRingConfig(), component, ringKey, logger, prometheus.WrapRegistererWithPrefix("pyroscope_", reg)) if err != nil { - return nil, errors.Wrap(err, "failed to initialize query-schedulers' ring client") + return nil, fmt.Errorf("failed to initialize query-schedulers' ring client: %w", err) } return client, err diff --git a/pkg/scheduler/schedulerdiscovery/ring_test.go b/pkg/scheduler/schedulerdiscovery/ring_test.go index 389638af04..4353ddf842 100644 --- a/pkg/scheduler/schedulerdiscovery/ring_test.go +++ b/pkg/scheduler/schedulerdiscovery/ring_test.go @@ -3,7 +3,8 @@ package schedulerdiscovery import ( - "fmt" + "net" + "strconv" "testing" "time" @@ -22,7 +23,7 @@ func TestRingConfig_DefaultConfigToBasicLifecyclerConfig(t *testing.T) { expected := ring.BasicLifecyclerConfig{ ID: cfg.SchedulerRing.InstanceID, - Addr: fmt.Sprintf("%s:%d", cfg.SchedulerRing.InstanceAddr, cfg.SchedulerRing.InstancePort), + Addr: net.JoinHostPort(cfg.SchedulerRing.InstanceAddr, strconv.Itoa(cfg.SchedulerRing.InstancePort)), HeartbeatPeriod: cfg.SchedulerRing.HeartbeatPeriod, HeartbeatTimeout: cfg.SchedulerRing.HeartbeatTimeout, TokensObservePeriod: 0, @@ -50,7 +51,7 @@ func TestRingConfig_CustomConfigToBasicLifecyclerConfig(t *testing.T) { // ring config expected := ring.BasicLifecyclerConfig{ ID: "test", - Addr: "1.2.3.4:10", + Addr: net.JoinHostPort(cfg.SchedulerRing.InstanceAddr, strconv.Itoa(cfg.SchedulerRing.InstancePort)), HeartbeatPeriod: 1 * time.Second, HeartbeatTimeout: 10 * time.Second, TokensObservePeriod: 0, @@ -62,3 +63,25 @@ func TestRingConfig_CustomConfigToBasicLifecyclerConfig(t *testing.T) { require.NoError(t, err) assert.Equal(t, expected, actual) } + +func TestRingConfig_AddressFamilies(t *testing.T) { + cfg := Config{} + flagext.DefaultValues(&cfg) + + t.Run("IPv4", func(t *testing.T) { + cfg.SchedulerRing.InstanceAddr = "1.2.3.4" + cfg.SchedulerRing.InstancePort = 10 + actual, err := toBasicLifecyclerConfig(cfg.SchedulerRing, log.NewNopLogger()) + require.NoError(t, err) + assert.Equal(t, "1.2.3.4:10", actual.Addr) + }) + + t.Run("IPv6", func(t *testing.T) { + cfg.SchedulerRing.InstanceAddr = "::1" + cfg.SchedulerRing.InstancePort = 10 + cfg.SchedulerRing.EnableIPv6 = true + actual, err := toBasicLifecyclerConfig(cfg.SchedulerRing, log.NewNopLogger()) + require.NoError(t, err) + assert.Equal(t, "[::1]:10", actual.Addr) + }) +} diff --git a/pkg/scheduler/schedulerpb/custom.go b/pkg/scheduler/schedulerpb/custom.go index b8535bb794..5de74eca87 100644 --- a/pkg/scheduler/schedulerpb/custom.go +++ b/pkg/scheduler/schedulerpb/custom.go @@ -2,7 +2,7 @@ package schedulerpb -import "github.com/pkg/errors" +import "errors" var ( ErrSchedulerIsNotRunning = errors.New("scheduler is not running") diff --git a/pkg/scheduler/schedulerpb/scheduler.pb.go b/pkg/scheduler/schedulerpb/scheduler.pb.go index e717d927cf..4faec5e3ee 100644 --- a/pkg/scheduler/schedulerpb/scheduler.pb.go +++ b/pkg/scheduler/schedulerpb/scheduler.pb.go @@ -5,18 +5,19 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: scheduler/schedulerpb/scheduler.proto package schedulerpb import ( - httpgrpc "github.com/grafana/pyroscope/pkg/util/httpgrpc" + httpgrpc "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -130,20 +131,17 @@ func (SchedulerToFrontendStatus) EnumDescriptor() ([]byte, []int) { // Querier reports its own clientID when it connects, so that scheduler knows how many *different* queriers are connected. // To signal that querier is ready to accept another request, querier sends empty message. type QuerierToScheduler struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + QuerierID string `protobuf:"bytes,1,opt,name=querierID,proto3" json:"querierID,omitempty"` unknownFields protoimpl.UnknownFields - - QuerierID string `protobuf:"bytes,1,opt,name=querierID,proto3" json:"querierID,omitempty"` + sizeCache protoimpl.SizeCache } func (x *QuerierToScheduler) Reset() { *x = QuerierToScheduler{} - if protoimpl.UnsafeEnabled { - mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *QuerierToScheduler) String() string { @@ -154,7 +152,7 @@ func (*QuerierToScheduler) ProtoMessage() {} func (x *QuerierToScheduler) ProtoReflect() protoreflect.Message { mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -177,10 +175,7 @@ func (x *QuerierToScheduler) GetQuerierID() string { } type SchedulerToQuerier struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Query ID as reported by frontend. When querier sends the response back to frontend (using frontendAddress), // it identifies the query by using this ID. QueryID uint64 `protobuf:"varint,1,opt,name=queryID,proto3" json:"queryID,omitempty"` @@ -191,16 +186,16 @@ type SchedulerToQuerier struct { UserID string `protobuf:"bytes,4,opt,name=userID,proto3" json:"userID,omitempty"` // Whether query statistics tracking should be enabled. The response will include // statistics only when this option is enabled. - StatsEnabled bool `protobuf:"varint,5,opt,name=statsEnabled,proto3" json:"statsEnabled,omitempty"` + StatsEnabled bool `protobuf:"varint,5,opt,name=statsEnabled,proto3" json:"statsEnabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SchedulerToQuerier) Reset() { *x = SchedulerToQuerier{} - if protoimpl.UnsafeEnabled { - mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SchedulerToQuerier) String() string { @@ -211,7 +206,7 @@ func (*SchedulerToQuerier) ProtoMessage() {} func (x *SchedulerToQuerier) ProtoReflect() protoreflect.Message { mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -262,29 +257,26 @@ func (x *SchedulerToQuerier) GetStatsEnabled() bool { } type FrontendToScheduler struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Type FrontendToSchedulerType `protobuf:"varint,1,opt,name=type,proto3,enum=schedulerpb.FrontendToSchedulerType" json:"type,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Type FrontendToSchedulerType `protobuf:"varint,1,opt,name=type,proto3,enum=schedulerpb.FrontendToSchedulerType" json:"type,omitempty"` // Used by INIT message. Will be put into all requests passed to querier. FrontendAddress string `protobuf:"bytes,2,opt,name=frontendAddress,proto3" json:"frontendAddress,omitempty"` // Used by ENQUEUE and CANCEL. // Each frontend manages its own queryIDs. Different frontends may use same set of query IDs. QueryID uint64 `protobuf:"varint,3,opt,name=queryID,proto3" json:"queryID,omitempty"` // Following are used by ENQUEUE only. - UserID string `protobuf:"bytes,4,opt,name=userID,proto3" json:"userID,omitempty"` - HttpRequest *httpgrpc.HTTPRequest `protobuf:"bytes,5,opt,name=httpRequest,proto3" json:"httpRequest,omitempty"` - StatsEnabled bool `protobuf:"varint,6,opt,name=statsEnabled,proto3" json:"statsEnabled,omitempty"` + UserID string `protobuf:"bytes,4,opt,name=userID,proto3" json:"userID,omitempty"` + HttpRequest *httpgrpc.HTTPRequest `protobuf:"bytes,5,opt,name=httpRequest,proto3" json:"httpRequest,omitempty"` + StatsEnabled bool `protobuf:"varint,6,opt,name=statsEnabled,proto3" json:"statsEnabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FrontendToScheduler) Reset() { *x = FrontendToScheduler{} - if protoimpl.UnsafeEnabled { - mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FrontendToScheduler) String() string { @@ -295,7 +287,7 @@ func (*FrontendToScheduler) ProtoMessage() {} func (x *FrontendToScheduler) ProtoReflect() protoreflect.Message { mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -353,21 +345,18 @@ func (x *FrontendToScheduler) GetStatsEnabled() bool { } type SchedulerToFrontend struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Status SchedulerToFrontendStatus `protobuf:"varint,1,opt,name=status,proto3,enum=schedulerpb.SchedulerToFrontendStatus" json:"status,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` unknownFields protoimpl.UnknownFields - - Status SchedulerToFrontendStatus `protobuf:"varint,1,opt,name=status,proto3,enum=schedulerpb.SchedulerToFrontendStatus" json:"status,omitempty"` - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SchedulerToFrontend) Reset() { *x = SchedulerToFrontend{} - if protoimpl.UnsafeEnabled { - mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SchedulerToFrontend) String() string { @@ -378,7 +367,7 @@ func (*SchedulerToFrontend) ProtoMessage() {} func (x *SchedulerToFrontend) ProtoReflect() protoreflect.Message { mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -408,20 +397,17 @@ func (x *SchedulerToFrontend) GetError() string { } type NotifyQuerierShutdownRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + QuerierID string `protobuf:"bytes,1,opt,name=querierID,proto3" json:"querierID,omitempty"` unknownFields protoimpl.UnknownFields - - QuerierID string `protobuf:"bytes,1,opt,name=querierID,proto3" json:"querierID,omitempty"` + sizeCache protoimpl.SizeCache } func (x *NotifyQuerierShutdownRequest) Reset() { *x = NotifyQuerierShutdownRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *NotifyQuerierShutdownRequest) String() string { @@ -432,7 +418,7 @@ func (*NotifyQuerierShutdownRequest) ProtoMessage() {} func (x *NotifyQuerierShutdownRequest) ProtoReflect() protoreflect.Message { mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -455,18 +441,16 @@ func (x *NotifyQuerierShutdownRequest) GetQuerierID() string { } type NotifyQuerierShutdownResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NotifyQuerierShutdownResponse) Reset() { *x = NotifyQuerierShutdownResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *NotifyQuerierShutdownResponse) String() string { @@ -477,7 +461,7 @@ func (*NotifyQuerierShutdownResponse) ProtoMessage() {} func (x *NotifyQuerierShutdownResponse) ProtoReflect() protoreflect.Message { mi := &file_scheduler_schedulerpb_scheduler_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -494,118 +478,62 @@ func (*NotifyQuerierShutdownResponse) Descriptor() ([]byte, []int) { var File_scheduler_schedulerpb_scheduler_proto protoreflect.FileDescriptor -var file_scheduler_schedulerpb_scheduler_proto_rawDesc = []byte{ - 0x0a, 0x25, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x72, 0x70, 0x62, 0x1a, 0x1c, 0x75, 0x74, 0x69, 0x6c, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x67, - 0x72, 0x70, 0x63, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x32, 0x0a, 0x12, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x54, 0x6f, 0x53, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x72, 0x49, 0x44, 0x22, 0xcd, 0x01, 0x0a, 0x12, 0x53, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x72, 0x54, 0x6f, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x12, 0x18, 0x0a, - 0x07, 0x71, 0x75, 0x65, 0x72, 0x79, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x49, 0x44, 0x12, 0x37, 0x0a, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, - 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x52, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x73, 0x45, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x88, 0x02, 0x0a, 0x13, 0x46, 0x72, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x38, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x73, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x46, 0x72, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x79, 0x49, 0x44, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x79, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, - 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x44, 0x12, 0x37, 0x0a, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x74, 0x74, 0x70, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, - 0x0c, 0x73, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x22, 0x6b, 0x0a, 0x13, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x54, 0x6f, - 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x3e, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, - 0x54, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3c, - 0x0a, 0x1c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x53, - 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, - 0x0a, 0x09, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x49, 0x44, 0x22, 0x1f, 0x0a, 0x1d, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x53, 0x68, 0x75, - 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x3c, 0x0a, - 0x17, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x49, 0x54, - 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x51, 0x55, 0x45, 0x55, 0x45, 0x10, 0x01, 0x12, - 0x0a, 0x0a, 0x06, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x02, 0x2a, 0x63, 0x0a, 0x19, 0x53, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x54, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, - 0x12, 0x20, 0x0a, 0x1c, 0x54, 0x4f, 0x4f, 0x5f, 0x4d, 0x41, 0x4e, 0x59, 0x5f, 0x52, 0x45, 0x51, - 0x55, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x50, 0x45, 0x52, 0x5f, 0x54, 0x45, 0x4e, 0x41, 0x4e, 0x54, - 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, - 0x0d, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, - 0x32, 0xdc, 0x01, 0x0a, 0x13, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x46, 0x6f, - 0x72, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x12, 0x55, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x12, 0x1f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x54, 0x6f, 0x53, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x1a, 0x1f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, - 0x54, 0x6f, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, - 0x6e, 0x0a, 0x15, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, - 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x29, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x72, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, - 0x62, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x72, 0x53, - 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, - 0x70, 0x0a, 0x14, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x46, - 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x58, 0x0a, 0x0c, 0x46, 0x72, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x64, 0x4c, 0x6f, 0x6f, 0x70, 0x12, 0x20, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, - 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x1a, 0x20, 0x2e, 0x73, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x72, 0x54, 0x6f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x22, 0x00, 0x28, 0x01, 0x30, - 0x01, 0x42, 0xa5, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x72, 0x70, 0x62, 0x42, 0x0e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, - 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0xa2, - 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x72, 0x70, 0x62, 0xca, 0x02, 0x0b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, - 0x62, 0xe2, 0x02, 0x17, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0b, 0x53, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} +const file_scheduler_schedulerpb_scheduler_proto_rawDesc = "" + + "\n" + + "%scheduler/schedulerpb/scheduler.proto\x12\vschedulerpb\x1a\x1cutil/httpgrpc/httpgrpc.proto\"2\n" + + "\x12QuerierToScheduler\x12\x1c\n" + + "\tquerierID\x18\x01 \x01(\tR\tquerierID\"\xcd\x01\n" + + "\x12SchedulerToQuerier\x12\x18\n" + + "\aqueryID\x18\x01 \x01(\x04R\aqueryID\x127\n" + + "\vhttpRequest\x18\x02 \x01(\v2\x15.httpgrpc.HTTPRequestR\vhttpRequest\x12(\n" + + "\x0ffrontendAddress\x18\x03 \x01(\tR\x0ffrontendAddress\x12\x16\n" + + "\x06userID\x18\x04 \x01(\tR\x06userID\x12\"\n" + + "\fstatsEnabled\x18\x05 \x01(\bR\fstatsEnabled\"\x88\x02\n" + + "\x13FrontendToScheduler\x128\n" + + "\x04type\x18\x01 \x01(\x0e2$.schedulerpb.FrontendToSchedulerTypeR\x04type\x12(\n" + + "\x0ffrontendAddress\x18\x02 \x01(\tR\x0ffrontendAddress\x12\x18\n" + + "\aqueryID\x18\x03 \x01(\x04R\aqueryID\x12\x16\n" + + "\x06userID\x18\x04 \x01(\tR\x06userID\x127\n" + + "\vhttpRequest\x18\x05 \x01(\v2\x15.httpgrpc.HTTPRequestR\vhttpRequest\x12\"\n" + + "\fstatsEnabled\x18\x06 \x01(\bR\fstatsEnabled\"k\n" + + "\x13SchedulerToFrontend\x12>\n" + + "\x06status\x18\x01 \x01(\x0e2&.schedulerpb.SchedulerToFrontendStatusR\x06status\x12\x14\n" + + "\x05error\x18\x02 \x01(\tR\x05error\"<\n" + + "\x1cNotifyQuerierShutdownRequest\x12\x1c\n" + + "\tquerierID\x18\x01 \x01(\tR\tquerierID\"\x1f\n" + + "\x1dNotifyQuerierShutdownResponse*<\n" + + "\x17FrontendToSchedulerType\x12\b\n" + + "\x04INIT\x10\x00\x12\v\n" + + "\aENQUEUE\x10\x01\x12\n" + + "\n" + + "\x06CANCEL\x10\x02*c\n" + + "\x19SchedulerToFrontendStatus\x12\x06\n" + + "\x02OK\x10\x00\x12 \n" + + "\x1cTOO_MANY_REQUESTS_PER_TENANT\x10\x01\x12\t\n" + + "\x05ERROR\x10\x02\x12\x11\n" + + "\rSHUTTING_DOWN\x10\x032\xdc\x01\n" + + "\x13SchedulerForQuerier\x12U\n" + + "\vQuerierLoop\x12\x1f.schedulerpb.QuerierToScheduler\x1a\x1f.schedulerpb.SchedulerToQuerier\"\x00(\x010\x01\x12n\n" + + "\x15NotifyQuerierShutdown\x12).schedulerpb.NotifyQuerierShutdownRequest\x1a*.schedulerpb.NotifyQuerierShutdownResponse2p\n" + + "\x14SchedulerForFrontend\x12X\n" + + "\fFrontendLoop\x12 .schedulerpb.FrontendToScheduler\x1a .schedulerpb.SchedulerToFrontend\"\x00(\x010\x01B\xa8\x01\n" + + "\x0fcom.schedulerpbB\x0eSchedulerProtoP\x01Z9github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb\xa2\x02\x03SXX\xaa\x02\vSchedulerpb\xca\x02\vSchedulerpb\xe2\x02\x17Schedulerpb\\GPBMetadata\xea\x02\vSchedulerpbb\x06proto3" var ( file_scheduler_schedulerpb_scheduler_proto_rawDescOnce sync.Once - file_scheduler_schedulerpb_scheduler_proto_rawDescData = file_scheduler_schedulerpb_scheduler_proto_rawDesc + file_scheduler_schedulerpb_scheduler_proto_rawDescData []byte ) func file_scheduler_schedulerpb_scheduler_proto_rawDescGZIP() []byte { file_scheduler_schedulerpb_scheduler_proto_rawDescOnce.Do(func() { - file_scheduler_schedulerpb_scheduler_proto_rawDescData = protoimpl.X.CompressGZIP(file_scheduler_schedulerpb_scheduler_proto_rawDescData) + file_scheduler_schedulerpb_scheduler_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_scheduler_schedulerpb_scheduler_proto_rawDesc), len(file_scheduler_schedulerpb_scheduler_proto_rawDesc))) }) return file_scheduler_schedulerpb_scheduler_proto_rawDescData } var file_scheduler_schedulerpb_scheduler_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_scheduler_schedulerpb_scheduler_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_scheduler_schedulerpb_scheduler_proto_goTypes = []interface{}{ +var file_scheduler_schedulerpb_scheduler_proto_goTypes = []any{ (FrontendToSchedulerType)(0), // 0: schedulerpb.FrontendToSchedulerType (SchedulerToFrontendStatus)(0), // 1: schedulerpb.SchedulerToFrontendStatus (*QuerierToScheduler)(nil), // 2: schedulerpb.QuerierToScheduler @@ -639,85 +567,11 @@ func file_scheduler_schedulerpb_scheduler_proto_init() { if File_scheduler_schedulerpb_scheduler_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_scheduler_schedulerpb_scheduler_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QuerierToScheduler); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_scheduler_schedulerpb_scheduler_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SchedulerToQuerier); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_scheduler_schedulerpb_scheduler_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FrontendToScheduler); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_scheduler_schedulerpb_scheduler_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SchedulerToFrontend); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_scheduler_schedulerpb_scheduler_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyQuerierShutdownRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_scheduler_schedulerpb_scheduler_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyQuerierShutdownResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_scheduler_schedulerpb_scheduler_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_scheduler_schedulerpb_scheduler_proto_rawDesc), len(file_scheduler_schedulerpb_scheduler_proto_rawDesc)), NumEnums: 2, NumMessages: 6, NumExtensions: 0, @@ -729,7 +583,6 @@ func file_scheduler_schedulerpb_scheduler_proto_init() { MessageInfos: file_scheduler_schedulerpb_scheduler_proto_msgTypes, }.Build() File_scheduler_schedulerpb_scheduler_proto = out.File - file_scheduler_schedulerpb_scheduler_proto_rawDesc = nil file_scheduler_schedulerpb_scheduler_proto_goTypes = nil file_scheduler_schedulerpb_scheduler_proto_depIdxs = nil } diff --git a/pkg/scheduler/schedulerpb/scheduler_vtproto.pb.go b/pkg/scheduler/schedulerpb/scheduler_vtproto.pb.go index bd4c4c6531..ea8a2e4a07 100644 --- a/pkg/scheduler/schedulerpb/scheduler_vtproto.pb.go +++ b/pkg/scheduler/schedulerpb/scheduler_vtproto.pb.go @@ -7,7 +7,7 @@ package schedulerpb import ( context "context" fmt "fmt" - httpgrpc "github.com/grafana/pyroscope/pkg/util/httpgrpc" + httpgrpc "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" protohelpers "github.com/planetscale/vtprotobuf/protohelpers" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/pkg/scheduler/schedulerpb/schedulerpbconnect/scheduler.connect.go b/pkg/scheduler/schedulerpb/schedulerpbconnect/scheduler.connect.go index ff740bdd86..28cc573d8b 100644 --- a/pkg/scheduler/schedulerpb/schedulerpbconnect/scheduler.connect.go +++ b/pkg/scheduler/schedulerpb/schedulerpbconnect/scheduler.connect.go @@ -13,7 +13,7 @@ import ( connect "connectrpc.com/connect" context "context" errors "errors" - schedulerpb "github.com/grafana/pyroscope/pkg/scheduler/schedulerpb" + schedulerpb "github.com/grafana/pyroscope/v2/pkg/scheduler/schedulerpb" http "net/http" strings "strings" ) @@ -51,15 +51,6 @@ const ( SchedulerForFrontendFrontendLoopProcedure = "/schedulerpb.SchedulerForFrontend/FrontendLoop" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - schedulerForQuerierServiceDescriptor = schedulerpb.File_scheduler_schedulerpb_scheduler_proto.Services().ByName("SchedulerForQuerier") - schedulerForQuerierQuerierLoopMethodDescriptor = schedulerForQuerierServiceDescriptor.Methods().ByName("QuerierLoop") - schedulerForQuerierNotifyQuerierShutdownMethodDescriptor = schedulerForQuerierServiceDescriptor.Methods().ByName("NotifyQuerierShutdown") - schedulerForFrontendServiceDescriptor = schedulerpb.File_scheduler_schedulerpb_scheduler_proto.Services().ByName("SchedulerForFrontend") - schedulerForFrontendFrontendLoopMethodDescriptor = schedulerForFrontendServiceDescriptor.Methods().ByName("FrontendLoop") -) - // SchedulerForQuerierClient is a client for the schedulerpb.SchedulerForQuerier service. type SchedulerForQuerierClient interface { // After calling this method, both Querier and Scheduler enter a loop, in which querier waits for @@ -82,17 +73,18 @@ type SchedulerForQuerierClient interface { // http://api.acme.com or https://acme.com/grpc). func NewSchedulerForQuerierClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) SchedulerForQuerierClient { baseURL = strings.TrimRight(baseURL, "/") + schedulerForQuerierMethods := schedulerpb.File_scheduler_schedulerpb_scheduler_proto.Services().ByName("SchedulerForQuerier").Methods() return &schedulerForQuerierClient{ querierLoop: connect.NewClient[schedulerpb.QuerierToScheduler, schedulerpb.SchedulerToQuerier]( httpClient, baseURL+SchedulerForQuerierQuerierLoopProcedure, - connect.WithSchema(schedulerForQuerierQuerierLoopMethodDescriptor), + connect.WithSchema(schedulerForQuerierMethods.ByName("QuerierLoop")), connect.WithClientOptions(opts...), ), notifyQuerierShutdown: connect.NewClient[schedulerpb.NotifyQuerierShutdownRequest, schedulerpb.NotifyQuerierShutdownResponse]( httpClient, baseURL+SchedulerForQuerierNotifyQuerierShutdownProcedure, - connect.WithSchema(schedulerForQuerierNotifyQuerierShutdownMethodDescriptor), + connect.WithSchema(schedulerForQuerierMethods.ByName("NotifyQuerierShutdown")), connect.WithClientOptions(opts...), ), } @@ -133,16 +125,17 @@ type SchedulerForQuerierHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewSchedulerForQuerierHandler(svc SchedulerForQuerierHandler, opts ...connect.HandlerOption) (string, http.Handler) { + schedulerForQuerierMethods := schedulerpb.File_scheduler_schedulerpb_scheduler_proto.Services().ByName("SchedulerForQuerier").Methods() schedulerForQuerierQuerierLoopHandler := connect.NewBidiStreamHandler( SchedulerForQuerierQuerierLoopProcedure, svc.QuerierLoop, - connect.WithSchema(schedulerForQuerierQuerierLoopMethodDescriptor), + connect.WithSchema(schedulerForQuerierMethods.ByName("QuerierLoop")), connect.WithHandlerOptions(opts...), ) schedulerForQuerierNotifyQuerierShutdownHandler := connect.NewUnaryHandler( SchedulerForQuerierNotifyQuerierShutdownProcedure, svc.NotifyQuerierShutdown, - connect.WithSchema(schedulerForQuerierNotifyQuerierShutdownMethodDescriptor), + connect.WithSchema(schedulerForQuerierMethods.ByName("NotifyQuerierShutdown")), connect.WithHandlerOptions(opts...), ) return "/schedulerpb.SchedulerForQuerier/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -188,11 +181,12 @@ type SchedulerForFrontendClient interface { // http://api.acme.com or https://acme.com/grpc). func NewSchedulerForFrontendClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) SchedulerForFrontendClient { baseURL = strings.TrimRight(baseURL, "/") + schedulerForFrontendMethods := schedulerpb.File_scheduler_schedulerpb_scheduler_proto.Services().ByName("SchedulerForFrontend").Methods() return &schedulerForFrontendClient{ frontendLoop: connect.NewClient[schedulerpb.FrontendToScheduler, schedulerpb.SchedulerToFrontend]( httpClient, baseURL+SchedulerForFrontendFrontendLoopProcedure, - connect.WithSchema(schedulerForFrontendFrontendLoopMethodDescriptor), + connect.WithSchema(schedulerForFrontendMethods.ByName("FrontendLoop")), connect.WithClientOptions(opts...), ), } @@ -225,10 +219,11 @@ type SchedulerForFrontendHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewSchedulerForFrontendHandler(svc SchedulerForFrontendHandler, opts ...connect.HandlerOption) (string, http.Handler) { + schedulerForFrontendMethods := schedulerpb.File_scheduler_schedulerpb_scheduler_proto.Services().ByName("SchedulerForFrontend").Methods() schedulerForFrontendFrontendLoopHandler := connect.NewBidiStreamHandler( SchedulerForFrontendFrontendLoopProcedure, svc.FrontendLoop, - connect.WithSchema(schedulerForFrontendFrontendLoopMethodDescriptor), + connect.WithSchema(schedulerForFrontendMethods.ByName("FrontendLoop")), connect.WithHandlerOptions(opts...), ) return "/schedulerpb.SchedulerForFrontend/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/segmentwriter/client/client.go b/pkg/segmentwriter/client/client.go new file mode 100644 index 0000000000..4c5fe89b99 --- /dev/null +++ b/pkg/segmentwriter/client/client.go @@ -0,0 +1,367 @@ +package segmentwriterclient + +import ( + "context" + "errors" + "fmt" + "os" + "strconv" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/ring" + ring_client "github.com/grafana/dskit/ring/client" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + "github.com/sony/gobreaker/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/connpool" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + "github.com/grafana/pyroscope/v2/pkg/util/circuitbreaker" +) + +var errServiceUnavailableMsg = "service is unavailable" + +// TODO(kolesnikovae): +// * Replace the ring service discovery and client pool implementations. +// * Make CB options configurable. + +const ( + // Circuit breaker defaults. + cbMinSuccess = 5 + cbMaxFailures = 3 + cbClosedInterval = 0 + cbOpenTimeout = time.Second + + poolCleanupPeriod = 15 * time.Second +) + +// Only these errors are considered as a signal to retry the request +// and send it to another instance. Client-side, internal, and unknown +// errors should not be retried, as they are likely to be permanent. +// Note that the client errors are not excluded from the list. +func isRetryable(err error) bool { + switch status.Code(err) { + case codes.Unknown, + codes.Internal, + codes.FailedPrecondition: + return false + default: + // All sorts of network errors. + return true + } +} + +// Client errors are returned as is without retries. +// Any other error is substituted with a stub message +// and UNAVAILABLE status. +func isClientError(err error) bool { + switch status.Code(err) { + case codes.InvalidArgument, + codes.Canceled, + codes.PermissionDenied, + codes.Unauthenticated: + return true + default: + return errors.Is(err, context.Canceled) + } +} + +// https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern +// The circuit breaker is used to prevent the client from sending +// requests to unhealthy instances. The logic is as follows: +// +// Once we observe 3 consecutive failures, the circuit breaker will trip +// and open the circuit – any attempt to send a request will fail +// immediately with a "circuit breaker is open" error (UNAVAILABLE). +// +// After the expiration of the Timeout (5 seconds), the circuit breaker will +// transition to the half-open state. In this state, if a failure occurs, +// the breaker will revert to the open state. After MaxRequests (5) +// consecutive successful requests, the circuit breaker will return to the +// closed state. +var circuitBreakerConfig = gobreaker.Settings{ + MaxRequests: cbMinSuccess, + Interval: cbClosedInterval, + Timeout: cbOpenTimeout, + IsSuccessful: shouldBeHandledByCaller, + ReadyToTrip: func(counts gobreaker.Counts) bool { + return counts.ConsecutiveFailures >= cbMaxFailures + }, +} + +// If the function returns false, the error is counted towards tripping +// the open state, when no requests flow through the circuit. Otherwise, +// the error handling is returned back the caller. +// +// In fact, the configuration should only prevent sending requests +// to instances that are a-priory unable to process them at the moment, +// and we want to avoid time waste. For example, when a service instance +// went unavailable for a long period of time, or is not reposing in +// timely fashion. +// +// From the caller perspective, we're converting those to UNAVAILABLE, +// thereby allowing the caller to retry the request against another service +// instance. +// +// Note that client-side, internal, and unknown errors are not included: +// in case if a request is failing permanently regardless of the service +// instance, there is a good chance that all the circuits will be opened +// by retries, making the whole service unavailable. +// +// Next, ResourceExhausted also excluded from the list: as the error is +// tenant-request-specific, and the circuit breaker operates connection-wise. +func shouldBeHandledByCaller(err error) bool { + if errors.Is(err, os.ErrDeadlineExceeded) { + return false + } + if status.Code(err) == codes.Unavailable { + return false + } + // The error handling is returned back the caller: the circuit + // remains closed. + return true +} + +// The default gRPC service config is explicitly set to balance between +// instances. +const grpcServiceConfig = `{ + "healthCheckConfig": { + "serviceName": "pyroscope.segment-writer" + } +}` + +type Client struct { + logger log.Logger + metrics *metrics + + ring ring.ReadRing + pool *connpool.Pool + distributor *distributor.Distributor + + service services.Service + subservices *services.Manager + watcher *services.FailureWatcher +} + +func NewSegmentWriterClient( + grpcClientConfig grpcclient.Config, + logger log.Logger, + registry prometheus.Registerer, + ring ring.ReadRing, + placement placement.Placement, + dialOpts ...grpc.DialOption, +) (*Client, error) { + pool, err := newConnPool(ring, logger, grpcClientConfig, dialOpts...) + if err != nil { + return nil, err + } + c := &Client{ + logger: logger, + metrics: newMetrics(registry), + distributor: distributor.NewDistributor(placement, ring), + pool: pool, + ring: ring, + } + c.subservices, err = services.NewManager(c.pool) + if err != nil { + return nil, fmt.Errorf("services manager: %w", err) + } + c.watcher = services.NewFailureWatcher() + c.watcher.WatchManager(c.subservices) + c.service = services.NewBasicService(c.starting, c.running, c.stopping) + return c, nil +} + +func (c *Client) Service() services.Service { return c.service } + +// CheckReady reports whether the client can dispatch requests, i.e. its +// service is Running and the segment-writer ring has at least one healthy +// instance. Used by callers (e.g. the distributor) to gate readiness so +// that traffic isn't accepted before the ring has been populated. +func (c *Client) CheckReady(_ context.Context) error { + if state := c.service.State(); state != services.Running { + return fmt.Errorf("segment-writer client not running: %s", state) + } + rs, err := c.ring.GetAllHealthy(ring.Reporting) + if err != nil { + return fmt.Errorf("segment-writer ring: %w", err) + } + if len(rs.Instances) == 0 { + return errors.New("segment-writer ring has no healthy instances") + } + return nil +} + +func (c *Client) starting(ctx context.Context) error { + // Warm up connections. The pool does not do this. + instances, err := c.ring.GetAllHealthy(ring.Reporting) + if err != nil { + // The ring might be empty initially if the segment-writer service + // is not yet ready. In such cases, we avoid failing the client to + // allow for eventual readiness. + level.Debug(c.logger).Log("msg", "unable to create connections", "err", err) + } else { + var wg sync.WaitGroup + for _, x := range instances.Instances { + wg.Add(1) + go func(x ring.InstanceDesc) { + defer wg.Done() + _, _ = c.pool.GetClientFor(x.Addr) + }(x) + } + wg.Wait() + } + return services.StartManagerAndAwaitHealthy(ctx, c.subservices) +} + +func (c *Client) running(ctx context.Context) error { + select { + case <-ctx.Done(): + return nil + case err := <-c.watcher.Chan(): + return fmt.Errorf("segement writer client subservice failed: %w", err) + } +} + +func (c *Client) stopping(_ error) error { + return services.StopManagerAndAwaitStopped(context.Background(), c.subservices) +} + +func (c *Client) Push( + ctx context.Context, + req *segmentwriterv1.PushRequest, +) (resp *segmentwriterv1.PushResponse, err error) { + k := distributor.NewTenantServiceDatasetKey(req.TenantId, req.Labels...) + p, dErr := c.distributor.Distribute(k) + if dErr != nil { + level.Error(c.logger).Log( + "msg", "unable to distribute request", + "tenant", req.TenantId, + "err", dErr, + ) + return nil, status.Error(codes.Unavailable, errServiceUnavailableMsg) + } + + // In case of a failure, the request is sent to another instance. + // At most 5 attempts to push the data to the segment writer. + instances := placement.ActiveInstances(p.Instances) + req.Shard = p.Shard + for attempts := 5; attempts >= 0 && instances.Next(); attempts-- { + instance := instances.At() + logger := log.With(c.logger, + "tenant", req.TenantId, + "shard", req.Shard, + "instance_addr", instance.Addr, + "instance_id", instance.Id, + "attempts_left", attempts, + ) + level.Debug(logger).Log("msg", "sending request") + resp, err = c.pushToInstance(ctx, req, instance.Addr) + if err == nil { + return resp, nil + } + if isClientError(err) { + return nil, err + } + if !isRetryable(err) { + level.Error(logger).Log("msg", "failed to push data to segment writer", "err", err) + return nil, status.Error(codes.Unavailable, errServiceUnavailableMsg) + } + level.Warn(logger).Log("msg", "failed attempt to push data to segment writer", "err", err) + if ctxErr := ctx.Err(); ctxErr != nil { + return nil, ctxErr + } + } + + level.Error(c.logger).Log( + "msg", "no segment writer instances available for the request", + "tenant", req.TenantId, + "shard", req.Shard, + "last_err", err, + ) + + return nil, status.Error(codes.Unavailable, errServiceUnavailableMsg) +} + +func (c *Client) pushToInstance( + ctx context.Context, + req *segmentwriterv1.PushRequest, + addr string, +) (*segmentwriterv1.PushResponse, error) { + conn, err := c.pool.GetConnFor(addr) + if err != nil { + return nil, err + } + // We explicitly force the client to not wait for the connection: + // if the connection is not ready, the client will go to the next + // instance. + client := segmentwriterv1.NewSegmentWriterServiceClient(conn) + resp, err := client.Push(ctx, req, grpc.WaitForReady(false)) + if err == nil { + c.metrics.sentBytes. + WithLabelValues(strconv.Itoa(int(req.Shard)), req.TenantId, addr). + Observe(float64(len(req.Profile))) + } + return resp, err +} + +func newConnPool( + rring ring.ReadRing, + logger log.Logger, + grpcClientConfig grpcclient.Config, + dialOpts ...grpc.DialOption, +) (*connpool.Pool, error) { + options, err := grpcClientConfig.DialOption(nil, nil, nil) + if err != nil { + return nil, err + } + + // The options (including interceptors) are shared by all client connections. + options = append(options, dialOpts...) + options = append(options, + grpc.WithDefaultServiceConfig(grpcServiceConfig), + // Just in case: we explicitly disable the built-in + // retry mechanism of the gRPC client. + grpc.WithDisableRetry(), + ) + + // Note that circuit breaker must be created per client conn. + factory := connpool.NewConnPoolFactory(func(ring.InstanceDesc) []grpc.DialOption { + cb := circuitbreaker.UnaryClientInterceptor(gobreaker.NewCircuitBreaker[any](circuitBreakerConfig)) + return append(options, grpc.WithUnaryInterceptor(cb)) + }) + + p := ring_client.NewPool( + "segment-writer", + ring_client.PoolConfig{ + CheckInterval: poolCleanupPeriod, + // Note that health checks are not used: gGRPC health-checking + // is done at the gRPC connection level. + HealthCheckEnabled: false, + HealthCheckTimeout: 0, + MaxConcurrentHealthChecks: 0, + }, + // Discovery is used to remove clients that can't be found + // in the ring, including unhealthy instances. CheckInterval + // specifies how frequently the stale clients are removed. + // Discovery builds a list of healthy instances. + // An instance is healthy, if it's heartbeat timestamp + // is not older than a configured threshold (intrinsic + // to the ring itself). + ring_client.NewRingServiceDiscovery(rring), + factory, + nil, // Client count gauge is not used. + logger, + ) + + return &connpool.Pool{Pool: p}, nil +} diff --git a/pkg/segmentwriter/client/client_metrics.go b/pkg/segmentwriter/client/client_metrics.go new file mode 100644 index 0000000000..dfe570ad6b --- /dev/null +++ b/pkg/segmentwriter/client/client_metrics.go @@ -0,0 +1,32 @@ +package segmentwriterclient + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +type metrics struct { + sentBytes *prometheus.HistogramVec +} + +func newMetrics(reg prometheus.Registerer) *metrics { + m := &metrics{ + // Note that the number of shards per tenant is limited. + // The same for the "addr" limit: a shard resides on a single address, + // ideally; in practice, if the segment writer is not available, the + // shard may be relocated. + sentBytes: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pyroscope_segment_writer_client_sent_bytes", + Buckets: prometheus.ExponentialBucketsRange(100, 100<<20, 30), + Help: "Number of bytes sent by the segment writer client.", + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"shard", "tenant", "addr"}), + } + if reg != nil { + reg.MustRegister(m.sentBytes) + } + return m +} diff --git a/pkg/segmentwriter/client/client_test.go b/pkg/segmentwriter/client/client_test.go new file mode 100644 index 0000000000..e4a857be87 --- /dev/null +++ b/pkg/segmentwriter/client/client_test.go @@ -0,0 +1,302 @@ +package segmentwriterclient + +import ( + "context" + "errors" + "flag" + "fmt" + "io" + "net" + "os" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/services" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + "github.com/grafana/pyroscope/v2/pkg/testhelper" +) + +type segwriterServerMock struct { + segmentwriterv1.UnimplementedSegmentWriterServiceServer + mock.Mock +} + +func (m *segwriterServerMock) Push( + ctx context.Context, + req *segmentwriterv1.PushRequest, +) (*segmentwriterv1.PushResponse, error) { + args := m.Called(ctx, req) + return args.Get(0).(*segmentwriterv1.PushResponse), args.Error(1) +} + +type testPlacement struct{} + +func (testPlacement) Policy(k placement.Key) placement.Policy { + return placement.Policy{ + TenantShards: 0, // Unlimited. + DatasetShards: 1, + PickShard: func(n int) int { + return int(k.Fingerprint % uint64(n)) + }, + } +} + +type segwriterClientSuite struct { + suite.Suite + + listener *bufconn.Listener + dialer func(context.Context, string) (net.Conn, error) + server *grpc.Server + service *segwriterServerMock + done chan struct{} + + logger log.Logger + config grpcclient.Config + ring testhelper.MockRing + client *Client +} + +func (s *segwriterClientSuite) SetupTest() { + listener := bufconn.Listen(256 << 10) + s.listener = listener + s.dialer = func(context.Context, string) (net.Conn, error) { return listener.Dial() } + s.server = grpc.NewServer() + s.service = new(segwriterServerMock) + segmentwriterv1.RegisterSegmentWriterServiceServer(s.server, s.service) + + s.logger = log.NewLogfmtLogger(os.Stdout) + s.config = grpcclient.Config{} + s.config.RegisterFlags(flag.NewFlagSet("", flag.PanicOnError)) + instances := []ring.InstanceDesc{ + {Id: "a", Addr: "localhost", Tokens: make([]uint32, 1)}, + {Id: "b", Addr: "localhost", Tokens: make([]uint32, 1)}, + {Id: "c", Addr: "localhost", Tokens: make([]uint32, 1)}, + } + s.ring = testhelper.NewMockRing(instances, 1) + + var err error + s.client, err = NewSegmentWriterClient( + s.config, s.logger, nil, s.ring, + testPlacement{}, + grpc.WithContextDialer(s.dialer)) + s.Require().NoError(err) + + s.done = make(chan struct{}) + go func() { + defer close(s.done) + if err := s.server.Serve(listener); err != nil && !errors.Is(err, grpc.ErrServerStopped) { + s.T().Errorf("unexpected server error: %v", err) + } + }() + + // Wait for the server + conn, err := grpc.NewClient("", + grpc.WithContextDialer(s.dialer), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + + s.Require().NoError(err) + s.Require().NoError(conn.Close()) +} + +func (s *segwriterClientSuite) BeforeTest(_, _ string) { + svc := s.client.Service() + s.Require().NoError(svc.StartAsync(context.Background())) + s.Require().NoError(svc.AwaitRunning(context.Background())) + s.Require().Equal(services.Running, svc.State()) +} + +func (s *segwriterClientSuite) AfterTest(_, _ string) { + svc := s.client.Service() + svc.StopAsync() + s.Require().NoError(svc.AwaitTerminated(context.Background())) + s.Require().Equal(services.Terminated, svc.State()) + + s.service.AssertExpectations(s.T()) +} + +func (s *segwriterClientSuite) TearDownTest() { + s.server.GracefulStop() + <-s.done +} + +func TestSegmentWriterClientSuite(t *testing.T) { suite.Run(t, new(segwriterClientSuite)) } + +func (s *segwriterClientSuite) Test_Push_HappyPath() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(&segmentwriterv1.PushResponse{}, nil). + Once() + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().NoError(err) +} + +func (s *segwriterClientSuite) Test_Push_EmptyRing() { + emptyRing := testhelper.NewMockRing(nil, 1) + var err error + s.client, err = NewSegmentWriterClient( + s.config, s.logger, nil, emptyRing, + testPlacement{}, + grpc.WithContextDialer(s.dialer)) + s.Require().NoError(err) + + _, err = s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().Equal(codes.Unavailable.String(), status.Code(err).String()) +} + +func (s *segwriterClientSuite) Test_Push_ClientError_Cancellation() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), context.Canceled). + Once() + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().Equal(codes.Canceled.String(), status.Code(err).String()) +} + +func (s *segwriterClientSuite) Test_Push_Client_Deadline() { + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Second)) + defer cancel() + _, err := s.client.Push(ctx, &segmentwriterv1.PushRequest{}) + s.Assert().ErrorIs(err, context.DeadlineExceeded) +} + +func (s *segwriterClientSuite) Test_Push_NonClient_Deadline() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), context.DeadlineExceeded). + Once() + + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), nil). + Once() + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().NoError(err) +} + +func (s *segwriterClientSuite) Test_Push_ClientError_InvalidArgument() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), status.Error(codes.InvalidArgument, errServiceUnavailableMsg)). + Once() + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().Equal(codes.InvalidArgument.String(), status.Code(err).String()) +} + +func (s *segwriterClientSuite) Test_Push_ServerError_NonRetryable() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), io.EOF). + Once() + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().Equal(codes.Unavailable.String(), status.Code(err).String()) +} + +func (s *segwriterClientSuite) Test_Push_ServerError_Retry_Unavailable() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), status.Error(codes.Unavailable, errServiceUnavailableMsg)). + Once() + + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), nil). + Once() + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().NoError(err) +} + +func (s *segwriterClientSuite) Test_Push_ServerError_Retry_ResourceExhausted() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), status.Error(codes.ResourceExhausted, errServiceUnavailableMsg)). + Once() + + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), nil). + Once() + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().NoError(err) +} + +func (s *segwriterClientSuite) Test_Push_DialError() { + dialer := func(ctx context.Context, s string) (net.Conn, error) { + return nil, io.EOF + } + var err error + s.client, err = NewSegmentWriterClient( + s.config, s.logger, nil, s.ring, + testPlacement{}, + grpc.WithContextDialer(dialer)) + s.Require().NoError(err) + + _, err = s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().Equal(codes.Unavailable.String(), status.Code(err).String()) +} + +func (s *segwriterClientSuite) Test_Push_DialError_Retry() { + var failed bool + dialer := func(context.Context, string) (net.Conn, error) { + if failed { + return nil, net.UnknownNetworkError("network issue") + } + failed = true + return s.listener.Dial() + } + var err error + s.client, err = NewSegmentWriterClient( + s.config, s.logger, nil, s.ring, + testPlacement{}, + grpc.WithContextDialer(dialer)) + s.Require().NoError(err) + + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), nil). + Once() + + _, err = s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().NoError(err) +} + +func (s *segwriterClientSuite) Test_Push_AllInstancesUnavailable() { + s.service.On("Push", mock.Anything, mock.Anything). + Return(new(segmentwriterv1.PushResponse), status.Error(codes.Unavailable, errServiceUnavailableMsg)) + + _, err := s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + s.Assert().Equal(codes.Unavailable.String(), status.Code(err).String()) +} + +func (s *segwriterClientSuite) Test_Push_ConnTimeout() { + dialer := func(ctx context.Context, _ string) (net.Conn, error) { + <-ctx.Done() + return nil, fmt.Errorf("dial error") + } + + // Unfortunately, we can't set arbitrary timeout + // here: the minimal allowed value is 1s. + s.config.ConnectTimeout = time.Second + var err error + s.client, err = NewSegmentWriterClient( + s.config, s.logger, nil, s.ring, + testPlacement{}, + grpc.WithContextDialer(dialer)) + s.Require().NoError(err) + + // Note that we use the background context: we do not + // want to wait for the context to expire, but fail + // fast, once the connection timeout expires. + _, err = s.client.Push(context.Background(), &segmentwriterv1.PushRequest{}) + // The client, however, won't see the underlying error. + s.Require().NotNil(err) + s.Assert().Contains(err.Error(), errServiceUnavailableMsg) +} diff --git a/pkg/segmentwriter/client/connpool/conn_pool_ring.go b/pkg/segmentwriter/client/connpool/conn_pool_ring.go new file mode 100644 index 0000000000..88ff32c3e2 --- /dev/null +++ b/pkg/segmentwriter/client/connpool/conn_pool_ring.go @@ -0,0 +1,59 @@ +package connpool + +import ( + "io" + + "github.com/grafana/dskit/services" + "google.golang.org/grpc" + "google.golang.org/grpc/health/grpc_health_v1" + + "github.com/grafana/dskit/ring" + ring_client "github.com/grafana/dskit/ring/client" + + "github.com/grafana/pyroscope/v2/pkg/util/health" +) + +// NOTE(kolesnikovae): This is a tiny wrapper for ring_client.Pool +// that is not tailored for the specific use case of the segment +// writer client, and it should be refactored out. + +type ConnPool interface { + GetConnFor(addr string) (grpc.ClientConnInterface, error) + services.Service +} + +type Pool struct{ *ring_client.Pool } + +func (p *Pool) GetConnFor(addr string) (grpc.ClientConnInterface, error) { + c, err := p.GetClientFor(addr) + if err != nil { + return nil, err + } + return c.(grpc.ClientConnInterface), nil +} + +type ConnFactory struct { + options func(ring.InstanceDesc) []grpc.DialOption +} + +func NewConnPoolFactory(options func(ring.InstanceDesc) []grpc.DialOption) ring_client.PoolFactory { + return &ConnFactory{options: options} +} + +func (f *ConnFactory) FromInstance(inst ring.InstanceDesc) (ring_client.PoolClient, error) { + conn, err := grpc.NewClient(inst.Addr, f.options(inst)...) + if err != nil { + return nil, err + } + return &poolConn{ + ClientConnInterface: conn, + HealthClient: health.NoOpClient, + Closer: conn, + }, nil +} + +type poolConn struct { + grpc.ClientConnInterface + grpc_health_v1.HealthClient + io.Closer +} diff --git a/pkg/segmentwriter/client/distributor/README.md b/pkg/segmentwriter/client/distributor/README.md new file mode 100644 index 0000000000..e44530f328 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/README.md @@ -0,0 +1,325 @@ +# Data Distribution Algorithm + +## Background + +The **main requirement** for a distribution algorithm is that profile series of the same tenant service should be +co-located, as spatial locality is crucial for compaction and query performance. The distribution algorithm should +not aim to place all profiles of a specific tenant service in a dedicated shard; instead, it should distribute them +among the optimal number of shards. + +Distributors must be aware of availability zones and should only route profiles to segment writers in the home AZ. +Depending on the environment, crossing AZ network boundaries usually incurs penalties: cloud providers may charge +for cross-AZ traffic, or in on-premises deployments, AZs may represent different data centers with high-latency +connections. + +The number of shards and segment writers is not constant and may change over time. The distribution algorithm should +aim to minimize data re-balancing when such changes occur. Nevertheless, we do not perform actual data re-balancing: +data written to a shard remains there until it is compacted or deleted. The only reason for minimizing re-balancing +is to optimize data locality; this concerns both data in transit, as segment writers are sensitive to the variance of +the datasets, and data at rest, as this is crucial for compaction efficiency and query performance in the end. + +# Overview + +* Profiles are *distributed* among segment-writers based on the profile labels. +* Profile labels _must_ include `service_name` label, which denotes the dataset the profile belongs to. +* Each profile belongs to a tenant. + +The choice of a placement for a profile involves a three-step process: + +1. Finding *m* suitable locations from the total of *N* options using the request `tenant_id`. +2. Finding *n* suitable locations from the total of *m* options using the `service_name` label. +3. Finding the exact location *s* from the total of *n* options. + +Where: + + * **N** is the total number of shards in the deployment. + * **m** – tenant shard limits – is configured explicitly. + * **n** – dataset shard limits – selected dynamically, based on the observed ingestion rate and patterns. + +The number of shards in the deployment is determined by the number of nodes in the deployment: +* We seek to minimize the number of shards to optimize the cost of the solution: as we flush segments per shard, + the number of shards directly affects the number of write operations to the object storage. +* Experimentally, we found that a conservative processing rate is approximately 8 MB/s per core, depending on the + processor and the network bandwidth (thus, 128 cores should be generally enough to handle 1 GB/s). This unit is + recommended as a quantifier of the deployment size and the shard size. + +Due to the nature of continuous profiling, it is usually beneficial to keep the same profile series on the same shard, +as this allows for more optimal utilization of the TSDB index (the inverted index used for searching by labels). +However, data is often distributed across profile series unevenly; using a series label hash as the distribution key +at any of the steps above may lead to significant data skews. To mitigate this, we propose to employ adaptive load +balancing: use `fingerprint mod n` as the distribution key at step 3 by default, and switch to `random(n)`, when a +skew is observed. + +In case of a failure, the next suitable segment writer is selected (from *n* options available to the tenant service, +increasing the number if needed). The shard identifier is specified explicitly in the request to the segment writer to +maintain data locality in case of transient failures and rollouts. + +The proposed approach assumes that two requests with the same distribution key may end up in different shards. +This should be a rare occurrence, but such placement is expected. + +# Implementation + +The existing ring implementation is used for discovery: the underlying [memberlist](https://github.com/hashicorp/memberlist) +library is used to maintain the list of the segment-writer service instances: + +```mermaid +graph RL + Lifecycler-.->Memberlist + Memberlist-.->Ring + + subgraph SegmentWriter["segment-writer"] + Lifecycler["lifecycler"] + end + + subgraph Memberlist["memberlist"] + end + + subgraph Distributor["distributor"] + Ring["ring"] + end + +``` + +Instead of using the ring for the actual placement, distributor builds its own view of the ring, which is then used to +determine the placement of the keys (profiles). The main reason for this is that the exising ring implementation is not +well suited for the proposed algorithm, as it does not provide a way to map a key to a specific shard. + +In accordance to the algorithm, for each key (profile), we need to identify a subset of shards allowed for the tenant, +and subset of shards allowed for the dataset. [Jump consistent hash](https://arxiv.org/pdf/1406.2294) is used to pick +the subring position: + +```cpp +int32_t JumpConsistentHash(uint64_t key, int32_t num_buckets) { + int64_t b = 1, j = 0; + while (j < num_buckets) { + b = j; + key = key * 2862933555777941757ULL + 1; + j = (b + 1) * (double(1LL << 31) / double((key >> 33) + 1)); + } + return b; +} +``` + +The function ensures _balance_, which essentially states that objects are evenly distributed among buckets, and +_monotonicity_, which says that when the number of buckets is increased, objects move only from old buckets to new +buckets, thus doing no unnecessary rearrangement. + +The diagram below illustrates how a specific key (profile) can be mapped to a specific shard and node: +1. First subring (tenant shards) starts at offset 3 and its size is 8 (configured explicitly). +2. Second subring (dataset shards) starts at offset 1 within the parent subring (tenant) and includes 4 shards (determined dynamically). + +```mermaid +block-beta + columns 15 + + nodes["nodes"]:2 + space + node_a["node A"]:4 + node_b["node B"]:4 + node_c["node C"]:4 + + shards["ring"]:2 + space + shard_0["0"] + shard_1["1"] + shard_2["2"] + shard_3["3"] + shard_4["4"] + shard_5["5"] + shard_6["6"] + shard_7["7"] + shard_8["8"] + shard_9["9"] + shard_10["10"] + shard_11["11"] + + tenant["tenant"]:2 + space:4 + ts_3["3"] + ts_4["4"] + ts_5["5"] + ts_6["6"] + ts_7["7"] + ts_8["8"] + ts_9["9"] + space:2 + + dataset["dataset"]:2 + space:5 + ds_4["4"] + ds_5["5"] + ds_6["6"] + ds_7["7"] + space:4 + +``` + +Such placement enables hot spots: in this specific example, all the dataset shards end up on the same node, which may +lead to uneven load distribution and poses problems in case of node failures. For example, if node B fails, all the +requests that target it, would be routed to node A (or C), which may lead to a cascading failure. + +To mitigate this, shards are mapped to instances through a separate mapping table. The mapping table is updated every +time when the number of nodes changes, but it preserves the existing mapping as much as possible. + +```mermaid +block-beta + columns 15 + + shards["ring"]:2 + space + shard_0["0"] + shard_1["1"] + shard_2["2"] + shard_3["3"] + shard_4["4"] + shard_5["5"] + shard_6["6"] + shard_7["7"] + shard_8["8"] + shard_9["9"] + shard_10["10"] + shard_11["11"] + + tenant["tenant"]:2 + space:4 + ts_3["3"] + ts_4["4"] + ts_5["5"] + ts_6["6"] + ts_7["7"] + ts_8["8"] + ts_9["9"] + space:2 + + dataset["dataset"]:2 + space:5 + ds_4["4"] + ds_5["5"] + ds_6["6"] + ds_7["7"] + space:4 + + space:15 + + mapping["mapping"]:2 + space + map_4["4"] + map_11["11"] + map_5["5"] + map_2["2"] + map_3["3"] + map_0["0"] + map_7["7"] + map_9["9"] + map_8["8"] + map_10["10"] + map_1["1"] + map_6["6"] + + space:15 + + m_shards["shards"]:2 + space + m_shard_0["0"] + m_shard_1["1"] + m_shard_2["2"] + m_shard_3["3"] + m_shard_4["4"] + m_shard_5["5"] + m_shard_6["6"] + m_shard_7["7"] + m_shard_8["8"] + m_shard_9["9"] + m_shard_10["10"] + m_shard_11["11"] + + nodes["nodes"]:2 + space + node_a["node A"]:4 + node_b["node B"]:4 + node_c["node C"]:4 + + style m_shard_3 fill:#969,stroke:#333,stroke-width:4px + style m_shard_0 fill:#969,stroke:#333,stroke-width:4px + style m_shard_7 fill:#969,stroke:#333,stroke-width:4px + style m_shard_9 fill:#969,stroke:#333,stroke-width:4px + + ds_4 --> map_3 + map_3 --> m_shard_3 + + ds_5 --> map_0 + map_0 --> m_shard_0 + + ds_6 --> map_7 + map_7 --> m_shard_7 + + ds_7 --> map_9 + map_9 --> m_shard_9 +``` + +In the current implementation, the mapping is a simple permutation generated with a predefined random seed using the +Fisher-Yates: when N new shards added or removed, at max N shards are moved to a different node. Ideally, the random +distribution should ensure uniform distribution of the shards across the nodes. + +Now, if node B fails, its shards are distributed among the remaining nodes, which ensures that the load is distributed +evenly even in case of a failure. In our example: +1. Suppose, we selected shard 6. +2. It's routed to node B via the mapping table. +3. An attempt to store a profile in the shard 6 fails because of the node failure. +4. We pick the next location (7) which is then mapped to node C. +5. Until node B is back, we will route writes to the shard 6 to node C. + +> Use of continuous shard ranges in subrings allows to minimize the number of datasets affected by a topology change: +ones that overlap the parent ring boundaries are affected the most, and it is expected that a dataset may change its +mapping entirely. However, such impact is preferable over the alternative, where larger number of datasets is affected +in a more subtle way. + +## Placement management + +Placement is managed by the Placement Manager, which resides in the metastore. The Placement Manager is a singleton and +runs only on the Raft leader node. + +The Placement Manager keeps track of dataset statistics based on the metadata records received from the segment-writer +service instances. Currently, the only metric that affects placement is the dataset size after it is written in the wire +format. + +The Placement Manager builds placement rules at regular intervals, which are then used by the distributor to determine +the placement for each received profile. Since actual data re-balancing is not performed, the placement rules are not +synchronized across the distributor instances. + +```mermaid +graph LR + Distributor==>SegmentWriter + PlacementAgent-.-PlacementRules + SegmentWriter-->|metadata|PlacementManager + SegmentWriter==>|data|Segments + PlacementManager-.->PlacementRules + + subgraph Distributor["distributor"] + PlacementAgent + end + + subgraph Metastore["metastore"] + PlacementManager + end + + subgraph ObjectStore["object store"] + PlacementRules(placement rules) + Segments(segments) + end + + subgraph SegmentWriter["segment-writer"] + end +``` + +Placement rules are defined in the [protobuf format](placement/adaptive_placement/adaptive_placementpb/adaptive_placement.proto). + +As of now, placement rules do not include the exact shards and mappings to nodes. Instead, they specify how many shards +are allocated for a specific dataset and tenant, and what load balancing strategy should be used: `fingerprint mod` or +`round robin`. In the future, placement management might be extended to include direct shard-to-node mappings, thus +implementing directory-based sharding. + +There are a number of basic heuristics to determine the minimal sufficient number of shards for a dataset with a minimal +control options. Specifically, due to a substantial lag in the feedback loop (up to tens of seconds), shard allocation +is pessimistic and may lead to over-allocation of shards if a persistent burst trend is observed. Conversely, when the +observed data rate decreases, the number of shards is not reduced immediately. diff --git a/pkg/segmentwriter/client/distributor/distribution_key.go b/pkg/segmentwriter/client/distributor/distribution_key.go new file mode 100644 index 0000000000..d4449c7fc8 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/distribution_key.go @@ -0,0 +1,24 @@ +package distributor + +import ( + "github.com/cespare/xxhash/v2" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" +) + +// NewTenantServiceDatasetKey builds a distribution key, where the dataset +// is the service name, and the fingerprint is the hash of the labels. +// The resulting key references the tenant and dataset strings. +func NewTenantServiceDatasetKey(tenant string, labels ...*typesv1.LabelPair) placement.Key { + dataset := phlaremodel.Labels(labels).Get(phlaremodel.LabelNameServiceName) + return placement.Key{ + TenantID: tenant, + DatasetName: dataset, + + Tenant: xxhash.Sum64String(tenant), + Dataset: xxhash.Sum64String(dataset), + Fingerprint: phlaremodel.Labels(labels).Hash(), + } +} diff --git a/pkg/segmentwriter/client/distributor/distributor.go b/pkg/segmentwriter/client/distributor/distributor.go new file mode 100644 index 0000000000..8140e58b35 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/distributor.go @@ -0,0 +1,346 @@ +package distributor + +import ( + "fmt" + "math/rand" + "slices" + "strings" + "sync" + "time" + + "github.com/grafana/dskit/ring" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" +) + +// NOTE(kolesnikovae): Essentially, we do not depend on the dskit/ring and +// only use it as a discovery mechanism build on top of the memberlist. +// It would be better to access the memberlist/serf directly. +var op = ring.NewOp([]ring.InstanceState{ring.ACTIVE, ring.LEAVING, ring.PENDING, ring.JOINING}, nil) + +const defaultRingUpdateInterval = 5 * time.Second + +type Distributor struct { + mu sync.RWMutex + ring ring.ReadRing + placement placement.Placement + distribution *distribution + + RingUpdateInterval time.Duration +} + +func NewDistributor(placement placement.Placement, r ring.ReadRing) *Distributor { + return &Distributor{ + ring: r, + placement: placement, + RingUpdateInterval: defaultRingUpdateInterval, + } +} + +func (d *Distributor) Distribute(k placement.Key) (*placement.ShardMapping, error) { + if err := d.updateDistribution(d.ring, d.RingUpdateInterval); err != nil { + return nil, err + } + return d.distribute(k), nil +} + +func (d *Distributor) updateDistribution(r ring.ReadRing, maxAge time.Duration) error { + d.mu.RLock() + x := d.distribution + if x != nil && !x.isExpired(maxAge) { + d.mu.RUnlock() + return nil + } + d.mu.RUnlock() + d.mu.Lock() + defer d.mu.Unlock() + x = d.distribution + if x != nil && !x.isExpired(maxAge) { + return nil + } + if x == nil { + x = newDistribution() + } + if err := x.readRing(r); err != nil { + return fmt.Errorf("failed to read ring: %w", err) + } + d.distribution = x + return nil +} + +// emptyMapping is returned by distributor if the ring is empty. +// This helps to handle a case when requests arrive before the +// ring is populated (no instances registered). +var emptyMapping = &placement.ShardMapping{ + Instances: iter.NewEmptyIterator[ring.InstanceDesc](), + Shard: 0, +} + +func (d *Distributor) distribute(k placement.Key) *placement.ShardMapping { + d.mu.RLock() + defer d.mu.RUnlock() + // Determine the number of shards for the tenant within the available + // space, and the dataset shards within the tenant subring. + s := len(d.distribution.shards) + if s == 0 { + return emptyMapping + } + p := d.placement.Policy(k) + tenantSize := p.TenantShards + if tenantSize == 0 || tenantSize > s { + tenantSize = s + } + datasetSize := min(tenantSize, max(1, p.DatasetShards)) + // When we create subrings, we need to ensure that each of them has at + // least p shards. However, the data distribution must be restricted + // according to the limits. + all := newSubring(s) + tenant := all.subring(k.Tenant, tenantSize) + dataset := tenant.subring(k.Dataset, datasetSize) + // We pick a shard from the dataset subring: its index is relative + // to the dataset subring. + offset := p.PickShard(datasetSize) + // Next we want to find p instances eligible to host the key. + // The choice must be limited to the dataset / tenant subring, + // but extended if needed. + return &placement.ShardMapping{ + Shard: uint32(dataset.at(offset)) + 1, // 0 shard ID is a sentinel + Instances: d.distribution.instances(dataset, offset), + } +} + +type distribution struct { + timestamp time.Time + shards []uint32 // Shard ID -> Instance ID. + desc []ring.InstanceDesc + perm *perm +} + +func newDistribution() *distribution { + return &distribution{ + timestamp: time.Now(), + perm: new(perm), + } +} + +func (d *distribution) isExpired(maxAge time.Duration) bool { + return time.Now().Add(-maxAge).After(d.timestamp) +} + +func (d *distribution) readRing(r ring.ReadRing) error { + all, err := r.GetAllHealthy(op) + if err != nil { + return err + } + if len(all.Instances) == 0 { + return ring.ErrEmptyRing + } + d.timestamp = time.Now() + d.desc = all.Instances + // Jump consistent hashing requires a deterministic order of instances. + // Moreover, instances can be only added to the end, otherwise this may + // cause massive relocations. + slices.SortFunc(d.desc, func(a, b ring.InstanceDesc) int { + return strings.Compare(a.Id, b.Id) + }) + // Now we create a mapping of shards to instances. + var tmp [256]uint32 // Try to allocate on stack. + instances := tmp[:0] + for j := range d.desc { + for range all.Instances[j].Tokens { + instances = append(instances, uint32(j)) + } + } + // We use shuffling to avoid hotspots: a contiguous range of shards + // is distributed over instances in a pseudo-random fashion. + // Given that the number of shards and instances is known in advance, + // we maintain a deterministic permutation that perturbs as little as + // possible, when the number of shards or instances changes: only the + // delta moves. + size := len(instances) + d.perm.resize(size) + // Note that we can't reuse d.shards because it may be used by iterators. + // In fact, this is a snapshot that must not be modified. + d.shards = make([]uint32, size) + for j := range d.shards { + d.shards[j] = instances[d.perm.v[j]] + } + return nil +} + +// instances returns an iterator that iterates over instances +// that may host the shard at the offset in the order of preference: +// dataset -> tenant -> all shards. +func (d *distribution) instances(r subring, off int) *iterator { + return &iterator{ + off: off, + lim: r.size(), + ring: r, + shards: d.shards, + desc: d.desc, + } +} + +// The inputs are a key and the number of buckets. +// It outputs a bucket number in the range [0, buckets). +// +// Refer to https://arxiv.org/pdf/1406.2294: +// The function satisfies the two properties: +// 1. About the same number of keys map to each bucket. +// 2. The mapping from key to bucket is perturbed as little as possible when +// the number of buckets is changed. Thus, the only data that needs to move +// when the number of buckets changes is the data for the relatively small +// number of keys whose bucket assignment changed. +func jump(key uint64, buckets int) int { + var b, j = -1, 0 + for j < buckets { + b = j + key = key*2862933555777941757 + 1 + j = int(float64(b+1) * (float64(int64(1)<<31) / float64((key>>33)+1))) + } + return b +} + +// Subring is a utility to calculate the subring +// for a given key within the available space: +// +// Note that this is not a recursive implementation, +// but a more straightforward one, optimized for the +// case where there can be up to two nested rings. +type subring struct { + // |<---------n----------->| Available space. + // | . a---|---------b . . | Ring. + // | . . . c-----d . . . . | Subring. + n, a, b, c, d int +} + +func newSubring(n int) subring { return subring{n: n, b: n, d: n} } + +// The function creates a subring of the specified size for the given key. +// The subring offset is calculated with the jump function. +func (s subring) subring(k uint64, size int) subring { + n := s + n.a, n.b = n.c, n.d + n.c = n.a + jump(k, n.b-n.a) + n.d = n.c + size + return n +} + +func (s subring) pop() subring { + n := s + n.c, n.d = n.a, n.b + n.a, n.b = 0, n.n + return n +} + +// The function returns the absolute offset of the relative n. +func (s subring) at(n int) int { + // [ . a-------|-----b . . ] + // [ . . . . . c-----|-x-d ] + // + // [ . a-------|-----b . . ] + // [ . |-x-d . c-----| . . ] + n %= s.d - s.c + x := s.c + n + x = (x - s.a) % (s.b - s.a) + p := (x + s.a) % s.n + return p +} + +// offset reports offset in the parent ring. +func (s subring) offset() int { return s.c - s.a } + +// size reports the size of the ring. +func (s subring) size() int { return s.d - s.c } + +// iterator iterates instances that host the shards of the subring. +// The iterator is not limited to the subring, and will continue with +// the parent subring when the current one is exhausted. +type iterator struct { + n int // Number of instances collected. + off int // Current offset in the ring (relative). + lim int // Remaining instances in the subring. + + ring subring + shards []uint32 + desc []ring.InstanceDesc +} + +func (i *iterator) Err() error { return nil } + +func (i *iterator) Close() error { return nil } + +func (i *iterator) Next() bool { + if i.n >= i.ring.n { + return false + } + if i.lim > 0 { + i.lim-- + } else { + for i.lim <= 0 { + // We have exhausted the subring. + // Navigate to the parent ring. + if i.ring.n == i.ring.size() { + // No parent rings left. + return false + } + // Start with the offset right after the subring. + size := i.ring.size() + i.off = i.ring.offset() + size + p := i.ring.pop() // Load parent. + // How many items remain in the ring. + i.lim = p.size() - size - 1 + i.ring = p + } + } + i.off++ + i.n++ + return true +} + +func (i *iterator) At() ring.InstanceDesc { + a := i.ring.at(i.off - 1) // Translate the relative offset to absolute. + x := i.shards[a] // Map the shard to the instance. + return i.desc[x] +} + +// Fisher–Yates shuffle with predefined steps. +// Rand source with a seed is not enough as we +// can't guarantee the same sequence of calls +// with identical arguments, which would make +// the state of two instances incoherent. +type perm struct{ v []uint32 } + +func (p *perm) resize(n int) { + d := max(0, n-len(p.v)) + p.v = slices.Grow(p.v, d)[:n] + // We do want to start with 0 (in contrast to the standard + // implementation) as this is required for the n == 1 case: + // we need to zero v[0]. + // Although, it's possible to make the change incrementally, + // for simplicity, we just rebuild the permutation. + for i := 0; i < n; i++ { + j := steps[i] + p.v[i], p.v[j] = p.v[j], uint32(i) + } +} + +var steps [4 << 10]uint32 + +func init() { + // The seed impacts mapping of shards to nodes. + // TODO(kolesnikovae): + // Stochastic approach does not work well + // in all the cases; it should be replaced + // with a deterministic one. + const randSeed = -3035313949336265834 + setSeed(randSeed) +} + +func setSeed(n int64) { + r := rand.New(rand.NewSource(n)) + for i := range steps { + steps[i] = uint32(r.Intn(i + 1)) + } +} diff --git a/pkg/segmentwriter/client/distributor/distributor_test.go b/pkg/segmentwriter/client/distributor/distributor_test.go new file mode 100644 index 0000000000..0c28d3fd56 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/distributor_test.go @@ -0,0 +1,453 @@ +package distributor + +import ( + "bytes" + "fmt" + "testing" + + "github.com/grafana/dskit/ring" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockplacement" + "github.com/grafana/pyroscope/v2/pkg/testhelper" +) + +// TODO(kolesnikovae): Test distribution fairness. + +var ( + testLabels = []*typesv1.LabelPair{ + {Name: "foo", Value: "bar"}, + {Name: "baz", Value: "qux"}, + {Name: "service_name", Value: "my-service"}, + } + testInstances = []ring.InstanceDesc{ + {Id: "a", Tokens: make([]uint32, 1)}, + {Id: "b", Tokens: make([]uint32, 1)}, + {Id: "c", State: ring.LEAVING, Tokens: make([]uint32, 1)}, + } + zeroShard = func(int) int { return 0 } +) + +func Test_EmptyRing(t *testing.T) { + m := new(mockplacement.MockPlacement) + r := testhelper.NewMockRing(nil, 1) + d := NewDistributor(m, r) + + k := NewTenantServiceDatasetKey("") + _, err := d.Distribute(k) + assert.ErrorIs(t, err, ring.ErrEmptyRing) +} + +func Test_Distribution_AvailableShards(t *testing.T) { + for _, tc := range []struct { + description string + placement.Policy + }{ + { + description: "zero", + Policy: placement.Policy{ + TenantShards: 0, + DatasetShards: 0, + PickShard: zeroShard, + }, + }, + { + description: "min", + Policy: placement.Policy{ + TenantShards: 1, + DatasetShards: 1, + PickShard: zeroShard, + }, + }, + { + description: "insufficient", + Policy: placement.Policy{ + TenantShards: 1 << 10, + DatasetShards: 1 << 9, + PickShard: zeroShard, + }, + }, + { + description: "invalid", + Policy: placement.Policy{ + TenantShards: 1 << 10, + DatasetShards: 2 << 10, + PickShard: zeroShard, + }, + }, + } { + t.Run(tc.description, func(t *testing.T) { + k := NewTenantServiceDatasetKey("tenant-a", testLabels...) + m := new(mockplacement.MockPlacement) + m.On("Policy", k, mock.Anything).Return(tc.Policy).Once() + r := testhelper.NewMockRing(testInstances, 1) + d := NewDistributor(m, r) + p, err := d.Distribute(k) + require.NoError(t, err) + c := make([]ring.InstanceDesc, 0, 2) + for p.Instances.Next() { + c = append(c, p.Instances.At()) + } + + assert.Equal(t, 3, len(c)) + m.AssertExpectations(t) + }) + } +} + +func Test_RingUpdate(t *testing.T) { + k := NewTenantServiceDatasetKey("") + m := new(mockplacement.MockPlacement) + m.On("Policy", k, mock.Anything).Return(placement.Policy{ + TenantShards: 1, + DatasetShards: 1, + PickShard: zeroShard, + }) + + r := testhelper.NewMockRing(testInstances, 1) + d := NewDistributor(m, r) + _, err := d.Distribute(k) + require.NoError(t, err) + + instances := make([]ring.InstanceDesc, 2) + copy(instances, testInstances[:1]) + r.SetInstances(instances) + require.NoError(t, d.updateDistribution(r, 0)) + + p, err := d.Distribute(k) + require.NoError(t, err) + c := make([]ring.InstanceDesc, 0, 1) + for p.Instances.Next() { + c = append(c, p.Instances.At()) + } + + // Only one instance is available. + assert.Equal(t, 1, len(c)) + m.AssertExpectations(t) +} + +func Test_Distributor_Distribute(t *testing.T) { + m := new(mockplacement.MockPlacement) + r := testhelper.NewMockRing([]ring.InstanceDesc{ + {Id: "a", Tokens: make([]uint32, 4)}, + {Id: "b", Tokens: make([]uint32, 4)}, + {Id: "c", Tokens: make([]uint32, 4)}, + }, 1) + + d := NewDistributor(m, r) + collect := func(offset, n int) []string { + h := uint64(14046587775414411003) + k := placement.Key{ + Tenant: h, + Dataset: h, + Fingerprint: h, + } + m.On("Policy", k).Return(placement.Policy{ + TenantShards: 8, + DatasetShards: 4, + PickShard: func(int) int { return offset }, + }).Once() + p, err := d.Distribute(k) + require.NoError(t, err) + return collectN(p.Instances, n) + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 all shards + // * * * * > * * * tenant (size 8, offset 8) + // > * * * dataset (size 4, offset 6+8 mod 12 = 2) + // 2 1 0 1 1 2 2 0 1 0 0 2 shuffling (see d.distribution.shards) + // ---------------------------------------------------------------------- + // 0 1 2 3 4 PickShard 0 (offset within dataset) + // ^ borrowed from the tenant + // + // 3 0 1 2 4 PickShard 1 + // 2 3 0 1 4 PickShard 2 + // 1 2 3 0 4 PickShard 3 + + // Identical keys have identical placement. + assert.Equal(t, []string{"a", "b", "b", "a", "a"}, collect(0, 5)) + assert.Equal(t, []string{"a", "b", "b", "a", "a"}, collect(0, 5)) + + // Placement of different keys in the dataset is bound. + assert.Equal(t, []string{"b", "b", "a", "a", "a"}, collect(1, 5)) + assert.Equal(t, []string{"b", "a", "a", "b", "a"}, collect(2, 5)) + assert.Equal(t, []string{"a", "a", "b", "b", "a"}, collect(3, 5)) + + // Now we're trying to collect more instances than available. + // 0 1 2 3 4 5 6 7 8 9 10 11 all shards + // * * * * > * * * tenant (size 8, offset 8) + // > * x * dataset (size 4, offset 6+8 mod 12 = 2) + // 0 1 2 PickShard 2 (13) + // 6 7 2 3 8 9 10 11 0 1 4 5 + // ^ ^ ^ ^ borrowed from the tenant + // ^ ^ ^ ^ borrowed from the top ring + // 2 1 0 1 1 2 2 0 1 0 0 2 shuffling (see d.distribution.shards) + assert.Equal(t, []string{"b", "a", "a", "b", "a", "c", "c", "b", "b", "c", "c", "a"}, collect(2, 13)) +} + +func Test_distribution_iterator(t *testing.T) { + d := &distribution{ + shards: []uint32{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2}, + desc: []ring.InstanceDesc{{Id: "a"}, {Id: "b"}, {Id: "c"}}, + } + + t.Run("empty ring", func(t *testing.T) { + assert.Equal(t, []string{}, collectN(d.instances(subring{}, 0), 10)) + }) + + t.Run("matching subrings", func(t *testing.T) { + r := subring{ + n: 12, + a: 8, + b: 16, + c: 8, + d: 16, + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 all shards + // a a a a b b b b c c c c no shuffling (!) + // * * * * > * * * tenant (size 8, offset 8) + // * * * * > * * * dataset (size 8, offset 8) + // + // 4 5 6 7|8 9 10 11|0 1 2 3 PickShard 0 (offset within dataset/tenant) + // 3 4 5 6|8 9 10 11|7 0 1 2 PickShard 1 + // 2 3 4 5|8 9 10 11|6 7 0 1 PickShard 2 + + var expected bytes.Buffer + for _, line := range []string{ + "0 [c c c c a a a a b b b b]", + "1 [c c c a a a a c b b b b]", + "2 [c c a a a a c c b b b b]", + "3 [c a a a a c c c b b b b]", + "4 [a a a a c c c c b b b b]", + "5 [a a a c c c c a b b b b]", + "6 [a a c c c c a a b b b b]", + "7 [a c c c c a a a b b b b]", + "8 [c c c c a a a a b b b b]", + "9 [c c c a a a a c b b b b]", + } { + _, _ = fmt.Fprintln(&expected, line) + } + + var actual bytes.Buffer + for i := 0; i < 10; i++ { + _, _ = fmt.Fprintln(&actual, i, collectN(d.instances(r, i), 20)) + } + + assert.Equal(t, expected.String(), actual.String()) + }) + + t.Run("nested subrings", func(t *testing.T) { + r := subring{ + n: 12, + a: 1, + b: 9, + c: 3, + d: 7, + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 all shards + // a a a a b b b b c c c c no shuffling (!) + // > * * * * * * * tenant (size 8, offset 1) + // > * * * dataset (size 4, offset 3) + // + // 11 4 5 0 1 2 3 6 7 8 9 10 PickShard 0 (offset within dataset) + // 11 4 5 3 0 1 2 6 7 8 9 10 PickShard 1 + + var expected bytes.Buffer + for _, line := range []string{ + "0 [a b b b b c a a c c c a]", + "1 [b b b a b c a a c c c a]", + "2 [b b a b b c a a c c c a]", + "3 [b a b b b c a a c c c a]", + "4 [a b b b b c a a c c c a]", + "5 [b b b a b c a a c c c a]", + "6 [b b a b b c a a c c c a]", + "7 [b a b b b c a a c c c a]", + "8 [a b b b b c a a c c c a]", + "9 [b b b a b c a a c c c a]", + } { + _, _ = fmt.Fprintln(&expected, line) + } + + var actual bytes.Buffer + for i := 0; i < 10; i++ { + _, _ = fmt.Fprintln(&actual, i, collectN(d.instances(r, i), 20)) + } + + assert.Equal(t, expected.String(), actual.String()) + }) + + t.Run("nested subrings aligned", func(t *testing.T) { + r := subring{ + n: 12, + a: 1, + b: 9, + c: 1, + d: 5, + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 all shards + // a a a a b b b b c c c c no shuffling (!) + // > * * * * * * * tenant (size 8, offset 1) + // > * * * dataset (size 4, offset 1) + + var expected bytes.Buffer + for _, line := range []string{ + "0 [a a a b b b b c c c c a]", + "1 [a a b a b b b c c c c a]", + "2 [a b a a b b b c c c c a]", + "3 [b a a a b b b c c c c a]", + "4 [a a a b b b b c c c c a]", + "5 [a a b a b b b c c c c a]", + "6 [a b a a b b b c c c c a]", + "7 [b a a a b b b c c c c a]", + "8 [a a a b b b b c c c c a]", + "9 [a a b a b b b c c c c a]", + } { + _, _ = fmt.Fprintln(&expected, line) + } + + var actual bytes.Buffer + for i := 0; i < 10; i++ { + _, _ = fmt.Fprintln(&actual, i, collectN(d.instances(r, i), 20)) + } + + assert.Equal(t, expected.String(), actual.String()) + }) + + t.Run("nested subrings wrap", func(t *testing.T) { + r := subring{ + n: 12, + a: 8, + b: 16, + c: 10, + d: 14, + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 all shards + // a a a a b b b b c c c c no shuffling (!) + // * * * * > * * * tenant (size 8, offset 8) + // * * > * dataset (size 4, offset 14 mod 12 = 2) + + var expected bytes.Buffer + for _, line := range []string{ + "0 [c c a a a a c c b b b b]", + "1 [c a a c a a c c b b b b]", + "2 [a a c c a a c c b b b b]", + "3 [a c c a a a c c b b b b]", + "4 [c c a a a a c c b b b b]", + "5 [c a a c a a c c b b b b]", + "6 [a a c c a a c c b b b b]", + "7 [a c c a a a c c b b b b]", + "8 [c c a a a a c c b b b b]", + "9 [c a a c a a c c b b b b]", + } { + _, _ = fmt.Fprintln(&expected, line) + } + + var actual bytes.Buffer + for i := 0; i < 10; i++ { + _, _ = fmt.Fprintln(&actual, i, collectN(d.instances(r, i), 20)) + } + + assert.Equal(t, expected.String(), actual.String()) + }) + + t.Run("overlapping subrings", func(t *testing.T) { + r := subring{ + n: 12, + a: 8, + b: 16, + c: 14, + d: 18, + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 all shards + // a a a a b b b b c c c c no shuffling (!) + // * * * * > * * * tenant (size 8, offset 8) + // > * * * dataset (size 4, offset 14 mod 12 = 2) + // 6 7|0 1|8 9 10 11|2 3|4 5 PickShard 0 (offset within dataset) + // 6 7|3 0|8 9 10 11|1 2|4 5 PickShard 1 + // 6 7|2 3|8 9 10 11|0 1|4 5 PickShard 2 + // 6 7|1 2|8 9 10 11|3 0|4 5 PickShard 3 + + var expected bytes.Buffer + for _, line := range []string{ + "0 [a a c c c c a a b b b b]", + "1 [a c c a c c a a b b b b]", + "2 [c c a a c c a a b b b b]", + "3 [c a a c c c a a b b b b]", + "4 [a a c c c c a a b b b b]", + "5 [a c c a c c a a b b b b]", + "6 [c c a a c c a a b b b b]", + "7 [c a a c c c a a b b b b]", + "8 [a a c c c c a a b b b b]", + "9 [a c c a c c a a b b b b]", + } { + _, _ = fmt.Fprintln(&expected, line) + } + + var actual bytes.Buffer + for i := 0; i < 10; i++ { + _, _ = fmt.Fprintln(&actual, i, collectN(d.instances(r, i), 20)) + } + + assert.Equal(t, expected.String(), actual.String()) + }) +} + +func Test_permutation(t *testing.T) { + actual := make([][]uint32, 0, 16) + copyP := func(s []uint32) []uint32 { + c := make([]uint32, len(s)) + copy(c, s) + return c + } + + var p perm + for i := 0; i <= 32; i += 4 { + p.resize(i) + actual = append(actual, copyP(p.v)) + } + for i := 32; i >= 0; i -= 4 { + p.resize(i) + actual = append(actual, copyP(p.v)) + } + expected := [][]uint32{ + {}, + {3, 1, 0, 2}, + {3, 6, 0, 5, 7, 4, 1, 2}, + {11, 6, 0, 5, 7, 8, 9, 2, 4, 1, 3, 10}, + {11, 6, 0, 5, 14, 8, 15, 2, 12, 1, 3, 13, 4, 10, 7, 9}, + {11, 6, 0, 19, 14, 8, 15, 2, 12, 17, 3, 18, 4, 16, 7, 9, 10, 1, 13, 5}, + {11, 6, 0, 19, 14, 8, 15, 2, 21, 17, 3, 18, 4, 16, 7, 22, 10, 1, 23, 5, 9, 12, 20, 13}, + {11, 6, 0, 19, 14, 8, 15, 2, 26, 17, 25, 18, 24, 16, 7, 22, 10, 1, 23, 5, 9, 12, 20, 13, 4, 3, 27, 21}, + {11, 6, 0, 28, 31, 8, 15, 2, 26, 17, 25, 18, 24, 16, 7, 22, 10, 1, 23, 5, 30, 12, 20, 13, 4, 29, 27, 21, 19, 3, 9, 14}, + {11, 6, 0, 28, 31, 8, 15, 2, 26, 17, 25, 18, 24, 16, 7, 22, 10, 1, 23, 5, 30, 12, 20, 13, 4, 29, 27, 21, 19, 3, 9, 14}, + {11, 6, 0, 19, 14, 8, 15, 2, 26, 17, 25, 18, 24, 16, 7, 22, 10, 1, 23, 5, 9, 12, 20, 13, 4, 3, 27, 21}, + {11, 6, 0, 19, 14, 8, 15, 2, 21, 17, 3, 18, 4, 16, 7, 22, 10, 1, 23, 5, 9, 12, 20, 13}, + {11, 6, 0, 19, 14, 8, 15, 2, 12, 17, 3, 18, 4, 16, 7, 9, 10, 1, 13, 5}, + {11, 6, 0, 5, 14, 8, 15, 2, 12, 1, 3, 13, 4, 10, 7, 9}, + {11, 6, 0, 5, 7, 8, 9, 2, 4, 1, 3, 10}, + {3, 6, 0, 5, 7, 4, 1, 2}, + {3, 1, 0, 2}, + {}, + } + + assert.Equal(t, expected, actual) +} + +func collectN(i iter.Iterator[ring.InstanceDesc], n int) []string { + s := make([]string, 0, n) + for n > 0 && i.Next() { + s = append(s, i.At().Id) + n-- + } + return s +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placement.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placement.go new file mode 100644 index 0000000000..592081a008 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placement.go @@ -0,0 +1,65 @@ +package adaptiveplacement + +import ( + "go.uber.org/atomic" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +// AdaptivePlacement is a placement policy that +// adapts to the distribution of data. +// +// It uses a set of rules to determine the number +// of shards to allocate to each tenant and dataset, +// and a load balancing function to distribute the +// dataset keys. +type AdaptivePlacement struct { + datasets atomic.Pointer[map[datasetKey]*adaptive_placementpb.DatasetPlacement] + limits Limits +} + +func NewAdaptivePlacement(limits Limits) *AdaptivePlacement { + return &AdaptivePlacement{limits: limits} +} + +func (a *AdaptivePlacement) Policy(k placement.Key) placement.Policy { + dk := datasetKey{ + tenant: k.TenantID, + dataset: k.DatasetName, + } + datasets := a.datasets.Load() + if datasets == nil { + return a.defaultPolicy(k) + } + dataset, ok := (*datasets)[dk] + if !ok { + return a.defaultPolicy(k) + } + return placement.Policy{ + TenantShards: int(dataset.TenantShardLimit), + DatasetShards: int(dataset.DatasetShardLimit), + PickShard: loadBalancingFromProto(dataset.LoadBalancing).pick(k), + } +} + +func (a *AdaptivePlacement) defaultPolicy(k placement.Key) placement.Policy { + limits := a.limits.PlacementLimits(k.TenantID) + return placement.Policy{ + TenantShards: int(limits.TenantShards), + DatasetShards: int(limits.DefaultDatasetShards), + PickShard: limits.LoadBalancing.pick(k), + } +} + +func (a *AdaptivePlacement) Update(rules *adaptive_placementpb.PlacementRules) { + datasets := make(map[datasetKey]*adaptive_placementpb.DatasetPlacement, len(rules.Datasets)) + for _, dataset := range rules.Datasets { + k := datasetKey{ + tenant: rules.Tenants[dataset.Tenant].TenantId, + dataset: dataset.Name, + } + datasets[k] = dataset + } + a.datasets.Store(&datasets) +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placement_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placement_test.go new file mode 100644 index 0000000000..8412f8301b --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placement_test.go @@ -0,0 +1,131 @@ +package adaptiveplacement + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +func Test_AdaptivePlacement(t *testing.T) { + const unitSize = 512 << 10 + defaults := PlacementLimits{ + TenantShards: 10, + DefaultDatasetShards: 2, + MinDatasetShards: 1, + MaxDatasetShards: 10, + UnitSizeBytes: unitSize, + BurstWindow: 17 * time.Minute, + DecayWindow: 19 * time.Minute, + LoadBalancing: DynamicLoadBalancing, + } + + withDefaults := func(fn func(*PlacementLimits)) PlacementLimits { + limits := defaults + fn(&limits) + return limits + } + + m := new(mockLimits) + m.On("PlacementLimits", "tenant-a").Return(withDefaults(func(l *PlacementLimits) {})) + m.On("PlacementLimits", "tenant-b").Return(withDefaults(func(l *PlacementLimits) { + l.TenantShards = 20 + l.DefaultDatasetShards = 3 + })) + + p := NewAdaptivePlacement(m) + + policy := p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-a", + }) + assert.Equal(t, 10, policy.TenantShards) + assert.Equal(t, 2, policy.DatasetShards) + assert.False(t, isRoundRobin(policy.PickShard)) + + policy = p.Policy(placement.Key{ + TenantID: "tenant-b", + DatasetName: "dataset-b-1", + }) + assert.Equal(t, 20, policy.TenantShards) + assert.Equal(t, 3, policy.DatasetShards) + assert.False(t, isRoundRobin(policy.PickShard)) + + // Load new rules and override limits for tenant-a dataset-a + p.Update(&adaptive_placementpb.PlacementRules{ + Tenants: []*adaptive_placementpb.TenantPlacement{ + {TenantId: "tenant-a"}, + {TenantId: "tenant-b"}, + {TenantId: "tenant-c"}, + }, + Datasets: []*adaptive_placementpb.DatasetPlacement{ + { + // A placement rule may have a newer/different limit for the tenant. + Tenant: 0, + Name: "dataset-a", + TenantShardLimit: 4, + DatasetShardLimit: 4, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN, + }, + { + Tenant: 0, + Name: "dataset-a-2", + TenantShardLimit: 4, + DatasetShardLimit: 1, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_FINGERPRINT, + }, + }, + CreatedAt: 1, + }) + + // Assert that the new rules impacted the placement policy for the dataset. + policy = p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-a", + }) + assert.Equal(t, 4, policy.TenantShards) + assert.Equal(t, 4, policy.DatasetShards) + assert.True(t, isRoundRobin(policy.PickShard)) + + // Other datasets of the tenant are not affected. + policy = p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-b", + }) + assert.Equal(t, 10, policy.TenantShards) + assert.Equal(t, 2, policy.DatasetShards) + assert.False(t, isRoundRobin(policy.PickShard)) + + policy = p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-a-2", + }) + assert.Equal(t, 4, policy.TenantShards) + assert.Equal(t, 1, policy.DatasetShards) + assert.False(t, isRoundRobin(policy.PickShard)) + + // Other tenants are not affected. + policy = p.Policy(placement.Key{ + TenantID: "tenant-b", + DatasetName: "dataset-b-1", + }) + assert.Equal(t, 20, policy.TenantShards) + assert.Equal(t, 3, policy.DatasetShards) + assert.False(t, isRoundRobin(policy.PickShard)) +} + +// This does not test the actual round-robin behavior, +// but rather that the function is not deterministic. +func isRoundRobin(fn func(int) int) bool { + const N = 10 + r := fn(N) + for i := 0; i < N; i++ { + if r != fn(N) { + return true + } + } + return false +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.pb.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.pb.go new file mode 100644 index 0000000000..0d25c403f6 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.pb.go @@ -0,0 +1,609 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.proto + +package adaptive_placementpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type LoadBalancing int32 + +const ( + LoadBalancing_LOAD_BALANCING_UNSPECIFIED LoadBalancing = 0 + LoadBalancing_LOAD_BALANCING_FINGERPRINT LoadBalancing = 1 + LoadBalancing_LOAD_BALANCING_ROUND_ROBIN LoadBalancing = 2 +) + +// Enum value maps for LoadBalancing. +var ( + LoadBalancing_name = map[int32]string{ + 0: "LOAD_BALANCING_UNSPECIFIED", + 1: "LOAD_BALANCING_FINGERPRINT", + 2: "LOAD_BALANCING_ROUND_ROBIN", + } + LoadBalancing_value = map[string]int32{ + "LOAD_BALANCING_UNSPECIFIED": 0, + "LOAD_BALANCING_FINGERPRINT": 1, + "LOAD_BALANCING_ROUND_ROBIN": 2, + } +) + +func (x LoadBalancing) Enum() *LoadBalancing { + p := new(LoadBalancing) + *p = x + return p +} + +func (x LoadBalancing) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LoadBalancing) Descriptor() protoreflect.EnumDescriptor { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_enumTypes[0].Descriptor() +} + +func (LoadBalancing) Type() protoreflect.EnumType { + return &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_enumTypes[0] +} + +func (x LoadBalancing) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LoadBalancing.Descriptor instead. +func (LoadBalancing) EnumDescriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{0} +} + +// DistributionStats includes the data the Placement is built based on. +type DistributionStats struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tenants []*TenantStats `protobuf:"bytes,1,rep,name=tenants,proto3" json:"tenants,omitempty"` + Datasets []*DatasetStats `protobuf:"bytes,2,rep,name=datasets,proto3" json:"datasets,omitempty"` + Shards []*ShardStats `protobuf:"bytes,3,rep,name=shards,proto3" json:"shards,omitempty"` + CreatedAt int64 `protobuf:"varint,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistributionStats) Reset() { + *x = DistributionStats{} + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistributionStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistributionStats) ProtoMessage() {} + +func (x *DistributionStats) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DistributionStats.ProtoReflect.Descriptor instead. +func (*DistributionStats) Descriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{0} +} + +func (x *DistributionStats) GetTenants() []*TenantStats { + if x != nil { + return x.Tenants + } + return nil +} + +func (x *DistributionStats) GetDatasets() []*DatasetStats { + if x != nil { + return x.Datasets + } + return nil +} + +func (x *DistributionStats) GetShards() []*ShardStats { + if x != nil { + return x.Shards + } + return nil +} + +func (x *DistributionStats) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +type TenantStats struct { + state protoimpl.MessageState `protogen:"open.v1"` + TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TenantStats) Reset() { + *x = TenantStats{} + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TenantStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TenantStats) ProtoMessage() {} + +func (x *TenantStats) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TenantStats.ProtoReflect.Descriptor instead. +func (*TenantStats) Descriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{1} +} + +func (x *TenantStats) GetTenantId() string { + if x != nil { + return x.TenantId + } + return "" +} + +type DatasetStats struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tenant uint32 `protobuf:"varint,1,opt,name=tenant,proto3" json:"tenant,omitempty"` // Reference to TenantStats. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Shard value is a reference to ShardStats. + Shards []uint32 `protobuf:"varint,3,rep,packed,name=shards,proto3" json:"shards,omitempty"` + // Data rate in bytes per second for each shard. + // The dataset size is measured after being encoded + // in the block wire format. + Usage []uint64 `protobuf:"varint,4,rep,packed,name=usage,proto3" json:"usage,omitempty"` + // Standard deviation of the data rate across shards + // aggregated within a sliding time window. + StdDev uint64 `protobuf:"varint,5,opt,name=std_dev,json=stdDev,proto3" json:"std_dev,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DatasetStats) Reset() { + *x = DatasetStats{} + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DatasetStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DatasetStats) ProtoMessage() {} + +func (x *DatasetStats) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DatasetStats.ProtoReflect.Descriptor instead. +func (*DatasetStats) Descriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{2} +} + +func (x *DatasetStats) GetTenant() uint32 { + if x != nil { + return x.Tenant + } + return 0 +} + +func (x *DatasetStats) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DatasetStats) GetShards() []uint32 { + if x != nil { + return x.Shards + } + return nil +} + +func (x *DatasetStats) GetUsage() []uint64 { + if x != nil { + return x.Usage + } + return nil +} + +func (x *DatasetStats) GetStdDev() uint64 { + if x != nil { + return x.StdDev + } + return 0 +} + +type ShardStats struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Shard ID. + Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // Owner represents the node that hosted the shard. + // There may be multiple entries for a single shard + // if it was relocated across different nodes. + Owner string `protobuf:"bytes,2,opt,name=owner,proto3" json:"owner,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ShardStats) Reset() { + *x = ShardStats{} + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ShardStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShardStats) ProtoMessage() {} + +func (x *ShardStats) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShardStats.ProtoReflect.Descriptor instead. +func (*ShardStats) Descriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{3} +} + +func (x *ShardStats) GetId() uint32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *ShardStats) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + +type PlacementRules struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tenants []*TenantPlacement `protobuf:"bytes,1,rep,name=tenants,proto3" json:"tenants,omitempty"` + Datasets []*DatasetPlacement `protobuf:"bytes,2,rep,name=datasets,proto3" json:"datasets,omitempty"` + CreatedAt int64 `protobuf:"varint,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PlacementRules) Reset() { + *x = PlacementRules{} + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PlacementRules) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlacementRules) ProtoMessage() {} + +func (x *PlacementRules) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlacementRules.ProtoReflect.Descriptor instead. +func (*PlacementRules) Descriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{4} +} + +func (x *PlacementRules) GetTenants() []*TenantPlacement { + if x != nil { + return x.Tenants + } + return nil +} + +func (x *PlacementRules) GetDatasets() []*DatasetPlacement { + if x != nil { + return x.Datasets + } + return nil +} + +func (x *PlacementRules) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +type TenantPlacement struct { + state protoimpl.MessageState `protogen:"open.v1"` + TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TenantPlacement) Reset() { + *x = TenantPlacement{} + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TenantPlacement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TenantPlacement) ProtoMessage() {} + +func (x *TenantPlacement) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TenantPlacement.ProtoReflect.Descriptor instead. +func (*TenantPlacement) Descriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{5} +} + +func (x *TenantPlacement) GetTenantId() string { + if x != nil { + return x.TenantId + } + return "" +} + +type DatasetPlacement struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tenant uint32 `protobuf:"varint,1,opt,name=tenant,proto3" json:"tenant,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + TenantShardLimit uint64 `protobuf:"varint,3,opt,name=tenant_shard_limit,json=tenantShardLimit,proto3" json:"tenant_shard_limit,omitempty"` + DatasetShardLimit uint64 `protobuf:"varint,4,opt,name=dataset_shard_limit,json=datasetShardLimit,proto3" json:"dataset_shard_limit,omitempty"` + LoadBalancing LoadBalancing `protobuf:"varint,5,opt,name=load_balancing,json=loadBalancing,proto3,enum=adaptive_placement.LoadBalancing" json:"load_balancing,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DatasetPlacement) Reset() { + *x = DatasetPlacement{} + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DatasetPlacement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DatasetPlacement) ProtoMessage() {} + +func (x *DatasetPlacement) ProtoReflect() protoreflect.Message { + mi := &file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DatasetPlacement.ProtoReflect.Descriptor instead. +func (*DatasetPlacement) Descriptor() ([]byte, []int) { + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP(), []int{6} +} + +func (x *DatasetPlacement) GetTenant() uint32 { + if x != nil { + return x.Tenant + } + return 0 +} + +func (x *DatasetPlacement) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DatasetPlacement) GetTenantShardLimit() uint64 { + if x != nil { + return x.TenantShardLimit + } + return 0 +} + +func (x *DatasetPlacement) GetDatasetShardLimit() uint64 { + if x != nil { + return x.DatasetShardLimit + } + return 0 +} + +func (x *DatasetPlacement) GetLoadBalancing() LoadBalancing { + if x != nil { + return x.LoadBalancing + } + return LoadBalancing_LOAD_BALANCING_UNSPECIFIED +} + +var File_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto protoreflect.FileDescriptor + +const file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDesc = "" + + "\n" + + "jsegmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.proto\x12\x12adaptive_placement\"\xe3\x01\n" + + "\x11DistributionStats\x129\n" + + "\atenants\x18\x01 \x03(\v2\x1f.adaptive_placement.TenantStatsR\atenants\x12<\n" + + "\bdatasets\x18\x02 \x03(\v2 .adaptive_placement.DatasetStatsR\bdatasets\x126\n" + + "\x06shards\x18\x03 \x03(\v2\x1e.adaptive_placement.ShardStatsR\x06shards\x12\x1d\n" + + "\n" + + "created_at\x18\x04 \x01(\x03R\tcreatedAt\"*\n" + + "\vTenantStats\x12\x1b\n" + + "\ttenant_id\x18\x01 \x01(\tR\btenantId\"\x81\x01\n" + + "\fDatasetStats\x12\x16\n" + + "\x06tenant\x18\x01 \x01(\rR\x06tenant\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x16\n" + + "\x06shards\x18\x03 \x03(\rR\x06shards\x12\x14\n" + + "\x05usage\x18\x04 \x03(\x04R\x05usage\x12\x17\n" + + "\astd_dev\x18\x05 \x01(\x04R\x06stdDev\"2\n" + + "\n" + + "ShardStats\x12\x0e\n" + + "\x02id\x18\x01 \x01(\rR\x02id\x12\x14\n" + + "\x05owner\x18\x02 \x01(\tR\x05owner\"\xb0\x01\n" + + "\x0ePlacementRules\x12=\n" + + "\atenants\x18\x01 \x03(\v2#.adaptive_placement.TenantPlacementR\atenants\x12@\n" + + "\bdatasets\x18\x02 \x03(\v2$.adaptive_placement.DatasetPlacementR\bdatasets\x12\x1d\n" + + "\n" + + "created_at\x18\x03 \x01(\x03R\tcreatedAt\".\n" + + "\x0fTenantPlacement\x12\x1b\n" + + "\ttenant_id\x18\x01 \x01(\tR\btenantId\"\xe6\x01\n" + + "\x10DatasetPlacement\x12\x16\n" + + "\x06tenant\x18\x01 \x01(\rR\x06tenant\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12,\n" + + "\x12tenant_shard_limit\x18\x03 \x01(\x04R\x10tenantShardLimit\x12.\n" + + "\x13dataset_shard_limit\x18\x04 \x01(\x04R\x11datasetShardLimit\x12H\n" + + "\x0eload_balancing\x18\x05 \x01(\x0e2!.adaptive_placement.LoadBalancingR\rloadBalancing*o\n" + + "\rLoadBalancing\x12\x1e\n" + + "\x1aLOAD_BALANCING_UNSPECIFIED\x10\x00\x12\x1e\n" + + "\x1aLOAD_BALANCING_FINGERPRINT\x10\x01\x12\x1e\n" + + "\x1aLOAD_BALANCING_ROUND_ROBIN\x10\x02B\x8b\x02\n" + + "\x16com.adaptive_placementB\x16AdaptivePlacementProtoP\x01Zugithub.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb\xa2\x02\x03AXX\xaa\x02\x11AdaptivePlacement\xca\x02\x11AdaptivePlacement\xe2\x02\x1dAdaptivePlacement\\GPBMetadata\xea\x02\x11AdaptivePlacementb\x06proto3" + +var ( + file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescOnce sync.Once + file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescData []byte +) + +func file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescGZIP() []byte { + file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescOnce.Do(func() { + file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDesc), len(file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDesc))) + }) + return file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDescData +} + +var file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_goTypes = []any{ + (LoadBalancing)(0), // 0: adaptive_placement.LoadBalancing + (*DistributionStats)(nil), // 1: adaptive_placement.DistributionStats + (*TenantStats)(nil), // 2: adaptive_placement.TenantStats + (*DatasetStats)(nil), // 3: adaptive_placement.DatasetStats + (*ShardStats)(nil), // 4: adaptive_placement.ShardStats + (*PlacementRules)(nil), // 5: adaptive_placement.PlacementRules + (*TenantPlacement)(nil), // 6: adaptive_placement.TenantPlacement + (*DatasetPlacement)(nil), // 7: adaptive_placement.DatasetPlacement +} +var file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_depIdxs = []int32{ + 2, // 0: adaptive_placement.DistributionStats.tenants:type_name -> adaptive_placement.TenantStats + 3, // 1: adaptive_placement.DistributionStats.datasets:type_name -> adaptive_placement.DatasetStats + 4, // 2: adaptive_placement.DistributionStats.shards:type_name -> adaptive_placement.ShardStats + 6, // 3: adaptive_placement.PlacementRules.tenants:type_name -> adaptive_placement.TenantPlacement + 7, // 4: adaptive_placement.PlacementRules.datasets:type_name -> adaptive_placement.DatasetPlacement + 0, // 5: adaptive_placement.DatasetPlacement.load_balancing:type_name -> adaptive_placement.LoadBalancing + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { + file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_init() +} +func file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_init() { + if File_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDesc), len(file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_rawDesc)), + NumEnums: 1, + NumMessages: 7, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_goTypes, + DependencyIndexes: file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_depIdxs, + EnumInfos: file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_enumTypes, + MessageInfos: file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_msgTypes, + }.Build() + File_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto = out.File + file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_goTypes = nil + file_segmentwriter_client_distributor_placement_adaptiveplacement_adaptive_placementpb_adaptive_placement_proto_depIdxs = nil +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.proto b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.proto new file mode 100644 index 0000000000..4bf7ead2e5 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.proto @@ -0,0 +1,62 @@ +syntax = "proto3"; + +package adaptive_placement; + +// DistributionStats includes the data the Placement is built based on. +message DistributionStats { + repeated TenantStats tenants = 1; + repeated DatasetStats datasets = 2; + repeated ShardStats shards = 3; + int64 created_at = 4; +} + +message TenantStats { + string tenant_id = 1; +} + +message DatasetStats { + uint32 tenant = 1; // Reference to TenantStats. + string name = 2; + // Shard value is a reference to ShardStats. + repeated uint32 shards = 3; + // Data rate in bytes per second for each shard. + // The dataset size is measured after being encoded + // in the block wire format. + repeated uint64 usage = 4; + // Standard deviation of the data rate across shards + // aggregated within a sliding time window. + uint64 std_dev = 5; +} + +message ShardStats { + // Shard ID. + uint32 id = 1; + // Owner represents the node that hosted the shard. + // There may be multiple entries for a single shard + // if it was relocated across different nodes. + string owner = 2; +} + +enum LoadBalancing { + LOAD_BALANCING_UNSPECIFIED = 0; + LOAD_BALANCING_FINGERPRINT = 1; + LOAD_BALANCING_ROUND_ROBIN = 2; +} + +message PlacementRules { + repeated TenantPlacement tenants = 1; + repeated DatasetPlacement datasets = 2; + int64 created_at = 3; +} + +message TenantPlacement { + string tenant_id = 1; +} + +message DatasetPlacement { + uint32 tenant = 1; + string name = 2; + uint64 tenant_shard_limit = 3; + uint64 dataset_shard_limit = 4; + LoadBalancing load_balancing = 5; +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement_vtproto.pb.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement_vtproto.pb.go new file mode 100644 index 0000000000..a7749cf241 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement_vtproto.pb.go @@ -0,0 +1,1602 @@ +// Code generated by protoc-gen-go-vtproto. DO NOT EDIT. +// protoc-gen-go-vtproto version: v0.6.0 +// source: segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb/adaptive_placement.proto + +package adaptive_placementpb + +import ( + fmt "fmt" + protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +func (m *DistributionStats) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DistributionStats) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DistributionStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CreatedAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CreatedAt)) + i-- + dAtA[i] = 0x20 + } + if len(m.Shards) > 0 { + for iNdEx := len(m.Shards) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Shards[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + } + if len(m.Datasets) > 0 { + for iNdEx := len(m.Datasets) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Datasets[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Tenants) > 0 { + for iNdEx := len(m.Tenants) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Tenants[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *TenantStats) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TenantStats) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TenantStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TenantId) > 0 { + i -= len(m.TenantId) + copy(dAtA[i:], m.TenantId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DatasetStats) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DatasetStats) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DatasetStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.StdDev != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.StdDev)) + i-- + dAtA[i] = 0x28 + } + if len(m.Usage) > 0 { + var pksize2 int + for _, num := range m.Usage { + pksize2 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize2 + j1 := i + for _, num := range m.Usage { + for num >= 1<<7 { + dAtA[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA[j1] = uint8(num) + j1++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2)) + i-- + dAtA[i] = 0x22 + } + if len(m.Shards) > 0 { + var pksize4 int + for _, num := range m.Shards { + pksize4 += protohelpers.SizeOfVarint(uint64(num)) + } + i -= pksize4 + j3 := i + for _, num := range m.Shards { + for num >= 1<<7 { + dAtA[j3] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j3++ + } + dAtA[j3] = uint8(num) + j3++ + } + i = protohelpers.EncodeVarint(dAtA, i, uint64(pksize4)) + i-- + dAtA[i] = 0x1a + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if m.Tenant != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tenant)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ShardStats) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ShardStats) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ShardStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0x12 + } + if m.Id != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *PlacementRules) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PlacementRules) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PlacementRules) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.CreatedAt != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CreatedAt)) + i-- + dAtA[i] = 0x18 + } + if len(m.Datasets) > 0 { + for iNdEx := len(m.Datasets) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Datasets[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Tenants) > 0 { + for iNdEx := len(m.Tenants) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Tenants[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *TenantPlacement) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TenantPlacement) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TenantPlacement) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.TenantId) > 0 { + i -= len(m.TenantId) + copy(dAtA[i:], m.TenantId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TenantId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DatasetPlacement) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DatasetPlacement) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DatasetPlacement) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.LoadBalancing != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.LoadBalancing)) + i-- + dAtA[i] = 0x28 + } + if m.DatasetShardLimit != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.DatasetShardLimit)) + i-- + dAtA[i] = 0x20 + } + if m.TenantShardLimit != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.TenantShardLimit)) + i-- + dAtA[i] = 0x18 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if m.Tenant != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tenant)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *DistributionStats) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Tenants) > 0 { + for _, e := range m.Tenants { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Datasets) > 0 { + for _, e := range m.Datasets { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Shards) > 0 { + for _, e := range m.Shards { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.CreatedAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CreatedAt)) + } + n += len(m.unknownFields) + return n +} + +func (m *TenantStats) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TenantId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DatasetStats) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Tenant != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Tenant)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Shards) > 0 { + l = 0 + for _, e := range m.Shards { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if len(m.Usage) > 0 { + l = 0 + for _, e := range m.Usage { + l += protohelpers.SizeOfVarint(uint64(e)) + } + n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l + } + if m.StdDev != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.StdDev)) + } + n += len(m.unknownFields) + return n +} + +func (m *ShardStats) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Id)) + } + l = len(m.Owner) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *PlacementRules) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Tenants) > 0 { + for _, e := range m.Tenants { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if len(m.Datasets) > 0 { + for _, e := range m.Datasets { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + if m.CreatedAt != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.CreatedAt)) + } + n += len(m.unknownFields) + return n +} + +func (m *TenantPlacement) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TenantId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DatasetPlacement) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Tenant != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Tenant)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.TenantShardLimit != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.TenantShardLimit)) + } + if m.DatasetShardLimit != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.DatasetShardLimit)) + } + if m.LoadBalancing != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.LoadBalancing)) + } + n += len(m.unknownFields) + return n +} + +func (m *DistributionStats) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DistributionStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DistributionStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenants", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenants = append(m.Tenants, &TenantStats{}) + if err := m.Tenants[len(m.Tenants)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Datasets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Datasets = append(m.Datasets, &DatasetStats{}) + if err := m.Datasets[len(m.Datasets)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Shards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Shards = append(m.Shards, &ShardStats{}) + if err := m.Shards[len(m.Shards)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) + } + m.CreatedAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreatedAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TenantStats) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TenantStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TenantStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DatasetStats) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DatasetStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DatasetStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + m.Tenant = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Tenant |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType == 0 { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Shards = append(m.Shards, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Shards) == 0 { + m.Shards = make([]uint32, 0, elementCount) + } + for iNdEx < postIndex { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Shards = append(m.Shards, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Shards", wireType) + } + case 4: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Usage = append(m.Usage, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Usage) == 0 { + m.Usage = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Usage = append(m.Usage, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StdDev", wireType) + } + m.StdDev = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StdDev |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ShardStats) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ShardStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ShardStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PlacementRules) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PlacementRules: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PlacementRules: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenants", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tenants = append(m.Tenants, &TenantPlacement{}) + if err := m.Tenants[len(m.Tenants)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Datasets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Datasets = append(m.Datasets, &DatasetPlacement{}) + if err := m.Datasets[len(m.Datasets)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) + } + m.CreatedAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreatedAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TenantPlacement) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TenantPlacement: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TenantPlacement: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TenantId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DatasetPlacement) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DatasetPlacement: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DatasetPlacement: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Tenant", wireType) + } + m.Tenant = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Tenant |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TenantShardLimit", wireType) + } + m.TenantShardLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TenantShardLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DatasetShardLimit", wireType) + } + m.DatasetShardLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DatasetShardLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LoadBalancing", wireType) + } + m.LoadBalancing = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LoadBalancing |= LoadBalancing(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/config.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/config.go new file mode 100644 index 0000000000..34164267a8 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/config.go @@ -0,0 +1,74 @@ +package adaptiveplacement + +import ( + "flag" + "time" +) + +const flagPrefix = "adaptive-placement." + +type Limits interface { + PlacementLimits(tenant string) PlacementLimits +} + +// PlacementLimits defines the limits for adaptive sharding. +// These parameters are tenant-specific. +type PlacementLimits struct { + TenantShards uint64 `yaml:"adaptive_placement_tenant_shards" json:"adaptive_placement_tenant_shards" category:"advanced" doc:"hidden"` + DefaultDatasetShards uint64 `yaml:"adaptive_placement_default_dataset_shards" json:"adaptive_placement_default_dataset_shards" category:"advanced" doc:"hidden"` + LoadBalancing LoadBalancing `yaml:"adaptive_placement_load_balancing" json:"adaptive_placement_load_balancing" category:"advanced" doc:"hidden"` + MinDatasetShards uint64 `yaml:"adaptive_placement_min_dataset_shards" json:"adaptive_placement_min_dataset_shards" category:"advanced" doc:"hidden"` + MaxDatasetShards uint64 `yaml:"adaptive_placement_max_dataset_shards" json:"adaptive_placement_max_dataset_shards" category:"advanced" doc:"hidden"` + UnitSizeBytes uint64 `yaml:"adaptive_placement_unit_size_bytes" json:"adaptive_placement_unit_size_bytes" category:"advanced" doc:"hidden"` + BurstWindow time.Duration `yaml:"adaptive_placement_burst_window" json:"adaptive_placement_burst_window" category:"advanced" doc:"hidden"` + DecayWindow time.Duration `yaml:"adaptive_placement_decay_window" json:"adaptive_placement_decay_window" category:"advanced" doc:"hidden"` +} + +func (o *PlacementLimits) RegisterFlags(f *flag.FlagSet) { + o.RegisterFlagsWithPrefix(flagPrefix, f) +} + +func (o *PlacementLimits) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + o.LoadBalancing = DynamicLoadBalancing + f.Var(&o.LoadBalancing, prefix+"load-balancing", "Load balancing strategy; "+validOptionsString+".") + f.Uint64Var(&o.TenantShards, prefix+"tenant-shards", 0, "Number of shards per tenant. If 0, the limit is not applied.") + f.Uint64Var(&o.DefaultDatasetShards, prefix+"default-dataset-shards", 1, "Default number of shards per dataset.") + f.Uint64Var(&o.MinDatasetShards, prefix+"min-dataset-shards", 1, "Minimum number of shards per dataset.") + f.Uint64Var(&o.MaxDatasetShards, prefix+"max-dataset-shards", 1<<10, "Maximum number of shards per dataset.") + f.Uint64Var(&o.UnitSizeBytes, prefix+"unit-size-bytes", 128<<10, "Shards are allocated based on the utilisation of units per second. The option specifies the unit size in bytes.") + f.DurationVar(&o.BurstWindow, prefix+"burst-window", 17*time.Minute, "Duration of the burst window. During this time, scale-outs are more aggressive.") + f.DurationVar(&o.DecayWindow, prefix+"decay-window", 19*time.Minute, "Duration of the decay window. During this time, scale-ins are delayed.") +} + +type Config struct { + PlacementUpdateInterval time.Duration `yaml:"placement_rules_update_interval" json:"placement_rules_update_interval" category:"advanced"` + PlacementRetentionPeriod time.Duration `yaml:"placement_rules_retention_period" json:"placement_rules_retention_period" category:"advanced"` + StatsConfidencePeriod time.Duration `yaml:"stats_confidence_period" json:"stats_confidence_period" category:"advanced"` + StatsAggregationWindow time.Duration `yaml:"stats_aggregation_window" json:"stats_aggregation_window" category:"advanced"` + StatsRetentionPeriod time.Duration `yaml:"stats_retention_period" json:"stats_retention_period" category:"advanced"` + ExportShardLimitMetrics bool `yaml:"export_shard_limit_metrics" json:"export_shard_limit_metrics" category:"advanced"` + ExportShardUsageMetrics bool `yaml:"export_shard_usage_metrics" json:"export_shard_usage_metrics" category:"advanced"` + ExportShardUsageBreakdownMetrics bool `yaml:"export_shard_usage_breakdown_metrics" json:"export_shard_usage_breakdown_metrics" category:"advanced"` +} + +func DefaultConfig() Config { + var c Config + var f flag.FlagSet + c.RegisterFlags(&f) + return c +} + +func (c *Config) RegisterFlags(f *flag.FlagSet) { + c.RegisterFlagsWithPrefix(flagPrefix, f) +} + +func (c *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) { + f.DurationVar(&c.PlacementUpdateInterval, prefix+"placement-rules-update-interval", 15*time.Second, "Interval between updates to placement rules.") + f.DurationVar(&c.PlacementRetentionPeriod, prefix+"placement-rules-retention-period", 15*time.Minute, "Retention period for inactive placement rules.") + f.DurationVar(&c.StatsConfidencePeriod, prefix+"stats-confidence-period", 0, "Confidence period for stats. During this period, placement rules are not updated. If 0, placement rules may be applied using incomplete stats.") + f.DurationVar(&c.StatsAggregationWindow, prefix+"stats-aggregation-window", 3*time.Minute, "Time window for aggregating shard stats.") + f.DurationVar(&c.StatsRetentionPeriod, prefix+"stats-retention-period", 15*time.Minute, "Retention period for stats that are no longer updated.") + f.BoolVar(&c.ExportShardLimitMetrics, prefix+"export-shard-limit-metrics", true, "If enabled, shard limit metrics are exported as Prometheus metrics.") + f.BoolVar(&c.ExportShardUsageMetrics, prefix+"export-shard-usage-metrics", false, "If enabled, shard utilization metrics are exported as Prometheus metrics.") + f.BoolVar(&c.ExportShardUsageBreakdownMetrics, prefix+"export-shard-usage-breakdown-metrics", false, "If enabled, shard utilization breakdown metrics, including shard ownership, are exported as Prometheus metrics.") +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/distribution_stats.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/distribution_stats.go new file mode 100644 index 0000000000..63ebe5eaa5 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/distribution_stats.go @@ -0,0 +1,184 @@ +package adaptiveplacement + +import ( + "math" + "slices" + "strings" + "sync" + "time" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ewma" + + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +// DistributionStats is a helper struct that tracks the data rate of each +// dataset within a certain time window. EWMA aggregation function is used +// to calculate the instantaneous rate of the dataset, the time window is +// half-life of the EWMA function. +// +// DistributionStats is safe for concurrent use. +type DistributionStats struct { + mu sync.Mutex + counters map[counterKey]*ewma.Rate + window time.Duration +} + +func NewDistributionStats(window time.Duration) *DistributionStats { + return &DistributionStats{ + counters: make(map[counterKey]*ewma.Rate), + window: window, + } +} + +type Sample struct { + TenantID string + DatasetName string + ShardOwner string + ShardID uint32 + Size uint64 +} + +func (d *DistributionStats) RecordStats(samples iter.Iterator[Sample]) { + d.recordStats(time.Now().UnixNano(), samples) +} + +func (d *DistributionStats) Build() *adaptive_placementpb.DistributionStats { + return d.build(time.Now().UnixNano()) +} + +func (d *DistributionStats) Expire(before time.Time) { + d.mu.Lock() + defer d.mu.Unlock() + for k, v := range d.counters { + if v.LastUpdate().Before(before) { + delete(d.counters, k) + } + } +} + +func (d *DistributionStats) recordStats(now int64, samples iter.Iterator[Sample]) { + d.mu.Lock() + defer d.mu.Unlock() + for samples.Next() { + s := samples.At() + // TODO(kolesnikovae): intern strings with unique (go 1.23) + c := d.counter(counterKey{ + tenant: s.TenantID, + dataset: s.DatasetName, + shard: shard{ + owner: s.ShardOwner, + id: s.ShardID, + }, + }) + c.UpdateAt(float64(s.Size), now) + } +} + +func (d *DistributionStats) counter(k counterKey) *ewma.Rate { + c, ok := d.counters[k] + if !ok { + c = ewma.NewHalfLife(d.window) + d.counters[k] = c + } + return c +} + +type counterKey struct { + tenant string + dataset string + shard shard +} + +func (k counterKey) compare(x counterKey) int { + if c := strings.Compare(k.tenant, x.tenant); c != 0 { + return c + } + if c := strings.Compare(k.dataset, x.dataset); c != 0 { + return c + } + if k.shard.id != x.shard.id { + return int(k.shard.id) - int(x.shard.id) + } + return strings.Compare(k.shard.owner, x.shard.owner) +} + +type shard struct { + owner string + id uint32 +} + +func (d *DistributionStats) build(now int64) *adaptive_placementpb.DistributionStats { + d.mu.Lock() + defer d.mu.Unlock() + + tenants := make(map[string]int) + datasets := make(map[string]int) + shards := make(map[shard]int) + + // Although, not strictly required, we iterate over the keys + // in a deterministic order to make the output deterministic. + keys := make([]counterKey, 0, len(d.counters)) + for k := range d.counters { + keys = append(keys, k) + } + slices.SortFunc(keys, func(a, b counterKey) int { + return a.compare(b) + }) + + stats := &adaptive_placementpb.DistributionStats{CreatedAt: now} + for _, k := range keys { + c := d.counters[k] + // Skip dataset-wide counters. + if k.shard.id == 0 { + continue + } + + ti, ok := tenants[k.tenant] + if !ok { + ti = len(stats.Tenants) + tenants[k.tenant] = ti + stats.Tenants = append(stats.Tenants, &adaptive_placementpb.TenantStats{ + TenantId: k.tenant, + }) + } + + di, ok := datasets[k.dataset] + if !ok { + di = len(stats.Datasets) + datasets[k.dataset] = di + stats.Datasets = append(stats.Datasets, &adaptive_placementpb.DatasetStats{ + Tenant: uint32(ti), + Name: k.dataset, + }) + } + + si, ok := shards[k.shard] + if !ok { + si = len(stats.Shards) + shards[k.shard] = si + stats.Shards = append(stats.Shards, &adaptive_placementpb.ShardStats{ + Id: k.shard.id, + Owner: k.shard.owner, + }) + } + + ds := stats.Datasets[di] + ds.Shards = append(ds.Shards, uint32(si)) + ds.Usage = append(ds.Usage, uint64(math.Round(c.ValueAt(now)))) + } + + for _, dataset := range stats.Datasets { + c := d.counter(counterKey{ + tenant: stats.Tenants[dataset.Tenant].TenantId, + dataset: dataset.Name, + }) + // Unlike the shard counters, we update the dataset-wide + // counters at the build time. + c.UpdateAt(float64(stdDev(dataset.Usage)), now) + dataset.StdDev = uint64(math.Round(c.ValueAt(now))) + } + + return stats +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/distribution_stats_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/distribution_stats_test.go new file mode 100644 index 0000000000..1d5162193c --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/distribution_stats_test.go @@ -0,0 +1,179 @@ +package adaptiveplacement + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +func Test_StatsTracker(t *testing.T) { + const window = time.Second * 10 + stats := NewDistributionStats(window) + var now time.Duration + + for ; now < window; now += time.Second { + stats.recordStats(now.Nanoseconds(), iter.NewSliceIterator([]Sample{ + {TenantID: "tenant-a", DatasetName: "dataset-a", ShardID: 1, Size: 10}, + {TenantID: "tenant-a", DatasetName: "dataset-b", ShardID: 1, Size: 10}, + })) + } + + // Note that we deal with half-life exponent decay here. + // Therefore, in 10s we only reached 50% of the target value. + expected := &adaptive_placementpb.DistributionStats{ + Tenants: []*adaptive_placementpb.TenantStats{ + {TenantId: "tenant-a"}, + }, + Datasets: []*adaptive_placementpb.DatasetStats{ + { + Tenant: 0, + Name: "dataset-a", + Shards: []uint32{0}, + Usage: []uint64{5}, + }, + { + Tenant: 0, + Name: "dataset-b", + Shards: []uint32{0}, + Usage: []uint64{5}, + }, + }, + Shards: []*adaptive_placementpb.ShardStats{ + {Id: 1}, + }, + CreatedAt: now.Nanoseconds(), + } + assert.Equal(t, expected.String(), stats.build(now.Nanoseconds()).String()) + + // Reassign dataset-a to shard 2 and add dataset-c. + for ; now < time.Second*20; now += time.Second { + stats.recordStats(now.Nanoseconds(), + iter.NewSliceIterator([]Sample{ + {TenantID: "tenant-a", DatasetName: "dataset-a", ShardID: 2, Size: 10}, // Moved from shard 1. + {TenantID: "tenant-a", DatasetName: "dataset-b", ShardID: 1, Size: 10}, // Not changed. + {TenantID: "tenant-b", DatasetName: "dataset-c", ShardID: 2, Size: 10}, // Added. + })) + } + expected = &adaptive_placementpb.DistributionStats{ + Tenants: []*adaptive_placementpb.TenantStats{ + {TenantId: "tenant-a"}, + {TenantId: "tenant-b"}, + }, + Datasets: []*adaptive_placementpb.DatasetStats{ + { + Tenant: 0, + Name: "dataset-a", + Shards: []uint32{0, 1}, + Usage: []uint64{3, 5}, + }, + { + Tenant: 0, + Name: "dataset-b", + Shards: []uint32{0}, + Usage: []uint64{8}, + }, + { + Tenant: 1, + Name: "dataset-c", + Shards: []uint32{1}, + Usage: []uint64{5}, + }, + }, + Shards: []*adaptive_placementpb.ShardStats{ + {Id: 1}, + {Id: 2}, + }, + CreatedAt: now.Nanoseconds(), + } + assert.Equal(t, expected.String(), stats.build(now.Nanoseconds()).String()) + + // Next 30 seconds nothing changes. + for ; now < time.Minute; now += time.Second { + stats.recordStats(now.Nanoseconds(), + iter.NewSliceIterator([]Sample{ + {TenantID: "tenant-a", DatasetName: "dataset-a", ShardID: 2, Size: 10}, + {TenantID: "tenant-a", DatasetName: "dataset-b", ShardID: 1, Size: 10}, + {TenantID: "tenant-b", DatasetName: "dataset-c", ShardID: 2, Size: 10}, + })) + } + expected = &adaptive_placementpb.DistributionStats{ + Tenants: []*adaptive_placementpb.TenantStats{ + {TenantId: "tenant-a"}, + {TenantId: "tenant-b"}, + }, + Datasets: []*adaptive_placementpb.DatasetStats{ + { + Tenant: 0, + Name: "dataset-a", + Shards: []uint32{0, 1}, + Usage: []uint64{0, 10}, + }, + { + Tenant: 0, + Name: "dataset-b", + Shards: []uint32{0}, + Usage: []uint64{10}, + }, + { + Tenant: 1, + Name: "dataset-c", + Shards: []uint32{1}, + Usage: []uint64{10}, + }, + }, + Shards: []*adaptive_placementpb.ShardStats{ + {Id: 1}, + {Id: 2}, + }, + CreatedAt: now.Nanoseconds(), + } + assert.Equal(t, expected.String(), stats.build(now.Nanoseconds()).String()) + + // See what happens when a stale counter is removed (dataset-a, shard 1). + stats.Expire(time.Unix(40, 0)) + stats.build(now.Nanoseconds()) + expected = &adaptive_placementpb.DistributionStats{ + Tenants: []*adaptive_placementpb.TenantStats{ + {TenantId: "tenant-a"}, + {TenantId: "tenant-b"}, + }, + Datasets: []*adaptive_placementpb.DatasetStats{ + { + Tenant: 0, + Name: "dataset-a", + Shards: []uint32{0}, + Usage: []uint64{10}, + }, + { + Tenant: 0, + Name: "dataset-b", + Shards: []uint32{1}, + Usage: []uint64{10}, + }, + { + Tenant: 1, + Name: "dataset-c", + Shards: []uint32{0}, + Usage: []uint64{10}, + }, + }, + Shards: []*adaptive_placementpb.ShardStats{ + {Id: 2}, + {Id: 1}, + }, + CreatedAt: now.Nanoseconds(), + } + assert.Equal(t, expected.String(), stats.build(now.Nanoseconds()).String()) + + // Expire all counters. + stats.Expire(time.Now()) + s := stats.build(now.Nanoseconds()) + assert.Empty(t, s.Tenants) + assert.Empty(t, s.Datasets) + assert.Empty(t, s.Shards) + assert.Empty(t, stats.counters) +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ewma/ewma.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ewma/ewma.go new file mode 100644 index 0000000000..9801acf290 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ewma/ewma.go @@ -0,0 +1,81 @@ +package ewma + +import ( + "math" + "time" +) + +// Rate is an exponentially weighted moving average event rate. +// The rate is always calculated per second and samples are +// summed up within the second duration. +type Rate struct { + lifetime float64 + last int64 + cumulative float64 + ewma float64 +} + +// New creates a new rate with a given lifetime. +// +// lifetime is the time required for the decaying quantity to +// reduced to 1⁄e ≈ 0.367879441 times its initial value. +func New(lifetime time.Duration) *Rate { + return &Rate{lifetime: max(1, lifetime.Seconds())} +} + +// NewHalfLife creates a new rate with a given half-life. +// +// halflife is the time required for the decaying quantity +// to fall to one half of its initial value. +func NewHalfLife(halflife time.Duration) *Rate { + // https://en.wikipedia.org/wiki/Exponential_decay: + // halflife = ln(2)/λ = tau * ln(2) + // tau = 1/λ = halflife/ln(2) + return &Rate{lifetime: max(1, halflife.Seconds()) / math.Ln2} +} + +func (r *Rate) Value() float64 { return r.value(time.Now().UnixNano()) } +func (r *Rate) Update(v float64) { r.update(v, time.Now().UnixNano()) } + +func (r *Rate) ValueAt(t int64) float64 { return r.value(t) } +func (r *Rate) UpdateAt(v float64, t int64) { r.update(v, t) } + +func (r *Rate) LastUpdate() time.Time { return time.Unix(0, r.last) } + +func (r *Rate) value(now int64) float64 { + delta := float64(now - r.last) + if delta < 0 { + return 0 + } + delta /= 1e9 + if delta >= 1 { + // Correct the result for the time passed since the last update. + // Over time, the delta increases and the decreased value (the + // instant rate cumulative/delta) dominates in both ways: + // directly and via the impact of the exponent. The value is + // asymptotically approaching zero, if no updates are made. + return ewma(r.ewma, r.cumulative/delta, delta, r.lifetime) + } + return r.ewma +} + +// update updates the rate with a new value and timestamp in nanoseconds. +// It's assumed that time never goes backwards. +func (r *Rate) update(v float64, now int64) { + delta := float64(now - r.last) + if delta < 0 { + return + } + delta /= 1e9 + if delta >= 1 { + r.ewma = ewma(r.ewma, r.cumulative/delta, delta, r.lifetime) + r.cumulative = 0 + r.last = now + } + r.cumulative += v +} + +func ewma(old, value, delta, lifetime float64) float64 { + alpha := 1 - math.Exp(-delta/lifetime) + return alpha*value + (1-alpha)*old +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ewma/ewma_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ewma/ewma_test.go new file mode 100644 index 0000000000..dfdec3db64 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ewma/ewma_test.go @@ -0,0 +1,154 @@ +package ewma + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_Rate_HalfLife(t *testing.T) { + s := int64(0) + r := NewHalfLife(time.Second * 10) + + // Expected rate 100. + step := int64(1e9 / 10) // 100ms + for i := 0; i < 500; i++ { // 50s. + r.update(10, s) + if i == 100 { // 10s (half-life) + // Half-life: 10s => 100 * 0.5 = 50. + assert.InEpsilon(t, float64(50), r.value(s), 0.0001) + } + s += step + } + // Here and below: Value takes into account the time + // since the last update, so we need to adjust it to + // compensate the last iteration. + assert.InEpsilon(t, 100, r.value(s-step), 0.05) + + // Rate decreases. + step = int64(1e9 / 10) // 100ms + for i := 0; i < 500; i++ { // 50s. + r.update(5, s) + s += step + } + assert.InEpsilon(t, 50, r.value(s-step), 0.05) + + // Exactly 1s rate. + step = int64(1e9) // 1s + for i := 0; i < 50; i++ { // 50s + r.update(50, s) + s += step + } + assert.InEpsilon(t, 50, r.value(s-step), 0.005) + + // Sub-second rate. + step = int64(1e9 * 2) // 2s + for i := 0; i < 50; i++ { // 50s. + r.update(1, s) + if i == 5 { // 10s (half-life) + // We expect that after expiration of the half-life interval, + // the rate should be roughly 25: (~50 + 0.5) / 2 = ~25. + // The numbers are not exact because r has state: + // in the beginning it is slightly greater than 50. + assert.InEpsilon(t, 25, int(r.value(s)), 0.0001) + } + s += step // Once per two seconds. + } + assert.InEpsilon(t, 0.5, r.value(s-step), 0.5) +} + +func Test_Rate_HalfLife_Tail(t *testing.T) { + // Expected rate 100. + const ( + step int64 = 1e9 / 10 // 100ms + steps int64 = 1200 // 120s. + update int64 = 10 + + rate = update * int64(time.Second) / step + halflife = time.Second * 10 + ) + + r := NewHalfLife(halflife) + var s int64 + for i := int64(0); i < steps; i++ { + r.update(float64(update), s) + s += step + if i == int64(halflife)/step { + // Just in case: check half-life value. + assert.InEpsilon(t, float64(rate/2), r.value(s), 0.0001) + } + } + + assert.InEpsilon(t, float64(rate), r.value(s), 0.05) + // Now we stop updating the rate and + // expect that it will decay to zero. + timespan := s + (steps * step) + assert.Less(t, r.value(timespan), float64(1)) + // Half-life check: note that r is not exactly 100, + // therefore we will have some error here. + timespan = s + int64(halflife) + assert.InEpsilon(t, r.value(timespan), r.value(s)/2, 0.05) +} + +func Test_Rate_HalfLife_Complement(t *testing.T) { + // The test examines the complementarity of two rates, + // when the sum of the rates is constant. + const ( + step = int64(1e9 / 10) // 100ms + steps = 600 // 60s. + update = 10 + + rate = update * int64(time.Second) / step + halflife = time.Second * 10 + ) + + s := int64(0) + a := NewHalfLife(halflife) + for i := 0; i < steps; i++ { + a.update(update, s) + s += step + } + assert.InEpsilon(t, float64(rate), a.value(s), 0.05) + + b := NewHalfLife(halflife) + const interval = steps / 10 + for n := 0; n < steps; n += interval { + for i := 0; i < interval; i++ { + b.update(update, s) + s += step + } + // The sum of the rates is expected to be constant. + assert.InEpsilon(t, float64(rate), a.value(s)+b.value(s), 0.05) + } +} + +func Test_Rate_Lifetime(t *testing.T) { + // Expected rate 100. + const ( + step int64 = 1e9 / 10 // 100ms + steps int64 = 100 // 10s. + update int64 = 10 + + rate = update * int64(time.Second) / step + // lifetime/3 approximates SMA (error is ~5%). + lifetime = time.Second * 10 / 3 + ) + + r := New(lifetime) + var s int64 + for i := int64(0); i < steps; i++ { + r.update(float64(update), s) + s += step + } + + assert.InEpsilon(t, float64(rate), r.value(s), 0.05) + // Now we stop updating the rate and expect + // that it will decay to zero. Note that the + // value decays more slowly: after 20 seconds + // we still observe a non-zero value (~5%). + for i := int64(0); i < 2*steps; i++ { + s += step + } + assert.Less(t, r.value(s), float64(5)) +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/load_balancing.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/load_balancing.go new file mode 100644 index 0000000000..9ca1c8ead2 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/load_balancing.go @@ -0,0 +1,168 @@ +package adaptiveplacement + +import ( + "errors" + "fmt" + "math" + "math/rand" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +type LoadBalancing string + +const ( + FingerprintLoadBalancing LoadBalancing = "fingerprint" + RoundRobinLoadBalancing LoadBalancing = "round-robin" + DynamicLoadBalancing LoadBalancing = "dynamic" +) + +var ErrLoadBalancing = errors.New("invalid load balancing option") + +var loadBalancingOptions = []LoadBalancing{ + FingerprintLoadBalancing, + RoundRobinLoadBalancing, + DynamicLoadBalancing, +} + +const validOptionsString = "valid options: fingerprint, round-robin, dynamic" + +func (lb *LoadBalancing) Set(text string) error { + x := LoadBalancing(text) + for _, name := range loadBalancingOptions { + if x == name { + *lb = x + return nil + } + } + return fmt.Errorf("%w: %s; %s", ErrLoadBalancing, x, validOptionsString) +} + +func (lb *LoadBalancing) String() string { return string(*lb) } + +func (lb LoadBalancing) proto() adaptive_placementpb.LoadBalancing { + switch lb { + default: + return adaptive_placementpb.LoadBalancing_LOAD_BALANCING_UNSPECIFIED + case DynamicLoadBalancing: + return adaptive_placementpb.LoadBalancing_LOAD_BALANCING_UNSPECIFIED + case RoundRobinLoadBalancing: + return adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN + case FingerprintLoadBalancing: + return adaptive_placementpb.LoadBalancing_LOAD_BALANCING_FINGERPRINT + } +} + +func loadBalancingFromProto(lb adaptive_placementpb.LoadBalancing) LoadBalancing { + switch lb { + default: + return FingerprintLoadBalancing + case adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN: + return RoundRobinLoadBalancing + } +} + +func (lb LoadBalancing) pick(k placement.Key) func(int) int { + switch lb { + default: + return pickFingerprintMod(k) + case RoundRobinLoadBalancing: + return pickRoundRobin() + } +} + +func pickFingerprintMod(k placement.Key) func(int) int { + return func(n int) int { + return int(k.Fingerprint % uint64(n)) + } +} + +func pickRoundRobin() func(int) int { return roundRobin } +func roundRobin(n int) int { return rand.Intn(n) } + +// needsDynamicBalancing returns true if the load balancing strategy +// should be chosen dynamically based on the dataset stats. +// x is the currently set load balancing strategy. +func (lb LoadBalancing) needsDynamicBalancing(x adaptive_placementpb.LoadBalancing) bool { + // If the configured load balancing is "dynamic", we should + // try to find the best strategy based on the dataset stats, + // except if the x is already set to round-robin, which should + // ensure the best distribution (from the available options). + return lb == DynamicLoadBalancing && x != adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN +} + +// loadBalancingStrategy chooses the load balancing strategy. +// +// By default, we adhere to the standard fingerprint-based distribution, +// since it provides slightly better locality in case if the dataset has +// enough keys to distribute. However, oftentimes this is not the case. +// +// If at least one shard is significantly overheated, and relative standard +// deviation within the aggregation window is very high, which indicates +// that the distribution is uneven, we resort to round-robin load balancing. +func loadBalancingStrategy(stats *adaptive_placementpb.DatasetStats, unit uint64, target int) LoadBalancing { + lb := FingerprintLoadBalancing + if len(stats.Shards) < 2 { + return lb + } + if p := float64(len(stats.Shards)) / float64(target); p > 2 || p < 0.5 { + // It is possible that the dataset is being moved + // to a different node, or different shards, or is + // being scaled in/out, and therefore nonuniform + // distribution might be expected within some period + // of time. Moreover, there might be a sudden surge + // in usage; together with high dispersion, this can + // lead to false positives. + return lb + } + t := 2 * unit + var overheated bool + for _, v := range stats.Usage { + if v >= t { + overheated = true + break + } + } + if !overheated { + return lb + } + if float64(stats.StdDev)/float64(mean(stats.Usage)) < 0.5 { + return lb + } + // Thresholds (2 x unit size, shards/target ratio, 0.5 RSD) are arbitrary + // and can be adjusted. The current values are conservative and were chosen + // to use RR as a last resort. + return RoundRobinLoadBalancing +} + +func stdDev(d []uint64) uint64 { + if len(d) == 0 { + return 0 + } + m := mean(d) + var variance uint64 + for _, v := range d { + dev := v - m + variance += dev * dev + } + variance /= uint64(len(d)) + return uint64(math.Sqrt(float64(variance))) +} + +func mean(d []uint64) (m uint64) { + if len(d) == 0 { + return m + } + for _, v := range d { + m += v + } + return m / uint64(len(d)) +} + +func sum(d []uint64) (s uint64) { + for _, v := range d { + s += v + } + return s +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/load_balancing_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/load_balancing_test.go new file mode 100644 index 0000000000..4d31c6b087 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/load_balancing_test.go @@ -0,0 +1,138 @@ +package adaptiveplacement + +import ( + "fmt" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +func Test_loadBalancingStrategy(t *testing.T) { + const randSeed = 752383033 + rnd := rand.New(rand.NewSource(randSeed)) + const unitSize = 512 << 10 + + randomize := func(f float64, values ...uint64) []uint64 { + for i, v := range values { + j := uint64(float64(v) * f) + if rnd.Float64() > 0.5 { + values[i] += j + } else { + values[i] -= j + } + } + return values + } + + for i, test := range []struct { + usage []uint64 + expected LoadBalancing + }{ + { + expected: FingerprintLoadBalancing, + }, + { + usage: []uint64{0}, + expected: FingerprintLoadBalancing, + }, + { + usage: []uint64{unitSize}, + expected: FingerprintLoadBalancing, + }, + { + usage: []uint64{0, 0, 0, 0, 0}, + expected: FingerprintLoadBalancing, + }, + { + usage: []uint64{unitSize, unitSize, unitSize, unitSize, unitSize}, + expected: FingerprintLoadBalancing, + }, + { + usage: []uint64{2 * unitSize, unitSize, unitSize, unitSize, unitSize}, + expected: FingerprintLoadBalancing, + }, + { + usage: randomize(0.1, unitSize, unitSize, unitSize, unitSize, unitSize), + expected: FingerprintLoadBalancing, + }, + { + usage: randomize(0.9, unitSize, unitSize, unitSize, unitSize, unitSize), + expected: FingerprintLoadBalancing, + }, + { + usage: randomize(0.1, 2*unitSize, 2*unitSize, 2*unitSize, 2*unitSize, 2*unitSize), + expected: FingerprintLoadBalancing, + }, + { + usage: []uint64{2 * unitSize, unitSize / 2, unitSize, unitSize, unitSize}, + expected: FingerprintLoadBalancing, + }, + { + usage: []uint64{2 * unitSize, unitSize / 2, unitSize / 2, unitSize, unitSize}, + expected: RoundRobinLoadBalancing, + }, + { + usage: randomize(0.9, 2*unitSize, 2*unitSize, 2*unitSize, 2*unitSize, 2*unitSize), + expected: RoundRobinLoadBalancing, + }, + } { + stats := &adaptive_placementpb.DatasetStats{ + Shards: make([]uint32, len(test.usage)), + Usage: test.usage, + StdDev: stdDev(test.usage), + } + target := len(stats.Shards) + assert.Equal(t, test.expected, loadBalancingStrategy(stats, unitSize, target), fmt.Sprint(i)) + } + +} + +func Test_loadBalancingStrategy_relocation(t *testing.T) { + const unitSize = 512 << 10 + for i, test := range []struct { + usage []uint64 + expected LoadBalancing + target int + }{ + { + usage: []uint64{2 * unitSize, 2 * unitSize, unitSize / 2, unitSize / 2, unitSize / 2}, + expected: RoundRobinLoadBalancing, + target: 5, // 5/5 + }, + { + usage: []uint64{2 * unitSize, 2 * unitSize, unitSize / 2, unitSize / 2}, + expected: RoundRobinLoadBalancing, + target: 2, // 2/4 + }, + { + usage: []uint64{2 * unitSize, 2 * unitSize, unitSize / 2, unitSize / 2, unitSize / 2}, + expected: RoundRobinLoadBalancing, + target: 3, // 3/5 + }, + { + usage: []uint64{2 * unitSize, 2 * unitSize, unitSize / 2, unitSize / 2, unitSize / 2}, + expected: FingerprintLoadBalancing, + target: 2, // 2/5 + }, + { + usage: []uint64{unitSize, unitSize, unitSize / 5, unitSize / 5}, + expected: FingerprintLoadBalancing, + target: 2, // 2/4 + }, + { + usage: []uint64{2*unitSize - 1, 0}, + expected: FingerprintLoadBalancing, + target: 1, // 1/2 + }, + } { + stats := &adaptive_placementpb.DatasetStats{ + Shards: make([]uint32, len(test.usage)), + Usage: test.usage, + StdDev: stdDev(test.usage), + } + assert.Equal(t, test.expected, loadBalancingStrategy(stats, unitSize, test.target), fmt.Sprint(i)) + } +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent.go new file mode 100644 index 0000000000..5edd1a4b38 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent.go @@ -0,0 +1,103 @@ +package adaptiveplacement + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type Agent struct { + service services.Service + logger log.Logger + store StoreReader + config Config + metrics *agentMetrics + + placement *AdaptivePlacement + rules *adaptive_placementpb.PlacementRules +} + +func NewAgent( + logger log.Logger, + reg prometheus.Registerer, + config Config, + limits Limits, + store Store, +) *Agent { + a := Agent{ + logger: logger, + store: store, + config: config, + placement: NewAdaptivePlacement(limits), + metrics: newAgentMetrics(reg), + } + a.service = services.NewTimerService( + config.PlacementUpdateInterval, + a.starting, + a.loadRulesNoError, + a.stopping, + ) + return &a +} + +func (a *Agent) Service() services.Service { return a.service } + +func (a *Agent) Placement() *AdaptivePlacement { return a.placement } + +func (a *Agent) starting(ctx context.Context) error { + _ = a.loadRulesNoError(ctx) + if a.rules == nil { + // The exact reason is logged in loadRules. + return fmt.Errorf("failed to load placement rules") + } + return nil +} + +func (a *Agent) stopping(error) error { return nil } + +// The function is only needed to satisfy the services.OneIteration +// signature: there's no case when the service stops on its own: +// it's better to serve outdated rules than to not serve at all. +func (a *Agent) loadRulesNoError(ctx context.Context) error { + util.Recover(func() { a.loadRules(ctx) }) + return nil +} + +func (a *Agent) loadRules(ctx context.Context) { + rules, err := a.store.LoadRules(ctx) + switch { + case err == nil: + case errors.Is(err, ErrRulesNotFound): + _ = level.Warn(a.logger).Log("msg", "placement rules not found") + rules = &adaptive_placementpb.PlacementRules{CreatedAt: time.Now().UnixNano()} + default: + _ = level.Error(a.logger).Log("msg", "failed to load placement rules", "err", err) + return + } + a.metrics.lag.Set(max(0, time.Since(time.Unix(0, rules.CreatedAt)).Seconds())) + if a.rules != nil { + if rules.CreatedAt < a.rules.CreatedAt { + _ = level.Warn(a.logger).Log( + "msg", "placement rules are outdated", + "discovered", time.Unix(0, rules.CreatedAt), + "loaded", time.Unix(0, a.rules.CreatedAt), + ) + return + } + } + _ = level.Debug(a.logger).Log( + "msg", "loading placement rules", + "created_at", time.Unix(0, rules.CreatedAt), + ) + a.placement.Update(rules) + a.rules = rules +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent_metrics.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent_metrics.go new file mode 100644 index 0000000000..1158784298 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent_metrics.go @@ -0,0 +1,22 @@ +package adaptiveplacement + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type agentMetrics struct { + lag prometheus.Gauge +} + +func newAgentMetrics(reg prometheus.Registerer) *agentMetrics { + m := &agentMetrics{ + lag: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "pyroscope_adaptive_sharding_rules_update_lag_seconds", + Help: "Delay in seconds since the last update of the placement rules.", + }), + } + if reg != nil { + reg.MustRegister(m.lag) + } + return m +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent_test.go new file mode 100644 index 0000000000..79f63c5a9b --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_agent_test.go @@ -0,0 +1,185 @@ +package adaptiveplacement + +import ( + "context" + "fmt" + "io" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockadaptiveplacement" +) + +type agentSuite struct { + suite.Suite + + logger log.Logger + reg *prometheus.Registry + config Config + limits *mockLimits + store *mockadaptiveplacement.MockStore + agent *Agent + error error +} + +func (s *agentSuite) SetupTest() { + s.logger = log.NewLogfmtLogger(io.Discard) + s.reg = prometheus.NewRegistry() + s.config.PlacementUpdateInterval = 15 * time.Second + s.limits = new(mockLimits) + s.store = new(mockadaptiveplacement.MockStore) + s.agent = NewAgent( + s.logger, + s.reg, + s.config, + s.limits, + s.store, + ) +} + +func (s *agentSuite) AfterTest(_, _ string) { + svc := s.agent.Service() + svc.StopAsync() + if s.error == nil { + s.Require().NoError(svc.AwaitTerminated(context.Background())) + s.Require().Equal(services.Terminated, svc.State()) + } else { + s.Require().Equal(services.Failed, svc.State()) + } + s.limits.AssertExpectations(s.T()) + s.store.AssertExpectations(s.T()) +} + +func (s *agentSuite) start() error { + ctx := context.Background() + svc := s.agent.Service() + s.Require().NoError(svc.StartAsync(ctx)) + s.error = svc.AwaitRunning(ctx) + return s.error +} + +func Test_AgentSuite(t *testing.T) { suite.Run(t, new(agentSuite)) } + +func (s *agentSuite) Test_Agent_loads_rules_on_start() { + s.store.On("LoadRules", mock.Anything). + Return(&adaptive_placementpb.PlacementRules{}, nil) + s.Require().NoError(s.start()) + s.Assert().NotNil(s.agent.rules) + s.Assert().NotNil(s.agent.Placement()) +} + +func (s *agentSuite) Test_Agent_service_doesnt_fail_if_rules_cant_be_found() { + s.store.On("LoadRules", mock.Anything). + Return((*adaptive_placementpb.PlacementRules)(nil), ErrRulesNotFound) + s.Require().NoError(s.start()) + s.Assert().NotNil(s.agent.rules) + s.Assert().NotNil(s.agent.Placement()) +} + +func (s *agentSuite) Test_Agent_service_fails_if_rules_cant_be_loaded() { + s.store.On("LoadRules", mock.Anything). + Return((*adaptive_placementpb.PlacementRules)(nil), fmt.Errorf("error")) + s.Require().Error(s.start()) + s.Assert().Nil(s.agent.rules) + s.Assert().NotNil(s.agent.Placement()) +} + +func (s *agentSuite) Test_Agent_updates_placement_rules() { + s.limits.On("PlacementLimits", "tenant-a").Return(PlacementLimits{ + TenantShards: 1, + DefaultDatasetShards: 1, + }) + + s.store.On("LoadRules", mock.Anything). + Return(&adaptive_placementpb.PlacementRules{CreatedAt: 100}, nil). + Once() + + s.Require().NoError(s.start()) + + p := s.agent.Placement() + s.Require().NotNil(p) + policy := p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-a", + }) + s.Assert().Equal(1, policy.TenantShards) + s.Assert().Equal(1, policy.DatasetShards) + + s.store.On("LoadRules", mock.Anything). + Return(&adaptive_placementpb.PlacementRules{ + CreatedAt: 150, + Tenants: []*adaptive_placementpb.TenantPlacement{ + {TenantId: "tenant-a"}, + }, + Datasets: []*adaptive_placementpb.DatasetPlacement{ + { + Name: "dataset-a", + TenantShardLimit: 10, + DatasetShardLimit: 10, + }, + }, + }, nil). + Once() + + s.agent.loadRules(context.Background()) + policy = p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-a", + }) + s.Assert().Equal(10, policy.TenantShards) + s.Assert().Equal(10, policy.DatasetShards) +} + +func (s *agentSuite) Test_Agent_ignored_outdated_rules() { + s.limits.On("PlacementLimits", "tenant-a").Return(PlacementLimits{ + TenantShards: 1, + DefaultDatasetShards: 1, + }) + + s.store.On("LoadRules", mock.Anything). + Return(&adaptive_placementpb.PlacementRules{CreatedAt: 100}, nil). + Once() + + s.Require().NoError(s.start()) + + p := s.agent.Placement() + s.Require().NotNil(p) + policy := p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-a", + }) + s.Assert().Equal(1, policy.TenantShards) + s.Assert().Equal(1, policy.DatasetShards) + + s.store.On("LoadRules", mock.Anything). + Return(&adaptive_placementpb.PlacementRules{ + CreatedAt: 10, + Tenants: []*adaptive_placementpb.TenantPlacement{ + {TenantId: "tenant-a"}, + }, + Datasets: []*adaptive_placementpb.DatasetPlacement{ + { + Name: "dataset-a", + TenantShardLimit: 10, + DatasetShardLimit: 10, + }, + }, + }, nil). + Once() + + s.agent.loadRules(context.Background()) + policy = p.Policy(placement.Key{ + TenantID: "tenant-a", + DatasetName: "dataset-a", + }) + s.Assert().Equal(1, policy.TenantShards) + s.Assert().Equal(1, policy.DatasetShards) +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager.go new file mode 100644 index 0000000000..84f7b94520 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager.go @@ -0,0 +1,210 @@ +package adaptiveplacement + +import ( + "context" + "errors" + "strconv" + "sync/atomic" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +// Manager maintains placement rules and distribution stats in the store. +// +// Manager implements services.Service interface for convenience, but it's +// meant to be started and stopped explicitly via Start and Stop calls. +// +// If manager is being stopped while updating rules, an ongoing attempt is +// not aborted: we're interested in finishing the operation so that the rules +// reflect the most recent statistics. Another reason is that another instance +// might be already running at the Stop call time. +// +// When just started, the manager may not have enough statistics to build +// the rules: StatsConfidencePeriod should expire before the first update. +// Note that ruler won't downscale datasets for a certain period of time +// after the ruler is created regardless of the confidence period. Therefore, +// it's generally safe to publish rules even with incomplete statistics; +// however, this allows for delays in response to changes of the data flow. +type Manager struct { + started atomic.Bool + startedAt time.Time + + service services.Service + logger log.Logger + config Config + limits Limits + metrics *managerMetrics + + store Store + stats *DistributionStats + ruler *Ruler +} + +func NewManager( + logger log.Logger, + reg prometheus.Registerer, + config Config, + limits Limits, + store Store, +) *Manager { + m := &Manager{ + logger: logger, + config: config, + limits: limits, + store: store, + stats: NewDistributionStats(config.StatsAggregationWindow), + metrics: newManagerMetrics(reg), + } + m.service = services.NewTimerService( + config.PlacementUpdateInterval, + m.starting, + m.updateRulesNoError, + m.stopping, + ) + return m +} + +func (m *Manager) Service() services.Service { return m.service } + +func (m *Manager) RecordStats(samples iter.Iterator[Sample]) { m.stats.RecordStats(samples) } + +func (m *Manager) Start() { m.started.Store(true) } +func (m *Manager) Stop() { m.started.Store(false) } + +func (m *Manager) starting(context.Context) error { return nil } +func (m *Manager) stopping(error) error { return nil } + +// The function is only needed to satisfy the services.OneIteration +// signature: there's no case when the service stops on its own: +// it's better to serve outdated rules than to not serve at all. +func (m *Manager) updateRulesNoError(ctx context.Context) error { + util.Recover(func() { m.updateRules(ctx) }) + return nil +} + +func (m *Manager) updateRules(ctx context.Context) { + if !m.started.Load() { + m.reset() + return + } + // Initialize the ruler if it's the first run after start. + if m.ruler == nil && !m.loadRules(ctx) { + return + } + + // Cleanup outdated data first: note that when we load the + // rules from the store we don't check how old they are. + now := time.Now() + m.ruler.Expire(now.Add(-m.config.PlacementRetentionPeriod)) + m.stats.Expire(now.Add(-m.config.StatsRetentionPeriod)) + + stats := m.stats.Build() + rules := m.ruler.BuildRules(stats) + + m.metrics.rulesTotal.Set(float64(len(rules.Datasets))) + m.metrics.statsTotal.Set(float64(len(stats.Datasets))) + + if time.Since(m.startedAt) < m.config.StatsConfidencePeriod { + _ = level.Debug(m.logger).Log("msg", "confidence period not expired, skipping update") + return + } + + if err := m.store.StoreRules(ctx, rules); err != nil { + _ = level.Error(m.logger).Log("msg", "failed to store placement rules", "err", err) + } else { + m.metrics.lastUpdate.SetToCurrentTime() + _ = level.Debug(m.logger).Log( + "msg", "placement rules updated", + "datasets", len(rules.Datasets), + "created_at", time.Unix(0, rules.CreatedAt), + ) + } + + if err := m.store.StoreStats(ctx, stats); err != nil { + _ = level.Error(m.logger).Log("msg", "failed to store stats", "err", err) + } else { + _ = level.Debug(m.logger).Log( + "msg", "placement stats updated", + "datasets", len(rules.Datasets), + "created_at", time.Unix(0, rules.CreatedAt), + ) + } + + m.exportMetrics(rules, stats) +} + +func (m *Manager) reset() { + // Note that we only reset the ruler here, but not the stats: + // there's no harm in old samples as long as they are within + // the retention period. + m.ruler = nil + m.metrics.rulesTotal.Set(0) + m.metrics.statsTotal.Set(0) + m.metrics.datasetShardLimit.Reset() + m.metrics.datasetShardUsage.Reset() + m.metrics.datasetShardUsageBreakdown.Reset() +} + +func (m *Manager) loadRules(ctx context.Context) bool { + rules, err := m.store.LoadRules(ctx) + switch { + case err == nil: + case errors.Is(err, ErrRulesNotFound): + _ = level.Warn(m.logger).Log("msg", "placement rules not found") + rules = &adaptive_placementpb.PlacementRules{CreatedAt: time.Now().UnixNano()} + default: + _ = level.Error(m.logger).Log("msg", "failed to load placement rules", "err", err) + return false + } + if m.ruler == nil { + m.ruler = NewRuler(m.limits) + m.startedAt = time.Now() + } + m.ruler.Load(rules) + return true +} + +func (m *Manager) exportMetrics( + rules *adaptive_placementpb.PlacementRules, + stats *adaptive_placementpb.DistributionStats, +) { + if m.config.ExportShardLimitMetrics { + for _, dataset := range rules.Datasets { + m.metrics.datasetShardLimit.WithLabelValues( + rules.Tenants[dataset.Tenant].TenantId, + dataset.Name, + strconv.Itoa(int(dataset.LoadBalancing))). + Set(float64(dataset.DatasetShardLimit)) + } + } + + if m.config.ExportShardUsageMetrics { + for _, dataset := range stats.Datasets { + m.metrics.datasetShardUsage.WithLabelValues( + stats.Tenants[dataset.Tenant].TenantId, + dataset.Name). + Set(float64(sum(dataset.Usage))) + } + } + + if m.config.ExportShardUsageBreakdownMetrics { + for _, dataset := range stats.Datasets { + for i, ds := range dataset.Shards { + m.metrics.datasetShardUsageBreakdown.WithLabelValues( + stats.Tenants[dataset.Tenant].TenantId, + dataset.Name, + strconv.Itoa(int(stats.Shards[ds].Id)), + stats.Shards[ds].Owner). + Set(float64(dataset.Usage[i])) + } + } + } +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager_metrics.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager_metrics.go new file mode 100644 index 0000000000..6fb4298ac3 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager_metrics.go @@ -0,0 +1,58 @@ +package adaptiveplacement + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type managerMetrics struct { + rulesTotal prometheus.Gauge + statsTotal prometheus.Gauge + lastUpdate prometheus.Gauge + + datasetShardLimit *prometheus.GaugeVec + datasetShardUsage *prometheus.GaugeVec + datasetShardUsageBreakdown *prometheus.GaugeVec +} + +func newManagerMetrics(reg prometheus.Registerer) *managerMetrics { + m := &managerMetrics{ + lastUpdate: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "pyroscope_adaptive_placement_rules_last_update_time", + Help: "Second timestamp of the last successful update.", + }), + rulesTotal: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "pyroscope_adaptive_placement_rules", + Help: "Total number of rule entries.", + }), + statsTotal: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "pyroscope_adaptive_placement_stats", + Help: "Total number of stats entries.", + }), + + datasetShardLimit: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pyroscope_adaptive_placement_dataset_shard_limit", + Help: "Maximum number of shards allowed for a dataset.", + }, []string{"tenant", "dataset", "load_balancing"}), + + datasetShardUsage: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pyroscope_adaptive_placement_dataset_shard_usage_bytes_per_second", + Help: "Usage of the dataset in bytes per second.", + }, []string{"tenant", "dataset"}), + + datasetShardUsageBreakdown: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pyroscope_adaptive_placement_dataset_shard_usage_per_shard_bytes_per_second", + Help: "Usage of the dataset shard in bytes per second.", + }, []string{"tenant", "dataset", "shard_id", "shard_owner"}), + } + if reg != nil { + reg.MustRegister( + m.lastUpdate, + m.rulesTotal, + m.statsTotal, + m.datasetShardLimit, + m.datasetShardUsage, + m.datasetShardUsageBreakdown, + ) + } + return m +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager_test.go new file mode 100644 index 0000000000..5f0e5a8d04 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/placement_manager_test.go @@ -0,0 +1,157 @@ +package adaptiveplacement + +import ( + "context" + "fmt" + "io" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + + "github.com/grafana/pyroscope/v2/pkg/iter" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockadaptiveplacement" +) + +type managerSuite struct { + suite.Suite + + logger log.Logger + reg *prometheus.Registry + config Config + limits *mockLimits + store *mockadaptiveplacement.MockStore + manager *Manager +} + +func (s *managerSuite) SetupTest() { + s.logger = log.NewLogfmtLogger(io.Discard) + s.reg = prometheus.NewRegistry() + s.config = Config{ + PlacementUpdateInterval: 15 * time.Second, + PlacementRetentionPeriod: 15 * time.Minute, + + StatsConfidencePeriod: 0, + StatsAggregationWindow: 3 * time.Minute, + StatsRetentionPeriod: 5 * time.Minute, + } + s.limits = new(mockLimits) + s.store = new(mockadaptiveplacement.MockStore) + s.manager = NewManager( + s.logger, + s.reg, + s.config, + s.limits, + s.store, + ) +} + +func (s *managerSuite) BeforeTest(_, _ string) { + ctx := context.Background() + svc := s.manager.Service() + s.Require().NoError(svc.StartAsync(ctx)) + s.Require().NoError(svc.AwaitRunning(ctx)) +} + +func (s *managerSuite) AfterTest(_, _ string) { + svc := s.manager.Service() + svc.StopAsync() + s.Require().NoError(svc.AwaitTerminated(context.Background())) + s.Require().Equal(services.Terminated, svc.State()) + s.limits.AssertExpectations(s.T()) + s.store.AssertExpectations(s.T()) +} + +func Test_ManagerSuite(t *testing.T) { suite.Run(t, new(managerSuite)) } + +func (s *managerSuite) Test_Manager_only_updates_rules_if_started() { + oldRules := &adaptive_placementpb.PlacementRules{CreatedAt: 100} + s.store.On("LoadRules", mock.Anything).Return(oldRules, nil) + + newRules := func(r *adaptive_placementpb.PlacementRules) bool { return r.CreatedAt > 100 } + s.store.On("StoreRules", mock.Anything, mock.MatchedBy(newRules)).Return(nil).Once() + s.store.On("StoreStats", mock.Anything, mock.Anything).Return(nil).Once() + + s.manager.Start() + s.manager.updateRules(context.Background()) + + s.manager.Stop() + s.manager.updateRules(context.Background()) +} + +func (s *managerSuite) Test_Manager_doesnt_update_rules_until_confidence_period_expiration() { + s.manager.config.StatsConfidencePeriod = time.Minute + + oldRules := &adaptive_placementpb.PlacementRules{CreatedAt: 100} + s.store.On("LoadRules", mock.Anything).Return(oldRules, nil) + + s.manager.Start() + s.manager.updateRules(context.Background()) +} + +func (s *managerSuite) Test_Manager_doesnt_update_rules_if_store_fails() { + s.store.On("LoadRules", mock.Anything). + Return((*adaptive_placementpb.PlacementRules)(nil), fmt.Errorf("error")) + + s.manager.Start() + s.manager.updateRules(context.Background()) +} + +func (s *managerSuite) Test_Manager_updates_rules_if_no_rules_not_found() { + s.store.On("LoadRules", mock.Anything). + Return((*adaptive_placementpb.PlacementRules)(nil), ErrRulesNotFound) + + newRules := func(r *adaptive_placementpb.PlacementRules) bool { return r.CreatedAt > 0 } + s.store.On("StoreRules", mock.Anything, mock.MatchedBy(newRules)).Return(nil).Once() + s.store.On("StoreStats", mock.Anything, mock.Anything).Return(nil).Once() + + s.manager.Start() + s.manager.updateRules(context.Background()) +} + +func (s *managerSuite) Test_Manager_exports_metrics() { + s.manager.config.ExportShardLimitMetrics = true + s.manager.config.ExportShardUsageMetrics = true + s.manager.config.ExportShardUsageBreakdownMetrics = true + + oldRules := &adaptive_placementpb.PlacementRules{CreatedAt: 100} + s.store.On("LoadRules", mock.Anything).Return(oldRules, nil) + + newRules := func(r *adaptive_placementpb.PlacementRules) bool { return r.CreatedAt > 100 } + s.store.On("StoreRules", mock.Anything, mock.MatchedBy(newRules)).Return(nil).Once() + s.store.On("StoreStats", mock.Anything, mock.Anything).Return(nil).Once() + + s.limits.On("PlacementLimits", mock.Anything).Return(PlacementLimits{ + DefaultDatasetShards: 2, + MinDatasetShards: 1, + UnitSizeBytes: 256 << 10, + BurstWindow: time.Minute, + DecayWindow: time.Minute, + }) + + s.manager.RecordStats(iter.NewSliceIterator([]Sample{ + {TenantID: "tenant-a", DatasetName: "dataset-a", ShardID: 1, Size: 100 << 10}, + {TenantID: "tenant-a", DatasetName: "dataset-a", ShardID: 2, Size: 100 << 10}, + {TenantID: "tenant-b", DatasetName: "dataset-b", ShardID: 2, Size: 100 << 10}, + })) + + s.manager.Start() + s.manager.updateRules(context.Background()) + + n, err := testutil.GatherAndCount(s.reg, + "pyroscope_adaptive_placement_rules_last_update_time", + "pyroscope_adaptive_placement_rules", + "pyroscope_adaptive_placement_stats", + "pyroscope_adaptive_placement_dataset_shard_limit", + "pyroscope_adaptive_placement_dataset_shard_usage_bytes_per_second", + "pyroscope_adaptive_placement_dataset_shard_usage_per_shard_bytes_per_second", + ) + s.Require().NoError(err) + s.Assert().Equal(10, n) +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ruler.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ruler.go new file mode 100644 index 0000000000..c5816ab8a4 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ruler.go @@ -0,0 +1,180 @@ +package adaptiveplacement + +import ( + "slices" + "strings" + "time" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +// Ruler builds placement rules based on distribution stats. +// +// Ruler is not safe for concurrent use: the caller should +// ensure synchronization. +type Ruler struct { + limits Limits + datasets map[datasetKey]*datasetShards +} + +func NewRuler(limits Limits) *Ruler { + return &Ruler{ + limits: limits, + datasets: make(map[datasetKey]*datasetShards), + } +} + +func (r *Ruler) Load(rules *adaptive_placementpb.PlacementRules) { + tenantLimits := make([]PlacementLimits, len(rules.Tenants)) + for i, t := range rules.Tenants { + tenantLimits[i] = r.limits.PlacementLimits(t.TenantId) + } + for _, ds := range rules.Datasets { + k := datasetKey{ + tenant: rules.Tenants[ds.Tenant].TenantId, + dataset: ds.Name, + } + limits := tenantLimits[ds.Tenant] + dataset := &datasetShards{ + allocator: newShardAllocator(limits), + lastUpdate: rules.CreatedAt, + tenantShards: ds.TenantShardLimit, + datasetShards: ds.DatasetShardLimit, + loadBalancing: ds.LoadBalancing, + } + // NOTE(kolesnikovae): We prohibit decreasing the number + // of shards for the dataset till the expiration of the + // decay window since the moment rules were created. Thus, + // if statistics are not available or populated slowly, + // we won't shrink the dataset prematurely but will be + // able to scale out if needed. + dataset.allocator.decayOffset = rules.CreatedAt + dataset.allocator.currentMin = int(ds.DatasetShardLimit) + r.datasets[k] = dataset + } +} + +func (r *Ruler) BuildRules(stats *adaptive_placementpb.DistributionStats) *adaptive_placementpb.PlacementRules { + rules := adaptive_placementpb.PlacementRules{ + Tenants: make([]*adaptive_placementpb.TenantPlacement, len(stats.Tenants)), + Datasets: make([]*adaptive_placementpb.DatasetPlacement, len(stats.Datasets)), + CreatedAt: stats.CreatedAt, + } + + tenantLimits := make([]PlacementLimits, len(stats.Tenants)) + tenants := make(map[string]int) + for i, t := range stats.Tenants { + tenants[t.TenantId] = i + tenantLimits[i] = r.limits.PlacementLimits(t.TenantId) + rules.Tenants[i] = &adaptive_placementpb.TenantPlacement{ + TenantId: t.TenantId, + } + } + + for i, datasetStats := range stats.Datasets { + k := datasetKey{ + tenant: rules.Tenants[datasetStats.Tenant].TenantId, + dataset: datasetStats.Name, + } + limits := tenantLimits[datasetStats.Tenant] + dataset, ok := r.datasets[k] + if !ok { + dataset = &datasetShards{ + allocator: new(shardAllocator), + lastUpdate: stats.CreatedAt, + tenantShards: limits.TenantShards, + datasetShards: limits.DefaultDatasetShards, + loadBalancing: limits.LoadBalancing.proto(), + } + r.datasets[k] = dataset + } + rules.Datasets[i] = dataset.placement(datasetStats, limits, stats.CreatedAt) + } + + // Include datasets that were not present in the current stats. + // Although, not strictly required, we iterate over the keys + // in a deterministic order to make the output deterministic. + keys := make([]datasetKey, 0, len(r.datasets)) + for k, dataset := range r.datasets { + if dataset.lastUpdate < stats.CreatedAt { + keys = append(keys, k) + } + } + slices.SortFunc(keys, func(a, b datasetKey) int { + return a.compare(b) + }) + + for _, k := range keys { + dataset := r.datasets[k] + t, ok := tenants[k.tenant] + if !ok { + t = len(rules.Tenants) + tenants[k.tenant] = t + rules.Tenants = append(rules.Tenants, &adaptive_placementpb.TenantPlacement{ + TenantId: k.tenant, + }) + } + rules.Datasets = append(rules.Datasets, &adaptive_placementpb.DatasetPlacement{ + Tenant: uint32(t), + Name: k.dataset, + TenantShardLimit: dataset.tenantShards, + DatasetShardLimit: dataset.datasetShards, + LoadBalancing: dataset.loadBalancing, + }) + } + + return &rules +} + +func (r *Ruler) Expire(before time.Time) { + for k, ds := range r.datasets { + if time.Unix(0, ds.lastUpdate).Before(before) { + delete(r.datasets, k) + } + } +} + +type datasetKey struct{ tenant, dataset string } + +func (k datasetKey) compare(x datasetKey) int { + if c := strings.Compare(k.tenant, x.tenant); c != 0 { + return c + } + return strings.Compare(k.dataset, x.dataset) +} + +type datasetShards struct { + allocator *shardAllocator + // Last time the dataset was updated, + // according to the stats update time. + lastUpdate int64 + // Limits. + tenantShards uint64 + datasetShards uint64 + loadBalancing adaptive_placementpb.LoadBalancing +} + +func (d *datasetShards) placement( + stats *adaptive_placementpb.DatasetStats, + limits PlacementLimits, + now int64, +) *adaptive_placementpb.DatasetPlacement { + d.lastUpdate = now + d.allocator.setLimits(limits) + d.tenantShards = limits.TenantShards + d.datasetShards = uint64(d.allocator.observe(sum(stats.Usage), now)) + // Determine whether we need to change the load balancing strategy. + configured := limits + if configured.LoadBalancing != DynamicLoadBalancing { + d.loadBalancing = configured.LoadBalancing.proto() + } else if configured.LoadBalancing.needsDynamicBalancing(d.loadBalancing) { + d.loadBalancing = loadBalancingStrategy(stats, d.allocator.unitSize, d.allocator.target).proto() + } + return &adaptive_placementpb.DatasetPlacement{ + Tenant: stats.Tenant, + Name: stats.Name, + TenantShardLimit: d.tenantShards, + DatasetShardLimit: d.datasetShards, + LoadBalancing: d.loadBalancing, + } +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ruler_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ruler_test.go new file mode 100644 index 0000000000..e1f046f2f9 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/ruler_test.go @@ -0,0 +1,207 @@ +package adaptiveplacement + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +type mockLimits struct{ mock.Mock } + +func (m *mockLimits) PlacementLimits(tenant string) PlacementLimits { + return m.Called(tenant).Get(0).(PlacementLimits) +} + +func Test_Ruler(t *testing.T) { + const unitSize = 512 << 10 + defaults := PlacementLimits{ + TenantShards: 10, + DefaultDatasetShards: 2, + MinDatasetShards: 1, + MaxDatasetShards: 10, + UnitSizeBytes: unitSize, + BurstWindow: 17 * time.Minute, + DecayWindow: 19 * time.Minute, + LoadBalancing: DynamicLoadBalancing, + } + + withDefaults := func(fn func(*PlacementLimits)) PlacementLimits { + limits := defaults + fn(&limits) + return limits + } + + defaultLimits := withDefaults(func(l *PlacementLimits) {}) + + m := new(mockLimits) + m.On("PlacementLimits", "tenant-a"). + Return(withDefaults(func(l *PlacementLimits) { + l.TenantShards = 20 + l.DefaultDatasetShards = 3 + })) + + m.On("PlacementLimits", "tenant-b").Return(withDefaults(func(l *PlacementLimits) { + l.LoadBalancing = FingerprintLoadBalancing + })) + + m.On("PlacementLimits", "tenant-c").Return(defaultLimits) + + m.On("PlacementLimits", "tenant-d").Return(withDefaults(func(l *PlacementLimits) { + l.MinDatasetShards = 5 + l.LoadBalancing = RoundRobinLoadBalancing + })) + + oldRules := &adaptive_placementpb.PlacementRules{ + Tenants: []*adaptive_placementpb.TenantPlacement{ + {TenantId: "tenant-a"}, + {TenantId: "tenant-b"}, + {TenantId: "tenant-c"}, + }, + Datasets: []*adaptive_placementpb.DatasetPlacement{ + { + Tenant: 0, + Name: "dataset-a", + TenantShardLimit: 2, + DatasetShardLimit: 5, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN, + }, + { + Tenant: 1, + Name: "dataset-b", + TenantShardLimit: 2, + DatasetShardLimit: 3, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN, + }, + { + Tenant: 2, + Name: "dataset-c", + TenantShardLimit: 2, + DatasetShardLimit: 3, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_FINGERPRINT, + }, + }, + } + + stats := &adaptive_placementpb.DistributionStats{ + Tenants: []*adaptive_placementpb.TenantStats{ + {TenantId: "tenant-a"}, + {TenantId: "tenant-b"}, + {TenantId: "tenant-c"}, + {TenantId: "tenant-d"}, + }, + Datasets: []*adaptive_placementpb.DatasetStats{ + { + Tenant: 0, + Name: "dataset-a", + Shards: []uint32{0, 1, 2, 3, 4}, + Usage: []uint64{unitSize, unitSize, unitSize, unitSize, unitSize / 2}, + }, + { + Tenant: 1, + Name: "dataset-b", + Shards: []uint32{0, 1, 2}, + Usage: []uint64{unitSize, unitSize, unitSize}, + }, + { + Tenant: 2, + Name: "dataset-c", + Shards: []uint32{0, 1, 2}, + Usage: []uint64{unitSize, unitSize, unitSize / 2}, + }, + { + Tenant: 3, + Name: "dataset-d", + Shards: []uint32{0}, + Usage: []uint64{unitSize}, + }, + }, + Shards: []*adaptive_placementpb.ShardStats{ + {Id: 1, Owner: "node-a"}, + {Id: 2, Owner: "node-b"}, + {Id: 3, Owner: "node-c"}, + {Id: 4, Owner: "node-a"}, + {Id: 5, Owner: "node-c"}, + }, + CreatedAt: 1, + } + + expected := &adaptive_placementpb.PlacementRules{ + CreatedAt: 1, + Tenants: []*adaptive_placementpb.TenantPlacement{ + {TenantId: "tenant-a"}, + {TenantId: "tenant-b"}, + {TenantId: "tenant-c"}, + {TenantId: "tenant-d"}, + }, + Datasets: []*adaptive_placementpb.DatasetPlacement{ + { + Tenant: 0, + Name: "dataset-a", + TenantShardLimit: 20, + DatasetShardLimit: 5, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN, + }, + { + Tenant: 1, + Name: "dataset-b", + TenantShardLimit: 10, + DatasetShardLimit: 4, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_FINGERPRINT, + }, + { + Tenant: 2, + Name: "dataset-c", + TenantShardLimit: 10, + DatasetShardLimit: 3, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_FINGERPRINT, + }, + { + Tenant: 3, + Name: "dataset-d", + TenantShardLimit: 10, + DatasetShardLimit: 5, + LoadBalancing: adaptive_placementpb.LoadBalancing_LOAD_BALANCING_ROUND_ROBIN, + }, + }, + } + + ruler := NewRuler(m) + ruler.Load(oldRules) + assert.Equal(t, expected.String(), ruler.BuildRules(stats).String()) + + // Next update only includes tenant-a dataset-a. + // We expect that dataset-b and dataset-c will still be present. + update := &adaptive_placementpb.DistributionStats{ + Tenants: []*adaptive_placementpb.TenantStats{ + {TenantId: "tenant-a"}, + }, + Datasets: []*adaptive_placementpb.DatasetStats{ + { + Tenant: 0, + Name: "dataset-a", + Shards: []uint32{0, 1, 2, 3, 4}, + Usage: []uint64{unitSize, unitSize, unitSize, unitSize, unitSize / 2}, + }, + }, + Shards: []*adaptive_placementpb.ShardStats{ + {Id: 1, Owner: "node-a"}, + {Id: 2, Owner: "node-b"}, + {Id: 3, Owner: "node-c"}, + {Id: 4, Owner: "node-a"}, + {Id: 5, Owner: "node-c"}, + }, + CreatedAt: 2, + } + + expected.CreatedAt = 2 + assert.Equal(t, expected.String(), ruler.BuildRules(update).String()) + + ruler.Expire(time.Now()) + expected = &adaptive_placementpb.PlacementRules{CreatedAt: 3} + empty := &adaptive_placementpb.DistributionStats{CreatedAt: 3} + assert.Equal(t, expected.String(), ruler.BuildRules(empty).String()) +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/shard_allocator.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/shard_allocator.go new file mode 100644 index 0000000000..79d8d5a545 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/shard_allocator.go @@ -0,0 +1,90 @@ +package adaptiveplacement + +import ( + "math" +) + +// shardAllocator dynamically adjusts the number of shards allocated for a +// dataset based on observed data rates. The system is designed to scale out +// rapidly in response to increased load while scaling in more conservatively +// to prevent unnecessary shard churn. +// +// The system calculates the total data rate from incoming dataset statistics +// and determines the required number of shards based on a fixed unit size +// i.e., the portion of the rate that a single shard can handle. Note that +// it is expected that the rate values are aggregated over a time window and +// are not varying overly frequently. +// +// When the observed data rate increases, the system aggressively increases the +// number of shards. This is achieved using an exponential growth factor that +// doubles the shard allocation request on consecutive scale-out events. This +// allows preventing "laddering" (slow, step-wise shard increases) when load +// is growing steadily. +// +// To avoid the risk of premature shrinking that could cause oscillations, the +// system decreases the number of shards more cautiously. It enforces a minimum +// shard count over a configurable time window: the system doesn't allocate +// fewer shards than were allocated during the last window. +type shardAllocator struct { + // Unit size denotes the portion of rate that needs + // to be allocated to a single shard. + unitSize uint64 + // Minimum and maximum number of shards allowed. + min, max int + // Burst window specifies the time interval during which + // the shard allocation delta multiplier grows on scale outs. + burstWindow int64 + // Decay window specifies the minimal time interval + // before the target number of shards can be decreased. + decayWindow int64 + + target int // Target number of shards. + burstOffset int64 // Timestamp of the burst window start. + multiplier float64 + decayOffset int64 // Timestamp of the decay window start. + previousMin int // Minimum number of shards in the previous decay window. + currentMin int // Minimum number of shards in the current decay window. +} + +func newShardAllocator(limits PlacementLimits) *shardAllocator { + a := new(shardAllocator) + a.setLimits(limits) + return a +} + +func (a *shardAllocator) setLimits(limits PlacementLimits) { + a.unitSize = limits.UnitSizeBytes + a.min = int(limits.MinDatasetShards) + a.max = int(limits.MaxDatasetShards) + a.burstWindow = limits.BurstWindow.Nanoseconds() + a.decayWindow = limits.DecayWindow.Nanoseconds() +} + +func (a *shardAllocator) observe(usage uint64, now int64) int { + target := int(usage/a.unitSize) + 1 + delta := target - a.target + if delta > 0 { + // Scale out. + if a.burstOffset == 0 || now-a.burstOffset >= a.burstWindow { + // Reset multiplier if burst window has passed. + a.multiplier = 1 + } else { + // Increase multiplier on consecutive scale-outs within burst window. + // Limiting the multiplier here allow us to not worry about overflows. + if a.multiplier < 16 { + a.multiplier *= 2 + } + scaled := target + int(math.Ceil(float64(delta)*a.multiplier)) + target = min(2*target, scaled) + } + // Start/prolong burst window. + a.burstOffset = now + } + if a.decayOffset == 0 || now-a.decayOffset >= a.decayWindow { + a.previousMin, a.currentMin = a.currentMin, target + a.decayOffset = now + } + a.currentMin = max(a.currentMin, target) + a.target = min(a.max, max(a.min, a.previousMin, a.currentMin)) + return a.target +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/shard_allocator_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/shard_allocator_test.go new file mode 100644 index 0000000000..776acb8a59 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/shard_allocator_test.go @@ -0,0 +1,59 @@ +package adaptiveplacement + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_shard_allocator(t *testing.T) { + a := &shardAllocator{ + unitSize: 10, + min: 1, + max: 5, + burstWindow: 50, + decayWindow: 50, + } + + for i, test := range []struct { + usage uint64 + now int64 + want int + }{ + {0, 0, 1}, + {0, 1, 1}, + {5, 2, 1}, + {10, 3, 2}, + {10, 4, 2}, + {11, 5, 2}, + {20, 6, 5}, + {10, 7, 5}, + {5, 8, 5}, + {5, 9, 5}, + {5, 51, 5}, + {5, 101, 1}, + {100, 151, 5}, + } { + require.Equal(t, test.want, a.observe(test.usage, test.now), fmt.Sprint(i)) + } +} + +func Test_shard_limit(t *testing.T) { + a := &shardAllocator{ + unitSize: 128 << 10, + min: 1, + max: 10, + burstWindow: 1e9 * 10, + decayWindow: 1e9 * 10 * 5, + } + + var now int64 + var hi int + for i := uint64(0); i < 100; i++ { + old := hi + hi = a.observe(2*a.unitSize*i, now) + require.GreaterOrEqual(t, hi, old) + now += 1e9 * 10 + } +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/store.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/store.go new file mode 100644 index 0000000000..65fbe63959 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/store.go @@ -0,0 +1,122 @@ +package adaptiveplacement + +import ( + "bytes" + "context" + "errors" + "time" + + "github.com/thanos-io/objstore" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" +) + +const ( + pathRoot = "adaptive_placement/" + rulesFilePath = pathRoot + "placement_rules.binpb" + statsFilePath = pathRoot + "placement_stats.binpb" +) + +var ( + ErrRulesNotFound = errors.New("placement rules not found") + ErrStatsNotFound = errors.New("placement stats not found") +) + +type StoreReader interface { + LoadRules(context.Context) (*adaptive_placementpb.PlacementRules, error) + LoadStats(context.Context) (*adaptive_placementpb.DistributionStats, error) +} + +type StoreWriter interface { + StoreRules(context.Context, *adaptive_placementpb.PlacementRules) error + StoreStats(context.Context, *adaptive_placementpb.DistributionStats) error +} + +type Store interface { + StoreReader + StoreWriter +} + +type BucketStore struct{ bucket objstore.Bucket } + +func NewStore(bucket objstore.Bucket) *BucketStore { return &BucketStore{bucket: bucket} } + +func (s *BucketStore) LoadRules(ctx context.Context) (*adaptive_placementpb.PlacementRules, error) { + var rules adaptive_placementpb.PlacementRules + if err := s.get(ctx, rulesFilePath, &rules); err != nil { + if s.bucket.IsObjNotFoundErr(err) { + return nil, ErrRulesNotFound + } + return nil, err + } + return &rules, nil +} + +func (s *BucketStore) LoadStats(ctx context.Context) (*adaptive_placementpb.DistributionStats, error) { + var stats adaptive_placementpb.DistributionStats + if err := s.get(ctx, statsFilePath, &stats); err != nil { + if s.bucket.IsObjNotFoundErr(err) { + return nil, ErrStatsNotFound + } + return nil, err + } + return &stats, nil +} + +func (s *BucketStore) StoreRules(ctx context.Context, rules *adaptive_placementpb.PlacementRules) error { + return s.put(ctx, rulesFilePath, rules) +} + +func (s *BucketStore) StoreStats(ctx context.Context, stats *adaptive_placementpb.DistributionStats) error { + return s.put(ctx, statsFilePath, stats) +} + +type vtProtoMessage interface { + UnmarshalVT([]byte) error + MarshalVT() ([]byte, error) +} + +func (s *BucketStore) get(ctx context.Context, name string, m vtProtoMessage) error { + r, err := s.bucket.Get(ctx, name) + if err != nil { + return err + } + defer func() { + _ = r.Close() + }() + var buf bytes.Buffer + if _, err = buf.ReadFrom(r); err != nil { + return err + } + return m.UnmarshalVT(buf.Bytes()) +} + +func (s *BucketStore) put(ctx context.Context, name string, m vtProtoMessage) error { + b, err := m.MarshalVT() + if err != nil { + return err + } + return s.bucket.Upload(ctx, name, bytes.NewReader(b)) +} + +// EmptyStore is a Store implementation that always returns +// empty rules and stats, and doesn't store anything. +type EmptyStore struct{} + +func NewEmptyStore() *EmptyStore { return new(EmptyStore) } + +func (e *EmptyStore) LoadRules(context.Context) (*adaptive_placementpb.PlacementRules, error) { + return &adaptive_placementpb.PlacementRules{CreatedAt: time.Now().UnixNano()}, nil +} + +func (e *EmptyStore) LoadStats(context.Context) (*adaptive_placementpb.DistributionStats, error) { + return &adaptive_placementpb.DistributionStats{CreatedAt: time.Now().UnixNano()}, nil +} + +func (e *EmptyStore) StoreRules(context.Context, *adaptive_placementpb.PlacementRules) error { + return nil +} + +func (e *EmptyStore) StoreStats(context.Context, *adaptive_placementpb.DistributionStats) error { + return nil +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/store_test.go b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/store_test.go new file mode 100644 index 0000000000..c1703837b2 --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/store_test.go @@ -0,0 +1,109 @@ +package adaptiveplacement + +import ( + "bytes" + "context" + "fmt" + "io" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" +) + +type storeSuite struct { + suite.Suite + + bucket *mockobjstore.MockBucket + store *BucketStore +} + +func (s *storeSuite) SetupTest() { + s.bucket = new(mockobjstore.MockBucket) + s.store = NewStore(s.bucket) +} + +func Test_StoreSuite(t *testing.T) { suite.Run(t, new(storeSuite)) } + +func (s *storeSuite) Test_LoadRules() { + rules := &adaptive_placementpb.PlacementRules{CreatedAt: 1} + s.bucket.On("Get", mock.Anything, rulesFilePath). + Return(s.marshal(rules), nil) + loaded, err := s.store.LoadRules(context.Background()) + s.NoError(err) + s.Equal(rules, loaded) + s.bucket.AssertExpectations(s.T()) +} + +func (s *storeSuite) Test_LoadRules_not_found() { + notFound := fmt.Errorf("not found") + s.bucket.On("Get", mock.Anything, rulesFilePath). + Return(nil, notFound) + s.bucket.On("IsObjNotFoundErr", notFound).Return(true) + _, err := s.store.LoadRules(context.Background()) + s.ErrorIs(err, ErrRulesNotFound) + s.bucket.AssertExpectations(s.T()) +} + +func (s *storeSuite) Test_StoreRules() { + rules := &adaptive_placementpb.PlacementRules{CreatedAt: 1} + s.bucket.On("Upload", mock.Anything, rulesFilePath, mock.Anything). + Run(func(args mock.Arguments) { + var stored adaptive_placementpb.PlacementRules + s.unmarshal(args[2].(io.Reader), &stored) + s.Equal(rules, &stored) + }). + Return(nil). + Once() + s.NoError(s.store.StoreRules(context.Background(), rules)) + s.bucket.AssertExpectations(s.T()) +} + +func (s *storeSuite) Test_LoadStats() { + stats := &adaptive_placementpb.DistributionStats{CreatedAt: 1} + s.bucket.On("Get", mock.Anything, statsFilePath). + Return(s.marshal(stats), nil) + loaded, err := s.store.LoadStats(context.Background()) + s.NoError(err) + s.Equal(stats, loaded) + s.bucket.AssertExpectations(s.T()) +} + +func (s *storeSuite) Test_LoadStats_not_found() { + notFound := fmt.Errorf("not found") + s.bucket.On("Get", mock.Anything, statsFilePath). + Return(nil, notFound) + s.bucket.On("IsObjNotFoundErr", notFound).Return(true) + _, err := s.store.LoadStats(context.Background()) + s.ErrorIs(err, ErrStatsNotFound) + s.bucket.AssertExpectations(s.T()) +} + +func (s *storeSuite) Test_StoreStats() { + stats := &adaptive_placementpb.DistributionStats{CreatedAt: 1} + s.bucket.On("Upload", mock.Anything, statsFilePath, mock.Anything). + Run(func(args mock.Arguments) { + var stored adaptive_placementpb.DistributionStats + s.unmarshal(args[2].(io.Reader), &stored) + s.Equal(stats, &stored) + }). + Return(nil). + Once() + s.NoError(s.store.StoreStats(context.Background(), stats)) + s.bucket.AssertExpectations(s.T()) +} + +func (s *storeSuite) marshal(m vtProtoMessage) io.ReadCloser { + b, err := m.MarshalVT() + s.Require().NoError(err) + return io.NopCloser(bytes.NewBuffer(b)) +} + +func (s *storeSuite) unmarshal(r io.Reader, m vtProtoMessage) { + b, err := io.ReadAll(r) + s.Require().NoError(err) + s.Require().NoError(m.UnmarshalVT(b)) +} diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes.png new file mode 100644 index 0000000000..a97f06d957 Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes_2.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes_2.png new file mode 100644 index 0000000000..06c478156d Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes_2.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes_3.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes_3.png new file mode 100644 index 0000000000..4baed54146 Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/extreme_spikes_3.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/low_rate_oscillations.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/low_rate_oscillations.png new file mode 100644 index 0000000000..4339738ed2 Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/low_rate_oscillations.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/low_rate_oscillations_2.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/low_rate_oscillations_2.png new file mode 100644 index 0000000000..34a261f542 Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/low_rate_oscillations_2.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steady_front.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steady_front.png new file mode 100644 index 0000000000..6c721c0da8 Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steady_front.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steady_front_2.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steady_front_2.png new file mode 100644 index 0000000000..f9df07881c Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steady_front_2.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steep_front.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steep_front.png new file mode 100644 index 0000000000..7496007d0a Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steep_front.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steep_front_2.png b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steep_front_2.png new file mode 100644 index 0000000000..4ad8c806a3 Binary files /dev/null and b/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/testdata/plots/steep_front_2.png differ diff --git a/pkg/segmentwriter/client/distributor/placement/placement.go b/pkg/segmentwriter/client/distributor/placement/placement.go new file mode 100644 index 0000000000..5e92e6089e --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/placement.go @@ -0,0 +1,111 @@ +package placement + +import ( + "github.com/grafana/dskit/ring" + + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +// Placement is a strategy to distribute keys over shards. +type Placement interface { + Policy(Key) Policy +} + +type Key struct { + TenantID string + DatasetName string + + Tenant uint64 + Dataset uint64 + Fingerprint uint64 +} + +// Policy is a placement policy of a given key. +type Policy struct { + // TenantShards returns the number of shards + // available to the tenant. + TenantShards int + // DatasetShards returns the number of shards + // available to the dataset from the tenant shards. + DatasetShards int + // PickShard returns the shard index + // for a given key from n total. + PickShard func(n int) int +} + +// ShardMapping represents the placement of a given key. +// +// Each key is mapped to one of the shards, based on the placement +// strategy. In turn, each shard is associated with an instance. +// +// ShardMapping provides a number of instances that can host the key. +// It is assumed, that the caller will use the first one by default, +// and will try the rest in case of failure. This is done to avoid +// excessive data distribution in case of temporary unavailability +// of the instances: first, we try the instance that the key is +// mapped to, then we try the instances that host the dataset, then +// instances that host the tenant. Finally, we try any instances. +// +// Note that the instances are not guaranteed to be unique. +// It's also not guaranteed that the instances are available. +// Use ActiveInstances wrapper if you need to filter out inactive +// instances and duplicates. +type ShardMapping struct { + Instances iter.Iterator[ring.InstanceDesc] + Shard uint32 +} + +// ActiveInstances returns an iterator that filters out inactive instances. +// Note that active state does not mean that the instance is healthy. +func ActiveInstances(i iter.Iterator[ring.InstanceDesc]) iter.Iterator[ring.InstanceDesc] { + return FilterInstances(InstanceSet(i), func(x *ring.InstanceDesc) bool { + return x.State != ring.ACTIVE + }) +} + +func InstanceSet(i iter.Iterator[ring.InstanceDesc]) iter.Iterator[ring.InstanceDesc] { + seen := make(map[string]struct{}) + return FilterInstances(i, func(x *ring.InstanceDesc) bool { + k := x.Id + if k == "" { + k = x.Addr + } + if _, ok := seen[k]; ok { + return true + } + seen[k] = struct{}{} + return false + }) +} + +// FilterInstances returns an iterator that filters out +// instances on which the filter function returns true. +func FilterInstances( + i iter.Iterator[ring.InstanceDesc], + filter func(x *ring.InstanceDesc) bool, +) iter.Iterator[ring.InstanceDesc] { + return &instances{ + Iterator: i, + filter: filter, + } +} + +type instances struct { + iter.Iterator[ring.InstanceDesc] + filter func(*ring.InstanceDesc) bool + cur ring.InstanceDesc +} + +func (i *instances) At() ring.InstanceDesc { return i.cur } + +func (i *instances) Next() bool { + for i.Iterator.Next() { + x := i.Iterator.At() + if i.filter(&x) { + continue + } + i.cur = x + return true + } + return false +} diff --git a/pkg/segmentwriter/client/distributor/placement/placement_test.go b/pkg/segmentwriter/client/distributor/placement/placement_test.go new file mode 100644 index 0000000000..33a2ab3e2c --- /dev/null +++ b/pkg/segmentwriter/client/distributor/placement/placement_test.go @@ -0,0 +1,71 @@ +package placement + +import ( + "testing" + + "github.com/grafana/dskit/ring" + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/iter" +) + +func Test_ActiveInstances(t *testing.T) { + for _, test := range []struct { + description string + instances []ring.InstanceDesc + expected []ring.InstanceDesc + }{ + { + description: "empty", + }, + { + description: "all active", + instances: []ring.InstanceDesc{ + {Id: "a", State: ring.ACTIVE}, + {Id: "b", State: ring.ACTIVE}, + {Id: "c", State: ring.ACTIVE}, + }, + expected: []ring.InstanceDesc{ + {Id: "a", State: ring.ACTIVE}, + {Id: "b", State: ring.ACTIVE}, + {Id: "c", State: ring.ACTIVE}, + }, + }, + { + description: "active duplicate", + instances: []ring.InstanceDesc{ + {Id: "a", State: ring.ACTIVE}, + {Id: "a", State: ring.ACTIVE}, + }, + expected: []ring.InstanceDesc{ + {Id: "a", State: ring.ACTIVE}, + }, + }, + { + description: "non-active duplicate", + instances: []ring.InstanceDesc{ + {Id: "a", State: ring.PENDING}, + {Id: "a", State: ring.PENDING}, + }, + }, + { + description: "mixed", + instances: []ring.InstanceDesc{ + {Id: "a", State: ring.PENDING}, + {Id: "b", State: ring.ACTIVE}, + {Id: "c", State: ring.JOINING}, + {Id: "d", State: ring.LEAVING}, + {Id: "c", State: ring.JOINING}, + {Id: "e", State: ring.ACTIVE}, + {Id: "e", State: ring.ACTIVE}, + }, + expected: []ring.InstanceDesc{ + {Id: "b", State: ring.ACTIVE}, + {Id: "e", State: ring.ACTIVE}, + }, + }, + } { + active := ActiveInstances(iter.NewSliceIterator(test.instances)) + assert.Equal(t, test.expected, iter.MustSlice(active)) + } +} diff --git a/pkg/segmentwriter/memdb/head.go b/pkg/segmentwriter/memdb/head.go new file mode 100644 index 0000000000..7c30e7bcc6 --- /dev/null +++ b/pkg/segmentwriter/memdb/head.go @@ -0,0 +1,215 @@ +package memdb + +import ( + "bytes" + "context" + "fmt" + "math" + "sync" + + "github.com/google/uuid" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/model" + "go.uber.org/atomic" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/labels" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" +) + +type FlushedHead struct { + Index []byte + Profiles []byte + Symbols []byte + Unsymbolized bool + Meta struct { + ProfileTypeNames []string + MinTimeNanos int64 + MaxTimeNanos int64 + NumSamples uint64 + NumProfiles uint64 + NumSeries uint64 + } + + datasetIndexSeries []*profileSeries +} + +type datasetIndexWriter interface { + AddSeries(idx uint32, labels phlaremodel.Labels, fp model.Fingerprint) +} + +// WriteDatasetIndex feeds the flushed head's series (labels + fingerprint) +// into the given dataset index writer, attributing every series to the +// supplied dataset index (the dataset's global position in the block). +// It is safe to call concurrently with other heads' writes only if the +// writer itself is externally synchronised; segment flushes call it +// serially in dataset (tenant+service) order. +func (f *FlushedHead) WriteDatasetIndex(w datasetIndexWriter, idx uint32) { + for _, s := range f.datasetIndexSeries { + w.AddSeries(idx, s.lbs, s.fp) + } +} + +type Head struct { + symbols *symdb.PartitionWriter + metaLock sync.RWMutex + minTimeNanos int64 + maxTimeNanos int64 + totalSamples *atomic.Uint64 + profiles *profilesIndex + metrics *HeadMetrics +} + +func NewHead(metrics *HeadMetrics) *Head { + h := &Head{ + metrics: metrics, + symbols: symdb.NewPartitionWriter(0, &symdb.Config{ + Version: symdb.FormatV3, + }), + totalSamples: atomic.NewUint64(0), + minTimeNanos: math.MaxInt64, + maxTimeNanos: 0, + profiles: newProfileIndex(metrics), + } + + return h +} + +func (h *Head) Ingest(p *profilev1.Profile, id uuid.UUID, externalLabels []*typesv1.LabelPair, annotations []*typesv1.ProfileAnnotation) { + if len(p.Sample) == 0 { + return + } + + // Delta not supported. + externalLabels = phlaremodel.Labels(externalLabels).Delete(phlaremodel.LabelNameDelta) + // Label order is enforced to ensure that __profile_type__ and __service_name__ always + // come first in the label set. This is important for spatial locality: profiles are + // stored in the label series order. + externalLabels = phlaremodel.Labels(externalLabels).Delete(phlaremodel.LabelNameOrder) + + lbls, seriesFingerprints := labels.CreateProfileLabels(true, p, externalLabels...) + metricName := phlaremodel.Labels(externalLabels).Get(model.MetricNameLabel) + + var profileIngested bool + memProfiles := h.symbols.WriteProfileSymbols(p) + for idxType := range memProfiles { + profile := &memProfiles[idxType] + profile.ID = id + profile.SeriesFingerprint = seriesFingerprints[idxType] + profile.Samples = profile.Samples.Compact() + + profile.TotalValue = profile.Samples.Sum() + + profile.Annotations.Keys = make([]string, 0, len(annotations)) + profile.Annotations.Values = make([]string, 0, len(annotations)) + for _, annotation := range annotations { + profile.Annotations.Keys = append(profile.Annotations.Keys, annotation.Key) + profile.Annotations.Values = append(profile.Annotations.Values, annotation.Value) + } + + if profile.Samples.Len() == 0 { + continue + } + + h.profiles.Add(profile, lbls[idxType], metricName) + + profileIngested = true + h.totalSamples.Add(uint64(profile.Samples.Len())) + h.metrics.sampleValuesIngested.WithLabelValues(metricName).Add(float64(profile.Samples.Len())) + h.metrics.sampleValuesReceived.WithLabelValues(metricName).Add(float64(len(p.Sample))) + } + + if !profileIngested { + return + } + + h.metaLock.Lock() + if p.TimeNanos < h.minTimeNanos { + h.minTimeNanos = p.TimeNanos + } + if p.TimeNanos > h.maxTimeNanos { + h.maxTimeNanos = p.TimeNanos + } + h.metaLock.Unlock() +} + +func (h *Head) Flush(ctx context.Context) (res *FlushedHead, err error) { + t := prometheus.NewTimer(h.metrics.flushedBlockDurationSeconds) + defer t.ObserveDuration() + + if res, err = h.flush(ctx); err != nil { + h.metrics.flushedBlocks.WithLabelValues("failed").Inc() + return nil, err + } + + blockSize := len(res.Index) + len(res.Profiles) + len(res.Symbols) + h.metrics.flushedBlocks.WithLabelValues("success").Inc() + + unsymbolized := "false" + if res.Unsymbolized { + unsymbolized = "true" + } + + h.metrics.flushedBlocksUnsymbolized.WithLabelValues(unsymbolized).Inc() + h.metrics.flushedBlockSamples.Observe(float64(res.Meta.NumSamples)) + h.metrics.flusehdBlockProfiles.Observe(float64(res.Meta.NumProfiles)) + h.metrics.flushedBlockSeries.Observe(float64(res.Meta.NumSeries)) + h.metrics.flushedBlockSizeBytes.Observe(float64(blockSize)) + h.metrics.flushedFileSizeBytes.WithLabelValues("tsdb").Observe(float64(len(res.Index))) + h.metrics.flushedFileSizeBytes.WithLabelValues("profiles.parquet").Observe(float64(len(res.Profiles))) + h.metrics.flushedFileSizeBytes.WithLabelValues("symbols.symdb").Observe(float64(len(res.Symbols))) + return res, nil +} + +func (h *Head) flush(ctx context.Context) (*FlushedHead, error) { + var ( + err error + profiles []schemav1.InMemoryProfile + ) + res := new(FlushedHead) + res.Meta.MinTimeNanos = h.minTimeNanos + res.Meta.MaxTimeNanos = h.maxTimeNanos + res.Meta.NumSamples = h.totalSamples.Load() + res.Meta.NumSeries = uint64(h.profiles.totalSeries.Load()) + + if res.Meta.NumSamples == 0 { + return res, nil + } + + res.Unsymbolized = HasUnsymbolizedProfiles(h.symbols.Symbols()) + + symbolsBuffer := bytes.NewBuffer(nil) + if err := symdb.WritePartition(h.symbols, symbolsBuffer); err != nil { + return nil, err + } + res.Symbols = symbolsBuffer.Bytes() + + if res.Meta.ProfileTypeNames, err = h.profiles.profileTypeNames(); err != nil { + return nil, fmt.Errorf("failed to get profile type names: %w", err) + } + + if res.Index, profiles, res.datasetIndexSeries, err = h.profiles.Flush(ctx); err != nil { + return nil, fmt.Errorf("failed to flush profiles: %w", err) + } + res.Meta.NumProfiles = uint64(len(profiles)) + + if res.Profiles, err = WriteProfiles(h.metrics, profiles); err != nil { + return nil, fmt.Errorf("failed to write profiles parquet: %w", err) + } + return res, nil +} + +// TODO: move into the symbolizer package when available +func HasUnsymbolizedProfiles(symbols *symdb.Symbols) bool { + locations := symbols.Locations + mappings := symbols.Mappings + for _, loc := range locations { + if !mappings[loc.MappingId].HasFunctions { + return true + } + } + return false +} diff --git a/pkg/segmentwriter/memdb/head_test.go b/pkg/segmentwriter/memdb/head_test.go new file mode 100644 index 0000000000..b7ee212d7d --- /dev/null +++ b/pkg/segmentwriter/memdb/head_test.go @@ -0,0 +1,996 @@ +package memdb + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "strconv" + "sync" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/google/pprof/profile" + "github.com/google/uuid" + "github.com/parquet-go/parquet-go" + "github.com/prometheus/common/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/bench" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + testutil2 "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/symdb" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb/testutil" +) + +var defaultAnnotations []*typesv1.ProfileAnnotation + +func TestHeadLabelValues(t *testing.T) { + head := newTestHead() + head.Ingest(newProfileFoo(), uuid.New(), []*typesv1.LabelPair{{Name: "job", Value: "foo"}, {Name: "namespace", Value: "phlare"}}, defaultAnnotations) + head.Ingest(newProfileBar(), uuid.New(), []*typesv1.LabelPair{{Name: "job", Value: "bar"}, {Name: "namespace", Value: "phlare"}}, defaultAnnotations) + + q := flushTestHead(t, head) + + res, err := q.LabelValues(context.Background(), connect.NewRequest(&typesv1.LabelValuesRequest{Name: "cluster"})) + require.NoError(t, err) + require.Equal(t, []string{}, res.Msg.Names) + + res, err = q.LabelValues(context.Background(), connect.NewRequest(&typesv1.LabelValuesRequest{Name: "job"})) + require.NoError(t, err) + require.Equal(t, []string{"bar", "foo"}, res.Msg.Names) +} + +func TestHeadLabelNames(t *testing.T) { + head := newTestHead() + head.Ingest(newProfileFoo(), uuid.New(), []*typesv1.LabelPair{{Name: "job", Value: "foo"}, {Name: "namespace", Value: "phlare"}}, defaultAnnotations) + head.Ingest(newProfileBar(), uuid.New(), []*typesv1.LabelPair{{Name: "job", Value: "bar"}, {Name: "namespace", Value: "phlare"}}, defaultAnnotations) + + q := flushTestHead(t, head) + + res, err := q.LabelNames(context.Background(), connect.NewRequest(&typesv1.LabelNamesRequest{})) + require.NoError(t, err) + require.Equal(t, []string{"__period_type__", "__period_unit__", "__profile_type__", "__type__", "__unit__", "job", "namespace"}, res.Msg.Names) +} + +func TestHeadSeries(t *testing.T) { + head := newTestHead() + fooLabels := phlaremodel.NewLabelsBuilder(nil).Set("namespace", "phlare").Set("job", "foo").Labels() + barLabels := phlaremodel.NewLabelsBuilder(nil).Set("namespace", "phlare").Set("job", "bar").Labels() + head.Ingest(newProfileFoo(), uuid.New(), fooLabels, defaultAnnotations) + head.Ingest(newProfileBar(), uuid.New(), barLabels, defaultAnnotations) + + lblBuilder := phlaremodel.NewLabelsBuilder(nil). + Set("namespace", "phlare"). + Set("job", "foo"). + Set("__period_type__", "type"). + Set("__period_unit__", "unit"). + Set("__type__", "type"). + Set("__unit__", "unit"). + Set("__profile_type__", ":type:unit:type:unit") + expected := lblBuilder.Labels() + + q := flushTestHead(t, head) + + res, err := q.Series(context.Background(), &ingestv1.SeriesRequest{Matchers: []string{`{job="foo"}`}}) + require.NoError(t, err) + require.Equal(t, []*typesv1.Labels{{Labels: expected}}, res) + + // Test we can filter labelNames + res, err = q.Series(context.Background(), &ingestv1.SeriesRequest{LabelNames: []string{"job", "not-existing"}}) + require.NoError(t, err) + lblBuilder.Reset(nil) + jobFoo := lblBuilder.Set("job", "foo").Labels() + lblBuilder.Reset(nil) + jobBar := lblBuilder.Set("job", "bar").Labels() + require.Len(t, res, 2) + require.Contains(t, res, &typesv1.Labels{Labels: jobFoo}) + require.Contains(t, res, &typesv1.Labels{Labels: jobBar}) +} + +func TestHeadProfileTypes(t *testing.T) { + head := newTestHead() + head.Ingest(newProfileFoo(), uuid.New(), []*typesv1.LabelPair{{Name: "__name__", Value: "foo"}, {Name: "job", Value: "foo"}, {Name: "namespace", Value: "phlare"}}, defaultAnnotations) + head.Ingest(newProfileBar(), uuid.New(), []*typesv1.LabelPair{{Name: "__name__", Value: "bar"}, {Name: "namespace", Value: "phlare"}}, defaultAnnotations) + + q := flushTestHead(t, head) + + res, err := q.ProfileTypes(context.Background(), connect.NewRequest(&ingestv1.ProfileTypesRequest{})) + require.NoError(t, err) + require.Equal(t, []*typesv1.ProfileType{ + mustParseProfileSelector(t, "bar:type:unit:type:unit"), + mustParseProfileSelector(t, "foo:type:unit:type:unit"), + }, res.Msg.ProfileTypes) +} + +func TestHead_SelectMatchingProfiles_Order(t *testing.T) { + const n = 15 + head := NewHead(NewHeadMetricsWithPrefix(nil, "")) + + now := time.Now() + for i := 0; i < n; i++ { + x := newProfileFoo() + // Make sure some of our profiles have matching timestamps. + x.TimeNanos = now.Add(time.Second * time.Duration(i-i%2)).UnixNano() + head.Ingest(x, uuid.UUID{}, []*typesv1.LabelPair{ + {Name: "job", Value: "foo"}, + {Name: "x", Value: strconv.Itoa(i)}, + }, defaultAnnotations) + } + + q := flushTestHead(t, head) + + typ, err := phlaremodel.ParseProfileTypeSelector(":type:unit:type:unit") + require.NoError(t, err) + req := &ingestv1.SelectProfilesRequest{ + LabelSelector: "{}", + Type: typ, + End: now.Add(time.Hour).UnixMilli(), + } + + profiles := make([]phlaredb.Profile, 0, n) + i, err := q.SelectMatchingProfiles(context.Background(), req) + require.NoError(t, err) + s, err := iter.Slice(i) + require.NoError(t, err) + profiles = append(profiles, s...) + + assert.Equal(t, n, len(profiles)) + for i, p := range profiles { + x, err := strconv.Atoi(p.Labels().Get("x")) + require.NoError(t, err) + require.Equal(t, i, x, "SelectMatchingProfiles order mismatch") + } +} + +const testdataPrefix = "../../phlaredb" + +func TestHeadFlushQuery(t *testing.T) { + testdata := []struct { + path string + profile *profilev1.Profile + svc string + }{ + {testdataPrefix + "/testdata/heap", nil, "svc_heap"}, + {testdataPrefix + "/testdata/profile", nil, "svc_profile"}, + {testdataPrefix + "/testdata/profile_uncompressed", nil, "svc_profile_uncompressed"}, + {testdataPrefix + "/testdata/profile_python", nil, "svc_python"}, + {testdataPrefix + "/testdata/profile_java", nil, "svc_java"}, + } + for i := range testdata { + td := &testdata[i] + p := parseProfile(t, td.path) + td.profile = p + } + + head := newTestHead() + ctx := context.Background() + + for pos := range testdata { + head.Ingest(testdata[pos].profile.CloneVT(), uuid.New(), []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameServiceName, Value: testdata[pos].svc}, + }, defaultAnnotations) + } + + flushed, err := head.Flush(ctx) + require.NoError(t, err) + + assert.Equal(t, 14192, int(flushed.Meta.NumSamples)) + assert.Equal(t, 11, int(flushed.Meta.NumSeries)) // different value from original phlaredb test because service_name label added + assert.Equal(t, 11, int(flushed.Meta.NumProfiles)) + assert.Equal(t, []string{ + ":CPU:nanoseconds:CPU:nanoseconds", + ":alloc_objects:count:space:bytes", + ":alloc_space:bytes:space:bytes", + ":cpu:nanoseconds:cpu:nanoseconds", + ":inuse_objects:count:space:bytes", + ":inuse_space:bytes:space:bytes", + ":sample:count:CPU:nanoseconds", + ":samples:count:cpu:nanoseconds", + }, flushed.Meta.ProfileTypeNames) + + q := createBlockFromFlushedHead(t, flushed) + + for _, td := range testdata { + for stIndex := range td.profile.SampleType { + p, err := q.SelectMergePprof(context.Background(), &ingestv1.SelectProfilesRequest{ + LabelSelector: fmt.Sprintf("{%s=\"%s\"}", phlaremodel.LabelNameServiceName, td.svc), + Type: profileTypeFromProfile(td.profile, stIndex), + Start: time.Unix(0, td.profile.TimeNanos).UnixMilli(), + End: time.Unix(0, td.profile.TimeNanos).Add(time.Millisecond).UnixMilli(), + }, 163840, nil, + ) + require.NoError(t, err) + require.NotNil(t, p) + + compareProfile(t, td.profile, stIndex, p) + } + } +} + +func TestHead_Concurrent_Ingest(t *testing.T) { + head := newTestHead() + + wg := sync.WaitGroup{} + + profilesPerSeries := 330 + + for i := 0; i < 3; i++ { + wg.Add(1) + // ingester + go func(i int) { + defer wg.Done() + tick := time.NewTicker(time.Millisecond) + defer tick.Stop() + for j := 0; j < profilesPerSeries; j++ { + <-tick.C + ingestThreeProfileStreams(profilesPerSeries*i+j, head.Ingest) + } + t.Logf("ingest stream %s done", streams[i]) + }(i) + } + + wg.Wait() + + _ = flushTestHead(t, head) +} + +func profileWithID(id int) (*profilev1.Profile, uuid.UUID) { + p := newProfileFoo() + p.TimeNanos = int64(id) + return p, uuid.MustParse(fmt.Sprintf("00000000-0000-0000-0000-%012d", id)) +} + +func TestHead_ProfileOrder(t *testing.T) { + head := newTestHead() + + p, u := profileWithID(1) + head.Ingest(p, u, []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameProfileName, Value: "memory"}, + {Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, + {Name: phlaremodel.LabelNameServiceName, Value: "service-a"}, + }, defaultAnnotations) + + p, u = profileWithID(2) + head.Ingest(p, u, []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameProfileName, Value: "memory"}, + {Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, + {Name: phlaremodel.LabelNameServiceName, Value: "service-b"}, + {Name: "____Label", Value: "important"}, + }, defaultAnnotations) + + p, u = profileWithID(3) + head.Ingest(p, u, []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameProfileName, Value: "memory"}, + {Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, + {Name: phlaremodel.LabelNameServiceName, Value: "service-c"}, + {Name: "AAALabel", Value: "important"}, + }, defaultAnnotations) + + p, u = profileWithID(4) + head.Ingest(p, u, []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameProfileName, Value: "cpu"}, + {Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, + {Name: phlaremodel.LabelNameServiceName, Value: "service-a"}, + {Name: "000Label", Value: "important"}, + }, defaultAnnotations) + + p, u = profileWithID(5) + head.Ingest(p, u, []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameProfileName, Value: "cpu"}, + {Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, + {Name: phlaremodel.LabelNameServiceName, Value: "service-b"}, + }, defaultAnnotations) + + p, u = profileWithID(6) + head.Ingest(p, u, []*typesv1.LabelPair{ + {Name: phlaremodel.LabelNameProfileName, Value: "cpu"}, + {Name: phlaremodel.LabelNameOrder, Value: phlaremodel.LabelOrderEnforced}, + {Name: phlaremodel.LabelNameServiceName, Value: "service-b"}, + }, defaultAnnotations) + + flushed, err := head.Flush(context.Background()) + require.NoError(t, err) + + // test that the profiles are ordered correctly + type row struct{ TimeNanos uint64 } + rows, err := parquet.Read[row](bytes.NewReader(flushed.Profiles), int64(len(flushed.Profiles))) + require.NoError(t, err) + require.Equal(t, []row{ + {4}, {5}, {6}, {1}, {2}, {3}, + }, rows) +} + +func TestFlushEmptyHead(t *testing.T) { + head := newTestHead() + flushed, err := head.Flush(context.Background()) + require.NoError(t, err) + require.NotNil(t, flushed) + require.Equal(t, 0, len(flushed.Profiles)) +} + +func TestMergeProfilesStacktraces(t *testing.T) { + defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) + + // ingest some sample data + var ( + end = time.Unix(0, int64(time.Hour)) + start = end.Add(-time.Minute) + step = 15 * time.Second + ) + + db := newTestHead() + + ingestProfiles(t, db, cpuProfileGenerator, start.UnixNano(), end.UnixNano(), step, + defaultAnnotations, + &typesv1.LabelPair{Name: "namespace", Value: "my-namespace"}, + &typesv1.LabelPair{Name: "pod", Value: "my-pod"}, + ) + + q := flushTestHead(t, db) + + // create client + client, cleanup := testutil.IngesterClientForTest(t, []phlaredb.Querier{q}) + defer cleanup() + + t.Run("request the one existing series", func(t *testing.T) { + bidi := client.MergeProfilesStacktraces(context.Background()) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + + resp, err := bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + require.Len(t, resp.SelectedProfiles.Fingerprints, 1) + require.Len(t, resp.SelectedProfiles.Profiles, 5) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{ + Profiles: []bool{true}, + })) + + // expect empty response + resp, err = bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + + // received result + resp, err = bidi.Receive() + require.NoError(t, err) + require.NotNil(t, resp.Result) + + at, err := phlaremodel.UnmarshalTree[phlaremodel.FunctionName, phlaremodel.FunctionNameI](resp.Result.TreeBytes) + require.NoError(t, err) + require.Equal(t, int64(500000000), at.Total()) + }) + + t.Run("request non existing series", func(t *testing.T) { + bidi := client.MergeProfilesStacktraces(context.Background()) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="not-my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + + // expect empty resp to signal it is finished + resp, err := bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + require.Nil(t, resp.SelectedProfiles) + + // still receiving a result + resp, err = bidi.Receive() + require.NoError(t, err) + require.NotNil(t, resp.Result) + require.Len(t, resp.Result.Stacktraces, 0) + require.Len(t, resp.Result.FunctionNames, 0) + require.Nil(t, resp.SelectedProfiles) + }) + + t.Run("empty request fails", func(t *testing.T) { + bidi := client.MergeProfilesStacktraces(context.Background()) + + // It is possible that the error returned by server side of the + // stream closes the net.Conn before bidi.Send has finished. The + // short timing for that to happen with real HTTP servers makes this + // unlikely, but it does happen with the synchronous in memory + // net.Pipe() that is used here. + // See https://github.com/grafana/pyroscope/issues/3549 for more details. + if err := bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{}); !errors.Is(err, io.EOF) { + require.NoError(t, err) + } + + _, err := bidi.Receive() + require.EqualError(t, err, "invalid_argument: missing initial select request") + }) + + t.Run("test cancellation", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + bidi := client.MergeProfilesStacktraces(ctx) + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + cancel() + }) + + t.Run("test close request", func(t *testing.T) { + bidi := client.MergeProfilesStacktraces(context.Background()) + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesStacktracesRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + require.NoError(t, bidi.CloseRequest()) + }) +} + +func TestMergeProfilesLabels(t *testing.T) { + defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) + + // ingest some sample data + var ( + end = time.Unix(0, int64(time.Hour)) + start = end.Add(-time.Minute) + step = 15 * time.Second + ) + + db := newTestHead() + + ingestProfiles(t, db, cpuProfileGenerator, start.UnixNano(), end.UnixNano(), step, + []*typesv1.ProfileAnnotation{ + {Key: "foo", Value: "test annotation"}, + }, + &typesv1.LabelPair{Name: "namespace", Value: "my-namespace"}, + &typesv1.LabelPair{Name: "pod", Value: "my-pod"}, + ) + + q := flushTestHead(t, db) + + // create client + client, cleanup := testutil.IngesterClientForTest(t, []phlaredb.Querier{q}) + defer cleanup() + + t.Run("request the one existing series", func(t *testing.T) { + bidi := client.MergeProfilesLabels(context.Background()) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesLabelsRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + + resp, err := bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Series) + require.Len(t, resp.SelectedProfiles.Fingerprints, 1) + require.Len(t, resp.SelectedProfiles.Profiles, 5) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesLabelsRequest{ + Profiles: []bool{true}, + })) + + // expect empty response + resp, err = bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Series) + + // received result + resp, err = bidi.Receive() + require.NoError(t, err) + require.NotNil(t, resp.Series) + + require.NoError(t, err) + require.Equal(t, 1, len(resp.Series)) + point := resp.Series[0].Points[0] + require.Equal(t, int64(3540000), point.Timestamp) + require.Equal(t, float64(500000000), point.Value) + require.Equal(t, "test annotation", point.Annotations[0].Value) + }) +} + +func TestMergeProfilesPprof(t *testing.T) { + defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) + + // ingest some sample data + var ( + end = time.Unix(0, int64(time.Hour)) + start = end.Add(-time.Minute) + step = 15 * time.Second + ) + + db := NewHead(NewHeadMetricsWithPrefix(nil, "")) + + ingestProfiles(t, db, cpuProfileGenerator, start.UnixNano(), end.UnixNano(), step, + defaultAnnotations, + &typesv1.LabelPair{Name: "namespace", Value: "my-namespace"}, + &typesv1.LabelPair{Name: "pod", Value: "my-pod"}, + ) + + q := flushTestHead(t, db) + + // create client + client, cleanup := testutil.IngesterClientForTest(t, []phlaredb.Querier{q}) + defer cleanup() + + t.Run("request the one existing series", func(t *testing.T) { + bidi := client.MergeProfilesPprof(context.Background()) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + + resp, err := bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + require.Len(t, resp.SelectedProfiles.Fingerprints, 1) + require.Len(t, resp.SelectedProfiles.Profiles, 5) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{ + Profiles: []bool{true}, + })) + + // expect empty resp to signal it is finished + resp, err = bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + + // received result + resp, err = bidi.Receive() + require.NoError(t, err) + require.NotNil(t, resp.Result) + p, err := profile.ParseUncompressed(resp.Result) + require.NoError(t, err) + require.Len(t, p.Sample, 48) + require.Len(t, p.Location, 287) + }) + + t.Run("request non existing series", func(t *testing.T) { + bidi := client.MergeProfilesPprof(context.Background()) + + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="not-my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + + // expect empty resp to signal it is finished + resp, err := bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + require.Nil(t, resp.SelectedProfiles) + + // still receiving a result + resp, err = bidi.Receive() + require.NoError(t, err) + require.NotNil(t, resp.Result) + p, err := profile.ParseUncompressed(resp.Result) + require.NoError(t, err) + require.Len(t, p.Sample, 0) + require.Len(t, p.Location, 0) + require.Nil(t, resp.SelectedProfiles) + }) + + t.Run("empty request fails", func(t *testing.T) { + bidi := client.MergeProfilesPprof(context.Background()) + + // It is possible that the error returned by server side of the + // stream closes the net.Conn before bidi.Send has finished. The + // short timing for that to happen with real HTTP servers makes this + // unlikely, but it does happen with the synchronous in memory + // net.Pipe() that is used here. + // See https://github.com/grafana/pyroscope/issues/3549 for more details. + if err := bidi.Send(&ingestv1.MergeProfilesPprofRequest{}); !errors.Is(err, io.EOF) { + require.NoError(t, err) + } + + _, err := bidi.Receive() + require.EqualError(t, err, "invalid_argument: missing initial select request") + }) + + t.Run("test cancellation", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + bidi := client.MergeProfilesPprof(ctx) + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + cancel() + }) + + t.Run("test close request", func(t *testing.T) { + bidi := client.MergeProfilesPprof(context.Background()) + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: start.UnixMilli(), + End: end.UnixMilli(), + }, + })) + require.NoError(t, bidi.CloseRequest()) + }) + + t.Run("timerange with no Profiles", func(t *testing.T) { + bidi := client.MergeProfilesPprof(context.Background()) + require.NoError(t, bidi.Send(&ingestv1.MergeProfilesPprofRequest{ + Request: &ingestv1.SelectProfilesRequest{ + LabelSelector: `{pod="my-pod"}`, + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: 0, + End: 1, + }, + })) + _, err := bidi.Receive() + require.NoError(t, err) + _, err = bidi.Receive() + require.NoError(t, err) + }) +} + +// See https://github.com/grafana/pyroscope/pull/3356 +func Test_HeadFlush_DuplicateLabels(t *testing.T) { + defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) + + // ingest some sample data + var ( + end = time.Unix(0, int64(time.Hour)) + start = end.Add(-time.Minute) + step = 15 * time.Second + ) + + head := newTestHead() + + ingestProfiles(t, head, cpuProfileGenerator, start.UnixNano(), end.UnixNano(), step, + defaultAnnotations, + &typesv1.LabelPair{Name: "namespace", Value: "my-namespace"}, + &typesv1.LabelPair{Name: "pod", Value: "my-pod"}, + &typesv1.LabelPair{Name: "pod", Value: "not-my-pod"}, + ) +} + +// TODO: move into the symbolizer package when available +func TestUnsymbolized(t *testing.T) { + testCases := []struct { + name string + profile *profilev1.Profile + expectUnsymbolized bool + }{ + { + name: "fully symbolized profile", + profile: &profilev1.Profile{ + StringTable: []string{"", "a"}, + Function: []*profilev1.Function{ + {Id: 4, Name: 1}, + }, + Mapping: []*profilev1.Mapping{ + {Id: 239, HasFunctions: true}, + }, + Location: []*profilev1.Location{ + {Id: 5, MappingId: 239, Line: []*profilev1.Line{{FunctionId: 4, Line: 1}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{5}, Value: []int64{1}}, + }, + }, + expectUnsymbolized: false, + }, + { + name: "mapping without functions", + profile: &profilev1.Profile{ + StringTable: []string{"", "a"}, + Function: []*profilev1.Function{ + {Id: 4, Name: 1}, + }, + Mapping: []*profilev1.Mapping{ + {Id: 239, HasFunctions: false}, + }, + Location: []*profilev1.Location{ + {Id: 5, MappingId: 239, Line: []*profilev1.Line{{FunctionId: 4, Line: 1}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{5}, Value: []int64{1}}, + }, + }, + expectUnsymbolized: true, + }, + { + name: "multiple locations with mixed symbolization", + profile: &profilev1.Profile{ + StringTable: []string{"", "a", "b"}, + Function: []*profilev1.Function{ + {Id: 4, Name: 1}, + {Id: 5, Name: 2}, + }, + Mapping: []*profilev1.Mapping{ + {Id: 239, HasFunctions: true}, + {Id: 240, HasFunctions: false}, + }, + Location: []*profilev1.Location{ + {Id: 5, MappingId: 239, Line: []*profilev1.Line{{FunctionId: 4, Line: 1}}}, + {Id: 6, MappingId: 240, Line: nil}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{5, 6}, Value: []int64{1}}, + }, + }, + expectUnsymbolized: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + symbols := symdb.NewPartitionWriter(0, &symdb.Config{ + Version: symdb.FormatV3, + }) + symbols.WriteProfileSymbols(tc.profile) + unsymbolized := HasUnsymbolizedProfiles(symbols.Symbols()) + assert.Equal(t, tc.expectUnsymbolized, unsymbolized) + }) + } +} + +func BenchmarkHeadIngestProfiles(t *testing.B) { + var ( + profilePaths = []string{ + testdataPrefix + "/testdata/heap", + testdataPrefix + "/testdata/profile", + } + profileCount = 0 + ) + + head := newTestHead() + + t.ReportAllocs() + + for n := 0; n < t.N; n++ { + for pos := range profilePaths { + p := parseProfile(t, profilePaths[pos]) + head.Ingest(p, uuid.New(), []*typesv1.LabelPair{}, defaultAnnotations) + profileCount++ + } + } +} + +func newTestHead() *Head { + head := NewHead(NewHeadMetricsWithPrefix(nil, "")) + return head +} + +func parseProfile(t testing.TB, path string) *profilev1.Profile { + p, err := pprof.OpenFile(path) + require.NoError(t, err, "failed opening profile: ", path) + if p.Mapping == nil { + // Add fake mappings to some profiles, otherwise query may panic in symdb or return wrong unpredictable results + p.Mapping = []*profilev1.Mapping{ + {Id: 0}, + } + } + return p.Profile +} + +var valueTypeStrings = []string{"unit", "type"} + +func newValueType() *profilev1.ValueType { + return &profilev1.ValueType{ + Unit: 1, + Type: 2, + } +} + +func newProfileFoo() *profilev1.Profile { + baseTable := append([]string{""}, valueTypeStrings...) + baseTableLen := int64(len(baseTable)) + 0 + return &profilev1.Profile{ + Function: []*profilev1.Function{ + { + Id: 1, + Name: baseTableLen + 0, + }, + { + Id: 2, + Name: baseTableLen + 1, + }, + }, + Location: []*profilev1.Location{ + { + Id: 1, + MappingId: 1, + Address: 0x1337, + }, + { + Id: 2, + MappingId: 1, + Address: 0x1338, + }, + }, + Mapping: []*profilev1.Mapping{ + {Id: 1, Filename: baseTableLen + 2}, + }, + StringTable: append(baseTable, []string{ + "func_a", + "func_b", + "my-foo-binary", + }...), + TimeNanos: 123456, + PeriodType: newValueType(), + SampleType: []*profilev1.ValueType{newValueType()}, + Sample: []*profilev1.Sample{ + { + Value: []int64{0o123}, + LocationId: []uint64{1}, + }, + { + Value: []int64{1234}, + LocationId: []uint64{1, 2}, + }, + }, + } +} + +func newProfileBar() *profilev1.Profile { + baseTable := append([]string{""}, valueTypeStrings...) + baseTableLen := int64(len(baseTable)) + 0 + return &profilev1.Profile{ + Function: []*profilev1.Function{ + { + Id: 10, + Name: baseTableLen + 1, + }, + { + Id: 21, + Name: baseTableLen + 0, + }, + }, + Location: []*profilev1.Location{ + { + Id: 113, + MappingId: 1, + Address: 0x1337, + Line: []*profilev1.Line{ + {FunctionId: 10, Line: 1}, + }, + }, + }, + Mapping: []*profilev1.Mapping{ + {Id: 1, Filename: baseTableLen + 2}, + }, + StringTable: append(baseTable, []string{ + "func_b", + "func_a", + "my-bar-binary", + }...), + TimeNanos: 123456, + PeriodType: newValueType(), + SampleType: []*profilev1.ValueType{newValueType()}, + Sample: []*profilev1.Sample{ + { + Value: []int64{2345}, + LocationId: []uint64{113}, + }, + }, + } +} + +var streams = []string{"stream-a", "stream-b", "stream-c"} + +func ingestThreeProfileStreams(i int, ingest func(*profilev1.Profile, uuid.UUID, []*typesv1.LabelPair, []*typesv1.ProfileAnnotation)) { + p := testhelper.NewProfileBuilder(time.Second.Nanoseconds() * int64(i)) + p.CPUProfile() + p.WithLabels( + "job", "foo", + "stream", streams[i%3], + ) + p.UUID = uuid.MustParse(fmt.Sprintf("00000000-0000-0000-0000-%012d", i)) + p.ForStacktraceString("func1", "func2").AddSamples(10) + p.ForStacktraceString("func1").AddSamples(20) + p.Annotations = []*typesv1.ProfileAnnotation{ + {Key: "foo", Value: "bar"}, + } + + ingest(p.Profile, p.UUID, p.Labels, p.Annotations) +} + +func profileTypeFromProfile(p *profilev1.Profile, stIndex int) *typesv1.ProfileType { + t := &typesv1.ProfileType{ + SampleType: p.StringTable[p.SampleType[stIndex].Type], + SampleUnit: p.StringTable[p.SampleType[stIndex].Unit], + PeriodType: p.StringTable[p.PeriodType.Type], + PeriodUnit: p.StringTable[p.PeriodType.Unit], + } + t.ID = fmt.Sprintf(":%s:%s:%s:%s", t.SampleType, t.SampleUnit, t.PeriodType, t.PeriodUnit) + return t +} + +func compareProfile(t *testing.T, expected *profilev1.Profile, expectedSampleTypeIndex int, actual *profilev1.Profile) { + actualCollapsed := bench.StackCollapseProto(actual, 0, 1.0) + expectedCollapsed := bench.StackCollapseProto(expected, expectedSampleTypeIndex, 1.0) + assert.Equal(t, expectedCollapsed, actualCollapsed) +} + +func flushTestHead(t *testing.T, head *Head) phlaredb.Querier { + flushed, err := head.Flush(context.Background()) + require.NoError(t, err) + + q := createBlockFromFlushedHead(t, flushed) + return q +} + +func createBlockFromFlushedHead(t *testing.T, flushed *FlushedHead) phlaredb.Querier { + dir := t.TempDir() + block := testutil2.OpenBlockFromMemory(t, dir, model.TimeFromUnixNano(flushed.Meta.MinTimeNanos), model.TimeFromUnixNano(flushed.Meta.MinTimeNanos), flushed.Profiles, flushed.Index, flushed.Symbols) + q := block.Queriers() + err := q.Open(context.Background()) + require.NoError(t, err) + require.Len(t, q, 1) + return q[0] +} + +func mustParseProfileSelector(t testing.TB, selector string) *typesv1.ProfileType { + ps, err := phlaremodel.ParseProfileTypeSelector(selector) + require.NoError(t, err) + return ps +} + +//nolint:unparam +func ingestProfiles(b testing.TB, db *Head, generator func(tsNano int64, t testing.TB) (*profilev1.Profile, string), from, to int64, step time.Duration, annotations []*typesv1.ProfileAnnotation, externalLabels ...*typesv1.LabelPair) { + b.Helper() + for i := from; i <= to; i += int64(step) { + p, name := generator(i, b) + db.Ingest( + p, + uuid.New(), + append(externalLabels, &typesv1.LabelPair{Name: model.MetricNameLabel, Value: name}), + annotations, + ) + } +} + +var cpuProfileGenerator = func(tsNano int64, t testing.TB) (*profilev1.Profile, string) { + p := parseProfile(t, testdataPrefix+"/testdata/profile") + p.TimeNanos = tsNano + return p, "process_cpu" +} diff --git a/pkg/segmentwriter/memdb/index/buf.go b/pkg/segmentwriter/memdb/index/buf.go new file mode 100644 index 0000000000..c049433a43 --- /dev/null +++ b/pkg/segmentwriter/memdb/index/buf.go @@ -0,0 +1,112 @@ +package index + +import ( + "bytes" + "fmt" + "io" + "sync" +) + +type BufferWriter struct { + buf *bytes.Buffer + pos uint64 +} + +var pool = sync.Pool{ + New: func() interface{} { + return NewBufferWriter() + }, +} + +func GetBufferWriterFromPool() *BufferWriter { + res := pool.Get().(*BufferWriter) + res.Reset() + return res +} + +func PutBufferWriterToPool(fw *BufferWriter) { + fw.Reset() + pool.Put(fw) +} + +// NewBufferWriter returns a new BufferWriter. +// todo: pooling memory +func NewBufferWriter() *BufferWriter { + return &BufferWriter{ + buf: bytes.NewBuffer(make([]byte, 0, 0x2000)), + pos: 0, + } +} + +func (fw *BufferWriter) Pos() uint64 { + return fw.pos +} + +func (fw *BufferWriter) Write(bufs ...[]byte) error { + for _, buf := range bufs { + n, err := fw.buf.Write(buf) + if err != nil { + return err + } + fw.pos += uint64(n) + } + return nil +} + +func (fw *BufferWriter) Flush() error { + return nil +} + +func (fw *BufferWriter) WriteAt(buf []byte, pos uint64) error { + if pos > fw.pos { + return fmt.Errorf("position out of range") + } + if pos+uint64(len(buf)) > fw.pos { + return fmt.Errorf("write exceeds buffer size") + } + copy(fw.buf.Bytes()[pos:], buf) + return nil +} + +func (fw *BufferWriter) Read(buf []byte) (int, error) { + return fw.buf.Read(buf) +} + +func (fw *BufferWriter) ReadFrom(r io.Reader) (int64, error) { + n, err := fw.buf.ReadFrom(r) + if err != nil { + return n, err + } + fw.pos += uint64(n) + return n, err +} + +func (fw *BufferWriter) AddPadding(size int) error { + p := fw.pos % uint64(size) + if p == 0 { + return nil + } + p = uint64(size) - p + + if err := fw.Write(make([]byte, p)); err != nil { + return fmt.Errorf("add padding: %w", err) + } + return nil +} + +func (fw *BufferWriter) Buffer() ([]byte, io.Closer, error) { + return fw.buf.Bytes(), io.NopCloser(nil), nil +} + +func (fw *BufferWriter) Close() error { + return nil +} + +func (fw *BufferWriter) Reset() { + fw.pos = 0 + fw.buf.Reset() +} + +func (fw *BufferWriter) Remove() error { + return nil +} diff --git a/pkg/segmentwriter/memdb/index/index.go b/pkg/segmentwriter/memdb/index/index.go new file mode 100644 index 0000000000..f3978ce7e4 --- /dev/null +++ b/pkg/segmentwriter/memdb/index/index.go @@ -0,0 +1,1149 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// A tsdb index writer, that does not use files and mmap +// To be for tiny segments in v2 POC branch +// Inspired by loki https://raw.githubusercontent.com/grafana/loki/main/pkg/storage/wal/index/index.go +// But actually copied from pyroscope and modified accordingly + +package index + +import ( + "bytes" + "context" + "fmt" + "hash" + "hash/crc32" + "io" + "math" + "sort" + "unsafe" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/storage" + tsdb_enc "github.com/prometheus/prometheus/tsdb/encoding" + + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/encoding" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" +) + +const ( + // MagicIndex 4 bytes at the head of an index file. + MagicIndex = 0xBAAAD700 + // HeaderLen represents number of bytes reserved of index for header. + HeaderLen = 5 + + // FormatV2 represents the index file format version. + FormatV2 = 2 + + IndexFilename = "index" + + // store every 1024 series' fingerprints in the fingerprint offsets table + fingerprintInterval = 1 << 10 + + SegmentsIndexWriterBufSize = 2 * 0x1000 // small for segments + BlocksIndexWriterBufSize = 1 << 22 // large for blocks +) + +type indexWriterStage uint8 + +const ( + idxStageNone indexWriterStage = iota + idxStageSymbols + idxStageSeries + idxStageDone +) + +func (s indexWriterStage) String() string { + switch s { + case idxStageNone: + return "none" + case idxStageSymbols: + return "symbols" + case idxStageSeries: + return "series" + case idxStageDone: + return "done" + } + return "" +} + +// The table gets initialized with sync.Once but may still cause a race +// with any other use of the crc32 package anywhere. Thus we initialize it +// before. +var castagnoliTable *crc32.Table + +func init() { + castagnoliTable = crc32.MakeTable(crc32.Castagnoli) +} + +// newCRC32 initializes a CRC32 hash with a preconfigured polynomial, so the +// polynomial may be easily changed in one location at a later time, if necessary. +func newCRC32() hash.Hash32 { + return crc32.New(castagnoliTable) +} + +type symbolCacheEntry struct { + index uint32 + lastValue string + lastValueIndex uint32 +} + +// Writer implements the IndexWriter interface for the standard +// serialization format. +type Writer struct { + ctx context.Context + + f *BufferWriter + + // Temporary file for postings. + fP *BufferWriter + // Temporary file for posting offsets table. + fPO *BufferWriter + cntPO uint64 + + toc TOC + stage indexWriterStage + postingsStart uint64 // Due to padding, can differ from TOC entry. + + // Reusable memory. + buf1 encoding.Encbuf + buf2 encoding.Encbuf + + numSymbols int + symbols *Symbols + symbolFile io.Closer + lastSymbol string + symbolCache map[string]symbolCacheEntry + + labelIndexes []labelIndexHashEntry // Label index offsets. + labelNames map[string]uint64 // Label names, and their usage. + // Keeps track of the fingerprint/offset for every n series + fingerprintOffsets index.FingerprintOffsets + + // Hold last series to validate that clients insert new series in order. + lastSeries phlaremodel.Labels + lastSeriesHash uint64 + lastRef storage.SeriesRef + + crc32 hash.Hash + + Version int +} + +// TOC represents index Table Of Content that states where each section of index starts. +type TOC struct { + Symbols uint64 + Series uint64 + LabelIndices uint64 + LabelIndicesTable uint64 + Postings uint64 + PostingsTable uint64 + FingerprintOffsets uint64 + Metadata Metadata +} + +// Metadata is TSDB-level metadata +type Metadata struct { + From, Through int64 + Checksum uint32 +} + +func (m *Metadata) EnsureBounds(from, through int64) { + if m.From == 0 || from < m.From { + m.From = from + } + + if m.Through == 0 || through > m.Through { + m.Through = through + } +} + +// NewWriter returns a new Writer to the given filename. It serializes data in format version 2. +func NewWriter(ctx context.Context, bufferSize int) (*Writer, error) { + iw := &Writer{ + ctx: ctx, + f: GetBufferWriterFromPool(), + fP: GetBufferWriterFromPool(), + fPO: GetBufferWriterFromPool(), + stage: idxStageNone, + + // Reusable memory. + buf1: encoding.EncWrap(tsdb_enc.Encbuf{B: make([]byte, 0, bufferSize)}), + buf2: encoding.EncWrap(tsdb_enc.Encbuf{B: make([]byte, 0, bufferSize)}), + + symbolCache: make(map[string]symbolCacheEntry, 1<<8), + labelNames: make(map[string]uint64, 1<<8), + crc32: newCRC32(), + } + if err := iw.writeMeta(); err != nil { + return nil, err + } + return iw, nil +} + +func (w *Writer) write(bufs ...[]byte) error { + return w.f.Write(bufs...) +} + +func (w *Writer) writeAt(buf []byte, pos uint64) error { + return w.f.WriteAt(buf, pos) +} + +func (w *Writer) addPadding(size int) error { + return w.f.AddPadding(size) +} + +// ensureStage handles transitions between write stages and ensures that IndexWriter +// methods are called in an order valid for the implementation. +func (w *Writer) ensureStage(s indexWriterStage) error { + select { + case <-w.ctx.Done(): + return w.ctx.Err() + default: + } + + if w.stage == s { + return nil + } + if w.stage < s-1 { + // A stage has been skipped. + if err := w.ensureStage(s - 1); err != nil { + return err + } + } + if w.stage > s { + return fmt.Errorf("invalid stage %q, currently at %q", s, w.stage) + } + + // Mark start of sections in table of contents. + switch s { + case idxStageSymbols: + w.toc.Symbols = w.f.pos + if err := w.startSymbols(); err != nil { + return err + } + case idxStageSeries: + if err := w.finishSymbols(); err != nil { + return err + } + w.toc.Series = w.f.pos + + case idxStageDone: + w.toc.LabelIndices = w.f.pos + // LabelIndices generation depends on the posting offset + // table produced at this stage. + if err := w.writePostingsToTmpFiles(); err != nil { + return err + } + if err := w.writeLabelIndices(); err != nil { + return err + } + + w.toc.Postings = w.f.pos + if err := w.writePostings(); err != nil { + return err + } + + w.toc.LabelIndicesTable = w.f.pos + if err := w.writeLabelIndexesOffsetTable(); err != nil { + return err + } + + w.toc.PostingsTable = w.f.pos + if err := w.writePostingsOffsetTable(); err != nil { + return err + } + + w.toc.FingerprintOffsets = w.f.pos + if err := w.writeFingerprintOffsetsTable(); err != nil { + return err + } + + if err := w.writeTOC(); err != nil { + return err + } + } + + w.stage = s + return nil +} + +func (w *Writer) writeMeta() error { + w.buf1.Reset() + w.buf1.PutBE32(MagicIndex) + w.buf1.PutByte(FormatV2) + + return w.write(w.buf1.Get()) +} + +// AddSeries adds the series one at a time along with its chunks. +// Requires a specific fingerprint to be passed in the case where the "desired" +// fingerprint differs from what labels.Hash() produces. For example, +// multitenant TSDBs embed a tenant label, but the actual series has no such +// label and so the derived fingerprint differs. +func (w *Writer) AddSeries(ref storage.SeriesRef, lset phlaremodel.Labels, fp model.Fingerprint, chunks ...index.ChunkMeta) error { + if err := w.ensureStage(idxStageSeries); err != nil { + return err + } + + // Put the supplied fingerprint instead of the calculated hash. + // This allows us to have a synthetic label (__loki_tenant__) in + // the pre-compacted TSDBs which map to fingerprints (and chunks) + // without this label in storage. + labelHash := uint64(fp) + + if ref < w.lastRef && len(w.lastSeries) != 0 { + return fmt.Errorf("series with reference greater than %d already added", ref) + } + // We add padding to 16 bytes to increase the addressable space we get through 4 byte + // series references. + if err := w.addPadding(16); err != nil { + return fmt.Errorf("failed to write padding bytes: %v", err) + } + + if w.f.pos%16 != 0 { + return fmt.Errorf("series write not 16-byte aligned at %d", w.f.pos) + } + + w.buf2.Reset() + w.buf2.PutBE64(labelHash) + w.buf2.PutUvarint(len(lset)) + + for _, l := range lset { + var err error + cacheEntry, ok := w.symbolCache[l.Name] + nameIndex := cacheEntry.index + if !ok { + nameIndex, err = w.symbols.ReverseLookup(l.Name) + if err != nil { + return fmt.Errorf("symbol entry for %q does not exist, %v", l.Name, err) + } + } + w.labelNames[l.Name]++ + w.buf2.PutUvarint32(nameIndex) + + valueIndex := cacheEntry.lastValueIndex + if !ok || cacheEntry.lastValue != l.Value { + valueIndex, err = w.symbols.ReverseLookup(l.Value) + if err != nil { + return fmt.Errorf("symbol entry for %q does not exist, %v", l.Value, err) + } + w.symbolCache[l.Name] = symbolCacheEntry{ + index: nameIndex, + lastValue: l.Value, + lastValueIndex: valueIndex, + } + } + w.buf2.PutUvarint32(valueIndex) + } + + w.buf2.PutUvarint(len(chunks)) + + if len(chunks) > 0 { + c := chunks[0] + w.toc.Metadata.EnsureBounds(c.MinTime, c.MaxTime) + + w.buf2.PutVarint64(c.MinTime) + w.buf2.PutUvarint64(uint64(c.MaxTime - c.MinTime)) + w.buf2.PutUvarint32(c.KB) + w.buf2.PutUvarint32(c.SeriesIndex) + w.buf2.PutBE32(c.Checksum) + t0 := c.MaxTime + + for _, c := range chunks[1:] { + w.toc.Metadata.EnsureBounds(c.MinTime, c.MaxTime) + // Encode the diff against previous chunk as varint + // instead of uvarint because chunks may overlap + w.buf2.PutVarint64(c.MinTime - t0) + w.buf2.PutUvarint64(uint64(c.MaxTime - c.MinTime)) + w.buf2.PutUvarint32(c.KB) + w.buf2.PutUvarint32(c.SeriesIndex) + t0 = c.MaxTime + + w.buf2.PutBE32(c.Checksum) + } + } + + w.buf1.Reset() + w.buf1.PutUvarint(w.buf2.Len()) + + w.buf2.PutHash(w.crc32) + + w.lastSeries = append(w.lastSeries[:0], lset...) + w.lastSeriesHash = labelHash + w.lastRef = ref + + if ref%fingerprintInterval == 0 { + sRef := w.f.pos / 16 + w.fingerprintOffsets = append(w.fingerprintOffsets, [2]uint64{sRef, labelHash}) + } + + if err := w.write(w.buf1.Get(), w.buf2.Get()); err != nil { + return fmt.Errorf("write series data: %w", err) + } + + return nil +} + +func (w *Writer) startSymbols() error { + // We are at w.toc.Symbols. + // Leave 4 bytes of space for the length, and another 4 for the number of symbols + // which will both be calculated later. + return w.write([]byte("alenblen")) +} + +func (w *Writer) AddSymbol(sym string) error { + if err := w.ensureStage(idxStageSymbols); err != nil { + return err + } + if w.numSymbols != 0 && sym <= w.lastSymbol { + return fmt.Errorf("symbol %q out-of-order", sym) + } + w.lastSymbol = sym + w.numSymbols++ + w.buf1.Reset() + w.buf1.PutUvarintStr(sym) + return w.write(w.buf1.Get()) +} + +func (w *Writer) finishSymbols() error { + symbolTableSize := w.f.pos - w.toc.Symbols - 4 + // The symbol table's part is 4 bytes. So the total symbol table size must be less than or equal to 2^32-1 + if symbolTableSize > math.MaxUint32 { + return fmt.Errorf("symbol table size exceeds 4 bytes: %d", symbolTableSize) + } + + // Write out the length and symbol count. + w.buf1.Reset() + w.buf1.PutBE32int(int(symbolTableSize)) + w.buf1.PutBE32int(w.numSymbols) + if err := w.writeAt(w.buf1.Get(), w.toc.Symbols); err != nil { + return err + } + + hashPos := w.f.pos + // Leave space for the hash. We can only calculate it + // now that the number of symbols is known, so mmap and do it from there. + if err := w.write([]byte("hash")); err != nil { + return err + } + if err := w.f.Flush(); err != nil { + return err + } + + //sf, err := fileutil.OpenMmapFile(w.f.name) + buf, sf, err := w.f.Buffer() + if err != nil { + return err + } + w.symbolFile = sf + hash := crc32.Checksum(buf[w.toc.Symbols+4:hashPos], castagnoliTable) + w.buf1.Reset() + w.buf1.PutBE32(hash) + if err := w.writeAt(w.buf1.Get(), hashPos); err != nil { + return err + } + + // Load in the symbol table efficiently for the rest of the index writing. + w.symbols, err = NewSymbols(RealByteSlice(buf), int(w.toc.Symbols)) + if err != nil { + return fmt.Errorf("read symbols: %w", err) + } + return nil +} + +func (w *Writer) writeLabelIndices() error { + if err := w.fPO.Flush(); err != nil { + return err + } + + // Find all the label values in the tmp posting offset table. + //f, err := fileutil.OpenMmapFile(w.fPO.name) + buf, closer, err := w.fPO.Buffer() + if err != nil { + return err + } + defer closer.Close() + + d := encoding.DecWrap(tsdb_enc.NewDecbufRaw(RealByteSlice(buf), int(w.fPO.pos))) + cnt := w.cntPO + current := []byte{} + values := []uint32{} + for d.Err() == nil && cnt > 0 { + cnt-- + d.Uvarint() // Keycount. + name := d.UvarintBytes() // Label name. + value := yoloString(d.UvarintBytes()) // Label value. + d.Uvarint64() // Offset. + if len(name) == 0 { + continue // All index is ignored. + } + + if !bytes.Equal(name, current) && len(values) > 0 { + // We've reached a new label name. + if err := w.writeLabelIndex(string(current), values); err != nil { + return err + } + values = values[:0] + } + current = name + sid, err := w.symbols.ReverseLookup(value) + if err != nil { + return err + } + values = append(values, sid) + } + if d.Err() != nil { + return d.Err() + } + + // Handle the last label. + if len(values) > 0 { + if err := w.writeLabelIndex(string(current), values); err != nil { + return err + } + } + return nil +} + +func (w *Writer) writeLabelIndex(name string, values []uint32) error { + // Align beginning to 4 bytes for more efficient index list scans. + if err := w.addPadding(4); err != nil { + return err + } + + w.labelIndexes = append(w.labelIndexes, labelIndexHashEntry{ + keys: []string{name}, + offset: w.f.pos, + }) + + startPos := w.f.pos + // Leave 4 bytes of space for the length, which will be calculated later. + if err := w.write([]byte("alen")); err != nil { + return err + } + w.crc32.Reset() + + w.buf1.Reset() + w.buf1.PutBE32int(1) // Number of names. + w.buf1.PutBE32int(len(values)) + w.buf1.WriteToHash(w.crc32) + if err := w.write(w.buf1.Get()); err != nil { + return err + } + + for _, v := range values { + w.buf1.Reset() + w.buf1.PutBE32(v) + w.buf1.WriteToHash(w.crc32) + if err := w.write(w.buf1.Get()); err != nil { + return err + } + } + + // Write out the length. + w.buf1.Reset() + l := w.f.pos - startPos - 4 + if l > math.MaxUint32 { + return fmt.Errorf("label index size exceeds 4 bytes: %d", l) + } + w.buf1.PutBE32int(int(l)) + if err := w.writeAt(w.buf1.Get(), startPos); err != nil { + return err + } + + w.buf1.Reset() + w.buf1.PutHashSum(w.crc32) + return w.write(w.buf1.Get()) +} + +// writeLabelIndexesOffsetTable writes the label indices offset table. +func (w *Writer) writeLabelIndexesOffsetTable() error { + startPos := w.f.pos + // Leave 4 bytes of space for the length, which will be calculated later. + if err := w.write([]byte("alen")); err != nil { + return err + } + w.crc32.Reset() + + w.buf1.Reset() + w.buf1.PutBE32int(len(w.labelIndexes)) + w.buf1.WriteToHash(w.crc32) + if err := w.write(w.buf1.Get()); err != nil { + return err + } + + for _, e := range w.labelIndexes { + w.buf1.Reset() + w.buf1.PutUvarint(len(e.keys)) + for _, k := range e.keys { + w.buf1.PutUvarintStr(k) + } + w.buf1.PutUvarint64(e.offset) + w.buf1.WriteToHash(w.crc32) + if err := w.write(w.buf1.Get()); err != nil { + return err + } + } + // Write out the length. + w.buf1.Reset() + l := w.f.pos - startPos - 4 + if l > math.MaxUint32 { + return fmt.Errorf("label indexes offset table size exceeds 4 bytes: %d", l) + } + w.buf1.PutBE32int(int(l)) + if err := w.writeAt(w.buf1.Get(), startPos); err != nil { + return err + } + + w.buf1.Reset() + w.buf1.PutHashSum(w.crc32) + return w.write(w.buf1.Get()) +} + +// writePostingsOffsetTable writes the postings offset table. +func (w *Writer) writePostingsOffsetTable() error { + // Ensure everything is in the temporary file. + if err := w.fPO.Flush(); err != nil { + return err + } + + startPos := w.f.pos + // Leave 4 bytes of space for the length, which will be calculated later. + if err := w.write([]byte("alen")); err != nil { + return err + } + + // Copy over the tmp posting offset table, however we need to + // adjust the offsets. + adjustment := w.postingsStart + + w.buf1.Reset() + w.crc32.Reset() + w.buf1.PutBE32int(int(w.cntPO)) // Count. + w.buf1.WriteToHash(w.crc32) + if err := w.write(w.buf1.Get()); err != nil { + return err + } + + //f, err := fileutil.OpenMmapFile(w.fPO.name) + buf, closer, err := w.fPO.Buffer() + if err != nil { + return err + } + defer func() { + if closer != nil { + closer.Close() + } + }() + d := encoding.DecWrap(tsdb_enc.NewDecbufRaw(RealByteSlice(buf), int(w.fPO.pos))) + cnt := w.cntPO + for d.Err() == nil && cnt > 0 { + w.buf1.Reset() + w.buf1.PutUvarint(d.Uvarint()) // Keycount. + w.buf1.PutUvarintBytes(d.UvarintBytes()) // Label name. + w.buf1.PutUvarintBytes(d.UvarintBytes()) // Label value. + w.buf1.PutUvarint64(d.Uvarint64() + adjustment) // Offset. + w.buf1.WriteToHash(w.crc32) + if err := w.write(w.buf1.Get()); err != nil { + return err + } + cnt-- + } + if d.Err() != nil { + return d.Err() + } + + // Cleanup temporary file. + //if err := f.Close(); err != nil { + // return err + //} + //f = nil + if err := w.fPO.Close(); err != nil { + return err + } + if err := w.fPO.Remove(); err != nil { + return err + } + //w.fPO = nil + + // Write out the length. + w.buf1.Reset() + l := w.f.pos - startPos - 4 + if l > math.MaxUint32 { + return fmt.Errorf("postings offset table size exceeds 4 bytes: %d", l) + } + w.buf1.PutBE32int(int(l)) + if err := w.writeAt(w.buf1.Get(), startPos); err != nil { + return err + } + + // Finally write the hash. + w.buf1.Reset() + w.buf1.PutHashSum(w.crc32) + return w.write(w.buf1.Get()) +} + +func (w *Writer) writeFingerprintOffsetsTable() error { + w.buf1.Reset() + w.buf2.Reset() + + w.buf1.PutBE32int(len(w.fingerprintOffsets)) // Count. + // build offsets + for _, x := range w.fingerprintOffsets { + w.buf1.PutBE64(x[0]) // series offset + w.buf1.PutBE64(x[1]) // hash + } + + // write length + ln := w.buf1.Len() + // TODO(owen-d): can remove the uint32 cast in the future + // Had to uint32 wrap these for arm32 builds, which we'll remove in the future. + if uint32(ln) > uint32(math.MaxUint32) { + return fmt.Errorf("fingerprint offset size exceeds 4 bytes: %d", ln) + } + + w.buf2.PutBE32int(ln) + if err := w.write(w.buf2.Get()); err != nil { + return err + } + + // write offsets+checksum + w.buf1.PutHash(w.crc32) + if err := w.write(w.buf1.Get()); err != nil { + return fmt.Errorf("failure writing fingerprint offsets: %w", err) + } + return nil +} + +func (w *Writer) writeTOC() error { + w.buf1.Reset() + + w.buf1.PutBE64(w.toc.Symbols) + w.buf1.PutBE64(w.toc.Series) + w.buf1.PutBE64(w.toc.LabelIndices) + w.buf1.PutBE64(w.toc.LabelIndicesTable) + w.buf1.PutBE64(w.toc.Postings) + w.buf1.PutBE64(w.toc.PostingsTable) + w.buf1.PutBE64(w.toc.FingerprintOffsets) + + // metadata + w.buf1.PutBE64int64(w.toc.Metadata.From) + w.buf1.PutBE64int64(w.toc.Metadata.Through) + + w.buf1.PutHash(w.crc32) + + return w.write(w.buf1.Get()) +} + +func (w *Writer) writePostingsToTmpFiles() error { + names := make([]string, 0, len(w.labelNames)) + for n := range w.labelNames { + names = append(names, n) + } + sort.Strings(names) + + if err := w.f.Flush(); err != nil { + return err + } + //f, err := fileutil.OpenMmapFile(w.f.name) + buf, closer, err := w.f.Buffer() + if err != nil { + return err + } + defer closer.Close() + + // Write out the special all posting. + offsets := []uint32{} + d := encoding.DecWrap(tsdb_enc.NewDecbufRaw(RealByteSlice(buf), int(w.toc.LabelIndices))) + d.Skip(int(w.toc.Series)) + for d.Len() > 0 { + d.ConsumePadding() + startPos := w.toc.LabelIndices - uint64(d.Len()) + if startPos%16 != 0 { + return fmt.Errorf("series not 16-byte aligned at %d", startPos) + } + offsets = append(offsets, uint32(startPos/16)) + // Skip to next series. + x := d.Uvarint() + d.Skip(x + crc32.Size) + if err := d.Err(); err != nil { + return err + } + } + if err := w.writePosting("", "", offsets); err != nil { + return err + } + maxPostings := uint64(len(offsets)) // No label name can have more postings than this. + + for len(names) > 0 { + batchNames := []string{} + var c uint64 + // Try to bunch up label names into one loop, but avoid + // using more memory than a single label name can. + for len(names) > 0 { + if w.labelNames[names[0]]+c > maxPostings { + if c > 0 { + break + } + return fmt.Errorf("corruption detected when writing postings to index: label %q has %d uses, but maxPostings is %d", names[0], w.labelNames[names[0]], maxPostings) + } + batchNames = append(batchNames, names[0]) + c += w.labelNames[names[0]] + names = names[1:] + } + + nameSymbols := map[uint32]string{} + for _, name := range batchNames { + sid, err := w.symbols.ReverseLookup(name) + if err != nil { + return err + } + nameSymbols[sid] = name + } + // Label name -> label value -> positions. + postings := map[uint32]map[uint32][]uint32{} + + d := encoding.DecWrap(tsdb_enc.NewDecbufRaw(RealByteSlice(buf), int(w.toc.LabelIndices))) + d.Skip(int(w.toc.Series)) + for d.Len() > 0 { + d.ConsumePadding() + startPos := w.toc.LabelIndices - uint64(d.Len()) + l := d.Uvarint() // Length of this series in bytes. + startLen := d.Len() + + _ = d.Be64() // skip fingerprint + // See if label names we want are in the series. + numLabels := d.Uvarint() + for i := 0; i < numLabels; i++ { + lno := uint32(d.Uvarint()) + lvo := uint32(d.Uvarint()) + + if _, ok := nameSymbols[lno]; ok { + if _, ok := postings[lno]; !ok { + postings[lno] = map[uint32][]uint32{} + } + postings[lno][lvo] = append(postings[lno][lvo], uint32(startPos/16)) + } + } + // Skip to next series. + d.Skip(l - (startLen - d.Len()) + crc32.Size) + if err := d.Err(); err != nil { + return err + } + } + + for _, name := range batchNames { + // Write out postings for this label name. + sid, err := w.symbols.ReverseLookup(name) + if err != nil { + return err + } + values := make([]uint32, 0, len(postings[sid])) + for v := range postings[sid] { + values = append(values, v) + } + // Symbol numbers are in order, so the strings will also be in order. + sort.Sort(uint32slice(values)) + for _, v := range values { + value, err := w.symbols.Lookup(v) + if err != nil { + return err + } + if err := w.writePosting(name, value, postings[sid][v]); err != nil { + return err + } + } + } + select { + case <-w.ctx.Done(): + return w.ctx.Err() + default: + } + } + return nil +} + +func (w *Writer) writePosting(name, value string, offs []uint32) error { + // Align beginning to 4 bytes for more efficient postings list scans. + if err := w.fP.AddPadding(4); err != nil { + return err + } + + // Write out postings offset table to temporary file as we go. + w.buf1.Reset() + w.buf1.PutUvarint(2) + w.buf1.PutUvarintStr(name) + w.buf1.PutUvarintStr(value) + w.buf1.PutUvarint64(w.fP.pos) // This is relative to the postings tmp file, not the final index file. + if err := w.fPO.Write(w.buf1.Get()); err != nil { + return err + } + w.cntPO++ + + w.buf1.Reset() + w.buf1.PutBE32int(len(offs)) + + for _, off := range offs { + if off > (1<<32)-1 { + return fmt.Errorf("series offset %d exceeds 4 bytes", off) + } + w.buf1.PutBE32(off) + } + + w.buf2.Reset() + l := w.buf1.Len() + // We convert to uint to make code compile on 32-bit systems, as math.MaxUint32 doesn't fit into int there. + if uint(l) > math.MaxUint32 { + return fmt.Errorf("posting size exceeds 4 bytes: %d", l) + } + w.buf2.PutBE32int(l) + w.buf1.PutHash(w.crc32) + return w.fP.Write(w.buf2.Get(), w.buf1.Get()) +} + +func (w *Writer) writePostings() error { + // There's padding in the tmp file, make sure it actually works. + if err := w.f.AddPadding(4); err != nil { + return err + } + w.postingsStart = w.f.pos + + // Copy temporary file into main index. + if err := w.fP.Flush(); err != nil { + return err + } + //if _, err := w.fP.f.Seek(0, 0); err != nil { + // return err + //} + // Don't need to calculate a checksum, so can copy directly. + //n, err := io.CopyBuffer(w.f.fbuf, w.fP.f, make([]byte, 1<<20)) + //buf := make([]byte, cap(w.buf1.B)) + //buf := w.buf1.B[:cap(w.buf1.B)] + //n, err := io.CopyBuffer(w.f.fbuf, w.fP.f, buf) + //if err != nil { + // return err + //} + n, err := w.f.ReadFrom(w.fP) + if err != nil { + return err + } + if uint64(n) != w.fP.pos { + return fmt.Errorf("wrote %d bytes to posting temporary file, but only read back %d", w.fP.pos, n) + } + //w.f.pos += uint64(n) + + if err := w.fP.Close(); err != nil { + return err + } + if err := w.fP.Remove(); err != nil { + return err + } + //w.fP = nil + return nil +} + +type uint32slice []uint32 + +func (s uint32slice) Len() int { return len(s) } +func (s uint32slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s uint32slice) Less(i, j int) bool { return s[i] < s[j] } + +type labelIndexHashEntry struct { + keys []string + offset uint64 +} + +func (w *Writer) Close() error { + // Even if this fails, we need to close all the files. + ensureErr := w.ensureStage(idxStageDone) + + if w.symbolFile != nil { + if err := w.symbolFile.Close(); err != nil { + return err + } + } + if w.fP != nil { + if err := w.fP.Close(); err != nil { + return err + } + } + if w.fPO != nil { + if err := w.fPO.Close(); err != nil { + return err + } + } + if err := w.f.Close(); err != nil { + return err + } + // w.f is kept around a bit longer and returned to pool by users + PutBufferWriterToPool(w.fP) + PutBufferWriterToPool(w.fPO) + w.fP = nil + w.fPO = nil + + return ensureErr +} + +// StringIter iterates over a sorted list of strings. +type StringIter interface { + // Next advances the iterator and returns true if another value was found. + Next() bool + + // At returns the value at the current iterator position. + At() string + + // Err returns the last error of the iterator. + Err() error +} + +// ByteSlice abstracts a byte slice. +type ByteSlice interface { + Len() int + Range(start, end int) []byte +} + +type RealByteSlice []byte + +func (b RealByteSlice) Len() int { + return len(b) +} + +func (b RealByteSlice) Range(start, end int) []byte { + return b[start:end] +} + +func (b RealByteSlice) Sub(start, end int) ByteSlice { + return b[start:end] +} + +type Symbols struct { + bs ByteSlice + off int + + offsets []int + seen int +} + +const symbolFactor = 32 + +// NewSymbols returns a Symbols object for symbol lookups. +func NewSymbols(bs ByteSlice, off int) (*Symbols, error) { + s := &Symbols{ + bs: bs, + off: off, + } + d := encoding.DecWrap(tsdb_enc.NewDecbufAt(bs, off, castagnoliTable)) + var ( + origLen = d.Len() + cnt = d.Be32int() + basePos = off + 4 + ) + s.offsets = make([]int, 0, 1+cnt/symbolFactor) + for d.Err() == nil && s.seen < cnt { + if s.seen%symbolFactor == 0 { + s.offsets = append(s.offsets, basePos+origLen-d.Len()) + } + d.UvarintBytes() // The symbol. + s.seen++ + } + if d.Err() != nil { + return nil, d.Err() + } + return s, nil +} + +func (s Symbols) Lookup(o uint32) (string, error) { + d := encoding.DecWrap(tsdb_enc.Decbuf{ + B: s.bs.Range(0, s.bs.Len()), + }) + + if int(o) >= s.seen { + return "", fmt.Errorf("unknown symbol offset %d", o) + } + d.Skip(s.offsets[int(o/symbolFactor)]) + // Walk until we find the one we want. + for i := o - (o / symbolFactor * symbolFactor); i > 0; i-- { + d.UvarintBytes() + } + sym := d.UvarintStr() + if d.Err() != nil { + return "", d.Err() + } + return sym, nil +} + +func (s Symbols) ReverseLookup(sym string) (uint32, error) { + if len(s.offsets) == 0 { + return 0, fmt.Errorf("unknown symbol %q - no symbols", sym) + } + i := sort.Search(len(s.offsets), func(i int) bool { + // Any decoding errors here will be lost, however + // we already read through all of this at startup. + d := encoding.DecWrap(tsdb_enc.Decbuf{ + B: s.bs.Range(0, s.bs.Len()), + }) + d.Skip(s.offsets[i]) + return yoloString(d.UvarintBytes()) > sym + }) + d := encoding.DecWrap(tsdb_enc.Decbuf{ + B: s.bs.Range(0, s.bs.Len()), + }) + if i > 0 { + i-- + } + d.Skip(s.offsets[i]) + res := i * symbolFactor + var lastSymbol string + for d.Err() == nil && res <= s.seen { + lastSymbol = yoloString(d.UvarintBytes()) + if lastSymbol >= sym { + break + } + res++ + } + if d.Err() != nil { + return 0, d.Err() + } + if lastSymbol != sym { + return 0, fmt.Errorf("unknown symbol %q", sym) + } + return uint32(res), nil +} + +func (s Symbols) Size() int { + return len(s.offsets) * 8 +} + +func yoloString(b []byte) string { + return *((*string)(unsafe.Pointer(&b))) +} + +// todo better name, nicer api +func (w *Writer) ReleaseIndexBuffer() *BufferWriter { + res := w.f + w.f = nil + return res +} + +// todo better name, nicer api +func (w *Writer) ReleaseIndex() []byte { + bw := w.ReleaseIndexBuffer() + defer PutBufferWriterToPool(bw) + buffer, _, _ := bw.Buffer() + res := make([]byte, len(buffer)) + copy(res, buffer) + return res +} diff --git a/pkg/segmentwriter/memdb/index/index_test.go b/pkg/segmentwriter/memdb/index/index_test.go new file mode 100644 index 0000000000..665627d0ad --- /dev/null +++ b/pkg/segmentwriter/memdb/index/index_test.go @@ -0,0 +1,527 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package index + +import ( + "context" + "errors" + "fmt" + "hash/crc32" + "math/rand" + "sort" + "testing" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/storage" + "github.com/prometheus/prometheus/tsdb/encoding" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/iter" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m, + goleak.IgnoreTopFunction("github.com/golang/glog.(*fileSink).flushDaemon"), + goleak.IgnoreTopFunction("github.com/dgraph-io/ristretto.(*defaultPolicy).processItems"), + goleak.IgnoreTopFunction("github.com/dgraph-io/ristretto.(*Cache).processItems"), + ) +} + +type series struct { + l phlaremodel.Labels + chunks []index.ChunkMeta +} + +type mockIndex struct { + series map[storage.SeriesRef]series + // we're forced to use a anonymous struct here because we can't use typesv1.LabelPair as it's not comparable. + postings map[struct{ Name, Value string }][]storage.SeriesRef + symbols map[string]struct{} +} + +func newMockIndex() mockIndex { + allPostingsKeyName, allPostingsKeyValue := index.AllPostingsKey() + ix := mockIndex{ + series: make(map[storage.SeriesRef]series), + postings: make(map[struct{ Name, Value string }][]storage.SeriesRef), + symbols: make(map[string]struct{}), + } + ix.postings[struct { + Name string + Value string + }{allPostingsKeyName, allPostingsKeyValue}] = []storage.SeriesRef{} + return ix +} + +func (m mockIndex) Symbols() (map[string]struct{}, error) { + return m.symbols, nil +} + +func (m mockIndex) AddSeries(ref storage.SeriesRef, l phlaremodel.Labels, chunks ...index.ChunkMeta) error { + allPostingsKeyName, allPostingsKeyValue := index.AllPostingsKey() + + if _, ok := m.series[ref]; ok { + return fmt.Errorf("series with reference %d already added", ref) + } + for _, lbl := range l { + m.symbols[lbl.Name] = struct{}{} + m.symbols[lbl.Value] = struct{}{} + if _, ok := m.postings[struct { + Name string + Value string + }{lbl.Name, lbl.Value}]; !ok { + m.postings[struct { + Name string + Value string + }{lbl.Name, lbl.Value}] = []storage.SeriesRef{} + } + m.postings[struct { + Name string + Value string + }{lbl.Name, lbl.Value}] = append(m.postings[struct { + Name string + Value string + }{lbl.Name, lbl.Value}], ref) + } + m.postings[struct { + Name string + Value string + }{allPostingsKeyName, allPostingsKeyValue}] = append(m.postings[struct { + Name string + Value string + }{allPostingsKeyName, allPostingsKeyValue}], ref) + + s := series{l: l} + // Actual chunk data is not stored in the index. + s.chunks = append(s.chunks, chunks...) + m.series[ref] = s + + return nil +} + +func (m mockIndex) Close() error { + return nil +} + +func (m mockIndex) LabelValues(name string) ([]string, error) { + values := []string{} + for l := range m.postings { + if l.Name == name { + values = append(values, l.Value) + } + } + return values, nil +} + +func (m mockIndex) Postings(name string, values ...string) (index.Postings, error) { + p := []index.Postings{} + for _, value := range values { + p = append(p, iter.NewSliceSeekIterator(m.postings[struct { + Name string + Value string + }{Name: name, Value: value}])) + } + return index.Merge(p...), nil +} + +func (m mockIndex) Series(ref storage.SeriesRef, lset *phlaremodel.Labels, chks *[]index.ChunkMeta) error { + s, ok := m.series[ref] + if !ok { + return errors.New("not found") + } + *lset = append((*lset)[:0], s.l...) + *chks = append((*chks)[:0], s.chunks...) + + return nil +} + +func TestIndexRW_Create_Open(t *testing.T) { + + // An empty index must still result in a readable file. + iw, err := NewWriter(context.Background(), BlocksIndexWriterBufSize) + require.NoError(t, err) + require.NoError(t, iw.Close()) + + bytes := iw.ReleaseIndexBuffer().buf.Bytes() + ir, err := index.NewReader(index.RealByteSlice(bytes)) + require.NoError(t, err) + require.NoError(t, ir.Close()) + + // Modify magic header must cause open to fail. + //f, err := os.OpenFile(fn, os.O_WRONLY, 0o666) + //require.NoError(t, err) + //err = iw.f.WriteAt([]byte{0, 0}, 0) + bytes[0] = 0 + require.NoError(t, err) + //f.Close() + + //_, err = NewFileReader(dir) + //require.Error(t, err) +} + +func TestIndexRW_Postings(t *testing.T) { + + iw, err := NewWriter(context.Background(), BlocksIndexWriterBufSize) + require.NoError(t, err) + + series := []phlaremodel.Labels{ + phlaremodel.LabelsFromStrings("a", "1", "b", "1"), + phlaremodel.LabelsFromStrings("a", "1", "b", "2"), + phlaremodel.LabelsFromStrings("a", "1", "b", "3"), + phlaremodel.LabelsFromStrings("a", "1", "b", "4"), + } + + require.NoError(t, iw.AddSymbol("1")) + require.NoError(t, iw.AddSymbol("2")) + require.NoError(t, iw.AddSymbol("3")) + require.NoError(t, iw.AddSymbol("4")) + require.NoError(t, iw.AddSymbol("a")) + require.NoError(t, iw.AddSymbol("b")) + + // Postings lists are only written if a series with the respective + // reference was added before. + require.NoError(t, iw.AddSeries(1, series[0], model.Fingerprint(series[0].Hash()))) + require.NoError(t, iw.AddSeries(2, series[1], model.Fingerprint(series[1].Hash()))) + require.NoError(t, iw.AddSeries(3, series[2], model.Fingerprint(series[2].Hash()))) + require.NoError(t, iw.AddSeries(4, series[3], model.Fingerprint(series[3].Hash()))) + + require.NoError(t, iw.Close()) + + ir, err := index.NewReader(index.RealByteSlice(iw.ReleaseIndexBuffer().buf.Bytes())) + require.NoError(t, err) + + p, err := ir.Postings("a", nil, "1") + require.NoError(t, err) + + var l phlaremodel.Labels + var c []index.ChunkMeta + + for i := 0; p.Next(); i++ { + _, err := ir.Series(p.At(), &l, &c) + + require.NoError(t, err) + require.Equal(t, 0, len(c)) + require.Equal(t, series[i], l) + } + require.NoError(t, p.Err()) + + require.NoError(t, ir.Close()) +} + +func TestPostingsMany(t *testing.T) { + + iw, err := NewWriter(context.Background(), BlocksIndexWriterBufSize) + require.NoError(t, err) + + // Create a label in the index which has 999 values. + symbols := map[string]struct{}{} + series := []phlaremodel.Labels{} + for i := 1; i < 1000; i++ { + v := fmt.Sprintf("%03d", i) + series = append(series, phlaremodel.LabelsFromStrings("i", v, "foo", "bar")) + symbols[v] = struct{}{} + } + symbols["i"] = struct{}{} + symbols["foo"] = struct{}{} + symbols["bar"] = struct{}{} + syms := []string{} + for s := range symbols { + syms = append(syms, s) + } + sort.Strings(syms) + for _, s := range syms { + require.NoError(t, iw.AddSymbol(s)) + } + + sort.Slice(series, func(i, j int) bool { + return series[i].Hash() < series[j].Hash() + }) + + for i, s := range series { + require.NoError(t, iw.AddSeries(storage.SeriesRef(i), s, model.Fingerprint(s.Hash()))) + } + require.NoError(t, iw.Close()) + + ir, err := index.NewReader(index.RealByteSlice(iw.ReleaseIndexBuffer().buf.Bytes())) + require.NoError(t, err) + defer func() { require.NoError(t, ir.Close()) }() + + cases := []struct { + in []string + }{ + // Simple cases, everything is present. + {in: []string{"002"}}, + {in: []string{"031", "032", "033"}}, + {in: []string{"032", "033"}}, + {in: []string{"127", "128"}}, + {in: []string{"127", "128", "129"}}, + {in: []string{"127", "129"}}, + {in: []string{"128", "129"}}, + {in: []string{"998", "999"}}, + {in: []string{"999"}}, + // Before actual values. + {in: []string{"000"}}, + {in: []string{"000", "001"}}, + {in: []string{"000", "002"}}, + // After actual values. + {in: []string{"999a"}}, + {in: []string{"999", "999a"}}, + {in: []string{"998", "999", "999a"}}, + // In the middle of actual values. + {in: []string{"126a", "127", "128"}}, + {in: []string{"127", "127a", "128"}}, + {in: []string{"127", "127a", "128", "128a", "129"}}, + {in: []string{"127", "128a", "129"}}, + {in: []string{"128", "128a", "129"}}, + {in: []string{"128", "129", "129a"}}, + {in: []string{"126a", "126b", "127", "127a", "127b", "128", "128a", "128b", "129", "129a", "129b"}}, + } + + for _, c := range cases { + it, err := ir.Postings("i", nil, c.in...) + require.NoError(t, err) + + got := []string{} + var lbls phlaremodel.Labels + var metas []index.ChunkMeta + for it.Next() { + _, err := ir.Series(it.At(), &lbls, &metas) + require.NoError(t, err) + got = append(got, lbls.Get("i")) + } + require.NoError(t, it.Err()) + exp := []string{} + for _, e := range c.in { + if _, ok := symbols[e]; ok && e != "l" { + exp = append(exp, e) + } + } + + // sort expected values by label hash instead of lexicographically by labelset + sort.Slice(exp, func(i, j int) bool { + return labels.StableHash(labels.FromStrings("i", exp[i], "foo", "bar")) < labels.StableHash(labels.FromStrings("i", exp[j], "foo", "bar")) + }) + + require.Equal(t, exp, got, fmt.Sprintf("input: %v", c.in)) + } +} + +func TestPersistence_index_e2e(t *testing.T) { + lbls, err := labels.ReadLabels("../../../phlaredb/tsdb/testdata/20kseries.json", 20000) + require.NoError(t, err) + + flbls := make([]phlaremodel.Labels, len(lbls)) + for i, ls := range lbls { + flbls[i] = make(phlaremodel.Labels, 0, ls.Len()) + ls.Range(func(l labels.Label) { + flbls[i] = append(flbls[i], &typesv1.LabelPair{Name: l.Name, Value: l.Value}) + }) + } + + // Sort labels as the index writer expects series in sorted order by fingerprint. + sort.Slice(flbls, func(i, j int) bool { + return flbls[i].Hash() < flbls[j].Hash() + }) + + symbols := map[string]struct{}{} + for _, lset := range lbls { + lset.Range(func(l labels.Label) { + symbols[l.Name] = struct{}{} + symbols[l.Value] = struct{}{} + }) + } + + var input index.IndexWriterSeriesSlice + + // Generate ChunkMetas for every label set. + for i, lset := range flbls { + var metas []index.ChunkMeta + + for j := 0; j <= (i % 20); j++ { + metas = append(metas, index.ChunkMeta{ + MinTime: int64(j * 10000), + MaxTime: int64((j + 1) * 10000), + Checksum: rand.Uint32(), + }) + } + input = append(input, &index.IndexWriterSeries{ + Labels: lset, + Chunks: metas, + }) + } + + iw, err := NewWriter(context.Background(), BlocksIndexWriterBufSize) + require.NoError(t, err) + + syms := []string{} + for s := range symbols { + syms = append(syms, s) + } + sort.Strings(syms) + for _, s := range syms { + require.NoError(t, iw.AddSymbol(s)) + } + + // Population procedure as done by compaction. + var ( + postings = index.NewMemPostings() + values = map[string]map[string]struct{}{} + ) + + mi := newMockIndex() + + for i, s := range input { + err = iw.AddSeries(storage.SeriesRef(i), s.Labels, model.Fingerprint(s.Labels.Hash()), s.Chunks...) + require.NoError(t, err) + require.NoError(t, mi.AddSeries(storage.SeriesRef(i), s.Labels, s.Chunks...)) + + for _, l := range s.Labels { + valset, ok := values[l.Name] + if !ok { + valset = map[string]struct{}{} + values[l.Name] = valset + } + valset[l.Value] = struct{}{} + } + postings.Add(storage.SeriesRef(i), s.Labels) + } + + err = iw.Close() + require.NoError(t, err) + + ir, err := index.NewReader(index.RealByteSlice(iw.ReleaseIndexBuffer().buf.Bytes())) + require.NoError(t, err) + + for p := range mi.postings { + gotp, err := ir.Postings(p.Name, nil, p.Value) + require.NoError(t, err) + + expp, err := mi.Postings(p.Name, p.Value) + require.NoError(t, err) + + var lset, explset phlaremodel.Labels + var chks, expchks []index.ChunkMeta + + for gotp.Next() { + require.True(t, expp.Next()) + + ref := gotp.At() + + _, err := ir.Series(ref, &lset, &chks) + require.NoError(t, err) + + err = mi.Series(expp.At(), &explset, &expchks) + require.NoError(t, err) + require.Equal(t, explset, lset) + require.Equal(t, expchks, chks) + } + require.False(t, expp.Next(), "Expected no more postings for %q=%q", p.Name, p.Value) + require.NoError(t, gotp.Err()) + } + + labelPairs := map[string][]string{} + for l := range mi.postings { + labelPairs[l.Name] = append(labelPairs[l.Name], l.Value) + } + for k, v := range labelPairs { + sort.Strings(v) + + res, err := ir.LabelValues(k) + require.NoError(t, err) + sort.Strings(res) + + require.Equal(t, len(v), len(res)) + for i := 0; i < len(v); i++ { + require.Equal(t, v[i], res[i]) + } + } + + gotSymbols, err := ir.SymbolTable() + require.NoError(t, err) + sort.Strings(gotSymbols) + expSymbols := []string{} + for s := range mi.symbols { + expSymbols = append(expSymbols, s) + } + sort.Strings(expSymbols) + require.Equal(t, expSymbols, gotSymbols) + + require.NoError(t, ir.Close()) +} + +func TestDecbufUvarintWithInvalidBuffer(t *testing.T) { + b := RealByteSlice([]byte{0x81, 0x81, 0x81, 0x81, 0x81, 0x81}) + + db := encoding.NewDecbufUvarintAt(b, 0, castagnoliTable) + require.Error(t, db.Err()) +} + +func TestSymbols(t *testing.T) { + buf := encoding.Encbuf{} + + // Add prefix to the buffer to simulate symbols as part of larger buffer. + buf.PutUvarintStr("something") + + symbolsStart := buf.Len() + buf.PutBE32int(204) // Length of symbols table. + buf.PutBE32int(100) // Number of symbols. + for i := 0; i < 100; i++ { + // i represents index in unicode characters table. + buf.PutUvarintStr(string(rune(i))) // Symbol. + } + checksum := crc32.Checksum(buf.Get()[symbolsStart+4:], castagnoliTable) + buf.PutBE32(checksum) // Check sum at the end. + + s, err := NewSymbols(RealByteSlice(buf.Get()), symbolsStart) + require.NoError(t, err) + + // We store only 4 offsets to symbols. + require.Equal(t, 32, s.Size()) + + for i := 99; i >= 0; i-- { + s, err := s.Lookup(uint32(i)) + require.NoError(t, err) + require.Equal(t, string(rune(i)), s) + } + _, err = s.Lookup(100) + require.Error(t, err) + + for i := 99; i >= 0; i-- { + r, err := s.ReverseLookup(string(rune(i))) + require.NoError(t, err) + require.Equal(t, uint32(i), r) + } + _, err = s.ReverseLookup(string(rune(100))) + require.Error(t, err) +} + +func TestWriter_ShouldReturnErrorOnSeriesWithDuplicatedLabelNames(t *testing.T) { + w, err := NewWriter(context.Background(), BlocksIndexWriterBufSize) + require.NoError(t, err) + + require.NoError(t, w.AddSymbol("__name__")) + require.NoError(t, w.AddSymbol("metric_1")) + require.NoError(t, w.AddSymbol("metric_2")) + + require.NoError(t, w.AddSeries(0, phlaremodel.LabelsFromStrings("__name__", "metric_1", "__name__", "metric_2"), 0)) + + err = w.Close() + require.Error(t, err) + require.ErrorContains(t, err, "corruption detected when writing postings to index") +} diff --git a/pkg/segmentwriter/memdb/metrics.go b/pkg/segmentwriter/memdb/metrics.go new file mode 100644 index 0000000000..8ab00f21bb --- /dev/null +++ b/pkg/segmentwriter/memdb/metrics.go @@ -0,0 +1,201 @@ +package memdb + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +// todo remove unused +type HeadMetrics struct { + //series prometheus.Gauge + seriesCreated *prometheus.CounterVec + // + //profiles prometheus.Gauge + profilesCreated *prometheus.CounterVec + // + //sizeBytes *prometheus.GaugeVec + rowsWritten *prometheus.CounterVec + // + sampleValuesIngested *prometheus.CounterVec + sampleValuesReceived *prometheus.CounterVec + + flushedFileSizeBytes *prometheus.HistogramVec + flushedBlockSizeBytes prometheus.Histogram + flushedBlockDurationSeconds prometheus.Histogram + flushedBlockSeries prometheus.Histogram + flushedBlockSamples prometheus.Histogram + flusehdBlockProfiles prometheus.Histogram + blockDurationSeconds prometheus.Histogram + flushedBlocks *prometheus.CounterVec + //flushedBlocksReasons *prometheus.CounterVec + flushedBlocksUnsymbolized *prometheus.CounterVec + writtenProfileSegments *prometheus.CounterVec + writtenProfileSegmentsBytes prometheus.Histogram +} + +func NewHeadMetricsWithPrefix(reg prometheus.Registerer, prefix string) *HeadMetrics { + m := &HeadMetrics{ + seriesCreated: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: prefix + "_tsdb_head_series_created_total", + Help: "Total number of series created in the head", + }, []string{"profile_name"}), + rowsWritten: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: prefix + "_rows_written", + Help: "Number of rows written to a parquet table.", + }, + []string{"type"}), + profilesCreated: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: prefix + "_head_profiles_created_total", + Help: "Total number of profiles created in the head", + }, []string{"profile_name"}), + sampleValuesIngested: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: prefix + "_head_ingested_sample_values_total", + Help: "Number of sample values ingested into the head per profile type.", + }, + []string{"profile_name"}), + sampleValuesReceived: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: prefix + "_head_received_sample_values_total", + Help: "Number of sample values received into the head per profile type.", + }, + []string{"profile_name"}), + //sizeBytes: prometheus.NewGaugeVec( + // prometheus.GaugeOpts{ + // Name: prefix + "_head_size_bytes", + // Help: "Size of a particular in memory store within the head phlaredb block.", + // }, + // []string{"type"}), + //series: prometheus.NewGauge(prometheus.GaugeOpts{ + // Name: prefix + "_tsdb_head_series", + // Help: "Total number of series in the head block.", + //}), + //profiles: prometheus.NewGauge(prometheus.GaugeOpts{ + // Name: prefix + "_head_profiles", + // Help: "Total number of profiles in the head block.", + //}), + flushedFileSizeBytes: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: prefix + "_head_flushed_table_size_bytes", + Help: "Size of a flushed table in bytes.", + // [2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB, 256MB, 512MB, 1GB, 2GB] + Buckets: prometheus.ExponentialBuckets(2*1024*1024, 2, 11), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"name"}), + flushedBlockSizeBytes: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: prefix + "_head_flushed_block_size_bytes", + Help: "Size of a flushed block in bytes.", + // [50MB, 75MB, 112.5MB, 168.75MB, 253.125MB, 379.688MB, 569.532MB, 854.298MB, 1.281MB, 1.922MB, 2.883MB] + Buckets: prometheus.ExponentialBuckets(50*1024*1024, 1.5, 11), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + flushedBlockDurationSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: prefix + "_head_flushed_block_duration_seconds", + Help: "Time to flushed a block in seconds.", + // [5s, 7.5s, 11.25s, 16.875s, 25.3125s, 37.96875s, 56.953125s, 85.4296875s, 128.14453125s, 192.216796875s] + Buckets: prometheus.ExponentialBuckets(5, 1.5, 10), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + flushedBlockSeries: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: prefix + "_head_flushed_block_series", + Help: "Number of series in a flushed block.", + // [1k, 3k, 5k, 7k, 9k, 11k, 13k, 15k, 17k, 19k] + Buckets: prometheus.LinearBuckets(1000, 2000, 10), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + flushedBlockSamples: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: prefix + "_head_flushed_block_samples", + Help: "Number of samples in a flushed block.", + // [200k, 400k, 800k, 1.6M, 3.2M, 6.4M, 12.8M, 25.6M, 51.2M, 102.4M, 204.8M, 409.6M, 819.2M, 1.6384G, 3.2768G] + Buckets: prometheus.ExponentialBuckets(200_000, 2, 15), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + flusehdBlockProfiles: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: prefix + "_head_flushed_block_profiles", + Help: "Number of profiles in a flushed block.", + // [20k, 40k, 80k, 160k, 320k, 640k, 1.28M, 2.56M, 5.12M, 10.24M] + Buckets: prometheus.ExponentialBuckets(20_000, 2, 10), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + blockDurationSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: prefix + "_head_block_duration_seconds", + Help: "Duration of a block in seconds (the range it covers).", + // [20m, 40m, 1h, 1h20, 1h40, 2h, 2h20, 2h40, 3h, 3h20, 3h40, 4h, 4h20, 4h40, 5h, 5h20, 5h40, 6h, 6h20, 6h40, 7h, 7h20, 7h40, 8h] + Buckets: prometheus.LinearBuckets(1200, 1200, 24), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + flushedBlocks: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: prefix + "_head_flushed_blocks_total", + Help: "Total number of blocks flushed.", + }, []string{"status"}), + //flushedBlocksReasons: prometheus.NewCounterVec(prometheus.CounterOpts{ + // Name: prefix + "_head_flushed_reason_total", + // Help: "Total count of reasons why block has been flushed.", + //}, []string{"reason"}), + flushedBlocksUnsymbolized: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: prefix + "_head_flushed_blocks_unsymbolized_total", + Help: "Total number of blocks flushed, labeled by unsymbolized status (unsymbolized=true means at least one profile lacks symbols, false means all profiles are symbolized)", + }, []string{"unsymbolized"}), + writtenProfileSegments: prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: prefix + "_head_written_profile_segments_total", + Help: "Total number and status of profile row groups segments written.", + }, []string{"status"}), + writtenProfileSegmentsBytes: prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: prefix + "_head_written_profile_segments_size_bytes", + Help: "Size of a flushed table in bytes.", + // [512KB, 1MB, 2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB, 256MB, 512MB] + Buckets: prometheus.ExponentialBuckets(512*1024, 2, 11), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }), + //samples: prometheus.NewGauge(prometheus.GaugeOpts{ + // Name: prefix + "_head_samples", + // Help: "Number of samples in the head.", + //}), + } + + m.register(reg) + return m +} + +func (m *HeadMetrics) register(reg prometheus.Registerer) { + if reg == nil { + return + } + //reg.MustRegister(m.series) + reg.MustRegister(m.seriesCreated) + //reg.MustRegister(m.profiles) + reg.MustRegister(m.profilesCreated) + //reg.MustRegister(m.sizeBytes) + reg.MustRegister(m.rowsWritten) + reg.MustRegister(m.sampleValuesIngested) + reg.MustRegister(m.sampleValuesReceived) + reg.MustRegister(m.flushedFileSizeBytes) + reg.MustRegister(m.flushedBlockSizeBytes) + reg.MustRegister(m.flushedBlockDurationSeconds) + reg.MustRegister(m.flushedBlockSeries) + reg.MustRegister(m.flushedBlockSamples) + reg.MustRegister(m.flusehdBlockProfiles) + reg.MustRegister(m.blockDurationSeconds) + reg.MustRegister(m.flushedBlocks) + //reg.MustRegister(m.flushedBlocksReasons) + reg.MustRegister(m.flushedBlocksUnsymbolized) + reg.MustRegister(m.writtenProfileSegments) + reg.MustRegister(m.writtenProfileSegmentsBytes) +} diff --git a/pkg/segmentwriter/memdb/profile_index.go b/pkg/segmentwriter/memdb/profile_index.go new file mode 100644 index 0000000000..b77586d3ab --- /dev/null +++ b/pkg/segmentwriter/memdb/profile_index.go @@ -0,0 +1,175 @@ +package memdb + +import ( + "context" + "sort" + "sync" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/storage" + "go.uber.org/atomic" + + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + memindex "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb/index" +) + +type profileSeries struct { + lbs phlaremodel.Labels + fp model.Fingerprint + minTime, maxTime int64 + profiles []*schemav1.InMemoryProfile +} + +type profilesIndex struct { + ix *tsdb.BitPrefixInvertedIndex + profilesPerFP map[model.Fingerprint]*profileSeries + mutex sync.RWMutex + metrics *HeadMetrics + totalSeries *atomic.Int64 +} + +func newProfileIndex(metrics *HeadMetrics) *profilesIndex { + ix, err := tsdb.NewBitPrefixWithShards(32) + if err != nil { + panic(err) + } + return &profilesIndex{ + ix: ix, + profilesPerFP: make(map[model.Fingerprint]*profileSeries), + metrics: metrics, + totalSeries: atomic.NewInt64(0), + } +} + +// Add a new set of profile to the index. +// The seriesRef are expected to match the profile labels passed in. +func (pi *profilesIndex) Add(ps *schemav1.InMemoryProfile, lbs phlaremodel.Labels, profileName string) { + pi.mutex.Lock() + defer pi.mutex.Unlock() + profiles, ok := pi.profilesPerFP[ps.SeriesFingerprint] + if !ok { + lbs := pi.ix.Add(lbs, ps.SeriesFingerprint) + profiles = &profileSeries{ + lbs: lbs, + fp: ps.SeriesFingerprint, + minTime: ps.TimeNanos, + maxTime: ps.TimeNanos, + } + pi.profilesPerFP[ps.SeriesFingerprint] = profiles + //pi.metrics.series.Set(float64(pi.totalSeries.Inc())) // todo how did it work? + pi.totalSeries.Inc() + pi.metrics.seriesCreated.WithLabelValues(profileName).Inc() + } + + // profile is latest in this series, use a shortcut + if ps.TimeNanos > profiles.maxTime { + // update max timeNanos + profiles.maxTime = ps.TimeNanos + + // add profile to in memory slice + profiles.profiles = append(profiles.profiles, ps) + } else { + // use binary search to find position + i := sort.Search(len(profiles.profiles), func(i int) bool { + return profiles.profiles[i].TimeNanos > ps.TimeNanos + }) + + // insert into slice at correct position + profiles.profiles = append(profiles.profiles, &schemav1.InMemoryProfile{}) + copy(profiles.profiles[i+1:], profiles.profiles[i:]) + profiles.profiles[i] = ps + } + + if ps.TimeNanos < profiles.minTime { + profiles.minTime = ps.TimeNanos + } + + //pi.metrics.profiles.Set(float64(pi.totalProfiles.Inc())) //todo how did it work? + pi.metrics.profilesCreated.WithLabelValues(profileName).Inc() +} + +func (pi *profilesIndex) Flush(ctx context.Context) ([]byte, []schemav1.InMemoryProfile, []*profileSeries, error) { + writer, err := memindex.NewWriter(ctx, memindex.SegmentsIndexWriterBufSize) + if err != nil { + return nil, nil, nil, err + } + pi.mutex.RLock() + defer pi.mutex.RUnlock() + + pfs := make([]*profileSeries, 0, len(pi.profilesPerFP)) + profilesSize := 0 + for _, p := range pi.profilesPerFP { + pfs = append(pfs, p) + profilesSize += len(p.profiles) + } + + // sort by fp + sort.Slice(pfs, func(i, j int) bool { + return phlaremodel.CompareLabelPairs(pfs[i].lbs, pfs[j].lbs) < 0 + }) + + symbolsMap := make(map[string]struct{}) + for _, s := range pfs { + for _, l := range s.lbs { + symbolsMap[l.Name] = struct{}{} + symbolsMap[l.Value] = struct{}{} + } + } + + // Sort symbols + symbols := make([]string, 0, len(symbolsMap)) + for s := range symbolsMap { + symbols = append(symbols, s) + } + sort.Strings(symbols) + + // Add symbols + for _, symbol := range symbols { + if err := writer.AddSymbol(symbol); err != nil { + return nil, nil, nil, err + } + } + + profiles := make([]schemav1.InMemoryProfile, 0, profilesSize) + + // Add series + for i, s := range pfs { + if err := writer.AddSeries(storage.SeriesRef(i), s.lbs, s.fp, index.ChunkMeta{ + MinTime: s.minTime, + MaxTime: s.maxTime, + // We store the series Index from the head with the series to use when retrieving data from parquet. + SeriesIndex: uint32(i), + }); err != nil { + return nil, nil, nil, err + } + // store series index + for j := range s.profiles { + s.profiles[j].SeriesIndex = uint32(i) + } + //profiles = append(profiles, s.profiles...) + for _, profile := range s.profiles { + profiles = append(profiles, *profile) //todo avoid copy + } + } + + err = writer.Close() + if err != nil { + return nil, nil, nil, err + } + + //todo maybe return the bufferWriter to avoid copy, it is copied again anyway + tsdbIndex := writer.ReleaseIndex() + + return tsdbIndex, profiles, pfs, err +} + +func (pi *profilesIndex) profileTypeNames() ([]string, error) { + pi.mutex.RLock() + defer pi.mutex.RUnlock() + ptypes, err := pi.ix.LabelValues(phlaremodel.LabelNameProfileType, nil) + sort.Strings(ptypes) + return ptypes, err +} diff --git a/pkg/segmentwriter/memdb/profile_index_test.go b/pkg/segmentwriter/memdb/profile_index_test.go new file mode 100644 index 0000000000..7282233836 --- /dev/null +++ b/pkg/segmentwriter/memdb/profile_index_test.go @@ -0,0 +1,323 @@ +package memdb + +import ( + "context" + "errors" + "fmt" + "sort" + "sync" + "testing" + + "github.com/google/uuid" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" +) + +func TestIndex(t *testing.T) { + a := newProfileIndex(NewHeadMetricsWithPrefix(prometheus.NewRegistry(), "")) + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for j := 0; j < 10; j++ { + lb1 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "bytes"}, + {Name: "__profile_type__", Value: "::::"}, + {Name: "bar", Value: fmt.Sprint(j)}, + }) + sort.Sort(lb1) + lb2 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "count"}, + {Name: "__profile_type__", Value: "::::"}, + {Name: "bar", Value: fmt.Sprint(j)}, + }) + sort.Sort(lb2) + + for k := int64(0); k < 10; k++ { + id := uuid.New() + a.Add(&v1.InMemoryProfile{ + ID: id, + TimeNanos: k, + SeriesFingerprint: model.Fingerprint(lb1.Hash()), + }, lb1, "memory") + a.Add(&v1.InMemoryProfile{ + ID: id, + TimeNanos: k, + SeriesFingerprint: model.Fingerprint(lb2.Hash()), + }, lb2, "memory") + } + } + }() + } + wg.Wait() + + // Testing Matching + fps, err := selectMatchingFPs(a, &ingestv1.SelectProfilesRequest{ + LabelSelector: `memory{bar=~"[0-9]", buzz!="bar"}`, + Type: &typesv1.ProfileType{}, + }) + require.NoError(t, err) + require.Len(t, fps, 20) + + names, err := a.ix.LabelNames(nil) + require.NoError(t, err) + require.Equal(t, []string{"__name__", "__profile_type__", "__sample__type__", "bar"}, names) + + values, err := a.ix.LabelValues("__sample__type__", nil) + require.NoError(t, err) + require.Equal(t, []string{"bytes", "count"}, values) + values, err = a.ix.LabelValues("bar", nil) + require.NoError(t, err) + require.Equal(t, []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, values) +} + +func selectMatchingFPs(pi *profilesIndex, params *ingestv1.SelectProfilesRequest) ([]model.Fingerprint, error) { + selectors, err := phlaremodel.ParseMetricSelector(params.LabelSelector) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "failed to parse label selectors: "+err.Error()) + } + if params.Type == nil { + return nil, errors.New("no profileType given") + } + selectors = append(selectors, phlaremodel.SelectorFromProfileType(params.Type)) + + filters, matchers := phlaredb.SplitFiltersAndMatchers(selectors) + ids, err := pi.ix.Lookup(matchers, nil) + if err != nil { + return nil, err + } + + pi.mutex.RLock() + defer pi.mutex.RUnlock() + + // filter fingerprints that no longer exist or don't match the filters + var idx int +outer: + for _, fp := range ids { + profile, ok := pi.profilesPerFP[fp] + if !ok { + // If a profile labels is missing here, it has already been flushed + // and is supposed to be picked up from storage by querier + continue + } + for _, filter := range filters { + if !filter.Matches(profile.lbs.Get(filter.Name)) { + continue outer + } + } + + // keep this one + ids[idx] = fp + idx++ + } + + return ids[:idx], nil +} + +func TestWriteRead(t *testing.T) { + a := newProfileIndex(NewHeadMetricsWithPrefix(prometheus.NewRegistry(), "")) + + for j := 0; j < 10; j++ { + lb1 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "bytes"}, + {Name: "bar", Value: fmt.Sprint(j)}, + }) + sort.Sort(lb1) + lb2 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "count"}, + {Name: "bar", Value: fmt.Sprint(j)}, + }) + sort.Sort(lb2) + + for k := int64(0); k < 10; k++ { + id := uuid.New() + a.Add(&v1.InMemoryProfile{ + ID: id, + TimeNanos: k, + SeriesFingerprint: model.Fingerprint(lb1.Hash()), + }, lb1, "memory") + a.Add(&v1.InMemoryProfile{ + ID: id, + TimeNanos: k, + SeriesFingerprint: model.Fingerprint(lb2.Hash()), + }, lb2, "memory") + } + } + + indexData, _, _, err := a.Flush(context.Background()) + require.NoError(t, err) + + r, err := index.NewReader(index.RealByteSlice(indexData)) + require.NoError(t, err) + + names, err := r.LabelNames() + require.NoError(t, err) + require.Equal(t, []string{"__name__", "__sample__type__", "bar"}, names) + + values, err := r.LabelValues("bar") + require.NoError(t, err) + require.Equal(t, []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, values) + + from, through := r.Bounds() + require.Equal(t, int64(0), from) + require.Equal(t, int64(9), through) + p, err := r.Postings("__name__", nil, "memory") + lbls := make(phlaremodel.Labels, 2) + chks := make([]index.ChunkMeta, 1) + require.NoError(t, err) + for p.Next() { + fp, err := r.Series(p.At(), &lbls, &chks) + require.NoError(t, err) + require.Equal(t, lbls.Hash(), fp) + require.Equal(t, "memory", lbls.Get("__name__")) + require.Equal(t, 3, len(lbls)) + require.Equal(t, 1, len(chks)) + require.Equal(t, int64(0), chks[0].MinTime) + require.Equal(t, int64(9), chks[0].MaxTime) + } +} + +func TestQueryIndex(t *testing.T) { + a := newProfileIndex(NewHeadMetricsWithPrefix(prometheus.NewRegistry(), "")) + + for j := 0; j < 10; j++ { + lb1 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "bytes"}, + {Name: "bar", Value: fmt.Sprint(j)}, + }) + sort.Sort(lb1) + lb2 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "count"}, + {Name: "bar", Value: fmt.Sprint(j)}, + }) + sort.Sort(lb2) + + for k := int64(0); k < 10; k++ { + id := uuid.New() + a.Add(&v1.InMemoryProfile{ + ID: id, + TimeNanos: k, + SeriesFingerprint: model.Fingerprint(lb1.Hash()), + }, lb1, "memory") + a.Add(&v1.InMemoryProfile{ + ID: id, + TimeNanos: k, + SeriesFingerprint: model.Fingerprint(lb2.Hash()), + }, lb2, "memory") + } + } + + indexData, _, _, err := a.Flush(context.Background()) + require.NoError(t, err) + + r, err := index.NewReader(index.RealByteSlice(indexData)) + require.NoError(t, err) + + p, err := phlaredb.PostingsForMatchers(r, nil, labels.MustNewMatcher(labels.MatchRegexp, "bar", "(1|2)")) + require.NoError(t, err) + + lbls := make(phlaremodel.Labels, 3) + chks := make([]index.ChunkMeta, 1) + for p.Next() { + fp, err := r.Series(p.At(), &lbls, &chks) + require.NoError(t, err) + require.Equal(t, lbls.Hash(), fp) + require.Equal(t, 3, len(lbls)) + + require.Equal(t, "memory", lbls.Get("__name__")) + require.True(t, lbls.Get("bar") == "1" || lbls.Get("bar") == "2") + + require.Equal(t, 1, len(chks)) + require.Equal(t, int64(0), chks[0].MinTime) + require.Equal(t, int64(9), chks[0].MaxTime) + } +} + +func TestProfileTypeNames(t *testing.T) { + a := newProfileIndex(NewHeadMetricsWithPrefix(prometheus.NewRegistry(), "")) + + for j := 0; j < 5; j++ { + lb1 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "cpu"}, + {Name: phlaremodel.LabelNameProfileType, Value: fmt.Sprintf("test-profile-type-%d", j)}, + }) + sort.Sort(lb1) + a.Add(&v1.InMemoryProfile{ + ID: uuid.New(), + TimeNanos: 0, + SeriesFingerprint: model.Fingerprint(lb1.Hash()), + }, lb1, "cpu") + } + names, err := a.profileTypeNames() + require.NoError(t, err) + require.Equal(t, []string{"test-profile-type-0", "test-profile-type-1", "test-profile-type-2", "test-profile-type-3", "test-profile-type-4"}, names) +} + +func TestIndexAddOutOfOrder(t *testing.T) { + a := newProfileIndex(NewHeadMetricsWithPrefix(prometheus.NewRegistry(), "")) + + lb1 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "bytes"}, + {Name: "bar", Value: "1"}, + }) + sort.Sort(lb1) + + lb2 := phlaremodel.Labels([]*typesv1.LabelPair{ + {Name: "__name__", Value: "memory"}, + {Name: "__sample__type__", Value: "bytes"}, + {Name: "bar", Value: "2"}, + }) + sort.Sort(lb2) + + a.Add(&v1.InMemoryProfile{ + ID: uuid.New(), + TimeNanos: 239, + SeriesFingerprint: model.Fingerprint(lb2.Hash()), + }, lb2, "memory") + + ts := []uint64{10, 20, 0} + + for _, t := range ts { + a.Add(&v1.InMemoryProfile{ + ID: uuid.New(), + TimeNanos: int64(t), + SeriesFingerprint: model.Fingerprint(lb1.Hash()), + }, lb1, "memory") + } + + a.Add(&v1.InMemoryProfile{ + ID: uuid.New(), + TimeNanos: 238, + SeriesFingerprint: model.Fingerprint(lb2.Hash()), + }, lb2, "memory") + + _, profiles, _, err := a.Flush(context.Background()) + require.NoError(t, err) + assert.Equal(t, 5, len(profiles)) + expectedTS := []int64{0, 10, 20, 238, 239} + expectedSeriesIndex := []uint32{0, 0, 0, 1, 1} + for i := range profiles { + assert.Equal(t, expectedTS[i], profiles[i].TimeNanos) + assert.Equal(t, expectedSeriesIndex[i], profiles[i].SeriesIndex) + } +} diff --git a/pkg/segmentwriter/memdb/profiles.go b/pkg/segmentwriter/memdb/profiles.go new file mode 100644 index 0000000000..44edc4a7bb --- /dev/null +++ b/pkg/segmentwriter/memdb/profiles.go @@ -0,0 +1,36 @@ +package memdb + +import ( + "bytes" + "fmt" + + "github.com/parquet-go/parquet-go" + + v1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" + "github.com/grafana/pyroscope/v2/pkg/util/build" +) + +const segmentsParquetWriteBufferSize = 32 << 10 + +func WriteProfiles(metrics *HeadMetrics, profiles []v1.InMemoryProfile) ([]byte, error) { + buf := &bytes.Buffer{} + w := parquet.NewGenericWriter[*v1.Profile]( + buf, + parquet.PageBufferSize(segmentsParquetWriteBufferSize), + parquet.CreatedBy("github.com/grafana/pyroscope/", build.Version, build.Revision), + v1.ProfilesSchema, + ) + + if _, err := parquet.CopyRows(w, v1.NewInMemoryProfilesRowReader(profiles)); err != nil { + return nil, fmt.Errorf("failed to write profile rows to parquet table: %w", err) + } + if err := w.Close(); err != nil { + return nil, fmt.Errorf("failed to close parquet table: %w", err) + } + + metrics.writtenProfileSegments.WithLabelValues("success").Inc() + res := buf.Bytes() + metrics.writtenProfileSegmentsBytes.Observe(float64(len(res))) + metrics.rowsWritten.WithLabelValues("profiles").Add(float64(len(profiles))) + return res, nil +} diff --git a/pkg/segmentwriter/memdb/profiles_test.go b/pkg/segmentwriter/memdb/profiles_test.go new file mode 100644 index 0000000000..919a5cac79 --- /dev/null +++ b/pkg/segmentwriter/memdb/profiles_test.go @@ -0,0 +1,58 @@ +package memdb + +import ( + "bytes" + "testing" + + "github.com/google/uuid" + "github.com/parquet-go/parquet-go" + "github.com/stretchr/testify/require" + + schemav1 "github.com/grafana/pyroscope/v2/pkg/phlaredb/schemas/v1" +) + +func genProfile(series uint32, timeNanos int, numSamples int) schemav1.InMemoryProfile { + res := schemav1.InMemoryProfile{ + ID: uuid.New(), + TimeNanos: int64(timeNanos), + SeriesIndex: series, + StacktracePartition: 0, + Samples: schemav1.Samples{ + StacktraceIDs: make([]uint32, numSamples), + Values: make([]uint64, numSamples), + Spans: nil, + }, + } + for i := range res.Samples.StacktraceIDs { + res.Samples.StacktraceIDs[i] = uint32(i) + res.Samples.Values[i] = uint64(i) + } + return res +} + +func TestWriteProfiles(t *testing.T) { + m := NewHeadMetricsWithPrefix(nil, "") + profiles := []schemav1.InMemoryProfile{ + genProfile(239, 4242, 4242), + genProfile(1, 1, 1), + genProfile(2, 2, 2), + genProfile(2, 2, 2), + } + profileParquet, err := WriteProfiles(m, profiles) + require.NoError(t, err) + + reader := parquet.NewReader(bytes.NewReader(profileParquet), schemav1.ProfilesSchema) + for i := 0; i < len(profiles); i++ { + var p schemav1.Profile + err := reader.Read(&p) + require.NoError(t, err) + ep := profiles[i] + require.Equal(t, ep.ID, p.ID) + require.Equal(t, ep.SeriesIndex, p.SeriesIndex) + require.Equal(t, ep.TimeNanos, p.TimeNanos) + for j := range ep.Samples.Values { + require.Equal(t, int64(ep.Samples.Values[j]), p.Samples[j].Value) + require.Equal(t, uint64(ep.Samples.StacktraceIDs[j]), p.Samples[j].StacktraceID) + } + } +} diff --git a/pkg/segmentwriter/memdb/testutil/querier.go b/pkg/segmentwriter/memdb/testutil/querier.go new file mode 100644 index 0000000000..2167877035 --- /dev/null +++ b/pkg/segmentwriter/memdb/testutil/querier.go @@ -0,0 +1,91 @@ +package testutil + +import ( + "context" + "errors" + "net/http" + "testing" + + "connectrpc.com/connect" + "github.com/stretchr/testify/assert" + + ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1/ingesterv1connect" + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/testhelper" +) + +// Copied from phlaredb, todo +type IngesterHandlerPhlareDB struct { + phlaredb.Queriers +} + +func IngesterClientForTest(t *testing.T, q phlaredb.Queriers) (ingesterv1connect.IngesterServiceClient, func()) { + assert.NotEmpty(t, q) + mux := http.NewServeMux() + mux.Handle(ingesterv1connect.NewIngesterServiceHandler(&IngesterHandlerPhlareDB{q}, connectapi.DefaultHandlerOptions()...)) + serv := testhelper.NewInMemoryServer(mux) + + var httpClient = serv.Client() + + client := ingesterv1connect.NewIngesterServiceClient( + httpClient, serv.URL(), connectapi.DefaultClientOptions()..., + ) + + return client, serv.Close +} + +func (i *IngesterHandlerPhlareDB) MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesStacktracesRequest, ingestv1.MergeProfilesStacktracesResponse]) error { + return phlaredb.MergeProfilesStacktraces(ctx, stream, i.ForTimeRange) +} + +func (i *IngesterHandlerPhlareDB) MergeProfilesLabels(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesLabelsRequest, ingestv1.MergeProfilesLabelsResponse]) error { + return phlaredb.MergeProfilesLabels(ctx, stream, i.ForTimeRange) +} + +func (i *IngesterHandlerPhlareDB) MergeProfilesPprof(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesPprofRequest, ingestv1.MergeProfilesPprofResponse]) error { + return phlaredb.MergeProfilesPprof(ctx, stream, i.ForTimeRange) +} + +func (i *IngesterHandlerPhlareDB) MergeSpanProfile(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeSpanProfileRequest, ingestv1.MergeSpanProfileResponse]) error { + return phlaredb.MergeSpanProfile(ctx, stream, i.ForTimeRange) +} + +func (i *IngesterHandlerPhlareDB) Push(context.Context, *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) LabelValues(context.Context, *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) LabelNames(context.Context, *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) ProfileTypes(context.Context, *connect.Request[ingestv1.ProfileTypesRequest]) (*connect.Response[ingestv1.ProfileTypesResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) Series(context.Context, *connect.Request[ingestv1.SeriesRequest]) (*connect.Response[ingestv1.SeriesResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) Flush(context.Context, *connect.Request[ingestv1.FlushRequest]) (*connect.Response[ingestv1.FlushResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) BlockMetadata(context.Context, *connect.Request[ingestv1.BlockMetadataRequest]) (*connect.Response[ingestv1.BlockMetadataResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) GetProfileStats(context.Context, *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) { + return nil, errors.New("not implemented") +} + +func (i *IngesterHandlerPhlareDB) GetBlockStats(context.Context, *connect.Request[ingestv1.GetBlockStatsRequest]) (*connect.Response[ingestv1.GetBlockStatsResponse], error) { + return nil, errors.New("not implemented") +} diff --git a/pkg/segmentwriter/segment.go b/pkg/segmentwriter/segment.go new file mode 100644 index 0000000000..e5292efac1 --- /dev/null +++ b/pkg/segmentwriter/segment.go @@ -0,0 +1,812 @@ +package segmentwriter + +import ( + "bytes" + "context" + "crypto/rand" + "fmt" + "io" + "math" + "os" + "runtime" + "slices" + "strings" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/google/uuid" + "github.com/grafana/dskit/backoff" + "github.com/grafana/dskit/tracing" + "github.com/oklog/ulid/v2" + "github.com/thanos-io/objstore" + "golang.org/x/exp/maps" + "golang.org/x/time/rate" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/model/pprofsplit" + pprofmodel "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb" + "github.com/grafana/pyroscope/v2/pkg/util/retry" +) + +type shardKey uint32 + +type segmentsWriter struct { + config Config + limits Limits + logger log.Logger + bucket objstore.Bucket + metastore metastorev1.IndexServiceClient + + shards map[shardKey]*shard + shardsLock sync.RWMutex + pool workerPool + + ctx context.Context + cancel context.CancelFunc + + metrics *segmentMetrics + headMetrics *memdb.HeadMetrics + hedgedUploadLimiter *rate.Limiter +} + +type shard struct { + wg sync.WaitGroup + logger log.Logger + concatBuf []byte + sw *segmentsWriter + mu sync.RWMutex + segment *segment +} + +func (sh *shard) ingest(fn func(head segmentIngest)) segmentWaitFlushed { + sh.mu.RLock() + s := sh.segment + s.inFlightProfiles.Add(1) + sh.mu.RUnlock() + defer s.inFlightProfiles.Done() + fn(s) + return s +} + +func (sh *shard) loop(ctx context.Context) { + loopWG := new(sync.WaitGroup) + ticker := time.NewTicker(sh.sw.config.SegmentDuration) + defer func() { + ticker.Stop() + // Blocking here to make sure no asynchronous code is executed on this shard once loop exits + // This is mostly needed to fix a race in our integration tests + loopWG.Wait() + }() + for { + select { + case <-ticker.C: + sh.flushSegment(context.Background(), loopWG) + case <-ctx.Done(): + sh.flushSegment(context.Background(), loopWG) + return + } + } +} + +func (sh *shard) flushSegment(ctx context.Context, wg *sync.WaitGroup) { + sh.mu.Lock() + s := sh.segment + sh.segment = sh.sw.newSegment(sh, s.shard, sh.logger) + sh.mu.Unlock() + + wg.Add(1) + go func() { // not blocking next ticks in case metastore/s3 latency is high + defer wg.Done() + t1 := time.Now() + s.inFlightProfiles.Wait() + s.debuginfo.waitInflight = time.Since(t1) + + err := s.flush(ctx) + if err != nil { + _ = level.Error(sh.sw.logger).Log("msg", "failed to flush segment", "err", err) + } + if s.debuginfo.movedHeads > 0 { + _ = level.Debug(s.logger).Log("msg", + "writing segment block done", + "heads-count", len(s.datasets), + "heads-moved-count", s.debuginfo.movedHeads, + "tenant-indexes", s.debuginfo.tenantIndexes, + "tenant-index-bytes", s.debuginfo.tenantIndexBytes, + "inflight-duration", s.debuginfo.waitInflight, + "flush-heads-duration", s.debuginfo.flushHeadsDuration, + "flush-block-duration", s.debuginfo.flushBlockDuration, + "store-meta-duration", s.debuginfo.storeMetaDuration, + "total-duration", time.Since(t1)) + } + }() +} + +func newSegmentWriter(l log.Logger, metrics *segmentMetrics, hm *memdb.HeadMetrics, config Config, limits Limits, bucket objstore.Bucket, metastoreClient metastorev1.IndexServiceClient) *segmentsWriter { + sw := &segmentsWriter{ + limits: limits, + metrics: metrics, + headMetrics: hm, + config: config, + logger: l, + bucket: bucket, + shards: make(map[shardKey]*shard), + metastore: metastoreClient, + } + sw.hedgedUploadLimiter = rate.NewLimiter(rate.Limit(sw.config.UploadHedgeRateMax), int(sw.config.UploadHedgeRateBurst)) + sw.ctx, sw.cancel = context.WithCancel(context.Background()) + flushWorkers := runtime.GOMAXPROCS(-1) + if config.FlushConcurrency > 0 { + flushWorkers = int(config.FlushConcurrency) + } + sw.pool.run(max(minFlushConcurrency, flushWorkers)) + return sw +} + +func (sw *segmentsWriter) ingest(shard shardKey, fn func(head segmentIngest)) (await segmentWaitFlushed) { + sw.shardsLock.RLock() + s, ok := sw.shards[shard] + sw.shardsLock.RUnlock() + if ok { + return s.ingest(fn) + } + + sw.shardsLock.Lock() + s, ok = sw.shards[shard] + if ok { + sw.shardsLock.Unlock() + return s.ingest(fn) + } + + s = sw.newShard(shard) + sw.shards[shard] = s + sw.shardsLock.Unlock() + return s.ingest(fn) +} + +func (sw *segmentsWriter) stop() { + sw.logger.Log("msg", "stopping segments writer") + sw.cancel() + sw.shardsLock.Lock() + defer sw.shardsLock.Unlock() + for _, s := range sw.shards { + s.wg.Wait() + } + sw.pool.stop() + sw.logger.Log("msg", "segments writer stopped") +} + +func (sw *segmentsWriter) newShard(sk shardKey) *shard { + sl := log.With(sw.logger, "shard", fmt.Sprintf("%d", sk)) + sh := &shard{ + sw: sw, + logger: sl, + concatBuf: make([]byte, 4*0x1000), + } + sh.segment = sw.newSegment(sh, sk, sl) + sh.wg.Add(1) + go func() { + defer sh.wg.Done() + sh.loop(sw.ctx) + }() + return sh +} + +func (sw *segmentsWriter) newSegment(sh *shard, sk shardKey, sl log.Logger) *segment { + id := ulid.MustNew(ulid.Timestamp(time.Now()), rand.Reader) + sshard := fmt.Sprintf("%d", sk) + s := &segment{ + logger: log.With(sl, "segment-id", id.String()), + ulid: id, + datasets: make(map[datasetKey]*dataset), + sw: sw, + sh: sh, + shard: sk, + sshard: sshard, + doneChan: make(chan struct{}), + } + return s +} + +func (s *segment) flush(ctx context.Context) (err error) { + span, ctx := tracing.StartSpanFromContext(ctx, "segment.flush") + span.SetTag("block_id", s.ulid.String()) + span.SetTag("datasets", len(s.datasets)) + span.SetTag("shard", s.shard) + defer span.Finish() + + t1 := time.Now() + defer func() { + if err != nil { + s.flushErrMutex.Lock() + s.flushErr = err + s.flushErrMutex.Unlock() + } + close(s.doneChan) + s.sw.metrics.flushSegmentDuration.WithLabelValues(s.sshard).Observe(time.Since(t1).Seconds()) + }() + + stream := s.flushHeads(ctx) + s.debuginfo.movedHeads = len(stream.heads) + if len(stream.heads) == 0 { + return nil + } + + // TODO(kolesnikovae): Use buffer pool for blockData. + blockData, blockMeta, err := s.flushBlock(stream) + if err != nil { + return fmt.Errorf("failed to flush block %s: %w", s.ulid.String(), err) + } + if err = s.sw.uploadBlock(ctx, blockData, blockMeta, s); err != nil { + return fmt.Errorf("failed to upload block %s: %w", s.ulid.String(), err) + } + if err = s.sw.storeMetadata(ctx, blockMeta, s); err != nil { + return fmt.Errorf("failed to store meta %s: %w", s.ulid.String(), err) + } + + return nil +} + +func (s *segment) flushBlock(stream flushStream) ([]byte, *metastorev1.BlockMeta, error) { + start := time.Now() + hostname, _ := os.Hostname() + + stringTable := metadata.NewStringTable() + meta := &metastorev1.BlockMeta{ + FormatVersion: 1, + Id: s.ulid.String(), + Tenant: 0, + Shard: uint32(s.shard), + CompactionLevel: 0, + CreatedBy: stringTable.Put(hostname), + MinTime: math.MaxInt64, + MaxTime: 0, + Size: 0, + Datasets: make([]*metastorev1.Dataset, 0, len(stream.heads)), + } + + blockFile := bytes.NewBuffer(nil) + + w := &writerOffset{Writer: blockFile} + // Datasets are flushed in tenant+service order, so all datasets of a + // given tenant are contiguous. We accumulate series of each tenant in + // a DatasetIndexWriter and emit a per-tenant dataset index pseudo- + // dataset once we observe the tenant boundary (or after the last head). + var ( + curTenant string + curTenantIdx int + dsIndex *block.DatasetIndexWriter + ) + for stream.Next() { + f := stream.At() + if dsIndex == nil || f.dataset.key.tenant != curTenant { + if dsIndex != nil { + n, err := writeTenantDatasetIndex(w, meta, stringTable, curTenant, curTenantIdx, dsIndex) + if err != nil { + return nil, nil, err + } + if n > 0 { + s.debuginfo.tenantIndexes++ + s.debuginfo.tenantIndexBytes += n + s.sw.metrics.tenantIndexBytes.WithLabelValues(s.sshard, curTenant).Observe(float64(n)) + } + } + curTenant = f.dataset.key.tenant + curTenantIdx = len(meta.Datasets) + dsIndex = block.NewDatasetIndexWriter() + } + ds := concatSegmentHead(f, w, stringTable) + f.flushed.WriteDatasetIndex(dsIndex, uint32(len(meta.Datasets))) + meta.MinTime = min(meta.MinTime, ds.MinTime) + meta.MaxTime = max(meta.MaxTime, ds.MaxTime) + meta.Datasets = append(meta.Datasets, ds) + s.sw.metrics.headSizeBytes.WithLabelValues(s.sshard, f.dataset.key.tenant).Observe(float64(ds.Size)) + } + if dsIndex != nil { + n, err := writeTenantDatasetIndex(w, meta, stringTable, curTenant, curTenantIdx, dsIndex) + if err != nil { + return nil, nil, err + } + if n > 0 { + s.debuginfo.tenantIndexes++ + s.debuginfo.tenantIndexBytes += n + s.sw.metrics.tenantIndexBytes.WithLabelValues(s.sshard, curTenant).Observe(float64(n)) + } + } + + meta.StringTable = stringTable.Strings + meta.MetadataOffset = uint64(w.offset) + if err := metadata.Encode(w, meta); err != nil { + return nil, nil, fmt.Errorf("failed to encode metadata: %w", err) + } + meta.Size = uint64(w.offset) + s.debuginfo.flushBlockDuration = time.Since(start) + return blockFile.Bytes(), meta, nil +} + +type writerOffset struct { + io.Writer + offset int64 +} + +func (w *writerOffset) Write(p []byte) (n int, err error) { + n, err = w.Writer.Write(p) + w.offset += int64(n) + return n, err +} + +// writeTenantDatasetIndex flushes a per-tenant dataset index built from +// the series of all datasets of the tenant in the segment, writes it to +// the block file, and appends a pseudo-dataset entry to the block +// metadata, annotated with the __tenant_dataset__ = dataset_tsdb_index +// label. +// +// firstDatasetIdx is the index of the tenant's first real dataset within +// meta.Datasets and is used to derive the time range covered by the +// tenant in the segment. +// writeTenantDatasetIndex returns the number of bytes written for the +// dataset index payload (0 if the index is empty and no pseudo-dataset +// was emitted). +func writeTenantDatasetIndex( + w *writerOffset, + meta *metastorev1.BlockMeta, + stringTable *metadata.StringTable, + tenant string, + firstDatasetIdx int, + dsIndex *block.DatasetIndexWriter, +) (int64, error) { + defer dsIndex.Close() + if dsIndex.Empty() { + return 0, nil + } + off := uint64(w.offset) + n, err := dsIndex.WriteTo(w) + if err != nil { + return 0, fmt.Errorf("failed to write dataset index: %w", err) + } + var minT, maxT int64 = math.MaxInt64, 0 + for _, ds := range meta.Datasets[firstDatasetIdx:] { + minT = min(minT, ds.MinTime) + maxT = max(maxT, ds.MaxTime) + } + // We annotate the dataset with the + // __tenant_dataset__ = "dataset_tsdb_index" label, + // so the dataset index metadata can be queried. + labels := metadata.NewLabelBuilder(stringTable). + WithLabelSet(metadata.LabelNameTenantDataset, metadata.LabelValueDatasetTSDBIndex). + Build() + meta.Datasets = append(meta.Datasets, &metastorev1.Dataset{ + Format: uint32(block.DatasetFormat1), + Tenant: stringTable.Put(tenant), + Name: 0, // Anonymous. + MinTime: minT, + MaxTime: maxT, + TableOfContents: []uint64{off}, + Size: uint64(n), + Labels: labels, + }) + return n, nil +} + +func concatSegmentHead(f *datasetFlush, w *writerOffset, s *metadata.StringTable) *metastorev1.Dataset { + tenantServiceOffset := w.offset + + ptypes := f.flushed.Meta.ProfileTypeNames + + offsets := []uint64{0, 0, 0} + + offsets[0] = uint64(w.offset) + _, _ = w.Write(f.flushed.Profiles) + + offsets[1] = uint64(w.offset) + _, _ = w.Write(f.flushed.Index) + + offsets[2] = uint64(w.offset) + _, _ = w.Write(f.flushed.Symbols) + + tenantServiceSize := w.offset - tenantServiceOffset + + ds := &metastorev1.Dataset{ + Tenant: s.Put(f.dataset.key.tenant), + Name: s.Put(f.dataset.key.service), + MinTime: f.flushed.Meta.MinTimeNanos / 1e6, + MaxTime: f.flushed.Meta.MaxTimeNanos / 1e6, + Size: uint64(tenantServiceSize), + // - 0: profiles.parquet + // - 1: index.tsdb + // - 2: symbols.symdb + TableOfContents: offsets, + Labels: nil, + } + + lb := metadata.NewLabelBuilder(s) + for _, profileType := range ptypes { + lb.WithLabelSet(model.LabelNameServiceName, f.dataset.key.service, model.LabelNameProfileType, profileType) + } + + if f.flushed.Unsymbolized { + lb.WithLabelSet(model.LabelNameServiceName, f.dataset.key.service, metadata.LabelNameUnsymbolized, "true") + } + + // Other optional labels: + // lb.WithLabelSet("label_name", "label_value", ...) + ds.Labels = lb.Build() + + return ds +} + +func (s *segment) flushHeads(ctx context.Context) flushStream { + heads := maps.Values(s.datasets) + slices.SortFunc(heads, func(a, b *dataset) int { + return a.key.compare(b.key) + }) + + stream := make([]*datasetFlush, len(heads)) + for i := range heads { + f := &datasetFlush{ + dataset: heads[i], + done: make(chan struct{}), + } + stream[i] = f + s.sw.pool.do(func() { + defer close(f.done) + flushed, err := s.flushDataset(ctx, f.dataset) + if err != nil { + level.Error(s.logger).Log("msg", "failed to flush head", "err", err) + return + } + if flushed == nil { + level.Debug(s.logger).Log("msg", "skipping nil head") + return + } + if flushed.Meta.NumSamples == 0 { + level.Debug(s.logger).Log("msg", "skipping empty head") + return + } + f.flushed = flushed + }) + } + + return flushStream{heads: stream} +} + +type flushStream struct { + heads []*datasetFlush + cur *datasetFlush + n int +} + +func (s *flushStream) At() *datasetFlush { return s.cur } + +func (s *flushStream) Next() bool { + for s.n < len(s.heads) { + f := s.heads[s.n] + s.n++ + <-f.done + if f.flushed != nil { + s.cur = f + return true + } + } + return false +} + +func (s *segment) flushDataset(ctx context.Context, e *dataset) (*memdb.FlushedHead, error) { + th := time.Now() + flushed, err := e.head.Flush(ctx) + if err != nil { + s.sw.metrics.flushServiceHeadDuration.WithLabelValues(s.sshard, e.key.tenant).Observe(time.Since(th).Seconds()) + s.sw.metrics.flushServiceHeadError.WithLabelValues(s.sshard, e.key.tenant).Inc() + return nil, fmt.Errorf("failed to flush head : %w", err) + } + s.sw.metrics.flushServiceHeadDuration.WithLabelValues(s.sshard, e.key.tenant).Observe(time.Since(th).Seconds()) + level.Debug(s.logger).Log( + "msg", "flushed head", + "tenant", e.key.tenant, + "service", e.key.service, + "profiles", flushed.Meta.NumProfiles, + "profiletypes", fmt.Sprintf("%v", flushed.Meta.ProfileTypeNames), + "mintime", flushed.Meta.MinTimeNanos, + "maxtime", flushed.Meta.MaxTimeNanos, + "head-flush-duration", time.Since(th).String(), + ) + return flushed, nil +} + +type datasetKey struct { + tenant string + service string +} + +func (k datasetKey) compare(x datasetKey) int { + if k.tenant != x.tenant { + return strings.Compare(k.tenant, x.tenant) + } + return strings.Compare(k.service, x.service) +} + +type dataset struct { + key datasetKey + sw *segmentsWriter + once sync.Once + head *memdb.Head +} + +func newDataset(k datasetKey, sw *segmentsWriter) *dataset { return &dataset{key: k, sw: sw} } + +func (d *dataset) initHead() *memdb.Head { + d.once.Do(func() { + d.head = memdb.NewHead(d.sw.headMetrics) + }) + return d.head +} + +type datasetFlush struct { + dataset *dataset + flushed *memdb.FlushedHead + done chan struct{} +} + +type segment struct { + ulid ulid.ULID + shard shardKey + sshard string + inFlightProfiles sync.WaitGroup + + datasetsLock sync.Mutex + datasets map[datasetKey]*dataset + + logger log.Logger + sw *segmentsWriter + + // TODO(kolesnikovae): Revisit. + doneChan chan struct{} + flushErr error + flushErrMutex sync.Mutex + + debuginfo struct { + movedHeads int + waitInflight time.Duration + flushHeadsDuration time.Duration + flushBlockDuration time.Duration + storeMetaDuration time.Duration + tenantIndexes int + tenantIndexBytes int64 + } + + // TODO(kolesnikovae): Naming. + sh *shard +} + +type segmentIngest interface { + ingest(tenantID string, p *profilev1.Profile, id uuid.UUID, labels []*typesv1.LabelPair, annotations []*typesv1.ProfileAnnotation) +} + +type segmentWaitFlushed interface { + waitFlushed(ctx context.Context) error +} + +func (s *segment) waitFlushed(ctx context.Context) error { + select { + case <-ctx.Done(): + return fmt.Errorf("waitFlushed: %s %w", s.ulid.String(), ctx.Err()) + case <-s.doneChan: + s.flushErrMutex.Lock() + res := s.flushErr + s.flushErrMutex.Unlock() + return res + } +} + +func (s *segment) ingest(tenantID string, p *profilev1.Profile, id uuid.UUID, labels []*typesv1.LabelPair, annotations []*typesv1.ProfileAnnotation) { + // TODO(kolesnikovae): Refactor: profile split should be moved inside the + // dataset.Ingest: we want to do it together with / instead of creation + // of the internal representation (InMemoryProfile). + // symbols.WriteProfileSymbols should be replaced with something more + // suitable (see comment) – we want to avoid allocating intermediate + // objects that are used only temporarily. + // Many sample series refer to same symbols, so we can avoid extra + // processing and index symbols just once: at this point we know that + // all samples are to be stored, and all the referred symbols need to + // be indexed. This will require quite a bit of refactoring, but it's + // worth it. + serviceName := model.Labels(labels).Get(model.LabelNameServiceName) + ds := s.datasetForIngest(datasetKey{tenant: tenantID, service: serviceName}) + appender := &sampleAppender{dataset: ds.initHead(), profile: p, id: id, annotations: annotations} + // Relabeling rules cannot be applied here: it should be done before the + // ingestion, in distributors. Otherwise, it may change the distribution + // key, including the "service_name" label, which we use to determine the + // profile target dataset. + // TODO: Replace with pprof.GroupSamples + _ = pprofsplit.VisitSampleSeries(p, labels, nil, appender) + s.sw.metrics.segmentIngestBytes.WithLabelValues(s.sshard, tenantID).Observe(float64(p.SizeVT())) +} + +type sampleAppender struct { + id uuid.UUID + dataset *memdb.Head + profile *profilev1.Profile + exporter *pprofmodel.SampleExporter + annotations []*typesv1.ProfileAnnotation +} + +func (v *sampleAppender) VisitProfile(labels model.Labels) { + v.dataset.Ingest(v.profile, v.id, labels, v.annotations) +} + +func (v *sampleAppender) VisitSampleSeries(labels model.Labels, samples []*profilev1.Sample) { + if v.exporter == nil { + v.exporter = pprofmodel.NewSampleExporter(v.profile) + } + var n profilev1.Profile + v.exporter.ExportSamples(&n, samples) + v.dataset.Ingest(&n, v.id, labels, v.annotations) +} + +func (v *sampleAppender) ValidateLabels(labels model.Labels) (model.Labels, error) { + return labels, nil +} + +func (v *sampleAppender) Discarded(_, _ int) {} + +func (s *segment) datasetForIngest(k datasetKey) *dataset { + s.datasetsLock.Lock() + ds, ok := s.datasets[k] + if !ok { + ds = newDataset(k, s.sw) + s.datasets[k] = ds + } + s.datasetsLock.Unlock() + return ds +} + +func (sw *segmentsWriter) uploadBlock(ctx context.Context, blockData []byte, meta *metastorev1.BlockMeta, s *segment) error { + uploadStart := time.Now() + var err error + defer func() { + sw.metrics.segmentUploadDuration. + WithLabelValues(statusLabelValue(err)). + Observe(time.Since(uploadStart).Seconds()) + }() + + path := block.ObjectPath(meta) + sw.metrics.segmentSizeBytes. + WithLabelValues(s.sshard). + Observe(float64(len(blockData))) + + if sw.config.UploadTimeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, sw.config.UploadTimeout) + defer cancel() + } + + // To mitigate tail latency issues, we use a hedged upload strategy: + // if the request is not completed within a certain time, we trigger + // a second upload attempt. Upload errors are retried explicitly and + // are included into the call duration. + hedgedUpload := retry.Hedged[any]{ + Trigger: time.After(sw.config.UploadHedgeAfter), + Call: func(ctx context.Context, hedge bool) (any, error) { + retryConfig := backoff.Config{ + MinBackoff: sw.config.UploadMinBackoff, + MaxBackoff: sw.config.UploadMaxBackoff, + MaxRetries: sw.config.UploadMaxRetries, + } + var attemptErr error + if hedge { + if limitErr := sw.hedgedUploadLimiter.Wait(ctx); limitErr != nil { + return nil, limitErr + } + // Hedged requests are not retried. + retryConfig.MaxRetries = 0 + attemptStart := time.Now() + defer func() { + sw.metrics.segmentHedgedUploadDuration. + WithLabelValues(statusLabelValue(attemptErr)). + Observe(time.Since(attemptStart).Seconds()) + }() + } + // Retry on all errors. + retries := backoff.New(ctx, retryConfig) + for retries.Ongoing() { + if attemptErr = sw.bucket.Upload(ctx, path, bytes.NewReader(blockData)); attemptErr == nil { + break + } + retries.Wait() + } + return nil, attemptErr + }, + } + + if _, err = hedgedUpload.Do(ctx); err != nil { + return err + } + + level.Debug(sw.logger).Log("msg", "uploaded block", "path", path, "upload_duration", time.Since(uploadStart)) + return nil +} + +func (sw *segmentsWriter) storeMetadata(ctx context.Context, meta *metastorev1.BlockMeta, s *segment) error { + start := time.Now() + var err error + defer func() { + sw.metrics.storeMetadataDuration. + WithLabelValues(statusLabelValue(err)). + Observe(time.Since(start).Seconds()) + s.debuginfo.storeMetaDuration = time.Since(start) + }() + + mdCtx := ctx + if sw.config.MetadataUpdateTimeout > 0 { + var cancel context.CancelFunc + mdCtx, cancel = context.WithTimeout(mdCtx, sw.config.MetadataUpdateTimeout) + defer cancel() + } + + if _, err = sw.metastore.AddBlock(mdCtx, &metastorev1.AddBlockRequest{Block: meta}); err == nil { + return nil + } + + level.Error(s.logger).Log("msg", "failed to store meta in metastore", "err", err) + if !sw.config.MetadataDLQEnabled { + return err + } + + defer func() { + sw.metrics.storeMetadataDLQ.WithLabelValues(statusLabelValue(err)).Inc() + }() + + if err = s.sw.storeMetadataDLQ(ctx, meta); err == nil { + level.Debug(s.logger).Log("msg", "successfully wrote block metadata to DLQ", "block_id", meta.Id) + return nil + } + + level.Error(s.logger).Log("msg", "metastore fallback failed", "err", err) + return err +} + +func (sw *segmentsWriter) storeMetadataDLQ(ctx context.Context, meta *metastorev1.BlockMeta) error { + metadataBytes, err := meta.MarshalVT() + if err != nil { + return err + } + return sw.bucket.Upload(ctx, block.MetadataDLQObjectPath(meta), bytes.NewReader(metadataBytes)) +} + +type workerPool struct { + workers sync.WaitGroup + jobs chan func() +} + +func (p *workerPool) run(n int) { + if p.jobs != nil { + return + } + p.jobs = make(chan func()) + p.workers.Add(n) + for i := 0; i < n; i++ { + go func() { + defer p.workers.Done() + for job := range p.jobs { + job() + } + }() + } +} + +// do must not be called after stop. +func (p *workerPool) do(job func()) { + p.jobs <- job +} + +func (p *workerPool) stop() { + close(p.jobs) + p.workers.Wait() +} diff --git a/pkg/segmentwriter/segment_metrics.go b/pkg/segmentwriter/segment_metrics.go new file mode 100644 index 0000000000..b1d5edd7ca --- /dev/null +++ b/pkg/segmentwriter/segment_metrics.go @@ -0,0 +1,191 @@ +package segmentwriter + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +type segmentMetrics struct { + segmentIngestBytes *prometheus.HistogramVec + segmentSizeBytes *prometheus.HistogramVec + headSizeBytes *prometheus.HistogramVec + tenantIndexBytes *prometheus.HistogramVec + segmentFlushWaitDuration *prometheus.HistogramVec + segmentFlushTimeouts *prometheus.CounterVec + storeMetadataDuration *prometheus.HistogramVec + storeMetadataDLQ *prometheus.CounterVec + segmentUploadDuration *prometheus.HistogramVec + segmentHedgedUploadDuration *prometheus.HistogramVec + flushSegmentDuration *prometheus.HistogramVec + flushHeadsDuration *prometheus.HistogramVec + flushServiceHeadDuration *prometheus.HistogramVec + flushServiceHeadError *prometheus.CounterVec +} + +var ( + networkTimingBuckets = prometheus.ExponentialBucketsRange(0.005, 4, 20) + dataTimingBuckets = prometheus.ExponentialBucketsRange(0.001, 1, 20) + segmentFlushWaitBuckets = []float64{.1, .2, .3, .4, .5, .6, .7, .8, .9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2} +) + +func newSegmentMetrics(reg prometheus.Registerer) *segmentMetrics { + // TODO(kolesnikovae): + // - Use native histograms for all metrics + // - Remove unnecessary labels (e.g. shard) + // - Remove/merge/replace metrics + // - Rename to pyroscope_segment_writer_* + // - Add Help. + m := &segmentMetrics{ + segmentIngestBytes: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "segment_writer", + Name: "segment_ingest_bytes", + Buckets: prometheus.ExponentialBucketsRange(10*1024, 15*1024*1024, 20), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, + []string{"shard", "tenant"}), + segmentSizeBytes: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "segment_writer", + Name: "segment_size_bytes", + Buckets: prometheus.ExponentialBucketsRange(100*1024, 100*1024*1024, 20), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, + []string{"shard"}), + + segmentUploadDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "segment_writer", + Name: "upload_duration_seconds", + Help: "Duration of segment upload requests.", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"status"}), + + segmentHedgedUploadDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "segment_writer", + Name: "hedged_upload_duration_seconds", + Help: "Duration of hedged segment upload requests.", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"status"}), + + storeMetadataDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Subsystem: "segment_writer", + Name: "store_metadata_duration_seconds", + Help: "Duration of store metadata requests.", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"status"}), + + storeMetadataDLQ: prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "pyroscope", + Subsystem: "segment_writer", + Name: "store_metadata_dlq", + Help: "Number of store metadata entries that were sent to the DLQ.", + }, []string{"status"}), + + segmentFlushWaitDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "segment_ingester_wait_duration_seconds", + Buckets: segmentFlushWaitBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"tenant"}), + segmentFlushTimeouts: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Name: "segment_ingester_wait_timeouts", + }, []string{"tenant"}), + flushHeadsDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "segment_flush_heads_duration_seconds", + Buckets: dataTimingBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"shard"}), + flushServiceHeadDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "segment_flush_service_head_duration_seconds", + Buckets: dataTimingBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"shard", "tenant"}), + flushSegmentDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "segment_flush_segment_duration_seconds", + Buckets: networkTimingBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"shard"}), + + flushServiceHeadError: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Name: "segment_flush_service_head_errors", + }, []string{"shard", "tenant"}), + headSizeBytes: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "segment_head_size_bytes", + Buckets: prometheus.ExponentialBucketsRange(10*1024, 100*1024*1024, 30), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"shard", "tenant"}), + tenantIndexBytes: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "pyroscope", + Name: "segment_tenant_index_bytes", + Help: "Size of the per-tenant dataset index emitted into a flushed segment block.", + Buckets: prometheus.ExponentialBucketsRange(1024, 100*1024*1024, 20), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 32, + NativeHistogramMinResetDuration: time.Minute * 15, + }, []string{"shard", "tenant"}), + } + + if reg != nil { + reg.MustRegister(m.segmentIngestBytes) + reg.MustRegister(m.segmentSizeBytes) + reg.MustRegister(m.storeMetadataDuration) + reg.MustRegister(m.segmentFlushWaitDuration) + reg.MustRegister(m.segmentFlushTimeouts) + reg.MustRegister(m.storeMetadataDLQ) + reg.MustRegister(m.segmentUploadDuration) + reg.MustRegister(m.segmentHedgedUploadDuration) + reg.MustRegister(m.flushHeadsDuration) + reg.MustRegister(m.flushServiceHeadDuration) + reg.MustRegister(m.flushServiceHeadError) + reg.MustRegister(m.flushSegmentDuration) + reg.MustRegister(m.headSizeBytes) + reg.MustRegister(m.tenantIndexBytes) + } + return m +} + +func statusLabelValue(err error) string { + if err == nil { + return "success" + } + return "error" +} diff --git a/pkg/segmentwriter/segment_test.go b/pkg/segmentwriter/segment_test.go new file mode 100644 index 0000000000..a65ad271a4 --- /dev/null +++ b/pkg/segmentwriter/segment_test.go @@ -0,0 +1,1219 @@ +package segmentwriter + +import ( + "bytes" + "context" + "errors" + "flag" + "fmt" + "io" + "math/rand" + "path/filepath" + "slices" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + gprofile "github.com/google/pprof/profile" + "github.com/grafana/dskit/flagext" + prommodel "github.com/prometheus/common/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/thanos-io/objstore" + "golang.org/x/time/rate" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + ingesterv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1/ingesterv1connect" + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/block" + "github.com/grafana/pyroscope/v2/pkg/block/metadata" + "github.com/grafana/pyroscope/v2/pkg/metastore" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/dlq" + metastoretest "github.com/grafana/pyroscope/v2/pkg/metastore/test" + "github.com/grafana/pyroscope/v2/pkg/model" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/memory" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/bench" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + testutil3 "github.com/grafana/pyroscope/v2/pkg/phlaredb/block/testutil" + tsdbindex "github.com/grafana/pyroscope/v2/pkg/phlaredb/tsdb/index" + pprofth "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb" + memdbtest "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb/testutil" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockdlq" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockmetastorev1" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func TestSegmentIngest(t *testing.T) { + td := [][]inputChunk{ + staticTestData(), + testDataGenerator{ + seed: 239, + chunks: 3, + profiles: 256, + shards: 4, + tenants: 3, + services: 5, + }.generate(), + //testDataGenerator{ + // seed: time.Now().UnixNano(), + // chunks: 3, + // profiles: 4096, + // shards: 8, + // tenants: 12, + // services: 16, + //}.generate(), + } + for i, chunks := range td { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + t.Run("ingestWithMetastoreAvailable", func(t *testing.T) { + ingestWithMetastoreAvailable(t, chunks) + }) + t.Run("ingestWithDLQ", func(t *testing.T) { + ingestWithDLQ(t, chunks) + }) + }) + } +} + +func ingestWithMetastoreAvailable(t *testing.T, chunks []inputChunk) { + sw := newTestSegmentWriter(t, defaultTestConfig()) + defer sw.stop() + blocks := make(chan *metastorev1.BlockMeta, 128) + + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + blocks <- args.Get(1).(*metastorev1.AddBlockRequest).Block + }).Return(new(metastorev1.AddBlockResponse), nil) + for _, chunk := range chunks { + chunkBlocks := make([]*metastorev1.BlockMeta, 0, len(chunk)) + waiterSet := sw.ingestChunk(t, chunk, false) + for range waiterSet { + meta := <-blocks + chunkBlocks = append(chunkBlocks, meta) + } + inputs := groupInputs(t, chunk) + clients := sw.createBlocksFromMetas(chunkBlocks) + sw.queryInputs(clients, inputs) + } +} + +func ingestWithDLQ(t *testing.T, chunks []inputChunk) { + sw := newTestSegmentWriter(t, defaultTestConfig()) + defer sw.stop() + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Return(nil, fmt.Errorf("metastore unavailable")) + ingestedChunks := make([]inputChunk, 0, len(chunks)) + for chunkIndex, chunk := range chunks { + t.Logf("ingesting chunk %d", chunkIndex) + _ = sw.ingestChunk(t, chunk, false) + ingestedChunks = append(ingestedChunks, chunk) + allBlocks := sw.getMetadataDLQ() + clients := sw.createBlocksFromMetas(allBlocks) + inputs := groupInputs(t, ingestedChunks...) + t.Logf("querying chunk %d", chunkIndex) + sw.queryInputs(clients, inputs) + } +} + +func TestIngestWait(t *testing.T) { + sw := newTestSegmentWriter(t, defaultTestConfig()) + + defer sw.stop() + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + time.Sleep(1 * time.Second) + }).Return(new(metastorev1.AddBlockResponse), nil) + + t1 := time.Now() + awaiter := sw.ingest(0, func(head segmentIngest) { + p := cpuProfile(42, 480, "svc1", "foo", "bar") + head.ingest("t1", p.Profile, p.UUID, p.Labels, p.Annotations) + }) + err := awaiter.waitFlushed(context.Background()) + require.NoError(t, err) + since := time.Since(t1) + require.True(t, since > 1*time.Second) +} + +func TestBusyIngestLoop(t *testing.T) { + + sw := newTestSegmentWriter(t, defaultTestConfig()) + defer sw.stop() + + writeCtx, writeCancel := context.WithCancel(context.Background()) + readCtx, readCancel := context.WithCancel(context.Background()) + metaChan := make(chan *metastorev1.BlockMeta) + + var cnt atomic.Int32 + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + metaChan <- args.Get(1).(*metastorev1.AddBlockRequest).Block + if cnt.Add(1) == 3 { + writeCancel() + } + }).Return(new(metastorev1.AddBlockResponse), nil) + metas := make([]*metastorev1.BlockMeta, 0) + readG := sync.WaitGroup{} + readG.Add(1) + go func() { + defer readG.Done() + for { + select { + case <-readCtx.Done(): + return + case meta := <-metaChan: + metas = append(metas, meta) + } + } + }() + writeG := sync.WaitGroup{} + allProfiles := make([]*pprofth.ProfileBuilder, 0) + m := new(sync.Mutex) + nWorkers := 5 + for i := 0; i < nWorkers; i++ { + workerno := i + writeG.Add(1) + go func() { + defer writeG.Done() + awaiters := make([]segmentWaitFlushed, 0) + profiles := make([]*pprofth.ProfileBuilder, 0) + defer func() { + require.NotEmpty(t, profiles) + require.NotEmpty(t, awaiters) + for _, awaiter := range awaiters { + err := awaiter.waitFlushed(context.Background()) + require.NoError(t, err) + } + m.Lock() + allProfiles = append(allProfiles, profiles...) + m.Unlock() + }() + for { + select { + case <-writeCtx.Done(): + return + default: + ts := workerno*1000000000 + len(profiles) + awaiter := sw.ingest(1, func(head segmentIngest) { + p := cpuProfile(42, ts, "svc1", "foo", "bar") + head.ingest("t1", p.CloneVT(), p.UUID, p.Labels, p.Annotations) + profiles = append(profiles, p) + }) + awaiters = append(awaiters, awaiter) + } + } + }() + } + writeG.Wait() + + readCancel() + readG.Wait() + assert.True(t, len(metas) >= 3) + + chunk := make(inputChunk, 0) + for _, p := range allProfiles { + chunk = append(chunk, input{shard: 1, tenant: "t1", profile: p}) + } + inputs := groupInputs(t, chunk) + clients := sw.createBlocksFromMetas(metas) + sw.queryInputs(clients, inputs) +} + +func TestDLQFail(t *testing.T) { + l := test.NewTestingLogger(t) + bucket := mockobjstore.NewMockBucket(t) + bucket.On("Upload", mock.Anything, mock.MatchedBy(func(name string) bool { + return isSegmentPath(name) + }), mock.Anything).Return(nil) + bucket.On("Upload", mock.Anything, mock.MatchedBy(func(name string) bool { + return isDLQPath(name) + }), mock.Anything).Return(fmt.Errorf("mock upload DLQ error")) + client := mockmetastorev1.NewMockIndexServiceClient(t) + client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Return(nil, fmt.Errorf("mock add block error")) + + res := newSegmentWriter( + l, + newSegmentMetrics(nil), + memdb.NewHeadMetricsWithPrefix(nil, ""), + defaultTestConfig(), + validation.MockDefaultOverrides(), + bucket, + client, + ) + defer res.stop() + ts := 420 + ing := func(head segmentIngest) { + ts += 420 + p := cpuProfile(42, ts, "svc1", "foo", "bar") + head.ingest("t1", p.Profile, p.UUID, p.Labels, p.Annotations) + } + + awaiter1 := res.ingest(0, ing) + awaiter2 := res.ingest(0, ing) + + err1 := awaiter1.waitFlushed(context.Background()) + require.Error(t, err1) + + err2 := awaiter1.waitFlushed(context.Background()) + require.Error(t, err2) + + err3 := awaiter2.waitFlushed(context.Background()) + require.Error(t, err3) + + require.Equal(t, err1, err2) + require.Equal(t, err1, err3) +} + +func TestDatasetMinMaxTime(t *testing.T) { + l := test.NewTestingLogger(t) + bucket := memory.NewInMemBucket() + metas := make(chan *metastorev1.BlockMeta) + client := mockmetastorev1.NewMockIndexServiceClient(t) + client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + meta := args.Get(1).(*metastorev1.AddBlockRequest).Block + metas <- meta + }).Return(new(metastorev1.AddBlockResponse), nil) + res := newSegmentWriter( + l, + newSegmentMetrics(nil), + memdb.NewHeadMetricsWithPrefix(nil, ""), + defaultTestConfig(), + validation.MockDefaultOverrides(), + bucket, + client, + ) + data := []input{ + {shard: 1, tenant: "tb", profile: cpuProfile(42, 239, "svc1", "foo", "bar")}, + {shard: 1, tenant: "tb", profile: cpuProfile(13, 420, "svc1", "qwe", "foo", "bar")}, + {shard: 1, tenant: "tb", profile: cpuProfile(13, 420, "svc2", "qwe", "foo", "bar")}, + {shard: 1, tenant: "tb", profile: cpuProfile(13, 421, "svc2", "qwe", "foo", "bar")}, + {shard: 1, tenant: "ta", profile: cpuProfile(13, 10, "svc1", "vbn", "foo", "bar")}, + {shard: 1, tenant: "ta", profile: cpuProfile(13, 1337, "svc1", "vbn", "foo", "bar")}, + } + _ = res.ingest(1, func(head segmentIngest) { + for _, p := range data { + head.ingest(p.tenant, p.profile.Profile, p.profile.UUID, p.profile.Labels, p.profile.Annotations) + } + }) + defer res.stop() + + block := <-metas + + // Datasets in the block: real datasets are sorted by tenant+service; a + // per-tenant dataset index pseudo-dataset is appended after the last + // real dataset of each tenant. + expected := [][2]int{ + {10, 1337}, // ta/svc1 + {10, 1337}, // ta dataset index + {239, 420}, // tb/svc1 + {420, 421}, // tb/svc2 + {239, 421}, // tb dataset index + } + + require.Equal(t, len(expected), len(block.Datasets)) + for i, ds := range block.Datasets { + assert.Equalf(t, expected[i][0], int(ds.MinTime), "idx %d", i) + assert.Equalf(t, expected[i][1], int(ds.MaxTime), "idx %d", i) + } + assert.Equal(t, int64(10), block.MinTime) + assert.Equal(t, int64(1337), block.MaxTime) +} + +// TestSegmentTenantDatasetIndexes flushes a multi-tenant segment and +// inspects the per-tenant Format1 dataset_index pseudo-datasets in the +// resulting block. For each tenant it verifies that the dataset_index +// encodes one entry per real dataset of the tenant, and that each +// entry's chunk SeriesIndex is the global position of the real dataset +// within meta.Datasets (this is what the query backend uses to resolve +// datasets from a Format1 lookup). +func TestSegmentTenantDatasetIndexes(t *testing.T) { + l := test.NewTestingLogger(t) + bucket := memory.NewInMemBucket() + metas := make(chan *metastorev1.BlockMeta, 1) + client := mockmetastorev1.NewMockIndexServiceClient(t) + client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + metas <- args.Get(1).(*metastorev1.AddBlockRequest).Block + }).Return(new(metastorev1.AddBlockResponse), nil) + sw := newSegmentWriter( + l, + newSegmentMetrics(nil), + memdb.NewHeadMetricsWithPrefix(nil, ""), + defaultTestConfig(), + validation.MockDefaultOverrides(), + bucket, + client, + ) + defer sw.stop() + + // Two tenants on the same shard so they share the segment block. + data := []input{ + {shard: 1, tenant: "ta", profile: cpuProfile(13, 100, "svc1", "foo", "bar")}, + {shard: 1, tenant: "ta", profile: cpuProfile(13, 110, "svc2", "foo", "bar")}, + {shard: 1, tenant: "tb", profile: cpuProfile(13, 120, "svc1", "foo", "bar")}, + } + _ = sw.ingest(1, func(head segmentIngest) { + for _, p := range data { + head.ingest(p.tenant, p.profile.Profile, p.profile.UUID, p.profile.Labels, p.profile.Annotations) + } + }) + + meta := <-metas + + // Group real datasets by tenant; record their global positions in + // meta.Datasets and find each tenant's Format1 pseudo-dataset. + realByTenant := map[string][]int{} + indexByTenant := map[string]*metastorev1.Dataset{} + for i, ds := range meta.Datasets { + tenantName := meta.StringTable[ds.Tenant] + switch block.DatasetFormat(ds.Format) { + case block.DatasetFormat0: + realByTenant[tenantName] = append(realByTenant[tenantName], i) + case block.DatasetFormat1: + require.Nil(t, indexByTenant[tenantName], "more than one Format1 dataset for tenant %s", tenantName) + indexByTenant[tenantName] = ds + } + } + require.Equal(t, []int{0, 1}, realByTenant["ta"], "expected ta to have two real datasets") + require.Len(t, realByTenant["tb"], 1, "expected tb to have one real dataset") + require.Len(t, indexByTenant, 2, "expected one Format1 dataset per tenant") + + // Open the block and inspect each tenant's dataset_index. + obj := block.NewObject(phlareobj.NewBucket(bucket), meta) + t.Cleanup(func() { _ = obj.Close() }) + require.NoError(t, obj.Open(context.Background())) + + for tenantName, indexDS := range indexByTenant { + t.Run(tenantName, func(t *testing.T) { + ds := block.NewDataset(indexDS, obj) + t.Cleanup(func() { _ = ds.Close() }) + require.NoError(t, ds.Open(context.Background(), block.SectionDatasetIndex)) + + // Walk every series in the index and collect chunk + // SeriesIndex values; they must equal the global + // positions of the tenant's real datasets within + // meta.Datasets. + indexReader := ds.Index() + n, v := tsdbindex.AllPostingsKey() + postings, err := indexReader.Postings(n, nil, v) + require.NoError(t, err) + var seriesIndices []int + chunks := make([]tsdbindex.ChunkMeta, 1) + for postings.Next() { + _, err := indexReader.Series(postings.At(), nil, &chunks) + require.NoError(t, err) + require.Len(t, chunks, 1, "each series in the dataset_index should map to exactly one chunk") + seriesIndices = append(seriesIndices, int(chunks[0].SeriesIndex)) + } + require.NoError(t, postings.Err()) + slices.Sort(seriesIndices) + assert.Equal(t, realByTenant[tenantName], seriesIndices, + "dataset_index series must point to the tenant's real datasets via global positions") + }) + } +} + +func TestQueryMultipleSeriesSingleTenant(t *testing.T) { + metas := make(chan *metastorev1.BlockMeta, 1) + + sw := newTestSegmentWriter(t, defaultTestConfig()) + defer sw.stop() + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + metas <- args.Get(1).(*metastorev1.AddBlockRequest).Block + }).Return(new(metastorev1.AddBlockResponse), nil) + + data := inputChunk([]input{ + {shard: 1, tenant: "tb", profile: cpuProfile(42, 239, "svc1", "kek", "foo", "bar")}, + {shard: 1, tenant: "tb", profile: cpuProfile(13, 420, "svc1", "qwe1", "foo", "bar")}, + {shard: 1, tenant: "tb", profile: cpuProfile(17, 420, "svc2", "qwe3", "foo", "bar")}, + {shard: 1, tenant: "tb", profile: cpuProfile(13, 421, "svc2", "qwe", "foo", "bar")}, + {shard: 1, tenant: "ta", profile: cpuProfile(13, 10, "svc1", "vbn", "foo", "bar")}, + {shard: 1, tenant: "ta", profile: cpuProfile(13, 1337, "svc1", "vbn", "foo", "bar")}, + }) + sw.ingestChunk(t, data, false) + block := <-metas + + clients := sw.createBlocksFromMetas([]*metastorev1.BlockMeta{block}) + defer func() { + for _, tc := range clients { + tc.f() + } + }() + + client := clients["tb"] + actualMerged := sw.query(client, &ingesterv1.SelectProfilesRequest{ + LabelSelector: "{service_name=~\"svc[12]\"}", + Type: mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds"), + Start: 239, + End: 420, + }) + expectedMerged := mergeProfiles(t, []*profilev1.Profile{ + data[0].profile.Profile, + data[1].profile.Profile, + data[2].profile.Profile, + }) + actualCollapsed := bench.StackCollapseProto(actualMerged, 0, 1) + expectedCollapsed := bench.StackCollapseProto(expectedMerged, 0, 1) + require.Equal(t, expectedCollapsed, actualCollapsed) +} + +func TestDLQRecoveryMock(t *testing.T) { + chunk := inputChunk([]input{ + {shard: 1, tenant: "tb", profile: cpuProfile(42, 239, "svc1", "kek", "foo", "bar")}, + }) + + sw := newTestSegmentWriter(t, defaultTestConfig()) + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Return(nil, fmt.Errorf("mock metastore unavailable")) + + _ = sw.ingestChunk(t, chunk, false) + allBlocks := sw.getMetadataDLQ() + assert.Len(t, allBlocks, 1) + + recoveredMetas := make(chan *metastorev1.BlockMeta, 1) + srv := mockdlq.NewMockMetastore(t) + srv.On("AddRecoveredBlock", mock.Anything, mock.Anything). + Once(). + Run(func(args mock.Arguments) { + meta := args.Get(1).(*metastorev1.AddBlockRequest).Block + recoveredMetas <- meta + }). + Return(&metastorev1.AddBlockResponse{}, nil) + recovery := dlq.NewRecovery(test.NewTestingLogger(t), dlq.Config{ + CheckInterval: 100 * time.Millisecond, + }, srv, sw.bucket, nil) + recovery.Start() + defer recovery.Stop() + + meta := <-recoveredMetas + assert.Equal(t, allBlocks[0].Id, meta.Id) + + clients := sw.createBlocksFromMetas(allBlocks) + inputs := groupInputs(t, chunk) + sw.queryInputs(clients, inputs) +} + +func TestDLQRecovery(t *testing.T) { + const tenant = "tb" + var ts = time.Now().UnixMilli() + chunk := inputChunk([]input{ + {shard: 1, tenant: tenant, profile: cpuProfile(42, int(ts), "svc1", "kek", "foo", "bar")}, + }) + + sw := newTestSegmentWriter(t, defaultTestConfig()) + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Return(nil, fmt.Errorf("mock metastore unavailable")) + + _ = sw.ingestChunk(t, chunk, false) + + cfg := new(metastore.Config) + flagext.DefaultValues(cfg) + cfg.Index.Recovery.CheckInterval = 100 * time.Millisecond + m := metastoretest.NewMetastoreSet(t, cfg, 3, sw.bucket) + defer m.Close() + + queryBlock := func() *metastorev1.BlockMeta { + res, err := m.Client.QueryMetadata(context.Background(), &metastorev1.QueryMetadataRequest{ + TenantId: []string{tenant}, + StartTime: ts - 1, + EndTime: ts + 1, + Query: "{service_name=~\"svc1\"}", + }) + if err != nil { + return nil + } + if len(res.Blocks) == 1 { + return res.Blocks[0] + } + return nil + } + require.Eventually(t, func() bool { + return queryBlock() != nil + }, 10*time.Second, 100*time.Millisecond) + + block := queryBlock() + require.NotNil(t, block) + + clients := sw.createBlocksFromMetas([]*metastorev1.BlockMeta{block}) + inputs := groupInputs(t, chunk) + sw.queryInputs(clients, inputs) +} + +func TestUnsymbolizedLabelIsSet(t *testing.T) { + sw := newTestSegmentWriter(t, defaultTestConfig()) + defer sw.stop() + blocks := make(chan *metastorev1.BlockMeta, 1) + + sw.client.On("AddBlock", mock.Anything, mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + blocks <- args.Get(1).(*metastorev1.AddBlockRequest).Block + }).Return(new(metastorev1.AddBlockResponse), nil) + + p := pprofth.NewProfileBuilder(time.Now().UnixNano()). + CPUProfile(). + WithLabels(model.LabelNameServiceName, "svc1") + + p.Mapping = []*profilev1.Mapping{ + {Id: 1, HasFunctions: false}, + } + + loc := &profilev1.Location{ + Id: 1, + MappingId: 1, + Line: nil, + } + p.Location = append(p.Location, loc) + + keyIdx := int64(len(p.StringTable)) + p.StringTable = append(p.StringTable, "foo") + valIdx := int64(len(p.StringTable)) + p.StringTable = append(p.StringTable, "bar") + + sample1 := &profilev1.Sample{ + LocationId: []uint64{1}, + Value: []int64{1}, + Label: []*profilev1.Label{ + {Key: keyIdx, Str: valIdx}, + }, + } + p.Sample = append(p.Sample, sample1) + + sample2 := &profilev1.Sample{ + LocationId: []uint64{1}, + Value: []int64{2}, + Label: nil, + } + p.Sample = append(p.Sample, sample2) + + chunk := inputChunk{ + {shard: 1, tenant: "t1", profile: p}, + } + _ = sw.ingestChunk(t, chunk, false) + block := <-blocks + + require.True(t, hasUnsymbolizedLabel(t, block)) +} + +type sw struct { + *segmentsWriter + bucket *memory.InMemBucket + client *mockmetastorev1.MockIndexServiceClient + t *testing.T + queryNo int +} + +func newTestSegmentWriter(t *testing.T, cfg Config) sw { + l := test.NewTestingLogger(t) + bucket := memory.NewInMemBucket() + client := mockmetastorev1.NewMockIndexServiceClient(t) + res := newSegmentWriter( + l, + newSegmentMetrics(nil), + memdb.NewHeadMetricsWithPrefix(nil, ""), + cfg, + validation.MockDefaultOverrides(), + bucket, + client, + ) + return sw{ + t: t, + segmentsWriter: res, + bucket: bucket, + client: client, + } +} + +func defaultTestConfig() Config { + return Config{ + SegmentDuration: 100 * time.Millisecond, + UploadTimeout: time.Second, + MetadataUpdateTimeout: time.Second, + MetadataDLQEnabled: true, + } +} + +func (sw *sw) createBlocksFromMetas(blocks []*metastorev1.BlockMeta) tenantClients { + dir := sw.t.TempDir() + for _, meta := range blocks { + blobReader, err := sw.bucket.Get(context.Background(), block.ObjectPath(meta)) + require.NoError(sw.t, err) + blob, err := io.ReadAll(blobReader) + require.NoError(sw.t, err) + + for _, ds := range meta.Datasets { + if block.DatasetFormat(ds.Format) != block.DatasetFormat0 { + // Skip pseudo-datasets such as the per-tenant dataset index. + continue + } + tenant := meta.StringTable[ds.Tenant] + profiles := blob[ds.TableOfContents[0]:ds.TableOfContents[1]] + tsdb := blob[ds.TableOfContents[1]:ds.TableOfContents[2]] + symbols := blob[ds.TableOfContents[2] : ds.TableOfContents[0]+ds.Size] + testutil3.CreateBlockFromMemory(sw.t, + filepath.Join(dir, tenant), + prommodel.TimeFromUnixNano(ds.MinTime*1e6), //todo do not use 1e6, add comments to minTime clarifying the unit + prommodel.TimeFromUnixNano(ds.MaxTime*1e6), + profiles, + tsdb, + symbols, + ) + } + } + + res := make(tenantClients) + for _, meta := range blocks { + for _, ds := range meta.Datasets { + if block.DatasetFormat(ds.Format) != block.DatasetFormat0 { + continue + } + tenant := meta.StringTable[ds.Tenant] + if _, ok := res[tenant]; !ok { + // todo consider not using BlockQuerier for tests + blockBucket, err := filesystem.NewBucket(filepath.Join(dir, tenant)) + require.NoError(sw.t, err) + + blockQuerier := phlaredb.NewBlockQuerier(context.Background(), blockBucket) + err = blockQuerier.Sync(context.Background()) + require.NoError(sw.t, err) + + queriers := blockQuerier.Queriers() + err = queriers.Open(context.Background()) + require.NoError(sw.t, err) + + q, f := memdbtest.IngesterClientForTest(sw.t, queriers) + + res[tenant] = tenantClient{ + tenant: tenant, + client: q, + f: f, + } + } + } + } + + return res +} + +func (sw *sw) queryInputs(clients tenantClients, inputs groupedInputs) { + sw.queryNo++ + t := sw.t + defer func() { + for _, tc := range clients { + tc.f() + } + }() + + for tenant, tenantInputs := range inputs { + tc, ok := clients[tenant] + require.True(sw.t, ok) + for svc, metricNameInputs := range tenantInputs { + for metricName, profiles := range metricNameInputs { + start, end := getStartEndTime(profiles) + ps := make([]*profilev1.Profile, 0, len(profiles)) + for _, p := range profiles { + ps = append(ps, p.Profile) + } + expectedMerged := mergeProfiles(sw.t, ps) + + sts := sampleTypesFromMetricName(sw.t, metricName) + for sti, st := range sts { + q := &ingesterv1.SelectProfilesRequest{ + LabelSelector: fmt.Sprintf("{%s=\"%s\"}", model.LabelNameServiceName, svc), + Type: st, + Start: start, + End: end, + } + actualMerged := sw.query(tc, q) + + actualCollapsed := bench.StackCollapseProto(actualMerged, 0, 1) + expectedCollapsed := bench.StackCollapseProto(expectedMerged, sti, 1) + require.Equal(t, expectedCollapsed, actualCollapsed) + } + + } + } + } +} + +func (sw *sw) query(tc tenantClient, q *ingesterv1.SelectProfilesRequest) *profilev1.Profile { + t := sw.t + bidi := tc.client.MergeProfilesPprof(context.Background()) + err := bidi.Send(&ingesterv1.MergeProfilesPprofRequest{ + Request: q, + }) + require.NoError(sw.t, err) + + resp, err := bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + require.NotNilf(t, resp.SelectedProfiles, "res %+v", resp) + require.NotEmpty(t, resp.SelectedProfiles.Fingerprints) + require.NotEmpty(t, resp.SelectedProfiles.Profiles) + + nProfiles := len(resp.SelectedProfiles.Profiles) + + bools := make([]bool, nProfiles) + for i := 0; i < nProfiles; i++ { + bools[i] = true + } + require.NoError(t, bidi.Send(&ingesterv1.MergeProfilesPprofRequest{ + Profiles: bools, + })) + + // expect empty resp to signal it is finished + resp, err = bidi.Receive() + require.NoError(t, err) + require.Nil(t, resp.Result) + require.Nil(t, resp.SelectedProfiles) + + resp, err = bidi.Receive() + require.NoError(t, err) + require.NotNil(t, resp.Result) + + actualMerged := &profilev1.Profile{} + err = actualMerged.UnmarshalVT(resp.Result) + require.NoError(t, err) + return actualMerged +} + +// millis +func getStartEndTime(profiles []*pprofth.ProfileBuilder) (int64, int64) { + start := profiles[0].TimeNanos + end := profiles[0].TimeNanos + for _, p := range profiles { + if p.TimeNanos < start { + start = p.TimeNanos + } + if p.TimeNanos > end { + end = p.TimeNanos + } + } + start = start / 1e6 + end = end / 1e6 + end += 1 + return start, end +} + +func (sw *sw) getMetadataDLQ() []*metastorev1.BlockMeta { + objects := sw.bucket.Objects() + dlqFiles := []string{} + for s := range objects { + if isDLQPath(s) { + dlqFiles = append(dlqFiles, s) + } + } + slices.Sort(dlqFiles) + var metas []*metastorev1.BlockMeta + for _, s := range dlqFiles { + var meta = new(metastorev1.BlockMeta) + err := meta.UnmarshalVT(objects[s]) + require.NoError(sw.t, err) + metas = append(metas, meta) + } + return metas +} + +// nolint: unparam +func (sw *sw) ingestChunk(t *testing.T, chunk inputChunk, expectAwaitError bool) map[segmentWaitFlushed]struct{} { + wg := sync.WaitGroup{} + waiterSet := make(map[segmentWaitFlushed]struct{}) + mutex := new(sync.Mutex) + for i := range chunk { + it := chunk[i] + wg.Add(1) + + go func() { + defer wg.Done() + awaiter := sw.ingest(shardKey(it.shard), func(head segmentIngest) { + p := it.profile.CloneVT() // important to not rewrite original profile + head.ingest(it.tenant, p, it.profile.UUID, it.profile.Labels, it.profile.Annotations) + }) + err := awaiter.waitFlushed(context.Background()) + if expectAwaitError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + mutex.Lock() + waiterSet[awaiter] = struct{}{} + mutex.Unlock() + }() + } + wg.Wait() + return waiterSet +} + +type input struct { + shard uint32 + tenant string + profile *pprofth.ProfileBuilder +} + +// tenant -> service -> sample +type groupedInputs map[string]map[string]map[string][]*pprofth.ProfileBuilder + +type inputChunk []input + +type tenantClient struct { + tenant string + client ingesterv1connect.IngesterServiceClient + f func() +} + +// tenant -> block +type tenantClients map[string]tenantClient + +func groupInputs(t *testing.T, chunks ...inputChunk) groupedInputs { + shardToTenantToServiceToSampleType := make(groupedInputs) + for _, chunk := range chunks { + + for _, in := range chunk { + if _, ok := shardToTenantToServiceToSampleType[in.tenant]; !ok { + shardToTenantToServiceToSampleType[in.tenant] = make(map[string]map[string][]*pprofth.ProfileBuilder) + } + svc := "" + for _, lbl := range in.profile.Labels { + if lbl.Name == model.LabelNameServiceName { + svc = lbl.Value + } + } + require.NotEmptyf(t, svc, "service name not found in labels: %v", in.profile.Labels) + if _, ok := shardToTenantToServiceToSampleType[in.tenant][svc]; !ok { + shardToTenantToServiceToSampleType[in.tenant][svc] = make(map[string][]*pprofth.ProfileBuilder) + } + metricname := "" + for _, lbl := range in.profile.Labels { + if lbl.Name == prommodel.MetricNameLabel { + metricname = lbl.Value + } + } + require.NotEmptyf(t, metricname, "metric name not found in labels: %v", in.profile.Labels) + shardToTenantToServiceToSampleType[in.tenant][svc][metricname] = append(shardToTenantToServiceToSampleType[in.tenant][svc][metricname], in.profile) + } + } + + return shardToTenantToServiceToSampleType + +} + +func cpuProfile(samples int, tsMillis int, svc string, stack ...string) *pprofth.ProfileBuilder { + return pprofth.NewProfileBuilder(int64(tsMillis*1e6)). + CPUProfile(). + WithLabels(model.LabelNameServiceName, svc). + WithAnnotations("test annotation"). + ForStacktraceString(stack...). + AddSamples([]int64{int64(samples)}...) +} + +func memProfile(samples int, tsMillis int, svc string, stack ...string) *pprofth.ProfileBuilder { + v := int64(samples) + return pprofth.NewProfileBuilder(int64(tsMillis*1e6)). + MemoryProfile(). + WithLabels(model.LabelNameServiceName, svc). + ForStacktraceString(stack...). + AddSamples([]int64{v, v * 1024, v, v * 1024}...) +} + +func sampleTypesFromMetricName(t *testing.T, name string) []*typesv1.ProfileType { + if strings.Contains(name, "process_cpu") { + return []*typesv1.ProfileType{mustParseProfileSelector(t, "process_cpu:cpu:nanoseconds:cpu:nanoseconds")} + } + if strings.Contains(name, "memory") { + return []*typesv1.ProfileType{ + mustParseProfileSelector(t, "memory:alloc_objects:count:space:bytes"), + mustParseProfileSelector(t, "memory:alloc_space:bytes:space:bytes"), + mustParseProfileSelector(t, "memory:inuse_objects:count:space:bytes"), + mustParseProfileSelector(t, "memory:inuse_space:bytes:space:bytes"), + } + } + require.Failf(t, "unknown metric name: %s", name) + return nil +} + +func mustParseProfileSelector(t testing.TB, selector string) *typesv1.ProfileType { + ps, err := model.ParseProfileTypeSelector(selector) + require.NoError(t, err) + return ps +} + +func mergeProfiles(t *testing.T, profiles []*profilev1.Profile) *profilev1.Profile { + gps := make([]*gprofile.Profile, 0, len(profiles)) + for _, profile := range profiles { + gp := gprofileFromProtoProfile(t, profile) + gps = append(gps, gp) + gp.Compact() + } + merge, err := gprofile.Merge(gps) + require.NoError(t, err) + + r := bytes.NewBuffer(nil) + err = merge.WriteUncompressed(r) + require.NoError(t, err) + + msg := &profilev1.Profile{} + err = msg.UnmarshalVT(r.Bytes()) + require.NoError(t, err) + return msg +} + +func gprofileFromProtoProfile(t *testing.T, profile *profilev1.Profile) *gprofile.Profile { + data, err := profile.MarshalVT() + require.NoError(t, err) + p, err := gprofile.ParseData(data) + require.NoError(t, err) + return p +} + +func staticTestData() []inputChunk { + return []inputChunk{ + { + //todo check why it takes 10ms for each head + {shard: 1, tenant: "t1", profile: cpuProfile(42, 480, "svc1", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: cpuProfile(13, 233, "svc1", "qwe", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: cpuProfile(13, 472, "svc1", "qwe", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: cpuProfile(13, 961, "svc1", "qwe", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: cpuProfile(13, 56, "svc1", "qwe", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: cpuProfile(13, 549, "svc1", "qwe", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: memProfile(13, 146, "svc1", "qwe", "qwe", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: memProfile(43, 866, "svc1", "asd", "zxc")}, + {shard: 1, tenant: "t1", profile: cpuProfile(07, 213, "svc2", "s3", "s2", "s1")}, + {shard: 1, tenant: "t2", profile: cpuProfile(47, 540, "svc2", "s3", "s2", "s1")}, + {shard: 1, tenant: "t2", profile: cpuProfile(77, 499, "svc3", "s3", "s2", "s1")}, + {shard: 2, tenant: "t2", profile: cpuProfile(29, 859, "svc3", "s3", "s2", "s1")}, + {shard: 2, tenant: "t2", profile: memProfile(11, 115, "svc3", "s3", "s2", "s1")}, + {shard: 4, tenant: "t2", profile: memProfile(11, 304, "svc3", "s3", "s2", "s1")}, + }, + { + {shard: 1, tenant: "t1", profile: cpuProfile(05, 914, "svc1", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: cpuProfile(07, 290, "svc1", "qwe", "foo", "bar")}, + {shard: 1, tenant: "t1", profile: cpuProfile(24, 748, "svc2", "s3", "s2", "s1")}, + {shard: 2, tenant: "t3", profile: memProfile(23, 639, "svc3", "s3", "s2", "s1")}, + {shard: 3, tenant: "t3", profile: memProfile(23, 912, "svc3", "s3", "s2", "s1")}, + {shard: 3, tenant: "t3", profile: memProfile(33, 799, "svc3", "s2", "s1")}, + }, + } +} + +type ( + testDataGenerator struct { + seed int64 + chunks int + profiles int + shards int + tenants int + services int + } +) + +func (g testDataGenerator) generate() []inputChunk { + r := rand.New(rand.NewSource(g.seed)) + tg := timestampGenerator{ + m: make(map[int64]struct{}), + r: rand.New(rand.NewSource(r.Int63())), + } + chunks := make([]inputChunk, g.chunks) + + services := make([]string, 0, g.services) + for i := 0; i < g.services; i++ { + services = append(services, fmt.Sprintf("svc%d", i)) + } + tenatns := make([]string, 0, g.tenants) + for i := 0; i < g.tenants; i++ { + tenatns = append(tenatns, fmt.Sprintf("t%d", i)) + } + const nFrames = 16384 + frames := make([]string, 0, nFrames) + for i := 0; i < nFrames; i++ { + frames = append(frames, fmt.Sprintf("frame%d", i)) + } + + for i := range chunks { + chunk := make(inputChunk, 0, g.profiles) + for j := 0; j < g.profiles; j++ { + shard := r.Intn(g.shards) + tenant := tenatns[r.Intn(g.tenants)] + svc := services[r.Intn(g.services)] + stack := make([]string, 0, 3) + for i := 0; i < 3; i++ { + stack = append(stack, frames[r.Intn(nFrames)]) + } + typ := r.Intn(2) + var p *pprofth.ProfileBuilder + nSamples := r.Intn(100) + ts := tg.next() + if typ == 0 { + p = cpuProfile(nSamples+1, ts, svc, stack...) + } else { + p = memProfile(nSamples+1, ts, svc, stack...) + } + chunk = append(chunk, input{shard: uint32(shard), tenant: tenant, profile: p}) + } + chunks[i] = chunk + } + return chunks +} + +type timestampGenerator struct { + m map[int64]struct{} + r *rand.Rand +} + +func (g *timestampGenerator) next() int { + for { + ts := g.r.Int63n(100000000) + if _, ok := g.m[ts]; !ok { + g.m[ts] = struct{}{} + return int(ts) + } + } +} + +func isDLQPath(p string) bool { + fs := strings.Split(p, "/") + return len(fs) == 5 && + fs[0] == block.DirNameDLQ && + fs[2] == block.DirNameAnonTenant && + fs[4] == block.FileNameMetadataObject +} + +func isSegmentPath(p string) bool { + fs := strings.Split(p, "/") + return len(fs) == 5 && + fs[0] == block.DirNameSegment && + fs[2] == block.DirNameAnonTenant && + fs[4] == block.FileNameDataObject +} + +func hasUnsymbolizedLabel(t *testing.T, block *metastorev1.BlockMeta) bool { + t.Helper() + for _, ds := range block.Datasets { + i := 0 + for i < len(ds.Labels) { + n := int(ds.Labels[i]) + i++ + for j := 0; j < n; j++ { + keyIdx := ds.Labels[i] + valIdx := ds.Labels[i+1] + i += 2 + if block.StringTable[keyIdx] == metadata.LabelNameUnsymbolized && block.StringTable[valIdx] == "true" { + return true + } + } + } + } + return false +} + +type mockBucket struct { + *memory.InMemBucket + uploads atomic.Int64 +} + +func (m *mockBucket) Upload(ctx context.Context, _ string, _ io.Reader, _ ...objstore.ObjectUploadOption) error { + m.uploads.Add(1) + <-ctx.Done() + return ctx.Err() +} + +func TestUploadBlock_HedgedUploadLimiter(t *testing.T) { + t.Run("disabled", func(t *testing.T) { + t.Parallel() + + bucket := &mockBucket{InMemBucket: memory.NewInMemBucket()} + logger := test.NewTestingLogger(t) + + var config Config + config.RegisterFlags(flag.NewFlagSet("test", flag.PanicOnError)) + config.UploadTimeout = time.Millisecond * 250 + config.UploadHedgeAfter = time.Millisecond + config.UploadHedgeRateMax = 0 + config.UploadHedgeRateBurst = 0 + config.UploadMaxRetries = 0 + + sw := &segmentsWriter{ + config: config, + logger: logger, + bucket: bucket, + hedgedUploadLimiter: rate.NewLimiter(rate.Limit(config.UploadHedgeRateMax), int(config.UploadHedgeRateBurst)), + metrics: newSegmentMetrics(nil), + } + + err := sw.uploadBlock(context.Background(), nil, new(metastorev1.BlockMeta), new(segment)) + require.ErrorIs(t, err, context.DeadlineExceeded) + require.Equal(t, int64(1), bucket.uploads.Load()) + }) + + t.Run("available", func(t *testing.T) { + t.Parallel() + + bucket := &mockBucket{InMemBucket: memory.NewInMemBucket()} + logger := test.NewTestingLogger(t) + + var config Config + config.RegisterFlags(flag.NewFlagSet("test", flag.PanicOnError)) + config.UploadTimeout = time.Millisecond * 250 + config.UploadHedgeAfter = time.Millisecond + config.UploadHedgeRateMax = 10 + config.UploadHedgeRateBurst = 10 + config.UploadMaxRetries = 0 + + sw := &segmentsWriter{ + config: config, + logger: logger, + bucket: bucket, + hedgedUploadLimiter: rate.NewLimiter(rate.Limit(config.UploadHedgeRateMax), int(config.UploadHedgeRateBurst)), + metrics: newSegmentMetrics(nil), + } + + // To avoid flakiness: there are no guarantees that the + // hedged request is triggered before the upload timeout + // expiration. + hedgedRequestTriggered := func() bool { + bucket.uploads.Store(0) + err := sw.uploadBlock(context.Background(), nil, new(metastorev1.BlockMeta), new(segment)) + return errors.Is(err, context.DeadlineExceeded) && int64(2) == bucket.uploads.Load() + } + + require.Eventually(t, hedgedRequestTriggered, time.Second*10, time.Millisecond*50) + }) + + t.Run("exhausted", func(t *testing.T) { + t.Parallel() + + bucket := &mockBucket{InMemBucket: memory.NewInMemBucket()} + logger := test.NewTestingLogger(t) + + var config Config + config.RegisterFlags(flag.NewFlagSet("test", flag.PanicOnError)) + config.UploadTimeout = time.Millisecond * 250 + config.UploadHedgeAfter = time.Millisecond + config.UploadHedgeRateMax = 0.1 + config.UploadHedgeRateBurst = 10 + config.UploadMaxRetries = 0 + + sw := &segmentsWriter{ + config: config, + logger: logger, + bucket: bucket, + hedgedUploadLimiter: rate.NewLimiter(rate.Limit(config.UploadHedgeRateMax), int(config.UploadHedgeRateBurst)), + metrics: newSegmentMetrics(nil), + } + + require.True(t, sw.hedgedUploadLimiter.ReserveN(time.Now(), int(config.UploadHedgeRateBurst)).OK()) + err := sw.uploadBlock(context.Background(), nil, new(metastorev1.BlockMeta), new(segment)) + require.ErrorIs(t, err, context.DeadlineExceeded) + require.Equal(t, int64(1), bucket.uploads.Load()) + }) +} diff --git a/pkg/segmentwriter/service.go b/pkg/segmentwriter/service.go new file mode 100644 index 0000000000..713dd0c2d5 --- /dev/null +++ b/pkg/segmentwriter/service.go @@ -0,0 +1,307 @@ +package segmentwriter + +import ( + "context" + "errors" + "flag" + "fmt" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/google/uuid" + "github.com/grafana/dskit/grpcclient" + "github.com/grafana/dskit/multierror" + "github.com/grafana/dskit/ring" + "github.com/grafana/dskit/services" + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + metastoreclient "github.com/grafana/pyroscope/v2/pkg/metastore/client" + "github.com/grafana/pyroscope/v2/pkg/model/relabel" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/segmentwriter/memdb" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/fieldcategory" + "github.com/grafana/pyroscope/v2/pkg/util/health" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +const ( + RingName = "segment-writer" + RingKey = "segment-writer-ring" + + minFlushConcurrency = 8 + defaultSegmentDuration = 500 * time.Millisecond + defaultHedgedRequestMaxRate = 2 // 2 hedged requests per second + defaultHedgedRequestBurst = 10 // allow bursts of 10 hedged requests +) + +type Config struct { + GRPCClientConfig grpcclient.Config `yaml:"grpc_client_config" doc:"description=Configures the gRPC client used to communicate with the segment writer."` + LifecyclerConfig ring.LifecyclerConfig `yaml:"lifecycler,omitempty"` + SegmentDuration time.Duration `yaml:"segment_duration,omitempty" category:"advanced"` + FlushConcurrency uint `yaml:"flush_concurrency,omitempty" category:"advanced"` + UploadTimeout time.Duration `yaml:"upload-timeout,omitempty" category:"advanced"` + UploadMaxRetries int `yaml:"upload-retry_max_retries,omitempty" category:"advanced"` + UploadMinBackoff time.Duration `yaml:"upload-retry_min_period,omitempty" category:"advanced"` + UploadMaxBackoff time.Duration `yaml:"upload-retry_max_period,omitempty" category:"advanced"` + UploadHedgeAfter time.Duration `yaml:"upload-hedge_upload_after,omitempty" category:"advanced"` + UploadHedgeRateMax float64 `yaml:"upload-hedge_rate_max,omitempty" category:"advanced"` + UploadHedgeRateBurst uint `yaml:"upload-hedge_rate_burst,omitempty" category:"advanced"` + MetadataDLQEnabled bool `yaml:"metadata_dlq_enabled,omitempty" category:"advanced"` + MetadataUpdateTimeout time.Duration `yaml:"metadata_update_timeout,omitempty" category:"advanced"` + BucketHealthCheckEnabled bool `yaml:"bucket_health_check_enabled,omitempty" category:"advanced"` + BucketHealthCheckTimeout time.Duration `yaml:"bucket_health_check_timeout,omitempty" category:"advanced"` +} + +func (cfg *Config) Validate() error { + // TODO(kolesnikovae): implement. + if err := cfg.LifecyclerConfig.Validate(); err != nil { + return err + } + return cfg.GRPCClientConfig.Validate() +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + const prefix = "segment-writer" + // Ring/KV store flags come from dskit and cannot be tagged directly; mark them advanced here. + fieldcategory.AddOverrides(map[string]fieldcategory.Category{ + prefix + ".availability-zone": fieldcategory.Advanced, + prefix + ".consul.hostname": fieldcategory.Advanced, + prefix + ".distributor.replication-factor": fieldcategory.Advanced, + prefix + ".distributor.zone-awareness-enabled": fieldcategory.Advanced, + prefix + ".etcd.endpoints": fieldcategory.Advanced, + prefix + ".etcd.password": fieldcategory.Advanced, + prefix + ".etcd.username": fieldcategory.Advanced, + prefix + ".lifecycler.interface": fieldcategory.Advanced, + prefix + ".store": fieldcategory.Advanced, + prefix + ".tokens-file-path": fieldcategory.Advanced, + }) + cfg.LifecyclerConfig.RegisterFlagsWithPrefix(prefix+".", f, util.Logger) + cfg.GRPCClientConfig.RegisterFlagsWithPrefix(prefix+".grpc-client-config", f) + f.DurationVar(&cfg.SegmentDuration, prefix+".segment-duration", defaultSegmentDuration, "Timeout when flushing segments to bucket.") + f.UintVar(&cfg.FlushConcurrency, prefix+".flush-concurrency", 0, "Number of concurrent flushes. Defaults to the number of CPUs, but not less than 8.") + f.DurationVar(&cfg.UploadTimeout, prefix+".upload-timeout", 2*time.Second, "Timeout for upload requests, including retries.") + f.IntVar(&cfg.UploadMaxRetries, prefix+".upload-max-retries", 3, "Number of times to backoff and retry before failing.") + f.DurationVar(&cfg.UploadMinBackoff, prefix+".upload-retry-min-period", 50*time.Millisecond, "Minimum delay when backing off.") + f.DurationVar(&cfg.UploadMaxBackoff, prefix+".upload-retry-max-period", defaultSegmentDuration, "Maximum delay when backing off.") + f.DurationVar(&cfg.UploadHedgeAfter, prefix+".upload-hedge-after", defaultSegmentDuration, "Time after which to hedge the upload request.") + f.Float64Var(&cfg.UploadHedgeRateMax, prefix+".upload-hedge-rate-max", defaultHedgedRequestMaxRate, "Maximum number of hedged requests per second. 0 disables rate limiting.") + f.UintVar(&cfg.UploadHedgeRateBurst, prefix+".upload-hedge-rate-burst", defaultHedgedRequestBurst, "Maximum number of hedged requests in a burst.") + f.BoolVar(&cfg.MetadataDLQEnabled, prefix+".metadata-dlq-enabled", true, "Enables dead letter queue (DLQ) for metadata. If the metadata update fails, it will be stored and updated asynchronously.") + f.DurationVar(&cfg.MetadataUpdateTimeout, prefix+".metadata-update-timeout", 2*time.Second, "Timeout for metadata update requests.") + f.BoolVar(&cfg.BucketHealthCheckEnabled, prefix+".bucket-health-check-enabled", true, "Enables bucket health check on startup. This both validates credentials and warms up the connection to reduce latency for the first write.") + f.DurationVar(&cfg.BucketHealthCheckTimeout, prefix+".bucket-health-check-timeout", 10*time.Second, "Timeout for bucket health check operations.") +} + +type Limits interface { + IngestionRelabelingRules(tenantID string) []*relabel.Config + DistributorUsageGroups(tenantID string) *validation.UsageGroupConfig +} + +type SegmentWriterService struct { + services.Service + segmentwriterv1.UnimplementedSegmentWriterServiceServer + + config Config + logger log.Logger + reg prometheus.Registerer + health health.Service + + requests util.InflightRequests + lifecycler *ring.Lifecycler + subservices *services.Manager + subservicesWatcher *services.FailureWatcher + + storageBucket phlareobj.Bucket + segmentWriter *segmentsWriter +} + +func New( + reg prometheus.Registerer, + logger log.Logger, + config Config, + limits Limits, + health health.Service, + storageBucket phlareobj.Bucket, + metastoreClient *metastoreclient.Client, +) (*SegmentWriterService, error) { + i := &SegmentWriterService{ + config: config, + logger: logger, + reg: reg, + health: health, + storageBucket: storageBucket, + } + + // The lifecycler is only used for discovery: it maintains the state of the + // instance in the ring and nothing more. Flush is managed explicitly at + // shutdown, and data/state transfer is not required. + var err error + i.lifecycler, err = ring.NewLifecycler( + config.LifecyclerConfig, + noOpTransferFlush{}, + RingName, + RingKey, + false, + i.logger, prometheus.WrapRegistererWithPrefix("pyroscope_segment_writer_", i.reg)) + if err != nil { + return nil, err + } + + i.subservices, err = services.NewManager(i.lifecycler) + if err != nil { + return nil, fmt.Errorf("services manager: %w", err) + } + if storageBucket == nil { + return nil, errors.New("storage bucket is required for segment writer") + } + if metastoreClient == nil { + return nil, errors.New("metastore client is required for segment writer") + } + metrics := newSegmentMetrics(i.reg) + headMetrics := memdb.NewHeadMetricsWithPrefix(reg, "pyroscope_segment_writer") + i.segmentWriter = newSegmentWriter(i.logger, metrics, headMetrics, config, limits, storageBucket, metastoreClient) + i.subservicesWatcher = services.NewFailureWatcher() + i.subservicesWatcher.WatchManager(i.subservices) + i.Service = services.NewBasicService(i.starting, i.running, i.stopping) + return i, nil +} + +// performBucketHealthCheck performs a lightweight bucket operation to warm up the connection +// and detect any object storage issues early. This serves the dual purpose of validating +// bucket accessibility and reducing latency for the first actual write operation. +func (i *SegmentWriterService) performBucketHealthCheck(ctx context.Context) error { + if !i.config.BucketHealthCheckEnabled { + return nil + } + + level.Debug(i.logger).Log("msg", "starting bucket health check", "timeout", i.config.BucketHealthCheckTimeout.String()) + + healthCheckCtx, cancel := context.WithTimeout(ctx, i.config.BucketHealthCheckTimeout) + defer cancel() + + err := i.storageBucket.Iter(healthCheckCtx, "", func(string) error { + // We only care about connectivity, not the actual contents + // Return an error to stop iteration after first item (if any) + return errors.New("stop iteration") + }) + + // Ignore the "stop iteration" error we intentionally return + // and any "object not found" type errors as they indicate the bucket is accessible + if err == nil || i.storageBucket.IsObjNotFoundErr(err) || err.Error() == "stop iteration" { + level.Debug(i.logger).Log("msg", "bucket health check succeeded") + return nil + } + + level.Warn(i.logger).Log("msg", "bucket health check failed", "err", err) + return nil // Don't fail startup, just warn +} + +func (i *SegmentWriterService) starting(ctx context.Context) error { + // Perform bucket health check before ring registration to warm up the connection + // and avoid slow first requests affecting p99 latency + // On error, will emit a warning but continue startup + _ = i.performBucketHealthCheck(ctx) + + if err := services.StartManagerAndAwaitHealthy(ctx, i.subservices); err != nil { + return err + } + // The instance is ready to handle incoming requests. + // We do not have to wait for the lifecycler: its readiness check + // is only used to limit the number of instances that can be coming + // or going at any one time, by only returning true if all instances + // are active. + i.requests.Open() + i.health.SetServing() + return nil +} + +func (i *SegmentWriterService) running(ctx context.Context) error { + select { + case <-ctx.Done(): + return nil + case err := <-i.subservicesWatcher.Chan(): // handle lifecycler errors + return fmt.Errorf("lifecycler failed: %w", err) + } +} + +func (i *SegmentWriterService) stopping(_ error) error { + i.health.SetNotServing() + errs := multierror.New() + errs.Add(services.StopManagerAndAwaitStopped(context.Background(), i.subservices)) + time.Sleep(i.config.LifecyclerConfig.MinReadyDuration) + i.requests.Drain() + i.segmentWriter.stop() + return errs.Err() +} + +func (i *SegmentWriterService) Push(ctx context.Context, req *segmentwriterv1.PushRequest) (*segmentwriterv1.PushResponse, error) { + if !i.requests.Add() { + return nil, status.Error(codes.Unavailable, "service is unavailable") + } else { + defer func() { + i.requests.Done() + }() + } + + if req.TenantId == "" { + return nil, status.Error(codes.InvalidArgument, tenant.ErrNoTenantID.Error()) + } + var id uuid.UUID + if err := id.UnmarshalBinary(req.ProfileId); err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + p, err := pprof.RawFromBytes(req.Profile) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + wait := i.segmentWriter.ingest(shardKey(req.Shard), func(segment segmentIngest) { + segment.ingest(req.TenantId, p.Profile, id, req.Labels, req.Annotations) + }) + + flushStarted := time.Now() + defer func() { + i.segmentWriter.metrics.segmentFlushWaitDuration. + WithLabelValues(req.TenantId). + Observe(time.Since(flushStarted).Seconds()) + }() + if err = wait.waitFlushed(ctx); err == nil { + return &segmentwriterv1.PushResponse{}, nil + } + + switch { + case errors.Is(err, context.Canceled): + return nil, status.FromContextError(err).Err() + + case errors.Is(err, context.DeadlineExceeded): + i.segmentWriter.metrics.segmentFlushTimeouts.WithLabelValues(req.TenantId).Inc() + level.Error(i.logger).Log("msg", "flush timeout", "err", err) + return nil, status.FromContextError(err).Err() + + default: + level.Error(i.logger).Log("msg", "flush err", "err", err) + return nil, status.Error(codes.Unknown, err.Error()) + } +} + +// CheckReady is used to indicate when the ingesters are ready for +// the addition removal of another ingester. Returns 204 when the ingester is +// ready, 500 otherwise. +func (i *SegmentWriterService) CheckReady(ctx context.Context) error { + if s := i.State(); s != services.Running && s != services.Stopping { + return fmt.Errorf("ingester not ready: %v", s) + } + return i.lifecycler.CheckReady(ctx) +} + +type noOpTransferFlush struct{} + +func (noOpTransferFlush) Flush() {} +func (noOpTransferFlush) TransferOut(context.Context) error { return ring.ErrTransferDisabled } diff --git a/pkg/settings/bucket.go b/pkg/settings/bucket.go index 10105131f3..64f5d85bfd 100644 --- a/pkg/settings/bucket.go +++ b/pkg/settings/bucket.go @@ -4,35 +4,33 @@ import ( "bytes" "context" "encoding/json" + "errors" + "fmt" "slices" "strings" "sync" - "github.com/pkg/errors" "github.com/thanos-io/objstore" settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" ) var ( - oldSettingErr = errors.New("newer update already written") + errOldSetting = errors.New("newer update already written") settingsFilename = "tenant_settings.json" ) -// NewMemoryStore will create a settings store with an in-memory objstore -// bucket. -func NewMemoryStore() (Store, error) { - return NewBucketStore(objstore.NewInMemBucket()) +// newMemoryStore will create a settings store with an in-memory bucket. +func newMemoryStore() store { + return newBucketStore(objstore.NewInMemBucket()) } // NewBucketStore will create a settings store with an objstore bucket. -func NewBucketStore(bucket objstore.Bucket) (Store, error) { - store := &bucketStore{ +func newBucketStore(bucket objstore.Bucket) store { + return &bucketStore{ store: make(map[string]map[string]*settingsv1.Setting), bucket: bucket, } - - return store, nil } type bucketStore struct { @@ -83,7 +81,7 @@ func (s *bucketStore) Set(ctx context.Context, tenantID string, setting *setting oldSetting, ok := s.store[tenantID][setting.Name] if ok && oldSetting.ModifiedAt > setting.ModifiedAt { - return nil, errors.Wrapf(oldSettingErr, "failed to update %s", setting.Name) + return nil, fmt.Errorf("failed to update %s: %w", setting.Name, errOldSetting) } s.store[tenantID][setting.Name] = setting @@ -95,11 +93,37 @@ func (s *bucketStore) Set(ctx context.Context, tenantID string, setting *setting return setting, nil } -func (s *bucketStore) Flush(ctx context.Context) error { +func (s *bucketStore) Delete(ctx context.Context, tenantID string, name string, modifiedAtMs int64) error { s.rw.Lock() defer s.rw.Unlock() - return s.unsafeFlush(ctx) + err := s.unsafeLoad(ctx) + if err != nil { + return err + } + + tenantSettings, ok := s.store[tenantID] + if !ok { + return nil + } + + setting, ok := tenantSettings[name] + if !ok { + return nil + } + + if setting.ModifiedAt > modifiedAtMs { + return fmt.Errorf("failed to delete %s: %w", name, errOldSetting) + } + + delete(tenantSettings, name) + + err = s.unsafeFlush(ctx) + if err != nil { + return err + } + + return nil } func (s *bucketStore) Close() error { @@ -135,6 +159,7 @@ func (s *bucketStore) unsafeLoad(ctx context.Context) error { err = json.NewDecoder(reader).Decode(&s.store) if err != nil { + reader.Close() return err } diff --git a/pkg/settings/bucket_test.go b/pkg/settings/bucket_test.go index 9aec3b480f..5d7f5a46ef 100644 --- a/pkg/settings/bucket_test.go +++ b/pkg/settings/bucket_test.go @@ -12,18 +12,17 @@ import ( func TestMemoryBucket_Get(t *testing.T) { ctx := context.Background() - tenantID := "[anonymous]" + const tenantID = "[anonymous]" t.Run("get settings are sorted", func(t *testing.T) { - mem, err := NewMemoryStore() - assert.NoError(t, err) + mem := newMemoryStore() settings := []*settingsv1.Setting{ {Name: "key1", Value: "val1"}, {Name: "key2", Value: "val2"}, } for _, s := range settings { - _, err = mem.Set(ctx, tenantID, s) + _, err := mem.Set(ctx, tenantID, s) assert.NoError(t, err) } got, err := mem.Get(ctx, tenantID) @@ -35,8 +34,8 @@ func TestMemoryBucket_Get(t *testing.T) { }) t.Run("don't get settings from another tenant", func(t *testing.T) { - mem, err := NewMemoryStore() - assert.NoError(t, err) + var err error + mem := newMemoryStore() otherTenantID := "other" @@ -66,11 +65,10 @@ func TestMemoryBucket_Get(t *testing.T) { func TestMemoryBucket_Set(t *testing.T) { ctx := context.Background() - tenantID := "[anonymous]" + const tenantID = "[anonymous]" t.Run("set a new key", func(t *testing.T) { - mem, err := NewMemoryStore() - assert.NoError(t, err) + mem := newMemoryStore() setting := &settingsv1.Setting{ Name: "key1", @@ -82,8 +80,7 @@ func TestMemoryBucket_Set(t *testing.T) { }) t.Run("update a key", func(t *testing.T) { - mem, err := NewMemoryStore() - assert.NoError(t, err) + mem := newMemoryStore() setting := &settingsv1.Setting{ Name: "key1", @@ -103,8 +100,7 @@ func TestMemoryBucket_Set(t *testing.T) { }) t.Run("don't update a key that's too old", func(t *testing.T) { - mem, err := NewMemoryStore() - assert.NoError(t, err) + mem := newMemoryStore() setting := &settingsv1.Setting{ Name: "key1", @@ -124,3 +120,48 @@ func TestMemoryBucket_Set(t *testing.T) { assert.EqualError(t, err, "failed to update key1: newer update already written") }) } + +func TestMemoryBucket_Delete(t *testing.T) { + ctx := context.Background() + const tenantID = "[anonymous]" + + t.Run("delete a key", func(t *testing.T) { + mem := newMemoryStore() + + setting := &settingsv1.Setting{ + Name: "key1", + Value: "val1", + } + _, err := mem.Set(ctx, tenantID, setting) + assert.NoError(t, err) + + err = mem.Delete(ctx, tenantID, setting.Name, setting.ModifiedAt) + assert.NoError(t, err) + + got, err := mem.Get(ctx, tenantID) + assert.NoError(t, err) + assert.Empty(t, got) + }) + + t.Run("delete a non-existent key", func(t *testing.T) { + mem := newMemoryStore() + + err := mem.Delete(ctx, tenantID, "key1", 0) + assert.NoError(t, err) + }) + + t.Run("don't delete a key that's too old", func(t *testing.T) { + mem := newMemoryStore() + + setting := &settingsv1.Setting{ + Name: "key1", + Value: "val1", + ModifiedAt: 10, + } + _, err := mem.Set(ctx, tenantID, setting) + assert.NoError(t, err) + + err = mem.Delete(ctx, tenantID, setting.Name, 5) + assert.EqualError(t, err, "failed to delete key1: newer update already written") + }) +} diff --git a/pkg/settings/recording/client/client.go b/pkg/settings/recording/client/client.go new file mode 100644 index 0000000000..61e470f931 --- /dev/null +++ b/pkg/settings/recording/client/client.go @@ -0,0 +1,57 @@ +package recording + +import ( + "context" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/services" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1/settingsv1connect" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/tenant" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" +) + +type Client struct { + service services.Service + client settingsv1connect.RecordingRulesServiceClient + logger log.Logger +} + +func NewClient(address string, logger log.Logger, auth connect.Option) (*Client, error) { + httpClient := httputil.InstrumentedDefaultHTTPClient() + opts := connectapi.DefaultClientOptions() + opts = append(opts, auth) + c := Client{ + client: settingsv1connect.NewRecordingRulesServiceClient(httpClient, address, opts...), + logger: logger, + } + c.service = services.NewIdleService(c.starting, c.stopping) + return &c, nil +} + +func (b *Client) RecordingRules(tenantId string) ([]*phlaremodel.RecordingRule, error) { + ctx := tenant.InjectTenantID(context.Background(), tenantId) + resp, err := b.client.ListRecordingRules(ctx, connect.NewRequest(&settingsv1.ListRecordingRulesRequest{})) + if err != nil { + return nil, err + } + rules := make([]*phlaremodel.RecordingRule, 0, len(resp.Msg.Rules)) + for _, rule := range resp.Msg.Rules { + r, err := phlaremodel.NewRecordingRule(rule) + if err == nil { + rules = append(rules, r) + } else { + level.Error(b.logger).Log("msg", "failed to parse recording rule", "rule", rule, "err", err) + } + } + return rules, nil +} + +func (b *Client) Service() services.Service { return b.service } +func (b *Client) starting(context.Context) error { return nil } +func (b *Client) stopping(error) error { return nil } diff --git a/pkg/settings/recording/config.go b/pkg/settings/recording/config.go new file mode 100644 index 0000000000..6152333025 --- /dev/null +++ b/pkg/settings/recording/config.go @@ -0,0 +1,30 @@ +package recording + +import ( + "flag" +) + +type Config struct { + Enabled bool `yaml:"enabled" category:"experimental"` +} + +const ( + flagPrefix = "tenant-settings.recording-rules." + flagEnabled = flagPrefix + "enabled" +) + +func (cfg *Config) RegisterFlags(fs *flag.FlagSet) { + fs.BoolVar( + &cfg.Enabled, + flagEnabled, + false, + "Enable the storing of recording rules in tenant settings.", + ) +} + +func (cfg *Config) Validate() error { + if !cfg.Enabled { + return nil + } + return nil +} diff --git a/pkg/settings/recording/recording.go b/pkg/settings/recording/recording.go new file mode 100644 index 0000000000..de7f48d7be --- /dev/null +++ b/pkg/settings/recording/recording.go @@ -0,0 +1,423 @@ +package recording + +import ( + "context" + "crypto/sha256" + "errors" + "fmt" + "math/rand" + "regexp" + "sort" + "strings" + "sync" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + prom "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/thanos-io/objstore" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1/settingsv1connect" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/settings/store" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +var _ settingsv1connect.RecordingRulesServiceHandler = (*RecordingRules)(nil) + +func New(bucket objstore.Bucket, logger log.Logger, overrides *validation.Overrides) *RecordingRules { + return &RecordingRules{ + bucket: bucket, + logger: logger, + stores: make(map[store.Key]*bucketStore), + overrides: overrides, + } +} + +// RecordingRules is a collection that gathers rules coming from config and coming from the bucket storage. +// Rules coming from config work as overrides of store rules, and in case of repeated ID, config rules prevail. +type RecordingRules struct { + bucket objstore.Bucket + logger log.Logger + + rw sync.RWMutex + stores map[store.Key]*bucketStore + + overrides *validation.Overrides +} + +// GetRecordingRule will return a rule of the given ID or not found. +// Rules defined by config are returned over rules in the store. +func (r *RecordingRules) GetRecordingRule(ctx context.Context, req *connect.Request[settingsv1.GetRecordingRuleRequest]) (*connect.Response[settingsv1.GetRecordingRuleResponse], error) { + err := validateGet(req.Msg) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + tenantID, err := r.tenantOrError(ctx) + if err != nil { + return nil, err + } + + // look for provisioned rules + rulesFromConfig := r.recordingRulesFromOverrides(tenantID) + for _, r := range rulesFromConfig { + if r.Id == req.Msg.Id { + return connect.NewResponse(&settingsv1.GetRecordingRuleResponse{Rule: r}), nil + } + } + + s := r.storeForTenant(tenantID) + rule, err := s.Get(ctx, req.Msg.Id) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + if rule == nil { + return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("no rule with id='%s' found", req.Msg.Id)) + } + + res := &settingsv1.GetRecordingRuleResponse{ + Rule: convertRuleToAPI(rule), + } + return connect.NewResponse(res), nil +} + +// ListRecordingRules will return all the rules defined by config and in the store. Rules in the store with the same ID +// as a rule in config will be filtered out. +func (r *RecordingRules) ListRecordingRules(ctx context.Context, req *connect.Request[settingsv1.ListRecordingRulesRequest]) (*connect.Response[settingsv1.ListRecordingRulesResponse], error) { + tenantId, err := r.tenantOrError(ctx) + if err != nil { + return nil, err + } + + rulesFromOverrides := r.recordingRulesFromOverrides(tenantId) + ruleIds := make(map[string]struct{}, len(rulesFromOverrides)) + res := &settingsv1.ListRecordingRulesResponse{ + Rules: make([]*settingsv1.RecordingRule, 0), + } + for _, r := range rulesFromOverrides { + ruleIds[r.Id] = struct{}{} + res.Rules = append(res.Rules, r) + } + + s := r.storeForTenant(tenantId) + rulesFromStore, err := s.List(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + for _, rule := range rulesFromStore.Rules { + if _, overridden := ruleIds[rule.Id]; overridden { + continue + } + res.Rules = append(res.Rules, convertRuleToAPI(rule)) + } + + return connect.NewResponse(res), nil +} + +// UpsertRecordingRule upserts a rule in the storage. +// Operational purposes: you can upsert store rules (no matter if they exist in config) +func (r *RecordingRules) UpsertRecordingRule(ctx context.Context, req *connect.Request[settingsv1.UpsertRecordingRuleRequest]) (*connect.Response[settingsv1.UpsertRecordingRuleResponse], error) { + err := validateUpsert(req.Msg) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid request: %v", err)) + } + + tenantID, err := r.tenantOrError(ctx) + if err != nil { + return nil, err + } + s := r.storeForTenant(tenantID) + + newRule := &settingsv1.RecordingRuleStore{ + Id: req.Msg.Id, + MetricName: req.Msg.MetricName, + Matchers: req.Msg.Matchers, + GroupBy: req.Msg.GroupBy, + ExternalLabels: req.Msg.ExternalLabels, + Generation: req.Msg.Generation, + StacktraceFilter: req.Msg.StacktraceFilter, + } + newRule, err = s.Upsert(ctx, newRule, r.overrides.MaxRecordingRules(tenantID)) + if err != nil { + var cErr *store.ErrConflictGeneration + if errors.As(err, &cErr) { + return nil, connect.NewError(connect.CodeAlreadyExists, fmt.Errorf("conflicting update, please try again")) + } + var mErr *store.ErrMaxElementsExceeded + if errors.As(err, &mErr) { + return nil, connect.NewError(connect.CodeResourceExhausted, fmt.Errorf("recording rules limit (%d) exceeded for this tenant", mErr.Max)) + } + return nil, connect.NewError(connect.CodeInternal, err) + } + + res := &settingsv1.UpsertRecordingRuleResponse{ + Rule: convertRuleToAPI(newRule), + } + return connect.NewResponse(res), nil +} + +// DeleteRecordingRule deletes a store rule +// Operational purposes: you can delete store rules (no matter if they exist in config) +func (r *RecordingRules) DeleteRecordingRule(ctx context.Context, req *connect.Request[settingsv1.DeleteRecordingRuleRequest]) (*connect.Response[settingsv1.DeleteRecordingRuleResponse], error) { + err := validateDelete(req.Msg) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("invalid request: %v", err)) + } + + s, err := r.storeFromContext(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + err = s.Delete(ctx, req.Msg.Id) + if err != nil { + return nil, err + } + + res := &settingsv1.DeleteRecordingRuleResponse{} + return connect.NewResponse(res), nil +} + +func (r *RecordingRules) storeFromContext(ctx context.Context) (*bucketStore, error) { + tenantID, err := r.tenantOrError(ctx) + if err != nil { + return nil, err + } + return r.storeForTenant(tenantID), nil +} + +func (r *RecordingRules) storeForTenant(tenantID string) *bucketStore { + key := store.Key{TenantID: tenantID} + + r.rw.RLock() + tenantStore, ok := r.stores[key] + r.rw.RUnlock() + if ok { + return tenantStore + } + + r.rw.Lock() + defer r.rw.Unlock() + + tenantStore, ok = r.stores[key] + if ok { + return tenantStore + } + + tenantStore = newBucketStore(r.logger, r.bucket, key) + r.stores[key] = tenantStore + return tenantStore +} + +func (r *RecordingRules) tenantOrError(ctx context.Context) (string, error) { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + level.Error(r.logger).Log("error getting tenant ID", "err", err) + return "", connect.NewError(connect.CodeInternal, err) + } + return tenantID, nil +} + +func (r *RecordingRules) recordingRulesFromOverrides(tenantID string) []*settingsv1.RecordingRule { + rules := r.overrides.RecordingRules(tenantID) + for i := range rules { + rules[i].Provisioned = true + if rules[i].Id == "" { + // for consistency, rules will be filled with an ID + rules[i].Id = idForRule(rules[i]) + } + } + return rules +} + +func validateGet(req *settingsv1.GetRecordingRuleRequest) error { + // Format fields. + req.Id = strings.TrimSpace(req.Id) + + // Validate fields. + var errs []error + + if req.Id == "" { + errs = append(errs, fmt.Errorf("id is required")) + } + + return errors.Join(errs...) +} + +var ( + upsertIdRE = regexp.MustCompile(`^[a-zA-Z]+$`) +) + +func validateUpsert(req *settingsv1.UpsertRecordingRuleRequest) error { + // Validate fields. + var errs []error + + // Format fields. + if req.Id == "" { + req.Id = generateID(idLength) + req.Generation = 1 + } + req.MetricName = strings.TrimSpace(req.MetricName) + + if !upsertIdRE.MatchString(req.Id) { + errs = append(errs, fmt.Errorf("id %q must match %s", req.Id, upsertIdRE.String())) + } + + if req.MetricName == "" { + errs = append(errs, fmt.Errorf("metric_name is required")) + } else if err := model.ValidateMetricName(req.MetricName); err != nil { + errs = append(errs, fmt.Errorf("metric_name %q is invalid: %v", req.MetricName, err)) + } + + profileTypeMatcher := 0 + for _, m := range req.Matchers { + matchers, err := model.ParseMetricSelector(m) + if err != nil { + errs = append(errs, fmt.Errorf("matcher %q is invalid: %v", m, err)) + } + for _, matcher := range matchers { + if matcher == nil { + continue + } + if matcher.Name == model.LabelNameProfileType { + if matcher.Type != labels.MatchEqual { + errs = append(errs, fmt.Errorf("matcher %q must have type %q", matcher.Name, labels.MatchEqual)) + } + profileTypeMatcher += 1 + } + } + } + + if profileTypeMatcher != 1 { + errs = append(errs, fmt.Errorf("matchers must contain a %q matcher", model.LabelNameProfileType)) + } + + for _, l := range req.GroupBy { + name := prom.LabelName(l) + if !prom.LegacyValidation.IsValidLabelName(string(name)) { + errs = append(errs, fmt.Errorf("group_by label %q must match %s", l, prom.LabelNameRE.String())) + } + } + + for _, l := range req.ExternalLabels { + name := prom.LabelName(l.Name) + if !prom.LegacyValidation.IsValidLabelName(string(name)) { + errs = append(errs, fmt.Errorf("external_labels name %q must match %s", name, prom.LabelNameRE.String())) + } + + value := prom.LabelValue(l.Value) + if !value.IsValid() { + errs = append(errs, fmt.Errorf("external_labels value %q must be a valid utf-8 string", l.Value)) + } + } + + if req.Generation < 0 { + errs = append(errs, fmt.Errorf("generation must be positive")) + } + + return errors.Join(errs...) +} + +func validateDelete(req *settingsv1.DeleteRecordingRuleRequest) error { + // Format fields. + req.Id = strings.TrimSpace(req.Id) + + // Validate fields. + var errs []error + + if req.Id == "" { + errs = append(errs, fmt.Errorf("id is required")) + } + + return errors.Join(errs...) +} + +func convertRuleToAPI(rule *settingsv1.RecordingRuleStore) *settingsv1.RecordingRule { + apiRule := &settingsv1.RecordingRule{ + Id: rule.Id, + MetricName: rule.MetricName, + ProfileType: "unknown", + Matchers: rule.Matchers, + GroupBy: rule.GroupBy, + ExternalLabels: rule.ExternalLabels, + Generation: rule.Generation, + StacktraceFilter: rule.StacktraceFilter, + } + + // Try find the profile type from the matchers. +Loop: + for _, m := range rule.Matchers { + s, err := model.ParseMetricSelector(m) + if err != nil { + // Since this value is loaded from the tenant settings database and + // we validate selectors before saving, we should theoretically + // always have valid selectors. If there's an error parsing a + // selector, we'll just skip it. + continue + } + + for _, label := range s { + if label.Name != model.LabelNameProfileType { + continue + } + + if label.Type != labels.MatchEqual { + continue + } + + apiRule.ProfileType = label.Value + break Loop + } + } + + return apiRule +} + +const ( + alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + idLength = 10 +) + +func generateID(length int) string { + + if length < 1 { + return "" + } + + b := make([]byte, length) + for i := range b { + b[i] = alphabet[rand.Intn(len(alphabet))] + } + return string(b) +} + +func idForRule(rule *settingsv1.RecordingRule) string { + var b strings.Builder + b.WriteString(rule.MetricName) + b.WriteString(rule.ProfileType) + sort.Strings(rule.Matchers) + for _, m := range rule.Matchers { + b.WriteString(m) + } + sort.Strings(rule.GroupBy) + for _, g := range rule.GroupBy { + b.WriteString(g) + } + for _, l := range rule.ExternalLabels { + b.WriteString(l.Name) + b.WriteString(l.Value) + } + if rule.StacktraceFilter != nil && rule.StacktraceFilter.FunctionName != nil { + b.WriteString(rule.StacktraceFilter.FunctionName.FunctionName) + } + sum := sha256.Sum256([]byte(b.String())) + id := make([]byte, idLength) + for i := 0; i < idLength; i++ { + id[i] = alphabet[sum[i]%byte(len(alphabet))] + } + return string(id) +} diff --git a/pkg/settings/recording/recording_test.go b/pkg/settings/recording/recording_test.go new file mode 100644 index 0000000000..2e52e80d1f --- /dev/null +++ b/pkg/settings/recording/recording_test.go @@ -0,0 +1,716 @@ +package recording + +import ( + "context" + "fmt" + "math/rand/v2" + "os" + "testing" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/grafana/dskit/user" + "github.com/stretchr/testify/require" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func Test_validateGet(t *testing.T) { + tests := []struct { + Name string + Req *settingsv1.GetRecordingRuleRequest + WantErr string + }{ + { + Name: "valid", + Req: &settingsv1.GetRecordingRuleRequest{ + Id: "random", + }, + WantErr: "", + }, + { + Name: "valid_with_formatted_fields", + Req: &settingsv1.GetRecordingRuleRequest{ + Id: " random ", + }, + WantErr: "", + }, + { + Name: "empty_id", + Req: &settingsv1.GetRecordingRuleRequest{ + Id: "", + }, + WantErr: "id is required", + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + err := validateGet(tt.Req) + if tt.WantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.WantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_validateUpsert(t *testing.T) { + tests := []struct { + Name string + Req *settingsv1.UpsertRecordingRuleRequest + WantErr string + }{ + { + Name: "valid", + Req: &settingsv1.UpsertRecordingRuleRequest{ + Id: "abcdef", + MetricName: "profiles_recorded_my_metric", + Matchers: []string{ + `{ label_a = "A" }`, + `{ label_b =~ "B" }`, + `{ __profile_type__ = "any-type" }`, + }, + GroupBy: []string{ + "label_c", + }, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "label_a", Value: "A"}, + {Name: "label_b", Value: "B"}, + }, + Generation: 1, + }, + WantErr: "", + }, + { + Name: "minimal_valid", + Req: &settingsv1.UpsertRecordingRuleRequest{ + Id: "", + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: "", + }, + { + Name: "valid_with_formatted_fields", + Req: &settingsv1.UpsertRecordingRuleRequest{ + Id: "abcdef", + MetricName: " profiles_recorded_my_metric ", + Matchers: []string{ + ` { __profile_type__ ="any-type"}`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: "", + }, + { + Name: "empty_id", + Req: &settingsv1.UpsertRecordingRuleRequest{ + Id: "", + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: "", + }, + { + Name: "whitespace_only_id", + Req: &settingsv1.UpsertRecordingRuleRequest{ + Id: " ", + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `id " " must match ^[a-zA-Z]+$`, + }, + { + Name: "invalid_id", + Req: &settingsv1.UpsertRecordingRuleRequest{ + Id: "?", + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `id "?" must match ^[a-zA-Z]+$`, + }, + { + Name: "empty_metric_name", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: "metric_name is required", + }, + { + Name: "invalid_metric_name", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: string([]byte{0xC0, 0xAF}), // invalid utf-8 + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: "metric_name \"\\xc0\\xaf\" is invalid: invalid metric name: \xc0\xaf", + }, + { + Name: "invalid_matchers", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{ + "", + `{ __profile_type__ = "any-type" }`, + }, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `matcher "" is invalid: unknown position: parse error: unexpected end of input`, + }, + { + Name: "mixed_invalid_matchers", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{ + "", + `{ __profile_type__ = "any-type", INVALID }`, + }, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: "matcher \"\" is invalid: unknown position: parse error: unexpected end of input\nmatcher \"{ __profile_type__ = \\\"any-type\\\", INVALID }\" is invalid: 1:42: parse error: unexpected \"}\" in label matching, expected label matching operator", + }, + { + Name: "missing __profile_type__ matcher", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `matchers must contain a "__profile_type__" matcher`, + }, + { + Name: "multiple __profile_type__ matcher", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`, `{ __profile_type__ = "any-type-2" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `matchers must contain a "__profile_type__" matcher`, + }, + { + Name: "non-equality __profile_type__ matcher", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ =~ "any-type.*" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `matcher "__profile_type__" must have type "="`, + }, + { + Name: "non-unique __profile_type__ matcher", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{ + `{ __profile_type__ = "any-type" }`, + `{ __profile_type__ = "another-type" }`, + }, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `matchers must contain a "__profile_type__" matcher`, + }, + { + Name: "invalid_group_by_empty", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{ + "", + }, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `group_by label "" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + Name: "invalid_group_by_with_dot", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{ + "service.name", + }, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `group_by label "service.name" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + Name: "invalid_group_by_with_utf8", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{ + "世界", + }, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `group_by label "世界" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + Name: "invalid_group_by_starts_with_number", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{ + "123invalid", + }, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: `group_by label "123invalid" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + Name: "invalid_external_label_utf8", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{ + { + Name: string([]byte{0xC0, 0xAF}), // invalid utf-8 + Value: string([]byte{0xC0, 0xAF}), // invalid utf-8 + }, + }, + }, + WantErr: `external_labels name "\xc0\xaf" must match ^[a-zA-Z_][a-zA-Z0-9_]*$ +external_labels value "\xc0\xaf" must be a valid utf-8 string`, + }, + { + Name: "invalid_external_label_with_dot", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "service.name", Value: "foo"}, + }, + }, + WantErr: `external_labels name "service.name" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + Name: "invalid_external_label_with_utf8_name", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "世界", Value: "value"}, + }, + }, + WantErr: `external_labels name "世界" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + Name: "invalid_external_label_starts_with_number", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "123invalid", Value: "value"}, + }, + }, + WantErr: `external_labels name "123invalid" must match ^[a-zA-Z_][a-zA-Z0-9_]*$`, + }, + { + Name: "invalid_generation", + Req: &settingsv1.UpsertRecordingRuleRequest{ + Id: "abcdef", + MetricName: "profiles_recorded_my_metric", + Matchers: []string{`{ __profile_type__ = "any-type" }`}, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + Generation: -1, + }, + WantErr: "generation must be positive", + }, + { + Name: "multiple_errors", + Req: &settingsv1.UpsertRecordingRuleRequest{ + MetricName: "", + Matchers: []string{ + "", + }, + GroupBy: []string{}, + ExternalLabels: []*typesv1.LabelPair{}, + }, + WantErr: "metric_name is required\nmatcher \"\" is invalid: unknown position: parse error: unexpected end of input\nmatchers must contain a \"__profile_type__\" matcher", + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + err := validateUpsert(tt.Req) + if tt.WantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.WantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_validateDelete(t *testing.T) { + tests := []struct { + Name string + Req *settingsv1.DeleteRecordingRuleRequest + WantErr string + }{ + { + Name: "valid", + Req: &settingsv1.DeleteRecordingRuleRequest{ + Id: "random", + }, + WantErr: "", + }, + { + Name: "valid_with_formatted_fields", + Req: &settingsv1.DeleteRecordingRuleRequest{ + Id: " random ", + }, + WantErr: "", + }, + { + Name: "empty_id", + Req: &settingsv1.DeleteRecordingRuleRequest{ + Id: "", + }, + WantErr: "id is required", + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + err := validateDelete(tt.Req) + if tt.WantErr != "" { + require.Error(t, err) + require.EqualError(t, err, tt.WantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_idForRule(t *testing.T) { + tests := []struct { + name string + rule *settingsv1.RecordingRule + expectedId string + }{ + { + name: "some-rule", + expectedId: "veouCnOZTo", + rule: &settingsv1.RecordingRule{ + MetricName: "metric1", + ProfileType: "cpu", + Matchers: []string{ + `{ label_a = "A" }`, + `{ label_b =~ "B" }`, + }, + GroupBy: []string{"label_c", "label_d"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "label_e", Value: "E"}, + {Name: "label_f", Value: "F"}, + }, + StacktraceFilter: &settingsv1.StacktraceFilter{ + FunctionName: &settingsv1.StacktraceFilterFunctionName{ + FunctionName: "function_name", + }, + }, + }, + }, + { + name: "some-other-rule", + expectedId: "XMMpSpeTom", + rule: &settingsv1.RecordingRule{ + MetricName: "metric1", + ProfileType: "cpu", + Matchers: []string{ + `{ label_a = "A" }`, + `{ label_b =~ "B" }`, + }, + GroupBy: []string{"label_c", "label_d"}, + ExternalLabels: []*typesv1.LabelPair{ + {Name: "label_e", Value: "E"}, + {Name: "label_f", Value: "F"}, + }, + StacktraceFilter: &settingsv1.StacktraceFilter{ + FunctionName: &settingsv1.StacktraceFilterFunctionName{ + FunctionName: "another_function_name", + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := idForRule(tt.rule) + require.Equal(t, tt.expectedId, result) + }) + } +} + +type testRecordingRules struct { + *RecordingRules + bucketPath string +} + +func newTestRecordingRules(t *testing.T, overrides *validation.Overrides) *testRecordingRules { + logger := log.NewNopLogger() + if testing.Verbose() { + logger = log.NewLogfmtLogger(os.Stderr) + } + bucketPath := t.TempDir() + bucket, err := filesystem.NewBucket(bucketPath) + require.NoError(t, err) + + return &testRecordingRules{ + RecordingRules: New(bucket, logger, overrides), + bucketPath: bucketPath, + } +} + +func TestRecordingRules_Get(t *testing.T) { + testUser := "user1" + storeRule1 := RandomRule() + storeRule2 := RandomRule() + configRule1 := RandomRule() + configRule1.Id = storeRule2.Id // configRule1 overrides storeRule2 + configRule2 := RandomRule() + configRule2.Id = "" // this rule doesn't override any rule + + r := newTestRecordingRules(t, validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + user1 := validation.MockDefaultLimits() + user1.RecordingRules = validation.RecordingRules{ + configRule1, + configRule2, + } + tenantLimits[testUser] = user1 + })) + + ctx := user.InjectOrgID(context.Background(), testUser) + + t.Run("Get not found", func(t *testing.T) { + _, err := r.GetRecordingRule(ctx, connect.NewRequest(&settingsv1.GetRecordingRuleRequest{Id: storeRule1.Id})) + require.EqualError(t, err, fmt.Sprintf("not_found: no rule with id='%s' found", storeRule1.Id)) + }) + + t.Run("List rules empty for other user", func(t *testing.T) { + ctx2 := user.InjectOrgID(context.Background(), "user2") + resp, err := r.ListRecordingRules(ctx2, connect.NewRequest(&settingsv1.ListRecordingRulesRequest{})) + require.NoError(t, err) + require.Empty(t, resp.Msg.Rules) + }) + + t.Run("Get config rule from autogenerated ID", func(t *testing.T) { + idForConfigRule2 := idForRule(configRule2) + resp, err := r.GetRecordingRule(ctx, connect.NewRequest(&settingsv1.GetRecordingRuleRequest{Id: idForConfigRule2})) + require.NoError(t, err) + require.Equal(t, configRule2, resp.Msg.Rule) + }) + + t.Run("Insert store rules", func(t *testing.T) { + rule, err := r.UpsertRecordingRule(ctx, connect.NewRequest(&settingsv1.UpsertRecordingRuleRequest{ + Id: storeRule1.Id, + MetricName: storeRule1.MetricName, + Matchers: storeRule1.Matchers, + GroupBy: storeRule1.GroupBy, + Generation: storeRule1.Generation, + ExternalLabels: storeRule1.ExternalLabels, + StacktraceFilter: storeRule1.StacktraceFilter, + })) + require.NoError(t, err) + require.Equal(t, storeRule1, rule.Msg.Rule) + rule, err = r.UpsertRecordingRule(ctx, connect.NewRequest(&settingsv1.UpsertRecordingRuleRequest{ + Id: storeRule2.Id, + MetricName: storeRule2.MetricName, + Matchers: storeRule2.Matchers, + GroupBy: storeRule2.GroupBy, + Generation: storeRule2.Generation, + ExternalLabels: storeRule2.ExternalLabels, + StacktraceFilter: storeRule2.StacktraceFilter, + })) + require.NoError(t, err) + require.Equal(t, storeRule2, rule.Msg.Rule) + }) + + t.Run("Get overridden rule from config", func(t *testing.T) { + resp, err := r.GetRecordingRule(ctx, connect.NewRequest(&settingsv1.GetRecordingRuleRequest{Id: storeRule2.Id})) + require.NoError(t, err) + require.NotEqual(t, storeRule2, configRule1) + require.Equal(t, configRule1, resp.Msg.Rule) + }) + + t.Run("List rules with overrides", func(t *testing.T) { + resp, err := r.ListRecordingRules(ctx, connect.NewRequest(&settingsv1.ListRecordingRulesRequest{})) + require.NoError(t, err) + require.EqualValues(t, resp.Msg.Rules, []*settingsv1.RecordingRule{ + configRule1, + configRule2, + storeRule1, + // No storeRule2 as it's overridden by configRule1 + }) + }) + + t.Run("Upsert overridden rule just changes the original", func(t *testing.T) { + upsertedRule, err := r.UpsertRecordingRule(ctx, connect.NewRequest(&settingsv1.UpsertRecordingRuleRequest{ + Id: storeRule2.Id, + MetricName: storeRule2.MetricName, + Matchers: storeRule2.Matchers, + GroupBy: storeRule2.GroupBy, + Generation: storeRule2.Generation, + ExternalLabels: storeRule2.ExternalLabels, + StacktraceFilter: storeRule2.StacktraceFilter, + })) + storeRule2.Generation++ + require.NoError(t, err) + require.Equal(t, storeRule2, upsertedRule.Msg.Rule) + + rule, err := r.GetRecordingRule(ctx, connect.NewRequest(&settingsv1.GetRecordingRuleRequest{Id: storeRule2.Id})) + require.NoError(t, err) + require.Equal(t, configRule1, rule.Msg.Rule) + }) + + t.Run("Delete store rules", func(t *testing.T) { + _, err := r.DeleteRecordingRule(ctx, connect.NewRequest(&settingsv1.DeleteRecordingRuleRequest{Id: storeRule1.Id})) + require.NoError(t, err) + _, err = r.DeleteRecordingRule(ctx, connect.NewRequest(&settingsv1.DeleteRecordingRuleRequest{Id: storeRule2.Id})) + require.NoError(t, err) + resp, err := r.ListRecordingRules(ctx, connect.NewRequest(&settingsv1.ListRecordingRulesRequest{})) + require.NoError(t, err) + require.EqualValues(t, resp.Msg.Rules, []*settingsv1.RecordingRule{ + configRule1, + configRule2, + }) + }) + + t.Run("Can't delete config rules", func(t *testing.T) { + _, err := r.DeleteRecordingRule(ctx, connect.NewRequest(&settingsv1.DeleteRecordingRuleRequest{Id: configRule1.Id})) + + require.EqualError(t, err, fmt.Sprintf("not_found: no rule with ID='%s' found", configRule1.Id)) + }) + +} + +func upsertReqFromRule(rule *settingsv1.RecordingRule) *settingsv1.UpsertRecordingRuleRequest { + return &settingsv1.UpsertRecordingRuleRequest{ + Id: rule.Id, + MetricName: rule.MetricName, + Matchers: rule.Matchers, + GroupBy: rule.GroupBy, + Generation: rule.Generation, + ExternalLabels: rule.ExternalLabels, + StacktraceFilter: rule.StacktraceFilter, + } +} + +func TestRecordingRules_MaxRecordingRules(t *testing.T) { + const testUser = "user1" + + r := newTestRecordingRules(t, validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + limits := validation.MockDefaultLimits() + limits.MaxRecordingRules = 2 + tenantLimits[testUser] = limits + })) + + ctx := user.InjectOrgID(context.Background(), testUser) + + rule1, rule2 := RandomRule(), RandomRule() + + t.Run("can create up to the limit", func(t *testing.T) { + _, err := r.UpsertRecordingRule(ctx, connect.NewRequest(upsertReqFromRule(rule1))) + require.NoError(t, err) + _, err = r.UpsertRecordingRule(ctx, connect.NewRequest(upsertReqFromRule(rule2))) + require.NoError(t, err) + }) + + t.Run("creating beyond the limit is rejected", func(t *testing.T) { + _, err := r.UpsertRecordingRule(ctx, connect.NewRequest(upsertReqFromRule(RandomRule()))) + require.Error(t, err) + require.Equal(t, connect.CodeResourceExhausted, connect.CodeOf(err)) + }) + + t.Run("updating an existing rule at the limit is allowed", func(t *testing.T) { + req := upsertReqFromRule(rule1) + req.Generation = 1 // matches stored generation + _, err := r.UpsertRecordingRule(ctx, connect.NewRequest(req)) + require.NoError(t, err) + }) + + t.Run("creating again after deleting a rule is allowed", func(t *testing.T) { + _, err := r.DeleteRecordingRule(ctx, connect.NewRequest(&settingsv1.DeleteRecordingRuleRequest{Id: rule2.Id})) + require.NoError(t, err) + _, err = r.UpsertRecordingRule(ctx, connect.NewRequest(upsertReqFromRule(RandomRule()))) + require.NoError(t, err) + }) +} + +const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func RandomString(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letters[rand.IntN(len(letters))] + } + return string(b) +} + +func RandomRule() *settingsv1.RecordingRule { + profileType := RandomString(5) + matchers := make([]string, rand.IntN(3)) + for i := range matchers { + matchers[i] = fmt.Sprintf(`{ %s = "%s" }`, RandomString(5), RandomString(5)) + } + matchers = append(matchers, fmt.Sprintf(`{ __profile_type__ = "%s" }`, profileType)) + groupBy := make([]string, rand.IntN(2)+1) + for i := range groupBy { + groupBy[i] = RandomString(5) + } + externalLabels := make([]*typesv1.LabelPair, rand.IntN(2)+1) + for i := range externalLabels { + externalLabels[i] = &typesv1.LabelPair{ + Name: RandomString(5), + Value: RandomString(5), + } + } + var functionFilter *settingsv1.StacktraceFilter + if rand.IntN(2) == 1 { + functionFilter = &settingsv1.StacktraceFilter{ + FunctionName: &settingsv1.StacktraceFilterFunctionName{ + FunctionName: RandomString(5), + }, + } + } + return &settingsv1.RecordingRule{ + Id: RandomString(10), + MetricName: "profiles_recorded_" + RandomString(5), + ProfileType: profileType, + Matchers: matchers, + GroupBy: groupBy, + Generation: 1, + ExternalLabels: externalLabels, + StacktraceFilter: functionFilter, + } +} diff --git a/pkg/settings/recording/store.go b/pkg/settings/recording/store.go new file mode 100644 index 0000000000..3d614ca711 --- /dev/null +++ b/pkg/settings/recording/store.go @@ -0,0 +1,120 @@ +package recording + +import ( + "context" + "encoding/json" + "fmt" + + "connectrpc.com/connect" + "github.com/go-kit/log" + "github.com/thanos-io/objstore" + "google.golang.org/protobuf/encoding/protojson" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + "github.com/grafana/pyroscope/v2/pkg/settings/store" +) + +func newBucketStore(logger log.Logger, bucket objstore.Bucket, key store.Key) *bucketStore { + bs := &bucketStore{ + logger: logger, + } + + bs.store = store.New(logger, bucket, key, &storeHelper{ + b: bs, + }) + return bs +} + +type bucketStore struct { + logger log.Logger + store *store.GenericStore[*settingsv1.RecordingRuleStore, *storeHelper] +} + +func (b *bucketStore) Get(ctx context.Context, id string) (*settingsv1.RecordingRuleStore, error) { + var rule *settingsv1.RecordingRuleStore + err := b.store.Read(ctx, func(ctx context.Context, c *store.Collection[*settingsv1.RecordingRuleStore]) error { + for _, r := range c.Elements { + if r.Id != id { + continue + } + + rule = r + break + } + return nil + }) + if err != nil { + return nil, err + } + return rule, nil +} + +func (b *bucketStore) List(ctx context.Context) (*settingsv1.RecordingRulesStore, error) { + var rules *settingsv1.RecordingRulesStore + err := b.store.Read(ctx, func(ctx context.Context, c *store.Collection[*settingsv1.RecordingRuleStore]) error { + rules = &settingsv1.RecordingRulesStore{ + Rules: c.Elements, + Generation: c.Generation, + } + return nil + }) + if err != nil { + return nil, err + } + + return rules, nil +} + +// Upsert inserts or updates newRule. maxRules caps the number of rules that can +// be stored for the tenant; 0 disables the limit. The cap only applies when a +// new rule would be created, not when an existing rule is updated. +func (b *bucketStore) Upsert(ctx context.Context, newRule *settingsv1.RecordingRuleStore, maxRules int) (*settingsv1.RecordingRuleStore, error) { + err := b.store.Upsert(ctx, newRule, &newRule.Generation, maxRules) + if err != nil { + return nil, err + } + + return newRule, nil +} + +func (b *bucketStore) Delete(ctx context.Context, ruleID string) error { + err := b.store.Delete(ctx, ruleID) + if err == store.ErrElementNotFound { + return connect.NewError(connect.CodeNotFound, fmt.Errorf("no rule with ID='%s' found", ruleID)) + } + return nil +} + +type storeHelper struct { + b *bucketStore +} + +func (*storeHelper) SetGeneration(rule *settingsv1.RecordingRuleStore, generation int64) { + rule.Generation = generation +} + +func (*storeHelper) GetGeneration(rule *settingsv1.RecordingRuleStore) int64 { + return rule.Generation +} + +func (*storeHelper) FromStore(storeBytes json.RawMessage) (*settingsv1.RecordingRuleStore, error) { + var store settingsv1.RecordingRuleStore + err := protojson.Unmarshal(storeBytes, &store) + if err != nil { + return nil, fmt.Errorf("error unmarshaling json from store: %w", err) + } + + return &store, nil +} + +func (*storeHelper) ToStore(rule *settingsv1.RecordingRuleStore) (json.RawMessage, error) { + return protojson.Marshal(rule) +} + +func (*storeHelper) ID(rule *settingsv1.RecordingRuleStore) string { + return rule.Id +} + +func (*storeHelper) TypePath() string { + return "settings/recording_rule.v1" +} diff --git a/pkg/settings/setting_test.go b/pkg/settings/setting_test.go index 58bf0d7a72..a4440ec107 100644 --- a/pkg/settings/setting_test.go +++ b/pkg/settings/setting_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "testing" + "time" "connectrpc.com/connect" "github.com/go-kit/log" @@ -11,7 +12,7 @@ import ( "github.com/stretchr/testify/require" settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" - "github.com/grafana/pyroscope/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) func TestTenantSettings_Get(t *testing.T) { @@ -260,11 +261,128 @@ func TestTenantSettings_Set(t *testing.T) { }) } +func TestTenantSettings_Delete(t *testing.T) { + t.Run("delete a setting", func(t *testing.T) { + const tenantID = "1234" + initialSetting := &settingsv1.Setting{ + Name: "key1", + Value: "val1", + ModifiedAt: 100, + } + + ts, cleanup := newTestTenantSettings(t, map[string][]*settingsv1.Setting{ + tenantID: { + initialSetting, + }, + }) + defer cleanup() + + ctx := tenant.InjectTenantID(context.Background(), tenantID) + req := &connect.Request[settingsv1.DeleteSettingsRequest]{ + Msg: &settingsv1.DeleteSettingsRequest{ + Name: initialSetting.Name, + }, + } + + got, err := ts.Delete(ctx, req) + require.NoError(t, err) + + want := &settingsv1.DeleteSettingsResponse{} + require.Equal(t, want, got.Msg) + }) + + t.Run("missing tenant id", func(t *testing.T) { + ts, cleanup := newTestTenantSettings(t, map[string][]*settingsv1.Setting{}) + defer cleanup() + + ctx := context.Background() + req := &connect.Request[settingsv1.DeleteSettingsRequest]{ + Msg: &settingsv1.DeleteSettingsRequest{ + Name: "key1", + }, + } + + _, err := ts.Delete(ctx, req) + require.EqualError(t, err, "invalid_argument: no org id") + }) + + t.Run("missing setting name", func(t *testing.T) { + const tenantID = "1234" + + ts, cleanup := newTestTenantSettings(t, map[string][]*settingsv1.Setting{}) + defer cleanup() + + ctx := tenant.InjectTenantID(context.Background(), tenantID) + req := &connect.Request[settingsv1.DeleteSettingsRequest]{ + Msg: &settingsv1.DeleteSettingsRequest{ + Name: "", // Purposely empty + }, + } + + _, err := ts.Delete(ctx, req) + require.EqualError(t, err, "invalid_argument: no setting name provided") + }) + + t.Run("out of order", func(t *testing.T) { + const tenantID = "1234" + initialSetting := &settingsv1.Setting{ + Name: "key1", + Value: "val1", + + // Set to some point in the future to make subsequent deletes come + // in out of order. + ModifiedAt: time.Now().Add(12 * time.Hour).UnixMilli(), + } + + ts, cleanup := newTestTenantSettings(t, map[string][]*settingsv1.Setting{ + tenantID: { + initialSetting, + }, + }) + defer cleanup() + + ctx := tenant.InjectTenantID(context.Background(), tenantID) + req := &connect.Request[settingsv1.DeleteSettingsRequest]{ + Msg: &settingsv1.DeleteSettingsRequest{ + Name: initialSetting.Name, + }, + } + + _, err := ts.Delete(ctx, req) + require.EqualError(t, err, "already_exists: failed to delete key1: newer update already written") + }) + + t.Run("settings store returns error", func(t *testing.T) { + store := &fakeStore{} + wantErr := fmt.Errorf("settings store failed") + + // Get method fails once. + store.On("Delete", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(wantErr). + Once() + + ts := &TenantSettings{ + store: store, + logger: log.NewNopLogger(), + } + + ctx := tenant.InjectTenantID(context.Background(), "1234") + req := &connect.Request[settingsv1.DeleteSettingsRequest]{ + Msg: &settingsv1.DeleteSettingsRequest{ + Name: "key1", + }, + } + + _, err := ts.Delete(ctx, req) + require.EqualError(t, err, fmt.Sprintf("internal: %s", wantErr)) + }) +} + func newTestTenantSettings(t *testing.T, initial map[string][]*settingsv1.Setting) (*TenantSettings, func()) { t.Helper() - store, err := NewMemoryStore() - require.NoError(t, err) + store := newMemoryStore() + var err error for tenant, settings := range initial { for _, setting := range settings { @@ -307,8 +425,8 @@ func (s *fakeStore) Set(ctx context.Context, tenantID string, setting *settingsv return args.Get(0).(*settingsv1.Setting), args.Error(1) } -func (s *fakeStore) Flush(ctx context.Context) error { - args := s.Called(ctx) +func (s *fakeStore) Delete(ctx context.Context, tenantID string, name string, modifiedAtMs int64) error { + args := s.Called(ctx, tenantID, name, modifiedAtMs) return args.Error(0) } diff --git a/pkg/settings/settings.go b/pkg/settings/settings.go index be4c700b14..91067ab74a 100644 --- a/pkg/settings/settings.go +++ b/pkg/settings/settings.go @@ -2,6 +2,8 @@ package settings import ( "context" + "errors" + "flag" "fmt" "time" @@ -10,15 +12,44 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/services" "github.com/grafana/dskit/tenant" - "github.com/pkg/errors" + "github.com/thanos-io/objstore" settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1/settingsv1connect" + "github.com/grafana/pyroscope/v2/pkg/settings/recording" + "github.com/grafana/pyroscope/v2/pkg/validation" ) -func New(store Store, logger log.Logger) (*TenantSettings, error) { +type Config struct { + Recording recording.Config `yaml:"recording_rules"` +} + +func (cfg *Config) RegisterFlags(fs *flag.FlagSet) { + cfg.Recording.RegisterFlags(fs) +} + +func (cfg *Config) Validate() error { + return errors.Join( + cfg.Recording.Validate(), + ) +} + +var _ settingsv1connect.SettingsServiceHandler = (*TenantSettings)(nil) + +func New(cfg Config, bucket objstore.Bucket, logger log.Logger, overrides *validation.Overrides) (*TenantSettings, error) { + if bucket == nil { + bucket = objstore.NewInMemBucket() + level.Warn(logger).Log("msg", "using in-memory settings store, changes will be lost after shutdown") + } + ts := &TenantSettings{ - store: store, - logger: logger, + RecordingRulesServiceHandler: &settingsv1connect.UnimplementedRecordingRulesServiceHandler{}, + store: newBucketStore(bucket), + logger: logger, + } + + if cfg.Recording.Enabled { + ts.RecordingRulesServiceHandler = recording.New(bucket, logger, overrides) } ts.Service = services.NewBasicService(ts.starting, ts.running, ts.stopping) @@ -28,8 +59,9 @@ func New(store Store, logger log.Logger) (*TenantSettings, error) { type TenantSettings struct { services.Service + settingsv1connect.RecordingRulesServiceHandler - store Store + store store logger log.Logger } @@ -38,45 +70,22 @@ func (ts *TenantSettings) starting(ctx context.Context) error { } func (ts *TenantSettings) running(ctx context.Context) error { - ticker := time.NewTicker(24 * time.Hour) - done := false - - for !done { - select { - case <-ticker.C: - err := ts.store.Flush(ctx) - if err != nil { - level.Warn(ts.logger).Log( - "msg", "failed to refresh tenant settings", - "err", err, - ) - } - case <-ctx.Done(): - ticker.Stop() - done = true - } - } - + <-ctx.Done() return nil } func (ts *TenantSettings) stopping(_ error) error { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - err := ts.store.Flush(ctx) - if err != nil { - return err - } - - err = ts.store.Close() + err := ts.store.Close() if err != nil { return err } return nil } -func (ts *TenantSettings) Get(ctx context.Context, req *connect.Request[settingsv1.GetSettingsRequest]) (*connect.Response[settingsv1.GetSettingsResponse], error) { +func (ts *TenantSettings) Get( + ctx context.Context, + req *connect.Request[settingsv1.GetSettingsRequest], +) (*connect.Response[settingsv1.GetSettingsResponse], error) { tenantID, err := tenant.TenantID(ctx) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) @@ -92,7 +101,10 @@ func (ts *TenantSettings) Get(ctx context.Context, req *connect.Request[settings }), nil } -func (ts *TenantSettings) Set(ctx context.Context, req *connect.Request[settingsv1.SetSettingsRequest]) (*connect.Response[settingsv1.SetSettingsResponse], error) { +func (ts *TenantSettings) Set( + ctx context.Context, + req *connect.Request[settingsv1.SetSettingsRequest], +) (*connect.Response[settingsv1.SetSettingsResponse], error) { tenantID, err := tenant.TenantID(ctx) if err != nil { return nil, connect.NewError(connect.CodeInvalidArgument, err) @@ -108,7 +120,7 @@ func (ts *TenantSettings) Set(ctx context.Context, req *connect.Request[settings setting, err := ts.store.Set(ctx, tenantID, req.Msg.Setting) if err != nil { - if errors.Is(err, oldSettingErr) { + if errors.Is(err, errOldSetting) { return nil, connect.NewError(connect.CodeAlreadyExists, err) } return nil, connect.NewError(connect.CodeInternal, err) @@ -118,3 +130,25 @@ func (ts *TenantSettings) Set(ctx context.Context, req *connect.Request[settings Setting: setting, }), nil } + +func (ts *TenantSettings) Delete(ctx context.Context, req *connect.Request[settingsv1.DeleteSettingsRequest]) (*connect.Response[settingsv1.DeleteSettingsResponse], error) { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + if req.Msg == nil || req.Msg.Name == "" { + return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("no setting name provided")) + } + + modifiedAt := time.Now().UnixMilli() + err = ts.store.Delete(ctx, tenantID, req.Msg.Name, modifiedAt) + if err != nil { + if errors.Is(err, errOldSetting) { + return nil, connect.NewError(connect.CodeAlreadyExists, err) + } + return nil, connect.NewError(connect.CodeInternal, err) + } + + return connect.NewResponse(&settingsv1.DeleteSettingsResponse{}), nil +} diff --git a/pkg/settings/store.go b/pkg/settings/store.go index 1c24291436..96e2ebc02f 100644 --- a/pkg/settings/store.go +++ b/pkg/settings/store.go @@ -6,15 +6,15 @@ import ( settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" ) -type Store interface { +type store interface { // Get settings for a tenant. Get(ctx context.Context, tenantID string) ([]*settingsv1.Setting, error) // Set a setting for a tenant. Set(ctx context.Context, tenantID string, setting *settingsv1.Setting) (*settingsv1.Setting, error) - // Flush the store to disk. - Flush(ctx context.Context) error + // Delete a setting for a tenant. + Delete(ctx context.Context, tenantID string, name string, modifiedAtMs int64) error // Close the store. Close() error diff --git a/pkg/settings/store/store.go b/pkg/settings/store/store.go new file mode 100644 index 0000000000..fdf09f900a --- /dev/null +++ b/pkg/settings/store/store.go @@ -0,0 +1,305 @@ +package store + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "path/filepath" + "strconv" + "sync" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/thanos-io/objstore" +) + +type Key struct { + TenantID string +} + +var ErrElementNotFound = errors.New("element not found") + +// ErrMaxElementsExceeded is returned by Upsert when inserting a new element +// would exceed the configured maximum number of elements in the collection. +type ErrMaxElementsExceeded struct { + Max int +} + +func (e ErrMaxElementsExceeded) Error() string { + return fmt.Sprintf("maximum number of elements reached: limit=%d", e.Max) +} + +type ErrConflictGeneration struct { + ObservedGeneration int64 + StoreGeneration int64 +} + +func (e ErrConflictGeneration) Error() string { + return fmt.Sprintf("conflicting update, please try again: observed_generation=%d, store_generation=%d", e.ObservedGeneration, e.StoreGeneration) +} + +type StoreHelper[T any] interface { + ID(T) string + GetGeneration(T) int64 + SetGeneration(T, int64) + FromStore(json.RawMessage) (T, error) + ToStore(T) (json.RawMessage, error) + TypePath() string +} + +type Collection[T any] struct { + Generation int64 + Elements []T +} + +type GenericStore[T any, H StoreHelper[T]] struct { + logger log.Logger + bucket objstore.Bucket + helper H + path string + + cacheLock sync.RWMutex + cache *Collection[T] +} + +func New[T any, H StoreHelper[T]]( + logger log.Logger, bucket objstore.Bucket, key Key, helper H, +) *GenericStore[T, H] { + return &GenericStore[T, H]{ + logger: logger, + bucket: bucket, + helper: helper, + path: filepath.Join(key.TenantID, helper.TypePath()) + ".json", + } +} + +// ReadTxn is a transaction that runs under the read lock of the cache. The Collection should not be mutated at all. +type ReadTxn[T any] func(context.Context, *Collection[T]) error + +func (s *GenericStore[T, H]) Read(ctx context.Context, txn ReadTxn[T]) error { + // serve from cache if available + s.cacheLock.RLock() + if s.cache != nil { + defer s.cacheLock.RUnlock() + return txn(ctx, s.cache) + } + s.cacheLock.RUnlock() + + // get write lock and fetch from bucket + s.cacheLock.Lock() + defer s.cacheLock.Unlock() + + // check again if cache is available in the meantime + if s.cache != nil { + return txn(ctx, s.cache) + } + + // load from bucket + if err := s.unsafeLoadCache(ctx); err != nil { + return err + } + + return txn(ctx, s.cache) +} + +func (s *GenericStore[T, H]) Get(ctx context.Context) (*Collection[T], error) { + var result *Collection[T] + err := s.Read(ctx, func(ctx context.Context, coll *Collection[T]) error { + result = coll + return nil + }) + if err != nil { + return nil, err + } + return result, nil + +} + +func (s *GenericStore[T, H]) Delete(ctx context.Context, id string) error { + return s.Update(ctx, func(_ context.Context, coll *Collection[T]) error { + // iterate over the rules to find the rule + for idx, e := range coll.Elements { + if s.helper.ID(e) == id { + // delete the rule + coll.Elements = append(coll.Elements[:idx], coll.Elements[idx+1:]...) + + // return early and save the ruleset + return nil + } + } + return ErrElementNotFound + }) +} + +// Upsert inserts or updates elem in the collection. If maxElements is greater +// than 0, inserting a new element is rejected with ErrMaxElementsExceeded once +// the collection already holds maxElements elements. Updates to an existing +// element are never affected by maxElements. The check runs inside the write +// transaction, so the limit is enforced atomically against concurrent upserts. +func (s *GenericStore[T, H]) Upsert(ctx context.Context, elem T, observedGeneration *int64, maxElements int) error { + return s.Update(ctx, func(_ context.Context, coll *Collection[T]) error { + // iterate over the store list to find the element with the same idx + pos := -1 + for idx, e := range coll.Elements { + if s.helper.ID(e) == s.helper.ID(elem) { + pos = idx + } + } + + // new element required + if pos == -1 { + if maxElements > 0 && len(coll.Elements) >= maxElements { + return &ErrMaxElementsExceeded{Max: maxElements} + } + + // create a new rule + coll.Elements = append(coll.Elements, elem) + + // by definition, the generation of a new element is 1 + s.helper.SetGeneration(elem, 1) + + return nil + } + + // check if there had been a conflicted updated + storedElem := coll.Elements[pos] + storedGeneration := s.helper.GetGeneration(storedElem) + if observedGeneration != nil && *observedGeneration != storedGeneration { + level.Warn(s.logger).Log( + "msg", "conflicting update, please try again", + "observed_generation", observedGeneration, + "stored_generation", storedGeneration, + ) + + return &ErrConflictGeneration{ + ObservedGeneration: *observedGeneration, + StoreGeneration: storedGeneration, + } + } + + s.helper.SetGeneration(elem, storedGeneration+1) + coll.Elements[pos] = elem + + return nil + }) +} + +type UpdateTxn[T any] func(context.Context, *Collection[T]) error + +// Update will under write lock, call a transaction the Collection. If there is an error returned, the update will be cancelled. +func (s *GenericStore[T, H]) Update( + ctx context.Context, + txn UpdateTxn[T], +) error { + // get write lock and fetch from bucket + s.cacheLock.Lock() + defer s.cacheLock.Unlock() + + // ensure we have the latest data + data, err := s.getFromBucket(ctx) + if err != nil { + return err + } + + // call callback + if err := txn(ctx, data); err != nil { + return err + } + + // save the changes + return s.unsafeFlush(ctx, data) +} + +type storeStruct struct { + Generation string `json:"generation"` + Elements []json.RawMessage `json:"elements,omitempty"` + ElementsCompat []json.RawMessage `json:"rules,omitempty"` +} + +func (s *GenericStore[T, H]) getFromBucket(ctx context.Context) (*Collection[T], error) { + // fetch from bucket + r, err := s.bucket.Get(ctx, s.path) + if s.bucket.IsObjNotFoundErr(err) { + return &Collection[T]{ + Elements: make([]T, 0), + }, nil + } + if err != nil { + return nil, err + } + defer func() { + _ = r.Close() + }() + + var storeStruct storeStruct + if err := json.NewDecoder(r).Decode(&storeStruct); err != nil { + return nil, err + } + + // handle compatibility with old model + if len(storeStruct.Elements) == 0 { + storeStruct.Elements = storeStruct.ElementsCompat + } + + var ( + result = make([]T, len(storeStruct.Elements)) + ) + for idx, element := range storeStruct.Elements { + result[idx], err = s.helper.FromStore(element) + if err != nil { + return nil, err + } + } + + generation, err := strconv.ParseInt(storeStruct.Generation, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid generation: %s", storeStruct.Generation) + } + + return &Collection[T]{ + Generation: generation, + Elements: result, + }, nil +} + +// unsafeLoad reads from bucket into the cache, only call with write lock held +func (s *GenericStore[T, H]) unsafeLoadCache(ctx context.Context) error { + // fetch from bucket + data, err := s.getFromBucket(ctx) + if err != nil { + return err + } + + s.cache = data + return nil +} + +// unsafeFlush writes from arguments into the bucket and then reset cache. Only call with write lock held +func (s *GenericStore[T, H]) unsafeFlush(ctx context.Context, coll *Collection[T]) error { + var ( + data = storeStruct{ + Elements: make([]json.RawMessage, len(coll.Elements)), + Generation: strconv.FormatInt(coll.Generation+1, 10), + } + err error + ) + for idx, element := range coll.Elements { + data.Elements[idx], err = s.helper.ToStore(element) + if err != nil { + return err + } + } + + dataJson, err := json.Marshal(data) + if err != nil { + return err + } + + // reset cache + s.cache = nil + + // write to bucket + return s.bucket.Upload(ctx, s.path, bytes.NewReader(dataJson)) +} diff --git a/pkg/settings/store/store_test.go b/pkg/settings/store/store_test.go new file mode 100644 index 0000000000..39afe54026 --- /dev/null +++ b/pkg/settings/store/store_test.go @@ -0,0 +1,220 @@ +package store + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "testing" + + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + + "github.com/go-kit/log" + "github.com/stretchr/testify/require" +) + +type testObj struct { + Name string + Data string + Generation int64 +} + +const storeJSON = `{ + "generation":"4", + "elements":[ + {"Name":"a","Data":"data-a-v3","Generation":3}, + {"Name":"b","Data":"data-b","Generation":1} + ] +}` + +type testObjHelper struct{} + +func (*testObjHelper) ID(o *testObj) string { + return o.Name +} + +func (*testObjHelper) GetGeneration(o *testObj) int64 { + return o.Generation +} + +func (*testObjHelper) SetGeneration(o *testObj, gen int64) { + o.Generation = gen +} + +func (*testObjHelper) FromStore(data json.RawMessage) (*testObj, error) { + var obj testObj + err := json.Unmarshal(data, &obj) + return &obj, err +} + +func (*testObjHelper) ToStore(obj *testObj) (json.RawMessage, error) { + return json.Marshal(obj) +} + +func (*testObjHelper) TypePath() string { + return "testobj.v1" +} + +type testStore struct { + *GenericStore[*testObj, *testObjHelper] + bucketPath string +} + +func newTestStore(t testing.TB, tenantID string) *testStore { + logger := log.NewNopLogger() + if testing.Verbose() { + logger = log.NewLogfmtLogger(os.Stderr) + } + bucketPath := t.TempDir() + bucket, err := filesystem.NewBucket(bucketPath) + require.NoError(t, err) + return &testStore{ + GenericStore: New( + logger, + bucket, + Key{TenantID: tenantID}, + &testObjHelper{}, + ), + bucketPath: bucketPath, + } +} + +func Test_GenericStore(t *testing.T) { + s := newTestStore(t, "user-a") + ctx := context.Background() + + t.Run("empty", func(t *testing.T) { + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{}, result.Elements) + }) + + t.Run("one element", func(t *testing.T) { + require.NoError(t, s.Upsert(ctx, &testObj{Name: "a", Data: "data-a"}, nil, 0)) + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "a", Data: "data-a", Generation: 1}, + }, result.Elements) + }) + + t.Run("second element", func(t *testing.T) { + require.NoError(t, s.Upsert(ctx, &testObj{Name: "b", Data: "data-b"}, nil, 0)) + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "a", Data: "data-a", Generation: 1}, + {Name: "b", Data: "data-b", Generation: 1}, + }, result.Elements) + }) + + t.Run("update without generation", func(t *testing.T) { + require.NoError(t, s.Upsert(ctx, &testObj{Name: "a", Data: "data-a-v2"}, nil, 0)) + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "a", Data: "data-a-v2", Generation: 2}, + {Name: "b", Data: "data-b", Generation: 1}, + }, result.Elements) + }) + + t.Run("update with generation", func(t *testing.T) { + observedGeneration := int64(2) + require.NoError(t, s.Upsert(ctx, &testObj{Name: "a", Data: "data-a-v3"}, &observedGeneration, 0)) + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "a", Data: "data-a-v3", Generation: 3}, + {Name: "b", Data: "data-b", Generation: 1}, + }, result.Elements) + }) + + t.Run("validate stored data is as expected", func(t *testing.T) { + storePath := filepath.Join(s.bucketPath, "user-a/testobj.v1.json") + actual, err := os.ReadFile(storePath) + require.NoError(t, err) + require.JSONEq(t, storeJSON, string(actual)) + }) + + t.Run("restore from stored data", func(t *testing.T) { + newS := newTestStore(t, "user-b") + storePath := filepath.Join(newS.bucketPath, "user-b/testobj.v1.json") + require.NoError(t, os.MkdirAll(filepath.Dir(storePath), 0o755)) + require.NoError(t, os.WriteFile( + storePath, + []byte(storeJSON), + 0o644, + )) + result, err := newS.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "a", Data: "data-a-v3", Generation: 3}, + {Name: "b", Data: "data-b", Generation: 1}, + }, result.Elements) + }) + + t.Run("update with wrong generation", func(t *testing.T) { + observedGeneration := int64(2) + require.ErrorContains(t, s.Upsert(ctx, &testObj{Name: "a", Data: "data-a-v4"}, &observedGeneration, 0), "conflicting update, please try again: observed_generation=2, store_generation=3") + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "a", Data: "data-a-v3", Generation: 3}, + {Name: "b", Data: "data-b", Generation: 1}, + }, result.Elements) + }) + + t.Run("delete element that exists", func(t *testing.T) { + require.NoError(t, s.Delete(ctx, "a")) + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "b", Data: "data-b", Generation: 1}, + }, result.Elements) + }) + t.Run("delete element that doesnt exist", func(t *testing.T) { + require.ErrorContains(t, s.Delete(ctx, "c"), "element not found") + result, err := s.Get(ctx) + require.NoError(t, err) + require.Equal(t, []*testObj{ + {Name: "b", Data: "data-b", Generation: 1}, + }, result.Elements) + }) +} + +func Test_GenericStore_Upsert_MaxElements(t *testing.T) { + s := newTestStore(t, "user-a") + ctx := context.Background() + const max = 2 + + t.Run("insert up to the limit", func(t *testing.T) { + require.NoError(t, s.Upsert(ctx, &testObj{Name: "a", Data: "data-a"}, nil, max)) + require.NoError(t, s.Upsert(ctx, &testObj{Name: "b", Data: "data-b"}, nil, max)) + }) + + t.Run("inserting beyond the limit is rejected", func(t *testing.T) { + err := s.Upsert(ctx, &testObj{Name: "c", Data: "data-c"}, nil, max) + var mErr *ErrMaxElementsExceeded + require.ErrorAs(t, err, &mErr) + require.Equal(t, max, mErr.Max) + + // the rejected element was not stored + result, err := s.Get(ctx) + require.NoError(t, err) + require.Len(t, result.Elements, max) + }) + + t.Run("updating an existing element is allowed at the limit", func(t *testing.T) { + require.NoError(t, s.Upsert(ctx, &testObj{Name: "a", Data: "data-a-v2"}, nil, max)) + result, err := s.Get(ctx) + require.NoError(t, err) + require.Len(t, result.Elements, max) + }) + + t.Run("0 disables the limit", func(t *testing.T) { + require.NoError(t, s.Upsert(ctx, &testObj{Name: "c", Data: "data-c"}, nil, 0)) + result, err := s.Get(ctx) + require.NoError(t, err) + require.Len(t, result.Elements, 3) + }) +} diff --git a/pkg/slices/slices.go b/pkg/slices/slices.go index 70de8711f4..0afc7b9c46 100644 --- a/pkg/slices/slices.go +++ b/pkg/slices/slices.go @@ -1,5 +1,9 @@ package slices +import ( + "slices" +) + // RemoveInPlace removes all elements from a slice that match the given predicate. // Does not allocate a new slice. func RemoveInPlace[T any](collection []T, predicate func(T, int) bool) []T { @@ -27,9 +31,5 @@ func Clear[S ~[]E, E any](s S) { } func GrowLen[S ~[]E, E any](s S, n int) S { - if cap(s) < n { - s = make([]E, n) - } - s = s[:n] - return s + return slices.Grow(s[:0], n)[:n] } diff --git a/pkg/storegateway/block.go b/pkg/storegateway/block.go index c7279b3dad..07593d50c6 100644 --- a/pkg/storegateway/block.go +++ b/pkg/storegateway/block.go @@ -2,15 +2,16 @@ package storegateway import ( "context" + "errors" + "fmt" "os" "path" "path/filepath" "github.com/go-kit/log" - "github.com/pkg/errors" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) type BlockCloser interface { @@ -29,7 +30,7 @@ func (bs *BucketStore) createBlock(ctx context.Context, meta *block.Meta) (*Bloc // add the dir if it doesn't exist if _, err := os.Stat(blockLocalPath); errors.Is(err, os.ErrNotExist) { if err := os.MkdirAll(blockLocalPath, 0o750); err != nil { - return nil, errors.Wrap(err, "create dir") + return nil, fmt.Errorf("create dir: %w", err) } } metaPath := filepath.Join(blockLocalPath, block.MetaFilename) @@ -38,26 +39,26 @@ func (bs *BucketStore) createBlock(ctx context.Context, meta *block.Meta) (*Bloc // fetch the meta from the bucket r, err := bs.bucket.Get(ctx, path.Join(meta.ULID.String(), block.MetaFilename)) if err != nil { - return nil, errors.Wrap(err, "get meta") + return nil, fmt.Errorf("get meta: %w", err) } meta, err := block.Read(r) if err != nil { - return nil, errors.Wrap(err, "read meta") + return nil, fmt.Errorf("read meta: %w", err) } // add meta.json if it does not exist if _, err := meta.WriteToFile(bs.logger, blockLocalPath); err != nil { - return nil, errors.Wrap(err, "write meta.json") + return nil, fmt.Errorf("write meta.json: %w", err) } outMeta = meta.Clone() } else { // read meta.json if it exists and validate it diskMeta, _, err := block.MetaFromDir(blockLocalPath) if err != nil { - return nil, errors.Wrap(err, "read meta.json") + return nil, fmt.Errorf("read meta.json: %w", err) } if meta.ULID.String() != diskMeta.ULID.String() { - return nil, errors.Wrap(err, "meta.json does not match") + return nil, fmt.Errorf("meta.json does not match") } outMeta = diskMeta.Clone() diff --git a/pkg/storegateway/block_filter.go b/pkg/storegateway/block_filter.go index 58f6162e01..8c2ee7818f 100644 --- a/pkg/storegateway/block_filter.go +++ b/pkg/storegateway/block_filter.go @@ -2,18 +2,18 @@ package storegateway import ( "context" + "errors" "time" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/ring" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/prometheus/model/timestamp" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/bucketindex" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucketindex" ) const ( diff --git a/pkg/storegateway/blocks.gohtml b/pkg/storegateway/blocks.gohtml index 9ee8101dd4..95d1f8dbc8 100644 --- a/pkg/storegateway/blocks.gohtml +++ b/pkg/storegateway/blocks.gohtml @@ -1,6 +1,6 @@ -{{- /*gotype: github.com/grafana/pyroscope/pkg/storegateway.blocksPageContents*/ -}} +{{- /*gotype: github.com/grafana/pyroscope/v2/pkg/storegateway.blocksPageContents*/ -}} - + Store-gateway: bucket tenant blocks diff --git a/pkg/storegateway/bucket.go b/pkg/storegateway/bucket.go index 60dffd8e7b..c8a8c951b9 100644 --- a/pkg/storegateway/bucket.go +++ b/pkg/storegateway/bucket.go @@ -2,6 +2,7 @@ package storegateway import ( "context" + "fmt" "os" "path" "path/filepath" @@ -11,14 +12,13 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/phlaredb/block" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" ) // TODO move this to a config. @@ -61,7 +61,7 @@ func NewBucketStore(bucket phlareobj.Bucket, fetcher block.MetadataFetcher, tena } if err := os.MkdirAll(syncDir, 0o750); err != nil { - return nil, errors.Wrap(err, "create dir") + return nil, fmt.Errorf("create dir: %w", err) } return s, nil @@ -69,12 +69,12 @@ func NewBucketStore(bucket phlareobj.Bucket, fetcher block.MetadataFetcher, tena func (b *BucketStore) InitialSync(ctx context.Context) error { if err := b.SyncBlocks(ctx); err != nil { - return errors.Wrap(err, "sync block") + return fmt.Errorf("sync block: %w", err) } fis, err := os.ReadDir(b.syncDir) if err != nil { - return errors.Wrap(err, "read dir") + return fmt.Errorf("read dir: %w", err) } names := make([]string, 0, len(fis)) for _, fi := range fis { @@ -183,7 +183,7 @@ func (bs *BucketStore) addBlock(ctx context.Context, meta *block.Meta) (err erro ctx = phlaredb.ContextWithBlockMetrics(ctx, bs.metrics.blockMetrics) b, err := bs.createBlock(ctx, meta) if err != nil { - return nil, errors.Wrap(err, "load block from disk") + return nil, fmt.Errorf("load block from disk: %w", err) } bs.blockSet.add(b) bs.blocks[meta.ULID] = b @@ -240,10 +240,10 @@ func (s *BucketStore) removeBlock(id ulid.ULID) (returnErr error) { s.metrics.blockDrops.Inc() if err := b.Close(); err != nil { - return errors.Wrap(err, "close block") + return fmt.Errorf("close block: %w", err) } if err := os.RemoveAll(s.localPath(id.String())); err != nil { - return errors.Wrap(err, "delete block") + return fmt.Errorf("delete block: %w", err) } return nil } @@ -255,7 +255,7 @@ func (s *BucketStore) localPath(id string) string { // RemoveBlocksAndClose remove all blocks from local disk and releases all resources associated with the BucketStore. func (s *BucketStore) RemoveBlocksAndClose() error { if err := os.RemoveAll(s.syncDir); err != nil { - return errors.Wrap(err, "delete block") + return fmt.Errorf("delete block: %w", err) } return nil } diff --git a/pkg/storegateway/bucket_index_metadata_fetcher.go b/pkg/storegateway/bucket_index_metadata_fetcher.go index 36f383eea7..480ac0a411 100644 --- a/pkg/storegateway/bucket_index_metadata_fetcher.go +++ b/pkg/storegateway/bucket_index_metadata_fetcher.go @@ -7,17 +7,18 @@ package storegateway import ( "context" + "errors" + "fmt" "time" "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/oklog/ulid" - "github.com/pkg/errors" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" - "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/bucketindex" + "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucketindex" ) const ( @@ -107,7 +108,7 @@ func (f *BucketIndexMetadataFetcher) Fetch(ctx context.Context) (metas map[ulid. f.metrics.Synced.WithLabelValues(block.FailedMeta).Set(1) f.metrics.Submit() - return nil, nil, errors.Wrapf(err, "read bucket index") + return nil, nil, fmt.Errorf("read bucket index: %w", err) } // check if index is older than 1 hour, fallback to metafetcher @@ -146,7 +147,7 @@ func (f *BucketIndexMetadataFetcher) Fetch(ctx context.Context) (metas map[ulid. } if err != nil { - return nil, nil, errors.Wrap(err, "filter metas") + return nil, nil, fmt.Errorf("filter metas: %w", err) } } diff --git a/pkg/storegateway/bucket_index_metadata_fetcher_test.go b/pkg/storegateway/bucket_index_metadata_fetcher_test.go index fd625911b1..8fca12a201 100644 --- a/pkg/storegateway/bucket_index_metadata_fetcher_test.go +++ b/pkg/storegateway/bucket_index_metadata_fetcher_test.go @@ -15,17 +15,17 @@ import ( "github.com/go-kit/log" "github.com/grafana/dskit/concurrency" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore" - objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/bucketindex" + "github.com/grafana/pyroscope/v2/pkg/objstore" + objstore_testutil "github.com/grafana/pyroscope/v2/pkg/objstore/testutil" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucketindex" ) func TestBucketIndexMetadataFetcher_Fetch(t *testing.T) { diff --git a/pkg/storegateway/bucket_stores.go b/pkg/storegateway/bucket_stores.go index 97ba263e81..67a117ca3e 100644 --- a/pkg/storegateway/bucket_stores.go +++ b/pkg/storegateway/bucket_stores.go @@ -2,7 +2,9 @@ package storegateway import ( "context" + "errors" "flag" + "fmt" "os" "path/filepath" "sync" @@ -12,14 +14,14 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/backoff" "github.com/grafana/dskit/multierror" - "github.com/pkg/errors" + "github.com/grafana/dskit/tenant" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/phlaredb/bucket" - "github.com/grafana/pyroscope/pkg/util" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/bucket" + "github.com/grafana/pyroscope/v2/pkg/util" ) var errBucketStoreNotFound = errors.New("bucket store not found") @@ -137,9 +139,12 @@ func NewBucketStores(cfg BucketStoreConfig, shardingStrategy ShardingStrategy, s } // Register metrics. bs.syncTimes = promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ - Name: "pyroscope_bucket_stores_blocks_sync_seconds", - Help: "The total time it takes to perform a sync stores", - Buckets: []float64{0.1, 1, 10, 30, 60, 120, 300, 600, 900}, + Name: "pyroscope_bucket_stores_blocks_sync_seconds", + Help: "The total time it takes to perform a sync stores", + Buckets: []float64{0.1, 1, 10, 30, 60, 120, 300, 600, 900}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, }) bs.syncLastSuccess = promauto.With(reg).NewGauge(prometheus.GaugeOpts{ Name: "pyroscope_bucket_stores_blocks_last_successful_sync_timestamp_seconds", @@ -229,7 +234,7 @@ func (bs *BucketStores) syncUsersBlocks(ctx context.Context, f func(context.Cont ownedUserIDs, err := bs.shardingStrategy.FilterUsers(ctx, userIDs) if err != nil { - return errors.Wrap(err, "unable to check tenants owned by this store-gateway instance") + return fmt.Errorf("unable to check tenants owned by this store-gateway instance: %w", err) } includeUserIDs := make(map[string]struct{}, len(ownedUserIDs)) @@ -251,7 +256,7 @@ func (bs *BucketStores) syncUsersBlocks(ctx context.Context, f func(context.Cont for job := range jobs { if err := f(ctx, job.store); err != nil { errsMx.Lock() - errs.Add(errors.Wrapf(err, "failed to synchronize Pyroscope blocks for user %s", job.userID)) + errs.Add(fmt.Errorf("failed to synchronize Pyroscope blocks for user %s: %w", job.userID, err)) errsMx.Unlock() } } @@ -336,11 +341,15 @@ func (bs *BucketStores) getOrCreateStore(userID string) (*BucketStore, error) { filters, ) - s, err := NewBucketStore( + userSyncDir, err := bs.syncDirForUser(userID) + if err != nil { + return nil, err + } + s, err = NewBucketStore( bs.storageBucket, fetcher, userID, - bs.syncDirForUser(userID), + userSyncDir, userLogger, bs.reg, ) @@ -382,7 +391,11 @@ func (bs *BucketStores) closeBucketStoreAndDeleteLocalFilesForExcludedTenants(in level.Warn(bs.logger).Log("msg", "failed to close bucket store for user", "tenant", userID, "err", err) } - userSyncDir := bs.syncDirForUser(userID) + userSyncDir, err := bs.syncDirForUser(userID) + if err != nil { + level.Warn(bs.logger).Log("msg", "skipping delete of user sync directory", "tenant", userID, "err", err) + continue + } err = os.RemoveAll(userSyncDir) if err == nil { level.Info(bs.logger).Log("msg", "deleted user sync directory", "dir", userSyncDir) @@ -392,8 +405,11 @@ func (bs *BucketStores) closeBucketStoreAndDeleteLocalFilesForExcludedTenants(in } } -func (u *BucketStores) syncDirForUser(userID string) string { - return filepath.Join(u.cfg.SyncDir, userID) +func (u *BucketStores) syncDirForUser(userID string) (string, error) { + if err := tenant.ValidTenantID(userID); err != nil { + return "", fmt.Errorf("syncDirForUser: invalid userID: %w", err) + } + return filepath.Join(u.cfg.SyncDir, userID), nil } // closeBucketStore closes bucket store for given user diff --git a/pkg/storegateway/bucket_stores_test.go b/pkg/storegateway/bucket_stores_test.go index e490c5cf80..6d85d9fcac 100644 --- a/pkg/storegateway/bucket_stores_test.go +++ b/pkg/storegateway/bucket_stores_test.go @@ -10,18 +10,19 @@ import ( "time" "github.com/go-kit/log" - "github.com/oklog/ulid" + "github.com/oklog/ulid/v2" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/expfmt" + "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/test" - "github.com/grafana/pyroscope/pkg/validation" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/test" + "github.com/grafana/pyroscope/v2/pkg/validation" ) func TestBucketStores_BlockMetricsRegistration(t *testing.T) { @@ -113,7 +114,7 @@ func assertMetricsGathered(tb testing.TB, reg prometheus.Gatherer, gathered bool } } - var p expfmt.TextParser + p := expfmt.NewTextParser(model.UTF8Validation) for _, e := range expected { _, err = p.TextToMetricFamilies(strings.NewReader(e)) require.NoError(tb, err, "expected metric is not valid:\n%s", e) diff --git a/pkg/storegateway/clientpool/client_pool.go b/pkg/storegateway/clientpool/client_pool.go index d8400eb478..6cb676775d 100644 --- a/pkg/storegateway/clientpool/client_pool.go +++ b/pkg/storegateway/clientpool/client_pool.go @@ -16,7 +16,7 @@ import ( ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" "github.com/grafana/pyroscope/api/gen/proto/go/storegateway/v1/storegatewayv1connect" - "github.com/grafana/pyroscope/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) type BidiClientMergeProfilesStacktraces interface { @@ -67,7 +67,7 @@ func (f *poolFactory) FromInstance(inst ring.InstanceDesc) (ring_client.PoolClie return nil, err } - httpClient := util.InstrumentedDefaultHTTPClient(util.WithTracingTransport()) + httpClient := httputil.InstrumentedDefaultHTTPClient(httputil.WithTracingTransport(), httputil.WithBaggageTransport()) return &storeGatewayPoolClient{ StoreGatewayServiceClient: storegatewayv1connect.NewStoreGatewayServiceClient(httpClient, "http://"+inst.Addr, f.options...), HealthClient: grpc_health_v1.NewHealthClient(conn), diff --git a/pkg/storegateway/gateway.go b/pkg/storegateway/gateway.go index b639e270c7..9c81ac9cdf 100644 --- a/pkg/storegateway/gateway.go +++ b/pkg/storegateway/gateway.go @@ -2,7 +2,9 @@ package storegateway import ( "context" + "errors" "flag" + "fmt" "time" "github.com/go-kit/log" @@ -10,13 +12,12 @@ import ( "github.com/grafana/dskit/kv" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - phlareobj "github.com/grafana/pyroscope/pkg/objstore" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/validation" + phlareobj "github.com/grafana/pyroscope/v2/pkg/objstore" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/validation" ) const ( @@ -74,7 +75,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet, logger log.Logger) { func (c *Config) Validate(limits validation.Limits) error { if err := c.BucketStoreConfig.Validate(util.Logger); err != nil { - return errors.Wrap(err, "bucket store config") + return fmt.Errorf("bucket store config: %w", err) } if limits.StoreGatewayTenantShardSize < 0 { return errInvalidTenantShardSize @@ -91,7 +92,7 @@ func NewStoreGateway(gatewayCfg Config, storageBucket phlareobj.Bucket, limits L logger, ) if err != nil { - return nil, errors.Wrap(err, "create KV store client") + return nil, fmt.Errorf("create KV store client: %w", err) } return newStoreGateway(gatewayCfg, storageBucket, ringStore, limits, logger, reg) @@ -119,7 +120,7 @@ func newStoreGateway(gatewayCfg Config, storageBucket phlareobj.Bucket, ringStor lifecyclerCfg, err := gatewayCfg.ShardingRing.ToLifecyclerConfig(logger) if err != nil { - return nil, errors.Wrap(err, "invalid ring lifecycler config") + return nil, fmt.Errorf("invalid ring lifecycler config: %w", err) } // Define lifecycler delegates in reverse order (last to be called defined first because they're @@ -131,20 +132,20 @@ func newStoreGateway(gatewayCfg Config, storageBucket phlareobj.Bucket, ringStor g.ringLifecycler, err = ring.NewBasicLifecycler(lifecyclerCfg, RingNameForServer, RingKey, ringStore, delegate, logger, prometheus.WrapRegistererWithPrefix("pyroscope_", reg)) if err != nil { - return nil, errors.Wrap(err, "create ring lifecycler") + return nil, fmt.Errorf("create ring lifecycler: %w", err) } ringCfg := gatewayCfg.ShardingRing.ToRingConfig() g.ring, err = ring.NewWithStoreClientAndStrategy(ringCfg, RingNameForServer, RingKey, ringStore, ring.NewIgnoreUnhealthyInstancesReplicationStrategy(), prometheus.WrapRegistererWithPrefix("pyroscope_", reg), logger) if err != nil { - return nil, errors.Wrap(err, "create ring client") + return nil, fmt.Errorf("create ring client: %w", err) } shardingStrategy = NewShuffleShardingStrategy(g.ring, lifecyclerCfg.ID, lifecyclerCfg.Addr, limits, logger) g.stores, err = NewBucketStores(gatewayCfg.BucketStoreConfig, shardingStrategy, storageBucket, limits, logger, prometheus.WrapRegistererWith(prometheus.Labels{"component": "store-gateway"}, reg)) if err != nil { - return nil, errors.Wrap(err, "create bucket stores") + return nil, fmt.Errorf("create bucket stores: %w", err) } g.Service = services.NewBasicService(g.starting, g.running, g.stopping) @@ -169,14 +170,14 @@ func (g *StoreGateway) starting(ctx context.Context) (err error) { // First of all we register the instance in the ring and wait // until the lifecycler successfully started. if g.subservices, err = services.NewManager(g.ringLifecycler, g.ring); err != nil { - return errors.Wrap(err, "unable to start store-gateway dependencies") + return fmt.Errorf("unable to start store-gateway dependencies: %w", err) } g.subservicesWatcher = services.NewFailureWatcher() g.subservicesWatcher.WatchManager(g.subservices) if err = services.StartManagerAndAwaitHealthy(ctx, g.subservices); err != nil { - return errors.Wrap(err, "unable to start store-gateway dependencies") + return fmt.Errorf("unable to start store-gateway dependencies: %w", err) } // Wait until the ring client detected this instance in the JOINING state to @@ -208,14 +209,14 @@ func (g *StoreGateway) starting(ctx context.Context) (err error) { // and we can run the initial synchronization. g.bucketSync.WithLabelValues(syncReasonInitial).Inc() if err = g.stores.InitialSync(ctx); err != nil { - return errors.Wrap(err, "initial blocks synchronization") + return fmt.Errorf("initial blocks synchronization: %w", err) } // Now that the initial sync is done, we should have loaded all blocks // assigned to our shard, so we can switch to ACTIVE and start serving // requests. if err = g.ringLifecycler.ChangeState(ctx, ring.ACTIVE); err != nil { - return errors.Wrapf(err, "switch instance to %s in the ring", ring.ACTIVE) + return fmt.Errorf("switch instance to %s in the ring: %w", ring.ACTIVE, err) } // Wait until the ring client detected this instance in the ACTIVE state to @@ -256,7 +257,7 @@ func (g *StoreGateway) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-g.subservicesWatcher.Chan(): - return errors.Wrap(err, "store gateway subservice failed") + return fmt.Errorf("store gateway subservice failed: %w", err) } } } diff --git a/pkg/storegateway/gateway_blocks_http.go b/pkg/storegateway/gateway_blocks_http.go index a5f105d02c..e4ac45c18b 100644 --- a/pkg/storegateway/gateway_blocks_http.go +++ b/pkg/storegateway/gateway_blocks_http.go @@ -13,10 +13,12 @@ import ( "github.com/dustin/go-humanize" "github.com/gorilla/mux" + "github.com/grafana/dskit/tenant" "github.com/prometheus/prometheus/model/labels" - "github.com/grafana/pyroscope/pkg/phlaredb/block" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + "github.com/grafana/pyroscope/v2/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) //go:embed blocks.gohtml @@ -60,12 +62,16 @@ func (s *StoreGateway) BlocksHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) tenantID := vars["tenant"] if tenantID == "" { - util.WriteTextResponse(w, "Tenant ID can't be empty") + httputil.WriteTextResponse(w, "Tenant ID can't be empty") + return + } + if err := tenant.ValidTenantID(tenantID); err != nil { + http.Error(w, "Invalid tenant ID", http.StatusBadRequest) return } if err := req.ParseForm(); err != nil { - util.WriteTextResponse(w, fmt.Sprintf("Can't parse form: %s", err)) + httputil.WriteTextResponse(w, fmt.Sprintf("Can't parse form: %s", err)) return } @@ -82,7 +88,7 @@ func (s *StoreGateway) BlocksHandler(w http.ResponseWriter, req *http.Request) { metasMap, err := block.ListBlocks(filepath.Join(s.gatewayCfg.BucketStoreConfig.SyncDir, tenantID), time.Time{}) if err != nil { - util.WriteTextResponse(w, fmt.Sprintf("Failed to read block metadata: %s", err)) + httputil.WriteTextResponse(w, fmt.Sprintf("Failed to read block metadata: %s", err)) return } metas := block.SortBlocks(metasMap) @@ -134,7 +140,7 @@ func (s *StoreGateway) BlocksHandler(w http.ResponseWriter, req *http.Request) { }) } - util.RenderHTTPResponse(w, blocksPageContents{ + httputil.RenderHTTPResponse(w, blocksPageContents{ Now: time.Now(), Tenant: tenantID, RichMetas: richMetas, diff --git a/pkg/storegateway/gateway_ring.go b/pkg/storegateway/gateway_ring.go index 35827c95b7..38da3a5fb7 100644 --- a/pkg/storegateway/gateway_ring.go +++ b/pkg/storegateway/gateway_ring.go @@ -2,13 +2,14 @@ package storegateway import ( "flag" - "fmt" + "net" + "strconv" "time" "github.com/go-kit/log" "github.com/grafana/dskit/ring" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -109,7 +110,7 @@ func (cfg *RingConfig) ToLifecyclerConfig(logger log.Logger) (ring.BasicLifecycl return ring.BasicLifecyclerConfig{ ID: cfg.Ring.InstanceID, - Addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), + Addr: net.JoinHostPort(instanceAddr, strconv.Itoa(instancePort)), Zone: cfg.InstanceZone, HeartbeatPeriod: cfg.Ring.HeartbeatPeriod, HeartbeatTimeout: cfg.Ring.HeartbeatTimeout, diff --git a/pkg/storegateway/gateway_tenants_http.go b/pkg/storegateway/gateway_tenants_http.go index 4427f00d70..d2bb9d3f57 100644 --- a/pkg/storegateway/gateway_tenants_http.go +++ b/pkg/storegateway/gateway_tenants_http.go @@ -9,7 +9,7 @@ import ( "net/http" "time" - "github.com/grafana/pyroscope/pkg/util" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) //go:embed tenants.gohtml @@ -24,11 +24,11 @@ type tenantsPageContents struct { func (s *StoreGateway) TenantsHandler(w http.ResponseWriter, req *http.Request) { tenantIDs, err := s.stores.scanUsers(req.Context()) if err != nil { - util.WriteTextResponse(w, fmt.Sprintf("Can't read tenants: %s", err)) + httputil.WriteTextResponse(w, fmt.Sprintf("Can't read tenants: %s", err)) return } - util.RenderHTTPResponse(w, tenantsPageContents{ + httputil.RenderHTTPResponse(w, tenantsPageContents{ Now: time.Now(), Tenants: tenantIDs, }, tenantsTemplate, req) diff --git a/pkg/storegateway/metrics.go b/pkg/storegateway/metrics.go index 2a5d6cefcf..2e52e187ed 100644 --- a/pkg/storegateway/metrics.go +++ b/pkg/storegateway/metrics.go @@ -1,8 +1,8 @@ package storegateway import ( - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/util" "github.com/prometheus/client_golang/prometheus" ) diff --git a/pkg/storegateway/query.go b/pkg/storegateway/query.go index ded9dcf4a3..9f4e5e2e3b 100644 --- a/pkg/storegateway/query.go +++ b/pkg/storegateway/query.go @@ -2,17 +2,17 @@ package storegateway import ( "context" + "errors" "io" "slices" "connectrpc.com/connect" - "github.com/pkg/errors" "github.com/prometheus/common/model" ingestv1 "github.com/grafana/pyroscope/api/gen/proto/go/ingester/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/phlaredb" - "github.com/grafana/pyroscope/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/phlaredb" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) func (s *StoreGateway) MergeProfilesStacktraces(ctx context.Context, stream *connect.BidiStream[ingestv1.MergeProfilesStacktracesRequest, ingestv1.MergeProfilesStacktracesResponse]) error { diff --git a/pkg/storegateway/ring_status.gohtml b/pkg/storegateway/ring_status.gohtml index 3320f43204..fd46b6e6fb 100644 --- a/pkg/storegateway/ring_status.gohtml +++ b/pkg/storegateway/ring_status.gohtml @@ -1,4 +1,4 @@ -{{- /*gotype: github.com/grafana/pyroscope/pkg/storegateway.ringStatusPageContents*/ -}} +{{- /*gotype: github.com/grafana/pyroscope/v2/pkg/storegateway.ringStatusPageContents*/ -}} diff --git a/pkg/storegateway/tenants.gohtml b/pkg/storegateway/tenants.gohtml index 176a7c4985..b350edb1e9 100644 --- a/pkg/storegateway/tenants.gohtml +++ b/pkg/storegateway/tenants.gohtml @@ -1,6 +1,6 @@ -{{- /*gotype: github.com/grafana/pyroscope/pkg/storegateway.tenantsPageContents*/ -}} +{{- /*gotype: github.com/grafana/pyroscope/v2/pkg/storegateway.tenantsPageContents*/ -}} - + Store-gateway: bucket tenants diff --git a/pkg/symbolizer/debuginfod_client.go b/pkg/symbolizer/debuginfod_client.go new file mode 100644 index 0000000000..22ba8b0112 --- /dev/null +++ b/pkg/symbolizer/debuginfod_client.go @@ -0,0 +1,356 @@ +package symbolizer + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "net" + "net/http" + "os" + "regexp" + "time" + + "github.com/go-kit/log" + "github.com/grafana/dskit/backoff" + "github.com/grafana/dskit/tenant" + "golang.org/x/sync/singleflight" + + "github.com/dgraph-io/ristretto/v2" +) + +// DebuginfodClientConfig holds configuration for the debuginfod client. +type DebuginfodClientConfig struct { + BaseURL string + HTTPClient *http.Client + BackoffConfig backoff.Config + UserAgent string + + NotFoundCacheMaxItems int64 + NotFoundCacheTTL time.Duration +} + +// DebuginfodHTTPClient implements the DebuginfodClient interface using HTTP. +type DebuginfodHTTPClient struct { + cfg DebuginfodClientConfig + metrics *metrics + logger log.Logger + limits Limits + + // Used to deduplicate concurrent requests for the same build ID + group singleflight.Group + + notFoundCache *ristretto.Cache[string, bool] +} + +// NewDebuginfodClient creates a new client for fetching debug information from a debuginfod server. +func NewDebuginfodClient(logger log.Logger, baseURL string, metrics *metrics, limits Limits) (*DebuginfodHTTPClient, error) { + return NewDebuginfodClientWithConfig(logger, DebuginfodClientConfig{ + BaseURL: baseURL, + //UserAgent: "Pyroscope-Symbolizer/1.0", + BackoffConfig: backoff.Config{ + MinBackoff: 1 * time.Second, + MaxBackoff: 10 * time.Second, + MaxRetries: 3, + }, + NotFoundCacheMaxItems: 100000, + NotFoundCacheTTL: 7 * 24 * time.Hour, + }, metrics, limits) +} + +// NewDebuginfodClientWithConfig creates a new client with the specified configuration. +func NewDebuginfodClientWithConfig(logger log.Logger, cfg DebuginfodClientConfig, metrics *metrics, limits Limits) (*DebuginfodHTTPClient, error) { + httpClient := cfg.HTTPClient + if httpClient == nil { + transport := &http.Transport{ + MaxIdleConnsPerHost: 10, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + } + + httpClient = &http.Client{ + Transport: transport, + Timeout: 120 * time.Second, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + if len(via) >= 3 { + return fmt.Errorf("stopped after 3 redirects") + } + return nil + }, + } + } + + cache, err := ristretto.NewCache(&ristretto.Config[string, bool]{ + NumCounters: cfg.NotFoundCacheMaxItems * 10, + MaxCost: cfg.NotFoundCacheMaxItems, + BufferItems: 64, + }) + if err != nil { + return nil, fmt.Errorf("failed to create not-found cache: %w", err) + } + + client := &DebuginfodHTTPClient{ + cfg: DebuginfodClientConfig{ + BaseURL: cfg.BaseURL, + UserAgent: cfg.UserAgent, + HTTPClient: httpClient, + BackoffConfig: cfg.BackoffConfig, + }, + metrics: metrics, + logger: logger, + notFoundCache: cache, + limits: limits, + } + + return client, nil +} + +// FetchDebuginfo fetches the debuginfo file for a specific build ID. +// +// Concurrent callers for the same build ID share one fetch, detached from +// any single caller's cancellation. The error contract follows from that: +// a done caller gets its own context error without waiting for the shared +// fetch to finish, and every other error comes from the shared fetch — it +// may wrap a context error (e.g. the HTTP client's timeout) that says +// nothing about the caller's own context. +func (c *DebuginfodHTTPClient) FetchDebuginfo(ctx context.Context, buildID string) (io.ReadCloser, error) { + start := time.Now() + status := statusSuccess + defer func() { + c.metrics.debuginfodRequestDuration.WithLabelValues(status).Observe(time.Since(start).Seconds()) + }() + + sanitizedBuildID, err := sanitizeBuildID(buildID) + if err != nil { + status = statusErrorInvalidID + return nil, err + } + + if found, _ := c.notFoundCache.Get(sanitizedBuildID); found { + status = statusErrorNotFound + c.metrics.cacheOperations.WithLabelValues("not_found", "get", statusSuccess).Inc() + return nil, buildIDNotFoundError{buildID: sanitizedBuildID} + } + c.metrics.cacheOperations.WithLabelValues("not_found", "get", "miss").Inc() + + // Detached so one caller's cancellation cannot fail the fetch for the + // others; context values are preserved, and the HTTP client's timeout + // plus bounded retries keep the detached fetch finite. + localCtx := context.WithoutCancel(ctx) + resCh := c.group.DoChan(sanitizedBuildID, func() (interface{}, error) { + return c.fetchDebugInfoWithRetries(localCtx, sanitizedBuildID) + }) + + // A done caller stops waiting; the fetch keeps running for the rest. + var v interface{} + select { + case res := <-resCh: + v, err = res.Val, res.Err + case <-ctx.Done(): + err = ctx.Err() + } + + if err != nil { + var bnfErr buildIDNotFoundError + switch { + case errors.As(err, &bnfErr): + status = statusErrorNotFound + case errors.Is(err, context.Canceled): + status = statusErrorCanceled + case errors.Is(err, context.DeadlineExceeded): + status = statusErrorTimeout + case isInvalidBuildIDError(err): + status = statusErrorInvalidID + default: + if statusCode, ok := isHTTPStatusError(err); ok { + status = categorizeHTTPStatusCode(statusCode) + } else { + status = statusErrorOther + } + } + return nil, err + } + + data := v.([]byte) + return io.NopCloser(bytes.NewReader(data)), nil +} + +// doRequest performs an HTTP request to the specified URL and returns the response body. +func (c *DebuginfodHTTPClient) doRequest(ctx context.Context, url string) ([]byte, error) { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, err + } + + maxBytes := int64(c.limits.SymbolizerMaxSymbolSizeBytes(tenantID)) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + req.Header.Set("Accept-Encoding", "gzip, deflate") + if c.cfg.UserAgent != "" { + req.Header.Set("User-Agent", c.cfg.UserAgent) + } + + resp, err := c.cfg.HTTPClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to execute request: %w", err) + } + defer resp.Body.Close() + + var r io.Reader = resp.Body + // maxBytes == 0 means unlimited body size + if maxBytes > 0 { + r = io.LimitReader(r, maxBytes+1) // +1 to detect if limit is exceeded + } + + data, err := io.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + // Check if we hit the size limit + if maxBytes > 0 && int64(len(data)) > maxBytes { + return nil, &ErrSymbolSizeBytesExceedsLimit{Limit: maxBytes} + } + + if resp.StatusCode != http.StatusOK { + errorBody := string(data) + + // Truncate large error responses + if len(errorBody) > 1000 { + errorBody = errorBody[:1000] + "... [truncated]" + } + return nil, httpStatusError{ + statusCode: resp.StatusCode, + body: errorBody, + } + } + + c.metrics.debuginfodFileSize.Observe(float64(len(data))) + + return data, nil +} + +// fetchDebugInfoWithRetries attempts to fetch debug info with retries on transient errors. +func (c *DebuginfodHTTPClient) fetchDebugInfoWithRetries(ctx context.Context, sanitizedBuildID string) ([]byte, error) { + url := fmt.Sprintf("%s/buildid/%s/debuginfo", c.cfg.BaseURL, sanitizedBuildID) + var data []byte + + // Use dskit backoff for retries with exponential backoff + backOff := backoff.New(ctx, c.cfg.BackoffConfig) + + attempt := func() ([]byte, error) { + return c.doRequest(ctx, url) + } + + var lastErr error + for backOff.Ongoing() { + data, err := attempt() + if err == nil { + return data, nil + } + + // Don't retry on 404 errors + if statusCode, isHTTPErr := isHTTPStatusError(err); isHTTPErr && statusCode == http.StatusNotFound { + c.notFoundCache.SetWithTTL(sanitizedBuildID, true, 1, c.cfg.NotFoundCacheTTL) + c.notFoundCache.Wait() + c.metrics.cacheOperations.WithLabelValues("not_found", "set", statusSuccess).Inc() + c.metrics.cacheSizeBytes.WithLabelValues("not_found").Set(float64(c.notFoundCache.Metrics.CostAdded())) + return nil, buildIDNotFoundError{buildID: sanitizedBuildID} + } + + lastErr = err + + if !isRetryableError(err) { + break + } + + backOff.Wait() + } + + if lastErr != nil { + return nil, fmt.Errorf("failed to fetch debuginfo after %d attempts: %w", backOff.NumRetries(), lastErr) + } + + return data, nil +} + +// categorizeHTTPStatusCode maps HTTP status codes to metric status strings. +func categorizeHTTPStatusCode(statusCode int) string { + switch { + case statusCode == http.StatusNotFound: + return statusErrorNotFound + case statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden: + return statusErrorUnauthorized + case statusCode == http.StatusTooManyRequests: + return statusErrorRateLimited + case statusCode >= 400 && statusCode < 500: + return statusErrorClientError + case statusCode >= 500: + return statusErrorServerError + default: + return statusErrorHTTPOther + } +} + +// isRetryableError determines if an error should trigger a retry attempt. +func isRetryableError(err error) bool { + if err == nil { + return false + } + + if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) { + return false + } + + if isInvalidBuildIDError(err) { + return false + } + + var bnfErr buildIDNotFoundError + if errors.As(err, &bnfErr) { + return false + } + + if statusCode, ok := isHTTPStatusError(err); ok { + // Don't retry 4xx client errors except for 429 (too many requests) + if statusCode == http.StatusTooManyRequests { + return true + } + if statusCode >= 400 && statusCode < 500 { + return false + } + // Retry on 5xx server errors + return statusCode >= 500 + } + + if os.IsTimeout(err) { + return true + } + + var netErr net.Error + if errors.As(err, &netErr) { + return netErr.Timeout() + } + + return false +} + +// sanitizeBuildID ensures that the buildID is a safe and valid string for use in file paths. +// It validates that the build ID contains only alphanumeric characters, underscores, and hyphens. +// This prevents potential security issues like path traversal attacks. +func sanitizeBuildID(buildID string) (string, error) { + if buildID == "" { + return "", nil + } + + validBuildID := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) + if !validBuildID.MatchString(buildID) { + return "", invalidBuildIDError{buildID: buildID} + } + return buildID, nil +} diff --git a/pkg/symbolizer/debuginfod_client_test.go b/pkg/symbolizer/debuginfod_client_test.go new file mode 100644 index 0000000000..953189f0ef --- /dev/null +++ b/pkg/symbolizer/debuginfod_client_test.go @@ -0,0 +1,434 @@ +package symbolizer + +import ( + "context" + "errors" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func TestDebuginfodClient(t *testing.T) { + // Create a test server that returns different responses based on the request + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + buildID := r.URL.Path[len("/buildid/"):] + buildID = buildID[:len(buildID)-len("/debuginfo")] + + switch buildID { + case "valid-build-id": + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("mock debug info")) + case "not-found": + w.WriteHeader(http.StatusNotFound) + case "server-error": + w.WriteHeader(http.StatusInternalServerError) + case "rate-limited": + w.WriteHeader(http.StatusTooManyRequests) + default: + w.WriteHeader(http.StatusBadRequest) + } + })) + defer server.Close() + + limits := validation.MockOverrides(func(defaults *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.Symbolizer.MaxSymbolSizeBytes = 4 + tenantLimits["tenant-limited"] = l + }) + + // Create a client with the test server URL + metrics := newMetrics(prometheus.NewRegistry()) + client, err := NewDebuginfodClient(log.NewNopLogger(), server.URL, metrics, limits) + require.NoError(t, err) + + // Test cases + tests := []struct { + name string + buildID string + tenantID string + expectedError bool + expectedData string + errorCheck func(error) bool + }{ + { + name: "valid build ID", + buildID: "valid-build-id", + expectedError: false, + expectedData: "mock debug info", + }, + { + name: "not found", + buildID: "not-found", + expectedError: true, + errorCheck: func(err error) bool { + var notFoundErr buildIDNotFoundError + return errors.As(err, ¬FoundErr) + }, + }, + { + name: "server error", + buildID: "server-error", + expectedError: true, + errorCheck: func(err error) bool { + return err != nil && err.Error() != "" && + (err.Error() == "HTTP error 500" || + err.Error() == "failed to fetch debuginfo after 3 attempts: HTTP error 500") + }, + }, + { + name: "rate limited", + buildID: "rate-limited", + expectedError: true, + errorCheck: func(err error) bool { + return err != nil && err.Error() != "" && + (err.Error() == "HTTP error 429" || + err.Error() == "failed to fetch debuginfo after 3 attempts: HTTP error 429") + }, + }, + { + name: "invalid build ID", + buildID: "invalid/build/id", + expectedError: true, + errorCheck: func(err error) bool { + return isInvalidBuildIDError(err) + }, + }, + { + name: "size limit", + buildID: "valid-build-id", + tenantID: "tenant-limited", + expectedError: true, + errorCheck: func(err error) bool { + return err != nil && strings.Contains(err.Error(), "symbol size exceeds maximum allowed size of 4 bytes") + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Fetch debug info + tenantID := "tenant" + if tc.tenantID != "" { + tenantID = tc.tenantID + } + ctx := tenant.InjectTenantID(context.Background(), tenantID) + reader, err := client.FetchDebuginfo(ctx, tc.buildID) + + // Check error + if tc.expectedError { + assert.Error(t, err) + if tc.errorCheck != nil { + assert.True(t, tc.errorCheck(err), "Error type check failed: %v", err) + } + return + } + + // Check success case + require.NoError(t, err) + defer reader.Close() + + // Read the data + data, err := io.ReadAll(reader) + require.NoError(t, err) + assert.Equal(t, tc.expectedData, string(data)) + }) + } +} + +func TestDebuginfodClientSingleflight(t *testing.T) { + // Create a test server that sleeps to simulate a slow response + requestCount := 0 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requestCount++ + time.Sleep(100 * time.Millisecond) + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("mock debug info")) + })) + defer server.Close() + + // Create a client with the test server URL + metrics := newMetrics(prometheus.NewRegistry()) + client, err := NewDebuginfodClient(log.NewNopLogger(), server.URL, metrics, validation.MockDefaultOverrides()) + require.NoError(t, err) + + // Make concurrent requests with the same build ID + buildID := "singleflight-test-id" + ctx := tenant.InjectTenantID(context.Background(), "tenant") + + // Channel to synchronize goroutines + done := make(chan struct{}) + results := make(chan []byte, 3) + errors := make(chan error, 3) + + // Start 3 concurrent requests + for i := 0; i < 3; i++ { + go func() { + reader, err := client.FetchDebuginfo(ctx, buildID) + if err != nil { + errors <- err + done <- struct{}{} + return + } + data, err := io.ReadAll(reader) + reader.Close() + if err != nil { + errors <- err + } else { + results <- data + } + done <- struct{}{} + }() + } + + // Wait for all requests to complete + for i := 0; i < 3; i++ { + <-done + } + + // Check results + close(results) + close(errors) + + // Should have no errors + for err := range errors { + t.Errorf("Unexpected error: %v", err) + } + + // All results should be the same + var data []byte + for result := range results { + if data == nil { + data = result + } else { + assert.Equal(t, data, result) + } + } + + // Should have made only one HTTP request + assert.Equal(t, 1, requestCount, "Expected only one HTTP request") +} + +func TestDebuginfodClientCanceledCallerDoesNotWaitForFetch(t *testing.T) { + requestStarted := make(chan struct{}) + release := make(chan struct{}) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + close(requestStarted) + <-release + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("mock debug info")) + })) + defer server.Close() + + metrics := newMetrics(prometheus.NewRegistry()) + client, err := NewDebuginfodClient(log.NewNopLogger(), server.URL, metrics, validation.MockDefaultOverrides()) + require.NoError(t, err) + + buildID := "cancel-wait-test-id" + + // A waiter with a live context stays on the shared fetch until it finishes. + type fetchResult struct { + data []byte + err error + } + waiterCh := make(chan fetchResult, 1) + go func() { + reader, err := client.FetchDebuginfo(tenant.InjectTenantID(context.Background(), "tenant"), buildID) + if err != nil { + waiterCh <- fetchResult{err: err} + return + } + defer reader.Close() + data, err := io.ReadAll(reader) + waiterCh <- fetchResult{data: data, err: err} + }() + + <-requestStarted + + // A canceled caller joining the same in-flight fetch returns its own + // context error immediately instead of blocking until the fetch finishes. + canceledCtx, cancel := context.WithCancel(tenant.InjectTenantID(context.Background(), "tenant")) + cancel() + _, err = client.FetchDebuginfo(canceledCtx, buildID) + require.ErrorIs(t, err, context.Canceled) + + close(release) + res := <-waiterCh + require.NoError(t, res.err) + require.Equal(t, "mock debug info", string(res.data)) +} + +func TestSanitizeBuildID(t *testing.T) { + tests := []struct { + name string + buildID string + expected string + expectError bool + }{ + { + name: "valid build ID", + buildID: "abcdef1234567890", + expected: "abcdef1234567890", + expectError: false, + }, + { + name: "valid build ID with dashes and underscores", + buildID: "abcdef-1234_7890", + expected: "abcdef-1234_7890", + expectError: false, + }, + { + name: "invalid build ID with slashes", + buildID: "abcdef/1234", + expected: "", + expectError: true, + }, + { + name: "invalid build ID with spaces", + buildID: "abcdef 1234", + expected: "", + expectError: true, + }, + { + name: "invalid build ID with special characters", + buildID: "abcdef#1234", + expected: "", + expectError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result, err := sanitizeBuildID(tc.buildID) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expected, result) + } + }) + } +} + +func TestIsRetryableError(t *testing.T) { + tests := []struct { + name string + err error + expected bool + }{ + { + name: "nil error", + err: nil, + expected: false, + }, + { + name: "context canceled", + err: context.Canceled, + expected: false, + }, + { + name: "context deadline exceeded", + err: context.DeadlineExceeded, + expected: false, + }, + { + name: "invalid build ID", + err: invalidBuildIDError{buildID: "invalid"}, + expected: false, + }, + { + name: "build ID not found", + err: buildIDNotFoundError{buildID: "not-found"}, + expected: false, + }, + { + name: "HTTP 404", + err: httpStatusError{statusCode: http.StatusNotFound}, + expected: false, + }, + { + name: "HTTP 429", + err: httpStatusError{statusCode: http.StatusTooManyRequests}, + expected: true, + }, + { + name: "HTTP 500", + err: httpStatusError{statusCode: http.StatusInternalServerError}, + expected: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result := isRetryableError(tc.err) + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestDebuginfodClientNotFoundCache(t *testing.T) { + requestCount := 0 + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requestCount++ + buildID := r.URL.Path[len("/buildid/"):] + buildID = buildID[:len(buildID)-len("/debuginfo")] + if buildID == "not-found-cached" { + w.WriteHeader(http.StatusNotFound) + return + } + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("mock debug info")) + })) + defer server.Close() + + client, err := NewDebuginfodClientWithConfig(log.NewNopLogger(), DebuginfodClientConfig{ + BaseURL: server.URL, + NotFoundCacheMaxItems: 100, + NotFoundCacheTTL: 10 * time.Second, + }, newMetrics(nil), validation.MockDefaultOverrides()) + require.NoError(t, err) + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + buildID := "not-found-cached" + + // First request should hit the server and get a 404 + reader, err := client.FetchDebuginfo(ctx, buildID) + assert.Error(t, err) + assert.Nil(t, reader) + + var notFoundErr buildIDNotFoundError + assert.True(t, errors.As(err, ¬FoundErr)) + assert.Equal(t, 1, requestCount) + + client.notFoundCache.Wait() + + // Second request should get 404 from cache without hitting server + reader, err = client.FetchDebuginfo(ctx, buildID) + assert.Error(t, err) + assert.Nil(t, reader) + assert.True(t, errors.As(err, ¬FoundErr)) + assert.Equal(t, 1, requestCount) + + // Third request should hit the server + reader, err = client.FetchDebuginfo(ctx, "valid-id") + assert.NoError(t, err) + require.NotNil(t, reader) + + data, err := io.ReadAll(reader) + require.NoError(t, err) + reader.Close() + assert.Equal(t, "mock debug info", string(data)) + + assert.Equal(t, 2, requestCount) +} diff --git a/pkg/symbolizer/errors.go b/pkg/symbolizer/errors.go new file mode 100644 index 0000000000..275698a456 --- /dev/null +++ b/pkg/symbolizer/errors.go @@ -0,0 +1,50 @@ +package symbolizer + +import ( + "errors" + "fmt" +) + +type invalidBuildIDError struct { + buildID string +} + +func (e invalidBuildIDError) Error() string { + return fmt.Sprintf("invalid build ID: %s", e.buildID) +} + +type buildIDNotFoundError struct { + buildID string +} + +func (e buildIDNotFoundError) Error() string { + return fmt.Sprintf("build ID not found: %s", e.buildID) +} + +type httpStatusError struct { + statusCode int + body string +} + +func (e httpStatusError) Error() string { + if e.body != "" { + return fmt.Sprintf("HTTP error %d: %s", e.statusCode, e.body) + } + return fmt.Sprintf("HTTP error %d", e.statusCode) +} + +// Helper function to check if an error is of a specific type +func isInvalidBuildIDError(err error) bool { + var invalidBuildIDError invalidBuildIDError + ok := errors.As(err, &invalidBuildIDError) + return ok +} + +func isHTTPStatusError(err error) (int, bool) { + var httpErr httpStatusError + ok := errors.As(err, &httpErr) + if ok { + return httpErr.statusCode, true + } + return 0, false +} diff --git a/pkg/symbolizer/metrics.go b/pkg/symbolizer/metrics.go new file mode 100644 index 0000000000..d3d0ad0a51 --- /dev/null +++ b/pkg/symbolizer/metrics.go @@ -0,0 +1,139 @@ +package symbolizer + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/util" +) + +const ( + // Status values for metrics + statusSuccess = "success" + + // Error status prefixes + statusErrorPrefix = "error:" + + // HTTP error statuses + statusErrorNotFound = statusErrorPrefix + "not_found" + statusErrorUnauthorized = statusErrorPrefix + "unauthorized" + statusErrorRateLimited = statusErrorPrefix + "rate_limited" + statusErrorClientError = statusErrorPrefix + "client_error" + statusErrorServerError = statusErrorPrefix + "server_error" + statusErrorHTTPOther = statusErrorPrefix + "http_other" + + // General error statuses + statusErrorCanceled = statusErrorPrefix + "canceled" + statusErrorTimeout = statusErrorPrefix + "timeout" + statusErrorInvalidID = statusErrorPrefix + "invalid_id" + statusErrorOther = statusErrorPrefix + "other" + statusErrorDebuginfod = statusErrorPrefix + "debuginfod_error" +) + +type metrics struct { + registerer prometheus.Registerer + + // Debuginfod metrics + debuginfodRequestDuration *prometheus.HistogramVec + debuginfodFileSize prometheus.Histogram + + // Cache metrics + cacheOperations *prometheus.CounterVec + cacheSizeBytes *prometheus.GaugeVec + + // Profile symbolization metrics + profileSymbolization *prometheus.HistogramVec + + // Debug symbol resolution metrics + debugSymbolResolution *prometheus.HistogramVec + debugSymbolResolutionErrors *prometheus.CounterVec +} + +func newMetrics(reg prometheus.Registerer) *metrics { + m := &metrics{ + registerer: reg, + debuginfodRequestDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pyroscope_symbolizer_debuginfod_request_duration_seconds", + Help: "Time spent performing debuginfod requests by status", + Buckets: []float64{0.1, 0.5, 1, 5, 10, 30, 60, 120, 300}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"status"}), + debuginfodFileSize: prometheus.NewHistogram( + prometheus.HistogramOpts{ + Name: "pyroscope_symbolizer_debuginfo_file_size_bytes", + Help: "Size of debug info files fetched from debuginfod", + // 1MB to 4GB + Buckets: prometheus.ExponentialBuckets(1024*1024, 2, 12), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, + ), + // cache metrics + cacheOperations: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "pyroscope_symbolizer_cache_operations_total", + Help: "Total number of cache operations by cache type, operation and status", + }, + []string{"cache_type", "operation", "status"}, + ), + cacheSizeBytes: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pyroscope_symbolizer_cache_size_bytes", + Help: "Current size of cache in bytes by cache type", + }, []string{"cache_type"}), + // profile symbolization metrics + profileSymbolization: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pyroscope_profile_symbolization_duration_seconds", + Help: "Time spent performing profile symbolization by status", + Buckets: []float64{.01, .05, .1, .5, 1, 5, 10, 30}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"status"}), + // debug symbol resolution metrics + debugSymbolResolution: prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "pyroscope_debug_symbol_resolution_duration_seconds", + Help: "Time spent resolving debug symbols from ELF files by status", + Buckets: []float64{.001, .005, .01, .05, .1, .5, 1, 5, 10}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"status"}), + debugSymbolResolutionErrors: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "pyroscope_debug_symbol_resolution_errors_total", + Help: "Total number of errors encountered during debug symbol resolution by error type", + }, + []string{"error_type"}, + ), + } + + if reg != nil { + m.register() + } + + return m +} + +func (m *metrics) register() { + if m.registerer == nil { + return + } + + collectors := []prometheus.Collector{ + m.debuginfodRequestDuration, + m.debuginfodFileSize, + m.cacheOperations, + m.cacheSizeBytes, + m.profileSymbolization, + m.debugSymbolResolution, + m.debugSymbolResolutionErrors, + } + + for _, collector := range collectors { + util.RegisterOrGet(m.registerer, collector) + } +} diff --git a/pkg/symbolizer/reader.go b/pkg/symbolizer/reader.go new file mode 100644 index 0000000000..e356dd2e90 --- /dev/null +++ b/pkg/symbolizer/reader.go @@ -0,0 +1,124 @@ +package symbolizer + +import ( + "bytes" + "fmt" + "io" + + "github.com/klauspost/compress/gzip" + "github.com/klauspost/compress/zstd" +) + +func NewReaderAtCloser(data []byte) interface { + io.ReadCloser + io.ReaderAt +} { + bytesReader := bytes.NewReader(data) + return struct { + io.ReadCloser + io.ReaderAt + }{ + ReadCloser: io.NopCloser(bytesReader), + ReaderAt: bytesReader, + } +} + +// memoryBuffer implements io.WriteSeeker for writing to an in-memory buffer with seeking capabilities +type memoryBuffer struct { + data []byte + pos int64 +} + +func newMemoryBuffer(initialCapacity int) *memoryBuffer { + capacity := initialCapacity + if capacity < 0 { + capacity = 0 + } + + return &memoryBuffer{ + data: make([]byte, 0, capacity), + pos: 0, + } +} + +func (m *memoryBuffer) Write(p []byte) (n int, err error) { + if m.pos > int64(len(m.data)) { + m.data = append(m.data, make([]byte, m.pos-int64(len(m.data)))...) + } + + if m.pos+int64(len(p)) > int64(len(m.data)) { + m.data = append(m.data, make([]byte, m.pos+int64(len(p))-int64(len(m.data)))...) + } + + n = copy(m.data[m.pos:], p) + m.pos += int64(n) + return n, nil +} + +func (m *memoryBuffer) Seek(offset int64, whence int) (int64, error) { + var newPos int64 + switch whence { + case io.SeekStart: + newPos = offset + case io.SeekCurrent: + newPos = m.pos + offset + case io.SeekEnd: + newPos = int64(len(m.data)) + offset + default: + return 0, fmt.Errorf("invalid whence: %d", whence) + } + + if newPos < 0 { + return 0, fmt.Errorf("negative position: %d", newPos) + } + + m.pos = newPos + return m.pos, nil +} + +func (m *memoryBuffer) Bytes() []byte { + return m.data +} + +func readAllWithLimit(r io.Reader, typ string, maxBytes int64) ([]byte, error) { + // maxBytes == 0 means unlimited body size + if maxBytes > 0 { + r = io.LimitReader(r, maxBytes+1) // +1 to detect if limit is exceeded + } + + decompressed, err := io.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("decompress %s data: %w", typ, err) + } + + // Check if we hit the size limit + if maxBytes > 0 && int64(len(decompressed)) > maxBytes { + return nil, &ErrSymbolSizeBytesExceedsLimit{Limit: maxBytes} + } + + return decompressed, nil +} + +// detectCompression checks if data is compressed and decompresses it if needed +func detectCompression(data []byte, maxBytes int64) ([]byte, error) { + if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b { + r, err := gzip.NewReader(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("create gzip reader: %w", err) + } + defer r.Close() + return readAllWithLimit(r, "gzip", maxBytes) + } + + // Check for zstd (magic bytes: 0x28, 0xb5, 0x2f, 0xfd) + if len(data) >= 4 && data[0] == 0x28 && data[1] == 0xb5 && data[2] == 0x2f && data[3] == 0xfd { + r, err := zstd.NewReader(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("create zstd reader: %w", err) + } + defer r.Close() + return readAllWithLimit(r, "zstd", maxBytes) + } + + return data, nil +} diff --git a/pkg/symbolizer/resolve_test.go b/pkg/symbolizer/resolve_test.go new file mode 100644 index 0000000000..1d60a24dad --- /dev/null +++ b/pkg/symbolizer/resolve_test.go @@ -0,0 +1,283 @@ +package symbolizer + +import ( + "bytes" + "context" + "fmt" + "io" + "testing" + "time" + + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/lidia" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +func TestResolveSizeLimitExceeded(t *testing.T) { + limits := validation.MockOverrides(func(_ *validation.Limits, tenantLimits map[string]*validation.Limits) { + l := validation.MockDefaultLimits() + l.Symbolizer.MaxSymbolSizeBytes = 4 + tenantLimits["tenant-limited"] = l + }) + s, mockClient, mockBucket := newSymbolizerTest(t, &symbolizerInputs{Limits: limits}) + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant-limited", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(openTestFile(t), nil).Once() + + ctx := tenant.InjectTenantID(context.Background(), "tenant-limited") + frames, err := s.Resolve(ctx, "build-id", "some-binary", []uint64{0x1500}) + + require.NoError(t, err) + require.Len(t, frames, 1) + require.Nil(t, frames[0]) +} + +func TestResolveContextCancellation(t *testing.T) { + t.Run("already canceled", func(t *testing.T) { + s, _, _ := newSymbolizerTest(t, nil) + ctx, cancel := context.WithCancel(tenant.InjectTenantID(context.Background(), "tenant")) + cancel() + + frames, err := s.Resolve(ctx, "build-id", "binary", []uint64{0x1500}) + + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) + require.Nil(t, frames) + }) + + t.Run("canceled mid-fetch", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + + fetchStarted := make(chan struct{}) + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return( + func(ctx context.Context, buildID string) (io.ReadCloser, error) { + close(fetchStarted) + <-ctx.Done() + return nil, ctx.Err() + }, + ).Once() + + ctx, cancel := context.WithCancel(tenant.InjectTenantID(context.Background(), "tenant")) + type result struct { + frames [][]lidia.SourceInfoFrame + err error + } + resCh := make(chan result, 1) + go func() { + frames, err := s.Resolve(ctx, "build-id", "binary", []uint64{0x1500}) + resCh <- result{frames, err} + }() + + <-fetchStarted + cancel() + res := <-resCh + + require.Error(t, res.err) + require.ErrorIs(t, res.err, context.Canceled) + require.Nil(t, res.frames) + }) + + t.Run("canceled mid-fetch with successful fetch", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + + // The deduplicated fetch is detached from caller cancellation, so it + // can complete successfully after the caller's context is done; the + // canceled caller must still get an error, not the fetched result. + fetchStarted := make(chan struct{}) + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return( + func(ctx context.Context, buildID string) (io.ReadCloser, error) { + close(fetchStarted) + <-ctx.Done() + return openTestFile(t), nil + }, + ).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Return(nil).Once() + + ctx, cancel := context.WithCancel(tenant.InjectTenantID(context.Background(), "tenant")) + type result struct { + frames [][]lidia.SourceInfoFrame + err error + } + resCh := make(chan result, 1) + go func() { + frames, err := s.Resolve(ctx, "build-id", "binary", []uint64{0x1500}) + resCh <- result{frames, err} + }() + + <-fetchStarted + cancel() + res := <-resCh + + require.Error(t, res.err) + require.ErrorIs(t, res.err, context.Canceled) + require.Nil(t, res.frames) + }) + + t.Run("deadline exceeded mid-fetch", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return( + func(ctx context.Context, buildID string) (io.ReadCloser, error) { + <-ctx.Done() + return nil, ctx.Err() + }, + ).Once() + + ctx, cancel := context.WithTimeout(tenant.InjectTenantID(context.Background(), "tenant"), 1*time.Millisecond) + defer cancel() + + frames, err := s.Resolve(ctx, "build-id", "binary", []uint64{0x1500}) + + require.Error(t, err) + require.ErrorIs(t, err, context.DeadlineExceeded) + require.Nil(t, frames) + }) + + t.Run("foreign context error degrades to fallback", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + // The deduplicated debuginfod fetch is shared with other callers and + // can surface another caller's cancellation; with this caller's + // context alive it must degrade to unresolved slots like any other + // fetch failure. + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(nil, context.Canceled).Once() + + frames, err := s.Resolve(tenant.InjectTenantID(context.Background(), "tenant"), "build-id", "binary", []uint64{0x1500}) + + require.NoError(t, err) + require.Len(t, frames, 1) + require.Nil(t, frames[0]) + }) +} + +func TestResolveInvalidBuildID(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + ctx := tenant.InjectTenantID(context.Background(), "tenant") + + frames, err := s.Resolve(ctx, "../traversal", "binary", []uint64{0x1500, 0x3c5a}) + + require.NoError(t, err) + require.Len(t, frames, 2) + require.Nil(t, frames[0]) + require.Nil(t, frames[1]) + require.Equal(t, float64(1), testutil.ToFloat64(s.metrics.debugSymbolResolutionErrors.WithLabelValues("invalid_build_id"))) + + // No mockClient/mockBucket expectations configured above: AssertExpectations here + // (and the mocks' own t.Cleanup) prove Resolve rejected the malformed buildID before + // touching the bucket or debuginfod. + mockClient.AssertExpectations(t) + mockBucket.AssertExpectations(t) +} + +func TestSymbolizePprofPropagatesContextCancellation(t *testing.T) { + s, _, _ := newSymbolizerTest(t, nil) + profile := &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + BuildId: 1, + MemoryStart: 0x0, + MemoryLimit: 0x1000000, + }}, + Location: []*googlev1.Location{{Id: 1, MappingId: 1, Address: 0x1500}}, + StringTable: []string{"", "build-id"}, + } + + ctx, cancel := context.WithCancel(tenant.InjectTenantID(context.Background(), "tenant")) + cancel() + + err := s.SymbolizePprof(ctx, profile) + + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +func TestSymbolizeMappingsConcurrentFanOut(t *testing.T) { + elfFile := openTestFile(t) + elfData, err := io.ReadAll(elfFile) + require.NoError(t, err) + require.NoError(t, elfFile.Close()) + + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + s.cfg.MaxDebuginfodConcurrency = 4 + + // addrs per build ID; 0x1500 resolves to "main", 0x3c5a resolves to "atoll_b" + // (see testdata/symbols.debug, also used by TestSymbolizePprof). + buildIDAddrs := map[string][]uint64{ + "build-id-1": {0x1500, 0x3c5a}, + "build-id-2": {0x1500}, + "build-id-3": {0x1500}, + } + buildIDs := []string{"build-id-1", "build-id-2", "build-id-3"} + + fetchStarted := make(chan struct{}, len(buildIDs)) + release := make(chan struct{}) + blockUntilReleased := func(context.Context, string) (io.ReadCloser, error) { + fetchStarted <- struct{}{} + <-release + return io.NopCloser(bytes.NewReader(elfData)), nil + } + + stringTable := []string{""} + mappings := make([]*googlev1.Mapping, len(buildIDs)) + var locations []*googlev1.Location + nextLocID := uint64(1) + + for i, buildID := range buildIDs { + buildIDIdx := int64(len(stringTable)) + stringTable = append(stringTable, buildID) + + mappings[i] = &googlev1.Mapping{ + BuildId: buildIDIdx, + MemoryStart: 0x0, + MemoryLimit: 0x1000000, + } + mappingID := uint64(i + 1) + + for _, addr := range buildIDAddrs[buildID] { + locations = append(locations, &googlev1.Location{ + Id: nextLocID, + MappingId: mappingID, + Address: addr, + }) + nextLocID++ + } + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", buildID)).Return(nil, fmt.Errorf("not found")).Once() + mockClient.On("FetchDebuginfo", mock.Anything, buildID).Return(blockUntilReleased).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", buildID), mock.Anything).Return(nil).Once() + } + + profile := &googlev1.Profile{ + Mapping: mappings, + Location: locations, + StringTable: stringTable, + } + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + errCh := make(chan error, 1) + go func() { + errCh <- s.SymbolizePprof(ctx, profile) + }() + + for range buildIDs { + <-fetchStarted + } + close(release) + + require.NoError(t, <-errCh) + + for _, mapping := range mappings { + require.True(t, mapping.HasFunctions) + } + assertLocationHasFunction(t, profile, locations[0], "main", "main") + assertLocationHasFunction(t, profile, locations[1], "atoll_b", "atoll_b") + assertLocationHasFunction(t, profile, locations[2], "main", "main") + assertLocationHasFunction(t, profile, locations[3], "main", "main") +} diff --git a/pkg/symbolizer/symbolizer.go b/pkg/symbolizer/symbolizer.go new file mode 100644 index 0000000000..32304bbf52 --- /dev/null +++ b/pkg/symbolizer/symbolizer.go @@ -0,0 +1,582 @@ +package symbolizer + +import ( + "bytes" + "context" + "debug/elf" + "errors" + "flag" + "fmt" + "io" + "net/http" + "path" + "path/filepath" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tenant" + + "github.com/prometheus/client_golang/prometheus" + "golang.org/x/sync/errgroup" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/lidia" + "github.com/grafana/pyroscope/v2/pkg/debuginfo" + "github.com/grafana/pyroscope/v2/pkg/objstore" +) + +const bucketPrefix = "symbolizer" + +type DebuginfodClient interface { + FetchDebuginfo(ctx context.Context, buildID string) (io.ReadCloser, error) +} + +// Resolver resolves debug symbols for addresses within a single binary (identified by +// buildID). result[i] is aligned to addrs[i]; a nil/empty slice at index i means address i +// could not be resolved. A non-nil error is returned only when the caller's own +// ctx is done (context.Canceled or context.DeadlineExceeded), in which case +// result is nil; any other failure degrades to unresolved slots. +// A buildID that is empty or fails validation resolves nothing: every result slot is nil. +type Resolver interface { + Resolve(ctx context.Context, buildID, binaryName string, addrs []uint64) ([][]lidia.SourceInfoFrame, error) +} + +var _ Resolver = (*Symbolizer)(nil) + +// Resolve implements Resolver. +func (s *Symbolizer) Resolve(ctx context.Context, buildID, binaryName string, addrs []uint64) ([][]lidia.SourceInfoFrame, error) { + if err := ctx.Err(); err != nil { + return nil, fmt.Errorf("resolve symbols: %w", err) + } + + if buildID == "" { + s.metrics.debugSymbolResolutionErrors.WithLabelValues("empty_build_id").Inc() + return make([][]lidia.SourceInfoFrame, len(addrs)), nil + } + + if _, err := sanitizeBuildID(buildID); err != nil { + s.metrics.debugSymbolResolutionErrors.WithLabelValues("invalid_build_id").Inc() + return make([][]lidia.SourceInfoFrame, len(addrs)), nil + } + + lidiaBytes, err := s.getLidiaBytes(ctx, buildID) + // Whatever the fetch outcome, only this caller's own context ends the + // call: errors from below may carry context errors that are not ours, + // and the shared fetch can succeed after our context is done. + if ctxErr := ctx.Err(); ctxErr != nil { + return nil, fmt.Errorf("resolve symbols: %w", ctxErr) + } + if err != nil { + level.Warn(s.logger).Log("msg", "Failed to get debug info", "buildID", buildID, "binaryName", binaryName, "err", err) + return make([][]lidia.SourceInfoFrame, len(addrs)), nil + } + + lidiaReader := NewReaderAtCloser(lidiaBytes) + table, err := lidia.OpenReader(lidiaReader, lidia.WithCRC()) + if err != nil { + s.metrics.debugSymbolResolutionErrors.WithLabelValues("lidia_error").Inc() + level.Warn(s.logger).Log("msg", "Failed to open Lidia file", "err", err) + return make([][]lidia.SourceInfoFrame, len(addrs)), nil + } + defer table.Close() + + return s.resolveWithTable(table, addrs), nil +} + +func (s *Symbolizer) resolveWithTable(table *lidia.Table, addrs []uint64) [][]lidia.SourceInfoFrame { + result := make([][]lidia.SourceInfoFrame, len(addrs)) + var framesBuf []lidia.SourceInfoFrame + + resolveStart := time.Now() + defer func() { + s.metrics.debugSymbolResolution.WithLabelValues(statusSuccess).Observe(time.Since(resolveStart).Seconds()) + }() + + for i, addr := range addrs { + frames, err := table.Lookup(framesBuf, addr) + if err != nil || len(frames) == 0 { + continue // result[i] stays nil + } + result[i] = frames + } + return result +} + +type Config struct { + DebuginfodURL string `yaml:"debuginfod_url" category:"advanced"` + MaxDebuginfodConcurrency int `yaml:"max_debuginfod_concurrency" category:"advanced"` +} + +func (cfg *Config) RegisterFlags(f *flag.FlagSet) { + f.StringVar(&cfg.DebuginfodURL, "symbolizer.debuginfod-url", "https://debuginfod.elfutils.org", "URL of the debuginfod server") + f.IntVar(&cfg.MaxDebuginfodConcurrency, "symbolizer.max-debuginfod-concurrency", 10, "Maximum number of concurrent symbolization requests to debuginfod server.") +} + +func (cfg *Config) Validate() error { + if cfg.MaxDebuginfodConcurrency < 1 { + return fmt.Errorf("invalid max-debuginfod-concurrency value, must be positive") + } + return nil +} + +type Symbolizer struct { + logger log.Logger + client DebuginfodClient + bucket objstore.Bucket + metrics *metrics + cfg Config + limits Limits +} + +type ErrSymbolSizeBytesExceedsLimit struct { + Limit int64 +} + +func (e *ErrSymbolSizeBytesExceedsLimit) Error() string { + return fmt.Sprintf("symbol size exceeds maximum allowed size of %d bytes", e.Limit) +} + +type Limits interface { + SymbolizerMaxSymbolSizeBytes(tenantID string) int +} + +func New(logger log.Logger, cfg Config, reg prometheus.Registerer, storageBucket objstore.Bucket, limits Limits) (*Symbolizer, error) { + if err := cfg.Validate(); err != nil { + return nil, err + } + m := newMetrics(reg) + + client, err := NewDebuginfodClient(logger, cfg.DebuginfodURL, m, limits) + if err != nil { + return nil, err + } + + return &Symbolizer{ + logger: logger, + client: client, + bucket: storageBucket, + metrics: m, + cfg: cfg, + limits: limits, + }, nil +} + +func (s *Symbolizer) SymbolizePprof(ctx context.Context, profile *googlev1.Profile) error { + start := time.Now() + status := statusSuccess + defer func() { + s.metrics.profileSymbolization.WithLabelValues(status).Observe(time.Since(start).Seconds()) + }() + + mappingsToSymbolize := make(map[uint64]bool) + for i, mapping := range profile.Mapping { + if mapping.HasFunctions { + continue + } + mappingsToSymbolize[uint64(i+1)] = true + } + if len(mappingsToSymbolize) == 0 { + return nil + } + + locationsByMapping, err := s.groupLocationsByMapping(profile, mappingsToSymbolize) + if err != nil { + return fmt.Errorf("grouping locations by mapping: %w", err) + } + + stringMap := make(map[string]int64, len(profile.StringTable)) + for i, str := range profile.StringTable { + stringMap[str] = int64(i) + } + + allSymbolizedLocs, err := s.symbolizeMappingsConcurrently(ctx, profile, locationsByMapping) + if err != nil { + return fmt.Errorf("symbolizing mappings: %w", err) + } + + s.updateAllSymbolsInProfile(profile, allSymbolizedLocs, stringMap) + + return nil +} + +// symbolizeMappingsConcurrently symbolizes multiple mappings concurrently with a concurrency limit. +func (s *Symbolizer) symbolizeMappingsConcurrently( + ctx context.Context, + profile *googlev1.Profile, + locationsByMapping map[uint64][]*googlev1.Location, +) ([]symbolizedLocation, error) { + maxConcurrency := s.cfg.MaxDebuginfodConcurrency + if maxConcurrency <= 0 { + maxConcurrency = 10 + } + + type mappingJob struct { + mappingID uint64 + locations []*googlev1.Location + } + + type mappingResult struct { + mappingID uint64 + locations []symbolizedLocation + } + + totalLocs := 0 + jobs := make(chan mappingJob, len(locationsByMapping)) + for mappingID, locations := range locationsByMapping { + totalLocs += len(locations) + jobs <- mappingJob{mappingID: mappingID, locations: locations} + } + close(jobs) + + // Process jobs concurrently with errgroup for proper error handling + g, ctx := errgroup.WithContext(ctx) + g.SetLimit(maxConcurrency) + + // Results channel with buffer to avoid blocking jobs + results := make(chan mappingResult, len(locationsByMapping)) + + for job := range jobs { + job := job + g.Go(func() error { + mapping := profile.Mapping[job.mappingID-1] + + binaryName, err := s.extractBinaryName(profile, mapping) + if err != nil { + return fmt.Errorf("extract binary name for mapping %d: %w", job.mappingID, err) + } + + buildID, err := s.extractBuildID(profile, mapping) + if err != nil { + return fmt.Errorf("extract build ID for mapping %d: %w", job.mappingID, err) + } + + addrs := make([]uint64, len(job.locations)) + for i, loc := range job.locations { + addrs[i] = loc.Address + } + + frames, err := s.Resolve(ctx, buildID, binaryName, addrs) + if err != nil { + return fmt.Errorf("resolve mapping %d: %w", job.mappingID, err) + } + + // Collect symbolized locations for this mapping + symbolizedLocs := make([]symbolizedLocation, len(job.locations)) + for i, loc := range job.locations { + lines := frames[i] + if len(lines) == 0 { + lines = s.createFallbackSymbol(binaryName, loc.Address) + } + symbolizedLocs[i] = symbolizedLocation{ + loc: loc, + lines: lines, + mapping: mapping, + } + } + + select { + case results <- mappingResult{mappingID: job.mappingID, locations: symbolizedLocs}: + case <-ctx.Done(): + return ctx.Err() + } + + return nil + }) + } + + err := g.Wait() + close(results) + + if err != nil { + return nil, err + } + + allSymbolizedLocs := make([]symbolizedLocation, 0, totalLocs) + for result := range results { + allSymbolizedLocs = append(allSymbolizedLocs, result.locations...) + } + + return allSymbolizedLocs, nil +} + +// groupLocationsByMapping groups locations by their mapping ID +func (s *Symbolizer) groupLocationsByMapping(profile *googlev1.Profile, mappingsToSymbolize map[uint64]bool) (map[uint64][]*googlev1.Location, error) { + locsByMapping := make(map[uint64][]*googlev1.Location) + + for i, loc := range profile.Location { + if loc.MappingId == 0 { + // MappingId 0 is valid per the pprof spec for locations without a + // known mapping (e.g. JIT-compiled or kernel frames). Skip them as + // there is no binary to look up symbols in. + continue + } + + mappingIdx := loc.MappingId - 1 + if int(mappingIdx) >= len(profile.Mapping) { + return nil, fmt.Errorf("invalid profile: location at index %d references non-existent mapping %d", i, loc.MappingId) + } + + if !mappingsToSymbolize[loc.MappingId] { + continue + } + + // Skip locations that already have symbols + if len(loc.Line) > 0 { + continue + } + + locsByMapping[loc.MappingId] = append(locsByMapping[loc.MappingId], loc) + } + + return locsByMapping, nil +} + +// extractBinaryName extracts the binary name from the mapping +func (s *Symbolizer) extractBinaryName(profile *googlev1.Profile, mapping *googlev1.Mapping) (string, error) { + if mapping.Filename < 0 || int(mapping.Filename) >= len(profile.StringTable) { + return "", fmt.Errorf("invalid mapping: filename index %d out of range (string table length: %d)", + mapping.Filename, len(profile.StringTable)) + } + + fullPath := profile.StringTable[mapping.Filename] + return filepath.Base(fullPath), nil +} + +// extractBuildID extracts and sanitizes the build ID from the mapping +func (s *Symbolizer) extractBuildID(profile *googlev1.Profile, mapping *googlev1.Mapping) (string, error) { + buildID := profile.StringTable[mapping.BuildId] + sanitizedBuildID, err := sanitizeBuildID(buildID) + if err != nil { + level.Error(s.logger).Log("msg", "Invalid buildID", "buildID", buildID) + return "", err + } + + return sanitizedBuildID, nil +} + +func (s *Symbolizer) updateAllSymbolsInProfile( + profile *googlev1.Profile, + symbolizedLocs []symbolizedLocation, + stringMap map[string]int64, +) { + funcMap := make(map[funcKey]uint64) + maxFuncID := uint64(len(profile.Function)) + funcPtrMap := make(map[uint64]*googlev1.Function) + + for _, item := range symbolizedLocs { + loc := item.loc + lines := item.lines + mapping := item.mapping + + locIdx := loc.Id - 1 + if loc.Id <= 0 || locIdx >= uint64(len(profile.Location)) { + continue + } + + profile.Location[locIdx].Line = make([]*googlev1.Line, len(lines)) + + for j, line := range lines { + nameIdx, ok := stringMap[line.FunctionName] + if !ok { + nameIdx = int64(len(profile.StringTable)) + profile.StringTable = append(profile.StringTable, line.FunctionName) + stringMap[line.FunctionName] = nameIdx + } + + filenameIdx, ok := stringMap[line.FilePath] + if !ok { + filenameIdx = int64(len(profile.StringTable)) + profile.StringTable = append(profile.StringTable, line.FilePath) + stringMap[line.FilePath] = filenameIdx + } + + key := funcKey{nameIdx, filenameIdx} + funcID, ok := funcMap[key] + if !ok { + maxFuncID++ + funcID = maxFuncID + fn := &googlev1.Function{ + Id: funcID, + Name: nameIdx, + Filename: filenameIdx, + StartLine: int64(line.LineNumber), + } + profile.Function = append(profile.Function, fn) + funcMap[key] = funcID + funcPtrMap[funcID] = fn + } else { + // Update StartLine to be the minimum line number seen for this function + if line.LineNumber > 0 { + if fn, ok := funcPtrMap[funcID]; ok { + currentStartLine := fn.StartLine + // 0 means "not set" in proto + if currentStartLine == 0 || int64(line.LineNumber) < currentStartLine { + fn.StartLine = int64(line.LineNumber) + } + } + } + } + + profile.Location[locIdx].Line[j] = &googlev1.Line{ + FunctionId: funcID, + Line: int64(line.LineNumber), + } + } + + mapping.HasFunctions = true + } +} + +func (s *Symbolizer) getLidiaBytes(ctx context.Context, buildID string) ([]byte, error) { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, err + } + + lidiaBytes, err := s.fetchLidiaFromObjectStore(ctx, tenantID, buildID) + if err == nil { + s.metrics.cacheOperations.WithLabelValues("object_storage", "get", statusSuccess).Inc() + return lidiaBytes, nil + } + s.metrics.cacheOperations.WithLabelValues("object_storage", "get", "miss").Inc() + + lidiaBytes, err = s.fetchLidiaFromDebuginfod(ctx, buildID) + if err != nil { + return nil, err + } + + if err := s.bucket.Upload(ctx, lidiaObjectPath(tenantID, buildID), bytes.NewReader(lidiaBytes)); err != nil { + level.Warn(s.logger).Log("msg", "Failed to store debug info in objstore", "buildID", buildID, "err", err) + s.metrics.cacheOperations.WithLabelValues("object_storage", "set", "error").Inc() + } else { + s.metrics.cacheOperations.WithLabelValues("object_storage", "set", statusSuccess).Inc() + } + + return lidiaBytes, nil +} + +// fetchLidiaFromObjectStore retrieves Lidia data from the object store +func (s *Symbolizer) fetchLidiaFromObjectStore(ctx context.Context, tenantID, buildID string) ([]byte, error) { + objstoreReader, err := s.bucket.Get(ctx, lidiaObjectPath(tenantID, buildID)) + if err != nil { + return nil, err + } + defer objstoreReader.Close() + + data, err := io.ReadAll(objstoreReader) + if err != nil { + return nil, fmt.Errorf("read content: %w", err) + } + + return data, nil +} + +func lidiaObjectPath(tenantID, buildID string) string { + return path.Join(bucketPrefix, tenantID, buildID) +} + +// fetchLidiaFromDebuginfod fetches debug info from debuginfod and converts to Lidia format +func (s *Symbolizer) fetchLidiaFromDebuginfod(ctx context.Context, buildID string) ([]byte, error) { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, err + } + + debugReader, err := s.fetch(ctx, buildID) + if err != nil { + var bnfErr buildIDNotFoundError + if errors.As(err, &bnfErr) { + return nil, err + } + return nil, err + } + defer debugReader.Close() + + maxSize := int64(s.limits.SymbolizerMaxSymbolSizeBytes(tenantID)) + elfData, err := readAllWithLimit(debugReader, "debuginfo", maxSize) + if err != nil { + return nil, fmt.Errorf("read debuginfo data: %w", err) + } + + lidiaData, err := s.processELFData(elfData, maxSize) + if err != nil { + return nil, err + } + + return lidiaData, nil +} + +func (s *Symbolizer) fetch(ctx context.Context, buildID string) (io.ReadCloser, error) { + if r, err := s.fetchFromUploadedDebugInfo(ctx, buildID); err == nil { + return r, nil + } + return s.fetchFromDebuginfod(ctx, buildID) +} + +func (s *Symbolizer) fetchFromUploadedDebugInfo(ctx context.Context, buildID string) (io.ReadCloser, error) { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return nil, err + } + validatedBuildID, err := debuginfo.ValidateGnuBuildID(buildID) + if err != nil { + return nil, err + } + return s.bucket.Get(ctx, debuginfo.ObjectPath(tenantID, validatedBuildID)) +} + +func (s *Symbolizer) fetchFromDebuginfod(ctx context.Context, buildID string) (io.ReadCloser, error) { + debugReader, err := s.client.FetchDebuginfo(ctx, buildID) + if err != nil { + var bnfErr buildIDNotFoundError + statusCode, isHTTPError := isHTTPStatusError(err) + + if errors.As(err, &bnfErr) || (isHTTPError && statusCode == http.StatusNotFound) { + return nil, buildIDNotFoundError{buildID: buildID} + } + + return nil, fmt.Errorf("fetch debuginfo: %w", err) + } + + return debugReader, nil +} + +func (s *Symbolizer) processELFData(data []byte, maxSize int64) (lidiaData []byte, err error) { + decompressedData, err := detectCompression(data, maxSize) + if err != nil { + s.metrics.debugSymbolResolutionErrors.WithLabelValues("compression_error").Inc() + return nil, fmt.Errorf("detect compression: %w", err) + } + + reader := bytes.NewReader(decompressedData) + + elfFile, err := elf.NewFile(reader) + if err != nil { + s.metrics.debugSymbolResolutionErrors.WithLabelValues("elf_parsing_error").Inc() + return nil, fmt.Errorf("parse ELF file: %w", err) + } + defer elfFile.Close() + + initialSize := len(data) * 2 // A simple heuristic: twice the compressed size + memBuffer := newMemoryBuffer(initialSize) + + err = lidia.CreateLidiaFromELF(elfFile, memBuffer, lidia.WithCRC(), lidia.WithFiles(), lidia.WithLines()) + if err != nil { + return nil, fmt.Errorf("create lidia file: %w", err) + } + + return memBuffer.Bytes(), nil +} + +func (s *Symbolizer) createFallbackSymbol(binaryName string, address uint64) []lidia.SourceInfoFrame { + prefix := "unknown" + if binaryName != "" { + prefix = binaryName + } + + return []lidia.SourceInfoFrame{{ + FunctionName: fmt.Sprintf("%s!0x%x", prefix, address), + LineNumber: 0, + }} +} diff --git a/pkg/symbolizer/symbolizer_test.go b/pkg/symbolizer/symbolizer_test.go new file mode 100644 index 0000000000..96b3119c89 --- /dev/null +++ b/pkg/symbolizer/symbolizer_test.go @@ -0,0 +1,796 @@ +package symbolizer + +import ( + "bytes" + "compress/gzip" + "context" + "fmt" + "io" + "os" + "strings" + "testing" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/lidia" + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mockobjstore" + "github.com/grafana/pyroscope/v2/pkg/test/mocks/mocksymbolizer" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +type symbolizerInputs struct { + Registry *prometheus.Registry + Limits Limits +} + +func newSymbolizerTest(t *testing.T, inp *symbolizerInputs) (*Symbolizer, *mocksymbolizer.MockDebuginfodClient, *mockobjstore.MockBucket) { + t.Helper() + mockClient := mocksymbolizer.NewMockDebuginfodClient(t) + lidiaBucket := mockobjstore.NewMockBucket(t) + + if inp == nil { + inp = &symbolizerInputs{} + } + + if inp.Limits == nil { + inp.Limits = validation.MockDefaultOverrides() + } + + if inp.Registry == nil { + inp.Registry = prometheus.NewRegistry() + } + + s, err := New( + log.NewNopLogger(), + Config{MaxDebuginfodConcurrency: 1}, + inp.Registry, + lidiaBucket, + inp.Limits, + ) + require.NoError(t, err) + s.client = mockClient + + return s, mockClient, lidiaBucket +} + +// TestSymbolizePprof tests symbolization using testdata/symbols.debug which contains: +// +// 0x1500 -> (contains both functions) +// - main (/usr/src/stress-1.0.7-1/src/stress.c:87) +// - fprintf (/usr/include/x86_64-linux-gnu/bits/stdio2.h:77) +// +// 0x3c5a -> atoll_b (/usr/src/stress-1.0.7-1/src/stress.c:632) +// 0x2745 -> main (/usr/src/stress-1.0.7-1/src/stress.c:87) +// todo add parca bucket test +func TestSymbolizePprof(t *testing.T) { + tests := []struct { + name string + profile *googlev1.Profile + setupMock func(*mocksymbolizer.MockDebuginfodClient, *mockobjstore.MockBucket) + wantErr bool + validate func(*testing.T, *googlev1.Profile) + }{ + { + name: "already symbolized mapping", + profile: &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + HasFunctions: true, + HasFilenames: true, + HasLineNumbers: true, + }}, + Location: []*googlev1.Location{{ + MappingId: 1, + Line: []*googlev1.Line{{ + FunctionId: 0, + Line: 42, + }}, + }}, + Function: []*googlev1.Function{{ + Name: 1, + Filename: 2, + }}, + StringTable: []string{"", "main", "main.go"}, + }, + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + + }, + validate: func(t *testing.T, p *googlev1.Profile) { + require.True(t, p.Mapping[0].HasFunctions) + require.True(t, p.Mapping[0].HasFilenames) + require.True(t, p.Mapping[0].HasLineNumbers) + }, + }, + { + name: "needs symbolization single address", + profile: &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + BuildId: 1, + MemoryStart: 0x0, + MemoryLimit: 0x1000000, + FileOffset: 0x0, + }}, + Location: []*googlev1.Location{{ + Id: 1, + MappingId: 1, + Address: 0x1500, + }}, + StringTable: []string{"", "build-id"}, + }, + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(openTestFile(t), nil).Once() + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Return(nil).Once() + + }, + validate: func(t *testing.T, p *googlev1.Profile) { + require.True(t, p.Mapping[0].HasFunctions) + + require.Len(t, p.Location[0].Line, 1) + + assertLocationHasFunction(t, p, p.Location[0], "main", "main") + }, + }, + { + name: "empty build ID creates fallback symbols", + profile: &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + Id: 1, + Filename: 2, + BuildId: 1, + }}, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0xa4c}, + {Id: 2, MappingId: 1, Address: 0x9f0}, + }, + StringTable: []string{"", "", "linux-vdso.1.so"}, + }, + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + + }, + validate: func(t *testing.T, p *googlev1.Profile) { + require.True(t, p.Mapping[0].HasFunctions) + require.Len(t, p.Location[0].Line, 1) + require.Len(t, p.Location[1].Line, 1) + + fn1 := p.StringTable[p.Function[p.Location[0].Line[0].FunctionId-1].Name] + fn2 := p.StringTable[p.Function[p.Location[1].Line[0].FunctionId-1].Name] + require.Contains(t, fn1, "linux-vdso.1.so") + require.Contains(t, fn1, "0xa4c") + require.Contains(t, fn2, "linux-vdso.1.so") + require.Contains(t, fn2, "0x9f0") + }, + }, + { + name: "multiple locations per mapping", + profile: &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + BuildId: 1, + MemoryStart: 0x0, + MemoryLimit: 0x1000000, + FileOffset: 0x0, + }}, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0x1500}, + {Id: 2, MappingId: 1, Address: 0x3b60}, + {Id: 3, MappingId: 1, Address: 0x1440}, + }, + StringTable: []string{"", "build-id"}, + }, + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(openTestFile(t), nil).Once() + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Return(nil).Once() + + }, + validate: func(t *testing.T, p *googlev1.Profile) { + require.True(t, p.Mapping[0].HasFunctions) + + // First location (0x1500) - main + require.Len(t, p.Location[0].Line, 1) + assertLocationHasFunction(t, p, p.Location[0], "main", "main") + + // Second location (0x3b60) - atoll_b + require.Len(t, p.Location[1].Line, 1) + assertLocationHasFunction(t, p, p.Location[1], "atoll_b", "atoll_b") + + // Third location (0x1440) - main + require.Len(t, p.Location[2].Line, 1) + assertLocationHasFunction(t, p, p.Location[2], "main", "main") + }, + }, + { + name: "preserve existing symbols when HasFunctions=false", + // This tests a defensive check against data inconsistency where a mapping has + // HasFunctions=false but contains locations with existing symbols. + // This scenario should be rare, but we maintain the check for robustness. + profile: &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + Id: 1, + BuildId: 1, + Filename: 2, + MemoryStart: 0x0, + MemoryLimit: 0x1000000, + FileOffset: 0x0, + HasFunctions: false, + }}, + Location: []*googlev1.Location{ + { + Id: 1, + MappingId: 1, + Address: 0x1000, + Line: []*googlev1.Line{{ + FunctionId: 1, + Line: 42, + }}, + }, + { + Id: 2, + MappingId: 1, + Address: 0x1500, + Line: nil, + }, + }, + Function: []*googlev1.Function{{ + Id: 1, + Name: 3, + }}, + StringTable: []string{"", "build-id", "alloy", "existing_function"}, + }, + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(openTestFile(t), nil).Once() + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Return(nil).Once() + + }, + validate: func(t *testing.T, p *googlev1.Profile) { + require.True(t, p.Mapping[0].HasFunctions) + + require.Len(t, p.Location[0].Line, 1) + require.Equal(t, uint64(1), p.Location[0].Line[0].FunctionId) + require.Equal(t, "existing_function", p.StringTable[p.Function[0].Name]) + + require.Len(t, p.Location[1].Line, 1) + assertLocationHasFunction(t, p, p.Location[1], "main", "main") + + existingFuncStillExists := false + for _, str := range p.StringTable { + if str == "existing_function" { + existingFuncStillExists = true + break + } + } + require.True(t, existingFuncStillExists) + + placeholderFound := false + for _, str := range p.StringTable { + if strings.Contains(str, "!0x") { + placeholderFound = true + break + } + } + require.False(t, placeholderFound) + }, + }, + { + name: "locations with MappingId 0 are skipped", + profile: &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + BuildId: 1, + MemoryStart: 0x0, + MemoryLimit: 0x1000000, + FileOffset: 0x0, + }}, + Location: []*googlev1.Location{ + // MappingId 0: kernel/JIT frame with no mapping — must not cause an error + {Id: 1, MappingId: 0, Address: 0xffffffff}, + // Normal location that should be symbolized + {Id: 2, MappingId: 1, Address: 0x1500}, + }, + StringTable: []string{"", "build-id"}, + }, + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(openTestFile(t), nil).Once() + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Return(nil).Once() + }, + validate: func(t *testing.T, p *googlev1.Profile) { + // Location with MappingId 0 should be untouched + require.Empty(t, p.Location[0].Line) + // Normal location should be symbolized + require.NotEmpty(t, p.Location[1].Line) + assertLocationHasFunction(t, p, p.Location[1], "main", "main") + }, + }, + { + name: "parca bucket provides debuginfo when debuginfod has no data", + profile: &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{ + BuildId: 1, + MemoryStart: 0x0, + MemoryLimit: 0x1000000, + FileOffset: 0x0, + }}, + Location: []*googlev1.Location{{ + Id: 1, + MappingId: 1, + Address: 0x1500, + }}, + StringTable: []string{"", "abcdef1234abcdef1234"}, + }, + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "abcdef1234abcdef1234")).Return(nil, fmt.Errorf("not found")).Once() + mockBucket.On("Get", mock.Anything, "debug-info/tenant/abcdef1234abcdef1234/exe").Return(openTestFile(t), nil).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "abcdef1234abcdef1234"), mock.Anything).Return(nil).Once() + }, + validate: func(t *testing.T, p *googlev1.Profile) { + require.True(t, p.Mapping[0].HasFunctions) + require.Len(t, p.Location[0].Line, 1) + assertLocationHasFunction(t, p, p.Location[0], "main", "main") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + tt.setupMock(mockClient, mockBucket) + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + err := s.SymbolizePprof(ctx, tt.profile) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + tt.validate(t, tt.profile) + mockClient.AssertExpectations(t) + }) + } +} + +func TestSymbolizationKeepsSequentialFunctionIDs(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + + profile := &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{BuildId: 1}}, + Location: []*googlev1.Location{{Id: 1, MappingId: 1, Address: 0x1500}}, + Function: []*googlev1.Function{{Id: 1, Name: 1}}, + StringTable: []string{"", "build-id", "existing_func"}, + Sample: []*googlev1.Sample{{ + LocationId: []uint64{1}, + Value: []int64{100}, + }}, + } + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")) + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(openTestFile(t), nil) + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Return(nil) + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + err := s.SymbolizePprof(ctx, profile) + require.NoError(t, err) + + // Verify sequential function IDs + for i, fn := range profile.Function { + require.Equal(t, uint64(i+1), fn.Id) + } + + _, err = model.TreeFromBackendProfile(profile, 1000) + require.NoError(t, err) +} + +func TestSymbolizationWithLidiaData(t *testing.T) { + + const testLidiaZip = "testdata/test_lidia_file.gz" + const buildID = "ffcf60c240417166980a43fbbfde486e0b3718e5" + + lidiaData, err := extractGzipFile(t, testLidiaZip) + require.NoError(t, err) + require.NotEmpty(t, lidiaData) + + // Configure the mock to return the same Lidia data for both Get operations + getLidiaData := func() io.ReadCloser { + return io.NopCloser(bytes.NewReader(lidiaData)) + } + + sym, _, mockBucket := newSymbolizerTest(t, nil) + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", buildID)).Return(getLidiaData(), nil).Once() + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", buildID)).Return(getLidiaData(), nil).Once() + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + frames, err := sym.Resolve(ctx, buildID, "test-binary", []uint64{0x1b743d6}) + require.NoError(t, err) + require.NotEmpty(t, frames[0]) + + // Second request should also fetch from store + frames2, err := sym.Resolve(ctx, buildID, "test-binary", []uint64{0x1b743d6}) + require.NoError(t, err) + require.NotEmpty(t, frames2[0]) +} + +// TestSymbolizeWithObjectStore validates the symbolizer's behavior with the object store +func TestSymbolizeWithObjectStore(t *testing.T) { + + elfTestFile := openTestFile(t) + elfData, err := io.ReadAll(elfTestFile) + elfTestFile.Close() + require.NoError(t, err) + + var capturedLidiaData []byte + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + + // 1. First request: Object store miss → fetch from debuginfod → store Lidia data in object store + t.Run("store-miss", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return(io.NopCloser(bytes.NewReader(elfData)), nil).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Run(func(args mock.Arguments) { + reader := args.Get(2).(io.Reader) + var buf bytes.Buffer + teeReader := io.TeeReader(reader, &buf) + var err error + capturedLidiaData, err = io.ReadAll(teeReader) + require.NoError(t, err) + }).Return(nil).Once() + + frames, err := s.Resolve(ctx, "build-id", "", []uint64{0x1500}) + require.NoError(t, err) + require.NotEmpty(t, frames[0]) + require.NotEmpty(t, capturedLidiaData) + + mockClient.AssertExpectations(t) + mockBucket.AssertExpectations(t) + + }) + + // 2. Second request (same build-id, same address): Object store hit → use cached Lidia data + t.Run("store hit, same address", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return( + io.NopCloser(bytes.NewReader(capturedLidiaData)), nil, + ).Once() + + frames, err := s.Resolve(ctx, "build-id", "", []uint64{0x1500}) + require.NoError(t, err) + require.NotEmpty(t, frames[0]) + + mockClient.AssertExpectations(t) + mockBucket.AssertExpectations(t) + }) + + // 3. Third request (same build-id, different address): Object store hit → use cached Lidia data + t.Run("store hit, different address", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return( + io.NopCloser(bytes.NewReader(capturedLidiaData)), nil, + ).Once() + + frames, err := s.Resolve(ctx, "build-id", "", []uint64{0x3c5a}) + require.NoError(t, err) + require.NotEmpty(t, frames[0]) + + mockClient.AssertExpectations(t) + mockBucket.AssertExpectations(t) + }) + + // 4. Fourth request (different build-id): Object store miss → fetch from debuginfod → store Lidia data + t.Run("store miss, different build-id", func(t *testing.T) { + s, mockClient, mockBucket := newSymbolizerTest(t, nil) + + var capturedLidiaData2 []byte + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "different-build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockClient.On("FetchDebuginfo", mock.Anything, "different-build-id").Return(io.NopCloser(bytes.NewReader(elfData)), nil).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "different-build-id"), mock.Anything).Run(func(args mock.Arguments) { + reader := args.Get(2).(io.Reader) + var buf bytes.Buffer + teeReader := io.TeeReader(reader, &buf) + var err error + capturedLidiaData2, err = io.ReadAll(teeReader) + require.NoError(t, err) + }).Return(nil).Once() + + frames, err := s.Resolve(ctx, "different-build-id", "", []uint64{0x1500}) + require.NoError(t, err) + require.NotEmpty(t, frames[0]) + require.NotEmpty(t, capturedLidiaData2) + + mockClient.AssertExpectations(t) + mockBucket.AssertExpectations(t) + }) + +} + +func TestSymbolizerMetrics(t *testing.T) { + tests := []struct { + name string + setupMock func(*mocksymbolizer.MockDebuginfodClient, *mockobjstore.MockBucket) + setupTest func(*Symbolizer, context.Context) + expected map[string]int + }{ + { + name: "successful symbolization with cache", + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + elfTestFile := openTestFile(t) + elfData, err := io.ReadAll(elfTestFile) + elfTestFile.Close() + require.NoError(t, err) + + preProcessor := &Symbolizer{ + logger: log.NewNopLogger(), + metrics: newMetrics(nil), + } + lidiaData, err := preProcessor.processELFData(elfData, 0) // 0 means unlimited + require.NoError(t, err) + require.NotEmpty(t, lidiaData) + + mockBucket.On("IsObjNotFoundErr", mock.Anything).Return(true).Maybe() + mockBucket.On("Name").Return("test-bucket").Maybe() + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return(nil, fmt.Errorf("not found")).Once() + + mockClient.On("FetchDebuginfo", mock.Anything, "build-id").Return( + io.NopCloser(bytes.NewReader(elfData)), nil, + ).Once() + mockBucket.On("Upload", mock.Anything, lidiaObjectPath("tenant", "build-id"), mock.Anything).Return(nil).Once() + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "build-id")).Return( + io.NopCloser(bytes.NewReader(lidiaData)), nil, + ).Once() + }, + setupTest: func(s *Symbolizer, ctx context.Context) { + _, err := s.Resolve(ctx, "build-id", "", []uint64{0x1500}) + require.NoError(t, err) + + _, err = s.Resolve(ctx, "build-id", "", []uint64{0x1500}) + require.NoError(t, err) + }, + expected: map[string]int{ + "pyroscope_profile_symbolization_duration_seconds": 0, + "pyroscope_debug_symbol_resolution_duration_seconds": 1, + "pyroscope_debug_symbol_resolution_errors_total": 0, + }, + }, + { + name: "debuginfod error", + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "unknown-build-id")).Return(nil, fmt.Errorf("not found")).Once() + mockClient.On("FetchDebuginfo", mock.Anything, "unknown-build-id"). + Return(nil, buildIDNotFoundError{buildID: "unknown-build-id"}).Once() + }, + setupTest: func(s *Symbolizer, ctx context.Context) { + frames, err := s.Resolve(ctx, "unknown-build-id", "some-binary", []uint64{0x1500}) + require.NoError(t, err) + require.Len(t, frames, 1) + require.Nil(t, frames[0]) + }, + expected: map[string]int{ + "pyroscope_profile_symbolization_duration_seconds": 0, + "pyroscope_debug_symbol_resolution_duration_seconds": 0, + "pyroscope_debug_symbol_resolution_errors_total": 0, + }, + }, + { + name: "elf_parsing_error", + setupMock: func(mockClient *mocksymbolizer.MockDebuginfodClient, mockBucket *mockobjstore.MockBucket) { + invalidData := []byte("invalid elf data") + + mockBucket.On("Get", mock.Anything, lidiaObjectPath("tenant", "invalid-elf")).Return(nil, fmt.Errorf("not found")).Once() + mockClient.On("FetchDebuginfo", mock.Anything, "invalid-elf").Return( + io.NopCloser(bytes.NewReader(invalidData)), nil, + ).Once() + }, + setupTest: func(s *Symbolizer, ctx context.Context) { + _, err := s.Resolve(ctx, "invalid-elf", "", []uint64{0x1500}) + require.NoError(t, err) + }, + expected: map[string]int{ + "pyroscope_profile_symbolization_duration_seconds": 0, + "pyroscope_debug_symbol_resolution_errors_total": 1, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + reg := prometheus.NewRegistry() + s, mockClient, mockBucket := newSymbolizerTest(t, &symbolizerInputs{Registry: reg}) + + tt.setupMock(mockClient, mockBucket) + + ctx := tenant.InjectTenantID(context.Background(), "tenant") + tt.setupTest(s, ctx) + + for metricName, expectedCount := range tt.expected { + count, err := testutil.GatherAndCount(reg, metricName) + require.NoError(t, err, "Error gathering metric %s", metricName) + require.Equal(t, expectedCount, count, "Metric %s count mismatch", metricName) + } + + mockClient.AssertExpectations(t) + mockBucket.AssertExpectations(t) + }) + } +} + +func assertLocationHasFunction(t *testing.T, profile *googlev1.Profile, loc *googlev1.Location, + functionName, fileName string) { + t.Helper() + + found := false + + for _, line := range loc.Line { + for _, fn := range profile.Function { + if fn.Id == line.FunctionId { + name := "" + if fn.Name >= 0 && int(fn.Name) < len(profile.StringTable) { + name = profile.StringTable[fn.Name] + } + if name == functionName { + found = true + } + } + } + } + + require.True(t, found, "Function %q not found in location", functionName) + + if found { + fileNameFound := false + for _, str := range profile.StringTable { + if str == fileName { + fileNameFound = true + break + } + } + require.True(t, fileNameFound, "Filename %q not found in string table", fileName) + } + +} + +func openTestFile(t *testing.T) io.ReadCloser { + t.Helper() + f, err := os.Open("testdata/symbols.debug") + require.NoError(t, err) + + data, err := io.ReadAll(f) + require.NoError(t, err) + f.Close() + + return NewReaderAtCloser(data) +} + +func extractGzipFile(t *testing.T, gzipPath string) ([]byte, error) { + t.Helper() + file, err := os.Open(gzipPath) + if err != nil { + return nil, err + } + defer file.Close() + + gzipReader, err := gzip.NewReader(file) + if err != nil { + return nil, err + } + defer gzipReader.Close() + + return io.ReadAll(gzipReader) +} + +func TestConfigValidate(t *testing.T) { + tests := []struct { + name string + setup func(cfg *Config) + wantErr bool + }{ + { + name: "valid config with positive concurrency", + setup: func(cfg *Config) { cfg.MaxDebuginfodConcurrency = 10 }, + wantErr: false, + }, + { + name: "invalid config with zero concurrency", + setup: func(cfg *Config) { cfg.MaxDebuginfodConcurrency = 0 }, + wantErr: true, + }, + { + name: "invalid config with negative concurrency", + setup: func(cfg *Config) { cfg.MaxDebuginfodConcurrency = -1 }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := Config{} + tt.setup(&cfg) + err := cfg.Validate() + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +// TestUpdateAllSymbolsInProfile verifies that line numbers, file paths, and StartLine +// are properly passed through from SourceInfoFrame to the profile. +func TestUpdateAllSymbolsInProfile(t *testing.T) { + s := &Symbolizer{logger: log.NewNopLogger()} + stringMap := make(map[string]int64) + + t.Run("basic symbolization", func(t *testing.T) { + profile := &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{Id: 1, HasFunctions: false}}, + Location: []*googlev1.Location{{Id: 1, MappingId: 1, Address: 0x1500}}, + StringTable: []string{""}, + Function: []*googlev1.Function{}, + } + + symbolizedLocs := []symbolizedLocation{{ + loc: profile.Location[0], + lines: []lidia.SourceInfoFrame{{LineNumber: 42, FunctionName: "testFunction", FilePath: "/path/to/test.go"}}, + mapping: profile.Mapping[0], + }} + + s.updateAllSymbolsInProfile(profile, symbolizedLocs, stringMap) + + require.True(t, profile.Mapping[0].HasFunctions) + require.Len(t, profile.Location[0].Line, 1) + require.Len(t, profile.Function, 1) + + line := profile.Location[0].Line[0] + fn := profile.Function[0] + + require.Equal(t, int64(42), line.Line) + require.Equal(t, int64(42), fn.StartLine) + require.Equal(t, "testFunction", profile.StringTable[fn.Name]) + require.Equal(t, "/path/to/test.go", profile.StringTable[fn.Filename]) + }) + + t.Run("minimum StartLine for same function", func(t *testing.T) { + profile := &googlev1.Profile{ + Mapping: []*googlev1.Mapping{{Id: 1, HasFunctions: false}}, + Location: []*googlev1.Location{ + {Id: 1, MappingId: 1, Address: 0x1500}, + {Id: 2, MappingId: 1, Address: 0x1600}, + }, + StringTable: []string{""}, + Function: []*googlev1.Function{}, + } + + symbolizedLocs := []symbolizedLocation{ + { + loc: profile.Location[0], + lines: []lidia.SourceInfoFrame{{LineNumber: 100, FunctionName: "testFunction", FilePath: "/path/to/test.go"}}, + mapping: profile.Mapping[0], + }, + { + loc: profile.Location[1], + lines: []lidia.SourceInfoFrame{{LineNumber: 50, FunctionName: "testFunction", FilePath: "/path/to/test.go"}}, + mapping: profile.Mapping[0], + }, + } + + s.updateAllSymbolsInProfile(profile, symbolizedLocs, stringMap) + + require.Len(t, profile.Function, 1) + // StartLine properly updated + require.Equal(t, int64(50), profile.Function[0].StartLine) + require.Equal(t, int64(100), profile.Location[0].Line[0].Line) + require.Equal(t, int64(50), profile.Location[1].Line[0].Line) + }) +} diff --git a/pkg/symbolizer/testdata/symbols.debug b/pkg/symbolizer/testdata/symbols.debug new file mode 100644 index 0000000000..61cdfba1aa Binary files /dev/null and b/pkg/symbolizer/testdata/symbols.debug differ diff --git a/pkg/symbolizer/testdata/test_lidia_file.gz b/pkg/symbolizer/testdata/test_lidia_file.gz new file mode 100644 index 0000000000..f72d192a4a Binary files /dev/null and b/pkg/symbolizer/testdata/test_lidia_file.gz differ diff --git a/pkg/symbolizer/types.go b/pkg/symbolizer/types.go new file mode 100644 index 0000000000..94597a8eee --- /dev/null +++ b/pkg/symbolizer/types.go @@ -0,0 +1,22 @@ +package symbolizer + +import ( + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + "github.com/grafana/pyroscope/lidia" +) + +// LidiaTableCacheEntry represents a cached Lidia table with its binary layout information +type LidiaTableCacheEntry struct { + Data []byte // Processed Lidia table data +} + +// symbolizedLocation represents a location that has been symbolized +type symbolizedLocation struct { + loc *googlev1.Location + lines []lidia.SourceInfoFrame + mapping *googlev1.Mapping +} + +type funcKey struct { + nameIdx, filenameIdx int64 +} diff --git a/pkg/tenant/interceptor.go b/pkg/tenant/interceptor.go index e820b4a3d3..7563738756 100644 --- a/pkg/tenant/interceptor.go +++ b/pkg/tenant/interceptor.go @@ -46,7 +46,10 @@ func (i *authInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { if !i.enabled { return next(InjectTenantID(ctx, DefaultTenantID), req) } - _, ctx, _ = ExtractTenantIDFromHeaders(ctx, req.Header()) + _, ctx, err := ExtractTenantIDFromHeaders(ctx, req.Header()) + if err != nil { + return nil, connect.NewError(connect.CodeUnauthenticated, err) + } resp, err := next(ctx, req) if err != nil && errors.Is(err, ErrNoTenantID) { @@ -72,7 +75,10 @@ func (i *authInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc if !i.enabled { return next(InjectTenantID(ctx, DefaultTenantID), conn) } - _, ctx, _ = ExtractTenantIDFromHeaders(ctx, conn.RequestHeader()) + _, ctx, err := ExtractTenantIDFromHeaders(ctx, conn.RequestHeader()) + if err != nil { + return connect.NewError(connect.CodeUnauthenticated, err) + } if err := next(ctx, conn); err != nil { if errors.Is(err, ErrNoTenantID) { return connect.NewError(connect.CodeUnauthenticated, err) @@ -85,7 +91,11 @@ func (i *authInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc var defaultResolver tenant.Resolver = tenant.NewMultiResolver() -// ExtractTenantIDFromHeaders extracts a single TenantID from http headers. +// ExtractTenantIDFromHeaders extracts the tenant ID(s) from http headers and +// injects them into the context. It supports both single and multi-tenant +// requests (pipe-separated org IDs such as "tenant-a|tenant-b"). +// Tenant IDs are deduplicated and sorted before being injected back into the +// context, so downstream handlers always see a canonical representation. func ExtractTenantIDFromHeaders(ctx context.Context, headers http.Header) (string, context.Context, error) { orgID := headers.Get(user.OrgIDHeaderName) if orgID == "" { @@ -93,12 +103,19 @@ func ExtractTenantIDFromHeaders(ctx context.Context, headers http.Header) (strin } ctx = InjectTenantID(ctx, orgID) - tenantID, err := defaultResolver.TenantID(ctx) + tenantIDs, err := defaultResolver.TenantIDs(ctx) if err != nil { - return "", nil, err + return "", ctx, err + } + + // Re-inject the normalized (deduped, sorted) string only + // when it differs from the raw header value. + normalized := tenant.JoinTenantIDs(tenantIDs) + if normalized != orgID { + ctx = InjectTenantID(ctx, normalized) } - return tenantID, ctx, nil + return normalized, ctx, nil } // ExtractTenantIDFromContext extracts a single TenantID from the context. diff --git a/pkg/tenant/interceptor_test.go b/pkg/tenant/interceptor_test.go index bc69aa2a48..40cbb92dcb 100644 --- a/pkg/tenant/interceptor_test.go +++ b/pkg/tenant/interceptor_test.go @@ -6,6 +6,7 @@ import ( "testing" "connectrpc.com/connect" + "github.com/grafana/dskit/user" "github.com/stretchr/testify/require" ) @@ -59,6 +60,68 @@ func Test_AuthInterceptor(t *testing.T) { require.NoError(t, err) require.Nil(t, resp) }, + "server: enable, allow multi-tenant header": func(t *testing.T) { + i := NewAuthInterceptor(true) + // Supply tenants out of order and with a duplicate to verify + // that the context receives the canonical (sorted, deduped) form. + req := newFakeReqWithHeader("tenant-b|tenant-a|tenant-b") + nextCalled := false + + resp, err := i.WrapUnary(func(ctx context.Context, ar connect.AnyRequest) (connect.AnyResponse, error) { + nextCalled = true + // The context must carry the normalised tenant string. + tenantID, tenantErr := ExtractTenantIDFromContext(ctx) + require.ErrorContains(t, tenantErr, "multiple org IDs") + _ = tenantID + // Use the raw org-ID to verify dedup+sort. + orgID, orgErr := user.ExtractOrgID(ctx) + require.NoError(t, orgErr) + require.Equal(t, "tenant-a|tenant-b", orgID, "tenants must be sorted and deduplicated") + return nil, nil + })(context.Background(), req) + + require.Nil(t, resp) + require.NoError(t, err) + require.True(t, nextCalled, "multi-tenant request must reach the handler") + }, + "server: enable, canonicalize duplicate tenant header": func(t *testing.T) { + i := NewAuthInterceptor(true) + req := newFakeReqWithHeader("tenant-a|tenant-a") + + resp, err := i.WrapUnary(func(ctx context.Context, ar connect.AnyRequest) (connect.AnyResponse, error) { + tenantID, tenantErr := ExtractTenantIDFromContext(ctx) + require.NoError(t, tenantErr) + require.Equal(t, "tenant-a", tenantID) + + orgID, orgErr := user.ExtractOrgID(ctx) + require.NoError(t, orgErr) + require.Equal(t, "tenant-a", orgID) + return nil, nil + })(context.Background(), req) + + require.Nil(t, resp) + require.NoError(t, err) + }, + "server: enable, reject inherited tenant when header missing": func(t *testing.T) { + i := NewAuthInterceptor(true) + req := newFakeReq(false) + nextCalled := false + + resp, err := i.WrapUnary(func(ctx context.Context, ar connect.AnyRequest) (connect.AnyResponse, error) { + nextCalled = true + + tenantID, tenantErr := ExtractTenantIDFromContext(ctx) + require.NoError(t, tenantErr) + require.Equal(t, "attacker", tenantID) + + return nil, nil + })(InjectTenantID(context.Background(), "attacker"), req) + + require.Nil(t, resp) + require.ErrorIs(t, err, ErrNoTenantID) + require.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err)) + require.False(t, nextCalled, "missing tenant header must stop the request before the handler runs") + }, "streaming client should forward from context": func(t *testing.T) { i := NewAuthInterceptor(false) inConn := newFakeClientStreamingConn() @@ -71,22 +134,38 @@ func Test_AuthInterceptor(t *testing.T) { i := NewAuthInterceptor(true) shc := newFakeClientStreamingConn() shc.requestHeaders.Set("X-Scope-OrgID", "foo") - _ = i.WrapStreamingHandler(func(ctx context.Context, shc connect.StreamingHandlerConn) error { + err := i.WrapStreamingHandler(func(ctx context.Context, shc connect.StreamingHandlerConn) error { tenantID, err := ExtractTenantIDFromContext(ctx) require.NoError(t, err) require.Equal(t, tenantID, "foo") return nil })(context.Background(), shc) + require.NoError(t, err) + }, + "streaming server should reject inherited tenant when header missing": func(t *testing.T) { + i := NewAuthInterceptor(true) + shc := newFakeClientStreamingConn() + nextCalled := false + + err := i.WrapStreamingHandler(func(ctx context.Context, shc connect.StreamingHandlerConn) error { + nextCalled = true + return nil + })(InjectTenantID(context.Background(), "attacker"), shc) + + require.ErrorIs(t, err, ErrNoTenantID) + require.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err)) + require.False(t, nextCalled, "missing tenant header must stop the request before the handler runs") }, "streaming server should forward default tenant to context if disable": func(t *testing.T) { i := NewAuthInterceptor(false) shc := newFakeClientStreamingConn() - _ = i.WrapStreamingHandler(func(ctx context.Context, shc connect.StreamingHandlerConn) error { + err := i.WrapStreamingHandler(func(ctx context.Context, shc connect.StreamingHandlerConn) error { tenantID, err := ExtractTenantIDFromContext(ctx) require.NoError(t, err) require.Equal(t, tenantID, DefaultTenantID) return nil })(context.Background(), shc) + require.NoError(t, err) }, } { t.Run(testName, testCase) @@ -107,6 +186,16 @@ func newFakeReq(isClient bool) fakeReq { } } +func newFakeReqWithHeader(orgID string) fakeReq { + h := http.Header{} + h.Set("X-Scope-OrgID", orgID) + return fakeReq{ + isClient: false, + headers: h, + AnyRequest: connect.NewRequest(&http.Request{}), + } +} + func (f fakeReq) Spec() connect.Spec { return connect.Spec{ IsClient: f.isClient, diff --git a/pkg/test/boltdb.go b/pkg/test/boltdb.go new file mode 100644 index 0000000000..064a59b30d --- /dev/null +++ b/pkg/test/boltdb.go @@ -0,0 +1,23 @@ +package test + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" +) + +func BoltDB(t testing.TB) *bbolt.DB { + tempDir := t.TempDir() + opts := bbolt.Options{ + NoGrowSync: true, + NoFreelistSync: true, + FreelistType: bbolt.FreelistMapType, + InitialMmapSize: 32 << 20, + NoSync: true, + } + db, err := bbolt.Open(filepath.Join(tempDir, "boltdb"), 0644, &opts) + require.NoError(t, err) + return db +} diff --git a/pkg/test/copy.go b/pkg/test/copy.go index ea5c7c05e5..22e454a9b3 100644 --- a/pkg/test/copy.go +++ b/pkg/test/copy.go @@ -6,13 +6,13 @@ package test import ( + "fmt" "io" "os" "path/filepath" "testing" "github.com/grafana/dskit/runutil" - "github.com/pkg/errors" "github.com/stretchr/testify/require" ) @@ -36,7 +36,7 @@ func copyRecursive(src, dst string) error { } if !info.Mode().IsRegular() { - return errors.Errorf("%s is not a regular file", path) + return fmt.Errorf("%s is not a regular file", path) } source, err := os.Open(filepath.Clean(path)) diff --git a/pkg/test/idempotence.go b/pkg/test/idempotence.go new file mode 100644 index 0000000000..de69cdfbff --- /dev/null +++ b/pkg/test/idempotence.go @@ -0,0 +1,34 @@ +package test + +import ( + "testing" +) + +// AssertIdempotent asserts that the test is valid when run multiple times. +func AssertIdempotent(t *testing.T, fn func(*testing.T)) { + t.Helper() + for i := 0; i < 2; i++ { + fn(t) + if t.Failed() { + if i > 0 { + t.Fatal("the function is not idempotent") + } + return + } + } +} + +func AssertIdempotentSubtest(t *testing.T, fn func(*testing.T)) func(*testing.T) { + t.Helper() + return func(t *testing.T) { + for i := 0; i < 2; i++ { + fn(t) + if t.Failed() { + if i > 0 { + t.Fatal("the function is not idempotent") + } + return + } + } + } +} diff --git a/pkg/test/in_memory_listeners.go b/pkg/test/in_memory_listeners.go new file mode 100644 index 0000000000..c6649a1428 --- /dev/null +++ b/pkg/test/in_memory_listeners.go @@ -0,0 +1,28 @@ +package test + +import ( + "context" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/test/bufconn" +) + +// Create in-memory listeners at given addresses. +// Also returns gRPC dial option for a client to connect to the appropriate in-memory listener +// for a given address. +func CreateInMemoryListeners(addresses []string) (map[string]*bufconn.Listener, grpc.DialOption) { + listeners := make(map[string]*bufconn.Listener) + for _, a := range addresses { + el := bufconn.Listen(256 << 10) + listeners[a] = el + } + dialer := func(_ context.Context, address string) (net.Conn, error) { + el := listeners[address] + if el != nil { + return el.Dial() + } + return net.Dial("tcp", address) + } + return listeners, grpc.WithContextDialer(dialer) +} diff --git a/pkg/test/integration/cluster/cluster.go b/pkg/test/integration/cluster/cluster.go index 744083270b..4324aedc81 100644 --- a/pkg/test/integration/cluster/cluster.go +++ b/pkg/test/integration/cluster/cluster.go @@ -2,32 +2,26 @@ package cluster import ( "context" - "errors" - "flag" "fmt" - "io" "log" - "math" "math/rand" "net" "net/http" "os" "path/filepath" - "strings" "sync" "time" - "github.com/prometheus/client_golang/prometheus" - pm "github.com/prometheus/client_model/go" "golang.org/x/sync/errgroup" "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/cfg" - "github.com/grafana/pyroscope/pkg/phlare" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) +const listenAddr = "127.0.0.1" + func getFreeTCPPorts(address string, count int) ([]int, error) { ports := make([]int, count) for i := 0; i < count; i++ { @@ -58,79 +52,122 @@ func newComponent(target string) *Component { } } -func NewMicroServiceCluster() *Cluster { - // use custom http client to resolve dynamically to healthy components - - c := &Cluster{} +type testTransport struct { + defaultDialContext func(ctx context.Context, network, addr string) (net.Conn, error) + next http.RoundTripper + c *Cluster +} +// use custom http transport to resolve dynamically to healthy components +func newTestTransport(c *Cluster) http.RoundTripper { defaultTransport := http.DefaultTransport.(*http.Transport) - transport := &http.Transport{ - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - var err error - switch addr { - case "push:80": - addr, err = c.pickHealthyComponent("distributor") - if err != nil { - return nil, err - } - case "querier:80": - addr, err = c.pickHealthyComponent("query-frontend", "querier") - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("unknown addr %s", addr) - } + t := &testTransport{ + defaultDialContext: defaultTransport.DialContext, + c: c, + } + t.next = &http.Transport{ + Proxy: defaultTransport.Proxy, + TLSClientConfig: defaultTransport.TLSClientConfig, + TLSHandshakeTimeout: defaultTransport.TLSHandshakeTimeout, + ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout, + MaxIdleConns: defaultTransport.MaxIdleConns, + IdleConnTimeout: defaultTransport.IdleConnTimeout, + ForceAttemptHTTP2: defaultTransport.ForceAttemptHTTP2, + DialContext: t.DialContext, + } + return t +} - return defaultTransport.DialContext(ctx, network, addr) - }, +func (t *testTransport) RoundTrip(req *http.Request) (*http.Response, error) { + tenantID, err := tenant.ExtractTenantIDFromContext(req.Context()) + if err == nil { + req.Header.Set("X-Scope-OrgID", tenantID) } - c.httpClient = &http.Client{Transport: transport} - c.Components = []*Component{ - newComponent("distributor"), - newComponent("distributor"), - newComponent("querier"), - newComponent("querier"), - newComponent("ingester"), - newComponent("ingester"), - newComponent("ingester"), - newComponent("store-gateway"), - newComponent("store-gateway"), - newComponent("store-gateway"), + return t.next.RoundTrip(req) +} + +func (t *testTransport) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + var err error + switch addr { + case "push:80": + addr, err = t.c.pickHealthyComponent("distributor") + if err != nil { + return nil, err + } + case "querier:80": + addr, err = t.c.pickHealthyComponent("query-frontend", "querier") + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unknown addr %s", addr) } + + return t.defaultDialContext(ctx, network, addr) +} + +type ClusterOption func(c *Cluster) + +func NewMicroServiceCluster(opts ...ClusterOption) *Cluster { + c := &Cluster{} + WithV1()(c) + + // apply options + for _, opt := range opts { + opt(c) + } + + c.httpClient = &http.Client{Transport: newTestTransport(c)} + c.Components = make([]*Component, len(c.expectedComponents)) + for idx := range c.expectedComponents { + c.Components[idx] = newComponent(c.expectedComponents[idx]) + } + return c } type Cluster struct { Components []*Component - wg sync.WaitGroup // components wait group + perTarget map[string][]int // indexes replicas per target into Components slice + + wg sync.WaitGroup // components wait group + + v2 bool // is this a v2 cluster + debuginfodURL string // debuginfod URL for symbolization + expectedComponents []string // number of expected components tmpDir string httpClient *http.Client } -func nodeNameFlags(nodeName string) []string { +func (c *Cluster) commonFlags(comp *Component) []string { + nodeName := comp.nodeName() return []string{ + "-auth.multitenancy-enabled=true", + "-tracing.enabled=false", // data race + "-self-profiling.disable-push=true", + fmt.Sprintf("-pyroscopedb.data-path=%s", c.dataDir(comp)), + "-storage.backend=filesystem", + fmt.Sprintf("-storage.filesystem.dir=%s", c.dataSharedDir()), + fmt.Sprintf("-target=%s", comp.Target), + fmt.Sprintf("-memberlist.advertise-port=%d", comp.memberlistPort), + fmt.Sprintf("-memberlist.bind-port=%d", comp.memberlistPort), + fmt.Sprintf("-memberlist.bind-addr=%s", listenAddr), + "-memberlist.leave-timeout=1s", + "-memberlist.advertise-addr=" + listenAddr, "-memberlist.nodename=" + nodeName, - "-ingester.lifecycler.ID=" + nodeName, - "-compactor.ring.instance-id=" + nodeName, - "-distributor.ring.instance-id=" + nodeName, - "-overrides-exporter.ring.instance-id=" + nodeName, - "-query-scheduler.ring.instance-id=" + nodeName, - "-store-gateway.sharding-ring.instance-id=" + nodeName, - } -} - -func listenAddrFlags(listenAddr string) []string { - return []string{ - "-compactor.ring.instance-addr=" + listenAddr, + fmt.Sprintf("-server.http-listen-port=%d", comp.httpPort), + fmt.Sprintf("-server.http-listen-address=%s", listenAddr), + fmt.Sprintf("-server.grpc-listen-port=%d", comp.grpcPort), + fmt.Sprintf("-server.grpc-listen-address=%s", listenAddr), "-distributor.ring.instance-addr=" + listenAddr, - "-ingester.lifecycler.addr=" + listenAddr, - "-memberlist.advertise-addr=" + listenAddr, + "-distributor.ring.instance-id=" + nodeName, + "-distributor.ring.heartbeat-period=1s", "-overrides-exporter.ring.instance-addr=" + listenAddr, + "-overrides-exporter.ring.instance-id=" + nodeName, + "-overrides-exporter.ring.heartbeat-period=1s", "-query-frontend.instance-addr=" + listenAddr, - "-query-scheduler.ring.instance-addr=" + listenAddr, - "-store-gateway.sharding-ring.instance-addr=" + listenAddr, + "-query-frontend.async-queries-enabled=true", } } @@ -140,7 +177,7 @@ func (c *Cluster) pickHealthyComponent(targets ...string) (addr string, err erro for _, comp := range c.Components { for i, target := range targets { if comp.Target == target { - results[i] = append(results[i], fmt.Sprintf("%s:%d", "127.0.0.1", comp.ports[0])) + results[i] = append(results[i], fmt.Sprintf("%s:%d", listenAddr, comp.httpPort)) } } } @@ -154,88 +191,62 @@ func (c *Cluster) pickHealthyComponent(targets ...string) (addr string, err erro return "", fmt.Errorf("no healthy component found for targets %v", targets) } +func (c *Cluster) dataSharedDir() string { + return filepath.Join(c.tmpDir, "data", "v2", "shared") +} + +func (c *Cluster) dataDir(comp *Component) string { + return filepath.Join(c.tmpDir, comp.nodeName(), "data") +} -func (c *Cluster) Prepare() (err error) { +func (c *Cluster) Prepare(ctx context.Context) (err error) { // tmp dir c.tmpDir, err = os.MkdirTemp("", "pyroscope-test") if err != nil { return err } - dataSharedDir := filepath.Join(c.tmpDir, "data-shared") - if err := os.Mkdir(dataSharedDir, 0o755); err != nil { + if err := os.MkdirAll(c.dataSharedDir(), 0o755); err != nil { return err } // allocate two tcp ports per component portsPerComponent := 3 - listenAddr := "127.0.0.1" + if c.v2 { + portsPerComponent = 4 + } ports, err := getFreeTCPPorts(listenAddr, len(c.Components)*portsPerComponent) if err != nil { return err } - perTarget := map[string]int{} - for _, c := range c.Components { - v, ok := perTarget[c.Target] - if ok { - v += 1 - } - perTarget[c.Target] = v - c.replica = v - } - + // flags with all components that participate in memberlist memberlistJoin := []string{} + c.perTarget = map[string][]int{} + for compidx, comp := range c.Components { + c.perTarget[comp.Target] = append(c.perTarget[comp.Target], compidx) + comp.replica = len(c.perTarget[comp.Target]) - 1 - for _, comp := range c.Components { - comp.ports = ports[0:portsPerComponent] - ports = ports[3:] - prefix := filepath.Join(c.tmpDir, comp.nodeName()) - dataDir := filepath.Join(prefix, "data") - compactorDir := filepath.Join(prefix, "data-compactor") - syncDir := filepath.Join(prefix, "pyroscope-sync") - - for _, dir := range []string{prefix, dataDir, compactorDir, syncDir} { - if err := os.MkdirAll(dir, 0o755); err != nil { - return err - } - } + // allocate ports + comp.addPorts(ports[0:portsPerComponent]) + ports = ports[portsPerComponent:] + + // add to memberlist join list + memberlistJoin = append(memberlistJoin, fmt.Sprintf("%s:%d", listenAddr, comp.memberlistPort)) - comp.flags = append( - nodeNameFlags(comp.nodeName()), - listenAddrFlags("127.0.0.1")...) - comp.flags = append(comp.flags, - []string{ - "-tracing.enabled=false", // data race - "-distributor.replication-factor=3", - "-store-gateway.sharding-ring.replication-factor=3", - fmt.Sprintf("-target=%s", comp.Target), - fmt.Sprintf("-memberlist.advertise-port=%d", comp.ports[2]), - fmt.Sprintf("-memberlist.bind-port=%d", comp.ports[2]), - fmt.Sprintf("-memberlist.bind-addr=%s", listenAddr), - fmt.Sprintf("-server.http-listen-port=%d", comp.ports[0]), - fmt.Sprintf("-server.http-listen-address=%s", listenAddr), - fmt.Sprintf("-server.grpc-listen-port=%d", comp.ports[1]), - fmt.Sprintf("-server.grpc-listen-address=%s", listenAddr), - fmt.Sprintf("-blocks-storage.bucket-store.sync-dir=%s", syncDir), - fmt.Sprintf("-compactor.data-dir=%s", compactorDir), - fmt.Sprintf("-pyroscopedb.data-path=%s", dataDir), - "-storage.backend=filesystem", - fmt.Sprintf("-storage.filesystem.dir=%s", dataSharedDir), - }...) - - // handle memberlist join - for _, m := range memberlistJoin { - comp.flags = append(comp.flags, fmt.Sprintf("-memberlist.join=%s", m)) + if err := os.MkdirAll(c.dataDir(comp), 0o755); err != nil { + return err } - memberlistJoin = append(memberlistJoin, fmt.Sprintf("127.0.0.1:%d", comp.ports[2])) + } + if c.v2 { + return c.v2Prepare(ctx, memberlistJoin) } - return nil + return c.v1Prepare(ctx, memberlistJoin) } func (c *Cluster) Stop() func(context.Context) error { - funcWaiters := make([]func(context.Context) error, 0, len(c.Components)) + funcWaiters := make([]func(context.Context) error, 0, len(c.Components)+1) for _, comp := range c.Components { funcWaiters = append(funcWaiters, comp.Stop()) } @@ -250,18 +261,12 @@ func (c *Cluster) Stop() func(context.Context) error { } return g.Wait() } - } func (c *Cluster) Start(ctx context.Context) (err error) { - notReady := make(map[*Component]error) - countPerTarget := map[string]int{} - for _, comp := range c.Components { - countPerTarget[comp.Target]++ - p, err := comp.start(ctx) if err != nil { return err @@ -292,21 +297,22 @@ func (c *Cluster) Start(ctx context.Context) (err error) { ctx, cancel := context.WithTimeout(context.Background(), rate) defer cancel() - if t.Target == "querier" { - if err := t.httpReadyCheck(ctx); err != nil { - return err - } + var found bool + var err error - return t.querierReadyCheck(ctx, countPerTarget["ingester"], countPerTarget["store-gateway"]) + if c.v2 { + found, err = c.v2ReadyCheckComponent(ctx, t) + } else { + found, err = c.v1ReadyCheckComponent(ctx, t) } - if t.Target == "distributor" { - if err := t.httpReadyCheck(ctx); err != nil { + if found { + if err != nil { return err } - - return t.distributorReadyCheck(ctx, countPerTarget["ingester"], countPerTarget["distributor"]) + return nil } + // fallback to http ready check return t.httpReadyCheck(ctx) }(); err != nil { notReady[t] = err @@ -349,200 +355,3 @@ func (c *Cluster) PushClient() pushv1connect.PusherServiceClient { connectapi.DefaultClientOptions()..., ) } - -type Component struct { - Target string - replica int - ports []int - flags []string - cfg phlare.Config - p *phlare.Phlare - reg *prometheus.Registry -} - -type gatherCheck struct { - g prometheus.Gatherer - conditions []gatherCoditions -} - -//nolint:unparam -func (c *gatherCheck) addExpectValue(value float64, metricName string, labelPairs ...string) *gatherCheck { - c.conditions = append(c.conditions, gatherCoditions{ - metricName: metricName, - labelPairs: labelPairs, - expectedValue: value, - }) - return c -} - -type gatherCoditions struct { - metricName string - labelPairs []string - expectedValue float64 -} - -func (c *gatherCoditions) String() string { - b := strings.Builder{} - b.WriteString(c.metricName) - b.WriteRune('{') - for i := 0; i < len(c.labelPairs); i += 2 { - b.WriteString(c.labelPairs[i]) - b.WriteRune('=') - b.WriteString(c.labelPairs[i+1]) - b.WriteRune(',') - } - s := b.String() - return s[:len(s)-1] + "}" -} - -func (c *gatherCoditions) matches(pairs []*pm.LabelPair) bool { -outer: - for i := 0; i < len(c.labelPairs); i += 2 { - for _, l := range pairs { - if l.GetName() != c.labelPairs[i] { - continue - } - if l.GetValue() == c.labelPairs[i+1] { - continue outer // match move to next pair - } - return false // value wrong - } - return false // label not found - } - return true -} - -func (comp *Component) checkMetrics() *gatherCheck { - return &gatherCheck{ - g: comp.reg, - } -} - -func (g *gatherCheck) run(ctx context.Context) error { - actualValues := make([]float64, len(g.conditions)) - - // maps from metric name to condition index - nameMap := make(map[string][]int) - for idx, c := range g.conditions { - // not a number - actualValues[idx] = math.NaN() - nameMap[c.metricName] = append(nameMap[c.metricName], idx) - } - - // now gather actual metrics - metrics, err := g.g.Gather() - if err != nil { - return err - } - - for _, m := range metrics { - if ctx.Err() != nil { - return ctx.Err() - } - - conditions, ok := nameMap[m.GetName()] - if !ok { - continue - } - - // now iterate over all label pairs - for _, sm := range m.GetMetric() { - // check for each condition if it matches with he labels - for _, condIdx := range conditions { - if g.conditions[condIdx].matches(sm.Label) { - actualValues[condIdx] = sm.GetGauge().GetValue() // TODO: handle other types - } - } - } - } - - errs := make([]error, len(actualValues)) - for idx, actual := range actualValues { - cond := g.conditions[idx] - if math.IsNaN(actual) { - errs[idx] = fmt.Errorf("metric for %s not found", cond.String()) - continue - } - if actual != cond.expectedValue { - errs[idx] = fmt.Errorf("unexpected value for %s: expected %f, got %f", cond.String(), cond.expectedValue, actual) - } - } - - return errors.Join(errs...) -} - -func (comp *Component) querierReadyCheck(ctx context.Context, expectedIngesters, expectedStoreGateways int) (err error) { - check := comp.checkMetrics(). - addExpectValue(float64(expectedIngesters), "pyroscope_ring_members", "name", "ingester", "state", "ACTIVE"). - addExpectValue(float64(expectedStoreGateways), "pyroscope_ring_members", "name", "store-gateway-client", "state", "ACTIVE") - return check.run(ctx) -} - -func (comp *Component) distributorReadyCheck(ctx context.Context, expectedIngesters, expectedDistributors int) (err error) { - check := comp.checkMetrics(). - addExpectValue(float64(expectedIngesters), "pyroscope_ring_members", "name", "ingester", "state", "ACTIVE"). - addExpectValue(float64(expectedDistributors), "pyroscope_ring_members", "name", "distributor", "state", "ACTIVE") - return check.run(ctx) -} - -func (comp *Component) httpReadyCheck(ctx context.Context) error { - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("http://127.0.0.1:%d/ready", comp.ports[0]), nil) - if err != nil { - return err - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - - if resp.StatusCode/100 == 2 { - return nil - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - return fmt.Errorf("status=%d msg=%s", resp.StatusCode, string(body)) -} - -func (comp *Component) Stop() func(context.Context) error { - return comp.p.Stop() -} - -func (comp *Component) String() string { - if len(comp.ports) == 3 { - return fmt.Sprintf("[%s] http=%d grpc=%d memberlist=%d", comp.nodeName(), comp.ports[0], comp.ports[1], comp.ports[2]) - } - return fmt.Sprintf("[%s]", comp.nodeName()) -} - -func (comp *Component) nodeName() string { - return fmt.Sprintf("%s-%d", comp.Target, comp.replica) -} - -var lockRegistry sync.Mutex - -func (comp *Component) start(_ context.Context) (*phlare.Phlare, error) { - fs := flag.NewFlagSet(comp.nodeName(), flag.PanicOnError) - if err := cfg.DynamicUnmarshal(&comp.cfg, comp.flags, fs); err != nil { - return nil, err - } - - // Hack to avoid clashing metrics, we should track down the use of globals - // restore oldReg := prometheus.DefaultRegisterer - comp.reg = prometheus.NewRegistry() - lockRegistry.Lock() - defer lockRegistry.Unlock() - prometheus.DefaultRegisterer = comp.reg - prometheus.DefaultGatherer = comp.reg - comp.cfg.Server.Gatherer = comp.reg - f, err := phlare.New(comp.cfg) - if err != nil { - return nil, err - } - - return f, nil -} diff --git a/pkg/test/integration/cluster/cluster_v1.go b/pkg/test/integration/cluster/cluster_v1.go new file mode 100644 index 0000000000..fd65d10bfa --- /dev/null +++ b/pkg/test/integration/cluster/cluster_v1.go @@ -0,0 +1,82 @@ +package cluster + +import ( + "context" + "fmt" + "os" + "path/filepath" +) + +func WithV1() ClusterOption { + return func(c *Cluster) { + c.v2 = false + c.expectedComponents = []string{ + "distributor", + "distributor", + "querier", + "querier", + "ingester", + "ingester", + "ingester", + "store-gateway", + "store-gateway", + "store-gateway", + } + } +} + +func WithSymbolizer(debuginfodURL string) ClusterOption { + return func(c *Cluster) { + c.debuginfodURL = debuginfodURL + } +} + +func (c *Cluster) v1ReadyCheckComponent(ctx context.Context, t *Component) (bool, error) { + switch t.Target { + case "querier": + return true, t.querierReadyCheck(ctx, len(c.perTarget["ingester"]), len(c.perTarget["store-gateway"])) + case "distributor": + return true, t.distributorReadyCheck(ctx, len(c.perTarget["ingester"]), len(c.perTarget["distributor"]), 0) + } + return false, nil +} + +func (c *Cluster) v1Prepare(_ context.Context, memberlistJoin []string) error { + for _, comp := range c.Components { + dataDir := c.dataDir(comp) + compactorDir := filepath.Join(dataDir, "..", "data-compactor") + syncDir := filepath.Join(dataDir, "..", "pyroscope-sync") + + for _, dir := range []string{compactorDir, syncDir} { + if err := os.MkdirAll(dir, 0o755); err != nil { + return err + } + } + + comp.flags = c.commonFlags(comp) + comp.flags = append(comp.flags, + "-architecture.storage=v1", + fmt.Sprintf("-blocks-storage.bucket-store.sync-dir=%s", syncDir), + fmt.Sprintf("-compactor.data-dir=%s", compactorDir), + fmt.Sprintf("-pyroscopedb.data-path=%s", dataDir), + "-distributor.replication-factor=3", + "-store-gateway.sharding-ring.replication-factor=3", + "-query-scheduler.ring.instance-id="+comp.nodeName(), + "-query-scheduler.ring.instance-addr="+listenAddr, + "-store-gateway.sharding-ring.instance-id="+comp.nodeName(), + "-store-gateway.sharding-ring.instance-addr="+listenAddr, + "-compactor.ring.instance-addr="+listenAddr, + "-compactor.ring.instance-id="+comp.nodeName(), + "-write-path=ingester", + "-ingester.lifecycler.addr="+listenAddr, + "-ingester.lifecycler.ID="+comp.nodeName(), + "-ingester.min-ready-duration=0", + ) + + // handle memberlist join + for _, m := range memberlistJoin { + comp.flags = append(comp.flags, fmt.Sprintf("-memberlist.join=%s", m)) + } + } + return nil +} diff --git a/pkg/test/integration/cluster/cluster_v2.go b/pkg/test/integration/cluster/cluster_v2.go new file mode 100644 index 0000000000..e2ed8adeb6 --- /dev/null +++ b/pkg/test/integration/cluster/cluster_v2.go @@ -0,0 +1,317 @@ +package cluster + +import ( + "context" + "fmt" + "os" + "path/filepath" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" +) + +func WithV2() ClusterOption { + return func(c *Cluster) { + c.v2 = true + c.expectedComponents = []string{ + "distributor", + "distributor", + "segment-writer", + "segment-writer", + "metastore", + "metastore", + "metastore", + "query-frontend", + "query-backend", + "compaction-worker", + } + } +} + +// WithV2Federated configures a V2 cluster suitable for exercising the +// federated (multi-tenant) query path. It mirrors the V2 cluster but +// without a compaction-worker: L0 segment blocks therefore remain +// Format1 (per-tenant dataset_index pseudo-datasets) for the duration +// of the test, which is what the multi-Format1 resolution path in the +// query backend handles. +// +// With two segment-writers and adaptive placement defaults, profiles +// from each tenant are spread across both writers, so each flushed L0 +// segment is a multi-tenant block and naturally exercises the +// multi-Format1 resolution path. +func WithV2Federated() ClusterOption { + return func(c *Cluster) { + c.v2 = true + c.expectedComponents = []string{ + "distributor", + "distributor", + "segment-writer", + "segment-writer", + "metastore", + "metastore", + "metastore", + "query-frontend", + "query-backend", + } + } +} + +func (c *Cluster) metastoreConfig() (string, error) { + cfgPath := filepath.Join(c.tmpDir, "metastore.yaml") + + // check if the file exists + if _, err := os.Stat(cfgPath); err == nil { + return cfgPath, nil + } else if !os.IsNotExist(err) { + return "", err + } + + // ensure compaction worker are picking up l0 compaction straight away + metastoreConfig := ` +metastore: + levels: + - maxblocks: 20 + maxage: 2000000000 # 2 seconds +` + tmpFile, err := os.Create(cfgPath) + if err != nil { + return "", err + } + if _, err := tmpFile.Write([]byte(metastoreConfig)); err != nil { + return "", err + } + if err := tmpFile.Close(); err != nil { + return "", err + } + return tmpFile.Name(), nil +} + +func (c *Cluster) metastores() []*Component { + metastores := make([]*Component, 0, len(c.perTarget["metastore"])) + for _, compidx := range c.perTarget["metastore"] { + metastores = append(metastores, c.Components[compidx]) + } + return metastores +} + +func (c *Cluster) metastoreExpectedLeader() *Component { + metastores := c.metastores() + return metastores[len(metastores)-1] +} + +func (c *Cluster) CompactionJobsFinished(ctx context.Context) (float64, error) { + leader := c.metastoreExpectedLeader() + + floatCh := make(chan float64, 1) + check := leader.checkMetrics(). + addRetrieveValue(floatCh, "pyroscope_metastore_compaction_scheduler_queue_completed_jobs_total", "level", "0") + + if err := check.run(ctx); err != nil { + return 0, err + } + close(floatCh) + + sum := 0.0 + found := false + for v := range floatCh { + found = true + sum += v + } + if !found { + return 0, fmt.Errorf("no value received") + } + return sum, nil +} + +func (c *Cluster) v2Prepare(_ context.Context, memberlistJoin []string) error { + metastoreLeader := c.metastoreExpectedLeader() + + for _, comp := range c.Components { + if err := c.v2PrepareComponent(comp, metastoreLeader); err != nil { + return err + } + + // handle memberlist join + for _, m := range memberlistJoin { + comp.flags = append(comp.flags, fmt.Sprintf("-memberlist.join=%s", m)) + } + } + + return nil +} + +func (c *Cluster) v2PrepareComponent(comp *Component, metastoreLeader *Component) error { + dataDir := c.dataDir(comp) + + comp.flags = c.commonFlags(comp) + + comp.flags = append(comp.flags, + "-architecture.storage=v2", + "-querier.query-tree-enabled=true", // always enable the tree based SelectMergeProfiles + "-metastore.min-ready-duration=0", + fmt.Sprintf("-metastore.address=%s:%d/%s", listenAddr, metastoreLeader.grpcPort, metastoreLeader.nodeName()), + ) + + if c.debuginfodURL != "" && comp.Target == "query-frontend" { + comp.flags = append(comp.flags, + fmt.Sprintf("-symbolizer.debuginfod-url=%s", c.debuginfodURL), + "-symbolizer.enabled=true", + ) + } + + if comp.Target == "segment-writer" { + comp.flags = append(comp.flags, + "-segment-writer.num-tokens=1", + "-segment-writer.min-ready-duration=0", + "-segment-writer.lifecycler.addr="+listenAddr, + "-segment-writer.lifecycler.ID="+comp.nodeName(), + "-segment-writer.heartbeat-period=1s", + ) + } + + if comp.Target == "compaction-worker" { + comp.flags = append(comp.flags, + "-compaction-worker.job-concurrency=20", + "-compaction-worker.job-poll-interval=1s", + ) + } + + // register query-backends in the frontend and themselves + if comp.Target == "query-frontend" || comp.Target == "query-backend" { + for _, compidx := range c.perTarget["query-backend"] { + comp.flags = append(comp.flags, + fmt.Sprintf("-query-backend.address=%s:%d", listenAddr, c.Components[compidx].grpcPort), + ) + } + } + + // handle metastore folders and ports + if comp.Target == "metastore" { + cfgPath, err := c.metastoreConfig() + if err != nil { + return err + } + comp.flags = append(comp.flags, + fmt.Sprint("-config.file=", cfgPath), + fmt.Sprintf("-metastore.data-dir=%s", dataDir+"../metastore-ephemeral"), + fmt.Sprintf("-metastore.raft.dir=%s", dataDir+"../metastore-raft"), + fmt.Sprintf("-metastore.raft.snapshots-dir=%s", dataDir+"../metastore-snapshots"), + fmt.Sprintf("-metastore.raft.bind-address=%s:%d", listenAddr, comp.raftPort), + fmt.Sprintf("-metastore.raft.advertise-address=%s:%d", listenAddr, comp.raftPort), + fmt.Sprintf("-metastore.raft.server-id=%s", comp.nodeName()), + fmt.Sprintf("-metastore.raft.bootstrap-expect-peers=%d", len(c.perTarget[comp.Target])), + ) + + // add bootstrap peers + for _, compidx := range c.perTarget[comp.Target] { + peer := c.Components[compidx] + comp.flags = append(comp.flags, + fmt.Sprintf("-metastore.raft.bootstrap-peers=%s:%d/%s", listenAddr, peer.raftPort, peer.nodeName()), + ) + } + } + + return nil +} + +func (c *Cluster) v2ReadyCheckComponent(ctx context.Context, t *Component) (bool, error) { + switch t.Target { + case "metastore": + return true, t.metastoreReadyCheck(ctx, c.metastores(), c.metastoreExpectedLeader()) + case "distributor": + return true, t.distributorReadyCheck(ctx, 0, len(c.perTarget["segment-writer"]), len(c.perTarget["distributor"])) + } + return false, nil +} + +// for the metastore, we need to check that the first replica is the leader, as this is configured statically as the client for other components. +func (comp *Component) metastoreReadyCheck(ctx context.Context, metastores []*Component, expectedLeader *Component) error { + expectedPeers := len(metastores) + + opts := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + } + cc, err := grpc.NewClient(fmt.Sprintf("%s:%d", listenAddr, comp.grpcPort), opts...) + if err != nil { + return err + } + + client := raftnodepb.NewRaftNodeServiceClient(cc) + + nodeInfo, err := client.NodeInfo(ctx, &raftnodepb.NodeInfoRequest{}) + if err != nil { + return err + } + + // only ready once all peers are here + if len(nodeInfo.Node.Peers) != expectedPeers { + return fmt.Errorf("unexpected peer count: exp=%d actual=%d", expectedPeers, len(nodeInfo.Node.Peers)) + } + + // only ready once leader is known + if nodeInfo.Node.LeaderId == "" { + return fmt.Errorf("leader not known on node %s", comp.nodeName()) + } + + // exit if we are not the leader + if nodeInfo.Node.LeaderId != nodeInfo.Node.ServerId { + return nil + } + + // if we are replica 0 we are done as we are already leader + if comp.replica == expectedPeers-1 { + return nil + } + + // promote last metastore to new leader + _, err = client.PromoteToLeader(ctx, &raftnodepb.PromoteToLeaderRequest{ + ServerId: fmt.Sprintf("%s:%d/%s", listenAddr, expectedLeader.raftPort, expectedLeader.nodeName()), + CurrentTerm: nodeInfo.Node.CurrentTerm, + }) + return err +} + +func (c *Cluster) GetMetastoreRaftNodeClient() (raftnodepb.RaftNodeServiceClient, error) { + leader := c.metastoreExpectedLeader() + opts := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + } + cc, err := grpc.NewClient(fmt.Sprintf("127.0.0.1:%d", leader.grpcPort), opts...) + if err != nil { + return nil, err + } + + return raftnodepb.NewRaftNodeServiceClient(cc), nil +} + +func (c *Cluster) AddMetastoreWithAutoJoin(ctx context.Context) error { + leader := c.metastoreExpectedLeader() + + comp := newComponent("metastore") + comp.replica = len(c.perTarget["metastore"]) + c.Components = append(c.Components, comp) + c.perTarget["metastore"] = append(c.perTarget["metastore"], len(c.Components)-1) + + if err := c.v2PrepareComponent(comp, leader); err != nil { + return err + } + comp.flags = append(comp.flags, "-metastore.raft.auto-join=true") + + p, err := comp.start(ctx) + if err != nil { + return fmt.Errorf("failed to start component: %w", err) + } + comp.p = p + + c.wg.Add(1) + go func() { + defer c.wg.Done() + if err := p.Run(); err != nil { + fmt.Printf("metastore with auto-join stopped with error: %v\n", err) + } + }() + + return nil +} diff --git a/pkg/test/integration/cluster/component.go b/pkg/test/integration/cluster/component.go new file mode 100644 index 0000000000..2ac28aa03a --- /dev/null +++ b/pkg/test/integration/cluster/component.go @@ -0,0 +1,128 @@ +package cluster + +import ( + "context" + "flag" + "fmt" + "io" + "net/http" + "sync" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/grafana/pyroscope/v2/pkg/cfg" + "github.com/grafana/pyroscope/v2/pkg/pyroscope" +) + +type Component struct { + Target string + replica int + flags []string + cfg pyroscope.Config + p *pyroscope.Pyroscope + reg *prometheus.Registry + + httpPort int + grpcPort int + memberlistPort int + raftPort int +} + +func (c *Component) addPorts(ports []int) { + if len(ports) < 1 { + return + } + c.httpPort = ports[0] + if len(ports) < 2 { + return + } + c.grpcPort = ports[1] + if len(ports) < 3 { + return + } + c.memberlistPort = ports[2] + if len(ports) < 4 { + return + } + c.raftPort = ports[3] +} + +func (comp *Component) querierReadyCheck(ctx context.Context, expectedIngesters, expectedStoreGateways int) (err error) { + check := comp.checkMetrics(). + addExpectValue(float64(expectedIngesters), "pyroscope_ring_members", "name", "ingester", "state", "ACTIVE"). + addExpectValue(float64(expectedStoreGateways), "pyroscope_ring_members", "name", "store-gateway-client", "state", "ACTIVE") + return check.run(ctx) +} + +func (comp *Component) distributorReadyCheck(ctx context.Context, expectedIngesters, expectedDistributors, expectedSegmentWriters int) (err error) { + check := comp.checkMetrics() + if expectedIngesters > 0 { + check = check.addExpectValue(float64(expectedIngesters), "pyroscope_ring_members", "name", "ingester", "state", "ACTIVE") + } + if expectedSegmentWriters > 0 { + check = check.addExpectValue(float64(expectedSegmentWriters), "pyroscope_ring_members", "name", "segment-writer", "state", "ACTIVE") + } + if expectedDistributors > 0 { + check = check.addExpectValue(float64(expectedDistributors), "pyroscope_ring_members", "name", "distributor", "state", "ACTIVE") + } + return check.run(ctx) +} + +func (comp *Component) httpReadyCheck(ctx context.Context) error { + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("http://%s:%d/ready", listenAddr, comp.httpPort), nil) + if err != nil { + return err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + + if resp.StatusCode/100 == 2 { + return nil + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + return fmt.Errorf("status=%d msg=%s", resp.StatusCode, string(body)) +} + +func (comp *Component) Stop() func(context.Context) error { + return comp.p.Stop() +} + +func (comp *Component) String() string { + return fmt.Sprintf("[%s] http=%d grpc=%d memberlist=%d raft=%d", comp.nodeName(), comp.httpPort, comp.grpcPort, comp.memberlistPort, comp.raftPort) +} + +func (comp *Component) nodeName() string { + return fmt.Sprintf("%s-%d", comp.Target, comp.replica) +} + +var lockRegistry sync.Mutex + +func (comp *Component) start(_ context.Context) (*pyroscope.Pyroscope, error) { + fs := flag.NewFlagSet(comp.nodeName(), flag.PanicOnError) + if err := cfg.DynamicUnmarshal(&comp.cfg, comp.flags, fs); err != nil { + return nil, err + } + + // Hack to avoid clashing metrics, we should track down the use of globals + // restore oldReg := prometheus.DefaultRegisterer + comp.reg = prometheus.NewRegistry() + lockRegistry.Lock() + defer lockRegistry.Unlock() + prometheus.DefaultRegisterer = comp.reg + prometheus.DefaultGatherer = comp.reg + comp.cfg.Server.Gatherer = comp.reg + f, err := pyroscope.New(comp.cfg) + if err != nil { + return nil, err + } + + return f, nil +} diff --git a/pkg/test/integration/cluster/metrics.go b/pkg/test/integration/cluster/metrics.go new file mode 100644 index 0000000000..d0a114d61c --- /dev/null +++ b/pkg/test/integration/cluster/metrics.go @@ -0,0 +1,154 @@ +package cluster + +import ( + "context" + "errors" + "fmt" + "math" + "strings" + + "github.com/prometheus/client_golang/prometheus" + pm "github.com/prometheus/client_model/go" +) + +type gatherCheck struct { + g prometheus.Gatherer + conditions []gatherCoditions +} + +func matchValue(exp float64) func(float64) error { + return func(value float64) error { + if value == exp { + return nil + } + return fmt.Errorf("expected %f, got %f", exp, value) + } +} + +//nolint:unparam +func (c *gatherCheck) addExpectValue(value float64, metricName string, labelPairs ...string) *gatherCheck { + c.conditions = append(c.conditions, gatherCoditions{ + metricName: metricName, + labelPairs: labelPairs, + valueCheck: matchValue(value), + }) + return c +} + +func retrieveValue(ch chan float64) func(float64) error { + return func(value float64) error { + ch <- value + return nil + } +} + +func (c *gatherCheck) addRetrieveValue(valueCh chan float64, metricName string, labelPairs ...string) *gatherCheck { + c.conditions = append(c.conditions, gatherCoditions{ + metricName: metricName, + labelPairs: labelPairs, + valueCheck: retrieveValue(valueCh), + }) + return c +} + +type gatherCoditions struct { + metricName string + labelPairs []string + valueCheck func(float64) error +} + +func (c *gatherCoditions) String() string { + b := strings.Builder{} + b.WriteString(c.metricName) + b.WriteRune('{') + for i := 0; i < len(c.labelPairs); i += 2 { + b.WriteString(c.labelPairs[i]) + b.WriteRune('=') + b.WriteString(c.labelPairs[i+1]) + b.WriteRune(',') + } + s := b.String() + return s[:len(s)-1] + "}" +} + +func (c *gatherCoditions) matches(pairs []*pm.LabelPair) bool { +outer: + for i := 0; i < len(c.labelPairs); i += 2 { + for _, l := range pairs { + if l.GetName() != c.labelPairs[i] { + continue + } + if l.GetValue() == c.labelPairs[i+1] { + continue outer // match move to next pair + } + return false // value wrong + } + return false // label not found + } + return true +} + +func (comp *Component) checkMetrics() *gatherCheck { + return &gatherCheck{ + g: comp.reg, + } +} + +func (g *gatherCheck) run(ctx context.Context) error { + actualValues := make([]float64, len(g.conditions)) + + // maps from metric name to condition index + nameMap := make(map[string][]int) + for idx, c := range g.conditions { + // not a number + actualValues[idx] = math.NaN() + nameMap[c.metricName] = append(nameMap[c.metricName], idx) + } + + // now gather actual metrics + metrics, err := g.g.Gather() + if err != nil { + return err + } + + for _, m := range metrics { + if ctx.Err() != nil { + return ctx.Err() + } + + conditions, ok := nameMap[m.GetName()] + if !ok { + continue + } + + // now iterate over all label pairs + for _, sm := range m.GetMetric() { + // check for each condition if it matches with he labels + for _, condIdx := range conditions { + if g.conditions[condIdx].matches(sm.Label) { + v := -1.0 // -1.0 is an invalid value, when metric type is not gauge or counter + if g := sm.GetGauge(); g != nil { + v = g.GetValue() + } else if c := sm.GetCounter(); c != nil { + v = c.GetValue() + } + actualValues[condIdx] = v + } + } + } + } + + errs := make([]error, len(actualValues)) + for idx, actual := range actualValues { + cond := g.conditions[idx] + if math.IsNaN(actual) { + errs[idx] = fmt.Errorf("metric for %s not found", cond.String()) + continue + } + if err := cond.valueCheck(actual); err != nil { + errs[idx] = fmt.Errorf("unexpected value for %s: %w", cond.String(), err) + } + } + + return errors.Join(errs...) +} diff --git a/pkg/test/integration/debuginfod_server.go b/pkg/test/integration/debuginfod_server.go new file mode 100644 index 0000000000..0c1c4ccb0a --- /dev/null +++ b/pkg/test/integration/debuginfod_server.go @@ -0,0 +1,94 @@ +package integration + +import ( + "fmt" + "io" + "net" + "net/http" + "os" + "path/filepath" + "strings" +) + +type TestDebuginfodServer struct { + server *http.Server + debugFiles map[string]string + listener net.Listener +} + +func NewTestDebuginfodServer() (*TestDebuginfodServer, error) { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, fmt.Errorf("failed to listen: %w", err) + } + + s := &TestDebuginfodServer{ + debugFiles: make(map[string]string), + listener: listener, + } + + mux := http.NewServeMux() + mux.HandleFunc("/buildid/", s.handleBuildID) + + s.server = &http.Server{ + Handler: mux, + } + + return s, nil +} + +func (s *TestDebuginfodServer) AddDebugFile(buildID, filePath string) { + s.debugFiles[buildID] = filePath +} + +func (s *TestDebuginfodServer) URL() string { + return fmt.Sprintf("http://%s", s.listener.Addr().String()) +} + +func (s *TestDebuginfodServer) Start() error { + go func() { + _ = s.server.Serve(s.listener) + }() + return nil +} + +func (s *TestDebuginfodServer) Stop() error { + return s.server.Close() +} + +func (s *TestDebuginfodServer) handleBuildID(w http.ResponseWriter, r *http.Request) { + parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/buildid/"), "/") + if len(parts) != 2 || parts[1] != "debuginfo" { + http.Error(w, "Invalid path", http.StatusBadRequest) + return + } + + buildID := parts[0] + filePath, ok := s.debugFiles[buildID] + if !ok { + http.Error(w, "Build ID not found", http.StatusNotFound) + return + } + + file, err := os.Open(filePath) + if err != nil { + http.Error(w, fmt.Sprintf("Failed to open debug file: %v", err), http.StatusInternalServerError) + return + } + defer file.Close() + + fileInfo, err := file.Stat() + if err != nil { + http.Error(w, fmt.Sprintf("Failed to stat debug file: %v", err), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Length", fmt.Sprintf("%d", fileInfo.Size())) + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filepath.Base(filePath))) + + _, err = io.Copy(w, file) + if err != nil { + return + } +} diff --git a/pkg/test/integration/helper.go b/pkg/test/integration/helper.go index 5d22c00a6a..4e627c14ef 100644 --- a/pkg/test/integration/helper.go +++ b/pkg/test/integration/helper.go @@ -10,9 +10,9 @@ import ( "io" "math/rand" "mime/multipart" - "net" "net/http" "os" + "sort" "strings" "sync" "testing" @@ -23,59 +23,106 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + "github.com/prometheus/common/expfmt" + + profilesv1 "go.opentelemetry.io/proto/otlp/collector/profiles/v1development" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - connectapi "github.com/grafana/pyroscope/pkg/api/connect" - "github.com/grafana/pyroscope/pkg/cfg" - "github.com/grafana/pyroscope/pkg/og/structs/flamebearer" - "github.com/grafana/pyroscope/pkg/phlare" - "github.com/grafana/pyroscope/pkg/pprof" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" + connectapi "github.com/grafana/pyroscope/v2/pkg/api/connect" + "github.com/grafana/pyroscope/v2/pkg/cfg" + "github.com/grafana/pyroscope/v2/pkg/distributor/writepath" + objstoreclient "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/og/structs/flamebearer" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/pyroscope" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" ) -// getFreePorts returns a number of free local port for the tests to listen on. Note this will make sure the returned ports do not overlap, by stopping to listen once all ports are allocated -func getFreePorts(len int) (ports []int, err error) { - ports = make([]int, len) - for i := 0; i < len; i++ { - var a *net.TCPAddr - if a, err = net.ResolveTCPAddr("tcp", "127.0.0.1:0"); err == nil { - var l *net.TCPListener - if l, err = net.ListenTCP("tcp", a); err != nil { - return nil, err - } - defer l.Close() - ports[i] = l.Addr().(*net.TCPAddr).Port - } +func EachPyroscopeTest(t *testing.T, f func(p *PyroscopeTest, t *testing.T)) { + tests := []struct { + name string + f func(t *testing.T) *PyroscopeTest + }{ + { + "v1", + func(t *testing.T) *PyroscopeTest { + return new(PyroscopeTest).Configure(t, false) + }, + }, + { + "v2", + func(t *testing.T) *PyroscopeTest { + return new(PyroscopeTest).Configure(t, true) + }, + }, + } + for _, pt := range tests { + t.Run(pt.name, func(t *testing.T) { + p := pt.f(t) + p.start(t) + t.Cleanup(func() { + p.stop() + }) + f(p, t) + }) } - return ports, nil } type PyroscopeTest struct { - config phlare.Config - it *phlare.Phlare - wg sync.WaitGroup - reg prometheus.Registerer - + config pyroscope.Config + it *pyroscope.Pyroscope + wg sync.WaitGroup + prevReg prometheus.Registerer + reg *prometheus.Registry httpPort int memberlistPort int + grpcPort int + raftPort int } const address = "127.0.0.1" const storeInMemory = "inmemory" -func (p *PyroscopeTest) Start(t *testing.T) { +func (p *PyroscopeTest) start(t *testing.T) { + var err error + + p.it, err = pyroscope.New(p.config) - ports, err := getFreePorts(2) + require.NoError(t, err) + + p.wg.Add(1) + go func() { + defer p.wg.Done() + err := p.it.Run() + require.NoError(t, err) + }() + require.Eventually(t, func() bool { + return p.ringActive() && p.ready() + }, 30*time.Second, 100*time.Millisecond) +} + +func (p *PyroscopeTest) Configure(t *testing.T, v2 bool) *PyroscopeTest { + ports, err := GetFreePorts(4) require.NoError(t, err) p.httpPort = ports[0] p.memberlistPort = ports[1] + p.grpcPort = ports[2] + p.raftPort = ports[3] + t.Logf("ports: http %d memberlist %d grpc %d raft %d", p.httpPort, p.memberlistPort, p.grpcPort, p.raftPort) - p.reg = prometheus.DefaultRegisterer - prometheus.DefaultRegisterer = prometheus.NewRegistry() + p.prevReg = prometheus.DefaultRegisterer + p.reg = prometheus.NewRegistry() + prometheus.DefaultRegisterer = p.reg err = cfg.DynamicUnmarshal(&p.config, []string{"pyroscope"}, flag.NewFlagSet("pyroscope", flag.ContinueOnError)) require.NoError(t, err) @@ -84,10 +131,12 @@ func (p *PyroscopeTest) Start(t *testing.T) { p.config.Server.HTTPListenAddress = address p.config.Server.HTTPListenPort = p.httpPort p.config.Server.GRPCListenAddress = address + p.config.Server.GRPCListenPort = p.grpcPort p.config.Worker.SchedulerAddress = address p.config.MemberlistKV.AdvertisePort = p.memberlistPort p.config.MemberlistKV.TCPTransport.BindPort = p.memberlistPort p.config.Ingester.LifecyclerConfig.Addr = address + p.config.Ingester.LifecyclerConfig.MinReadyDuration = 0 p.config.QueryScheduler.ServiceDiscovery.SchedulerRing.InstanceAddr = address p.config.Frontend.Addr = address @@ -109,24 +158,34 @@ func (p *PyroscopeTest) Start(t *testing.T) { p.config.LimitsConfig.MaxQueryLookback = 0 p.config.LimitsConfig.RejectOlderThan = 0 _ = p.config.Server.LogLevel.Set("debug") - p.it, err = phlare.New(p.config) - - require.NoError(t, err) - p.wg.Add(1) - go func() { - defer p.wg.Done() - err := p.it.Run() - require.NoError(t, err) - }() - require.Eventually(t, func() bool { - return p.ringActive() && p.ready() - }, 30*time.Second, 100*time.Millisecond) + if !v2 { + p.config.ArchitectureStorage = pyroscope.V1 + p.config.LimitsConfig.WritePathOverrides.WritePath = writepath.IngesterPath + p.config.Storage.Bucket.Backend = objstoreclient.None + } else { + p.config.ArchitectureStorage = pyroscope.V2 + p.config.Storage.Bucket.Filesystem.Directory = t.TempDir() + p.config.Storage.Bucket.Backend = "filesystem" + p.config.SegmentWriter.LifecyclerConfig.MinReadyDuration = 0 * time.Second + p.config.SegmentWriter.LifecyclerConfig.Addr = address + p.config.SegmentWriter.MetadataUpdateTimeout = 0 * time.Second + p.config.Metastore.MinReadyDuration = 0 * time.Second + p.config.QueryBackend.Address = fmt.Sprintf("%s:%d", address, p.grpcPort) + p.config.Metastore.Address = fmt.Sprintf("%s:%d", address, p.grpcPort) + p.config.Metastore.Raft.ServerID = fmt.Sprintf("%s:%d", address, p.raftPort) + p.config.Metastore.Raft.BindAddress = fmt.Sprintf("%s:%d", address, p.raftPort) + p.config.Metastore.Raft.AdvertiseAddress = fmt.Sprintf("%s:%d", address, p.raftPort) + p.config.Metastore.Raft.Dir = t.TempDir() + p.config.Metastore.Raft.SnapshotsDir = t.TempDir() + p.config.Metastore.FSM.DataDir = t.TempDir() + } + return p } -func (p *PyroscopeTest) Stop(t *testing.T) { +func (p *PyroscopeTest) stop() { defer func() { - prometheus.DefaultRegisterer = p.reg + prometheus.DefaultRegisterer = p.prevReg }() p.it.SignalHandler.Stop() p.wg.Wait() @@ -136,12 +195,35 @@ func (p *PyroscopeTest) ready() bool { return httpBodyContains(p.URL()+"/ready", "ready") } func (p *PyroscopeTest) ringActive() bool { - return httpBodyContains(p.URL()+"/ring", "ACTIVE") + if p.config.ArchitectureStorage == pyroscope.V1 || p.config.ArchitectureStorage == pyroscope.V1V2Dual { + return httpBodyContains(p.URL()+"/ring", "ACTIVE") + } + return httpBodyContains(p.URL()+"/ring-segment-writer", "ACTIVE") } func (p *PyroscopeTest) URL() string { return fmt.Sprintf("http://%s:%d", address, p.httpPort) } +func (p *PyroscopeTest) Metrics(t testing.TB, keep func(string) bool) string { + dto, err := p.reg.Gather() + require.NoError(t, err) + gotBuf := bytes.NewBuffer(nil) + enc := expfmt.NewEncoder(gotBuf, expfmt.NewFormat(expfmt.TypeTextPlain)) + for _, mf := range dto { + if err := enc.Encode(mf); err != nil { + require.NoError(t, err) + } + } + split := strings.Split(gotBuf.String(), "\n") + res := []string{} + for _, line := range split { + if keep(line) { + res = append(res, line) + } + } + return strings.Join(res, "\n") +} + func httpBodyContains(url string, needle string) bool { fmt.Println("httpBodyContains", url, needle) res, err := http.Get(url) @@ -170,7 +252,7 @@ func (p *PyroscopeTest) NewRequestBuilder(t *testing.T) *RequestBuilder { } func (p *PyroscopeTest) TempAppName() string { - return fmt.Sprintf("pprof.integration.%d", + return fmt.Sprintf("pprof-integration-%d", rand.Uint64()) } @@ -288,6 +370,18 @@ func (b *RequestBuilder) IngestJFRRequestBody(jfr []byte, labels []byte) *http.R return req } +func (b *RequestBuilder) IngestSpeedscopeRequest(speedscopePath string) *http.Request { + speedscopeData, err := os.ReadFile(speedscopePath) + require.NoError(b.t, err) + + url := b.url + "/ingest?name=" + b.AppName + "&format=speedscope" + req, err := http.NewRequest("POST", url, bytes.NewReader(speedscopeData)) + require.NoError(b.t, err) + req.Header.Set("Content-Type", "application/json") + + return req +} + func (b *RequestBuilder) Render(metric string) *flamebearer.FlamebearerProfile { queryURL := b.url + "/pyroscope/render?query=" + createRenderQuery(metric, b.AppName) + "&from=946656000&until=now&format=collapsed" fmt.Println(queryURL) @@ -305,11 +399,11 @@ func (b *RequestBuilder) Render(metric string) *flamebearer.FlamebearerProfile { return fb } -func (b *RequestBuilder) PushPPROFRequest(file string, metric string) *connect.Request[pushv1.PushRequest] { +func (b *RequestBuilder) PushPPROFRequestFromFile(file string, metric string) *connect.Request[pushv1.PushRequest] { updateTimestamp := func(rawProfile []byte) []byte { expectedProfile, err := pprof.RawFromBytes(rawProfile) require.NoError(b.t, err) - expectedProfile.Profile.TimeNanos = time.Now().Add(-time.Minute).UnixNano() + expectedProfile.TimeNanos = time.Now().Add(-time.Minute).UnixNano() buf := bytes.NewBuffer(nil) _, err = expectedProfile.WriteTo(buf) require.NoError(b.t, err) @@ -337,6 +431,19 @@ func (b *RequestBuilder) PushPPROFRequest(file string, metric string) *connect.R return req } +func (b *RequestBuilder) PushPPROFRequestFromBytes(rawProfile []byte, name string) *connect.Request[pushv1.PushRequest] { + req := connect.NewRequest(&pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{{ + Labels: []*typesv1.LabelPair{ + {Name: "__name__", Value: name}, + {Name: "service_name", Value: b.AppName}, + }, + Samples: []*pushv1.RawSample{{RawProfile: rawProfile}}, + }}, + }) + return req +} + func (b *RequestBuilder) QueryClient() querierv1connect.QuerierServiceClient { return querierv1connect.NewQuerierServiceClient( http.DefaultClient, @@ -395,18 +502,121 @@ func (b *RequestBuilder) SelectMergeProfile(metric string, query map[string]stri cnt++ } selector.WriteString("{") - add("service_name", b.AppName) + if query["service_name"] == "" { + add("service_name", b.AppName) + } + for k, v := range query { add(k, v) } selector.WriteString("}") qc := b.QueryClient() - resp, err := qc.SelectMergeProfile(context.Background(), connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + resp, err := qc.SelectMergeProfile(context.Background(), connect.NewRequest(&querierv1.SelectMergeProfileRequest{ //nolint:staticcheck // Legacy querier.v1 integration coverage. ProfileTypeID: metric, - Start: time.Unix(0, 0).UnixMilli(), + Start: time.Unix(1, 0).UnixMilli(), End: time.Now().UnixMilli(), LabelSelector: selector.String(), })) require.NoError(b.t, err) return resp } + +func (b *RequestBuilder) OtelPushClient() profilesv1.ProfilesServiceClient { + grpcAddr := strings.TrimPrefix(b.url, "http://") + + conn, err := grpc.NewClient(grpcAddr, + grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(b.t, err) + + return profilesv1.NewProfilesServiceClient(conn) +} + +// OtelPushHTTPProtobuf creates an HTTP request for OTLP ingestion with binary/protobuf content type +func (b *RequestBuilder) OtelPushHTTPProtobuf(profile *profilesv1.ExportProfilesServiceRequest) *http.Request { + profileBytes, err := proto.Marshal(profile) + require.NoError(b.t, err) + + url := b.url + "/v1development/profiles" + req, err := http.NewRequest("POST", url, bytes.NewReader(profileBytes)) + require.NoError(b.t, err) + req.Header.Set("Content-Type", "application/x-protobuf") + return req +} + +// OtelPushHTTPJSON creates an HTTP request for OTLP ingestion with JSON content type +func (b *RequestBuilder) OtelPushHTTPJSON(profile *profilesv1.ExportProfilesServiceRequest) *http.Request { + profileBytes, err := protojson.Marshal(profile) + require.NoError(b.t, err) + + url := b.url + "/v1development/profiles" + req, err := http.NewRequest("POST", url, bytes.NewReader(profileBytes)) + require.NoError(b.t, err) + req.Header.Set("Content-Type", "application/json") + return req +} + +// normalizePprof returns a copy of p with functions, locations, and samples +// renumbered in a canonical order determined by the string table. Functions +// are sorted by their Name string-table index; locations by their first +// function ID; samples by their location-ID sequence. This makes profiles +// with identical logical content but different internal ID assignments +// directly comparable. +func normalizePprof(p *profilev1.Profile) *profilev1.Profile { + out := proto.Clone(p).(*profilev1.Profile) + + // Sort functions by their actual name string (not the string table index, + // which is insertion-order dependent) and reassign IDs. + sort.Slice(out.Function, func(i, j int) bool { + ni := out.StringTable[out.Function[i].Name] + nj := out.StringTable[out.Function[j].Name] + return ni < nj + }) + funcIDMap := make(map[uint64]uint64, len(out.Function)) + for i, fn := range out.Function { + newID := uint64(i + 1) + funcIDMap[fn.Id] = newID + fn.Id = newID + } + + // Update FunctionId references in all location lines. + for _, loc := range out.Location { + for _, line := range loc.Line { + line.FunctionId = funcIDMap[line.FunctionId] + } + } + + // Sort locations by their first line's FunctionId and reassign IDs. + sort.Slice(out.Location, func(i, j int) bool { + li, lj := out.Location[i].Line, out.Location[j].Line + for k := 0; k < len(li) && k < len(lj); k++ { + if li[k].FunctionId != lj[k].FunctionId { + return li[k].FunctionId < lj[k].FunctionId + } + } + return len(li) < len(lj) + }) + locIDMap := make(map[uint64]uint64, len(out.Location)) + for i, loc := range out.Location { + newID := uint64(i + 1) + locIDMap[loc.Id] = newID + loc.Id = newID + } + + // Update LocationId references in samples and sort samples. + for _, sample := range out.Sample { + for k, id := range sample.LocationId { + sample.LocationId[k] = locIDMap[id] + } + } + sort.Slice(out.Sample, func(i, j int) bool { + si, sj := out.Sample[i].LocationId, out.Sample[j].LocationId + for k := 0; k < len(si) && k < len(sj); k++ { + if si[k] != sj[k] { + return si[k] < sj[k] + } + } + return len(si) < len(sj) + }) + + return out +} diff --git a/pkg/test/integration/http_status_codes_test.go b/pkg/test/integration/http_status_codes_test.go new file mode 100644 index 0000000000..37190e17f8 --- /dev/null +++ b/pkg/test/integration/http_status_codes_test.go @@ -0,0 +1,2607 @@ +package integration + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" +) + +type Request struct { + ProfileType string +} + +func TestStatusCodes(t *testing.T) { + const profileTypeProcessCPU = "process_cpu:cpu:nanoseconds:cpu:nanoseconds" + + toJSON := func(obj any) string { + bytes, err := json.Marshal(obj) + if err != nil { + panic(fmt.Sprintf("failed to marshal to json: %v", err)) + } + return string(bytes) + } + + type Test struct { + Name string + Method string + Params url.Values + Header http.Header + Body string + WantV1StatusCode int // For test cases which expect a different v1 status code + } + + type EndpointTestGroup struct { + Path string + // All the test cases partitioned by expected HTTP status code. + Tests map[int][]Test + } + + renderTests := EndpointTestGroup{ + Path: "/pyroscope/render", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "format_dot_valid", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "format": []string{"dot"}, + }, + }, + { + Name: "format_dot_with_max_nodes", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "format": []string{"dot"}, + "maxNodes": []string{"50"}, + }, + }, + { + Name: "format_dot_with_max_nodes_hyphen", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "format": []string{"dot"}, + "max-nodes": []string{"50"}, + }, + }, + { + Name: "with_group_by", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "groupBy": []string{"service_name"}, + }, + }, + { + Name: "with_group_by_multiple", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "groupBy": []string{"service_name", "region"}, + }, + }, + { + Name: "with_aggregation_sum", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "aggregation": []string{"sum"}, + }, + }, + { + Name: "with_aggregation_avg", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "aggregation": []string{"avg"}, + }, + }, + { + Name: "with_aggregation_invalid", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "aggregation": []string{"invalid"}, + }, + }, + { + Name: "with_max_nodes", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "maxNodes": []string{"1024"}, + }, + }, + { + Name: "with_max_nodes_hyphen", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "max-nodes": []string{"1024"}, + }, + }, + { + Name: "with_max_nodes_zero", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "maxNodes": []string{"0"}, + }, + }, + { + Name: "with_max_nodes_invalid", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "maxNodes": []string{"invalid"}, + }, + }, + { + Name: "all_params_combined", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + "groupBy": []string{"service_name"}, + "aggregation": []string{"sum"}, + "maxNodes": []string{"512"}, + }, + }, + }, + http.StatusBadRequest: { + { + Name: "all_zero_time_range", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"0"}, + "until": []string{"0"}, + }, + }, + { + Name: "from_zero_time_range", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"0"}, + "until": []string{"now"}, + }, + }, + { + Name: "until_zero_time_range", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"0"}, + }, + }, + { + Name: "missing_query", + Method: http.MethodGet, + Params: url.Values{ + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "invalid_query_syntax", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{"bad_query"}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "query_without_profile_type", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{`{service_name="test"}`}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "invalid_profile_type_format", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{`invalid_format{service_name="test"}`}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "empty_query_param", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{""}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "from_and_until_0_with_dot_format", + Method: http.MethodGet, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"0"}, + "until": []string{"0"}, + "format": []string{"dot"}, + }, + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "post_method_not_allowed", + Method: http.MethodPost, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Params: url.Values{ + "query": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "from": []string{"now-15m"}, + "until": []string{"now"}, + }, + }, + }, + }, + } + + renderDiffTests := EndpointTestGroup{ + Path: "/pyroscope/render-diff", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "same_query_different_times", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-60m"}, + "leftUntil": []string{"now-30m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-30m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "same_time_range", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-15m"}, + "leftUntil": []string{"now"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + }, + http.StatusBadRequest: { + { + Name: "missing_left_query", + Method: http.MethodGet, + Params: url.Values{ + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "missing_right_query", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "invalid_left_query_syntax", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{"bad_query"}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "invalid_right_query_syntax", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{"bad_query"}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "left_query_without_profile_type", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{`{service_name="test"}`}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "right_query_without_profile_type", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{`{service_name="test"}`}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "invalid_left_profile_type_format", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{`invalid_format{service_name="test"}`}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "invalid_right_profile_type_format", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{`invalid_format{service_name="test"}`}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "profile_types_mismatch", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery("memory:alloc_objects:count:space:bytes", "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "empty_left_query", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{""}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "empty_right_query", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{""}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "left_from_zero", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"0"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "left_until_zero", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"0"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "right_from_zero", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"0"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "right_until_zero", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"0"}, + }, + }, + { + Name: "all_zero_time_ranges", + Method: http.MethodGet, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"0"}, + "leftUntil": []string{"0"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"0"}, + "rightUntil": []string{"0"}, + }, + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "post_method_not_allowed", + Method: http.MethodPost, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Params: url.Values{ + "leftQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "leftFrom": []string{"now-30m"}, + "leftUntil": []string{"now-15m"}, + "rightQuery": []string{createRenderQuery(profileTypeProcessCPU, "pyroscope")}, + "rightFrom": []string{"now-15m"}, + "rightUntil": []string{"now"}, + }, + }, + }, + }, + } + + profileTypesTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/ProfileTypes", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "zero_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": 0, + "end": 0, + }), + }, + { + Name: "valid_long_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-24 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_short_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-5 * time.Minute).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + // TODO(bryan) this should be fixed + Name: "negative_start", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": -1, + "end": time.Now().UnixMilli(), + }), + }, + { + // TODO(bryan) this should be fixed + Name: "negative_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": -2, + "end": -1, + }), + }, + }, + http.StatusBadRequest: { + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }), + }, + { + Name: "start_string_instead_of_number", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"start": "now-1h", "end": 0}`, + }, + { + Name: "end_string_instead_of_number", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"start": 0, "end": "now"}`, + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Params: url.Values{ + "start": []string{fmt.Sprintf("%d", time.Now().Add(-1*time.Hour).UnixMilli())}, + "end": []string{fmt.Sprintf("%d", time.Now().UnixMilli())}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + }, + } + + labelValuesTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/LabelValues", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_with_matchers", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "matchers": []string{`{namespace="default"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_with_multiple_matchers", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "matchers": []string{`{namespace="default"}`, `{region="us-west"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusBadRequest: { + { + Name: "invalid_no_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + }), + // V1 allows no time ranges + WantV1StatusCode: http.StatusOK, + }, + { + Name: "invalid_matchers_syntax", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "matchers": []string{"!bad_syntax!"}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + WantV1StatusCode: http.StatusInternalServerError, + }, + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }), + }, + { + Name: "empty_name", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "missing_name", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "name": "service_name", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + }, + } + + labelNamesTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/LabelNames", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_with_matchers", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{namespace="default"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusBadRequest: { + { + Name: "valid_no_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{}), + // V1 allows no time ranges + WantV1StatusCode: http.StatusOK, + }, + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }), + }, + { + Name: "invalid_matchers_syntax", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{"!bad_syntax!"}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + WantV1StatusCode: http.StatusInternalServerError, + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + }, + } + + seriesTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/Series", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_with_label_names", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + "labelNames": []string{"service_name", "namespace"}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_no_matchers", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusBadRequest: { + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }), + }, + { + Name: "invalid_no_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + }), + // V1 allows no time ranges + WantV1StatusCode: http.StatusOK, + }, + { + Name: "invalid_matchers_syntax", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{"!bad_syntax!"}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + WantV1StatusCode: http.StatusInternalServerError, + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "matchers": []string{`{service_name="test"}`}, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + }, + } + + selectMergeStacktracesTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/SelectMergeStacktraces", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_with_max_nodes", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "maxNodes": 1024, + }), + }, + { + Name: "valid_with_format_tree", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "format": 2, + }), + }, + { + Name: "valid_with_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": `{service_name="test"}`, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusBadRequest: { + { + Name: "missing_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "empty_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "invalid_profile_type_format", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "invalid_format", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "missing_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "invalid_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "!bad_syntax!", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }), + }, + { + Name: "invalid_no_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + }), + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + }, + } + + selectMergeProfileTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/SelectMergeProfile", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "valid_with_max_nodes", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "maxNodes": 1024, + }), + }, + { + Name: "valid_with_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": `{service_name="test"}`, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusBadRequest: { + { + Name: "missing_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "empty_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "invalid_profile_type_format", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "invalid_format", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "missing_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "invalid_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "!bad_syntax!", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }), + }, + { + Name: "valid_no_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + }), + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + }, + }, + }, + } + + selectSeriesTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/SelectSeries", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "valid_with_group_by", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + "groupBy": []string{"service_name"}, + }), + }, + { + Name: "valid_with_limit", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + "limit": 10, + }), + }, + }, + http.StatusBadRequest: { + { + Name: "missing_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "empty_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "invalid_profile_type_format", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "invalid_format", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "missing_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "invalid_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "!bad_syntax!", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "invalid_no_step", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }), + WantV1StatusCode: http.StatusBadRequest, + }, + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "invalid_no_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "step": 15.0, + }), + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "step": 15.0, + }), + }, + }, + }, + } + + diffTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/Diff", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "valid_with_max_nodes", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + "maxNodes": 1024, + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "maxNodes": 512, + }, + }), + }, + { + Name: "valid_same_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + }, + http.StatusBadRequest: { + { + Name: "missing_left", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "missing_right", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + }), + }, + { + Name: "left_missing_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "right_missing_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "left_invalid_profile_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": "invalid_format", + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "right_invalid_profile_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": "invalid_format", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "left_missing_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "right_missing_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "left": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-2 * time.Hour).UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + }, + "right": map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + }, + }), + }, + }, + }, + } + + selectMergeSpanProfileTests := EndpointTestGroup{ + Path: "/querier.v1.QuerierService/SelectMergeSpanProfile", + Tests: map[int][]Test{ + http.StatusOK: { + { + Name: "valid", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345", "0123456789012346"}, + }), + }, + { + Name: "valid_with_max_nodes", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + "maxNodes": 1024, + }), + }, + { + Name: "valid_with_format_tree", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + "format": 2, + }), + }, + }, + http.StatusBadRequest: { + { + Name: "missing_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "empty_profile_type_id", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "invalid_profile_type_format", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": "invalid_format", + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "missing_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "invalid_label_selector", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "!bad_syntax!", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "invalid_json", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: `{"invalid json"`, + }, + { + Name: "empty_body", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: "", + }, + { + Name: "start_after_end", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().UnixMilli(), + "end": time.Now().Add(-1 * time.Hour).UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "invalid_no_time_range", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "spanSelector": []string{"0123456789012345"}, + }), + }, + }, + http.StatusMethodNotAllowed: { + { + Name: "get_method_not_allowed", + Method: http.MethodGet, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + }, + { + Name: "put_method_not_allowed", + Method: http.MethodPut, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "delete_method_not_allowed", + Method: http.MethodDelete, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + { + Name: "patch_method_not_allowed", + Method: http.MethodPatch, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + }, + http.StatusUnsupportedMediaType: { + { + Name: "invalid_content_type", + Method: http.MethodPost, + Header: http.Header{ + "Content-Type": []string{"text/plain"}, + }, + Body: toJSON(map[string]any{ + "profileTypeID": profileTypeProcessCPU, + "labelSelector": "{}", + "start": time.Now().Add(-1 * time.Hour).UnixMilli(), + "end": time.Now().UnixMilli(), + "spanSelector": []string{"0123456789012345"}, + }), + }, + }, + }, + } + + allTests := []EndpointTestGroup{ + renderTests, + renderDiffTests, + profileTypesTests, + labelValuesTests, + labelNamesTests, + seriesTests, + selectMergeStacktracesTests, + selectMergeProfileTests, + selectSeriesTests, + selectMergeSpanProfileTests, + diffTests, + } + + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + // Ingest a minimal profile so the head's time range covers [now-1h, now]. + // Without this, the head has Bounds() = (0,0) and ForTimeRange excludes it, + // meaning invalid matchers are never parsed and always return 200. + rb := p.NewRequestBuilder(t) + profileBytes, err := testhelper.NewProfileBuilder(time.Now().Add(-time.Second).UnixNano()). + CPUProfile(). + ForStacktraceString("foo", "bar"). + AddSamples(1). + MarshalVT() + require.NoError(t, err) + rb.Push(rb.PushPPROFRequestFromBytes(profileBytes, "process_cpu"), 200, "") + + client := http.DefaultClient + isV1Test := strings.HasSuffix(t.Name(), "v1") + + for _, endpoint := range allTests { + for wantCode, tests := range endpoint.Tests { + for _, tt := range tests { + t.Run(fmt.Sprintf("%s/%s", endpoint.Path, tt.Name), func(t *testing.T) { + t.Parallel() + + path, err := url.JoinPath(p.URL(), endpoint.Path) + require.NoError(t, err, "failed to create path") + + u, err := url.Parse(path) + require.NoError(t, err, "failed to parse url") + u.RawQuery = tt.Params.Encode() + + var reqBody io.Reader + if tt.Body != "" { + reqBody = bytes.NewReader([]byte(tt.Body)) + } + + req, err := http.NewRequest(tt.Method, u.String(), reqBody) + require.NoError(t, err) + + for key, vals := range tt.Header { + for _, val := range vals { + req.Header.Add(key, val) + } + } + + res, err := client.Do(req) + require.NoError(t, err) + + wantCode := wantCode + if tt.WantV1StatusCode != 0 && isV1Test { + wantCode = tt.WantV1StatusCode + } + + if !assert.Equal(t, wantCode, res.StatusCode) { + bytes, err := io.ReadAll(res.Body) + res.Body.Close() + if err != nil { + t.Log("failed to read response body:", err) + } else { + t.Log("response body:", string(bytes)) + } + } + }) + } + } + } + }) +} diff --git a/pkg/test/integration/ingest_jfr_test.go b/pkg/test/integration/ingest_jfr_test.go index 5b68517c46..3b50fbf1d1 100644 --- a/pkg/test/integration/ingest_jfr_test.go +++ b/pkg/test/integration/ingest_jfr_test.go @@ -11,9 +11,9 @@ import ( "github.com/stretchr/testify/require" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/og/convert/pprof/bench" - "github.com/grafana/pyroscope/pkg/pprof" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/bench" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) type jfrTestData struct { @@ -148,29 +148,27 @@ func TestNOJFRDump(t *testing.T) { } func TestIngestJFR(t *testing.T) { - p := new(PyroscopeTest) - p.Start(t) - defer p.Stop(t) - - for _, testdatum := range jfrTestDatas { - t.Run(testdatum.jfr, func(t *testing.T) { - - rb := p.NewRequestBuilder(t) - req := rb.IngestJFRRequestFiles(testdatum.jfr, testdatum.labels) - p.Ingest(t, req, testdatum.expectStatus) - - if testdatum.expectStatus == 200 { - assert.NotEqual(t, len(testdatum.expectedMetrics), 0) - for _, metric := range testdatum.expectedMetrics { - goldFile := expectedPPROFFile(testdatum, metric) - t.Logf("%v gold file %s", metric, goldFile) - rb.Render(metric.name) - profile := rb.SelectMergeProfile(metric.name, metric.query) - verifyPPROF(t, profile, goldFile, metric) + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + for _, testdatum := range jfrTestDatas { + t.Run(testdatum.jfr, func(t *testing.T) { + + rb := p.NewRequestBuilder(t) + req := rb.IngestJFRRequestFiles(testdatum.jfr, testdatum.labels) + p.Ingest(t, req, testdatum.expectStatus) + + if testdatum.expectStatus == 200 { + assert.NotEqual(t, len(testdatum.expectedMetrics), 0) + for _, metric := range testdatum.expectedMetrics { + goldFile := expectedPPROFFile(testdatum, metric) + t.Logf("%v gold file %s", metric, goldFile) + rb.Render(metric.name) + profile := rb.SelectMergeProfile(metric.name, metric.query) + verifyPPROF(t, profile, goldFile, metric) + } } - } - }) - } + }) + } + }) } func expectedPPROFFile(testdatum jfrTestData, metric expectedMetric) string { @@ -185,18 +183,16 @@ func expectedPPROFFile(testdatum jfrTestData, metric expectedMetric) string { } func TestCorruptedJFR422(t *testing.T) { - p := new(PyroscopeTest) - p.Start(t) - defer p.Stop(t) - - td := jfrTestDatas[0] - jfr, err := bench.ReadGzipFile(td.jfr) - require.NoError(t, err) - jfr[0] = 0 // corrupt jfr + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + td := jfrTestDatas[0] + jfr, err := bench.ReadGzipFile(td.jfr) + require.NoError(t, err) + jfr[0] = 0 // corrupt jfr - rb := p.NewRequestBuilder(t) - req := rb.IngestJFRRequestBody(jfr, nil) - p.Ingest(t, req, 422) + rb := p.NewRequestBuilder(t) + req := rb.IngestJFRRequestBody(jfr, nil) + p.Ingest(t, req, 422) + }) } func verifyPPROF(t *testing.T, resp *connect.Response[profilev1.Profile], expectedPPROF string, metric expectedMetric) { diff --git a/pkg/test/integration/ingest_otlp_test.go b/pkg/test/integration/ingest_otlp_test.go new file mode 100644 index 0000000000..f7b4e378fb --- /dev/null +++ b/pkg/test/integration/ingest_otlp_test.go @@ -0,0 +1,264 @@ +package integration + +import ( + "context" + "encoding/json" + "io" + "net/http" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + profilesv1 "go.opentelemetry.io/proto/otlp/collector/profiles/v1development" + commonv1 "go.opentelemetry.io/proto/otlp/common/v1" + "google.golang.org/protobuf/proto" + + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/strprofile" +) + +type otlpTestData struct { + name string + profilePath string + expectedProfiles []expectedProfile + assertMetrics func(t *testing.T, p *PyroscopeTest) +} + +type expectedProfile struct { + metricName string + query map[string]string + expectedJsonPath string +} + +var otlpTestDatas = []otlpTestData{ + { + name: "unsymbolized profile from otel-ebpf-profiler with cpu and offcpu", + profilePath: "testdata/otel-ebpf-profile.pb.bin", + expectedProfiles: []expectedProfile{ + { + "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + map[string]string{"service_name": "unknown_service"}, + "testdata/otel-ebpf-profile-cpu.out.json", + }, + { + "off_cpu:off_cpu:nanoseconds::", + map[string]string{"service_name": "unknown_service"}, + "testdata/otel-ebpf-profile-offcpu.out.json", + }, + }, + assertMetrics: func(t *testing.T, p *PyroscopeTest) { + + }, + }, +} + +func TestIngestOTLP(t *testing.T) { + for _, td := range otlpTestDatas { + t.Run(td.name, func(t *testing.T) { + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + rb := p.NewRequestBuilder(t) + runNo := p.TempAppName() + + profileBytes, err := os.ReadFile(td.profilePath) + require.NoError(t, err) + var profile = new(profilesv1.ExportProfilesServiceRequest) + err = proto.Unmarshal(profileBytes, profile) + require.NoError(t, err) + + for _, rp := range profile.ResourceProfiles { + for _, sp := range rp.ScopeProfiles { + sp.Scope.Attributes = append(sp.Scope.Attributes, &commonv1.KeyValue{ + Key: "test_run_no", Value: &commonv1.AnyValue{Value: &commonv1.AnyValue_StringValue{StringValue: runNo}}, + }) + } + } + + client := rb.OtelPushClient() + _, err = client.Export(context.Background(), profile) + require.NoError(t, err) + + for _, metric := range td.expectedProfiles { + + query := make(map[string]string) + for k, v := range metric.query { + query[k] = v + } + query["test_run_no"] = runNo + + resp := rb.SelectMergeProfile(metric.metricName, query) + + assert.NotEmpty(t, resp.Msg.Sample) + assert.NotEmpty(t, resp.Msg.Function) + assert.NotEmpty(t, resp.Msg.Mapping) + assert.NotEmpty(t, resp.Msg.Location) + + actual := strprofile.ToCompactProfile(resp.Msg, strprofile.Options{ + NoTime: true, + NoDuration: true, + }) + strprofile.SortProfileSamples(actual) + actualBytes, err := json.Marshal(actual) + assert.NoError(t, err) + + pprofDumpFileName := strings.ReplaceAll(metric.expectedJsonPath, ".json", ".pprof.pb.bin") // for debugging + pprof, err := resp.Msg.MarshalVT() + assert.NoError(t, err) + err = os.WriteFile(pprofDumpFileName, pprof, 0644) + assert.NoError(t, err) + + expectedBytes, err := os.ReadFile(metric.expectedJsonPath) + require.NoError(t, err) + var expected strprofile.CompactProfile + assert.NoError(t, json.Unmarshal(expectedBytes, &expected)) + strprofile.SortProfileSamples(expected) + expectedBytes, err = json.Marshal(expected) + require.NoError(t, err) + + assert.Equal(t, string(expectedBytes), string(actualBytes)) + } + td.assertMetrics(t, p) + }) + }) + } +} + +// TestIngestOTLPHTTPBinary tests OTLP ingestion via HTTP with binary/protobuf content type +func TestIngestOTLPHTTPBinary(t *testing.T) { + for _, td := range otlpTestDatas { + t.Run(td.name, func(t *testing.T) { + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + rb := p.NewRequestBuilder(t) + runNo := p.TempAppName() + + profileBytes, err := os.ReadFile(td.profilePath) + require.NoError(t, err) + var profile = new(profilesv1.ExportProfilesServiceRequest) + err = proto.Unmarshal(profileBytes, profile) + require.NoError(t, err) + + for _, rp := range profile.ResourceProfiles { + for _, sp := range rp.ScopeProfiles { + sp.Scope.Attributes = append(sp.Scope.Attributes, &commonv1.KeyValue{ + Key: "test_run_no", Value: &commonv1.AnyValue{Value: &commonv1.AnyValue_StringValue{StringValue: runNo}}, + }) + } + } + + // Send via HTTP with application/x-protobuf content type + req := rb.OtelPushHTTPProtobuf(profile) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode, "Response body: %s", string(body)) + + for _, metric := range td.expectedProfiles { + query := make(map[string]string) + for k, v := range metric.query { + query[k] = v + } + query["test_run_no"] = runNo + + resp := rb.SelectMergeProfile(metric.metricName, query) + + assert.NotEmpty(t, resp.Msg.Sample) + assert.NotEmpty(t, resp.Msg.Function) + assert.NotEmpty(t, resp.Msg.Mapping) + assert.NotEmpty(t, resp.Msg.Location) + + actual := strprofile.ToCompactProfile(resp.Msg, strprofile.Options{ + NoTime: true, + NoDuration: true, + }) + strprofile.SortProfileSamples(actual) + actualBytes, err := json.Marshal(actual) + assert.NoError(t, err) + + expectedBytes, err := os.ReadFile(metric.expectedJsonPath) + require.NoError(t, err) + var expected strprofile.CompactProfile + assert.NoError(t, json.Unmarshal(expectedBytes, &expected)) + strprofile.SortProfileSamples(expected) + expectedBytes, err = json.Marshal(expected) + require.NoError(t, err) + + assert.Equal(t, string(expectedBytes), string(actualBytes)) + } + td.assertMetrics(t, p) + }) + }) + } +} + +// TestIngestOTLPHTTPJSON tests OTLP ingestion via HTTP with JSON content type +func TestIngestOTLPHTTPJSON(t *testing.T) { + for _, td := range otlpTestDatas { + t.Run(td.name, func(t *testing.T) { + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + rb := p.NewRequestBuilder(t) + runNo := p.TempAppName() + + profileBytes, err := os.ReadFile(td.profilePath) + require.NoError(t, err) + var profile = new(profilesv1.ExportProfilesServiceRequest) + err = proto.Unmarshal(profileBytes, profile) + require.NoError(t, err) + + for _, rp := range profile.ResourceProfiles { + for _, sp := range rp.ScopeProfiles { + sp.Scope.Attributes = append(sp.Scope.Attributes, &commonv1.KeyValue{ + Key: "test_run_no", Value: &commonv1.AnyValue{Value: &commonv1.AnyValue_StringValue{StringValue: runNo}}, + }) + } + } + + // Send via HTTP with application/json content type + req := rb.OtelPushHTTPJSON(profile) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode, "Response body: %s", string(body)) + + for _, metric := range td.expectedProfiles { + query := make(map[string]string) + for k, v := range metric.query { + query[k] = v + } + query["test_run_no"] = runNo + + resp := rb.SelectMergeProfile(metric.metricName, query) + + assert.NotEmpty(t, resp.Msg.Sample) + assert.NotEmpty(t, resp.Msg.Function) + assert.NotEmpty(t, resp.Msg.Mapping) + assert.NotEmpty(t, resp.Msg.Location) + + actual := strprofile.ToCompactProfile(resp.Msg, strprofile.Options{ + NoTime: true, + NoDuration: true, + }) + strprofile.SortProfileSamples(actual) + actualBytes, err := json.Marshal(actual) + assert.NoError(t, err) + + expectedBytes, err := os.ReadFile(metric.expectedJsonPath) + require.NoError(t, err) + var expected strprofile.CompactProfile + assert.NoError(t, json.Unmarshal(expectedBytes, &expected)) + strprofile.SortProfileSamples(expected) + expectedBytes, err = json.Marshal(expected) + require.NoError(t, err) + + assert.Equal(t, string(expectedBytes), string(actualBytes)) + } + td.assertMetrics(t, p) + }) + }) + } +} diff --git a/pkg/test/integration/ingest_pprof_test.go b/pkg/test/integration/ingest_pprof_test.go index 0cc8133444..78a2e194f0 100644 --- a/pkg/test/integration/ingest_pprof_test.go +++ b/pkg/test/integration/ingest_pprof_test.go @@ -4,16 +4,19 @@ import ( "fmt" "os" "testing" + "time" "connectrpc.com/connect" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" - pprof2 "github.com/grafana/pyroscope/pkg/og/convert/pprof" - "github.com/grafana/pyroscope/pkg/og/convert/pprof/bench" - "github.com/grafana/pyroscope/pkg/og/ingestion" - "github.com/grafana/pyroscope/pkg/pprof" + pprof2 "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/bench" + "github.com/grafana/pyroscope/v2/pkg/og/convert/pprof/strprofile" + "github.com/grafana/pyroscope/v2/pkg/og/ingestion" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" ) const repoRoot = "../../../" @@ -245,104 +248,258 @@ var ( ) func TestIngest(t *testing.T) { - p := PyroscopeTest{} - p.Start(t) - defer p.Stop(t) - - for _, td := range testdata { - t.Run(td.profile, func(t *testing.T) { - rb := p.NewRequestBuilder(t). - Spy(td.spyName) - req := rb.IngestPPROFRequest(td.profile, td.prevProfile, td.sampleTypeConfig) - p.Ingest(t, req, td.expectStatusIngest) - - if td.expectStatusIngest == 200 { - for _, metric := range td.metrics { - rb.Render(metric.name) - profile := rb.SelectMergeProfile(metric.name, metric.query) - assertPPROF(t, profile, metric, td, td.fixAtIngest) + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + for _, td := range testdata { + t.Run(td.profile, func(t *testing.T) { + rb := p.NewRequestBuilder(t). + Spy(td.spyName) + req := rb.IngestPPROFRequest(td.profile, td.prevProfile, td.sampleTypeConfig) + p.Ingest(t, req, td.expectStatusIngest) + + if td.expectStatusIngest == 200 { + for _, metric := range td.metrics { + rb.Render(metric.name) + profile := rb.SelectMergeProfile(metric.name, metric.query) + assertPPROF(t, profile, metric, td, td.fixAtIngest) + } } - } - }) - } + }) + } + }) } func TestIngestPPROFFixPythonLinenumbers(t *testing.T) { - p := PyroscopeTest{} - p.Start(t) - defer p.Stop(t) - profile := pprof.RawFromProto(&profilev1.Profile{ - SampleType: []*profilev1.ValueType{{ - Type: 5, - Unit: 6, - }}, - PeriodType: &profilev1.ValueType{ - Type: 5, Unit: 6, - }, - StringTable: []string{"", "main", "func1", "func2", "qwe.py", "cpu", "nanoseconds"}, - Period: 1000000000, - Function: []*profilev1.Function{ - {Id: 1, Name: 1, Filename: 4, SystemName: 1, StartLine: 239}, - {Id: 2, Name: 2, Filename: 4, SystemName: 2, StartLine: 42}, - {Id: 3, Name: 3, Filename: 4, SystemName: 3, StartLine: 7}, - }, - Location: []*profilev1.Location{ - {Id: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 242}}}, - {Id: 2, Line: []*profilev1.Line{{FunctionId: 2, Line: 50}}}, - {Id: 3, Line: []*profilev1.Line{{FunctionId: 3, Line: 8}}}, - }, - Sample: []*profilev1.Sample{ - {LocationId: []uint64{2, 1}, Value: []int64{10}}, - {LocationId: []uint64{3, 1}, Value: []int64{13}}, - }, + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + + profile := pprof.RawFromProto(&profilev1.Profile{ + SampleType: []*profilev1.ValueType{{ + Type: 5, + Unit: 6, + }}, + PeriodType: &profilev1.ValueType{ + Type: 5, Unit: 6, + }, + StringTable: []string{"", "main", "func1", "func2", "qwe.py", "cpu", "nanoseconds"}, + Period: 1000000000, + Function: []*profilev1.Function{ + {Id: 1, Name: 1, Filename: 4, SystemName: 1, StartLine: 239}, + {Id: 2, Name: 2, Filename: 4, SystemName: 2, StartLine: 42}, + {Id: 3, Name: 3, Filename: 4, SystemName: 3, StartLine: 7}, + }, + Location: []*profilev1.Location{ + {Id: 1, Line: []*profilev1.Line{{FunctionId: 1, Line: 242}}}, + {Id: 2, Line: []*profilev1.Line{{FunctionId: 2, Line: 50}}}, + {Id: 3, Line: []*profilev1.Line{{FunctionId: 3, Line: 8}}}, + }, + Sample: []*profilev1.Sample{ + {LocationId: []uint64{2, 1}, Value: []int64{10}}, + {LocationId: []uint64{3, 1}, Value: []int64{13}}, + }, + }) + + tempProfileFile, err := os.CreateTemp("", "profile") + require.NoError(t, err) + _, err = profile.WriteTo(tempProfileFile) + assert.NoError(t, err) + tempProfileFile.Close() + defer os.Remove(tempProfileFile.Name()) + + rb := p.NewRequestBuilder(t). + Spy("pyspy") + req := rb.IngestPPROFRequest(tempProfileFile.Name(), "", "") + p.Ingest(t, req, 200) + + renderedProfile := rb.SelectMergeProfile("process_cpu:cpu:nanoseconds:cpu:nanoseconds", nil) + actual := bench.StackCollapseProto(renderedProfile.Msg, 0, 1) + expected := []string{ + "qwe.py main;qwe.py func1 10", + "qwe.py main;qwe.py func2 13", + } + assert.Equal(t, expected, actual) }) +} - tempProfileFile, err := os.CreateTemp("", "profile") - require.NoError(t, err) - _, err = profile.WriteTo(tempProfileFile) - assert.NoError(t, err) - tempProfileFile.Close() - defer os.Remove(tempProfileFile.Name()) - - rb := p.NewRequestBuilder(t). - Spy("pyspy") - req := rb.IngestPPROFRequest(tempProfileFile.Name(), "", "") - p.Ingest(t, req, 200) - - renderedProfile := rb.SelectMergeProfile("process_cpu:cpu:nanoseconds:cpu:nanoseconds", nil) - actual := bench.StackCollapseProto(renderedProfile.Msg, 0, 1) - expected := []string{ - "qwe.py:242 - main;qwe.py:50 - func1 10", - "qwe.py:242 - main;qwe.py:8 - func2 13", - } - assert.Equal(t, expected, actual) +func TestIngestPPROFSanitizeOtelLabels(t *testing.T) { + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + + p1 := testhelper.NewProfileBuilder(time.Now().Add(-time.Second).UnixNano()). + CPUProfile(). + ForStacktraceString("my", "other"). + AddSamples(239) + p1.Sample[0].Label = []*profilev1.Label{ + { + Key: p1.AddString("foo_bar"), + Str: p1.AddString("qwe_asd"), + }, + } + p1bs, err := p1.MarshalVT() + require.NoError(t, err) + + rb := p.NewRequestBuilder(t) + rb.Push(rb.PushPPROFRequestFromBytes(p1bs, "process_cpu"), 200, "") + + renderedProfile := rb.SelectMergeProfile("process_cpu:cpu:nanoseconds:cpu:nanoseconds", map[string]string{ + "foo_bar": "qwe_asd", + }) + actual, err := strprofile.Stringify(renderedProfile.Msg, strprofile.Options{ + NoTime: true, + NoDuration: true, + }) + require.NoError(t, err) + expected := `{ + "sample_types": [ + { + "type": "cpu", + "unit": "nanoseconds" + } + ], + "samples": [ + { + "locations": [ + { + "address": "0x0", + "lines": [ + "my[]@:0" + ], + "mapping": "0x0-0x0@0x0 ()" + }, + { + "address": "0x0", + "lines": [ + "other[]@:0" + ], + "mapping": "0x0-0x0@0x0 ()" + } + ], + "values": "239" + } + ], + "period": "1000000000" +}` + assert.JSONEq(t, expected, actual) + }) } -func TestPush(t *testing.T) { - p := new(PyroscopeTest) - p.Start(t) - defer p.Stop(t) +func TestGodeltaprofRelabelPush(t *testing.T) { + const blockSize = 1024 + const metric = "godeltaprof_memory" + + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + + p1, _ := testhelper.NewProfileBuilder(time.Now().Add(-time.Second).UnixNano()). + MemoryProfile(). + ForStacktraceString("my", "other"). + AddSamples(239, 239*blockSize, 1000, 1000*blockSize). + MarshalVT() - for _, td := range testdata { - if td.prevProfile != "" { - continue + p2, _ := testhelper.NewProfileBuilder(time.Now().UnixNano()). + MemoryProfile(). + ForStacktraceString("my", "other"). + AddSamples(3, 3*blockSize, 1000, 1000*blockSize). + MarshalVT() + + rb := p.NewRequestBuilder(t) + rb.Push(rb.PushPPROFRequestFromBytes(p1, metric), 200, "") + rb.Push(rb.PushPPROFRequestFromBytes(p2, metric), 200, "") + renderedProfile := rb.SelectMergeProfile("memory:alloc_objects:count:space:bytes", nil) + actual := bench.StackCollapseProto(renderedProfile.Msg, 0, 1) + expected := []string{ + "other;my 242", } - t.Run(td.profile, func(t *testing.T) { - rb := p.NewRequestBuilder(t) + assert.Equal(t, expected, actual) + }) +} - req := rb.PushPPROFRequest(td.profile, td.metrics[0].name) - rb.Push(req, td.expectStatusPush, td.expectedError) +func TestPushStringTableOOBSampleType(t *testing.T) { + const blockSize = 1024 + const metric = "godeltaprof_memory" - if td.expectStatusPush == 200 { - for _, metric := range td.metrics { - rb.Render(metric.name) - profile := rb.SelectMergeProfile(metric.name, metric.query) + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { - assertPPROF(t, profile, metric, td, td.fixAtPush) - } + testdata := []struct { + name string + corrupt func(p *testhelper.ProfileBuilder) + expectedErr string + }{ + { + name: "sample type", + corrupt: func(p *testhelper.ProfileBuilder) { + p.SampleType[0].Type = 100500 + }, + expectedErr: "sample type type string index out of range", + }, + { + name: "function name", + corrupt: func(p *testhelper.ProfileBuilder) { + p.Function[0].Name = 100500 + }, + expectedErr: "function name string index out of range", + }, + { + name: "mapping", + corrupt: func(p *testhelper.ProfileBuilder) { + p.Mapping[0].Filename = 100500 + }, + expectedErr: "mapping file name string index out of range", + }, + { + name: "Sample label", + corrupt: func(p *testhelper.ProfileBuilder) { + p.Sample[0].Label = []*profilev1.Label{{ + Key: 100500, + }} + }, + expectedErr: "sample label string index out of range", + }, + { + name: "String 0 not empty", + corrupt: func(p *testhelper.ProfileBuilder) { + p.StringTable[0] = "hmmm" + }, + expectedErr: "string 0 should be empty string", + }, + } + for _, td := range testdata { + t.Run(td.name, func(t *testing.T) { + p1 := testhelper.NewProfileBuilder(time.Now().Add(-time.Second).UnixNano()). + MemoryProfile(). + ForStacktraceString("my", "other"). + AddSamples(239, 239*blockSize, 1000, 1000*blockSize) + td.corrupt(p1) + p1bs, err := p1.MarshalVT() + require.NoError(t, err) + + rb := p.NewRequestBuilder(t) + rb.Push(rb.PushPPROFRequestFromBytes(p1bs, metric), 400, td.expectedErr) + }) + } + }) +} + +func TestPush(t *testing.T) { + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + + for _, td := range testdata { + if td.prevProfile != "" { + continue } - }) - } + t.Run(td.profile, func(t *testing.T) { + rb := p.NewRequestBuilder(t) + + req := rb.PushPPROFRequestFromFile(td.profile, td.metrics[0].name) + rb.Push(req, td.expectStatusPush, td.expectedError) + + if td.expectStatusPush == 200 { + for _, metric := range td.metrics { + rb.Render(metric.name) + profile := rb.SelectMergeProfile(metric.name, metric.query) + + assertPPROF(t, profile, metric, td, td.fixAtPush) + } + } + }) + } + }) } func assertPPROF(t *testing.T, resp *connect.Response[profilev1.Profile], metric expectedMetric, testdatum pprofTestData, fix func(*pprof.Profile) *pprof.Profile) { diff --git a/pkg/test/integration/ingest_speedscope_test.go b/pkg/test/integration/ingest_speedscope_test.go new file mode 100644 index 0000000000..e93725b358 --- /dev/null +++ b/pkg/test/integration/ingest_speedscope_test.go @@ -0,0 +1,80 @@ +package integration + +import ( + "testing" + + "connectrpc.com/connect" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" +) + +type speedscopeTestDataStruct struct { + name string + speedscopeFile string + expectStatus int + expectedMetrics []expectedMetric +} + +const ( + testdataDirSpeedscope = repoRoot + "pkg/og/convert/speedscope/testdata" +) + +var ( + speedscopeTestData = []speedscopeTestDataStruct{ + { + name: "single profile evented", + speedscopeFile: testdataDirSpeedscope + "/simple.speedscope.json", + expectStatus: 200, + expectedMetrics: []expectedMetric{ + // The difference between the metric name here and in the other test is a quirk in + // how the speedscope parsing logic. Only multi profile uploads will + // append the unit to the metric name which is parsed differently downstream. + {"process_cpu:cpu:nanoseconds:cpu:nanoseconds", nil, 0}, + }, + }, + { + name: "multi profile sampled", + speedscopeFile: testdataDirSpeedscope + "/two-sampled.speedscope.json", + expectStatus: 200, + expectedMetrics: []expectedMetric{ + {"wall:wall:nanoseconds:cpu:nanoseconds", nil, 0}, + }, + }, + { + name: "multi profile samples bytes units", + speedscopeFile: testdataDirSpeedscope + "/two-sampled-bytes.speedscope.json", + expectStatus: 200, + expectedMetrics: []expectedMetric{ + {"memory:samples:bytes::", nil, 0}, + }, + }, + } +) + +func TestIngestSpeedscope(t *testing.T) { + EachPyroscopeTest(t, func(p *PyroscopeTest, t *testing.T) { + for _, td := range speedscopeTestData { + t.Run(td.name, func(t *testing.T) { + rb := p.NewRequestBuilder(t) + req := rb.IngestSpeedscopeRequest(td.speedscopeFile) + p.Ingest(t, req, td.expectStatus) + + if td.expectStatus == 200 { + for _, metric := range td.expectedMetrics { + rb.Render(metric.name) + profile := rb.SelectMergeProfile(metric.name, metric.query) + assertSpeedscopeProfile(t, profile) + } + } + }) + } + }) +} + +func assertSpeedscopeProfile(t *testing.T, resp *connect.Response[profilev1.Profile]) { + assert.Equal(t, 1, len(resp.Msg.SampleType), "SampleType should be set") + require.Greater(t, len(resp.Msg.Sample), 0, "Profile should contain samples") + assert.Greater(t, resp.Msg.Sample[0].Value[0], int64(0), "Sample value should be positive") +} diff --git a/pkg/test/integration/microservices_test.go b/pkg/test/integration/microservices_test.go index 9cc6d9a597..6e49b16271 100644 --- a/pkg/test/integration/microservices_test.go +++ b/pkg/test/integration/microservices_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "sort" + "strings" "testing" "time" @@ -12,13 +13,16 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" "github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect" querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/pprof/testhelper" - "github.com/grafana/pyroscope/pkg/test/integration/cluster" + "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + "github.com/grafana/pyroscope/v2/pkg/pprof/testhelper" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/integration/cluster" ) // TestMicroServicesIntegration tests the integration of the microservices in a @@ -28,11 +32,11 @@ import ( // and then queries the series, label names and label values. It then stops some // of the services and runs the same queries again to check if the cluster is still // able to respond to queries. -func TestMicroServicesIntegration(t *testing.T) { +func TestMicroServicesIntegrationV1(t *testing.T) { c := cluster.NewMicroServiceCluster() ctx := context.Background() - require.NoError(t, c.Prepare()) + require.NoError(t, c.Prepare(ctx)) for _, comp := range c.Components { t.Log(comp.String()) } @@ -75,110 +79,594 @@ func TestMicroServicesIntegration(t *testing.T) { } +func TestMicroServicesIntegrationV2(t *testing.T) { + c := cluster.NewMicroServiceCluster(cluster.WithV2()) + ctx := context.Background() + + require.NoError(t, c.Prepare(ctx)) + for _, comp := range c.Components { + t.Log(comp.String()) + } + + // start returns as soon the cluster is ready + require.NoError(t, c.Start(ctx)) + t.Log("Cluster ready") + defer func() { + waitStopped := c.Stop() + require.NoError(t, waitStopped(ctx)) + }() + + tc := newTestCtx(c) + t.Run("PushProfiles", func(t *testing.T) { + tc.pushProfiles(ctx, t) + }) + + // Segments contain a per-tenant dataset index, so queries that do not + // match a service_name can find data without waiting for compaction. + require.Eventually(t, func() bool { + for tenantID := range tc.perTenantData { + ctx := tenant.InjectTenantID(ctx, tenantID) + resp, err := tc.querier.LabelValues(ctx, connect.NewRequest(&typesv1.LabelValuesRequest{ + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + Name: "service_name", + })) + if err != nil { + return false + } + if len(resp.Msg.Names) != tc.perTenantData[tenantID].serviceCount { + return false + } + } + return true + }, time.Minute, time.Second) + t.Log("All tenants have all expected labelValues available") + + tc.runQueryTest(ctx, t) + +} + +// TestMicroServicesIntegrationV2_Federated boots a V2 cluster with a +// single segment-writer and no compaction-worker, ingests profiles for +// multiple tenants and runs federated (multi-tenant) queries against +// them. The single-writer / no-compaction setup deterministically +// produces L0 blocks containing one Format1 dataset_index pseudo-dataset +// per tenant, which is what the multi-Format1 resolution path in the +// query backend handles. +func TestMicroServicesIntegrationV2_Federated(t *testing.T) { + c := cluster.NewMicroServiceCluster(cluster.WithV2Federated()) + ctx := context.Background() + + require.NoError(t, c.Prepare(ctx)) + for _, comp := range c.Components { + t.Log(comp.String()) + } + + require.NoError(t, c.Start(ctx)) + t.Log("Cluster ready") + defer func() { + waitStopped := c.Stop() + require.NoError(t, waitStopped(ctx)) + }() + + tc := newTestCtx(c) + // Use a small fixed dataset for this test: federated correctness does + // not depend on dataset size, and this keeps the test fast. + tc.perTenantData = map[string]tenantParams{ + "tenant-a": {serviceCount: 3, samples: 2}, + "tenant-b": {serviceCount: 2, samples: 2}, + } + + t.Run("PushProfiles", func(t *testing.T) { + tc.pushProfiles(ctx, t) + }) + + // Wait for all per-tenant services to be visible via the dataset + // index. Without a compaction-worker the L0 segments are the only + // queryable blocks, so a positive answer here also confirms that + // multi-tenant L0 blocks have been flushed and indexed. + require.Eventually(t, func() bool { + for tenantID := range tc.perTenantData { + ctx := tenant.InjectTenantID(ctx, tenantID) + resp, err := tc.querier.LabelValues(ctx, connect.NewRequest(&typesv1.LabelValuesRequest{ + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + Name: "service_name", + })) + if err != nil { + return false + } + if len(resp.Msg.Names) != tc.perTenantData[tenantID].serviceCount { + return false + } + } + return true + }, time.Minute, time.Second) + + t.Run("QueryFederatedMultiTenant", func(t *testing.T) { + tc.runFederatedQueryTest(ctx, t) + }) +} + +// TestMetastoreAutoJoin tests that a new metastore node can join an existing cluster +// using the auto-join feature without requiring bootstrap configuration. +func TestMetastoreAutoJoin(t *testing.T) { + c := cluster.NewMicroServiceCluster(cluster.WithV2()) + ctx := context.Background() + + require.NoError(t, c.Prepare(ctx)) + for _, comp := range c.Components { + t.Log(comp.String()) + } + + require.NoError(t, c.Start(ctx)) + defer func() { + waitStopped := c.Stop() + require.NoError(t, waitStopped(ctx)) + }() + + client, err := c.GetMetastoreRaftNodeClient() + require.NoError(t, err) + nodeInfo, err := client.NodeInfo(ctx, &raftnodepb.NodeInfoRequest{}) + require.NoError(t, err) + require.Equal(t, 3, len(nodeInfo.Node.Peers), "initial cluster should have 3 peers") + + err = c.AddMetastoreWithAutoJoin(ctx) + require.NoError(t, err) + + require.Eventually(t, func() bool { + nodeInfo, err := client.NodeInfo(ctx, &raftnodepb.NodeInfoRequest{}) + if err != nil { + t.Logf("Failed to get node info: %v", err) + return false + } + t.Logf("Current peer count: %d", len(nodeInfo.Node.Peers)) + return len(nodeInfo.Node.Peers) == 4 + }, 30*time.Second, 1*time.Second, "new metastore should join cluster") +} + func newTestCtx(x interface { PushClient() pushv1connect.PusherServiceClient QueryClient() querierv1connect.QuerierServiceClient }) *testCtx { return &testCtx{ - now: time.Now().Truncate(time.Second), - serviceCount: 100, - samples: 5, - querier: x.QueryClient(), - pusher: x.PushClient(), + now: time.Now().Truncate(time.Second), + perTenantData: map[string]tenantParams{ + "tenant-a": { + serviceCount: 100, + samples: 5, + }, + "tenant-b": { + serviceCount: 1, + samples: 1, + }, + "tenant-not-existing": {}, + }, + querier: x.QueryClient(), + pusher: x.PushClient(), } } -type testCtx struct { - now time.Time +type tenantParams struct { serviceCount int samples int +} + +type testCtx struct { + now time.Time - querier querierv1connect.QuerierServiceClient - pusher pushv1connect.PusherServiceClient + perTenantData map[string]tenantParams + querier querierv1connect.QuerierServiceClient + pusher pushv1connect.PusherServiceClient } func (tc *testCtx) pushProfiles(ctx context.Context, t *testing.T) { g, gctx := errgroup.WithContext(ctx) g.SetLimit(20) - // for loop range over serviceCount - for i := 0; i < tc.serviceCount; i++ { - var i = i - g.Go(func() error { - serviceName := fmt.Sprintf("test-service-%d", i) - builder := testhelper.NewProfileBuilder(int64(1)). - CPUProfile(). - WithLabels( - "job", "test", - "service_name", serviceName, - ) - builder.ForStacktraceString("foo", "bar", "baz").AddSamples(1) - for j := 0; j < tc.samples; j++ { - builder.TimeNanos = tc.now.Add(time.Duration(j) * 5 * time.Second).UnixNano() - if (i+j)%3 == 0 { - builder.ForStacktraceString("foo", "bar", "boz").AddSamples(3) + for tenantID, params := range tc.perTenantData { + gctx := tenant.InjectTenantID(gctx, tenantID) + for i := 0; i < params.serviceCount; i++ { + var i = i + g.Go(func() error { + serviceName := fmt.Sprintf("%s/test-service-%d", tenantID, i) + builder := testhelper.NewProfileBuilder(tc.now.UnixNano()). + CPUProfile(). + WithLabels( + "job", "test", + "service_name", serviceName, + ) + builder.ForStacktraceString("foo", "bar", "baz").AddSamples(1) + for j := 0; j < params.samples; j++ { + if (i+j)%3 == 0 { + builder.ForStacktraceString("foo", "bar", "boz").AddSamples(3) + } } - } - rawProfile, err := builder.MarshalVT() - require.NoError(t, err) + rawProfile, err := builder.MarshalVT() + require.NoError(t, err) - _, err = tc.pusher.Push(gctx, connect.NewRequest(&pushv1.PushRequest{ - Series: []*pushv1.RawProfileSeries{{ - Labels: builder.Labels, - Samples: []*pushv1.RawSample{{RawProfile: rawProfile}}, - }}, - })) - return err - }) + _, err = tc.pusher.Push(gctx, connect.NewRequest(&pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{{ + Labels: builder.Labels, + Samples: []*pushv1.RawSample{{RawProfile: rawProfile}}, + }}, + })) + return err + }) + } } require.NoError(t, g.Wait()) } func (tc *testCtx) runQueryTest(ctx context.Context, t *testing.T) { + isV2 := strings.HasSuffix(t.Name(), "V2") t.Run("QuerySeries", func(t *testing.T) { - resp, err := tc.querier.Series(ctx, connect.NewRequest(&querierv1.SeriesRequest{ - Start: tc.now.Add(-time.Hour).UnixMilli(), - End: tc.now.Add(time.Hour).UnixMilli(), - LabelNames: []string{"__profile_type__", "job", "service_name"}, - })) - require.NoError(t, err) - require.Len(t, resp.Msg.LabelsSet, 100) + for tenantID, params := range tc.perTenantData { + t.Run(tenantID, func(t *testing.T) { + ctx := tenant.InjectTenantID(ctx, tenantID) + resp, err := tc.querier.Series(ctx, connect.NewRequest(&querierv1.SeriesRequest{ + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + LabelNames: []string{"__profile_type__", "service_name"}, + })) + require.NoError(t, err) + require.Len(t, resp.Msg.LabelsSet, params.serviceCount) + + // no services to check + if params.serviceCount == 0 { + return + } + + expectedValues := make([]*typesv1.Labels, params.serviceCount) + for i := 0; i < params.serviceCount; i++ { + // check if the service name is in the response + expectedValues[i] = &typesv1.Labels{ + Labels: []*typesv1.LabelPair{ + { + Name: "__profile_type__", + Value: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + }, + { + Name: "service_name", + Value: fmt.Sprintf("%s/test-service-%d", tenantID, i), + }, + }, + } + } + + // sort the response by service name + sort.Slice(resp.Msg.LabelsSet, func(i, j int) bool { + return resp.Msg.LabelsSet[i].Labels[1].Value < resp.Msg.LabelsSet[j].Labels[1].Value + }) + sort.Slice(expectedValues, func(i, j int) bool { + return expectedValues[i].Labels[1].Value < expectedValues[j].Labels[1].Value + }) + assert.Equal(t, expectedValues, resp.Msg.LabelsSet) + }) + } }) t.Run("QueryLabelNames", func(t *testing.T) { - resp, err := tc.querier.LabelNames(ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ - Start: tc.now.Add(-time.Hour).UnixMilli(), - End: tc.now.Add(time.Hour).UnixMilli(), - })) - require.NoError(t, err) + for tenantID, params := range tc.perTenantData { + t.Run(tenantID, func(t *testing.T) { + ctx := tenant.InjectTenantID(ctx, tenantID) + resp, err := tc.querier.LabelNames(ctx, connect.NewRequest(&typesv1.LabelNamesRequest{ + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + })) + require.NoError(t, err) + + // no services, no label names + if params.serviceCount == 0 { + assert.Len(t, resp.Msg.Names, 0) + return + } + + assert.Equal(t, []string{ + "__name__", + "__period_type__", + "__period_unit__", + "__profile_type__", + "__service_name__", + "__type__", + "__unit__", + "job", + "service_name", + }, resp.Msg.Names) + }) + } + }) + + validateProfileTypes := func(t *testing.T, serviceCount int, resp *querierv1.ProfileTypesResponse) { + // no services, no label names + if serviceCount == 0 { + assert.Len(t, resp.ProfileTypes, 0) + return + } + + profileTypes := make([]string, 0, len(resp.ProfileTypes)) + for _, pt := range resp.ProfileTypes { + profileTypes = append(profileTypes, pt.ID) + } assert.Equal(t, []string{ - "__name__", - "__period_type__", - "__period_unit__", - "__profile_type__", - "__service_name__", - "__type__", - "__unit__", - "job", - "service_name", - }, resp.Msg.Names) + "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + }, profileTypes) + } + + t.Run("QueryProfileTypesWithTimeRange", func(t *testing.T) { + for tenantID, params := range tc.perTenantData { + t.Run(tenantID, func(t *testing.T) { + ctx := tenant.InjectTenantID(ctx, tenantID) + + // Query profile types with time range + resp, err := tc.querier.ProfileTypes(ctx, connect.NewRequest(&querierv1.ProfileTypesRequest{ + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + })) + require.NoError(t, err) + + validateProfileTypes(t, params.serviceCount, resp.Msg) + }) + } + }) + + // Note: Some ProfileTypes API clients rely on the ability to call it without start/end. + // See https://github.com/grafana/grafana/issues/110211 + t.Run("QueryProfileTypesWithoutTimeRange", func(t *testing.T) { + for tenantID, params := range tc.perTenantData { + t.Run(tenantID, func(t *testing.T) { + ctx := tenant.InjectTenantID(ctx, tenantID) + + // Query profile types with time range + resp, err := tc.querier.ProfileTypes(ctx, connect.NewRequest(&querierv1.ProfileTypesRequest{})) + require.NoError(t, err) + + validateProfileTypes(t, params.serviceCount, resp.Msg) + }) + } }) t.Run("QueryLabelValues", func(t *testing.T) { - resp, err := tc.querier.LabelValues(ctx, connect.NewRequest(&typesv1.LabelValuesRequest{ - Start: tc.now.Add(-time.Hour).UnixMilli(), - End: tc.now.Add(time.Hour).UnixMilli(), - Name: "service_name", - })) - require.NoError(t, err) - // loop over numbers from i too serviceCount - expectedValues := make([]string, tc.serviceCount) - for i := 0; i < tc.serviceCount; i++ { - // check if the service name is in the response - expectedValues[i] = fmt.Sprintf("test-service-%d", i) - } - sort.Strings(expectedValues) - assert.Equal(t, expectedValues, resp.Msg.Names) + for tenantID, params := range tc.perTenantData { + t.Run(tenantID, func(t *testing.T) { + ctx := tenant.InjectTenantID(ctx, tenantID) + resp, err := tc.querier.LabelValues(ctx, connect.NewRequest(&typesv1.LabelValuesRequest{ + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + Name: "service_name", + })) + require.NoError(t, err) + + // no services, no label values + if params.serviceCount == 0 { + assert.Len(t, resp.Msg.Names, 0) + return + } + + expectedValues := make([]string, params.serviceCount) + for i := 0; i < params.serviceCount; i++ { + // check if the service name is in the response + expectedValues[i] = fmt.Sprintf("%s/test-service-%d", tenantID, i) + } + sort.Strings(expectedValues) + assert.Equal(t, expectedValues, resp.Msg.Names) + }) + } + }) + + t.Run("QuerySelectMergeProfile", func(t *testing.T) { + for tenantID, params := range tc.perTenantData { + t.Run(tenantID, func(t *testing.T) { + ctx := tenant.InjectTenantID(ctx, tenantID) + req := &querierv1.SelectMergeProfileRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + LabelSelector: "{}", + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + } + resp, err := tc.querier.SelectMergeProfile(ctx, connect.NewRequest(req)) //nolint:staticcheck // Legacy querier.v1 integration coverage. + require.NoError(t, err) + + // no services, no samples profile + if params.serviceCount == 0 { + return + } + + // TODO: Experimental storage layer v2 doesn't support DurationNanos yet + // https://github.com/grafana/pyroscope/issues/4192 + if !isV2 { + assert.Equal(t, int64(7200000000000), resp.Msg.DurationNanos, "DurationNanos") + } + + assert.Equal(t, req.End*1e6, resp.Msg.TimeNanos, "TimeNanos") + + assert.Equal(t, + []*profilev1.ValueType{ + {Type: 6, Unit: 5}, + }, resp.Msg.SampleType, "SampleType", + ) + + // boz samples + bozSamples := 0 + for i := 0; i < params.serviceCount; i++ { + for j := 0; j < params.samples; j++ { + if (i+j)%3 == 0 { + bozSamples += 3 + } + } + } + + normalized := normalizePprof(resp.Msg) + assert.Equal(t, + []*profilev1.Sample{ + {LocationId: []uint64{4, 1, 2}, Value: []int64{int64(params.serviceCount)}}, + {LocationId: []uint64{4, 1, 3}, Value: []int64{int64(bozSamples)}}, + }, normalized.Sample, "Samples", + ) + assert.Equal(t, + []*profilev1.Mapping{ + {Id: 1, HasFunctions: true}, + }, resp.Msg.Mapping, "Mappings", + ) + assert.Equal(t, + []*profilev1.Location{ + {Id: 1, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 1}}}, + {Id: 2, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 2}}}, + {Id: 3, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 3}}}, + {Id: 4, MappingId: 1, Line: []*profilev1.Line{{FunctionId: 4}}}, + }, normalized.Location, "Locations", + ) + assert.Equal(t, + []*profilev1.Function{ + {Id: 1, Name: 2}, + {Id: 2, Name: 3}, + {Id: 3, Name: 4}, + {Id: 4, Name: 1}, + }, normalized.Function, "Functions", + ) + assert.Equal(t, + []string{"", "foo", "bar", "baz", "boz", "nanoseconds", "cpu"}, + resp.Msg.StringTable, + ) + assert.Equal(t, + &profilev1.ValueType{Type: 6, Unit: 5}, + resp.Msg.PeriodType, + ) + }) + } }) + + t.Run("QuerierServiceAsync", func(t *testing.T) { + if !isV2 { + t.Skip("Async queries require query-frontend which is not present in V1 microservices cluster") + } + for tenantID, params := range tc.perTenantData { + t.Run(tenantID, func(t *testing.T) { + ctx := tenant.InjectTenantID(ctx, tenantID) + submitReq := &querierv1.SelectMergeStacktracesRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + LabelSelector: `{__profile_type__="process_cpu:cpu:nanoseconds:cpu:nanoseconds"}`, + Format: querierv1.ProfileFormat_PROFILE_FORMAT_TREE, + Async: &querierv1.AsyncQueryRequest{Type: querierv1.AsyncQueryType_ASYNC_QUERY_TYPE_FORCE}, + } + + // Submit async query. + resp, err := tc.querier.SelectMergeStacktraces(ctx, connect.NewRequest(submitReq)) + require.NoError(t, err) + require.NotNil(t, resp.Msg.Async, "expected async metadata on submit response") + require.NotEmpty(t, resp.Msg.Async.RequestId) + assert.Equal(t, querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_IN_PROGRESS, resp.Msg.Async.Status) + + // Poll until done. + pollReq := &querierv1.SelectMergeStacktracesRequest{ + Async: &querierv1.AsyncQueryRequest{ + Type: querierv1.AsyncQueryType_ASYNC_QUERY_TYPE_FORCE, + RequestId: resp.Msg.Async.RequestId, + }, + } + require.Eventually(t, func() bool { + pollResp, err := tc.querier.SelectMergeStacktraces(ctx, connect.NewRequest(pollReq)) + if err != nil { + return false + } + if pollResp.Msg.GetAsync() == nil { + return false + } + if pollResp.Msg.Async.Status == querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_IN_PROGRESS { + return false + } + resp = pollResp + return true + }, 30*time.Second, 500*time.Millisecond) + + require.NotNil(t, resp.Msg.Async) + + // No services means no profile data. + if params.serviceCount == 0 { + assert.NotEqual(t, querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_IN_PROGRESS, resp.Msg.Async.Status) + return + } + + require.Equal(t, querierv1.AsyncQueryStatus_ASYNC_QUERY_STATUS_SUCCESS, resp.Msg.Async.Status, "error: %s", resp.Msg.Async.ErrorMessage) + require.NotEmpty(t, resp.Msg.Tree, "expected a tree payload") + }) + } + }) +} + +// runFederatedQueryTest exercises queries that span multiple tenants by +// passing a pipe-separated tenant ID in X-Scope-OrgID. It is intended to +// be driven against a cluster that produces multi-tenant L0 blocks (see +// cluster.WithV2Federated), so that the query backend's multi-Format1 +// dataset_index resolution path is exercised. +func (tc *testCtx) runFederatedQueryTest(ctx context.Context, t *testing.T) { + tenants := make([]string, 0, len(tc.perTenantData)) + expectedServices := 0 + expectedServiceNames := make([]string, 0) + // expectedTotalSampleValue mirrors the per-tenant ingest pattern in + // pushProfiles: each service emits one foo/bar/baz sample with + // value=1, plus a foo/bar/boz sample with value=3 for every (i,j) + // where (i+j)%3 == 0. The merged federated profile sums all those + // values across every service of every tenant. + expectedTotalSampleValue := int64(0) + for tenantID, params := range tc.perTenantData { + tenants = append(tenants, tenantID) + expectedServices += params.serviceCount + for i := 0; i < params.serviceCount; i++ { + expectedServiceNames = append(expectedServiceNames, fmt.Sprintf("%s/test-service-%d", tenantID, i)) + expectedTotalSampleValue++ // foo/bar/baz, value=1 + for j := 0; j < params.samples; j++ { + if (i+j)%3 == 0 { + expectedTotalSampleValue += 3 // foo/bar/boz, value=3 + } + } + } + } + sort.Strings(tenants) + sort.Strings(expectedServiceNames) + orgID := strings.Join(tenants, "|") + // The connect tenant interceptor on the client side calls the + // single-tenant resolver, which rejects multi-tenant IDs, so + // we set the X-Scope-OrgID header explicitly to bypass it. + + // LabelValues without a service_name matcher takes the + // dataset_index lookup path (index-only branch). Asserting the + // exact set of service names confirms that every tenant's data is + // reachable through the federated query, not just one of them. + lvReq := connect.NewRequest(&typesv1.LabelValuesRequest{ + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + Name: "service_name", + }) + lvReq.Header().Set("X-Scope-OrgID", orgID) + lv, err := tc.querier.LabelValues(ctx, lvReq) + require.NoError(t, err) + assert.Equal(t, expectedServiceNames, lv.Msg.Names, "federated label values must include every tenant's services") + + // SelectMergeProfile without a service_name matcher needs + // SectionProfiles+SectionSymbols, exercising the resolve path + // where each per-tenant dataset_index is opened. Summing the + // merged sample values lets us check that data from every + // tenant ended up in the merged profile. + smpReq := connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + LabelSelector: "{}", + Start: tc.now.Add(-time.Hour).UnixMilli(), + End: tc.now.Add(time.Hour).UnixMilli(), + }) + smpReq.Header().Set("X-Scope-OrgID", orgID) + resp, err := tc.querier.SelectMergeProfile(ctx, smpReq) //nolint:staticcheck // Legacy querier.v1 integration coverage. + require.NoError(t, err) + require.NotNil(t, resp.Msg) + assert.NotEmpty(t, resp.Msg.Sample, "federated profile must contain samples") + var totalSampleValue int64 + for _, s := range resp.Msg.Sample { + for _, v := range s.Value { + totalSampleValue += v + } + } + assert.Equal(t, expectedTotalSampleValue, totalSampleValue, "federated profile must merge sample values from every tenant") } diff --git a/pkg/test/integration/ports.go b/pkg/test/integration/ports.go new file mode 100644 index 0000000000..2265e5e075 --- /dev/null +++ b/pkg/test/integration/ports.go @@ -0,0 +1,24 @@ +package integration + +import "net" + +// GetFreePorts returns a number of free local port for the tests to listen on. +// This will make sure the returned ports do not overlap, by stopping to listen once all ports are allocated +// +// Note: This function should only be used in integration tests. +// Use in-memory network connections in unittests. +func GetFreePorts(len int) (ports []int, err error) { + ports = make([]int, len) + for i := 0; i < len; i++ { + var a *net.TCPAddr + if a, err = net.ResolveTCPAddr("tcp", "127.0.0.1:0"); err == nil { + var l *net.TCPListener + if l, err = net.ListenTCP("tcp", a); err != nil { + return nil, err + } + defer l.Close() + ports[i] = l.Addr().(*net.TCPAddr).Port + } + } + return ports, nil +} diff --git a/pkg/test/integration/symbolization_test.go b/pkg/test/integration/symbolization_test.go new file mode 100644 index 0000000000..ec679f6eff --- /dev/null +++ b/pkg/test/integration/symbolization_test.go @@ -0,0 +1,360 @@ +package integration + +import ( + "bytes" + "context" + "fmt" + "path/filepath" + "runtime" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/google/pprof/profile" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/test/integration/cluster" +) + +const testBuildID = "2fa2055ef20fabc972d5751147e093275514b142" + +func TestMicroServicesIntegrationV2Symbolization(t *testing.T) { + debuginfodServer, err := NewTestDebuginfodServer() + require.NoError(t, err) + + _, currentFile, _, _ := runtime.Caller(0) + testDataDir := filepath.Join(filepath.Dir(currentFile), "..", "..", "symbolizer", "testdata") + debugFilePath := filepath.Join(testDataDir, "symbols.debug") + + debuginfodServer.AddDebugFile(testBuildID, debugFilePath) + + require.NoError(t, debuginfodServer.Start()) + defer func() { + _ = debuginfodServer.Stop() + }() + + c := cluster.NewMicroServiceCluster( + cluster.WithV2(), + cluster.WithSymbolizer(debuginfodServer.URL()), + ) + + ctx := context.Background() + + require.NoError(t, c.Prepare(ctx)) + for _, comp := range c.Components { + t.Log(comp.String()) + } + + require.NoError(t, c.Start(ctx)) + t.Log("Cluster ready") + defer func() { + waitStopped := c.Stop() + require.NoError(t, waitStopped(ctx)) + }() + + t.Run("SymbolizationFlow", func(t *testing.T) { + testSymbolizationFlow(t, ctx, c) + }) +} + +func testSymbolizationFlow(t *testing.T, ctx context.Context, c *cluster.Cluster) { + tests := []struct { + name string + profile func(now time.Time) *profile.Profile + expected string + // Symbolized frames that must still be present after the pushed + // segment has been compacted; nil skips the post-compaction phase. + postCompactionSymbols map[string]uint64 + skip bool + }{ + { + name: "fully unsymbolized", + profile: func(now time.Time) *profile.Profile { + p := &profile.Profile{ + DurationNanos: int64(10 * time.Second), + Period: 1000000000, + SampleType: []*profile.ValueType{ + {Type: "cpu", Unit: "nanoseconds"}, + }, + PeriodType: &profile.ValueType{ + Type: "cpu", + Unit: "nanoseconds", + }, + } + + m := &profile.Mapping{ + ID: 1, + Start: 0, + Limit: 0x1000000, + Offset: 0, + File: "libfoo.so", + BuildID: testBuildID, + HasFunctions: false, + } + p.Mapping = []*profile.Mapping{m} + + loc1 := &profile.Location{ + ID: 1, + Mapping: m, + Address: 0x1500, + } + loc2 := &profile.Location{ + ID: 2, + Mapping: m, + Address: 0x3c5a, + } + p.Location = []*profile.Location{loc1, loc2} + + p.Sample = []*profile.Sample{ + { + Location: []*profile.Location{loc1}, + Value: []int64{100}, + }, + { + Location: []*profile.Location{loc2}, + Value: []int64{200}, + }, + { + Location: []*profile.Location{loc1, loc2}, + Value: []int64{3}, + }, + } + + return p + }, + expected: `PeriodType: cpu nanoseconds +Period: 1000000000 +Samples: +cpu/nanoseconds[dflt] + 200: 1 + 100: 2 + 3: 2 1 +Locations + 1: 0x3c5a M=1 atoll_b :0:0 s=0() + 2: 0x1500 M=1 main :0:0 s=0() +Mappings +1: 0x0/0x1000000/0x0 libfoo.so 2fa2055ef20fabc972d5751147e093275514b142 [FN] +`, + postCompactionSymbols: map[string]uint64{"main": 0x1500, "atoll_b": 0x3c5a}, + }, + { + name: "partially symbolized", + profile: func(now time.Time) *profile.Profile { + p := &profile.Profile{ + DurationNanos: int64(10 * time.Second), + Period: 1000000000, + SampleType: []*profile.ValueType{ + {Type: "cpu", Unit: "nanoseconds"}, + }, + PeriodType: &profile.ValueType{ + Type: "cpu", + Unit: "nanoseconds", + }, + } + + m := &profile.Mapping{ + ID: 1, + Start: 0, + Limit: 0x1000000, + Offset: 0, + File: "libfoo.so", + BuildID: testBuildID, + HasFunctions: true, + } + p.Mapping = []*profile.Mapping{m} + f1 := &profile.Function{ + ID: 1, + Name: "symbolized_func", + Filename: "src.c", + } + loc1 := &profile.Location{ + ID: 1, + Mapping: m, + Address: 0x1500, + Line: []profile.Line{{Function: f1, Line: 239}}, + } + loc2 := &profile.Location{ + ID: 2, + Mapping: m, + Address: 0x3c5a, + } + p.Location = []*profile.Location{loc1, loc2} + + p.Sample = []*profile.Sample{ + { + Location: []*profile.Location{loc1}, + Value: []int64{100}, + }, + { + Location: []*profile.Location{loc2}, + Value: []int64{200}, + }, + { + Location: []*profile.Location{loc1, loc2}, + Value: []int64{3}, + }, + } + p.Function = []*profile.Function{ + f1, + } + + return p + }, + expected: `PeriodType: cpu nanoseconds +Period: 1000000000 +Samples: +cpu/nanoseconds[dflt] + 200: 2 + 3: 1 2 + 100: 1 +Locations + 1: 0x0 M=1 symbolized_func src.c:239:0 s=0() + 2: 0x0 M=1 atoll_b :0:0 s=0() +Mappings +1: 0x0/0x0/0x0 libfoo.so 2fa2055ef20fabc972d5751147e093275514b142 [FN] +`, + skip: true, // TODO fix the testdata or symbolization + }, + } + pusher := c.PushClient() + querier := c.QueryClient() + + now := time.Now().Truncate(time.Second) + tenantID := "test-tenant" + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.skip { + t.Skip() + } + serviceName := "test-symbolization-service-" + test.name + src := test.profile(now) + + var buf bytes.Buffer + err := src.Write(&buf) + require.NoError(t, err) + rawProfile := buf.Bytes() + + ctx = tenant.InjectTenantID(ctx, tenantID) + _, err = pusher.Push(ctx, connect.NewRequest(&pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{{ + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: serviceName}, + {Name: "__name__", Value: "process_cpu"}, + }, + Samples: []*pushv1.RawSample{{RawProfile: rawProfile}}, + }}, + })) + require.NoError(t, err) + + q := connect.NewRequest(&querierv1.SelectMergeProfileRequest{ + ProfileTypeID: "process_cpu:cpu:nanoseconds:cpu:nanoseconds", + Start: now.Add(-time.Hour).UnixMilli(), + End: now.Add(time.Hour).UnixMilli(), + LabelSelector: `{service_name="` + serviceName + `"}`, + }) + require.Eventually(t, func() bool { + resp, err := querier.SelectMergeProfile(ctx, q) //nolint:staticcheck // Legacy querier.v1 integration coverage. + if err != nil { + t.Logf("Error querying profile: %v", err) + return false + } + normalized := normalizePprof(resp.Msg) + rp := pprof.RawFromProto(normalized) + rp.TimeNanos = 0 + actual := rp.DebugString() + + fmt.Println(actual) + + if len(normalized.Sample) == 0 { + return false + } + + if actual != test.expected { + assert.Equal(t, test.expected, actual) + //fmt.Println(src.String()) + return false + } + return true + }, 5*time.Second, 100*time.Millisecond) + + if test.postCompactionSymbols == nil { + return + } + // The cluster compacts L0 blocks within seconds, and compaction + // deletes the source blocks: if the rewrite loses the addresses + // of line-less locations, the profile can never be symbolized + // again. The golden comparison above is order-sensitive and + // compaction may renumber locations, so past this point only the + // symbolized frames are asserted. + // Age-based batch flushing is evaluated only when another block + // arrives at the same compaction level, so keep pushing filler + // blocks — to a service the query below does not select — until + // the planner picks up the staged blocks. + require.Eventually(t, func() bool { + _, err := pusher.Push(ctx, connect.NewRequest(&pushv1.PushRequest{ + Series: []*pushv1.RawProfileSeries{{ + Labels: []*typesv1.LabelPair{ + {Name: "service_name", Value: serviceName + "-compaction-filler"}, + {Name: "__name__", Value: "process_cpu"}, + }, + Samples: []*pushv1.RawSample{{RawProfile: rawProfile}}, + }}, + })) + if err != nil { + t.Logf("Error pushing filler profile: %v", err) + return false + } + n, err := c.CompactionJobsFinished(ctx) + return err == nil && n >= 1 + }, 30*time.Second, time.Second, "no L0 compaction observed") + + queried := false + for deadline := time.Now().Add(8 * time.Second); time.Now().Before(deadline); time.Sleep(500 * time.Millisecond) { + resp, err := querier.SelectMergeProfile(ctx, q) //nolint:staticcheck // Legacy querier.v1 integration coverage. + if err != nil { + t.Logf("Error querying profile: %v", err) + continue + } + requireSymbolizedFrames(t, resp.Msg, test.postCompactionSymbols) + queried = true + } + require.True(t, queried, "profile was not queryable after compaction") + }) + } + +} + +// requireSymbolizedFrames asserts that the profile contains a symbolized +// frame for every expected function name → address pair, and no fallback +// (binary!0xaddr) frames. +func requireSymbolizedFrames(t *testing.T, p *profilev1.Profile, symbols map[string]uint64) { + t.Helper() + names := make(map[uint64]string, len(p.Function)) + for _, f := range p.Function { + names[f.Id] = p.StringTable[f.Name] + } + type frame struct { + name string + address uint64 + } + frames := make(map[frame]struct{}) + for _, loc := range p.Location { + for _, line := range loc.Line { + name := names[line.FunctionId] + require.NotContains(t, name, "!0x", "unexpected fallback frame") + frames[frame{name: name, address: loc.Address}] = struct{}{} + } + } + for name, address := range symbols { + _, ok := frames[frame{name: name, address: address}] + require.True(t, ok, "missing symbolized frame %s@%#x (got: %v)", name, address, frames) + } +} diff --git a/pkg/test/integration/testdata/.gitignore b/pkg/test/integration/testdata/.gitignore new file mode 100644 index 0000000000..5463c12e3e --- /dev/null +++ b/pkg/test/integration/testdata/.gitignore @@ -0,0 +1 @@ +*.pprof.pb.bin \ No newline at end of file diff --git a/pkg/test/integration/testdata/README.md b/pkg/test/integration/testdata/README.md new file mode 100644 index 0000000000..8054b3beee --- /dev/null +++ b/pkg/test/integration/testdata/README.md @@ -0,0 +1,124 @@ +## Data generation + +OTLP ingest handler has been updated to be compatible with OTLP protocol 1.8. Unfortunately, otel-collector does not yet have full support for 1.8.0, which prevents us from using otelcollector-contrib compiled image. Below procedure should be revisited once otel-collector is fully updated to 1.8. + +To generate data for this fixture, use following procedure: + +1. Patch ingest_handler.go to dump the received data: + +``` +diff --git a/pkg/ingester/otlp/ingest_handler.go b/pkg/ingester/otlp/ingest_handler.go +index bf7a6612f..1a6619243 100644 +--- a/pkg/ingester/otlp/ingest_handler.go ++++ b/pkg/ingester/otlp/ingest_handler.go +@@ -2,13 +2,18 @@ package otlp + + import ( + "context" ++ "encoding/json" + "fmt" + "net/http" ++ "os" ++ "path/filepath" + "strings" ++ "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/keepalive" ++ "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + "github.com/go-kit/log" +@@ -103,6 +108,20 @@ func (h *ingestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + } + + func (h *ingestHandler) Export(ctx context.Context, er *pprofileotlp.ExportProfilesServiceRequest) (*pprofileotlp.ExportProfilesServiceResponse, error) { ++ // Debug: dump request to files & optionally corrupt data ++ //for _, rp := range er.GetResourceProfiles() { ++ // for _, sp := range rp.GetScopeProfiles() { ++ // for _, p := range sp.GetProfiles() { ++ // for _, s := range p.Sample { ++ // s.StackIndex = 1000000000 ++ // } ++ // } ++ // } ++ //} ++ if err := h.dumpRequestToFiles(er); err != nil { ++ level.Warn(h.log).Log("msg", "failed to dump request to debug files", "err", err) ++ } ++ + // TODO: @petethepig This logic is copied from util.AuthenticateUser and should be refactored into a common function + // Extracts user ID from the request metadata and returns and injects the user ID in the context + if !h.multitenancyEnabled { +@@ -243,3 +262,55 @@ func appendAttributesUnique(labels []*typesv1.LabelPair, attrs []*v1.KeyValue, p + } + return labels + } ++ ++// dumpRequestToFiles dumps the received request to both protobuf and JSON formats for debugging ++func (h *ingestHandler) dumpRequestToFiles(er *pprofileotlp.ExportProfilesServiceRequest) error { ++ captureDir := "/tmp/capture" ++ ++ // Ensure capture directory exists ++ if err := os.MkdirAll(captureDir, 0755); err != nil { ++ return fmt.Errorf("failed to create capture directory: %w", err) ++ } ++ ++ // Generate timestamp-based filename ++ timestamp := time.Now().UnixNano() ++ ++ // Dump as protobuf binary ++ pbData, err := proto.Marshal(er) ++ if err != nil { ++ return fmt.Errorf("failed to marshal protobuf: %w", err) ++ } ++ ++ pbFilename := filepath.Join(captureDir, fmt.Sprintf("%d.pb.bin", timestamp)) ++ if err := os.WriteFile(pbFilename, pbData, 0644); err != nil { ++ return fmt.Errorf("failed to write protobuf file: %w", err) ++ } ++ ++ // Dump as formatted JSON ++ jsonData, err := protojson.MarshalOptions{ ++ Multiline: true, ++ Indent: " ", ++ }.Marshal(er) ++ if err != nil { ++ return fmt.Errorf("failed to marshal JSON: %w", err) ++ } ++ ++ // Pretty print JSON ++ var prettyJSON map[string]interface{} ++ if err := json.Unmarshal(jsonData, &prettyJSON); err != nil { ++ return fmt.Errorf("failed to unmarshal JSON for pretty printing: %w", err) ++ } ++ ++ formattedJSON, err := json.MarshalIndent(prettyJSON, "", " ") ++ if err != nil { ++ return fmt.Errorf("failed to marshal pretty JSON: %w", err) ++ } ++ ++ jsonFilename := filepath.Join(captureDir, fmt.Sprintf("%d.pb.json", timestamp)) ++ if err := os.WriteFile(jsonFilename, formattedJSON, 0644); err != nil { ++ return fmt.Errorf("failed to write JSON file: %w", err) ++ } ++ ++ level.Debug(h.log).Log("msg", "dumped request to debug files", "pb_file", pbFilename, "json_file", jsonFilename) ++ return nil ++} +``` +2.Launch local pyroscope instance +3.Compile & start ebpf profiler with following parameters: + +``` +./ebpf-profiler -collection-agent -off-cpu-threshold 1 -disable-tls +``` + +Example command to start profiler under Docker/Podman on Mac (from a source directory with compiled profiler): +``` +podman run -v "$PWD":/agent --mount type=bind,source=/sys/kernel/tracing,target=/sys/kernel/tracing --mount type=bind,source=/sys/kernel/debug,target=/sys/kernel/debug -it --privileged --replace --pid=host --name ebpf --user 0:0 otel/opentelemetry-ebpf-profiler-dev:latest /agent/ebpf-profiler -collection-agent -off-cpu-threshold 1 -disable-tls +``` +Note that this will capture live data from all processes on the machine it runs on + +4.Allow some profiles to be gathered, explore /tmp/capture dir diff --git a/pkg/test/integration/testdata/otel-ebpf-profile-cpu.out.json b/pkg/test/integration/testdata/otel-ebpf-profile-cpu.out.json new file mode 100644 index 0000000000..03ea7ffafd --- /dev/null +++ b/pkg/test/integration/testdata/otel-ebpf-profile-cpu.out.json @@ -0,0 +1 @@ +{"sample_types":[{"type":"cpu","unit":"nanoseconds"}],"samples":[{"locations":[{"address":"0x0","lines":["ZSTD_decompressSequences_bmi2.constprop.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressContinue.part.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressContinueStream[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressStream[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["zstd_decompress_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["end_bbio_compressed_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_check_read_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"50000000"},{"locations":[{"address":"0x0","lines":["mem_cgroup_iter[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["lru_gen_age_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"50000000"},{"locations":[{"address":"0x0","lines":["HUF_decompress4X2_usingDTable_internal_fast_c_loop[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["HUF_decompress4X2_usingDTable_internal_fast.constprop.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["HUF_decompress4X2_usingDTable_internal[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decodeLiteralsBlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressBlock_internal.part.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressContinue.part.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressContinueStream[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressStream[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["zstd_decompress_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["end_bbio_compressed_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_check_read_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"50000000"},{"locations":[{"address":"0x0","lines":["smp_call_function_many_cond[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["on_each_cpu_cond_mask[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["arch_tlbbatch_flush[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_unmap_flush_dirty[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_folio_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict_folios[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_shrink_lruvec[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"100000000"},{"locations":[{"address":"0x0","lines":["_raw_spin_unlock_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict_folios[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_shrink_lruvec[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"50000000"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["smpboot_thread_fn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"100000000"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"100000000"}],"period":"1000000000"} \ No newline at end of file diff --git a/pkg/test/integration/testdata/otel-ebpf-profile-offcpu.out.json b/pkg/test/integration/testdata/otel-ebpf-profile-offcpu.out.json new file mode 100644 index 0000000000..dc0726c2e5 --- /dev/null +++ b/pkg/test/integration/testdata/otel-ebpf-profile-offcpu.out.json @@ -0,0 +1 @@ +{"sample_types":[{"type":"off_cpu","unit":"nanoseconds"}],"samples":[{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_hrtimeout_range_clock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usleep_range_state[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pci_power_up[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pci_pm_power_up_and_verify_state[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pci_pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"12037294"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_ext_port_status[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_activate[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_interface.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"219508"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_tasks_wait_gp[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_tasks_one_gp[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_tasks_kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"12461808"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_kill_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_kill_anchored_urbs[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btusb_suspend[]@:0"],"mapping":"0x0-0x0@0x0 btusb(3498c7fb33302e816220ebd3cf073e2bed477bb3)"},{"address":"0x0","lines":["usb_suspend_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"503206"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread_worker_fn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"755212030"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_ext_port_status[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"26529"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_read_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_read_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_read_lock_root_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_csums_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["can_nocow_file_extent[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["run_delalloc_nocow[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writepage_delalloc[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_writepage[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_write_cache_pages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_single_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeback_sb_inodes[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_inodes_wb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_writeback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_workfn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"594880"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xa_erase[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__btrfs_release_delayed_node.part.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_evict_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["prune_icache_sb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["super_cache_scan[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_shrink_slab[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_slab_memcg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"184526"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_read_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_read_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_file_extent[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["run_delalloc_nocow[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writepage_delalloc[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_writepage[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_write_cache_pages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_single_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeback_sb_inodes[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_inodes_wb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_writeback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_workfn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"81836"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__mutex_lock.constprop.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["iwl_mvm_async_handlers_by_context[]@:0"],"mapping":"0x0-0x0@0x0 iwlmvm(dacb71a91d438f8f94e1aceee90bb36dc3c250ff)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"1124227"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["arch_tlbbatch_flush[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_unmap_flush_dirty[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_folio_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict_folios[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_shrink_lruvec[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"9500115"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["msleep[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"10894010"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_handle_usb2_port_link_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_get_usb2_port_status[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_get_port_status[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_hub_control[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rh_call_control[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_hcd_submit_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_ext_port_status[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"285800"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_hrtimeout_range_clock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usleep_range_state[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ex_system_do_sleep[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ex_opcode_1A_0T_0R[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ds_exec_end_op[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ps_parse_loop[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ps_parse_aml[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ps_execute_method[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ns_evaluate[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_ev_asynch_execute_gpe_method[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["acpi_os_execute_deferred[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"1053127"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_kill_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_quiesce[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_suspend_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_idle[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_idle[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"50136"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_write_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_write[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lock_root_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_csum[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_csum_file_blocks[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"403158"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["asm_sysvec_reschedule_ipi[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressSequences_bmi2.constprop.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressContinue.part.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressContinueStream[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ZSTD_decompressStream[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["zstd_decompress_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["end_bbio_compressed_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_check_read_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"49752"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_read_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_read_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_csum[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_csum_file_blocks[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"119948"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["asm_sysvec_apic_timer_interrupt[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["lzo1x_1_do_compress.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["lzogeneric1x_1_compress.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["lzorle1x_1_compress[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["zcomp_compress[]@:0"],"mapping":"0x0-0x0@0x0 zram(59cf195409a1d66353035caf4d262325c968df53)"},{"address":"0x0","lines":["zram_write_page[]@:0"],"mapping":"0x0-0x0@0x0 zram(59cf195409a1d66353035caf4d262325c968df53)"},{"address":"0x0","lines":["zram_bio_write[]@:0"],"mapping":"0x0-0x0@0x0 zram(59cf195409a1d66353035caf4d262325c968df53)"},{"address":"0x0","lines":["__submit_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__submit_bio_noacct[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["submit_bio_wait[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["swap_writepage_bdev_sync.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["swap_writeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_folio_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict_folios[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_shrink_lruvec[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"749193"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"15857"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__cond_resched_lock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["find_first_inode_to_shrink[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_extent_map_shrinker_worker[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"49990"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"122093226066"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_write_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_write[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_file_extent[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_drop_extents[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["insert_reserved_file_extent[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"94478"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["lru_add_drain_per_cpu[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"52127"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"90689"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_find_delalloc_range[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["find_lock_delalloc_range[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writepage_delalloc[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_writepage[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_write_cache_pages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_single_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeback_sb_inodes[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_inodes_wb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_writeback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_workfn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"50865"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["io_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["bit_wait_io[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__wait_on_bit[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["out_of_line_wait_on_bit[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["read_extent_buffer_pages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_read_extent_buffer[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["read_block_for_search[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_csum[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_csum_file_blocks[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"570685"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["asm_sysvec_apic_timer_interrupt[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__call_rcu_common.constprop.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__destroy_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["destroy_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["prune_icache_sb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["super_cache_scan[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_shrink_slab[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_slab_memcg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"217684"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__local_bh_enable_ip[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xts_encrypt_vaes_avx2[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["crypt_convert_block_skcipher[]@:0"],"mapping":"0x0-0x0@0x0 dm_crypt(21561265672356400f5c437db70e30f32ce12793)"},{"address":"0x0","lines":["crypt_convert[]@:0"],"mapping":"0x0-0x0@0x0 dm_crypt(21561265672356400f5c437db70e30f32ce12793)"},{"address":"0x0","lines":["kcryptd_crypt_write_convert[]@:0"],"mapping":"0x0-0x0@0x0 dm_crypt(21561265672356400f5c437db70e30f32ce12793)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"30150"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["asm_sysvec_reschedule_ipi[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["page_counter_try_charge[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__mem_cgroup_try_charge_swap[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["folio_alloc_swap[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_folio_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict_folios[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_shrink_lruvec[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"32769"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["zram_write_page[]@:0"],"mapping":"0x0-0x0@0x0 zram(59cf195409a1d66353035caf4d262325c968df53)"},{"address":"0x0","lines":["zram_bio_write[]@:0"],"mapping":"0x0-0x0@0x0 zram(59cf195409a1d66353035caf4d262325c968df53)"},{"address":"0x0","lines":["__submit_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__submit_bio_noacct[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["submit_bio_wait[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["swap_writepage_bdev_sync.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["swap_writeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_folio_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict_folios[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_shrink_lruvec[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"33734"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_tasks_kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"6073127"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["evict_folios[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["try_to_shrink_lruvec[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"813426"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["asm_sysvec_reschedule_ipi[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["mod_delayed_work_on[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kblockd_mod_delayed_work_on[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["blk_mq_dispatch_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["blk_mq_flush_plug_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__blk_flush_plug[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["io_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rq_qos_wait[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wbt_wait[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rq_qos_throttle[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["blk_mq_submit_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__submit_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["submit_bio_noacct_nocheck[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["dmcrypt_write[]@:0"],"mapping":"0x0-0x0@0x0 dm_crypt(21561265672356400f5c437db70e30f32ce12793)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"54036"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["inode_lru_isolate[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__list_lru_walk_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["list_lru_walk_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["prune_icache_sb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["super_cache_scan[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_shrink_slab[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_slab_memcg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_one[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_many[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["shrink_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["balance_pgdat[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"41216"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock_irqrestore[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["folio_wake_bit[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["end_bbio_data_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["end_bbio_compressed_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_check_read_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"133616"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_read_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_read_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_read_lock_root_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_file_extent[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_drop_extents[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["insert_reserved_file_extent[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"321807"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["msleep[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_hub_control[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rh_call_control[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_hcd_submit_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_suspend_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"11439084"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd_try_to_sleep[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"745175296"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["psi_rtpoll_worker[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"6863453910"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_suspend_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"157889"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_ext_port_status[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"38266"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock_irqrestore[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["mmio_invalidate_full[]@:0"],"mapping":"0x0-0x0@0x0 i915(7d1e6ccecce74adfe7950f5be10120f52c703b22)"},{"address":"0x0","lines":["intel_gt_invalidate_tlb_full[]@:0"],"mapping":"0x0-0x0@0x0 i915(7d1e6ccecce74adfe7950f5be10120f52c703b22)"},{"address":"0x0","lines":["__i915_gem_object_unset_pages[]@:0"],"mapping":"0x0-0x0@0x0 i915(7d1e6ccecce74adfe7950f5be10120f52c703b22)"},{"address":"0x0","lines":["__i915_gem_object_put_pages[]@:0"],"mapping":"0x0-0x0@0x0 i915(7d1e6ccecce74adfe7950f5be10120f52c703b22)"},{"address":"0x0","lines":["__i915_gem_object_pages_fini[]@:0"],"mapping":"0x0-0x0@0x0 i915(7d1e6ccecce74adfe7950f5be10120f52c703b22)"},{"address":"0x0","lines":["__i915_gem_free_objects.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 i915(7d1e6ccecce74adfe7950f5be10120f52c703b22)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"31028"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["css_rstat_flush[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["flush_memcg_stats_dwork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"328152"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["irq_wait_for_interrupt[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["irq_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"16682016951"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["msleep[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_activate[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_interface.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"20230083"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["synchronize_rcu_expedited_wait_once[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["synchronize_rcu_expedited_wait[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_exp_wait_wake[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread_worker_fn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"4586014"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["io_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rq_qos_wait[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wbt_wait[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rq_qos_throttle[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["blk_mq_submit_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__submit_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["submit_bio_noacct_nocheck[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["dmcrypt_write[]@:0"],"mapping":"0x0-0x0@0x0 dm_crypt(21561265672356400f5c437db70e30f32ce12793)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"6272090488"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_configure_endpoint[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_change_max_exit_latency[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_set_usb2_hardware_lpm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_enable_usb2_hardware_lpm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"113600"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["asm_sysvec_apic_timer_interrupt[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_compress_heuristic[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_run_delalloc_range[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writepage_delalloc[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_writepage[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_write_cache_pages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_single_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeback_sb_inodes[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_inodes_wb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_writeback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_workfn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"49209"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_stop_device.constprop.0.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_hub_control[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rh_call_control[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_hcd_submit_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_suspend_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"123489"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd_try_to_sleep[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kswapd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"657934680"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"16377"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kcompactd[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"856651918"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_gp_kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"3373188796"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_get_status[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["finish_port_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"379077"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__hci_cmd_sync_sk[]@:0"],"mapping":"0x0-0x0@0x0 bluetooth(6fef910a1cb65f1d918fdb79ce81d21d9b61138a)"},{"address":"0x0","lines":["__hci_cmd_sync_status_sk[]@:0"],"mapping":"0x0-0x0@0x0 bluetooth(6fef910a1cb65f1d918fdb79ce81d21d9b61138a)"},{"address":"0x0","lines":["hci_inquiry_sync[]@:0"],"mapping":"0x0-0x0@0x0 bluetooth(6fef910a1cb65f1d918fdb79ce81d21d9b61138a)"},{"address":"0x0","lines":["hci_cmd_sync_work[]@:0"],"mapping":"0x0-0x0@0x0 bluetooth(6fef910a1cb65f1d918fdb79ce81d21d9b61138a)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"1729162"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock_irqrestore[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["synchronize_rcu_normal[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_tasks_wait_gp[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_tasks_one_gp[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_tasks_kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"326564"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_disable_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["finish_port_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_resume_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_resume[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_autoresume_device[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_remote_wakeup[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"157715"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__flush_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__lru_add_drain_all[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["khugepaged[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"838591"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["iwl_trans_pcie_send_hcmd_sync[]@:0"],"mapping":"0x0-0x0@0x0 iwlwifi(26299ec240f9dc12fb2b744c611a93d1ec173b82)"},{"address":"0x0","lines":["iwl_trans_send_cmd[]@:0"],"mapping":"0x0-0x0@0x0 iwlwifi(26299ec240f9dc12fb2b744c611a93d1ec173b82)"},{"address":"0x0","lines":["iwl_mvm_send_cmd[]@:0"],"mapping":"0x0-0x0@0x0 iwlmvm(dacb71a91d438f8f94e1aceee90bb36dc3c250ff)"},{"address":"0x0","lines":["iwl_mvm_config_scan[]@:0"],"mapping":"0x0-0x0@0x0 iwlmvm(dacb71a91d438f8f94e1aceee90bb36dc3c250ff)"},{"address":"0x0","lines":["iwl_mvm_recalc_tcm[]@:0"],"mapping":"0x0-0x0@0x0 iwlmvm(dacb71a91d438f8f94e1aceee90bb36dc3c250ff)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"2173192"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["msleep[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["port_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_event[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"10479332"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["add_delayed_ref[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_free_tree_block[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_force_cow_block[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_cow_block[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_csum[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_csum_file_blocks[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"18121"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["smpboot_thread_fn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"91093413366"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["drm_atomic_helper_wait_for_flip_done[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["intel_atomic_commit_tail[]@:0"],"mapping":"0x0-0x0@0x0 i915(7d1e6ccecce74adfe7950f5be10120f52c703b22)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"290793507"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["io_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["folio_wait_bit_common[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_write_cache_pages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_single_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeback_sb_inodes[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_inodes_wb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_writeback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_workfn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"640135"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_hrtimeout_range_clock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usleep_range_state[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pci_set_low_power_state[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pci_set_power_state[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pci_finish_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pci_pm_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"11321881"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["iwl_trans_pcie_send_hcmd_sync[]@:0"],"mapping":"0x0-0x0@0x0 iwlwifi(26299ec240f9dc12fb2b744c611a93d1ec173b82)"},{"address":"0x0","lines":["iwl_trans_send_cmd[]@:0"],"mapping":"0x0-0x0@0x0 iwlwifi(26299ec240f9dc12fb2b744c611a93d1ec173b82)"},{"address":"0x0","lines":["iwl_mvm_request_system_statistics[]@:0"],"mapping":"0x0-0x0@0x0 iwlmvm(dacb71a91d438f8f94e1aceee90bb36dc3c250ff)"},{"address":"0x0","lines":["iwl_mvm_request_statistics[]@:0"],"mapping":"0x0-0x0@0x0 iwlmvm(dacb71a91d438f8f94e1aceee90bb36dc3c250ff)"},{"address":"0x0","lines":["iwl_mvm_recalc_tcm[]@:0"],"mapping":"0x0-0x0@0x0 iwlmvm(dacb71a91d438f8f94e1aceee90bb36dc3c250ff)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"625549"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_write_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_write[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["lock_extent_buffer_for_io[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btree_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_single_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeback_sb_inodes[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_inodes_wb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_writeback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_workfn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"69135"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_read_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_read_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_read_lock_root_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_csum[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_csum_file_blocks[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"403042"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_thunk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["_raw_spin_unlock[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_clear_extent_bit_changeset[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_finish_one_ordered[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_work_helper[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"20330"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_configure_endpoint[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_change_max_exit_latency[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["xhci_set_usb2_hardware_lpm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_disable_usb2_hardware_lpm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_port_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_generic_driver_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_suspend_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"19423"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["preempt_schedule_irq[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["asm_sysvec_apic_timer_interrupt[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["mempool_free_bulk[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["mempool_free[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["bio_free[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["end_bbio_compressed_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_check_read_bio[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"127526"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_gp_fqs_loop[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rcu_gp_kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"916429336"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_preempt_disabled[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rwsem_down_read_slowpath[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["down_read[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_tree_read_lock_nested[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_read_lock_root_node[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_search_slot[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_next_old_leaf[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_lookup_csums_list[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["can_nocow_file_extent[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["run_delalloc_nocow[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writepage_delalloc[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_writepage[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["extent_write_cache_pages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["btrfs_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["do_writepages[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_single_inode[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["writeback_sb_inodes[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__writeback_inodes_wb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_writeback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wb_workfn[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"345156"},{"locations":[{"address":"0x0","lines":["finish_task_switch.isra.0[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["schedule_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["wait_for_completion_timeout[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_start_wait_urb[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_control_msg[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["hub_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_suspend_both[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_callback[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["__pm_runtime_suspend[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["usb_runtime_idle[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["rpm_idle[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["pm_runtime_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["process_one_work[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["worker_thread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["kthread[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"},{"address":"0x0","lines":["ret_from_fork_asm[]@:0"],"mapping":"0x0-0x0@0x0 vmlinux(7b547e58a70dd26d821993906be478993a56599b)"}],"values":"31130"}],"period":"1"} \ No newline at end of file diff --git a/pkg/test/integration/testdata/otel-ebpf-profile.pb.bin b/pkg/test/integration/testdata/otel-ebpf-profile.pb.bin new file mode 100644 index 0000000000..b9b009b557 Binary files /dev/null and b/pkg/test/integration/testdata/otel-ebpf-profile.pb.bin differ diff --git a/pkg/test/integration/testdata/otel-ebpf-profile.pb.json b/pkg/test/integration/testdata/otel-ebpf-profile.pb.json new file mode 100644 index 0000000000..0495e2e1cf --- /dev/null +++ b/pkg/test/integration/testdata/otel-ebpf-profile.pb.json @@ -0,0 +1 @@ +{"resourceProfiles":[{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"66"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[4,5,6],"values":["806680624","807052076","451841649","183092582","83836990","226003802","187786634","80112779","59735903","98066686","50898058","43097036","247917426","47934039","364872305","114842675","232978992","872914215","35933275","148013352","121486043"],"timestampsUnixNano":["1774910497581596132","1774910498388697292","1774910498840563114","1774910499023705662","1774910499107588758","1774910499333661270","1774910499521489213","1774910499601684320","1774910499661518481","1774910499759632418","1774910499810577755","1774910499853714260","1774910500101672310","1774910500149695575","1774910500514616010","1774910500629541581","1774910500862533871","1774910501735519195","1774910501771487006","1774910501919526497","1774910502041031866"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2013966"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":2,"attributeIndices":[7,8,9],"values":["157715"],"timestampsUnixNano":["1774910498150387264"]},{"stackIndex":3,"attributeIndices":[7,8,9],"values":["10479332"],"timestampsUnixNano":["1774910498138611840"]},{"stackIndex":4,"attributeIndices":[7,8,9],"values":["10894010"],"timestampsUnixNano":["1774910498149686256"]},{"stackIndex":5,"attributeIndices":[7,8,9],"values":["113600"],"timestampsUnixNano":["1774910498150620505"]},{"stackIndex":6,"attributeIndices":[7,8,9],"values":["375577067","342007710","16785384","194873501","252989712","774299990","121628591","896975585","255879251","318970130","448924995","575047878"],"timestampsUnixNano":["1774910497785501202","1774910498127556068","1774910498167607347","1774910498362518928","1774910498615540699","1774910499389893116","1774910499511572241","1774910500408585067","1774910500664499758","1774910500983531661","1774910501432489476","1774910502007559993"]},{"stackIndex":7,"attributeIndices":[7,8,9],"values":["285800"],"timestampsUnixNano":["1774910498127905070"]},{"stackIndex":8,"attributeIndices":[7,8,9],"values":["26529"],"timestampsUnixNano":["1774910498128032157"]},{"stackIndex":9,"attributeIndices":[7,8,9],"values":["16377"],"timestampsUnixNano":["1774910498128096031"]},{"stackIndex":10,"attributeIndices":[7,8,9],"values":["38266"],"timestampsUnixNano":["1774910498138752921"]},{"stackIndex":11,"attributeIndices":[7,8,9],"values":["379077"],"timestampsUnixNano":["1774910498150148658"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1180"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":12,"attributeIndices":[10,11,12],"values":["2202999813","2085184","3000540690"],"timestampsUnixNano":["1774910497977260592","1774910497979531840","1774910500980181056"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"18"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":13,"attributeIndices":[13,14,15],"values":["91421","25607","3711","5599","13904","4403","4496","11267"],"timestampsUnixNano":["1774910500530518713","1774910502024611420","1774910502026628061","1774910502031913518","1774910502032846620","1774910502036041287","1774910502037730526","1774910502039352483"]},{"stackIndex":13,"attributeIndices":[13,14,16],"values":["7235","6459","6266","4876","10675","5532","6578","8027","7271","7048","12443","5550","5353","5849"],"timestampsUnixNano":["1774910500545239011","1774910500547141025","1774910500548650106","1774910500553739854","1774910500556685603","1774910500559204340","1774910500561176434","1774910500564337024","1774910500568229517","1774910500569808277","1774910501851111649","1774910501851450833","1774910501852020483","1774910501852785723"]},{"stackIndex":14,"attributeIndices":[13,14,12],"values":["2958796","14945411","6634894","5942752","555209","110740","20602517","3975689"],"timestampsUnixNano":["1774910500717701891","1774910500732681807","1774910500739355767","1774910500745363635","1774910500745967827","1774910500746109303","1774910500766731354","1774910500770758644"]},{"stackIndex":14,"attributeIndices":[13,14,17],"values":["1759495","2412449","1961036","2977417","1712169","1309215","948796","1131910","1862598","1307776","580960","704345","1499598","1256052","1007556","1321742","894724","1686079","2723970","703348","603793","881771","1365029","617119","9530936","9199663","969147","581786","1304553","1167496","620498","1214769","2348091"],"timestampsUnixNano":["1774910500592341974","1774910500594791216","1774910500596818721","1774910500599832364","1774910500601588564","1774910500602950943","1774910500603943251","1774910500605130377","1774910500607035929","1774910500608383610","1774910500609009656","1774910500609752997","1774910500611278982","1774910501854937759","1774910501855968530","1774910501857330119","1774910501858446113","1774910501860202300","1774910501862943957","1774910501863687850","1774910501864308793","1774910501865296688","1774910501866691808","1774910501867342001","1774910502002377571","1774910502011615534","1774910502012618290","1774910502013222450","1774910502014559257","1774910502015748631","1774910502016385232","1774910502017622388","1774910502019986213"]},{"stackIndex":13,"attributeIndices":[13,14,18],"values":["7263","8045","88438","6307","6507","48079"],"timestampsUnixNano":["1774910500851161374","1774910500853367691","1774910500854083171","1774910500854798875","1774910500855577430","1774910501827379965"]},{"stackIndex":14,"attributeIndices":[13,14,19],"values":["1090292","1828268","946742","362408","926983"],"timestampsUnixNano":["1774910500533429760","1774910501592721954","1774910501808805496","1774910501809202283","1774910501810181941"]},{"stackIndex":14,"attributeIndices":[13,14,20],"values":["901056","1013683","2931062","1689833","1692191","1670993","11780264","506160","1169096","885908","4950850","4438977","1108661","12710965","12332486","10376648","1732780","1416332","3956953","4495915","1043967","1556940","920722","1021726","459253","1139542","2194318","980273","2780140","2638111","3873137","17512305","3486716","399657","564192","701353","2518270","2410604","8843477","4140271","423257","3230359","23621923","7252961","754833","391956","526372","4164690","1177535","627891","1085008","1103710"],"timestampsUnixNano":["1774910500535425929","1774910500536466078","1774910500617721238","1774910500619450771","1774910500621183391","1774910500622898975","1774910500634718424","1774910500658176132","1774910500659418963","1774910500660387734","1774910500665404887","1774910500669947335","1774910500671101377","1774910500691842031","1774910500704216997","1774910500714675871","1774910500827129716","1774910500828588121","1774910500832575126","1774910500837114228","1774910500838210008","1774910500839837698","1774910500840805543","1774910501869939326","1774910501870436249","1774910501871598261","1774910501873817494","1774910501874829323","1774910501877636093","1774910501880317963","1774910501884221516","1774910501901802106","1774910501905342660","1774910501905791073","1774910501906400291","1774910501907142122","1774910501909885022","1774910501912325124","1774910501932514872","1774910501936702670","1774910501937161092","1774910501940419680","1774910501964074956","1774910501971410079","1774910501972202713","1774910501972630896","1774910501973191806","1774910502044427168","1774910502075487073","1774910502076160549","1774910502077298416","1774910502304517815"]},{"stackIndex":13,"attributeIndices":[13,14,21],"values":["7834","5428","4520","6954","8441","11793","4653","59423","146722","33331","28740","4581","4100","12068","7203","8273","27452","7348","47147","57161","5767","21574","13685","79398","11641","11037","23510","5811","5926","5399","164588","17298","19184"],"timestampsUnixNano":["1774910500466654562","1774910500470529815","1774910500471403135","1774910500483207531","1774910500484311256","1774910500485356148","1774910500489251956","1774910500497971590","1774910500499982001","1774910500520552437","1774910500529892610","1774910500790863510","1774910500796678556","1774910500856313261","1774910500858201251","1774910500860888277","1774910500862448959","1774910500862880101","1774910500863636768","1774910500864237003","1774910500867099423","1774910500868496538","1774910500872395555","1774910500878642851","1774910500879015154","1774910500881536409","1774910500882562426","1774910500885303173","1774910500886226315","1774910500887792971","1774910500889045435","1774910500889941993","1774910500891630564"]},{"stackIndex":14,"attributeIndices":[13,14,6],"values":["1789395","1383367","5360708","5502672","1714370","1594836","2932278"],"timestampsUnixNano":["1774910500588968670","1774910500777244516","1774910500782662809","1774910500788203230","1774910502293397418","1774910502295138150","1774910502298109466"]},{"stackIndex":14,"attributeIndices":[13,14,9],"values":["793217","294259","713103","1391548","381869","1413298","642910","956491","822658","695205","624062","170293","2282561","1908508","36310357","19224751"],"timestampsUnixNano":["1774910500773102043","1774910500773432857","1774910500822455626","1774910500842907604","1774910500843337561","1774910500844777419","1774910501811734275","1774910501812791601","1774910501813662135","1774910501814404789","1774910501815056242","1774910501815274148","1774910501817579839","1774910501819513953","1774910502173572933","1774910502192973770"]},{"stackIndex":13,"attributeIndices":[13,14,22],"values":["7878","9518","90372","131946","10784","8907","93189","74827","9443","39747","10096","5573","5709","6318","814604","7990","4314","49374","6832","26926"],"timestampsUnixNano":["1774910500671645264","1774910500808367365","1774910500817942920","1774910501758797198","1774910502046037455","1774910502046329200","1774910502061682288","1774910502072666885","1774910502072844360","1774910502086269747","1774910502093886175","1774910502094731706","1774910502096270753","1774910502122225047","1774910502134504643","1774910502198710044","1774910502205313100","1774910502245266365","1774910502258487148","1774910502275290445"]},{"stackIndex":13,"attributeIndices":[13,14,23],"values":["18248","18172","4952","36296","48086","14577","10581","12791","9301"],"timestampsUnixNano":["1774910500652525563","1774910501913543836","1774910501915761090","1774910501917276252","1774910501918417182","1774910501921504486","1774910501921965142","1774910501922878512","1774910502201745988"]},{"stackIndex":13,"attributeIndices":[13,14,19],"values":["7760","8290","226330","6230","23009","5728"],"timestampsUnixNano":["1774910500533460502","1774910501592756433","1774910501807835009","1774910501808830693","1774910501809245522","1774910501810197169"]},{"stackIndex":13,"attributeIndices":[13,14,20],"values":["19442","5721","11612","6858","7552","8807","7709","9171","23103","14265","22922","18534","24869","9111","8759","6947","4383","8614","20692","7768","10302","10551","114782","5998","5411","5074","5071","5251","11564","33506","12482","5607","11266","9169","4890","42981","4985","10989","7734","6790","5345","25215","6264","5881","5870","5016","9375","8889","10130","9210"],"timestampsUnixNano":["1774910500534512804","1774910500535445011","1774910500536508069","1774910500614774737","1774910500617751430","1774910500621218183","1774910500622928989","1774910500634763683","1774910500657650045","1774910500658233130","1774910500659486264","1774910500660438782","1774910500665487095","1774910500704283172","1774910500804108501","1774910500827160559","1774910500828610626","1774910500832607380","1774910500837155905","1774910500838267057","1774910500839874147","1774910500840836889","1774910501413407860","1774910501869965977","1774910501870451491","1774910501871614101","1774910501873841792","1774910501874848899","1774910501877671232","1774910501884279700","1774910501901842098","1774910501905381726","1774910501905827929","1774910501906432832","1774910501907359409","1774910501912403083","1774910501923663542","1774910501932552218","1774910501936727057","1774910501937180892","1774910501940443099","1774910501964144632","1774910501971437049","1774910501972230534","1774910501972657139","1774910501973206617","1774910502040242953","1774910502075521469","1774910502076203442","1774910502193763022"]},{"stackIndex":14,"attributeIndices":[13,14,21],"values":["23285030","3658790","169082","832457","7361169","4381351","1069599","1009502","3845397","4493779","2586795","1463961","1830811","20411400","7882773","1327863","3287995","2463855","959476","843832","2627442","1478781","385455","611098","465382","2827097","1255885","3791800","4548354","849747","672529","337163","2451571","967475","2702826","890566","1532553","810556","824005","1626892"],"timestampsUnixNano":["1774910500466612036","1774910500470322523","1774910500470513975","1774910500471369125","1774910500478773494","1774910500483178332","1774910500484285722","1774910500485327602","1774910500489209207","1774910500493753634","1774910500496380676","1774910500497863773","1774910500499813003","1774910500520414122","1774910500528445114","1774910500529809602","1774910500794168492","1774910500796652789","1774910500857286928","1774910500858165392","1774910500860837903","1774910500862382783","1774910500862852263","1774910500863559562","1774910500864117346","1774910500867076789","1774910500868398037","1774910500872296737","1774910500876953240","1774910500877830575","1774910500878545634","1774910500878990878","1774910500881475800","1774910500882517050","1774910500885276766","1774910500886201476","1774910500887766534","1774910500888610524","1774910500889889098","1774910500891582012"]},{"stackIndex":13,"attributeIndices":[13,14,6],"values":["6459","5749","5665","9840","5784","11814","96328","12364"],"timestampsUnixNano":["1774910500587154131","1774910500775844352","1774910500777292192","1774910500782692484","1774910500788234893","1774910501984756463","1774910502293528293","1774910502298143472"]},{"stackIndex":13,"attributeIndices":[13,14,9],"values":["8116","6668","5354","10905","8967","6358","3954","26058","5247","7584","4253","5106","4605","3742","4590","5637","102099"],"timestampsUnixNano":["1774910500772291170","1774910500773126226","1774910500773458386","1774910500841504150","1774910500842945717","1774910500843356779","1774910501811078738","1774910501811816254","1774910501812811845","1774910501813688087","1774910501814425782","1774910501815096732","1774910501815290768","1774910501817597275","1774910501819531747","1774910501975302961","1774910502173726423"]},{"stackIndex":14,"attributeIndices":[13,14,22],"values":["9436236","575593","243978","15217043","9467402","1346720","124133","7363307","176751","284250","511712","1487609","2022011","23866103","11377368","1762781","39833897","13170029","16721748"],"timestampsUnixNano":["1774910500817826518","1774910502045993828","1774910502046293244","1774910502061556941","1774910502071169540","1774910502072549328","1774910502072812061","1774910502093651914","1774910502093861488","1774910502094181061","1774910502094712465","1774910502096228058","1774910502098309718","1774910502122198938","1774910502133611472","1774910502198673572","1774910502245166217","1774910502258453306","1774910502275220715"]},{"stackIndex":14,"attributeIndices":[13,14,23],"values":["2188795","1441067","1063330","3038731","418209","865189"],"timestampsUnixNano":["1774910501915747101","1774910501917208727","1774910501918346353","1774910501921464173","1774910501921931173","1774910501922837330"]},{"stackIndex":14,"attributeIndices":[13,14,16],"values":["2396418","2273268","1860920","1474556","5054507","2900619","2482879","1937539","3122569","3849077","1510888","2796664","310551","544308","736339"],"timestampsUnixNano":["1774910500542905560","1774910500545205763","1774910500547111872","1774910500548626825","1774910500553713216","1774910500556648514","1774910500559177272","1774910500561149778","1774910500564307779","1774910500568199707","1774910500569751063","1774910501851074223","1774910501851433382","1774910501852003109","1774910501852763908"]},{"stackIndex":14,"attributeIndices":[13,14,18],"values":["7355891","2861389","2135297","586934","661751","576865","100913","5354061","3819205"],"timestampsUnixNano":["1774910500581279670","1774910500584201382","1774910500853319763","1774910500853968030","1774910500854762679","1774910500855387599","1774910500855546290","1774910501832753018","1774910501836604743"]},{"stackIndex":13,"attributeIndices":[13,14,12],"values":["5595","6025","20717","17045","5313","9936","6013"],"timestampsUnixNano":["1774910500717728672","1774910500732712257","1774910500739406018","1774910500745403446","1774910500746121672","1774910500766772305","1774910500770799926"]},{"stackIndex":13,"attributeIndices":[13,14,17],"values":["12318","6269","5906","5591","7271","6025","5748","5655","6019","5998","5856","8155","11910","10710","37630","6072","17273","3696","88307","4726","4910","3718","5280","5624","4548","8512","4447","3156","3285","2613","5562"],"timestampsUnixNano":["1774910500594844333","1774910500599868198","1774910500601634775","1774910500602987441","1774910500603988669","1774910500605162808","1774910500607066380","1774910500608419942","1774910500609039465","1774910500611308023","1774910501853669674","1774910501854955254","1774910501856003090","1774910501857546289","1774910501858507113","1774910501860215816","1774910501862975700","1774910501863698898","1774910501864408672","1774910501865321130","1774910501866719651","1774910501867369751","1774910502002408852","1774910502011641014","1774910502012633535","1774910502013248592","1774910502014575510","1774910502015759987","1774910502016402453","1774910502017633735","1774910502020015426"]},{"stackIndex":14,"attributeIndices":[13,14,15],"values":["1978278","2580302","1569991","1038230","886792","3152107","1652336","1568915"],"timestampsUnixNano":["1774910502026605940","1774910502029215805","1774910502030817347","1774910502031879051","1774910502032807996","1774910502036009311","1774910502037702464","1774910502039309281"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"278"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[24,25,22],"values":["342111321","1193445","423363","6186718","53336","43981","40912","34393","38686","40884","45580","40728","75244"],"timestampsUnixNano":["1774910502130132873","1774910502131348505","1774910502131801870","1774910502138004978","1774910502138078648","1774910502138134110","1774910502138189106","1774910502138236169","1774910502138284155","1774910502138333862","1774910502138390299","1774910502138440047","1774910502138525308"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"84"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[26,27,12],"values":["1696481157","827369948","1908228155","1845730366"],"timestampsUnixNano":["1774910497556094361","1774910498383494251","1774910500291735940","1774910502137497951"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2001"}},{"key":"process.executable.path","value":{"stringValue":"/usr/bin/containerd"}},{"key":"process.executable.name","value":{"stringValue":"containerd"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":15,"attributeIndices":[32,33,16],"values":["1071827","18687"],"timestampsUnixNano":["1774910502259306061","1774910502259374067"]},{"stackIndex":16,"attributeIndices":[32,34,9],"values":["1096723","30171306"],"timestampsUnixNano":["1774910502259344666","1774910502289544565"]},{"stackIndex":17,"attributeIndices":[32,33,12],"values":["24242","58063","799812"],"timestampsUnixNano":["1774910502288527949","1774910502288651214","1774910502289483097"]},{"stackIndex":18,"attributeIndices":[32,35,6],"values":["10099841"],"timestampsUnixNano":["1774910500616330581"]},{"stackIndex":18,"attributeIndices":[32,35,18],"values":["10058685","10179821","10075661","10053319","10152135","10063170","10053275"],"timestampsUnixNano":["1774910500952764136","1774910501268748162","1774910501289112129","1774910501625579659","1774910501962604872","1774910502267559716","1774910502299072161"]},{"stackIndex":16,"attributeIndices":[32,33,16],"values":["336420944","316941491","19317235","673412153","305596246"],"timestampsUnixNano":["1774910500942682671","1774910501259685182","1774910501279064400","1774910501952528833","1774910502258180606"]},{"stackIndex":15,"attributeIndices":[32,34,9],"values":["336248662","147877","315393373","1181503","108306","19092624","336853387","336320324","102281","304321452","1034664"],"timestampsUnixNano":["1774910500942508081","1774910500942809892","1774910501258245660","1774910501259517033","1774910501259776339","1774910501278911905","1774910501615890816","1774910501952381149","1774910501952619256","1774910502256985202","1774910502258116502"]},{"stackIndex":19,"attributeIndices":[32,35,18],"values":["305690974","10176574","326197524","326735199","294767299","21322916"],"timestampsUnixNano":["1774910501258520097","1774910501278992865","1774910501615415343","1774910501952396637","1774910502257451835","1774910502288952360"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2016425"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[36,37,12],"values":["2869017"],"timestampsUnixNano":["1774910502136485827"]},{"stackIndex":6,"attributeIndices":[36,37,6],"values":["23823","19500","24249","78593","49172","24291","18262","41152","38632","45767","28841"],"timestampsUnixNano":["1774910502137849114","1774910502137904339","1774910502137962690","1774910502138056786","1774910502138125973","1774910502138164018","1774910502138213167","1774910502138279164","1774910502138325540","1774910502138379619","1774910502138416115"]},{"stackIndex":6,"attributeIndices":[36,37,23],"values":["5929"],"timestampsUnixNano":["1774910502132529917"]},{"stackIndex":20,"attributeIndices":[36,37,20],"values":["127252"],"timestampsUnixNano":["1774910502131145673"]},{"stackIndex":21,"attributeIndices":[36,37,20],"values":["28408"],"timestampsUnixNano":["1774910502131524113"]},{"stackIndex":6,"attributeIndices":[36,37,20],"values":["10050","714997"],"timestampsUnixNano":["1774910502131590221","1774910502132345963"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019040"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[38,39,19],"values":["5554"],"timestampsUnixNano":["1774910502130923755"]},{"stackIndex":6,"attributeIndices":[38,39,17],"values":["6598","107878","35653"],"timestampsUnixNano":["1774910502132446734","1774910502132563285","1774910502133172191"]},{"stackIndex":22,"attributeIndices":[38,39,17],"values":["26686","20481"],"timestampsUnixNano":["1774910502133429147","1774910502133459520"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2017091"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[40,41,18],"values":["48089555","24881207","366893967","484035634","144429350","796845287","1004959316","19239015","266829093","126116200","583565072","46052371","575975102"],"timestampsUnixNano":["1774910497565581775","1774910497590500500","1774910497957424746","1774910498441788509","1774910498586258705","1774910499383520561","1774910500388495834","1774910500407755180","1774910500674619908","1774910500800757471","1774910501385491490","1774910501431564688","1774910502007562835"]},{"stackIndex":23,"attributeIndices":[40,41,18],"values":["259198","302083"],"timestampsUnixNano":["1774910497957718985","1774910498586619140"]},{"stackIndex":24,"attributeIndices":[40,41,18],"values":["1124227"],"timestampsUnixNano":["1774910500801896253"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2013473"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[46,47,16],"values":["171734411","29042132","741929127","1038906293","1006172505","971743817","52029862","10897785","565033358"],"timestampsUnixNano":["1774910497591488516","1774910497620555119","1774910498362515753","1774910499401511418","1774910500407713312","1774910501379507115","1774910501431561280","1774910501442480970","1774910502007558253"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2012063"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[48,49,22],"values":["186013364","102155219","31773001","384013252","337907432","45771272","40056079","23808921","851951805","299909707","448027696","256135876","127814376","834834091","76019496","241879701","319008186","128846750"],"timestampsUnixNano":["1774910497585588129","1774910497687812969","1774910497719621910","1774910498103697246","1774910498441723427","1774910498487526556","1774910498527621398","1774910498551534707","1774910499403530735","1774910499703494843","1774910500151555870","1774910500407769968","1774910500535621863","1774910501370483097","1774910501446518684","1774910501688504875","1774910502007563678","1774910502136918282"]},{"stackIndex":25,"attributeIndices":[48,49,22],"values":["52127"],"timestampsUnixNano":["1774910502008033164"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019042"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[50,51,6],"values":["2012449450","2773210705","1188155","3576227"],"timestampsUnixNano":["1774910497885256050","1774910500658503265","1774910500659717267","1774910500663317322"]},{"stackIndex":6,"attributeIndices":[50,51,16],"values":["24625","11942","5820","5149","28170"],"timestampsUnixNano":["1774910502130038350","1774910502130708156","1774910502130797554","1774910502130812429","1774910502130863255"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"48"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[52,53,19],"values":["48599164","82027174","37068493","674956110","190037618","82910899","53902943","6099855","252202338","237594861","256019142","764277","35071690","61003315","839884028","65824589","226958456","311927569","90978373","95998607","541650440","96235131","111980673","12913352","81967043","100623844"],"timestampsUnixNano":["1774910497593287802","1774910497675367467","1774910497712516233","1774910498387520620","1774910498577598368","1774910498660552018","1774910498714503822","1774910498720644933","1774910498972900545","1774910499210547538","1774910499466626394","1774910499467458752","1774910499502614496","1774910499563664618","1774910500403628285","1774910500469513218","1774910500696498885","1774910501008494562","1774910501099498541","1774910501195535930","1774910501737229101","1774910501833498466","1774910501945522766","1774910501958495930","1774910502040494647","1774910502141147202"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2013430"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[54,55,12],"values":["825983850","206766268","927727511","16749907","697848571","400739644","317907931","567779929","62971221","492118763"],"timestampsUnixNano":["1774910498231642290","1774910498438500599","1774910499366277172","1774910499383546425","1774910500081436288","1774910500482479238","1774910500800397911","1774910501369494619","1774910501432481263","1774910501924614393"]},{"stackIndex":23,"attributeIndices":[54,55,12],"values":["438689","205531","565204","402487"],"timestampsUnixNano":["1774910499366763311","1774910500081688845","1774910500801687782","1774910501925041441"]},{"stackIndex":26,"attributeIndices":[54,55,12],"values":["625549"],"timestampsUnixNano":["1774910500801060466"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"118"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":132,"unitStrindex":133},"samples":[{"stackIndex":27,"attributeIndices":[56,57,12],"timestampsUnixNano":["1774910501461234984"]},{"stackIndex":28,"attributeIndices":[56,57,12],"timestampsUnixNano":["1774910501761222030"]},{"stackIndex":29,"attributeIndices":[56,57,22],"timestampsUnixNano":["1774910502311353261"]},{"stackIndex":30,"attributeIndices":[56,57,12],"timestampsUnixNano":["1774910501411223329"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{"typeStrindex":131,"unitStrindex":2},"period":"50000000"},{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":31,"attributeIndices":[56,57,12],"values":["217684"],"timestampsUnixNano":["1774910501436703426"]},{"stackIndex":32,"attributeIndices":[56,57,21],"values":["31265363"],"timestampsUnixNano":["1774910502173073390"]},{"stackIndex":33,"attributeIndices":[56,57,21],"values":["50840"],"timestampsUnixNano":["1774910502188536100"]},{"stackIndex":34,"attributeIndices":[56,57,21],"values":["33734"],"timestampsUnixNano":["1774910502192525145"]},{"stackIndex":32,"attributeIndices":[56,57,23],"values":["26629391"],"timestampsUnixNano":["1774910500678960982"]},{"stackIndex":35,"attributeIndices":[56,57,17],"values":["71238"],"timestampsUnixNano":["1774910500699256970"]},{"stackIndex":35,"attributeIndices":[56,57,12],"values":["742188"],"timestampsUnixNano":["1774910501447283951"]},{"stackIndex":36,"attributeIndices":[56,57,12],"values":["384982"],"timestampsUnixNano":["1774910501450875182"]},{"stackIndex":37,"attributeIndices":[56,57,22],"values":["41216"],"timestampsUnixNano":["1774910502193533702"]},{"stackIndex":32,"attributeIndices":[56,57,12],"values":["83881152","20196180","104429132","105873737","52259158","38680811","30063111","28555435","10405440","9387801","77425368","17239255"],"timestampsUnixNano":["1774910500634445430","1774910500817616652","1774910500927570552","1774910501583514377","1774910501827147139","1774910501884036794","1774910501932368098","1774910501963823703","1774910501992715890","1774910502002196569","1774910502085951440","1774910502121867123"]},{"stackIndex":38,"attributeIndices":[56,57,12],"values":["483431051","174503629"],"timestampsUnixNano":["1774910501411025092","1774910501758041018"]},{"stackIndex":32,"attributeIndices":[56,57,15],"values":["19953655"],"timestampsUnixNano":["1774910502274739308"]},{"stackIndex":39,"attributeIndices":[56,57,22],"values":["9116796","313555","19256"],"timestampsUnixNano":["1774910502301869033","1774910502303443920","1774910502306213395"]},{"stackIndex":40,"attributeIndices":[56,57,22],"values":["32769"],"timestampsUnixNano":["1774910502305972988"]},{"stackIndex":41,"attributeIndices":[56,57,22],"values":["184526"],"timestampsUnixNano":["1774910502193834019"]},{"stackIndex":42,"attributeIndices":[56,57,22],"values":["313371"],"timestampsUnixNano":["1774910500686847708"]},{"stackIndex":32,"attributeIndices":[56,57,22],"values":["4013400","34910150","7154337","42852420"],"timestampsUnixNano":["1774910500691777646","1774910500739220603","1774910502201590729","1774910502244557717"]},{"stackIndex":39,"attributeIndices":[56,57,15],"values":["31628"],"timestampsUnixNano":["1774910500773867061"]},{"stackIndex":39,"attributeIndices":[56,57,12],"values":["18880"],"timestampsUnixNano":["1774910501432496508"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2009007"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[60,61,12],"values":["7460"],"timestampsUnixNano":["1774910502132553889"]},{"stackIndex":6,"attributeIndices":[60,61,21],"values":["185270"],"timestampsUnixNano":["1774910502135099266"]},{"stackIndex":6,"attributeIndices":[60,61,18],"values":["13664","10183","14920","25489","5755","13994","83967"],"timestampsUnixNano":["1774910502133802366","1774910502133879791","1774910502133927679","1774910502133963715","1774910502134005524","1774910502134054979","1774910502134149263"]},{"stackIndex":6,"attributeIndices":[60,61,19],"values":["108034"],"timestampsUnixNano":["1774910502131415812"]},{"stackIndex":6,"attributeIndices":[60,61,22],"values":["5936","6171","4870"],"timestampsUnixNano":["1774910502134341146","1774910502134415767","1774910502134429500"]},{"stackIndex":21,"attributeIndices":[60,61,12],"values":["235936"],"timestampsUnixNano":["1774910502132466591"]},{"stackIndex":43,"attributeIndices":[60,61,12],"values":["29983"],"timestampsUnixNano":["1774910502132523039"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"15"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[62,63,17],"values":["148961942","194141155","82772741","299028846","27935026","66934822","188974342","189938346","2983672","28002272","11004862","90203608","905684681","115002428","987288","473904915","53209166","267758209","22183151","179617338","98944804","138049242","138906825","16967370","1076761","144894455","338972541","73986261","17970347","67969636","61001733","1943152","163038926","18935041","2980940","13030632","13971308","14907915"],"timestampsUnixNano":["1774910497691584598","1774910497885752176","1774910497968570062","1774910498267626399","1774910498295593896","1774910498362543469","1774910498551547815","1774910498741499287","1774910498744502744","1774910498772525517","1774910498783585538","1774910498873802199","1774910499779511108","1774910499894521314","1774910499895523860","1774910500369509071","1774910500422747792","1774910500690532576","1774910500712725110","1774910500892548568","1774910500991510683","1774910501129574101","1774910501268520217","1774910501285499727","1774910501286594648","1774910501431505515","1774910501770502668","1774910501844499120","1774910501862487111","1774910501930548523","1774910501991559601","1774910501993522833","1774910502156566249","1774910502175520107","1774910502178510778","1774910502191551241","1774910502205551669","1774910502220484868"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2018339"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[64,65,17],"values":["42961452","45962186","254610623","293899028","127869271","146085411","45816869","63918031","191962682","383997043","262052114","121766706","255946720","384906421","127002568","127925328","64906079","62844540","131010645","32632771","7259520","9088463","459703942","128030032","63966724","63981041","65914948","254061094","63956622","191950406","127905643","65015841"],"timestampsUnixNano":["1774910497570548796","1774910497616542796","1774910497871191804","1774910498167608702","1774910498295532227","1774910498441674857","1774910498487537905","1774910498551504252","1774910498743507705","1774910499127542234","1774910499389633040","1774910499511532586","1774910499767537772","1774910500152494745","1774910500279543244","1774910500407554505","1774910500472614565","1774910500535480144","1774910500666510379","1774910500699188744","1774910500706515152","1774910500715760417","1774910501175487871","1774910501303535209","1774910501367536482","1774910501431531761","1774910501497478735","1774910501751564974","1774910501815550598","1774910502007528813","1774910502135487997","1774910502200525225"]},{"stackIndex":44,"attributeIndices":[64,65,17],"values":["1053127"],"timestampsUnixNano":["1774910497873132830"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019079"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[66,67,18],"values":["255341"],"timestampsUnixNano":["1774910498151841246"]},{"stackIndex":45,"attributeIndices":[66,67,18],"values":["1729162"],"timestampsUnixNano":["1774910498153606542"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"271"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[70,71,20],"values":["936485857","946906905","17203566","16326730","16707741","16437622","16312887","17055550","1165917142","16672012","16495353","16562649","16635713","16780262","16654957","16452652","699952234","16597573","16636430","16744434","16581774","16757630","16605788","16666018","16637115","16601454","16578684","16662854","16545438","16547539","16742977","16597318","233060163","198013214","71157","50025","55271","58298","59916","2182884","52710","45781","43095","41721","42883","42145","40316","40403","41452","44948","68114","39058","42806","44149","41613","47835","59472","176577"],"timestampsUnixNano":["1774910498424814658","1774910499371773096","1774910499389008932","1774910499405395191","1774910499422164231","1774910499438655775","1774910499455013948","1774910499472109146","1774910500638083431","1774910500654803163","1774910500671354699","1774910500687964053","1774910500704629382","1774910500721445559","1774910500738148737","1774910500754644197","1774910501454632607","1774910501471277175","1774910501487953020","1774910501504733028","1774910501521366282","1774910501538152003","1774910501554800012","1774910501571528293","1774910501588207735","1774910501604852866","1774910501621484804","1774910501638196444","1774910501654804889","1774910501671402073","1774910501688198165","1774910501704860392","1774910501937969073","1774910502136019328","1774910502136116330","1774910502136180308","1774910502136247666","1774910502136316922","1774910502136387765","1774910502138584966","1774910502138656620","1774910502138715393","1774910502138770067","1774910502138821632","1774910502138875237","1774910502138928649","1774910502138978294","1774910502139028170","1774910502139079116","1774910502139136490","1774910502139214996","1774910502139264336","1774910502139316795","1774910502139370732","1774910502139421816","1774910502139480269","1774910502139549914","1774910502139736231"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"3066"}},{"key":"process.executable.path","value":{"stringValue":"/usr/bin/kwin_wayland"}},{"key":"process.executable.name","value":{"stringValue":"kwin_wayland"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":46,"attributeIndices":[72,73,22],"values":["24871"],"timestampsUnixNano":["1774910500836582544"]},{"stackIndex":47,"attributeIndices":[74,75,23],"values":["30442"],"timestampsUnixNano":["1774910502104736389"]},{"stackIndex":48,"attributeIndices":[72,73,22],"values":["12775717","12558012","13334299","12723660","12702495","13792757","12646817","12624013","13870644","12161189","12692787","13833479","12289279","12647104","14013743","12391964","12774659","13676642","13998078","12703945","12942493","13676248","12517915","12885006","13611299","12434499","12593855","13450728","10305311","12665318","11484860","11175147","12711849","11446030","10574410","12583470","13655148","13344616","11431611","11362643","12612891","11667987","12171543","12495860","11343196","11805335","13098658","12757316","11592980","11449997","12462924","11428391","11275881","12096185","10832305","10173432","11186067","11445832","10555306","10955421","11903291","11589624","11715323","12675511","11348253","11941892","12366053","11994811","10819428","11008269","12009516","11149932","11257346","12145224","10728891","10380081","11697024","11870156","10425954","10650800","9565623","10496967","11772234","11559282","10463091","10643398","11055907","13802920","12704297","13604125","13168283","13226967","14295053","13845569","13056179"],"timestampsUnixNano":["1774910500736574184","1774910500753283653","1774910500769809054","1774910500786510092","1774910500803173458","1774910500819844544","1774910500836513687","1774910500853219409","1774910500869856493","1774910500886445493","1774910500903150624","1774910500919812776","1774910500936569928","1774910500953151486","1774910500969825805","1774910500986526276","1774910501003234318","1774910501019882890","1774910501036533787","1774910501053237374","1774910501069850591","1774910501086512539","1774910501103211567","1774910501119890202","1774910501136538950","1774910501153179756","1774910501169853748","1774910501186545572","1774910501203194412","1774910501219837650","1774910501236502058","1774910501253213335","1774910501269852029","1774910501286527172","1774910501303217825","1774910501319870693","1774910501336601840","1774910501353160443","1774910501369854102","1774910501386493030","1774910501403169736","1774910501419863634","1774910501436542799","1774910501453217219","1774910501469884202","1774910501486543033","1774910501503250443","1774910501519889288","1774910501536606472","1774910501553254892","1774910501569924314","1774910501586531170","1774910501603261529","1774910501619765414","1774910501636574911","1774910501653053794","1774910501669792868","1774910501686387038","1774910501703057047","1774910501719747541","1774910501736490585","1774910501753120642","1774910501769786591","1774910501786481437","1774910501803136885","1774910501819808097","1774910501836506106","1774910501853174613","1774910501869845413","1774910501886508696","1774910501903197041","1774910501919870409","1774910501936536967","1774910501953228525","1774910501969889784","1774910501986553079","1774910502003241089","1774910502019899511","1774910502036569433","1774910502053232737","1774910502069850848","1774910502086525527","1774910502103207732","1774910502119873043","1774910502136558147","1774910502153225453","1774910502169808641","1774910502186480489","1774910502203137928","1774910502219831998","1774910502236501089","1774910502253154465","1774910502269866596","1774910502286510565","1774910502303135831"]},{"stackIndex":49,"attributeIndices":[72,73,22],"values":["3814894","2740405","3657131","3624217","2438518","3715373","3716874","2431250","3924453","3590456","2477668","4158605","3596542","2298459","4010583","3617853","2611907","2211551","3693275","3378519","2642262","3784955","3513930","2563180","3896806","3714661","2888486","5906589","3631671","4751563","5190202","3626526","4870462","5659653","3665306","2767687","2767951","4981415","4963426","3777181","4844424","4236278","3836989","4950277","4520391","3337468","3535980","4827803","4941859","3768735","4912383","5133223","3951361","5631898","5828741","5228160","4804420","5627358","5393093","4476942","4718166","4684443","3648177","4871549","4415015","4024336","4308219","5514250","5363935","4295466","5300598","5139616","4249157","5614346","5929017","4611806","4446577","5960920","5691457","6617691","5866661","4597244","4732859","6004120","5634242","5026071","2376109","144272","3239289","235991","2550307","149961","3150347","2857516","124466","1935750","180234","2234317","171207","2895136","212615","2503872","225603"],"timestampsUnixNano":["1774910500740691833","1774910500756422345","1774910500773746738","1774910500790438736","1774910500805996760","1774910500823826348","1774910500840566649","1774910500855950164","1774910500874247136","1774910500890413892","1774910500905931993","1774910500924244100","1774910500940466269","1774910500955759918","1774910500974099488","1774910500990428993","1774910501006174556","1774910501022489708","1774910501040474669","1774910501056871602","1774910501072789380","1774910501090644998","1774910501106972607","1774910501122832835","1774910501140700127","1774910501157224638","1774910501173061444","1774910501192850650","1774910501207128449","1774910501224987586","1774910501241999192","1774910501257091507","1774910501275031108","1774910501292603408","1774910501307231466","1774910501322913280","1774910501339737320","1774910501358369095","1774910501375093146","1774910501390531295","1774910501408170579","1774910501424341800","1774910501440687222","1774910501458499637","1774910501474702980","1774910501490116833","1774910501507088508","1774910501524964898","1774910501541776870","1774910501557406721","1774910501575057554","1774910501591948463","1774910501607601500","1774910501625706174","1774910501642832888","1774910501658569304","1774910501674907432","1774910501692455720","1774910501708754394","1774910501724527693","1774910501741499229","1774910501758036333","1774910501773770769","1774910501791759515","1774910501807839949","1774910501824106944","1774910501841148913","1774910501858994511","1774910501875465292","1774910501891156410","1774910501908699517","1774910501925256895","1774910501941058500","1774910501959126709","1774910501976139820","1774910501991502249","1774910502007988509","1774910502026042423","1774910502042544577","1774910502060247104","1774910502075998121","1774910502091398657","1774910502108272751","1774910502126070900","1774910502142548126","1774910502158695196","1774910502172463645","1774910502172652683","1774910502190083093","1774910502190396942","1774910502206020639","1774910502206203732","1774910502223300619","1774910502239741740","1774910502239902901","1774910502255339157","1774910502255548870","1774910502272422831","1774910502272639916","1774910502289816081","1774910502290056362","1774910502305944561","1774910502306196224"]},{"stackIndex":50,"attributeIndices":[74,75,23],"values":["12747508","998207","256933","3739578","8380532","631009","13194901","913590","133510","12646359","917380","108478","4863534","7434504","849526","13669955","943619","157537","12543017","1049236","209360","12245503","1128683","134111","7436051","6010434","830586","172194","12210831","857380","246313","12761215","612879","177784","8048907","5024027","1114387","236531","12176504","919751","213031","12549309","833623","271032","9001235","4332101","1096059","123773","12416462","956861","164879","12807902","840627","109470","9021542","4274724","820317","241377","3312858","9895695","993424","197059","12571240","1005558","162023","9079483","3266234","1118266","203776","3943138","9136100","983723","279827","12344473","1002762","191475","9171937","3250992","829751","247916","3949976","8899022","965363","135473","12481623","903999","111846","12598637","965386","232581","1394984","2332766","7204057","1318879","945740","144069","10168279","970457","158574","9743598","2267582","996955","977594","159733","5540205","5576890","1045299","982490","11031935","1060370","117337","12721914","843476","1019829","172983","305295","10994703","809451","791610","160903","10471025","804473","233320","12469602","1043748","202820","5922496","7354876","810565","21834","13196458","1082942","1012921","171540","11384039","1135340","985406","210314","5566176","5360855","1105376","995923","330058","134389","11861697","1252994","997027","169847","11498009","961601","991905","123426","12074546","873847","232338","979449","133715","7859272","4101693","897847","989514","120579","11208475","925935","987724","119731","11710255","1053104","986540","79339","8371472","4512079","868598","993940","205605","2017176","10024756","1001185","1034543","180811","11516138","1035871","1085047","183091","4912825","6209510","803663","985680","12333451","1110873","1001651","157117","11382979","1125792","1077698","165031","10079928","873363","883045","1049933","243679","4894700","6432381","1070281","989729","204705","4850810","5665558","826425","991757","10085460","1122628","999480","198926","11143480","501944","55843","1108684","192534","9829889","1050030","1105495","1046174","152062","10526365","1172169","1026110","210923","10909125","1157836","283568","985232","221604","7813703","3406295","1192730","988184","197061","11462920","1255505","1011974","133647","11748062","882185","990215","139345","2641344","9911851","99598","244117","1009677","105179","11279727","1011138","990960","162569","11866323","1162612","993185","148700","12364153","620602","1989088","131804","5891024","5572004","998279","1994143","106957","10737581","1070382","1994772","141849","10172207","338688","949798","1988728","119161","5080457","6538414","1110940","1990837","57234","11142479","1055108","2008985","91411","11234510","63381","719199","2035984","122076","6355296","5320237","947328","1992583","132033","10699689","766090","1986705","124319","10195205","827064","1993608","116331","5491579","5831956","924518","1983888","11763477","1129283","1998841","181261","10390300","903453","2029437","217428","3432480","6860873","856714","1987119","141934","9457266","1031774","2047045","149492","10453792","868318","1982147","89785","4822119","6724236","915268","1996371","11357001","1084617","1991304","94302","10470285","730891","1996157","10723803","670408","10958382","80355","4980420","8605228","12727444","64854","13499490","873123","206251","10590883","1870731","158261","12996092","89218","11341956","2749295","174456","8126152","5073352","35383","12991080","16374"],"timestampsUnixNano":["1774910500736900107","1774910500738079831","1774910500741018320","1774910500744947631","1774910500753721423","1774910500754593898","1774910500770109996","1774910500771247642","1774910500774014983","1774910500786836204","1774910500787914564","1774910500790684480","1774910500795740953","1774910500803552196","1774910500804592527","1774910500820136623","1774910500821237443","1774910500824136235","1774910500836879632","1774910500838060293","1774910500840815676","1774910500853213539","1774910500854726780","1774910500856219484","1774910500863838570","1774910500870378090","1774910500871432035","1774910500874509273","1774910500886886102","1774910500887942960","1774910500890704645","1774910500903642397","1774910500904652157","1774910500906183267","1774910500914388294","1774910500920121299","1774910500921432467","1774910500924559054","1774910500936928146","1774910500938032259","1774910500940753009","1774910500953456797","1774910500954502557","1774910500956090565","1774910500965262533","1774910500970138753","1774910500971434750","1774910500974291857","1774910500986851312","1774910500987999785","1774910500990649919","1774910501003614426","1774910501004671507","1774910501006402258","1774910501015597500","1774910501020253594","1774910501021260766","1774910501022797602","1774910501026308603","1774910501036835313","1774910501038013028","1774910501040774768","1774910501053500059","1774910501054717232","1774910501057122790","1774910501066363342","1774910501070187481","1774910501071416794","1774910501073122897","1774910501077253679","1774910501086895181","1774910501088057063","1774910501090994687","1774910501103503333","1774910501104682083","1774910501107226435","1774910501116537491","1774910501120310151","1774910501121355861","1774910501123215765","1774910501127351850","1774910501136864486","1774910501138010083","1774910501140929861","1774910501153569486","1774910501154690450","1774910501157448123","1774910501170203343","1774910501171367974","1774910501173249819","1774910501174794472","1774910501177464522","1774910501185141463","1774910501186979638","1774910501188149730","1774910501193066213","1774910501203399200","1774910501204704818","1774910501207432292","1774910501217380003","1774910501220272047","1774910501221407841","1774910501222627867","1774910501225266744","1774910501230965330","1774910501236866459","1774910501238056561","1774910501239253866","1774910501253505732","1774910501254743095","1774910501257281229","1774910501270154997","1774910501271249028","1774910501272491039","1774910501275272154","1774910501275743493","1774910501286931125","1774910501287995576","1774910501289067159","1774910501292920648","1774910501303619066","1774910501304633256","1774910501307543100","1774910501320180714","1774910501321400572","1774910501323156454","1774910501329223270","1774910501337012105","1774910501338065353","1774910501340064771","1774910501353424066","1774910501354690092","1774910501356023894","1774910501358615842","1774910501370153407","1774910501371462956","1774910501372775869","1774910501375364031","1774910501381093492","1774910501386778054","1774910501388060695","1774910501389235079","1774910501390990658","1774910501391308412","1774910501403374136","1774910501404729584","1774910501405861620","1774910501408448210","1774910501420098783","1774910501421241483","1774910501422369072","1774910501424577824","1774910501436837296","1774910501437909052","1774910501438369089","1774910501439598332","1774910501440937094","1774910501448997240","1774910501453539574","1774910501454565541","1774910501455761491","1774910501458761358","1774910501470173211","1774910501471225507","1774910501472381830","1774910501474918751","1774910501486771204","1774910501487907874","1774910501489033578","1774910501490278306","1774910501498775283","1774910501503593674","1774910501504650121","1774910501506005791","1774910501507351690","1774910501509541418","1774910501520121171","1774910501521293617","1774910501522492368","1774910501525217413","1774910501536880066","1774910501538082453","1774910501539471696","1774910501542074081","1774910501547150546","1774910501553667852","1774910501554710658","1774910501556111032","1774910501570175533","1774910501571457632","1774910501572751818","1774910501575294611","1774910501586836296","1774910501588131165","1774910501589532488","1774910501592186088","1774910501602409713","1774910501603701297","1774910501604778162","1774910501606208512","1774910501607935613","1774910501613038106","1774910501620114335","1774910501621391112","1774910501622777885","1774910501625994397","1774910501631023449","1774910501637048297","1774910501638094580","1774910501639543516","1774910501653376381","1774910501654719786","1774910501656072420","1774910501658832122","1774910501670138776","1774910501670833235","1774910501671288952","1774910501672571121","1774910501675164086","1774910501685160586","1774910501686823514","1774910501688084042","1774910501689588604","1774910501692705175","1774910501703394046","1774910501704786725","1774910501706146266","1774910501709016812","1774910501720089806","1774910501721435492","1774910501722063477","1774910501723428950","1774910501724834064","1774910501732803892","1774910501736796427","1774910501738070824","1774910501739213139","1774910501741790928","1774910501753396501","1774910501754767888","1774910501756037007","1774910501758218662","1774910501770113539","1774910501771222624","1774910501772423298","1774910501774017660","1774910501776834775","1774910501786884129","1774910501787279853","1774910501787901245","1774910501789109679","1774910501791998388","1774910501803419162","1774910501804567800","1774910501805695109","1774910501808114668","1774910501820113298","1774910501821412902","1774910501822722953","1774910501824321721","1774910501836830648","1774910501837891100","1774910501840089558","1774910501841387202","1774910501847456700","1774910501853469630","1774910501854555295","1774910501856686658","1774910501859200878","1774910501870086413","1774910501871249220","1774910501873375078","1774910501875711951","1774910501886046937","1774910501886826628","1774910501887888661","1774910501890080143","1774910501891378853","1774910501896615170","1774910501903392601","1774910501904549001","1774910501906642614","1774910501908844748","1774910501920104018","1774910501921223428","1774910501923340340","1774910501925432419","1774910501936806238","1774910501937044322","1774910501937951997","1774910501940154073","1774910501941276548","1774910501947766645","1774910501953551596","1774910501954603628","1774910501956774773","1774910501959346013","1774910501970210362","1774910501971224067","1774910501973394229","1774910501976424398","1774910501986883667","1774910501987884808","1774910501990098954","1774910501991741347","1774910501997394492","1774910502003532798","1774910502004563599","1774910502006715149","1774910502020122230","1774910502021331912","1774910502023623199","1774910502026339826","1774910502036896752","1774910502037982545","1774910502040210823","1774910502042830965","1774910502046444183","1774910502053608975","1774910502054622414","1774910502056828587","1774910502060526932","1774910502070154049","1774910502071316885","1774910502073656091","1774910502076210214","1774910502086802398","1774910502087888113","1774910502090082340","1774910502091607976","1774910502096604554","1774910502103518712","1774910502104563845","1774910502106778653","1774910502120059935","1774910502121221306","1774910502123343599","1774910502126281257","1774910502136910053","1774910502137882201","1774910502140090200","1774910502153723000","1774910502154601215","1774910502170083956","1774910502172759097","1774910502177866887","1774910502186836782","1774910502203463285","1774910502206292991","1774910502219934916","1774910502221219893","1774910502223602158","1774910502234346790","1774910502236877205","1774910502240088437","1774910502253232366","1774910502255662266","1774910502267141906","1774910502270215937","1774910502272841242","1774910502281132972","1774910502286917254","1774910502290137250","1774910502303287109","1774910502306254998"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"757"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":51,"attributeIndices":[78,79,15],"values":["94602"],"timestampsUnixNano":["1774910502131183242"]},{"stackIndex":51,"attributeIndices":[78,79,17],"values":["410557","721022","726551","86192","49588","54521","48052","44324","169525","604744","31130","30625","24908","28560"],"timestampsUnixNano":["1774910502133566760","1774910502134325089","1774910502135084326","1774910502135203127","1774910502135273216","1774910502136691975","1774910502136755054","1774910502136812315","1774910502137042081","1774910502137686565","1774910502139583847","1774910502139632050","1774910502139666826","1774910502139773446"]},{"stackIndex":51,"attributeIndices":[78,79,22],"values":["417797","52281","39020","39897","31976","32950","33053","41920","33898","67231"],"timestampsUnixNano":["1774910502131764927","1774910502138054681","1774910502138116008","1774910502138172586","1774910502138219695","1774910502138267624","1774910502138315763","1774910502138373930","1774910502138422785","1774910502138505908"]},{"stackIndex":51,"attributeIndices":[78,79,21],"values":["109052","100855","50103","61067","38642","105476"],"timestampsUnixNano":["1774910502135504822","1774910502135628580","1774910502135691424","1774910502135766386","1774910502135819973","1774910502135938086"]},{"stackIndex":52,"attributeIndices":[78,79,17],"values":["54036"],"timestampsUnixNano":["1774910502139735147"]},{"stackIndex":51,"attributeIndices":[78,79,18],"values":["114566"],"timestampsUnixNano":["1774910502132489246"]},{"stackIndex":51,"attributeIndices":[78,79,19],"values":["261008"],"timestampsUnixNano":["1774910502132178725"]},{"stackIndex":51,"attributeIndices":[78,79,23],"values":["6265806860","57828","53359","72228","41646","55618","325196"],"timestampsUnixNano":["1774910502130184494","1774910502130302358","1774910502130375800","1774910502130491288","1774910502130552096","1774910502130623172","1774910502130985900"]},{"stackIndex":51,"attributeIndices":[78,79,20],"values":["70696","45069","49129","52646","47324","49196","41378","36759","35119","36957","36442","34076","34702","33191","41211","63159","34465","36828","37348","35360","34595","36410"],"timestampsUnixNano":["1774910502136087103","1774910502136159291","1774910502136227730","1774910502136298719","1774910502136362862","1774910502138632543","1774910502138696318","1774910502138750433","1774910502138803668","1774910502138857196","1774910502138910044","1774910502138960942","1774910502139011513","1774910502139059989","1774910502139118895","1774910502139197690","1774910502139247789","1774910502139299495","1774910502139352554","1774910502139404621","1774910502139454953","1774910502139515000"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019854"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[80,81,15],"values":["789184"],"timestampsUnixNano":["1774910502133413842"]},{"stackIndex":6,"attributeIndices":[80,81,22],"values":["7190","7009","7505","5645"],"timestampsUnixNano":["1774910502137145673","1774910502137168349","1774910502137192481","1774910502137207085"]},{"stackIndex":6,"attributeIndices":[80,81,23],"values":["6322","25353","46481"],"timestampsUnixNano":["1774910502131121855","1774910502131156985","1774910502131241596"]},{"stackIndex":43,"attributeIndices":[80,81,20],"values":["76200"],"timestampsUnixNano":["1774910502132419924"]},{"stackIndex":6,"attributeIndices":[80,81,12],"values":["73970"],"timestampsUnixNano":["1774910502130084875"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019856"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":132,"unitStrindex":133},"samples":[{"stackIndex":53,"attributeIndices":[82,83,12],"timestampsUnixNano":["1774910498611250939"]},{"stackIndex":54,"attributeIndices":[82,83,17],"timestampsUnixNano":["1774910501111075510"]},{"stackIndex":55,"attributeIndices":[82,83,15],"timestampsUnixNano":["1774910501711207774"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{"typeStrindex":131,"unitStrindex":2},"period":"50000000"},{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[82,83,22],"values":["512072923","20423518","4808080","22471574","22016782","261706","1093761","6338223","24129668","21703640","369338","8938157","5418054","13913634","28656890","17862","17867204","5663059","45331946","390485944","372427451","6002081","9979144","15821013","18943137","47834809","5101891","3038595","54917354","552726","7302136","1075804","943910","928165","949488","309652","427930","322009","911679","75632","413834","557100","1352254","1349107","447673","1151640"],"timestampsUnixNano":["1774910498423686993","1774910498444179124","1774910498449044063","1774910498471550505","1774910498493626353","1774910498493934139","1774910498495076925","1774910498501487808","1774910498525642098","1774910498547690100","1774910498548121646","1774910498557095323","1774910498562549875","1774910498576493427","1774910498605175115","1774910499095645087","1774910499113554913","1774910499119266774","1774910499164628335","1774910499555189416","1774910499927643219","1774910499933673852","1774910499943689439","1774910499959560269","1774910499978556608","1774910500026437644","1774910500031598918","1774910500034674901","1774910500089626417","1774910500090226092","1774910500097580250","1774910500355096266","1774910500356056883","1774910500356995013","1774910500357959752","1774910500358286341","1774910500359211424","1774910500359637851","1774910500360558020","1774910500360650342","1774910500361612148","1774910500362255323","1774910500363633301","1774910500365007522","1774910500824438062","1774910502136393816"]},{"stackIndex":6,"attributeIndices":[82,83,6],"values":["449465","104619","12993745","922526","4433216","1181856","252486","1809357","4420125","16733168","1904527","13476","144823","79930","371897","749339","770864","149287","560683","1127555","13272955","501123","84377","5442644","1422351","298286","557469","202928","302679","865264","7936773","221553","684153","10629410","1522331","7375664","2342061","3250663","2553022","1429584","268718","224698","1388297","742540","286647","1845168","178726","2362893","1961554","4712193","1344426","731076","738368","2064478","291665","14430","21012416","2040960","447764","401538","5052887","15576513","11350258","5927759","6504","5770","5759","6198"],"timestampsUnixNano":["1774910498656009906","1774910500605699478","1774910500618719673","1774910500619908218","1774910500624633576","1774910500626355458","1774910500627122629","1774910500628956815","1774910500633951723","1774910500650725636","1774910500771339127","1774910500771366625","1774910500771516757","1774910500771601805","1774910500771995877","1774910500772752591","1774910500773674764","1774910500773910412","1774910500774765534","1774910500776426767","1774910500789961886","1774910500790480582","1774910500790583247","1774910500796049884","1774910500797491308","1774910500797857383","1774910500798839368","1774910500799584720","1774910500800359542","1774910500801727138","1774910500810384312","1774910500810746796","1774910500811948116","1774910500823045260","1774910501302805300","1774910501310197008","1774910501312555703","1774910501315847069","1774910501318428887","1774910501319894813","1774910501320179370","1774910501320438375","1774910501321833731","1774910501322607118","1774910501322908273","1774910501324783250","1774910501324985660","1774910501327386927","1774910501329368771","1774910501727072625","1774910501729128843","1774910501730610591","1774910501732111012","1774910501735111823","1774910501767815320","1774910502009566370","1774910502031247339","1774910502033415378","1774910502033964878","1774910502034742028","1774910502040573833","1774910502112487741","1774910502123852234","1774910502129800728","1774910502137139322","1774910502137164458","1774910502137203952","1774910502137232611"]},{"stackIndex":6,"attributeIndices":[82,83,19],"values":["32455845","12879735","51011749","374624","617227","5191891","33417455","25262490","36049003","1117718","780038","476498","445082","424990","435239","1066937","369482","771442","829334","1832845","1419927","3828833","189406","226712","241442","74026","4103732","43865","555934","125693","314239","7387818","1175325","1179930"],"timestampsUnixNano":["1774910500135711836","1774910500148641819","1774910500199730820","1774910500200140875","1774910500200809350","1774910500206044126","1774910500239498723","1774910500264806710","1774910500300908486","1774910500302612435","1774910500304129005","1774910500305149209","1774910500306096469","1774910500307022284","1774910500307898753","1774910500372752755","1774910501124643203","1774910501125467783","1774910501126343400","1774910501128227212","1774910501129674859","1774910501133539382","1774910501133779425","1774910501134029973","1774910501134319730","1774910501134418049","1774910501138551689","1774910501138612643","1774910501139194814","1774910501139334929","1774910501139722879","1774910501622260597","1774910501624083106","1774910501625762964"]},{"stackIndex":56,"attributeIndices":[82,83,6],"values":["244116"],"timestampsUnixNano":["1774910500651063382"]},{"stackIndex":57,"attributeIndices":[82,83,6],"values":["19423"],"timestampsUnixNano":["1774910500651785860"]},{"stackIndex":58,"attributeIndices":[82,83,6],"values":["11439084"],"timestampsUnixNano":["1774910500663492513"]},{"stackIndex":6,"attributeIndices":[82,83,21],"values":["397758","1192001","824243","693834","1692387","5308699","2233361","2000095","1192953","502527","957534","1611886","1725794","1681397","1623537","1193011","2167677","1443862","1918460","496385","549916","279939","547025","703014","758187","496522","191561","1266709","354405","118753","2384006","2225247","1541797","2739836","3225945","2201316","862995","1970648","4539045","1982233","1125287","16939118","46247487","1789524","1892834","3021455","991087","881767","8680562","701715","534692","604820","99028","2829772","42278118","194134","885438","125997","11165","253723","81750","274668","89228","1659277","2050057","640704","2859393","1298995","1683653","1119648"],"timestampsUnixNano":["1774910501140482429","1774910501141689666","1774910501142546322","1774910501143278171","1774910501144987083","1774910501150314269","1774910501152562644","1774910501154579644","1774910501155788783","1774910501156306043","1774910501157276925","1774910501158906339","1774910501160647135","1774910501162336861","1774910501163978500","1774910501165188125","1774910501167371231","1774910501168833596","1774910501170762040","1774910501171292279","1774910501171852845","1774910501172176644","1774910501172743791","1774910501173844048","1774910501174979156","1774910501175487636","1774910501175688826","1774910501176974827","1774910501177368422","1774910501177497845","1774910501179963280","1774910501182206804","1774910501183771206","1774910501186540379","1774910501189796267","1774910501192013410","1774910501192889577","1774910501195229948","1774910501200288192","1774910501202762184","1774910501204272137","1774910501221531400","1774910501267812554","1774910501270141360","1774910501272120621","1774910501275600219","1774910501276620935","1774910501278063432","1774910501286800332","1774910501287532266","1774910501288149092","1774910501288784288","1774910501544604269","1774910501547469918","1774910501589766128","1774910501590025166","1774910501591048064","1774910501591480631","1774910501591498051","1774910501591839095","1774910501592212841","1774910501592569195","1774910501592675726","1774910501594353987","1774910501596842961","1774910501597502149","1774910501600816246","1774910501602481491","1774910501668814020","1774910501669959088"]},{"stackIndex":59,"attributeIndices":[82,83,6],"values":["69135"],"timestampsUnixNano":["1774910502133757092"]},{"stackIndex":60,"attributeIndices":[82,83,20],"values":["15857"],"timestampsUnixNano":["1774910497885225642"]},{"stackIndex":61,"attributeIndices":[82,83,20],"values":["22971","15241","13385","12540"],"timestampsUnixNano":["1774910497905622565","1774910497905684934","1774910497905736016","1774910497905785000"]},{"stackIndex":62,"attributeIndices":[82,83,22],"values":["31028"],"timestampsUnixNano":["1774910498525874014"]},{"stackIndex":6,"attributeIndices":[82,83,16],"values":["1111693","262249","489441","468970","480036","412393","469635","491580","457820","732483","403148","182790","27967223","59767","693414","376616","4555091","325594","4620049","5459893","1478853","3606770","6469952","19036055","17123923"],"timestampsUnixNano":["1774910500323937285","1774910500324216859","1774910500325253646","1774910500326224688","1774910500327292823","1774910500328223442","1774910500329203682","1774910500330204359","1774910500331233919","1774910501436753804","1774910501437352199","1774910501437764797","1774910501473305180","1774910501474128196","1774910501475873300","1774910501477622714","1774910501483505778","1774910501483859973","1774910501488507963","1774910501493987582","1774910501495497922","1774910501499118909","1774910501505610687","1774910501524683298","1774910501541846609"]},{"stackIndex":6,"attributeIndices":[82,83,17],"values":["521739","524272","564054","968170","733537","443234","1511855","720304","2740489","407022","2118084","21561380","177373","3590642","440016","532654","887788","5922522","636164","810565","1201005","850671","1501564","214672","1386283","930700","1726105","4981343","550351","916479","7522375","23450986","1047622","980049","343339","2927466","310648","436159","2000373","383186","753530","618730","768925","1933429","2773600","1099810","1647007","4563948","3057571","1641400","10810183","2878848","1275329","3521225","3014317","2632334","365881","184723","113554","1511652","696521","606505","4358728","9109521","6350791","772617","846261","274804","61657","193361","169120","219769","101238","72881","97335","683814","177231","66496","106791","348188","185097","1274543","1259478","397582","1940514","284002","587928","118871","150265","378457","85360","181437","1356340","10731102","353057","179646","885289","3987662","383448","481294","314546","274299","29003","1015932","215613","767561","103828","975654","68880","312507","99639","2349678","179431","1333733","5349761","1282616","504801","6623022","868307","610759","452482","1402036","291987","3392517","3280628","14086861","1428709","1221319","1189753","2798093","549150","265023","387339","696554","4056706","14660","335758","490507","3285269","1186844","106713","2917657","608498","783391","524458","548882","764280","889222","115222","150534","413590","24672007","396873","523603","580078","254923","494691","96640","412385","344700","380432","1394775","463927","270370","5607","2217356","1058740","740152","3119371","1142306","389532","593673","581429","419248","77688","144252","307911","683290","903021","106493","133425","63192","129985","5766","1203660"],"timestampsUnixNano":["1774910500434917976","1774910500435786255","1774910500436387336","1774910500437541867","1774910500438580203","1774910500439050956","1774910500440615889","1774910500441613924","1774910500444372860","1774910500445132888","1774910500447580099","1774910500469165207","1774910500469401586","1774910500473009962","1774910500473467964","1774910500474018123","1774910500474909665","1774910500480847142","1774910500481497861","1774910500482316809","1774910500483528291","1774910500484387262","1774910500485894908","1774910500486123138","1774910500487570633","1774910500488521247","1774910500490282508","1774910500495277522","1774910500495839860","1774910500496766789","1774910500504301777","1774910500527772208","1774910500528835469","1774910500825824130","1774910500826468157","1774910500829643884","1774910500830432242","1774910500831147892","1774910500833410972","1774910500833876738","1774910500834635066","1774910500835266732","1774910500836047676","1774910500912575663","1774910500915375990","1774910500916507883","1774910500918213714","1774910500922800457","1774910500925883874","1774910500927541183","1774910500938369539","1774910500941267826","1774910500942586056","1774910500946122155","1774910500949156375","1774910500951809061","1774910500952213662","1774910500952424117","1774910500952549550","1774910500954065685","1774910500954795846","1774910500955427911","1774910500959830004","1774910500968957694","1774910500975330746","1774910500976139939","1774910500977019742","1774910500977337051","1774910500977414203","1774910500977631924","1774910500977818319","1774910500978071763","1774910500978204214","1774910500978281547","1774910500978389724","1774910500979077294","1774910500979283822","1774910500979367312","1774910500979495759","1774910500979849124","1774910500980072581","1774910500981368674","1774910500982664994","1774910500983078027","1774910500985051070","1774910500985350577","1774910500985957487","1774910500986093491","1774910500986262712","1774910500986645941","1774910500986736955","1774910500986932834","1774910500988294898","1774910500999488015","1774910500999861366","1774910501000059216","1774910501001477622","1774910501005521866","1774910501005926414","1774910501006446208","1774910501006781823","1774910501007112669","1774910501007156542","1774910501008192230","1774910501008432340","1774910501009220135","1774910501009340964","1774910501010339495","1774910501010422509","1774910501010745584","1774910501010849235","1774910501013208992","1774910501013409433","1774910501014765681","1774910501020130296","1774910501021432251","1774910501021975130","1774910501028639643","1774910501029548509","1774910501030219228","1774910501030694469","1774910501032140986","1774910501032453286","1774910501035910046","1774910501039209051","1774910501053317027","1774910501054760636","1774910501055995721","1774910501057200450","1774910501060448140","1774910501061044425","1774910501061326965","1774910501061752145","1774910501062467060","1774910501066585875","1774910501066616679","1774910501066961337","1774910501067497719","1774910501070800931","1774910501072582328","1774910501072723510","1774910501075699740","1774910501076335163","1774910501077173984","1774910501077729804","1774910501078326351","1774910501079122534","1774910501080073038","1774910501080217753","1774910501080405690","1774910501080826020","1774910501105523507","1774910501106015431","1774910501106553388","1774910501107163262","1774910501107435484","1774910501107949650","1774910501108068638","1774910501108512207","1774910501108863396","1774910501109284107","1774910501110698225","1774910501111580192","1774910501111886564","1774910501111918314","1774910501114152517","1774910501115580006","1774910501116771796","1774910501119913974","1774910501121094704","1774910501121506428","1774910501122140277","1774910501122746861","1774910501123215194","1774910501123318075","1774910501123494001","1774910501123808276","1774910501736603033","1774910501738124331","1774910501738274794","1774910501738415787","1774910501738484377","1774910501738632407","1774910502138489587","1774910502139707155"]},{"stackIndex":6,"attributeIndices":[82,83,18],"values":["2807681","1670126","81733","5698846","3463998","349974","119760","1476873","1299105","848858","455489","630548","2129379","1071014","921325","1367408","143482","1349004","243590","677066","384036","461015","598119","212742","103604","116972","288215","390862","595462","481565","329133","153945","433598","1321413","1702716","1485410","883754","207268","2055081","2295725","1451525","28198814","140527","9648796","24370674","14015564","10781878","5913582","22344613","7311093","868379","272061","7100174","5798564","452765","8800214","2326595","302982","31817372","6327079","297323","2812050","3672339","9452041","1656087","1334864","1126575","1587765","4362675","7766901","12499350","315531","862158","652837","1292547","1058534","1478039","952571","962638","9467040","8720465","3892564","24797518","8431876","5348191","3004141","3556842","89468","37688","516109","942555","1647880","632276","7465411"],"timestampsUnixNano":["1774910500689826672","1774910500691535945","1774910500691659887","1774910500697387040","1774910500700887330","1774910500701730086","1774910500702314012","1774910500704225709","1774910500705823610","1774910500707048457","1774910500708288507","1774910500884454921","1774910500886609131","1774910500888007246","1774910500889072998","1774910500890518554","1774910500890679675","1774910500892225271","1774910500893033101","1774910500894242754","1774910500895173583","1774910500896200308","1774910500897362327","1774910500898103671","1774910500898238053","1774910500898915296","1774910500899228778","1774910500900148977","1774910500901354669","1774910500902393475","1774910500903237676","1774910500903894962","1774910500904345927","1774910500906178887","1774910500907933120","1774910500909436469","1774910500910337425","1774910500910552651","1774910501341508096","1774910501343883888","1774910501345388098","1774910501373611290","1774910501373928173","1774910501383600287","1774910501407994965","1774910501422100944","1774910501433098863","1774910501777156554","1774910501799522513","1774910501806858099","1774910501807928367","1774910501808328172","1774910501815543969","1774910501821537063","1774910501822019683","1774910501830849519","1774910501833207152","1774910501834219944","1774910501866073680","1774910501872414691","1774910501872719268","1774910501875537098","1774910501879215934","1774910501888691115","1774910501890366401","1774910501891709552","1774910501892842195","1774910501894437657","1774910501898807360","1774910501906585689","1774910501919091872","1774910501919414734","1774910501920282604","1774910501920953534","1774910501922263495","1774910501923341664","1774910501924825419","1774910501925796184","1774910501926777575","1774910501936261623","1774910501944994099","1774910501948916211","1774910501973731326","1774910501982186224","1774910501988827502","1774910501992429580","1774910501996031074","1774910501996162550","1774910501996206192","1774910501996737253","1774910501997685807","1774910501999341597","1774910502000004012","1774910502007487938"]},{"stackIndex":63,"attributeIndices":[82,83,6],"values":["95633","163457"],"timestampsUnixNano":["1774910500651252897","1774910500651470755"]},{"stackIndex":64,"attributeIndices":[82,83,16],"values":["49990"],"timestampsUnixNano":["1774910501442526568"]},{"stackIndex":6,"attributeIndices":[82,83,20],"values":["808063795","444906","855254","1184774","282907","471029","203261","952116","1060440","995738","1375373","1698592","598215","1624458","855063","12641954","9585500","10175201","440121","7087359","2771081","604315","11014638","8163039","956775","27100932","1159808","1060826","1540848","856536","1059913","937135","3787176","3184243","1616464","1263036","1745773","1539781","1532755","1267420","1061263","982132","1243658"],"timestampsUnixNano":["1774910497884652999","1774910497885163107","1774910500346574818","1774910500347783100","1774910500348091267","1774910500349047765","1774910500349323756","1774910500350283755","1774910500351368414","1774910500352383058","1774910500367628521","1774910500530743200","1774910500531357626","1774910500532999718","1774910500533872258","1774910500546528069","1774910500556135290","1774910500566339504","1774910500566818202","1774910500574347001","1774910500577157121","1774910500578561997","1774910500589608849","1774910500597788014","1774910500842072044","1774910500869191828","1774910500870372243","1774910500871448723","1774910500873021996","1774910500873893688","1774910500874968736","1774910500875949964","1774910500879766508","1774910500882977900","1774910501673328659","1774910501674608668","1774910501676371175","1774910501677933873","1774910501679497773","1774910501680791944","1774910501681884851","1774910501682899428","1774910501684170439"]},{"stackIndex":6,"attributeIndices":[82,83,15],"values":["509544","443273","2547868","874603","778072","1595931","657324","924993","653220","668344","622442","729698","709731","859367","738731","869798","727063","2626887","483045","758885","579968","475365","752169","744598","519215","525921","844963","501188","433121","581476","454556","432659","560686","668140","416181","657854","614700","578293","1153359","12763314","531646","518263","672571","558796","9908580","3011034","328250","1147307","627672","437175","1210956","432510","755868","1040727","1342806","1690918","1227967","6031394","16666","1386830","1703153","1737379","978045","767273","1171603","320910","382319","2411397","52104","741920","2859213","1333237","364980","512796","656423","770968","839732","878531","909488","848157","701783","369532","898968","1770941","361044","1315332","745818","1353756","445000","204593","156151","726811","290770","1034824","4023548","142522","537465","747600","400649","419697","400220","273670","718479","1750018","971048","1526295","5303504","459610","742438","465437","443252","22126551","512583","100283","3571350"],"timestampsUnixNano":["1774910500332340016","1774910500333288474","1774910500336274346","1774910500337930138","1774910500339564721","1774910500341918233","1774910500343102317","1774910500344526110","1774910500374238287","1774910500375347294","1774910500376382621","1774910500377579439","1774910500378665691","1774910500379991276","1774910500381177746","1774910500382685452","1774910500383834215","1774910500386843471","1774910500387363518","1774910500388423965","1774910500389467925","1774910500390225615","1774910500416881053","1774910500418292558","1774910500419039010","1774910500419769653","1774910500421160642","1774910500422209703","1774910500423220330","1774910500424297894","1774910500425289655","1774910500425942389","1774910500426678357","1774910500427846705","1774910500428471684","1774910500429425591","1774910500430322666","1774910500709798240","1774910500711764489","1774910500725209239","1774910500726084115","1774910500726955988","1774910500728040618","1774910500728947000","1774910500739301486","1774910500742337474","1774910500742730028","1774910500743883533","1774910500744520946","1774910500745221209","1774910500746454573","1774910500747329298","1774910500748137181","1774910500749204280","1774910500750572450","1774910500752286789","1774910500753542121","1774910500759601267","1774910500759643698","1774910500761037551","1774910500762760918","1774910500764521969","1774910501687804867","1774910501689314245","1774910501691152420","1774910501692109263","1774910501692518041","1774910501695387952","1774910501695485212","1774910501696234025","1774910501699114154","1774910501700468038","1774910501700861146","1774910501701411568","1774910501702087237","1774910501703339036","1774910501704682016","1774910501705998223","1774910501707350888","1774910501708715171","1774910501710001668","1774910501711030556","1774910501712751100","1774910501715517156","1774910501716533756","1774910501717871120","1774910501718944655","1774910501720590206","1774910501721061824","1774910501721296774","1774910501721507727","1774910501740204806","1774910502041405879","1774910502042554116","1774910502046656221","1774910502046813513","1774910502047361512","1774910502048116192","1774910502048531498","1774910502049251682","1774910502050161439","1774910502050897871","1774910502052105745","1774910502054499481","1774910502056027400","1774910502058199571","1774910502064114090","1774910502065141776","1774910502066171870","1774910502067261314","1774910502068461953","1774910502090949981","1774910502091480821","1774910502091598761","1774910502095187061"]},{"stackIndex":65,"attributeIndices":[82,83,18],"values":["44234"],"timestampsUnixNano":["1774910500674642930"]},{"stackIndex":66,"attributeIndices":[82,83,18],"values":["11321881"],"timestampsUnixNano":["1774910500686509321"]},{"stackIndex":67,"attributeIndices":[82,83,6],"values":["125523"],"timestampsUnixNano":["1774910500651683670"]},{"stackIndex":68,"attributeIndices":[82,83,6],"values":["123489"],"timestampsUnixNano":["1774910500652005271"]},{"stackIndex":69,"attributeIndices":[82,83,22],"values":["49752"],"timestampsUnixNano":["1774910500823870206"]},{"stackIndex":70,"attributeIndices":[82,83,20],"values":["20230083"],"timestampsUnixNano":["1774910497905510138"]},{"stackIndex":6,"attributeIndices":[82,83,12],"values":["1474867","542011","3907362"],"timestampsUnixNano":["1774910498606706661","1774910498607284318","1774910498611223894"]},{"stackIndex":6,"attributeIndices":[82,83,9],"values":["419233","467521","650838","396619","971144","941406","867044","795232","905218","741517","831167","804456","879383","880667","721507","947552","3518088","660215","389465","536274","178106","360361","221715","378658","132186","951525","2268684","781349","137741","141416","29938","429025","440672","409453","287506","494696","287474","2001151","236912","1783835","1604324","1802007","2098022","1485216","1346058","1688536","1565105","1955423","2266124","88589"],"timestampsUnixNano":["1774910500309659768","1774910500310562594","1774910500311651579","1774910500312177538","1774910500313168600","1774910500314127660","1774910500315012357","1774910500315822952","1774910500316742561","1774910500317498415","1774910500318343583","1774910500319162549","1774910500320056207","1774910500320951111","1774910500321686797","1774910501294118309","1774910501635592540","1774910501636324023","1774910501636746523","1774910501637347468","1774910501637558821","1774910501637971026","1774910501638213648","1774910501638650791","1774910501638815127","1774910501639826479","1774910501642121197","1774910501642952165","1774910501643115745","1774910501643302366","1774910501643353152","1774910501643836590","1774910501644298095","1774910501644748890","1774910501645070718","1774910501645609420","1774910501645921177","1774910501647982224","1774910501648238335","1774910501650065541","1774910501651685605","1774910501653502149","1774910501655615870","1774910501657118380","1774910501658480776","1774910501660179353","1774910501661757491","1774910501663727424","1774910501666007946","1774910502136987841"]},{"stackIndex":6,"attributeIndices":[82,83,23],"values":["669251","611587","124548","1373785","781794","471380","978376","332219","438643","411703","945952","548313","898131","655626","1105923","904503","711516","604863","433973","1162099","727495","918569"],"timestampsUnixNano":["1774910500392651741","1774910500393541409","1774910500393685549","1774910500395417413","1774910500396563195","1774910500397379396","1774910500398716918","1774910500399428152","1774910500400081059","1774910500400732156","1774910500402065307","1774910500402951413","1774910500404206963","1774910500405314875","1774910500406898160","1774910500408206396","1774910500409315737","1774910500410223808","1774910500410900710","1774910500412427980","1774910500414009276","1774910500415237171"]},{"stackIndex":71,"attributeIndices":[82,83,6],"values":["32366"],"timestampsUnixNano":["1774910500663593505"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"31"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[88,89,20],"values":["50787","41173","39714","3993722500"],"timestampsUnixNano":["1774910497905671549","1774910497905724344","1774910497905774076","1774910501899505868"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1181"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":12,"attributeIndices":[90,91,12],"values":["30819624","318507","47249","1190282","32267856","72869180","595819339","392092","641578","226300","27022453","686055481","3474701","10723448","360597","13924509","573291","1319099","81644002","1640646","1139909","3192752","29608013","561078","568748648","901747","22797025","5494645","7015990","23782","370536581","1916825","176184","25157221","688530706","3478687","26822529","371363","447187","3712233"],"timestampsUnixNano":["1774910498662578890","1774910498663124558","1774910498663292996","1774910498664500763","1774910498696804156","1774910498769992495","1774910499366043983","1774910499366663465","1774910499367403224","1774910499367675439","1774910499394940038","1774910500081205362","1774910500084907126","1774910500095788322","1774910500096312770","1774910500110269611","1774910500111016579","1774910500112373552","1774910500194162914","1774910500196071280","1774910500197435071","1774910500200697556","1774910500230578509","1774910500231412668","1774910500800199080","1774910500801295620","1774910500824482831","1774910500830208008","1774910500837397703","1774910500837512295","1774910501208062465","1774910501210286560","1774910501210493698","1774910501235686780","1774910501924408430","1774910501928090693","1774910501955361637","1774910501955965307","1774910501956446495","1774910501960205606"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1961929"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":72,"attributeIndices":[92,93,19],"values":["90689"],"timestampsUnixNano":["1774910502130579884"]},{"stackIndex":6,"attributeIndices":[92,93,19],"values":["7899"],"timestampsUnixNano":["1774910502130705454"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2014063"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[94,95,6],"values":["28191206","15290088","19606064","15019129","8022411","5212234","106388202","58570544","50992746","51607359","60944315","51667943","50793256","61840635","50343894","50482980","62955455","31228942","29355111","7912616","99450062","52489211","60601598","48585726","50659130","59863914","19857067","40844990","48530951","52234528","67860756","39236692","8481477","51922196","68283481","52371623","51302663","37632991","26370703","50791576","105800100","60567744","50768144","50109805","58335098","47200372","49844744","51415513","57442185","63606780","31807036","34053516","45015259","58628896","51020515","51621939","39852081","34192481","47683653","65189121","4225785","43897379","53865697","65238918","66115179","20124601","50354812","48769126","49536339","57695041","50428633","50781940","18356046","42679075","21245501","29674924","49960345","57795555","32446379","23503903","47916407","50231911","46088975","46034696","15917434","1391409","60486464","47962199","55376137","28253704","43886900","47840249","54188793","60110963","49155120","51070943","59831104","44528","49178429","49976636","49596786","31669810","45982106","46848799"],"timestampsUnixNano":["1774910497570513649","1774910497585855619","1774910497605525570","1774910497620583578","1774910497628627312","1774910497633873499","1774910497740312768","1774910497798950997","1774910497849992834","1774910497901650833","1774910497962651201","1774910498014386749","1774910498065233372","1774910498127122701","1774910498177510069","1774910498228039500","1774910498291044580","1774910498322341485","1774910498351747879","1774910498359715622","1774910498459208035","1774910498511747365","1774910498572399421","1774910498621066371","1774910498671777896","1774910498731671366","1774910498751601059","1774910498792498184","1774910498841082087","1774910498893359470","1774910498961277674","1774910499000606912","1774910499009138260","1774910499061111915","1774910499129453138","1774910499181904411","1774910499233257041","1774910499270947685","1774910499297386338","1774910499348223473","1774910499454089053","1774910499514717052","1774910499565532032","1774910499615690396","1774910499674087401","1774910499721343042","1774910499771236908","1774910499822708352","1774910499880206669","1774910499943865491","1774910499975723950","1774910500009827332","1774910500054886684","1774910500113577660","1774910500164644903","1774910500216313638","1774910500256215190","1774910500290473146","1774910500338248403","1774910500403471297","1774910500407756273","1774910500451699883","1774910500505613821","1774910500570921210","1774910500637069542","1774910500657235445","1774910500707630875","1774910500756429120","1774910500806043290","1774910500863790210","1774910500914266261","1774910500965093204","1774910500983493955","1774910501026195800","1774910501047503989","1774910501077217359","1774910501127221312","1774910501185049932","1774910501217565532","1774910501241127333","1774910501289081118","1774910501339366859","1774910501385501065","1774910501431562034","1774910501447504202","1774910501448976577","1774910501509495896","1774910501557502610","1774910501612919498","1774910501641224049","1774910501685159904","1774910501733052487","1774910501787282283","1774910501847430967","1774910501896613319","1774910501947704315","1774910502007564024","1774910502007662219","1774910502056860357","1774910502106883811","1774910502156513074","1774910502188216433","1774910502234229182","1774910502281129827"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2012293"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[96,97,20],"values":["211995166","283899438","205651521","248362242","64924114","62532320","575997514","191869129","134189314","187718522","382664361","63291203","191956703","192906167","638911209","63958525","320057860","575951945","63913276"],"timestampsUnixNano":["1774910497621889111","1774910497905821414","1774910498111495823","1774910498359898838","1774910498424870337","1774910498487503580","1774910499063554929","1774910499255510105","1774910499389730323","1774910499577509332","1774910499960211718","1774910500023538713","1774910500215549869","1774910500408507956","1774910501047494672","1774910501111482797","1774910501431559667","1774910502007542923","1774910502071516442"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"24"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[98,99,15],"values":["162992060","4787579","690084647","4443221","187802905","402274333","107726112","14469208","180707062","1090842","92765881","59283183","11647930","640615267","209769638","78645666","158867211","620337","16623231","40208871","66683131","14657082","5151868","30832542","38143742","31317046","140746","46221445","90381336","40315940","29562681","25494122","134485825","24851486","1074096","49967073","68244324","571728","132938091","19516235","832132","1449324","3378574","9723291","32275255","284726769","16647927","99231276","88347671","32615632","79941168","7913361","8595882","26751447","387050","1188664","1337745","59816928","25538348","70877358"],"timestampsUnixNano":["1774910497683552090","1774910497688408420","1774910498378523367","1774910498383003754","1774910498570876305","1774910498973202935","1774910499080989288","1774910499095508054","1774910499276255502","1774910499277409792","1774910499370203691","1774910499429530047","1774910499441229196","1774910500081879646","1774910500291679418","1774910500370382289","1774910500529294376","1774910500529937200","1774910500546586459","1774910500586833944","1774910500653558051","1774910500668261425","1774910500673452846","1774910500704318502","1774910500742501761","1774910500773838152","1774910500773996419","1774910500820236975","1774910500910648025","1774910500950998835","1774910500980590191","1774910501006111345","1774910501140626705","1774910501165495113","1774910501166594348","1774910501216583443","1774910501284886267","1774910501285540461","1774910501418498803","1774910501438041567","1774910501438897984","1774910501440363829","1774910501443762287","1774910501453500936","1774910501485798277","1774910501770547509","1774910501787231330","1774910501886513851","1774910501974894790","1774910502007544466","1774910502087558351","1774910502095497897","1774910502104110816","1774910502130885295","1774910502131299592","1774910502132503789","1774910502133856200","1774910502193687093","1774910502219270588","1774910502290182895"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"25"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[100,101,15],"values":["385445431","63655","32100","32403","225600662","40101","33740","32946","9828","2416592667","245359267","223637032","863974478","400014930"],"timestampsUnixNano":["1774910497885968037","1774910497886056793","1774910497886104803","1774910497886142246","1774910498111748017","1774910498111800448","1774910498111838952","1774910498111875727","1774910498111889534","1774910500528487096","1774910500773857593","1774910500997503148","1774910501861497661","1774910502261523853"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"72"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":132,"unitStrindex":133},"samples":[{"stackIndex":73,"attributeIndices":[102,103,18],"timestampsUnixNano":["1774910500611625181"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{"typeStrindex":131,"unitStrindex":2},"period":"50000000"},{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[102,103,18],"values":["885960033","235242263","951642446","112937222","320985142","569985797","184203941","82637438","61881238","34894024","202001868","813816210","298051369","158938078"],"timestampsUnixNano":["1774910498153661880","1774910498388945262","1774910499340623342","1774910499453598996","1774910499774621247","1774910500344661796","1774910500528900236","1774910500611573687","1774910500673551961","1774910500708536832","1774910500910574977","1774910501724423835","1774910502022519286","1774910502181494613"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1442747"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[104,105,21],"values":["1038965449","812912895","179936038","780014579","63959999","128062864","191840644","704873968","126873654","6976981","249022325","319912157","255916452"],"timestampsUnixNano":["1774910498442537996","1774910499255487785","1774910499435496483","1774910500215537752","1774910500279543285","1774910500407694262","1774910500599599458","1774910501304508203","1774910501431504679","1774910501438495596","1774910501687575597","1774910502007533179","1774910502263489580"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"97"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":74,"attributeIndices":[106,107,6],"values":["35370181","16517600","40026791","149010003","297234653","70434505","56927044","32947202","47022320"],"timestampsUnixNano":["1774910500687752485","1774910500704293443","1774910500744343019","1774910501477641036","1774910501774894234","1774910501845353830","1774910501902305737","1774910501935268567","1774910501982311655"]},{"stackIndex":74,"attributeIndices":[106,107,9],"values":["20882032","25696546"],"timestampsUnixNano":["1774910500797422949","1774910500823139928"]},{"stackIndex":74,"attributeIndices":[106,107,23],"values":["64583041"],"timestampsUnixNano":["1774910502194433606"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2012776"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[108,109,23],"values":["7013","60716"],"timestampsUnixNano":["1774910502131650681","1774910502131887690"]},{"stackIndex":6,"attributeIndices":[108,109,15],"values":["58727","195379"],"timestampsUnixNano":["1774910502131106160","1774910502131316449"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"42"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[110,111,22],"values":["121728990","11206156","5101087","81989934","62773824","103142731","110823656","421824938","58017177","52972069","107491428","43408770","16102706","163746722","97895983","67684555","51300999","35597106","36344816","104874523","63849571","93093629","62812874","97969678","369848219","109778829","299237258","37796328","172292984","10608800","47969674","60032815","11850751","7030466","24914156","11897447","34845911","62859166","531956","3597200","17937090","890049","11108091","111014614","6259447","130327326","66262828","92817186","105942322","35941199","24021165","30436987","53450379","126082176","7838666","411808567","52093336","28637787","73464355","50912087","48125589","25023108"],"timestampsUnixNano":["1774910497589340906","1774910497600600327","1774910497605748571","1774910497687762203","1774910497750583172","1774910497853755558","1774910497964636059","1774910498386514686","1774910498444567949","1774910498497606952","1774910498605198223","1774910498648631540","1774910498664803286","1774910498828579936","1774910498926519158","1774910498994256573","1774910499045588847","1774910499081230621","1774910499117632792","1774910499222553718","1774910499286454583","1774910499379608521","1774910499442494221","1774910499540539943","1774910499910468178","1774910500020291313","1774910500319619861","1774910500357521195","1774910500529856513","1774910500540512653","1774910500588523352","1774910500648612632","1774910500660525953","1774910500667578729","1774910500692555575","1774910500704540336","1774910500739428553","1774910500802318734","1774910500802892227","1774910500806522452","1774910500824514195","1774910500825427614","1774910500836559907","1774910500947595774","1774910500953894028","1774910501084252209","1774910501150548261","1774910501243506595","1774910501349509294","1774910501385482755","1774910501409544714","1774910501440015465","1774910501493501921","1774910501619625256","1774910501627500735","1774910502039352885","1774910502091488947","1774910502120165998","1774910502193653427","1774910502244593168","1774910502292757099","1774910502317824132"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"92"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":75,"attributeIndices":[112,113,22],"values":["5990889","6470919"],"timestampsUnixNano":["1774910497918591092","1774910497925493216"]},{"stackIndex":76,"attributeIndices":[112,113,22],"values":["6073127"],"timestampsUnixNano":["1774910497931616424"]},{"stackIndex":77,"attributeIndices":[112,113,20],"values":["326564"],"timestampsUnixNano":["1774910497903981028"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"226"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[114,115,18],"values":["16635101","233281161","16596508","16416521","966624000","16768956","16531052","16782712","16560664","16581854","116522141","16745306","16436473","16551082","16773531","16584542","16597943","216423351","16835243","16608802","16566893","16544296","16800434","16593047","16447388","16756222","16534686","16431980","16771655","16445510","16784309","16519882","16699603","16586364","49891752","100021844","166500270","1510939523","114380","4013633","84745917","16825605","16380189","16678781","16848632"],"timestampsUnixNano":["1774910498288252089","1774910498521595298","1774910498538241701","1774910498554701864","1774910499521374388","1774910499538197423","1774910499554783072","1774910499571608541","1774910499588238286","1774910499604880688","1774910499721444898","1774910499738302913","1774910499754818431","1774910499771410595","1774910499788242560","1774910499804897870","1774910499821540936","1774910500038017368","1774910500054892426","1774910500071573448","1774910500088186998","1774910500104776477","1774910500121625539","1774910500138273700","1774910500154807063","1774910500171610022","1774910500188218599","1774910500204721740","1774910500221538081","1774910500238031614","1774910500254850020","1774910500271425766","1774910500288166779","1774910500304814511","1774910500354771502","1774910500454845359","1774910500621398717","1774910502132377406","1774910502132520510","1774910502136548036","1774910502221317611","1774910502238181745","1774910502254611826","1774910502271323173","1774910502288214320"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019857"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[116,117,21],"values":["4372","53444","4056","8291","19326","22446","4075"],"timestampsUnixNano":["1774910502131142496","1774910502131253155","1774910502131279990","1774910502131296185","1774910502131324254","1774910502131372914","1774910502131393736"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"30"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[118,119,20],"values":["15582735","444370628","224011848","15735053","144036956","487979678","65850741","55111231","87702999","288108089","60742875","26064132","423819717","200929678","178026256","128017221","28878721","26964800","59888166","25790676","40105624","66993449","5032390","72973155","53855359","19896799","11969970","47999276","12023145","13856335","141136874","4856737","1374689","14534210","40908511","12056047","63912630","18523691","35330653","59031417","178777058","260001481","15914288","1522783","15724055","109717427","110020611","35884120","62992118","30102432","15957810","1796923","14952730","10605197","1344697","1451112","3784957","621590","1102207","174375","78873522","73851111","9349575","14572942"],"timestampsUnixNano":["1774910497556154812","1774910498000555754","1774910498224630905","1774910498240458400","1774910498384610843","1774910498872621678","1774910498938554731","1774910498993728130","1774910499081508010","1774910499369677558","1774910499430525720","1774910499456630836","1774910499880517376","1774910500081498917","1774910500259571677","1774910500387670132","1774910500416574743","1774910500443585515","1774910500503516507","1774910500529377433","1774910500569518029","1774910500636540299","1774910500641637600","1774910500714692747","1774910500768567650","1774910500788501553","1774910500800512841","1774910500848532139","1774910500860600041","1774910500874498707","1774910501015669029","1774910501020558487","1774910501022025074","1774910501036591988","1774910501077525559","1774910501089639768","1774910501153639407","1774910501172204242","1774910501207565728","1774910501266635903","1774910501445504812","1774910501705546037","1774910501721489382","1774910501723040094","1774910501738794451","1774910501848532428","1774910501958607636","1774910501994523991","1774910502057554870","1774910502087712009","1774910502103704151","1774910502105519067","1774910502120501738","1774910502131128222","1774910502132488975","1774910502133954663","1774910502137756704","1774910502138402211","1774910502139535648","1774910502139722716","1774910502218608377","1774910502292504785","1774910502301897146","1774910502316499663"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"19"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":132,"unitStrindex":133},"samples":[{"stackIndex":73,"attributeIndices":[120,121,17],"timestampsUnixNano":["1774910501861077230"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{"typeStrindex":131,"unitStrindex":2},"period":"50000000"},{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[120,121,17],"values":["965391049","110178263","573611474","29176391","21585007","28627426","62491330","292072677","197258022","54624826","153933759","430834","92500297","103333855","304771","14718598","767037","1261438","183923098","301186639","100514381","14322516","85998734","200831626","31062651","7940790","61063797","350163","9649242","62170849","138728803","94340561","49979410","30488195","15529701","20493660","79689594","8556124","9995439","575330","22798153","30940199","27660391","66951559","41404724","392993082","79468","54389595","261215","3769690","7131394","271331677","138485497","236404740","6000912","1096454","25369688","661558","629386","244684","741481","49175","1069674","4421669","36827207","3070603","15244060","588556","96672150","11297717","13903343"],"timestampsUnixNano":["1774910497556496018","1774910497666699734","1774910498240368990","1774910498269617890","1774910498291275791","1774910498319966854","1774910498382516177","1774910498674604607","1774910498871916300","1774910498926584150","1774910499080558477","1774910499081053292","1774910499173589463","1774910499276958101","1774910499277302065","1774910499292042331","1774910499292870700","1774910499294170192","1774910499478135474","1774910499779349747","1774910499879892185","1774910499894294045","1774910499980363094","1774910500181242880","1774910500212347963","1774910500220377103","1774910500281494858","1774910500281879280","1774910500291551069","1774910500353779756","1774910500492556920","1774910500586932382","1774910500636946669","1774910500667489208","1774910500683055190","1774910500703582077","1774910500783297781","1774910500791878264","1774910500801900730","1774910500802514019","1774910500825343019","1774910500856303598","1774910500883986557","1774910500950964769","1774910500992392659","1774910501385443345","1774910501385550914","1774910501439952690","1774910501440239839","1774910501444031719","1774910501451179855","1774910501722555697","1774910501861068853","1774910502097506495","1774910502103542089","1774910502104661361","1774910502130043679","1774910502130732613","1774910502131381745","1774910502131638531","1774910502132393635","1774910502132456564","1774910502133535250","1774910502137970625","1774910502174816781","1774910502177920639","1774910502193180816","1774910502193807856","1774910502290503309","1774910502301843071","1774910502315773240"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"37"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[122,123,23],"values":["50558","38423","60405","40192","40499","37522"],"timestampsUnixNano":["1774910497885384490","1774910497885434671","1774910497885504002","1774910497885553688","1774910497885603425","1774910497885648996"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"55"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[124,125,9],"values":["51043","10627705"],"timestampsUnixNano":["1774910498128081427","1774910498138722033"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019041"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":78,"attributeIndices":[126,127,18],"values":["49209"],"timestampsUnixNano":["1774910502132535770"]},{"stackIndex":6,"attributeIndices":[126,127,16],"values":["13255","145544","5869","241325","5422","5350"],"timestampsUnixNano":["1774910502137332130","1774910502137490615","1774910502137505705","1774910502137768098","1774910502137815817","1774910502137829153"]},{"stackIndex":6,"attributeIndices":[126,127,23],"values":["6404","45061","37266","39360","31545","35998","33169","35221","32284","32901","29510","39039","63977","27661","50168","43403","23765","28449","16989","65224","18847","6429","57780"],"timestampsUnixNano":["1774910502133841196","1774910502133898491","1774910502138621919","1774910502138697579","1774910502138751753","1774910502138807196","1774910502138859780","1774910502138914600","1774910502138964730","1774910502139015276","1774910502139063773","1774910502139119585","1774910502139201349","1774910502139249940","1774910502139315915","1774910502139368044","1774910502139398472","1774910502139459004","1774910502139506404","1774910502139600711","1774910502139627737","1774910502139665293","1774910502139776833"]},{"stackIndex":6,"attributeIndices":[126,127,17],"values":["736542","302618"],"timestampsUnixNano":["1774910502135060643","1774910502316822269"]},{"stackIndex":6,"attributeIndices":[126,127,9],"values":["13047545"],"timestampsUnixNano":["1774910502315251582"]},{"stackIndex":79,"attributeIndices":[126,127,18],"values":["279629","172293","188213"],"timestampsUnixNano":["1774910502132408359","1774910502132756927","1774910502133037950"]},{"stackIndex":6,"attributeIndices":[126,127,18],"values":["119296"],"timestampsUnixNano":["1774910502133256676"]},{"stackIndex":22,"attributeIndices":[126,127,18],"values":["9665","132783"],"timestampsUnixNano":["1774910502133433964","1774910502136649645"]},{"stackIndex":6,"attributeIndices":[126,127,6],"values":["310872","846991","1239856","7456914","1636293","37583554","2110876","821948","1745287","11024646","23747961","3172677","2360414","19507984","428806","4018887","30329044","6593787","181476"],"timestampsUnixNano":["1774910502141818813","1774910502142693315","1774910502143943150","1774910502151884495","1774910502153561838","1774910502192013516","1774910502194343744","1774910502195883442","1774910502197651382","1774910502208683421","1774910502232451705","1774910502235687947","1774910502238083790","1774910502257611068","1774910502258057701","1774910502262091805","1774910502292453580","1774910502299388198","1774910502300246256"]},{"stackIndex":80,"attributeIndices":[126,127,16],"values":["20330"],"timestampsUnixNano":["1774910502137276978"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"229"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[128,129,21],"values":["114761","103980","55050","65976","41027","110029"],"timestampsUnixNano":["1774910502135528882","1774910502135642202","1774910502135706021","1774910502135782278","1774910502135833568","1774910502135953335"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1187"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":12,"attributeIndices":[130,131,16],"values":["816999400","522620"],"timestampsUnixNano":["1774910498239259510","1774910498239989990"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2012527"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[132,133,19],"values":["832128860","1030107766","633789358","384824934","574960869","448036725"],"timestampsUnixNano":["1774910498359652420","1774910499389804036","1774910500023653050","1774910500408513427","1774910500983498199","1774910501431555782"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1398751"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[134,135,23],"values":["976037468","303843554","665018034","102896707","45970735","17997864","832107723","383706690","578960000","61060194","63936969","512817624"],"timestampsUnixNano":["1774910498439555525","1774910498743498955","1774910499408552913","1774910499511491547","1774910499557513554","1774910499575582252","1774910500407747133","1774910500791498035","1774910501370485377","1774910501431561957","1774910501495522152","1774910502008365919"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1182"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":12,"attributeIndices":[136,137,12],"values":["2920715253"],"timestampsUnixNano":["1774910498601685723"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"67"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[138,139,6],"values":["3042984896","219913418"],"timestampsUnixNano":["1774910500663565243","1774910500883504936"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"99"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":81,"attributeIndices":[140,141,19],"values":["15658","34517","788416"],"timestampsUnixNano":["1774910502007596237","1774910502007651728","1774910502008453122"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019043"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[142,143,17],"values":["60785"],"timestampsUnixNano":["1774910502137101754"]},{"stackIndex":6,"attributeIndices":[142,143,18],"values":["52299"],"timestampsUnixNano":["1774910502130064984"]},{"stackIndex":6,"attributeIndices":[142,143,6],"values":["22176","46298","51092","36424","50149","40562","18187","6363","36940","6433"],"timestampsUnixNano":["1774910502139354901","1774910502139420142","1774910502139480244","1774910502139530236","1774910502139589262","1774910502139649847","1774910502139676398","1774910502139719745","1774910502139765166","1774910502139805954"]},{"stackIndex":6,"attributeIndices":[142,143,22],"values":["34185","10502","6297","6668","32935","5755","455886","60704","11233","24635","7426","57103","54601","54221","22263","49673","46051","48483","44601","45212","42554","49825","51202","17356"],"timestampsUnixNano":["1774910502130840755","1774910502130890050","1774910502130955128","1774910502131062019","1774910502131168307","1774910502131208758","1774910502131749361","1774910502133974302","1774910502134028015","1774910502134090566","1774910502134201461","1774910502138561694","1774910502138636403","1774910502138708643","1774910502138742109","1774910502138817231","1774910502138869464","1774910502138924326","1774910502138974469","1774910502139025518","1774910502139073674","1774910502139129209","1774910502139190783","1774910502139240510"]},{"stackIndex":6,"attributeIndices":[142,143,12],"values":["7176","423984"],"timestampsUnixNano":["1774910502131796743","1774910502132231954"]},{"stackIndex":22,"attributeIndices":[142,143,15],"values":["21726","15073","30746"],"timestampsUnixNano":["1774910502133434445","1774910502133460968","1774910502133509594"]},{"stackIndex":21,"attributeIndices":[142,143,17],"values":["102111"],"timestampsUnixNano":["1774910502136656729"]},{"stackIndex":20,"attributeIndices":[142,143,17],"values":["275906"],"timestampsUnixNano":["1774910502136966702"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2016788"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":82,"attributeIndices":[144,145,21],"values":["30150"],"timestampsUnixNano":["1774910502134505432"]},{"stackIndex":6,"attributeIndices":[144,145,18],"values":["13673","478220","5579","16540"],"timestampsUnixNano":["1774910502137292401","1774910502137791984","1774910502137814556","1774910502137838788"]},{"stackIndex":6,"attributeIndices":[144,145,22],"values":["6367","8191","11041","40299","124795"],"timestampsUnixNano":["1774910502134851684","1774910502134923657","1774910502134941474","1774910502135110683","1774910502135243454"]},{"stackIndex":83,"attributeIndices":[144,145,22],"values":["570685"],"timestampsUnixNano":["1774910502136961225"]},{"stackIndex":21,"attributeIndices":[144,145,22],"values":["36587"],"timestampsUnixNano":["1774910502137015255"]},{"stackIndex":6,"attributeIndices":[144,145,12],"values":["21428"],"timestampsUnixNano":["1774910502131218836"]},{"stackIndex":6,"attributeIndices":[144,145,15],"values":["24285","48395","41239","32698","31081","22981"],"timestampsUnixNano":["1774910502138105195","1774910502138183818","1774910502138232252","1774910502138270037","1774910502138317780","1774910502138361034"]},{"stackIndex":6,"attributeIndices":[144,145,21],"values":["1036611","49501","30852","33321","5622","36059","33432","3879","5002","172986","78017","16757"],"timestampsUnixNano":["1774910502133618585","1774910502133682510","1774910502133720666","1774910502133759767","1774910502133771392","1774910502133813811","1774910502133888957","1774910502133918097","1774910502133954214","1774910502134235625","1774910502134325164","1774910502134351067"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2014633"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[146,147,6],"values":["15448980","15449010","15618353","15482554","15334634","15393690","15700494","15462062","15437433","15373837","15545694","15441837","15547268","15437311","15485412","15335440","15466943","15365546","15454524","15387744","15546353","13200653","407373","1446846","123414","15462882","15553936","15574111","15374638","15459007","15457818","15524550","15361612","15617358","15336777","15516615","15505876","15433965","15582733","15161221","15661740","15571833","15308266","15763768","15052812","15474856","15607200","15274202","8615091","6731391","15339805","15525683","15385849","15706385","15405986","15280907","15382101","15310215","15592830","15344129","15395525","15365603","15429969","15360435","15655268","15458311","15316062","15378236","15507259","15519511","15292657","15530549","15384355","15259767","15491152","15247125","15463892","15335232","15506640","15577371","15423345","15616123","15290584","15409607","15594644","15445612","15672071","15694037","15443173","15322010","15381380","15475928","15629905","15500054","15423170","15507798","13412268","58549","2013505","15458113","15414276","15463026","15590297","15350608","15466820","15427057","15544743","15618393","15682230","15438366","15549290","15438464","15441519","15396361","15719816","15523846","15550325","15422861","15452866"],"timestampsUnixNano":["1774910497603518990","1774910497620210159","1774910497637037301","1774910497653786657","1774910497670192882","1774910497886907671","1774910497903778562","1774910497920286261","1774910497937038508","1774910497953597916","1774910497970294487","1774910497987000866","1774910498003799093","1774910498020256025","1774910498037030234","1774910498053584813","1774910498070295468","1774910498087009465","1774910498103709299","1774910498120208227","1774910498137076586","1774910498151448634","1774910498151942666","1774910498153448895","1774910498153661276","1774910498170256513","1774910498187102569","1774910498203730801","1774910498220295180","1774910498237001414","1774910498253714392","1774910498320259289","1774910498336821601","1774910498353757123","1774910498370226165","1774910498387082178","1774910498403708329","1774910498420312940","1774910498437181272","1774910498453386831","1774910498470510955","1774910498487001553","1774910498503519117","1774910498587131071","1774910498603287893","1774910498620214101","1774910498636985587","1774910498653506555","1774910498663438715","1774910498670237519","1774910498687052333","1774910498853671586","1774910498870250990","1774910498887114820","1774910498903579469","1774910498920147738","1774910498936946623","1774910498953521070","1774910498970337598","1774910498986905856","1774910499003585632","1774910499020211109","1774910499037037701","1774910499053569104","1774910499070415613","1774910499087071017","1774910499103531110","1774910499120145416","1774910499137010943","1774910499153757436","1774910499170168239","1774910499187106815","1774910499203600241","1774910499220126906","1774910499236971521","1774910499253477730","1774910499270269902","1774910499286868859","1774910499636911725","1774910499653727053","1774910499670220254","1774910499687118381","1774910499703519248","1774910499720203639","1774910499853665924","1774910500036790144","1774910500337024505","1774910500487069981","1774910500503518673","1774910500520069291","1774910500536776026","1774910500553422184","1774910500570265213","1774910500586818020","1774910500603438377","1774910500786784085","1774910500801360425","1774910500801459454","1774910500803510454","1774910500886842362","1774910500903418554","1774910500920163901","1774910500936970171","1774910500953433553","1774910500970176091","1774910500986867530","1774910501003578572","1774910501020340996","1774910501187028505","1774910501203581017","1774910501220325827","1774910501236908763","1774910501253545296","1774910501270150601","1774910501287013642","1774910501436810118","1774910502170155061","1774910502186817034","1774910502203434680"]},{"stackIndex":6,"attributeIndices":[146,147,17],"values":["15342220","15452065","15301320","15252841","15296393","15526236","15572900","15197005","15321071","15443827","15342981","15197764","15400800","15244799","15379301","15352642","15628754","15388648","15446685","15289690","15277853","15300300"],"timestampsUnixNano":["1774910497703533055","1774910497720186189","1774910497736909693","1774910497753500923","1774910497770163830","1774910497786920045","1774910497803710358","1774910497820126341","1774910497836925971","1774910497853584750","1774910497870245108","1774910499870084536","1774910499886968980","1774910499903513829","1774910499920278321","1774910499936885504","1774910499953742942","1774910499970164909","1774910499986914596","1774910500003447837","1774910500020138888","1774910501770090860"]},{"stackIndex":84,"attributeIndices":[146,147,18],"values":["1092299","1151206","1280174","1204667","1014342","1105332","960920","951146","928269","1123531","807451","1302817","1145852","994817","1194359","1105067","920086","1223038","1140970","1160787","1037919","892181","1112168","961084","988535","1169330","1110492","978380","943665","1101389","880087","1138554","1039825","954665","1106595","944903","1022970","1059813","966868","1113985"],"timestampsUnixNano":["1774910498271469922","1774910498288151578","1774910498521511901","1774910498538163517","1774910498554659319","1774910499538102867","1774910499554709050","1774910499571500701","1774910499588126733","1774910499604807332","1774910499738178789","1774910499754741210","1774910499771335374","1774910499788127825","1774910499804813112","1774910499821431522","1774910500054785915","1774910500071491652","1774910500088112673","1774910500104693906","1774910500121473408","1774910500138154120","1774910500154731465","1774910500171475900","1774910500188104609","1774910500204658381","1774910500221438935","1774910500237982208","1774910500254740929","1774910500271370601","1774910500288063934","1774910500304741100","1774910500354680939","1774910500454757360","1774910500621336224","1774910502221256710","1774910502238123727","1774910502254571353","1774910502271271640","1774910502288151517"]},{"stackIndex":6,"attributeIndices":[146,147,19],"values":["15503879","15318374","15146039","15479944","15461519","15315249","15512237","15481496","15861900","15448914","15512941","15523508","15803185","15583009","15462034","15468476","15586765","15385752","15507707"],"timestampsUnixNano":["1774910498786968800","1774910498803612717","1774910498820113118","1774910498836935090","1774910501820102625","1774910501836806239","1774910501853457270","1774910501870074073","1774910501887154014","1774910501903382393","1774910501920094949","1774910501970184449","1774910501987070091","1774910502003515852","1774910502020066946","1774910502036863488","1774910502053626005","1774910502070122731","1774910502086835392"]},{"stackIndex":84,"attributeIndices":[146,147,15],"values":["860005","1053221","1159359","1139454","1019019","1085386"],"timestampsUnixNano":["1774910498754751599","1774910499304740294","1774910499321500695","1774910499338084031","1774910499354827985","1774910501737988960"]},{"stackIndex":6,"attributeIndices":[146,147,9],"values":["14582204","15473529","15549738","15532526","15487144","15410404","15446790","15452256","15420839","15492687","15513514","15498584","15464926","15632922","15337271","15478142","15246031","15289268"],"timestampsUnixNano":["1774910499503462199","1774910500820085106","1774910500836817649","1774910500853548395","1774910501036819198","1774910501053536809","1774910501070232951","1774910501086951730","1774910501103552190","1774910501120276896","1774910501136880765","1774910501153589372","1774910501320142504","1774910501336980195","1774910501353418988","1774910501370194653","1774910501386723918","1774910501403422097"]},{"stackIndex":6,"attributeIndices":[146,147,16],"values":["15290435","15429155","15588083","15477950","15304647","15533186","15258467","15199579","15463827","15284946","15381849","15707170"],"timestampsUnixNano":["1774910497553518212","1774910497570223175","1774910497587038167","1774910498703577730","1774910498720240419","1774910498737109940","1774910498753537291","1774910500386774068","1774910500403505557","1774910500420152659","1774910500436887926","1774910502153628439"]},{"stackIndex":6,"attributeIndices":[146,147,20],"values":["15525653","14771286","15041360","14775537","15234971","15436496","15099623","15497839","15339883","15462573","15569906","15491445","15428831","15568318","15415877","15528234","15483617","15613848","15404131","15492900","15513105","15369701","15306108","15474869","15231574","15559208","15169208","15319648","15433345","15133584","15200874","104904","8417896"],"timestampsUnixNano":["1774910499387295281","1774910499403776137","1774910499420432995","1774910499436936239","1774910499453887808","1774910499470446580","1774910499487204709","1774910500653576390","1774910500670137712","1774910500686814339","1774910500703531042","1774910500720117207","1774910500736871295","1774910500753713406","1774910500770056406","1774910501470156274","1774910501486757454","1774910501503564649","1774910501520129534","1774910501536856682","1774910501553661794","1774910501570164105","1774910501586831338","1774910501603678899","1774910501620080009","1774910501637039415","1774910501653359941","1774910501670119834","1774910501686832210","1774910501703325895","1774910501720057270","1774910501928329487","1774910501936780969"]},{"stackIndex":84,"attributeIndices":[146,147,6],"values":["1076313","1055963","1013904","826094","978781","987992","767356","1057217","923930","993595","1000526","984466","838910","981756","946583","1037896","1034001","968874","813977","1121237","903816","893859","1042547","769417","877296","1019345","994561","865033","958469","963066","1134313","846427","1102333","856511","910567","970494","744440","1255531","689714","948408","1046219","809273","1280576","946028","990021","1117241","1272358","933349","947885","848155","955249","1193621","1003276","1001807","901973","1016317","1045265","1064327","899065","967875","844767","934078","1017364","1162522","995950","850349","1189120","833592","945211","1144999","990903","1144125","979623","1059262","888131","1056819","831679","1075326","1115053","935545","810391","987311","1178417","1037638","1063969","860646","1008129","1075057","1026516","875537","1003674","1127821","1045027","957414","1088349","1078928","1028647","976126","978534","865134","1011167","863723","951066","1035130","935428","768300","1074707","1078955","951651","1025902"],"timestampsUnixNano":["1774910497604701958","1774910497621361276","1774910497638207756","1774910497654758941","1774910497671356352","1774910497888016664","1774910497904731645","1774910497921499097","1774910497938121728","1774910497954690624","1774910497971452377","1774910497988149728","1774910498004749225","1774910498021448848","1774910498038143810","1774910498054748112","1774910498071499848","1774910498088143438","1774910498104722827","1774910498121440621","1774910498138143031","1774910498154698435","1774910498171435204","1774910498188047573","1774910498204817391","1774910498221436825","1774910498238152422","1774910498254741640","1774910498304668660","1774910498321375757","1774910498338073211","1774910498354778023","1774910498371468211","1774910498388104442","1774910498404776249","1774910498421479070","1774910498438109706","1774910498454772458","1774910498471355537","1774910498488113222","1774910498504692383","1774910498588116458","1774910498604675082","1774910498621298139","1774910498638132880","1774910498654747770","1774910498671644490","1774910498854769933","1774910498871342910","1774910498888089578","1774910498904763748","1774910498921464002","1774910498938109015","1774910498954674596","1774910498971440414","1774910498988088669","1774910499004759531","1774910499021435190","1774910499038102155","1774910499054675219","1774910499071468607","1774910499088126895","1774910499104671712","1774910499121422616","1774910499138139667","1774910499154771617","1774910499171484366","1774910499188109130","1774910499204760167","1774910499221397818","1774910499238124288","1774910499254737376","1774910499271407581","1774910499638081239","1774910499654727723","1774910499671404539","1774910499688119655","1774910499704727134","1774910500321300963","1774910500338101331","1774910500488010829","1774910500504660735","1774910500521348928","1774910500537909673","1774910500554584928","1774910500571252848","1774910500587954028","1774910500604617105","1774910500787905881","1774910500871320009","1774910500887947734","1774910500904640039","1774910500921314662","1774910500938023078","1774910500954637164","1774910500971375067","1774910500987990379","1774910501004663795","1774910501171292011","1774910501188050594","1774910501204706657","1774910501221374471","1774910501238016157","1774910501254685952","1774910501271242616","1774910501287936962","1774910501421238271","1774910502171332450","1774910502187905906","1774910502204573565"]},{"stackIndex":84,"attributeIndices":[146,147,17],"values":["1038688","1038430","1225185","1138267","1199563","1074150","1094115","1006980","1331003","1080654","1083435","817655","1328725","1067869","1184077","981631","1064860","827658","1100919","1012786","1174923","1281704","1036592"],"timestampsUnixNano":["1774910497688088070","1774910497704676465","1774910497721531604","1774910497738174239","1774910497754813086","1774910497771350231","1774910497788097477","1774910497804850538","1774910497821553808","1774910497838095641","1774910497854828037","1774910499854787659","1774910499871519195","1774910499888183742","1774910499904820774","1774910499921404462","1774910499938051169","1774910499954711418","1774910499971390608","1774910499988068565","1774910500004788149","1774910501754751860","1774910501771214350"]},{"stackIndex":6,"attributeIndices":[146,147,18],"values":["15277113","15252109","15304113","15608645","15507266","15370813","15588925","15434661","15339863","15416348","15753662","15033970","15233564","15566804","15213828","15251600","15431073","15663034","15267086","13421673","1837701","7789915","7394789","15505228","15475741","15237508","15505053","15347843","12605279","2497889","15383689","15346807","15566030","15310021","15626354","15282908","15272125","15633508","15229159","15598298","15573771"],"timestampsUnixNano":["1774910498286843477","1774910498536842642","1774910498553541612","1774910498570307783","1774910499536878666","1774910499553563154","1774910499570368137","1774910499587036815","1774910499603571595","1774910499620293379","1774910499737193629","1774910499753330712","1774910499770048159","1774910499786972591","1774910499803450205","1774910499820144864","1774910499836966149","1774910500053677169","1774910500070153243","1774910500084990915","1774910500086867991","1774910500095972758","1774910500103410958","1774910500120277308","1774910500137095015","1774910500153505252","1774910500170307618","1774910500186950350","1774910500200817079","1774910500203369146","1774910500220101880","1774910500236880372","1774910500253594713","1774910500270154503","1774910500287048803","1774910500303444134","1774910500470113511","1774910502236947381","1774910502253407167","1774910502270207898","1774910502286893191"]},{"stackIndex":84,"attributeIndices":[146,147,19],"values":["1129598","1098219","1142564","1077049","1230099","985618","1013008","1098001","626755","1090816","1046612","973561","944079","714479","946117","1198683","1029008","917532","1051829","967677","16608718"],"timestampsUnixNano":["1774910498788197993","1774910498804852288","1774910498821380859","1774910501804598660","1774910501821412785","1774910501837885997","1774910501854552678","1774910501871245901","1774910501887884404","1774910501904547668","1774910501921223193","1774910501954604582","1774910501971220195","1774910501987879600","1774910502004559412","1774910502021331930","1774910502037983886","1774910502054673114","1774910502071266192","1774910502087886612","1774910502104550352"]},{"stackIndex":6,"attributeIndices":[146,147,15],"values":["15392851","15430616","15382561","15273070","15500135","15255809"],"timestampsUnixNano":["1774910498770242164","1774910499303533057","1774910499320208386","1774910499336851992","1774910499353632343","1774910499370164871"]},{"stackIndex":84,"attributeIndices":[146,147,9],"values":["1154306","1059652","1067519","1076504","1149303","1101719","1064129","997564","1064977","911231","1049387","1016187","922621","1081749","899177","1140043","1121989","1248880","1208434","1071485","1030874"],"timestampsUnixNano":["1774910499504745482","1774910500821233254","1774910500837980366","1774910500854713177","1774910501038064828","1774910501054725463","1774910501071408220","1774910501088060081","1774910501104716555","1774910501121296345","1774910501138028029","1774910501154722334","1774910501304622142","1774910501321303373","1774910501338015874","1774910501354655129","1774910501371407403","1774910501388062975","1774910501404737440","1774910502121207661","1774910502304546448"]},{"stackIndex":84,"attributeIndices":[146,147,16],"values":["1112338","1044907","1041646","1140670","889602","1128754","1107800","1109466","1170699","1012579","909179"],"timestampsUnixNano":["1774910497554738067","1774910497571390336","1774910498704829732","1774910498721501713","1774910498738170064","1774910500371439109","1774910500387992007","1774910500404770131","1774910500421426780","1774910500438025546","1774910502137877069"]},{"stackIndex":84,"attributeIndices":[146,147,20],"values":["1033216","1436488","1365378","1450901","1507041","926957","1397683","956163","1004192","1071795","1008167","943803","1195409","1125737","758785","943262","968457","1073043","1001169","1111952","1147057","915317","1221853","1217110","993192","1213000","938425","1257910","1119621","1110275","1366839","1291940","1054021"],"timestampsUnixNano":["1774910499371719082","1774910499388883508","1774910499405285547","1774910499422052834","1774910499438528034","1774910499454935597","1774910499471998192","1774910500637990601","1774910500654700286","1774910500671291250","1774910500687917144","1774910500704578089","1774910500721384267","1774910500738079816","1774910500754588423","1774910501454564828","1774910501471222769","1774910501487904930","1774910501504650118","1774910501521323529","1774910501538082516","1774910501554695642","1774910501571461728","1774910501588134366","1774910501604764288","1774910501621391092","1774910501638096112","1774910501654719808","1774910501671323954","1774910501688084065","1774910501704784859","1774910501721434468","1774910501937911292"]},{"stackIndex":84,"attributeIndices":[146,147,22],"values":["675996"],"timestampsUnixNano":["1774910501787895910"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1179"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":12,"attributeIndices":[148,149,18],"values":["412747985","27100313","272301","21372561","261863443","334115012","120749","8892569","15693","6754","365830","98754","596951","371549","320341","18142110","27726245","1140561","350284","420241","711188","28414544","1073981","6092057","212130","297879","26129466","1044628","254802424","412685449","1722497","742990","1494224","606982772","103443786","4419858","10585011","100005533","4594810","557104","273853","184240447","413943792","528738","952047","704423","955356","552660","484319","8180572","13024067","107534845","22546653","28129588","225081237","3096125","711890961","3992820","1683209","3897604","2444759"],"timestampsUnixNano":["1774910497930073565","1774910497957283554","1774910497957692062","1774910497979089199","1774910498241023292","1774910498575236342","1774910498575412155","1774910498584324837","1774910498584467527","1774910498584531693","1774910498584907336","1774910498585092144","1774910498585704392","1774910498586163595","1774910498586571577","1774910498604757207","1774910498632532838","1774910498633754146","1774910498634160277","1774910498634627212","1774910498635381371","1774910498663855651","1774910498664971275","1774910498671108105","1774910498671382108","1774910498671703154","1774910498697882983","1774910498699000239","1774910498953855855","1774910499366643886","1774910499368491937","1774910499369377512","1774910499371020380","1774910499978074954","1774910500081638303","1774910500086112821","1774910500096732282","1774910500196782056","1774910500201449721","1774910500202065256","1774910500202372236","1774910500386694199","1774910500800690904","1774910500801282599","1774910500802263835","1774910500803019422","1774910500804005542","1774910500804579186","1774910500805084984","1774910500813299904","1774910500826372360","1774910500933935492","1774910500956575478","1774910500984759903","1774910501209885228","1774910501213031815","1774910501924956291","1774910501928972920","1774910501930669255","1774910501934645789","1774910501937168085"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019853"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[150,151,20],"values":["7955","5885","5740","136199"],"timestampsUnixNano":["1774910502132614074","1774910502132655212","1774910502132865516","1774910502133267669"]},{"stackIndex":85,"attributeIndices":[150,151,20],"values":["94478"],"timestampsUnixNano":["1774910502133755589"]},{"stackIndex":6,"attributeIndices":[150,151,21],"values":["3924","13644","31620","152129","44015","76127","21622","17570","17372","8005","1168804"],"timestampsUnixNano":["1774910502134079287","1774910502134247959","1774910502134287608","1774910502134476524","1774910502134548511","1774910502134915848","1774910502134951641","1774910502135115709","1774910502135140252","1774910502135232980","1774910502136408193"]},{"stackIndex":43,"attributeIndices":[150,151,21],"values":["13765"],"timestampsUnixNano":["1774910502136544620"]},{"stackIndex":6,"attributeIndices":[150,151,17],"values":["15577","4811","5525","56027","30423"],"timestampsUnixNano":["1774910502131023198","1774910502131052769","1774910502131101976","1774910502131179218","1774910502131230160"]},{"stackIndex":6,"attributeIndices":[150,151,22],"values":["72634"],"timestampsUnixNano":["1774910502131819907"]},{"stackIndex":22,"attributeIndices":[150,151,22],"values":["8049"],"timestampsUnixNano":["1774910502132217601"]},{"stackIndex":86,"attributeIndices":[150,151,20],"values":["18121"],"timestampsUnixNano":["1774910502132505155"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2019855"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":22,"attributeIndices":[152,153,23],"values":["56598"],"timestampsUnixNano":["1774910502130678507"]},{"stackIndex":6,"attributeIndices":[152,153,12],"values":["1307062"],"timestampsUnixNano":["1774910502132400195"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2013346"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":132,"unitStrindex":133},"samples":[{"stackIndex":53,"attributeIndices":[154,155,22],"timestampsUnixNano":["1774910499711373961"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{"typeStrindex":131,"unitStrindex":2},"period":"50000000"},{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":87,"attributeIndices":[154,155,20],"values":["8346"],"timestampsUnixNano":["1774910502130367982"]},{"stackIndex":88,"attributeIndices":[154,155,22],"values":["328152"],"timestampsUnixNano":["1774910499770044997"]},{"stackIndex":6,"attributeIndices":[154,155,20],"values":["1805108","501271","388372","225373","37164","352950","136028","111044","13258142","1371439","3861045","458250","254719","648009","407032","381832","339819","234179","340761","398221","265570","1565342","3572731","1378255","4250391","896126","634666","333203","843093","167322","221647","112169","469123","5623825","2071270","1440910","1465073","2987184","1388206","1431033","26673","112383","80339","36850","534340","1177649","66647269","34568712"],"timestampsUnixNano":["1774910500984962434","1774910500985505863","1774910500985913808","1774910500986181932","1774910500986240784","1774910500986621363","1774910500986787639","1774910500986913134","1774910501000194376","1774910501001587370","1774910501005466687","1774910501005988010","1774910501105935024","1774910501106621925","1774910501107044100","1774910501107459758","1774910501107829921","1774910501108095930","1774910501108443354","1774910501108898479","1774910501109169704","1774910501110749724","1774910501114328580","1774910501115743117","1774910501120021877","1774910501120944718","1774910501121640843","1774910501122004804","1774910501122897459","1774910501123083275","1774910501123346488","1774910501123467088","1774910501123964902","1774910501727238241","1774910501729331187","1774910501730843769","1774910501732339944","1774910501735348204","1774910501736754479","1774910501738204904","1774910501738249643","1774910501738400113","1774910501738501084","1774910501738546781","1774910501739099817","1774910501740294987","1774910501806956962","1774910502129823514"]},{"stackIndex":6,"attributeIndices":[154,155,23],"values":["6089476","17923277","26199439","1708004","545643","786457","6267958","13169282","31040891","456919","7423649","5532440","442424","44964694","384951","20202","5535487","7902536","24588646","45078113","117374","472493","4434750","10172316","34770198","496763","970355","489130","374528","433907","520071","469189","873786","241092","298770","209003","955205","376477","678030","726913","652899","693076","721425","683985","386151","24935719","926425","5501","5415","13774","19692","10553","5383","5829","8168","5695","6392","8298","11181","12727","61223","59830"],"timestampsUnixNano":["1774910497676332478","1774910497694282436","1774910497720531283","1774910497722609529","1774910497723198458","1774910497724033750","1774910497730341878","1774910497743550362","1774910497774633090","1774910497775125445","1774910497782576945","1774910497788176987","1774910497788666784","1774910497833651096","1774910497834090291","1774910497834156882","1774910497839716080","1774910497847647067","1774910497872276284","1774910499600303061","1774910499600521213","1774910499601014996","1774910499605501253","1774910499615720448","1774910499650544134","1774910499651091472","1774910500353929812","1774910500355021428","1774910500355987710","1774910500356891420","1774910500357865712","1774910500358420302","1774910500359312857","1774910500359574753","1774910500360451211","1774910500360736385","1774910500361708151","1774910500362105915","1774910500363437506","1774910500364878028","1774910500366109153","1774910500367449143","1774910500368915253","1774910500801821838","1774910501808355938","1774910501833302340","1774910501834250246","1774910502137428852","1774910502137451690","1774910502137478812","1774910502137523007","1774910502137541913","1774910502137559819","1774910502137575407","1774910502137593054","1774910502137608076","1774910502137624732","1774910502137642612","1774910502137663583","1774910502137686406","1774910502137757386","1774910502137861789"]},{"stackIndex":61,"attributeIndices":[154,155,15],"values":["29583","20418","6306","6379"],"timestampsUnixNano":["1774910497885994653","1774910497886073397","1774910497886110453","1774910497886147988"]},{"stackIndex":6,"attributeIndices":[154,155,18],"values":["69197322","282790","6446375","28063816","16517636","295800","503437","5832818","17083225","35737740","28481980","27103741","466505","861432","4892808","44626335","384206","24639908","30609970","5671351","3510770","5828795","822418","892736","1129613","260842","437462","441125","475801","414030","417466","365943","373173","376695","465727","461255","321572","628505","634232","373583","1014996","123704","184717","660238","1030846","347971","526924","961810","1014062","971967","1112223","924648","2978703","1641041","1624578","2338919","1153775","237739","727868","1618601","21006464","367650","981778","742274","370379","1078306","17620","793534","4218612","7764054","1193111","6595778","471291","1159721","19801","268663","356464","7709","100098","52942","84941","77741","851531","149589","6953","497327","780388","1144766","5841","10839","5490","61872","37124","36049","30312","21948","19391","31427","68159","26145","46463","25739","21673","25154","21142","19958","18215","27544","75578","38275","23351","17471","35601","17320","29352","39706","30826","31965","72499","21556","4189419","9724552","38307137"],"timestampsUnixNano":["1774910499164771602","1774910499165099533","1774910499171591376","1774910499199687217","1774910499216257331","1774910499216605154","1774910499217156787","1774910499223038310","1774910499240156811","1774910499275959010","1774910499304496550","1774910499331627240","1774910499332154598","1774910499333070981","1774910499338006476","1774910499382660839","1774910499383099324","1774910499407761084","1774910499438410854","1774910499444144003","1774910499447686787","1774910499453552489","1774910500309743124","1774910500310651377","1774910500311796764","1774910500312074633","1774910500313069698","1774910500314030903","1774910500314912638","1774910500315721008","1774910500316602729","1774910500317438029","1774910500318258642","1774910500319078740","1774910500319966637","1774910500320844763","1774910500321584866","1774910500322705166","1774910500323840432","1774910500324313759","1774910500325344704","1774910500325483774","1774910500325688054","1774910500326374015","1774910500327419986","1774910500327783028","1774910500328328134","1774910500329306239","1774910500330337489","1774910500331328572","1774910500332459294","1774910500333414667","1774910500336414303","1774910500338087635","1774910500339764916","1774910500342134964","1774910500343318520","1774910500343589196","1774910500344333154","1774910500776506374","1774910500797537982","1774910500797919813","1774910500798908326","1774910500799658214","1774910500823466715","1774910500824559913","1774910500954703106","1774910500955536489","1774910500959777319","1774910500967616554","1774910500968851359","1774910500975507502","1774910500975998815","1774910500977211654","1774910500977260623","1774910500977558211","1774910500977959926","1774910500977989997","1774910500978117225","1774910500978184616","1774910500978292616","1774910500978375967","1774910500979242907","1774910500979441147","1774910500979462652","1774910500979992798","1774910502041492332","1774910502042653486","1774910502137931520","1774910502137950388","1774910502137976409","1774910502138046074","1774910502138114769","1774910502138174820","1774910502138223585","1774910502138261512","1774910502138309206","1774910502138369311","1774910502138650329","1774910502138685843","1774910502138763901","1774910502138796927","1774910502138848801","1774910502138903384","1774910502138953568","1774910502139004077","1774910502139053254","1774910502139109301","1774910502139212839","1774910502139260138","1774910502139290285","1774910502139343606","1774910502139408981","1774910502139447930","1774910502139518113","1774910502139577944","1774910502139638668","1774910502139688582","1774910502139788289","1774910502139816891","1774910502144012757","1774910502153747421","1774910502192074141"]},{"stackIndex":6,"attributeIndices":[154,155,22],"values":["5143530","29234047","11956256","3105570","291013","2456015","8215015","35645392","155594","423727","5361048","8071200","35242602","546806","1112290","5526586","10663005","34954514","203595","5099381","516285","522940","446327","183785","65401","854392","1070789","975347","1272799","1084827","1260776","1145851","1509561","1114313","3506317","1024641","1041566","702011","1462285","928007","1023738","1676463","1181675","742252","1375377","629130","643553","656078","1322858","866502","1296083","1098121","1556444","1285421","1096820","804969","746971","1618307","1426263","1261972","1642917","1368555","703019","508001","144258","142994","844258","353367","673192","174739","792307","115325","96487","282443","108871","2209865","306862","1169602","651762","584739","162645","448924","960218","4681273"],"timestampsUnixNano":["1774910499664088816","1774910499693374608","1774910499705399683","1774910499708551300","1774910499708870499","1774910499711354441","1774910499719611478","1774910499755296689","1774910499755549004","1774910499755990556","1774910499761397079","1774910499769497849","1774910499805574214","1774910499806160254","1774910499807319540","1774910499812880575","1774910499823575448","1774910499858575199","1774910499859036679","1774910499864172951","1774910500371460489","1774910500372629133","1774910500373202392","1774910500373399638","1774910500373478003","1774910500374351775","1774910500375446429","1774910500376443614","1774910500377724386","1774910500378832595","1774910500380117805","1774910500381283207","1774910500382807425","1774910500383937454","1774910500387458061","1774910500388521066","1774910500389589157","1774910500390306643","1774910500391783825","1774910500392740175","1774910500393778132","1774910500395469190","1774910500396667884","1774910500397424396","1774910500398811397","1774910500399457384","1774910500400121737","1774910500400788720","1774910500402123895","1774910500403002329","1774910500404309816","1774910500405429647","1774910500407008266","1774910500408311112","1774910500409434579","1774910500410257838","1774910500411011300","1774910500412649816","1774910500414118562","1774910500415401675","1774910500417065011","1774910500418461216","1774910500419199496","1774910501006875382","1774910501007035792","1774910501007209676","1774910501008068410","1774910501008451216","1774910501009131078","1774910501009363042","1774910501010163719","1774910501010315277","1774910501010433892","1774910501010721689","1774910501010860960","1774910501013077400","1774910501013430798","1774910501014608494","1774910501015888256","1774910501142403601","1774910501142610114","1774910501143073266","1774910501144767048","1774910501150101372"]},{"stackIndex":6,"attributeIndices":[154,155,19],"values":["1503384","958592","968114","986486","1047996","611279","743646","1141562","525984","1024148","856807","3665911","796094","1394537","1115971","3082354","3793739","718375","23998775","93257","624448","1349628","10509178","5267894","1079304","16631991","2224854","1325412","16211451","1834514","248735","34493189","6920453","776042","1694136"],"timestampsUnixNano":["1774910500421404153","1774910500422388809","1774910500423382701","1774910500424388428","1774910500425451629","1774910500426095509","1774910500426860729","1774910500428021344","1774910500428571204","1774910500429616629","1774910500430498274","1774910500434237100","1774910500435064762","1774910500436493741","1774910500437629429","1774910500440727590","1774910500444549756","1774910500445305599","1774910500469335350","1774910502043668236","1774910502195802821","1774910502197563135","1774910502208522590","1774910502214410031","1774910502215527066","1774910502232182439","1774910502235331634","1774910502237687063","1774910502254629774","1774910502257520965","1774910502257941665","1774910502292556758","1774910502299496664","1774910502300283415","1774910502301984638"]},{"stackIndex":6,"attributeIndices":[154,155,9],"values":["657321","3211933","760819","672790","2255824","297115","399795","174311","424679","3819634","10166682","5462610","611108","539326","1083026","338444","722161","465944","3434196","816627","1172075","916674","1023406","1142588","833932"],"timestampsUnixNano":["1774910500826521186","1774910500829742440","1774910500830510692","1774910500831189598","1774910500833462011","1774910500833798297","1774910500834567602","1774910500835212986","1774910500835964292","1774910500840264751","1774910500863561912","1774910500869059345","1774910500870151311","1774910500871280068","1774910500872887951","1774910500873780263","1774910500874797375","1774910500875845122","1774910500879582147","1774910500893170367","1774910500894361780","1774910500895296269","1774910500896337390","1774910500897497134","1774910500898348262"]},{"stackIndex":87,"attributeIndices":[154,155,17],"values":["73490"],"timestampsUnixNano":["1774910502131737534"]},{"stackIndex":89,"attributeIndices":[154,155,15],"values":["15469","5824","4843","4994"],"timestampsUnixNano":["1774910498111761116","1774910498111805723","1774910498111843284","1774910498111880206"]},{"stackIndex":6,"attributeIndices":[154,155,17],"values":["34782635","18987623","497332","36351476","232356863","5688960","17770948","26938297","512400","7601236","6638549","21633631","23377158","429500","8464255","5951070","1912179","41668352","2326976","212674","3369782","44300393","177442","786626","6469938","4372788","39963472","214571","7897182","6263544","2930369","5718070","40822941","1929804","1824892","236226","1553295","498906","1170279","780190","6592075","395325","47297","382501","5606850","1668421","1178256","1962166","444023","604299","237081","629413","1082922","1786166","1297554","313769","207167","2271014","1805429","885599","1696992","2524581","1730120","950766","2345836","5031801","2445455","1487641","63562675","4256311","4485418","1396092","1480937","7087859","789554","458025","689931","3928407","227925","1036572","413794","356588","347133","2178171","3145803","3296616","21594085","1763605","1511724","1774788","1237762","2913784","497009","2296833","862050","575494","291510","933096","1218526","1321837","1267798","1302566","1430227","1199901","1047646","1791728","2714965","2210949","1100846","2265374","516501","407086","1127689","953806","1321394","549126","502358","4351462","323989","30110","4290246","1018065","7473209","3146820","24159497","8751683","303657","6106075","7106852","57134","53420","504126","2637913","578510","9696104","21605925","2145856","547175","908142"],"timestampsUnixNano":["1774910498367596326","1774910498386616657","1774910498387170923","1774910498423587376","1774910498656096592","1774910498661820618","1774910498679625204","1774910498706600893","1774910498707180465","1774910498714844917","1774910498721519153","1774910498743185654","1774910498766617965","1774910498767103809","1774910498775606369","1774910498781588765","1774910498783530092","1774910498825251001","1774910498827617899","1774910498827867260","1774910498831269622","1774910498875597306","1774910498875801005","1774910498876617863","1774910498883113964","1774910498887519236","1774910498927516641","1774910498927772770","1774910498935720274","1774910498942033902","1774910498945051279","1774910498950793971","1774910498991639618","1774910498993608918","1774910498995543551","1774910498995812824","1774910500530715335","1774910500531280784","1774910500532960626","1774910500533835663","1774910500540480172","1774910500841517021","1774910500841583132","1774910500841980755","1774910500847789683","1774910501167308751","1774910501168807901","1774910501170795534","1774910501171249641","1774910501171895095","1774910501172145032","1774910501172807283","1774910501173902781","1774910501175700567","1774910501177005710","1774910501177329920","1774910501177575779","1774910501179867239","1774910501182103011","1774910501183603667","1774910501186360359","1774910501189696133","1774910501191973335","1774910501192961411","1774910501195323661","1774910501200373101","1774910501202835733","1774910501204337041","1774910501267913619","1774910501272202191","1774910501276706594","1774910501278120358","1774910501279617653","1774910501286731450","1774910501287606634","1774910501288086049","1774910501288853757","1774910501292806070","1774910501590044352","1774910501591091998","1774910501591514387","1774910501591875391","1774910501592228109","1774910501594410565","1774910501597564828","1774910501600870211","1774910501622478596","1774910501624278900","1774910501689538816","1774910501691344103","1774910501692602242","1774910501695533810","1774910501696053232","1774910501698927617","1774910501700331040","1774910501700949531","1774910501701259908","1774910501702247920","1774910501703483393","1774910501704834524","1774910501706117923","1774910501707441353","1774910501708887524","1774910501710104415","1774910501711159316","1774910501712962419","1774910501715702711","1774910501717932005","1774910501719047546","1774910501721327798","1774910501920175090","1774910501920854485","1774910501922229514","1774910501923315981","1774910501924759935","1774910501925737972","1774910501926655015","1774910501931497474","1774910501931849209","1774910501931911480","1774910501936212740","1774910501937357370","1774910501944836753","1774910501948810454","1774910501973688634","1774910501982483344","1774910501982804232","1774910501988937173","1774910501996072103","1774910501996144966","1774910501996218707","1774910501996725919","1774910501999373575","1774910501999964904","1774910502009688844","1774910502031302937","1774910502033465486","1774910502034028523","1774910502034953990"]},{"stackIndex":90,"attributeIndices":[154,155,17],"values":["133616"],"timestampsUnixNano":["1774910501184636536"]},{"stackIndex":91,"attributeIndices":[154,155,15],"values":["50865"],"timestampsUnixNano":["1774910502131347084"]},{"stackIndex":65,"attributeIndices":[154,155,15],"values":["5902"],"timestampsUnixNano":["1774910498111894909"]},{"stackIndex":92,"attributeIndices":[154,155,9],"values":["345156"],"timestampsUnixNano":["1774910502136901668"]},{"stackIndex":93,"attributeIndices":[154,155,20],"values":["21968","109744"],"timestampsUnixNano":["1774910502130885212","1774910502131020218"]},{"stackIndex":6,"attributeIndices":[154,155,16],"values":["4725699","1676698","2659945","26509005","2211411","481594","996758","3310250","9388726","398189","139105","26171268","805586","579640","3499475","1258212","1237042","1504323","1939330","13389483","945571","865232","1045181","910589","13257351","36627","126509","6855","659487","21976","15991","1998604","860399","459325","543314","772849","1045166","637918","5444415","705559","1236034","1194878","4380400","1628546","105842","100606","353321","780691","920129","8695","13676","207804","276328","1037382","6915351","962025","6831510"],"timestampsUnixNano":["1774910500624736316","1774910500626431471","1774910500629097388","1774910500655623468","1774910500657882165","1774910500658420645","1774910500659613775","1774910500663141460","1774910500673409198","1774910500674600342","1774910500674767097","1774910500700967837","1774910500701791501","1774910500702381292","1774910500705888341","1774910500707157235","1774910500708411993","1774910500709925587","1774910500711883120","1774910500725292265","1774910500726258496","1774910500727145026","1774910500728214396","1774910500729147266","1774910500742427289","1774910500742487759","1774910500742641931","1774910500742677558","1774910500743816312","1774910500744269670","1774910500744562895","1774910500746568362","1774910500747451230","1774910500747928350","1774910500749053451","1774910500750443739","1774910500752108985","1774910500753347968","1774910500759542464","1774910500760861674","1774910500762617588","1774910500764387384","1774910500769332023","1774910500771318706","1774910500771494793","1774910500771621290","1774910500771980759","1774910500772777368","1774910500773705128","1774910500773724486","1774910500773746192","1774910500773960574","1774910500800727820","1774910501294202318","1774910501301139063","1774910501302678981","1774910501310100560"]},{"stackIndex":6,"attributeIndices":[154,155,12],"values":["356542","1241561","441133","2283594","1389969","819324","1211640","348138","321529","386340","443420","766697","866519","744895","1224415","2364559","1496554","2134983","5871109","991141","1038289","1125617","1138620"],"timestampsUnixNano":["1774910500810814959","1774910500812067990","1774910500884357167","1774910500886735503","1774910500888139902","1774910500888981977","1774910500890386409","1774910500890784429","1774910502047297002","1774910502048069803","1774910502048561613","1774910502049336868","1774910502050225205","1774910502050980838","1774910502052216649","1774910502054607459","1774910502056130859","1774910502058295387","1774910502064203057","1774910502065206062","1774910502066253490","1774910502067388249","1774910502068569180"]},{"stackIndex":93,"attributeIndices":[154,155,15],"values":["22244"],"timestampsUnixNano":["1774910502131204910"]},{"stackIndex":94,"attributeIndices":[154,155,23],"values":["12037294"],"timestampsUnixNano":["1774910497884652976"]},{"stackIndex":6,"attributeIndices":[154,155,21],"values":["8303","4684"],"timestampsUnixNano":["1774910502137353845","1774910502137373086"]},{"stackIndex":93,"attributeIndices":[154,155,17],"values":["88360"],"timestampsUnixNano":["1774910502132313379"]},{"stackIndex":95,"attributeIndices":[154,155,17],"values":["127526"],"timestampsUnixNano":["1774910500883621612"]},{"stackIndex":93,"attributeIndices":[154,155,9],"values":["27862","17950"],"timestampsUnixNano":["1774910502135483552","1774910502135524859"]},{"stackIndex":93,"attributeIndices":[154,155,22],"values":["176921","129831"],"timestampsUnixNano":["1774910502132630484","1774910502133738033"]},{"stackIndex":6,"attributeIndices":[154,155,6],"values":["29526374","56337419","340541","1758191","16868306","28029926","437645","44500719","130971","1240923","5757001","42416902","44625716","436979","12330816","221370558","146538","5270194","45144453","101412665","1715764","1397288","982212","918258","924238","843476","5866053","5354881","477423","3588169","1016876","9038821","632697","10410296","1196430","10788776","7905267","822227","940383","1175115","998315","835355","1130273","1750066","1478980","886454","466539","318694","1690354","1854023","1397116","1303008","3925823","2444654","955377","10239815","3136414","990050","2935540","2062750","428876","2878495","200999","214517","89166","1660770","1170209","551649","611479","979160","1559853","602149","4104264","417205","7085","185355","4067470","116542","440709","248711","231514","452215","28880551","6163869","188201","2525695","3173339","1026514","705042","346749","4468172","2180531","903720","663927","486433","941528","3727012","4139102","3037852","12312806","253296"],"timestampsUnixNano":["1774910497565101733","1774910497621491426","1774910497621856982","1774910497623644210","1774910497640535244","1774910497668602393","1774910497669103608","1774910499043489336","1774910499043651622","1774910499044951116","1774910499050748859","1774910499093200784","1774910499914575716","1774910499915062370","1774910499927450733","1774910500148870907","1774910500149073164","1774910500154379082","1774910500199550067","1774910500301077002","1774910500302824917","1774910500304253398","1774910500305253049","1774910500306190487","1774910500307131736","1774910500307990930","1774910500546487034","1774910500551979931","1774910500552487688","1774910500556088737","1774910500557182273","1774910500566233612","1774910500566990535","1774910500577430497","1774910500578672035","1774910500589498571","1774910500597706208","1774910500899331958","1774910500900289768","1774910500901486828","1774910500902501064","1774910500903351524","1774910500904496804","1774910500906262444","1774910500907770279","1774910500909298175","1774910500910291601","1774910500910658700","1774910500912376684","1774910500915165705","1774910500916689201","1774910500918023620","1774910500922530275","1774910500925659541","1774910500927293229","1774910500938247374","1774910500941420503","1774910500942434354","1774910500945938406","1774910500948554873","1774910500949017626","1774910500951941101","1774910500952169907","1774910500952437045","1774910500952533989","1774910500954211470","1774910500982624631","1774910501124768225","1774910501125402957","1774910501126431014","1774910501128012855","1774910501129569184","1774910501133720991","1774910501134194176","1774910501134228257","1774910501134443572","1774910501138517249","1774910501138668747","1774910501139123862","1774910501139403655","1774910501139642017","1774910501140130163","1774910501866021196","1774910501872361287","1774910501872676264","1774910501875444395","1774910501879056344","1774910501880748533","1774910501881492008","1774910501881863414","1774910501886357274","1774910501888562086","1774910501890257471","1774910501891597735","1774910501892748350","1774910501894337633","1774910501898714376","1774910501903498158","1774910501906550063","1774910501919039315","1774910501919362977"]},{"stackIndex":61,"attributeIndices":[154,155,23],"values":["19375","14888","11894","12504","12100","10900","11024"],"timestampsUnixNano":["1774910497885335539","1774910497885397731","1774910497885445040","1774910497885514935","1774910497885564284","1774910497885612921","1774910497885658591"]},{"stackIndex":6,"attributeIndices":[154,155,15],"values":["5230867","20124409","10982642","13780916","517440","9166913","5278659","763646","44447490","583267","233826","6206633","44160688","149470","113731","6243944","1635308","44046652","525982","9438664","854064","5126038","42941578","416387","1080784","225527","5324635","27579975","17044403","1570019","82547","3927473","44844973","149773","1750557","10237062","3850486","1666718","34837174","471207","9238161","5988836","7152513","37314753","408330","449070","629071","464037","768444","491104","908168","71667","444236","585439","3178826","356182","231730","509703","5606444","322736","657702","1092271","696088","1221433","438664","464246","466833","163781","562324","613463","859660","4752052","193584","149821","742823","7154243","19551497","2885823","824532","1443327","318397","6878428","548294","244983","395657","708810","1155097","608693","3091454","2745342","13695149","1036092","799013","1325472","3209517","127213","320126","370853","184084","986769","3787202","620954","207883","3610000","1774856","2709291","923205","457892","797769","278794","1062749","596981","363466","19097","252680","1456444","1707590","662513","388628","611442","1194426","1283364","567390","616755","1167641","913946","1545146","2722995","2781437","1241246","370615","201531","1423071","654737","388071","540729","7193","445490","717609","356063","2137950","12237744","1739890","2622128","1162966","93431951","5639258","4081057","370587","607939","360706","384992","241548","353635","295586","247747","809323","2515330","500353","359606","211249","154943","676950","209082","493891","276936","486163","1741395","483589","1494918","1020540","1269037","1473867","744417","893176","1184108","920562","1217837","1528518","48846","705509","1221787","750141","1174080","1284566","787398","1180934","1017296","733354","741217","606924","652266","796691","971735"],"timestampsUnixNano":["1774910497891397542","1774910497911552798","1774910497922649677","1774910497936524796","1774910497937102749","1774910497946325576","1774910497951640191","1774910497952444616","1774910497996928862","1774910497997560298","1774910497997833455","1774910498004088327","1774910498048285948","1774910498048494243","1774910498048630481","1774910498054899220","1774910498056565255","1774910498100637033","1774910498101226932","1774910498110724259","1774910498111623946","1774910498117068710","1774910498160034144","1774910498160502099","1774910498161611321","1774910498161919915","1774910498167279274","1774910498194891175","1774910498211987621","1774910498213605974","1774910498213728203","1774910498217684226","1774910498262553625","1774910498262746361","1774910498264534367","1774910498274798541","1774910498278679126","1774910498280371001","1774910499488622624","1774910499489158783","1774910499498457767","1774910499504553122","1774910499511735462","1774910499549077236","1774910499549529353","1774910499549999233","1774910500345591739","1774910500346439894","1774910500347669896","1774910500348245296","1774910500349179204","1774910500349276470","1774910500350173077","1774910500351239847","1774910500472911723","1774910500473403381","1774910500473973356","1774910500474774227","1774910500480762065","1774910500481438407","1774910500482295345","1774910500483497799","1774910500484343300","1774910500485746209","1774910500486248721","1774910500486726835","1774910500487216351","1774910500487409348","1774910500488381011","1774910500489246003","1774910500490132801","1774910500495165735","1774910500495619185","1774910500495792211","1774910500496707405","1774910500504163936","1774910500524599738","1774910500527729093","1774910500528807873","1774910501021472194","1774910501021827668","1774910501028776204","1774910501029350065","1774910501029646621","1774910501030067483","1774910501030820691","1774910501031998059","1774910501032645774","1774910501035757125","1774910501039028902","1774910501053199063","1774910501054649930","1774910501055916076","1774910501057275446","1774910501060495783","1774910501060638175","1774910501060988989","1774910501061415505","1774910501061618052","1774910501062641694","1774910501066449372","1774910501067114444","1774910501067343684","1774910501070985058","1774910501072780430","1774910501075526002","1774910501076507053","1774910501076991299","1774910501077843061","1774910501078152328","1774910501079277165","1774910501079906137","1774910501080326744","1774910501080374981","1774910501080666878","1774910501152396434","1774910501154474747","1774910501155559541","1774910501156247508","1774910501157217474","1774910501158826031","1774910501160583836","1774910501161611228","1774910501162254334","1774910501163881287","1774910501165115959","1774910501312369539","1774910501315711808","1774910501318532766","1774910501319805539","1774910501320209206","1774910501320419964","1774910501321863543","1774910501322527113","1774910501322936159","1774910501323484398","1774910501323509019","1774910501323964561","1774910501324722169","1774910501325106283","1774910501327267014","1774910501339535377","1774910501341316117","1774910501344017679","1774910501345203380","1774910501438685944","1774910501631571554","1774910501635674314","1774910501636077393","1774910501636809026","1774910501637186935","1774910501637609648","1774910501637867420","1774910501638253983","1774910501638574177","1774910501638860815","1774910501639693035","1774910501642267982","1774910501642802664","1774910501643234667","1774910501643501724","1774910501643687594","1774910501644429554","1774910501644664162","1774910501645206307","1774910501645514627","1774910501646051064","1774910501647825610","1774910501648366646","1774910501649893225","1774910501651515372","1774910501653303322","1774910501655393682","1774910501656865983","1774910501658402579","1774910501660098000","1774910501661618781","1774910501663605616","1774910501665801100","1774910501665875510","1774910501667040509","1774910501668738428","1774910501669881444","1774910501671509847","1774910501673213157","1774910501674463194","1774910501676147401","1774910501677747198","1774910501679282048","1774910501680628493","1774910501681697691","1774910501682783622","1774910501683988548","1774910501685765789"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"287"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[156,157,6],"values":["2233191030","16626596","16623688","16840494","16486665","16487519","200055132","16488287","16701156","16713962","16557313","16453393","16772076","16627575","16498313","16680641","16655599","16507416","16776023","16541813","16494347","16649699","16664843","16481863","16701898","16550157","16682691","16555571","16666596","16522866","49825021","16683952","16606673","16710704","16601761","16577142","16616770","16651213","16563886","16547122","16521673","16714093","16499723","66528666","16820990","16380934","16590590","16789933","16524189","16841967","166376764","16646970","16473720","16715161","16632799","16625976","16606628","16468577","16773986","16561250","16597243","16706413","16546479","16482110","16807413","16497581","16499772","16681373","16684349","16576275","16633489","16599210","16585406","16529554","16710679","16509213","16686378","349812006","16650575","16597420","16659115","16673274","16493122","133234337","183201511","299953497","16792553","133135056","16645107","16630801","16574904","16460509","16653559","16634780","16638492","16605357","166575143","16633833","83404651","16573154","16649476","16637166","16656262","16586630","16688018","16537126","16653023","166579112","16758655","16570168","16647374","16558912","16583033","16497780","16683918","133213429","733282564","16726485","16551757","16570831"],"timestampsUnixNano":["1774910497588074486","1774910497604764358","1774910497621422806","1774910497638309910","1774910497654863539","1774910497671417155","1774910497871519061","1774910497888081897","1774910497904829166","1774910497921607012","1774910497938230288","1774910497954752552","1774910497971564519","1774910497988257409","1774910498004822470","1774910498021549114","1774910498038255384","1774910498054832022","1774910498071649938","1774910498088261254","1774910498104826345","1774910498121534807","1774910498138253532","1774910498154798791","1774910498171553822","1774910498188162122","1774910498204926088","1774910498221547406","1774910498238262726","1774910498254855168","1774910498304738496","1774910498321464590","1774910498338143910","1774910498354895877","1774910498371569883","1774910498388208343","1774910498404884912","1774910498421604116","1774910498438232413","1774910498454853516","1774910498471433694","1774910498488216679","1774910498504783583","1774910498571370064","1774910498588245017","1774910498604743049","1774910498621382082","1774910498638237875","1774910498654827379","1774910498671717402","1774910498838150848","1774910498854870646","1774910498871412225","1774910498888178587","1774910498904872415","1774910498921568975","1774910498938217287","1774910498954748829","1774910498971567628","1774910498988195354","1774910499004850743","1774910499021613556","1774910499038214885","1774910499054765120","1774910499071619611","1774910499088220054","1774910499104773654","1774910499121507788","1774910499138243510","1774910499154881967","1774910499171580663","1774910499188222578","1774910499204872854","1774910499221484881","1774910499238236578","1774910499254809658","1774910499271540249","1774910499621410593","1774910499638153685","1774910499654800910","1774910499671506806","1774910499688234761","1774910499704798109","1774910499838077227","1774910500021348241","1774910500321355841","1774910500338196978","1774910500471379505","1774910500488079002","1774910500504752992","1774910500521398033","1774910500537949193","1774910500554638780","1774910500571321971","1774910500588018720","1774910500604668739","1774910500771278283","1774910500787950356","1774910500871388330","1774910500888008121","1774910500904703925","1774910500921383062","1774910500938086189","1774910500954713058","1774910500971443835","1774910500988036702","1774910501004726062","1774910501171349725","1774910501188148608","1774910501204780593","1774910501221476528","1774910501238109183","1774910501254757949","1774910501271296921","1774910501288021243","1774910501421289832","1774910502154608408","1774910502171397702","1774910502187986193","1774910502204611483"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"85"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[158,159,12],"values":["3104893308","1010772","1659855954","3001843","165317224","454215512","225941549","9843638","3213239","34636172","62056428","364957790","347994717"],"timestampsUnixNano":["1774910498926516398","1774910498927573241","1774910500587491973","1774910500590507954","1774910500755844622","1774910501210532417","1774910501436488294","1774910501446545850","1774910501450494088","1774910501485509495","1774910501548558357","1774910501913543512","1774910502261560817"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"1288"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":96,"attributeIndices":[160,161,21],"values":["5090961716","109942172","102972581","104908552","103077572","104871234","103082553","103864222","103978473","103979674","103965161","104054587","103912493","104967151","102998888","104959889","103986901","102970091"],"timestampsUnixNano":["1774910500522485953","1774910500632491585","1774910500735495618","1774910500840489317","1774910500943587769","1774910501048489263","1774910501151595518","1774910501255486777","1774910501359487892","1774910501463487796","1774910501567482515","1774910501671552888","1774910501775489922","1774910501880483088","1774910501983504933","1774910502088485280","1774910502192493889","1774910502295493595"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"281"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[162,163,16],"values":["16511606","16609473","1116593436","16684994","16572674","16663702","1633231896","16407923","16794735","16581428","16544921","1699783070"],"timestampsUnixNano":["1774910497554797442","1774910497571453854","1774910498688104817","1774910498704941699","1774910498721580257","1774910498738285230","1774910500371586069","1774910500388045337","1774910500404874623","1774910500421510244","1774910500438099798","1774910502137924247"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"60"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[164,165,16],"values":["642015825","4952881","3451290","673570679","34821886","83023363","286421997","78529439","493822867","499972216","584023528","444897380","35987355","497972966","321955413","57986729","48284779","417598818"],"timestampsUnixNano":["1774910497588551876","1774910497593550603","1774910497597029264","1774910498270645341","1774910498305557227","1774910498388614463","1774910498675062247","1774910498753631050","1774910499247511149","1774910499747542239","1774910500331604993","1774910500776529594","1774910500812544266","1774910501310550150","1774910501632535769","1774910501690563014","1774910501738884664","1774910502156517170"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"79"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[166,167,21],"values":["1244011751","128994688","586950441","469043024","230861920","646989159","5905862","8049806","658936621","140942313","44996696","56939330","49962619","36996097","21054248","25868621","35032505","6944906","4009288","1912142","5964868","13053587","49888171","34977292","5993187","101082642","72916868","26033793","40937598","46945777","52962625","10085745","39918477","996150","134920944","137974991","3993405","68986489","21990556","25003383","5911470","33131801","20903747","45897693","14026832","80887546","19003657","89977320","116017537","3957711"],"timestampsUnixNano":["1774910497555544536","1774910497684571104","1774910498271547712","1774910498740624187","1774910498971530388","1774910499618564922","1774910499624504325","1774910499632584160","1774910500291555058","1774910500432528226","1774910500477546722","1774910500534512504","1774910500584493246","1774910500621515950","1774910500642585344","1774910500668491466","1774910500703542148","1774910500710513086","1774910500714570669","1774910500716496006","1774910500722516083","1774910500735583328","1774910500785485312","1774910500820478749","1774910500826483197","1774910500927577365","1774910501000508482","1774910501026553437","1774910501067539316","1774910501114497798","1774910501167483771","1774910501177580792","1774910501217508486","1774910501218549254","1774910501353487581","1774910501491504712","1774910501495509354","1774910501564510019","1774910501586512765","1774910501611554586","1774910501617488218","1774910501650637556","1774910501671579584","1774910501717489391","1774910501731571221","1774910501812486410","1774910501831506316","1774910501921501793","1774910502037528676","1774910502041510012"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"2011794"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[168,169,15],"values":["476236550","333081","264846168","1952715","295112479","39024539","191948570","703951850","1024511095","63395136","54913161","376944061","527995468","13996098","562001555"],"timestampsUnixNano":["1774910497886168681","1774910497886520725","1774910498151378106","1774910498153359932","1774910498448502581","1774910498487548350","1774910498679542656","1774910499383546407","1774910500408109175","1774910500471534675","1774910500526483053","1774910500903481592","1774910501431494038","1774910501445514149","1774910502007620051"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"116"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[170,171,19],"values":["3183306600","16757683","16600614","16416975","1744571756","1238501610","16810592","16408679","16602531","16672176","16608257","16605846","16657704","33367085","16570205","16630008","16633521","16756707","16596367","16664759","16541420","16568879","16627932","27279686","261677"],"timestampsUnixNano":["1774910498771470453","1774910498788299516","1774910498804972921","1774910498821458710","1774910500566081858","1774910501804644110","1774910501821494751","1774910501837948227","1774910501854595053","1774910501871294681","1774910501887936265","1774910501904584491","1774910501921270287","1774910501954664377","1774910501971270094","1774910501987935874","1774910502004608164","1774910502021398591","1774910502038043165","1774910502054741285","1774910502071330638","1774910502087945253","1774910502104606940","1774910502131920770","1774910502132206967"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"16"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":97,"attributeIndices":[172,173,16],"values":["4014703","3915567","3965877","4123266","3917351","3898121","4112374","3916050","4962740","3147839","4005583","3817504","5100820","4733889","4235222","3783419","3951714","890799","4140943","839645","4987684","2045291","3966189","3918104","927747","3930709","4081544","4102327"],"timestampsUnixNano":["1774910497545532978","1774910497550489201","1774910497554484989","1774910499265646415","1774910499269618942","1774910499452566971","1774910499547638377","1774910499551597066","1774910499560487404","1774910499563660478","1774910499567769380","1774910499571633494","1774910499698756645","1774910499703537885","1774910499869845918","1774910499873672003","1774910500031630792","1774910500032560363","1774910500245731063","1774910500246609998","1774910500391563850","1774910500393639796","1774910500457598617","1774910500461546628","1774910501207509010","1774910501274560248","1774910502080585595","1774910502084707566"]},{"stackIndex":98,"attributeIndices":[172,173,16],"values":["987356","178969048","90894510","3865669","121936404","162019400","153924003","208955996","139891176","59916756","1006847","63060083","31914976"],"timestampsUnixNano":["1774910497546552695","1774910499448635503","1774910499543502566","1774910499555502833","1774910499693619107","1774910499865586084","1774910500027638441","1774910500241550336","1774910500386545429","1774910500453588113","1774910500462578406","1774910501270594422","1774910502076485314"]},{"stackIndex":98,"attributeIndices":[172,173,23],"values":["10916239","30866653","107090450","1042093","8915441"],"timestampsUnixNano":["1774910497694491285","1774910497788484407","1774910497903759369","1774910497913561705","1774910497930561607"]},{"stackIndex":97,"attributeIndices":[172,173,23],"values":["4053174","3993255","4117098","4766692","3841594","4016801","3943704","5075358"],"timestampsUnixNano":["1774910497757578053","1774910497792491407","1774910497796637527","1774910497908584523","1774910497912488976","1774910497917599043","1774910497921586744","1774910497935668150"]},{"stackIndex":97,"attributeIndices":[172,173,21],"values":["3967552","3986557","1957066","5031688","3906023","3980369","3987966","3992046","4007929","3983877","3985705","2958526","3996653"],"timestampsUnixNano":["1774910500686485693","1774910500703495802","1774910500705496139","1774910500710564006","1774910500714496896","1774910501417491476","1774910501425475516","1774910501429479031","1774910501433497991","1774910501437498530","1774910501441495421","1774910501444479935","1774910501448489644"]},{"stackIndex":98,"attributeIndices":[172,173,21],"values":["12990397","3966781"],"timestampsUnixNano":["1774910500699492387","1774910501421479271"]},{"stackIndex":97,"attributeIndices":[172,173,17],"values":["4026174","3958669","992003","4991043","3023632","4976547","3959657","4417248","3969957","3982377"],"timestampsUnixNano":["1774910501282553273","1774910501286542754","1774910501975486945","1774910502001477565","1774910502004510254","1774910502012492041","1774910502016472160","1774910502139500826","1774910502143500385","1774910502147495019"]},{"stackIndex":98,"attributeIndices":[172,173,17],"values":["4990540","2974441"],"timestampsUnixNano":["1774910501980491312","1774910502007492311"]},{"stackIndex":97,"attributeIndices":[172,173,18],"values":["1008506","4976145","1009546","3924793","1949236","3963134","1050639","4027875","3920967","3917403","3984812","858898","4014512"],"timestampsUnixNano":["1774910497559534992","1774910497564538133","1774910497583546026","1774910497587513936","1774910497589494233","1774910497593482584","1774910497594555419","1774910497644595902","1774910497648563381","1774910497652572937","1774910497657629196","1774910497658536104","1774910497682545364"]},{"stackIndex":98,"attributeIndices":[172,173,18],"values":["979096","19919908"],"timestampsUnixNano":["1774910497653599755","1774910497678500978"]},{"stackIndex":98,"attributeIndices":[172,173,19],"values":["16020920","147998492","865644","69777507","107844805","43968528","9980954","1002749","20995698","15024593","991120","3910017","12036779","50027139","1118974","82987586","13990667","8990205","26895110","2927480","14964109"],"timestampsUnixNano":["1774910497955606918","1774910498108543566","1774910498117574197","1774910498195572668","1774910498308499754","1774910498356574130","1774910500548484919","1774910500555493770","1774910500821507532","1774910500840536516","1774910500845495252","1774910500853532706","1774910500869550834","1774910501107546208","1774910501112621729","1774910501202541373","1774910502190517969","1774910502223489549","1774910502254489291","1774910502270529007","1774910502290489316"]},{"stackIndex":97,"attributeIndices":[172,173,19],"values":["4841765","4017338","4039900","3979743","4041724","4027620","936442","4011537","4853563","3955125","4020926","3985023","4977826","984111","3972339","972257","3988206","4970549","3967832","3924032","4069587","3936574","3967533","4082440","4894679","3961456","3914582","4023671","2806741","3941166","3966979","962751","4954934","4982831","4987000","3982577","4050419","4958199","4034207","4026898","3994378","905167","3966700"],"timestampsUnixNano":["1774910497960493512","1774910498112601623","1774910498116678498","1774910498121582980","1774910498125667558","1774910498199634015","1774910498200612351","1774910498312553760","1774910498361497621","1774910498535577909","1774910498539633776","1774910500538479740","1774910500553481107","1774910500554481438","1774910500790491663","1774910500791485215","1774910500795493280","1774910500800489281","1774910500825492592","1774910500844481554","1774910500849583436","1774910500857490547","1774910500873538635","1774910501025590242","1774910501030526732","1774910501057500788","1774910501111483963","1774910501116677013","1774910501119522280","1774910502176497001","1774910502194515947","1774910502195501819","1774910502200478285","1774910502205476369","1774910502210482710","1774910502214484289","1774910502227558805","1774910502259478494","1774910502263526787","1774910502267573367","1774910502274547211","1774910502275497206","1774910502294486352"]},{"stackIndex":98,"attributeIndices":[172,173,20],"values":["97935796","56939038","37967841","8131931","18937501","6954676","14963172","2968772","5945105","3970728","13009272","28992034","10913177"],"timestampsUnixNano":["1774910498461504407","1774910498526545523","1774910498602549868","1774910500618632171","1774910500645561386","1774910500657528671","1774910500769521384","1774910501832481710","1774910501905485143","1774910501917482839","1774910501936500466","1774910501970498482","1774910502040534128"]},{"stackIndex":97,"attributeIndices":[172,173,20],"values":["3957856","4014598","4021422","3983586","893684","4959838","3987477","1961763","4991674","4096385","3878341","3980281","3960824","940376","3973471","3857584","4075752","4103773","803420","3928248","5010862","3892034","3863242","4000794","3970384","3945236","3967242","849097","4016813","3942269","5005825","2059358","3930363","1058787","3825248","1062387","2953566","3970145","3997706","14972","3964798","4079801","3876751","1962607","4980490","3988374","1024295","4018080","3969028","3988980","1996577","3952046","994050","4018491","3946109","1045477"],"timestampsUnixNano":["1774910498465501921","1774910498469560678","1774910498530594502","1774910498564548979","1774910500573496952","1774910500578485326","1774910500582496480","1774910500584483802","1774910500589499892","1774910500593620759","1774910500597545738","1774910500601553241","1774910500605533726","1774910500606492861","1774910500610483229","1774910500622507036","1774910500626604139","1774910500649698716","1774910500650538752","1774910500661495342","1774910500666540117","1774910500670491302","1774910500746514081","1774910500750537566","1774910500754539858","1774910500773489396","1774910500777489665","1774910501732485771","1774910501736519131","1774910501740488594","1774910501745508425","1774910501747599316","1774910501751559528","1774910501752645163","1774910501756496203","1774910501757580645","1774910501829491018","1774910501871482385","1774910501875499603","1774910501875526224","1774910501879499580","1774910501883597673","1774910501887507787","1774910501889486282","1774910501894478935","1774910501898480715","1774910501899521263","1774910501909516879","1774910501913499577","1774910501921479392","1774910501923483747","1774910501940478376","1774910501941493064","1774910502024555080","1774910502028528021","1774910502029599053"]},{"stackIndex":97,"attributeIndices":[172,173,6],"values":["3986991","5017904","4943858","4986881","4934941","3962238","4045015","3943731","3986563","3993583","2985889","3970906","3983265","4001304","3997320","4001760","4024644","3976339","943171","4001126","3970610","3944485","12117","4017728","4966692","3978560","4964823","3896621","3942001","5089440","4925845","3928330","3930000","3974789"],"timestampsUnixNano":["1774910497577488625","1774910497604543071","1774910497609514258","1774910497614530136","1774910497619496969","1774910497623490646","1774910497627568025","1774910497631542734","1774910497635564743","1774910501477493777","1774910501480505943","1774910501484504712","1774910501488506105","1774910501492529029","1774910501500573018","1774910501504597464","1774910501523560475","1774910501527568903","1774910501528531472","1774910501532549050","1774910501555539464","1774910501559523107","1774910501559562516","1774910501563595418","1774910501568594912","1774910501572599008","1774910501577592318","1774910501581520866","1774910501585489260","1774910501590594414","1774910501595550024","1774910501599507266","1774910501630513884","1774910502097481217"]},{"stackIndex":97,"attributeIndices":[172,173,22],"values":["966721","1013755","3967296","4041390","3816735","978670","3996509","3988064","3972717","4128304","3959215","968359","3973693","22611","3973521","991283","3999668","3960076"],"timestampsUnixNano":["1774910497699532563","1774910500499563745","1774910500504504356","1774910500508586128","1774910500525484677","1774910500526479783","1774910500530486940","1774910500564491003","1774910500568494041","1774910500678628185","1774910501048528431","1774910501049514353","1774910501783483121","1774910501783528060","1774910501809476831","1774910501810478371","1774910501817496852","1774910501821492230"]},{"stackIndex":97,"attributeIndices":[172,173,9],"values":["988479","4992566","4014441","913946","4045156","3914478","4996252","4887531","3965090","4023317","4120325","3899222","3925349","3977698","3935815","4016088","4927726","2929923","3859754","4042699"],"timestampsUnixNano":["1774910498608533401","1774910498613553714","1774910498662593162","1774910498663533356","1774910498667614399","1774910498671563851","1774910498748622148","1774910498865515653","1774910498946640856","1774910498950693692","1774910498965725084","1774910498969673441","1774910499097503554","1774910500470556440","1774910500475549958","1774910500479589630","1774910500491568360","1774910500494538286","1774910500720539419","1774910500724604751"]},{"stackIndex":98,"attributeIndices":[172,173,9],"values":["44966563","71999088","111922880","77096999","10841035","123826630","159096311","1013573","6993210"],"timestampsUnixNano":["1774910498658550124","1774910498743593994","1774910498860591498","1774910498942642298","1774910498961569801","1774910499093551197","1774910499256637313","1774910500471593612","1774910500486610501"]},{"stackIndex":98,"attributeIndices":[172,173,22],"values":["918097","12965579","10046449","21949728","2996469","1004387","26008288"],"timestampsUnixNano":["1774910500500511258","1774910500521588374","1774910501044544170","1774910501805488500","1774910501813484001","1774910501822530175","1774910501863509851"]},{"stackIndex":97,"attributeIndices":[172,173,15],"values":["3988068","3962152","9338","4948197","4987875","1036787","3957715","3963545","980949","5054279","3978128"],"timestampsUnixNano":["1774910500738576486","1774910500881484989","1774910500881516298","1774910500893496257","1774910500995582686","1774910501296585178","1774910501376593879","1774910501380582454","1774910501453481160","1774910501697548857","1774910501989581623"]},{"stackIndex":98,"attributeIndices":[172,173,15],"values":["3889907","6997932","97058116","75997793","27926307","29925494","1000671"],"timestampsUnixNano":["1774910500742489744","1774910500888528914","1774910500990575281","1774910501372616802","1774910501408531551","1774910501727503361","1774910501985582343"]},{"stackIndex":98,"attributeIndices":[172,173,6],"values":["3934519","14889334","18969951","27011104"],"timestampsUnixNano":["1774910501496487251","1774910501519514217","1774910501551537321","1774910501626554974"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"36"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[174,175,23],"values":["28809614","26043677","859737","8082089","753171","2446959","277711891","397851875","16410836","33401612","30070001","43652","22174589","154601357","131871204","118942187","84976509","49927627","332863395","61139010","5782442","115395889","83489124","437055337","33795345","85082723","210044841","123715511","75992487","37834604","16981070","121927733","12129892","303467909","455028134","137320201","167953006","307996198","2456258","14438682","35132700","126798695","25011665","35122969"],"timestampsUnixNano":["1774910497569560251","1774910497595644537","1774910497596541818","1774910497604665968","1774910497605462509","1774910497607947179","1774910497885695800","1774910498283572207","1774910498300032068","1774910498333551863","1774910498363662920","1774910498363780620","1774910498385979005","1774910498540617414","1774910498672529656","1774910498791533702","1774910498876617754","1774910498926576480","1774910499259491198","1774910499320664465","1774910499326531662","1774910499441986627","1774910499525503827","1774910499962651834","1774910499996537696","1774910500081684526","1774910500291783087","1774910500415592622","1774910500491621518","1774910500529503160","1774910500546521268","1774910500668500243","1774910500680668240","1774910500984164755","1774910501439222727","1774910501576567609","1774910501744545894","1774910502052581263","1774910502055062407","1774910502069532977","1774910502104709447","1774910502231533533","1774910502256594814","1774910502291753184"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"225"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[176,177,15],"values":["1249984881","180707590","352413643","16657250","16702188","16499007","16745722","1113997044","968942388","300068073","134139799","258836011","2193737","3961979","544686"],"timestampsUnixNano":["1774910498754861850","1774910498935646687","1774910499288105642","1774910499304829564","1774910499321582642","1774910499338134349","1774910499354912538","1774910500468963455","1774910501437936235","1774910501738049347","1774910501872219625","1774910502131090387","1774910502133299057","1774910502137280002","1774910502137860524"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"3088"}},{"key":"process.executable.path","value":{"stringValue":"/usr/libexec/xdg-desktop-portal"}},{"key":"process.executable.name","value":{"stringValue":"xdg-desktop-portal"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":99,"attributeIndices":[185,186,6],"values":["157929"],"timestampsUnixNano":["1774910502303661905"]},{"stackIndex":100,"attributeIndices":[191,192,16],"values":["3513144947"],"timestampsUnixNano":["1774910502303456786"]},{"stackIndex":99,"attributeIndices":[185,186,23],"values":["371605"],"timestampsUnixNano":["1774910502302608983"]},{"stackIndex":101,"attributeIndices":[193,194,18],"values":["500058255"],"timestampsUnixNano":["1774910500798627027"]},{"stackIndex":102,"attributeIndices":[195,196,16],"values":["3513096899"],"timestampsUnixNano":["1774910501299872551"]},{"stackIndex":99,"attributeIndices":[185,186,22],"values":["437096","705163","149928"],"timestampsUnixNano":["1774910501300164612","1774910501301006560","1774910501301343202"]},{"stackIndex":101,"attributeIndices":[195,196,9],"values":["500055583"],"timestampsUnixNano":["1774910501801420416"]},{"stackIndex":103,"attributeIndices":[197,198,6],"values":["1000756641"],"timestampsUnixNano":["1774910502302199147"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"273"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[199,200,12],"values":["4728373303"],"timestampsUnixNano":["1774910502133416857"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"54"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[201,202,9],"values":["207066023","1748809","11299416","7662324","105961807","88771559","66645268","113325701","214029457","46936430","25967171","149773023","97137195","146820765","279973369","167949382","182905313","289964858","14937133","763211660","58526568","40927125","192985656","119685777","5163536","11959205","128354732","70649749","42969757","109965929","63781757","37045675","112916899","11924600","117851585","211102436","191824664","8007100","27925360","220968604","15898598","10993284","112758502"],"timestampsUnixNano":["1774910497555728704","1774910497557517798","1774910497568846626","1774910497576568920","1774910497682583748","1774910497771446835","1774910497838196406","1774910497951568773","1774910498165645457","1774910498212646387","1774910498238697109","1774910498388527937","1774910498485697521","1774910498632586237","1774910498912610192","1774910499080644258","1774910499263596263","1774910499553612242","1774910499568638526","1774910500331926630","1774910500390499816","1774910500431517619","1774910500624545181","1774910500744325489","1774910500749537331","1774910500761535647","1774910500889919844","1774910500960602164","1774910501003617477","1774910501113617130","1774910501177501869","1774910501214647767","1774910501327629164","1774910501339597852","1774910501457499019","1774910501668639198","1774910501860499502","1774910501868537835","1774910501896500658","1774910502117527763","1774910502133470666","1774910502144526411","1774910502257315029"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"228"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[203,204,17],"values":["233282383","16473552","16836264","16592899","16569047","16487979","16705388","16764589","16621302","16500738","16723900","1999942500","16618918","16664897","16570719","16580807","16517998","16609210","16641432","16624845","16644696","1362587798","354008935","33214671","16432495","261879008","99978623","434526","728519","733234","86907","49436","1344383","52961","50034","95839","189367","622226","1856584","30658"],"timestampsUnixNano":["1774910497688197584","1774910497704736913","1774910497721612426","1774910497738251884","1774910497754870754","1774910497771396170","1774910497788139588","1774910497804933738","1774910497821607666","1774910497838143310","1774910497854905628","1774910499854891127","1774910499871571034","1774910499888273594","1774910499904903223","1774910499921537899","1774910499938118028","1774910499954779755","1774910499971472623","1774910499988163242","1774910500004864947","1774910501367503903","1774910501721543889","1774910501754792425","1774910501771252936","1774910502033157809","1774910502133157671","1774910502133605759","1774910502134359091","1774910502135118457","1774910502135225061","1774910502135286067","1774910502136639165","1774910502136708141","1774910502136768926","1774910502136873658","1774910502137082739","1774910502137723270","1774910502139602496","1774910502139642635"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"78"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":1,"attributeIndices":[205,206,21],"values":["2008654788","314362625","489554174","200945284","7177628","297050692","703121495","121164450","179615486","148004345","253282865","27300583","73097457","401660274","152769063","696332232","1371394","57281178","63841034"],"timestampsUnixNano":["1774910498068497113","1774910498382953734","1774910498872531477","1774910499073515999","1774910499080750351","1774910499377838467","1774910500080998616","1774910500202221138","1774910500381870718","1774910500529909666","1774910500783208698","1774910500810535399","1774910500883670538","1774910501285358661","1774910501438181259","1774910502134535447","1774910502135918944","1774910502193218256","1774910502257088028"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"272"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[207,208,9],"values":["15881745","1299746916","16594649","16711260","16731756","166508622","16743805","16622615","16676964","16593890","16611578","16544782","16671589","16646084","149853031","16616166","16694505","16575397","16726220","16615739","16630950","716399487","183320213"],"timestampsUnixNano":["1774910499504820195","1774910500804614955","1774910500821270526","1774910500838017892","1774910500854781914","1774910501021335667","1774910501038130226","1774910501054789884","1774910501071503867","1774910501088135583","1774910501104787598","1774910501121371744","1774910501138094461","1774910501154788298","1774910501304681364","1774910501321350174","1774910501338086256","1774910501354719735","1774910501371481418","1774910501388137326","1774910501404809858","1774910502121254357","1774910502304607151"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"},{"resource":{"attributes":[{"key":"process.pid","value":{"intValue":"136"}}]},"scopeProfiles":[{"scope":{"name":"/home/korniltsev/claude_repos/open-telemetry/opentelemetry-ebpf-profiler/ebpf-profiler"},"profiles":[{"sampleType":{"typeStrindex":1,"unitStrindex":2},"samples":[{"stackIndex":6,"attributeIndices":[209,210,23],"values":["5874938727","51032","83109","76644","42373","82682","336822"],"timestampsUnixNano":["1774910502130247442","1774910502130323938","1774910502130420777","1774910502130512623","1774910502130569058","1774910502130662651","1774910502131013799"]}],"timeUnixNano":"1774910497545532978","durationNano":"4788991611","periodType":{}}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"schemaUrl":"https://opentelemetry.io/schemas/1.37.0"}],"dictionary":{"mappingTable":[{},{"filenameStrindex":3,"attributeIndices":[1,2]},{"memoryLimit":"20168704","filenameStrindex":63,"attributeIndices":[28,29,30]},{"filenameStrindex":117,"attributeIndices":[42,43]},{"filenameStrindex":120,"attributeIndices":[44,45]},{"filenameStrindex":162,"attributeIndices":[58,59]},{"filenameStrindex":194,"attributeIndices":[68,69]},{"filenameStrindex":216,"attributeIndices":[76,77]},{"filenameStrindex":237,"attributeIndices":[84,85]},{"filenameStrindex":257,"attributeIndices":[86,87]},{"memoryLimit":"1503232","filenameStrindex":329,"attributeIndices":[178,179]},{"memoryLimit":"679936","filenameStrindex":330,"attributeIndices":[181,182]},{"memoryLimit":"1175552","filenameStrindex":331,"attributeIndices":[183,184]},{"memoryLimit":"565248","filenameStrindex":332,"attributeIndices":[187,188]},{"memoryLimit":"229376","filenameStrindex":333,"attributeIndices":[189,190]}],"locationTable":[{},{"mappingIndex":1,"address":"4330560","lines":[{"functionIndex":1}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23046159","lines":[{"functionIndex":2}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23047014","lines":[{"functionIndex":3}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4271855","lines":[{"functionIndex":4}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4211611","lines":[{"functionIndex":5}],"attributeIndices":[3]},{"mappingIndex":1,"address":"3388559","lines":[{"functionIndex":6}],"attributeIndices":[3]},{"mappingIndex":1,"address":"3046809","lines":[{"functionIndex":7}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23076738","lines":[{"functionIndex":8}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23050946","lines":[{"functionIndex":9}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17926184","lines":[{"functionIndex":10}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17926694","lines":[{"functionIndex":11}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17872915","lines":[{"functionIndex":12}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17889649","lines":[{"functionIndex":13}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17896561","lines":[{"functionIndex":14}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17993564","lines":[{"functionIndex":15}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17943783","lines":[{"functionIndex":16}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16989175","lines":[{"functionIndex":17}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16989724","lines":[{"functionIndex":18}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16990954","lines":[{"functionIndex":19}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16994993","lines":[{"functionIndex":20}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17950029","lines":[{"functionIndex":21}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17897060","lines":[{"functionIndex":22}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17902448","lines":[{"functionIndex":23}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17903387","lines":[{"functionIndex":24}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4165745","lines":[{"functionIndex":25}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4168565","lines":[{"functionIndex":26}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5160586","lines":[{"functionIndex":27}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17902420","lines":[{"functionIndex":23}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17896447","lines":[{"functionIndex":14}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23076796","lines":[{"functionIndex":8}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23051657","lines":[{"functionIndex":28}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18186623","lines":[{"functionIndex":29}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18189819","lines":[{"functionIndex":30}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18191003","lines":[{"functionIndex":31}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17950445","lines":[{"functionIndex":32}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17896579","lines":[{"functionIndex":14}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4168315","lines":[{"functionIndex":26}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18264017","lines":[{"functionIndex":33}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18264716","lines":[{"functionIndex":34}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18265165","lines":[{"functionIndex":35}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18265820","lines":[{"functionIndex":36}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17914524","lines":[{"functionIndex":37}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17916681","lines":[{"functionIndex":38}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17926152","lines":[{"functionIndex":10}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17869800","lines":[{"functionIndex":39}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17900961","lines":[{"functionIndex":23}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17902397","lines":[{"functionIndex":23}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17895924","lines":[{"functionIndex":14}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17927433","lines":[{"functionIndex":40}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17889543","lines":[{"functionIndex":13}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4819862","lines":[{"functionIndex":41}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4823549","lines":[{"functionIndex":42}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4949964","lines":[{"functionIndex":43}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4957405","lines":[{"functionIndex":44}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4958422","lines":[{"functionIndex":45}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4216291","lines":[{"functionIndex":46}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4216399","lines":[{"functionIndex":46}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23077479","lines":[{"functionIndex":47}],"attributeIndices":[3]},{"mappingIndex":1,"address":"9029617","lines":[{"functionIndex":48}],"attributeIndices":[3]},{"mappingIndex":1,"address":"9029777","lines":[{"functionIndex":49}],"attributeIndices":[3]},{"mappingIndex":1,"address":"9029885","lines":[{"functionIndex":50}],"attributeIndices":[3]},{"mappingIndex":1,"address":"9035551","lines":[{"functionIndex":51}],"attributeIndices":[3]},{"mappingIndex":1,"address":"22989261","lines":[{"functionIndex":52}],"attributeIndices":[3]},{"mappingIndex":1,"address":"302","lines":[{"functionIndex":53}],"attributeIndices":[3]},{"mappingIndex":2,"address":"28173","lines":[{"functionIndex":54,"line":"36"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"27684","lines":[{"functionIndex":55,"line":"34"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"281875","lines":[{"functionIndex":56,"line":"120"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"336357","lines":[{"functionIndex":57,"line":"3742"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"342352","lines":[{"functionIndex":58,"line":"4152"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"343492","lines":[{"functionIndex":59,"line":"4281"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"560886","lines":[{"functionIndex":60,"line":"462"}],"attributeIndices":[31]},{"mappingIndex":1,"address":"5308089","lines":[{"functionIndex":61}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5310109","lines":[{"functionIndex":62}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5310343","lines":[{"functionIndex":63}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5291844","lines":[{"functionIndex":64}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5292364","lines":[{"functionIndex":65}],"attributeIndices":[3]},{"mappingIndex":2,"address":"576834","lines":[{"functionIndex":66,"line":"558"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"282735","lines":[{"functionIndex":67,"line":"76"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"111462","lines":[{"functionIndex":68,"line":"48"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"330507","lines":[{"functionIndex":69,"line":"1975"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"338139","lines":[{"functionIndex":57,"line":"3388"}],"attributeIndices":[31]},{"mappingIndex":1,"address":"5071078","lines":[{"functionIndex":70}],"attributeIndices":[3]},{"mappingIndex":1,"address":"22989527","lines":[{"functionIndex":52}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23076173","lines":[{"functionIndex":71}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5158521","lines":[{"functionIndex":72}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5158833","lines":[{"functionIndex":73}],"attributeIndices":[3]},{"mappingIndex":2,"address":"575318","lines":[{"functionIndex":74,"line":"135"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"363663","lines":[{"functionIndex":75,"line":"6248"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"324116","lines":[{"functionIndex":76,"line":"1942"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"323924","lines":[{"functionIndex":77,"line":"1904"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"560740","lines":[{"functionIndex":78,"line":"396"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"282852","lines":[{"functionIndex":67,"line":"82"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"111764","lines":[{"functionIndex":79,"line":"90"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"112072","lines":[{"functionIndex":80,"line":"112"}],"attributeIndices":[31]},{"mappingIndex":2,"address":"363959","lines":[{"functionIndex":75,"line":"6284"}],"attributeIndices":[31]},{"mappingIndex":1,"address":"23047140","lines":[{"functionIndex":81}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23063938","lines":[{"functionIndex":82}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23065193","lines":[{"functionIndex":83}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10766220","lines":[{"functionIndex":84}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10767047","lines":[{"functionIndex":85}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10307794","lines":[{"functionIndex":86}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10390989","lines":[{"functionIndex":87}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10399106","lines":[{"functionIndex":88}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10491130","lines":[{"functionIndex":89}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10722675","lines":[{"functionIndex":90}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23062245","lines":[{"functionIndex":91}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23062887","lines":[{"functionIndex":92}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10765820","lines":[{"functionIndex":93}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10767207","lines":[{"functionIndex":94}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10307702","lines":[{"functionIndex":86}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10393820","lines":[{"functionIndex":95}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10546375","lines":[{"functionIndex":96}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10473981","lines":[{"functionIndex":97}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10491027","lines":[{"functionIndex":89}],"attributeIndices":[3]},{"mappingIndex":3,"address":"78101","lines":[{"functionIndex":98}],"attributeIndices":[3]},{"mappingIndex":3,"address":"149549","lines":[{"functionIndex":99}],"attributeIndices":[3]},{"mappingIndex":4,"address":"101557","lines":[{"functionIndex":100}],"attributeIndices":[3]},{"mappingIndex":4,"address":"224100","lines":[{"functionIndex":101}],"attributeIndices":[3]},{"mappingIndex":4,"address":"108758","lines":[{"functionIndex":102}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23058295","lines":[{"functionIndex":103}],"attributeIndices":[3]},{"mappingIndex":4,"address":"74395","lines":[{"functionIndex":104}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23047441","lines":[{"functionIndex":105}],"attributeIndices":[3]},{"mappingIndex":1,"address":"3056517","lines":[{"functionIndex":106}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7171075","lines":[{"functionIndex":107}],"attributeIndices":[3]},{"mappingIndex":4,"address":"101289","lines":[{"functionIndex":108}],"attributeIndices":[3]},{"mappingIndex":4,"address":"104488","lines":[{"functionIndex":109}],"attributeIndices":[3]},{"mappingIndex":4,"address":"108717","lines":[{"functionIndex":102}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23088020","lines":[{"functionIndex":110}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7238545","lines":[{"functionIndex":111}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7244640","lines":[{"functionIndex":112}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7244975","lines":[{"functionIndex":113}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7257825","lines":[{"functionIndex":114}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7259313","lines":[{"functionIndex":115}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7260235","lines":[{"functionIndex":116}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7261897","lines":[{"functionIndex":117}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5313523","lines":[{"functionIndex":118}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5314819","lines":[{"functionIndex":119}],"attributeIndices":[3]},{"mappingIndex":1,"address":"3788617","lines":[{"functionIndex":120}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7632483","lines":[{"functionIndex":121}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7231501","lines":[{"functionIndex":122}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7238607","lines":[{"functionIndex":111}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5313526","lines":[{"functionIndex":118}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8281936","lines":[{"functionIndex":123}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7218819","lines":[{"functionIndex":124}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7260021","lines":[{"functionIndex":116}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23047639","lines":[{"functionIndex":125}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5641","lines":[{"functionIndex":126}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4989644","lines":[{"functionIndex":127}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8697910","lines":[{"functionIndex":128}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8698233","lines":[{"functionIndex":129}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8707693","lines":[{"functionIndex":130}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8535981","lines":[{"functionIndex":131}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7270950","lines":[{"functionIndex":132}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7273664","lines":[{"functionIndex":133}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7245000","lines":[{"functionIndex":113}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7225032","lines":[{"functionIndex":134}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7261818","lines":[{"functionIndex":117}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13434781","lines":[{"functionIndex":135}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13436281","lines":[{"functionIndex":136}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13436899","lines":[{"functionIndex":137}],"attributeIndices":[3]},{"mappingIndex":5,"address":"721","lines":[{"functionIndex":138}],"attributeIndices":[3]},{"mappingIndex":5,"address":"20649","lines":[{"functionIndex":139}],"attributeIndices":[3]},{"mappingIndex":5,"address":"21731","lines":[{"functionIndex":140}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12332740","lines":[{"functionIndex":141}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12333135","lines":[{"functionIndex":142}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12292582","lines":[{"functionIndex":143}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7906213","lines":[{"functionIndex":144}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7909102","lines":[{"functionIndex":145}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7192843","lines":[{"functionIndex":146}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7231610","lines":[{"functionIndex":122}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23087969","lines":[{"functionIndex":147}],"attributeIndices":[3]},{"mappingIndex":5,"address":"20805","lines":[{"functionIndex":139}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23088039","lines":[{"functionIndex":110}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13434787","lines":[{"functionIndex":135}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8697552","lines":[{"functionIndex":148}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7439634","lines":[{"functionIndex":149}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7439983","lines":[{"functionIndex":150}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8707629","lines":[{"functionIndex":130}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7225259","lines":[{"functionIndex":134}],"attributeIndices":[3]},{"mappingIndex":1,"address":"3788687","lines":[{"functionIndex":120}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5705","lines":[{"functionIndex":151}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8239346","lines":[{"functionIndex":152}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8295923","lines":[{"functionIndex":153}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7933689","lines":[{"functionIndex":154}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7232678","lines":[{"functionIndex":122}],"attributeIndices":[3]},{"mappingIndex":1,"address":"22961708","lines":[{"functionIndex":155}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10935698","lines":[{"functionIndex":156}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10494366","lines":[{"functionIndex":157}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8699420","lines":[{"functionIndex":158}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13435204","lines":[{"functionIndex":135}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10308363","lines":[{"functionIndex":86}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23077771","lines":[{"functionIndex":159}],"attributeIndices":[3]},{"mappingIndex":1,"address":"15083802","lines":[{"functionIndex":160}],"attributeIndices":[3]},{"mappingIndex":1,"address":"15058668","lines":[{"functionIndex":161}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14974608","lines":[{"functionIndex":162}],"attributeIndices":[3]},{"mappingIndex":1,"address":"15156116","lines":[{"functionIndex":163}],"attributeIndices":[3]},{"mappingIndex":1,"address":"15163212","lines":[{"functionIndex":164}],"attributeIndices":[3]},{"mappingIndex":1,"address":"15167920","lines":[{"functionIndex":165}],"attributeIndices":[3]},{"mappingIndex":1,"address":"15116261","lines":[{"functionIndex":166}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14991147","lines":[{"functionIndex":167}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14799241","lines":[{"functionIndex":168}],"attributeIndices":[3]},{"mappingIndex":6,"address":"393556","lines":[{"functionIndex":169}],"attributeIndices":[3]},{"mappingIndex":6,"address":"394568","lines":[{"functionIndex":170}],"attributeIndices":[3]},{"mappingIndex":6,"address":"426530","lines":[{"functionIndex":171}],"attributeIndices":[3]},{"mappingIndex":6,"address":"388146","lines":[{"functionIndex":172}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23086303","lines":[{"functionIndex":173}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17196104","lines":[{"functionIndex":174}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17220676","lines":[{"functionIndex":175}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8659619","lines":[{"functionIndex":176}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8660657","lines":[{"functionIndex":177}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8663747","lines":[{"functionIndex":178}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23019626","lines":[{"functionIndex":179}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5205027","lines":[{"functionIndex":180}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5219693","lines":[{"functionIndex":181}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8653878","lines":[{"functionIndex":182}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8659910","lines":[{"functionIndex":176}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8664606","lines":[{"functionIndex":183}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23047253","lines":[{"functionIndex":184}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12503280","lines":[{"functionIndex":185}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12714585","lines":[{"functionIndex":186}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12502118","lines":[{"functionIndex":187}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12410257","lines":[{"functionIndex":188}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12332451","lines":[{"functionIndex":141}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12333778","lines":[{"functionIndex":189}],"attributeIndices":[3]},{"mappingIndex":7,"address":"7976","lines":[{"functionIndex":190}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4174507","lines":[{"functionIndex":191}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12323770","lines":[{"functionIndex":192}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12404310","lines":[{"functionIndex":193}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12407400","lines":[{"functionIndex":194}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12331697","lines":[{"functionIndex":195}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23047248","lines":[{"functionIndex":184}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4330714","lines":[{"functionIndex":1}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14011850","lines":[{"functionIndex":196}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13982662","lines":[{"functionIndex":197}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13983272","lines":[{"functionIndex":198}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13992215","lines":[{"functionIndex":199}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10870082","lines":[{"functionIndex":200}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10879393","lines":[{"functionIndex":201}],"attributeIndices":[3]},{"mappingIndex":1,"address":"11276613","lines":[{"functionIndex":202}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13930214","lines":[{"functionIndex":203}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13932681","lines":[{"functionIndex":204}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13968929","lines":[{"functionIndex":205}],"attributeIndices":[3]},{"mappingIndex":1,"address":"13997533","lines":[{"functionIndex":206}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14040767","lines":[{"functionIndex":207}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17921996","lines":[{"functionIndex":208}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17922693","lines":[{"functionIndex":209}],"attributeIndices":[3]},{"mappingIndex":8,"address":"3057","lines":[{"functionIndex":210}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17944191","lines":[{"functionIndex":211}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17950141","lines":[{"functionIndex":212}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16991748","lines":[{"functionIndex":213}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16996455","lines":[{"functionIndex":214}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18191563","lines":[{"functionIndex":31}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17950564","lines":[{"functionIndex":215}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17894987","lines":[{"functionIndex":216}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17993484","lines":[{"functionIndex":217}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17944475","lines":[{"functionIndex":211}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18267977","lines":[{"functionIndex":36}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17913226","lines":[{"functionIndex":37}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17895075","lines":[{"functionIndex":216}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10628124","lines":[{"functionIndex":218}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10654979","lines":[{"functionIndex":219}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7145762","lines":[{"functionIndex":220}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8852033","lines":[{"functionIndex":221}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8853181","lines":[{"functionIndex":222}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8853979","lines":[{"functionIndex":223}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8855106","lines":[{"functionIndex":224}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8860047","lines":[{"functionIndex":225}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16990193","lines":[{"functionIndex":19}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16990455","lines":[{"functionIndex":19}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17879672","lines":[{"functionIndex":226}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17882083","lines":[{"functionIndex":227}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17943310","lines":[{"functionIndex":228}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17943508","lines":[{"functionIndex":16}],"attributeIndices":[3]},{"mappingIndex":9,"address":"368673","lines":[{"functionIndex":229}],"attributeIndices":[3]},{"mappingIndex":9,"address":"369357","lines":[{"functionIndex":230}],"attributeIndices":[3]},{"mappingIndex":9,"address":"480407","lines":[{"functionIndex":231}],"attributeIndices":[3]},{"mappingIndex":9,"address":"480644","lines":[{"functionIndex":232}],"attributeIndices":[3]},{"mappingIndex":9,"address":"472322","lines":[{"functionIndex":233}],"attributeIndices":[3]},{"mappingIndex":9,"address":"472829","lines":[{"functionIndex":234}],"attributeIndices":[3]},{"mappingIndex":8,"address":"3069","lines":[{"functionIndex":210}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4319058","lines":[{"functionIndex":235}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10579113","lines":[{"functionIndex":236}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10583561","lines":[{"functionIndex":237}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17892562","lines":[{"functionIndex":238}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17893026","lines":[{"functionIndex":239}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16994551","lines":[{"functionIndex":240}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17950336","lines":[{"functionIndex":241}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16993502","lines":[{"functionIndex":242}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16996435","lines":[{"functionIndex":214}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14384600","lines":[{"functionIndex":243}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14396038","lines":[{"functionIndex":244}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14400675","lines":[{"functionIndex":245}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14413192","lines":[{"functionIndex":246}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17894718","lines":[{"functionIndex":216}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18262185","lines":[{"functionIndex":247}],"attributeIndices":[3]},{"mappingIndex":1,"address":"18267924","lines":[{"functionIndex":36}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14012195","lines":[{"functionIndex":196}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17880206","lines":[{"functionIndex":226}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4165713","lines":[{"functionIndex":25}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7432255","lines":[{"functionIndex":248}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4917157","lines":[{"functionIndex":249}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4923079","lines":[{"functionIndex":250}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4923621","lines":[{"functionIndex":251}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4923630","lines":[{"functionIndex":251}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4968565","lines":[{"functionIndex":252}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4916925","lines":[{"functionIndex":249}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10881187","lines":[{"functionIndex":253}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10527244","lines":[{"functionIndex":254}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10635554","lines":[{"functionIndex":255}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10641562","lines":[{"functionIndex":256}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10642408","lines":[{"functionIndex":257}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10644595","lines":[{"functionIndex":258}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7074376","lines":[{"functionIndex":259}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10642952","lines":[{"functionIndex":257}],"attributeIndices":[3]},{"mappingIndex":1,"address":"11260907","lines":[{"functionIndex":260}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10490268","lines":[{"functionIndex":89}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4161413","lines":[{"functionIndex":261}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7171623","lines":[{"functionIndex":262}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8236820","lines":[{"functionIndex":263}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4032102","lines":[{"functionIndex":264}],"attributeIndices":[3]},{"mappingIndex":1,"address":"3846198","lines":[{"functionIndex":265}],"attributeIndices":[3]},{"mappingIndex":7,"address":"19172","lines":[{"functionIndex":266}],"attributeIndices":[3]},{"mappingIndex":7,"address":"26843","lines":[{"functionIndex":267}],"attributeIndices":[3]},{"mappingIndex":7,"address":"27709","lines":[{"functionIndex":268}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23049824","lines":[{"functionIndex":269}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23049132","lines":[{"functionIndex":270}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23049414","lines":[{"functionIndex":271}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10652077","lines":[{"functionIndex":272}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10416110","lines":[{"functionIndex":273}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10280453","lines":[{"functionIndex":274}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10308261","lines":[{"functionIndex":86}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16740138","lines":[{"functionIndex":275}],"attributeIndices":[3]},{"mappingIndex":9,"address":"1054923","lines":[{"functionIndex":276}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10309416","lines":[{"functionIndex":86}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10888475","lines":[{"functionIndex":277}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10362379","lines":[{"functionIndex":278}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10284430","lines":[{"functionIndex":279}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10286149","lines":[{"functionIndex":280}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10308945","lines":[{"functionIndex":86}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10524691","lines":[{"functionIndex":281}],"attributeIndices":[3]},{"mappingIndex":1,"address":"5426465","lines":[{"functionIndex":282}],"attributeIndices":[3]},{"mappingIndex":1,"address":"8260681","lines":[{"functionIndex":283}],"attributeIndices":[3]},{"mappingIndex":1,"address":"17893314","lines":[{"functionIndex":239}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7068745","lines":[{"functionIndex":284}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10637079","lines":[{"functionIndex":285}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10879207","lines":[{"functionIndex":201}],"attributeIndices":[3]},{"mappingIndex":1,"address":"11262530","lines":[{"functionIndex":286}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10629263","lines":[{"functionIndex":287}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10635293","lines":[{"functionIndex":255}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10318542","lines":[{"functionIndex":288}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10394981","lines":[{"functionIndex":289}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10470784","lines":[{"functionIndex":290}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10525031","lines":[{"functionIndex":281}],"attributeIndices":[3]},{"mappingIndex":1,"address":"10394839","lines":[{"functionIndex":289}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14395598","lines":[{"functionIndex":291}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14402082","lines":[{"functionIndex":292}],"attributeIndices":[3]},{"mappingIndex":1,"address":"14420175","lines":[{"functionIndex":293}],"attributeIndices":[3]},{"mappingIndex":1,"address":"16996415","lines":[{"functionIndex":214}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7109297","lines":[{"functionIndex":294}],"attributeIndices":[3]},{"mappingIndex":1,"address":"7109757","lines":[{"functionIndex":295}],"attributeIndices":[3]},{"mappingIndex":1,"address":"12298878","lines":[{"functionIndex":296}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4666190","lines":[{"functionIndex":297}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4960361","lines":[{"functionIndex":298}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4975062","lines":[{"functionIndex":299}],"attributeIndices":[3]},{"mappingIndex":1,"address":"4975122","lines":[{"functionIndex":299}],"attributeIndices":[3]},{"mappingIndex":1,"address":"23077542","lines":[{"functionIndex":47}],"attributeIndices":[3]},{"mappingIndex":10,"address":"502177","attributeIndices":[180]},{"mappingIndex":10,"address":"453691","attributeIndices":[180]},{"mappingIndex":10,"address":"453763","attributeIndices":[180]},{"mappingIndex":10,"address":"952069","attributeIndices":[180]},{"mappingIndex":11,"address":"303967","attributeIndices":[180]},{"mappingIndex":11,"address":"304414","attributeIndices":[180]},{"mappingIndex":12,"address":"954257","attributeIndices":[180]},{"mappingIndex":11,"address":"481089","attributeIndices":[180]},{"mappingIndex":10,"address":"468067","attributeIndices":[180]},{"mappingIndex":10,"address":"1005035","attributeIndices":[180]},{"mappingIndex":12,"address":"881347","attributeIndices":[180]},{"mappingIndex":12,"address":"950860","attributeIndices":[180]},{"mappingIndex":12,"address":"991004","attributeIndices":[180]},{"mappingIndex":12,"address":"991498","attributeIndices":[180]},{"mappingIndex":13,"address":"304410","attributeIndices":[180]},{"mappingIndex":13,"address":"458711","attributeIndices":[180]},{"mappingIndex":13,"address":"247972","attributeIndices":[180]},{"mappingIndex":14,"address":"27502","attributeIndices":[180]},{"mappingIndex":14,"address":"153456","attributeIndices":[180]},{"mappingIndex":14,"address":"155327","attributeIndices":[180]},{"mappingIndex":13,"address":"203963","attributeIndices":[180]},{"mappingIndex":12,"address":"1029989","attributeIndices":[180]},{"mappingIndex":12,"address":"523115","attributeIndices":[180]},{"mappingIndex":11,"address":"485777","attributeIndices":[180]},{"mappingIndex":10,"address":"996236","attributeIndices":[180]},{"mappingIndex":11,"address":"447114","attributeIndices":[180]},{"mappingIndex":11,"address":"41420","attributeIndices":[180]},{"mappingIndex":11,"address":"485865","attributeIndices":[180]},{"mappingIndex":11,"address":"41788","attributeIndices":[180]},{"mappingIndex":11,"address":"485438","attributeIndices":[180]},{"mappingIndex":13,"address":"60581","attributeIndices":[180]},{"mappingIndex":10,"address":"13748","attributeIndices":[180]},{"mappingIndex":10,"address":"13927","attributeIndices":[180]},{"mappingIndex":13,"address":"62420","attributeIndices":[180]}],"functionTable":[{},{"nameStrindex":6},{"nameStrindex":8},{"nameStrindex":9},{"nameStrindex":10},{"nameStrindex":11},{"nameStrindex":12},{"nameStrindex":13},{"nameStrindex":17},{"nameStrindex":18},{"nameStrindex":19},{"nameStrindex":20},{"nameStrindex":21},{"nameStrindex":22},{"nameStrindex":23},{"nameStrindex":24},{"nameStrindex":25},{"nameStrindex":26},{"nameStrindex":27},{"nameStrindex":28},{"nameStrindex":29},{"nameStrindex":30},{"nameStrindex":31},{"nameStrindex":32},{"nameStrindex":33},{"nameStrindex":34},{"nameStrindex":35},{"nameStrindex":36},{"nameStrindex":37},{"nameStrindex":38},{"nameStrindex":39},{"nameStrindex":40},{"nameStrindex":41},{"nameStrindex":42},{"nameStrindex":43},{"nameStrindex":44},{"nameStrindex":45},{"nameStrindex":46},{"nameStrindex":47},{"nameStrindex":48},{"nameStrindex":49},{"nameStrindex":50},{"nameStrindex":51},{"nameStrindex":52},{"nameStrindex":53},{"nameStrindex":54},{"nameStrindex":55},{"nameStrindex":56},{"nameStrindex":57},{"nameStrindex":58},{"nameStrindex":59},{"nameStrindex":60},{"nameStrindex":61},{"nameStrindex":62},{"nameStrindex":65,"filenameStrindex":66},{"nameStrindex":67,"filenameStrindex":68},{"nameStrindex":69,"filenameStrindex":70},{"nameStrindex":71,"filenameStrindex":72},{"nameStrindex":73,"filenameStrindex":72},{"nameStrindex":74,"filenameStrindex":72},{"nameStrindex":75,"filenameStrindex":76},{"nameStrindex":77},{"nameStrindex":78},{"nameStrindex":79},{"nameStrindex":80},{"nameStrindex":81},{"nameStrindex":82,"filenameStrindex":83},{"nameStrindex":84,"filenameStrindex":85},{"nameStrindex":86,"filenameStrindex":87},{"nameStrindex":88,"filenameStrindex":72},{"nameStrindex":89},{"nameStrindex":90},{"nameStrindex":91},{"nameStrindex":92},{"nameStrindex":93,"filenameStrindex":83},{"nameStrindex":94,"filenameStrindex":72},{"nameStrindex":95,"filenameStrindex":72},{"nameStrindex":96,"filenameStrindex":72},{"nameStrindex":97,"filenameStrindex":76},{"nameStrindex":98,"filenameStrindex":87},{"nameStrindex":99,"filenameStrindex":87},{"nameStrindex":100},{"nameStrindex":101},{"nameStrindex":102},{"nameStrindex":103},{"nameStrindex":104},{"nameStrindex":105},{"nameStrindex":106},{"nameStrindex":107},{"nameStrindex":108},{"nameStrindex":109},{"nameStrindex":110},{"nameStrindex":111},{"nameStrindex":112},{"nameStrindex":113},{"nameStrindex":114},{"nameStrindex":115},{"nameStrindex":116},{"nameStrindex":118},{"nameStrindex":119},{"nameStrindex":121},{"nameStrindex":122},{"nameStrindex":123},{"nameStrindex":124},{"nameStrindex":125},{"nameStrindex":126},{"nameStrindex":127},{"nameStrindex":128},{"nameStrindex":129},{"nameStrindex":130},{"nameStrindex":134},{"nameStrindex":135},{"nameStrindex":136},{"nameStrindex":137},{"nameStrindex":138},{"nameStrindex":139},{"nameStrindex":140},{"nameStrindex":141},{"nameStrindex":142},{"nameStrindex":143},{"nameStrindex":144},{"nameStrindex":145},{"nameStrindex":146},{"nameStrindex":147},{"nameStrindex":148},{"nameStrindex":149},{"nameStrindex":150},{"nameStrindex":151},{"nameStrindex":152},{"nameStrindex":153},{"nameStrindex":154},{"nameStrindex":155},{"nameStrindex":156},{"nameStrindex":157},{"nameStrindex":158},{"nameStrindex":159},{"nameStrindex":160},{"nameStrindex":161},{"nameStrindex":163},{"nameStrindex":164},{"nameStrindex":165},{"nameStrindex":166},{"nameStrindex":167},{"nameStrindex":168},{"nameStrindex":169},{"nameStrindex":170},{"nameStrindex":171},{"nameStrindex":172},{"nameStrindex":173},{"nameStrindex":174},{"nameStrindex":175},{"nameStrindex":176},{"nameStrindex":177},{"nameStrindex":178},{"nameStrindex":179},{"nameStrindex":180},{"nameStrindex":181},{"nameStrindex":182},{"nameStrindex":183},{"nameStrindex":184},{"nameStrindex":185},{"nameStrindex":186},{"nameStrindex":187},{"nameStrindex":188},{"nameStrindex":189},{"nameStrindex":190},{"nameStrindex":191},{"nameStrindex":192},{"nameStrindex":193},{"nameStrindex":195},{"nameStrindex":196},{"nameStrindex":197},{"nameStrindex":198},{"nameStrindex":199},{"nameStrindex":200},{"nameStrindex":201},{"nameStrindex":202},{"nameStrindex":203},{"nameStrindex":204},{"nameStrindex":205},{"nameStrindex":206},{"nameStrindex":207},{"nameStrindex":208},{"nameStrindex":209},{"nameStrindex":210},{"nameStrindex":211},{"nameStrindex":212},{"nameStrindex":213},{"nameStrindex":214},{"nameStrindex":215},{"nameStrindex":217},{"nameStrindex":218},{"nameStrindex":219},{"nameStrindex":220},{"nameStrindex":221},{"nameStrindex":222},{"nameStrindex":223},{"nameStrindex":224},{"nameStrindex":225},{"nameStrindex":226},{"nameStrindex":227},{"nameStrindex":228},{"nameStrindex":229},{"nameStrindex":230},{"nameStrindex":231},{"nameStrindex":232},{"nameStrindex":233},{"nameStrindex":234},{"nameStrindex":235},{"nameStrindex":236},{"nameStrindex":238},{"nameStrindex":239},{"nameStrindex":240},{"nameStrindex":241},{"nameStrindex":242},{"nameStrindex":243},{"nameStrindex":244},{"nameStrindex":245},{"nameStrindex":246},{"nameStrindex":247},{"nameStrindex":248},{"nameStrindex":249},{"nameStrindex":250},{"nameStrindex":251},{"nameStrindex":252},{"nameStrindex":253},{"nameStrindex":254},{"nameStrindex":255},{"nameStrindex":256},{"nameStrindex":258},{"nameStrindex":259},{"nameStrindex":260},{"nameStrindex":261},{"nameStrindex":262},{"nameStrindex":263},{"nameStrindex":264},{"nameStrindex":265},{"nameStrindex":266},{"nameStrindex":267},{"nameStrindex":268},{"nameStrindex":269},{"nameStrindex":270},{"nameStrindex":271},{"nameStrindex":272},{"nameStrindex":273},{"nameStrindex":274},{"nameStrindex":275},{"nameStrindex":276},{"nameStrindex":277},{"nameStrindex":278},{"nameStrindex":279},{"nameStrindex":280},{"nameStrindex":281},{"nameStrindex":282},{"nameStrindex":283},{"nameStrindex":284},{"nameStrindex":285},{"nameStrindex":286},{"nameStrindex":287},{"nameStrindex":288},{"nameStrindex":289},{"nameStrindex":290},{"nameStrindex":291},{"nameStrindex":292},{"nameStrindex":293},{"nameStrindex":294},{"nameStrindex":295},{"nameStrindex":296},{"nameStrindex":297},{"nameStrindex":298},{"nameStrindex":299},{"nameStrindex":300},{"nameStrindex":301},{"nameStrindex":302},{"nameStrindex":303},{"nameStrindex":304},{"nameStrindex":305},{"nameStrindex":306},{"nameStrindex":307},{"nameStrindex":308},{"nameStrindex":309},{"nameStrindex":310},{"nameStrindex":311},{"nameStrindex":312},{"nameStrindex":313},{"nameStrindex":314},{"nameStrindex":315},{"nameStrindex":316},{"nameStrindex":317},{"nameStrindex":318},{"nameStrindex":319},{"nameStrindex":320},{"nameStrindex":321},{"nameStrindex":322},{"nameStrindex":323},{"nameStrindex":324},{"nameStrindex":325},{"nameStrindex":326},{"nameStrindex":327},{"nameStrindex":328}],"linkTable":[{}],"stringTable":["","off_cpu","nanoseconds","vmlinux","process.executable.build_id.gnu","process.executable.build_id.htlhash","finish_task_switch.isra.0","profile.frame.type","__schedule","schedule","smpboot_thread_fn","kthread","ret_from_fork","ret_from_fork_asm","thread.name","thread.id","cpu.logical_number","schedule_timeout","wait_for_completion_timeout","usb_start_wait_urb","usb_control_msg","usb_disable_remote_wakeup","finish_port_resume","usb_port_resume","usb_generic_driver_resume","usb_resume_both","__rpm_callback","rpm_callback","rpm_resume","__pm_runtime_resume","usb_autoresume_device","usb_remote_wakeup","port_event","hub_event","process_one_work","worker_thread","msleep","wait_for_completion","xhci_configure_endpoint","xhci_change_max_exit_latency","xhci_set_usb2_hardware_lpm","usb_enable_usb2_hardware_lpm","xhci_handle_usb2_port_link_resume","xhci_get_usb2_port_status","xhci_get_port_status","xhci_hub_control","rh_call_control","usb_hcd_submit_urb","hub_ext_port_status","usb_get_status","irq_wait_for_interrupt","irq_thread","synchronize_rcu_expedited_wait_once","synchronize_rcu_expedited_wait","rcu_exp_wait_wake","kthread_worker_fn","schedule_hrtimeout_range_clock","ep_poll","do_epoll_wait","do_epoll_pwait.part.0","__x64_sys_epoll_pwait","do_syscall_64","entry_SYSCALL_64_after_hwframe","containerd","process.executable.build_id.go","internal/runtime/syscall.Syscall6","/usr/local/go/src/internal/runtime/syscall/asm_linux_amd64.s","internal/runtime/syscall.EpollWait","/usr/local/go/src/internal/runtime/syscall/syscall_linux.go","runtime.netpoll","/usr/local/go/src/runtime/netpoll_epoll.go","runtime.findRunnable","/usr/local/go/src/runtime/proc.go","runtime.schedule","runtime.park_m","runtime.mcall","/usr/local/go/src/runtime/asm_amd64.s","futex_do_wait","__futex_wait","futex_wait","do_futex","__x64_sys_futex","runtime.futex","/usr/local/go/src/runtime/sys_linux_amd64.s","runtime.futexsleep","/usr/local/go/src/runtime/os_linux.go","runtime.notesleep","/usr/local/go/src/runtime/lock_futex.go","runtime.stopm","exit_to_user_mode_loop","do_nanosleep","hrtimer_nanosleep","__x64_sys_nanosleep","runtime.usleep","runtime.sysmon","runtime.mstart1","runtime.mstart0","runtime.mstart","runtime.notetsleep_internal","runtime.notetsleep","schedule_preempt_disabled","rwsem_down_write_slowpath","down_write","btrfs_tree_lock_nested","btrfs_lock_root_node","btrfs_search_slot","btrfs_lookup_csum","btrfs_csum_file_blocks","btrfs_finish_one_ordered","btrfs_work_helper","rwsem_down_read_slowpath","down_read","btrfs_tree_read_lock_nested","btrfs_read_lock_root_node","btrfs_lookup_file_extent","btrfs_drop_extents","insert_reserved_file_extent","iwlwifi","iwl_trans_pcie_send_hcmd_sync","iwl_trans_send_cmd","iwlmvm","iwl_mvm_send_cmd","iwl_mvm_config_scan","iwl_mvm_recalc_tcm","__mutex_lock.constprop.0","iwl_mvm_async_handlers_by_context","preempt_schedule","preempt_schedule_thunk","lru_add_drain_per_cpu","iwl_mvm_request_system_statistics","iwl_mvm_request_statistics","cpu","samples","count","_raw_spin_unlock_irq","evict_folios","try_to_shrink_lruvec","shrink_one","shrink_many","shrink_node","balance_pgdat","kswapd","smp_call_function_many_cond","on_each_cpu_cond_mask","arch_tlbbatch_flush","try_to_unmap_flush_dirty","shrink_folio_list","mem_cgroup_iter","lru_gen_age_node","preempt_schedule_irq","asm_sysvec_apic_timer_interrupt","__call_rcu_common.constprop.0","__destroy_inode","destroy_inode","prune_icache_sb","super_cache_scan","do_shrink_slab","shrink_slab_memcg","kswapd_try_to_sleep","lzo1x_1_do_compress.isra.0","lzogeneric1x_1_compress.isra.0","lzorle1x_1_compress","zram","zcomp_compress","zram_write_page","zram_bio_write","__submit_bio","__submit_bio_noacct","submit_bio_wait","swap_writepage_bdev_sync.isra.0","swap_writeout","writeout","_raw_spin_unlock","inode_lru_isolate","__list_lru_walk_one","list_lru_walk_one","asm_sysvec_reschedule_ipi","page_counter_try_charge","__mem_cgroup_try_charge_swap","folio_alloc_swap","xa_erase","__btrfs_release_delayed_node.part.0","btrfs_evict_inode","evict","usleep_range_state","acpi_ex_system_do_sleep","acpi_ex_opcode_1A_0T_0R","acpi_ds_exec_end_op","acpi_ps_parse_loop","acpi_ps_parse_aml","acpi_ps_execute_method","acpi_ns_evaluate","acpi_ev_asynch_execute_gpe_method","acpi_os_execute_deferred","bluetooth","__hci_cmd_sync_sk","__hci_cmd_sync_status_sk","hci_inquiry_sync","hci_cmd_sync_work","_raw_spin_unlock_irqrestore","dma_fence_add_callback","sync_file_poll","do_poll.constprop.0","do_sys_poll","__x64_sys_poll","irqentry_exit","common_nsleep","__x64_sys_clock_nanosleep","poll_schedule_timeout.constprop.0","__x64_sys_ppoll","io_schedule","rq_qos_wait","wbt_wait","__rq_qos_throttle","blk_mq_submit_bio","submit_bio_noacct_nocheck","dm_crypt","dmcrypt_write","mod_delayed_work_on","kblockd_mod_delayed_work_on","blk_mq_dispatch_list","blk_mq_flush_plug_list","__blk_flush_plug","ZSTD_decompressSequences_bmi2.constprop.0","ZSTD_decompressContinue.part.0","ZSTD_decompressContinueStream","ZSTD_decompressStream","zstd_decompress_bio","end_bbio_compressed_read","btrfs_check_read_bio","HUF_decompress4X2_usingDTable_internal_fast_c_loop","HUF_decompress4X2_usingDTable_internal_fast.constprop.0","HUF_decompress4X2_usingDTable_internal","ZSTD_decodeLiteralsBlock","ZSTD_decompressBlock_internal.part.0","usb_kill_urb","usb_kill_anchored_urbs","btusb","btusb_suspend","usb_suspend_both","usb_runtime_suspend","rpm_suspend","pm_runtime_work","usb_disable_usb2_hardware_lpm","usb_port_suspend","usb_generic_driver_suspend","lock_extent_buffer_for_io","btree_writepages","do_writepages","__writeback_single_inode","writeback_sb_inodes","__writeback_inodes_wb","wb_writeback","wb_workfn","hub_activate","hub_resume","usb_resume_interface.isra.0","i915","mmio_invalidate_full","intel_gt_invalidate_tlb_full","__i915_gem_object_unset_pages","__i915_gem_object_put_pages","__i915_gem_object_pages_fini","__i915_gem_free_objects.isra.0","__cond_resched_lock","find_first_inode_to_shrink","btrfs_extent_map_shrinker_worker","hub_quiesce","hub_suspend","__pm_runtime_suspend","usb_runtime_idle","rpm_idle","pci_set_low_power_state","__pci_set_power_state","pci_finish_runtime_suspend","pci_pm_runtime_suspend","xhci_stop_device.constprop.0.isra.0","kcompactd","rcu_tasks_wait_gp","rcu_tasks_one_gp","rcu_tasks_kthread","synchronize_rcu_normal","btrfs_compress_heuristic","btrfs_run_delalloc_range","writepage_delalloc","extent_writepage","extent_write_cache_pages","btrfs_writepages","folio_wait_bit_common","btrfs_clear_extent_bit_changeset","__flush_work","__lru_add_drain_all","khugepaged","__local_bh_enable_ip","xts_encrypt_vaes_avx2","crypt_convert_block_skcipher","crypt_convert","kcryptd_crypt_write_convert","bit_wait_io","__wait_on_bit","out_of_line_wait_on_bit","read_extent_buffer_pages","btrfs_read_extent_buffer","read_block_for_search","drm_atomic_helper_wait_for_flip_done","intel_atomic_commit_tail","add_delayed_ref","btrfs_free_tree_block","btrfs_force_cow_block","btrfs_cow_block","run_delalloc_nocow","css_rstat_flush","flush_memcg_stats_dwork","folio_wake_bit","end_bbio_data_read","btrfs_find_delalloc_range","find_lock_delalloc_range","btrfs_next_old_leaf","btrfs_lookup_csums_list","can_nocow_file_extent","pci_power_up","pci_pm_power_up_and_verify_state","pci_pm_runtime_resume","mempool_free_bulk","mempool_free","bio_free","psi_rtpoll_worker","rcu_gp_fqs_loop","rcu_gp_kthread","libc.so.6","libglib-2.0.so.0.8600.4","libgio-2.0.so.0.8600.4","xdg-desktop-portal","libgobject-2.0.so.0.8600.4"],"attributeTable":[{"value":{}},{"keyStrindex":4,"value":{"stringValue":"7b547e58a70dd26d821993906be478993a56599b"}},{"keyStrindex":5,"value":{"stringValue":"4494a39fd41444aeefd0bc20ed4291cb"}},{"keyStrindex":7,"value":{"stringValue":"kernel"}},{"keyStrindex":14,"value":{"stringValue":"migration/10"}},{"keyStrindex":15,"value":{"intValue":"66"}},{"keyStrindex":16,"value":{"intValue":"10"}},{"keyStrindex":14,"value":{"stringValue":"kworker/8:1"}},{"keyStrindex":15,"value":{"intValue":"2013966"}},{"keyStrindex":16,"value":{"intValue":"8"}},{"keyStrindex":14,"value":{"stringValue":"irq/189-iwlwifi"}},{"keyStrindex":15,"value":{"intValue":"1180"}},{"keyStrindex":16,"value":{"intValue":"3"}},{"keyStrindex":14,"value":{"stringValue":"rcu_exp_gp_kthr"}},{"keyStrindex":15,"value":{"intValue":"18"}},{"keyStrindex":16,"value":{"intValue":"2"}},{"keyStrindex":16,"value":{"intValue":"9"}},{"keyStrindex":16,"value":{"intValue":"0"}},{"keyStrindex":16,"value":{"intValue":"11"}},{"keyStrindex":16,"value":{"intValue":"7"}},{"keyStrindex":16,"value":{"intValue":"4"}},{"keyStrindex":16,"value":{"intValue":"1"}},{"keyStrindex":16,"value":{"intValue":"6"}},{"keyStrindex":16,"value":{"intValue":"5"}},{"keyStrindex":14,"value":{"stringValue":"kworker/6:1H"}},{"keyStrindex":15,"value":{"intValue":"278"}},{"keyStrindex":14,"value":{"stringValue":"migration/3"}},{"keyStrindex":15,"value":{"intValue":"84"}},{"keyStrindex":4,"value":{"stringValue":"6a9f8a6c1f8211533de21fdf73df8ea9827ab10d"}},{"keyStrindex":64,"value":{"stringValue":"OeVl-hOMi2Ufm9HG8B5l/j6O1Uoc09UIO0-0icHUK/fMRb2SIIl2wDgC8fHhY4/DX5zPPjiC1kPcoCeDhCX"}},{"keyStrindex":5,"value":{"stringValue":"4cb37b29f2ca50e692cc879e157d9ce9"}},{"keyStrindex":7,"value":{"stringValue":"go"}},{"keyStrindex":14,"value":{"stringValue":"containerd"}},{"keyStrindex":15,"value":{"intValue":"2017"}},{"keyStrindex":15,"value":{"intValue":"2016"}},{"keyStrindex":15,"value":{"intValue":"2012"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:0"}},{"keyStrindex":15,"value":{"intValue":"2016425"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:2"}},{"keyStrindex":15,"value":{"intValue":"2019040"}},{"keyStrindex":14,"value":{"stringValue":"kworker/11:0"}},{"keyStrindex":15,"value":{"intValue":"2017091"}},{"keyStrindex":4,"value":{"stringValue":"26299ec240f9dc12fb2b744c611a93d1ec173b82"}},{"keyStrindex":5,"value":{"stringValue":"185191bcd3047998ed6302255304d88d"}},{"keyStrindex":4,"value":{"stringValue":"dacb71a91d438f8f94e1aceee90bb36dc3c250ff"}},{"keyStrindex":5,"value":{"stringValue":"6bc526f880cfeb6dce6df73cc50a2e33"}},{"keyStrindex":14,"value":{"stringValue":"kworker/9:0"}},{"keyStrindex":15,"value":{"intValue":"2013473"}},{"keyStrindex":14,"value":{"stringValue":"kworker/6:0"}},{"keyStrindex":15,"value":{"intValue":"2012063"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:8"}},{"keyStrindex":15,"value":{"intValue":"2019042"}},{"keyStrindex":14,"value":{"stringValue":"migration/7"}},{"keyStrindex":15,"value":{"intValue":"48"}},{"keyStrindex":14,"value":{"stringValue":"kworker/3:0"}},{"keyStrindex":15,"value":{"intValue":"2013430"}},{"keyStrindex":14,"value":{"stringValue":"kswapd0"}},{"keyStrindex":15,"value":{"intValue":"118"}},{"keyStrindex":4,"value":{"stringValue":"59cf195409a1d66353035caf4d262325c968df53"}},{"keyStrindex":5,"value":{"stringValue":"35b111e30aa2cd54eae23c10b7323581"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:13"}},{"keyStrindex":15,"value":{"intValue":"2009007"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/0"}},{"keyStrindex":15,"value":{"intValue":"15"}},{"keyStrindex":14,"value":{"stringValue":"kworker/0:0"}},{"keyStrindex":15,"value":{"intValue":"2018339"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u49:3"}},{"keyStrindex":15,"value":{"intValue":"2019079"}},{"keyStrindex":4,"value":{"stringValue":"6fef910a1cb65f1d918fdb79ce81d21d9b61138a"}},{"keyStrindex":5,"value":{"stringValue":"c8b6882798add2cd1ae2ee9e0d89adce"}},{"keyStrindex":14,"value":{"stringValue":"kworker/4:1H"}},{"keyStrindex":15,"value":{"intValue":"271"}},{"keyStrindex":14,"value":{"stringValue":"eDP-1"}},{"keyStrindex":15,"value":{"intValue":"3193"}},{"keyStrindex":14,"value":{"stringValue":"kwin_wayland"}},{"keyStrindex":15,"value":{"intValue":"3066"}},{"keyStrindex":4,"value":{"stringValue":"21561265672356400f5c437db70e30f32ce12793"}},{"keyStrindex":5,"value":{"stringValue":"15c8d2aead236a36bdb54b6ac3a611a4"}},{"keyStrindex":14,"value":{"stringValue":"dmcrypt_write/2"}},{"keyStrindex":15,"value":{"intValue":"757"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:15"}},{"keyStrindex":15,"value":{"intValue":"2019854"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:18"}},{"keyStrindex":15,"value":{"intValue":"2019856"}},{"keyStrindex":4,"value":{"stringValue":"3498c7fb33302e816220ebd3cf073e2bed477bb3"}},{"keyStrindex":5,"value":{"stringValue":"e1ac4740252a423d77f345627666c8dc"}},{"keyStrindex":4,"value":{"stringValue":"7d1e6ccecce74adfe7950f5be10120f52c703b22"}},{"keyStrindex":5,"value":{"stringValue":"f6fc5b367dd002e50db8b92ff3d285e4"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/4"}},{"keyStrindex":15,"value":{"intValue":"31"}},{"keyStrindex":14,"value":{"stringValue":"irq/190-iwlwifi"}},{"keyStrindex":15,"value":{"intValue":"1181"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:5"}},{"keyStrindex":15,"value":{"intValue":"1961929"}},{"keyStrindex":14,"value":{"stringValue":"kworker/10:1"}},{"keyStrindex":15,"value":{"intValue":"2014063"}},{"keyStrindex":14,"value":{"stringValue":"kworker/4:2"}},{"keyStrindex":15,"value":{"intValue":"2012293"}},{"keyStrindex":14,"value":{"stringValue":"migration/2"}},{"keyStrindex":15,"value":{"intValue":"24"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/2"}},{"keyStrindex":15,"value":{"intValue":"25"}},{"keyStrindex":14,"value":{"stringValue":"migration/11"}},{"keyStrindex":15,"value":{"intValue":"72"}},{"keyStrindex":14,"value":{"stringValue":"kworker/1:2"}},{"keyStrindex":15,"value":{"intValue":"1442747"}},{"keyStrindex":14,"value":{"stringValue":"kcompactd0"}},{"keyStrindex":15,"value":{"intValue":"97"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:1"}},{"keyStrindex":15,"value":{"intValue":"2012776"}},{"keyStrindex":14,"value":{"stringValue":"migration/6"}},{"keyStrindex":15,"value":{"intValue":"42"}},{"keyStrindex":14,"value":{"stringValue":"rcu_tasks_trace"}},{"keyStrindex":15,"value":{"intValue":"92"}},{"keyStrindex":14,"value":{"stringValue":"kworker/11:1H"}},{"keyStrindex":15,"value":{"intValue":"226"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:19"}},{"keyStrindex":15,"value":{"intValue":"2019857"}},{"keyStrindex":14,"value":{"stringValue":"migration/4"}},{"keyStrindex":15,"value":{"intValue":"30"}},{"keyStrindex":14,"value":{"stringValue":"migration/0"}},{"keyStrindex":15,"value":{"intValue":"19"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/5"}},{"keyStrindex":15,"value":{"intValue":"37"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/8"}},{"keyStrindex":15,"value":{"intValue":"55"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:7"}},{"keyStrindex":15,"value":{"intValue":"2019041"}},{"keyStrindex":14,"value":{"stringValue":"kworker/1:1H"}},{"keyStrindex":15,"value":{"intValue":"229"}},{"keyStrindex":14,"value":{"stringValue":"irq/196-iwlwifi"}},{"keyStrindex":15,"value":{"intValue":"1187"}},{"keyStrindex":14,"value":{"stringValue":"kworker/7:0"}},{"keyStrindex":15,"value":{"intValue":"2012527"}},{"keyStrindex":14,"value":{"stringValue":"kworker/5:1"}},{"keyStrindex":15,"value":{"intValue":"1398751"}},{"keyStrindex":14,"value":{"stringValue":"irq/191-iwlwifi"}},{"keyStrindex":15,"value":{"intValue":"1182"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/10"}},{"keyStrindex":15,"value":{"intValue":"67"}},{"keyStrindex":14,"value":{"stringValue":"khugepaged"}},{"keyStrindex":15,"value":{"intValue":"99"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:10"}},{"keyStrindex":15,"value":{"intValue":"2019043"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:3"}},{"keyStrindex":15,"value":{"intValue":"2016788"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u49:1"}},{"keyStrindex":15,"value":{"intValue":"2014633"}},{"keyStrindex":14,"value":{"stringValue":"irq/188-iwlwifi"}},{"keyStrindex":15,"value":{"intValue":"1179"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:12"}},{"keyStrindex":15,"value":{"intValue":"2019853"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:17"}},{"keyStrindex":15,"value":{"intValue":"2019855"}},{"keyStrindex":14,"value":{"stringValue":"kworker/u48:4"}},{"keyStrindex":15,"value":{"intValue":"2013346"}},{"keyStrindex":14,"value":{"stringValue":"kworker/10:1H"}},{"keyStrindex":15,"value":{"intValue":"287"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/3"}},{"keyStrindex":15,"value":{"intValue":"85"}},{"keyStrindex":14,"value":{"stringValue":"psimon"}},{"keyStrindex":15,"value":{"intValue":"1288"}},{"keyStrindex":14,"value":{"stringValue":"kworker/9:1H"}},{"keyStrindex":15,"value":{"intValue":"281"}},{"keyStrindex":14,"value":{"stringValue":"migration/9"}},{"keyStrindex":15,"value":{"intValue":"60"}},{"keyStrindex":14,"value":{"stringValue":"ksoftirqd/1"}},{"keyStrindex":15,"value":{"intValue":"79"}},{"keyStrindex":14,"value":{"stringValue":"kworker/2:2"}},{"keyStrindex":15,"value":{"intValue":"2011794"}},{"keyStrindex":14,"value":{"stringValue":"kworker/7:1H"}},{"keyStrindex":15,"value":{"intValue":"116"}},{"keyStrindex":14,"value":{"stringValue":"rcu_preempt"}},{"keyStrindex":15,"value":{"intValue":"16"}},{"keyStrindex":14,"value":{"stringValue":"migration/5"}},{"keyStrindex":15,"value":{"intValue":"36"}},{"keyStrindex":14,"value":{"stringValue":"kworker/2:1H"}},{"keyStrindex":15,"value":{"intValue":"225"}},{"keyStrindex":4,"value":{"stringValue":"ff0267465bc3d76e21003b3bc5598fd5ee63e261"}},{"keyStrindex":5,"value":{"stringValue":"3d32373db239c02b3f4faa93171fbd1c"}},{"keyStrindex":7,"value":{"stringValue":"native"}},{"keyStrindex":4,"value":{"stringValue":"15d610c39cc8b0285512ad922544b1fe807347a7"}},{"keyStrindex":5,"value":{"stringValue":"d4198e8d0ee1d82549ed4df4e4489064"}},{"keyStrindex":4,"value":{"stringValue":"0430f16e5ded3ab85c7ca849b7da4c6ff73f2bae"}},{"keyStrindex":5,"value":{"stringValue":"7bd3f7611fada7a009775a498c888657"}},{"keyStrindex":14,"value":{"stringValue":"gdbus"}},{"keyStrindex":15,"value":{"intValue":"3097"}},{"keyStrindex":4,"value":{"stringValue":"f8c505eae46862dd410ab001e36e9d10fb5d7f5a"}},{"keyStrindex":5,"value":{"stringValue":"ac04bb854ef10f5a2e96014fbcc8850e"}},{"keyStrindex":4,"value":{"stringValue":"9997cd5a95b4e5ab1f36395138532e706f104bbf"}},{"keyStrindex":5,"value":{"stringValue":"e3b4be3549ba0a528f60b6c6b8d0d378"}},{"keyStrindex":14,"value":{"stringValue":"pool-1629"}},{"keyStrindex":15,"value":{"intValue":"327609"}},{"keyStrindex":14,"value":{"stringValue":"pool-1628"}},{"keyStrindex":15,"value":{"intValue":"327608"}},{"keyStrindex":14,"value":{"stringValue":"pool-1631"}},{"keyStrindex":15,"value":{"intValue":"2008364"}},{"keyStrindex":14,"value":{"stringValue":"xdg-desktop-por"}},{"keyStrindex":15,"value":{"intValue":"3088"}},{"keyStrindex":14,"value":{"stringValue":"kworker/3:1H"}},{"keyStrindex":15,"value":{"intValue":"273"}},{"keyStrindex":14,"value":{"stringValue":"migration/8"}},{"keyStrindex":15,"value":{"intValue":"54"}},{"keyStrindex":14,"value":{"stringValue":"kworker/0:1H"}},{"keyStrindex":15,"value":{"intValue":"228"}},{"keyStrindex":14,"value":{"stringValue":"migration/1"}},{"keyStrindex":15,"value":{"intValue":"78"}},{"keyStrindex":14,"value":{"stringValue":"kworker/8:1H"}},{"keyStrindex":15,"value":{"intValue":"272"}},{"keyStrindex":14,"value":{"stringValue":"kworker/5:1H"}},{"keyStrindex":15,"value":{"intValue":"136"}}],"stackTable":[{},{"locationIndices":[1,2,3,4,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,5,6,7]},{"locationIndices":[1,2,3,8,27,28,24,25,26,5,6,7]},{"locationIndices":[1,2,3,8,27,29,15,16,17,18,19,20,21,22,23,24,25,26,5,6,7]},{"locationIndices":[1,2,3,30,31,32,33,34,35,36,15,16,17,18,19,20,21,22,23,24,25,26,5,6,7]},{"locationIndices":[1,2,3,37,5,6,7]},{"locationIndices":[1,2,3,8,9,38,39,40,41,42,43,44,11,45,46,24,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,45,46,24,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,47,24,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,45,48,15,16,17,18,19,20,21,22,23,24,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,49,50,14,15,16,17,18,19,20,21,22,23,24,25,26,5,6,7]},{"locationIndices":[1,2,3,51,52,5,6,7]},{"locationIndices":[1,2,3,8,53,54,55,56,5,6,7]},{"locationIndices":[1,2,3,57,5,6,7]},{"locationIndices":[1,2,3,58,59,60,61,62,63,64,65,66,67,68,69,70,71]},{"locationIndices":[1,2,3,72,73,74,75,76,63,64,77,78,79,80,81,69,70,71]},{"locationIndices":[1,2,3,82,83,64,65,66,67,68,69,70,71]},{"locationIndices":[1,2,3,84,85,86,63,64,87,88,88,89,90,91]},{"locationIndices":[1,2,3,72,73,74,75,76,63,64,77,92,93,94,95,89,90,91]},{"locationIndices":[1,2,3,96,97,98,99,100,101,102,103,104,105,25,26,5,6,7]},{"locationIndices":[1,2,3,96,106,107,108,109,110,102,103,104,105,25,26,5,6,7]},{"locationIndices":[1,2,3,96,106,107,108,109,110,111,112,113,114,105,25,26,5,6,7]},{"locationIndices":[1,2,3,8,115,116,117,118,119,25,26,5,6,7]},{"locationIndices":[1,2,3,96,120,121,25,26,5,6,7]},{"locationIndices":[1,2,122,123,124,25,26,5,6,7]},{"locationIndices":[1,2,3,8,115,116,125,126,127,25,26,5,6,7]},{"locationIndices":[128,129,130,131,132,133,134,135,5,6,7]},{"locationIndices":[136,137,138,139,140,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[142,137,138,139,140,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[143,144,145,135,5,6,7]},{"locationIndices":[1,2,146,147,148,149,150,151,152,153,154,155,132,133,134,135,5,6,7]},{"locationIndices":[1,2,3,8,156,157,5,6,7]},{"locationIndices":[1,2,146,147,158,159,160,161,162,163,164,165,166,167,168,169,170,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[1,2,122,123,171,172,163,164,165,166,167,168,169,170,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[1,2,122,123,173,129,130,131,132,133,134,135,5,6,7]},{"locationIndices":[1,2,146,147,174,159,160,161,162,163,164,165,166,167,168,169,170,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[1,2,122,123,171,175,176,177,178,152,153,154,155,132,133,134,135,5,6,7]},{"locationIndices":[1,2,3,179,157,5,6,7]},{"locationIndices":[1,2,122,123,180,139,140,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[1,2,146,181,182,183,184,185,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[1,2,122,123,171,186,187,188,189,151,152,153,154,155,132,133,134,135,5,6,7]},{"locationIndices":[1,2,146,147,190,159,160,161,162,163,164,165,166,167,168,169,170,141,130,131,132,133,134,135,5,6,7]},{"locationIndices":[1,2,3,96,106,107,108,191,102,103,104,105,25,26,5,6,7]},{"locationIndices":[1,2,3,58,192,193,194,195,196,197,198,199,200,201,25,26,5,6,7]},{"locationIndices":[1,2,3,8,202,203,204,205,25,26,5,6,7]},{"locationIndices":[1,2,122,123,206,207,208,209,210,211,63,64]},{"locationIndices":[1,2,3,212,181]},{"locationIndices":[1,2,3,84,85,213,214,63,64]},{"locationIndices":[1,2,3,72,73,74,75,76,63,64]},{"locationIndices":[1,2,3,58,215,216,210,217,63,64]},{"locationIndices":[1,2,3,218,219,220,221,222,223,224,225,5,6,7]},{"locationIndices":[1,2,146,181,226,227,228,229,230,231,219,220,221,222,223,224,225,5,6,7]},{"locationIndices":[232,2,3,37,5,6,7]},{"locationIndices":[233,234,235,236,237,238,239,25,26,5,6,7]},{"locationIndices":[240,241,242,243,244,234,235,236,237,238,239,25,26,5,6,7]},{"locationIndices":[1,2,3,245,246,247,248,249,17,18,250,251,25,26,5,6,7]},{"locationIndices":[1,2,3,30,31,32,33,252,253,254,255,256,249,17,18,250,251,25,26,5,6,7]},{"locationIndices":[1,2,3,8,27,257,258,43,44,11,259,255,256,249,17,18,250,251,25,26,5,6,7]},{"locationIndices":[1,2,3,96,97,98,99,260,261,262,263,264,265,266,267,25,26,5,6,7]},{"locationIndices":[1,2,3,268,269,20,21,22,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,45,270,271,272,273,17,18,19,20,21,22,25,26,5,6,7]},{"locationIndices":[1,2,122,123,206,274,275,276,277,278,279,25,26,5,6,7]},{"locationIndices":[1,2,3,245,246,280,248,249,17,18,250,251,25,26,5,6,7]},{"locationIndices":[1,2,122,123,171,281,282,283,25,26,5,6,7]},{"locationIndices":[1,2,3,245,284,285,248,249,17,18,250,286,287,288,289,25,26,5,6,7]},{"locationIndices":[1,2,3,58,192,290,291,292,293,17,18,250,289,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,294,255,256,249,17,18,250,251,25,26,5,6,7]},{"locationIndices":[1,2,3,30,31,295,296,258,43,44,11,259,255,256,249,17,18,250,251,25,26,5,6,7]},{"locationIndices":[1,2,146,181,297,234,235,236,237,238,239,25,26,5,6,7]},{"locationIndices":[1,2,3,8,27,298,271,272,273,17,18,19,20,21,22,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,259,255,256,249,17,18,250,251,25,26,5,6,7]},{"locationIndices":[1,2,122,123,173,299,26,5,6,7]},{"locationIndices":[232,2,3,4,5,6,7]},{"locationIndices":[1,2,3,8,300,5,6,7]},{"locationIndices":[1,2,3,8,301,302,303,5,6,7]},{"locationIndices":[1,2,3,8,304,5,6,7]},{"locationIndices":[1,2,122,123,206,305,306,302,303,5,6,7]},{"locationIndices":[1,2,146,147,307,308,309,310,311,312,262,263,264,265,266,267,25,26,5,6,7]},{"locationIndices":[1,2,3,218,313,314,312,262,263,264,265,266,267,25,26,5,6,7]},{"locationIndices":[1,2,122,123,171,315,316,105,25,26,5,6,7]},{"locationIndices":[1,2,3,30,31,317,318,319,5,6,7]},{"locationIndices":[1,2,122,123,320,321,322,323,324,25,26,5,6,7]},{"locationIndices":[1,2,3,218,325,326,327,328,329,330,331,102,103,104,105,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,332,333,25,26,5,6,7]},{"locationIndices":[1,2,3,96,97,98,99,334,111,112,113,114,105,25,26,5,6,7]},{"locationIndices":[1,2,122,123,171,335,336,337,338,339,102,103,104,105,25,26,5,6,7]},{"locationIndices":[1,2,3,96,106,107,108,191,111,340,309,310,311,312,262,263,264,265,266,267,25,26,5,6,7]},{"locationIndices":[1,2,122,123,173,341,342,25,26,5,6,7]},{"locationIndices":[1,2,3,8,9,10,11,343,248,249,17,18,250,286,287,288,289,25,26,5,6,7]},{"locationIndices":[1,2,122,123,206,344,345,346,239,25,26,5,6,7]},{"locationIndices":[1,2,122,123,171,347,348,349,310,311,312,262,263,264,265,266,267,25,26,5,6,7]},{"locationIndices":[1,2,3,96,106,107,108,109,110,350,351,352,353,309,310,311,312,262,263,264,265,266,267,25,26,5,6,7]},{"locationIndices":[1,2,3,96,106,107,108,109,110,354,352,353,309,310,311,312,262,263,264,265,266,267,25,26,5,6,7]},{"locationIndices":[1,2,3,58,192,355,356,357,17,18,19,358,25,26,5,6,7]},{"locationIndices":[1,2,146,147,359,360,361,346,239,25,26,5,6,7]},{"locationIndices":[1,2,3,362,5,6,7]},{"locationIndices":[1,2,3,8,363,364,5,6,7]},{"locationIndices":[1,2,3,365,5,6,7]},{"locationIndices":[1,2,3,366,215,216,210,217,63,64,367,368,369,370,371,372,373,374,375,376]},{"locationIndices":[1,2,3,58,215,216,210,217,63,64,367,368,369,370,371,372,377,378,379,380,381,382,383,384,385,386,387,388,389,390,374,375,376]},{"locationIndices":[1,2,3,72,73,74,75,76,63,64,391,392,393,394,374,375,376]},{"locationIndices":[1,2,3,72,73,74,75,76,63,64,391,392,393,395,396,374,375,376]},{"locationIndices":[1,2,3,366,215,216,210,217,63,64,367,368,369,370,371,372,397,398,399,400]}]}} \ No newline at end of file diff --git a/pkg/test/logger.go b/pkg/test/logger.go index 8c0831e8f9..c4e3ad353c 100644 --- a/pkg/test/logger.go +++ b/pkg/test/logger.go @@ -3,22 +3,29 @@ package test import ( + "bytes" "testing" "github.com/go-kit/log" ) -type testingLogger struct { +type TestingLogger struct { t testing.TB } -func NewTestingLogger(t testing.TB) log.Logger { - return &testingLogger{ - t: t, - } +func NewTestingLogger(t testing.TB) *TestingLogger { + return &TestingLogger{t: t} } -func (l *testingLogger) Log(keyvals ...interface{}) error { - l.t.Log(keyvals...) +func (l *TestingLogger) Log(keyvals ...interface{}) error { + l.t.Helper() + buf := bytes.NewBuffer(nil) + lf := log.NewLogfmtLogger(buf) + lf.Log(keyvals...) + bs := buf.Bytes() + if len(bs) > 0 && bs[len(bs)-1] == '\n' { + bs = bs[:len(bs)-1] + } + l.t.Log(string(bs)) return nil } diff --git a/pkg/test/mocks/mockadaptiveplacement/mock_store.go b/pkg/test/mocks/mockadaptiveplacement/mock_store.go new file mode 100644 index 0000000000..3e81a1359d --- /dev/null +++ b/pkg/test/mocks/mockadaptiveplacement/mock_store.go @@ -0,0 +1,248 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockadaptiveplacement + +import ( + adaptive_placementpb "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement/adaptive_placementpb" + + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockStore is an autogenerated mock type for the Store type +type MockStore struct { + mock.Mock +} + +type MockStore_Expecter struct { + mock *mock.Mock +} + +func (_m *MockStore) EXPECT() *MockStore_Expecter { + return &MockStore_Expecter{mock: &_m.Mock} +} + +// LoadRules provides a mock function with given fields: _a0 +func (_m *MockStore) LoadRules(_a0 context.Context) (*adaptive_placementpb.PlacementRules, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for LoadRules") + } + + var r0 *adaptive_placementpb.PlacementRules + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*adaptive_placementpb.PlacementRules, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) *adaptive_placementpb.PlacementRules); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*adaptive_placementpb.PlacementRules) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStore_LoadRules_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoadRules' +type MockStore_LoadRules_Call struct { + *mock.Call +} + +// LoadRules is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockStore_Expecter) LoadRules(_a0 interface{}) *MockStore_LoadRules_Call { + return &MockStore_LoadRules_Call{Call: _e.mock.On("LoadRules", _a0)} +} + +func (_c *MockStore_LoadRules_Call) Run(run func(_a0 context.Context)) *MockStore_LoadRules_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockStore_LoadRules_Call) Return(_a0 *adaptive_placementpb.PlacementRules, _a1 error) *MockStore_LoadRules_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStore_LoadRules_Call) RunAndReturn(run func(context.Context) (*adaptive_placementpb.PlacementRules, error)) *MockStore_LoadRules_Call { + _c.Call.Return(run) + return _c +} + +// LoadStats provides a mock function with given fields: _a0 +func (_m *MockStore) LoadStats(_a0 context.Context) (*adaptive_placementpb.DistributionStats, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for LoadStats") + } + + var r0 *adaptive_placementpb.DistributionStats + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*adaptive_placementpb.DistributionStats, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) *adaptive_placementpb.DistributionStats); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*adaptive_placementpb.DistributionStats) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStore_LoadStats_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoadStats' +type MockStore_LoadStats_Call struct { + *mock.Call +} + +// LoadStats is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockStore_Expecter) LoadStats(_a0 interface{}) *MockStore_LoadStats_Call { + return &MockStore_LoadStats_Call{Call: _e.mock.On("LoadStats", _a0)} +} + +func (_c *MockStore_LoadStats_Call) Run(run func(_a0 context.Context)) *MockStore_LoadStats_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockStore_LoadStats_Call) Return(_a0 *adaptive_placementpb.DistributionStats, _a1 error) *MockStore_LoadStats_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStore_LoadStats_Call) RunAndReturn(run func(context.Context) (*adaptive_placementpb.DistributionStats, error)) *MockStore_LoadStats_Call { + _c.Call.Return(run) + return _c +} + +// StoreRules provides a mock function with given fields: _a0, _a1 +func (_m *MockStore) StoreRules(_a0 context.Context, _a1 *adaptive_placementpb.PlacementRules) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for StoreRules") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *adaptive_placementpb.PlacementRules) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStore_StoreRules_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StoreRules' +type MockStore_StoreRules_Call struct { + *mock.Call +} + +// StoreRules is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *adaptive_placementpb.PlacementRules +func (_e *MockStore_Expecter) StoreRules(_a0 interface{}, _a1 interface{}) *MockStore_StoreRules_Call { + return &MockStore_StoreRules_Call{Call: _e.mock.On("StoreRules", _a0, _a1)} +} + +func (_c *MockStore_StoreRules_Call) Run(run func(_a0 context.Context, _a1 *adaptive_placementpb.PlacementRules)) *MockStore_StoreRules_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*adaptive_placementpb.PlacementRules)) + }) + return _c +} + +func (_c *MockStore_StoreRules_Call) Return(_a0 error) *MockStore_StoreRules_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_StoreRules_Call) RunAndReturn(run func(context.Context, *adaptive_placementpb.PlacementRules) error) *MockStore_StoreRules_Call { + _c.Call.Return(run) + return _c +} + +// StoreStats provides a mock function with given fields: _a0, _a1 +func (_m *MockStore) StoreStats(_a0 context.Context, _a1 *adaptive_placementpb.DistributionStats) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for StoreStats") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *adaptive_placementpb.DistributionStats) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStore_StoreStats_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StoreStats' +type MockStore_StoreStats_Call struct { + *mock.Call +} + +// StoreStats is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *adaptive_placementpb.DistributionStats +func (_e *MockStore_Expecter) StoreStats(_a0 interface{}, _a1 interface{}) *MockStore_StoreStats_Call { + return &MockStore_StoreStats_Call{Call: _e.mock.On("StoreStats", _a0, _a1)} +} + +func (_c *MockStore_StoreStats_Call) Run(run func(_a0 context.Context, _a1 *adaptive_placementpb.DistributionStats)) *MockStore_StoreStats_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*adaptive_placementpb.DistributionStats)) + }) + return _c +} + +func (_c *MockStore_StoreStats_Call) Return(_a0 error) *MockStore_StoreStats_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_StoreStats_Call) RunAndReturn(run func(context.Context, *adaptive_placementpb.DistributionStats) error) *MockStore_StoreStats_Call { + _c.Call.Return(run) + return _c +} + +// NewMockStore creates a new instance of MockStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockStore(t interface { + mock.TestingT + Cleanup(func()) +}) *MockStore { + mock := &MockStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockclient/mock_repository_service.go b/pkg/test/mocks/mockclient/mock_repository_service.go new file mode 100644 index 0000000000..d6caf6dbeb --- /dev/null +++ b/pkg/test/mocks/mockclient/mock_repository_service.go @@ -0,0 +1,188 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockclient + +import ( + context "context" + + github "github.com/google/go-github/v81/github" + mock "github.com/stretchr/testify/mock" +) + +// MockrepositoryService is an autogenerated mock type for the repositoryService type +type MockrepositoryService struct { + mock.Mock +} + +type MockrepositoryService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockrepositoryService) EXPECT() *MockrepositoryService_Expecter { + return &MockrepositoryService_Expecter{mock: &_m.Mock} +} + +// GetCommit provides a mock function with given fields: ctx, owner, repo, ref, opts +func (_m *MockrepositoryService) GetCommit(ctx context.Context, owner string, repo string, ref string, opts *github.ListOptions) (*github.RepositoryCommit, *github.Response, error) { + ret := _m.Called(ctx, owner, repo, ref, opts) + + if len(ret) == 0 { + panic("no return value specified for GetCommit") + } + + var r0 *github.RepositoryCommit + var r1 *github.Response + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *github.ListOptions) (*github.RepositoryCommit, *github.Response, error)); ok { + return rf(ctx, owner, repo, ref, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *github.ListOptions) *github.RepositoryCommit); ok { + r0 = rf(ctx, owner, repo, ref, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*github.RepositoryCommit) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, *github.ListOptions) *github.Response); ok { + r1 = rf(ctx, owner, repo, ref, opts) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*github.Response) + } + } + + if rf, ok := ret.Get(2).(func(context.Context, string, string, string, *github.ListOptions) error); ok { + r2 = rf(ctx, owner, repo, ref, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockrepositoryService_GetCommit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommit' +type MockrepositoryService_GetCommit_Call struct { + *mock.Call +} + +// GetCommit is a helper method to define mock.On call +// - ctx context.Context +// - owner string +// - repo string +// - ref string +// - opts *github.ListOptions +func (_e *MockrepositoryService_Expecter) GetCommit(ctx interface{}, owner interface{}, repo interface{}, ref interface{}, opts interface{}) *MockrepositoryService_GetCommit_Call { + return &MockrepositoryService_GetCommit_Call{Call: _e.mock.On("GetCommit", ctx, owner, repo, ref, opts)} +} + +func (_c *MockrepositoryService_GetCommit_Call) Run(run func(ctx context.Context, owner string, repo string, ref string, opts *github.ListOptions)) *MockrepositoryService_GetCommit_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(*github.ListOptions)) + }) + return _c +} + +func (_c *MockrepositoryService_GetCommit_Call) Return(_a0 *github.RepositoryCommit, _a1 *github.Response, _a2 error) *MockrepositoryService_GetCommit_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockrepositoryService_GetCommit_Call) RunAndReturn(run func(context.Context, string, string, string, *github.ListOptions) (*github.RepositoryCommit, *github.Response, error)) *MockrepositoryService_GetCommit_Call { + _c.Call.Return(run) + return _c +} + +// GetContents provides a mock function with given fields: ctx, owner, repo, path, opts +func (_m *MockrepositoryService) GetContents(ctx context.Context, owner string, repo string, path string, opts *github.RepositoryContentGetOptions) (*github.RepositoryContent, []*github.RepositoryContent, *github.Response, error) { + ret := _m.Called(ctx, owner, repo, path, opts) + + if len(ret) == 0 { + panic("no return value specified for GetContents") + } + + var r0 *github.RepositoryContent + var r1 []*github.RepositoryContent + var r2 *github.Response + var r3 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *github.RepositoryContentGetOptions) (*github.RepositoryContent, []*github.RepositoryContent, *github.Response, error)); ok { + return rf(ctx, owner, repo, path, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *github.RepositoryContentGetOptions) *github.RepositoryContent); ok { + r0 = rf(ctx, owner, repo, path, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*github.RepositoryContent) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, *github.RepositoryContentGetOptions) []*github.RepositoryContent); ok { + r1 = rf(ctx, owner, repo, path, opts) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).([]*github.RepositoryContent) + } + } + + if rf, ok := ret.Get(2).(func(context.Context, string, string, string, *github.RepositoryContentGetOptions) *github.Response); ok { + r2 = rf(ctx, owner, repo, path, opts) + } else { + if ret.Get(2) != nil { + r2 = ret.Get(2).(*github.Response) + } + } + + if rf, ok := ret.Get(3).(func(context.Context, string, string, string, *github.RepositoryContentGetOptions) error); ok { + r3 = rf(ctx, owner, repo, path, opts) + } else { + r3 = ret.Error(3) + } + + return r0, r1, r2, r3 +} + +// MockrepositoryService_GetContents_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetContents' +type MockrepositoryService_GetContents_Call struct { + *mock.Call +} + +// GetContents is a helper method to define mock.On call +// - ctx context.Context +// - owner string +// - repo string +// - path string +// - opts *github.RepositoryContentGetOptions +func (_e *MockrepositoryService_Expecter) GetContents(ctx interface{}, owner interface{}, repo interface{}, path interface{}, opts interface{}) *MockrepositoryService_GetContents_Call { + return &MockrepositoryService_GetContents_Call{Call: _e.mock.On("GetContents", ctx, owner, repo, path, opts)} +} + +func (_c *MockrepositoryService_GetContents_Call) Run(run func(ctx context.Context, owner string, repo string, path string, opts *github.RepositoryContentGetOptions)) *MockrepositoryService_GetContents_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(*github.RepositoryContentGetOptions)) + }) + return _c +} + +func (_c *MockrepositoryService_GetContents_Call) Return(_a0 *github.RepositoryContent, _a1 []*github.RepositoryContent, _a2 *github.Response, _a3 error) *MockrepositoryService_GetContents_Call { + _c.Call.Return(_a0, _a1, _a2, _a3) + return _c +} + +func (_c *MockrepositoryService_GetContents_Call) RunAndReturn(run func(context.Context, string, string, string, *github.RepositoryContentGetOptions) (*github.RepositoryContent, []*github.RepositoryContent, *github.Response, error)) *MockrepositoryService_GetContents_Call { + _c.Call.Return(run) + return _c +} + +// NewMockrepositoryService creates a new instance of MockrepositoryService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockrepositoryService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockrepositoryService { + mock := &MockrepositoryService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockcompactor/mock_block_queue_store.go b/pkg/test/mocks/mockcompactor/mock_block_queue_store.go new file mode 100644 index 0000000000..99811e0c07 --- /dev/null +++ b/pkg/test/mocks/mockcompactor/mock_block_queue_store.go @@ -0,0 +1,227 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockcompactor + +import ( + compaction "github.com/grafana/pyroscope/v2/pkg/metastore/compaction" + bbolt "go.etcd.io/bbolt" + + iter "github.com/grafana/pyroscope/v2/pkg/iter" + mock "github.com/stretchr/testify/mock" +) + +// MockBlockQueueStore is an autogenerated mock type for the BlockQueueStore type +type MockBlockQueueStore struct { + mock.Mock +} + +type MockBlockQueueStore_Expecter struct { + mock *mock.Mock +} + +func (_m *MockBlockQueueStore) EXPECT() *MockBlockQueueStore_Expecter { + return &MockBlockQueueStore_Expecter{mock: &_m.Mock} +} + +// CreateBuckets provides a mock function with given fields: _a0 +func (_m *MockBlockQueueStore) CreateBuckets(_a0 *bbolt.Tx) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for CreateBuckets") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBlockQueueStore_CreateBuckets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateBuckets' +type MockBlockQueueStore_CreateBuckets_Call struct { + *mock.Call +} + +// CreateBuckets is a helper method to define mock.On call +// - _a0 *bbolt.Tx +func (_e *MockBlockQueueStore_Expecter) CreateBuckets(_a0 interface{}) *MockBlockQueueStore_CreateBuckets_Call { + return &MockBlockQueueStore_CreateBuckets_Call{Call: _e.mock.On("CreateBuckets", _a0)} +} + +func (_c *MockBlockQueueStore_CreateBuckets_Call) Run(run func(_a0 *bbolt.Tx)) *MockBlockQueueStore_CreateBuckets_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx)) + }) + return _c +} + +func (_c *MockBlockQueueStore_CreateBuckets_Call) Return(_a0 error) *MockBlockQueueStore_CreateBuckets_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBlockQueueStore_CreateBuckets_Call) RunAndReturn(run func(*bbolt.Tx) error) *MockBlockQueueStore_CreateBuckets_Call { + _c.Call.Return(run) + return _c +} + +// DeleteEntry provides a mock function with given fields: tx, index, id +func (_m *MockBlockQueueStore) DeleteEntry(tx *bbolt.Tx, index uint64, id string) error { + ret := _m.Called(tx, index, id) + + if len(ret) == 0 { + panic("no return value specified for DeleteEntry") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, uint64, string) error); ok { + r0 = rf(tx, index, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBlockQueueStore_DeleteEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteEntry' +type MockBlockQueueStore_DeleteEntry_Call struct { + *mock.Call +} + +// DeleteEntry is a helper method to define mock.On call +// - tx *bbolt.Tx +// - index uint64 +// - id string +func (_e *MockBlockQueueStore_Expecter) DeleteEntry(tx interface{}, index interface{}, id interface{}) *MockBlockQueueStore_DeleteEntry_Call { + return &MockBlockQueueStore_DeleteEntry_Call{Call: _e.mock.On("DeleteEntry", tx, index, id)} +} + +func (_c *MockBlockQueueStore_DeleteEntry_Call) Run(run func(tx *bbolt.Tx, index uint64, id string)) *MockBlockQueueStore_DeleteEntry_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(uint64), args[2].(string)) + }) + return _c +} + +func (_c *MockBlockQueueStore_DeleteEntry_Call) Return(_a0 error) *MockBlockQueueStore_DeleteEntry_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBlockQueueStore_DeleteEntry_Call) RunAndReturn(run func(*bbolt.Tx, uint64, string) error) *MockBlockQueueStore_DeleteEntry_Call { + _c.Call.Return(run) + return _c +} + +// ListEntries provides a mock function with given fields: _a0 +func (_m *MockBlockQueueStore) ListEntries(_a0 *bbolt.Tx) iter.Iterator[compaction.BlockEntry] { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for ListEntries") + } + + var r0 iter.Iterator[compaction.BlockEntry] + if rf, ok := ret.Get(0).(func(*bbolt.Tx) iter.Iterator[compaction.BlockEntry]); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(iter.Iterator[compaction.BlockEntry]) + } + } + + return r0 +} + +// MockBlockQueueStore_ListEntries_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListEntries' +type MockBlockQueueStore_ListEntries_Call struct { + *mock.Call +} + +// ListEntries is a helper method to define mock.On call +// - _a0 *bbolt.Tx +func (_e *MockBlockQueueStore_Expecter) ListEntries(_a0 interface{}) *MockBlockQueueStore_ListEntries_Call { + return &MockBlockQueueStore_ListEntries_Call{Call: _e.mock.On("ListEntries", _a0)} +} + +func (_c *MockBlockQueueStore_ListEntries_Call) Run(run func(_a0 *bbolt.Tx)) *MockBlockQueueStore_ListEntries_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx)) + }) + return _c +} + +func (_c *MockBlockQueueStore_ListEntries_Call) Return(_a0 iter.Iterator[compaction.BlockEntry]) *MockBlockQueueStore_ListEntries_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBlockQueueStore_ListEntries_Call) RunAndReturn(run func(*bbolt.Tx) iter.Iterator[compaction.BlockEntry]) *MockBlockQueueStore_ListEntries_Call { + _c.Call.Return(run) + return _c +} + +// StoreEntry provides a mock function with given fields: _a0, _a1 +func (_m *MockBlockQueueStore) StoreEntry(_a0 *bbolt.Tx, _a1 compaction.BlockEntry) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for StoreEntry") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, compaction.BlockEntry) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBlockQueueStore_StoreEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StoreEntry' +type MockBlockQueueStore_StoreEntry_Call struct { + *mock.Call +} + +// StoreEntry is a helper method to define mock.On call +// - _a0 *bbolt.Tx +// - _a1 compaction.BlockEntry +func (_e *MockBlockQueueStore_Expecter) StoreEntry(_a0 interface{}, _a1 interface{}) *MockBlockQueueStore_StoreEntry_Call { + return &MockBlockQueueStore_StoreEntry_Call{Call: _e.mock.On("StoreEntry", _a0, _a1)} +} + +func (_c *MockBlockQueueStore_StoreEntry_Call) Run(run func(_a0 *bbolt.Tx, _a1 compaction.BlockEntry)) *MockBlockQueueStore_StoreEntry_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(compaction.BlockEntry)) + }) + return _c +} + +func (_c *MockBlockQueueStore_StoreEntry_Call) Return(_a0 error) *MockBlockQueueStore_StoreEntry_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBlockQueueStore_StoreEntry_Call) RunAndReturn(run func(*bbolt.Tx, compaction.BlockEntry) error) *MockBlockQueueStore_StoreEntry_Call { + _c.Call.Return(run) + return _c +} + +// NewMockBlockQueueStore creates a new instance of MockBlockQueueStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockBlockQueueStore(t interface { + mock.TestingT + Cleanup(func()) +}) *MockBlockQueueStore { + mock := &MockBlockQueueStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockcompactor/mock_tombstones.go b/pkg/test/mocks/mockcompactor/mock_tombstones.go new file mode 100644 index 0000000000..79505533bc --- /dev/null +++ b/pkg/test/mocks/mockcompactor/mock_tombstones.go @@ -0,0 +1,86 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockcompactor + +import ( + time "time" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + iter "github.com/grafana/pyroscope/v2/pkg/iter" + mock "github.com/stretchr/testify/mock" +) + +// MockTombstones is an autogenerated mock type for the Tombstones type +type MockTombstones struct { + mock.Mock +} + +type MockTombstones_Expecter struct { + mock *mock.Mock +} + +func (_m *MockTombstones) EXPECT() *MockTombstones_Expecter { + return &MockTombstones_Expecter{mock: &_m.Mock} +} + +// ListTombstones provides a mock function with given fields: before +func (_m *MockTombstones) ListTombstones(before time.Time) iter.Iterator[*metastorev1.Tombstones] { + ret := _m.Called(before) + + if len(ret) == 0 { + panic("no return value specified for ListTombstones") + } + + var r0 iter.Iterator[*metastorev1.Tombstones] + if rf, ok := ret.Get(0).(func(time.Time) iter.Iterator[*metastorev1.Tombstones]); ok { + r0 = rf(before) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(iter.Iterator[*metastorev1.Tombstones]) + } + } + + return r0 +} + +// MockTombstones_ListTombstones_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListTombstones' +type MockTombstones_ListTombstones_Call struct { + *mock.Call +} + +// ListTombstones is a helper method to define mock.On call +// - before time.Time +func (_e *MockTombstones_Expecter) ListTombstones(before interface{}) *MockTombstones_ListTombstones_Call { + return &MockTombstones_ListTombstones_Call{Call: _e.mock.On("ListTombstones", before)} +} + +func (_c *MockTombstones_ListTombstones_Call) Run(run func(before time.Time)) *MockTombstones_ListTombstones_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(time.Time)) + }) + return _c +} + +func (_c *MockTombstones_ListTombstones_Call) Return(_a0 iter.Iterator[*metastorev1.Tombstones]) *MockTombstones_ListTombstones_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockTombstones_ListTombstones_Call) RunAndReturn(run func(time.Time) iter.Iterator[*metastorev1.Tombstones]) *MockTombstones_ListTombstones_Call { + _c.Call.Return(run) + return _c +} + +// NewMockTombstones creates a new instance of MockTombstones. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockTombstones(t interface { + mock.TestingT + Cleanup(func()) +}) *MockTombstones { + mock := &MockTombstones{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockdiscovery/mock_discovery.go b/pkg/test/mocks/mockdiscovery/mock_discovery.go new file mode 100644 index 0000000000..4ef9006e3c --- /dev/null +++ b/pkg/test/mocks/mockdiscovery/mock_discovery.go @@ -0,0 +1,132 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockdiscovery + +import ( + discovery "github.com/grafana/pyroscope/v2/pkg/metastore/discovery" + mock "github.com/stretchr/testify/mock" +) + +// MockDiscovery is an autogenerated mock type for the Discovery type +type MockDiscovery struct { + mock.Mock +} + +type MockDiscovery_Expecter struct { + mock *mock.Mock +} + +func (_m *MockDiscovery) EXPECT() *MockDiscovery_Expecter { + return &MockDiscovery_Expecter{mock: &_m.Mock} +} + +// Close provides a mock function with no fields +func (_m *MockDiscovery) Close() { + _m.Called() +} + +// MockDiscovery_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type MockDiscovery_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +func (_e *MockDiscovery_Expecter) Close() *MockDiscovery_Close_Call { + return &MockDiscovery_Close_Call{Call: _e.mock.On("Close")} +} + +func (_c *MockDiscovery_Close_Call) Run(run func()) *MockDiscovery_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockDiscovery_Close_Call) Return() *MockDiscovery_Close_Call { + _c.Call.Return() + return _c +} + +func (_c *MockDiscovery_Close_Call) RunAndReturn(run func()) *MockDiscovery_Close_Call { + _c.Run(run) + return _c +} + +// Rediscover provides a mock function with no fields +func (_m *MockDiscovery) Rediscover() { + _m.Called() +} + +// MockDiscovery_Rediscover_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Rediscover' +type MockDiscovery_Rediscover_Call struct { + *mock.Call +} + +// Rediscover is a helper method to define mock.On call +func (_e *MockDiscovery_Expecter) Rediscover() *MockDiscovery_Rediscover_Call { + return &MockDiscovery_Rediscover_Call{Call: _e.mock.On("Rediscover")} +} + +func (_c *MockDiscovery_Rediscover_Call) Run(run func()) *MockDiscovery_Rediscover_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockDiscovery_Rediscover_Call) Return() *MockDiscovery_Rediscover_Call { + _c.Call.Return() + return _c +} + +func (_c *MockDiscovery_Rediscover_Call) RunAndReturn(run func()) *MockDiscovery_Rediscover_Call { + _c.Run(run) + return _c +} + +// Subscribe provides a mock function with given fields: updates +func (_m *MockDiscovery) Subscribe(updates discovery.Updates) { + _m.Called(updates) +} + +// MockDiscovery_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type MockDiscovery_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - updates discovery.Updates +func (_e *MockDiscovery_Expecter) Subscribe(updates interface{}) *MockDiscovery_Subscribe_Call { + return &MockDiscovery_Subscribe_Call{Call: _e.mock.On("Subscribe", updates)} +} + +func (_c *MockDiscovery_Subscribe_Call) Run(run func(updates discovery.Updates)) *MockDiscovery_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(discovery.Updates)) + }) + return _c +} + +func (_c *MockDiscovery_Subscribe_Call) Return() *MockDiscovery_Subscribe_Call { + _c.Call.Return() + return _c +} + +func (_c *MockDiscovery_Subscribe_Call) RunAndReturn(run func(discovery.Updates)) *MockDiscovery_Subscribe_Call { + _c.Run(run) + return _c +} + +// NewMockDiscovery creates a new instance of MockDiscovery. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockDiscovery(t interface { + mock.TestingT + Cleanup(func()) +}) *MockDiscovery { + mock := &MockDiscovery{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockdlq/mock_metastore.go b/pkg/test/mocks/mockdlq/mock_metastore.go new file mode 100644 index 0000000000..e2365b49ba --- /dev/null +++ b/pkg/test/mocks/mockdlq/mock_metastore.go @@ -0,0 +1,96 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockdlq + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" +) + +// MockMetastore is an autogenerated mock type for the Metastore type +type MockMetastore struct { + mock.Mock +} + +type MockMetastore_Expecter struct { + mock *mock.Mock +} + +func (_m *MockMetastore) EXPECT() *MockMetastore_Expecter { + return &MockMetastore_Expecter{mock: &_m.Mock} +} + +// AddRecoveredBlock provides a mock function with given fields: _a0, _a1 +func (_m *MockMetastore) AddRecoveredBlock(_a0 context.Context, _a1 *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddRecoveredBlock") + } + + var r0 *metastorev1.AddBlockResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.AddBlockRequest) *metastorev1.AddBlockResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.AddBlockResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.AddBlockRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMetastore_AddRecoveredBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddRecoveredBlock' +type MockMetastore_AddRecoveredBlock_Call struct { + *mock.Call +} + +// AddRecoveredBlock is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.AddBlockRequest +func (_e *MockMetastore_Expecter) AddRecoveredBlock(_a0 interface{}, _a1 interface{}) *MockMetastore_AddRecoveredBlock_Call { + return &MockMetastore_AddRecoveredBlock_Call{Call: _e.mock.On("AddRecoveredBlock", _a0, _a1)} +} + +func (_c *MockMetastore_AddRecoveredBlock_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.AddBlockRequest)) *MockMetastore_AddRecoveredBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.AddBlockRequest)) + }) + return _c +} + +func (_c *MockMetastore_AddRecoveredBlock_Call) Return(_a0 *metastorev1.AddBlockResponse, _a1 error) *MockMetastore_AddRecoveredBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMetastore_AddRecoveredBlock_Call) RunAndReturn(run func(context.Context, *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error)) *MockMetastore_AddRecoveredBlock_Call { + _c.Call.Return(run) + return _c +} + +// NewMockMetastore creates a new instance of MockMetastore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockMetastore(t interface { + mock.TestingT + Cleanup(func()) +}) *MockMetastore { + mock := &MockMetastore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockfrontend/mock_limits.go b/pkg/test/mocks/mockfrontend/mock_limits.go new file mode 100644 index 0000000000..3eb0cd229e --- /dev/null +++ b/pkg/test/mocks/mockfrontend/mock_limits.go @@ -0,0 +1,542 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockfrontend + +import ( + time "time" + + mock "github.com/stretchr/testify/mock" +) + +// MockLimits is an autogenerated mock type for the Limits type +type MockLimits struct { + mock.Mock +} + +type MockLimits_Expecter struct { + mock *mock.Mock +} + +func (_m *MockLimits) EXPECT() *MockLimits_Expecter { + return &MockLimits_Expecter{mock: &_m.Mock} +} + +// MaxFlameGraphNodesDefault provides a mock function with given fields: _a0 +func (_m *MockLimits) MaxFlameGraphNodesDefault(_a0 string) int { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for MaxFlameGraphNodesDefault") + } + + var r0 int + if rf, ok := ret.Get(0).(func(string) int); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// MockLimits_MaxFlameGraphNodesDefault_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxFlameGraphNodesDefault' +type MockLimits_MaxFlameGraphNodesDefault_Call struct { + *mock.Call +} + +// MaxFlameGraphNodesDefault is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) MaxFlameGraphNodesDefault(_a0 interface{}) *MockLimits_MaxFlameGraphNodesDefault_Call { + return &MockLimits_MaxFlameGraphNodesDefault_Call{Call: _e.mock.On("MaxFlameGraphNodesDefault", _a0)} +} + +func (_c *MockLimits_MaxFlameGraphNodesDefault_Call) Run(run func(_a0 string)) *MockLimits_MaxFlameGraphNodesDefault_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_MaxFlameGraphNodesDefault_Call) Return(_a0 int) *MockLimits_MaxFlameGraphNodesDefault_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_MaxFlameGraphNodesDefault_Call) RunAndReturn(run func(string) int) *MockLimits_MaxFlameGraphNodesDefault_Call { + _c.Call.Return(run) + return _c +} + +// MaxFlameGraphNodesMax provides a mock function with given fields: _a0 +func (_m *MockLimits) MaxFlameGraphNodesMax(_a0 string) int { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for MaxFlameGraphNodesMax") + } + + var r0 int + if rf, ok := ret.Get(0).(func(string) int); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// MockLimits_MaxFlameGraphNodesMax_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxFlameGraphNodesMax' +type MockLimits_MaxFlameGraphNodesMax_Call struct { + *mock.Call +} + +// MaxFlameGraphNodesMax is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) MaxFlameGraphNodesMax(_a0 interface{}) *MockLimits_MaxFlameGraphNodesMax_Call { + return &MockLimits_MaxFlameGraphNodesMax_Call{Call: _e.mock.On("MaxFlameGraphNodesMax", _a0)} +} + +func (_c *MockLimits_MaxFlameGraphNodesMax_Call) Run(run func(_a0 string)) *MockLimits_MaxFlameGraphNodesMax_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_MaxFlameGraphNodesMax_Call) Return(_a0 int) *MockLimits_MaxFlameGraphNodesMax_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_MaxFlameGraphNodesMax_Call) RunAndReturn(run func(string) int) *MockLimits_MaxFlameGraphNodesMax_Call { + _c.Call.Return(run) + return _c +} + +// MaxFlameGraphNodesOnSelectMergeProfile provides a mock function with given fields: _a0 +func (_m *MockLimits) MaxFlameGraphNodesOnSelectMergeProfile(_a0 string) bool { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for MaxFlameGraphNodesOnSelectMergeProfile") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxFlameGraphNodesOnSelectMergeProfile' +type MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call struct { + *mock.Call +} + +// MaxFlameGraphNodesOnSelectMergeProfile is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) MaxFlameGraphNodesOnSelectMergeProfile(_a0 interface{}) *MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call { + return &MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call{Call: _e.mock.On("MaxFlameGraphNodesOnSelectMergeProfile", _a0)} +} + +func (_c *MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call) Run(run func(_a0 string)) *MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call) Return(_a0 bool) *MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call) RunAndReturn(run func(string) bool) *MockLimits_MaxFlameGraphNodesOnSelectMergeProfile_Call { + _c.Call.Return(run) + return _c +} + +// MaxQueryLength provides a mock function with given fields: tenantID +func (_m *MockLimits) MaxQueryLength(tenantID string) time.Duration { + ret := _m.Called(tenantID) + + if len(ret) == 0 { + panic("no return value specified for MaxQueryLength") + } + + var r0 time.Duration + if rf, ok := ret.Get(0).(func(string) time.Duration); ok { + r0 = rf(tenantID) + } else { + r0 = ret.Get(0).(time.Duration) + } + + return r0 +} + +// MockLimits_MaxQueryLength_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxQueryLength' +type MockLimits_MaxQueryLength_Call struct { + *mock.Call +} + +// MaxQueryLength is a helper method to define mock.On call +// - tenantID string +func (_e *MockLimits_Expecter) MaxQueryLength(tenantID interface{}) *MockLimits_MaxQueryLength_Call { + return &MockLimits_MaxQueryLength_Call{Call: _e.mock.On("MaxQueryLength", tenantID)} +} + +func (_c *MockLimits_MaxQueryLength_Call) Run(run func(tenantID string)) *MockLimits_MaxQueryLength_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_MaxQueryLength_Call) Return(_a0 time.Duration) *MockLimits_MaxQueryLength_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_MaxQueryLength_Call) RunAndReturn(run func(string) time.Duration) *MockLimits_MaxQueryLength_Call { + _c.Call.Return(run) + return _c +} + +// MaxQueryLookback provides a mock function with given fields: tenantID +func (_m *MockLimits) MaxQueryLookback(tenantID string) time.Duration { + ret := _m.Called(tenantID) + + if len(ret) == 0 { + panic("no return value specified for MaxQueryLookback") + } + + var r0 time.Duration + if rf, ok := ret.Get(0).(func(string) time.Duration); ok { + r0 = rf(tenantID) + } else { + r0 = ret.Get(0).(time.Duration) + } + + return r0 +} + +// MockLimits_MaxQueryLookback_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxQueryLookback' +type MockLimits_MaxQueryLookback_Call struct { + *mock.Call +} + +// MaxQueryLookback is a helper method to define mock.On call +// - tenantID string +func (_e *MockLimits_Expecter) MaxQueryLookback(tenantID interface{}) *MockLimits_MaxQueryLookback_Call { + return &MockLimits_MaxQueryLookback_Call{Call: _e.mock.On("MaxQueryLookback", tenantID)} +} + +func (_c *MockLimits_MaxQueryLookback_Call) Run(run func(tenantID string)) *MockLimits_MaxQueryLookback_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_MaxQueryLookback_Call) Return(_a0 time.Duration) *MockLimits_MaxQueryLookback_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_MaxQueryLookback_Call) RunAndReturn(run func(string) time.Duration) *MockLimits_MaxQueryLookback_Call { + _c.Call.Return(run) + return _c +} + +// MaxQueryParallelism provides a mock function with given fields: _a0 +func (_m *MockLimits) MaxQueryParallelism(_a0 string) int { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for MaxQueryParallelism") + } + + var r0 int + if rf, ok := ret.Get(0).(func(string) int); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// MockLimits_MaxQueryParallelism_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxQueryParallelism' +type MockLimits_MaxQueryParallelism_Call struct { + *mock.Call +} + +// MaxQueryParallelism is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) MaxQueryParallelism(_a0 interface{}) *MockLimits_MaxQueryParallelism_Call { + return &MockLimits_MaxQueryParallelism_Call{Call: _e.mock.On("MaxQueryParallelism", _a0)} +} + +func (_c *MockLimits_MaxQueryParallelism_Call) Run(run func(_a0 string)) *MockLimits_MaxQueryParallelism_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_MaxQueryParallelism_Call) Return(_a0 int) *MockLimits_MaxQueryParallelism_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_MaxQueryParallelism_Call) RunAndReturn(run func(string) int) *MockLimits_MaxQueryParallelism_Call { + _c.Call.Return(run) + return _c +} + +// QueryAnalysisEnabled provides a mock function with given fields: _a0 +func (_m *MockLimits) QueryAnalysisEnabled(_a0 string) bool { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for QueryAnalysisEnabled") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockLimits_QueryAnalysisEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QueryAnalysisEnabled' +type MockLimits_QueryAnalysisEnabled_Call struct { + *mock.Call +} + +// QueryAnalysisEnabled is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) QueryAnalysisEnabled(_a0 interface{}) *MockLimits_QueryAnalysisEnabled_Call { + return &MockLimits_QueryAnalysisEnabled_Call{Call: _e.mock.On("QueryAnalysisEnabled", _a0)} +} + +func (_c *MockLimits_QueryAnalysisEnabled_Call) Run(run func(_a0 string)) *MockLimits_QueryAnalysisEnabled_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_QueryAnalysisEnabled_Call) Return(_a0 bool) *MockLimits_QueryAnalysisEnabled_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_QueryAnalysisEnabled_Call) RunAndReturn(run func(string) bool) *MockLimits_QueryAnalysisEnabled_Call { + _c.Call.Return(run) + return _c +} + +// QuerySanitizeOnMerge provides a mock function with given fields: _a0 +func (_m *MockLimits) QuerySanitizeOnMerge(_a0 string) bool { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for QuerySanitizeOnMerge") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockLimits_QuerySanitizeOnMerge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QuerySanitizeOnMerge' +type MockLimits_QuerySanitizeOnMerge_Call struct { + *mock.Call +} + +// QuerySanitizeOnMerge is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) QuerySanitizeOnMerge(_a0 interface{}) *MockLimits_QuerySanitizeOnMerge_Call { + return &MockLimits_QuerySanitizeOnMerge_Call{Call: _e.mock.On("QuerySanitizeOnMerge", _a0)} +} + +func (_c *MockLimits_QuerySanitizeOnMerge_Call) Run(run func(_a0 string)) *MockLimits_QuerySanitizeOnMerge_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_QuerySanitizeOnMerge_Call) Return(_a0 bool) *MockLimits_QuerySanitizeOnMerge_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_QuerySanitizeOnMerge_Call) RunAndReturn(run func(string) bool) *MockLimits_QuerySanitizeOnMerge_Call { + _c.Call.Return(run) + return _c +} + +// QuerySplitDuration provides a mock function with given fields: _a0 +func (_m *MockLimits) QuerySplitDuration(_a0 string) time.Duration { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for QuerySplitDuration") + } + + var r0 time.Duration + if rf, ok := ret.Get(0).(func(string) time.Duration); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(time.Duration) + } + + return r0 +} + +// MockLimits_QuerySplitDuration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QuerySplitDuration' +type MockLimits_QuerySplitDuration_Call struct { + *mock.Call +} + +// QuerySplitDuration is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) QuerySplitDuration(_a0 interface{}) *MockLimits_QuerySplitDuration_Call { + return &MockLimits_QuerySplitDuration_Call{Call: _e.mock.On("QuerySplitDuration", _a0)} +} + +func (_c *MockLimits_QuerySplitDuration_Call) Run(run func(_a0 string)) *MockLimits_QuerySplitDuration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_QuerySplitDuration_Call) Return(_a0 time.Duration) *MockLimits_QuerySplitDuration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_QuerySplitDuration_Call) RunAndReturn(run func(string) time.Duration) *MockLimits_QuerySplitDuration_Call { + _c.Call.Return(run) + return _c +} + +// QueryTreeEnabled provides a mock function with given fields: _a0 +func (_m *MockLimits) QueryTreeEnabled(_a0 string) bool { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for QueryTreeEnabled") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockLimits_QueryTreeEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QueryTreeEnabled' +type MockLimits_QueryTreeEnabled_Call struct { + *mock.Call +} + +// QueryTreeEnabled is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) QueryTreeEnabled(_a0 interface{}) *MockLimits_QueryTreeEnabled_Call { + return &MockLimits_QueryTreeEnabled_Call{Call: _e.mock.On("QueryTreeEnabled", _a0)} +} + +func (_c *MockLimits_QueryTreeEnabled_Call) Run(run func(_a0 string)) *MockLimits_QueryTreeEnabled_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_QueryTreeEnabled_Call) Return(_a0 bool) *MockLimits_QueryTreeEnabled_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_QueryTreeEnabled_Call) RunAndReturn(run func(string) bool) *MockLimits_QueryTreeEnabled_Call { + _c.Call.Return(run) + return _c +} + +// SymbolizerEnabled provides a mock function with given fields: _a0 +func (_m *MockLimits) SymbolizerEnabled(_a0 string) bool { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for SymbolizerEnabled") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockLimits_SymbolizerEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SymbolizerEnabled' +type MockLimits_SymbolizerEnabled_Call struct { + *mock.Call +} + +// SymbolizerEnabled is a helper method to define mock.On call +// - _a0 string +func (_e *MockLimits_Expecter) SymbolizerEnabled(_a0 interface{}) *MockLimits_SymbolizerEnabled_Call { + return &MockLimits_SymbolizerEnabled_Call{Call: _e.mock.On("SymbolizerEnabled", _a0)} +} + +func (_c *MockLimits_SymbolizerEnabled_Call) Run(run func(_a0 string)) *MockLimits_SymbolizerEnabled_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockLimits_SymbolizerEnabled_Call) Return(_a0 bool) *MockLimits_SymbolizerEnabled_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockLimits_SymbolizerEnabled_Call) RunAndReturn(run func(string) bool) *MockLimits_SymbolizerEnabled_Call { + _c.Call.Return(run) + return _c +} + +// NewMockLimits creates a new instance of MockLimits. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockLimits(t interface { + mock.TestingT + Cleanup(func()) +}) *MockLimits { + mock := &MockLimits{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockindex/mock_store.go b/pkg/test/mocks/mockindex/mock_store.go new file mode 100644 index 0000000000..fd421374ae --- /dev/null +++ b/pkg/test/mocks/mockindex/mock_store.go @@ -0,0 +1,302 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockindex + +import ( + bbolt "go.etcd.io/bbolt" + + iter "iter" + + store "github.com/grafana/pyroscope/v2/pkg/metastore/index/store" + mock "github.com/stretchr/testify/mock" +) + +// MockStore is an autogenerated mock type for the Store type +type MockStore struct { + mock.Mock +} + +type MockStore_Expecter struct { + mock *mock.Mock +} + +func (_m *MockStore) EXPECT() *MockStore_Expecter { + return &MockStore_Expecter{mock: &_m.Mock} +} + +// CreateBuckets provides a mock function with given fields: _a0 +func (_m *MockStore) CreateBuckets(_a0 *bbolt.Tx) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for CreateBuckets") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStore_CreateBuckets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateBuckets' +type MockStore_CreateBuckets_Call struct { + *mock.Call +} + +// CreateBuckets is a helper method to define mock.On call +// - _a0 *bbolt.Tx +func (_e *MockStore_Expecter) CreateBuckets(_a0 interface{}) *MockStore_CreateBuckets_Call { + return &MockStore_CreateBuckets_Call{Call: _e.mock.On("CreateBuckets", _a0)} +} + +func (_c *MockStore_CreateBuckets_Call) Run(run func(_a0 *bbolt.Tx)) *MockStore_CreateBuckets_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx)) + }) + return _c +} + +func (_c *MockStore_CreateBuckets_Call) Return(_a0 error) *MockStore_CreateBuckets_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_CreateBuckets_Call) RunAndReturn(run func(*bbolt.Tx) error) *MockStore_CreateBuckets_Call { + _c.Call.Return(run) + return _c +} + +// DeleteShard provides a mock function with given fields: tx, p, tenant, shard +func (_m *MockStore) DeleteShard(tx *bbolt.Tx, p store.Partition, tenant string, shard uint32) error { + ret := _m.Called(tx, p, tenant, shard) + + if len(ret) == 0 { + panic("no return value specified for DeleteShard") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, store.Partition, string, uint32) error); ok { + r0 = rf(tx, p, tenant, shard) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStore_DeleteShard_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteShard' +type MockStore_DeleteShard_Call struct { + *mock.Call +} + +// DeleteShard is a helper method to define mock.On call +// - tx *bbolt.Tx +// - p store.Partition +// - tenant string +// - shard uint32 +func (_e *MockStore_Expecter) DeleteShard(tx interface{}, p interface{}, tenant interface{}, shard interface{}) *MockStore_DeleteShard_Call { + return &MockStore_DeleteShard_Call{Call: _e.mock.On("DeleteShard", tx, p, tenant, shard)} +} + +func (_c *MockStore_DeleteShard_Call) Run(run func(tx *bbolt.Tx, p store.Partition, tenant string, shard uint32)) *MockStore_DeleteShard_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(store.Partition), args[2].(string), args[3].(uint32)) + }) + return _c +} + +func (_c *MockStore_DeleteShard_Call) Return(_a0 error) *MockStore_DeleteShard_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_DeleteShard_Call) RunAndReturn(run func(*bbolt.Tx, store.Partition, string, uint32) error) *MockStore_DeleteShard_Call { + _c.Call.Return(run) + return _c +} + +// LoadShard provides a mock function with given fields: tx, p, tenant, shard +func (_m *MockStore) LoadShard(tx *bbolt.Tx, p store.Partition, tenant string, shard uint32) (*store.Shard, error) { + ret := _m.Called(tx, p, tenant, shard) + + if len(ret) == 0 { + panic("no return value specified for LoadShard") + } + + var r0 *store.Shard + var r1 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, store.Partition, string, uint32) (*store.Shard, error)); ok { + return rf(tx, p, tenant, shard) + } + if rf, ok := ret.Get(0).(func(*bbolt.Tx, store.Partition, string, uint32) *store.Shard); ok { + r0 = rf(tx, p, tenant, shard) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.Shard) + } + } + + if rf, ok := ret.Get(1).(func(*bbolt.Tx, store.Partition, string, uint32) error); ok { + r1 = rf(tx, p, tenant, shard) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStore_LoadShard_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoadShard' +type MockStore_LoadShard_Call struct { + *mock.Call +} + +// LoadShard is a helper method to define mock.On call +// - tx *bbolt.Tx +// - p store.Partition +// - tenant string +// - shard uint32 +func (_e *MockStore_Expecter) LoadShard(tx interface{}, p interface{}, tenant interface{}, shard interface{}) *MockStore_LoadShard_Call { + return &MockStore_LoadShard_Call{Call: _e.mock.On("LoadShard", tx, p, tenant, shard)} +} + +func (_c *MockStore_LoadShard_Call) Run(run func(tx *bbolt.Tx, p store.Partition, tenant string, shard uint32)) *MockStore_LoadShard_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(store.Partition), args[2].(string), args[3].(uint32)) + }) + return _c +} + +func (_c *MockStore_LoadShard_Call) Return(_a0 *store.Shard, _a1 error) *MockStore_LoadShard_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStore_LoadShard_Call) RunAndReturn(run func(*bbolt.Tx, store.Partition, string, uint32) (*store.Shard, error)) *MockStore_LoadShard_Call { + _c.Call.Return(run) + return _c +} + +// LoadShardVersion provides a mock function with given fields: tx, p, tenant, shard +func (_m *MockStore) LoadShardVersion(tx *bbolt.Tx, p store.Partition, tenant string, shard uint32) (uint64, error) { + ret := _m.Called(tx, p, tenant, shard) + + if len(ret) == 0 { + panic("no return value specified for LoadShardVersion") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, store.Partition, string, uint32) (uint64, error)); ok { + return rf(tx, p, tenant, shard) + } + if rf, ok := ret.Get(0).(func(*bbolt.Tx, store.Partition, string, uint32) uint64); ok { + r0 = rf(tx, p, tenant, shard) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(*bbolt.Tx, store.Partition, string, uint32) error); ok { + r1 = rf(tx, p, tenant, shard) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStore_LoadShardVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoadShardVersion' +type MockStore_LoadShardVersion_Call struct { + *mock.Call +} + +// LoadShardVersion is a helper method to define mock.On call +// - tx *bbolt.Tx +// - p store.Partition +// - tenant string +// - shard uint32 +func (_e *MockStore_Expecter) LoadShardVersion(tx interface{}, p interface{}, tenant interface{}, shard interface{}) *MockStore_LoadShardVersion_Call { + return &MockStore_LoadShardVersion_Call{Call: _e.mock.On("LoadShardVersion", tx, p, tenant, shard)} +} + +func (_c *MockStore_LoadShardVersion_Call) Run(run func(tx *bbolt.Tx, p store.Partition, tenant string, shard uint32)) *MockStore_LoadShardVersion_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(store.Partition), args[2].(string), args[3].(uint32)) + }) + return _c +} + +func (_c *MockStore_LoadShardVersion_Call) Return(_a0 uint64, _a1 error) *MockStore_LoadShardVersion_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStore_LoadShardVersion_Call) RunAndReturn(run func(*bbolt.Tx, store.Partition, string, uint32) (uint64, error)) *MockStore_LoadShardVersion_Call { + _c.Call.Return(run) + return _c +} + +// Partitions provides a mock function with given fields: tx +func (_m *MockStore) Partitions(tx *bbolt.Tx) iter.Seq[store.Partition] { + ret := _m.Called(tx) + + if len(ret) == 0 { + panic("no return value specified for Partitions") + } + + var r0 iter.Seq[store.Partition] + if rf, ok := ret.Get(0).(func(*bbolt.Tx) iter.Seq[store.Partition]); ok { + r0 = rf(tx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(iter.Seq[store.Partition]) + } + } + + return r0 +} + +// MockStore_Partitions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Partitions' +type MockStore_Partitions_Call struct { + *mock.Call +} + +// Partitions is a helper method to define mock.On call +// - tx *bbolt.Tx +func (_e *MockStore_Expecter) Partitions(tx interface{}) *MockStore_Partitions_Call { + return &MockStore_Partitions_Call{Call: _e.mock.On("Partitions", tx)} +} + +func (_c *MockStore_Partitions_Call) Run(run func(tx *bbolt.Tx)) *MockStore_Partitions_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx)) + }) + return _c +} + +func (_c *MockStore_Partitions_Call) Return(_a0 iter.Seq[store.Partition]) *MockStore_Partitions_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStore_Partitions_Call) RunAndReturn(run func(*bbolt.Tx) iter.Seq[store.Partition]) *MockStore_Partitions_Call { + _c.Call.Return(run) + return _c +} + +// NewMockStore creates a new instance of MockStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockStore(t interface { + mock.TestingT + Cleanup(func()) +}) *MockStore { + mock := &MockStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_compaction_service_client.go b/pkg/test/mocks/mockmetastorev1/mock_compaction_service_client.go new file mode 100644 index 0000000000..3fdc30dcbe --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_compaction_service_client.go @@ -0,0 +1,112 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" + grpc "google.golang.org/grpc" +) + +// MockCompactionServiceClient is an autogenerated mock type for the CompactionServiceClient type +type MockCompactionServiceClient struct { + mock.Mock +} + +type MockCompactionServiceClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockCompactionServiceClient) EXPECT() *MockCompactionServiceClient_Expecter { + return &MockCompactionServiceClient_Expecter{mock: &_m.Mock} +} + +// PollCompactionJobs provides a mock function with given fields: ctx, in, opts +func (_m *MockCompactionServiceClient) PollCompactionJobs(ctx context.Context, in *metastorev1.PollCompactionJobsRequest, opts ...grpc.CallOption) (*metastorev1.PollCompactionJobsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for PollCompactionJobs") + } + + var r0 *metastorev1.PollCompactionJobsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.PollCompactionJobsRequest, ...grpc.CallOption) (*metastorev1.PollCompactionJobsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.PollCompactionJobsRequest, ...grpc.CallOption) *metastorev1.PollCompactionJobsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.PollCompactionJobsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.PollCompactionJobsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockCompactionServiceClient_PollCompactionJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PollCompactionJobs' +type MockCompactionServiceClient_PollCompactionJobs_Call struct { + *mock.Call +} + +// PollCompactionJobs is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.PollCompactionJobsRequest +// - opts ...grpc.CallOption +func (_e *MockCompactionServiceClient_Expecter) PollCompactionJobs(ctx interface{}, in interface{}, opts ...interface{}) *MockCompactionServiceClient_PollCompactionJobs_Call { + return &MockCompactionServiceClient_PollCompactionJobs_Call{Call: _e.mock.On("PollCompactionJobs", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockCompactionServiceClient_PollCompactionJobs_Call) Run(run func(ctx context.Context, in *metastorev1.PollCompactionJobsRequest, opts ...grpc.CallOption)) *MockCompactionServiceClient_PollCompactionJobs_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.PollCompactionJobsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockCompactionServiceClient_PollCompactionJobs_Call) Return(_a0 *metastorev1.PollCompactionJobsResponse, _a1 error) *MockCompactionServiceClient_PollCompactionJobs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockCompactionServiceClient_PollCompactionJobs_Call) RunAndReturn(run func(context.Context, *metastorev1.PollCompactionJobsRequest, ...grpc.CallOption) (*metastorev1.PollCompactionJobsResponse, error)) *MockCompactionServiceClient_PollCompactionJobs_Call { + _c.Call.Return(run) + return _c +} + +// NewMockCompactionServiceClient creates a new instance of MockCompactionServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockCompactionServiceClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockCompactionServiceClient { + mock := &MockCompactionServiceClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_compaction_service_server.go b/pkg/test/mocks/mockmetastorev1/mock_compaction_service_server.go new file mode 100644 index 0000000000..08c181fb6d --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_compaction_service_server.go @@ -0,0 +1,128 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" +) + +// MockCompactionServiceServer is an autogenerated mock type for the CompactionServiceServer type +type MockCompactionServiceServer struct { + mock.Mock +} + +type MockCompactionServiceServer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockCompactionServiceServer) EXPECT() *MockCompactionServiceServer_Expecter { + return &MockCompactionServiceServer_Expecter{mock: &_m.Mock} +} + +// PollCompactionJobs provides a mock function with given fields: _a0, _a1 +func (_m *MockCompactionServiceServer) PollCompactionJobs(_a0 context.Context, _a1 *metastorev1.PollCompactionJobsRequest) (*metastorev1.PollCompactionJobsResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for PollCompactionJobs") + } + + var r0 *metastorev1.PollCompactionJobsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.PollCompactionJobsRequest) (*metastorev1.PollCompactionJobsResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.PollCompactionJobsRequest) *metastorev1.PollCompactionJobsResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.PollCompactionJobsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.PollCompactionJobsRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockCompactionServiceServer_PollCompactionJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PollCompactionJobs' +type MockCompactionServiceServer_PollCompactionJobs_Call struct { + *mock.Call +} + +// PollCompactionJobs is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.PollCompactionJobsRequest +func (_e *MockCompactionServiceServer_Expecter) PollCompactionJobs(_a0 interface{}, _a1 interface{}) *MockCompactionServiceServer_PollCompactionJobs_Call { + return &MockCompactionServiceServer_PollCompactionJobs_Call{Call: _e.mock.On("PollCompactionJobs", _a0, _a1)} +} + +func (_c *MockCompactionServiceServer_PollCompactionJobs_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.PollCompactionJobsRequest)) *MockCompactionServiceServer_PollCompactionJobs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.PollCompactionJobsRequest)) + }) + return _c +} + +func (_c *MockCompactionServiceServer_PollCompactionJobs_Call) Return(_a0 *metastorev1.PollCompactionJobsResponse, _a1 error) *MockCompactionServiceServer_PollCompactionJobs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockCompactionServiceServer_PollCompactionJobs_Call) RunAndReturn(run func(context.Context, *metastorev1.PollCompactionJobsRequest) (*metastorev1.PollCompactionJobsResponse, error)) *MockCompactionServiceServer_PollCompactionJobs_Call { + _c.Call.Return(run) + return _c +} + +// mustEmbedUnimplementedCompactionServiceServer provides a mock function with no fields +func (_m *MockCompactionServiceServer) mustEmbedUnimplementedCompactionServiceServer() { + _m.Called() +} + +// MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'mustEmbedUnimplementedCompactionServiceServer' +type MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call struct { + *mock.Call +} + +// mustEmbedUnimplementedCompactionServiceServer is a helper method to define mock.On call +func (_e *MockCompactionServiceServer_Expecter) mustEmbedUnimplementedCompactionServiceServer() *MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call { + return &MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call{Call: _e.mock.On("mustEmbedUnimplementedCompactionServiceServer")} +} + +func (_c *MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call) Run(run func()) *MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call) Return() *MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call { + _c.Call.Return() + return _c +} + +func (_c *MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call) RunAndReturn(run func()) *MockCompactionServiceServer_mustEmbedUnimplementedCompactionServiceServer_Call { + _c.Run(run) + return _c +} + +// NewMockCompactionServiceServer creates a new instance of MockCompactionServiceServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockCompactionServiceServer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockCompactionServiceServer { + mock := &MockCompactionServiceServer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_index_service_client.go b/pkg/test/mocks/mockmetastorev1/mock_index_service_client.go new file mode 100644 index 0000000000..706cc52070 --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_index_service_client.go @@ -0,0 +1,186 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" + grpc "google.golang.org/grpc" +) + +// MockIndexServiceClient is an autogenerated mock type for the IndexServiceClient type +type MockIndexServiceClient struct { + mock.Mock +} + +type MockIndexServiceClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockIndexServiceClient) EXPECT() *MockIndexServiceClient_Expecter { + return &MockIndexServiceClient_Expecter{mock: &_m.Mock} +} + +// AddBlock provides a mock function with given fields: ctx, in, opts +func (_m *MockIndexServiceClient) AddBlock(ctx context.Context, in *metastorev1.AddBlockRequest, opts ...grpc.CallOption) (*metastorev1.AddBlockResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddBlock") + } + + var r0 *metastorev1.AddBlockResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.AddBlockRequest, ...grpc.CallOption) (*metastorev1.AddBlockResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.AddBlockRequest, ...grpc.CallOption) *metastorev1.AddBlockResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.AddBlockResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.AddBlockRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockIndexServiceClient_AddBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddBlock' +type MockIndexServiceClient_AddBlock_Call struct { + *mock.Call +} + +// AddBlock is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.AddBlockRequest +// - opts ...grpc.CallOption +func (_e *MockIndexServiceClient_Expecter) AddBlock(ctx interface{}, in interface{}, opts ...interface{}) *MockIndexServiceClient_AddBlock_Call { + return &MockIndexServiceClient_AddBlock_Call{Call: _e.mock.On("AddBlock", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockIndexServiceClient_AddBlock_Call) Run(run func(ctx context.Context, in *metastorev1.AddBlockRequest, opts ...grpc.CallOption)) *MockIndexServiceClient_AddBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.AddBlockRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockIndexServiceClient_AddBlock_Call) Return(_a0 *metastorev1.AddBlockResponse, _a1 error) *MockIndexServiceClient_AddBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockIndexServiceClient_AddBlock_Call) RunAndReturn(run func(context.Context, *metastorev1.AddBlockRequest, ...grpc.CallOption) (*metastorev1.AddBlockResponse, error)) *MockIndexServiceClient_AddBlock_Call { + _c.Call.Return(run) + return _c +} + +// GetBlockMetadata provides a mock function with given fields: ctx, in, opts +func (_m *MockIndexServiceClient) GetBlockMetadata(ctx context.Context, in *metastorev1.GetBlockMetadataRequest, opts ...grpc.CallOption) (*metastorev1.GetBlockMetadataResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetBlockMetadata") + } + + var r0 *metastorev1.GetBlockMetadataResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetBlockMetadataRequest, ...grpc.CallOption) (*metastorev1.GetBlockMetadataResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetBlockMetadataRequest, ...grpc.CallOption) *metastorev1.GetBlockMetadataResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.GetBlockMetadataResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.GetBlockMetadataRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockIndexServiceClient_GetBlockMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlockMetadata' +type MockIndexServiceClient_GetBlockMetadata_Call struct { + *mock.Call +} + +// GetBlockMetadata is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.GetBlockMetadataRequest +// - opts ...grpc.CallOption +func (_e *MockIndexServiceClient_Expecter) GetBlockMetadata(ctx interface{}, in interface{}, opts ...interface{}) *MockIndexServiceClient_GetBlockMetadata_Call { + return &MockIndexServiceClient_GetBlockMetadata_Call{Call: _e.mock.On("GetBlockMetadata", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockIndexServiceClient_GetBlockMetadata_Call) Run(run func(ctx context.Context, in *metastorev1.GetBlockMetadataRequest, opts ...grpc.CallOption)) *MockIndexServiceClient_GetBlockMetadata_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.GetBlockMetadataRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockIndexServiceClient_GetBlockMetadata_Call) Return(_a0 *metastorev1.GetBlockMetadataResponse, _a1 error) *MockIndexServiceClient_GetBlockMetadata_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockIndexServiceClient_GetBlockMetadata_Call) RunAndReturn(run func(context.Context, *metastorev1.GetBlockMetadataRequest, ...grpc.CallOption) (*metastorev1.GetBlockMetadataResponse, error)) *MockIndexServiceClient_GetBlockMetadata_Call { + _c.Call.Return(run) + return _c +} + +// NewMockIndexServiceClient creates a new instance of MockIndexServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockIndexServiceClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockIndexServiceClient { + mock := &MockIndexServiceClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_index_service_server.go b/pkg/test/mocks/mockmetastorev1/mock_index_service_server.go new file mode 100644 index 0000000000..c53047e170 --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_index_service_server.go @@ -0,0 +1,187 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" +) + +// MockIndexServiceServer is an autogenerated mock type for the IndexServiceServer type +type MockIndexServiceServer struct { + mock.Mock +} + +type MockIndexServiceServer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockIndexServiceServer) EXPECT() *MockIndexServiceServer_Expecter { + return &MockIndexServiceServer_Expecter{mock: &_m.Mock} +} + +// AddBlock provides a mock function with given fields: _a0, _a1 +func (_m *MockIndexServiceServer) AddBlock(_a0 context.Context, _a1 *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddBlock") + } + + var r0 *metastorev1.AddBlockResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.AddBlockRequest) *metastorev1.AddBlockResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.AddBlockResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.AddBlockRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockIndexServiceServer_AddBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddBlock' +type MockIndexServiceServer_AddBlock_Call struct { + *mock.Call +} + +// AddBlock is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.AddBlockRequest +func (_e *MockIndexServiceServer_Expecter) AddBlock(_a0 interface{}, _a1 interface{}) *MockIndexServiceServer_AddBlock_Call { + return &MockIndexServiceServer_AddBlock_Call{Call: _e.mock.On("AddBlock", _a0, _a1)} +} + +func (_c *MockIndexServiceServer_AddBlock_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.AddBlockRequest)) *MockIndexServiceServer_AddBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.AddBlockRequest)) + }) + return _c +} + +func (_c *MockIndexServiceServer_AddBlock_Call) Return(_a0 *metastorev1.AddBlockResponse, _a1 error) *MockIndexServiceServer_AddBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockIndexServiceServer_AddBlock_Call) RunAndReturn(run func(context.Context, *metastorev1.AddBlockRequest) (*metastorev1.AddBlockResponse, error)) *MockIndexServiceServer_AddBlock_Call { + _c.Call.Return(run) + return _c +} + +// GetBlockMetadata provides a mock function with given fields: _a0, _a1 +func (_m *MockIndexServiceServer) GetBlockMetadata(_a0 context.Context, _a1 *metastorev1.GetBlockMetadataRequest) (*metastorev1.GetBlockMetadataResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetBlockMetadata") + } + + var r0 *metastorev1.GetBlockMetadataResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetBlockMetadataRequest) (*metastorev1.GetBlockMetadataResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetBlockMetadataRequest) *metastorev1.GetBlockMetadataResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.GetBlockMetadataResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.GetBlockMetadataRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockIndexServiceServer_GetBlockMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlockMetadata' +type MockIndexServiceServer_GetBlockMetadata_Call struct { + *mock.Call +} + +// GetBlockMetadata is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.GetBlockMetadataRequest +func (_e *MockIndexServiceServer_Expecter) GetBlockMetadata(_a0 interface{}, _a1 interface{}) *MockIndexServiceServer_GetBlockMetadata_Call { + return &MockIndexServiceServer_GetBlockMetadata_Call{Call: _e.mock.On("GetBlockMetadata", _a0, _a1)} +} + +func (_c *MockIndexServiceServer_GetBlockMetadata_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.GetBlockMetadataRequest)) *MockIndexServiceServer_GetBlockMetadata_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.GetBlockMetadataRequest)) + }) + return _c +} + +func (_c *MockIndexServiceServer_GetBlockMetadata_Call) Return(_a0 *metastorev1.GetBlockMetadataResponse, _a1 error) *MockIndexServiceServer_GetBlockMetadata_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockIndexServiceServer_GetBlockMetadata_Call) RunAndReturn(run func(context.Context, *metastorev1.GetBlockMetadataRequest) (*metastorev1.GetBlockMetadataResponse, error)) *MockIndexServiceServer_GetBlockMetadata_Call { + _c.Call.Return(run) + return _c +} + +// mustEmbedUnimplementedIndexServiceServer provides a mock function with no fields +func (_m *MockIndexServiceServer) mustEmbedUnimplementedIndexServiceServer() { + _m.Called() +} + +// MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'mustEmbedUnimplementedIndexServiceServer' +type MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call struct { + *mock.Call +} + +// mustEmbedUnimplementedIndexServiceServer is a helper method to define mock.On call +func (_e *MockIndexServiceServer_Expecter) mustEmbedUnimplementedIndexServiceServer() *MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call { + return &MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call{Call: _e.mock.On("mustEmbedUnimplementedIndexServiceServer")} +} + +func (_c *MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call) Run(run func()) *MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call) Return() *MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call { + _c.Call.Return() + return _c +} + +func (_c *MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call) RunAndReturn(run func()) *MockIndexServiceServer_mustEmbedUnimplementedIndexServiceServer_Call { + _c.Run(run) + return _c +} + +// NewMockIndexServiceServer creates a new instance of MockIndexServiceServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockIndexServiceServer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockIndexServiceServer { + mock := &MockIndexServiceServer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_metadata_query_service_client.go b/pkg/test/mocks/mockmetastorev1/mock_metadata_query_service_client.go new file mode 100644 index 0000000000..88af890f75 --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_metadata_query_service_client.go @@ -0,0 +1,186 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" + grpc "google.golang.org/grpc" +) + +// MockMetadataQueryServiceClient is an autogenerated mock type for the MetadataQueryServiceClient type +type MockMetadataQueryServiceClient struct { + mock.Mock +} + +type MockMetadataQueryServiceClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockMetadataQueryServiceClient) EXPECT() *MockMetadataQueryServiceClient_Expecter { + return &MockMetadataQueryServiceClient_Expecter{mock: &_m.Mock} +} + +// QueryMetadata provides a mock function with given fields: ctx, in, opts +func (_m *MockMetadataQueryServiceClient) QueryMetadata(ctx context.Context, in *metastorev1.QueryMetadataRequest, opts ...grpc.CallOption) (*metastorev1.QueryMetadataResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for QueryMetadata") + } + + var r0 *metastorev1.QueryMetadataResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataRequest, ...grpc.CallOption) (*metastorev1.QueryMetadataResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataRequest, ...grpc.CallOption) *metastorev1.QueryMetadataResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.QueryMetadataResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.QueryMetadataRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMetadataQueryServiceClient_QueryMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QueryMetadata' +type MockMetadataQueryServiceClient_QueryMetadata_Call struct { + *mock.Call +} + +// QueryMetadata is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.QueryMetadataRequest +// - opts ...grpc.CallOption +func (_e *MockMetadataQueryServiceClient_Expecter) QueryMetadata(ctx interface{}, in interface{}, opts ...interface{}) *MockMetadataQueryServiceClient_QueryMetadata_Call { + return &MockMetadataQueryServiceClient_QueryMetadata_Call{Call: _e.mock.On("QueryMetadata", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockMetadataQueryServiceClient_QueryMetadata_Call) Run(run func(ctx context.Context, in *metastorev1.QueryMetadataRequest, opts ...grpc.CallOption)) *MockMetadataQueryServiceClient_QueryMetadata_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.QueryMetadataRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockMetadataQueryServiceClient_QueryMetadata_Call) Return(_a0 *metastorev1.QueryMetadataResponse, _a1 error) *MockMetadataQueryServiceClient_QueryMetadata_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMetadataQueryServiceClient_QueryMetadata_Call) RunAndReturn(run func(context.Context, *metastorev1.QueryMetadataRequest, ...grpc.CallOption) (*metastorev1.QueryMetadataResponse, error)) *MockMetadataQueryServiceClient_QueryMetadata_Call { + _c.Call.Return(run) + return _c +} + +// QueryMetadataLabels provides a mock function with given fields: ctx, in, opts +func (_m *MockMetadataQueryServiceClient) QueryMetadataLabels(ctx context.Context, in *metastorev1.QueryMetadataLabelsRequest, opts ...grpc.CallOption) (*metastorev1.QueryMetadataLabelsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for QueryMetadataLabels") + } + + var r0 *metastorev1.QueryMetadataLabelsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataLabelsRequest, ...grpc.CallOption) (*metastorev1.QueryMetadataLabelsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataLabelsRequest, ...grpc.CallOption) *metastorev1.QueryMetadataLabelsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.QueryMetadataLabelsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.QueryMetadataLabelsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMetadataQueryServiceClient_QueryMetadataLabels_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QueryMetadataLabels' +type MockMetadataQueryServiceClient_QueryMetadataLabels_Call struct { + *mock.Call +} + +// QueryMetadataLabels is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.QueryMetadataLabelsRequest +// - opts ...grpc.CallOption +func (_e *MockMetadataQueryServiceClient_Expecter) QueryMetadataLabels(ctx interface{}, in interface{}, opts ...interface{}) *MockMetadataQueryServiceClient_QueryMetadataLabels_Call { + return &MockMetadataQueryServiceClient_QueryMetadataLabels_Call{Call: _e.mock.On("QueryMetadataLabels", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockMetadataQueryServiceClient_QueryMetadataLabels_Call) Run(run func(ctx context.Context, in *metastorev1.QueryMetadataLabelsRequest, opts ...grpc.CallOption)) *MockMetadataQueryServiceClient_QueryMetadataLabels_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.QueryMetadataLabelsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockMetadataQueryServiceClient_QueryMetadataLabels_Call) Return(_a0 *metastorev1.QueryMetadataLabelsResponse, _a1 error) *MockMetadataQueryServiceClient_QueryMetadataLabels_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMetadataQueryServiceClient_QueryMetadataLabels_Call) RunAndReturn(run func(context.Context, *metastorev1.QueryMetadataLabelsRequest, ...grpc.CallOption) (*metastorev1.QueryMetadataLabelsResponse, error)) *MockMetadataQueryServiceClient_QueryMetadataLabels_Call { + _c.Call.Return(run) + return _c +} + +// NewMockMetadataQueryServiceClient creates a new instance of MockMetadataQueryServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockMetadataQueryServiceClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockMetadataQueryServiceClient { + mock := &MockMetadataQueryServiceClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_metadata_query_service_server.go b/pkg/test/mocks/mockmetastorev1/mock_metadata_query_service_server.go new file mode 100644 index 0000000000..8651e337c5 --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_metadata_query_service_server.go @@ -0,0 +1,187 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" +) + +// MockMetadataQueryServiceServer is an autogenerated mock type for the MetadataQueryServiceServer type +type MockMetadataQueryServiceServer struct { + mock.Mock +} + +type MockMetadataQueryServiceServer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockMetadataQueryServiceServer) EXPECT() *MockMetadataQueryServiceServer_Expecter { + return &MockMetadataQueryServiceServer_Expecter{mock: &_m.Mock} +} + +// QueryMetadata provides a mock function with given fields: _a0, _a1 +func (_m *MockMetadataQueryServiceServer) QueryMetadata(_a0 context.Context, _a1 *metastorev1.QueryMetadataRequest) (*metastorev1.QueryMetadataResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for QueryMetadata") + } + + var r0 *metastorev1.QueryMetadataResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataRequest) (*metastorev1.QueryMetadataResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataRequest) *metastorev1.QueryMetadataResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.QueryMetadataResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.QueryMetadataRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMetadataQueryServiceServer_QueryMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QueryMetadata' +type MockMetadataQueryServiceServer_QueryMetadata_Call struct { + *mock.Call +} + +// QueryMetadata is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.QueryMetadataRequest +func (_e *MockMetadataQueryServiceServer_Expecter) QueryMetadata(_a0 interface{}, _a1 interface{}) *MockMetadataQueryServiceServer_QueryMetadata_Call { + return &MockMetadataQueryServiceServer_QueryMetadata_Call{Call: _e.mock.On("QueryMetadata", _a0, _a1)} +} + +func (_c *MockMetadataQueryServiceServer_QueryMetadata_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.QueryMetadataRequest)) *MockMetadataQueryServiceServer_QueryMetadata_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.QueryMetadataRequest)) + }) + return _c +} + +func (_c *MockMetadataQueryServiceServer_QueryMetadata_Call) Return(_a0 *metastorev1.QueryMetadataResponse, _a1 error) *MockMetadataQueryServiceServer_QueryMetadata_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMetadataQueryServiceServer_QueryMetadata_Call) RunAndReturn(run func(context.Context, *metastorev1.QueryMetadataRequest) (*metastorev1.QueryMetadataResponse, error)) *MockMetadataQueryServiceServer_QueryMetadata_Call { + _c.Call.Return(run) + return _c +} + +// QueryMetadataLabels provides a mock function with given fields: _a0, _a1 +func (_m *MockMetadataQueryServiceServer) QueryMetadataLabels(_a0 context.Context, _a1 *metastorev1.QueryMetadataLabelsRequest) (*metastorev1.QueryMetadataLabelsResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for QueryMetadataLabels") + } + + var r0 *metastorev1.QueryMetadataLabelsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataLabelsRequest) (*metastorev1.QueryMetadataLabelsResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.QueryMetadataLabelsRequest) *metastorev1.QueryMetadataLabelsResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.QueryMetadataLabelsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.QueryMetadataLabelsRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMetadataQueryServiceServer_QueryMetadataLabels_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QueryMetadataLabels' +type MockMetadataQueryServiceServer_QueryMetadataLabels_Call struct { + *mock.Call +} + +// QueryMetadataLabels is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.QueryMetadataLabelsRequest +func (_e *MockMetadataQueryServiceServer_Expecter) QueryMetadataLabels(_a0 interface{}, _a1 interface{}) *MockMetadataQueryServiceServer_QueryMetadataLabels_Call { + return &MockMetadataQueryServiceServer_QueryMetadataLabels_Call{Call: _e.mock.On("QueryMetadataLabels", _a0, _a1)} +} + +func (_c *MockMetadataQueryServiceServer_QueryMetadataLabels_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.QueryMetadataLabelsRequest)) *MockMetadataQueryServiceServer_QueryMetadataLabels_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.QueryMetadataLabelsRequest)) + }) + return _c +} + +func (_c *MockMetadataQueryServiceServer_QueryMetadataLabels_Call) Return(_a0 *metastorev1.QueryMetadataLabelsResponse, _a1 error) *MockMetadataQueryServiceServer_QueryMetadataLabels_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMetadataQueryServiceServer_QueryMetadataLabels_Call) RunAndReturn(run func(context.Context, *metastorev1.QueryMetadataLabelsRequest) (*metastorev1.QueryMetadataLabelsResponse, error)) *MockMetadataQueryServiceServer_QueryMetadataLabels_Call { + _c.Call.Return(run) + return _c +} + +// mustEmbedUnimplementedMetadataQueryServiceServer provides a mock function with no fields +func (_m *MockMetadataQueryServiceServer) mustEmbedUnimplementedMetadataQueryServiceServer() { + _m.Called() +} + +// MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'mustEmbedUnimplementedMetadataQueryServiceServer' +type MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call struct { + *mock.Call +} + +// mustEmbedUnimplementedMetadataQueryServiceServer is a helper method to define mock.On call +func (_e *MockMetadataQueryServiceServer_Expecter) mustEmbedUnimplementedMetadataQueryServiceServer() *MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call { + return &MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call{Call: _e.mock.On("mustEmbedUnimplementedMetadataQueryServiceServer")} +} + +func (_c *MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call) Run(run func()) *MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call) Return() *MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call { + _c.Call.Return() + return _c +} + +func (_c *MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call) RunAndReturn(run func()) *MockMetadataQueryServiceServer_mustEmbedUnimplementedMetadataQueryServiceServer_Call { + _c.Run(run) + return _c +} + +// NewMockMetadataQueryServiceServer creates a new instance of MockMetadataQueryServiceServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockMetadataQueryServiceServer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockMetadataQueryServiceServer { + mock := &MockMetadataQueryServiceServer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_tenant_service_client.go b/pkg/test/mocks/mockmetastorev1/mock_tenant_service_client.go new file mode 100644 index 0000000000..7d69ce47cc --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_tenant_service_client.go @@ -0,0 +1,260 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" + grpc "google.golang.org/grpc" +) + +// MockTenantServiceClient is an autogenerated mock type for the TenantServiceClient type +type MockTenantServiceClient struct { + mock.Mock +} + +type MockTenantServiceClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockTenantServiceClient) EXPECT() *MockTenantServiceClient_Expecter { + return &MockTenantServiceClient_Expecter{mock: &_m.Mock} +} + +// DeleteTenant provides a mock function with given fields: ctx, in, opts +func (_m *MockTenantServiceClient) DeleteTenant(ctx context.Context, in *metastorev1.DeleteTenantRequest, opts ...grpc.CallOption) (*metastorev1.DeleteTenantResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DeleteTenant") + } + + var r0 *metastorev1.DeleteTenantResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.DeleteTenantRequest, ...grpc.CallOption) (*metastorev1.DeleteTenantResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.DeleteTenantRequest, ...grpc.CallOption) *metastorev1.DeleteTenantResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.DeleteTenantResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.DeleteTenantRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockTenantServiceClient_DeleteTenant_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteTenant' +type MockTenantServiceClient_DeleteTenant_Call struct { + *mock.Call +} + +// DeleteTenant is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.DeleteTenantRequest +// - opts ...grpc.CallOption +func (_e *MockTenantServiceClient_Expecter) DeleteTenant(ctx interface{}, in interface{}, opts ...interface{}) *MockTenantServiceClient_DeleteTenant_Call { + return &MockTenantServiceClient_DeleteTenant_Call{Call: _e.mock.On("DeleteTenant", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockTenantServiceClient_DeleteTenant_Call) Run(run func(ctx context.Context, in *metastorev1.DeleteTenantRequest, opts ...grpc.CallOption)) *MockTenantServiceClient_DeleteTenant_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.DeleteTenantRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockTenantServiceClient_DeleteTenant_Call) Return(_a0 *metastorev1.DeleteTenantResponse, _a1 error) *MockTenantServiceClient_DeleteTenant_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockTenantServiceClient_DeleteTenant_Call) RunAndReturn(run func(context.Context, *metastorev1.DeleteTenantRequest, ...grpc.CallOption) (*metastorev1.DeleteTenantResponse, error)) *MockTenantServiceClient_DeleteTenant_Call { + _c.Call.Return(run) + return _c +} + +// GetTenant provides a mock function with given fields: ctx, in, opts +func (_m *MockTenantServiceClient) GetTenant(ctx context.Context, in *metastorev1.GetTenantRequest, opts ...grpc.CallOption) (*metastorev1.GetTenantResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetTenant") + } + + var r0 *metastorev1.GetTenantResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantRequest, ...grpc.CallOption) (*metastorev1.GetTenantResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantRequest, ...grpc.CallOption) *metastorev1.GetTenantResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.GetTenantResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.GetTenantRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockTenantServiceClient_GetTenant_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTenant' +type MockTenantServiceClient_GetTenant_Call struct { + *mock.Call +} + +// GetTenant is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.GetTenantRequest +// - opts ...grpc.CallOption +func (_e *MockTenantServiceClient_Expecter) GetTenant(ctx interface{}, in interface{}, opts ...interface{}) *MockTenantServiceClient_GetTenant_Call { + return &MockTenantServiceClient_GetTenant_Call{Call: _e.mock.On("GetTenant", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockTenantServiceClient_GetTenant_Call) Run(run func(ctx context.Context, in *metastorev1.GetTenantRequest, opts ...grpc.CallOption)) *MockTenantServiceClient_GetTenant_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.GetTenantRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockTenantServiceClient_GetTenant_Call) Return(_a0 *metastorev1.GetTenantResponse, _a1 error) *MockTenantServiceClient_GetTenant_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockTenantServiceClient_GetTenant_Call) RunAndReturn(run func(context.Context, *metastorev1.GetTenantRequest, ...grpc.CallOption) (*metastorev1.GetTenantResponse, error)) *MockTenantServiceClient_GetTenant_Call { + _c.Call.Return(run) + return _c +} + +// GetTenants provides a mock function with given fields: ctx, in, opts +func (_m *MockTenantServiceClient) GetTenants(ctx context.Context, in *metastorev1.GetTenantsRequest, opts ...grpc.CallOption) (*metastorev1.GetTenantsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetTenants") + } + + var r0 *metastorev1.GetTenantsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantsRequest, ...grpc.CallOption) (*metastorev1.GetTenantsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantsRequest, ...grpc.CallOption) *metastorev1.GetTenantsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.GetTenantsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.GetTenantsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockTenantServiceClient_GetTenants_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTenants' +type MockTenantServiceClient_GetTenants_Call struct { + *mock.Call +} + +// GetTenants is a helper method to define mock.On call +// - ctx context.Context +// - in *metastorev1.GetTenantsRequest +// - opts ...grpc.CallOption +func (_e *MockTenantServiceClient_Expecter) GetTenants(ctx interface{}, in interface{}, opts ...interface{}) *MockTenantServiceClient_GetTenants_Call { + return &MockTenantServiceClient_GetTenants_Call{Call: _e.mock.On("GetTenants", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockTenantServiceClient_GetTenants_Call) Run(run func(ctx context.Context, in *metastorev1.GetTenantsRequest, opts ...grpc.CallOption)) *MockTenantServiceClient_GetTenants_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*metastorev1.GetTenantsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockTenantServiceClient_GetTenants_Call) Return(_a0 *metastorev1.GetTenantsResponse, _a1 error) *MockTenantServiceClient_GetTenants_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockTenantServiceClient_GetTenants_Call) RunAndReturn(run func(context.Context, *metastorev1.GetTenantsRequest, ...grpc.CallOption) (*metastorev1.GetTenantsResponse, error)) *MockTenantServiceClient_GetTenants_Call { + _c.Call.Return(run) + return _c +} + +// NewMockTenantServiceClient creates a new instance of MockTenantServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockTenantServiceClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockTenantServiceClient { + mock := &MockTenantServiceClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetastorev1/mock_tenant_service_server.go b/pkg/test/mocks/mockmetastorev1/mock_tenant_service_server.go new file mode 100644 index 0000000000..e1d33d3d62 --- /dev/null +++ b/pkg/test/mocks/mockmetastorev1/mock_tenant_service_server.go @@ -0,0 +1,246 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetastorev1 + +import ( + context "context" + + metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" + mock "github.com/stretchr/testify/mock" +) + +// MockTenantServiceServer is an autogenerated mock type for the TenantServiceServer type +type MockTenantServiceServer struct { + mock.Mock +} + +type MockTenantServiceServer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockTenantServiceServer) EXPECT() *MockTenantServiceServer_Expecter { + return &MockTenantServiceServer_Expecter{mock: &_m.Mock} +} + +// DeleteTenant provides a mock function with given fields: _a0, _a1 +func (_m *MockTenantServiceServer) DeleteTenant(_a0 context.Context, _a1 *metastorev1.DeleteTenantRequest) (*metastorev1.DeleteTenantResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for DeleteTenant") + } + + var r0 *metastorev1.DeleteTenantResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.DeleteTenantRequest) (*metastorev1.DeleteTenantResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.DeleteTenantRequest) *metastorev1.DeleteTenantResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.DeleteTenantResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.DeleteTenantRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockTenantServiceServer_DeleteTenant_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteTenant' +type MockTenantServiceServer_DeleteTenant_Call struct { + *mock.Call +} + +// DeleteTenant is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.DeleteTenantRequest +func (_e *MockTenantServiceServer_Expecter) DeleteTenant(_a0 interface{}, _a1 interface{}) *MockTenantServiceServer_DeleteTenant_Call { + return &MockTenantServiceServer_DeleteTenant_Call{Call: _e.mock.On("DeleteTenant", _a0, _a1)} +} + +func (_c *MockTenantServiceServer_DeleteTenant_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.DeleteTenantRequest)) *MockTenantServiceServer_DeleteTenant_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.DeleteTenantRequest)) + }) + return _c +} + +func (_c *MockTenantServiceServer_DeleteTenant_Call) Return(_a0 *metastorev1.DeleteTenantResponse, _a1 error) *MockTenantServiceServer_DeleteTenant_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockTenantServiceServer_DeleteTenant_Call) RunAndReturn(run func(context.Context, *metastorev1.DeleteTenantRequest) (*metastorev1.DeleteTenantResponse, error)) *MockTenantServiceServer_DeleteTenant_Call { + _c.Call.Return(run) + return _c +} + +// GetTenant provides a mock function with given fields: _a0, _a1 +func (_m *MockTenantServiceServer) GetTenant(_a0 context.Context, _a1 *metastorev1.GetTenantRequest) (*metastorev1.GetTenantResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetTenant") + } + + var r0 *metastorev1.GetTenantResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantRequest) (*metastorev1.GetTenantResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantRequest) *metastorev1.GetTenantResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.GetTenantResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.GetTenantRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockTenantServiceServer_GetTenant_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTenant' +type MockTenantServiceServer_GetTenant_Call struct { + *mock.Call +} + +// GetTenant is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.GetTenantRequest +func (_e *MockTenantServiceServer_Expecter) GetTenant(_a0 interface{}, _a1 interface{}) *MockTenantServiceServer_GetTenant_Call { + return &MockTenantServiceServer_GetTenant_Call{Call: _e.mock.On("GetTenant", _a0, _a1)} +} + +func (_c *MockTenantServiceServer_GetTenant_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.GetTenantRequest)) *MockTenantServiceServer_GetTenant_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.GetTenantRequest)) + }) + return _c +} + +func (_c *MockTenantServiceServer_GetTenant_Call) Return(_a0 *metastorev1.GetTenantResponse, _a1 error) *MockTenantServiceServer_GetTenant_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockTenantServiceServer_GetTenant_Call) RunAndReturn(run func(context.Context, *metastorev1.GetTenantRequest) (*metastorev1.GetTenantResponse, error)) *MockTenantServiceServer_GetTenant_Call { + _c.Call.Return(run) + return _c +} + +// GetTenants provides a mock function with given fields: _a0, _a1 +func (_m *MockTenantServiceServer) GetTenants(_a0 context.Context, _a1 *metastorev1.GetTenantsRequest) (*metastorev1.GetTenantsResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetTenants") + } + + var r0 *metastorev1.GetTenantsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantsRequest) (*metastorev1.GetTenantsResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *metastorev1.GetTenantsRequest) *metastorev1.GetTenantsResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*metastorev1.GetTenantsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *metastorev1.GetTenantsRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockTenantServiceServer_GetTenants_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTenants' +type MockTenantServiceServer_GetTenants_Call struct { + *mock.Call +} + +// GetTenants is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *metastorev1.GetTenantsRequest +func (_e *MockTenantServiceServer_Expecter) GetTenants(_a0 interface{}, _a1 interface{}) *MockTenantServiceServer_GetTenants_Call { + return &MockTenantServiceServer_GetTenants_Call{Call: _e.mock.On("GetTenants", _a0, _a1)} +} + +func (_c *MockTenantServiceServer_GetTenants_Call) Run(run func(_a0 context.Context, _a1 *metastorev1.GetTenantsRequest)) *MockTenantServiceServer_GetTenants_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*metastorev1.GetTenantsRequest)) + }) + return _c +} + +func (_c *MockTenantServiceServer_GetTenants_Call) Return(_a0 *metastorev1.GetTenantsResponse, _a1 error) *MockTenantServiceServer_GetTenants_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockTenantServiceServer_GetTenants_Call) RunAndReturn(run func(context.Context, *metastorev1.GetTenantsRequest) (*metastorev1.GetTenantsResponse, error)) *MockTenantServiceServer_GetTenants_Call { + _c.Call.Return(run) + return _c +} + +// mustEmbedUnimplementedTenantServiceServer provides a mock function with no fields +func (_m *MockTenantServiceServer) mustEmbedUnimplementedTenantServiceServer() { + _m.Called() +} + +// MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'mustEmbedUnimplementedTenantServiceServer' +type MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call struct { + *mock.Call +} + +// mustEmbedUnimplementedTenantServiceServer is a helper method to define mock.On call +func (_e *MockTenantServiceServer_Expecter) mustEmbedUnimplementedTenantServiceServer() *MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call { + return &MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call{Call: _e.mock.On("mustEmbedUnimplementedTenantServiceServer")} +} + +func (_c *MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call) Run(run func()) *MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call) Return() *MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call { + _c.Call.Return() + return _c +} + +func (_c *MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call) RunAndReturn(run func()) *MockTenantServiceServer_mustEmbedUnimplementedTenantServiceServer_Call { + _c.Run(run) + return _c +} + +// NewMockTenantServiceServer creates a new instance of MockTenantServiceServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockTenantServiceServer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockTenantServiceServer { + mock := &MockTenantServiceServer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetrics/mock_exporter.go b/pkg/test/mocks/mockmetrics/mock_exporter.go new file mode 100644 index 0000000000..85db3d0ac1 --- /dev/null +++ b/pkg/test/mocks/mockmetrics/mock_exporter.go @@ -0,0 +1,114 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetrics + +import ( + prompb "github.com/prometheus/prometheus/prompb" + mock "github.com/stretchr/testify/mock" +) + +// MockExporter is an autogenerated mock type for the Exporter type +type MockExporter struct { + mock.Mock +} + +type MockExporter_Expecter struct { + mock *mock.Mock +} + +func (_m *MockExporter) EXPECT() *MockExporter_Expecter { + return &MockExporter_Expecter{mock: &_m.Mock} +} + +// Flush provides a mock function with no fields +func (_m *MockExporter) Flush() { + _m.Called() +} + +// MockExporter_Flush_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Flush' +type MockExporter_Flush_Call struct { + *mock.Call +} + +// Flush is a helper method to define mock.On call +func (_e *MockExporter_Expecter) Flush() *MockExporter_Flush_Call { + return &MockExporter_Flush_Call{Call: _e.mock.On("Flush")} +} + +func (_c *MockExporter_Flush_Call) Run(run func()) *MockExporter_Flush_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockExporter_Flush_Call) Return() *MockExporter_Flush_Call { + _c.Call.Return() + return _c +} + +func (_c *MockExporter_Flush_Call) RunAndReturn(run func()) *MockExporter_Flush_Call { + _c.Run(run) + return _c +} + +// Send provides a mock function with given fields: tenant, series +func (_m *MockExporter) Send(tenant string, series []prompb.TimeSeries) error { + ret := _m.Called(tenant, series) + + if len(ret) == 0 { + panic("no return value specified for Send") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, []prompb.TimeSeries) error); ok { + r0 = rf(tenant, series) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockExporter_Send_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Send' +type MockExporter_Send_Call struct { + *mock.Call +} + +// Send is a helper method to define mock.On call +// - tenant string +// - series []prompb.TimeSeries +func (_e *MockExporter_Expecter) Send(tenant interface{}, series interface{}) *MockExporter_Send_Call { + return &MockExporter_Send_Call{Call: _e.mock.On("Send", tenant, series)} +} + +func (_c *MockExporter_Send_Call) Run(run func(tenant string, series []prompb.TimeSeries)) *MockExporter_Send_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].([]prompb.TimeSeries)) + }) + return _c +} + +func (_c *MockExporter_Send_Call) Return(_a0 error) *MockExporter_Send_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockExporter_Send_Call) RunAndReturn(run func(string, []prompb.TimeSeries) error) *MockExporter_Send_Call { + _c.Call.Return(run) + return _c +} + +// NewMockExporter creates a new instance of MockExporter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockExporter(t interface { + mock.TestingT + Cleanup(func()) +}) *MockExporter { + mock := &MockExporter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockmetrics/mock_ruler.go b/pkg/test/mocks/mockmetrics/mock_ruler.go new file mode 100644 index 0000000000..9ed75a77a3 --- /dev/null +++ b/pkg/test/mocks/mockmetrics/mock_ruler.go @@ -0,0 +1,83 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockmetrics + +import ( + model "github.com/grafana/pyroscope/v2/pkg/model" + mock "github.com/stretchr/testify/mock" +) + +// MockRuler is an autogenerated mock type for the Ruler type +type MockRuler struct { + mock.Mock +} + +type MockRuler_Expecter struct { + mock *mock.Mock +} + +func (_m *MockRuler) EXPECT() *MockRuler_Expecter { + return &MockRuler_Expecter{mock: &_m.Mock} +} + +// RecordingRules provides a mock function with given fields: tenant +func (_m *MockRuler) RecordingRules(tenant string) []*model.RecordingRule { + ret := _m.Called(tenant) + + if len(ret) == 0 { + panic("no return value specified for RecordingRules") + } + + var r0 []*model.RecordingRule + if rf, ok := ret.Get(0).(func(string) []*model.RecordingRule); ok { + r0 = rf(tenant) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*model.RecordingRule) + } + } + + return r0 +} + +// MockRuler_RecordingRules_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RecordingRules' +type MockRuler_RecordingRules_Call struct { + *mock.Call +} + +// RecordingRules is a helper method to define mock.On call +// - tenant string +func (_e *MockRuler_Expecter) RecordingRules(tenant interface{}) *MockRuler_RecordingRules_Call { + return &MockRuler_RecordingRules_Call{Call: _e.mock.On("RecordingRules", tenant)} +} + +func (_c *MockRuler_RecordingRules_Call) Run(run func(tenant string)) *MockRuler_RecordingRules_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockRuler_RecordingRules_Call) Return(_a0 []*model.RecordingRule) *MockRuler_RecordingRules_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockRuler_RecordingRules_Call) RunAndReturn(run func(string) []*model.RecordingRule) *MockRuler_RecordingRules_Call { + _c.Call.Return(run) + return _c +} + +// NewMockRuler creates a new instance of MockRuler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockRuler(t interface { + mock.TestingT + Cleanup(func()) +}) *MockRuler { + mock := &MockRuler{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockobjstore/helper.go b/pkg/test/mocks/mockobjstore/helper.go new file mode 100644 index 0000000000..7c607ecd31 --- /dev/null +++ b/pkg/test/mocks/mockobjstore/helper.go @@ -0,0 +1,86 @@ +package mockobjstore + +import ( + "bytes" + "context" + "errors" + "io" + "testing" + "time" + + "github.com/stretchr/testify/mock" + "github.com/thanos-io/objstore" +) + +// ErrObjectDoesNotExist is used in tests to simulate objstore.Bucket.IsObjNotFoundErr(). +var ErrObjectDoesNotExist = errors.New("object does not exist") + +func NewMockBucketWithHelper(t testing.TB) *MockBucket { + m := &MockBucket{} + m.EXPECT().IsObjNotFoundErr(mock.Anything).RunAndReturn(func(err error) bool { + return errors.Is(err, ErrObjectDoesNotExist) + }) + m.EXPECT().Name().Return("mock") + return m +} + +func (m *MockBucket) MockIter(prefix string, objects []string, err error) { + m.MockIterWithCallback(prefix, objects, err, nil) +} + +// MockIterWithCallback is a convenient method to mock Iter() and get a callback called when the Iter +// API is called. +func (m *MockBucket) MockIterWithCallback(prefix string, objects []string, err error, cb func()) { + // implement IsObjNotFoundErr + m.On("Iter", mock.Anything, prefix, mock.Anything, mock.Anything).Return(err).Run(func(args mock.Arguments) { + if cb != nil { + cb() + } + + f := args.Get(2).(func(string) error) + + for _, o := range objects { + if f(o) != nil { + break + } + } + }) +} + +func (m *MockBucket) MockUpload(name string, err error) { + m.On("Upload", mock.Anything, name, mock.Anything, mock.Anything).Return(err) +} + +func (m *MockBucket) MockAttributes(name string, attrs objstore.ObjectAttributes, err error) { + m.On("Attributes", mock.Anything, name).Return(attrs, err) +} + +func (m *MockBucket) MockDelete(name string, err error) { + m.On("Delete", mock.Anything, name).Return(err) +} + +func (m *MockBucket) MockExists(name string, exists bool, err error) { + m.On("Exists", mock.Anything, name).Return(exists, err) +} + +// MockGet is a convenient method to mock Get() and Exists() +func (m *MockBucket) MockGet(name, content string, err error) { + if content != "" { + m.On("Exists", mock.Anything, name).Return(true, err) + m.On("Attributes", mock.Anything, name).Return(objstore.ObjectAttributes{ + Size: int64(len(content)), + LastModified: time.Now(), + }, nil) + + // Since we return an ReadCloser and it can be consumed only once, + // each time the mocked Get() is called we do create a new one, so + // that getting the same mocked object twice works as expected. + m.On("Get", mock.Anything, name).Return(func(_ context.Context, _ string) (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader([]byte(content))), err + }) + } else { + m.On("Exists", mock.Anything, name).Return(false, err) + m.On("Get", mock.Anything, name).Return(nil, ErrObjectDoesNotExist) + m.On("Attributes", mock.Anything, name).Return(nil, ErrObjectDoesNotExist) + } +} diff --git a/pkg/test/mocks/mockobjstore/helper_test.go b/pkg/test/mocks/mockobjstore/helper_test.go new file mode 100644 index 0000000000..d3c9ccc10c --- /dev/null +++ b/pkg/test/mocks/mockobjstore/helper_test.go @@ -0,0 +1,38 @@ +package mockobjstore + +import ( + "context" + "io" + "sync" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestClientMock_MockGet(t *testing.T) { + expected := "body" + + m := NewMockBucketWithHelper(t) + m.MockGet("test", expected, nil) + + // Run many goroutines all requesting the same mocked object and + // ensure there's no race. + wg := sync.WaitGroup{} + for i := 0; i < 1000; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + reader, err := m.Get(context.Background(), "test") + require.NoError(t, err) + + actual, err := io.ReadAll(reader) + require.NoError(t, err) + require.Equal(t, []byte(expected), actual) + + require.NoError(t, reader.Close()) + }() + } + + wg.Wait() +} diff --git a/pkg/test/mocks/mockobjstore/mock_bucket.go b/pkg/test/mocks/mockobjstore/mock_bucket.go new file mode 100644 index 0000000000..1ba8c49e4a --- /dev/null +++ b/pkg/test/mocks/mockobjstore/mock_bucket.go @@ -0,0 +1,842 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockobjstore + +import ( + context "context" + io "io" + + pkgobjstore "github.com/grafana/pyroscope/v2/pkg/objstore" + mock "github.com/stretchr/testify/mock" + objstore "github.com/thanos-io/objstore" +) + +// MockBucket is an autogenerated mock type for the Bucket type +type MockBucket struct { + mock.Mock +} + +type MockBucket_Expecter struct { + mock *mock.Mock +} + +func (_m *MockBucket) EXPECT() *MockBucket_Expecter { + return &MockBucket_Expecter{mock: &_m.Mock} +} + +// Attributes provides a mock function with given fields: ctx, name +func (_m *MockBucket) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { + ret := _m.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for Attributes") + } + + var r0 objstore.ObjectAttributes + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (objstore.ObjectAttributes, error)); ok { + return rf(ctx, name) + } + if rf, ok := ret.Get(0).(func(context.Context, string) objstore.ObjectAttributes); ok { + r0 = rf(ctx, name) + } else { + r0 = ret.Get(0).(objstore.ObjectAttributes) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBucket_Attributes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Attributes' +type MockBucket_Attributes_Call struct { + *mock.Call +} + +// Attributes is a helper method to define mock.On call +// - ctx context.Context +// - name string +func (_e *MockBucket_Expecter) Attributes(ctx interface{}, name interface{}) *MockBucket_Attributes_Call { + return &MockBucket_Attributes_Call{Call: _e.mock.On("Attributes", ctx, name)} +} + +func (_c *MockBucket_Attributes_Call) Run(run func(ctx context.Context, name string)) *MockBucket_Attributes_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockBucket_Attributes_Call) Return(_a0 objstore.ObjectAttributes, _a1 error) *MockBucket_Attributes_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBucket_Attributes_Call) RunAndReturn(run func(context.Context, string) (objstore.ObjectAttributes, error)) *MockBucket_Attributes_Call { + _c.Call.Return(run) + return _c +} + +// Close provides a mock function with no fields +func (_m *MockBucket) Close() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Close") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBucket_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type MockBucket_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +func (_e *MockBucket_Expecter) Close() *MockBucket_Close_Call { + return &MockBucket_Close_Call{Call: _e.mock.On("Close")} +} + +func (_c *MockBucket_Close_Call) Run(run func()) *MockBucket_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBucket_Close_Call) Return(_a0 error) *MockBucket_Close_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_Close_Call) RunAndReturn(run func() error) *MockBucket_Close_Call { + _c.Call.Return(run) + return _c +} + +// Delete provides a mock function with given fields: ctx, name +func (_m *MockBucket) Delete(ctx context.Context, name string) error { + ret := _m.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBucket_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' +type MockBucket_Delete_Call struct { + *mock.Call +} + +// Delete is a helper method to define mock.On call +// - ctx context.Context +// - name string +func (_e *MockBucket_Expecter) Delete(ctx interface{}, name interface{}) *MockBucket_Delete_Call { + return &MockBucket_Delete_Call{Call: _e.mock.On("Delete", ctx, name)} +} + +func (_c *MockBucket_Delete_Call) Run(run func(ctx context.Context, name string)) *MockBucket_Delete_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockBucket_Delete_Call) Return(_a0 error) *MockBucket_Delete_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_Delete_Call) RunAndReturn(run func(context.Context, string) error) *MockBucket_Delete_Call { + _c.Call.Return(run) + return _c +} + +// Exists provides a mock function with given fields: ctx, name +func (_m *MockBucket) Exists(ctx context.Context, name string) (bool, error) { + ret := _m.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for Exists") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok { + return rf(ctx, name) + } + if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok { + r0 = rf(ctx, name) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBucket_Exists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exists' +type MockBucket_Exists_Call struct { + *mock.Call +} + +// Exists is a helper method to define mock.On call +// - ctx context.Context +// - name string +func (_e *MockBucket_Expecter) Exists(ctx interface{}, name interface{}) *MockBucket_Exists_Call { + return &MockBucket_Exists_Call{Call: _e.mock.On("Exists", ctx, name)} +} + +func (_c *MockBucket_Exists_Call) Run(run func(ctx context.Context, name string)) *MockBucket_Exists_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockBucket_Exists_Call) Return(_a0 bool, _a1 error) *MockBucket_Exists_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBucket_Exists_Call) RunAndReturn(run func(context.Context, string) (bool, error)) *MockBucket_Exists_Call { + _c.Call.Return(run) + return _c +} + +// Get provides a mock function with given fields: ctx, name +func (_m *MockBucket) Get(ctx context.Context, name string) (io.ReadCloser, error) { + ret := _m.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 io.ReadCloser + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (io.ReadCloser, error)); ok { + return rf(ctx, name) + } + if rf, ok := ret.Get(0).(func(context.Context, string) io.ReadCloser); ok { + r0 = rf(ctx, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(io.ReadCloser) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBucket_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type MockBucket_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - ctx context.Context +// - name string +func (_e *MockBucket_Expecter) Get(ctx interface{}, name interface{}) *MockBucket_Get_Call { + return &MockBucket_Get_Call{Call: _e.mock.On("Get", ctx, name)} +} + +func (_c *MockBucket_Get_Call) Run(run func(ctx context.Context, name string)) *MockBucket_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockBucket_Get_Call) Return(_a0 io.ReadCloser, _a1 error) *MockBucket_Get_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBucket_Get_Call) RunAndReturn(run func(context.Context, string) (io.ReadCloser, error)) *MockBucket_Get_Call { + _c.Call.Return(run) + return _c +} + +// GetRange provides a mock function with given fields: ctx, name, off, length +func (_m *MockBucket) GetRange(ctx context.Context, name string, off int64, length int64) (io.ReadCloser, error) { + ret := _m.Called(ctx, name, off, length) + + if len(ret) == 0 { + panic("no return value specified for GetRange") + } + + var r0 io.ReadCloser + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, int64, int64) (io.ReadCloser, error)); ok { + return rf(ctx, name, off, length) + } + if rf, ok := ret.Get(0).(func(context.Context, string, int64, int64) io.ReadCloser); ok { + r0 = rf(ctx, name, off, length) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(io.ReadCloser) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, int64, int64) error); ok { + r1 = rf(ctx, name, off, length) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBucket_GetRange_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRange' +type MockBucket_GetRange_Call struct { + *mock.Call +} + +// GetRange is a helper method to define mock.On call +// - ctx context.Context +// - name string +// - off int64 +// - length int64 +func (_e *MockBucket_Expecter) GetRange(ctx interface{}, name interface{}, off interface{}, length interface{}) *MockBucket_GetRange_Call { + return &MockBucket_GetRange_Call{Call: _e.mock.On("GetRange", ctx, name, off, length)} +} + +func (_c *MockBucket_GetRange_Call) Run(run func(ctx context.Context, name string, off int64, length int64)) *MockBucket_GetRange_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(int64), args[3].(int64)) + }) + return _c +} + +func (_c *MockBucket_GetRange_Call) Return(_a0 io.ReadCloser, _a1 error) *MockBucket_GetRange_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBucket_GetRange_Call) RunAndReturn(run func(context.Context, string, int64, int64) (io.ReadCloser, error)) *MockBucket_GetRange_Call { + _c.Call.Return(run) + return _c +} + +// IsAccessDeniedErr provides a mock function with given fields: err +func (_m *MockBucket) IsAccessDeniedErr(err error) bool { + ret := _m.Called(err) + + if len(ret) == 0 { + panic("no return value specified for IsAccessDeniedErr") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(error) bool); ok { + r0 = rf(err) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockBucket_IsAccessDeniedErr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsAccessDeniedErr' +type MockBucket_IsAccessDeniedErr_Call struct { + *mock.Call +} + +// IsAccessDeniedErr is a helper method to define mock.On call +// - err error +func (_e *MockBucket_Expecter) IsAccessDeniedErr(err interface{}) *MockBucket_IsAccessDeniedErr_Call { + return &MockBucket_IsAccessDeniedErr_Call{Call: _e.mock.On("IsAccessDeniedErr", err)} +} + +func (_c *MockBucket_IsAccessDeniedErr_Call) Run(run func(err error)) *MockBucket_IsAccessDeniedErr_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(error)) + }) + return _c +} + +func (_c *MockBucket_IsAccessDeniedErr_Call) Return(_a0 bool) *MockBucket_IsAccessDeniedErr_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_IsAccessDeniedErr_Call) RunAndReturn(run func(error) bool) *MockBucket_IsAccessDeniedErr_Call { + _c.Call.Return(run) + return _c +} + +// IsObjNotFoundErr provides a mock function with given fields: err +func (_m *MockBucket) IsObjNotFoundErr(err error) bool { + ret := _m.Called(err) + + if len(ret) == 0 { + panic("no return value specified for IsObjNotFoundErr") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(error) bool); ok { + r0 = rf(err) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MockBucket_IsObjNotFoundErr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsObjNotFoundErr' +type MockBucket_IsObjNotFoundErr_Call struct { + *mock.Call +} + +// IsObjNotFoundErr is a helper method to define mock.On call +// - err error +func (_e *MockBucket_Expecter) IsObjNotFoundErr(err interface{}) *MockBucket_IsObjNotFoundErr_Call { + return &MockBucket_IsObjNotFoundErr_Call{Call: _e.mock.On("IsObjNotFoundErr", err)} +} + +func (_c *MockBucket_IsObjNotFoundErr_Call) Run(run func(err error)) *MockBucket_IsObjNotFoundErr_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(error)) + }) + return _c +} + +func (_c *MockBucket_IsObjNotFoundErr_Call) Return(_a0 bool) *MockBucket_IsObjNotFoundErr_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_IsObjNotFoundErr_Call) RunAndReturn(run func(error) bool) *MockBucket_IsObjNotFoundErr_Call { + _c.Call.Return(run) + return _c +} + +// Iter provides a mock function with given fields: ctx, dir, f, options +func (_m *MockBucket) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, dir, f) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Iter") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, func(string) error, ...objstore.IterOption) error); ok { + r0 = rf(ctx, dir, f, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBucket_Iter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Iter' +type MockBucket_Iter_Call struct { + *mock.Call +} + +// Iter is a helper method to define mock.On call +// - ctx context.Context +// - dir string +// - f func(string) error +// - options ...objstore.IterOption +func (_e *MockBucket_Expecter) Iter(ctx interface{}, dir interface{}, f interface{}, options ...interface{}) *MockBucket_Iter_Call { + return &MockBucket_Iter_Call{Call: _e.mock.On("Iter", + append([]interface{}{ctx, dir, f}, options...)...)} +} + +func (_c *MockBucket_Iter_Call) Run(run func(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption)) *MockBucket_Iter_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]objstore.IterOption, len(args)-3) + for i, a := range args[3:] { + if a != nil { + variadicArgs[i] = a.(objstore.IterOption) + } + } + run(args[0].(context.Context), args[1].(string), args[2].(func(string) error), variadicArgs...) + }) + return _c +} + +func (_c *MockBucket_Iter_Call) Return(_a0 error) *MockBucket_Iter_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_Iter_Call) RunAndReturn(run func(context.Context, string, func(string) error, ...objstore.IterOption) error) *MockBucket_Iter_Call { + _c.Call.Return(run) + return _c +} + +// IterWithAttributes provides a mock function with given fields: ctx, dir, f, options +func (_m *MockBucket) IterWithAttributes(ctx context.Context, dir string, f func(objstore.IterObjectAttributes) error, options ...objstore.IterOption) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, dir, f) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for IterWithAttributes") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, func(objstore.IterObjectAttributes) error, ...objstore.IterOption) error); ok { + r0 = rf(ctx, dir, f, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBucket_IterWithAttributes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IterWithAttributes' +type MockBucket_IterWithAttributes_Call struct { + *mock.Call +} + +// IterWithAttributes is a helper method to define mock.On call +// - ctx context.Context +// - dir string +// - f func(objstore.IterObjectAttributes) error +// - options ...objstore.IterOption +func (_e *MockBucket_Expecter) IterWithAttributes(ctx interface{}, dir interface{}, f interface{}, options ...interface{}) *MockBucket_IterWithAttributes_Call { + return &MockBucket_IterWithAttributes_Call{Call: _e.mock.On("IterWithAttributes", + append([]interface{}{ctx, dir, f}, options...)...)} +} + +func (_c *MockBucket_IterWithAttributes_Call) Run(run func(ctx context.Context, dir string, f func(objstore.IterObjectAttributes) error, options ...objstore.IterOption)) *MockBucket_IterWithAttributes_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]objstore.IterOption, len(args)-3) + for i, a := range args[3:] { + if a != nil { + variadicArgs[i] = a.(objstore.IterOption) + } + } + run(args[0].(context.Context), args[1].(string), args[2].(func(objstore.IterObjectAttributes) error), variadicArgs...) + }) + return _c +} + +func (_c *MockBucket_IterWithAttributes_Call) Return(_a0 error) *MockBucket_IterWithAttributes_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_IterWithAttributes_Call) RunAndReturn(run func(context.Context, string, func(objstore.IterObjectAttributes) error, ...objstore.IterOption) error) *MockBucket_IterWithAttributes_Call { + _c.Call.Return(run) + return _c +} + +// Name provides a mock function with no fields +func (_m *MockBucket) Name() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Name") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// MockBucket_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' +type MockBucket_Name_Call struct { + *mock.Call +} + +// Name is a helper method to define mock.On call +func (_e *MockBucket_Expecter) Name() *MockBucket_Name_Call { + return &MockBucket_Name_Call{Call: _e.mock.On("Name")} +} + +func (_c *MockBucket_Name_Call) Run(run func()) *MockBucket_Name_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBucket_Name_Call) Return(_a0 string) *MockBucket_Name_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_Name_Call) RunAndReturn(run func() string) *MockBucket_Name_Call { + _c.Call.Return(run) + return _c +} + +// Provider provides a mock function with no fields +func (_m *MockBucket) Provider() objstore.ObjProvider { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Provider") + } + + var r0 objstore.ObjProvider + if rf, ok := ret.Get(0).(func() objstore.ObjProvider); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(objstore.ObjProvider) + } + + return r0 +} + +// MockBucket_Provider_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Provider' +type MockBucket_Provider_Call struct { + *mock.Call +} + +// Provider is a helper method to define mock.On call +func (_e *MockBucket_Expecter) Provider() *MockBucket_Provider_Call { + return &MockBucket_Provider_Call{Call: _e.mock.On("Provider")} +} + +func (_c *MockBucket_Provider_Call) Run(run func()) *MockBucket_Provider_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBucket_Provider_Call) Return(_a0 objstore.ObjProvider) *MockBucket_Provider_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_Provider_Call) RunAndReturn(run func() objstore.ObjProvider) *MockBucket_Provider_Call { + _c.Call.Return(run) + return _c +} + +// ReaderAt provides a mock function with given fields: ctx, filename +func (_m *MockBucket) ReaderAt(ctx context.Context, filename string) (pkgobjstore.ReaderAtCloser, error) { + ret := _m.Called(ctx, filename) + + if len(ret) == 0 { + panic("no return value specified for ReaderAt") + } + + var r0 pkgobjstore.ReaderAtCloser + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (pkgobjstore.ReaderAtCloser, error)); ok { + return rf(ctx, filename) + } + if rf, ok := ret.Get(0).(func(context.Context, string) pkgobjstore.ReaderAtCloser); ok { + r0 = rf(ctx, filename) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(pkgobjstore.ReaderAtCloser) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, filename) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBucket_ReaderAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReaderAt' +type MockBucket_ReaderAt_Call struct { + *mock.Call +} + +// ReaderAt is a helper method to define mock.On call +// - ctx context.Context +// - filename string +func (_e *MockBucket_Expecter) ReaderAt(ctx interface{}, filename interface{}) *MockBucket_ReaderAt_Call { + return &MockBucket_ReaderAt_Call{Call: _e.mock.On("ReaderAt", ctx, filename)} +} + +func (_c *MockBucket_ReaderAt_Call) Run(run func(ctx context.Context, filename string)) *MockBucket_ReaderAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockBucket_ReaderAt_Call) Return(_a0 pkgobjstore.ReaderAtCloser, _a1 error) *MockBucket_ReaderAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBucket_ReaderAt_Call) RunAndReturn(run func(context.Context, string) (pkgobjstore.ReaderAtCloser, error)) *MockBucket_ReaderAt_Call { + _c.Call.Return(run) + return _c +} + +// SupportedIterOptions provides a mock function with no fields +func (_m *MockBucket) SupportedIterOptions() []objstore.IterOptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for SupportedIterOptions") + } + + var r0 []objstore.IterOptionType + if rf, ok := ret.Get(0).(func() []objstore.IterOptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]objstore.IterOptionType) + } + } + + return r0 +} + +// MockBucket_SupportedIterOptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SupportedIterOptions' +type MockBucket_SupportedIterOptions_Call struct { + *mock.Call +} + +// SupportedIterOptions is a helper method to define mock.On call +func (_e *MockBucket_Expecter) SupportedIterOptions() *MockBucket_SupportedIterOptions_Call { + return &MockBucket_SupportedIterOptions_Call{Call: _e.mock.On("SupportedIterOptions")} +} + +func (_c *MockBucket_SupportedIterOptions_Call) Run(run func()) *MockBucket_SupportedIterOptions_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBucket_SupportedIterOptions_Call) Return(_a0 []objstore.IterOptionType) *MockBucket_SupportedIterOptions_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_SupportedIterOptions_Call) RunAndReturn(run func() []objstore.IterOptionType) *MockBucket_SupportedIterOptions_Call { + _c.Call.Return(run) + return _c +} + +// Upload provides a mock function with given fields: ctx, name, r, opts +func (_m *MockBucket) Upload(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption) error { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, name, r) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Upload") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, io.Reader, ...objstore.ObjectUploadOption) error); ok { + r0 = rf(ctx, name, r, opts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBucket_Upload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Upload' +type MockBucket_Upload_Call struct { + *mock.Call +} + +// Upload is a helper method to define mock.On call +// - ctx context.Context +// - name string +// - r io.Reader +// - opts ...objstore.ObjectUploadOption +func (_e *MockBucket_Expecter) Upload(ctx interface{}, name interface{}, r interface{}, opts ...interface{}) *MockBucket_Upload_Call { + return &MockBucket_Upload_Call{Call: _e.mock.On("Upload", + append([]interface{}{ctx, name, r}, opts...)...)} +} + +func (_c *MockBucket_Upload_Call) Run(run func(ctx context.Context, name string, r io.Reader, opts ...objstore.ObjectUploadOption)) *MockBucket_Upload_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]objstore.ObjectUploadOption, len(args)-3) + for i, a := range args[3:] { + if a != nil { + variadicArgs[i] = a.(objstore.ObjectUploadOption) + } + } + run(args[0].(context.Context), args[1].(string), args[2].(io.Reader), variadicArgs...) + }) + return _c +} + +func (_c *MockBucket_Upload_Call) Return(_a0 error) *MockBucket_Upload_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBucket_Upload_Call) RunAndReturn(run func(context.Context, string, io.Reader, ...objstore.ObjectUploadOption) error) *MockBucket_Upload_Call { + _c.Call.Return(run) + return _c +} + +// NewMockBucket creates a new instance of MockBucket. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockBucket(t interface { + mock.TestingT + Cleanup(func()) +}) *MockBucket { + mock := &MockBucket{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockotlp/mock_push_service.go b/pkg/test/mocks/mockotlp/mock_push_service.go new file mode 100644 index 0000000000..1d87e6a457 --- /dev/null +++ b/pkg/test/mocks/mockotlp/mock_push_service.go @@ -0,0 +1,84 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockotlp + +import ( + context "context" + + model "github.com/grafana/pyroscope/v2/pkg/distributor/model" + mock "github.com/stretchr/testify/mock" +) + +// MockPushService is an autogenerated mock type for the PushService type +type MockPushService struct { + mock.Mock +} + +type MockPushService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockPushService) EXPECT() *MockPushService_Expecter { + return &MockPushService_Expecter{mock: &_m.Mock} +} + +// PushBatch provides a mock function with given fields: ctx, req +func (_m *MockPushService) PushBatch(ctx context.Context, req *model.PushRequest) error { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for PushBatch") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *model.PushRequest) error); ok { + r0 = rf(ctx, req) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockPushService_PushBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PushBatch' +type MockPushService_PushBatch_Call struct { + *mock.Call +} + +// PushBatch is a helper method to define mock.On call +// - ctx context.Context +// - req *model.PushRequest +func (_e *MockPushService_Expecter) PushBatch(ctx interface{}, req interface{}) *MockPushService_PushBatch_Call { + return &MockPushService_PushBatch_Call{Call: _e.mock.On("PushBatch", ctx, req)} +} + +func (_c *MockPushService_PushBatch_Call) Run(run func(ctx context.Context, req *model.PushRequest)) *MockPushService_PushBatch_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*model.PushRequest)) + }) + return _c +} + +func (_c *MockPushService_PushBatch_Call) Return(_a0 error) *MockPushService_PushBatch_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockPushService_PushBatch_Call) RunAndReturn(run func(context.Context, *model.PushRequest) error) *MockPushService_PushBatch_Call { + _c.Call.Return(run) + return _c +} + +// NewMockPushService creates a new instance of MockPushService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockPushService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockPushService { + mock := &MockPushService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockplacement/mock_placement.go b/pkg/test/mocks/mockplacement/mock_placement.go new file mode 100644 index 0000000000..7306687216 --- /dev/null +++ b/pkg/test/mocks/mockplacement/mock_placement.go @@ -0,0 +1,81 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockplacement + +import ( + placement "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement" + mock "github.com/stretchr/testify/mock" +) + +// MockPlacement is an autogenerated mock type for the Placement type +type MockPlacement struct { + mock.Mock +} + +type MockPlacement_Expecter struct { + mock *mock.Mock +} + +func (_m *MockPlacement) EXPECT() *MockPlacement_Expecter { + return &MockPlacement_Expecter{mock: &_m.Mock} +} + +// Policy provides a mock function with given fields: _a0 +func (_m *MockPlacement) Policy(_a0 placement.Key) placement.Policy { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Policy") + } + + var r0 placement.Policy + if rf, ok := ret.Get(0).(func(placement.Key) placement.Policy); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(placement.Policy) + } + + return r0 +} + +// MockPlacement_Policy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Policy' +type MockPlacement_Policy_Call struct { + *mock.Call +} + +// Policy is a helper method to define mock.On call +// - _a0 placement.Key +func (_e *MockPlacement_Expecter) Policy(_a0 interface{}) *MockPlacement_Policy_Call { + return &MockPlacement_Policy_Call{Call: _e.mock.On("Policy", _a0)} +} + +func (_c *MockPlacement_Policy_Call) Run(run func(_a0 placement.Key)) *MockPlacement_Policy_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(placement.Key)) + }) + return _c +} + +func (_c *MockPlacement_Policy_Call) Return(_a0 placement.Policy) *MockPlacement_Policy_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockPlacement_Policy_Call) RunAndReturn(run func(placement.Key) placement.Policy) *MockPlacement_Policy_Call { + _c.Call.Return(run) + return _c +} + +// NewMockPlacement creates a new instance of MockPlacement. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockPlacement(t interface { + mock.TestingT + Cleanup(func()) +}) *MockPlacement { + mock := &MockPlacement{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockpyroscope/mock_push_service.go b/pkg/test/mocks/mockpyroscope/mock_push_service.go new file mode 100644 index 0000000000..35cea5db6a --- /dev/null +++ b/pkg/test/mocks/mockpyroscope/mock_push_service.go @@ -0,0 +1,145 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockpyroscope + +import ( + context "context" + + connect "connectrpc.com/connect" + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + model "github.com/grafana/pyroscope/v2/pkg/distributor/model" + mock "github.com/stretchr/testify/mock" +) + +// MockPushService is an autogenerated mock type for the PushService type +type MockPushService struct { + mock.Mock +} + +type MockPushService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockPushService) EXPECT() *MockPushService_Expecter { + return &MockPushService_Expecter{mock: &_m.Mock} +} + +// Push provides a mock function with given fields: ctx, req +func (_m *MockPushService) Push(ctx context.Context, req *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error) { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for Push") + } + + var r0 *connect.Response[pushv1.PushResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error)); ok { + return rf(ctx, req) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[pushv1.PushRequest]) *connect.Response[pushv1.PushResponse]); ok { + r0 = rf(ctx, req) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[pushv1.PushResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[pushv1.PushRequest]) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockPushService_Push_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Push' +type MockPushService_Push_Call struct { + *mock.Call +} + +// Push is a helper method to define mock.On call +// - ctx context.Context +// - req *connect.Request[pushv1.PushRequest] +func (_e *MockPushService_Expecter) Push(ctx interface{}, req interface{}) *MockPushService_Push_Call { + return &MockPushService_Push_Call{Call: _e.mock.On("Push", ctx, req)} +} + +func (_c *MockPushService_Push_Call) Run(run func(ctx context.Context, req *connect.Request[pushv1.PushRequest])) *MockPushService_Push_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[pushv1.PushRequest])) + }) + return _c +} + +func (_c *MockPushService_Push_Call) Return(_a0 *connect.Response[pushv1.PushResponse], _a1 error) *MockPushService_Push_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockPushService_Push_Call) RunAndReturn(run func(context.Context, *connect.Request[pushv1.PushRequest]) (*connect.Response[pushv1.PushResponse], error)) *MockPushService_Push_Call { + _c.Call.Return(run) + return _c +} + +// PushBatch provides a mock function with given fields: ctx, req +func (_m *MockPushService) PushBatch(ctx context.Context, req *model.PushRequest) error { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for PushBatch") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *model.PushRequest) error); ok { + r0 = rf(ctx, req) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockPushService_PushBatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PushBatch' +type MockPushService_PushBatch_Call struct { + *mock.Call +} + +// PushBatch is a helper method to define mock.On call +// - ctx context.Context +// - req *model.PushRequest +func (_e *MockPushService_Expecter) PushBatch(ctx interface{}, req interface{}) *MockPushService_PushBatch_Call { + return &MockPushService_PushBatch_Call{Call: _e.mock.On("PushBatch", ctx, req)} +} + +func (_c *MockPushService_PushBatch_Call) Run(run func(ctx context.Context, req *model.PushRequest)) *MockPushService_PushBatch_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*model.PushRequest)) + }) + return _c +} + +func (_c *MockPushService_PushBatch_Call) Return(_a0 error) *MockPushService_PushBatch_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockPushService_PushBatch_Call) RunAndReturn(run func(context.Context, *model.PushRequest) error) *MockPushService_PushBatch_Call { + _c.Call.Return(run) + return _c +} + +// NewMockPushService creates a new instance of MockPushService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockPushService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockPushService { + mock := &MockPushService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockquerierv1connect/mock_querier_service_client.go b/pkg/test/mocks/mockquerierv1connect/mock_querier_service_client.go new file mode 100644 index 0000000000..05b665f9b1 --- /dev/null +++ b/pkg/test/mocks/mockquerierv1connect/mock_querier_service_client.go @@ -0,0 +1,808 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockquerierv1connect + +import ( + context "context" + + connect "connectrpc.com/connect" + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + mock "github.com/stretchr/testify/mock" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +// MockQuerierServiceClient is an autogenerated mock type for the QuerierServiceClient type +type MockQuerierServiceClient struct { + mock.Mock +} + +type MockQuerierServiceClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockQuerierServiceClient) EXPECT() *MockQuerierServiceClient_Expecter { + return &MockQuerierServiceClient_Expecter{mock: &_m.Mock} +} + +// AnalyzeQuery provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) AnalyzeQuery(_a0 context.Context, _a1 *connect.Request[querierv1.AnalyzeQueryRequest]) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AnalyzeQuery") + } + + var r0 *connect.Response[querierv1.AnalyzeQueryResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.AnalyzeQueryRequest]) (*connect.Response[querierv1.AnalyzeQueryResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.AnalyzeQueryRequest]) *connect.Response[querierv1.AnalyzeQueryResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.AnalyzeQueryResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.AnalyzeQueryRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_AnalyzeQuery_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AnalyzeQuery' +type MockQuerierServiceClient_AnalyzeQuery_Call struct { + *mock.Call +} + +// AnalyzeQuery is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.AnalyzeQueryRequest] +func (_e *MockQuerierServiceClient_Expecter) AnalyzeQuery(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_AnalyzeQuery_Call { + return &MockQuerierServiceClient_AnalyzeQuery_Call{Call: _e.mock.On("AnalyzeQuery", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_AnalyzeQuery_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.AnalyzeQueryRequest])) *MockQuerierServiceClient_AnalyzeQuery_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.AnalyzeQueryRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_AnalyzeQuery_Call) Return(_a0 *connect.Response[querierv1.AnalyzeQueryResponse], _a1 error) *MockQuerierServiceClient_AnalyzeQuery_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_AnalyzeQuery_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.AnalyzeQueryRequest]) (*connect.Response[querierv1.AnalyzeQueryResponse], error)) *MockQuerierServiceClient_AnalyzeQuery_Call { + _c.Call.Return(run) + return _c +} + +// AsyncQuery provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) AsyncQuery(_a0 context.Context, _a1 *connect.Request[querierv1.AsyncQueryRequest]) (*connect.Response[querierv1.AsyncQueryResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AsyncQuery") + } + + var r0 *connect.Response[querierv1.AsyncQueryResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.AsyncQueryRequest]) (*connect.Response[querierv1.AsyncQueryResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.AsyncQueryRequest]) *connect.Response[querierv1.AsyncQueryResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.AsyncQueryResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.AsyncQueryRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_AsyncQuery_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AsyncQuery' +type MockQuerierServiceClient_AsyncQuery_Call struct { + *mock.Call +} + +// AsyncQuery is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.AsyncQueryRequest] +func (_e *MockQuerierServiceClient_Expecter) AsyncQuery(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_AsyncQuery_Call { + return &MockQuerierServiceClient_AsyncQuery_Call{Call: _e.mock.On("AsyncQuery", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_AsyncQuery_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.AsyncQueryRequest])) *MockQuerierServiceClient_AsyncQuery_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.AsyncQueryRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_AsyncQuery_Call) Return(_a0 *connect.Response[querierv1.AsyncQueryResponse], _a1 error) *MockQuerierServiceClient_AsyncQuery_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_AsyncQuery_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.AsyncQueryRequest]) (*connect.Response[querierv1.AsyncQueryResponse], error)) *MockQuerierServiceClient_AsyncQuery_Call { + _c.Call.Return(run) + return _c +} + +// Diff provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) Diff(_a0 context.Context, _a1 *connect.Request[querierv1.DiffRequest]) (*connect.Response[querierv1.DiffResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Diff") + } + + var r0 *connect.Response[querierv1.DiffResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.DiffRequest]) (*connect.Response[querierv1.DiffResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.DiffRequest]) *connect.Response[querierv1.DiffResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.DiffResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.DiffRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_Diff_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Diff' +type MockQuerierServiceClient_Diff_Call struct { + *mock.Call +} + +// Diff is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.DiffRequest] +func (_e *MockQuerierServiceClient_Expecter) Diff(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_Diff_Call { + return &MockQuerierServiceClient_Diff_Call{Call: _e.mock.On("Diff", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_Diff_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.DiffRequest])) *MockQuerierServiceClient_Diff_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.DiffRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_Diff_Call) Return(_a0 *connect.Response[querierv1.DiffResponse], _a1 error) *MockQuerierServiceClient_Diff_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_Diff_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.DiffRequest]) (*connect.Response[querierv1.DiffResponse], error)) *MockQuerierServiceClient_Diff_Call { + _c.Call.Return(run) + return _c +} + +// GetProfileStats provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) GetProfileStats(_a0 context.Context, _a1 *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetProfileStats") + } + + var r0 *connect.Response[typesv1.GetProfileStatsResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[typesv1.GetProfileStatsRequest]) *connect.Response[typesv1.GetProfileStatsResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[typesv1.GetProfileStatsResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[typesv1.GetProfileStatsRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_GetProfileStats_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProfileStats' +type MockQuerierServiceClient_GetProfileStats_Call struct { + *mock.Call +} + +// GetProfileStats is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[typesv1.GetProfileStatsRequest] +func (_e *MockQuerierServiceClient_Expecter) GetProfileStats(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_GetProfileStats_Call { + return &MockQuerierServiceClient_GetProfileStats_Call{Call: _e.mock.On("GetProfileStats", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_GetProfileStats_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[typesv1.GetProfileStatsRequest])) *MockQuerierServiceClient_GetProfileStats_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[typesv1.GetProfileStatsRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_GetProfileStats_Call) Return(_a0 *connect.Response[typesv1.GetProfileStatsResponse], _a1 error) *MockQuerierServiceClient_GetProfileStats_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_GetProfileStats_Call) RunAndReturn(run func(context.Context, *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error)) *MockQuerierServiceClient_GetProfileStats_Call { + _c.Call.Return(run) + return _c +} + +// LabelNames provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) LabelNames(_a0 context.Context, _a1 *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for LabelNames") + } + + var r0 *connect.Response[typesv1.LabelNamesResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[typesv1.LabelNamesRequest]) *connect.Response[typesv1.LabelNamesResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[typesv1.LabelNamesResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[typesv1.LabelNamesRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_LabelNames_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LabelNames' +type MockQuerierServiceClient_LabelNames_Call struct { + *mock.Call +} + +// LabelNames is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[typesv1.LabelNamesRequest] +func (_e *MockQuerierServiceClient_Expecter) LabelNames(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_LabelNames_Call { + return &MockQuerierServiceClient_LabelNames_Call{Call: _e.mock.On("LabelNames", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_LabelNames_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[typesv1.LabelNamesRequest])) *MockQuerierServiceClient_LabelNames_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[typesv1.LabelNamesRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_LabelNames_Call) Return(_a0 *connect.Response[typesv1.LabelNamesResponse], _a1 error) *MockQuerierServiceClient_LabelNames_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_LabelNames_Call) RunAndReturn(run func(context.Context, *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error)) *MockQuerierServiceClient_LabelNames_Call { + _c.Call.Return(run) + return _c +} + +// LabelValues provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) LabelValues(_a0 context.Context, _a1 *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for LabelValues") + } + + var r0 *connect.Response[typesv1.LabelValuesResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[typesv1.LabelValuesRequest]) *connect.Response[typesv1.LabelValuesResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[typesv1.LabelValuesResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[typesv1.LabelValuesRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_LabelValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LabelValues' +type MockQuerierServiceClient_LabelValues_Call struct { + *mock.Call +} + +// LabelValues is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[typesv1.LabelValuesRequest] +func (_e *MockQuerierServiceClient_Expecter) LabelValues(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_LabelValues_Call { + return &MockQuerierServiceClient_LabelValues_Call{Call: _e.mock.On("LabelValues", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_LabelValues_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[typesv1.LabelValuesRequest])) *MockQuerierServiceClient_LabelValues_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[typesv1.LabelValuesRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_LabelValues_Call) Return(_a0 *connect.Response[typesv1.LabelValuesResponse], _a1 error) *MockQuerierServiceClient_LabelValues_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_LabelValues_Call) RunAndReturn(run func(context.Context, *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error)) *MockQuerierServiceClient_LabelValues_Call { + _c.Call.Return(run) + return _c +} + +// ProfileTypes provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) ProfileTypes(_a0 context.Context, _a1 *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for ProfileTypes") + } + + var r0 *connect.Response[querierv1.ProfileTypesResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.ProfileTypesRequest]) *connect.Response[querierv1.ProfileTypesResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.ProfileTypesResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.ProfileTypesRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_ProfileTypes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProfileTypes' +type MockQuerierServiceClient_ProfileTypes_Call struct { + *mock.Call +} + +// ProfileTypes is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.ProfileTypesRequest] +func (_e *MockQuerierServiceClient_Expecter) ProfileTypes(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_ProfileTypes_Call { + return &MockQuerierServiceClient_ProfileTypes_Call{Call: _e.mock.On("ProfileTypes", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_ProfileTypes_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.ProfileTypesRequest])) *MockQuerierServiceClient_ProfileTypes_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.ProfileTypesRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_ProfileTypes_Call) Return(_a0 *connect.Response[querierv1.ProfileTypesResponse], _a1 error) *MockQuerierServiceClient_ProfileTypes_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_ProfileTypes_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error)) *MockQuerierServiceClient_ProfileTypes_Call { + _c.Call.Return(run) + return _c +} + +// SelectHeatmap provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) SelectHeatmap(_a0 context.Context, _a1 *connect.Request[querierv1.SelectHeatmapRequest]) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for SelectHeatmap") + } + + var r0 *connect.Response[querierv1.SelectHeatmapResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectHeatmapRequest]) (*connect.Response[querierv1.SelectHeatmapResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectHeatmapRequest]) *connect.Response[querierv1.SelectHeatmapResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.SelectHeatmapResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.SelectHeatmapRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_SelectHeatmap_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectHeatmap' +type MockQuerierServiceClient_SelectHeatmap_Call struct { + *mock.Call +} + +// SelectHeatmap is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.SelectHeatmapRequest] +func (_e *MockQuerierServiceClient_Expecter) SelectHeatmap(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_SelectHeatmap_Call { + return &MockQuerierServiceClient_SelectHeatmap_Call{Call: _e.mock.On("SelectHeatmap", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_SelectHeatmap_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.SelectHeatmapRequest])) *MockQuerierServiceClient_SelectHeatmap_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.SelectHeatmapRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_SelectHeatmap_Call) Return(_a0 *connect.Response[querierv1.SelectHeatmapResponse], _a1 error) *MockQuerierServiceClient_SelectHeatmap_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_SelectHeatmap_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.SelectHeatmapRequest]) (*connect.Response[querierv1.SelectHeatmapResponse], error)) *MockQuerierServiceClient_SelectHeatmap_Call { + _c.Call.Return(run) + return _c +} + +// SelectMergeProfile provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) SelectMergeProfile(_a0 context.Context, _a1 *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[googlev1.Profile], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for SelectMergeProfile") + } + + var r0 *connect.Response[googlev1.Profile] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[googlev1.Profile], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectMergeProfileRequest]) *connect.Response[googlev1.Profile]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[googlev1.Profile]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.SelectMergeProfileRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_SelectMergeProfile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectMergeProfile' +type MockQuerierServiceClient_SelectMergeProfile_Call struct { + *mock.Call +} + +// SelectMergeProfile is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.SelectMergeProfileRequest] +func (_e *MockQuerierServiceClient_Expecter) SelectMergeProfile(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_SelectMergeProfile_Call { + return &MockQuerierServiceClient_SelectMergeProfile_Call{Call: _e.mock.On("SelectMergeProfile", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_SelectMergeProfile_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.SelectMergeProfileRequest])) *MockQuerierServiceClient_SelectMergeProfile_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.SelectMergeProfileRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_SelectMergeProfile_Call) Return(_a0 *connect.Response[googlev1.Profile], _a1 error) *MockQuerierServiceClient_SelectMergeProfile_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_SelectMergeProfile_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[googlev1.Profile], error)) *MockQuerierServiceClient_SelectMergeProfile_Call { + _c.Call.Return(run) + return _c +} + +// SelectMergeSpanProfile provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) SelectMergeSpanProfile(_a0 context.Context, _a1 *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for SelectMergeSpanProfile") + } + + var r0 *connect.Response[querierv1.SelectMergeSpanProfileResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectMergeSpanProfileRequest]) *connect.Response[querierv1.SelectMergeSpanProfileResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.SelectMergeSpanProfileResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.SelectMergeSpanProfileRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_SelectMergeSpanProfile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectMergeSpanProfile' +type MockQuerierServiceClient_SelectMergeSpanProfile_Call struct { + *mock.Call +} + +// SelectMergeSpanProfile is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.SelectMergeSpanProfileRequest] +func (_e *MockQuerierServiceClient_Expecter) SelectMergeSpanProfile(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_SelectMergeSpanProfile_Call { + return &MockQuerierServiceClient_SelectMergeSpanProfile_Call{Call: _e.mock.On("SelectMergeSpanProfile", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_SelectMergeSpanProfile_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.SelectMergeSpanProfileRequest])) *MockQuerierServiceClient_SelectMergeSpanProfile_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.SelectMergeSpanProfileRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_SelectMergeSpanProfile_Call) Return(_a0 *connect.Response[querierv1.SelectMergeSpanProfileResponse], _a1 error) *MockQuerierServiceClient_SelectMergeSpanProfile_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_SelectMergeSpanProfile_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error)) *MockQuerierServiceClient_SelectMergeSpanProfile_Call { + _c.Call.Return(run) + return _c +} + +// SelectMergeStacktraces provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) SelectMergeStacktraces(_a0 context.Context, _a1 *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for SelectMergeStacktraces") + } + + var r0 *connect.Response[querierv1.SelectMergeStacktracesResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectMergeStacktracesRequest]) *connect.Response[querierv1.SelectMergeStacktracesResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.SelectMergeStacktracesResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.SelectMergeStacktracesRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_SelectMergeStacktraces_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectMergeStacktraces' +type MockQuerierServiceClient_SelectMergeStacktraces_Call struct { + *mock.Call +} + +// SelectMergeStacktraces is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.SelectMergeStacktracesRequest] +func (_e *MockQuerierServiceClient_Expecter) SelectMergeStacktraces(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_SelectMergeStacktraces_Call { + return &MockQuerierServiceClient_SelectMergeStacktraces_Call{Call: _e.mock.On("SelectMergeStacktraces", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_SelectMergeStacktraces_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.SelectMergeStacktracesRequest])) *MockQuerierServiceClient_SelectMergeStacktraces_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.SelectMergeStacktracesRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_SelectMergeStacktraces_Call) Return(_a0 *connect.Response[querierv1.SelectMergeStacktracesResponse], _a1 error) *MockQuerierServiceClient_SelectMergeStacktraces_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_SelectMergeStacktraces_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error)) *MockQuerierServiceClient_SelectMergeStacktraces_Call { + _c.Call.Return(run) + return _c +} + +// SelectSeries provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) SelectSeries(_a0 context.Context, _a1 *connect.Request[querierv1.SelectSeriesRequest]) (*connect.Response[querierv1.SelectSeriesResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for SelectSeries") + } + + var r0 *connect.Response[querierv1.SelectSeriesResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectSeriesRequest]) (*connect.Response[querierv1.SelectSeriesResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SelectSeriesRequest]) *connect.Response[querierv1.SelectSeriesResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.SelectSeriesResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.SelectSeriesRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_SelectSeries_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectSeries' +type MockQuerierServiceClient_SelectSeries_Call struct { + *mock.Call +} + +// SelectSeries is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.SelectSeriesRequest] +func (_e *MockQuerierServiceClient_Expecter) SelectSeries(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_SelectSeries_Call { + return &MockQuerierServiceClient_SelectSeries_Call{Call: _e.mock.On("SelectSeries", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_SelectSeries_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.SelectSeriesRequest])) *MockQuerierServiceClient_SelectSeries_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.SelectSeriesRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_SelectSeries_Call) Return(_a0 *connect.Response[querierv1.SelectSeriesResponse], _a1 error) *MockQuerierServiceClient_SelectSeries_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_SelectSeries_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.SelectSeriesRequest]) (*connect.Response[querierv1.SelectSeriesResponse], error)) *MockQuerierServiceClient_SelectSeries_Call { + _c.Call.Return(run) + return _c +} + +// Series provides a mock function with given fields: _a0, _a1 +func (_m *MockQuerierServiceClient) Series(_a0 context.Context, _a1 *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Series") + } + + var r0 *connect.Response[querierv1.SeriesResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[querierv1.SeriesRequest]) *connect.Response[querierv1.SeriesResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[querierv1.SeriesResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[querierv1.SeriesRequest]) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQuerierServiceClient_Series_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Series' +type MockQuerierServiceClient_Series_Call struct { + *mock.Call +} + +// Series is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *connect.Request[querierv1.SeriesRequest] +func (_e *MockQuerierServiceClient_Expecter) Series(_a0 interface{}, _a1 interface{}) *MockQuerierServiceClient_Series_Call { + return &MockQuerierServiceClient_Series_Call{Call: _e.mock.On("Series", _a0, _a1)} +} + +func (_c *MockQuerierServiceClient_Series_Call) Run(run func(_a0 context.Context, _a1 *connect.Request[querierv1.SeriesRequest])) *MockQuerierServiceClient_Series_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*connect.Request[querierv1.SeriesRequest])) + }) + return _c +} + +func (_c *MockQuerierServiceClient_Series_Call) Return(_a0 *connect.Response[querierv1.SeriesResponse], _a1 error) *MockQuerierServiceClient_Series_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQuerierServiceClient_Series_Call) RunAndReturn(run func(context.Context, *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error)) *MockQuerierServiceClient_Series_Call { + _c.Call.Return(run) + return _c +} + +// NewMockQuerierServiceClient creates a new instance of MockQuerierServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockQuerierServiceClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockQuerierServiceClient { + mock := &MockQuerierServiceClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockqueryfrontend/mock_query_backend.go b/pkg/test/mocks/mockqueryfrontend/mock_query_backend.go new file mode 100644 index 0000000000..46f5d61126 --- /dev/null +++ b/pkg/test/mocks/mockqueryfrontend/mock_query_backend.go @@ -0,0 +1,97 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockqueryfrontend + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + queryv1 "github.com/grafana/pyroscope/api/gen/proto/go/query/v1" +) + +// MockQueryBackend is an autogenerated mock type for the QueryBackend type +type MockQueryBackend struct { + mock.Mock +} + +type MockQueryBackend_Expecter struct { + mock *mock.Mock +} + +func (_m *MockQueryBackend) EXPECT() *MockQueryBackend_Expecter { + return &MockQueryBackend_Expecter{mock: &_m.Mock} +} + +// Invoke provides a mock function with given fields: ctx, req +func (_m *MockQueryBackend) Invoke(ctx context.Context, req *queryv1.InvokeRequest) (*queryv1.InvokeResponse, error) { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for Invoke") + } + + var r0 *queryv1.InvokeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *queryv1.InvokeRequest) (*queryv1.InvokeResponse, error)); ok { + return rf(ctx, req) + } + if rf, ok := ret.Get(0).(func(context.Context, *queryv1.InvokeRequest) *queryv1.InvokeResponse); ok { + r0 = rf(ctx, req) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*queryv1.InvokeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *queryv1.InvokeRequest) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockQueryBackend_Invoke_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Invoke' +type MockQueryBackend_Invoke_Call struct { + *mock.Call +} + +// Invoke is a helper method to define mock.On call +// - ctx context.Context +// - req *queryv1.InvokeRequest +func (_e *MockQueryBackend_Expecter) Invoke(ctx interface{}, req interface{}) *MockQueryBackend_Invoke_Call { + return &MockQueryBackend_Invoke_Call{Call: _e.mock.On("Invoke", ctx, req)} +} + +func (_c *MockQueryBackend_Invoke_Call) Run(run func(ctx context.Context, req *queryv1.InvokeRequest)) *MockQueryBackend_Invoke_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*queryv1.InvokeRequest)) + }) + return _c +} + +func (_c *MockQueryBackend_Invoke_Call) Return(_a0 *queryv1.InvokeResponse, _a1 error) *MockQueryBackend_Invoke_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockQueryBackend_Invoke_Call) RunAndReturn(run func(context.Context, *queryv1.InvokeRequest) (*queryv1.InvokeResponse, error)) *MockQueryBackend_Invoke_Call { + _c.Call.Return(run) + return _c +} + +// NewMockQueryBackend creates a new instance of MockQueryBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockQueryBackend(t interface { + mock.TestingT + Cleanup(func()) +}) *MockQueryBackend { + mock := &MockQueryBackend{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockqueryfrontend/mock_symbolizer.go b/pkg/test/mocks/mockqueryfrontend/mock_symbolizer.go new file mode 100644 index 0000000000..c484537276 --- /dev/null +++ b/pkg/test/mocks/mockqueryfrontend/mock_symbolizer.go @@ -0,0 +1,84 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockqueryfrontend + +import ( + context "context" + + googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + mock "github.com/stretchr/testify/mock" +) + +// MockSymbolizer is an autogenerated mock type for the Symbolizer type +type MockSymbolizer struct { + mock.Mock +} + +type MockSymbolizer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockSymbolizer) EXPECT() *MockSymbolizer_Expecter { + return &MockSymbolizer_Expecter{mock: &_m.Mock} +} + +// SymbolizePprof provides a mock function with given fields: ctx, profile +func (_m *MockSymbolizer) SymbolizePprof(ctx context.Context, profile *googlev1.Profile) error { + ret := _m.Called(ctx, profile) + + if len(ret) == 0 { + panic("no return value specified for SymbolizePprof") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *googlev1.Profile) error); ok { + r0 = rf(ctx, profile) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockSymbolizer_SymbolizePprof_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SymbolizePprof' +type MockSymbolizer_SymbolizePprof_Call struct { + *mock.Call +} + +// SymbolizePprof is a helper method to define mock.On call +// - ctx context.Context +// - profile *googlev1.Profile +func (_e *MockSymbolizer_Expecter) SymbolizePprof(ctx interface{}, profile interface{}) *MockSymbolizer_SymbolizePprof_Call { + return &MockSymbolizer_SymbolizePprof_Call{Call: _e.mock.On("SymbolizePprof", ctx, profile)} +} + +func (_c *MockSymbolizer_SymbolizePprof_Call) Run(run func(ctx context.Context, profile *googlev1.Profile)) *MockSymbolizer_SymbolizePprof_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*googlev1.Profile)) + }) + return _c +} + +func (_c *MockSymbolizer_SymbolizePprof_Call) Return(_a0 error) *MockSymbolizer_SymbolizePprof_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockSymbolizer_SymbolizePprof_Call) RunAndReturn(run func(context.Context, *googlev1.Profile) error) *MockSymbolizer_SymbolizePprof_Call { + _c.Call.Return(run) + return _c +} + +// NewMockSymbolizer creates a new instance of MockSymbolizer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockSymbolizer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockSymbolizer { + mock := &MockSymbolizer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockraftnodepb/mock_raft_node_service_client.go b/pkg/test/mocks/mockraftnodepb/mock_raft_node_service_client.go new file mode 100644 index 0000000000..ba5ac51d8e --- /dev/null +++ b/pkg/test/mocks/mockraftnodepb/mock_raft_node_service_client.go @@ -0,0 +1,482 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockraftnodepb + +import ( + context "context" + + raftnodepb "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + mock "github.com/stretchr/testify/mock" + grpc "google.golang.org/grpc" +) + +// MockRaftNodeServiceClient is an autogenerated mock type for the RaftNodeServiceClient type +type MockRaftNodeServiceClient struct { + mock.Mock +} + +type MockRaftNodeServiceClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockRaftNodeServiceClient) EXPECT() *MockRaftNodeServiceClient_Expecter { + return &MockRaftNodeServiceClient_Expecter{mock: &_m.Mock} +} + +// AddNode provides a mock function with given fields: ctx, in, opts +func (_m *MockRaftNodeServiceClient) AddNode(ctx context.Context, in *raftnodepb.AddNodeRequest, opts ...grpc.CallOption) (*raftnodepb.AddNodeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddNode") + } + + var r0 *raftnodepb.AddNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.AddNodeRequest, ...grpc.CallOption) (*raftnodepb.AddNodeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.AddNodeRequest, ...grpc.CallOption) *raftnodepb.AddNodeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.AddNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.AddNodeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceClient_AddNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddNode' +type MockRaftNodeServiceClient_AddNode_Call struct { + *mock.Call +} + +// AddNode is a helper method to define mock.On call +// - ctx context.Context +// - in *raftnodepb.AddNodeRequest +// - opts ...grpc.CallOption +func (_e *MockRaftNodeServiceClient_Expecter) AddNode(ctx interface{}, in interface{}, opts ...interface{}) *MockRaftNodeServiceClient_AddNode_Call { + return &MockRaftNodeServiceClient_AddNode_Call{Call: _e.mock.On("AddNode", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockRaftNodeServiceClient_AddNode_Call) Run(run func(ctx context.Context, in *raftnodepb.AddNodeRequest, opts ...grpc.CallOption)) *MockRaftNodeServiceClient_AddNode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*raftnodepb.AddNodeRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockRaftNodeServiceClient_AddNode_Call) Return(_a0 *raftnodepb.AddNodeResponse, _a1 error) *MockRaftNodeServiceClient_AddNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceClient_AddNode_Call) RunAndReturn(run func(context.Context, *raftnodepb.AddNodeRequest, ...grpc.CallOption) (*raftnodepb.AddNodeResponse, error)) *MockRaftNodeServiceClient_AddNode_Call { + _c.Call.Return(run) + return _c +} + +// DemoteLeader provides a mock function with given fields: ctx, in, opts +func (_m *MockRaftNodeServiceClient) DemoteLeader(ctx context.Context, in *raftnodepb.DemoteLeaderRequest, opts ...grpc.CallOption) (*raftnodepb.DemoteLeaderResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DemoteLeader") + } + + var r0 *raftnodepb.DemoteLeaderResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.DemoteLeaderRequest, ...grpc.CallOption) (*raftnodepb.DemoteLeaderResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.DemoteLeaderRequest, ...grpc.CallOption) *raftnodepb.DemoteLeaderResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.DemoteLeaderResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.DemoteLeaderRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceClient_DemoteLeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DemoteLeader' +type MockRaftNodeServiceClient_DemoteLeader_Call struct { + *mock.Call +} + +// DemoteLeader is a helper method to define mock.On call +// - ctx context.Context +// - in *raftnodepb.DemoteLeaderRequest +// - opts ...grpc.CallOption +func (_e *MockRaftNodeServiceClient_Expecter) DemoteLeader(ctx interface{}, in interface{}, opts ...interface{}) *MockRaftNodeServiceClient_DemoteLeader_Call { + return &MockRaftNodeServiceClient_DemoteLeader_Call{Call: _e.mock.On("DemoteLeader", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockRaftNodeServiceClient_DemoteLeader_Call) Run(run func(ctx context.Context, in *raftnodepb.DemoteLeaderRequest, opts ...grpc.CallOption)) *MockRaftNodeServiceClient_DemoteLeader_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*raftnodepb.DemoteLeaderRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockRaftNodeServiceClient_DemoteLeader_Call) Return(_a0 *raftnodepb.DemoteLeaderResponse, _a1 error) *MockRaftNodeServiceClient_DemoteLeader_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceClient_DemoteLeader_Call) RunAndReturn(run func(context.Context, *raftnodepb.DemoteLeaderRequest, ...grpc.CallOption) (*raftnodepb.DemoteLeaderResponse, error)) *MockRaftNodeServiceClient_DemoteLeader_Call { + _c.Call.Return(run) + return _c +} + +// NodeInfo provides a mock function with given fields: ctx, in, opts +func (_m *MockRaftNodeServiceClient) NodeInfo(ctx context.Context, in *raftnodepb.NodeInfoRequest, opts ...grpc.CallOption) (*raftnodepb.NodeInfoResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for NodeInfo") + } + + var r0 *raftnodepb.NodeInfoResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.NodeInfoRequest, ...grpc.CallOption) (*raftnodepb.NodeInfoResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.NodeInfoRequest, ...grpc.CallOption) *raftnodepb.NodeInfoResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.NodeInfoResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.NodeInfoRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceClient_NodeInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeInfo' +type MockRaftNodeServiceClient_NodeInfo_Call struct { + *mock.Call +} + +// NodeInfo is a helper method to define mock.On call +// - ctx context.Context +// - in *raftnodepb.NodeInfoRequest +// - opts ...grpc.CallOption +func (_e *MockRaftNodeServiceClient_Expecter) NodeInfo(ctx interface{}, in interface{}, opts ...interface{}) *MockRaftNodeServiceClient_NodeInfo_Call { + return &MockRaftNodeServiceClient_NodeInfo_Call{Call: _e.mock.On("NodeInfo", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockRaftNodeServiceClient_NodeInfo_Call) Run(run func(ctx context.Context, in *raftnodepb.NodeInfoRequest, opts ...grpc.CallOption)) *MockRaftNodeServiceClient_NodeInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*raftnodepb.NodeInfoRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockRaftNodeServiceClient_NodeInfo_Call) Return(_a0 *raftnodepb.NodeInfoResponse, _a1 error) *MockRaftNodeServiceClient_NodeInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceClient_NodeInfo_Call) RunAndReturn(run func(context.Context, *raftnodepb.NodeInfoRequest, ...grpc.CallOption) (*raftnodepb.NodeInfoResponse, error)) *MockRaftNodeServiceClient_NodeInfo_Call { + _c.Call.Return(run) + return _c +} + +// PromoteToLeader provides a mock function with given fields: ctx, in, opts +func (_m *MockRaftNodeServiceClient) PromoteToLeader(ctx context.Context, in *raftnodepb.PromoteToLeaderRequest, opts ...grpc.CallOption) (*raftnodepb.PromoteToLeaderResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for PromoteToLeader") + } + + var r0 *raftnodepb.PromoteToLeaderResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.PromoteToLeaderRequest, ...grpc.CallOption) (*raftnodepb.PromoteToLeaderResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.PromoteToLeaderRequest, ...grpc.CallOption) *raftnodepb.PromoteToLeaderResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.PromoteToLeaderResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.PromoteToLeaderRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceClient_PromoteToLeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PromoteToLeader' +type MockRaftNodeServiceClient_PromoteToLeader_Call struct { + *mock.Call +} + +// PromoteToLeader is a helper method to define mock.On call +// - ctx context.Context +// - in *raftnodepb.PromoteToLeaderRequest +// - opts ...grpc.CallOption +func (_e *MockRaftNodeServiceClient_Expecter) PromoteToLeader(ctx interface{}, in interface{}, opts ...interface{}) *MockRaftNodeServiceClient_PromoteToLeader_Call { + return &MockRaftNodeServiceClient_PromoteToLeader_Call{Call: _e.mock.On("PromoteToLeader", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockRaftNodeServiceClient_PromoteToLeader_Call) Run(run func(ctx context.Context, in *raftnodepb.PromoteToLeaderRequest, opts ...grpc.CallOption)) *MockRaftNodeServiceClient_PromoteToLeader_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*raftnodepb.PromoteToLeaderRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockRaftNodeServiceClient_PromoteToLeader_Call) Return(_a0 *raftnodepb.PromoteToLeaderResponse, _a1 error) *MockRaftNodeServiceClient_PromoteToLeader_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceClient_PromoteToLeader_Call) RunAndReturn(run func(context.Context, *raftnodepb.PromoteToLeaderRequest, ...grpc.CallOption) (*raftnodepb.PromoteToLeaderResponse, error)) *MockRaftNodeServiceClient_PromoteToLeader_Call { + _c.Call.Return(run) + return _c +} + +// ReadIndex provides a mock function with given fields: ctx, in, opts +func (_m *MockRaftNodeServiceClient) ReadIndex(ctx context.Context, in *raftnodepb.ReadIndexRequest, opts ...grpc.CallOption) (*raftnodepb.ReadIndexResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ReadIndex") + } + + var r0 *raftnodepb.ReadIndexResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.ReadIndexRequest, ...grpc.CallOption) (*raftnodepb.ReadIndexResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.ReadIndexRequest, ...grpc.CallOption) *raftnodepb.ReadIndexResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.ReadIndexResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.ReadIndexRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceClient_ReadIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadIndex' +type MockRaftNodeServiceClient_ReadIndex_Call struct { + *mock.Call +} + +// ReadIndex is a helper method to define mock.On call +// - ctx context.Context +// - in *raftnodepb.ReadIndexRequest +// - opts ...grpc.CallOption +func (_e *MockRaftNodeServiceClient_Expecter) ReadIndex(ctx interface{}, in interface{}, opts ...interface{}) *MockRaftNodeServiceClient_ReadIndex_Call { + return &MockRaftNodeServiceClient_ReadIndex_Call{Call: _e.mock.On("ReadIndex", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockRaftNodeServiceClient_ReadIndex_Call) Run(run func(ctx context.Context, in *raftnodepb.ReadIndexRequest, opts ...grpc.CallOption)) *MockRaftNodeServiceClient_ReadIndex_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*raftnodepb.ReadIndexRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockRaftNodeServiceClient_ReadIndex_Call) Return(_a0 *raftnodepb.ReadIndexResponse, _a1 error) *MockRaftNodeServiceClient_ReadIndex_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceClient_ReadIndex_Call) RunAndReturn(run func(context.Context, *raftnodepb.ReadIndexRequest, ...grpc.CallOption) (*raftnodepb.ReadIndexResponse, error)) *MockRaftNodeServiceClient_ReadIndex_Call { + _c.Call.Return(run) + return _c +} + +// RemoveNode provides a mock function with given fields: ctx, in, opts +func (_m *MockRaftNodeServiceClient) RemoveNode(ctx context.Context, in *raftnodepb.RemoveNodeRequest, opts ...grpc.CallOption) (*raftnodepb.RemoveNodeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RemoveNode") + } + + var r0 *raftnodepb.RemoveNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.RemoveNodeRequest, ...grpc.CallOption) (*raftnodepb.RemoveNodeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.RemoveNodeRequest, ...grpc.CallOption) *raftnodepb.RemoveNodeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.RemoveNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.RemoveNodeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceClient_RemoveNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveNode' +type MockRaftNodeServiceClient_RemoveNode_Call struct { + *mock.Call +} + +// RemoveNode is a helper method to define mock.On call +// - ctx context.Context +// - in *raftnodepb.RemoveNodeRequest +// - opts ...grpc.CallOption +func (_e *MockRaftNodeServiceClient_Expecter) RemoveNode(ctx interface{}, in interface{}, opts ...interface{}) *MockRaftNodeServiceClient_RemoveNode_Call { + return &MockRaftNodeServiceClient_RemoveNode_Call{Call: _e.mock.On("RemoveNode", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockRaftNodeServiceClient_RemoveNode_Call) Run(run func(ctx context.Context, in *raftnodepb.RemoveNodeRequest, opts ...grpc.CallOption)) *MockRaftNodeServiceClient_RemoveNode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*raftnodepb.RemoveNodeRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockRaftNodeServiceClient_RemoveNode_Call) Return(_a0 *raftnodepb.RemoveNodeResponse, _a1 error) *MockRaftNodeServiceClient_RemoveNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceClient_RemoveNode_Call) RunAndReturn(run func(context.Context, *raftnodepb.RemoveNodeRequest, ...grpc.CallOption) (*raftnodepb.RemoveNodeResponse, error)) *MockRaftNodeServiceClient_RemoveNode_Call { + _c.Call.Return(run) + return _c +} + +// NewMockRaftNodeServiceClient creates a new instance of MockRaftNodeServiceClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockRaftNodeServiceClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockRaftNodeServiceClient { + mock := &MockRaftNodeServiceClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockraftnodepb/mock_raft_node_service_server.go b/pkg/test/mocks/mockraftnodepb/mock_raft_node_service_server.go new file mode 100644 index 0000000000..81bbe0cea2 --- /dev/null +++ b/pkg/test/mocks/mockraftnodepb/mock_raft_node_service_server.go @@ -0,0 +1,423 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockraftnodepb + +import ( + context "context" + + raftnodepb "github.com/grafana/pyroscope/v2/pkg/metastore/raftnode/raftnodepb" + mock "github.com/stretchr/testify/mock" +) + +// MockRaftNodeServiceServer is an autogenerated mock type for the RaftNodeServiceServer type +type MockRaftNodeServiceServer struct { + mock.Mock +} + +type MockRaftNodeServiceServer_Expecter struct { + mock *mock.Mock +} + +func (_m *MockRaftNodeServiceServer) EXPECT() *MockRaftNodeServiceServer_Expecter { + return &MockRaftNodeServiceServer_Expecter{mock: &_m.Mock} +} + +// AddNode provides a mock function with given fields: _a0, _a1 +func (_m *MockRaftNodeServiceServer) AddNode(_a0 context.Context, _a1 *raftnodepb.AddNodeRequest) (*raftnodepb.AddNodeResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddNode") + } + + var r0 *raftnodepb.AddNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.AddNodeRequest) (*raftnodepb.AddNodeResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.AddNodeRequest) *raftnodepb.AddNodeResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.AddNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.AddNodeRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceServer_AddNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddNode' +type MockRaftNodeServiceServer_AddNode_Call struct { + *mock.Call +} + +// AddNode is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *raftnodepb.AddNodeRequest +func (_e *MockRaftNodeServiceServer_Expecter) AddNode(_a0 interface{}, _a1 interface{}) *MockRaftNodeServiceServer_AddNode_Call { + return &MockRaftNodeServiceServer_AddNode_Call{Call: _e.mock.On("AddNode", _a0, _a1)} +} + +func (_c *MockRaftNodeServiceServer_AddNode_Call) Run(run func(_a0 context.Context, _a1 *raftnodepb.AddNodeRequest)) *MockRaftNodeServiceServer_AddNode_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*raftnodepb.AddNodeRequest)) + }) + return _c +} + +func (_c *MockRaftNodeServiceServer_AddNode_Call) Return(_a0 *raftnodepb.AddNodeResponse, _a1 error) *MockRaftNodeServiceServer_AddNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceServer_AddNode_Call) RunAndReturn(run func(context.Context, *raftnodepb.AddNodeRequest) (*raftnodepb.AddNodeResponse, error)) *MockRaftNodeServiceServer_AddNode_Call { + _c.Call.Return(run) + return _c +} + +// DemoteLeader provides a mock function with given fields: _a0, _a1 +func (_m *MockRaftNodeServiceServer) DemoteLeader(_a0 context.Context, _a1 *raftnodepb.DemoteLeaderRequest) (*raftnodepb.DemoteLeaderResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for DemoteLeader") + } + + var r0 *raftnodepb.DemoteLeaderResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.DemoteLeaderRequest) (*raftnodepb.DemoteLeaderResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.DemoteLeaderRequest) *raftnodepb.DemoteLeaderResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.DemoteLeaderResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.DemoteLeaderRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceServer_DemoteLeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DemoteLeader' +type MockRaftNodeServiceServer_DemoteLeader_Call struct { + *mock.Call +} + +// DemoteLeader is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *raftnodepb.DemoteLeaderRequest +func (_e *MockRaftNodeServiceServer_Expecter) DemoteLeader(_a0 interface{}, _a1 interface{}) *MockRaftNodeServiceServer_DemoteLeader_Call { + return &MockRaftNodeServiceServer_DemoteLeader_Call{Call: _e.mock.On("DemoteLeader", _a0, _a1)} +} + +func (_c *MockRaftNodeServiceServer_DemoteLeader_Call) Run(run func(_a0 context.Context, _a1 *raftnodepb.DemoteLeaderRequest)) *MockRaftNodeServiceServer_DemoteLeader_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*raftnodepb.DemoteLeaderRequest)) + }) + return _c +} + +func (_c *MockRaftNodeServiceServer_DemoteLeader_Call) Return(_a0 *raftnodepb.DemoteLeaderResponse, _a1 error) *MockRaftNodeServiceServer_DemoteLeader_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceServer_DemoteLeader_Call) RunAndReturn(run func(context.Context, *raftnodepb.DemoteLeaderRequest) (*raftnodepb.DemoteLeaderResponse, error)) *MockRaftNodeServiceServer_DemoteLeader_Call { + _c.Call.Return(run) + return _c +} + +// NodeInfo provides a mock function with given fields: _a0, _a1 +func (_m *MockRaftNodeServiceServer) NodeInfo(_a0 context.Context, _a1 *raftnodepb.NodeInfoRequest) (*raftnodepb.NodeInfoResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for NodeInfo") + } + + var r0 *raftnodepb.NodeInfoResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.NodeInfoRequest) (*raftnodepb.NodeInfoResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.NodeInfoRequest) *raftnodepb.NodeInfoResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.NodeInfoResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.NodeInfoRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceServer_NodeInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeInfo' +type MockRaftNodeServiceServer_NodeInfo_Call struct { + *mock.Call +} + +// NodeInfo is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *raftnodepb.NodeInfoRequest +func (_e *MockRaftNodeServiceServer_Expecter) NodeInfo(_a0 interface{}, _a1 interface{}) *MockRaftNodeServiceServer_NodeInfo_Call { + return &MockRaftNodeServiceServer_NodeInfo_Call{Call: _e.mock.On("NodeInfo", _a0, _a1)} +} + +func (_c *MockRaftNodeServiceServer_NodeInfo_Call) Run(run func(_a0 context.Context, _a1 *raftnodepb.NodeInfoRequest)) *MockRaftNodeServiceServer_NodeInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*raftnodepb.NodeInfoRequest)) + }) + return _c +} + +func (_c *MockRaftNodeServiceServer_NodeInfo_Call) Return(_a0 *raftnodepb.NodeInfoResponse, _a1 error) *MockRaftNodeServiceServer_NodeInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceServer_NodeInfo_Call) RunAndReturn(run func(context.Context, *raftnodepb.NodeInfoRequest) (*raftnodepb.NodeInfoResponse, error)) *MockRaftNodeServiceServer_NodeInfo_Call { + _c.Call.Return(run) + return _c +} + +// PromoteToLeader provides a mock function with given fields: _a0, _a1 +func (_m *MockRaftNodeServiceServer) PromoteToLeader(_a0 context.Context, _a1 *raftnodepb.PromoteToLeaderRequest) (*raftnodepb.PromoteToLeaderResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for PromoteToLeader") + } + + var r0 *raftnodepb.PromoteToLeaderResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.PromoteToLeaderRequest) (*raftnodepb.PromoteToLeaderResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.PromoteToLeaderRequest) *raftnodepb.PromoteToLeaderResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.PromoteToLeaderResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.PromoteToLeaderRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceServer_PromoteToLeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PromoteToLeader' +type MockRaftNodeServiceServer_PromoteToLeader_Call struct { + *mock.Call +} + +// PromoteToLeader is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *raftnodepb.PromoteToLeaderRequest +func (_e *MockRaftNodeServiceServer_Expecter) PromoteToLeader(_a0 interface{}, _a1 interface{}) *MockRaftNodeServiceServer_PromoteToLeader_Call { + return &MockRaftNodeServiceServer_PromoteToLeader_Call{Call: _e.mock.On("PromoteToLeader", _a0, _a1)} +} + +func (_c *MockRaftNodeServiceServer_PromoteToLeader_Call) Run(run func(_a0 context.Context, _a1 *raftnodepb.PromoteToLeaderRequest)) *MockRaftNodeServiceServer_PromoteToLeader_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*raftnodepb.PromoteToLeaderRequest)) + }) + return _c +} + +func (_c *MockRaftNodeServiceServer_PromoteToLeader_Call) Return(_a0 *raftnodepb.PromoteToLeaderResponse, _a1 error) *MockRaftNodeServiceServer_PromoteToLeader_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceServer_PromoteToLeader_Call) RunAndReturn(run func(context.Context, *raftnodepb.PromoteToLeaderRequest) (*raftnodepb.PromoteToLeaderResponse, error)) *MockRaftNodeServiceServer_PromoteToLeader_Call { + _c.Call.Return(run) + return _c +} + +// ReadIndex provides a mock function with given fields: _a0, _a1 +func (_m *MockRaftNodeServiceServer) ReadIndex(_a0 context.Context, _a1 *raftnodepb.ReadIndexRequest) (*raftnodepb.ReadIndexResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for ReadIndex") + } + + var r0 *raftnodepb.ReadIndexResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.ReadIndexRequest) (*raftnodepb.ReadIndexResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.ReadIndexRequest) *raftnodepb.ReadIndexResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.ReadIndexResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.ReadIndexRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceServer_ReadIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadIndex' +type MockRaftNodeServiceServer_ReadIndex_Call struct { + *mock.Call +} + +// ReadIndex is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *raftnodepb.ReadIndexRequest +func (_e *MockRaftNodeServiceServer_Expecter) ReadIndex(_a0 interface{}, _a1 interface{}) *MockRaftNodeServiceServer_ReadIndex_Call { + return &MockRaftNodeServiceServer_ReadIndex_Call{Call: _e.mock.On("ReadIndex", _a0, _a1)} +} + +func (_c *MockRaftNodeServiceServer_ReadIndex_Call) Run(run func(_a0 context.Context, _a1 *raftnodepb.ReadIndexRequest)) *MockRaftNodeServiceServer_ReadIndex_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*raftnodepb.ReadIndexRequest)) + }) + return _c +} + +func (_c *MockRaftNodeServiceServer_ReadIndex_Call) Return(_a0 *raftnodepb.ReadIndexResponse, _a1 error) *MockRaftNodeServiceServer_ReadIndex_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceServer_ReadIndex_Call) RunAndReturn(run func(context.Context, *raftnodepb.ReadIndexRequest) (*raftnodepb.ReadIndexResponse, error)) *MockRaftNodeServiceServer_ReadIndex_Call { + _c.Call.Return(run) + return _c +} + +// RemoveNode provides a mock function with given fields: _a0, _a1 +func (_m *MockRaftNodeServiceServer) RemoveNode(_a0 context.Context, _a1 *raftnodepb.RemoveNodeRequest) (*raftnodepb.RemoveNodeResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for RemoveNode") + } + + var r0 *raftnodepb.RemoveNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.RemoveNodeRequest) (*raftnodepb.RemoveNodeResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *raftnodepb.RemoveNodeRequest) *raftnodepb.RemoveNodeResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raftnodepb.RemoveNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *raftnodepb.RemoveNodeRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRaftNodeServiceServer_RemoveNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveNode' +type MockRaftNodeServiceServer_RemoveNode_Call struct { + *mock.Call +} + +// RemoveNode is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *raftnodepb.RemoveNodeRequest +func (_e *MockRaftNodeServiceServer_Expecter) RemoveNode(_a0 interface{}, _a1 interface{}) *MockRaftNodeServiceServer_RemoveNode_Call { + return &MockRaftNodeServiceServer_RemoveNode_Call{Call: _e.mock.On("RemoveNode", _a0, _a1)} +} + +func (_c *MockRaftNodeServiceServer_RemoveNode_Call) Run(run func(_a0 context.Context, _a1 *raftnodepb.RemoveNodeRequest)) *MockRaftNodeServiceServer_RemoveNode_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*raftnodepb.RemoveNodeRequest)) + }) + return _c +} + +func (_c *MockRaftNodeServiceServer_RemoveNode_Call) Return(_a0 *raftnodepb.RemoveNodeResponse, _a1 error) *MockRaftNodeServiceServer_RemoveNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRaftNodeServiceServer_RemoveNode_Call) RunAndReturn(run func(context.Context, *raftnodepb.RemoveNodeRequest) (*raftnodepb.RemoveNodeResponse, error)) *MockRaftNodeServiceServer_RemoveNode_Call { + _c.Call.Return(run) + return _c +} + +// mustEmbedUnimplementedRaftNodeServiceServer provides a mock function with no fields +func (_m *MockRaftNodeServiceServer) mustEmbedUnimplementedRaftNodeServiceServer() { + _m.Called() +} + +// MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'mustEmbedUnimplementedRaftNodeServiceServer' +type MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call struct { + *mock.Call +} + +// mustEmbedUnimplementedRaftNodeServiceServer is a helper method to define mock.On call +func (_e *MockRaftNodeServiceServer_Expecter) mustEmbedUnimplementedRaftNodeServiceServer() *MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call { + return &MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call{Call: _e.mock.On("mustEmbedUnimplementedRaftNodeServiceServer")} +} + +func (_c *MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call) Run(run func()) *MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call) Return() *MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call { + _c.Call.Return() + return _c +} + +func (_c *MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call) RunAndReturn(run func()) *MockRaftNodeServiceServer_mustEmbedUnimplementedRaftNodeServiceServer_Call { + _c.Run(run) + return _c +} + +// NewMockRaftNodeServiceServer creates a new instance of MockRaftNodeServiceServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockRaftNodeServiceServer(t interface { + mock.TestingT + Cleanup(func()) +}) *MockRaftNodeServiceServer { + mock := &MockRaftNodeServiceServer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockscheduler/mock_job_store.go b/pkg/test/mocks/mockscheduler/mock_job_store.go new file mode 100644 index 0000000000..eeef01479d --- /dev/null +++ b/pkg/test/mocks/mockscheduler/mock_job_store.go @@ -0,0 +1,378 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockscheduler + +import ( + raft_log "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1/raft_log" + iter "github.com/grafana/pyroscope/v2/pkg/iter" + mock "github.com/stretchr/testify/mock" + bbolt "go.etcd.io/bbolt" +) + +// MockJobStore is an autogenerated mock type for the JobStore type +type MockJobStore struct { + mock.Mock +} + +type MockJobStore_Expecter struct { + mock *mock.Mock +} + +func (_m *MockJobStore) EXPECT() *MockJobStore_Expecter { + return &MockJobStore_Expecter{mock: &_m.Mock} +} + +// CreateBuckets provides a mock function with given fields: _a0 +func (_m *MockJobStore) CreateBuckets(_a0 *bbolt.Tx) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for CreateBuckets") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockJobStore_CreateBuckets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateBuckets' +type MockJobStore_CreateBuckets_Call struct { + *mock.Call +} + +// CreateBuckets is a helper method to define mock.On call +// - _a0 *bbolt.Tx +func (_e *MockJobStore_Expecter) CreateBuckets(_a0 interface{}) *MockJobStore_CreateBuckets_Call { + return &MockJobStore_CreateBuckets_Call{Call: _e.mock.On("CreateBuckets", _a0)} +} + +func (_c *MockJobStore_CreateBuckets_Call) Run(run func(_a0 *bbolt.Tx)) *MockJobStore_CreateBuckets_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx)) + }) + return _c +} + +func (_c *MockJobStore_CreateBuckets_Call) Return(_a0 error) *MockJobStore_CreateBuckets_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobStore_CreateBuckets_Call) RunAndReturn(run func(*bbolt.Tx) error) *MockJobStore_CreateBuckets_Call { + _c.Call.Return(run) + return _c +} + +// DeleteJobPlan provides a mock function with given fields: tx, name +func (_m *MockJobStore) DeleteJobPlan(tx *bbolt.Tx, name string) error { + ret := _m.Called(tx, name) + + if len(ret) == 0 { + panic("no return value specified for DeleteJobPlan") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, string) error); ok { + r0 = rf(tx, name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockJobStore_DeleteJobPlan_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteJobPlan' +type MockJobStore_DeleteJobPlan_Call struct { + *mock.Call +} + +// DeleteJobPlan is a helper method to define mock.On call +// - tx *bbolt.Tx +// - name string +func (_e *MockJobStore_Expecter) DeleteJobPlan(tx interface{}, name interface{}) *MockJobStore_DeleteJobPlan_Call { + return &MockJobStore_DeleteJobPlan_Call{Call: _e.mock.On("DeleteJobPlan", tx, name)} +} + +func (_c *MockJobStore_DeleteJobPlan_Call) Run(run func(tx *bbolt.Tx, name string)) *MockJobStore_DeleteJobPlan_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(string)) + }) + return _c +} + +func (_c *MockJobStore_DeleteJobPlan_Call) Return(_a0 error) *MockJobStore_DeleteJobPlan_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobStore_DeleteJobPlan_Call) RunAndReturn(run func(*bbolt.Tx, string) error) *MockJobStore_DeleteJobPlan_Call { + _c.Call.Return(run) + return _c +} + +// DeleteJobState provides a mock function with given fields: tx, name +func (_m *MockJobStore) DeleteJobState(tx *bbolt.Tx, name string) error { + ret := _m.Called(tx, name) + + if len(ret) == 0 { + panic("no return value specified for DeleteJobState") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, string) error); ok { + r0 = rf(tx, name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockJobStore_DeleteJobState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteJobState' +type MockJobStore_DeleteJobState_Call struct { + *mock.Call +} + +// DeleteJobState is a helper method to define mock.On call +// - tx *bbolt.Tx +// - name string +func (_e *MockJobStore_Expecter) DeleteJobState(tx interface{}, name interface{}) *MockJobStore_DeleteJobState_Call { + return &MockJobStore_DeleteJobState_Call{Call: _e.mock.On("DeleteJobState", tx, name)} +} + +func (_c *MockJobStore_DeleteJobState_Call) Run(run func(tx *bbolt.Tx, name string)) *MockJobStore_DeleteJobState_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(string)) + }) + return _c +} + +func (_c *MockJobStore_DeleteJobState_Call) Return(_a0 error) *MockJobStore_DeleteJobState_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobStore_DeleteJobState_Call) RunAndReturn(run func(*bbolt.Tx, string) error) *MockJobStore_DeleteJobState_Call { + _c.Call.Return(run) + return _c +} + +// GetJobPlan provides a mock function with given fields: tx, name +func (_m *MockJobStore) GetJobPlan(tx *bbolt.Tx, name string) (*raft_log.CompactionJobPlan, error) { + ret := _m.Called(tx, name) + + if len(ret) == 0 { + panic("no return value specified for GetJobPlan") + } + + var r0 *raft_log.CompactionJobPlan + var r1 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, string) (*raft_log.CompactionJobPlan, error)); ok { + return rf(tx, name) + } + if rf, ok := ret.Get(0).(func(*bbolt.Tx, string) *raft_log.CompactionJobPlan); ok { + r0 = rf(tx, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*raft_log.CompactionJobPlan) + } + } + + if rf, ok := ret.Get(1).(func(*bbolt.Tx, string) error); ok { + r1 = rf(tx, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockJobStore_GetJobPlan_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJobPlan' +type MockJobStore_GetJobPlan_Call struct { + *mock.Call +} + +// GetJobPlan is a helper method to define mock.On call +// - tx *bbolt.Tx +// - name string +func (_e *MockJobStore_Expecter) GetJobPlan(tx interface{}, name interface{}) *MockJobStore_GetJobPlan_Call { + return &MockJobStore_GetJobPlan_Call{Call: _e.mock.On("GetJobPlan", tx, name)} +} + +func (_c *MockJobStore_GetJobPlan_Call) Run(run func(tx *bbolt.Tx, name string)) *MockJobStore_GetJobPlan_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(string)) + }) + return _c +} + +func (_c *MockJobStore_GetJobPlan_Call) Return(_a0 *raft_log.CompactionJobPlan, _a1 error) *MockJobStore_GetJobPlan_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockJobStore_GetJobPlan_Call) RunAndReturn(run func(*bbolt.Tx, string) (*raft_log.CompactionJobPlan, error)) *MockJobStore_GetJobPlan_Call { + _c.Call.Return(run) + return _c +} + +// ListEntries provides a mock function with given fields: _a0 +func (_m *MockJobStore) ListEntries(_a0 *bbolt.Tx) iter.Iterator[*raft_log.CompactionJobState] { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for ListEntries") + } + + var r0 iter.Iterator[*raft_log.CompactionJobState] + if rf, ok := ret.Get(0).(func(*bbolt.Tx) iter.Iterator[*raft_log.CompactionJobState]); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(iter.Iterator[*raft_log.CompactionJobState]) + } + } + + return r0 +} + +// MockJobStore_ListEntries_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListEntries' +type MockJobStore_ListEntries_Call struct { + *mock.Call +} + +// ListEntries is a helper method to define mock.On call +// - _a0 *bbolt.Tx +func (_e *MockJobStore_Expecter) ListEntries(_a0 interface{}) *MockJobStore_ListEntries_Call { + return &MockJobStore_ListEntries_Call{Call: _e.mock.On("ListEntries", _a0)} +} + +func (_c *MockJobStore_ListEntries_Call) Run(run func(_a0 *bbolt.Tx)) *MockJobStore_ListEntries_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx)) + }) + return _c +} + +func (_c *MockJobStore_ListEntries_Call) Return(_a0 iter.Iterator[*raft_log.CompactionJobState]) *MockJobStore_ListEntries_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobStore_ListEntries_Call) RunAndReturn(run func(*bbolt.Tx) iter.Iterator[*raft_log.CompactionJobState]) *MockJobStore_ListEntries_Call { + _c.Call.Return(run) + return _c +} + +// StoreJobPlan provides a mock function with given fields: _a0, _a1 +func (_m *MockJobStore) StoreJobPlan(_a0 *bbolt.Tx, _a1 *raft_log.CompactionJobPlan) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for StoreJobPlan") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, *raft_log.CompactionJobPlan) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockJobStore_StoreJobPlan_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StoreJobPlan' +type MockJobStore_StoreJobPlan_Call struct { + *mock.Call +} + +// StoreJobPlan is a helper method to define mock.On call +// - _a0 *bbolt.Tx +// - _a1 *raft_log.CompactionJobPlan +func (_e *MockJobStore_Expecter) StoreJobPlan(_a0 interface{}, _a1 interface{}) *MockJobStore_StoreJobPlan_Call { + return &MockJobStore_StoreJobPlan_Call{Call: _e.mock.On("StoreJobPlan", _a0, _a1)} +} + +func (_c *MockJobStore_StoreJobPlan_Call) Run(run func(_a0 *bbolt.Tx, _a1 *raft_log.CompactionJobPlan)) *MockJobStore_StoreJobPlan_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(*raft_log.CompactionJobPlan)) + }) + return _c +} + +func (_c *MockJobStore_StoreJobPlan_Call) Return(_a0 error) *MockJobStore_StoreJobPlan_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobStore_StoreJobPlan_Call) RunAndReturn(run func(*bbolt.Tx, *raft_log.CompactionJobPlan) error) *MockJobStore_StoreJobPlan_Call { + _c.Call.Return(run) + return _c +} + +// StoreJobState provides a mock function with given fields: _a0, _a1 +func (_m *MockJobStore) StoreJobState(_a0 *bbolt.Tx, _a1 *raft_log.CompactionJobState) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for StoreJobState") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*bbolt.Tx, *raft_log.CompactionJobState) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockJobStore_StoreJobState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StoreJobState' +type MockJobStore_StoreJobState_Call struct { + *mock.Call +} + +// StoreJobState is a helper method to define mock.On call +// - _a0 *bbolt.Tx +// - _a1 *raft_log.CompactionJobState +func (_e *MockJobStore_Expecter) StoreJobState(_a0 interface{}, _a1 interface{}) *MockJobStore_StoreJobState_Call { + return &MockJobStore_StoreJobState_Call{Call: _e.mock.On("StoreJobState", _a0, _a1)} +} + +func (_c *MockJobStore_StoreJobState_Call) Run(run func(_a0 *bbolt.Tx, _a1 *raft_log.CompactionJobState)) *MockJobStore_StoreJobState_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bbolt.Tx), args[1].(*raft_log.CompactionJobState)) + }) + return _c +} + +func (_c *MockJobStore_StoreJobState_Call) Return(_a0 error) *MockJobStore_StoreJobState_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockJobStore_StoreJobState_Call) RunAndReturn(run func(*bbolt.Tx, *raft_log.CompactionJobState) error) *MockJobStore_StoreJobState_Call { + _c.Call.Return(run) + return _c +} + +// NewMockJobStore creates a new instance of MockJobStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockJobStore(t interface { + mock.TestingT + Cleanup(func()) +}) *MockJobStore { + mock := &MockJobStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mocksymbolizer/mock_debuginfod_client.go b/pkg/test/mocks/mocksymbolizer/mock_debuginfod_client.go new file mode 100644 index 0000000000..5a4491c45c --- /dev/null +++ b/pkg/test/mocks/mocksymbolizer/mock_debuginfod_client.go @@ -0,0 +1,96 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocksymbolizer + +import ( + context "context" + io "io" + + mock "github.com/stretchr/testify/mock" +) + +// MockDebuginfodClient is an autogenerated mock type for the DebuginfodClient type +type MockDebuginfodClient struct { + mock.Mock +} + +type MockDebuginfodClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockDebuginfodClient) EXPECT() *MockDebuginfodClient_Expecter { + return &MockDebuginfodClient_Expecter{mock: &_m.Mock} +} + +// FetchDebuginfo provides a mock function with given fields: ctx, buildID +func (_m *MockDebuginfodClient) FetchDebuginfo(ctx context.Context, buildID string) (io.ReadCloser, error) { + ret := _m.Called(ctx, buildID) + + if len(ret) == 0 { + panic("no return value specified for FetchDebuginfo") + } + + var r0 io.ReadCloser + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (io.ReadCloser, error)); ok { + return rf(ctx, buildID) + } + if rf, ok := ret.Get(0).(func(context.Context, string) io.ReadCloser); ok { + r0 = rf(ctx, buildID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(io.ReadCloser) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, buildID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockDebuginfodClient_FetchDebuginfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FetchDebuginfo' +type MockDebuginfodClient_FetchDebuginfo_Call struct { + *mock.Call +} + +// FetchDebuginfo is a helper method to define mock.On call +// - ctx context.Context +// - buildID string +func (_e *MockDebuginfodClient_Expecter) FetchDebuginfo(ctx interface{}, buildID interface{}) *MockDebuginfodClient_FetchDebuginfo_Call { + return &MockDebuginfodClient_FetchDebuginfo_Call{Call: _e.mock.On("FetchDebuginfo", ctx, buildID)} +} + +func (_c *MockDebuginfodClient_FetchDebuginfo_Call) Run(run func(ctx context.Context, buildID string)) *MockDebuginfodClient_FetchDebuginfo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockDebuginfodClient_FetchDebuginfo_Call) Return(_a0 io.ReadCloser, _a1 error) *MockDebuginfodClient_FetchDebuginfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockDebuginfodClient_FetchDebuginfo_Call) RunAndReturn(run func(context.Context, string) (io.ReadCloser, error)) *MockDebuginfodClient_FetchDebuginfo_Call { + _c.Call.Return(run) + return _c +} + +// NewMockDebuginfodClient creates a new instance of MockDebuginfodClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockDebuginfodClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockDebuginfodClient { + mock := &MockDebuginfodClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockwritepath/mock_ingester_client.go b/pkg/test/mocks/mockwritepath/mock_ingester_client.go new file mode 100644 index 0000000000..ea2466f26d --- /dev/null +++ b/pkg/test/mocks/mockwritepath/mock_ingester_client.go @@ -0,0 +1,98 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockwritepath + +import ( + context "context" + + connect "connectrpc.com/connect" + pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1" + model "github.com/grafana/pyroscope/v2/pkg/distributor/model" + mock "github.com/stretchr/testify/mock" +) + +// MockIngesterClient is an autogenerated mock type for the IngesterClient type +type MockIngesterClient struct { + mock.Mock +} + +type MockIngesterClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockIngesterClient) EXPECT() *MockIngesterClient_Expecter { + return &MockIngesterClient_Expecter{mock: &_m.Mock} +} + +// Push provides a mock function with given fields: _a0, _a1 +func (_m *MockIngesterClient) Push(_a0 context.Context, _a1 *model.ProfileSeries) (*connect.Response[pushv1.PushResponse], error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Push") + } + + var r0 *connect.Response[pushv1.PushResponse] + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *model.ProfileSeries) (*connect.Response[pushv1.PushResponse], error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *model.ProfileSeries) *connect.Response[pushv1.PushResponse]); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.Response[pushv1.PushResponse]) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *model.ProfileSeries) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockIngesterClient_Push_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Push' +type MockIngesterClient_Push_Call struct { + *mock.Call +} + +// Push is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *model.ProfileSeries +func (_e *MockIngesterClient_Expecter) Push(_a0 interface{}, _a1 interface{}) *MockIngesterClient_Push_Call { + return &MockIngesterClient_Push_Call{Call: _e.mock.On("Push", _a0, _a1)} +} + +func (_c *MockIngesterClient_Push_Call) Run(run func(_a0 context.Context, _a1 *model.ProfileSeries)) *MockIngesterClient_Push_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*model.ProfileSeries)) + }) + return _c +} + +func (_c *MockIngesterClient_Push_Call) Return(_a0 *connect.Response[pushv1.PushResponse], _a1 error) *MockIngesterClient_Push_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockIngesterClient_Push_Call) RunAndReturn(run func(context.Context, *model.ProfileSeries) (*connect.Response[pushv1.PushResponse], error)) *MockIngesterClient_Push_Call { + _c.Call.Return(run) + return _c +} + +// NewMockIngesterClient creates a new instance of MockIngesterClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockIngesterClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockIngesterClient { + mock := &MockIngesterClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/mocks/mockwritepath/mock_segment_writer_client.go b/pkg/test/mocks/mockwritepath/mock_segment_writer_client.go new file mode 100644 index 0000000000..49b95483ad --- /dev/null +++ b/pkg/test/mocks/mockwritepath/mock_segment_writer_client.go @@ -0,0 +1,96 @@ +// Code generated by mockery. DO NOT EDIT. + +package mockwritepath + +import ( + context "context" + + segmentwriterv1 "github.com/grafana/pyroscope/api/gen/proto/go/segmentwriter/v1" + mock "github.com/stretchr/testify/mock" +) + +// MockSegmentWriterClient is an autogenerated mock type for the SegmentWriterClient type +type MockSegmentWriterClient struct { + mock.Mock +} + +type MockSegmentWriterClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockSegmentWriterClient) EXPECT() *MockSegmentWriterClient_Expecter { + return &MockSegmentWriterClient_Expecter{mock: &_m.Mock} +} + +// Push provides a mock function with given fields: _a0, _a1 +func (_m *MockSegmentWriterClient) Push(_a0 context.Context, _a1 *segmentwriterv1.PushRequest) (*segmentwriterv1.PushResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Push") + } + + var r0 *segmentwriterv1.PushResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *segmentwriterv1.PushRequest) (*segmentwriterv1.PushResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *segmentwriterv1.PushRequest) *segmentwriterv1.PushResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*segmentwriterv1.PushResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *segmentwriterv1.PushRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockSegmentWriterClient_Push_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Push' +type MockSegmentWriterClient_Push_Call struct { + *mock.Call +} + +// Push is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *segmentwriterv1.PushRequest +func (_e *MockSegmentWriterClient_Expecter) Push(_a0 interface{}, _a1 interface{}) *MockSegmentWriterClient_Push_Call { + return &MockSegmentWriterClient_Push_Call{Call: _e.mock.On("Push", _a0, _a1)} +} + +func (_c *MockSegmentWriterClient_Push_Call) Run(run func(_a0 context.Context, _a1 *segmentwriterv1.PushRequest)) *MockSegmentWriterClient_Push_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*segmentwriterv1.PushRequest)) + }) + return _c +} + +func (_c *MockSegmentWriterClient_Push_Call) Return(_a0 *segmentwriterv1.PushResponse, _a1 error) *MockSegmentWriterClient_Push_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockSegmentWriterClient_Push_Call) RunAndReturn(run func(context.Context, *segmentwriterv1.PushRequest) (*segmentwriterv1.PushResponse, error)) *MockSegmentWriterClient_Push_Call { + _c.Call.Return(run) + return _c +} + +// NewMockSegmentWriterClient creates a new instance of MockSegmentWriterClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockSegmentWriterClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockSegmentWriterClient { + mock := &MockSegmentWriterClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/test/time.go b/pkg/test/time.go new file mode 100644 index 0000000000..f7103a4372 --- /dev/null +++ b/pkg/test/time.go @@ -0,0 +1,29 @@ +package test + +import ( + "crypto/rand" + "time" + + "github.com/oklog/ulid/v2" + "github.com/prometheus/common/model" +) + +func ULID(t string) string { + parsed, _ := time.Parse(time.RFC3339, t) + l := ulid.MustNew(ulid.Timestamp(parsed), rand.Reader) + return l.String() +} + +func UnixMilli(t string) int64 { + return Time(t).UnixMilli() +} + +func Time(t string) time.Time { + x, _ := time.Parse(time.RFC3339, t) + return x +} + +func Duration(d string) time.Duration { + parsed, _ := model.ParseDuration(d) + return time.Duration(parsed) +} diff --git a/pkg/testhelper/ring.go b/pkg/testhelper/ring.go index 00a57e8ffa..210040357e 100644 --- a/pkg/testhelper/ring.go +++ b/pkg/testhelper/ring.go @@ -11,7 +11,7 @@ type MockRing struct { replicationFactor uint32 } -func NewMockRing(ingesters []ring.InstanceDesc, replicationFactor uint32) ring.ReadRing { +func NewMockRing(ingesters []ring.InstanceDesc, replicationFactor uint32) MockRing { return MockRing{ ingesters: ingesters, replicationFactor: replicationFactor, @@ -31,6 +31,10 @@ func (r MockRing) Get(key uint32, op ring.Operation, buf []ring.InstanceDesc, _ return result, nil } +func (r MockRing) GetWithOptions(key uint32, op ring.Operation, opts ...ring.Option) (ring.ReplicationSet, error) { + return r.Get(key, op, nil, nil, nil) +} + func (r MockRing) GetAllHealthy(op ring.Operation) (ring.ReplicationSet, error) { return r.GetReplicationSetForOperation(op) } @@ -42,6 +46,10 @@ func (r MockRing) GetReplicationSetForOperation(op ring.Operation) (ring.Replica }, nil } +func (r MockRing) GetSubringForOperationStates(op ring.Operation) ring.ReadRing { + return r +} + func (r MockRing) ReplicationFactor() int { return int(r.replicationFactor) } @@ -50,6 +58,10 @@ func (r MockRing) InstancesCount() int { return len(r.ingesters) } +func (r MockRing) InstancesWithTokensCount() int { + return len(r.ingesters) +} + func (r MockRing) Subring(key uint32, n int) ring.ReadRing { return r } @@ -92,3 +104,31 @@ func (r MockRing) GetInstanceState(instanceID string) (ring.InstanceState, error func (r MockRing) GetTokenRangesForInstance(instanceID string) (ring.TokenRanges, error) { return nil, nil } + +func (r MockRing) InstancesInZoneCount(zone string) int { + return len(r.ingesters) +} + +func (r MockRing) InstancesWithTokensInZoneCount(zone string) int { + return len(r.ingesters) +} + +func (r MockRing) WritableInstancesWithTokensCount() int { + return len(r.ingesters) +} + +func (r MockRing) WritableInstancesWithTokensInZoneCount(zone string) int { + return len(r.ingesters) +} + +func (r MockRing) Zones() []string { + return nil +} + +func (r MockRing) ZonesCount() int { + return 1 +} + +func (r *MockRing) SetInstances(instances []ring.InstanceDesc) { + r.ingesters = instances +} diff --git a/pkg/usage/usage.go b/pkg/usage/usage.go index 2d2f883ffb..76adca848b 100644 --- a/pkg/usage/usage.go +++ b/pkg/usage/usage.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/dskit/flagext" - "github.com/grafana/pyroscope/pkg/util/fieldcategory" + "github.com/grafana/pyroscope/v2/pkg/util/fieldcategory" ) // Usage prints command-line usage. @@ -42,12 +42,11 @@ func Usage(printAll bool, configs ...interface{}) error { return } - if override, ok := fieldcategory.GetOverride(fl.Name); ok { - fieldCat = override - } else if v.Kind() == reflect.Ptr { + if v.Kind() == reflect.Ptr { ptr := v.Pointer() - field, ok = fields[ptr] - if ok { + var found bool + field, found = fields[ptr] + if found { catStr := field.Tag.Get("category") switch catStr { case "advanced": @@ -57,6 +56,10 @@ func Usage(printAll bool, configs ...interface{}) error { } } } + // Category overrides take precedence over struct field tags. + if override, ok := fieldcategory.GetOverride(fl.Name); ok { + fieldCat = override + } if fieldCat != fieldcategory.Basic && !printAll { // Don't print help for this flag since we're supposed to print only basic flags diff --git a/pkg/usagestats/reporter.go b/pkg/usagestats/reporter.go index ebfa4e753c..5fc01fe71d 100644 --- a/pkg/usagestats/reporter.go +++ b/pkg/usagestats/reporter.go @@ -19,7 +19,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/thanos-io/objstore" - "github.com/grafana/pyroscope/pkg/util/build" + "github.com/grafana/pyroscope/v2/pkg/util/build" ) const ( @@ -46,7 +46,7 @@ type Config struct { // RegisterFlags adds the flags required to config this to the given FlagSet func (cfg *Config) RegisterFlags(f *flag.FlagSet) { - f.BoolVar(&cfg.Enabled, "usage-stats.enabled", true, "Enable anonymous usage reporting.") + f.BoolVar(&cfg.Enabled, "usage-stats.enabled", true, "Enable anonymous usage statistics collection. For more details about usage statistics, refer to https://grafana.com/docs/pyroscope/latest/configure-server/anonymous-usage-statistics-reporting/") } type Reporter struct { diff --git a/pkg/usagestats/reporter_test.go b/pkg/usagestats/reporter_test.go index a509aa60c3..f86d01dadb 100644 --- a/pkg/usagestats/reporter_test.go +++ b/pkg/usagestats/reporter_test.go @@ -2,6 +2,7 @@ package usagestats import ( "context" + "encoding/json" "net/http" "net/http/httptest" "os" @@ -10,12 +11,11 @@ import ( "github.com/go-kit/log" "github.com/grafana/dskit/kv" - jsoniter "github.com/json-iterator/go" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" ) func Test_LeaderElection(t *testing.T) { @@ -81,7 +81,7 @@ func Test_ReportLoop(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { var received Report totalReport++ - require.NoError(t, jsoniter.NewDecoder(r.Body).Decode(&received)) + require.NoError(t, json.NewDecoder(r.Body).Decode(&received)) clusterIDs = append(clusterIDs, received.ClusterID) rw.WriteHeader(http.StatusOK) })) diff --git a/pkg/usagestats/seed.go b/pkg/usagestats/seed.go index 1a98569504..5d2523e069 100644 --- a/pkg/usagestats/seed.go +++ b/pkg/usagestats/seed.go @@ -1,10 +1,10 @@ package usagestats import ( + "encoding/json" "fmt" "time" - jsoniter "github.com/json-iterator/go" prom "github.com/prometheus/prometheus/web/api/v1" "github.com/grafana/dskit/kv/memberlist" @@ -35,7 +35,7 @@ func (c *ClusterSeed) Merge(mergeable memberlist.Mergeable, localCAS bool) (chan if c.CreatedAt.Before(other.CreatedAt) { return nil, nil } - if c.CreatedAt == other.CreatedAt { + if c.CreatedAt.Equal(other.CreatedAt) { // if we have the exact same creation date but the key is different // we take the smallest UID using string alphabetical comparison to ensure stability. if c.UID > other.UID { @@ -72,13 +72,17 @@ type jsonCodec struct{} // currently crashing because the in-memory kvstore use a singleton. func (jsonCodec) Decode(data []byte) (interface{}, error) { var seed ClusterSeed - if err := jsoniter.ConfigFastest.Unmarshal(data, &seed); err != nil { + err := json.Unmarshal(data, &seed) + if err != nil { return nil, err } return &seed, nil } func (jsonCodec) Encode(obj interface{}) ([]byte, error) { - return jsoniter.ConfigFastest.Marshal(obj) + return json.Marshal(obj) +} + +func (jsonCodec) CodecID() string { + return "usagestats.jsonCodec" } -func (jsonCodec) CodecID() string { return "usagestats.jsonCodec" } diff --git a/pkg/usagestats/seed_test.go b/pkg/usagestats/seed_test.go index b6ebd6f321..6f8c251324 100644 --- a/pkg/usagestats/seed_test.go +++ b/pkg/usagestats/seed_test.go @@ -15,8 +15,8 @@ import ( "github.com/grafana/dskit/services" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/objstore/client" - "github.com/grafana/pyroscope/pkg/objstore/providers/filesystem" + "github.com/grafana/pyroscope/v2/pkg/objstore/client" + "github.com/grafana/pyroscope/v2/pkg/objstore/providers/filesystem" ) type dnsProviderMock struct { @@ -37,8 +37,10 @@ func createMemberlist(t *testing.T, port, memberID int) *memberlist.KV { var cfg memberlist.KVConfig flagext.DefaultValues(&cfg) cfg.TCPTransport = memberlist.TCPTransportConfig{ - BindAddrs: []string{"127.0.0.1"}, - BindPort: 0, + BindAddrs: []string{"127.0.0.1"}, + BindPort: 0, + MaxConcurrentWrites: 3, + AcquireWriterTimeout: 250 * time.Millisecond, } cfg.GossipInterval = 100 * time.Millisecond cfg.GossipNodes = 3 diff --git a/pkg/usagestats/stats.go b/pkg/usagestats/stats.go index b2180b9177..68b1ae9b06 100644 --- a/pkg/usagestats/stats.go +++ b/pkg/usagestats/stats.go @@ -14,10 +14,9 @@ import ( "sync" "time" - "github.com/grafana/pyroscope/pkg/util/build" + "github.com/grafana/pyroscope/v2/pkg/util/build" "github.com/cespare/xxhash/v2" - jsoniter "github.com/json-iterator/go" prom "github.com/prometheus/prometheus/web/api/v1" "go.uber.org/atomic" ) @@ -25,7 +24,7 @@ import ( var ( httpClient = http.Client{Timeout: 5 * time.Second} usageStatsURL = "https://stats.grafana.org/phlare-usage-report" - statsPrefix = "github.com/grafana/pyroscope/" + statsPrefix = "github.com/grafana/pyroscope/v2/" targetKey = "target" editionKey = "edition" @@ -49,7 +48,7 @@ type Report struct { // sendReport sends the report to the stats server func sendReport(ctx context.Context, seed ClusterSeed, interval time.Time) error { report := buildReport(seed, interval) - out, err := jsoniter.MarshalIndent(report, "", " ") + out, err := json.MarshalIndent(report, "", " ") if err != nil { return err } @@ -419,9 +418,8 @@ func (s *MultiStatistics) Value() map[string]interface{} { } func (s *MultiStatistics) Record(v float64, key string) { - keyStats := s.getOrCreateStatistics(key) - keyStats.Record(v) - s.values["__total__"].Record(v) + s.getOrCreateStatistics(key).Record(v) + s.getOrCreateStatistics("__total__").Record(v) } func (s *MultiStatistics) getOrCreateStatistics(key string) *Statistics { @@ -589,9 +587,8 @@ func (c *MultiCounter) reset() { } func (c *MultiCounter) Inc(i int64, keyValue string) { - v := c.getOrCreateCounter(keyValue) - v.Inc(i) - c.values["__total__"].Inc(i) + c.getOrCreateCounter(keyValue).Inc(i) + c.getOrCreateCounter("__total__").Inc(i) } func (c *MultiCounter) getOrCreateCounter(keyValue string) *Counter { diff --git a/pkg/usagestats/stats_test.go b/pkg/usagestats/stats_test.go index e0101d704e..355fa789f4 100644 --- a/pkg/usagestats/stats_test.go +++ b/pkg/usagestats/stats_test.go @@ -1,16 +1,17 @@ package usagestats import ( + "encoding/json" + "fmt" "runtime" "sync" "testing" "time" "github.com/google/uuid" - jsoniter "github.com/json-iterator/go" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/util/build" + "github.com/grafana/pyroscope/v2/pkg/util/build" ) func Test_BuildReport(t *testing.T) { @@ -61,7 +62,7 @@ func Test_BuildReport(t *testing.T) { require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["avg"], float64(25+300+5)/3) require.Equal(t, r.Metrics["active_tenants"], int64(3)) - out, _ := jsoniter.MarshalIndent(r, "", " ") + out, _ := json.MarshalIndent(r, "", " ") t.Log(string(out)) } @@ -126,11 +127,12 @@ func TestMultiCounter(t *testing.T) { for _, entry := range drilldown { entryMap := entry.(map[string]interface{}) data := entryMap["data"].(map[string]interface{}) - if entryMap["key_name"] == "key_value_a" { + switch entryMap["key_name"] { + case "key_value_a": require.Equal(t, int64(400), data["total"]) - } else if entryMap["key_name"] == "key_value_b" { + case "key_value_b": require.Equal(t, int64(200), data["total"]) - } else { + default: t.FailNow() } } @@ -158,21 +160,22 @@ func TestMultiStatistic(t *testing.T) { for _, entry := range drilldown { entryMap := entry.(map[string]interface{}) data := entryMap["data"].(map[string]interface{}) - if entryMap["key_name"] == "key_value_a" { + switch entryMap["key_name"] { + case "key_value_a": require.Equal(t, float64(100), data["min"]) require.Equal(t, float64(300), data["max"]) require.Equal(t, int64(2), data["count"]) require.Equal(t, float64(200), data["avg"]) require.Equal(t, float64(100), data["stddev"]) require.Equal(t, float64(10000), data["stdvar"]) - } else if entryMap["key_name"] == "key_value_b" { + case "key_value_b": require.Equal(t, float64(200), data["min"]) require.Equal(t, float64(200), data["max"]) require.Equal(t, int64(1), data["count"]) require.Equal(t, float64(200), data["avg"]) require.Equal(t, float64(0), data["stddev"]) require.Equal(t, float64(0), data["stdvar"]) - } else { + default: t.FailNow() } } @@ -219,3 +222,22 @@ func TestPanics(t *testing.T) { Edition("new edition") }) } + +func TestMultiCounter_ConcurrentInc(t *testing.T) { + // Concurrent Inc with distinct keys overlaps map inserts with the + // "__total__" access; run with -race to guard the counter's thread-safety. + mc := NewMultiCounter("test_multi_counter_concurrent", "key_name") + + const goroutines = 8 + var wg sync.WaitGroup + wg.Add(goroutines) + for g := 0; g < goroutines; g++ { + go func(g int) { + defer wg.Done() + mc.Inc(1, fmt.Sprintf("key_%d", g)) + }(g) + } + wg.Wait() + + require.Equal(t, int64(goroutines), mc.Value()["total"]) +} diff --git a/pkg/util/body/limit.go b/pkg/util/body/limit.go new file mode 100644 index 0000000000..7f349f075e --- /dev/null +++ b/pkg/util/body/limit.go @@ -0,0 +1,35 @@ +package body + +import ( + "context" + "net/http" + + "github.com/grafana/dskit/tenant" +) + +type Limits interface { + IngestionBodyLimitBytes(tenantID string) int64 +} + +func getMaxBodySize(ctx context.Context, limits Limits) int64 { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return 0 + } + + return limits.IngestionBodyLimitBytes(tenantID) +} + +func NewSizeLimitHandler(limits Limits) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + maxBodySize := getMaxBodySize(r.Context(), limits) + + if maxBodySize > 0 { + r.Body = http.MaxBytesReader(w, r.Body, maxBodySize) + } + + h.ServeHTTP(w, r) + }) + } +} diff --git a/pkg/util/body/limit_test.go b/pkg/util/body/limit_test.go new file mode 100644 index 0000000000..582a4e13b3 --- /dev/null +++ b/pkg/util/body/limit_test.go @@ -0,0 +1,94 @@ +package body + +import ( + "errors" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/grafana/pyroscope/v2/pkg/tenant" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" +) + +// Test handler that records what happened +type testHandler struct { + called bool +} + +func (h *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.called = true + n, err := io.Copy(io.Discard, r.Body) + println(n) + var maxBytesError *http.MaxBytesError + if errors.As(err, &maxBytesError) { + httputil.ErrorWithStatus(w, err, http.StatusRequestEntityTooLarge) + return + } + + w.WriteHeader(http.StatusOK) +} + +func TestRequestBodyLimitMiddleware(t *testing.T) { + tenantID := "my-tenant" + anyByte := string('0') + tests := []struct { + name string + bodyLimit int64 + bodySize int + expectedError bool + }{ + { + name: "body size below limit", + bodyLimit: 10, + bodySize: 9, + expectedError: false, + }, + { + name: "body size matches limit", + bodyLimit: 10, + bodySize: 10, + expectedError: false, + }, + { + name: "body exceeds limit", + bodyLimit: 10, + bodySize: 11, + expectedError: true, + }, + { + name: "no limit set", + bodyLimit: 0, + bodySize: 11, + expectedError: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + limits := validation.MockLimits{ + IngestionBodyLimitBytesValue: tt.bodyLimit, + } + middleware := NewSizeLimitHandler(limits) + + var handler testHandler + req := httptest.NewRequest(http.MethodPost, "/test", strings.NewReader(strings.Repeat(anyByte, tt.bodySize))) + req = req.WithContext(tenant.InjectTenantID(req.Context(), tenantID)) + w := httptest.NewRecorder() + + middleware(&handler).ServeHTTP(w, req) + + // Verify handler was called + assert.True(t, handler.called) + + if tt.expectedError { + assert.Equal(t, http.StatusRequestEntityTooLarge, w.Code) + } else { + assert.Equal(t, http.StatusOK, w.Code) + } + }) + } +} diff --git a/pkg/util/bufferpool/pool.go b/pkg/util/bufferpool/pool.go new file mode 100644 index 0000000000..b4fa477460 --- /dev/null +++ b/pkg/util/bufferpool/pool.go @@ -0,0 +1,98 @@ +package bufferpool + +import ( + "bytes" + "io" + "sync" +) + +// Sized *bytes.Buffer pools: from 2^9 (512b) to 2^30 (1GB). +var pools [maxPool]sync.Pool + +type Buffer struct { + B []byte + p int64 +} + +const ( + minBits = 9 + maxPool = 22 +) + +// GetBuffer returns a buffer from the pool, or creates a new one. +// The returned buffer has at least the requested capacity. +func GetBuffer(size int) *Buffer { + i := poolIndex(size) + if i < 0 { + return &Buffer{B: make([]byte, 0, size)} + } + x := pools[i].Get() + if x != nil { + return x.(*Buffer) + } + c := 2 << (minBits + i - 1) + c += bytes.MinRead + return &Buffer{ + B: make([]byte, 0, c), + p: i, + } +} + +// Put places the buffer into the pool. +func Put(b *Buffer) { + if b == nil { + return + } + if p := returnPool(cap(b.B), b.p); p > 0 { + b.B = b.B[:0] + pools[p].Put(b) + } +} + +func returnPool(c int, p int64) int64 { + // Empty buffers are ignored. + if c == 0 { + return -1 + } + i := poolIndex(c) + if p == 0 { + // The buffer does not belong to any pool, or it's + // of the smallest size. We pick the pool based on + // its current capacity. + return i + } + d := i - p + if d < 0 { + // This buffer was likely obtained outside the pool. + // For example, an empty one, or with pre-allocated + // byte slice. + return i + } + if d > 1 { + // Relocate the buffer, if it's capacity has been + // grown by more than a power of two. + return i + } + // Otherwise, keep the buffer in the current pool. + return p +} + +func poolIndex(n int) (i int64) { + n-- + n >>= minBits + for n > 0 { + n >>= 1 + i++ + } + if i >= maxPool { + return -1 + } + return i +} + +func (b *Buffer) ReadFrom(r io.Reader) (int64, error) { + buf := bytes.NewBuffer(b.B) + n, err := buf.ReadFrom(r) + b.B = buf.Bytes() + return n, err +} diff --git a/pkg/util/bufferpool/pool_test.go b/pkg/util/bufferpool/pool_test.go new file mode 100644 index 0000000000..5097915208 --- /dev/null +++ b/pkg/util/bufferpool/pool_test.go @@ -0,0 +1,22 @@ +package bufferpool + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_returnPool(t *testing.T) { + assert.EqualValues(t, 0, returnPool(512, 0)) // Buffers can be added to the pool. + assert.EqualValues(t, 1, returnPool(513, 0)) + assert.EqualValues(t, 1, returnPool(1<<10, 0)) + assert.EqualValues(t, -1, returnPool(0, 0)) // Empty buffers are ignored. + assert.EqualValues(t, -1, returnPool(0, 10)) // + assert.EqualValues(t, 5, returnPool(1<<14, 0)) // New buffers are added to the appropriate pool. + assert.EqualValues(t, 5, returnPool(1<<14, 3)) // Buffer of a capacity exceeding the next power of two are relocated. + assert.EqualValues(t, 4, returnPool(1<<14, 4)) // Buffer of a capacity not exceeding the next power of two are retained. + assert.EqualValues(t, 5, returnPool(1<<14, 5)) // Buffer of the nominal capacity. + assert.EqualValues(t, 5, returnPool(1<<14, 6)) // Buffer of a smaller capacity must be relocated. + assert.EqualValues(t, 21, returnPool(1<<30, 13)) + assert.EqualValues(t, -1, returnPool(1<<30+1, 13)) // No pools for buffers larger than 4MB. +} diff --git a/pkg/util/circuitbreaker/cirquit_breaker.go b/pkg/util/circuitbreaker/cirquit_breaker.go new file mode 100644 index 0000000000..8c779a3348 --- /dev/null +++ b/pkg/util/circuitbreaker/cirquit_breaker.go @@ -0,0 +1,28 @@ +package circuitbreaker + +import ( + "context" + "errors" + "fmt" + + "github.com/sony/gobreaker/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func UnaryClientInterceptor(cb *gobreaker.CircuitBreaker[any]) grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + _, err := cb.Execute(func() (interface{}, error) { + return nil, invoker(ctx, method, req, reply, cc, opts...) + }) + switch { + case err == nil: + return nil + case errors.Is(err, gobreaker.ErrOpenState) || errors.Is(err, gobreaker.ErrTooManyRequests): + return status.Error(codes.Unavailable, fmt.Sprintf("circuit breaker: %s", err.Error())) + default: + return err + } + } +} diff --git a/pkg/util/cli/banner.go b/pkg/util/cli/banner.go index 571fba81f6..f7b697de1f 100644 --- a/pkg/util/cli/banner.go +++ b/pkg/util/cli/banner.go @@ -4,7 +4,6 @@ import ( "io" "strings" - "github.com/aybabtme/rgbterm" "github.com/fatih/color" ) @@ -29,7 +28,7 @@ func GradientBanner(banner string, w io.Writer) error { r := gradient(startColor, endColor, 16, progress) g := gradient(startColor, endColor, 8, progress) b := gradient(startColor, endColor, 0, progress) - _, err := w.Write([]byte(rgbterm.FgString(line, r, g, b) + "\n")) + _, err := color.RGB(r, g, b).Fprintln(w, line) if err != nil { return nil } @@ -37,8 +36,8 @@ func GradientBanner(banner string, w io.Writer) error { return nil } -func gradient(start, end, offset int, progress float64) uint8 { +func gradient(start, end, offset int, progress float64) int { start = (start >> offset) & 0xff end = (end >> offset) & 0xff - return uint8(start + int(float64(end-start)*progress)) + return start + int(float64(end-start)*progress) } diff --git a/pkg/util/config.go b/pkg/util/config.go index cbfb5a34d4..eaefd5173b 100644 --- a/pkg/util/config.go +++ b/pkg/util/config.go @@ -8,6 +8,7 @@ package util import ( "fmt" "reflect" + "time" ) func stringKeyMapToInterfaceKeyMap(m map[string]interface{}) map[interface{}]interface{} { @@ -60,6 +61,10 @@ func DiffConfig(defaultConfig, actualConfig map[interface{}]interface{}) (map[in if defaultValue != nil { output[key] = v } + case time.Time: + if defaultValue != nil && !v.IsZero() { + output[key] = v + } case map[interface{}]interface{}: defaultV, ok := defaultValue.(map[interface{}]interface{}) if !ok { diff --git a/pkg/util/connectgrpc/connectgrpc.go b/pkg/util/connectgrpc/connectgrpc.go index b0d333c9aa..8f88d48c16 100644 --- a/pkg/util/connectgrpc/connectgrpc.go +++ b/pkg/util/connectgrpc/connectgrpc.go @@ -13,8 +13,8 @@ import ( "connectrpc.com/connect" "google.golang.org/protobuf/proto" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) type UnaryHandler[Req any, Res any] func(context.Context, *connect.Request[Req]) (*connect.Response[Res], error) @@ -166,12 +166,30 @@ func removeContentHeaders(h http.Header) http.Header { return h } +// filterHeader filters headers, which would expose details about the implementation details of the connectgrpc implementation +func filterHeader(name string) bool { + if strings.ToLower(name) == "content-type" { + return true + } + if strings.ToLower(name) == "accept-encoding" { + return true + } + if strings.ToLower(name) == "content-encoding" { + return true + } + return false +} + func decodeResponse[Resp any](r *httpgrpc.HTTPResponse) (*connect.Response[Resp], error) { if err := decompressResponse(r); err != nil { return nil, err } resp := &connect.Response[Resp]{Msg: new(Resp)} for _, h := range r.Headers { + if filterHeader(h.Key) { + continue + } + for _, v := range h.Values { resp.Header().Add(h.Key, v) } diff --git a/pkg/util/connectgrpc/connectgrpc_test.go b/pkg/util/connectgrpc/connectgrpc_test.go index b8b71a0980..ef4b0543d5 100644 --- a/pkg/util/connectgrpc/connectgrpc_test.go +++ b/pkg/util/connectgrpc/connectgrpc_test.go @@ -1,6 +1,7 @@ package connectgrpc import ( + "bytes" "context" "net/http" "net/http/httptest" @@ -11,12 +12,11 @@ import ( "github.com/gorilla/mux" "github.com/samber/lo" "github.com/stretchr/testify/require" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + httpserver "github.com/grafana/pyroscope/v2/pkg/util/http/server" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) type fakeQuerier struct { @@ -40,11 +40,22 @@ func (m *mockRoundTripper) RoundTripGRPC(_ context.Context, req *httpgrpc.HTTPRe return m.resp, nil } +func headerToSlice(t testing.TB, header http.Header) []string { + buf := new(bytes.Buffer) + excludeHeaders := map[string]bool{"Content-Length": true, "Date": true} + require.NoError(t, header.WriteSubset(buf, excludeHeaders)) + sl := strings.Split(strings.ReplaceAll(buf.String(), "\r\n", "\n"), "\n") + if len(sl) > 0 && sl[len(sl)-1] == "" { + sl = sl[:len(sl)-1] + } + return sl +} + func Test_RoundTripUnary(t *testing.T) { request := func(t *testing.T) *connect.Request[typesv1.LabelValuesRequest] { - server := httptest.NewUnstartedServer(nil) mux := mux.NewRouter() - server.Config.Handler = h2c.NewHandler(mux, &http2.Server{}) + server := httptest.NewUnstartedServer(mux) + httpserver.EnableHTTP2(server.Config) server.Start() defer server.Close() @@ -64,8 +75,15 @@ func Test_RoundTripUnary(t *testing.T) { t.Run("HTTP request can trip GRPC", func(t *testing.T) { req := request(t) - m := &mockRoundTripper{resp: &httpgrpc.HTTPResponse{Code: 200}} - _, err := RoundTripUnary[typesv1.LabelValuesRequest, typesv1.LabelValuesResponse](context.Background(), m, req) + m := &mockRoundTripper{resp: &httpgrpc.HTTPResponse{ + Code: 200, + Headers: []*httpgrpc.Header{ + {Key: "Content-Type", Values: []string{"application/proto"}}, + {Key: "X-My-App", Values: []string{"foobar"}}, + }, + }} + + resp, err := RoundTripUnary[typesv1.LabelValuesRequest, typesv1.LabelValuesResponse](context.Background(), m, req) require.NoError(t, err) require.Equal(t, "POST", m.req.Method) require.Equal(t, "/querier.v1.QuerierService/LabelValues", m.req.Url) @@ -79,6 +97,10 @@ func Test_RoundTripUnary(t *testing.T) { decoded, err := decodeRequest[typesv1.LabelValuesRequest](m.req) require.NoError(t, err) require.Equal(t, req.Msg.Name, decoded.Msg.Name) + + // ensure no headers leak + require.Equal(t, []string{"X-My-App: foobar"}, headerToSlice(t, resp.Header())) + }) t.Run("HTTP request URL can be overridden", func(t *testing.T) { diff --git a/pkg/util/copy.go b/pkg/util/copy.go index 002a4c3d85..dda043cab3 100644 --- a/pkg/util/copy.go +++ b/pkg/util/copy.go @@ -32,7 +32,6 @@ package util import ( "fmt" "io" - "io/ioutil" "os" "path/filepath" ) @@ -108,7 +107,7 @@ func CopyDir(src string, dst string) (err error) { return } - entries, err := ioutil.ReadDir(src) + entries, err := os.ReadDir(src) if err != nil { return } @@ -124,7 +123,7 @@ func CopyDir(src string, dst string) (err error) { } } else { // Skip symlinks. - if entry.Mode()&os.ModeSymlink != 0 { + if entry.Type()&os.ModeSymlink != 0 { continue } diff --git a/pkg/util/delayhandler/connect.go b/pkg/util/delayhandler/connect.go new file mode 100644 index 0000000000..59549fe04e --- /dev/null +++ b/pkg/util/delayhandler/connect.go @@ -0,0 +1,74 @@ +package delayhandler + +import ( + "context" + + "connectrpc.com/connect" +) + +type delayInterceptor struct { + limits Limits +} + +func NewConnect(limits Limits) connect.Interceptor { + return &delayInterceptor{limits: limits} +} + +func (i *delayInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { + return func(ctx context.Context, req connect.AnyRequest) (resp connect.AnyResponse, err error) { + start := timeNow() + delay := getDelay(ctx, i.limits) + delayCtx := context.Background() + if delay > 0 { + var cancel context.CancelFunc + delayCtx, cancel = context.WithCancel(context.Background()) + defer cancel() + ctx = WithDelayCancel(ctx, cancel) + } + + // now run the chain after me + resp, err = next(ctx, req) + + // if there is an error, return it immediately + if err != nil { + return resp, err + } + + // The delay has been cancelled down the chain. + if delayCtx.Err() != nil { + return resp, err + } + + // no delay, return immediately + if delay <= 0 { + return resp, err + } + + delayLeft := delay - timeNow().Sub(start) + + // if the delay is already expired, return immediately + if delayLeft <= 0 { + return resp, err + } + + // add delay header + addDelayHeader(resp.Header(), delayLeft) + + // if the delay is not expired, sleep for the remaining time + <-timeAfter(delayLeft) + + return resp, nil + } +} + +// do nothing for streaming handlers +func (delayInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc { + return func(ctx context.Context, conn connect.StreamingHandlerConn) (err error) { + panic("delayInterceptor not implemented") + } +} + +// do nothing for streaming clients +func (delayInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc { + panic("delayInterceptor not implemented") +} diff --git a/pkg/util/delayhandler/connect_test.go b/pkg/util/delayhandler/connect_test.go new file mode 100644 index 0000000000..668462edf0 --- /dev/null +++ b/pkg/util/delayhandler/connect_test.go @@ -0,0 +1,89 @@ +package delayhandler + +import ( + "context" + "testing" + "time" + + "connectrpc.com/connect" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +func TestConnectInterceptor(t *testing.T) { + now := time.Unix(1718211600, 0) + tenantID := "tenant" + + tests := []struct { + name string + configDelay time.Duration + cancelDelay bool + expectSleep bool + expectHeader bool + }{ + { + name: "no delay", + configDelay: 0, + expectSleep: false, + expectHeader: false, + }, + { + name: "with delay", + configDelay: 100 * time.Millisecond, + expectSleep: true, + expectHeader: true, + }, + { + name: "cancelled delay", + configDelay: 100 * time.Millisecond, + cancelDelay: true, + expectSleep: false, + expectHeader: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + timeNowMock(t, []time.Time{now, now.Add(5 * time.Millisecond)}) + sleeps, cleanUpSleep := timeAfterMock() + defer cleanUpSleep() + + limits := newMockLimits() + limits.setDelay(tenantID, tt.configDelay) + + interceptor := NewConnect(limits) + + handler := connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { + if tt.cancelDelay { + CancelDelay(ctx) + } + return connect.NewResponse(&struct{}{}), nil + }) + + wrappedHandler := interceptor.WrapUnary(handler) + req := connect.NewRequest(&struct{}{}) + ctx := tenant.InjectTenantID(context.Background(), tenantID) + + resp, err := wrappedHandler(ctx, req) + + require.NoError(t, err) + require.NotNil(t, resp) + + if tt.expectSleep { + require.Len(t, sleeps.values, 1) + assert.Greater(t, sleeps.values[0], 80*time.Millisecond) + assert.Less(t, sleeps.values[0], 120*time.Millisecond) + } else { + require.Len(t, sleeps.values, 0) + } + + if tt.expectHeader { + assert.Contains(t, resp.Header().Get("Server-Timing"), "artificial_delay") + } else { + assert.Empty(t, resp.Header().Get("Server-Timing")) + } + }) + } +} diff --git a/pkg/util/delayhandler/delay.go b/pkg/util/delayhandler/delay.go new file mode 100644 index 0000000000..cdaa0fb333 --- /dev/null +++ b/pkg/util/delayhandler/delay.go @@ -0,0 +1,53 @@ +package delayhandler + +import ( + "context" + "fmt" + "net/http" + "strconv" + "time" + + "github.com/grafana/dskit/tenant" + + "github.com/grafana/pyroscope/v2/pkg/util" +) + +var ( + // have local variables to allow for mocking in tests + timeNow = time.Now + timeAfter = time.After +) + +type Limits interface { + IngestionArtificialDelay(tenantID string) time.Duration +} + +type delayCancelCtxKey struct{} + +func CancelDelay(ctx context.Context) { + if cancel, ok := ctx.Value(delayCancelCtxKey{}).(context.CancelFunc); ok && cancel != nil { + cancel() + } +} + +func WithDelayCancel(ctx context.Context, cancel context.CancelFunc) context.Context { + return context.WithValue(ctx, delayCancelCtxKey{}, cancel) +} + +func addDelayHeader(h http.Header, delay time.Duration) { + durationInMs := strconv.FormatFloat(float64(delay)/float64(time.Millisecond), 'f', -1, 64) + h.Add("Server-Timing", fmt.Sprintf("artificial_delay;dur=%s", durationInMs)) +} + +func getDelay(ctx context.Context, limits Limits) time.Duration { + tenantID, err := tenant.TenantID(ctx) + if err != nil { + return 0 + } + + delay := limits.IngestionArtificialDelay(tenantID) + if delay > 0 { + return util.DurationWithJitter(delay, 0.10) + } + return 0 +} diff --git a/pkg/util/delayhandler/http.go b/pkg/util/delayhandler/http.go new file mode 100644 index 0000000000..311be41cd7 --- /dev/null +++ b/pkg/util/delayhandler/http.go @@ -0,0 +1,127 @@ +package delayhandler + +import ( + "context" + "net/http" + "time" + + "github.com/grafana/dskit/tracing" +) + +func wrapResponseWriter(w http.ResponseWriter, end time.Time) (http.ResponseWriter, *delayedResponseWriter) { + wrapped := &delayedResponseWriter{wrapped: w, end: end} + + // check if the writer implements the Flusher interface + flusher, ok := w.(http.Flusher) + if ok { + return &delayedResponseWriterWithFlush{ + delayedResponseWriter: wrapped, + flusher: flusher, + }, wrapped + } + + return wrapped, wrapped +} + +type delayedResponseWriterWithFlush struct { + *delayedResponseWriter + flusher http.Flusher +} + +func (w *delayedResponseWriterWithFlush) Flush() { + w.flusher.Flush() +} + +type delayedResponseWriter struct { + wrapped http.ResponseWriter + end time.Time + statusWritten bool + requestError bool +} + +func (w *delayedResponseWriter) WriteHeader(statusCode int) { + // do not forget to write the status code to the wrapped writer + defer w.wrapped.WriteHeader(statusCode) + w.statusWritten = true + + // errors shouldn't be delayed + if statusCode/100 != 2 { + w.requestError = true + return + } + + delayLeft := w.end.Sub(timeNow()) + if delayLeft > 0 { + addDelayHeader(w.wrapped.Header(), delayLeft) + } +} + +func (w *delayedResponseWriter) Header() http.Header { + return w.wrapped.Header() +} + +func (w *delayedResponseWriter) Write(p []byte) (int, error) { + return w.wrapped.Write(p) +} + +func NewHTTP(limits Limits) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := timeNow() + ctx := r.Context() + + delay := getDelay(ctx, limits) + var delayRw *delayedResponseWriter + delayCtx := context.Background() + if delay > 0 { + var cancel context.CancelFunc + delayCtx, cancel = context.WithCancel(delayCtx) + defer cancel() + ctx = WithDelayCancel(ctx, cancel) + w, delayRw = wrapResponseWriter(w, start.Add(delay)) + + // only add a span when delay is active + var sp *tracing.Span + sp, ctx = tracing.StartSpanFromContext(ctx, "delayhandler.Handler") + defer sp.Finish() + } + + // now run the chain after me + h.ServeHTTP(w, r.WithContext(ctx)) + + // if we didn't delay, return immediately + if delayRw == nil { + return + } + + // if request errored we skip the delay + if delayRw.requestError { + return + } + + // The delay has been canceled down the chain. + if delayCtx.Err() != nil { + return + } + + delayLeft := delayRw.end.Sub(timeNow()) + // nothing to do if we're past the end time + if delayLeft <= 0 { + return + } + + // when headers are not written, we add the delay header + if !delayRw.statusWritten { + addDelayHeader(w.Header(), delayLeft) + } + + // create a separate span to make the artificial delay clear + sp, _ := tracing.StartSpanFromContext(ctx, "delayhandler.Delay") + sp.SetTag("delayed_by", delayLeft.String()) + defer sp.Finish() + + // wait for the delay to elapse + <-timeAfter(delayLeft) + }) + } +} diff --git a/pkg/util/delayhandler/http_test.go b/pkg/util/delayhandler/http_test.go new file mode 100644 index 0000000000..3e760ffedb --- /dev/null +++ b/pkg/util/delayhandler/http_test.go @@ -0,0 +1,350 @@ +package delayhandler + +import ( + "context" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + "testing" + "time" + + "github.com/grafana/dskit/middleware" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/health/grpc_health_v1" + + "github.com/grafana/pyroscope/v2/pkg/tenant" + httpserver "github.com/grafana/pyroscope/v2/pkg/util/http/server" +) + +// Mock implementation of the Limits interface +type mockLimits struct { + delays map[string]time.Duration +} + +func (m *mockLimits) IngestionArtificialDelay(tenantID string) time.Duration { + if delay, ok := m.delays[tenantID]; ok { + return delay + } + return 0 +} + +func newMockLimits() *mockLimits { + return &mockLimits{ + delays: make(map[string]time.Duration), + } +} + +func (m *mockLimits) setDelay(tenantID string, delay time.Duration) { + m.delays[tenantID] = delay +} + +// Test handler that records what happened +type testHandler struct { + statusCode int + body string + called bool + cancelDelay bool +} + +func (h *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.called = true + if h.cancelDelay { + CancelDelay(r.Context()) + } + if h.statusCode != 0 { + w.WriteHeader(h.statusCode) + } + if h.body != "" { + _, _ = w.Write([]byte(h.body)) + } +} + +func timeNowMock(t *testing.T, values []time.Time) func() { + old := timeNow + t.Cleanup(func() { + timeNow = old + }) + timeNow = func() time.Time { + if len(values) == 0 { + t.Fatalf("timeNowMock: no more values") + } + now := values[0] + values = values[1:] + return now + } + return func() { + + timeNow = old + } +} + +type timeAfterRecorder struct { + start time.Time + values []time.Duration +} + +func timeAfterMock() (*timeAfterRecorder, func()) { + m := &timeAfterRecorder{ + start: time.Now(), + } + old := timeAfter + timeAfter = func(d time.Duration) <-chan time.Time { + m.values = append(m.values, d) + + ch := make(chan time.Time) + go func() { + ch <- m.start.Add(d) + }() + + return ch + } + return m, func() { + timeAfter = old + } +} + +func fracDuration(d time.Duration, frac float64) time.Duration { + return time.Duration(int64(float64(d.Milliseconds())*frac)) * time.Millisecond +} + +func TestNewHTTP(t *testing.T) { + now := time.Unix(1718211600, 0) + tenantID := "my-tenant" + + tests := []struct { + name string + configDelay time.Duration + handlerStatusCode int + handlerBody string + handlerDelay time.Duration // delay in handler + middlewareDelay time.Duration // delay in other middlewares + cancelDelay bool + expectDelay bool + expectDelayHeader bool + }{ + { + name: "enabled/successful request", + configDelay: 100 * time.Millisecond, + handlerBody: "success", + expectDelay: true, + expectDelayHeader: true, + }, + { + name: "disabled/successful request", + configDelay: 0, + handlerBody: "success", + }, + { + name: "enabled/successful request/written headers", + configDelay: 100 * time.Millisecond, + handlerStatusCode: http.StatusOK, + handlerBody: "success", + expectDelay: true, + expectDelayHeader: true, + }, + { + name: "enabled/failed request/written headers", + configDelay: 100 * time.Millisecond, + handlerStatusCode: http.StatusInternalServerError, + handlerBody: "error", + }, + { + name: "disabled/failed request/written headers", + handlerStatusCode: http.StatusInternalServerError, + handlerBody: "error", + }, + { + name: "enabled/successful slow request", + configDelay: 100 * time.Millisecond, + handlerBody: "slow handler success", + handlerDelay: 200 * time.Millisecond, + }, + { + name: "enabled/successful slow request/written headers", + configDelay: 100 * time.Millisecond, + handlerStatusCode: http.StatusOK, + handlerBody: "slow handler success", + handlerDelay: 200 * time.Millisecond, + }, + { + name: "enabled/successful request/written headers/slow middleware", + configDelay: 100 * time.Millisecond, + handlerStatusCode: http.StatusOK, + handlerBody: "slow middlewares success", + middlewareDelay: 200 * time.Millisecond, + expectDelayHeader: true, + }, + { + name: "enabled/successful request/slow middleware", + configDelay: 100 * time.Millisecond, + handlerBody: "slow middlewares success", + middlewareDelay: 200 * time.Millisecond, + }, + { + name: "enabled/cancel delay", + configDelay: 100 * time.Millisecond, + handlerBody: "success", + cancelDelay: true, + }, + { + name: "disabled/cancel delay no effect", + configDelay: 0, + handlerBody: "success", + cancelDelay: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + handlerDelay := tt.handlerDelay + if handlerDelay == 0 { + handlerDelay = 5 * time.Millisecond + } + middlewareDelay := tt.middlewareDelay + if middlewareDelay == 0 { + middlewareDelay = 1 * time.Millisecond + } + + // start of handler + nows := []time.Time{ + now, + } + + // when a upstream handler writes headers, we will have an extra timeNow call + if tt.handlerStatusCode != 0 { + nows = append(nows, now.Add(handlerDelay)) + } + // final time now check including both delays + nows = append(nows, now.Add(handlerDelay+middlewareDelay)) + + // mock timeNow and timeAfter + cleanUpNow := timeNowMock(t, nows) + defer cleanUpNow() + sleeps, cleanUpSleep := timeAfterMock() + defer cleanUpSleep() + sleeps.start = now + + limits := newMockLimits() + limits.setDelay(tenantID, tt.configDelay) + middleware := NewHTTP(limits) + + handler := &testHandler{ + statusCode: tt.handlerStatusCode, + body: tt.handlerBody, + cancelDelay: tt.cancelDelay, + } + + req := httptest.NewRequest(http.MethodPost, "/test", strings.NewReader("test")) + req = req.WithContext(tenant.InjectTenantID(req.Context(), "my-tenant")) + w := httptest.NewRecorder() + + middleware(handler).ServeHTTP(w, req) + + // Verify handler was called + assert.True(t, handler.called) + + // Verify response + expectedStatusCode := tt.handlerStatusCode + if expectedStatusCode == 0 { + expectedStatusCode = http.StatusOK + } + assert.Equal(t, expectedStatusCode, w.Code) + assert.Equal(t, tt.handlerBody, w.Body.String()) + + // Expect header or no header depending on delay + if tt.expectDelayHeader { + serverTiming := w.Header().Get("Server-Timing") + require.Contains(t, serverTiming, "artificial_delay") + require.Contains(t, serverTiming, "dur=") + idx := strings.Index(serverTiming, "dur=") + + durationFloat, err := strconv.ParseFloat(serverTiming[idx+4:], 64) + duration := time.Duration(durationFloat) * time.Millisecond + assert.NoError(t, err) + + assert.Greater(t, duration, fracDuration(tt.configDelay, 0.8)-handlerDelay-middlewareDelay) + assert.Greater(t, fracDuration(tt.configDelay, 1.1), duration) + } else { + serverTiming := w.Header().Get("Server-Timing") + assert.Empty(t, serverTiming) + } + + // Expect sleeps when delayed + if tt.expectDelay { + require.Len(t, sleeps.values, 1) + + // check if delay is within jitter of expected + assert.Greater(t, sleeps.values[0], fracDuration(tt.configDelay, 0.8)-handlerDelay-middlewareDelay) + assert.Greater(t, fracDuration(tt.configDelay, 1.1), sleeps.values[0]) + } else { + require.Len(t, sleeps.values, 0) + } + + }) + } +} + +type healthMock struct { + grpc_health_v1.UnimplementedHealthServer + called bool +} + +func (h *healthMock) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { + h.called = true + return &grpc_health_v1.HealthCheckResponse{Status: grpc_health_v1.HealthCheckResponse_SERVING}, nil +} + +func TestGRPCHandler(t *testing.T) { + limits := newMockLimits() + limits.setDelay("my-tenant", 100*time.Millisecond) + delayMiddleware := middleware.Func(func(h http.Handler) http.Handler { + return NewHTTP(limits)(h) + }) + + sleeps, cleanUpSleep := timeAfterMock() + defer cleanUpSleep() + + addTenantMiddleware := middleware.Func(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r = r.WithContext(tenant.InjectTenantID(r.Context(), "my-tenant")) + h.ServeHTTP(w, r) + }) + }) + + grpcServer := grpc.NewServer() + healthM := &healthMock{} + grpc_health_v1.RegisterHealthServer(grpcServer, healthM) + + handler := middleware.Merge( + addTenantMiddleware, + delayMiddleware, + ).Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + grpcServer.ServeHTTP(w, r) + })) + + httpServer := httptest.NewUnstartedServer(handler) + httpserver.EnableHTTP2(httpServer.Config) + httpServer.Start() + defer httpServer.Close() + + // Set up a connection to the server. + u, err := url.Parse(httpServer.URL) + require.NoError(t, err) + conn, err := grpc.NewClient(u.Host, grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(t, err) + defer conn.Close() + + hc := grpc_health_v1.NewHealthClient(conn) + resp, err := hc.Check(context.Background(), &grpc_health_v1.HealthCheckRequest{Service: "pyroscope"}) + require.NoError(t, err) + assert.Equal(t, grpc_health_v1.HealthCheckResponse_SERVING, resp.Status) + assert.True(t, healthM.called) + + // check if the delay is applied + require.Len(t, sleeps.values, 1) +} diff --git a/pkg/util/fieldcategory/overrides.go b/pkg/util/fieldcategory/overrides.go index bdaee77c7c..211a6557c6 100644 --- a/pkg/util/fieldcategory/overrides.go +++ b/pkg/util/fieldcategory/overrides.go @@ -2,7 +2,10 @@ package fieldcategory -import "fmt" +import ( + "fmt" + "sync" +) type Category int @@ -30,20 +33,29 @@ func (c Category) String() string { // Fields are primarily categorized via struct tags, but this can be impossible when third party libraries are involved // Only categorize fields here when you can't otherwise, since struct tags are less likely to become stale -var overrides = map[string]Category{} +var ( + overridesMu sync.RWMutex + overrides = map[string]Category{} +) func AddOverrides(o map[string]Category) { + overridesMu.Lock() + defer overridesMu.Unlock() for n, c := range o { overrides[n] = c } } func GetOverride(fieldName string) (category Category, ok bool) { + overridesMu.RLock() + defer overridesMu.RUnlock() category, ok = overrides[fieldName] return } func VisitOverrides(f func(name string)) { + overridesMu.RLock() + defer overridesMu.RUnlock() for override := range overrides { f(override) } diff --git a/pkg/util/gziphandler/gzip.go b/pkg/util/gziphandler/gzip.go index ecd69631e7..023160c634 100644 --- a/pkg/util/gziphandler/gzip.go +++ b/pkg/util/gziphandler/gzip.go @@ -520,8 +520,11 @@ func handleContentType(contentTypes []parsedContentType, ct string) bool { func parseEncodings(s string) (codings, error) { c := make(codings) var e []string + var ss string + var found bool - for _, ss := range strings.Split(s, ",") { + for { + ss, s, found = strings.Cut(s, ",") coding, qvalue, err := parseCoding(ss) if err != nil { @@ -529,6 +532,10 @@ func parseEncodings(s string) (codings, error) { } else { c[coding] = qvalue } + + if !found { + break + } } // TODO (adammck): Use a proper multi-error struct, so the individual errors diff --git a/pkg/util/gziphandler/gzip_test.go b/pkg/util/gziphandler/gzip_test.go index 6934fa8e9a..9f75f18cb9 100644 --- a/pkg/util/gziphandler/gzip_test.go +++ b/pkg/util/gziphandler/gzip_test.go @@ -7,6 +7,7 @@ package gziphandler import ( "bytes" "compress/gzip" + "context" "fmt" "io" "net" @@ -15,9 +16,11 @@ import ( "net/url" "os" "strconv" + "strings" "testing" "github.com/stretchr/testify/assert" + "google.golang.org/grpc/test/bufconn" ) const ( @@ -271,12 +274,8 @@ func TestGzipHandlerContentLength(t *testing.T) { } // httptest.NewRecorder doesn't give you access to the Content-Length - // header so instead, we create a server on a random port and make - // a request to that instead - ln, err := net.Listen("tcp", "127.0.0.1:") - if err != nil { - t.Fatalf("failed creating listen socket: %v", err) - } + // header so instead, we create an in-memory network connection to a server. + ln := bufconn.Listen(256 << 10) defer ln.Close() srv := &http.Server{ Handler: nil, @@ -299,7 +298,13 @@ func TestGzipHandlerContentLength(t *testing.T) { Close: true, } req.Header.Set("Accept-Encoding", "gzip") - res, err := http.DefaultClient.Do(req) + + client := http.Client{ + Transport: &http.Transport{ + DialContext: func(context.Context, string, string) (net.Conn, error) { return ln.Dial() }, + }, + } + res, err := client.Do(req) if err != nil { t.Fatalf("Unexpected error making http request in test iteration %d: %v", num, err) } @@ -614,6 +619,17 @@ func TestContentTypes(t *testing.T) { } } +func BenchmarkParseEncodings(b *testing.B) { + req := httptest.NewRequest(http.MethodGet, "/whatever", nil) + req.Header.Set("Accept-Encoding", strings.Repeat(",", http.DefaultMaxHeaderBytes)) + b.ReportAllocs() + b.ResetTimer() + for range b.N { + _, err := parseEncodings(req.Header.Get(acceptEncoding)) + assert.Error(b, err) + } +} + // -------------------------------------------------------------------- func BenchmarkGzipHandler_S2k(b *testing.B) { benchmark(b, false, 2048) } diff --git a/pkg/util/hashedslice/hashedslice.go b/pkg/util/hashedslice/hashedslice.go new file mode 100644 index 0000000000..3ee245ccf2 --- /dev/null +++ b/pkg/util/hashedslice/hashedslice.go @@ -0,0 +1,63 @@ +// Package hashedslice provides a content-addressed, append-only slice: +// adding a value equal to one added before returns the existing index +// instead of appending, so a value's index is stable for the life of the +// slice. +package hashedslice + +import "slices" + +// New returns an empty Slice that uses equal to confirm matches when two +// values share a hash. +func New[A any](equal func(A, A) bool) *Slice[A] { + return &Slice[A]{ + m: make(map[uint64]int), + equal: equal, + } +} + +// Slice is a content-addressed, append-only slice. Callers supply each +// value's hash; collisions are resolved by probing successive hash slots +// and confirming with the equality function, so hash quality affects +// performance, not correctness. Not safe for concurrent use. +type Slice[A any] struct { + m map[uint64]int + equal func(A, A) bool + + // Values holds the distinct values in insertion order; indices returned + // by Add point into it. Hashes is parallel to Values and records each + // value's original hash. Both are exported for read access and must not + // be modified. + Values []A + Hashes []uint64 +} + +// Len returns the number of distinct values added. +func (h *Slice[A]) Len() int { + return len(h.Values) +} + +// Grow ensures capacity for size additional values. +func (h *Slice[A]) Grow(size int) { + h.Values = slices.Grow(h.Values, size) + h.Hashes = slices.Grow(h.Hashes, size) +} + +// Add returns the index of v, appending it if no equal value was added +// before. hash must be deterministic for v: equal values must supply equal +// hashes. +func (h *Slice[A]) Add(hash uint64, v A) int32 { + for probeHash := hash; ; probeHash++ { + idx, found := h.m[probeHash] + if !found { + idx = len(h.Values) + h.m[probeHash] = idx + h.Values = append(h.Values, v) + h.Hashes = append(h.Hashes, hash) // store original hash, not probe offset + return int32(idx) + } + if h.equal(h.Values[idx], v) { + return int32(idx) + } + // hash collision: probe next slot + } +} diff --git a/pkg/util/hashedslice/hashedslice_test.go b/pkg/util/hashedslice/hashedslice_test.go new file mode 100644 index 0000000000..4ef02eea83 --- /dev/null +++ b/pkg/util/hashedslice/hashedslice_test.go @@ -0,0 +1,64 @@ +package hashedslice_test + +import ( + "testing" + + "github.com/cespare/xxhash/v2" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/util/hashedslice" +) + +func stringEq(a, b string) bool { return a == b } + +func add(h *hashedslice.Slice[string], s string) int32 { + return h.Add(xxhash.Sum64String(s), s) +} + +func TestAddDedupsEqualValues(t *testing.T) { + h := hashedslice.New(stringEq) + require.Equal(t, 0, h.Len()) + + a := add(h, "a") + b := add(h, "b") + require.Equal(t, a, add(h, "a")) + require.Equal(t, b, add(h, "b")) + require.NotEqual(t, a, b) + + require.Equal(t, 2, h.Len()) + require.Equal(t, []string{"a", "b"}, h.Values) + require.Equal(t, "a", h.Values[a]) + require.Equal(t, "b", h.Values[b]) + require.Equal(t, []uint64{xxhash.Sum64String("a"), xxhash.Sum64String("b")}, h.Hashes) +} + +// TestAddResolvesHashCollisions forces distinct values onto the same hash: +// they must still get distinct indices, repeated adds must keep returning +// them, and Hashes must record the original hash for both, not the probed +// slot. +func TestAddResolvesHashCollisions(t *testing.T) { + h := hashedslice.New(stringEq) + const hash = uint64(42) + + a := h.Add(hash, "a") + b := h.Add(hash, "b") + c := h.Add(hash, "c") + require.NotEqual(t, a, b) + require.NotEqual(t, b, c) + + require.Equal(t, a, h.Add(hash, "a")) + require.Equal(t, b, h.Add(hash, "b")) + require.Equal(t, c, h.Add(hash, "c")) + + require.Equal(t, []string{"a", "b", "c"}, h.Values) + require.Equal(t, []uint64{hash, hash, hash}, h.Hashes) +} + +func TestGrowPreservesContent(t *testing.T) { + h := hashedslice.New(stringEq) + a := add(h, "a") + h.Grow(1024) + require.Equal(t, a, add(h, "a")) + require.Equal(t, []string{"a"}, h.Values) + require.Equal(t, 1, h.Len()) +} diff --git a/pkg/util/health/health.go b/pkg/util/health/health.go new file mode 100644 index 0000000000..7d3473aeb7 --- /dev/null +++ b/pkg/util/health/health.go @@ -0,0 +1,68 @@ +package health + +import ( + "context" + "errors" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "google.golang.org/grpc" + "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" +) + +type Service interface { + SetServing() + SetNotServing() +} + +type noopService struct{} + +var NoOpService = noopService{} + +func (noopService) SetServing() {} + +func (noopService) SetNotServing() {} + +type GRPCHealthService struct { + logger log.Logger + name string + server *health.Server +} + +func NewGRPCHealthService(server *health.Server, logger log.Logger, name string) *GRPCHealthService { + return &GRPCHealthService{ + logger: logger, + name: name, + server: server, + } +} + +func (s *GRPCHealthService) setStatus(x grpc_health_v1.HealthCheckResponse_ServingStatus) { + level.Info(s.logger).Log("msg", "setting health status", "status", x) + s.server.SetServingStatus(s.name, x) +} + +func (s *GRPCHealthService) SetServing() { + s.setStatus(grpc_health_v1.HealthCheckResponse_SERVING) +} + +func (s *GRPCHealthService) SetNotServing() { + s.setStatus(grpc_health_v1.HealthCheckResponse_NOT_SERVING) +} + +var NoOpClient = noOpClient{} + +type noOpClient struct{} + +func (noOpClient) Check(context.Context, *grpc_health_v1.HealthCheckRequest, ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error) { + return &grpc_health_v1.HealthCheckResponse{Status: grpc_health_v1.HealthCheckResponse_SERVING}, nil +} + +func (noOpClient) List(ctx context.Context, in *grpc_health_v1.HealthListRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthListResponse, error) { + return nil, errors.New("not implemented") +} + +func (noOpClient) Watch(context.Context, *grpc_health_v1.HealthCheckRequest, ...grpc.CallOption) (grpc_health_v1.Health_WatchClient, error) { + return nil, errors.New("not implemented") +} diff --git a/pkg/util/http.go b/pkg/util/http.go deleted file mode 100644 index 43920d4798..0000000000 --- a/pkg/util/http.go +++ /dev/null @@ -1,452 +0,0 @@ -package util - -import ( - "bytes" - "context" - "crypto/tls" - "encoding/json" - "errors" - "html/template" - "io" - "net" - "net/http" - "strings" - "time" - - "github.com/dustin/go-humanize" - "github.com/felixge/httpsnoop" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/gorilla/mux" - "github.com/grafana/dskit/instrument" - dslog "github.com/grafana/dskit/log" - "github.com/grafana/dskit/middleware" - "github.com/grafana/dskit/multierror" - "github.com/grafana/dskit/tracing" - "github.com/grafana/dskit/user" - "github.com/opentracing/opentracing-go" - "github.com/prometheus/client_golang/prometheus" - "golang.org/x/net/http2" - "gopkg.in/yaml.v3" - - "github.com/grafana/pyroscope/pkg/tenant" - httputil "github.com/grafana/pyroscope/pkg/util/http" - "github.com/grafana/pyroscope/pkg/util/nethttp" -) - -var defaultTransport http.RoundTripper = &http2.Transport{ - AllowHTTP: true, - ReadIdleTimeout: 30 * time.Second, - WriteByteTimeout: 30 * time.Second, - PingTimeout: 90 * time.Second, - DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { - return net.Dial(network, addr) - }, -} - -type RoundTripperFunc func(req *http.Request) (*http.Response, error) - -func (f RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { - return f(req) -} - -type RoundTripperInstrumentFunc func(next http.RoundTripper) http.RoundTripper - -// InstrumentedDefaultHTTPClient returns an http client configured with some -// default settings which is wrapped with a variety of instrumented -// RoundTrippers. -func InstrumentedDefaultHTTPClient(instruments ...RoundTripperInstrumentFunc) *http.Client { - client := &http.Client{ - Transport: defaultTransport, - } - return InstrumentedHTTPClient(client, instruments...) -} - -// InstrumentedHTTPClient adds the associated instrumentation middlewares to the -// provided http client. -func InstrumentedHTTPClient(client *http.Client, instruments ...RoundTripperInstrumentFunc) *http.Client { - for i := len(instruments) - 1; i >= 0; i-- { - client.Transport = instruments[i](client.Transport) - } - return client -} - -// WithTracingTransport wraps the given RoundTripper with a tracing instrumented -// one. -func WithTracingTransport() RoundTripperInstrumentFunc { - return func(next http.RoundTripper) http.RoundTripper { - next = &nethttp.Transport{RoundTripper: next} - return RoundTripperFunc(func(req *http.Request) (*http.Response, error) { - req = nethttp.TraceRequest(opentracing.GlobalTracer(), req) - return next.RoundTrip(req) - }) - } -} - -// WriteYAMLResponse writes some YAML as a HTTP response. -func WriteYAMLResponse(w http.ResponseWriter, v interface{}) { - // There is not standardised content-type for YAML, text/plain ensures the - // YAML is displayed in the browser instead of offered as a download - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - - data, err := yaml.Marshal(v) - if err != nil { - httputil.Error(w, err) - return - } - - // We ignore errors here, because we cannot do anything about them. - // Write will trigger sending Status code, so we cannot send a different status code afterwards. - // Also this isn't internal error, but error communicating with client. - _, _ = w.Write(data) -} - -const ( - maxResponseBodyInLogs = 4096 // At most 4k bytes from response bodies in our logs. -) - -// Log middleware logs http requests -type Log struct { - Log log.Logger - LogRequestHeaders bool // LogRequestHeaders true -> dump http headers at debug log level - LogRequestAtInfoLevel bool // LogRequestAtInfoLevel true -> log requests at info log level - SourceIPs *middleware.SourceIPExtractor -} - -// logWithRequest information from the request and context as fields. -func (l Log) logWithRequest(r *http.Request) log.Logger { - localLog := l.Log - traceID, ok := tracing.ExtractTraceID(r.Context()) - if ok { - localLog = log.With(localLog, "traceID", traceID) - } - - if l.SourceIPs != nil { - ips := l.SourceIPs.Get(r) - if ips != "" { - localLog = log.With(localLog, "sourceIPs", ips) - } - } - orgID := r.Header.Get(user.OrgIDHeaderName) - if orgID == "" { - localLog = user.LogWith(r.Context(), localLog) - } else { - localLog = log.With(localLog, "orgID", orgID) - } - return localLog -} - -// measure request body size -type reqBody struct { - b io.ReadCloser - read byteSize -} - -func (w *reqBody) Read(p []byte) (int, error) { - n, err := w.b.Read(p) - if n > 0 { - w.read += byteSize(n) - } - return n, err -} - -func (w *reqBody) Close() error { - return w.b.Close() -} - -type byteSize uint64 - -func (bs byteSize) String() string { - return strings.Replace(humanize.IBytes(uint64(bs)), " ", "", 1) -} - -// Wrap implements Middleware -func (l Log) Wrap(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - begin := time.Now() - uri := r.RequestURI // capture the URI before running next, as it may get rewritten - requestLog := l.logWithRequest(r) - // Log headers before running 'next' in case other interceptors change the data. - headers, err := dumpRequest(r) - if err != nil { - headers = nil - level.Error(requestLog).Log("msg", "Could not dump request headers", "err", err) - } - var ( - httpErr multierror.MultiError - httpCode int = http.StatusOK - headerWritten bool - buf bytes.Buffer - bodyLeft int = maxResponseBodyInLogs - ) - - wrapped := httpsnoop.Wrap(w, httpsnoop.Hooks{ - WriteHeader: func(next httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { - return func(code int) { - next(code) - if !headerWritten { - httpCode = code - headerWritten = true - } - } - }, - - Write: func(next httpsnoop.WriteFunc) httpsnoop.WriteFunc { - return func(p []byte) (int, error) { - n, err := next(p) - headerWritten = true - httpErr.Add(err) - if httpCode >= 500 && httpCode < 600 { - bodyLeft = captureResponseBody(p, bodyLeft, &buf) - } - return n, err - } - }, - - ReadFrom: func(next httpsnoop.ReadFromFunc) httpsnoop.ReadFromFunc { - return func(src io.Reader) (int64, error) { - n, err := next(src) - headerWritten = true - httpErr.Add(err) - return n, err - } - }, - }) - - origBody := r.Body - defer func() { - // No need to leak our Body wrapper beyond the scope of this handler. - r.Body = origBody - }() - - rBody := &reqBody{b: origBody} - r.Body = rBody - - next.ServeHTTP(wrapped, r) - - statusCode, writeErr := httpCode, httpErr.Err() - - requestLogD := log.With(requestLog, "method", r.Method, "uri", uri, "status", statusCode, "duration", time.Since(begin)) - if rBody.read > 0 { - requestLogD = log.With(requestLogD, "request_body_size", rBody.read) - } - - if writeErr != nil { - if errors.Is(writeErr, context.Canceled) { - if l.LogRequestAtInfoLevel { - level.Info(requestLogD).Log("msg", dslog.LazySprintf("request cancelled: %s ws: %v; %s", writeErr, IsWSHandshakeRequest(r), headers)) - } else { - level.Debug(requestLogD).Log("msg", dslog.LazySprintf("request cancelled: %s ws: %v; %s", writeErr, IsWSHandshakeRequest(r), headers)) - } - } else { - level.Warn(requestLogD).Log("msg", dslog.LazySprintf("error: %s ws: %v; %s", writeErr, IsWSHandshakeRequest(r), headers)) - } - - return - } - if 100 <= statusCode && statusCode < 500 { - if l.LogRequestAtInfoLevel { - level.Info(requestLogD).Log("msg", "http request processed") - } else { - level.Debug(requestLogD).Log("msg", "http request processed") - } - if l.LogRequestHeaders && headers != nil { - if l.LogRequestAtInfoLevel { - level.Info(requestLog).Log("msg", dslog.LazySprintf("ws: %v; %s", IsWSHandshakeRequest(r), string(headers))) - } else { - level.Debug(requestLog).Log("msg", dslog.LazySprintf("ws: %v; %s", IsWSHandshakeRequest(r), string(headers))) - } - } - } else { - level.Warn(requestLog).Log("msg", dslog.LazySprintf("%s %s (%d) %s Response: %q ws: %v; %s", - r.Method, uri, statusCode, time.Since(begin), buf.Bytes(), IsWSHandshakeRequest(r), headers)) - } - }) -} - -func captureResponseBody(data []byte, bodyBytesLeft int, buf *bytes.Buffer) int { - if bodyBytesLeft <= 0 { - return 0 - } - if len(data) > bodyBytesLeft { - buf.Write(data[:bodyBytesLeft]) - _, _ = io.WriteString(buf, "...") - return 0 - } else { - buf.Write(data) - return bodyBytesLeft - len(data) - } -} - -func dumpRequest(req *http.Request) ([]byte, error) { - var b bytes.Buffer - - // Exclude some headers for security, or just that we don't need them when debugging - err := req.Header.WriteSubset(&b, map[string]bool{ - "Cookie": true, - "X-Csrf-Token": true, - "Authorization": true, - }) - if err != nil { - return nil, err - } - - ret := bytes.Replace(b.Bytes(), []byte("\r\n"), []byte("; "), -1) - return ret, nil -} - -// IsWSHandshakeRequest returns true if the given request is a websocket handshake request. -func IsWSHandshakeRequest(req *http.Request) bool { - if strings.ToLower(req.Header.Get("Upgrade")) == "websocket" { - // Connection header values can be of form "foo, bar, ..." - parts := strings.Split(strings.ToLower(req.Header.Get("Connection")), ",") - for _, part := range parts { - if strings.TrimSpace(part) == "upgrade" { - return true - } - } - } - return false -} - -// NewHTTPMetricMiddleware creates a new middleware that automatically instruments HTTP requests from the given router. -func NewHTTPMetricMiddleware(mux *mux.Router, namespace string, reg prometheus.Registerer) (middleware.Interface, error) { - // Prometheus histograms for requests. - requestDuration := prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Namespace: namespace, - Name: "request_duration_seconds", - Help: "Time (in seconds) spent serving HTTP requests.", - Buckets: instrument.DefBuckets, - }, []string{"method", "route", "status_code", "ws"}) - err := reg.Register(requestDuration) - if err != nil { - already, ok := err.(prometheus.AlreadyRegisteredError) - if ok { - requestDuration = already.ExistingCollector.(*prometheus.HistogramVec) - } else { - return nil, err - } - } - - receivedMessageSize := prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Namespace: namespace, - Name: "request_message_bytes", - Help: "Size (in bytes) of messages received in the request.", - Buckets: middleware.BodySizeBuckets, - }, []string{"method", "route"}) - err = reg.Register(receivedMessageSize) - if err != nil { - already, ok := err.(prometheus.AlreadyRegisteredError) - if ok { - receivedMessageSize = already.ExistingCollector.(*prometheus.HistogramVec) - } else { - return nil, err - } - } - - sentMessageSize := prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Namespace: namespace, - Name: "response_message_bytes", - Help: "Size (in bytes) of messages sent in response.", - Buckets: middleware.BodySizeBuckets, - }, []string{"method", "route"}) - - err = reg.Register(sentMessageSize) - if err != nil { - already, ok := err.(prometheus.AlreadyRegisteredError) - if ok { - sentMessageSize = already.ExistingCollector.(*prometheus.HistogramVec) - } else { - return nil, err - } - } - - inflightRequests := prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: namespace, - Name: "inflight_requests", - Help: "Current number of inflight requests.", - }, []string{"method", "route"}) - err = reg.Register(inflightRequests) - if err != nil { - already, ok := err.(prometheus.AlreadyRegisteredError) - if ok { - inflightRequests = already.ExistingCollector.(*prometheus.GaugeVec) - } else { - return nil, err - } - } - return middleware.Instrument{ - RouteMatcher: mux, - Duration: requestDuration, - RequestBodySize: receivedMessageSize, - ResponseBodySize: sentMessageSize, - InflightRequests: inflightRequests, - }, nil -} - -// WriteHTMLResponse sends message as text/html response with 200 status code. -func WriteHTMLResponse(w http.ResponseWriter, message string) { - w.Header().Set("Content-Type", "text/html") - - // Ignore inactionable errors. - _, _ = w.Write([]byte(message)) -} - -// WriteTextResponse sends message as text/plain response with 200 status code. -func WriteTextResponse(w http.ResponseWriter, message string) { - w.Header().Set("Content-Type", "text/plain") - - // Ignore inactionable errors. - _, _ = w.Write([]byte(message)) -} - -// RenderHTTPResponse either responds with JSON or a rendered HTML page using the passed in template -// by checking the Accepts header. -func RenderHTTPResponse(w http.ResponseWriter, v interface{}, t *template.Template, r *http.Request) { - accept := r.Header.Get("Accept") - if strings.Contains(accept, "application/json") { - WriteJSONResponse(w, v) - return - } - - w.Header().Set("Content-Type", "text/html; charset=utf-8") - err := t.Execute(w, v) - if err != nil { - httputil.Error(w, err) - } -} - -// WriteJSONResponse writes some JSON as a HTTP response. -func WriteJSONResponse(w http.ResponseWriter, v interface{}) { - w.Header().Set("Content-Type", "application/json") - - data, err := json.Marshal(v) - if err != nil { - httputil.Error(w, err) - return - } - - // We ignore errors here, because we cannot do anything about them. - // Write will trigger sending Status code, so we cannot send a different status code afterwards. - // Also this isn't internal error, but error communicating with client. - _, _ = w.Write(data) -} - -// AuthenticateUser propagates the user ID from HTTP headers back to the request's context. -// If on is false, it will inject the default tenant ID. -func AuthenticateUser(on bool) middleware.Interface { - return middleware.Func(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !on { - next.ServeHTTP(w, r.WithContext(user.InjectOrgID(r.Context(), tenant.DefaultTenantID))) - return - } - _, ctx, err := user.ExtractOrgIDFromHTTPRequest(r) - if err != nil { - httputil.ErrorWithStatus(w, err, http.StatusUnauthorized) - return - } - next.ServeHTTP(w, r.WithContext(ctx)) - }) - }) -} diff --git a/pkg/util/http/auth.go b/pkg/util/http/auth.go new file mode 100644 index 0000000000..b82c1966fb --- /dev/null +++ b/pkg/util/http/auth.go @@ -0,0 +1,30 @@ +package http + +import ( + "net/http" + + "github.com/grafana/dskit/middleware" + "github.com/grafana/dskit/user" + + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +// AuthenticateUser propagates the user ID from HTTP headers back to the request's context. +// If on is false, it will inject the default tenant ID. +func AuthenticateUser(on bool) middleware.Interface { + // TODO: @petethepig This logic is copied in otlp.*ingestHandler.Export. We should unify + return middleware.Func(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !on { + next.ServeHTTP(w, r.WithContext(user.InjectOrgID(r.Context(), tenant.DefaultTenantID))) + return + } + _, ctx, err := user.ExtractOrgIDFromHTTPRequest(r) + if err != nil { + ErrorWithStatus(w, err, http.StatusUnauthorized) + return + } + next.ServeHTTP(w, r.WithContext(ctx)) + }) + }) +} diff --git a/pkg/util/http/client.go b/pkg/util/http/client.go new file mode 100644 index 0000000000..4c2e33d03e --- /dev/null +++ b/pkg/util/http/client.go @@ -0,0 +1,79 @@ +package http + +import ( + "context" + "crypto/tls" + "net" + "net/http" + "time" + + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel/baggage" + "golang.org/x/net/http2" +) + +var defaultTransport http.RoundTripper = &http2.Transport{ + AllowHTTP: true, + ReadIdleTimeout: 30 * time.Second, + WriteByteTimeout: 30 * time.Second, + PingTimeout: 90 * time.Second, + DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { + return net.Dial(network, addr) + }, +} + +type RoundTripperFunc func(req *http.Request) (*http.Response, error) + +func (f RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +type RoundTripperInstrumentFunc func(next http.RoundTripper) http.RoundTripper + +// InstrumentedDefaultHTTPClient returns an http client configured with some +// default settings which is wrapped with a variety of instrumented +// RoundTrippers. +func InstrumentedDefaultHTTPClient(instruments ...RoundTripperInstrumentFunc) *http.Client { + client := &http.Client{ + Transport: defaultTransport, + } + return InstrumentedHTTPClient(client, instruments...) +} + +// InstrumentedHTTPClient adds the associated instrumentation middlewares to the +// provided http client. +func InstrumentedHTTPClient(client *http.Client, instruments ...RoundTripperInstrumentFunc) *http.Client { + for i := len(instruments) - 1; i >= 0; i-- { + client.Transport = instruments[i](client.Transport) + } + return client +} + +// WithTracingTransport wraps the given RoundTripper with a tracing instrumented +// one. +func WithTracingTransport() RoundTripperInstrumentFunc { + return func(next http.RoundTripper) http.RoundTripper { + return otelhttp.NewTransport(next) + } +} + +// WithBaggageTransport will set the Baggage header on the request if there is +// any baggage in the context and it was not already set. +func WithBaggageTransport() RoundTripperInstrumentFunc { + return func(next http.RoundTripper) http.RoundTripper { + return RoundTripperFunc(func(req *http.Request) (*http.Response, error) { + _, ok := req.Header["Baggage"] + if ok { + return next.RoundTrip(req) + } + + b := baggage.FromContext(req.Context()) + if b.Len() == 0 { + return next.RoundTrip(req) + } + + req.Header.Set("Baggage", b.String()) + return next.RoundTrip(req) + }) + } +} diff --git a/pkg/util/http/error.go b/pkg/util/http/error.go index c0d01395d9..9f9c517715 100644 --- a/pkg/util/http/error.go +++ b/pkg/util/http/error.go @@ -11,8 +11,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/util/connectgrpc" + "github.com/grafana/pyroscope/v2/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/util/connectgrpc" ) var errorWriter = connect.NewErrorWriter() @@ -21,8 +21,8 @@ var errorWriter = connect.NewErrorWriter() const StatusClientClosedRequest = 499 const ( - ErrClientCanceled = "The request was cancelled by the client." - ErrDeadlineExceeded = "Request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed." + ErrClientCanceled = "the request was cancelled by the client" + ErrDeadlineExceeded = "request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed" ) // Error write a go error with the correct status code. @@ -60,6 +60,9 @@ func ErrorWithStatus(w http.ResponseWriter, err error, status int) { // ClientHTTPStatusAndError returns error and http status that is "safe" to return to client without // exposing any implementation details. func ClientHTTPStatusAndError(err error) (int, error) { + if err == nil { + return http.StatusOK, nil + } // todo handle multi errors // me, ok := err.(multierror.MultiError) // if ok && me.Is(context.Canceled) { @@ -71,13 +74,16 @@ func ClientHTTPStatusAndError(err error) (int, error) { s, isRPC := status.FromError(err) switch { - case errors.Is(err, context.Canceled): + case errors.Is(err, context.Canceled) || + (isRPC && s.Code() == codes.Canceled): return StatusClientClosedRequest, errors.New(ErrClientCanceled) case errors.Is(err, context.DeadlineExceeded) || (isRPC && s.Code() == codes.DeadlineExceeded): return http.StatusGatewayTimeout, errors.New(ErrDeadlineExceeded) case errors.Is(err, tenant.ErrNoTenantID): return http.StatusBadRequest, err + case isRPC && s.Code() == codes.InvalidArgument: + return http.StatusBadRequest, err default: if grpcErr, ok := httpgrpc.HTTPResponseFromError(err); ok { return int(grpcErr.Code), errors.New(string(grpcErr.Body)) diff --git a/pkg/util/http/error_test.go b/pkg/util/http/error_test.go index cf8f0bbd14..8ca9fc80ce 100644 --- a/pkg/util/http/error_test.go +++ b/pkg/util/http/error_test.go @@ -11,12 +11,12 @@ import ( "testing" "connectrpc.com/connect" - "github.com/gogo/status" "github.com/grafana/dskit/httpgrpc" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" - "github.com/grafana/pyroscope/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) func Test_writeError(t *testing.T) { @@ -27,13 +27,13 @@ func Test_writeError(t *testing.T) { msg string expectedStatus int }{ - {"cancelled", context.Canceled, `{"code":"canceled","message":"The request was cancelled by the client."}`, StatusClientClosedRequest}, - {"rpc cancelled", status.New(codes.Canceled, context.Canceled.Error()).Err(), `{"code":"unknown","message":"rpc error: code = Canceled desc = context canceled"}`, http.StatusInternalServerError}, + {"cancelled", context.Canceled, `{"code":"canceled","message":"the request was cancelled by the client"}`, StatusClientClosedRequest}, + {"rpc cancelled", status.New(codes.Canceled, context.Canceled.Error()).Err(), `{"code":"canceled","message":"the request was cancelled by the client"}`, StatusClientClosedRequest}, {"orgid", tenant.ErrNoTenantID, `{"code":"invalid_argument","message":"no org id"}`, http.StatusBadRequest}, - {"deadline", context.DeadlineExceeded, `{"code":"deadline_exceeded","message":"Request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed."}`, http.StatusGatewayTimeout}, - {"rpc deadline", status.New(codes.DeadlineExceeded, context.DeadlineExceeded.Error()).Err(), `{"code":"deadline_exceeded","message":"Request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed."}`, http.StatusGatewayTimeout}, + {"deadline", context.DeadlineExceeded, `{"code":"deadline_exceeded","message":"request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed"}`, http.StatusGatewayTimeout}, + {"rpc deadline", status.New(codes.DeadlineExceeded, context.DeadlineExceeded.Error()).Err(), `{"code":"deadline_exceeded","message":"request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed"}`, http.StatusGatewayTimeout}, // {"mixed context, rpc deadline and another", multierror.MultiError{errors.New("standard error"), context.DeadlineExceeded, status.New(codes.DeadlineExceeded, context.DeadlineExceeded.Error()).Err()}, "3 errors: standard error; context deadline exceeded; rpc error: code = DeadlineExceeded desc = context deadline exceeded", http.StatusInternalServerError}, - {"httpgrpc", httpgrpc.Errorf(http.StatusBadRequest, errors.New("foo").Error()), `{"code":"invalid_argument","message":"foo"}`, http.StatusBadRequest}, + {"httpgrpc", httpgrpc.Errorf(http.StatusBadRequest, "foo"), `{"code":"invalid_argument","message":"foo"}`, http.StatusBadRequest}, {"internal", errors.New("foo"), `{"code":"unknown","message":"foo"}`, http.StatusInternalServerError}, {"connect", connect.NewError(connect.CodeInvalidArgument, errors.New("foo")), `{"code":"invalid_argument","message":"foo"}`, http.StatusBadRequest}, {"connect wrapped", fmt.Errorf("foo %w", connect.NewError(connect.CodeInvalidArgument, errors.New("foo"))), `{"code":"invalid_argument","message":"foo"}`, http.StatusBadRequest}, @@ -42,12 +42,12 @@ func Test_writeError(t *testing.T) { t.Run(tt.name, func(t *testing.T) { rec := httptest.NewRecorder() Error(rec, tt.err) - require.Equal(t, tt.expectedStatus, rec.Result().StatusCode) + assert.Equal(t, tt.expectedStatus, rec.Result().StatusCode) b, err := io.ReadAll(rec.Result().Body) if err != nil { t.Fatal(err) } - require.Equal(t, tt.msg, strings.TrimSpace(string(b))) + assert.Equal(t, tt.msg, strings.TrimSpace(string(b))) }) } } diff --git a/pkg/util/http/http_test.go b/pkg/util/http/http_test.go new file mode 100644 index 0000000000..48ffe83829 --- /dev/null +++ b/pkg/util/http/http_test.go @@ -0,0 +1,225 @@ +package http + +import ( + "bytes" + "context" + "errors" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/go-kit/log" + "github.com/grafana/dskit/user" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/tenant" +) + +func TestWriteTextResponse(t *testing.T) { + w := httptest.NewRecorder() + + WriteTextResponse(w, "hello world") + + assert.Equal(t, 200, w.Code) + assert.Equal(t, "hello world", w.Body.String()) + assert.Equal(t, "text/plain", w.Header().Get("Content-Type")) +} + +func TestMultitenantMiddleware(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "http://localhost:8080", nil) + + // No org ID header. + m := AuthenticateUser(true).Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + id, err := tenant.ExtractTenantIDFromContext(r.Context()) + require.NoError(t, err) + assert.Equal(t, "1", id) + })) + m.ServeHTTP(w, r) + assert.Equal(t, http.StatusUnauthorized, w.Code) + + w = httptest.NewRecorder() + r.Header.Set("X-Scope-OrgID", "1") + m.ServeHTTP(w, r) + assert.Equal(t, http.StatusOK, w.Code) + + // No org ID header without auth. + r = httptest.NewRequest("GET", "http://localhost:8080", nil) + m = AuthenticateUser(false).Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + id, err := tenant.ExtractTenantIDFromContext(r.Context()) + require.NoError(t, err) + assert.Equal(t, tenant.DefaultTenantID, id) + })) + m.ServeHTTP(w, r) + assert.Equal(t, http.StatusOK, w.Code) +} + +func removeLogFields(line string, fields ...string) string { + for _, field := range fields { + // find field + needle := field + "=" + pos := strings.Index(line, needle) + if pos < 0 { + continue + } + + // find space after field + offset := pos + len(needle) + posSpace := strings.Index(line[offset:], " ") + if posSpace < 0 { + // remove all after needle + line = line[0:offset] + continue + } + + // remove value + line = line[:offset] + line[offset+posSpace:] + } + + return line + +} + +type errorRecorder struct { + writeErr error +} + +func (r *errorRecorder) Write([]byte) (int, error) { return 0, r.writeErr } + +func (*errorRecorder) Header() http.Header { return make(http.Header) } + +func (*errorRecorder) WriteHeader(statusCode int) {} + +func TestHTTPLog(t *testing.T) { + ctxTenant := user.InjectOrgID(context.Background(), "my-tenant") + for _, tc := range []struct { + name string + log *Log + ctx context.Context + reqBody io.Reader + writeErr error + setHeaderList []string + statusCode int + message string + }{ + { + name: "Header logging disabled", + log: &Log{ + LogRequestHeaders: false, + }, + setHeaderList: []string{"good-header", "authorization"}, + message: `level=debug method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 msg="http request processed"`, + }, + { + name: "Header logging enable", + log: &Log{ + LogRequestHeaders: true, + }, + setHeaderList: []string{"good-header", "authorization"}, + message: `level=debug method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 request_header_Good-Header=good-headerValue msg="http request processed"`, + }, + { + name: "Extra Header excluded", + log: &Log{ + LogRequestHeaders: true, + LogRequestExcludeHeaders: []string{"bad-header"}, + }, + setHeaderList: []string{"good-header", "bad-header", "authorization"}, + message: `level=debug method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 request_header_Good-Header=good-headerValue msg="http request processed"`, + }, + { + name: "Extra Header with different casing", + log: &Log{ + LogRequestHeaders: true, + LogRequestExcludeHeaders: []string{"Bad-Header"}, + }, + setHeaderList: []string{"good-header", "bad-header", "authorization"}, + message: `level=debug method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 request_header_Good-Header=good-headerValue msg="http request processed"`, + }, + { + name: "Two Extra Headers excluded", + log: &Log{ + LogRequestHeaders: true, + LogRequestExcludeHeaders: []string{"bad-header", "bad-header2"}, + }, + setHeaderList: []string{"good-header", "bad-header", "bad-header2", "authorization"}, + message: `level=debug method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 request_header_Good-Header=good-headerValue msg="http request processed"`, + }, + { + name: "Status code 500 should still log headers", + log: &Log{ + LogRequestHeaders: false, + LogRequestExcludeHeaders: []string{"bad-header"}, + }, + setHeaderList: []string{"good-header", "bad-header", "authorization"}, + message: `level=warn method=GET uri=http://example.com/foo status=500 duration= proto=HTTP/1.1 request_header_Good-Header=good-headerValue msg="http request failed" response_body="Hello world!"`, + + statusCode: http.StatusInternalServerError, + }, + { + name: "Log request body size latency", + log: &Log{}, + reqBody: strings.NewReader("Hello World! I am a request body."), + message: `level=debug method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 request_body_size=33B request_body_read_duration= msg="http request processed"`, + }, + { + name: "Write errors should be shown at warning level", + log: &Log{}, + writeErr: errors.New("some error"), + message: `level=warn method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 msg="http request failed" err="some error"`, + }, + { + name: "Context cancelled requests should not be at warning level", + log: &Log{}, + writeErr: context.Canceled, + message: `level=debug method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 msg="request cancelled"`, + }, + { + name: "Tenant id should be logged", + ctx: ctxTenant, + log: &Log{}, + message: `level=debug tenant=my-tenant method=GET uri=http://example.com/foo status=200 duration= proto=HTTP/1.1 msg="http request processed"`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + buf := bytes.NewBuffer(nil) + + if tc.statusCode == 0 { + tc.statusCode = http.StatusOK + } + + ctx := tc.ctx + if ctx == nil { + ctx = context.Background() + } + + tc.log.Log = log.NewLogfmtLogger(buf) + + handler := func(w http.ResponseWriter, r *http.Request) { + if r.Body != nil { + _, _ = io.Copy(io.Discard, r.Body) + } + w.WriteHeader(tc.statusCode) + _, _ = io.WriteString(w, "Hello world!") + } + loggingHandler := tc.log.Wrap(http.HandlerFunc(handler)) + + req := httptest.NewRequestWithContext(ctx, "GET", "http://example.com/foo", tc.reqBody) + for _, header := range tc.setHeaderList { + req.Header.Set(header, header+"Value") + } + + var recorder http.ResponseWriter = httptest.NewRecorder() + if tc.writeErr != nil { + recorder = &errorRecorder{writeErr: tc.writeErr} + } + loggingHandler.ServeHTTP(recorder, req) + + output := buf.String() + assert.Equal(t, tc.message, removeLogFields(strings.TrimSpace(output), "duration", "request_body_read_duration")) + }) + } +} diff --git a/pkg/util/http/logging.go b/pkg/util/http/logging.go new file mode 100644 index 0000000000..bc8c027b7e --- /dev/null +++ b/pkg/util/http/logging.go @@ -0,0 +1,280 @@ +package http + +import ( + "bytes" + "context" + "errors" + "io" + "net/http" + "net/textproto" + "slices" + "strings" + "sync" + "time" + + "github.com/dustin/go-humanize" + "github.com/felixge/httpsnoop" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/middleware" + "github.com/grafana/dskit/multierror" + "github.com/grafana/dskit/tracing" + "github.com/grafana/dskit/user" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +const ( + maxResponseBodyInLogs = 4096 // At most 4k bytes from response bodies in our logs. +) + +var timeNow = time.Now + +// Log middleware logs http requests +type Log struct { + Log log.Logger + LogRequestHeaders bool + LogRequestExcludeHeaders []string + LogRequestAtInfoLevel bool // LogRequestAtInfoLevel true -> log requests at info log level + SourceIPs *middleware.SourceIPExtractor + + filterHeaderMap map[string]struct{} + filterHeaderOnce sync.Once +} + +func (l *Log) filterHeader(key string) bool { + // ensure map is populated once + l.filterHeaderOnce.Do(func() { + l.filterHeaderMap = make(map[string]struct{}) + for _, k := range l.LogRequestExcludeHeaders { + l.filterHeaderMap[textproto.CanonicalMIMEHeaderKey(k)] = struct{}{} + } + for k := range middleware.AlwaysExcludedHeaders { + l.filterHeaderMap[textproto.CanonicalMIMEHeaderKey(k)] = struct{}{} + } + }) + _, filter := l.filterHeaderMap[key] + return filter +} + +func (l *Log) extractHeaders(req *http.Request) []any { + // Populate header list first and sort it + logKeys := make([]string, 0, len(req.Header)) + for k := range req.Header { + if l.filterHeader(k) { + continue + } + logKeys = append(logKeys, k) + } + slices.SortFunc(logKeys, strings.Compare) + + // build the log fields + logFields := make([]any, 0, len(logKeys)*2) + for _, k := range logKeys { + logFields = append( + logFields, + "request_header_"+k, + req.Header.Get(k), + ) + } + + return logFields +} + +// logWithRequest information from the request and context as fields. +func (l *Log) logWithRequest(r *http.Request) log.Logger { + localLog := l.Log + traceID, ok := tracing.ExtractTraceID(r.Context()) + if ok { + localLog = log.With(localLog, "traceID", traceID) + } + + if l.SourceIPs != nil { + ips := l.SourceIPs.Get(r) + if ips != "" { + localLog = log.With(localLog, "sourceIPs", ips) + } + } + + tenantID := r.Header.Get(user.OrgIDHeaderName) + if tenantID == "" { + id, err := user.ExtractOrgID(r.Context()) + if err == nil { + tenantID = id + } + } + if tenantID != "" { + localLog = log.With(localLog, "tenant", tenantID) + } + + return localLog +} + +// measure request body size +type reqBody struct { + b io.ReadCloser + read byteSize + + start time.Time + duration time.Duration + + sp trace.Span +} + +func (w *reqBody) Read(p []byte) (int, error) { + if w.start.IsZero() { + w.start = timeNow() + if w.sp != nil { + w.sp.AddEvent("start reading body from request") + } + } + n, err := w.b.Read(p) + if n > 0 { + w.read += byteSize(n) + } + if err == io.EOF { + w.duration = timeNow().Sub(w.start) + if w.sp != nil { + w.sp.AddEvent("read body from request") + if w.read > 0 { + w.sp.SetAttributes(attribute.Int64("request_body_size", int64(w.read))) + } + } + } + return n, err +} + +func (w *reqBody) Close() error { + return w.b.Close() +} + +type byteSize uint64 + +func (bs byteSize) String() string { + return strings.Replace(humanize.IBytes(uint64(bs)), " ", "", 1) +} + +// Wrap implements Middleware +func (l *Log) Wrap(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + begin := timeNow() + uri := r.RequestURI // Capture the URI before running next, as it may get rewritten + requestLog := l.logWithRequest(r) + // Log headers before running 'next' in case other interceptors change the data. + + var ( + httpErr multierror.MultiError + httpCode = http.StatusOK + headerWritten bool + buf bytes.Buffer + bodyLeft = maxResponseBodyInLogs + ) + + headerFields := l.extractHeaders(r) + + wrapped := httpsnoop.Wrap(w, httpsnoop.Hooks{ + WriteHeader: func(next httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { + return func(code int) { + next(code) + if !headerWritten { + httpCode = code + headerWritten = true + } + } + }, + + Write: func(next httpsnoop.WriteFunc) httpsnoop.WriteFunc { + return func(p []byte) (int, error) { + n, err := next(p) + headerWritten = true + httpErr.Add(err) + if httpCode >= 400 && httpCode < 600 { + bodyLeft = captureResponseBody(p, bodyLeft, &buf) + } + return n, err + } + }, + + ReadFrom: func(next httpsnoop.ReadFromFunc) httpsnoop.ReadFromFunc { + return func(src io.Reader) (int64, error) { + n, err := next(src) + headerWritten = true + httpErr.Add(err) + return n, err + } + }, + }) + + origBody := r.Body + defer func() { + // No need to leak our Body wrapper beyond the scope of this handler. + r.Body = origBody + }() + + rBody := &reqBody{ + b: origBody, + sp: trace.SpanFromContext(r.Context()), + } + r.Body = rBody + + next.ServeHTTP(wrapped, r) + + statusCode, writeErr := httpCode, httpErr.Err() + + requestLog = log.With(requestLog, "method", r.Method, "uri", uri, "status", statusCode, "duration", time.Since(begin), "proto", r.Proto) + + if l.LogRequestHeaders { + requestLog = log.With(requestLog, headerFields...) + } + if rBody.read > 0 { + requestLog = log.With(requestLog, "request_body_size", rBody.read) + if rBody.duration > 0 { + requestLog = log.With(requestLog, "request_body_read_duration", rBody.duration) + } + } + + requestLvl := level.Debug + if l.LogRequestAtInfoLevel { + requestLvl = level.Info + } + + // log successful requests + if writeErr == nil && (100 <= statusCode && statusCode < 400) { + requestLvl(requestLog).Log("msg", "http request processed") + return + } + + // context cancelled is not considered a failure + if writeErr != nil && errors.Is(writeErr, context.Canceled) { + requestLvl(requestLog).Log("msg", "request cancelled") + return + } + + // add request headers if not anyhow added + if !l.LogRequestHeaders { + requestLog = log.With(requestLog, headerFields...) + } + + // writeError shouldn't log the body + if writeErr != nil { + level.Warn(requestLog).Log("msg", "http request failed", "err", writeErr) + return + } + + level.Warn(requestLog).Log("msg", "http request failed", "response_body", buf.Bytes()) + }) +} + +func captureResponseBody(data []byte, bodyBytesLeft int, buf *bytes.Buffer) int { + if bodyBytesLeft <= 0 { + return 0 + } + if len(data) > bodyBytesLeft { + buf.Write(data[:bodyBytesLeft]) + _, _ = io.WriteString(buf, "...") + return 0 + } + + buf.Write(data) + return bodyBytesLeft - len(data) +} diff --git a/pkg/util/http/metrics.go b/pkg/util/http/metrics.go new file mode 100644 index 0000000000..c03f926772 --- /dev/null +++ b/pkg/util/http/metrics.go @@ -0,0 +1,93 @@ +package http + +import ( + "time" + + "github.com/gorilla/mux" + "github.com/grafana/dskit/instrument" + "github.com/grafana/dskit/middleware" + "github.com/prometheus/client_golang/prometheus" +) + +// NewHTTPMetricMiddleware creates a new middleware that automatically instruments HTTP requests from the given router. +func NewHTTPMetricMiddleware(mux *mux.Router, namespace string, reg prometheus.Registerer) (middleware.Interface, error) { + // Prometheus histograms for requests. + requestDuration := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: namespace, + Name: "request_duration_seconds", + Help: "Time (in seconds) spent serving HTTP requests.", + Buckets: instrument.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"method", "route", "status_code", "ws"}) + err := reg.Register(requestDuration) + if err != nil { + already, ok := err.(prometheus.AlreadyRegisteredError) + if ok { + requestDuration = already.ExistingCollector.(*prometheus.HistogramVec) + } else { + return nil, err + } + } + + receivedMessageSize := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: namespace, + Name: "request_message_bytes", + Help: "Size (in bytes) of messages received in the request.", + Buckets: middleware.BodySizeBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"method", "route"}) + err = reg.Register(receivedMessageSize) + if err != nil { + already, ok := err.(prometheus.AlreadyRegisteredError) + if ok { + receivedMessageSize = already.ExistingCollector.(*prometheus.HistogramVec) + } else { + return nil, err + } + } + + sentMessageSize := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: namespace, + Name: "response_message_bytes", + Help: "Size (in bytes) of messages sent in response.", + Buckets: middleware.BodySizeBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 50, + NativeHistogramMinResetDuration: time.Hour, + }, []string{"method", "route"}) + + err = reg.Register(sentMessageSize) + if err != nil { + already, ok := err.(prometheus.AlreadyRegisteredError) + if ok { + sentMessageSize = already.ExistingCollector.(*prometheus.HistogramVec) + } else { + return nil, err + } + } + + inflightRequests := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: namespace, + Name: "inflight_requests", + Help: "Current number of inflight requests.", + }, []string{"method", "route"}) + err = reg.Register(inflightRequests) + if err != nil { + already, ok := err.(prometheus.AlreadyRegisteredError) + if ok { + inflightRequests = already.ExistingCollector.(*prometheus.GaugeVec) + } else { + return nil, err + } + } + return middleware.Instrument{ + Duration: requestDuration, + RequestBodySize: receivedMessageSize, + ResponseBodySize: sentMessageSize, + InflightRequests: inflightRequests, + }, nil +} diff --git a/pkg/util/http/middleware.go b/pkg/util/http/middleware.go new file mode 100644 index 0000000000..69b247f5d9 --- /dev/null +++ b/pkg/util/http/middleware.go @@ -0,0 +1,16 @@ +package http + +import ( + "net/http" + + "github.com/grafana/dskit/middleware" + "github.com/grafana/pyroscope-go/x/k6" +) + +// K6Middleware creates a middleware that extracts k6 load test labels from the +// request baggage and adds them as dynamic profiling labels. +func K6Middleware() middleware.Interface { + return middleware.Func(func(h http.Handler) http.Handler { + return k6.LabelsFromBaggageHandler(h) + }) +} diff --git a/pkg/util/http/response.go b/pkg/util/http/response.go new file mode 100644 index 0000000000..08db29d748 --- /dev/null +++ b/pkg/util/http/response.go @@ -0,0 +1,76 @@ +package http + +import ( + "encoding/json" + "html/template" + "net/http" + "strings" + + "go.yaml.in/yaml/v3" +) + +// WriteYAMLResponse writes some YAML as a HTTP response. +func WriteYAMLResponse(w http.ResponseWriter, v interface{}) { + // There is not standardised content-type for YAML, text/plain ensures the + // YAML is displayed in the browser instead of offered as a download + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + + data, err := yaml.Marshal(v) + if err != nil { + Error(w, err) + return + } + + // We ignore errors here, because we cannot do anything about them. + // Write will trigger sending Status code, so we cannot send a different status code afterwards. + // Also this isn't internal error, but error communicating with client. + _, _ = w.Write(data) +} + +// WriteHTMLResponse sends message as text/html response with 200 status code. +func WriteHTMLResponse(w http.ResponseWriter, message string) { + w.Header().Set("Content-Type", "text/html") + + // Ignore inactionable errors. + _, _ = w.Write([]byte(message)) +} + +// WriteTextResponse sends message as text/plain response with 200 status code. +func WriteTextResponse(w http.ResponseWriter, message string) { + w.Header().Set("Content-Type", "text/plain") + + // Ignore inactionable errors. + _, _ = w.Write([]byte(message)) +} + +// RenderHTTPResponse either responds with JSON or a rendered HTML page using the passed in template +// by checking the Accepts header. +func RenderHTTPResponse(w http.ResponseWriter, v interface{}, t *template.Template, r *http.Request) { + accept := r.Header.Get("Accept") + if strings.Contains(accept, "application/json") { + WriteJSONResponse(w, v) + return + } + + w.Header().Set("Content-Type", "text/html; charset=utf-8") + err := t.Execute(w, v) + if err != nil { + Error(w, err) + } +} + +// WriteJSONResponse writes some JSON as a HTTP response. +func WriteJSONResponse(w http.ResponseWriter, v interface{}) { + w.Header().Set("Content-Type", "application/json") + + data, err := json.Marshal(v) + if err != nil { + Error(w, err) + return + } + + // We ignore errors here, because we cannot do anything about them. + // Write will trigger sending Status code, so we cannot send a different status code afterwards. + // Also this isn't internal error, but error communicating with client. + _, _ = w.Write(data) +} diff --git a/pkg/util/http/server/server.go b/pkg/util/http/server/server.go new file mode 100644 index 0000000000..d0e2dc7d4b --- /dev/null +++ b/pkg/util/http/server/server.go @@ -0,0 +1,12 @@ +package server + +import "net/http" + +// EnableHTTP2 enables HTTP/1, TLS HTTP/2, and cleartext HTTP/2 on a server. +func EnableHTTP2(server *http.Server) { + protocols := new(http.Protocols) + protocols.SetHTTP1(true) + protocols.SetHTTP2(true) + protocols.SetUnencryptedHTTP2(true) + server.Protocols = protocols +} diff --git a/pkg/util/http_test.go b/pkg/util/http_test.go deleted file mode 100644 index a0c555c735..0000000000 --- a/pkg/util/http_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package util_test - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/grafana/pyroscope/pkg/tenant" - "github.com/grafana/pyroscope/pkg/util" -) - -func TestWriteTextResponse(t *testing.T) { - w := httptest.NewRecorder() - - util.WriteTextResponse(w, "hello world") - - assert.Equal(t, 200, w.Code) - assert.Equal(t, "hello world", w.Body.String()) - assert.Equal(t, "text/plain", w.Header().Get("Content-Type")) -} - -func TestMultitenantMiddleware(t *testing.T) { - w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "http://localhost:8080", nil) - - // No org ID header. - m := util.AuthenticateUser(true).Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - id, err := tenant.ExtractTenantIDFromContext(r.Context()) - require.NoError(t, err) - assert.Equal(t, "1", id) - })) - m.ServeHTTP(w, r) - assert.Equal(t, http.StatusUnauthorized, w.Code) - - w = httptest.NewRecorder() - r.Header.Set("X-Scope-OrgID", "1") - m.ServeHTTP(w, r) - assert.Equal(t, http.StatusOK, w.Code) - - // No org ID header without auth. - r = httptest.NewRequest("GET", "http://localhost:8080", nil) - m = util.AuthenticateUser(false).Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - id, err := tenant.ExtractTenantIDFromContext(r.Context()) - require.NoError(t, err) - assert.Equal(t, tenant.DefaultTenantID, id) - })) - m.ServeHTTP(w, r) - assert.Equal(t, http.StatusOK, w.Code) -} diff --git a/pkg/util/httpgrpc/httpgrpc.go b/pkg/util/httpgrpc/httpgrpc.go index c79e3a0971..bf6a0d183b 100644 --- a/pkg/util/httpgrpc/httpgrpc.go +++ b/pkg/util/httpgrpc/httpgrpc.go @@ -2,8 +2,8 @@ package httpgrpc import ( "fmt" + "log/slog" - log "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" @@ -44,7 +44,7 @@ func HTTPResponseFromError(err error) (*HTTPResponse, bool) { var resp HTTPResponse if err := anypb.UnmarshalTo(status.Details[0], &resp, proto.UnmarshalOptions{}); err != nil { - log.Errorf("Got error containing non-response: %v", err) + slog.Error("got error containing non-response", "err", err) return nil, false } diff --git a/pkg/util/httpgrpc/httpgrpc.pb.go b/pkg/util/httpgrpc/httpgrpc.pb.go index 41d98cb476..b0a0ea4066 100644 --- a/pkg/util/httpgrpc/httpgrpc.pb.go +++ b/pkg/util/httpgrpc/httpgrpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.36.11 // protoc (unknown) // source: util/httpgrpc/httpgrpc.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,23 +22,20 @@ const ( ) type HTTPRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + Headers []*Header `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty"` + Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` unknownFields protoimpl.UnknownFields - - Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - Headers []*Header `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty"` - Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HTTPRequest) Reset() { *x = HTTPRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *HTTPRequest) String() string { @@ -48,7 +46,7 @@ func (*HTTPRequest) ProtoMessage() {} func (x *HTTPRequest) ProtoReflect() protoreflect.Message { mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -92,22 +90,19 @@ func (x *HTTPRequest) GetBody() []byte { } type HTTPResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Code int32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` + Headers []*Header `protobuf:"bytes,2,rep,name=headers,proto3" json:"headers,omitempty"` + Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` unknownFields protoimpl.UnknownFields - - Code int32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` - Headers []*Header `protobuf:"bytes,2,rep,name=headers,proto3" json:"headers,omitempty"` - Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HTTPResponse) Reset() { *x = HTTPResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *HTTPResponse) String() string { @@ -118,7 +113,7 @@ func (*HTTPResponse) ProtoMessage() {} func (x *HTTPResponse) ProtoReflect() protoreflect.Message { mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -155,21 +150,18 @@ func (x *HTTPResponse) GetBody() []byte { } type Header struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"` unknownFields protoimpl.UnknownFields - - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Header) Reset() { *x = Header{} - if protoimpl.UnsafeEnabled { - mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Header) String() string { @@ -180,7 +172,7 @@ func (*Header) ProtoMessage() {} func (x *Header) ProtoReflect() protoreflect.Message { mi := &file_util_httpgrpc_httpgrpc_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -211,57 +203,39 @@ func (x *Header) GetValues() []string { var File_util_httpgrpc_httpgrpc_proto protoreflect.FileDescriptor -var file_util_httpgrpc_httpgrpc_proto_rawDesc = []byte{ - 0x0a, 0x1c, 0x75, 0x74, 0x69, 0x6c, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2f, - 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, - 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x22, 0x77, 0x0a, 0x0b, 0x48, 0x54, 0x54, 0x50, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, - 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, - 0x6c, 0x12, 0x2a, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, - 0x79, 0x22, 0x62, 0x0a, 0x0c, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x32, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x32, 0x41, 0x0a, 0x04, 0x48, 0x54, 0x54, - 0x50, 0x12, 0x39, 0x0a, 0x06, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x15, 0x2e, 0x68, 0x74, - 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x54, - 0x54, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x8d, 0x01, 0x0a, - 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x42, 0x0d, 0x48, - 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, - 0x6e, 0x61, 0x2f, 0x70, 0x79, 0x72, 0x6f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2f, 0x70, 0x6b, 0x67, - 0x2f, 0x75, 0x74, 0x69, 0x6c, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0xa2, 0x02, - 0x03, 0x48, 0x58, 0x58, 0xaa, 0x02, 0x08, 0x48, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0xca, - 0x02, 0x08, 0x48, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0xe2, 0x02, 0x14, 0x48, 0x74, 0x74, - 0x70, 0x67, 0x72, 0x70, 0x63, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x08, 0x48, 0x74, 0x74, 0x70, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, -} +const file_util_httpgrpc_httpgrpc_proto_rawDesc = "" + + "\n" + + "\x1cutil/httpgrpc/httpgrpc.proto\x12\bhttpgrpc\"w\n" + + "\vHTTPRequest\x12\x16\n" + + "\x06method\x18\x01 \x01(\tR\x06method\x12\x10\n" + + "\x03url\x18\x02 \x01(\tR\x03url\x12*\n" + + "\aheaders\x18\x03 \x03(\v2\x10.httpgrpc.HeaderR\aheaders\x12\x12\n" + + "\x04body\x18\x04 \x01(\fR\x04body\"b\n" + + "\fHTTPResponse\x12\x12\n" + + "\x04Code\x18\x01 \x01(\x05R\x04Code\x12*\n" + + "\aheaders\x18\x02 \x03(\v2\x10.httpgrpc.HeaderR\aheaders\x12\x12\n" + + "\x04body\x18\x03 \x01(\fR\x04body\"2\n" + + "\x06Header\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x16\n" + + "\x06values\x18\x02 \x03(\tR\x06values2A\n" + + "\x04HTTP\x129\n" + + "\x06Handle\x12\x15.httpgrpc.HTTPRequest\x1a\x16.httpgrpc.HTTPResponse\"\x00B\x90\x01\n" + + "\fcom.httpgrpcB\rHttpgrpcProtoP\x01Z1github.com/grafana/pyroscope/v2/pkg/util/httpgrpc\xa2\x02\x03HXX\xaa\x02\bHttpgrpc\xca\x02\bHttpgrpc\xe2\x02\x14Httpgrpc\\GPBMetadata\xea\x02\bHttpgrpcb\x06proto3" var ( file_util_httpgrpc_httpgrpc_proto_rawDescOnce sync.Once - file_util_httpgrpc_httpgrpc_proto_rawDescData = file_util_httpgrpc_httpgrpc_proto_rawDesc + file_util_httpgrpc_httpgrpc_proto_rawDescData []byte ) func file_util_httpgrpc_httpgrpc_proto_rawDescGZIP() []byte { file_util_httpgrpc_httpgrpc_proto_rawDescOnce.Do(func() { - file_util_httpgrpc_httpgrpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_util_httpgrpc_httpgrpc_proto_rawDescData) + file_util_httpgrpc_httpgrpc_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_util_httpgrpc_httpgrpc_proto_rawDesc), len(file_util_httpgrpc_httpgrpc_proto_rawDesc))) }) return file_util_httpgrpc_httpgrpc_proto_rawDescData } var file_util_httpgrpc_httpgrpc_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_util_httpgrpc_httpgrpc_proto_goTypes = []interface{}{ +var file_util_httpgrpc_httpgrpc_proto_goTypes = []any{ (*HTTPRequest)(nil), // 0: httpgrpc.HTTPRequest (*HTTPResponse)(nil), // 1: httpgrpc.HTTPResponse (*Header)(nil), // 2: httpgrpc.Header @@ -283,49 +257,11 @@ func file_util_httpgrpc_httpgrpc_proto_init() { if File_util_httpgrpc_httpgrpc_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_util_httpgrpc_httpgrpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HTTPRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_util_httpgrpc_httpgrpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HTTPResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_util_httpgrpc_httpgrpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Header); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_util_httpgrpc_httpgrpc_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_util_httpgrpc_httpgrpc_proto_rawDesc), len(file_util_httpgrpc_httpgrpc_proto_rawDesc)), NumEnums: 0, NumMessages: 3, NumExtensions: 0, @@ -336,7 +272,6 @@ func file_util_httpgrpc_httpgrpc_proto_init() { MessageInfos: file_util_httpgrpc_httpgrpc_proto_msgTypes, }.Build() File_util_httpgrpc_httpgrpc_proto = out.File - file_util_httpgrpc_httpgrpc_proto_rawDesc = nil file_util_httpgrpc_httpgrpc_proto_goTypes = nil file_util_httpgrpc_httpgrpc_proto_depIdxs = nil } diff --git a/pkg/util/httpgrpc/httpgrpcconnect/httpgrpc.connect.go b/pkg/util/httpgrpc/httpgrpcconnect/httpgrpc.connect.go index 071bbc9959..cbed16066c 100644 --- a/pkg/util/httpgrpc/httpgrpcconnect/httpgrpc.connect.go +++ b/pkg/util/httpgrpc/httpgrpcconnect/httpgrpc.connect.go @@ -8,7 +8,7 @@ import ( connect "connectrpc.com/connect" context "context" errors "errors" - httpgrpc "github.com/grafana/pyroscope/pkg/util/httpgrpc" + httpgrpc "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" http "net/http" strings "strings" ) @@ -37,12 +37,6 @@ const ( HTTPHandleProcedure = "/httpgrpc.HTTP/Handle" ) -// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. -var ( - hTTPServiceDescriptor = httpgrpc.File_util_httpgrpc_httpgrpc_proto.Services().ByName("HTTP") - hTTPHandleMethodDescriptor = hTTPServiceDescriptor.Methods().ByName("Handle") -) - // HTTPClient is a client for the httpgrpc.HTTP service. type HTTPClient interface { Handle(context.Context, *connect.Request[httpgrpc.HTTPRequest]) (*connect.Response[httpgrpc.HTTPResponse], error) @@ -57,11 +51,12 @@ type HTTPClient interface { // http://api.acme.com or https://acme.com/grpc). func NewHTTPClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) HTTPClient { baseURL = strings.TrimRight(baseURL, "/") + hTTPMethods := httpgrpc.File_util_httpgrpc_httpgrpc_proto.Services().ByName("HTTP").Methods() return &hTTPClient{ handle: connect.NewClient[httpgrpc.HTTPRequest, httpgrpc.HTTPResponse]( httpClient, baseURL+HTTPHandleProcedure, - connect.WithSchema(hTTPHandleMethodDescriptor), + connect.WithSchema(hTTPMethods.ByName("Handle")), connect.WithClientOptions(opts...), ), } @@ -88,10 +83,11 @@ type HTTPHandler interface { // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. func NewHTTPHandler(svc HTTPHandler, opts ...connect.HandlerOption) (string, http.Handler) { + hTTPMethods := httpgrpc.File_util_httpgrpc_httpgrpc_proto.Services().ByName("HTTP").Methods() hTTPHandleHandler := connect.NewUnaryHandler( HTTPHandleProcedure, svc.Handle, - connect.WithSchema(hTTPHandleMethodDescriptor), + connect.WithSchema(hTTPMethods.ByName("Handle")), connect.WithHandlerOptions(opts...), ) return "/httpgrpc.HTTP/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/util/httpgrpcutil/carrier.go b/pkg/util/httpgrpcutil/carrier.go index bcb44571bf..f8b398190e 100644 --- a/pkg/util/httpgrpcutil/carrier.go +++ b/pkg/util/httpgrpcutil/carrier.go @@ -6,16 +6,18 @@ package httpgrpcutil import ( - "errors" + "context" + "strings" - "github.com/opentracing/opentracing-go" + "go.opentelemetry.io/otel" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) -// Used to transfer trace information from/to HTTP request. +// HttpgrpcHeadersCarrier implements propagation.TextMapCarrier for OTel trace context propagation over httpgrpc requests. type HttpgrpcHeadersCarrier httpgrpc.HTTPRequest +// Set implements propagation.TextMapCarrier for OTel. func (c *HttpgrpcHeadersCarrier) Set(key, val string) { c.Headers = append(c.Headers, &httpgrpc.Header{ Key: key, @@ -23,26 +25,28 @@ func (c *HttpgrpcHeadersCarrier) Set(key, val string) { }) } -func (c *HttpgrpcHeadersCarrier) ForeachKey(handler func(key, val string) error) error { +// Get implements propagation.TextMapCarrier for OTel. +func (c *HttpgrpcHeadersCarrier) Get(key string) string { for _, h := range c.Headers { - for _, v := range h.Values { - if err := handler(h.Key, v); err != nil { - return err - } + if strings.EqualFold(h.Key, key) && len(h.Values) > 0 { + return h.Values[0] } } - return nil + return "" } -func GetParentSpanForRequest(tracer opentracing.Tracer, req *httpgrpc.HTTPRequest) (opentracing.SpanContext, error) { - if tracer == nil { - return nil, nil +// Keys implements propagation.TextMapCarrier for OTel. +func (c *HttpgrpcHeadersCarrier) Keys() []string { + keys := make([]string, len(c.Headers)) + for i, h := range c.Headers { + keys[i] = h.Key } + return keys +} +// GetParentContextForRequest extracts parent trace context from HTTP request +// headers and attaches it to the provided context using OTel propagation. +func GetParentContextForRequest(ctx context.Context, req *httpgrpc.HTTPRequest) context.Context { carrier := (*HttpgrpcHeadersCarrier)(req) - extracted, err := tracer.Extract(opentracing.HTTPHeaders, carrier) - if errors.Is(err, opentracing.ErrSpanContextNotFound) { - err = nil - } - return extracted, err + return otel.GetTextMapPropagator().Extract(ctx, carrier) } diff --git a/pkg/util/httpgrpcutil/errors.go b/pkg/util/httpgrpcutil/errors.go index 4da6791ee4..c91c8455db 100644 --- a/pkg/util/httpgrpcutil/errors.go +++ b/pkg/util/httpgrpcutil/errors.go @@ -5,7 +5,7 @@ package httpgrpcutil import ( "net/http" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) // PrioritizeRecoverableErr checks whether in the given slice of errors there is a recoverable error, if yes then it will diff --git a/pkg/util/httpgrpcutil/errors_test.go b/pkg/util/httpgrpcutil/errors_test.go index f935278bca..1a647134a8 100644 --- a/pkg/util/httpgrpcutil/errors_test.go +++ b/pkg/util/httpgrpcutil/errors_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/util/httpgrpc" + "github.com/grafana/pyroscope/v2/pkg/util/httpgrpc" ) func TestPrioritizeRecoverableErr(t *testing.T) { diff --git a/pkg/util/inflight_requets.go b/pkg/util/inflight_requets.go new file mode 100644 index 0000000000..997f870387 --- /dev/null +++ b/pkg/util/inflight_requets.go @@ -0,0 +1,60 @@ +package util + +import ( + "sync" +) + +// InflightRequests utility emerged due to the need to handle request draining +// at the service level. +// +// Ideally, this should be the responsibility of the server using the service. +// However, since the server is a dependency of the service and is only shut +// down after the service is stopped, requests may still arrive after the Stop +// call. This issue arises from how we initialize modules. +// +// In other scenarios, request draining could be managed at a higher level, +// such as in a load balancer or service discovery mechanism. The goal would +// be to stop routing requests to an instance that is about to shut down. +// +// In our case, service instances that are not directly exposed to the outside +// world but are discoverable via e.g, ring, kubernetes, or DNS. There's no a +// _reliable_ mechanism to ensure that all the clients are aware of fact that +// the instance is leaving, so requests may continue to arrive within a short +// period of time. InflightRequests ensure that such requests will be rejected. +type InflightRequests struct { + mu sync.RWMutex + wg sync.WaitGroup + allowed bool +} + +// Open allows new requests. +func (r *InflightRequests) Open() { + r.mu.Lock() + r.allowed = true + r.mu.Unlock() +} + +// Add adds a new request if allowed. +func (r *InflightRequests) Add() bool { + r.mu.RLock() + defer r.mu.RUnlock() + if !r.allowed { + return false + } + r.wg.Add(1) + return true +} + +// Done completes a request. +func (r *InflightRequests) Done() { + r.wg.Done() +} + +// Drain prevents new requests from being accepted +// and waits for all ongoing requests to complete. +func (r *InflightRequests) Drain() { + r.mu.Lock() + r.allowed = false + r.mu.Unlock() + r.wg.Wait() +} diff --git a/pkg/util/interceptor.go b/pkg/util/interceptor.go index c4437a1d93..54a4e93d7f 100644 --- a/pkg/util/interceptor.go +++ b/pkg/util/interceptor.go @@ -9,7 +9,7 @@ import ( "github.com/go-kit/log/level" "github.com/grafana/dskit/tracing" - "github.com/grafana/pyroscope/pkg/tenant" + "github.com/grafana/pyroscope/v2/pkg/tenant" ) type timeoutInterceptor struct { @@ -68,7 +68,6 @@ func NewLogInterceptor(logger log.Logger) connect.UnaryInterceptorFunc { "route", req.Spec().Procedure, "tenant", tenantID, "traceID", traceID, - "parameters", req.Any(), "duration", time.Since(begin), ) }() diff --git a/pkg/util/labels.go b/pkg/util/labels.go deleted file mode 100644 index 82c0fa88ce..0000000000 --- a/pkg/util/labels.go +++ /dev/null @@ -1,35 +0,0 @@ -package util - -import ( - "github.com/cespare/xxhash/v2" - "github.com/prometheus/prometheus/model/labels" -) - -var seps = []byte{'\xff'} - -// StableHash is a labels hashing implementation which is guaranteed to not change over time. -// This function should be used whenever labels hashing backward compatibility must be guaranteed. -func StableHash(ls labels.Labels) uint64 { - // Use xxhash.Sum64(b) for fast path as it's faster. - b := make([]byte, 0, 1024) - for i, v := range ls { - if len(b)+len(v.Name)+len(v.Value)+2 >= cap(b) { - // If labels entry is 1KB+ do not allocate whole entry. - h := xxhash.New() - _, _ = h.Write(b) - for _, v := range ls[i:] { - _, _ = h.WriteString(v.Name) - _, _ = h.Write(seps) - _, _ = h.WriteString(v.Value) - _, _ = h.Write(seps) - } - return h.Sum64() - } - - b = append(b, v.Name...) - b = append(b, seps[0]) - b = append(b, v.Value...) - b = append(b, seps[0]) - } - return xxhash.Sum64(b) -} diff --git a/pkg/util/logger.go b/pkg/util/logger.go index 64549f7878..1510256c3e 100644 --- a/pkg/util/logger.go +++ b/pkg/util/logger.go @@ -1,14 +1,19 @@ package util import ( + "bytes" "context" + "io" + "os" + "sync" + "time" "github.com/go-kit/log" "github.com/grafana/dskit/tenant" "github.com/grafana/dskit/tracing" ) -// Logger is a global logger to use only where you cannot inject a logger. +// Logger is a nop global logger var Logger = log.NewNopLogger() // LoggerWithUserID returns a Logger that has information about the current user in @@ -60,3 +65,124 @@ func LoggerWithContext(ctx context.Context, l log.Logger) log.Logger { func WithSourceIPs(sourceIPs string, l log.Logger) log.Logger { return log.With(l, "sourceIPs", sourceIPs) } + +// AsyncWriter is a writer that buffers writes and flushes them asynchronously +// in the order they were written. It is safe for concurrent use. +// +// If the internal queue is full, writes will block until there is space. +// Errors are ignored: it's caller responsibility to handle errors from the +// underlying writer. +type AsyncWriter struct { + mu sync.Mutex + w io.Writer + pool sync.Pool + buffer *bytes.Buffer + flushQueue chan *bytes.Buffer + maxSize int + maxCount int + flushInterval time.Duration + writes int + closeOnce sync.Once + close chan struct{} + done chan error + closed bool +} + +func NewAsyncWriter(w io.Writer, bufSize, maxBuffers, maxWrites int, flushInterval time.Duration) *AsyncWriter { + bw := &AsyncWriter{ + w: w, + flushQueue: make(chan *bytes.Buffer, maxBuffers), + maxSize: bufSize, + maxCount: maxWrites, + flushInterval: flushInterval, + close: make(chan struct{}), + done: make(chan error), + pool: sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(make([]byte, 0, bufSize)) + }, + }, + } + go bw.loop() + return bw +} + +func (aw *AsyncWriter) Write(p []byte) (int, error) { + aw.mu.Lock() + defer aw.mu.Unlock() + if aw.closed { + return 0, os.ErrClosed + } + if aw.overflows(len(p)) { + aw.enqueueFlush() + } + if aw.buffer == nil { + aw.buffer = aw.pool.Get().(*bytes.Buffer) + aw.buffer.Reset() + } + aw.writes++ + return aw.buffer.Write(p) +} + +func (aw *AsyncWriter) overflows(n int) bool { + return aw.buffer != nil && (aw.buffer.Len()+n >= aw.maxSize || aw.writes >= aw.maxCount) +} + +func (aw *AsyncWriter) Close() error { + aw.closeOnce.Do(func() { + // Break the loop. + close(aw.close) + <-aw.done + // Empty the queue. + aw.mu.Lock() + defer aw.mu.Unlock() + aw.enqueueFlush() + close(aw.flushQueue) + for buf := range aw.flushQueue { + aw.flushSync(buf) + } + aw.closed = true + }) + return nil +} + +func (aw *AsyncWriter) enqueueFlush() { + buf := aw.buffer + if buf == nil || buf.Len() == 0 { + return + } + aw.buffer = nil + aw.writes = 0 + select { + case aw.flushQueue <- buf: + default: + } +} + +func (aw *AsyncWriter) loop() { + ticker := time.NewTicker(aw.flushInterval) + defer func() { + ticker.Stop() + close(aw.done) + }() + + for { + select { + case buf := <-aw.flushQueue: + aw.flushSync(buf) + + case <-ticker.C: + aw.mu.Lock() + aw.enqueueFlush() + aw.mu.Unlock() + + case <-aw.close: + return + } + } +} + +func (aw *AsyncWriter) flushSync(b *bytes.Buffer) { + _, _ = aw.w.Write(b.Bytes()) + aw.pool.Put(b) +} diff --git a/pkg/util/logger_test.go b/pkg/util/logger_test.go new file mode 100644 index 0000000000..e81dc90b62 --- /dev/null +++ b/pkg/util/logger_test.go @@ -0,0 +1,64 @@ +package util + +import ( + "bytes" + "fmt" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAsyncWriter_Write(t *testing.T) { + var buf bytes.Buffer + w := NewAsyncWriter(&buf, 10, 2, 2, 100*time.Millisecond) + n, err := w.Write([]byte("hello")) + require.NoError(t, err) + assert.Equal(t, 5, n) + assert.NoError(t, w.Close()) + assert.Equal(t, "hello", buf.String()) +} + +func TestAsyncWriter_Empty(t *testing.T) { + var buf bytes.Buffer + w := NewAsyncWriter(&buf, 10, 2, 2, 100*time.Millisecond) + assert.NoError(t, w.Close()) + assert.EqualValues(t, 0, buf.Len()) +} + +func TestAsyncWriter_Overflow(t *testing.T) { + var buf bytes.Buffer + w := NewAsyncWriter(&buf, 10, 2, 2, 100*time.Millisecond) + _, _ = w.Write([]byte("hello")) + _, _ = w.Write([]byte("world")) + assert.NoError(t, w.Close()) + assert.Equal(t, "helloworld", buf.String()) +} + +func TestAsyncWriter_Close(t *testing.T) { + var buf bytes.Buffer + w := NewAsyncWriter(&buf, 10, 2, 2, 100*time.Millisecond) + _, _ = w.Write([]byte("hello")) + assert.NoError(t, w.Close()) + assert.Equal(t, "hello", buf.String()) + assert.NoError(t, w.Close()) +} + +func TestAsyncWriter_ConcurrentWrites(t *testing.T) { + var buf bytes.Buffer + w := NewAsyncWriter(&buf, 50, 2, 10, 100*time.Millisecond) + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + _, _ = fmt.Fprintf(w, "hello %d\n", i) + }(i) + } + wg.Wait() + + assert.NoError(t, w.Close()) + assert.Equal(t, 80, buf.Len()) +} diff --git a/pkg/util/loser/tree_test.go b/pkg/util/loser/tree_test.go index cdf6767be6..1038e4c72e 100644 --- a/pkg/util/loser/tree_test.go +++ b/pkg/util/loser/tree_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/util/loser" + "github.com/grafana/pyroscope/v2/pkg/util/loser" ) type List struct { @@ -167,13 +167,13 @@ func TestInitWithErr(t *testing.T) { NewList(), NewList(5, 6, 7, 8), } - lists[0].err = testErr + lists[0].err = errTest tree := loser.New(lists, math.MaxUint64, func(s *List) uint64 { return s.At() }, func(a, b uint64) bool { return a < b }, func(s *List) { s.Close() }) if tree.Next() { t.Errorf("Next() should have returned false") } - if tree.Err() != testErr { - t.Errorf("Err() should have returned %v, got %v", testErr, tree.Err()) + if tree.Err() != errTest { + t.Errorf("Err() should have returned %v, got %v", errTest, tree.Err()) } tree.Close() @@ -183,7 +183,7 @@ func TestInitWithErr(t *testing.T) { } -var testErr = errors.New("test") +var errTest = errors.New("test") func TestErrDuringNext(t *testing.T) { lists := []*List{ @@ -197,12 +197,12 @@ func TestErrDuringNext(t *testing.T) { t.Errorf("Next() should have returned true") } // now error for second - lists[0].err = testErr + lists[0].err = errTest if tree.Next() { t.Errorf("Next() should have returned false") } - if tree.Err() != testErr { - t.Errorf("Err() should have returned %v, got %v", testErr, tree.Err()) + if tree.Err() != errTest { + t.Errorf("Err() should have returned %v, got %v", errTest, tree.Err()) } if tree.Next() { t.Errorf("Next() should have returned false") diff --git a/pkg/util/math/math.go b/pkg/util/math/math.go deleted file mode 100644 index 45acfb5b7d..0000000000 --- a/pkg/util/math/math.go +++ /dev/null @@ -1,19 +0,0 @@ -package math - -import ( - "golang.org/x/exp/constraints" -) - -func Min[T constraints.Ordered](a, b T) T { - if a < b { - return a - } - return b -} - -func Max[T constraints.Ordered](a, b T) T { - if a > b { - return a - } - return b -} diff --git a/pkg/util/minheap/minheap.go b/pkg/util/minheap/minheap.go new file mode 100644 index 0000000000..b5baaf24cd --- /dev/null +++ b/pkg/util/minheap/minheap.go @@ -0,0 +1,51 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package minheap + +func Push(h []int64, x int64) []int64 { + h = append(h, x) + up(h, len(h)-1) + return h +} + +func Pop(h []int64) []int64 { + n := len(h) - 1 + h[0], h[n] = h[n], h[0] + down(h, 0, n) + n = len(h) + h = h[0 : n-1] + return h +} + +func up(h []int64, j int) { + for { + i := (j - 1) / 2 // parent + if i == j || (h[j] >= h[i]) { + break + } + h[i], h[j] = h[j], h[i] + j = i + } +} + +func down(h []int64, i0, n int) bool { + i := i0 + for { + j1 := 2*i + 1 + if j1 >= n || j1 < 0 { // j1 < 0 after int overflow + break + } + j := j1 // left child + if j2 := j1 + 1; j2 < n && h[j2] < h[j1] { + j = j2 // = 2*i + 2 // right child + } + if h[j] >= h[i] { + break + } + h[i], h[j] = h[j], h[i] + i = j + } + return i > i0 +} diff --git a/pkg/util/net.go b/pkg/util/net.go deleted file mode 100644 index 07e8f79682..0000000000 --- a/pkg/util/net.go +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/util/net.go -// Provenance-includes-license: Apache-2.0 -// Provenance-includes-copyright: The Cortex Authors. - -package util - -import ( - "fmt" - "net" - "strings" - - "github.com/go-kit/log/level" -) - -// GetFirstAddressOf returns the first IPv4 address of the supplied interface names, omitting any 169.254.x.x automatic private IPs if possible. -func GetFirstAddressOf(names []string) (string, error) { - var ipAddr string - for _, name := range names { - inf, err := net.InterfaceByName(name) - if err != nil { - level.Warn(Logger).Log("msg", "error getting interface", "inf", name, "err", err) - continue - } - addrs, err := inf.Addrs() - if err != nil { - level.Warn(Logger).Log("msg", "error getting addresses for interface", "inf", name, "err", err) - continue - } - if len(addrs) <= 0 { - level.Warn(Logger).Log("msg", "no addresses found for interface", "inf", name, "err", err) - continue - } - if ip := filterIPs(addrs); ip != "" { - ipAddr = ip - } - if strings.HasPrefix(ipAddr, `169.254.`) || ipAddr == "" { - continue - } - return ipAddr, nil - } - if ipAddr == "" { - return "", fmt.Errorf("No address found for %s", names) - } - if strings.HasPrefix(ipAddr, `169.254.`) { - level.Warn(Logger).Log("msg", "using automatic private ip", "address", ipAddr) - } - return ipAddr, nil -} - -// filterIPs attempts to return the first non automatic private IP (APIPA / 169.254.x.x) if possible, only returning APIPA if available and no other valid IP is found. -func filterIPs(addrs []net.Addr) string { - var ipAddr string - for _, addr := range addrs { - if v, ok := addr.(*net.IPNet); ok { - if ip := v.IP.To4(); ip != nil { - ipAddr = v.IP.String() - if !strings.HasPrefix(ipAddr, `169.254.`) { - return ipAddr - } - } - } - } - return ipAddr -} diff --git a/pkg/util/nethttp/client.go b/pkg/util/nethttp/client.go deleted file mode 100644 index 15833102a4..0000000000 --- a/pkg/util/nethttp/client.go +++ /dev/null @@ -1,211 +0,0 @@ -package nethttp - -import ( - "context" - "io" - "net/http" - "net/http/httptrace" - - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/opentracing/opentracing-go/log" -) - -type contextKey int - -const ( - keyTracer contextKey = iota - componentName = "pyroscope/net/http" -) - -type Transport struct { - // The actual RoundTripper to use for the request. A nil RoundTripper defaults to http.DefaultTransport. - http.RoundTripper -} - -func TraceRequest(tr opentracing.Tracer, req *http.Request) *http.Request { - ht := &Tracer{tr: tr} - ctx := req.Context() - ctx = httptrace.WithClientTrace(ctx, ht.clientTrace()) - req = req.WithContext(context.WithValue(ctx, keyTracer, ht)) - return req -} - -type closeTracker struct { - io.ReadCloser - sp opentracing.Span -} - -func (c closeTracker) Close() error { - err := c.ReadCloser.Close() - c.sp.LogFields(log.String("event", "ClosedBody")) - c.sp.Finish() - return err -} - -func TracerFromRequest(req *http.Request) *Tracer { - tr, ok := req.Context().Value(keyTracer).(*Tracer) - if !ok { - return nil - } - return tr -} - -func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { - rt := t.RoundTripper - if rt == nil { - rt = http.DefaultTransport - } - tracer := TracerFromRequest(req) - if tracer == nil { - return rt.RoundTrip(req) - } - - tracer.start(req) - - carrier := opentracing.HTTPHeadersCarrier(req.Header) - err := tracer.sp.Tracer().Inject(tracer.sp.Context(), opentracing.HTTPHeaders, carrier) - if err != nil { - return rt.RoundTrip(req) - } - - resp, err := rt.RoundTrip(req) - - if err != nil { - tracer.sp.Finish() - return resp, err - } - ext.HTTPStatusCode.Set(tracer.sp, uint16(resp.StatusCode)) - if resp.StatusCode >= http.StatusInternalServerError { - ext.Error.Set(tracer.sp, true) - } - // Normally the span is finished when the response body is closed, but with streaming the initial HTTP response - // does not have a body and this never happens. We are patching this here by finishing the span early, knowing - // that this will make the span shorter than what it actually is. - if req.Method == "HEAD" || resp.ContentLength < 0 { - tracer.sp.Finish() - } else { - resp.Body = closeTracker{resp.Body, tracer.sp} - } - return resp, nil -} - -type Tracer struct { - tr opentracing.Tracer - sp opentracing.Span -} - -func (t *Tracer) start(req *http.Request) opentracing.Span { - ctx := opentracing.SpanFromContext(req.Context()).Context() - t.sp = t.tr.StartSpan("HTTP "+req.Method, opentracing.ChildOf(ctx)) - ext.SpanKindRPCClient.Set(t.sp) - ext.Component.Set(t.sp, componentName) - ext.HTTPMethod.Set(t.sp, req.Method) - ext.HTTPUrl.Set(t.sp, req.URL.String()) - return t.sp -} - -func (t *Tracer) clientTrace() *httptrace.ClientTrace { - return &httptrace.ClientTrace{ - GetConn: t.getConn, - GotConn: t.gotConn, - PutIdleConn: t.putIdleConn, - GotFirstResponseByte: t.gotFirstResponseByte, - Got100Continue: t.got100Continue, - DNSStart: t.dnsStart, - DNSDone: t.dnsDone, - ConnectStart: t.connectStart, - ConnectDone: t.connectDone, - WroteHeaders: t.wroteHeaders, - Wait100Continue: t.wait100Continue, - WroteRequest: t.wroteRequest, - } -} - -func (t *Tracer) getConn(hostPort string) { - ext.HTTPUrl.Set(t.sp, hostPort) - t.sp.LogFields(log.String("event", "GetConn")) -} - -func (t *Tracer) gotConn(info httptrace.GotConnInfo) { - t.sp.SetTag("net/http.reused", info.Reused) - t.sp.SetTag("net/http.was_idle", info.WasIdle) - t.sp.LogFields(log.String("event", "GotConn")) -} - -func (t *Tracer) putIdleConn(error) { - t.sp.LogFields(log.String("event", "PutIdleConn")) -} - -func (t *Tracer) gotFirstResponseByte() { - t.sp.LogFields(log.String("event", "GotFirstResponseByte")) -} - -func (t *Tracer) got100Continue() { - t.sp.LogFields(log.String("event", "Got100Continue")) -} - -func (t *Tracer) dnsStart(info httptrace.DNSStartInfo) { - t.sp.LogFields( - log.String("event", "DNSStart"), - log.String("host", info.Host), - ) -} - -func (t *Tracer) dnsDone(info httptrace.DNSDoneInfo) { - fields := []log.Field{log.String("event", "DNSDone")} - for _, addr := range info.Addrs { - fields = append(fields, log.String("addr", addr.String())) - } - if info.Err != nil { - fields = append(fields, log.Error(info.Err)) - } - t.sp.LogFields(fields...) -} - -func (t *Tracer) connectStart(network, addr string) { - t.sp.LogFields( - log.String("event", "ConnectStart"), - log.String("network", network), - log.String("addr", addr), - ) -} - -func (t *Tracer) connectDone(network, addr string, err error) { - if err != nil { - t.sp.LogFields( - log.String("message", "ConnectDone"), - log.String("network", network), - log.String("addr", addr), - log.String("event", "error"), - log.Error(err), - ) - } else { - t.sp.LogFields( - log.String("event", "ConnectDone"), - log.String("network", network), - log.String("addr", addr), - ) - } -} - -func (t *Tracer) wroteHeaders() { - t.sp.LogFields(log.String("event", "WroteHeaders")) -} - -func (t *Tracer) wait100Continue() { - t.sp.LogFields(log.String("event", "Wait100Continue")) -} - -func (t *Tracer) wroteRequest(info httptrace.WroteRequestInfo) { - if info.Err != nil { - t.sp.LogFields( - log.String("message", "WroteRequest"), - log.String("event", "error"), - log.Error(info.Err), - ) - ext.Error.Set(t.sp, true) - } else { - t.sp.LogFields(log.String("event", "WroteRequest")) - } -} diff --git a/pkg/util/prometheus.go b/pkg/util/prometheus.go index 1143571dbe..8cd31cc10f 100644 --- a/pkg/util/prometheus.go +++ b/pkg/util/prometheus.go @@ -1,6 +1,8 @@ package util import ( + "errors" + "github.com/prometheus/client_golang/prometheus" ) @@ -13,7 +15,8 @@ func RegisterOrGet[T prometheus.Collector](reg prometheus.Registerer, c T) T { } err := reg.Register(c) if err != nil { - already, ok := err.(prometheus.AlreadyRegisteredError) + var already prometheus.AlreadyRegisteredError + ok := errors.As(err, &already) if ok { return already.ExistingCollector.(T) } @@ -21,3 +24,19 @@ func RegisterOrGet[T prometheus.Collector](reg prometheus.Registerer, c T) T { } return c } + +func Register(reg prometheus.Registerer, collectors ...prometheus.Collector) { + if reg == nil { + return + } + for _, collector := range collectors { + err := reg.Register(collector) + if err != nil { + var alreadyRegisteredError prometheus.AlreadyRegisteredError + ok := errors.As(err, &alreadyRegisteredError) + if !ok { + panic(err) + } + } + } +} diff --git a/pkg/util/ratelimit/ratelimit.go b/pkg/util/ratelimit/ratelimit.go new file mode 100644 index 0000000000..e7d7ab01c4 --- /dev/null +++ b/pkg/util/ratelimit/ratelimit.go @@ -0,0 +1,42 @@ +package ratelimit + +import "time" + +// Limiter implements a simple token-bucket rate limiter. +// Tokens are replenished over time. +type Limiter struct { + rate float64 + tokens float64 + updated time.Time + // For testing purposes. + sleep func(time.Duration) + now func() time.Time +} + +func NewLimiter(rate float64) *Limiter { + return &Limiter{ + rate: rate, + tokens: rate, + sleep: time.Sleep, + now: time.Now, + } +} + +func (l *Limiter) Wait(n int) { + for { + now := l.now() + elapsed := now.Sub(l.updated).Seconds() + l.updated = now + l.tokens += elapsed * l.rate + if l.tokens > l.rate { + l.tokens = l.rate + } + if l.tokens >= float64(n) { + l.tokens -= float64(n) + return + } + missing := float64(n) - l.tokens + delay := time.Duration(missing/l.rate*1e9) * time.Nanosecond + l.sleep(delay) + } +} diff --git a/pkg/util/ratelimit/ratelimit_test.go b/pkg/util/ratelimit/ratelimit_test.go new file mode 100644 index 0000000000..9467d355e0 --- /dev/null +++ b/pkg/util/ratelimit/ratelimit_test.go @@ -0,0 +1,32 @@ +package ratelimit + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLimiter(t *testing.T) { + var sleptFor []time.Duration + now := time.Unix(0, 0) + + l := NewLimiter(100) + l.now = func() time.Time { return now } + l.sleep = func(d time.Duration) { + sleptFor = append(sleptFor, d) + now = now.Add(d) + } + + l.Wait(100) + assert.Len(t, sleptFor, 0) + + l.Wait(100) + require.Len(t, sleptFor, 1) + assert.Equal(t, time.Second, sleptFor[0]) + + l.Wait(100) + require.Len(t, sleptFor, 2) + assert.Equal(t, time.Second, sleptFor[1]) +} diff --git a/pkg/util/ratelimit/writer.go b/pkg/util/ratelimit/writer.go new file mode 100644 index 0000000000..ba3198a556 --- /dev/null +++ b/pkg/util/ratelimit/writer.go @@ -0,0 +1,32 @@ +package ratelimit + +import ( + "io" +) + +type Writer struct { + w io.Writer + l *Limiter +} + +func NewWriter(w io.Writer, l *Limiter) *Writer { + return &Writer{w: w, l: l} +} + +func (rw *Writer) Write(p []byte) (int, error) { + var total int + for len(p) > 0 { + n := len(p) + if n > int(rw.l.rate) { + n = int(rw.l.rate) + } + rw.l.Wait(n) + written, err := rw.w.Write(p[:n]) + total += written + p = p[written:] + if err != nil { + return total, err + } + } + return total, nil +} diff --git a/pkg/util/ratelimit/writer_test.go b/pkg/util/ratelimit/writer_test.go new file mode 100644 index 0000000000..f408ee4c59 --- /dev/null +++ b/pkg/util/ratelimit/writer_test.go @@ -0,0 +1,33 @@ +package ratelimit + +import ( + "io" + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWriter(t *testing.T) { + var sleptFor time.Duration + now := time.Unix(0, 0) + + limiter := NewLimiter(100) + limiter.now = func() time.Time { return now } + limiter.sleep = func(d time.Duration) { + sleptFor += d + now = now.Add(d) + } + + w := NewWriter(io.Discard, limiter) + + const N = 1 << 10 + n, err := io.CopyN(w, rand.New(rand.NewSource(42)), N) + require.NoError(t, err) + assert.EqualValues(t, n, N) + + t.Log("written in", sleptFor) + assert.Greater(t, sleptFor, time.Second*9) +} diff --git a/pkg/util/recovery.go b/pkg/util/recovery.go index bcd7905e3b..eabf6fa9e6 100644 --- a/pkg/util/recovery.go +++ b/pkg/util/recovery.go @@ -10,10 +10,11 @@ import ( "connectrpc.com/connect" "github.com/grafana/dskit/httpgrpc" "github.com/grafana/dskit/middleware" + grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - httputil "github.com/grafana/pyroscope/pkg/util/http" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) const maxStacksize = 8 * 1024 @@ -29,17 +30,18 @@ var ( return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { defer func() { if p := recover(); p != nil { - httputil.Error(w, httpgrpc.Errorf(http.StatusInternalServerError, "error while processing request: %v", panicError(p))) + httputil.Error(w, httpgrpc.Errorf(http.StatusInternalServerError, "error while processing request: %v", PanicError(p))) } }() next.ServeHTTP(w, req) }) }) - RecoveryInterceptor recoveryInterceptor + RecoveryInterceptor recoveryInterceptor + RecoveryInterceptorGRPC = grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandler(PanicError)) ) -func panicError(p interface{}) error { +func PanicError(p interface{}) error { stack := make([]byte, maxStacksize) stack = stack[:runtime.Stack(stack, true)] // keep a multiline stack @@ -53,20 +55,29 @@ func RecoverPanic(f func() error) func() error { return func() (err error) { defer func() { if p := recover(); p != nil { - err = panicError(p) + err = PanicError(p) } }() return f() } } +func Recover(f func()) { + defer func() { + if p := recover(); p != nil { + _ = PanicError(p) + } + }() + f() +} + type recoveryInterceptor struct{} func (recoveryInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { return func(ctx context.Context, req connect.AnyRequest) (resp connect.AnyResponse, err error) { defer func() { if p := recover(); p != nil { - err = connect.NewError(connect.CodeInternal, panicError(p)) + err = connect.NewError(connect.CodeInternal, PanicError(p)) } }() return next(ctx, req) @@ -77,7 +88,7 @@ func (recoveryInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFun return func(ctx context.Context, conn connect.StreamingHandlerConn) (err error) { defer func() { if p := recover(); p != nil { - err = connect.NewError(connect.CodeInternal, panicError(p)) + err = connect.NewError(connect.CodeInternal, PanicError(p)) } }() return next(ctx, conn) diff --git a/pkg/util/refctr/refctr.go b/pkg/util/refctr/refctr.go index 7bfcba35ee..df2c541232 100644 --- a/pkg/util/refctr/refctr.go +++ b/pkg/util/refctr/refctr.go @@ -3,8 +3,9 @@ package refctr import "sync" type Counter struct { - m sync.Mutex - c int + m sync.Mutex + c int + err error } // Inc increments the counter and calls the init function, @@ -30,15 +31,43 @@ func (r *Counter) Inc(init func() error) (err error) { return init() } +// IncErr is identical to Inc, with the only difference that if the +// function fails, the error is returned on any further IncErr call, +// preventing from calling the faulty initialization function again. +func (r *Counter) IncErr(init func() error) (err error) { + r.m.Lock() + if r.err != nil { + err = r.err + r.m.Unlock() + return err + } + defer func() { + // If initialization fails, we need to make sure + // the next call makes another attempt. + if err != nil { + r.err = err + r.c-- + } + r.m.Unlock() + }() + if r.c++; r.c > 1 { + return nil + } + // Mutex is acquired during the call in order to serialize + // access to the resources, so that the consequent callers + // only have access to them after initialization finishes. + return init() +} + // Dec decrements the counter and calls the release function, // if this is the last reference. func (r *Counter) Dec(release func()) { r.m.Lock() + defer r.m.Unlock() if r.c < 0 { panic("bug: negative reference counter") } if r.c--; r.c < 1 { release() } - r.m.Unlock() } diff --git a/pkg/util/retry/hedged.go b/pkg/util/retry/hedged.go new file mode 100644 index 0000000000..957a4aa49c --- /dev/null +++ b/pkg/util/retry/hedged.go @@ -0,0 +1,77 @@ +package retry + +import ( + "context" + "sync" + "sync/atomic" + "time" +) + +// Hedged executes Call with a speculative retry after trigger fires +// if it has not returned earlier. +// +// By default, if one of the attempts fails, another one is not canceled. +// In this case the speculative attempt will not start until the trigger fires. +// For more granular control, use FailFast. +type Hedged[T any] struct { + // The function must be thread-safe because multiple instances may be running + // concurrently. The function must return as soon as possible after context + // cancellation, otherwise the speculation makes no sense. + // + // The function argument indicates whether this is a speculative retry attempt. + Call Call[T] + Trigger <-chan time.Time + + // FailFast specifies how a failure is handled. If it is set to true: + // - the result received first is returned, regardless of anything. + // - if Call fails before the trigger fires, it won't be retried. + FailFast bool +} + +type Call[T any] func(ctx context.Context, isRetry bool) (T, error) + +func (s Hedged[T]) Do(ctx context.Context) (T, error) { + attemptCtx, cancel := context.WithCancel(ctx) + defer cancel() + var ( + ret T + err error + failed uint64 + + wg sync.WaitGroup + do sync.Once + ) + + attempt := func(isRetry bool) { + wg.Add(1) + go func() { + defer wg.Done() + attemptRet, attemptErr := s.Call(attemptCtx, isRetry) + if attemptErr != nil && atomic.SwapUint64(&failed, 1) == 0 && !s.FailFast { + // This attempt has failed, but not another one. If allowed, + // we give another attempt a chance. Otherwise, if both ones + // did fail, or it's not allowed to proceed after the first + // failure, we store the result with error and cancel any + // ongoing attempt. + return + } + // If there is an ongoing attempt, it will be cancelled, + // because we already got the result. + cancel() + do.Do(func() { + ret, err = attemptRet, attemptErr + }) + }() + } + + attempt(false) + select { + case <-attemptCtx.Done(): + // Call has returned, or caller cancelled the request. + case <-s.Trigger: + attempt(true) + } + + wg.Wait() + return ret, err +} diff --git a/pkg/util/retry/hedged_test.go b/pkg/util/retry/hedged_test.go new file mode 100644 index 0000000000..859ac74e54 --- /dev/null +++ b/pkg/util/retry/hedged_test.go @@ -0,0 +1,137 @@ +package retry + +import ( + "context" + "errors" + "testing" + "testing/synctest" + "time" +) + +func Test_Hedging(t *testing.T) { + e1 := errors.New("e1") + e2 := errors.New("e2") + + // hedgeDelay is the trigger delay. Attempts with returnAfter=0 return + // immediately (before the trigger fires). Attempts with + // returnAfter=2*hedgeDelay return after the trigger has fired. + const hedgeDelay = time.Second + + type attempt struct { + returnAfter time.Duration // 0 = immediate + err error + } + + type testCase struct { + description string + failFast bool + attempts [2]attempt + expectRetry bool + expectError error + } + + testCases := []testCase{ + { + description: "Attempt fails before retry and FailFast", + failFast: true, + attempts: [2]attempt{{err: e1}, {}}, + expectRetry: false, + expectError: e1, + }, + { + description: "Attempt fails before retry and not FailFast", + failFast: false, + attempts: [2]attempt{{err: e1}, {}}, + expectRetry: true, + expectError: nil, + }, + { + description: "Attempt fails before retry and retry fails and FailFast", + failFast: true, + attempts: [2]attempt{{err: e1}, {err: e2}}, + expectRetry: false, + expectError: e1, + }, + { + description: "Attempt fails before retry and retry fails and not FailFast", + failFast: false, + attempts: [2]attempt{{err: e1}, {err: e2}}, + expectRetry: true, + expectError: e2, + }, + { + description: "Attempt fails after retry and FailFast", + failFast: true, + attempts: [2]attempt{{returnAfter: hedgeDelay * 2, err: e1}, {returnAfter: hedgeDelay * 2}}, + expectRetry: false, + expectError: e1, + }, + { + description: "Attempt fails after retry and not FailFast", + failFast: false, + attempts: [2]attempt{{returnAfter: hedgeDelay * 2, err: e1}, {returnAfter: hedgeDelay * 2}}, + expectRetry: true, + expectError: nil, + }, + { + description: "Attempt fails after retry and retry fails and FailFast", + failFast: true, + attempts: [2]attempt{{returnAfter: hedgeDelay * 2, err: e1}, {returnAfter: hedgeDelay * 2, err: e2}}, + expectRetry: false, + expectError: e1, + }, + { + description: "Attempt fails after retry and retry fails and not FailFast", + failFast: false, + attempts: [2]attempt{{returnAfter: hedgeDelay * 2, err: e1}, {returnAfter: hedgeDelay * 2, err: e2}}, + expectRetry: true, + expectError: e2, + }, + } + + for _, c := range testCases { + t.Run(c.description, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + a := Hedged[bool]{ + Trigger: time.After(hedgeDelay), + FailFast: c.failFast, + Call: func(ctx context.Context, isRetry bool) (bool, error) { + spec := c.attempts[0] + if isRetry { + spec = c.attempts[1] + } + if spec.returnAfter > 0 { + select { + case <-time.After(spec.returnAfter): + case <-ctx.Done(): + } + } + return isRetry, spec.err + }, + } + + done := make(chan struct{}) + var gotResult bool + var gotErr error + go func() { + defer close(done) + gotResult, gotErr = a.Do(context.Background()) + }() + + synctest.Wait() + time.Sleep(hedgeDelay) // fire trigger + synctest.Wait() + time.Sleep(hedgeDelay * 2) // let slow attempts complete + synctest.Wait() + <-done + + if gotResult != c.expectRetry { + t.Fatalf("expected isRetry=%v, got %v", c.expectRetry, gotResult) + } + if !errors.Is(gotErr, c.expectError) { + t.Fatalf("expected error %v, got %v", c.expectError, gotErr) + } + }) + }) + } +} diff --git a/pkg/util/servicediscovery/dns.go b/pkg/util/servicediscovery/dns.go index 767c3d9eb0..b3e27206c9 100644 --- a/pkg/util/servicediscovery/dns.go +++ b/pkg/util/servicediscovery/dns.go @@ -12,9 +12,8 @@ import ( "github.com/grafana/dskit/grpcutil" "github.com/grafana/dskit/services" - "github.com/pkg/errors" - util_log "github.com/grafana/pyroscope/pkg/util" + util_log "github.com/grafana/pyroscope/v2/pkg/util" ) // Instance notified by the service discovery. @@ -89,7 +88,7 @@ func (w *dnsServiceDiscovery) watchDNSLoop(servCtx context.Context) error { if servCtx.Err() != nil { return nil } - return errors.Wrapf(err, "error from DNS service discovery") + return fmt.Errorf("error from DNS service discovery: %w", err) } for _, update := range updates { diff --git a/pkg/util/servicediscovery/ring.go b/pkg/util/servicediscovery/ring.go index 547697b417..75b4435872 100644 --- a/pkg/util/servicediscovery/ring.go +++ b/pkg/util/servicediscovery/ring.go @@ -4,12 +4,12 @@ package servicediscovery import ( "context" + "fmt" "sort" "time" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" - "github.com/pkg/errors" ) var ( @@ -47,11 +47,19 @@ func NewRing(ringClient *ring.Ring, ringCheckPeriod time.Duration, maxUsedInstan func (r *ringServiceDiscovery) starting(ctx context.Context) error { r.subservicesWatcher.WatchService(r.ringClient) - return errors.Wrap(services.StartAndAwaitRunning(ctx, r.ringClient), "failed to start ring client") + err := services.StartAndAwaitRunning(ctx, r.ringClient) + if err != nil { + return fmt.Errorf("failed to start ring client: %w", err) + } + return nil } func (r *ringServiceDiscovery) stopping(_ error) error { - return errors.Wrap(services.StopAndAwaitTerminated(context.Background(), r.ringClient), "failed to stop ring client") + err := services.StopAndAwaitTerminated(context.Background(), r.ringClient) + if err != nil { + return fmt.Errorf("failed to stop ring client: %w", err) + } + return nil } func (r *ringServiceDiscovery) running(ctx context.Context) error { @@ -70,7 +78,7 @@ func (r *ringServiceDiscovery) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-r.subservicesWatcher.Chan(): - return errors.Wrap(err, "a subservice of ring-based service discovery has failed") + return fmt.Errorf("a subservice of ring-based service discovery has failed: %w", err) } } } diff --git a/pkg/util/servicediscovery/ring_test.go b/pkg/util/servicediscovery/ring_test.go index 9f29242857..5c2bcaaa35 100644 --- a/pkg/util/servicediscovery/ring_test.go +++ b/pkg/util/servicediscovery/ring_test.go @@ -57,10 +57,10 @@ func TestRingServiceDiscovery_WithoutMaxUsedInstances(t *testing.T) { // Register some instances. require.NoError(t, inmem.CAS(ctx, ringKey, func(in interface{}) (out interface{}, retry bool, err error) { desc := in.(*ring.Desc) - desc.AddIngester("instance-1", "127.0.0.1", "", nil, ring.ACTIVE, time.Now()) - desc.AddIngester("instance-2", "127.0.0.2", "", nil, ring.PENDING, time.Now()) - desc.AddIngester("instance-3", "127.0.0.3", "", nil, ring.JOINING, time.Now()) - desc.AddIngester("instance-4", "127.0.0.4", "", nil, ring.LEAVING, time.Now()) + desc.AddIngester("instance-1", "127.0.0.1", "", nil, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-2", "127.0.0.2", "", nil, ring.PENDING, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-3", "127.0.0.3", "", nil, ring.JOINING, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-4", "127.0.0.4", "", nil, ring.LEAVING, time.Now(), false, time.Now(), ring.InstanceVersions{}) return desc, true, nil })) @@ -71,8 +71,8 @@ func TestRingServiceDiscovery_WithoutMaxUsedInstances(t *testing.T) { // Register more instances. require.NoError(t, inmem.CAS(ctx, ringKey, func(in interface{}) (out interface{}, retry bool, err error) { desc := in.(*ring.Desc) - desc.AddIngester("instance-5", "127.0.0.5", "", nil, ring.ACTIVE, time.Now()) - desc.AddIngester("instance-6", "127.0.0.6", "", nil, ring.ACTIVE, time.Now()) + desc.AddIngester("instance-5", "127.0.0.5", "", nil, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-6", "127.0.0.6", "", nil, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) return desc, true, nil })) @@ -159,10 +159,10 @@ func TestRingServiceDiscovery_WithMaxUsedInstances(t *testing.T) { // Register some instances. require.NoError(t, inmem.CAS(ctx, ringKey, func(in interface{}) (out interface{}, retry bool, err error) { desc := in.(*ring.Desc) - desc.AddIngester("instance-1", "127.0.0.1", "", nil, ring.ACTIVE, time.Now()) - desc.AddIngester("instance-2", "127.0.0.2", "", nil, ring.PENDING, time.Now()) - desc.AddIngester("instance-3", "127.0.0.3", "", nil, ring.JOINING, time.Now()) - desc.AddIngester("instance-4", "127.0.0.4", "", nil, ring.LEAVING, time.Now()) + desc.AddIngester("instance-1", "127.0.0.1", "", nil, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-2", "127.0.0.2", "", nil, ring.PENDING, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-3", "127.0.0.3", "", nil, ring.JOINING, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-4", "127.0.0.4", "", nil, ring.LEAVING, time.Now(), false, time.Now(), ring.InstanceVersions{}) return desc, true, nil })) @@ -173,8 +173,8 @@ func TestRingServiceDiscovery_WithMaxUsedInstances(t *testing.T) { // Register more instances. require.NoError(t, inmem.CAS(ctx, ringKey, func(in interface{}) (out interface{}, retry bool, err error) { desc := in.(*ring.Desc) - desc.AddIngester("instance-5", "127.0.0.5", "", nil, ring.ACTIVE, time.Now()) - desc.AddIngester("instance-6", "127.0.0.6", "", nil, ring.ACTIVE, time.Now()) + desc.AddIngester("instance-5", "127.0.0.5", "", nil, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester("instance-6", "127.0.0.6", "", nil, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) return desc, true, nil })) diff --git a/pkg/util/spanlogger/query_log.go b/pkg/util/spanlogger/query_log.go new file mode 100644 index 0000000000..a17be9aa28 --- /dev/null +++ b/pkg/util/spanlogger/query_log.go @@ -0,0 +1,365 @@ +package spanlogger + +import ( + "context" + "fmt" + "strings" + "time" + + "connectrpc.com/connect" + "github.com/dustin/go-humanize" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/grafana/dskit/tracing" + "github.com/prometheus/common/model" + + profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" + querierv1 "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1" + "github.com/grafana/pyroscope/api/gen/proto/go/querier/v1/querierv1connect" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +type LogSpanParametersWrapper struct { + client querierv1connect.QuerierServiceClient + logger log.Logger +} + +func NewLogSpanParametersWrapper(client querierv1connect.QuerierServiceClient, logger log.Logger) *LogSpanParametersWrapper { + return &LogSpanParametersWrapper{ + client: client, + logger: logger, + } +} + +// logWithRequestMetadata returns a SpanLogger enriched with request metadata. +// Add new extractions here to make them available on all query log lines. +func (l LogSpanParametersWrapper) logWithRequestMetadata(ctx context.Context, req connect.AnyRequest) *SpanLogger { + logger := l.logger + if ua := req.Header().Get("User-Agent"); ua != "" { + logger = log.With(logger, "user_agent", ua) + } + return FromContext(ctx, logger) +} + +// logQuery emits a "query started" line, executes fn, then emits a "query +// finished" line with latency and (optionally) humanized bytes fetched. +// reqFields must be a flat key-value list of request-scoped fields that will +// appear on both lines. +func (l LogSpanParametersWrapper) logQuery( + logger *SpanLogger, + stats *QueryStats, + reqFields []interface{}, + fn func() error, +) error { + level.Info(logger).Log(append([]interface{}{"msg", "query started"}, reqFields...)...) + + t := time.Now() + err := fn() + latency := time.Since(t) + + finishFields := make([]interface{}, 0, len(reqFields)+8) + finishFields = append(finishFields, "msg", "query finished") + finishFields = append(finishFields, reqFields...) + finishFields = append(finishFields, "latency", latency) + if stats != nil { + finishFields = append(finishFields, + "fetched_object_bytes", humanize.Bytes(stats.ObjectStorageBytes), + "fetched_metastore_bytes", humanize.Bytes(stats.MetastoreBytes), + "estimated_object_bytes", humanize.Bytes(stats.EstimatedBytes), + ) + if stats.ObjectStorageBytes > 0 { + finishFields = append(finishFields, + "estimation_ratio", fmt.Sprintf("%.2f", float64(stats.EstimatedBytes)/float64(stats.ObjectStorageBytes)), + ) + } + } + level.Info(logger).Log(finishFields...) + return err +} + +func (l LogSpanParametersWrapper) ProfileTypes(ctx context.Context, c *connect.Request[querierv1.ProfileTypesRequest]) (*connect.Response[querierv1.ProfileTypesResponse], error) { + spanName := "ProfileTypes" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[querierv1.ProfileTypesResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + }, func() (err error) { + resp, err = l.client.ProfileTypes(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) LabelValues(ctx context.Context, c *connect.Request[typesv1.LabelValuesRequest]) (*connect.Response[typesv1.LabelValuesResponse], error) { + spanName := "LabelValues" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[typesv1.LabelValuesResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "matchers", lazyJoin(c.Msg.Matchers), + "name", c.Msg.Name, + }, func() (err error) { + resp, err = l.client.LabelValues(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) LabelNames(ctx context.Context, c *connect.Request[typesv1.LabelNamesRequest]) (*connect.Response[typesv1.LabelNamesResponse], error) { + spanName := "LabelNames" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[typesv1.LabelNamesResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "matchers", lazyJoin(c.Msg.Matchers), + }, func() (err error) { + resp, err = l.client.LabelNames(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) Series(ctx context.Context, c *connect.Request[querierv1.SeriesRequest]) (*connect.Response[querierv1.SeriesResponse], error) { + spanName := "Series" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[querierv1.SeriesResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "matchers", lazyJoin(c.Msg.Matchers), + "label_names", lazyJoin(c.Msg.LabelNames), + }, func() (err error) { + resp, err = l.client.Series(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) SelectMergeStacktraces(ctx context.Context, c *connect.Request[querierv1.SelectMergeStacktracesRequest]) (*connect.Response[querierv1.SelectMergeStacktracesResponse], error) { + spanName := "SelectMergeStacktraces" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[querierv1.SelectMergeStacktracesResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "selector", c.Msg.LabelSelector, + "profile_type", c.Msg.ProfileTypeID, + "format", c.Msg.Format, + "max_nodes", c.Msg.GetMaxNodes(), + "profile_id_selector", lazyJoin(c.Msg.ProfileIdSelector), + "span_selector", lazyJoin(c.Msg.SpanSelector), + }, func() (err error) { + resp, err = l.client.SelectMergeStacktraces(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) SelectMergeSpanProfile(ctx context.Context, c *connect.Request[querierv1.SelectMergeSpanProfileRequest]) (*connect.Response[querierv1.SelectMergeSpanProfileResponse], error) { + spanName := "SelectMergeSpanProfile" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[querierv1.SelectMergeSpanProfileResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "selector", c.Msg.LabelSelector, + "profile_type", c.Msg.ProfileTypeID, + "format", c.Msg.Format, + "max_nodes", c.Msg.GetMaxNodes(), + }, func() (err error) { + resp, err = l.client.SelectMergeSpanProfile(ctx, c) //nolint:staticcheck // Required querier.v1 compatibility wrapper. + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) SelectMergeProfile(ctx context.Context, c *connect.Request[querierv1.SelectMergeProfileRequest]) (*connect.Response[profilev1.Profile], error) { + spanName := "SelectMergeProfile" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[profilev1.Profile] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "selector", c.Msg.LabelSelector, + "max_nodes", c.Msg.GetMaxNodes(), + "profile_type", c.Msg.ProfileTypeID, + "stacktrace_selector", c.Msg.GetStackTraceSelector(), + "profile_id_selector", lazyJoin(c.Msg.ProfileIdSelector), + }, func() (err error) { + resp, err = l.client.SelectMergeProfile(ctx, c) //nolint:staticcheck // Required querier.v1 compatibility wrapper. + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) SelectSeries(ctx context.Context, c *connect.Request[querierv1.SelectSeriesRequest]) (*connect.Response[querierv1.SelectSeriesResponse], error) { + spanName := "SelectSeries" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[querierv1.SelectSeriesResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "selector", c.Msg.LabelSelector, + "profile_type", c.Msg.ProfileTypeID, + "stacktrace_selector", c.Msg.GetStackTraceSelector(), + "step", c.Msg.Step, + "by", lazyJoin(c.Msg.GroupBy), + "aggregation", c.Msg.GetAggregation().String(), + "limit", c.Msg.Limit, + "exemplar_type", c.Msg.ExemplarType, + }, func() (err error) { + resp, err = l.client.SelectSeries(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) SelectHeatmap(ctx context.Context, c *connect.Request[querierv1.SelectHeatmapRequest]) (*connect.Response[querierv1.SelectHeatmapResponse], error) { + spanName := "SelectHeatmap" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[querierv1.SelectHeatmapResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "selector", c.Msg.LabelSelector, + "profile_type", c.Msg.ProfileTypeID, + "step", c.Msg.Step, + "by", lazyJoin(c.Msg.GroupBy), + "query_type", c.Msg.QueryType, + "exemplar_type", c.Msg.ExemplarType, + "limit", c.Msg.Limit, + }, func() (err error) { + resp, err = l.client.SelectHeatmap(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) Diff(ctx context.Context, c *connect.Request[querierv1.DiffRequest]) (*connect.Response[querierv1.DiffResponse], error) { + spanName := "Diff" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + left := &querierv1.SelectMergeStacktracesRequest{} + if c.Msg.Left != nil { + left = c.Msg.Left + } + right := &querierv1.SelectMergeStacktracesRequest{} + if c.Msg.Right != nil { + right = c.Msg.Right + } + + var resp *connect.Response[querierv1.DiffResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "left_start", model.Time(left.Start).Time().String(), + "left_end", model.Time(left.End).Time().String(), + "left_query_window", model.Time(left.End).Sub(model.Time(left.Start)).String(), + "left_selector", left.LabelSelector, + "left_profile_type", left.ProfileTypeID, + "left_format", left.Format, + "left_max_nodes", left.GetMaxNodes(), + "left_span_selector", lazyJoin(left.SpanSelector), + "right_start", model.Time(right.Start).Time().String(), + "right_end", model.Time(right.End).Time().String(), + "right_query_window", model.Time(right.End).Sub(model.Time(right.Start)).String(), + "right_selector", right.LabelSelector, + "right_profile_type", right.ProfileTypeID, + "right_format", right.Format, + "right_max_nodes", right.GetMaxNodes(), + "right_span_selector", lazyJoin(right.SpanSelector), + }, func() (err error) { + resp, err = l.client.Diff(ctx, c) + return err + }) + return resp, err +} + +func (l LogSpanParametersWrapper) GetProfileStats(ctx context.Context, c *connect.Request[typesv1.GetProfileStatsRequest]) (*connect.Response[typesv1.GetProfileStatsResponse], error) { + sp, ctx := tracing.StartSpanFromContext(ctx, "GetProfileStats") + defer sp.Finish() + + return l.client.GetProfileStats(ctx, c) +} + +func (l LogSpanParametersWrapper) AnalyzeQuery(ctx context.Context, c *connect.Request[querierv1.AnalyzeQueryRequest]) (*connect.Response[querierv1.AnalyzeQueryResponse], error) { + spanName := "AnalyzeQuery" + sp, ctx := tracing.StartSpanFromContext(ctx, spanName) + defer sp.Finish() + ctx, stats := ContextWithQueryStats(ctx) + + var resp *connect.Response[querierv1.AnalyzeQueryResponse] + err := l.logQuery(l.logWithRequestMetadata(ctx, c), stats, []interface{}{ + "method", spanName, + "start", model.Time(c.Msg.Start).Time().String(), + "end", model.Time(c.Msg.End).Time().String(), + "query_window", model.Time(c.Msg.End).Sub(model.Time(c.Msg.Start)).String(), + "query", c.Msg.Query, + }, func() (err error) { + resp, err = l.client.AnalyzeQuery(ctx, c) + return err + }) + return resp, err +} + +type LazyJoin struct { + strs []string + sep string +} + +func (l *LazyJoin) String() string { + return strings.Join(l.strs, l.sep) +} + +func lazyJoin(strs []string) *LazyJoin { + return &LazyJoin{strs: strs, sep: ","} +} diff --git a/pkg/util/spanlogger/query_stats.go b/pkg/util/spanlogger/query_stats.go new file mode 100644 index 0000000000..4b60e3ddf1 --- /dev/null +++ b/pkg/util/spanlogger/query_stats.go @@ -0,0 +1,29 @@ +package spanlogger + +import "context" + +// QueryStats is populated by the query-frontend during query execution and +// read by LogSpanParametersWrapper after the call returns, so that bytes +// fetched can be included in the query log line. +type QueryStats struct { + ObjectStorageBytes uint64 + MetastoreBytes uint64 + // EstimatedBytes is the pre-execution metadata size estimate (weight.Total()) + // derived from block dataset section offsets before the backend is invoked. + EstimatedBytes uint64 +} + +type queryStatsKey struct{} + +// ContextWithQueryStats attaches a fresh QueryStats to ctx and returns both +// the enriched context and a pointer to the stats struct. +func ContextWithQueryStats(ctx context.Context) (context.Context, *QueryStats) { + s := &QueryStats{} + return context.WithValue(ctx, queryStatsKey{}, s), s +} + +// QueryStatsFromContext returns the QueryStats stored in ctx, or nil if none. +func QueryStatsFromContext(ctx context.Context) *QueryStats { + s, _ := ctx.Value(queryStatsKey{}).(*QueryStats) + return s +} diff --git a/pkg/util/spanlogger/spanlogger.go b/pkg/util/spanlogger/spanlogger.go index 4b33a5e11b..e3aa3e5b6c 100644 --- a/pkg/util/spanlogger/spanlogger.go +++ b/pkg/util/spanlogger/spanlogger.go @@ -8,6 +8,7 @@ import ( "github.com/go-kit/log" "github.com/grafana/dskit/spanlogger" "github.com/grafana/dskit/tenant" + "go.opentelemetry.io/otel" ) const ( @@ -23,7 +24,7 @@ type SpanLogger = spanlogger.SpanLogger // NewWithLogger is like New but allows to pass a logger. func NewWithLogger(ctx context.Context, logger log.Logger, method string, kvps ...interface{}) (*SpanLogger, context.Context) { - return spanlogger.New(ctx, logger, method, defaultTenantResolver, kvps...) + return spanlogger.NewOTel(ctx, logger, otel.Tracer("pyroscope"), method, defaultTenantResolver, kvps...) } // FromContext returns a SpanLogger using the current parent span. diff --git a/pkg/util/strings.go b/pkg/util/strings.go index c982e73140..5d9bc6ae43 100644 --- a/pkg/util/strings.go +++ b/pkg/util/strings.go @@ -5,6 +5,8 @@ package util +import "strings" + // StringsContain returns true if the search value is within the list of input values. func StringsContain(values []string, search string) bool { for _, v := range values { @@ -24,3 +26,38 @@ func StringsMap(values []string) map[string]bool { } return out } + +// ToCamel converts s to CamelCase. Word boundaries are any non-letter, +// non-digit character (underscore, hyphen, space, etc.). Digits end a word, so +// the character that follows them is also capitalised. +func ToCamel(s string) string { + s = strings.TrimSpace(s) + if s == "" { + return s + } + var b strings.Builder + b.Grow(len(s)) + capNext := true + for _, r := range s { + switch { + case r >= 'A' && r <= 'Z': + b.WriteRune(r) + capNext = false + case r >= 'a' && r <= 'z': + if capNext { + b.WriteRune(r - ('a' - 'A')) + } else { + b.WriteRune(r) + } + capNext = false + case r >= '0' && r <= '9': + b.WriteRune(r) + capNext = true + default: + if b.Len() > 0 { + capNext = true + } + } + } + return b.String() +} diff --git a/pkg/util/ulid.go b/pkg/util/ulid.go new file mode 100644 index 0000000000..1ebcfd0d53 --- /dev/null +++ b/pkg/util/ulid.go @@ -0,0 +1,16 @@ +package util + +import ( + "unsafe" + + "github.com/oklog/ulid/v2" +) + +func ULIDStringUnixNano(s string) int64 { + var u ulid.ULID + b := unsafe.Slice(unsafe.StringData(s), len(s)) + if err := u.UnmarshalText(b); err == nil { + return int64(u.Time()) * 1e6 + } + return -1 +} diff --git a/pkg/util/validation/limits.go b/pkg/util/validation/limits.go index 0beb42dd51..1e205b10b2 100644 --- a/pkg/util/validation/limits.go +++ b/pkg/util/validation/limits.go @@ -2,6 +2,18 @@ package validation import "time" +func AllTruePerTenant(tenantIDs []string, f func(string) bool) bool { + if len(tenantIDs) == 0 { + return false + } + for _, tenantID := range tenantIDs { + if !f(tenantID) { + return false + } + } + return true +} + // SmallestPositiveNonZeroIntPerTenant is returning the minimal positive and // non-zero value of the supplied limit function for all given tenants. In many // limits a value of 0 means unlimited so the method will return 0 only if all diff --git a/pkg/util/yaml.go b/pkg/util/yaml.go index 961c269711..072f071f75 100644 --- a/pkg/util/yaml.go +++ b/pkg/util/yaml.go @@ -5,7 +5,7 @@ package util -import "gopkg.in/yaml.v3" +import "go.yaml.in/yaml/v3" // YAMLMarshalUnmarshal utility function that converts a YAML interface in a map // doing marshal and unmarshal of the parameter diff --git a/pkg/validation/exporter/exporter.go b/pkg/validation/exporter/exporter.go index 258ef73719..cbd7939a40 100644 --- a/pkg/validation/exporter/exporter.go +++ b/pkg/validation/exporter/exporter.go @@ -8,16 +8,16 @@ package exporter import ( "context" "flag" + "fmt" "net/http" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/validation" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" + "github.com/grafana/pyroscope/v2/pkg/validation" ) // Config holds the configuration for an overrides-exporter @@ -79,7 +79,7 @@ func NewOverridesExporter( var err error exporter.ring, err = newRing(config.Ring, log, registerer) if err != nil { - return nil, errors.Wrap(err, "failed to create ring/lifecycler") + return nil, fmt.Errorf("failed to create ring/lifecycler: %w", err) } exporter.Service = services.NewBasicService(exporter.starting, exporter.running, exporter.stopping) @@ -165,7 +165,7 @@ func (oe *OverridesExporter) RingHandler(w http.ResponseWriter, req *http.Reques

    Overrides-exporter hash ring is disabled.

    ` - util.WriteHTMLResponse(w, ringDisabledPage) + httputil.WriteHTMLResponse(w, ringDisabledPage) } // isLeader determines whether this overrides-exporter instance is the leader @@ -177,7 +177,7 @@ func (oe *OverridesExporter) isLeader() bool { // If the ring is not enabled, export all metrics return true } - if oe.Service.State() != services.Running { + if oe.State() != services.Running { // We haven't finished startup yet, likely waiting for ring stability. return false } diff --git a/pkg/validation/exporter/exporter_test.go b/pkg/validation/exporter/exporter_test.go index 91b3198d48..98c0a41c79 100644 --- a/pkg/validation/exporter/exporter_test.go +++ b/pkg/validation/exporter/exporter_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/pyroscope/pkg/validation" + "github.com/grafana/pyroscope/v2/pkg/validation" ) func TestOverridesExporter_withConfig(t *testing.T) { diff --git a/pkg/validation/exporter/ring.go b/pkg/validation/exporter/ring.go index 3075e42c83..7e27dcbe91 100644 --- a/pkg/validation/exporter/ring.go +++ b/pkg/validation/exporter/ring.go @@ -4,8 +4,11 @@ package exporter import ( "context" + "errors" "flag" "fmt" + "net" + "strconv" "time" "github.com/go-kit/log" @@ -13,10 +16,9 @@ import ( "github.com/grafana/dskit/kv" "github.com/grafana/dskit/ring" "github.com/grafana/dskit/services" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "github.com/grafana/pyroscope/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util" ) const ( @@ -65,7 +67,7 @@ func (c *RingConfig) RegisterFlags(f *flag.FlagSet, logger log.Logger) { // toBasicLifecyclerConfig transforms a RingConfig into configuration that can be used to create a BasicLifecycler. func (c *RingConfig) toBasicLifecyclerConfig(logger log.Logger) (ring.BasicLifecyclerConfig, error) { - instanceAddr, err := ring.GetInstanceAddr(c.Ring.InstanceAddr, c.Ring.InstanceInterfaceNames, logger, true) + instanceAddr, err := ring.GetInstanceAddr(c.Ring.InstanceAddr, c.Ring.InstanceInterfaceNames, logger, c.Ring.EnableIPv6) if err != nil { return ring.BasicLifecyclerConfig{}, err } @@ -74,7 +76,7 @@ func (c *RingConfig) toBasicLifecyclerConfig(logger log.Logger) (ring.BasicLifec return ring.BasicLifecyclerConfig{ ID: c.Ring.InstanceID, - Addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), + Addr: net.JoinHostPort(instanceAddr, strconv.Itoa(instancePort)), HeartbeatPeriod: c.Ring.HeartbeatPeriod, HeartbeatTimeout: c.Ring.HeartbeatTimeout, TokensObservePeriod: 0, @@ -129,7 +131,7 @@ func newRing(config RingConfig, logger log.Logger, reg prometheus.Registerer) (* logger, ) if err != nil { - return nil, errors.Wrap(err, "failed to initialize overrides-exporter's KV store") + return nil, fmt.Errorf("failed to initialize overrides-exporter's KV store: %w", err) } delegate := ring.BasicLifecyclerDelegate(ring.NewInstanceRegisterDelegate(ring.ACTIVE, ringNumTokens)) @@ -144,17 +146,17 @@ func newRing(config RingConfig, logger log.Logger, reg prometheus.Registerer) (* const ringName = "overrides-exporter" lifecycler, err := ring.NewBasicLifecycler(lifecyclerConfig, ringName, ringKey, kvStore, delegate, logger, reg) if err != nil { - return nil, errors.Wrap(err, "failed to initialize overrides-exporter's lifecycler") + return nil, fmt.Errorf("failed to initialize overrides-exporter's lifecycler: %w", err) } ringClient, err := ring.New(config.ToRingConfig(), ringName, ringKey, logger, reg) if err != nil { - return nil, errors.Wrap(err, "failed to create a overrides-exporter ring client") + return nil, fmt.Errorf("failed to create a overrides-exporter ring client: %w", err) } manager, err := services.NewManager(lifecycler, ringClient) if err != nil { - return nil, errors.Wrap(err, "failed to create service manager") + return nil, fmt.Errorf("failed to create service manager: %w", err) } r := &overridesExporterRing{ @@ -184,7 +186,7 @@ func (r *overridesExporterRing) isLeader() (bool, error) { func ringLeader(r ring.ReadRing) (*ring.InstanceDesc, error) { rs, err := r.Get(leaderToken, ringOp, nil, nil, nil) if err != nil { - return nil, errors.Wrapf(err, "failed to get a healthy instance for token %d", leaderToken) + return nil, fmt.Errorf("failed to get a healthy instance for token %d: %w", leaderToken, err) } if len(rs.Instances) != 1 { return nil, fmt.Errorf("got %d instances for token %d (but expected 1)", len(rs.Instances), leaderToken) @@ -196,12 +198,12 @@ func ringLeader(r ring.ReadRing) (*ring.InstanceDesc, error) { func (r *overridesExporterRing) starting(ctx context.Context) error { r.subserviceWatcher.WatchManager(r.subserviceManager) if err := services.StartManagerAndAwaitHealthy(ctx, r.subserviceManager); err != nil { - return errors.Wrap(err, "unable to start overrides-exporter ring subservice manager") + return fmt.Errorf("unable to start overrides-exporter ring subservice manager: %w", err) } level.Info(r.logger).Log("msg", "waiting until overrides-exporter is ACTIVE in the ring") if err := ring.WaitInstanceState(ctx, r.client, r.lifecycler.GetInstanceID(), ring.ACTIVE); err != nil { - return errors.Wrap(err, "overrides-exporter failed to become ACTIVE in the ring") + return fmt.Errorf("overrides-exporter failed to become ACTIVE in the ring: %w", err) } level.Info(r.logger).Log("msg", "overrides-exporter is ACTIVE in the ring") @@ -228,13 +230,14 @@ func (r *overridesExporterRing) running(ctx context.Context) error { case <-ctx.Done(): return nil case err := <-r.subserviceWatcher.Chan(): - return errors.Wrap(err, "a subservice of overrides-exporter ring has failed") + return fmt.Errorf("a subservice of overrides-exporter ring has failed: %w", err) } } func (r *overridesExporterRing) stopping(_ error) error { - return errors.Wrap( - services.StopManagerAndAwaitStopped(context.Background(), r.subserviceManager), - "failed to stop overrides-exporter's ring subservice manager", - ) + err := services.StopManagerAndAwaitStopped(context.Background(), r.subserviceManager) + if err != nil { + return fmt.Errorf("failed to stop overrides-exporter's ring subservice manager: %w", err) + } + return nil } diff --git a/pkg/validation/exporter/ring_test.go b/pkg/validation/exporter/ring_test.go index a40ffe6498..ab1e2f7a87 100644 --- a/pkg/validation/exporter/ring_test.go +++ b/pkg/validation/exporter/ring_test.go @@ -68,8 +68,8 @@ func TestOverridesExporterRing_scaleDown(t *testing.T) { ctx := context.Background() require.NoError(t, ringStore.CAS(ctx, ringKey, func(in interface{}) (out interface{}, retry bool, err error) { desc := ring.NewDesc() - desc.AddIngester(l1.GetInstanceID(), l1.GetInstanceAddr(), "", []uint32{leaderToken + 1}, ring.ACTIVE, time.Now()) - desc.AddIngester(l2.GetInstanceID(), l2.GetInstanceAddr(), "", []uint32{leaderToken + 2}, ring.ACTIVE, time.Now()) + desc.AddIngester(l1.GetInstanceID(), l1.GetInstanceAddr(), "", []uint32{leaderToken + 1}, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) + desc.AddIngester(l2.GetInstanceID(), l2.GetInstanceAddr(), "", []uint32{leaderToken + 2}, ring.ACTIVE, time.Now(), false, time.Now(), ring.InstanceVersions{}) return desc, true, nil })) diff --git a/pkg/validation/limits.go b/pkg/validation/limits.go index 4d0131628b..a1fe3d51d8 100644 --- a/pkg/validation/limits.go +++ b/pkg/validation/limits.go @@ -4,13 +4,20 @@ import ( "encoding/json" "flag" "fmt" + "iter" "time" - "github.com/pkg/errors" "github.com/prometheus/common/model" - "gopkg.in/yaml.v3" - - "github.com/grafana/pyroscope/pkg/phlaredb/block" + "go.yaml.in/yaml/v3" + + "github.com/grafana/pyroscope/v2/pkg/distributor/ingestlimits" + "github.com/grafana/pyroscope/v2/pkg/distributor/sampling" + "github.com/grafana/pyroscope/v2/pkg/distributor/writepath" + "github.com/grafana/pyroscope/v2/pkg/frontend/readpath" + "github.com/grafana/pyroscope/v2/pkg/metastore/index/cleaner/retention" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/phlaredb/block" + placement "github.com/grafana/pyroscope/v2/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" ) const ( @@ -27,13 +34,19 @@ const ( // to support tenant-friendly duration format (e.g: "1h30m45s") in JSON value. type Limits struct { // Distributor enforced limits. - IngestionRateMB float64 `yaml:"ingestion_rate_mb" json:"ingestion_rate_mb"` - IngestionBurstSizeMB float64 `yaml:"ingestion_burst_size_mb" json:"ingestion_burst_size_mb"` - MaxLabelNameLength int `yaml:"max_label_name_length" json:"max_label_name_length"` - MaxLabelValueLength int `yaml:"max_label_value_length" json:"max_label_value_length"` - MaxLabelNamesPerSeries int `yaml:"max_label_names_per_series" json:"max_label_names_per_series"` - MaxSessionsPerSeries int `yaml:"max_sessions_per_series" json:"max_sessions_per_series"` - EnforceLabelsOrder bool `yaml:"enforce_labels_order" json:"enforce_labels_order"` + IngestionRateMB float64 `yaml:"ingestion_rate_mb" json:"ingestion_rate_mb"` + IngestionBurstSizeMB float64 `yaml:"ingestion_burst_size_mb" json:"ingestion_burst_size_mb"` + IngestionLimit *ingestlimits.Config `yaml:"ingestion_limit" json:"ingestion_limit" category:"advanced" doc:"hidden"` + IngestionBodyLimitMB float64 `yaml:"ingestion_body_limit_mb" json:"ingestion_body_limit_mb" category:"advanced" doc:"hidden"` + DistributorSampling *sampling.Config `yaml:"distributor_sampling" json:"distributor_sampling" category:"advanced" doc:"hidden"` + KeepStrippedProfiles bool `yaml:"keep_stripped_profiles" json:"keep_stripped_profiles"` + MaxLabelNameLength int `yaml:"max_label_name_length" json:"max_label_name_length"` + MaxLabelValueLength int `yaml:"max_label_value_length" json:"max_label_value_length"` + MaxLabelNamesPerSeries int `yaml:"max_label_names_per_series" json:"max_label_names_per_series"` + MaxSessionsPerSeries int `yaml:"max_sessions_per_series" json:"max_sessions_per_series"` + EnforceLabelsOrder bool `yaml:"enforce_labels_order" json:"enforce_labels_order"` + DisableLabelSanitization bool `yaml:"disable_label_sanitization" json:"disable_label_sanitization"` + PushMaxConcurrency int `yaml:"push_max_concurrency" json:"push_max_concurrency"` MaxProfileSizeBytes int `yaml:"max_profile_size_bytes" json:"max_profile_size_bytes"` MaxProfileStacktraceSamples int `yaml:"max_profile_stacktrace_samples" json:"max_profile_stacktrace_samples"` @@ -41,16 +54,28 @@ type Limits struct { MaxProfileStacktraceDepth int `yaml:"max_profile_stacktrace_depth" json:"max_profile_stacktrace_depth"` MaxProfileSymbolValueLength int `yaml:"max_profile_symbol_value_length" json:"max_profile_symbol_value_length"` + // Distributor per-app usage breakdown. + DistributorUsageGroups *UsageGroupConfig `yaml:"distributor_usage_groups" json:"distributor_usage_groups"` + // Distributor aggregation. DistributorAggregationWindow model.Duration `yaml:"distributor_aggregation_window" json:"distributor_aggregation_window"` DistributorAggregationPeriod model.Duration `yaml:"distributor_aggregation_period" json:"distributor_aggregation_period"` + // IngestionRelabelingRules allow to specify additional relabeling rules that get applied before a profile gets ingested. There are some default relabeling rules, which ensure consistency of profiling series. The position of the default rules can be contolled by IngestionRelabelingDefaultRulesPosition + IngestionRelabelingRules IngestionRelabelRules `yaml:"ingestion_relabeling_rules" json:"ingestion_relabeling_rules" category:"advanced"` + IngestionRelabelingDefaultRulesPosition RelabelRulesPosition `yaml:"ingestion_relabeling_default_rules_position" json:"ingestion_relabeling_default_rules_position" category:"advanced"` + + SampleTypeRelabelingRules SampleTypeRelabelRules `yaml:"sample_type_relabeling_rules" json:"sample_type_relabeling_rules" category:"advanced"` + // The tenant shard size determines the how many ingesters a particular // tenant will be sharded to. Needs to be specified on distributors for // correct distribution and on ingesters so that the local ingestion limit // can be calculated correctly. IngestionTenantShardSize int `yaml:"ingestion_tenant_shard_size" json:"ingestion_tenant_shard_size"` + // IngestionArtificialDelay is the artificial ingestion latency. It make sure the ingestion requests are delayed at the end of the request, to achieve a more uniform latency. + IngestionArtificialDelay model.Duration `yaml:"ingestion_artificial_delay" json:"ingestion_artificial_delay" category:"experimental" doc:"hidden"` + // Ingester enforced limits. MaxLocalSeriesPerTenant int `yaml:"max_local_series_per_tenant" json:"max_local_series_per_tenant"` MaxGlobalSeriesPerTenant int `yaml:"max_global_series_per_tenant" json:"max_global_series_per_tenant"` @@ -61,16 +86,19 @@ type Limits struct { MaxQueryParallelism int `yaml:"max_query_parallelism" json:"max_query_parallelism"` QueryAnalysisEnabled bool `yaml:"query_analysis_enabled" json:"query_analysis_enabled"` QueryAnalysisSeriesEnabled bool `yaml:"query_analysis_series_enabled" json:"query_analysis_series_enabled"` + IncludeStrippedProfiles bool `yaml:"include_stripped_profiles" json:"include_stripped_profiles"` // Flame graph enforced limits. - MaxFlameGraphNodesDefault int `yaml:"max_flamegraph_nodes_default" json:"max_flamegraph_nodes_default"` - MaxFlameGraphNodesMax int `yaml:"max_flamegraph_nodes_max" json:"max_flamegraph_nodes_max"` - + MaxFlameGraphNodesDefault int `yaml:"max_flamegraph_nodes_default" json:"max_flamegraph_nodes_default"` + MaxFlameGraphNodesMax int `yaml:"max_flamegraph_nodes_max" json:"max_flamegraph_nodes_max"` + MaxFlameGraphNodesOnSelectMergeProfile bool `yaml:"max_flamegraph_nodes_on_select_merge_profile" json:"max_flamegraph_nodes_on_select_merge_profile" category:"advanced" doc:"hidden"` // Store-gateway. StoreGatewayTenantShardSize int `yaml:"store_gateway_tenant_shard_size" json:"store_gateway_tenant_shard_size"` // Query frontend. - QuerySplitDuration model.Duration `yaml:"split_queries_by_interval" json:"split_queries_by_interval"` + QuerySplitDuration model.Duration `yaml:"split_queries_by_interval" json:"split_queries_by_interval"` + QuerySanitizeOnMerge bool `yaml:"query_sanitize_on_merge" json:"query_sanitize_on_merge"` + MaxAsyncQueryConcurrency int `yaml:"max_async_query_concurrency" json:"max_async_query_concurrency"` // Compactor. CompactorBlocksRetentionPeriod model.Duration `yaml:"compactor_blocks_retention_period" json:"compactor_blocks_retention_period"` @@ -90,6 +118,30 @@ type Limits struct { // Ensure profiles are dated within the IngestionWindow of the distributor. RejectOlderThan model.Duration `yaml:"reject_older_than" json:"reject_older_than"` RejectNewerThan model.Duration `yaml:"reject_newer_than" json:"reject_newer_than"` + + // Write path overrides used in distributor. + WritePathOverrides writepath.Config `yaml:",inline" json:",inline"` + + // Write path overrides used in query-frontend. + ReadPathOverrides readpath.Config `yaml:",inline" json:",inline"` + + // Data retention configuration. + Retention retention.Config `yaml:",inline" json:",inline"` + + // Adaptive placement limits used in distributors and in the metastore. + // Distributors use these limits to determine how many shards to allocate + // to a tenant dataset by default, if no placement rules defined. + AdaptivePlacementLimits placement.PlacementLimits `yaml:",inline" json:",inline"` + + // RecordingRules allow to specify static recording rules. This is not compatible with recording rules + // coming from a RecordingRulesClient, that will replace any static rules defined. + RecordingRules RecordingRules `yaml:"recording_rules" json:"recording_rules" category:"experimental" doc:"hidden"` + + // MaxRecordingRules is the maximum number of recording rules a tenant can create and store. + MaxRecordingRules int `yaml:"max_recording_rules" json:"max_recording_rules"` + + // Symbolizer. + Symbolizer Symbolizer `yaml:"symbolizer" json:"symbolizer" category:"experimental" doc:"hidden"` } // LimitError are errors that do not comply with the limits specified. @@ -103,14 +155,16 @@ func (e LimitError) Error() string { func (l *Limits) RegisterFlags(f *flag.FlagSet) { f.Float64Var(&l.IngestionRateMB, "distributor.ingestion-rate-limit-mb", 4, "Per-tenant ingestion rate limit in sample size per second. Units in MB.") f.Float64Var(&l.IngestionBurstSizeMB, "distributor.ingestion-burst-size-mb", 2, "Per-tenant allowed ingestion burst size (in sample size). Units in MB. The burst size refers to the per-distributor local rate limiter, and should be set at least to the maximum profile size expected in a single push request.") - + f.Float64Var(&l.IngestionBodyLimitMB, "distributor.ingestion-body-limit-mb", 256, "Per-tenant ingestion body size limit in MB, before decompressing. 0 to disable.") f.IntVar(&l.IngestionTenantShardSize, "distributor.ingestion-tenant-shard-size", 0, "The tenant's shard size used by shuffle-sharding. Must be set both on ingesters and distributors. 0 disables shuffle sharding.") + f.IntVar(&l.PushMaxConcurrency, "distributor.push.max-concurrency", 256, "Maximum number of series within a single batched push that are processed concurrently. 0 = unbounded (legacy behavior); 1 = serialize pushes (kill switch).") f.IntVar(&l.MaxLabelNameLength, "validation.max-length-label-name", 1024, "Maximum length accepted for label names.") f.IntVar(&l.MaxLabelValueLength, "validation.max-length-label-value", 2048, "Maximum length accepted for label value. This setting also applies to the metric name.") f.IntVar(&l.MaxLabelNamesPerSeries, "validation.max-label-names-per-series", 30, "Maximum number of label names per series.") f.IntVar(&l.MaxSessionsPerSeries, "validation.max-sessions-per-series", 0, "Maximum number of sessions per series. 0 to disable.") f.BoolVar(&l.EnforceLabelsOrder, "validation.enforce-labels-order", false, "Enforce labels order optimization.") + f.BoolVar(&l.DisableLabelSanitization, "validation.disable-label-sanitization", true, "Disable label name sanitization (converting dots to underscores). When disabled, labels with dots are accepted as-is using UTF-8 validation.") f.IntVar(&l.MaxLocalSeriesPerTenant, "ingester.max-local-series-per-tenant", 0, "Maximum number of active series of profiles per tenant, per ingester. 0 to disable.") f.IntVar(&l.MaxGlobalSeriesPerTenant, "ingester.max-global-series-per-tenant", 5000, "Maximum number of active series of profiles per tenant, across the cluster. 0 to disable. When the global limit is enabled, each ingester is configured with a dynamic local limit based on the replication factor and the current number of healthy ingesters, and is kept updated whenever the number of ingesters change.") @@ -125,6 +179,8 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) { _ = l.QuerySplitDuration.Set("0s") f.Var(&l.QuerySplitDuration, "querier.split-queries-by-interval", "Split queries by a time interval and execute in parallel. The value 0 disables splitting by time") + f.BoolVar(&l.QuerySanitizeOnMerge, "querier.sanitize-on-merge", true, "Whether profiles should be sanitized when merging.") + f.IntVar(&l.MaxAsyncQueryConcurrency, "query-frontend.max-async-query-concurrency", 5, "Maximum number of concurrent async queries per tenant. 0 to disable async queries.") f.IntVar(&l.MaxQueryParallelism, "querier.max-query-parallelism", 0, "Maximum number of queries that will be scheduled in parallel by the frontend.") @@ -138,8 +194,11 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) { f.IntVar(&l.MaxProfileSymbolValueLength, "validation.max-profile-symbol-value-length", 65535, "Maximum length of a profile symbol value (labels, function names and filenames, etc...). Profiles are not rejected instead symbol values are truncated. 0 to disable.") f.IntVar(&l.MaxFlameGraphNodesDefault, "querier.max-flamegraph-nodes-default", 8<<10, "Maximum number of flame graph nodes by default. 0 to disable.") - f.IntVar(&l.MaxFlameGraphNodesMax, "querier.max-flamegraph-nodes-max", 0, "Maximum number of flame graph nodes allowed. 0 to disable.") + f.IntVar(&l.MaxFlameGraphNodesMax, "querier.max-flamegraph-nodes-max", 1<<20, "Maximum number of flame graph nodes allowed. 0 to disable.") + f.BoolVar(&l.MaxFlameGraphNodesOnSelectMergeProfile, "querier.max-flamegraph-nodes-on-select-merge-profile", false, "Enforce the max nodes limits and defaults on SelectMergeProfile API. Historically this limit was not enforced to enable to gather full pprof profiles without truncation.") + f.BoolVar(&l.KeepStrippedProfiles, "distributor.sampling.keep-stripped-profiles", false, "When a profile is sampled out, retain its totals and labels with stacktraces stripped (marked __sampled__) instead of dropping it.") + f.BoolVar(&l.IncludeStrippedProfiles, "query-backend.include-stripped-profiles", false, "Include profiles that were sampled out and stored with stacktraces stripped (marked __sampled__) in query results.") f.Var(&l.DistributorAggregationWindow, "distributor.aggregation-window", "Duration of the distributor aggregation window. Requires aggregation period to be specified. 0 to disable.") f.Var(&l.DistributorAggregationPeriod, "distributor.aggregation-period", "Duration of the distributor aggregation period. Requires aggregation window to be specified. 0 to disable.") @@ -150,13 +209,26 @@ func (l *Limits) RegisterFlags(f *flag.FlagSet) { f.IntVar(&l.CompactorTenantShardSize, "compactor.compactor-tenant-shard-size", 0, "Max number of compactors that can compact blocks for single tenant. 0 to disable the limit and use all compactors.") _ = l.CompactorPartialBlockDeletionDelay.Set("1d") f.Var(&l.CompactorPartialBlockDeletionDelay, "compactor.partial-block-deletion-delay", fmt.Sprintf("If a partial block (unfinished block without %s file) hasn't been modified for this time, it will be marked for deletion. The minimum accepted value is %s: a lower value will be ignored and the feature disabled. 0 to disable.", block.MetaFilename, MinCompactorPartialBlockDeletionDelay.String())) - f.BoolVar(&l.CompactorDownsamplerEnabled, "compactor.compactor-downsampler-enabled", true, "If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept.") + f.BoolVar(&l.CompactorDownsamplerEnabled, "compactor.compactor-downsampler-enabled", true, "If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. Note: This set the default for the teanant overrides, in order to be effective it also requires compactor.downsampler-enabled to be set to true.") _ = l.RejectNewerThan.Set("10m") f.Var(&l.RejectNewerThan, "validation.reject-newer-than", "This limits how far into the future profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 10m.") _ = l.RejectOlderThan.Set("1h") f.Var(&l.RejectOlderThan, "validation.reject-older-than", "This limits how far into the past profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 1h.") + + _ = l.IngestionRelabelingDefaultRulesPosition.Set("first") + f.Var(&l.IngestionRelabelingDefaultRulesPosition, "distributor.ingestion-relabeling-default-rules-position", "Position of the default ingestion relabeling rules in relation to relabel rules from overrides. Valid values are 'first', 'last' or 'disabled'.") + _ = l.IngestionRelabelingRules.Set("[]") + f.Var(&l.IngestionRelabelingRules, "distributor.ingestion-relabeling-rules", "List of ingestion relabel configurations. The relabeling rules work the same way, as those of [Prometheus](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config). All rules are applied in the order they are specified. Note: In most situations, it is more effective to use relabeling directly in Grafana Alloy.") + + _ = l.SampleTypeRelabelingRules.Set("[]") + f.Var(&l.SampleTypeRelabelingRules, "distributor.sample-type-relabeling-rules", "List of sample type relabel configurations. Rules are applied to sample types with __type__ and __unit__ labels, along with all series labels.") + + f.Var(&l.IngestionArtificialDelay, "distributor.ingestion-artificial-delay", "Target ingestion delay to apply to all tenants. If set to a non-zero value, the distributor will artificially delay ingestion time-frame by the specified duration by computing the difference between actual ingestion and the target. There is no delay on actual ingestion of samples, it is only the response back to the client.") + + f.IntVar(&l.MaxRecordingRules, "recording-rules.max-rules-per-tenant", 25, "Maximum number of recording rules a tenant can create. 0 to disable.") + } // UnmarshalYAML implements the yaml.Unmarshaler interface. @@ -170,10 +242,10 @@ func (l *Limits) UnmarshalYAML(unmarshal func(interface{}) error) error { if defaultLimits != nil { b, err := yaml.Marshal(defaultLimits) if err != nil { - return errors.Wrap(err, "cloning limits (marshaling)") + return fmt.Errorf("cloning limits (marshaling): %w", err) } if err := yaml.Unmarshal(b, (*plain)(l)); err != nil { - return errors.Wrap(err, "cloning limits (unmarshaling)") + return fmt.Errorf("cloning limits (unmarshaling): %w", err) } } return unmarshal((*plain)(l)) @@ -181,6 +253,19 @@ func (l *Limits) UnmarshalYAML(unmarshal func(interface{}) error) error { // Validate validates that this limits config is valid. func (l *Limits) Validate() error { + if l.IngestionRelabelingDefaultRulesPosition != "" { + if err := l.IngestionRelabelingDefaultRulesPosition.Set(string(l.IngestionRelabelingDefaultRulesPosition)); err != nil { + return err + } + } + + for idx, rule := range l.RecordingRules { + _, err := phlaremodel.NewRecordingRule(rule) + if err != nil { + return fmt.Errorf("rule at pos %d is not valid: %v", idx, err) + } + } + return nil } @@ -203,6 +288,8 @@ type TenantLimits interface { TenantLimits(tenantID string) *Limits // AllByTenantID gets a mapping of all tenant IDs and limits for that tenant AllByTenantID() map[string]*Limits + // RuntimeConfig returns the runtime config values, if available, and nil otherwise. + RuntimeConfig() *RuntimeConfigValues } // Overrides periodically fetch a set of per-tenant overrides, and provides convenience @@ -237,6 +324,31 @@ func (o *Overrides) IngestionBurstSizeBytes(tenantID string) int { return int(o.getOverridesForTenant(tenantID).IngestionBurstSizeMB * bytesInMB) } +func (o *Overrides) IngestionBodyLimitBytes(tenantID string) int64 { + return int64(o.getOverridesForTenant(tenantID).IngestionBodyLimitMB * bytesInMB) +} + +func (o *Overrides) IngestionLimit(tenantID string) *ingestlimits.Config { + return o.getOverridesForTenant(tenantID).IngestionLimit +} + +func (o *Overrides) DistributorSampling(tenantID string) *sampling.Config { + return o.getOverridesForTenant(tenantID).DistributorSampling +} + +func (o *Overrides) KeepStrippedProfiles(tenantID string) bool { + return o.getOverridesForTenant(tenantID).KeepStrippedProfiles +} + +func (o *Overrides) IncludeStrippedProfiles(tenantID string) bool { + return o.getOverridesForTenant(tenantID).IncludeStrippedProfiles +} + +// IngestionArtificialDelay returns the artificial ingestion latency for a given user. +func (o *Overrides) IngestionArtificialDelay(tenantID string) time.Duration { + return time.Duration(o.getOverridesForTenant(tenantID).IngestionArtificialDelay) +} + // IngestionTenantShardSize returns the ingesters shard size for a given user. func (o *Overrides) IngestionTenantShardSize(tenantID string) int { return o.getOverridesForTenant(tenantID).IngestionTenantShardSize @@ -292,6 +404,10 @@ func (o *Overrides) EnforceLabelsOrder(tenantID string) bool { return o.getOverridesForTenant(tenantID).EnforceLabelsOrder } +func (o *Overrides) DisableLabelSanitization(tenantID string) bool { + return o.getOverridesForTenant(tenantID).DisableLabelSanitization +} + func (o *Overrides) DistributorAggregationWindow(tenantID string) model.Duration { return o.getOverridesForTenant(tenantID).DistributorAggregationWindow } @@ -323,6 +439,13 @@ func (o *Overrides) MaxQueryParallelism(tenantID string) int { return o.getOverridesForTenant(tenantID).MaxQueryParallelism } +// PushMaxConcurrency returns the maximum number of series within a single +// batched push that the distributor processes concurrently. 0 means unbounded +// (legacy behavior); 1 serializes pushes (kill switch). +func (o *Overrides) PushMaxConcurrency(tenantID string) int { + return o.getOverridesForTenant(tenantID).PushMaxConcurrency +} + // MaxQueryLookback returns the max lookback period of queries. func (o *Overrides) MaxQueryLookback(tenantID string) time.Duration { return time.Duration(o.getOverridesForTenant(tenantID).MaxQueryLookback) @@ -338,6 +461,11 @@ func (o *Overrides) MaxFlameGraphNodesMax(tenantID string) int { return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesMax } +// MaxFlameGraphNodesOnSelectMergeProfiles returns if the max flame graph nodes should be enforced for the SelectMergeProfile API. +func (o *Overrides) MaxFlameGraphNodesOnSelectMergeProfile(tenantID string) bool { + return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesOnSelectMergeProfile +} + // StoreGatewayTenantShardSize returns the store-gateway shard size for a given user. func (o *Overrides) StoreGatewayTenantShardSize(userID string) int { return o.getOverridesForTenant(userID).StoreGatewayTenantShardSize @@ -348,6 +476,16 @@ func (o *Overrides) QuerySplitDuration(tenantID string) time.Duration { return time.Duration(o.getOverridesForTenant(tenantID).QuerySplitDuration) } +// QuerySanitizeOnMerge returns whether profiles should be sanitized in the read path. +func (o *Overrides) QuerySanitizeOnMerge(tenantID string) bool { + return o.getOverridesForTenant(tenantID).QuerySanitizeOnMerge +} + +// MaxAsyncQueryConcurrency returns the maximum number of concurrent async queries per tenant. +func (o *Overrides) MaxAsyncQueryConcurrency(tenantID string) int { + return o.getOverridesForTenant(tenantID).MaxAsyncQueryConcurrency +} + // CompactorTenantShardSize returns number of compactors that this user can use. 0 = all compactors. func (o *Overrides) CompactorTenantShardSize(userID string) int { return o.getOverridesForTenant(userID).CompactorTenantShardSize @@ -427,12 +565,65 @@ func (o *Overrides) QueryAnalysisEnabled(tenantID string) bool { return o.getOverridesForTenant(tenantID).QueryAnalysisEnabled } +func (o *Overrides) Retention() (defaults retention.Config, overrides iter.Seq2[string, retention.Config]) { + return GetOverride(o, func(tenantID string, limits *Limits) retention.Config { + return limits.Retention + }) +} + +// GetOverride is a convenience function to get an override value for all tenants. +// The order is not deterministic. +func GetOverride[T any](o *Overrides, fn func(string, *Limits) T) (defaults T, overrides iter.Seq2[string, T]) { + defaults = fn("", o.defaultLimits) + if o.tenantLimits == nil { + return defaults, func(yield func(string, T) bool) {} + } + c := o.tenantLimits.RuntimeConfig() + if c == nil { + return defaults, func(yield func(string, T) bool) {} + } + return defaults, func(yield func(string, T) bool) { + for tenantID, limits := range c.TenantLimits { + if !yield(tenantID, fn(tenantID, limits)) { + return + } + } + } +} + // QueryAnalysisSeriesEnabled can be used to disable the series portion of the query analysis endpoint in the query frontend. // To be used for tenants where calculating series can be expensive. func (o *Overrides) QueryAnalysisSeriesEnabled(tenantID string) bool { return o.getOverridesForTenant(tenantID).QueryAnalysisSeriesEnabled } +func (o *Overrides) WritePathOverrides(tenantID string) writepath.Config { + return o.getOverridesForTenant(tenantID).WritePathOverrides +} + +func (o *Overrides) ReadPathOverrides(tenantID string) readpath.Config { + return o.getOverridesForTenant(tenantID).ReadPathOverrides +} + +func (o *Overrides) QueryTreeEnabled(tenantID string) bool { + return o.getOverridesForTenant(tenantID).ReadPathOverrides.QueryTreeEnabled +} + +func (o *Overrides) PlacementLimits(tenantID string) placement.PlacementLimits { + // Both limits aimed at the same thing: limit the number of shards tenant's + // data is distributed to. The IngestionTenantShardSize specifies the number + // of ingester instances (taking into account the replication factor), while + // the PlacementLimits.TenantShards specifies the number of shards and it's + // not set by default. Each segment writer own very small number of shards + // (4, by default) so we can use the same value for both. + t := o.getOverridesForTenant(tenantID) + l := t.AdaptivePlacementLimits + if t.IngestionTenantShardSize > 0 && uint64(t.IngestionTenantShardSize) > l.TenantShards { + l.TenantShards = uint64(t.IngestionTenantShardSize) + } + return l +} + func (o *Overrides) DefaultLimits() *Limits { return o.defaultLimits } diff --git a/pkg/validation/limits_mock.go b/pkg/validation/limits_mock.go index 5e1247a7e5..b7aedbc5ce 100644 --- a/pkg/validation/limits_mock.go +++ b/pkg/validation/limits_mock.go @@ -10,6 +10,7 @@ import "github.com/grafana/dskit/flagext" // mockTenantLimits exposes per-tenant limits based on a provided map type mockTenantLimits struct { limits map[string]*Limits + config *RuntimeConfigValues } // NewMockTenantLimits creates a new mockTenantLimits that returns per-tenant limits based on @@ -28,6 +29,8 @@ func (l *mockTenantLimits) AllByTenantID() map[string]*Limits { return l.limits } +func (l *mockTenantLimits) RuntimeConfig() *RuntimeConfigValues { return l.config } + func MockOverrides(customize func(defaults *Limits, tenantLimits map[string]*Limits)) *Overrides { defaults := MockDefaultLimits() tenantLimits := map[string]*Limits{} diff --git a/pkg/validation/limits_test.go b/pkg/validation/limits_test.go index f70449c37c..0ccdb9fc81 100644 --- a/pkg/validation/limits_test.go +++ b/pkg/validation/limits_test.go @@ -4,10 +4,13 @@ import ( "encoding/json" "reflect" "testing" + "time" + "github.com/grafana/dskit/flagext" + "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) func TestLimitsTagsYamlMatchJson(t *testing.T) { @@ -75,6 +78,13 @@ shard_streams: blocked_queries: - pattern: ".*foo.*" regex: true +recording_rules: + - metric_name: 'any-name' + matchers: ['any-matcher'] + group_by: ['any-group-by'] + external_labels: + - name: 'any-label-name' + value: 'any-label-value' ` inputJSON := ` { @@ -120,10 +130,23 @@ blocked_queries: "logging_enabled": true }, "blocked_queries": [ - { - "pattern": ".*foo.*", - "regex": true - } + { + "pattern": ".*foo.*", + "regex": true + } + ], + "recording_rules": [ + { + "metric_name": "any-name", + "matchers": ["any-matcher"], + "group_by": ["any-group-by"], + "external_labels": [ + { + "name" : "any-label-name", + "value" : "any-label-value" + } + ] + } ] } ` @@ -162,3 +185,57 @@ func TestOverwriteMarshalingStringMapYAML(t *testing.T) { require.Nil(t, yaml.Unmarshal(out, &back)) require.Equal(t, m, back) } + +func TestDistributorIngestionArtificialDelay(t *testing.T) { + tests := map[string]struct { + tenantID string + defaultLimits func(*Limits) + tenantLimits func(*Limits) + expectedDelay time.Duration + }{ + "should not apply delay by default": { + tenantID: "tenant-a", + tenantLimits: func(*Limits) {}, + expectedDelay: 0, + }, + "should apply globally if set": { + tenantID: "tenant-a", + defaultLimits: func(l *Limits) { + l.IngestionArtificialDelay = model.Duration(time.Second) + }, + tenantLimits: func(*Limits) {}, + expectedDelay: time.Second, + }, + "should apply delay if a plain delay has been configured for the tenant": { + tenantID: "tenant-a", + tenantLimits: func(l *Limits) { + l.IngestionArtificialDelay = model.Duration(time.Second) + }, + expectedDelay: time.Second, + }, + "should tenant limit should override global": { + tenantID: "tenant-a", + defaultLimits: func(l *Limits) { + l.IngestionArtificialDelay = model.Duration(time.Second) + }, + tenantLimits: func(l *Limits) { + l.IngestionArtificialDelay = model.Duration(0) + }, + expectedDelay: 0, + }, + } + for testName, testData := range tests { + t.Run(testName, func(t *testing.T) { + tenantLimits := &Limits{} + flagext.DefaultValues(tenantLimits) + if testData.defaultLimits != nil { + testData.defaultLimits(tenantLimits) + } + testData.tenantLimits(tenantLimits) + + ov, err := NewOverrides(Limits{}, NewMockTenantLimits(map[string]*Limits{testData.tenantID: tenantLimits})) + require.NoError(t, err) + require.Equal(t, testData.expectedDelay, ov.IngestionArtificialDelay(testData.tenantID)) + }) + } +} diff --git a/pkg/validation/recording_rules.go b/pkg/validation/recording_rules.go new file mode 100644 index 0000000000..0aadaf426b --- /dev/null +++ b/pkg/validation/recording_rules.go @@ -0,0 +1,59 @@ +package validation + +import ( + "encoding/json" + "flag" + "fmt" + + "go.yaml.in/yaml/v3" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" +) + +type RecordingRules []*settingsv1.RecordingRule + +func (r *RecordingRules) RegisterFlags(f *flag.FlagSet) { + f.Var(r, "compaction-worker.metrics-exporter.rules-source.static", "List of static recording rules of the type settingsv1.RecordingRule. Will only be use in the absence of a recording rules client.") +} + +func (r *RecordingRules) Set(s string) error { + var rules []*settingsv1.RecordingRule + if err := json.Unmarshal([]byte(s), &rules); err != nil { + return fmt.Errorf("failed to unmarshal recording rules: %w", err) + } + *r = rules + return nil +} + +func (r *RecordingRules) String() string { + jsonBytes, err := json.Marshal(*r) + if err != nil { + panic(fmt.Errorf("error marshal json: %w", err)) + } + return string(jsonBytes) +} + +func (r *RecordingRules) UnmarshalYAML(value *yaml.Node) error { + var temp interface{} + if err := value.Decode(&temp); err != nil { + return err + } + + jsonBytes, err := json.Marshal(temp) + if err != nil { + return err + } + + return json.Unmarshal(jsonBytes, r) +} + +func (o *Overrides) RecordingRules(tenantId string) []*settingsv1.RecordingRule { + limits := o.getOverridesForTenant(tenantId) + return limits.RecordingRules +} + +// MaxRecordingRules returns the maximum number of recording rules a tenant is +// allowed to create and store. A value of 0 means no limit. +func (o *Overrides) MaxRecordingRules(tenantId string) int { + return o.getOverridesForTenant(tenantId).MaxRecordingRules +} diff --git a/pkg/validation/recording_rules_test.go b/pkg/validation/recording_rules_test.go new file mode 100644 index 0000000000..4a5599f756 --- /dev/null +++ b/pkg/validation/recording_rules_test.go @@ -0,0 +1,88 @@ +package validation + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + settingsv1 "github.com/grafana/pyroscope/api/gen/proto/go/settings/v1" + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +const recordingRulesOverrideConfig = ` +overrides: + empty-overrides: {} + empty-rules: + recording_rules: [] + some-rules: + recording_rules: + - metric_name: 'profiles_recorded_any_name' + matchers: ['{__profile_type__="any-profile-type", foo="bar"}'] + group_by: ['any_group_by'] + external_labels: + - name: 'any_label_name' + value: 'any-label-value' +` + +func Test_RecordingRules(t *testing.T) { + rc, err := LoadRuntimeConfig(bytes.NewReader([]byte(recordingRulesOverrideConfig))) + require.NoError(t, err) + + o, err := newOverrides(rc) + require.NoError(t, err) + + rules := o.RecordingRules("no-overrides") + assert.Equal(t, 0, len(rules)) + + rules = o.RecordingRules("empty-overrides") + assert.Equal(t, 0, len(rules)) + + rules = o.RecordingRules("empty-rules") + assert.Equal(t, 0, len(rules)) + + rules = o.RecordingRules("some-rules") + assert.Equal(t, []*settingsv1.RecordingRule{ + { + MetricName: "profiles_recorded_any_name", + Matchers: []string{"{__profile_type__=\"any-profile-type\", foo=\"bar\"}"}, + GroupBy: []string{"any_group_by"}, + ExternalLabels: []*typesv1.LabelPair{{Name: "any_label_name", Value: "any-label-value"}}, + }, + }, rules) + + _, err = LoadRuntimeConfig(bytes.NewReader([]byte(` +overrides: + wrong_name: + recording_rules: + - metric_name: "" + `))) + require.ErrorContains(t, err, "invalid metric name: ") + + _, err = LoadRuntimeConfig(bytes.NewReader([]byte(` +overrides: + wrong_name: + recording_rules: + - metric_name: "metric_name_without_preffix" + `))) + require.ErrorContains(t, err, "metric name must start with profiles_recorded_") + + _, err = LoadRuntimeConfig(bytes.NewReader([]byte(` +overrides: + malformed_matchers: + recording_rules: + - metric_name: 'profiles_recorded_any_name' + matchers: ['{foo="bar}'] + `))) + require.ErrorContains(t, err, "failed to parse matchers") + + _, err = LoadRuntimeConfig(bytes.NewReader([]byte(` +overrides: + missing_profile_type: + recording_rules: + - metric_name: 'profiles_recorded_any_name' + matchers: ['{foo="bar"}'] + `))) + require.ErrorContains(t, err, "no __profile_type__ matcher present") +} diff --git a/pkg/validation/relabeling.go b/pkg/validation/relabeling.go new file mode 100644 index 0000000000..319efe084c --- /dev/null +++ b/pkg/validation/relabeling.go @@ -0,0 +1,188 @@ +package validation + +import ( + "encoding/json" + "fmt" + + "go.yaml.in/yaml/v3" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/relabel" +) + +var ( + godeltaprof = relabel.MustNewRegexp("godeltaprof_(.*)") + defaultRelabelRules = []*relabel.Config{ + // replace godeltaprof_ prefix from name + { + SourceLabels: []model.LabelName{"__name__"}, + Action: relabel.Replace, + Regex: godeltaprof, + TargetLabel: "__name_replaced__", + Replacement: "$0", + }, + { + SourceLabels: []model.LabelName{"__name_replaced__"}, + Action: relabel.Replace, + Regex: godeltaprof, + TargetLabel: "__delta__", + Replacement: "false", + }, + { + SourceLabels: []model.LabelName{"__name__"}, + Regex: godeltaprof, + Action: relabel.Replace, + TargetLabel: "__name__", + Replacement: "$1", + }, + // replace wall with process_cpu when __type__ is cpu + { + SourceLabels: []model.LabelName{"__name__", "__type__"}, + Separator: "/", + Regex: relabel.MustNewRegexp("wall/cpu"), + Action: relabel.Replace, + Replacement: "wall", + TargetLabel: "__name_replaced__", + }, + { + SourceLabels: []model.LabelName{"__name__", "__type__"}, + Separator: "/", + Regex: relabel.MustNewRegexp("wall/cpu"), + Action: relabel.Replace, + Replacement: "process_cpu", + TargetLabel: "__name__", + }, + } +) + +type RelabelRulesPosition string + +func (p *RelabelRulesPosition) Set(s string) error { + switch sp := RelabelRulesPosition(s); sp { + case RelabelRulePositionFirst, RelabelRulePositionLast, RelabelRulePositionDisabled: + *p = sp + return nil + } + return fmt.Errorf("invalid ingestion_relabeling_default_rules_position: %s", s) +} + +func (p *RelabelRulesPosition) String() string { + return string(*p) +} + +const ( + RelabelRulePositionFirst RelabelRulesPosition = "first" + RelabelRulePositionDisabled RelabelRulesPosition = "disabled" + RelabelRulePositionLast RelabelRulesPosition = "last" +) + +type RelabelRules []*relabel.Config + +func (p *RelabelRules) Set(s string) error { + v := []*relabel.Config{} + if err := yaml.Unmarshal([]byte(s), &v); err != nil { + return err + } + + for idx, rule := range v { + if err := rule.Validate(model.UTF8Validation); err != nil { + return fmt.Errorf("rule at pos %d is not valid: %w", idx, err) + } + } + *p = v + return nil +} + +func (p *RelabelRules) String() string { + yamlBytes, err := yaml.Marshal(p) + if err != nil { + panic(fmt.Errorf("error marshal yaml: %w", err)) + } + + temp := make([]interface{}, 0, len(*p)) + err = yaml.Unmarshal(yamlBytes, &temp) + if err != nil { + panic(fmt.Errorf("error unmarshal yaml: %w", err)) + } + + jsonBytes, err := json.Marshal(temp) + if err != nil { + panic(fmt.Errorf("error marshal json: %w", err)) + } + return string(jsonBytes) +} + +type IngestionRelabelRules []*relabel.Config + +func (r *IngestionRelabelRules) Set(s string) error { + return (*RelabelRules)(r).Set(s) +} + +func (r *IngestionRelabelRules) String() string { + return (*RelabelRules)(r).String() +} + +func (r *IngestionRelabelRules) ExampleDoc() (comment string, yaml interface{}) { + return `This example consists of two rules, the first one will drop all profiles received with an label 'environment="secrets"' and the second rule will add a label 'powered_by="Grafana Labs"' to all profile series.`, + []map[string]interface{}{ + {"action": "drop", "source_labels": []interface{}{"environment"}, "regex": "secret"}, + {"action": "replace", "replacement": "grafana-labs", "target_label": "powered_by"}, + } +} + +type SampleTypeRelabelRules []*relabel.Config + +func (r *SampleTypeRelabelRules) Set(s string) error { + if err := (*RelabelRules)(r).Set(s); err != nil { + return err + } + + for idx, rule := range *r { + if rule.Action != relabel.Drop && rule.Action != relabel.Keep { + return fmt.Errorf("rule at pos %d: sample type relabeling only supports 'drop' and 'keep' actions, got '%s'", idx, rule.Action) + } + } + return nil +} + +func (r *SampleTypeRelabelRules) String() string { + return (*RelabelRules)(r).String() +} + +func (r *SampleTypeRelabelRules) ExampleDoc() (comment string, yaml interface{}) { + return `This example shows sample type filtering rules. The first rule drops all allocation-related sample types (alloc_objects, alloc_space) from memory profiles, keeping only in-use metrics. The second rule keeps only CPU-related sample types by matching the __type__ label. The third rule shows how to drop allocation sample types for a specific service by combining __type__ and service_name labels.`, + []map[string]interface{}{ + {"action": "drop", "source_labels": []interface{}{"__type__"}, "regex": "alloc_.*"}, + {"action": "keep", "source_labels": []interface{}{"__type__"}, "regex": "cpu|wall"}, + {"action": "drop", "source_labels": []interface{}{"__type__", "service_name"}, "separator": ";", "regex": "alloc_.*;my-service"}, + } +} + +func (o *Overrides) IngestionRelabelingRules(tenantID string) []*relabel.Config { + l := o.getOverridesForTenant(tenantID) + + // return only custom rules when default rules are disabled + if l.IngestionRelabelingDefaultRulesPosition == RelabelRulePositionDisabled { + return l.IngestionRelabelingRules + } + + // quick return if no rules are defined + if len(l.IngestionRelabelingRules) == 0 { + return defaultRelabelRules + } + + rules := make([]*relabel.Config, 0, len(l.IngestionRelabelingRules)+len(defaultRelabelRules)) + + if l.IngestionRelabelingDefaultRulesPosition == "" || l.IngestionRelabelingDefaultRulesPosition == RelabelRulePositionFirst { + rules = append(rules, defaultRelabelRules...) + return append(rules, l.IngestionRelabelingRules...) + } + + rules = append(rules, l.IngestionRelabelingRules...) + return append(rules, defaultRelabelRules...) +} + +func (o *Overrides) SampleTypeRelabelingRules(tenantID string) []*relabel.Config { + l := o.getOverridesForTenant(tenantID) + return l.SampleTypeRelabelingRules +} diff --git a/pkg/validation/relabeling_test.go b/pkg/validation/relabeling_test.go new file mode 100644 index 0000000000..523588e441 --- /dev/null +++ b/pkg/validation/relabeling_test.go @@ -0,0 +1,209 @@ +package validation + +import ( + "bytes" + "flag" + "testing" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/model/relabel" + "github.com/stretchr/testify/require" + + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +type wrappedRuntimeConfig struct { + rc *RuntimeConfigValues +} + +func (w *wrappedRuntimeConfig) TenantLimits(tenantID string) *Limits { + return w.rc.TenantLimits[tenantID] +} + +func (w *wrappedRuntimeConfig) AllByTenantID() map[string]*Limits { + return w.rc.TenantLimits +} + +func (w *wrappedRuntimeConfig) RuntimeConfig() *RuntimeConfigValues { + return w.rc +} + +func newOverrides(rc *RuntimeConfigValues) (*Overrides, error) { + var defaultCfg Limits + fs := flag.NewFlagSet("test", flag.PanicOnError) + defaultCfg.RegisterFlags(fs) + return NewOverrides(defaultCfg, &wrappedRuntimeConfig{rc}) +} + +const tenantOverrideConfig = ` +overrides: + nothing: {} + disabled: + ingestion_relabeling_default_rules_position: disabled + custom-rule-end: + ingestion_relabeling_rules: + - action: drop + custom-rule-start: + ingestion_relabeling_default_rules_position: last + ingestion_relabeling_rules: + - action: drop + custom-rule-only: + ingestion_relabeling_default_rules_position: disabled + ingestion_relabeling_rules: + - action: drop + +` + +func Test_IngestionRelabelingRules(t *testing.T) { + rc, err := LoadRuntimeConfig(bytes.NewReader([]byte(tenantOverrideConfig))) + require.NoError(t, err) + + o, err := newOverrides(rc) + require.NoError(t, err) + + rules := o.IngestionRelabelingRules("xxxx") + require.Equal(t, len(defaultRelabelRules), len(rules)) + + rules = o.IngestionRelabelingRules("nothing") + require.Equal(t, len(defaultRelabelRules), len(rules)) + + rules = o.IngestionRelabelingRules("disabled") + require.Equal(t, 0, len(rules)) + + rules = o.IngestionRelabelingRules("custom-rule-end") + require.Equal(t, len(defaultRelabelRules)+1, len(rules)) + require.Equal(t, relabel.Drop, rules[len(defaultRelabelRules)].Action) + + rules = o.IngestionRelabelingRules("custom-rule-start") + require.Equal(t, len(defaultRelabelRules)+1, len(rules)) + require.Equal(t, relabel.Drop, rules[0].Action) + + rules = o.IngestionRelabelingRules("custom-rule-only") + require.Equal(t, 1, len(rules)) + require.Equal(t, relabel.Drop, rules[0].Action) + + _, err = LoadRuntimeConfig(bytes.NewReader([]byte(` +overrides: + wrong-mode: + ingestion_relabeling_default_rules_position: end + `))) + require.ErrorContains(t, err, "invalid ingestion_relabeling_default_rules_position: end") + + _, err = LoadRuntimeConfig(bytes.NewReader([]byte(` +overrides: + wrong-rule-action: + ingestion_relabeling_rules: [{action: refund}] + `))) + require.ErrorContains(t, err, "unknown relabel action \"refund\"") + + // Empty relabel config is valid with UTF8 validation (defaults to replace action with no-op). + _, err = LoadRuntimeConfig(bytes.NewReader([]byte(` +overrides: + empty-rule: + ingestion_relabeling_rules: [{}] + `))) + require.NoError(t, err) + +} + +func Test_SampleTypeRelabelRules_Set(t *testing.T) { + tests := []struct { + name string + config string + wantErr bool + errContains string + }{ + { + name: "valid drop action", + config: `[{"action": "drop", "source_labels": ["__type__"], "regex": "alloc_.*"}]`, + wantErr: false, + }, + { + name: "valid keep action", + config: `[{"action": "keep", "source_labels": ["__type__"], "regex": "cpu|wall"}]`, + wantErr: false, + }, + { + name: "invalid replace action", + config: `[{"action": "replace", "source_labels": ["__type__"], "target_label": "new_type", "replacement": "cpu"}]`, + wantErr: true, + errContains: "sample type relabeling only supports 'drop' and 'keep' actions, got 'replace'", + }, + { + name: "invalid labeldrop action", + config: `[{"action": "labeldrop", "regex": "temp_.*"}]`, + wantErr: true, + errContains: "sample type relabeling only supports 'drop' and 'keep' actions, got 'labeldrop'", + }, + { + name: "multiple rules with one invalid", + config: `[{"action": "keep", "source_labels": ["__type__"], "regex": "cpu"}, {"action": "replace", "source_labels": ["__type__"], "target_label": "new_type", "replacement": "cpu"}]`, + wantErr: true, + errContains: "rule at pos 1: sample type relabeling only supports 'drop' and 'keep' actions, got 'replace'", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var rules SampleTypeRelabelRules + err := rules.Set(tt.config) + if tt.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errContains) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_defaultRelabelRules(t *testing.T) { + for _, rule := range defaultRelabelRules { + require.NoError(t, rule.Validate(model.UTF8Validation)) + } + for _, tc := range []struct { + name string + input labels.Labels + expected labels.Labels + kept bool + }{ + { + name: "let empty through", + input: labels.Labels{}, + expected: labels.Labels{}, + kept: true, + }, + { + name: "godelta prof remove prefix", + input: labels.FromStrings( + phlaremodel.LabelNameProfileName, "godeltaprof_memory", // TODO: Verify is this is really the prefix used + ), + expected: labels.FromStrings( + phlaremodel.LabelNameProfileName, "memory", + "__name_replaced__", "godeltaprof_memory", + "__delta__", "false", + ), + kept: true, + }, + { + name: "replace wall name with cpu type", + input: labels.FromStrings( + phlaremodel.LabelNameProfileName, "wall", + phlaremodel.LabelNameType, "cpu", + ), + expected: labels.FromStrings( + phlaremodel.LabelNameProfileName, "process_cpu", + "__name_replaced__", "wall", + phlaremodel.LabelNameType, "cpu", + ), + kept: true, + }, + } { + lb := labels.NewBuilder(tc.input) + kept := relabel.ProcessBuilder(lb, defaultRelabelRules...) + require.Equal(t, tc.expected, lb.Labels()) + require.Equal(t, tc.kept, kept) + } + +} diff --git a/pkg/validation/retention_overrides_test.go b/pkg/validation/retention_overrides_test.go new file mode 100644 index 0000000000..e101123528 --- /dev/null +++ b/pkg/validation/retention_overrides_test.go @@ -0,0 +1,172 @@ +package validation + +import ( + "bytes" + "flag" + "testing" + "time" + + "github.com/prometheus/common/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/metastore/index/cleaner/retention" +) + +func TestRetentionOverridesYAML(t *testing.T) { + yamlConfig := ` +overrides: + tenant-default: {} + tenant-short: + retention_period: 24h + tenant-long: + retention_period: 30d + tenant-infinite: + retention_period: 0 +` + + runtimeConfig, err := LoadRuntimeConfig(bytes.NewReader([]byte(yamlConfig))) + require.NoError(t, err) + + var testLimits Limits + fs := flag.NewFlagSet("test", flag.PanicOnError) + testLimits.RegisterFlags(fs) + testLimits.Retention.RegisterFlags(fs) + expectedDefault := model.Duration(31 * 24 * time.Hour) + + overrides, err := NewOverrides(testLimits, &mockTenantLimits{ + limits: runtimeConfig.TenantLimits, + config: runtimeConfig, + }) + require.NoError(t, err) + defaults, overridesIter := overrides.Retention() + assert.Equal(t, expectedDefault, defaults.RetentionPeriod) + + tenantOverrides := make(map[string]retention.Config) + for tenantID, config := range overridesIter { + tenantOverrides[tenantID] = config + } + + expectedOverrides := map[string]model.Duration{ + "tenant-short": model.Duration(24 * time.Hour), + "tenant-long": model.Duration(720 * time.Hour), + "tenant-infinite": 0, // Infinite retention. + } + + for tenantID, expectedPeriod := range expectedOverrides { + config, exists := tenantOverrides[tenantID] + require.True(t, exists, "tenant %s should have override config", tenantID) + assert.Equal(t, expectedPeriod, config.RetentionPeriod, + "tenant %s should have retention period %v", tenantID, expectedPeriod) + } +} + +func TestRetentionOverridesYAML_DurationOverride(t *testing.T) { + yamlConfig := ` +overrides: + tenant-default: {} + tenant-short: + retention_period: 24h + tenant-long: + retention_period: 30d + tenant-infinite: + retention_period: 0s +` + + runtimeConfig, err := LoadRuntimeConfig(bytes.NewReader([]byte(yamlConfig))) + require.NoError(t, err) + + var testLimits Limits + fs := flag.NewFlagSet("test", flag.PanicOnError) + testLimits.RegisterFlags(fs) + testLimits.Retention.RegisterFlags(fs) + expectedDefault := model.Duration(31 * 24 * time.Hour) + + overrides, err := NewOverrides(testLimits, &mockTenantLimits{ + limits: runtimeConfig.TenantLimits, + config: runtimeConfig, + }) + require.NoError(t, err) + defaults, overridesIter := overrides.Retention() + assert.Equal(t, expectedDefault, defaults.RetentionPeriod) + + tenantOverrides := make(map[string]retention.Config) + for tenantID, config := range overridesIter { + tenantOverrides[tenantID] = config + } + + expectedOverrides := map[string]model.Duration{ + "tenant-short": model.Duration(24 * time.Hour), + "tenant-long": model.Duration(720 * time.Hour), + "tenant-infinite": 0, // Infinite retention. + } + + for tenantID, expectedPeriod := range expectedOverrides { + config, exists := tenantOverrides[tenantID] + require.True(t, exists, "tenant %s should have override config", tenantID) + assert.Equal(t, expectedPeriod, config.RetentionPeriod, + "tenant %s should have retention period %v", tenantID, expectedPeriod) + } +} + +func TestRetentionOverrides(t *testing.T) { + expectedDefault := model.Duration(31 * 24 * time.Hour) + + tests := []struct { + name string + tenantLimits map[string]*Limits + wantOverrides map[string]model.Duration + }{ + { + name: "no overrides", + tenantLimits: nil, + wantOverrides: map[string]model.Duration{}, + }, + { + name: "with tenant overrides", + tenantLimits: map[string]*Limits{ + "tenant-a": {Retention: retention.Config{RetentionPeriod: model.Duration(30 * 24 * time.Hour)}}, + "tenant-b": {Retention: retention.Config{RetentionPeriod: 0}}, // infinite + }, + wantOverrides: map[string]model.Duration{ + "tenant-a": model.Duration(30 * 24 * time.Hour), + "tenant-b": 0, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var testLimits Limits + fs := flag.NewFlagSet("test", flag.PanicOnError) + testLimits.RegisterFlags(fs) + testLimits.Retention.RegisterFlags(fs) + + var tenantLimits TenantLimits + if tt.tenantLimits != nil { + tenantLimits = &mockTenantLimits{ + limits: tt.tenantLimits, + config: &RuntimeConfigValues{TenantLimits: tt.tenantLimits}, + } + } + + overrides, err := NewOverrides(testLimits, tenantLimits) + require.NoError(t, err) + + defaults, overridesIter := overrides.Retention() + assert.Equal(t, expectedDefault, defaults.RetentionPeriod) + + actualOverrides := make(map[string]model.Duration) + for tenantID, config := range overridesIter { + actualOverrides[tenantID] = config.RetentionPeriod + } + assert.Equal(t, tt.wantOverrides, actualOverrides) + + secondPass := make(map[string]model.Duration) + for tenantID, config := range overridesIter { + secondPass[tenantID] = config.RetentionPeriod + } + assert.Equal(t, actualOverrides, secondPass) + }) + } +} diff --git a/pkg/validation/runtime_config.go b/pkg/validation/runtime_config.go new file mode 100644 index 0000000000..7364cc8172 --- /dev/null +++ b/pkg/validation/runtime_config.go @@ -0,0 +1,44 @@ +package validation + +import ( + "fmt" + "io" + + "github.com/go-kit/log/level" + "go.yaml.in/yaml/v3" + + "github.com/grafana/pyroscope/v2/pkg/util" +) + +type RuntimeConfigValues struct { + TenantLimits map[string]*Limits `yaml:"overrides"` +} + +func (r RuntimeConfigValues) validate() error { + for t, c := range r.TenantLimits { + if c == nil { + level.Warn(util.Logger).Log("msg", "skipping empty tenant limit definition", "tenant", t) + continue + } + + if err := c.Validate(); err != nil { + return fmt.Errorf("invalid override for tenant %s: %w", t, err) + } + } + + return nil +} + +func LoadRuntimeConfig(r io.Reader) (*RuntimeConfigValues, error) { + overrides := &RuntimeConfigValues{} + + decoder := yaml.NewDecoder(r) + decoder.KnownFields(true) + if err := decoder.Decode(&overrides); err != nil { + return nil, err + } + if err := overrides.validate(); err != nil { + return nil, err + } + return overrides, nil +} diff --git a/pkg/validation/symbolizer.go b/pkg/validation/symbolizer.go new file mode 100644 index 0000000000..6b285290bc --- /dev/null +++ b/pkg/validation/symbolizer.go @@ -0,0 +1,26 @@ +package validation + +import ( + "flag" +) + +type Symbolizer struct { + // Enabled enables the symbolizer in the query frontend. + Enabled bool `yaml:"enabled" json:"enabled" category:"experimental" doc:"hidden"` + + // Maximum symbol size is checked against both the payload size and the decompressed size + MaxSymbolSizeBytes int `category:"advanced"` +} + +func (s *Symbolizer) RegisterFlags(f *flag.FlagSet) { + f.BoolVar(&s.Enabled, "symbolizer.enabled", false, "Enable symbolization for tenants by default.") + f.IntVar(&s.MaxSymbolSizeBytes, "valdation.symbolizer.max-symbol-size-bytes", 512*1024*1024, "Maximum size of a symbol in bytes. This an upper limits to both the compressed and uncompressed size. 0 to disable.") +} + +func (o *Overrides) SymbolizerEnabled(tenantID string) bool { + return o.getOverridesForTenant(tenantID).Symbolizer.Enabled +} + +func (o *Overrides) SymbolizerMaxSymbolSizeBytes(tenantID string) int { + return o.getOverridesForTenant(tenantID).Symbolizer.MaxSymbolSizeBytes +} diff --git a/pkg/validation/symbolizer_test.go b/pkg/validation/symbolizer_test.go new file mode 100644 index 0000000000..0ba755ee2d --- /dev/null +++ b/pkg/validation/symbolizer_test.go @@ -0,0 +1,58 @@ +package validation + +import ( + "bytes" + "flag" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const symbolizerOverrideConfig = ` +overrides: + symbolizer-disabled: + symbolizer: + enabled: false + symbolizer-enabled: + symbolizer: + enabled: true + mixed-config: + symbolizer: + enabled: true + ingestion_rate_mb: 100 +` + +func Test_SymbolizerEnabled(t *testing.T) { + rc, err := LoadRuntimeConfig(bytes.NewReader([]byte(symbolizerOverrideConfig))) + require.NoError(t, err) + + var defaultCfg Limits + fs := flag.NewFlagSet("test", flag.PanicOnError) + defaultCfg.RegisterFlags(fs) + defaultCfg.Symbolizer.RegisterFlags(fs) + + err = fs.Parse([]string{}) + require.NoError(t, err) + + o, err := NewOverrides(defaultCfg, &wrappedRuntimeConfig{rc}) + require.NoError(t, err) + + assert.False(t, o.SymbolizerEnabled("empty-overrides")) + assert.False(t, o.SymbolizerEnabled("symbolizer-disabled")) + assert.True(t, o.SymbolizerEnabled("symbolizer-enabled")) + assert.True(t, o.SymbolizerEnabled("mixed-config")) +} + +func Test_SymbolizerMockOverrides(t *testing.T) { + overrides := MockOverrides(func(defaults *Limits, tenantLimits map[string]*Limits) { + defaults.Symbolizer.Enabled = false + + l := MockDefaultLimits() + l.Symbolizer.Enabled = true + tenantLimits["enabled-tenant"] = l + }) + + assert.False(t, overrides.SymbolizerEnabled("default-tenant")) + assert.True(t, overrides.SymbolizerEnabled("enabled-tenant")) +} diff --git a/pkg/validation/testutil.go b/pkg/validation/testutil.go index 13e04f9a06..5a3795f72c 100644 --- a/pkg/validation/testutil.go +++ b/pkg/validation/testutil.go @@ -10,13 +10,16 @@ type MockLimits struct { MaxQueryLengthValue time.Duration MaxQueryLookbackValue time.Duration QueryAnalysisEnabledValue bool + QuerySanitizeOnMergeValue bool QueryAnalysisSeriesEnabledValue bool MaxLabelNameLengthValue int MaxLabelValueLengthValue int MaxLabelNamesPerSeriesValue int + DisableLabelSanitizationValue bool - MaxFlameGraphNodesDefaultValue int - MaxFlameGraphNodesMaxValue int + MaxFlameGraphNodesDefaultValue int + MaxFlameGraphNodesMaxValue int + MaxFlameGraphNodesOnSelectMergeProfileValue bool DistributorAggregationWindowValue time.Duration DistributorAggregationPeriodValue time.Duration @@ -29,24 +32,44 @@ type MockLimits struct { MaxProfileStacktraceDepthValue int MaxProfileStacktraceSampleLabelsValue int MaxProfileSymbolValueLengthValue int + + MaxQueriersPerTenantValue int + + SymbolizerEnabledValue bool + QueryTreeEnabledValue bool + + MaxAsyncQueryConcurrencyValue int + + IngestionBodyLimitBytesValue int64 + + PushMaxConcurrencyValue int } func (m MockLimits) QuerySplitDuration(string) time.Duration { return m.QuerySplitDurationValue } func (m MockLimits) MaxQueryParallelism(string) int { return m.MaxQueryParallelismValue } +func (m MockLimits) PushMaxConcurrency(string) int { return m.PushMaxConcurrencyValue } func (m MockLimits) MaxQueryLength(tenantID string) time.Duration { return m.MaxQueryLengthValue } func (m MockLimits) MaxQueryLookback(tenantID string) time.Duration { return m.MaxQueryLookbackValue } func (m MockLimits) QueryAnalysisEnabled(tenantID string) bool { return m.QueryAnalysisEnabledValue } func (m MockLimits) QueryAnalysisSeriesEnabled(tenantID string) bool { return m.QueryAnalysisSeriesEnabledValue } - +func (m MockLimits) QuerySanitizeOnMerge(tenantID string) bool { + return m.QuerySanitizeOnMergeValue +} func (m MockLimits) MaxFlameGraphNodesDefault(string) int { return m.MaxFlameGraphNodesDefaultValue } func (m MockLimits) MaxFlameGraphNodesMax(string) int { return m.MaxFlameGraphNodesMaxValue } +func (m MockLimits) MaxFlameGraphNodesOnSelectMergeProfile(string) bool { + return m.MaxFlameGraphNodesOnSelectMergeProfileValue +} func (m MockLimits) MaxLabelNameLength(userID string) int { return m.MaxLabelNameLengthValue } func (m MockLimits) MaxLabelValueLength(userID string) int { return m.MaxLabelValueLengthValue } func (m MockLimits) MaxLabelNamesPerSeries(userID string) int { return m.MaxLabelNamesPerSeriesValue } -func (m MockLimits) MaxProfileSizeBytes(userID string) int { return m.MaxProfileSizeBytesValue } +func (m MockLimits) DisableLabelSanitization(userID string) bool { + return m.DisableLabelSanitizationValue +} +func (m MockLimits) MaxProfileSizeBytes(userID string) int { return m.MaxProfileSizeBytesValue } func (m MockLimits) MaxProfileStacktraceSamples(userID string) int { return m.MaxProfileStacktraceSamplesValue } @@ -70,6 +93,10 @@ func (m MockLimits) MaxProfileSymbolValueLength(userID string) int { return m.MaxProfileSymbolValueLengthValue } +func (m MockLimits) MaxQueriersPerTenant(_ string) int { + return m.MaxQueriersPerTenantValue +} + func (m MockLimits) RejectOlderThan(userID string) time.Duration { return m.RejectOlderThanValue } @@ -77,3 +104,11 @@ func (m MockLimits) RejectOlderThan(userID string) time.Duration { func (m MockLimits) RejectNewerThan(userID string) time.Duration { return m.RejectNewerThanValue } + +func (m MockLimits) SymbolizerEnabled(s string) bool { return m.SymbolizerEnabledValue } +func (m MockLimits) QueryTreeEnabled(s string) bool { return m.QueryTreeEnabledValue } +func (m MockLimits) MaxAsyncQueryConcurrency(s string) int { return m.MaxAsyncQueryConcurrencyValue } + +func (m MockLimits) IngestionBodyLimitBytes(tenantID string) int64 { + return m.IngestionBodyLimitBytesValue +} diff --git a/pkg/validation/usage_groups.go b/pkg/validation/usage_groups.go new file mode 100644 index 0000000000..18bb3f657b --- /dev/null +++ b/pkg/validation/usage_groups.go @@ -0,0 +1,349 @@ +// This file is a modified copy of the usage groups implementation in Mimir: +// +// https://github.com/grafana/mimir/blob/0e8c09f237649e95dc1bf3f7547fd279c24bdcf9/pkg/ingester/activeseries/custom_trackers_config.go#L48 + +package validation + +import ( + "encoding/json" + "fmt" + "strings" + "unicode/utf8" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prometheus/prometheus/model/labels" + "go.yaml.in/yaml/v3" + + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" +) + +const ( + // Maximum number of usage groups that can be configured (per tenant). + maxUsageGroups = 50 + + // The usage group name to use when no user-defined usage groups matched. + noMatchName = "other" +) + +var ( + // This is a duplicate of distributor_received_decompressed_bytes, but with + // usage_group as a label. + usageGroupReceivedDecompressedBytes = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Name: "usage_group_received_decompressed_total", + Help: "The total number of decompressed bytes per profile received by usage group.", + }, + []string{"type", "tenant", "usage_group"}, + ) + + // This is a duplicate of discarded_bytes_total, but with usage_group as a + // label. + usageGroupDiscardedBytes = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Name: "usage_group_discarded_bytes_total", + Help: "The total number of bytes that were discarded by usage group.", + }, + []string{"reason", "tenant", "usage_group"}, + ) +) + +// templatePart represents a part of a parsed usage group name template +type templatePart struct { + isLiteral bool + value string // literal text or label name for placeholder +} + +// usageGroupEntry represents a single usage group configuration +type usageGroupEntry struct { + matchers []*labels.Matcher + // For static names, template is nil and name is used + name string + // For dynamic names, template contains the parsed template parts + template []templatePart +} + +type UsageGroupConfig struct { + config map[string][]*labels.Matcher + + parsedEntries []usageGroupEntry +} + +const dynamicLabelNamePrefix = "${labels." + +type UsageGroupEvaluator struct { + logger log.Logger +} + +func NewUsageGroupEvaluator(logger log.Logger) *UsageGroupEvaluator { + return &UsageGroupEvaluator{ + logger: logger, + } +} + +func (e *UsageGroupEvaluator) GetMatch(tenantID string, c *UsageGroupConfig, lbls phlaremodel.Labels) UsageGroupMatch { + match := UsageGroupMatch{ + tenantID: tenantID, + names: make([]UsageGroupMatchName, 0, len(c.parsedEntries)), + } + + for _, entry := range c.parsedEntries { + if c.matchesAll(entry.matchers, lbls) { + if entry.template != nil { + resolvedName, err := c.expandTemplate(entry.template, lbls) + if err != nil { + level.Warn(e.logger).Log( + "msg", "failed to expand usage group template, skipping usage group", + "err", err, + "usage_group", entry.name) + continue + } + if resolvedName == "" { + level.Warn(e.logger).Log( + "msg", "usage group template expanded to empty string, skipping usage group", + "usage_group", entry.name) + continue + } + match.names = append(match.names, UsageGroupMatchName{ + ConfiguredName: entry.name, + ResolvedName: resolvedName, + }) + } else { + match.names = append(match.names, UsageGroupMatchName{ + ConfiguredName: entry.name, + ResolvedName: entry.name, + }) + } + } + } + + return match +} + +func (c *UsageGroupConfig) UnmarshalYAML(value *yaml.Node) error { + m := make(map[string]string) + err := value.Decode(&m) + if err != nil { + return fmt.Errorf("malformed usage group config: %w", err) + } + + entries, rawData, err := parseUsageGroupEntries(m) + if err != nil { + return err + } + c.parsedEntries = entries + c.config = rawData + return nil +} + +func (c *UsageGroupConfig) UnmarshalJSON(bytes []byte) error { + m := make(map[string]string) + err := json.Unmarshal(bytes, &m) + if err != nil { + return fmt.Errorf("malformed usage group config: %w", err) + } + + entries, rawData, err := parseUsageGroupEntries(m) + if err != nil { + return err + } + c.parsedEntries = entries + c.config = rawData + return nil +} + +type UsageGroupMatch struct { + tenantID string + names []UsageGroupMatchName +} + +type UsageGroupMatchName struct { + ConfiguredName string + ResolvedName string +} + +func (m *UsageGroupMatchName) IsMoreSpecificThan(other *UsageGroupMatchName) bool { + return !strings.Contains(m.ConfiguredName, dynamicLabelNamePrefix) && strings.Contains(other.ConfiguredName, dynamicLabelNamePrefix) +} + +func (m *UsageGroupMatchName) String() string { + return fmt.Sprintf("{configured: %s, resolved: %s}", m.ConfiguredName, m.ResolvedName) +} + +func (m UsageGroupMatch) CountReceivedBytes(profileType string, n int64) { + if len(m.names) == 0 { + usageGroupReceivedDecompressedBytes.WithLabelValues(profileType, m.tenantID, noMatchName).Add(float64(n)) + return + } + + for _, name := range m.names { + usageGroupReceivedDecompressedBytes.WithLabelValues(profileType, m.tenantID, name.ResolvedName).Add(float64(n)) + } +} + +func (m UsageGroupMatch) CountDiscardedBytes(reason string, n int64) { + if len(m.names) == 0 { + usageGroupDiscardedBytes.WithLabelValues(reason, m.tenantID, noMatchName).Add(float64(n)) + return + } + + for _, name := range m.names { + usageGroupDiscardedBytes.WithLabelValues(reason, m.tenantID, name.ResolvedName).Add(float64(n)) + } +} + +func (m UsageGroupMatch) Names() []UsageGroupMatchName { + return m.names +} + +func NewUsageGroupConfig(m map[string]string) (*UsageGroupConfig, error) { + entries, rawData, err := parseUsageGroupEntries(m) + if err != nil { + return nil, err + } + config := &UsageGroupConfig{ + parsedEntries: entries, + config: rawData, + } + return config, nil +} + +func parseUsageGroupEntries(m map[string]string) ([]usageGroupEntry, map[string][]*labels.Matcher, error) { + if len(m) > maxUsageGroups { + return nil, nil, fmt.Errorf("maximum number of usage groups is %d, got %d", maxUsageGroups, len(m)) + } + + rawData := make(map[string][]*labels.Matcher) + entries := make([]usageGroupEntry, 0, len(m)) + + for name, matchersText := range m { + if !utf8.ValidString(name) { + return nil, nil, fmt.Errorf("usage group name %q is not valid UTF-8", name) + } + + name = strings.TrimSpace(name) + if name == "" { + return nil, nil, fmt.Errorf("usage group name cannot be empty") + } + + if name == noMatchName { + return nil, nil, fmt.Errorf("usage group name %q is reserved", noMatchName) + } + + matchers, err := phlaremodel.ParseMetricSelector(matchersText) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse matchers for usage group %q: %w", name, err) + } + + entry := usageGroupEntry{ + matchers: matchers, + name: name, + } + + if strings.Contains(name, dynamicLabelNamePrefix) { + template, err := parseTemplate(name) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse template for usage group %q: %w", name, err) + } + entry.template = template + } + + entries = append(entries, entry) + rawData[name] = matchers + } + + return entries, rawData, nil +} + +// parseTemplate parses a usage group name template into parts +func parseTemplate(name string) ([]templatePart, error) { + var parts []templatePart + remaining := name + + for len(remaining) > 0 { + before, after, found := strings.Cut(remaining, dynamicLabelNamePrefix) + + // add literal part before placeholder (if any) + if len(before) > 0 { + parts = append(parts, templatePart{ + isLiteral: true, + value: before, + }) + } + + if !found { + break + } + + labelName, afterBrace, foundBrace := strings.Cut(after, "}") + if !foundBrace { + return nil, fmt.Errorf("unclosed placeholder") + } + + if labelName == "" { + return nil, fmt.Errorf("empty label name in placeholder") + } + + parts = append(parts, templatePart{ + isLiteral: false, + value: labelName, + }) + + remaining = afterBrace + } + + return parts, nil +} + +func (o *Overrides) DistributorUsageGroups(tenantID string) *UsageGroupConfig { + config := o.getOverridesForTenant(tenantID).DistributorUsageGroups + + // It should never be nil, but check just in case! + if config == nil { + config = &UsageGroupConfig{} + } + return config +} + +func (c *UsageGroupConfig) matchesAll(matchers []*labels.Matcher, lbls phlaremodel.Labels) bool { + if len(lbls) == 0 && len(matchers) > 0 { + return false + } + + for _, m := range matchers { + if lbl, ok := lbls.GetLabel(m.Name); ok { + if !m.Matches(lbl.Value) { + return false + } + continue + } + return false + } + return true +} + +func (c *UsageGroupConfig) expandTemplate(template []templatePart, lbls phlaremodel.Labels) (string, error) { + var result strings.Builder + result.Grow(len(template) * 8) + + for _, part := range template { + if part.isLiteral { + result.WriteString(part.value) + } else { + value, found := lbls.GetLabel(part.value) + if !found { + return "", fmt.Errorf("label %q not found", part.value) + } + if value.Value == "" { + return "", fmt.Errorf("label %q is empty", part.value) + } + result.WriteString(value.Value) + } + } + + return result.String(), nil +} diff --git a/pkg/validation/usage_groups_bench_test.go b/pkg/validation/usage_groups_bench_test.go new file mode 100644 index 0000000000..f7e25c0cbf --- /dev/null +++ b/pkg/validation/usage_groups_bench_test.go @@ -0,0 +1,74 @@ +package validation + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +func BenchmarkUsageGroups_Regular(b *testing.B) { + config, err := NewUsageGroupConfig(map[string]string{ + "app/frontend": `{service_name=~"(.*)"}`, + "app/backend": `{team=~"(.*)"}`, + "app/database": `{environment=~"(.*)"}`, + "team/platform": `{service_name=~"(.*)", team=~"(.*)"}`, + "team/product": `{service_name=~"(.*)", team=~"(.*)", environment=~"(.*)"}`, + }) + require.NoError(b, err) + + l := model.Labels{ + {Name: "service_name", Value: "frontend"}, + {Name: "team", Value: "platform"}, + {Name: "environment", Value: "production"}, + } + evaluator := NewUsageGroupEvaluator(util.Logger) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = evaluator.GetMatch("tenant1", config, l) + } +} + +func BenchmarkUsageGroups_Dynamic(b *testing.B) { + config, err := NewUsageGroupConfig(map[string]string{ + "app/${labels.service_name}": `{service_name=~".*"}`, + "team/${labels.team}": `{team=~".*"}`, + "env/${labels.environment}": `{environment=~".*"}`, + "${labels.service_name}/${labels.team}": `{service_name=~".*", team=~".*"}`, + "complex/${labels.service_name}-${labels.team}-${labels.environment}": `{service_name=~".*", team=~".*", environment=~".*"}`, + }) + require.NoError(b, err) + + l := model.Labels{ + {Name: "service_name", Value: "frontend"}, + {Name: "team", Value: "platform"}, + {Name: "environment", Value: "production"}, + } + evaluator := NewUsageGroupEvaluator(util.Logger) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = evaluator.GetMatch("tenant1", config, l) + } +} + +func BenchmarkUsageGroups_ComplexRegex(b *testing.B) { + config, err := NewUsageGroupConfig(map[string]string{ + "complex/${labels.service_name}": `{service_name=~"[a-zA-Z]+-[0-9]+"}`, + "very-complex/${labels.service_name}": `{service_name=~"[a-zA-Z]+-[0-9]+\\.[a-z]{2,4}"}`, + }) + require.NoError(b, err) + + l := model.Labels{ + {Name: "service_name", Value: "frontend-123.prod"}, + } + evaluator := NewUsageGroupEvaluator(util.Logger) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = evaluator.GetMatch("tenant1", config, l) + } +} diff --git a/pkg/validation/usage_groups_test.go b/pkg/validation/usage_groups_test.go new file mode 100644 index 0000000000..a7aac9776d --- /dev/null +++ b/pkg/validation/usage_groups_test.go @@ -0,0 +1,624 @@ +package validation + +import ( + "encoding/json" + "fmt" + "slices" + "testing" + + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/require" + "go.yaml.in/yaml/v3" + + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/util" +) + +func TestUsageGroupConfig_GetUsageGroups(t *testing.T) { + tests := []struct { + Name string + TenantID string + Config map[string]string + Labels phlaremodel.Labels + WantedNames []string + }{ + { + Name: "single_usage_group_match", + TenantID: "tenant1", + Config: map[string]string{ + "app/foo": `{service_name="foo"}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: "foo"}, + }, + WantedNames: []string{"app/foo"}, + }, + { + Name: "multiple_usage_group_matches", + TenantID: "tenant1", + Config: map[string]string{ + "app/foo": `{service_name="foo"}`, + "app/foo2": `{service_name="foo", namespace=~"bar.*"}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: "foo"}, + {Name: "namespace", Value: "barbaz"}, + }, + WantedNames: []string{ + "app/foo", + "app/foo2", + }, + }, + { + Name: "no_usage_group_matches", + TenantID: "tenant1", + Config: map[string]string{ + "app/foo": `{service_name="notfound"}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: "foo"}, + }, + WantedNames: []string{}, + }, + { + Name: "wildcard_matcher", + TenantID: "tenant1", + Config: map[string]string{ + "app/foo": `{}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: "foo"}, + }, + WantedNames: []string{"app/foo"}, + }, + { + Name: "no_labels", + TenantID: "tenant1", + Config: map[string]string{ + "app/foo": `{service_name="foo"}`, + }, + Labels: phlaremodel.Labels{}, + WantedNames: []string{}, + }, + { + Name: "disjoint_labels_do_not_match", + TenantID: "tenant1", + Config: map[string]string{ + "app/foo": `{namespace="foo", container="bar"}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: "foo"}, + }, + WantedNames: []string{}, + }, + { + Name: "dynamic_usage_group_names", + TenantID: "tenant1", + Config: map[string]string{ + "app/${labels.service_name}": `{service_name=~"(.*)"}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: "foo"}, + }, + WantedNames: []string{ + "app/foo", + }, + }, + { + Name: "dynamic_usage_group_names_missing_label", + TenantID: "tenant1", + Config: map[string]string{ + "app/${labels.service_name}/${labels.env}": `{service_name=~"(.*)"}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: "foo"}, + }, + WantedNames: []string{}, + }, + { + Name: "dynamic_usage_group_names_empty_label", + TenantID: "tenant1", + Config: map[string]string{ + "app/${labels.service_name}": `{service_name=~"(.*)"}`, + }, + Labels: phlaremodel.Labels{ + {Name: "service_name", Value: ""}, + }, + WantedNames: []string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + config, err := NewUsageGroupConfig(tt.Config) + require.NoError(t, err) + + evaluator := NewUsageGroupEvaluator(util.Logger) + got := evaluator.GetMatch(tt.TenantID, config, tt.Labels) + + gotNames := make([]string, len(got.names)) + for i, name := range got.names { + gotNames[i] = name.ResolvedName + } + slices.Sort(gotNames) + slices.Sort(tt.WantedNames) + require.Equal(t, tt.WantedNames, gotNames) + }) + } +} + +func TestUsageGroupMatch_CountReceivedBytes(t *testing.T) { + tests := []struct { + Name string + Match UsageGroupMatch + Count int64 + WantCounts map[string]float64 + }{ + { + Name: "single_usage_group_match", + Match: UsageGroupMatch{ + tenantID: "tenant1", + names: []UsageGroupMatchName{{ResolvedName: "app/foo"}}, + }, + Count: 100, + WantCounts: map[string]float64{ + "app/foo": 100, + "app/foo2": 0, + "other": 0, + }, + }, + { + Name: "multiple_usage_group_matches", + Match: UsageGroupMatch{ + tenantID: "tenant1", + names: []UsageGroupMatchName{ + {ResolvedName: "app/foo"}, + {ResolvedName: "app/foo2"}, + }, + }, + Count: 100, + WantCounts: map[string]float64{ + "app/foo": 100, + "app/foo2": 100, + "other": 0, + }, + }, + { + Name: "no_usage_group_matches", + Match: UsageGroupMatch{ + tenantID: "tenant1", + names: []UsageGroupMatchName{}, + }, + Count: 100, + WantCounts: map[string]float64{ + "app/foo": 0, + "app/foo2": 0, + "other": 100, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + const profileType = "cpu" + usageGroupReceivedDecompressedBytes.Reset() + + tt.Match.CountReceivedBytes(profileType, tt.Count) + + for name, want := range tt.WantCounts { + collector := usageGroupReceivedDecompressedBytes.WithLabelValues( + profileType, + tt.Match.tenantID, + name, + ) + + got := testutil.ToFloat64(collector) + require.Equal(t, got, want, "usage group %s has incorrect metric value", name) + } + }) + } +} + +func TestUsageGroupMatch_CountDiscardedBytes(t *testing.T) { + tests := []struct { + Name string + Match UsageGroupMatch + Count int64 + WantCounts map[string]float64 + }{ + { + Name: "single_usage_group_match", + Match: UsageGroupMatch{ + tenantID: "tenant1", + names: []UsageGroupMatchName{{ResolvedName: "app/foo"}}, + }, + Count: 100, + WantCounts: map[string]float64{ + "app/foo": 100, + "app/foo2": 0, + "other": 0, + }, + }, + { + Name: "multiple_usage_group_matches", + Match: UsageGroupMatch{ + tenantID: "tenant1", + names: []UsageGroupMatchName{ + {ResolvedName: "app/foo"}, + {ResolvedName: "app/foo2"}, + }, + }, + Count: 100, + WantCounts: map[string]float64{ + "app/foo": 100, + "app/foo2": 100, + "other": 0, + }, + }, + { + Name: "no_usage_group_matches", + Match: UsageGroupMatch{ + tenantID: "tenant1", + names: []UsageGroupMatchName{}, + }, + Count: 100, + WantCounts: map[string]float64{ + "app/foo": 0, + "app/foo2": 0, + "other": 100, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + const reason = "no_reason" + usageGroupDiscardedBytes.Reset() + + tt.Match.CountDiscardedBytes(reason, tt.Count) + + for name, want := range tt.WantCounts { + collector := usageGroupDiscardedBytes.WithLabelValues( + reason, + tt.Match.tenantID, + name, + ) + + got := testutil.ToFloat64(collector) + require.Equal(t, got, want, "usage group %q has incorrect metric value", name) + } + }) + } +} + +func (c *UsageGroupConfig) valuesMap() map[string][]string { + m := make(map[string][]string) + for k, v := range c.config { + for _, matcher := range v { + m[k] = append(m[k], matcher.String()) + } + } + return m +} + +func TestNewUsageGroupConfig(t *testing.T) { + tests := []struct { + Name string + ConfigMap map[string]string + Want *UsageGroupConfig + WantErr string + }{ + { + Name: "single_usage_group", + ConfigMap: map[string]string{ + "app/foo": `{service_name="foo"}`, + }, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{service_name="foo"}`), + }, + }, + }, + { + Name: "multiple_usage_groups", + ConfigMap: map[string]string{ + "app/foo": `{service_name="foo"}`, + "app/foo2": `{service_name="foo", namespace=~"bar.*"}`, + }, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{service_name="foo"}`), + "app/foo2": testMustParseMatcher(t, `{service_name="foo", namespace=~"bar.*"}`), + }, + }, + }, + { + Name: "no_usage_groups", + ConfigMap: map[string]string{}, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{}, + }, + }, + { + Name: "wildcard_matcher", + ConfigMap: map[string]string{ + "app/foo": `{}`, + }, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{}`), + }, + }, + }, + { + Name: "too_many_usage_groups", + ConfigMap: func() map[string]string { + m := make(map[string]string) + for i := 0; i < maxUsageGroups+1; i++ { + m[fmt.Sprintf("app/foo%d", i)] = `{service_name="foo"}` + } + return m + }(), + WantErr: fmt.Sprintf("maximum number of usage groups is %d, got %d", maxUsageGroups, maxUsageGroups+1), + }, + { + Name: "invalid_matcher", + ConfigMap: map[string]string{ + "app/foo": `????`, + }, + WantErr: `failed to parse matchers for usage group "app/foo": 1:1: parse error: unexpected character: '?'`, + }, + { + Name: "empty_matcher", + ConfigMap: map[string]string{ + "app/foo": ``, + }, + WantErr: `failed to parse matchers for usage group "app/foo": unknown position: parse error: unexpected end of input`, + }, + { + Name: "empty_name", + ConfigMap: map[string]string{ + "": `{service_name="foo"}`, + }, + WantErr: "usage group name cannot be empty", + }, + { + Name: "whitespace_name", + ConfigMap: map[string]string{ + " app/foo ": `{service_name="foo"}`, + }, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{service_name="foo"}`), + }, + }, + }, + { + Name: "reserved_name", + ConfigMap: map[string]string{ + noMatchName: `{service_name="foo"}`, + }, + WantErr: fmt.Sprintf("usage group name %q is reserved", noMatchName), + }, + { + Name: "invalid_utf8_name", + ConfigMap: map[string]string{ + "app/\x80foo": `{service_name="foo"}`, + }, + WantErr: `usage group name "app/\x80foo" is not valid UTF-8`, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + got, err := NewUsageGroupConfig(tt.ConfigMap) + if tt.WantErr != "" { + require.EqualError(t, err, tt.WantErr) + } else { + require.NoError(t, err) + require.Equal(t, tt.Want.valuesMap(), got.valuesMap()) + } + }) + } +} + +func TestUsageGroupConfig_UnmarshalYAML(t *testing.T) { + type Object struct { + UsageGroups UsageGroupConfig `yaml:"usage_groups"` + } + + tests := []struct { + Name string + YAML string + Want *UsageGroupConfig + WantErr string + }{ + { + Name: "single_usage_group", + YAML: ` +usage_groups: + app/foo: '{service_name="foo"}'`, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{service_name="foo"}`), + }, + }, + }, + { + Name: "multiple_usage_groups", + YAML: ` +usage_groups: + app/foo: '{service_name="foo"}' + app/foo2: '{service_name="foo", namespace=~"bar.*"}'`, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{service_name="foo"}`), + "app/foo2": testMustParseMatcher(t, `{service_name="foo", namespace=~"bar.*"}`), + }, + }, + }, + { + Name: "empty_usage_groups", + YAML: ` +usage_groups: {}`, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{}, + }, + }, + { + Name: "invalid_yaml", + YAML: `usage_groups: ?????`, + WantErr: "malformed usage group config: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `?????` into map[string]string", + }, + { + Name: "invalid_matcher", + YAML: ` +usage_groups: + app/foo: ?????`, + WantErr: `failed to parse matchers for usage group "app/foo": 1:1: parse error: unexpected character: '?'`, + }, + { + Name: "missing_usage_groups_key_in_config", + YAML: ` +some_other_config: + foo: bar`, + Want: &UsageGroupConfig{}, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + got := Object{} + err := yaml.Unmarshal([]byte(tt.YAML), &got) + if tt.WantErr != "" { + require.EqualError(t, err, tt.WantErr) + } else { + require.NoError(t, err) + require.Equal(t, tt.Want.valuesMap(), got.UsageGroups.valuesMap()) + } + }) + } +} + +func TestUsageGroupConfig_UnmarshalJSON(t *testing.T) { + type Object struct { + UsageGroups UsageGroupConfig `json:"usage_groups"` + } + + tests := []struct { + Name string + JSON string + Want *UsageGroupConfig + WantErr string + }{ + { + Name: "single_usage_group", + JSON: `{ + "usage_groups": { + "app/foo": "{service_name=\"foo\"}" + } + }`, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{service_name="foo"}`), + }, + }, + }, + { + Name: "multiple_usage_groups", + JSON: `{ + "usage_groups": { + "app/foo": "{service_name=\"foo\"}", + "app/foo2": "{service_name=\"foo\", namespace=~\"bar.*\"}" + } + }`, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{ + "app/foo": testMustParseMatcher(t, `{service_name="foo"}`), + "app/foo2": testMustParseMatcher(t, `{service_name="foo", namespace=~"bar.*"}`), + }, + }, + }, + { + Name: "empty_usage_groups", + JSON: `{"usage_groups": {}}`, + Want: &UsageGroupConfig{ + config: map[string][]*labels.Matcher{}, + }, + }, + { + Name: "invalid_json", + JSON: `{"usage_groups": "?????"}`, + WantErr: "malformed usage group config: json: cannot unmarshal string into Go value of type map[string]string", + }, + { + Name: "invalid_matcher", + JSON: `{"usage_groups": {"app/foo": "?????"}}`, + WantErr: `failed to parse matchers for usage group "app/foo": 1:1: parse error: unexpected character: '?'`, + }, + { + Name: "missing_usage_groups_key_in_config", + JSON: `{"some_other_key": {"foo": "bar"}}`, + Want: &UsageGroupConfig{}, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + got := Object{} + err := json.Unmarshal([]byte(tt.JSON), &got) + if tt.WantErr != "" { + require.EqualError(t, err, tt.WantErr) + } else { + require.NoError(t, err) + require.Equal(t, tt.Want.valuesMap(), got.UsageGroups.valuesMap()) + } + }) + } +} + +func testMustParseMatcher(t *testing.T, s string) []*labels.Matcher { + m, err := phlaremodel.ParseMetricSelector(s) + require.NoError(t, err) + return m +} + +func TestUsageGroupMatchName_IsMoreSpecificThan(t *testing.T) { + tests := []struct { + Name string + Match UsageGroupMatchName + Other UsageGroupMatchName + Want bool + }{ + { + Name: "same name", + Match: UsageGroupMatchName{ConfiguredName: "app/foo"}, + Other: UsageGroupMatchName{ConfiguredName: "app/foo"}, + Want: false, + }, + { + Name: "less specific name", + Match: UsageGroupMatchName{ConfiguredName: "${labels.service_name}"}, + Other: UsageGroupMatchName{ConfiguredName: "test-service"}, + Want: false, + }, + { + Name: "more specific name", + Match: UsageGroupMatchName{ConfiguredName: "test-service"}, + Other: UsageGroupMatchName{ConfiguredName: "${labels.service_name}"}, + Want: true, + }, + { + Name: "more specific name with prefix", + Match: UsageGroupMatchName{ConfiguredName: "test-service"}, + Other: UsageGroupMatchName{ConfiguredName: "service/${labels.service_name}"}, + Want: true, + }, + } + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + require.Equal(t, tt.Want, tt.Match.IsMoreSpecificThan(&tt.Other)) + }) + } +} diff --git a/pkg/validation/user_limits_handler.go b/pkg/validation/user_limits_handler.go index 32a1d9ec7a..aa3e6bc6c3 100644 --- a/pkg/validation/user_limits_handler.go +++ b/pkg/validation/user_limits_handler.go @@ -7,8 +7,7 @@ import ( "github.com/grafana/dskit/tenant" - "github.com/grafana/pyroscope/pkg/util" - httputil "github.com/grafana/pyroscope/pkg/util/http" + httputil "github.com/grafana/pyroscope/v2/pkg/util/http" ) type TenantLimitsResponse struct { @@ -41,6 +40,6 @@ func TenantLimitsHandler(defaultLimits Limits, tenantLimits TenantLimits) http.H MaxGlobalSeriesPerTenant: userLimits.MaxGlobalSeriesPerTenant, } - util.WriteJSONResponse(w, limits) + httputil.WriteJSONResponse(w, limits) } } diff --git a/pkg/validation/validate.go b/pkg/validation/validate.go index 7c87682cb6..0c91489437 100644 --- a/pkg/validation/validate.go +++ b/pkg/validation/validate.go @@ -2,23 +2,25 @@ package validation import ( "encoding/hex" + "errors" "fmt" + "slices" "sort" "strings" "time" "unicode/utf8" + "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/common/model" - googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" - "github.com/grafana/pyroscope/pkg/util" - "github.com/grafana/pyroscope/pkg/util/validation" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" + "github.com/grafana/pyroscope/v2/pkg/util" + "github.com/grafana/pyroscope/v2/pkg/util/validation" ) type Reason string @@ -47,28 +49,41 @@ const ( DuplicateLabelNames Reason = "duplicate_label_names" // SeriesLimit is a reason for discarding lines when we can't create a new stream // because the limit of active streams has been reached. - SeriesLimit Reason = "series_limit" - QueryLimit Reason = "query_limit" - SamplesLimit Reason = "samples_limit" - ProfileSizeLimit Reason = "profile_size_limit" - SampleLabelsLimit Reason = "sample_labels_limit" - MalformedProfile Reason = "malformed_profile" - FlameGraphLimit Reason = "flamegraph_limit" - - SeriesLimitErrorMsg = "Maximum active series limit exceeded (%d/%d), reduce the number of active streams (reduce labels or reduce label values), or contact your administrator to see if the limit can be increased" - MissingLabelsErrorMsg = "error at least one label pair is required per profile" - InvalidLabelsErrorMsg = "invalid labels '%s' with error: %s" - MaxLabelNamesPerSeriesErrorMsg = "profile series '%s' has %d label names; limit %d" - LabelNameTooLongErrorMsg = "profile with labels '%s' has label name too long: '%s'" - LabelValueTooLongErrorMsg = "profile with labels '%s' has label value too long: '%s'" - DuplicateLabelNamesErrorMsg = "profile with labels '%s' has duplicate label name: '%s'" - QueryTooLongErrorMsg = "the query time range exceeds the limit (max_query_length, actual: %s, limit: %s)" - ProfileTooBigErrorMsg = "the profile with labels '%s' exceeds the size limit (max_profile_size_byte, actual: %d, limit: %d)" - ProfileTooManySamplesErrorMsg = "the profile with labels '%s' exceeds the samples count limit (max_profile_stacktrace_samples, actual: %d, limit: %d)" - ProfileTooManySampleLabelsErrorMsg = "the profile with labels '%s' exceeds the sample labels limit (max_profile_stacktrace_sample_labels, actual: %d, limit: %d)" - NotInIngestionWindowErrorMsg = "profile with labels '%s' is outside of ingestion window (profile timestamp: %s, %s)" - MaxFlameGraphNodesErrorMsg = "max flamegraph nodes limit %d is greater than allowed %d" - MaxFlameGraphNodesUnlimitedErrorMsg = "max flamegraph nodes limit must be set (max allowed %d)" + SeriesLimit Reason = "series_limit" + QueryLimit Reason = "query_limit" + SamplesLimit Reason = "samples_limit" + ProfileSizeLimit Reason = "profile_size_limit" + SampleLabelsLimit Reason = "sample_labels_limit" + MalformedProfile Reason = "malformed_profile" + FlameGraphLimit Reason = "flamegraph_limit" + QueryMissingTimeRange Reason = "missing_time_range" + QueryInvalidTimeRange Reason = "invalid_time_range" + + IngestLimitReached Reason = "ingest_limit_reached" + SkippedBySamplingRules Reason = "dropped_by_sampling_rules" + + BodySizeLimit Reason = "body_size_limit_exceeded" + + // Those profiles were dropped because of relabeling rules + DroppedByRelabelRules Reason = "dropped_by_relabel_rules" + + SeriesLimitErrorMsg = "Maximum active series limit exceeded (%d/%d), reduce the number of active streams (reduce labels or reduce label values), or contact your administrator to see if the limit can be increased" + MissingLabelsErrorMsg = "error at least one label pair is required per profile" + InvalidLabelsErrorMsg = "invalid labels '%s' with error: %s" + MaxLabelNamesPerSeriesErrorMsg = "profile series '%s' has %d label names; limit %d" + LabelNameTooLongErrorMsg = "profile with labels '%s' has label name too long: '%s'" + LabelValueTooLongErrorMsg = "profile with labels '%s' has label value too long: '%s'" + DuplicateLabelNamesErrorMsg = "profile with labels '%s' has duplicate label name: '%s'" + DuplicateLabelNamesAfterSanitizationErrorMsg = "profile with labels '%s' has duplicate label name '%s' after label name sanitization from '%s'" + QueryTooLongErrorMsg = "the query time range exceeds the limit (max_query_length, actual: %s, limit: %s)" + ProfileTooBigErrorMsg = "the profile with labels '%s' exceeds the size limit (max_profile_size_byte, actual: %d, limit: %d)" + ProfileTooManySamplesErrorMsg = "the profile with labels '%s' exceeds the samples count limit (max_profile_stacktrace_samples, actual: %d, limit: %d)" + ProfileTooManySampleLabelsErrorMsg = "the profile with labels '%s' exceeds the sample labels limit (max_profile_stacktrace_sample_labels, actual: %d, limit: %d)" + NotInIngestionWindowErrorMsg = "profile with labels '%s' is outside of ingestion window (profile timestamp: %s, %s)" + MaxFlameGraphNodesErrorMsg = "max flamegraph nodes limit %d is greater than allowed %d" + MaxFlameGraphNodesUnlimitedErrorMsg = "max flamegraph nodes limit must be set (max allowed %d)" + QueryMissingTimeRangeErrorMsg = "missing time range in the query" + QueryStartAfterEndErrorMsg = "query start time is after end time" ) var ( @@ -91,70 +106,151 @@ var ( }, []string{ReasonLabel, "tenant"}, ) + + // sanitizedLabelNames is a metric of the number of label names that were sanitized. + sanitizedLabelNames = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "pyroscope", + Name: "sanitized_label_names_total", + Help: "The total number of label names that were sanitized (e.g., dots replaced with underscores).", + }, + []string{"tenant"}, + ) ) type LabelValidationLimits interface { MaxLabelNameLength(tenantID string) int MaxLabelValueLength(tenantID string) int MaxLabelNamesPerSeries(tenantID string) int + DisableLabelSanitization(tenantID string) bool } // ValidateLabels validates the labels of a profile. -func ValidateLabels(limits LabelValidationLimits, tenantID string, ls []*typesv1.LabelPair) error { +// Returns the potentially modified labels slice (e.g., after sanitization) and any validation error. +func ValidateLabels(limits LabelValidationLimits, tenantID string, ls []*typesv1.LabelPair, logger log.Logger) ([]*typesv1.LabelPair, error) { if len(ls) == 0 { - return NewErrorf(MissingLabels, MissingLabelsErrorMsg) + return nil, NewErrorf(MissingLabels, MissingLabelsErrorMsg) } sort.Sort(phlaremodel.Labels(ls)) numLabelNames := len(ls) maxLabels := limits.MaxLabelNamesPerSeries(tenantID) if numLabelNames > maxLabels { - return NewErrorf(MaxLabelNamesPerSeries, MaxLabelNamesPerSeriesErrorMsg, phlaremodel.LabelPairsString(ls), numLabelNames, maxLabels) + return nil, NewErrorf(MaxLabelNamesPerSeries, MaxLabelNamesPerSeriesErrorMsg, phlaremodel.LabelPairsString(ls), numLabelNames, maxLabels) } metricNameValue := phlaremodel.Labels(ls).Get(model.MetricNameLabel) - if !model.IsValidMetricName(model.LabelValue(metricNameValue)) { - return NewErrorf(InvalidLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "invalid metric name") + if !model.UTF8Validation.IsValidMetricName(metricNameValue) { + return nil, NewErrorf(InvalidLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "invalid metric name") } serviceNameValue := phlaremodel.Labels(ls).Get(phlaremodel.LabelNameServiceName) if !isValidServiceName(serviceNameValue) { - return NewErrorf(MissingLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "service name is not provided") + return nil, NewErrorf(MissingLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "service name is not provided") } - lastLabelName := "" - for _, l := range ls { - if len(l.Name) > limits.MaxLabelNameLength(tenantID) { - return NewErrorf(LabelNameTooLong, LabelNameTooLongErrorMsg, phlaremodel.LabelPairsString(ls), l.Name) + var ( + lastLabelName = "" + idx = 0 + disableLabelSanitization = limits.DisableLabelSanitization(tenantID) + maxLabelNameLength = limits.MaxLabelNameLength(tenantID) + maxLabelValueLength = limits.MaxLabelValueLength(tenantID) + ) + for idx < len(ls) { + l := ls[idx] + if len(l.Name) > maxLabelNameLength { + return nil, NewErrorf(LabelNameTooLong, LabelNameTooLongErrorMsg, phlaremodel.LabelPairsString(ls), l.Name) } - if len(l.Value) > limits.MaxLabelValueLength(tenantID) { - return NewErrorf(LabelValueTooLong, LabelValueTooLongErrorMsg, phlaremodel.LabelPairsString(ls), l.Value) + if len(l.Value) > maxLabelValueLength { + return nil, NewErrorf(LabelValueTooLong, LabelValueTooLongErrorMsg, phlaremodel.LabelPairsString(ls), l.Value) } - var origName string - var ok bool - if origName, l.Name, ok = SanitizeLabelName(l.Name); !ok { - return NewErrorf(InvalidLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "invalid label name '"+origName+"'") + if disableLabelSanitization { + // When sanitization is disabled, use UTF-8 validation directly + if !model.UTF8Validation.IsValidLabelName(l.Name) { + return nil, NewErrorf(InvalidLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "invalid label name '"+l.Name+"'") + } + } else { + if origName, newName, ok := SanitizeLegacyLabelName(l.Name); ok && origName != newName { + var err error + ls, idx, err = handleSanitizedLabel(ls, idx, origName, newName) + if err != nil { + return nil, err + } + level.Debug(logger).Log( + "msg", "label name sanitized", + "origName", origName, + "serviceName", serviceNameValue) + + sanitizedLabelNames.WithLabelValues(tenantID).Inc() + lastLabelName = "" + if idx > 0 && idx <= len(ls) { + lastLabelName = ls[idx-1].Name + } + continue + } else if !ok { + return nil, NewErrorf(InvalidLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "invalid label name '"+origName+"'") + } } if !model.LabelValue(l.Value).IsValid() { - return NewErrorf(InvalidLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "invalid label value '"+l.Value+"'") + return nil, NewErrorf(InvalidLabels, InvalidLabelsErrorMsg, phlaremodel.LabelPairsString(ls), "invalid label value '"+l.Value+"'") } if cmp := strings.Compare(lastLabelName, l.Name); cmp == 0 { - return NewErrorf(DuplicateLabelNames, DuplicateLabelNamesErrorMsg, phlaremodel.LabelPairsString(ls), origName) + return nil, NewErrorf(DuplicateLabelNames, DuplicateLabelNamesErrorMsg, phlaremodel.LabelPairsString(ls), l.Name) } lastLabelName = l.Name + idx += 1 } - return nil + return ls, nil +} + +// handleSanitizedLabel handles the case where a label name is sanitized. It ensures that the label name is unique and fails if the value is distinct. +func handleSanitizedLabel(ls []*typesv1.LabelPair, origIdx int, origName, newName string) ([]*typesv1.LabelPair, int, error) { + newLabel := &typesv1.LabelPair{Name: newName, Value: ls[origIdx].Value} + + // Create new slice without the original element + newSlice := make([]*typesv1.LabelPair, 0, len(ls)) + newSlice = append(newSlice, ls[:origIdx]...) + newSlice = append(newSlice, ls[origIdx+1:]...) + + insertIdx, found := slices.BinarySearchFunc(newSlice, newLabel, + func(a, b *typesv1.LabelPair) int { + return strings.Compare(a.Name, b.Name) + }) + + if found { + if newSlice[insertIdx].Value == newLabel.Value { + // Same name and value we are done and can just return newSlice + return newSlice, origIdx, nil + } else { + // Same name, different value - error + return nil, 0, NewErrorf(DuplicateLabelNames, + DuplicateLabelNamesAfterSanitizationErrorMsg, + phlaremodel.LabelPairsString(ls), newName, origName) + } + } + + // Insert the new label at correct position + newSlice = slices.Insert(newSlice, insertIdx, newLabel) + + finalIdx := insertIdx + if insertIdx >= origIdx { + finalIdx = origIdx + } + + copy(ls, newSlice) + return ls[:len(newSlice)], finalIdx, nil } -// SanitizeLabelName reports whether the label name is valid, -// and returns the sanitized value. +// SanitizeLegacyLabelName reports whether the label name is a valid legacy label name, +// and returns the sanitized value. Legacy label names are non utf-8 and contain characters +// [a-zA-Z0-9_.]. // -// The only change the function makes is replacing dots with underscores. -func SanitizeLabelName(ln string) (old, sanitized string, ok bool) { +// The only sanitization the function makes is replacing dots with underscores. +func SanitizeLegacyLabelName(ln string) (old, sanitized string, ok bool) { if len(ln) == 0 { return ln, ln, false } hasDots := false for i, b := range ln { - if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { + if (b < 'a' || b > 'z') && (b < 'A' || b > 'Z') && b != '_' && (b < '0' || b > '9' || i == 0) { if b == '.' { hasDots = true } else { @@ -218,25 +314,32 @@ func (iw *ingestionWindow) valid(t model.Time, ls phlaremodel.Labels) error { return NewErrorf(NotInIngestionWindow, NotInIngestionWindowErrorMsg, phlaremodel.LabelPairsString(ls), util.FormatTimeMillis(int64(t)), iw.errorDetail()) } -func ValidateProfile(limits ProfileValidationLimits, tenantID string, prof *googlev1.Profile, uncompressedSize int, ls phlaremodel.Labels, now model.Time) error { - if prof == nil { - return nil +type ValidatedProfile struct { + *pprof.Profile +} + +func ValidateProfile(limits ProfileValidationLimits, tenantID string, prof *pprof.Profile, uncompressedSize int, ls phlaremodel.Labels, now model.Time) (ValidatedProfile, error) { + if prof == nil || prof.Profile == nil { + return ValidatedProfile{}, NewErrorf(MalformedProfile, "nil profile") + } + if len(prof.SampleType) == 0 { + return ValidatedProfile{}, NewErrorf(MalformedProfile, "empty profile") } if prof.TimeNanos > 0 { // check profile timestamp within ingestion window if err := newIngestionWindow(limits, tenantID, now).valid(model.TimeFromUnixNano(prof.TimeNanos), ls); err != nil { - return err + return ValidatedProfile{}, err } } else { prof.TimeNanos = now.UnixNano() } if limit := limits.MaxProfileSizeBytes(tenantID); limit != 0 && uncompressedSize > limit { - return NewErrorf(ProfileSizeLimit, ProfileTooBigErrorMsg, phlaremodel.LabelPairsString(ls), uncompressedSize, limit) + return ValidatedProfile{}, NewErrorf(ProfileSizeLimit, ProfileTooBigErrorMsg, phlaremodel.LabelPairsString(ls), uncompressedSize, limit) } if limit, size := limits.MaxProfileStacktraceSamples(tenantID), len(prof.Sample); limit != 0 && size > limit { - return NewErrorf(SamplesLimit, ProfileTooManySamplesErrorMsg, phlaremodel.LabelPairsString(ls), size, limit) + return ValidatedProfile{}, NewErrorf(SamplesLimit, ProfileTooManySamplesErrorMsg, phlaremodel.LabelPairsString(ls), size, limit) } var ( depthLimit = limits.MaxProfileStacktraceDepth(tenantID) @@ -249,7 +352,7 @@ func ValidateProfile(limits ProfileValidationLimits, tenantID string, prof *goog s.LocationId = s.LocationId[len(s.LocationId)-depthLimit:] } if labelsLimit != 0 && len(s.Label) > labelsLimit { - return NewErrorf(SampleLabelsLimit, ProfileTooManySampleLabelsErrorMsg, phlaremodel.LabelPairsString(ls), len(s.Label), labelsLimit) + return ValidatedProfile{}, NewErrorf(SampleLabelsLimit, ProfileTooManySampleLabelsErrorMsg, phlaremodel.LabelPairsString(ls), len(s.Label), labelsLimit) } } if symbolLengthLimit > 0 { @@ -261,24 +364,75 @@ func ValidateProfile(limits ProfileValidationLimits, tenantID string, prof *goog } for _, location := range prof.Location { if location.Id == 0 { - return NewErrorf(MalformedProfile, "location id is 0") + return ValidatedProfile{}, NewErrorf(MalformedProfile, "location id is 0") } } for _, function := range prof.Function { if function.Id == 0 { - return NewErrorf(MalformedProfile, "function id is 0") + return ValidatedProfile{}, NewErrorf(MalformedProfile, "function id is 0") + } + } + for _, s := range prof.Sample { + if s == nil { + return ValidatedProfile{}, NewErrorf(MalformedProfile, "nil sample") } + if len(s.Value) != len(prof.SampleType) { + return ValidatedProfile{}, NewErrorf(MalformedProfile, "sample value length mismatch") + } + } + + if err := validateStringTableAccess(prof); err != nil { + return ValidatedProfile{}, err } for _, valueType := range prof.SampleType { stt := prof.StringTable[valueType.Type] if strings.Contains(stt, "-") { - return NewErrorf(MalformedProfile, "sample type contains -") + return ValidatedProfile{}, NewErrorf(MalformedProfile, "sample type contains -") } // todo check if sample type is valid from the promql parser perspective } + for _, s := range prof.StringTable { if !utf8.ValidString(s) { - return NewErrorf(MalformedProfile, "invalid utf8 string hex: %s", hex.EncodeToString([]byte(s))) + return ValidatedProfile{}, NewErrorf(MalformedProfile, "invalid utf8 string hex: %s", hex.EncodeToString([]byte(s))) + } + } + return ValidatedProfile{Profile: prof}, nil +} + +func validateStringTableAccess(prof *pprof.Profile) error { + if len(prof.StringTable) == 0 || prof.StringTable[0] != "" { + return NewErrorf(MalformedProfile, "string 0 should be empty string") + } + for _, valueType := range prof.SampleType { + if int(valueType.Type) >= len(prof.StringTable) { + return NewErrorf(MalformedProfile, "sample type type string index out of range") + } + } + for _, sample := range prof.Sample { + for _, lbl := range sample.Label { + if int(lbl.Str) >= len(prof.StringTable) || int(lbl.Key) >= len(prof.StringTable) { + return NewErrorf(MalformedProfile, "sample label string index out of range") + } + } + } + for _, function := range prof.Function { + if int(function.Name) >= len(prof.StringTable) { + return NewErrorf(MalformedProfile, "function name string index out of range") + } + if int(function.SystemName) >= len(prof.StringTable) { + return NewErrorf(MalformedProfile, "function system name index string out of range") + } + if int(function.Filename) >= len(prof.StringTable) { + return NewErrorf(MalformedProfile, "function file name string index out of range") + } + } + for _, mapping := range prof.Mapping { + if int(mapping.Filename) >= len(prof.StringTable) { + return NewErrorf(MalformedProfile, "mapping file name string index out of range") + } + if int(mapping.BuildId) >= len(prof.StringTable) { + return NewErrorf(MalformedProfile, "mapping build id string index out of range") } } return nil @@ -324,6 +478,14 @@ type ValidatedRangeRequest struct { } func ValidateRangeRequest(limits RangeRequestLimits, tenantIDs []string, req model.Interval, now model.Time) (ValidatedRangeRequest, error) { + if req.Start == 0 || req.End == 0 { + return ValidatedRangeRequest{}, NewErrorf(QueryMissingTimeRange, QueryMissingTimeRangeErrorMsg) + } + + if req.Start > req.End { + return ValidatedRangeRequest{}, NewErrorf(QueryInvalidTimeRange, QueryStartAfterEndErrorMsg) + } + if maxQueryLookback := validation.SmallestPositiveNonZeroDurationPerTenant(tenantIDs, limits.MaxQueryLookback); maxQueryLookback > 0 { minStartTime := now.Add(-maxQueryLookback) @@ -361,9 +523,30 @@ func ValidateRangeRequest(limits RangeRequestLimits, tenantIDs []string, req mod return ValidatedRangeRequest{Interval: req}, nil } +func SanitizeTimeRange(limits RangeRequestLimits, tenant []string, start, end *int64) (empty bool, err error) { + var interval model.Interval + if start != nil { + interval.Start = model.Time(*start) + } + if end != nil { + interval.End = model.Time(*end) + } + validated, err := ValidateRangeRequest(limits, tenant, interval, model.Now()) + if err != nil { + return false, err + } + if validated.IsEmpty { + return true, nil + } + *start = int64(validated.Start) + *end = int64(validated.End) + return false, nil +} + type FlameGraphLimits interface { MaxFlameGraphNodesDefault(string) int MaxFlameGraphNodesMax(string) int + MaxFlameGraphNodesOnSelectMergeProfile(string) bool } func ValidateMaxNodes(l FlameGraphLimits, tenantIDs []string, n int64) (int64, error) { diff --git a/pkg/validation/validate_bench_test.go b/pkg/validation/validate_bench_test.go new file mode 100644 index 0000000000..48e1f5ffaf --- /dev/null +++ b/pkg/validation/validate_bench_test.go @@ -0,0 +1,34 @@ +package validation + +import ( + "fmt" + "testing" + + "github.com/go-kit/log" + + typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" +) + +func BenchmarkValidateLabels(b *testing.B) { + overrides := MockDefaultOverrides() + logger := log.NewNopLogger() + labels := []*typesv1.LabelPair{ + {Name: "__name__", Value: "process_cpu"}, + {Name: "service_name", Value: "my-service"}, + } + for i := 0; i < 18; i++ { + labels = append(labels, &typesv1.LabelPair{ + Name: fmt.Sprintf("label_%d", i), + Value: fmt.Sprintf("value_%d", i), + }) + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := ValidateLabels(overrides, "tenant-1", labels, logger) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/pkg/validation/validate_test.go b/pkg/validation/validate_test.go index 9d9de6bf01..7d8d6da96a 100644 --- a/pkg/validation/validate_test.go +++ b/pkg/validation/validate_test.go @@ -4,13 +4,14 @@ import ( "testing" "time" + "github.com/go-kit/log" "github.com/prometheus/common/model" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" googlev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1" typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" - phlaremodel "github.com/grafana/pyroscope/pkg/model" + phlaremodel "github.com/grafana/pyroscope/v2/pkg/model" + "github.com/grafana/pyroscope/v2/pkg/pprof" ) func TestValidateLabels(t *testing.T) { @@ -57,9 +58,9 @@ func TestValidateLabels(t *testing.T) { { name: "invalid metric name", lbs: []*typesv1.LabelPair{ - {Name: model.MetricNameLabel, Value: "&&"}, + {Name: model.MetricNameLabel, Value: "\x80"}, }, - expectedErr: `invalid labels '{__name__="&&"}' with error: invalid metric name`, + expectedErr: `invalid labels '{__name__="\x80"}' with error: invalid metric name`, expectedReason: InvalidLabels, }, { @@ -123,15 +124,24 @@ func TestValidateLabels(t *testing.T) { {Name: phlaremodel.LabelNameServiceName, Value: "svc"}, }, expectedReason: DuplicateLabelNames, - expectedErr: "profile with labels '{__name__=\"qux\", label_name=\"foo\", label_name=\"bar\", service_name=\"svc\"}' has duplicate label name: 'label.name'", + expectedErr: "profile with labels '{__name__=\"qux\", label.name=\"bar\", label_name=\"foo\", service_name=\"svc\"}' has duplicate label name 'label_name' after label name sanitization from 'label.name'", + }, + { + name: "duplicates once sanitized with matching values", + lbs: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "qux"}, + {Name: "service.name", Value: "svc0"}, + {Name: "service_abc", Value: "def"}, + {Name: "service_name", Value: "svc0"}, + }, }, } { t.Run(tt.name, func(t *testing.T) { - err := ValidateLabels(MockLimits{ + _, err := ValidateLabels(MockLimits{ MaxLabelNamesPerSeriesValue: 4, MaxLabelNameLengthValue: 12, MaxLabelValueLengthValue: 10, - }, "foo", tt.lbs) + }, "foo", tt.lbs, log.NewNopLogger()) if tt.expectedErr != "" { require.Error(t, err) require.Equal(t, tt.expectedErr, err.Error()) @@ -143,6 +153,385 @@ func TestValidateLabels(t *testing.T) { } } +func TestValidateLabels_SanitizedLabelsReturned(t *testing.T) { + for _, tt := range []struct { + name string + inputLabels []*typesv1.LabelPair + expectedLabels []*typesv1.LabelPair + }{ + { + name: "single dotted label is sanitized", + inputLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "service_name", Value: "my-svc"}, + {Name: "label.dot", Value: "val"}, + }, + expectedLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "label_dot", Value: "val"}, + {Name: "service_name", Value: "my-svc"}, + }, + }, + { + name: "dotted label merged with existing underscore label", + inputLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "service.name", Value: "my-svc"}, + {Name: "service_name", Value: "my-svc"}, + }, + expectedLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "service_name", Value: "my-svc"}, + }, + }, + { + name: "multiple dotted labels sanitized", + inputLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "foo.bar", Value: "val1"}, + {Name: "label.dot", Value: "val2"}, + {Name: "service_name", Value: "my-svc"}, + }, + expectedLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "foo_bar", Value: "val1"}, + {Name: "label_dot", Value: "val2"}, + {Name: "service_name", Value: "my-svc"}, + }, + }, + { + name: "labels without dots unchanged", + inputLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "service_name", Value: "my-svc"}, + }, + expectedLabels: []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "service_name", Value: "my-svc"}, + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + result, err := ValidateLabels(MockLimits{ + MaxLabelNamesPerSeriesValue: 10, + MaxLabelNameLengthValue: 50, + MaxLabelValueLengthValue: 50, + }, "test-tenant", tt.inputLabels, log.NewNopLogger()) + + require.NoError(t, err) + require.Equal(t, len(tt.expectedLabels), len(result), "unexpected number of labels") + + for i, expected := range tt.expectedLabels { + require.Equal(t, expected.Name, result[i].Name, "label name mismatch at index %d", i) + require.Equal(t, expected.Value, result[i].Value, "label value mismatch at index %d", i) + } + }) + } +} + +func TestValidateLabels_DisableSanitization(t *testing.T) { + t.Run("dotted labels accepted when sanitization disabled", func(t *testing.T) { + inputLabels := []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "my-svc"}, // service_name is required + {Name: "label.with.dots", Value: "val"}, + } + + result, err := ValidateLabels(MockLimits{ + MaxLabelNamesPerSeriesValue: 10, + MaxLabelNameLengthValue: 50, + MaxLabelValueLengthValue: 50, + DisableLabelSanitizationValue: true, + }, "test-tenant", inputLabels, log.NewNopLogger()) + + require.NoError(t, err) + // Labels should not be sanitized - dots remain + require.Equal(t, 3, len(result)) + require.Equal(t, model.MetricNameLabel, result[0].Name) + require.Equal(t, "label.with.dots", result[1].Name) // sorted after __name__ + require.Equal(t, phlaremodel.LabelNameServiceName, result[2].Name) + }) + + t.Run("invalid UTF-8 rejected when sanitization disabled", func(t *testing.T) { + inputLabels := []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: "service_name", Value: "my-svc"}, + {Name: "\xc5", Value: "val"}, + } + + _, err := ValidateLabels(MockLimits{ + MaxLabelNamesPerSeriesValue: 10, + MaxLabelNameLengthValue: 50, + MaxLabelValueLengthValue: 50, + DisableLabelSanitizationValue: true, + }, "test-tenant", inputLabels, log.NewNopLogger()) + + require.Error(t, err) + require.Equal(t, InvalidLabels, ReasonOf(err)) + }) + + t.Run("dotted labels sanitized when sanitization enabled (default)", func(t *testing.T) { + inputLabels := []*typesv1.LabelPair{ + {Name: model.MetricNameLabel, Value: "cpu"}, + {Name: phlaremodel.LabelNameServiceName, Value: "my-svc"}, // service_name is required + {Name: "custom.label", Value: "val"}, + } + + result, err := ValidateLabels(MockLimits{ + MaxLabelNamesPerSeriesValue: 10, + MaxLabelNameLengthValue: 50, + MaxLabelValueLengthValue: 50, + DisableLabelSanitizationValue: false, // explicitly false (default) + }, "test-tenant", inputLabels, log.NewNopLogger()) + + require.NoError(t, err) + // custom.label should be sanitized to custom_label + require.Equal(t, 3, len(result)) + require.Equal(t, model.MetricNameLabel, result[0].Name) + require.Equal(t, "custom_label", result[1].Name) + require.Equal(t, phlaremodel.LabelNameServiceName, result[2].Name) + }) +} + +func Test_SanitizeLegacyLabelName(t *testing.T) { + tests := []struct { + Name string + LabelName string + WantOld string + WantSanitized string + WantOk bool + }{ + { + Name: "empty string is invalid", + LabelName: "", + WantOld: "", + WantSanitized: "", + WantOk: false, + }, + { + Name: "valid simple label name", + LabelName: "service", + WantOld: "service", + WantSanitized: "service", + WantOk: true, + }, + { + Name: "valid label with underscores", + LabelName: "service_name", + WantOld: "service_name", + WantSanitized: "service_name", + WantOk: true, + }, + { + Name: "valid label with numbers", + LabelName: "service123", + WantOld: "service123", + WantSanitized: "service123", + WantOk: true, + }, + { + Name: "valid mixed case label", + LabelName: "ServiceName", + WantOld: "ServiceName", + WantSanitized: "ServiceName", + WantOk: true, + }, + { + Name: "label with dots gets sanitized", + LabelName: "service.name", + WantOld: "service.name", + WantSanitized: "service_name", + WantOk: true, + }, + { + Name: "label with multiple dots gets sanitized", + LabelName: "service.name.type", + WantOld: "service.name.type", + WantSanitized: "service_name_type", + WantOk: true, + }, + { + Name: "label starting with number is invalid", + LabelName: "123service", + WantOld: "123service", + WantSanitized: "123service", + WantOk: false, + }, + { + Name: "label with hyphen is invalid", + LabelName: "service-name", + WantOld: "service-name", + WantSanitized: "service-name", + WantOk: false, + }, + { + Name: "label with space is invalid", + LabelName: "service name", + WantOld: "service name", + WantSanitized: "service name", + WantOk: false, + }, + { + Name: "label with special characters is invalid", + LabelName: "service@name", + WantOld: "service@name", + WantSanitized: "service@name", + WantOk: false, + }, + { + Name: "label with dots and invalid characters is invalid", + LabelName: "service.name@host", + WantOld: "service.name@host", + WantSanitized: "service.name@host", + WantOk: false, + }, + { + Name: "label starting with underscore", + LabelName: "_service", + WantOld: "_service", + WantSanitized: "_service", + WantOk: true, + }, + { + Name: "label with only underscores", + LabelName: "___", + WantOld: "___", + WantSanitized: "___", + WantOk: true, + }, + { + Name: "label ending with dot", + LabelName: "service.", + WantOld: "service.", + WantSanitized: "service_", + WantOk: true, + }, + { + Name: "label starting with dot gets sanitized", + LabelName: ".service", + WantOld: ".service", + WantSanitized: "_service", + WantOk: true, + }, + { + Name: "single dot", + LabelName: ".", + WantOld: ".", + WantSanitized: "_", + WantOk: true, + }, + { + Name: "double dots", + LabelName: "..", + WantOld: "..", + WantSanitized: "__", + WantOk: true, + }, + { + Name: "double dots with letter at end", + LabelName: "..a", + WantOld: "..a", + WantSanitized: "__a", + WantOk: true, + }, + { + Name: "letter with double dots at end", + LabelName: "a..", + WantOld: "a..", + WantSanitized: "a__", + WantOk: true, + }, + { + Name: "letter surrounded by dots", + LabelName: ".a.", + WantOld: ".a.", + WantSanitized: "_a_", + WantOk: true, + }, + { + Name: "letter surrounded by double dots", + LabelName: "..a..", + WantOld: "..a..", + WantSanitized: "__a__", + WantOk: true, + }, + { + Name: "letter with dot and number", + LabelName: "a.0", + WantOld: "a.0", + WantSanitized: "a_0", + WantOk: true, + }, + { + Name: "number with dot is invalid", + LabelName: "0.a", + WantOld: "0.a", + WantSanitized: "0.a", + WantOk: false, + }, + { + Name: "single underscore", + LabelName: "_", + WantOld: "_", + WantSanitized: "_", + WantOk: true, + }, + { + Name: "double underscore with letter", + LabelName: "__a", + WantOld: "__a", + WantSanitized: "__a", + WantOk: true, + }, + { + Name: "letter surrounded by double underscores", + LabelName: "__a__", + WantOld: "__a__", + WantSanitized: "__a__", + WantOk: true, + }, + { + Name: "unicode characters are invalid", + LabelName: "世界", + WantOld: "世界", + WantSanitized: "世界", + WantOk: false, + }, + { + Name: "mixed unicode with valid characters is invalid", + LabelName: "界世_a", + WantOld: "界世_a", + WantSanitized: "界世_a", + WantOk: false, + }, + { + Name: "mixed unicode with underscores is invalid", + LabelName: "界世__a", + WantOld: "界世__a", + WantSanitized: "界世__a", + WantOk: false, + }, + { + Name: "valid characters with unicode suffix is invalid", + LabelName: "a_世界", + WantOld: "a_世界", + WantSanitized: "a_世界", + WantOk: false, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + t.Parallel() + + gotOld, gotSanitized, gotOk := SanitizeLegacyLabelName(tt.LabelName) + require.Equal(t, tt.WantOld, gotOld) + require.Equal(t, tt.WantSanitized, gotSanitized) + require.Equal(t, tt.WantOk, gotOk) + }) + } +} + func Test_ValidateRangeRequest(t *testing.T) { now := model.Now() for _, tt := range []struct { @@ -200,6 +589,38 @@ func Test_ValidateRangeRequest(t *testing.T) { }, }, }, + { + name: "empty start", + in: model.Interval{ + Start: 0, + End: now, + }, + expectedErr: NewErrorf(QueryMissingTimeRange, QueryMissingTimeRangeErrorMsg), + }, + { + name: "empty end", + in: model.Interval{ + Start: now, + End: 0, + }, + expectedErr: NewErrorf(QueryMissingTimeRange, QueryMissingTimeRangeErrorMsg), + }, + { + name: "empty start and end", + in: model.Interval{ + Start: 0, + End: 0, + }, + expectedErr: NewErrorf(QueryMissingTimeRange, QueryMissingTimeRangeErrorMsg), + }, + { + name: "start after end", + in: model.Interval{ + Start: 1000, + End: 500, + }, + expectedErr: NewErrorf(QueryInvalidTimeRange, QueryStartAfterEndErrorMsg), + }, } { tt := tt t.Run(tt.name, func(t *testing.T) { @@ -229,12 +650,34 @@ func TestValidateProfile(t *testing.T) { nil, 0, MockLimits{}, + NewErrorf(MalformedProfile, "nil profile"), nil, + }, + { + "empty profile", + &googlev1.Profile{}, + 0, + MockLimits{}, + NewErrorf(MalformedProfile, "empty profile"), + nil, + }, + { + "empty string table", + &googlev1.Profile{ + SampleType: []*googlev1.ValueType{{}}, + }, + 3, + MockLimits{ + MaxProfileSizeBytesValue: 100, + }, + NewErrorf(MalformedProfile, "string 0 should be empty string"), nil, }, { "too big", - &googlev1.Profile{}, + &googlev1.Profile{ + SampleType: []*googlev1.ValueType{{}}, + }, 3, MockLimits{ MaxProfileSizeBytesValue: 1, @@ -245,7 +688,8 @@ func TestValidateProfile(t *testing.T) { { "too many samples", &googlev1.Profile{ - Sample: make([]*googlev1.Sample, 3), + SampleType: []*googlev1.ValueType{{}}, + Sample: make([]*googlev1.Sample, 3), }, 0, MockLimits{ @@ -254,12 +698,40 @@ func TestValidateProfile(t *testing.T) { NewErrorf(SamplesLimit, ProfileTooManySamplesErrorMsg, `{foo="bar"}`, 3, 2), nil, }, + { + "nil sample", + &googlev1.Profile{ + SampleType: []*googlev1.ValueType{{}}, + Sample: make([]*googlev1.Sample, 3), + }, + 0, + MockLimits{ + MaxProfileStacktraceSamplesValue: 100, + }, + NewErrorf(MalformedProfile, "nil sample"), + nil, + }, + { + "sample value mismatch", + &googlev1.Profile{ + SampleType: []*googlev1.ValueType{{}}, + Sample: []*googlev1.Sample{{Value: []int64{1, 2}}}, + }, + 0, + MockLimits{ + MaxProfileStacktraceSamplesValue: 100, + }, + NewErrorf(MalformedProfile, "sample value length mismatch"), + nil, + }, { "too many labels", &googlev1.Profile{ + SampleType: []*googlev1.ValueType{{}}, Sample: []*googlev1.Sample{ { Label: make([]*googlev1.Label, 3), + Value: []int64{239}, }, }, }, @@ -273,10 +745,12 @@ func TestValidateProfile(t *testing.T) { { "truncate labels and stacktrace", &googlev1.Profile{ - StringTable: []string{"foo", "/foo/bar"}, + SampleType: []*googlev1.ValueType{{}}, + StringTable: []string{"", "foo", "/foo/bar"}, Sample: []*googlev1.Sample{ { LocationId: []uint64{0, 1, 2, 3, 4, 5}, + Value: []int64{239}, }, }, }, @@ -288,14 +762,15 @@ func TestValidateProfile(t *testing.T) { nil, func(t *testing.T, profile *googlev1.Profile) { t.Helper() - require.Equal(t, []string{"foo", "bar"}, profile.StringTable) + require.Equal(t, []string{"", "foo", "bar"}, profile.StringTable) require.Equal(t, []uint64{4, 5}, profile.Sample[0].LocationId) }, }, { name: "newer than ingestion window", profile: &googlev1.Profile{ - TimeNanos: now.Add(1 * time.Hour).UnixNano(), + SampleType: []*googlev1.ValueType{{}}, + TimeNanos: now.Add(1 * time.Hour).UnixNano(), }, limits: MockLimits{ RejectNewerThanValue: 10 * time.Minute, @@ -308,7 +783,8 @@ func TestValidateProfile(t *testing.T) { { name: "older than ingestion window", profile: &googlev1.Profile{ - TimeNanos: now.Add(-61 * time.Minute).UnixNano(), + SampleType: []*googlev1.ValueType{{}}, + TimeNanos: now.Add(-61 * time.Minute).UnixNano(), }, limits: MockLimits{ RejectOlderThanValue: time.Hour, @@ -321,7 +797,9 @@ func TestValidateProfile(t *testing.T) { { name: "just in the ingestion window", profile: &googlev1.Profile{ - TimeNanos: now.Add(-1 * time.Minute).UnixNano(), + SampleType: []*googlev1.ValueType{{}}, + TimeNanos: now.Add(-1 * time.Minute).UnixNano(), + StringTable: []string{""}, }, limits: MockLimits{ RejectOlderThanValue: time.Hour, @@ -329,8 +807,11 @@ func TestValidateProfile(t *testing.T) { }, }, { - name: "without timestamp", - profile: &googlev1.Profile{}, + name: "without timestamp", + profile: &googlev1.Profile{ + SampleType: []*googlev1.ValueType{{}}, + StringTable: []string{""}, + }, limits: MockLimits{ RejectOlderThanValue: time.Hour, RejectNewerThanValue: 10 * time.Minute, @@ -339,7 +820,7 @@ func TestValidateProfile(t *testing.T) { } { tc := tc t.Run(tc.name, func(t *testing.T) { - err := ValidateProfile(tc.limits, "foo", tc.profile, tc.size, phlaremodel.LabelsFromStrings("foo", "bar"), now) + _, err := ValidateProfile(tc.limits, "foo", pprof.RawFromProto(tc.profile), tc.size, phlaremodel.LabelsFromStrings("foo", "bar"), now) if tc.expectedErr != nil { require.Error(t, err) require.Equal(t, tc.expectedErr, err) @@ -413,41 +894,3 @@ func TestValidateFlamegraphMaxNodes(t *testing.T) { }) } } - -func Test_SanitizeLabelName(t *testing.T) { - for _, tc := range []struct { - input string - expected string - valid bool - }{ - {"", "", false}, - {".", "_", true}, - {".a", "_a", true}, - {"a.", "a_", true}, - {"..", "__", true}, - {"..a", "__a", true}, - {"a..", "a__", true}, - {"a.a", "a_a", true}, - {".a.", "_a_", true}, - {"..a..", "__a__", true}, - {"世界", "世界", false}, - {"界世_a", "界世_a", false}, - {"界世__a", "界世__a", false}, - {"a_世界", "a_世界", false}, - {"0.a", "0.a", false}, - {"0a", "0a", false}, - {"a.0", "a_0", true}, - {"a0", "a0", true}, - {"_", "_", true}, - {"__a", "__a", true}, - {"__a__", "__a__", true}, - } { - tc := tc - t.Run("", func(t *testing.T) { - origName, actual, valid := SanitizeLabelName(tc.input) - assert.Equal(t, tc.input, origName) - assert.Equal(t, tc.expected, actual) - assert.Equal(t, tc.valid, valid) - }) - } -} diff --git a/public/README.md b/public/README.md deleted file mode 100644 index 3a6f3cc2e0..0000000000 --- a/public/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Frontend - -## tl;dr - -```bash -yarn install -# Make sure you have the backend running. -yarn dev -``` - -## Overrides - -This repository currently uses [grafana/pyroscope] components, which then are overridden as necessary, -using typescript's alias and webpack alias configuration. See [tsconfig.json] and [webpack.common.js] -for more info. - -[tsconfig.json]: ../tsconfig.json -[webpack.common.js]: ../scripts/webpack/webpack.common.js - -### Guidelines for imports - -It may be confusing to see different imports, so let's go over the most common examples: - -`@pyroscope` -> Refers to code in this repository. Note that this is needed since other -downstream repositories may use this repository, and they also may want to override specific files. diff --git a/public/app/.storybook/main.js b/public/app/.storybook/main.js deleted file mode 100644 index 4971d73ab3..0000000000 --- a/public/app/.storybook/main.js +++ /dev/null @@ -1,68 +0,0 @@ -const path = require('path'); - -module.exports = { - stories: [ - '../stories/**/*.stories.mdx', - '../stories/**/*.stories.@(js|jsx|ts|tsx)', - ], - addons: ['@storybook/addon-links', '@storybook/addon-essentials'], - core: { - builder: 'webpack5', - }, - webpackFinal: async (config) => { - config.resolve.alias = { - ...config.resolve.alias, - // Only allow importing ui elements, since at some point we want to move - // ui to its own package - '@pyroscope/ui': path.resolve(__dirname, '../ui'), - '@ui': path.resolve(__dirname, '..//ui'), - - '@utils': path.resolve(__dirname, '../util'), - }; - config.resolve.extensions.push('.ts', '.tsx'); - - // support sass - config.module.rules.push({ - test: /\.scss$/, - use: ['style-loader', 'css-loader', 'sass-loader'], - include: path.resolve(__dirname, '../'), - }); - - // https://github.com/storybookjs/storybook/issues/6188#issuecomment-1026502543 - // remove svg from existing rule - config.module.rules = config.module.rules.map((rule) => { - if ( - String(rule.test) === - String( - /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/ - ) - ) { - return { - ...rule, - test: /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/, - }; - } - - return rule; - }); - - // This was copied from our main webpack config - config.module.rules.push({ - test: /\.svg$/, - use: [ - { - loader: 'react-svg-loader', - options: { - svgo: { - plugins: [ - { convertPathData: { noSpaceAfterFlags: false } }, - { removeViewBox: false }, - ], - }, - }, - }, - ], - }); - return config; - }, -}; diff --git a/public/app/.storybook/preview.js b/public/app/.storybook/preview.js deleted file mode 100644 index d3914580a7..0000000000 --- a/public/app/.storybook/preview.js +++ /dev/null @@ -1,9 +0,0 @@ -export const parameters = { - actions: { argTypesRegex: '^on[A-Z].*' }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/, - }, - }, -}; diff --git a/public/app/app.tsx b/public/app/app.tsx deleted file mode 100644 index 5544267974..0000000000 --- a/public/app/app.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import { Sidebar } from '@pyroscope/components/Sidebar'; -import { TenantWall } from '@pyroscope/components/TenantWall'; -import { useSelectFirstApp } from '@pyroscope/hooks/useAppNames'; -import '@pyroscope/jquery-import'; -import { ComparisonView } from '@pyroscope/pages/ComparisonView'; -import { DiffView } from '@pyroscope/pages/DiffView'; -import { ExploreView } from '@pyroscope/pages/ExploreView'; -import { SingleView } from '@pyroscope/pages/SingleView'; -import { ROUTES } from '@pyroscope/pages/routes'; -import store from '@pyroscope/redux/store'; -import Notifications from '@pyroscope/ui/Notifications'; -import { history } from '@pyroscope/util/history'; -import '@szhsin/react-menu/dist/index.css'; -import ReactDOM from 'react-dom/client'; -import { Provider } from 'react-redux'; -import { Route, Router, Switch } from 'react-router-dom'; -import { setupReduxQuerySync } from './redux/useReduxQuerySync'; -import './sass/profile.scss'; - -const container = document.getElementById('reactRoot') as HTMLElement; -const root = ReactDOM.createRoot(container); - -setupReduxQuerySync(); - -declare global { - interface Window { - __grafana_public_path__: string; - } -} - -if (typeof window !== 'undefined') { - // Icons from @grafana/ui are not bundled, this forces them to be loaded via a CDN instead. - window.__grafana_public_path__ = 'assets/grafana/'; -} - -function App() { - useSelectFirstApp(); - - return ( - -
    - -
    - - - - - - - - - - - - - - - - -
    -
    -
    - ); -} - -root.render( - - - - -); diff --git a/public/app/components/AppSelector/AppSelector.module.css b/public/app/components/AppSelector/AppSelector.module.css deleted file mode 100644 index a2368993e1..0000000000 --- a/public/app/components/AppSelector/AppSelector.module.css +++ /dev/null @@ -1,13 +0,0 @@ -.appSelectorModal { - /* upstream code is positioned based on a label */ - left: initial !important; - max-width: calc(100vw - 290px); -} - -.noData { - width: 600px; - height: 300px; - display: flex; - justify-content: center; - align-items: center; -} diff --git a/public/app/components/AppSelector/AppSelector.module.scss b/public/app/components/AppSelector/AppSelector.module.scss deleted file mode 100644 index 7c393b992e..0000000000 --- a/public/app/components/AppSelector/AppSelector.module.scss +++ /dev/null @@ -1,39 +0,0 @@ -@use '../../sass/mixins/outline.scss' as *; - -.container { - display: flex; - align-items: center; - position: relative; - - .appSelectorModal { - height: auto; - width: auto; - right: unset; - left: -100px; // Refers to the width of the "Application" label - z-index: 999; - max-width: calc(100vw - 290px); - } - - .headerTitle { - text-transform: uppercase; - margin-left: 10px; - color: var(--ps-select-modal-title); - font-weight: 700; - font-size: 0.8em; - } - - .search { - background: var(--ps-immutable-off-white); - color: var(--ps-immutable-placeholder-text); - border: 1px solid var(--ps-ui-border); - margin: 10px 0 10px 10px; - } - - .noData { - width: 600px; - height: 300px; - display: flex; - justify-content: center; - align-items: center; - } -} diff --git a/public/app/components/AppSelector/AppSelector.spec.tsx b/public/app/components/AppSelector/AppSelector.spec.tsx deleted file mode 100644 index 19ee5706b0..0000000000 --- a/public/app/components/AppSelector/AppSelector.spec.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import React from 'react'; -import { brandQuery } from '../../models/query'; -import { appToQuery, App } from '../../models/app'; -import { - render, - screen, - fireEvent, - waitFor, - act, -} from '@testing-library/react'; -import { AppSelector } from './AppSelector'; -import { MENU_ITEM_ROLE } from './SelectButton'; - -jest.mock('@pyroscope/services/apps'); - -const { getByTestId, queryByRole } = screen; -const mockApps: App[] = [ - { name: 'single', units: 'unknown', spyName: 'unknown' }, - { name: 'double.cpu', units: 'unknown', spyName: 'unknown' }, - { name: 'double.space', units: 'unknown', spyName: 'unknown' }, - { name: 'triple.app.cpu', units: 'unknown', spyName: 'unknown' }, - { name: 'triple.app.objects', units: 'unknown', spyName: 'unknown' }, -]; - -describe('AppSelector', () => { - describe('when no query exists / is invalid', () => { - it('renders an empty app selector', () => { - render( - {}} - selectedQuery={brandQuery('')} - /> - ); - - expect(screen.getByRole('button')).toHaveTextContent( - 'Select an application' - ); - }); - }); - - describe('when a query exists', () => { - describe('when an equivalent app exists', () => { - it('selects that app', () => { - const apps = [ - { - __profile_type__: 'process_cpu:cpu:nanoseconds:cpu:nanoseconds', - __name_id__: 'pyroscope_app' as const, - pyroscope_app: 'myapp', - name: 'myapp', - __type__: 'type', - __name__: 'name', - }, - ]; - const query = appToQuery(apps[0]); - - render( - {}} - selectedQuery={query} - /> - ); - - expect(screen.getByRole('button')).toHaveTextContent('myapp:name:type'); - }); - }); - }); - - describe('when a query exists', () => { - describe('when an equivalent app DOES NOT exist', () => { - it('shows the default label', () => { - const apps = [ - { - __profile_type__: 'process_cpu:cpu:nanoseconds:cpu:nanoseconds', - pyroscope_app: 'myapp', - __name_id__: 'pyroscope_app' as const, - name: '', - __type__: 'type', - __name__: 'name', - }, - ]; - - const query = brandQuery( - 'memory:alloc_objects:count::1{pyroscope_app="simple.golang.app"}' - ); - - render( - {}} - selectedQuery={query} - /> - ); - - expect(screen.getByRole('button')).toHaveTextContent( - 'Select an application' - ); - }); - }); - }); - - // TODO: test - // * interaction -}); - -describe('AppSelector', () => { - // TODO copied from og - it.skip('gets the list of apps, interacts with it -- naming convention changed', async () => { - const onSelected = jest.fn(); - - render( - - ); - - act(() => getByTestId('toggler').click()); - - // checks that there are 3 groups - expect(queryByRole(MENU_ITEM_ROLE, { name: 'single' })).toBeInTheDocument(); - expect(queryByRole(MENU_ITEM_ROLE, { name: 'double' })).toBeInTheDocument(); - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'triple.app' }) - ).toBeInTheDocument(); - - fireEvent.click(screen.getByRole(MENU_ITEM_ROLE, { name: 'single' })); - expect(onSelected).toHaveBeenCalledWith('single'); - - act(() => getByTestId('toggler').click()); - - // checks if 'triple' group expands 2 profile types - fireEvent.click(screen.getByRole(MENU_ITEM_ROLE, { name: 'triple.app' })); - await waitFor(() => { - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'triple.app.cpu' }) - ).toBeInTheDocument(); - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'triple.app.objects' }) - ).toBeInTheDocument(); - }); - // checks if 'double' group expands 2 profile types - fireEvent.click(screen.getByRole(MENU_ITEM_ROLE, { name: 'double' })); - await waitFor(() => { - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'double.space' }) - ).toBeInTheDocument(); - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'double.cpu' }) - ).toBeInTheDocument(); - }); - }); -}); - -describe('AppSelector', () => { - // TODO copied from og - it.skip('filters apps by query input -- naming conventions changed', async () => { - const onSelected = jest.fn(); - - render( - - ); - - act(() => getByTestId('toggler').click()); - - const input = screen.getByTestId('app-selector-search'); - act(() => fireEvent.change(input, { target: { value: 'triple.app' } })); - - // picks groups, which either should be rendered or not - await waitFor(() => { - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'single' }) - ).not.toBeInTheDocument(); - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'double' }) - ).not.toBeInTheDocument(); - expect( - queryByRole(MENU_ITEM_ROLE, { name: 'triple.app' }) - ).toBeInTheDocument(); - }); - }); -}); diff --git a/public/app/components/AppSelector/AppSelector.tsx b/public/app/components/AppSelector/AppSelector.tsx deleted file mode 100644 index 5fe1c930be..0000000000 --- a/public/app/components/AppSelector/AppSelector.tsx +++ /dev/null @@ -1,225 +0,0 @@ -import React, { useState, useEffect, useMemo } from 'react'; -import ModalWithToggle from '@pyroscope/ui/Modals/ModalWithToggle'; -import { App, appFromQuery, appToQuery } from '@pyroscope/models/app'; -import { Query } from '@pyroscope/models/query'; -import cx from 'classnames'; -import SelectButton from '@pyroscope/components/AppSelector/SelectButton'; -import ogStyles from './AppSelector.module.scss'; -import styles from './AppSelector.module.css'; - -// type App = Omit; - -interface AppSelectorProps { - /** Triggered when an app is selected */ - onSelected: (query: Query) => void; - - /** List of all applications */ - apps: App[]; - - selectedQuery: Query; -} - -// TODO: unify this with public/app/overrides/services/apps.ts -function uniqueByName(apps: App[]) { - const idFn = (b: App) => b.name; - const visited = new Set(); - - return apps.filter((b) => { - if (visited.has(idFn(b))) { - return false; - } - - visited.add(idFn(b)); - return true; - }); -} - -function findAppsWithName(apps: App[], appName: string) { - return apps.filter((a) => { - return a.name === appName; - }); -} - -function queryToApp(query: Query, apps: App[]) { - const maybeSelectedApp = appFromQuery(query); - if (!maybeSelectedApp) { - return undefined; - } - - return apps.find( - (a) => - a.__profile_type__ === maybeSelectedApp?.__profile_type__ && - a.name === maybeSelectedApp?.name - ); -} - -export function AppSelector({ - onSelected, - apps, - selectedQuery, -}: AppSelectorProps) { - const maybeSelectedApp = queryToApp(selectedQuery, apps); - const [filter, setFilter] = useState(''); - const filteredApps = useMemo( - () => - apps.filter((app) => - app.name.toLowerCase().includes(filter.trim().toLowerCase()) - ), - [apps, filter] - ); - useEffect(() => { - setFilter(''); - }, [selectedQuery]); - - return ( -
    - onSelected(appToQuery(app))} - selectedApp={maybeSelectedApp} - filter={filter} - setFilter={setFilter} - /> -
    - ); -} - -export const SelectorModalWithToggler = ({ - apps, - selectedApp, - onSelected: onSelectedUpstream, - filter, - setFilter, -}: { - apps: App[]; - selectedApp?: App; - onSelected: (app: App) => void; - filter: string; - setFilter: (filter: string) => void; -}) => { - const onSelected = (app: App) => { - // Reset state - setSelectedLeftSide(undefined); - - onSelectedUpstream(app); - setModalOpenStatus(false); - }; - - const leftSideApps = uniqueByName(apps); - const [isModalOpen, setModalOpenStatus] = useState(false); - const [selectedLeftSide, setSelectedLeftSide] = useState(); - const matchedApps = findAppsWithName( - apps, - selectedLeftSide || selectedApp?.name || '' - ); - const label = 'Select an application'; - - // For the left side, it's possible to be selected either via - // * The current query (ie. just opened the component) - // * The current "expanded state" (ie. clicked on the left side) - const isLeftSideSelected = (a: App) => { - if (selectedLeftSide) { - return selectedLeftSide === a.name; - } - - return selectedApp?.name === a.name; - }; - - // For the right side, the only way to be selected is if matches the current query - // Since clicking on an item sets that app as the current query - const isRightSideSelected = (a: App) => { - if (selectedLeftSide) { - return false; - } - - return selectedApp?.__profile_type__ === a.__profile_type__; - }; - - const groups = useMemo(() => { - const allGroups = leftSideApps.map((app) => app.name.split('-')[0]); - const uniqGroups = Array.from(new Set(allGroups)); - - const dedupedUniqGroups = uniqGroups.filter((x) => { - return !uniqGroups.find((y) => x !== y && y.startsWith(x)); - }); - - const groupOrApp = dedupedUniqGroups.map((groupName) => { - const appNamesEntries = leftSideApps.filter((app) => - app.name.startsWith(groupName) - ); - - return appNamesEntries.length > 1 ? groupName : appNamesEntries[0].name; - }); - - return groupOrApp; - }, [leftSideApps]); - - const listHeight = useMemo(() => { - const windowHeight = window?.innerHeight || 0; - const listRequiredHeight = Math.max(groups.length, matchedApps.length) * 35; - - if (windowHeight && listRequiredHeight) { - return windowHeight >= listRequiredHeight ? 'auto' : `${windowHeight}px`; - } - - return 'auto'; - }, [groups, matchedApps]); - - return ( - { - setSelectedLeftSide(undefined); - setModalOpenStatus(false); - }} - modalHeight={listHeight} - noDataEl={ - !leftSideApps?.length ? ( -
    - No Data -
    - ) : null - } - toggleText={ - selectedApp - ? `${selectedApp?.name}:${selectedApp.__name__}:${selectedApp.__type__}` - : label - } - headerEl={ - <> -
    {label}
    - setFilter(e.target.value)} - className={ogStyles.search} - data-testid="app-selector-search" - /> - - } - leftSideEl={leftSideApps.map((app) => ( - { - setSelectedLeftSide(app.name); - }} - icon="folder" - isSelected={isLeftSideSelected(app)} - key={app.name} - /> - ))} - rightSideEl={matchedApps.map((app) => ( - onSelected(app)} - isSelected={isRightSideSelected(app)} - key={app.__profile_type__} - /> - ))} - /> - ); -}; diff --git a/public/app/components/AppSelector/Label.tsx b/public/app/components/AppSelector/Label.tsx deleted file mode 100644 index eb14404bca..0000000000 --- a/public/app/components/AppSelector/Label.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export function Label() { - return <>Profile Type: ; -} - -export const LabelString = 'Select Profile Type'; diff --git a/public/app/components/AppSelector/SelectButton.module.scss b/public/app/components/AppSelector/SelectButton.module.scss deleted file mode 100644 index 1c5076c4ce..0000000000 --- a/public/app/components/AppSelector/SelectButton.module.scss +++ /dev/null @@ -1,55 +0,0 @@ -.button { - display: flex; - flex-direction: row; - align-items: center; - flex-shrink: 0; - white-space: nowrap; - cursor: pointer; - border: none; - outline: none; - width: 100%; - justify-content: space-between; - padding-left: 10px; - padding-right: 10px; - overflow: hidden; - height: 35px; - - & > div { - display: flex; - align-items: center; - max-width: 100%; - } - - &:hover { - background-color: var(--ps-ui-element-bg-highlight); - } - - &.isSelected { - background-color: var(--ps-blue-primary); - } -} - -.itemIcon { - width: 18px !important; - display: flex; - flex-shrink: 0; - margin-right: 10px; -} - -.pyroscopeLogo { - width: 18px; - height: 18px; - margin-right: 10px; - display: flex; - flex-shrink: 0; -} - -.appName { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.chevron { - margin-left: 10px; -} diff --git a/public/app/components/AppSelector/SelectButton.tsx b/public/app/components/AppSelector/SelectButton.tsx deleted file mode 100644 index 1c58ad0da1..0000000000 --- a/public/app/components/AppSelector/SelectButton.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React from 'react'; -import { faFolder } from '@fortawesome/free-solid-svg-icons/faFolder'; -import { faFolderOpen } from '@fortawesome/free-solid-svg-icons/faFolderOpen'; -import { faAngleRight } from '@fortawesome/free-solid-svg-icons/faAngleRight'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import classNames from 'classnames/bind'; -import styles from './SelectButton.module.scss'; - -const cx = classNames.bind(styles); - -export const MENU_ITEM_ROLE = 'menuitem'; - -interface SelectButtonProps { - name: string; - isSelected: boolean; - onClick: () => void; - icon: 'folder' | 'pyroscope'; -} - -function PyroscopeLogo({ className }: { className: string }) { - return ( - - - - - - - - - ); -} - -const Icon = ({ - isSelected, - icon, -}: { - icon: SelectButtonProps['icon']; - isSelected: boolean; -}) => { - if (icon === 'folder') { - return ( - - ); - } - - return ; -}; - -const SelectButton = ({ - icon, - name, - isSelected, - onClick, -}: SelectButtonProps) => { - return ( - - ); -}; - -export default SelectButton; diff --git a/public/app/components/AppSelector/index.tsx b/public/app/components/AppSelector/index.tsx deleted file mode 100644 index b95f43abd0..0000000000 --- a/public/app/components/AppSelector/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { AppSelector } from './AppSelector'; diff --git a/public/app/components/ChartTitle.module.scss b/public/app/components/ChartTitle.module.scss deleted file mode 100644 index 00e22c7303..0000000000 --- a/public/app/components/ChartTitle.module.scss +++ /dev/null @@ -1,34 +0,0 @@ -.chartTitle { - display: flex; - align-items: center; - justify-content: center; - height: 20px; - margin-bottom: 5px; - - .colorOrIcon { - display: inline-block; - align-self: center; - width: 12px; - height: 12px; - margin: 0 5px; - border-radius: 2px; - - &.icon { - height: 20px; - width: 20px; - - svg { - vertical-align: initial; - } - } - } - - .title { - display: flex; - text-align: center; - margin: 0; - font-size: 18px; - font-weight: 600; - line-height: 18px; - } -} diff --git a/public/app/components/ChartTitle.tsx b/public/app/components/ChartTitle.tsx deleted file mode 100644 index 7bd43a7c7c..0000000000 --- a/public/app/components/ChartTitle.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { ReactNode } from 'react'; -import Color from 'color'; -import clsx from 'clsx'; -import styles from './ChartTitle.module.scss'; - -import profileMetrics from '../constants/profile-metrics.json'; - -const typeToDescriptionMap: Record = Object.values( - profileMetrics -).reduce((acc, { type, description }) => ({ ...acc, [type]: description }), {}); - -const chartTitleKeys = { - ...typeToDescriptionMap, - exception: typeToDescriptionMap.exceptions, // alias - unknown: '', - - baseline: 'Baseline time range', - comparison: 'Comparison time range', - selection_included: 'Selection-included Exemplar Flamegraph', - selection_excluded: 'Selection-excluded Exemplar Flamegraph', -}; - -type ChartTitleKey = keyof typeof chartTitleKeys; - -export interface ChartTitleProps { - children?: ReactNode; - className?: string; - color?: Color; - icon?: ReactNode; - postfix?: ReactNode; - titleKey?: ChartTitleKey; -} - -export function getChartTitle(key: ChartTitleKey) { - return chartTitleKeys[key]; -} - -export default function ChartTitle({ - children, - className, - color, - icon, - postfix, - titleKey = 'unknown', -}: ChartTitleProps) { - return ( -
    - {(icon || color) && ( - - {icon} - - )} -

    {children || getChartTitle(titleKey)}

    - {postfix} -
    - ); -} diff --git a/public/app/components/CheckIcon.tsx b/public/app/components/CheckIcon.tsx deleted file mode 100644 index 58e4cfc030..0000000000 --- a/public/app/components/CheckIcon.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; - -// https://www.svgrepo.com/vectors/check/ -export default function CheckIcon({ className }: { className?: string }) { - return ( - - - - - - ); -} diff --git a/public/app/components/CustomDatePicker.module.scss b/public/app/components/CustomDatePicker.module.scss deleted file mode 100644 index 4ba7293932..0000000000 --- a/public/app/components/CustomDatePicker.module.scss +++ /dev/null @@ -1,7 +0,0 @@ -.datePickerInput { - width: 200px; -} - -.timezoneSelect { - background-color: var(--ps-ui-element-bg-highlight); -} diff --git a/public/app/components/CustomDatePicker.tsx b/public/app/components/CustomDatePicker.tsx deleted file mode 100644 index 8c625d389a..0000000000 --- a/public/app/components/CustomDatePicker.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { isAfter, isSameSecond } from 'date-fns'; -import DatePicker from 'react-datepicker'; -import Button from '@pyroscope/ui/Button'; -import { formatAsOBject, getUTCdate } from '@pyroscope/util/formatDate'; -import useTimeZone from '@pyroscope/hooks/timeZone.hook'; -import Select from '@pyroscope/ui/Select'; -import TextField from '@pyroscope/ui/Form/TextField'; -import styles from './CustomDatePicker.module.scss'; - -interface CustomDatePickerProps { - from: string; - until: string; - onSubmit: (from: string, until: string) => void; -} -function CustomDatePicker({ from, until, onSubmit }: CustomDatePickerProps) { - const { - options: timeZoneOptions, - changeTimeZoneOffset, - offset, - } = useTimeZone(); - const [warning, setWarning] = useState(false); - const [selectedDate, setSelectedDate] = useState({ - from: formatAsOBject(from), - until: formatAsOBject(until), - }); - - const updateDateRange = () => { - if ( - isSameSecond(selectedDate.from, selectedDate.until) || - isAfter(selectedDate.from, selectedDate.until) - ) { - return setWarning(true); - } - - onSubmit( - Math.round(selectedDate.from.getTime() / 1000).toString(), - Math.round(selectedDate.until.getTime() / 1000).toString() - ); - return setWarning(false); - }; - - // Since 'from' and 'until' are the source of truth - // Since our component state back when they change - useEffect(() => { - setSelectedDate({ - // ...selectedDate, -- we are replacing all values in the object, no need to keep the old one - from: formatAsOBject(from), - until: formatAsOBject(until), - }); - }, [from, until]); - - const selectFromAsDate = getUTCdate(selectedDate.from, offset); - const selectUntilAsDate = getUTCdate(selectedDate.until, offset); - - const onDateChange = (date: Date | null, area: 'from' | 'until') => { - if (date) { - setSelectedDate({ - ...selectedDate, - [area]: - offset === 0 - ? new Date( - date.getTime() + date.getTimezoneOffset() * 60 * 1000 * -1 - ) - : date, - }); - } - }; - - return ( -
    -

    Custom Date Range

    -
    - onDateChange(date, 'from')} - selectsStart - showTimeSelect - startDate={selectFromAsDate} - dateFormat="yyyy-MM-dd hh:mm aa" - customInput={ - - } - /> -
    -
    - onDateChange(date, 'until')} - selectsEnd - showTimeSelect - startDate={selectFromAsDate} - endDate={selectUntilAsDate} - minDate={selectFromAsDate} - dateFormat="yyyy-MM-dd hh:mm aa" - customInput={ - - } - /> -
    - {warning &&

    Warning: invalid date Range

    } - - - -
    - - -
    -
    - ); -} - -export default CustomDatePicker; diff --git a/public/app/components/DateRangePicker.tsx b/public/app/components/DateRangePicker.tsx deleted file mode 100644 index a93c9c6984..0000000000 --- a/public/app/components/DateRangePicker.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import React, { useState } from 'react'; - -import { useAppDispatch, useAppSelector } from '@pyroscope/redux/hooks'; -import { - setDateRange, - selectContinuousState, - actions, -} from '@pyroscope/redux/reducers/continuous'; -import cx from 'classnames'; -import Button from '@pyroscope/ui/Button'; -import { readableRange } from '@pyroscope/util/formatDate'; -import { faClock } from '@fortawesome/free-solid-svg-icons/faClock'; -import OutsideClickHandler from 'react-outside-click-handler'; -import useTimeZone from '@pyroscope/hooks/timeZone.hook'; -import CustomDatePicker from './CustomDatePicker'; -import CheckIcon from './CheckIcon'; - -const defaultPresets = [ - [ - { label: 'Last 5 minutes', from: 'now-5m', until: 'now' }, - { label: 'Last 15 minutes', from: 'now-15m', until: 'now' }, - { label: 'Last 30 minutes', from: 'now-30m', until: 'now' }, - { label: 'Last 1 hour', from: 'now-1h', until: 'now' }, - { label: 'Last 3 hours', from: 'now-3h', until: 'now' }, - { label: 'Last 6 hours', from: 'now-6h', until: 'now' }, - { label: 'Last 12 hours', from: 'now-12h', until: 'now' }, - { label: 'Last 24 hours', from: 'now-24h', until: 'now' }, - ], - [ - { label: 'Last 2 days', from: 'now-2d', until: 'now' }, - { label: 'Last 7 days', from: 'now-7d', until: 'now' }, - { label: 'Last 30 days', from: 'now-30d', until: 'now' }, - { label: 'Last 90 days', from: 'now-90d', until: 'now' }, - ], -]; - -function findPreset(from: string, until = 'now') { - return defaultPresets - .flat() - .filter((a) => a.until === until) - .find((a) => from === a.from); -} - -function dateToLabel(from: string, until: string, offsetInMinutes: number) { - const preset = findPreset(from, until); - - if (preset) { - return preset.label; - } - - return readableRange(from, until, offsetInMinutes); -} - -function DateRangePicker() { - const dispatch = useAppDispatch(); - const { offset } = useTimeZone(); - const { - from, - until, - comparisonView: { comparisonMode }, - } = useAppSelector(selectContinuousState); - const [opened, setOpened] = useState(false); - - const toggleDropdown = () => { - setOpened(!opened); - }; - - const hideDropdown = () => { - setOpened(false); - }; - const selectPreset = ({ from, until }: { from: string; until: string }) => { - dispatch(setDateRange({ from, until })); - setOpened(false); - - if (comparisonMode.active) { - dispatch( - actions.setComparisonMode({ - ...comparisonMode, - active: false, - }) - ); - } - }; - - const isPresetSelected = (preset: (typeof defaultPresets)[0][0]) => { - return preset.label === dateToLabel(from, until, offset); - }; - - const handleChangeDataRange = (from: string, until: string) => { - dispatch(setDateRange({ from, until })); - - if (comparisonMode.active) { - dispatch( - actions.setComparisonMode({ - ...comparisonMode, - active: false, - }) - ); - } - }; - - return ( -
    - - -
    -
    -

    Quick Presets

    -
    - {defaultPresets.map((arr, i) => ( -
    - {arr.map((x) => ( - - ))} -
    - ))} -
    -
    - -
    -
    -
    - ); -} - -export default DateRangePicker; diff --git a/public/app/components/ExportData.module.scss b/public/app/components/ExportData.module.scss deleted file mode 100644 index 208eac01a7..0000000000 --- a/public/app/components/ExportData.module.scss +++ /dev/null @@ -1,57 +0,0 @@ -.dropdownContainer { - position: relative; - display: inline-block; -} - -.dropdownMenuItem { - display: block; - clear: both; - font-weight: normal; - padding: 4px 16px; - font-size: 11px; - line-height: 20px; - color: var(--ps-neutral-2) !important; - text-decoration: none; - white-space: nowrap; - cursor: pointer; - width: 100%; - text-align: left; - border: 0; - &:hover { - background-color: var(--ps-ui-element-bg-highlight); - } -} - -.menuShow { - display: flex; - min-width: 180px; - position: absolute; - right: 0; - z-index: 1000; - flex-direction: column; - border: 1px solid var(--ps-ui-border); - box-shadow: 0px 5px 10px var(--ps-dropdown-shadow); - background-color: var(--ps-dropdown-background); - color: var(--ps-neutral-1); -} - -.menuHide { - display: none; -} - -.toggleMenuButton { - height: 37px; - padding: 0; - margin-left: 2px; - margin-top: 0px; - border-color: transparent; - background-color: transparent; - min-width: auto; - width: 40px; - - svg { - width: auto !important; - height: 18px; - // margin-top: 4px; - } -} diff --git a/public/app/components/ExportData.spec.tsx b/public/app/components/ExportData.spec.tsx deleted file mode 100644 index 6512da47b9..0000000000 --- a/public/app/components/ExportData.spec.tsx +++ /dev/null @@ -1,578 +0,0 @@ -import React from 'react'; -// import { SimpleSingle as TestData } from '@utils/testData'; -import { render as testRender, screen } from '@testing-library/react'; -import { Profile } from '@pyroscope/legacy/models'; -import 'web-streams-polyfill'; -import ExportData, { getFilename } from './ExportData'; -import { BrowserRouter } from 'react-router-dom'; -import { Provider } from 'react-redux'; -import { configureStore } from '@reduxjs/toolkit'; -import { setStore } from '@pyroscope/services/storage'; -import { continuousReducer } from '../redux/reducers/continuous'; - -function createStore(preloadedState: any) { - const store = configureStore({ - reducer: { - continuous: continuousReducer, - }, - preloadedState, - }); - setStore(store); - return store; -} - -function render(component: any) { - const store = createStore({ - continuous: { - from: 'now-1h', - until: 'now', - leftFrom: 'now-1h', - leftUntil: 'now-30m', - rightFrom: 'now-30m', - rightUntil: 'now', - query: 'simple.golang.app.cpu{}', - }, - }); - - return testRender({component}, { - wrapper: BrowserRouter as any, - }); -} - -describe('ExportData', () => { - it.skip('fails if theres not a single export mode -- Since we force some exports, this never happens', () => { - // ignore console.error since jsdom will complain - jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn()); - - expect(() => render()).toThrow(); - - jest.restoreAllMocks(); - }); - - // For these tests, since the code actually navigates to a url - // We took the easy route and just test for the button presence - describe('assert button presence', () => { - it('supports a download JSON button', () => { - render(); - screen.getByRole('button', { name: /json/i }); - }); - - it('supports a download pprof button', () => { - render(); - screen.getByRole('button', { name: /pprof/i }); - }); - - it('supports a download png button', () => { - render(); - screen.getByRole('button', { name: /png/i }); - }); - - it.skip('supports a download html button -- no -- exportHTML is explicitly set to false', () => { - render(); - screen.getByRole('button', { name: /html/i }); - }); - - describe('the "flamegraph.com" export button', () => { - it('is enabled by default"', () => { - render(); - screen.getByRole('button', { name: /flamegraph\.com/i }); - }); - - it('can be enabled"', () => { - render(); - screen.getByRole('button', { name: /flamegraph\.com/i }); - }); - - it('can be disabled"', () => { - render( - - ); - expect( - screen.queryByRole('button', { name: /flamegraph\.com/i }) - ).not.toBeInTheDocument(); - }); - }); - }); - - describe('filename', () => { - it('generates a fullname', () => { - expect( - getFilename( - 'pyroscope.server.alloc_objects', - TestData.metadata.startTime, - TestData.metadata.endTime - ) - ).toBe( - 'pyroscope.server.alloc_objects_2022-03-09_2025-to-2022-03-09_2025' - ); - }); - - it('uses the appname if its the only thing available', () => { - expect(getFilename('pyroscope.server.alloc_objects')).toBe( - 'pyroscope.server.alloc_objects' - ); - }); - - it('uses the date if its the only thing available', () => { - expect( - getFilename( - undefined, - TestData.metadata.startTime, - TestData.metadata.endTime - ) - ).toBe('flamegraph_2022-03-09_2025-to-2022-03-09_2025'); - }); - - it('uses a generic name if nothing is available ', () => { - expect(getFilename()).toBe('flamegraph'); - }); - }); -}); - -// const TestData = { -// version: 1, -// flamebearer: { -// names: [ -// 'total', -// 'runtime/pprof.profileWriter', -// 'runtime/pprof.newProfileBuilder', -// 'runtime/pprof.(*profileBuilder).readMapping', -// 'runtime/pprof.parseProcSelfMaps', -// 'os.ReadFile', -// 'runtime/pprof.(*profileBuilder).build', -// 'runtime/pprof.(*protobuf).varint', -// 'runtime/pprof.(*protobuf).string', -// 'runtime/pprof.(*profileBuilder).appendLocsForStack', -// 'runtime/pprof.allFrames', -// 'runtime/pprof.(*profileBuilder).stringIndex', -// 'runtime/pprof.(*profileBuilder).emitLocation', -// 'runtime/pprof.(*profileBuilder).pbLine', -// 'runtime/pprof.(*profileBuilder).flush', -// 'compress/gzip.(*Writer).Write', -// 'compress/flate.NewWriter', -// 'compress/flate.(*compressor).init', -// 'runtime/pprof.(*pcDeck).tryAdd', -// 'compress/flate.newDeflateFast', -// 'compress/flate.(*Writer).Close', -// 'compress/flate.(*compressor).close', -// 'compress/flate.(*compressor).encSpeed', -// 'compress/flate.(*huffmanBitWriter).writeBlockDynamic', -// 'compress/flate.(*huffmanBitWriter).indexTokens', -// 'compress/flate.(*huffmanEncoder).generate', -// 'runtime/pprof.(*profileBuilder).addCPUData', -// 'runtime/pprof.(*profMap).lookup', -// 'net/http.HandlerFunc.ServeHTTP', -// 'github.com/slok/go-http-metrics/middleware/std.Handler.func1', -// 'github.com/slok/go-http-metrics/middleware.Middleware.Measure', -// 'github.com/slok/go-http-metrics/middleware/std.Handler.func1.1', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Get', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).GetContext', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).GetContext', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).get', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).GetContext.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).GetContext.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).Lookup', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).get', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).GetOrSet', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).get.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.treeCodec.Deserialize', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.Deserialize', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*Dict).GetValue', -// 'bytes.NewReader', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).GetOrCreate', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache/lfu.(*Cache).increment', -// 'net/http.(*conn).serve', -// 'net/http.serverHandler.ServeHTTP', -// 'github.com/klauspost/compress/gzhttp.NewWrapper.func1.1', -// 'github.com/klauspost/compress/gzhttp.NewWrapper.func1.1.1', -// 'github.com/klauspost/compress/gzhttp.(*GzipResponseWriter).Close', -// 'github.com/klauspost/compress/gzhttp/writer/gzkp.(*pooledWriter).Close', -// 'github.com/klauspost/compress/flate.(*Writer).Close', -// 'github.com/klauspost/compress/flate.(*compressor).close', -// 'github.com/klauspost/compress/flate.(*compressor).storeFast', -// 'github.com/klauspost/compress/flate.(*fastGen).addBlock', -// 'github.com/gorilla/mux.(*Router).ServeHTTP', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Merge', -// 'github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).renderHandler', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/flamebearer.NewProfile', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).FlamebearerStruct', -// 'github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).writeResponseJSON', -// 'encoding/json.(*Encoder).Encode', -// 'github.com/slok/go-http-metrics/middleware/std.(*responseWriterInterceptor).Write', -// 'github.com/klauspost/compress/gzhttp.(*GzipResponseWriter).Write', -// 'github.com/klauspost/compress/gzhttp.(*GzipResponseWriter).startGzip', -// 'github.com/klauspost/compress/gzip.(*Writer).Write', -// 'github.com/klauspost/compress/flate.NewWriter', -// 'github.com/klauspost/compress/flate.newFastEnc', -// 'net/http.(*fileHandler).ServeHTTP', -// 'net/http.serveFile', -// 'net/http.serveContent', -// 'io.Copy', -// 'io.copyBuffer', -// 'github.com/klauspost/compress/flate.(*Writer).Write', -// 'github.com/klauspost/compress/flate.(*compressor).write', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*treeNode).clone', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*streeNode).put', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Put.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Clone', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache.New.func2', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).saveToDisk', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.treeCodec.Serialize', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).SerializeTruncate', -// 'github.com/valyala/bytebufferpool.(*ByteBuffer).Write', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/cappedarr.New', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).minValue', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).iterateWithTotal', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*Dict).Put', -// 'github.com/pyroscope-io/pyroscope/pkg/util/varint.NewWriter', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*trieNode).findNodeAt', -// 'github.com/pyroscope-io/pyroscope/pkg/util/varint.Writer.Write', -// 'bytes.(*Buffer).Write', -// 'bytes.(*Buffer).grow', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.segmentCodec.Serialize', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).Serialize', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Segment).serialize', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.dictionaryCodec.Serialize', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/dict.(*Dict).Serialize', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile', -// 'github.com/sirupsen/logrus.(*Entry).Debug', -// 'github.com/sirupsen/logrus.(*Entry).Log', -// 'github.com/sirupsen/logrus.Entry.log', -// 'github.com/sirupsen/logrus.(*Entry).write', -// 'github.com/sirupsen/logrus.(*TextFormatter).Format', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Iterate', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Tree).Insert', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.ParseKey', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*parser).nameParserCase', -// 'github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put', -// 'github.com/sirupsen/logrus.(*Logger).WithFields', -// 'github.com/sirupsen/logrus.(*Logger).newEntry', -// 'sync.(*Pool).Get', -// 'sync.(*Pool).pin', -// 'sync.(*Pool).pinSlow', -// 'github.com/sirupsen/logrus.(*Entry).WithFields', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.newNode', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/segment.(*Key).TreeKey', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/sortedmap.New', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/labels.(*Labels).Put', -// 'github.com/dgraph-io/badger/v2.(*DB).Update', -// 'github.com/dgraph-io/badger/v2.(*Txn).Commit', -// 'github.com/dgraph-io/badger/v2.(*Txn).commitAndSend', -// 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot', -// 'runtime/pprof.writeHeap', -// 'runtime/pprof.writeHeapInternal', -// 'runtime/pprof.writeHeapProto', -// 'runtime/pprof.(*profileBuilder).pbSample', -// 'github.com/valyala/bytebufferpool.(*ByteBuffer).WriteString', -// 'github.com/pyroscope-io/pyroscope/pkg/storage/tree.(*Profile).Get', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func3', -// 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).takeSnapshots.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Insert', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.newTrieNode', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).findNodeAt', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).insert', -// 'github.com/pyroscope-io/pyroscope/pkg/agent.mergeTagsWithAppName', -// 'github.com/pyroscope-io/pyroscope/pkg/convert.ParsePprof', -// 'io.ReadAll', -// 'google.golang.org/protobuf/proto.Unmarshal', -// 'google.golang.org/protobuf/proto.UnmarshalOptions.unmarshal', -// 'google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshal', -// 'google.golang.org/protobuf/internal/impl.(*MessageInfo).unmarshalPointer', -// 'google.golang.org/protobuf/internal/impl.consumeMessageSliceInfo', -// 'reflect.New', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.getHeapProfile', -// 'google.golang.org/protobuf/internal/impl.pointer.AppendPointerSlice', -// 'google.golang.org/protobuf/internal/impl.consumeStringSliceValidateUTF8', -// 'google.golang.org/protobuf/internal/impl.consumeUint64Slice', -// 'google.golang.org/protobuf/internal/impl.consumeInt64Slice', -// 'compress/gzip.NewReader', -// 'compress/gzip.(*Reader).Reset', -// 'compress/gzip.(*Reader).readHeader', -// 'compress/flate.(*dictDecoder).init', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.(*GoSpy).Snapshot.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/agent/gospy.startCPUProfile', -// 'runtime/pprof.StartCPUProfile', -// 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).reset', -// 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).uploadTries', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Diff', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*Trie).Diff.func1', -// 'github.com/pyroscope-io/pyroscope/pkg/structs/transporttrie.(*trieNode).clone', -// 'github.com/dgraph-io/badger/v2.(*DB).updateSize', -// 'github.com/dgraph-io/badger/v2.(*DB).calculateSize', -// 'github.com/dgraph-io/badger/v2.(*DB).calculateSize.func2', -// 'path/filepath.Walk', -// 'path/filepath.walk', -// 'path/filepath.readDirNames', -// 'os.(*File).Readdirnames', -// 'os.(*File).readdir', -// 'github.com/dgraph-io/badger/v2.(*DB).doWrites.func1', -// 'github.com/dgraph-io/badger/v2.(*DB).writeRequests', -// 'github.com/dgraph-io/badger/v2.(*valueLog).write', -// 'github.com/dgraph-io/badger/v2.(*logFile).encodeEntry', -// 'bytes.makeSlice', -// ], -// levels: [ -// [0, 4147083, 0, 0], -// [ -// 0, 344, 0, 177, 0, 64, 0, 169, 0, 8193, 0, 58, 0, 2315453, 415074, 129, -// 0, 839135, 0, 103, 0, 861368, 0, 84, 0, 8193, 0, 79, 0, 8193, 0, 78, 0, -// 15438, 0, 48, 0, 17477, 0, 28, 0, 73225, 0, 1, -// ], -// [ -// 0, 344, 0, 178, 0, 64, 0, 170, 0, 8193, 0, 28, 415074, 345011, 0, 164, -// 0, 1555368, 0, 130, 0, 839135, 0, 104, 0, 861368, 0, 85, 0, 8193, 0, 80, -// 0, 8193, 0, 78, 0, 15438, 0, 49, 0, 17477, 0, 28, 0, 65, 0, 26, 0, 7441, -// 0, 6, 0, 65719, 0, 2, -// ], -// [ -// 0, 344, 0, 179, 0, 64, 0, 171, 0, 8193, 0, 28, 415074, 345011, 0, 165, -// 0, 778, 745, 157, 0, 46, 0, 161, 0, 686849, 0, 152, 0, 10222, 0, 144, 0, -// 578792, 0, 136, 0, 2731, 2731, 135, 0, 275950, 0, 131, 0, 839135, 4097, -// 105, 0, 26494, 0, 101, 0, 47, 0, 98, 0, 834827, 0, 86, 0, 8193, 0, 81, -// 0, 8193, 0, 78, 0, 15438, 0, 28, 0, 17477, 0, 29, 0, 65, 65, 27, 0, 228, -// 0, 20, 0, 134, 0, 15, 0, 6809, 0, 9, 0, 98, 98, 8, 0, 172, 172, 7, 0, -// 65719, 0, 3, -// ], -// [ -// 0, 344, 0, 180, 0, 64, 0, 172, 0, 8193, 0, 29, 415074, 345011, 88237, -// 166, 745, 33, 0, 158, 0, 46, 0, 162, 0, 33, 0, 157, 0, 686816, 0, 144, -// 0, 10144, 0, 146, 0, 78, 78, 145, 0, 578792, 0, 137, 2731, 275950, 30, -// 132, 4097, 278195, 0, 115, 0, 32768, 0, 113, 0, 518613, 507690, 111, 0, -// 5462, 0, 106, 0, 26494, 26494, 102, 0, 47, 0, 99, 0, 834827, 105818, 87, -// 0, 8193, 0, 82, 0, 8193, 0, 78, 0, 15438, 0, 50, 0, 17477, 0, 30, 65, -// 228, 0, 21, 0, 134, 29, 16, 0, 3277, 3277, 18, 0, 591, 293, 12, 0, 192, -// 192, 11, 0, 228, 228, 7, 0, 2521, 2521, 10, 270, 182, 182, 5, 0, 65537, -// 65537, 4, -// ], -// [ -// 0, 344, 0, 96, 0, 64, 0, 173, 0, 8193, 0, 30, 503311, 90117, 0, 168, 0, -// 166657, 0, 141, 745, 33, 0, 159, 0, 46, 46, 163, 0, 33, 0, 158, 0, -// 686346, 0, 146, 0, 470, 470, 145, 0, 10144, 0, 147, 78, 578792, 0, 138, -// 2761, 275920, 24578, 133, 4097, 5462, 0, 125, 0, 255050, 0, 79, 0, -// 17683, 0, 116, 0, 32768, 32768, 114, 507690, 10923, 10923, 112, 0, 5462, -// 0, 107, 26494, 47, 0, 100, 105818, 593133, 396514, 92, 0, 135623, 0, 90, -// 0, 227, 227, 89, 0, 26, 26, 88, 0, 8193, 0, 83, 0, 8193, 0, 78, 0, -// 15436, 0, 58, 0, 2, 0, 51, 0, 17477, 0, 31, 65, 228, 0, 22, 29, 58, 58, -// 17, 0, 47, 47, 19, 3570, 5, 0, 14, 0, 293, 0, 13, -// ], -// [ -// 0, 344, 0, 97, 0, 64, 0, 174, 0, 8193, 0, 31, 503311, 90117, 0, 168, 0, -// 166657, 166657, 167, 745, 33, 33, 160, 46, 33, 0, 159, 0, 686346, 0, -// 147, 470, 10144, 0, 148, 78, 23667, 0, 143, 0, 555125, 284775, 139, -// 27339, 250440, 0, 9, 0, 271, 0, 6, 0, 43, 0, 134, 0, 588, 0, 2, 4097, -// 5462, 0, 126, 0, 255050, 0, 80, 0, 17426, 17426, 121, 0, 257, 0, 117, -// 551381, 5462, 0, 108, 26494, 47, 0, 100, 502332, 163850, 0, 94, 0, -// 32769, 32769, 93, 0, 135623, 135623, 91, 253, 8193, 0, 78, 0, 8193, 0, -// 78, 0, 5, 0, 71, 0, 15431, 0, 28, 0, 2, 0, 52, 0, 17477, 0, 28, 65, 228, -// 0, 23, 3704, 5, 0, 15, 0, 293, 293, 7, -// ], -// [ -// 0, 344, 344, 181, 0, 64, 0, 175, 0, 8193, 0, 28, 503311, 90117, 0, 168, -// 167481, 33, 33, 160, 0, 686346, 0, 148, 470, 10144, 0, 149, 78, 1821, 0, -// 113, 0, 21846, 21846, 124, 284775, 122885, 0, 141, 0, 147465, 147465, -// 140, 27339, 820, 201, 12, 0, 147, 147, 11, 0, 410, 410, 7, 0, 249063, -// 249063, 10, 0, 29, 29, 11, 0, 233, 233, 8, 0, 9, 9, 7, 0, 43, 0, 14, 0, -// 588, 0, 3, 4097, 5462, 0, 127, 0, 255050, 0, 81, 17426, 257, 0, 118, -// 551381, 5462, 0, 109, 26494, 47, 0, 100, 502332, 163850, 0, 95, 168645, -// 8193, 0, 78, 0, 8193, 0, 78, 0, 5, 0, 72, 0, 15431, 0, 28, 0, 2, 0, 53, -// 0, 17477, 0, 28, 65, 228, 0, 24, 3704, 5, 3, 16, -// ], -// [ -// 344, 64, 64, 176, 0, 8193, 0, 28, 503311, 90117, 0, 168, 167514, 686346, -// 0, 149, 470, 10144, 0, 150, 78, 1821, 1821, 114, 306621, 122885, 122885, -// 142, 175005, 107, 0, 14, 0, 512, 512, 7, 249891, 43, 0, 15, 0, 588, 588, -// 5, 4097, 5462, 5462, 128, 0, 255050, 0, 82, 17426, 257, 0, 119, 551381, -// 5462, 5462, 110, 26494, 47, 0, 100, 502332, 163850, 0, 96, 168645, 8193, -// 0, 78, 0, 8193, 0, 78, 0, 5, 0, 73, 0, 15431, 0, 29, 0, 2, 0, 54, 0, -// 17477, 0, 28, 65, 228, 228, 25, 3707, 2, 2, 17, -// ], -// [ -// 408, 8193, 0, 28, 503311, 90117, 0, 168, 167514, 658478, 0, 150, 0, -// 27309, 27309, 154, 0, 559, 559, 153, 470, 10144, 10144, 151, 606410, -// 107, 0, 15, 250403, 43, 3, 16, 10147, 10923, 0, 123, 0, 196611, 0, 83, -// 0, 47516, 39323, 59, 17426, 257, 257, 120, 583337, 47, 0, 100, 502332, -// 163850, 163850, 97, 168645, 8193, 0, 78, 0, 8193, 0, 78, 0, 5, 0, 74, 0, -// 15431, 0, 30, 0, 2, 0, 55, 0, 17477, 0, 32, -// ], -// [ -// 408, 8193, 0, 32, 503311, 90117, 0, 168, 167514, 510384, 0, 149, 0, -// 148094, 148094, 151, 644892, 107, 25, 16, 250406, 14, 14, 17, 0, 26, 26, -// 19, 10147, 10923, 10923, 124, 0, 196611, 0, 78, 39323, 8193, 8193, 122, -// 601020, 47, 0, 100, 834827, 8193, 0, 78, 0, 8193, 0, 78, 0, 5, 0, 75, 0, -// 15431, 0, 31, 0, 2, 0, 56, 0, 17477, 0, 33, -// ], -// [ -// 408, 8193, 0, 33, 503311, 90117, 0, 168, 167514, 163843, 163843, 156, 0, -// 96672, 0, 150, 0, 184332, 184332, 155, 0, 65537, 65537, 153, 793011, 40, -// 40, 17, 0, 42, 42, 19, 271516, 196611, 0, 78, 648536, 15, 0, 100, 0, 32, -// 0, 95, 834827, 8193, 0, 78, 0, 8193, 0, 78, 0, 5, 0, 66, 0, 15431, 0, -// 28, 0, 2, 2, 57, 0, 17477, 0, 34, -// ], -// [ -// 408, 8193, 0, 34, 503311, 90117, 0, 168, 331357, 96672, 96672, 151, -// 1314478, 196611, 16385, 78, 648536, 15, 0, 95, 0, 32, 32, 88, 834827, -// 8193, 0, 78, 0, 8193, 0, 78, 0, 2, 0, 76, 0, 3, 0, 67, 0, 15431, 0, 28, -// 2, 17477, 0, 35, -// ], -// [ -// 408, 8193, 0, 35, 503311, 90117, 0, 168, 1758892, 180226, 65537, 78, -// 648536, 15, 15, 88, 834859, 8193, 0, 78, 0, 8193, 0, 78, 0, 2, 0, 77, 0, -// 3, 0, 68, 0, 15431, 0, 28, 2, 17477, 0, 35, -// ], -// [ -// 408, 8193, 0, 35, 503311, 90117, 0, 168, 1824429, 114689, 8192, 78, -// 1483410, 8193, 0, 78, 0, 8193, 0, 78, 0, 2, 0, 56, 0, 3, 3, 69, 0, 2323, -// 0, 60, 0, 13108, 0, 32, 2, 17477, 0, 35, -// ], -// [ -// 408, 8193, 0, 35, 503311, 90117, 0, 168, 1832621, 106497, 0, 78, -// 1483410, 8193, 0, 78, 0, 8193, 0, 78, 0, 2, 2, 57, 3, 10, 0, 63, 0, -// 2313, 0, 61, 0, 13108, 0, 33, 2, 17477, 0, 35, -// ], -// [ -// 408, 8193, 0, 35, 503311, 90117, 16385, 168, 1832621, 106497, 73728, 78, -// 1483410, 8193, 0, 78, 0, 8193, 0, 78, 5, 10, 0, 64, 0, 2313, 2313, 62, -// 0, 13108, 0, 34, 2, 17477, 0, 35, -// ], -// [ -// 408, 8193, 0, 35, 519696, 73732, 0, 168, 1906349, 32769, 0, 78, 1483410, -// 8193, 0, 78, 0, 8193, 0, 78, 5, 10, 0, 65, 2313, 13108, 0, 35, 2, 17477, -// 0, 35, -// ], -// [ -// 408, 8193, 0, 35, 519696, 73732, 16385, 168, 1906349, 32769, 0, 78, -// 1483410, 8193, 0, 78, 0, 8193, 0, 78, 5, 10, 0, 66, 2313, 13108, 0, 35, -// 2, 6554, 0, 36, 0, 10923, 0, 35, -// ], -// [ -// 408, 8193, 0, 35, 536081, 57347, 8192, 168, 1906349, 32769, 24577, 78, -// 1483410, 8193, 0, 78, 0, 8193, 0, 78, 5, 10, 0, 67, 2313, 13108, 0, 35, -// 2, 6554, 0, 37, 0, 10923, 0, 36, -// ], -// [ -// 408, 8193, 0, 36, 544273, 49155, 8193, 168, 1930926, 8192, 8192, 78, -// 1483410, 8193, 0, 78, 0, 8193, 0, 78, 5, 10, 0, 68, 2313, 13108, 0, 35, -// 2, 6554, 0, 38, 0, 10923, 0, 37, -// ], -// [ -// 408, 8193, 0, 37, 552466, 40962, 0, 168, 3422528, 8193, 0, 78, 0, 8193, -// 0, 78, 5, 10, 5, 69, 2313, 13108, 0, 35, 2, 6554, 0, 39, 0, 10923, 0, -// 38, -// ], -// [ -// 408, 8193, 0, 38, 552466, 40962, 8192, 168, 3422528, 8193, 0, 78, 0, -// 8193, 0, 78, 10, 5, 5, 70, 2313, 13108, 0, 35, 2, 6554, 0, 40, 0, 10923, -// 0, 39, -// ], -// [ -// 408, 8193, 0, 39, 560658, 32770, 8192, 168, 3422528, 8193, 0, 78, 0, -// 8193, 0, 78, 2328, 6554, 0, 36, 0, 6554, 0, 35, 2, 6554, 0, 41, 0, -// 10923, 0, 40, -// ], -// [ -// 408, 8193, 0, 40, 568850, 24578, 0, 168, 3422528, 8193, 0, 78, 0, 8193, -// 0, 78, 2328, 6554, 0, 37, 0, 6554, 0, 36, 2, 6554, 0, 42, 0, 10923, 0, -// 41, -// ], -// [ -// 408, 8193, 0, 41, 568850, 24578, 8193, 168, 3422528, 8193, 0, 78, 0, -// 8193, 0, 78, 2328, 6554, 6554, 59, 0, 6554, 0, 37, 2, 6554, 0, 46, 0, -// 10923, 0, 42, -// ], -// [ -// 408, 8193, 0, 42, 577043, 16385, 8193, 168, 3422528, 8193, 0, 78, 0, -// 8193, 0, 78, 8882, 6554, 6554, 59, 2, 6554, 0, 39, 0, 10923, 0, 43, -// ], -// [ -// 408, 8193, 0, 43, 585236, 8192, 0, 168, 3422528, 8193, 0, 78, 0, 8193, -// 0, 78, 15438, 6554, 0, 40, 0, 10923, 0, 44, -// ], -// [ -// 408, 8193, 8193, 122, 585236, 8192, 8192, 168, 3422528, 8193, 0, 78, 0, -// 8193, 0, 78, 15438, 6554, 6554, 47, 0, 10923, 10923, 45, -// ], -// [4024557, 8193, 0, 78, 0, 8193, 0, 78], -// [4024557, 8193, 0, 78, 0, 8193, 0, 78], -// [4024557, 8193, 0, 78, 0, 8193, 0, 78], -// [4024557, 8193, 8193, 78, 0, 8193, 8193, 78], -// ], -// numTicks: 4147083, -// maxSelf: 507690, -// }, -// timeline: { -// startTime: 1642688200, -// samples: [ -// 52997, 314116, 166037, 145716, 119938, 156626, 95277, 299103, 42874, -// 103485, 78324, 50019, 93481, 257538, 246101, 75713, 127838, 89530, 112918, -// 268927, 79218, 61979, 117654, 87601, 88796, 316884, 103538, 131815, -// 113310, 149760, 0, -// ], -// durationDelta: 10, -// watermarks: {}, -// }, -// metadata: { -// format: 'single', -// spyName: 'gospy', -// sampleRate: 100, -// units: 'objects', -// appName: 'pyroscope.server.alloc_objects', -// startTime: 1642688208, -// endTime: 1642688508, -// query: 'pyroscope.server.alloc_objects{}', -// maxNodes: 1024, -// }, -// }; - -const TestData: Profile = { - version: 1, - flamebearer: { - names: [ - 'total', - 'runtime.main', - 'main.main', - 'github.com/pyroscope-io/client/pyroscope.TagWrapper', - 'runtime/pprof.Do', - 'github.com/pyroscope-io/client/pyroscope.TagWrapper.func1', - 'main.main.func1', - 'main.slowFunction', - 'main.slowFunction.func1', - 'main.work', - 'main.fastFunction', - 'main.fastFunction.func1', - ], - levels: [ - [0, 95, 0, 0], - [0, 95, 0, 1], - [0, 95, 0, 2], - [0, 95, 0, 3], - [0, 95, 0, 4], - [0, 95, 0, 5], - [0, 95, 0, 6], - [0, 19, 0, 10, 0, 76, 0, 7], - [0, 19, 0, 3, 0, 76, 0, 4], - [0, 19, 0, 4, 0, 76, 0, 8], - [0, 19, 0, 5, 0, 76, 76, 9], - [0, 19, 0, 11], - [0, 19, 19, 9], - ], - numTicks: 95, - maxSelf: 76, - }, - metadata: { - format: 'single', - spyName: 'gospy', - sampleRate: 100, - units: 'samples', - name: 'simple.golang.app.cpu 2022-03-09T20:25:55Z', - appName: 'simple.golang.app.cpu', - startTime: 1646857555, - endTime: 1646857555, - query: 'simple.golang.app.cpu{}', - maxNodes: 8192, - }, -}; diff --git a/public/app/components/ExportData.tsx b/public/app/components/ExportData.tsx deleted file mode 100644 index 9904f5bf96..0000000000 --- a/public/app/components/ExportData.tsx +++ /dev/null @@ -1,412 +0,0 @@ -import Button from '@pyroscope/ui/Button'; -import handleError from '@pyroscope/util/handleError'; -import OutsideClickHandler from 'react-outside-click-handler'; -import React, { useState } from 'react'; -import saveAs from 'file-saver'; -import showModalWithInput from '@pyroscope/components/Modals/ModalWithInput'; -import styles from './ExportData.module.scss'; -import { ContinuousState } from '@pyroscope/redux/reducers/continuous'; -import { - convertPresetsToDate, - formatAsOBject, -} from '@pyroscope/util/formatDate'; -import { createBiggestInterval } from '@pyroscope/util/timerange'; -import { downloadWithOrgID } from '@pyroscope/services/base'; -import { faShareSquare } from '@fortawesome/free-solid-svg-icons/faShareSquare'; -import { Field, Message } from 'protobufjs/light'; -import { flameGraphUpload } from '@pyroscope/services/flamegraphcom'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { format } from 'date-fns'; -import { isRouteActive, ROUTES } from '@pyroscope/pages/routes'; -import { Profile } from '@pyroscope/legacy/models'; -import { Tooltip } from '@pyroscope/ui/Tooltip'; -import { useAppDispatch, useAppSelector } from '@pyroscope/redux/hooks'; -import { useLocation } from 'react-router-dom'; -import 'compression-streams-polyfill'; - -/* eslint-disable react/destructuring-assignment */ - -// These are modeled individually since each condition may have different values -// For example, a exportPprof: true may accept a custom export function -// For cases like grafana -type exportJSON = { - exportJSON?: boolean; - flamebearer: Profile; -}; - -type exportPprof = { - exportPprof?: boolean; - flamebearer: Profile; -}; - -type exportHTML = { - exportHTML?: boolean; - fetchUrlFunc?: () => string; - flamebearer: Profile; -}; - -type exportFlamegraphDotCom = { - exportFlamegraphDotCom?: boolean; - exportFlamegraphDotComFn?: (name?: string) => Promise; - flamebearer: Profile; -}; - -type exportPNG = { - exportPNG?: boolean; - flamebearer: Profile; -}; - -export class PprofRequest extends Message { - constructor( - profile_typeID: string, - label_selector: string, - start: number, - end: number - ) { - super(); - this.profile_typeID = profile_typeID; - this.label_selector = label_selector; - this.start = start; - this.end = end; - } - - @Field.d(1, 'string') - profile_typeID: string; - - @Field.d(2, 'string') - label_selector: string; - - @Field.d(3, 'int64') - start: number; - - @Field.d(4, 'int64') - end: number; -} - -export type ExportDataProps = { - buttonEl?: React.ComponentType<{ - onClick: (event: React.MouseEvent) => void; - }>; -} & exportPprof & - exportHTML & - exportFlamegraphDotCom & - exportPNG & - exportJSON; - -function biggestTimeRangeInUnixMs(state: ContinuousState) { - return createBiggestInterval({ - from: [state.from, state.leftFrom, state.rightFrom] - .map(formatAsOBject) - .map((d) => d.valueOf()), - until: [state.until, state.leftUntil, state.leftUntil] - .map(formatAsOBject) - .map((d) => d.valueOf()), - }); -} - -function buildPprofQuery(state: ContinuousState) { - const { from, until } = biggestTimeRangeInUnixMs(state); - const labelsIndex = state.query.indexOf('{'); - const profileTypeID = state.query.substring(0, labelsIndex); - const label_selector = state.query.substring(labelsIndex); - const message = new PprofRequest(profileTypeID, label_selector, from, until); - return PprofRequest.encode(message).finish(); -} - -function ExportData(props: ExportDataProps) { - const { exportJSON = false, exportFlamegraphDotCom = true } = props; - let { exportPprof } = props; - const exportPNG = true; - const exportHTML = false; - const { pathname } = useLocation(); - const dispatch = useAppDispatch(); - const pprofQuery = useAppSelector((state: { continuous: ContinuousState }) => - buildPprofQuery(state.continuous) - ); - - if ( - isRouteActive(pathname, ROUTES.COMPARISON_DIFF_VIEW) || - isRouteActive(pathname, ROUTES.COMPARISON_VIEW) - ) { - exportPprof = false; - } - if ( - !exportPNG && - !exportJSON && - !exportPprof && - !exportHTML && - !exportFlamegraphDotCom - ) { - throw new Error('At least one export button should be enabled'); - } - - const [toggleMenu, setToggleMenu] = useState(false); - - const downloadJSON = async () => { - if (!props.exportJSON) { - return; - } - - // TODO additional check this won't be needed once we use strictNullChecks - if (props.exportJSON) { - const { flamebearer } = props; - - const defaultExportName = getFilename( - flamebearer.metadata.appName, - flamebearer.metadata.startTime, - flamebearer.metadata.endTime - ); - // get user input from modal - const customExportName = await getCustomExportName(defaultExportName); - // return if user cancels the modal - if (!customExportName) { - return; - } - - const filename = `${customExportName}.json`; - - const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent( - JSON.stringify(flamebearer) - )}`; - - saveAs(dataStr, filename); - } - }; - - const downloadFlamegraphDotCom = async () => { - if (!exportFlamegraphDotCom) { - return; - } - - const { flamebearer } = props; - - const defaultExportName = getFilename( - flamebearer.metadata.appName, - flamebearer.metadata.startTime, - flamebearer.metadata.endTime - ); - // get user input from modal - const customExportName = await getCustomExportName(defaultExportName); - // return if user cancels the modal - if (!customExportName) { - return; - } - - const url = await flameGraphUpload(customExportName, flamebearer); - if (url.isErr) { - handleError(dispatch, 'Failed to export to flamegraph.com', url.error); - return; - } - - const dlLink = document.createElement('a'); - dlLink.target = '_blank'; - dlLink.href = url.value; - - document.body.appendChild(dlLink); - dlLink.click(); - document.body.removeChild(dlLink); - }; - - const downloadPNG = async () => { - if (exportPNG) { - const { flamebearer } = props; - - const defaultExportName = getFilename( - flamebearer.metadata.appName, - flamebearer.metadata.startTime, - flamebearer.metadata.endTime - ); - // get user input from modal - const customExportName = await getCustomExportName(defaultExportName); - // return if user cancels the modal - if (!customExportName) { - return; - } - - const filename = `${customExportName}.png`; - - // TODO use ref - // this won't work for comparison side by side - const canvasElement = document.querySelector( - '.flamegraph-canvas' - ) as HTMLCanvasElement; - canvasElement.toBlob(function (blob) { - if (!blob) { - return; - } - saveAs(blob, filename); - }); - } - }; - - const handleToggleMenu = (event: React.MouseEvent) => { - event.preventDefault(); - setToggleMenu(!toggleMenu); - }; - - const downloadPprof = async function () { - if (!exportPprof) { - return; - } - - if (props.exportPprof) { - // get user input from modal - const customExportName = await getCustomExportName('profile.pb.gz'); - // return if user cancels the modal - if (!customExportName) { - return; - } - const response = await downloadWithOrgID( - '/querier.v1.QuerierService/SelectMergeProfile', - { - headers: { - 'content-type': 'application/proto', - }, - method: 'POST', - body: pprofQuery, - } - ); - if (response.isErr) { - handleError(dispatch, 'Failed to export to pprof', response.error); - return; - } - const data = await new Response( - response.value.body?.pipeThrough(new CompressionStream('gzip')) - ).blob(); - saveAs(data, customExportName); - } - }; - - const downloadHTML = async function () {}; - - async function getCustomExportName(defaultExportName: string) { - return showModalWithInput({ - title: 'Enter export name', - confirmButtonText: 'Export', - input: 'text', - inputValue: defaultExportName, - inputPlaceholder: 'Export name', - type: 'normal', - validationMessage: 'Name must not be empty', - onConfirm: (value: ShamefulAny) => value, - }); - } - - return ( -
    - setToggleMenu(false)}> - {props.buttonEl ? ( - - ) : ( - - - - )} -
    - {exportPNG && ( - - )} - {exportJSON && ( - - )} - {exportPprof && ( - - )} - {exportHTML && ( - - )} - {exportFlamegraphDotCom && ( - - )} -
    -
    -
    - ); -} - -const dateFormat = 'yyyy-MM-dd_HHmm'; - -function dateForExportFilename(from: string, until: string) { - let start = new Date(Math.round(parseInt(from, 10) * 1000)); - let end = new Date(Math.round(parseInt(until, 10) * 1000)); - - if (/^now-/.test(from) && until === 'now') { - const { _from } = convertPresetsToDate(from); - - start = new Date(Math.round(parseInt(_from.toString(), 10) * 1000)); - end = new Date(); - } - - return `${format(start, dateFormat)}-to-${format(end, dateFormat)}`; -} - -export function getFilename( - appName?: string, - startTime?: number, - endTime?: number -) { - // const appname = flamebearer.metadata.appName; - let date = ''; - - if (startTime && endTime) { - date = dateForExportFilename(startTime.toString(), endTime.toString()); - } - - // both name and date are available - if (appName && date) { - return [appName, date].join('_'); - } - - // only fullname - if (appName) { - return appName; - } - - // only date - if (date) { - return ['flamegraph', date].join('_'); - } - - // nothing is available, use a generic name - return `flamegraph`; -} - -export default ExportData; diff --git a/public/app/components/FileList.module.scss b/public/app/components/FileList.module.scss deleted file mode 100644 index 4133a799a9..0000000000 --- a/public/app/components/FileList.module.scss +++ /dev/null @@ -1,67 +0,0 @@ -@use '../../sass/variables' as *; - -$tdHeight: 25px; - -.tableContainer { - overflow-y: scroll; - padding: 5px; - margin-bottom: 10px; - - table { - font-size: 14px; - - th { - padding: 6px 10px; - } - - td { - font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; - - &:first-child { - margin-left: 15px; - position: relative; - } - } - - th, - td { - span { - // mix-blend-mode: exclusion; - text-shadow: 0 0 1px var(--ps-table-row-text-shadow); - } - - &:first-child { - border-left: none; - text-align: left; - width: auto; - min-width: auto; - max-width: initial; - white-space: nowrap; - } - - &:last-child { - width: 250px; - min-width: 250px; - max-width: 250px; - padding: 0px 10px; - } - } - - .profileName { - display: flex; - align-items: center; - - span { - display: inline-block; - overflow: hidden; - text-overflow: ellipsis; - width: calc(100% - 30px); - margin-right: 10px; - } - } - } -} - -.checkIcon { - margin-left: 8px; -} diff --git a/public/app/components/FileList.tsx b/public/app/components/FileList.tsx deleted file mode 100644 index 47bb685b9d..0000000000 --- a/public/app/components/FileList.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React, { useMemo } from 'react'; -import { format, parseISO } from 'date-fns'; - -import { Maybe } from '@pyroscope/util/fp'; -import { AllProfiles } from '@pyroscope/models/adhoc'; -import TableUI, { useTableSort, BodyRow } from '@pyroscope/ui/Table'; -import CheckIcon from './CheckIcon'; -import styles from './FileList.module.scss'; - -const dateModifiedColName = 'updatedAt'; -const fileNameColName = 'name'; -const headRow = [ - { name: fileNameColName, label: 'Filename', sortable: 1 }, - { - name: dateModifiedColName, - label: 'Date Modified', - sortable: 1, - default: true, - }, -]; - -const getBodyRows = ( - sortedProfilesIds: Array, - onProfileSelected: (id: string) => void, - selectedProfileId: Maybe -): BodyRow[] => { - return sortedProfilesIds.reduce((acc, profile) => { - const isRowSelected = selectedProfileId.mapOr( - false, - (profId) => profId === profile.id - ); - - const date = parseISO(profile.updatedAt); - const timeString = `${format(date, 'MMM d, yyyy')} at ${format( - date, - 'h:mm a' - )}`; - - acc.push({ - cells: [ - { - value: ( -
    - {profile.name} - {isRowSelected && } -
    - ), - }, - { value: timeString }, - ], - onClick: () => { - // Optimize to not reload the same one - if ( - selectedProfileId.isJust && - selectedProfileId.value === profile.id - ) { - return; - } - onProfileSelected(profile.id); - }, - isRowSelected, - }); - - return acc; - }, [] as BodyRow[]); -}; - -interface FileListProps { - className?: string; - profilesList: AllProfiles; - onProfileSelected: (id: string) => void; - selectedProfileId: Maybe; -} - -function FileList(props: FileListProps) { - const { - profilesList: profiles, - onProfileSelected, - className, - selectedProfileId, - } = props; - - const { sortBy, sortByDirection, ...rest } = useTableSort(headRow); - const sortedProfilesIds = useMemo(() => { - const m = sortByDirection === 'asc' ? 1 : -1; - - let sorted: Array = []; - - if (profiles) { - const filesInfo = Object.values(profiles); - - switch (sortBy) { - case fileNameColName: - sorted = filesInfo.sort( - (a, b) => m * a[sortBy].localeCompare(b[sortBy]) - ); - break; - case dateModifiedColName: - sorted = filesInfo.sort( - (a, b) => - m * - (new Date(a[sortBy]).getTime() - new Date(b[sortBy]).getTime()) - ); - break; - default: - sorted = filesInfo; - } - } - - return sorted; - }, [profiles, sortBy, sortByDirection]); - - const tableBodyProps = profiles - ? { - type: 'filled' as const, - bodyRows: getBodyRows( - sortedProfilesIds, - onProfileSelected, - selectedProfileId - ), - } - : { type: 'not-filled' as const, value: '' }; - - return ( - <> -
    - -
    - - ); -} - -export default FileList; diff --git a/public/app/components/FlameGraphWrapper.tsx b/public/app/components/FlameGraphWrapper.tsx deleted file mode 100644 index d92c26e6bb..0000000000 --- a/public/app/components/FlameGraphWrapper.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import React from 'react'; -import { createTheme } from '@grafana/data'; -import { FlameGraph } from '@grafana/flamegraph'; -import { Button, Tooltip } from '@grafana/ui'; - -import useColorMode from '@pyroscope/hooks/colorMode.hook'; -import { FlamegraphRenderer } from '@pyroscope/legacy/flamegraph/FlamegraphRenderer'; -import ExportData from '@pyroscope/components/ExportData'; -import type { Profile } from '@pyroscope/legacy/models'; -import useExportToFlamegraphDotCom from '@pyroscope/components/exportToFlamegraphDotCom.hook'; -import { SharedQuery } from '@pyroscope/legacy/flamegraph/FlameGraph/FlameGraphRenderer'; - -import { - isExportToFlamegraphDotComEnabled, - isGrafanaFlamegraphEnabled, -} from '@pyroscope/util/features'; - -import { flamebearerToDataFrameDTO } from '@pyroscope/util/flamebearer'; - -type Props = { - profile?: Profile; - dataTestId?: string; - vertical?: boolean; - sharedQuery?: SharedQuery; - timelineEl?: React.ReactNode; - diff?: boolean; -}; - -export function FlameGraphWrapper(props: Props) { - const { colorMode } = useColorMode(); - const exportToFlamegraphDotComFn = useExportToFlamegraphDotCom(props.profile); - - if (isGrafanaFlamegraphEnabled) { - const dataFrame = props.profile - ? flamebearerToDataFrameDTO( - props.profile.flamebearer.levels, - props.profile.flamebearer.names, - props.profile.metadata.units, - Boolean(props.diff) - ) - : undefined; - - let extraEl = <>; - - // This is a bit weird but the typing is not great. It seems like flamegraph assumed profile can be undefined - // but then ExportData won't work so not sure if the profile === undefined could actually happen. - if (props.profile) { - extraEl = ( - { - return ( - -